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

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial: (48 commits)
  Documentation: update broken web addresses.
  fix comment typo "choosed" -> "chosen"
  hostap:hostap_hw.c Fix typo in comment
  Fix spelling contorller -> controller in comments
  Kconfig.debug: FAIL_IO_TIMEOUT: typo Faul -> Fault
  fs/Kconfig: Fix typo Userpace -> Userspace
  Removing dead MACH_U300_BS26
  drivers/infiniband: Remove unnecessary casts of private_data
  fs/ocfs2: Remove unnecessary casts of private_data
  libfc: use ARRAY_SIZE
  scsi: bfa: use ARRAY_SIZE
  drm: i915: use ARRAY_SIZE
  drm: drm_edid: use ARRAY_SIZE
  synclink: use ARRAY_SIZE
  block: cciss: use ARRAY_SIZE
  comment typo fixes: charater => character
  fix comment typos concerning "challenge"
  arm: plat-spear: fix typo in kerneldoc
  reiserfs: typo comment fix
  update email address
  ...
diff --git a/Documentation/ABI/testing/debugfs-ec b/Documentation/ABI/testing/debugfs-ec
new file mode 100644
index 0000000..6546115
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-ec
@@ -0,0 +1,20 @@
+What:		/sys/kernel/debug/ec/*/{gpe,use_global_lock,io}
+Date:		July 2010
+Contact:	Thomas Renninger <trenn@suse.de>
+Description:
+
+General information like which GPE is assigned to the EC and whether
+the global lock should get used.
+Knowing the EC GPE one can watch the amount of HW events related to
+the EC here (XY -> GPE number from /sys/kernel/debug/ec/*/gpe):
+/sys/firmware/acpi/interrupts/gpeXY
+
+The io file is binary and a userspace tool located here:
+ftp://ftp.suse.com/pub/people/trenn/sources/ec/
+should get used to read out the 256 Embedded Controller registers
+or writing to them.
+
+CAUTION: Do not write to the Embedded Controller if you don't know
+what you are doing! Rebooting afterwards also is a good idea.
+This can influence the way your machine is cooled and fans may
+not get switched on again after you did a wrong write.
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
index 88340a2..063bda7 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
@@ -33,19 +33,6 @@
 		left. E.g. a returned value of 138 means 1.38
 		This file is readonly.
 
-What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/kone_driver_version
-Date:		March 2010
-Contact:	Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:	When read, this file returns the driver version.
-		The format of the string is "v<major>.<minor>.<patchlevel>".
-		This attribute is used by the userland tools to find the sysfs-
-		paths of installed kone-mice and determine the capabilites of
-		the driver. Versions of this driver for old kernels replace
-		usbhid instead of generic-usb. The way to scan for this file
-		has been chosen to provide a consistent way for all supported
-		kernel versions.
-		This file is readonly.
-
 What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]
 Date:		March 2010
 Contact:	Stefan Achatz <erazor_de@users.sourceforge.net>
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index d6a801f..2875f1f 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -114,3 +114,18 @@
 		if this file contains "1", which is the default.  It may be
 		disabled by writing "0" to this file, in which case all devices
 		will be suspended and resumed synchronously.
+
+What:		/sys/power/wakeup_count
+Date:		July 2010
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/power/wakeup_count file allows user space to put the
+		system into a sleep state while taking into account the
+		concurrent arrival of wakeup events.  Reading from it returns
+		the current number of registered wakeup events and it blocks if
+		some wakeup events are being processed at the time the file is
+		read from.  Writing to it will only succeed if the current
+		number of wakeup events is equal to the written value and, if
+		successful, will make the kernel abort a subsequent transition
+		to a sleep state if any wakeup events are reported after the
+		write has returned.
diff --git a/Documentation/DocBook/dvb/dvbapi.xml b/Documentation/DocBook/dvb/dvbapi.xml
index 63c528f..e3a97fd 100644
--- a/Documentation/DocBook/dvb/dvbapi.xml
+++ b/Documentation/DocBook/dvb/dvbapi.xml
@@ -12,10 +12,12 @@
 <othername role="mi">O. C.</othername>
 <affiliation><address><email>rjkm@metzlerbros.de</email></address></affiliation>
 </author>
+</authorgroup>
+<authorgroup>
 <author>
 <firstname>Mauro</firstname>
-<surname>Chehab</surname>
 <othername role="mi">Carvalho</othername>
+<surname>Chehab</surname>
 <affiliation><address><email>mchehab@redhat.com</email></address></affiliation>
 <contrib>Ported document to Docbook XML.</contrib>
 </author>
@@ -23,13 +25,24 @@
 <copyright>
 	<year>2002</year>
 	<year>2003</year>
-	<year>2009</year>
 	<holder>Convergence GmbH</holder>
 </copyright>
+<copyright>
+	<year>2009-2010</year>
+	<holder>Mauro Carvalho Chehab</holder>
+</copyright>
 
 <revhistory>
 <!-- Put document revisions here, newest first. -->
 <revision>
+	<revnumber>2.0.3</revnumber>
+	<date>2010-07-03</date>
+	<authorinitials>mcc</authorinitials>
+	<revremark>
+		Add some frontend capabilities flags, present on kernel, but missing at the specs.
+	</revremark>
+</revision>
+<revision>
 	<revnumber>2.0.2</revnumber>
 	<date>2009-10-25</date>
 	<authorinitials>mcc</authorinitials>
@@ -63,7 +76,7 @@
 
 
 <title>LINUX DVB API</title>
-<subtitle>Version 3</subtitle>
+<subtitle>Version 5.2</subtitle>
 <!-- ADD THE CHAPTERS HERE -->
   <chapter id="dvb_introdution">
     &sub-intro;
diff --git a/Documentation/DocBook/dvb/frontend.h.xml b/Documentation/DocBook/dvb/frontend.h.xml
index b99644f..d08e0d4 100644
--- a/Documentation/DocBook/dvb/frontend.h.xml
+++ b/Documentation/DocBook/dvb/frontend.h.xml
@@ -63,6 +63,7 @@
         FE_CAN_8VSB                     = 0x200000,
         FE_CAN_16VSB                    = 0x400000,
         FE_HAS_EXTENDED_CAPS            = 0x800000,   /* We need more bitspace for newer APIs, indicate this. */
+        FE_CAN_TURBO_FEC                = 0x8000000,  /* frontend supports "turbo fec modulation" */
         FE_CAN_2G_MODULATION            = 0x10000000, /* frontend supports "2nd generation modulation" (DVB-S2) */
         FE_NEEDS_BENDING                = 0x20000000, /* not supported anymore, don't use (frontend requires frequency bending) */
         FE_CAN_RECOVER                  = 0x40000000, /* frontend can recover from a cable unplug automatically */
diff --git a/Documentation/DocBook/dvb/frontend.xml b/Documentation/DocBook/dvb/frontend.xml
index 300ba1f..78d756d 100644
--- a/Documentation/DocBook/dvb/frontend.xml
+++ b/Documentation/DocBook/dvb/frontend.xml
@@ -64,8 +64,14 @@
 	FE_CAN_BANDWIDTH_AUTO         = 0x40000,
 	FE_CAN_GUARD_INTERVAL_AUTO    = 0x80000,
 	FE_CAN_HIERARCHY_AUTO         = 0x100000,
-	FE_CAN_MUTE_TS                = 0x80000000,
-	FE_CAN_CLEAN_SETUP            = 0x40000000
+	FE_CAN_8VSB                   = 0x200000,
+	FE_CAN_16VSB                  = 0x400000,
+	FE_HAS_EXTENDED_CAPS          = 0x800000,
+	FE_CAN_TURBO_FEC              = 0x8000000,
+	FE_CAN_2G_MODULATION          = 0x10000000,
+	FE_NEEDS_BENDING              = 0x20000000,
+	FE_CAN_RECOVER                = 0x40000000,
+	FE_CAN_MUTE_TS                = 0x80000000
 	} fe_caps_t;
 </programlisting>
 </section>
diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
index 5d4d40f4..6ae9715 100644
--- a/Documentation/DocBook/media-entities.tmpl
+++ b/Documentation/DocBook/media-entities.tmpl
@@ -218,6 +218,7 @@
 <!ENTITY sub-dev-teletext SYSTEM "v4l/dev-teletext.xml">
 <!ENTITY sub-driver SYSTEM "v4l/driver.xml">
 <!ENTITY sub-libv4l SYSTEM "v4l/libv4l.xml">
+<!ENTITY sub-lirc_device_interface SYSTEM "v4l/lirc_device_interface.xml">
 <!ENTITY sub-remote_controllers SYSTEM "v4l/remote_controllers.xml">
 <!ENTITY sub-fdl-appendix SYSTEM "v4l/fdl-appendix.xml">
 <!ENTITY sub-close SYSTEM "v4l/func-close.xml">
diff --git a/Documentation/DocBook/media.tmpl b/Documentation/DocBook/media.tmpl
index eea564b..f11048d 100644
--- a/Documentation/DocBook/media.tmpl
+++ b/Documentation/DocBook/media.tmpl
@@ -28,7 +28,7 @@
 <title>LINUX MEDIA INFRASTRUCTURE API</title>
 
 <copyright>
-	<year>2009</year>
+	<year>2009-2010</year>
 	<holder>LinuxTV Developers</holder>
 </copyright>
 
@@ -61,7 +61,7 @@
 		in fact it covers several different video standards including
 		DVB-T, DVB-S, DVB-C and ATSC. The API is currently being updated
 		to documment support also for DVB-S2, ISDB-T and ISDB-S.</para>
-	<para>The third part covers other API's used by all media infrastructure devices</para>
+	<para>The third part covers Remote Controller API</para>
 	<para>For additional information and for the latest development code,
 		see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
 	<para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
@@ -86,7 +86,7 @@
 </author>
 </authorgroup>
 <copyright>
-	<year>2009</year>
+	<year>2009-2010</year>
 	<holder>Mauro Carvalho Chehab</holder>
 </copyright>
 
@@ -101,7 +101,7 @@
 </revhistory>
 </partinfo>
 
-<title>Other API's used by media infrastructure drivers</title>
+<title>Remote Controller API</title>
 <chapter id="remote_controllers">
 &sub-remote_controllers;
 </chapter>
diff --git a/Documentation/DocBook/v4l/lirc_device_interface.xml b/Documentation/DocBook/v4l/lirc_device_interface.xml
new file mode 100644
index 0000000..0413234
--- /dev/null
+++ b/Documentation/DocBook/v4l/lirc_device_interface.xml
@@ -0,0 +1,235 @@
+<section id="lirc_dev">
+<title>LIRC Device Interface</title>
+
+
+<section id="lirc_dev_intro">
+<title>Introduction</title>
+
+<para>The LIRC device interface is a bi-directional interface for
+transporting raw IR data between userspace and kernelspace. Fundamentally,
+it is just a chardev (/dev/lircX, for X = 0, 1, 2, ...), with a number
+of standard struct file_operations defined on it. With respect to
+transporting raw IR data to and fro, the essential fops are read, write
+and ioctl.</para>
+
+<para>Example dmesg output upon a driver registering w/LIRC:</para>
+  <blockquote>
+    <para>$ dmesg |grep lirc_dev</para>
+    <para>lirc_dev: IR Remote Control driver registered, major 248</para>
+    <para>rc rc0: lirc_dev: driver ir-lirc-codec (mceusb) registered at minor = 0</para>
+  </blockquote>
+
+<para>What you should see for a chardev:</para>
+  <blockquote>
+    <para>$ ls -l /dev/lirc*</para>
+    <para>crw-rw---- 1 root root 248, 0 Jul  2 22:20 /dev/lirc0</para>
+  </blockquote>
+</section>
+
+<section id="lirc_read">
+<title>LIRC read fop</title>
+
+<para>The lircd userspace daemon reads raw IR data from the LIRC chardev. The
+exact format of the data depends on what modes a driver supports, and what
+mode has been selected. lircd obtains supported modes and sets the active mode
+via the ioctl interface, detailed at <xref linkend="lirc_ioctl"/>. The generally
+preferred mode is LIRC_MODE_MODE2, in which packets containing an int value
+describing an IR signal are read from the chardev.</para>
+
+<para>See also <ulink url="http://www.lirc.org/html/technical.html">http://www.lirc.org/html/technical.html</ulink> for more info.</para>
+</section>
+
+<section id="lirc_write">
+<title>LIRC write fop</title>
+
+<para>The data written to the chardev is a pulse/space sequence of integer
+values. Pulses and spaces are only marked implicitly by their position. The
+data must start and end with a pulse, therefore, the data must always include
+an unevent number of samples. The write function must block until the data has
+been transmitted by the hardware.</para>
+</section>
+
+<section id="lirc_ioctl">
+<title>LIRC ioctl fop</title>
+
+<para>The LIRC device's ioctl definition is bound by the ioctl function
+definition of struct file_operations, leaving us with an unsigned int
+for the ioctl command and an unsigned long for the arg. For the purposes
+of ioctl portability across 32-bit and 64-bit, these values are capped
+to their 32-bit sizes.</para>
+
+<para>The following ioctls can be used to change specific hardware settings.
+In general each driver should have a default set of settings. The driver
+implementation is expected to re-apply the default settings when the device
+is closed by user-space, so that every application opening the device can rely
+on working with the default settings initially.</para>
+
+<variablelist>
+  <varlistentry>
+    <term>LIRC_GET_FEATURES</term>
+    <listitem>
+      <para>Obviously, get the underlying hardware device's features. If a driver
+      does not announce support of certain features, calling of the corresponding
+      ioctls is undefined.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_SEND_MODE</term>
+    <listitem>
+      <para>Get supported transmit mode. Only LIRC_MODE_PULSE is supported by lircd.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_REC_MODE</term>
+    <listitem>
+      <para>Get supported receive modes. Only LIRC_MODE_MODE2 and LIRC_MODE_LIRCCODE
+      are supported by lircd.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_SEND_CARRIER</term>
+    <listitem>
+      <para>Get carrier frequency (in Hz) currently used for transmit.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_REC_CARRIER</term>
+    <listitem>
+      <para>Get carrier frequency (in Hz) currently used for IR reception.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_{G,S}ET_{SEND,REC}_DUTY_CYCLE</term>
+    <listitem>
+      <para>Get/set the duty cycle (from 0 to 100) of the carrier signal. Currently,
+      no special meaning is defined for 0 or 100, but this could be used to switch
+      off carrier generation in the future, so these values should be reserved.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_REC_RESOLUTION</term>
+    <listitem>
+      <para>Some receiver have maximum resolution which is defined by internal
+      sample rate or data format limitations. E.g. it's common that signals can
+      only be reported in 50 microsecond steps. This integer value is used by
+      lircd to automatically adjust the aeps tolerance value in the lircd
+      config file.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_M{IN,AX}_TIMEOUT</term>
+    <listitem>
+      <para>Some devices have internal timers that can be used to detect when
+      there's no IR activity for a long time. This can help lircd in detecting
+      that a IR signal is finished and can speed up the decoding process.
+      Returns an integer value with the minimum/maximum timeout that can be
+      set. Some devices have a fixed timeout, in that case both ioctls will
+      return the same value even though the timeout cannot be changed.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_M{IN,AX}_FILTER_{PULSE,SPACE}</term>
+    <listitem>
+      <para>Some devices are able to filter out spikes in the incoming signal
+      using given filter rules. These ioctls return the hardware capabilities
+      that describe the bounds of the possible filters. Filter settings depend
+      on the IR protocols that are expected. lircd derives the settings from
+      all protocols definitions found in its config file.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_LENGTH</term>
+    <listitem>
+      <para>Retrieves the code length in bits (only for LIRC_MODE_LIRCCODE).
+      Reads on the device must be done in blocks matching the bit count.
+      The bit could should be rounded up so that it matches full bytes.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_{SEND,REC}_MODE</term>
+    <listitem>
+      <para>Set send/receive mode. Largely obsolete for send, as only
+      LIRC_MODE_PULSE is supported.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_{SEND,REC}_CARRIER</term>
+    <listitem>
+      <para>Set send/receive carrier (in Hz).</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_TRANSMITTER_MASK</term>
+    <listitem>
+      <para>This enables the given set of transmitters. The first transmitter
+      is encoded by the least significant bit, etc. When an invalid bit mask
+      is given, i.e. a bit is set, even though the device does not have so many
+      transitters, then this ioctl returns the number of available transitters
+      and does nothing otherwise.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_REC_TIMEOUT</term>
+    <listitem>
+      <para>Sets the integer value for IR inactivity timeout (cf.
+      LIRC_GET_MIN_TIMEOUT and LIRC_GET_MAX_TIMEOUT). A value of 0 (if
+      supported by the hardware) disables all hardware timeouts and data should
+      be reported as soon as possible. If the exact value cannot be set, then
+      the next possible value _greater_ than the given value should be set.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_REC_TIMEOUT_REPORTS</term>
+    <listitem>
+      <para>Enable (1) or disable (0) timeout reports in LIRC_MODE_MODE2. By
+      default, timeout reports should be turned off.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_REC_FILTER_{,PULSE,SPACE}</term>
+    <listitem>
+      <para>Pulses/spaces shorter than this are filtered out by hardware. If
+      filters cannot be set independently for pulse/space, the corresponding
+      ioctls must return an error and LIRC_SET_REC_FILTER shall be used instead.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_MEASURE_CARRIER_MODE</term>
+    <listitem>
+      <para>Enable (1)/disable (0) measure mode. If enabled, from the next key
+      press on, the driver will send LIRC_MODE2_FREQUENCY packets. By default
+      this should be turned off.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_REC_{DUTY_CYCLE,CARRIER}_RANGE</term>
+    <listitem>
+      <para>To set a range use LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE
+      with the lower bound first and later LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER
+      with the upper bound.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_NOTIFY_DECODE</term>
+    <listitem>
+      <para>This ioctl is called by lircd whenever a successful decoding of an
+      incoming IR signal could be done. This can be used by supporting hardware
+      to give visual feedback to the user e.g. by flashing a LED.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SETUP_{START,END}</term>
+    <listitem>
+      <para>Setting of several driver parameters can be optimized by encapsulating
+      the according ioctl calls with LIRC_SETUP_START/LIRC_SETUP_END. When a
+      driver receives a LIRC_SETUP_START ioctl it can choose to not commit
+      further setting changes to the hardware until a LIRC_SETUP_END is received.
+      But this is open to the driver implementation and every driver must also
+      handle parameter changes which are not encapsulated by LIRC_SETUP_START
+      and LIRC_SETUP_END. Drivers can also choose to ignore these ioctls.</para>
+    </listitem>
+  </varlistentry>
+</variablelist>
+
+</section>
+</section>
diff --git a/Documentation/DocBook/v4l/remote_controllers.xml b/Documentation/DocBook/v4l/remote_controllers.xml
index 73f5eab..3c3b667 100644
--- a/Documentation/DocBook/v4l/remote_controllers.xml
+++ b/Documentation/DocBook/v4l/remote_controllers.xml
@@ -173,3 +173,5 @@
 <para>This program demonstrates how to replace the keymap tables.</para>
 &sub-keytable-c;
 </section>
+
+&sub-lirc_device_interface;
diff --git a/Documentation/apparmor.txt b/Documentation/apparmor.txt
new file mode 100644
index 0000000..93c1fd7
--- /dev/null
+++ b/Documentation/apparmor.txt
@@ -0,0 +1,39 @@
+--- What is AppArmor? ---
+
+AppArmor is MAC style security extension for the Linux kernel.  It implements
+a task centered policy, with task "profiles" being created and loaded
+from user space.  Tasks on the system that do not have a profile defined for
+them run in an unconfined state which is equivalent to standard Linux DAC
+permissions.
+
+--- How to enable/disable ---
+
+set CONFIG_SECURITY_APPARMOR=y
+
+If AppArmor should be selected as the default security module then
+   set CONFIG_DEFAULT_SECURITY="apparmor"
+   and CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1
+
+Build the kernel
+
+If AppArmor is not the default security module it can be enabled by passing
+security=apparmor on the kernel's command line.
+
+If AppArmor is the default security module it can be disabled by passing
+apparmor=0, security=XXXX (where XXX is valid security module), on the
+kernel's command line
+
+For AppArmor to enforce any restrictions beyond standard Linux DAC permissions
+policy must be loaded into the kernel from user space (see the Documentation
+and tools links).
+
+--- Documentation ---
+
+Documentation can be found on the wiki.
+
+--- Links ---
+
+Mailing List - apparmor@lists.ubuntu.com
+Wiki - http://apparmor.wiki.kernel.org/
+User space tools - https://launchpad.net/apparmor
+Kernel module - git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index 239cbdb..350959f 100644
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -26,7 +26,7 @@
 		"dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
 		"or51211", "or51132_qam", "or51132_vsb", "bluebird",
 		"opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
-		"af9015", "ngene");
+		"af9015", "ngene", "az6027");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -518,11 +518,11 @@
 sub af9015 {
 	my $sourcefile = "download.ashx?file=57";
 	my $url = "http://www.ite.com.tw/EN/Services/$sourcefile";
-	my $hash = "ff5b096ed47c080870eacdab2de33ad6";
+	my $hash = "e3f08935158038d385ad382442f4bb2d";
 	my $outfile = "dvb-usb-af9015.fw";
 	my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
-	my $fwoffset = 0x22708;
-	my $fwlength = 18225;
+	my $fwoffset = 0x25690;
+	my $fwlength = 18725;
 	my ($chunklength, $buf, $rcount);
 
 	checkstandard();
@@ -567,6 +567,23 @@
     "$file1, $file2";
 }
 
+sub az6027{
+    my $file = "AZ6027_Linux_Driver.tar.gz";
+    my $url = "http://linux.terratec.de/files/$file";
+    my $firmware = "dvb-usb-az6027-03.fw";
+
+    wgetfile($file, $url);
+
+    #untar
+    if( system("tar xzvf $file $firmware")){
+        die "failed to untar firmware";
+    }
+    if( system("rm $file")){
+        die ("unable to remove unnecessary files");
+    }
+
+    $firmware;
+}
 # ---------------------------------------------------------------
 # Utilities
 
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 40a9c32..be7030e 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -303,15 +303,6 @@
 
 ---------------------------
 
-What: CONFIG_NF_CT_ACCT
-When: 2.6.29
-Why:  Accounting can now be enabled/disabled without kernel recompilation.
-      Currently used only to set a default value for a feature that is also
-      controlled by a kernel/module/sysfs/sysctl parameter.
-Who:  Krzysztof Piotr Oledzki <ole@ans.pl>
-
----------------------------
-
 What:	sysfs ui for changing p4-clockmod parameters
 When:	September 2009
 Why:	See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and
@@ -377,16 +368,6 @@
 
 ----------------------------
 
-What:	lock_policy_rwsem_* and unlock_policy_rwsem_* will not be
-	exported interface anymore.
-When:	2.6.33
-Why:	cpu_policy_rwsem has a new cleaner definition making it local to
-	cpufreq core and contained inside cpufreq.c. Other dependent
-	drivers should not use it in order to safely avoid lockdep issues.
-Who:	Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
-
-----------------------------
-
 What:	sound-slot/service-* module aliases and related clutters in
 	sound/sound_core.c
 When:	August 2010
@@ -459,57 +440,6 @@
 
 ----------------------------
 
-What:	usbvideo quickcam_messenger driver
-When:	2.6.35
-Files:	drivers/media/video/usbvideo/quickcam_messenger.[ch]
-Why:	obsolete v4l1 driver replaced by gspca_stv06xx
-Who:	Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:	ov511 v4l1 driver
-When:	2.6.35
-Files:	drivers/media/video/ov511.[ch]
-Why:	obsolete v4l1 driver replaced by gspca_ov519
-Who:	Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:	w9968cf v4l1 driver
-When:	2.6.35
-Files:	drivers/media/video/w9968cf*.[ch]
-Why:	obsolete v4l1 driver replaced by gspca_ov519
-Who:	Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:	ovcamchip sensor framework
-When:	2.6.35
-Files:	drivers/media/video/ovcamchip/*
-Why:	Only used by obsoleted v4l1 drivers
-Who:	Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:	stv680 v4l1 driver
-When:	2.6.35
-Files:	drivers/media/video/stv680.[ch]
-Why:	obsolete v4l1 driver replaced by gspca_stv0680
-Who:	Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:	zc0301 v4l driver
-When:	2.6.35
-Files:	drivers/media/video/zc0301/*
-Why:	Duplicate functionality with the gspca_zc3xx driver, zc0301 only
-	supports 2 USB-ID's (because it only supports a limited set of
-	sensors) wich are also supported by the gspca_zc3xx driver
-	(which supports 53 USB-ID's in total)
-Who:	Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
 What:	sysfs-class-rfkill state file
 When:	Feb 2014
 Files:	net/rfkill/core.c
@@ -538,17 +468,6 @@
 
 ----------------------------
 
-What:	KVM memory aliases support
-When:	July 2010
-Why:	Memory aliasing support is used for speeding up guest vga access
-	through the vga windows.
-
-	Modern userspace no longer uses this feature, so it's just bitrotted
-	code and can be removed with no impact.
-Who:	Avi Kivity <avi@redhat.com>
-
-----------------------------
-
 What:	xtime, wall_to_monotonic
 When:	2.6.36+
 Files:	kernel/time/timekeeping.c include/linux/time.h
@@ -559,16 +478,6 @@
 
 ----------------------------
 
-What:	KVM kernel-allocated memory slots
-When:	July 2010
-Why:	Since 2.6.25, kvm supports user-allocated memory slots, which are
-	much more flexible than kernel-allocated slots.  All current userspace
-	supports the newer interface and this code can be removed with no
-	impact.
-Who:	Avi Kivity <avi@redhat.com>
-
-----------------------------
-
 What:	KVM paravirt mmu host support
 When:	January 2011
 Why:	The paravirt mmu host support is slower than non-paravirt mmu, both
diff --git a/Documentation/filesystems/nfs/nfsroot.txt b/Documentation/filesystems/nfs/nfsroot.txt
index 3ba0b94..f2430a7 100644
--- a/Documentation/filesystems/nfs/nfsroot.txt
+++ b/Documentation/filesystems/nfs/nfsroot.txt
@@ -124,6 +124,8 @@
 
   <hostname>	Name of the client. May be supplied by autoconfiguration,
   		but its absence will not trigger autoconfiguration.
+		If specified and DHCP is used, the user provided hostname will
+		be carried in the DHCP request to hopefully update DNS record.
 
   		Default: Client IP address is used in ASCII notation.
 
diff --git a/Documentation/input/multi-touch-protocol.txt b/Documentation/input/multi-touch-protocol.txt
index c0fc1c7..bdcba154 100644
--- a/Documentation/input/multi-touch-protocol.txt
+++ b/Documentation/input/multi-touch-protocol.txt
@@ -6,31 +6,149 @@
 Introduction
 ------------
 
-In order to utilize the full power of the new multi-touch devices, a way to
-report detailed finger data to user space is needed. This document
-describes the multi-touch (MT) protocol which allows kernel drivers to
-report details for an arbitrary number of fingers.
+In order to utilize the full power of the new multi-touch and multi-user
+devices, a way to report detailed data from multiple contacts, i.e.,
+objects in direct contact with the device surface, is needed.  This
+document describes the multi-touch (MT) protocol which allows kernel
+drivers to report details for an arbitrary number of contacts.
+
+The protocol is divided into two types, depending on the capabilities of the
+hardware. For devices handling anonymous contacts (type A), the protocol
+describes how to send the raw data for all contacts to the receiver. For
+devices capable of tracking identifiable contacts (type B), the protocol
+describes how to send updates for individual contacts via event slots.
 
 
-Usage
------
+Protocol Usage
+--------------
 
-Anonymous finger details are sent sequentially as separate packets of ABS
-events. Only the ABS_MT events are recognized as part of a finger
-packet. The end of a packet is marked by calling the input_mt_sync()
-function, which generates a SYN_MT_REPORT event. This instructs the
-receiver to accept the data for the current finger and prepare to receive
-another. The end of a multi-touch transfer is marked by calling the usual
+Contact details are sent sequentially as separate packets of ABS_MT
+events. Only the ABS_MT events are recognized as part of a contact
+packet. Since these events are ignored by current single-touch (ST)
+applications, the MT protocol can be implemented on top of the ST protocol
+in an existing driver.
+
+Drivers for type A devices separate contact packets by calling
+input_mt_sync() at the end of each packet. This generates a SYN_MT_REPORT
+event, which instructs the receiver to accept the data for the current
+contact and prepare to receive another.
+
+Drivers for type B devices separate contact packets by calling
+input_mt_slot(), with a slot as argument, at the beginning of each packet.
+This generates an ABS_MT_SLOT event, which instructs the receiver to
+prepare for updates of the given slot.
+
+All drivers mark the end of a multi-touch transfer by calling the usual
 input_sync() function. This instructs the receiver to act upon events
-accumulated since last EV_SYN/SYN_REPORT and prepare to receive a new
-set of events/packets.
+accumulated since last EV_SYN/SYN_REPORT and prepare to receive a new set
+of events/packets.
+
+The main difference between the stateless type A protocol and the stateful
+type B slot protocol lies in the usage of identifiable contacts to reduce
+the amount of data sent to userspace. The slot protocol requires the use of
+the ABS_MT_TRACKING_ID, either provided by the hardware or computed from
+the raw data [5].
+
+For type A devices, the kernel driver should generate an arbitrary
+enumeration of the full set of anonymous contacts currently on the
+surface. The order in which the packets appear in the event stream is not
+important.  Event filtering and finger tracking is left to user space [3].
+
+For type B devices, the kernel driver should associate a slot with each
+identified contact, and use that slot to propagate changes for the contact.
+Creation, replacement and destruction of contacts is achieved by modifying
+the ABS_MT_TRACKING_ID of the associated slot.  A non-negative tracking id
+is interpreted as a contact, and the value -1 denotes an unused slot.  A
+tracking id not previously present is considered new, and a tracking id no
+longer present is considered removed.  Since only changes are propagated,
+the full state of each initiated contact has to reside in the receiving
+end.  Upon receiving an MT event, one simply updates the appropriate
+attribute of the current slot.
+
+
+Protocol Example A
+------------------
+
+Here is what a minimal event sequence for a two-contact touch would look
+like for a type A device:
+
+   ABS_MT_POSITION_X x[0]
+   ABS_MT_POSITION_Y y[0]
+   SYN_MT_REPORT
+   ABS_MT_POSITION_X x[1]
+   ABS_MT_POSITION_Y y[1]
+   SYN_MT_REPORT
+   SYN_REPORT
+
+The sequence after moving one of the contacts looks exactly the same; the
+raw data for all present contacts are sent between every synchronization
+with SYN_REPORT.
+
+Here is the sequence after lifting the first contact:
+
+   ABS_MT_POSITION_X x[1]
+   ABS_MT_POSITION_Y y[1]
+   SYN_MT_REPORT
+   SYN_REPORT
+
+And here is the sequence after lifting the second contact:
+
+   SYN_MT_REPORT
+   SYN_REPORT
+
+If the driver reports one of BTN_TOUCH or ABS_PRESSURE in addition to the
+ABS_MT events, the last SYN_MT_REPORT event may be omitted. Otherwise, the
+last SYN_REPORT will be dropped by the input core, resulting in no
+zero-contact event reaching userland.
+
+
+Protocol Example B
+------------------
+
+Here is what a minimal event sequence for a two-contact touch would look
+like for a type B device:
+
+   ABS_MT_SLOT 0
+   ABS_MT_TRACKING_ID 45
+   ABS_MT_POSITION_X x[0]
+   ABS_MT_POSITION_Y y[0]
+   ABS_MT_SLOT 1
+   ABS_MT_TRACKING_ID 46
+   ABS_MT_POSITION_X x[1]
+   ABS_MT_POSITION_Y y[1]
+   SYN_REPORT
+
+Here is the sequence after moving contact 45 in the x direction:
+
+   ABS_MT_SLOT 0
+   ABS_MT_POSITION_X x[0]
+   SYN_REPORT
+
+Here is the sequence after lifting the contact in slot 0:
+
+   ABS_MT_TRACKING_ID -1
+   SYN_REPORT
+
+The slot being modified is already 0, so the ABS_MT_SLOT is omitted.  The
+message removes the association of slot 0 with contact 45, thereby
+destroying contact 45 and freeing slot 0 to be reused for another contact.
+
+Finally, here is the sequence after lifting the second contact:
+
+   ABS_MT_SLOT 1
+   ABS_MT_TRACKING_ID -1
+   SYN_REPORT
+
+
+Event Usage
+-----------
 
 A set of ABS_MT events with the desired properties is defined. The events
 are divided into categories, to allow for partial implementation.  The
 minimum set consists of ABS_MT_POSITION_X and ABS_MT_POSITION_Y, which
-allows for multiple fingers to be tracked.  If the device supports it, the
+allows for multiple contacts to be tracked.  If the device supports it, the
 ABS_MT_TOUCH_MAJOR and ABS_MT_WIDTH_MAJOR may be used to provide the size
-of the contact area and approaching finger, respectively.
+of the contact area and approaching contact, respectively.
 
 The TOUCH and WIDTH parameters have a geometrical interpretation; imagine
 looking through a window at someone gently holding a finger against the
@@ -41,56 +159,26 @@
 ABS_MT_WIDTH_MAJOR. Now imagine the person pressing the finger harder
 against the glass. The inner region will increase, and in general, the
 ratio ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR, which is always smaller than
-unity, is related to the finger pressure. For pressure-based devices,
+unity, is related to the contact pressure. For pressure-based devices,
 ABS_MT_PRESSURE may be used to provide the pressure on the contact area
 instead.
 
-In addition to the MAJOR parameters, the oval shape of the finger can be
+In addition to the MAJOR parameters, the oval shape of the contact can be
 described by adding the MINOR parameters, such that MAJOR and MINOR are the
 major and minor axis of an ellipse. Finally, the orientation of the oval
 shape can be describe with the ORIENTATION parameter.
 
 The ABS_MT_TOOL_TYPE may be used to specify whether the touching tool is a
-finger or a pen or something else.  Devices with more granular information
+contact or a pen or something else.  Devices with more granular information
 may specify general shapes as blobs, i.e., as a sequence of rectangular
 shapes grouped together by an ABS_MT_BLOB_ID. Finally, for the few devices
 that currently support it, the ABS_MT_TRACKING_ID event may be used to
-report finger tracking from hardware [5].
+report contact tracking from hardware [5].
 
-Here is what a minimal event sequence for a two-finger touch would look
-like:
-
-   ABS_MT_POSITION_X
-   ABS_MT_POSITION_Y
-   SYN_MT_REPORT
-   ABS_MT_POSITION_X
-   ABS_MT_POSITION_Y
-   SYN_MT_REPORT
-   SYN_REPORT
-
-Here is the sequence after lifting one of the fingers:
-
-   ABS_MT_POSITION_X
-   ABS_MT_POSITION_Y
-   SYN_MT_REPORT
-   SYN_REPORT
-
-And here is the sequence after lifting the remaining finger:
-
-   SYN_MT_REPORT
-   SYN_REPORT
-
-If the driver reports one of BTN_TOUCH or ABS_PRESSURE in addition to the
-ABS_MT events, the last SYN_MT_REPORT event may be omitted. Otherwise, the
-last SYN_REPORT will be dropped by the input core, resulting in no
-zero-finger event reaching userland.
 
 Event Semantics
 ---------------
 
-The word "contact" is used to describe a tool which is in direct contact
-with the surface. A finger, a pen or a rubber all classify as contacts.
-
 ABS_MT_TOUCH_MAJOR
 
 The length of the major axis of the contact. The length should be given in
@@ -157,15 +245,16 @@
 ABS_MT_BLOB_ID
 
 The BLOB_ID groups several packets together into one arbitrarily shaped
-contact. This is a low-level anonymous grouping, and should not be confused
-with the high-level trackingID [5]. Most kernel drivers will not have blob
-capability, and can safely omit the event.
+contact. This is a low-level anonymous grouping for type A devices, and
+should not be confused with the high-level trackingID [5]. Most type A
+devices do not have blob capability, so drivers can safely omit this event.
 
 ABS_MT_TRACKING_ID
 
 The TRACKING_ID identifies an initiated contact throughout its life cycle
-[5]. There are currently only a few devices that support it, so this event
-should normally be omitted.
+[5]. This event is mandatory for type B devices. The value range of the
+TRACKING_ID should be large enough to ensure unique identification of a
+contact maintained over an extended period of time.
 
 
 Event Computation
@@ -192,20 +281,11 @@
 Finger Tracking
 ---------------
 
-The kernel driver should generate an arbitrary enumeration of the set of
-anonymous contacts currently on the surface. The order in which the packets
-appear in the event stream is not important.
-
 The process of finger tracking, i.e., to assign a unique trackingID to each
-initiated contact on the surface, is left to user space; preferably the
-multi-touch X driver [3]. In that driver, the trackingID stays the same and
-unique until the contact vanishes (when the finger leaves the surface). The
-problem of assigning a set of anonymous fingers to a set of identified
-fingers is a euclidian bipartite matching problem at each event update, and
-relies on a sufficiently rapid update rate.
-
-There are a few devices that support trackingID in hardware. User space can
-make use of these native identifiers to reduce bandwidth and cpu usage.
+initiated contact on the surface, is a Euclidian Bipartite Matching
+problem.  At each event synchronization, the set of actual contacts is
+matched to the set of contacts from the previous synchronization. A full
+implementation can be found in [3].
 
 
 Gestures
diff --git a/Documentation/isdn/INTERFACE.CAPI b/Documentation/isdn/INTERFACE.CAPI
index f172091..309eb5e 100644
--- a/Documentation/isdn/INTERFACE.CAPI
+++ b/Documentation/isdn/INTERFACE.CAPI
@@ -113,12 +113,16 @@
 int (*load_firmware)(struct capi_ctr *ctrlr, capiloaddata *ldata)
 	(optional) pointer to a callback function for sending firmware and
 	configuration data to the device
+	The function may return before the operation has completed.
+	Completion must be signalled by a call to capi_ctr_ready().
 	Return value: 0 on success, error code on error
 	Called in process context.
 
 void (*reset_ctr)(struct capi_ctr *ctrlr)
-	(optional) pointer to a callback function for performing a reset on
-	the device, releasing all registered applications
+	(optional) pointer to a callback function for stopping the device,
+	releasing all registered applications
+	The function may return before the operation has completed.
+	Completion must be signalled by a call to capi_ctr_down().
 	Called in process context.
 
 void (*register_appl)(struct capi_ctr *ctrlr, u16 applid,
diff --git a/Documentation/isdn/README.gigaset b/Documentation/isdn/README.gigaset
index e472df8..ef3343e 100644
--- a/Documentation/isdn/README.gigaset
+++ b/Documentation/isdn/README.gigaset
@@ -47,9 +47,9 @@
 
 1.2. Software
      --------
-     The driver works with ISDN4linux and so can be used with any software
-     which is able to use ISDN4linux for ISDN connections (voice or data).
-     Experimental Kernel CAPI support is available as a compilation option.
+     The driver works with the Kernel CAPI subsystem as well as the old
+     ISDN4Linux subsystem, so it can be used with any software which is able
+     to use CAPI 2.0 or ISDN4Linux for ISDN connections (voice or data).
 
      There are some user space tools available at
      http://sourceforge.net/projects/gigaset307x/
@@ -152,61 +152,42 @@
      - GIGVER_FWBASE: retrieve the firmware version of the base
      Upon return, version[] is filled with the requested version information.
 
-2.3. ISDN4linux
-     ----------
-     This is the "normal" mode of operation. After loading the module you can
-     set up the ISDN system just as you'd do with any ISDN card supported by
-     the ISDN4Linux subsystem. Most distributions provide some configuration
-     utility. If not, you can use some HOWTOs like
-         http://www.linuxhaven.de/dlhp/HOWTO/DE-ISDN-HOWTO-5.html
-     If this doesn't work, because you have some device like SX100 where
-     debug output (see section 3.2.) shows something like this when dialing
-         CMD Received: ERROR
-         Available Params: 0
-         Connection State: 0, Response: -1
-         gigaset_process_response: resp_code -1 in ConState 0 !
-         Timeout occurred
-     you probably need to use unimodem mode. (see section 2.5.)
-
-2.4. CAPI
+2.3. CAPI
      ----
      If the driver is compiled with CAPI support (kernel configuration option
-     GIGASET_CAPI, experimental) it can also be used with CAPI 2.0 kernel and
-     user space applications. For user space access, the module capi.ko must
-     be loaded. The capiinit command (included in the capi4k-utils package)
-     does this for you.
+     GIGASET_CAPI) the devices will show up as CAPI controllers as soon as the
+     corresponding driver module is loaded, and can then be used with CAPI 2.0
+     kernel and user space applications. For user space access, the module
+     capi.ko must be loaded.
 
-     The CAPI variant of the driver supports legacy ISDN4Linux applications
-     via the capidrv compatibility driver. The kernel module capidrv.ko must
-     be loaded explicitly with the command
+     Legacy ISDN4Linux applications are supported via the capidrv
+     compatibility driver. The kernel module capidrv.ko must be loaded
+     explicitly with the command
         modprobe capidrv
      if needed, and cannot be unloaded again without unloading the driver
      first. (These are limitations of capidrv.)
 
-     The note about unimodem mode in the preceding section applies here, too.
+     Most distributions handle loading and unloading of the various CAPI
+     modules automatically via the command capiinit(1) from the capi4k-utils
+     package or a similar mechanism. Note that capiinit(1) cannot unload the
+     Gigaset drivers because it doesn't support more than one module per
+     driver.
+
+2.4. ISDN4Linux
+     ----------
+     If the driver is compiled without CAPI support (native ISDN4Linux
+     variant), it registers the device with the legacy ISDN4Linux subsystem
+     after loading the module. It can then be used with ISDN4Linux
+     applications only. Most distributions provide some configuration utility
+     for setting up that subsystem. Otherwise you can use some HOWTOs like
+         http://www.linuxhaven.de/dlhp/HOWTO/DE-ISDN-HOWTO-5.html
+
 
 2.5. Unimodem mode
      -------------
-     This is needed for some devices [e.g. SX100] as they have problems with
-     the "normal" commands.
-
-     If you have installed the command line tool gigacontr, you can enter
-     unimodem mode using
-         gigacontr --mode unimodem
-     You can switch back using
-         gigacontr --mode isdn
-
-     You can also put the driver directly into Unimodem mode when it's loaded,
-     by passing the module parameter startmode=0 to the hardware specific
-     module, e.g.
-	modprobe usb_gigaset startmode=0
-     or by adding a line like
-	options usb_gigaset startmode=0
-     to an appropriate module configuration file, like /etc/modprobe.d/gigaset
-     or /etc/modprobe.conf.local.
-
      In this mode the device works like a modem connected to a serial port
      (the /dev/ttyGU0, ... mentioned above) which understands the commands
+
          ATZ                 init, reset
              => OK or ERROR
          ATD
@@ -234,6 +215,31 @@
      to an appropriate module configuration file, like /etc/modprobe.d/gigaset
      or /etc/modprobe.conf.local.
 
+     Unimodem mode is needed for making some devices [e.g. SX100] work which
+     do not support the regular Gigaset command set. If debug output (see
+     section 3.2.) shows something like this when dialing:
+         CMD Received: ERROR
+         Available Params: 0
+         Connection State: 0, Response: -1
+         gigaset_process_response: resp_code -1 in ConState 0 !
+         Timeout occurred
+     then switching to unimodem mode may help.
+
+     If you have installed the command line tool gigacontr, you can enter
+     unimodem mode using
+         gigacontr --mode unimodem
+     You can switch back using
+         gigacontr --mode isdn
+
+     You can also put the driver directly into Unimodem mode when it's loaded,
+     by passing the module parameter startmode=0 to the hardware specific
+     module, e.g.
+	modprobe usb_gigaset startmode=0
+     or by adding a line like
+	options usb_gigaset startmode=0
+     to an appropriate module configuration file, like /etc/modprobe.d/gigaset
+     or /etc/modprobe.conf.local.
+
 2.6. Call-ID (CID) mode
      ------------------
      Call-IDs are numbers used to tag commands to, and responses from, the
@@ -263,7 +269,22 @@
      change its CID mode while the driver is loaded, eg.
         echo 0 > /sys/class/tty/ttyGU0/cidmode
 
-2.7. Unregistered Wireless Devices (M101/M105)
+2.7. Dialing Numbers
+     ---------------
+     The called party number provided by an application for dialing out must
+     be a public network number according to the local dialing plan, without
+     any dial prefix for getting an outside line.
+
+     Internal calls can be made by providing an internal extension number
+     prefixed with "**" (two asterisks) as the called party number. So to dial
+     eg. the first registered DECT handset, give "**11" as the called party
+     number. Dialing "***" (three asterisks) calls all extensions
+     simultaneously (global call).
+
+     This holds for both CAPI 2.0 and ISDN4Linux applications. Unimodem mode
+     does not support internal calls.
+
+2.8. Unregistered Wireless Devices (M101/M105)
      -----------------------------------------
      The main purpose of the ser_gigaset and usb_gigaset drivers is to allow
      the M101 and M105 wireless devices to be used as ISDN devices for ISDN
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 2b2407d..d9239d5 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -93,6 +93,7 @@
 			Documentation/scsi/.
 	SECURITY Different security models are enabled.
 	SELINUX SELinux support is enabled.
+	APPARMOR AppArmor support is enabled.
 	SERIAL	Serial support is enabled.
 	SH	SuperH architecture is enabled.
 	SMP	The kernel is an SMP kernel.
@@ -1597,8 +1598,7 @@
 			[NETFILTER] Enable connection tracking flow accounting
 			0 to disable accounting
 			1 to enable accounting
-			Default value depends on CONFIG_NF_CT_ACCT that is
-			going to be removed in 2.6.29.
+			Default value is 0.
 
 	nfsaddrs=	[NFS]
 			See Documentation/filesystems/nfs/nfsroot.txt.
@@ -2312,6 +2312,13 @@
 			If enabled at boot time, /selinux/disable can be used
 			later to disable prior to initial policy load.
 
+	apparmor=	[APPARMOR] Disable or enable AppArmor at boot time
+			Format: { "0" | "1" }
+			See security/apparmor/Kconfig help text
+			0 -- disable.
+			1 -- enable.
+			Default value is set via kernel config option.
+
 	serialnumber	[BUGS=X86-32]
 
 	shapers=	[NET]
diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt
index a237518..5f5b649 100644
--- a/Documentation/kvm/api.txt
+++ b/Documentation/kvm/api.txt
@@ -126,6 +126,10 @@
 kvm adjusts nmsrs to reflect the actual number of msrs and fills in
 the indices array with their numbers.
 
+Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are
+not returned in the MSR list, as different vcpus can have a different number
+of banks, as set via the KVM_X86_SETUP_MCE ioctl.
+
 4.4 KVM_CHECK_EXTENSION
 
 Capability: basic
@@ -160,29 +164,7 @@
 Parameters: struct kvm_memory_region (in)
 Returns: 0 on success, -1 on error
 
-struct kvm_memory_region {
-	__u32 slot;
-	__u32 flags;
-	__u64 guest_phys_addr;
-	__u64 memory_size; /* bytes */
-};
-
-/* for kvm_memory_region::flags */
-#define KVM_MEM_LOG_DIRTY_PAGES  1UL
-
-This ioctl allows the user to create or modify a guest physical memory
-slot.  When changing an existing slot, it may be moved in the guest
-physical memory space, or its flags may be modified.  It may not be
-resized.  Slots may not overlap.
-
-The flags field supports just one flag, KVM_MEM_LOG_DIRTY_PAGES, which
-instructs kvm to keep track of writes to memory within the slot.  See
-the KVM_GET_DIRTY_LOG ioctl.
-
-It is recommended to use the KVM_SET_USER_MEMORY_REGION ioctl instead
-of this API, if available.  This newer API allows placing guest memory
-at specified locations in the host address space, yielding better
-control and easy access.
+This ioctl is obsolete and has been removed.
 
 4.6 KVM_CREATE_VCPU
 
@@ -226,17 +208,7 @@
 Parameters: struct kvm_memory_alias (in)
 Returns: 0 (success), -1 (error)
 
-struct kvm_memory_alias {
-	__u32 slot;  /* this has a different namespace than memory slots */
-	__u32 flags;
-	__u64 guest_phys_addr;
-	__u64 memory_size;
-	__u64 target_phys_addr;
-};
-
-Defines a guest physical address space region as an alias to another
-region.  Useful for aliased address, for example the VGA low memory
-window. Should not be used with userspace memory.
+This ioctl is obsolete and has been removed.
 
 4.9 KVM_RUN
 
@@ -892,6 +864,174 @@
 This ioctl is only useful after KVM_CREATE_IRQCHIP.  Without an in-kernel
 irqchip, the multiprocessing state must be maintained by userspace.
 
+4.39 KVM_SET_IDENTITY_MAP_ADDR
+
+Capability: KVM_CAP_SET_IDENTITY_MAP_ADDR
+Architectures: x86
+Type: vm ioctl
+Parameters: unsigned long identity (in)
+Returns: 0 on success, -1 on error
+
+This ioctl defines the physical address of a one-page region in the guest
+physical address space.  The region must be within the first 4GB of the
+guest physical address space and must not conflict with any memory slot
+or any mmio address.  The guest may malfunction if it accesses this memory
+region.
+
+This ioctl is required on Intel-based hosts.  This is needed on Intel hardware
+because of a quirk in the virtualization implementation (see the internals
+documentation when it pops into existence).
+
+4.40 KVM_SET_BOOT_CPU_ID
+
+Capability: KVM_CAP_SET_BOOT_CPU_ID
+Architectures: x86, ia64
+Type: vm ioctl
+Parameters: unsigned long vcpu_id
+Returns: 0 on success, -1 on error
+
+Define which vcpu is the Bootstrap Processor (BSP).  Values are the same
+as the vcpu id in KVM_CREATE_VCPU.  If this ioctl is not called, the default
+is vcpu 0.
+
+4.41 KVM_GET_XSAVE
+
+Capability: KVM_CAP_XSAVE
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xsave (out)
+Returns: 0 on success, -1 on error
+
+struct kvm_xsave {
+	__u32 region[1024];
+};
+
+This ioctl would copy current vcpu's xsave struct to the userspace.
+
+4.42 KVM_SET_XSAVE
+
+Capability: KVM_CAP_XSAVE
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xsave (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_xsave {
+	__u32 region[1024];
+};
+
+This ioctl would copy userspace's xsave struct to the kernel.
+
+4.43 KVM_GET_XCRS
+
+Capability: KVM_CAP_XCRS
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xcrs (out)
+Returns: 0 on success, -1 on error
+
+struct kvm_xcr {
+	__u32 xcr;
+	__u32 reserved;
+	__u64 value;
+};
+
+struct kvm_xcrs {
+	__u32 nr_xcrs;
+	__u32 flags;
+	struct kvm_xcr xcrs[KVM_MAX_XCRS];
+	__u64 padding[16];
+};
+
+This ioctl would copy current vcpu's xcrs to the userspace.
+
+4.44 KVM_SET_XCRS
+
+Capability: KVM_CAP_XCRS
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xcrs (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_xcr {
+	__u32 xcr;
+	__u32 reserved;
+	__u64 value;
+};
+
+struct kvm_xcrs {
+	__u32 nr_xcrs;
+	__u32 flags;
+	struct kvm_xcr xcrs[KVM_MAX_XCRS];
+	__u64 padding[16];
+};
+
+This ioctl would set vcpu's xcr to the value userspace specified.
+
+4.45 KVM_GET_SUPPORTED_CPUID
+
+Capability: KVM_CAP_EXT_CPUID
+Architectures: x86
+Type: system ioctl
+Parameters: struct kvm_cpuid2 (in/out)
+Returns: 0 on success, -1 on error
+
+struct kvm_cpuid2 {
+	__u32 nent;
+	__u32 padding;
+	struct kvm_cpuid_entry2 entries[0];
+};
+
+#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX 1
+#define KVM_CPUID_FLAG_STATEFUL_FUNC    2
+#define KVM_CPUID_FLAG_STATE_READ_NEXT  4
+
+struct kvm_cpuid_entry2 {
+	__u32 function;
+	__u32 index;
+	__u32 flags;
+	__u32 eax;
+	__u32 ebx;
+	__u32 ecx;
+	__u32 edx;
+	__u32 padding[3];
+};
+
+This ioctl returns x86 cpuid features which are supported by both the hardware
+and kvm.  Userspace can use the information returned by this ioctl to
+construct cpuid information (for KVM_SET_CPUID2) that is consistent with
+hardware, kernel, and userspace capabilities, and with user requirements (for
+example, the user may wish to constrain cpuid to emulate older hardware,
+or for feature consistency across a cluster).
+
+Userspace invokes KVM_GET_SUPPORTED_CPUID by passing a kvm_cpuid2 structure
+with the 'nent' field indicating the number of entries in the variable-size
+array 'entries'.  If the number of entries is too low to describe the cpu
+capabilities, an error (E2BIG) is returned.  If the number is too high,
+the 'nent' field is adjusted and an error (ENOMEM) is returned.  If the
+number is just right, the 'nent' field is adjusted to the number of valid
+entries in the 'entries' array, which is then filled.
+
+The entries returned are the host cpuid as returned by the cpuid instruction,
+with unknown or unsupported features masked out.  The fields in each entry
+are defined as follows:
+
+  function: the eax value used to obtain the entry
+  index: the ecx value used to obtain the entry (for entries that are
+         affected by ecx)
+  flags: an OR of zero or more of the following:
+        KVM_CPUID_FLAG_SIGNIFCANT_INDEX:
+           if the index field is valid
+        KVM_CPUID_FLAG_STATEFUL_FUNC:
+           if cpuid for this function returns different values for successive
+           invocations; there will be several entries with the same function,
+           all with this flag set
+        KVM_CPUID_FLAG_STATE_READ_NEXT:
+           for KVM_CPUID_FLAG_STATEFUL_FUNC entries, set if this entry is
+           the first entry to be read by a cpu
+   eax, ebx, ecx, edx: the values returned by the cpuid instruction for
+         this function/index combination
+
 5. The kvm_run structure
 
 Application code obtains a pointer to the kvm_run structure by
diff --git a/Documentation/kvm/mmu.txt b/Documentation/kvm/mmu.txt
index aaed6ab..142cc51 100644
--- a/Documentation/kvm/mmu.txt
+++ b/Documentation/kvm/mmu.txt
@@ -77,10 +77,10 @@
 
 Guest memory (gpa) is part of the user address space of the process that is
 using kvm.  Userspace defines the translation between guest addresses and user
-addresses (gpa->hva); note that two gpas may alias to the same gva, but not
+addresses (gpa->hva); note that two gpas may alias to the same hva, but not
 vice versa.
 
-These gvas may be backed using any method available to the host: anonymous
+These hvas may be backed using any method available to the host: anonymous
 memory, file backed memory, and device memory.  Memory might be paged by the
 host at any time.
 
@@ -161,7 +161,7 @@
   role.cr4_pae:
     Contains the value of cr4.pae for which the page is valid (e.g. whether
     32-bit or 64-bit gptes are in use).
-  role.cr4_nxe:
+  role.nxe:
     Contains the value of efer.nxe for which the page is valid.
   role.cr0_wp:
     Contains the value of cr0.wp for which the page is valid.
@@ -180,7 +180,9 @@
     guest pages as leaves.
   gfns:
     An array of 512 guest frame numbers, one for each present pte.  Used to
-    perform a reverse map from a pte to a gfn.
+    perform a reverse map from a pte to a gfn. When role.direct is set, any
+    element of this array can be calculated from the gfn field when used, in
+    this case, the array of gfns is not allocated. See role.direct and gfn.
   slot_bitmap:
     A bitmap containing one bit per memory slot.  If the page contains a pte
     mapping a page from memory slot n, then bit n of slot_bitmap will be set
@@ -296,6 +298,48 @@
   - look up affected sptes through reverse map
   - drop (or update) translations
 
+Emulating cr0.wp
+================
+
+If tdp is not enabled, the host must keep cr0.wp=1 so page write protection
+works for the guest kernel, not guest guest userspace.  When the guest
+cr0.wp=1, this does not present a problem.  However when the guest cr0.wp=0,
+we cannot map the permissions for gpte.u=1, gpte.w=0 to any spte (the
+semantics require allowing any guest kernel access plus user read access).
+
+We handle this by mapping the permissions to two possible sptes, depending
+on fault type:
+
+- kernel write fault: spte.u=0, spte.w=1 (allows full kernel access,
+  disallows user access)
+- read fault: spte.u=1, spte.w=0 (allows full read access, disallows kernel
+  write access)
+
+(user write faults generate a #PF)
+
+Large pages
+===========
+
+The mmu supports all combinations of large and small guest and host pages.
+Supported page sizes include 4k, 2M, 4M, and 1G.  4M pages are treated as
+two separate 2M pages, on both guest and host, since the mmu always uses PAE
+paging.
+
+To instantiate a large spte, four constraints must be satisfied:
+
+- the spte must point to a large host page
+- the guest pte must be a large pte of at least equivalent size (if tdp is
+  enabled, there is no guest pte and this condition is satisified)
+- if the spte will be writeable, the large page frame may not overlap any
+  write-protected pages
+- the guest page must be wholly contained by a single memory slot
+
+To check the last two conditions, the mmu maintains a ->write_count set of
+arrays for each memory slot and large page size.  Every write protected page
+causes its write_count to be incremented, thus preventing instantiation of
+a large spte.  The frames at the end of an unaligned memory slot have
+artificically inflated ->write_counts so they can never be instantiated.
+
 Further reading
 ===============
 
diff --git a/Documentation/kvm/msr.txt b/Documentation/kvm/msr.txt
new file mode 100644
index 0000000..8ddcfe8
--- /dev/null
+++ b/Documentation/kvm/msr.txt
@@ -0,0 +1,153 @@
+KVM-specific MSRs.
+Glauber Costa <glommer@redhat.com>, Red Hat Inc, 2010
+=====================================================
+
+KVM makes use of some custom MSRs to service some requests.
+At present, this facility is only used by kvmclock.
+
+Custom MSRs have a range reserved for them, that goes from
+0x4b564d00 to 0x4b564dff. There are MSRs outside this area,
+but they are deprecated and their use is discouraged.
+
+Custom MSR list
+--------
+
+The current supported Custom MSR list is:
+
+MSR_KVM_WALL_CLOCK_NEW:   0x4b564d00
+
+	data: 4-byte alignment physical address of a memory area which must be
+	in guest RAM. This memory is expected to hold a copy of the following
+	structure:
+
+	struct pvclock_wall_clock {
+		u32   version;
+		u32   sec;
+		u32   nsec;
+	} __attribute__((__packed__));
+
+	whose data will be filled in by the hypervisor. The hypervisor is only
+	guaranteed to update this data at the moment of MSR write.
+	Users that want to reliably query this information more than once have
+	to write more than once to this MSR. Fields have the following meanings:
+
+		version: guest has to check version before and after grabbing
+		time information and check that they are both equal and even.
+		An odd version indicates an in-progress update.
+
+		sec: number of seconds for wallclock.
+
+		nsec: number of nanoseconds for wallclock.
+
+	Note that although MSRs are per-CPU entities, the effect of this
+	particular MSR is global.
+
+	Availability of this MSR must be checked via bit 3 in 0x4000001 cpuid
+	leaf prior to usage.
+
+MSR_KVM_SYSTEM_TIME_NEW:  0x4b564d01
+
+	data: 4-byte aligned physical address of a memory area which must be in
+	guest RAM, plus an enable bit in bit 0. This memory is expected to hold
+	a copy of the following structure:
+
+	struct pvclock_vcpu_time_info {
+		u32   version;
+		u32   pad0;
+		u64   tsc_timestamp;
+		u64   system_time;
+		u32   tsc_to_system_mul;
+		s8    tsc_shift;
+		u8    flags;
+		u8    pad[2];
+	} __attribute__((__packed__)); /* 32 bytes */
+
+	whose data will be filled in by the hypervisor periodically. Only one
+	write, or registration, is needed for each VCPU. The interval between
+	updates of this structure is arbitrary and implementation-dependent.
+	The hypervisor may update this structure at any time it sees fit until
+	anything with bit0 == 0 is written to it.
+
+	Fields have the following meanings:
+
+		version: guest has to check version before and after grabbing
+		time information and check that they are both equal and even.
+		An odd version indicates an in-progress update.
+
+		tsc_timestamp: the tsc value at the current VCPU at the time
+		of the update of this structure. Guests can subtract this value
+		from current tsc to derive a notion of elapsed time since the
+		structure update.
+
+		system_time: a host notion of monotonic time, including sleep
+		time at the time this structure was last updated. Unit is
+		nanoseconds.
+
+		tsc_to_system_mul: a function of the tsc frequency. One has
+		to multiply any tsc-related quantity by this value to get
+		a value in nanoseconds, besides dividing by 2^tsc_shift
+
+		tsc_shift: cycle to nanosecond divider, as a power of two, to
+		allow for shift rights. One has to shift right any tsc-related
+		quantity by this value to get a value in nanoseconds, besides
+		multiplying by tsc_to_system_mul.
+
+		With this information, guests can derive per-CPU time by
+		doing:
+
+			time = (current_tsc - tsc_timestamp)
+			time = (time * tsc_to_system_mul) >> tsc_shift
+			time = time + system_time
+
+		flags: bits in this field indicate extended capabilities
+		coordinated between the guest and the hypervisor. Availability
+		of specific flags has to be checked in 0x40000001 cpuid leaf.
+		Current flags are:
+
+		 flag bit   | cpuid bit    | meaning
+		-------------------------------------------------------------
+			    |	           | time measures taken across
+		     0      |	   24      | multiple cpus are guaranteed to
+			    |		   | be monotonic
+		-------------------------------------------------------------
+
+	Availability of this MSR must be checked via bit 3 in 0x4000001 cpuid
+	leaf prior to usage.
+
+
+MSR_KVM_WALL_CLOCK:  0x11
+
+	data and functioning: same as MSR_KVM_WALL_CLOCK_NEW. Use that instead.
+
+	This MSR falls outside the reserved KVM range and may be removed in the
+	future. Its usage is deprecated.
+
+	Availability of this MSR must be checked via bit 0 in 0x4000001 cpuid
+	leaf prior to usage.
+
+MSR_KVM_SYSTEM_TIME: 0x12
+
+	data and functioning: same as MSR_KVM_SYSTEM_TIME_NEW. Use that instead.
+
+	This MSR falls outside the reserved KVM range and may be removed in the
+	future. Its usage is deprecated.
+
+	Availability of this MSR must be checked via bit 0 in 0x4000001 cpuid
+	leaf prior to usage.
+
+	The suggested algorithm for detecting kvmclock presence is then:
+
+		if (!kvm_para_available())    /* refer to cpuid.txt */
+			return NON_PRESENT;
+
+		flags = cpuid_eax(0x40000001);
+		if (flags & 3) {
+			msr_kvm_system_time = MSR_KVM_SYSTEM_TIME_NEW;
+			msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK_NEW;
+			return PRESENT;
+		} else if (flags & 0) {
+			msr_kvm_system_time = MSR_KVM_SYSTEM_TIME;
+			msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK;
+			return PRESENT;
+		} else
+			return NON_PRESENT;
diff --git a/Documentation/kvm/review-checklist.txt b/Documentation/kvm/review-checklist.txt
new file mode 100644
index 0000000..730475a
--- /dev/null
+++ b/Documentation/kvm/review-checklist.txt
@@ -0,0 +1,38 @@
+Review checklist for kvm patches
+================================
+
+1.  The patch must follow Documentation/CodingStyle and
+    Documentation/SubmittingPatches.
+
+2.  Patches should be against kvm.git master branch.
+
+3.  If the patch introduces or modifies a new userspace API:
+    - the API must be documented in Documentation/kvm/api.txt
+    - the API must be discoverable using KVM_CHECK_EXTENSION
+
+4.  New state must include support for save/restore.
+
+5.  New features must default to off (userspace should explicitly request them).
+    Performance improvements can and should default to on.
+
+6.  New cpu features should be exposed via KVM_GET_SUPPORTED_CPUID2
+
+7.  Emulator changes should be accompanied by unit tests for qemu-kvm.git
+    kvm/test directory.
+
+8.  Changes should be vendor neutral when possible.  Changes to common code
+    are better than duplicating changes to vendor code.
+
+9.  Similarly, prefer changes to arch independent code than to arch dependent
+    code.
+
+10. User/kernel interfaces and guest/host interfaces must be 64-bit clean
+    (all variables and sizes naturally aligned on 64-bit; use specific types
+    only - u64 rather than ulong).
+
+11. New guest visible features must either be documented in a hardware manual
+    or be accompanied by documentation.
+
+12. Features must be robust against reset and kexec - for example, shared
+    host/guest memory must be unshared to prevent the host from writing to
+    guest memory that the guest has not reserved for this purpose.
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index fc15538..f6f8025 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -960,70 +960,21 @@
 	subsystem, and follow all of the hwmon guidelines at
 	Documentation/hwmon.
 
+EXPERIMENTAL: Embedded controller register dump
+-----------------------------------------------
 
-EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump
-------------------------------------------------------------------------
+This feature is not included in the thinkpad driver anymore.
+Instead the EC can be accessed through /sys/kernel/debug/ec with
+a userspace tool which can be found here:
+ftp://ftp.suse.com/pub/people/trenn/sources/ec
 
-This feature is marked EXPERIMENTAL because the implementation
-directly accesses hardware registers and may not work as expected. USE
-WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.
-
-This feature dumps the values of 256 embedded controller
-registers. Values which have changed since the last time the registers
-were dumped are marked with a star:
-
-[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
-EC       +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
-EC 0x00:  a7  47  87  01  fe  96  00  08  01  00  cb  00  00  00  40  00
-EC 0x10:  00  00  ff  ff  f4  3c  87  09  01  ff  42  01  ff  ff  0d  00
-EC 0x20:  00  00  00  00  00  00  00  00  00  00  00  03  43  00  00  80
-EC 0x30:  01  07  1a  00  30  04  00  00 *85  00  00  10  00  50  00  00
-EC 0x40:  00  00  00  00  00  00  14  01  00  04  00  00  00  00  00  00
-EC 0x50:  00  c0  02  0d  00  01  01  02  02  03  03  03  03 *bc *02 *bc
-EC 0x60: *02 *bc *02  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0x70:  00  00  00  00  00  12  30  40 *24 *26 *2c *27 *20  80 *1f  80
-EC 0x80:  00  00  00  06 *37 *0e  03  00  00  00  0e  07  00  00  00  00
-EC 0x90:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xa0: *ff  09  ff  09  ff  ff *64  00 *00 *00 *a2  41 *ff *ff *e0  00
-EC 0xb0:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xc0:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xd0:  03  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xe0:  00  00  00  00  00  00  00  00  11  20  49  04  24  06  55  03
-EC 0xf0:  31  55  48  54  35  38  57  57  08  2f  45  73  07  65  6c  1a
-
-This feature can be used to determine the register holding the fan
+Use it to determine the register holding the fan
 speed on some models. To do that, do the following:
-
 	- make sure the battery is fully charged
 	- make sure the fan is running
-	- run 'cat /proc/acpi/ibm/ecdump' several times, once per second or so
+	- use above mentioned tool to read out the EC
 
-The first step makes sure various charging-related values don't
-vary. The second ensures that the fan-related values do vary, since
-the fan speed fluctuates a bit. The third will (hopefully) mark the
-fan register with a star:
-
-[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
-EC       +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
-EC 0x00:  a7  47  87  01  fe  96  00  08  01  00  cb  00  00  00  40  00
-EC 0x10:  00  00  ff  ff  f4  3c  87  09  01  ff  42  01  ff  ff  0d  00
-EC 0x20:  00  00  00  00  00  00  00  00  00  00  00  03  43  00  00  80
-EC 0x30:  01  07  1a  00  30  04  00  00  85  00  00  10  00  50  00  00
-EC 0x40:  00  00  00  00  00  00  14  01  00  04  00  00  00  00  00  00
-EC 0x50:  00  c0  02  0d  00  01  01  02  02  03  03  03  03  bc  02  bc
-EC 0x60:  02  bc  02  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0x70:  00  00  00  00  00  12  30  40  24  27  2c  27  21  80  1f  80
-EC 0x80:  00  00  00  06 *be  0d  03  00  00  00  0e  07  00  00  00  00
-EC 0x90:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xa0:  ff  09  ff  09  ff  ff  64  00  00  00  a2  41  ff  ff  e0  00
-EC 0xb0:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xc0:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xd0:  03  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xe0:  00  00  00  00  00  00  00  00  11  20  49  04  24  06  55  03
-EC 0xf0:  31  55  48  54  35  38  57  57  08  2f  45  73  07  65  6c  1a
-
-Another set of values that varies often is the temperature
+Often fan and temperature values vary between
 readings. Since temperatures don't change vary fast, you can take
 several quick dumps to eliminate them.
 
diff --git a/Documentation/networking/README.ipw2200 b/Documentation/networking/README.ipw2200
index c276490..616a8e5 100644
--- a/Documentation/networking/README.ipw2200
+++ b/Documentation/networking/README.ipw2200
@@ -171,7 +171,7 @@
   
   led
 	Can be used to turn on experimental LED code.
-	0 = Off, 1 = On.  Default is 0.
+	0 = Off, 1 = On.  Default is 1.
 
   mode
 	Can be used to set the default mode of the adapter.  
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index e0ec7cb..d2b62b7 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -49,6 +49,7 @@
 3.3	Configuring Bonding Manually with Ifenslave
 3.3.1		Configuring Multiple Bonds Manually
 3.4	Configuring Bonding Manually via Sysfs
+3.5	Overriding Configuration for Special Cases
 
 4. Querying Bonding Configuration
 4.1	Bonding Configuration
@@ -1318,8 +1319,87 @@
 echo +eth2 > /sys/class/net/bond1/bonding/slaves
 echo +eth3 > /sys/class/net/bond1/bonding/slaves
 
+3.5 Overriding Configuration for Special Cases
+----------------------------------------------
+When using the bonding driver, the physical port which transmits a frame is
+typically selected by the bonding driver, and is not relevant to the user or
+system administrator.  The output port is simply selected using the policies of
+the selected bonding mode.  On occasion however, it is helpful to direct certain
+classes of traffic to certain physical interfaces on output to implement
+slightly more complex policies.  For example, to reach a web server over a
+bonded interface in which eth0 connects to a private network, while eth1
+connects via a public network, it may be desirous to bias the bond to send said
+traffic over eth0 first, using eth1 only as a fall back, while all other traffic
+can safely be sent over either interface.  Such configurations may be achieved
+using the traffic control utilities inherent in linux.
 
-4. Querying Bonding Configuration 
+By default the bonding driver is multiqueue aware and 16 queues are created
+when the driver initializes (see Documentation/networking/multiqueue.txt
+for details).  If more or less queues are desired the module parameter
+tx_queues can be used to change this value.  There is no sysfs parameter
+available as the allocation is done at module init time.
+
+The output of the file /proc/net/bonding/bondX has changed so the output Queue
+ID is now printed for each slave:
+
+Bonding Mode: fault-tolerance (active-backup)
+Primary Slave: None
+Currently Active Slave: eth0
+MII Status: up
+MII Polling Interval (ms): 0
+Up Delay (ms): 0
+Down Delay (ms): 0
+
+Slave Interface: eth0
+MII Status: up
+Link Failure Count: 0
+Permanent HW addr: 00:1a:a0:12:8f:cb
+Slave queue ID: 0
+
+Slave Interface: eth1
+MII Status: up
+Link Failure Count: 0
+Permanent HW addr: 00:1a:a0:12:8f:cc
+Slave queue ID: 2
+
+The queue_id for a slave can be set using the command:
+
+# echo "eth1:2" > /sys/class/net/bond0/bonding/queue_id
+
+Any interface that needs a queue_id set should set it with multiple calls
+like the one above until proper priorities are set for all interfaces.  On
+distributions that allow configuration via initscripts, multiple 'queue_id'
+arguments can be added to BONDING_OPTS to set all needed slave queues.
+
+These queue id's can be used in conjunction with the tc utility to configure
+a multiqueue qdisc and filters to bias certain traffic to transmit on certain
+slave devices.  For instance, say we wanted, in the above configuration to
+force all traffic bound to 192.168.1.100 to use eth1 in the bond as its output
+device. The following commands would accomplish this:
+
+# tc qdisc add dev bond0 handle 1 root multiq
+
+# tc filter add dev bond0 protocol ip parent 1: prio 1 u32 match ip dst \
+	192.168.1.100 action skbedit queue_mapping 2
+
+These commands tell the kernel to attach a multiqueue queue discipline to the
+bond0 interface and filter traffic enqueued to it, such that packets with a dst
+ip of 192.168.1.100 have their output queue mapping value overwritten to 2.
+This value is then passed into the driver, causing the normal output path
+selection policy to be overridden, selecting instead qid 2, which maps to eth1.
+
+Note that qid values begin at 1.  Qid 0 is reserved to initiate to the driver
+that normal output policy selection should take place.  One benefit to simply
+leaving the qid for a slave to 0 is the multiqueue awareness in the bonding
+driver that is now present.  This awareness allows tc filters to be placed on
+slave devices as well as bond devices and the bonding driver will simply act as
+a pass-through for selecting output queues on the slave device rather than 
+output port selection.
+
+This feature first appeared in bonding driver version 3.7.0 and support for
+output slave selection was limited to round-robin and active-backup modes.
+
+4 Querying Bonding Configuration
 =================================
 
 4.1 Bonding Configuration
diff --git a/Documentation/networking/caif/spi_porting.txt b/Documentation/networking/caif/spi_porting.txt
new file mode 100644
index 0000000..61d7c92
--- /dev/null
+++ b/Documentation/networking/caif/spi_porting.txt
@@ -0,0 +1,208 @@
+- CAIF SPI porting -
+
+- CAIF SPI basics:
+
+Running CAIF over SPI needs some extra setup, owing to the nature of SPI.
+Two extra GPIOs have been added in order to negotiate the transfers
+ between the master and the slave. The minimum requirement for running
+CAIF over SPI is a SPI slave chip and two GPIOs (more details below).
+Please note that running as a slave implies that you need to keep up
+with the master clock. An overrun or underrun event is fatal.
+
+- CAIF SPI framework:
+
+To make porting as easy as possible, the CAIF SPI has been divided in
+two parts. The first part (called the interface part) deals with all
+generic functionality such as length framing, SPI frame negotiation
+and SPI frame delivery and transmission. The other part is the CAIF
+SPI slave device part, which is the module that you have to write if
+you want to run SPI CAIF on a new hardware. This part takes care of
+the physical hardware, both with regard to SPI and to GPIOs.
+
+- Implementing a CAIF SPI device:
+
+	- Functionality provided by the CAIF SPI slave device:
+
+	In order to implement a SPI device you will, as a minimum,
+	need to implement the following
+	functions:
+
+	int (*init_xfer) (struct cfspi_xfer * xfer, struct cfspi_dev *dev):
+
+	This function is called by the CAIF SPI interface to give
+	you a chance to set up your hardware to be ready to receive
+	a stream of data from the master. The xfer structure contains
+	both physical and logical adresses, as well as the total length
+	of the transfer in both directions.The dev parameter can be used
+	to map to different CAIF SPI slave devices.
+
+	void (*sig_xfer) (bool xfer, struct cfspi_dev *dev):
+
+	This function is called by the CAIF SPI interface when the output
+	(SPI_INT) GPIO needs to change state. The boolean value of the xfer
+	variable indicates whether the GPIO should be asserted (HIGH) or
+	deasserted (LOW). The dev parameter can be used to map to different CAIF
+	SPI slave devices.
+
+	- Functionality provided by the CAIF SPI interface:
+
+	void (*ss_cb) (bool assert, struct cfspi_ifc *ifc);
+
+	This function is called by the CAIF SPI slave device in order to
+	signal a change of state of the input GPIO (SS) to the interface.
+	Only active edges are mandatory to be reported.
+	This function can be called from IRQ context (recommended in order
+	not to introduce latency). The ifc parameter should be the pointer
+	returned from the platform probe function in the SPI device structure.
+
+	void (*xfer_done_cb) (struct cfspi_ifc *ifc);
+
+	This function is called by the CAIF SPI slave device in order to
+	report that a transfer is completed. This function should only be
+	called once both the transmission and the reception are completed.
+	This function can be called from IRQ context (recommended in order
+	not to introduce latency). The ifc parameter should be the pointer
+	returned from the platform probe function in the SPI device structure.
+
+	- Connecting the bits and pieces:
+
+		- Filling in the SPI slave device structure:
+
+		Connect the necessary callback functions.
+		Indicate clock speed (used to calculate toggle delays).
+		Chose a suitable name (helps debugging if you use several CAIF
+		SPI slave devices).
+		Assign your private data (can be used to map to your structure).
+
+		- Filling in the SPI slave platform device structure:
+		Add name of driver to connect to ("cfspi_sspi").
+		Assign the SPI slave device structure as platform data.
+
+- Padding:
+
+In order to optimize throughput, a number of SPI padding options are provided.
+Padding can be enabled independently for uplink and downlink transfers.
+Padding can be enabled for the head, the tail and for the total frame size.
+The padding needs to be correctly configured on both sides of the link.
+The padding can be changed via module parameters in cfspi_sspi.c or via
+the sysfs directory of the cfspi_sspi driver (before device registration).
+
+- CAIF SPI device template:
+
+/*
+ *	Copyright (C) ST-Ericsson AB 2010
+ *	Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ *	License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <net/caif/caif_spi.h>
+
+MODULE_LICENSE("GPL");
+
+struct sspi_struct {
+	struct cfspi_dev sdev;
+	struct cfspi_xfer *xfer;
+};
+
+static struct sspi_struct slave;
+static struct platform_device slave_device;
+
+static irqreturn_t sspi_irq(int irq, void *arg)
+{
+	/* You only need to trigger on an edge to the active state of the
+	 * SS signal. Once a edge is detected, the ss_cb() function should be
+	 * called with the parameter assert set to true. It is OK
+	 * (and even advised) to call the ss_cb() function in IRQ context in
+	 * order not to add any delay. */
+
+	return IRQ_HANDLED;
+}
+
+static void sspi_complete(void *context)
+{
+	/* Normally the DMA or the SPI framework will call you back
+	 * in something similar to this. The only thing you need to
+	 * do is to call the xfer_done_cb() function, providing the pointer
+	 * to the CAIF SPI interface. It is OK to call this function
+	 * from IRQ context. */
+}
+
+static int sspi_init_xfer(struct cfspi_xfer *xfer, struct cfspi_dev *dev)
+{
+	/* Store transfer info. For a normal implementation you should
+	 * set up your DMA here and make sure that you are ready to
+	 * receive the data from the master SPI. */
+
+	struct sspi_struct *sspi = (struct sspi_struct *)dev->priv;
+
+	sspi->xfer = xfer;
+
+	return 0;
+}
+
+void sspi_sig_xfer(bool xfer, struct cfspi_dev *dev)
+{
+	/* If xfer is true then you should assert the SPI_INT to indicate to
+	 * the master that you are ready to recieve the data from the master
+	 * SPI. If xfer is false then you should de-assert SPI_INT to indicate
+	 * that the transfer is done.
+	 */
+
+	struct sspi_struct *sspi = (struct sspi_struct *)dev->priv;
+}
+
+static void sspi_release(struct device *dev)
+{
+	/*
+	 * Here you should release your SPI device resources.
+	 */
+}
+
+static int __init sspi_init(void)
+{
+	/* Here you should initialize your SPI device by providing the
+	 * necessary functions, clock speed, name and private data. Once
+	 * done, you can register your device with the
+	 * platform_device_register() function. This function will return
+	 * with the CAIF SPI interface initialized. This is probably also
+	 * the place where you should set up your GPIOs, interrupts and SPI
+	 * resources. */
+
+	int res = 0;
+
+	/* Initialize slave device. */
+	slave.sdev.init_xfer = sspi_init_xfer;
+	slave.sdev.sig_xfer = sspi_sig_xfer;
+	slave.sdev.clk_mhz = 13;
+	slave.sdev.priv = &slave;
+	slave.sdev.name = "spi_sspi";
+	slave_device.dev.release = sspi_release;
+
+	/* Initialize platform device. */
+	slave_device.name = "cfspi_sspi";
+	slave_device.dev.platform_data = &slave.sdev;
+
+	/* Register platform device. */
+	res = platform_device_register(&slave_device);
+	if (res) {
+		printk(KERN_WARNING "sspi_init: failed to register dev.\n");
+		return -ENODEV;
+	}
+
+	return res;
+}
+
+static void __exit sspi_exit(void)
+{
+	platform_device_del(&slave_device);
+}
+
+module_init(sspi_init);
+module_exit(sspi_exit);
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index d0536b5..f350c69 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -903,7 +903,7 @@
 arp_notify - BOOLEAN
 	Define mode for notification of address and device changes.
 	0 - (default): do nothing
-	1 - Generate gratuitous arp replies when device is brought up
+	1 - Generate gratuitous arp requests when device is brought up
 	    or hardware address changes.
 
 arp_accept - BOOLEAN
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
index 2a72262..073894d 100644
--- a/Documentation/networking/packet_mmap.txt
+++ b/Documentation/networking/packet_mmap.txt
@@ -493,6 +493,32 @@
     pfd.events = POLLOUT;
     retval = poll(&pfd, 1, timeout);
 
+-------------------------------------------------------------------------------
++ PACKET_TIMESTAMP
+-------------------------------------------------------------------------------
+
+The PACKET_TIMESTAMP setting determines the source of the timestamp in
+the packet meta information.  If your NIC is capable of timestamping
+packets in hardware, you can request those hardware timestamps to used.
+Note: you may need to enable the generation of hardware timestamps with
+SIOCSHWTSTAMP.
+
+PACKET_TIMESTAMP accepts the same integer bit field as
+SO_TIMESTAMPING.  However, only the SOF_TIMESTAMPING_SYS_HARDWARE
+and SOF_TIMESTAMPING_RAW_HARDWARE values are recognized by
+PACKET_TIMESTAMP.  SOF_TIMESTAMPING_SYS_HARDWARE takes precedence over
+SOF_TIMESTAMPING_RAW_HARDWARE if both bits are set.
+
+    int req = 0;
+    req |= SOF_TIMESTAMPING_SYS_HARDWARE;
+    setsockopt(fd, SOL_PACKET, PACKET_TIMESTAMP, (void *) &req, sizeof(req))
+
+If PACKET_TIMESTAMP is not set, a software timestamp generated inside
+the networking stack is used (the behavior before this setting was added).
+
+See include/linux/net_tstamp.h and Documentation/networking/timestamping
+for more information on hardware timestamps.
+
 --------------------------------------------------------------------------------
 + THANKS
 --------------------------------------------------------------------------------
diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt
index 61bb645..75e4fd7 100644
--- a/Documentation/networking/pktgen.txt
+++ b/Documentation/networking/pktgen.txt
@@ -151,6 +151,8 @@
 
  pgset stop    	          aborts injection. Also, ^C aborts generator.
 
+ pgset "rate 300M"        set rate to 300 Mb/s
+ pgset "ratep 1000000"    set rate to 1Mpps
 
 Example scripts
 ===============
@@ -241,6 +243,9 @@
 flows
 flowlen
 
+rate
+ratep
+
 References:
 ftp://robur.slu.se/pub/Linux/net-development/pktgen-testing/
 ftp://robur.slu.se/pub/Linux/net-development/pktgen-testing/examples/
diff --git a/Documentation/padata.txt b/Documentation/padata.txt
index 269d7d0..473ebf2 100644
--- a/Documentation/padata.txt
+++ b/Documentation/padata.txt
@@ -1,5 +1,5 @@
 The padata parallel execution mechanism
-Last updated for 2.6.34
+Last updated for 2.6.36
 
 Padata is a mechanism by which the kernel can farm work out to be done in
 parallel on multiple CPUs while retaining the ordering of tasks.  It was
@@ -13,31 +13,86 @@
 
     #include <linux/padata.h>
 
-    struct padata_instance *padata_alloc(const struct cpumask *cpumask,
-				         struct workqueue_struct *wq);
+    struct padata_instance *padata_alloc(struct workqueue_struct *wq,
+					 const struct cpumask *pcpumask,
+					 const struct cpumask *cbcpumask);
 
-The cpumask describes which processors will be used to execute work
-submitted to this instance.  The workqueue wq is where the work will
-actually be done; it should be a multithreaded queue, naturally.
+The pcpumask describes which processors will be used to execute work
+submitted to this instance in parallel. The cbcpumask defines which
+processors are allowed to use as the serialization callback processor.
+The workqueue wq is where the work will actually be done; it should be
+a multithreaded queue, naturally.
+
+To allocate a padata instance with the cpu_possible_mask for both
+cpumasks this helper function can be used:
+
+    struct padata_instance *padata_alloc_possible(struct workqueue_struct *wq);
+
+Note: Padata maintains two kinds of cpumasks internally. The user supplied
+cpumasks, submitted by padata_alloc/padata_alloc_possible and the 'usable'
+cpumasks. The usable cpumasks are always the subset of active cpus in the
+user supplied cpumasks, these are the cpumasks padata actually use. So
+it is legal to supply a cpumask to padata that contains offline cpus.
+Once a offline cpu in the user supplied cpumask comes online, padata
+is going to use it.
 
 There are functions for enabling and disabling the instance:
 
-    void padata_start(struct padata_instance *pinst);
+    int padata_start(struct padata_instance *pinst);
     void padata_stop(struct padata_instance *pinst);
 
-These functions literally do nothing beyond setting or clearing the
-"padata_start() was called" flag; if that flag is not set, other functions
-will refuse to work.
+These functions are setting or clearing the "PADATA_INIT" flag;
+if that flag is not set, other functions will refuse to work.
+padata_start returns zero on success (flag set) or -EINVAL if the
+padata cpumask contains no active cpu (flag not set).
+padata_stop clears the flag and blocks until the padata instance
+is unused.
 
 The list of CPUs to be used can be adjusted with these functions:
 
-    int padata_set_cpumask(struct padata_instance *pinst,
+    int padata_set_cpumasks(struct padata_instance *pinst,
+			    cpumask_var_t pcpumask,
+			    cpumask_var_t cbcpumask);
+    int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type,
 			   cpumask_var_t cpumask);
-    int padata_add_cpu(struct padata_instance *pinst, int cpu);
-    int padata_remove_cpu(struct padata_instance *pinst, int cpu);
+    int padata_add_cpu(struct padata_instance *pinst, int cpu, int mask);
+    int padata_remove_cpu(struct padata_instance *pinst, int cpu, int mask);
 
-Changing the CPU mask has the look of an expensive operation, though, so it
-probably should not be done with great frequency.
+Changing the CPU masks are expensive operations, though, so it should not be
+done with great frequency.
+
+It's possible to change both cpumasks of a padata instance with
+padata_set_cpumasks by specifying the cpumasks for parallel execution (pcpumask)
+and for the serial callback function (cbcpumask). padata_set_cpumask is to
+change just one of the cpumasks. Here cpumask_type is one of PADATA_CPU_SERIAL,
+PADATA_CPU_PARALLEL and cpumask specifies the new cpumask to use.
+To simply add or remove one cpu from a certain cpumask the functions
+padata_add_cpu/padata_remove_cpu are used. cpu specifies the cpu to add or
+remove and mask is one of PADATA_CPU_SERIAL, PADATA_CPU_PARALLEL.
+
+If a user is interested in padata cpumask changes, he can register to
+the padata cpumask change notifier:
+
+    int padata_register_cpumask_notifier(struct padata_instance *pinst,
+					 struct notifier_block *nblock);
+
+To unregister from that notifier:
+
+    int padata_unregister_cpumask_notifier(struct padata_instance *pinst,
+					   struct notifier_block *nblock);
+
+The padata cpumask change notifier notifies about changes of the usable
+cpumasks, i.e. the subset of active cpus in the user supplied cpumask.
+
+Padata calls the notifier chain with:
+
+    blocking_notifier_call_chain(&pinst->cpumask_change_notifier,
+				 notification_mask,
+				 &pd_new->cpumask);
+
+Here cpumask_change_notifier is registered notifier, notification_mask
+is one of PADATA_CPU_SERIAL, PADATA_CPU_PARALLEL and cpumask is a pointer
+to a struct padata_cpumask that contains the new cpumask informations.
 
 Actually submitting work to the padata instance requires the creation of a
 padata_priv structure:
@@ -50,7 +105,7 @@
 
 This structure will almost certainly be embedded within some larger
 structure specific to the work to be done.  Most its fields are private to
-padata, but the structure should be zeroed at initialization time, and the
+padata, but the structure should be zeroed at initialisation time, and the
 parallel() and serial() functions should be provided.  Those functions will
 be called in the process of getting the work done as we will see
 momentarily.
@@ -63,12 +118,10 @@
 The pinst and padata structures must be set up as described above; cb_cpu
 specifies which CPU will be used for the final callback when the work is
 done; it must be in the current instance's CPU mask.  The return value from
-padata_do_parallel() is a little strange; zero is an error return
-indicating that the caller forgot the padata_start() formalities.  -EBUSY
-means that somebody, somewhere else is messing with the instance's CPU
-mask, while -EINVAL is a complaint about cb_cpu not being in that CPU mask.
-If all goes well, this function will return -EINPROGRESS, indicating that
-the work is in progress.
+padata_do_parallel() is zero on success, indicating that the work is in
+progress. -EBUSY means that somebody, somewhere else is messing with the
+instance's CPU mask, while -EINVAL is a complaint about cb_cpu not being
+in that CPU mask or about a not running instance.
 
 Each task submitted to padata_do_parallel() will, in turn, be passed to
 exactly one call to the above-mentioned parallel() function, on one CPU, so
diff --git a/Documentation/scsi/hpsa.txt b/Documentation/scsi/hpsa.txt
new file mode 100644
index 0000000..dca6583
--- /dev/null
+++ b/Documentation/scsi/hpsa.txt
@@ -0,0 +1,107 @@
+
+HPSA - Hewlett Packard Smart Array driver
+-----------------------------------------
+
+This file describes the hpsa SCSI driver for HP Smart Array controllers.
+The hpsa driver is intended to supplant the cciss driver for newer
+Smart Array controllers.  The hpsa driver is a SCSI driver, while the
+cciss driver is a "block" driver.  Actually cciss is both a block
+driver (for logical drives) AND a SCSI driver (for tape drives). This
+"split-brained" design of the cciss driver is a source of excess
+complexity and eliminating that complexity is one of the reasons
+for hpsa to exist.
+
+Supported devices:
+------------------
+
+Smart Array P212
+Smart Array P410
+Smart Array P410i
+Smart Array P411
+Smart Array P812
+Smart Array P712m
+Smart Array P711m
+StorageWorks P1210m
+
+Additionally, older Smart Arrays may work with the hpsa driver if the kernel
+boot parameter "hpsa_allow_any=1" is specified, however these are not tested
+nor supported by HP with this driver.  For older Smart Arrays, the cciss
+driver should still be used.
+
+HPSA specific entries in /sys
+-----------------------------
+
+  In addition to the generic SCSI attributes available in /sys, hpsa supports
+  the following attributes:
+
+  HPSA specific host attributes:
+  ------------------------------
+
+  /sys/class/scsi_host/host*/rescan
+  /sys/class/scsi_host/host*/firmware_revision
+
+  the host "rescan" attribute is a write only attribute.  Writing to this
+  attribute will cause the driver to scan for new, changed, or removed devices
+  (e.g. hot-plugged tape drives, or newly configured or deleted logical drives,
+  etc.) and notify the SCSI midlayer of any changes detected.  Normally this is
+  triggered automatically by HP's Array Configuration Utility (either the GUI or
+  command line variety) so for logical drive changes, the user should not
+  normally have to use this.  It may be useful when hot plugging devices like
+  tape drives, or entire storage boxes containing pre-configured logical drives.
+
+  The "firmware_revision" attribute contains the firmware version of the Smart Array.
+  For example:
+
+	root@host:/sys/class/scsi_host/host4# cat firmware_revision
+	7.14
+
+  HPSA specific disk attributes:
+  ------------------------------
+
+  /sys/class/scsi_disk/c:b:t:l/device/unique_id
+  /sys/class/scsi_disk/c:b:t:l/device/raid_level
+  /sys/class/scsi_disk/c:b:t:l/device/lunid
+
+  (where c:b:t:l are the controller, bus, target and lun of the device)
+
+  For example:
+
+	root@host:/sys/class/scsi_disk/4:0:0:0/device# cat unique_id
+	600508B1001044395355323037570F77
+	root@host:/sys/class/scsi_disk/4:0:0:0/device# cat lunid
+	0x0000004000000000
+	root@host:/sys/class/scsi_disk/4:0:0:0/device# cat raid_level
+	RAID 0
+
+HPSA specific ioctls:
+---------------------
+
+  For compatibility with applications written for the cciss driver, many, but
+  not all of the ioctls supported by the cciss driver are also supported by the
+  hpsa driver.  The data structures used by these are described in
+  include/linux/cciss_ioctl.h
+
+  CCISS_DEREGDISK
+  CCISS_REGNEWDISK
+  CCISS_REGNEWD
+
+  The above three ioctls all do exactly the same thing, which is to cause the driver
+  to rescan for new devices.  This does exactly the same thing as writing to the
+  hpsa specific host "rescan" attribute.
+
+  CCISS_GETPCIINFO
+
+	Returns PCI domain, bus, device and function and "board ID" (PCI subsystem ID).
+
+  CCISS_GETDRIVVER
+
+	Returns driver version in three bytes encoded as:
+		(major_version << 16) | (minor_version << 8) | (subminor_version)
+
+  CCISS_PASSTHRU
+  CCISS_BIG_PASSTHRU
+
+	Allows "BMIC" and "CISS" commands to be passed through to the Smart Array.
+	These are used extensively by the HP Array Configuration Utility, SNMP storage
+	agents, etc.  See cciss_vol_status at http://cciss.sf.net for some examples.
+
diff --git a/Documentation/tomoyo.txt b/Documentation/tomoyo.txt
index b3a232c..200a2d3 100644
--- a/Documentation/tomoyo.txt
+++ b/Documentation/tomoyo.txt
@@ -3,8 +3,8 @@
 TOMOYO is a name-based MAC extension (LSM module) for the Linux kernel.
 
 LiveCD-based tutorials are available at
-http://tomoyo.sourceforge.jp/en/1.6.x/1st-step/ubuntu8.04-live/
-http://tomoyo.sourceforge.jp/en/1.6.x/1st-step/centos5-live/ .
+http://tomoyo.sourceforge.jp/1.7/1st-step/ubuntu10.04-live/
+http://tomoyo.sourceforge.jp/1.7/1st-step/centos5-live/ .
 Though these tutorials use non-LSM version of TOMOYO, they are useful for you
 to know what TOMOYO is.
 
@@ -13,12 +13,12 @@
 Build the kernel with CONFIG_SECURITY_TOMOYO=y and pass "security=tomoyo" on
 kernel's command line.
 
-Please see http://tomoyo.sourceforge.jp/en/2.2.x/ for details.
+Please see http://tomoyo.sourceforge.jp/2.3/ for details.
 
 --- Where is documentation? ---
 
 User <-> Kernel interface documentation is available at
-http://tomoyo.sourceforge.jp/en/2.2.x/policy-reference.html .
+http://tomoyo.sourceforge.jp/2.3/policy-reference.html .
 
 Materials we prepared for seminars and symposiums are available at
 http://sourceforge.jp/projects/tomoyo/docs/?category_id=532&language_id=1 .
@@ -50,6 +50,6 @@
 SELinux/SMACK/AppArmor etc. when you want to use TOMOYO.
 
 We hope that LSM becomes stackable in future. Meanwhile, you can use non-LSM
-version of TOMOYO, available at http://tomoyo.sourceforge.jp/en/1.6.x/ .
+version of TOMOYO, available at http://tomoyo.sourceforge.jp/1.7/ .
 LSM version of TOMOYO is a subset of non-LSM version of TOMOYO. We are planning
 to port non-LSM version's functionalities to LSM versions.
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
index 16ca030..87c4634 100644
--- a/Documentation/video4linux/CARDLIST.cx23885
+++ b/Documentation/video4linux/CARDLIST.cx23885
@@ -17,9 +17,9 @@
  16 -> DVBWorld DVB-S2 2005                                [0001:2005]
  17 -> NetUP Dual DVB-S2 CI                                [1b55:2a2c]
  18 -> Hauppauge WinTV-HVR1270                             [0070:2211]
- 19 -> Hauppauge WinTV-HVR1275                             [0070:2215]
- 20 -> Hauppauge WinTV-HVR1255                             [0070:2251]
- 21 -> Hauppauge WinTV-HVR1210                             [0070:2291,0070:2295]
+ 19 -> Hauppauge WinTV-HVR1275                             [0070:2215,0070:221d,0070:22f2]
+ 20 -> Hauppauge WinTV-HVR1255                             [0070:2251,0070:2259,0070:22f1]
+ 21 -> Hauppauge WinTV-HVR1210                             [0070:2291,0070:2295,0070:2299,0070:229d,0070:22f0,0070:22f3,0070:22f4,0070:22f5]
  22 -> Mygica X8506 DMB-TH                                 [14f1:8651]
  23 -> Magic-Pro ProHDTV Extreme 2                         [14f1:8657]
  24 -> Hauppauge WinTV-HVR1850                             [0070:8541]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index 3a623aa..5c56875 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -72,3 +72,4 @@
  73 -> Reddo DVB-C USB TV Box                   (em2870)
  74 -> Actionmaster/LinXcel/Digitus VC211A      (em2800)
  75 -> Dikom DK300                              (em2882)
+ 76 -> KWorld PlusTV 340U or UB435-Q (ATSC)     (em2870)        [1b80:a340]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 1387a69..4000c29 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -178,4 +178,5 @@
 177 -> Hawell HW-404M7
 178 -> Beholder BeholdTV H7                     [5ace:7190]
 179 -> Beholder BeholdTV A7                     [5ace:7090]
-180 -> Avermedia M733A                          [1461:4155,1461:4255]
+180 -> Avermedia PCI M733A                      [1461:4155,1461:4255]
+181 -> TechoTrend TT-budget T-3000              [13c2:2804]
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index f13eb03..56ba7bb 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -29,8 +29,12 @@
 zc3xx		041e:4034	Creative Instant P0620
 zc3xx		041e:4035	Creative Instant P0620D
 zc3xx		041e:4036	Creative Live !
+sq930x		041e:4038	Creative Joy-IT
 zc3xx		041e:403a	Creative Nx Pro 2
 spca561		041e:403b	Creative Webcam Vista (VF0010)
+sq930x		041e:403c	Creative Live! Ultra
+sq930x		041e:403d	Creative Live! Ultra for Notebooks
+sq930x		041e:4041	Creative Live! Motion
 zc3xx		041e:4051	Creative Live!Cam Notebook Pro (VF0250)
 ov519		041e:4052	Creative Live! VISTA IM
 zc3xx		041e:4053	Creative Live!Cam Video IM
@@ -138,6 +142,7 @@
 finepix		04cb:013f	Fujifilm FinePix F420
 sunplus		04f1:1001	JVC GC A50
 spca561		04fc:0561	Flexcam 100
+spca1528	04fc:1528	Sunplus MD80 clone
 sunplus		04fc:500c	Sunplus CA500C
 sunplus		04fc:504a	Aiptek Mini PenCam 1.3
 sunplus		04fc:504b	Maxell MaxPocket LE 1.3
@@ -253,6 +258,7 @@
 pac7302		093a:2621	PAC731x
 pac7302		093a:2622	Genius Eye 312
 pac7302		093a:2624	PAC7302
+pac7302		093a:2625	Genius iSlim 310
 pac7302		093a:2626	Labtec 2200
 pac7302		093a:2628	Genius iLook 300
 pac7302		093a:2629	Genious iSlim 300
@@ -362,6 +368,8 @@
 sq905c		2770:905c	All 11 known cameras with this ID
 sq905		2770:9120	All 24 known cameras with this ID
 sq905c		2770:913d	All 4 known cameras with this ID
+sq930x		2770:930b	Sweex Motion Tracking / I-Tec iCam Tracer
+sq930x		2770:930c	Trust WB-3500T / NSG Robbie 2.0
 spca500		2899:012c	Toptro Industrial
 ov519		8020:ef04	ov519
 spca508		8086:0110	Intel Easy PC Camera
diff --git a/MAINTAINERS b/MAINTAINERS
index 02f75fc..88ec044 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -313,11 +313,9 @@
 F:	drivers/hwmon/adm1029.c
 
 ADM8211 WIRELESS DRIVER
-M:	Michael Wu <flamingice@sourmilk.net>
 L:	linux-wireless@vger.kernel.org
 W:	http://linuxwireless.org/
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
-S:	Maintained
+S:	Orphan
 F:	drivers/net/wireless/adm8211.*
 
 ADT746X FAN DRIVER
@@ -1369,7 +1367,7 @@
 M:	Eilon Greenstein <eilong@broadcom.com>
 L:	netdev@vger.kernel.org
 S:	Supported
-F:	drivers/net/bnx2x*
+F:	drivers/net/bnx2x/
 
 BROADCOM TG3 GIGABIT ETHERNET DRIVER
 M:	Matt Carlson <mcarlson@broadcom.com>
@@ -1771,6 +1769,13 @@
 S:	Supported
 F:	drivers/infiniband/hw/cxgb4/
 
+CXGB4VF ETHERNET DRIVER (CXGB4VF)
+M:	Casey Leedom <leedom@chelsio.com>
+L:	netdev@vger.kernel.org
+W:	http://www.chelsio.com
+S:	Supported
+F:	drivers/net/cxgb4vf/
+
 CYBERPRO FB DRIVER
 M:	Russell King <linux@arm.linux.org.uk>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -2620,6 +2625,14 @@
 F:	Documentation/blockdev/cpqarray.txt
 F:	drivers/block/cpqarray.*
 
+HEWLETT-PACKARD SMART ARRAY RAID DRIVER (hpsa)
+M:	Stephen M. Cameron <scameron@beardog.cce.hp.com>
+L:	iss_storagedev@hp.com
+S:	Supported
+F:	Documentation/scsi/hpsa.txt
+F:	drivers/scsi/hpsa*.[ch]
+F:	include/linux/cciss*.h
+
 HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
 M:	Mike Miller <mike.miller@hp.com>
 L:	iss_storagedev@hp.com
@@ -3686,7 +3699,7 @@
 MARVELL MWL8K WIRELESS DRIVER
 M:	Lennert Buytenhek <buytenh@wantstofly.org>
 L:	linux-wireless@vger.kernel.org
-S:	Maintained
+S:	Odd Fixes
 F:	drivers/net/wireless/mwl8k.c
 
 MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
@@ -3915,17 +3928,19 @@
 S:	Maintained
 F:	net/sched/sch_netem.c
 
-NETERION (S2IO) 10GbE DRIVER (xframe/vxge)
-M:	Ramkrishna Vepa <ram.vepa@neterion.com>
-M:	Rastapur Santosh <santosh.rastapur@neterion.com>
-M:	Sivakumar Subramani <sivakumar.subramani@neterion.com>
-M:	Sreenivasa Honnur <sreenivasa.honnur@neterion.com>
+NETERION 10GbE DRIVERS (s2io/vxge)
+M:	Ramkrishna Vepa <ramkrishna.vepa@exar.com>
+M:	Sivakumar Subramani <sivakumar.subramani@exar.com>
+M:	Sreenivasa Honnur <sreenivasa.honnur@exar.com>
+M:	Jon Mason <jon.mason@exar.com>
 L:	netdev@vger.kernel.org
 W:	http://trac.neterion.com/cgi-bin/trac.cgi/wiki/Linux?Anonymous
 W:	http://trac.neterion.com/cgi-bin/trac.cgi/wiki/X3100Linux?Anonymous
 S:	Supported
 F:	Documentation/networking/s2io.txt
 F:	drivers/net/s2io*
+F:	Documentation/networking/vxge.txt
+F:	drivers/net/vxge/
 
 NETFILTER/IPTABLES/IPCHAINS
 P:	Rusty Russell
@@ -4272,10 +4287,9 @@
 F:	fs/exofs/
 
 P54 WIRELESS DRIVER
-M:	Michael Wu <flamingice@sourmilk.net>
+M:	Christian Lamparter <chunkeey@googlemail.com>
 L:	linux-wireless@vger.kernel.org
-W:	http://prism54.org
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
+W:	http://wireless.kernel.org/en/users/Drivers/p54
 S:	Maintained
 F:	drivers/net/wireless/p54/
 
@@ -4537,7 +4551,7 @@
 M:	"Luis R. Rodriguez" <mcgrof@gmail.com>
 L:	linux-wireless@vger.kernel.org
 W:	http://prism54.org
-S:	Maintained
+S:	Obsolete
 F:	drivers/net/wireless/prism54/
 
 PROMISE DC4030 CACHING DISK CONTROLLER DRIVER
@@ -4733,9 +4747,8 @@
 F:	drivers/rapidio/
 
 RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
-M:	Corey Thomas <coreythomas@charter.net>
 L:	linux-wireless@vger.kernel.org
-S:	Maintained
+S:	Orphan
 F:	drivers/net/wireless/ray*
 
 RCUTORTURE MODULE
@@ -5061,6 +5074,14 @@
 F:	include/linux/selinux*
 F:	security/selinux/
 
+APPARMOR SECURITY MODULE
+M:	John Johansen <john.johansen@canonical.com>
+L:	apparmor@lists.ubuntu.com (subscribers-only, general discussion)
+W:	apparmor.wiki.kernel.org
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
+S:	Supported
+F:	security/apparmor/
+
 SENSABLE PHANTOM
 M:	Jiri Slaby <jirislaby@gmail.com>
 S:	Maintained
@@ -5605,7 +5626,7 @@
 L:	tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
 L:	tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
 W:	http://tomoyo.sourceforge.jp/
-T:	quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.2.x/tomoyo-lsm/patches/
+T:	quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.3.x/tomoyo-lsm/patches/
 S:	Maintained
 F:	security/tomoyo/
 
@@ -6060,10 +6081,9 @@
 F:	drivers/media/video/zc0301/
 
 USB ZD1201 DRIVER
-M:	Jeroen Vreeken <pe1rxq@amsat.org>
-L:	linux-usb@vger.kernel.org
+L:	linux-wireless@vger.kernel.org
 W:	http://linux-lc100020.sourceforge.net
-S:	Maintained
+S:	Orphan
 F:	drivers/net/wireless/zd1201.*
 
 USB ZR364XX DRIVER
@@ -6251,14 +6271,6 @@
 F:	drivers/watchdog/
 F:	include/linux/watchdog.h
 
-WAVELAN NETWORK DRIVER & WIRELESS EXTENSIONS
-M:	Jean Tourrilhes <jt@hpl.hp.com>
-L:	linux-wireless@vger.kernel.org
-W:	http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/
-S:	Maintained
-F:	Documentation/networking/wavelan.txt
-F:	drivers/staging/wavelan/
-
 WD7000 SCSI DRIVER
 M:	Miroslav Zagorac <zaga@fly.cc.fer.hr>
 L:	linux-scsi@vger.kernel.org
diff --git a/arch/arm/plat-samsung/include/plat/keypad.h b/arch/arm/plat-samsung/include/plat/keypad.h
new file mode 100644
index 0000000..3a70c12
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/keypad.h
@@ -0,0 +1,43 @@
+/*
+ * Samsung Platform - Keypad platform data definitions
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __PLAT_SAMSUNG_KEYPAD_H
+#define __PLAT_SAMSUNG_KEYPAD_H
+
+#include <linux/input/matrix_keypad.h>
+
+#define SAMSUNG_MAX_ROWS	8
+#define SAMSUNG_MAX_COLS	8
+
+/**
+ * struct samsung_keypad_platdata - Platform device data for Samsung Keypad.
+ * @keymap_data: pointer to &matrix_keymap_data.
+ * @rows: number of keypad row supported.
+ * @cols: number of keypad col supported.
+ * @no_autorepeat: disable key autorepeat.
+ * @wakeup: controls whether the device should be set up as wakeup source.
+ * @cfg_gpio: configure the GPIO.
+ *
+ * Initialisation data specific to either the machine or the platform
+ * for the device driver to use or call-back when configuring gpio.
+ */
+struct samsung_keypad_platdata {
+	const struct matrix_keymap_data	*keymap_data;
+	unsigned int rows;
+	unsigned int cols;
+	bool no_autorepeat;
+	bool wakeup;
+
+	void (*cfg_gpio)(unsigned int rows, unsigned int cols);
+};
+
+#endif /* __PLAT_SAMSUNG_KEYPAD_H */
diff --git a/arch/ia64/include/asm/kvm_host.h b/arch/ia64/include/asm/kvm_host.h
index a362e67..2f229e5 100644
--- a/arch/ia64/include/asm/kvm_host.h
+++ b/arch/ia64/include/asm/kvm_host.h
@@ -235,6 +235,7 @@
 #define KVM_REQ_PTC_G		32
 #define KVM_REQ_RESUME		33
 
+#define KVM_HPAGE_GFN_SHIFT(x)	0
 #define KVM_NR_PAGE_SIZES	1
 #define KVM_PAGES_PER_HPAGE(x)	1
 
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 9b109f2..f56a631 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -725,8 +725,6 @@
 	int r;
 	sigset_t sigsaved;
 
-	vcpu_load(vcpu);
-
 	if (vcpu->sigset_active)
 		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
 
@@ -748,7 +746,6 @@
 	if (vcpu->sigset_active)
 		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
 
-	vcpu_put(vcpu);
 	return r;
 }
 
@@ -883,8 +880,6 @@
 	struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd);
 	int i;
 
-	vcpu_load(vcpu);
-
 	for (i = 0; i < 16; i++) {
 		vpd->vgr[i] = regs->vpd.vgr[i];
 		vpd->vbgr[i] = regs->vpd.vbgr[i];
@@ -931,8 +926,6 @@
 	vcpu->arch.itc_offset = regs->saved_itc - kvm_get_itc(vcpu);
 	set_bit(KVM_REQ_RESUME, &vcpu->requests);
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
@@ -1802,35 +1795,24 @@
 	kvm_vmm_info = NULL;
 }
 
-static int kvm_ia64_sync_dirty_log(struct kvm *kvm,
-		struct kvm_dirty_log *log)
+static void kvm_ia64_sync_dirty_log(struct kvm *kvm,
+				    struct kvm_memory_slot *memslot)
 {
-	struct kvm_memory_slot *memslot;
-	int r, i;
+	int i;
 	long base;
 	unsigned long n;
 	unsigned long *dirty_bitmap = (unsigned long *)(kvm->arch.vm_base +
 			offsetof(struct kvm_vm_data, kvm_mem_dirty_log));
 
-	r = -EINVAL;
-	if (log->slot >= KVM_MEMORY_SLOTS)
-		goto out;
-
-	memslot = &kvm->memslots->memslots[log->slot];
-	r = -ENOENT;
-	if (!memslot->dirty_bitmap)
-		goto out;
-
 	n = kvm_dirty_bitmap_bytes(memslot);
 	base = memslot->base_gfn / BITS_PER_LONG;
 
+	spin_lock(&kvm->arch.dirty_log_lock);
 	for (i = 0; i < n/sizeof(long); ++i) {
 		memslot->dirty_bitmap[i] = dirty_bitmap[base + i];
 		dirty_bitmap[base + i] = 0;
 	}
-	r = 0;
-out:
-	return r;
+	spin_unlock(&kvm->arch.dirty_log_lock);
 }
 
 int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
@@ -1842,12 +1824,17 @@
 	int is_dirty = 0;
 
 	mutex_lock(&kvm->slots_lock);
-	spin_lock(&kvm->arch.dirty_log_lock);
 
-	r = kvm_ia64_sync_dirty_log(kvm, log);
-	if (r)
+	r = -EINVAL;
+	if (log->slot >= KVM_MEMORY_SLOTS)
 		goto out;
 
+	memslot = &kvm->memslots->memslots[log->slot];
+	r = -ENOENT;
+	if (!memslot->dirty_bitmap)
+		goto out;
+
+	kvm_ia64_sync_dirty_log(kvm, memslot);
 	r = kvm_get_dirty_log(kvm, log, &is_dirty);
 	if (r)
 		goto out;
@@ -1855,14 +1842,12 @@
 	/* If nothing is dirty, don't bother messing with page tables. */
 	if (is_dirty) {
 		kvm_flush_remote_tlbs(kvm);
-		memslot = &kvm->memslots->memslots[log->slot];
 		n = kvm_dirty_bitmap_bytes(memslot);
 		memset(memslot->dirty_bitmap, 0, n);
 	}
 	r = 0;
 out:
 	mutex_unlock(&kvm->slots_lock);
-	spin_unlock(&kvm->arch.dirty_log_lock);
 	return r;
 }
 
@@ -1953,11 +1938,6 @@
 	return vcpu->arch.timer_fired;
 }
 
-gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
-{
-	return gfn;
-}
-
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
 {
 	return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE) ||
@@ -1967,9 +1947,7 @@
 int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
 				    struct kvm_mp_state *mp_state)
 {
-	vcpu_load(vcpu);
 	mp_state->mp_state = vcpu->arch.mp_state;
-	vcpu_put(vcpu);
 	return 0;
 }
 
@@ -2000,10 +1978,8 @@
 {
 	int r = 0;
 
-	vcpu_load(vcpu);
 	vcpu->arch.mp_state = mp_state->mp_state;
 	if (vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)
 		r = vcpu_reset(vcpu);
-	vcpu_put(vcpu);
 	return r;
 }
diff --git a/arch/microblaze/include/asm/system.h b/arch/microblaze/include/asm/system.h
index 48c4f03..81e1f7d 100644
--- a/arch/microblaze/include/asm/system.h
+++ b/arch/microblaze/include/asm/system.h
@@ -101,10 +101,7 @@
  * MicroBlaze doesn't handle unaligned accesses in hardware.
  *
  * Based on this we force the IP header alignment in network drivers.
- * We also modify NET_SKB_PAD to be a cacheline in size, thus maintaining
- * cacheline alignment of buffers.
  */
 #define NET_IP_ALIGN	2
-#define NET_SKB_PAD	L1_CACHE_BYTES
 
 #endif /* _ASM_MICROBLAZE_SYSTEM_H */
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c
index 4c247e0..df971fa 100644
--- a/arch/parisc/kernel/firmware.c
+++ b/arch/parisc/kernel/firmware.c
@@ -1123,7 +1123,6 @@
  */
 int pdc_iodc_print(const unsigned char *str, unsigned count)
 {
-	static int posx;        /* for simple TAB-Simulation... */
 	unsigned int i;
 	unsigned long flags;
 
@@ -1133,19 +1132,12 @@
 			iodc_dbuf[i+0] = '\r';
 			iodc_dbuf[i+1] = '\n';
 			i += 2;
-			posx = 0;
 			goto print;
-		case '\t':
-			while (posx & 7) {
-				iodc_dbuf[i] = ' ';
-				i++, posx++;
-			}
-			break;
 		case '\b':	/* BS */
-			posx -= 2;
+			i--; /* overwrite last */
 		default:
 			iodc_dbuf[i] = str[i];
-			i++, posx++;
+			i++;
 			break;
 		}
 	}
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index 6f74d93..8274a2d 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -115,7 +115,15 @@
 extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte);
 extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr);
 extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu);
-extern struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data);
+
+extern void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte);
+extern struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu);
+extern void kvmppc_mmu_hpte_destroy(struct kvm_vcpu *vcpu);
+extern int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu);
+extern void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte);
+extern int kvmppc_mmu_hpte_sysinit(void);
+extern void kvmppc_mmu_hpte_sysexit(void);
+
 extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data);
 extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data);
 extern void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec);
diff --git a/arch/powerpc/include/asm/kvm_fpu.h b/arch/powerpc/include/asm/kvm_fpu.h
index 94f05de..c3d4f05 100644
--- a/arch/powerpc/include/asm/kvm_fpu.h
+++ b/arch/powerpc/include/asm/kvm_fpu.h
@@ -22,24 +22,24 @@
 
 #include <linux/types.h>
 
-extern void fps_fres(struct thread_struct *t, u32 *dst, u32 *src1);
-extern void fps_frsqrte(struct thread_struct *t, u32 *dst, u32 *src1);
-extern void fps_fsqrts(struct thread_struct *t, u32 *dst, u32 *src1);
+extern void fps_fres(u64 *fpscr, u32 *dst, u32 *src1);
+extern void fps_frsqrte(u64 *fpscr, u32 *dst, u32 *src1);
+extern void fps_fsqrts(u64 *fpscr, u32 *dst, u32 *src1);
 
-extern void fps_fadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
-extern void fps_fdivs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
-extern void fps_fmuls(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
-extern void fps_fsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
+extern void fps_fadds(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2);
+extern void fps_fdivs(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2);
+extern void fps_fmuls(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2);
+extern void fps_fsubs(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2);
 
-extern void fps_fmadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+extern void fps_fmadds(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2,
 		       u32 *src3);
-extern void fps_fmsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+extern void fps_fmsubs(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2,
 		       u32 *src3);
-extern void fps_fnmadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+extern void fps_fnmadds(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2,
 		        u32 *src3);
-extern void fps_fnmsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+extern void fps_fnmsubs(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2,
 		        u32 *src3);
-extern void fps_fsel(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+extern void fps_fsel(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2,
 		     u32 *src3);
 
 #define FPD_ONE_IN(name) extern void fpd_ ## name(u64 *fpscr, u32 *cr, \
@@ -82,4 +82,7 @@
 FPD_THREE_IN(fnmsub)
 FPD_THREE_IN(fnmadd)
 
+extern void kvm_cvt_fd(u32 *from, u64 *to, u64 *fpscr);
+extern void kvm_cvt_df(u64 *from, u32 *to, u64 *fpscr);
+
 #endif
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 0c9ad86..b0b23c0 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -35,10 +35,17 @@
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
 
 /* We don't currently support large pages. */
+#define KVM_HPAGE_GFN_SHIFT(x)	0
 #define KVM_NR_PAGE_SIZES	1
 #define KVM_PAGES_PER_HPAGE(x)	(1UL<<31)
 
-#define HPTEG_CACHE_NUM 1024
+#define HPTEG_CACHE_NUM			(1 << 15)
+#define HPTEG_HASH_BITS_PTE		13
+#define HPTEG_HASH_BITS_VPTE		13
+#define HPTEG_HASH_BITS_VPTE_LONG	5
+#define HPTEG_HASH_NUM_PTE		(1 << HPTEG_HASH_BITS_PTE)
+#define HPTEG_HASH_NUM_VPTE		(1 << HPTEG_HASH_BITS_VPTE)
+#define HPTEG_HASH_NUM_VPTE_LONG	(1 << HPTEG_HASH_BITS_VPTE_LONG)
 
 struct kvm;
 struct kvm_run;
@@ -151,6 +158,9 @@
 };
 
 struct hpte_cache {
+	struct hlist_node list_pte;
+	struct hlist_node list_vpte;
+	struct hlist_node list_vpte_long;
 	u64 host_va;
 	u64 pfn;
 	ulong slot;
@@ -282,8 +292,10 @@
 	unsigned long pending_exceptions;
 
 #ifdef CONFIG_PPC_BOOK3S
-	struct hpte_cache hpte_cache[HPTEG_CACHE_NUM];
-	int hpte_cache_offset;
+	struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE];
+	struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE];
+	struct hlist_head hpte_hash_vpte_long[HPTEG_HASH_NUM_VPTE_LONG];
+	int hpte_cache_count;
 #endif
 };
 
diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h
index a6297c6..6c294ac 100644
--- a/arch/powerpc/include/asm/system.h
+++ b/arch/powerpc/include/asm/system.h
@@ -515,11 +515,8 @@
  * powers of 2 writes until it reaches sufficient alignment).
  *
  * Based on this we disable the IP header alignment in network drivers.
- * We also modify NET_SKB_PAD to be a cacheline in size, thus maintaining
- * cacheline alignment of buffers.
  */
 #define NET_IP_ALIGN	0
-#define NET_SKB_PAD	L1_CACHE_BYTES
 
 #define cmpxchg64(ptr, o, n)						\
   ({									\
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 3b4dcc8..ab3e392 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -101,10 +101,6 @@
 EXPORT_SYMBOL(start_thread);
 EXPORT_SYMBOL(kernel_thread);
 
-#ifdef CONFIG_PPC_FPU
-EXPORT_SYMBOL_GPL(cvt_df);
-EXPORT_SYMBOL_GPL(cvt_fd);
-#endif
 EXPORT_SYMBOL(giveup_fpu);
 #ifdef CONFIG_ALTIVEC
 EXPORT_SYMBOL(giveup_altivec);
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c
index 8123125..9b9b5cd 100644
--- a/arch/powerpc/kvm/44x_tlb.c
+++ b/arch/powerpc/kvm/44x_tlb.c
@@ -316,7 +316,8 @@
 	gfn = gpaddr >> PAGE_SHIFT;
 	new_page = gfn_to_page(vcpu->kvm, gfn);
 	if (is_error_page(new_page)) {
-		printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n", gfn);
+		printk(KERN_ERR "Couldn't get guest page for gfn %llx!\n",
+			(unsigned long long)gfn);
 		kvm_release_page_clean(new_page);
 		return;
 	}
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index ff43606..d45c818 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -45,6 +45,7 @@
 	book3s.o \
 	book3s_emulate.o \
 	book3s_interrupts.o \
+	book3s_mmu_hpte.o \
 	book3s_64_mmu_host.o \
 	book3s_64_mmu.o \
 	book3s_32_mmu.o
@@ -57,6 +58,7 @@
 	book3s.o \
 	book3s_emulate.o \
 	book3s_interrupts.o \
+	book3s_mmu_hpte.o \
 	book3s_32_mmu_host.o \
 	book3s_32_mmu.o
 kvm-objs-$(CONFIG_KVM_BOOK3S_32) := $(kvm-book3s_32-objs)
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index b998abf..a3cef30 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -1047,8 +1047,6 @@
 {
 	int i;
 
-	vcpu_load(vcpu);
-
 	regs->pc = kvmppc_get_pc(vcpu);
 	regs->cr = kvmppc_get_cr(vcpu);
 	regs->ctr = kvmppc_get_ctr(vcpu);
@@ -1069,8 +1067,6 @@
 	for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
 		regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
@@ -1078,8 +1074,6 @@
 {
 	int i;
 
-	vcpu_load(vcpu);
-
 	kvmppc_set_pc(vcpu, regs->pc);
 	kvmppc_set_cr(vcpu, regs->cr);
 	kvmppc_set_ctr(vcpu, regs->ctr);
@@ -1099,8 +1093,6 @@
 	for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
 		kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
@@ -1110,8 +1102,6 @@
 	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
 	int i;
 
-	vcpu_load(vcpu);
-
 	sregs->pvr = vcpu->arch.pvr;
 
 	sregs->u.s.sdr1 = to_book3s(vcpu)->sdr1;
@@ -1131,8 +1121,6 @@
 		}
 	}
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
@@ -1142,8 +1130,6 @@
 	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
 	int i;
 
-	vcpu_load(vcpu);
-
 	kvmppc_set_pvr(vcpu, sregs->pvr);
 
 	vcpu3s->sdr1 = sregs->u.s.sdr1;
@@ -1171,8 +1157,6 @@
 	/* Flush the MMU after messing with the segments */
 	kvmppc_mmu_pte_flush(vcpu, 0, 0);
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
@@ -1309,12 +1293,17 @@
 int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
 	int ret;
-	struct thread_struct ext_bkp;
+	double fpr[32][TS_FPRWIDTH];
+	unsigned int fpscr;
+	int fpexc_mode;
 #ifdef CONFIG_ALTIVEC
-	bool save_vec = current->thread.used_vr;
+	vector128 vr[32];
+	vector128 vscr;
+	unsigned long uninitialized_var(vrsave);
+	int used_vr;
 #endif
 #ifdef CONFIG_VSX
-	bool save_vsx = current->thread.used_vsr;
+	int used_vsr;
 #endif
 	ulong ext_msr;
 
@@ -1327,27 +1316,27 @@
 	/* Save FPU state in stack */
 	if (current->thread.regs->msr & MSR_FP)
 		giveup_fpu(current);
-	memcpy(ext_bkp.fpr, current->thread.fpr, sizeof(current->thread.fpr));
-	ext_bkp.fpscr = current->thread.fpscr;
-	ext_bkp.fpexc_mode = current->thread.fpexc_mode;
+	memcpy(fpr, current->thread.fpr, sizeof(current->thread.fpr));
+	fpscr = current->thread.fpscr.val;
+	fpexc_mode = current->thread.fpexc_mode;
 
 #ifdef CONFIG_ALTIVEC
 	/* Save Altivec state in stack */
-	if (save_vec) {
+	used_vr = current->thread.used_vr;
+	if (used_vr) {
 		if (current->thread.regs->msr & MSR_VEC)
 			giveup_altivec(current);
-		memcpy(ext_bkp.vr, current->thread.vr, sizeof(ext_bkp.vr));
-		ext_bkp.vscr = current->thread.vscr;
-		ext_bkp.vrsave = current->thread.vrsave;
+		memcpy(vr, current->thread.vr, sizeof(current->thread.vr));
+		vscr = current->thread.vscr;
+		vrsave = current->thread.vrsave;
 	}
-	ext_bkp.used_vr = current->thread.used_vr;
 #endif
 
 #ifdef CONFIG_VSX
 	/* Save VSX state in stack */
-	if (save_vsx && (current->thread.regs->msr & MSR_VSX))
+	used_vsr = current->thread.used_vsr;
+	if (used_vsr && (current->thread.regs->msr & MSR_VSX))
 			__giveup_vsx(current);
-	ext_bkp.used_vsr = current->thread.used_vsr;
 #endif
 
 	/* Remember the MSR with disabled extensions */
@@ -1372,22 +1361,22 @@
 	kvmppc_giveup_ext(vcpu, MSR_VSX);
 
 	/* Restore FPU state from stack */
-	memcpy(current->thread.fpr, ext_bkp.fpr, sizeof(ext_bkp.fpr));
-	current->thread.fpscr = ext_bkp.fpscr;
-	current->thread.fpexc_mode = ext_bkp.fpexc_mode;
+	memcpy(current->thread.fpr, fpr, sizeof(current->thread.fpr));
+	current->thread.fpscr.val = fpscr;
+	current->thread.fpexc_mode = fpexc_mode;
 
 #ifdef CONFIG_ALTIVEC
 	/* Restore Altivec state from stack */
-	if (save_vec && current->thread.used_vr) {
-		memcpy(current->thread.vr, ext_bkp.vr, sizeof(ext_bkp.vr));
-		current->thread.vscr = ext_bkp.vscr;
-		current->thread.vrsave= ext_bkp.vrsave;
+	if (used_vr && current->thread.used_vr) {
+		memcpy(current->thread.vr, vr, sizeof(current->thread.vr));
+		current->thread.vscr = vscr;
+		current->thread.vrsave = vrsave;
 	}
-	current->thread.used_vr = ext_bkp.used_vr;
+	current->thread.used_vr = used_vr;
 #endif
 
 #ifdef CONFIG_VSX
-	current->thread.used_vsr = ext_bkp.used_vsr;
+	current->thread.used_vsr = used_vsr;
 #endif
 
 	return ret;
@@ -1395,12 +1384,22 @@
 
 static int kvmppc_book3s_init(void)
 {
-	return kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), 0,
-			THIS_MODULE);
+	int r;
+
+	r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), 0,
+		     THIS_MODULE);
+
+	if (r)
+		return r;
+
+	r = kvmppc_mmu_hpte_sysinit();
+
+	return r;
 }
 
 static void kvmppc_book3s_exit(void)
 {
+	kvmppc_mmu_hpte_sysexit();
 	kvm_exit();
 }
 
diff --git a/arch/powerpc/kvm/book3s_32_mmu.c b/arch/powerpc/kvm/book3s_32_mmu.c
index 0b10503..3292d76 100644
--- a/arch/powerpc/kvm/book3s_32_mmu.c
+++ b/arch/powerpc/kvm/book3s_32_mmu.c
@@ -354,10 +354,10 @@
 		*vsid = VSID_REAL_DR | gvsid;
 		break;
 	case MSR_DR|MSR_IR:
-		if (!sr->valid)
-			return -1;
-
-		*vsid = sr->vsid;
+		if (sr->valid)
+			*vsid = sr->vsid;
+		else
+			*vsid = VSID_BAT | gvsid;
 		break;
 	default:
 		BUG();
diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c
index 0bb6600..0b51ef8 100644
--- a/arch/powerpc/kvm/book3s_32_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_32_mmu_host.c
@@ -19,6 +19,7 @@
  */
 
 #include <linux/kvm_host.h>
+#include <linux/hash.h>
 
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
@@ -57,139 +58,26 @@
 static ulong htab;
 static u32 htabmask;
 
-static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
+void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
 {
 	volatile u32 *pteg;
 
-	dprintk_mmu("KVM: Flushing SPTE: 0x%llx (0x%llx) -> 0x%llx\n",
-		    pte->pte.eaddr, pte->pte.vpage, pte->host_va);
-
+	/* Remove from host HTAB */
 	pteg = (u32*)pte->slot;
-
 	pteg[0] = 0;
+
+	/* And make sure it's gone from the TLB too */
 	asm volatile ("sync");
 	asm volatile ("tlbie %0" : : "r" (pte->pte.eaddr) : "memory");
 	asm volatile ("sync");
 	asm volatile ("tlbsync");
-
-	pte->host_va = 0;
-
-	if (pte->pte.may_write)
-		kvm_release_pfn_dirty(pte->pfn);
-	else
-		kvm_release_pfn_clean(pte->pfn);
-}
-
-void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
-{
-	int i;
-
-	dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%x & 0x%x\n",
-		    vcpu->arch.hpte_cache_offset, guest_ea, ea_mask);
-	BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
-
-	guest_ea &= ea_mask;
-	for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
-		struct hpte_cache *pte;
-
-		pte = &vcpu->arch.hpte_cache[i];
-		if (!pte->host_va)
-			continue;
-
-		if ((pte->pte.eaddr & ea_mask) == guest_ea) {
-			invalidate_pte(vcpu, pte);
-		}
-	}
-
-	/* Doing a complete flush -> start from scratch */
-	if (!ea_mask)
-		vcpu->arch.hpte_cache_offset = 0;
-}
-
-void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
-{
-	int i;
-
-	dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n",
-		    vcpu->arch.hpte_cache_offset, guest_vp, vp_mask);
-	BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
-
-	guest_vp &= vp_mask;
-	for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
-		struct hpte_cache *pte;
-
-		pte = &vcpu->arch.hpte_cache[i];
-		if (!pte->host_va)
-			continue;
-
-		if ((pte->pte.vpage & vp_mask) == guest_vp) {
-			invalidate_pte(vcpu, pte);
-		}
-	}
-}
-
-void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
-{
-	int i;
-
-	dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%llx & 0x%llx\n",
-		    vcpu->arch.hpte_cache_offset, pa_start, pa_end);
-	BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
-
-	for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
-		struct hpte_cache *pte;
-
-		pte = &vcpu->arch.hpte_cache[i];
-		if (!pte->host_va)
-			continue;
-
-		if ((pte->pte.raddr >= pa_start) &&
-		    (pte->pte.raddr < pa_end)) {
-			invalidate_pte(vcpu, pte);
-		}
-	}
-}
-
-struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data)
-{
-	int i;
-	u64 guest_vp;
-
-	guest_vp = vcpu->arch.mmu.ea_to_vp(vcpu, ea, false);
-	for (i=0; i<vcpu->arch.hpte_cache_offset; i++) {
-		struct hpte_cache *pte;
-
-		pte = &vcpu->arch.hpte_cache[i];
-		if (!pte->host_va)
-			continue;
-
-		if (pte->pte.vpage == guest_vp)
-			return &pte->pte;
-	}
-
-	return NULL;
-}
-
-static int kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
-{
-	if (vcpu->arch.hpte_cache_offset == HPTEG_CACHE_NUM)
-		kvmppc_mmu_pte_flush(vcpu, 0, 0);
-
-	return vcpu->arch.hpte_cache_offset++;
 }
 
 /* We keep 512 gvsid->hvsid entries, mapping the guest ones to the array using
  * a hash, so we don't waste cycles on looping */
 static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid)
 {
-	return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK));
+	return hash_64(gvsid, SID_MAP_BITS);
 }
 
 
@@ -256,7 +144,6 @@
 	register int rr = 0;
 	bool primary = false;
 	bool evict = false;
-	int hpte_id;
 	struct hpte_cache *pte;
 
 	/* Get host physical address for gpa */
@@ -341,8 +228,7 @@
 
 	/* Now tell our Shadow PTE code about the new page */
 
-	hpte_id = kvmppc_mmu_hpte_cache_next(vcpu);
-	pte = &vcpu->arch.hpte_cache[hpte_id];
+	pte = kvmppc_mmu_hpte_cache_next(vcpu);
 
 	dprintk_mmu("KVM: %c%c Map 0x%llx: [%lx] 0x%llx (0x%llx) -> %lx\n",
 		    orig_pte->may_write ? 'w' : '-',
@@ -355,6 +241,8 @@
 	pte->pte = *orig_pte;
 	pte->pfn = hpaddr >> PAGE_SHIFT;
 
+	kvmppc_mmu_hpte_cache_map(vcpu, pte);
+
 	return 0;
 }
 
@@ -439,7 +327,7 @@
 
 void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
 {
-	kvmppc_mmu_pte_flush(vcpu, 0, 0);
+	kvmppc_mmu_hpte_destroy(vcpu);
 	preempt_disable();
 	__destroy_context(to_book3s(vcpu)->context_id);
 	preempt_enable();
@@ -479,5 +367,7 @@
 	htabmask = ((sdr1 & 0x1FF) << 16) | 0xFFC0;
 	htab = (ulong)__va(sdr1 & 0xffff0000);
 
+	kvmppc_mmu_hpte_init(vcpu);
+
 	return 0;
 }
diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c
index e4b5744..384179a 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_host.c
@@ -20,6 +20,7 @@
  */
 
 #include <linux/kvm_host.h>
+#include <linux/hash.h>
 
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
@@ -46,135 +47,20 @@
 #define dprintk_slb(a, ...) do { } while(0)
 #endif
 
-static void invalidate_pte(struct hpte_cache *pte)
+void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
 {
-	dprintk_mmu("KVM: Flushing SPT: 0x%lx (0x%llx) -> 0x%llx\n",
-		    pte->pte.eaddr, pte->pte.vpage, pte->host_va);
-
 	ppc_md.hpte_invalidate(pte->slot, pte->host_va,
 			       MMU_PAGE_4K, MMU_SEGSIZE_256M,
 			       false);
-	pte->host_va = 0;
-
-	if (pte->pte.may_write)
-		kvm_release_pfn_dirty(pte->pfn);
-	else
-		kvm_release_pfn_clean(pte->pfn);
-}
-
-void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
-{
-	int i;
-
-	dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%lx & 0x%lx\n",
-		    vcpu->arch.hpte_cache_offset, guest_ea, ea_mask);
-	BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
-
-	guest_ea &= ea_mask;
-	for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
-		struct hpte_cache *pte;
-
-		pte = &vcpu->arch.hpte_cache[i];
-		if (!pte->host_va)
-			continue;
-
-		if ((pte->pte.eaddr & ea_mask) == guest_ea) {
-			invalidate_pte(pte);
-		}
-	}
-
-	/* Doing a complete flush -> start from scratch */
-	if (!ea_mask)
-		vcpu->arch.hpte_cache_offset = 0;
-}
-
-void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
-{
-	int i;
-
-	dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n",
-		    vcpu->arch.hpte_cache_offset, guest_vp, vp_mask);
-	BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
-
-	guest_vp &= vp_mask;
-	for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
-		struct hpte_cache *pte;
-
-		pte = &vcpu->arch.hpte_cache[i];
-		if (!pte->host_va)
-			continue;
-
-		if ((pte->pte.vpage & vp_mask) == guest_vp) {
-			invalidate_pte(pte);
-		}
-	}
-}
-
-void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
-{
-	int i;
-
-	dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%lx & 0x%lx\n",
-		    vcpu->arch.hpte_cache_offset, pa_start, pa_end);
-	BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
-
-	for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
-		struct hpte_cache *pte;
-
-		pte = &vcpu->arch.hpte_cache[i];
-		if (!pte->host_va)
-			continue;
-
-		if ((pte->pte.raddr >= pa_start) &&
-		    (pte->pte.raddr < pa_end)) {
-			invalidate_pte(pte);
-		}
-	}
-}
-
-struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data)
-{
-	int i;
-	u64 guest_vp;
-
-	guest_vp = vcpu->arch.mmu.ea_to_vp(vcpu, ea, false);
-	for (i=0; i<vcpu->arch.hpte_cache_offset; i++) {
-		struct hpte_cache *pte;
-
-		pte = &vcpu->arch.hpte_cache[i];
-		if (!pte->host_va)
-			continue;
-
-		if (pte->pte.vpage == guest_vp)
-			return &pte->pte;
-	}
-
-	return NULL;
-}
-
-static int kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
-{
-	if (vcpu->arch.hpte_cache_offset == HPTEG_CACHE_NUM)
-		kvmppc_mmu_pte_flush(vcpu, 0, 0);
-
-	return vcpu->arch.hpte_cache_offset++;
 }
 
 /* We keep 512 gvsid->hvsid entries, mapping the guest ones to the array using
  * a hash, so we don't waste cycles on looping */
 static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid)
 {
-	return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^
-		     ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK));
+	return hash_64(gvsid, SID_MAP_BITS);
 }
 
-
 static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
 {
 	struct kvmppc_sid_map *map;
@@ -273,8 +159,7 @@
 		attempt++;
 		goto map_again;
 	} else {
-		int hpte_id = kvmppc_mmu_hpte_cache_next(vcpu);
-		struct hpte_cache *pte = &vcpu->arch.hpte_cache[hpte_id];
+		struct hpte_cache *pte = kvmppc_mmu_hpte_cache_next(vcpu);
 
 		dprintk_mmu("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx\n",
 			    ((rflags & HPTE_R_PP) == 3) ? '-' : 'w',
@@ -292,6 +177,8 @@
 		pte->host_va = va;
 		pte->pte = *orig_pte;
 		pte->pfn = hpaddr >> PAGE_SHIFT;
+
+		kvmppc_mmu_hpte_cache_map(vcpu, pte);
 	}
 
 	return 0;
@@ -418,7 +305,7 @@
 
 void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
 {
-	kvmppc_mmu_pte_flush(vcpu, 0, 0);
+	kvmppc_mmu_hpte_destroy(vcpu);
 	__destroy_context(to_book3s(vcpu)->context_id);
 }
 
@@ -436,5 +323,7 @@
 	vcpu3s->vsid_first = vcpu3s->context_id << USER_ESID_BITS;
 	vcpu3s->vsid_next = vcpu3s->vsid_first;
 
+	kvmppc_mmu_hpte_init(vcpu);
+
 	return 0;
 }
diff --git a/arch/powerpc/kvm/book3s_mmu_hpte.c b/arch/powerpc/kvm/book3s_mmu_hpte.c
new file mode 100644
index 0000000..4868d4a
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_mmu_hpte.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved.
+ *
+ * Authors:
+ *     Alexander Graf <agraf@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/hash.h>
+#include <linux/slab.h>
+
+#include <asm/kvm_ppc.h>
+#include <asm/kvm_book3s.h>
+#include <asm/machdep.h>
+#include <asm/mmu_context.h>
+#include <asm/hw_irq.h>
+
+#define PTE_SIZE	12
+
+/* #define DEBUG_MMU */
+
+#ifdef DEBUG_MMU
+#define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__)
+#else
+#define dprintk_mmu(a, ...) do { } while(0)
+#endif
+
+static struct kmem_cache *hpte_cache;
+
+static inline u64 kvmppc_mmu_hash_pte(u64 eaddr)
+{
+	return hash_64(eaddr >> PTE_SIZE, HPTEG_HASH_BITS_PTE);
+}
+
+static inline u64 kvmppc_mmu_hash_vpte(u64 vpage)
+{
+	return hash_64(vpage & 0xfffffffffULL, HPTEG_HASH_BITS_VPTE);
+}
+
+static inline u64 kvmppc_mmu_hash_vpte_long(u64 vpage)
+{
+	return hash_64((vpage & 0xffffff000ULL) >> 12,
+		       HPTEG_HASH_BITS_VPTE_LONG);
+}
+
+void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
+{
+	u64 index;
+
+	/* Add to ePTE list */
+	index = kvmppc_mmu_hash_pte(pte->pte.eaddr);
+	hlist_add_head(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]);
+
+	/* Add to vPTE list */
+	index = kvmppc_mmu_hash_vpte(pte->pte.vpage);
+	hlist_add_head(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]);
+
+	/* Add to vPTE_long list */
+	index = kvmppc_mmu_hash_vpte_long(pte->pte.vpage);
+	hlist_add_head(&pte->list_vpte_long,
+		       &vcpu->arch.hpte_hash_vpte_long[index]);
+}
+
+static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
+{
+	dprintk_mmu("KVM: Flushing SPT: 0x%lx (0x%llx) -> 0x%llx\n",
+		    pte->pte.eaddr, pte->pte.vpage, pte->host_va);
+
+	/* Different for 32 and 64 bit */
+	kvmppc_mmu_invalidate_pte(vcpu, pte);
+
+	if (pte->pte.may_write)
+		kvm_release_pfn_dirty(pte->pfn);
+	else
+		kvm_release_pfn_clean(pte->pfn);
+
+	hlist_del(&pte->list_pte);
+	hlist_del(&pte->list_vpte);
+	hlist_del(&pte->list_vpte_long);
+
+	vcpu->arch.hpte_cache_count--;
+	kmem_cache_free(hpte_cache, pte);
+}
+
+static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu)
+{
+	struct hpte_cache *pte;
+	struct hlist_node *node, *tmp;
+	int i;
+
+	for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
+		struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
+
+		hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
+			invalidate_pte(vcpu, pte);
+	}
+}
+
+static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea)
+{
+	struct hlist_head *list;
+	struct hlist_node *node, *tmp;
+	struct hpte_cache *pte;
+
+	/* Find the list of entries in the map */
+	list = &vcpu->arch.hpte_hash_pte[kvmppc_mmu_hash_pte(guest_ea)];
+
+	/* Check the list for matching entries and invalidate */
+	hlist_for_each_entry_safe(pte, node, tmp, list, list_pte)
+		if ((pte->pte.eaddr & ~0xfffUL) == guest_ea)
+			invalidate_pte(vcpu, pte);
+}
+
+void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
+{
+	u64 i;
+
+	dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%lx & 0x%lx\n",
+		    vcpu->arch.hpte_cache_count, guest_ea, ea_mask);
+
+	guest_ea &= ea_mask;
+
+	switch (ea_mask) {
+	case ~0xfffUL:
+		kvmppc_mmu_pte_flush_page(vcpu, guest_ea);
+		break;
+	case 0x0ffff000:
+		/* 32-bit flush w/o segment, go through all possible segments */
+		for (i = 0; i < 0x100000000ULL; i += 0x10000000ULL)
+			kvmppc_mmu_pte_flush(vcpu, guest_ea | i, ~0xfffUL);
+		break;
+	case 0:
+		/* Doing a complete flush -> start from scratch */
+		kvmppc_mmu_pte_flush_all(vcpu);
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+}
+
+/* Flush with mask 0xfffffffff */
+static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp)
+{
+	struct hlist_head *list;
+	struct hlist_node *node, *tmp;
+	struct hpte_cache *pte;
+	u64 vp_mask = 0xfffffffffULL;
+
+	list = &vcpu->arch.hpte_hash_vpte[kvmppc_mmu_hash_vpte(guest_vp)];
+
+	/* Check the list for matching entries and invalidate */
+	hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte)
+		if ((pte->pte.vpage & vp_mask) == guest_vp)
+			invalidate_pte(vcpu, pte);
+}
+
+/* Flush with mask 0xffffff000 */
+static void kvmppc_mmu_pte_vflush_long(struct kvm_vcpu *vcpu, u64 guest_vp)
+{
+	struct hlist_head *list;
+	struct hlist_node *node, *tmp;
+	struct hpte_cache *pte;
+	u64 vp_mask = 0xffffff000ULL;
+
+	list = &vcpu->arch.hpte_hash_vpte_long[
+		kvmppc_mmu_hash_vpte_long(guest_vp)];
+
+	/* Check the list for matching entries and invalidate */
+	hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
+		if ((pte->pte.vpage & vp_mask) == guest_vp)
+			invalidate_pte(vcpu, pte);
+}
+
+void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
+{
+	dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n",
+		    vcpu->arch.hpte_cache_count, guest_vp, vp_mask);
+	guest_vp &= vp_mask;
+
+	switch(vp_mask) {
+	case 0xfffffffffULL:
+		kvmppc_mmu_pte_vflush_short(vcpu, guest_vp);
+		break;
+	case 0xffffff000ULL:
+		kvmppc_mmu_pte_vflush_long(vcpu, guest_vp);
+		break;
+	default:
+		WARN_ON(1);
+		return;
+	}
+}
+
+void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
+{
+	struct hlist_node *node, *tmp;
+	struct hpte_cache *pte;
+	int i;
+
+	dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%lx - 0x%lx\n",
+		    vcpu->arch.hpte_cache_count, pa_start, pa_end);
+
+	for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
+		struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
+
+		hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
+			if ((pte->pte.raddr >= pa_start) &&
+			    (pte->pte.raddr < pa_end))
+				invalidate_pte(vcpu, pte);
+	}
+}
+
+struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
+{
+	struct hpte_cache *pte;
+
+	pte = kmem_cache_zalloc(hpte_cache, GFP_KERNEL);
+	vcpu->arch.hpte_cache_count++;
+
+	if (vcpu->arch.hpte_cache_count == HPTEG_CACHE_NUM)
+		kvmppc_mmu_pte_flush_all(vcpu);
+
+	return pte;
+}
+
+void kvmppc_mmu_hpte_destroy(struct kvm_vcpu *vcpu)
+{
+	kvmppc_mmu_pte_flush(vcpu, 0, 0);
+}
+
+static void kvmppc_mmu_hpte_init_hash(struct hlist_head *hash_list, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		INIT_HLIST_HEAD(&hash_list[i]);
+}
+
+int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu)
+{
+	/* init hpte lookup hashes */
+	kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte,
+				  ARRAY_SIZE(vcpu->arch.hpte_hash_pte));
+	kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte,
+				  ARRAY_SIZE(vcpu->arch.hpte_hash_vpte));
+	kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte_long,
+				  ARRAY_SIZE(vcpu->arch.hpte_hash_vpte_long));
+
+	return 0;
+}
+
+int kvmppc_mmu_hpte_sysinit(void)
+{
+	/* init hpte slab cache */
+	hpte_cache = kmem_cache_create("kvm-spt", sizeof(struct hpte_cache),
+				       sizeof(struct hpte_cache), 0, NULL);
+
+	return 0;
+}
+
+void kvmppc_mmu_hpte_sysexit(void)
+{
+	kmem_cache_destroy(hpte_cache);
+}
diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
index a9f66ab..474f2e2 100644
--- a/arch/powerpc/kvm/book3s_paired_singles.c
+++ b/arch/powerpc/kvm/book3s_paired_singles.c
@@ -159,10 +159,7 @@
 
 static inline void kvmppc_sync_qpr(struct kvm_vcpu *vcpu, int rt)
 {
-	struct thread_struct t;
-
-	t.fpscr.val = vcpu->arch.fpscr;
-	cvt_df((double*)&vcpu->arch.fpr[rt], (float*)&vcpu->arch.qpr[rt], &t);
+	kvm_cvt_df(&vcpu->arch.fpr[rt], &vcpu->arch.qpr[rt], &vcpu->arch.fpscr);
 }
 
 static void kvmppc_inject_pf(struct kvm_vcpu *vcpu, ulong eaddr, bool is_store)
@@ -183,7 +180,6 @@
 				   int rs, ulong addr, int ls_type)
 {
 	int emulated = EMULATE_FAIL;
-	struct thread_struct t;
 	int r;
 	char tmp[8];
 	int len = sizeof(u32);
@@ -191,8 +187,6 @@
 	if (ls_type == FPU_LS_DOUBLE)
 		len = sizeof(u64);
 
-	t.fpscr.val = vcpu->arch.fpscr;
-
 	/* read from memory */
 	r = kvmppc_ld(vcpu, &addr, len, tmp, true);
 	vcpu->arch.paddr_accessed = addr;
@@ -210,7 +204,7 @@
 	/* put in registers */
 	switch (ls_type) {
 	case FPU_LS_SINGLE:
-		cvt_fd((float*)tmp, (double*)&vcpu->arch.fpr[rs], &t);
+		kvm_cvt_fd((u32*)tmp, &vcpu->arch.fpr[rs], &vcpu->arch.fpscr);
 		vcpu->arch.qpr[rs] = *((u32*)tmp);
 		break;
 	case FPU_LS_DOUBLE:
@@ -229,17 +223,14 @@
 				    int rs, ulong addr, int ls_type)
 {
 	int emulated = EMULATE_FAIL;
-	struct thread_struct t;
 	int r;
 	char tmp[8];
 	u64 val;
 	int len;
 
-	t.fpscr.val = vcpu->arch.fpscr;
-
 	switch (ls_type) {
 	case FPU_LS_SINGLE:
-		cvt_df((double*)&vcpu->arch.fpr[rs], (float*)tmp, &t);
+		kvm_cvt_df(&vcpu->arch.fpr[rs], (u32*)tmp, &vcpu->arch.fpscr);
 		val = *((u32*)tmp);
 		len = sizeof(u32);
 		break;
@@ -278,13 +269,10 @@
 				   int rs, ulong addr, bool w, int i)
 {
 	int emulated = EMULATE_FAIL;
-	struct thread_struct t;
 	int r;
 	float one = 1.0;
 	u32 tmp[2];
 
-	t.fpscr.val = vcpu->arch.fpscr;
-
 	/* read from memory */
 	if (w) {
 		r = kvmppc_ld(vcpu, &addr, sizeof(u32), tmp, true);
@@ -308,7 +296,7 @@
 	emulated = EMULATE_DONE;
 
 	/* put in registers */
-	cvt_fd((float*)&tmp[0], (double*)&vcpu->arch.fpr[rs], &t);
+	kvm_cvt_fd(&tmp[0], &vcpu->arch.fpr[rs], &vcpu->arch.fpscr);
 	vcpu->arch.qpr[rs] = tmp[1];
 
 	dprintk(KERN_INFO "KVM: PSQ_LD [0x%x, 0x%x] at 0x%lx (%d)\n", tmp[0],
@@ -322,14 +310,11 @@
 				    int rs, ulong addr, bool w, int i)
 {
 	int emulated = EMULATE_FAIL;
-	struct thread_struct t;
 	int r;
 	u32 tmp[2];
 	int len = w ? sizeof(u32) : sizeof(u64);
 
-	t.fpscr.val = vcpu->arch.fpscr;
-
-	cvt_df((double*)&vcpu->arch.fpr[rs], (float*)&tmp[0], &t);
+	kvm_cvt_df(&vcpu->arch.fpr[rs], &tmp[0], &vcpu->arch.fpscr);
 	tmp[1] = vcpu->arch.qpr[rs];
 
 	r = kvmppc_st(vcpu, &addr, len, tmp, true);
@@ -517,7 +502,7 @@
 static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc,
 				      int reg_out, int reg_in1, int reg_in2,
 				      int reg_in3, int scalar,
-				      void (*func)(struct thread_struct *t,
+				      void (*func)(u64 *fpscr,
 						 u32 *dst, u32 *src1,
 						 u32 *src2, u32 *src3))
 {
@@ -526,27 +511,25 @@
 	u32 ps0_out;
 	u32 ps0_in1, ps0_in2, ps0_in3;
 	u32 ps1_in1, ps1_in2, ps1_in3;
-	struct thread_struct t;
-	t.fpscr.val = vcpu->arch.fpscr;
 
 	/* RC */
 	WARN_ON(rc);
 
 	/* PS0 */
-	cvt_df((double*)&fpr[reg_in1], (float*)&ps0_in1, &t);
-	cvt_df((double*)&fpr[reg_in2], (float*)&ps0_in2, &t);
-	cvt_df((double*)&fpr[reg_in3], (float*)&ps0_in3, &t);
+	kvm_cvt_df(&fpr[reg_in1], &ps0_in1, &vcpu->arch.fpscr);
+	kvm_cvt_df(&fpr[reg_in2], &ps0_in2, &vcpu->arch.fpscr);
+	kvm_cvt_df(&fpr[reg_in3], &ps0_in3, &vcpu->arch.fpscr);
 
 	if (scalar & SCALAR_LOW)
 		ps0_in2 = qpr[reg_in2];
 
-	func(&t, &ps0_out, &ps0_in1, &ps0_in2, &ps0_in3);
+	func(&vcpu->arch.fpscr, &ps0_out, &ps0_in1, &ps0_in2, &ps0_in3);
 
 	dprintk(KERN_INFO "PS3 ps0 -> f(0x%x, 0x%x, 0x%x) = 0x%x\n",
 			  ps0_in1, ps0_in2, ps0_in3, ps0_out);
 
 	if (!(scalar & SCALAR_NO_PS0))
-		cvt_fd((float*)&ps0_out, (double*)&fpr[reg_out], &t);
+		kvm_cvt_fd(&ps0_out, &fpr[reg_out], &vcpu->arch.fpscr);
 
 	/* PS1 */
 	ps1_in1 = qpr[reg_in1];
@@ -557,7 +540,7 @@
 		ps1_in2 = ps0_in2;
 
 	if (!(scalar & SCALAR_NO_PS1))
-		func(&t, &qpr[reg_out], &ps1_in1, &ps1_in2, &ps1_in3);
+		func(&vcpu->arch.fpscr, &qpr[reg_out], &ps1_in1, &ps1_in2, &ps1_in3);
 
 	dprintk(KERN_INFO "PS3 ps1 -> f(0x%x, 0x%x, 0x%x) = 0x%x\n",
 			  ps1_in1, ps1_in2, ps1_in3, qpr[reg_out]);
@@ -568,7 +551,7 @@
 static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc,
 				    int reg_out, int reg_in1, int reg_in2,
 				    int scalar,
-				    void (*func)(struct thread_struct *t,
+				    void (*func)(u64 *fpscr,
 						 u32 *dst, u32 *src1,
 						 u32 *src2))
 {
@@ -578,27 +561,25 @@
 	u32 ps0_in1, ps0_in2;
 	u32 ps1_out;
 	u32 ps1_in1, ps1_in2;
-	struct thread_struct t;
-	t.fpscr.val = vcpu->arch.fpscr;
 
 	/* RC */
 	WARN_ON(rc);
 
 	/* PS0 */
-	cvt_df((double*)&fpr[reg_in1], (float*)&ps0_in1, &t);
+	kvm_cvt_df(&fpr[reg_in1], &ps0_in1, &vcpu->arch.fpscr);
 
 	if (scalar & SCALAR_LOW)
 		ps0_in2 = qpr[reg_in2];
 	else
-		cvt_df((double*)&fpr[reg_in2], (float*)&ps0_in2, &t);
+		kvm_cvt_df(&fpr[reg_in2], &ps0_in2, &vcpu->arch.fpscr);
 
-	func(&t, &ps0_out, &ps0_in1, &ps0_in2);
+	func(&vcpu->arch.fpscr, &ps0_out, &ps0_in1, &ps0_in2);
 
 	if (!(scalar & SCALAR_NO_PS0)) {
 		dprintk(KERN_INFO "PS2 ps0 -> f(0x%x, 0x%x) = 0x%x\n",
 				  ps0_in1, ps0_in2, ps0_out);
 
-		cvt_fd((float*)&ps0_out, (double*)&fpr[reg_out], &t);
+		kvm_cvt_fd(&ps0_out, &fpr[reg_out], &vcpu->arch.fpscr);
 	}
 
 	/* PS1 */
@@ -608,7 +589,7 @@
 	if (scalar & SCALAR_HIGH)
 		ps1_in2 = ps0_in2;
 
-	func(&t, &ps1_out, &ps1_in1, &ps1_in2);
+	func(&vcpu->arch.fpscr, &ps1_out, &ps1_in1, &ps1_in2);
 
 	if (!(scalar & SCALAR_NO_PS1)) {
 		qpr[reg_out] = ps1_out;
@@ -622,31 +603,29 @@
 
 static int kvmppc_ps_one_in(struct kvm_vcpu *vcpu, bool rc,
 				    int reg_out, int reg_in,
-				    void (*func)(struct thread_struct *t,
+				    void (*func)(u64 *t,
 						 u32 *dst, u32 *src1))
 {
 	u32 *qpr = vcpu->arch.qpr;
 	u64 *fpr = vcpu->arch.fpr;
 	u32 ps0_out, ps0_in;
 	u32 ps1_in;
-	struct thread_struct t;
-	t.fpscr.val = vcpu->arch.fpscr;
 
 	/* RC */
 	WARN_ON(rc);
 
 	/* PS0 */
-	cvt_df((double*)&fpr[reg_in], (float*)&ps0_in, &t);
-	func(&t, &ps0_out, &ps0_in);
+	kvm_cvt_df(&fpr[reg_in], &ps0_in, &vcpu->arch.fpscr);
+	func(&vcpu->arch.fpscr, &ps0_out, &ps0_in);
 
 	dprintk(KERN_INFO "PS1 ps0 -> f(0x%x) = 0x%x\n",
 			  ps0_in, ps0_out);
 
-	cvt_fd((float*)&ps0_out, (double*)&fpr[reg_out], &t);
+	kvm_cvt_fd(&ps0_out, &fpr[reg_out], &vcpu->arch.fpscr);
 
 	/* PS1 */
 	ps1_in = qpr[reg_in];
-	func(&t, &qpr[reg_out], &ps1_in);
+	func(&vcpu->arch.fpscr, &qpr[reg_out], &ps1_in);
 
 	dprintk(KERN_INFO "PS1 ps1 -> f(0x%x) = 0x%x\n",
 			  ps1_in, qpr[reg_out]);
@@ -672,13 +651,10 @@
 
 	bool rcomp = (inst & 1) ? true : false;
 	u32 cr = kvmppc_get_cr(vcpu);
-	struct thread_struct t;
 #ifdef DEBUG
 	int i;
 #endif
 
-	t.fpscr.val = vcpu->arch.fpscr;
-
 	if (!kvmppc_inst_is_paired_single(vcpu, inst))
 		return EMULATE_FAIL;
 
@@ -695,7 +671,7 @@
 #ifdef DEBUG
 	for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) {
 		u32 f;
-		cvt_df((double*)&vcpu->arch.fpr[i], (float*)&f, &t);
+		kvm_cvt_df(&vcpu->arch.fpr[i], &f, &vcpu->arch.fpscr);
 		dprintk(KERN_INFO "FPR[%d] = 0x%x / 0x%llx    QPR[%d] = 0x%x\n",
 			i, f, vcpu->arch.fpr[i], i, vcpu->arch.qpr[i]);
 	}
@@ -819,8 +795,9 @@
 			WARN_ON(rcomp);
 			vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_ra];
 			/* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */
-			cvt_df((double*)&vcpu->arch.fpr[ax_rb],
-			       (float*)&vcpu->arch.qpr[ax_rd], &t);
+			kvm_cvt_df(&vcpu->arch.fpr[ax_rb],
+				   &vcpu->arch.qpr[ax_rd],
+				   &vcpu->arch.fpscr);
 			break;
 		case OP_4X_PS_MERGE01:
 			WARN_ON(rcomp);
@@ -830,17 +807,20 @@
 		case OP_4X_PS_MERGE10:
 			WARN_ON(rcomp);
 			/* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */
-			cvt_fd((float*)&vcpu->arch.qpr[ax_ra],
-			       (double*)&vcpu->arch.fpr[ax_rd], &t);
+			kvm_cvt_fd(&vcpu->arch.qpr[ax_ra],
+				   &vcpu->arch.fpr[ax_rd],
+				   &vcpu->arch.fpscr);
 			/* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */
-			cvt_df((double*)&vcpu->arch.fpr[ax_rb],
-			       (float*)&vcpu->arch.qpr[ax_rd], &t);
+			kvm_cvt_df(&vcpu->arch.fpr[ax_rb],
+				   &vcpu->arch.qpr[ax_rd],
+				   &vcpu->arch.fpscr);
 			break;
 		case OP_4X_PS_MERGE11:
 			WARN_ON(rcomp);
 			/* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */
-			cvt_fd((float*)&vcpu->arch.qpr[ax_ra],
-			       (double*)&vcpu->arch.fpr[ax_rd], &t);
+			kvm_cvt_fd(&vcpu->arch.qpr[ax_ra],
+				   &vcpu->arch.fpr[ax_rd],
+				   &vcpu->arch.fpscr);
 			vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
 			break;
 		}
@@ -1275,7 +1255,7 @@
 #ifdef DEBUG
 	for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) {
 		u32 f;
-		cvt_df((double*)&vcpu->arch.fpr[i], (float*)&f, &t);
+		kvm_cvt_df(&vcpu->arch.fpr[i], &f, &vcpu->arch.fpscr);
 		dprintk(KERN_INFO "FPR[%d] = 0x%x\n", i, f);
 	}
 #endif
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index a33ab8c..8d4e35f 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -144,7 +144,7 @@
                                         unsigned int priority)
 {
 	int allowed = 0;
-	ulong msr_mask;
+	ulong uninitialized_var(msr_mask);
 	bool update_esr = false, update_dear = false;
 
 	switch (priority) {
@@ -485,8 +485,6 @@
 {
 	int i;
 
-	vcpu_load(vcpu);
-
 	regs->pc = vcpu->arch.pc;
 	regs->cr = kvmppc_get_cr(vcpu);
 	regs->ctr = vcpu->arch.ctr;
@@ -507,8 +505,6 @@
 	for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
 		regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
@@ -516,8 +512,6 @@
 {
 	int i;
 
-	vcpu_load(vcpu);
-
 	vcpu->arch.pc = regs->pc;
 	kvmppc_set_cr(vcpu, regs->cr);
 	vcpu->arch.ctr = regs->ctr;
@@ -537,8 +531,6 @@
 	for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
 		kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
@@ -569,9 +561,7 @@
 {
 	int r;
 
-	vcpu_load(vcpu);
 	r = kvmppc_core_vcpu_translate(vcpu, tr);
-	vcpu_put(vcpu);
 	return r;
 }
 
diff --git a/arch/powerpc/kvm/fpu.S b/arch/powerpc/kvm/fpu.S
index 2b340a3..cb34bbe 100644
--- a/arch/powerpc/kvm/fpu.S
+++ b/arch/powerpc/kvm/fpu.S
@@ -271,3 +271,21 @@
 FPD_THREE_IN(fmadd)
 FPD_THREE_IN(fnmsub)
 FPD_THREE_IN(fnmadd)
+
+_GLOBAL(kvm_cvt_fd)
+	lfd	0,0(r5)			/* load up fpscr value */
+	MTFSF_L(0)
+	lfs	0,0(r3)
+	stfd	0,0(r4)
+	mffs	0
+	stfd	0,0(r5)			/* save new fpscr value */
+	blr
+
+_GLOBAL(kvm_cvt_df)
+	lfd	0,0(r5)			/* load up fpscr value */
+	MTFSF_L(0)
+	lfd	0,0(r3)
+	stfs	0,0(r4)
+	mffs	0
+	stfd	0,0(r5)			/* save new fpscr value */
+	blr
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 9b8683f..72a4ad8 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -36,11 +36,6 @@
 #define CREATE_TRACE_POINTS
 #include "trace.h"
 
-gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
-{
-	return gfn;
-}
-
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
 	return !(v->arch.msr & MSR_WE) || !!(v->arch.pending_exceptions);
@@ -287,7 +282,7 @@
 static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
                                       struct kvm_run *run)
 {
-	u64 gpr;
+	u64 uninitialized_var(gpr);
 
 	if (run->mmio.len > sizeof(gpr)) {
 		printk(KERN_ERR "bad MMIO length: %d\n", run->mmio.len);
@@ -423,8 +418,6 @@
 	int r;
 	sigset_t sigsaved;
 
-	vcpu_load(vcpu);
-
 	if (vcpu->sigset_active)
 		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
 
@@ -456,8 +449,6 @@
 	if (vcpu->sigset_active)
 		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
 
-	vcpu_put(vcpu);
-
 	return r;
 }
 
@@ -523,8 +514,9 @@
 		if (copy_from_user(&irq, argp, sizeof(irq)))
 			goto out;
 		r = kvm_vcpu_ioctl_interrupt(vcpu, &irq);
-		break;
+		goto out;
 	}
+
 	case KVM_ENABLE_CAP:
 	{
 		struct kvm_enable_cap cap;
diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c
index 9a9586f..f02e89c 100644
--- a/arch/s390/appldata/appldata_net_sum.c
+++ b/arch/s390/appldata/appldata_net_sum.c
@@ -85,7 +85,8 @@
 
 	rcu_read_lock();
 	for_each_netdev_rcu(&init_net, dev) {
-		const struct net_device_stats *stats = dev_get_stats(dev);
+		struct rtnl_link_stats64 temp;
+		const struct net_device_stats *stats = dev_get_stats(dev, &temp);
 
 		rx_packets += stats->rx_packets;
 		tx_packets += stats->tx_packets;
diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile
index 6a1157f..1cf81d7 100644
--- a/arch/s390/crypto/Makefile
+++ b/arch/s390/crypto/Makefile
@@ -5,6 +5,6 @@
 obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o sha_common.o
 obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o sha_common.o
 obj-$(CONFIG_CRYPTO_SHA512_S390) += sha512_s390.o sha_common.o
-obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o
+obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o
 obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
 obj-$(CONFIG_S390_PRNG) += prng.o
diff --git a/arch/s390/crypto/crypto_des.h b/arch/s390/crypto/crypto_des.h
index c964b64..6210457 100644
--- a/arch/s390/crypto/crypto_des.h
+++ b/arch/s390/crypto/crypto_des.h
@@ -15,4 +15,4 @@
 
 extern int crypto_des_check_key(const u8*, unsigned int, u32*);
 
-#endif //__CRYPTO_DES_H__
+#endif /*__CRYPTO_DES_H__*/
diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c
index 2bc479a..cc54201 100644
--- a/arch/s390/crypto/des_s390.c
+++ b/arch/s390/crypto/des_s390.c
@@ -14,32 +14,21 @@
  *
  */
 
-#include <crypto/algapi.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
+#include <crypto/des.h>
 
 #include "crypt_s390.h"
-#include "crypto_des.h"
-
-#define DES_BLOCK_SIZE 8
-#define DES_KEY_SIZE 8
-
-#define DES3_128_KEY_SIZE	(2 * DES_KEY_SIZE)
-#define DES3_128_BLOCK_SIZE	DES_BLOCK_SIZE
 
 #define DES3_192_KEY_SIZE	(3 * DES_KEY_SIZE)
-#define DES3_192_BLOCK_SIZE	DES_BLOCK_SIZE
 
 struct crypt_s390_des_ctx {
 	u8 iv[DES_BLOCK_SIZE];
 	u8 key[DES_KEY_SIZE];
 };
 
-struct crypt_s390_des3_128_ctx {
-	u8 iv[DES_BLOCK_SIZE];
-	u8 key[DES3_128_KEY_SIZE];
-};
-
 struct crypt_s390_des3_192_ctx {
 	u8 iv[DES_BLOCK_SIZE];
 	u8 key[DES3_192_KEY_SIZE];
@@ -50,13 +39,16 @@
 {
 	struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm);
 	u32 *flags = &tfm->crt_flags;
-	int ret;
+	u32 tmp[DES_EXPKEY_WORDS];
 
-	/* test if key is valid (not a weak key) */
-	ret = crypto_des_check_key(key, keylen, flags);
-	if (ret == 0)
-		memcpy(dctx->key, key, keylen);
-	return ret;
+	/* check for weak keys */
+	if (!des_ekey(tmp, key) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
+		return -EINVAL;
+	}
+
+	memcpy(dctx->key, key, keylen);
+	return 0;
 }
 
 static void des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
@@ -237,165 +229,6 @@
  *   complementation keys.  Any weakness is obviated by the use of
  *   multiple keys.
  *
- *   However, if the two  independent 64-bit keys are equal,
- *   then the DES3 operation is simply the same as DES.
- *   Implementers MUST reject keys that exhibit this property.
- *
- */
-static int des3_128_setkey(struct crypto_tfm *tfm, const u8 *key,
-			   unsigned int keylen)
-{
-	int i, ret;
-	struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
-	const u8 *temp_key = key;
-	u32 *flags = &tfm->crt_flags;
-
-	if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE)) &&
-	    (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
-		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
-		return -EINVAL;
-	}
-	for (i = 0; i < 2; i++, temp_key += DES_KEY_SIZE) {
-		ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
-		if (ret < 0)
-			return ret;
-	}
-	memcpy(dctx->key, key, keylen);
-	return 0;
-}
-
-static void des3_128_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-	struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
-
-	crypt_s390_km(KM_TDEA_128_ENCRYPT, dctx->key, dst, (void*)src,
-		      DES3_128_BLOCK_SIZE);
-}
-
-static void des3_128_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-	struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
-
-	crypt_s390_km(KM_TDEA_128_DECRYPT, dctx->key, dst, (void*)src,
-		      DES3_128_BLOCK_SIZE);
-}
-
-static struct crypto_alg des3_128_alg = {
-	.cra_name		=	"des3_ede128",
-	.cra_driver_name	=	"des3_ede128-s390",
-	.cra_priority		=	CRYPT_S390_PRIORITY,
-	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
-	.cra_blocksize		=	DES3_128_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct crypt_s390_des3_128_ctx),
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(des3_128_alg.cra_list),
-	.cra_u			=	{
-		.cipher = {
-			.cia_min_keysize	=	DES3_128_KEY_SIZE,
-			.cia_max_keysize	=	DES3_128_KEY_SIZE,
-			.cia_setkey		=	des3_128_setkey,
-			.cia_encrypt		=	des3_128_encrypt,
-			.cia_decrypt		=	des3_128_decrypt,
-		}
-	}
-};
-
-static int ecb_des3_128_encrypt(struct blkcipher_desc *desc,
-				struct scatterlist *dst,
-				struct scatterlist *src, unsigned int nbytes)
-{
-	struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
-	struct blkcipher_walk walk;
-
-	blkcipher_walk_init(&walk, dst, src, nbytes);
-	return ecb_desall_crypt(desc, KM_TDEA_128_ENCRYPT, sctx->key, &walk);
-}
-
-static int ecb_des3_128_decrypt(struct blkcipher_desc *desc,
-				struct scatterlist *dst,
-				struct scatterlist *src, unsigned int nbytes)
-{
-	struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
-	struct blkcipher_walk walk;
-
-	blkcipher_walk_init(&walk, dst, src, nbytes);
-	return ecb_desall_crypt(desc, KM_TDEA_128_DECRYPT, sctx->key, &walk);
-}
-
-static struct crypto_alg ecb_des3_128_alg = {
-	.cra_name		=	"ecb(des3_ede128)",
-	.cra_driver_name	=	"ecb-des3_ede128-s390",
-	.cra_priority		=	CRYPT_S390_COMPOSITE_PRIORITY,
-	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
-	.cra_blocksize		=	DES3_128_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct crypt_s390_des3_128_ctx),
-	.cra_type		=	&crypto_blkcipher_type,
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(
-						ecb_des3_128_alg.cra_list),
-	.cra_u			=	{
-		.blkcipher = {
-			.min_keysize		=	DES3_128_KEY_SIZE,
-			.max_keysize		=	DES3_128_KEY_SIZE,
-			.setkey			=	des3_128_setkey,
-			.encrypt		=	ecb_des3_128_encrypt,
-			.decrypt		=	ecb_des3_128_decrypt,
-		}
-	}
-};
-
-static int cbc_des3_128_encrypt(struct blkcipher_desc *desc,
-				struct scatterlist *dst,
-				struct scatterlist *src, unsigned int nbytes)
-{
-	struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
-	struct blkcipher_walk walk;
-
-	blkcipher_walk_init(&walk, dst, src, nbytes);
-	return cbc_desall_crypt(desc, KMC_TDEA_128_ENCRYPT, sctx->iv, &walk);
-}
-
-static int cbc_des3_128_decrypt(struct blkcipher_desc *desc,
-				struct scatterlist *dst,
-				struct scatterlist *src, unsigned int nbytes)
-{
-	struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
-	struct blkcipher_walk walk;
-
-	blkcipher_walk_init(&walk, dst, src, nbytes);
-	return cbc_desall_crypt(desc, KMC_TDEA_128_DECRYPT, sctx->iv, &walk);
-}
-
-static struct crypto_alg cbc_des3_128_alg = {
-	.cra_name		=	"cbc(des3_ede128)",
-	.cra_driver_name	=	"cbc-des3_ede128-s390",
-	.cra_priority		=	CRYPT_S390_COMPOSITE_PRIORITY,
-	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
-	.cra_blocksize		=	DES3_128_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct crypt_s390_des3_128_ctx),
-	.cra_type		=	&crypto_blkcipher_type,
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(
-						cbc_des3_128_alg.cra_list),
-	.cra_u			=	{
-		.blkcipher = {
-			.min_keysize		=	DES3_128_KEY_SIZE,
-			.max_keysize		=	DES3_128_KEY_SIZE,
-			.ivsize			=	DES3_128_BLOCK_SIZE,
-			.setkey			=	des3_128_setkey,
-			.encrypt		=	cbc_des3_128_encrypt,
-			.decrypt		=	cbc_des3_128_decrypt,
-		}
-	}
-};
-
-/*
- * RFC2451:
- *
- *   For DES-EDE3, there is no known need to reject weak or
- *   complementation keys.  Any weakness is obviated by the use of
- *   multiple keys.
- *
  *   However, if the first two or last two independent 64-bit keys are
  *   equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the
  *   same as DES.  Implementers MUST reject keys that exhibit this
@@ -405,9 +238,7 @@
 static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key,
 			   unsigned int keylen)
 {
-	int i, ret;
 	struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
-	const u8 *temp_key = key;
 	u32 *flags = &tfm->crt_flags;
 
 	if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
@@ -417,11 +248,6 @@
 		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
 		return -EINVAL;
 	}
-	for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) {
-		ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
-		if (ret < 0)
-			return ret;
-	}
 	memcpy(dctx->key, key, keylen);
 	return 0;
 }
@@ -431,7 +257,7 @@
 	struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
 
 	crypt_s390_km(KM_TDEA_192_ENCRYPT, dctx->key, dst, (void*)src,
-		      DES3_192_BLOCK_SIZE);
+		      DES_BLOCK_SIZE);
 }
 
 static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
@@ -439,7 +265,7 @@
 	struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
 
 	crypt_s390_km(KM_TDEA_192_DECRYPT, dctx->key, dst, (void*)src,
-		      DES3_192_BLOCK_SIZE);
+		      DES_BLOCK_SIZE);
 }
 
 static struct crypto_alg des3_192_alg = {
@@ -447,7 +273,7 @@
 	.cra_driver_name	=	"des3_ede-s390",
 	.cra_priority		=	CRYPT_S390_PRIORITY,
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
-	.cra_blocksize		=	DES3_192_BLOCK_SIZE,
+	.cra_blocksize		=	DES_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct crypt_s390_des3_192_ctx),
 	.cra_module		=	THIS_MODULE,
 	.cra_list		=	LIST_HEAD_INIT(des3_192_alg.cra_list),
@@ -489,7 +315,7 @@
 	.cra_driver_name	=	"ecb-des3_ede-s390",
 	.cra_priority		=	CRYPT_S390_COMPOSITE_PRIORITY,
 	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
-	.cra_blocksize		=	DES3_192_BLOCK_SIZE,
+	.cra_blocksize		=	DES_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct crypt_s390_des3_192_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
@@ -533,7 +359,7 @@
 	.cra_driver_name	=	"cbc-des3_ede-s390",
 	.cra_priority		=	CRYPT_S390_COMPOSITE_PRIORITY,
 	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
-	.cra_blocksize		=	DES3_192_BLOCK_SIZE,
+	.cra_blocksize		=	DES_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct crypt_s390_des3_192_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
@@ -543,7 +369,7 @@
 		.blkcipher = {
 			.min_keysize		=	DES3_192_KEY_SIZE,
 			.max_keysize		=	DES3_192_KEY_SIZE,
-			.ivsize			=	DES3_192_BLOCK_SIZE,
+			.ivsize			=	DES_BLOCK_SIZE,
 			.setkey			=	des3_192_setkey,
 			.encrypt		=	cbc_des3_192_encrypt,
 			.decrypt		=	cbc_des3_192_decrypt,
@@ -553,10 +379,9 @@
 
 static int des_s390_init(void)
 {
-	int ret = 0;
+	int ret;
 
 	if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
-	    !crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
 	    !crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
 		return -EOPNOTSUPP;
 
@@ -569,17 +394,6 @@
 	ret = crypto_register_alg(&cbc_des_alg);
 	if (ret)
 		goto cbc_des_err;
-
-	ret = crypto_register_alg(&des3_128_alg);
-	if (ret)
-		goto des3_128_err;
-	ret = crypto_register_alg(&ecb_des3_128_alg);
-	if (ret)
-		goto ecb_des3_128_err;
-	ret = crypto_register_alg(&cbc_des3_128_alg);
-	if (ret)
-		goto cbc_des3_128_err;
-
 	ret = crypto_register_alg(&des3_192_alg);
 	if (ret)
 		goto des3_192_err;
@@ -589,7 +403,6 @@
 	ret = crypto_register_alg(&cbc_des3_192_alg);
 	if (ret)
 		goto cbc_des3_192_err;
-
 out:
 	return ret;
 
@@ -598,12 +411,6 @@
 ecb_des3_192_err:
 	crypto_unregister_alg(&des3_192_alg);
 des3_192_err:
-	crypto_unregister_alg(&cbc_des3_128_alg);
-cbc_des3_128_err:
-	crypto_unregister_alg(&ecb_des3_128_alg);
-ecb_des3_128_err:
-	crypto_unregister_alg(&des3_128_alg);
-des3_128_err:
 	crypto_unregister_alg(&cbc_des_alg);
 cbc_des_err:
 	crypto_unregister_alg(&ecb_des_alg);
@@ -613,21 +420,18 @@
 	goto out;
 }
 
-static void __exit des_s390_fini(void)
+static void __exit des_s390_exit(void)
 {
 	crypto_unregister_alg(&cbc_des3_192_alg);
 	crypto_unregister_alg(&ecb_des3_192_alg);
 	crypto_unregister_alg(&des3_192_alg);
-	crypto_unregister_alg(&cbc_des3_128_alg);
-	crypto_unregister_alg(&ecb_des3_128_alg);
-	crypto_unregister_alg(&des3_128_alg);
 	crypto_unregister_alg(&cbc_des_alg);
 	crypto_unregister_alg(&ecb_des_alg);
 	crypto_unregister_alg(&des_alg);
 }
 
 module_init(des_s390_init);
-module_exit(des_s390_fini);
+module_exit(des_s390_exit);
 
 MODULE_ALIAS("des");
 MODULE_ALIAS("des3_ede");
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 27605b6..cef7dbf 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -26,7 +26,7 @@
 
 struct sca_entry {
 	atomic_t scn;
-	__u64	reserved;
+	__u32	reserved;
 	__u64	sda;
 	__u64	reserved2[2];
 } __attribute__((packed));
@@ -41,7 +41,8 @@
 } __attribute__((packed));
 
 #define KVM_NR_PAGE_SIZES 2
-#define KVM_HPAGE_SHIFT(x) (PAGE_SHIFT + ((x) - 1) * 8)
+#define KVM_HPAGE_GFN_SHIFT(x) (((x) - 1) * 8)
+#define KVM_HPAGE_SHIFT(x) (PAGE_SHIFT + KVM_HPAGE_GFN_SHIFT(x))
 #define KVM_HPAGE_SIZE(x) (1UL << KVM_HPAGE_SHIFT(x))
 #define KVM_HPAGE_MASK(x)	(~(KVM_HPAGE_SIZE(x) - 1))
 #define KVM_PAGES_PER_HPAGE(x)	(KVM_HPAGE_SIZE(x) / PAGE_SIZE)
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h
index 0eaae626..2ba6302 100644
--- a/arch/s390/include/asm/qdio.h
+++ b/arch/s390/include/asm/qdio.h
@@ -84,6 +84,7 @@
 
 #define QIB_AC_OUTBOUND_PCI_SUPPORTED	0x40
 #define QIB_RFLAGS_ENABLE_QEBSM		0x80
+#define QIB_RFLAGS_ENABLE_DATA_DIV	0x02
 
 /**
  * struct qib - queue information block (QIB)
@@ -284,6 +285,9 @@
 	u8 val[QDIO_MAX_BUFFERS_PER_Q];
 } __attribute__ ((packed, aligned(256)));
 
+#define CHSC_AC2_DATA_DIV_AVAILABLE	0x0010
+#define CHSC_AC2_DATA_DIV_ENABLED	0x0002
+
 struct qdio_ssqd_desc {
 	u8 flags;
 	u8:8;
@@ -332,6 +336,7 @@
  * @adapter_name: name for the adapter
  * @qib_param_field_format: format for qib_parm_field
  * @qib_param_field: pointer to 128 bytes or NULL, if no param field
+ * @qib_rflags: rflags to set
  * @input_slib_elements: pointer to no_input_qs * 128 words of data or NULL
  * @output_slib_elements: pointer to no_output_qs * 128 words of data or NULL
  * @no_input_qs: number of input queues
@@ -348,6 +353,7 @@
 	unsigned char adapter_name[8];
 	unsigned int qib_param_field_format;
 	unsigned char *qib_param_field;
+	unsigned char qib_rflags;
 	unsigned long *input_slib_elements;
 	unsigned long *output_slib_elements;
 	unsigned int no_input_qs;
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 3ddc308..f7b6df4 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -135,7 +135,7 @@
 	spin_lock_bh(&vcpu->arch.local_int.lock);
 	if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) {
 		vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP;
-		rc = __kvm_s390_vcpu_store_status(vcpu,
+		rc = kvm_s390_vcpu_store_status(vcpu,
 						  KVM_S390_STORE_STATUS_NOADDR);
 		if (rc >= 0)
 			rc = -EOPNOTSUPP;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index ae37058..4fe6865 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -207,6 +207,7 @@
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 {
 	VCPU_EVENT(vcpu, 3, "%s", "free cpu");
+	clear_bit(63 - vcpu->vcpu_id, (unsigned long *) &vcpu->kvm->arch.sca->mcn);
 	if (vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda ==
 		(__u64) vcpu->arch.sie_block)
 		vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda = 0;
@@ -296,7 +297,7 @@
 {
 	atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH);
 	set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests);
-	vcpu->arch.sie_block->ecb   = 2;
+	vcpu->arch.sie_block->ecb   = 6;
 	vcpu->arch.sie_block->eca   = 0xC1002001U;
 	vcpu->arch.sie_block->fac   = (int) (long) facilities;
 	hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
@@ -329,6 +330,7 @@
 		kvm->arch.sca->cpu[id].sda = (__u64) vcpu->arch.sie_block;
 	vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32);
 	vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
+	set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
 
 	spin_lock_init(&vcpu->arch.local_int.lock);
 	INIT_LIST_HEAD(&vcpu->arch.local_int.list);
@@ -363,63 +365,49 @@
 
 static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
 {
-	vcpu_load(vcpu);
 	kvm_s390_vcpu_initial_reset(vcpu);
-	vcpu_put(vcpu);
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
-	vcpu_load(vcpu);
 	memcpy(&vcpu->arch.guest_gprs, &regs->gprs, sizeof(regs->gprs));
-	vcpu_put(vcpu);
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
-	vcpu_load(vcpu);
 	memcpy(&regs->gprs, &vcpu->arch.guest_gprs, sizeof(regs->gprs));
-	vcpu_put(vcpu);
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 				  struct kvm_sregs *sregs)
 {
-	vcpu_load(vcpu);
 	memcpy(&vcpu->arch.guest_acrs, &sregs->acrs, sizeof(sregs->acrs));
 	memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs));
-	vcpu_put(vcpu);
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
 				  struct kvm_sregs *sregs)
 {
-	vcpu_load(vcpu);
 	memcpy(&sregs->acrs, &vcpu->arch.guest_acrs, sizeof(sregs->acrs));
 	memcpy(&sregs->crs, &vcpu->arch.sie_block->gcr, sizeof(sregs->crs));
-	vcpu_put(vcpu);
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
-	vcpu_load(vcpu);
 	memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs));
 	vcpu->arch.guest_fpregs.fpc = fpu->fpc;
-	vcpu_put(vcpu);
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
-	vcpu_load(vcpu);
 	memcpy(&fpu->fprs, &vcpu->arch.guest_fpregs.fprs, sizeof(fpu->fprs));
 	fpu->fpc = vcpu->arch.guest_fpregs.fpc;
-	vcpu_put(vcpu);
 	return 0;
 }
 
@@ -427,14 +415,12 @@
 {
 	int rc = 0;
 
-	vcpu_load(vcpu);
 	if (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_RUNNING)
 		rc = -EBUSY;
 	else {
 		vcpu->run->psw_mask = psw.mask;
 		vcpu->run->psw_addr = psw.addr;
 	}
-	vcpu_put(vcpu);
 	return rc;
 }
 
@@ -498,8 +484,6 @@
 	int rc;
 	sigset_t sigsaved;
 
-	vcpu_load(vcpu);
-
 rerun_vcpu:
 	if (vcpu->requests)
 		if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
@@ -568,8 +552,6 @@
 	if (vcpu->sigset_active)
 		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
 
-	vcpu_put(vcpu);
-
 	vcpu->stat.exit_userspace++;
 	return rc;
 }
@@ -589,7 +571,7 @@
  * KVM_S390_STORE_STATUS_NOADDR: -> 0x1200 on 64 bit
  * KVM_S390_STORE_STATUS_PREFIXED: -> prefix
  */
-int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
+int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
 {
 	const unsigned char archmode = 1;
 	int prefix;
@@ -651,45 +633,42 @@
 	return 0;
 }
 
-static int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
-{
-	int rc;
-
-	vcpu_load(vcpu);
-	rc = __kvm_s390_vcpu_store_status(vcpu, addr);
-	vcpu_put(vcpu);
-	return rc;
-}
-
 long kvm_arch_vcpu_ioctl(struct file *filp,
 			 unsigned int ioctl, unsigned long arg)
 {
 	struct kvm_vcpu *vcpu = filp->private_data;
 	void __user *argp = (void __user *)arg;
+	long r;
 
 	switch (ioctl) {
 	case KVM_S390_INTERRUPT: {
 		struct kvm_s390_interrupt s390int;
 
+		r = -EFAULT;
 		if (copy_from_user(&s390int, argp, sizeof(s390int)))
-			return -EFAULT;
-		return kvm_s390_inject_vcpu(vcpu, &s390int);
+			break;
+		r = kvm_s390_inject_vcpu(vcpu, &s390int);
+		break;
 	}
 	case KVM_S390_STORE_STATUS:
-		return kvm_s390_vcpu_store_status(vcpu, arg);
+		r = kvm_s390_vcpu_store_status(vcpu, arg);
+		break;
 	case KVM_S390_SET_INITIAL_PSW: {
 		psw_t psw;
 
+		r = -EFAULT;
 		if (copy_from_user(&psw, argp, sizeof(psw)))
-			return -EFAULT;
-		return kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw);
+			break;
+		r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw);
+		break;
 	}
 	case KVM_S390_INITIAL_RESET:
-		return kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+		r = kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+		break;
 	default:
-		;
+		r = -EINVAL;
 	}
-	return -EINVAL;
+	return r;
 }
 
 /* Section: memory related */
@@ -744,11 +723,6 @@
 {
 }
 
-gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
-{
-	return gfn;
-}
-
 static int __init kvm_s390_init(void)
 {
 	int ret;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index cfa9d17..a7b7586 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -92,7 +92,7 @@
 int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
 
 /* implemented in kvm-s390.c */
-int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu,
+int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu,
 				 unsigned long addr);
 /* implemented in diag.c */
 int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index 3a170bd..de375b6 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -316,7 +316,7 @@
 	.format_name = "UYVY",
 	.format_depth = 16,
 	.format = {
-		.code = V4L2_MBUS_FMT_YUYV8_2X8_BE,
+		.code = V4L2_MBUS_FMT_UYVY8_2X8,
 		.colorspace = V4L2_COLORSPACE_SMPTE170M,
 		.field = V4L2_FIELD_NONE,
 		.width = 640,
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index f053726..2ab233b 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -25,11 +25,6 @@
 #include "net_kern.h"
 #include "net_user.h"
 
-static inline void set_ether_mac(struct net_device *dev, unsigned char *addr)
-{
-	memcpy(dev->dev_addr, addr, ETH_ALEN);
-}
-
 #define DRIVER_NAME "uml-netdev"
 
 static DEFINE_SPINLOCK(opened_lock);
@@ -266,7 +261,7 @@
 	struct sockaddr *hwaddr = addr;
 
 	spin_lock_irq(&lp->lock);
-	set_ether_mac(dev, hwaddr->sa_data);
+	eth_mac_addr(dev, hwaddr->sa_data);
 	spin_unlock_irq(&lp->lock);
 
 	return 0;
@@ -380,7 +375,6 @@
 	.ndo_tx_timeout 	= uml_net_tx_timeout,
 	.ndo_set_mac_address	= uml_net_set_mac,
 	.ndo_change_mtu 	= uml_net_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
 	.ndo_validate_addr	= eth_validate_addr,
 };
 
@@ -478,7 +472,7 @@
 	    ((*transport->user->init)(&lp->user, dev) != 0))
 		goto out_unregister;
 
-	set_ether_mac(dev, device->mac);
+	eth_mac_addr(dev, device->mac);
 	dev->mtu = transport->user->mtu;
 	dev->netdev_ops = &uml_netdev_ops;
 	dev->ethtool_ops = &uml_net_ethtool_ops;
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h
index c991b3a..815c5b2 100644
--- a/arch/x86/include/asm/i387.h
+++ b/arch/x86/include/asm/i387.h
@@ -482,6 +482,8 @@
 	memcpy(dst->state, src->state, xstate_size);
 }
 
+extern void fpu_finit(struct fpu *fpu);
+
 #endif /* __ASSEMBLY__ */
 
 #define PSHUFB_XMM5_XMM0 .byte 0x66, 0x0f, 0x38, 0x00, 0xc5
diff --git a/arch/x86/include/asm/intel_scu_ipc.h b/arch/x86/include/asm/intel_scu_ipc.h
index 4470c9a..29f6679 100644
--- a/arch/x86/include/asm/intel_scu_ipc.h
+++ b/arch/x86/include/asm/intel_scu_ipc.h
@@ -1,6 +1,12 @@
 #ifndef _ASM_X86_INTEL_SCU_IPC_H_
 #define  _ASM_X86_INTEL_SCU_IPC_H_
 
+#define IPCMSG_VRTC	0xFA	 /* Set vRTC device */
+
+/* Command id associated with message IPCMSG_VRTC */
+#define IPC_CMD_VRTC_SETTIME      1 /* Set time */
+#define IPC_CMD_VRTC_SETALARM     2 /* Set alarm */
+
 /* Read single register */
 int intel_scu_ipc_ioread8(u16 addr, u8 *data);
 
@@ -28,20 +34,6 @@
 /* Update single register based on the mask */
 int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask);
 
-/*
- * Indirect register read
- * Can be used when SCCB(System Controller Configuration Block) register
- * HRIM(Honor Restricted IPC Messages) is set (bit 23)
- */
-int intel_scu_ipc_register_read(u32 addr, u32 *data);
-
-/*
- * Indirect register write
- * Can be used when SCCB(System Controller Configuration Block) register
- * HRIM(Honor Restricted IPC Messages) is set (bit 23)
- */
-int intel_scu_ipc_register_write(u32 addr, u32 data);
-
 /* Issue commands to the SCU with or without data */
 int intel_scu_ipc_simple_command(int cmd, int sub);
 int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index ff90055..4d8dcbd 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -22,6 +22,8 @@
 #define __KVM_HAVE_XEN_HVM
 #define __KVM_HAVE_VCPU_EVENTS
 #define __KVM_HAVE_DEBUGREGS
+#define __KVM_HAVE_XSAVE
+#define __KVM_HAVE_XCRS
 
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
@@ -299,4 +301,24 @@
 	__u64 reserved[9];
 };
 
+/* for KVM_CAP_XSAVE */
+struct kvm_xsave {
+	__u32 region[1024];
+};
+
+#define KVM_MAX_XCRS	16
+
+struct kvm_xcr {
+	__u32 xcr;
+	__u32 reserved;
+	__u64 value;
+};
+
+struct kvm_xcrs {
+	__u32 nr_xcrs;
+	__u32 flags;
+	struct kvm_xcr xcrs[KVM_MAX_XCRS];
+	__u64 padding[16];
+};
+
 #endif /* _ASM_X86_KVM_H */
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 0b2729b..51cfd73 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -51,8 +51,10 @@
 #define X86EMUL_UNHANDLEABLE    1
 /* Terminate emulation but return success to the caller. */
 #define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */
-#define X86EMUL_RETRY_INSTR     2 /* retry the instruction for some reason */
-#define X86EMUL_CMPXCHG_FAILED  2 /* cmpxchg did not see expected value */
+#define X86EMUL_RETRY_INSTR     3 /* retry the instruction for some reason */
+#define X86EMUL_CMPXCHG_FAILED  4 /* cmpxchg did not see expected value */
+#define X86EMUL_IO_NEEDED       5 /* IO is needed to complete emulation */
+
 struct x86_emulate_ops {
 	/*
 	 * read_std: Read bytes of standard (non-emulated/special) memory.
@@ -92,6 +94,7 @@
 	int (*read_emulated)(unsigned long addr,
 			     void *val,
 			     unsigned int bytes,
+			     unsigned int *error,
 			     struct kvm_vcpu *vcpu);
 
 	/*
@@ -104,6 +107,7 @@
 	int (*write_emulated)(unsigned long addr,
 			      const void *val,
 			      unsigned int bytes,
+			      unsigned int *error,
 			      struct kvm_vcpu *vcpu);
 
 	/*
@@ -118,6 +122,7 @@
 				const void *old,
 				const void *new,
 				unsigned int bytes,
+				unsigned int *error,
 				struct kvm_vcpu *vcpu);
 
 	int (*pio_in_emulated)(int size, unsigned short port, void *val,
@@ -132,18 +137,26 @@
 				      int seg, struct kvm_vcpu *vcpu);
 	u16 (*get_segment_selector)(int seg, struct kvm_vcpu *vcpu);
 	void (*set_segment_selector)(u16 sel, int seg, struct kvm_vcpu *vcpu);
+	unsigned long (*get_cached_segment_base)(int seg, struct kvm_vcpu *vcpu);
 	void (*get_gdt)(struct desc_ptr *dt, struct kvm_vcpu *vcpu);
 	ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu);
-	void (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
+	int (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
 	int (*cpl)(struct kvm_vcpu *vcpu);
-	void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
+	int (*get_dr)(int dr, unsigned long *dest, struct kvm_vcpu *vcpu);
+	int (*set_dr)(int dr, unsigned long value, struct kvm_vcpu *vcpu);
+	int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
+	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
 };
 
 /* Type, address-of, and value of an instruction's operand. */
 struct operand {
 	enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type;
 	unsigned int bytes;
-	unsigned long val, orig_val, *ptr;
+	unsigned long orig_val, *ptr;
+	union {
+		unsigned long val;
+		char valptr[sizeof(unsigned long) + 2];
+	};
 };
 
 struct fetch_cache {
@@ -186,6 +199,7 @@
 	unsigned long modrm_val;
 	struct fetch_cache fetch;
 	struct read_cache io_read;
+	struct read_cache mem_read;
 };
 
 struct x86_emulate_ctxt {
@@ -202,6 +216,12 @@
 	int interruptibility;
 
 	bool restart; /* restart string instruction after writeback */
+
+	int exception; /* exception that happens during emulation or -1 */
+	u32 error_code; /* error code for exception */
+	bool error_code_valid;
+	unsigned long cr2; /* faulted address in case of #PF */
+
 	/* decode cache */
 	struct decode_cache decode;
 };
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 76f5483..502e53f 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -15,6 +15,7 @@
 #include <linux/mm.h>
 #include <linux/mmu_notifier.h>
 #include <linux/tracepoint.h>
+#include <linux/cpumask.h>
 
 #include <linux/kvm.h>
 #include <linux/kvm_para.h>
@@ -39,11 +40,14 @@
 				  0xFFFFFF0000000000ULL)
 
 #define INVALID_PAGE (~(hpa_t)0)
+#define VALID_PAGE(x) ((x) != INVALID_PAGE)
+
 #define UNMAPPED_GVA (~(gpa_t)0)
 
 /* KVM Hugepage definitions for x86 */
 #define KVM_NR_PAGE_SIZES	3
-#define KVM_HPAGE_SHIFT(x)	(PAGE_SHIFT + (((x) - 1) * 9))
+#define KVM_HPAGE_GFN_SHIFT(x)	(((x) - 1) * 9)
+#define KVM_HPAGE_SHIFT(x)	(PAGE_SHIFT + KVM_HPAGE_GFN_SHIFT(x))
 #define KVM_HPAGE_SIZE(x)	(1UL << KVM_HPAGE_SHIFT(x))
 #define KVM_HPAGE_MASK(x)	(~(KVM_HPAGE_SIZE(x) - 1))
 #define KVM_PAGES_PER_HPAGE(x)	(KVM_HPAGE_SIZE(x) / PAGE_SIZE)
@@ -69,8 +73,6 @@
 
 #define IOPL_SHIFT 12
 
-#define KVM_ALIAS_SLOTS 4
-
 #define KVM_PERMILLE_MMU_PAGES 20
 #define KVM_MIN_ALLOC_MMU_PAGES 64
 #define KVM_MMU_HASH_SHIFT 10
@@ -241,7 +243,7 @@
 	void (*prefetch_page)(struct kvm_vcpu *vcpu,
 			      struct kvm_mmu_page *page);
 	int (*sync_page)(struct kvm_vcpu *vcpu,
-			 struct kvm_mmu_page *sp);
+			 struct kvm_mmu_page *sp, bool clear_unsync);
 	void (*invlpg)(struct kvm_vcpu *vcpu, gva_t gva);
 	hpa_t root_hpa;
 	int root_level;
@@ -301,8 +303,8 @@
 		unsigned long mmu_seq;
 	} update_pte;
 
-	struct i387_fxsave_struct host_fx_image;
-	struct i387_fxsave_struct guest_fx_image;
+	struct fpu guest_fpu;
+	u64 xcr0;
 
 	gva_t mmio_fault_cr2;
 	struct kvm_pio_request pio;
@@ -360,26 +362,11 @@
 
 	/* fields used by HYPER-V emulation */
 	u64 hv_vapic;
-};
 
-struct kvm_mem_alias {
-	gfn_t base_gfn;
-	unsigned long npages;
-	gfn_t target_gfn;
-#define KVM_ALIAS_INVALID     1UL
-	unsigned long flags;
-};
-
-#define KVM_ARCH_HAS_UNALIAS_INSTANTIATION
-
-struct kvm_mem_aliases {
-	struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS];
-	int naliases;
+	cpumask_var_t wbinvd_dirty_mask;
 };
 
 struct kvm_arch {
-	struct kvm_mem_aliases *aliases;
-
 	unsigned int n_free_mmu_pages;
 	unsigned int n_requested_mmu_pages;
 	unsigned int n_alloc_mmu_pages;
@@ -533,6 +520,8 @@
 
 	void (*set_supported_cpuid)(u32 func, struct kvm_cpuid_entry2 *entry);
 
+	bool (*has_wbinvd_exit)(void);
+
 	const struct trace_print_flags *exit_reasons_str;
 };
 
@@ -576,7 +565,6 @@
 #define EMULTYPE_SKIP		    (1 << 2)
 int emulate_instruction(struct kvm_vcpu *vcpu,
 			unsigned long cr2, u16 error_code, int emulation_type);
-void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
 void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
 void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
 
@@ -591,10 +579,7 @@
 int kvm_emulate_halt(struct kvm_vcpu *vcpu);
 int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
 int emulate_clts(struct kvm_vcpu *vcpu);
-int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr,
-		    unsigned long *dest);
-int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr,
-		    unsigned long value);
+int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu);
 
 void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
 int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg);
@@ -602,15 +587,16 @@
 int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
 		    bool has_error_code, u32 error_code);
 
-void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
-void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
-void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
+int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
+int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
+int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
 void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8);
 int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val);
 int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val);
 unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu);
 void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
 void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l);
+int kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr);
 
 int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
 int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data);
@@ -630,12 +616,7 @@
 
 void kvm_inject_nmi(struct kvm_vcpu *vcpu);
 
-void fx_init(struct kvm_vcpu *vcpu);
-
-int emulator_write_emulated(unsigned long addr,
-			    const void *val,
-			    unsigned int bytes,
-			    struct kvm_vcpu *vcpu);
+int fx_init(struct kvm_vcpu *vcpu);
 
 void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu);
 void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
@@ -664,8 +645,6 @@
 int complete_pio(struct kvm_vcpu *vcpu);
 bool kvm_check_iopl(struct kvm_vcpu *vcpu);
 
-struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn);
-
 static inline struct kvm_mmu_page *page_header(hpa_t shadow_page)
 {
 	struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT);
@@ -719,21 +698,6 @@
 }
 #endif
 
-static inline void kvm_fx_save(struct i387_fxsave_struct *image)
-{
-	asm("fxsave (%0)":: "r" (image));
-}
-
-static inline void kvm_fx_restore(struct i387_fxsave_struct *image)
-{
-	asm("fxrstor (%0)":: "r" (image));
-}
-
-static inline void kvm_fx_finit(void)
-{
-	asm("finit");
-}
-
 static inline u32 get_rdx_init_val(void)
 {
 	return 0x600; /* P6 family */
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 8c7ae43..509a421 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -20,6 +20,7 @@
 #define _EFER_LMA		10 /* Long mode active (read-only) */
 #define _EFER_NX		11 /* No execute enable */
 #define _EFER_SVME		12 /* Enable virtualization */
+#define _EFER_LMSLE		13 /* Long Mode Segment Limit Enable */
 #define _EFER_FFXSR		14 /* Enable Fast FXSAVE/FXRSTOR */
 
 #define EFER_SCE		(1<<_EFER_SCE)
@@ -27,6 +28,7 @@
 #define EFER_LMA		(1<<_EFER_LMA)
 #define EFER_NX			(1<<_EFER_NX)
 #define EFER_SVME		(1<<_EFER_SVME)
+#define EFER_LMSLE		(1<<_EFER_LMSLE)
 #define EFER_FFXSR		(1<<_EFER_FFXSR)
 
 /* Intel MSRs. Some also available on other CPUs */
diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h
index e7f4d33..33ecc3e 100644
--- a/arch/x86/include/asm/system.h
+++ b/arch/x86/include/asm/system.h
@@ -457,4 +457,11 @@
 	alternative(ASM_NOP3, "lfence", X86_FEATURE_LFENCE_RDTSC);
 }
 
+/*
+ * We handle most unaligned accesses in hardware.  On the other hand
+ * unaligned DMA can be quite expensive on some Nehalem processors.
+ *
+ * Based on this we disable the IP header alignment in network drivers.
+ */
+#define NET_IP_ALIGN	0
 #endif /* _ASM_X86_SYSTEM_H */
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 9e6779f..9f0cbd9 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -257,6 +257,7 @@
 #define EXIT_REASON_IO_INSTRUCTION      30
 #define EXIT_REASON_MSR_READ            31
 #define EXIT_REASON_MSR_WRITE           32
+#define EXIT_REASON_INVALID_STATE	33
 #define EXIT_REASON_MWAIT_INSTRUCTION   36
 #define EXIT_REASON_MONITOR_INSTRUCTION 39
 #define EXIT_REASON_PAUSE_INSTRUCTION   40
@@ -266,6 +267,7 @@
 #define EXIT_REASON_EPT_VIOLATION       48
 #define EXIT_REASON_EPT_MISCONFIG       49
 #define EXIT_REASON_WBINVD		54
+#define EXIT_REASON_XSETBV		55
 
 /*
  * Interruption-information format
@@ -375,6 +377,9 @@
 #define VMX_EPT_EXTENT_CONTEXT_BIT		(1ull << 25)
 #define VMX_EPT_EXTENT_GLOBAL_BIT		(1ull << 26)
 
+#define VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT      (1ull << 9) /* (41 - 32) */
+#define VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT      (1ull << 10) /* (42 - 32) */
+
 #define VMX_EPT_DEFAULT_GAW			3
 #define VMX_EPT_MAX_GAW				0x4
 #define VMX_EPT_MT_EPTE_SHIFT			3
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
index 2c4390c..32c3666 100644
--- a/arch/x86/include/asm/xsave.h
+++ b/arch/x86/include/asm/xsave.h
@@ -13,6 +13,12 @@
 
 #define FXSAVE_SIZE	512
 
+#define XSAVE_HDR_SIZE	    64
+#define XSAVE_HDR_OFFSET    FXSAVE_SIZE
+
+#define XSAVE_YMM_SIZE	    256
+#define XSAVE_YMM_OFFSET    (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET)
+
 /*
  * These are the features that the OS can handle currently.
  */
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index 1d3cdda..246cd3a 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -34,7 +34,6 @@
 #include <linux/compiler.h>
 #include <linux/dmi.h>
 #include <linux/slab.h>
-#include <trace/events/power.h>
 
 #include <linux/acpi.h>
 #include <linux/io.h>
@@ -324,8 +323,6 @@
 		}
 	}
 
-	trace_power_frequency(POWER_PSTATE, data->freq_table[next_state].frequency);
-
 	switch (data->cpu_feature) {
 	case SYSTEM_INTEL_MSR_CAPABLE:
 		cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
@@ -351,7 +348,7 @@
 
 	freqs.old = perf->states[perf->state].core_frequency * 1000;
 	freqs.new = data->freq_table[next_state].frequency;
-	for_each_cpu(i, cmd.mask) {
+	for_each_cpu(i, policy->cpus) {
 		freqs.cpu = i;
 		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 	}
@@ -367,7 +364,7 @@
 		}
 	}
 
-	for_each_cpu(i, cmd.mask) {
+	for_each_cpu(i, policy->cpus) {
 		freqs.cpu = i;
 		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 	}
diff --git a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
index 16e3483..32974cf 100644
--- a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
+++ b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
@@ -169,12 +169,9 @@
  *	Low Level chipset interface				*
  ****************************************************************/
 static struct pci_device_id gx_chipset_tbl[] __initdata = {
-	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY,
-		PCI_ANY_ID, PCI_ANY_ID },
-	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520,
-		PCI_ANY_ID, PCI_ANY_ID },
-	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510,
-		PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY), },
+	{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
+	{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
 	{ 0, },
 };
 
@@ -199,7 +196,7 @@
 	}
 
 	/* detect which companion chip is used */
-	while ((gx_pci = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, gx_pci)) != NULL) {
+	for_each_pci_dev(gx_pci) {
 		if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL)
 			return gx_pci;
 	}
diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.c b/arch/x86/kernel/cpu/cpufreq/longhaul.c
index 7e7eea4..03162da 100644
--- a/arch/x86/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/x86/kernel/cpu/cpufreq/longhaul.c
@@ -426,7 +426,7 @@
 }
 
 
-static int __init longhaul_get_ranges(void)
+static int __cpuinit longhaul_get_ranges(void)
 {
 	unsigned int i, j, k = 0;
 	unsigned int ratio;
@@ -530,7 +530,7 @@
 }
 
 
-static void __init longhaul_setup_voltagescaling(void)
+static void __cpuinit longhaul_setup_voltagescaling(void)
 {
 	union msr_longhaul longhaul;
 	struct mV_pos minvid, maxvid, vid;
@@ -784,7 +784,7 @@
 	return 0;
 }
 
-static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
+static int __cpuinit longhaul_cpu_init(struct cpufreq_policy *policy)
 {
 	struct cpuinfo_x86 *c = &cpu_data(0);
 	char *cpuname = NULL;
diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.h b/arch/x86/kernel/cpu/cpufreq/longhaul.h
index e2360a4..cbf48fb 100644
--- a/arch/x86/kernel/cpu/cpufreq/longhaul.h
+++ b/arch/x86/kernel/cpu/cpufreq/longhaul.h
@@ -56,7 +56,7 @@
 /*
  * VIA C3 Samuel 1  & Samuel 2 (stepping 0)
  */
-static const int __initdata samuel1_mults[16] = {
+static const int __cpuinitdata samuel1_mults[16] = {
 	-1, /* 0000 -> RESERVED */
 	30, /* 0001 ->  3.0x */
 	40, /* 0010 ->  4.0x */
@@ -75,7 +75,7 @@
 	-1, /* 1111 -> RESERVED */
 };
 
-static const int __initdata samuel1_eblcr[16] = {
+static const int __cpuinitdata samuel1_eblcr[16] = {
 	50, /* 0000 -> RESERVED */
 	30, /* 0001 ->  3.0x */
 	40, /* 0010 ->  4.0x */
@@ -97,7 +97,7 @@
 /*
  * VIA C3 Samuel2 Stepping 1->15
  */
-static const int __initdata samuel2_eblcr[16] = {
+static const int __cpuinitdata samuel2_eblcr[16] = {
 	50,  /* 0000 ->  5.0x */
 	30,  /* 0001 ->  3.0x */
 	40,  /* 0010 ->  4.0x */
@@ -119,7 +119,7 @@
 /*
  * VIA C3 Ezra
  */
-static const int __initdata ezra_mults[16] = {
+static const int __cpuinitdata ezra_mults[16] = {
 	100, /* 0000 -> 10.0x */
 	30,  /* 0001 ->  3.0x */
 	40,  /* 0010 ->  4.0x */
@@ -138,7 +138,7 @@
 	120, /* 1111 -> 12.0x */
 };
 
-static const int __initdata ezra_eblcr[16] = {
+static const int __cpuinitdata ezra_eblcr[16] = {
 	50,  /* 0000 ->  5.0x */
 	30,  /* 0001 ->  3.0x */
 	40,  /* 0010 ->  4.0x */
@@ -160,7 +160,7 @@
 /*
  * VIA C3 (Ezra-T) [C5M].
  */
-static const int __initdata ezrat_mults[32] = {
+static const int __cpuinitdata ezrat_mults[32] = {
 	100, /* 0000 -> 10.0x */
 	30,  /* 0001 ->  3.0x */
 	40,  /* 0010 ->  4.0x */
@@ -196,7 +196,7 @@
 	-1,  /* 1111 -> RESERVED (12.0x) */
 };
 
-static const int __initdata ezrat_eblcr[32] = {
+static const int __cpuinitdata ezrat_eblcr[32] = {
 	50,  /* 0000 ->  5.0x */
 	30,  /* 0001 ->  3.0x */
 	40,  /* 0010 ->  4.0x */
@@ -235,7 +235,7 @@
 /*
  * VIA C3 Nehemiah */
 
-static const int __initdata  nehemiah_mults[32] = {
+static const int __cpuinitdata nehemiah_mults[32] = {
 	100, /* 0000 -> 10.0x */
 	-1, /* 0001 -> 16.0x */
 	40,  /* 0010 ->  4.0x */
@@ -270,7 +270,7 @@
 	-1, /* 1111 -> 12.0x */
 };
 
-static const int __initdata nehemiah_eblcr[32] = {
+static const int __cpuinitdata nehemiah_eblcr[32] = {
 	50,  /* 0000 ->  5.0x */
 	160, /* 0001 -> 16.0x */
 	40,  /* 0010 ->  4.0x */
@@ -315,7 +315,7 @@
 	unsigned short pos;
 };
 
-static const struct mV_pos __initdata vrm85_mV[32] = {
+static const struct mV_pos __cpuinitdata vrm85_mV[32] = {
 	{1250, 8},	{1200, 6},	{1150, 4},	{1100, 2},
 	{1050, 0},	{1800, 30},	{1750, 28},	{1700, 26},
 	{1650, 24},	{1600, 22},	{1550, 20},	{1500, 18},
@@ -326,14 +326,14 @@
 	{1475, 17},	{1425, 15},	{1375, 13},	{1325, 11}
 };
 
-static const unsigned char __initdata mV_vrm85[32] = {
+static const unsigned char __cpuinitdata mV_vrm85[32] = {
 	0x04,	0x14,	0x03,	0x13,	0x02,	0x12,	0x01,	0x11,
 	0x00,	0x10,	0x0f,	0x1f,	0x0e,	0x1e,	0x0d,	0x1d,
 	0x0c,	0x1c,	0x0b,	0x1b,	0x0a,	0x1a,	0x09,	0x19,
 	0x08,	0x18,	0x07,	0x17,	0x06,	0x16,	0x05,	0x15
 };
 
-static const struct mV_pos __initdata mobilevrm_mV[32] = {
+static const struct mV_pos __cpuinitdata mobilevrm_mV[32] = {
 	{1750, 31},	{1700, 30},	{1650, 29},	{1600, 28},
 	{1550, 27},	{1500, 26},	{1450, 25},	{1400, 24},
 	{1350, 23},	{1300, 22},	{1250, 21},	{1200, 20},
@@ -344,7 +344,7 @@
 	{675, 3},	{650, 2},	{625, 1},	{600, 0}
 };
 
-static const unsigned char __initdata mV_mobilevrm[32] = {
+static const unsigned char __cpuinitdata mV_mobilevrm[32] = {
 	0x1f,	0x1e,	0x1d,	0x1c,	0x1b,	0x1a,	0x19,	0x18,
 	0x17,	0x16,	0x15,	0x14,	0x13,	0x12,	0x11,	0x10,
 	0x0f,	0x0e,	0x0d,	0x0c,	0x0b,	0x0a,	0x09,	0x08,
diff --git a/arch/x86/kernel/cpu/cpufreq/longrun.c b/arch/x86/kernel/cpu/cpufreq/longrun.c
index e7b559d..fc09f14 100644
--- a/arch/x86/kernel/cpu/cpufreq/longrun.c
+++ b/arch/x86/kernel/cpu/cpufreq/longrun.c
@@ -165,8 +165,8 @@
  * TMTA rules:
  * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq)
  */
-static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
-						   unsigned int *high_freq)
+static unsigned int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
+						      unsigned int *high_freq)
 {
 	u32 msr_lo, msr_hi;
 	u32 save_lo, save_hi;
@@ -258,7 +258,7 @@
 }
 
 
-static int __init longrun_cpu_init(struct cpufreq_policy *policy)
+static int __cpuinit longrun_cpu_init(struct cpufreq_policy *policy)
 {
 	int result = 0;
 
diff --git a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
index 7b8a8ba..bd1cac7 100644
--- a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
+++ b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
@@ -178,13 +178,8 @@
 		}
 	}
 
-	if (c->x86 != 0xF) {
-		if (!cpu_has(c, X86_FEATURE_EST))
-			printk(KERN_WARNING PFX "Unknown CPU. "
-				"Please send an e-mail to "
-				"<cpufreq@vger.kernel.org>\n");
+	if (c->x86 != 0xF)
 		return 0;
-	}
 
 	/* on P-4s, the TSC runs with constant frequency independent whether
 	 * throttling is active or not. */
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
index 9a97116..4a45fd6 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
@@ -569,7 +569,7 @@
  * We will then get the same kind of behaviour already tested under
  * the "well-known" other OS.
  */
-static int __init fixup_sgtc(void)
+static int __cpuinit fixup_sgtc(void)
 {
 	unsigned int sgtc;
 	unsigned int m;
@@ -603,7 +603,7 @@
 }
 
 
-static int __init acer_cpufreq_pst(const struct dmi_system_id *d)
+static int __cpuinit acer_cpufreq_pst(const struct dmi_system_id *d)
 {
 	printk(KERN_WARNING PFX
 		"%s laptop with broken PST tables in BIOS detected.\n",
@@ -621,7 +621,7 @@
  * A BIOS update is all that can save them.
  * Mention this, and disable cpufreq.
  */
-static struct dmi_system_id __initdata powernow_dmi_table[] = {
+static struct dmi_system_id __cpuinitdata powernow_dmi_table[] = {
 	{
 		.callback = acer_cpufreq_pst,
 		.ident = "Acer Aspire",
@@ -633,7 +633,7 @@
 	{ }
 };
 
-static int __init powernow_cpu_init(struct cpufreq_policy *policy)
+static int __cpuinit powernow_cpu_init(struct cpufreq_policy *policy)
 {
 	union msr_fidvidstatus fidvidstatus;
 	int result;
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
index 1376f41..491977b 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
@@ -806,6 +806,8 @@
 	 * www.amd.com
 	 */
 	printk(KERN_ERR FW_BUG PFX "No PSB or ACPI _PSS objects\n");
+	printk(KERN_ERR PFX "Make sure that your BIOS is up to date"
+		" and Cool'N'Quiet support is enabled in BIOS setup\n");
 	return -ENODEV;
 }
 
@@ -910,8 +912,8 @@
 {
 	int i;
 	u32 hi = 0, lo = 0;
-	rdmsr(MSR_PSTATE_CUR_LIMIT, hi, lo);
-	data->max_hw_pstate = (hi & HW_PSTATE_MAX_MASK) >> HW_PSTATE_MAX_SHIFT;
+	rdmsr(MSR_PSTATE_CUR_LIMIT, lo, hi);
+	data->max_hw_pstate = (lo & HW_PSTATE_MAX_MASK) >> HW_PSTATE_MAX_SHIFT;
 
 	for (i = 0; i < data->acpi_data.state_count; i++) {
 		u32 index;
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 18cc425..1970ef9 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -600,6 +600,7 @@
 		 */
 		if (!(flags & MCP_DONTLOG) && !mce_dont_log_ce) {
 			mce_log(&m);
+			atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, &m);
 			add_taint(TAINT_MACHINE_CHECK);
 		}
 
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 86cef6b..c4444bc 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -107,7 +107,7 @@
 }
 #endif	/* CONFIG_X86_64 */
 
-static void fpu_finit(struct fpu *fpu)
+void fpu_finit(struct fpu *fpu)
 {
 #ifdef CONFIG_X86_32
 	if (!HAVE_HWFP) {
@@ -132,6 +132,7 @@
 		fp->fos = 0xffff0000u;
 	}
 }
+EXPORT_SYMBOL_GPL(fpu_finit);
 
 /*
  * The _current_ task is using the FPU for the first time
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index e7e3521..cbcf013 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -28,6 +28,7 @@
 EXPORT_SYMBOL(idle_nomwait);
 
 struct kmem_cache *task_xstate_cachep;
+EXPORT_SYMBOL_GPL(task_xstate_cachep);
 
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
@@ -371,7 +372,7 @@
 void default_idle(void)
 {
 	if (hlt_use_halt()) {
-		trace_power_start(POWER_CSTATE, 1);
+		trace_power_start(POWER_CSTATE, 1, smp_processor_id());
 		current_thread_info()->status &= ~TS_POLLING;
 		/*
 		 * TS_POLLING-cleared state must be visible before we
@@ -441,7 +442,7 @@
  */
 void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
 {
-	trace_power_start(POWER_CSTATE, (ax>>4)+1);
+	trace_power_start(POWER_CSTATE, (ax>>4)+1, smp_processor_id());
 	if (!need_resched()) {
 		if (cpu_has(&current_cpu_data, X86_FEATURE_CLFLUSH_MONITOR))
 			clflush((void *)&current_thread_info()->flags);
@@ -457,7 +458,7 @@
 static void mwait_idle(void)
 {
 	if (!need_resched()) {
-		trace_power_start(POWER_CSTATE, 1);
+		trace_power_start(POWER_CSTATE, 1, smp_processor_id());
 		if (cpu_has(&current_cpu_data, X86_FEATURE_CLFLUSH_MONITOR))
 			clflush((void *)&current_thread_info()->flags);
 
@@ -478,7 +479,7 @@
  */
 static void poll_idle(void)
 {
-	trace_power_start(POWER_CSTATE, 0);
+	trace_power_start(POWER_CSTATE, 0, smp_processor_id());
 	local_irq_enable();
 	while (!need_resched())
 		cpu_relax();
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 5ac0bb4..b38bd8b 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -9,6 +9,7 @@
  * privileged instructions:
  *
  * Copyright (C) 2006 Qumranet
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
  *
  *   Avi Kivity <avi@qumranet.com>
  *   Yaniv Kamay <yaniv@qumranet.com>
@@ -67,6 +68,9 @@
 #define SrcImmUByte (8<<4)      /* 8-bit unsigned immediate operand. */
 #define SrcImmU     (9<<4)      /* Immediate operand, unsigned */
 #define SrcSI       (0xa<<4)	/* Source is in the DS:RSI */
+#define SrcImmFAddr (0xb<<4)	/* Source is immediate far address */
+#define SrcMemFAddr (0xc<<4)	/* Source is far address in memory */
+#define SrcAcc      (0xd<<4)	/* Source Accumulator */
 #define SrcMask     (0xf<<4)
 /* Generic ModRM decode. */
 #define ModRM       (1<<8)
@@ -88,10 +92,6 @@
 #define Src2CL      (1<<29)
 #define Src2ImmByte (2<<29)
 #define Src2One     (3<<29)
-#define Src2Imm16   (4<<29)
-#define Src2Mem16   (5<<29) /* Used for Ep encoding. First argument has to be
-			       in memory and second argument is located
-			       immediately after the first one in memory. */
 #define Src2Mask    (7<<29)
 
 enum {
@@ -124,15 +124,15 @@
 	/* 0x20 - 0x27 */
 	ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
 	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
+	ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
 	/* 0x28 - 0x2F */
 	ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
 	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	0, 0, 0, 0,
+	ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
 	/* 0x30 - 0x37 */
 	ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
 	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	0, 0, 0, 0,
+	ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
 	/* 0x38 - 0x3F */
 	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
 	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
@@ -170,20 +170,20 @@
 	/* 0x88 - 0x8F */
 	ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
 	ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstMem | SrcReg | ModRM | Mov, ModRM | DstReg,
-	DstReg | SrcMem | ModRM | Mov, Group | Group1A,
+	DstMem | SrcNone | ModRM | Mov, ModRM | DstReg,
+	ImplicitOps | SrcMem16 | ModRM, Group | Group1A,
 	/* 0x90 - 0x97 */
 	DstReg, DstReg, DstReg, DstReg,	DstReg, DstReg, DstReg, DstReg,
 	/* 0x98 - 0x9F */
-	0, 0, SrcImm | Src2Imm16 | No64, 0,
+	0, 0, SrcImmFAddr | No64, 0,
 	ImplicitOps | Stack, ImplicitOps | Stack, 0, 0,
 	/* 0xA0 - 0xA7 */
-	ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs,
-	ByteOp | DstMem | SrcReg | Mov | MemAbs, DstMem | SrcReg | Mov | MemAbs,
+	ByteOp | DstAcc | SrcMem | Mov | MemAbs, DstAcc | SrcMem | Mov | MemAbs,
+	ByteOp | DstMem | SrcAcc | Mov | MemAbs, DstMem | SrcAcc | Mov | MemAbs,
 	ByteOp | SrcSI | DstDI | Mov | String, SrcSI | DstDI | Mov | String,
 	ByteOp | SrcSI | DstDI | String, SrcSI | DstDI | String,
 	/* 0xA8 - 0xAF */
-	0, 0, ByteOp | DstDI | Mov | String, DstDI | Mov | String,
+	DstAcc | SrcImmByte | ByteOp, DstAcc | SrcImm, ByteOp | DstDI | Mov | String, DstDI | Mov | String,
 	ByteOp | SrcSI | DstAcc | Mov | String, SrcSI | DstAcc | Mov | String,
 	ByteOp | DstDI | String, DstDI | String,
 	/* 0xB0 - 0xB7 */
@@ -215,7 +215,7 @@
 	ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
 	/* 0xE8 - 0xEF */
 	SrcImm | Stack, SrcImm | ImplicitOps,
-	SrcImmU | Src2Imm16 | No64, SrcImmByte | ImplicitOps,
+	SrcImmFAddr | No64, SrcImmByte | ImplicitOps,
 	SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
 	SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
 	/* 0xF0 - 0xF7 */
@@ -337,20 +337,20 @@
 	[Group1A*8] =
 	DstMem | SrcNone | ModRM | Mov | Stack, 0, 0, 0, 0, 0, 0, 0,
 	[Group3_Byte*8] =
-	ByteOp | SrcImm | DstMem | ModRM, 0,
+	ByteOp | SrcImm | DstMem | ModRM, ByteOp | SrcImm | DstMem | ModRM,
 	ByteOp | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM,
 	0, 0, 0, 0,
 	[Group3*8] =
-	DstMem | SrcImm | ModRM, 0,
+	DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
 	DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
 	0, 0, 0, 0,
 	[Group4*8] =
-	ByteOp | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM,
+	ByteOp | DstMem | SrcNone | ModRM | Lock, ByteOp | DstMem | SrcNone | ModRM | Lock,
 	0, 0, 0, 0, 0, 0,
 	[Group5*8] =
-	DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
+	DstMem | SrcNone | ModRM | Lock, DstMem | SrcNone | ModRM | Lock,
 	SrcMem | ModRM | Stack, 0,
-	SrcMem | ModRM | Stack, SrcMem | ModRM | Src2Mem16 | ImplicitOps,
+	SrcMem | ModRM | Stack, SrcMemFAddr | ModRM | ImplicitOps,
 	SrcMem | ModRM | Stack, 0,
 	[Group7*8] =
 	0, 0, ModRM | SrcMem | Priv, ModRM | SrcMem | Priv,
@@ -576,6 +576,13 @@
 	(_type)_x;							\
 })
 
+#define insn_fetch_arr(_arr, _size, _eip)                                \
+({	rc = do_insn_fetch(ctxt, ops, (_eip), _arr, (_size));		\
+	if (rc != X86EMUL_CONTINUE)					\
+		goto done;						\
+	(_eip) += (_size);						\
+})
+
 static inline unsigned long ad_mask(struct decode_cache *c)
 {
 	return (1UL << (c->ad_bytes << 3)) - 1;
@@ -617,31 +624,66 @@
 	c->seg_override = seg;
 }
 
-static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg)
+static unsigned long seg_base(struct x86_emulate_ctxt *ctxt,
+			      struct x86_emulate_ops *ops, int seg)
 {
 	if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS)
 		return 0;
 
-	return kvm_x86_ops->get_segment_base(ctxt->vcpu, seg);
+	return ops->get_cached_segment_base(seg, ctxt->vcpu);
 }
 
 static unsigned long seg_override_base(struct x86_emulate_ctxt *ctxt,
+				       struct x86_emulate_ops *ops,
 				       struct decode_cache *c)
 {
 	if (!c->has_seg_override)
 		return 0;
 
-	return seg_base(ctxt, c->seg_override);
+	return seg_base(ctxt, ops, c->seg_override);
 }
 
-static unsigned long es_base(struct x86_emulate_ctxt *ctxt)
+static unsigned long es_base(struct x86_emulate_ctxt *ctxt,
+			     struct x86_emulate_ops *ops)
 {
-	return seg_base(ctxt, VCPU_SREG_ES);
+	return seg_base(ctxt, ops, VCPU_SREG_ES);
 }
 
-static unsigned long ss_base(struct x86_emulate_ctxt *ctxt)
+static unsigned long ss_base(struct x86_emulate_ctxt *ctxt,
+			     struct x86_emulate_ops *ops)
 {
-	return seg_base(ctxt, VCPU_SREG_SS);
+	return seg_base(ctxt, ops, VCPU_SREG_SS);
+}
+
+static void emulate_exception(struct x86_emulate_ctxt *ctxt, int vec,
+				      u32 error, bool valid)
+{
+	ctxt->exception = vec;
+	ctxt->error_code = error;
+	ctxt->error_code_valid = valid;
+	ctxt->restart = false;
+}
+
+static void emulate_gp(struct x86_emulate_ctxt *ctxt, int err)
+{
+	emulate_exception(ctxt, GP_VECTOR, err, true);
+}
+
+static void emulate_pf(struct x86_emulate_ctxt *ctxt, unsigned long addr,
+		       int err)
+{
+	ctxt->cr2 = addr;
+	emulate_exception(ctxt, PF_VECTOR, err, true);
+}
+
+static void emulate_ud(struct x86_emulate_ctxt *ctxt)
+{
+	emulate_exception(ctxt, UD_VECTOR, 0, false);
+}
+
+static void emulate_ts(struct x86_emulate_ctxt *ctxt, int err)
+{
+	emulate_exception(ctxt, TS_VECTOR, err, true);
 }
 
 static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt,
@@ -932,12 +974,9 @@
 	/* we cannot decode insn before we complete previous rep insn */
 	WARN_ON(ctxt->restart);
 
-	/* Shadow copy of register state. Committed on successful emulation. */
-	memset(c, 0, sizeof(struct decode_cache));
 	c->eip = ctxt->eip;
 	c->fetch.start = c->fetch.end = c->eip;
-	ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS);
-	memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
+	ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS);
 
 	switch (mode) {
 	case X86EMUL_MODE_REAL:
@@ -1060,7 +1099,7 @@
 		set_seg_override(c, VCPU_SREG_DS);
 
 	if (!(!c->twobyte && c->b == 0x8d))
-		c->modrm_ea += seg_override_base(ctxt, c);
+		c->modrm_ea += seg_override_base(ctxt, ops, c);
 
 	if (c->ad_bytes != 8)
 		c->modrm_ea = (u32)c->modrm_ea;
@@ -1148,6 +1187,25 @@
 		else
 			c->src.val = insn_fetch(u8, 1, c->eip);
 		break;
+	case SrcAcc:
+		c->src.type = OP_REG;
+		c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+		c->src.ptr = &c->regs[VCPU_REGS_RAX];
+		switch (c->src.bytes) {
+			case 1:
+				c->src.val = *(u8 *)c->src.ptr;
+				break;
+			case 2:
+				c->src.val = *(u16 *)c->src.ptr;
+				break;
+			case 4:
+				c->src.val = *(u32 *)c->src.ptr;
+				break;
+			case 8:
+				c->src.val = *(u64 *)c->src.ptr;
+				break;
+		}
+		break;
 	case SrcOne:
 		c->src.bytes = 1;
 		c->src.val = 1;
@@ -1156,10 +1214,21 @@
 		c->src.type = OP_MEM;
 		c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
 		c->src.ptr = (unsigned long *)
-			register_address(c,  seg_override_base(ctxt, c),
+			register_address(c,  seg_override_base(ctxt, ops, c),
 					 c->regs[VCPU_REGS_RSI]);
 		c->src.val = 0;
 		break;
+	case SrcImmFAddr:
+		c->src.type = OP_IMM;
+		c->src.ptr = (unsigned long *)c->eip;
+		c->src.bytes = c->op_bytes + 2;
+		insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip);
+		break;
+	case SrcMemFAddr:
+		c->src.type = OP_MEM;
+		c->src.ptr = (unsigned long *)c->modrm_ea;
+		c->src.bytes = c->op_bytes + 2;
+		break;
 	}
 
 	/*
@@ -1179,22 +1248,10 @@
 		c->src2.bytes = 1;
 		c->src2.val = insn_fetch(u8, 1, c->eip);
 		break;
-	case Src2Imm16:
-		c->src2.type = OP_IMM;
-		c->src2.ptr = (unsigned long *)c->eip;
-		c->src2.bytes = 2;
-		c->src2.val = insn_fetch(u16, 2, c->eip);
-		break;
 	case Src2One:
 		c->src2.bytes = 1;
 		c->src2.val = 1;
 		break;
-	case Src2Mem16:
-		c->src2.type = OP_MEM;
-		c->src2.bytes = 2;
-		c->src2.ptr = (unsigned long *)(c->modrm_ea + c->src.bytes);
-		c->src2.val = 0;
-		break;
 	}
 
 	/* Decode and fetch the destination operand: register or memory. */
@@ -1253,7 +1310,7 @@
 		c->dst.type = OP_MEM;
 		c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
 		c->dst.ptr = (unsigned long *)
-			register_address(c, es_base(ctxt),
+			register_address(c, es_base(ctxt, ops),
 					 c->regs[VCPU_REGS_RDI]);
 		c->dst.val = 0;
 		break;
@@ -1263,6 +1320,37 @@
 	return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
 }
 
+static int read_emulated(struct x86_emulate_ctxt *ctxt,
+			 struct x86_emulate_ops *ops,
+			 unsigned long addr, void *dest, unsigned size)
+{
+	int rc;
+	struct read_cache *mc = &ctxt->decode.mem_read;
+	u32 err;
+
+	while (size) {
+		int n = min(size, 8u);
+		size -= n;
+		if (mc->pos < mc->end)
+			goto read_cached;
+
+		rc = ops->read_emulated(addr, mc->data + mc->end, n, &err,
+					ctxt->vcpu);
+		if (rc == X86EMUL_PROPAGATE_FAULT)
+			emulate_pf(ctxt, addr, err);
+		if (rc != X86EMUL_CONTINUE)
+			return rc;
+		mc->end += n;
+
+	read_cached:
+		memcpy(dest, mc->data + mc->pos, n);
+		mc->pos += n;
+		dest += n;
+		addr += n;
+	}
+	return X86EMUL_CONTINUE;
+}
+
 static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
 			   struct x86_emulate_ops *ops,
 			   unsigned int size, unsigned short port,
@@ -1330,13 +1418,13 @@
 	get_descriptor_table_ptr(ctxt, ops, selector, &dt);
 
 	if (dt.size < index * 8 + 7) {
-		kvm_inject_gp(ctxt->vcpu, selector & 0xfffc);
+		emulate_gp(ctxt, selector & 0xfffc);
 		return X86EMUL_PROPAGATE_FAULT;
 	}
 	addr = dt.address + index * 8;
 	ret = ops->read_std(addr, desc, sizeof *desc, ctxt->vcpu,  &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT)
-		kvm_inject_page_fault(ctxt->vcpu, addr, err);
+		emulate_pf(ctxt, addr, err);
 
        return ret;
 }
@@ -1355,14 +1443,14 @@
 	get_descriptor_table_ptr(ctxt, ops, selector, &dt);
 
 	if (dt.size < index * 8 + 7) {
-		kvm_inject_gp(ctxt->vcpu, selector & 0xfffc);
+		emulate_gp(ctxt, selector & 0xfffc);
 		return X86EMUL_PROPAGATE_FAULT;
 	}
 
 	addr = dt.address + index * 8;
 	ret = ops->write_std(addr, desc, sizeof *desc, ctxt->vcpu, &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT)
-		kvm_inject_page_fault(ctxt->vcpu, addr, err);
+		emulate_pf(ctxt, addr, err);
 
 	return ret;
 }
@@ -1481,11 +1569,70 @@
 	ops->set_cached_descriptor(&seg_desc, seg, ctxt->vcpu);
 	return X86EMUL_CONTINUE;
 exception:
-	kvm_queue_exception_e(ctxt->vcpu, err_vec, err_code);
+	emulate_exception(ctxt, err_vec, err_code, true);
 	return X86EMUL_PROPAGATE_FAULT;
 }
 
-static inline void emulate_push(struct x86_emulate_ctxt *ctxt)
+static inline int writeback(struct x86_emulate_ctxt *ctxt,
+			    struct x86_emulate_ops *ops)
+{
+	int rc;
+	struct decode_cache *c = &ctxt->decode;
+	u32 err;
+
+	switch (c->dst.type) {
+	case OP_REG:
+		/* The 4-byte case *is* correct:
+		 * in 64-bit mode we zero-extend.
+		 */
+		switch (c->dst.bytes) {
+		case 1:
+			*(u8 *)c->dst.ptr = (u8)c->dst.val;
+			break;
+		case 2:
+			*(u16 *)c->dst.ptr = (u16)c->dst.val;
+			break;
+		case 4:
+			*c->dst.ptr = (u32)c->dst.val;
+			break;	/* 64b: zero-ext */
+		case 8:
+			*c->dst.ptr = c->dst.val;
+			break;
+		}
+		break;
+	case OP_MEM:
+		if (c->lock_prefix)
+			rc = ops->cmpxchg_emulated(
+					(unsigned long)c->dst.ptr,
+					&c->dst.orig_val,
+					&c->dst.val,
+					c->dst.bytes,
+					&err,
+					ctxt->vcpu);
+		else
+			rc = ops->write_emulated(
+					(unsigned long)c->dst.ptr,
+					&c->dst.val,
+					c->dst.bytes,
+					&err,
+					ctxt->vcpu);
+		if (rc == X86EMUL_PROPAGATE_FAULT)
+			emulate_pf(ctxt,
+					      (unsigned long)c->dst.ptr, err);
+		if (rc != X86EMUL_CONTINUE)
+			return rc;
+		break;
+	case OP_NONE:
+		/* no writeback */
+		break;
+	default:
+		break;
+	}
+	return X86EMUL_CONTINUE;
+}
+
+static inline void emulate_push(struct x86_emulate_ctxt *ctxt,
+				struct x86_emulate_ops *ops)
 {
 	struct decode_cache *c = &ctxt->decode;
 
@@ -1493,7 +1640,7 @@
 	c->dst.bytes = c->op_bytes;
 	c->dst.val = c->src.val;
 	register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes);
-	c->dst.ptr = (void *) register_address(c, ss_base(ctxt),
+	c->dst.ptr = (void *) register_address(c, ss_base(ctxt, ops),
 					       c->regs[VCPU_REGS_RSP]);
 }
 
@@ -1504,9 +1651,9 @@
 	struct decode_cache *c = &ctxt->decode;
 	int rc;
 
-	rc = ops->read_emulated(register_address(c, ss_base(ctxt),
-						 c->regs[VCPU_REGS_RSP]),
-				dest, len, ctxt->vcpu);
+	rc = read_emulated(ctxt, ops, register_address(c, ss_base(ctxt, ops),
+						       c->regs[VCPU_REGS_RSP]),
+			   dest, len);
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
 
@@ -1541,7 +1688,7 @@
 		break;
 	case X86EMUL_MODE_VM86:
 		if (iopl < 3) {
-			kvm_inject_gp(ctxt->vcpu, 0);
+			emulate_gp(ctxt, 0);
 			return X86EMUL_PROPAGATE_FAULT;
 		}
 		change_mask |= EFLG_IF;
@@ -1557,15 +1704,14 @@
 	return rc;
 }
 
-static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt, int seg)
+static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt,
+			      struct x86_emulate_ops *ops, int seg)
 {
 	struct decode_cache *c = &ctxt->decode;
-	struct kvm_segment segment;
 
-	kvm_x86_ops->get_segment(ctxt->vcpu, &segment, seg);
+	c->src.val = ops->get_segment_selector(seg, ctxt->vcpu);
 
-	c->src.val = segment.selector;
-	emulate_push(ctxt);
+	emulate_push(ctxt, ops);
 }
 
 static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
@@ -1583,19 +1729,31 @@
 	return rc;
 }
 
-static void emulate_pusha(struct x86_emulate_ctxt *ctxt)
+static int emulate_pusha(struct x86_emulate_ctxt *ctxt,
+			  struct x86_emulate_ops *ops)
 {
 	struct decode_cache *c = &ctxt->decode;
 	unsigned long old_esp = c->regs[VCPU_REGS_RSP];
+	int rc = X86EMUL_CONTINUE;
 	int reg = VCPU_REGS_RAX;
 
 	while (reg <= VCPU_REGS_RDI) {
 		(reg == VCPU_REGS_RSP) ?
 		(c->src.val = old_esp) : (c->src.val = c->regs[reg]);
 
-		emulate_push(ctxt);
+		emulate_push(ctxt, ops);
+
+		rc = writeback(ctxt, ops);
+		if (rc != X86EMUL_CONTINUE)
+			return rc;
+
 		++reg;
 	}
+
+	/* Disable writeback. */
+	c->dst.type = OP_NONE;
+
+	return rc;
 }
 
 static int emulate_popa(struct x86_emulate_ctxt *ctxt,
@@ -1695,14 +1853,14 @@
 		old_eip = c->eip;
 		c->eip = c->src.val;
 		c->src.val = old_eip;
-		emulate_push(ctxt);
+		emulate_push(ctxt, ops);
 		break;
 	}
 	case 4: /* jmp abs */
 		c->eip = c->src.val;
 		break;
 	case 6:	/* push */
-		emulate_push(ctxt);
+		emulate_push(ctxt, ops);
 		break;
 	}
 	return X86EMUL_CONTINUE;
@@ -1748,145 +1906,82 @@
 	return rc;
 }
 
-static inline int writeback(struct x86_emulate_ctxt *ctxt,
-			    struct x86_emulate_ops *ops)
-{
-	int rc;
-	struct decode_cache *c = &ctxt->decode;
-
-	switch (c->dst.type) {
-	case OP_REG:
-		/* The 4-byte case *is* correct:
-		 * in 64-bit mode we zero-extend.
-		 */
-		switch (c->dst.bytes) {
-		case 1:
-			*(u8 *)c->dst.ptr = (u8)c->dst.val;
-			break;
-		case 2:
-			*(u16 *)c->dst.ptr = (u16)c->dst.val;
-			break;
-		case 4:
-			*c->dst.ptr = (u32)c->dst.val;
-			break;	/* 64b: zero-ext */
-		case 8:
-			*c->dst.ptr = c->dst.val;
-			break;
-		}
-		break;
-	case OP_MEM:
-		if (c->lock_prefix)
-			rc = ops->cmpxchg_emulated(
-					(unsigned long)c->dst.ptr,
-					&c->dst.orig_val,
-					&c->dst.val,
-					c->dst.bytes,
-					ctxt->vcpu);
-		else
-			rc = ops->write_emulated(
-					(unsigned long)c->dst.ptr,
-					&c->dst.val,
-					c->dst.bytes,
-					ctxt->vcpu);
-		if (rc != X86EMUL_CONTINUE)
-			return rc;
-		break;
-	case OP_NONE:
-		/* no writeback */
-		break;
-	default:
-		break;
-	}
-	return X86EMUL_CONTINUE;
-}
-
-static void toggle_interruptibility(struct x86_emulate_ctxt *ctxt, u32 mask)
-{
-	u32 int_shadow = kvm_x86_ops->get_interrupt_shadow(ctxt->vcpu, mask);
-	/*
-	 * an sti; sti; sequence only disable interrupts for the first
-	 * instruction. So, if the last instruction, be it emulated or
-	 * not, left the system with the INT_STI flag enabled, it
-	 * means that the last instruction is an sti. We should not
-	 * leave the flag on in this case. The same goes for mov ss
-	 */
-	if (!(int_shadow & mask))
-		ctxt->interruptibility = mask;
-}
-
 static inline void
 setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
-	struct kvm_segment *cs, struct kvm_segment *ss)
+			struct x86_emulate_ops *ops, struct desc_struct *cs,
+			struct desc_struct *ss)
 {
-	memset(cs, 0, sizeof(struct kvm_segment));
-	kvm_x86_ops->get_segment(ctxt->vcpu, cs, VCPU_SREG_CS);
-	memset(ss, 0, sizeof(struct kvm_segment));
+	memset(cs, 0, sizeof(struct desc_struct));
+	ops->get_cached_descriptor(cs, VCPU_SREG_CS, ctxt->vcpu);
+	memset(ss, 0, sizeof(struct desc_struct));
 
 	cs->l = 0;		/* will be adjusted later */
-	cs->base = 0;		/* flat segment */
+	set_desc_base(cs, 0);	/* flat segment */
 	cs->g = 1;		/* 4kb granularity */
-	cs->limit = 0xffffffff;	/* 4GB limit */
+	set_desc_limit(cs, 0xfffff);	/* 4GB limit */
 	cs->type = 0x0b;	/* Read, Execute, Accessed */
 	cs->s = 1;
 	cs->dpl = 0;		/* will be adjusted later */
-	cs->present = 1;
-	cs->db = 1;
+	cs->p = 1;
+	cs->d = 1;
 
-	ss->unusable = 0;
-	ss->base = 0;		/* flat segment */
-	ss->limit = 0xffffffff;	/* 4GB limit */
+	set_desc_base(ss, 0);	/* flat segment */
+	set_desc_limit(ss, 0xfffff);	/* 4GB limit */
 	ss->g = 1;		/* 4kb granularity */
 	ss->s = 1;
 	ss->type = 0x03;	/* Read/Write, Accessed */
-	ss->db = 1;		/* 32bit stack segment */
+	ss->d = 1;		/* 32bit stack segment */
 	ss->dpl = 0;
-	ss->present = 1;
+	ss->p = 1;
 }
 
 static int
-emulate_syscall(struct x86_emulate_ctxt *ctxt)
+emulate_syscall(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
 {
 	struct decode_cache *c = &ctxt->decode;
-	struct kvm_segment cs, ss;
+	struct desc_struct cs, ss;
 	u64 msr_data;
+	u16 cs_sel, ss_sel;
 
 	/* syscall is not available in real mode */
 	if (ctxt->mode == X86EMUL_MODE_REAL ||
 	    ctxt->mode == X86EMUL_MODE_VM86) {
-		kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+		emulate_ud(ctxt);
 		return X86EMUL_PROPAGATE_FAULT;
 	}
 
-	setup_syscalls_segments(ctxt, &cs, &ss);
+	setup_syscalls_segments(ctxt, ops, &cs, &ss);
 
-	kvm_x86_ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
+	ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
 	msr_data >>= 32;
-	cs.selector = (u16)(msr_data & 0xfffc);
-	ss.selector = (u16)(msr_data + 8);
+	cs_sel = (u16)(msr_data & 0xfffc);
+	ss_sel = (u16)(msr_data + 8);
 
 	if (is_long_mode(ctxt->vcpu)) {
-		cs.db = 0;
+		cs.d = 0;
 		cs.l = 1;
 	}
-	kvm_x86_ops->set_segment(ctxt->vcpu, &cs, VCPU_SREG_CS);
-	kvm_x86_ops->set_segment(ctxt->vcpu, &ss, VCPU_SREG_SS);
+	ops->set_cached_descriptor(&cs, VCPU_SREG_CS, ctxt->vcpu);
+	ops->set_segment_selector(cs_sel, VCPU_SREG_CS, ctxt->vcpu);
+	ops->set_cached_descriptor(&ss, VCPU_SREG_SS, ctxt->vcpu);
+	ops->set_segment_selector(ss_sel, VCPU_SREG_SS, ctxt->vcpu);
 
 	c->regs[VCPU_REGS_RCX] = c->eip;
 	if (is_long_mode(ctxt->vcpu)) {
 #ifdef CONFIG_X86_64
 		c->regs[VCPU_REGS_R11] = ctxt->eflags & ~EFLG_RF;
 
-		kvm_x86_ops->get_msr(ctxt->vcpu,
-			ctxt->mode == X86EMUL_MODE_PROT64 ?
-			MSR_LSTAR : MSR_CSTAR, &msr_data);
+		ops->get_msr(ctxt->vcpu,
+			     ctxt->mode == X86EMUL_MODE_PROT64 ?
+			     MSR_LSTAR : MSR_CSTAR, &msr_data);
 		c->eip = msr_data;
 
-		kvm_x86_ops->get_msr(ctxt->vcpu, MSR_SYSCALL_MASK, &msr_data);
+		ops->get_msr(ctxt->vcpu, MSR_SYSCALL_MASK, &msr_data);
 		ctxt->eflags &= ~(msr_data | EFLG_RF);
 #endif
 	} else {
 		/* legacy mode */
-		kvm_x86_ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
+		ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
 		c->eip = (u32)msr_data;
 
 		ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
@@ -1896,15 +1991,16 @@
 }
 
 static int
-emulate_sysenter(struct x86_emulate_ctxt *ctxt)
+emulate_sysenter(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
 {
 	struct decode_cache *c = &ctxt->decode;
-	struct kvm_segment cs, ss;
+	struct desc_struct cs, ss;
 	u64 msr_data;
+	u16 cs_sel, ss_sel;
 
 	/* inject #GP if in real mode */
 	if (ctxt->mode == X86EMUL_MODE_REAL) {
-		kvm_inject_gp(ctxt->vcpu, 0);
+		emulate_gp(ctxt, 0);
 		return X86EMUL_PROPAGATE_FAULT;
 	}
 
@@ -1912,67 +2008,70 @@
 	* Therefore, we inject an #UD.
 	*/
 	if (ctxt->mode == X86EMUL_MODE_PROT64) {
-		kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+		emulate_ud(ctxt);
 		return X86EMUL_PROPAGATE_FAULT;
 	}
 
-	setup_syscalls_segments(ctxt, &cs, &ss);
+	setup_syscalls_segments(ctxt, ops, &cs, &ss);
 
-	kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
+	ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
 	switch (ctxt->mode) {
 	case X86EMUL_MODE_PROT32:
 		if ((msr_data & 0xfffc) == 0x0) {
-			kvm_inject_gp(ctxt->vcpu, 0);
+			emulate_gp(ctxt, 0);
 			return X86EMUL_PROPAGATE_FAULT;
 		}
 		break;
 	case X86EMUL_MODE_PROT64:
 		if (msr_data == 0x0) {
-			kvm_inject_gp(ctxt->vcpu, 0);
+			emulate_gp(ctxt, 0);
 			return X86EMUL_PROPAGATE_FAULT;
 		}
 		break;
 	}
 
 	ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
-	cs.selector = (u16)msr_data;
-	cs.selector &= ~SELECTOR_RPL_MASK;
-	ss.selector = cs.selector + 8;
-	ss.selector &= ~SELECTOR_RPL_MASK;
+	cs_sel = (u16)msr_data;
+	cs_sel &= ~SELECTOR_RPL_MASK;
+	ss_sel = cs_sel + 8;
+	ss_sel &= ~SELECTOR_RPL_MASK;
 	if (ctxt->mode == X86EMUL_MODE_PROT64
 		|| is_long_mode(ctxt->vcpu)) {
-		cs.db = 0;
+		cs.d = 0;
 		cs.l = 1;
 	}
 
-	kvm_x86_ops->set_segment(ctxt->vcpu, &cs, VCPU_SREG_CS);
-	kvm_x86_ops->set_segment(ctxt->vcpu, &ss, VCPU_SREG_SS);
+	ops->set_cached_descriptor(&cs, VCPU_SREG_CS, ctxt->vcpu);
+	ops->set_segment_selector(cs_sel, VCPU_SREG_CS, ctxt->vcpu);
+	ops->set_cached_descriptor(&ss, VCPU_SREG_SS, ctxt->vcpu);
+	ops->set_segment_selector(ss_sel, VCPU_SREG_SS, ctxt->vcpu);
 
-	kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_EIP, &msr_data);
+	ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_EIP, &msr_data);
 	c->eip = msr_data;
 
-	kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data);
+	ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data);
 	c->regs[VCPU_REGS_RSP] = msr_data;
 
 	return X86EMUL_CONTINUE;
 }
 
 static int
-emulate_sysexit(struct x86_emulate_ctxt *ctxt)
+emulate_sysexit(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
 {
 	struct decode_cache *c = &ctxt->decode;
-	struct kvm_segment cs, ss;
+	struct desc_struct cs, ss;
 	u64 msr_data;
 	int usermode;
+	u16 cs_sel, ss_sel;
 
 	/* inject #GP if in real mode or Virtual 8086 mode */
 	if (ctxt->mode == X86EMUL_MODE_REAL ||
 	    ctxt->mode == X86EMUL_MODE_VM86) {
-		kvm_inject_gp(ctxt->vcpu, 0);
+		emulate_gp(ctxt, 0);
 		return X86EMUL_PROPAGATE_FAULT;
 	}
 
-	setup_syscalls_segments(ctxt, &cs, &ss);
+	setup_syscalls_segments(ctxt, ops, &cs, &ss);
 
 	if ((c->rex_prefix & 0x8) != 0x0)
 		usermode = X86EMUL_MODE_PROT64;
@@ -1981,35 +2080,37 @@
 
 	cs.dpl = 3;
 	ss.dpl = 3;
-	kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
+	ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
 	switch (usermode) {
 	case X86EMUL_MODE_PROT32:
-		cs.selector = (u16)(msr_data + 16);
+		cs_sel = (u16)(msr_data + 16);
 		if ((msr_data & 0xfffc) == 0x0) {
-			kvm_inject_gp(ctxt->vcpu, 0);
+			emulate_gp(ctxt, 0);
 			return X86EMUL_PROPAGATE_FAULT;
 		}
-		ss.selector = (u16)(msr_data + 24);
+		ss_sel = (u16)(msr_data + 24);
 		break;
 	case X86EMUL_MODE_PROT64:
-		cs.selector = (u16)(msr_data + 32);
+		cs_sel = (u16)(msr_data + 32);
 		if (msr_data == 0x0) {
-			kvm_inject_gp(ctxt->vcpu, 0);
+			emulate_gp(ctxt, 0);
 			return X86EMUL_PROPAGATE_FAULT;
 		}
-		ss.selector = cs.selector + 8;
-		cs.db = 0;
+		ss_sel = cs_sel + 8;
+		cs.d = 0;
 		cs.l = 1;
 		break;
 	}
-	cs.selector |= SELECTOR_RPL_MASK;
-	ss.selector |= SELECTOR_RPL_MASK;
+	cs_sel |= SELECTOR_RPL_MASK;
+	ss_sel |= SELECTOR_RPL_MASK;
 
-	kvm_x86_ops->set_segment(ctxt->vcpu, &cs, VCPU_SREG_CS);
-	kvm_x86_ops->set_segment(ctxt->vcpu, &ss, VCPU_SREG_SS);
+	ops->set_cached_descriptor(&cs, VCPU_SREG_CS, ctxt->vcpu);
+	ops->set_segment_selector(cs_sel, VCPU_SREG_CS, ctxt->vcpu);
+	ops->set_cached_descriptor(&ss, VCPU_SREG_SS, ctxt->vcpu);
+	ops->set_segment_selector(ss_sel, VCPU_SREG_SS, ctxt->vcpu);
 
-	c->eip = ctxt->vcpu->arch.regs[VCPU_REGS_RDX];
-	c->regs[VCPU_REGS_RSP] = ctxt->vcpu->arch.regs[VCPU_REGS_RCX];
+	c->eip = c->regs[VCPU_REGS_RDX];
+	c->regs[VCPU_REGS_RSP] = c->regs[VCPU_REGS_RCX];
 
 	return X86EMUL_CONTINUE;
 }
@@ -2030,25 +2131,25 @@
 					    struct x86_emulate_ops *ops,
 					    u16 port, u16 len)
 {
-	struct kvm_segment tr_seg;
+	struct desc_struct tr_seg;
 	int r;
 	u16 io_bitmap_ptr;
 	u8 perm, bit_idx = port & 0x7;
 	unsigned mask = (1 << len) - 1;
 
-	kvm_get_segment(ctxt->vcpu, &tr_seg, VCPU_SREG_TR);
-	if (tr_seg.unusable)
+	ops->get_cached_descriptor(&tr_seg, VCPU_SREG_TR, ctxt->vcpu);
+	if (!tr_seg.p)
 		return false;
-	if (tr_seg.limit < 103)
+	if (desc_limit_scaled(&tr_seg) < 103)
 		return false;
-	r = ops->read_std(tr_seg.base + 102, &io_bitmap_ptr, 2, ctxt->vcpu,
-			  NULL);
+	r = ops->read_std(get_desc_base(&tr_seg) + 102, &io_bitmap_ptr, 2,
+			  ctxt->vcpu, NULL);
 	if (r != X86EMUL_CONTINUE)
 		return false;
-	if (io_bitmap_ptr + port/8 > tr_seg.limit)
+	if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg))
 		return false;
-	r = ops->read_std(tr_seg.base + io_bitmap_ptr + port/8, &perm, 1,
-			  ctxt->vcpu, NULL);
+	r = ops->read_std(get_desc_base(&tr_seg) + io_bitmap_ptr + port/8,
+			  &perm, 1, ctxt->vcpu, NULL);
 	if (r != X86EMUL_CONTINUE)
 		return false;
 	if ((perm >> bit_idx) & mask)
@@ -2066,17 +2167,6 @@
 	return true;
 }
 
-static u32 get_cached_descriptor_base(struct x86_emulate_ctxt *ctxt,
-				      struct x86_emulate_ops *ops,
-				      int seg)
-{
-	struct desc_struct desc;
-	if (ops->get_cached_descriptor(&desc, seg, ctxt->vcpu))
-		return get_desc_base(&desc);
-	else
-		return ~0;
-}
-
 static void save_state_to_tss16(struct x86_emulate_ctxt *ctxt,
 				struct x86_emulate_ops *ops,
 				struct tss_segment_16 *tss)
@@ -2165,7 +2255,7 @@
 			    &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT) {
 		/* FIXME: need to provide precise fault address */
-		kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+		emulate_pf(ctxt, old_tss_base, err);
 		return ret;
 	}
 
@@ -2175,7 +2265,7 @@
 			     &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT) {
 		/* FIXME: need to provide precise fault address */
-		kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+		emulate_pf(ctxt, old_tss_base, err);
 		return ret;
 	}
 
@@ -2183,7 +2273,7 @@
 			    &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT) {
 		/* FIXME: need to provide precise fault address */
-		kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+		emulate_pf(ctxt, new_tss_base, err);
 		return ret;
 	}
 
@@ -2196,7 +2286,7 @@
 				     ctxt->vcpu, &err);
 		if (ret == X86EMUL_PROPAGATE_FAULT) {
 			/* FIXME: need to provide precise fault address */
-			kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+			emulate_pf(ctxt, new_tss_base, err);
 			return ret;
 		}
 	}
@@ -2238,7 +2328,10 @@
 	struct decode_cache *c = &ctxt->decode;
 	int ret;
 
-	ops->set_cr(3, tss->cr3, ctxt->vcpu);
+	if (ops->set_cr(3, tss->cr3, ctxt->vcpu)) {
+		emulate_gp(ctxt, 0);
+		return X86EMUL_PROPAGATE_FAULT;
+	}
 	c->eip = tss->eip;
 	ctxt->eflags = tss->eflags | 2;
 	c->regs[VCPU_REGS_RAX] = tss->eax;
@@ -2304,7 +2397,7 @@
 			    &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT) {
 		/* FIXME: need to provide precise fault address */
-		kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+		emulate_pf(ctxt, old_tss_base, err);
 		return ret;
 	}
 
@@ -2314,7 +2407,7 @@
 			     &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT) {
 		/* FIXME: need to provide precise fault address */
-		kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+		emulate_pf(ctxt, old_tss_base, err);
 		return ret;
 	}
 
@@ -2322,7 +2415,7 @@
 			    &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT) {
 		/* FIXME: need to provide precise fault address */
-		kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+		emulate_pf(ctxt, new_tss_base, err);
 		return ret;
 	}
 
@@ -2335,7 +2428,7 @@
 				     ctxt->vcpu, &err);
 		if (ret == X86EMUL_PROPAGATE_FAULT) {
 			/* FIXME: need to provide precise fault address */
-			kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+			emulate_pf(ctxt, new_tss_base, err);
 			return ret;
 		}
 	}
@@ -2352,7 +2445,7 @@
 	int ret;
 	u16 old_tss_sel = ops->get_segment_selector(VCPU_SREG_TR, ctxt->vcpu);
 	ulong old_tss_base =
-		get_cached_descriptor_base(ctxt, ops, VCPU_SREG_TR);
+		ops->get_cached_segment_base(VCPU_SREG_TR, ctxt->vcpu);
 	u32 desc_limit;
 
 	/* FIXME: old_tss_base == ~0 ? */
@@ -2369,7 +2462,7 @@
 	if (reason != TASK_SWITCH_IRET) {
 		if ((tss_selector & 3) > next_tss_desc.dpl ||
 		    ops->cpl(ctxt->vcpu) > next_tss_desc.dpl) {
-			kvm_inject_gp(ctxt->vcpu, 0);
+			emulate_gp(ctxt, 0);
 			return X86EMUL_PROPAGATE_FAULT;
 		}
 	}
@@ -2378,8 +2471,7 @@
 	if (!next_tss_desc.p ||
 	    ((desc_limit < 0x67 && (next_tss_desc.type & 8)) ||
 	     desc_limit < 0x2b)) {
-		kvm_queue_exception_e(ctxt->vcpu, TS_VECTOR,
-				      tss_selector & 0xfffc);
+		emulate_ts(ctxt, tss_selector & 0xfffc);
 		return X86EMUL_PROPAGATE_FAULT;
 	}
 
@@ -2425,7 +2517,7 @@
 		c->op_bytes = c->ad_bytes = (next_tss_desc.type & 8) ? 4 : 2;
 		c->lock_prefix = 0;
 		c->src.val = (unsigned long) error_code;
-		emulate_push(ctxt);
+		emulate_push(ctxt, ops);
 	}
 
 	return ret;
@@ -2439,18 +2531,16 @@
 	struct decode_cache *c = &ctxt->decode;
 	int rc;
 
-	memset(c, 0, sizeof(struct decode_cache));
 	c->eip = ctxt->eip;
-	memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
 	c->dst.type = OP_NONE;
 
 	rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason,
 				     has_error_code, error_code);
 
 	if (rc == X86EMUL_CONTINUE) {
-		memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs);
-		kvm_rip_write(ctxt->vcpu, c->eip);
 		rc = writeback(ctxt, ops);
+		if (rc == X86EMUL_CONTINUE)
+			ctxt->eip = c->eip;
 	}
 
 	return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
@@ -2474,29 +2564,22 @@
 	int rc = X86EMUL_CONTINUE;
 	int saved_dst_type = c->dst.type;
 
-	ctxt->interruptibility = 0;
-
-	/* Shadow copy of register state. Committed on successful emulation.
-	 * NOTE: we can copy them from vcpu as x86_decode_insn() doesn't
-	 * modify them.
-	 */
-
-	memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
+	ctxt->decode.mem_read.pos = 0;
 
 	if (ctxt->mode == X86EMUL_MODE_PROT64 && (c->d & No64)) {
-		kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+		emulate_ud(ctxt);
 		goto done;
 	}
 
 	/* LOCK prefix is allowed only with some instructions */
 	if (c->lock_prefix && (!(c->d & Lock) || c->dst.type != OP_MEM)) {
-		kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+		emulate_ud(ctxt);
 		goto done;
 	}
 
 	/* Privileged instruction can be executed only in CPL=0 */
 	if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) {
-		kvm_inject_gp(ctxt->vcpu, 0);
+		emulate_gp(ctxt, 0);
 		goto done;
 	}
 
@@ -2506,7 +2589,7 @@
 		if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) {
 		string_done:
 			ctxt->restart = false;
-			kvm_rip_write(ctxt->vcpu, c->eip);
+			ctxt->eip = c->eip;
 			goto done;
 		}
 		/* The second termination condition only applies for REPE
@@ -2529,20 +2612,16 @@
 	}
 
 	if (c->src.type == OP_MEM) {
-		rc = ops->read_emulated((unsigned long)c->src.ptr,
-					&c->src.val,
-					c->src.bytes,
-					ctxt->vcpu);
+		rc = read_emulated(ctxt, ops, (unsigned long)c->src.ptr,
+					c->src.valptr, c->src.bytes);
 		if (rc != X86EMUL_CONTINUE)
 			goto done;
 		c->src.orig_val = c->src.val;
 	}
 
 	if (c->src2.type == OP_MEM) {
-		rc = ops->read_emulated((unsigned long)c->src2.ptr,
-					&c->src2.val,
-					c->src2.bytes,
-					ctxt->vcpu);
+		rc = read_emulated(ctxt, ops, (unsigned long)c->src2.ptr,
+					&c->src2.val, c->src2.bytes);
 		if (rc != X86EMUL_CONTINUE)
 			goto done;
 	}
@@ -2553,8 +2632,8 @@
 
 	if ((c->dst.type == OP_MEM) && !(c->d & Mov)) {
 		/* optimisation - avoid slow emulated read if Mov */
-		rc = ops->read_emulated((unsigned long)c->dst.ptr, &c->dst.val,
-					c->dst.bytes, ctxt->vcpu);
+		rc = read_emulated(ctxt, ops, (unsigned long)c->dst.ptr,
+				   &c->dst.val, c->dst.bytes);
 		if (rc != X86EMUL_CONTINUE)
 			goto done;
 	}
@@ -2571,7 +2650,7 @@
 		emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags);
 		break;
 	case 0x06:		/* push es */
-		emulate_push_sreg(ctxt, VCPU_SREG_ES);
+		emulate_push_sreg(ctxt, ops, VCPU_SREG_ES);
 		break;
 	case 0x07:		/* pop es */
 		rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES);
@@ -2583,14 +2662,14 @@
 		emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags);
 		break;
 	case 0x0e:		/* push cs */
-		emulate_push_sreg(ctxt, VCPU_SREG_CS);
+		emulate_push_sreg(ctxt, ops, VCPU_SREG_CS);
 		break;
 	case 0x10 ... 0x15:
 	      adc:		/* adc */
 		emulate_2op_SrcV("adc", c->src, c->dst, ctxt->eflags);
 		break;
 	case 0x16:		/* push ss */
-		emulate_push_sreg(ctxt, VCPU_SREG_SS);
+		emulate_push_sreg(ctxt, ops, VCPU_SREG_SS);
 		break;
 	case 0x17:		/* pop ss */
 		rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS);
@@ -2602,7 +2681,7 @@
 		emulate_2op_SrcV("sbb", c->src, c->dst, ctxt->eflags);
 		break;
 	case 0x1e:		/* push ds */
-		emulate_push_sreg(ctxt, VCPU_SREG_DS);
+		emulate_push_sreg(ctxt, ops, VCPU_SREG_DS);
 		break;
 	case 0x1f:		/* pop ds */
 		rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS);
@@ -2632,7 +2711,7 @@
 		emulate_1op("dec", c->dst, ctxt->eflags);
 		break;
 	case 0x50 ... 0x57:  /* push reg */
-		emulate_push(ctxt);
+		emulate_push(ctxt, ops);
 		break;
 	case 0x58 ... 0x5f: /* pop reg */
 	pop_instruction:
@@ -2641,7 +2720,9 @@
 			goto done;
 		break;
 	case 0x60:	/* pusha */
-		emulate_pusha(ctxt);
+		rc = emulate_pusha(ctxt, ops);
+		if (rc != X86EMUL_CONTINUE)
+			goto done;
 		break;
 	case 0x61:	/* popa */
 		rc = emulate_popa(ctxt, ops);
@@ -2655,14 +2736,14 @@
 		break;
 	case 0x68: /* push imm */
 	case 0x6a: /* push imm8 */
-		emulate_push(ctxt);
+		emulate_push(ctxt, ops);
 		break;
 	case 0x6c:		/* insb */
 	case 0x6d:		/* insw/insd */
 		c->dst.bytes = min(c->dst.bytes, 4u);
 		if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
 					  c->dst.bytes)) {
-			kvm_inject_gp(ctxt->vcpu, 0);
+			emulate_gp(ctxt, 0);
 			goto done;
 		}
 		if (!pio_in_emulated(ctxt, ops, c->dst.bytes,
@@ -2674,7 +2755,7 @@
 		c->src.bytes = min(c->src.bytes, 4u);
 		if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
 					  c->src.bytes)) {
-			kvm_inject_gp(ctxt->vcpu, 0);
+			emulate_gp(ctxt, 0);
 			goto done;
 		}
 		ops->pio_out_emulated(c->src.bytes, c->regs[VCPU_REGS_RDX],
@@ -2707,6 +2788,7 @@
 		}
 		break;
 	case 0x84 ... 0x85:
+	test:
 		emulate_2op_SrcV("test", c->src, c->dst, ctxt->eflags);
 		break;
 	case 0x86 ... 0x87:	/* xchg */
@@ -2735,18 +2817,13 @@
 		break;
 	case 0x88 ... 0x8b:	/* mov */
 		goto mov;
-	case 0x8c: { /* mov r/m, sreg */
-		struct kvm_segment segreg;
-
-		if (c->modrm_reg <= VCPU_SREG_GS)
-			kvm_get_segment(ctxt->vcpu, &segreg, c->modrm_reg);
-		else {
-			kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+	case 0x8c:  /* mov r/m, sreg */
+		if (c->modrm_reg > VCPU_SREG_GS) {
+			emulate_ud(ctxt);
 			goto done;
 		}
-		c->dst.val = segreg.selector;
+		c->dst.val = ops->get_segment_selector(c->modrm_reg, ctxt->vcpu);
 		break;
-	}
 	case 0x8d: /* lea r16/r32, m */
 		c->dst.val = c->modrm_ea;
 		break;
@@ -2757,12 +2834,12 @@
 
 		if (c->modrm_reg == VCPU_SREG_CS ||
 		    c->modrm_reg > VCPU_SREG_GS) {
-			kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+			emulate_ud(ctxt);
 			goto done;
 		}
 
 		if (c->modrm_reg == VCPU_SREG_SS)
-			toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_MOV_SS);
+			ctxt->interruptibility = KVM_X86_SHADOW_INT_MOV_SS;
 
 		rc = load_segment_descriptor(ctxt, ops, sel, c->modrm_reg);
 
@@ -2775,19 +2852,19 @@
 			goto done;
 		break;
 	case 0x90: /* nop / xchg r8,rax */
-		if (!(c->rex_prefix & 1)) { /* nop */
-			c->dst.type = OP_NONE;
+		if (c->dst.ptr == (unsigned long *)&c->regs[VCPU_REGS_RAX]) {
+			c->dst.type = OP_NONE;  /* nop */
 			break;
 		}
 	case 0x91 ... 0x97: /* xchg reg,rax */
-		c->src.type = c->dst.type = OP_REG;
-		c->src.bytes = c->dst.bytes = c->op_bytes;
+		c->src.type = OP_REG;
+		c->src.bytes = c->op_bytes;
 		c->src.ptr = (unsigned long *) &c->regs[VCPU_REGS_RAX];
 		c->src.val = *(c->src.ptr);
 		goto xchg;
 	case 0x9c: /* pushf */
 		c->src.val =  (unsigned long) ctxt->eflags;
-		emulate_push(ctxt);
+		emulate_push(ctxt, ops);
 		break;
 	case 0x9d: /* popf */
 		c->dst.type = OP_REG;
@@ -2797,19 +2874,15 @@
 		if (rc != X86EMUL_CONTINUE)
 			goto done;
 		break;
-	case 0xa0 ... 0xa1:	/* mov */
-		c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
-		c->dst.val = c->src.val;
-		break;
-	case 0xa2 ... 0xa3:	/* mov */
-		c->dst.val = (unsigned long)c->regs[VCPU_REGS_RAX];
-		break;
+	case 0xa0 ... 0xa3:	/* mov */
 	case 0xa4 ... 0xa5:	/* movs */
 		goto mov;
 	case 0xa6 ... 0xa7:	/* cmps */
 		c->dst.type = OP_NONE; /* Disable writeback. */
 		DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.ptr, c->dst.ptr);
 		goto cmp;
+	case 0xa8 ... 0xa9:	/* test ax, imm */
+		goto test;
 	case 0xaa ... 0xab:	/* stos */
 		c->dst.val = c->regs[VCPU_REGS_RAX];
 		break;
@@ -2855,19 +2928,23 @@
 		long int rel = c->src.val;
 		c->src.val = (unsigned long) c->eip;
 		jmp_rel(c, rel);
-		emulate_push(ctxt);
+		emulate_push(ctxt, ops);
 		break;
 	}
 	case 0xe9: /* jmp rel */
 		goto jmp;
-	case 0xea: /* jmp far */
+	case 0xea: { /* jmp far */
+		unsigned short sel;
 	jump_far:
-		if (load_segment_descriptor(ctxt, ops, c->src2.val,
-					    VCPU_SREG_CS))
+		memcpy(&sel, c->src.valptr + c->op_bytes, 2);
+
+		if (load_segment_descriptor(ctxt, ops, sel, VCPU_SREG_CS))
 			goto done;
 
-		c->eip = c->src.val;
+		c->eip = 0;
+		memcpy(&c->eip, c->src.valptr, c->op_bytes);
 		break;
+	}
 	case 0xeb:
 	      jmp:		/* jmp rel short */
 		jmp_rel(c, c->src.val);
@@ -2879,20 +2956,20 @@
 	do_io_in:
 		c->dst.bytes = min(c->dst.bytes, 4u);
 		if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) {
-			kvm_inject_gp(ctxt->vcpu, 0);
+			emulate_gp(ctxt, 0);
 			goto done;
 		}
 		if (!pio_in_emulated(ctxt, ops, c->dst.bytes, c->src.val,
 				     &c->dst.val))
 			goto done; /* IO is needed */
 		break;
-	case 0xee: /* out al,dx */
-	case 0xef: /* out (e/r)ax,dx */
+	case 0xee: /* out dx,al */
+	case 0xef: /* out dx,(e/r)ax */
 		c->src.val = c->regs[VCPU_REGS_RDX];
 	do_io_out:
 		c->dst.bytes = min(c->dst.bytes, 4u);
 		if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) {
-			kvm_inject_gp(ctxt->vcpu, 0);
+			emulate_gp(ctxt, 0);
 			goto done;
 		}
 		ops->pio_out_emulated(c->dst.bytes, c->src.val, &c->dst.val, 1,
@@ -2916,18 +2993,20 @@
 		c->dst.type = OP_NONE;	/* Disable writeback. */
 		break;
 	case 0xfa: /* cli */
-		if (emulator_bad_iopl(ctxt, ops))
-			kvm_inject_gp(ctxt->vcpu, 0);
-		else {
+		if (emulator_bad_iopl(ctxt, ops)) {
+			emulate_gp(ctxt, 0);
+			goto done;
+		} else {
 			ctxt->eflags &= ~X86_EFLAGS_IF;
 			c->dst.type = OP_NONE;	/* Disable writeback. */
 		}
 		break;
 	case 0xfb: /* sti */
-		if (emulator_bad_iopl(ctxt, ops))
-			kvm_inject_gp(ctxt->vcpu, 0);
-		else {
-			toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_STI);
+		if (emulator_bad_iopl(ctxt, ops)) {
+			emulate_gp(ctxt, 0);
+			goto done;
+		} else {
+			ctxt->interruptibility = KVM_X86_SHADOW_INT_STI;
 			ctxt->eflags |= X86_EFLAGS_IF;
 			c->dst.type = OP_NONE;	/* Disable writeback. */
 		}
@@ -2964,11 +3043,12 @@
 	c->dst.type = saved_dst_type;
 
 	if ((c->d & SrcMask) == SrcSI)
-		string_addr_inc(ctxt, seg_override_base(ctxt, c), VCPU_REGS_RSI,
-				&c->src);
+		string_addr_inc(ctxt, seg_override_base(ctxt, ops, c),
+				VCPU_REGS_RSI, &c->src);
 
 	if ((c->d & DstMask) == DstDI)
-		string_addr_inc(ctxt, es_base(ctxt), VCPU_REGS_RDI, &c->dst);
+		string_addr_inc(ctxt, es_base(ctxt, ops), VCPU_REGS_RDI,
+				&c->dst);
 
 	if (c->rep_prefix && (c->d & String)) {
 		struct read_cache *rc = &ctxt->decode.io_read;
@@ -2981,11 +3061,12 @@
 		    (rc->end != 0 && rc->end == rc->pos))
 			ctxt->restart = false;
 	}
-
-	/* Commit shadow register state. */
-	memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs);
-	kvm_rip_write(ctxt->vcpu, c->eip);
-	ops->set_rflags(ctxt->vcpu, ctxt->eflags);
+	/*
+	 * reset read cache here in case string instruction is restared
+	 * without decoding
+	 */
+	ctxt->decode.mem_read.end = 0;
+	ctxt->eip = c->eip;
 
 done:
 	return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
@@ -3051,7 +3132,7 @@
 			c->dst.type = OP_NONE;
 			break;
 		case 5: /* not defined */
-			kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+			emulate_ud(ctxt);
 			goto done;
 		case 7: /* invlpg*/
 			emulate_invlpg(ctxt->vcpu, c->modrm_ea);
@@ -3063,7 +3144,7 @@
 		}
 		break;
 	case 0x05: 		/* syscall */
-		rc = emulate_syscall(ctxt);
+		rc = emulate_syscall(ctxt, ops);
 		if (rc != X86EMUL_CONTINUE)
 			goto done;
 		else
@@ -3073,8 +3154,11 @@
 		emulate_clts(ctxt->vcpu);
 		c->dst.type = OP_NONE;
 		break;
-	case 0x08:		/* invd */
 	case 0x09:		/* wbinvd */
+		kvm_emulate_wbinvd(ctxt->vcpu);
+		c->dst.type = OP_NONE;
+		break;
+	case 0x08:		/* invd */
 	case 0x0d:		/* GrpP (prefetch) */
 	case 0x18:		/* Grp16 (prefetch/nop) */
 		c->dst.type = OP_NONE;
@@ -3084,7 +3168,7 @@
 		case 1:
 		case 5 ... 7:
 		case 9 ... 15:
-			kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+			emulate_ud(ctxt);
 			goto done;
 		}
 		c->regs[c->modrm_rm] = ops->get_cr(c->modrm_reg, ctxt->vcpu);
@@ -3093,31 +3177,42 @@
 	case 0x21: /* mov from dr to reg */
 		if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
 		    (c->modrm_reg == 4 || c->modrm_reg == 5)) {
-			kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+			emulate_ud(ctxt);
 			goto done;
 		}
-		emulator_get_dr(ctxt, c->modrm_reg, &c->regs[c->modrm_rm]);
+		ops->get_dr(c->modrm_reg, &c->regs[c->modrm_rm], ctxt->vcpu);
 		c->dst.type = OP_NONE;	/* no writeback */
 		break;
 	case 0x22: /* mov reg, cr */
-		ops->set_cr(c->modrm_reg, c->modrm_val, ctxt->vcpu);
+		if (ops->set_cr(c->modrm_reg, c->modrm_val, ctxt->vcpu)) {
+			emulate_gp(ctxt, 0);
+			goto done;
+		}
 		c->dst.type = OP_NONE;
 		break;
 	case 0x23: /* mov from reg to dr */
 		if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
 		    (c->modrm_reg == 4 || c->modrm_reg == 5)) {
-			kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+			emulate_ud(ctxt);
 			goto done;
 		}
-		emulator_set_dr(ctxt, c->modrm_reg, c->regs[c->modrm_rm]);
+
+		if (ops->set_dr(c->modrm_reg, c->regs[c->modrm_rm] &
+				((ctxt->mode == X86EMUL_MODE_PROT64) ?
+				 ~0ULL : ~0U), ctxt->vcpu) < 0) {
+			/* #UD condition is already handled by the code above */
+			emulate_gp(ctxt, 0);
+			goto done;
+		}
+
 		c->dst.type = OP_NONE;	/* no writeback */
 		break;
 	case 0x30:
 		/* wrmsr */
 		msr_data = (u32)c->regs[VCPU_REGS_RAX]
 			| ((u64)c->regs[VCPU_REGS_RDX] << 32);
-		if (kvm_set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data)) {
-			kvm_inject_gp(ctxt->vcpu, 0);
+		if (ops->set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data)) {
+			emulate_gp(ctxt, 0);
 			goto done;
 		}
 		rc = X86EMUL_CONTINUE;
@@ -3125,8 +3220,8 @@
 		break;
 	case 0x32:
 		/* rdmsr */
-		if (kvm_get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data)) {
-			kvm_inject_gp(ctxt->vcpu, 0);
+		if (ops->get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data)) {
+			emulate_gp(ctxt, 0);
 			goto done;
 		} else {
 			c->regs[VCPU_REGS_RAX] = (u32)msr_data;
@@ -3136,14 +3231,14 @@
 		c->dst.type = OP_NONE;
 		break;
 	case 0x34:		/* sysenter */
-		rc = emulate_sysenter(ctxt);
+		rc = emulate_sysenter(ctxt, ops);
 		if (rc != X86EMUL_CONTINUE)
 			goto done;
 		else
 			goto writeback;
 		break;
 	case 0x35:		/* sysexit */
-		rc = emulate_sysexit(ctxt);
+		rc = emulate_sysexit(ctxt, ops);
 		if (rc != X86EMUL_CONTINUE)
 			goto done;
 		else
@@ -3160,7 +3255,7 @@
 		c->dst.type = OP_NONE;
 		break;
 	case 0xa0:	  /* push fs */
-		emulate_push_sreg(ctxt, VCPU_SREG_FS);
+		emulate_push_sreg(ctxt, ops, VCPU_SREG_FS);
 		break;
 	case 0xa1:	 /* pop fs */
 		rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS);
@@ -3179,7 +3274,7 @@
 		emulate_2op_cl("shld", c->src2, c->src, c->dst, ctxt->eflags);
 		break;
 	case 0xa8:	/* push gs */
-		emulate_push_sreg(ctxt, VCPU_SREG_GS);
+		emulate_push_sreg(ctxt, ops, VCPU_SREG_GS);
 		break;
 	case 0xa9:	/* pop gs */
 		rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS);
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 0150aff..0fd6378 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2006 Intel Corporation
  * Copyright (c) 2007 Keir Fraser, XenSource Inc
  * Copyright (c) 2008 Intel Corporation
+ * Copyright 2009 Red Hat, Inc. and/or its affilates.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -33,6 +34,7 @@
 
 #include <linux/kvm_host.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
 
 #include "irq.h"
 #include "i8254.h"
@@ -243,11 +245,22 @@
 {
 	struct kvm_kpit_state *ps = container_of(kian, struct kvm_kpit_state,
 						 irq_ack_notifier);
-	raw_spin_lock(&ps->inject_lock);
-	if (atomic_dec_return(&ps->pit_timer.pending) < 0)
+	int value;
+
+	spin_lock(&ps->inject_lock);
+	value = atomic_dec_return(&ps->pit_timer.pending);
+	if (value < 0)
+		/* spurious acks can be generated if, for example, the
+		 * PIC is being reset.  Handle it gracefully here
+		 */
 		atomic_inc(&ps->pit_timer.pending);
+	else if (value > 0)
+		/* in this case, we had multiple outstanding pit interrupts
+		 * that we needed to inject.  Reinject
+		 */
+		queue_work(ps->pit->wq, &ps->pit->expired);
 	ps->irq_ack = 1;
-	raw_spin_unlock(&ps->inject_lock);
+	spin_unlock(&ps->inject_lock);
 }
 
 void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu)
@@ -263,10 +276,10 @@
 		hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
 }
 
-static void destroy_pit_timer(struct kvm_timer *pt)
+static void destroy_pit_timer(struct kvm_pit *pit)
 {
-	pr_debug("execute del timer!\n");
-	hrtimer_cancel(&pt->timer);
+	hrtimer_cancel(&pit->pit_state.pit_timer.timer);
+	cancel_work_sync(&pit->expired);
 }
 
 static bool kpit_is_periodic(struct kvm_timer *ktimer)
@@ -280,6 +293,60 @@
 	.is_periodic = kpit_is_periodic,
 };
 
+static void pit_do_work(struct work_struct *work)
+{
+	struct kvm_pit *pit = container_of(work, struct kvm_pit, expired);
+	struct kvm *kvm = pit->kvm;
+	struct kvm_vcpu *vcpu;
+	int i;
+	struct kvm_kpit_state *ps = &pit->pit_state;
+	int inject = 0;
+
+	/* Try to inject pending interrupts when
+	 * last one has been acked.
+	 */
+	spin_lock(&ps->inject_lock);
+	if (ps->irq_ack) {
+		ps->irq_ack = 0;
+		inject = 1;
+	}
+	spin_unlock(&ps->inject_lock);
+	if (inject) {
+		kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1);
+		kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0);
+
+		/*
+		 * Provides NMI watchdog support via Virtual Wire mode.
+		 * The route is: PIT -> PIC -> LVT0 in NMI mode.
+		 *
+		 * Note: Our Virtual Wire implementation is simplified, only
+		 * propagating PIT interrupts to all VCPUs when they have set
+		 * LVT0 to NMI delivery. Other PIC interrupts are just sent to
+		 * VCPU0, and only if its LVT0 is in EXTINT mode.
+		 */
+		if (kvm->arch.vapics_in_nmi_mode > 0)
+			kvm_for_each_vcpu(i, vcpu, kvm)
+				kvm_apic_nmi_wd_deliver(vcpu);
+	}
+}
+
+static enum hrtimer_restart pit_timer_fn(struct hrtimer *data)
+{
+	struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer);
+	struct kvm_pit *pt = ktimer->kvm->arch.vpit;
+
+	if (ktimer->reinject || !atomic_read(&ktimer->pending)) {
+		atomic_inc(&ktimer->pending);
+		queue_work(pt->wq, &pt->expired);
+	}
+
+	if (ktimer->t_ops->is_periodic(ktimer)) {
+		hrtimer_add_expires_ns(&ktimer->timer, ktimer->period);
+		return HRTIMER_RESTART;
+	} else
+		return HRTIMER_NORESTART;
+}
+
 static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period)
 {
 	struct kvm_timer *pt = &ps->pit_timer;
@@ -291,13 +358,13 @@
 
 	/* TODO The new value only affected after the retriggered */
 	hrtimer_cancel(&pt->timer);
+	cancel_work_sync(&ps->pit->expired);
 	pt->period = interval;
 	ps->is_periodic = is_period;
 
-	pt->timer.function = kvm_timer_fn;
+	pt->timer.function = pit_timer_fn;
 	pt->t_ops = &kpit_ops;
 	pt->kvm = ps->pit->kvm;
-	pt->vcpu = pt->kvm->bsp_vcpu;
 
 	atomic_set(&pt->pending, 0);
 	ps->irq_ack = 1;
@@ -346,7 +413,7 @@
 		}
 		break;
 	default:
-		destroy_pit_timer(&ps->pit_timer);
+		destroy_pit_timer(kvm->arch.vpit);
 	}
 }
 
@@ -625,7 +692,15 @@
 
 	mutex_init(&pit->pit_state.lock);
 	mutex_lock(&pit->pit_state.lock);
-	raw_spin_lock_init(&pit->pit_state.inject_lock);
+	spin_lock_init(&pit->pit_state.inject_lock);
+
+	pit->wq = create_singlethread_workqueue("kvm-pit-wq");
+	if (!pit->wq) {
+		mutex_unlock(&pit->pit_state.lock);
+		kfree(pit);
+		return NULL;
+	}
+	INIT_WORK(&pit->expired, pit_do_work);
 
 	kvm->arch.vpit = pit;
 	pit->kvm = kvm;
@@ -677,6 +752,9 @@
 	struct hrtimer *timer;
 
 	if (kvm->arch.vpit) {
+		kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &kvm->arch.vpit->dev);
+		kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
+					      &kvm->arch.vpit->speaker_dev);
 		kvm_unregister_irq_mask_notifier(kvm, 0,
 					       &kvm->arch.vpit->mask_notifier);
 		kvm_unregister_irq_ack_notifier(kvm,
@@ -684,54 +762,10 @@
 		mutex_lock(&kvm->arch.vpit->pit_state.lock);
 		timer = &kvm->arch.vpit->pit_state.pit_timer.timer;
 		hrtimer_cancel(timer);
+		cancel_work_sync(&kvm->arch.vpit->expired);
 		kvm_free_irq_source_id(kvm, kvm->arch.vpit->irq_source_id);
 		mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+		destroy_workqueue(kvm->arch.vpit->wq);
 		kfree(kvm->arch.vpit);
 	}
 }
-
-static void __inject_pit_timer_intr(struct kvm *kvm)
-{
-	struct kvm_vcpu *vcpu;
-	int i;
-
-	kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1);
-	kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0);
-
-	/*
-	 * Provides NMI watchdog support via Virtual Wire mode.
-	 * The route is: PIT -> PIC -> LVT0 in NMI mode.
-	 *
-	 * Note: Our Virtual Wire implementation is simplified, only
-	 * propagating PIT interrupts to all VCPUs when they have set
-	 * LVT0 to NMI delivery. Other PIC interrupts are just sent to
-	 * VCPU0, and only if its LVT0 is in EXTINT mode.
-	 */
-	if (kvm->arch.vapics_in_nmi_mode > 0)
-		kvm_for_each_vcpu(i, vcpu, kvm)
-			kvm_apic_nmi_wd_deliver(vcpu);
-}
-
-void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu)
-{
-	struct kvm_pit *pit = vcpu->kvm->arch.vpit;
-	struct kvm *kvm = vcpu->kvm;
-	struct kvm_kpit_state *ps;
-
-	if (pit) {
-		int inject = 0;
-		ps = &pit->pit_state;
-
-		/* Try to inject pending interrupts when
-		 * last one has been acked.
-		 */
-		raw_spin_lock(&ps->inject_lock);
-		if (atomic_read(&ps->pit_timer.pending) && ps->irq_ack) {
-			ps->irq_ack = 0;
-			inject = 1;
-		}
-		raw_spin_unlock(&ps->inject_lock);
-		if (inject)
-			__inject_pit_timer_intr(kvm);
-	}
-}
diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h
index 900d6b0..46d08ca 100644
--- a/arch/x86/kvm/i8254.h
+++ b/arch/x86/kvm/i8254.h
@@ -27,7 +27,7 @@
 	u32    speaker_data_on;
 	struct mutex lock;
 	struct kvm_pit *pit;
-	raw_spinlock_t inject_lock;
+	spinlock_t inject_lock;
 	unsigned long irq_ack;
 	struct kvm_irq_ack_notifier irq_ack_notifier;
 };
@@ -40,6 +40,8 @@
 	struct kvm_kpit_state pit_state;
 	int irq_source_id;
 	struct kvm_irq_mask_notifier mask_notifier;
+	struct workqueue_struct *wq;
+	struct work_struct expired;
 };
 
 #define KVM_PIT_BASE_ADDRESS	    0x40
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index 93825ff..8d10c06 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2003-2004 Fabrice Bellard
  * Copyright (c) 2007 Intel Corporation
+ * Copyright 2009 Red Hat, Inc. and/or its affilates.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -33,6 +34,8 @@
 #include <linux/kvm_host.h>
 #include "trace.h"
 
+static void pic_irq_request(struct kvm *kvm, int level);
+
 static void pic_lock(struct kvm_pic *s)
 	__acquires(&s->lock)
 {
@@ -43,16 +46,25 @@
 	__releases(&s->lock)
 {
 	bool wakeup = s->wakeup_needed;
-	struct kvm_vcpu *vcpu;
+	struct kvm_vcpu *vcpu, *found = NULL;
+	int i;
 
 	s->wakeup_needed = false;
 
 	raw_spin_unlock(&s->lock);
 
 	if (wakeup) {
-		vcpu = s->kvm->bsp_vcpu;
-		if (vcpu)
-			kvm_vcpu_kick(vcpu);
+		kvm_for_each_vcpu(i, vcpu, s->kvm) {
+			if (kvm_apic_accept_pic_intr(vcpu)) {
+				found = vcpu;
+				break;
+			}
+		}
+
+		if (!found)
+			found = s->kvm->bsp_vcpu;
+
+		kvm_vcpu_kick(found);
 	}
 }
 
@@ -173,10 +185,7 @@
 		pic_set_irq1(&s->pics[0], 2, 0);
 	}
 	irq = pic_get_irq(&s->pics[0]);
-	if (irq >= 0)
-		s->irq_request(s->irq_request_opaque, 1);
-	else
-		s->irq_request(s->irq_request_opaque, 0);
+	pic_irq_request(s->kvm, irq >= 0);
 }
 
 void kvm_pic_update_irq(struct kvm_pic *s)
@@ -261,8 +270,7 @@
 void kvm_pic_reset(struct kvm_kpic_state *s)
 {
 	int irq;
-	struct kvm *kvm = s->pics_state->irq_request_opaque;
-	struct kvm_vcpu *vcpu0 = kvm->bsp_vcpu;
+	struct kvm_vcpu *vcpu0 = s->pics_state->kvm->bsp_vcpu;
 	u8 irr = s->irr, isr = s->imr;
 
 	s->last_irr = 0;
@@ -301,8 +309,7 @@
 			/*
 			 * deassert a pending interrupt
 			 */
-			s->pics_state->irq_request(s->pics_state->
-						   irq_request_opaque, 0);
+			pic_irq_request(s->pics_state->kvm, 0);
 			s->init_state = 1;
 			s->init4 = val & 1;
 			if (val & 0x02)
@@ -356,10 +363,20 @@
 		}
 	} else
 		switch (s->init_state) {
-		case 0:		/* normal mode */
+		case 0: { /* normal mode */
+			u8 imr_diff = s->imr ^ val,
+				off = (s == &s->pics_state->pics[0]) ? 0 : 8;
 			s->imr = val;
+			for (irq = 0; irq < PIC_NUM_PINS/2; irq++)
+				if (imr_diff & (1 << irq))
+					kvm_fire_mask_notifiers(
+						s->pics_state->kvm,
+						SELECT_PIC(irq + off),
+						irq + off,
+						!!(s->imr & (1 << irq)));
 			pic_update_irq(s->pics_state);
 			break;
+		}
 		case 1:
 			s->irq_base = val & 0xf8;
 			s->init_state = 2;
@@ -518,9 +535,8 @@
 /*
  * callback when PIC0 irq status changed
  */
-static void pic_irq_request(void *opaque, int level)
+static void pic_irq_request(struct kvm *kvm, int level)
 {
-	struct kvm *kvm = opaque;
 	struct kvm_vcpu *vcpu = kvm->bsp_vcpu;
 	struct kvm_pic *s = pic_irqchip(kvm);
 	int irq = pic_get_irq(&s->pics[0]);
@@ -549,8 +565,6 @@
 	s->kvm = kvm;
 	s->pics[0].elcr_mask = 0xf8;
 	s->pics[1].elcr_mask = 0xde;
-	s->irq_request = pic_irq_request;
-	s->irq_request_opaque = kvm;
 	s->pics[0].pics_state = s;
 	s->pics[1].pics_state = s;
 
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index 96dfbb6..2095a04 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -1,6 +1,7 @@
 /*
  * irq.c: API for in kernel interrupt controller
  * Copyright (c) 2007, Intel Corporation.
+ * Copyright 2009 Red Hat, Inc. and/or its affilates.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -89,7 +90,6 @@
 void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
 {
 	kvm_inject_apic_timer_irqs(vcpu);
-	kvm_inject_pit_timer_irqs(vcpu);
 	/* TODO: PIT, RTC etc. */
 }
 EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index cd1f362..ffed068 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -38,8 +38,6 @@
 struct kvm;
 struct kvm_vcpu;
 
-typedef void irq_request_func(void *opaque, int level);
-
 struct kvm_kpic_state {
 	u8 last_irr;	/* edge detection */
 	u8 irr;		/* interrupt request register */
@@ -67,8 +65,6 @@
 	unsigned pending_acks;
 	struct kvm *kvm;
 	struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */
-	irq_request_func *irq_request;
-	void *irq_request_opaque;
 	int output;		/* intr from master PIC */
 	struct kvm_io_device dev;
 	void (*ack_notifier)(void *opaque, int irq);
diff --git a/arch/x86/kvm/kvm_cache_regs.h b/arch/x86/kvm/kvm_cache_regs.h
index cff851c..6491ac8 100644
--- a/arch/x86/kvm/kvm_cache_regs.h
+++ b/arch/x86/kvm/kvm_cache_regs.h
@@ -36,6 +36,8 @@
 
 static inline u64 kvm_pdptr_read(struct kvm_vcpu *vcpu, int index)
 {
+	might_sleep();  /* on svm */
+
 	if (!test_bit(VCPU_EXREG_PDPTR,
 		      (unsigned long *)&vcpu->arch.regs_avail))
 		kvm_x86_ops->cache_reg(vcpu, VCPU_EXREG_PDPTR);
@@ -69,4 +71,10 @@
 	return kvm_read_cr4_bits(vcpu, ~0UL);
 }
 
+static inline u64 kvm_read_edx_eax(struct kvm_vcpu *vcpu)
+{
+	return (kvm_register_read(vcpu, VCPU_REGS_RAX) & -1u)
+		| ((u64)(kvm_register_read(vcpu, VCPU_REGS_RDX) & -1u) << 32);
+}
+
 #endif
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 1eb7a4a..77d8c0f 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2006 Qumranet, Inc.
  * Copyright (C) 2007 Novell
  * Copyright (C) 2007 Intel
+ * Copyright 2009 Red Hat, Inc. and/or its affilates.
  *
  * Authors:
  *   Dor Laor <dor.laor@qumranet.com>
@@ -328,7 +329,7 @@
 		   "dest_mode 0x%x, short_hand 0x%x\n",
 		   target, source, dest, dest_mode, short_hand);
 
-	ASSERT(!target);
+	ASSERT(target);
 	switch (short_hand) {
 	case APIC_DEST_NOSHORT:
 		if (dest_mode == 0)
@@ -533,7 +534,7 @@
 	struct kvm_vcpu *vcpu = apic->vcpu;
 	struct kvm_run *run = vcpu->run;
 
-	set_bit(KVM_REQ_REPORT_TPR_ACCESS, &vcpu->requests);
+	kvm_make_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu);
 	run->tpr_access.rip = kvm_rip_read(vcpu);
 	run->tpr_access.is_write = write;
 }
@@ -1106,13 +1107,11 @@
 	u32 lvt0 = apic_get_reg(vcpu->arch.apic, APIC_LVT0);
 	int r = 0;
 
-	if (kvm_vcpu_is_bsp(vcpu)) {
-		if (!apic_hw_enabled(vcpu->arch.apic))
-			r = 1;
-		if ((lvt0 & APIC_LVT_MASKED) == 0 &&
-		    GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
-			r = 1;
-	}
+	if (!apic_hw_enabled(vcpu->arch.apic))
+		r = 1;
+	if ((lvt0 & APIC_LVT_MASKED) == 0 &&
+	    GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
+		r = 1;
 	return r;
 }
 
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index b1ed0a1..0dcc95e 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -7,6 +7,7 @@
  * MMU support
  *
  * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
  *
  * Authors:
  *   Yaniv Kamay  <yaniv@qumranet.com>
@@ -32,6 +33,7 @@
 #include <linux/compiler.h>
 #include <linux/srcu.h>
 #include <linux/slab.h>
+#include <linux/uaccess.h>
 
 #include <asm/page.h>
 #include <asm/cmpxchg.h>
@@ -90,8 +92,6 @@
 #define PT_FIRST_AVAIL_BITS_SHIFT 9
 #define PT64_SECOND_AVAIL_BITS_SHIFT 52
 
-#define VALID_PAGE(x) ((x) != INVALID_PAGE)
-
 #define PT64_LEVEL_BITS 9
 
 #define PT64_LEVEL_SHIFT(level) \
@@ -173,7 +173,7 @@
 	     shadow_walk_okay(&(_walker));			\
 	     shadow_walk_next(&(_walker)))
 
-typedef int (*mmu_parent_walk_fn) (struct kvm_mmu_page *sp);
+typedef void (*mmu_parent_walk_fn) (struct kvm_mmu_page *sp, u64 *spte);
 
 static struct kmem_cache *pte_chain_cache;
 static struct kmem_cache *rmap_desc_cache;
@@ -288,6 +288,35 @@
 #endif
 }
 
+static u64 __xchg_spte(u64 *sptep, u64 new_spte)
+{
+#ifdef CONFIG_X86_64
+	return xchg(sptep, new_spte);
+#else
+	u64 old_spte;
+
+	do {
+		old_spte = *sptep;
+	} while (cmpxchg64(sptep, old_spte, new_spte) != old_spte);
+
+	return old_spte;
+#endif
+}
+
+static void update_spte(u64 *sptep, u64 new_spte)
+{
+	u64 old_spte;
+
+	if (!shadow_accessed_mask || (new_spte & shadow_accessed_mask) ||
+	      !is_rmap_spte(*sptep))
+		__set_spte(sptep, new_spte);
+	else {
+		old_spte = __xchg_spte(sptep, new_spte);
+		if (old_spte & shadow_accessed_mask)
+			mark_page_accessed(pfn_to_page(spte_to_pfn(old_spte)));
+	}
+}
+
 static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
 				  struct kmem_cache *base_cache, int min)
 {
@@ -304,10 +333,11 @@
 	return 0;
 }
 
-static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
+static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc,
+				  struct kmem_cache *cache)
 {
 	while (mc->nobjs)
-		kfree(mc->objects[--mc->nobjs]);
+		kmem_cache_free(cache, mc->objects[--mc->nobjs]);
 }
 
 static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
@@ -355,10 +385,11 @@
 
 static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
 {
-	mmu_free_memory_cache(&vcpu->arch.mmu_pte_chain_cache);
-	mmu_free_memory_cache(&vcpu->arch.mmu_rmap_desc_cache);
+	mmu_free_memory_cache(&vcpu->arch.mmu_pte_chain_cache, pte_chain_cache);
+	mmu_free_memory_cache(&vcpu->arch.mmu_rmap_desc_cache, rmap_desc_cache);
 	mmu_free_memory_cache_page(&vcpu->arch.mmu_page_cache);
-	mmu_free_memory_cache(&vcpu->arch.mmu_page_header_cache);
+	mmu_free_memory_cache(&vcpu->arch.mmu_page_header_cache,
+				mmu_page_header_cache);
 }
 
 static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc,
@@ -379,7 +410,7 @@
 
 static void mmu_free_pte_chain(struct kvm_pte_chain *pc)
 {
-	kfree(pc);
+	kmem_cache_free(pte_chain_cache, pc);
 }
 
 static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
@@ -390,7 +421,23 @@
 
 static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd)
 {
-	kfree(rd);
+	kmem_cache_free(rmap_desc_cache, rd);
+}
+
+static gfn_t kvm_mmu_page_get_gfn(struct kvm_mmu_page *sp, int index)
+{
+	if (!sp->role.direct)
+		return sp->gfns[index];
+
+	return sp->gfn + (index << ((sp->role.level - 1) * PT64_LEVEL_BITS));
+}
+
+static void kvm_mmu_page_set_gfn(struct kvm_mmu_page *sp, int index, gfn_t gfn)
+{
+	if (sp->role.direct)
+		BUG_ON(gfn != kvm_mmu_page_get_gfn(sp, index));
+	else
+		sp->gfns[index] = gfn;
 }
 
 /*
@@ -403,8 +450,8 @@
 {
 	unsigned long idx;
 
-	idx = (gfn / KVM_PAGES_PER_HPAGE(level)) -
-	      (slot->base_gfn / KVM_PAGES_PER_HPAGE(level));
+	idx = (gfn >> KVM_HPAGE_GFN_SHIFT(level)) -
+	      (slot->base_gfn >> KVM_HPAGE_GFN_SHIFT(level));
 	return &slot->lpage_info[level - 2][idx].write_count;
 }
 
@@ -414,9 +461,7 @@
 	int *write_count;
 	int i;
 
-	gfn = unalias_gfn(kvm, gfn);
-
-	slot = gfn_to_memslot_unaliased(kvm, gfn);
+	slot = gfn_to_memslot(kvm, gfn);
 	for (i = PT_DIRECTORY_LEVEL;
 	     i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
 		write_count   = slot_largepage_idx(gfn, slot, i);
@@ -430,8 +475,7 @@
 	int *write_count;
 	int i;
 
-	gfn = unalias_gfn(kvm, gfn);
-	slot = gfn_to_memslot_unaliased(kvm, gfn);
+	slot = gfn_to_memslot(kvm, gfn);
 	for (i = PT_DIRECTORY_LEVEL;
 	     i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
 		write_count   = slot_largepage_idx(gfn, slot, i);
@@ -447,8 +491,7 @@
 	struct kvm_memory_slot *slot;
 	int *largepage_idx;
 
-	gfn = unalias_gfn(kvm, gfn);
-	slot = gfn_to_memslot_unaliased(kvm, gfn);
+	slot = gfn_to_memslot(kvm, gfn);
 	if (slot) {
 		largepage_idx = slot_largepage_idx(gfn, slot, level);
 		return *largepage_idx;
@@ -501,7 +544,6 @@
 
 /*
  * Take gfn and return the reverse mapping to it.
- * Note: gfn must be unaliased before this function get called
  */
 
 static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int level)
@@ -513,8 +555,8 @@
 	if (likely(level == PT_PAGE_TABLE_LEVEL))
 		return &slot->rmap[gfn - slot->base_gfn];
 
-	idx = (gfn / KVM_PAGES_PER_HPAGE(level)) -
-		(slot->base_gfn / KVM_PAGES_PER_HPAGE(level));
+	idx = (gfn >> KVM_HPAGE_GFN_SHIFT(level)) -
+		(slot->base_gfn >> KVM_HPAGE_GFN_SHIFT(level));
 
 	return &slot->lpage_info[level - 2][idx].rmap_pde;
 }
@@ -541,9 +583,8 @@
 
 	if (!is_rmap_spte(*spte))
 		return count;
-	gfn = unalias_gfn(vcpu->kvm, gfn);
 	sp = page_header(__pa(spte));
-	sp->gfns[spte - sp->spt] = gfn;
+	kvm_mmu_page_set_gfn(sp, spte - sp->spt, gfn);
 	rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level);
 	if (!*rmapp) {
 		rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte);
@@ -600,19 +641,13 @@
 	struct kvm_rmap_desc *desc;
 	struct kvm_rmap_desc *prev_desc;
 	struct kvm_mmu_page *sp;
-	pfn_t pfn;
+	gfn_t gfn;
 	unsigned long *rmapp;
 	int i;
 
-	if (!is_rmap_spte(*spte))
-		return;
 	sp = page_header(__pa(spte));
-	pfn = spte_to_pfn(*spte);
-	if (*spte & shadow_accessed_mask)
-		kvm_set_pfn_accessed(pfn);
-	if (is_writable_pte(*spte))
-		kvm_set_pfn_dirty(pfn);
-	rmapp = gfn_to_rmap(kvm, sp->gfns[spte - sp->spt], sp->role.level);
+	gfn = kvm_mmu_page_get_gfn(sp, spte - sp->spt);
+	rmapp = gfn_to_rmap(kvm, gfn, sp->role.level);
 	if (!*rmapp) {
 		printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte);
 		BUG();
@@ -644,6 +679,32 @@
 	}
 }
 
+static void set_spte_track_bits(u64 *sptep, u64 new_spte)
+{
+	pfn_t pfn;
+	u64 old_spte = *sptep;
+
+	if (!shadow_accessed_mask || !is_shadow_present_pte(old_spte) ||
+	      old_spte & shadow_accessed_mask) {
+		__set_spte(sptep, new_spte);
+	} else
+		old_spte = __xchg_spte(sptep, new_spte);
+
+	if (!is_rmap_spte(old_spte))
+		return;
+	pfn = spte_to_pfn(old_spte);
+	if (!shadow_accessed_mask || old_spte & shadow_accessed_mask)
+		kvm_set_pfn_accessed(pfn);
+	if (is_writable_pte(old_spte))
+		kvm_set_pfn_dirty(pfn);
+}
+
+static void drop_spte(struct kvm *kvm, u64 *sptep, u64 new_spte)
+{
+	set_spte_track_bits(sptep, new_spte);
+	rmap_remove(kvm, sptep);
+}
+
 static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte)
 {
 	struct kvm_rmap_desc *desc;
@@ -676,7 +737,6 @@
 	u64 *spte;
 	int i, write_protected = 0;
 
-	gfn = unalias_gfn(kvm, gfn);
 	rmapp = gfn_to_rmap(kvm, gfn, PT_PAGE_TABLE_LEVEL);
 
 	spte = rmap_next(kvm, rmapp, NULL);
@@ -685,7 +745,7 @@
 		BUG_ON(!(*spte & PT_PRESENT_MASK));
 		rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
 		if (is_writable_pte(*spte)) {
-			__set_spte(spte, *spte & ~PT_WRITABLE_MASK);
+			update_spte(spte, *spte & ~PT_WRITABLE_MASK);
 			write_protected = 1;
 		}
 		spte = rmap_next(kvm, rmapp, spte);
@@ -709,9 +769,9 @@
 			BUG_ON((*spte & (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)) != (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK));
 			pgprintk("rmap_write_protect(large): spte %p %llx %lld\n", spte, *spte, gfn);
 			if (is_writable_pte(*spte)) {
-				rmap_remove(kvm, spte);
+				drop_spte(kvm, spte,
+					  shadow_trap_nonpresent_pte);
 				--kvm->stat.lpages;
-				__set_spte(spte, shadow_trap_nonpresent_pte);
 				spte = NULL;
 				write_protected = 1;
 			}
@@ -731,8 +791,7 @@
 	while ((spte = rmap_next(kvm, rmapp, NULL))) {
 		BUG_ON(!(*spte & PT_PRESENT_MASK));
 		rmap_printk("kvm_rmap_unmap_hva: spte %p %llx\n", spte, *spte);
-		rmap_remove(kvm, spte);
-		__set_spte(spte, shadow_trap_nonpresent_pte);
+		drop_spte(kvm, spte, shadow_trap_nonpresent_pte);
 		need_tlb_flush = 1;
 	}
 	return need_tlb_flush;
@@ -754,8 +813,7 @@
 		rmap_printk("kvm_set_pte_rmapp: spte %p %llx\n", spte, *spte);
 		need_flush = 1;
 		if (pte_write(*ptep)) {
-			rmap_remove(kvm, spte);
-			__set_spte(spte, shadow_trap_nonpresent_pte);
+			drop_spte(kvm, spte, shadow_trap_nonpresent_pte);
 			spte = rmap_next(kvm, rmapp, NULL);
 		} else {
 			new_spte = *spte &~ (PT64_BASE_ADDR_MASK);
@@ -763,9 +821,8 @@
 
 			new_spte &= ~PT_WRITABLE_MASK;
 			new_spte &= ~SPTE_HOST_WRITEABLE;
-			if (is_writable_pte(*spte))
-				kvm_set_pfn_dirty(spte_to_pfn(*spte));
-			__set_spte(spte, new_spte);
+			new_spte &= ~shadow_accessed_mask;
+			set_spte_track_bits(spte, new_spte);
 			spte = rmap_next(kvm, rmapp, spte);
 		}
 	}
@@ -799,8 +856,12 @@
 			ret = handler(kvm, &memslot->rmap[gfn_offset], data);
 
 			for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) {
-				int idx = gfn_offset;
-				idx /= KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL + j);
+				unsigned long idx;
+				int sh;
+
+				sh = KVM_HPAGE_GFN_SHIFT(PT_DIRECTORY_LEVEL+j);
+				idx = ((memslot->base_gfn+gfn_offset) >> sh) -
+					(memslot->base_gfn >> sh);
 				ret |= handler(kvm,
 					&memslot->lpage_info[j][idx].rmap_pde,
 					data);
@@ -863,7 +924,6 @@
 
 	sp = page_header(__pa(spte));
 
-	gfn = unalias_gfn(vcpu->kvm, gfn);
 	rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level);
 
 	kvm_unmap_rmapp(vcpu->kvm, rmapp, 0);
@@ -894,10 +954,12 @@
 static void kvm_mmu_free_page(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
 	ASSERT(is_empty_shadow_page(sp->spt));
+	hlist_del(&sp->hash_link);
 	list_del(&sp->link);
 	__free_page(virt_to_page(sp->spt));
-	__free_page(virt_to_page(sp->gfns));
-	kfree(sp);
+	if (!sp->role.direct)
+		__free_page(virt_to_page(sp->gfns));
+	kmem_cache_free(mmu_page_header_cache, sp);
 	++kvm->arch.n_free_mmu_pages;
 }
 
@@ -907,13 +969,15 @@
 }
 
 static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
-					       u64 *parent_pte)
+					       u64 *parent_pte, int direct)
 {
 	struct kvm_mmu_page *sp;
 
 	sp = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_header_cache, sizeof *sp);
 	sp->spt = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache, PAGE_SIZE);
-	sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache, PAGE_SIZE);
+	if (!direct)
+		sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache,
+						  PAGE_SIZE);
 	set_page_private(virt_to_page(sp->spt), (unsigned long)sp);
 	list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages);
 	bitmap_zero(sp->slot_bitmap, KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS);
@@ -998,7 +1062,6 @@
 	BUG();
 }
 
-
 static void mmu_parent_walk(struct kvm_mmu_page *sp, mmu_parent_walk_fn fn)
 {
 	struct kvm_pte_chain *pte_chain;
@@ -1008,63 +1071,37 @@
 
 	if (!sp->multimapped && sp->parent_pte) {
 		parent_sp = page_header(__pa(sp->parent_pte));
-		fn(parent_sp);
-		mmu_parent_walk(parent_sp, fn);
-		return;
-	}
-	hlist_for_each_entry(pte_chain, node, &sp->parent_ptes, link)
-		for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) {
-			if (!pte_chain->parent_ptes[i])
-				break;
-			parent_sp = page_header(__pa(pte_chain->parent_ptes[i]));
-			fn(parent_sp);
-			mmu_parent_walk(parent_sp, fn);
-		}
-}
-
-static void kvm_mmu_update_unsync_bitmap(u64 *spte)
-{
-	unsigned int index;
-	struct kvm_mmu_page *sp = page_header(__pa(spte));
-
-	index = spte - sp->spt;
-	if (!__test_and_set_bit(index, sp->unsync_child_bitmap))
-		sp->unsync_children++;
-	WARN_ON(!sp->unsync_children);
-}
-
-static void kvm_mmu_update_parents_unsync(struct kvm_mmu_page *sp)
-{
-	struct kvm_pte_chain *pte_chain;
-	struct hlist_node *node;
-	int i;
-
-	if (!sp->parent_pte)
-		return;
-
-	if (!sp->multimapped) {
-		kvm_mmu_update_unsync_bitmap(sp->parent_pte);
+		fn(parent_sp, sp->parent_pte);
 		return;
 	}
 
 	hlist_for_each_entry(pte_chain, node, &sp->parent_ptes, link)
 		for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) {
-			if (!pte_chain->parent_ptes[i])
+			u64 *spte = pte_chain->parent_ptes[i];
+
+			if (!spte)
 				break;
-			kvm_mmu_update_unsync_bitmap(pte_chain->parent_ptes[i]);
+			parent_sp = page_header(__pa(spte));
+			fn(parent_sp, spte);
 		}
 }
 
-static int unsync_walk_fn(struct kvm_mmu_page *sp)
-{
-	kvm_mmu_update_parents_unsync(sp);
-	return 1;
-}
-
+static void mark_unsync(struct kvm_mmu_page *sp, u64 *spte);
 static void kvm_mmu_mark_parents_unsync(struct kvm_mmu_page *sp)
 {
-	mmu_parent_walk(sp, unsync_walk_fn);
-	kvm_mmu_update_parents_unsync(sp);
+	mmu_parent_walk(sp, mark_unsync);
+}
+
+static void mark_unsync(struct kvm_mmu_page *sp, u64 *spte)
+{
+	unsigned int index;
+
+	index = spte - sp->spt;
+	if (__test_and_set_bit(index, sp->unsync_child_bitmap))
+		return;
+	if (sp->unsync_children++)
+		return;
+	kvm_mmu_mark_parents_unsync(sp);
 }
 
 static void nonpaging_prefetch_page(struct kvm_vcpu *vcpu,
@@ -1077,7 +1114,7 @@
 }
 
 static int nonpaging_sync_page(struct kvm_vcpu *vcpu,
-			       struct kvm_mmu_page *sp)
+			       struct kvm_mmu_page *sp, bool clear_unsync)
 {
 	return 1;
 }
@@ -1123,35 +1160,40 @@
 	int i, ret, nr_unsync_leaf = 0;
 
 	for_each_unsync_children(sp->unsync_child_bitmap, i) {
+		struct kvm_mmu_page *child;
 		u64 ent = sp->spt[i];
 
-		if (is_shadow_present_pte(ent) && !is_large_pte(ent)) {
-			struct kvm_mmu_page *child;
-			child = page_header(ent & PT64_BASE_ADDR_MASK);
+		if (!is_shadow_present_pte(ent) || is_large_pte(ent))
+			goto clear_child_bitmap;
 
-			if (child->unsync_children) {
-				if (mmu_pages_add(pvec, child, i))
-					return -ENOSPC;
+		child = page_header(ent & PT64_BASE_ADDR_MASK);
 
-				ret = __mmu_unsync_walk(child, pvec);
-				if (!ret)
-					__clear_bit(i, sp->unsync_child_bitmap);
-				else if (ret > 0)
-					nr_unsync_leaf += ret;
-				else
-					return ret;
-			}
+		if (child->unsync_children) {
+			if (mmu_pages_add(pvec, child, i))
+				return -ENOSPC;
 
-			if (child->unsync) {
-				nr_unsync_leaf++;
-				if (mmu_pages_add(pvec, child, i))
-					return -ENOSPC;
-			}
-		}
+			ret = __mmu_unsync_walk(child, pvec);
+			if (!ret)
+				goto clear_child_bitmap;
+			else if (ret > 0)
+				nr_unsync_leaf += ret;
+			else
+				return ret;
+		} else if (child->unsync) {
+			nr_unsync_leaf++;
+			if (mmu_pages_add(pvec, child, i))
+				return -ENOSPC;
+		} else
+			 goto clear_child_bitmap;
+
+		continue;
+
+clear_child_bitmap:
+		__clear_bit(i, sp->unsync_child_bitmap);
+		sp->unsync_children--;
+		WARN_ON((int)sp->unsync_children < 0);
 	}
 
-	if (find_first_bit(sp->unsync_child_bitmap, 512) == 512)
-		sp->unsync_children = 0;
 
 	return nr_unsync_leaf;
 }
@@ -1166,26 +1208,6 @@
 	return __mmu_unsync_walk(sp, pvec);
 }
 
-static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm *kvm, gfn_t gfn)
-{
-	unsigned index;
-	struct hlist_head *bucket;
-	struct kvm_mmu_page *sp;
-	struct hlist_node *node;
-
-	pgprintk("%s: looking for gfn %lx\n", __func__, gfn);
-	index = kvm_page_table_hashfn(gfn);
-	bucket = &kvm->arch.mmu_page_hash[index];
-	hlist_for_each_entry(sp, node, bucket, hash_link)
-		if (sp->gfn == gfn && !sp->role.direct
-		    && !sp->role.invalid) {
-			pgprintk("%s: found role %x\n",
-				 __func__, sp->role.word);
-			return sp;
-		}
-	return NULL;
-}
-
 static void kvm_unlink_unsync_page(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
 	WARN_ON(!sp->unsync);
@@ -1194,20 +1216,36 @@
 	--kvm->stat.mmu_unsync;
 }
 
-static int kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp);
+static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
+				    struct list_head *invalid_list);
+static void kvm_mmu_commit_zap_page(struct kvm *kvm,
+				    struct list_head *invalid_list);
 
-static int kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
+#define for_each_gfn_sp(kvm, sp, gfn, pos)				\
+  hlist_for_each_entry(sp, pos,						\
+   &(kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)], hash_link)	\
+	if ((sp)->gfn != (gfn)) {} else
+
+#define for_each_gfn_indirect_valid_sp(kvm, sp, gfn, pos)		\
+  hlist_for_each_entry(sp, pos,						\
+   &(kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)], hash_link)	\
+		if ((sp)->gfn != (gfn) || (sp)->role.direct ||		\
+			(sp)->role.invalid) {} else
+
+/* @sp->gfn should be write-protected at the call site */
+static int __kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
+			   struct list_head *invalid_list, bool clear_unsync)
 {
 	if (sp->role.cr4_pae != !!is_pae(vcpu)) {
-		kvm_mmu_zap_page(vcpu->kvm, sp);
+		kvm_mmu_prepare_zap_page(vcpu->kvm, sp, invalid_list);
 		return 1;
 	}
 
-	if (rmap_write_protect(vcpu->kvm, sp->gfn))
-		kvm_flush_remote_tlbs(vcpu->kvm);
-	kvm_unlink_unsync_page(vcpu->kvm, sp);
-	if (vcpu->arch.mmu.sync_page(vcpu, sp)) {
-		kvm_mmu_zap_page(vcpu->kvm, sp);
+	if (clear_unsync)
+		kvm_unlink_unsync_page(vcpu->kvm, sp);
+
+	if (vcpu->arch.mmu.sync_page(vcpu, sp, clear_unsync)) {
+		kvm_mmu_prepare_zap_page(vcpu->kvm, sp, invalid_list);
 		return 1;
 	}
 
@@ -1215,6 +1253,52 @@
 	return 0;
 }
 
+static int kvm_sync_page_transient(struct kvm_vcpu *vcpu,
+				   struct kvm_mmu_page *sp)
+{
+	LIST_HEAD(invalid_list);
+	int ret;
+
+	ret = __kvm_sync_page(vcpu, sp, &invalid_list, false);
+	if (ret)
+		kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
+
+	return ret;
+}
+
+static int kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
+			 struct list_head *invalid_list)
+{
+	return __kvm_sync_page(vcpu, sp, invalid_list, true);
+}
+
+/* @gfn should be write-protected at the call site */
+static void kvm_sync_pages(struct kvm_vcpu *vcpu,  gfn_t gfn)
+{
+	struct kvm_mmu_page *s;
+	struct hlist_node *node;
+	LIST_HEAD(invalid_list);
+	bool flush = false;
+
+	for_each_gfn_indirect_valid_sp(vcpu->kvm, s, gfn, node) {
+		if (!s->unsync)
+			continue;
+
+		WARN_ON(s->role.level != PT_PAGE_TABLE_LEVEL);
+		if ((s->role.cr4_pae != !!is_pae(vcpu)) ||
+			(vcpu->arch.mmu.sync_page(vcpu, s, true))) {
+			kvm_mmu_prepare_zap_page(vcpu->kvm, s, &invalid_list);
+			continue;
+		}
+		kvm_unlink_unsync_page(vcpu->kvm, s);
+		flush = true;
+	}
+
+	kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
+	if (flush)
+		kvm_mmu_flush_tlb(vcpu);
+}
+
 struct mmu_page_path {
 	struct kvm_mmu_page *parent[PT64_ROOT_LEVEL-1];
 	unsigned int idx[PT64_ROOT_LEVEL-1];
@@ -1281,6 +1365,7 @@
 	struct kvm_mmu_page *sp;
 	struct mmu_page_path parents;
 	struct kvm_mmu_pages pages;
+	LIST_HEAD(invalid_list);
 
 	kvm_mmu_pages_init(parent, &parents, &pages);
 	while (mmu_unsync_walk(parent, &pages)) {
@@ -1293,9 +1378,10 @@
 			kvm_flush_remote_tlbs(vcpu->kvm);
 
 		for_each_sp(pages, sp, parents, i) {
-			kvm_sync_page(vcpu, sp);
+			kvm_sync_page(vcpu, sp, &invalid_list);
 			mmu_pages_clear_parents(&parents);
 		}
+		kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
 		cond_resched_lock(&vcpu->kvm->mmu_lock);
 		kvm_mmu_pages_init(parent, &parents, &pages);
 	}
@@ -1310,11 +1396,10 @@
 					     u64 *parent_pte)
 {
 	union kvm_mmu_page_role role;
-	unsigned index;
 	unsigned quadrant;
-	struct hlist_head *bucket;
 	struct kvm_mmu_page *sp;
-	struct hlist_node *node, *tmp;
+	struct hlist_node *node;
+	bool need_sync = false;
 
 	role = vcpu->arch.mmu.base_role;
 	role.level = level;
@@ -1322,40 +1407,45 @@
 	if (role.direct)
 		role.cr4_pae = 0;
 	role.access = access;
-	if (vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) {
+	if (!tdp_enabled && vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) {
 		quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level));
 		quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
 		role.quadrant = quadrant;
 	}
-	index = kvm_page_table_hashfn(gfn);
-	bucket = &vcpu->kvm->arch.mmu_page_hash[index];
-	hlist_for_each_entry_safe(sp, node, tmp, bucket, hash_link)
-		if (sp->gfn == gfn) {
-			if (sp->unsync)
-				if (kvm_sync_page(vcpu, sp))
-					continue;
+	for_each_gfn_sp(vcpu->kvm, sp, gfn, node) {
+		if (!need_sync && sp->unsync)
+			need_sync = true;
 
-			if (sp->role.word != role.word)
-				continue;
+		if (sp->role.word != role.word)
+			continue;
 
-			mmu_page_add_parent_pte(vcpu, sp, parent_pte);
-			if (sp->unsync_children) {
-				set_bit(KVM_REQ_MMU_SYNC, &vcpu->requests);
-				kvm_mmu_mark_parents_unsync(sp);
-			}
-			trace_kvm_mmu_get_page(sp, false);
-			return sp;
-		}
+		if (sp->unsync && kvm_sync_page_transient(vcpu, sp))
+			break;
+
+		mmu_page_add_parent_pte(vcpu, sp, parent_pte);
+		if (sp->unsync_children) {
+			kvm_make_request(KVM_REQ_MMU_SYNC, vcpu);
+			kvm_mmu_mark_parents_unsync(sp);
+		} else if (sp->unsync)
+			kvm_mmu_mark_parents_unsync(sp);
+
+		trace_kvm_mmu_get_page(sp, false);
+		return sp;
+	}
 	++vcpu->kvm->stat.mmu_cache_miss;
-	sp = kvm_mmu_alloc_page(vcpu, parent_pte);
+	sp = kvm_mmu_alloc_page(vcpu, parent_pte, direct);
 	if (!sp)
 		return sp;
 	sp->gfn = gfn;
 	sp->role = role;
-	hlist_add_head(&sp->hash_link, bucket);
+	hlist_add_head(&sp->hash_link,
+		&vcpu->kvm->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)]);
 	if (!direct) {
 		if (rmap_write_protect(vcpu->kvm, gfn))
 			kvm_flush_remote_tlbs(vcpu->kvm);
+		if (level > PT_PAGE_TABLE_LEVEL && need_sync)
+			kvm_sync_pages(vcpu, gfn);
+
 		account_shadowed(vcpu->kvm, gfn);
 	}
 	if (shadow_trap_nonpresent_pte != shadow_notrap_nonpresent_pte)
@@ -1402,6 +1492,47 @@
 	--iterator->level;
 }
 
+static void link_shadow_page(u64 *sptep, struct kvm_mmu_page *sp)
+{
+	u64 spte;
+
+	spte = __pa(sp->spt)
+		| PT_PRESENT_MASK | PT_ACCESSED_MASK
+		| PT_WRITABLE_MASK | PT_USER_MASK;
+	__set_spte(sptep, spte);
+}
+
+static void drop_large_spte(struct kvm_vcpu *vcpu, u64 *sptep)
+{
+	if (is_large_pte(*sptep)) {
+		drop_spte(vcpu->kvm, sptep, shadow_trap_nonpresent_pte);
+		kvm_flush_remote_tlbs(vcpu->kvm);
+	}
+}
+
+static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep,
+				   unsigned direct_access)
+{
+	if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep)) {
+		struct kvm_mmu_page *child;
+
+		/*
+		 * For the direct sp, if the guest pte's dirty bit
+		 * changed form clean to dirty, it will corrupt the
+		 * sp's access: allow writable in the read-only sp,
+		 * so we should update the spte at this point to get
+		 * a new sp with the correct access.
+		 */
+		child = page_header(*sptep & PT64_BASE_ADDR_MASK);
+		if (child->role.access == direct_access)
+			return;
+
+		mmu_page_remove_parent_pte(child, sptep);
+		__set_spte(sptep, shadow_trap_nonpresent_pte);
+		kvm_flush_remote_tlbs(vcpu->kvm);
+	}
+}
+
 static void kvm_mmu_page_unlink_children(struct kvm *kvm,
 					 struct kvm_mmu_page *sp)
 {
@@ -1422,7 +1553,8 @@
 			} else {
 				if (is_large_pte(ent))
 					--kvm->stat.lpages;
-				rmap_remove(kvm, &pt[i]);
+				drop_spte(kvm, &pt[i],
+					  shadow_trap_nonpresent_pte);
 			}
 		}
 		pt[i] = shadow_trap_nonpresent_pte;
@@ -1464,7 +1596,8 @@
 }
 
 static int mmu_zap_unsync_children(struct kvm *kvm,
-				   struct kvm_mmu_page *parent)
+				   struct kvm_mmu_page *parent,
+				   struct list_head *invalid_list)
 {
 	int i, zapped = 0;
 	struct mmu_page_path parents;
@@ -1478,7 +1611,7 @@
 		struct kvm_mmu_page *sp;
 
 		for_each_sp(pages, sp, parents, i) {
-			kvm_mmu_zap_page(kvm, sp);
+			kvm_mmu_prepare_zap_page(kvm, sp, invalid_list);
 			mmu_pages_clear_parents(&parents);
 			zapped++;
 		}
@@ -1488,32 +1621,52 @@
 	return zapped;
 }
 
-static int kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp)
+static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
+				    struct list_head *invalid_list)
 {
 	int ret;
 
-	trace_kvm_mmu_zap_page(sp);
+	trace_kvm_mmu_prepare_zap_page(sp);
 	++kvm->stat.mmu_shadow_zapped;
-	ret = mmu_zap_unsync_children(kvm, sp);
+	ret = mmu_zap_unsync_children(kvm, sp, invalid_list);
 	kvm_mmu_page_unlink_children(kvm, sp);
 	kvm_mmu_unlink_parents(kvm, sp);
-	kvm_flush_remote_tlbs(kvm);
 	if (!sp->role.invalid && !sp->role.direct)
 		unaccount_shadowed(kvm, sp->gfn);
 	if (sp->unsync)
 		kvm_unlink_unsync_page(kvm, sp);
 	if (!sp->root_count) {
-		hlist_del(&sp->hash_link);
-		kvm_mmu_free_page(kvm, sp);
+		/* Count self */
+		ret++;
+		list_move(&sp->link, invalid_list);
 	} else {
-		sp->role.invalid = 1;
 		list_move(&sp->link, &kvm->arch.active_mmu_pages);
 		kvm_reload_remote_mmus(kvm);
 	}
+
+	sp->role.invalid = 1;
 	kvm_mmu_reset_last_pte_updated(kvm);
 	return ret;
 }
 
+static void kvm_mmu_commit_zap_page(struct kvm *kvm,
+				    struct list_head *invalid_list)
+{
+	struct kvm_mmu_page *sp;
+
+	if (list_empty(invalid_list))
+		return;
+
+	kvm_flush_remote_tlbs(kvm);
+
+	do {
+		sp = list_first_entry(invalid_list, struct kvm_mmu_page, link);
+		WARN_ON(!sp->role.invalid || sp->root_count);
+		kvm_mmu_free_page(kvm, sp);
+	} while (!list_empty(invalid_list));
+
+}
+
 /*
  * Changing the number of mmu pages allocated to the vm
  * Note: if kvm_nr_mmu_pages is too small, you will get dead lock
@@ -1521,6 +1674,7 @@
 void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages)
 {
 	int used_pages;
+	LIST_HEAD(invalid_list);
 
 	used_pages = kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages;
 	used_pages = max(0, used_pages);
@@ -1538,9 +1692,10 @@
 
 			page = container_of(kvm->arch.active_mmu_pages.prev,
 					    struct kvm_mmu_page, link);
-			used_pages -= kvm_mmu_zap_page(kvm, page);
-			used_pages--;
+			used_pages -= kvm_mmu_prepare_zap_page(kvm, page,
+							       &invalid_list);
 		}
+		kvm_mmu_commit_zap_page(kvm, &invalid_list);
 		kvm_nr_mmu_pages = used_pages;
 		kvm->arch.n_free_mmu_pages = 0;
 	}
@@ -1553,47 +1708,36 @@
 
 static int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
 {
-	unsigned index;
-	struct hlist_head *bucket;
 	struct kvm_mmu_page *sp;
-	struct hlist_node *node, *n;
+	struct hlist_node *node;
+	LIST_HEAD(invalid_list);
 	int r;
 
 	pgprintk("%s: looking for gfn %lx\n", __func__, gfn);
 	r = 0;
-	index = kvm_page_table_hashfn(gfn);
-	bucket = &kvm->arch.mmu_page_hash[index];
-restart:
-	hlist_for_each_entry_safe(sp, node, n, bucket, hash_link)
-		if (sp->gfn == gfn && !sp->role.direct) {
-			pgprintk("%s: gfn %lx role %x\n", __func__, gfn,
-				 sp->role.word);
-			r = 1;
-			if (kvm_mmu_zap_page(kvm, sp))
-				goto restart;
-		}
+
+	for_each_gfn_indirect_valid_sp(kvm, sp, gfn, node) {
+		pgprintk("%s: gfn %lx role %x\n", __func__, gfn,
+			 sp->role.word);
+		r = 1;
+		kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
+	}
+	kvm_mmu_commit_zap_page(kvm, &invalid_list);
 	return r;
 }
 
 static void mmu_unshadow(struct kvm *kvm, gfn_t gfn)
 {
-	unsigned index;
-	struct hlist_head *bucket;
 	struct kvm_mmu_page *sp;
-	struct hlist_node *node, *nn;
+	struct hlist_node *node;
+	LIST_HEAD(invalid_list);
 
-	index = kvm_page_table_hashfn(gfn);
-	bucket = &kvm->arch.mmu_page_hash[index];
-restart:
-	hlist_for_each_entry_safe(sp, node, nn, bucket, hash_link) {
-		if (sp->gfn == gfn && !sp->role.direct
-		    && !sp->role.invalid) {
-			pgprintk("%s: zap %lx %x\n",
-				 __func__, gfn, sp->role.word);
-			if (kvm_mmu_zap_page(kvm, sp))
-				goto restart;
-		}
+	for_each_gfn_indirect_valid_sp(kvm, sp, gfn, node) {
+		pgprintk("%s: zap %lx %x\n",
+			 __func__, gfn, sp->role.word);
+		kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
 	}
+	kvm_mmu_commit_zap_page(kvm, &invalid_list);
 }
 
 static void page_header_update_slot(struct kvm *kvm, void *pte, gfn_t gfn)
@@ -1723,47 +1867,51 @@
 }
 EXPORT_SYMBOL_GPL(kvm_get_guest_memory_type);
 
-static int kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
+static void __kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
 {
-	unsigned index;
-	struct hlist_head *bucket;
-	struct kvm_mmu_page *s;
-	struct hlist_node *node, *n;
-
-	index = kvm_page_table_hashfn(sp->gfn);
-	bucket = &vcpu->kvm->arch.mmu_page_hash[index];
-	/* don't unsync if pagetable is shadowed with multiple roles */
-	hlist_for_each_entry_safe(s, node, n, bucket, hash_link) {
-		if (s->gfn != sp->gfn || s->role.direct)
-			continue;
-		if (s->role.word != sp->role.word)
-			return 1;
-	}
 	trace_kvm_mmu_unsync_page(sp);
 	++vcpu->kvm->stat.mmu_unsync;
 	sp->unsync = 1;
 
 	kvm_mmu_mark_parents_unsync(sp);
-
 	mmu_convert_notrap(sp);
-	return 0;
+}
+
+static void kvm_unsync_pages(struct kvm_vcpu *vcpu,  gfn_t gfn)
+{
+	struct kvm_mmu_page *s;
+	struct hlist_node *node;
+
+	for_each_gfn_indirect_valid_sp(vcpu->kvm, s, gfn, node) {
+		if (s->unsync)
+			continue;
+		WARN_ON(s->role.level != PT_PAGE_TABLE_LEVEL);
+		__kvm_unsync_page(vcpu, s);
+	}
 }
 
 static int mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
 				  bool can_unsync)
 {
-	struct kvm_mmu_page *shadow;
+	struct kvm_mmu_page *s;
+	struct hlist_node *node;
+	bool need_unsync = false;
 
-	shadow = kvm_mmu_lookup_page(vcpu->kvm, gfn);
-	if (shadow) {
-		if (shadow->role.level != PT_PAGE_TABLE_LEVEL)
+	for_each_gfn_indirect_valid_sp(vcpu->kvm, s, gfn, node) {
+		if (!can_unsync)
 			return 1;
-		if (shadow->unsync)
-			return 0;
-		if (can_unsync && oos_shadow)
-			return kvm_unsync_page(vcpu, shadow);
-		return 1;
+
+		if (s->role.level != PT_PAGE_TABLE_LEVEL)
+			return 1;
+
+		if (!need_unsync && !s->unsync) {
+			if (!oos_shadow)
+				return 1;
+			need_unsync = true;
+		}
 	}
+	if (need_unsync)
+		kvm_unsync_pages(vcpu, gfn);
 	return 0;
 }
 
@@ -1804,13 +1952,14 @@
 	spte |= (u64)pfn << PAGE_SHIFT;
 
 	if ((pte_access & ACC_WRITE_MASK)
-	    || (write_fault && !is_write_protection(vcpu) && !user_fault)) {
+	    || (!tdp_enabled && write_fault && !is_write_protection(vcpu)
+		&& !user_fault)) {
 
 		if (level > PT_PAGE_TABLE_LEVEL &&
 		    has_wrprotected_page(vcpu->kvm, gfn, level)) {
 			ret = 1;
-			spte = shadow_trap_nonpresent_pte;
-			goto set_pte;
+			drop_spte(vcpu->kvm, sptep, shadow_trap_nonpresent_pte);
+			goto done;
 		}
 
 		spte |= PT_WRITABLE_MASK;
@@ -1841,7 +1990,10 @@
 		mark_page_dirty(vcpu->kvm, gfn);
 
 set_pte:
-	__set_spte(sptep, spte);
+	if (is_writable_pte(*sptep) && !is_writable_pte(spte))
+		kvm_set_pfn_dirty(pfn);
+	update_spte(sptep, spte);
+done:
 	return ret;
 }
 
@@ -1853,7 +2005,6 @@
 			 bool reset_host_protection)
 {
 	int was_rmapped = 0;
-	int was_writable = is_writable_pte(*sptep);
 	int rmap_count;
 
 	pgprintk("%s: spte %llx access %x write_fault %d"
@@ -1878,8 +2029,7 @@
 		} else if (pfn != spte_to_pfn(*sptep)) {
 			pgprintk("hfn old %lx new %lx\n",
 				 spte_to_pfn(*sptep), pfn);
-			rmap_remove(vcpu->kvm, sptep);
-			__set_spte(sptep, shadow_trap_nonpresent_pte);
+			drop_spte(vcpu->kvm, sptep, shadow_trap_nonpresent_pte);
 			kvm_flush_remote_tlbs(vcpu->kvm);
 		} else
 			was_rmapped = 1;
@@ -1890,7 +2040,7 @@
 		      reset_host_protection)) {
 		if (write_fault)
 			*ptwrite = 1;
-		kvm_x86_ops->tlb_flush(vcpu);
+		kvm_mmu_flush_tlb(vcpu);
 	}
 
 	pgprintk("%s: setting spte %llx\n", __func__, *sptep);
@@ -1904,15 +2054,10 @@
 	page_header_update_slot(vcpu->kvm, sptep, gfn);
 	if (!was_rmapped) {
 		rmap_count = rmap_add(vcpu, sptep, gfn);
-		kvm_release_pfn_clean(pfn);
 		if (rmap_count > RMAP_RECYCLE_THRESHOLD)
 			rmap_recycle(vcpu, sptep, gfn);
-	} else {
-		if (was_writable)
-			kvm_release_pfn_dirty(pfn);
-		else
-			kvm_release_pfn_clean(pfn);
 	}
+	kvm_release_pfn_clean(pfn);
 	if (speculative) {
 		vcpu->arch.last_pte_updated = sptep;
 		vcpu->arch.last_pte_gfn = gfn;
@@ -1941,7 +2086,10 @@
 		}
 
 		if (*iterator.sptep == shadow_trap_nonpresent_pte) {
-			pseudo_gfn = (iterator.addr & PT64_DIR_BASE_ADDR_MASK) >> PAGE_SHIFT;
+			u64 base_addr = iterator.addr;
+
+			base_addr &= PT64_LVL_ADDR_MASK(iterator.level);
+			pseudo_gfn = base_addr >> PAGE_SHIFT;
 			sp = kvm_mmu_get_page(vcpu, pseudo_gfn, iterator.addr,
 					      iterator.level - 1,
 					      1, ACC_ALL, iterator.sptep);
@@ -1960,6 +2108,29 @@
 	return pt_write;
 }
 
+static void kvm_send_hwpoison_signal(struct kvm *kvm, gfn_t gfn)
+{
+	char buf[1];
+	void __user *hva;
+	int r;
+
+	/* Touch the page, so send SIGBUS */
+	hva = (void __user *)gfn_to_hva(kvm, gfn);
+	r = copy_from_user(buf, hva, 1);
+}
+
+static int kvm_handle_bad_page(struct kvm *kvm, gfn_t gfn, pfn_t pfn)
+{
+	kvm_release_pfn_clean(pfn);
+	if (is_hwpoison_pfn(pfn)) {
+		kvm_send_hwpoison_signal(kvm, gfn);
+		return 0;
+	} else if (is_fault_pfn(pfn))
+		return -EFAULT;
+
+	return 1;
+}
+
 static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn)
 {
 	int r;
@@ -1983,10 +2154,8 @@
 	pfn = gfn_to_pfn(vcpu->kvm, gfn);
 
 	/* mmio */
-	if (is_error_pfn(pfn)) {
-		kvm_release_pfn_clean(pfn);
-		return 1;
-	}
+	if (is_error_pfn(pfn))
+		return kvm_handle_bad_page(vcpu->kvm, gfn, pfn);
 
 	spin_lock(&vcpu->kvm->mmu_lock);
 	if (mmu_notifier_retry(vcpu, mmu_seq))
@@ -2009,6 +2178,7 @@
 {
 	int i;
 	struct kvm_mmu_page *sp;
+	LIST_HEAD(invalid_list);
 
 	if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
 		return;
@@ -2018,8 +2188,10 @@
 
 		sp = page_header(root);
 		--sp->root_count;
-		if (!sp->root_count && sp->role.invalid)
-			kvm_mmu_zap_page(vcpu->kvm, sp);
+		if (!sp->root_count && sp->role.invalid) {
+			kvm_mmu_prepare_zap_page(vcpu->kvm, sp, &invalid_list);
+			kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
+		}
 		vcpu->arch.mmu.root_hpa = INVALID_PAGE;
 		spin_unlock(&vcpu->kvm->mmu_lock);
 		return;
@@ -2032,10 +2204,12 @@
 			sp = page_header(root);
 			--sp->root_count;
 			if (!sp->root_count && sp->role.invalid)
-				kvm_mmu_zap_page(vcpu->kvm, sp);
+				kvm_mmu_prepare_zap_page(vcpu->kvm, sp,
+							 &invalid_list);
 		}
 		vcpu->arch.mmu.pae_root[i] = INVALID_PAGE;
 	}
+	kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
 	spin_unlock(&vcpu->kvm->mmu_lock);
 	vcpu->arch.mmu.root_hpa = INVALID_PAGE;
 }
@@ -2045,7 +2219,7 @@
 	int ret = 0;
 
 	if (!kvm_is_visible_gfn(vcpu->kvm, root_gfn)) {
-		set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
+		kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
 		ret = 1;
 	}
 
@@ -2073,6 +2247,7 @@
 			root_gfn = 0;
 		}
 		spin_lock(&vcpu->kvm->mmu_lock);
+		kvm_mmu_free_some_pages(vcpu);
 		sp = kvm_mmu_get_page(vcpu, root_gfn, 0,
 				      PT64_ROOT_LEVEL, direct,
 				      ACC_ALL, NULL);
@@ -2103,6 +2278,7 @@
 			root_gfn = i << 30;
 		}
 		spin_lock(&vcpu->kvm->mmu_lock);
+		kvm_mmu_free_some_pages(vcpu);
 		sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
 				      PT32_ROOT_LEVEL, direct,
 				      ACC_ALL, NULL);
@@ -2198,10 +2374,8 @@
 	mmu_seq = vcpu->kvm->mmu_notifier_seq;
 	smp_rmb();
 	pfn = gfn_to_pfn(vcpu->kvm, gfn);
-	if (is_error_pfn(pfn)) {
-		kvm_release_pfn_clean(pfn);
-		return 1;
-	}
+	if (is_error_pfn(pfn))
+		return kvm_handle_bad_page(vcpu->kvm, gfn, pfn);
 	spin_lock(&vcpu->kvm->mmu_lock);
 	if (mmu_notifier_retry(vcpu, mmu_seq))
 		goto out_unlock;
@@ -2243,7 +2417,7 @@
 void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu)
 {
 	++vcpu->stat.tlb_flush;
-	kvm_x86_ops->tlb_flush(vcpu);
+	kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
 }
 
 static void paging_new_cr3(struct kvm_vcpu *vcpu)
@@ -2457,10 +2631,9 @@
 static void destroy_kvm_mmu(struct kvm_vcpu *vcpu)
 {
 	ASSERT(vcpu);
-	if (VALID_PAGE(vcpu->arch.mmu.root_hpa)) {
+	if (VALID_PAGE(vcpu->arch.mmu.root_hpa))
+		/* mmu.free() should set root_hpa = INVALID_PAGE */
 		vcpu->arch.mmu.free(vcpu);
-		vcpu->arch.mmu.root_hpa = INVALID_PAGE;
-	}
 }
 
 int kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
@@ -2477,9 +2650,6 @@
 	r = mmu_topup_memory_caches(vcpu);
 	if (r)
 		goto out;
-	spin_lock(&vcpu->kvm->mmu_lock);
-	kvm_mmu_free_some_pages(vcpu);
-	spin_unlock(&vcpu->kvm->mmu_lock);
 	r = mmu_alloc_roots(vcpu);
 	spin_lock(&vcpu->kvm->mmu_lock);
 	mmu_sync_roots(vcpu);
@@ -2508,7 +2678,7 @@
 	pte = *spte;
 	if (is_shadow_present_pte(pte)) {
 		if (is_last_spte(pte, sp->role.level))
-			rmap_remove(vcpu->kvm, spte);
+			drop_spte(vcpu->kvm, spte, shadow_trap_nonpresent_pte);
 		else {
 			child = page_header(pte & PT64_BASE_ADDR_MASK);
 			mmu_page_remove_parent_pte(child, spte);
@@ -2529,6 +2699,9 @@
 		return;
         }
 
+	if (is_rsvd_bits_set(vcpu, *(u64 *)new, PT_PAGE_TABLE_LEVEL))
+		return;
+
 	++vcpu->kvm->stat.mmu_pte_updated;
 	if (!sp->role.cr4_pae)
 		paging32_update_pte(vcpu, sp, spte, new);
@@ -2549,11 +2722,15 @@
 	return (old & ~new & PT64_PERM_MASK) != 0;
 }
 
-static void mmu_pte_write_flush_tlb(struct kvm_vcpu *vcpu, u64 old, u64 new)
+static void mmu_pte_write_flush_tlb(struct kvm_vcpu *vcpu, bool zap_page,
+				    bool remote_flush, bool local_flush)
 {
-	if (need_remote_flush(old, new))
+	if (zap_page)
+		return;
+
+	if (remote_flush)
 		kvm_flush_remote_tlbs(vcpu->kvm);
-	else
+	else if (local_flush)
 		kvm_mmu_flush_tlb(vcpu);
 }
 
@@ -2603,10 +2780,10 @@
 		       bool guest_initiated)
 {
 	gfn_t gfn = gpa >> PAGE_SHIFT;
+	union kvm_mmu_page_role mask = { .word = 0 };
 	struct kvm_mmu_page *sp;
-	struct hlist_node *node, *n;
-	struct hlist_head *bucket;
-	unsigned index;
+	struct hlist_node *node;
+	LIST_HEAD(invalid_list);
 	u64 entry, gentry;
 	u64 *spte;
 	unsigned offset = offset_in_page(gpa);
@@ -2619,6 +2796,9 @@
 	int npte;
 	int r;
 	int invlpg_counter;
+	bool remote_flush, local_flush, zap_page;
+
+	zap_page = remote_flush = local_flush = false;
 
 	pgprintk("%s: gpa %llx bytes %d\n", __func__, gpa, bytes);
 
@@ -2674,13 +2854,9 @@
 			vcpu->arch.last_pte_updated = NULL;
 		}
 	}
-	index = kvm_page_table_hashfn(gfn);
-	bucket = &vcpu->kvm->arch.mmu_page_hash[index];
 
-restart:
-	hlist_for_each_entry_safe(sp, node, n, bucket, hash_link) {
-		if (sp->gfn != gfn || sp->role.direct || sp->role.invalid)
-			continue;
+	mask.cr0_wp = mask.cr4_pae = mask.nxe = 1;
+	for_each_gfn_indirect_valid_sp(vcpu->kvm, sp, gfn, node) {
 		pte_size = sp->role.cr4_pae ? 8 : 4;
 		misaligned = (offset ^ (offset + bytes - 1)) & ~(pte_size - 1);
 		misaligned |= bytes < 4;
@@ -2697,8 +2873,8 @@
 			 */
 			pgprintk("misaligned: gpa %llx bytes %d role %x\n",
 				 gpa, bytes, sp->role.word);
-			if (kvm_mmu_zap_page(vcpu->kvm, sp))
-				goto restart;
+			zap_page |= !!kvm_mmu_prepare_zap_page(vcpu->kvm, sp,
+						     &invalid_list);
 			++vcpu->kvm->stat.mmu_flooded;
 			continue;
 		}
@@ -2722,16 +2898,22 @@
 			if (quadrant != sp->role.quadrant)
 				continue;
 		}
+		local_flush = true;
 		spte = &sp->spt[page_offset / sizeof(*spte)];
 		while (npte--) {
 			entry = *spte;
 			mmu_pte_write_zap_pte(vcpu, sp, spte);
-			if (gentry)
+			if (gentry &&
+			      !((sp->role.word ^ vcpu->arch.mmu.base_role.word)
+			      & mask.word))
 				mmu_pte_write_new_pte(vcpu, sp, spte, &gentry);
-			mmu_pte_write_flush_tlb(vcpu, entry, *spte);
+			if (!remote_flush && need_remote_flush(entry, *spte))
+				remote_flush = true;
 			++spte;
 		}
 	}
+	mmu_pte_write_flush_tlb(vcpu, zap_page, remote_flush, local_flush);
+	kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
 	kvm_mmu_audit(vcpu, "post pte write");
 	spin_unlock(&vcpu->kvm->mmu_lock);
 	if (!is_error_pfn(vcpu->arch.update_pte.pfn)) {
@@ -2759,15 +2941,21 @@
 
 void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
 {
-	while (vcpu->kvm->arch.n_free_mmu_pages < KVM_REFILL_PAGES &&
+	int free_pages;
+	LIST_HEAD(invalid_list);
+
+	free_pages = vcpu->kvm->arch.n_free_mmu_pages;
+	while (free_pages < KVM_REFILL_PAGES &&
 	       !list_empty(&vcpu->kvm->arch.active_mmu_pages)) {
 		struct kvm_mmu_page *sp;
 
 		sp = container_of(vcpu->kvm->arch.active_mmu_pages.prev,
 				  struct kvm_mmu_page, link);
-		kvm_mmu_zap_page(vcpu->kvm, sp);
+		free_pages += kvm_mmu_prepare_zap_page(vcpu->kvm, sp,
+						       &invalid_list);
 		++vcpu->kvm->stat.mmu_recycled;
 	}
+	kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
 }
 
 int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code)
@@ -2795,11 +2983,8 @@
 		return 1;
 	case EMULATE_DO_MMIO:
 		++vcpu->stat.mmio_exits;
-		return 0;
+		/* fall through */
 	case EMULATE_FAIL:
-		vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
-		vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
-		vcpu->run->internal.ndata = 0;
 		return 0;
 	default:
 		BUG();
@@ -2896,7 +3081,7 @@
 		pt = sp->spt;
 		for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
 			/* avoid RMW */
-			if (pt[i] & PT_WRITABLE_MASK)
+			if (is_writable_pte(pt[i]))
 				pt[i] &= ~PT_WRITABLE_MASK;
 	}
 	kvm_flush_remote_tlbs(kvm);
@@ -2905,25 +3090,26 @@
 void kvm_mmu_zap_all(struct kvm *kvm)
 {
 	struct kvm_mmu_page *sp, *node;
+	LIST_HEAD(invalid_list);
 
 	spin_lock(&kvm->mmu_lock);
 restart:
 	list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link)
-		if (kvm_mmu_zap_page(kvm, sp))
+		if (kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list))
 			goto restart;
 
+	kvm_mmu_commit_zap_page(kvm, &invalid_list);
 	spin_unlock(&kvm->mmu_lock);
-
-	kvm_flush_remote_tlbs(kvm);
 }
 
-static int kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm)
+static int kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm,
+					       struct list_head *invalid_list)
 {
 	struct kvm_mmu_page *page;
 
 	page = container_of(kvm->arch.active_mmu_pages.prev,
 			    struct kvm_mmu_page, link);
-	return kvm_mmu_zap_page(kvm, page) + 1;
+	return kvm_mmu_prepare_zap_page(kvm, page, invalid_list);
 }
 
 static int mmu_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
@@ -2936,6 +3122,7 @@
 
 	list_for_each_entry(kvm, &vm_list, vm_list) {
 		int npages, idx, freed_pages;
+		LIST_HEAD(invalid_list);
 
 		idx = srcu_read_lock(&kvm->srcu);
 		spin_lock(&kvm->mmu_lock);
@@ -2943,12 +3130,14 @@
 			 kvm->arch.n_free_mmu_pages;
 		cache_count += npages;
 		if (!kvm_freed && nr_to_scan > 0 && npages > 0) {
-			freed_pages = kvm_mmu_remove_some_alloc_mmu_pages(kvm);
+			freed_pages = kvm_mmu_remove_some_alloc_mmu_pages(kvm,
+							  &invalid_list);
 			cache_count -= freed_pages;
 			kvm_freed = kvm;
 		}
 		nr_to_scan--;
 
+		kvm_mmu_commit_zap_page(kvm, &invalid_list);
 		spin_unlock(&kvm->mmu_lock);
 		srcu_read_unlock(&kvm->srcu, idx);
 	}
@@ -3074,7 +3263,7 @@
 
 static int kvm_pv_mmu_flush_tlb(struct kvm_vcpu *vcpu)
 {
-	kvm_set_cr3(vcpu, vcpu->arch.cr3);
+	(void)kvm_set_cr3(vcpu, vcpu->arch.cr3);
 	return 1;
 }
 
@@ -3331,9 +3520,9 @@
 	struct kvm_mmu_page *rev_sp;
 	gfn_t gfn;
 
-	if (*sptep & PT_WRITABLE_MASK) {
+	if (is_writable_pte(*sptep)) {
 		rev_sp = page_header(__pa(sptep));
-		gfn = rev_sp->gfns[sptep - rev_sp->spt];
+		gfn = kvm_mmu_page_get_gfn(rev_sp, sptep - rev_sp->spt);
 
 		if (!gfn_to_memslot(kvm, gfn)) {
 			if (!printk_ratelimit())
@@ -3347,8 +3536,7 @@
 			return;
 		}
 
-		rmapp = gfn_to_rmap(kvm, rev_sp->gfns[sptep - rev_sp->spt],
-				    rev_sp->role.level);
+		rmapp = gfn_to_rmap(kvm, gfn, rev_sp->role.level);
 		if (!*rmapp) {
 			if (!printk_ratelimit())
 				return;
@@ -3381,7 +3569,7 @@
 
 			if (!(ent & PT_PRESENT_MASK))
 				continue;
-			if (!(ent & PT_WRITABLE_MASK))
+			if (!is_writable_pte(ent))
 				continue;
 			inspect_spte_has_rmap(vcpu->kvm, &pt[i]);
 		}
@@ -3409,13 +3597,12 @@
 		if (sp->unsync)
 			continue;
 
-		gfn = unalias_gfn(vcpu->kvm, sp->gfn);
-		slot = gfn_to_memslot_unaliased(vcpu->kvm, sp->gfn);
+		slot = gfn_to_memslot(vcpu->kvm, sp->gfn);
 		rmapp = &slot->rmap[gfn - slot->base_gfn];
 
 		spte = rmap_next(vcpu->kvm, rmapp, NULL);
 		while (spte) {
-			if (*spte & PT_WRITABLE_MASK)
+			if (is_writable_pte(*spte))
 				printk(KERN_ERR "%s: (%s) shadow page has "
 				"writable mappings: gfn %lx role %x\n",
 			       __func__, audit_msg, sp->gfn,
diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
index 42f07b1..3aab0f0 100644
--- a/arch/x86/kvm/mmutrace.h
+++ b/arch/x86/kvm/mmutrace.h
@@ -190,7 +190,7 @@
 	TP_ARGS(sp)
 );
 
-DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_zap_page,
+DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_prepare_zap_page,
 	TP_PROTO(struct kvm_mmu_page *sp),
 
 	TP_ARGS(sp)
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 2331bdc..51ef909 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -7,6 +7,7 @@
  * MMU support
  *
  * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
  *
  * Authors:
  *   Yaniv Kamay  <yaniv@qumranet.com>
@@ -118,21 +119,25 @@
 {
 	pt_element_t pte;
 	gfn_t table_gfn;
-	unsigned index, pt_access, pte_access;
+	unsigned index, pt_access, uninitialized_var(pte_access);
 	gpa_t pte_gpa;
-	int rsvd_fault = 0;
+	bool eperm, present, rsvd_fault;
 
 	trace_kvm_mmu_pagetable_walk(addr, write_fault, user_fault,
 				     fetch_fault);
 walk:
+	present = true;
+	eperm = rsvd_fault = false;
 	walker->level = vcpu->arch.mmu.root_level;
 	pte = vcpu->arch.cr3;
 #if PTTYPE == 64
 	if (!is_long_mode(vcpu)) {
 		pte = kvm_pdptr_read(vcpu, (addr >> 30) & 3);
 		trace_kvm_mmu_paging_element(pte, walker->level);
-		if (!is_present_gpte(pte))
-			goto not_present;
+		if (!is_present_gpte(pte)) {
+			present = false;
+			goto error;
+		}
 		--walker->level;
 	}
 #endif
@@ -150,37 +155,42 @@
 		walker->table_gfn[walker->level - 1] = table_gfn;
 		walker->pte_gpa[walker->level - 1] = pte_gpa;
 
-		if (kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte)))
-			goto not_present;
+		if (kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte))) {
+			present = false;
+			break;
+		}
 
 		trace_kvm_mmu_paging_element(pte, walker->level);
 
-		if (!is_present_gpte(pte))
-			goto not_present;
+		if (!is_present_gpte(pte)) {
+			present = false;
+			break;
+		}
 
-		rsvd_fault = is_rsvd_bits_set(vcpu, pte, walker->level);
-		if (rsvd_fault)
-			goto access_error;
+		if (is_rsvd_bits_set(vcpu, pte, walker->level)) {
+			rsvd_fault = true;
+			break;
+		}
 
 		if (write_fault && !is_writable_pte(pte))
 			if (user_fault || is_write_protection(vcpu))
-				goto access_error;
+				eperm = true;
 
 		if (user_fault && !(pte & PT_USER_MASK))
-			goto access_error;
+			eperm = true;
 
 #if PTTYPE == 64
 		if (fetch_fault && (pte & PT64_NX_MASK))
-			goto access_error;
+			eperm = true;
 #endif
 
-		if (!(pte & PT_ACCESSED_MASK)) {
+		if (!eperm && !rsvd_fault && !(pte & PT_ACCESSED_MASK)) {
 			trace_kvm_mmu_set_accessed_bit(table_gfn, index,
 						       sizeof(pte));
-			mark_page_dirty(vcpu->kvm, table_gfn);
 			if (FNAME(cmpxchg_gpte)(vcpu->kvm, table_gfn,
 			    index, pte, pte|PT_ACCESSED_MASK))
 				goto walk;
+			mark_page_dirty(vcpu->kvm, table_gfn);
 			pte |= PT_ACCESSED_MASK;
 		}
 
@@ -213,15 +223,18 @@
 		--walker->level;
 	}
 
+	if (!present || eperm || rsvd_fault)
+		goto error;
+
 	if (write_fault && !is_dirty_gpte(pte)) {
 		bool ret;
 
 		trace_kvm_mmu_set_dirty_bit(table_gfn, index, sizeof(pte));
-		mark_page_dirty(vcpu->kvm, table_gfn);
 		ret = FNAME(cmpxchg_gpte)(vcpu->kvm, table_gfn, index, pte,
 			    pte|PT_DIRTY_MASK);
 		if (ret)
 			goto walk;
+		mark_page_dirty(vcpu->kvm, table_gfn);
 		pte |= PT_DIRTY_MASK;
 		walker->ptes[walker->level - 1] = pte;
 	}
@@ -229,22 +242,18 @@
 	walker->pt_access = pt_access;
 	walker->pte_access = pte_access;
 	pgprintk("%s: pte %llx pte_access %x pt_access %x\n",
-		 __func__, (u64)pte, pt_access, pte_access);
+		 __func__, (u64)pte, pte_access, pt_access);
 	return 1;
 
-not_present:
+error:
 	walker->error_code = 0;
-	goto err;
-
-access_error:
-	walker->error_code = PFERR_PRESENT_MASK;
-
-err:
+	if (present)
+		walker->error_code |= PFERR_PRESENT_MASK;
 	if (write_fault)
 		walker->error_code |= PFERR_WRITE_MASK;
 	if (user_fault)
 		walker->error_code |= PFERR_USER_MASK;
-	if (fetch_fault)
+	if (fetch_fault && is_nx(vcpu))
 		walker->error_code |= PFERR_FETCH_MASK;
 	if (rsvd_fault)
 		walker->error_code |= PFERR_RSVD_MASK;
@@ -252,7 +261,7 @@
 	return 0;
 }
 
-static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
+static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
 			      u64 *spte, const void *pte)
 {
 	pt_element_t gpte;
@@ -263,7 +272,7 @@
 	gpte = *(const pt_element_t *)pte;
 	if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) {
 		if (!is_present_gpte(gpte)) {
-			if (page->unsync)
+			if (sp->unsync)
 				new_spte = shadow_trap_nonpresent_pte;
 			else
 				new_spte = shadow_notrap_nonpresent_pte;
@@ -272,7 +281,7 @@
 		return;
 	}
 	pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
-	pte_access = page->role.access & FNAME(gpte_access)(vcpu, gpte);
+	pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
 	if (gpte_to_gfn(gpte) != vcpu->arch.update_pte.gfn)
 		return;
 	pfn = vcpu->arch.update_pte.pfn;
@@ -285,11 +294,22 @@
 	 * we call mmu_set_spte() with reset_host_protection = true beacuse that
 	 * vcpu->arch.update_pte.pfn was fetched from get_user_pages(write = 1).
 	 */
-	mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0,
-		     gpte & PT_DIRTY_MASK, NULL, PT_PAGE_TABLE_LEVEL,
+	mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0,
+		     is_dirty_gpte(gpte), NULL, PT_PAGE_TABLE_LEVEL,
 		     gpte_to_gfn(gpte), pfn, true, true);
 }
 
+static bool FNAME(gpte_changed)(struct kvm_vcpu *vcpu,
+				struct guest_walker *gw, int level)
+{
+	int r;
+	pt_element_t curr_pte;
+
+	r = kvm_read_guest_atomic(vcpu->kvm, gw->pte_gpa[level - 1],
+				  &curr_pte, sizeof(curr_pte));
+	return r || curr_pte != gw->ptes[level - 1];
+}
+
 /*
  * Fetch a shadow pte for a specific level in the paging hierarchy.
  */
@@ -299,75 +319,86 @@
 			 int *ptwrite, pfn_t pfn)
 {
 	unsigned access = gw->pt_access;
-	struct kvm_mmu_page *shadow_page;
-	u64 spte, *sptep = NULL;
-	int direct;
-	gfn_t table_gfn;
-	int r;
-	int level;
-	pt_element_t curr_pte;
-	struct kvm_shadow_walk_iterator iterator;
+	struct kvm_mmu_page *sp = NULL;
+	bool dirty = is_dirty_gpte(gw->ptes[gw->level - 1]);
+	int top_level;
+	unsigned direct_access;
+	struct kvm_shadow_walk_iterator it;
 
 	if (!is_present_gpte(gw->ptes[gw->level - 1]))
 		return NULL;
 
-	for_each_shadow_entry(vcpu, addr, iterator) {
-		level = iterator.level;
-		sptep = iterator.sptep;
-		if (iterator.level == hlevel) {
-			mmu_set_spte(vcpu, sptep, access,
-				     gw->pte_access & access,
-				     user_fault, write_fault,
-				     gw->ptes[gw->level-1] & PT_DIRTY_MASK,
-				     ptwrite, level,
-				     gw->gfn, pfn, false, true);
-			break;
+	direct_access = gw->pt_access & gw->pte_access;
+	if (!dirty)
+		direct_access &= ~ACC_WRITE_MASK;
+
+	top_level = vcpu->arch.mmu.root_level;
+	if (top_level == PT32E_ROOT_LEVEL)
+		top_level = PT32_ROOT_LEVEL;
+	/*
+	 * Verify that the top-level gpte is still there.  Since the page
+	 * is a root page, it is either write protected (and cannot be
+	 * changed from now on) or it is invalid (in which case, we don't
+	 * really care if it changes underneath us after this point).
+	 */
+	if (FNAME(gpte_changed)(vcpu, gw, top_level))
+		goto out_gpte_changed;
+
+	for (shadow_walk_init(&it, vcpu, addr);
+	     shadow_walk_okay(&it) && it.level > gw->level;
+	     shadow_walk_next(&it)) {
+		gfn_t table_gfn;
+
+		drop_large_spte(vcpu, it.sptep);
+
+		sp = NULL;
+		if (!is_shadow_present_pte(*it.sptep)) {
+			table_gfn = gw->table_gfn[it.level - 2];
+			sp = kvm_mmu_get_page(vcpu, table_gfn, addr, it.level-1,
+					      false, access, it.sptep);
 		}
 
-		if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep))
-			continue;
+		/*
+		 * Verify that the gpte in the page we've just write
+		 * protected is still there.
+		 */
+		if (FNAME(gpte_changed)(vcpu, gw, it.level - 1))
+			goto out_gpte_changed;
 
-		if (is_large_pte(*sptep)) {
-			rmap_remove(vcpu->kvm, sptep);
-			__set_spte(sptep, shadow_trap_nonpresent_pte);
-			kvm_flush_remote_tlbs(vcpu->kvm);
-		}
-
-		if (level <= gw->level) {
-			int delta = level - gw->level + 1;
-			direct = 1;
-			if (!is_dirty_gpte(gw->ptes[level - delta]))
-				access &= ~ACC_WRITE_MASK;
-			table_gfn = gpte_to_gfn(gw->ptes[level - delta]);
-			/* advance table_gfn when emulating 1gb pages with 4k */
-			if (delta == 0)
-				table_gfn += PT_INDEX(addr, level);
-			access &= gw->pte_access;
-		} else {
-			direct = 0;
-			table_gfn = gw->table_gfn[level - 2];
-		}
-		shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1,
-					       direct, access, sptep);
-		if (!direct) {
-			r = kvm_read_guest_atomic(vcpu->kvm,
-						  gw->pte_gpa[level - 2],
-						  &curr_pte, sizeof(curr_pte));
-			if (r || curr_pte != gw->ptes[level - 2]) {
-				kvm_mmu_put_page(shadow_page, sptep);
-				kvm_release_pfn_clean(pfn);
-				sptep = NULL;
-				break;
-			}
-		}
-
-		spte = __pa(shadow_page->spt)
-			| PT_PRESENT_MASK | PT_ACCESSED_MASK
-			| PT_WRITABLE_MASK | PT_USER_MASK;
-		*sptep = spte;
+		if (sp)
+			link_shadow_page(it.sptep, sp);
 	}
 
-	return sptep;
+	for (;
+	     shadow_walk_okay(&it) && it.level > hlevel;
+	     shadow_walk_next(&it)) {
+		gfn_t direct_gfn;
+
+		validate_direct_spte(vcpu, it.sptep, direct_access);
+
+		drop_large_spte(vcpu, it.sptep);
+
+		if (is_shadow_present_pte(*it.sptep))
+			continue;
+
+		direct_gfn = gw->gfn & ~(KVM_PAGES_PER_HPAGE(it.level) - 1);
+
+		sp = kvm_mmu_get_page(vcpu, direct_gfn, addr, it.level-1,
+				      true, direct_access, it.sptep);
+		link_shadow_page(it.sptep, sp);
+	}
+
+	mmu_set_spte(vcpu, it.sptep, access, gw->pte_access & access,
+		     user_fault, write_fault, dirty, ptwrite, it.level,
+		     gw->gfn, pfn, false, true);
+
+	return it.sptep;
+
+out_gpte_changed:
+	if (sp)
+		kvm_mmu_put_page(sp, it.sptep);
+	kvm_release_pfn_clean(pfn);
+	return NULL;
 }
 
 /*
@@ -431,11 +462,8 @@
 	pfn = gfn_to_pfn(vcpu->kvm, walker.gfn);
 
 	/* mmio */
-	if (is_error_pfn(pfn)) {
-		pgprintk("gfn %lx is mmio\n", walker.gfn);
-		kvm_release_pfn_clean(pfn);
-		return 1;
-	}
+	if (is_error_pfn(pfn))
+		return kvm_handle_bad_page(vcpu->kvm, walker.gfn, pfn);
 
 	spin_lock(&vcpu->kvm->mmu_lock);
 	if (mmu_notifier_retry(vcpu, mmu_seq))
@@ -443,6 +471,7 @@
 	kvm_mmu_free_some_pages(vcpu);
 	sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
 			     level, &write_pt, pfn);
+	(void)sptep;
 	pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __func__,
 		 sptep, *sptep, write_pt);
 
@@ -464,6 +493,7 @@
 static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)
 {
 	struct kvm_shadow_walk_iterator iterator;
+	struct kvm_mmu_page *sp;
 	gpa_t pte_gpa = -1;
 	int level;
 	u64 *sptep;
@@ -475,10 +505,13 @@
 		level = iterator.level;
 		sptep = iterator.sptep;
 
+		sp = page_header(__pa(sptep));
 		if (is_last_spte(*sptep, level)) {
-			struct kvm_mmu_page *sp = page_header(__pa(sptep));
 			int offset, shift;
 
+			if (!sp->unsync)
+				break;
+
 			shift = PAGE_SHIFT -
 				  (PT_LEVEL_BITS - PT64_LEVEL_BITS) * level;
 			offset = sp->role.quadrant << shift;
@@ -487,16 +520,17 @@
 			pte_gpa += (sptep - sp->spt) * sizeof(pt_element_t);
 
 			if (is_shadow_present_pte(*sptep)) {
-				rmap_remove(vcpu->kvm, sptep);
 				if (is_large_pte(*sptep))
 					--vcpu->kvm->stat.lpages;
+				drop_spte(vcpu->kvm, sptep,
+					  shadow_trap_nonpresent_pte);
 				need_flush = 1;
-			}
-			__set_spte(sptep, shadow_trap_nonpresent_pte);
+			} else
+				__set_spte(sptep, shadow_trap_nonpresent_pte);
 			break;
 		}
 
-		if (!is_shadow_present_pte(*sptep))
+		if (!is_shadow_present_pte(*sptep) || !sp->unsync_children)
 			break;
 	}
 
@@ -570,9 +604,9 @@
  * Using the cached information from sp->gfns is safe because:
  * - The spte has a reference to the struct page, so the pfn for a given gfn
  *   can't change unless all sptes pointing to it are nuked first.
- * - Alias changes zap the entire shadow cache.
  */
-static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
+static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
+			    bool clear_unsync)
 {
 	int i, offset, nr_present;
 	bool reset_host_protection;
@@ -580,6 +614,9 @@
 
 	offset = nr_present = 0;
 
+	/* direct kvm_mmu_page can not be unsync. */
+	BUG_ON(sp->role.direct);
+
 	if (PTTYPE == 32)
 		offset = sp->role.quadrant << PT64_LEVEL_BITS;
 
@@ -589,7 +626,7 @@
 		unsigned pte_access;
 		pt_element_t gpte;
 		gpa_t pte_gpa;
-		gfn_t gfn = sp->gfns[i];
+		gfn_t gfn;
 
 		if (!is_shadow_present_pte(sp->spt[i]))
 			continue;
@@ -600,16 +637,17 @@
 					  sizeof(pt_element_t)))
 			return -EINVAL;
 
-		if (gpte_to_gfn(gpte) != gfn || !is_present_gpte(gpte) ||
-		    !(gpte & PT_ACCESSED_MASK)) {
+		gfn = gpte_to_gfn(gpte);
+		if (is_rsvd_bits_set(vcpu, gpte, PT_PAGE_TABLE_LEVEL)
+		      || gfn != sp->gfns[i] || !is_present_gpte(gpte)
+		      || !(gpte & PT_ACCESSED_MASK)) {
 			u64 nonpresent;
 
-			rmap_remove(vcpu->kvm, &sp->spt[i]);
-			if (is_present_gpte(gpte))
+			if (is_present_gpte(gpte) || !clear_unsync)
 				nonpresent = shadow_trap_nonpresent_pte;
 			else
 				nonpresent = shadow_notrap_nonpresent_pte;
-			__set_spte(&sp->spt[i], nonpresent);
+			drop_spte(vcpu->kvm, &sp->spt[i], nonpresent);
 			continue;
 		}
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index ce438e0..56c9b6b 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -4,6 +4,7 @@
  * AMD SVM support
  *
  * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
  *
  * Authors:
  *   Yaniv Kamay  <yaniv@qumranet.com>
@@ -285,11 +286,11 @@
 
 static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
 {
+	vcpu->arch.efer = efer;
 	if (!npt_enabled && !(efer & EFER_LMA))
 		efer &= ~EFER_LME;
 
 	to_svm(vcpu)->vmcb->save.efer = efer | EFER_SVME;
-	vcpu->arch.efer = efer;
 }
 
 static int is_external_interrupt(u32 info)
@@ -640,7 +641,7 @@
 
 	if (nested) {
 		printk(KERN_INFO "kvm: Nested Virtualization enabled\n");
-		kvm_enable_efer_bits(EFER_SVME);
+		kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE);
 	}
 
 	for_each_possible_cpu(cpu) {
@@ -806,7 +807,7 @@
 	 * svm_set_cr0() sets PG and WP and clears NW and CD on save->cr0.
 	 */
 	svm->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
-	kvm_set_cr0(&svm->vcpu, svm->vcpu.arch.cr0);
+	(void)kvm_set_cr0(&svm->vcpu, svm->vcpu.arch.cr0);
 
 	save->cr4 = X86_CR4_PAE;
 	/* rdx = ?? */
@@ -903,13 +904,18 @@
 	svm->asid_generation = 0;
 	init_vmcb(svm);
 
-	fx_init(&svm->vcpu);
+	err = fx_init(&svm->vcpu);
+	if (err)
+		goto free_page4;
+
 	svm->vcpu.arch.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
 	if (kvm_vcpu_is_bsp(&svm->vcpu))
 		svm->vcpu.arch.apic_base |= MSR_IA32_APICBASE_BSP;
 
 	return &svm->vcpu;
 
+free_page4:
+	__free_page(hsave_page);
 free_page3:
 	__free_pages(nested_msrpm_pages, MSRPM_ALLOC_ORDER);
 free_page2:
@@ -1488,7 +1494,7 @@
 		 */
 		pr_err("KVM: Guest triggered AMD Erratum 383\n");
 
-		set_bit(KVM_REQ_TRIPLE_FAULT, &svm->vcpu.requests);
+		kvm_make_request(KVM_REQ_TRIPLE_FAULT, &svm->vcpu);
 
 		return;
 	}
@@ -1535,7 +1541,7 @@
 	string = (io_info & SVM_IOIO_STR_MASK) != 0;
 	in = (io_info & SVM_IOIO_TYPE_MASK) != 0;
 	if (string || in)
-		return !(emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO);
+		return emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DONE;
 
 	port = io_info >> 16;
 	size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
@@ -1957,7 +1963,7 @@
 		svm->vmcb->save.cr3 = hsave->save.cr3;
 		svm->vcpu.arch.cr3 = hsave->save.cr3;
 	} else {
-		kvm_set_cr3(&svm->vcpu, hsave->save.cr3);
+		(void)kvm_set_cr3(&svm->vcpu, hsave->save.cr3);
 	}
 	kvm_register_write(&svm->vcpu, VCPU_REGS_RAX, hsave->save.rax);
 	kvm_register_write(&svm->vcpu, VCPU_REGS_RSP, hsave->save.rsp);
@@ -2080,7 +2086,7 @@
 		svm->vmcb->save.cr3 = nested_vmcb->save.cr3;
 		svm->vcpu.arch.cr3 = nested_vmcb->save.cr3;
 	} else
-		kvm_set_cr3(&svm->vcpu, nested_vmcb->save.cr3);
+		(void)kvm_set_cr3(&svm->vcpu, nested_vmcb->save.cr3);
 
 	/* Guest paging mode is active - reset mmu */
 	kvm_mmu_reset_context(&svm->vcpu);
@@ -2386,16 +2392,12 @@
 
 static int invlpg_interception(struct vcpu_svm *svm)
 {
-	if (emulate_instruction(&svm->vcpu, 0, 0, 0) != EMULATE_DONE)
-		pr_unimpl(&svm->vcpu, "%s: failed\n", __func__);
-	return 1;
+	return emulate_instruction(&svm->vcpu, 0, 0, 0) == EMULATE_DONE;
 }
 
 static int emulate_on_interception(struct vcpu_svm *svm)
 {
-	if (emulate_instruction(&svm->vcpu, 0, 0, 0) != EMULATE_DONE)
-		pr_unimpl(&svm->vcpu, "%s: failed\n", __func__);
-	return 1;
+	return emulate_instruction(&svm->vcpu, 0, 0, 0) == EMULATE_DONE;
 }
 
 static int cr8_write_interception(struct vcpu_svm *svm)
@@ -2726,6 +2728,99 @@
 	[SVM_EXIT_NPF]				= pf_interception,
 };
 
+void dump_vmcb(struct kvm_vcpu *vcpu)
+{
+	struct vcpu_svm *svm = to_svm(vcpu);
+	struct vmcb_control_area *control = &svm->vmcb->control;
+	struct vmcb_save_area *save = &svm->vmcb->save;
+
+	pr_err("VMCB Control Area:\n");
+	pr_err("cr_read:            %04x\n", control->intercept_cr_read);
+	pr_err("cr_write:           %04x\n", control->intercept_cr_write);
+	pr_err("dr_read:            %04x\n", control->intercept_dr_read);
+	pr_err("dr_write:           %04x\n", control->intercept_dr_write);
+	pr_err("exceptions:         %08x\n", control->intercept_exceptions);
+	pr_err("intercepts:         %016llx\n", control->intercept);
+	pr_err("pause filter count: %d\n", control->pause_filter_count);
+	pr_err("iopm_base_pa:       %016llx\n", control->iopm_base_pa);
+	pr_err("msrpm_base_pa:      %016llx\n", control->msrpm_base_pa);
+	pr_err("tsc_offset:         %016llx\n", control->tsc_offset);
+	pr_err("asid:               %d\n", control->asid);
+	pr_err("tlb_ctl:            %d\n", control->tlb_ctl);
+	pr_err("int_ctl:            %08x\n", control->int_ctl);
+	pr_err("int_vector:         %08x\n", control->int_vector);
+	pr_err("int_state:          %08x\n", control->int_state);
+	pr_err("exit_code:          %08x\n", control->exit_code);
+	pr_err("exit_info1:         %016llx\n", control->exit_info_1);
+	pr_err("exit_info2:         %016llx\n", control->exit_info_2);
+	pr_err("exit_int_info:      %08x\n", control->exit_int_info);
+	pr_err("exit_int_info_err:  %08x\n", control->exit_int_info_err);
+	pr_err("nested_ctl:         %lld\n", control->nested_ctl);
+	pr_err("nested_cr3:         %016llx\n", control->nested_cr3);
+	pr_err("event_inj:          %08x\n", control->event_inj);
+	pr_err("event_inj_err:      %08x\n", control->event_inj_err);
+	pr_err("lbr_ctl:            %lld\n", control->lbr_ctl);
+	pr_err("next_rip:           %016llx\n", control->next_rip);
+	pr_err("VMCB State Save Area:\n");
+	pr_err("es:   s: %04x a: %04x l: %08x b: %016llx\n",
+		save->es.selector, save->es.attrib,
+		save->es.limit, save->es.base);
+	pr_err("cs:   s: %04x a: %04x l: %08x b: %016llx\n",
+		save->cs.selector, save->cs.attrib,
+		save->cs.limit, save->cs.base);
+	pr_err("ss:   s: %04x a: %04x l: %08x b: %016llx\n",
+		save->ss.selector, save->ss.attrib,
+		save->ss.limit, save->ss.base);
+	pr_err("ds:   s: %04x a: %04x l: %08x b: %016llx\n",
+		save->ds.selector, save->ds.attrib,
+		save->ds.limit, save->ds.base);
+	pr_err("fs:   s: %04x a: %04x l: %08x b: %016llx\n",
+		save->fs.selector, save->fs.attrib,
+		save->fs.limit, save->fs.base);
+	pr_err("gs:   s: %04x a: %04x l: %08x b: %016llx\n",
+		save->gs.selector, save->gs.attrib,
+		save->gs.limit, save->gs.base);
+	pr_err("gdtr: s: %04x a: %04x l: %08x b: %016llx\n",
+		save->gdtr.selector, save->gdtr.attrib,
+		save->gdtr.limit, save->gdtr.base);
+	pr_err("ldtr: s: %04x a: %04x l: %08x b: %016llx\n",
+		save->ldtr.selector, save->ldtr.attrib,
+		save->ldtr.limit, save->ldtr.base);
+	pr_err("idtr: s: %04x a: %04x l: %08x b: %016llx\n",
+		save->idtr.selector, save->idtr.attrib,
+		save->idtr.limit, save->idtr.base);
+	pr_err("tr:   s: %04x a: %04x l: %08x b: %016llx\n",
+		save->tr.selector, save->tr.attrib,
+		save->tr.limit, save->tr.base);
+	pr_err("cpl:            %d                efer:         %016llx\n",
+		save->cpl, save->efer);
+	pr_err("cr0:            %016llx cr2:          %016llx\n",
+		save->cr0, save->cr2);
+	pr_err("cr3:            %016llx cr4:          %016llx\n",
+		save->cr3, save->cr4);
+	pr_err("dr6:            %016llx dr7:          %016llx\n",
+		save->dr6, save->dr7);
+	pr_err("rip:            %016llx rflags:       %016llx\n",
+		save->rip, save->rflags);
+	pr_err("rsp:            %016llx rax:          %016llx\n",
+		save->rsp, save->rax);
+	pr_err("star:           %016llx lstar:        %016llx\n",
+		save->star, save->lstar);
+	pr_err("cstar:          %016llx sfmask:       %016llx\n",
+		save->cstar, save->sfmask);
+	pr_err("kernel_gs_base: %016llx sysenter_cs:  %016llx\n",
+		save->kernel_gs_base, save->sysenter_cs);
+	pr_err("sysenter_esp:   %016llx sysenter_eip: %016llx\n",
+		save->sysenter_esp, save->sysenter_eip);
+	pr_err("gpat:           %016llx dbgctl:       %016llx\n",
+		save->g_pat, save->dbgctl);
+	pr_err("br_from:        %016llx br_to:        %016llx\n",
+		save->br_from, save->br_to);
+	pr_err("excp_from:      %016llx excp_to:      %016llx\n",
+		save->last_excp_from, save->last_excp_to);
+
+}
+
 static int handle_exit(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
@@ -2770,6 +2865,8 @@
 		kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
 		kvm_run->fail_entry.hardware_entry_failure_reason
 			= svm->vmcb->control.exit_code;
+		pr_err("KVM: FAILED VMRUN WITH VMCB:\n");
+		dump_vmcb(vcpu);
 		return 0;
 	}
 
@@ -2826,9 +2923,6 @@
 {
 	struct vmcb_control_area *control;
 
-	trace_kvm_inj_virq(irq);
-
-	++svm->vcpu.stat.irq_injections;
 	control = &svm->vmcb->control;
 	control->int_vector = irq;
 	control->int_ctl &= ~V_INTR_PRIO_MASK;
@@ -2842,6 +2936,9 @@
 
 	BUG_ON(!(gif_set(svm)));
 
+	trace_kvm_inj_virq(vcpu->arch.interrupt.nr);
+	++vcpu->stat.irq_injections;
+
 	svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr |
 		SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
 }
@@ -3327,6 +3424,11 @@
 	return false;
 }
 
+static bool svm_has_wbinvd_exit(void)
+{
+	return true;
+}
+
 static void svm_fpu_deactivate(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
@@ -3411,6 +3513,8 @@
 	.rdtscp_supported = svm_rdtscp_supported,
 
 	.set_supported_cpuid = svm_set_supported_cpuid,
+
+	.has_wbinvd_exit = svm_has_wbinvd_exit,
 };
 
 static int __init svm_init(void)
diff --git a/arch/x86/kvm/timer.c b/arch/x86/kvm/timer.c
index 4ddadb1..e16a0db 100644
--- a/arch/x86/kvm/timer.c
+++ b/arch/x86/kvm/timer.c
@@ -1,3 +1,17 @@
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * This module enables machines with Intel VT-x extensions to run virtual
+ * machines without emulation or binary translation.
+ *
+ * timer support
+ *
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
 #include <linux/kvm_host.h>
 #include <linux/kvm.h>
 #include <linux/hrtimer.h>
@@ -18,7 +32,7 @@
 	if (ktimer->reinject || !atomic_read(&ktimer->pending)) {
 		atomic_inc(&ktimer->pending);
 		/* FIXME: this code should not know anything about vcpus */
-		set_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests);
+		kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
 	}
 
 	if (waitqueue_active(q))
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index ee03679..27a0222 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -5,6 +5,7 @@
  * machines without emulation or binary translation.
  *
  * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
  *
  * Authors:
  *   Avi Kivity   <avi@qumranet.com>
@@ -36,6 +37,8 @@
 #include <asm/vmx.h>
 #include <asm/virtext.h>
 #include <asm/mce.h>
+#include <asm/i387.h>
+#include <asm/xcr.h>
 
 #include "trace.h"
 
@@ -63,6 +66,9 @@
 static int __read_mostly emulate_invalid_guest_state = 0;
 module_param(emulate_invalid_guest_state, bool, S_IRUGO);
 
+static int __read_mostly vmm_exclusive = 1;
+module_param(vmm_exclusive, bool, S_IRUGO);
+
 #define KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST				\
 	(X86_CR0_WP | X86_CR0_NE | X86_CR0_NW | X86_CR0_CD)
 #define KVM_GUEST_CR0_MASK						\
@@ -173,10 +179,13 @@
 
 static int init_rmode(struct kvm *kvm);
 static u64 construct_eptp(unsigned long root_hpa);
+static void kvm_cpu_vmxon(u64 addr);
+static void kvm_cpu_vmxoff(void);
 
 static DEFINE_PER_CPU(struct vmcs *, vmxarea);
 static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
 static DEFINE_PER_CPU(struct list_head, vcpus_on_cpu);
+static DEFINE_PER_CPU(struct desc_ptr, host_gdt);
 
 static unsigned long *vmx_io_bitmap_a;
 static unsigned long *vmx_io_bitmap_b;
@@ -334,6 +343,11 @@
 	return vmx_capability.ept & VMX_EPT_1GB_PAGE_BIT;
 }
 
+static inline bool cpu_has_vmx_ept_4levels(void)
+{
+	return vmx_capability.ept & VMX_EPT_PAGE_WALK_4_BIT;
+}
+
 static inline bool cpu_has_vmx_invept_individual_addr(void)
 {
 	return vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT;
@@ -349,6 +363,16 @@
 	return vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT;
 }
 
+static inline bool cpu_has_vmx_invvpid_single(void)
+{
+	return vmx_capability.vpid & VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT;
+}
+
+static inline bool cpu_has_vmx_invvpid_global(void)
+{
+	return vmx_capability.vpid & VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT;
+}
+
 static inline bool cpu_has_vmx_ept(void)
 {
 	return vmcs_config.cpu_based_2nd_exec_ctrl &
@@ -389,6 +413,12 @@
 	return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS;
 }
 
+static inline bool cpu_has_vmx_wbinvd_exit(void)
+{
+	return vmcs_config.cpu_based_2nd_exec_ctrl &
+		SECONDARY_EXEC_WBINVD_EXITING;
+}
+
 static inline bool report_flexpriority(void)
 {
 	return flexpriority_enabled;
@@ -453,6 +483,19 @@
 		       vmcs, phys_addr);
 }
 
+static void vmcs_load(struct vmcs *vmcs)
+{
+	u64 phys_addr = __pa(vmcs);
+	u8 error;
+
+	asm volatile (__ex(ASM_VMX_VMPTRLD_RAX) "; setna %0"
+			: "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
+			: "cc", "memory");
+	if (error)
+		printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n",
+		       vmcs, phys_addr);
+}
+
 static void __vcpu_clear(void *arg)
 {
 	struct vcpu_vmx *vmx = arg;
@@ -475,12 +518,27 @@
 	smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 1);
 }
 
-static inline void vpid_sync_vcpu_all(struct vcpu_vmx *vmx)
+static inline void vpid_sync_vcpu_single(struct vcpu_vmx *vmx)
 {
 	if (vmx->vpid == 0)
 		return;
 
-	__invvpid(VMX_VPID_EXTENT_SINGLE_CONTEXT, vmx->vpid, 0);
+	if (cpu_has_vmx_invvpid_single())
+		__invvpid(VMX_VPID_EXTENT_SINGLE_CONTEXT, vmx->vpid, 0);
+}
+
+static inline void vpid_sync_vcpu_global(void)
+{
+	if (cpu_has_vmx_invvpid_global())
+		__invvpid(VMX_VPID_EXTENT_ALL_CONTEXT, 0, 0);
+}
+
+static inline void vpid_sync_context(struct vcpu_vmx *vmx)
+{
+	if (cpu_has_vmx_invvpid_single())
+		vpid_sync_vcpu_single(vmx);
+	else
+		vpid_sync_vcpu_global();
 }
 
 static inline void ept_sync_global(void)
@@ -812,6 +870,9 @@
 		wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
 	}
 #endif
+	if (current_thread_info()->status & TS_USEDFPU)
+		clts();
+	load_gdt(&__get_cpu_var(host_gdt));
 }
 
 static void vmx_load_host_state(struct vcpu_vmx *vmx)
@@ -828,35 +889,30 @@
 static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
-	u64 phys_addr = __pa(vmx->vmcs);
 	u64 tsc_this, delta, new_offset;
+	u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
 
-	if (vcpu->cpu != cpu) {
+	if (!vmm_exclusive)
+		kvm_cpu_vmxon(phys_addr);
+	else if (vcpu->cpu != cpu)
 		vcpu_clear(vmx);
-		kvm_migrate_timers(vcpu);
-		set_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests);
-		local_irq_disable();
-		list_add(&vmx->local_vcpus_link,
-			 &per_cpu(vcpus_on_cpu, cpu));
-		local_irq_enable();
-	}
 
 	if (per_cpu(current_vmcs, cpu) != vmx->vmcs) {
-		u8 error;
-
 		per_cpu(current_vmcs, cpu) = vmx->vmcs;
-		asm volatile (__ex(ASM_VMX_VMPTRLD_RAX) "; setna %0"
-			      : "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
-			      : "cc");
-		if (error)
-			printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n",
-			       vmx->vmcs, phys_addr);
+		vmcs_load(vmx->vmcs);
 	}
 
 	if (vcpu->cpu != cpu) {
 		struct desc_ptr dt;
 		unsigned long sysenter_esp;
 
+		kvm_migrate_timers(vcpu);
+		kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
+		local_irq_disable();
+		list_add(&vmx->local_vcpus_link,
+			 &per_cpu(vcpus_on_cpu, cpu));
+		local_irq_enable();
+
 		vcpu->cpu = cpu;
 		/*
 		 * Linux uses per-cpu TSS and GDT, so set these when switching
@@ -884,6 +940,10 @@
 static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
 {
 	__vmx_load_host_state(to_vmx(vcpu));
+	if (!vmm_exclusive) {
+		__vcpu_clear(to_vmx(vcpu));
+		kvm_cpu_vmxoff();
+	}
 }
 
 static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
@@ -1286,6 +1346,13 @@
 	/* locked but not enabled */
 }
 
+static void kvm_cpu_vmxon(u64 addr)
+{
+	asm volatile (ASM_VMX_VMXON_RAX
+			: : "a"(&addr), "m"(addr)
+			: "memory", "cc");
+}
+
 static int hardware_enable(void *garbage)
 {
 	int cpu = raw_smp_processor_id();
@@ -1308,11 +1375,13 @@
 		wrmsrl(MSR_IA32_FEATURE_CONTROL, old | test_bits);
 	}
 	write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */
-	asm volatile (ASM_VMX_VMXON_RAX
-		      : : "a"(&phys_addr), "m"(phys_addr)
-		      : "memory", "cc");
 
-	ept_sync_global();
+	if (vmm_exclusive) {
+		kvm_cpu_vmxon(phys_addr);
+		ept_sync_global();
+	}
+
+	store_gdt(&__get_cpu_var(host_gdt));
 
 	return 0;
 }
@@ -1334,13 +1403,15 @@
 static void kvm_cpu_vmxoff(void)
 {
 	asm volatile (__ex(ASM_VMX_VMXOFF) : : : "cc");
-	write_cr4(read_cr4() & ~X86_CR4_VMXE);
 }
 
 static void hardware_disable(void *garbage)
 {
-	vmclear_local_vcpus();
-	kvm_cpu_vmxoff();
+	if (vmm_exclusive) {
+		vmclear_local_vcpus();
+		kvm_cpu_vmxoff();
+	}
+	write_cr4(read_cr4() & ~X86_CR4_VMXE);
 }
 
 static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt,
@@ -1539,7 +1610,8 @@
 	if (!cpu_has_vmx_vpid())
 		enable_vpid = 0;
 
-	if (!cpu_has_vmx_ept()) {
+	if (!cpu_has_vmx_ept() ||
+	    !cpu_has_vmx_ept_4levels()) {
 		enable_ept = 0;
 		enable_unrestricted_guest = 0;
 	}
@@ -1628,7 +1700,7 @@
 		gfn_t base_gfn;
 
 		slots = kvm_memslots(kvm);
-		base_gfn = kvm->memslots->memslots[0].base_gfn +
+		base_gfn = slots->memslots[0].base_gfn +
 				 kvm->memslots->memslots[0].npages - 3;
 		return base_gfn << PAGE_SHIFT;
 	}
@@ -1759,9 +1831,12 @@
 
 static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
 {
-	vpid_sync_vcpu_all(to_vmx(vcpu));
-	if (enable_ept)
+	vpid_sync_context(to_vmx(vcpu));
+	if (enable_ept) {
+		if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
+			return;
 		ept_sync_context(construct_eptp(vcpu->arch.mmu.root_hpa));
+	}
 }
 
 static void vmx_decache_cr0_guest_bits(struct kvm_vcpu *vcpu)
@@ -2507,7 +2582,7 @@
 	vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, !!bypass_guest_pf);
 	vmcs_write32(CR3_TARGET_COUNT, 0);           /* 22.2.1 */
 
-	vmcs_writel(HOST_CR0, read_cr0());  /* 22.2.3 */
+	vmcs_writel(HOST_CR0, read_cr0() | X86_CR0_TS);  /* 22.2.3 */
 	vmcs_writel(HOST_CR4, read_cr4());  /* 22.2.3, 22.2.5 */
 	vmcs_writel(HOST_CR3, read_cr3());  /* 22.2.3  FIXME: shadow tables */
 
@@ -2599,21 +2674,27 @@
 
 static int init_rmode(struct kvm *kvm)
 {
+	int idx, ret = 0;
+
+	idx = srcu_read_lock(&kvm->srcu);
 	if (!init_rmode_tss(kvm))
-		return 0;
+		goto exit;
 	if (!init_rmode_identity_map(kvm))
-		return 0;
-	return 1;
+		goto exit;
+
+	ret = 1;
+exit:
+	srcu_read_unlock(&kvm->srcu, idx);
+	return ret;
 }
 
 static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	u64 msr;
-	int ret, idx;
+	int ret;
 
 	vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP));
-	idx = srcu_read_lock(&vcpu->kvm->srcu);
 	if (!init_rmode(vmx->vcpu.kvm)) {
 		ret = -ENOMEM;
 		goto out;
@@ -2630,7 +2711,9 @@
 		msr |= MSR_IA32_APICBASE_BSP;
 	kvm_set_apic_base(&vmx->vcpu, msr);
 
-	fx_init(&vmx->vcpu);
+	ret = fx_init(&vmx->vcpu);
+	if (ret != 0)
+		goto out;
 
 	seg_setup(VCPU_SREG_CS);
 	/*
@@ -2713,7 +2796,7 @@
 	vmx_fpu_activate(&vmx->vcpu);
 	update_exception_bitmap(&vmx->vcpu);
 
-	vpid_sync_vcpu_all(vmx);
+	vpid_sync_context(vmx);
 
 	ret = 0;
 
@@ -2721,7 +2804,6 @@
 	vmx->emulation_required = 0;
 
 out:
-	srcu_read_unlock(&vcpu->kvm->srcu, idx);
 	return ret;
 }
 
@@ -2826,9 +2908,7 @@
 {
 	if (!cpu_has_virtual_nmis())
 		return to_vmx(vcpu)->soft_vnmi_blocked;
-	else
-		return !!(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
-			  GUEST_INTR_STATE_NMI);
+	return vmcs_read32(GUEST_INTERRUPTIBILITY_INFO)	& GUEST_INTR_STATE_NMI;
 }
 
 static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
@@ -3070,7 +3150,7 @@
 	++vcpu->stat.io_exits;
 
 	if (string || in)
-		return !(emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO);
+		return emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DONE;
 
 	port = exit_qualification >> 16;
 	size = (exit_qualification & 7) + 1;
@@ -3090,11 +3170,20 @@
 	hypercall[2] = 0xc1;
 }
 
+static void complete_insn_gp(struct kvm_vcpu *vcpu, int err)
+{
+	if (err)
+		kvm_inject_gp(vcpu, 0);
+	else
+		skip_emulated_instruction(vcpu);
+}
+
 static int handle_cr(struct kvm_vcpu *vcpu)
 {
 	unsigned long exit_qualification, val;
 	int cr;
 	int reg;
+	int err;
 
 	exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
 	cr = exit_qualification & 15;
@@ -3105,16 +3194,16 @@
 		trace_kvm_cr_write(cr, val);
 		switch (cr) {
 		case 0:
-			kvm_set_cr0(vcpu, val);
-			skip_emulated_instruction(vcpu);
+			err = kvm_set_cr0(vcpu, val);
+			complete_insn_gp(vcpu, err);
 			return 1;
 		case 3:
-			kvm_set_cr3(vcpu, val);
-			skip_emulated_instruction(vcpu);
+			err = kvm_set_cr3(vcpu, val);
+			complete_insn_gp(vcpu, err);
 			return 1;
 		case 4:
-			kvm_set_cr4(vcpu, val);
-			skip_emulated_instruction(vcpu);
+			err = kvm_set_cr4(vcpu, val);
+			complete_insn_gp(vcpu, err);
 			return 1;
 		case 8: {
 				u8 cr8_prev = kvm_get_cr8(vcpu);
@@ -3321,28 +3410,23 @@
 static int handle_wbinvd(struct kvm_vcpu *vcpu)
 {
 	skip_emulated_instruction(vcpu);
-	/* TODO: Add support for VT-d/pass-through device */
+	kvm_emulate_wbinvd(vcpu);
+	return 1;
+}
+
+static int handle_xsetbv(struct kvm_vcpu *vcpu)
+{
+	u64 new_bv = kvm_read_edx_eax(vcpu);
+	u32 index = kvm_register_read(vcpu, VCPU_REGS_RCX);
+
+	if (kvm_set_xcr(vcpu, index, new_bv) == 0)
+		skip_emulated_instruction(vcpu);
 	return 1;
 }
 
 static int handle_apic_access(struct kvm_vcpu *vcpu)
 {
-	unsigned long exit_qualification;
-	enum emulation_result er;
-	unsigned long offset;
-
-	exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
-	offset = exit_qualification & 0xffful;
-
-	er = emulate_instruction(vcpu, 0, 0, 0);
-
-	if (er !=  EMULATE_DONE) {
-		printk(KERN_ERR
-		       "Fail to handle apic access vmexit! Offset is 0x%lx\n",
-		       offset);
-		return -ENOEXEC;
-	}
-	return 1;
+	return emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DONE;
 }
 
 static int handle_task_switch(struct kvm_vcpu *vcpu)
@@ -3554,13 +3638,8 @@
 			goto out;
 		}
 
-		if (err != EMULATE_DONE) {
-			vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
-			vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
-			vcpu->run->internal.ndata = 0;
-			ret = 0;
-			goto out;
-		}
+		if (err != EMULATE_DONE)
+			return 0;
 
 		if (signal_pending(current))
 			goto out;
@@ -3623,6 +3702,7 @@
 	[EXIT_REASON_TPR_BELOW_THRESHOLD]     = handle_tpr_below_threshold,
 	[EXIT_REASON_APIC_ACCESS]             = handle_apic_access,
 	[EXIT_REASON_WBINVD]                  = handle_wbinvd,
+	[EXIT_REASON_XSETBV]                  = handle_xsetbv,
 	[EXIT_REASON_TASK_SWITCH]             = handle_task_switch,
 	[EXIT_REASON_MCE_DURING_VMENTRY]      = handle_machine_check,
 	[EXIT_REASON_EPT_VIOLATION]	      = handle_ept_violation,
@@ -3656,6 +3736,13 @@
 	if (enable_ept && is_paging(vcpu))
 		vcpu->arch.cr3 = vmcs_readl(GUEST_CR3);
 
+	if (exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) {
+		vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+		vcpu->run->fail_entry.hardware_entry_failure_reason
+			= exit_reason;
+		return 0;
+	}
+
 	if (unlikely(vmx->fail)) {
 		vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY;
 		vcpu->run->fail_entry.hardware_entry_failure_reason
@@ -3861,11 +3948,6 @@
 	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
 		vmx_set_interrupt_shadow(vcpu, 0);
 
-	/*
-	 * Loading guest fpu may have cleared host cr0.ts
-	 */
-	vmcs_writel(HOST_CR0, read_cr0());
-
 	asm(
 		/* Store host registers */
 		"push %%"R"dx; push %%"R"bp;"
@@ -4001,6 +4083,19 @@
 	kmem_cache_free(kvm_vcpu_cache, vmx);
 }
 
+static inline void vmcs_init(struct vmcs *vmcs)
+{
+	u64 phys_addr = __pa(per_cpu(vmxarea, raw_smp_processor_id()));
+
+	if (!vmm_exclusive)
+		kvm_cpu_vmxon(phys_addr);
+
+	vmcs_clear(vmcs);
+
+	if (!vmm_exclusive)
+		kvm_cpu_vmxoff();
+}
+
 static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
 {
 	int err;
@@ -4026,7 +4121,7 @@
 	if (!vmx->vmcs)
 		goto free_msrs;
 
-	vmcs_clear(vmx->vmcs);
+	vmcs_init(vmx->vmcs);
 
 	cpu = get_cpu();
 	vmx_vcpu_load(&vmx->vcpu, cpu);
@@ -4265,6 +4360,8 @@
 	.rdtscp_supported = vmx_rdtscp_supported,
 
 	.set_supported_cpuid = vmx_set_supported_cpuid,
+
+	.has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
 };
 
 static int __init vmx_init(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 7fa89c3..97aab03 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -6,6 +6,7 @@
  * Copyright (C) 2006 Qumranet, Inc.
  * Copyright (C) 2008 Qumranet, Inc.
  * Copyright IBM Corporation, 2008
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
  *
  * Authors:
  *   Avi Kivity   <avi@qumranet.com>
@@ -41,17 +42,19 @@
 #include <linux/srcu.h>
 #include <linux/slab.h>
 #include <linux/perf_event.h>
+#include <linux/uaccess.h>
 #include <trace/events/kvm.h>
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
 
 #include <asm/debugreg.h>
-#include <asm/uaccess.h>
 #include <asm/msr.h>
 #include <asm/desc.h>
 #include <asm/mtrr.h>
 #include <asm/mce.h>
+#include <asm/i387.h>
+#include <asm/xcr.h>
 
 #define MAX_IO_MSRS 256
 #define CR0_RESERVED_BITS						\
@@ -62,6 +65,7 @@
 	(~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\
 			  | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE	\
 			  | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR	\
+			  | X86_CR4_OSXSAVE \
 			  | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE))
 
 #define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
@@ -147,6 +151,13 @@
 	{ NULL }
 };
 
+u64 __read_mostly host_xcr0;
+
+static inline u32 bit(int bitno)
+{
+	return 1 << (bitno & 31);
+}
+
 static void kvm_on_user_return(struct user_return_notifier *urn)
 {
 	unsigned slot;
@@ -285,7 +296,7 @@
 	prev_nr = vcpu->arch.exception.nr;
 	if (prev_nr == DF_VECTOR) {
 		/* triple fault -> shutdown */
-		set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
+		kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
 		return;
 	}
 	class1 = exception_class(prev_nr);
@@ -414,121 +425,163 @@
 	return changed;
 }
 
-void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
+int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 {
+	unsigned long old_cr0 = kvm_read_cr0(vcpu);
+	unsigned long update_bits = X86_CR0_PG | X86_CR0_WP |
+				    X86_CR0_CD | X86_CR0_NW;
+
 	cr0 |= X86_CR0_ET;
 
 #ifdef CONFIG_X86_64
-	if (cr0 & 0xffffffff00000000UL) {
-		kvm_inject_gp(vcpu, 0);
-		return;
-	}
+	if (cr0 & 0xffffffff00000000UL)
+		return 1;
 #endif
 
 	cr0 &= ~CR0_RESERVED_BITS;
 
-	if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) {
-		kvm_inject_gp(vcpu, 0);
-		return;
-	}
+	if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD))
+		return 1;
 
-	if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) {
-		kvm_inject_gp(vcpu, 0);
-		return;
-	}
+	if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE))
+		return 1;
 
 	if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
 #ifdef CONFIG_X86_64
 		if ((vcpu->arch.efer & EFER_LME)) {
 			int cs_db, cs_l;
 
-			if (!is_pae(vcpu)) {
-				kvm_inject_gp(vcpu, 0);
-				return;
-			}
+			if (!is_pae(vcpu))
+				return 1;
 			kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
-			if (cs_l) {
-				kvm_inject_gp(vcpu, 0);
-				return;
-
-			}
+			if (cs_l)
+				return 1;
 		} else
 #endif
-		if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.cr3)) {
-			kvm_inject_gp(vcpu, 0);
-			return;
-		}
-
+		if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.cr3))
+			return 1;
 	}
 
 	kvm_x86_ops->set_cr0(vcpu, cr0);
 
-	kvm_mmu_reset_context(vcpu);
-	return;
+	if ((cr0 ^ old_cr0) & update_bits)
+		kvm_mmu_reset_context(vcpu);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(kvm_set_cr0);
 
 void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
 {
-	kvm_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~0x0eul) | (msw & 0x0f));
+	(void)kvm_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~0x0eul) | (msw & 0x0f));
 }
 EXPORT_SYMBOL_GPL(kvm_lmsw);
 
-void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
+{
+	u64 xcr0;
+
+	/* Only support XCR_XFEATURE_ENABLED_MASK(xcr0) now  */
+	if (index != XCR_XFEATURE_ENABLED_MASK)
+		return 1;
+	xcr0 = xcr;
+	if (kvm_x86_ops->get_cpl(vcpu) != 0)
+		return 1;
+	if (!(xcr0 & XSTATE_FP))
+		return 1;
+	if ((xcr0 & XSTATE_YMM) && !(xcr0 & XSTATE_SSE))
+		return 1;
+	if (xcr0 & ~host_xcr0)
+		return 1;
+	vcpu->arch.xcr0 = xcr0;
+	vcpu->guest_xcr0_loaded = 0;
+	return 0;
+}
+
+int kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
+{
+	if (__kvm_set_xcr(vcpu, index, xcr)) {
+		kvm_inject_gp(vcpu, 0);
+		return 1;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_set_xcr);
+
+static bool guest_cpuid_has_xsave(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid_entry2 *best;
+
+	best = kvm_find_cpuid_entry(vcpu, 1, 0);
+	return best && (best->ecx & bit(X86_FEATURE_XSAVE));
+}
+
+static void update_cpuid(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid_entry2 *best;
+
+	best = kvm_find_cpuid_entry(vcpu, 1, 0);
+	if (!best)
+		return;
+
+	/* Update OSXSAVE bit */
+	if (cpu_has_xsave && best->function == 0x1) {
+		best->ecx &= ~(bit(X86_FEATURE_OSXSAVE));
+		if (kvm_read_cr4_bits(vcpu, X86_CR4_OSXSAVE))
+			best->ecx |= bit(X86_FEATURE_OSXSAVE);
+	}
+}
+
+int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
 	unsigned long old_cr4 = kvm_read_cr4(vcpu);
 	unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE;
 
-	if (cr4 & CR4_RESERVED_BITS) {
-		kvm_inject_gp(vcpu, 0);
-		return;
-	}
+	if (cr4 & CR4_RESERVED_BITS)
+		return 1;
+
+	if (!guest_cpuid_has_xsave(vcpu) && (cr4 & X86_CR4_OSXSAVE))
+		return 1;
 
 	if (is_long_mode(vcpu)) {
-		if (!(cr4 & X86_CR4_PAE)) {
-			kvm_inject_gp(vcpu, 0);
-			return;
-		}
+		if (!(cr4 & X86_CR4_PAE))
+			return 1;
 	} else if (is_paging(vcpu) && (cr4 & X86_CR4_PAE)
 		   && ((cr4 ^ old_cr4) & pdptr_bits)
-		   && !load_pdptrs(vcpu, vcpu->arch.cr3)) {
-		kvm_inject_gp(vcpu, 0);
-		return;
-	}
+		   && !load_pdptrs(vcpu, vcpu->arch.cr3))
+		return 1;
 
-	if (cr4 & X86_CR4_VMXE) {
-		kvm_inject_gp(vcpu, 0);
-		return;
-	}
+	if (cr4 & X86_CR4_VMXE)
+		return 1;
+
 	kvm_x86_ops->set_cr4(vcpu, cr4);
-	vcpu->arch.cr4 = cr4;
-	kvm_mmu_reset_context(vcpu);
+
+	if ((cr4 ^ old_cr4) & pdptr_bits)
+		kvm_mmu_reset_context(vcpu);
+
+	if ((cr4 ^ old_cr4) & X86_CR4_OSXSAVE)
+		update_cpuid(vcpu);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(kvm_set_cr4);
 
-void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
+int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 {
 	if (cr3 == vcpu->arch.cr3 && !pdptrs_changed(vcpu)) {
 		kvm_mmu_sync_roots(vcpu);
 		kvm_mmu_flush_tlb(vcpu);
-		return;
+		return 0;
 	}
 
 	if (is_long_mode(vcpu)) {
-		if (cr3 & CR3_L_MODE_RESERVED_BITS) {
-			kvm_inject_gp(vcpu, 0);
-			return;
-		}
+		if (cr3 & CR3_L_MODE_RESERVED_BITS)
+			return 1;
 	} else {
 		if (is_pae(vcpu)) {
-			if (cr3 & CR3_PAE_RESERVED_BITS) {
-				kvm_inject_gp(vcpu, 0);
-				return;
-			}
-			if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) {
-				kvm_inject_gp(vcpu, 0);
-				return;
-			}
+			if (cr3 & CR3_PAE_RESERVED_BITS)
+				return 1;
+			if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3))
+				return 1;
 		}
 		/*
 		 * We don't check reserved bits in nonpae mode, because
@@ -546,24 +599,28 @@
 	 * to debug) behavior on the guest side.
 	 */
 	if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT)))
-		kvm_inject_gp(vcpu, 0);
-	else {
-		vcpu->arch.cr3 = cr3;
-		vcpu->arch.mmu.new_cr3(vcpu);
-	}
+		return 1;
+	vcpu->arch.cr3 = cr3;
+	vcpu->arch.mmu.new_cr3(vcpu);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(kvm_set_cr3);
 
-void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
+int __kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
 {
-	if (cr8 & CR8_RESERVED_BITS) {
-		kvm_inject_gp(vcpu, 0);
-		return;
-	}
+	if (cr8 & CR8_RESERVED_BITS)
+		return 1;
 	if (irqchip_in_kernel(vcpu->kvm))
 		kvm_lapic_set_tpr(vcpu, cr8);
 	else
 		vcpu->arch.cr8 = cr8;
+	return 0;
+}
+
+void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
+{
+	if (__kvm_set_cr8(vcpu, cr8))
+		kvm_inject_gp(vcpu, 0);
 }
 EXPORT_SYMBOL_GPL(kvm_set_cr8);
 
@@ -576,7 +633,7 @@
 }
 EXPORT_SYMBOL_GPL(kvm_get_cr8);
 
-int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
+static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
 {
 	switch (dr) {
 	case 0 ... 3:
@@ -585,29 +642,21 @@
 			vcpu->arch.eff_db[dr] = val;
 		break;
 	case 4:
-		if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-			kvm_queue_exception(vcpu, UD_VECTOR);
-			return 1;
-		}
+		if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
+			return 1; /* #UD */
 		/* fall through */
 	case 6:
-		if (val & 0xffffffff00000000ULL) {
-			kvm_inject_gp(vcpu, 0);
-			return 1;
-		}
+		if (val & 0xffffffff00000000ULL)
+			return -1; /* #GP */
 		vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1;
 		break;
 	case 5:
-		if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-			kvm_queue_exception(vcpu, UD_VECTOR);
-			return 1;
-		}
+		if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
+			return 1; /* #UD */
 		/* fall through */
 	default: /* 7 */
-		if (val & 0xffffffff00000000ULL) {
-			kvm_inject_gp(vcpu, 0);
-			return 1;
-		}
+		if (val & 0xffffffff00000000ULL)
+			return -1; /* #GP */
 		vcpu->arch.dr7 = (val & DR7_VOLATILE) | DR7_FIXED_1;
 		if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) {
 			kvm_x86_ops->set_dr7(vcpu, vcpu->arch.dr7);
@@ -618,28 +667,37 @@
 
 	return 0;
 }
+
+int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
+{
+	int res;
+
+	res = __kvm_set_dr(vcpu, dr, val);
+	if (res > 0)
+		kvm_queue_exception(vcpu, UD_VECTOR);
+	else if (res < 0)
+		kvm_inject_gp(vcpu, 0);
+
+	return res;
+}
 EXPORT_SYMBOL_GPL(kvm_set_dr);
 
-int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
+static int _kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
 {
 	switch (dr) {
 	case 0 ... 3:
 		*val = vcpu->arch.db[dr];
 		break;
 	case 4:
-		if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-			kvm_queue_exception(vcpu, UD_VECTOR);
+		if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
 			return 1;
-		}
 		/* fall through */
 	case 6:
 		*val = vcpu->arch.dr6;
 		break;
 	case 5:
-		if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-			kvm_queue_exception(vcpu, UD_VECTOR);
+		if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
 			return 1;
-		}
 		/* fall through */
 	default: /* 7 */
 		*val = vcpu->arch.dr7;
@@ -648,12 +706,16 @@
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(kvm_get_dr);
 
-static inline u32 bit(int bitno)
+int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
 {
-	return 1 << (bitno & 31);
+	if (_kvm_get_dr(vcpu, dr, val)) {
+		kvm_queue_exception(vcpu, UD_VECTOR);
+		return 1;
+	}
+	return 0;
 }
+EXPORT_SYMBOL_GPL(kvm_get_dr);
 
 /*
  * List of msr numbers which we expose to userspace through KVM_GET_MSRS
@@ -682,10 +744,14 @@
 
 static u32 emulated_msrs[] = {
 	MSR_IA32_MISC_ENABLE,
+	MSR_IA32_MCG_STATUS,
+	MSR_IA32_MCG_CTL,
 };
 
 static int set_efer(struct kvm_vcpu *vcpu, u64 efer)
 {
+	u64 old_efer = vcpu->arch.efer;
+
 	if (efer & efer_reserved_bits)
 		return 1;
 
@@ -714,11 +780,13 @@
 
 	kvm_x86_ops->set_efer(vcpu, efer);
 
-	vcpu->arch.efer = efer;
-
 	vcpu->arch.mmu.base_role.nxe = (efer & EFER_NX) && !tdp_enabled;
 	kvm_mmu_reset_context(vcpu);
 
+	/* Update reserved bits */
+	if ((efer ^ old_efer) & EFER_NX)
+		kvm_mmu_reset_context(vcpu);
+
 	return 0;
 }
 
@@ -882,7 +950,7 @@
 
 	if (!vcpu->time_page)
 		return 0;
-	set_bit(KVM_REQ_KVMCLOCK_UPDATE, &v->requests);
+	kvm_make_request(KVM_REQ_KVMCLOCK_UPDATE, v);
 	return 1;
 }
 
@@ -1524,16 +1592,12 @@
 {
 	int i, idx;
 
-	vcpu_load(vcpu);
-
 	idx = srcu_read_lock(&vcpu->kvm->srcu);
 	for (i = 0; i < msrs->nmsrs; ++i)
 		if (do_msr(vcpu, entries[i].index, &entries[i].data))
 			break;
 	srcu_read_unlock(&vcpu->kvm->srcu, idx);
 
-	vcpu_put(vcpu);
-
 	return i;
 }
 
@@ -1618,6 +1682,7 @@
 	case KVM_CAP_PCI_SEGMENT:
 	case KVM_CAP_DEBUGREGS:
 	case KVM_CAP_X86_ROBUST_SINGLESTEP:
+	case KVM_CAP_XSAVE:
 		r = 1;
 		break;
 	case KVM_CAP_COALESCED_MMIO:
@@ -1641,6 +1706,9 @@
 	case KVM_CAP_MCE:
 		r = KVM_MAX_MCE_BANKS;
 		break;
+	case KVM_CAP_XCRS:
+		r = cpu_has_xsave;
+		break;
 	default:
 		r = 0;
 		break;
@@ -1717,8 +1785,28 @@
 	return r;
 }
 
+static void wbinvd_ipi(void *garbage)
+{
+	wbinvd();
+}
+
+static bool need_emulate_wbinvd(struct kvm_vcpu *vcpu)
+{
+	return vcpu->kvm->arch.iommu_domain &&
+		!(vcpu->kvm->arch.iommu_flags & KVM_IOMMU_CACHE_COHERENCY);
+}
+
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
+	/* Address WBINVD may be executed by guest */
+	if (need_emulate_wbinvd(vcpu)) {
+		if (kvm_x86_ops->has_wbinvd_exit())
+			cpumask_set_cpu(cpu, vcpu->arch.wbinvd_dirty_mask);
+		else if (vcpu->cpu != -1 && vcpu->cpu != cpu)
+			smp_call_function_single(vcpu->cpu,
+					wbinvd_ipi, NULL, 1);
+	}
+
 	kvm_x86_ops->vcpu_load(vcpu, cpu);
 	if (unlikely(per_cpu(cpu_tsc_khz, cpu) == 0)) {
 		unsigned long khz = cpufreq_quick_get(cpu);
@@ -1731,8 +1819,8 @@
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
-	kvm_put_guest_fpu(vcpu);
 	kvm_x86_ops->vcpu_put(vcpu);
+	kvm_put_guest_fpu(vcpu);
 }
 
 static int is_efer_nx(void)
@@ -1781,7 +1869,6 @@
 	if (copy_from_user(cpuid_entries, entries,
 			   cpuid->nent * sizeof(struct kvm_cpuid_entry)))
 		goto out_free;
-	vcpu_load(vcpu);
 	for (i = 0; i < cpuid->nent; i++) {
 		vcpu->arch.cpuid_entries[i].function = cpuid_entries[i].function;
 		vcpu->arch.cpuid_entries[i].eax = cpuid_entries[i].eax;
@@ -1799,7 +1886,7 @@
 	r = 0;
 	kvm_apic_set_version(vcpu);
 	kvm_x86_ops->cpuid_update(vcpu);
-	vcpu_put(vcpu);
+	update_cpuid(vcpu);
 
 out_free:
 	vfree(cpuid_entries);
@@ -1820,11 +1907,10 @@
 	if (copy_from_user(&vcpu->arch.cpuid_entries, entries,
 			   cpuid->nent * sizeof(struct kvm_cpuid_entry2)))
 		goto out;
-	vcpu_load(vcpu);
 	vcpu->arch.cpuid_nent = cpuid->nent;
 	kvm_apic_set_version(vcpu);
 	kvm_x86_ops->cpuid_update(vcpu);
-	vcpu_put(vcpu);
+	update_cpuid(vcpu);
 	return 0;
 
 out:
@@ -1837,7 +1923,6 @@
 {
 	int r;
 
-	vcpu_load(vcpu);
 	r = -E2BIG;
 	if (cpuid->nent < vcpu->arch.cpuid_nent)
 		goto out;
@@ -1849,7 +1934,6 @@
 
 out:
 	cpuid->nent = vcpu->arch.cpuid_nent;
-	vcpu_put(vcpu);
 	return r;
 }
 
@@ -1901,13 +1985,13 @@
 		0 /* Reserved */ | f_lm | F(3DNOWEXT) | F(3DNOW);
 	/* cpuid 1.ecx */
 	const u32 kvm_supported_word4_x86_features =
-		F(XMM3) | 0 /* Reserved, DTES64, MONITOR */ |
+		F(XMM3) | F(PCLMULQDQ) | 0 /* DTES64, MONITOR */ |
 		0 /* DS-CPL, VMX, SMX, EST */ |
 		0 /* TM2 */ | F(SSSE3) | 0 /* CNXT-ID */ | 0 /* Reserved */ |
 		0 /* Reserved */ | F(CX16) | 0 /* xTPR Update, PDCM */ |
 		0 /* Reserved, DCA */ | F(XMM4_1) |
 		F(XMM4_2) | F(X2APIC) | F(MOVBE) | F(POPCNT) |
-		0 /* Reserved, XSAVE, OSXSAVE */;
+		0 /* Reserved, AES */ | F(XSAVE) | 0 /* OSXSAVE */ | F(AVX);
 	/* cpuid 0x80000001.ecx */
 	const u32 kvm_supported_word6_x86_features =
 		F(LAHF_LM) | F(CMP_LEGACY) | F(SVM) | 0 /* ExtApicSpace */ |
@@ -1922,7 +2006,7 @@
 
 	switch (function) {
 	case 0:
-		entry->eax = min(entry->eax, (u32)0xb);
+		entry->eax = min(entry->eax, (u32)0xd);
 		break;
 	case 1:
 		entry->edx &= kvm_supported_word0_x86_features;
@@ -1980,6 +2064,20 @@
 		}
 		break;
 	}
+	case 0xd: {
+		int i;
+
+		entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+		for (i = 1; *nent < maxnent; ++i) {
+			if (entry[i - 1].eax == 0 && i != 2)
+				break;
+			do_cpuid_1_ent(&entry[i], function, i);
+			entry[i].flags |=
+			       KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+			++*nent;
+		}
+		break;
+	}
 	case KVM_CPUID_SIGNATURE: {
 		char signature[12] = "KVMKVMKVM\0\0";
 		u32 *sigptr = (u32 *)signature;
@@ -2081,9 +2179,7 @@
 static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
 				    struct kvm_lapic_state *s)
 {
-	vcpu_load(vcpu);
 	memcpy(s->regs, vcpu->arch.apic->regs, sizeof *s);
-	vcpu_put(vcpu);
 
 	return 0;
 }
@@ -2091,11 +2187,9 @@
 static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
 				    struct kvm_lapic_state *s)
 {
-	vcpu_load(vcpu);
 	memcpy(vcpu->arch.apic->regs, s->regs, sizeof *s);
 	kvm_apic_post_state_restore(vcpu);
 	update_cr8_intercept(vcpu);
-	vcpu_put(vcpu);
 
 	return 0;
 }
@@ -2107,20 +2201,15 @@
 		return -EINVAL;
 	if (irqchip_in_kernel(vcpu->kvm))
 		return -ENXIO;
-	vcpu_load(vcpu);
 
 	kvm_queue_interrupt(vcpu, irq->irq, false);
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
 static int kvm_vcpu_ioctl_nmi(struct kvm_vcpu *vcpu)
 {
-	vcpu_load(vcpu);
 	kvm_inject_nmi(vcpu);
-	vcpu_put(vcpu);
 
 	return 0;
 }
@@ -2140,7 +2229,6 @@
 	int r;
 	unsigned bank_num = mcg_cap & 0xff, bank;
 
-	vcpu_load(vcpu);
 	r = -EINVAL;
 	if (!bank_num || bank_num >= KVM_MAX_MCE_BANKS)
 		goto out;
@@ -2155,7 +2243,6 @@
 	for (bank = 0; bank < bank_num; bank++)
 		vcpu->arch.mce_banks[bank*4] = ~(u64)0;
 out:
-	vcpu_put(vcpu);
 	return r;
 }
 
@@ -2188,7 +2275,7 @@
 			printk(KERN_DEBUG "kvm: set_mce: "
 			       "injects mce exception while "
 			       "previous one is in progress!\n");
-			set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
+			kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
 			return 0;
 		}
 		if (banks[1] & MCI_STATUS_VAL)
@@ -2213,8 +2300,6 @@
 static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
 					       struct kvm_vcpu_events *events)
 {
-	vcpu_load(vcpu);
-
 	events->exception.injected =
 		vcpu->arch.exception.pending &&
 		!kvm_exception_is_soft(vcpu->arch.exception.nr);
@@ -2239,8 +2324,6 @@
 	events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
 			 | KVM_VCPUEVENT_VALID_SIPI_VECTOR
 			 | KVM_VCPUEVENT_VALID_SHADOW);
-
-	vcpu_put(vcpu);
 }
 
 static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
@@ -2251,8 +2334,6 @@
 			      | KVM_VCPUEVENT_VALID_SHADOW))
 		return -EINVAL;
 
-	vcpu_load(vcpu);
-
 	vcpu->arch.exception.pending = events->exception.injected;
 	vcpu->arch.exception.nr = events->exception.nr;
 	vcpu->arch.exception.has_error_code = events->exception.has_error_code;
@@ -2275,22 +2356,16 @@
 	if (events->flags & KVM_VCPUEVENT_VALID_SIPI_VECTOR)
 		vcpu->arch.sipi_vector = events->sipi_vector;
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
 static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu,
 					     struct kvm_debugregs *dbgregs)
 {
-	vcpu_load(vcpu);
-
 	memcpy(dbgregs->db, vcpu->arch.db, sizeof(vcpu->arch.db));
 	dbgregs->dr6 = vcpu->arch.dr6;
 	dbgregs->dr7 = vcpu->arch.dr7;
 	dbgregs->flags = 0;
-
-	vcpu_put(vcpu);
 }
 
 static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
@@ -2299,40 +2374,113 @@
 	if (dbgregs->flags)
 		return -EINVAL;
 
-	vcpu_load(vcpu);
-
 	memcpy(vcpu->arch.db, dbgregs->db, sizeof(vcpu->arch.db));
 	vcpu->arch.dr6 = dbgregs->dr6;
 	vcpu->arch.dr7 = dbgregs->dr7;
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
+static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
+					 struct kvm_xsave *guest_xsave)
+{
+	if (cpu_has_xsave)
+		memcpy(guest_xsave->region,
+			&vcpu->arch.guest_fpu.state->xsave,
+			sizeof(struct xsave_struct));
+	else {
+		memcpy(guest_xsave->region,
+			&vcpu->arch.guest_fpu.state->fxsave,
+			sizeof(struct i387_fxsave_struct));
+		*(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)] =
+			XSTATE_FPSSE;
+	}
+}
+
+static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
+					struct kvm_xsave *guest_xsave)
+{
+	u64 xstate_bv =
+		*(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)];
+
+	if (cpu_has_xsave)
+		memcpy(&vcpu->arch.guest_fpu.state->xsave,
+			guest_xsave->region, sizeof(struct xsave_struct));
+	else {
+		if (xstate_bv & ~XSTATE_FPSSE)
+			return -EINVAL;
+		memcpy(&vcpu->arch.guest_fpu.state->fxsave,
+			guest_xsave->region, sizeof(struct i387_fxsave_struct));
+	}
+	return 0;
+}
+
+static void kvm_vcpu_ioctl_x86_get_xcrs(struct kvm_vcpu *vcpu,
+					struct kvm_xcrs *guest_xcrs)
+{
+	if (!cpu_has_xsave) {
+		guest_xcrs->nr_xcrs = 0;
+		return;
+	}
+
+	guest_xcrs->nr_xcrs = 1;
+	guest_xcrs->flags = 0;
+	guest_xcrs->xcrs[0].xcr = XCR_XFEATURE_ENABLED_MASK;
+	guest_xcrs->xcrs[0].value = vcpu->arch.xcr0;
+}
+
+static int kvm_vcpu_ioctl_x86_set_xcrs(struct kvm_vcpu *vcpu,
+				       struct kvm_xcrs *guest_xcrs)
+{
+	int i, r = 0;
+
+	if (!cpu_has_xsave)
+		return -EINVAL;
+
+	if (guest_xcrs->nr_xcrs > KVM_MAX_XCRS || guest_xcrs->flags)
+		return -EINVAL;
+
+	for (i = 0; i < guest_xcrs->nr_xcrs; i++)
+		/* Only support XCR0 currently */
+		if (guest_xcrs->xcrs[0].xcr == XCR_XFEATURE_ENABLED_MASK) {
+			r = __kvm_set_xcr(vcpu, XCR_XFEATURE_ENABLED_MASK,
+				guest_xcrs->xcrs[0].value);
+			break;
+		}
+	if (r)
+		r = -EINVAL;
+	return r;
+}
+
 long kvm_arch_vcpu_ioctl(struct file *filp,
 			 unsigned int ioctl, unsigned long arg)
 {
 	struct kvm_vcpu *vcpu = filp->private_data;
 	void __user *argp = (void __user *)arg;
 	int r;
-	struct kvm_lapic_state *lapic = NULL;
+	union {
+		struct kvm_lapic_state *lapic;
+		struct kvm_xsave *xsave;
+		struct kvm_xcrs *xcrs;
+		void *buffer;
+	} u;
 
+	u.buffer = NULL;
 	switch (ioctl) {
 	case KVM_GET_LAPIC: {
 		r = -EINVAL;
 		if (!vcpu->arch.apic)
 			goto out;
-		lapic = kzalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
+		u.lapic = kzalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
 
 		r = -ENOMEM;
-		if (!lapic)
+		if (!u.lapic)
 			goto out;
-		r = kvm_vcpu_ioctl_get_lapic(vcpu, lapic);
+		r = kvm_vcpu_ioctl_get_lapic(vcpu, u.lapic);
 		if (r)
 			goto out;
 		r = -EFAULT;
-		if (copy_to_user(argp, lapic, sizeof(struct kvm_lapic_state)))
+		if (copy_to_user(argp, u.lapic, sizeof(struct kvm_lapic_state)))
 			goto out;
 		r = 0;
 		break;
@@ -2341,14 +2489,14 @@
 		r = -EINVAL;
 		if (!vcpu->arch.apic)
 			goto out;
-		lapic = kmalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
+		u.lapic = kmalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
 		r = -ENOMEM;
-		if (!lapic)
+		if (!u.lapic)
 			goto out;
 		r = -EFAULT;
-		if (copy_from_user(lapic, argp, sizeof(struct kvm_lapic_state)))
+		if (copy_from_user(u.lapic, argp, sizeof(struct kvm_lapic_state)))
 			goto out;
-		r = kvm_vcpu_ioctl_set_lapic(vcpu, lapic);
+		r = kvm_vcpu_ioctl_set_lapic(vcpu, u.lapic);
 		if (r)
 			goto out;
 		r = 0;
@@ -2464,9 +2612,7 @@
 		r = -EFAULT;
 		if (copy_from_user(&mce, argp, sizeof mce))
 			goto out;
-		vcpu_load(vcpu);
 		r = kvm_vcpu_ioctl_x86_set_mce(vcpu, &mce);
-		vcpu_put(vcpu);
 		break;
 	}
 	case KVM_GET_VCPU_EVENTS: {
@@ -2513,11 +2659,67 @@
 		r = kvm_vcpu_ioctl_x86_set_debugregs(vcpu, &dbgregs);
 		break;
 	}
+	case KVM_GET_XSAVE: {
+		u.xsave = kzalloc(sizeof(struct kvm_xsave), GFP_KERNEL);
+		r = -ENOMEM;
+		if (!u.xsave)
+			break;
+
+		kvm_vcpu_ioctl_x86_get_xsave(vcpu, u.xsave);
+
+		r = -EFAULT;
+		if (copy_to_user(argp, u.xsave, sizeof(struct kvm_xsave)))
+			break;
+		r = 0;
+		break;
+	}
+	case KVM_SET_XSAVE: {
+		u.xsave = kzalloc(sizeof(struct kvm_xsave), GFP_KERNEL);
+		r = -ENOMEM;
+		if (!u.xsave)
+			break;
+
+		r = -EFAULT;
+		if (copy_from_user(u.xsave, argp, sizeof(struct kvm_xsave)))
+			break;
+
+		r = kvm_vcpu_ioctl_x86_set_xsave(vcpu, u.xsave);
+		break;
+	}
+	case KVM_GET_XCRS: {
+		u.xcrs = kzalloc(sizeof(struct kvm_xcrs), GFP_KERNEL);
+		r = -ENOMEM;
+		if (!u.xcrs)
+			break;
+
+		kvm_vcpu_ioctl_x86_get_xcrs(vcpu, u.xcrs);
+
+		r = -EFAULT;
+		if (copy_to_user(argp, u.xcrs,
+				 sizeof(struct kvm_xcrs)))
+			break;
+		r = 0;
+		break;
+	}
+	case KVM_SET_XCRS: {
+		u.xcrs = kzalloc(sizeof(struct kvm_xcrs), GFP_KERNEL);
+		r = -ENOMEM;
+		if (!u.xcrs)
+			break;
+
+		r = -EFAULT;
+		if (copy_from_user(u.xcrs, argp,
+				   sizeof(struct kvm_xcrs)))
+			break;
+
+		r = kvm_vcpu_ioctl_x86_set_xcrs(vcpu, u.xcrs);
+		break;
+	}
 	default:
 		r = -EINVAL;
 	}
 out:
-	kfree(lapic);
+	kfree(u.buffer);
 	return r;
 }
 
@@ -2560,115 +2762,6 @@
 	return kvm->arch.n_alloc_mmu_pages;
 }
 
-gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn)
-{
-	int i;
-	struct kvm_mem_alias *alias;
-	struct kvm_mem_aliases *aliases;
-
-	aliases = kvm_aliases(kvm);
-
-	for (i = 0; i < aliases->naliases; ++i) {
-		alias = &aliases->aliases[i];
-		if (alias->flags & KVM_ALIAS_INVALID)
-			continue;
-		if (gfn >= alias->base_gfn
-		    && gfn < alias->base_gfn + alias->npages)
-			return alias->target_gfn + gfn - alias->base_gfn;
-	}
-	return gfn;
-}
-
-gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
-{
-	int i;
-	struct kvm_mem_alias *alias;
-	struct kvm_mem_aliases *aliases;
-
-	aliases = kvm_aliases(kvm);
-
-	for (i = 0; i < aliases->naliases; ++i) {
-		alias = &aliases->aliases[i];
-		if (gfn >= alias->base_gfn
-		    && gfn < alias->base_gfn + alias->npages)
-			return alias->target_gfn + gfn - alias->base_gfn;
-	}
-	return gfn;
-}
-
-/*
- * Set a new alias region.  Aliases map a portion of physical memory into
- * another portion.  This is useful for memory windows, for example the PC
- * VGA region.
- */
-static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
-					 struct kvm_memory_alias *alias)
-{
-	int r, n;
-	struct kvm_mem_alias *p;
-	struct kvm_mem_aliases *aliases, *old_aliases;
-
-	r = -EINVAL;
-	/* General sanity checks */
-	if (alias->memory_size & (PAGE_SIZE - 1))
-		goto out;
-	if (alias->guest_phys_addr & (PAGE_SIZE - 1))
-		goto out;
-	if (alias->slot >= KVM_ALIAS_SLOTS)
-		goto out;
-	if (alias->guest_phys_addr + alias->memory_size
-	    < alias->guest_phys_addr)
-		goto out;
-	if (alias->target_phys_addr + alias->memory_size
-	    < alias->target_phys_addr)
-		goto out;
-
-	r = -ENOMEM;
-	aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
-	if (!aliases)
-		goto out;
-
-	mutex_lock(&kvm->slots_lock);
-
-	/* invalidate any gfn reference in case of deletion/shrinking */
-	memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases));
-	aliases->aliases[alias->slot].flags |= KVM_ALIAS_INVALID;
-	old_aliases = kvm->arch.aliases;
-	rcu_assign_pointer(kvm->arch.aliases, aliases);
-	synchronize_srcu_expedited(&kvm->srcu);
-	kvm_mmu_zap_all(kvm);
-	kfree(old_aliases);
-
-	r = -ENOMEM;
-	aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
-	if (!aliases)
-		goto out_unlock;
-
-	memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases));
-
-	p = &aliases->aliases[alias->slot];
-	p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
-	p->npages = alias->memory_size >> PAGE_SHIFT;
-	p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT;
-	p->flags &= ~(KVM_ALIAS_INVALID);
-
-	for (n = KVM_ALIAS_SLOTS; n > 0; --n)
-		if (aliases->aliases[n - 1].npages)
-			break;
-	aliases->naliases = n;
-
-	old_aliases = kvm->arch.aliases;
-	rcu_assign_pointer(kvm->arch.aliases, aliases);
-	synchronize_srcu_expedited(&kvm->srcu);
-	kfree(old_aliases);
-	r = 0;
-
-out_unlock:
-	mutex_unlock(&kvm->slots_lock);
-out:
-	return r;
-}
-
 static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
 {
 	int r;
@@ -2797,7 +2890,6 @@
 	struct kvm_memory_slot *memslot;
 	unsigned long n;
 	unsigned long is_dirty = 0;
-	unsigned long *dirty_bitmap = NULL;
 
 	mutex_lock(&kvm->slots_lock);
 
@@ -2812,27 +2904,30 @@
 
 	n = kvm_dirty_bitmap_bytes(memslot);
 
-	r = -ENOMEM;
-	dirty_bitmap = vmalloc(n);
-	if (!dirty_bitmap)
-		goto out;
-	memset(dirty_bitmap, 0, n);
-
 	for (i = 0; !is_dirty && i < n/sizeof(long); i++)
 		is_dirty = memslot->dirty_bitmap[i];
 
 	/* If nothing is dirty, don't bother messing with page tables. */
 	if (is_dirty) {
 		struct kvm_memslots *slots, *old_slots;
+		unsigned long *dirty_bitmap;
 
 		spin_lock(&kvm->mmu_lock);
 		kvm_mmu_slot_remove_write_access(kvm, log->slot);
 		spin_unlock(&kvm->mmu_lock);
 
-		slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
-		if (!slots)
-			goto out_free;
+		r = -ENOMEM;
+		dirty_bitmap = vmalloc(n);
+		if (!dirty_bitmap)
+			goto out;
+		memset(dirty_bitmap, 0, n);
 
+		r = -ENOMEM;
+		slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
+		if (!slots) {
+			vfree(dirty_bitmap);
+			goto out;
+		}
 		memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots));
 		slots->memslots[log->slot].dirty_bitmap = dirty_bitmap;
 
@@ -2841,13 +2936,20 @@
 		synchronize_srcu_expedited(&kvm->srcu);
 		dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap;
 		kfree(old_slots);
+
+		r = -EFAULT;
+		if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n)) {
+			vfree(dirty_bitmap);
+			goto out;
+		}
+		vfree(dirty_bitmap);
+	} else {
+		r = -EFAULT;
+		if (clear_user(log->dirty_bitmap, n))
+			goto out;
 	}
 
 	r = 0;
-	if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n))
-		r = -EFAULT;
-out_free:
-	vfree(dirty_bitmap);
 out:
 	mutex_unlock(&kvm->slots_lock);
 	return r;
@@ -2867,7 +2969,6 @@
 	union {
 		struct kvm_pit_state ps;
 		struct kvm_pit_state2 ps2;
-		struct kvm_memory_alias alias;
 		struct kvm_pit_config pit_config;
 	} u;
 
@@ -2888,22 +2989,6 @@
 			goto out;
 		break;
 	}
-	case KVM_SET_MEMORY_REGION: {
-		struct kvm_memory_region kvm_mem;
-		struct kvm_userspace_memory_region kvm_userspace_mem;
-
-		r = -EFAULT;
-		if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
-			goto out;
-		kvm_userspace_mem.slot = kvm_mem.slot;
-		kvm_userspace_mem.flags = kvm_mem.flags;
-		kvm_userspace_mem.guest_phys_addr = kvm_mem.guest_phys_addr;
-		kvm_userspace_mem.memory_size = kvm_mem.memory_size;
-		r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 0);
-		if (r)
-			goto out;
-		break;
-	}
 	case KVM_SET_NR_MMU_PAGES:
 		r = kvm_vm_ioctl_set_nr_mmu_pages(kvm, arg);
 		if (r)
@@ -2912,14 +2997,6 @@
 	case KVM_GET_NR_MMU_PAGES:
 		r = kvm_vm_ioctl_get_nr_mmu_pages(kvm);
 		break;
-	case KVM_SET_MEMORY_ALIAS:
-		r = -EFAULT;
-		if (copy_from_user(&u.alias, argp, sizeof(struct kvm_memory_alias)))
-			goto out;
-		r = kvm_vm_ioctl_set_memory_alias(kvm, &u.alias);
-		if (r)
-			goto out;
-		break;
 	case KVM_CREATE_IRQCHIP: {
 		struct kvm_pic *vpic;
 
@@ -3259,7 +3336,7 @@
 		}
 		ret = kvm_read_guest(vcpu->kvm, gpa, data, toread);
 		if (ret < 0) {
-			r = X86EMUL_UNHANDLEABLE;
+			r = X86EMUL_IO_NEEDED;
 			goto out;
 		}
 
@@ -3315,7 +3392,7 @@
 		}
 		ret = kvm_write_guest(vcpu->kvm, gpa, data, towrite);
 		if (ret < 0) {
-			r = X86EMUL_UNHANDLEABLE;
+			r = X86EMUL_IO_NEEDED;
 			goto out;
 		}
 
@@ -3330,10 +3407,10 @@
 static int emulator_read_emulated(unsigned long addr,
 				  void *val,
 				  unsigned int bytes,
+				  unsigned int *error_code,
 				  struct kvm_vcpu *vcpu)
 {
 	gpa_t                 gpa;
-	u32 error_code;
 
 	if (vcpu->mmio_read_completed) {
 		memcpy(val, vcpu->mmio_data, bytes);
@@ -3343,12 +3420,10 @@
 		return X86EMUL_CONTINUE;
 	}
 
-	gpa = kvm_mmu_gva_to_gpa_read(vcpu, addr, &error_code);
+	gpa = kvm_mmu_gva_to_gpa_read(vcpu, addr, error_code);
 
-	if (gpa == UNMAPPED_GVA) {
-		kvm_inject_page_fault(vcpu, addr, error_code);
+	if (gpa == UNMAPPED_GVA)
 		return X86EMUL_PROPAGATE_FAULT;
-	}
 
 	/* For APIC access vmexit */
 	if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
@@ -3370,11 +3445,12 @@
 	trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, 0);
 
 	vcpu->mmio_needed = 1;
-	vcpu->mmio_phys_addr = gpa;
-	vcpu->mmio_size = bytes;
-	vcpu->mmio_is_write = 0;
+	vcpu->run->exit_reason = KVM_EXIT_MMIO;
+	vcpu->run->mmio.phys_addr = vcpu->mmio_phys_addr = gpa;
+	vcpu->run->mmio.len = vcpu->mmio_size = bytes;
+	vcpu->run->mmio.is_write = vcpu->mmio_is_write = 0;
 
-	return X86EMUL_UNHANDLEABLE;
+	return X86EMUL_IO_NEEDED;
 }
 
 int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
@@ -3392,17 +3468,15 @@
 static int emulator_write_emulated_onepage(unsigned long addr,
 					   const void *val,
 					   unsigned int bytes,
+					   unsigned int *error_code,
 					   struct kvm_vcpu *vcpu)
 {
 	gpa_t                 gpa;
-	u32 error_code;
 
-	gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, &error_code);
+	gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error_code);
 
-	if (gpa == UNMAPPED_GVA) {
-		kvm_inject_page_fault(vcpu, addr, error_code);
+	if (gpa == UNMAPPED_GVA)
 		return X86EMUL_PROPAGATE_FAULT;
-	}
 
 	/* For APIC access vmexit */
 	if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
@@ -3420,10 +3494,11 @@
 		return X86EMUL_CONTINUE;
 
 	vcpu->mmio_needed = 1;
-	vcpu->mmio_phys_addr = gpa;
-	vcpu->mmio_size = bytes;
-	vcpu->mmio_is_write = 1;
-	memcpy(vcpu->mmio_data, val, bytes);
+	vcpu->run->exit_reason = KVM_EXIT_MMIO;
+	vcpu->run->mmio.phys_addr = vcpu->mmio_phys_addr = gpa;
+	vcpu->run->mmio.len = vcpu->mmio_size = bytes;
+	vcpu->run->mmio.is_write = vcpu->mmio_is_write = 1;
+	memcpy(vcpu->run->mmio.data, val, bytes);
 
 	return X86EMUL_CONTINUE;
 }
@@ -3431,6 +3506,7 @@
 int emulator_write_emulated(unsigned long addr,
 			    const void *val,
 			    unsigned int bytes,
+			    unsigned int *error_code,
 			    struct kvm_vcpu *vcpu)
 {
 	/* Crossing a page boundary? */
@@ -3438,16 +3514,17 @@
 		int rc, now;
 
 		now = -addr & ~PAGE_MASK;
-		rc = emulator_write_emulated_onepage(addr, val, now, vcpu);
+		rc = emulator_write_emulated_onepage(addr, val, now, error_code,
+						     vcpu);
 		if (rc != X86EMUL_CONTINUE)
 			return rc;
 		addr += now;
 		val += now;
 		bytes -= now;
 	}
-	return emulator_write_emulated_onepage(addr, val, bytes, vcpu);
+	return emulator_write_emulated_onepage(addr, val, bytes, error_code,
+					       vcpu);
 }
-EXPORT_SYMBOL_GPL(emulator_write_emulated);
 
 #define CMPXCHG_TYPE(t, ptr, old, new) \
 	(cmpxchg((t *)(ptr), *(t *)(old), *(t *)(new)) == *(t *)(old))
@@ -3463,6 +3540,7 @@
 				     const void *old,
 				     const void *new,
 				     unsigned int bytes,
+				     unsigned int *error_code,
 				     struct kvm_vcpu *vcpu)
 {
 	gpa_t gpa;
@@ -3484,6 +3562,10 @@
 		goto emul_write;
 
 	page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
+	if (is_error_page(page)) {
+		kvm_release_page_clean(page);
+		goto emul_write;
+	}
 
 	kaddr = kmap_atomic(page, KM_USER0);
 	kaddr += offset_in_page(gpa);
@@ -3516,7 +3598,7 @@
 emul_write:
 	printk_once(KERN_WARNING "kvm: emulating exchange as write\n");
 
-	return emulator_write_emulated(addr, new, bytes, vcpu);
+	return emulator_write_emulated(addr, new, bytes, error_code, vcpu);
 }
 
 static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
@@ -3604,6 +3686,21 @@
 	return X86EMUL_CONTINUE;
 }
 
+int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu)
+{
+	if (!need_emulate_wbinvd(vcpu))
+		return X86EMUL_CONTINUE;
+
+	if (kvm_x86_ops->has_wbinvd_exit()) {
+		smp_call_function_many(vcpu->arch.wbinvd_dirty_mask,
+				wbinvd_ipi, NULL, 1);
+		cpumask_clear(vcpu->arch.wbinvd_dirty_mask);
+	}
+	wbinvd();
+	return X86EMUL_CONTINUE;
+}
+EXPORT_SYMBOL_GPL(kvm_emulate_wbinvd);
+
 int emulate_clts(struct kvm_vcpu *vcpu)
 {
 	kvm_x86_ops->set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~X86_CR0_TS));
@@ -3611,36 +3708,17 @@
 	return X86EMUL_CONTINUE;
 }
 
-int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest)
+int emulator_get_dr(int dr, unsigned long *dest, struct kvm_vcpu *vcpu)
 {
-	return kvm_get_dr(ctxt->vcpu, dr, dest);
+	return _kvm_get_dr(vcpu, dr, dest);
 }
 
-int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
+int emulator_set_dr(int dr, unsigned long value, struct kvm_vcpu *vcpu)
 {
-	unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
 
-	return kvm_set_dr(ctxt->vcpu, dr, value & mask);
+	return __kvm_set_dr(vcpu, dr, value);
 }
 
-void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
-{
-	u8 opcodes[4];
-	unsigned long rip = kvm_rip_read(vcpu);
-	unsigned long rip_linear;
-
-	if (!printk_ratelimit())
-		return;
-
-	rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS);
-
-	kvm_read_guest_virt(rip_linear, (void *)opcodes, 4, vcpu, NULL);
-
-	printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n",
-	       context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
-}
-EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
-
 static u64 mk_cr_64(u64 curr_cr, u32 new_val)
 {
 	return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
@@ -3674,27 +3752,32 @@
 	return value;
 }
 
-static void emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
+static int emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
 {
+	int res = 0;
+
 	switch (cr) {
 	case 0:
-		kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
+		res = kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
 		break;
 	case 2:
 		vcpu->arch.cr2 = val;
 		break;
 	case 3:
-		kvm_set_cr3(vcpu, val);
+		res = kvm_set_cr3(vcpu, val);
 		break;
 	case 4:
-		kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
+		res = kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
 		break;
 	case 8:
-		kvm_set_cr8(vcpu, val & 0xfUL);
+		res = __kvm_set_cr8(vcpu, val & 0xfUL);
 		break;
 	default:
 		vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
+		res = -1;
 	}
+
+	return res;
 }
 
 static int emulator_get_cpl(struct kvm_vcpu *vcpu)
@@ -3707,6 +3790,12 @@
 	kvm_x86_ops->get_gdt(vcpu, dt);
 }
 
+static unsigned long emulator_get_cached_segment_base(int seg,
+						      struct kvm_vcpu *vcpu)
+{
+	return get_segment_base(vcpu, seg);
+}
+
 static bool emulator_get_cached_descriptor(struct desc_struct *desc, int seg,
 					   struct kvm_vcpu *vcpu)
 {
@@ -3779,11 +3868,6 @@
 	kvm_set_segment(vcpu, &kvm_seg, seg);
 }
 
-static void emulator_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
-{
-	kvm_x86_ops->set_rflags(vcpu, rflags);
-}
-
 static struct x86_emulate_ops emulate_ops = {
 	.read_std            = kvm_read_guest_virt_system,
 	.write_std           = kvm_write_guest_virt_system,
@@ -3797,11 +3881,15 @@
 	.set_cached_descriptor = emulator_set_cached_descriptor,
 	.get_segment_selector = emulator_get_segment_selector,
 	.set_segment_selector = emulator_set_segment_selector,
+	.get_cached_segment_base = emulator_get_cached_segment_base,
 	.get_gdt             = emulator_get_gdt,
 	.get_cr              = emulator_get_cr,
 	.set_cr              = emulator_set_cr,
 	.cpl                 = emulator_get_cpl,
-	.set_rflags          = emulator_set_rflags,
+	.get_dr              = emulator_get_dr,
+	.set_dr              = emulator_set_dr,
+	.set_msr             = kvm_set_msr,
+	.get_msr             = kvm_get_msr,
 };
 
 static void cache_all_regs(struct kvm_vcpu *vcpu)
@@ -3812,14 +3900,75 @@
 	vcpu->arch.regs_dirty = ~0;
 }
 
+static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask)
+{
+	u32 int_shadow = kvm_x86_ops->get_interrupt_shadow(vcpu, mask);
+	/*
+	 * an sti; sti; sequence only disable interrupts for the first
+	 * instruction. So, if the last instruction, be it emulated or
+	 * not, left the system with the INT_STI flag enabled, it
+	 * means that the last instruction is an sti. We should not
+	 * leave the flag on in this case. The same goes for mov ss
+	 */
+	if (!(int_shadow & mask))
+		kvm_x86_ops->set_interrupt_shadow(vcpu, mask);
+}
+
+static void inject_emulated_exception(struct kvm_vcpu *vcpu)
+{
+	struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
+	if (ctxt->exception == PF_VECTOR)
+		kvm_inject_page_fault(vcpu, ctxt->cr2, ctxt->error_code);
+	else if (ctxt->error_code_valid)
+		kvm_queue_exception_e(vcpu, ctxt->exception, ctxt->error_code);
+	else
+		kvm_queue_exception(vcpu, ctxt->exception);
+}
+
+static int handle_emulation_failure(struct kvm_vcpu *vcpu)
+{
+	++vcpu->stat.insn_emulation_fail;
+	trace_kvm_emulate_insn_failed(vcpu);
+	vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+	vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
+	vcpu->run->internal.ndata = 0;
+	kvm_queue_exception(vcpu, UD_VECTOR);
+	return EMULATE_FAIL;
+}
+
+static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t gva)
+{
+	gpa_t gpa;
+
+	if (tdp_enabled)
+		return false;
+
+	/*
+	 * if emulation was due to access to shadowed page table
+	 * and it failed try to unshadow page and re-entetr the
+	 * guest to let CPU execute the instruction.
+	 */
+	if (kvm_mmu_unprotect_page_virt(vcpu, gva))
+		return true;
+
+	gpa = kvm_mmu_gva_to_gpa_system(vcpu, gva, NULL);
+
+	if (gpa == UNMAPPED_GVA)
+		return true; /* let cpu generate fault */
+
+	if (!kvm_is_error_hva(gfn_to_hva(vcpu->kvm, gpa >> PAGE_SHIFT)))
+		return true;
+
+	return false;
+}
+
 int emulate_instruction(struct kvm_vcpu *vcpu,
 			unsigned long cr2,
 			u16 error_code,
 			int emulation_type)
 {
-	int r, shadow_mask;
-	struct decode_cache *c;
-	struct kvm_run *run = vcpu->run;
+	int r;
+	struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
 
 	kvm_clear_exception_queue(vcpu);
 	vcpu->arch.mmio_fault_cr2 = cr2;
@@ -3831,8 +3980,6 @@
 	 */
 	cache_all_regs(vcpu);
 
-	vcpu->mmio_is_write = 0;
-
 	if (!(emulation_type & EMULTYPE_NO_DECODE)) {
 		int cs_db, cs_l;
 		kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
@@ -3846,13 +3993,16 @@
 			? X86EMUL_MODE_VM86 : cs_l
 			? X86EMUL_MODE_PROT64 :	cs_db
 			? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+		memset(c, 0, sizeof(struct decode_cache));
+		memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
+		vcpu->arch.emulate_ctxt.interruptibility = 0;
+		vcpu->arch.emulate_ctxt.exception = -1;
 
 		r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
 		trace_kvm_emulate_insn_start(vcpu);
 
 		/* Only allow emulation of specific instructions on #UD
 		 * (namely VMMCALL, sysenter, sysexit, syscall)*/
-		c = &vcpu->arch.emulate_ctxt.decode;
 		if (emulation_type & EMULTYPE_TRAP_UD) {
 			if (!c->twobyte)
 				return EMULATE_FAIL;
@@ -3880,11 +4030,11 @@
 
 		++vcpu->stat.insn_emulation;
 		if (r)  {
-			++vcpu->stat.insn_emulation_fail;
-			trace_kvm_emulate_insn_failed(vcpu);
-			if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
+			if (reexecute_instruction(vcpu, cr2))
 				return EMULATE_DONE;
-			return EMULATE_FAIL;
+			if (emulation_type & EMULTYPE_SKIP)
+				return EMULATE_FAIL;
+			return handle_emulation_failure(vcpu);
 		}
 	}
 
@@ -3893,12 +4043,29 @@
 		return EMULATE_DONE;
 	}
 
+	/* this is needed for vmware backdor interface to work since it
+	   changes registers values  during IO operation */
+	memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
+
 restart:
 	r = x86_emulate_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
-	shadow_mask = vcpu->arch.emulate_ctxt.interruptibility;
 
-	if (r == 0)
-		kvm_x86_ops->set_interrupt_shadow(vcpu, shadow_mask);
+	if (r) { /* emulation failed */
+		if (reexecute_instruction(vcpu, cr2))
+			return EMULATE_DONE;
+
+		return handle_emulation_failure(vcpu);
+	}
+
+	toggle_interruptibility(vcpu, vcpu->arch.emulate_ctxt.interruptibility);
+	kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
+	memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
+	kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
+
+	if (vcpu->arch.emulate_ctxt.exception >= 0) {
+		inject_emulated_exception(vcpu);
+		return EMULATE_DONE;
+	}
 
 	if (vcpu->arch.pio.count) {
 		if (!vcpu->arch.pio.in)
@@ -3906,35 +4073,12 @@
 		return EMULATE_DO_MMIO;
 	}
 
-	if (r || vcpu->mmio_is_write) {
-		run->exit_reason = KVM_EXIT_MMIO;
-		run->mmio.phys_addr = vcpu->mmio_phys_addr;
-		memcpy(run->mmio.data, vcpu->mmio_data, 8);
-		run->mmio.len = vcpu->mmio_size;
-		run->mmio.is_write = vcpu->mmio_is_write;
-	}
-
-	if (r) {
-		if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
-			goto done;
-		if (!vcpu->mmio_needed) {
-			++vcpu->stat.insn_emulation_fail;
-			trace_kvm_emulate_insn_failed(vcpu);
-			kvm_report_emulation_failure(vcpu, "mmio");
-			return EMULATE_FAIL;
-		}
+	if (vcpu->mmio_needed) {
+		if (vcpu->mmio_is_write)
+			vcpu->mmio_needed = 0;
 		return EMULATE_DO_MMIO;
 	}
 
-	if (vcpu->mmio_is_write) {
-		vcpu->mmio_needed = 0;
-		return EMULATE_DO_MMIO;
-	}
-
-done:
-	if (vcpu->arch.exception.pending)
-		vcpu->arch.emulate_ctxt.restart = false;
-
 	if (vcpu->arch.emulate_ctxt.restart)
 		goto restart;
 
@@ -4108,6 +4252,9 @@
 
 	perf_register_guest_info_callbacks(&kvm_guest_cbs);
 
+	if (cpu_has_xsave)
+		host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
+
 	return 0;
 
 out:
@@ -4270,7 +4417,7 @@
 
 	kvm_x86_ops->patch_hypercall(vcpu, instruction);
 
-	return emulator_write_emulated(rip, instruction, 3, vcpu);
+	return emulator_write_emulated(rip, instruction, 3, NULL, vcpu);
 }
 
 void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
@@ -4506,59 +4653,78 @@
 	}
 }
 
+static void kvm_load_guest_xcr0(struct kvm_vcpu *vcpu)
+{
+	if (kvm_read_cr4_bits(vcpu, X86_CR4_OSXSAVE) &&
+			!vcpu->guest_xcr0_loaded) {
+		/* kvm_set_xcr() also depends on this */
+		xsetbv(XCR_XFEATURE_ENABLED_MASK, vcpu->arch.xcr0);
+		vcpu->guest_xcr0_loaded = 1;
+	}
+}
+
+static void kvm_put_guest_xcr0(struct kvm_vcpu *vcpu)
+{
+	if (vcpu->guest_xcr0_loaded) {
+		if (vcpu->arch.xcr0 != host_xcr0)
+			xsetbv(XCR_XFEATURE_ENABLED_MASK, host_xcr0);
+		vcpu->guest_xcr0_loaded = 0;
+	}
+}
+
 static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 {
 	int r;
 	bool req_int_win = !irqchip_in_kernel(vcpu->kvm) &&
 		vcpu->run->request_interrupt_window;
 
-	if (vcpu->requests)
-		if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
-			kvm_mmu_unload(vcpu);
-
-	r = kvm_mmu_reload(vcpu);
-	if (unlikely(r))
-		goto out;
-
 	if (vcpu->requests) {
-		if (test_and_clear_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests))
+		if (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu))
+			kvm_mmu_unload(vcpu);
+		if (kvm_check_request(KVM_REQ_MIGRATE_TIMER, vcpu))
 			__kvm_migrate_timers(vcpu);
-		if (test_and_clear_bit(KVM_REQ_KVMCLOCK_UPDATE, &vcpu->requests))
+		if (kvm_check_request(KVM_REQ_KVMCLOCK_UPDATE, vcpu))
 			kvm_write_guest_time(vcpu);
-		if (test_and_clear_bit(KVM_REQ_MMU_SYNC, &vcpu->requests))
+		if (kvm_check_request(KVM_REQ_MMU_SYNC, vcpu))
 			kvm_mmu_sync_roots(vcpu);
-		if (test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))
+		if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu))
 			kvm_x86_ops->tlb_flush(vcpu);
-		if (test_and_clear_bit(KVM_REQ_REPORT_TPR_ACCESS,
-				       &vcpu->requests)) {
+		if (kvm_check_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu)) {
 			vcpu->run->exit_reason = KVM_EXIT_TPR_ACCESS;
 			r = 0;
 			goto out;
 		}
-		if (test_and_clear_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests)) {
+		if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
 			vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
 			r = 0;
 			goto out;
 		}
-		if (test_and_clear_bit(KVM_REQ_DEACTIVATE_FPU, &vcpu->requests)) {
+		if (kvm_check_request(KVM_REQ_DEACTIVATE_FPU, vcpu)) {
 			vcpu->fpu_active = 0;
 			kvm_x86_ops->fpu_deactivate(vcpu);
 		}
 	}
 
+	r = kvm_mmu_reload(vcpu);
+	if (unlikely(r))
+		goto out;
+
 	preempt_disable();
 
 	kvm_x86_ops->prepare_guest_switch(vcpu);
 	if (vcpu->fpu_active)
 		kvm_load_guest_fpu(vcpu);
+	kvm_load_guest_xcr0(vcpu);
+
+	atomic_set(&vcpu->guest_mode, 1);
+	smp_wmb();
 
 	local_irq_disable();
 
-	clear_bit(KVM_REQ_KICK, &vcpu->requests);
-	smp_mb__after_clear_bit();
-
-	if (vcpu->requests || need_resched() || signal_pending(current)) {
-		set_bit(KVM_REQ_KICK, &vcpu->requests);
+	if (!atomic_read(&vcpu->guest_mode) || vcpu->requests
+	    || need_resched() || signal_pending(current)) {
+		atomic_set(&vcpu->guest_mode, 0);
+		smp_wmb();
 		local_irq_enable();
 		preempt_enable();
 		r = 1;
@@ -4603,7 +4769,8 @@
 	if (hw_breakpoint_active())
 		hw_breakpoint_restore();
 
-	set_bit(KVM_REQ_KICK, &vcpu->requests);
+	atomic_set(&vcpu->guest_mode, 0);
+	smp_wmb();
 	local_irq_enable();
 
 	++vcpu->stat.exits;
@@ -4665,7 +4832,7 @@
 			srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
 			kvm_vcpu_block(vcpu);
 			vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
-			if (test_and_clear_bit(KVM_REQ_UNHALT, &vcpu->requests))
+			if (kvm_check_request(KVM_REQ_UNHALT, vcpu))
 			{
 				switch(vcpu->arch.mp_state) {
 				case KVM_MP_STATE_HALTED:
@@ -4717,8 +4884,6 @@
 	int r;
 	sigset_t sigsaved;
 
-	vcpu_load(vcpu);
-
 	if (vcpu->sigset_active)
 		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
 
@@ -4743,7 +4908,7 @@
 		vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
 		r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE);
 		srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
-		if (r == EMULATE_DO_MMIO) {
+		if (r != EMULATE_DONE) {
 			r = 0;
 			goto out;
 		}
@@ -4759,14 +4924,11 @@
 	if (vcpu->sigset_active)
 		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
 
-	vcpu_put(vcpu);
 	return r;
 }
 
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
-	vcpu_load(vcpu);
-
 	regs->rax = kvm_register_read(vcpu, VCPU_REGS_RAX);
 	regs->rbx = kvm_register_read(vcpu, VCPU_REGS_RBX);
 	regs->rcx = kvm_register_read(vcpu, VCPU_REGS_RCX);
@@ -4789,15 +4951,11 @@
 	regs->rip = kvm_rip_read(vcpu);
 	regs->rflags = kvm_get_rflags(vcpu);
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
-	vcpu_load(vcpu);
-
 	kvm_register_write(vcpu, VCPU_REGS_RAX, regs->rax);
 	kvm_register_write(vcpu, VCPU_REGS_RBX, regs->rbx);
 	kvm_register_write(vcpu, VCPU_REGS_RCX, regs->rcx);
@@ -4822,8 +4980,6 @@
 
 	vcpu->arch.exception.pending = false;
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
@@ -4842,8 +4998,6 @@
 {
 	struct desc_ptr dt;
 
-	vcpu_load(vcpu);
-
 	kvm_get_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
 	kvm_get_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
 	kvm_get_segment(vcpu, &sregs->es, VCPU_SREG_ES);
@@ -4875,32 +5029,27 @@
 		set_bit(vcpu->arch.interrupt.nr,
 			(unsigned long *)sregs->interrupt_bitmap);
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
 				    struct kvm_mp_state *mp_state)
 {
-	vcpu_load(vcpu);
 	mp_state->mp_state = vcpu->arch.mp_state;
-	vcpu_put(vcpu);
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
 				    struct kvm_mp_state *mp_state)
 {
-	vcpu_load(vcpu);
 	vcpu->arch.mp_state = mp_state->mp_state;
-	vcpu_put(vcpu);
 	return 0;
 }
 
 int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
 		    bool has_error_code, u32 error_code)
 {
+	struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
 	int cs_db, cs_l, ret;
 	cache_all_regs(vcpu);
 
@@ -4915,6 +5064,8 @@
 		? X86EMUL_MODE_VM86 : cs_l
 		? X86EMUL_MODE_PROT64 :	cs_db
 		? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+	memset(c, 0, sizeof(struct decode_cache));
+	memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
 
 	ret = emulator_task_switch(&vcpu->arch.emulate_ctxt, &emulate_ops,
 				   tss_selector, reason, has_error_code,
@@ -4923,6 +5074,8 @@
 	if (ret)
 		return EMULATE_FAIL;
 
+	memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
+	kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
 	kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
 	return EMULATE_DONE;
 }
@@ -4935,8 +5088,6 @@
 	int pending_vec, max_bits;
 	struct desc_ptr dt;
 
-	vcpu_load(vcpu);
-
 	dt.size = sregs->idt.limit;
 	dt.address = sregs->idt.base;
 	kvm_x86_ops->set_idt(vcpu, &dt);
@@ -4996,8 +5147,6 @@
 	    !is_protmode(vcpu))
 		vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
@@ -5007,12 +5156,10 @@
 	unsigned long rflags;
 	int i, r;
 
-	vcpu_load(vcpu);
-
 	if (dbg->control & (KVM_GUESTDBG_INJECT_DB | KVM_GUESTDBG_INJECT_BP)) {
 		r = -EBUSY;
 		if (vcpu->arch.exception.pending)
-			goto unlock_out;
+			goto out;
 		if (dbg->control & KVM_GUESTDBG_INJECT_DB)
 			kvm_queue_exception(vcpu, DB_VECTOR);
 		else
@@ -5054,34 +5201,12 @@
 
 	r = 0;
 
-unlock_out:
-	vcpu_put(vcpu);
+out:
 
 	return r;
 }
 
 /*
- * fxsave fpu state.  Taken from x86_64/processor.h.  To be killed when
- * we have asm/x86/processor.h
- */
-struct fxsave {
-	u16	cwd;
-	u16	swd;
-	u16	twd;
-	u16	fop;
-	u64	rip;
-	u64	rdp;
-	u32	mxcsr;
-	u32	mxcsr_mask;
-	u32	st_space[32];	/* 8*16 bytes for each FP-reg = 128 bytes */
-#ifdef CONFIG_X86_64
-	u32	xmm_space[64];	/* 16*16 bytes for each XMM-reg = 256 bytes */
-#else
-	u32	xmm_space[32];	/* 8*16 bytes for each XMM-reg = 128 bytes */
-#endif
-};
-
-/*
  * Translate a guest virtual address to a guest physical address.
  */
 int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
@@ -5091,7 +5216,6 @@
 	gpa_t gpa;
 	int idx;
 
-	vcpu_load(vcpu);
 	idx = srcu_read_lock(&vcpu->kvm->srcu);
 	gpa = kvm_mmu_gva_to_gpa_system(vcpu, vaddr, NULL);
 	srcu_read_unlock(&vcpu->kvm->srcu, idx);
@@ -5099,16 +5223,14 @@
 	tr->valid = gpa != UNMAPPED_GVA;
 	tr->writeable = 1;
 	tr->usermode = 0;
-	vcpu_put(vcpu);
 
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
-	struct fxsave *fxsave = (struct fxsave *)&vcpu->arch.guest_fx_image;
-
-	vcpu_load(vcpu);
+	struct i387_fxsave_struct *fxsave =
+			&vcpu->arch.guest_fpu.state->fxsave;
 
 	memcpy(fpu->fpr, fxsave->st_space, 128);
 	fpu->fcw = fxsave->cwd;
@@ -5119,16 +5241,13 @@
 	fpu->last_dp = fxsave->rdp;
 	memcpy(fpu->xmm, fxsave->xmm_space, sizeof fxsave->xmm_space);
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
 int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
-	struct fxsave *fxsave = (struct fxsave *)&vcpu->arch.guest_fx_image;
-
-	vcpu_load(vcpu);
+	struct i387_fxsave_struct *fxsave =
+			&vcpu->arch.guest_fpu.state->fxsave;
 
 	memcpy(fxsave->st_space, fpu->fpr, 128);
 	fxsave->cwd = fpu->fcw;
@@ -5139,61 +5258,63 @@
 	fxsave->rdp = fpu->last_dp;
 	memcpy(fxsave->xmm_space, fpu->xmm, sizeof fxsave->xmm_space);
 
-	vcpu_put(vcpu);
-
 	return 0;
 }
 
-void fx_init(struct kvm_vcpu *vcpu)
+int fx_init(struct kvm_vcpu *vcpu)
 {
-	unsigned after_mxcsr_mask;
+	int err;
+
+	err = fpu_alloc(&vcpu->arch.guest_fpu);
+	if (err)
+		return err;
+
+	fpu_finit(&vcpu->arch.guest_fpu);
 
 	/*
-	 * Touch the fpu the first time in non atomic context as if
-	 * this is the first fpu instruction the exception handler
-	 * will fire before the instruction returns and it'll have to
-	 * allocate ram with GFP_KERNEL.
+	 * Ensure guest xcr0 is valid for loading
 	 */
-	if (!used_math())
-		kvm_fx_save(&vcpu->arch.host_fx_image);
-
-	/* Initialize guest FPU by resetting ours and saving into guest's */
-	preempt_disable();
-	kvm_fx_save(&vcpu->arch.host_fx_image);
-	kvm_fx_finit();
-	kvm_fx_save(&vcpu->arch.guest_fx_image);
-	kvm_fx_restore(&vcpu->arch.host_fx_image);
-	preempt_enable();
+	vcpu->arch.xcr0 = XSTATE_FP;
 
 	vcpu->arch.cr0 |= X86_CR0_ET;
-	after_mxcsr_mask = offsetof(struct i387_fxsave_struct, st_space);
-	vcpu->arch.guest_fx_image.mxcsr = 0x1f80;
-	memset((void *)&vcpu->arch.guest_fx_image + after_mxcsr_mask,
-	       0, sizeof(struct i387_fxsave_struct) - after_mxcsr_mask);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(fx_init);
 
+static void fx_free(struct kvm_vcpu *vcpu)
+{
+	fpu_free(&vcpu->arch.guest_fpu);
+}
+
 void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
 {
 	if (vcpu->guest_fpu_loaded)
 		return;
 
+	/*
+	 * Restore all possible states in the guest,
+	 * and assume host would use all available bits.
+	 * Guest xcr0 would be loaded later.
+	 */
+	kvm_put_guest_xcr0(vcpu);
 	vcpu->guest_fpu_loaded = 1;
-	kvm_fx_save(&vcpu->arch.host_fx_image);
-	kvm_fx_restore(&vcpu->arch.guest_fx_image);
+	unlazy_fpu(current);
+	fpu_restore_checking(&vcpu->arch.guest_fpu);
 	trace_kvm_fpu(1);
 }
 
 void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
 {
+	kvm_put_guest_xcr0(vcpu);
+
 	if (!vcpu->guest_fpu_loaded)
 		return;
 
 	vcpu->guest_fpu_loaded = 0;
-	kvm_fx_save(&vcpu->arch.guest_fx_image);
-	kvm_fx_restore(&vcpu->arch.host_fx_image);
+	fpu_save_init(&vcpu->arch.guest_fpu);
 	++vcpu->stat.fpu_reload;
-	set_bit(KVM_REQ_DEACTIVATE_FPU, &vcpu->requests);
+	kvm_make_request(KVM_REQ_DEACTIVATE_FPU, vcpu);
 	trace_kvm_fpu(0);
 }
 
@@ -5204,6 +5325,8 @@
 		vcpu->arch.time_page = NULL;
 	}
 
+	free_cpumask_var(vcpu->arch.wbinvd_dirty_mask);
+	fx_free(vcpu);
 	kvm_x86_ops->vcpu_free(vcpu);
 }
 
@@ -5217,9 +5340,6 @@
 {
 	int r;
 
-	/* We do fxsave: this must be aligned. */
-	BUG_ON((unsigned long)&vcpu->arch.host_fx_image & 0xF);
-
 	vcpu->arch.mtrr_state.have_fixed = 1;
 	vcpu_load(vcpu);
 	r = kvm_arch_vcpu_reset(vcpu);
@@ -5241,6 +5361,7 @@
 	kvm_mmu_unload(vcpu);
 	vcpu_put(vcpu);
 
+	fx_free(vcpu);
 	kvm_x86_ops->vcpu_free(vcpu);
 }
 
@@ -5334,7 +5455,12 @@
 	}
 	vcpu->arch.mcg_cap = KVM_MAX_MCE_BANKS;
 
+	if (!zalloc_cpumask_var(&vcpu->arch.wbinvd_dirty_mask, GFP_KERNEL))
+		goto fail_free_mce_banks;
+
 	return 0;
+fail_free_mce_banks:
+	kfree(vcpu->arch.mce_banks);
 fail_free_lapic:
 	kvm_free_lapic(vcpu);
 fail_mmu_destroy:
@@ -5364,12 +5490,6 @@
 	if (!kvm)
 		return ERR_PTR(-ENOMEM);
 
-	kvm->arch.aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
-	if (!kvm->arch.aliases) {
-		kfree(kvm);
-		return ERR_PTR(-ENOMEM);
-	}
-
 	INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
 	INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
 
@@ -5412,12 +5532,12 @@
 void kvm_arch_sync_events(struct kvm *kvm)
 {
 	kvm_free_all_assigned_devices(kvm);
+	kvm_free_pit(kvm);
 }
 
 void kvm_arch_destroy_vm(struct kvm *kvm)
 {
 	kvm_iommu_unmap_guest(kvm);
-	kvm_free_pit(kvm);
 	kfree(kvm->arch.vpic);
 	kfree(kvm->arch.vioapic);
 	kvm_free_vcpus(kvm);
@@ -5427,7 +5547,6 @@
 	if (kvm->arch.ept_identity_pagetable)
 		put_page(kvm->arch.ept_identity_pagetable);
 	cleanup_srcu_struct(&kvm->srcu);
-	kfree(kvm->arch.aliases);
 	kfree(kvm);
 }
 
@@ -5438,6 +5557,11 @@
 				int user_alloc)
 {
 	int npages = memslot->npages;
+	int map_flags = MAP_PRIVATE | MAP_ANONYMOUS;
+
+	/* Prevent internal slot pages from being moved by fork()/COW. */
+	if (memslot->id >= KVM_MEMORY_SLOTS)
+		map_flags = MAP_SHARED | MAP_ANONYMOUS;
 
 	/*To keep backward compatibility with older userspace,
 	 *x86 needs to hanlde !user_alloc case.
@@ -5450,7 +5574,7 @@
 			userspace_addr = do_mmap(NULL, 0,
 						 npages * PAGE_SIZE,
 						 PROT_READ | PROT_WRITE,
-						 MAP_PRIVATE | MAP_ANONYMOUS,
+						 map_flags,
 						 0);
 			up_write(&current->mm->mmap_sem);
 
@@ -5523,7 +5647,7 @@
 
 	me = get_cpu();
 	if (cpu != me && (unsigned)cpu < nr_cpu_ids && cpu_online(cpu))
-		if (!test_and_set_bit(KVM_REQ_KICK, &vcpu->requests))
+		if (atomic_xchg(&vcpu->guest_mode, 0))
 			smp_send_reschedule(cpu);
 	put_cpu();
 }
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index f4b5445..b7a4047 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -65,13 +65,6 @@
 	return kvm_read_cr0_bits(vcpu, X86_CR0_PG);
 }
 
-static inline struct kvm_mem_aliases *kvm_aliases(struct kvm *kvm)
-{
-	return rcu_dereference_check(kvm->arch.aliases,
-			srcu_read_lock_held(&kvm->srcu)
-			|| lockdep_is_held(&kvm->slots_lock));
-}
-
 void kvm_before_handle_nmi(struct kvm_vcpu *vcpu);
 void kvm_after_handle_nmi(struct kvm_vcpu *vcpu);
 
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 9d9434f..1cd497d 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -80,6 +80,11 @@
 
 config CRYPTO_PCOMP
 	tristate
+	select CRYPTO_PCOMP2
+	select CRYPTO_ALGAPI
+
+config CRYPTO_PCOMP2
+	tristate
 	select CRYPTO_ALGAPI2
 
 config CRYPTO_MANAGER
@@ -94,7 +99,15 @@
 	select CRYPTO_AEAD2
 	select CRYPTO_HASH2
 	select CRYPTO_BLKCIPHER2
-	select CRYPTO_PCOMP
+	select CRYPTO_PCOMP2
+
+config CRYPTO_MANAGER_TESTS
+	bool "Run algolithms' self-tests"
+	default y
+	depends on CRYPTO_MANAGER2
+	help
+	  Run cryptomanager's tests for the new crypto algorithms being
+	  registered.
 
 config CRYPTO_GF128MUL
 	tristate "GF(2^128) multiplication functions (EXPERIMENTAL)"
diff --git a/crypto/Makefile b/crypto/Makefile
index d7e6441..423b7de 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -26,7 +26,7 @@
 crypto_hash-objs += shash.o
 obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o
 
-obj-$(CONFIG_CRYPTO_PCOMP) += pcompress.o
+obj-$(CONFIG_CRYPTO_PCOMP2) += pcompress.o
 
 cryptomgr-objs := algboss.o testmgr.o
 
@@ -61,7 +61,7 @@
 obj-$(CONFIG_CRYPTO_DES) += des_generic.o
 obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o
 obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
-obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o
+obj-$(CONFIG_CRYPTO_TWOFISH) += twofish_generic.o
 obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o
 obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o
 obj-$(CONFIG_CRYPTO_AES) += aes_generic.o
diff --git a/crypto/algboss.c b/crypto/algboss.c
index c3c196b..40bd391 100644
--- a/crypto/algboss.c
+++ b/crypto/algboss.c
@@ -206,6 +206,7 @@
 	return NOTIFY_OK;
 }
 
+#ifdef CONFIG_CRYPTO_MANAGER_TESTS
 static int cryptomgr_test(void *data)
 {
 	struct crypto_test_param *param = data;
@@ -266,6 +267,7 @@
 err:
 	return NOTIFY_OK;
 }
+#endif /* CONFIG_CRYPTO_MANAGER_TESTS */
 
 static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
 			    void *data)
@@ -273,8 +275,10 @@
 	switch (msg) {
 	case CRYPTO_MSG_ALG_REQUEST:
 		return cryptomgr_schedule_probe(data);
+#ifdef CONFIG_CRYPTO_MANAGER_TESTS
 	case CRYPTO_MSG_ALG_REGISTER:
 		return cryptomgr_schedule_test(data);
+#endif
 	}
 
 	return NOTIFY_DONE;
diff --git a/crypto/authenc.c b/crypto/authenc.c
index b9884ee..a5a22cf 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -616,7 +616,7 @@
 	auth = ahash_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
 			       CRYPTO_ALG_TYPE_AHASH_MASK);
 	if (IS_ERR(auth))
-		return ERR_PTR(PTR_ERR(auth));
+		return ERR_CAST(auth);
 
 	auth_base = &auth->base;
 
diff --git a/crypto/ctr.c b/crypto/ctr.c
index 6c3bfab..4ca7222 100644
--- a/crypto/ctr.c
+++ b/crypto/ctr.c
@@ -185,7 +185,7 @@
 	alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER,
 				  CRYPTO_ALG_TYPE_MASK);
 	if (IS_ERR(alg))
-		return ERR_PTR(PTR_ERR(alg));
+		return ERR_CAST(alg);
 
 	/* Block size must be >= 4 bytes. */
 	err = -EINVAL;
diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c
index 247178c..de30782 100644
--- a/crypto/pcrypt.c
+++ b/crypto/pcrypt.c
@@ -24,12 +24,40 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/kobject.h>
+#include <linux/cpu.h>
 #include <crypto/pcrypt.h>
 
-static struct padata_instance *pcrypt_enc_padata;
-static struct padata_instance *pcrypt_dec_padata;
-static struct workqueue_struct *encwq;
-static struct workqueue_struct *decwq;
+struct padata_pcrypt {
+	struct padata_instance *pinst;
+	struct workqueue_struct *wq;
+
+	/*
+	 * Cpumask for callback CPUs. It should be
+	 * equal to serial cpumask of corresponding padata instance,
+	 * so it is updated when padata notifies us about serial
+	 * cpumask change.
+	 *
+	 * cb_cpumask is protected by RCU. This fact prevents us from
+	 * using cpumask_var_t directly because the actual type of
+	 * cpumsak_var_t depends on kernel configuration(particularly on
+	 * CONFIG_CPUMASK_OFFSTACK macro). Depending on the configuration
+	 * cpumask_var_t may be either a pointer to the struct cpumask
+	 * or a variable allocated on the stack. Thus we can not safely use
+	 * cpumask_var_t with RCU operations such as rcu_assign_pointer or
+	 * rcu_dereference. So cpumask_var_t is wrapped with struct
+	 * pcrypt_cpumask which makes possible to use it with RCU.
+	 */
+	struct pcrypt_cpumask {
+		cpumask_var_t mask;
+	} *cb_cpumask;
+	struct notifier_block nblock;
+};
+
+static struct padata_pcrypt pencrypt;
+static struct padata_pcrypt pdecrypt;
+static struct kset           *pcrypt_kset;
 
 struct pcrypt_instance_ctx {
 	struct crypto_spawn spawn;
@@ -42,25 +70,32 @@
 };
 
 static int pcrypt_do_parallel(struct padata_priv *padata, unsigned int *cb_cpu,
-			      struct padata_instance *pinst)
+			      struct padata_pcrypt *pcrypt)
 {
 	unsigned int cpu_index, cpu, i;
+	struct pcrypt_cpumask *cpumask;
 
 	cpu = *cb_cpu;
 
-	if (cpumask_test_cpu(cpu, cpu_active_mask))
+	rcu_read_lock_bh();
+	cpumask = rcu_dereference(pcrypt->cb_cpumask);
+	if (cpumask_test_cpu(cpu, cpumask->mask))
 			goto out;
 
-	cpu_index = cpu % cpumask_weight(cpu_active_mask);
+	if (!cpumask_weight(cpumask->mask))
+			goto out;
 
-	cpu = cpumask_first(cpu_active_mask);
+	cpu_index = cpu % cpumask_weight(cpumask->mask);
+
+	cpu = cpumask_first(cpumask->mask);
 	for (i = 0; i < cpu_index; i++)
-		cpu = cpumask_next(cpu, cpu_active_mask);
+		cpu = cpumask_next(cpu, cpumask->mask);
 
 	*cb_cpu = cpu;
 
 out:
-	return padata_do_parallel(pinst, padata, cpu);
+	rcu_read_unlock_bh();
+	return padata_do_parallel(pcrypt->pinst, padata, cpu);
 }
 
 static int pcrypt_aead_setkey(struct crypto_aead *parent,
@@ -142,11 +177,9 @@
 			       req->cryptlen, req->iv);
 	aead_request_set_assoc(creq, req->assoc, req->assoclen);
 
-	err = pcrypt_do_parallel(padata, &ctx->cb_cpu, pcrypt_enc_padata);
-	if (err)
-		return err;
-	else
-		err = crypto_aead_encrypt(creq);
+	err = pcrypt_do_parallel(padata, &ctx->cb_cpu, &pencrypt);
+	if (!err)
+		return -EINPROGRESS;
 
 	return err;
 }
@@ -186,11 +219,9 @@
 			       req->cryptlen, req->iv);
 	aead_request_set_assoc(creq, req->assoc, req->assoclen);
 
-	err = pcrypt_do_parallel(padata, &ctx->cb_cpu, pcrypt_dec_padata);
-	if (err)
-		return err;
-	else
-		err = crypto_aead_decrypt(creq);
+	err = pcrypt_do_parallel(padata, &ctx->cb_cpu, &pdecrypt);
+	if (!err)
+		return -EINPROGRESS;
 
 	return err;
 }
@@ -232,11 +263,9 @@
 	aead_givcrypt_set_assoc(creq, areq->assoc, areq->assoclen);
 	aead_givcrypt_set_giv(creq, req->giv, req->seq);
 
-	err = pcrypt_do_parallel(padata, &ctx->cb_cpu, pcrypt_enc_padata);
-	if (err)
-		return err;
-	else
-		err = crypto_aead_givencrypt(creq);
+	err = pcrypt_do_parallel(padata, &ctx->cb_cpu, &pencrypt);
+	if (!err)
+		return -EINPROGRESS;
 
 	return err;
 }
@@ -376,6 +405,115 @@
 	kfree(inst);
 }
 
+static int pcrypt_cpumask_change_notify(struct notifier_block *self,
+					unsigned long val, void *data)
+{
+	struct padata_pcrypt *pcrypt;
+	struct pcrypt_cpumask *new_mask, *old_mask;
+	struct padata_cpumask *cpumask = (struct padata_cpumask *)data;
+
+	if (!(val & PADATA_CPU_SERIAL))
+		return 0;
+
+	pcrypt = container_of(self, struct padata_pcrypt, nblock);
+	new_mask = kmalloc(sizeof(*new_mask), GFP_KERNEL);
+	if (!new_mask)
+		return -ENOMEM;
+	if (!alloc_cpumask_var(&new_mask->mask, GFP_KERNEL)) {
+		kfree(new_mask);
+		return -ENOMEM;
+	}
+
+	old_mask = pcrypt->cb_cpumask;
+
+	cpumask_copy(new_mask->mask, cpumask->cbcpu);
+	rcu_assign_pointer(pcrypt->cb_cpumask, new_mask);
+	synchronize_rcu_bh();
+
+	free_cpumask_var(old_mask->mask);
+	kfree(old_mask);
+	return 0;
+}
+
+static int pcrypt_sysfs_add(struct padata_instance *pinst, const char *name)
+{
+	int ret;
+
+	pinst->kobj.kset = pcrypt_kset;
+	ret = kobject_add(&pinst->kobj, NULL, name);
+	if (!ret)
+		kobject_uevent(&pinst->kobj, KOBJ_ADD);
+
+	return ret;
+}
+
+static int pcrypt_init_padata(struct padata_pcrypt *pcrypt,
+			      const char *name)
+{
+	int ret = -ENOMEM;
+	struct pcrypt_cpumask *mask;
+
+	get_online_cpus();
+
+	pcrypt->wq = create_workqueue(name);
+	if (!pcrypt->wq)
+		goto err;
+
+	pcrypt->pinst = padata_alloc_possible(pcrypt->wq);
+	if (!pcrypt->pinst)
+		goto err_destroy_workqueue;
+
+	mask = kmalloc(sizeof(*mask), GFP_KERNEL);
+	if (!mask)
+		goto err_free_padata;
+	if (!alloc_cpumask_var(&mask->mask, GFP_KERNEL)) {
+		kfree(mask);
+		goto err_free_padata;
+	}
+
+	cpumask_and(mask->mask, cpu_possible_mask, cpu_active_mask);
+	rcu_assign_pointer(pcrypt->cb_cpumask, mask);
+
+	pcrypt->nblock.notifier_call = pcrypt_cpumask_change_notify;
+	ret = padata_register_cpumask_notifier(pcrypt->pinst, &pcrypt->nblock);
+	if (ret)
+		goto err_free_cpumask;
+
+	ret = pcrypt_sysfs_add(pcrypt->pinst, name);
+	if (ret)
+		goto err_unregister_notifier;
+
+	put_online_cpus();
+
+	return ret;
+
+err_unregister_notifier:
+	padata_unregister_cpumask_notifier(pcrypt->pinst, &pcrypt->nblock);
+err_free_cpumask:
+	free_cpumask_var(mask->mask);
+	kfree(mask);
+err_free_padata:
+	padata_free(pcrypt->pinst);
+err_destroy_workqueue:
+	destroy_workqueue(pcrypt->wq);
+err:
+	put_online_cpus();
+
+	return ret;
+}
+
+static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt)
+{
+	kobject_put(&pcrypt->pinst->kobj);
+	free_cpumask_var(pcrypt->cb_cpumask->mask);
+	kfree(pcrypt->cb_cpumask);
+
+	padata_stop(pcrypt->pinst);
+	padata_unregister_cpumask_notifier(pcrypt->pinst, &pcrypt->nblock);
+	destroy_workqueue(pcrypt->wq);
+	padata_free(pcrypt->pinst);
+}
+
 static struct crypto_template pcrypt_tmpl = {
 	.name = "pcrypt",
 	.alloc = pcrypt_alloc,
@@ -385,52 +523,39 @@
 
 static int __init pcrypt_init(void)
 {
-	encwq = create_workqueue("pencrypt");
-	if (!encwq)
+	int err = -ENOMEM;
+
+	pcrypt_kset = kset_create_and_add("pcrypt", NULL, kernel_kobj);
+	if (!pcrypt_kset)
 		goto err;
 
-	decwq = create_workqueue("pdecrypt");
-	if (!decwq)
-		goto err_destroy_encwq;
+	err = pcrypt_init_padata(&pencrypt, "pencrypt");
+	if (err)
+		goto err_unreg_kset;
 
+	err = pcrypt_init_padata(&pdecrypt, "pdecrypt");
+	if (err)
+		goto err_deinit_pencrypt;
 
-	pcrypt_enc_padata = padata_alloc(cpu_possible_mask, encwq);
-	if (!pcrypt_enc_padata)
-		goto err_destroy_decwq;
-
-	pcrypt_dec_padata = padata_alloc(cpu_possible_mask, decwq);
-	if (!pcrypt_dec_padata)
-		goto err_free_padata;
-
-	padata_start(pcrypt_enc_padata);
-	padata_start(pcrypt_dec_padata);
+	padata_start(pencrypt.pinst);
+	padata_start(pdecrypt.pinst);
 
 	return crypto_register_template(&pcrypt_tmpl);
 
-err_free_padata:
-	padata_free(pcrypt_enc_padata);
-
-err_destroy_decwq:
-	destroy_workqueue(decwq);
-
-err_destroy_encwq:
-	destroy_workqueue(encwq);
-
+err_deinit_pencrypt:
+	pcrypt_fini_padata(&pencrypt);
+err_unreg_kset:
+	kset_unregister(pcrypt_kset);
 err:
-	return -ENOMEM;
+	return err;
 }
 
 static void __exit pcrypt_exit(void)
 {
-	padata_stop(pcrypt_enc_padata);
-	padata_stop(pcrypt_dec_padata);
+	pcrypt_fini_padata(&pencrypt);
+	pcrypt_fini_padata(&pdecrypt);
 
-	destroy_workqueue(encwq);
-	destroy_workqueue(decwq);
-
-	padata_free(pcrypt_enc_padata);
-	padata_free(pcrypt_dec_padata);
-
+	kset_unregister(pcrypt_kset);
 	crypto_unregister_template(&pcrypt_tmpl);
 }
 
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 5c8aaa0..abd980c 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -22,6 +22,17 @@
 #include <crypto/rng.h>
 
 #include "internal.h"
+
+#ifndef CONFIG_CRYPTO_MANAGER_TESTS
+
+/* a perfect nop */
+int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
+{
+	return 0;
+}
+
+#else
+
 #include "testmgr.h"
 
 /*
@@ -2530,4 +2541,7 @@
 non_fips_alg:
 	return -EINVAL;
 }
+
+#endif /* CONFIG_CRYPTO_MANAGER_TESTS */
+
 EXPORT_SYMBOL_GPL(alg_test);
diff --git a/crypto/twofish.c b/crypto/twofish_generic.c
similarity index 99%
rename from crypto/twofish.c
rename to crypto/twofish_generic.c
index dfcda23..1f07b84 100644
--- a/crypto/twofish.c
+++ b/crypto/twofish_generic.c
@@ -212,3 +212,4 @@
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION ("Twofish Cipher Algorithm");
+MODULE_ALIAS("twofish");
diff --git a/crypto/xts.c b/crypto/xts.c
index d87b0f3..555ecaa 100644
--- a/crypto/xts.c
+++ b/crypto/xts.c
@@ -224,7 +224,7 @@
 	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
 				  CRYPTO_ALG_TYPE_MASK);
 	if (IS_ERR(alg))
-		return ERR_PTR(PTR_ERR(alg));
+		return ERR_CAST(alg);
 
 	inst = crypto_alloc_instance("xts", alg);
 	if (IS_ERR(inst))
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 7464115..08e0140 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -104,6 +104,24 @@
 	help
 	  Say N to disable power /sys interface
 
+config ACPI_EC_DEBUGFS
+	tristate "EC read/write access through /sys/kernel/debug/ec"
+	default n
+	help
+	  Say N to disable Embedded Controller /sys/kernel/debug interface
+
+	  Be aware that using this interface can confuse your Embedded
+	  Controller in a way that a normal reboot is not enough. You then
+	  have to power of your system, and remove the laptop battery for
+	  some seconds.
+	  An Embedded Controller typically is available on laptops and reads
+	  sensor values like battery state and temperature.
+	  The kernel accesses the EC through ACPI parsed code provided by BIOS
+	  tables. This option allows to access the EC directly without ACPI
+	  code being involved.
+	  Thus this option is a debug option that helps to write ACPI drivers
+	  and can be used to identify ACPI code or EC firmware bugs.
+
 config ACPI_PROC_EVENT
 	bool "Deprecated /proc/acpi/event support"
 	depends on PROC_FS
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 6ee3316..833b582 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -60,6 +60,7 @@
 obj-$(CONFIG_ACPI_SBS)		+= sbs.o
 obj-$(CONFIG_ACPI_POWER_METER)	+= power_meter.o
 obj-$(CONFIG_ACPI_HED)		+= hed.o
+obj-$(CONFIG_ACPI_EC_DEBUGFS)	+= ec_sys.o
 
 # processor has its own "processor." module_param namespace
 processor-y			:= processor_driver.o processor_throttling.o
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 5f2027d..1fa0aaf 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -34,8 +34,6 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
@@ -45,10 +43,13 @@
 #include <acpi/acpi_drivers.h>
 #include <linux/dmi.h>
 
+#include "internal.h"
+
 #define ACPI_EC_CLASS			"embedded_controller"
 #define ACPI_EC_DEVICE_NAME		"Embedded Controller"
 #define ACPI_EC_FILE_INFO		"info"
 
+#undef PREFIX
 #define PREFIX				"ACPI: EC: "
 
 /* EC status register */
@@ -106,19 +107,8 @@
 	bool done;
 };
 
-static struct acpi_ec {
-	acpi_handle handle;
-	unsigned long gpe;
-	unsigned long command_addr;
-	unsigned long data_addr;
-	unsigned long global_lock;
-	unsigned long flags;
-	struct mutex lock;
-	wait_queue_head_t wait;
-	struct list_head list;
-	struct transaction *curr;
-	spinlock_t curr_lock;
-} *boot_ec, *first_ec;
+struct acpi_ec *boot_ec, *first_ec;
+EXPORT_SYMBOL(first_ec);
 
 static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
 static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
@@ -679,72 +669,6 @@
 }
 
 /* --------------------------------------------------------------------------
-                              FS Interface (/proc)
-   -------------------------------------------------------------------------- */
-
-static struct proc_dir_entry *acpi_ec_dir;
-
-static int acpi_ec_read_info(struct seq_file *seq, void *offset)
-{
-	struct acpi_ec *ec = seq->private;
-
-	if (!ec)
-		goto end;
-
-	seq_printf(seq, "gpe:\t\t\t0x%02x\n", (u32) ec->gpe);
-	seq_printf(seq, "ports:\t\t\t0x%02x, 0x%02x\n",
-		   (unsigned)ec->command_addr, (unsigned)ec->data_addr);
-	seq_printf(seq, "use global lock:\t%s\n",
-		   ec->global_lock ? "yes" : "no");
-      end:
-	return 0;
-}
-
-static int acpi_ec_info_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_ec_read_info, PDE(inode)->data);
-}
-
-static const struct file_operations acpi_ec_info_ops = {
-	.open = acpi_ec_info_open_fs,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-	.owner = THIS_MODULE,
-};
-
-static int acpi_ec_add_fs(struct acpi_device *device)
-{
-	struct proc_dir_entry *entry = NULL;
-
-	if (!acpi_device_dir(device)) {
-		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
-						     acpi_ec_dir);
-		if (!acpi_device_dir(device))
-			return -ENODEV;
-	}
-
-	entry = proc_create_data(ACPI_EC_FILE_INFO, S_IRUGO,
-				 acpi_device_dir(device),
-				 &acpi_ec_info_ops, acpi_driver_data(device));
-	if (!entry)
-		return -ENODEV;
-	return 0;
-}
-
-static int acpi_ec_remove_fs(struct acpi_device *device)
-{
-
-	if (acpi_device_dir(device)) {
-		remove_proc_entry(ACPI_EC_FILE_INFO, acpi_device_dir(device));
-		remove_proc_entry(acpi_device_bid(device), acpi_ec_dir);
-		acpi_device_dir(device) = NULL;
-	}
-
-	return 0;
-}
-
-/* --------------------------------------------------------------------------
                                Driver Interface
    -------------------------------------------------------------------------- */
 static acpi_status
@@ -894,7 +818,12 @@
 	if (!first_ec)
 		first_ec = ec;
 	device->driver_data = ec;
-	acpi_ec_add_fs(device);
+
+	WARN(!request_region(ec->data_addr, 1, "EC data"),
+	     "Could not request EC data io port 0x%lx", ec->data_addr);
+	WARN(!request_region(ec->command_addr, 1, "EC cmd"),
+	     "Could not request EC cmd io port 0x%lx", ec->command_addr);
+
 	pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
 			  ec->gpe, ec->command_addr, ec->data_addr);
 
@@ -921,7 +850,8 @@
 		kfree(handler);
 	}
 	mutex_unlock(&ec->lock);
-	acpi_ec_remove_fs(device);
+	release_region(ec->data_addr, 1);
+	release_region(ec->command_addr, 1);
 	device->driver_data = NULL;
 	if (ec == first_ec)
 		first_ec = NULL;
@@ -1120,16 +1050,10 @@
 {
 	int result = 0;
 
-	acpi_ec_dir = proc_mkdir(ACPI_EC_CLASS, acpi_root_dir);
-	if (!acpi_ec_dir)
-		return -ENODEV;
-
 	/* Now register the driver for the EC */
 	result = acpi_bus_register_driver(&acpi_ec_driver);
-	if (result < 0) {
-		remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
+	if (result < 0)
 		return -ENODEV;
-	}
 
 	return result;
 }
@@ -1140,9 +1064,6 @@
 {
 
 	acpi_bus_unregister_driver(&acpi_ec_driver);
-
-	remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
-
 	return;
 }
 #endif	/* 0 */
diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c
new file mode 100644
index 0000000..0e869b3
--- /dev/null
+++ b/drivers/acpi/ec_sys.c
@@ -0,0 +1,160 @@
+/*
+ * ec_sys.c
+ *
+ * Copyright (C) 2010 SUSE Products GmbH/Novell
+ * Author:
+ *      Thomas Renninger <trenn@suse.de>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/debugfs.h>
+#include "internal.h"
+
+MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>");
+MODULE_DESCRIPTION("ACPI EC sysfs access driver");
+MODULE_LICENSE("GPL");
+
+static bool write_support;
+module_param(write_support, bool, 0644);
+MODULE_PARM_DESC(write_support, "Dangerous, reboot and removal of battery may "
+		 "be needed.");
+
+#define EC_SPACE_SIZE 256
+
+struct sysdev_class acpi_ec_sysdev_class = {
+	.name = "ec",
+};
+
+static struct dentry *acpi_ec_debugfs_dir;
+
+static int acpi_ec_open_io(struct inode *i, struct file *f)
+{
+	f->private_data = i->i_private;
+	return 0;
+}
+
+static ssize_t acpi_ec_read_io(struct file *f, char __user *buf,
+			       size_t count, loff_t *off)
+{
+	/* Use this if support reading/writing multiple ECs exists in ec.c:
+	 * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
+	 */
+	unsigned int size = EC_SPACE_SIZE;
+	u8 *data = (u8 *) buf;
+	loff_t init_off = *off;
+	int err = 0;
+
+	if (*off >= size)
+		return 0;
+	if (*off + count >= size) {
+		size -= *off;
+		count = size;
+	} else
+		size = count;
+
+	while (size) {
+		err = ec_read(*off, &data[*off - init_off]);
+		if (err)
+			return err;
+		*off += 1;
+		size--;
+	}
+	return count;
+}
+
+static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
+				size_t count, loff_t *off)
+{
+	/* Use this if support reading/writing multiple ECs exists in ec.c:
+	 * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
+	 */
+
+	unsigned int size = count;
+	loff_t init_off = *off;
+	u8 *data = (u8 *) buf;
+	int err = 0;
+
+	if (*off >= EC_SPACE_SIZE)
+		return 0;
+	if (*off + count >= EC_SPACE_SIZE) {
+		size = EC_SPACE_SIZE - *off;
+		count = size;
+	}
+
+	while (size) {
+		u8 byte_write = data[*off - init_off];
+		err = ec_write(*off, byte_write);
+		if (err)
+			return err;
+
+		*off += 1;
+		size--;
+	}
+	return count;
+}
+
+static struct file_operations acpi_ec_io_ops = {
+	.owner = THIS_MODULE,
+	.open  = acpi_ec_open_io,
+	.read  = acpi_ec_read_io,
+	.write = acpi_ec_write_io,
+};
+
+int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count)
+{
+	struct dentry *dev_dir;
+	char name[64];
+	mode_t mode = 0400;
+
+	if (ec_device_count == 0) {
+		acpi_ec_debugfs_dir = debugfs_create_dir("ec", NULL);
+		if (!acpi_ec_debugfs_dir)
+			return -ENOMEM;
+	}
+
+	sprintf(name, "ec%u", ec_device_count);
+	dev_dir = debugfs_create_dir(name, acpi_ec_debugfs_dir);
+	if (!dev_dir) {
+		if (ec_device_count != 0)
+			goto error;
+		return -ENOMEM;
+	}
+
+	if (!debugfs_create_x32("gpe", 0444, dev_dir, (u32 *)&first_ec->gpe))
+		goto error;
+	if (!debugfs_create_bool("use_global_lock", 0444, dev_dir,
+				 (u32 *)&first_ec->global_lock))
+		goto error;
+
+	if (write_support)
+		mode = 0600;
+	if (!debugfs_create_file("io", mode, dev_dir, ec, &acpi_ec_io_ops))
+		goto error;
+
+	return 0;
+
+error:
+	debugfs_remove_recursive(acpi_ec_debugfs_dir);
+	return -ENOMEM;
+}
+
+static int __init acpi_ec_sys_init(void)
+{
+	int err = 0;
+	if (first_ec)
+		err = acpi_ec_add_debugfs(first_ec, 0);
+	else
+		err = -ENODEV;
+	return err;
+}
+
+static void __exit acpi_ec_sys_exit(void)
+{
+	debugfs_remove_recursive(acpi_ec_debugfs_dir);
+}
+
+module_init(acpi_ec_sys_init);
+module_exit(acpi_ec_sys_exit);
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index f8f190e..8ae2726 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -18,6 +18,11 @@
  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#ifndef _ACPI_INTERNAL_H_
+#define _ACPI_INTERNAL_H_
+
+#include <linux/sysdev.h>
+
 #define PREFIX "ACPI: "
 
 int init_acpi_device_notify(void);
@@ -46,6 +51,23 @@
 /* --------------------------------------------------------------------------
                                   Embedded Controller
    -------------------------------------------------------------------------- */
+struct acpi_ec {
+	acpi_handle handle;
+	unsigned long gpe;
+	unsigned long command_addr;
+	unsigned long data_addr;
+	unsigned long global_lock;
+	unsigned long flags;
+	struct mutex lock;
+	wait_queue_head_t wait;
+	struct list_head list;
+	struct transaction *curr;
+	spinlock_t curr_lock;
+	struct sys_device sysdev;
+};
+
+extern struct acpi_ec *first_ec;
+
 int acpi_ec_init(void);
 int acpi_ec_ecdt_probe(void);
 int acpi_boot_ec_enable(void);
@@ -63,3 +85,5 @@
 #else
 static inline int acpi_sleep_proc_init(void) { return 0; }
 #endif
+
+#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index f1a0a00..be7461c 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -177,7 +177,7 @@
 
 config ATM_NICSTAR
 	tristate "IDT 77201 (NICStAR) (ForeRunnerLE)"
-	depends on PCI && !64BIT && VIRT_TO_BUS
+	depends on PCI
 	help
 	  The NICStAR chipset family is used in a large number of ATM NICs for
 	  25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE
diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c
index 6d44f07..46b9476 100644
--- a/drivers/atm/adummy.c
+++ b/drivers/atm/adummy.c
@@ -40,6 +40,42 @@
 
 static LIST_HEAD(adummy_devs);
 
+static ssize_t __set_signal(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t len)
+{
+	struct atm_dev *atm_dev = container_of(dev, struct atm_dev, class_dev);
+	int signal;
+
+	if (sscanf(buf, "%d", &signal) == 1) {
+
+		if (signal < ATM_PHY_SIG_LOST || signal > ATM_PHY_SIG_FOUND)
+			signal = ATM_PHY_SIG_UNKNOWN;
+
+		atm_dev_signal_change(atm_dev, signal);
+		return 1;
+	}
+	return -EINVAL;
+}
+
+static ssize_t __show_signal(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct atm_dev *atm_dev = container_of(dev, struct atm_dev, class_dev);
+	return sprintf(buf, "%d\n", atm_dev->signal);
+}
+static DEVICE_ATTR(signal, 0644, __show_signal, __set_signal);
+
+static struct attribute *adummy_attrs[] = {
+	&dev_attr_signal.attr,
+	NULL
+};
+
+static struct attribute_group adummy_group_attrs = {
+	.name = NULL, /* We want them in dev's root folder */
+	.attrs = adummy_attrs
+};
+
 static int __init
 adummy_start(struct atm_dev *dev)
 {
@@ -128,6 +164,9 @@
 	adummy_dev->atm_dev = atm_dev;
 	atm_dev->dev_data = adummy_dev;
 
+	if (sysfs_create_group(&atm_dev->class_dev.kobj, &adummy_group_attrs))
+		dev_err(&atm_dev->class_dev, "Could not register attrs for adummy\n");
+
 	if (adummy_start(atm_dev)) {
 		printk(KERN_ERR DEV_LABEL ": adummy_start() failed\n");
 		err = -ENODEV;
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 9d18644..a33896a 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -2371,10 +2371,8 @@
 /********** module entry **********/
 
 static struct pci_device_id amb_pci_tbl[] = {
-	{ PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR, PCI_ANY_ID, PCI_ANY_ID,
-	  0, 0, 0 },
-	{ PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR_BAD, PCI_ANY_ID, PCI_ANY_ID,
-	  0, 0, 0 },
+	{ PCI_VDEVICE(MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR), 0 },
+	{ PCI_VDEVICE(MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR_BAD), 0 },
 	{ 0, }
 };
 
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 90a5a7c..80f9f36 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -2269,10 +2269,8 @@
 
 
 static struct pci_device_id eni_pci_tbl[] = {
-	{ PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_FPGA, PCI_ANY_ID, PCI_ANY_ID,
-	  0, 0, 0 /* FPGA */ },
-	{ PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_ASIC, PCI_ANY_ID, PCI_ANY_ID,
-	  0, 0, 1 /* ASIC */ },
+	{ PCI_VDEVICE(EF, PCI_DEVICE_ID_EF_ATM_FPGA), 0 /* FPGA */ },
+	{ PCI_VDEVICE(EF, PCI_DEVICE_ID_EF_ATM_ASIC), 1 /* ASIC */ },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci,eni_pci_tbl);
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 6e600af..8717809 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -2027,10 +2027,8 @@
 }
 
 static struct pci_device_id firestream_pci_tbl[] = {
-	{ PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS50, 
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, FS_IS50},
-	{ PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS155, 
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, FS_IS155},
+	{ PCI_VDEVICE(FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS50), FS_IS50},
+	{ PCI_VDEVICE(FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS155), FS_IS155},
 	{ 0, }
 };
 
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index 56c2e99..801e8b6 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -67,6 +67,7 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
+#include <linux/bitmap.h>
 #include <linux/slab.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
@@ -778,61 +779,39 @@
 static int __devinit
 he_init_group(struct he_dev *he_dev, int group)
 {
+	struct he_buff *heb, *next;
+	dma_addr_t mapping;
 	int i;
 
-	/* small buffer pool */
-	he_dev->rbps_pool = pci_pool_create("rbps", he_dev->pci_dev,
-			CONFIG_RBPS_BUFSIZE, 8, 0);
-	if (he_dev->rbps_pool == NULL) {
-		hprintk("unable to create rbps pages\n");
+	he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32));
+	he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32));
+	he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32));
+	he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0),
+		  G0_RBPS_BS + (group * 32));
+
+	/* bitmap table */
+	he_dev->rbpl_table = kmalloc(BITS_TO_LONGS(RBPL_TABLE_SIZE)
+				     * sizeof(unsigned long), GFP_KERNEL);
+	if (!he_dev->rbpl_table) {
+		hprintk("unable to allocate rbpl bitmap table\n");
 		return -ENOMEM;
 	}
+	bitmap_zero(he_dev->rbpl_table, RBPL_TABLE_SIZE);
 
-	he_dev->rbps_base = pci_alloc_consistent(he_dev->pci_dev,
-		CONFIG_RBPS_SIZE * sizeof(struct he_rbp), &he_dev->rbps_phys);
-	if (he_dev->rbps_base == NULL) {
-		hprintk("failed to alloc rbps_base\n");
-		goto out_destroy_rbps_pool;
+	/* rbpl_virt 64-bit pointers */
+	he_dev->rbpl_virt = kmalloc(RBPL_TABLE_SIZE
+				    * sizeof(struct he_buff *), GFP_KERNEL);
+	if (!he_dev->rbpl_virt) {
+		hprintk("unable to allocate rbpl virt table\n");
+		goto out_free_rbpl_table;
 	}
-	memset(he_dev->rbps_base, 0, CONFIG_RBPS_SIZE * sizeof(struct he_rbp));
-	he_dev->rbps_virt = kmalloc(CONFIG_RBPS_SIZE * sizeof(struct he_virt), GFP_KERNEL);
-	if (he_dev->rbps_virt == NULL) {
-		hprintk("failed to alloc rbps_virt\n");
-		goto out_free_rbps_base;
-	}
-
-	for (i = 0; i < CONFIG_RBPS_SIZE; ++i) {
-		dma_addr_t dma_handle;
-		void *cpuaddr;
-
-		cpuaddr = pci_pool_alloc(he_dev->rbps_pool, GFP_KERNEL|GFP_DMA, &dma_handle);
-		if (cpuaddr == NULL)
-			goto out_free_rbps_virt;
-
-		he_dev->rbps_virt[i].virt = cpuaddr;
-		he_dev->rbps_base[i].status = RBP_LOANED | RBP_SMALLBUF | (i << RBP_INDEX_OFF);
-		he_dev->rbps_base[i].phys = dma_handle;
-
-	}
-	he_dev->rbps_tail = &he_dev->rbps_base[CONFIG_RBPS_SIZE - 1];
-
-	he_writel(he_dev, he_dev->rbps_phys, G0_RBPS_S + (group * 32));
-	he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail),
-						G0_RBPS_T + (group * 32));
-	he_writel(he_dev, CONFIG_RBPS_BUFSIZE/4,
-						G0_RBPS_BS + (group * 32));
-	he_writel(he_dev,
-			RBP_THRESH(CONFIG_RBPS_THRESH) |
-			RBP_QSIZE(CONFIG_RBPS_SIZE - 1) |
-			RBP_INT_ENB,
-						G0_RBPS_QI + (group * 32));
 
 	/* large buffer pool */
 	he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev,
-			CONFIG_RBPL_BUFSIZE, 8, 0);
+					    CONFIG_RBPL_BUFSIZE, 64, 0);
 	if (he_dev->rbpl_pool == NULL) {
 		hprintk("unable to create rbpl pool\n");
-		goto out_free_rbps_virt;
+		goto out_free_rbpl_virt;
 	}
 
 	he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev,
@@ -842,30 +821,29 @@
 		goto out_destroy_rbpl_pool;
 	}
 	memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp));
-	he_dev->rbpl_virt = kmalloc(CONFIG_RBPL_SIZE * sizeof(struct he_virt), GFP_KERNEL);
-	if (he_dev->rbpl_virt == NULL) {
-		hprintk("failed to alloc rbpl_virt\n");
-		goto out_free_rbpl_base;
-	}
+
+	INIT_LIST_HEAD(&he_dev->rbpl_outstanding);
 
 	for (i = 0; i < CONFIG_RBPL_SIZE; ++i) {
-		dma_addr_t dma_handle;
-		void *cpuaddr;
 
-		cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &dma_handle);
-		if (cpuaddr == NULL)
-			goto out_free_rbpl_virt;
+		heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &mapping);
+		if (!heb)
+			goto out_free_rbpl;
+		heb->mapping = mapping;
+		list_add(&heb->entry, &he_dev->rbpl_outstanding);
 
-		he_dev->rbpl_virt[i].virt = cpuaddr;
-		he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF);
-		he_dev->rbpl_base[i].phys = dma_handle;
+		set_bit(i, he_dev->rbpl_table);
+		he_dev->rbpl_virt[i] = heb;
+		he_dev->rbpl_hint = i + 1;
+		he_dev->rbpl_base[i].idx =  i << RBP_IDX_OFFSET;
+		he_dev->rbpl_base[i].phys = mapping + offsetof(struct he_buff, data);
 	}
 	he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE - 1];
 
 	he_writel(he_dev, he_dev->rbpl_phys, G0_RBPL_S + (group * 32));
 	he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail),
 						G0_RBPL_T + (group * 32));
-	he_writel(he_dev, CONFIG_RBPL_BUFSIZE/4,
+	he_writel(he_dev, (CONFIG_RBPL_BUFSIZE - sizeof(struct he_buff))/4,
 						G0_RBPL_BS + (group * 32));
 	he_writel(he_dev,
 			RBP_THRESH(CONFIG_RBPL_THRESH) |
@@ -879,7 +857,7 @@
 		CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), &he_dev->rbrq_phys);
 	if (he_dev->rbrq_base == NULL) {
 		hprintk("failed to allocate rbrq\n");
-		goto out_free_rbpl_virt;
+		goto out_free_rbpl;
 	}
 	memset(he_dev->rbrq_base, 0, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq));
 
@@ -920,33 +898,20 @@
 	pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE *
 			sizeof(struct he_rbrq), he_dev->rbrq_base,
 			he_dev->rbrq_phys);
-	i = CONFIG_RBPL_SIZE;
-out_free_rbpl_virt:
-	while (i--)
-		pci_pool_free(he_dev->rbpl_pool, he_dev->rbpl_virt[i].virt,
-				he_dev->rbpl_base[i].phys);
-	kfree(he_dev->rbpl_virt);
+out_free_rbpl:
+	list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry)
+		pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
 
-out_free_rbpl_base:
 	pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE *
 			sizeof(struct he_rbp), he_dev->rbpl_base,
 			he_dev->rbpl_phys);
 out_destroy_rbpl_pool:
 	pci_pool_destroy(he_dev->rbpl_pool);
+out_free_rbpl_virt:
+	kfree(he_dev->rbpl_virt);
+out_free_rbpl_table:
+	kfree(he_dev->rbpl_table);
 
-	i = CONFIG_RBPS_SIZE;
-out_free_rbps_virt:
-	while (i--)
-		pci_pool_free(he_dev->rbps_pool, he_dev->rbps_virt[i].virt,
-				he_dev->rbps_base[i].phys);
-	kfree(he_dev->rbps_virt);
-
-out_free_rbps_base:
-	pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE *
-			sizeof(struct he_rbp), he_dev->rbps_base,
-			he_dev->rbps_phys);
-out_destroy_rbps_pool:
-	pci_pool_destroy(he_dev->rbps_pool);
 	return -ENOMEM;
 }
 
@@ -1002,7 +967,8 @@
 	he_writel(he_dev, 0x0, GRP_54_MAP);
 	he_writel(he_dev, 0x0, GRP_76_MAP);
 
-	if (request_irq(he_dev->pci_dev->irq, he_irq_handler, IRQF_DISABLED|IRQF_SHARED, DEV_LABEL, he_dev)) {
+	if (request_irq(he_dev->pci_dev->irq,
+			he_irq_handler, IRQF_SHARED, DEV_LABEL, he_dev)) {
 		hprintk("irq %d already in use\n", he_dev->pci_dev->irq);
 		return -EINVAL;
 	}   
@@ -1576,9 +1542,10 @@
 static void
 he_stop(struct he_dev *he_dev)
 {
-	u16 command;
-	u32 gen_cntl_0, reg;
+	struct he_buff *heb, *next;
 	struct pci_dev *pci_dev;
+	u32 gen_cntl_0, reg;
+	u16 command;
 
 	pci_dev = he_dev->pci_dev;
 
@@ -1619,37 +1586,19 @@
 						he_dev->hsp, he_dev->hsp_phys);
 
 	if (he_dev->rbpl_base) {
-		int i;
+		list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry)
+			pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
 
-		for (i = 0; i < CONFIG_RBPL_SIZE; ++i) {
-			void *cpuaddr = he_dev->rbpl_virt[i].virt;
-			dma_addr_t dma_handle = he_dev->rbpl_base[i].phys;
-
-			pci_pool_free(he_dev->rbpl_pool, cpuaddr, dma_handle);
-		}
 		pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE
 			* sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys);
 	}
 
+	kfree(he_dev->rbpl_virt);
+	kfree(he_dev->rbpl_table);
+
 	if (he_dev->rbpl_pool)
 		pci_pool_destroy(he_dev->rbpl_pool);
 
-	if (he_dev->rbps_base) {
-		int i;
-
-		for (i = 0; i < CONFIG_RBPS_SIZE; ++i) {
-			void *cpuaddr = he_dev->rbps_virt[i].virt;
-			dma_addr_t dma_handle = he_dev->rbps_base[i].phys;
-
-			pci_pool_free(he_dev->rbps_pool, cpuaddr, dma_handle);
-		}
-		pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE
-			* sizeof(struct he_rbp), he_dev->rbps_base, he_dev->rbps_phys);
-	}
-
-	if (he_dev->rbps_pool)
-		pci_pool_destroy(he_dev->rbps_pool);
-
 	if (he_dev->rbrq_base)
 		pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq),
 							he_dev->rbrq_base, he_dev->rbrq_phys);
@@ -1679,13 +1628,13 @@
 __alloc_tpd(struct he_dev *he_dev)
 {
 	struct he_tpd *tpd;
-	dma_addr_t dma_handle; 
+	dma_addr_t mapping;
 
-	tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &dma_handle);
+	tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &mapping);
 	if (tpd == NULL)
 		return NULL;
 			
-	tpd->status = TPD_ADDR(dma_handle);
+	tpd->status = TPD_ADDR(mapping);
 	tpd->reserved = 0; 
 	tpd->iovec[0].addr = 0; tpd->iovec[0].len = 0;
 	tpd->iovec[1].addr = 0; tpd->iovec[1].len = 0;
@@ -1714,13 +1663,12 @@
 	struct he_rbrq *rbrq_tail = (struct he_rbrq *)
 				((unsigned long)he_dev->rbrq_base |
 					he_dev->hsp->group[group].rbrq_tail);
-	struct he_rbp *rbp = NULL;
 	unsigned cid, lastcid = -1;
-	unsigned buf_len = 0;
 	struct sk_buff *skb;
 	struct atm_vcc *vcc = NULL;
 	struct he_vcc *he_vcc;
-	struct he_iovec *iov;
+	struct he_buff *heb, *next;
+	int i;
 	int pdus_assembled = 0;
 	int updated = 0;
 
@@ -1740,44 +1688,35 @@
 			RBRQ_CON_CLOSED(he_dev->rbrq_head) ? " CON_CLOSED" : "",
 			RBRQ_HBUF_ERR(he_dev->rbrq_head) ? " HBUF_ERR" : "");
 
-		if (RBRQ_ADDR(he_dev->rbrq_head) & RBP_SMALLBUF)
-			rbp = &he_dev->rbps_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))];
-		else
-			rbp = &he_dev->rbpl_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))];
-		
-		buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4;
-		cid = RBRQ_CID(he_dev->rbrq_head);
+		i = RBRQ_ADDR(he_dev->rbrq_head) >> RBP_IDX_OFFSET;
+		heb = he_dev->rbpl_virt[i];
 
+		cid = RBRQ_CID(he_dev->rbrq_head);
 		if (cid != lastcid)
 			vcc = __find_vcc(he_dev, cid);
 		lastcid = cid;
 
-		if (vcc == NULL) {
-			hprintk("vcc == NULL  (cid 0x%x)\n", cid);
-			if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
-					rbp->status &= ~RBP_LOANED;
+		if (vcc == NULL || (he_vcc = HE_VCC(vcc)) == NULL) {
+			hprintk("vcc/he_vcc == NULL  (cid 0x%x)\n", cid);
+			if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) {
+				clear_bit(i, he_dev->rbpl_table);
+				list_del(&heb->entry);
+				pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
+			}
 					
 			goto next_rbrq_entry;
 		}
 
-		he_vcc = HE_VCC(vcc);
-		if (he_vcc == NULL) {
-			hprintk("he_vcc == NULL  (cid 0x%x)\n", cid);
-			if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
-					rbp->status &= ~RBP_LOANED;
-			goto next_rbrq_entry;
-		}
-
 		if (RBRQ_HBUF_ERR(he_dev->rbrq_head)) {
 			hprintk("HBUF_ERR!  (cid 0x%x)\n", cid);
 				atomic_inc(&vcc->stats->rx_drop);
 			goto return_host_buffers;
 		}
 
-		he_vcc->iov_tail->iov_base = RBRQ_ADDR(he_dev->rbrq_head);
-		he_vcc->iov_tail->iov_len = buf_len;
-		he_vcc->pdu_len += buf_len;
-		++he_vcc->iov_tail;
+		heb->len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4;
+		clear_bit(i, he_dev->rbpl_table);
+		list_move_tail(&heb->entry, &he_vcc->buffers);
+		he_vcc->pdu_len += heb->len;
 
 		if (RBRQ_CON_CLOSED(he_dev->rbrq_head)) {
 			lastcid = -1;
@@ -1786,12 +1725,6 @@
 			goto return_host_buffers;
 		}
 
-#ifdef notdef
-		if ((he_vcc->iov_tail - he_vcc->iov_head) > HE_MAXIOV) {
-			hprintk("iovec full!  cid 0x%x\n", cid);
-			goto return_host_buffers;
-		}
-#endif
 		if (!RBRQ_END_PDU(he_dev->rbrq_head))
 			goto next_rbrq_entry;
 
@@ -1819,15 +1752,8 @@
 
 		__net_timestamp(skb);
 
-		for (iov = he_vcc->iov_head;
-				iov < he_vcc->iov_tail; ++iov) {
-			if (iov->iov_base & RBP_SMALLBUF)
-				memcpy(skb_put(skb, iov->iov_len),
-					he_dev->rbps_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len);
-			else
-				memcpy(skb_put(skb, iov->iov_len),
-					he_dev->rbpl_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len);
-		}
+		list_for_each_entry(heb, &he_vcc->buffers, entry)
+			memcpy(skb_put(skb, heb->len), &heb->data, heb->len);
 
 		switch (vcc->qos.aal) {
 			case ATM_AAL0:
@@ -1867,17 +1793,9 @@
 return_host_buffers:
 		++pdus_assembled;
 
-		for (iov = he_vcc->iov_head;
-				iov < he_vcc->iov_tail; ++iov) {
-			if (iov->iov_base & RBP_SMALLBUF)
-				rbp = &he_dev->rbps_base[RBP_INDEX(iov->iov_base)];
-			else
-				rbp = &he_dev->rbpl_base[RBP_INDEX(iov->iov_base)];
-
-			rbp->status &= ~RBP_LOANED;
-		}
-
-		he_vcc->iov_tail = he_vcc->iov_head;
+		list_for_each_entry_safe(heb, next, &he_vcc->buffers, entry)
+			pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
+		INIT_LIST_HEAD(&he_vcc->buffers);
 		he_vcc->pdu_len = 0;
 
 next_rbrq_entry:
@@ -1978,27 +1896,46 @@
 	}
 }
 
-
 static void
 he_service_rbpl(struct he_dev *he_dev, int group)
 {
-	struct he_rbp *newtail;
+	struct he_rbp *new_tail;
 	struct he_rbp *rbpl_head;
+	struct he_buff *heb;
+	dma_addr_t mapping;
+	int i;
 	int moved = 0;
 
 	rbpl_head = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
 					RBPL_MASK(he_readl(he_dev, G0_RBPL_S)));
 
 	for (;;) {
-		newtail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
+		new_tail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
 						RBPL_MASK(he_dev->rbpl_tail+1));
 
 		/* table 3.42 -- rbpl_tail should never be set to rbpl_head */
-		if ((newtail == rbpl_head) || (newtail->status & RBP_LOANED))
+		if (new_tail == rbpl_head)
 			break;
 
-		newtail->status |= RBP_LOANED;
-		he_dev->rbpl_tail = newtail;
+		i = find_next_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE, he_dev->rbpl_hint);
+		if (i > (RBPL_TABLE_SIZE - 1)) {
+			i = find_first_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE);
+			if (i > (RBPL_TABLE_SIZE - 1))
+				break;
+		}
+		he_dev->rbpl_hint = i + 1;
+
+		heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_ATOMIC|GFP_DMA, &mapping);
+		if (!heb)
+			break;
+		heb->mapping = mapping;
+		list_add(&heb->entry, &he_dev->rbpl_outstanding);
+		he_dev->rbpl_virt[i] = heb;
+		set_bit(i, he_dev->rbpl_table);
+		new_tail->idx = i << RBP_IDX_OFFSET;
+		new_tail->phys = mapping + offsetof(struct he_buff, data);
+
+		he_dev->rbpl_tail = new_tail;
 		++moved;
 	} 
 
@@ -2007,33 +1944,6 @@
 }
 
 static void
-he_service_rbps(struct he_dev *he_dev, int group)
-{
-	struct he_rbp *newtail;
-	struct he_rbp *rbps_head;
-	int moved = 0;
-
-	rbps_head = (struct he_rbp *) ((unsigned long)he_dev->rbps_base |
-					RBPS_MASK(he_readl(he_dev, G0_RBPS_S)));
-
-	for (;;) {
-		newtail = (struct he_rbp *) ((unsigned long)he_dev->rbps_base |
-						RBPS_MASK(he_dev->rbps_tail+1));
-
-		/* table 3.42 -- rbps_tail should never be set to rbps_head */
-		if ((newtail == rbps_head) || (newtail->status & RBP_LOANED))
-			break;
-
-		newtail->status |= RBP_LOANED;
-		he_dev->rbps_tail = newtail;
-		++moved;
-	} 
-
-	if (moved)
-		he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), G0_RBPS_T);
-}
-
-static void
 he_tasklet(unsigned long data)
 {
 	unsigned long flags;
@@ -2055,10 +1965,8 @@
 				HPRINTK("rbrq%d threshold\n", group);
 				/* fall through */
 			case ITYPE_RBRQ_TIMER:
-				if (he_service_rbrq(he_dev, group)) {
+				if (he_service_rbrq(he_dev, group))
 					he_service_rbpl(he_dev, group);
-					he_service_rbps(he_dev, group);
-				}
 				break;
 			case ITYPE_TBRQ_THRESH:
 				HPRINTK("tbrq%d threshold\n", group);
@@ -2070,7 +1978,7 @@
 				he_service_rbpl(he_dev, group);
 				break;
 			case ITYPE_RBPS_THRESH:
-				he_service_rbps(he_dev, group);
+				/* shouldn't happen unless small buffers enabled */
 				break;
 			case ITYPE_PHY:
 				HPRINTK("phy interrupt\n");
@@ -2098,7 +2006,6 @@
 
 				he_service_rbrq(he_dev, 0);
 				he_service_rbpl(he_dev, 0);
-				he_service_rbps(he_dev, 0);
 				he_service_tbrq(he_dev, 0);
 				break;
 			default:
@@ -2252,7 +2159,7 @@
 		return -ENOMEM;
 	}
 
-	he_vcc->iov_tail = he_vcc->iov_head;
+	INIT_LIST_HEAD(&he_vcc->buffers);
 	he_vcc->pdu_len = 0;
 	he_vcc->rc_index = -1;
 
@@ -2406,8 +2313,8 @@
 			goto open_failed;
 		}
 
-		rsr1 = RSR1_GROUP(0);
-		rsr4 = RSR4_GROUP(0);
+		rsr1 = RSR1_GROUP(0) | RSR1_RBPL_ONLY;
+		rsr4 = RSR4_GROUP(0) | RSR4_RBPL_ONLY;
 		rsr0 = vcc->qos.rxtp.traffic_class == ATM_UBR ? 
 				(RSR0_EPD_ENABLE|RSR0_PPD_ENABLE) : 0;
 
@@ -2963,8 +2870,7 @@
 MODULE_PARM_DESC(sdh, "use SDH framing (default 0)");
 
 static struct pci_device_id he_pci_tbl[] = {
-	{ PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_HE, PCI_ANY_ID, PCI_ANY_ID,
-	  0, 0, 0 },
+	{ PCI_VDEVICE(FORE, PCI_DEVICE_ID_FORE_HE), 0 },
 	{ 0, }
 };
 
diff --git a/drivers/atm/he.h b/drivers/atm/he.h
index c2983e0..110a27d 100644
--- a/drivers/atm/he.h
+++ b/drivers/atm/he.h
@@ -67,11 +67,6 @@
 #define CONFIG_RBPL_BUFSIZE	4096
 #define RBPL_MASK(x)		(((unsigned long)(x))&((CONFIG_RBPL_SIZE<<3)-1))
 
-#define CONFIG_RBPS_SIZE	1024
-#define CONFIG_RBPS_THRESH	64
-#define CONFIG_RBPS_BUFSIZE	128
-#define RBPS_MASK(x)		(((unsigned long)(x))&((CONFIG_RBPS_SIZE<<3)-1))
-
 /* 5.1.3 initialize connection memory */
 
 #define CONFIG_RSRA		0x00000
@@ -203,36 +198,37 @@
 	} group[HE_NUM_GROUPS];
 };
 
-/* figure 2.9 receive buffer pools */
+/*
+ * figure 2.9 receive buffer pools
+ *
+ * since a virtual address might be more than 32 bits, we store an index
+ * in the virt member of he_rbp.  NOTE: the lower six bits in the  rbrq
+ * addr member are used for buffer status further limiting us to 26 bits.
+ */
 
 struct he_rbp {
 	volatile u32 phys;
-	volatile u32 status;
+	volatile u32 idx;	/* virt */
 };
 
-/* NOTE: it is suggested that virt be the virtual address of the host
-   buffer.  on a 64-bit machine, this would not work.  Instead, we
-   store the real virtual address in another list, and store an index
-   (and buffer status) in the virt member.
-*/
+#define RBP_IDX_OFFSET 6
 
-#define RBP_INDEX_OFF	6
-#define RBP_INDEX(x)	(((long)(x) >> RBP_INDEX_OFF) & 0xffff)
-#define RBP_LOANED	0x80000000
-#define RBP_SMALLBUF	0x40000000
+/*
+ * the he dma engine will try to hold an extra 16 buffers in its local
+ * caches.  and add a couple buffers for safety.
+ */
 
-struct he_virt {
-	void *virt;
+#define RBPL_TABLE_SIZE (CONFIG_RBPL_SIZE + 16 + 2)
+
+struct he_buff {
+	struct list_head entry;
+	dma_addr_t mapping;
+	unsigned long len;
+	u8 data[];
 };
 
-#define RBPL_ALIGNMENT CONFIG_RBPL_SIZE
-#define RBPS_ALIGNMENT CONFIG_RBPS_SIZE
-
 #ifdef notyet
 struct he_group {
-	u32 rpbs_size, rpbs_qsize;
-	struct he_rbp rbps_ba;
-
 	u32 rpbl_size, rpbl_qsize;
 	struct he_rpb_entry *rbpl_ba;
 };
@@ -297,18 +293,15 @@
 	struct he_rbrq *rbrq_base, *rbrq_head;
 	int rbrq_peak;
 
+	struct he_buff **rbpl_virt;
+	unsigned long *rbpl_table;
+	unsigned long rbpl_hint;
 	struct pci_pool *rbpl_pool;
 	dma_addr_t rbpl_phys;
 	struct he_rbp *rbpl_base, *rbpl_tail;
-	struct he_virt *rbpl_virt;
+	struct list_head rbpl_outstanding;
 	int rbpl_peak;
 
-	struct pci_pool *rbps_pool;
-	dma_addr_t rbps_phys;
-	struct he_rbp *rbps_base, *rbps_tail;
-	struct he_virt *rbps_virt;
-	int rbps_peak;
-
 	dma_addr_t tbrq_phys;
 	struct he_tbrq *tbrq_base, *tbrq_head;
 	int tbrq_peak;
@@ -321,20 +314,12 @@
 	struct he_dev *next;
 };
 
-struct he_iovec
-{
-	u32 iov_base;
-	u32 iov_len;
-};
-
 #define HE_MAXIOV 20
 
 struct he_vcc
 {
-	struct he_iovec iov_head[HE_MAXIOV];
-	struct he_iovec *iov_tail;
+	struct list_head buffers;
 	int pdu_len;
-
 	int rc_index;
 
 	wait_queue_head_t rx_waitq;
diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c
index dab5cf5..bca9cb8 100644
--- a/drivers/atm/idt77105.c
+++ b/drivers/atm/idt77105.c
@@ -126,7 +126,7 @@
                 istat = GET(ISTAT); /* side effect: clears all interrupt status bits */
                 if (istat & IDT77105_ISTAT_GOODSIG) {
                     /* Found signal again */
-                    dev->signal = ATM_PHY_SIG_FOUND;
+                    atm_dev_signal_change(dev, ATM_PHY_SIG_FOUND);
 	            printk(KERN_NOTICE "%s(itf %d): signal detected again\n",
                         dev->type,dev->number);
                     /* flush the receive FIFO */
@@ -222,7 +222,7 @@
             /* Rx Signal Condition Change - line went up or down */
             if (istat & IDT77105_ISTAT_GOODSIG) {   /* signal detected again */
                 /* This should not happen (restart timer does it) but JIC */
-                dev->signal = ATM_PHY_SIG_FOUND;
+		atm_dev_signal_change(dev, ATM_PHY_SIG_FOUND);
             } else {    /* signal lost */
                 /*
                  * Disable interrupts and stop all transmission and
@@ -235,7 +235,7 @@
                     IDT77105_MCR_DRIC|
                     IDT77105_MCR_HALTTX
                     ) & ~IDT77105_MCR_EIP, MCR);
-                dev->signal = ATM_PHY_SIG_LOST;
+		atm_dev_signal_change(dev, ATM_PHY_SIG_LOST);
 	        printk(KERN_NOTICE "%s(itf %d): signal lost\n",
                     dev->type,dev->number);
             }
@@ -272,8 +272,9 @@
 	memset(&PRIV(dev)->stats,0,sizeof(struct idt77105_stats));
         
         /* initialise dev->signal from Good Signal Bit */
-        dev->signal = GET(ISTAT) & IDT77105_ISTAT_GOODSIG ? ATM_PHY_SIG_FOUND :
-	  ATM_PHY_SIG_LOST;
+	atm_dev_signal_change(dev,
+		GET(ISTAT) & IDT77105_ISTAT_GOODSIG ?
+		ATM_PHY_SIG_FOUND : ATM_PHY_SIG_LOST);
 	if (dev->signal == ATM_PHY_SIG_LOST)
 		printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type,
 		    dev->number);
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index 98657a6..1679cbf 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -3364,7 +3364,7 @@
 		writel(SAR_STAT_TMROF, SAR_REG_STAT);
 	}
 	IPRINTK("%s: Request IRQ ... ", card->name);
-	if (request_irq(pcidev->irq, idt77252_interrupt, IRQF_DISABLED|IRQF_SHARED,
+	if (request_irq(pcidev->irq, idt77252_interrupt, IRQF_SHARED,
 			card->name, card) != 0) {
 		printk("%s: can't allocate IRQ.\n", card->name);
 		deinit_card(card);
@@ -3779,8 +3779,7 @@
 
 static struct pci_device_id idt77252_pci_tbl[] =
 {
-	{ PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_IDT_IDT77252,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VDEVICE(IDT, PCI_DEVICE_ID_IDT_IDT77252), 0 },
 	{ 0, }
 };
 
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index b7473a6..2f3516b 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -1,5 +1,4 @@
-/******************************************************************************
- *
+/*
  * nicstar.c
  *
  * Device driver supporting CBR for IDT 77201/77211 "NICStAR" based cards.
@@ -16,12 +15,10 @@
  *
  *
  * (C) INESC 1999
- *
- *
- ******************************************************************************/
+ */
 
-
-/**** IMPORTANT INFORMATION ***************************************************
+/*
+ * IMPORTANT INFORMATION
  *
  * There are currently three types of spinlocks:
  *
@@ -31,9 +28,9 @@
  *
  * These must NEVER be grabbed in reverse order.
  *
- ******************************************************************************/
+ */
 
-/* Header files ***************************************************************/
+/* Header files */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -41,6 +38,7 @@
 #include <linux/atmdev.h>
 #include <linux/atm.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/delay.h>
@@ -50,6 +48,7 @@
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
+#include <linux/idr.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
@@ -61,16 +60,11 @@
 #include "idt77105.h"
 #endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
 
-#if BITS_PER_LONG != 32
-#  error FIXME: this driver requires a 32-bit platform
-#endif
-
-/* Additional code ************************************************************/
+/* Additional code */
 
 #include "nicstarmac.c"
 
-
-/* Configurable parameters ****************************************************/
+/* Configurable parameters */
 
 #undef PHY_LOOPBACK
 #undef TX_DEBUG
@@ -78,11 +72,10 @@
 #undef GENERAL_DEBUG
 #undef EXTRA_DEBUG
 
-#undef NS_USE_DESTRUCTORS /* For now keep this undefined unless you know
-                             you're going to use only raw ATM */
+#undef NS_USE_DESTRUCTORS	/* For now keep this undefined unless you know
+				   you're going to use only raw ATM */
 
-
-/* Do not touch these *********************************************************/
+/* Do not touch these */
 
 #ifdef TX_DEBUG
 #define TXPRINTK(args...) printk(args)
@@ -108,2908 +101,2773 @@
 #define XPRINTK(args...)
 #endif /* EXTRA_DEBUG */
 
-
-/* Macros *********************************************************************/
+/* Macros */
 
 #define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ)
 
 #define NS_DELAY mdelay(1)
 
-#define ALIGN_BUS_ADDR(addr, alignment) \
-        ((((u32) (addr)) + (((u32) (alignment)) - 1)) & ~(((u32) (alignment)) - 1))
-#define ALIGN_ADDRESS(addr, alignment) \
-        bus_to_virt(ALIGN_BUS_ADDR(virt_to_bus(addr), alignment))
-
-#undef CEIL
+#define PTR_DIFF(a, b)	((u32)((unsigned long)(a) - (unsigned long)(b)))
 
 #ifndef ATM_SKB
 #define ATM_SKB(s) (&(s)->atm)
 #endif
 
+#define scq_virt_to_bus(scq, p) \
+		(scq->dma + ((unsigned long)(p) - (unsigned long)(scq)->org))
 
-/* Function declarations ******************************************************/
+/* Function declarations */
 
-static u32 ns_read_sram(ns_dev *card, u32 sram_address);
-static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count);
+static u32 ns_read_sram(ns_dev * card, u32 sram_address);
+static void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value,
+			  int count);
 static int __devinit ns_init_card(int i, struct pci_dev *pcidev);
-static void __devinit ns_init_card_error(ns_dev *card, int error);
-static scq_info *get_scq(int size, u32 scd);
-static void free_scq(scq_info *scq, struct atm_vcc *vcc);
+static void __devinit ns_init_card_error(ns_dev * card, int error);
+static scq_info *get_scq(ns_dev *card, int size, u32 scd);
+static void free_scq(ns_dev *card, scq_info * scq, struct atm_vcc *vcc);
 static void push_rxbufs(ns_dev *, struct sk_buff *);
 static irqreturn_t ns_irq_handler(int irq, void *dev_id);
 static int ns_open(struct atm_vcc *vcc);
 static void ns_close(struct atm_vcc *vcc);
-static void fill_tst(ns_dev *card, int n, vc_map *vc);
+static void fill_tst(ns_dev * card, int n, vc_map * vc);
 static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb);
-static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd,
-                     struct sk_buff *skb);
-static void process_tsq(ns_dev *card);
-static void drain_scq(ns_dev *card, scq_info *scq, int pos);
-static void process_rsq(ns_dev *card);
-static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe);
+static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
+		     struct sk_buff *skb);
+static void process_tsq(ns_dev * card);
+static void drain_scq(ns_dev * card, scq_info * scq, int pos);
+static void process_rsq(ns_dev * card);
+static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe);
 #ifdef NS_USE_DESTRUCTORS
 static void ns_sb_destructor(struct sk_buff *sb);
 static void ns_lb_destructor(struct sk_buff *lb);
 static void ns_hb_destructor(struct sk_buff *hb);
 #endif /* NS_USE_DESTRUCTORS */
-static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb);
-static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count);
-static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb);
-static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb);
-static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb);
-static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page);
-static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg);
-static void which_list(ns_dev *card, struct sk_buff *skb);
+static void recycle_rx_buf(ns_dev * card, struct sk_buff *skb);
+static void recycle_iovec_rx_bufs(ns_dev * card, struct iovec *iov, int count);
+static void recycle_iov_buf(ns_dev * card, struct sk_buff *iovb);
+static void dequeue_sm_buf(ns_dev * card, struct sk_buff *sb);
+static void dequeue_lg_buf(ns_dev * card, struct sk_buff *lb);
+static int ns_proc_read(struct atm_dev *dev, loff_t * pos, char *page);
+static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg);
+#ifdef EXTRA_DEBUG
+static void which_list(ns_dev * card, struct sk_buff *skb);
+#endif
 static void ns_poll(unsigned long arg);
 static int ns_parse_mac(char *mac, unsigned char *esi);
-static short ns_h2i(char c);
 static void ns_phy_put(struct atm_dev *dev, unsigned char value,
-                       unsigned long addr);
+		       unsigned long addr);
 static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr);
 
-
-
-/* Global variables ***********************************************************/
+/* Global variables */
 
 static struct ns_dev *cards[NS_MAX_CARDS];
 static unsigned num_cards;
-static struct atmdev_ops atm_ops =
-{
-   .open	= ns_open,
-   .close	= ns_close,
-   .ioctl	= ns_ioctl,
-   .send	= ns_send,
-   .phy_put	= ns_phy_put,
-   .phy_get	= ns_phy_get,
-   .proc_read	= ns_proc_read,
-   .owner	= THIS_MODULE,
+static struct atmdev_ops atm_ops = {
+	.open = ns_open,
+	.close = ns_close,
+	.ioctl = ns_ioctl,
+	.send = ns_send,
+	.phy_put = ns_phy_put,
+	.phy_get = ns_phy_get,
+	.proc_read = ns_proc_read,
+	.owner = THIS_MODULE,
 };
+
 static struct timer_list ns_timer;
 static char *mac[NS_MAX_CARDS];
 module_param_array(mac, charp, NULL, 0);
 MODULE_LICENSE("GPL");
 
-
-/* Functions*******************************************************************/
+/* Functions */
 
 static int __devinit nicstar_init_one(struct pci_dev *pcidev,
 				      const struct pci_device_id *ent)
 {
-   static int index = -1;
-   unsigned int error;
+	static int index = -1;
+	unsigned int error;
 
-   index++;
-   cards[index] = NULL;
+	index++;
+	cards[index] = NULL;
 
-   error = ns_init_card(index, pcidev);
-   if (error) {
-      cards[index--] = NULL;	/* don't increment index */
-      goto err_out;
-   }
+	error = ns_init_card(index, pcidev);
+	if (error) {
+		cards[index--] = NULL;	/* don't increment index */
+		goto err_out;
+	}
 
-   return 0;
+	return 0;
 err_out:
-   return -ENODEV;
+	return -ENODEV;
 }
 
-
-
 static void __devexit nicstar_remove_one(struct pci_dev *pcidev)
 {
-   int i, j;
-   ns_dev *card = pci_get_drvdata(pcidev);
-   struct sk_buff *hb;
-   struct sk_buff *iovb;
-   struct sk_buff *lb;
-   struct sk_buff *sb;
-   
-   i = card->index;
+	int i, j;
+	ns_dev *card = pci_get_drvdata(pcidev);
+	struct sk_buff *hb;
+	struct sk_buff *iovb;
+	struct sk_buff *lb;
+	struct sk_buff *sb;
 
-   if (cards[i] == NULL)
-      return;
+	i = card->index;
 
-   if (card->atmdev->phy && card->atmdev->phy->stop)
-      card->atmdev->phy->stop(card->atmdev);
+	if (cards[i] == NULL)
+		return;
 
-   /* Stop everything */
-   writel(0x00000000, card->membase + CFG);
+	if (card->atmdev->phy && card->atmdev->phy->stop)
+		card->atmdev->phy->stop(card->atmdev);
 
-   /* De-register device */
-   atm_dev_deregister(card->atmdev);
+	/* Stop everything */
+	writel(0x00000000, card->membase + CFG);
 
-   /* Disable PCI device */
-   pci_disable_device(pcidev);
-   
-   /* Free up resources */
-   j = 0;
-   PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count);
-   while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
-   {
-      dev_kfree_skb_any(hb);
-      j++;
-   }
-   PRINTK("nicstar%d: %d huge buffers freed.\n", i, j);
-   j = 0;
-   PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, card->iovpool.count);
-   while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
-   {
-      dev_kfree_skb_any(iovb);
-      j++;
-   }
-   PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j);
-   while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
-      dev_kfree_skb_any(lb);
-   while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
-      dev_kfree_skb_any(sb);
-   free_scq(card->scq0, NULL);
-   for (j = 0; j < NS_FRSCD_NUM; j++)
-   {
-      if (card->scd2vc[j] != NULL)
-         free_scq(card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc);
-   }
-   kfree(card->rsq.org);
-   kfree(card->tsq.org);
-   free_irq(card->pcidev->irq, card);
-   iounmap(card->membase);
-   kfree(card);
+	/* De-register device */
+	atm_dev_deregister(card->atmdev);
+
+	/* Disable PCI device */
+	pci_disable_device(pcidev);
+
+	/* Free up resources */
+	j = 0;
+	PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count);
+	while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) {
+		dev_kfree_skb_any(hb);
+		j++;
+	}
+	PRINTK("nicstar%d: %d huge buffers freed.\n", i, j);
+	j = 0;
+	PRINTK("nicstar%d: freeing %d iovec buffers.\n", i,
+	       card->iovpool.count);
+	while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) {
+		dev_kfree_skb_any(iovb);
+		j++;
+	}
+	PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j);
+	while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
+		dev_kfree_skb_any(lb);
+	while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
+		dev_kfree_skb_any(sb);
+	free_scq(card, card->scq0, NULL);
+	for (j = 0; j < NS_FRSCD_NUM; j++) {
+		if (card->scd2vc[j] != NULL)
+			free_scq(card, card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc);
+	}
+	idr_remove_all(&card->idr);
+	idr_destroy(&card->idr);
+	pci_free_consistent(card->pcidev, NS_RSQSIZE + NS_RSQ_ALIGNMENT,
+			    card->rsq.org, card->rsq.dma);
+	pci_free_consistent(card->pcidev, NS_TSQSIZE + NS_TSQ_ALIGNMENT,
+			    card->tsq.org, card->tsq.dma);
+	free_irq(card->pcidev->irq, card);
+	iounmap(card->membase);
+	kfree(card);
 }
 
-
-
-static struct pci_device_id nicstar_pci_tbl[] __devinitdata =
-{
-	{PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_IDT_IDT77201,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static struct pci_device_id nicstar_pci_tbl[] __devinitdata = {
+	{ PCI_VDEVICE(IDT, PCI_DEVICE_ID_IDT_IDT77201), 0 },
 	{0,}			/* terminate list */
 };
+
 MODULE_DEVICE_TABLE(pci, nicstar_pci_tbl);
 
-
-
 static struct pci_driver nicstar_driver = {
-	.name		= "nicstar",
-	.id_table	= nicstar_pci_tbl,
-	.probe		= nicstar_init_one,
-	.remove		= __devexit_p(nicstar_remove_one),
+	.name = "nicstar",
+	.id_table = nicstar_pci_tbl,
+	.probe = nicstar_init_one,
+	.remove = __devexit_p(nicstar_remove_one),
 };
 
-
-
 static int __init nicstar_init(void)
 {
-   unsigned error = 0;	/* Initialized to remove compile warning */
+	unsigned error = 0;	/* Initialized to remove compile warning */
 
-   XPRINTK("nicstar: nicstar_init() called.\n");
+	XPRINTK("nicstar: nicstar_init() called.\n");
 
-   error = pci_register_driver(&nicstar_driver);
-   
-   TXPRINTK("nicstar: TX debug enabled.\n");
-   RXPRINTK("nicstar: RX debug enabled.\n");
-   PRINTK("nicstar: General debug enabled.\n");
+	error = pci_register_driver(&nicstar_driver);
+
+	TXPRINTK("nicstar: TX debug enabled.\n");
+	RXPRINTK("nicstar: RX debug enabled.\n");
+	PRINTK("nicstar: General debug enabled.\n");
 #ifdef PHY_LOOPBACK
-   printk("nicstar: using PHY loopback.\n");
+	printk("nicstar: using PHY loopback.\n");
 #endif /* PHY_LOOPBACK */
-   XPRINTK("nicstar: nicstar_init() returned.\n");
+	XPRINTK("nicstar: nicstar_init() returned.\n");
 
-   if (!error) {
-      init_timer(&ns_timer);
-      ns_timer.expires = jiffies + NS_POLL_PERIOD;
-      ns_timer.data = 0UL;
-      ns_timer.function = ns_poll;
-      add_timer(&ns_timer);
-   }
-   
-   return error;
+	if (!error) {
+		init_timer(&ns_timer);
+		ns_timer.expires = jiffies + NS_POLL_PERIOD;
+		ns_timer.data = 0UL;
+		ns_timer.function = ns_poll;
+		add_timer(&ns_timer);
+	}
+
+	return error;
 }
 
-
-
 static void __exit nicstar_cleanup(void)
 {
-   XPRINTK("nicstar: nicstar_cleanup() called.\n");
+	XPRINTK("nicstar: nicstar_cleanup() called.\n");
 
-   del_timer(&ns_timer);
+	del_timer(&ns_timer);
 
-   pci_unregister_driver(&nicstar_driver);
+	pci_unregister_driver(&nicstar_driver);
 
-   XPRINTK("nicstar: nicstar_cleanup() returned.\n");
+	XPRINTK("nicstar: nicstar_cleanup() returned.\n");
 }
 
-
-
-static u32 ns_read_sram(ns_dev *card, u32 sram_address)
+static u32 ns_read_sram(ns_dev * card, u32 sram_address)
 {
-   unsigned long flags;
-   u32 data;
-   sram_address <<= 2;
-   sram_address &= 0x0007FFFC;	/* address must be dword aligned */
-   sram_address |= 0x50000000;	/* SRAM read command */
-   spin_lock_irqsave(&card->res_lock, flags);
-   while (CMD_BUSY(card));
-   writel(sram_address, card->membase + CMD);
-   while (CMD_BUSY(card));
-   data = readl(card->membase + DR0);
-   spin_unlock_irqrestore(&card->res_lock, flags);
-   return data;
+	unsigned long flags;
+	u32 data;
+	sram_address <<= 2;
+	sram_address &= 0x0007FFFC;	/* address must be dword aligned */
+	sram_address |= 0x50000000;	/* SRAM read command */
+	spin_lock_irqsave(&card->res_lock, flags);
+	while (CMD_BUSY(card)) ;
+	writel(sram_address, card->membase + CMD);
+	while (CMD_BUSY(card)) ;
+	data = readl(card->membase + DR0);
+	spin_unlock_irqrestore(&card->res_lock, flags);
+	return data;
 }
 
-
-   
-static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count)
+static void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value,
+			  int count)
 {
-   unsigned long flags;
-   int i, c;
-   count--;	/* count range now is 0..3 instead of 1..4 */
-   c = count;
-   c <<= 2;	/* to use increments of 4 */
-   spin_lock_irqsave(&card->res_lock, flags);
-   while (CMD_BUSY(card));
-   for (i = 0; i <= c; i += 4)
-      writel(*(value++), card->membase + i);
-   /* Note: DR# registers are the first 4 dwords in nicstar's memspace,
-            so card->membase + DR0 == card->membase */
-   sram_address <<= 2;
-   sram_address &= 0x0007FFFC;
-   sram_address |= (0x40000000 | count);
-   writel(sram_address, card->membase + CMD);
-   spin_unlock_irqrestore(&card->res_lock, flags);
+	unsigned long flags;
+	int i, c;
+	count--;		/* count range now is 0..3 instead of 1..4 */
+	c = count;
+	c <<= 2;		/* to use increments of 4 */
+	spin_lock_irqsave(&card->res_lock, flags);
+	while (CMD_BUSY(card)) ;
+	for (i = 0; i <= c; i += 4)
+		writel(*(value++), card->membase + i);
+	/* Note: DR# registers are the first 4 dwords in nicstar's memspace,
+	   so card->membase + DR0 == card->membase */
+	sram_address <<= 2;
+	sram_address &= 0x0007FFFC;
+	sram_address |= (0x40000000 | count);
+	writel(sram_address, card->membase + CMD);
+	spin_unlock_irqrestore(&card->res_lock, flags);
 }
 
-
 static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
 {
-   int j;
-   struct ns_dev *card = NULL;
-   unsigned char pci_latency;
-   unsigned error;
-   u32 data;
-   u32 u32d[4];
-   u32 ns_cfg_rctsize;
-   int bcount;
-   unsigned long membase;
+	int j;
+	struct ns_dev *card = NULL;
+	unsigned char pci_latency;
+	unsigned error;
+	u32 data;
+	u32 u32d[4];
+	u32 ns_cfg_rctsize;
+	int bcount;
+	unsigned long membase;
 
-   error = 0;
+	error = 0;
 
-   if (pci_enable_device(pcidev))
-   {
-      printk("nicstar%d: can't enable PCI device\n", i);
-      error = 2;
-      ns_init_card_error(card, error);
-      return error;
-   }
+	if (pci_enable_device(pcidev)) {
+		printk("nicstar%d: can't enable PCI device\n", i);
+		error = 2;
+		ns_init_card_error(card, error);
+		return error;
+	}
+        if ((pci_set_dma_mask(pcidev, DMA_BIT_MASK(32)) != 0) ||
+	    (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32)) != 0)) {
+                printk(KERN_WARNING
+		       "nicstar%d: No suitable DMA available.\n", i);
+		error = 2;
+		ns_init_card_error(card, error);
+		return error;
+        }
 
-   if ((card = kmalloc(sizeof(ns_dev), GFP_KERNEL)) == NULL)
-   {
-      printk("nicstar%d: can't allocate memory for device structure.\n", i);
-      error = 2;
-      ns_init_card_error(card, error);
-      return error;
-   }
-   cards[i] = card;
-   spin_lock_init(&card->int_lock);
-   spin_lock_init(&card->res_lock);
-      
-   pci_set_drvdata(pcidev, card);
-   
-   card->index = i;
-   card->atmdev = NULL;
-   card->pcidev = pcidev;
-   membase = pci_resource_start(pcidev, 1);
-   card->membase = ioremap(membase, NS_IOREMAP_SIZE);
-   if (!card->membase)
-   {
-      printk("nicstar%d: can't ioremap() membase.\n",i);
-      error = 3;
-      ns_init_card_error(card, error);
-      return error;
-   }
-   PRINTK("nicstar%d: membase at 0x%x.\n", i, card->membase);
+	if ((card = kmalloc(sizeof(ns_dev), GFP_KERNEL)) == NULL) {
+		printk
+		    ("nicstar%d: can't allocate memory for device structure.\n",
+		     i);
+		error = 2;
+		ns_init_card_error(card, error);
+		return error;
+	}
+	cards[i] = card;
+	spin_lock_init(&card->int_lock);
+	spin_lock_init(&card->res_lock);
 
-   pci_set_master(pcidev);
+	pci_set_drvdata(pcidev, card);
 
-   if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0)
-   {
-      printk("nicstar%d: can't read PCI latency timer.\n", i);
-      error = 6;
-      ns_init_card_error(card, error);
-      return error;
-   }
+	card->index = i;
+	card->atmdev = NULL;
+	card->pcidev = pcidev;
+	membase = pci_resource_start(pcidev, 1);
+	card->membase = ioremap(membase, NS_IOREMAP_SIZE);
+	if (!card->membase) {
+		printk("nicstar%d: can't ioremap() membase.\n", i);
+		error = 3;
+		ns_init_card_error(card, error);
+		return error;
+	}
+	PRINTK("nicstar%d: membase at 0x%p.\n", i, card->membase);
+
+	pci_set_master(pcidev);
+
+	if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0) {
+		printk("nicstar%d: can't read PCI latency timer.\n", i);
+		error = 6;
+		ns_init_card_error(card, error);
+		return error;
+	}
 #ifdef NS_PCI_LATENCY
-   if (pci_latency < NS_PCI_LATENCY)
-   {
-      PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, NS_PCI_LATENCY);
-      for (j = 1; j < 4; j++)
-      {
-         if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0)
-	    break;
-      }
-      if (j == 4)
-      {
-         printk("nicstar%d: can't set PCI latency timer to %d.\n", i, NS_PCI_LATENCY);
-         error = 7;
-         ns_init_card_error(card, error);
-	 return error;
-      }
-   }
+	if (pci_latency < NS_PCI_LATENCY) {
+		PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i,
+		       NS_PCI_LATENCY);
+		for (j = 1; j < 4; j++) {
+			if (pci_write_config_byte
+			    (pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0)
+				break;
+		}
+		if (j == 4) {
+			printk
+			    ("nicstar%d: can't set PCI latency timer to %d.\n",
+			     i, NS_PCI_LATENCY);
+			error = 7;
+			ns_init_card_error(card, error);
+			return error;
+		}
+	}
 #endif /* NS_PCI_LATENCY */
-      
-   /* Clear timer overflow */
-   data = readl(card->membase + STAT);
-   if (data & NS_STAT_TMROF)
-      writel(NS_STAT_TMROF, card->membase + STAT);
 
-   /* Software reset */
-   writel(NS_CFG_SWRST, card->membase + CFG);
-   NS_DELAY;
-   writel(0x00000000, card->membase + CFG);
+	/* Clear timer overflow */
+	data = readl(card->membase + STAT);
+	if (data & NS_STAT_TMROF)
+		writel(NS_STAT_TMROF, card->membase + STAT);
 
-   /* PHY reset */
-   writel(0x00000008, card->membase + GP);
-   NS_DELAY;
-   writel(0x00000001, card->membase + GP);
-   NS_DELAY;
-   while (CMD_BUSY(card));
-   writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD);	/* Sync UTOPIA with SAR clock */
-   NS_DELAY;
-      
-   /* Detect PHY type */
-   while (CMD_BUSY(card));
-   writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD);
-   while (CMD_BUSY(card));
-   data = readl(card->membase + DR0);
-   switch(data) {
-      case 0x00000009:
-         printk("nicstar%d: PHY seems to be 25 Mbps.\n", i);
-         card->max_pcr = ATM_25_PCR;
-         while(CMD_BUSY(card));
-         writel(0x00000008, card->membase + DR0);
-         writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD);
-         /* Clear an eventual pending interrupt */
-         writel(NS_STAT_SFBQF, card->membase + STAT);
+	/* Software reset */
+	writel(NS_CFG_SWRST, card->membase + CFG);
+	NS_DELAY;
+	writel(0x00000000, card->membase + CFG);
+
+	/* PHY reset */
+	writel(0x00000008, card->membase + GP);
+	NS_DELAY;
+	writel(0x00000001, card->membase + GP);
+	NS_DELAY;
+	while (CMD_BUSY(card)) ;
+	writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD);	/* Sync UTOPIA with SAR clock */
+	NS_DELAY;
+
+	/* Detect PHY type */
+	while (CMD_BUSY(card)) ;
+	writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD);
+	while (CMD_BUSY(card)) ;
+	data = readl(card->membase + DR0);
+	switch (data) {
+	case 0x00000009:
+		printk("nicstar%d: PHY seems to be 25 Mbps.\n", i);
+		card->max_pcr = ATM_25_PCR;
+		while (CMD_BUSY(card)) ;
+		writel(0x00000008, card->membase + DR0);
+		writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD);
+		/* Clear an eventual pending interrupt */
+		writel(NS_STAT_SFBQF, card->membase + STAT);
 #ifdef PHY_LOOPBACK
-         while(CMD_BUSY(card));
-         writel(0x00000022, card->membase + DR0);
-         writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD);
+		while (CMD_BUSY(card)) ;
+		writel(0x00000022, card->membase + DR0);
+		writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD);
 #endif /* PHY_LOOPBACK */
-	 break;
-      case 0x00000030:
-      case 0x00000031:
-         printk("nicstar%d: PHY seems to be 155 Mbps.\n", i);
-         card->max_pcr = ATM_OC3_PCR;
+		break;
+	case 0x00000030:
+	case 0x00000031:
+		printk("nicstar%d: PHY seems to be 155 Mbps.\n", i);
+		card->max_pcr = ATM_OC3_PCR;
 #ifdef PHY_LOOPBACK
-         while(CMD_BUSY(card));
-         writel(0x00000002, card->membase + DR0);
-         writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD);
+		while (CMD_BUSY(card)) ;
+		writel(0x00000002, card->membase + DR0);
+		writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD);
 #endif /* PHY_LOOPBACK */
-	 break;
-      default:
-         printk("nicstar%d: unknown PHY type (0x%08X).\n", i, data);
-         error = 8;
-         ns_init_card_error(card, error);
-         return error;
-   }
-   writel(0x00000000, card->membase + GP);
+		break;
+	default:
+		printk("nicstar%d: unknown PHY type (0x%08X).\n", i, data);
+		error = 8;
+		ns_init_card_error(card, error);
+		return error;
+	}
+	writel(0x00000000, card->membase + GP);
 
-   /* Determine SRAM size */
-   data = 0x76543210;
-   ns_write_sram(card, 0x1C003, &data, 1);
-   data = 0x89ABCDEF;
-   ns_write_sram(card, 0x14003, &data, 1);
-   if (ns_read_sram(card, 0x14003) == 0x89ABCDEF &&
-       ns_read_sram(card, 0x1C003) == 0x76543210)
-       card->sram_size = 128;
-   else
-      card->sram_size = 32;
-   PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size);
+	/* Determine SRAM size */
+	data = 0x76543210;
+	ns_write_sram(card, 0x1C003, &data, 1);
+	data = 0x89ABCDEF;
+	ns_write_sram(card, 0x14003, &data, 1);
+	if (ns_read_sram(card, 0x14003) == 0x89ABCDEF &&
+	    ns_read_sram(card, 0x1C003) == 0x76543210)
+		card->sram_size = 128;
+	else
+		card->sram_size = 32;
+	PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size);
 
-   card->rct_size = NS_MAX_RCTSIZE;
+	card->rct_size = NS_MAX_RCTSIZE;
 
 #if (NS_MAX_RCTSIZE == 4096)
-   if (card->sram_size == 128)
-      printk("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n", i);
+	if (card->sram_size == 128)
+		printk
+		    ("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n",
+		     i);
 #elif (NS_MAX_RCTSIZE == 16384)
-   if (card->sram_size == 32)
-   {
-      printk("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n", i);
-      card->rct_size = 4096;
-   }
+	if (card->sram_size == 32) {
+		printk
+		    ("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n",
+		     i);
+		card->rct_size = 4096;
+	}
 #else
 #error NS_MAX_RCTSIZE must be either 4096 or 16384 in nicstar.c
 #endif
 
-   card->vpibits = NS_VPIBITS;
-   if (card->rct_size == 4096)
-      card->vcibits = 12 - NS_VPIBITS;
-   else /* card->rct_size == 16384 */
-      card->vcibits = 14 - NS_VPIBITS;
+	card->vpibits = NS_VPIBITS;
+	if (card->rct_size == 4096)
+		card->vcibits = 12 - NS_VPIBITS;
+	else			/* card->rct_size == 16384 */
+		card->vcibits = 14 - NS_VPIBITS;
 
-   /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */
-   if (mac[i] == NULL)
-      nicstar_init_eprom(card->membase);
+	/* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */
+	if (mac[i] == NULL)
+		nicstar_init_eprom(card->membase);
 
-   /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */
-   writel(0x00000000, card->membase + VPM);
-      
-   /* Initialize TSQ */
-   card->tsq.org = kmalloc(NS_TSQSIZE + NS_TSQ_ALIGNMENT, GFP_KERNEL);
-   if (card->tsq.org == NULL)
-   {
-      printk("nicstar%d: can't allocate TSQ.\n", i);
-      error = 10;
-      ns_init_card_error(card, error);
-      return error;
-   }
-   card->tsq.base = (ns_tsi *) ALIGN_ADDRESS(card->tsq.org, NS_TSQ_ALIGNMENT);
-   card->tsq.next = card->tsq.base;
-   card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1);
-   for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++)
-      ns_tsi_init(card->tsq.base + j);
-   writel(0x00000000, card->membase + TSQH);
-   writel((u32) virt_to_bus(card->tsq.base), card->membase + TSQB);
-   PRINTK("nicstar%d: TSQ base at 0x%x  0x%x  0x%x.\n", i, (u32) card->tsq.base,
-          (u32) virt_to_bus(card->tsq.base), readl(card->membase + TSQB));
-      
-   /* Initialize RSQ */
-   card->rsq.org = kmalloc(NS_RSQSIZE + NS_RSQ_ALIGNMENT, GFP_KERNEL);
-   if (card->rsq.org == NULL)
-   {
-      printk("nicstar%d: can't allocate RSQ.\n", i);
-      error = 11;
-      ns_init_card_error(card, error);
-      return error;
-   }
-   card->rsq.base = (ns_rsqe *) ALIGN_ADDRESS(card->rsq.org, NS_RSQ_ALIGNMENT);
-   card->rsq.next = card->rsq.base;
-   card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1);
-   for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++)
-      ns_rsqe_init(card->rsq.base + j);
-   writel(0x00000000, card->membase + RSQH);
-   writel((u32) virt_to_bus(card->rsq.base), card->membase + RSQB);
-   PRINTK("nicstar%d: RSQ base at 0x%x.\n", i, (u32) card->rsq.base);
-      
-   /* Initialize SCQ0, the only VBR SCQ used */
-   card->scq1 = NULL;
-   card->scq2 = NULL;
-   card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0);
-   if (card->scq0 == NULL)
-   {
-      printk("nicstar%d: can't get SCQ0.\n", i);
-      error = 12;
-      ns_init_card_error(card, error);
-      return error;
-   }
-   u32d[0] = (u32) virt_to_bus(card->scq0->base);
-   u32d[1] = (u32) 0x00000000;
-   u32d[2] = (u32) 0xffffffff;
-   u32d[3] = (u32) 0x00000000;
-   ns_write_sram(card, NS_VRSCD0, u32d, 4);
-   ns_write_sram(card, NS_VRSCD1, u32d, 4);	/* These last two won't be used */
-   ns_write_sram(card, NS_VRSCD2, u32d, 4);	/* but are initialized, just in case... */
-   card->scq0->scd = NS_VRSCD0;
-   PRINTK("nicstar%d: VBR-SCQ0 base at 0x%x.\n", i, (u32) card->scq0->base);
+	/* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */
+	writel(0x00000000, card->membase + VPM);
 
-   /* Initialize TSTs */
-   card->tst_addr = NS_TST0;
-   card->tst_free_entries = NS_TST_NUM_ENTRIES;
-   data = NS_TST_OPCODE_VARIABLE;
-   for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
-      ns_write_sram(card, NS_TST0 + j, &data, 1);
-   data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0);
-   ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1);
-   for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
-      ns_write_sram(card, NS_TST1 + j, &data, 1);
-   data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1);
-   ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1);
-   for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
-      card->tste2vc[j] = NULL;
-   writel(NS_TST0 << 2, card->membase + TSTB);
+	/* Initialize TSQ */
+	card->tsq.org = pci_alloc_consistent(card->pcidev,
+					     NS_TSQSIZE + NS_TSQ_ALIGNMENT,
+					     &card->tsq.dma);
+	if (card->tsq.org == NULL) {
+		printk("nicstar%d: can't allocate TSQ.\n", i);
+		error = 10;
+		ns_init_card_error(card, error);
+		return error;
+	}
+	card->tsq.base = PTR_ALIGN(card->tsq.org, NS_TSQ_ALIGNMENT);
+	card->tsq.next = card->tsq.base;
+	card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1);
+	for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++)
+		ns_tsi_init(card->tsq.base + j);
+	writel(0x00000000, card->membase + TSQH);
+	writel(ALIGN(card->tsq.dma, NS_TSQ_ALIGNMENT), card->membase + TSQB);
+	PRINTK("nicstar%d: TSQ base at 0x%p.\n", i, card->tsq.base);
 
+	/* Initialize RSQ */
+	card->rsq.org = pci_alloc_consistent(card->pcidev,
+					     NS_RSQSIZE + NS_RSQ_ALIGNMENT,
+					     &card->rsq.dma);
+	if (card->rsq.org == NULL) {
+		printk("nicstar%d: can't allocate RSQ.\n", i);
+		error = 11;
+		ns_init_card_error(card, error);
+		return error;
+	}
+	card->rsq.base = PTR_ALIGN(card->rsq.org, NS_RSQ_ALIGNMENT);
+	card->rsq.next = card->rsq.base;
+	card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1);
+	for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++)
+		ns_rsqe_init(card->rsq.base + j);
+	writel(0x00000000, card->membase + RSQH);
+	writel(ALIGN(card->rsq.dma, NS_RSQ_ALIGNMENT), card->membase + RSQB);
+	PRINTK("nicstar%d: RSQ base at 0x%p.\n", i, card->rsq.base);
 
-   /* Initialize RCT. AAL type is set on opening the VC. */
+	/* Initialize SCQ0, the only VBR SCQ used */
+	card->scq1 = NULL;
+	card->scq2 = NULL;
+	card->scq0 = get_scq(card, VBR_SCQSIZE, NS_VRSCD0);
+	if (card->scq0 == NULL) {
+		printk("nicstar%d: can't get SCQ0.\n", i);
+		error = 12;
+		ns_init_card_error(card, error);
+		return error;
+	}
+	u32d[0] = scq_virt_to_bus(card->scq0, card->scq0->base);
+	u32d[1] = (u32) 0x00000000;
+	u32d[2] = (u32) 0xffffffff;
+	u32d[3] = (u32) 0x00000000;
+	ns_write_sram(card, NS_VRSCD0, u32d, 4);
+	ns_write_sram(card, NS_VRSCD1, u32d, 4);	/* These last two won't be used */
+	ns_write_sram(card, NS_VRSCD2, u32d, 4);	/* but are initialized, just in case... */
+	card->scq0->scd = NS_VRSCD0;
+	PRINTK("nicstar%d: VBR-SCQ0 base at 0x%p.\n", i, card->scq0->base);
+
+	/* Initialize TSTs */
+	card->tst_addr = NS_TST0;
+	card->tst_free_entries = NS_TST_NUM_ENTRIES;
+	data = NS_TST_OPCODE_VARIABLE;
+	for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
+		ns_write_sram(card, NS_TST0 + j, &data, 1);
+	data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0);
+	ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1);
+	for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
+		ns_write_sram(card, NS_TST1 + j, &data, 1);
+	data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1);
+	ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1);
+	for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
+		card->tste2vc[j] = NULL;
+	writel(NS_TST0 << 2, card->membase + TSTB);
+
+	/* Initialize RCT. AAL type is set on opening the VC. */
 #ifdef RCQ_SUPPORT
-   u32d[0] = NS_RCTE_RAWCELLINTEN;
+	u32d[0] = NS_RCTE_RAWCELLINTEN;
 #else
-   u32d[0] = 0x00000000;
+	u32d[0] = 0x00000000;
 #endif /* RCQ_SUPPORT */
-   u32d[1] = 0x00000000;
-   u32d[2] = 0x00000000;
-   u32d[3] = 0xFFFFFFFF;
-   for (j = 0; j < card->rct_size; j++)
-      ns_write_sram(card, j * 4, u32d, 4);      
-      
-   memset(card->vcmap, 0, NS_MAX_RCTSIZE * sizeof(vc_map));
-      
-   for (j = 0; j < NS_FRSCD_NUM; j++)
-      card->scd2vc[j] = NULL;
+	u32d[1] = 0x00000000;
+	u32d[2] = 0x00000000;
+	u32d[3] = 0xFFFFFFFF;
+	for (j = 0; j < card->rct_size; j++)
+		ns_write_sram(card, j * 4, u32d, 4);
 
-   /* Initialize buffer levels */
-   card->sbnr.min = MIN_SB;
-   card->sbnr.init = NUM_SB;
-   card->sbnr.max = MAX_SB;
-   card->lbnr.min = MIN_LB;
-   card->lbnr.init = NUM_LB;
-   card->lbnr.max = MAX_LB;
-   card->iovnr.min = MIN_IOVB;
-   card->iovnr.init = NUM_IOVB;
-   card->iovnr.max = MAX_IOVB;
-   card->hbnr.min = MIN_HB;
-   card->hbnr.init = NUM_HB;
-   card->hbnr.max = MAX_HB;
-   
-   card->sm_handle = 0x00000000;
-   card->sm_addr = 0x00000000;
-   card->lg_handle = 0x00000000;
-   card->lg_addr = 0x00000000;
-   
-   card->efbie = 1;	/* To prevent push_rxbufs from enabling the interrupt */
+	memset(card->vcmap, 0, NS_MAX_RCTSIZE * sizeof(vc_map));
 
-   /* Pre-allocate some huge buffers */
-   skb_queue_head_init(&card->hbpool.queue);
-   card->hbpool.count = 0;
-   for (j = 0; j < NUM_HB; j++)
-   {
-      struct sk_buff *hb;
-      hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
-      if (hb == NULL)
-      {
-         printk("nicstar%d: can't allocate %dth of %d huge buffers.\n",
-                i, j, NUM_HB);
-         error = 13;
-         ns_init_card_error(card, error);
-	 return error;
-      }
-      NS_SKB_CB(hb)->buf_type = BUF_NONE;
-      skb_queue_tail(&card->hbpool.queue, hb);
-      card->hbpool.count++;
-   }
+	for (j = 0; j < NS_FRSCD_NUM; j++)
+		card->scd2vc[j] = NULL;
 
+	/* Initialize buffer levels */
+	card->sbnr.min = MIN_SB;
+	card->sbnr.init = NUM_SB;
+	card->sbnr.max = MAX_SB;
+	card->lbnr.min = MIN_LB;
+	card->lbnr.init = NUM_LB;
+	card->lbnr.max = MAX_LB;
+	card->iovnr.min = MIN_IOVB;
+	card->iovnr.init = NUM_IOVB;
+	card->iovnr.max = MAX_IOVB;
+	card->hbnr.min = MIN_HB;
+	card->hbnr.init = NUM_HB;
+	card->hbnr.max = MAX_HB;
 
-   /* Allocate large buffers */
-   skb_queue_head_init(&card->lbpool.queue);
-   card->lbpool.count = 0;			/* Not used */
-   for (j = 0; j < NUM_LB; j++)
-   {
-      struct sk_buff *lb;
-      lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
-      if (lb == NULL)
-      {
-         printk("nicstar%d: can't allocate %dth of %d large buffers.\n",
-                i, j, NUM_LB);
-         error = 14;
-         ns_init_card_error(card, error);
-	 return error;
-      }
-      NS_SKB_CB(lb)->buf_type = BUF_LG;
-      skb_queue_tail(&card->lbpool.queue, lb);
-      skb_reserve(lb, NS_SMBUFSIZE);
-      push_rxbufs(card, lb);
-      /* Due to the implementation of push_rxbufs() this is 1, not 0 */
-      if (j == 1)
-      {
-         card->rcbuf = lb;
-         card->rawch = (u32) virt_to_bus(lb->data);
-      }
-   }
-   /* Test for strange behaviour which leads to crashes */
-   if ((bcount = ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min)
-   {
-      printk("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n",
-             i, j, bcount);
-      error = 14;
-      ns_init_card_error(card, error);
-      return error;
-   }
-      
+	card->sm_handle = 0x00000000;
+	card->sm_addr = 0x00000000;
+	card->lg_handle = 0x00000000;
+	card->lg_addr = 0x00000000;
 
-   /* Allocate small buffers */
-   skb_queue_head_init(&card->sbpool.queue);
-   card->sbpool.count = 0;			/* Not used */
-   for (j = 0; j < NUM_SB; j++)
-   {
-      struct sk_buff *sb;
-      sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
-      if (sb == NULL)
-      {
-         printk("nicstar%d: can't allocate %dth of %d small buffers.\n",
-                i, j, NUM_SB);
-         error = 15;
-         ns_init_card_error(card, error);
-	 return error;
-      }
-      NS_SKB_CB(sb)->buf_type = BUF_SM;
-      skb_queue_tail(&card->sbpool.queue, sb);
-      skb_reserve(sb, NS_AAL0_HEADER);
-      push_rxbufs(card, sb);
-   }
-   /* Test for strange behaviour which leads to crashes */
-   if ((bcount = ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min)
-   {
-      printk("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n",
-             i, j, bcount);
-      error = 15;
-      ns_init_card_error(card, error);
-      return error;
-   }
-      
+	card->efbie = 1;	/* To prevent push_rxbufs from enabling the interrupt */
 
-   /* Allocate iovec buffers */
-   skb_queue_head_init(&card->iovpool.queue);
-   card->iovpool.count = 0;
-   for (j = 0; j < NUM_IOVB; j++)
-   {
-      struct sk_buff *iovb;
-      iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
-      if (iovb == NULL)
-      {
-         printk("nicstar%d: can't allocate %dth of %d iovec buffers.\n",
-                i, j, NUM_IOVB);
-         error = 16;
-         ns_init_card_error(card, error);
-	 return error;
-      }
-      NS_SKB_CB(iovb)->buf_type = BUF_NONE;
-      skb_queue_tail(&card->iovpool.queue, iovb);
-      card->iovpool.count++;
-   }
+	idr_init(&card->idr);
 
-   /* Configure NICStAR */
-   if (card->rct_size == 4096)
-      ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES;
-   else /* (card->rct_size == 16384) */
-      ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES;
+	/* Pre-allocate some huge buffers */
+	skb_queue_head_init(&card->hbpool.queue);
+	card->hbpool.count = 0;
+	for (j = 0; j < NUM_HB; j++) {
+		struct sk_buff *hb;
+		hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
+		if (hb == NULL) {
+			printk
+			    ("nicstar%d: can't allocate %dth of %d huge buffers.\n",
+			     i, j, NUM_HB);
+			error = 13;
+			ns_init_card_error(card, error);
+			return error;
+		}
+		NS_PRV_BUFTYPE(hb) = BUF_NONE;
+		skb_queue_tail(&card->hbpool.queue, hb);
+		card->hbpool.count++;
+	}
 
-   card->efbie = 1;
+	/* Allocate large buffers */
+	skb_queue_head_init(&card->lbpool.queue);
+	card->lbpool.count = 0;	/* Not used */
+	for (j = 0; j < NUM_LB; j++) {
+		struct sk_buff *lb;
+		lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
+		if (lb == NULL) {
+			printk
+			    ("nicstar%d: can't allocate %dth of %d large buffers.\n",
+			     i, j, NUM_LB);
+			error = 14;
+			ns_init_card_error(card, error);
+			return error;
+		}
+		NS_PRV_BUFTYPE(lb) = BUF_LG;
+		skb_queue_tail(&card->lbpool.queue, lb);
+		skb_reserve(lb, NS_SMBUFSIZE);
+		push_rxbufs(card, lb);
+		/* Due to the implementation of push_rxbufs() this is 1, not 0 */
+		if (j == 1) {
+			card->rcbuf = lb;
+			card->rawcell = (struct ns_rcqe *) lb->data;
+			card->rawch = NS_PRV_DMA(lb);
+		}
+	}
+	/* Test for strange behaviour which leads to crashes */
+	if ((bcount =
+	     ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min) {
+		printk
+		    ("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n",
+		     i, j, bcount);
+		error = 14;
+		ns_init_card_error(card, error);
+		return error;
+	}
 
-   card->intcnt = 0;
-   if (request_irq(pcidev->irq, &ns_irq_handler, IRQF_DISABLED | IRQF_SHARED, "nicstar", card) != 0)
-   {
-      printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
-      error = 9;
-      ns_init_card_error(card, error);
-      return error;
-   }
+	/* Allocate small buffers */
+	skb_queue_head_init(&card->sbpool.queue);
+	card->sbpool.count = 0;	/* Not used */
+	for (j = 0; j < NUM_SB; j++) {
+		struct sk_buff *sb;
+		sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
+		if (sb == NULL) {
+			printk
+			    ("nicstar%d: can't allocate %dth of %d small buffers.\n",
+			     i, j, NUM_SB);
+			error = 15;
+			ns_init_card_error(card, error);
+			return error;
+		}
+		NS_PRV_BUFTYPE(sb) = BUF_SM;
+		skb_queue_tail(&card->sbpool.queue, sb);
+		skb_reserve(sb, NS_AAL0_HEADER);
+		push_rxbufs(card, sb);
+	}
+	/* Test for strange behaviour which leads to crashes */
+	if ((bcount =
+	     ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min) {
+		printk
+		    ("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n",
+		     i, j, bcount);
+		error = 15;
+		ns_init_card_error(card, error);
+		return error;
+	}
 
-   /* Register device */
-   card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
-   if (card->atmdev == NULL)
-   {
-      printk("nicstar%d: can't register device.\n", i);
-      error = 17;
-      ns_init_card_error(card, error);
-      return error;
-   }
-      
-   if (ns_parse_mac(mac[i], card->atmdev->esi)) {
-      nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET,
-                         card->atmdev->esi, 6);
-      if (memcmp(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00", 6) == 0) {
-         nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT,
-                         card->atmdev->esi, 6);
-      }
-   }
+	/* Allocate iovec buffers */
+	skb_queue_head_init(&card->iovpool.queue);
+	card->iovpool.count = 0;
+	for (j = 0; j < NUM_IOVB; j++) {
+		struct sk_buff *iovb;
+		iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
+		if (iovb == NULL) {
+			printk
+			    ("nicstar%d: can't allocate %dth of %d iovec buffers.\n",
+			     i, j, NUM_IOVB);
+			error = 16;
+			ns_init_card_error(card, error);
+			return error;
+		}
+		NS_PRV_BUFTYPE(iovb) = BUF_NONE;
+		skb_queue_tail(&card->iovpool.queue, iovb);
+		card->iovpool.count++;
+	}
 
-   printk("nicstar%d: MAC address %pM\n", i, card->atmdev->esi);
+	/* Configure NICStAR */
+	if (card->rct_size == 4096)
+		ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES;
+	else			/* (card->rct_size == 16384) */
+		ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES;
 
-   card->atmdev->dev_data = card;
-   card->atmdev->ci_range.vpi_bits = card->vpibits;
-   card->atmdev->ci_range.vci_bits = card->vcibits;
-   card->atmdev->link_rate = card->max_pcr;
-   card->atmdev->phy = NULL;
+	card->efbie = 1;
+
+	card->intcnt = 0;
+	if (request_irq
+	    (pcidev->irq, &ns_irq_handler, IRQF_SHARED, "nicstar", card) != 0) {
+		printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
+		error = 9;
+		ns_init_card_error(card, error);
+		return error;
+	}
+
+	/* Register device */
+	card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
+	if (card->atmdev == NULL) {
+		printk("nicstar%d: can't register device.\n", i);
+		error = 17;
+		ns_init_card_error(card, error);
+		return error;
+	}
+
+	if (ns_parse_mac(mac[i], card->atmdev->esi)) {
+		nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET,
+				   card->atmdev->esi, 6);
+		if (memcmp(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00", 6) ==
+		    0) {
+			nicstar_read_eprom(card->membase,
+					   NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT,
+					   card->atmdev->esi, 6);
+		}
+	}
+
+	printk("nicstar%d: MAC address %pM\n", i, card->atmdev->esi);
+
+	card->atmdev->dev_data = card;
+	card->atmdev->ci_range.vpi_bits = card->vpibits;
+	card->atmdev->ci_range.vci_bits = card->vcibits;
+	card->atmdev->link_rate = card->max_pcr;
+	card->atmdev->phy = NULL;
 
 #ifdef CONFIG_ATM_NICSTAR_USE_SUNI
-   if (card->max_pcr == ATM_OC3_PCR)
-      suni_init(card->atmdev);
+	if (card->max_pcr == ATM_OC3_PCR)
+		suni_init(card->atmdev);
 #endif /* CONFIG_ATM_NICSTAR_USE_SUNI */
 
 #ifdef CONFIG_ATM_NICSTAR_USE_IDT77105
-   if (card->max_pcr == ATM_25_PCR)
-      idt77105_init(card->atmdev);
+	if (card->max_pcr == ATM_25_PCR)
+		idt77105_init(card->atmdev);
 #endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
 
-   if (card->atmdev->phy && card->atmdev->phy->start)
-      card->atmdev->phy->start(card->atmdev);
+	if (card->atmdev->phy && card->atmdev->phy->start)
+		card->atmdev->phy->start(card->atmdev);
 
-   writel(NS_CFG_RXPATH |
-          NS_CFG_SMBUFSIZE |
-          NS_CFG_LGBUFSIZE |
-          NS_CFG_EFBIE |
-          NS_CFG_RSQSIZE |
-          NS_CFG_VPIBITS |
-          ns_cfg_rctsize |
-          NS_CFG_RXINT_NODELAY |
-          NS_CFG_RAWIE |		/* Only enabled if RCQ_SUPPORT */
-          NS_CFG_RSQAFIE |
-          NS_CFG_TXEN |
-          NS_CFG_TXIE |
-          NS_CFG_TSQFIE_OPT |		/* Only enabled if ENABLE_TSQFIE */ 
-          NS_CFG_PHYIE,
-          card->membase + CFG);
+	writel(NS_CFG_RXPATH | NS_CFG_SMBUFSIZE | NS_CFG_LGBUFSIZE | NS_CFG_EFBIE | NS_CFG_RSQSIZE | NS_CFG_VPIBITS | ns_cfg_rctsize | NS_CFG_RXINT_NODELAY | NS_CFG_RAWIE |	/* Only enabled if RCQ_SUPPORT */
+	       NS_CFG_RSQAFIE | NS_CFG_TXEN | NS_CFG_TXIE | NS_CFG_TSQFIE_OPT |	/* Only enabled if ENABLE_TSQFIE */
+	       NS_CFG_PHYIE, card->membase + CFG);
 
-   num_cards++;
+	num_cards++;
 
-   return error;
+	return error;
 }
 
-
-
-static void __devinit ns_init_card_error(ns_dev *card, int error)
+static void __devinit ns_init_card_error(ns_dev * card, int error)
 {
-   if (error >= 17)
-   {
-      writel(0x00000000, card->membase + CFG);
-   }
-   if (error >= 16)
-   {
-      struct sk_buff *iovb;
-      while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
-         dev_kfree_skb_any(iovb);
-   }
-   if (error >= 15)
-   {
-      struct sk_buff *sb;
-      while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
-         dev_kfree_skb_any(sb);
-      free_scq(card->scq0, NULL);
-   }
-   if (error >= 14)
-   {
-      struct sk_buff *lb;
-      while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
-         dev_kfree_skb_any(lb);
-   }
-   if (error >= 13)
-   {
-      struct sk_buff *hb;
-      while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
-         dev_kfree_skb_any(hb);
-   }
-   if (error >= 12)
-   {
-      kfree(card->rsq.org);
-   }
-   if (error >= 11)
-   {
-      kfree(card->tsq.org);
-   }
-   if (error >= 10)
-   {
-      free_irq(card->pcidev->irq, card);
-   }
-   if (error >= 4)
-   {
-      iounmap(card->membase);
-   }
-   if (error >= 3)
-   {
-      pci_disable_device(card->pcidev);
-      kfree(card);
-   }
+	if (error >= 17) {
+		writel(0x00000000, card->membase + CFG);
+	}
+	if (error >= 16) {
+		struct sk_buff *iovb;
+		while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
+			dev_kfree_skb_any(iovb);
+	}
+	if (error >= 15) {
+		struct sk_buff *sb;
+		while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
+			dev_kfree_skb_any(sb);
+		free_scq(card, card->scq0, NULL);
+	}
+	if (error >= 14) {
+		struct sk_buff *lb;
+		while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
+			dev_kfree_skb_any(lb);
+	}
+	if (error >= 13) {
+		struct sk_buff *hb;
+		while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
+			dev_kfree_skb_any(hb);
+	}
+	if (error >= 12) {
+		kfree(card->rsq.org);
+	}
+	if (error >= 11) {
+		kfree(card->tsq.org);
+	}
+	if (error >= 10) {
+		free_irq(card->pcidev->irq, card);
+	}
+	if (error >= 4) {
+		iounmap(card->membase);
+	}
+	if (error >= 3) {
+		pci_disable_device(card->pcidev);
+		kfree(card);
+	}
 }
 
-
-
-static scq_info *get_scq(int size, u32 scd)
+static scq_info *get_scq(ns_dev *card, int size, u32 scd)
 {
-   scq_info *scq;
-   int i;
+	scq_info *scq;
+	int i;
 
-   if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
-      return NULL;
+	if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
+		return NULL;
 
-   scq = kmalloc(sizeof(scq_info), GFP_KERNEL);
-   if (scq == NULL)
-      return NULL;
-   scq->org = kmalloc(2 * size, GFP_KERNEL);
-   if (scq->org == NULL)
-   {
-      kfree(scq);
-      return NULL;
-   }
-   scq->skb = kmalloc(sizeof(struct sk_buff *) *
-                                          (size / NS_SCQE_SIZE), GFP_KERNEL);
-   if (scq->skb == NULL)
-   {
-      kfree(scq->org);
-      kfree(scq);
-      return NULL;
-   }
-   scq->num_entries = size / NS_SCQE_SIZE;
-   scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size);
-   scq->next = scq->base;
-   scq->last = scq->base + (scq->num_entries - 1);
-   scq->tail = scq->last;
-   scq->scd = scd;
-   scq->num_entries = size / NS_SCQE_SIZE;
-   scq->tbd_count = 0;
-   init_waitqueue_head(&scq->scqfull_waitq);
-   scq->full = 0;
-   spin_lock_init(&scq->lock);
+	scq = kmalloc(sizeof(scq_info), GFP_KERNEL);
+	if (!scq)
+		return NULL;
+        scq->org = pci_alloc_consistent(card->pcidev, 2 * size, &scq->dma);
+	if (!scq->org) {
+		kfree(scq);
+		return NULL;
+	}
+	scq->skb = kmalloc(sizeof(struct sk_buff *) *
+			   (size / NS_SCQE_SIZE), GFP_KERNEL);
+	if (!scq->skb) {
+		kfree(scq->org);
+		kfree(scq);
+		return NULL;
+	}
+	scq->num_entries = size / NS_SCQE_SIZE;
+	scq->base = PTR_ALIGN(scq->org, size);
+	scq->next = scq->base;
+	scq->last = scq->base + (scq->num_entries - 1);
+	scq->tail = scq->last;
+	scq->scd = scd;
+	scq->num_entries = size / NS_SCQE_SIZE;
+	scq->tbd_count = 0;
+	init_waitqueue_head(&scq->scqfull_waitq);
+	scq->full = 0;
+	spin_lock_init(&scq->lock);
 
-   for (i = 0; i < scq->num_entries; i++)
-      scq->skb[i] = NULL;
+	for (i = 0; i < scq->num_entries; i++)
+		scq->skb[i] = NULL;
 
-   return scq;
+	return scq;
 }
 
-
-
 /* For variable rate SCQ vcc must be NULL */
-static void free_scq(scq_info *scq, struct atm_vcc *vcc)
+static void free_scq(ns_dev *card, scq_info *scq, struct atm_vcc *vcc)
 {
-   int i;
+	int i;
 
-   if (scq->num_entries == VBR_SCQ_NUM_ENTRIES)
-      for (i = 0; i < scq->num_entries; i++)
-      {
-         if (scq->skb[i] != NULL)
-	 {
-            vcc = ATM_SKB(scq->skb[i])->vcc;
-            if (vcc->pop != NULL)
-	       vcc->pop(vcc, scq->skb[i]);
-	    else
-               dev_kfree_skb_any(scq->skb[i]);
-         }
-      }
-   else /* vcc must be != NULL */
-   {
-      if (vcc == NULL)
-      {
-         printk("nicstar: free_scq() called with vcc == NULL for fixed rate scq.");
-         for (i = 0; i < scq->num_entries; i++)
-            dev_kfree_skb_any(scq->skb[i]);
-      }
-      else
-         for (i = 0; i < scq->num_entries; i++)
-         {
-            if (scq->skb[i] != NULL)
-            {
-               if (vcc->pop != NULL)
-                  vcc->pop(vcc, scq->skb[i]);
-               else
-                  dev_kfree_skb_any(scq->skb[i]);
-            }
-         }
-   }
-   kfree(scq->skb);
-   kfree(scq->org);
-   kfree(scq);
+	if (scq->num_entries == VBR_SCQ_NUM_ENTRIES)
+		for (i = 0; i < scq->num_entries; i++) {
+			if (scq->skb[i] != NULL) {
+				vcc = ATM_SKB(scq->skb[i])->vcc;
+				if (vcc->pop != NULL)
+					vcc->pop(vcc, scq->skb[i]);
+				else
+					dev_kfree_skb_any(scq->skb[i]);
+			}
+	} else {		/* vcc must be != NULL */
+
+		if (vcc == NULL) {
+			printk
+			    ("nicstar: free_scq() called with vcc == NULL for fixed rate scq.");
+			for (i = 0; i < scq->num_entries; i++)
+				dev_kfree_skb_any(scq->skb[i]);
+		} else
+			for (i = 0; i < scq->num_entries; i++) {
+				if (scq->skb[i] != NULL) {
+					if (vcc->pop != NULL)
+						vcc->pop(vcc, scq->skb[i]);
+					else
+						dev_kfree_skb_any(scq->skb[i]);
+				}
+			}
+	}
+	kfree(scq->skb);
+	pci_free_consistent(card->pcidev,
+			    2 * (scq->num_entries == VBR_SCQ_NUM_ENTRIES ?
+				 VBR_SCQSIZE : CBR_SCQSIZE),
+			    scq->org, scq->dma);
+	kfree(scq);
 }
 
-
-
 /* The handles passed must be pointers to the sk_buff containing the small
    or large buffer(s) cast to u32. */
-static void push_rxbufs(ns_dev *card, struct sk_buff *skb)
+static void push_rxbufs(ns_dev * card, struct sk_buff *skb)
 {
-   struct ns_skb_cb *cb = NS_SKB_CB(skb);
-   u32 handle1, addr1;
-   u32 handle2, addr2;
-   u32 stat;
-   unsigned long flags;
-   
-   /* *BARF* */
-   handle2 = addr2 = 0;
-   handle1 = (u32)skb;
-   addr1 = (u32)virt_to_bus(skb->data);
+	struct sk_buff *handle1, *handle2;
+	u32 id1 = 0, id2 = 0;
+	u32 addr1, addr2;
+	u32 stat;
+	unsigned long flags;
+	int err;
+
+	/* *BARF* */
+	handle2 = NULL;
+	addr2 = 0;
+	handle1 = skb;
+	addr1 = pci_map_single(card->pcidev,
+			       skb->data,
+			       (NS_PRV_BUFTYPE(skb) == BUF_SM
+				? NS_SMSKBSIZE : NS_LGSKBSIZE),
+			       PCI_DMA_TODEVICE);
+	NS_PRV_DMA(skb) = addr1; /* save so we can unmap later */
 
 #ifdef GENERAL_DEBUG
-   if (!addr1)
-      printk("nicstar%d: push_rxbufs called with addr1 = 0.\n", card->index);
+	if (!addr1)
+		printk("nicstar%d: push_rxbufs called with addr1 = 0.\n",
+		       card->index);
 #endif /* GENERAL_DEBUG */
 
-   stat = readl(card->membase + STAT);
-   card->sbfqc = ns_stat_sfbqc_get(stat);
-   card->lbfqc = ns_stat_lfbqc_get(stat);
-   if (cb->buf_type == BUF_SM)
-   {
-      if (!addr2)
-      {
-         if (card->sm_addr)
-	 {
-	    addr2 = card->sm_addr;
-	    handle2 = card->sm_handle;
-	    card->sm_addr = 0x00000000;
-	    card->sm_handle = 0x00000000;
-	 }
-	 else /* (!sm_addr) */
-	 {
-	    card->sm_addr = addr1;
-	    card->sm_handle = handle1;
-	 }
-      }      
-   }
-   else /* buf_type == BUF_LG */
-   {
-      if (!addr2)
-      {
-         if (card->lg_addr)
-	 {
-	    addr2 = card->lg_addr;
-	    handle2 = card->lg_handle;
-	    card->lg_addr = 0x00000000;
-	    card->lg_handle = 0x00000000;
-	 }
-	 else /* (!lg_addr) */
-	 {
-	    card->lg_addr = addr1;
-	    card->lg_handle = handle1;
-	 }
-      }      
-   }
+	stat = readl(card->membase + STAT);
+	card->sbfqc = ns_stat_sfbqc_get(stat);
+	card->lbfqc = ns_stat_lfbqc_get(stat);
+	if (NS_PRV_BUFTYPE(skb) == BUF_SM) {
+		if (!addr2) {
+			if (card->sm_addr) {
+				addr2 = card->sm_addr;
+				handle2 = card->sm_handle;
+				card->sm_addr = 0x00000000;
+				card->sm_handle = 0x00000000;
+			} else {	/* (!sm_addr) */
 
-   if (addr2)
-   {
-      if (cb->buf_type == BUF_SM)
-      {
-         if (card->sbfqc >= card->sbnr.max)
-         {
-            skb_unlink((struct sk_buff *) handle1, &card->sbpool.queue);
-            dev_kfree_skb_any((struct sk_buff *) handle1);
-            skb_unlink((struct sk_buff *) handle2, &card->sbpool.queue);
-            dev_kfree_skb_any((struct sk_buff *) handle2);
-            return;
-         }
-	 else
-            card->sbfqc += 2;
-      }
-      else /* (buf_type == BUF_LG) */
-      {
-         if (card->lbfqc >= card->lbnr.max)
-         {
-            skb_unlink((struct sk_buff *) handle1, &card->lbpool.queue);
-            dev_kfree_skb_any((struct sk_buff *) handle1);
-            skb_unlink((struct sk_buff *) handle2, &card->lbpool.queue);
-            dev_kfree_skb_any((struct sk_buff *) handle2);
-            return;
-         }
-         else
-            card->lbfqc += 2;
-      }
+				card->sm_addr = addr1;
+				card->sm_handle = handle1;
+			}
+		}
+	} else {		/* buf_type == BUF_LG */
 
-      spin_lock_irqsave(&card->res_lock, flags);
+		if (!addr2) {
+			if (card->lg_addr) {
+				addr2 = card->lg_addr;
+				handle2 = card->lg_handle;
+				card->lg_addr = 0x00000000;
+				card->lg_handle = 0x00000000;
+			} else {	/* (!lg_addr) */
 
-      while (CMD_BUSY(card));
-      writel(addr2, card->membase + DR3);
-      writel(handle2, card->membase + DR2);
-      writel(addr1, card->membase + DR1);
-      writel(handle1, card->membase + DR0);
-      writel(NS_CMD_WRITE_FREEBUFQ | cb->buf_type, card->membase + CMD);
- 
-      spin_unlock_irqrestore(&card->res_lock, flags);
+				card->lg_addr = addr1;
+				card->lg_handle = handle1;
+			}
+		}
+	}
 
-      XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n", card->index,
-              (cb->buf_type == BUF_SM ? "small" : "large"), addr1, addr2);
-   }
+	if (addr2) {
+		if (NS_PRV_BUFTYPE(skb) == BUF_SM) {
+			if (card->sbfqc >= card->sbnr.max) {
+				skb_unlink(handle1, &card->sbpool.queue);
+				dev_kfree_skb_any(handle1);
+				skb_unlink(handle2, &card->sbpool.queue);
+				dev_kfree_skb_any(handle2);
+				return;
+			} else
+				card->sbfqc += 2;
+		} else {	/* (buf_type == BUF_LG) */
 
-   if (!card->efbie && card->sbfqc >= card->sbnr.min &&
-       card->lbfqc >= card->lbnr.min)
-   {
-      card->efbie = 1;
-      writel((readl(card->membase + CFG) | NS_CFG_EFBIE), card->membase + CFG);
-   }
+			if (card->lbfqc >= card->lbnr.max) {
+				skb_unlink(handle1, &card->lbpool.queue);
+				dev_kfree_skb_any(handle1);
+				skb_unlink(handle2, &card->lbpool.queue);
+				dev_kfree_skb_any(handle2);
+				return;
+			} else
+				card->lbfqc += 2;
+		}
 
-   return;
+		do {
+			if (!idr_pre_get(&card->idr, GFP_ATOMIC)) {
+				printk(KERN_ERR
+				       "nicstar%d: no free memory for idr\n",
+				       card->index);
+				goto out;
+			}
+
+			if (!id1)
+				err = idr_get_new_above(&card->idr, handle1, 0, &id1);
+
+			if (!id2 && err == 0)
+				err = idr_get_new_above(&card->idr, handle2, 0, &id2);
+
+		} while (err == -EAGAIN);
+
+		if (err)
+			goto out;
+
+		spin_lock_irqsave(&card->res_lock, flags);
+		while (CMD_BUSY(card)) ;
+		writel(addr2, card->membase + DR3);
+		writel(id2, card->membase + DR2);
+		writel(addr1, card->membase + DR1);
+		writel(id1, card->membase + DR0);
+		writel(NS_CMD_WRITE_FREEBUFQ | NS_PRV_BUFTYPE(skb),
+		       card->membase + CMD);
+		spin_unlock_irqrestore(&card->res_lock, flags);
+
+		XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n",
+			card->index,
+			(NS_PRV_BUFTYPE(skb) == BUF_SM ? "small" : "large"),
+			addr1, addr2);
+	}
+
+	if (!card->efbie && card->sbfqc >= card->sbnr.min &&
+	    card->lbfqc >= card->lbnr.min) {
+		card->efbie = 1;
+		writel((readl(card->membase + CFG) | NS_CFG_EFBIE),
+		       card->membase + CFG);
+	}
+
+out:
+	return;
 }
 
-
-
 static irqreturn_t ns_irq_handler(int irq, void *dev_id)
 {
-   u32 stat_r;
-   ns_dev *card;
-   struct atm_dev *dev;
-   unsigned long flags;
+	u32 stat_r;
+	ns_dev *card;
+	struct atm_dev *dev;
+	unsigned long flags;
 
-   card = (ns_dev *) dev_id;
-   dev = card->atmdev;
-   card->intcnt++;
+	card = (ns_dev *) dev_id;
+	dev = card->atmdev;
+	card->intcnt++;
 
-   PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index);
+	PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index);
 
-   spin_lock_irqsave(&card->int_lock, flags);
-   
-   stat_r = readl(card->membase + STAT);
+	spin_lock_irqsave(&card->int_lock, flags);
 
-   /* Transmit Status Indicator has been written to T. S. Queue */
-   if (stat_r & NS_STAT_TSIF)
-   {
-      TXPRINTK("nicstar%d: TSI interrupt\n", card->index);
-      process_tsq(card);
-      writel(NS_STAT_TSIF, card->membase + STAT);
-   }
-   
-   /* Incomplete CS-PDU has been transmitted */
-   if (stat_r & NS_STAT_TXICP)
-   {
-      writel(NS_STAT_TXICP, card->membase + STAT);
-      TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n",
-               card->index);
-   }
-   
-   /* Transmit Status Queue 7/8 full */
-   if (stat_r & NS_STAT_TSQF)
-   {
-      writel(NS_STAT_TSQF, card->membase + STAT);
-      PRINTK("nicstar%d: TSQ full.\n", card->index);
-      process_tsq(card);
-   }
-   
-   /* Timer overflow */
-   if (stat_r & NS_STAT_TMROF)
-   {
-      writel(NS_STAT_TMROF, card->membase + STAT);
-      PRINTK("nicstar%d: Timer overflow.\n", card->index);
-   }
-   
-   /* PHY device interrupt signal active */
-   if (stat_r & NS_STAT_PHYI)
-   {
-      writel(NS_STAT_PHYI, card->membase + STAT);
-      PRINTK("nicstar%d: PHY interrupt.\n", card->index);
-      if (dev->phy && dev->phy->interrupt) {
-         dev->phy->interrupt(dev);
-      }
-   }
+	stat_r = readl(card->membase + STAT);
 
-   /* Small Buffer Queue is full */
-   if (stat_r & NS_STAT_SFBQF)
-   {
-      writel(NS_STAT_SFBQF, card->membase + STAT);
-      printk("nicstar%d: Small free buffer queue is full.\n", card->index);
-   }
-   
-   /* Large Buffer Queue is full */
-   if (stat_r & NS_STAT_LFBQF)
-   {
-      writel(NS_STAT_LFBQF, card->membase + STAT);
-      printk("nicstar%d: Large free buffer queue is full.\n", card->index);
-   }
+	/* Transmit Status Indicator has been written to T. S. Queue */
+	if (stat_r & NS_STAT_TSIF) {
+		TXPRINTK("nicstar%d: TSI interrupt\n", card->index);
+		process_tsq(card);
+		writel(NS_STAT_TSIF, card->membase + STAT);
+	}
 
-   /* Receive Status Queue is full */
-   if (stat_r & NS_STAT_RSQF)
-   {
-      writel(NS_STAT_RSQF, card->membase + STAT);
-      printk("nicstar%d: RSQ full.\n", card->index);
-      process_rsq(card);
-   }
+	/* Incomplete CS-PDU has been transmitted */
+	if (stat_r & NS_STAT_TXICP) {
+		writel(NS_STAT_TXICP, card->membase + STAT);
+		TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n",
+			 card->index);
+	}
 
-   /* Complete CS-PDU received */
-   if (stat_r & NS_STAT_EOPDU)
-   {
-      RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index);
-      process_rsq(card);
-      writel(NS_STAT_EOPDU, card->membase + STAT);
-   }
+	/* Transmit Status Queue 7/8 full */
+	if (stat_r & NS_STAT_TSQF) {
+		writel(NS_STAT_TSQF, card->membase + STAT);
+		PRINTK("nicstar%d: TSQ full.\n", card->index);
+		process_tsq(card);
+	}
 
-   /* Raw cell received */
-   if (stat_r & NS_STAT_RAWCF)
-   {
-      writel(NS_STAT_RAWCF, card->membase + STAT);
+	/* Timer overflow */
+	if (stat_r & NS_STAT_TMROF) {
+		writel(NS_STAT_TMROF, card->membase + STAT);
+		PRINTK("nicstar%d: Timer overflow.\n", card->index);
+	}
+
+	/* PHY device interrupt signal active */
+	if (stat_r & NS_STAT_PHYI) {
+		writel(NS_STAT_PHYI, card->membase + STAT);
+		PRINTK("nicstar%d: PHY interrupt.\n", card->index);
+		if (dev->phy && dev->phy->interrupt) {
+			dev->phy->interrupt(dev);
+		}
+	}
+
+	/* Small Buffer Queue is full */
+	if (stat_r & NS_STAT_SFBQF) {
+		writel(NS_STAT_SFBQF, card->membase + STAT);
+		printk("nicstar%d: Small free buffer queue is full.\n",
+		       card->index);
+	}
+
+	/* Large Buffer Queue is full */
+	if (stat_r & NS_STAT_LFBQF) {
+		writel(NS_STAT_LFBQF, card->membase + STAT);
+		printk("nicstar%d: Large free buffer queue is full.\n",
+		       card->index);
+	}
+
+	/* Receive Status Queue is full */
+	if (stat_r & NS_STAT_RSQF) {
+		writel(NS_STAT_RSQF, card->membase + STAT);
+		printk("nicstar%d: RSQ full.\n", card->index);
+		process_rsq(card);
+	}
+
+	/* Complete CS-PDU received */
+	if (stat_r & NS_STAT_EOPDU) {
+		RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index);
+		process_rsq(card);
+		writel(NS_STAT_EOPDU, card->membase + STAT);
+	}
+
+	/* Raw cell received */
+	if (stat_r & NS_STAT_RAWCF) {
+		writel(NS_STAT_RAWCF, card->membase + STAT);
 #ifndef RCQ_SUPPORT
-      printk("nicstar%d: Raw cell received and no support yet...\n",
-             card->index);
+		printk("nicstar%d: Raw cell received and no support yet...\n",
+		       card->index);
 #endif /* RCQ_SUPPORT */
-      /* NOTE: the following procedure may keep a raw cell pending until the
-               next interrupt. As this preliminary support is only meant to
-               avoid buffer leakage, this is not an issue. */
-      while (readl(card->membase + RAWCT) != card->rawch)
-      {
-         ns_rcqe *rawcell;
+		/* NOTE: the following procedure may keep a raw cell pending until the
+		   next interrupt. As this preliminary support is only meant to
+		   avoid buffer leakage, this is not an issue. */
+		while (readl(card->membase + RAWCT) != card->rawch) {
 
-         rawcell = (ns_rcqe *) bus_to_virt(card->rawch);
-         if (ns_rcqe_islast(rawcell))
-         {
-            struct sk_buff *oldbuf;
+			if (ns_rcqe_islast(card->rawcell)) {
+				struct sk_buff *oldbuf;
 
-            oldbuf = card->rcbuf;
-            card->rcbuf = (struct sk_buff *) ns_rcqe_nextbufhandle(rawcell);
-            card->rawch = (u32) virt_to_bus(card->rcbuf->data);
-            recycle_rx_buf(card, oldbuf);
-         }
-         else
-            card->rawch += NS_RCQE_SIZE;
-      }
-   }
+				oldbuf = card->rcbuf;
+				card->rcbuf = idr_find(&card->idr,
+						       ns_rcqe_nextbufhandle(card->rawcell));
+				card->rawch = NS_PRV_DMA(card->rcbuf);
+				card->rawcell = (struct ns_rcqe *)
+						card->rcbuf->data;
+				recycle_rx_buf(card, oldbuf);
+			} else {
+				card->rawch += NS_RCQE_SIZE;
+				card->rawcell++;
+			}
+		}
+	}
 
-   /* Small buffer queue is empty */
-   if (stat_r & NS_STAT_SFBQE)
-   {
-      int i;
-      struct sk_buff *sb;
+	/* Small buffer queue is empty */
+	if (stat_r & NS_STAT_SFBQE) {
+		int i;
+		struct sk_buff *sb;
 
-      writel(NS_STAT_SFBQE, card->membase + STAT);
-      printk("nicstar%d: Small free buffer queue empty.\n",
-             card->index);
-      for (i = 0; i < card->sbnr.min; i++)
-      {
-         sb = dev_alloc_skb(NS_SMSKBSIZE);
-         if (sb == NULL)
-         {
-            writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG);
-            card->efbie = 0;
-            break;
-         }
-         NS_SKB_CB(sb)->buf_type = BUF_SM;
-         skb_queue_tail(&card->sbpool.queue, sb);
-         skb_reserve(sb, NS_AAL0_HEADER);
-         push_rxbufs(card, sb);
-      }
-      card->sbfqc = i;
-      process_rsq(card);
-   }
+		writel(NS_STAT_SFBQE, card->membase + STAT);
+		printk("nicstar%d: Small free buffer queue empty.\n",
+		       card->index);
+		for (i = 0; i < card->sbnr.min; i++) {
+			sb = dev_alloc_skb(NS_SMSKBSIZE);
+			if (sb == NULL) {
+				writel(readl(card->membase + CFG) &
+				       ~NS_CFG_EFBIE, card->membase + CFG);
+				card->efbie = 0;
+				break;
+			}
+			NS_PRV_BUFTYPE(sb) = BUF_SM;
+			skb_queue_tail(&card->sbpool.queue, sb);
+			skb_reserve(sb, NS_AAL0_HEADER);
+			push_rxbufs(card, sb);
+		}
+		card->sbfqc = i;
+		process_rsq(card);
+	}
 
-   /* Large buffer queue empty */
-   if (stat_r & NS_STAT_LFBQE)
-   {
-      int i;
-      struct sk_buff *lb;
+	/* Large buffer queue empty */
+	if (stat_r & NS_STAT_LFBQE) {
+		int i;
+		struct sk_buff *lb;
 
-      writel(NS_STAT_LFBQE, card->membase + STAT);
-      printk("nicstar%d: Large free buffer queue empty.\n",
-             card->index);
-      for (i = 0; i < card->lbnr.min; i++)
-      {
-         lb = dev_alloc_skb(NS_LGSKBSIZE);
-         if (lb == NULL)
-         {
-            writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG);
-            card->efbie = 0;
-            break;
-         }
-         NS_SKB_CB(lb)->buf_type = BUF_LG;
-         skb_queue_tail(&card->lbpool.queue, lb);
-         skb_reserve(lb, NS_SMBUFSIZE);
-         push_rxbufs(card, lb);
-      }
-      card->lbfqc = i;
-      process_rsq(card);
-   }
+		writel(NS_STAT_LFBQE, card->membase + STAT);
+		printk("nicstar%d: Large free buffer queue empty.\n",
+		       card->index);
+		for (i = 0; i < card->lbnr.min; i++) {
+			lb = dev_alloc_skb(NS_LGSKBSIZE);
+			if (lb == NULL) {
+				writel(readl(card->membase + CFG) &
+				       ~NS_CFG_EFBIE, card->membase + CFG);
+				card->efbie = 0;
+				break;
+			}
+			NS_PRV_BUFTYPE(lb) = BUF_LG;
+			skb_queue_tail(&card->lbpool.queue, lb);
+			skb_reserve(lb, NS_SMBUFSIZE);
+			push_rxbufs(card, lb);
+		}
+		card->lbfqc = i;
+		process_rsq(card);
+	}
 
-   /* Receive Status Queue is 7/8 full */
-   if (stat_r & NS_STAT_RSQAF)
-   {
-      writel(NS_STAT_RSQAF, card->membase + STAT);
-      RXPRINTK("nicstar%d: RSQ almost full.\n", card->index);
-      process_rsq(card);
-   }
-   
-   spin_unlock_irqrestore(&card->int_lock, flags);
-   PRINTK("nicstar%d: end of interrupt service\n", card->index);
-   return IRQ_HANDLED;
+	/* Receive Status Queue is 7/8 full */
+	if (stat_r & NS_STAT_RSQAF) {
+		writel(NS_STAT_RSQAF, card->membase + STAT);
+		RXPRINTK("nicstar%d: RSQ almost full.\n", card->index);
+		process_rsq(card);
+	}
+
+	spin_unlock_irqrestore(&card->int_lock, flags);
+	PRINTK("nicstar%d: end of interrupt service\n", card->index);
+	return IRQ_HANDLED;
 }
 
-
-
 static int ns_open(struct atm_vcc *vcc)
 {
-   ns_dev *card;
-   vc_map *vc;
-   unsigned long tmpl, modl;
-   int tcr, tcra;	/* target cell rate, and absolute value */
-   int n = 0;		/* Number of entries in the TST. Initialized to remove
-                           the compiler warning. */
-   u32 u32d[4];
-   int frscdi = 0;	/* Index of the SCD. Initialized to remove the compiler
-                           warning. How I wish compilers were clever enough to
-			   tell which variables can truly be used
-			   uninitialized... */
-   int inuse;		/* tx or rx vc already in use by another vcc */
-   short vpi = vcc->vpi;
-   int vci = vcc->vci;
+	ns_dev *card;
+	vc_map *vc;
+	unsigned long tmpl, modl;
+	int tcr, tcra;		/* target cell rate, and absolute value */
+	int n = 0;		/* Number of entries in the TST. Initialized to remove
+				   the compiler warning. */
+	u32 u32d[4];
+	int frscdi = 0;		/* Index of the SCD. Initialized to remove the compiler
+				   warning. How I wish compilers were clever enough to
+				   tell which variables can truly be used
+				   uninitialized... */
+	int inuse;		/* tx or rx vc already in use by another vcc */
+	short vpi = vcc->vpi;
+	int vci = vcc->vci;
 
-   card = (ns_dev *) vcc->dev->dev_data;
-   PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int) vpi, vci);
-   if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0)
-   {
-      PRINTK("nicstar%d: unsupported AAL.\n", card->index);
-      return -EINVAL;
-   }
+	card = (ns_dev *) vcc->dev->dev_data;
+	PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int)vpi,
+	       vci);
+	if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) {
+		PRINTK("nicstar%d: unsupported AAL.\n", card->index);
+		return -EINVAL;
+	}
 
-   vc = &(card->vcmap[vpi << card->vcibits | vci]);
-   vcc->dev_data = vc;
+	vc = &(card->vcmap[vpi << card->vcibits | vci]);
+	vcc->dev_data = vc;
 
-   inuse = 0;
-   if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx)
-      inuse = 1;
-   if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx)
-      inuse += 2;
-   if (inuse)
-   {
-      printk("nicstar%d: %s vci already in use.\n", card->index,
-             inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx");
-      return -EINVAL;
-   }
+	inuse = 0;
+	if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx)
+		inuse = 1;
+	if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx)
+		inuse += 2;
+	if (inuse) {
+		printk("nicstar%d: %s vci already in use.\n", card->index,
+		       inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx");
+		return -EINVAL;
+	}
 
-   set_bit(ATM_VF_ADDR,&vcc->flags);
+	set_bit(ATM_VF_ADDR, &vcc->flags);
 
-   /* NOTE: You are not allowed to modify an open connection's QOS. To change
-      that, remove the ATM_VF_PARTIAL flag checking. There may be other changes
-      needed to do that. */
-   if (!test_bit(ATM_VF_PARTIAL,&vcc->flags))
-   {
-      scq_info *scq;
-      
-      set_bit(ATM_VF_PARTIAL,&vcc->flags);
-      if (vcc->qos.txtp.traffic_class == ATM_CBR)
-      {
-         /* Check requested cell rate and availability of SCD */
-         if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0 &&
-             vcc->qos.txtp.min_pcr == 0)
-         {
-            PRINTK("nicstar%d: trying to open a CBR vc with cell rate = 0 \n",
-	           card->index);
-	    clear_bit(ATM_VF_PARTIAL,&vcc->flags);
-	    clear_bit(ATM_VF_ADDR,&vcc->flags);
-            return -EINVAL;
-         }
+	/* NOTE: You are not allowed to modify an open connection's QOS. To change
+	   that, remove the ATM_VF_PARTIAL flag checking. There may be other changes
+	   needed to do that. */
+	if (!test_bit(ATM_VF_PARTIAL, &vcc->flags)) {
+		scq_info *scq;
 
-         tcr = atm_pcr_goal(&(vcc->qos.txtp));
-         tcra = tcr >= 0 ? tcr : -tcr;
-      
-         PRINTK("nicstar%d: target cell rate = %d.\n", card->index,
-                vcc->qos.txtp.max_pcr);
+		set_bit(ATM_VF_PARTIAL, &vcc->flags);
+		if (vcc->qos.txtp.traffic_class == ATM_CBR) {
+			/* Check requested cell rate and availability of SCD */
+			if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0
+			    && vcc->qos.txtp.min_pcr == 0) {
+				PRINTK
+				    ("nicstar%d: trying to open a CBR vc with cell rate = 0 \n",
+				     card->index);
+				clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+				clear_bit(ATM_VF_ADDR, &vcc->flags);
+				return -EINVAL;
+			}
 
-         tmpl = (unsigned long)tcra * (unsigned long)NS_TST_NUM_ENTRIES;
-         modl = tmpl % card->max_pcr;
+			tcr = atm_pcr_goal(&(vcc->qos.txtp));
+			tcra = tcr >= 0 ? tcr : -tcr;
 
-         n = (int)(tmpl / card->max_pcr);
-         if (tcr > 0)
-         {
-            if (modl > 0) n++;
-         }
-         else if (tcr == 0)
-         {
-            if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0)
-	    {
-               PRINTK("nicstar%d: no CBR bandwidth free.\n", card->index);
-	       clear_bit(ATM_VF_PARTIAL,&vcc->flags);
-	       clear_bit(ATM_VF_ADDR,&vcc->flags);
-               return -EINVAL;
-            }
-         }
+			PRINTK("nicstar%d: target cell rate = %d.\n",
+			       card->index, vcc->qos.txtp.max_pcr);
 
-         if (n == 0)
-         {
-            printk("nicstar%d: selected bandwidth < granularity.\n", card->index);
-	    clear_bit(ATM_VF_PARTIAL,&vcc->flags);
-	    clear_bit(ATM_VF_ADDR,&vcc->flags);
-            return -EINVAL;
-         }
+			tmpl =
+			    (unsigned long)tcra *(unsigned long)
+			    NS_TST_NUM_ENTRIES;
+			modl = tmpl % card->max_pcr;
 
-         if (n > (card->tst_free_entries - NS_TST_RESERVED))
-         {
-            PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index);
-	    clear_bit(ATM_VF_PARTIAL,&vcc->flags);
-	    clear_bit(ATM_VF_ADDR,&vcc->flags);
-            return -EINVAL;
-         }
-         else
-            card->tst_free_entries -= n;
+			n = (int)(tmpl / card->max_pcr);
+			if (tcr > 0) {
+				if (modl > 0)
+					n++;
+			} else if (tcr == 0) {
+				if ((n =
+				     (card->tst_free_entries -
+				      NS_TST_RESERVED)) <= 0) {
+					PRINTK
+					    ("nicstar%d: no CBR bandwidth free.\n",
+					     card->index);
+					clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+					clear_bit(ATM_VF_ADDR, &vcc->flags);
+					return -EINVAL;
+				}
+			}
 
-         XPRINTK("nicstar%d: writing %d tst entries.\n", card->index, n);
-         for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++)
-         {
-            if (card->scd2vc[frscdi] == NULL)
-            {
-               card->scd2vc[frscdi] = vc;
-               break;
-	    }
-         }
-         if (frscdi == NS_FRSCD_NUM)
-         {
-            PRINTK("nicstar%d: no SCD available for CBR channel.\n", card->index);
-            card->tst_free_entries += n;
-	    clear_bit(ATM_VF_PARTIAL,&vcc->flags);
-	    clear_bit(ATM_VF_ADDR,&vcc->flags);
-	    return -EBUSY;
-         }
+			if (n == 0) {
+				printk
+				    ("nicstar%d: selected bandwidth < granularity.\n",
+				     card->index);
+				clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+				clear_bit(ATM_VF_ADDR, &vcc->flags);
+				return -EINVAL;
+			}
 
-         vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE;
+			if (n > (card->tst_free_entries - NS_TST_RESERVED)) {
+				PRINTK
+				    ("nicstar%d: not enough free CBR bandwidth.\n",
+				     card->index);
+				clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+				clear_bit(ATM_VF_ADDR, &vcc->flags);
+				return -EINVAL;
+			} else
+				card->tst_free_entries -= n;
 
-         scq = get_scq(CBR_SCQSIZE, vc->cbr_scd);
-         if (scq == NULL)
-         {
-            PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index);
-            card->scd2vc[frscdi] = NULL;
-            card->tst_free_entries += n;
-	    clear_bit(ATM_VF_PARTIAL,&vcc->flags);
-	    clear_bit(ATM_VF_ADDR,&vcc->flags);
-            return -ENOMEM;
-         }
-	 vc->scq = scq;
-         u32d[0] = (u32) virt_to_bus(scq->base);
-         u32d[1] = (u32) 0x00000000;
-         u32d[2] = (u32) 0xffffffff;
-         u32d[3] = (u32) 0x00000000;
-         ns_write_sram(card, vc->cbr_scd, u32d, 4);
-         
-	 fill_tst(card, n, vc);
-      }
-      else if (vcc->qos.txtp.traffic_class == ATM_UBR)
-      {
-         vc->cbr_scd = 0x00000000;
-	 vc->scq = card->scq0;
-      }
-      
-      if (vcc->qos.txtp.traffic_class != ATM_NONE)
-      {
-         vc->tx = 1;
-	 vc->tx_vcc = vcc;
-	 vc->tbd_count = 0;
-      }
-      if (vcc->qos.rxtp.traffic_class != ATM_NONE)
-      {
-         u32 status;
-      
-         vc->rx = 1;
-         vc->rx_vcc = vcc;
-         vc->rx_iov = NULL;
+			XPRINTK("nicstar%d: writing %d tst entries.\n",
+				card->index, n);
+			for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++) {
+				if (card->scd2vc[frscdi] == NULL) {
+					card->scd2vc[frscdi] = vc;
+					break;
+				}
+			}
+			if (frscdi == NS_FRSCD_NUM) {
+				PRINTK
+				    ("nicstar%d: no SCD available for CBR channel.\n",
+				     card->index);
+				card->tst_free_entries += n;
+				clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+				clear_bit(ATM_VF_ADDR, &vcc->flags);
+				return -EBUSY;
+			}
 
-	 /* Open the connection in hardware */
-	 if (vcc->qos.aal == ATM_AAL5)
-	    status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN;
-	 else /* vcc->qos.aal == ATM_AAL0 */
-	    status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN;
+			vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE;
+
+			scq = get_scq(card, CBR_SCQSIZE, vc->cbr_scd);
+			if (scq == NULL) {
+				PRINTK("nicstar%d: can't get fixed rate SCQ.\n",
+				       card->index);
+				card->scd2vc[frscdi] = NULL;
+				card->tst_free_entries += n;
+				clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+				clear_bit(ATM_VF_ADDR, &vcc->flags);
+				return -ENOMEM;
+			}
+			vc->scq = scq;
+			u32d[0] = scq_virt_to_bus(scq, scq->base);
+			u32d[1] = (u32) 0x00000000;
+			u32d[2] = (u32) 0xffffffff;
+			u32d[3] = (u32) 0x00000000;
+			ns_write_sram(card, vc->cbr_scd, u32d, 4);
+
+			fill_tst(card, n, vc);
+		} else if (vcc->qos.txtp.traffic_class == ATM_UBR) {
+			vc->cbr_scd = 0x00000000;
+			vc->scq = card->scq0;
+		}
+
+		if (vcc->qos.txtp.traffic_class != ATM_NONE) {
+			vc->tx = 1;
+			vc->tx_vcc = vcc;
+			vc->tbd_count = 0;
+		}
+		if (vcc->qos.rxtp.traffic_class != ATM_NONE) {
+			u32 status;
+
+			vc->rx = 1;
+			vc->rx_vcc = vcc;
+			vc->rx_iov = NULL;
+
+			/* Open the connection in hardware */
+			if (vcc->qos.aal == ATM_AAL5)
+				status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN;
+			else	/* vcc->qos.aal == ATM_AAL0 */
+				status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN;
 #ifdef RCQ_SUPPORT
-         status |= NS_RCTE_RAWCELLINTEN;
+			status |= NS_RCTE_RAWCELLINTEN;
 #endif /* RCQ_SUPPORT */
-         ns_write_sram(card, NS_RCT + (vpi << card->vcibits | vci) *
-	               NS_RCT_ENTRY_SIZE, &status, 1);
-      }
-      
-   }
-   
-   set_bit(ATM_VF_READY,&vcc->flags);
-   return 0;
+			ns_write_sram(card,
+				      NS_RCT +
+				      (vpi << card->vcibits | vci) *
+				      NS_RCT_ENTRY_SIZE, &status, 1);
+		}
+
+	}
+
+	set_bit(ATM_VF_READY, &vcc->flags);
+	return 0;
 }
 
-
-
 static void ns_close(struct atm_vcc *vcc)
 {
-   vc_map *vc;
-   ns_dev *card;
-   u32 data;
-   int i;
-   
-   vc = vcc->dev_data;
-   card = vcc->dev->dev_data;
-   PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index,
-          (int) vcc->vpi, vcc->vci);
+	vc_map *vc;
+	ns_dev *card;
+	u32 data;
+	int i;
 
-   clear_bit(ATM_VF_READY,&vcc->flags);
-   
-   if (vcc->qos.rxtp.traffic_class != ATM_NONE)
-   {
-      u32 addr;
-      unsigned long flags;
-      
-      addr = NS_RCT + (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE;
-      spin_lock_irqsave(&card->res_lock, flags);
-      while(CMD_BUSY(card));
-      writel(NS_CMD_CLOSE_CONNECTION | addr << 2, card->membase + CMD);
-      spin_unlock_irqrestore(&card->res_lock, flags);
-      
-      vc->rx = 0;
-      if (vc->rx_iov != NULL)
-      {
-	 struct sk_buff *iovb;
-	 u32 stat;
-   
-         stat = readl(card->membase + STAT);
-         card->sbfqc = ns_stat_sfbqc_get(stat);   
-         card->lbfqc = ns_stat_lfbqc_get(stat);
+	vc = vcc->dev_data;
+	card = vcc->dev->dev_data;
+	PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index,
+	       (int)vcc->vpi, vcc->vci);
 
-         PRINTK("nicstar%d: closing a VC with pending rx buffers.\n",
-	        card->index);
-         iovb = vc->rx_iov;
-         recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-	                       NS_SKB(iovb)->iovcnt);
-         NS_SKB(iovb)->iovcnt = 0;
-         NS_SKB(iovb)->vcc = NULL;
-         spin_lock_irqsave(&card->int_lock, flags);
-         recycle_iov_buf(card, iovb);
-         spin_unlock_irqrestore(&card->int_lock, flags);
-         vc->rx_iov = NULL;
-      }
-   }
+	clear_bit(ATM_VF_READY, &vcc->flags);
 
-   if (vcc->qos.txtp.traffic_class != ATM_NONE)
-   {
-      vc->tx = 0;
-   }
+	if (vcc->qos.rxtp.traffic_class != ATM_NONE) {
+		u32 addr;
+		unsigned long flags;
 
-   if (vcc->qos.txtp.traffic_class == ATM_CBR)
-   {
-      unsigned long flags;
-      ns_scqe *scqep;
-      scq_info *scq;
+		addr =
+		    NS_RCT +
+		    (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE;
+		spin_lock_irqsave(&card->res_lock, flags);
+		while (CMD_BUSY(card)) ;
+		writel(NS_CMD_CLOSE_CONNECTION | addr << 2,
+		       card->membase + CMD);
+		spin_unlock_irqrestore(&card->res_lock, flags);
 
-      scq = vc->scq;
+		vc->rx = 0;
+		if (vc->rx_iov != NULL) {
+			struct sk_buff *iovb;
+			u32 stat;
 
-      for (;;)
-      {
-         spin_lock_irqsave(&scq->lock, flags);
-         scqep = scq->next;
-         if (scqep == scq->base)
-            scqep = scq->last;
-         else
-            scqep--;
-         if (scqep == scq->tail)
-         {
-            spin_unlock_irqrestore(&scq->lock, flags);
-            break;
-         }
-         /* If the last entry is not a TSR, place one in the SCQ in order to
-            be able to completely drain it and then close. */
-         if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next)
-         {
-            ns_scqe tsr;
-            u32 scdi, scqi;
-            u32 data;
-            int index;
+			stat = readl(card->membase + STAT);
+			card->sbfqc = ns_stat_sfbqc_get(stat);
+			card->lbfqc = ns_stat_lfbqc_get(stat);
 
-            tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
-            scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
-            scqi = scq->next - scq->base;
-            tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
-            tsr.word_3 = 0x00000000;
-            tsr.word_4 = 0x00000000;
-            *scq->next = tsr;
-            index = (int) scqi;
-            scq->skb[index] = NULL;
-            if (scq->next == scq->last)
-               scq->next = scq->base;
-            else
-               scq->next++;
-            data = (u32) virt_to_bus(scq->next);
-            ns_write_sram(card, scq->scd, &data, 1);
-         }
-         spin_unlock_irqrestore(&scq->lock, flags);
-         schedule();
-      }
+			PRINTK
+			    ("nicstar%d: closing a VC with pending rx buffers.\n",
+			     card->index);
+			iovb = vc->rx_iov;
+			recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data,
+					      NS_PRV_IOVCNT(iovb));
+			NS_PRV_IOVCNT(iovb) = 0;
+			spin_lock_irqsave(&card->int_lock, flags);
+			recycle_iov_buf(card, iovb);
+			spin_unlock_irqrestore(&card->int_lock, flags);
+			vc->rx_iov = NULL;
+		}
+	}
 
-      /* Free all TST entries */
-      data = NS_TST_OPCODE_VARIABLE;
-      for (i = 0; i < NS_TST_NUM_ENTRIES; i++)
-      {
-         if (card->tste2vc[i] == vc)
-	 {
-            ns_write_sram(card, card->tst_addr + i, &data, 1);
-            card->tste2vc[i] = NULL;
-            card->tst_free_entries++;
-	 }
-      }
-      
-      card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL;
-      free_scq(vc->scq, vcc);
-   }
+	if (vcc->qos.txtp.traffic_class != ATM_NONE) {
+		vc->tx = 0;
+	}
 
-   /* remove all references to vcc before deleting it */
-   if (vcc->qos.txtp.traffic_class != ATM_NONE)
-   {
-     unsigned long flags;
-     scq_info *scq = card->scq0;
+	if (vcc->qos.txtp.traffic_class == ATM_CBR) {
+		unsigned long flags;
+		ns_scqe *scqep;
+		scq_info *scq;
 
-     spin_lock_irqsave(&scq->lock, flags);
+		scq = vc->scq;
 
-     for(i = 0; i < scq->num_entries; i++) {
-       if(scq->skb[i] && ATM_SKB(scq->skb[i])->vcc == vcc) {
-        ATM_SKB(scq->skb[i])->vcc = NULL;
-	atm_return(vcc, scq->skb[i]->truesize);
-        PRINTK("nicstar: deleted pending vcc mapping\n");
-       }
-     }
+		for (;;) {
+			spin_lock_irqsave(&scq->lock, flags);
+			scqep = scq->next;
+			if (scqep == scq->base)
+				scqep = scq->last;
+			else
+				scqep--;
+			if (scqep == scq->tail) {
+				spin_unlock_irqrestore(&scq->lock, flags);
+				break;
+			}
+			/* If the last entry is not a TSR, place one in the SCQ in order to
+			   be able to completely drain it and then close. */
+			if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next) {
+				ns_scqe tsr;
+				u32 scdi, scqi;
+				u32 data;
+				int index;
 
-     spin_unlock_irqrestore(&scq->lock, flags);
-   }
+				tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
+				scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
+				scqi = scq->next - scq->base;
+				tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
+				tsr.word_3 = 0x00000000;
+				tsr.word_4 = 0x00000000;
+				*scq->next = tsr;
+				index = (int)scqi;
+				scq->skb[index] = NULL;
+				if (scq->next == scq->last)
+					scq->next = scq->base;
+				else
+					scq->next++;
+				data = scq_virt_to_bus(scq, scq->next);
+				ns_write_sram(card, scq->scd, &data, 1);
+			}
+			spin_unlock_irqrestore(&scq->lock, flags);
+			schedule();
+		}
 
-   vcc->dev_data = NULL;
-   clear_bit(ATM_VF_PARTIAL,&vcc->flags);
-   clear_bit(ATM_VF_ADDR,&vcc->flags);
+		/* Free all TST entries */
+		data = NS_TST_OPCODE_VARIABLE;
+		for (i = 0; i < NS_TST_NUM_ENTRIES; i++) {
+			if (card->tste2vc[i] == vc) {
+				ns_write_sram(card, card->tst_addr + i, &data,
+					      1);
+				card->tste2vc[i] = NULL;
+				card->tst_free_entries++;
+			}
+		}
+
+		card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL;
+		free_scq(card, vc->scq, vcc);
+	}
+
+	/* remove all references to vcc before deleting it */
+	if (vcc->qos.txtp.traffic_class != ATM_NONE) {
+		unsigned long flags;
+		scq_info *scq = card->scq0;
+
+		spin_lock_irqsave(&scq->lock, flags);
+
+		for (i = 0; i < scq->num_entries; i++) {
+			if (scq->skb[i] && ATM_SKB(scq->skb[i])->vcc == vcc) {
+				ATM_SKB(scq->skb[i])->vcc = NULL;
+				atm_return(vcc, scq->skb[i]->truesize);
+				PRINTK
+				    ("nicstar: deleted pending vcc mapping\n");
+			}
+		}
+
+		spin_unlock_irqrestore(&scq->lock, flags);
+	}
+
+	vcc->dev_data = NULL;
+	clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+	clear_bit(ATM_VF_ADDR, &vcc->flags);
 
 #ifdef RX_DEBUG
-   {
-      u32 stat, cfg;
-      stat = readl(card->membase + STAT);
-      cfg = readl(card->membase + CFG);
-      printk("STAT = 0x%08X  CFG = 0x%08X  \n", stat, cfg);
-      printk("TSQ: base = 0x%08X  next = 0x%08X  last = 0x%08X  TSQT = 0x%08X \n",
-             (u32) card->tsq.base, (u32) card->tsq.next,(u32) card->tsq.last,
-	     readl(card->membase + TSQT));
-      printk("RSQ: base = 0x%08X  next = 0x%08X  last = 0x%08X  RSQT = 0x%08X \n",
-             (u32) card->rsq.base, (u32) card->rsq.next,(u32) card->rsq.last,
-	     readl(card->membase + RSQT));
-      printk("Empty free buffer queue interrupt %s \n",
-             card->efbie ? "enabled" : "disabled");
-      printk("SBCNT = %d  count = %d   LBCNT = %d count = %d \n",
-             ns_stat_sfbqc_get(stat), card->sbpool.count,
-	     ns_stat_lfbqc_get(stat), card->lbpool.count);
-      printk("hbpool.count = %d  iovpool.count = %d \n",
-             card->hbpool.count, card->iovpool.count);
-   }
+	{
+		u32 stat, cfg;
+		stat = readl(card->membase + STAT);
+		cfg = readl(card->membase + CFG);
+		printk("STAT = 0x%08X  CFG = 0x%08X  \n", stat, cfg);
+		printk
+		    ("TSQ: base = 0x%p  next = 0x%p  last = 0x%p  TSQT = 0x%08X \n",
+		     card->tsq.base, card->tsq.next,
+		     card->tsq.last, readl(card->membase + TSQT));
+		printk
+		    ("RSQ: base = 0x%p  next = 0x%p  last = 0x%p  RSQT = 0x%08X \n",
+		     card->rsq.base, card->rsq.next,
+		     card->rsq.last, readl(card->membase + RSQT));
+		printk("Empty free buffer queue interrupt %s \n",
+		       card->efbie ? "enabled" : "disabled");
+		printk("SBCNT = %d  count = %d   LBCNT = %d count = %d \n",
+		       ns_stat_sfbqc_get(stat), card->sbpool.count,
+		       ns_stat_lfbqc_get(stat), card->lbpool.count);
+		printk("hbpool.count = %d  iovpool.count = %d \n",
+		       card->hbpool.count, card->iovpool.count);
+	}
 #endif /* RX_DEBUG */
 }
 
-
-
-static void fill_tst(ns_dev *card, int n, vc_map *vc)
+static void fill_tst(ns_dev * card, int n, vc_map * vc)
 {
-   u32 new_tst;
-   unsigned long cl;
-   int e, r;
-   u32 data;
-      
-   /* It would be very complicated to keep the two TSTs synchronized while
-      assuring that writes are only made to the inactive TST. So, for now I
-      will use only one TST. If problems occur, I will change this again */
-   
-   new_tst = card->tst_addr;
+	u32 new_tst;
+	unsigned long cl;
+	int e, r;
+	u32 data;
 
-   /* Fill procedure */
+	/* It would be very complicated to keep the two TSTs synchronized while
+	   assuring that writes are only made to the inactive TST. So, for now I
+	   will use only one TST. If problems occur, I will change this again */
 
-   for (e = 0; e < NS_TST_NUM_ENTRIES; e++)
-   {
-      if (card->tste2vc[e] == NULL)
-         break;
-   }
-   if (e == NS_TST_NUM_ENTRIES) {
-      printk("nicstar%d: No free TST entries found. \n", card->index);
-      return;
-   }
+	new_tst = card->tst_addr;
 
-   r = n;
-   cl = NS_TST_NUM_ENTRIES;
-   data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd);
-      
-   while (r > 0)
-   {
-      if (cl >= NS_TST_NUM_ENTRIES && card->tste2vc[e] == NULL)
-      {
-         card->tste2vc[e] = vc;
-         ns_write_sram(card, new_tst + e, &data, 1);
-         cl -= NS_TST_NUM_ENTRIES;
-         r--;
-      }
+	/* Fill procedure */
 
-      if (++e == NS_TST_NUM_ENTRIES) {
-         e = 0;
-      }
-      cl += n;
-   }
-   
-   /* End of fill procedure */
-   
-   data = ns_tste_make(NS_TST_OPCODE_END, new_tst);
-   ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1);
-   ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1);
-   card->tst_addr = new_tst;
+	for (e = 0; e < NS_TST_NUM_ENTRIES; e++) {
+		if (card->tste2vc[e] == NULL)
+			break;
+	}
+	if (e == NS_TST_NUM_ENTRIES) {
+		printk("nicstar%d: No free TST entries found. \n", card->index);
+		return;
+	}
+
+	r = n;
+	cl = NS_TST_NUM_ENTRIES;
+	data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd);
+
+	while (r > 0) {
+		if (cl >= NS_TST_NUM_ENTRIES && card->tste2vc[e] == NULL) {
+			card->tste2vc[e] = vc;
+			ns_write_sram(card, new_tst + e, &data, 1);
+			cl -= NS_TST_NUM_ENTRIES;
+			r--;
+		}
+
+		if (++e == NS_TST_NUM_ENTRIES) {
+			e = 0;
+		}
+		cl += n;
+	}
+
+	/* End of fill procedure */
+
+	data = ns_tste_make(NS_TST_OPCODE_END, new_tst);
+	ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1);
+	ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1);
+	card->tst_addr = new_tst;
 }
 
-
-
 static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
 {
-   ns_dev *card;
-   vc_map *vc;
-   scq_info *scq;
-   unsigned long buflen;
-   ns_scqe scqe;
-   u32 flags;		/* TBD flags, not CPU flags */
-   
-   card = vcc->dev->dev_data;
-   TXPRINTK("nicstar%d: ns_send() called.\n", card->index);
-   if ((vc = (vc_map *) vcc->dev_data) == NULL)
-   {
-      printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index);
-      atomic_inc(&vcc->stats->tx_err);
-      dev_kfree_skb_any(skb);
-      return -EINVAL;
-   }
-   
-   if (!vc->tx)
-   {
-      printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index);
-      atomic_inc(&vcc->stats->tx_err);
-      dev_kfree_skb_any(skb);
-      return -EINVAL;
-   }
-   
-   if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0)
-   {
-      printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index);
-      atomic_inc(&vcc->stats->tx_err);
-      dev_kfree_skb_any(skb);
-      return -EINVAL;
-   }
-   
-   if (skb_shinfo(skb)->nr_frags != 0)
-   {
-      printk("nicstar%d: No scatter-gather yet.\n", card->index);
-      atomic_inc(&vcc->stats->tx_err);
-      dev_kfree_skb_any(skb);
-      return -EINVAL;
-   }
-   
-   ATM_SKB(skb)->vcc = vcc;
+	ns_dev *card;
+	vc_map *vc;
+	scq_info *scq;
+	unsigned long buflen;
+	ns_scqe scqe;
+	u32 flags;		/* TBD flags, not CPU flags */
 
-   if (vcc->qos.aal == ATM_AAL5)
-   {
-      buflen = (skb->len + 47 + 8) / 48 * 48;	/* Multiple of 48 */
-      flags = NS_TBD_AAL5;
-      scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data));
-      scqe.word_3 = cpu_to_le32((u32) skb->len);
-      scqe.word_4 = ns_tbd_mkword_4(0, (u32) vcc->vpi, (u32) vcc->vci, 0,
-                           ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? 1 : 0);
-      flags |= NS_TBD_EOPDU;
-   }
-   else /* (vcc->qos.aal == ATM_AAL0) */
-   {
-      buflen = ATM_CELL_PAYLOAD;	/* i.e., 48 bytes */
-      flags = NS_TBD_AAL0;
-      scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data) + NS_AAL0_HEADER);
-      scqe.word_3 = cpu_to_le32(0x00000000);
-      if (*skb->data & 0x02)	/* Payload type 1 - end of pdu */
-         flags |= NS_TBD_EOPDU;
-      scqe.word_4 = cpu_to_le32(*((u32 *) skb->data) & ~NS_TBD_VC_MASK);
-      /* Force the VPI/VCI to be the same as in VCC struct */
-      scqe.word_4 |= cpu_to_le32((((u32) vcc->vpi) << NS_TBD_VPI_SHIFT |
-                                 ((u32) vcc->vci) << NS_TBD_VCI_SHIFT) &
-                                 NS_TBD_VC_MASK);
-   }
+	card = vcc->dev->dev_data;
+	TXPRINTK("nicstar%d: ns_send() called.\n", card->index);
+	if ((vc = (vc_map *) vcc->dev_data) == NULL) {
+		printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n",
+		       card->index);
+		atomic_inc(&vcc->stats->tx_err);
+		dev_kfree_skb_any(skb);
+		return -EINVAL;
+	}
 
-   if (vcc->qos.txtp.traffic_class == ATM_CBR)
-   {
-      scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen);
-      scq = ((vc_map *) vcc->dev_data)->scq;
-   }
-   else
-   {
-      scqe.word_1 = ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen);
-      scq = card->scq0;
-   }
+	if (!vc->tx) {
+		printk("nicstar%d: Trying to transmit on a non-tx VC.\n",
+		       card->index);
+		atomic_inc(&vcc->stats->tx_err);
+		dev_kfree_skb_any(skb);
+		return -EINVAL;
+	}
 
-   if (push_scqe(card, vc, scq, &scqe, skb) != 0)
-   {
-      atomic_inc(&vcc->stats->tx_err);
-      dev_kfree_skb_any(skb);
-      return -EIO;
-   }
-   atomic_inc(&vcc->stats->tx);
+	if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) {
+		printk("nicstar%d: Only AAL0 and AAL5 are supported.\n",
+		       card->index);
+		atomic_inc(&vcc->stats->tx_err);
+		dev_kfree_skb_any(skb);
+		return -EINVAL;
+	}
 
-   return 0;
+	if (skb_shinfo(skb)->nr_frags != 0) {
+		printk("nicstar%d: No scatter-gather yet.\n", card->index);
+		atomic_inc(&vcc->stats->tx_err);
+		dev_kfree_skb_any(skb);
+		return -EINVAL;
+	}
+
+	ATM_SKB(skb)->vcc = vcc;
+
+	NS_PRV_DMA(skb) = pci_map_single(card->pcidev, skb->data,
+					 skb->len, PCI_DMA_TODEVICE);
+
+	if (vcc->qos.aal == ATM_AAL5) {
+		buflen = (skb->len + 47 + 8) / 48 * 48;	/* Multiple of 48 */
+		flags = NS_TBD_AAL5;
+		scqe.word_2 = cpu_to_le32(NS_PRV_DMA(skb));
+		scqe.word_3 = cpu_to_le32(skb->len);
+		scqe.word_4 =
+		    ns_tbd_mkword_4(0, (u32) vcc->vpi, (u32) vcc->vci, 0,
+				    ATM_SKB(skb)->
+				    atm_options & ATM_ATMOPT_CLP ? 1 : 0);
+		flags |= NS_TBD_EOPDU;
+	} else {		/* (vcc->qos.aal == ATM_AAL0) */
+
+		buflen = ATM_CELL_PAYLOAD;	/* i.e., 48 bytes */
+		flags = NS_TBD_AAL0;
+		scqe.word_2 = cpu_to_le32(NS_PRV_DMA(skb) + NS_AAL0_HEADER);
+		scqe.word_3 = cpu_to_le32(0x00000000);
+		if (*skb->data & 0x02)	/* Payload type 1 - end of pdu */
+			flags |= NS_TBD_EOPDU;
+		scqe.word_4 =
+		    cpu_to_le32(*((u32 *) skb->data) & ~NS_TBD_VC_MASK);
+		/* Force the VPI/VCI to be the same as in VCC struct */
+		scqe.word_4 |=
+		    cpu_to_le32((((u32) vcc->
+				  vpi) << NS_TBD_VPI_SHIFT | ((u32) vcc->
+							      vci) <<
+				 NS_TBD_VCI_SHIFT) & NS_TBD_VC_MASK);
+	}
+
+	if (vcc->qos.txtp.traffic_class == ATM_CBR) {
+		scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen);
+		scq = ((vc_map *) vcc->dev_data)->scq;
+	} else {
+		scqe.word_1 =
+		    ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen);
+		scq = card->scq0;
+	}
+
+	if (push_scqe(card, vc, scq, &scqe, skb) != 0) {
+		atomic_inc(&vcc->stats->tx_err);
+		dev_kfree_skb_any(skb);
+		return -EIO;
+	}
+	atomic_inc(&vcc->stats->tx);
+
+	return 0;
 }
 
-
-
-static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd,
-                     struct sk_buff *skb)
+static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
+		     struct sk_buff *skb)
 {
-   unsigned long flags;
-   ns_scqe tsr;
-   u32 scdi, scqi;
-   int scq_is_vbr;
-   u32 data;
-   int index;
-   
-   spin_lock_irqsave(&scq->lock, flags);
-   while (scq->tail == scq->next)
-   {
-      if (in_interrupt()) {
-         spin_unlock_irqrestore(&scq->lock, flags);
-         printk("nicstar%d: Error pushing TBD.\n", card->index);
-         return 1;
-      }
+	unsigned long flags;
+	ns_scqe tsr;
+	u32 scdi, scqi;
+	int scq_is_vbr;
+	u32 data;
+	int index;
 
-      scq->full = 1;
-      spin_unlock_irqrestore(&scq->lock, flags);
-      interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT);
-      spin_lock_irqsave(&scq->lock, flags);
+	spin_lock_irqsave(&scq->lock, flags);
+	while (scq->tail == scq->next) {
+		if (in_interrupt()) {
+			spin_unlock_irqrestore(&scq->lock, flags);
+			printk("nicstar%d: Error pushing TBD.\n", card->index);
+			return 1;
+		}
 
-      if (scq->full) {
-         spin_unlock_irqrestore(&scq->lock, flags);
-         printk("nicstar%d: Timeout pushing TBD.\n", card->index);
-         return 1;
-      }
-   }
-   *scq->next = *tbd;
-   index = (int) (scq->next - scq->base);
-   scq->skb[index] = skb;
-   XPRINTK("nicstar%d: sending skb at 0x%x (pos %d).\n",
-           card->index, (u32) skb, index);
-   XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n",
-           card->index, le32_to_cpu(tbd->word_1), le32_to_cpu(tbd->word_2),
-           le32_to_cpu(tbd->word_3), le32_to_cpu(tbd->word_4),
-           (u32) scq->next);
-   if (scq->next == scq->last)
-      scq->next = scq->base;
-   else
-      scq->next++;
+		scq->full = 1;
+		spin_unlock_irqrestore(&scq->lock, flags);
+		interruptible_sleep_on_timeout(&scq->scqfull_waitq,
+					       SCQFULL_TIMEOUT);
+		spin_lock_irqsave(&scq->lock, flags);
 
-   vc->tbd_count++;
-   if (scq->num_entries == VBR_SCQ_NUM_ENTRIES)
-   {
-      scq->tbd_count++;
-      scq_is_vbr = 1;
-   }
-   else
-      scq_is_vbr = 0;
+		if (scq->full) {
+			spin_unlock_irqrestore(&scq->lock, flags);
+			printk("nicstar%d: Timeout pushing TBD.\n",
+			       card->index);
+			return 1;
+		}
+	}
+	*scq->next = *tbd;
+	index = (int)(scq->next - scq->base);
+	scq->skb[index] = skb;
+	XPRINTK("nicstar%d: sending skb at 0x%p (pos %d).\n",
+		card->index, skb, index);
+	XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%p.\n",
+		card->index, le32_to_cpu(tbd->word_1), le32_to_cpu(tbd->word_2),
+		le32_to_cpu(tbd->word_3), le32_to_cpu(tbd->word_4),
+		scq->next);
+	if (scq->next == scq->last)
+		scq->next = scq->base;
+	else
+		scq->next++;
 
-   if (vc->tbd_count >= MAX_TBD_PER_VC || scq->tbd_count >= MAX_TBD_PER_SCQ)
-   {
-      int has_run = 0;
+	vc->tbd_count++;
+	if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) {
+		scq->tbd_count++;
+		scq_is_vbr = 1;
+	} else
+		scq_is_vbr = 0;
 
-      while (scq->tail == scq->next)
-      {
-         if (in_interrupt()) {
-            data = (u32) virt_to_bus(scq->next);
-            ns_write_sram(card, scq->scd, &data, 1);
-            spin_unlock_irqrestore(&scq->lock, flags);
-            printk("nicstar%d: Error pushing TSR.\n", card->index);
-            return 0;
-         }
+	if (vc->tbd_count >= MAX_TBD_PER_VC
+	    || scq->tbd_count >= MAX_TBD_PER_SCQ) {
+		int has_run = 0;
 
-         scq->full = 1;
-         if (has_run++) break;
-         spin_unlock_irqrestore(&scq->lock, flags);
-         interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT);
-         spin_lock_irqsave(&scq->lock, flags);
-      }
+		while (scq->tail == scq->next) {
+			if (in_interrupt()) {
+				data = scq_virt_to_bus(scq, scq->next);
+				ns_write_sram(card, scq->scd, &data, 1);
+				spin_unlock_irqrestore(&scq->lock, flags);
+				printk("nicstar%d: Error pushing TSR.\n",
+				       card->index);
+				return 0;
+			}
 
-      if (!scq->full)
-      {
-         tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
-         if (scq_is_vbr)
-            scdi = NS_TSR_SCDISVBR;
-         else
-            scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
-         scqi = scq->next - scq->base;
-         tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
-         tsr.word_3 = 0x00000000;
-         tsr.word_4 = 0x00000000;
+			scq->full = 1;
+			if (has_run++)
+				break;
+			spin_unlock_irqrestore(&scq->lock, flags);
+			interruptible_sleep_on_timeout(&scq->scqfull_waitq,
+						       SCQFULL_TIMEOUT);
+			spin_lock_irqsave(&scq->lock, flags);
+		}
 
-         *scq->next = tsr;
-         index = (int) scqi;
-         scq->skb[index] = NULL;
-         XPRINTK("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n",
-                 card->index, le32_to_cpu(tsr.word_1), le32_to_cpu(tsr.word_2),
-                 le32_to_cpu(tsr.word_3), le32_to_cpu(tsr.word_4),
-		 (u32) scq->next);
-         if (scq->next == scq->last)
-            scq->next = scq->base;
-         else
-            scq->next++;
-         vc->tbd_count = 0;
-         scq->tbd_count = 0;
-      }
-      else
-         PRINTK("nicstar%d: Timeout pushing TSR.\n", card->index);
-   }
-   data = (u32) virt_to_bus(scq->next);
-   ns_write_sram(card, scq->scd, &data, 1);
-   
-   spin_unlock_irqrestore(&scq->lock, flags);
-   
-   return 0;
+		if (!scq->full) {
+			tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
+			if (scq_is_vbr)
+				scdi = NS_TSR_SCDISVBR;
+			else
+				scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
+			scqi = scq->next - scq->base;
+			tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
+			tsr.word_3 = 0x00000000;
+			tsr.word_4 = 0x00000000;
+
+			*scq->next = tsr;
+			index = (int)scqi;
+			scq->skb[index] = NULL;
+			XPRINTK
+			    ("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%p.\n",
+			     card->index, le32_to_cpu(tsr.word_1),
+			     le32_to_cpu(tsr.word_2), le32_to_cpu(tsr.word_3),
+			     le32_to_cpu(tsr.word_4), scq->next);
+			if (scq->next == scq->last)
+				scq->next = scq->base;
+			else
+				scq->next++;
+			vc->tbd_count = 0;
+			scq->tbd_count = 0;
+		} else
+			PRINTK("nicstar%d: Timeout pushing TSR.\n",
+			       card->index);
+	}
+	data = scq_virt_to_bus(scq, scq->next);
+	ns_write_sram(card, scq->scd, &data, 1);
+
+	spin_unlock_irqrestore(&scq->lock, flags);
+
+	return 0;
 }
 
-
-
-static void process_tsq(ns_dev *card)
+static void process_tsq(ns_dev * card)
 {
-   u32 scdi;
-   scq_info *scq;
-   ns_tsi *previous = NULL, *one_ahead, *two_ahead;
-   int serviced_entries;   /* flag indicating at least on entry was serviced */
-   
-   serviced_entries = 0;
-   
-   if (card->tsq.next == card->tsq.last)
-      one_ahead = card->tsq.base;
-   else
-      one_ahead = card->tsq.next + 1;
+	u32 scdi;
+	scq_info *scq;
+	ns_tsi *previous = NULL, *one_ahead, *two_ahead;
+	int serviced_entries;	/* flag indicating at least on entry was serviced */
 
-   if (one_ahead == card->tsq.last)
-      two_ahead = card->tsq.base;
-   else
-      two_ahead = one_ahead + 1;
-   
-   while (!ns_tsi_isempty(card->tsq.next) || !ns_tsi_isempty(one_ahead) ||
-          !ns_tsi_isempty(two_ahead))
-          /* At most two empty, as stated in the 77201 errata */
-   {
-      serviced_entries = 1;
-    
-      /* Skip the one or two possible empty entries */
-      while (ns_tsi_isempty(card->tsq.next)) {
-         if (card->tsq.next == card->tsq.last)
-            card->tsq.next = card->tsq.base;
-         else
-            card->tsq.next++;
-      }
-    
-      if (!ns_tsi_tmrof(card->tsq.next))
-      {
-         scdi = ns_tsi_getscdindex(card->tsq.next);
-	 if (scdi == NS_TSI_SCDISVBR)
-	    scq = card->scq0;
-	 else
-	 {
-	    if (card->scd2vc[scdi] == NULL)
-	    {
-	       printk("nicstar%d: could not find VC from SCD index.\n",
-	              card->index);
-               ns_tsi_init(card->tsq.next);
-               return;
-            }
-            scq = card->scd2vc[scdi]->scq;
-         }
-         drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next));
-         scq->full = 0;
-         wake_up_interruptible(&(scq->scqfull_waitq));
-      }
+	serviced_entries = 0;
 
-      ns_tsi_init(card->tsq.next);
-      previous = card->tsq.next;
-      if (card->tsq.next == card->tsq.last)
-         card->tsq.next = card->tsq.base;
-      else
-         card->tsq.next++;
+	if (card->tsq.next == card->tsq.last)
+		one_ahead = card->tsq.base;
+	else
+		one_ahead = card->tsq.next + 1;
 
-      if (card->tsq.next == card->tsq.last)
-         one_ahead = card->tsq.base;
-      else
-         one_ahead = card->tsq.next + 1;
+	if (one_ahead == card->tsq.last)
+		two_ahead = card->tsq.base;
+	else
+		two_ahead = one_ahead + 1;
 
-      if (one_ahead == card->tsq.last)
-         two_ahead = card->tsq.base;
-      else
-         two_ahead = one_ahead + 1;
-   }
+	while (!ns_tsi_isempty(card->tsq.next) || !ns_tsi_isempty(one_ahead) ||
+	       !ns_tsi_isempty(two_ahead))
+		/* At most two empty, as stated in the 77201 errata */
+	{
+		serviced_entries = 1;
 
-   if (serviced_entries) {
-      writel((((u32) previous) - ((u32) card->tsq.base)),
-             card->membase + TSQH);
-   }
+		/* Skip the one or two possible empty entries */
+		while (ns_tsi_isempty(card->tsq.next)) {
+			if (card->tsq.next == card->tsq.last)
+				card->tsq.next = card->tsq.base;
+			else
+				card->tsq.next++;
+		}
+
+		if (!ns_tsi_tmrof(card->tsq.next)) {
+			scdi = ns_tsi_getscdindex(card->tsq.next);
+			if (scdi == NS_TSI_SCDISVBR)
+				scq = card->scq0;
+			else {
+				if (card->scd2vc[scdi] == NULL) {
+					printk
+					    ("nicstar%d: could not find VC from SCD index.\n",
+					     card->index);
+					ns_tsi_init(card->tsq.next);
+					return;
+				}
+				scq = card->scd2vc[scdi]->scq;
+			}
+			drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next));
+			scq->full = 0;
+			wake_up_interruptible(&(scq->scqfull_waitq));
+		}
+
+		ns_tsi_init(card->tsq.next);
+		previous = card->tsq.next;
+		if (card->tsq.next == card->tsq.last)
+			card->tsq.next = card->tsq.base;
+		else
+			card->tsq.next++;
+
+		if (card->tsq.next == card->tsq.last)
+			one_ahead = card->tsq.base;
+		else
+			one_ahead = card->tsq.next + 1;
+
+		if (one_ahead == card->tsq.last)
+			two_ahead = card->tsq.base;
+		else
+			two_ahead = one_ahead + 1;
+	}
+
+	if (serviced_entries)
+		writel(PTR_DIFF(previous, card->tsq.base),
+		       card->membase + TSQH);
 }
 
-
-
-static void drain_scq(ns_dev *card, scq_info *scq, int pos)
+static void drain_scq(ns_dev * card, scq_info * scq, int pos)
 {
-   struct atm_vcc *vcc;
-   struct sk_buff *skb;
-   int i;
-   unsigned long flags;
-   
-   XPRINTK("nicstar%d: drain_scq() called, scq at 0x%x, pos %d.\n",
-           card->index, (u32) scq, pos);
-   if (pos >= scq->num_entries)
-   {
-      printk("nicstar%d: Bad index on drain_scq().\n", card->index);
-      return;
-   }
+	struct atm_vcc *vcc;
+	struct sk_buff *skb;
+	int i;
+	unsigned long flags;
 
-   spin_lock_irqsave(&scq->lock, flags);
-   i = (int) (scq->tail - scq->base);
-   if (++i == scq->num_entries)
-      i = 0;
-   while (i != pos)
-   {
-      skb = scq->skb[i];
-      XPRINTK("nicstar%d: freeing skb at 0x%x (index %d).\n",
-              card->index, (u32) skb, i);
-      if (skb != NULL)
-      {
-         vcc = ATM_SKB(skb)->vcc;
-	 if (vcc && vcc->pop != NULL) {
-	    vcc->pop(vcc, skb);
-	 } else {
-	    dev_kfree_skb_irq(skb);
-         }
-	 scq->skb[i] = NULL;
-      }
-      if (++i == scq->num_entries)
-         i = 0;
-   }
-   scq->tail = scq->base + pos;
-   spin_unlock_irqrestore(&scq->lock, flags);
+	XPRINTK("nicstar%d: drain_scq() called, scq at 0x%p, pos %d.\n",
+		card->index, scq, pos);
+	if (pos >= scq->num_entries) {
+		printk("nicstar%d: Bad index on drain_scq().\n", card->index);
+		return;
+	}
+
+	spin_lock_irqsave(&scq->lock, flags);
+	i = (int)(scq->tail - scq->base);
+	if (++i == scq->num_entries)
+		i = 0;
+	while (i != pos) {
+		skb = scq->skb[i];
+		XPRINTK("nicstar%d: freeing skb at 0x%p (index %d).\n",
+			card->index, skb, i);
+		if (skb != NULL) {
+			pci_unmap_single(card->pcidev,
+					 NS_PRV_DMA(skb),
+					 skb->len,
+					 PCI_DMA_TODEVICE);
+			vcc = ATM_SKB(skb)->vcc;
+			if (vcc && vcc->pop != NULL) {
+				vcc->pop(vcc, skb);
+			} else {
+				dev_kfree_skb_irq(skb);
+			}
+			scq->skb[i] = NULL;
+		}
+		if (++i == scq->num_entries)
+			i = 0;
+	}
+	scq->tail = scq->base + pos;
+	spin_unlock_irqrestore(&scq->lock, flags);
 }
 
-
-
-static void process_rsq(ns_dev *card)
+static void process_rsq(ns_dev * card)
 {
-   ns_rsqe *previous;
+	ns_rsqe *previous;
 
-   if (!ns_rsqe_valid(card->rsq.next))
-      return;
-   do {
-      dequeue_rx(card, card->rsq.next);
-      ns_rsqe_init(card->rsq.next);
-      previous = card->rsq.next;
-      if (card->rsq.next == card->rsq.last)
-         card->rsq.next = card->rsq.base;
-      else
-         card->rsq.next++;
-   } while (ns_rsqe_valid(card->rsq.next));
-   writel((((u32) previous) - ((u32) card->rsq.base)),
-          card->membase + RSQH);
+	if (!ns_rsqe_valid(card->rsq.next))
+		return;
+	do {
+		dequeue_rx(card, card->rsq.next);
+		ns_rsqe_init(card->rsq.next);
+		previous = card->rsq.next;
+		if (card->rsq.next == card->rsq.last)
+			card->rsq.next = card->rsq.base;
+		else
+			card->rsq.next++;
+	} while (ns_rsqe_valid(card->rsq.next));
+	writel(PTR_DIFF(previous, card->rsq.base), card->membase + RSQH);
 }
 
-
-
-static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
+static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe)
 {
-   u32 vpi, vci;
-   vc_map *vc;
-   struct sk_buff *iovb;
-   struct iovec *iov;
-   struct atm_vcc *vcc;
-   struct sk_buff *skb;
-   unsigned short aal5_len;
-   int len;
-   u32 stat;
+	u32 vpi, vci;
+	vc_map *vc;
+	struct sk_buff *iovb;
+	struct iovec *iov;
+	struct atm_vcc *vcc;
+	struct sk_buff *skb;
+	unsigned short aal5_len;
+	int len;
+	u32 stat;
+	u32 id;
 
-   stat = readl(card->membase + STAT);
-   card->sbfqc = ns_stat_sfbqc_get(stat);   
-   card->lbfqc = ns_stat_lfbqc_get(stat);
+	stat = readl(card->membase + STAT);
+	card->sbfqc = ns_stat_sfbqc_get(stat);
+	card->lbfqc = ns_stat_lfbqc_get(stat);
 
-   skb = (struct sk_buff *) le32_to_cpu(rsqe->buffer_handle);
-   vpi = ns_rsqe_vpi(rsqe);
-   vci = ns_rsqe_vci(rsqe);
-   if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits)
-   {
-      printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n",
-             card->index, vpi, vci);
-      recycle_rx_buf(card, skb);
-      return;
-   }
-   
-   vc = &(card->vcmap[vpi << card->vcibits | vci]);
-   if (!vc->rx)
-   {
-      RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n",
-             card->index, vpi, vci);
-      recycle_rx_buf(card, skb);
-      return;
-   }
+	id = le32_to_cpu(rsqe->buffer_handle);
+	skb = idr_find(&card->idr, id);
+	if (!skb) {
+		RXPRINTK(KERN_ERR
+			 "nicstar%d: idr_find() failed!\n", card->index);
+		return;
+	}
+	idr_remove(&card->idr, id);
+        pci_dma_sync_single_for_cpu(card->pcidev,
+				    NS_PRV_DMA(skb),
+				    (NS_PRV_BUFTYPE(skb) == BUF_SM
+				     ? NS_SMSKBSIZE : NS_LGSKBSIZE),
+				    PCI_DMA_FROMDEVICE);
+	pci_unmap_single(card->pcidev,
+			 NS_PRV_DMA(skb),
+			 (NS_PRV_BUFTYPE(skb) == BUF_SM
+			  ? NS_SMSKBSIZE : NS_LGSKBSIZE),
+			 PCI_DMA_FROMDEVICE);
+	vpi = ns_rsqe_vpi(rsqe);
+	vci = ns_rsqe_vci(rsqe);
+	if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits) {
+		printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n",
+		       card->index, vpi, vci);
+		recycle_rx_buf(card, skb);
+		return;
+	}
 
-   vcc = vc->rx_vcc;
+	vc = &(card->vcmap[vpi << card->vcibits | vci]);
+	if (!vc->rx) {
+		RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n",
+			 card->index, vpi, vci);
+		recycle_rx_buf(card, skb);
+		return;
+	}
 
-   if (vcc->qos.aal == ATM_AAL0)
-   {
-      struct sk_buff *sb;
-      unsigned char *cell;
-      int i;
+	vcc = vc->rx_vcc;
 
-      cell = skb->data;
-      for (i = ns_rsqe_cellcount(rsqe); i; i--)
-      {
-         if ((sb = dev_alloc_skb(NS_SMSKBSIZE)) == NULL)
-         {
-            printk("nicstar%d: Can't allocate buffers for aal0.\n",
-                   card->index);
-            atomic_add(i,&vcc->stats->rx_drop);
-            break;
-         }
-         if (!atm_charge(vcc, sb->truesize))
-         {
-            RXPRINTK("nicstar%d: atm_charge() dropped aal0 packets.\n",
-                     card->index);
-            atomic_add(i-1,&vcc->stats->rx_drop); /* already increased by 1 */
-            dev_kfree_skb_any(sb);
-            break;
-         }
-         /* Rebuild the header */
-         *((u32 *) sb->data) = le32_to_cpu(rsqe->word_1) << 4 |
-                               (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000);
-         if (i == 1 && ns_rsqe_eopdu(rsqe))
-            *((u32 *) sb->data) |= 0x00000002;
-         skb_put(sb, NS_AAL0_HEADER);
-         memcpy(skb_tail_pointer(sb), cell, ATM_CELL_PAYLOAD);
-         skb_put(sb, ATM_CELL_PAYLOAD);
-         ATM_SKB(sb)->vcc = vcc;
-	 __net_timestamp(sb);
-         vcc->push(vcc, sb);
-         atomic_inc(&vcc->stats->rx);
-         cell += ATM_CELL_PAYLOAD;
-      }
+	if (vcc->qos.aal == ATM_AAL0) {
+		struct sk_buff *sb;
+		unsigned char *cell;
+		int i;
 
-      recycle_rx_buf(card, skb);
-      return;
-   }
+		cell = skb->data;
+		for (i = ns_rsqe_cellcount(rsqe); i; i--) {
+			if ((sb = dev_alloc_skb(NS_SMSKBSIZE)) == NULL) {
+				printk
+				    ("nicstar%d: Can't allocate buffers for aal0.\n",
+				     card->index);
+				atomic_add(i, &vcc->stats->rx_drop);
+				break;
+			}
+			if (!atm_charge(vcc, sb->truesize)) {
+				RXPRINTK
+				    ("nicstar%d: atm_charge() dropped aal0 packets.\n",
+				     card->index);
+				atomic_add(i - 1, &vcc->stats->rx_drop);	/* already increased by 1 */
+				dev_kfree_skb_any(sb);
+				break;
+			}
+			/* Rebuild the header */
+			*((u32 *) sb->data) = le32_to_cpu(rsqe->word_1) << 4 |
+			    (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000);
+			if (i == 1 && ns_rsqe_eopdu(rsqe))
+				*((u32 *) sb->data) |= 0x00000002;
+			skb_put(sb, NS_AAL0_HEADER);
+			memcpy(skb_tail_pointer(sb), cell, ATM_CELL_PAYLOAD);
+			skb_put(sb, ATM_CELL_PAYLOAD);
+			ATM_SKB(sb)->vcc = vcc;
+			__net_timestamp(sb);
+			vcc->push(vcc, sb);
+			atomic_inc(&vcc->stats->rx);
+			cell += ATM_CELL_PAYLOAD;
+		}
 
-   /* To reach this point, the AAL layer can only be AAL5 */
+		recycle_rx_buf(card, skb);
+		return;
+	}
 
-   if ((iovb = vc->rx_iov) == NULL)
-   {
-      iovb = skb_dequeue(&(card->iovpool.queue));
-      if (iovb == NULL)		/* No buffers in the queue */
-      {
-         iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC);
-	 if (iovb == NULL)
-	 {
-	    printk("nicstar%d: Out of iovec buffers.\n", card->index);
-            atomic_inc(&vcc->stats->rx_drop);
-            recycle_rx_buf(card, skb);
-            return;
-	 }
-         NS_SKB_CB(iovb)->buf_type = BUF_NONE;
-      }
-      else
-         if (--card->iovpool.count < card->iovnr.min)
-	 {
-	    struct sk_buff *new_iovb;
-	    if ((new_iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL)
-	    {
-               NS_SKB_CB(iovb)->buf_type = BUF_NONE;
-               skb_queue_tail(&card->iovpool.queue, new_iovb);
-               card->iovpool.count++;
-	    }
-	 }
-      vc->rx_iov = iovb;
-      NS_SKB(iovb)->iovcnt = 0;
-      iovb->len = 0;
-      iovb->data = iovb->head;
-      skb_reset_tail_pointer(iovb);
-      NS_SKB(iovb)->vcc = vcc;
-      /* IMPORTANT: a pointer to the sk_buff containing the small or large
-                    buffer is stored as iovec base, NOT a pointer to the 
-	            small or large buffer itself. */
-   }
-   else if (NS_SKB(iovb)->iovcnt >= NS_MAX_IOVECS)
-   {
-      printk("nicstar%d: received too big AAL5 SDU.\n", card->index);
-      atomic_inc(&vcc->stats->rx_err);
-      recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS);
-      NS_SKB(iovb)->iovcnt = 0;
-      iovb->len = 0;
-      iovb->data = iovb->head;
-      skb_reset_tail_pointer(iovb);
-      NS_SKB(iovb)->vcc = vcc;
-   }
-   iov = &((struct iovec *) iovb->data)[NS_SKB(iovb)->iovcnt++];
-   iov->iov_base = (void *) skb;
-   iov->iov_len = ns_rsqe_cellcount(rsqe) * 48;
-   iovb->len += iov->iov_len;
+	/* To reach this point, the AAL layer can only be AAL5 */
 
-   if (NS_SKB(iovb)->iovcnt == 1)
-   {
-      if (NS_SKB_CB(skb)->buf_type != BUF_SM)
-      {
-         printk("nicstar%d: Expected a small buffer, and this is not one.\n",
-	        card->index);
-         which_list(card, skb);
-         atomic_inc(&vcc->stats->rx_err);
-         recycle_rx_buf(card, skb);
-         vc->rx_iov = NULL;
-         recycle_iov_buf(card, iovb);
-         return;
-      }
-   }
-   else /* NS_SKB(iovb)->iovcnt >= 2 */
-   {
-      if (NS_SKB_CB(skb)->buf_type != BUF_LG)
-      {
-         printk("nicstar%d: Expected a large buffer, and this is not one.\n",
-	        card->index);
-         which_list(card, skb);
-         atomic_inc(&vcc->stats->rx_err);
-         recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-	                       NS_SKB(iovb)->iovcnt);
-         vc->rx_iov = NULL;
-         recycle_iov_buf(card, iovb);
-	 return;
-      }
-   }
+	if ((iovb = vc->rx_iov) == NULL) {
+		iovb = skb_dequeue(&(card->iovpool.queue));
+		if (iovb == NULL) {	/* No buffers in the queue */
+			iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC);
+			if (iovb == NULL) {
+				printk("nicstar%d: Out of iovec buffers.\n",
+				       card->index);
+				atomic_inc(&vcc->stats->rx_drop);
+				recycle_rx_buf(card, skb);
+				return;
+			}
+			NS_PRV_BUFTYPE(iovb) = BUF_NONE;
+		} else if (--card->iovpool.count < card->iovnr.min) {
+			struct sk_buff *new_iovb;
+			if ((new_iovb =
+			     alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL) {
+				NS_PRV_BUFTYPE(iovb) = BUF_NONE;
+				skb_queue_tail(&card->iovpool.queue, new_iovb);
+				card->iovpool.count++;
+			}
+		}
+		vc->rx_iov = iovb;
+		NS_PRV_IOVCNT(iovb) = 0;
+		iovb->len = 0;
+		iovb->data = iovb->head;
+		skb_reset_tail_pointer(iovb);
+		/* IMPORTANT: a pointer to the sk_buff containing the small or large
+		   buffer is stored as iovec base, NOT a pointer to the
+		   small or large buffer itself. */
+	} else if (NS_PRV_IOVCNT(iovb) >= NS_MAX_IOVECS) {
+		printk("nicstar%d: received too big AAL5 SDU.\n", card->index);
+		atomic_inc(&vcc->stats->rx_err);
+		recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data,
+				      NS_MAX_IOVECS);
+		NS_PRV_IOVCNT(iovb) = 0;
+		iovb->len = 0;
+		iovb->data = iovb->head;
+		skb_reset_tail_pointer(iovb);
+	}
+	iov = &((struct iovec *)iovb->data)[NS_PRV_IOVCNT(iovb)++];
+	iov->iov_base = (void *)skb;
+	iov->iov_len = ns_rsqe_cellcount(rsqe) * 48;
+	iovb->len += iov->iov_len;
 
-   if (ns_rsqe_eopdu(rsqe))
-   {
-      /* This works correctly regardless of the endianness of the host */
-      unsigned char *L1L2 = (unsigned char *)((u32)skb->data +
-                                              iov->iov_len - 6);
-      aal5_len = L1L2[0] << 8 | L1L2[1];
-      len = (aal5_len == 0x0000) ? 0x10000 : aal5_len;
-      if (ns_rsqe_crcerr(rsqe) ||
-          len + 8 > iovb->len || len + (47 + 8) < iovb->len)
-      {
-         printk("nicstar%d: AAL5 CRC error", card->index);
-         if (len + 8 > iovb->len || len + (47 + 8) < iovb->len)
-            printk(" - PDU size mismatch.\n");
-         else
-            printk(".\n");
-         atomic_inc(&vcc->stats->rx_err);
-         recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-	   NS_SKB(iovb)->iovcnt);
-	 vc->rx_iov = NULL;
-         recycle_iov_buf(card, iovb);
-	 return;
-      }
-
-      /* By this point we (hopefully) have a complete SDU without errors. */
-
-      if (NS_SKB(iovb)->iovcnt == 1)	/* Just a small buffer */
-      {
-         /* skb points to a small buffer */
-         if (!atm_charge(vcc, skb->truesize))
-         {
-            push_rxbufs(card, skb);
-            atomic_inc(&vcc->stats->rx_drop);
-         }
-         else
-	 {
-            skb_put(skb, len);
-            dequeue_sm_buf(card, skb);
-#ifdef NS_USE_DESTRUCTORS
-            skb->destructor = ns_sb_destructor;
-#endif /* NS_USE_DESTRUCTORS */
-            ATM_SKB(skb)->vcc = vcc;
-	    __net_timestamp(skb);
-            vcc->push(vcc, skb);
-            atomic_inc(&vcc->stats->rx);
-         }
-      }
-      else if (NS_SKB(iovb)->iovcnt == 2)	/* One small plus one large buffer */
-      {
-         struct sk_buff *sb;
-
-         sb = (struct sk_buff *) (iov - 1)->iov_base;
-         /* skb points to a large buffer */
-
-         if (len <= NS_SMBUFSIZE)
-	 {
-            if (!atm_charge(vcc, sb->truesize))
-            {
-               push_rxbufs(card, sb);
-               atomic_inc(&vcc->stats->rx_drop);
-            }
-            else
-	    {
-               skb_put(sb, len);
-               dequeue_sm_buf(card, sb);
-#ifdef NS_USE_DESTRUCTORS
-               sb->destructor = ns_sb_destructor;
-#endif /* NS_USE_DESTRUCTORS */
-               ATM_SKB(sb)->vcc = vcc;
-	       __net_timestamp(sb);
-               vcc->push(vcc, sb);
-               atomic_inc(&vcc->stats->rx);
-            }
-
-            push_rxbufs(card, skb);
-
-	 }
-	 else			/* len > NS_SMBUFSIZE, the usual case */
-	 {
-            if (!atm_charge(vcc, skb->truesize))
-            {
-               push_rxbufs(card, skb);
-               atomic_inc(&vcc->stats->rx_drop);
-            }
-            else
-            {
-               dequeue_lg_buf(card, skb);
-#ifdef NS_USE_DESTRUCTORS
-               skb->destructor = ns_lb_destructor;
-#endif /* NS_USE_DESTRUCTORS */
-               skb_push(skb, NS_SMBUFSIZE);
-               skb_copy_from_linear_data(sb, skb->data, NS_SMBUFSIZE);
-               skb_put(skb, len - NS_SMBUFSIZE);
-               ATM_SKB(skb)->vcc = vcc;
-	       __net_timestamp(skb);
-               vcc->push(vcc, skb);
-               atomic_inc(&vcc->stats->rx);
-            }
-
-            push_rxbufs(card, sb);
-
-         }
-	 
-      }
-      else				/* Must push a huge buffer */
-      {
-         struct sk_buff *hb, *sb, *lb;
-	 int remaining, tocopy;
-         int j;
-
-         hb = skb_dequeue(&(card->hbpool.queue));
-         if (hb == NULL)		/* No buffers in the queue */
-         {
-
-            hb = dev_alloc_skb(NS_HBUFSIZE);
-            if (hb == NULL)
-            {
-               printk("nicstar%d: Out of huge buffers.\n", card->index);
-               atomic_inc(&vcc->stats->rx_drop);
-               recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-	                             NS_SKB(iovb)->iovcnt);
-               vc->rx_iov = NULL;
-               recycle_iov_buf(card, iovb);
-               return;
-            }
-            else if (card->hbpool.count < card->hbnr.min)
-	    {
-               struct sk_buff *new_hb;
-               if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
-               {
-                  skb_queue_tail(&card->hbpool.queue, new_hb);
-                  card->hbpool.count++;
-               }
-            }
-            NS_SKB_CB(hb)->buf_type = BUF_NONE;
-	 }
-	 else
-         if (--card->hbpool.count < card->hbnr.min)
-         {
-            struct sk_buff *new_hb;
-            if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
-            {
-               NS_SKB_CB(new_hb)->buf_type = BUF_NONE;
-               skb_queue_tail(&card->hbpool.queue, new_hb);
-               card->hbpool.count++;
-            }
-            if (card->hbpool.count < card->hbnr.min)
-	    {
-               if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
-               {
-                  NS_SKB_CB(new_hb)->buf_type = BUF_NONE;
-                  skb_queue_tail(&card->hbpool.queue, new_hb);
-                  card->hbpool.count++;
-               }
-            }
-         }
-
-         iov = (struct iovec *) iovb->data;
-
-         if (!atm_charge(vcc, hb->truesize))
-	 {
-            recycle_iovec_rx_bufs(card, iov, NS_SKB(iovb)->iovcnt);
-            if (card->hbpool.count < card->hbnr.max)
-            {
-               skb_queue_tail(&card->hbpool.queue, hb);
-               card->hbpool.count++;
-            }
-	    else
-	       dev_kfree_skb_any(hb);
-	    atomic_inc(&vcc->stats->rx_drop);
-         }
-         else
-	 {
-            /* Copy the small buffer to the huge buffer */
-            sb = (struct sk_buff *) iov->iov_base;
-            skb_copy_from_linear_data(sb, hb->data, iov->iov_len);
-            skb_put(hb, iov->iov_len);
-            remaining = len - iov->iov_len;
-            iov++;
-            /* Free the small buffer */
-            push_rxbufs(card, sb);
-
-            /* Copy all large buffers to the huge buffer and free them */
-            for (j = 1; j < NS_SKB(iovb)->iovcnt; j++)
-            {
-               lb = (struct sk_buff *) iov->iov_base;
-               tocopy = min_t(int, remaining, iov->iov_len);
-               skb_copy_from_linear_data(lb, skb_tail_pointer(hb), tocopy);
-               skb_put(hb, tocopy);
-               iov++;
-               remaining -= tocopy;
-               push_rxbufs(card, lb);
-            }
 #ifdef EXTRA_DEBUG
-            if (remaining != 0 || hb->len != len)
-               printk("nicstar%d: Huge buffer len mismatch.\n", card->index);
-#endif /* EXTRA_DEBUG */
-            ATM_SKB(hb)->vcc = vcc;
-#ifdef NS_USE_DESTRUCTORS
-            hb->destructor = ns_hb_destructor;
-#endif /* NS_USE_DESTRUCTORS */
-	    __net_timestamp(hb);
-            vcc->push(vcc, hb);
-            atomic_inc(&vcc->stats->rx);
-         }
-      }
+	if (NS_PRV_IOVCNT(iovb) == 1) {
+		if (NS_PRV_BUFTYPE(skb) != BUF_SM) {
+			printk
+			    ("nicstar%d: Expected a small buffer, and this is not one.\n",
+			     card->index);
+			which_list(card, skb);
+			atomic_inc(&vcc->stats->rx_err);
+			recycle_rx_buf(card, skb);
+			vc->rx_iov = NULL;
+			recycle_iov_buf(card, iovb);
+			return;
+		}
+	} else {		/* NS_PRV_IOVCNT(iovb) >= 2 */
 
-      vc->rx_iov = NULL;
-      recycle_iov_buf(card, iovb);
-   }
+		if (NS_PRV_BUFTYPE(skb) != BUF_LG) {
+			printk
+			    ("nicstar%d: Expected a large buffer, and this is not one.\n",
+			     card->index);
+			which_list(card, skb);
+			atomic_inc(&vcc->stats->rx_err);
+			recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data,
+					      NS_PRV_IOVCNT(iovb));
+			vc->rx_iov = NULL;
+			recycle_iov_buf(card, iovb);
+			return;
+		}
+	}
+#endif /* EXTRA_DEBUG */
+
+	if (ns_rsqe_eopdu(rsqe)) {
+		/* This works correctly regardless of the endianness of the host */
+		unsigned char *L1L2 = (unsigned char *)
+						(skb->data + iov->iov_len - 6);
+		aal5_len = L1L2[0] << 8 | L1L2[1];
+		len = (aal5_len == 0x0000) ? 0x10000 : aal5_len;
+		if (ns_rsqe_crcerr(rsqe) ||
+		    len + 8 > iovb->len || len + (47 + 8) < iovb->len) {
+			printk("nicstar%d: AAL5 CRC error", card->index);
+			if (len + 8 > iovb->len || len + (47 + 8) < iovb->len)
+				printk(" - PDU size mismatch.\n");
+			else
+				printk(".\n");
+			atomic_inc(&vcc->stats->rx_err);
+			recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data,
+					      NS_PRV_IOVCNT(iovb));
+			vc->rx_iov = NULL;
+			recycle_iov_buf(card, iovb);
+			return;
+		}
+
+		/* By this point we (hopefully) have a complete SDU without errors. */
+
+		if (NS_PRV_IOVCNT(iovb) == 1) {	/* Just a small buffer */
+			/* skb points to a small buffer */
+			if (!atm_charge(vcc, skb->truesize)) {
+				push_rxbufs(card, skb);
+				atomic_inc(&vcc->stats->rx_drop);
+			} else {
+				skb_put(skb, len);
+				dequeue_sm_buf(card, skb);
+#ifdef NS_USE_DESTRUCTORS
+				skb->destructor = ns_sb_destructor;
+#endif /* NS_USE_DESTRUCTORS */
+				ATM_SKB(skb)->vcc = vcc;
+				__net_timestamp(skb);
+				vcc->push(vcc, skb);
+				atomic_inc(&vcc->stats->rx);
+			}
+		} else if (NS_PRV_IOVCNT(iovb) == 2) {	/* One small plus one large buffer */
+			struct sk_buff *sb;
+
+			sb = (struct sk_buff *)(iov - 1)->iov_base;
+			/* skb points to a large buffer */
+
+			if (len <= NS_SMBUFSIZE) {
+				if (!atm_charge(vcc, sb->truesize)) {
+					push_rxbufs(card, sb);
+					atomic_inc(&vcc->stats->rx_drop);
+				} else {
+					skb_put(sb, len);
+					dequeue_sm_buf(card, sb);
+#ifdef NS_USE_DESTRUCTORS
+					sb->destructor = ns_sb_destructor;
+#endif /* NS_USE_DESTRUCTORS */
+					ATM_SKB(sb)->vcc = vcc;
+					__net_timestamp(sb);
+					vcc->push(vcc, sb);
+					atomic_inc(&vcc->stats->rx);
+				}
+
+				push_rxbufs(card, skb);
+
+			} else {	/* len > NS_SMBUFSIZE, the usual case */
+
+				if (!atm_charge(vcc, skb->truesize)) {
+					push_rxbufs(card, skb);
+					atomic_inc(&vcc->stats->rx_drop);
+				} else {
+					dequeue_lg_buf(card, skb);
+#ifdef NS_USE_DESTRUCTORS
+					skb->destructor = ns_lb_destructor;
+#endif /* NS_USE_DESTRUCTORS */
+					skb_push(skb, NS_SMBUFSIZE);
+					skb_copy_from_linear_data(sb, skb->data,
+								  NS_SMBUFSIZE);
+					skb_put(skb, len - NS_SMBUFSIZE);
+					ATM_SKB(skb)->vcc = vcc;
+					__net_timestamp(skb);
+					vcc->push(vcc, skb);
+					atomic_inc(&vcc->stats->rx);
+				}
+
+				push_rxbufs(card, sb);
+
+			}
+
+		} else {	/* Must push a huge buffer */
+
+			struct sk_buff *hb, *sb, *lb;
+			int remaining, tocopy;
+			int j;
+
+			hb = skb_dequeue(&(card->hbpool.queue));
+			if (hb == NULL) {	/* No buffers in the queue */
+
+				hb = dev_alloc_skb(NS_HBUFSIZE);
+				if (hb == NULL) {
+					printk
+					    ("nicstar%d: Out of huge buffers.\n",
+					     card->index);
+					atomic_inc(&vcc->stats->rx_drop);
+					recycle_iovec_rx_bufs(card,
+							      (struct iovec *)
+							      iovb->data,
+							      NS_PRV_IOVCNT(iovb));
+					vc->rx_iov = NULL;
+					recycle_iov_buf(card, iovb);
+					return;
+				} else if (card->hbpool.count < card->hbnr.min) {
+					struct sk_buff *new_hb;
+					if ((new_hb =
+					     dev_alloc_skb(NS_HBUFSIZE)) !=
+					    NULL) {
+						skb_queue_tail(&card->hbpool.
+							       queue, new_hb);
+						card->hbpool.count++;
+					}
+				}
+				NS_PRV_BUFTYPE(hb) = BUF_NONE;
+			} else if (--card->hbpool.count < card->hbnr.min) {
+				struct sk_buff *new_hb;
+				if ((new_hb =
+				     dev_alloc_skb(NS_HBUFSIZE)) != NULL) {
+					NS_PRV_BUFTYPE(new_hb) = BUF_NONE;
+					skb_queue_tail(&card->hbpool.queue,
+						       new_hb);
+					card->hbpool.count++;
+				}
+				if (card->hbpool.count < card->hbnr.min) {
+					if ((new_hb =
+					     dev_alloc_skb(NS_HBUFSIZE)) !=
+					    NULL) {
+						NS_PRV_BUFTYPE(new_hb) =
+						    BUF_NONE;
+						skb_queue_tail(&card->hbpool.
+							       queue, new_hb);
+						card->hbpool.count++;
+					}
+				}
+			}
+
+			iov = (struct iovec *)iovb->data;
+
+			if (!atm_charge(vcc, hb->truesize)) {
+				recycle_iovec_rx_bufs(card, iov,
+						      NS_PRV_IOVCNT(iovb));
+				if (card->hbpool.count < card->hbnr.max) {
+					skb_queue_tail(&card->hbpool.queue, hb);
+					card->hbpool.count++;
+				} else
+					dev_kfree_skb_any(hb);
+				atomic_inc(&vcc->stats->rx_drop);
+			} else {
+				/* Copy the small buffer to the huge buffer */
+				sb = (struct sk_buff *)iov->iov_base;
+				skb_copy_from_linear_data(sb, hb->data,
+							  iov->iov_len);
+				skb_put(hb, iov->iov_len);
+				remaining = len - iov->iov_len;
+				iov++;
+				/* Free the small buffer */
+				push_rxbufs(card, sb);
+
+				/* Copy all large buffers to the huge buffer and free them */
+				for (j = 1; j < NS_PRV_IOVCNT(iovb); j++) {
+					lb = (struct sk_buff *)iov->iov_base;
+					tocopy =
+					    min_t(int, remaining, iov->iov_len);
+					skb_copy_from_linear_data(lb,
+								  skb_tail_pointer
+								  (hb), tocopy);
+					skb_put(hb, tocopy);
+					iov++;
+					remaining -= tocopy;
+					push_rxbufs(card, lb);
+				}
+#ifdef EXTRA_DEBUG
+				if (remaining != 0 || hb->len != len)
+					printk
+					    ("nicstar%d: Huge buffer len mismatch.\n",
+					     card->index);
+#endif /* EXTRA_DEBUG */
+				ATM_SKB(hb)->vcc = vcc;
+#ifdef NS_USE_DESTRUCTORS
+				hb->destructor = ns_hb_destructor;
+#endif /* NS_USE_DESTRUCTORS */
+				__net_timestamp(hb);
+				vcc->push(vcc, hb);
+				atomic_inc(&vcc->stats->rx);
+			}
+		}
+
+		vc->rx_iov = NULL;
+		recycle_iov_buf(card, iovb);
+	}
 
 }
 
-
-
 #ifdef NS_USE_DESTRUCTORS
 
 static void ns_sb_destructor(struct sk_buff *sb)
 {
-   ns_dev *card;
-   u32 stat;
+	ns_dev *card;
+	u32 stat;
 
-   card = (ns_dev *) ATM_SKB(sb)->vcc->dev->dev_data;
-   stat = readl(card->membase + STAT);
-   card->sbfqc = ns_stat_sfbqc_get(stat);   
-   card->lbfqc = ns_stat_lfbqc_get(stat);
+	card = (ns_dev *) ATM_SKB(sb)->vcc->dev->dev_data;
+	stat = readl(card->membase + STAT);
+	card->sbfqc = ns_stat_sfbqc_get(stat);
+	card->lbfqc = ns_stat_lfbqc_get(stat);
 
-   do
-   {
-      sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
-      if (sb == NULL)
-         break;
-      NS_SKB_CB(sb)->buf_type = BUF_SM;
-      skb_queue_tail(&card->sbpool.queue, sb);
-      skb_reserve(sb, NS_AAL0_HEADER);
-      push_rxbufs(card, sb);
-   } while (card->sbfqc < card->sbnr.min);
+	do {
+		sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
+		if (sb == NULL)
+			break;
+		NS_PRV_BUFTYPE(sb) = BUF_SM;
+		skb_queue_tail(&card->sbpool.queue, sb);
+		skb_reserve(sb, NS_AAL0_HEADER);
+		push_rxbufs(card, sb);
+	} while (card->sbfqc < card->sbnr.min);
 }
 
-
-
 static void ns_lb_destructor(struct sk_buff *lb)
 {
-   ns_dev *card;
-   u32 stat;
+	ns_dev *card;
+	u32 stat;
 
-   card = (ns_dev *) ATM_SKB(lb)->vcc->dev->dev_data;
-   stat = readl(card->membase + STAT);
-   card->sbfqc = ns_stat_sfbqc_get(stat);   
-   card->lbfqc = ns_stat_lfbqc_get(stat);
+	card = (ns_dev *) ATM_SKB(lb)->vcc->dev->dev_data;
+	stat = readl(card->membase + STAT);
+	card->sbfqc = ns_stat_sfbqc_get(stat);
+	card->lbfqc = ns_stat_lfbqc_get(stat);
 
-   do
-   {
-      lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
-      if (lb == NULL)
-         break;
-      NS_SKB_CB(lb)->buf_type = BUF_LG;
-      skb_queue_tail(&card->lbpool.queue, lb);
-      skb_reserve(lb, NS_SMBUFSIZE);
-      push_rxbufs(card, lb);
-   } while (card->lbfqc < card->lbnr.min);
+	do {
+		lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
+		if (lb == NULL)
+			break;
+		NS_PRV_BUFTYPE(lb) = BUF_LG;
+		skb_queue_tail(&card->lbpool.queue, lb);
+		skb_reserve(lb, NS_SMBUFSIZE);
+		push_rxbufs(card, lb);
+	} while (card->lbfqc < card->lbnr.min);
 }
 
-
-
 static void ns_hb_destructor(struct sk_buff *hb)
 {
-   ns_dev *card;
+	ns_dev *card;
 
-   card = (ns_dev *) ATM_SKB(hb)->vcc->dev->dev_data;
+	card = (ns_dev *) ATM_SKB(hb)->vcc->dev->dev_data;
 
-   while (card->hbpool.count < card->hbnr.init)
-   {
-      hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
-      if (hb == NULL)
-         break;
-      NS_SKB_CB(hb)->buf_type = BUF_NONE;
-      skb_queue_tail(&card->hbpool.queue, hb);
-      card->hbpool.count++;
-   }
+	while (card->hbpool.count < card->hbnr.init) {
+		hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
+		if (hb == NULL)
+			break;
+		NS_PRV_BUFTYPE(hb) = BUF_NONE;
+		skb_queue_tail(&card->hbpool.queue, hb);
+		card->hbpool.count++;
+	}
 }
 
 #endif /* NS_USE_DESTRUCTORS */
 
-
-static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb)
+static void recycle_rx_buf(ns_dev * card, struct sk_buff *skb)
 {
-	struct ns_skb_cb *cb = NS_SKB_CB(skb);
-
-	if (unlikely(cb->buf_type == BUF_NONE)) {
-		printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
+	if (unlikely(NS_PRV_BUFTYPE(skb) == BUF_NONE)) {
+		printk("nicstar%d: What kind of rx buffer is this?\n",
+		       card->index);
 		dev_kfree_skb_any(skb);
 	} else
 		push_rxbufs(card, skb);
 }
 
-
-static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count)
+static void recycle_iovec_rx_bufs(ns_dev * card, struct iovec *iov, int count)
 {
 	while (count-- > 0)
-		recycle_rx_buf(card, (struct sk_buff *) (iov++)->iov_base);
+		recycle_rx_buf(card, (struct sk_buff *)(iov++)->iov_base);
 }
 
-
-static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb)
+static void recycle_iov_buf(ns_dev * card, struct sk_buff *iovb)
 {
-   if (card->iovpool.count < card->iovnr.max)
-   {
-      skb_queue_tail(&card->iovpool.queue, iovb);
-      card->iovpool.count++;
-   }
-   else
-      dev_kfree_skb_any(iovb);
+	if (card->iovpool.count < card->iovnr.max) {
+		skb_queue_tail(&card->iovpool.queue, iovb);
+		card->iovpool.count++;
+	} else
+		dev_kfree_skb_any(iovb);
 }
 
-
-
-static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb)
+static void dequeue_sm_buf(ns_dev * card, struct sk_buff *sb)
 {
-   skb_unlink(sb, &card->sbpool.queue);
+	skb_unlink(sb, &card->sbpool.queue);
 #ifdef NS_USE_DESTRUCTORS
-   if (card->sbfqc < card->sbnr.min)
+	if (card->sbfqc < card->sbnr.min)
 #else
-   if (card->sbfqc < card->sbnr.init)
-   {
-      struct sk_buff *new_sb;
-      if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL)
-      {
-         NS_SKB_CB(new_sb)->buf_type = BUF_SM;
-         skb_queue_tail(&card->sbpool.queue, new_sb);
-         skb_reserve(new_sb, NS_AAL0_HEADER);
-         push_rxbufs(card, new_sb);
-      }
-   }
-   if (card->sbfqc < card->sbnr.init)
+	if (card->sbfqc < card->sbnr.init) {
+		struct sk_buff *new_sb;
+		if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) {
+			NS_PRV_BUFTYPE(new_sb) = BUF_SM;
+			skb_queue_tail(&card->sbpool.queue, new_sb);
+			skb_reserve(new_sb, NS_AAL0_HEADER);
+			push_rxbufs(card, new_sb);
+		}
+	}
+	if (card->sbfqc < card->sbnr.init)
 #endif /* NS_USE_DESTRUCTORS */
-   {
-      struct sk_buff *new_sb;
-      if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL)
-      {
-         NS_SKB_CB(new_sb)->buf_type = BUF_SM;
-         skb_queue_tail(&card->sbpool.queue, new_sb);
-         skb_reserve(new_sb, NS_AAL0_HEADER);
-         push_rxbufs(card, new_sb);
-      }
-   }
+	{
+		struct sk_buff *new_sb;
+		if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) {
+			NS_PRV_BUFTYPE(new_sb) = BUF_SM;
+			skb_queue_tail(&card->sbpool.queue, new_sb);
+			skb_reserve(new_sb, NS_AAL0_HEADER);
+			push_rxbufs(card, new_sb);
+		}
+	}
 }
 
-
-
-static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb)
+static void dequeue_lg_buf(ns_dev * card, struct sk_buff *lb)
 {
-   skb_unlink(lb, &card->lbpool.queue);
+	skb_unlink(lb, &card->lbpool.queue);
 #ifdef NS_USE_DESTRUCTORS
-   if (card->lbfqc < card->lbnr.min)
+	if (card->lbfqc < card->lbnr.min)
 #else
-   if (card->lbfqc < card->lbnr.init)
-   {
-      struct sk_buff *new_lb;
-      if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL)
-      {
-         NS_SKB_CB(new_lb)->buf_type = BUF_LG;
-         skb_queue_tail(&card->lbpool.queue, new_lb);
-         skb_reserve(new_lb, NS_SMBUFSIZE);
-         push_rxbufs(card, new_lb);
-      }
-   }
-   if (card->lbfqc < card->lbnr.init)
+	if (card->lbfqc < card->lbnr.init) {
+		struct sk_buff *new_lb;
+		if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) {
+			NS_PRV_BUFTYPE(new_lb) = BUF_LG;
+			skb_queue_tail(&card->lbpool.queue, new_lb);
+			skb_reserve(new_lb, NS_SMBUFSIZE);
+			push_rxbufs(card, new_lb);
+		}
+	}
+	if (card->lbfqc < card->lbnr.init)
 #endif /* NS_USE_DESTRUCTORS */
-   {
-      struct sk_buff *new_lb;
-      if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL)
-      {
-         NS_SKB_CB(new_lb)->buf_type = BUF_LG;
-         skb_queue_tail(&card->lbpool.queue, new_lb);
-         skb_reserve(new_lb, NS_SMBUFSIZE);
-         push_rxbufs(card, new_lb);
-      }
-   }
+	{
+		struct sk_buff *new_lb;
+		if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) {
+			NS_PRV_BUFTYPE(new_lb) = BUF_LG;
+			skb_queue_tail(&card->lbpool.queue, new_lb);
+			skb_reserve(new_lb, NS_SMBUFSIZE);
+			push_rxbufs(card, new_lb);
+		}
+	}
 }
 
-
-
-static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page)
+static int ns_proc_read(struct atm_dev *dev, loff_t * pos, char *page)
 {
-   u32 stat;
-   ns_dev *card;
-   int left;
+	u32 stat;
+	ns_dev *card;
+	int left;
 
-   left = (int) *pos;
-   card = (ns_dev *) dev->dev_data;
-   stat = readl(card->membase + STAT);
-   if (!left--)
-      return sprintf(page, "Pool   count    min   init    max \n");
-   if (!left--)
-      return sprintf(page, "Small  %5d  %5d  %5d  %5d \n",
-                     ns_stat_sfbqc_get(stat), card->sbnr.min, card->sbnr.init,
-		     card->sbnr.max);
-   if (!left--)
-      return sprintf(page, "Large  %5d  %5d  %5d  %5d \n",
-                     ns_stat_lfbqc_get(stat), card->lbnr.min, card->lbnr.init,
-		     card->lbnr.max);
-   if (!left--)
-      return sprintf(page, "Huge   %5d  %5d  %5d  %5d \n", card->hbpool.count,
-                     card->hbnr.min, card->hbnr.init, card->hbnr.max);
-   if (!left--)
-      return sprintf(page, "Iovec  %5d  %5d  %5d  %5d \n", card->iovpool.count,
-                     card->iovnr.min, card->iovnr.init, card->iovnr.max);
-   if (!left--)
-   {
-      int retval;
-      retval = sprintf(page, "Interrupt counter: %u \n", card->intcnt);
-      card->intcnt = 0;
-      return retval;
-   }
+	left = (int)*pos;
+	card = (ns_dev *) dev->dev_data;
+	stat = readl(card->membase + STAT);
+	if (!left--)
+		return sprintf(page, "Pool   count    min   init    max \n");
+	if (!left--)
+		return sprintf(page, "Small  %5d  %5d  %5d  %5d \n",
+			       ns_stat_sfbqc_get(stat), card->sbnr.min,
+			       card->sbnr.init, card->sbnr.max);
+	if (!left--)
+		return sprintf(page, "Large  %5d  %5d  %5d  %5d \n",
+			       ns_stat_lfbqc_get(stat), card->lbnr.min,
+			       card->lbnr.init, card->lbnr.max);
+	if (!left--)
+		return sprintf(page, "Huge   %5d  %5d  %5d  %5d \n",
+			       card->hbpool.count, card->hbnr.min,
+			       card->hbnr.init, card->hbnr.max);
+	if (!left--)
+		return sprintf(page, "Iovec  %5d  %5d  %5d  %5d \n",
+			       card->iovpool.count, card->iovnr.min,
+			       card->iovnr.init, card->iovnr.max);
+	if (!left--) {
+		int retval;
+		retval =
+		    sprintf(page, "Interrupt counter: %u \n", card->intcnt);
+		card->intcnt = 0;
+		return retval;
+	}
 #if 0
-   /* Dump 25.6 Mbps PHY registers */
-   /* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it
-      here just in case it's needed for debugging. */
-   if (card->max_pcr == ATM_25_PCR && !left--)
-   {
-      u32 phy_regs[4];
-      u32 i;
+	/* Dump 25.6 Mbps PHY registers */
+	/* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it
+	   here just in case it's needed for debugging. */
+	if (card->max_pcr == ATM_25_PCR && !left--) {
+		u32 phy_regs[4];
+		u32 i;
 
-      for (i = 0; i < 4; i++)
-      {
-         while (CMD_BUSY(card));
-         writel(NS_CMD_READ_UTILITY | 0x00000200 | i, card->membase + CMD);
-         while (CMD_BUSY(card));
-         phy_regs[i] = readl(card->membase + DR0) & 0x000000FF;
-      }
+		for (i = 0; i < 4; i++) {
+			while (CMD_BUSY(card)) ;
+			writel(NS_CMD_READ_UTILITY | 0x00000200 | i,
+			       card->membase + CMD);
+			while (CMD_BUSY(card)) ;
+			phy_regs[i] = readl(card->membase + DR0) & 0x000000FF;
+		}
 
-      return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n",
-                     phy_regs[0], phy_regs[1], phy_regs[2], phy_regs[3]);
-   }
+		return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n",
+			       phy_regs[0], phy_regs[1], phy_regs[2],
+			       phy_regs[3]);
+	}
 #endif /* 0 - Dump 25.6 Mbps PHY registers */
 #if 0
-   /* Dump TST */
-   if (left-- < NS_TST_NUM_ENTRIES)
-   {
-      if (card->tste2vc[left + 1] == NULL)
-         return sprintf(page, "%5d - VBR/UBR \n", left + 1);
-      else
-         return sprintf(page, "%5d - %d %d \n", left + 1,
-                        card->tste2vc[left + 1]->tx_vcc->vpi,
-                        card->tste2vc[left + 1]->tx_vcc->vci);
-   }
+	/* Dump TST */
+	if (left-- < NS_TST_NUM_ENTRIES) {
+		if (card->tste2vc[left + 1] == NULL)
+			return sprintf(page, "%5d - VBR/UBR \n", left + 1);
+		else
+			return sprintf(page, "%5d - %d %d \n", left + 1,
+				       card->tste2vc[left + 1]->tx_vcc->vpi,
+				       card->tste2vc[left + 1]->tx_vcc->vci);
+	}
 #endif /* 0 */
-   return 0;
+	return 0;
 }
 
-
-
-static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg)
+static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg)
 {
-   ns_dev *card;
-   pool_levels pl;
-   long btype;
-   unsigned long flags;
+	ns_dev *card;
+	pool_levels pl;
+	long btype;
+	unsigned long flags;
 
-   card = dev->dev_data;
-   switch (cmd)
-   {
-      case NS_GETPSTAT:
-         if (get_user(pl.buftype, &((pool_levels __user *) arg)->buftype))
-	    return -EFAULT;
-         switch (pl.buftype)
-	 {
-	    case NS_BUFTYPE_SMALL:
-	       pl.count = ns_stat_sfbqc_get(readl(card->membase + STAT));
-	       pl.level.min = card->sbnr.min;
-	       pl.level.init = card->sbnr.init;
-	       pl.level.max = card->sbnr.max;
-	       break;
+	card = dev->dev_data;
+	switch (cmd) {
+	case NS_GETPSTAT:
+		if (get_user
+		    (pl.buftype, &((pool_levels __user *) arg)->buftype))
+			return -EFAULT;
+		switch (pl.buftype) {
+		case NS_BUFTYPE_SMALL:
+			pl.count =
+			    ns_stat_sfbqc_get(readl(card->membase + STAT));
+			pl.level.min = card->sbnr.min;
+			pl.level.init = card->sbnr.init;
+			pl.level.max = card->sbnr.max;
+			break;
 
-	    case NS_BUFTYPE_LARGE:
-	       pl.count = ns_stat_lfbqc_get(readl(card->membase + STAT));
-	       pl.level.min = card->lbnr.min;
-	       pl.level.init = card->lbnr.init;
-	       pl.level.max = card->lbnr.max;
-	       break;
+		case NS_BUFTYPE_LARGE:
+			pl.count =
+			    ns_stat_lfbqc_get(readl(card->membase + STAT));
+			pl.level.min = card->lbnr.min;
+			pl.level.init = card->lbnr.init;
+			pl.level.max = card->lbnr.max;
+			break;
 
-	    case NS_BUFTYPE_HUGE:
-	       pl.count = card->hbpool.count;
-	       pl.level.min = card->hbnr.min;
-	       pl.level.init = card->hbnr.init;
-	       pl.level.max = card->hbnr.max;
-	       break;
+		case NS_BUFTYPE_HUGE:
+			pl.count = card->hbpool.count;
+			pl.level.min = card->hbnr.min;
+			pl.level.init = card->hbnr.init;
+			pl.level.max = card->hbnr.max;
+			break;
 
-	    case NS_BUFTYPE_IOVEC:
-	       pl.count = card->iovpool.count;
-	       pl.level.min = card->iovnr.min;
-	       pl.level.init = card->iovnr.init;
-	       pl.level.max = card->iovnr.max;
-	       break;
+		case NS_BUFTYPE_IOVEC:
+			pl.count = card->iovpool.count;
+			pl.level.min = card->iovnr.min;
+			pl.level.init = card->iovnr.init;
+			pl.level.max = card->iovnr.max;
+			break;
 
-            default:
-	       return -ENOIOCTLCMD;
+		default:
+			return -ENOIOCTLCMD;
 
-	 }
-         if (!copy_to_user((pool_levels __user *) arg, &pl, sizeof(pl)))
-	    return (sizeof(pl));
-	 else
-	    return -EFAULT;
+		}
+		if (!copy_to_user((pool_levels __user *) arg, &pl, sizeof(pl)))
+			return (sizeof(pl));
+		else
+			return -EFAULT;
 
-      case NS_SETBUFLEV:
-         if (!capable(CAP_NET_ADMIN))
-	    return -EPERM;
-         if (copy_from_user(&pl, (pool_levels __user *) arg, sizeof(pl)))
-	    return -EFAULT;
-	 if (pl.level.min >= pl.level.init || pl.level.init >= pl.level.max)
-	    return -EINVAL;
-	 if (pl.level.min == 0)
-	    return -EINVAL;
-         switch (pl.buftype)
-	 {
-	    case NS_BUFTYPE_SMALL:
-               if (pl.level.max > TOP_SB)
-	          return -EINVAL;
-	       card->sbnr.min = pl.level.min;
-	       card->sbnr.init = pl.level.init;
-	       card->sbnr.max = pl.level.max;
-	       break;
+	case NS_SETBUFLEV:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (copy_from_user(&pl, (pool_levels __user *) arg, sizeof(pl)))
+			return -EFAULT;
+		if (pl.level.min >= pl.level.init
+		    || pl.level.init >= pl.level.max)
+			return -EINVAL;
+		if (pl.level.min == 0)
+			return -EINVAL;
+		switch (pl.buftype) {
+		case NS_BUFTYPE_SMALL:
+			if (pl.level.max > TOP_SB)
+				return -EINVAL;
+			card->sbnr.min = pl.level.min;
+			card->sbnr.init = pl.level.init;
+			card->sbnr.max = pl.level.max;
+			break;
 
-	    case NS_BUFTYPE_LARGE:
-               if (pl.level.max > TOP_LB)
-	          return -EINVAL;
-	       card->lbnr.min = pl.level.min;
-	       card->lbnr.init = pl.level.init;
-	       card->lbnr.max = pl.level.max;
-	       break;
+		case NS_BUFTYPE_LARGE:
+			if (pl.level.max > TOP_LB)
+				return -EINVAL;
+			card->lbnr.min = pl.level.min;
+			card->lbnr.init = pl.level.init;
+			card->lbnr.max = pl.level.max;
+			break;
 
-	    case NS_BUFTYPE_HUGE:
-               if (pl.level.max > TOP_HB)
-	          return -EINVAL;
-	       card->hbnr.min = pl.level.min;
-	       card->hbnr.init = pl.level.init;
-	       card->hbnr.max = pl.level.max;
-	       break;
+		case NS_BUFTYPE_HUGE:
+			if (pl.level.max > TOP_HB)
+				return -EINVAL;
+			card->hbnr.min = pl.level.min;
+			card->hbnr.init = pl.level.init;
+			card->hbnr.max = pl.level.max;
+			break;
 
-	    case NS_BUFTYPE_IOVEC:
-               if (pl.level.max > TOP_IOVB)
-	          return -EINVAL;
-	       card->iovnr.min = pl.level.min;
-	       card->iovnr.init = pl.level.init;
-	       card->iovnr.max = pl.level.max;
-	       break;
+		case NS_BUFTYPE_IOVEC:
+			if (pl.level.max > TOP_IOVB)
+				return -EINVAL;
+			card->iovnr.min = pl.level.min;
+			card->iovnr.init = pl.level.init;
+			card->iovnr.max = pl.level.max;
+			break;
 
-            default:
-	       return -EINVAL;
+		default:
+			return -EINVAL;
 
-         }	 
-         return 0;
+		}
+		return 0;
 
-      case NS_ADJBUFLEV:
-         if (!capable(CAP_NET_ADMIN))
-	    return -EPERM;
-         btype = (long) arg;	/* a long is the same size as a pointer or bigger */
-         switch (btype)
-	 {
-	    case NS_BUFTYPE_SMALL:
-	       while (card->sbfqc < card->sbnr.init)
-	       {
-                  struct sk_buff *sb;
+	case NS_ADJBUFLEV:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		btype = (long)arg;	/* a long is the same size as a pointer or bigger */
+		switch (btype) {
+		case NS_BUFTYPE_SMALL:
+			while (card->sbfqc < card->sbnr.init) {
+				struct sk_buff *sb;
 
-                  sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
-                  if (sb == NULL)
-                     return -ENOMEM;
-                  NS_SKB_CB(sb)->buf_type = BUF_SM;
-                  skb_queue_tail(&card->sbpool.queue, sb);
-                  skb_reserve(sb, NS_AAL0_HEADER);
-                  push_rxbufs(card, sb);
-	       }
-	       break;
+				sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
+				if (sb == NULL)
+					return -ENOMEM;
+				NS_PRV_BUFTYPE(sb) = BUF_SM;
+				skb_queue_tail(&card->sbpool.queue, sb);
+				skb_reserve(sb, NS_AAL0_HEADER);
+				push_rxbufs(card, sb);
+			}
+			break;
 
-            case NS_BUFTYPE_LARGE:
-	       while (card->lbfqc < card->lbnr.init)
-	       {
-                  struct sk_buff *lb;
+		case NS_BUFTYPE_LARGE:
+			while (card->lbfqc < card->lbnr.init) {
+				struct sk_buff *lb;
 
-                  lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
-                  if (lb == NULL)
-                     return -ENOMEM;
-                  NS_SKB_CB(lb)->buf_type = BUF_LG;
-                  skb_queue_tail(&card->lbpool.queue, lb);
-                  skb_reserve(lb, NS_SMBUFSIZE);
-                  push_rxbufs(card, lb);
-	       }
-	       break;
+				lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
+				if (lb == NULL)
+					return -ENOMEM;
+				NS_PRV_BUFTYPE(lb) = BUF_LG;
+				skb_queue_tail(&card->lbpool.queue, lb);
+				skb_reserve(lb, NS_SMBUFSIZE);
+				push_rxbufs(card, lb);
+			}
+			break;
 
-            case NS_BUFTYPE_HUGE:
-               while (card->hbpool.count > card->hbnr.init)
-	       {
-                  struct sk_buff *hb;
+		case NS_BUFTYPE_HUGE:
+			while (card->hbpool.count > card->hbnr.init) {
+				struct sk_buff *hb;
 
-                  spin_lock_irqsave(&card->int_lock, flags);
-		  hb = skb_dequeue(&card->hbpool.queue);
-		  card->hbpool.count--;
-                  spin_unlock_irqrestore(&card->int_lock, flags);
-                  if (hb == NULL)
-		     printk("nicstar%d: huge buffer count inconsistent.\n",
-		            card->index);
-                  else
-		     dev_kfree_skb_any(hb);
-		  
-	       }
-               while (card->hbpool.count < card->hbnr.init)
-               {
-                  struct sk_buff *hb;
+				spin_lock_irqsave(&card->int_lock, flags);
+				hb = skb_dequeue(&card->hbpool.queue);
+				card->hbpool.count--;
+				spin_unlock_irqrestore(&card->int_lock, flags);
+				if (hb == NULL)
+					printk
+					    ("nicstar%d: huge buffer count inconsistent.\n",
+					     card->index);
+				else
+					dev_kfree_skb_any(hb);
 
-                  hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
-                  if (hb == NULL)
-                     return -ENOMEM;
-                  NS_SKB_CB(hb)->buf_type = BUF_NONE;
-                  spin_lock_irqsave(&card->int_lock, flags);
-                  skb_queue_tail(&card->hbpool.queue, hb);
-                  card->hbpool.count++;
-                  spin_unlock_irqrestore(&card->int_lock, flags);
-               }
-	       break;
+			}
+			while (card->hbpool.count < card->hbnr.init) {
+				struct sk_buff *hb;
 
-            case NS_BUFTYPE_IOVEC:
-	       while (card->iovpool.count > card->iovnr.init)
-	       {
-	          struct sk_buff *iovb;
+				hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
+				if (hb == NULL)
+					return -ENOMEM;
+				NS_PRV_BUFTYPE(hb) = BUF_NONE;
+				spin_lock_irqsave(&card->int_lock, flags);
+				skb_queue_tail(&card->hbpool.queue, hb);
+				card->hbpool.count++;
+				spin_unlock_irqrestore(&card->int_lock, flags);
+			}
+			break;
 
-                  spin_lock_irqsave(&card->int_lock, flags);
-		  iovb = skb_dequeue(&card->iovpool.queue);
-		  card->iovpool.count--;
-                  spin_unlock_irqrestore(&card->int_lock, flags);
-                  if (iovb == NULL)
-		     printk("nicstar%d: iovec buffer count inconsistent.\n",
-		            card->index);
-                  else
-		     dev_kfree_skb_any(iovb);
+		case NS_BUFTYPE_IOVEC:
+			while (card->iovpool.count > card->iovnr.init) {
+				struct sk_buff *iovb;
 
-	       }
-               while (card->iovpool.count < card->iovnr.init)
-	       {
-	          struct sk_buff *iovb;
+				spin_lock_irqsave(&card->int_lock, flags);
+				iovb = skb_dequeue(&card->iovpool.queue);
+				card->iovpool.count--;
+				spin_unlock_irqrestore(&card->int_lock, flags);
+				if (iovb == NULL)
+					printk
+					    ("nicstar%d: iovec buffer count inconsistent.\n",
+					     card->index);
+				else
+					dev_kfree_skb_any(iovb);
 
-                  iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
-                  if (iovb == NULL)
-                     return -ENOMEM;
-                  NS_SKB_CB(iovb)->buf_type = BUF_NONE;
-                  spin_lock_irqsave(&card->int_lock, flags);
-                  skb_queue_tail(&card->iovpool.queue, iovb);
-                  card->iovpool.count++;
-                  spin_unlock_irqrestore(&card->int_lock, flags);
-	       }
-	       break;
+			}
+			while (card->iovpool.count < card->iovnr.init) {
+				struct sk_buff *iovb;
 
-            default:
-	       return -EINVAL;
+				iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
+				if (iovb == NULL)
+					return -ENOMEM;
+				NS_PRV_BUFTYPE(iovb) = BUF_NONE;
+				spin_lock_irqsave(&card->int_lock, flags);
+				skb_queue_tail(&card->iovpool.queue, iovb);
+				card->iovpool.count++;
+				spin_unlock_irqrestore(&card->int_lock, flags);
+			}
+			break;
 
-	 }
-         return 0;
+		default:
+			return -EINVAL;
 
-      default:
-         if (dev->phy && dev->phy->ioctl) {
-            return dev->phy->ioctl(dev, cmd, arg);
-         }
-         else {
-            printk("nicstar%d: %s == NULL \n", card->index,
-                   dev->phy ? "dev->phy->ioctl" : "dev->phy");
-            return -ENOIOCTLCMD;
-         }
-   }
+		}
+		return 0;
+
+	default:
+		if (dev->phy && dev->phy->ioctl) {
+			return dev->phy->ioctl(dev, cmd, arg);
+		} else {
+			printk("nicstar%d: %s == NULL \n", card->index,
+			       dev->phy ? "dev->phy->ioctl" : "dev->phy");
+			return -ENOIOCTLCMD;
+		}
+	}
 }
 
-
-static void which_list(ns_dev *card, struct sk_buff *skb)
+#ifdef EXTRA_DEBUG
+static void which_list(ns_dev * card, struct sk_buff *skb)
 {
-	printk("skb buf_type: 0x%08x\n", NS_SKB_CB(skb)->buf_type);
+	printk("skb buf_type: 0x%08x\n", NS_PRV_BUFTYPE(skb));
 }
-
+#endif /* EXTRA_DEBUG */
 
 static void ns_poll(unsigned long arg)
 {
-   int i;
-   ns_dev *card;
-   unsigned long flags;
-   u32 stat_r, stat_w;
+	int i;
+	ns_dev *card;
+	unsigned long flags;
+	u32 stat_r, stat_w;
 
-   PRINTK("nicstar: Entering ns_poll().\n");
-   for (i = 0; i < num_cards; i++)
-   {
-      card = cards[i];
-      if (spin_is_locked(&card->int_lock)) {
-      /* Probably it isn't worth spinning */
-         continue;
-      }
-      spin_lock_irqsave(&card->int_lock, flags);
+	PRINTK("nicstar: Entering ns_poll().\n");
+	for (i = 0; i < num_cards; i++) {
+		card = cards[i];
+		if (spin_is_locked(&card->int_lock)) {
+			/* Probably it isn't worth spinning */
+			continue;
+		}
+		spin_lock_irqsave(&card->int_lock, flags);
 
-      stat_w = 0;
-      stat_r = readl(card->membase + STAT);
-      if (stat_r & NS_STAT_TSIF)
-         stat_w |= NS_STAT_TSIF;
-      if (stat_r & NS_STAT_EOPDU)
-         stat_w |= NS_STAT_EOPDU;
+		stat_w = 0;
+		stat_r = readl(card->membase + STAT);
+		if (stat_r & NS_STAT_TSIF)
+			stat_w |= NS_STAT_TSIF;
+		if (stat_r & NS_STAT_EOPDU)
+			stat_w |= NS_STAT_EOPDU;
 
-      process_tsq(card);
-      process_rsq(card);
+		process_tsq(card);
+		process_rsq(card);
 
-      writel(stat_w, card->membase + STAT);
-      spin_unlock_irqrestore(&card->int_lock, flags);
-   }
-   mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD);
-   PRINTK("nicstar: Leaving ns_poll().\n");
+		writel(stat_w, card->membase + STAT);
+		spin_unlock_irqrestore(&card->int_lock, flags);
+	}
+	mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD);
+	PRINTK("nicstar: Leaving ns_poll().\n");
 }
 
-
-
 static int ns_parse_mac(char *mac, unsigned char *esi)
 {
-   int i, j;
-   short byte1, byte0;
+	int i, j;
+	short byte1, byte0;
 
-   if (mac == NULL || esi == NULL)
-      return -1;
-   j = 0;
-   for (i = 0; i < 6; i++)
-   {
-      if ((byte1 = ns_h2i(mac[j++])) < 0)
-         return -1;
-      if ((byte0 = ns_h2i(mac[j++])) < 0)
-         return -1;
-      esi[i] = (unsigned char) (byte1 * 16 + byte0);
-      if (i < 5)
-      {
-         if (mac[j++] != ':')
-            return -1;
-      }
-   }
-   return 0;
+	if (mac == NULL || esi == NULL)
+		return -1;
+	j = 0;
+	for (i = 0; i < 6; i++) {
+		if ((byte1 = hex_to_bin(mac[j++])) < 0)
+			return -1;
+		if ((byte0 = hex_to_bin(mac[j++])) < 0)
+			return -1;
+		esi[i] = (unsigned char)(byte1 * 16 + byte0);
+		if (i < 5) {
+			if (mac[j++] != ':')
+				return -1;
+		}
+	}
+	return 0;
 }
 
 
-
-static short ns_h2i(char c)
-{
-   if (c >= '0' && c <= '9')
-      return (short) (c - '0');
-   if (c >= 'A' && c <= 'F')
-      return (short) (c - 'A' + 10);
-   if (c >= 'a' && c <= 'f')
-      return (short) (c - 'a' + 10);
-   return -1;
-}
-
-
-
 static void ns_phy_put(struct atm_dev *dev, unsigned char value,
-                    unsigned long addr)
+		       unsigned long addr)
 {
-   ns_dev *card;
-   unsigned long flags;
+	ns_dev *card;
+	unsigned long flags;
 
-   card = dev->dev_data;
-   spin_lock_irqsave(&card->res_lock, flags);
-   while(CMD_BUSY(card));
-   writel((unsigned long) value, card->membase + DR0);
-   writel(NS_CMD_WRITE_UTILITY | 0x00000200 | (addr & 0x000000FF),
-          card->membase + CMD);
-   spin_unlock_irqrestore(&card->res_lock, flags);
+	card = dev->dev_data;
+	spin_lock_irqsave(&card->res_lock, flags);
+	while (CMD_BUSY(card)) ;
+	writel((u32) value, card->membase + DR0);
+	writel(NS_CMD_WRITE_UTILITY | 0x00000200 | (addr & 0x000000FF),
+	       card->membase + CMD);
+	spin_unlock_irqrestore(&card->res_lock, flags);
 }
 
-
-
 static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr)
 {
-   ns_dev *card;
-   unsigned long flags;
-   unsigned long data;
+	ns_dev *card;
+	unsigned long flags;
+	u32 data;
 
-   card = dev->dev_data;
-   spin_lock_irqsave(&card->res_lock, flags);
-   while(CMD_BUSY(card));
-   writel(NS_CMD_READ_UTILITY | 0x00000200 | (addr & 0x000000FF),
-          card->membase + CMD);
-   while(CMD_BUSY(card));
-   data = readl(card->membase + DR0) & 0x000000FF;
-   spin_unlock_irqrestore(&card->res_lock, flags);
-   return (unsigned char) data;
+	card = dev->dev_data;
+	spin_lock_irqsave(&card->res_lock, flags);
+	while (CMD_BUSY(card)) ;
+	writel(NS_CMD_READ_UTILITY | 0x00000200 | (addr & 0x000000FF),
+	       card->membase + CMD);
+	while (CMD_BUSY(card)) ;
+	data = readl(card->membase + DR0) & 0x000000FF;
+	spin_unlock_irqrestore(&card->res_lock, flags);
+	return (unsigned char)data;
 }
 
-
-
 module_init(nicstar_init);
 module_exit(nicstar_cleanup);
diff --git a/drivers/atm/nicstar.h b/drivers/atm/nicstar.h
index 6010e3d..9bc27ea 100644
--- a/drivers/atm/nicstar.h
+++ b/drivers/atm/nicstar.h
@@ -1,5 +1,4 @@
-/******************************************************************************
- *
+/*
  * nicstar.h
  *
  * Header file for the nicstar device driver.
@@ -8,29 +7,26 @@
  * PowerPC support by Jay Talbott (jay_talbott@mcg.mot.com) April 1999
  *
  * (C) INESC 1998
- *
- ******************************************************************************/
-
+ */
 
 #ifndef _LINUX_NICSTAR_H_
 #define _LINUX_NICSTAR_H_
 
-
-/* Includes *******************************************************************/
+/* Includes */
 
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/idr.h>
 #include <linux/uio.h>
 #include <linux/skbuff.h>
 #include <linux/atmdev.h>
 #include <linux/atm_nicstar.h>
 
-
-/* Options ********************************************************************/
+/* Options */
 
 #define NS_MAX_CARDS 4		/* Maximum number of NICStAR based cards
 				   controlled by the device driver. Must
-                                   be <= 5 */
+				   be <= 5 */
 
 #undef RCQ_SUPPORT		/* Do not define this for now */
 
@@ -43,7 +39,7 @@
 #define NS_VPIBITS 2		/* 0, 1, 2, or 8 */
 
 #define NS_MAX_RCTSIZE 4096	/* Number of entries. 4096 or 16384.
-                                   Define 4096 only if (all) your card(s)
+				   Define 4096 only if (all) your card(s)
 				   have 32K x 32bit SRAM, in which case
 				   setting this to 16384 will just waste a
 				   lot of memory.
@@ -51,33 +47,32 @@
 				   128K x 32bit SRAM will limit the maximum
 				   VCI. */
 
-/*#define NS_PCI_LATENCY 64*/	/* Must be a multiple of 32 */
+				/*#define NS_PCI_LATENCY 64*//* Must be a multiple of 32 */
 
 	/* Number of buffers initially allocated */
-#define NUM_SB 32	/* Must be even */
-#define NUM_LB 24	/* Must be even */
-#define NUM_HB 8	/* Pre-allocated huge buffers */
-#define NUM_IOVB 48	/* Iovec buffers */
+#define NUM_SB 32		/* Must be even */
+#define NUM_LB 24		/* Must be even */
+#define NUM_HB 8		/* Pre-allocated huge buffers */
+#define NUM_IOVB 48		/* Iovec buffers */
 
 	/* Lower level for count of buffers */
-#define MIN_SB 8	/* Must be even */
-#define MIN_LB 8	/* Must be even */
+#define MIN_SB 8		/* Must be even */
+#define MIN_LB 8		/* Must be even */
 #define MIN_HB 6
 #define MIN_IOVB 8
 
 	/* Upper level for count of buffers */
-#define MAX_SB 64	/* Must be even, <= 508 */
-#define MAX_LB 48	/* Must be even, <= 508 */
+#define MAX_SB 64		/* Must be even, <= 508 */
+#define MAX_LB 48		/* Must be even, <= 508 */
 #define MAX_HB 10
 #define MAX_IOVB 80
 
 	/* These are the absolute maximum allowed for the ioctl() */
-#define TOP_SB 256	/* Must be even, <= 508 */
-#define TOP_LB 128	/* Must be even, <= 508 */
+#define TOP_SB 256		/* Must be even, <= 508 */
+#define TOP_LB 128		/* Must be even, <= 508 */
 #define TOP_HB 64
 #define TOP_IOVB 256
 
-
 #define MAX_TBD_PER_VC 1	/* Number of TBDs before a TSR */
 #define MAX_TBD_PER_SCQ 10	/* Only meaningful for variable rate SCQs */
 
@@ -89,15 +84,12 @@
 
 #define PCR_TOLERANCE (1.0001)
 
-
-
-/* ESI stuff ******************************************************************/
+/* ESI stuff */
 
 #define NICSTAR_EPROM_MAC_ADDR_OFFSET 0x6C
 #define NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT 0xF6
 
-
-/* #defines *******************************************************************/
+/* #defines */
 
 #define NS_IOREMAP_SIZE 4096
 
@@ -123,22 +115,19 @@
 #define NS_SMSKBSIZE (NS_SMBUFSIZE + NS_AAL0_HEADER)
 #define NS_LGSKBSIZE (NS_SMBUFSIZE + NS_LGBUFSIZE)
 
+/* NICStAR structures located in host memory */
 
-/* NICStAR structures located in host memory **********************************/
-
-
-
-/* RSQ - Receive Status Queue 
+/*
+ * RSQ - Receive Status Queue
  *
  * Written by the NICStAR, read by the device driver.
  */
 
-typedef struct ns_rsqe
-{
-   u32 word_1;
-   u32 buffer_handle;
-   u32 final_aal5_crc32;
-   u32 word_4;
+typedef struct ns_rsqe {
+	u32 word_1;
+	u32 buffer_handle;
+	u32 final_aal5_crc32;
+	u32 word_4;
 } ns_rsqe;
 
 #define ns_rsqe_vpi(ns_rsqep) \
@@ -175,30 +164,27 @@
 #define ns_rsqe_cellcount(ns_rsqep) \
         (le32_to_cpu((ns_rsqep)->word_4) & 0x000001FF)
 #define ns_rsqe_init(ns_rsqep) \
-        ((ns_rsqep)->word_4 = cpu_to_le32(0x00000000)) 
+        ((ns_rsqep)->word_4 = cpu_to_le32(0x00000000))
 
 #define NS_RSQ_NUM_ENTRIES (NS_RSQSIZE / 16)
 #define NS_RSQ_ALIGNMENT NS_RSQSIZE
 
-
-
-/* RCQ - Raw Cell Queue
+/*
+ * RCQ - Raw Cell Queue
  *
  * Written by the NICStAR, read by the device driver.
  */
 
-typedef struct cell_payload
-{
-   u32 word[12];
+typedef struct cell_payload {
+	u32 word[12];
 } cell_payload;
 
-typedef struct ns_rcqe
-{
-   u32 word_1;
-   u32 word_2;
-   u32 word_3;
-   u32 word_4;
-   cell_payload payload;
+typedef struct ns_rcqe {
+	u32 word_1;
+	u32 word_2;
+	u32 word_3;
+	u32 word_4;
+	cell_payload payload;
 } ns_rcqe;
 
 #define NS_RCQE_SIZE 64		/* bytes */
@@ -210,28 +196,25 @@
 #define ns_rcqe_nextbufhandle(ns_rcqep) \
         (le32_to_cpu((ns_rcqep)->word_2))
 
-
-
-/* SCQ - Segmentation Channel Queue 
+/*
+ * SCQ - Segmentation Channel Queue
  *
  * Written by the device driver, read by the NICStAR.
  */
 
-typedef struct ns_scqe
-{
-   u32 word_1;
-   u32 word_2;
-   u32 word_3;
-   u32 word_4;
+typedef struct ns_scqe {
+	u32 word_1;
+	u32 word_2;
+	u32 word_3;
+	u32 word_4;
 } ns_scqe;
 
    /* NOTE: SCQ entries can be either a TBD (Transmit Buffer Descriptors)
-            or TSR (Transmit Status Requests) */
+      or TSR (Transmit Status Requests) */
 
 #define NS_SCQE_TYPE_TBD 0x00000000
 #define NS_SCQE_TYPE_TSR 0x80000000
 
-
 #define NS_TBD_EOPDU 0x40000000
 #define NS_TBD_AAL0  0x00000000
 #define NS_TBD_AAL34 0x04000000
@@ -253,10 +236,9 @@
 #define ns_tbd_mkword_4(gfc, vpi, vci, pt, clp) \
       (cpu_to_le32((gfc) << 28 | (vpi) << 20 | (vci) << 4 | (pt) << 1 | (clp)))
 
-
 #define NS_TSR_INTENABLE 0x20000000
 
-#define NS_TSR_SCDISVBR 0xFFFF		/* Use as scdi for VBR SCD */
+#define NS_TSR_SCDISVBR 0xFFFF	/* Use as scdi for VBR SCD */
 
 #define ns_tsr_mkword_1(flags) \
         (cpu_to_le32(NS_SCQE_TYPE_TSR | (flags)))
@@ -273,22 +255,20 @@
 
 #define NS_SCQE_SIZE 16
 
-
-
-/* TSQ - Transmit Status Queue
+/*
+ * TSQ - Transmit Status Queue
  *
  * Written by the NICStAR, read by the device driver.
  */
 
-typedef struct ns_tsi
-{
-   u32 word_1;
-   u32 word_2;
+typedef struct ns_tsi {
+	u32 word_1;
+	u32 word_2;
 } ns_tsi;
 
    /* NOTE: The first word can be a status word copied from the TSR which
-            originated the TSI, or a timer overflow indicator. In this last
-	    case, the value of the first word is all zeroes. */
+      originated the TSI, or a timer overflow indicator. In this last
+      case, the value of the first word is all zeroes. */
 
 #define NS_TSI_EMPTY          0x80000000
 #define NS_TSI_TIMESTAMP_MASK 0x00FFFFFF
@@ -301,12 +281,10 @@
 #define ns_tsi_init(ns_tsip) \
         ((ns_tsip)->word_2 = cpu_to_le32(NS_TSI_EMPTY))
 
-
 #define NS_TSQSIZE 8192
 #define NS_TSQ_NUM_ENTRIES 1024
 #define NS_TSQ_ALIGNMENT 8192
 
-
 #define NS_TSI_SCDISVBR NS_TSR_SCDISVBR
 
 #define ns_tsi_tmrof(ns_tsip) \
@@ -316,26 +294,22 @@
 #define ns_tsi_getscqpos(ns_tsip) \
         (le32_to_cpu((ns_tsip)->word_1) & 0x00007FFF)
 
+/* NICStAR structures located in local SRAM */
 
-
-/* NICStAR structures located in local SRAM ***********************************/
-
-
-
-/* RCT - Receive Connection Table
+/*
+ * RCT - Receive Connection Table
  *
  * Written by both the NICStAR and the device driver.
  */
 
-typedef struct ns_rcte
-{
-   u32 word_1;
-   u32 buffer_handle;
-   u32 dma_address;
-   u32 aal5_crc32;
+typedef struct ns_rcte {
+	u32 word_1;
+	u32 buffer_handle;
+	u32 dma_address;
+	u32 aal5_crc32;
 } ns_rcte;
 
-#define NS_RCTE_BSFB            0x00200000  /* Rev. D only */
+#define NS_RCTE_BSFB            0x00200000	/* Rev. D only */
 #define NS_RCTE_NZGFC           0x00100000
 #define NS_RCTE_CONNECTOPEN     0x00080000
 #define NS_RCTE_AALMASK         0x00070000
@@ -358,25 +332,21 @@
 #define NS_RCT_ENTRY_SIZE 4	/* Number of dwords */
 
    /* NOTE: We could make macros to contruct the first word of the RCTE,
-            but that doesn't seem to make much sense... */
+      but that doesn't seem to make much sense... */
 
-
-
-/* FBD - Free Buffer Descriptor
+/*
+ * FBD - Free Buffer Descriptor
  *
  * Written by the device driver using via the command register.
  */
 
-typedef struct ns_fbd
-{
-   u32 buffer_handle;
-   u32 dma_address;
+typedef struct ns_fbd {
+	u32 buffer_handle;
+	u32 dma_address;
 } ns_fbd;
 
-
-
-
-/* TST - Transmit Schedule Table
+/*
+ * TST - Transmit Schedule Table
  *
  * Written by the device driver.
  */
@@ -385,40 +355,38 @@
 
 #define NS_TST_OPCODE_MASK 0x60000000
 
-#define NS_TST_OPCODE_NULL     0x00000000 /* Insert null cell */
-#define NS_TST_OPCODE_FIXED    0x20000000 /* Cell from a fixed rate channel */
+#define NS_TST_OPCODE_NULL     0x00000000	/* Insert null cell */
+#define NS_TST_OPCODE_FIXED    0x20000000	/* Cell from a fixed rate channel */
 #define NS_TST_OPCODE_VARIABLE 0x40000000
-#define NS_TST_OPCODE_END      0x60000000 /* Jump */
+#define NS_TST_OPCODE_END      0x60000000	/* Jump */
 
 #define ns_tste_make(opcode, sramad) (opcode | sramad)
 
    /* NOTE:
 
       - When the opcode is FIXED, sramad specifies the SRAM address of the
-        SCD for that fixed rate channel.
+      SCD for that fixed rate channel.
       - When the opcode is END, sramad specifies the SRAM address of the
-        location of the next TST entry to read.
+      location of the next TST entry to read.
     */
 
-
-
-/* SCD - Segmentation Channel Descriptor
+/*
+ * SCD - Segmentation Channel Descriptor
  *
  * Written by both the device driver and the NICStAR
  */
 
-typedef struct ns_scd
-{
-   u32 word_1;
-   u32 word_2;
-   u32 partial_aal5_crc;
-   u32 reserved;
-   ns_scqe cache_a;
-   ns_scqe cache_b;
+typedef struct ns_scd {
+	u32 word_1;
+	u32 word_2;
+	u32 partial_aal5_crc;
+	u32 reserved;
+	ns_scqe cache_a;
+	ns_scqe cache_b;
 } ns_scd;
 
-#define NS_SCD_BASE_MASK_VAR 0xFFFFE000		/* Variable rate */
-#define NS_SCD_BASE_MASK_FIX 0xFFFFFC00		/* Fixed rate */
+#define NS_SCD_BASE_MASK_VAR 0xFFFFE000	/* Variable rate */
+#define NS_SCD_BASE_MASK_FIX 0xFFFFFC00	/* Fixed rate */
 #define NS_SCD_TAIL_MASK_VAR 0x00001FF0
 #define NS_SCD_TAIL_MASK_FIX 0x000003F0
 #define NS_SCD_HEAD_MASK_VAR 0x00001FF0
@@ -426,13 +394,9 @@
 #define NS_SCD_XMITFOREVER   0x02000000
 
    /* NOTE: There are other fields in word 2 of the SCD, but as they should
-            not be needed in the device driver they are not defined here. */
+      not be needed in the device driver they are not defined here. */
 
-
-
-
-/* NICStAR local SRAM memory map **********************************************/
-
+/* NICStAR local SRAM memory map */
 
 #define NS_RCT           0x00000
 #define NS_RCT_32_END    0x03FFF
@@ -455,100 +419,93 @@
 #define NS_LGFBQ         0x1FC00
 #define NS_LGFBQ_END     0x1FFFF
 
-
-
-/* NISCtAR operation registers ************************************************/
-
+/* NISCtAR operation registers */
 
 /* See Section 3.4 of `IDT77211 NICStAR User Manual' from www.idt.com */
 
-enum ns_regs
-{
-   DR0   = 0x00,      /* Data Register 0 R/W*/
-   DR1   = 0x04,      /* Data Register 1 W */
-   DR2   = 0x08,      /* Data Register 2 W */
-   DR3   = 0x0C,      /* Data Register 3 W */
-   CMD   = 0x10,      /* Command W */
-   CFG   = 0x14,      /* Configuration R/W */
-   STAT  = 0x18,      /* Status R/W */
-   RSQB  = 0x1C,      /* Receive Status Queue Base W */
-   RSQT  = 0x20,      /* Receive Status Queue Tail R */
-   RSQH  = 0x24,      /* Receive Status Queue Head W */
-   CDC   = 0x28,      /* Cell Drop Counter R/clear */
-   VPEC  = 0x2C,      /* VPI/VCI Lookup Error Count R/clear */
-   ICC   = 0x30,      /* Invalid Cell Count R/clear */
-   RAWCT = 0x34,      /* Raw Cell Tail R */
-   TMR   = 0x38,      /* Timer R */
-   TSTB  = 0x3C,      /* Transmit Schedule Table Base R/W */
-   TSQB  = 0x40,      /* Transmit Status Queue Base W */
-   TSQT  = 0x44,      /* Transmit Status Queue Tail R */
-   TSQH  = 0x48,      /* Transmit Status Queue Head W */
-   GP    = 0x4C,      /* General Purpose R/W */
-   VPM   = 0x50       /* VPI/VCI Mask W */
+enum ns_regs {
+	DR0 = 0x00,		/* Data Register 0 R/W */
+	DR1 = 0x04,		/* Data Register 1 W */
+	DR2 = 0x08,		/* Data Register 2 W */
+	DR3 = 0x0C,		/* Data Register 3 W */
+	CMD = 0x10,		/* Command W */
+	CFG = 0x14,		/* Configuration R/W */
+	STAT = 0x18,		/* Status R/W */
+	RSQB = 0x1C,		/* Receive Status Queue Base W */
+	RSQT = 0x20,		/* Receive Status Queue Tail R */
+	RSQH = 0x24,		/* Receive Status Queue Head W */
+	CDC = 0x28,		/* Cell Drop Counter R/clear */
+	VPEC = 0x2C,		/* VPI/VCI Lookup Error Count R/clear */
+	ICC = 0x30,		/* Invalid Cell Count R/clear */
+	RAWCT = 0x34,		/* Raw Cell Tail R */
+	TMR = 0x38,		/* Timer R */
+	TSTB = 0x3C,		/* Transmit Schedule Table Base R/W */
+	TSQB = 0x40,		/* Transmit Status Queue Base W */
+	TSQT = 0x44,		/* Transmit Status Queue Tail R */
+	TSQH = 0x48,		/* Transmit Status Queue Head W */
+	GP = 0x4C,		/* General Purpose R/W */
+	VPM = 0x50		/* VPI/VCI Mask W */
 };
 
-
-/* NICStAR commands issued to the CMD register ********************************/
-
+/* NICStAR commands issued to the CMD register */
 
 /* Top 4 bits are command opcode, lower 28 are parameters. */
 
 #define NS_CMD_NO_OPERATION         0x00000000
-        /* params always 0 */
+	/* params always 0 */
 
 #define NS_CMD_OPENCLOSE_CONNECTION 0x20000000
-        /* b19{1=open,0=close} b18-2{SRAM addr} */
+	/* b19{1=open,0=close} b18-2{SRAM addr} */
 
 #define NS_CMD_WRITE_SRAM           0x40000000
-        /* b18-2{SRAM addr} b1-0{burst size} */
+	/* b18-2{SRAM addr} b1-0{burst size} */
 
 #define NS_CMD_READ_SRAM            0x50000000
-        /* b18-2{SRAM addr} */
+	/* b18-2{SRAM addr} */
 
 #define NS_CMD_WRITE_FREEBUFQ       0x60000000
-        /* b0{large buf indicator} */
+	/* b0{large buf indicator} */
 
 #define NS_CMD_READ_UTILITY         0x80000000
-        /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */
+	/* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */
 
 #define NS_CMD_WRITE_UTILITY        0x90000000
-        /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */
+	/* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */
 
 #define NS_CMD_OPEN_CONNECTION (NS_CMD_OPENCLOSE_CONNECTION | 0x00080000)
 #define NS_CMD_CLOSE_CONNECTION NS_CMD_OPENCLOSE_CONNECTION
 
+/* NICStAR configuration bits */
 
-/* NICStAR configuration bits *************************************************/
-
-#define NS_CFG_SWRST          0x80000000    /* Software Reset */
-#define NS_CFG_RXPATH         0x20000000    /* Receive Path Enable */
-#define NS_CFG_SMBUFSIZE_MASK 0x18000000    /* Small Receive Buffer Size */
-#define NS_CFG_LGBUFSIZE_MASK 0x06000000    /* Large Receive Buffer Size */
-#define NS_CFG_EFBIE          0x01000000    /* Empty Free Buffer Queue
-                                               Interrupt Enable */
-#define NS_CFG_RSQSIZE_MASK   0x00C00000    /* Receive Status Queue Size */
-#define NS_CFG_ICACCEPT       0x00200000    /* Invalid Cell Accept */
-#define NS_CFG_IGNOREGFC      0x00100000    /* Ignore General Flow Control */
-#define NS_CFG_VPIBITS_MASK   0x000C0000    /* VPI/VCI Bits Size Select */
-#define NS_CFG_RCTSIZE_MASK   0x00030000    /* Receive Connection Table Size */
-#define NS_CFG_VCERRACCEPT    0x00008000    /* VPI/VCI Error Cell Accept */
-#define NS_CFG_RXINT_MASK     0x00007000    /* End of Receive PDU Interrupt
-                                               Handling */
-#define NS_CFG_RAWIE          0x00000800    /* Raw Cell Qu' Interrupt Enable */
-#define NS_CFG_RSQAFIE        0x00000400    /* Receive Queue Almost Full
-                                               Interrupt Enable */
-#define NS_CFG_RXRM           0x00000200    /* Receive RM Cells */
-#define NS_CFG_TMRROIE        0x00000080    /* Timer Roll Over Interrupt
-                                               Enable */
-#define NS_CFG_TXEN           0x00000020    /* Transmit Operation Enable */
-#define NS_CFG_TXIE           0x00000010    /* Transmit Status Interrupt
-                                               Enable */
-#define NS_CFG_TXURIE         0x00000008    /* Transmit Under-run Interrupt
-                                               Enable */
-#define NS_CFG_UMODE          0x00000004    /* Utopia Mode (cell/byte) Select */
-#define NS_CFG_TSQFIE         0x00000002    /* Transmit Status Queue Full
-                                               Interrupt Enable */
-#define NS_CFG_PHYIE          0x00000001    /* PHY Interrupt Enable */
+#define NS_CFG_SWRST          0x80000000	/* Software Reset */
+#define NS_CFG_RXPATH         0x20000000	/* Receive Path Enable */
+#define NS_CFG_SMBUFSIZE_MASK 0x18000000	/* Small Receive Buffer Size */
+#define NS_CFG_LGBUFSIZE_MASK 0x06000000	/* Large Receive Buffer Size */
+#define NS_CFG_EFBIE          0x01000000	/* Empty Free Buffer Queue
+						   Interrupt Enable */
+#define NS_CFG_RSQSIZE_MASK   0x00C00000	/* Receive Status Queue Size */
+#define NS_CFG_ICACCEPT       0x00200000	/* Invalid Cell Accept */
+#define NS_CFG_IGNOREGFC      0x00100000	/* Ignore General Flow Control */
+#define NS_CFG_VPIBITS_MASK   0x000C0000	/* VPI/VCI Bits Size Select */
+#define NS_CFG_RCTSIZE_MASK   0x00030000	/* Receive Connection Table Size */
+#define NS_CFG_VCERRACCEPT    0x00008000	/* VPI/VCI Error Cell Accept */
+#define NS_CFG_RXINT_MASK     0x00007000	/* End of Receive PDU Interrupt
+						   Handling */
+#define NS_CFG_RAWIE          0x00000800	/* Raw Cell Qu' Interrupt Enable */
+#define NS_CFG_RSQAFIE        0x00000400	/* Receive Queue Almost Full
+						   Interrupt Enable */
+#define NS_CFG_RXRM           0x00000200	/* Receive RM Cells */
+#define NS_CFG_TMRROIE        0x00000080	/* Timer Roll Over Interrupt
+						   Enable */
+#define NS_CFG_TXEN           0x00000020	/* Transmit Operation Enable */
+#define NS_CFG_TXIE           0x00000010	/* Transmit Status Interrupt
+						   Enable */
+#define NS_CFG_TXURIE         0x00000008	/* Transmit Under-run Interrupt
+						   Enable */
+#define NS_CFG_UMODE          0x00000004	/* Utopia Mode (cell/byte) Select */
+#define NS_CFG_TSQFIE         0x00000002	/* Transmit Status Queue Full
+						   Interrupt Enable */
+#define NS_CFG_PHYIE          0x00000001	/* PHY Interrupt Enable */
 
 #define NS_CFG_SMBUFSIZE_48    0x00000000
 #define NS_CFG_SMBUFSIZE_96    0x08000000
@@ -579,33 +536,29 @@
 #define NS_CFG_RXINT_624US   0x00003000
 #define NS_CFG_RXINT_899US   0x00004000
 
+/* NICStAR STATus bits */
 
-/* NICStAR STATus bits ********************************************************/
-
-#define NS_STAT_SFBQC_MASK 0xFF000000   /* hi 8 bits Small Buffer Queue Count */
-#define NS_STAT_LFBQC_MASK 0x00FF0000   /* hi 8 bits Large Buffer Queue Count */
-#define NS_STAT_TSIF       0x00008000   /* Transmit Status Queue Indicator */
-#define NS_STAT_TXICP      0x00004000   /* Transmit Incomplete PDU */
-#define NS_STAT_TSQF       0x00001000   /* Transmit Status Queue Full */
-#define NS_STAT_TMROF      0x00000800   /* Timer Overflow */
-#define NS_STAT_PHYI       0x00000400   /* PHY Device Interrupt */
-#define NS_STAT_CMDBZ      0x00000200   /* Command Busy */
-#define NS_STAT_SFBQF      0x00000100   /* Small Buffer Queue Full */
-#define NS_STAT_LFBQF      0x00000080   /* Large Buffer Queue Full */
-#define NS_STAT_RSQF       0x00000040   /* Receive Status Queue Full */
-#define NS_STAT_EOPDU      0x00000020   /* End of PDU */
-#define NS_STAT_RAWCF      0x00000010   /* Raw Cell Flag */
-#define NS_STAT_SFBQE      0x00000008   /* Small Buffer Queue Empty */
-#define NS_STAT_LFBQE      0x00000004   /* Large Buffer Queue Empty */
-#define NS_STAT_RSQAF      0x00000002   /* Receive Status Queue Almost Full */
+#define NS_STAT_SFBQC_MASK 0xFF000000	/* hi 8 bits Small Buffer Queue Count */
+#define NS_STAT_LFBQC_MASK 0x00FF0000	/* hi 8 bits Large Buffer Queue Count */
+#define NS_STAT_TSIF       0x00008000	/* Transmit Status Queue Indicator */
+#define NS_STAT_TXICP      0x00004000	/* Transmit Incomplete PDU */
+#define NS_STAT_TSQF       0x00001000	/* Transmit Status Queue Full */
+#define NS_STAT_TMROF      0x00000800	/* Timer Overflow */
+#define NS_STAT_PHYI       0x00000400	/* PHY Device Interrupt */
+#define NS_STAT_CMDBZ      0x00000200	/* Command Busy */
+#define NS_STAT_SFBQF      0x00000100	/* Small Buffer Queue Full */
+#define NS_STAT_LFBQF      0x00000080	/* Large Buffer Queue Full */
+#define NS_STAT_RSQF       0x00000040	/* Receive Status Queue Full */
+#define NS_STAT_EOPDU      0x00000020	/* End of PDU */
+#define NS_STAT_RAWCF      0x00000010	/* Raw Cell Flag */
+#define NS_STAT_SFBQE      0x00000008	/* Small Buffer Queue Empty */
+#define NS_STAT_LFBQE      0x00000004	/* Large Buffer Queue Empty */
+#define NS_STAT_RSQAF      0x00000002	/* Receive Status Queue Almost Full */
 
 #define ns_stat_sfbqc_get(stat) (((stat) & NS_STAT_SFBQC_MASK) >> 23)
 #define ns_stat_lfbqc_get(stat) (((stat) & NS_STAT_LFBQC_MASK) >> 15)
 
-
-
-/* #defines which depend on other #defines ************************************/
-
+/* #defines which depend on other #defines */
 
 #define NS_TST0 NS_TST_FRSCD
 #define NS_TST1 (NS_TST_FRSCD + NS_TST_NUM_ENTRIES + 1)
@@ -672,8 +625,7 @@
 #define NS_CFG_TSQFIE_OPT 0x00000000
 #endif /* ENABLE_TSQFIE */
 
-
-/* PCI stuff ******************************************************************/
+/* PCI stuff */
 
 #ifndef PCI_VENDOR_ID_IDT
 #define PCI_VENDOR_ID_IDT 0x111D
@@ -683,138 +635,124 @@
 #define PCI_DEVICE_ID_IDT_IDT77201 0x0001
 #endif /* PCI_DEVICE_ID_IDT_IDT77201 */
 
+/* Device driver structures */
 
-
-/* Device driver structures ***************************************************/
-
-
-struct ns_skb_cb {
-	u32 buf_type;			/* BUF_SM/BUF_LG/BUF_NONE */
+struct ns_skb_prv {
+	u32 buf_type;		/* BUF_SM/BUF_LG/BUF_NONE */
+	u32 dma;
+	int iovcnt;
 };
 
-#define NS_SKB_CB(skb)	((struct ns_skb_cb *)((skb)->cb))
+#define NS_PRV_BUFTYPE(skb)   \
+        (((struct ns_skb_prv *)(ATM_SKB(skb)+1))->buf_type)
+#define NS_PRV_DMA(skb) \
+        (((struct ns_skb_prv *)(ATM_SKB(skb)+1))->dma)
+#define NS_PRV_IOVCNT(skb) \
+        (((struct ns_skb_prv *)(ATM_SKB(skb)+1))->iovcnt)
 
-typedef struct tsq_info
-{
-   void *org;
-   ns_tsi *base;
-   ns_tsi *next;
-   ns_tsi *last;
+typedef struct tsq_info {
+	void *org;
+        dma_addr_t dma;
+	ns_tsi *base;
+	ns_tsi *next;
+	ns_tsi *last;
 } tsq_info;
 
-
-typedef struct scq_info
-{
-   void *org;
-   ns_scqe *base;
-   ns_scqe *last;
-   ns_scqe *next;
-   volatile ns_scqe *tail;		/* Not related to the nicstar register */
-   unsigned num_entries;
-   struct sk_buff **skb;		/* Pointer to an array of pointers
-                                           to the sk_buffs used for tx */
-   u32 scd;				/* SRAM address of the corresponding
-                                           SCD */
-   int tbd_count;			/* Only meaningful on variable rate */
-   wait_queue_head_t scqfull_waitq;
-   volatile char full;			/* SCQ full indicator */
-   spinlock_t lock;			/* SCQ spinlock */
+typedef struct scq_info {
+	void *org;
+	dma_addr_t dma;
+	ns_scqe *base;
+	ns_scqe *last;
+	ns_scqe *next;
+	volatile ns_scqe *tail;	/* Not related to the nicstar register */
+	unsigned num_entries;
+	struct sk_buff **skb;	/* Pointer to an array of pointers
+				   to the sk_buffs used for tx */
+	u32 scd;		/* SRAM address of the corresponding
+				   SCD */
+	int tbd_count;		/* Only meaningful on variable rate */
+	wait_queue_head_t scqfull_waitq;
+	volatile char full;	/* SCQ full indicator */
+	spinlock_t lock;	/* SCQ spinlock */
 } scq_info;
 
-
-
-typedef struct rsq_info
-{
-   void *org;
-   ns_rsqe *base;
-   ns_rsqe *next;
-   ns_rsqe *last;
+typedef struct rsq_info {
+	void *org;
+        dma_addr_t dma;
+	ns_rsqe *base;
+	ns_rsqe *next;
+	ns_rsqe *last;
 } rsq_info;
 
-
-typedef struct skb_pool
-{
-   volatile int count;			/* number of buffers in the queue */
-   struct sk_buff_head queue;
+typedef struct skb_pool {
+	volatile int count;	/* number of buffers in the queue */
+	struct sk_buff_head queue;
 } skb_pool;
 
 /* NOTE: for small and large buffer pools, the count is not used, as the
          actual value used for buffer management is the one read from the
 	 card. */
 
-
-typedef struct vc_map
-{
-   volatile unsigned int tx:1;				/* TX vc? */
-   volatile unsigned int rx:1;				/* RX vc? */
-   struct atm_vcc *tx_vcc, *rx_vcc;
-   struct sk_buff *rx_iov;		/* RX iovector skb */
-   scq_info *scq;			/* To keep track of the SCQ */
-   u32 cbr_scd;				/* SRAM address of the corresponding
-               				   SCD. 0x00000000 for UBR/VBR/ABR */
-   int tbd_count;
+typedef struct vc_map {
+	volatile unsigned int tx:1;	/* TX vc? */
+	volatile unsigned int rx:1;	/* RX vc? */
+	struct atm_vcc *tx_vcc, *rx_vcc;
+	struct sk_buff *rx_iov;	/* RX iovector skb */
+	scq_info *scq;		/* To keep track of the SCQ */
+	u32 cbr_scd;		/* SRAM address of the corresponding
+				   SCD. 0x00000000 for UBR/VBR/ABR */
+	int tbd_count;
 } vc_map;
 
-
-struct ns_skb_data
-{
-	struct atm_vcc *vcc;
-	int iovcnt;
-};
-
-#define NS_SKB(skb) (((struct ns_skb_data *) (skb)->cb))
-
-
-typedef struct ns_dev
-{
-   int index;				/* Card ID to the device driver */
-   int sram_size;			/* In k x 32bit words. 32 or 128 */
-   void __iomem *membase;		/* Card's memory base address */
-   unsigned long max_pcr;
-   int rct_size;			/* Number of entries */
-   int vpibits;
-   int vcibits;
-   struct pci_dev *pcidev;
-   struct atm_dev *atmdev;
-   tsq_info tsq;
-   rsq_info rsq;
-   scq_info *scq0, *scq1, *scq2;	/* VBR SCQs */
-   skb_pool sbpool;			/* Small buffers */
-   skb_pool lbpool;			/* Large buffers */
-   skb_pool hbpool;			/* Pre-allocated huge buffers */
-   skb_pool iovpool;			/* iovector buffers */
-   volatile int efbie;			/* Empty free buf. queue int. enabled */
-   volatile u32 tst_addr;		/* SRAM address of the TST in use */
-   volatile int tst_free_entries;
-   vc_map vcmap[NS_MAX_RCTSIZE];
-   vc_map *tste2vc[NS_TST_NUM_ENTRIES];
-   vc_map *scd2vc[NS_FRSCD_NUM];
-   buf_nr sbnr;
-   buf_nr lbnr;
-   buf_nr hbnr;
-   buf_nr iovnr;
-   int sbfqc;
-   int lbfqc;
-   u32 sm_handle;
-   u32 sm_addr;
-   u32 lg_handle;
-   u32 lg_addr;
-   struct sk_buff *rcbuf;		/* Current raw cell buffer */
-   u32 rawch;				/* Raw cell queue head */
-   unsigned intcnt;			/* Interrupt counter */
-   spinlock_t int_lock;		/* Interrupt lock */
-   spinlock_t res_lock;		/* Card resource lock */
+typedef struct ns_dev {
+	int index;		/* Card ID to the device driver */
+	int sram_size;		/* In k x 32bit words. 32 or 128 */
+	void __iomem *membase;	/* Card's memory base address */
+	unsigned long max_pcr;
+	int rct_size;		/* Number of entries */
+	int vpibits;
+	int vcibits;
+	struct pci_dev *pcidev;
+	struct idr idr;
+	struct atm_dev *atmdev;
+	tsq_info tsq;
+	rsq_info rsq;
+	scq_info *scq0, *scq1, *scq2;	/* VBR SCQs */
+	skb_pool sbpool;	/* Small buffers */
+	skb_pool lbpool;	/* Large buffers */
+	skb_pool hbpool;	/* Pre-allocated huge buffers */
+	skb_pool iovpool;	/* iovector buffers */
+	volatile int efbie;	/* Empty free buf. queue int. enabled */
+	volatile u32 tst_addr;	/* SRAM address of the TST in use */
+	volatile int tst_free_entries;
+	vc_map vcmap[NS_MAX_RCTSIZE];
+	vc_map *tste2vc[NS_TST_NUM_ENTRIES];
+	vc_map *scd2vc[NS_FRSCD_NUM];
+	buf_nr sbnr;
+	buf_nr lbnr;
+	buf_nr hbnr;
+	buf_nr iovnr;
+	int sbfqc;
+	int lbfqc;
+	struct sk_buff *sm_handle;
+	u32 sm_addr;
+	struct sk_buff *lg_handle;
+	u32 lg_addr;
+	struct sk_buff *rcbuf;	/* Current raw cell buffer */
+        struct ns_rcqe *rawcell;
+	u32 rawch;		/* Raw cell queue head */
+	unsigned intcnt;	/* Interrupt counter */
+	spinlock_t int_lock;	/* Interrupt lock */
+	spinlock_t res_lock;	/* Card resource lock */
 } ns_dev;
 
-
    /* NOTE: Each tste2vc entry relates a given TST entry to the corresponding
-            CBR vc. If the entry is not allocated, it must be NULL.
-	    
-	    There are two TSTs so the driver can modify them on the fly
-	    without stopping the transmission.
-	    
-	    scd2vc allows us to find out unused fixed rate SCDs, because
-	    they must have a NULL pointer here. */
+      CBR vc. If the entry is not allocated, it must be NULL.
 
+      There are two TSTs so the driver can modify them on the fly
+      without stopping the transmission.
+
+      scd2vc allows us to find out unused fixed rate SCDs, because
+      they must have a NULL pointer here. */
 
 #endif /* _LINUX_NICSTAR_H_ */
diff --git a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c
index 842e26c..f594526 100644
--- a/drivers/atm/nicstarmac.c
+++ b/drivers/atm/nicstarmac.c
@@ -13,15 +13,15 @@
 
 #define CYCLE_DELAY 5
 
-/* This was the original definition
+/*
+   This was the original definition
 #define osp_MicroDelay(microsec) \
     do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
 */
 #define osp_MicroDelay(microsec) {unsigned long useconds = (microsec); \
                                   udelay((useconds));}
-
-
-/* The following tables represent the timing diagrams found in
+/*
+ * The following tables represent the timing diagrams found in
  * the Data Sheet for the Xicor X25020 EEProm.  The #defines below
  * represent the bits in the NICStAR's General Purpose register
  * that must be toggled for the corresponding actions on the EEProm
@@ -31,86 +31,80 @@
 /* Write Data To EEProm from SI line on rising edge of CLK */
 /* Read Data From EEProm on falling edge of CLK */
 
-#define CS_HIGH		0x0002		/* Chip select high */
-#define CS_LOW		0x0000		/* Chip select low (active low)*/
-#define CLK_HIGH	0x0004		/* Clock high */
-#define CLK_LOW		0x0000		/* Clock low  */
-#define SI_HIGH		0x0001		/* Serial input data high */
-#define SI_LOW		0x0000		/* Serial input data low */
+#define CS_HIGH		0x0002	/* Chip select high */
+#define CS_LOW		0x0000	/* Chip select low (active low) */
+#define CLK_HIGH	0x0004	/* Clock high */
+#define CLK_LOW		0x0000	/* Clock low  */
+#define SI_HIGH		0x0001	/* Serial input data high */
+#define SI_LOW		0x0000	/* Serial input data low */
 
 /* Read Status Register = 0000 0101b */
 #if 0
-static u_int32_t rdsrtab[] =
-{
-    CS_HIGH | CLK_HIGH, 
-    CS_LOW | CLK_LOW, 
-    CLK_HIGH,             /* 0 */
-    CLK_LOW, 
-    CLK_HIGH,             /* 0 */
-    CLK_LOW, 
-    CLK_HIGH,             /* 0 */
-    CLK_LOW,
-    CLK_HIGH,             /* 0 */
-    CLK_LOW, 
-    CLK_HIGH,             /* 0 */
-    CLK_LOW | SI_HIGH, 
-    CLK_HIGH | SI_HIGH,   /* 1 */
-    CLK_LOW | SI_LOW, 
-    CLK_HIGH,             /* 0 */
-    CLK_LOW | SI_HIGH, 
-    CLK_HIGH | SI_HIGH   /* 1 */
+static u_int32_t rdsrtab[] = {
+	CS_HIGH | CLK_HIGH,
+	CS_LOW | CLK_LOW,
+	CLK_HIGH,		/* 0 */
+	CLK_LOW,
+	CLK_HIGH,		/* 0 */
+	CLK_LOW,
+	CLK_HIGH,		/* 0 */
+	CLK_LOW,
+	CLK_HIGH,		/* 0 */
+	CLK_LOW,
+	CLK_HIGH,		/* 0 */
+	CLK_LOW | SI_HIGH,
+	CLK_HIGH | SI_HIGH,	/* 1 */
+	CLK_LOW | SI_LOW,
+	CLK_HIGH,		/* 0 */
+	CLK_LOW | SI_HIGH,
+	CLK_HIGH | SI_HIGH	/* 1 */
 };
-#endif  /*  0  */
-
+#endif /*  0  */
 
 /* Read from EEPROM = 0000 0011b */
-static u_int32_t readtab[] =
-{
-    /*
-    CS_HIGH | CLK_HIGH, 
-    */
-    CS_LOW | CLK_LOW, 
-    CLK_HIGH,             /* 0 */
-    CLK_LOW, 
-    CLK_HIGH,             /* 0 */
-    CLK_LOW, 
-    CLK_HIGH,             /* 0 */
-    CLK_LOW,
-    CLK_HIGH,             /* 0 */
-    CLK_LOW, 
-    CLK_HIGH,             /* 0 */
-    CLK_LOW, 
-    CLK_HIGH,             /* 0 */
-    CLK_LOW | SI_HIGH, 
-    CLK_HIGH | SI_HIGH,   /* 1 */
-    CLK_LOW | SI_HIGH, 
-    CLK_HIGH | SI_HIGH    /* 1 */
+static u_int32_t readtab[] = {
+	/*
+	   CS_HIGH | CLK_HIGH,
+	 */
+	CS_LOW | CLK_LOW,
+	CLK_HIGH,		/* 0 */
+	CLK_LOW,
+	CLK_HIGH,		/* 0 */
+	CLK_LOW,
+	CLK_HIGH,		/* 0 */
+	CLK_LOW,
+	CLK_HIGH,		/* 0 */
+	CLK_LOW,
+	CLK_HIGH,		/* 0 */
+	CLK_LOW,
+	CLK_HIGH,		/* 0 */
+	CLK_LOW | SI_HIGH,
+	CLK_HIGH | SI_HIGH,	/* 1 */
+	CLK_LOW | SI_HIGH,
+	CLK_HIGH | SI_HIGH	/* 1 */
 };
 
-
 /* Clock to read from/write to the eeprom */
-static u_int32_t clocktab[] =
-{	
-    CLK_LOW,
-    CLK_HIGH,
-    CLK_LOW, 
-    CLK_HIGH,
-    CLK_LOW,
-    CLK_HIGH,
-    CLK_LOW, 
-    CLK_HIGH,
-    CLK_LOW, 
-    CLK_HIGH,
-    CLK_LOW, 
-    CLK_HIGH, 
-    CLK_LOW, 
-    CLK_HIGH,
-    CLK_LOW, 
-    CLK_HIGH,
-    CLK_LOW 
+static u_int32_t clocktab[] = {
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW
 };
 
-
 #define NICSTAR_REG_WRITE(bs, reg, val) \
 	while ( readl(bs + STAT) & 0x0200 ) ; \
 	writel((val),(base)+(reg))
@@ -124,153 +118,131 @@
  * register.  
  */
 #if 0
-u_int32_t
-nicstar_read_eprom_status( virt_addr_t base )
+u_int32_t nicstar_read_eprom_status(virt_addr_t base)
 {
-   u_int32_t	val;
-   u_int32_t	rbyte;
-   int32_t	i, j;
+	u_int32_t val;
+	u_int32_t rbyte;
+	int32_t i, j;
 
-   /* Send read instruction */
-   val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0;
+	/* Send read instruction */
+	val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0;
 
-   for (i=0; i<ARRAY_SIZE(rdsrtab); i++)
-   {
-	NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
-		(val | rdsrtab[i]) );
-        osp_MicroDelay( CYCLE_DELAY );
-   }
+	for (i = 0; i < ARRAY_SIZE(rdsrtab); i++) {
+		NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+				  (val | rdsrtab[i]));
+		osp_MicroDelay(CYCLE_DELAY);
+	}
 
-   /* Done sending instruction - now pull data off of bit 16, MSB first */
-   /* Data clocked out of eeprom on falling edge of clock */
+	/* Done sending instruction - now pull data off of bit 16, MSB first */
+	/* Data clocked out of eeprom on falling edge of clock */
 
-   rbyte = 0;
-   for (i=7, j=0; i>=0; i--)
-   {
-	NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
-		(val | clocktab[j++]) );
-        rbyte |= (((NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE)
-			& 0x00010000) >> 16) << i);
-	NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
-		(val | clocktab[j++]) );
-        osp_MicroDelay( CYCLE_DELAY );
-   }
-   NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, 2 );
-   osp_MicroDelay( CYCLE_DELAY );
-   return rbyte;
+	rbyte = 0;
+	for (i = 7, j = 0; i >= 0; i--) {
+		NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+				  (val | clocktab[j++]));
+		rbyte |= (((NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE)
+			    & 0x00010000) >> 16) << i);
+		NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+				  (val | clocktab[j++]));
+		osp_MicroDelay(CYCLE_DELAY);
+	}
+	NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 2);
+	osp_MicroDelay(CYCLE_DELAY);
+	return rbyte;
 }
-#endif  /*  0  */
-
+#endif /*  0  */
 
 /*
  * This routine will clock the Read_data function into the X2520
  * eeprom, followed by the address to read from, through the NicSTaR's General
  * Purpose register.  
  */
- 
-static u_int8_t 
-read_eprom_byte(virt_addr_t base, u_int8_t offset)
+
+static u_int8_t read_eprom_byte(virt_addr_t base, u_int8_t offset)
 {
-   u_int32_t val = 0;
-   int i,j=0;
-   u_int8_t tempread = 0;
+	u_int32_t val = 0;
+	int i, j = 0;
+	u_int8_t tempread = 0;
 
-   val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0;
+	val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0;
 
-   /* Send READ instruction */
-   for (i=0; i<ARRAY_SIZE(readtab); i++)
-   {
-	NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
-		(val | readtab[i]) );
-        osp_MicroDelay( CYCLE_DELAY );
-   }
+	/* Send READ instruction */
+	for (i = 0; i < ARRAY_SIZE(readtab); i++) {
+		NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+				  (val | readtab[i]));
+		osp_MicroDelay(CYCLE_DELAY);
+	}
 
-   /* Next, we need to send the byte address to read from */
-   for (i=7; i>=0; i--)
-   {
-      NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
-      		(val | clocktab[j++] | ((offset >> i) & 1) ) );
-      osp_MicroDelay(CYCLE_DELAY);
-      NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
-      		(val | clocktab[j++] | ((offset >> i) & 1) ) );
-      osp_MicroDelay( CYCLE_DELAY );
-   }
+	/* Next, we need to send the byte address to read from */
+	for (i = 7; i >= 0; i--) {
+		NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+				  (val | clocktab[j++] | ((offset >> i) & 1)));
+		osp_MicroDelay(CYCLE_DELAY);
+		NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+				  (val | clocktab[j++] | ((offset >> i) & 1)));
+		osp_MicroDelay(CYCLE_DELAY);
+	}
 
-   j = 0;
-   
-   /* Now, we can read data from the eeprom by clocking it in */
-   for (i=7; i>=0; i--)
-   {
-      NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
-      		(val | clocktab[j++]) );
-      osp_MicroDelay( CYCLE_DELAY );
-      tempread |= (((NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE )
-		& 0x00010000) >> 16) << i);
-      NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
-      		(val | clocktab[j++]) );
-      osp_MicroDelay( CYCLE_DELAY );
-   }
+	j = 0;
 
-   NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, 2 );
-   osp_MicroDelay( CYCLE_DELAY );
-   return tempread;
+	/* Now, we can read data from the eeprom by clocking it in */
+	for (i = 7; i >= 0; i--) {
+		NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+				  (val | clocktab[j++]));
+		osp_MicroDelay(CYCLE_DELAY);
+		tempread |=
+		    (((NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE)
+		       & 0x00010000) >> 16) << i);
+		NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+				  (val | clocktab[j++]));
+		osp_MicroDelay(CYCLE_DELAY);
+	}
+
+	NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 2);
+	osp_MicroDelay(CYCLE_DELAY);
+	return tempread;
 }
 
-
-static void
-nicstar_init_eprom( virt_addr_t base )
+static void nicstar_init_eprom(virt_addr_t base)
 {
-    u_int32_t val;
+	u_int32_t val;
 
-    /*
-     * turn chip select off
-     */
-    val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0;
+	/*
+	 * turn chip select off
+	 */
+	val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0;
 
-    NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
-    	(val | CS_HIGH | CLK_HIGH));
-    osp_MicroDelay( CYCLE_DELAY );
+	NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+			  (val | CS_HIGH | CLK_HIGH));
+	osp_MicroDelay(CYCLE_DELAY);
 
-    NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
-    	(val | CS_HIGH | CLK_LOW));
-    osp_MicroDelay( CYCLE_DELAY );
+	NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+			  (val | CS_HIGH | CLK_LOW));
+	osp_MicroDelay(CYCLE_DELAY);
 
-    NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
-    	(val | CS_HIGH | CLK_HIGH));
-    osp_MicroDelay( CYCLE_DELAY );
+	NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+			  (val | CS_HIGH | CLK_HIGH));
+	osp_MicroDelay(CYCLE_DELAY);
 
-    NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
-    	(val | CS_HIGH | CLK_LOW));
-    osp_MicroDelay( CYCLE_DELAY );
+	NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+			  (val | CS_HIGH | CLK_LOW));
+	osp_MicroDelay(CYCLE_DELAY);
 }
 
-
 /*
  * This routine will be the interface to the ReadPromByte function
  * above.
- */ 
+ */
 
 static void
-nicstar_read_eprom(
-    virt_addr_t	base,
-    u_int8_t	prom_offset,
-    u_int8_t	*buffer,
-    u_int32_t	nbytes )
+nicstar_read_eprom(virt_addr_t base,
+		   u_int8_t prom_offset, u_int8_t * buffer, u_int32_t nbytes)
 {
-    u_int		i;
-    
-    for (i=0; i<nbytes; i++)
-    {
-	buffer[i] = read_eprom_byte( base, prom_offset );
-	++prom_offset;
- 	osp_MicroDelay( CYCLE_DELAY );
-    }
+	u_int i;
+
+	for (i = 0; i < nbytes; i++) {
+		buffer[i] = read_eprom_byte(base, prom_offset);
+		++prom_offset;
+		osp_MicroDelay(CYCLE_DELAY);
+	}
 }
-
-
-/*
-void osp_MicroDelay(int x) {
-    
-}
-*/
-
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index ded76c4..6174965 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -383,7 +383,7 @@
 
 	/* Anything but 'Showtime' is down */
 	if (strcmp(state_str, "Showtime")) {
-		card->atmdev[port]->signal = ATM_PHY_SIG_LOST;
+		atm_dev_signal_change(card->atmdev[port], ATM_PHY_SIG_LOST);
 		release_vccs(card->atmdev[port]);
 		dev_info(&card->dev->dev, "Port %d: %s\n", port, state_str);
 		return 0;
@@ -401,7 +401,7 @@
 		 snr[0]?", SNR ":"", snr, attn[0]?", Attn ":"", attn);
 	
 	card->atmdev[port]->link_rate = rate_down / 424;
-	card->atmdev[port]->signal = ATM_PHY_SIG_FOUND;
+	atm_dev_signal_change(card->atmdev[port], ATM_PHY_SIG_FOUND);
 
 	return 0;
 }
@@ -1246,7 +1246,7 @@
 		card->atmdev[i]->ci_range.vci_bits = 16;
 		card->atmdev[i]->dev_data = card;
 		card->atmdev[i]->phy_data = (void *)(unsigned long)i;
-		card->atmdev[i]->signal = ATM_PHY_SIG_UNKNOWN;
+		atm_dev_signal_change(card->atmdev[i], ATM_PHY_SIG_UNKNOWN);
 
 		skb = alloc_skb(sizeof(*header), GFP_ATOMIC);
 		if (!skb) {
diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c
index da4b91f..41c56ea 100644
--- a/drivers/atm/suni.c
+++ b/drivers/atm/suni.c
@@ -291,8 +291,9 @@
 
 static void poll_los(struct atm_dev *dev)
 {
-	dev->signal = GET(RSOP_SIS) & SUNI_RSOP_SIS_LOSV ? ATM_PHY_SIG_LOST :
-	  ATM_PHY_SIG_FOUND;
+	atm_dev_signal_change(dev,
+		GET(RSOP_SIS) & SUNI_RSOP_SIS_LOSV ?
+		ATM_PHY_SIG_LOST : ATM_PHY_SIG_FOUND);
 }
 
 
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 702acce..4e885d2 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -1637,10 +1637,8 @@
 MODULE_LICENSE("GPL");
 
 static struct pci_device_id zatm_pci_tbl[] __devinitdata = {
-	{ PCI_VENDOR_ID_ZEITNET, PCI_DEVICE_ID_ZEITNET_1221,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ZATM_COPPER },
-	{ PCI_VENDOR_ID_ZEITNET, PCI_DEVICE_ID_ZEITNET_1225,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VDEVICE(ZEITNET, PCI_DEVICE_ID_ZEITNET_1221), ZATM_COPPER },
+	{ PCI_VDEVICE(ZEITNET, PCI_DEVICE_ID_ZEITNET_1225), 0 },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, zatm_pci_tbl);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 9b9d3bd..f8e7272 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1819,3 +1819,67 @@
 	spin_unlock(&devices_kset->list_lock);
 	async_synchronize_full();
 }
+
+/*
+ * Device logging functions
+ */
+
+#ifdef CONFIG_PRINTK
+
+static int __dev_printk(const char *level, const struct device *dev,
+			struct va_format *vaf)
+{
+	if (!dev)
+		return printk("%s(NULL device *): %pV", level, vaf);
+
+	return printk("%s%s %s: %pV",
+		      level, dev_driver_string(dev), dev_name(dev), vaf);
+}
+
+int dev_printk(const char *level, const struct device *dev,
+	       const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+	int r;
+
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	r = __dev_printk(level, dev, &vaf);
+	va_end(args);
+
+	return r;
+}
+EXPORT_SYMBOL(dev_printk);
+
+#define define_dev_printk_level(func, kern_level)		\
+int func(const struct device *dev, const char *fmt, ...)	\
+{								\
+	struct va_format vaf;					\
+	va_list args;						\
+	int r;							\
+								\
+	va_start(args, fmt);					\
+								\
+	vaf.fmt = fmt;						\
+	vaf.va = &args;						\
+								\
+	r = __dev_printk(kern_level, dev, &vaf);		\
+	va_end(args);						\
+								\
+	return r;						\
+}								\
+EXPORT_SYMBOL(func);
+
+define_dev_printk_level(dev_emerg, KERN_EMERG);
+define_dev_printk_level(dev_alert, KERN_ALERT);
+define_dev_printk_level(dev_crit, KERN_CRIT);
+define_dev_printk_level(dev_err, KERN_ERR);
+define_dev_printk_level(dev_warn, KERN_WARNING);
+define_dev_printk_level(dev_notice, KERN_NOTICE);
+define_dev_printk_level(_dev_info, KERN_INFO);
+
+#endif
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 89de753..cbccf9a 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_PM)	+= sysfs.o
-obj-$(CONFIG_PM_SLEEP)	+= main.o
+obj-$(CONFIG_PM_SLEEP)	+= main.o wakeup.o
 obj-$(CONFIG_PM_RUNTIME)	+= runtime.o
 obj-$(CONFIG_PM_OPS)	+= generic_ops.o
 obj-$(CONFIG_PM_TRACE_RTC)	+= trace.o
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 941fcb8..5419a49 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -59,6 +59,7 @@
 {
 	dev->power.status = DPM_ON;
 	init_completion(&dev->power.completion);
+	dev->power.wakeup_count = 0;
 	pm_runtime_init(dev);
 }
 
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index b0ec0e9..b78c401 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -123,6 +123,45 @@
 }
 EXPORT_SYMBOL_GPL(pm_runtime_idle);
 
+
+/**
+ * update_pm_runtime_accounting - Update the time accounting of power states
+ * @dev: Device to update the accounting for
+ *
+ * In order to be able to have time accounting of the various power states
+ * (as used by programs such as PowerTOP to show the effectiveness of runtime
+ * PM), we need to track the time spent in each state.
+ * update_pm_runtime_accounting must be called each time before the
+ * runtime_status field is updated, to account the time in the old state
+ * correctly.
+ */
+void update_pm_runtime_accounting(struct device *dev)
+{
+	unsigned long now = jiffies;
+	int delta;
+
+	delta = now - dev->power.accounting_timestamp;
+
+	if (delta < 0)
+		delta = 0;
+
+	dev->power.accounting_timestamp = now;
+
+	if (dev->power.disable_depth > 0)
+		return;
+
+	if (dev->power.runtime_status == RPM_SUSPENDED)
+		dev->power.suspended_jiffies += delta;
+	else
+		dev->power.active_jiffies += delta;
+}
+
+static void __update_runtime_status(struct device *dev, enum rpm_status status)
+{
+	update_pm_runtime_accounting(dev);
+	dev->power.runtime_status = status;
+}
+
 /**
  * __pm_runtime_suspend - Carry out run-time suspend of given device.
  * @dev: Device to suspend.
@@ -197,7 +236,7 @@
 		goto repeat;
 	}
 
-	dev->power.runtime_status = RPM_SUSPENDING;
+	__update_runtime_status(dev, RPM_SUSPENDING);
 	dev->power.deferred_resume = false;
 
 	if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
@@ -228,7 +267,7 @@
 	}
 
 	if (retval) {
-		dev->power.runtime_status = RPM_ACTIVE;
+		__update_runtime_status(dev, RPM_ACTIVE);
 		if (retval == -EAGAIN || retval == -EBUSY) {
 			if (dev->power.timer_expires == 0)
 				notify = true;
@@ -237,7 +276,7 @@
 			pm_runtime_cancel_pending(dev);
 		}
 	} else {
-		dev->power.runtime_status = RPM_SUSPENDED;
+		__update_runtime_status(dev, RPM_SUSPENDED);
 		pm_runtime_deactivate_timer(dev);
 
 		if (dev->parent) {
@@ -381,7 +420,7 @@
 		goto repeat;
 	}
 
-	dev->power.runtime_status = RPM_RESUMING;
+	__update_runtime_status(dev, RPM_RESUMING);
 
 	if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) {
 		spin_unlock_irq(&dev->power.lock);
@@ -411,10 +450,10 @@
 	}
 
 	if (retval) {
-		dev->power.runtime_status = RPM_SUSPENDED;
+		__update_runtime_status(dev, RPM_SUSPENDED);
 		pm_runtime_cancel_pending(dev);
 	} else {
-		dev->power.runtime_status = RPM_ACTIVE;
+		__update_runtime_status(dev, RPM_ACTIVE);
 		if (parent)
 			atomic_inc(&parent->power.child_count);
 	}
@@ -848,7 +887,7 @@
 	}
 
  out_set:
-	dev->power.runtime_status = status;
+	__update_runtime_status(dev, status);
 	dev->power.runtime_error = 0;
  out:
 	spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -1077,6 +1116,7 @@
 	dev->power.request_pending = false;
 	dev->power.request = RPM_REQ_NONE;
 	dev->power.deferred_resume = false;
+	dev->power.accounting_timestamp = jiffies;
 	INIT_WORK(&dev->power.work, pm_runtime_work);
 
 	dev->power.timer_expires = 0;
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index a4c33bc..e56b438 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -6,6 +6,7 @@
 #include <linux/string.h>
 #include <linux/pm_runtime.h>
 #include <asm/atomic.h>
+#include <linux/jiffies.h>
 #include "power.h"
 
 /*
@@ -73,6 +74,8 @@
  *	device are known to the PM core.  However, for some devices this
  *	attribute is set to "enabled" by bus type code or device drivers and in
  *	that cases it should be safe to leave the default value.
+ *
+ *	wakeup_count - Report the number of wakeup events related to the device
  */
 
 static const char enabled[] = "enabled";
@@ -108,6 +111,65 @@
 }
 
 static DEVICE_ATTR(control, 0644, control_show, control_store);
+
+static ssize_t rtpm_active_time_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int ret;
+	spin_lock_irq(&dev->power.lock);
+	update_pm_runtime_accounting(dev);
+	ret = sprintf(buf, "%i\n", jiffies_to_msecs(dev->power.active_jiffies));
+	spin_unlock_irq(&dev->power.lock);
+	return ret;
+}
+
+static DEVICE_ATTR(runtime_active_time, 0444, rtpm_active_time_show, NULL);
+
+static ssize_t rtpm_suspended_time_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int ret;
+	spin_lock_irq(&dev->power.lock);
+	update_pm_runtime_accounting(dev);
+	ret = sprintf(buf, "%i\n",
+		jiffies_to_msecs(dev->power.suspended_jiffies));
+	spin_unlock_irq(&dev->power.lock);
+	return ret;
+}
+
+static DEVICE_ATTR(runtime_suspended_time, 0444, rtpm_suspended_time_show, NULL);
+
+static ssize_t rtpm_status_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	const char *p;
+
+	if (dev->power.runtime_error) {
+		p = "error\n";
+	} else if (dev->power.disable_depth) {
+		p = "unsupported\n";
+	} else {
+		switch (dev->power.runtime_status) {
+		case RPM_SUSPENDED:
+			p = "suspended\n";
+			break;
+		case RPM_SUSPENDING:
+			p = "suspending\n";
+			break;
+		case RPM_RESUMING:
+			p = "resuming\n";
+			break;
+		case RPM_ACTIVE:
+			p = "active\n";
+			break;
+		default:
+			return -EIO;
+		}
+	}
+	return sprintf(buf, p);
+}
+
+static DEVICE_ATTR(runtime_status, 0444, rtpm_status_show, NULL);
 #endif
 
 static ssize_t
@@ -144,6 +206,16 @@
 
 static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
 
+#ifdef CONFIG_PM_SLEEP
+static ssize_t wakeup_count_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%lu\n", dev->power.wakeup_count);
+}
+
+static DEVICE_ATTR(wakeup_count, 0444, wakeup_count_show, NULL);
+#endif
+
 #ifdef CONFIG_PM_ADVANCED_DEBUG
 #ifdef CONFIG_PM_RUNTIME
 
@@ -172,27 +244,8 @@
 	return sprintf(buf, "enabled\n");
 }
 
-static ssize_t rtpm_status_show(struct device *dev,
-				struct device_attribute *attr, char *buf)
-{
-	if (dev->power.runtime_error)
-		return sprintf(buf, "error\n");
-	switch (dev->power.runtime_status) {
-	case RPM_SUSPENDED:
-		return sprintf(buf, "suspended\n");
-	case RPM_SUSPENDING:
-		return sprintf(buf, "suspending\n");
-	case RPM_RESUMING:
-		return sprintf(buf, "resuming\n");
-	case RPM_ACTIVE:
-		return sprintf(buf, "active\n");
-	}
-	return -EIO;
-}
-
 static DEVICE_ATTR(runtime_usage, 0444, rtpm_usagecount_show, NULL);
 static DEVICE_ATTR(runtime_active_kids, 0444, rtpm_children_show, NULL);
-static DEVICE_ATTR(runtime_status, 0444, rtpm_status_show, NULL);
 static DEVICE_ATTR(runtime_enabled, 0444, rtpm_enabled_show, NULL);
 
 #endif
@@ -228,14 +281,19 @@
 static struct attribute * power_attrs[] = {
 #ifdef CONFIG_PM_RUNTIME
 	&dev_attr_control.attr,
+	&dev_attr_runtime_status.attr,
+	&dev_attr_runtime_suspended_time.attr,
+	&dev_attr_runtime_active_time.attr,
 #endif
 	&dev_attr_wakeup.attr,
+#ifdef CONFIG_PM_SLEEP
+	&dev_attr_wakeup_count.attr,
+#endif
 #ifdef CONFIG_PM_ADVANCED_DEBUG
 	&dev_attr_async.attr,
 #ifdef CONFIG_PM_RUNTIME
 	&dev_attr_runtime_usage.attr,
 	&dev_attr_runtime_active_kids.attr,
-	&dev_attr_runtime_status.attr,
 	&dev_attr_runtime_enabled.attr,
 #endif
 #endif
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
new file mode 100644
index 0000000..eb594fa
--- /dev/null
+++ b/drivers/base/power/wakeup.c
@@ -0,0 +1,247 @@
+/*
+ * drivers/base/power/wakeup.c - System wakeup events framework
+ *
+ * Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/capability.h>
+#include <linux/suspend.h>
+#include <linux/pm.h>
+
+/*
+ * If set, the suspend/hibernate code will abort transitions to a sleep state
+ * if wakeup events are registered during or immediately before the transition.
+ */
+bool events_check_enabled;
+
+/* The counter of registered wakeup events. */
+static unsigned long event_count;
+/* A preserved old value of event_count. */
+static unsigned long saved_event_count;
+/* The counter of wakeup events being processed. */
+static unsigned long events_in_progress;
+
+static DEFINE_SPINLOCK(events_lock);
+
+static void pm_wakeup_timer_fn(unsigned long data);
+
+static DEFINE_TIMER(events_timer, pm_wakeup_timer_fn, 0, 0);
+static unsigned long events_timer_expires;
+
+/*
+ * The functions below use the observation that each wakeup event starts a
+ * period in which the system should not be suspended.  The moment this period
+ * will end depends on how the wakeup event is going to be processed after being
+ * detected and all of the possible cases can be divided into two distinct
+ * groups.
+ *
+ * First, a wakeup event may be detected by the same functional unit that will
+ * carry out the entire processing of it and possibly will pass it to user space
+ * for further processing.  In that case the functional unit that has detected
+ * the event may later "close" the "no suspend" period associated with it
+ * directly as soon as it has been dealt with.  The pair of pm_stay_awake() and
+ * pm_relax(), balanced with each other, is supposed to be used in such
+ * situations.
+ *
+ * Second, a wakeup event may be detected by one functional unit and processed
+ * by another one.  In that case the unit that has detected it cannot really
+ * "close" the "no suspend" period associated with it, unless it knows in
+ * advance what's going to happen to the event during processing.  This
+ * knowledge, however, may not be available to it, so it can simply specify time
+ * to wait before the system can be suspended and pass it as the second
+ * argument of pm_wakeup_event().
+ */
+
+/**
+ * pm_stay_awake - Notify the PM core that a wakeup event is being processed.
+ * @dev: Device the wakeup event is related to.
+ *
+ * Notify the PM core of a wakeup event (signaled by @dev) by incrementing the
+ * counter of wakeup events being processed.  If @dev is not NULL, the counter
+ * of wakeup events related to @dev is incremented too.
+ *
+ * Call this function after detecting of a wakeup event if pm_relax() is going
+ * to be called directly after processing the event (and possibly passing it to
+ * user space for further processing).
+ *
+ * It is safe to call this function from interrupt context.
+ */
+void pm_stay_awake(struct device *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&events_lock, flags);
+	if (dev)
+		dev->power.wakeup_count++;
+
+	events_in_progress++;
+	spin_unlock_irqrestore(&events_lock, flags);
+}
+
+/**
+ * pm_relax - Notify the PM core that processing of a wakeup event has ended.
+ *
+ * Notify the PM core that a wakeup event has been processed by decrementing
+ * the counter of wakeup events being processed and incrementing the counter
+ * of registered wakeup events.
+ *
+ * Call this function for wakeup events whose processing started with calling
+ * pm_stay_awake().
+ *
+ * It is safe to call it from interrupt context.
+ */
+void pm_relax(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&events_lock, flags);
+	if (events_in_progress) {
+		events_in_progress--;
+		event_count++;
+	}
+	spin_unlock_irqrestore(&events_lock, flags);
+}
+
+/**
+ * pm_wakeup_timer_fn - Delayed finalization of a wakeup event.
+ *
+ * Decrease the counter of wakeup events being processed after it was increased
+ * by pm_wakeup_event().
+ */
+static void pm_wakeup_timer_fn(unsigned long data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&events_lock, flags);
+	if (events_timer_expires
+	    && time_before_eq(events_timer_expires, jiffies)) {
+		events_in_progress--;
+		events_timer_expires = 0;
+	}
+	spin_unlock_irqrestore(&events_lock, flags);
+}
+
+/**
+ * pm_wakeup_event - Notify the PM core of a wakeup event.
+ * @dev: Device the wakeup event is related to.
+ * @msec: Anticipated event processing time (in milliseconds).
+ *
+ * Notify the PM core of a wakeup event (signaled by @dev) that will take
+ * approximately @msec milliseconds to be processed by the kernel.  Increment
+ * the counter of registered wakeup events and (if @msec is nonzero) set up
+ * the wakeup events timer to execute pm_wakeup_timer_fn() in future (if the
+ * timer has not been set up already, increment the counter of wakeup events
+ * being processed).  If @dev is not NULL, the counter of wakeup events related
+ * to @dev is incremented too.
+ *
+ * It is safe to call this function from interrupt context.
+ */
+void pm_wakeup_event(struct device *dev, unsigned int msec)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&events_lock, flags);
+	event_count++;
+	if (dev)
+		dev->power.wakeup_count++;
+
+	if (msec) {
+		unsigned long expires;
+
+		expires = jiffies + msecs_to_jiffies(msec);
+		if (!expires)
+			expires = 1;
+
+		if (!events_timer_expires
+		    || time_after(expires, events_timer_expires)) {
+			if (!events_timer_expires)
+				events_in_progress++;
+
+			mod_timer(&events_timer, expires);
+			events_timer_expires = expires;
+		}
+	}
+	spin_unlock_irqrestore(&events_lock, flags);
+}
+
+/**
+ * pm_check_wakeup_events - Check for new wakeup events.
+ *
+ * Compare the current number of registered wakeup events with its preserved
+ * value from the past to check if new wakeup events have been registered since
+ * the old value was stored.  Check if the current number of wakeup events being
+ * processed is zero.
+ */
+bool pm_check_wakeup_events(void)
+{
+	unsigned long flags;
+	bool ret = true;
+
+	spin_lock_irqsave(&events_lock, flags);
+	if (events_check_enabled) {
+		ret = (event_count == saved_event_count) && !events_in_progress;
+		events_check_enabled = ret;
+	}
+	spin_unlock_irqrestore(&events_lock, flags);
+	return ret;
+}
+
+/**
+ * pm_get_wakeup_count - Read the number of registered wakeup events.
+ * @count: Address to store the value at.
+ *
+ * Store the number of registered wakeup events at the address in @count.  Block
+ * if the current number of wakeup events being processed is nonzero.
+ *
+ * Return false if the wait for the number of wakeup events being processed to
+ * drop down to zero has been interrupted by a signal (and the current number
+ * of wakeup events being processed is still nonzero).  Otherwise return true.
+ */
+bool pm_get_wakeup_count(unsigned long *count)
+{
+	bool ret;
+
+	spin_lock_irq(&events_lock);
+	if (capable(CAP_SYS_ADMIN))
+		events_check_enabled = false;
+
+	while (events_in_progress && !signal_pending(current)) {
+		spin_unlock_irq(&events_lock);
+
+		schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+		spin_lock_irq(&events_lock);
+	}
+	*count = event_count;
+	ret = !events_in_progress;
+	spin_unlock_irq(&events_lock);
+	return ret;
+}
+
+/**
+ * pm_save_wakeup_count - Save the current number of registered wakeup events.
+ * @count: Value to compare with the current number of registered wakeup events.
+ *
+ * If @count is equal to the current number of registered wakeup events and the
+ * current number of wakeup events being processed is zero, store @count as the
+ * old number of registered wakeup events to be used by pm_check_wakeup_events()
+ * and return true.  Otherwise return false.
+ */
+bool pm_save_wakeup_count(unsigned long count)
+{
+	bool ret = false;
+
+	spin_lock_irq(&events_lock);
+	if (count == event_count && !events_in_progress) {
+		saved_event_count = count;
+		events_check_enabled = true;
+		ret = true;
+	}
+	spin_unlock_irq(&events_lock);
+	return ret;
+}
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 058fbcc..02deef4 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -58,6 +58,18 @@
 
 	  Say Y here to compile support for HCI BCSP protocol.
 
+config BT_HCIUART_ATH3K
+	bool "Atheros AR300x serial support"
+	depends on BT_HCIUART
+	help
+	  HCIATH3K (HCI Atheros AR300x) is a serial protocol for
+	  communication between host and Atheros AR300x Bluetooth devices.
+	  This protocol enables AR300x chips to be enabled with
+	  power management support.
+	  Enable this if you have Atheros AR300x serial Bluetooth device.
+
+	  Say Y here to compile support for HCI UART ATH3K protocol.
+
 config BT_HCIUART_LL
 	bool "HCILL protocol support"
 	depends on BT_HCIUART
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 7e5aed5..71bdf13 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -26,4 +26,5 @@
 hci_uart-$(CONFIG_BT_HCIUART_H4)	+= hci_h4.o
 hci_uart-$(CONFIG_BT_HCIUART_BCSP)	+= hci_bcsp.o
 hci_uart-$(CONFIG_BT_HCIUART_LL)	+= hci_ll.o
+hci_uart-$(CONFIG_BT_HCIUART_ATH3K)	+= hci_ath.o
 hci_uart-objs				:= $(hci_uart-y)
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
index b0c84c1..8b1b643 100644
--- a/drivers/bluetooth/bcm203x.c
+++ b/drivers/bluetooth/bcm203x.c
@@ -224,7 +224,7 @@
 
 	BT_DBG("firmware data %p size %zu", firmware->data, firmware->size);
 
-	data->fw_data = kmalloc(firmware->size, GFP_KERNEL);
+	data->fw_data = kmemdup(firmware->data, firmware->size, GFP_KERNEL);
 	if (!data->fw_data) {
 		BT_ERR("Can't allocate memory for firmware image");
 		release_firmware(firmware);
@@ -234,7 +234,6 @@
 		return -ENOMEM;
 	}
 
-	memcpy(data->fw_data, firmware->data, firmware->size);
 	data->fw_size = firmware->size;
 	data->fw_sent = 0;
 
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index d945cd1..751b338 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -62,7 +62,7 @@
 	__u8    type;
 	__le16  snum;
 	__le16  dlen;
-} __attribute__ ((packed));
+} __packed;
 
 static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
 {
diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c
index b50b41d..54739b0 100644
--- a/drivers/bluetooth/btmrvl_debugfs.c
+++ b/drivers/bluetooth/btmrvl_debugfs.c
@@ -216,7 +216,7 @@
 static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,
 						size_t count, loff_t *ppos)
 {
-	struct btmrvl_private *priv = (struct btmrvl_private *) file->private_data;
+	struct btmrvl_private *priv = file->private_data;
 	char buf[16];
 	long result, ret;
 
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index bed0ba6..90bda50 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -76,6 +76,7 @@
 	int (*hw_host_to_card) (struct btmrvl_private *priv,
 				u8 *payload, u16 nb);
 	int (*hw_wakeup_firmware) (struct btmrvl_private *priv);
+	int (*hw_process_int_status) (struct btmrvl_private *priv);
 	spinlock_t driver_lock;		/* spinlock used by driver */
 #ifdef CONFIG_DEBUG_FS
 	void *debugfs_data;
@@ -118,13 +119,13 @@
 	__le16 ocf_ogf;
 	u8 length;
 	u8 data[4];
-} __attribute__ ((packed));
+} __packed;
 
 struct btmrvl_event {
 	u8 ec;		/* event counter */
 	u8 length;
 	u8 data[4];
-} __attribute__ ((packed));
+} __packed;
 
 /* Prototype of global function */
 
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index ee37ef0..0d32ec8 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -502,14 +502,17 @@
 		spin_lock_irqsave(&priv->driver_lock, flags);
 		if (adapter->int_count) {
 			adapter->int_count = 0;
+			spin_unlock_irqrestore(&priv->driver_lock, flags);
+			priv->hw_process_int_status(priv);
 		} else if (adapter->ps_state == PS_SLEEP &&
 					!skb_queue_empty(&adapter->tx_queue)) {
 			spin_unlock_irqrestore(&priv->driver_lock, flags);
 			adapter->wakeup_tries++;
 			priv->hw_wakeup_firmware(priv);
 			continue;
+		} else {
+			spin_unlock_irqrestore(&priv->driver_lock, flags);
 		}
-		spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 		if (adapter->ps_state == PS_SLEEP)
 			continue;
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index df0773e..dcc2a6e 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -47,6 +47,7 @@
  * module_exit function is called.
  */
 static u8 user_rmmod;
+static u8 sdio_ireg;
 
 static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
 	.helper		= "sd8688_helper.bin",
@@ -83,10 +84,10 @@
 	*dat = 0;
 
 	fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret);
+	if (ret)
+		return -EIO;
 
-	if (!ret)
-		fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);
-
+	fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);
 	if (ret)
 		return -EIO;
 
@@ -216,7 +217,7 @@
 
 	tmphlprbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
 
-	tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL);
+	tmphlprbuf = kzalloc(tmphlprbufsz, GFP_KERNEL);
 	if (!tmphlprbuf) {
 		BT_ERR("Unable to allocate buffer for helper."
 			" Terminating download");
@@ -224,8 +225,6 @@
 		goto done;
 	}
 
-	memset(tmphlprbuf, 0, tmphlprbufsz);
-
 	helperbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, BTSDIO_DMA_ALIGN);
 
 	/* Perform helper data transfer */
@@ -318,7 +317,7 @@
 	BT_DBG("Downloading FW image (%d bytes)", firmwarelen);
 
 	tmpfwbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
-	tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
+	tmpfwbuf = kzalloc(tmpfwbufsz, GFP_KERNEL);
 	if (!tmpfwbuf) {
 		BT_ERR("Unable to allocate buffer for firmware."
 		       " Terminating download");
@@ -326,8 +325,6 @@
 		goto done;
 	}
 
-	memset(tmpfwbuf, 0, tmpfwbufsz);
-
 	/* Ensure aligned firmware buffer */
 	fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, BTSDIO_DMA_ALIGN);
 
@@ -555,78 +552,79 @@
 	return ret;
 }
 
-static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg)
+static int btmrvl_sdio_process_int_status(struct btmrvl_private *priv)
 {
-	int ret;
-	u8 sdio_ireg = 0;
+	ulong flags;
+	u8 ireg;
 	struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
 
-	*ireg = 0;
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	ireg = sdio_ireg;
+	sdio_ireg = 0;
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
-	sdio_ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
-	if (ret) {
-		BT_ERR("sdio_readb: read int status register failed");
-		ret = -EIO;
-		goto done;
-	}
-
-	if (sdio_ireg != 0) {
-		/*
-		 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
-		 * Clear the interrupt status register and re-enable the
-		 * interrupt.
-		 */
-		BT_DBG("sdio_ireg = 0x%x", sdio_ireg);
-
-		sdio_writeb(card->func, ~(sdio_ireg) & (DN_LD_HOST_INT_STATUS |
-							UP_LD_HOST_INT_STATUS),
-			    HOST_INTSTATUS_REG, &ret);
-		if (ret) {
-			BT_ERR("sdio_writeb: clear int status register "
-				"failed");
-			ret = -EIO;
-			goto done;
-		}
-	}
-
-	if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
+	sdio_claim_host(card->func);
+	if (ireg & DN_LD_HOST_INT_STATUS) {
 		if (priv->btmrvl_dev.tx_dnld_rdy)
 			BT_DBG("tx_done already received: "
-				" int_status=0x%x", sdio_ireg);
+				" int_status=0x%x", ireg);
 		else
 			priv->btmrvl_dev.tx_dnld_rdy = true;
 	}
 
-	if (sdio_ireg & UP_LD_HOST_INT_STATUS)
+	if (ireg & UP_LD_HOST_INT_STATUS)
 		btmrvl_sdio_card_to_host(priv);
 
-	*ireg = sdio_ireg;
+	sdio_release_host(card->func);
 
-	ret = 0;
-
-done:
-	return ret;
+	return 0;
 }
 
 static void btmrvl_sdio_interrupt(struct sdio_func *func)
 {
 	struct btmrvl_private *priv;
-	struct hci_dev *hcidev;
 	struct btmrvl_sdio_card *card;
+	ulong flags;
 	u8 ireg = 0;
+	int ret;
 
 	card = sdio_get_drvdata(func);
-	if (card && card->priv) {
-		priv = card->priv;
-		hcidev = priv->btmrvl_dev.hcidev;
-
-		if (btmrvl_sdio_get_int_status(priv, &ireg))
-			BT_ERR("reading HOST_INT_STATUS_REG failed");
-		else
-			BT_DBG("HOST_INT_STATUS_REG %#x", ireg);
-
-		btmrvl_interrupt(priv);
+	if (!card || !card->priv) {
+		BT_ERR("sbi_interrupt(%p) card or priv is "
+				"NULL, card=%p\n", func, card);
+		return;
 	}
+
+	priv = card->priv;
+
+	ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
+	if (ret) {
+		BT_ERR("sdio_readb: read int status register failed");
+		return;
+	}
+
+	if (ireg != 0) {
+		/*
+		 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+		 * Clear the interrupt status register and re-enable the
+		 * interrupt.
+		 */
+		BT_DBG("ireg = 0x%x", ireg);
+
+		sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
+					UP_LD_HOST_INT_STATUS),
+				HOST_INTSTATUS_REG, &ret);
+		if (ret) {
+			BT_ERR("sdio_writeb: clear int status register failed");
+			return;
+		}
+	}
+
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	sdio_ireg |= ireg;
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+	btmrvl_interrupt(priv);
 }
 
 static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
@@ -930,6 +928,7 @@
 	/* Initialize the interface specific function pointers */
 	priv->hw_host_to_card = btmrvl_sdio_host_to_card;
 	priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
+	priv->hw_process_int_status = btmrvl_sdio_process_int_status;
 
 	if (btmrvl_register_hdev(priv)) {
 		BT_ERR("Register hdev failed!");
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 5d9cc53..d22ce3c 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -59,6 +59,9 @@
 	/* Generic Bluetooth USB device */
 	{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
 
+	/* Apple iMac11,1 */
+	{ USB_DEVICE(0x05ac, 0x8215) },
+
 	/* AVM BlueFRITZ! USB v2.0 */
 	{ USB_DEVICE(0x057c, 0x3800) },
 
@@ -146,6 +149,7 @@
 #define BTUSB_BULK_RUNNING	1
 #define BTUSB_ISOC_RUNNING	2
 #define BTUSB_SUSPENDING	3
+#define BTUSB_DID_ISO_RESUME	4
 
 struct btusb_data {
 	struct hci_dev       *hdev;
@@ -179,7 +183,6 @@
 	unsigned int sco_num;
 	int isoc_altsetting;
 	int suspend_count;
-	int did_iso_resume:1;
 };
 
 static int inc_tx(struct btusb_data *data)
@@ -807,7 +810,7 @@
 	int err;
 
 	if (hdev->conn_hash.sco_num > 0) {
-		if (!data->did_iso_resume) {
+		if (!test_bit(BTUSB_DID_ISO_RESUME, &data->flags)) {
 			err = usb_autopm_get_interface(data->isoc);
 			if (err < 0) {
 				clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
@@ -815,7 +818,7 @@
 				return;
 			}
 
-			data->did_iso_resume = 1;
+			set_bit(BTUSB_DID_ISO_RESUME, &data->flags);
 		}
 		if (data->isoc_altsetting != 2) {
 			clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
@@ -836,10 +839,8 @@
 		usb_kill_anchored_urbs(&data->isoc_anchor);
 
 		__set_isoc_interface(hdev, 0);
-		if (data->did_iso_resume) {
-			data->did_iso_resume = 0;
+		if (test_and_clear_bit(BTUSB_DID_ISO_RESUME, &data->flags))
 			usb_autopm_put_interface(data->isoc);
-		}
 	}
 }
 
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index ef044d5..cbe9e44 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -104,7 +104,7 @@
 	u8 type;
 	u8 zero;
 	u16 len;
-} __attribute__ ((packed)) nsh_t;	/* Nokia Specific Header */
+} __packed nsh_t;	/* Nokia Specific Header */
 
 #define NSHL  4				/* Nokia Specific Header Length */
 
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
new file mode 100644
index 0000000..6a160c1
--- /dev/null
+++ b/drivers/bluetooth/hci_ath.c
@@ -0,0 +1,235 @@
+/*
+ *  Atheros Communication Bluetooth HCIATH3K UART protocol
+ *
+ *  HCIATH3K (HCI Atheros AR300x Protocol) is a Atheros Communication's
+ *  power management protocol extension to H4 to support AR300x Bluetooth Chip.
+ *
+ *  Copyright (c) 2009-2010 Atheros Communications Inc.
+ *
+ *  Acknowledgements:
+ *  This file is based on hci_h4.c, which was written
+ *  by Maxim Krasnyansky and Marcel Holtmann.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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/kernel.h>
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+
+struct ath_struct {
+	struct hci_uart *hu;
+	unsigned int cur_sleep;
+
+	struct sk_buff_head txq;
+	struct work_struct ctxtsw;
+};
+
+static int ath_wakeup_ar3k(struct tty_struct *tty)
+{
+	struct termios settings;
+	int status = tty->driver->ops->tiocmget(tty, NULL);
+
+	if (status & TIOCM_CTS)
+		return status;
+
+	/* Disable Automatic RTSCTS */
+	n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
+	settings.c_cflag &= ~CRTSCTS;
+	n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
+
+	/* Clear RTS first */
+	status = tty->driver->ops->tiocmget(tty, NULL);
+	tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
+	mdelay(20);
+
+	/* Set RTS, wake up board */
+	status = tty->driver->ops->tiocmget(tty, NULL);
+	tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
+	mdelay(20);
+
+	status = tty->driver->ops->tiocmget(tty, NULL);
+
+	n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
+	settings.c_cflag |= CRTSCTS;
+	n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
+
+	return status;
+}
+
+static void ath_hci_uart_work(struct work_struct *work)
+{
+	int status;
+	struct ath_struct *ath;
+	struct hci_uart *hu;
+	struct tty_struct *tty;
+
+	ath = container_of(work, struct ath_struct, ctxtsw);
+
+	hu = ath->hu;
+	tty = hu->tty;
+
+	/* verify and wake up controller */
+	if (ath->cur_sleep) {
+		status = ath_wakeup_ar3k(tty);
+		if (!(status & TIOCM_CTS))
+			return;
+	}
+
+	/* Ready to send Data */
+	clear_bit(HCI_UART_SENDING, &hu->tx_state);
+	hci_uart_tx_wakeup(hu);
+}
+
+/* Initialize protocol */
+static int ath_open(struct hci_uart *hu)
+{
+	struct ath_struct *ath;
+
+	BT_DBG("hu %p", hu);
+
+	ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
+	if (!ath)
+		return -ENOMEM;
+
+	skb_queue_head_init(&ath->txq);
+
+	hu->priv = ath;
+	ath->hu = hu;
+
+	INIT_WORK(&ath->ctxtsw, ath_hci_uart_work);
+
+	return 0;
+}
+
+/* Flush protocol data */
+static int ath_flush(struct hci_uart *hu)
+{
+	struct ath_struct *ath = hu->priv;
+
+	BT_DBG("hu %p", hu);
+
+	skb_queue_purge(&ath->txq);
+
+	return 0;
+}
+
+/* Close protocol */
+static int ath_close(struct hci_uart *hu)
+{
+	struct ath_struct *ath = hu->priv;
+
+	BT_DBG("hu %p", hu);
+
+	skb_queue_purge(&ath->txq);
+
+	cancel_work_sync(&ath->ctxtsw);
+
+	hu->priv = NULL;
+	kfree(ath);
+
+	return 0;
+}
+
+#define HCI_OP_ATH_SLEEP 0xFC04
+
+/* Enqueue frame for transmittion */
+static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+	struct ath_struct *ath = hu->priv;
+
+	if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
+		kfree_skb(skb);
+		return 0;
+	}
+
+	/*
+	 * Update power management enable flag with parameters of
+	 * HCI sleep enable vendor specific HCI command.
+	 */
+	if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
+		struct hci_command_hdr *hdr = (void *)skb->data;
+
+		if (__le16_to_cpu(hdr->opcode) == HCI_OP_ATH_SLEEP)
+			ath->cur_sleep = skb->data[HCI_COMMAND_HDR_SIZE];
+	}
+
+	BT_DBG("hu %p skb %p", hu, skb);
+
+	/* Prepend skb with frame type */
+	memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+	skb_queue_tail(&ath->txq, skb);
+	set_bit(HCI_UART_SENDING, &hu->tx_state);
+
+	schedule_work(&ath->ctxtsw);
+
+	return 0;
+}
+
+static struct sk_buff *ath_dequeue(struct hci_uart *hu)
+{
+	struct ath_struct *ath = hu->priv;
+
+	return skb_dequeue(&ath->txq);
+}
+
+/* Recv data */
+static int ath_recv(struct hci_uart *hu, void *data, int count)
+{
+	if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
+		BT_ERR("Frame Reassembly Failed");
+
+	return count;
+}
+
+static struct hci_uart_proto athp = {
+	.id = HCI_UART_ATH3K,
+	.open = ath_open,
+	.close = ath_close,
+	.recv = ath_recv,
+	.enqueue = ath_enqueue,
+	.dequeue = ath_dequeue,
+	.flush = ath_flush,
+};
+
+int __init ath_init(void)
+{
+	int err = hci_uart_register_proto(&athp);
+
+	if (!err)
+		BT_INFO("HCIATH3K protocol initialized");
+	else
+		BT_ERR("HCIATH3K protocol registration failed");
+
+	return err;
+}
+
+int __exit ath_deinit(void)
+{
+	return hci_uart_unregister_proto(&athp);
+}
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 42d69d4..9c5b2dc 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -739,7 +739,7 @@
 	.flush		= bcsp_flush
 };
 
-int bcsp_init(void)
+int __init bcsp_init(void)
 {
 	int err = hci_uart_register_proto(&bcsp);
 
@@ -751,7 +751,7 @@
 	return err;
 }
 
-int bcsp_deinit(void)
+int __exit bcsp_deinit(void)
 {
 	return hci_uart_unregister_proto(&bcsp);
 }
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index 3f038f5..7b8ad93 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -151,107 +151,8 @@
 /* Recv data */
 static int h4_recv(struct hci_uart *hu, void *data, int count)
 {
-	struct h4_struct *h4 = hu->priv;
-	register char *ptr;
-	struct hci_event_hdr *eh;
-	struct hci_acl_hdr   *ah;
-	struct hci_sco_hdr   *sh;
-	register int len, type, dlen;
-
-	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
-			hu, count, h4->rx_state, h4->rx_count);
-
-	ptr = data;
-	while (count) {
-		if (h4->rx_count) {
-			len = min_t(unsigned int, h4->rx_count, count);
-			memcpy(skb_put(h4->rx_skb, len), ptr, len);
-			h4->rx_count -= len; count -= len; ptr += len;
-
-			if (h4->rx_count)
-				continue;
-
-			switch (h4->rx_state) {
-			case H4_W4_DATA:
-				BT_DBG("Complete data");
-
-				hci_recv_frame(h4->rx_skb);
-
-				h4->rx_state = H4_W4_PACKET_TYPE;
-				h4->rx_skb = NULL;
-				continue;
-
-			case H4_W4_EVENT_HDR:
-				eh = hci_event_hdr(h4->rx_skb);
-
-				BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
-
-				h4_check_data_len(h4, eh->plen);
-				continue;
-
-			case H4_W4_ACL_HDR:
-				ah = hci_acl_hdr(h4->rx_skb);
-				dlen = __le16_to_cpu(ah->dlen);
-
-				BT_DBG("ACL header: dlen %d", dlen);
-
-				h4_check_data_len(h4, dlen);
-				continue;
-
-			case H4_W4_SCO_HDR:
-				sh = hci_sco_hdr(h4->rx_skb);
-
-				BT_DBG("SCO header: dlen %d", sh->dlen);
-
-				h4_check_data_len(h4, sh->dlen);
-				continue;
-			}
-		}
-
-		/* H4_W4_PACKET_TYPE */
-		switch (*ptr) {
-		case HCI_EVENT_PKT:
-			BT_DBG("Event packet");
-			h4->rx_state = H4_W4_EVENT_HDR;
-			h4->rx_count = HCI_EVENT_HDR_SIZE;
-			type = HCI_EVENT_PKT;
-			break;
-
-		case HCI_ACLDATA_PKT:
-			BT_DBG("ACL packet");
-			h4->rx_state = H4_W4_ACL_HDR;
-			h4->rx_count = HCI_ACL_HDR_SIZE;
-			type = HCI_ACLDATA_PKT;
-			break;
-
-		case HCI_SCODATA_PKT:
-			BT_DBG("SCO packet");
-			h4->rx_state = H4_W4_SCO_HDR;
-			h4->rx_count = HCI_SCO_HDR_SIZE;
-			type = HCI_SCODATA_PKT;
-			break;
-
-		default:
-			BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
-			hu->hdev->stat.err_rx++;
-			ptr++; count--;
-			continue;
-		};
-
-		ptr++; count--;
-
-		/* Allocate packet */
-		h4->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
-		if (!h4->rx_skb) {
-			BT_ERR("Can't allocate mem for new packet");
-			h4->rx_state = H4_W4_PACKET_TYPE;
-			h4->rx_count = 0;
-			return -ENOMEM;
-		}
-
-		h4->rx_skb->dev = (void *) hu->hdev;
-		bt_cb(h4->rx_skb)->pkt_type = type;
-	}
+	if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
+		BT_ERR("Frame Reassembly Failed");
 
 	return count;
 }
@@ -272,7 +173,7 @@
 	.flush		= h4_flush,
 };
 
-int h4_init(void)
+int __init h4_init(void)
 {
 	int err = hci_uart_register_proto(&h4p);
 
@@ -284,7 +185,7 @@
 	return err;
 }
 
-int h4_deinit(void)
+int __exit h4_deinit(void)
 {
 	return hci_uart_unregister_proto(&h4p);
 }
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 76a1abb..998833d 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -210,7 +210,6 @@
 static int hci_uart_send_frame(struct sk_buff *skb)
 {
 	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
-	struct tty_struct *tty;
 	struct hci_uart *hu;
 
 	if (!hdev) {
@@ -222,7 +221,6 @@
 		return -EBUSY;
 
 	hu = (struct hci_uart *) hdev->driver_data;
-	tty = hu->tty;
 
 	BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
 
@@ -397,6 +395,9 @@
 	if (!reset)
 		set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
 
+	if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
+		set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
+
 	if (hci_register_dev(hdev) < 0) {
 		BT_ERR("Can't register HCI device");
 		hci_free_dev(hdev);
@@ -477,6 +478,15 @@
 			return hu->hdev->id;
 		return -EUNATCH;
 
+	case HCIUARTSETFLAGS:
+		if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+			return -EBUSY;
+		hu->hdev_flags = arg;
+		break;
+
+	case HCIUARTGETFLAGS:
+		return hu->hdev_flags;
+
 	default:
 		err = n_tty_ioctl_helper(tty, file, cmd, arg);
 		break;
@@ -542,6 +552,9 @@
 #ifdef CONFIG_BT_HCIUART_LL
 	ll_init();
 #endif
+#ifdef CONFIG_BT_HCIUART_ATH3K
+	ath_init();
+#endif
 
 	return 0;
 }
@@ -559,6 +572,9 @@
 #ifdef CONFIG_BT_HCIUART_LL
 	ll_deinit();
 #endif
+#ifdef CONFIG_BT_HCIUART_ATH3K
+	ath_deinit();
+#endif
 
 	/* Release tty registration of line discipline */
 	if ((err = tty_unregister_ldisc(N_HCI)))
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index fb8445c..38595e7 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -74,7 +74,7 @@
 
 struct hcill_cmd {
 	u8 cmd;
-} __attribute__((packed));
+} __packed;
 
 struct ll_struct {
 	unsigned long rx_state;
@@ -517,7 +517,7 @@
 	.flush		= ll_flush,
 };
 
-int ll_init(void)
+int __init ll_init(void)
 {
 	int err = hci_uart_register_proto(&llp);
 
@@ -529,7 +529,7 @@
 	return err;
 }
 
-int ll_deinit(void)
+int __exit ll_deinit(void)
 {
 	return hci_uart_unregister_proto(&llp);
 }
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 50113db..99fb352 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -31,15 +31,20 @@
 #define HCIUARTSETPROTO		_IOW('U', 200, int)
 #define HCIUARTGETPROTO		_IOR('U', 201, int)
 #define HCIUARTGETDEVICE	_IOR('U', 202, int)
+#define HCIUARTSETFLAGS		_IOW('U', 203, int)
+#define HCIUARTGETFLAGS		_IOR('U', 204, int)
 
 /* UART protocols */
-#define HCI_UART_MAX_PROTO	5
+#define HCI_UART_MAX_PROTO	6
 
 #define HCI_UART_H4	0
 #define HCI_UART_BCSP	1
 #define HCI_UART_3WIRE	2
 #define HCI_UART_H4DS	3
 #define HCI_UART_LL	4
+#define HCI_UART_ATH3K	5
+
+#define HCI_UART_RAW_DEVICE	0
 
 struct hci_uart;
 
@@ -57,6 +62,7 @@
 	struct tty_struct	*tty;
 	struct hci_dev		*hdev;
 	unsigned long		flags;
+	unsigned long		hdev_flags;
 
 	struct hci_uart_proto	*proto;
 	void			*priv;
@@ -66,7 +72,7 @@
 	spinlock_t		rx_lock;
 };
 
-/* HCI_UART flag bits */
+/* HCI_UART proto flag bits */
 #define HCI_UART_PROTO_SET	0
 
 /* TX states  */
@@ -91,3 +97,8 @@
 int ll_init(void);
 int ll_deinit(void);
 #endif
+
+#ifdef CONFIG_BT_HCIUART_ATH3K
+int ath_init(void);
+int ath_deinit(void);
+#endif
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
index 0f9cbf1..101d5f2 100644
--- a/drivers/char/hw_random/n2-drv.c
+++ b/drivers/char/hw_random/n2-drv.c
@@ -387,7 +387,7 @@
 
 static int n2rng_data_read(struct hwrng *rng, u32 *data)
 {
-	struct n2rng *np = (struct n2rng *) rng->priv;
+	struct n2rng *np = rng->priv;
 	unsigned long ra = __pa(&np->test_data);
 	int len;
 
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 54109dc..25be210 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -1315,10 +1315,14 @@
 	if (test_bit(EV_SND, dev->evbit))
 		return true;
 
-	if (test_bit(EV_KEY, dev->evbit))
+	if (test_bit(EV_KEY, dev->evbit)) {
 		for (i = KEY_RESERVED; i < BTN_MISC; i++)
 			if (test_bit(i, dev->keybit))
 				return true;
+		for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++)
+			if (test_bit(i, dev->keybit))
+				return true;
+	}
 
 	return false;
 }
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 8d85587..caef35a 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -407,8 +407,8 @@
 	struct poolinfo *poolinfo;
 	__u32 *pool;
 	const char *name;
-	int limit;
 	struct entropy_store *pull;
+	int limit;
 
 	/* read-write data: */
 	spinlock_t lock;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 938b74e..199dcb9 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -29,6 +29,8 @@
 #include <linux/completion.h>
 #include <linux/mutex.h>
 
+#include <trace/events/power.h>
+
 #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \
 						"cpufreq-core", msg)
 
@@ -68,7 +70,7 @@
 static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
 
 #define lock_policy_rwsem(mode, cpu)					\
-int lock_policy_rwsem_##mode						\
+static int lock_policy_rwsem_##mode					\
 (int cpu)								\
 {									\
 	int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);		\
@@ -83,26 +85,22 @@
 }
 
 lock_policy_rwsem(read, cpu);
-EXPORT_SYMBOL_GPL(lock_policy_rwsem_read);
 
 lock_policy_rwsem(write, cpu);
-EXPORT_SYMBOL_GPL(lock_policy_rwsem_write);
 
-void unlock_policy_rwsem_read(int cpu)
+static void unlock_policy_rwsem_read(int cpu)
 {
 	int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
 	BUG_ON(policy_cpu == -1);
 	up_read(&per_cpu(cpu_policy_rwsem, policy_cpu));
 }
-EXPORT_SYMBOL_GPL(unlock_policy_rwsem_read);
 
-void unlock_policy_rwsem_write(int cpu)
+static void unlock_policy_rwsem_write(int cpu)
 {
 	int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
 	BUG_ON(policy_cpu == -1);
 	up_write(&per_cpu(cpu_policy_rwsem, policy_cpu));
 }
-EXPORT_SYMBOL_GPL(unlock_policy_rwsem_write);
 
 
 /* internal prototypes */
@@ -354,6 +352,9 @@
 
 	case CPUFREQ_POSTCHANGE:
 		adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
+		dprintk("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
+			(unsigned long)freqs->cpu);
+		trace_power_frequency(POWER_PSTATE, freqs->new, freqs->cpu);
 		srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
 				CPUFREQ_POSTCHANGE, freqs);
 		if (likely(policy) && likely(policy->cpu == freqs->cpu))
@@ -1875,8 +1876,7 @@
 	return NOTIFY_OK;
 }
 
-static struct notifier_block __refdata cpufreq_cpu_notifier =
-{
+static struct notifier_block __refdata cpufreq_cpu_notifier = {
     .notifier_call = cpufreq_cpu_callback,
 };
 
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index e131421..7b50936 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -459,6 +459,17 @@
 
 /************************** sysfs end ************************/
 
+static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq)
+{
+	if (dbs_tuners_ins.powersave_bias)
+		freq = powersave_bias_target(p, freq, CPUFREQ_RELATION_H);
+	else if (p->cur == p->max)
+		return;
+
+	__cpufreq_driver_target(p, freq, dbs_tuners_ins.powersave_bias ?
+			CPUFREQ_RELATION_L : CPUFREQ_RELATION_H);
+}
+
 static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
 {
 	unsigned int max_load_freq;
@@ -551,19 +562,7 @@
 
 	/* Check for frequency increase */
 	if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) {
-		/* if we are already at full speed then break out early */
-		if (!dbs_tuners_ins.powersave_bias) {
-			if (policy->cur == policy->max)
-				return;
-
-			__cpufreq_driver_target(policy, policy->max,
-				CPUFREQ_RELATION_H);
-		} else {
-			int freq = powersave_bias_target(policy, policy->max,
-					CPUFREQ_RELATION_H);
-			__cpufreq_driver_target(policy, freq,
-				CPUFREQ_RELATION_L);
-		}
+		dbs_freq_increase(policy, policy->max);
 		return;
 	}
 
@@ -610,7 +609,9 @@
 	/* We want all CPUs to do sampling nearly on same jiffy */
 	int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
 
-	delay -= jiffies % delay;
+	if (num_online_cpus() > 1)
+		delay -= jiffies % delay;
+
 	mutex_lock(&dbs_info->timer_mutex);
 
 	/* Common NORMAL_SAMPLE setup */
@@ -635,7 +636,9 @@
 {
 	/* We want all CPUs to do sampling nearly on same jiffy */
 	int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
-	delay -= jiffies % delay;
+
+	if (num_online_cpus() > 1)
+		delay -= jiffies % delay;
 
 	dbs_info->sample_type = DBS_NORMAL_SAMPLE;
 	INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 1994885..dbefe15 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -95,7 +95,7 @@
 	/* give the governor an opportunity to reflect on the outcome */
 	if (cpuidle_curr_governor->reflect)
 		cpuidle_curr_governor->reflect(dev);
-	trace_power_end(0);
+	trace_power_end(smp_processor_id());
 }
 
 /**
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c
index 09389dd..219d09c 100644
--- a/drivers/crypto/geode-aes.c
+++ b/drivers/crypto/geode-aes.c
@@ -573,7 +573,7 @@
 }
 
 static struct pci_device_id geode_aes_tbl[] = {
-	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, PCI_ANY_ID, PCI_ANY_ID} ,
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_LX_AES), } ,
 	{ 0, }
 };
 
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index 16fce3a..e449ac5 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -2018,7 +2018,6 @@
 {
 	unsigned long flags;
 	struct crypto_async_request *async_req;
-	struct hifn_context *ctx;
 	struct ablkcipher_request *req;
 	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
 	int i;
@@ -2035,7 +2034,6 @@
 
 	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);
 
@@ -2139,7 +2137,6 @@
 static int hifn_process_queue(struct hifn_device *dev)
 {
 	struct crypto_async_request *async_req, *backlog;
-	struct hifn_context *ctx;
 	struct ablkcipher_request *req;
 	unsigned long flags;
 	int err = 0;
@@ -2156,7 +2153,6 @@
 		if (backlog)
 			backlog->complete(backlog, -EINPROGRESS);
 
-		ctx = crypto_tfm_ctx(async_req->tfm);
 		req = container_of(async_req, struct ablkcipher_request, base);
 
 		err = hifn_handle_req(req);
diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c
index e095422..7d279e5 100644
--- a/drivers/crypto/mv_cesa.c
+++ b/drivers/crypto/mv_cesa.c
@@ -1055,20 +1055,20 @@
 	cp->queue_th = kthread_run(queue_manag, cp, "mv_crypto");
 	if (IS_ERR(cp->queue_th)) {
 		ret = PTR_ERR(cp->queue_th);
-		goto err_thread;
+		goto err_unmap_sram;
 	}
 
 	ret = request_irq(irq, crypto_int, IRQF_DISABLED, dev_name(&pdev->dev),
 			cp);
 	if (ret)
-		goto err_unmap_sram;
+		goto err_thread;
 
 	writel(SEC_INT_ACCEL0_DONE, cpg->reg + SEC_ACCEL_INT_MASK);
 	writel(SEC_CFG_STOP_DIG_ERR, cpg->reg + SEC_ACCEL_CFG);
 
 	ret = crypto_register_alg(&mv_aes_alg_ecb);
 	if (ret)
-		goto err_reg;
+		goto err_irq;
 
 	ret = crypto_register_alg(&mv_aes_alg_cbc);
 	if (ret)
@@ -1091,9 +1091,9 @@
 	return 0;
 err_unreg_ecb:
 	crypto_unregister_alg(&mv_aes_alg_ecb);
-err_thread:
+err_irq:
 	free_irq(irq, cp);
-err_reg:
+err_thread:
 	kthread_stop(cp->queue_th);
 err_unmap_sram:
 	iounmap(cp->sram);
diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c
index 23163fd..b99c38f 100644
--- a/drivers/crypto/n2_core.c
+++ b/drivers/crypto/n2_core.c
@@ -239,21 +239,57 @@
 }
 #endif
 
-struct n2_base_ctx {
-	struct list_head		list;
+struct n2_ahash_alg {
+	struct list_head	entry;
+	const char		*hash_zero;
+	const u32		*hash_init;
+	u8			hw_op_hashsz;
+	u8			digest_size;
+	u8			auth_type;
+	u8			hmac_type;
+	struct ahash_alg	alg;
 };
 
-static void n2_base_ctx_init(struct n2_base_ctx *ctx)
+static inline struct n2_ahash_alg *n2_ahash_alg(struct crypto_tfm *tfm)
 {
-	INIT_LIST_HEAD(&ctx->list);
+	struct crypto_alg *alg = tfm->__crt_alg;
+	struct ahash_alg *ahash_alg;
+
+	ahash_alg = container_of(alg, struct ahash_alg, halg.base);
+
+	return container_of(ahash_alg, struct n2_ahash_alg, alg);
+}
+
+struct n2_hmac_alg {
+	const char		*child_alg;
+	struct n2_ahash_alg	derived;
+};
+
+static inline struct n2_hmac_alg *n2_hmac_alg(struct crypto_tfm *tfm)
+{
+	struct crypto_alg *alg = tfm->__crt_alg;
+	struct ahash_alg *ahash_alg;
+
+	ahash_alg = container_of(alg, struct ahash_alg, halg.base);
+
+	return container_of(ahash_alg, struct n2_hmac_alg, derived.alg);
 }
 
 struct n2_hash_ctx {
-	struct n2_base_ctx		base;
-
 	struct crypto_ahash		*fallback_tfm;
 };
 
+#define N2_HASH_KEY_MAX			32 /* HW limit for all HMAC requests */
+
+struct n2_hmac_ctx {
+	struct n2_hash_ctx		base;
+
+	struct crypto_shash		*child_shash;
+
+	int				hash_key_len;
+	unsigned char			hash_key[N2_HASH_KEY_MAX];
+};
+
 struct n2_hash_req_ctx {
 	union {
 		struct md5_state	md5;
@@ -261,9 +297,6 @@
 		struct sha256_state	sha256;
 	} u;
 
-	unsigned char			hash_key[64];
-	unsigned char			keyed_zero_hash[32];
-
 	struct ahash_request		fallback_req;
 };
 
@@ -356,6 +389,94 @@
 	crypto_free_ahash(ctx->fallback_tfm);
 }
 
+static int n2_hmac_cra_init(struct crypto_tfm *tfm)
+{
+	const char *fallback_driver_name = tfm->__crt_alg->cra_name;
+	struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
+	struct n2_hmac_ctx *ctx = crypto_ahash_ctx(ahash);
+	struct n2_hmac_alg *n2alg = n2_hmac_alg(tfm);
+	struct crypto_ahash *fallback_tfm;
+	struct crypto_shash *child_shash;
+	int err;
+
+	fallback_tfm = crypto_alloc_ahash(fallback_driver_name, 0,
+					  CRYPTO_ALG_NEED_FALLBACK);
+	if (IS_ERR(fallback_tfm)) {
+		pr_warning("Fallback driver '%s' could not be loaded!\n",
+			   fallback_driver_name);
+		err = PTR_ERR(fallback_tfm);
+		goto out;
+	}
+
+	child_shash = crypto_alloc_shash(n2alg->child_alg, 0, 0);
+	if (IS_ERR(child_shash)) {
+		pr_warning("Child shash '%s' could not be loaded!\n",
+			   n2alg->child_alg);
+		err = PTR_ERR(child_shash);
+		goto out_free_fallback;
+	}
+
+	crypto_ahash_set_reqsize(ahash, (sizeof(struct n2_hash_req_ctx) +
+					 crypto_ahash_reqsize(fallback_tfm)));
+
+	ctx->child_shash = child_shash;
+	ctx->base.fallback_tfm = fallback_tfm;
+	return 0;
+
+out_free_fallback:
+	crypto_free_ahash(fallback_tfm);
+
+out:
+	return err;
+}
+
+static void n2_hmac_cra_exit(struct crypto_tfm *tfm)
+{
+	struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
+	struct n2_hmac_ctx *ctx = crypto_ahash_ctx(ahash);
+
+	crypto_free_ahash(ctx->base.fallback_tfm);
+	crypto_free_shash(ctx->child_shash);
+}
+
+static int n2_hmac_async_setkey(struct crypto_ahash *tfm, const u8 *key,
+				unsigned int keylen)
+{
+	struct n2_hmac_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct crypto_shash *child_shash = ctx->child_shash;
+	struct crypto_ahash *fallback_tfm;
+	struct {
+		struct shash_desc shash;
+		char ctx[crypto_shash_descsize(child_shash)];
+	} desc;
+	int err, bs, ds;
+
+	fallback_tfm = ctx->base.fallback_tfm;
+	err = crypto_ahash_setkey(fallback_tfm, key, keylen);
+	if (err)
+		return err;
+
+	desc.shash.tfm = child_shash;
+	desc.shash.flags = crypto_ahash_get_flags(tfm) &
+		CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	bs = crypto_shash_blocksize(child_shash);
+	ds = crypto_shash_digestsize(child_shash);
+	BUG_ON(ds > N2_HASH_KEY_MAX);
+	if (keylen > bs) {
+		err = crypto_shash_digest(&desc.shash, key, keylen,
+					  ctx->hash_key);
+		if (err)
+			return err;
+		keylen = ds;
+	} else if (keylen <= N2_HASH_KEY_MAX)
+		memcpy(ctx->hash_key, key, keylen);
+
+	ctx->hash_key_len = keylen;
+
+	return err;
+}
+
 static unsigned long wait_for_tail(struct spu_queue *qp)
 {
 	unsigned long head, hv_ret;
@@ -385,12 +506,12 @@
 	return hv_ret;
 }
 
-static int n2_hash_async_digest(struct ahash_request *req,
-				unsigned int auth_type, unsigned int digest_size,
-				unsigned int result_size, void *hash_loc)
+static int n2_do_async_digest(struct ahash_request *req,
+			      unsigned int auth_type, unsigned int digest_size,
+			      unsigned int result_size, void *hash_loc,
+			      unsigned long auth_key, unsigned int auth_key_len)
 {
 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
-	struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
 	struct cwq_initial_entry *ent;
 	struct crypto_hash_walk walk;
 	struct spu_queue *qp;
@@ -403,6 +524,7 @@
 	 */
 	if (unlikely(req->nbytes > (1 << 16))) {
 		struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
+		struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
 
 		ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
 		rctx->fallback_req.base.flags =
@@ -414,8 +536,6 @@
 		return crypto_ahash_digest(&rctx->fallback_req);
 	}
 
-	n2_base_ctx_init(&ctx->base);
-
 	nbytes = crypto_hash_walk_first(req, &walk);
 
 	cpu = get_cpu();
@@ -430,13 +550,13 @@
 	 */
 	ent = qp->q + qp->tail;
 
-	ent->control = control_word_base(nbytes, 0, 0,
+	ent->control = control_word_base(nbytes, auth_key_len, 0,
 					 auth_type, digest_size,
 					 false, true, false, false,
 					 OPCODE_INPLACE_BIT |
 					 OPCODE_AUTH_MAC);
 	ent->src_addr = __pa(walk.data);
-	ent->auth_key_addr = 0UL;
+	ent->auth_key_addr = auth_key;
 	ent->auth_iv_addr = __pa(hash_loc);
 	ent->final_auth_state_addr = 0UL;
 	ent->enc_key_addr = 0UL;
@@ -475,114 +595,55 @@
 	return err;
 }
 
-static int n2_md5_async_digest(struct ahash_request *req)
+static int n2_hash_async_digest(struct ahash_request *req)
 {
+	struct n2_ahash_alg *n2alg = n2_ahash_alg(req->base.tfm);
 	struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
-	struct md5_state *m = &rctx->u.md5;
+	int ds;
 
+	ds = n2alg->digest_size;
 	if (unlikely(req->nbytes == 0)) {
-		static const char md5_zero[MD5_DIGEST_SIZE] = {
-			0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
-			0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e,
-		};
-
-		memcpy(req->result, md5_zero, MD5_DIGEST_SIZE);
+		memcpy(req->result, n2alg->hash_zero, ds);
 		return 0;
 	}
-	m->hash[0] = cpu_to_le32(0x67452301);
-	m->hash[1] = cpu_to_le32(0xefcdab89);
-	m->hash[2] = cpu_to_le32(0x98badcfe);
-	m->hash[3] = cpu_to_le32(0x10325476);
+	memcpy(&rctx->u, n2alg->hash_init, n2alg->hw_op_hashsz);
 
-	return n2_hash_async_digest(req, AUTH_TYPE_MD5,
-				    MD5_DIGEST_SIZE, MD5_DIGEST_SIZE,
-				    m->hash);
+	return n2_do_async_digest(req, n2alg->auth_type,
+				  n2alg->hw_op_hashsz, ds,
+				  &rctx->u, 0UL, 0);
 }
 
-static int n2_sha1_async_digest(struct ahash_request *req)
+static int n2_hmac_async_digest(struct ahash_request *req)
 {
+	struct n2_hmac_alg *n2alg = n2_hmac_alg(req->base.tfm);
 	struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
-	struct sha1_state *s = &rctx->u.sha1;
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct n2_hmac_ctx *ctx = crypto_ahash_ctx(tfm);
+	int ds;
 
-	if (unlikely(req->nbytes == 0)) {
-		static const char sha1_zero[SHA1_DIGEST_SIZE] = {
-			0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32,
-			0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8,
-			0x07, 0x09
-		};
+	ds = n2alg->derived.digest_size;
+	if (unlikely(req->nbytes == 0) ||
+	    unlikely(ctx->hash_key_len > N2_HASH_KEY_MAX)) {
+		struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
+		struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
 
-		memcpy(req->result, sha1_zero, SHA1_DIGEST_SIZE);
-		return 0;
+		ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+		rctx->fallback_req.base.flags =
+			req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+		rctx->fallback_req.nbytes = req->nbytes;
+		rctx->fallback_req.src = req->src;
+		rctx->fallback_req.result = req->result;
+
+		return crypto_ahash_digest(&rctx->fallback_req);
 	}
-	s->state[0] = SHA1_H0;
-	s->state[1] = SHA1_H1;
-	s->state[2] = SHA1_H2;
-	s->state[3] = SHA1_H3;
-	s->state[4] = SHA1_H4;
+	memcpy(&rctx->u, n2alg->derived.hash_init,
+	       n2alg->derived.hw_op_hashsz);
 
-	return n2_hash_async_digest(req, AUTH_TYPE_SHA1,
-				    SHA1_DIGEST_SIZE, SHA1_DIGEST_SIZE,
-				    s->state);
-}
-
-static int n2_sha256_async_digest(struct ahash_request *req)
-{
-	struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
-	struct sha256_state *s = &rctx->u.sha256;
-
-	if (req->nbytes == 0) {
-		static const char sha256_zero[SHA256_DIGEST_SIZE] = {
-			0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a,
-			0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae,
-			0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99,
-			0x1b, 0x78, 0x52, 0xb8, 0x55
-		};
-
-		memcpy(req->result, sha256_zero, SHA256_DIGEST_SIZE);
-		return 0;
-	}
-	s->state[0] = SHA256_H0;
-	s->state[1] = SHA256_H1;
-	s->state[2] = SHA256_H2;
-	s->state[3] = SHA256_H3;
-	s->state[4] = SHA256_H4;
-	s->state[5] = SHA256_H5;
-	s->state[6] = SHA256_H6;
-	s->state[7] = SHA256_H7;
-
-	return n2_hash_async_digest(req, AUTH_TYPE_SHA256,
-				    SHA256_DIGEST_SIZE, SHA256_DIGEST_SIZE,
-				    s->state);
-}
-
-static int n2_sha224_async_digest(struct ahash_request *req)
-{
-	struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
-	struct sha256_state *s = &rctx->u.sha256;
-
-	if (req->nbytes == 0) {
-		static const char sha224_zero[SHA224_DIGEST_SIZE] = {
-			0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47,
-			0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2,
-			0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4,
-			0x2f
-		};
-
-		memcpy(req->result, sha224_zero, SHA224_DIGEST_SIZE);
-		return 0;
-	}
-	s->state[0] = SHA224_H0;
-	s->state[1] = SHA224_H1;
-	s->state[2] = SHA224_H2;
-	s->state[3] = SHA224_H3;
-	s->state[4] = SHA224_H4;
-	s->state[5] = SHA224_H5;
-	s->state[6] = SHA224_H6;
-	s->state[7] = SHA224_H7;
-
-	return n2_hash_async_digest(req, AUTH_TYPE_SHA256,
-				    SHA256_DIGEST_SIZE, SHA224_DIGEST_SIZE,
-				    s->state);
+	return n2_do_async_digest(req, n2alg->derived.hmac_type,
+				  n2alg->derived.hw_op_hashsz, ds,
+				  &rctx->u,
+				  __pa(&ctx->hash_key),
+				  ctx->hash_key_len);
 }
 
 struct n2_cipher_context {
@@ -1209,35 +1270,92 @@
 
 struct n2_hash_tmpl {
 	const char	*name;
-	int		(*digest)(struct ahash_request *req);
+	const char	*hash_zero;
+	const u32	*hash_init;
+	u8		hw_op_hashsz;
 	u8		digest_size;
 	u8		block_size;
+	u8		auth_type;
+	u8		hmac_type;
 };
+
+static const char md5_zero[MD5_DIGEST_SIZE] = {
+	0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
+	0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e,
+};
+static const u32 md5_init[MD5_HASH_WORDS] = {
+	cpu_to_le32(0x67452301),
+	cpu_to_le32(0xefcdab89),
+	cpu_to_le32(0x98badcfe),
+	cpu_to_le32(0x10325476),
+};
+static const char sha1_zero[SHA1_DIGEST_SIZE] = {
+	0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32,
+	0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8,
+	0x07, 0x09
+};
+static const u32 sha1_init[SHA1_DIGEST_SIZE / 4] = {
+	SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4,
+};
+static const char sha256_zero[SHA256_DIGEST_SIZE] = {
+	0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a,
+	0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae,
+	0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99,
+	0x1b, 0x78, 0x52, 0xb8, 0x55
+};
+static const u32 sha256_init[SHA256_DIGEST_SIZE / 4] = {
+	SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3,
+	SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7,
+};
+static const char sha224_zero[SHA224_DIGEST_SIZE] = {
+	0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47,
+	0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2,
+	0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4,
+	0x2f
+};
+static const u32 sha224_init[SHA256_DIGEST_SIZE / 4] = {
+	SHA224_H0, SHA224_H1, SHA224_H2, SHA224_H3,
+	SHA224_H4, SHA224_H5, SHA224_H6, SHA224_H7,
+};
+
 static const struct n2_hash_tmpl hash_tmpls[] = {
 	{ .name		= "md5",
-	  .digest	= n2_md5_async_digest,
+	  .hash_zero	= md5_zero,
+	  .hash_init	= md5_init,
+	  .auth_type	= AUTH_TYPE_MD5,
+	  .hmac_type	= AUTH_TYPE_HMAC_MD5,
+	  .hw_op_hashsz	= MD5_DIGEST_SIZE,
 	  .digest_size	= MD5_DIGEST_SIZE,
 	  .block_size	= MD5_HMAC_BLOCK_SIZE },
 	{ .name		= "sha1",
-	  .digest	= n2_sha1_async_digest,
+	  .hash_zero	= sha1_zero,
+	  .hash_init	= sha1_init,
+	  .auth_type	= AUTH_TYPE_SHA1,
+	  .hmac_type	= AUTH_TYPE_HMAC_SHA1,
+	  .hw_op_hashsz	= SHA1_DIGEST_SIZE,
 	  .digest_size	= SHA1_DIGEST_SIZE,
 	  .block_size	= SHA1_BLOCK_SIZE },
 	{ .name		= "sha256",
-	  .digest	= n2_sha256_async_digest,
+	  .hash_zero	= sha256_zero,
+	  .hash_init	= sha256_init,
+	  .auth_type	= AUTH_TYPE_SHA256,
+	  .hmac_type	= AUTH_TYPE_HMAC_SHA256,
+	  .hw_op_hashsz	= SHA256_DIGEST_SIZE,
 	  .digest_size	= SHA256_DIGEST_SIZE,
 	  .block_size	= SHA256_BLOCK_SIZE },
 	{ .name		= "sha224",
-	  .digest	= n2_sha224_async_digest,
+	  .hash_zero	= sha224_zero,
+	  .hash_init	= sha224_init,
+	  .auth_type	= AUTH_TYPE_SHA256,
+	  .hmac_type	= AUTH_TYPE_RESERVED,
+	  .hw_op_hashsz	= SHA256_DIGEST_SIZE,
 	  .digest_size	= SHA224_DIGEST_SIZE,
 	  .block_size	= SHA224_BLOCK_SIZE },
 };
 #define NUM_HASH_TMPLS ARRAY_SIZE(hash_tmpls)
 
-struct n2_ahash_alg {
-	struct list_head	entry;
-	struct ahash_alg	alg;
-};
 static LIST_HEAD(ahash_algs);
+static LIST_HEAD(hmac_algs);
 
 static int algs_registered;
 
@@ -1245,12 +1363,18 @@
 {
 	struct n2_cipher_alg *cipher, *cipher_tmp;
 	struct n2_ahash_alg *alg, *alg_tmp;
+	struct n2_hmac_alg *hmac, *hmac_tmp;
 
 	list_for_each_entry_safe(cipher, cipher_tmp, &cipher_algs, entry) {
 		crypto_unregister_alg(&cipher->alg);
 		list_del(&cipher->entry);
 		kfree(cipher);
 	}
+	list_for_each_entry_safe(hmac, hmac_tmp, &hmac_algs, derived.entry) {
+		crypto_unregister_ahash(&hmac->derived.alg);
+		list_del(&hmac->derived.entry);
+		kfree(hmac);
+	}
 	list_for_each_entry_safe(alg, alg_tmp, &ahash_algs, entry) {
 		crypto_unregister_ahash(&alg->alg);
 		list_del(&alg->entry);
@@ -1290,8 +1414,49 @@
 	list_add(&p->entry, &cipher_algs);
 	err = crypto_register_alg(alg);
 	if (err) {
+		pr_err("%s alg registration failed\n", alg->cra_name);
 		list_del(&p->entry);
 		kfree(p);
+	} else {
+		pr_info("%s alg registered\n", alg->cra_name);
+	}
+	return err;
+}
+
+static int __devinit __n2_register_one_hmac(struct n2_ahash_alg *n2ahash)
+{
+	struct n2_hmac_alg *p = kzalloc(sizeof(*p), GFP_KERNEL);
+	struct ahash_alg *ahash;
+	struct crypto_alg *base;
+	int err;
+
+	if (!p)
+		return -ENOMEM;
+
+	p->child_alg = n2ahash->alg.halg.base.cra_name;
+	memcpy(&p->derived, n2ahash, sizeof(struct n2_ahash_alg));
+	INIT_LIST_HEAD(&p->derived.entry);
+
+	ahash = &p->derived.alg;
+	ahash->digest = n2_hmac_async_digest;
+	ahash->setkey = n2_hmac_async_setkey;
+
+	base = &ahash->halg.base;
+	snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", p->child_alg);
+	snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "hmac-%s-n2", p->child_alg);
+
+	base->cra_ctxsize = sizeof(struct n2_hmac_ctx);
+	base->cra_init = n2_hmac_cra_init;
+	base->cra_exit = n2_hmac_cra_exit;
+
+	list_add(&p->derived.entry, &hmac_algs);
+	err = crypto_register_ahash(ahash);
+	if (err) {
+		pr_err("%s alg registration failed\n", base->cra_name);
+		list_del(&p->derived.entry);
+		kfree(p);
+	} else {
+		pr_info("%s alg registered\n", base->cra_name);
 	}
 	return err;
 }
@@ -1307,12 +1472,19 @@
 	if (!p)
 		return -ENOMEM;
 
+	p->hash_zero = tmpl->hash_zero;
+	p->hash_init = tmpl->hash_init;
+	p->auth_type = tmpl->auth_type;
+	p->hmac_type = tmpl->hmac_type;
+	p->hw_op_hashsz = tmpl->hw_op_hashsz;
+	p->digest_size = tmpl->digest_size;
+
 	ahash = &p->alg;
 	ahash->init = n2_hash_async_init;
 	ahash->update = n2_hash_async_update;
 	ahash->final = n2_hash_async_final;
 	ahash->finup = n2_hash_async_finup;
-	ahash->digest = tmpl->digest;
+	ahash->digest = n2_hash_async_digest;
 
 	halg = &ahash->halg;
 	halg->digestsize = tmpl->digest_size;
@@ -1331,9 +1503,14 @@
 	list_add(&p->entry, &ahash_algs);
 	err = crypto_register_ahash(ahash);
 	if (err) {
+		pr_err("%s alg registration failed\n", base->cra_name);
 		list_del(&p->entry);
 		kfree(p);
+	} else {
+		pr_info("%s alg registered\n", base->cra_name);
 	}
+	if (!err && p->hmac_type != AUTH_TYPE_RESERVED)
+		err = __n2_register_one_hmac(p);
 	return err;
 }
 
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 8b03433..7d14856 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -15,7 +15,6 @@
 
 #define pr_fmt(fmt) "%s: " fmt, __func__
 
-#include <linux/version.h>
 #include <linux/err.h>
 #include <linux/device.h>
 #include <linux/module.h>
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index bd78acf..97f4af1 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -720,7 +720,6 @@
 #define TALITOS_MDEU_MAX_CONTEXT_SIZE	TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512
 
 struct talitos_ahash_req_ctx {
-	u64 count;
 	u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
 	unsigned int hw_context_size;
 	u8 buf[HASH_MAX_BLOCK_SIZE];
@@ -729,6 +728,7 @@
 	unsigned int first;
 	unsigned int last;
 	unsigned int to_hash_later;
+	u64 nbuf;
 	struct scatterlist bufsl[2];
 	struct scatterlist *psrc;
 };
@@ -1613,6 +1613,7 @@
 	if (!req_ctx->last && req_ctx->to_hash_later) {
 		/* Position any partial block for next update/final/finup */
 		memcpy(req_ctx->buf, req_ctx->bufnext, req_ctx->to_hash_later);
+		req_ctx->nbuf = req_ctx->to_hash_later;
 	}
 	common_nonsnoop_hash_unmap(dev, edesc, areq);
 
@@ -1728,7 +1729,7 @@
 	struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
 
 	/* Initialize the context */
-	req_ctx->count = 0;
+	req_ctx->nbuf = 0;
 	req_ctx->first = 1; /* first indicates h/w must init its context */
 	req_ctx->swinit = 0; /* assume h/w init of context */
 	req_ctx->hw_context_size =
@@ -1776,52 +1777,54 @@
 			crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
 	unsigned int nbytes_to_hash;
 	unsigned int to_hash_later;
-	unsigned int index;
+	unsigned int nsg;
 	int chained;
 
-	index = req_ctx->count & (blocksize - 1);
-	req_ctx->count += nbytes;
-
-	if (!req_ctx->last && (index + nbytes) < blocksize) {
-		/* Buffer the partial block */
+	if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
+		/* Buffer up to one whole block */
 		sg_copy_to_buffer(areq->src,
 				  sg_count(areq->src, nbytes, &chained),
-				  req_ctx->buf + index, nbytes);
+				  req_ctx->buf + req_ctx->nbuf, nbytes);
+		req_ctx->nbuf += nbytes;
 		return 0;
 	}
 
-	if (index) {
-		/* partial block from previous update; chain it in. */
-		sg_init_table(req_ctx->bufsl, (nbytes) ? 2 : 1);
-		sg_set_buf(req_ctx->bufsl, req_ctx->buf, index);
-		if (nbytes)
-			scatterwalk_sg_chain(req_ctx->bufsl, 2,
-					     areq->src);
+	/* At least (blocksize + 1) bytes are available to hash */
+	nbytes_to_hash = nbytes + req_ctx->nbuf;
+	to_hash_later = nbytes_to_hash & (blocksize - 1);
+
+	if (req_ctx->last)
+		to_hash_later = 0;
+	else if (to_hash_later)
+		/* There is a partial block. Hash the full block(s) now */
+		nbytes_to_hash -= to_hash_later;
+	else {
+		/* Keep one block buffered */
+		nbytes_to_hash -= blocksize;
+		to_hash_later = blocksize;
+	}
+
+	/* Chain in any previously buffered data */
+	if (req_ctx->nbuf) {
+		nsg = (req_ctx->nbuf < nbytes_to_hash) ? 2 : 1;
+		sg_init_table(req_ctx->bufsl, nsg);
+		sg_set_buf(req_ctx->bufsl, req_ctx->buf, req_ctx->nbuf);
+		if (nsg > 1)
+			scatterwalk_sg_chain(req_ctx->bufsl, 2, areq->src);
 		req_ctx->psrc = req_ctx->bufsl;
-	} else {
+	} else
 		req_ctx->psrc = areq->src;
-	}
-	nbytes_to_hash =  index + nbytes;
-	if (!req_ctx->last) {
-		to_hash_later = (nbytes_to_hash & (blocksize - 1));
-		if (to_hash_later) {
-			int nents;
-			/* Must copy to_hash_later bytes from the end
-			 * to bufnext (a partial block) for later.
-			 */
-			nents = sg_count(areq->src, nbytes, &chained);
-			sg_copy_end_to_buffer(areq->src, nents,
-					      req_ctx->bufnext,
-					      to_hash_later,
-					      nbytes - to_hash_later);
 
-			/* Adjust count for what will be hashed now */
-			nbytes_to_hash -= to_hash_later;
-		}
-		req_ctx->to_hash_later = to_hash_later;
+	if (to_hash_later) {
+		int nents = sg_count(areq->src, nbytes, &chained);
+		sg_copy_end_to_buffer(areq->src, nents,
+				      req_ctx->bufnext,
+				      to_hash_later,
+				      nbytes - to_hash_later);
 	}
+	req_ctx->to_hash_later = to_hash_later;
 
-	/* allocate extended descriptor */
+	/* Allocate extended descriptor */
 	edesc = ahash_edesc_alloc(areq, nbytes_to_hash);
 	if (IS_ERR(edesc))
 		return PTR_ERR(edesc);
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 0d2f9db..70bb350 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -39,14 +39,6 @@
 	  there're four debug levels (x=0,1,2,3 from low to high).
 	  Usually you should select 'N'.
 
-config EDAC_DEBUG_VERBOSE
-	bool "More verbose debugging"
-	depends on EDAC_DEBUG
-	help
-	  This option makes debugging information more verbose.
-	  Source file name and line number where debugging message
-	  printed will be added to debugging message.
-
  config EDAC_DECODE_MCE
 	tristate "Decode MCEs in human-readable form (only on AMD for now)"
 	depends on CPU_SUP_AMD && X86_MCE
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index ac9f798..670239a 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -160,7 +160,7 @@
 	return 0;
 }
 
-static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 *bandwidth)
+static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bandwidth)
 {
 	struct amd64_pvt *pvt = mci->pvt_info;
 	u32 min_scrubrate = 0x0;
@@ -178,10 +178,10 @@
 
 	default:
 		amd64_printk(KERN_ERR, "Unsupported family!\n");
-		break;
+		return -EINVAL;
 	}
-	return amd64_search_set_scrub_rate(pvt->misc_f3_ctl, *bandwidth,
-			min_scrubrate);
+	return amd64_search_set_scrub_rate(pvt->misc_f3_ctl, bandwidth,
+					   min_scrubrate);
 }
 
 static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
@@ -796,6 +796,11 @@
 
 static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
 
+static u16 extract_syndrome(struct err_regs *err)
+{
+	return ((err->nbsh >> 15) & 0xff) | ((err->nbsl >> 16) & 0xff00);
+}
+
 static void amd64_cpu_display_info(struct amd64_pvt *pvt)
 {
 	if (boot_cpu_data.x86 == 0x11)
@@ -888,6 +893,9 @@
 		return;
 	}
 
+	amd64_printk(KERN_INFO, "using %s syndromes.\n",
+		     ((pvt->syn_type == 8) ? "x8" : "x4"));
+
 	/* Only if NOT ganged does dclr1 have valid info */
 	if (!dct_ganging_enabled(pvt))
 		amd64_dump_dramcfg_low(pvt->dclr1, 1);
@@ -1101,20 +1109,17 @@
 }
 
 static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
-					struct err_regs *info,
-					u64 sys_addr)
+				    struct err_regs *err_info, u64 sys_addr)
 {
 	struct mem_ctl_info *src_mci;
-	unsigned short syndrome;
 	int channel, csrow;
 	u32 page, offset;
+	u16 syndrome;
 
-	/* Extract the syndrome parts and form a 16-bit syndrome */
-	syndrome  = HIGH_SYNDROME(info->nbsl) << 8;
-	syndrome |= LOW_SYNDROME(info->nbsh);
+	syndrome = extract_syndrome(err_info);
 
 	/* CHIPKILL enabled */
-	if (info->nbcfg & K8_NBCFG_CHIPKILL) {
+	if (err_info->nbcfg & K8_NBCFG_CHIPKILL) {
 		channel = get_channel_from_ecc_syndrome(mci, syndrome);
 		if (channel < 0) {
 			/*
@@ -1123,8 +1128,8 @@
 			 * as suspect.
 			 */
 			amd64_mc_printk(mci, KERN_WARNING,
-				       "unknown syndrome 0x%x - possible error "
-				       "reporting race\n", syndrome);
+					"unknown syndrome 0x%04x - possible "
+					"error reporting race\n", syndrome);
 			edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
 			return;
 		}
@@ -1430,7 +1435,7 @@
 	u64 chan_off;
 
 	if (hi_range_sel) {
-		if (!(dct_sel_base_addr & 0xFFFFF800) &&
+		if (!(dct_sel_base_addr & 0xFFFF0000) &&
 		   hole_valid && (sys_addr >= 0x100000000ULL))
 			chan_off = hole_off << 16;
 		else
@@ -1654,13 +1659,13 @@
  * (MCX_ADDR).
  */
 static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
-				     struct err_regs *info,
+				     struct err_regs *err_info,
 				     u64 sys_addr)
 {
 	struct amd64_pvt *pvt = mci->pvt_info;
 	u32 page, offset;
-	unsigned short syndrome;
 	int nid, csrow, chan = 0;
+	u16 syndrome;
 
 	csrow = f10_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
 
@@ -1671,15 +1676,14 @@
 
 	error_address_to_page_and_offset(sys_addr, &page, &offset);
 
-	syndrome  = HIGH_SYNDROME(info->nbsl) << 8;
-	syndrome |= LOW_SYNDROME(info->nbsh);
+	syndrome = extract_syndrome(err_info);
 
 	/*
 	 * We need the syndromes for channel detection only when we're
 	 * ganged. Otherwise @chan should already contain the channel at
 	 * this point.
 	 */
-	if (dct_ganging_enabled(pvt) && pvt->nbcfg & K8_NBCFG_CHIPKILL)
+	if (dct_ganging_enabled(pvt) && (pvt->nbcfg & K8_NBCFG_CHIPKILL))
 		chan = get_channel_from_ecc_syndrome(mci, syndrome);
 
 	if (chan >= 0)
@@ -1878,7 +1882,7 @@
 };
 
 static int decode_syndrome(u16 syndrome, u16 *vectors, int num_vecs,
-				 int v_dim)
+			   int v_dim)
 {
 	unsigned int i, err_sym;
 
@@ -1955,124 +1959,23 @@
 static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
 {
 	struct amd64_pvt *pvt = mci->pvt_info;
-	u32 value = 0;
-	int err_sym = 0;
+	int err_sym = -1;
 
-	if (boot_cpu_data.x86 == 0x10) {
-
-		amd64_read_pci_cfg(pvt->misc_f3_ctl, 0x180, &value);
-
-		/* F3x180[EccSymbolSize]=1 => x8 symbols */
-		if (boot_cpu_data.x86_model > 7 &&
-		    value & BIT(25)) {
-			err_sym = decode_syndrome(syndrome, x8_vectors,
-						  ARRAY_SIZE(x8_vectors), 8);
-			return map_err_sym_to_channel(err_sym, 8);
-		}
+	if (pvt->syn_type == 8)
+		err_sym = decode_syndrome(syndrome, x8_vectors,
+					  ARRAY_SIZE(x8_vectors),
+					  pvt->syn_type);
+	else if (pvt->syn_type == 4)
+		err_sym = decode_syndrome(syndrome, x4_vectors,
+					  ARRAY_SIZE(x4_vectors),
+					  pvt->syn_type);
+	else {
+		amd64_printk(KERN_WARNING, "%s: Illegal syndrome type: %u\n",
+					   __func__, pvt->syn_type);
+		return err_sym;
 	}
-	err_sym = decode_syndrome(syndrome, x4_vectors, ARRAY_SIZE(x4_vectors), 4);
-	return map_err_sym_to_channel(err_sym, 4);
-}
 
-/*
- * Check for valid error in the NB Status High register. If so, proceed to read
- * NB Status Low, NB Address Low and NB Address High registers and store data
- * into error structure.
- *
- * Returns:
- *	- 1: if hardware regs contains valid error info
- *	- 0: if no valid error is indicated
- */
-static int amd64_get_error_info_regs(struct mem_ctl_info *mci,
-				     struct err_regs *regs)
-{
-	struct amd64_pvt *pvt;
-	struct pci_dev *misc_f3_ctl;
-
-	pvt = mci->pvt_info;
-	misc_f3_ctl = pvt->misc_f3_ctl;
-
-	if (amd64_read_pci_cfg(misc_f3_ctl, K8_NBSH, &regs->nbsh))
-		return 0;
-
-	if (!(regs->nbsh & K8_NBSH_VALID_BIT))
-		return 0;
-
-	/* valid error, read remaining error information registers */
-	if (amd64_read_pci_cfg(misc_f3_ctl, K8_NBSL, &regs->nbsl) ||
-	    amd64_read_pci_cfg(misc_f3_ctl, K8_NBEAL, &regs->nbeal) ||
-	    amd64_read_pci_cfg(misc_f3_ctl, K8_NBEAH, &regs->nbeah) ||
-	    amd64_read_pci_cfg(misc_f3_ctl, K8_NBCFG, &regs->nbcfg))
-		return 0;
-
-	return 1;
-}
-
-/*
- * This function is called to retrieve the error data from hardware and store it
- * in the info structure.
- *
- * Returns:
- *	- 1: if a valid error is found
- *	- 0: if no error is found
- */
-static int amd64_get_error_info(struct mem_ctl_info *mci,
-				struct err_regs *info)
-{
-	struct amd64_pvt *pvt;
-	struct err_regs regs;
-
-	pvt = mci->pvt_info;
-
-	if (!amd64_get_error_info_regs(mci, info))
-		return 0;
-
-	/*
-	 * Here's the problem with the K8's EDAC reporting: There are four
-	 * registers which report pieces of error information. They are shared
-	 * between CEs and UEs. Furthermore, contrary to what is stated in the
-	 * BKDG, the overflow bit is never used! Every error always updates the
-	 * reporting registers.
-	 *
-	 * Can you see the race condition? All four error reporting registers
-	 * must be read before a new error updates them! There is no way to read
-	 * all four registers atomically. The best than can be done is to detect
-	 * that a race has occured and then report the error without any kind of
-	 * precision.
-	 *
-	 * What is still positive is that errors are still reported and thus
-	 * problems can still be detected - just not localized because the
-	 * syndrome and address are spread out across registers.
-	 *
-	 * Grrrrr!!!!!  Here's hoping that AMD fixes this in some future K8 rev.
-	 * UEs and CEs should have separate register sets with proper overflow
-	 * bits that are used! At very least the problem can be fixed by
-	 * honoring the ErrValid bit in 'nbsh' and not updating registers - just
-	 * set the overflow bit - unless the current error is CE and the new
-	 * error is UE which would be the only situation for overwriting the
-	 * current values.
-	 */
-
-	regs = *info;
-
-	/* Use info from the second read - most current */
-	if (unlikely(!amd64_get_error_info_regs(mci, info)))
-		return 0;
-
-	/* clear the error bits in hardware */
-	pci_write_bits32(pvt->misc_f3_ctl, K8_NBSH, 0, K8_NBSH_VALID_BIT);
-
-	/* Check for the possible race condition */
-	if ((regs.nbsh != info->nbsh) ||
-	     (regs.nbsl != info->nbsl) ||
-	     (regs.nbeah != info->nbeah) ||
-	     (regs.nbeal != info->nbeal)) {
-		amd64_mc_printk(mci, KERN_WARNING,
-				"hardware STATUS read access race condition "
-				"detected!\n");
-		return 0;
-	}
-	return 1;
+	return map_err_sym_to_channel(err_sym, pvt->syn_type);
 }
 
 /*
@@ -2177,7 +2080,7 @@
 	 * catastrophic.
 	 */
 	if (info->nbsh & K8_NBSH_OVERFLOW)
-		edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR "Error Overflow");
+		edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR " Error Overflow");
 }
 
 void amd64_decode_bus_error(int node_id, struct err_regs *regs)
@@ -2199,20 +2102,6 @@
 }
 
 /*
- * The main polling 'check' function, called FROM the edac core to perform the
- * error checking and if an error is encountered, error processing.
- */
-static void amd64_check(struct mem_ctl_info *mci)
-{
-	struct err_regs regs;
-
-	if (amd64_get_error_info(mci, &regs)) {
-		struct amd64_pvt *pvt = mci->pvt_info;
-		amd_decode_nb_mce(pvt->mc_node_id, &regs, 1);
-	}
-}
-
-/*
  * Input:
  *	1) struct amd64_pvt which contains pvt->dram_f2_ctl pointer
  *	2) AMD Family index value
@@ -2284,6 +2173,7 @@
 static void amd64_read_mc_registers(struct amd64_pvt *pvt)
 {
 	u64 msr_val;
+	u32 tmp;
 	int dram;
 
 	/*
@@ -2349,10 +2239,22 @@
 	amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0);
 	amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_0, &pvt->dchr0);
 
-	if (!dct_ganging_enabled(pvt) && boot_cpu_data.x86 >= 0x10) {
-		amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_1, &pvt->dclr1);
-		amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_1, &pvt->dchr1);
+	if (boot_cpu_data.x86 >= 0x10) {
+		if (!dct_ganging_enabled(pvt)) {
+			amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_1, &pvt->dclr1);
+			amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_1, &pvt->dchr1);
+		}
+		amd64_read_pci_cfg(pvt->misc_f3_ctl, EXT_NB_MCA_CFG, &tmp);
 	}
+
+	if (boot_cpu_data.x86 == 0x10 &&
+	    boot_cpu_data.x86_model > 7 &&
+	    /* F3x180[EccSymbolSize]=1 => x8 symbols */
+	    tmp & BIT(25))
+		pvt->syn_type = 8;
+	else
+		pvt->syn_type = 4;
+
 	amd64_dump_misc_regs(pvt);
 }
 
@@ -2739,9 +2641,6 @@
 	mci->dev_name		= pci_name(pvt->dram_f2_ctl);
 	mci->ctl_page_to_phys	= NULL;
 
-	/* IMPORTANT: Set the polling 'check' function in this module */
-	mci->edac_check		= amd64_check;
-
 	/* memory scrubber interface */
 	mci->set_sdram_scrub_rate = amd64_set_scrub_rate;
 	mci->get_sdram_scrub_rate = amd64_get_scrub_rate;
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 0d4bf56..613b938 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -244,44 +244,17 @@
 
 
 #define F10_DCTL_SEL_LOW		0x110
-
-#define dct_sel_baseaddr(pvt)    \
-	((pvt->dram_ctl_select_low) & 0xFFFFF800)
-
-#define dct_sel_interleave_addr(pvt)    \
-	(((pvt->dram_ctl_select_low) >> 6) & 0x3)
-
-enum {
-	F10_DCTL_SEL_LOW_DctSelHiRngEn	= BIT(0),
-	F10_DCTL_SEL_LOW_DctSelIntLvEn	= BIT(2),
-	F10_DCTL_SEL_LOW_DctGangEn	= BIT(4),
-	F10_DCTL_SEL_LOW_DctDatIntLv	= BIT(5),
-	F10_DCTL_SEL_LOW_DramEnable	= BIT(8),
-	F10_DCTL_SEL_LOW_MemCleared	= BIT(10),
-};
-
-#define    dct_high_range_enabled(pvt)    \
-	(pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctSelHiRngEn)
-
-#define dct_interleave_enabled(pvt)	   \
-	(pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctSelIntLvEn)
-
-#define dct_ganging_enabled(pvt)        \
-	(pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctGangEn)
-
-#define dct_data_intlv_enabled(pvt)    \
-	(pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctDatIntLv)
-
-#define dct_dram_enabled(pvt)    \
-	(pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DramEnable)
-
-#define dct_memory_cleared(pvt)    \
-	(pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_MemCleared)
-
+#define dct_sel_baseaddr(pvt)		((pvt->dram_ctl_select_low) & 0xFFFFF800)
+#define dct_sel_interleave_addr(pvt)	(((pvt->dram_ctl_select_low) >> 6) & 0x3)
+#define dct_high_range_enabled(pvt)	(pvt->dram_ctl_select_low & BIT(0))
+#define dct_interleave_enabled(pvt)	(pvt->dram_ctl_select_low & BIT(2))
+#define dct_ganging_enabled(pvt)	(pvt->dram_ctl_select_low & BIT(4))
+#define dct_data_intlv_enabled(pvt)	(pvt->dram_ctl_select_low & BIT(5))
+#define dct_dram_enabled(pvt)		(pvt->dram_ctl_select_low & BIT(8))
+#define dct_memory_cleared(pvt)		(pvt->dram_ctl_select_low & BIT(10))
 
 #define F10_DCTL_SEL_HIGH		0x114
 
-
 /*
  * Function 3 - Misc Control
  */
@@ -382,6 +355,8 @@
 #define K8_NBCAP_SECDED			BIT(3)
 #define K8_NBCAP_DCT_DUAL		BIT(0)
 
+#define EXT_NB_MCA_CFG			0x180
+
 /* MSRs */
 #define K8_MSR_MCGCTL_NBE		BIT(4)
 
@@ -471,6 +446,9 @@
 	u32 dram_ctl_select_high;	/* DRAM Controller Select High Reg */
 	u32 online_spare;               /* On-Line spare Reg */
 
+	/* x4 or x8 syndromes in use */
+	u8 syn_type;
+
 	/* temp storage for when input is received from sysfs */
 	struct err_regs ctl_error_info;
 
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index ae3f80c..073f5a0 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -958,7 +958,7 @@
 }
 
 /* Program byte/sec bandwidth scrub rate to hardware */
-static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *new_bw)
+static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw)
 {
 	const struct scrubrate *scrubrates;
 	struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
@@ -975,7 +975,7 @@
 	 * desired rate and program the cooresponding register value.
 	 */
 	for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++)
-		if (scrubrates[i].bandwidth >= *new_bw)
+		if (scrubrates[i].bandwidth >= new_bw)
 			break;
 
 	if (scrubrates[i].bandwidth == SDRATE_EOT)
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index efca934..ce71466 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -49,21 +49,15 @@
 #define edac_printk(level, prefix, fmt, arg...) \
 	printk(level "EDAC " prefix ": " fmt, ##arg)
 
-#define edac_printk_verbose(level, prefix, fmt, arg...) \
-	printk(level "EDAC " prefix ": " "in %s, line at %d: " fmt,	\
-	       __FILE__, __LINE__, ##arg)
-
 #define edac_mc_printk(mci, level, fmt, arg...) \
 	printk(level "EDAC MC%d: " fmt, mci->mc_idx, ##arg)
 
 #define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \
 	printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg)
 
-/* edac_device printk */
 #define edac_device_printk(ctl, level, fmt, arg...) \
 	printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg)
 
-/* edac_pci printk */
 #define edac_pci_printk(ctl, level, fmt, arg...) \
 	printk(level "EDAC PCI%d: " fmt, ctl->pci_idx, ##arg)
 
@@ -76,21 +70,12 @@
 extern int edac_debug_level;
 extern const char *edac_mem_types[];
 
-#ifndef CONFIG_EDAC_DEBUG_VERBOSE
 #define edac_debug_printk(level, fmt, arg...)                           \
 	do {                                                            \
 		if (level <= edac_debug_level)                          \
 			edac_printk(KERN_DEBUG, EDAC_DEBUG,		\
 				    "%s: " fmt, __func__, ##arg);	\
 	} while (0)
-#else  /* CONFIG_EDAC_DEBUG_VERBOSE */
-#define edac_debug_printk(level, fmt, arg...)                            \
-	do {                                                             \
-		if (level <= edac_debug_level)                           \
-			edac_printk_verbose(KERN_DEBUG, EDAC_DEBUG, fmt, \
-					    ##arg);			\
-	} while (0)
-#endif
 
 #define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
 #define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ )
@@ -393,7 +378,7 @@
 	   internal representation and configures whatever else needs
 	   to be configured.
 	 */
-	int (*set_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw);
+	int (*set_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 bw);
 
 	/* Get the current sdram memory scrub rate from the internal
 	   representation and converts it to the closest matching
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index c200c2f..8aad94d 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -124,19 +124,6 @@
 	[EDAC_S16ECD16ED] = "S16ECD16ED"
 };
 
-
-
-static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
-{
-	int *value = (int *)ptr;
-
-	if (isdigit(*buffer))
-		*value = simple_strtoul(buffer, NULL, 0);
-
-	return count;
-}
-
-
 /* EDAC sysfs CSROW data structures and methods
  */
 
@@ -450,53 +437,54 @@
 
 /* memory scrubbing */
 static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
-					const char *data, size_t count)
+					  const char *data, size_t count)
 {
-	u32 bandwidth = -1;
+	unsigned long bandwidth = 0;
+	int err;
 
-	if (mci->set_sdram_scrub_rate) {
-
-		memctrl_int_store(&bandwidth, data, count);
-
-		if (!(*mci->set_sdram_scrub_rate) (mci, &bandwidth)) {
-			edac_printk(KERN_DEBUG, EDAC_MC,
-				"Scrub rate set successfully, applied: %d\n",
-				bandwidth);
-		} else {
-			/* FIXME: error codes maybe? */
-			edac_printk(KERN_DEBUG, EDAC_MC,
-				"Scrub rate set FAILED, could not apply: %d\n",
-				bandwidth);
-		}
-	} else {
-		/* FIXME: produce "not implemented" ERROR for user-side. */
+	if (!mci->set_sdram_scrub_rate) {
 		edac_printk(KERN_WARNING, EDAC_MC,
-			"Memory scrubbing 'set'control is not implemented!\n");
+			    "Memory scrub rate setting not implemented!\n");
+		return -EINVAL;
 	}
-	return count;
+
+	if (strict_strtoul(data, 10, &bandwidth) < 0)
+		return -EINVAL;
+
+	err = mci->set_sdram_scrub_rate(mci, (u32)bandwidth);
+	if (err) {
+		edac_printk(KERN_DEBUG, EDAC_MC,
+			    "Failed setting scrub rate to %lu\n", bandwidth);
+		return -EINVAL;
+	}
+	else {
+		edac_printk(KERN_DEBUG, EDAC_MC,
+			    "Scrub rate set to: %lu\n", bandwidth);
+		return count;
+	}
 }
 
 static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
 {
-	u32 bandwidth = -1;
+	u32 bandwidth = 0;
+	int err;
 
-	if (mci->get_sdram_scrub_rate) {
-		if (!(*mci->get_sdram_scrub_rate) (mci, &bandwidth)) {
-			edac_printk(KERN_DEBUG, EDAC_MC,
-				"Scrub rate successfully, fetched: %d\n",
-				bandwidth);
-		} else {
-			/* FIXME: error codes maybe? */
-			edac_printk(KERN_DEBUG, EDAC_MC,
-				"Scrub rate fetch FAILED, got: %d\n",
-				bandwidth);
-		}
-	} else {
-		/* FIXME: produce "not implemented" ERROR for user-side.  */
+	if (!mci->get_sdram_scrub_rate) {
 		edac_printk(KERN_WARNING, EDAC_MC,
-			"Memory scrubbing 'get' control is not implemented\n");
+			    "Memory scrub rate reading not implemented\n");
+		return -EINVAL;
 	}
-	return sprintf(data, "%d\n", bandwidth);
+
+	err = mci->get_sdram_scrub_rate(mci, &bandwidth);
+	if (err) {
+		edac_printk(KERN_DEBUG, EDAC_MC, "Error reading scrub rate\n");
+		return err;
+	}
+	else {
+		edac_printk(KERN_DEBUG, EDAC_MC,
+			    "Read scrub rate: %d\n", bandwidth);
+		return sprintf(data, "%d\n", bandwidth);
+	}
 }
 
 /* default attribute files for the MCI object */
diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c
index 97e64bc..bae9351 100644
--- a/drivers/edac/edac_mce_amd.c
+++ b/drivers/edac/edac_mce_amd.c
@@ -133,7 +133,7 @@
 	u32 ec  = mc0_status & 0xffff;
 	u32 xec = (mc0_status >> 16) & 0xf;
 
-	pr_emerg(" Data Cache Error");
+	pr_emerg("Data Cache Error");
 
 	if (xec == 1 && TLB_ERROR(ec))
 		pr_cont(": %s TLB multimatch.\n", LL_MSG(ec));
@@ -176,7 +176,7 @@
 	u32 ec  = mc1_status & 0xffff;
 	u32 xec = (mc1_status >> 16) & 0xf;
 
-	pr_emerg(" Instruction Cache Error");
+	pr_emerg("Instruction Cache Error");
 
 	if (xec == 1 && TLB_ERROR(ec))
 		pr_cont(": %s TLB multimatch.\n", LL_MSG(ec));
@@ -233,7 +233,7 @@
 	u32 ec = mc2_status & 0xffff;
 	u32 xec = (mc2_status >> 16) & 0xf;
 
-	pr_emerg(" Bus Unit Error");
+	pr_emerg("Bus Unit Error");
 
 	if (xec == 0x1)
 		pr_cont(" in the write data buffers.\n");
@@ -275,7 +275,7 @@
 	u32 ec  = mc3_status & 0xffff;
 	u32 xec = (mc3_status >> 16) & 0xf;
 
-	pr_emerg(" Load Store Error");
+	pr_emerg("Load Store Error");
 
 	if (xec == 0x0) {
 		u8 rrrr = (ec >> 4) & 0xf;
@@ -304,7 +304,7 @@
 	if (TLB_ERROR(ec) && !report_gart_errors)
 		return;
 
-	pr_emerg(" Northbridge Error, node %d", node_id);
+	pr_emerg("Northbridge Error, node %d", node_id);
 
 	/*
 	 * F10h, revD can disable ErrCpu[3:0] so check that first and also the
@@ -342,13 +342,13 @@
 static inline void amd_decode_err_code(unsigned int ec)
 {
 	if (TLB_ERROR(ec)) {
-		pr_emerg(" Transaction: %s, Cache Level %s\n",
+		pr_emerg("Transaction: %s, Cache Level %s\n",
 			 TT_MSG(ec), LL_MSG(ec));
 	} else if (MEM_ERROR(ec)) {
-		pr_emerg(" Transaction: %s, Type: %s, Cache Level: %s",
+		pr_emerg("Transaction: %s, Type: %s, Cache Level: %s",
 			 RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec));
 	} else if (BUS_ERROR(ec)) {
-		pr_emerg(" Transaction type: %s(%s), %s, Cache Level: %s, "
+		pr_emerg("Transaction type: %s(%s), %s, Cache Level: %s, "
 			 "Participating Processor: %s\n",
 			  RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec),
 			  PP_MSG(ec));
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index ee9753c..f459a6c 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -589,14 +589,13 @@
 /*
  * The bandwidth is based on experimentation, feel free to refine it.
  */
-static int i5100_set_scrub_rate(struct mem_ctl_info *mci,
-				       u32 *bandwidth)
+static int i5100_set_scrub_rate(struct mem_ctl_info *mci, u32 bandwidth)
 {
 	struct i5100_priv *priv = mci->pvt_info;
 	u32 dw;
 
 	pci_read_config_dword(priv->mc, I5100_MC, &dw);
-	if (*bandwidth) {
+	if (bandwidth) {
 		priv->scrub_enable = 1;
 		dw |= I5100_MC_SCRBEN_MASK;
 		schedule_delayed_work(&(priv->i5100_scrubbing),
@@ -610,7 +609,7 @@
 
 	pci_read_config_dword(priv->mc, I5100_MC, &dw);
 
-	*bandwidth = 5900000 * i5100_mc_scrben(dw);
+	bandwidth = 5900000 * i5100_mc_scrben(dw);
 
 	return 0;
 }
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 1b03ba1..a6c670b 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -122,8 +122,17 @@
 	  is necessary for iSCSI Boot Firmware Table Attributes module to work
 	  properly.
 
+config ISCSI_BOOT_SYSFS
+	tristate "iSCSI Boot Sysfs Interface"
+	default	n
+	help
+	  This option enables support for exposing iSCSI boot information
+	  via sysfs to userspace. If you wish to export this information,
+	  say Y. Otherwise, say N.
+
 config ISCSI_IBFT
 	tristate "iSCSI Boot Firmware Table Attributes module"
+	select ISCSI_BOOT_SYSFS
 	depends on ISCSI_IBFT_FIND
 	default	n
 	help
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 1c3c173..5fe7e16 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -10,4 +10,5 @@
 obj-$(CONFIG_DMIID)		+= dmi-id.o
 obj-$(CONFIG_ISCSI_IBFT_FIND)	+= iscsi_ibft_find.o
 obj-$(CONFIG_ISCSI_IBFT)	+= iscsi_ibft.o
+obj-$(CONFIG_ISCSI_BOOT_SYSFS)	+= iscsi_boot_sysfs.o
 obj-$(CONFIG_FIRMWARE_MEMMAP)	+= memmap.o
diff --git a/drivers/firmware/iscsi_boot_sysfs.c b/drivers/firmware/iscsi_boot_sysfs.c
new file mode 100644
index 0000000..df6bff7
--- /dev/null
+++ b/drivers/firmware/iscsi_boot_sysfs.c
@@ -0,0 +1,481 @@
+/*
+ * Export the iSCSI boot info to userland via sysfs.
+ *
+ * Copyright (C) 2010 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2010 Mike Christie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/capability.h>
+#include <linux/iscsi_boot_sysfs.h>
+
+
+MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>");
+MODULE_DESCRIPTION("sysfs interface and helpers to export iSCSI boot information");
+MODULE_LICENSE("GPL");
+/*
+ * The kobject and attribute structures.
+ */
+struct iscsi_boot_attr {
+	struct attribute attr;
+	int type;
+	ssize_t (*show) (void *data, int type, char *buf);
+};
+
+/*
+ * The routine called for all sysfs attributes.
+ */
+static ssize_t iscsi_boot_show_attribute(struct kobject *kobj,
+					 struct attribute *attr, char *buf)
+{
+	struct iscsi_boot_kobj *boot_kobj =
+			container_of(kobj, struct iscsi_boot_kobj, kobj);
+	struct iscsi_boot_attr *boot_attr =
+			container_of(attr, struct iscsi_boot_attr, attr);
+	ssize_t ret = -EIO;
+	char *str = buf;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (boot_kobj->show)
+		ret = boot_kobj->show(boot_kobj->data, boot_attr->type, str);
+	return ret;
+}
+
+static const struct sysfs_ops iscsi_boot_attr_ops = {
+	.show = iscsi_boot_show_attribute,
+};
+
+static void iscsi_boot_kobj_release(struct kobject *kobj)
+{
+	struct iscsi_boot_kobj *boot_kobj =
+			container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+	kfree(boot_kobj->data);
+	kfree(boot_kobj);
+}
+
+static struct kobj_type iscsi_boot_ktype = {
+	.release = iscsi_boot_kobj_release,
+	.sysfs_ops = &iscsi_boot_attr_ops,
+};
+
+#define iscsi_boot_rd_attr(fnname, sysfs_name, attr_type)		\
+static struct iscsi_boot_attr iscsi_boot_attr_##fnname = {	\
+	.attr	= { .name = __stringify(sysfs_name), .mode = 0444 },	\
+	.type	= attr_type,						\
+}
+
+/* Target attrs */
+iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX);
+iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS);
+iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR);
+iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT);
+iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN);
+iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE);
+iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC);
+iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME);
+iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME);
+iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET);
+iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name,
+		   ISCSI_BOOT_TGT_REV_CHAP_NAME);
+iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret,
+		   ISCSI_BOOT_TGT_REV_CHAP_SECRET);
+
+static struct attribute *target_attrs[] = {
+	&iscsi_boot_attr_tgt_index.attr,
+	&iscsi_boot_attr_tgt_flags.attr,
+	&iscsi_boot_attr_tgt_ip.attr,
+	&iscsi_boot_attr_tgt_port.attr,
+	&iscsi_boot_attr_tgt_lun.attr,
+	&iscsi_boot_attr_tgt_chap.attr,
+	&iscsi_boot_attr_tgt_nic.attr,
+	&iscsi_boot_attr_tgt_name.attr,
+	&iscsi_boot_attr_tgt_chap_name.attr,
+	&iscsi_boot_attr_tgt_chap_secret.attr,
+	&iscsi_boot_attr_tgt_chap_rev_name.attr,
+	&iscsi_boot_attr_tgt_chap_rev_secret.attr,
+	NULL
+};
+
+static mode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj,
+					     struct attribute *attr, int i)
+{
+	struct iscsi_boot_kobj *boot_kobj =
+			container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+	if (attr ==  &iscsi_boot_attr_tgt_index.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_TGT_INDEX);
+	else if (attr == &iscsi_boot_attr_tgt_flags.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_TGT_FLAGS);
+	else if (attr == &iscsi_boot_attr_tgt_ip.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					      ISCSI_BOOT_TGT_IP_ADDR);
+	else if (attr == &iscsi_boot_attr_tgt_port.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					      ISCSI_BOOT_TGT_PORT);
+	else if (attr == &iscsi_boot_attr_tgt_lun.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					      ISCSI_BOOT_TGT_LUN);
+	else if (attr == &iscsi_boot_attr_tgt_chap.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_TGT_CHAP_TYPE);
+	else if (attr == &iscsi_boot_attr_tgt_nic.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_TGT_NIC_ASSOC);
+	else if (attr == &iscsi_boot_attr_tgt_name.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_TGT_NAME);
+	else if (attr == &iscsi_boot_attr_tgt_chap_name.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_TGT_CHAP_NAME);
+	else if (attr == &iscsi_boot_attr_tgt_chap_secret.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_TGT_CHAP_SECRET);
+	else if (attr == &iscsi_boot_attr_tgt_chap_rev_name.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_TGT_REV_CHAP_NAME);
+	else if (attr == &iscsi_boot_attr_tgt_chap_rev_secret.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_TGT_REV_CHAP_SECRET);
+	return 0;
+}
+
+static struct attribute_group iscsi_boot_target_attr_group = {
+	.attrs = target_attrs,
+	.is_visible = iscsi_boot_tgt_attr_is_visible,
+};
+
+/* Ethernet attrs */
+iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX);
+iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS);
+iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR);
+iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK);
+iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN);
+iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY);
+iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS);
+iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns,
+		   ISCSI_BOOT_ETH_SECONDARY_DNS);
+iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP);
+iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN);
+iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC);
+iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME);
+
+static struct attribute *ethernet_attrs[] = {
+	&iscsi_boot_attr_eth_index.attr,
+	&iscsi_boot_attr_eth_flags.attr,
+	&iscsi_boot_attr_eth_ip.attr,
+	&iscsi_boot_attr_eth_subnet.attr,
+	&iscsi_boot_attr_eth_origin.attr,
+	&iscsi_boot_attr_eth_gateway.attr,
+	&iscsi_boot_attr_eth_primary_dns.attr,
+	&iscsi_boot_attr_eth_secondary_dns.attr,
+	&iscsi_boot_attr_eth_dhcp.attr,
+	&iscsi_boot_attr_eth_vlan.attr,
+	&iscsi_boot_attr_eth_mac.attr,
+	&iscsi_boot_attr_eth_hostname.attr,
+	NULL
+};
+
+static mode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj,
+					     struct attribute *attr, int i)
+{
+	struct iscsi_boot_kobj *boot_kobj =
+			container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+	if (attr ==  &iscsi_boot_attr_eth_index.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_ETH_INDEX);
+	else if (attr ==  &iscsi_boot_attr_eth_flags.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_ETH_FLAGS);
+	else if (attr ==  &iscsi_boot_attr_eth_ip.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_ETH_IP_ADDR);
+	else if (attr ==  &iscsi_boot_attr_eth_subnet.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_ETH_SUBNET_MASK);
+	else if (attr ==  &iscsi_boot_attr_eth_origin.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_ETH_ORIGIN);
+	else if (attr ==  &iscsi_boot_attr_eth_gateway.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_ETH_GATEWAY);
+	else if (attr ==  &iscsi_boot_attr_eth_primary_dns.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_ETH_PRIMARY_DNS);
+	else if (attr ==  &iscsi_boot_attr_eth_secondary_dns.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_ETH_SECONDARY_DNS);
+	else if (attr ==  &iscsi_boot_attr_eth_dhcp.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_ETH_DHCP);
+	else if (attr ==  &iscsi_boot_attr_eth_vlan.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_ETH_VLAN);
+	else if (attr ==  &iscsi_boot_attr_eth_mac.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_ETH_MAC);
+	else if (attr ==  &iscsi_boot_attr_eth_hostname.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_ETH_HOSTNAME);
+	return 0;
+}
+
+static struct attribute_group iscsi_boot_ethernet_attr_group = {
+	.attrs = ethernet_attrs,
+	.is_visible = iscsi_boot_eth_attr_is_visible,
+};
+
+/* Initiator attrs */
+iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX);
+iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS);
+iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER);
+iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER);
+iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server,
+		   ISCSI_BOOT_INI_PRI_RADIUS_SERVER);
+iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server,
+		   ISCSI_BOOT_INI_SEC_RADIUS_SERVER);
+iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME);
+
+static struct attribute *initiator_attrs[] = {
+	&iscsi_boot_attr_ini_index.attr,
+	&iscsi_boot_attr_ini_flags.attr,
+	&iscsi_boot_attr_ini_isns.attr,
+	&iscsi_boot_attr_ini_slp.attr,
+	&iscsi_boot_attr_ini_primary_radius.attr,
+	&iscsi_boot_attr_ini_secondary_radius.attr,
+	&iscsi_boot_attr_ini_name.attr,
+	NULL
+};
+
+static mode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj,
+					     struct attribute *attr, int i)
+{
+	struct iscsi_boot_kobj *boot_kobj =
+			container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+	if (attr ==  &iscsi_boot_attr_ini_index.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_INI_INDEX);
+	if (attr ==  &iscsi_boot_attr_ini_flags.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_INI_FLAGS);
+	if (attr ==  &iscsi_boot_attr_ini_isns.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_INI_ISNS_SERVER);
+	if (attr ==  &iscsi_boot_attr_ini_slp.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_INI_SLP_SERVER);
+	if (attr ==  &iscsi_boot_attr_ini_primary_radius.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_INI_PRI_RADIUS_SERVER);
+	if (attr ==  &iscsi_boot_attr_ini_secondary_radius.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_INI_SEC_RADIUS_SERVER);
+	if (attr ==  &iscsi_boot_attr_ini_name.attr)
+		return boot_kobj->is_visible(boot_kobj->data,
+					     ISCSI_BOOT_INI_INITIATOR_NAME);
+
+	return 0;
+}
+
+static struct attribute_group iscsi_boot_initiator_attr_group = {
+	.attrs = initiator_attrs,
+	.is_visible = iscsi_boot_ini_attr_is_visible,
+};
+
+static struct iscsi_boot_kobj *
+iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset,
+		       struct attribute_group *attr_group,
+		       const char *name, int index, void *data,
+		       ssize_t (*show) (void *data, int type, char *buf),
+		       mode_t (*is_visible) (void *data, int type))
+{
+	struct iscsi_boot_kobj *boot_kobj;
+
+	boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL);
+	if (!boot_kobj)
+		return NULL;
+	INIT_LIST_HEAD(&boot_kobj->list);
+
+	boot_kobj->kobj.kset = boot_kset->kset;
+	if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype,
+				 NULL, name, index)) {
+		kfree(boot_kobj);
+		return NULL;
+	}
+	boot_kobj->data = data;
+	boot_kobj->show = show;
+	boot_kobj->is_visible = is_visible;
+
+	if (sysfs_create_group(&boot_kobj->kobj, attr_group)) {
+		/*
+		 * We do not want to free this because the caller
+		 * will assume that since the creation call failed
+		 * the boot kobj was not setup and the normal release
+		 * path is not being run.
+		 */
+		boot_kobj->data = NULL;
+		kobject_put(&boot_kobj->kobj);
+		return NULL;
+	}
+	boot_kobj->attr_group = attr_group;
+
+	kobject_uevent(&boot_kobj->kobj, KOBJ_ADD);
+	/* Nothing broke so lets add it to the list. */
+	list_add_tail(&boot_kobj->list, &boot_kset->kobj_list);
+	return boot_kobj;
+}
+
+static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj)
+{
+	list_del(&boot_kobj->list);
+	sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group);
+	kobject_put(&boot_kobj->kobj);
+}
+
+/**
+ * iscsi_boot_create_target() - create boot target sysfs dir
+ * @boot_kset: boot kset
+ * @index: the target id
+ * @data: driver specific data for target
+ * @show: attr show function
+ * @is_visible: attr visibility function
+ *
+ * Note: The boot sysfs lib will free the data passed in for the caller
+ * when all refs to the target kobject have been released.
+ */
+struct iscsi_boot_kobj *
+iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index,
+			 void *data,
+			 ssize_t (*show) (void *data, int type, char *buf),
+			 mode_t (*is_visible) (void *data, int type))
+{
+	return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group,
+				      "target%d", index, data, show, is_visible);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_target);
+
+/**
+ * iscsi_boot_create_initiator() - create boot initiator sysfs dir
+ * @boot_kset: boot kset
+ * @index: the initiator id
+ * @data: driver specific data
+ * @show: attr show function
+ * @is_visible: attr visibility function
+ *
+ * Note: The boot sysfs lib will free the data passed in for the caller
+ * when all refs to the initiator kobject have been released.
+ */
+struct iscsi_boot_kobj *
+iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index,
+			    void *data,
+			    ssize_t (*show) (void *data, int type, char *buf),
+			    mode_t (*is_visible) (void *data, int type))
+{
+	return iscsi_boot_create_kobj(boot_kset,
+				      &iscsi_boot_initiator_attr_group,
+				      "initiator", index, data, show,
+				      is_visible);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator);
+
+/**
+ * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir
+ * @boot_kset: boot kset
+ * @index: the ethernet device id
+ * @data: driver specific data
+ * @show: attr show function
+ * @is_visible: attr visibility function
+ *
+ * Note: The boot sysfs lib will free the data passed in for the caller
+ * when all refs to the ethernet kobject have been released.
+ */
+struct iscsi_boot_kobj *
+iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index,
+			   void *data,
+			   ssize_t (*show) (void *data, int type, char *buf),
+			   mode_t (*is_visible) (void *data, int type))
+{
+	return iscsi_boot_create_kobj(boot_kset,
+				      &iscsi_boot_ethernet_attr_group,
+				      "ethernet%d", index, data, show,
+				      is_visible);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet);
+
+/**
+ * iscsi_boot_create_kset() - creates root sysfs tree
+ * @set_name: name of root dir
+ */
+struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name)
+{
+	struct iscsi_boot_kset *boot_kset;
+
+	boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL);
+	if (!boot_kset)
+		return NULL;
+
+	boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj);
+	if (!boot_kset->kset) {
+		kfree(boot_kset);
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&boot_kset->kobj_list);
+	return boot_kset;
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_kset);
+
+/**
+ * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host
+ * @hostno: host number of scsi host
+ */
+struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno)
+{
+	struct iscsi_boot_kset *boot_kset;
+	char *set_name;
+
+	set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno);
+	if (!set_name)
+		return NULL;
+
+	boot_kset = iscsi_boot_create_kset(set_name);
+	kfree(set_name);
+	return boot_kset;
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset);
+
+/**
+ * iscsi_boot_destroy_kset() - destroy kset and kobjects under it
+ * @boot_kset: boot kset
+ *
+ * This will remove the kset and kobjects and attrs under it.
+ */
+void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset)
+{
+	struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
+
+	list_for_each_entry_safe(boot_kobj, tmp_kobj,
+				 &boot_kset->kobj_list, list)
+		iscsi_boot_remove_kobj(boot_kobj);
+
+	kset_unregister(boot_kset->kset);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset);
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c
index ed2801c..4f04ec0 100644
--- a/drivers/firmware/iscsi_ibft.c
+++ b/drivers/firmware/iscsi_ibft.c
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2007 Red Hat, Inc.
+ *  Copyright 2007-2010 Red Hat, Inc.
  *  by Peter Jones <pjones@redhat.com>
  *  Copyright 2008 IBM, Inc.
  *  by Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
@@ -19,6 +19,9 @@
  *
  * Changelog:
  *
+ *  06 Jan 2010 - Peter Jones <pjones@redhat.com>
+ *    New changelog entries are in the git log from now on.  Not here.
+ *
  *  14 Mar 2008 - Konrad Rzeszutek <ketuzsezr@darnok.org>
  *    Updated comments and copyrights. (v0.4.9)
  *
@@ -78,9 +81,11 @@
 #include <linux/stat.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/acpi.h>
+#include <linux/iscsi_boot_sysfs.h>
 
-#define IBFT_ISCSI_VERSION "0.4.9"
-#define IBFT_ISCSI_DATE "2008-Mar-14"
+#define IBFT_ISCSI_VERSION "0.5.0"
+#define IBFT_ISCSI_DATE "2010-Feb-25"
 
 MODULE_AUTHOR("Peter Jones <pjones@redhat.com> and \
 Konrad Rzeszutek <ketuzsezr@darnok.org>");
@@ -166,108 +171,20 @@
 };
 
 /*
- * We do not support the other types, hence the usage of NULL.
- * This maps to the enum ibft_id.
- */
-static const char *ibft_id_names[] =
-	{NULL, NULL, "initiator", "ethernet%d", "target%d", NULL, NULL};
-
-/*
- * The text attributes names for each of the kobjects.
-*/
-enum ibft_eth_properties_enum {
-	ibft_eth_index,
-	ibft_eth_flags,
-	ibft_eth_ip_addr,
-	ibft_eth_subnet_mask,
-	ibft_eth_origin,
-	ibft_eth_gateway,
-	ibft_eth_primary_dns,
-	ibft_eth_secondary_dns,
-	ibft_eth_dhcp,
-	ibft_eth_vlan,
-	ibft_eth_mac,
-	/* ibft_eth_pci_bdf - this is replaced by link to the device itself. */
-	ibft_eth_hostname,
-	ibft_eth_end_marker,
-};
-
-static const char *ibft_eth_properties[] =
-	{"index", "flags", "ip-addr", "subnet-mask", "origin", "gateway",
-	"primary-dns", "secondary-dns", "dhcp", "vlan", "mac", "hostname",
-	NULL};
-
-enum ibft_tgt_properties_enum {
-	ibft_tgt_index,
-	ibft_tgt_flags,
-	ibft_tgt_ip_addr,
-	ibft_tgt_port,
-	ibft_tgt_lun,
-	ibft_tgt_chap_type,
-	ibft_tgt_nic_assoc,
-	ibft_tgt_name,
-	ibft_tgt_chap_name,
-	ibft_tgt_chap_secret,
-	ibft_tgt_rev_chap_name,
-	ibft_tgt_rev_chap_secret,
-	ibft_tgt_end_marker,
-};
-
-static const char *ibft_tgt_properties[] =
-	{"index", "flags", "ip-addr", "port", "lun", "chap-type", "nic-assoc",
-	"target-name", "chap-name", "chap-secret", "rev-chap-name",
-	"rev-chap-name-secret", NULL};
-
-enum ibft_initiator_properties_enum {
-	ibft_init_index,
-	ibft_init_flags,
-	ibft_init_isns_server,
-	ibft_init_slp_server,
-	ibft_init_pri_radius_server,
-	ibft_init_sec_radius_server,
-	ibft_init_initiator_name,
-	ibft_init_end_marker,
-};
-
-static const char *ibft_initiator_properties[] =
-	{"index", "flags", "isns-server", "slp-server", "pri-radius-server",
-	"sec-radius-server", "initiator-name", NULL};
-
-/*
  * The kobject and attribute structures.
  */
 
 struct ibft_kobject {
-	struct ibft_table_header *header;
+	struct acpi_table_ibft *header;
 	union {
 		struct ibft_initiator *initiator;
 		struct ibft_nic *nic;
 		struct ibft_tgt *tgt;
 		struct ibft_hdr *hdr;
 	};
-	struct kobject kobj;
-	struct list_head node;
 };
 
-struct ibft_attribute {
-	struct attribute attr;
-	ssize_t (*show) (struct  ibft_kobject *entry,
-			 struct ibft_attribute *attr, char *buf);
-	union {
-		struct ibft_initiator *initiator;
-		struct ibft_nic *nic;
-		struct ibft_tgt *tgt;
-		struct ibft_hdr *hdr;
-	};
-	struct kobject *kobj;
-	int type; /* The enum of the type. This can be any value of:
-		ibft_eth_properties_enum, ibft_tgt_properties_enum,
-		or ibft_initiator_properties_enum. */
-	struct list_head node;
-};
-
-static LIST_HEAD(ibft_attr_list);
-static LIST_HEAD(ibft_kobject_list);
+static struct iscsi_boot_kset *boot_kset;
 
 static const char nulls[16];
 
@@ -306,35 +223,27 @@
 static int ibft_verify_hdr(char *t, struct ibft_hdr *hdr, int id, int length)
 {
 	if (hdr->id != id) {
-		printk(KERN_ERR "iBFT error: We expected the " \
+		printk(KERN_ERR "iBFT error: We expected the %s " \
 				"field header.id to have %d but " \
-				"found %d instead!\n", id, hdr->id);
+				"found %d instead!\n", t, id, hdr->id);
 		return -ENODEV;
 	}
 	if (hdr->length != length) {
-		printk(KERN_ERR "iBFT error: We expected the " \
+		printk(KERN_ERR "iBFT error: We expected the %s " \
 				"field header.length to have %d but " \
-				"found %d instead!\n", length, hdr->length);
+				"found %d instead!\n", t, length, hdr->length);
 		return -ENODEV;
 	}
 
 	return 0;
 }
 
-static void ibft_release(struct kobject *kobj)
-{
-	struct ibft_kobject *ibft =
-		container_of(kobj, struct ibft_kobject, kobj);
-	kfree(ibft);
-}
-
 /*
  *  Routines for parsing the iBFT data to be human readable.
  */
-static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry,
-					struct ibft_attribute *attr,
-					char *buf)
+static ssize_t ibft_attr_show_initiator(void *data, int type, char *buf)
 {
+	struct ibft_kobject *entry = data;
 	struct ibft_initiator *initiator = entry->initiator;
 	void *ibft_loc = entry->header;
 	char *str = buf;
@@ -342,26 +251,26 @@
 	if (!initiator)
 		return 0;
 
-	switch (attr->type) {
-	case ibft_init_index:
+	switch (type) {
+	case ISCSI_BOOT_INI_INDEX:
 		str += sprintf(str, "%d\n", initiator->hdr.index);
 		break;
-	case ibft_init_flags:
+	case ISCSI_BOOT_INI_FLAGS:
 		str += sprintf(str, "%d\n", initiator->hdr.flags);
 		break;
-	case ibft_init_isns_server:
+	case ISCSI_BOOT_INI_ISNS_SERVER:
 		str += sprintf_ipaddr(str, initiator->isns_server);
 		break;
-	case ibft_init_slp_server:
+	case ISCSI_BOOT_INI_SLP_SERVER:
 		str += sprintf_ipaddr(str, initiator->slp_server);
 		break;
-	case ibft_init_pri_radius_server:
+	case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
 		str += sprintf_ipaddr(str, initiator->pri_radius_server);
 		break;
-	case ibft_init_sec_radius_server:
+	case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
 		str += sprintf_ipaddr(str, initiator->sec_radius_server);
 		break;
-	case ibft_init_initiator_name:
+	case ISCSI_BOOT_INI_INITIATOR_NAME:
 		str += sprintf_string(str, initiator->initiator_name_len,
 				      (char *)ibft_loc +
 				      initiator->initiator_name_off);
@@ -373,10 +282,9 @@
 	return str - buf;
 }
 
-static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
-				  struct ibft_attribute *attr,
-				  char *buf)
+static ssize_t ibft_attr_show_nic(void *data, int type, char *buf)
 {
+	struct ibft_kobject *entry = data;
 	struct ibft_nic *nic = entry->nic;
 	void *ibft_loc = entry->header;
 	char *str = buf;
@@ -385,42 +293,42 @@
 	if (!nic)
 		return 0;
 
-	switch (attr->type) {
-	case ibft_eth_index:
+	switch (type) {
+	case ISCSI_BOOT_ETH_INDEX:
 		str += sprintf(str, "%d\n", nic->hdr.index);
 		break;
-	case ibft_eth_flags:
+	case ISCSI_BOOT_ETH_FLAGS:
 		str += sprintf(str, "%d\n", nic->hdr.flags);
 		break;
-	case ibft_eth_ip_addr:
+	case ISCSI_BOOT_ETH_IP_ADDR:
 		str += sprintf_ipaddr(str, nic->ip_addr);
 		break;
-	case ibft_eth_subnet_mask:
+	case ISCSI_BOOT_ETH_SUBNET_MASK:
 		val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1));
 		str += sprintf(str, "%pI4", &val);
 		break;
-	case ibft_eth_origin:
+	case ISCSI_BOOT_ETH_ORIGIN:
 		str += sprintf(str, "%d\n", nic->origin);
 		break;
-	case ibft_eth_gateway:
+	case ISCSI_BOOT_ETH_GATEWAY:
 		str += sprintf_ipaddr(str, nic->gateway);
 		break;
-	case ibft_eth_primary_dns:
+	case ISCSI_BOOT_ETH_PRIMARY_DNS:
 		str += sprintf_ipaddr(str, nic->primary_dns);
 		break;
-	case ibft_eth_secondary_dns:
+	case ISCSI_BOOT_ETH_SECONDARY_DNS:
 		str += sprintf_ipaddr(str, nic->secondary_dns);
 		break;
-	case ibft_eth_dhcp:
+	case ISCSI_BOOT_ETH_DHCP:
 		str += sprintf_ipaddr(str, nic->dhcp);
 		break;
-	case ibft_eth_vlan:
+	case ISCSI_BOOT_ETH_VLAN:
 		str += sprintf(str, "%d\n", nic->vlan);
 		break;
-	case ibft_eth_mac:
+	case ISCSI_BOOT_ETH_MAC:
 		str += sprintf(str, "%pM\n", nic->mac);
 		break;
-	case ibft_eth_hostname:
+	case ISCSI_BOOT_ETH_HOSTNAME:
 		str += sprintf_string(str, nic->hostname_len,
 				      (char *)ibft_loc + nic->hostname_off);
 		break;
@@ -431,10 +339,9 @@
 	return str - buf;
 };
 
-static ssize_t ibft_attr_show_target(struct ibft_kobject *entry,
-				     struct ibft_attribute *attr,
-				     char *buf)
+static ssize_t ibft_attr_show_target(void *data, int type, char *buf)
 {
+	struct ibft_kobject *entry = data;
 	struct ibft_tgt *tgt = entry->tgt;
 	void *ibft_loc = entry->header;
 	char *str = buf;
@@ -443,48 +350,48 @@
 	if (!tgt)
 		return 0;
 
-	switch (attr->type) {
-	case ibft_tgt_index:
+	switch (type) {
+	case ISCSI_BOOT_TGT_INDEX:
 		str += sprintf(str, "%d\n", tgt->hdr.index);
 		break;
-	case ibft_tgt_flags:
+	case ISCSI_BOOT_TGT_FLAGS:
 		str += sprintf(str, "%d\n", tgt->hdr.flags);
 		break;
-	case ibft_tgt_ip_addr:
+	case ISCSI_BOOT_TGT_IP_ADDR:
 		str += sprintf_ipaddr(str, tgt->ip_addr);
 		break;
-	case ibft_tgt_port:
+	case ISCSI_BOOT_TGT_PORT:
 		str += sprintf(str, "%d\n", tgt->port);
 		break;
-	case ibft_tgt_lun:
+	case ISCSI_BOOT_TGT_LUN:
 		for (i = 0; i < 8; i++)
 			str += sprintf(str, "%x", (u8)tgt->lun[i]);
 		str += sprintf(str, "\n");
 		break;
-	case ibft_tgt_nic_assoc:
+	case ISCSI_BOOT_TGT_NIC_ASSOC:
 		str += sprintf(str, "%d\n", tgt->nic_assoc);
 		break;
-	case ibft_tgt_chap_type:
+	case ISCSI_BOOT_TGT_CHAP_TYPE:
 		str += sprintf(str, "%d\n", tgt->chap_type);
 		break;
-	case ibft_tgt_name:
+	case ISCSI_BOOT_TGT_NAME:
 		str += sprintf_string(str, tgt->tgt_name_len,
 				      (char *)ibft_loc + tgt->tgt_name_off);
 		break;
-	case ibft_tgt_chap_name:
+	case ISCSI_BOOT_TGT_CHAP_NAME:
 		str += sprintf_string(str, tgt->chap_name_len,
 				      (char *)ibft_loc + tgt->chap_name_off);
 		break;
-	case ibft_tgt_chap_secret:
+	case ISCSI_BOOT_TGT_CHAP_SECRET:
 		str += sprintf_string(str, tgt->chap_secret_len,
 				      (char *)ibft_loc + tgt->chap_secret_off);
 		break;
-	case ibft_tgt_rev_chap_name:
+	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
 		str += sprintf_string(str, tgt->rev_chap_name_len,
 				      (char *)ibft_loc +
 				      tgt->rev_chap_name_off);
 		break;
-	case ibft_tgt_rev_chap_secret:
+	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
 		str += sprintf_string(str, tgt->rev_chap_secret_len,
 				      (char *)ibft_loc +
 				      tgt->rev_chap_secret_off);
@@ -496,52 +403,19 @@
 	return str - buf;
 }
 
-/*
- * The routine called for all sysfs attributes.
- */
-static ssize_t ibft_show_attribute(struct kobject *kobj,
-				    struct attribute *attr,
-				    char *buf)
-{
-	struct ibft_kobject *dev =
-		container_of(kobj, struct ibft_kobject, kobj);
-	struct ibft_attribute *ibft_attr =
-		container_of(attr, struct ibft_attribute, attr);
-	ssize_t ret = -EIO;
-	char *str = buf;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-
-	if (ibft_attr->show)
-		ret = ibft_attr->show(dev, ibft_attr, str);
-
-	return ret;
-}
-
-static const struct sysfs_ops ibft_attr_ops = {
-	.show = ibft_show_attribute,
-};
-
-static struct kobj_type ibft_ktype = {
-	.release = ibft_release,
-	.sysfs_ops = &ibft_attr_ops,
-};
-
-static struct kset *ibft_kset;
-
 static int __init ibft_check_device(void)
 {
 	int len;
 	u8 *pos;
 	u8 csum = 0;
 
-	len = ibft_addr->length;
+	len = ibft_addr->header.length;
 
 	/* Sanity checking of iBFT. */
-	if (ibft_addr->revision != 1) {
+	if (ibft_addr->header.revision != 1) {
 		printk(KERN_ERR "iBFT module supports only revision 1, " \
-				"while this is %d.\n", ibft_addr->revision);
+				"while this is %d.\n",
+				ibft_addr->header.revision);
 		return -ENOENT;
 	}
 	for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++)
@@ -556,12 +430,149 @@
 }
 
 /*
+ * Helper routiners to check to determine if the entry is valid
+ * in the proper iBFT structure.
+ */
+static mode_t ibft_check_nic_for(void *data, int type)
+{
+	struct ibft_kobject *entry = data;
+	struct ibft_nic *nic = entry->nic;
+	mode_t rc = 0;
+
+	switch (type) {
+	case ISCSI_BOOT_ETH_INDEX:
+	case ISCSI_BOOT_ETH_FLAGS:
+		rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_ETH_IP_ADDR:
+		if (memcmp(nic->ip_addr, nulls, sizeof(nic->ip_addr)))
+			rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_ETH_SUBNET_MASK:
+		if (nic->subnet_mask_prefix)
+			rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_ETH_ORIGIN:
+		rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_ETH_GATEWAY:
+		if (memcmp(nic->gateway, nulls, sizeof(nic->gateway)))
+			rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_ETH_PRIMARY_DNS:
+		if (memcmp(nic->primary_dns, nulls,
+			   sizeof(nic->primary_dns)))
+			rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_ETH_SECONDARY_DNS:
+		if (memcmp(nic->secondary_dns, nulls,
+			   sizeof(nic->secondary_dns)))
+			rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_ETH_DHCP:
+		if (memcmp(nic->dhcp, nulls, sizeof(nic->dhcp)))
+			rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_ETH_VLAN:
+	case ISCSI_BOOT_ETH_MAC:
+		rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_ETH_HOSTNAME:
+		if (nic->hostname_off)
+			rc = S_IRUGO;
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+static mode_t __init ibft_check_tgt_for(void *data, int type)
+{
+	struct ibft_kobject *entry = data;
+	struct ibft_tgt *tgt = entry->tgt;
+	mode_t rc = 0;
+
+	switch (type) {
+	case ISCSI_BOOT_TGT_INDEX:
+	case ISCSI_BOOT_TGT_FLAGS:
+	case ISCSI_BOOT_TGT_IP_ADDR:
+	case ISCSI_BOOT_TGT_PORT:
+	case ISCSI_BOOT_TGT_LUN:
+	case ISCSI_BOOT_TGT_NIC_ASSOC:
+	case ISCSI_BOOT_TGT_CHAP_TYPE:
+		rc = S_IRUGO;
+	case ISCSI_BOOT_TGT_NAME:
+		if (tgt->tgt_name_len)
+			rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_TGT_CHAP_NAME:
+	case ISCSI_BOOT_TGT_CHAP_SECRET:
+		if (tgt->chap_name_len)
+			rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
+	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
+		if (tgt->rev_chap_name_len)
+			rc = S_IRUGO;
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+static mode_t __init ibft_check_initiator_for(void *data, int type)
+{
+	struct ibft_kobject *entry = data;
+	struct ibft_initiator *init = entry->initiator;
+	mode_t rc = 0;
+
+	switch (type) {
+	case ISCSI_BOOT_INI_INDEX:
+	case ISCSI_BOOT_INI_FLAGS:
+		rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_INI_ISNS_SERVER:
+		if (memcmp(init->isns_server, nulls,
+			   sizeof(init->isns_server)))
+			rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_INI_SLP_SERVER:
+		if (memcmp(init->slp_server, nulls,
+			   sizeof(init->slp_server)))
+			rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
+		if (memcmp(init->pri_radius_server, nulls,
+			   sizeof(init->pri_radius_server)))
+			rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
+		if (memcmp(init->sec_radius_server, nulls,
+			   sizeof(init->sec_radius_server)))
+			rc = S_IRUGO;
+		break;
+	case ISCSI_BOOT_INI_INITIATOR_NAME:
+		if (init->initiator_name_len)
+			rc = S_IRUGO;
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+/*
  * Helper function for ibft_register_kobjects.
  */
-static int __init ibft_create_kobject(struct ibft_table_header *header,
-				       struct ibft_hdr *hdr,
-				       struct list_head *list)
+static int __init ibft_create_kobject(struct acpi_table_ibft *header,
+				      struct ibft_hdr *hdr)
 {
+	struct iscsi_boot_kobj *boot_kobj = NULL;
 	struct ibft_kobject *ibft_kobj = NULL;
 	struct ibft_nic *nic = (struct ibft_nic *)hdr;
 	struct pci_dev *pci_dev;
@@ -578,14 +589,47 @@
 	case id_initiator:
 		rc = ibft_verify_hdr("initiator", hdr, id_initiator,
 				     sizeof(*ibft_kobj->initiator));
+		if (rc)
+			break;
+
+		boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index,
+						ibft_kobj,
+						ibft_attr_show_initiator,
+						ibft_check_initiator_for);
+		if (!boot_kobj) {
+			rc = -ENOMEM;
+			goto free_ibft_obj;
+		}
 		break;
 	case id_nic:
 		rc = ibft_verify_hdr("ethernet", hdr, id_nic,
 				     sizeof(*ibft_kobj->nic));
+		if (rc)
+			break;
+
+		boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index,
+						       ibft_kobj,
+						       ibft_attr_show_nic,
+						       ibft_check_nic_for);
+		if (!boot_kobj) {
+			rc = -ENOMEM;
+			goto free_ibft_obj;
+		}
 		break;
 	case id_target:
 		rc = ibft_verify_hdr("target", hdr, id_target,
 				     sizeof(*ibft_kobj->tgt));
+		if (rc)
+			break;
+
+		boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index,
+						     ibft_kobj,
+						     ibft_attr_show_target,
+						     ibft_check_tgt_for);
+		if (!boot_kobj) {
+			rc = -ENOMEM;
+			goto free_ibft_obj;
+		}
 		break;
 	case id_reserved:
 	case id_control:
@@ -596,29 +640,17 @@
 	default:
 		printk(KERN_ERR "iBFT has unknown structure type (%d). " \
 				"Report this bug to %.6s!\n", hdr->id,
-				header->oem_id);
+				header->header.oem_id);
 		rc = 1;
 		break;
 	}
 
 	if (rc) {
 		/* Skip adding this kobject, but exit with non-fatal error. */
-		kfree(ibft_kobj);
-		goto out_invalid_struct;
+		rc = 0;
+		goto free_ibft_obj;
 	}
 
-	ibft_kobj->kobj.kset = ibft_kset;
-
-	rc = kobject_init_and_add(&ibft_kobj->kobj, &ibft_ktype,
-				  NULL, ibft_id_names[hdr->id], hdr->index);
-
-	if (rc) {
-		kfree(ibft_kobj);
-		goto out;
-	}
-
-	kobject_uevent(&ibft_kobj->kobj, KOBJ_ADD);
-
 	if (hdr->id == id_nic) {
 		/*
 		* We don't search for the device in other domains than
@@ -629,19 +661,16 @@
 		pci_dev = pci_get_bus_and_slot((nic->pci_bdf & 0xff00) >> 8,
 					       (nic->pci_bdf & 0xff));
 		if (pci_dev) {
-			rc = sysfs_create_link(&ibft_kobj->kobj,
+			rc = sysfs_create_link(&boot_kobj->kobj,
 					       &pci_dev->dev.kobj, "device");
 			pci_dev_put(pci_dev);
 		}
 	}
-
-	/* Nothing broke so lets add it to the list. */
-	list_add_tail(&ibft_kobj->node, list);
-out:
-	return rc;
-out_invalid_struct:
-	/* Unsupported structs are skipped. */
 	return 0;
+
+free_ibft_obj:
+	kfree(ibft_kobj);
+	return rc;
 }
 
 /*
@@ -649,8 +678,7 @@
  * found add them on the passed-in list. We do not support the other
  * fields at this point, so they are skipped.
  */
-static int __init ibft_register_kobjects(struct ibft_table_header *header,
-					  struct list_head *list)
+static int __init ibft_register_kobjects(struct acpi_table_ibft *header)
 {
 	struct ibft_control *control = NULL;
 	void *ptr, *end;
@@ -660,7 +688,7 @@
 
 	control = (void *)header + sizeof(*header);
 	end = (void *)control + control->hdr.length;
-	eot_offset = (void *)header + header->length - (void *)control;
+	eot_offset = (void *)header + header->header.length - (void *)control;
 	rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control,
 			     sizeof(*control));
 
@@ -672,10 +700,10 @@
 	}
 	for (ptr = &control->initiator_off; ptr < end; ptr += sizeof(u16)) {
 		offset = *(u16 *)ptr;
-		if (offset && offset < header->length && offset < eot_offset) {
+		if (offset && offset < header->header.length &&
+						offset < eot_offset) {
 			rc = ibft_create_kobject(header,
-						 (void *)header + offset,
-						 list);
+						 (void *)header + offset);
 			if (rc)
 				break;
 		}
@@ -684,240 +712,28 @@
 	return rc;
 }
 
-static void ibft_unregister(struct list_head *attr_list,
-			     struct list_head *kobj_list)
+static void ibft_unregister(void)
 {
-	struct ibft_kobject *data = NULL, *n;
-	struct ibft_attribute *attr = NULL, *m;
+	struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
+	struct ibft_kobject *ibft_kobj;
 
-	list_for_each_entry_safe(attr, m, attr_list, node) {
-		sysfs_remove_file(attr->kobj, &attr->attr);
-		list_del(&attr->node);
-		kfree(attr);
+	list_for_each_entry_safe(boot_kobj, tmp_kobj,
+				 &boot_kset->kobj_list, list) {
+		ibft_kobj = boot_kobj->data;
+		if (ibft_kobj->hdr->id == id_nic)
+			sysfs_remove_link(&boot_kobj->kobj, "device");
 	};
-	list_del_init(attr_list);
-
-	list_for_each_entry_safe(data, n, kobj_list, node) {
-		list_del(&data->node);
-		if (data->hdr->id == id_nic)
-			sysfs_remove_link(&data->kobj, "device");
-		kobject_put(&data->kobj);
-	};
-	list_del_init(kobj_list);
 }
 
-static int __init ibft_create_attribute(struct ibft_kobject *kobj_data,
-					 int type,
-					 const char *name,
-					 ssize_t (*show)(struct ibft_kobject *,
-							 struct ibft_attribute*,
-							 char *buf),
-					 struct list_head *list)
+static void ibft_cleanup(void)
 {
-	struct ibft_attribute *attr = NULL;
-	struct ibft_hdr *hdr = kobj_data->hdr;
-
-	attr = kmalloc(sizeof(*attr), GFP_KERNEL);
-	if (!attr)
-		return -ENOMEM;
-
-	attr->attr.name = name;
-	attr->attr.mode = S_IRUSR;
-
-	attr->hdr = hdr;
-	attr->show = show;
-	attr->kobj = &kobj_data->kobj;
-	attr->type = type;
-
-	list_add_tail(&attr->node, list);
-
-	return 0;
+	ibft_unregister();
+	iscsi_boot_destroy_kset(boot_kset);
 }
 
-/*
- * Helper routiners to check to determine if the entry is valid
- * in the proper iBFT structure.
- */
-static int __init ibft_check_nic_for(struct ibft_nic *nic, int entry)
+static void __exit ibft_exit(void)
 {
-	int rc = 0;
-
-	switch (entry) {
-	case ibft_eth_index:
-	case ibft_eth_flags:
-		rc = 1;
-		break;
-	case ibft_eth_ip_addr:
-		if (memcmp(nic->ip_addr, nulls, sizeof(nic->ip_addr)))
-			rc = 1;
-		break;
-	case ibft_eth_subnet_mask:
-		if (nic->subnet_mask_prefix)
-			rc = 1;
-		break;
-	case ibft_eth_origin:
-		rc = 1;
-		break;
-	case ibft_eth_gateway:
-		if (memcmp(nic->gateway, nulls, sizeof(nic->gateway)))
-			rc = 1;
-		break;
-	case ibft_eth_primary_dns:
-		if (memcmp(nic->primary_dns, nulls,
-			   sizeof(nic->primary_dns)))
-			rc = 1;
-		break;
-	case ibft_eth_secondary_dns:
-		if (memcmp(nic->secondary_dns, nulls,
-			   sizeof(nic->secondary_dns)))
-			rc = 1;
-		break;
-	case ibft_eth_dhcp:
-		if (memcmp(nic->dhcp, nulls, sizeof(nic->dhcp)))
-			rc = 1;
-		break;
-	case ibft_eth_vlan:
-	case ibft_eth_mac:
-		rc = 1;
-		break;
-	case ibft_eth_hostname:
-		if (nic->hostname_off)
-			rc = 1;
-		break;
-	default:
-		break;
-	}
-
-	return rc;
-}
-
-static int __init ibft_check_tgt_for(struct ibft_tgt *tgt, int entry)
-{
-	int rc = 0;
-
-	switch (entry) {
-	case ibft_tgt_index:
-	case ibft_tgt_flags:
-	case ibft_tgt_ip_addr:
-	case ibft_tgt_port:
-	case ibft_tgt_lun:
-	case ibft_tgt_nic_assoc:
-	case ibft_tgt_chap_type:
-		rc = 1;
-	case ibft_tgt_name:
-		if (tgt->tgt_name_len)
-			rc = 1;
-		break;
-	case ibft_tgt_chap_name:
-	case ibft_tgt_chap_secret:
-		if (tgt->chap_name_len)
-			rc = 1;
-		break;
-	case ibft_tgt_rev_chap_name:
-	case ibft_tgt_rev_chap_secret:
-		if (tgt->rev_chap_name_len)
-			rc = 1;
-		break;
-	default:
-		break;
-	}
-
-	return rc;
-}
-
-static int __init ibft_check_initiator_for(struct ibft_initiator *init,
-					    int entry)
-{
-	int rc = 0;
-
-	switch (entry) {
-	case ibft_init_index:
-	case ibft_init_flags:
-		rc = 1;
-		break;
-	case ibft_init_isns_server:
-		if (memcmp(init->isns_server, nulls,
-			   sizeof(init->isns_server)))
-			rc = 1;
-		break;
-	case ibft_init_slp_server:
-		if (memcmp(init->slp_server, nulls,
-			   sizeof(init->slp_server)))
-			rc = 1;
-		break;
-	case ibft_init_pri_radius_server:
-		if (memcmp(init->pri_radius_server, nulls,
-			   sizeof(init->pri_radius_server)))
-			rc = 1;
-		break;
-	case ibft_init_sec_radius_server:
-		if (memcmp(init->sec_radius_server, nulls,
-			   sizeof(init->sec_radius_server)))
-			rc = 1;
-		break;
-	case ibft_init_initiator_name:
-		if (init->initiator_name_len)
-			rc = 1;
-		break;
-	default:
-		break;
-	}
-
-	return rc;
-}
-
-/*
- *  Register the attributes for all of the kobjects.
- */
-static int __init ibft_register_attributes(struct list_head *kobject_list,
-					    struct list_head *attr_list)
-{
-	int rc = 0, i = 0;
-	struct ibft_kobject *data = NULL;
-	struct ibft_attribute *attr = NULL, *m;
-
-	list_for_each_entry(data, kobject_list, node) {
-		switch (data->hdr->id) {
-		case id_nic:
-			for (i = 0; i < ibft_eth_end_marker && !rc; i++)
-				if (ibft_check_nic_for(data->nic, i))
-					rc = ibft_create_attribute(data, i,
-						ibft_eth_properties[i],
-						ibft_attr_show_nic, attr_list);
-			break;
-		case id_target:
-			for (i = 0; i < ibft_tgt_end_marker && !rc; i++)
-				if (ibft_check_tgt_for(data->tgt, i))
-					rc = ibft_create_attribute(data, i,
-						ibft_tgt_properties[i],
-						ibft_attr_show_target,
-						attr_list);
-			break;
-		case id_initiator:
-			for (i = 0; i < ibft_init_end_marker && !rc; i++)
-				if (ibft_check_initiator_for(
-					data->initiator, i))
-					rc = ibft_create_attribute(data, i,
-						ibft_initiator_properties[i],
-						ibft_attr_show_initiator,
-						attr_list);
-			break;
-		default:
-			break;
-		}
-		if (rc)
-			break;
-	}
-	list_for_each_entry_safe(attr, m, attr_list, node) {
-		rc = sysfs_create_file(attr->kobj, &attr->attr);
-		if (rc) {
-			list_del(&attr->node);
-			kfree(attr);
-			break;
-		}
-	}
-
-	return rc;
+	ibft_cleanup();
 }
 
 /*
@@ -927,26 +743,20 @@
 {
 	int rc = 0;
 
-	ibft_kset = kset_create_and_add("ibft", NULL, firmware_kobj);
-	if (!ibft_kset)
-		return -ENOMEM;
-
 	if (ibft_addr) {
 		printk(KERN_INFO "iBFT detected at 0x%llx.\n",
 		       (u64)isa_virt_to_bus(ibft_addr));
 
 		rc = ibft_check_device();
 		if (rc)
-			goto out_firmware_unregister;
+			return rc;
+
+		boot_kset = iscsi_boot_create_kset("ibft");
+		if (!boot_kset)
+			return -ENOMEM;
 
 		/* Scan the IBFT for data and register the kobjects. */
-		rc = ibft_register_kobjects(ibft_addr, &ibft_kobject_list);
-		if (rc)
-			goto out_free;
-
-		/* Register the attributes */
-		rc = ibft_register_attributes(&ibft_kobject_list,
-					      &ibft_attr_list);
+		rc = ibft_register_kobjects(ibft_addr);
 		if (rc)
 			goto out_free;
 	} else
@@ -955,17 +765,9 @@
 	return 0;
 
 out_free:
-	ibft_unregister(&ibft_attr_list, &ibft_kobject_list);
-out_firmware_unregister:
-	kset_unregister(ibft_kset);
+	ibft_cleanup();
 	return rc;
 }
 
-static void __exit ibft_exit(void)
-{
-	ibft_unregister(&ibft_attr_list, &ibft_kobject_list);
-	kset_unregister(ibft_kset);
-}
-
 module_init(ibft_init);
 module_exit(ibft_exit);
diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c
index d6470ef..2192456 100644
--- a/drivers/firmware/iscsi_ibft_find.c
+++ b/drivers/firmware/iscsi_ibft_find.c
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2007 Red Hat, Inc.
+ *  Copyright 2007-2010 Red Hat, Inc.
  *  by Peter Jones <pjones@redhat.com>
  *  Copyright 2007 IBM, Inc.
  *  by Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
@@ -22,6 +22,7 @@
 #include <linux/blkdev.h>
 #include <linux/ctype.h>
 #include <linux/device.h>
+#include <linux/efi.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/limits.h>
@@ -30,13 +31,15 @@
 #include <linux/stat.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/acpi.h>
+#include <linux/iscsi_ibft.h>
 
 #include <asm/mmzone.h>
 
 /*
  * Physical location of iSCSI Boot Format Table.
  */
-struct ibft_table_header *ibft_addr;
+struct acpi_table_ibft *ibft_addr;
 EXPORT_SYMBOL_GPL(ibft_addr);
 
 #define IBFT_SIGN "iBFT"
@@ -46,19 +49,20 @@
 #define VGA_MEM 0xA0000 /* VGA buffer */
 #define VGA_SIZE 0x20000 /* 128kB */
 
+#ifdef CONFIG_ACPI
+static int __init acpi_find_ibft(struct acpi_table_header *header)
+{
+	ibft_addr = (struct acpi_table_ibft *)header;
+	return 0;
+}
+#endif /* CONFIG_ACPI */
 
-/*
- * Routine used to find the iSCSI Boot Format Table. The logical
- * kernel address is set in the ibft_addr global variable.
- */
-unsigned long __init find_ibft_region(unsigned long *sizep)
+static int __init find_ibft_in_mem(void)
 {
 	unsigned long pos;
 	unsigned int len = 0;
 	void *virt;
 
-	ibft_addr = NULL;
-
 	for (pos = IBFT_START; pos < IBFT_END; pos += 16) {
 		/* The table can't be inside the VGA BIOS reserved space,
 		 * so skip that area */
@@ -72,14 +76,42 @@
 			/* if the length of the table extends past 1M,
 			 * the table cannot be valid. */
 			if (pos + len <= (IBFT_END-1)) {
-				ibft_addr = (struct ibft_table_header *)virt;
+				ibft_addr = (struct acpi_table_ibft *)virt;
 				break;
 			}
 		}
 	}
+	return len;
+}
+/*
+ * Routine used to find the iSCSI Boot Format Table. The logical
+ * kernel address is set in the ibft_addr global variable.
+ */
+unsigned long __init find_ibft_region(unsigned long *sizep)
+{
+
+	ibft_addr = NULL;
+
+#ifdef CONFIG_ACPI
+	/*
+	 * One spec says "IBFT", the other says "iBFT". We have to check
+	 * for both.
+	 */
+	if (!ibft_addr)
+		acpi_table_parse(ACPI_SIG_IBFT, acpi_find_ibft);
+	if (!ibft_addr)
+		acpi_table_parse(IBFT_SIGN, acpi_find_ibft);
+#endif /* CONFIG_ACPI */
+
+	/* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will
+	 * only use ACPI for this */
+
+	if (!ibft_addr && !efi_enabled)
+		find_ibft_in_mem();
+
 	if (ibft_addr) {
-		*sizep = PAGE_ALIGN(len);
-		return pos;
+		*sizep = PAGE_ALIGN(ibft_addr->header.length);
+		return (u64)isa_virt_to_bus(ibft_addr);
 	}
 
 	*sizep = 0;
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 4340993..6369ba7 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -68,6 +68,14 @@
 	---help---
 	Support for A4 tech X5 and WOP-35 / Trust 450L mice.
 
+config HID_ACRUX_FF
+	tristate "ACRUX force feedback support"
+	depends on USB_HID
+	select INPUT_FF_MEMLESS
+	---help---
+	Say Y here if you want to enable force feedback support for ACRUX
+	game controllers.
+
 config HID_APPLE
 	tristate "Apple" if EMBEDDED
 	depends on (USB_HID || BT_HIDP)
@@ -148,6 +156,12 @@
 	---help---
 	Support for the eGalax dual-touch panel.
 
+config HID_ELECOM
+	tristate "ELECOM"
+	depends on BT_HIDP
+	---help---
+	Support for the ELECOM BM084 (bluetooth mouse).
+
 config HID_EZKEY
 	tristate "Ezkey" if EMBEDDED
 	depends on USB_HID
@@ -417,10 +431,11 @@
 	enable force feedback support for it.
 
 config HID_TOPSEED
-	tristate "TopSeed Cyberlink remote control support"
+	tristate "TopSeed Cyberlink, BTC Emprex, Conceptronic remote control support"
 	depends on USB_HID
 	---help---
-	Say Y if you have a TopSeed Cyberlink or BTC Emprex remote control.
+	Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic
+	CLLRCMCE remote control.
 
 config HID_THRUSTMASTER
 	tristate "ThrustMaster devices support"
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 987fa06..46f037f 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -24,6 +24,7 @@
 
 obj-$(CONFIG_HID_3M_PCT)	+= hid-3m-pct.o
 obj-$(CONFIG_HID_A4TECH)	+= hid-a4tech.o
+obj-$(CONFIG_HID_ACRUX_FF)	+= hid-axff.o
 obj-$(CONFIG_HID_APPLE)		+= hid-apple.o
 obj-$(CONFIG_HID_BELKIN)	+= hid-belkin.o
 obj-$(CONFIG_HID_CANDO)		+= hid-cando.o
@@ -32,6 +33,7 @@
 obj-$(CONFIG_HID_CYPRESS)	+= hid-cypress.o
 obj-$(CONFIG_HID_DRAGONRISE)	+= hid-drff.o
 obj-$(CONFIG_HID_EGALAX)	+= hid-egalax.o
+obj-$(CONFIG_HID_ELECOM)	+= hid-elecom.o
 obj-$(CONFIG_HID_EZKEY)		+= hid-ezkey.o
 obj-$(CONFIG_HID_GYRATION)	+= hid-gyration.o
 obj-$(CONFIG_HID_KENSINGTON)	+= hid-kensington.o
diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c
new file mode 100644
index 0000000..f42ee14
--- /dev/null
+++ b/drivers/hid/hid-axff.c
@@ -0,0 +1,172 @@
+/*
+ * Force feedback support for ACRUX game controllers
+ *
+ * From what I have gathered, these devices are mass produced in China
+ * by several vendors. They often share the same design as the original
+ * Xbox 360 controller.
+ *
+ * 1a34:0802 "ACRUX USB GAMEPAD 8116"
+ *  - tested with a EXEQ EQ-PCU-02090 game controller.
+ *
+ * Copyright (c) 2010 Sergei Kolzun <x0r@dv-life.ru>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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/input.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+
+struct axff_device {
+	struct hid_report *report;
+};
+
+static int axff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
+{
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct axff_device *axff = data;
+	int left, right;
+
+	left = effect->u.rumble.strong_magnitude;
+	right = effect->u.rumble.weak_magnitude;
+
+	dbg_hid("called with 0x%04x 0x%04x", left, right);
+
+	left = left * 0xff / 0xffff;
+	right = right * 0xff / 0xffff;
+
+	axff->report->field[0]->value[0] = left;
+	axff->report->field[1]->value[0] = right;
+	axff->report->field[2]->value[0] = left;
+	axff->report->field[3]->value[0] = right;
+	dbg_hid("running with 0x%02x 0x%02x", left, right);
+	usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
+
+	return 0;
+}
+
+static int axff_init(struct hid_device *hid)
+{
+	struct axff_device *axff;
+	struct hid_report *report;
+	struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
+	struct list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct input_dev *dev = hidinput->input;
+	int error;
+
+	if (list_empty(report_list)) {
+		dev_err(&hid->dev, "no output reports found\n");
+		return -ENODEV;
+	}
+
+	report = list_first_entry(report_list, struct hid_report, list);
+
+	if (report->maxfield < 4) {
+		dev_err(&hid->dev, "no fields in the report: %d\n", report->maxfield);
+		return -ENODEV;
+	}
+
+	axff = kzalloc(sizeof(struct axff_device), GFP_KERNEL);
+	if (!axff)
+		return -ENOMEM;
+
+	set_bit(FF_RUMBLE, dev->ffbit);
+
+	error = input_ff_create_memless(dev, axff, axff_play);
+	if (error)
+		goto err_free_mem;
+
+	axff->report = report;
+	axff->report->field[0]->value[0] = 0x00;
+	axff->report->field[1]->value[0] = 0x00;
+	axff->report->field[2]->value[0] = 0x00;
+	axff->report->field[3]->value[0] = 0x00;
+	usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
+
+	dev_info(&hid->dev, "Force Feedback for ACRUX game controllers by Sergei Kolzun<x0r@dv-life.ru>\n");
+
+	return 0;
+
+err_free_mem:
+	kfree(axff);
+	return error;
+}
+
+static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int error;
+
+	dev_dbg(&hdev->dev, "ACRUX HID hardware probe...");
+
+	error = hid_parse(hdev);
+	if (error) {
+		dev_err(&hdev->dev, "parse failed\n");
+		return error;
+	}
+
+	error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+	if (error) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		return error;
+	}
+
+	error = axff_init(hdev);
+	if (error) {
+		/*
+		 * Do not fail device initialization completely as device
+		 * may still be partially operable, just warn.
+		 */
+		dev_warn(&hdev->dev,
+			 "Failed to enable force feedback support, error: %d\n",
+			 error);
+	}
+
+	return 0;
+}
+
+static const struct hid_device_id ax_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802), },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, ax_devices);
+
+static struct hid_driver ax_driver = {
+	.name = "acrux",
+	.id_table = ax_devices,
+	.probe = ax_probe,
+};
+
+static int __init ax_init(void)
+{
+	return hid_register_driver(&ax_driver);
+}
+
+static void __exit ax_exit(void)
+{
+	hid_unregister_driver(&ax_driver);
+}
+
+module_init(ax_init);
+module_exit(ax_exit);
+
+MODULE_AUTHOR("Sergei Kolzun");
+MODULE_DESCRIPTION("Force feedback support for ACRUX game controllers");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 866e54e..e635199 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1157,6 +1157,8 @@
 
 	if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE)
 		connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV);
+	if (hdev->quirks & HID_QUIRK_HIDINPUT_FORCE)
+		connect_mask |= HID_CONNECT_HIDINPUT_FORCE;
 	if (hdev->bus != BUS_USB)
 		connect_mask &= ~HID_CONNECT_HIDDEV;
 	if (hid_hiddev(hdev))
@@ -1239,6 +1241,9 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
+#if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE)
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
+#endif
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
@@ -1294,6 +1299,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
@@ -1375,10 +1381,10 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
-	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
@@ -1586,6 +1592,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) },
diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c
new file mode 100644
index 0000000..7a40878
--- /dev/null
+++ b/drivers/hid/hid-elecom.c
@@ -0,0 +1,57 @@
+/*
+ *  HID driver for Elecom BM084 (bluetooth mouse).
+ *  Removes a non-existing horizontal wheel from
+ *  the HID descriptor.
+ *  (This module is based on "hid-ortek".)
+ *
+ *  Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static void elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int rsize)
+{
+	if (rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) {
+		dev_info(&hdev->dev, "Fixing up Elecom BM084 "
+				"report descriptor.\n");
+		rdesc[47] = 0x00;
+	}
+}
+
+static const struct hid_device_id elecom_devices[] = {
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084)},
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, elecom_devices);
+
+static struct hid_driver elecom_driver = {
+	.name = "elecom",
+	.id_table = elecom_devices,
+	.report_fixup = elecom_report_fixup
+};
+
+static int __init elecom_init(void)
+{
+	return hid_register_driver(&elecom_driver);
+}
+
+static void __exit elecom_exit(void)
+{
+	hid_unregister_driver(&elecom_driver);
+}
+
+module_init(elecom_init);
+module_exit(elecom_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 31601ee..d3fc13a 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -34,6 +34,8 @@
 #define USB_DEVICE_ID_ACECAD_FLAIR	0x0004
 #define USB_DEVICE_ID_ACECAD_302	0x0008
 
+#define USB_VENDOR_ID_ACRUX		0x1a34
+
 #define USB_VENDOR_ID_ADS_TECH 		0x06e1
 #define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X	0xa155
 
@@ -81,12 +83,12 @@
 #define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI	0x0223
 #define USB_DEVICE_ID_APPLE_WELLSPRING_ISO	0x0224
 #define USB_DEVICE_ID_APPLE_WELLSPRING_JIS	0x0225
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI    0x0229
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO     0x022a
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS     0x022b
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI  0x022c
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO   0x022d
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS   0x022e
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI	0x0229
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO	0x022a
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS	0x022b
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI	0x022c
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO	0x022d
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS	0x022e
 #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI	0x0230
 #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO	0x0231
 #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS	0x0232
@@ -118,8 +120,8 @@
 #define USB_VENDOR_ID_AVERMEDIA		0x07ca
 #define USB_DEVICE_ID_AVER_FM_MR800	0xb800
 
-#define USB_VENDOR_ID_BELKIN           0x050d
-#define USB_DEVICE_ID_FLIP_KVM         0x3201
+#define USB_VENDOR_ID_BELKIN		0x050d
+#define USB_DEVICE_ID_FLIP_KVM		0x3201
 
 #define USB_VENDOR_ID_BERKSHIRE		0x0c98
 #define USB_DEVICE_ID_BERKSHIRE_PCWD	0x1140
@@ -128,7 +130,7 @@
 #define USB_DEVICE_ID_BTC_EMPREX_REMOTE	0x5578
 
 #define USB_VENDOR_ID_CANDO		0x2087
-#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01
+#define USB_DEVICE_ID_CANDO_MULTI_TOUCH	0x0a01
 #define USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 0x0b03
 
 #define USB_VENDOR_ID_CH		0x068e
@@ -175,7 +177,7 @@
 #define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701	0x819a
 
 #define USB_VENDOR_ID_DELORME		0x1163
-#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
+#define USB_DEVICE_ID_DELORME_EARTHMATE	0x0100
 #define USB_DEVICE_ID_DELORME_EM_LT20	0x0200
 
 #define USB_VENDOR_ID_DMI		0x0c0b
@@ -187,19 +189,23 @@
 #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER	0x0001
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH	0x480d
 
+#define USB_VENDOR_ID_ELECOM		0x056e
+#define USB_DEVICE_ID_ELECOM_BM084	0x0061
+
 #define USB_VENDOR_ID_ELO		0x04E7
 #define USB_DEVICE_ID_ELO_TS2700	0x0020
 
 #define USB_VENDOR_ID_ESSENTIAL_REALITY	0x0d7f
 #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
 
+#define USB_VENDOR_ID_ETT		0x0664
+#define USB_DEVICE_ID_TC5UH		0x0309
+#define USB_DEVICE_ID_TC4UM		0x0306
+
 #define USB_VENDOR_ID_ETURBOTOUCH	0x22b9
 #define USB_DEVICE_ID_ETURBOTOUCH	0x0006
 
-#define USB_VENDOR_ID_ETT		0x0664
-#define USB_DEVICE_ID_TC5UH		0x0309
-
-#define USB_VENDOR_ID_EZKEY 		0x0518
+#define USB_VENDOR_ID_EZKEY		0x0518
 #define USB_DEVICE_ID_BTC_8193		0x0002
 
 #define USB_VENDOR_ID_GAMERON		0x0810
@@ -296,9 +302,16 @@
 #define USB_VENDOR_ID_KBGEAR		0x084e
 #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO	0x1001
 
+#define USB_VENDOR_ID_KENSINGTON	0x047d
+#define USB_DEVICE_ID_KS_SLIMBLADE	0x2041
+
 #define USB_VENDOR_ID_KWORLD		0x1b80
 #define USB_DEVICE_ID_KWORLD_RADIO_FM700	0xd700
 
+#define USB_VENDOR_ID_KYE		0x0458
+#define USB_DEVICE_ID_KYE_ERGO_525V	0x0087
+#define USB_DEVICE_ID_KYE_GPEN_560	0x5003
+
 #define USB_VENDOR_ID_LABTEC		0x1020
 #define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD	0x0006
 
@@ -318,9 +331,6 @@
 #define USB_DEVICE_ID_LD_POWERCONTROL	0x2030
 #define USB_DEVICE_ID_LD_MACHINETEST	0x2040
 
-#define USB_VENDOR_ID_KENSINGTON	0x047d
-#define USB_DEVICE_ID_KS_SLIMBLADE	0x2041
-
 #define USB_VENDOR_ID_LOGITECH		0x046d
 #define USB_DEVICE_ID_LOGITECH_RECEIVER	0xc101
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
@@ -376,23 +386,23 @@
 #define USB_VENDOR_ID_MONTEREY		0x0566
 #define USB_DEVICE_ID_GENIUS_KB29E	0x3004
 
+#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
+#define USB_DEVICE_ID_N_S_HARMONY	0xc359
+
+#define USB_VENDOR_ID_NATSU		0x08b7
+#define USB_DEVICE_ID_NATSU_GAMEPAD	0x0001
+
 #define USB_VENDOR_ID_NCR		0x0404
 #define USB_DEVICE_ID_NCR_FIRST		0x0300
 #define USB_DEVICE_ID_NCR_LAST		0x03ff
 
-#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
-#define USB_DEVICE_ID_N_S_HARMONY       0xc359
-
-#define USB_VENDOR_ID_NATSU             0x08b7
-#define USB_DEVICE_ID_NATSU_GAMEPAD     0x0001
-
 #define USB_VENDOR_ID_NEC		0x073e
 #define USB_DEVICE_ID_NEC_USB_GAME_PAD	0x0301
 
 #define USB_VENDOR_ID_NEXTWINDOW	0x1926
 #define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN	0x0003
 
-#define USB_VENDOR_ID_NTRIG                0x1b96
+#define USB_VENDOR_ID_NTRIG		0x1b96
 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN   0x0001
 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1   0x0003
 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2   0x0004
@@ -427,9 +437,12 @@
 #define USB_VENDOR_ID_PETALYNX		0x18b1
 #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE	0x0037
 
-#define USB_VENDOR_ID_PHILIPS       0x0471
+#define USB_VENDOR_ID_PHILIPS		0x0471
 #define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617
 
+#define USB_VENDOR_ID_PI_ENGINEERING	0x05f3
+#define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL	0xff
+
 #define USB_VENDOR_ID_PLAYDOTCOM	0x0b43
 #define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII	0x0003
 
@@ -439,16 +452,16 @@
 #define USB_VENDOR_ID_PRODIGE		0x05af
 #define USB_DEVICE_ID_PRODIGE_CORDLESS	0x3062
 
+#define USB_VENDOR_ID_QUANTA		0x0408
+#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH	0x3000
+#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN	0x3001
+
 #define USB_VENDOR_ID_ROCCAT		0x1e7d
 #define USB_DEVICE_ID_ROCCAT_KONE	0x2ced
 
 #define USB_VENDOR_ID_SAITEK		0x06a3
 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD	0xff17
 
-#define USB_VENDOR_ID_QUANTA		0x0408
-#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH	0x3000
-#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN	0x3001
-
 #define USB_VENDOR_ID_SAMSUNG		0x0419
 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE	0x0001
 #define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE	0x0600
@@ -472,20 +485,23 @@
 
 #define USB_VENDOR_ID_THRUSTMASTER	0x044f
 
-#define USB_VENDOR_ID_TOUCHPACK		0x1bfd
-#define USB_DEVICE_ID_TOUCHPACK_RTS	0x1688
+#define USB_VENDOR_ID_TOPSEED		0x0766
+#define USB_DEVICE_ID_TOPSEED_CYBERLINK	0x0204
+
+#define USB_VENDOR_ID_TOPSEED2		0x1784
+#define USB_DEVICE_ID_TOPSEED2_RF_COMBO	0x0004
 
 #define USB_VENDOR_ID_TOPMAX		0x0663
 #define USB_DEVICE_ID_TOPMAX_COBRAPAD	0x0103
 
-#define USB_VENDOR_ID_TOPSEED		0x0766
-#define USB_DEVICE_ID_TOPSEED_CYBERLINK	0x0204
+#define USB_VENDOR_ID_TOUCHPACK		0x1bfd
+#define USB_DEVICE_ID_TOUCHPACK_RTS	0x1688
 
 #define USB_VENDOR_ID_TURBOX		0x062a
 #define USB_DEVICE_ID_TURBOX_KEYBOARD	0x0201
 
-#define USB_VENDOR_ID_TWINHAN           0x6253
-#define USB_DEVICE_ID_TWINHAN_IR_REMOTE 0x0100
+#define USB_VENDOR_ID_TWINHAN		0x6253
+#define USB_DEVICE_ID_TWINHAN_IR_REMOTE	0x0100
 
 #define USB_VENDOR_ID_UCLOGIC		0x5543
 #define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209	0x0042
@@ -500,7 +516,6 @@
 
 #define USB_VENDOR_ID_WACOM		0x056a
 #define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH	0x81
-#define USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH	0xbd
 
 #define USB_VENDOR_ID_WISEGROUP		0x0925
 #define USB_DEVICE_ID_SMARTJOY_PLUS	0x0005
@@ -522,9 +537,4 @@
 #define USB_VENDOR_ID_ZYDACRON	0x13EC
 #define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL	0x0006
 
-#define USB_VENDOR_ID_KYE		0x0458
-#define USB_DEVICE_ID_KYE_ERGO_525V	0x0087
-#define USB_DEVICE_ID_KYE_GPEN_560	0x5003
-
-
 #endif
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 7a0d2e4..6c03dcc 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -199,11 +199,11 @@
 		case HID_GD_MOUSE:
 		case HID_GD_POINTER:  code += 0x110; break;
 		case HID_GD_JOYSTICK:
-				      if (code <= 0xf)
-					      code += BTN_JOYSTICK;
-				      else
-					      code += BTN_TRIGGER_HAPPY;
-				      break;
+				if (code <= 0xf)
+					code += BTN_JOYSTICK;
+				else
+					code += BTN_TRIGGER_HAPPY;
+				break;
 		case HID_GD_GAMEPAD:  code += 0x130; break;
 		default:
 			switch (field->physical) {
@@ -301,6 +301,9 @@
 
 	case HID_UP_DIGITIZER:
 		switch (usage->hid & 0xff) {
+		case 0x00: /* Undefined */
+			goto ignore;
+
 		case 0x30: /* TipPressure */
 			if (!test_bit(BTN_TOUCH, input->keybit)) {
 				device->quirks |= HID_QUIRK_NOTOUCH;
@@ -480,7 +483,7 @@
 
 	case HID_UP_LOGIVENDOR:
 		goto ignore;
-	
+
 	case HID_UP_PID:
 		switch (usage->hid & HID_USAGE) {
 		case 0xa4: map_key_clear(BTN_DEAD);	break;
@@ -534,6 +537,9 @@
 			input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
 		else	input_set_abs_params(input, usage->code, a, b, 0, 0);
 
+		/* use a larger default input buffer for MT devices */
+		if (usage->code == ABS_MT_POSITION_X && input->hint_events_per_packet == 0)
+			input_set_events_per_packet(input, 60);
 	}
 
 	if (usage->type == EV_ABS &&
@@ -586,9 +592,9 @@
 			hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
 		if (hat_dir < 0 || hat_dir > 8) hat_dir = 0;
 		input_event(input, usage->type, usage->code    , hid_hat_to_axis[hat_dir].x);
-                input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
-                return;
-        }
+		input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
+		return;
+	}
 
 	if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
 		*quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index f10d56a..319b0e5 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -30,6 +30,21 @@
 module_param(emulate_scroll_wheel, bool, 0644);
 MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel");
 
+static unsigned int scroll_speed = 32;
+static int param_set_scroll_speed(const char *val, struct kernel_param *kp) {
+	unsigned long speed;
+	if (!val || strict_strtoul(val, 0, &speed) || speed > 63)
+		return -EINVAL;
+	scroll_speed = speed;
+	return 0;
+}
+module_param_call(scroll_speed, param_set_scroll_speed, param_get_uint, &scroll_speed, 0644);
+MODULE_PARM_DESC(scroll_speed, "Scroll speed, value from 0 (slow) to 63 (fast)");
+
+static bool scroll_acceleration = false;
+module_param(scroll_acceleration, bool, 0644);
+MODULE_PARM_DESC(scroll_acceleration, "Accelerate sequential scroll events");
+
 static bool report_touches = true;
 module_param(report_touches, bool, 0644);
 MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)");
@@ -50,6 +65,8 @@
 #define TOUCH_STATE_START 0x30
 #define TOUCH_STATE_DRAG  0x40
 
+#define SCROLL_ACCEL_DEFAULT 7
+
 /**
  * struct magicmouse_sc - Tracks Magic Mouse-specific data.
  * @input: Input device through which we report events.
@@ -78,8 +95,10 @@
 	struct {
 		short x;
 		short y;
+		short scroll_x;
 		short scroll_y;
 		u8 size;
+		u8 down;
 	} touches[16];
 	int tracking_ids[16];
 };
@@ -141,7 +160,7 @@
 	input_report_key(msc->input, BTN_RIGHT, state & 2);
 
 	if (state != last_state)
-		msc->scroll_accel = 0;
+		msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
 }
 
 static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata)
@@ -152,6 +171,7 @@
 	int id = (misc >> 6) & 15;
 	int x = x_y << 12 >> 20;
 	int y = -(x_y >> 20);
+	int down = (tdata[7] & TOUCH_STATE_MASK) != TOUCH_STATE_NONE;
 
 	/* Store tracking ID and other fields. */
 	msc->tracking_ids[raw_id] = id;
@@ -160,42 +180,54 @@
 	msc->touches[id].size = misc & 63;
 
 	/* If requested, emulate a scroll wheel by detecting small
-	 * vertical touch motions along the middle of the mouse.
+	 * vertical touch motions.
 	 */
-	if (emulate_scroll_wheel &&
-	    middle_button_start < x && x < middle_button_stop) {
-		static const int accel_profile[] = {
-			256, 228, 192, 160, 128, 96, 64, 32,
-		};
+	if (emulate_scroll_wheel) {
 		unsigned long now = jiffies;
-		int step = msc->touches[id].scroll_y - y;
-
-		/* Reset acceleration after half a second. */
-		if (time_after(now, msc->scroll_jiffies + HZ / 2))
-			msc->scroll_accel = 0;
+		int step_x = msc->touches[id].scroll_x - x;
+		int step_y = msc->touches[id].scroll_y - y;
 
 		/* Calculate and apply the scroll motion. */
 		switch (tdata[7] & TOUCH_STATE_MASK) {
 		case TOUCH_STATE_START:
+			msc->touches[id].scroll_x = x;
 			msc->touches[id].scroll_y = y;
-			msc->scroll_accel = min_t(int, msc->scroll_accel + 1,
-						ARRAY_SIZE(accel_profile) - 1);
+
+			/* Reset acceleration after half a second. */
+			if (scroll_acceleration && time_before(now,
+						msc->scroll_jiffies + HZ / 2))
+				msc->scroll_accel = max_t(int,
+						msc->scroll_accel - 1, 1);
+			else
+				msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
+
 			break;
 		case TOUCH_STATE_DRAG:
-			step = step / accel_profile[msc->scroll_accel];
-			if (step != 0) {
-				msc->touches[id].scroll_y = y;
+			step_x /= (64 - (int)scroll_speed) * msc->scroll_accel;
+			if (step_x != 0) {
+				msc->touches[id].scroll_x -= step_x *
+					(64 - scroll_speed) * msc->scroll_accel;
 				msc->scroll_jiffies = now;
-				input_report_rel(input, REL_WHEEL, step);
+				input_report_rel(input, REL_HWHEEL, -step_x);
+			}
+
+			step_y /= (64 - (int)scroll_speed) * msc->scroll_accel;
+			if (step_y != 0) {
+				msc->touches[id].scroll_y -= step_y *
+					(64 - scroll_speed) * msc->scroll_accel;
+				msc->scroll_jiffies = now;
+				input_report_rel(input, REL_WHEEL, step_y);
 			}
 			break;
 		}
 	}
 
 	/* Generate the input events for this touch. */
-	if (report_touches) {
+	if (report_touches && down) {
 		int orientation = (misc >> 10) - 32;
 
+		msc->touches[id].down = 1;
+
 		input_report_abs(input, ABS_MT_TRACKING_ID, id);
 		input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]);
 		input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]);
@@ -215,7 +247,7 @@
 {
 	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
 	struct input_dev *input = msc->input;
-	int x, y, ts, ii, clicks;
+	int x, y, ts, ii, clicks, last_up;
 
 	switch (data[0]) {
 	case 0x10:
@@ -235,12 +267,26 @@
 		msc->ntouches = (size - 6) / 8;
 		for (ii = 0; ii < msc->ntouches; ii++)
 			magicmouse_emit_touch(msc, ii, data + ii * 8 + 6);
+
+		if (report_touches) {
+			last_up = 1;
+			for (ii = 0; ii < ARRAY_SIZE(msc->touches); ii++) {
+				if (msc->touches[ii].down) {
+					last_up = 0;
+					msc->touches[ii].down = 0;
+				}
+			}
+			if (last_up) {
+				input_mt_sync(input);
+			}
+		}
+
 		/* When emulating three-button mode, it is important
 		 * to have the current touch information before
 		 * generating a click event.
 		 */
-		x = (signed char)data[1];
-		y = (signed char)data[2];
+		x = (int)(((data[3] & 0x0c) << 28) | (data[1] << 22)) >> 22;
+		y = (int)(((data[3] & 0x30) << 26) | (data[2] << 22)) >> 22;
 		clicks = data[3];
 		break;
 	case 0x20: /* Theoretically battery status (0-100), but I have
@@ -301,8 +347,10 @@
 	__set_bit(EV_REL, input->evbit);
 	__set_bit(REL_X, input->relbit);
 	__set_bit(REL_Y, input->relbit);
-	if (emulate_scroll_wheel)
+	if (emulate_scroll_wheel) {
 		__set_bit(REL_WHEEL, input->relbit);
+		__set_bit(REL_HWHEEL, input->relbit);
+	}
 
 	if (report_touches) {
 		__set_bit(EV_ABS, input->evbit);
@@ -345,6 +393,8 @@
 		return -ENOMEM;
 	}
 
+	msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
+
 	msc->quirks = id->driver_data;
 	hid_set_drvdata(hdev, msc);
 
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
index 7aabf65..346f0e3 100644
--- a/drivers/hid/hid-picolcd.c
+++ b/drivers/hid/hid-picolcd.c
@@ -127,6 +127,26 @@
 	.height         = 26,
 	.bits_per_pixel = 1,
 	.grayscale      = 1,
+	.red            = {
+		.offset = 0,
+		.length = 1,
+		.msb_right = 0,
+	},
+	.green          = {
+		.offset = 0,
+		.length = 1,
+		.msb_right = 0,
+	},
+	.blue           = {
+		.offset = 0,
+		.length = 1,
+		.msb_right = 0,
+	},
+	.transp         = {
+		.offset = 0,
+		.length = 0,
+		.msb_right = 0,
+	},
 };
 #endif /* CONFIG_HID_PICOLCD_FB */
 
@@ -188,6 +208,7 @@
 	/* Framebuffer stuff */
 	u8 fb_update_rate;
 	u8 fb_bpp;
+	u8 fb_force;
 	u8 *fb_vbitmap;		/* local copy of what was sent to PicoLCD */
 	u8 *fb_bitmap;		/* framebuffer */
 	struct fb_info *fb_info;
@@ -346,7 +367,7 @@
 			const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32;
 			for (i = 0; i < 64; i++) {
 				tdata[i] <<= 1;
-				tdata[i] |= (bdata[i/8] >> (7 - i % 8)) & 0x01;
+				tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01;
 			}
 		}
 	} else if (bpp == 8) {
@@ -399,13 +420,10 @@
 
 	if (data->fb_bitmap) {
 		if (clear) {
-			memset(data->fb_vbitmap, 0xff, PICOLCDFB_SIZE);
+			memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE);
 			memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp);
-		} else {
-			/* invert 1 byte in each tile to force resend */
-			for (i = 0; i < PICOLCDFB_SIZE; i += 64)
-				data->fb_vbitmap[i] = ~data->fb_vbitmap[i];
 		}
+		data->fb_force = 1;
 	}
 
 	/* schedule first output of framebuffer */
@@ -421,6 +439,9 @@
 	int chip, tile, n;
 	unsigned long flags;
 
+	if (!data)
+		return;
+
 	spin_lock_irqsave(&data->lock, flags);
 	if (!(data->status & PICOLCD_READY_FB)) {
 		spin_unlock_irqrestore(&data->lock, flags);
@@ -440,14 +461,18 @@
 	for (chip = 0; chip < 4; chip++)
 		for (tile = 0; tile < 8; tile++)
 			if (picolcd_fb_update_tile(data->fb_vbitmap,
-					data->fb_bitmap, data->fb_bpp, chip, tile)) {
+					data->fb_bitmap, data->fb_bpp, chip, tile) ||
+				data->fb_force) {
 				n += 2;
+				if (!data->fb_info->par)
+					return; /* device lost! */
 				if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
 					usbhid_wait_io(data->hdev);
 					n = 0;
 				}
 				picolcd_fb_send_tile(data->hdev, chip, tile);
 			}
+	data->fb_force = false;
 	if (n)
 		usbhid_wait_io(data->hdev);
 }
@@ -511,11 +536,23 @@
 static void picolcd_fb_destroy(struct fb_info *info)
 {
 	struct picolcd_data *data = info->par;
+	u32 *ref_cnt = info->pseudo_palette;
+	int may_release;
+
 	info->par = NULL;
 	if (data)
 		data->fb_info = NULL;
 	fb_deferred_io_cleanup(info);
-	framebuffer_release(info);
+
+	ref_cnt--;
+	mutex_lock(&info->lock);
+	(*ref_cnt)--;
+	may_release = !ref_cnt;
+	mutex_unlock(&info->lock);
+	if (may_release) {
+		framebuffer_release(info);
+		vfree((u8 *)info->fix.smem_start);
+	}
 }
 
 static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -526,29 +563,37 @@
 	/* only allow 1/8 bit depth (8-bit is grayscale) */
 	*var = picolcdfb_var;
 	var->activate = activate;
-	if (bpp >= 8)
+	if (bpp >= 8) {
 		var->bits_per_pixel = 8;
-	else
+		var->red.length     = 8;
+		var->green.length   = 8;
+		var->blue.length    = 8;
+	} else {
 		var->bits_per_pixel = 1;
+		var->red.length     = 1;
+		var->green.length   = 1;
+		var->blue.length    = 1;
+	}
 	return 0;
 }
 
 static int picolcd_set_par(struct fb_info *info)
 {
 	struct picolcd_data *data = info->par;
-	u8 *o_fb, *n_fb;
+	u8 *tmp_fb, *o_fb;
+	if (!data)
+		return -ENODEV;
 	if (info->var.bits_per_pixel == data->fb_bpp)
 		return 0;
 	/* switch between 1/8 bit depths */
 	if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8)
 		return -EINVAL;
 
-	o_fb = data->fb_bitmap;
-	n_fb = vmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel);
-	if (!n_fb)
+	o_fb   = data->fb_bitmap;
+	tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL);
+	if (!tmp_fb)
 		return -ENOMEM;
 
-	fb_deferred_io_cleanup(info);
 	/* translate FB content to new bits-per-pixel */
 	if (info->var.bits_per_pixel == 1) {
 		int i, b;
@@ -558,24 +603,87 @@
 				p <<= 1;
 				p |= o_fb[i*8+b] ? 0x01 : 0x00;
 			}
+			tmp_fb[i] = p;
 		}
+		memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE);
 		info->fix.visual = FB_VISUAL_MONO01;
 		info->fix.line_length = PICOLCDFB_WIDTH / 8;
 	} else {
 		int i;
+		memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE);
 		for (i = 0; i < PICOLCDFB_SIZE * 8; i++)
-			n_fb[i] = o_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
-		info->fix.visual = FB_VISUAL_TRUECOLOR;
+			o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
+		info->fix.visual = FB_VISUAL_DIRECTCOLOR;
 		info->fix.line_length = PICOLCDFB_WIDTH;
 	}
 
-	data->fb_bitmap   = n_fb;
+	kfree(tmp_fb);
 	data->fb_bpp      = info->var.bits_per_pixel;
-	info->screen_base = (char __force __iomem *)n_fb;
-	info->fix.smem_start = (unsigned long)n_fb;
-	info->fix.smem_len   = PICOLCDFB_SIZE*data->fb_bpp;
-	fb_deferred_io_init(info);
-	vfree(o_fb);
+	return 0;
+}
+
+/* Do refcounting on our FB and cleanup per worker if FB is
+ * closed after unplug of our device
+ * (fb_release holds info->lock and still touches info after
+ *  we return so we can't release it immediately.
+ */
+struct picolcd_fb_cleanup_item {
+	struct fb_info *info;
+	struct picolcd_fb_cleanup_item *next;
+};
+static struct picolcd_fb_cleanup_item *fb_pending;
+DEFINE_SPINLOCK(fb_pending_lock);
+
+static void picolcd_fb_do_cleanup(struct work_struct *data)
+{
+	struct picolcd_fb_cleanup_item *item;
+	unsigned long flags;
+
+	do {
+		spin_lock_irqsave(&fb_pending_lock, flags);
+		item = fb_pending;
+		fb_pending = item ? item->next : NULL;
+		spin_unlock_irqrestore(&fb_pending_lock, flags);
+
+		if (item) {
+			u8 *fb = (u8 *)item->info->fix.smem_start;
+			/* make sure we do not race against fb core when
+			 * releasing */
+			mutex_lock(&item->info->lock);
+			mutex_unlock(&item->info->lock);
+			framebuffer_release(item->info);
+			vfree(fb);
+		}
+	} while (item);
+}
+
+DECLARE_WORK(picolcd_fb_cleanup, picolcd_fb_do_cleanup);
+
+static int picolcd_fb_open(struct fb_info *info, int u)
+{
+	u32 *ref_cnt = info->pseudo_palette;
+	ref_cnt--;
+
+	(*ref_cnt)++;
+	return 0;
+}
+
+static int picolcd_fb_release(struct fb_info *info, int u)
+{
+	u32 *ref_cnt = info->pseudo_palette;
+	ref_cnt--;
+
+	(*ref_cnt)++;
+	if (!*ref_cnt) {
+		unsigned long flags;
+		struct picolcd_fb_cleanup_item *item = (struct picolcd_fb_cleanup_item *)ref_cnt;
+		item--;
+		spin_lock_irqsave(&fb_pending_lock, flags);
+		item->next = fb_pending;
+		fb_pending = item;
+		spin_unlock_irqrestore(&fb_pending_lock, flags);
+		schedule_work(&picolcd_fb_cleanup);
+	}
 	return 0;
 }
 
@@ -583,6 +691,8 @@
 static struct fb_ops picolcdfb_ops = {
 	.owner        = THIS_MODULE,
 	.fb_destroy   = picolcd_fb_destroy,
+	.fb_open      = picolcd_fb_open,
+	.fb_release   = picolcd_fb_release,
 	.fb_read      = fb_sys_read,
 	.fb_write     = picolcd_fb_write,
 	.fb_blank     = picolcd_fb_blank,
@@ -660,11 +770,12 @@
 {
 	struct device *dev = &data->hdev->dev;
 	struct fb_info *info = NULL;
-	int error = -ENOMEM;
+	int i, error = -ENOMEM;
 	u8 *fb_vbitmap = NULL;
 	u8 *fb_bitmap  = NULL;
+	u32 *palette;
 
-	fb_bitmap = vmalloc(PICOLCDFB_SIZE*picolcdfb_var.bits_per_pixel);
+	fb_bitmap = vmalloc(PICOLCDFB_SIZE*8);
 	if (fb_bitmap == NULL) {
 		dev_err(dev, "can't get a free page for framebuffer\n");
 		goto err_nomem;
@@ -678,18 +789,29 @@
 
 	data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT;
 	data->fb_defio = picolcd_fb_defio;
-	info = framebuffer_alloc(0, dev);
+	/* The extra memory is:
+	 * - struct picolcd_fb_cleanup_item
+	 * - u32 for ref_count
+	 * - 256*u32 for pseudo_palette
+	 */
+	info = framebuffer_alloc(257 * sizeof(u32) + sizeof(struct picolcd_fb_cleanup_item), dev);
 	if (info == NULL) {
 		dev_err(dev, "failed to allocate a framebuffer\n");
 		goto err_nomem;
 	}
 
+	palette  = info->par + sizeof(struct picolcd_fb_cleanup_item);
+	*palette = 1;
+	palette++;
+	for (i = 0; i < 256; i++)
+		palette[i] = i > 0 && i < 16 ? 0xff : 0;
+	info->pseudo_palette = palette;
 	info->fbdefio = &data->fb_defio;
 	info->screen_base = (char __force __iomem *)fb_bitmap;
 	info->fbops = &picolcdfb_ops;
 	info->var = picolcdfb_var;
 	info->fix = picolcdfb_fix;
-	info->fix.smem_len   = PICOLCDFB_SIZE;
+	info->fix.smem_len   = PICOLCDFB_SIZE*8;
 	info->fix.smem_start = (unsigned long)fb_bitmap;
 	info->par = data;
 	info->flags = FBINFO_FLAG_DEFAULT;
@@ -707,18 +829,20 @@
 		dev_err(dev, "failed to create sysfs attributes\n");
 		goto err_cleanup;
 	}
+	fb_deferred_io_init(info);
 	data->fb_info    = info;
 	error = register_framebuffer(info);
 	if (error) {
 		dev_err(dev, "failed to register framebuffer\n");
 		goto err_sysfs;
 	}
-	fb_deferred_io_init(info);
 	/* schedule first output of framebuffer */
+	data->fb_force = 1;
 	schedule_delayed_work(&info->deferred_work, 0);
 	return 0;
 
 err_sysfs:
+	fb_deferred_io_cleanup(info);
 	device_remove_file(dev, &dev_attr_fb_update_rate);
 err_cleanup:
 	data->fb_vbitmap = NULL;
@@ -737,19 +861,17 @@
 {
 	struct fb_info *info = data->fb_info;
 	u8 *fb_vbitmap = data->fb_vbitmap;
-	u8 *fb_bitmap  = data->fb_bitmap;
 
 	if (!info)
 		return;
 
+	info->par = NULL;
+	device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
+	unregister_framebuffer(info);
 	data->fb_vbitmap = NULL;
 	data->fb_bitmap  = NULL;
 	data->fb_bpp     = 0;
 	data->fb_info    = NULL;
-	device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
-	fb_deferred_io_cleanup(info);
-	unregister_framebuffer(info);
-	vfree(fb_bitmap);
 	kfree(fb_vbitmap);
 }
 
@@ -2566,6 +2688,13 @@
 	spin_lock_irqsave(&data->lock, flags);
 	data->status |= PICOLCD_FAILED;
 	spin_unlock_irqrestore(&data->lock, flags);
+#ifdef CONFIG_HID_PICOLCD_FB
+	/* short-circuit FB as early as possible in order to
+	 * avoid long delays if we host console.
+	 */
+	if (data->fb_info)
+		data->fb_info->par = NULL;
+#endif
 
 	picolcd_exit_devfs(data);
 	device_remove_file(&hdev->dev, &dev_attr_operation_mode);
@@ -2623,6 +2752,10 @@
 static void __exit picolcd_exit(void)
 {
 	hid_unregister_driver(&picolcd_driver);
+#ifdef CONFIG_HID_PICOLCD_FB
+	flush_scheduled_work();
+	WARN_ON(fb_pending);
+#endif
 }
 
 module_init(picolcd_init);
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 17f2dc0..f776957 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -22,11 +22,6 @@
  *      Is it possible to remove and reinstall the urb in raw-event- or any
  *      other handler, or to defer this action to be executed somewhere else?
  *
- * TODO implement notification mechanism for overlong macro execution
- *      If user wants to execute an overlong macro only the names of macroset
- *      and macro are given. Should userland tap hidraw or is there an
- *      additional streaming mechanism?
- *
  * TODO is it possible to overwrite group for sysfs attributes via udev?
  */
 
@@ -277,7 +272,7 @@
 		count = sizeof(struct kone_settings) - off;
 
 	mutex_lock(&kone->kone_lock);
-	memcpy(buf, &kone->settings + off, count);
+	memcpy(buf, ((char const *)&kone->settings) + off, count);
 	mutex_unlock(&kone->kone_lock);
 
 	return count;
@@ -337,7 +332,7 @@
 		count = sizeof(struct kone_profile) - off;
 
 	mutex_lock(&kone->kone_lock);
-	memcpy(buf, &kone->profiles[number - 1], sizeof(struct kone_profile));
+	memcpy(buf, ((char const *)&kone->profiles[number - 1]) + off, count);
 	mutex_unlock(&kone->kone_lock);
 
 	return count;
@@ -623,18 +618,6 @@
 }
 
 /*
- * This file is used by userland software to find devices that are handled by
- * this driver. This provides a consistent way for actual and older kernels
- * where this driver replaced usbhid instead of generic-usb.
- * Driver capabilities are determined by version number.
- */
-static ssize_t kone_sysfs_show_driver_version(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_DRIVER_VERSION "\n");
-}
-
-/*
  * Read actual dpi settings.
  * Returns raw value for further processing. Refer to enum kone_polling_rates to
  * get real value.
@@ -671,9 +654,6 @@
 		kone_sysfs_show_startup_profile,
 		kone_sysfs_set_startup_profile);
 
-static DEVICE_ATTR(kone_driver_version, 0440,
-		kone_sysfs_show_driver_version, NULL);
-
 static struct attribute *kone_attributes[] = {
 		&dev_attr_actual_dpi.attr,
 		&dev_attr_actual_profile.attr,
@@ -681,7 +661,6 @@
 		&dev_attr_firmware_version.attr,
 		&dev_attr_tcu.attr,
 		&dev_attr_startup_profile.attr,
-		&dev_attr_kone_driver_version.attr,
 		NULL
 };
 
diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h
index 003e6f8..130d656 100644
--- a/drivers/hid/hid-roccat-kone.h
+++ b/drivers/hid/hid-roccat-kone.h
@@ -14,8 +14,6 @@
 
 #include <linux/types.h>
 
-#define ROCCAT_KONE_DRIVER_VERSION "v0.3.1"
-
 #pragma pack(push)
 #pragma pack(1)
 
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
index e05d48e..f6e80c7 100644
--- a/drivers/hid/hid-roccat.c
+++ b/drivers/hid/hid-roccat.c
@@ -168,7 +168,7 @@
 		printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
 				minor);
 		error = -ENODEV;
-		goto exit_unlock;
+		goto exit_err;
 	}
 
 	if (!device->open++) {
@@ -178,7 +178,7 @@
 					PM_HINT_FULLON);
 			if (error < 0) {
 				--device->open;
-				goto exit_unlock;
+				goto exit_err;
 			}
 		}
 		error = device->hid->ll_driver->open(device->hid);
@@ -187,7 +187,7 @@
 				device->hid->ll_driver->power(device->hid,
 						PM_HINT_NORMAL);
 			--device->open;
-			goto exit_unlock;
+			goto exit_err;
 		}
 	}
 
@@ -202,6 +202,9 @@
 	mutex_unlock(&device->readers_lock);
 	mutex_unlock(&devices_lock);
 	return error;
+exit_err:
+	kfree(reader);
+	goto exit_unlock;
 }
 
 static int roccat_release(struct inode *inode, struct file *file)
diff --git a/drivers/hid/hid-roccat.h b/drivers/hid/hid-roccat.h
index d8aae0c..09e864e 100644
--- a/drivers/hid/hid-roccat.h
+++ b/drivers/hid/hid-roccat.h
@@ -15,7 +15,7 @@
 #include <linux/hid.h>
 #include <linux/types.h>
 
-#if defined(CONFIG_HID_ROCCAT) || defined (CONFIG_HID_ROCCAT_MODULE)
+#if defined(CONFIG_HID_ROCCAT) || defined(CONFIG_HID_ROCCAT_MODULE)
 int roccat_connect(struct hid_device *hid);
 void roccat_disconnect(int minor);
 int roccat_report_event(int minor, u8 const *data, int len);
diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c
index 2eebdcc..5771f85 100644
--- a/drivers/hid/hid-topseed.c
+++ b/drivers/hid/hid-topseed.c
@@ -6,6 +6,9 @@
  *
  *  Modified to also support BTC "Emprex 3009URF III Vista MCE Remote" by
  *  Wayne Thomas 2010.
+ *
+ *  Modified to support Conceptronic CLLRCMCE by
+ *  Kees Bakker 2010.
  */
 
 /*
@@ -34,6 +37,7 @@
 	case 0x00d: ts_map_key_clear(KEY_MEDIA);	break;
 	case 0x024: ts_map_key_clear(KEY_MENU);		break;
 	case 0x025: ts_map_key_clear(KEY_TV);		break;
+	case 0x027: ts_map_key_clear(KEY_MODE);		break;
 	case 0x031: ts_map_key_clear(KEY_AUDIO);	break;
 	case 0x032: ts_map_key_clear(KEY_TEXT);		break;
 	case 0x033: ts_map_key_clear(KEY_CHANNEL);	break;
@@ -60,6 +64,7 @@
 static const struct hid_device_id ts_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, ts_devices);
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index 1e051f1..807dcd1 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -436,7 +436,7 @@
 
 static const struct hid_device_id wacom_devices[] = {
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
-	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
+
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, wacom_devices);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 3ccd478..47d70c5 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -46,7 +46,6 @@
 {
 	struct hidraw_list *list = file->private_data;
 	int ret = 0, len;
-	char *report;
 	DECLARE_WAITQUEUE(wait, current);
 
 	mutex_lock(&list->read_mutex);
@@ -84,7 +83,6 @@
 		if (ret)
 			goto out;
 
-		report = list->buffer[list->tail].value;
 		len = list->buffer[list->tail].len > count ?
 			count : list->buffer[list->tail].len;
 
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 5f5aa39..2643d31 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -75,6 +75,8 @@
 	{ USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 
+	{ USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE },
+
 	{ 0, 0 }
 };
 
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index c24d2fa..254a003 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -67,7 +67,7 @@
 	struct mutex thread_lock;
 };
 
-static struct hiddev *hiddev_table[HIDDEV_MINORS];
+static struct usb_driver hiddev_driver;
 
 /*
  * Find a report, given the report's type and ID.  The ID can be specified
@@ -265,22 +265,19 @@
 static int hiddev_open(struct inode *inode, struct file *file)
 {
 	struct hiddev_list *list;
-	int res, i;
+	struct usb_interface *intf;
+	struct hiddev *hiddev;
+	int res;
 
-	/* See comment in hiddev_connect() for BKL explanation */
-	lock_kernel();
-	i = iminor(inode) - HIDDEV_MINOR_BASE;
-
-	if (i >= HIDDEV_MINORS || i < 0 || !hiddev_table[i])
+	intf = usb_find_interface(&hiddev_driver, iminor(inode));
+	if (!intf)
 		return -ENODEV;
+	hiddev = usb_get_intfdata(intf);
 
 	if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
 		return -ENOMEM;
 	mutex_init(&list->thread_lock);
-
-	list->hiddev = hiddev_table[i];
-
-
+	list->hiddev = hiddev;
 	file->private_data = list;
 
 	/*
@@ -289,7 +286,7 @@
 	 */
 	if (list->hiddev->exist) {
 		if (!list->hiddev->open++) {
-			res = usbhid_open(hiddev_table[i]->hid);
+			res = usbhid_open(hiddev->hid);
 			if (res < 0) {
 				res = -EIO;
 				goto bail;
@@ -301,12 +298,12 @@
 	}
 
 	spin_lock_irq(&list->hiddev->list_lock);
-	list_add_tail(&list->node, &hiddev_table[i]->list);
+	list_add_tail(&list->node, &hiddev->list);
 	spin_unlock_irq(&list->hiddev->list_lock);
 
 	if (!list->hiddev->open++)
 		if (list->hiddev->exist) {
-			struct hid_device *hid = hiddev_table[i]->hid;
+			struct hid_device *hid = hiddev->hid;
 			res = usbhid_get_power(hid);
 			if (res < 0) {
 				res = -EIO;
@@ -314,13 +311,10 @@
 			}
 			usbhid_open(hid);
 		}
-
-	unlock_kernel();
 	return 0;
 bail:
 	file->private_data = NULL;
 	kfree(list);
-	unlock_kernel();
 	return res;
 }
 
@@ -894,37 +888,14 @@
 	hid->hiddev = hiddev;
 	hiddev->hid = hid;
 	hiddev->exist = 1;
-
-	/*
-	 * BKL here is used to avoid race after usb_register_dev().
-	 * Once the device node has been created, open() could happen on it.
-	 * The code below will then fail, as hiddev_table hasn't been
-	 * updated.
-	 *
-	 * The obvious fix -- introducing mutex to guard hiddev_table[]
-	 * doesn't work, as usb_open() and usb_register_dev() both take
-	 * minor_rwsem, thus we'll have ABBA deadlock.
-	 *
-	 * Before BKL pushdown, usb_open() had been acquiring it in right
-	 * order, so _open() was safe to use it to protect from this race.
-	 * Now the order is different, but AB-BA deadlock still doesn't occur
-	 * as BKL is dropped on schedule() (i.e. while sleeping on
-	 * minor_rwsem). Fugly.
-	 */
-	lock_kernel();
+	usb_set_intfdata(usbhid->intf, usbhid);
 	retval = usb_register_dev(usbhid->intf, &hiddev_class);
 	if (retval) {
 		err_hid("Not able to get a minor for this device.");
 		hid->hiddev = NULL;
-		unlock_kernel();
 		kfree(hiddev);
 		return -1;
-	} else {
-		hid->minor = usbhid->intf->minor;
-		hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
 	}
-	unlock_kernel();
-
 	return 0;
 }
 
@@ -942,7 +913,6 @@
 	hiddev->exist = 0;
 	mutex_unlock(&hiddev->existancelock);
 
-	hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
 	usb_deregister_dev(usbhid->intf, &hiddev_class);
 
 	if (hiddev->open) {
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 54f0fb4..03d202b 100755
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -231,7 +231,7 @@
 
 	stop_critical_timings();
 #ifndef MODULE
-	trace_power_start(POWER_CSTATE, (eax >> 4) + 1);
+	trace_power_start(POWER_CSTATE, (eax >> 4) + 1, cpu);
 #endif
 	if (!need_resched()) {
 
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 0b926e4..a5ea1bc 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -215,7 +215,7 @@
 
 	neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev);
 	if (!neigh || !(neigh->nud_state & NUD_VALID)) {
-		neigh_event_send(rt->u.dst.neighbour, NULL);
+		neigh_event_send(rt->dst.neighbour, NULL);
 		ret = -ENODATA;
 		if (neigh)
 			goto release;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index ebfb117..abd683e 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -1364,7 +1364,7 @@
 		       __func__);
 		goto reject;
 	}
-	dst = &rt->u.dst;
+	dst = &rt->dst;
 	l2t = t3_l2t_get(tdev, dst->neighbour, dst->neighbour->dev);
 	if (!l2t) {
 		printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
@@ -1932,7 +1932,7 @@
 		err = -EHOSTUNREACH;
 		goto fail3;
 	}
-	ep->dst = &rt->u.dst;
+	ep->dst = &rt->dst;
 
 	/* get a l2t entry */
 	ep->l2t = t3_l2t_get(ep->com.tdev, ep->dst->neighbour,
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 855ee44..8c9b483 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -1365,7 +1365,7 @@
 		       __func__);
 		goto reject;
 	}
-	dst = &rt->u.dst;
+	dst = &rt->dst;
 	if (dst->neighbour->dev->flags & IFF_LOOPBACK) {
 		pdev = ip_dev_find(&init_net, peer_ip);
 		BUG_ON(!pdev);
@@ -1939,7 +1939,7 @@
 		err = -EHOSTUNREACH;
 		goto fail3;
 	}
-	ep->dst = &rt->u.dst;
+	ep->dst = &rt->dst;
 
 	/* get a l2t entry */
 	if (ep->dst->neighbour->dev->flags & IFF_LOOPBACK) {
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 986d6f3..d876d04 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -1146,7 +1146,7 @@
 	}
 
 	if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID)))
-		neigh_event_send(rt->u.dst.neighbour, NULL);
+		neigh_event_send(rt->dst.neighbour, NULL);
 
 	ip_rt_put(rt);
 	return rc;
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 5cc0a9a..42e7aad 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -1567,6 +1567,12 @@
 }
 
 
+static int nes_netdev_set_flags(struct net_device *netdev, u32 flags)
+{
+	return ethtool_op_set_flags(netdev, flags, ETH_FLAG_LRO);
+}
+
+
 static const struct ethtool_ops nes_ethtool_ops = {
 	.get_link = ethtool_op_get_link,
 	.get_settings = nes_netdev_get_settings,
@@ -1588,7 +1594,7 @@
 	.get_tso = ethtool_op_get_tso,
 	.set_tso = ethtool_op_set_tso,
 	.get_flags = ethtool_op_get_flags,
-	.set_flags = ethtool_op_set_flags,
+	.set_flags = nes_netdev_set_flags,
 };
 
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
index 40e8584..1a1657c 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
@@ -147,6 +147,11 @@
 	data[index++] = priv->lro.lro_mgr.stats.no_desc;
 }
 
+static int ipoib_set_flags(struct net_device *dev, u32 flags)
+{
+	return ethtool_op_set_flags(dev, flags, ETH_FLAG_LRO);
+}
+
 static const struct ethtool_ops ipoib_ethtool_ops = {
 	.get_drvinfo		= ipoib_get_drvinfo,
 	.get_rx_csum		= ipoib_get_rx_csum,
@@ -154,7 +159,7 @@
 	.get_coalesce		= ipoib_get_coalesce,
 	.set_coalesce		= ipoib_set_coalesce,
 	.get_flags		= ethtool_op_get_flags,
-	.set_flags		= ethtool_op_set_flags,
+	.set_flags		= ipoib_set_flags,
 	.get_strings		= ipoib_get_strings,
 	.get_sset_count		= ipoib_get_sset_count,
 	.get_ethtool_stats	= ipoib_get_ethtool_stats,
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 2ee6c7a..054edf3 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -10,7 +10,8 @@
 
 #define EVDEV_MINOR_BASE	64
 #define EVDEV_MINORS		32
-#define EVDEV_BUFFER_SIZE	64
+#define EVDEV_MIN_BUFFER_SIZE	64U
+#define EVDEV_BUF_PACKETS	8
 
 #include <linux/poll.h>
 #include <linux/sched.h>
@@ -23,7 +24,6 @@
 #include "input-compat.h"
 
 struct evdev {
-	int exist;
 	int open;
 	int minor;
 	struct input_handle handle;
@@ -33,16 +33,18 @@
 	spinlock_t client_lock; /* protects client_list */
 	struct mutex mutex;
 	struct device dev;
+	bool exist;
 };
 
 struct evdev_client {
-	struct input_event buffer[EVDEV_BUFFER_SIZE];
 	int head;
 	int tail;
 	spinlock_t buffer_lock; /* protects access to buffer, head and tail */
 	struct fasync_struct *fasync;
 	struct evdev *evdev;
 	struct list_head node;
+	int bufsize;
+	struct input_event buffer[];
 };
 
 static struct evdev *evdev_table[EVDEV_MINORS];
@@ -52,11 +54,15 @@
 			     struct input_event *event)
 {
 	/*
-	 * Interrupts are disabled, just acquire the lock
+	 * Interrupts are disabled, just acquire the lock.
+	 * Make sure we don't leave with the client buffer
+	 * "empty" by having client->head == client->tail.
 	 */
 	spin_lock(&client->buffer_lock);
-	client->buffer[client->head++] = *event;
-	client->head &= EVDEV_BUFFER_SIZE - 1;
+	do {
+		client->buffer[client->head++] = *event;
+		client->head &= client->bufsize - 1;
+	} while (client->head == client->tail);
 	spin_unlock(&client->buffer_lock);
 
 	if (event->type == EV_SYN)
@@ -242,11 +248,21 @@
 	return 0;
 }
 
+static unsigned int evdev_compute_buffer_size(struct input_dev *dev)
+{
+	unsigned int n_events =
+		max(dev->hint_events_per_packet * EVDEV_BUF_PACKETS,
+		    EVDEV_MIN_BUFFER_SIZE);
+
+	return roundup_pow_of_two(n_events);
+}
+
 static int evdev_open(struct inode *inode, struct file *file)
 {
 	struct evdev *evdev;
 	struct evdev_client *client;
 	int i = iminor(inode) - EVDEV_MINOR_BASE;
+	unsigned int bufsize;
 	int error;
 
 	if (i >= EVDEV_MINORS)
@@ -263,12 +279,17 @@
 	if (!evdev)
 		return -ENODEV;
 
-	client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
+	bufsize = evdev_compute_buffer_size(evdev->handle.dev);
+
+	client = kzalloc(sizeof(struct evdev_client) +
+				bufsize * sizeof(struct input_event),
+			 GFP_KERNEL);
 	if (!client) {
 		error = -ENOMEM;
 		goto err_put_evdev;
 	}
 
+	client->bufsize = bufsize;
 	spin_lock_init(&client->buffer_lock);
 	client->evdev = evdev;
 	evdev_attach_client(evdev, client);
@@ -334,7 +355,7 @@
 	have_event = client->head != client->tail;
 	if (have_event) {
 		*event = client->buffer[client->tail++];
-		client->tail &= EVDEV_BUFFER_SIZE - 1;
+		client->tail &= client->bufsize - 1;
 	}
 
 	spin_unlock_irq(&client->buffer_lock);
@@ -382,10 +403,15 @@
 {
 	struct evdev_client *client = file->private_data;
 	struct evdev *evdev = client->evdev;
+	unsigned int mask;
 
 	poll_wait(file, &evdev->wait, wait);
-	return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
-		(evdev->exist ? 0 : (POLLHUP | POLLERR));
+
+	mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
+	if (client->head != client->tail)
+		mask |= POLLIN | POLLRDNORM;
+
+	return mask;
 }
 
 #ifdef CONFIG_COMPAT
@@ -665,6 +691,10 @@
 								  sizeof(struct input_absinfo))))
 					return -EFAULT;
 
+				/* We can't change number of reserved MT slots */
+				if (t == ABS_MT_SLOT)
+					return -EINVAL;
+
 				/*
 				 * Take event lock to ensure that we are not
 				 * changing device parameters in the middle
@@ -768,7 +798,7 @@
 static void evdev_mark_dead(struct evdev *evdev)
 {
 	mutex_lock(&evdev->mutex);
-	evdev->exist = 0;
+	evdev->exist = false;
 	mutex_unlock(&evdev->mutex);
 }
 
@@ -817,7 +847,7 @@
 	init_waitqueue_head(&evdev->wait);
 
 	dev_set_name(&evdev->dev, "event%d", minor);
-	evdev->exist = 1;
+	evdev->exist = true;
 	evdev->minor = minor;
 
 	evdev->handle.dev = input_get_device(dev);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 9c79bd5..e1243b4 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -33,25 +33,6 @@
 
 #define INPUT_DEVICES	256
 
-/*
- * EV_ABS events which should not be cached are listed here.
- */
-static unsigned int input_abs_bypass_init_data[] __initdata = {
-	ABS_MT_TOUCH_MAJOR,
-	ABS_MT_TOUCH_MINOR,
-	ABS_MT_WIDTH_MAJOR,
-	ABS_MT_WIDTH_MINOR,
-	ABS_MT_ORIENTATION,
-	ABS_MT_POSITION_X,
-	ABS_MT_POSITION_Y,
-	ABS_MT_TOOL_TYPE,
-	ABS_MT_BLOB_ID,
-	ABS_MT_TRACKING_ID,
-	ABS_MT_PRESSURE,
-	0
-};
-static unsigned long input_abs_bypass[BITS_TO_LONGS(ABS_CNT)];
-
 static LIST_HEAD(input_dev_list);
 static LIST_HEAD(input_handler_list);
 
@@ -181,6 +162,56 @@
 #define INPUT_PASS_TO_DEVICE	2
 #define INPUT_PASS_TO_ALL	(INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
 
+static int input_handle_abs_event(struct input_dev *dev,
+				  unsigned int code, int *pval)
+{
+	bool is_mt_event;
+	int *pold;
+
+	if (code == ABS_MT_SLOT) {
+		/*
+		 * "Stage" the event; we'll flush it later, when we
+		 * get actiual touch data.
+		 */
+		if (*pval >= 0 && *pval < dev->mtsize)
+			dev->slot = *pval;
+
+		return INPUT_IGNORE_EVENT;
+	}
+
+	is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST;
+
+	if (!is_mt_event) {
+		pold = &dev->abs[code];
+	} else if (dev->mt) {
+		struct input_mt_slot *mtslot = &dev->mt[dev->slot];
+		pold = &mtslot->abs[code - ABS_MT_FIRST];
+	} else {
+		/*
+		 * Bypass filtering for multitouch events when
+		 * not employing slots.
+		 */
+		pold = NULL;
+	}
+
+	if (pold) {
+		*pval = input_defuzz_abs_event(*pval, *pold,
+						dev->absfuzz[code]);
+		if (*pold == *pval)
+			return INPUT_IGNORE_EVENT;
+
+		*pold = *pval;
+	}
+
+	/* Flush pending "slot" event */
+	if (is_mt_event && dev->slot != dev->abs[ABS_MT_SLOT]) {
+		dev->abs[ABS_MT_SLOT] = dev->slot;
+		input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
+	}
+
+	return INPUT_PASS_TO_HANDLERS;
+}
+
 static void input_handle_event(struct input_dev *dev,
 			       unsigned int type, unsigned int code, int value)
 {
@@ -196,12 +227,12 @@
 
 		case SYN_REPORT:
 			if (!dev->sync) {
-				dev->sync = 1;
+				dev->sync = true;
 				disposition = INPUT_PASS_TO_HANDLERS;
 			}
 			break;
 		case SYN_MT_REPORT:
-			dev->sync = 0;
+			dev->sync = false;
 			disposition = INPUT_PASS_TO_HANDLERS;
 			break;
 		}
@@ -233,21 +264,9 @@
 		break;
 
 	case EV_ABS:
-		if (is_event_supported(code, dev->absbit, ABS_MAX)) {
+		if (is_event_supported(code, dev->absbit, ABS_MAX))
+			disposition = input_handle_abs_event(dev, code, &value);
 
-			if (test_bit(code, input_abs_bypass)) {
-				disposition = INPUT_PASS_TO_HANDLERS;
-				break;
-			}
-
-			value = input_defuzz_abs_event(value,
-					dev->abs[code], dev->absfuzz[code]);
-
-			if (dev->abs[code] != value) {
-				dev->abs[code] = value;
-				disposition = INPUT_PASS_TO_HANDLERS;
-			}
-		}
 		break;
 
 	case EV_REL:
@@ -298,7 +317,7 @@
 	}
 
 	if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
-		dev->sync = 0;
+		dev->sync = false;
 
 	if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
 		dev->event(dev, type, code, value);
@@ -528,12 +547,30 @@
 EXPORT_SYMBOL(input_close_device);
 
 /*
+ * Simulate keyup events for all keys that are marked as pressed.
+ * The function must be called with dev->event_lock held.
+ */
+static void input_dev_release_keys(struct input_dev *dev)
+{
+	int code;
+
+	if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
+		for (code = 0; code <= KEY_MAX; code++) {
+			if (is_event_supported(code, dev->keybit, KEY_MAX) &&
+			    __test_and_clear_bit(code, dev->key)) {
+				input_pass_event(dev, EV_KEY, code, 0);
+			}
+		}
+		input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+	}
+}
+
+/*
  * Prepare device for unregistering
  */
 static void input_disconnect_device(struct input_dev *dev)
 {
 	struct input_handle *handle;
-	int code;
 
 	/*
 	 * Mark device as going away. Note that we take dev->mutex here
@@ -552,15 +589,7 @@
 	 * generate events even after we done here but they will not
 	 * reach any handlers.
 	 */
-	if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
-		for (code = 0; code <= KEY_MAX; code++) {
-			if (is_event_supported(code, dev->keybit, KEY_MAX) &&
-			    __test_and_clear_bit(code, dev->key)) {
-				input_pass_event(dev, EV_KEY, code, 0);
-			}
-		}
-		input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
-	}
+	input_dev_release_keys(dev);
 
 	list_for_each_entry(handle, &dev->h_list, d_node)
 		handle->open = 0;
@@ -684,7 +713,7 @@
 		      unsigned int scancode, unsigned int keycode)
 {
 	unsigned long flags;
-	int old_keycode;
+	unsigned int old_keycode;
 	int retval;
 
 	if (keycode > KEY_MAX)
@@ -1278,6 +1307,7 @@
 	struct input_dev *dev = to_input_dev(device);
 
 	input_ff_destroy(dev);
+	input_mt_destroy_slots(dev);
 	kfree(dev);
 
 	module_put(THIS_MODULE);
@@ -1433,6 +1463,15 @@
 
 	mutex_lock(&input_dev->mutex);
 	input_dev_reset(input_dev, true);
+
+	/*
+	 * Keys that have been pressed at suspend time are unlikely
+	 * to be still pressed when we resume.
+	 */
+	spin_lock_irq(&input_dev->event_lock);
+	input_dev_release_keys(input_dev);
+	spin_unlock_irq(&input_dev->event_lock);
+
 	mutex_unlock(&input_dev->mutex);
 
 	return 0;
@@ -1518,6 +1557,45 @@
 EXPORT_SYMBOL(input_free_device);
 
 /**
+ * input_mt_create_slots() - create MT input slots
+ * @dev: input device supporting MT events and finger tracking
+ * @num_slots: number of slots used by the device
+ *
+ * This function allocates all necessary memory for MT slot handling
+ * in the input device, and adds ABS_MT_SLOT to the device capabilities.
+ */
+int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots)
+{
+	if (!num_slots)
+		return 0;
+
+	dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
+	if (!dev->mt)
+		return -ENOMEM;
+
+	dev->mtsize = num_slots;
+	input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
+
+	return 0;
+}
+EXPORT_SYMBOL(input_mt_create_slots);
+
+/**
+ * input_mt_destroy_slots() - frees the MT slots of the input device
+ * @dev: input device with allocated MT slots
+ *
+ * This function is only needed in error path as the input core will
+ * automatically free the MT slots when the device is destroyed.
+ */
+void input_mt_destroy_slots(struct input_dev *dev)
+{
+	kfree(dev->mt);
+	dev->mt = NULL;
+	dev->mtsize = 0;
+}
+EXPORT_SYMBOL(input_mt_destroy_slots);
+
+/**
  * input_set_capability - mark device as capable of a certain event
  * @dev: device that is capable of emitting or accepting event
  * @type: type of the event (EV_KEY, EV_REL, etc...)
@@ -1926,20 +2004,10 @@
 	.open = input_open_file,
 };
 
-static void __init input_init_abs_bypass(void)
-{
-	const unsigned int *p;
-
-	for (p = input_abs_bypass_init_data; *p; p++)
-		input_abs_bypass[BIT_WORD(*p)] |= BIT_MASK(*p);
-}
-
 static int __init input_init(void)
 {
 	int err;
 
-	input_init_abs_bypass();
-
 	err = class_register(&input_class);
 	if (err) {
 		printk(KERN_ERR "input: unable to register input_dev class\n");
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 34157bb..6383458 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -37,7 +37,6 @@
 #define JOYDEV_BUFFER_SIZE	64
 
 struct joydev {
-	int exist;
 	int open;
 	int minor;
 	struct input_handle handle;
@@ -46,6 +45,7 @@
 	spinlock_t client_lock; /* protects client_list */
 	struct mutex mutex;
 	struct device dev;
+	bool exist;
 
 	struct js_corr corr[ABS_CNT];
 	struct JS_DATA_SAVE_TYPE glue;
@@ -760,7 +760,7 @@
 static void joydev_mark_dead(struct joydev *joydev)
 {
 	mutex_lock(&joydev->mutex);
-	joydev->exist = 0;
+	joydev->exist = false;
 	mutex_unlock(&joydev->mutex);
 }
 
@@ -817,10 +817,9 @@
 	init_waitqueue_head(&joydev->wait);
 
 	dev_set_name(&joydev->dev, "js%d", minor);
-	joydev->exist = 1;
+	joydev->exist = true;
 	joydev->minor = minor;
 
-	joydev->exist = 1;
 	joydev->handle.dev = input_get_device(dev);
 	joydev->handle.name = dev_name(&joydev->dev);
 	joydev->handle.handler = handler;
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index c1087ce..269a846 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -9,6 +9,7 @@
  *               2005 Dominic Cerquetti <binary1230@yahoo.com>
  *               2006 Adam Buchbinder <adam.buchbinder@gmail.com>
  *               2007 Jan Kratochvil <honza@jikos.cz>
+ *               2010 Christoph Fritz <chf.fritz@googlemail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -88,6 +89,9 @@
    but we map them to axes when possible to simplify things */
 #define MAP_DPAD_TO_BUTTONS		(1 << 0)
 #define MAP_TRIGGERS_TO_BUTTONS		(1 << 1)
+#define MAP_STICKS_TO_NULL		(1 << 2)
+#define DANCEPAD_MAP_CONFIG	(MAP_DPAD_TO_BUTTONS |			\
+				MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
 
 #define XTYPE_XBOX        0
 #define XTYPE_XBOX360     1
@@ -102,6 +106,10 @@
 module_param(triggers_to_buttons, bool, S_IRUGO);
 MODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads");
 
+static int sticks_to_null;
+module_param(sticks_to_null, bool, S_IRUGO);
+MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads");
+
 static const struct xpad_device {
 	u16 idVendor;
 	u16 idProduct;
@@ -114,7 +122,7 @@
 	{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
 	{ 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
 	{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
-	{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+	{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX },
 	{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
 	{ 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
 	{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
@@ -151,6 +159,7 @@
 	{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
 	{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
 	{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
 };
@@ -158,7 +167,7 @@
 /* buttons shared with xbox and xbox360 */
 static const signed short xpad_common_btn[] = {
 	BTN_A, BTN_B, BTN_X, BTN_Y,			/* "analog" buttons */
-	BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR,	/* start/back/sticks */
+	BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR,	/* start/back/sticks */
 	-1						/* terminating entry */
 };
 
@@ -168,10 +177,10 @@
 	-1			/* terminating entry */
 };
 
-/* used when dpad is mapped to nuttons */
+/* used when dpad is mapped to buttons */
 static const signed short xpad_btn_pad[] = {
-	BTN_LEFT, BTN_RIGHT,		/* d-pad left, right */
-	BTN_0, BTN_1,			/* d-pad up, down (XXX names??) */
+	BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY2,		/* d-pad left, right */
+	BTN_TRIGGER_HAPPY3, BTN_TRIGGER_HAPPY4,		/* d-pad up, down */
 	-1				/* terminating entry */
 };
 
@@ -279,17 +288,19 @@
 {
 	struct input_dev *dev = xpad->dev;
 
-	/* left stick */
-	input_report_abs(dev, ABS_X,
-			 (__s16) le16_to_cpup((__le16 *)(data + 12)));
-	input_report_abs(dev, ABS_Y,
-			 ~(__s16) le16_to_cpup((__le16 *)(data + 14)));
+	if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+		/* left stick */
+		input_report_abs(dev, ABS_X,
+				 (__s16) le16_to_cpup((__le16 *)(data + 12)));
+		input_report_abs(dev, ABS_Y,
+				 ~(__s16) le16_to_cpup((__le16 *)(data + 14)));
 
-	/* right stick */
-	input_report_abs(dev, ABS_RX,
-			 (__s16) le16_to_cpup((__le16 *)(data + 16)));
-	input_report_abs(dev, ABS_RY,
-			 ~(__s16) le16_to_cpup((__le16 *)(data + 18)));
+		/* right stick */
+		input_report_abs(dev, ABS_RX,
+				 (__s16) le16_to_cpup((__le16 *)(data + 16)));
+		input_report_abs(dev, ABS_RY,
+				 ~(__s16) le16_to_cpup((__le16 *)(data + 18)));
+	}
 
 	/* triggers left/right */
 	if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
@@ -302,10 +313,11 @@
 
 	/* digital pad */
 	if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
-		input_report_key(dev, BTN_LEFT,  data[2] & 0x04);
-		input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
-		input_report_key(dev, BTN_0,     data[2] & 0x01); /* up */
-		input_report_key(dev, BTN_1,     data[2] & 0x02); /* down */
+		/* dpad as buttons (left, right, up, down) */
+		input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04);
+		input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08);
+		input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01);
+		input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02);
 	} else {
 		input_report_abs(dev, ABS_HAT0X,
 				 !!(data[2] & 0x08) - !!(data[2] & 0x04));
@@ -315,7 +327,7 @@
 
 	/* start/back buttons and stick press left/right */
 	input_report_key(dev, BTN_START,  data[2] & 0x10);
-	input_report_key(dev, BTN_BACK,   data[2] & 0x20);
+	input_report_key(dev, BTN_SELECT, data[2] & 0x20);
 	input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
 	input_report_key(dev, BTN_THUMBR, data[2] & 0x80);
 
@@ -349,11 +361,11 @@
 
 	/* digital pad */
 	if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
-		/* dpad as buttons (right, left, down, up) */
-		input_report_key(dev, BTN_LEFT, data[2] & 0x04);
-		input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
-		input_report_key(dev, BTN_0, data[2] & 0x01);	/* up */
-		input_report_key(dev, BTN_1, data[2] & 0x02);	/* down */
+		/* dpad as buttons (left, right, up, down) */
+		input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04);
+		input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08);
+		input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01);
+		input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02);
 	} else {
 		input_report_abs(dev, ABS_HAT0X,
 				 !!(data[2] & 0x08) - !!(data[2] & 0x04));
@@ -363,7 +375,7 @@
 
 	/* start/back buttons */
 	input_report_key(dev, BTN_START,  data[2] & 0x10);
-	input_report_key(dev, BTN_BACK,   data[2] & 0x20);
+	input_report_key(dev, BTN_SELECT, data[2] & 0x20);
 
 	/* stick press left/right */
 	input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
@@ -378,17 +390,19 @@
 	input_report_key(dev, BTN_TR,	data[3] & 0x02);
 	input_report_key(dev, BTN_MODE,	data[3] & 0x04);
 
-	/* left stick */
-	input_report_abs(dev, ABS_X,
-			 (__s16) le16_to_cpup((__le16 *)(data + 6)));
-	input_report_abs(dev, ABS_Y,
-			 ~(__s16) le16_to_cpup((__le16 *)(data + 8)));
+	if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+		/* left stick */
+		input_report_abs(dev, ABS_X,
+				 (__s16) le16_to_cpup((__le16 *)(data + 6)));
+		input_report_abs(dev, ABS_Y,
+				 ~(__s16) le16_to_cpup((__le16 *)(data + 8)));
 
-	/* right stick */
-	input_report_abs(dev, ABS_RX,
-			 (__s16) le16_to_cpup((__le16 *)(data + 10)));
-	input_report_abs(dev, ABS_RY,
-			 ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
+		/* right stick */
+		input_report_abs(dev, ABS_RX,
+				 (__s16) le16_to_cpup((__le16 *)(data + 10)));
+		input_report_abs(dev, ABS_RY,
+				 ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
+	}
 
 	/* triggers left/right */
 	if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
@@ -814,6 +828,8 @@
 			xpad->mapping |= MAP_DPAD_TO_BUTTONS;
 		if (triggers_to_buttons)
 			xpad->mapping |= MAP_TRIGGERS_TO_BUTTONS;
+		if (sticks_to_null)
+			xpad->mapping |= MAP_STICKS_TO_NULL;
 	}
 
 	xpad->dev = input_dev;
@@ -830,16 +846,20 @@
 	input_dev->open = xpad_open;
 	input_dev->close = xpad_close;
 
-	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->evbit[0] = BIT_MASK(EV_KEY);
 
-	/* set up standard buttons and axes */
+	if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+		input_dev->evbit[0] |= BIT_MASK(EV_ABS);
+		/* set up axes */
+		for (i = 0; xpad_abs[i] >= 0; i++)
+			xpad_set_up_abs(input_dev, xpad_abs[i]);
+	}
+
+	/* set up standard buttons */
 	for (i = 0; xpad_common_btn[i] >= 0; i++)
 		__set_bit(xpad_common_btn[i], input_dev->keybit);
 
-	for (i = 0; xpad_abs[i] >= 0; i++)
-		xpad_set_up_abs(input_dev, xpad_abs[i]);
-
-	/* Now set up model-specific ones */
+	/* set up model-specific ones */
 	if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) {
 		for (i = 0; xpad360_btn[i] >= 0; i++)
 			__set_bit(xpad360_btn[i], input_dev->keybit);
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 1ba2514..b171f63 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -297,6 +297,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called max7359_keypad.
 
+config KEYBOARD_MCS
+	tristate "MELFAS MCS Touchkey"
+	depends on I2C
+	help
+	  Say Y here if you have the MELFAS MCS5000/5080 touchkey controller
+	  chip in your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mcs_touchkey.
+
 config KEYBOARD_IMX
 	tristate "IMX keypad support"
 	depends on ARCH_MXC
@@ -342,6 +354,15 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called pxa930_rotary.
 
+config KEYBOARD_SAMSUNG
+	tristate "Samsung keypad support"
+	depends on SAMSUNG_DEV_KEYPAD
+	help
+	  Say Y here if you want to use the Samsung keypad.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called samsung-keypad.
+
 config KEYBOARD_STOWAWAY
 	tristate "Stowaway keyboard"
 	select SERIO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 4596d0c..1a66d5f 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -26,12 +26,14 @@
 obj-$(CONFIG_KEYBOARD_MAPLE)		+= maple_keyb.o
 obj-$(CONFIG_KEYBOARD_MATRIX)		+= matrix_keypad.o
 obj-$(CONFIG_KEYBOARD_MAX7359)		+= max7359_keypad.o
+obj-$(CONFIG_KEYBOARD_MCS)		+= mcs_touchkey.o
 obj-$(CONFIG_KEYBOARD_NEWTON)		+= newtonkbd.o
 obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
 obj-$(CONFIG_KEYBOARD_OPENCORES)	+= opencores-kbd.o
 obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)	+= pxa930_rotary.o
 obj-$(CONFIG_KEYBOARD_QT2160)		+= qt2160.o
+obj-$(CONFIG_KEYBOARD_SAMSUNG)		+= samsung-keypad.o
 obj-$(CONFIG_KEYBOARD_SH_KEYSC)		+= sh_keysc.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)		+= stowaway.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)		+= sunkbd.o
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 744600e..d6918cb 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/i2c.h>
+#include <linux/gpio.h>
 #include <linux/slab.h>
 
 #include <linux/i2c/adp5588.h>
@@ -54,6 +55,10 @@
 
 #define KEYP_MAX_EVENT		10
 
+#define MAXGPIO			18
+#define ADP_BANK(offs)		((offs) >> 3)
+#define ADP_BIT(offs)		(1u << ((offs) & 0x7))
+
 /*
  * Early pre 4.0 Silicon required to delay readout by at least 25ms,
  * since the Event Counter Register updated 25ms after the interrupt
@@ -67,6 +72,16 @@
 	struct delayed_work work;
 	unsigned long delay;
 	unsigned short keycode[ADP5588_KEYMAPSIZE];
+	const struct adp5588_gpi_map *gpimap;
+	unsigned short gpimapsize;
+#ifdef CONFIG_GPIOLIB
+	unsigned char gpiomap[MAXGPIO];
+	bool export_gpio;
+	struct gpio_chip gc;
+	struct mutex gpio_lock;	/* Protect cached dir, dat_out */
+	u8 dat_out[3];
+	u8 dir[3];
+#endif
 };
 
 static int adp5588_read(struct i2c_client *client, u8 reg)
@@ -84,12 +99,222 @@
 	return i2c_smbus_write_byte_data(client, reg, val);
 }
 
+#ifdef CONFIG_GPIOLIB
+static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
+{
+	struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+	unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+	unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+	return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
+}
+
+static void adp5588_gpio_set_value(struct gpio_chip *chip,
+				   unsigned off, int val)
+{
+	struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+	unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+	unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+	mutex_lock(&kpad->gpio_lock);
+
+	if (val)
+		kpad->dat_out[bank] |= bit;
+	else
+		kpad->dat_out[bank] &= ~bit;
+
+	adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
+			   kpad->dat_out[bank]);
+
+	mutex_unlock(&kpad->gpio_lock);
+}
+
+static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
+{
+	struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+	unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+	unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+	int ret;
+
+	mutex_lock(&kpad->gpio_lock);
+
+	kpad->dir[bank] &= ~bit;
+	ret = adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]);
+
+	mutex_unlock(&kpad->gpio_lock);
+
+	return ret;
+}
+
+static int adp5588_gpio_direction_output(struct gpio_chip *chip,
+					 unsigned off, int val)
+{
+	struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+	unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+	unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+	int ret;
+
+	mutex_lock(&kpad->gpio_lock);
+
+	kpad->dir[bank] |= bit;
+
+	if (val)
+		kpad->dat_out[bank] |= bit;
+	else
+		kpad->dat_out[bank] &= ~bit;
+
+	ret = adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
+				 kpad->dat_out[bank]);
+	ret |= adp5588_write(kpad->client, GPIO_DIR1 + bank,
+				 kpad->dir[bank]);
+
+	mutex_unlock(&kpad->gpio_lock);
+
+	return ret;
+}
+
+static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
+				const struct adp5588_kpad_platform_data *pdata)
+{
+	bool pin_used[MAXGPIO];
+	int n_unused = 0;
+	int i;
+
+	memset(pin_used, 0, sizeof(pin_used));
+
+	for (i = 0; i < pdata->rows; i++)
+		pin_used[i] = true;
+
+	for (i = 0; i < pdata->cols; i++)
+		pin_used[i + GPI_PIN_COL_BASE - GPI_PIN_BASE] = true;
+
+	for (i = 0; i < kpad->gpimapsize; i++)
+		pin_used[kpad->gpimap[i].pin - GPI_PIN_BASE] = true;
+
+	for (i = 0; i < MAXGPIO; i++)
+		if (!pin_used[i])
+			kpad->gpiomap[n_unused++] = i;
+
+	return n_unused;
+}
+
+static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad)
+{
+	struct device *dev = &kpad->client->dev;
+	const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
+	const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
+	int i, error;
+
+	if (!gpio_data)
+		return 0;
+
+	kpad->gc.ngpio = adp5588_build_gpiomap(kpad, pdata);
+	if (kpad->gc.ngpio == 0) {
+		dev_info(dev, "No unused gpios left to export\n");
+		return 0;
+	}
+
+	kpad->export_gpio = true;
+
+	kpad->gc.direction_input = adp5588_gpio_direction_input;
+	kpad->gc.direction_output = adp5588_gpio_direction_output;
+	kpad->gc.get = adp5588_gpio_get_value;
+	kpad->gc.set = adp5588_gpio_set_value;
+	kpad->gc.can_sleep = 1;
+
+	kpad->gc.base = gpio_data->gpio_start;
+	kpad->gc.label = kpad->client->name;
+	kpad->gc.owner = THIS_MODULE;
+
+	mutex_init(&kpad->gpio_lock);
+
+	error = gpiochip_add(&kpad->gc);
+	if (error) {
+		dev_err(dev, "gpiochip_add failed, err: %d\n", error);
+		return error;
+	}
+
+	for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+		kpad->dat_out[i] = adp5588_read(kpad->client,
+						GPIO_DAT_OUT1 + i);
+		kpad->dir[i] = adp5588_read(kpad->client, GPIO_DIR1 + i);
+	}
+
+	if (gpio_data->setup) {
+		error = gpio_data->setup(kpad->client,
+					 kpad->gc.base, kpad->gc.ngpio,
+					 gpio_data->context);
+		if (error)
+			dev_warn(dev, "setup failed, %d\n", error);
+	}
+
+	return 0;
+}
+
+static void __devexit adp5588_gpio_remove(struct adp5588_kpad *kpad)
+{
+	struct device *dev = &kpad->client->dev;
+	const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
+	const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
+	int error;
+
+	if (!kpad->export_gpio)
+		return;
+
+	if (gpio_data->teardown) {
+		error = gpio_data->teardown(kpad->client,
+					    kpad->gc.base, kpad->gc.ngpio,
+					    gpio_data->context);
+		if (error)
+			dev_warn(dev, "teardown failed %d\n", error);
+	}
+
+	error = gpiochip_remove(&kpad->gc);
+	if (error)
+		dev_warn(dev, "gpiochip_remove failed %d\n", error);
+}
+#else
+static inline int adp5588_gpio_add(struct adp5588_kpad *kpad)
+{
+	return 0;
+}
+
+static inline void adp5588_gpio_remove(struct adp5588_kpad *kpad)
+{
+}
+#endif
+
+static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt)
+{
+	int i, j;
+
+	for (i = 0; i < ev_cnt; i++) {
+		int key = adp5588_read(kpad->client, Key_EVENTA + i);
+		int key_val = key & KEY_EV_MASK;
+
+		if (key_val >= GPI_PIN_BASE && key_val <= GPI_PIN_END) {
+			for (j = 0; j < kpad->gpimapsize; j++) {
+				if (key_val == kpad->gpimap[j].pin) {
+					input_report_switch(kpad->input,
+							kpad->gpimap[j].sw_evt,
+							key & KEY_EV_PRESSED);
+					break;
+				}
+			}
+		} else {
+			input_report_key(kpad->input,
+					 kpad->keycode[key_val - 1],
+					 key & KEY_EV_PRESSED);
+		}
+	}
+}
+
 static void adp5588_work(struct work_struct *work)
 {
 	struct adp5588_kpad *kpad = container_of(work,
 						struct adp5588_kpad, work.work);
 	struct i2c_client *client = kpad->client;
-	int i, key, status, ev_cnt;
+	int status, ev_cnt;
 
 	status = adp5588_read(client, INT_STAT);
 
@@ -99,12 +324,7 @@
 	if (status & KE_INT) {
 		ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
 		if (ev_cnt) {
-			for (i = 0; i < ev_cnt; i++) {
-				key = adp5588_read(client, Key_EVENTA + i);
-				input_report_key(kpad->input,
-					kpad->keycode[(key & KEY_EV_MASK) - 1],
-					key & KEY_EV_PRESSED);
-			}
+			adp5588_report_events(kpad, ev_cnt);
 			input_sync(kpad->input);
 		}
 	}
@@ -128,8 +348,10 @@
 
 static int __devinit adp5588_setup(struct i2c_client *client)
 {
-	struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+	const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+	const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
 	int i, ret;
+	unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
 
 	ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows));
 	ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF);
@@ -144,6 +366,32 @@
 	for (i = 0; i < KEYP_MAX_EVENT; i++)
 		ret |= adp5588_read(client, Key_EVENTA);
 
+	for (i = 0; i < pdata->gpimapsize; i++) {
+		unsigned short pin = pdata->gpimap[i].pin;
+
+		if (pin <= GPI_PIN_ROW_END) {
+			evt_mode1 |= (1 << (pin - GPI_PIN_ROW_BASE));
+		} else {
+			evt_mode2 |= ((1 << (pin - GPI_PIN_COL_BASE)) & 0xFF);
+			evt_mode3 |= ((1 << (pin - GPI_PIN_COL_BASE)) >> 8);
+		}
+	}
+
+	if (pdata->gpimapsize) {
+		ret |= adp5588_write(client, GPI_EM1, evt_mode1);
+		ret |= adp5588_write(client, GPI_EM2, evt_mode2);
+		ret |= adp5588_write(client, GPI_EM3, evt_mode3);
+	}
+
+	if (gpio_data) {
+		for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+			int pull_mask = gpio_data->pullup_dis_mask;
+
+			ret |= adp5588_write(client, GPIO_PULL1 + i,
+				(pull_mask >> (8 * i)) & 0xFF);
+		}
+	}
+
 	ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
 					OVR_FLOW_INT | K_LCK_INT |
 					GPI_INT | KE_INT); /* Status is W1C */
@@ -158,11 +406,49 @@
 	return 0;
 }
 
+static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad)
+{
+	int gpi_stat1 = adp5588_read(kpad->client, GPIO_DAT_STAT1);
+	int gpi_stat2 = adp5588_read(kpad->client, GPIO_DAT_STAT2);
+	int gpi_stat3 = adp5588_read(kpad->client, GPIO_DAT_STAT3);
+	int gpi_stat_tmp, pin_loc;
+	int i;
+
+	for (i = 0; i < kpad->gpimapsize; i++) {
+		unsigned short pin = kpad->gpimap[i].pin;
+
+		if (pin <= GPI_PIN_ROW_END) {
+			gpi_stat_tmp = gpi_stat1;
+			pin_loc = pin - GPI_PIN_ROW_BASE;
+		} else if ((pin - GPI_PIN_COL_BASE) < 8) {
+			gpi_stat_tmp = gpi_stat2;
+			pin_loc = pin - GPI_PIN_COL_BASE;
+		} else {
+			gpi_stat_tmp = gpi_stat3;
+			pin_loc = pin - GPI_PIN_COL_BASE - 8;
+		}
+
+		if (gpi_stat_tmp < 0) {
+			dev_err(&kpad->client->dev,
+				"Can't read GPIO_DAT_STAT switch %d default to OFF\n",
+				pin);
+			gpi_stat_tmp = 0;
+		}
+
+		input_report_switch(kpad->input,
+				    kpad->gpimap[i].sw_evt,
+				    !(gpi_stat_tmp & (1 << pin_loc)));
+	}
+
+	input_sync(kpad->input);
+}
+
+
 static int __devinit adp5588_probe(struct i2c_client *client,
 					const struct i2c_device_id *id)
 {
 	struct adp5588_kpad *kpad;
-	struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+	const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
 	struct input_dev *input;
 	unsigned int revid;
 	int ret, i;
@@ -189,6 +475,37 @@
 		return -EINVAL;
 	}
 
+	if (!pdata->gpimap && pdata->gpimapsize) {
+		dev_err(&client->dev, "invalid gpimap from pdata\n");
+		return -EINVAL;
+	}
+
+	if (pdata->gpimapsize > ADP5588_GPIMAPSIZE_MAX) {
+		dev_err(&client->dev, "invalid gpimapsize\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < pdata->gpimapsize; i++) {
+		unsigned short pin = pdata->gpimap[i].pin;
+
+		if (pin < GPI_PIN_BASE || pin > GPI_PIN_END) {
+			dev_err(&client->dev, "invalid gpi pin data\n");
+			return -EINVAL;
+		}
+
+		if (pin <= GPI_PIN_ROW_END) {
+			if (pin - GPI_PIN_ROW_BASE + 1 <= pdata->rows) {
+				dev_err(&client->dev, "invalid gpi row data\n");
+				return -EINVAL;
+			}
+		} else {
+			if (pin - GPI_PIN_COL_BASE + 1 <= pdata->cols) {
+				dev_err(&client->dev, "invalid gpi col data\n");
+				return -EINVAL;
+			}
+		}
+	}
+
 	if (!client->irq) {
 		dev_err(&client->dev, "no IRQ?\n");
 		return -EINVAL;
@@ -233,6 +550,9 @@
 	memcpy(kpad->keycode, pdata->keymap,
 		pdata->keymapsize * input->keycodesize);
 
+	kpad->gpimap = pdata->gpimap;
+	kpad->gpimapsize = pdata->gpimapsize;
+
 	/* setup input device */
 	__set_bit(EV_KEY, input->evbit);
 
@@ -243,6 +563,11 @@
 		__set_bit(kpad->keycode[i] & KEY_MAX, input->keybit);
 	__clear_bit(KEY_RESERVED, input->keybit);
 
+	if (kpad->gpimapsize)
+		__set_bit(EV_SW, input->evbit);
+	for (i = 0; i < kpad->gpimapsize; i++)
+		__set_bit(kpad->gpimap[i].sw_evt, input->swbit);
+
 	error = input_register_device(input);
 	if (error) {
 		dev_err(&client->dev, "unable to register input device\n");
@@ -261,6 +586,13 @@
 	if (error)
 		goto err_free_irq;
 
+	if (kpad->gpimapsize)
+		adp5588_report_switch_state(kpad);
+
+	error = adp5588_gpio_add(kpad);
+	if (error)
+		goto err_free_irq;
+
 	device_init_wakeup(&client->dev, 1);
 	i2c_set_clientdata(client, kpad);
 
@@ -287,6 +619,7 @@
 	free_irq(client->irq, kpad);
 	cancel_delayed_work_sync(&kpad->work);
 	input_unregister_device(kpad->input);
+	adp5588_gpio_remove(kpad);
 	kfree(kpad);
 
 	return 0;
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index b8213fd..a9fd147 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -31,6 +31,7 @@
 	struct input_dev *input;
 	struct timer_list timer;
 	struct work_struct work;
+	int timer_debounce;	/* in msecs */
 	bool disabled;
 };
 
@@ -109,7 +110,7 @@
 		 * Disable IRQ and possible debouncing timer.
 		 */
 		disable_irq(gpio_to_irq(bdata->button->gpio));
-		if (bdata->button->debounce_interval)
+		if (bdata->timer_debounce)
 			del_timer_sync(&bdata->timer);
 
 		bdata->disabled = true;
@@ -347,9 +348,9 @@
 
 	BUG_ON(irq != gpio_to_irq(button->gpio));
 
-	if (button->debounce_interval)
+	if (bdata->timer_debounce)
 		mod_timer(&bdata->timer,
-			jiffies + msecs_to_jiffies(button->debounce_interval));
+			jiffies + msecs_to_jiffies(bdata->timer_debounce));
 	else
 		schedule_work(&bdata->work);
 
@@ -383,6 +384,14 @@
 		goto fail3;
 	}
 
+	if (button->debounce_interval) {
+		error = gpio_set_debounce(button->gpio,
+					  button->debounce_interval * 1000);
+		/* use timer if gpiolib doesn't provide debounce */
+		if (error < 0)
+			bdata->timer_debounce = button->debounce_interval;
+	}
+
 	irq = gpio_to_irq(button->gpio);
 	if (irq < 0) {
 		error = irq;
@@ -498,7 +507,7 @@
  fail2:
 	while (--i >= 0) {
 		free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
-		if (pdata->buttons[i].debounce_interval)
+		if (ddata->data[i].timer_debounce)
 			del_timer_sync(&ddata->data[i].timer);
 		cancel_work_sync(&ddata->data[i].work);
 		gpio_free(pdata->buttons[i].gpio);
@@ -526,7 +535,7 @@
 	for (i = 0; i < pdata->nbuttons; i++) {
 		int irq = gpio_to_irq(pdata->buttons[i].gpio);
 		free_irq(irq, &ddata->data[i]);
-		if (pdata->buttons[i].debounce_interval)
+		if (ddata->data[i].timer_debounce)
 			del_timer_sync(&ddata->data[i].timer);
 		cancel_work_sync(&ddata->data[i].work);
 		gpio_free(pdata->buttons[i].gpio);
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c
index 40b032f..f7c2a16 100644
--- a/drivers/input/keyboard/lm8323.c
+++ b/drivers/input/keyboard/lm8323.c
@@ -642,6 +642,7 @@
 	struct lm8323_platform_data *pdata = client->dev.platform_data;
 	struct input_dev *idev;
 	struct lm8323_chip *lm;
+	int pwm;
 	int i, err;
 	unsigned long tmo;
 	u8 data[2];
@@ -710,8 +711,9 @@
 		goto fail1;
 	}
 
-	for (i = 0; i < LM8323_NUM_PWMS; i++) {
-		err = init_pwm(lm, i + 1, &client->dev, pdata->pwm_names[i]);
+	for (pwm = 0; pwm < LM8323_NUM_PWMS; pwm++) {
+		err = init_pwm(lm, pwm + 1, &client->dev,
+			       pdata->pwm_names[pwm]);
 		if (err < 0)
 			goto fail2;
 	}
@@ -764,9 +766,9 @@
 fail3:
 	device_remove_file(&client->dev, &dev_attr_disable_kp);
 fail2:
-	while (--i >= 0)
-		if (lm->pwm[i].enabled)
-			led_classdev_unregister(&lm->pwm[i].cdev);
+	while (--pwm >= 0)
+		if (lm->pwm[pwm].enabled)
+			led_classdev_unregister(&lm->pwm[pwm].cdev);
 fail1:
 	input_free_device(idev);
 	kfree(lm);
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index b443e08..b02e426 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -37,6 +37,7 @@
 	spinlock_t lock;
 	bool scan_pending;
 	bool stopped;
+	bool gpio_all_disabled;
 };
 
 /*
@@ -87,8 +88,12 @@
 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
 	int i;
 
-	for (i = 0; i < pdata->num_row_gpios; i++)
-		enable_irq(gpio_to_irq(pdata->row_gpios[i]));
+	if (pdata->clustered_irq > 0)
+		enable_irq(pdata->clustered_irq);
+	else {
+		for (i = 0; i < pdata->num_row_gpios; i++)
+			enable_irq(gpio_to_irq(pdata->row_gpios[i]));
+	}
 }
 
 static void disable_row_irqs(struct matrix_keypad *keypad)
@@ -96,8 +101,12 @@
 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
 	int i;
 
-	for (i = 0; i < pdata->num_row_gpios; i++)
-		disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
+	if (pdata->clustered_irq > 0)
+		disable_irq_nosync(pdata->clustered_irq);
+	else {
+		for (i = 0; i < pdata->num_row_gpios; i++)
+			disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
+	}
 }
 
 /*
@@ -216,25 +225,58 @@
 }
 
 #ifdef CONFIG_PM
-static int matrix_keypad_suspend(struct device *dev)
+static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct matrix_keypad *keypad = platform_get_drvdata(pdev);
 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+	unsigned int gpio;
 	int i;
 
-	matrix_keypad_stop(keypad->input_dev);
+	if (pdata->clustered_irq > 0) {
+		if (enable_irq_wake(pdata->clustered_irq) == 0)
+			keypad->gpio_all_disabled = true;
+	} else {
 
-	if (device_may_wakeup(&pdev->dev)) {
 		for (i = 0; i < pdata->num_row_gpios; i++) {
 			if (!test_bit(i, keypad->disabled_gpios)) {
-				unsigned int gpio = pdata->row_gpios[i];
+				gpio = pdata->row_gpios[i];
 
 				if (enable_irq_wake(gpio_to_irq(gpio)) == 0)
 					__set_bit(i, keypad->disabled_gpios);
 			}
 		}
 	}
+}
+
+static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad)
+{
+	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+	unsigned int gpio;
+	int i;
+
+	if (pdata->clustered_irq > 0) {
+		if (keypad->gpio_all_disabled) {
+			disable_irq_wake(pdata->clustered_irq);
+			keypad->gpio_all_disabled = false;
+		}
+	} else {
+		for (i = 0; i < pdata->num_row_gpios; i++) {
+			if (test_and_clear_bit(i, keypad->disabled_gpios)) {
+				gpio = pdata->row_gpios[i];
+				disable_irq_wake(gpio_to_irq(gpio));
+			}
+		}
+	}
+}
+
+static int matrix_keypad_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct matrix_keypad *keypad = platform_get_drvdata(pdev);
+
+	matrix_keypad_stop(keypad->input_dev);
+
+	if (device_may_wakeup(&pdev->dev))
+		matrix_keypad_enable_wakeup(keypad);
 
 	return 0;
 }
@@ -243,18 +285,9 @@
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct matrix_keypad *keypad = platform_get_drvdata(pdev);
-	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
-	int i;
 
-	if (device_may_wakeup(&pdev->dev)) {
-		for (i = 0; i < pdata->num_row_gpios; i++) {
-			if (test_and_clear_bit(i, keypad->disabled_gpios)) {
-				unsigned int gpio = pdata->row_gpios[i];
-
-				disable_irq_wake(gpio_to_irq(gpio));
-			}
-		}
-	}
+	if (device_may_wakeup(&pdev->dev))
+		matrix_keypad_disable_wakeup(keypad);
 
 	matrix_keypad_start(keypad->input_dev);
 
@@ -296,17 +329,31 @@
 		gpio_direction_input(pdata->row_gpios[i]);
 	}
 
-	for (i = 0; i < pdata->num_row_gpios; i++) {
-		err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
+	if (pdata->clustered_irq > 0) {
+		err = request_irq(pdata->clustered_irq,
 				matrix_keypad_interrupt,
-				IRQF_DISABLED |
-				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				pdata->clustered_irq_flags,
 				"matrix-keypad", keypad);
 		if (err) {
 			dev_err(&pdev->dev,
-				"Unable to acquire interrupt for GPIO line %i\n",
-				pdata->row_gpios[i]);
-			goto err_free_irqs;
+				"Unable to acquire clustered interrupt\n");
+			goto err_free_rows;
+		}
+	} else {
+		for (i = 0; i < pdata->num_row_gpios; i++) {
+			err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
+					matrix_keypad_interrupt,
+					IRQF_DISABLED |
+					IRQF_TRIGGER_RISING |
+					IRQF_TRIGGER_FALLING,
+					"matrix-keypad", keypad);
+			if (err) {
+				dev_err(&pdev->dev,
+					"Unable to acquire interrupt "
+					"for GPIO line %i\n",
+					pdata->row_gpios[i]);
+				goto err_free_irqs;
+			}
 		}
 	}
 
@@ -418,11 +465,16 @@
 
 	device_init_wakeup(&pdev->dev, 0);
 
-	for (i = 0; i < pdata->num_row_gpios; i++) {
-		free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
-		gpio_free(pdata->row_gpios[i]);
+	if (pdata->clustered_irq > 0) {
+		free_irq(pdata->clustered_irq, keypad);
+	} else {
+		for (i = 0; i < pdata->num_row_gpios; i++)
+			free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
 	}
 
+	for (i = 0; i < pdata->num_row_gpios; i++)
+		gpio_free(pdata->row_gpios[i]);
+
 	for (i = 0; i < pdata->num_col_gpios; i++)
 		gpio_free(pdata->col_gpios[i]);
 
diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c
new file mode 100644
index 0000000..63b849d
--- /dev/null
+++ b/drivers/input/keyboard/mcs_touchkey.c
@@ -0,0 +1,239 @@
+/*
+ * mcs_touchkey.c - Touchkey driver for MELFAS MCS5000/5080 controller
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c/mcs.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+
+/* MCS5000 Touchkey */
+#define MCS5000_TOUCHKEY_STATUS		0x04
+#define MCS5000_TOUCHKEY_STATUS_PRESS	7
+#define MCS5000_TOUCHKEY_FW		0x0a
+#define MCS5000_TOUCHKEY_BASE_VAL	0x61
+
+/* MCS5080 Touchkey */
+#define MCS5080_TOUCHKEY_STATUS		0x00
+#define MCS5080_TOUCHKEY_STATUS_PRESS	3
+#define MCS5080_TOUCHKEY_FW		0x01
+#define MCS5080_TOUCHKEY_BASE_VAL	0x1
+
+enum mcs_touchkey_type {
+	MCS5000_TOUCHKEY,
+	MCS5080_TOUCHKEY,
+};
+
+struct mcs_touchkey_chip {
+	unsigned int status_reg;
+	unsigned int pressbit;
+	unsigned int press_invert;
+	unsigned int baseval;
+};
+
+struct mcs_touchkey_data {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct mcs_touchkey_chip chip;
+	unsigned int key_code;
+	unsigned int key_val;
+	unsigned short keycodes[];
+};
+
+static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id)
+{
+	struct mcs_touchkey_data *data = dev_id;
+	struct mcs_touchkey_chip *chip = &data->chip;
+	struct i2c_client *client = data->client;
+	struct input_dev *input = data->input_dev;
+	unsigned int key_val;
+	unsigned int pressed;
+	int val;
+
+	val = i2c_smbus_read_byte_data(client, chip->status_reg);
+	if (val < 0) {
+		dev_err(&client->dev, "i2c read error [%d]\n", val);
+		goto out;
+	}
+
+	pressed = (val & (1 << chip->pressbit)) >> chip->pressbit;
+	if (chip->press_invert)
+		pressed ^= chip->press_invert;
+
+	/* key_val is 0 when released, so we should use key_val of press. */
+	if (pressed) {
+		key_val = val & (0xff >> (8 - chip->pressbit));
+		if (!key_val)
+			goto out;
+		key_val -= chip->baseval;
+		data->key_code = data->keycodes[key_val];
+		data->key_val = key_val;
+	}
+
+	input_event(input, EV_MSC, MSC_SCAN, data->key_val);
+	input_report_key(input, data->key_code, pressed);
+	input_sync(input);
+
+	dev_dbg(&client->dev, "key %d %d %s\n", data->key_val, data->key_code,
+		pressed ? "pressed" : "released");
+
+ out:
+	return IRQ_HANDLED;
+}
+
+static int __devinit mcs_touchkey_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	const struct mcs_platform_data *pdata;
+	struct mcs_touchkey_data *data;
+	struct input_dev *input_dev;
+	unsigned int fw_reg;
+	int fw_ver;
+	int error;
+	int i;
+
+	pdata = client->dev.platform_data;
+	if (!pdata) {
+		dev_err(&client->dev, "no platform data defined\n");
+		return -EINVAL;
+	}
+
+	data = kzalloc(sizeof(struct mcs_touchkey_data) +
+			sizeof(data->keycodes[0]) * (pdata->key_maxval + 1),
+			GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!data || !input_dev) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	data->client = client;
+	data->input_dev = input_dev;
+
+	if (id->driver_data == MCS5000_TOUCHKEY) {
+		data->chip.status_reg = MCS5000_TOUCHKEY_STATUS;
+		data->chip.pressbit = MCS5000_TOUCHKEY_STATUS_PRESS;
+		data->chip.baseval = MCS5000_TOUCHKEY_BASE_VAL;
+		fw_reg = MCS5000_TOUCHKEY_FW;
+	} else {
+		data->chip.status_reg = MCS5080_TOUCHKEY_STATUS;
+		data->chip.pressbit = MCS5080_TOUCHKEY_STATUS_PRESS;
+		data->chip.press_invert = 1;
+		data->chip.baseval = MCS5080_TOUCHKEY_BASE_VAL;
+		fw_reg = MCS5080_TOUCHKEY_FW;
+	}
+
+	fw_ver = i2c_smbus_read_byte_data(client, fw_reg);
+	if (fw_ver < 0) {
+		error = fw_ver;
+		dev_err(&client->dev, "i2c read error[%d]\n", error);
+		goto err_free_mem;
+	}
+	dev_info(&client->dev, "Firmware version: %d\n", fw_ver);
+
+	input_dev->name = "MELPAS MCS Touchkey";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY);
+	if (!pdata->no_autorepeat)
+		input_dev->evbit[0] |= BIT_MASK(EV_REP);
+	input_dev->keycode = data->keycodes;
+	input_dev->keycodesize = sizeof(data->keycodes[0]);
+	input_dev->keycodemax = pdata->key_maxval + 1;
+
+	for (i = 0; i < pdata->keymap_size; i++) {
+		unsigned int val = MCS_KEY_VAL(pdata->keymap[i]);
+		unsigned int code = MCS_KEY_CODE(pdata->keymap[i]);
+
+		data->keycodes[val] = code;
+		__set_bit(code, input_dev->keybit);
+	}
+
+	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+	input_set_drvdata(input_dev, data);
+
+	if (pdata->cfg_pin)
+		pdata->cfg_pin();
+
+	error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt,
+			IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
+	if (error) {
+		dev_err(&client->dev, "Failed to register interrupt\n");
+		goto err_free_mem;
+	}
+
+	error = input_register_device(input_dev);
+	if (error)
+		goto err_free_irq;
+
+	i2c_set_clientdata(client, data);
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, data);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(data);
+	return error;
+}
+
+static int __devexit mcs_touchkey_remove(struct i2c_client *client)
+{
+	struct mcs_touchkey_data *data = i2c_get_clientdata(client);
+
+	free_irq(client->irq, data);
+	input_unregister_device(data->input_dev);
+	kfree(data);
+
+	return 0;
+}
+
+static const struct i2c_device_id mcs_touchkey_id[] = {
+	{ "mcs5000_touchkey", MCS5000_TOUCHKEY },
+	{ "mcs5080_touchkey", MCS5080_TOUCHKEY },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mcs_touchkey_id);
+
+static struct i2c_driver mcs_touchkey_driver = {
+	.driver = {
+		.name	= "mcs_touchkey",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= mcs_touchkey_probe,
+	.remove		= __devexit_p(mcs_touchkey_remove),
+	.id_table	= mcs_touchkey_id,
+};
+
+static int __init mcs_touchkey_init(void)
+{
+	return i2c_add_driver(&mcs_touchkey_driver);
+}
+
+static void __exit mcs_touchkey_exit(void)
+{
+	i2c_del_driver(&mcs_touchkey_driver);
+}
+
+module_init(mcs_touchkey_init);
+module_exit(mcs_touchkey_exit);
+
+/* Module information */
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
+MODULE_DESCRIPTION("Touchkey driver for MELFAS MCS5000/5080 controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
new file mode 100644
index 0000000..f689f49
--- /dev/null
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -0,0 +1,491 @@
+/*
+ * Samsung keypad driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ * Author: Donghwa Lee <dh09.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <plat/keypad.h>
+
+#define SAMSUNG_KEYIFCON			0x00
+#define SAMSUNG_KEYIFSTSCLR			0x04
+#define SAMSUNG_KEYIFCOL			0x08
+#define SAMSUNG_KEYIFROW			0x0c
+#define SAMSUNG_KEYIFFC				0x10
+
+/* SAMSUNG_KEYIFCON */
+#define SAMSUNG_KEYIFCON_INT_F_EN		(1 << 0)
+#define SAMSUNG_KEYIFCON_INT_R_EN		(1 << 1)
+#define SAMSUNG_KEYIFCON_DF_EN			(1 << 2)
+#define SAMSUNG_KEYIFCON_FC_EN			(1 << 3)
+#define SAMSUNG_KEYIFCON_WAKEUPEN		(1 << 4)
+
+/* SAMSUNG_KEYIFSTSCLR */
+#define SAMSUNG_KEYIFSTSCLR_P_INT_MASK		(0xff << 0)
+#define SAMSUNG_KEYIFSTSCLR_R_INT_MASK		(0xff << 8)
+#define SAMSUNG_KEYIFSTSCLR_R_INT_OFFSET	8
+#define S5PV210_KEYIFSTSCLR_P_INT_MASK		(0x3fff << 0)
+#define S5PV210_KEYIFSTSCLR_R_INT_MASK		(0x3fff << 16)
+#define S5PV210_KEYIFSTSCLR_R_INT_OFFSET	16
+
+/* SAMSUNG_KEYIFCOL */
+#define SAMSUNG_KEYIFCOL_MASK			(0xff << 0)
+#define S5PV210_KEYIFCOLEN_MASK			(0xff << 8)
+
+/* SAMSUNG_KEYIFROW */
+#define SAMSUNG_KEYIFROW_MASK			(0xff << 0)
+#define S5PV210_KEYIFROW_MASK			(0x3fff << 0)
+
+/* SAMSUNG_KEYIFFC */
+#define SAMSUNG_KEYIFFC_MASK			(0x3ff << 0)
+
+enum samsung_keypad_type {
+	KEYPAD_TYPE_SAMSUNG,
+	KEYPAD_TYPE_S5PV210,
+};
+
+struct samsung_keypad {
+	struct input_dev *input_dev;
+	struct clk *clk;
+	void __iomem *base;
+	wait_queue_head_t wait;
+	bool stopped;
+	int irq;
+	unsigned int row_shift;
+	unsigned int rows;
+	unsigned int cols;
+	unsigned int row_state[SAMSUNG_MAX_COLS];
+	unsigned short keycodes[];
+};
+
+static int samsung_keypad_is_s5pv210(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	enum samsung_keypad_type type =
+		platform_get_device_id(pdev)->driver_data;
+
+	return type == KEYPAD_TYPE_S5PV210;
+}
+
+static void samsung_keypad_scan(struct samsung_keypad *keypad,
+				unsigned int *row_state)
+{
+	struct device *dev = keypad->input_dev->dev.parent;
+	unsigned int col;
+	unsigned int val;
+
+	for (col = 0; col < keypad->cols; col++) {
+		if (samsung_keypad_is_s5pv210(dev)) {
+			val = S5PV210_KEYIFCOLEN_MASK;
+			val &= ~(1 << col) << 8;
+		} else {
+			val = SAMSUNG_KEYIFCOL_MASK;
+			val &= ~(1 << col);
+		}
+
+		writel(val, keypad->base + SAMSUNG_KEYIFCOL);
+		mdelay(1);
+
+		val = readl(keypad->base + SAMSUNG_KEYIFROW);
+		row_state[col] = ~val & ((1 << keypad->rows) - 1);
+	}
+
+	/* KEYIFCOL reg clear */
+	writel(0, keypad->base + SAMSUNG_KEYIFCOL);
+}
+
+static bool samsung_keypad_report(struct samsung_keypad *keypad,
+				  unsigned int *row_state)
+{
+	struct input_dev *input_dev = keypad->input_dev;
+	unsigned int changed;
+	unsigned int pressed;
+	unsigned int key_down = 0;
+	unsigned int val;
+	unsigned int col, row;
+
+	for (col = 0; col < keypad->cols; col++) {
+		changed = row_state[col] ^ keypad->row_state[col];
+		key_down |= row_state[col];
+		if (!changed)
+			continue;
+
+		for (row = 0; row < keypad->rows; row++) {
+			if (!(changed & (1 << row)))
+				continue;
+
+			pressed = row_state[col] & (1 << row);
+
+			dev_dbg(&keypad->input_dev->dev,
+				"key %s, row: %d, col: %d\n",
+				pressed ? "pressed" : "released", row, col);
+
+			val = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
+
+			input_event(input_dev, EV_MSC, MSC_SCAN, val);
+			input_report_key(input_dev,
+					keypad->keycodes[val], pressed);
+		}
+		input_sync(keypad->input_dev);
+	}
+
+	memcpy(keypad->row_state, row_state, sizeof(keypad->row_state));
+
+	return key_down;
+}
+
+static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)
+{
+	struct samsung_keypad *keypad = dev_id;
+	unsigned int row_state[SAMSUNG_MAX_COLS];
+	unsigned int val;
+	bool key_down;
+
+	do {
+		val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
+		/* Clear interrupt. */
+		writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
+
+		samsung_keypad_scan(keypad, row_state);
+
+		key_down = samsung_keypad_report(keypad, row_state);
+		if (key_down)
+			wait_event_timeout(keypad->wait, keypad->stopped,
+					   msecs_to_jiffies(50));
+
+	} while (key_down && !keypad->stopped);
+
+	return IRQ_HANDLED;
+}
+
+static void samsung_keypad_start(struct samsung_keypad *keypad)
+{
+	unsigned int val;
+
+	/* Tell IRQ thread that it may poll the device. */
+	keypad->stopped = false;
+
+	clk_enable(keypad->clk);
+
+	/* Enable interrupt bits. */
+	val = readl(keypad->base + SAMSUNG_KEYIFCON);
+	val |= SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN;
+	writel(val, keypad->base + SAMSUNG_KEYIFCON);
+
+	/* KEYIFCOL reg clear. */
+	writel(0, keypad->base + SAMSUNG_KEYIFCOL);
+}
+
+static void samsung_keypad_stop(struct samsung_keypad *keypad)
+{
+	unsigned int val;
+
+	/* Signal IRQ thread to stop polling and disable the handler. */
+	keypad->stopped = true;
+	wake_up(&keypad->wait);
+	disable_irq(keypad->irq);
+
+	/* Clear interrupt. */
+	writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
+
+	/* Disable interrupt bits. */
+	val = readl(keypad->base + SAMSUNG_KEYIFCON);
+	val &= ~(SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN);
+	writel(val, keypad->base + SAMSUNG_KEYIFCON);
+
+	clk_disable(keypad->clk);
+
+	/*
+	 * Now that chip should not generate interrupts we can safely
+	 * re-enable the handler.
+	 */
+	enable_irq(keypad->irq);
+}
+
+static int samsung_keypad_open(struct input_dev *input_dev)
+{
+	struct samsung_keypad *keypad = input_get_drvdata(input_dev);
+
+	samsung_keypad_start(keypad);
+
+	return 0;
+}
+
+static void samsung_keypad_close(struct input_dev *input_dev)
+{
+	struct samsung_keypad *keypad = input_get_drvdata(input_dev);
+
+	samsung_keypad_stop(keypad);
+}
+
+static int __devinit samsung_keypad_probe(struct platform_device *pdev)
+{
+	const struct samsung_keypad_platdata *pdata;
+	const struct matrix_keymap_data *keymap_data;
+	struct samsung_keypad *keypad;
+	struct resource *res;
+	struct input_dev *input_dev;
+	unsigned int row_shift;
+	unsigned int keymap_size;
+	int error;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data defined\n");
+		return -EINVAL;
+	}
+
+	keymap_data = pdata->keymap_data;
+	if (!keymap_data) {
+		dev_err(&pdev->dev, "no keymap data defined\n");
+		return -EINVAL;
+	}
+
+	if (!pdata->rows || pdata->rows > SAMSUNG_MAX_ROWS)
+		return -EINVAL;
+
+	if (!pdata->cols || pdata->cols > SAMSUNG_MAX_COLS)
+		return -EINVAL;
+
+	/* initialize the gpio */
+	if (pdata->cfg_gpio)
+		pdata->cfg_gpio(pdata->rows, pdata->cols);
+
+	row_shift = get_count_order(pdata->cols);
+	keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]);
+
+	keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!keypad || !input_dev) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		error = -ENODEV;
+		goto err_free_mem;
+	}
+
+	keypad->base = ioremap(res->start, resource_size(res));
+	if (!keypad->base) {
+		error = -EBUSY;
+		goto err_free_mem;
+	}
+
+	keypad->clk = clk_get(&pdev->dev, "keypad");
+	if (IS_ERR(keypad->clk)) {
+		dev_err(&pdev->dev, "failed to get keypad clk\n");
+		error = PTR_ERR(keypad->clk);
+		goto err_unmap_base;
+	}
+
+	keypad->input_dev = input_dev;
+	keypad->row_shift = row_shift;
+	keypad->rows = pdata->rows;
+	keypad->cols = pdata->cols;
+	init_waitqueue_head(&keypad->wait);
+
+	input_dev->name = pdev->name;
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->dev.parent = &pdev->dev;
+	input_set_drvdata(input_dev, keypad);
+
+	input_dev->open = samsung_keypad_open;
+	input_dev->close = samsung_keypad_close;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY);
+	if (!pdata->no_autorepeat)
+		input_dev->evbit[0] |= BIT_MASK(EV_REP);
+
+	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+	input_dev->keycode = keypad->keycodes;
+	input_dev->keycodesize = sizeof(keypad->keycodes[0]);
+	input_dev->keycodemax = pdata->rows << row_shift;
+
+	matrix_keypad_build_keymap(keymap_data, row_shift,
+			input_dev->keycode, input_dev->keybit);
+
+	keypad->irq = platform_get_irq(pdev, 0);
+	if (keypad->irq < 0) {
+		error = keypad->irq;
+		goto err_put_clk;
+	}
+
+	error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq,
+			IRQF_ONESHOT, dev_name(&pdev->dev), keypad);
+	if (error) {
+		dev_err(&pdev->dev, "failed to register keypad interrupt\n");
+		goto err_put_clk;
+	}
+
+	error = input_register_device(keypad->input_dev);
+	if (error)
+		goto err_free_irq;
+
+	device_init_wakeup(&pdev->dev, pdata->wakeup);
+	platform_set_drvdata(pdev, keypad);
+	return 0;
+
+err_free_irq:
+	free_irq(keypad->irq, keypad);
+err_put_clk:
+	clk_put(keypad->clk);
+err_unmap_base:
+	iounmap(keypad->base);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(keypad);
+
+	return error;
+}
+
+static int __devexit samsung_keypad_remove(struct platform_device *pdev)
+{
+	struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+
+	device_init_wakeup(&pdev->dev, 0);
+	platform_set_drvdata(pdev, NULL);
+
+	input_unregister_device(keypad->input_dev);
+
+	/*
+	 * It is safe to free IRQ after unregistering device because
+	 * samsung_keypad_close will shut off interrupts.
+	 */
+	free_irq(keypad->irq, keypad);
+
+	clk_put(keypad->clk);
+
+	iounmap(keypad->base);
+	kfree(keypad);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad,
+					 bool enable)
+{
+	struct device *dev = keypad->input_dev->dev.parent;
+	unsigned int val;
+
+	clk_enable(keypad->clk);
+
+	val = readl(keypad->base + SAMSUNG_KEYIFCON);
+	if (enable) {
+		val |= SAMSUNG_KEYIFCON_WAKEUPEN;
+		if (device_may_wakeup(dev))
+			enable_irq_wake(keypad->irq);
+	} else {
+		val &= ~SAMSUNG_KEYIFCON_WAKEUPEN;
+		if (device_may_wakeup(dev))
+			disable_irq_wake(keypad->irq);
+	}
+	writel(val, keypad->base + SAMSUNG_KEYIFCON);
+
+	clk_disable(keypad->clk);
+}
+
+static int samsung_keypad_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+	struct input_dev *input_dev = keypad->input_dev;
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users)
+		samsung_keypad_stop(keypad);
+
+	samsung_keypad_toggle_wakeup(keypad, true);
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+
+static int samsung_keypad_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+	struct input_dev *input_dev = keypad->input_dev;
+
+	mutex_lock(&input_dev->mutex);
+
+	samsung_keypad_toggle_wakeup(keypad, false);
+
+	if (input_dev->users)
+		samsung_keypad_start(keypad);
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+
+static const struct dev_pm_ops samsung_keypad_pm_ops = {
+	.suspend	= samsung_keypad_suspend,
+	.resume		= samsung_keypad_resume,
+};
+#endif
+
+static struct platform_device_id samsung_keypad_driver_ids[] = {
+	{
+		.name		= "samsung-keypad",
+		.driver_data	= KEYPAD_TYPE_SAMSUNG,
+	}, {
+		.name		= "s5pv210-keypad",
+		.driver_data	= KEYPAD_TYPE_S5PV210,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids);
+
+static struct platform_driver samsung_keypad_driver = {
+	.probe		= samsung_keypad_probe,
+	.remove		= __devexit_p(samsung_keypad_remove),
+	.driver		= {
+		.name	= "samsung-keypad",
+		.owner	= THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &samsung_keypad_pm_ops,
+#endif
+	},
+	.id_table	= samsung_keypad_driver_ids,
+};
+
+static int __init samsung_keypad_init(void)
+{
+	return platform_driver_register(&samsung_keypad_driver);
+}
+module_init(samsung_keypad_init);
+
+static void __exit samsung_keypad_exit(void)
+{
+	platform_driver_unregister(&samsung_keypad_driver);
+}
+module_exit(samsung_keypad_exit);
+
+MODULE_DESCRIPTION("Samsung keypad driver");
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-keypad");
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index c44b9ea..b49e233 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -327,6 +327,17 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called pcf8574_keypad.
 
+config INPUT_PWM_BEEPER
+	tristate "PWM beeper support"
+	depends on HAVE_PWM
+	help
+	  Say Y here to get support for PWM based beeper devices.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called pwm-beeper.
+
 config INPUT_GPIO_ROTARY_ENCODER
 	tristate "Rotary encoders connected to GPIO pins"
 	depends on GPIOLIB && GENERIC_GPIO
@@ -390,4 +401,41 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called pcap_keys.
 
+config INPUT_ADXL34X
+	tristate "Analog Devices ADXL34x Three-Axis Digital Accelerometer"
+	default n
+	help
+	  Say Y here if you have a Accelerometer interface using the
+	  ADXL345/6 controller, and your board-specific initialization
+	  code includes that in its table of devices.
+
+	  This driver can use either I2C or SPI communication to the
+	  ADXL345/6 controller.  Select the appropriate method for
+	  your system.
+
+	  If unsure, say N (but it's safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adxl34x.
+
+config INPUT_ADXL34X_I2C
+	tristate "support I2C bus connection"
+	depends on INPUT_ADXL34X && I2C
+	default y
+	help
+	  Say Y here if you have ADXL345/6 hooked to an I2C bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adxl34x-i2c.
+
+config INPUT_ADXL34X_SPI
+	tristate "support SPI bus connection"
+	depends on INPUT_ADXL34X && SPI
+	default y
+	help
+	  Say Y here if you have ADXL345/6 hooked to a SPI bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adxl34x-spi.
+
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 71fe57d..19ccca7 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -8,6 +8,9 @@
 obj-$(CONFIG_INPUT_AD714X)		+= ad714x.o
 obj-$(CONFIG_INPUT_AD714X_I2C)		+= ad714x-i2c.o
 obj-$(CONFIG_INPUT_AD714X_SPI)		+= ad714x-spi.o
+obj-$(CONFIG_INPUT_ADXL34X)		+= adxl34x.o
+obj-$(CONFIG_INPUT_ADXL34X_I2C)		+= adxl34x-i2c.o
+obj-$(CONFIG_INPUT_ADXL34X_SPI)		+= adxl34x-spi.o
 obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
 obj-$(CONFIG_INPUT_ATI_REMOTE)		+= ati_remote.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
@@ -26,6 +29,7 @@
 obj-$(CONFIG_INPUT_PCF8574)		+= pcf8574_keypad.o
 obj-$(CONFIG_INPUT_PCSPKR)		+= pcspkr.o
 obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
+obj-$(CONFIG_INPUT_PWM_BEEPER)		+= pwm-beeper.o
 obj-$(CONFIG_INPUT_RB532_BUTTON)	+= rb532_button.o
 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)	+= rotary_encoder.o
 obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o
diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c
new file mode 100644
index 0000000..0779724
--- /dev/null
+++ b/drivers/input/misc/adxl34x-i2c.c
@@ -0,0 +1,163 @@
+/*
+ * ADLX345/346 Three-Axis Digital Accelerometers (I2C Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_I2C */
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include "adxl34x.h"
+
+static int adxl34x_smbus_read(struct device *dev, unsigned char reg)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int adxl34x_smbus_write(struct device *dev,
+			       unsigned char reg, unsigned char val)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int adxl34x_smbus_read_block(struct device *dev,
+				    unsigned char reg, int count,
+				    void *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return i2c_smbus_read_i2c_block_data(client, reg, count, buf);
+}
+
+static int adxl34x_i2c_read_block(struct device *dev,
+				  unsigned char reg, int count,
+				  void *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int ret;
+
+	ret = i2c_master_send(client, &reg, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_master_recv(client, buf, count);
+	if (ret < 0)
+		return ret;
+
+	if (ret != count)
+		return -EIO;
+
+	return 0;
+}
+
+static const struct adxl34x_bus_ops adxl34x_smbus_bops = {
+	.bustype	= BUS_I2C,
+	.write		= adxl34x_smbus_write,
+	.read		= adxl34x_smbus_read,
+	.read_block	= adxl34x_smbus_read_block,
+};
+
+static const struct adxl34x_bus_ops adxl34x_i2c_bops = {
+	.bustype	= BUS_I2C,
+	.write		= adxl34x_smbus_write,
+	.read		= adxl34x_smbus_read,
+	.read_block	= adxl34x_i2c_read_block,
+};
+
+static int __devinit adxl34x_i2c_probe(struct i2c_client *client,
+				       const struct i2c_device_id *id)
+{
+	struct adxl34x *ac;
+	int error;
+
+	error = i2c_check_functionality(client->adapter,
+			I2C_FUNC_SMBUS_BYTE_DATA);
+	if (!error) {
+		dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+		return -EIO;
+	}
+
+	ac = adxl34x_probe(&client->dev, client->irq, false,
+			   i2c_check_functionality(client->adapter,
+						   I2C_FUNC_SMBUS_READ_I2C_BLOCK) ?
+				&adxl34x_smbus_bops : &adxl34x_i2c_bops);
+	if (IS_ERR(ac))
+		return PTR_ERR(ac);
+
+	i2c_set_clientdata(client, ac);
+
+	return 0;
+}
+
+static int __devexit adxl34x_i2c_remove(struct i2c_client *client)
+{
+	struct adxl34x *ac = i2c_get_clientdata(client);
+
+	return adxl34x_remove(ac);
+}
+
+#ifdef CONFIG_PM
+static int adxl34x_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+	struct adxl34x *ac = i2c_get_clientdata(client);
+
+	adxl34x_suspend(ac);
+
+	return 0;
+}
+
+static int adxl34x_i2c_resume(struct i2c_client *client)
+{
+	struct adxl34x *ac = i2c_get_clientdata(client);
+
+	adxl34x_resume(ac);
+
+	return 0;
+}
+#else
+# define adxl34x_i2c_suspend NULL
+# define adxl34x_i2c_resume  NULL
+#endif
+
+static const struct i2c_device_id adxl34x_id[] = {
+	{ "adxl34x", 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, adxl34x_id);
+
+static struct i2c_driver adxl34x_driver = {
+	.driver = {
+		.name = "adxl34x",
+		.owner = THIS_MODULE,
+	},
+	.probe    = adxl34x_i2c_probe,
+	.remove   = __devexit_p(adxl34x_i2c_remove),
+	.suspend  = adxl34x_i2c_suspend,
+	.resume   = adxl34x_i2c_resume,
+	.id_table = adxl34x_id,
+};
+
+static int __init adxl34x_i2c_init(void)
+{
+	return i2c_add_driver(&adxl34x_driver);
+}
+module_init(adxl34x_i2c_init);
+
+static void __exit adxl34x_i2c_exit(void)
+{
+	i2c_del_driver(&adxl34x_driver);
+}
+module_exit(adxl34x_i2c_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer I2C Bus Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c
new file mode 100644
index 0000000..782de9e
--- /dev/null
+++ b/drivers/input/misc/adxl34x-spi.c
@@ -0,0 +1,145 @@
+/*
+ * ADLX345/346 Three-Axis Digital Accelerometers (SPI Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_SPI */
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include "adxl34x.h"
+
+#define MAX_SPI_FREQ_HZ		5000000
+#define MAX_FREQ_NO_FIFODELAY	1500000
+#define ADXL34X_CMD_MULTB	(1 << 6)
+#define ADXL34X_CMD_READ	(1 << 7)
+#define ADXL34X_WRITECMD(reg)	(reg & 0x3F)
+#define ADXL34X_READCMD(reg)	(ADXL34X_CMD_READ | (reg & 0x3F))
+#define ADXL34X_READMB_CMD(reg) (ADXL34X_CMD_READ | ADXL34X_CMD_MULTB \
+					| (reg & 0x3F))
+
+static int adxl34x_spi_read(struct device *dev, unsigned char reg)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	unsigned char cmd;
+
+	cmd = ADXL34X_READCMD(reg);
+
+	return spi_w8r8(spi, cmd);
+}
+
+static int adxl34x_spi_write(struct device *dev,
+			     unsigned char reg, unsigned char val)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	unsigned char buf[2];
+
+	buf[0] = ADXL34X_WRITECMD(reg);
+	buf[1] = val;
+
+	return spi_write(spi, buf, sizeof(buf));
+}
+
+static int adxl34x_spi_read_block(struct device *dev,
+				  unsigned char reg, int count,
+				  void *buf)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	ssize_t status;
+
+	reg = ADXL34X_READMB_CMD(reg);
+	status = spi_write_then_read(spi, &reg, 1, buf, count);
+
+	return (status < 0) ? status : 0;
+}
+
+static const struct adxl34x_bus_ops adx134x_spi_bops = {
+	.bustype	= BUS_SPI,
+	.write		= adxl34x_spi_write,
+	.read		= adxl34x_spi_read,
+	.read_block	= adxl34x_spi_read_block,
+};
+
+static int __devinit adxl34x_spi_probe(struct spi_device *spi)
+{
+	struct adxl34x *ac;
+
+	/* don't exceed max specified SPI CLK frequency */
+	if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
+		dev_err(&spi->dev, "SPI CLK %d Hz too fast\n", spi->max_speed_hz);
+		return -EINVAL;
+	}
+
+	ac = adxl34x_probe(&spi->dev, spi->irq,
+			   spi->max_speed_hz > MAX_FREQ_NO_FIFODELAY,
+			   &adx134x_spi_bops);
+
+	if (IS_ERR(ac))
+		return PTR_ERR(ac);
+
+	spi_set_drvdata(spi, ac);
+
+	return 0;
+}
+
+static int __devexit adxl34x_spi_remove(struct spi_device *spi)
+{
+	struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+	return adxl34x_remove(ac);
+}
+
+#ifdef CONFIG_PM
+static int adxl34x_spi_suspend(struct spi_device *spi, pm_message_t message)
+{
+	struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+	adxl34x_suspend(ac);
+
+	return 0;
+}
+
+static int adxl34x_spi_resume(struct spi_device *spi)
+{
+	struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+	adxl34x_resume(ac);
+
+	return 0;
+}
+#else
+# define adxl34x_spi_suspend NULL
+# define adxl34x_spi_resume  NULL
+#endif
+
+static struct spi_driver adxl34x_driver = {
+	.driver = {
+		.name = "adxl34x",
+		.bus = &spi_bus_type,
+		.owner = THIS_MODULE,
+	},
+	.probe   = adxl34x_spi_probe,
+	.remove  = __devexit_p(adxl34x_spi_remove),
+	.suspend = adxl34x_spi_suspend,
+	.resume  = adxl34x_spi_resume,
+};
+
+static int __init adxl34x_spi_init(void)
+{
+	return spi_register_driver(&adxl34x_driver);
+}
+module_init(adxl34x_spi_init);
+
+static void __exit adxl34x_spi_exit(void)
+{
+	spi_unregister_driver(&adxl34x_driver);
+}
+module_exit(adxl34x_spi_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer SPI Bus Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c
new file mode 100644
index 0000000..e2ca017
--- /dev/null
+++ b/drivers/input/misc/adxl34x.c
@@ -0,0 +1,915 @@
+/*
+ * ADXL345/346 Three-Axis Digital Accelerometers
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/input/adxl34x.h>
+
+#include "adxl34x.h"
+
+/* ADXL345/6 Register Map */
+#define DEVID		0x00	/* R   Device ID */
+#define THRESH_TAP	0x1D	/* R/W Tap threshold */
+#define OFSX		0x1E	/* R/W X-axis offset */
+#define OFSY		0x1F	/* R/W Y-axis offset */
+#define OFSZ		0x20	/* R/W Z-axis offset */
+#define DUR		0x21	/* R/W Tap duration */
+#define LATENT		0x22	/* R/W Tap latency */
+#define WINDOW		0x23	/* R/W Tap window */
+#define THRESH_ACT	0x24	/* R/W Activity threshold */
+#define THRESH_INACT	0x25	/* R/W Inactivity threshold */
+#define TIME_INACT	0x26	/* R/W Inactivity time */
+#define ACT_INACT_CTL	0x27	/* R/W Axis enable control for activity and */
+				/* inactivity detection */
+#define THRESH_FF	0x28	/* R/W Free-fall threshold */
+#define TIME_FF		0x29	/* R/W Free-fall time */
+#define TAP_AXES	0x2A	/* R/W Axis control for tap/double tap */
+#define ACT_TAP_STATUS	0x2B	/* R   Source of tap/double tap */
+#define BW_RATE		0x2C	/* R/W Data rate and power mode control */
+#define POWER_CTL	0x2D	/* R/W Power saving features control */
+#define INT_ENABLE	0x2E	/* R/W Interrupt enable control */
+#define INT_MAP		0x2F	/* R/W Interrupt mapping control */
+#define INT_SOURCE	0x30	/* R   Source of interrupts */
+#define DATA_FORMAT	0x31	/* R/W Data format control */
+#define DATAX0		0x32	/* R   X-Axis Data 0 */
+#define DATAX1		0x33	/* R   X-Axis Data 1 */
+#define DATAY0		0x34	/* R   Y-Axis Data 0 */
+#define DATAY1		0x35	/* R   Y-Axis Data 1 */
+#define DATAZ0		0x36	/* R   Z-Axis Data 0 */
+#define DATAZ1		0x37	/* R   Z-Axis Data 1 */
+#define FIFO_CTL	0x38	/* R/W FIFO control */
+#define FIFO_STATUS	0x39	/* R   FIFO status */
+#define TAP_SIGN	0x3A	/* R   Sign and source for tap/double tap */
+/* Orientation ADXL346 only */
+#define ORIENT_CONF	0x3B	/* R/W Orientation configuration */
+#define ORIENT		0x3C	/* R   Orientation status */
+
+/* DEVIDs */
+#define ID_ADXL345	0xE5
+#define ID_ADXL346	0xE6
+
+/* INT_ENABLE/INT_MAP/INT_SOURCE Bits */
+#define DATA_READY	(1 << 7)
+#define SINGLE_TAP	(1 << 6)
+#define DOUBLE_TAP	(1 << 5)
+#define ACTIVITY	(1 << 4)
+#define INACTIVITY	(1 << 3)
+#define FREE_FALL	(1 << 2)
+#define WATERMARK	(1 << 1)
+#define OVERRUN		(1 << 0)
+
+/* ACT_INACT_CONTROL Bits */
+#define ACT_ACDC	(1 << 7)
+#define ACT_X_EN	(1 << 6)
+#define ACT_Y_EN	(1 << 5)
+#define ACT_Z_EN	(1 << 4)
+#define INACT_ACDC	(1 << 3)
+#define INACT_X_EN	(1 << 2)
+#define INACT_Y_EN	(1 << 1)
+#define INACT_Z_EN	(1 << 0)
+
+/* TAP_AXES Bits */
+#define SUPPRESS	(1 << 3)
+#define TAP_X_EN	(1 << 2)
+#define TAP_Y_EN	(1 << 1)
+#define TAP_Z_EN	(1 << 0)
+
+/* ACT_TAP_STATUS Bits */
+#define ACT_X_SRC	(1 << 6)
+#define ACT_Y_SRC	(1 << 5)
+#define ACT_Z_SRC	(1 << 4)
+#define ASLEEP		(1 << 3)
+#define TAP_X_SRC	(1 << 2)
+#define TAP_Y_SRC	(1 << 1)
+#define TAP_Z_SRC	(1 << 0)
+
+/* BW_RATE Bits */
+#define LOW_POWER	(1 << 4)
+#define RATE(x)		((x) & 0xF)
+
+/* POWER_CTL Bits */
+#define PCTL_LINK	(1 << 5)
+#define PCTL_AUTO_SLEEP (1 << 4)
+#define PCTL_MEASURE	(1 << 3)
+#define PCTL_SLEEP	(1 << 2)
+#define PCTL_WAKEUP(x)	((x) & 0x3)
+
+/* DATA_FORMAT Bits */
+#define SELF_TEST	(1 << 7)
+#define SPI		(1 << 6)
+#define INT_INVERT	(1 << 5)
+#define FULL_RES	(1 << 3)
+#define JUSTIFY		(1 << 2)
+#define RANGE(x)	((x) & 0x3)
+#define RANGE_PM_2g	0
+#define RANGE_PM_4g	1
+#define RANGE_PM_8g	2
+#define RANGE_PM_16g	3
+
+/*
+ * Maximum value our axis may get in full res mode for the input device
+ * (signed 13 bits)
+ */
+#define ADXL_FULLRES_MAX_VAL 4096
+
+/*
+ * Maximum value our axis may get in fixed res mode for the input device
+ * (signed 10 bits)
+ */
+#define ADXL_FIXEDRES_MAX_VAL 512
+
+/* FIFO_CTL Bits */
+#define FIFO_MODE(x)	(((x) & 0x3) << 6)
+#define FIFO_BYPASS	0
+#define FIFO_FIFO	1
+#define FIFO_STREAM	2
+#define FIFO_TRIGGER	3
+#define TRIGGER		(1 << 5)
+#define SAMPLES(x)	((x) & 0x1F)
+
+/* FIFO_STATUS Bits */
+#define FIFO_TRIG	(1 << 7)
+#define ENTRIES(x)	((x) & 0x3F)
+
+/* TAP_SIGN Bits ADXL346 only */
+#define XSIGN		(1 << 6)
+#define YSIGN		(1 << 5)
+#define ZSIGN		(1 << 4)
+#define XTAP		(1 << 3)
+#define YTAP		(1 << 2)
+#define ZTAP		(1 << 1)
+
+/* ORIENT_CONF ADXL346 only */
+#define ORIENT_DEADZONE(x)	(((x) & 0x7) << 4)
+#define ORIENT_DIVISOR(x)	((x) & 0x7)
+
+/* ORIENT ADXL346 only */
+#define ADXL346_2D_VALID		(1 << 6)
+#define ADXL346_2D_ORIENT(x)		(((x) & 0x3) >> 4)
+#define ADXL346_3D_VALID		(1 << 3)
+#define ADXL346_3D_ORIENT(x)		((x) & 0x7)
+#define ADXL346_2D_PORTRAIT_POS		0	/* +X */
+#define ADXL346_2D_PORTRAIT_NEG		1	/* -X */
+#define ADXL346_2D_LANDSCAPE_POS	2	/* +Y */
+#define ADXL346_2D_LANDSCAPE_NEG	3	/* -Y */
+
+#define ADXL346_3D_FRONT		3	/* +X */
+#define ADXL346_3D_BACK			4	/* -X */
+#define ADXL346_3D_RIGHT		2	/* +Y */
+#define ADXL346_3D_LEFT			5	/* -Y */
+#define ADXL346_3D_TOP			1	/* +Z */
+#define ADXL346_3D_BOTTOM		6	/* -Z */
+
+#undef ADXL_DEBUG
+
+#define ADXL_X_AXIS			0
+#define ADXL_Y_AXIS			1
+#define ADXL_Z_AXIS			2
+
+#define AC_READ(ac, reg)	((ac)->bops->read((ac)->dev, reg))
+#define AC_WRITE(ac, reg, val)	((ac)->bops->write((ac)->dev, reg, val))
+
+struct axis_triple {
+	int x;
+	int y;
+	int z;
+};
+
+struct adxl34x {
+	struct device *dev;
+	struct input_dev *input;
+	struct mutex mutex;	/* reentrant protection for struct */
+	struct adxl34x_platform_data pdata;
+	struct axis_triple swcal;
+	struct axis_triple hwcal;
+	struct axis_triple saved;
+	char phys[32];
+	unsigned orient2d_saved;
+	unsigned orient3d_saved;
+	bool disabled;	/* P: mutex */
+	bool opened;	/* P: mutex */
+	bool suspended;	/* P: mutex */
+	bool fifo_delay;
+	int irq;
+	unsigned model;
+	unsigned int_mask;
+
+	const struct adxl34x_bus_ops *bops;
+};
+
+static const struct adxl34x_platform_data adxl34x_default_init = {
+	.tap_threshold = 35,
+	.tap_duration = 3,
+	.tap_latency = 20,
+	.tap_window = 20,
+	.tap_axis_control = ADXL_TAP_X_EN | ADXL_TAP_Y_EN | ADXL_TAP_Z_EN,
+	.act_axis_control = 0xFF,
+	.activity_threshold = 6,
+	.inactivity_threshold = 4,
+	.inactivity_time = 3,
+	.free_fall_threshold = 8,
+	.free_fall_time = 0x20,
+	.data_rate = 8,
+	.data_range = ADXL_FULL_RES,
+
+	.ev_type = EV_ABS,
+	.ev_code_x = ABS_X,	/* EV_REL */
+	.ev_code_y = ABS_Y,	/* EV_REL */
+	.ev_code_z = ABS_Z,	/* EV_REL */
+
+	.ev_code_tap = {BTN_TOUCH, BTN_TOUCH, BTN_TOUCH}, /* EV_KEY {x,y,z} */
+	.power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
+	.fifo_mode = FIFO_STREAM,
+	.watermark = 0,
+};
+
+static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis)
+{
+	short buf[3];
+
+	ac->bops->read_block(ac->dev, DATAX0, DATAZ1 - DATAX0 + 1, buf);
+
+	mutex_lock(&ac->mutex);
+	ac->saved.x = (s16) le16_to_cpu(buf[0]);
+	axis->x = ac->saved.x;
+
+	ac->saved.y = (s16) le16_to_cpu(buf[1]);
+	axis->y = ac->saved.y;
+
+	ac->saved.z = (s16) le16_to_cpu(buf[2]);
+	axis->z = ac->saved.z;
+	mutex_unlock(&ac->mutex);
+}
+
+static void adxl34x_service_ev_fifo(struct adxl34x *ac)
+{
+	struct adxl34x_platform_data *pdata = &ac->pdata;
+	struct axis_triple axis;
+
+	adxl34x_get_triple(ac, &axis);
+
+	input_event(ac->input, pdata->ev_type, pdata->ev_code_x,
+		    axis.x - ac->swcal.x);
+	input_event(ac->input, pdata->ev_type, pdata->ev_code_y,
+		    axis.y - ac->swcal.y);
+	input_event(ac->input, pdata->ev_type, pdata->ev_code_z,
+		    axis.z - ac->swcal.z);
+}
+
+static void adxl34x_report_key_single(struct input_dev *input, int key)
+{
+	input_report_key(input, key, true);
+	input_sync(input);
+	input_report_key(input, key, false);
+}
+
+static void adxl34x_send_key_events(struct adxl34x *ac,
+		struct adxl34x_platform_data *pdata, int status, int press)
+{
+	int i;
+
+	for (i = ADXL_X_AXIS; i <= ADXL_Z_AXIS; i++) {
+		if (status & (1 << (ADXL_Z_AXIS - i)))
+			input_report_key(ac->input,
+					 pdata->ev_code_tap[i], press);
+	}
+}
+
+static void adxl34x_do_tap(struct adxl34x *ac,
+		struct adxl34x_platform_data *pdata, int status)
+{
+	adxl34x_send_key_events(ac, pdata, status, true);
+	input_sync(ac->input);
+	adxl34x_send_key_events(ac, pdata, status, false);
+}
+
+static irqreturn_t adxl34x_irq(int irq, void *handle)
+{
+	struct adxl34x *ac = handle;
+	struct adxl34x_platform_data *pdata = &ac->pdata;
+	int int_stat, tap_stat, samples, orient, orient_code;
+
+	/*
+	 * ACT_TAP_STATUS should be read before clearing the interrupt
+	 * Avoid reading ACT_TAP_STATUS in case TAP detection is disabled
+	 */
+
+	if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN))
+		tap_stat = AC_READ(ac, ACT_TAP_STATUS);
+	else
+		tap_stat = 0;
+
+	int_stat = AC_READ(ac, INT_SOURCE);
+
+	if (int_stat & FREE_FALL)
+		adxl34x_report_key_single(ac->input, pdata->ev_code_ff);
+
+	if (int_stat & OVERRUN)
+		dev_dbg(ac->dev, "OVERRUN\n");
+
+	if (int_stat & (SINGLE_TAP | DOUBLE_TAP)) {
+		adxl34x_do_tap(ac, pdata, tap_stat);
+
+		if (int_stat & DOUBLE_TAP)
+			adxl34x_do_tap(ac, pdata, tap_stat);
+	}
+
+	if (pdata->ev_code_act_inactivity) {
+		if (int_stat & ACTIVITY)
+			input_report_key(ac->input,
+					 pdata->ev_code_act_inactivity, 1);
+		if (int_stat & INACTIVITY)
+			input_report_key(ac->input,
+					 pdata->ev_code_act_inactivity, 0);
+	}
+
+	/*
+	 * ORIENTATION SENSING ADXL346 only
+	 */
+	if (pdata->orientation_enable) {
+		orient = AC_READ(ac, ORIENT);
+		if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_2D) &&
+		    (orient & ADXL346_2D_VALID)) {
+
+			orient_code = ADXL346_2D_ORIENT(orient);
+			/* Report orientation only when it changes */
+			if (ac->orient2d_saved != orient_code) {
+				ac->orient2d_saved = orient_code;
+				adxl34x_report_key_single(ac->input,
+					pdata->ev_codes_orient_2d[orient_code]);
+			}
+		}
+
+		if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_3D) &&
+		    (orient & ADXL346_3D_VALID)) {
+
+			orient_code = ADXL346_3D_ORIENT(orient) - 1;
+			/* Report orientation only when it changes */
+			if (ac->orient3d_saved != orient_code) {
+				ac->orient3d_saved = orient_code;
+				adxl34x_report_key_single(ac->input,
+					pdata->ev_codes_orient_3d[orient_code]);
+			}
+		}
+	}
+
+	if (int_stat & (DATA_READY | WATERMARK)) {
+
+		if (pdata->fifo_mode)
+			samples = ENTRIES(AC_READ(ac, FIFO_STATUS)) + 1;
+		else
+			samples = 1;
+
+		for (; samples > 0; samples--) {
+			adxl34x_service_ev_fifo(ac);
+			/*
+			 * To ensure that the FIFO has
+			 * completely popped, there must be at least 5 us between
+			 * the end of reading the data registers, signified by the
+			 * transition to register 0x38 from 0x37 or the CS pin
+			 * going high, and the start of new reads of the FIFO or
+			 * reading the FIFO_STATUS register. For SPI operation at
+			 * 1.5 MHz or lower, the register addressing portion of the
+			 * transmission is sufficient delay to ensure the FIFO has
+			 * completely popped. It is necessary for SPI operation
+			 * greater than 1.5 MHz to de-assert the CS pin to ensure a
+			 * total of 5 us, which is at most 3.4 us at 5 MHz
+			 * operation.
+			 */
+			if (ac->fifo_delay && (samples > 1))
+				udelay(3);
+		}
+	}
+
+	input_sync(ac->input);
+
+	return IRQ_HANDLED;
+}
+
+static void __adxl34x_disable(struct adxl34x *ac)
+{
+	/*
+	 * A '0' places the ADXL34x into standby mode
+	 * with minimum power consumption.
+	 */
+	AC_WRITE(ac, POWER_CTL, 0);
+}
+
+static void __adxl34x_enable(struct adxl34x *ac)
+{
+	AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
+}
+
+void adxl34x_suspend(struct adxl34x *ac)
+{
+	mutex_lock(&ac->mutex);
+
+	if (!ac->suspended && !ac->disabled && ac->opened)
+		__adxl34x_disable(ac);
+
+	ac->suspended = true;
+
+	mutex_unlock(&ac->mutex);
+}
+EXPORT_SYMBOL_GPL(adxl34x_suspend);
+
+void adxl34x_resume(struct adxl34x *ac)
+{
+	mutex_lock(&ac->mutex);
+
+	if (ac->suspended && !ac->disabled && ac->opened)
+		__adxl34x_enable(ac);
+
+	ac->suspended = false;
+
+	mutex_unlock(&ac->mutex);
+}
+EXPORT_SYMBOL_GPL(adxl34x_resume);
+
+static ssize_t adxl34x_disable_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ac->disabled);
+}
+
+static ssize_t adxl34x_disable_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	unsigned long val;
+	int error;
+
+	error = strict_strtoul(buf, 10, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ac->mutex);
+
+	if (!ac->suspended && ac->opened) {
+		if (val) {
+			if (!ac->disabled)
+				__adxl34x_disable(ac);
+		} else {
+			if (ac->disabled)
+				__adxl34x_enable(ac);
+		}
+	}
+
+	ac->disabled = !!val;
+
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(disable, 0664, adxl34x_disable_show, adxl34x_disable_store);
+
+static ssize_t adxl34x_calibrate_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	ssize_t count;
+
+	mutex_lock(&ac->mutex);
+	count = sprintf(buf, "%d,%d,%d\n",
+			ac->hwcal.x * 4 + ac->swcal.x,
+			ac->hwcal.y * 4 + ac->swcal.y,
+			ac->hwcal.z * 4 + ac->swcal.z);
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static ssize_t adxl34x_calibrate_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+
+	/*
+	 * Hardware offset calibration has a resolution of 15.6 mg/LSB.
+	 * We use HW calibration and handle the remaining bits in SW. (4mg/LSB)
+	 */
+
+	mutex_lock(&ac->mutex);
+	ac->hwcal.x -= (ac->saved.x / 4);
+	ac->swcal.x = ac->saved.x % 4;
+
+	ac->hwcal.y -= (ac->saved.y / 4);
+	ac->swcal.y = ac->saved.y % 4;
+
+	ac->hwcal.z -= (ac->saved.z / 4);
+	ac->swcal.z = ac->saved.z % 4;
+
+	AC_WRITE(ac, OFSX, (s8) ac->hwcal.x);
+	AC_WRITE(ac, OFSY, (s8) ac->hwcal.y);
+	AC_WRITE(ac, OFSZ, (s8) ac->hwcal.z);
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(calibrate, 0664,
+		   adxl34x_calibrate_show, adxl34x_calibrate_store);
+
+static ssize_t adxl34x_rate_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", RATE(ac->pdata.data_rate));
+}
+
+static ssize_t adxl34x_rate_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	unsigned long val;
+	int error;
+
+	error = strict_strtoul(buf, 10, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ac->mutex);
+
+	ac->pdata.data_rate = RATE(val);
+	AC_WRITE(ac, BW_RATE,
+		 ac->pdata.data_rate |
+			(ac->pdata.low_power_mode ? LOW_POWER : 0));
+
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(rate, 0664, adxl34x_rate_show, adxl34x_rate_store);
+
+static ssize_t adxl34x_autosleep_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n",
+		ac->pdata.power_mode & (PCTL_AUTO_SLEEP | PCTL_LINK) ? 1 : 0);
+}
+
+static ssize_t adxl34x_autosleep_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	unsigned long val;
+	int error;
+
+	error = strict_strtoul(buf, 10, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ac->mutex);
+
+	if (val)
+		ac->pdata.power_mode |= (PCTL_AUTO_SLEEP | PCTL_LINK);
+	else
+		ac->pdata.power_mode &= ~(PCTL_AUTO_SLEEP | PCTL_LINK);
+
+	if (!ac->disabled && !ac->suspended && ac->opened)
+		AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
+
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(autosleep, 0664,
+		   adxl34x_autosleep_show, adxl34x_autosleep_store);
+
+static ssize_t adxl34x_position_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	ssize_t count;
+
+	mutex_lock(&ac->mutex);
+	count = sprintf(buf, "(%d, %d, %d)\n",
+			ac->saved.x, ac->saved.y, ac->saved.z);
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(position, S_IRUGO, adxl34x_position_show, NULL);
+
+#ifdef ADXL_DEBUG
+static ssize_t adxl34x_write_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	unsigned long val;
+	int error;
+
+	/*
+	 * This allows basic ADXL register write access for debug purposes.
+	 */
+	error = strict_strtoul(buf, 16, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ac->mutex);
+	AC_WRITE(ac, val >> 8, val & 0xFF);
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(write, 0664, NULL, adxl34x_write_store);
+#endif
+
+static struct attribute *adxl34x_attributes[] = {
+	&dev_attr_disable.attr,
+	&dev_attr_calibrate.attr,
+	&dev_attr_rate.attr,
+	&dev_attr_autosleep.attr,
+	&dev_attr_position.attr,
+#ifdef ADXL_DEBUG
+	&dev_attr_write.attr,
+#endif
+	NULL
+};
+
+static const struct attribute_group adxl34x_attr_group = {
+	.attrs = adxl34x_attributes,
+};
+
+static int adxl34x_input_open(struct input_dev *input)
+{
+	struct adxl34x *ac = input_get_drvdata(input);
+
+	mutex_lock(&ac->mutex);
+
+	if (!ac->suspended && !ac->disabled)
+		__adxl34x_enable(ac);
+
+	ac->opened = true;
+
+	mutex_unlock(&ac->mutex);
+
+	return 0;
+}
+
+static void adxl34x_input_close(struct input_dev *input)
+{
+	struct adxl34x *ac = input_get_drvdata(input);
+
+	mutex_lock(&ac->mutex);
+
+	if (!ac->suspended && !ac->disabled)
+		__adxl34x_disable(ac);
+
+	ac->opened = false;
+
+	mutex_unlock(&ac->mutex);
+}
+
+struct adxl34x *adxl34x_probe(struct device *dev, int irq,
+			      bool fifo_delay_default,
+			      const struct adxl34x_bus_ops *bops)
+{
+	struct adxl34x *ac;
+	struct input_dev *input_dev;
+	const struct adxl34x_platform_data *pdata;
+	int err, range, i;
+	unsigned char revid;
+
+	if (!irq) {
+		dev_err(dev, "no IRQ?\n");
+		err = -ENODEV;
+		goto err_out;
+	}
+
+	ac = kzalloc(sizeof(*ac), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ac || !input_dev) {
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ac->fifo_delay = fifo_delay_default;
+
+	pdata = dev->platform_data;
+	if (!pdata) {
+		dev_dbg(dev,
+			"No platfrom data: Using default initialization\n");
+		pdata = &adxl34x_default_init;
+	}
+
+	ac->pdata = *pdata;
+	pdata = &ac->pdata;
+
+	ac->input = input_dev;
+	ac->disabled = true;
+	ac->dev = dev;
+	ac->irq = irq;
+	ac->bops = bops;
+
+	mutex_init(&ac->mutex);
+
+	input_dev->name = "ADXL34x accelerometer";
+	revid = ac->bops->read(dev, DEVID);
+
+	switch (revid) {
+	case ID_ADXL345:
+		ac->model = 345;
+		break;
+	case ID_ADXL346:
+		ac->model = 346;
+		break;
+	default:
+		dev_err(dev, "Failed to probe %s\n", input_dev->name);
+		err = -ENODEV;
+		goto err_free_mem;
+	}
+
+	snprintf(ac->phys, sizeof(ac->phys), "%s/input0", dev_name(dev));
+
+	input_dev->phys = ac->phys;
+	input_dev->dev.parent = dev;
+	input_dev->id.product = ac->model;
+	input_dev->id.bustype = bops->bustype;
+	input_dev->open = adxl34x_input_open;
+	input_dev->close = adxl34x_input_close;
+
+	input_set_drvdata(input_dev, ac);
+
+	__set_bit(ac->pdata.ev_type, input_dev->evbit);
+
+	if (ac->pdata.ev_type == EV_REL) {
+		__set_bit(REL_X, input_dev->relbit);
+		__set_bit(REL_Y, input_dev->relbit);
+		__set_bit(REL_Z, input_dev->relbit);
+	} else {
+		/* EV_ABS */
+		__set_bit(ABS_X, input_dev->absbit);
+		__set_bit(ABS_Y, input_dev->absbit);
+		__set_bit(ABS_Z, input_dev->absbit);
+
+		if (pdata->data_range & FULL_RES)
+			range = ADXL_FULLRES_MAX_VAL;	/* Signed 13-bit */
+		else
+			range = ADXL_FIXEDRES_MAX_VAL;	/* Signed 10-bit */
+
+		input_set_abs_params(input_dev, ABS_X, -range, range, 3, 3);
+		input_set_abs_params(input_dev, ABS_Y, -range, range, 3, 3);
+		input_set_abs_params(input_dev, ABS_Z, -range, range, 3, 3);
+	}
+
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(pdata->ev_code_tap[ADXL_X_AXIS], input_dev->keybit);
+	__set_bit(pdata->ev_code_tap[ADXL_Y_AXIS], input_dev->keybit);
+	__set_bit(pdata->ev_code_tap[ADXL_Z_AXIS], input_dev->keybit);
+
+	if (pdata->ev_code_ff) {
+		ac->int_mask = FREE_FALL;
+		__set_bit(pdata->ev_code_ff, input_dev->keybit);
+	}
+
+	if (pdata->ev_code_act_inactivity)
+		__set_bit(pdata->ev_code_act_inactivity, input_dev->keybit);
+
+	ac->int_mask |= ACTIVITY | INACTIVITY;
+
+	if (pdata->watermark) {
+		ac->int_mask |= WATERMARK;
+		if (!FIFO_MODE(pdata->fifo_mode))
+			ac->pdata.fifo_mode |= FIFO_STREAM;
+	} else {
+		ac->int_mask |= DATA_READY;
+	}
+
+	if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN))
+		ac->int_mask |= SINGLE_TAP | DOUBLE_TAP;
+
+	if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS)
+		ac->fifo_delay = false;
+
+	ac->bops->write(dev, POWER_CTL, 0);
+
+	err = request_threaded_irq(ac->irq, NULL, adxl34x_irq,
+				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				   dev_name(dev), ac);
+	if (err) {
+		dev_err(dev, "irq %d busy?\n", ac->irq);
+		goto err_free_mem;
+	}
+
+	err = sysfs_create_group(&dev->kobj, &adxl34x_attr_group);
+	if (err)
+		goto err_free_irq;
+
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_remove_attr;
+
+	AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
+	AC_WRITE(ac, OFSX, pdata->x_axis_offset);
+	ac->hwcal.x = pdata->x_axis_offset;
+	AC_WRITE(ac, OFSY, pdata->y_axis_offset);
+	ac->hwcal.y = pdata->y_axis_offset;
+	AC_WRITE(ac, OFSZ, pdata->z_axis_offset);
+	ac->hwcal.z = pdata->z_axis_offset;
+	AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
+	AC_WRITE(ac, DUR, pdata->tap_duration);
+	AC_WRITE(ac, LATENT, pdata->tap_latency);
+	AC_WRITE(ac, WINDOW, pdata->tap_window);
+	AC_WRITE(ac, THRESH_ACT, pdata->activity_threshold);
+	AC_WRITE(ac, THRESH_INACT, pdata->inactivity_threshold);
+	AC_WRITE(ac, TIME_INACT, pdata->inactivity_time);
+	AC_WRITE(ac, THRESH_FF, pdata->free_fall_threshold);
+	AC_WRITE(ac, TIME_FF, pdata->free_fall_time);
+	AC_WRITE(ac, TAP_AXES, pdata->tap_axis_control);
+	AC_WRITE(ac, ACT_INACT_CTL, pdata->act_axis_control);
+	AC_WRITE(ac, BW_RATE, RATE(ac->pdata.data_rate) |
+		 (pdata->low_power_mode ? LOW_POWER : 0));
+	AC_WRITE(ac, DATA_FORMAT, pdata->data_range);
+	AC_WRITE(ac, FIFO_CTL, FIFO_MODE(pdata->fifo_mode) |
+			SAMPLES(pdata->watermark));
+
+	if (pdata->use_int2) {
+		/* Map all INTs to INT2 */
+		AC_WRITE(ac, INT_MAP, ac->int_mask | OVERRUN);
+	} else {
+		/* Map all INTs to INT1 */
+		AC_WRITE(ac, INT_MAP, 0);
+	}
+
+	if (ac->model == 346 && ac->pdata.orientation_enable) {
+		AC_WRITE(ac, ORIENT_CONF,
+			ORIENT_DEADZONE(ac->pdata.deadzone_angle) |
+			ORIENT_DIVISOR(ac->pdata.divisor_length));
+
+		ac->orient2d_saved = 1234;
+		ac->orient3d_saved = 1234;
+
+		if (pdata->orientation_enable & ADXL_EN_ORIENTATION_3D)
+			for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_3d); i++)
+				__set_bit(pdata->ev_codes_orient_3d[i],
+					  input_dev->keybit);
+
+		if (pdata->orientation_enable & ADXL_EN_ORIENTATION_2D)
+			for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_2d); i++)
+				__set_bit(pdata->ev_codes_orient_2d[i],
+					  input_dev->keybit);
+	} else {
+		ac->pdata.orientation_enable = 0;
+	}
+
+	AC_WRITE(ac, INT_ENABLE, ac->int_mask | OVERRUN);
+
+	ac->pdata.power_mode &= (PCTL_AUTO_SLEEP | PCTL_LINK);
+
+	return ac;
+
+ err_remove_attr:
+	sysfs_remove_group(&dev->kobj, &adxl34x_attr_group);
+ err_free_irq:
+	free_irq(ac->irq, ac);
+ err_free_mem:
+	input_free_device(input_dev);
+	kfree(ac);
+ err_out:
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(adxl34x_probe);
+
+int adxl34x_remove(struct adxl34x *ac)
+{
+	sysfs_remove_group(&ac->dev->kobj, &adxl34x_attr_group);
+	free_irq(ac->irq, ac);
+	input_unregister_device(ac->input);
+	dev_dbg(ac->dev, "unregistered accelerometer\n");
+	kfree(ac);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(adxl34x_remove);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/adxl34x.h b/drivers/input/misc/adxl34x.h
new file mode 100644
index 0000000..bbbc80f
--- /dev/null
+++ b/drivers/input/misc/adxl34x.h
@@ -0,0 +1,30 @@
+/*
+ * ADXL345/346 Three-Axis Digital Accelerometers (I2C/SPI Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADXL34X_H_
+#define _ADXL34X_H_
+
+struct device;
+struct adxl34x;
+
+struct adxl34x_bus_ops {
+	u16 bustype;
+	int (*read)(struct device *, unsigned char);
+	int (*read_block)(struct device *, unsigned char, int, void *);
+	int (*write)(struct device *, unsigned char, unsigned char);
+};
+
+void adxl34x_suspend(struct adxl34x *ac);
+void adxl34x_resume(struct adxl34x *ac);
+struct adxl34x *adxl34x_probe(struct device *dev, int irq,
+			      bool fifo_delay_default,
+			      const struct adxl34x_bus_ops *bops);
+int adxl34x_remove(struct adxl34x *ac);
+
+#endif
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index dfaa9a0..601f737 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -21,6 +21,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -60,12 +62,11 @@
 		input_report_key(input_dev, atlas_keymap[code], key_down);
 		input_sync(input_dev);
 
-		status = 0;
+		status = AE_OK;
 	} else {
-		printk(KERN_WARNING "atlas: shrugged on unexpected function"
-			":function=%x,address=%lx,value=%x\n",
+		pr_warn("shrugged on unexpected function: function=%x,address=%lx,value=%x\n",
 			function, (unsigned long)address, (u32)*value);
-		status = -EINVAL;
+		status = AE_BAD_PARAMETER;
 	}
 
 	return status;
@@ -79,7 +80,7 @@
 
 	input_dev = input_allocate_device();
 	if (!input_dev) {
-		printk(KERN_ERR "atlas: unable to allocate input device\n");
+		pr_err("unable to allocate input device\n");
 		return -ENOMEM;
 	}
 
@@ -102,7 +103,7 @@
 
 	err = input_register_device(input_dev);
 	if (err) {
-		printk(KERN_ERR "atlas: couldn't register input device\n");
+		pr_err("couldn't register input device\n");
 		input_free_device(input_dev);
 		return err;
 	}
@@ -112,12 +113,12 @@
 				0x81, &acpi_atlas_button_handler,
 				&acpi_atlas_button_setup, device);
 	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR "Atlas: Error installing addr spc handler\n");
+		pr_err("error installing addr spc handler\n");
 		input_unregister_device(input_dev);
-		status = -EINVAL;
+		err = -EINVAL;
 	}
 
-	return status;
+	return err;
 }
 
 static int atlas_acpi_button_remove(struct acpi_device *device, int type)
@@ -126,14 +127,12 @@
 
 	status = acpi_remove_address_space_handler(device->handle,
 				0x81, &acpi_atlas_button_handler);
-	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR "Atlas: Error removing addr spc handler\n");
-		status = -EINVAL;
-	}
+	if (ACPI_FAILURE(status))
+		pr_err("error removing addr spc handler\n");
 
 	input_unregister_device(input_dev);
 
-	return status;
+	return 0;
 }
 
 static const struct acpi_device_id atlas_device_ids[] = {
@@ -145,6 +144,7 @@
 static struct acpi_driver atlas_acpi_driver = {
 	.name	= ACPI_ATLAS_NAME,
 	.class	= ACPI_ATLAS_CLASS,
+	.owner	= THIS_MODULE,
 	.ids	= atlas_device_ids,
 	.ops	= {
 		.add	= atlas_acpi_button_add,
@@ -154,18 +154,10 @@
 
 static int __init atlas_acpi_init(void)
 {
-	int result;
-
 	if (acpi_disabled)
 		return -ENODEV;
 
-	result = acpi_bus_register_driver(&atlas_acpi_driver);
-	if (result < 0) {
-		printk(KERN_ERR "Atlas ACPI: Unable to register driver\n");
-		return -ENODEV;
-	}
-
-	return 0;
+	return acpi_bus_register_driver(&atlas_acpi_driver);
 }
 
 static void __exit atlas_acpi_exit(void)
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
new file mode 100644
index 0000000..57c294f
--- /dev/null
+++ b/drivers/input/misc/pwm-beeper.c
@@ -0,0 +1,199 @@
+/*
+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ *  PWM beeper driver
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under  the terms of the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+struct pwm_beeper {
+	struct input_dev *input;
+	struct pwm_device *pwm;
+	unsigned long period;
+};
+
+#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
+
+static int pwm_beeper_event(struct input_dev *input,
+			    unsigned int type, unsigned int code, int value)
+{
+	int ret = 0;
+	struct pwm_beeper *beeper = input_get_drvdata(input);
+	unsigned long period;
+
+	if (type != EV_SND || value < 0)
+		return -EINVAL;
+
+	switch (code) {
+	case SND_BELL:
+		value = value ? 1000 : 0;
+		break;
+	case SND_TONE:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (value == 0) {
+		pwm_config(beeper->pwm, 0, 0);
+		pwm_disable(beeper->pwm);
+	} else {
+		period = HZ_TO_NANOSECONDS(value);
+		ret = pwm_config(beeper->pwm, period / 2, period);
+		if (ret)
+			return ret;
+		ret = pwm_enable(beeper->pwm);
+		if (ret)
+			return ret;
+		beeper->period = period;
+	}
+
+	return 0;
+}
+
+static int __devinit pwm_beeper_probe(struct platform_device *pdev)
+{
+	unsigned long pwm_id = (unsigned long)pdev->dev.platform_data;
+	struct pwm_beeper *beeper;
+	int error;
+
+	beeper = kzalloc(sizeof(*beeper), GFP_KERNEL);
+	if (!beeper)
+		return -ENOMEM;
+
+	beeper->pwm = pwm_request(pwm_id, "pwm beeper");
+
+	if (IS_ERR(beeper->pwm)) {
+		error = PTR_ERR(beeper->pwm);
+		dev_err(&pdev->dev, "Failed to request pwm device: %d\n", error);
+		goto err_free;
+	}
+
+	beeper->input = input_allocate_device();
+	if (!beeper->input) {
+		dev_err(&pdev->dev, "Failed to allocate input device\n");
+		error = -ENOMEM;
+		goto err_pwm_free;
+	}
+	beeper->input->dev.parent = &pdev->dev;
+
+	beeper->input->name = "pwm-beeper";
+	beeper->input->phys = "pwm/input0";
+	beeper->input->id.bustype = BUS_HOST;
+	beeper->input->id.vendor = 0x001f;
+	beeper->input->id.product = 0x0001;
+	beeper->input->id.version = 0x0100;
+
+	beeper->input->evbit[0] = BIT(EV_SND);
+	beeper->input->sndbit[0] = BIT(SND_TONE) | BIT(SND_BELL);
+
+	beeper->input->event = pwm_beeper_event;
+
+	input_set_drvdata(beeper->input, beeper);
+
+	error = input_register_device(beeper->input);
+	if (error) {
+		dev_err(&pdev->dev, "Failed to register input device: %d\n", error);
+		goto err_input_free;
+	}
+
+	platform_set_drvdata(pdev, beeper);
+
+	return 0;
+
+err_input_free:
+	input_free_device(beeper->input);
+err_pwm_free:
+	pwm_free(beeper->pwm);
+err_free:
+	kfree(beeper);
+
+	return error;
+}
+
+static int __devexit pwm_beeper_remove(struct platform_device *pdev)
+{
+	struct pwm_beeper *beeper = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	input_unregister_device(beeper->input);
+
+	pwm_disable(beeper->pwm);
+	pwm_free(beeper->pwm);
+
+	kfree(beeper);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int pwm_beeper_suspend(struct device *dev)
+{
+	struct pwm_beeper *beeper = dev_get_drvdata(dev);
+
+	if (beeper->period)
+		pwm_disable(beeper->pwm);
+
+	return 0;
+}
+
+static int pwm_beeper_resume(struct device *dev)
+{
+	struct pwm_beeper *beeper = dev_get_drvdata(dev);
+
+	if (beeper->period) {
+		pwm_config(beeper->pwm, beeper->period / 2, beeper->period);
+		pwm_enable(beeper->pwm);
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops,
+			 pwm_beeper_suspend, pwm_beeper_resume);
+
+#define PWM_BEEPER_PM_OPS (&pwm_beeper_pm_ops)
+#else
+#define PWM_BEEPER_PM_OPS NULL
+#endif
+
+static struct platform_driver pwm_beeper_driver = {
+	.probe	= pwm_beeper_probe,
+	.remove = __devexit_p(pwm_beeper_remove),
+	.driver = {
+		.name	= "pwm-beeper",
+		.owner	= THIS_MODULE,
+		.pm	= PWM_BEEPER_PM_OPS,
+	},
+};
+
+static int __init pwm_beeper_init(void)
+{
+	return platform_driver_register(&pwm_beeper_driver);
+}
+module_init(pwm_beeper_init);
+
+static void __exit pwm_beeper_exit(void)
+{
+	platform_driver_unregister(&pwm_beeper_driver);
+}
+module_exit(pwm_beeper_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("PWM beeper driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pwm-beeper");
diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c
index e9069b8..f16972b 100644
--- a/drivers/input/misc/twl4030-pwrbutton.c
+++ b/drivers/input/misc/twl4030-pwrbutton.c
@@ -52,7 +52,7 @@
 	return IRQ_HANDLED;
 }
 
-static int __devinit twl4030_pwrbutton_probe(struct platform_device *pdev)
+static int __init twl4030_pwrbutton_probe(struct platform_device *pdev)
 {
 	struct input_dev *pwr;
 	int irq = platform_get_irq(pdev, 0);
@@ -95,7 +95,7 @@
 	return err;
 }
 
-static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev)
+static int __exit twl4030_pwrbutton_remove(struct platform_device *pdev)
 {
 	struct input_dev *pwr = platform_get_drvdata(pdev);
 	int irq = platform_get_irq(pdev, 0);
@@ -106,9 +106,8 @@
 	return 0;
 }
 
-struct platform_driver twl4030_pwrbutton_driver = {
-	.probe		= twl4030_pwrbutton_probe,
-	.remove		= __devexit_p(twl4030_pwrbutton_remove),
+static struct platform_driver twl4030_pwrbutton_driver = {
+	.remove		= __exit_p(twl4030_pwrbutton_remove),
 	.driver		= {
 		.name	= "twl4030_pwrbutton",
 		.owner	= THIS_MODULE,
@@ -117,7 +116,8 @@
 
 static int __init twl4030_pwrbutton_init(void)
 {
-	return platform_driver_register(&twl4030_pwrbutton_driver);
+	return platform_driver_probe(&twl4030_pwrbutton_driver,
+			twl4030_pwrbutton_probe);
 }
 module_init(twl4030_pwrbutton_init);
 
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 4dac8b7..12501de 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -1347,7 +1347,7 @@
 
 	err = map_bios();
 	if (err)
-		return err;
+		goto err_free_keymap;
 
 	err = platform_driver_register(&wistron_driver);
 	if (err)
@@ -1371,6 +1371,8 @@
 	platform_driver_unregister(&wistron_driver);
  err_unmap_bios:
 	unmap_bios();
+ err_free_keymap:
+	kfree(keymap);
 
 	return err;
 }
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 6dedded..ea67c49 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -312,6 +312,8 @@
 	__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
 	__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
 	__set_bit(BTN_LEFT, input_dev->keybit);
+
+	input_set_events_per_packet(input_dev, 60);
 }
 
 /* report button data as logical button state */
@@ -580,23 +582,30 @@
  */
 static int bcm5974_start_traffic(struct bcm5974 *dev)
 {
-	if (bcm5974_wellspring_mode(dev, true)) {
+	int error;
+
+	error = bcm5974_wellspring_mode(dev, true);
+	if (error) {
 		dprintk(1, "bcm5974: mode switch failed\n");
-		goto error;
+		goto err_out;
 	}
 
-	if (usb_submit_urb(dev->bt_urb, GFP_KERNEL))
-		goto error;
+	error = usb_submit_urb(dev->bt_urb, GFP_KERNEL);
+	if (error)
+		goto err_reset_mode;
 
-	if (usb_submit_urb(dev->tp_urb, GFP_KERNEL))
+	error = usb_submit_urb(dev->tp_urb, GFP_KERNEL);
+	if (error)
 		goto err_kill_bt;
 
 	return 0;
 
 err_kill_bt:
 	usb_kill_urb(dev->bt_urb);
-error:
-	return -EIO;
+err_reset_mode:
+	bcm5974_wellspring_mode(dev, false);
+err_out:
+	return error;
 }
 
 static void bcm5974_pause_traffic(struct bcm5974 *dev)
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 705589d..8c32440 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -502,7 +502,9 @@
 	}
 	input_report_abs(dev, ABS_PRESSURE, hw.z);
 
-	input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
+	if (SYN_CAP_PALMDETECT(priv->capabilities))
+		input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
+
 	input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
 	input_report_key(dev, BTN_LEFT, hw.left);
 	input_report_key(dev, BTN_RIGHT, hw.right);
@@ -602,7 +604,9 @@
 	input_set_abs_params(dev, ABS_Y,
 			     YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0);
 	input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
-	__set_bit(ABS_TOOL_WIDTH, dev->absbit);
+
+	if (SYN_CAP_PALMDETECT(priv->capabilities))
+		input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
 
 	__set_bit(EV_KEY, dev->evbit);
 	__set_bit(BTN_TOUCH, dev->keybit);
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index f34b22b..d8f68f7 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -57,7 +57,6 @@
 };
 
 struct mousedev {
-	int exist;
 	int open;
 	int minor;
 	struct input_handle handle;
@@ -66,6 +65,7 @@
 	spinlock_t client_lock; /* protects client_list */
 	struct mutex mutex;
 	struct device dev;
+	bool exist;
 
 	struct list_head mixdev_node;
 	int mixdev_open;
@@ -765,10 +765,15 @@
 {
 	struct mousedev_client *client = file->private_data;
 	struct mousedev *mousedev = client->mousedev;
+	unsigned int mask;
 
 	poll_wait(file, &mousedev->wait, wait);
-	return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) |
-		(mousedev->exist ? 0 : (POLLHUP | POLLERR));
+
+	mask = mousedev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
+	if (client->ready || client->buffer)
+		mask |= POLLIN | POLLRDNORM;
+
+	return mask;
 }
 
 static const struct file_operations mousedev_fops = {
@@ -802,7 +807,7 @@
 static void mousedev_mark_dead(struct mousedev *mousedev)
 {
 	mutex_lock(&mousedev->mutex);
-	mousedev->exist = 0;
+	mousedev->exist = false;
 	mutex_unlock(&mousedev->mutex);
 }
 
@@ -862,7 +867,7 @@
 		dev_set_name(&mousedev->dev, "mouse%d", minor);
 
 	mousedev->minor = minor;
-	mousedev->exist = 1;
+	mousedev->exist = true;
 	mousedev->handle.dev = input_get_device(dev);
 	mousedev->handle.name = dev_name(&mousedev->dev);
 	mousedev->handle.handler = handler;
diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h
index 2906e1b..f708c75 100644
--- a/drivers/input/serio/i8042-ppcio.h
+++ b/drivers/input/serio/i8042-ppcio.h
@@ -52,81 +52,6 @@
 {
 }
 
-#elif defined(CONFIG_SPRUCE)
-
-#define I8042_KBD_IRQ 22
-#define I8042_AUX_IRQ 21
-
-#define I8042_KBD_PHYS_DESC "spruceps2/serio0"
-#define I8042_AUX_PHYS_DESC "spruceps2/serio1"
-#define I8042_MUX_PHYS_DESC "spruceps2/serio%d"
-
-#define I8042_COMMAND_REG 0xff810000
-#define I8042_DATA_REG 0xff810001
-
-static inline int i8042_read_data(void)
-{
-	unsigned long kbd_data;
-
-	__raw_writel(0x00000088, 0xff500008);
-	eieio();
-
-	__raw_writel(0x03000000, 0xff50000c);
-	eieio();
-
-	asm volatile("lis     7,0xff88        \n\
-		      lswi    6,7,0x8         \n\
-		      mr      %0,6"
-	              : "=r" (kbd_data) :: "6", "7");
-
-	__raw_writel(0x00000000, 0xff50000c);
-	eieio();
-
-	return (unsigned char)(kbd_data >> 24);
-}
-
-static inline int i8042_read_status(void)
-{
-	unsigned long kbd_status;
-
-	__raw_writel(0x00000088, 0xff500008);
-	eieio();
-
-	__raw_writel(0x03000000, 0xff50000c);
-	eieio();
-
-	asm volatile("lis     7,0xff88        \n\
-		      ori     7,7,0x8         \n\
-		      lswi    6,7,0x8         \n\
-		      mr      %0,6"
-		      : "=r" (kbd_status) :: "6", "7");
-
-	__raw_writel(0x00000000, 0xff50000c);
-	eieio();
-
-	return (unsigned char)(kbd_status >> 24);
-}
-
-static inline void i8042_write_data(int val)
-{
-	*((unsigned char *)0xff810000) = (char)val;
-}
-
-static inline void i8042_write_command(int val)
-{
-	*((unsigned char *)0xff810001) = (char)val;
-}
-
-static inline int i8042_platform_init(void)
-{
-	i8042_reset = 1;
-	return 0;
-}
-
-static inline void i8042_platform_exit(void)
-{
-}
-
 #else
 
 #include "i8042-io.h"
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 6440a8f..258b98b 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -861,9 +861,6 @@
 	unsigned char param;
 	int i = 0;
 
-	if (!i8042_reset)
-		return 0;
-
 	/*
 	 * We try this 5 times; on some really fragile systems this does not
 	 * take the first time...
@@ -1020,7 +1017,8 @@
  * Reset the controller if requested.
  */
 
-	i8042_controller_selftest();
+	if (i8042_reset)
+		i8042_controller_selftest();
 
 /*
  * Restore the original control register setting.
@@ -1094,23 +1092,11 @@
 #ifdef CONFIG_PM
 
 /*
- * Here we try to restore the original BIOS settings to avoid
- * upsetting it.
- */
-
-static int i8042_pm_reset(struct device *dev)
-{
-	i8042_controller_reset();
-
-	return 0;
-}
-
-/*
  * Here we try to reset everything back to a state we had
  * before suspending.
  */
 
-static int i8042_pm_restore(struct device *dev)
+static int i8042_controller_resume(bool force_reset)
 {
 	int error;
 
@@ -1118,9 +1104,11 @@
 	if (error)
 		return error;
 
-	error = i8042_controller_selftest();
-	if (error)
-		return error;
+	if (i8042_reset || force_reset) {
+		error = i8042_controller_selftest();
+		if (error)
+			return error;
+	}
 
 /*
  * Restore original CTR value and disable all ports
@@ -1162,6 +1150,28 @@
 	return 0;
 }
 
+/*
+ * Here we try to restore the original BIOS settings to avoid
+ * upsetting it.
+ */
+
+static int i8042_pm_reset(struct device *dev)
+{
+	i8042_controller_reset();
+
+	return 0;
+}
+
+static int i8042_pm_resume(struct device *dev)
+{
+	/*
+	 * On resume from S2R we always try to reset the controller
+	 * to bring it in a sane state. (In case of S2D we expect
+	 * BIOS to reset the controller for us.)
+	 */
+	return i8042_controller_resume(true);
+}
+
 static int i8042_pm_thaw(struct device *dev)
 {
 	i8042_interrupt(0, NULL);
@@ -1169,9 +1179,14 @@
 	return 0;
 }
 
+static int i8042_pm_restore(struct device *dev)
+{
+	return i8042_controller_resume(false);
+}
+
 static const struct dev_pm_ops i8042_pm_ops = {
 	.suspend	= i8042_pm_reset,
-	.resume		= i8042_pm_restore,
+	.resume		= i8042_pm_resume,
 	.thaw		= i8042_pm_thaw,
 	.poweroff	= i8042_pm_reset,
 	.restore	= i8042_pm_restore,
@@ -1389,9 +1404,11 @@
 
 	i8042_platform_device = dev;
 
-	error = i8042_controller_selftest();
-	if (error)
-		return error;
+	if (i8042_reset) {
+		error = i8042_controller_selftest();
+		if (error)
+			return error;
+	}
 
 	error = i8042_controller_init();
 	if (error)
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 415f630..ce0b460 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -158,6 +158,39 @@
 	return 1;
 }
 
+static int wacom_dtu_irq(struct wacom_wac *wacom)
+{
+	struct wacom_features *features = &wacom->features;
+	char *data = wacom->data;
+	struct input_dev *input = wacom->input;
+	int prox = data[1] & 0x20, pressure;
+
+	dbg("wacom_dtu_irq: received report #%d", data[0]);
+
+	if (prox) {
+		/* Going into proximity select tool */
+		wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+		if (wacom->tool[0] == BTN_TOOL_PEN)
+			wacom->id[0] = STYLUS_DEVICE_ID;
+		else
+			wacom->id[0] = ERASER_DEVICE_ID;
+	}
+	input_report_key(input, BTN_STYLUS, data[1] & 0x02);
+	input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
+	input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
+	input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
+	pressure = ((data[7] & 0x01) << 8) | data[6];
+	if (pressure < 0)
+		pressure = features->pressure_max + pressure + 1;
+	input_report_abs(input, ABS_PRESSURE, pressure);
+	input_report_key(input, BTN_TOUCH, data[1] & 0x05);
+	if (!prox) /* out-prox */
+		wacom->id[0] = 0;
+	input_report_key(input, wacom->tool[0], prox);
+	input_report_abs(input, ABS_MISC, wacom->id[0]);
+	return 1;
+}
+
 static int wacom_graphire_irq(struct wacom_wac *wacom)
 {
 	struct wacom_features *features = &wacom->features;
@@ -845,6 +878,10 @@
 		sync = wacom_ptu_irq(wacom_wac);
 		break;
 
+	case DTU:
+		sync = wacom_dtu_irq(wacom_wac);
+		break;
+
 	case INTUOS:
 	case INTUOS3S:
 	case INTUOS3:
@@ -1030,6 +1067,7 @@
 
 	case PL:
 	case PTU:
+	case DTU:
 		__set_bit(BTN_TOOL_PEN, input_dev->keybit);
 		__set_bit(BTN_STYLUS, input_dev->keybit);
 		__set_bit(BTN_STYLUS2, input_dev->keybit);
@@ -1155,6 +1193,10 @@
 	{ "Wacom Cintiq 12WX",    WACOM_PKGLEN_INTUOS,    53020, 33440, 1023, 63, WACOM_BEE };
 static const struct wacom_features wacom_features_0xC7 =
 	{ "Wacom DTU1931",        WACOM_PKGLEN_GRAPHIRE,  37832, 30305,  511,  0, PL };
+static const struct wacom_features wacom_features_0xCE =
+	{ "Wacom DTU2231",        WACOM_PKGLEN_GRAPHIRE,  47864, 27011,  511,  0, DTU };
+static const struct wacom_features wacom_features_0xF0 =
+	{ "Wacom DTU1631",        WACOM_PKGLEN_GRAPHIRE,  34623, 19553,  511,  0, DTU };
 static const struct wacom_features wacom_features_0xCC =
 	{ "Wacom Cintiq 21UX2",   WACOM_PKGLEN_INTUOS,    87200, 65600, 2047, 63, WACOM_21UX2 };
 static const struct wacom_features wacom_features_0x90 =
@@ -1234,6 +1276,8 @@
 	{ USB_DEVICE_WACOM(0xC5) },
 	{ USB_DEVICE_WACOM(0xC6) },
 	{ USB_DEVICE_WACOM(0xC7) },
+	{ USB_DEVICE_WACOM(0xCE) },
+	{ USB_DEVICE_WACOM(0xF0) },
 	{ USB_DEVICE_WACOM(0xCC) },
 	{ USB_DEVICE_WACOM(0x90) },
 	{ USB_DEVICE_WACOM(0x93) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 854b920..99e1a54 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -43,6 +43,7 @@
 	WACOM_G4,
 	PTU,
 	PL,
+	DTU,
 	INTUOS,
 	INTUOS3S,
 	INTUOS3,
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 3b9d5e2..61f3518 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -55,37 +55,36 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad7877.
 
-config TOUCHSCREEN_AD7879_I2C
-	tristate "AD7879 based touchscreens: AD7879-1 I2C Interface"
-	depends on I2C
-	select TOUCHSCREEN_AD7879
+config TOUCHSCREEN_AD7879
+	tristate "Analog Devices AD7879-1/AD7889-1 touchscreen interface"
 	help
-	  Say Y here if you have a touchscreen interface using the
-	  AD7879-1/AD7889-1 controller, and your board-specific
-	  initialization code includes that in its table of I2C devices.
+	  Say Y here if you want to support a touchscreen interface using
+	  the AD7879-1/AD7889-1 controller.
 
-	  If unsure, say N (but it's safe to say "Y").
+	  You should select a bus connection too.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad7879.
 
+config TOUCHSCREEN_AD7879_I2C
+	tristate "support I2C bus connection"
+	depends on TOUCHSCREEN_AD7879 && I2C
+	help
+	  Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad7879-i2c.
+
 config TOUCHSCREEN_AD7879_SPI
-	tristate "AD7879 based touchscreens: AD7879 SPI Interface"
-	depends on SPI_MASTER && TOUCHSCREEN_AD7879_I2C = n
-	select TOUCHSCREEN_AD7879
+	tristate "support SPI bus connection"
+	depends on TOUCHSCREEN_AD7879 && SPI_MASTER
 	help
-	  Say Y here if you have a touchscreen interface using the
-	  AD7879/AD7889 controller, and your board-specific initialization
-	  code includes that in its table of SPI devices.
+	  Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus.
 
 	  If unsure, say N (but it's safe to say "Y").
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called ad7879.
-
-config TOUCHSCREEN_AD7879
-	tristate
-	default n
+	  module will be called ad7879-spi.
 
 config TOUCHSCREEN_BITSY
 	tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
@@ -99,6 +98,20 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called h3600_ts_input.
 
+config TOUCHSCREEN_CY8CTMG110
+	tristate "cy8ctmg110 touchscreen"
+	depends on I2C
+	depends on GPIOLIB
+
+	help
+	  Say Y here if you have a cy8ctmg110 capacitive touchscreen on
+	  an AAVA device.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cy8ctmg110_ts.
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
@@ -292,6 +305,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called penmount.
 
+config TOUCHSCREEN_QT602240
+	tristate "QT602240 I2C Touchscreen"
+	depends on I2C
+	help
+	  Say Y here if you have the AT42QT602240/ATMXT224 I2C touchscreen
+	  connected to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called qt602240_ts.
+
 config TOUCHSCREEN_MIGOR
 	tristate "Renesas MIGO-R touchscreen"
 	depends on SH_MIGOR && I2C
@@ -540,9 +565,9 @@
 	bool "Zytronic controller" if EMBEDDED
 	depends on TOUCHSCREEN_USB_COMPOSITE
 
-config TOUCHSCREEN_USB_ETT_TC5UH
+config TOUCHSCREEN_USB_ETT_TC45USB
 	default y
-	bool "ET&T TC5UH touchscreen controler support" if EMBEDDED
+	bool "ET&T USB series TC4UM/TC5UH touchscreen controler support" if EMBEDDED
 	depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_NEXIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 497964a..bd6f30b4 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -9,9 +9,13 @@
 obj-$(CONFIG_TOUCHSCREEN_88PM860X)	+= 88pm860x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_AD7877)	+= ad7877.o
 obj-$(CONFIG_TOUCHSCREEN_AD7879)	+= ad7879.o
+obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C)	+= ad7879-i2c.o
+obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI)	+= ad7879-spi.o
 obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
+obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)		+= gunze.o
@@ -30,6 +34,7 @@
 obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE)	+= usbtouchscreen.o
 obj-$(CONFIG_TOUCHSCREEN_PCAP)		+= pcap_ts.o
 obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)	+= penmount.o
+obj-$(CONFIG_TOUCHSCREEN_QT602240)	+= qt602240_ts.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)	+= s3c2410_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)	+= touchit213.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)	+= touchright.o
@@ -38,7 +43,6 @@
 obj-$(CONFIG_TOUCHSCREEN_UCB1400)	+= ucb1400_ts.o
 obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001)	+= wacom_w8001.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX)	+= wm97xx-ts.o
-obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705)	+= wm9705.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712)	+= wm9712.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713)	+= wm9713.o
diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c
new file mode 100644
index 0000000..d82a38e
--- /dev/null
+++ b/drivers/input/touchscreen/ad7879-i2c.c
@@ -0,0 +1,143 @@
+/*
+ * AD7879-1/AD7889-1 touchscreen (I2C bus)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_I2C */
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include "ad7879.h"
+
+#define AD7879_DEVID		0x79	/* AD7879-1/AD7889-1 */
+
+#ifdef CONFIG_PM
+static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+	struct ad7879 *ts = i2c_get_clientdata(client);
+
+	ad7879_suspend(ts);
+
+	return 0;
+}
+
+static int ad7879_i2c_resume(struct i2c_client *client)
+{
+	struct ad7879 *ts = i2c_get_clientdata(client);
+
+	ad7879_resume(ts);
+
+	return 0;
+}
+#else
+# define ad7879_i2c_suspend NULL
+# define ad7879_i2c_resume  NULL
+#endif
+
+/* All registers are word-sized.
+ * AD7879 uses a high-byte first convention.
+ */
+static int ad7879_i2c_read(struct device *dev, u8 reg)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return swab16(i2c_smbus_read_word_data(client, reg));
+}
+
+static int ad7879_i2c_multi_read(struct device *dev,
+				 u8 first_reg, u8 count, u16 *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	u8 idx;
+
+	i2c_smbus_read_i2c_block_data(client, first_reg, count * 2, (u8 *)buf);
+
+	for (idx = 0; idx < count; ++idx)
+		buf[idx] = swab16(buf[idx]);
+
+	return 0;
+}
+
+static int ad7879_i2c_write(struct device *dev, u8 reg, u16 val)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return i2c_smbus_write_word_data(client, reg, swab16(val));
+}
+
+static const struct ad7879_bus_ops ad7879_i2c_bus_ops = {
+	.bustype	= BUS_I2C,
+	.read		= ad7879_i2c_read,
+	.multi_read	= ad7879_i2c_multi_read,
+	.write		= ad7879_i2c_write,
+};
+
+static int __devinit ad7879_i2c_probe(struct i2c_client *client,
+				      const struct i2c_device_id *id)
+{
+	struct ad7879 *ts;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_err(&client->dev, "SMBUS Word Data not Supported\n");
+		return -EIO;
+	}
+
+	ts = ad7879_probe(&client->dev, AD7879_DEVID, client->irq,
+			  &ad7879_i2c_bus_ops);
+	if (IS_ERR(ts))
+		return PTR_ERR(ts);
+
+	i2c_set_clientdata(client, ts);
+
+	return 0;
+}
+
+static int __devexit ad7879_i2c_remove(struct i2c_client *client)
+{
+	struct ad7879 *ts = i2c_get_clientdata(client);
+
+	ad7879_remove(ts);
+
+	return 0;
+}
+
+static const struct i2c_device_id ad7879_id[] = {
+	{ "ad7879", 0 },
+	{ "ad7889", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ad7879_id);
+
+static struct i2c_driver ad7879_i2c_driver = {
+	.driver = {
+		.name	= "ad7879",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad7879_i2c_probe,
+	.remove		= __devexit_p(ad7879_i2c_remove),
+	.suspend	= ad7879_i2c_suspend,
+	.resume		= ad7879_i2c_resume,
+	.id_table	= ad7879_id,
+};
+
+static int __init ad7879_i2c_init(void)
+{
+	return i2c_add_driver(&ad7879_i2c_driver);
+}
+module_init(ad7879_i2c_init);
+
+static void __exit ad7879_i2c_exit(void)
+{
+	i2c_del_driver(&ad7879_i2c_driver);
+}
+module_exit(ad7879_i2c_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("AD7879(-1) touchscreen I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("i2c:ad7879");
diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c
new file mode 100644
index 0000000..59c6e68
--- /dev/null
+++ b/drivers/input/touchscreen/ad7879-spi.c
@@ -0,0 +1,198 @@
+/*
+ * AD7879/AD7889 touchscreen (SPI bus)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_SPI */
+#include <linux/spi/spi.h>
+
+#include "ad7879.h"
+
+#define AD7879_DEVID		0x7A	/* AD7879/AD7889 */
+
+#define MAX_SPI_FREQ_HZ      5000000
+#define AD7879_CMD_MAGIC     0xE000
+#define AD7879_CMD_READ      (1 << 10)
+#define AD7879_CMD(reg)      (AD7879_CMD_MAGIC | ((reg) & 0xF))
+#define AD7879_WRITECMD(reg) (AD7879_CMD(reg))
+#define AD7879_READCMD(reg)  (AD7879_CMD(reg) | AD7879_CMD_READ)
+
+#ifdef CONFIG_PM
+static int ad7879_spi_suspend(struct spi_device *spi, pm_message_t message)
+{
+	struct ad7879 *ts = spi_get_drvdata(spi);
+
+	ad7879_suspend(ts);
+
+	return 0;
+}
+
+static int ad7879_spi_resume(struct spi_device *spi)
+{
+	struct ad7879 *ts = spi_get_drvdata(spi);
+
+	ad7879_resume(ts);
+
+	return 0;
+}
+#else
+# define ad7879_spi_suspend NULL
+# define ad7879_spi_resume  NULL
+#endif
+
+/*
+ * ad7879_read/write are only used for initial setup and for sysfs controls.
+ * The main traffic is done in ad7879_collect().
+ */
+
+static int ad7879_spi_xfer(struct spi_device *spi,
+			   u16 cmd, u8 count, u16 *tx_buf, u16 *rx_buf)
+{
+	struct spi_message msg;
+	struct spi_transfer *xfers;
+	void *spi_data;
+	u16 *command;
+	u16 *_rx_buf = _rx_buf; /* shut gcc up */
+	u8 idx;
+	int ret;
+
+	xfers = spi_data = kzalloc(sizeof(*xfers) * (count + 2), GFP_KERNEL);
+	if (!spi_data)
+		return -ENOMEM;
+
+	spi_message_init(&msg);
+
+	command = spi_data;
+	command[0] = cmd;
+	if (count == 1) {
+		/* ad7879_spi_{read,write} gave us buf on stack */
+		command[1] = *tx_buf;
+		tx_buf = &command[1];
+		_rx_buf = rx_buf;
+		rx_buf = &command[2];
+	}
+
+	++xfers;
+	xfers[0].tx_buf = command;
+	xfers[0].len = 2;
+	spi_message_add_tail(&xfers[0], &msg);
+	++xfers;
+
+	for (idx = 0; idx < count; ++idx) {
+		if (rx_buf)
+			xfers[idx].rx_buf = &rx_buf[idx];
+		if (tx_buf)
+			xfers[idx].tx_buf = &tx_buf[idx];
+		xfers[idx].len = 2;
+		spi_message_add_tail(&xfers[idx], &msg);
+	}
+
+	ret = spi_sync(spi, &msg);
+
+	if (count == 1)
+		_rx_buf[0] = command[2];
+
+	kfree(spi_data);
+
+	return ret;
+}
+
+static int ad7879_spi_multi_read(struct device *dev,
+				 u8 first_reg, u8 count, u16 *buf)
+{
+	struct spi_device *spi = to_spi_device(dev);
+
+	return ad7879_spi_xfer(spi, AD7879_READCMD(first_reg), count, NULL, buf);
+}
+
+static int ad7879_spi_read(struct device *dev, u8 reg)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	u16 ret, dummy;
+
+	return ad7879_spi_xfer(spi, AD7879_READCMD(reg), 1, &dummy, &ret) ? : ret;
+}
+
+static int ad7879_spi_write(struct device *dev, u8 reg, u16 val)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	u16 dummy;
+
+	return ad7879_spi_xfer(spi, AD7879_WRITECMD(reg), 1, &val, &dummy);
+}
+
+static const struct ad7879_bus_ops ad7879_spi_bus_ops = {
+	.bustype	= BUS_SPI,
+	.read		= ad7879_spi_read,
+	.multi_read	= ad7879_spi_multi_read,
+	.write		= ad7879_spi_write,
+};
+
+static int __devinit ad7879_spi_probe(struct spi_device *spi)
+{
+	struct ad7879 *ts;
+	int err;
+
+	/* don't exceed max specified SPI CLK frequency */
+	if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
+		dev_err(&spi->dev, "SPI CLK %d Hz?\n", spi->max_speed_hz);
+		return -EINVAL;
+	}
+
+	spi->bits_per_word = 16;
+	err = spi_setup(spi);
+	if (err) {
+	        dev_dbg(&spi->dev, "spi master doesn't support 16 bits/word\n");
+	        return err;
+	}
+
+	ts = ad7879_probe(&spi->dev, AD7879_DEVID, spi->irq, &ad7879_spi_bus_ops);
+	if (IS_ERR(ts))
+		return PTR_ERR(ts);
+
+	spi_set_drvdata(spi, ts);
+
+	return 0;
+}
+
+static int __devexit ad7879_spi_remove(struct spi_device *spi)
+{
+	struct ad7879 *ts = spi_get_drvdata(spi);
+
+	ad7879_remove(ts);
+	spi_set_drvdata(spi, NULL);
+
+	return 0;
+}
+
+static struct spi_driver ad7879_spi_driver = {
+	.driver = {
+		.name	= "ad7879",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad7879_spi_probe,
+	.remove		= __devexit_p(ad7879_spi_remove),
+	.suspend	= ad7879_spi_suspend,
+	.resume		= ad7879_spi_resume,
+};
+
+static int __init ad7879_spi_init(void)
+{
+	return spi_register_driver(&ad7879_spi_driver);
+}
+module_init(ad7879_spi_init);
+
+static void __exit ad7879_spi_exit(void)
+{
+	spi_unregister_driver(&ad7879_spi_driver);
+}
+module_exit(ad7879_spi_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("AD7879(-1) touchscreen SPI bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:ad7879");
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index 4b32fb4..ba6f0bd 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -1,25 +1,9 @@
 /*
- * Copyright (C) 2008-2009 Michael Hennerich, Analog Devices Inc.
+ * AD7879/AD7889 based touchscreen and GPIO driver
  *
- * Description:	AD7879/AD7889 based touchscreen, and GPIO driver
- *		(I2C/SPI Interface)
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
  *
- * Bugs:        Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * Licensed under the GPL-2 or later.
  *
  * History:
  * Copyright (c) 2005 David Brownell
@@ -44,12 +28,12 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 #include <linux/spi/spi.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 
 #include <linux/spi/ad7879.h>
+#include "ad7879.h"
 
 #define AD7879_REG_ZEROS		0
 #define AD7879_REG_CTRL1		1
@@ -120,30 +104,19 @@
 #define	MAX_12BIT			((1<<12)-1)
 #define	TS_PEN_UP_TIMEOUT		msecs_to_jiffies(50)
 
-#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
-#define AD7879_DEVID		0x7A
-typedef struct spi_device	bus_device;
-#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
-#define AD7879_DEVID		0x79
-typedef struct i2c_client	bus_device;
-#endif
-
 struct ad7879 {
-	bus_device		*bus;
+	const struct ad7879_bus_ops *bops;
+
+	struct device		*dev;
 	struct input_dev	*input;
-	struct work_struct	work;
 	struct timer_list	timer;
 #ifdef CONFIG_GPIOLIB
 	struct gpio_chip	gc;
-#endif
 	struct mutex		mutex;
-	unsigned		disabled:1;	/* P: mutex */
-
-#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
-	struct spi_message	msg;
-	struct spi_transfer	xfer[AD7879_NR_SENSE + 1];
-	u16			cmd;
 #endif
+	unsigned int		irq;
+	bool			disabled;	/* P: input->mutex */
+	bool			suspended;	/* P: input->mutex */
 	u16			conversion_data[AD7879_NR_SENSE];
 	char			phys[32];
 	u8			first_conversion_delay;
@@ -158,11 +131,22 @@
 	u16			cmd_crtl3;
 };
 
-static int ad7879_read(bus_device *, u8);
-static int ad7879_write(bus_device *, u8, u16);
-static void ad7879_collect(struct ad7879 *);
+static int ad7879_read(struct ad7879 *ts, u8 reg)
+{
+	return ts->bops->read(ts->dev, reg);
+}
 
-static void ad7879_report(struct ad7879 *ts)
+static int ad7879_multi_read(struct ad7879 *ts, u8 first_reg, u8 count, u16 *buf)
+{
+	return ts->bops->multi_read(ts->dev, first_reg, count, buf);
+}
+
+static int ad7879_write(struct ad7879 *ts, u8 reg, u16 val)
+{
+	return ts->bops->write(ts->dev, reg, val);
+}
+
+static int ad7879_report(struct ad7879 *ts)
 {
 	struct input_dev *input_dev = ts->input;
 	unsigned Rt;
@@ -175,12 +159,14 @@
 
 	/*
 	 * The samples processed here are already preprocessed by the AD7879.
-	 * The preprocessing function consists of a median and an averaging filter.
-	 * The combination of these two techniques provides a robust solution,
-	 * discarding the spurious noise in the signal and keeping only the data of interest.
-	 * The size of both filters is programmable. (dev.platform_data, see linux/spi/ad7879.h)
-	 * Other user-programmable conversion controls include variable acquisition time,
-	 * and first conversion delay. Up to 16 averages can be taken per conversion.
+	 * The preprocessing function consists of a median and an averaging
+	 * filter.  The combination of these two techniques provides a robust
+	 * solution, discarding the spurious noise in the signal and keeping
+	 * only the data of interest.  The size of both filters is
+	 * programmable. (dev.platform_data, see linux/spi/ad7879.h) Other
+	 * user-programmable conversion controls include variable acquisition
+	 * time, and first conversion delay. Up to 16 averages can be taken
+	 * per conversion.
 	 */
 
 	if (likely(x && z1)) {
@@ -189,21 +175,17 @@
 		Rt /= z1;
 		Rt = (Rt + 2047) >> 12;
 
+		if (!timer_pending(&ts->timer))
+			input_report_key(input_dev, BTN_TOUCH, 1);
+
 		input_report_abs(input_dev, ABS_X, x);
 		input_report_abs(input_dev, ABS_Y, y);
 		input_report_abs(input_dev, ABS_PRESSURE, Rt);
 		input_sync(input_dev);
+		return 0;
 	}
-}
 
-static void ad7879_work(struct work_struct *work)
-{
-	struct ad7879 *ts = container_of(work, struct ad7879, work);
-
-	/* use keventd context to read the result registers */
-	ad7879_collect(ts);
-	ad7879_report(ts);
-	mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
+	return -EINVAL;
 }
 
 static void ad7879_ts_event_release(struct ad7879 *ts)
@@ -211,6 +193,7 @@
 	struct input_dev *input_dev = ts->input;
 
 	input_report_abs(input_dev, ABS_PRESSURE, 0);
+	input_report_key(input_dev, BTN_TOUCH, 0);
 	input_sync(input_dev);
 }
 
@@ -225,56 +208,98 @@
 {
 	struct ad7879 *ts = handle;
 
-	/* The repeated conversion sequencer controlled by TMR kicked off too fast.
-	 * We ignore the last and process the sample sequence currently in the queue.
-	 * It can't be older than 9.4ms
-	 */
+	ad7879_multi_read(ts, AD7879_REG_XPLUS, AD7879_NR_SENSE, ts->conversion_data);
 
-	if (!work_pending(&ts->work))
-		schedule_work(&ts->work);
+	if (!ad7879_report(ts))
+		mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
 
 	return IRQ_HANDLED;
 }
 
-static void ad7879_setup(struct ad7879 *ts)
+static void __ad7879_enable(struct ad7879 *ts)
 {
-	ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
-	ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
-	ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
+	ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	ad7879_write(ts, AD7879_REG_CTRL3, ts->cmd_crtl3);
+	ad7879_write(ts, AD7879_REG_CTRL1, ts->cmd_crtl1);
+
+	enable_irq(ts->irq);
 }
 
-static void ad7879_disable(struct ad7879 *ts)
+static void __ad7879_disable(struct ad7879 *ts)
 {
-	mutex_lock(&ts->mutex);
+	disable_irq(ts->irq);
 
-	if (!ts->disabled) {
+	if (del_timer_sync(&ts->timer))
+		ad7879_ts_event_release(ts);
 
-		ts->disabled = 1;
-		disable_irq(ts->bus->irq);
-
-		cancel_work_sync(&ts->work);
-
-		if (del_timer_sync(&ts->timer))
-			ad7879_ts_event_release(ts);
-
-		ad7879_write(ts->bus, AD7879_REG_CTRL2,
-			     AD7879_PM(AD7879_PM_SHUTDOWN));
-	}
-
-	mutex_unlock(&ts->mutex);
+	ad7879_write(ts, AD7879_REG_CTRL2, AD7879_PM(AD7879_PM_SHUTDOWN));
 }
 
-static void ad7879_enable(struct ad7879 *ts)
-{
-	mutex_lock(&ts->mutex);
 
-	if (ts->disabled) {
-		ad7879_setup(ts);
-		ts->disabled = 0;
-		enable_irq(ts->bus->irq);
+static int ad7879_open(struct input_dev *input)
+{
+	struct ad7879 *ts = input_get_drvdata(input);
+
+	/* protected by input->mutex */
+	if (!ts->disabled && !ts->suspended)
+		__ad7879_enable(ts);
+
+	return 0;
+}
+
+static void ad7879_close(struct input_dev* input)
+{
+	struct ad7879 *ts = input_get_drvdata(input);
+
+	/* protected by input->mutex */
+	if (!ts->disabled && !ts->suspended)
+		__ad7879_disable(ts);
+}
+
+void ad7879_suspend(struct ad7879 *ts)
+{
+	mutex_lock(&ts->input->mutex);
+
+	if (!ts->suspended && !ts->disabled && ts->input->users)
+		__ad7879_disable(ts);
+
+	ts->suspended = true;
+
+	mutex_unlock(&ts->input->mutex);
+}
+EXPORT_SYMBOL(ad7879_suspend);
+
+void ad7879_resume(struct ad7879 *ts)
+{
+	mutex_lock(&ts->input->mutex);
+
+	if (ts->suspended && !ts->disabled && ts->input->users)
+		__ad7879_enable(ts);
+
+	ts->suspended = false;
+
+	mutex_unlock(&ts->input->mutex);
+}
+EXPORT_SYMBOL(ad7879_resume);
+
+static void ad7879_toggle(struct ad7879 *ts, bool disable)
+{
+	mutex_lock(&ts->input->mutex);
+
+	if (!ts->suspended && ts->input->users != 0) {
+
+		if (disable) {
+			if (ts->disabled)
+				__ad7879_enable(ts);
+		} else {
+			if (!ts->disabled)
+				__ad7879_disable(ts);
+		}
 	}
 
-	mutex_unlock(&ts->mutex);
+	ts->disabled = disable;
+
+	mutex_unlock(&ts->input->mutex);
 }
 
 static ssize_t ad7879_disable_show(struct device *dev,
@@ -297,10 +322,7 @@
 	if (error)
 		return error;
 
-	if (val)
-		ad7879_disable(ts);
-	else
-		ad7879_enable(ts);
+	ad7879_toggle(ts, val);
 
 	return count;
 }
@@ -325,7 +347,7 @@
 
 	mutex_lock(&ts->mutex);
 	ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIODIR | AD7879_GPIOPOL;
-	err = ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
 	mutex_unlock(&ts->mutex);
 
 	return err;
@@ -345,7 +367,7 @@
 	else
 		ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
 
-	err = ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
 	mutex_unlock(&ts->mutex);
 
 	return err;
@@ -357,7 +379,7 @@
 	u16 val;
 
 	mutex_lock(&ts->mutex);
-	val = ad7879_read(ts->bus, AD7879_REG_CTRL2);
+	val = ad7879_read(ts, AD7879_REG_CTRL2);
 	mutex_unlock(&ts->mutex);
 
 	return !!(val & AD7879_GPIO_DATA);
@@ -374,16 +396,17 @@
 	else
 		ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
 
-	ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
 	mutex_unlock(&ts->mutex);
 }
 
-static int __devinit ad7879_gpio_add(struct device *dev)
+static int ad7879_gpio_add(struct ad7879 *ts,
+			   const struct ad7879_platform_data *pdata)
 {
-	struct ad7879 *ts = dev_get_drvdata(dev);
-	struct ad7879_platform_data *pdata = dev->platform_data;
 	int ret = 0;
 
+	mutex_init(&ts->mutex);
+
 	if (pdata->gpio_export) {
 		ts->gc.direction_input = ad7879_gpio_direction_input;
 		ts->gc.direction_output = ad7879_gpio_direction_output;
@@ -394,72 +417,75 @@
 		ts->gc.ngpio = 1;
 		ts->gc.label = "AD7879-GPIO";
 		ts->gc.owner = THIS_MODULE;
-		ts->gc.dev = dev;
+		ts->gc.dev = ts->dev;
 
 		ret = gpiochip_add(&ts->gc);
 		if (ret)
-			dev_err(dev, "failed to register gpio %d\n",
+			dev_err(ts->dev, "failed to register gpio %d\n",
 				ts->gc.base);
 	}
 
 	return ret;
 }
 
-/*
- * We mark ad7879_gpio_remove inline so there is a chance the code
- * gets discarded when not needed. We can't do __devinit/__devexit
- * markup since it is used in both probe and remove methods.
- */
-static inline void ad7879_gpio_remove(struct device *dev)
+static void ad7879_gpio_remove(struct ad7879 *ts)
 {
-	struct ad7879 *ts = dev_get_drvdata(dev);
-	struct ad7879_platform_data *pdata = dev->platform_data;
+	const struct ad7879_platform_data *pdata = ts->dev->platform_data;
 	int ret;
 
 	if (pdata->gpio_export) {
 		ret = gpiochip_remove(&ts->gc);
 		if (ret)
-			dev_err(dev, "failed to remove gpio %d\n",
+			dev_err(ts->dev, "failed to remove gpio %d\n",
 				ts->gc.base);
 	}
 }
 #else
-static inline int ad7879_gpio_add(struct device *dev)
+static inline int ad7879_gpio_add(struct ad7879 *ts,
+				  const struct ad7879_platform_data *pdata)
 {
 	return 0;
 }
 
-static inline void ad7879_gpio_remove(struct device *dev)
+static inline void ad7879_gpio_remove(struct ad7879 *ts)
 {
 }
 #endif
 
-static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
+struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
+			    const struct ad7879_bus_ops *bops)
 {
+	struct ad7879_platform_data *pdata = dev->platform_data;
+	struct ad7879 *ts;
 	struct input_dev *input_dev;
-	struct ad7879_platform_data *pdata = bus->dev.platform_data;
 	int err;
 	u16 revid;
 
-	if (!bus->irq) {
-		dev_err(&bus->dev, "no IRQ?\n");
-		return -ENODEV;
+	if (!irq) {
+		dev_err(dev, "no IRQ?\n");
+		err = -EINVAL;
+		goto err_out;
 	}
 
 	if (!pdata) {
-		dev_err(&bus->dev, "no platform data?\n");
-		return -ENODEV;
+		dev_err(dev, "no platform data?\n");
+		err = -EINVAL;
+		goto err_out;
 	}
 
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
 	input_dev = input_allocate_device();
-	if (!input_dev)
-		return -ENOMEM;
+	if (!ts || !input_dev) {
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
 
+	ts->bops = bops;
+	ts->dev = dev;
 	ts->input = input_dev;
+	ts->irq = irq;
 
 	setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
-	INIT_WORK(&ts->work, ad7879_work);
-	mutex_init(&ts->mutex);
 
 	ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
 	ts->pressure_max = pdata->pressure_max ? : ~0;
@@ -470,17 +496,26 @@
 	ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
 	ts->median = pdata->median;
 
-	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&bus->dev));
+	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
 
 	input_dev->name = "AD7879 Touchscreen";
 	input_dev->phys = ts->phys;
-	input_dev->dev.parent = &bus->dev;
+	input_dev->dev.parent = dev;
+	input_dev->id.bustype = bops->bustype;
+
+	input_dev->open = ad7879_open;
+	input_dev->close = ad7879_close;
+
+	input_set_drvdata(input_dev, ts);
 
 	__set_bit(EV_ABS, input_dev->evbit);
 	__set_bit(ABS_X, input_dev->absbit);
 	__set_bit(ABS_Y, input_dev->absbit);
 	__set_bit(ABS_PRESSURE, input_dev->absbit);
 
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+
 	input_set_abs_params(input_dev, ABS_X,
 			pdata->x_min ? : 0,
 			pdata->x_max ? : MAX_12BIT,
@@ -492,17 +527,18 @@
 	input_set_abs_params(input_dev, ABS_PRESSURE,
 			pdata->pressure_min, pdata->pressure_max, 0, 0);
 
-	err = ad7879_write(bus, AD7879_REG_CTRL2, AD7879_RESET);
-
+	err = ad7879_write(ts, AD7879_REG_CTRL2, AD7879_RESET);
 	if (err < 0) {
-		dev_err(&bus->dev, "Failed to write %s\n", input_dev->name);
+		dev_err(dev, "Failed to write %s\n", input_dev->name);
 		goto err_free_mem;
 	}
 
-	revid = ad7879_read(bus, AD7879_REG_REVID);
-
-	if ((revid & 0xFF) != AD7879_DEVID) {
-		dev_err(&bus->dev, "Failed to probe %s\n", input_dev->name);
+	revid = ad7879_read(ts, AD7879_REG_REVID);
+	input_dev->id.product = (revid & 0xff);
+	input_dev->id.version = revid >> 8;
+	if (input_dev->id.product != devid) {
+		dev_err(dev, "Failed to probe %s (%x vs %x)\n",
+			input_dev->name, devid, revid);
 		err = -ENODEV;
 		goto err_free_mem;
 	}
@@ -524,21 +560,21 @@
 			AD7879_ACQ(ts->acquisition_time) |
 			AD7879_TMR(ts->pen_down_acc_interval);
 
-	ad7879_setup(ts);
-
-	err = request_irq(bus->irq, ad7879_irq,
-			  IRQF_TRIGGER_FALLING, bus->dev.driver->name, ts);
-
+	err = request_threaded_irq(ts->irq, NULL, ad7879_irq,
+				   IRQF_TRIGGER_FALLING,
+				   dev_name(dev), ts);
 	if (err) {
-		dev_err(&bus->dev, "irq %d busy?\n", bus->irq);
+		dev_err(dev, "irq %d busy?\n", ts->irq);
 		goto err_free_mem;
 	}
 
-	err = sysfs_create_group(&bus->dev.kobj, &ad7879_attr_group);
+	__ad7879_disable(ts);
+
+	err = sysfs_create_group(&dev->kobj, &ad7879_attr_group);
 	if (err)
 		goto err_free_irq;
 
-	err = ad7879_gpio_add(&bus->dev);
+	err = ad7879_gpio_add(ts, pdata);
 	if (err)
 		goto err_remove_attr;
 
@@ -546,321 +582,32 @@
 	if (err)
 		goto err_remove_gpio;
 
-	dev_info(&bus->dev, "Rev.%d touchscreen, irq %d\n",
-		 revid >> 8, bus->irq);
-
-	return 0;
+	return ts;
 
 err_remove_gpio:
-	ad7879_gpio_remove(&bus->dev);
+	ad7879_gpio_remove(ts);
 err_remove_attr:
-	sysfs_remove_group(&bus->dev.kobj, &ad7879_attr_group);
+	sysfs_remove_group(&dev->kobj, &ad7879_attr_group);
 err_free_irq:
-	free_irq(bus->irq, ts);
+	free_irq(ts->irq, ts);
 err_free_mem:
 	input_free_device(input_dev);
-
-	return err;
+	kfree(ts);
+err_out:
+	return ERR_PTR(err);
 }
+EXPORT_SYMBOL(ad7879_probe);
 
-static int __devexit ad7879_destroy(bus_device *bus, struct ad7879 *ts)
+void ad7879_remove(struct ad7879 *ts)
 {
-	ad7879_gpio_remove(&bus->dev);
-	ad7879_disable(ts);
-	sysfs_remove_group(&ts->bus->dev.kobj, &ad7879_attr_group);
-	free_irq(ts->bus->irq, ts);
+	ad7879_gpio_remove(ts);
+	sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group);
+	free_irq(ts->irq, ts);
 	input_unregister_device(ts->input);
-	dev_dbg(&bus->dev, "unregistered touchscreen\n");
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int ad7879_suspend(bus_device *bus, pm_message_t message)
-{
-	struct ad7879 *ts = dev_get_drvdata(&bus->dev);
-
-	ad7879_disable(ts);
-
-	return 0;
-}
-
-static int ad7879_resume(bus_device *bus)
-{
-	struct ad7879 *ts = dev_get_drvdata(&bus->dev);
-
-	ad7879_enable(ts);
-
-	return 0;
-}
-#else
-#define ad7879_suspend NULL
-#define ad7879_resume  NULL
-#endif
-
-#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
-#define MAX_SPI_FREQ_HZ		5000000
-#define AD7879_CMD_MAGIC	0xE000
-#define AD7879_CMD_READ		(1 << 10)
-#define AD7879_WRITECMD(reg)	(AD7879_CMD_MAGIC | (reg & 0xF))
-#define AD7879_READCMD(reg)	(AD7879_CMD_MAGIC | AD7879_CMD_READ | (reg & 0xF))
-
-struct ser_req {
-	u16			command;
-	u16			data;
-	struct spi_message	msg;
-	struct spi_transfer	xfer[2];
-};
-
-/*
- * ad7879_read/write are only used for initial setup and for sysfs controls.
- * The main traffic is done in ad7879_collect().
- */
-
-static int ad7879_read(struct spi_device *spi, u8 reg)
-{
-	struct ser_req *req;
-	int status, ret;
-
-	req = kzalloc(sizeof *req, GFP_KERNEL);
-	if (!req)
-		return -ENOMEM;
-
-	spi_message_init(&req->msg);
-
-	req->command = (u16) AD7879_READCMD(reg);
-	req->xfer[0].tx_buf = &req->command;
-	req->xfer[0].len = 2;
-
-	req->xfer[1].rx_buf = &req->data;
-	req->xfer[1].len = 2;
-
-	spi_message_add_tail(&req->xfer[0], &req->msg);
-	spi_message_add_tail(&req->xfer[1], &req->msg);
-
-	status = spi_sync(spi, &req->msg);
-	ret = status ? : req->data;
-
-	kfree(req);
-
-	return ret;
-}
-
-static int ad7879_write(struct spi_device *spi, u8 reg, u16 val)
-{
-	struct ser_req *req;
-	int status;
-
-	req = kzalloc(sizeof *req, GFP_KERNEL);
-	if (!req)
-		return -ENOMEM;
-
-	spi_message_init(&req->msg);
-
-	req->command = (u16) AD7879_WRITECMD(reg);
-	req->xfer[0].tx_buf = &req->command;
-	req->xfer[0].len = 2;
-
-	req->data = val;
-	req->xfer[1].tx_buf = &req->data;
-	req->xfer[1].len = 2;
-
-	spi_message_add_tail(&req->xfer[0], &req->msg);
-	spi_message_add_tail(&req->xfer[1], &req->msg);
-
-	status = spi_sync(spi, &req->msg);
-
-	kfree(req);
-
-	return status;
-}
-
-static void ad7879_collect(struct ad7879 *ts)
-{
-	int status = spi_sync(ts->bus, &ts->msg);
-
-	if (status)
-		dev_err(&ts->bus->dev, "spi_sync --> %d\n", status);
-}
-
-static void ad7879_setup_ts_def_msg(struct ad7879 *ts)
-{
-	struct spi_message *m;
-	int i;
-
-	ts->cmd = (u16) AD7879_READCMD(AD7879_REG_XPLUS);
-
-	m = &ts->msg;
-	spi_message_init(m);
-	ts->xfer[0].tx_buf = &ts->cmd;
-	ts->xfer[0].len = 2;
-
-	spi_message_add_tail(&ts->xfer[0], m);
-
-	for (i = 0; i < AD7879_NR_SENSE; i++) {
-		ts->xfer[i + 1].rx_buf = &ts->conversion_data[i];
-		ts->xfer[i + 1].len = 2;
-		spi_message_add_tail(&ts->xfer[i + 1], m);
-	}
-}
-
-static int __devinit ad7879_probe(struct spi_device *spi)
-{
-	struct ad7879 *ts;
-	int error;
-
-	/* don't exceed max specified SPI CLK frequency */
-	if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
-		dev_err(&spi->dev, "SPI CLK %d Hz?\n", spi->max_speed_hz);
-		return -EINVAL;
-	}
-
-	ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL);
-	if (!ts)
-		return -ENOMEM;
-
-	dev_set_drvdata(&spi->dev, ts);
-	ts->bus = spi;
-
-	ad7879_setup_ts_def_msg(ts);
-
-	error = ad7879_construct(spi, ts);
-	if (error) {
-		dev_set_drvdata(&spi->dev, NULL);
-		kfree(ts);
-	}
-
-	return error;
-}
-
-static int __devexit ad7879_remove(struct spi_device *spi)
-{
-	struct ad7879 *ts = dev_get_drvdata(&spi->dev);
-
-	ad7879_destroy(spi, ts);
-	dev_set_drvdata(&spi->dev, NULL);
 	kfree(ts);
-
-	return 0;
 }
-
-static struct spi_driver ad7879_driver = {
-	.driver = {
-		.name	= "ad7879",
-		.bus	= &spi_bus_type,
-		.owner	= THIS_MODULE,
-	},
-	.probe		= ad7879_probe,
-	.remove		= __devexit_p(ad7879_remove),
-	.suspend	= ad7879_suspend,
-	.resume		= ad7879_resume,
-};
-
-static int __init ad7879_init(void)
-{
-	return spi_register_driver(&ad7879_driver);
-}
-module_init(ad7879_init);
-
-static void __exit ad7879_exit(void)
-{
-	spi_unregister_driver(&ad7879_driver);
-}
-module_exit(ad7879_exit);
-
-#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
-
-/* All registers are word-sized.
- * AD7879 uses a high-byte first convention.
- */
-static int ad7879_read(struct i2c_client *client, u8 reg)
-{
-	return swab16(i2c_smbus_read_word_data(client, reg));
-}
-
-static int ad7879_write(struct i2c_client *client, u8 reg, u16 val)
-{
-	return i2c_smbus_write_word_data(client, reg, swab16(val));
-}
-
-static void ad7879_collect(struct ad7879 *ts)
-{
-	int i;
-
-	for (i = 0; i < AD7879_NR_SENSE; i++)
-		ts->conversion_data[i] = ad7879_read(ts->bus,
-						     AD7879_REG_XPLUS + i);
-}
-
-static int __devinit ad7879_probe(struct i2c_client *client,
-					const struct i2c_device_id *id)
-{
-	struct ad7879 *ts;
-	int error;
-
-	if (!i2c_check_functionality(client->adapter,
-					I2C_FUNC_SMBUS_WORD_DATA)) {
-		dev_err(&client->dev, "SMBUS Word Data not Supported\n");
-		return -EIO;
-	}
-
-	ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL);
-	if (!ts)
-		return -ENOMEM;
-
-	i2c_set_clientdata(client, ts);
-	ts->bus = client;
-
-	error = ad7879_construct(client, ts);
-	if (error)
-		kfree(ts);
-
-	return error;
-}
-
-static int __devexit ad7879_remove(struct i2c_client *client)
-{
-	struct ad7879 *ts = dev_get_drvdata(&client->dev);
-
-	ad7879_destroy(client, ts);
-	kfree(ts);
-
-	return 0;
-}
-
-static const struct i2c_device_id ad7879_id[] = {
-	{ "ad7879", 0 },
-	{ "ad7889", 0 },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, ad7879_id);
-
-static struct i2c_driver ad7879_driver = {
-	.driver = {
-		.name	= "ad7879",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= ad7879_probe,
-	.remove		= __devexit_p(ad7879_remove),
-	.suspend	= ad7879_suspend,
-	.resume		= ad7879_resume,
-	.id_table	= ad7879_id,
-};
-
-static int __init ad7879_init(void)
-{
-	return i2c_add_driver(&ad7879_driver);
-}
-module_init(ad7879_init);
-
-static void __exit ad7879_exit(void)
-{
-	i2c_del_driver(&ad7879_driver);
-}
-module_exit(ad7879_exit);
-#endif
+EXPORT_SYMBOL(ad7879_remove);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("AD7879(-1) touchscreen Driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:ad7879");
diff --git a/drivers/input/touchscreen/ad7879.h b/drivers/input/touchscreen/ad7879.h
new file mode 100644
index 0000000..6b45a27
--- /dev/null
+++ b/drivers/input/touchscreen/ad7879.h
@@ -0,0 +1,30 @@
+/*
+ * AD7879/AD7889 touchscreen (bus interfaces)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _AD7879_H_
+#define _AD7879_H_
+
+#include <linux/types.h>
+
+struct ad7879;
+struct device;
+
+struct ad7879_bus_ops {
+	u16 bustype;
+	int (*read)(struct device *dev, u8 reg);
+	int (*multi_read)(struct device *dev, u8 first_reg, u8 count, u16 *buf);
+	int (*write)(struct device *dev, u8 reg, u16 val);
+};
+
+void ad7879_suspend(struct ad7879 *);
+void ad7879_resume(struct ad7879 *);
+struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned irq,
+			    const struct ad7879_bus_ops *bops);
+void ad7879_remove(struct ad7879 *);
+
+#endif
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index a9fdf55..1603193 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -68,6 +68,8 @@
 	u16	y;
 	u16	z1, z2;
 	int	ignore;
+	u8	x_buf[3];
+	u8	y_buf[3];
 };
 
 /*
@@ -79,6 +81,8 @@
 	u8			read_x, read_y, read_z1, read_z2, pwrdown;
 	u16			dummy;		/* for the pwrdown read */
 	struct ts_event		tc;
+	/* for ads7845 with mpc5121 psc spi we use 3-byte buffers */
+	u8			read_x_cmd[3], read_y_cmd[3], pwrdown_cmd[3];
 };
 
 struct ads7846 {
@@ -207,6 +211,14 @@
 	struct spi_transfer	xfer[6];
 };
 
+struct ads7845_ser_req {
+	u8			command[3];
+	u8			pwrdown[3];
+	u8			sample[3];
+	struct spi_message	msg;
+	struct spi_transfer	xfer[2];
+};
+
 static void ads7846_enable(struct ads7846 *ts);
 static void ads7846_disable(struct ads7846 *ts);
 
@@ -287,6 +299,41 @@
 	return status;
 }
 
+static int ads7845_read12_ser(struct device *dev, unsigned command)
+{
+	struct spi_device	*spi = to_spi_device(dev);
+	struct ads7846		*ts = dev_get_drvdata(dev);
+	struct ads7845_ser_req	*req = kzalloc(sizeof *req, GFP_KERNEL);
+	int			status;
+
+	if (!req)
+		return -ENOMEM;
+
+	spi_message_init(&req->msg);
+
+	req->command[0] = (u8) command;
+	req->xfer[0].tx_buf = req->command;
+	req->xfer[0].rx_buf = req->sample;
+	req->xfer[0].len = 3;
+	spi_message_add_tail(&req->xfer[0], &req->msg);
+
+	ts->irq_disabled = 1;
+	disable_irq(spi->irq);
+	status = spi_sync(spi, &req->msg);
+	ts->irq_disabled = 0;
+	enable_irq(spi->irq);
+
+	if (status == 0) {
+		/* BE12 value, then padding */
+		status = be16_to_cpu(*((u16 *)&req->sample[1]));
+		status = status >> 3;
+		status &= 0x0fff;
+	}
+
+	kfree(req);
+	return status;
+}
+
 #if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
 
 #define SHOW(name, var, adjust) static ssize_t \
@@ -540,10 +587,17 @@
 	/* ads7846_rx_val() did in-place conversion (including byteswap) from
 	 * on-the-wire format as part of debouncing to get stable readings.
 	 */
-	x = packet->tc.x;
-	y = packet->tc.y;
-	z1 = packet->tc.z1;
-	z2 = packet->tc.z2;
+	if (ts->model == 7845) {
+		x = *(u16 *)packet->tc.x_buf;
+		y = *(u16 *)packet->tc.y_buf;
+		z1 = 0;
+		z2 = 0;
+	} else {
+		x = packet->tc.x;
+		y = packet->tc.y;
+		z1 = packet->tc.z1;
+		z2 = packet->tc.z2;
+	}
 
 	/* range filtering */
 	if (x == MAX_12BIT)
@@ -551,6 +605,12 @@
 
 	if (ts->model == 7843) {
 		Rt = ts->pressure_max / 2;
+	} else if (ts->model == 7845) {
+		if (get_pendown_state(ts))
+			Rt = ts->pressure_max / 2;
+		else
+			Rt = 0;
+		dev_vdbg(&ts->spi->dev, "x/y: %d/%d, PD %d\n", x, y, Rt);
 	} else if (likely(x && z1)) {
 		/* compute touch pressure resistance using equation #2 */
 		Rt = z2;
@@ -671,10 +731,14 @@
 	m = &ts->msg[ts->msg_idx];
 	t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
 
-	/* adjust:  on-wire is a must-ignore bit, a BE12 value, then padding;
-	 * built from two 8 bit values written msb-first.
-	 */
-	val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
+	if (ts->model == 7845) {
+		val = be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3;
+	} else {
+		/* adjust:  on-wire is a must-ignore bit, a BE12 value, then
+		 * padding; built from two 8 bit values written msb-first.
+		 */
+		val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
+	}
 
 	action = ts->filter(ts->filter_data, ts->msg_idx, &val);
 	switch (action) {
@@ -878,14 +942,15 @@
 
 static int __devinit ads7846_probe(struct spi_device *spi)
 {
-	struct ads7846			*ts;
-	struct ads7846_packet		*packet;
-	struct input_dev		*input_dev;
-	struct ads7846_platform_data	*pdata = spi->dev.platform_data;
-	struct spi_message		*m;
-	struct spi_transfer		*x;
-	int				vref;
-	int				err;
+	struct ads7846 *ts;
+	struct ads7846_packet *packet;
+	struct input_dev *input_dev;
+	const struct ads7846_platform_data *pdata = spi->dev.platform_data;
+	struct spi_message *m;
+	struct spi_transfer *x;
+	unsigned long irq_flags;
+	int vref;
+	int err;
 
 	if (!spi->irq) {
 		dev_dbg(&spi->dev, "no IRQ?\n");
@@ -1008,16 +1073,26 @@
 
 	spi_message_init(m);
 
-	/* y- still on; turn on only y+ (and ADC) */
-	packet->read_y = READ_Y(vref);
-	x->tx_buf = &packet->read_y;
-	x->len = 1;
-	spi_message_add_tail(x, m);
+	if (ts->model == 7845) {
+		packet->read_y_cmd[0] = READ_Y(vref);
+		packet->read_y_cmd[1] = 0;
+		packet->read_y_cmd[2] = 0;
+		x->tx_buf = &packet->read_y_cmd[0];
+		x->rx_buf = &packet->tc.y_buf[0];
+		x->len = 3;
+		spi_message_add_tail(x, m);
+	} else {
+		/* y- still on; turn on only y+ (and ADC) */
+		packet->read_y = READ_Y(vref);
+		x->tx_buf = &packet->read_y;
+		x->len = 1;
+		spi_message_add_tail(x, m);
 
-	x++;
-	x->rx_buf = &packet->tc.y;
-	x->len = 2;
-	spi_message_add_tail(x, m);
+		x++;
+		x->rx_buf = &packet->tc.y;
+		x->len = 2;
+		spi_message_add_tail(x, m);
+	}
 
 	/* the first sample after switching drivers can be low quality;
 	 * optionally discard it, using a second one after the signals
@@ -1043,17 +1118,28 @@
 	m++;
 	spi_message_init(m);
 
-	/* turn y- off, x+ on, then leave in lowpower */
-	x++;
-	packet->read_x = READ_X(vref);
-	x->tx_buf = &packet->read_x;
-	x->len = 1;
-	spi_message_add_tail(x, m);
+	if (ts->model == 7845) {
+		x++;
+		packet->read_x_cmd[0] = READ_X(vref);
+		packet->read_x_cmd[1] = 0;
+		packet->read_x_cmd[2] = 0;
+		x->tx_buf = &packet->read_x_cmd[0];
+		x->rx_buf = &packet->tc.x_buf[0];
+		x->len = 3;
+		spi_message_add_tail(x, m);
+	} else {
+		/* turn y- off, x+ on, then leave in lowpower */
+		x++;
+		packet->read_x = READ_X(vref);
+		x->tx_buf = &packet->read_x;
+		x->len = 1;
+		spi_message_add_tail(x, m);
 
-	x++;
-	x->rx_buf = &packet->tc.x;
-	x->len = 2;
-	spi_message_add_tail(x, m);
+		x++;
+		x->rx_buf = &packet->tc.x;
+		x->len = 2;
+		spi_message_add_tail(x, m);
+	}
 
 	/* ... maybe discard first sample ... */
 	if (pdata->settle_delay_usecs) {
@@ -1144,15 +1230,25 @@
 	m++;
 	spi_message_init(m);
 
-	x++;
-	packet->pwrdown = PWRDOWN;
-	x->tx_buf = &packet->pwrdown;
-	x->len = 1;
-	spi_message_add_tail(x, m);
+	if (ts->model == 7845) {
+		x++;
+		packet->pwrdown_cmd[0] = PWRDOWN;
+		packet->pwrdown_cmd[1] = 0;
+		packet->pwrdown_cmd[2] = 0;
+		x->tx_buf = &packet->pwrdown_cmd[0];
+		x->len = 3;
+	} else {
+		x++;
+		packet->pwrdown = PWRDOWN;
+		x->tx_buf = &packet->pwrdown;
+		x->len = 1;
+		spi_message_add_tail(x, m);
 
-	x++;
-	x->rx_buf = &packet->dummy;
-	x->len = 2;
+		x++;
+		x->rx_buf = &packet->dummy;
+		x->len = 2;
+	}
+
 	CS_CHANGE(*x);
 	spi_message_add_tail(x, m);
 
@@ -1174,17 +1270,22 @@
 		goto err_put_regulator;
 	}
 
-	if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
-			spi->dev.driver->name, ts)) {
+	irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING;
+
+	err = request_irq(spi->irq, ads7846_irq, irq_flags,
+			  spi->dev.driver->name, ts);
+
+	if (err && !pdata->irq_flags) {
 		dev_info(&spi->dev,
 			"trying pin change workaround on irq %d\n", spi->irq);
 		err = request_irq(spi->irq, ads7846_irq,
 				  IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
 				  spi->dev.driver->name, ts);
-		if (err) {
-			dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
-			goto err_disable_regulator;
-		}
+	}
+
+	if (err) {
+		dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
+		goto err_disable_regulator;
 	}
 
 	err = ads784x_hwmon_register(spi, ts);
@@ -1196,8 +1297,11 @@
 	/* take a first sample, leaving nPENIRQ active and vREF off; avoid
 	 * the touchscreen, in case it's not connected.
 	 */
-	(void) ads7846_read12_ser(&spi->dev,
-			  READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+	if (ts->model == 7845)
+		ads7845_read12_ser(&spi->dev, PWRDOWN);
+	else
+		(void) ads7846_read12_ser(&spi->dev,
+				READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
 
 	err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
 	if (err)
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
new file mode 100644
index 0000000..4eb7df0
--- /dev/null
+++ b/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -0,0 +1,363 @@
+/*
+ * Driver for cypress touch screen controller
+ *
+ * Copyright (c) 2009 Aava Mobile
+ *
+ * Some cleanups by Alan Cox <alan@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/input/cy8ctmg110_pdata.h>
+
+#define CY8CTMG110_DRIVER_NAME      "cy8ctmg110"
+
+/* Touch coordinates */
+#define CY8CTMG110_X_MIN		0
+#define CY8CTMG110_Y_MIN		0
+#define CY8CTMG110_X_MAX		759
+#define CY8CTMG110_Y_MAX		465
+
+
+/* cy8ctmg110 register definitions */
+#define CY8CTMG110_TOUCH_WAKEUP_TIME	0
+#define CY8CTMG110_TOUCH_SLEEP_TIME	2
+#define CY8CTMG110_TOUCH_X1		3
+#define CY8CTMG110_TOUCH_Y1		5
+#define CY8CTMG110_TOUCH_X2		7
+#define CY8CTMG110_TOUCH_Y2		9
+#define CY8CTMG110_FINGERS		11
+#define CY8CTMG110_GESTURE		12
+#define CY8CTMG110_REG_MAX		13
+
+
+/*
+ * The touch driver structure.
+ */
+struct cy8ctmg110 {
+	struct input_dev *input;
+	char phys[32];
+	struct i2c_client *client;
+	int reset_pin;
+	int irq_pin;
+};
+
+/*
+ * cy8ctmg110_power is the routine that is called when touch hardware
+ * will powered off or on.
+ */
+static void cy8ctmg110_power(struct cy8ctmg110 *ts, bool poweron)
+{
+	if (ts->reset_pin)
+		gpio_direction_output(ts->reset_pin, 1 - poweron);
+}
+
+static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg,
+		unsigned char len, unsigned char *value)
+{
+	struct i2c_client *client = tsc->client;
+	unsigned int ret;
+	unsigned char i2c_data[6];
+
+	BUG_ON(len > 5);
+
+	i2c_data[0] = reg;
+	memcpy(i2c_data + 1, value, len);
+
+	ret = i2c_master_send(client, i2c_data, len + 1);
+	if (ret != 1) {
+		dev_err(&client->dev, "i2c write data cmd failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc,
+		unsigned char *data, unsigned char len, unsigned char cmd)
+{
+	struct i2c_client *client = tsc->client;
+	unsigned int ret;
+	struct i2c_msg msg[2] = {
+		/* first write slave position to i2c devices */
+		{ client->addr, 0, 1, &cmd },
+		/* Second read data from position */
+		{ client->addr, I2C_M_RD, len, data }
+	};
+
+	ret = i2c_transfer(client->adapter, msg, 2);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc)
+{
+	struct input_dev *input = tsc->input;
+	unsigned char reg_p[CY8CTMG110_REG_MAX];
+	int x, y;
+
+	memset(reg_p, 0, CY8CTMG110_REG_MAX);
+
+	/* Reading coordinates */
+	if (cy8ctmg110_read_regs(tsc, reg_p, 9, CY8CTMG110_TOUCH_X1) != 0)
+		return -EIO;
+
+	y = reg_p[2] << 8 | reg_p[3];
+	x = reg_p[0] << 8 | reg_p[1];
+
+	/* Number of touch */
+	if (reg_p[8] == 0) {
+		input_report_key(input, BTN_TOUCH, 0);
+	} else  {
+		input_report_key(input, BTN_TOUCH, 1);
+		input_report_abs(input, ABS_X, x);
+		input_report_abs(input, ABS_Y, y);
+	}
+
+	input_sync(input);
+
+	return 0;
+}
+
+static int cy8ctmg110_set_sleepmode(struct cy8ctmg110 *ts, bool sleep)
+{
+	unsigned char reg_p[3];
+
+	if (sleep) {
+		reg_p[0] = 0x00;
+		reg_p[1] = 0xff;
+		reg_p[2] = 5;
+	} else {
+		reg_p[0] = 0x10;
+		reg_p[1] = 0xff;
+		reg_p[2] = 0;
+	}
+
+	return cy8ctmg110_write_regs(ts, CY8CTMG110_TOUCH_WAKEUP_TIME, 3, reg_p);
+}
+
+static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)
+{
+	struct cy8ctmg110 *tsc = dev_id;
+
+	cy8ctmg110_touch_pos(tsc);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit cy8ctmg110_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	const struct cy8ctmg110_pdata *pdata = client->dev.platform_data;
+	struct cy8ctmg110 *ts;
+	struct input_dev *input_dev;
+	int err;
+
+	/* No pdata no way forward */
+	if (pdata == NULL) {
+		dev_err(&client->dev, "no pdata\n");
+		return -ENODEV;
+	}
+
+	if (!i2c_check_functionality(client->adapter,
+					I2C_FUNC_SMBUS_READ_WORD_DATA))
+		return -EIO;
+
+	ts = kzalloc(sizeof(struct cy8ctmg110), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts || !input_dev) {
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ts->client = client;
+	ts->input = input_dev;
+
+	snprintf(ts->phys, sizeof(ts->phys),
+		 "%s/input0", dev_name(&client->dev));
+
+	input_dev->name = CY8CTMG110_DRIVER_NAME " Touchscreen";
+	input_dev->phys = ts->phys;
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(input_dev, ABS_X,
+			CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y,
+			CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 0, 0);
+
+	if (ts->reset_pin) {
+		err = gpio_request(ts->reset_pin, NULL);
+		if (err) {
+			dev_err(&client->dev,
+				"Unable to request GPIO pin %d.\n",
+				ts->reset_pin);
+			goto err_free_mem;
+		}
+	}
+
+	cy8ctmg110_power(ts, true);
+	cy8ctmg110_set_sleepmode(ts, false);
+
+	err = gpio_request(ts->irq_pin, "touch_irq_key");
+	if (err < 0) {
+		dev_err(&client->dev,
+			"Failed to request GPIO %d, error %d\n",
+			ts->irq_pin, err);
+		goto err_shutoff_device;
+	}
+
+	err = gpio_direction_input(ts->irq_pin);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"Failed to configure input direction for GPIO %d, error %d\n",
+			ts->irq_pin, err);
+		goto err_free_irq_gpio;
+	}
+
+	client->irq = gpio_to_irq(ts->irq_pin);
+	if (client->irq < 0) {
+		err = client->irq;
+		dev_err(&client->dev,
+			"Unable to get irq number for GPIO %d, error %d\n",
+			ts->irq_pin, err);
+		goto err_free_irq_gpio;
+	}
+
+	err = request_threaded_irq(client->irq, NULL, cy8ctmg110_irq_thread,
+				   IRQF_TRIGGER_RISING, "touch_reset_key", ts);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"irq %d busy? error %d\n", client->irq, err);
+		goto err_free_irq_gpio;
+	}
+
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_free_irq;
+
+	i2c_set_clientdata(client, ts);
+	device_init_wakeup(&client->dev, 1);
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, ts);
+err_free_irq_gpio:
+	gpio_free(ts->irq_pin);
+err_shutoff_device:
+	cy8ctmg110_set_sleepmode(ts, true);
+	cy8ctmg110_power(ts, false);
+	if (ts->reset_pin)
+		gpio_free(ts->reset_pin);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(ts);
+	return err;
+}
+
+#ifdef CONFIG_PM
+static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(&client->dev))
+		enable_irq_wake(client->irq);
+	else {
+		cy8ctmg110_set_sleepmode(ts, true);
+		cy8ctmg110_power(ts, false);
+	}
+	return 0;
+}
+
+static int cy8ctmg110_resume(struct i2c_client *client)
+{
+	struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(&client->dev))
+		disable_irq_wake(client->irq);
+	else {
+		cy8ctmg110_power(ts, true);
+		cy8ctmg110_set_sleepmode(ts, false);
+	}
+	return 0;
+}
+#endif
+
+static int __devexit cy8ctmg110_remove(struct i2c_client *client)
+{
+	struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+	cy8ctmg110_set_sleepmode(ts, true);
+	cy8ctmg110_power(ts, false);
+
+	free_irq(client->irq, ts);
+	input_unregister_device(ts->input);
+	gpio_free(ts->irq_pin);
+	if (ts->reset_pin)
+		gpio_free(ts->reset_pin);
+	kfree(ts);
+
+	return 0;
+}
+
+static struct i2c_device_id cy8ctmg110_idtable[] = {
+	{ CY8CTMG110_DRIVER_NAME, 1 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
+
+static struct i2c_driver cy8ctmg110_driver = {
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= CY8CTMG110_DRIVER_NAME,
+	},
+	.id_table	= cy8ctmg110_idtable,
+	.probe		= cy8ctmg110_probe,
+	.remove		= __devexit_p(cy8ctmg110_remove),
+#ifdef CONFIG_PM
+	.suspend	= cy8ctmg110_suspend,
+	.resume		= cy8ctmg110_resume,
+#endif
+};
+
+static int __init cy8ctmg110_init(void)
+{
+	return i2c_add_driver(&cy8ctmg110_driver);
+}
+
+static void __exit cy8ctmg110_exit(void)
+{
+	i2c_del_driver(&cy8ctmg110_driver);
+}
+
+module_init(cy8ctmg110_init);
+module_exit(cy8ctmg110_exit);
+
+MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>");
+MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
index 1fb0c2f..6ee9940 100644
--- a/drivers/input/touchscreen/mcs5000_ts.c
+++ b/drivers/input/touchscreen/mcs5000_ts.c
@@ -16,7 +16,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
-#include <linux/i2c/mcs5000_ts.h>
+#include <linux/i2c/mcs.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/irq.h>
@@ -105,7 +105,7 @@
 struct mcs5000_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input_dev;
-	const struct mcs5000_ts_platform_data *platform_data;
+	const struct mcs_platform_data *platform_data;
 };
 
 static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
@@ -164,7 +164,7 @@
 
 static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
 {
-	const struct mcs5000_ts_platform_data *platform_data =
+	const struct mcs_platform_data *platform_data =
 		data->platform_data;
 	struct i2c_client *client = data->client;
 
diff --git a/drivers/input/touchscreen/qt602240_ts.c b/drivers/input/touchscreen/qt602240_ts.c
new file mode 100644
index 0000000..66b26ad
--- /dev/null
+++ b/drivers/input/touchscreen/qt602240_ts.c
@@ -0,0 +1,1401 @@
+/*
+ * AT42QT602240/ATMXT224 Touchscreen driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/i2c/qt602240_ts.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+/* Version */
+#define QT602240_VER_20			20
+#define QT602240_VER_21			21
+#define QT602240_VER_22			22
+
+/* Slave addresses */
+#define QT602240_APP_LOW		0x4a
+#define QT602240_APP_HIGH		0x4b
+#define QT602240_BOOT_LOW		0x24
+#define QT602240_BOOT_HIGH		0x25
+
+/* Firmware */
+#define QT602240_FW_NAME		"qt602240.fw"
+
+/* Registers */
+#define QT602240_FAMILY_ID		0x00
+#define QT602240_VARIANT_ID		0x01
+#define QT602240_VERSION		0x02
+#define QT602240_BUILD			0x03
+#define QT602240_MATRIX_X_SIZE		0x04
+#define QT602240_MATRIX_Y_SIZE		0x05
+#define QT602240_OBJECT_NUM		0x06
+#define QT602240_OBJECT_START		0x07
+
+#define QT602240_OBJECT_SIZE		6
+
+/* Object types */
+#define QT602240_DEBUG_DIAGNOSTIC	37
+#define QT602240_GEN_MESSAGE		5
+#define QT602240_GEN_COMMAND		6
+#define QT602240_GEN_POWER		7
+#define QT602240_GEN_ACQUIRE		8
+#define QT602240_TOUCH_MULTI		9
+#define QT602240_TOUCH_KEYARRAY		15
+#define QT602240_TOUCH_PROXIMITY	23
+#define QT602240_PROCI_GRIPFACE		20
+#define QT602240_PROCG_NOISE		22
+#define QT602240_PROCI_ONETOUCH		24
+#define QT602240_PROCI_TWOTOUCH		27
+#define QT602240_SPT_COMMSCONFIG	18	/* firmware ver 21 over */
+#define QT602240_SPT_GPIOPWM		19
+#define QT602240_SPT_SELFTEST		25
+#define QT602240_SPT_CTECONFIG		28
+#define QT602240_SPT_USERDATA		38	/* firmware ver 21 over */
+
+/* QT602240_GEN_COMMAND field */
+#define QT602240_COMMAND_RESET		0
+#define QT602240_COMMAND_BACKUPNV	1
+#define QT602240_COMMAND_CALIBRATE	2
+#define QT602240_COMMAND_REPORTALL	3
+#define QT602240_COMMAND_DIAGNOSTIC	5
+
+/* QT602240_GEN_POWER field */
+#define QT602240_POWER_IDLEACQINT	0
+#define QT602240_POWER_ACTVACQINT	1
+#define QT602240_POWER_ACTV2IDLETO	2
+
+/* QT602240_GEN_ACQUIRE field */
+#define QT602240_ACQUIRE_CHRGTIME	0
+#define QT602240_ACQUIRE_TCHDRIFT	2
+#define QT602240_ACQUIRE_DRIFTST	3
+#define QT602240_ACQUIRE_TCHAUTOCAL	4
+#define QT602240_ACQUIRE_SYNC		5
+#define QT602240_ACQUIRE_ATCHCALST	6
+#define QT602240_ACQUIRE_ATCHCALSTHR	7
+
+/* QT602240_TOUCH_MULTI field */
+#define QT602240_TOUCH_CTRL		0
+#define QT602240_TOUCH_XORIGIN		1
+#define QT602240_TOUCH_YORIGIN		2
+#define QT602240_TOUCH_XSIZE		3
+#define QT602240_TOUCH_YSIZE		4
+#define QT602240_TOUCH_BLEN		6
+#define QT602240_TOUCH_TCHTHR		7
+#define QT602240_TOUCH_TCHDI		8
+#define QT602240_TOUCH_ORIENT		9
+#define QT602240_TOUCH_MOVHYSTI		11
+#define QT602240_TOUCH_MOVHYSTN		12
+#define QT602240_TOUCH_NUMTOUCH		14
+#define QT602240_TOUCH_MRGHYST		15
+#define QT602240_TOUCH_MRGTHR		16
+#define QT602240_TOUCH_AMPHYST		17
+#define QT602240_TOUCH_XRANGE_LSB	18
+#define QT602240_TOUCH_XRANGE_MSB	19
+#define QT602240_TOUCH_YRANGE_LSB	20
+#define QT602240_TOUCH_YRANGE_MSB	21
+#define QT602240_TOUCH_XLOCLIP		22
+#define QT602240_TOUCH_XHICLIP		23
+#define QT602240_TOUCH_YLOCLIP		24
+#define QT602240_TOUCH_YHICLIP		25
+#define QT602240_TOUCH_XEDGECTRL	26
+#define QT602240_TOUCH_XEDGEDIST	27
+#define QT602240_TOUCH_YEDGECTRL	28
+#define QT602240_TOUCH_YEDGEDIST	29
+#define QT602240_TOUCH_JUMPLIMIT	30	/* firmware ver 22 over */
+
+/* QT602240_PROCI_GRIPFACE field */
+#define QT602240_GRIPFACE_CTRL		0
+#define QT602240_GRIPFACE_XLOGRIP	1
+#define QT602240_GRIPFACE_XHIGRIP	2
+#define QT602240_GRIPFACE_YLOGRIP	3
+#define QT602240_GRIPFACE_YHIGRIP	4
+#define QT602240_GRIPFACE_MAXTCHS	5
+#define QT602240_GRIPFACE_SZTHR1	7
+#define QT602240_GRIPFACE_SZTHR2	8
+#define QT602240_GRIPFACE_SHPTHR1	9
+#define QT602240_GRIPFACE_SHPTHR2	10
+#define QT602240_GRIPFACE_SUPEXTTO	11
+
+/* QT602240_PROCI_NOISE field */
+#define QT602240_NOISE_CTRL		0
+#define QT602240_NOISE_OUTFLEN		1
+#define QT602240_NOISE_GCAFUL_LSB	3
+#define QT602240_NOISE_GCAFUL_MSB	4
+#define QT602240_NOISE_GCAFLL_LSB	5
+#define QT602240_NOISE_GCAFLL_MSB	6
+#define QT602240_NOISE_ACTVGCAFVALID	7
+#define QT602240_NOISE_NOISETHR		8
+#define QT602240_NOISE_FREQHOPSCALE	10
+#define QT602240_NOISE_FREQ0		11
+#define QT602240_NOISE_FREQ1		12
+#define QT602240_NOISE_FREQ2		13
+#define QT602240_NOISE_FREQ3		14
+#define QT602240_NOISE_FREQ4		15
+#define QT602240_NOISE_IDLEGCAFVALID	16
+
+/* QT602240_SPT_COMMSCONFIG */
+#define QT602240_COMMS_CTRL		0
+#define QT602240_COMMS_CMD		1
+
+/* QT602240_SPT_CTECONFIG field */
+#define QT602240_CTE_CTRL		0
+#define QT602240_CTE_CMD		1
+#define QT602240_CTE_MODE		2
+#define QT602240_CTE_IDLEGCAFDEPTH	3
+#define QT602240_CTE_ACTVGCAFDEPTH	4
+#define QT602240_CTE_VOLTAGE		5	/* firmware ver 21 over */
+
+#define QT602240_VOLTAGE_DEFAULT	2700000
+#define QT602240_VOLTAGE_STEP		10000
+
+/* Define for QT602240_GEN_COMMAND */
+#define QT602240_BOOT_VALUE		0xa5
+#define QT602240_BACKUP_VALUE		0x55
+#define QT602240_BACKUP_TIME		25	/* msec */
+#define QT602240_RESET_TIME		65	/* msec */
+
+#define QT602240_FWRESET_TIME		175	/* msec */
+
+/* Command to unlock bootloader */
+#define QT602240_UNLOCK_CMD_MSB		0xaa
+#define QT602240_UNLOCK_CMD_LSB		0xdc
+
+/* Bootloader mode status */
+#define QT602240_WAITING_BOOTLOAD_CMD	0xc0	/* valid 7 6 bit only */
+#define QT602240_WAITING_FRAME_DATA	0x80	/* valid 7 6 bit only */
+#define QT602240_FRAME_CRC_CHECK	0x02
+#define QT602240_FRAME_CRC_FAIL		0x03
+#define QT602240_FRAME_CRC_PASS		0x04
+#define QT602240_APP_CRC_FAIL		0x40	/* valid 7 8 bit only */
+#define QT602240_BOOT_STATUS_MASK	0x3f
+
+/* Touch status */
+#define QT602240_SUPPRESS		(1 << 1)
+#define QT602240_AMP			(1 << 2)
+#define QT602240_VECTOR			(1 << 3)
+#define QT602240_MOVE			(1 << 4)
+#define QT602240_RELEASE		(1 << 5)
+#define QT602240_PRESS			(1 << 6)
+#define QT602240_DETECT			(1 << 7)
+
+/* Touchscreen absolute values */
+#define QT602240_MAX_XC			0x3ff
+#define QT602240_MAX_YC			0x3ff
+#define QT602240_MAX_AREA		0xff
+
+#define QT602240_MAX_FINGER		10
+
+/* Initial register values recommended from chip vendor */
+static const u8 init_vals_ver_20[] = {
+	/* QT602240_GEN_COMMAND(6) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_GEN_POWER(7) */
+	0x20, 0xff, 0x32,
+	/* QT602240_GEN_ACQUIRE(8) */
+	0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14,
+	/* QT602240_TOUCH_MULTI(9) */
+	0x00, 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00,
+	0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x64,
+	/* QT602240_TOUCH_KEYARRAY(15) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00,
+	/* QT602240_SPT_GPIOPWM(19) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+	/* QT602240_PROCI_GRIPFACE(20) */
+	0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x1e, 0x14, 0x04,
+	0x1e, 0x00,
+	/* QT602240_PROCG_NOISE(22) */
+	0x05, 0x00, 0x00, 0x19, 0x00, 0xe7, 0xff, 0x04, 0x32, 0x00,
+	0x01, 0x0a, 0x0f, 0x14, 0x00, 0x00, 0xe8,
+	/* QT602240_TOUCH_PROXIMITY(23) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00,
+	/* QT602240_PROCI_ONETOUCH(24) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_SPT_SELFTEST(25) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	/* QT602240_PROCI_TWOTOUCH(27) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_SPT_CTECONFIG(28) */
+	0x00, 0x00, 0x00, 0x04, 0x08,
+};
+
+static const u8 init_vals_ver_21[] = {
+	/* QT602240_GEN_COMMAND(6) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_GEN_POWER(7) */
+	0x20, 0xff, 0x32,
+	/* QT602240_GEN_ACQUIRE(8) */
+	0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23,
+	/* QT602240_TOUCH_MULTI(9) */
+	0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00,
+	0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_TOUCH_KEYARRAY(15) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00,
+	/* QT602240_SPT_GPIOPWM(19) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_PROCI_GRIPFACE(20) */
+	0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04,
+	0x0f, 0x0a,
+	/* QT602240_PROCG_NOISE(22) */
+	0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00,
+	0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03,
+	/* QT602240_TOUCH_PROXIMITY(23) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00,
+	/* QT602240_PROCI_ONETOUCH(24) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_SPT_SELFTEST(25) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	/* QT602240_PROCI_TWOTOUCH(27) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_SPT_CTECONFIG(28) */
+	0x00, 0x00, 0x00, 0x08, 0x10, 0x00,
+};
+
+static const u8 init_vals_ver_22[] = {
+	/* QT602240_GEN_COMMAND(6) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_GEN_POWER(7) */
+	0x20, 0xff, 0x32,
+	/* QT602240_GEN_ACQUIRE(8) */
+	0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23,
+	/* QT602240_TOUCH_MULTI(9) */
+	0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00,
+	0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00,
+	/* QT602240_TOUCH_KEYARRAY(15) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00,
+	/* QT602240_SPT_GPIOPWM(19) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_PROCI_GRIPFACE(20) */
+	0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04,
+	0x0f, 0x0a,
+	/* QT602240_PROCG_NOISE(22) */
+	0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00,
+	0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03,
+	/* QT602240_TOUCH_PROXIMITY(23) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_PROCI_ONETOUCH(24) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_SPT_SELFTEST(25) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	/* QT602240_PROCI_TWOTOUCH(27) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_SPT_CTECONFIG(28) */
+	0x00, 0x00, 0x00, 0x08, 0x10, 0x00,
+};
+
+struct qt602240_info {
+	u8 family_id;
+	u8 variant_id;
+	u8 version;
+	u8 build;
+	u8 matrix_xsize;
+	u8 matrix_ysize;
+	u8 object_num;
+};
+
+struct qt602240_object {
+	u8 type;
+	u16 start_address;
+	u8 size;
+	u8 instances;
+	u8 num_report_ids;
+
+	/* to map object and message */
+	u8 max_reportid;
+};
+
+struct qt602240_message {
+	u8 reportid;
+	u8 message[7];
+	u8 checksum;
+};
+
+struct qt602240_finger {
+	int status;
+	int x;
+	int y;
+	int area;
+};
+
+/* Each client has this additional data */
+struct qt602240_data {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	const struct qt602240_platform_data *pdata;
+	struct qt602240_object *object_table;
+	struct qt602240_info info;
+	struct qt602240_finger finger[QT602240_MAX_FINGER];
+	unsigned int irq;
+};
+
+static bool qt602240_object_readable(unsigned int type)
+{
+	switch (type) {
+	case QT602240_GEN_MESSAGE:
+	case QT602240_GEN_COMMAND:
+	case QT602240_GEN_POWER:
+	case QT602240_GEN_ACQUIRE:
+	case QT602240_TOUCH_MULTI:
+	case QT602240_TOUCH_KEYARRAY:
+	case QT602240_TOUCH_PROXIMITY:
+	case QT602240_PROCI_GRIPFACE:
+	case QT602240_PROCG_NOISE:
+	case QT602240_PROCI_ONETOUCH:
+	case QT602240_PROCI_TWOTOUCH:
+	case QT602240_SPT_COMMSCONFIG:
+	case QT602240_SPT_GPIOPWM:
+	case QT602240_SPT_SELFTEST:
+	case QT602240_SPT_CTECONFIG:
+	case QT602240_SPT_USERDATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool qt602240_object_writable(unsigned int type)
+{
+	switch (type) {
+	case QT602240_GEN_COMMAND:
+	case QT602240_GEN_POWER:
+	case QT602240_GEN_ACQUIRE:
+	case QT602240_TOUCH_MULTI:
+	case QT602240_TOUCH_KEYARRAY:
+	case QT602240_TOUCH_PROXIMITY:
+	case QT602240_PROCI_GRIPFACE:
+	case QT602240_PROCG_NOISE:
+	case QT602240_PROCI_ONETOUCH:
+	case QT602240_PROCI_TWOTOUCH:
+	case QT602240_SPT_GPIOPWM:
+	case QT602240_SPT_SELFTEST:
+	case QT602240_SPT_CTECONFIG:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void qt602240_dump_message(struct device *dev,
+				  struct qt602240_message *message)
+{
+	dev_dbg(dev, "reportid:\t0x%x\n", message->reportid);
+	dev_dbg(dev, "message1:\t0x%x\n", message->message[0]);
+	dev_dbg(dev, "message2:\t0x%x\n", message->message[1]);
+	dev_dbg(dev, "message3:\t0x%x\n", message->message[2]);
+	dev_dbg(dev, "message4:\t0x%x\n", message->message[3]);
+	dev_dbg(dev, "message5:\t0x%x\n", message->message[4]);
+	dev_dbg(dev, "message6:\t0x%x\n", message->message[5]);
+	dev_dbg(dev, "message7:\t0x%x\n", message->message[6]);
+	dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
+}
+
+static int qt602240_check_bootloader(struct i2c_client *client,
+				     unsigned int state)
+{
+	u8 val;
+
+recheck:
+	if (i2c_master_recv(client, &val, 1) != 1) {
+		dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
+		return -EIO;
+	}
+
+	switch (state) {
+	case QT602240_WAITING_BOOTLOAD_CMD:
+	case QT602240_WAITING_FRAME_DATA:
+		val &= ~QT602240_BOOT_STATUS_MASK;
+		break;
+	case QT602240_FRAME_CRC_PASS:
+		if (val == QT602240_FRAME_CRC_CHECK)
+			goto recheck;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (val != state) {
+		dev_err(&client->dev, "Unvalid bootloader mode state\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int qt602240_unlock_bootloader(struct i2c_client *client)
+{
+	u8 buf[2];
+
+	buf[0] = QT602240_UNLOCK_CMD_LSB;
+	buf[1] = QT602240_UNLOCK_CMD_MSB;
+
+	if (i2c_master_send(client, buf, 2) != 2) {
+		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int qt602240_fw_write(struct i2c_client *client,
+			     const u8 *data, unsigned int frame_size)
+{
+	if (i2c_master_send(client, data, frame_size) != frame_size) {
+		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int __qt602240_read_reg(struct i2c_client *client,
+			       u16 reg, u16 len, void *val)
+{
+	struct i2c_msg xfer[2];
+	u8 buf[2];
+
+	buf[0] = reg & 0xff;
+	buf[1] = (reg >> 8) & 0xff;
+
+	/* Write register */
+	xfer[0].addr = client->addr;
+	xfer[0].flags = 0;
+	xfer[0].len = 2;
+	xfer[0].buf = buf;
+
+	/* Read data */
+	xfer[1].addr = client->addr;
+	xfer[1].flags = I2C_M_RD;
+	xfer[1].len = len;
+	xfer[1].buf = val;
+
+	if (i2c_transfer(client->adapter, xfer, 2) != 2) {
+		dev_err(&client->dev, "%s: i2c transfer failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int qt602240_read_reg(struct i2c_client *client, u16 reg, u8 *val)
+{
+	return __qt602240_read_reg(client, reg, 1, val);
+}
+
+static int qt602240_write_reg(struct i2c_client *client, u16 reg, u8 val)
+{
+	u8 buf[3];
+
+	buf[0] = reg & 0xff;
+	buf[1] = (reg >> 8) & 0xff;
+	buf[2] = val;
+
+	if (i2c_master_send(client, buf, 3) != 3) {
+		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int qt602240_read_object_table(struct i2c_client *client,
+				      u16 reg, u8 *object_buf)
+{
+	return __qt602240_read_reg(client, reg, QT602240_OBJECT_SIZE,
+				   object_buf);
+}
+
+static struct qt602240_object *
+qt602240_get_object(struct qt602240_data *data, u8 type)
+{
+	struct qt602240_object *object;
+	int i;
+
+	for (i = 0; i < data->info.object_num; i++) {
+		object = data->object_table + i;
+		if (object->type == type)
+			return object;
+	}
+
+	dev_err(&data->client->dev, "Invalid object type\n");
+	return NULL;
+}
+
+static int qt602240_read_message(struct qt602240_data *data,
+				 struct qt602240_message *message)
+{
+	struct qt602240_object *object;
+	u16 reg;
+
+	object = qt602240_get_object(data, QT602240_GEN_MESSAGE);
+	if (!object)
+		return -EINVAL;
+
+	reg = object->start_address;
+	return __qt602240_read_reg(data->client, reg,
+			sizeof(struct qt602240_message), message);
+}
+
+static int qt602240_read_object(struct qt602240_data *data,
+				u8 type, u8 offset, u8 *val)
+{
+	struct qt602240_object *object;
+	u16 reg;
+
+	object = qt602240_get_object(data, type);
+	if (!object)
+		return -EINVAL;
+
+	reg = object->start_address;
+	return __qt602240_read_reg(data->client, reg + offset, 1, val);
+}
+
+static int qt602240_write_object(struct qt602240_data *data,
+				 u8 type, u8 offset, u8 val)
+{
+	struct qt602240_object *object;
+	u16 reg;
+
+	object = qt602240_get_object(data, type);
+	if (!object)
+		return -EINVAL;
+
+	reg = object->start_address;
+	return qt602240_write_reg(data->client, reg + offset, val);
+}
+
+static void qt602240_input_report(struct qt602240_data *data, int single_id)
+{
+	struct qt602240_finger *finger = data->finger;
+	struct input_dev *input_dev = data->input_dev;
+	int status = finger[single_id].status;
+	int finger_num = 0;
+	int id;
+
+	for (id = 0; id < QT602240_MAX_FINGER; id++) {
+		if (!finger[id].status)
+			continue;
+
+		input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+				finger[id].status != QT602240_RELEASE ?
+				finger[id].area : 0);
+		input_report_abs(input_dev, ABS_MT_POSITION_X,
+				finger[id].x);
+		input_report_abs(input_dev, ABS_MT_POSITION_Y,
+				finger[id].y);
+		input_mt_sync(input_dev);
+
+		if (finger[id].status == QT602240_RELEASE)
+			finger[id].status = 0;
+		else
+			finger_num++;
+	}
+
+	input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
+
+	if (status != QT602240_RELEASE) {
+		input_report_abs(input_dev, ABS_X, finger[single_id].x);
+		input_report_abs(input_dev, ABS_Y, finger[single_id].y);
+	}
+
+	input_sync(input_dev);
+}
+
+static void qt602240_input_touchevent(struct qt602240_data *data,
+				      struct qt602240_message *message, int id)
+{
+	struct qt602240_finger *finger = data->finger;
+	struct device *dev = &data->client->dev;
+	u8 status = message->message[0];
+	int x;
+	int y;
+	int area;
+
+	/* Check the touch is present on the screen */
+	if (!(status & QT602240_DETECT)) {
+		if (status & QT602240_RELEASE) {
+			dev_dbg(dev, "[%d] released\n", id);
+
+			finger[id].status = QT602240_RELEASE;
+			qt602240_input_report(data, id);
+		}
+		return;
+	}
+
+	/* Check only AMP detection */
+	if (!(status & (QT602240_PRESS | QT602240_MOVE)))
+		return;
+
+	x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6);
+	y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2);
+	area = message->message[4];
+
+	dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
+		status & QT602240_MOVE ? "moved" : "pressed",
+		x, y, area);
+
+	finger[id].status = status & QT602240_MOVE ?
+				QT602240_MOVE : QT602240_PRESS;
+	finger[id].x = x;
+	finger[id].y = y;
+	finger[id].area = area;
+
+	qt602240_input_report(data, id);
+}
+
+static irqreturn_t qt602240_interrupt(int irq, void *dev_id)
+{
+	struct qt602240_data *data = dev_id;
+	struct qt602240_message message;
+	struct qt602240_object *object;
+	struct device *dev = &data->client->dev;
+	int id;
+	u8 reportid;
+	u8 max_reportid;
+	u8 min_reportid;
+
+	do {
+		if (qt602240_read_message(data, &message)) {
+			dev_err(dev, "Failed to read message\n");
+			goto end;
+		}
+
+		reportid = message.reportid;
+
+		/* whether reportid is thing of QT602240_TOUCH_MULTI */
+		object = qt602240_get_object(data, QT602240_TOUCH_MULTI);
+		if (!object)
+			goto end;
+
+		max_reportid = object->max_reportid;
+		min_reportid = max_reportid - object->num_report_ids + 1;
+		id = reportid - min_reportid;
+
+		if (reportid >= min_reportid && reportid <= max_reportid)
+			qt602240_input_touchevent(data, &message, id);
+		else
+			qt602240_dump_message(dev, &message);
+	} while (reportid != 0xff);
+
+end:
+	return IRQ_HANDLED;
+}
+
+static int qt602240_check_reg_init(struct qt602240_data *data)
+{
+	struct qt602240_object *object;
+	struct device *dev = &data->client->dev;
+	int index = 0;
+	int i, j;
+	u8 version = data->info.version;
+	u8 *init_vals;
+
+	switch (version) {
+	case QT602240_VER_20:
+		init_vals = (u8 *)init_vals_ver_20;
+		break;
+	case QT602240_VER_21:
+		init_vals = (u8 *)init_vals_ver_21;
+		break;
+	case QT602240_VER_22:
+		init_vals = (u8 *)init_vals_ver_22;
+		break;
+	default:
+		dev_err(dev, "Firmware version %d doesn't support\n", version);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < data->info.object_num; i++) {
+		object = data->object_table + i;
+
+		if (!qt602240_object_writable(object->type))
+			continue;
+
+		for (j = 0; j < object->size + 1; j++)
+			qt602240_write_object(data, object->type, j,
+					init_vals[index + j]);
+
+		index += object->size + 1;
+	}
+
+	return 0;
+}
+
+static int qt602240_check_matrix_size(struct qt602240_data *data)
+{
+	const struct qt602240_platform_data *pdata = data->pdata;
+	struct device *dev = &data->client->dev;
+	int mode = -1;
+	int error;
+	u8 val;
+
+	dev_dbg(dev, "Number of X lines: %d\n", pdata->x_line);
+	dev_dbg(dev, "Number of Y lines: %d\n", pdata->y_line);
+
+	switch (pdata->x_line) {
+	case 0 ... 15:
+		if (pdata->y_line <= 14)
+			mode = 0;
+		break;
+	case 16:
+		if (pdata->y_line <= 12)
+			mode = 1;
+		if (pdata->y_line == 13 || pdata->y_line == 14)
+			mode = 0;
+		break;
+	case 17:
+		if (pdata->y_line <= 11)
+			mode = 2;
+		if (pdata->y_line == 12 || pdata->y_line == 13)
+			mode = 1;
+		break;
+	case 18:
+		if (pdata->y_line <= 10)
+			mode = 3;
+		if (pdata->y_line == 11 || pdata->y_line == 12)
+			mode = 2;
+		break;
+	case 19:
+		if (pdata->y_line <= 9)
+			mode = 4;
+		if (pdata->y_line == 10 || pdata->y_line == 11)
+			mode = 3;
+		break;
+	case 20:
+		mode = 4;
+	}
+
+	if (mode < 0) {
+		dev_err(dev, "Invalid X/Y lines\n");
+		return -EINVAL;
+	}
+
+	error = qt602240_read_object(data, QT602240_SPT_CTECONFIG,
+				QT602240_CTE_MODE, &val);
+	if (error)
+		return error;
+
+	if (mode == val)
+		return 0;
+
+	/* Change the CTE configuration */
+	qt602240_write_object(data, QT602240_SPT_CTECONFIG,
+			QT602240_CTE_CTRL, 1);
+	qt602240_write_object(data, QT602240_SPT_CTECONFIG,
+			QT602240_CTE_MODE, mode);
+	qt602240_write_object(data, QT602240_SPT_CTECONFIG,
+			QT602240_CTE_CTRL, 0);
+
+	return 0;
+}
+
+static int qt602240_make_highchg(struct qt602240_data *data)
+{
+	struct device *dev = &data->client->dev;
+	int count = 10;
+	int error;
+	u8 val;
+
+	/* Read dummy message to make high CHG pin */
+	do {
+		error = qt602240_read_object(data, QT602240_GEN_MESSAGE, 0, &val);
+		if (error)
+			return error;
+	} while ((val != 0xff) && --count);
+
+	if (!count) {
+		dev_err(dev, "CHG pin isn't cleared\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void qt602240_handle_pdata(struct qt602240_data *data)
+{
+	const struct qt602240_platform_data *pdata = data->pdata;
+	u8 voltage;
+
+	/* Set touchscreen lines */
+	qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_XSIZE,
+			pdata->x_line);
+	qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_YSIZE,
+			pdata->y_line);
+
+	/* Set touchscreen orient */
+	qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_ORIENT,
+			pdata->orient);
+
+	/* Set touchscreen burst length */
+	qt602240_write_object(data, QT602240_TOUCH_MULTI,
+			QT602240_TOUCH_BLEN, pdata->blen);
+
+	/* Set touchscreen threshold */
+	qt602240_write_object(data, QT602240_TOUCH_MULTI,
+			QT602240_TOUCH_TCHTHR, pdata->threshold);
+
+	/* Set touchscreen resolution */
+	qt602240_write_object(data, QT602240_TOUCH_MULTI,
+			QT602240_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff);
+	qt602240_write_object(data, QT602240_TOUCH_MULTI,
+			QT602240_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8);
+	qt602240_write_object(data, QT602240_TOUCH_MULTI,
+			QT602240_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff);
+	qt602240_write_object(data, QT602240_TOUCH_MULTI,
+			QT602240_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8);
+
+	/* Set touchscreen voltage */
+	if (data->info.version >= QT602240_VER_21 && pdata->voltage) {
+		if (pdata->voltage < QT602240_VOLTAGE_DEFAULT) {
+			voltage = (QT602240_VOLTAGE_DEFAULT - pdata->voltage) /
+				QT602240_VOLTAGE_STEP;
+			voltage = 0xff - voltage + 1;
+		} else
+			voltage = (pdata->voltage - QT602240_VOLTAGE_DEFAULT) /
+				QT602240_VOLTAGE_STEP;
+
+		qt602240_write_object(data, QT602240_SPT_CTECONFIG,
+				QT602240_CTE_VOLTAGE, voltage);
+	}
+}
+
+static int qt602240_get_info(struct qt602240_data *data)
+{
+	struct i2c_client *client = data->client;
+	struct qt602240_info *info = &data->info;
+	int error;
+	u8 val;
+
+	error = qt602240_read_reg(client, QT602240_FAMILY_ID, &val);
+	if (error)
+		return error;
+	info->family_id = val;
+
+	error = qt602240_read_reg(client, QT602240_VARIANT_ID, &val);
+	if (error)
+		return error;
+	info->variant_id = val;
+
+	error = qt602240_read_reg(client, QT602240_VERSION, &val);
+	if (error)
+		return error;
+	info->version = val;
+
+	error = qt602240_read_reg(client, QT602240_BUILD, &val);
+	if (error)
+		return error;
+	info->build = val;
+
+	error = qt602240_read_reg(client, QT602240_OBJECT_NUM, &val);
+	if (error)
+		return error;
+	info->object_num = val;
+
+	return 0;
+}
+
+static int qt602240_get_object_table(struct qt602240_data *data)
+{
+	int error;
+	int i;
+	u16 reg;
+	u8 reportid = 0;
+	u8 buf[QT602240_OBJECT_SIZE];
+
+	for (i = 0; i < data->info.object_num; i++) {
+		struct qt602240_object *object = data->object_table + i;
+
+		reg = QT602240_OBJECT_START + QT602240_OBJECT_SIZE * i;
+		error = qt602240_read_object_table(data->client, reg, buf);
+		if (error)
+			return error;
+
+		object->type = buf[0];
+		object->start_address = (buf[2] << 8) | buf[1];
+		object->size = buf[3];
+		object->instances = buf[4];
+		object->num_report_ids = buf[5];
+
+		if (object->num_report_ids) {
+			reportid += object->num_report_ids *
+					(object->instances + 1);
+			object->max_reportid = reportid;
+		}
+	}
+
+	return 0;
+}
+
+static int qt602240_initialize(struct qt602240_data *data)
+{
+	struct i2c_client *client = data->client;
+	struct qt602240_info *info = &data->info;
+	int error;
+	u8 val;
+
+	error = qt602240_get_info(data);
+	if (error)
+		return error;
+
+	data->object_table = kcalloc(info->object_num,
+				     sizeof(struct qt602240_data),
+				     GFP_KERNEL);
+	if (!data->object_table) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	/* Get object table information */
+	error = qt602240_get_object_table(data);
+	if (error)
+		return error;
+
+	/* Check register init values */
+	error = qt602240_check_reg_init(data);
+	if (error)
+		return error;
+
+	/* Check X/Y matrix size */
+	error = qt602240_check_matrix_size(data);
+	if (error)
+		return error;
+
+	error = qt602240_make_highchg(data);
+	if (error)
+		return error;
+
+	qt602240_handle_pdata(data);
+
+	/* Backup to memory */
+	qt602240_write_object(data, QT602240_GEN_COMMAND,
+			QT602240_COMMAND_BACKUPNV,
+			QT602240_BACKUP_VALUE);
+	msleep(QT602240_BACKUP_TIME);
+
+	/* Soft reset */
+	qt602240_write_object(data, QT602240_GEN_COMMAND,
+			QT602240_COMMAND_RESET, 1);
+	msleep(QT602240_RESET_TIME);
+
+	/* Update matrix size at info struct */
+	error = qt602240_read_reg(client, QT602240_MATRIX_X_SIZE, &val);
+	if (error)
+		return error;
+	info->matrix_xsize = val;
+
+	error = qt602240_read_reg(client, QT602240_MATRIX_Y_SIZE, &val);
+	if (error)
+		return error;
+	info->matrix_ysize = val;
+
+	dev_info(&client->dev,
+			"Family ID: %d Variant ID: %d Version: %d Build: %d\n",
+			info->family_id, info->variant_id, info->version,
+			info->build);
+
+	dev_info(&client->dev,
+			"Matrix X Size: %d Matrix Y Size: %d Object Num: %d\n",
+			info->matrix_xsize, info->matrix_ysize,
+			info->object_num);
+
+	return 0;
+}
+
+static ssize_t qt602240_object_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct qt602240_data *data = dev_get_drvdata(dev);
+	struct qt602240_object *object;
+	int count = 0;
+	int i, j;
+	int error;
+	u8 val;
+
+	for (i = 0; i < data->info.object_num; i++) {
+		object = data->object_table + i;
+
+		count += sprintf(buf + count,
+				"Object Table Element %d(Type %d)\n",
+				i + 1, object->type);
+
+		if (!qt602240_object_readable(object->type)) {
+			count += sprintf(buf + count, "\n");
+			continue;
+		}
+
+		for (j = 0; j < object->size + 1; j++) {
+			error = qt602240_read_object(data,
+						object->type, j, &val);
+			if (error)
+				return error;
+
+			count += sprintf(buf + count,
+					"  Byte %d: 0x%x (%d)\n", j, val, val);
+		}
+
+		count += sprintf(buf + count, "\n");
+	}
+
+	return count;
+}
+
+static int qt602240_load_fw(struct device *dev, const char *fn)
+{
+	struct qt602240_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	const struct firmware *fw = NULL;
+	unsigned int frame_size;
+	unsigned int pos = 0;
+	int ret;
+
+	ret = request_firmware(&fw, fn, dev);
+	if (ret) {
+		dev_err(dev, "Unable to open firmware %s\n", fn);
+		return ret;
+	}
+
+	/* Change to the bootloader mode */
+	qt602240_write_object(data, QT602240_GEN_COMMAND,
+			QT602240_COMMAND_RESET, QT602240_BOOT_VALUE);
+	msleep(QT602240_RESET_TIME);
+
+	/* Change to slave address of bootloader */
+	if (client->addr == QT602240_APP_LOW)
+		client->addr = QT602240_BOOT_LOW;
+	else
+		client->addr = QT602240_BOOT_HIGH;
+
+	ret = qt602240_check_bootloader(client, QT602240_WAITING_BOOTLOAD_CMD);
+	if (ret)
+		goto out;
+
+	/* Unlock bootloader */
+	qt602240_unlock_bootloader(client);
+
+	while (pos < fw->size) {
+		ret = qt602240_check_bootloader(client,
+						QT602240_WAITING_FRAME_DATA);
+		if (ret)
+			goto out;
+
+		frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
+
+		/* We should add 2 at frame size as the the firmware data is not
+		 * included the CRC bytes.
+		 */
+		frame_size += 2;
+
+		/* Write one frame to device */
+		qt602240_fw_write(client, fw->data + pos, frame_size);
+
+		ret = qt602240_check_bootloader(client,
+						QT602240_FRAME_CRC_PASS);
+		if (ret)
+			goto out;
+
+		pos += frame_size;
+
+		dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
+	}
+
+out:
+	release_firmware(fw);
+
+	/* Change to slave address of application */
+	if (client->addr == QT602240_BOOT_LOW)
+		client->addr = QT602240_APP_LOW;
+	else
+		client->addr = QT602240_APP_HIGH;
+
+	return ret;
+}
+
+static ssize_t qt602240_update_fw_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct qt602240_data *data = dev_get_drvdata(dev);
+	unsigned int version;
+	int error;
+
+	if (sscanf(buf, "%u", &version) != 1) {
+		dev_err(dev, "Invalid values\n");
+		return -EINVAL;
+	}
+
+	if (data->info.version < QT602240_VER_21 || version < QT602240_VER_21) {
+		dev_err(dev, "FW update supported starting with version 21\n");
+		return -EINVAL;
+	}
+
+	disable_irq(data->irq);
+
+	error = qt602240_load_fw(dev, QT602240_FW_NAME);
+	if (error) {
+		dev_err(dev, "The firmware update failed(%d)\n", error);
+		count = error;
+	} else {
+		dev_dbg(dev, "The firmware update succeeded\n");
+
+		/* Wait for reset */
+		msleep(QT602240_FWRESET_TIME);
+
+		kfree(data->object_table);
+		data->object_table = NULL;
+
+		qt602240_initialize(data);
+	}
+
+	enable_irq(data->irq);
+
+	return count;
+}
+
+static DEVICE_ATTR(object, 0444, qt602240_object_show, NULL);
+static DEVICE_ATTR(update_fw, 0664, NULL, qt602240_update_fw_store);
+
+static struct attribute *qt602240_attrs[] = {
+	&dev_attr_object.attr,
+	&dev_attr_update_fw.attr,
+	NULL
+};
+
+static const struct attribute_group qt602240_attr_group = {
+	.attrs = qt602240_attrs,
+};
+
+static void qt602240_start(struct qt602240_data *data)
+{
+	/* Touch enable */
+	qt602240_write_object(data,
+			QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0x83);
+}
+
+static void qt602240_stop(struct qt602240_data *data)
+{
+	/* Touch disable */
+	qt602240_write_object(data,
+			QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0);
+}
+
+static int qt602240_input_open(struct input_dev *dev)
+{
+	struct qt602240_data *data = input_get_drvdata(dev);
+
+	qt602240_start(data);
+
+	return 0;
+}
+
+static void qt602240_input_close(struct input_dev *dev)
+{
+	struct qt602240_data *data = input_get_drvdata(dev);
+
+	qt602240_stop(data);
+}
+
+static int __devinit qt602240_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct qt602240_data *data;
+	struct input_dev *input_dev;
+	int error;
+
+	if (!client->dev.platform_data)
+		return -EINVAL;
+
+	data = kzalloc(sizeof(struct qt602240_data), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!data || !input_dev) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	input_dev->name = "AT42QT602240/ATMXT224 Touchscreen";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+	input_dev->open = qt602240_input_open;
+	input_dev->close = qt602240_input_close;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+
+	/* For single touch */
+	input_set_abs_params(input_dev, ABS_X,
+			     0, QT602240_MAX_XC, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y,
+			     0, QT602240_MAX_YC, 0, 0);
+
+	/* For multi touch */
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+			     0, QT602240_MAX_AREA, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+			     0, QT602240_MAX_XC, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+			     0, QT602240_MAX_YC, 0, 0);
+
+	input_set_drvdata(input_dev, data);
+
+	data->client = client;
+	data->input_dev = input_dev;
+	data->pdata = client->dev.platform_data;
+	data->irq = client->irq;
+
+	i2c_set_clientdata(client, data);
+
+	error = qt602240_initialize(data);
+	if (error)
+		goto err_free_object;
+
+	error = request_threaded_irq(client->irq, NULL, qt602240_interrupt,
+			IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
+	if (error) {
+		dev_err(&client->dev, "Failed to register interrupt\n");
+		goto err_free_object;
+	}
+
+	error = input_register_device(input_dev);
+	if (error)
+		goto err_free_irq;
+
+	error = sysfs_create_group(&client->dev.kobj, &qt602240_attr_group);
+	if (error)
+		goto err_unregister_device;
+
+	return 0;
+
+err_unregister_device:
+	input_unregister_device(input_dev);
+	input_dev = NULL;
+err_free_irq:
+	free_irq(client->irq, data);
+err_free_object:
+	kfree(data->object_table);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(data);
+	return error;
+}
+
+static int __devexit qt602240_remove(struct i2c_client *client)
+{
+	struct qt602240_data *data = i2c_get_clientdata(client);
+
+	sysfs_remove_group(&client->dev.kobj, &qt602240_attr_group);
+	free_irq(data->irq, data);
+	input_unregister_device(data->input_dev);
+	kfree(data->object_table);
+	kfree(data);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int qt602240_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct qt602240_data *data = i2c_get_clientdata(client);
+	struct input_dev *input_dev = data->input_dev;
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users)
+		qt602240_stop(data);
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+
+static int qt602240_resume(struct i2c_client *client)
+{
+	struct qt602240_data *data = i2c_get_clientdata(client);
+	struct input_dev *input_dev = data->input_dev;
+
+	/* Soft reset */
+	qt602240_write_object(data, QT602240_GEN_COMMAND,
+			QT602240_COMMAND_RESET, 1);
+
+	msleep(QT602240_RESET_TIME);
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users)
+		qt602240_start(data);
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+#else
+#define qt602240_suspend	NULL
+#define qt602240_resume		NULL
+#endif
+
+static const struct i2c_device_id qt602240_id[] = {
+	{ "qt602240_ts", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, qt602240_id);
+
+static struct i2c_driver qt602240_driver = {
+	.driver = {
+		.name	= "qt602240_ts",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= qt602240_probe,
+	.remove		= __devexit_p(qt602240_remove),
+	.suspend	= qt602240_suspend,
+	.resume		= qt602240_resume,
+	.id_table	= qt602240_id,
+};
+
+static int __init qt602240_init(void)
+{
+	return i2c_add_driver(&qt602240_driver);
+}
+
+static void __exit qt602240_exit(void)
+{
+	i2c_del_driver(&qt602240_driver);
+}
+
+module_init(qt602240_init);
+module_exit(qt602240_exit);
+
+/* Module information */
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_DESCRIPTION("AT42QT602240/ATMXT224 Touchscreen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c
index 5b70a14..a644d18 100644
--- a/drivers/input/touchscreen/tps6507x-ts.c
+++ b/drivers/input/touchscreen/tps6507x-ts.c
@@ -355,9 +355,6 @@
 	struct tps6507x_ts *tsc = tps6507x_dev->ts;
 	struct input_dev *input_dev = tsc->input_dev;
 
-	if (!tsc)
-		return 0;
-
 	cancel_delayed_work_sync(&tsc->work);
 	destroy_workqueue(tsc->wq);
 
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 567d572..f45f80f 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -95,6 +95,7 @@
 	int  (*get_pkt_len) (unsigned char *pkt, int len);
 
 	int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);
+	int  (*alloc)       (struct usbtouch_usb *usbtouch);
 	int  (*init)        (struct usbtouch_usb *usbtouch);
 	void (*exit)	    (struct usbtouch_usb *usbtouch);
 };
@@ -135,7 +136,7 @@
 	DEVTYPE_JASTEC,
 	DEVTYPE_E2I,
 	DEVTYPE_ZYTRONIC,
-	DEVTYPE_TC5UH,
+	DEVTYPE_TC45USB,
 	DEVTYPE_NEXIO,
 };
 
@@ -222,8 +223,11 @@
 	{USB_DEVICE(0x14c8, 0x0003), .driver_info = DEVTYPE_ZYTRONIC},
 #endif
 
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
-	{USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH},
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+	/* TC5UH */
+	{USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC45USB},
+	/* TC4UM */
+	{USB_DEVICE(0x0664, 0x0306), .driver_info = DEVTYPE_TC45USB},
 #endif
 
 #ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
@@ -507,7 +511,7 @@
 	int ret = -ENOMEM;
 	unsigned char *buf;
 
-	buf = kmalloc(2, GFP_KERNEL);
+	buf = kmalloc(2, GFP_NOIO);
 	if (!buf)
 		goto err_nobuf;
 	/* reset */
@@ -574,10 +578,10 @@
 #endif
 
 /*****************************************************************************
- * ET&T TC5UH part
+ * ET&T TC5UH/TC4UM part
  */
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
-static int tc5uh_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+static int tc45usb_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 {
 	dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
 	dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
@@ -732,11 +736,43 @@
 {
 }
 
+static int nexio_alloc(struct usbtouch_usb *usbtouch)
+{
+	struct nexio_priv *priv;
+	int ret = -ENOMEM;
+
+	usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
+	if (!usbtouch->priv)
+		goto out_buf;
+
+	priv = usbtouch->priv;
+
+	priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt),
+				GFP_KERNEL);
+	if (!priv->ack_buf)
+		goto err_priv;
+
+	priv->ack = usb_alloc_urb(0, GFP_KERNEL);
+	if (!priv->ack) {
+		dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
+		goto err_ack_buf;
+	}
+
+	return 0;
+
+err_ack_buf:
+	kfree(priv->ack_buf);
+err_priv:
+	kfree(priv);
+out_buf:
+	return ret;
+}
+
 static int nexio_init(struct usbtouch_usb *usbtouch)
 {
 	struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
 	struct usb_host_interface *interface = usbtouch->interface->cur_altsetting;
-	struct nexio_priv *priv;
+	struct nexio_priv *priv = usbtouch->priv;
 	int ret = -ENOMEM;
 	int actual_len, i;
 	unsigned char *buf;
@@ -755,7 +791,7 @@
 	if (!input_ep || !output_ep)
 		return -ENXIO;
 
-	buf = kmalloc(NEXIO_BUFSIZE, GFP_KERNEL);
+	buf = kmalloc(NEXIO_BUFSIZE, GFP_NOIO);
 	if (!buf)
 		goto out_buf;
 
@@ -787,11 +823,11 @@
 		switch (buf[0]) {
 		case 0x83:	/* firmware version */
 			if (!firmware_ver)
-				firmware_ver = kstrdup(&buf[2], GFP_KERNEL);
+				firmware_ver = kstrdup(&buf[2], GFP_NOIO);
 			break;
 		case 0x84:	/* device name */
 			if (!device_name)
-				device_name = kstrdup(&buf[2], GFP_KERNEL);
+				device_name = kstrdup(&buf[2], GFP_NOIO);
 			break;
 		}
 	}
@@ -802,36 +838,11 @@
 	kfree(firmware_ver);
 	kfree(device_name);
 
-	/* prepare ACK URB */
-	ret = -ENOMEM;
-
-	usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
-	if (!usbtouch->priv)
-		goto out_buf;
-
-	priv = usbtouch->priv;
-
-	priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt),
-				GFP_KERNEL);
-	if (!priv->ack_buf)
-		goto err_priv;
-
-	priv->ack = usb_alloc_urb(0, GFP_KERNEL);
-	if (!priv->ack) {
-		dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
-		goto err_ack_buf;
-	}
-
 	usb_fill_bulk_urb(priv->ack, dev, usb_sndbulkpipe(dev, output_ep),
 			  priv->ack_buf, sizeof(nexio_ack_pkt),
 			  nexio_ack_complete, usbtouch);
 	ret = 0;
-	goto out_buf;
 
-err_ack_buf:
-	kfree(priv->ack_buf);
-err_priv:
-	kfree(priv);
 out_buf:
 	kfree(buf);
 	return ret;
@@ -849,29 +860,32 @@
 
 static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
 {
-	int x, y, begin_x, begin_y, end_x, end_y, w, h, ret;
 	struct nexio_touch_packet *packet = (void *) pkt;
 	struct nexio_priv *priv = usbtouch->priv;
+	unsigned int data_len = be16_to_cpu(packet->data_len);
+	unsigned int x_len = be16_to_cpu(packet->x_len);
+	unsigned int y_len = be16_to_cpu(packet->y_len);
+	int x, y, begin_x, begin_y, end_x, end_y, w, h, ret;
 
 	/* got touch data? */
 	if ((pkt[0] & 0xe0) != 0xe0)
 		return 0;
 
-	if (be16_to_cpu(packet->data_len) > 0xff)
-		packet->data_len = cpu_to_be16(be16_to_cpu(packet->data_len) - 0x100);
-	if (be16_to_cpu(packet->x_len) > 0xff)
-		packet->x_len = cpu_to_be16(be16_to_cpu(packet->x_len) - 0x80);
+	if (data_len > 0xff)
+		data_len -= 0x100;
+	if (x_len > 0xff)
+		x_len -= 0x80;
 
 	/* send ACK */
 	ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
 
 	if (!usbtouch->type->max_xc) {
-		usbtouch->type->max_xc = 2 * be16_to_cpu(packet->x_len);
-		input_set_abs_params(usbtouch->input, ABS_X, 0,
-				     2 * be16_to_cpu(packet->x_len), 0, 0);
-		usbtouch->type->max_yc = 2 * be16_to_cpu(packet->y_len);
-		input_set_abs_params(usbtouch->input, ABS_Y, 0,
-				     2 * be16_to_cpu(packet->y_len), 0, 0);
+		usbtouch->type->max_xc = 2 * x_len;
+		input_set_abs_params(usbtouch->input, ABS_X,
+				     0, usbtouch->type->max_xc, 0, 0);
+		usbtouch->type->max_yc = 2 * y_len;
+		input_set_abs_params(usbtouch->input, ABS_Y,
+				     0, usbtouch->type->max_yc, 0, 0);
 	}
 	/*
 	 * The device reports state of IR sensors on X and Y axes.
@@ -881,22 +895,21 @@
 	 * it's disabled (and untested) here as there's no X driver for that.
 	 */
 	begin_x = end_x = begin_y = end_y = -1;
-	for (x = 0; x < be16_to_cpu(packet->x_len); x++) {
+	for (x = 0; x < x_len; x++) {
 		if (begin_x == -1 && packet->data[x] > NEXIO_THRESHOLD) {
 			begin_x = x;
 			continue;
 		}
 		if (end_x == -1 && begin_x != -1 && packet->data[x] < NEXIO_THRESHOLD) {
 			end_x = x - 1;
-			for (y = be16_to_cpu(packet->x_len);
-			     y < be16_to_cpu(packet->data_len); y++) {
+			for (y = x_len; y < data_len; y++) {
 				if (begin_y == -1 && packet->data[y] > NEXIO_THRESHOLD) {
-					begin_y = y - be16_to_cpu(packet->x_len);
+					begin_y = y - x_len;
 					continue;
 				}
 				if (end_y == -1 &&
 				    begin_y != -1 && packet->data[y] < NEXIO_THRESHOLD) {
-					end_y = y - 1 - be16_to_cpu(packet->x_len);
+					end_y = y - 1 - x_len;
 					w = end_x - begin_x;
 					h = end_y - begin_y;
 #if 0
@@ -1104,14 +1117,14 @@
 	},
 #endif
 
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
-	[DEVTYPE_TC5UH] = {
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+	[DEVTYPE_TC45USB] = {
 		.min_xc		= 0x0,
 		.max_xc		= 0x0fff,
 		.min_yc		= 0x0,
 		.max_yc		= 0x0fff,
 		.rept_size	= 5,
-		.read_data	= tc5uh_read_data,
+		.read_data	= tc45usb_read_data,
 	},
 #endif
 
@@ -1120,6 +1133,7 @@
 		.rept_size	= 1024,
 		.irq_always	= true,
 		.read_data	= nexio_read_data,
+		.alloc		= nexio_alloc,
 		.init		= nexio_init,
 		.exit		= nexio_exit,
 	},
@@ -1263,6 +1277,7 @@
 	usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
 
 exit:
+	usb_mark_last_busy(interface_to_usbdev(usbtouch->interface));
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval)
 		err("%s - usb_submit_urb failed with result: %d",
@@ -1272,25 +1287,89 @@
 static int usbtouch_open(struct input_dev *input)
 {
 	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
+	int r;
 
 	usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface);
 
+	r = usb_autopm_get_interface(usbtouch->interface) ? -EIO : 0;
+	if (r < 0)
+		goto out;
+
 	if (!usbtouch->type->irq_always) {
-		if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
-		  return -EIO;
+		if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) {
+			r = -EIO;
+			goto out_put;
+		}
 	}
 
-	return 0;
+	usbtouch->interface->needs_remote_wakeup = 1;
+out_put:
+	usb_autopm_put_interface(usbtouch->interface);
+out:
+	return r;
 }
 
 static void usbtouch_close(struct input_dev *input)
 {
 	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
+	int r;
 
 	if (!usbtouch->type->irq_always)
 		usb_kill_urb(usbtouch->irq);
+	r = usb_autopm_get_interface(usbtouch->interface);
+	usbtouch->interface->needs_remote_wakeup = 0;
+	if (!r)
+		usb_autopm_put_interface(usbtouch->interface);
 }
 
+static int usbtouch_suspend
+(struct usb_interface *intf, pm_message_t message)
+{
+	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+
+	usb_kill_urb(usbtouch->irq);
+
+	return 0;
+}
+
+static int usbtouch_resume(struct usb_interface *intf)
+{
+	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+	struct input_dev *input = usbtouch->input;
+	int result = 0;
+
+	mutex_lock(&input->mutex);
+	if (input->users || usbtouch->type->irq_always)
+		result = usb_submit_urb(usbtouch->irq, GFP_NOIO);
+	mutex_unlock(&input->mutex);
+
+	return result;
+}
+
+static int usbtouch_reset_resume(struct usb_interface *intf)
+{
+	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+	struct input_dev *input = usbtouch->input;
+	int err = 0;
+
+	/* reinit the device */
+	if (usbtouch->type->init) {
+		err = usbtouch->type->init(usbtouch);
+		if (err) {
+			dbg("%s - type->init() failed, err: %d",
+			    __func__, err);
+			return err;
+		}
+	}
+
+	/* restart IO if needed */
+	mutex_lock(&input->mutex);
+	if (input->users)
+		err = usb_submit_urb(usbtouch->irq, GFP_NOIO);
+	mutex_unlock(&input->mutex);
+
+	return err;
+}
 
 static void usbtouch_free_buffers(struct usb_device *udev,
 				  struct usbtouch_usb *usbtouch)
@@ -1411,12 +1490,21 @@
 	usbtouch->irq->transfer_dma = usbtouch->data_dma;
 	usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
-	/* device specific init */
+	/* device specific allocations */
+	if (type->alloc) {
+		err = type->alloc(usbtouch);
+		if (err) {
+			dbg("%s - type->alloc() failed, err: %d", __func__, err);
+			goto out_free_urb;
+		}
+	}
+
+	/* device specific initialisation*/
 	if (type->init) {
 		err = type->init(usbtouch);
 		if (err) {
 			dbg("%s - type->init() failed, err: %d", __func__, err);
-			goto out_free_urb;
+			goto out_do_exit;
 		}
 	}
 
@@ -1429,8 +1517,11 @@
 	usb_set_intfdata(intf, usbtouch);
 
 	if (usbtouch->type->irq_always) {
+		/* this can't fail */
+		usb_autopm_get_interface(intf);
 		err = usb_submit_urb(usbtouch->irq, GFP_KERNEL);
 		if (err) {
+			usb_autopm_put_interface(intf);
 			err("%s - usb_submit_urb failed with result: %d",
 			    __func__, err);
 			goto out_unregister_input;
@@ -1481,7 +1572,11 @@
 	.name		= "usbtouchscreen",
 	.probe		= usbtouch_probe,
 	.disconnect	= usbtouch_disconnect,
+	.suspend	= usbtouch_suspend,
+	.resume		= usbtouch_resume,
+	.reset_resume	= usbtouch_reset_resume,
 	.id_table	= usbtouch_devices,
+	.supports_autosuspend = 1,
 };
 
 static int __init usbtouch_init(void)
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 0cabe31..f80a7c4 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -20,7 +20,6 @@
 #include <linux/signal.h>
 #include <linux/mutex.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/tty.h>
@@ -50,6 +49,7 @@
 
 /* -------- driver information -------------------------------------- */
 
+static DEFINE_MUTEX(capi_mutex);
 static struct class *capi_class;
 static int capi_major = 68;		/* allocated */
 
@@ -691,7 +691,7 @@
 static ssize_t
 capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 {
-	struct capidev *cdev = (struct capidev *)file->private_data;
+	struct capidev *cdev = file->private_data;
 	struct sk_buff *skb;
 	size_t copied;
 	int err;
@@ -726,7 +726,7 @@
 static ssize_t
 capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 {
-	struct capidev *cdev = (struct capidev *)file->private_data;
+	struct capidev *cdev = file->private_data;
 	struct sk_buff *skb;
 	u16 mlen;
 
@@ -773,7 +773,7 @@
 static unsigned int
 capi_poll(struct file *file, poll_table * wait)
 {
-	struct capidev *cdev = (struct capidev *)file->private_data;
+	struct capidev *cdev = file->private_data;
 	unsigned int mask = 0;
 
 	if (!cdev->ap.applid)
@@ -985,9 +985,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&capi_mutex);
 	ret = capi_ioctl(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&capi_mutex);
 
 	return ret;
 }
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index bf55ed5..2978bda 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -1450,12 +1450,9 @@
     	}
 
 	for (p = data, end = data+len; p < end; p++) {
-		u8 w;
 		PUTBYTE_TO_STATUS(card, ' ');
-		w = (*p >> 4) & 0xf;
-		PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
-		w = *p & 0xf;
-		PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
+		PUTBYTE_TO_STATUS(card, hex_asc_hi(*p));
+		PUTBYTE_TO_STATUS(card, hex_asc_lo(*p));
 	}
 	PUTBYTE_TO_STATUS(card, '\n');
 
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index c53e2417..33ec9e4 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -20,7 +20,7 @@
 #include <linux/sched.h>
 #include <linux/isdnif.h>
 #include <net/net_namespace.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include "isdn_divert.h"
 
 
@@ -28,6 +28,7 @@
 /* Variables for interface queue */
 /*********************************/
 ulong if_used = 0;		/* number of interface users */
+static DEFINE_MUTEX(isdn_divert_mutex);
 static struct divert_info *divert_info_head = NULL;	/* head of queue */
 static struct divert_info *divert_info_tail = NULL;	/* pointer to last entry */
 static DEFINE_SPINLOCK(divert_info_lock);/* lock for queue */
@@ -261,9 +262,9 @@
 {
 	long ret;
 
-	lock_kernel();
+	mutex_lock(&isdn_divert_mutex);
 	ret = isdn_divert_ioctl_unlocked(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&isdn_divert_mutex);
 
 	return ret;
 }
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig
index dcefedc..b18a92c 100644
--- a/drivers/isdn/gigaset/Kconfig
+++ b/drivers/isdn/gigaset/Kconfig
@@ -17,8 +17,7 @@
 if ISDN_DRV_GIGASET
 
 config GIGASET_CAPI
-	bool "Gigaset CAPI support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
+	bool "Gigaset CAPI support"
 	depends on ISDN_CAPI='y'||(ISDN_CAPI='m'&&ISDN_DRV_GIGASET='m')
 	default ISDN_I4L='n'
 	help
@@ -27,6 +26,7 @@
 	  subsystem you'll have to enable the capidrv glue driver.
 	  (select ISDN_CAPI_CAPIDRV.)
 	  Say N to build the old native ISDN4Linux variant.
+	  If unsure, say Y.
 
 config GIGASET_I4L
 	bool
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 47a5ffe..0ded364 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -1188,24 +1188,6 @@
 					break;
 				}
 			}
-#ifdef CONFIG_GIGASET_DEBUG
-			/* check assumption on remaining frames */
-			for (; i < BAS_NUMFRAMES; i++) {
-				ifd = &urb->iso_frame_desc[i];
-				if (ifd->status != -EINPROGRESS
-				    || ifd->actual_length != 0) {
-					dev_warn(cs->dev,
-					     "isochronous write: frame %d: %s, "
-					     "%d of %d bytes sent\n",
-					     i, get_usb_statmsg(ifd->status),
-					     ifd->actual_length, ifd->length);
-					offset = (ifd->offset +
-						  ifd->actual_length)
-						 % BAS_OUTBUFSIZE;
-					break;
-				}
-			}
-#endif
 			break;
 		case -EPIPE:			/* stall - probably underrun */
 			dev_err(cs->dev, "isochronous write stalled\n");
@@ -1913,65 +1895,41 @@
  * USB transmission is started if necessary.
  * parameters:
  *	cs		controller state structure
- *	buf		command string to send
- *	len		number of bytes to send (max. IF_WRITEBUF)
- *	wake_tasklet	tasklet to run when transmission is completed
- *			(NULL if none)
+ *	cb		command buffer structure
  * return value:
  *	number of bytes queued on success
  *	error code < 0 on error
  */
-static int gigaset_write_cmd(struct cardstate *cs,
-			     const unsigned char *buf, int len,
-			     struct tasklet_struct *wake_tasklet)
+static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb)
 {
-	struct cmdbuf_t *cb;
 	unsigned long flags;
 	int rc;
 
 	gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
 			     DEBUG_TRANSCMD : DEBUG_LOCKCMD,
-			   "CMD Transmit", len, buf);
-
-	if (len <= 0) {
-		/* nothing to do */
-		rc = 0;
-		goto notqueued;
-	}
+			   "CMD Transmit", cb->len, cb->buf);
 
 	/* translate "+++" escape sequence sent as a single separate command
 	 * into "close AT channel" command for error recovery
 	 * The next command will reopen the AT channel automatically.
 	 */
-	if (len == 3 && !memcmp(buf, "+++", 3)) {
+	if (cb->len == 3 && !memcmp(cb->buf, "+++", 3)) {
+		kfree(cb);
 		rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT);
-		goto notqueued;
+		if (cb->wake_tasklet)
+			tasklet_schedule(cb->wake_tasklet);
+		return rc < 0 ? rc : cb->len;
 	}
 
-	if (len > IF_WRITEBUF)
-		len = IF_WRITEBUF;
-	cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC);
-	if (!cb) {
-		dev_err(cs->dev, "%s: out of memory\n", __func__);
-		rc = -ENOMEM;
-		goto notqueued;
-	}
-
-	memcpy(cb->buf, buf, len);
-	cb->len = len;
-	cb->offset = 0;
-	cb->next = NULL;
-	cb->wake_tasklet = wake_tasklet;
-
 	spin_lock_irqsave(&cs->cmdlock, flags);
 	cb->prev = cs->lastcmdbuf;
 	if (cs->lastcmdbuf)
 		cs->lastcmdbuf->next = cb;
 	else {
 		cs->cmdbuf = cb;
-		cs->curlen = len;
+		cs->curlen = cb->len;
 	}
-	cs->cmdbytes += len;
+	cs->cmdbytes += cb->len;
 	cs->lastcmdbuf = cb;
 	spin_unlock_irqrestore(&cs->cmdlock, flags);
 
@@ -1988,12 +1946,7 @@
 	}
 	rc = start_cbsend(cs);
 	spin_unlock_irqrestore(&cs->lock, flags);
-	return rc < 0 ? rc : len;
-
-notqueued:			/* request handled without queuing */
-	if (wake_tasklet)
-		tasklet_schedule(wake_tasklet);
-	return rc;
+	return rc < 0 ? rc : cb->len;
 }
 
 /* gigaset_write_room
diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c
index 6fbe899..e5ea344 100644
--- a/drivers/isdn/gigaset/capi.c
+++ b/drivers/isdn/gigaset/capi.c
@@ -45,6 +45,7 @@
 #define CAPI_FACILITY_LI	0x0005
 
 #define CAPI_SUPPSVC_GETSUPPORTED	0x0000
+#define CAPI_SUPPSVC_LISTEN		0x0001
 
 /* missing from capiutil.h */
 #define CAPIMSG_PLCI_PART(m)	CAPIMSG_U8(m, 9)
@@ -270,9 +271,13 @@
 	kfree(dbgline);
 	if (CAPIMSG_COMMAND(data) == CAPI_DATA_B3 &&
 	    (CAPIMSG_SUBCOMMAND(data) == CAPI_REQ ||
-	     CAPIMSG_SUBCOMMAND(data) == CAPI_IND) &&
-	    CAPIMSG_DATALEN(data) > 0) {
+	     CAPIMSG_SUBCOMMAND(data) == CAPI_IND)) {
 		l = CAPIMSG_DATALEN(data);
+		gig_dbg(level, "   DataLength=%d", l);
+		if (l <= 0 || !(gigaset_debuglevel & DEBUG_LLDATA))
+			return;
+		if (l > 64)
+			l = 64; /* arbitrary limit */
 		dbgline = kmalloc(3*l, GFP_ATOMIC);
 		if (!dbgline)
 			return;
@@ -378,13 +383,13 @@
 	++bcs->trans_up;
 
 	if (!ap) {
-		dev_err(cs->dev, "%s: no application\n", __func__);
+		gig_dbg(DEBUG_MCMD, "%s: application gone", __func__);
 		return;
 	}
 
 	/* don't send further B3 messages if disconnected */
 	if (bcs->apconnstate < APCONN_ACTIVE) {
-		gig_dbg(DEBUG_LLDATA, "disconnected, discarding ack");
+		gig_dbg(DEBUG_MCMD, "%s: disconnected", __func__);
 		return;
 	}
 
@@ -422,13 +427,14 @@
 	bcs->trans_down++;
 
 	if (!ap) {
-		dev_err(cs->dev, "%s: no application\n", __func__);
+		gig_dbg(DEBUG_MCMD, "%s: application gone", __func__);
+		dev_kfree_skb_any(skb);
 		return;
 	}
 
 	/* don't send further B3 messages if disconnected */
 	if (bcs->apconnstate < APCONN_ACTIVE) {
-		gig_dbg(DEBUG_LLDATA, "disconnected, discarding data");
+		gig_dbg(DEBUG_MCMD, "%s: disconnected", __func__);
 		dev_kfree_skb_any(skb);
 		return;
 	}
@@ -454,7 +460,7 @@
 	/* Data64 parameter not present */
 
 	/* emit message */
-	dump_rawmsg(DEBUG_LLDATA, "DATA_B3_IND", skb->data);
+	dump_rawmsg(DEBUG_MCMD, __func__, skb->data);
 	capi_ctr_handle_message(&iif->ctr, ap->id, skb);
 }
 EXPORT_SYMBOL_GPL(gigaset_skb_rcvd);
@@ -747,7 +753,7 @@
 	ap = bcs->ap;
 	if (!ap) {
 		spin_unlock_irqrestore(&bcs->aplock, flags);
-		dev_err(cs->dev, "%s: no application\n", __func__);
+		gig_dbg(DEBUG_CMD, "%s: application gone", __func__);
 		return;
 	}
 	if (bcs->apconnstate == APCONN_NONE) {
@@ -843,7 +849,7 @@
 	ap = bcs->ap;
 	if (!ap) {
 		spin_unlock_irqrestore(&bcs->aplock, flags);
-		dev_err(cs->dev, "%s: no application\n", __func__);
+		gig_dbg(DEBUG_CMD, "%s: application gone", __func__);
 		return;
 	}
 	if (!bcs->apconnstate) {
@@ -901,13 +907,12 @@
  */
 void gigaset_isdn_hupB(struct bc_state *bcs)
 {
-	struct cardstate *cs = bcs->cs;
 	struct gigaset_capi_appl *ap = bcs->ap;
 
 	/* ToDo: assure order of DISCONNECT_B3_IND and DISCONNECT_IND ? */
 
 	if (!ap) {
-		dev_err(cs->dev, "%s: no application\n", __func__);
+		gig_dbg(DEBUG_CMD, "%s: application gone", __func__);
 		return;
 	}
 
@@ -978,6 +983,9 @@
 	struct cardstate *cs = ctr->driverdata;
 	struct gigaset_capi_appl *ap;
 
+	gig_dbg(DEBUG_CMD, "%s [%u] l3cnt=%u blkcnt=%u blklen=%u",
+		__func__, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
+
 	list_for_each_entry(ap, &iif->appls, ctrlist)
 		if (ap->id == appl) {
 			dev_notice(cs->dev,
@@ -1062,6 +1070,8 @@
 	struct gigaset_capi_appl *ap, *tmp;
 	unsigned ch;
 
+	gig_dbg(DEBUG_CMD, "%s [%u]", __func__, appl);
+
 	list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist)
 		if (ap->id == appl) {
 			/* remove from any channels */
@@ -1142,7 +1152,7 @@
 	case CAPI_FACILITY_SUPPSVC:
 		/* decode Function parameter */
 		pparam = cmsg->FacilityRequestParameter;
-		if (pparam == NULL || *pparam < 2) {
+		if (pparam == NULL || pparam[0] < 2) {
 			dev_notice(cs->dev, "%s: %s missing\n", "FACILITY_REQ",
 				   "Facility Request Parameter");
 			send_conf(iif, ap, skb, CapiIllMessageParmCoding);
@@ -1159,8 +1169,32 @@
 			/* Supported Services: none */
 			capimsg_setu32(confparam, 6, 0);
 			break;
+		case CAPI_SUPPSVC_LISTEN:
+			if (pparam[0] < 7 || pparam[3] < 4) {
+				dev_notice(cs->dev, "%s: %s missing\n",
+					   "FACILITY_REQ", "Notification Mask");
+				send_conf(iif, ap, skb,
+					  CapiIllMessageParmCoding);
+				return;
+			}
+			if (CAPIMSG_U32(pparam, 4) != 0) {
+				dev_notice(cs->dev,
+	"%s: unsupported supplementary service notification mask 0x%x\n",
+				   "FACILITY_REQ", CAPIMSG_U32(pparam, 4));
+				info = CapiFacilitySpecificFunctionNotSupported;
+				confparam[3] = 2;	/* length */
+				capimsg_setu16(confparam, 4,
+					CapiSupplementaryServiceNotSupported);
+			}
+			info = CapiSuccess;
+			confparam[3] = 2;	/* length */
+			capimsg_setu16(confparam, 4, CapiSuccess);
+			break;
 		/* ToDo: add supported services */
 		default:
+			dev_notice(cs->dev,
+		"%s: unsupported supplementary service function 0x%04x\n",
+				   "FACILITY_REQ", function);
 			info = CapiFacilitySpecificFunctionNotSupported;
 			/* Supplementary Service specific parameter */
 			confparam[3] = 2;	/* length */
@@ -1951,11 +1985,7 @@
 	u16 handle = CAPIMSG_HANDLE_REQ(skb->data);
 
 	/* frequent message, avoid _cmsg overhead */
-	dump_rawmsg(DEBUG_LLDATA, "DATA_B3_REQ", skb->data);
-
-	gig_dbg(DEBUG_LLDATA,
-		"Receiving data from LL (ch: %d, flg: %x, sz: %d|%d)",
-		channel, flags, msglen, datalen);
+	dump_rawmsg(DEBUG_MCMD, __func__, skb->data);
 
 	/* check parameters */
 	if (channel == 0 || channel > cs->channels || ncci != 1) {
@@ -2064,7 +2094,7 @@
 			    struct gigaset_capi_appl *ap,
 			    struct sk_buff *skb)
 {
-	dump_rawmsg(DEBUG_LLDATA, __func__, skb->data);
+	dump_rawmsg(DEBUG_MCMD, __func__, skb->data);
 	dev_kfree_skb_any(skb);
 }
 
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 5d4befb..3ca561e 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -791,8 +791,6 @@
 	spin_unlock_irqrestore(&cs->lock, flags);
 	setup_timer(&cs->timer, timer_tick, (unsigned long) cs);
 	cs->timer.expires = jiffies + msecs_to_jiffies(GIG_TICK);
-	/* FIXME: can jiffies increase too much until the timer is added?
-	 * Same problem(?) with mod_timer() in timer_tick(). */
 	add_timer(&cs->timer);
 
 	gig_dbg(DEBUG_INIT, "cs initialized");
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index ceaef9a..a141876 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -35,53 +35,40 @@
 #define RT_RING		2
 #define RT_NUMBER	3
 #define RT_STRING	4
-#define RT_HEX		5
 #define RT_ZCAU		6
 
 /* Possible ASCII responses */
 #define RSP_OK		0
-#define RSP_BUSY	1
-#define RSP_CONNECT	2
+#define RSP_ERROR	1
 #define RSP_ZGCI	3
 #define RSP_RING	4
-#define RSP_ZAOC	5
-#define RSP_ZCSTR	6
-#define RSP_ZCFGT	7
-#define RSP_ZCFG	8
-#define RSP_ZCCR	9
-#define RSP_EMPTY	10
-#define RSP_ZLOG	11
-#define RSP_ZCAU	12
-#define RSP_ZMWI	13
-#define RSP_ZABINFO	14
-#define RSP_ZSMLSTCHG	15
+#define RSP_ZVLS	5
+#define RSP_ZCAU	6
+
+/* responses with values to store in at_state */
+/* - numeric */
 #define RSP_VAR		100
 #define RSP_ZSAU	(RSP_VAR + VAR_ZSAU)
 #define RSP_ZDLE	(RSP_VAR + VAR_ZDLE)
-#define RSP_ZVLS	(RSP_VAR + VAR_ZVLS)
 #define RSP_ZCTP	(RSP_VAR + VAR_ZCTP)
+/* - string */
 #define RSP_STR		(RSP_VAR + VAR_NUM)
 #define RSP_NMBR	(RSP_STR + STR_NMBR)
 #define RSP_ZCPN	(RSP_STR + STR_ZCPN)
 #define RSP_ZCON	(RSP_STR + STR_ZCON)
 #define RSP_ZBC		(RSP_STR + STR_ZBC)
 #define RSP_ZHLC	(RSP_STR + STR_ZHLC)
-#define RSP_ERROR	-1	/* ERROR              */
+
 #define RSP_WRONG_CID	-2	/* unknown cid in cmd */
-#define RSP_UNKNOWN	-4	/* unknown response   */
-#define RSP_FAIL	-5	/* internal error     */
 #define RSP_INVAL	-6	/* invalid response   */
+#define RSP_NODEV	-9	/* device not connected */
 
 #define RSP_NONE	-19
 #define RSP_STRING	-20
 #define RSP_NULL	-21
-#define RSP_RETRYFAIL	-22
-#define RSP_RETRY	-23
-#define RSP_SKIP	-24
 #define RSP_INIT	-27
 #define RSP_ANY		-26
 #define RSP_LAST	-28
-#define RSP_NODEV	-9
 
 /* actions for process_response */
 #define ACT_NOTHING		0
@@ -259,13 +246,6 @@
 
 /* misc. */
 {RSP_ERROR,	 -1,  -1, -1,			 -1, -1, {ACT_ERROR} },
-{RSP_ZCFGT,	 -1,  -1, -1,			 -1, -1, {ACT_DEBUG} },
-{RSP_ZCFG,	 -1,  -1, -1,			 -1, -1, {ACT_DEBUG} },
-{RSP_ZLOG,	 -1,  -1, -1,			 -1, -1, {ACT_DEBUG} },
-{RSP_ZMWI,	 -1,  -1, -1,			 -1, -1, {ACT_DEBUG} },
-{RSP_ZABINFO,	 -1,  -1, -1,			 -1, -1, {ACT_DEBUG} },
-{RSP_ZSMLSTCHG,	 -1,  -1, -1,			 -1, -1, {ACT_DEBUG} },
-
 {RSP_ZCAU,	 -1,  -1, -1,			 -1, -1, {ACT_ZCAU} },
 {RSP_NONE,	 -1,  -1, -1,			 -1, -1, {ACT_DEBUG} },
 {RSP_ANY,	 -1,  -1, -1,			 -1, -1, {ACT_WARN} },
@@ -361,10 +341,6 @@
 
 /* misc. */
 {RSP_ZCON,	 -1,  -1, -1,			 -1, -1, {ACT_DEBUG} },
-{RSP_ZCCR,	 -1,  -1, -1,			 -1, -1, {ACT_DEBUG} },
-{RSP_ZAOC,	 -1,  -1, -1,			 -1, -1, {ACT_DEBUG} },
-{RSP_ZCSTR,	 -1,  -1, -1,			 -1, -1, {ACT_DEBUG} },
-
 {RSP_ZCAU,	 -1,  -1, -1,			 -1, -1, {ACT_ZCAU} },
 {RSP_NONE,	 -1,  -1, -1,			 -1, -1, {ACT_DEBUG} },
 {RSP_ANY,	 -1,  -1, -1,			 -1, -1, {ACT_WARN} },
@@ -387,20 +363,11 @@
 	{"ZVLS",	RSP_ZVLS,	RT_NUMBER},
 	{"ZCTP",	RSP_ZCTP,	RT_NUMBER},
 	{"ZDLE",	RSP_ZDLE,	RT_NUMBER},
-	{"ZCFGT",	RSP_ZCFGT,	RT_NUMBER},
-	{"ZCCR",	RSP_ZCCR,	RT_NUMBER},
-	{"ZMWI",	RSP_ZMWI,	RT_NUMBER},
 	{"ZHLC",	RSP_ZHLC,	RT_STRING},
 	{"ZBC",		RSP_ZBC,	RT_STRING},
 	{"NMBR",	RSP_NMBR,	RT_STRING},
 	{"ZCPN",	RSP_ZCPN,	RT_STRING},
 	{"ZCON",	RSP_ZCON,	RT_STRING},
-	{"ZAOC",	RSP_ZAOC,	RT_STRING},
-	{"ZCSTR",	RSP_ZCSTR,	RT_STRING},
-	{"ZCFG",	RSP_ZCFG,	RT_HEX},
-	{"ZLOG",	RSP_ZLOG,	RT_NOTHING},
-	{"ZABINFO",	RSP_ZABINFO,	RT_NOTHING},
-	{"ZSMLSTCHG",	RSP_ZSMLSTCHG,	RT_NOTHING},
 	{NULL,		0,		0}
 };
 
@@ -418,64 +385,18 @@
 	{NULL,				ZSAU_UNKNOWN}
 };
 
-/*
- * Get integer from char-pointer
- */
-static int isdn_getnum(char *p)
-{
-	int v = -1;
-
-	gig_dbg(DEBUG_EVENT, "string: %s", p);
-
-	while (*p >= '0' && *p <= '9')
-		v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p++) - '0');
-	if (*p)
-		v = -1; /* invalid Character */
-	return v;
-}
-
-/*
- * Get integer from char-pointer
- */
-static int isdn_gethex(char *p)
-{
-	int v = 0;
-	int c;
-
-	gig_dbg(DEBUG_EVENT, "string: %s", p);
-
-	if (!*p)
-		return -1;
-
-	do {
-		if (v > (INT_MAX - 15) / 16)
-			return -1;
-		c = *p;
-		if (c >= '0' && c <= '9')
-			c -= '0';
-		else if (c >= 'a' && c <= 'f')
-			c -= 'a' - 10;
-		else if (c >= 'A' && c <= 'F')
-			c -= 'A' - 10;
-		else
-			return -1;
-		v = v * 16 + c;
-	} while (*++p);
-
-	return v;
-}
-
 /* retrieve CID from parsed response
  * returns 0 if no CID, -1 if invalid CID, or CID value 1..65535
  */
 static int cid_of_response(char *s)
 {
-	int cid;
+	unsigned long cid;
+	int rc;
 
 	if (s[-1] != ';')
 		return 0;	/* no CID separator */
-	cid = isdn_getnum(s);
-	if (cid < 0)
+	rc = strict_strtoul(s, 10, &cid);
+	if (rc)
 		return 0;	/* CID not numeric */
 	if (cid < 1 || cid > 65535)
 		return -1;	/* CID out of range */
@@ -588,10 +509,10 @@
 					break;
 
 			if (!rt->response) {
-				event->type = RSP_UNKNOWN;
-				dev_warn(cs->dev,
-					 "unknown modem response: %s\n",
-					 argv[curarg]);
+				event->type = RSP_NONE;
+				gig_dbg(DEBUG_EVENT,
+					"unknown modem response: '%s'\n",
+					argv[curarg]);
 				break;
 			}
 
@@ -645,27 +566,27 @@
 		case RT_ZCAU:
 			event->parameter = -1;
 			if (curarg + 1 < params) {
-				i = isdn_gethex(argv[curarg]);
-				j = isdn_gethex(argv[curarg + 1]);
-				if (i >= 0 && i < 256 && j >= 0 && j < 256)
-					event->parameter = (unsigned) i << 8
-							   | j;
-				curarg += 2;
+				unsigned long type, value;
+
+				i = strict_strtoul(argv[curarg++], 16, &type);
+				j = strict_strtoul(argv[curarg++], 16, &value);
+
+				if (i == 0 && type < 256 &&
+				    j == 0 && value < 256)
+					event->parameter = (type << 8) | value;
 			} else
 				curarg = params - 1;
 			break;
 		case RT_NUMBER:
-		case RT_HEX:
+			event->parameter = -1;
 			if (curarg < params) {
-				if (param_type == RT_HEX)
-					event->parameter =
-						isdn_gethex(argv[curarg]);
-				else
-					event->parameter =
-						isdn_getnum(argv[curarg]);
-				++curarg;
-			} else
-				event->parameter = -1;
+				unsigned long res;
+				int rc;
+
+				rc = strict_strtoul(argv[curarg++], 10, &res);
+				if (rc == 0)
+					event->parameter = res;
+			}
 			gig_dbg(DEBUG_EVENT, "parameter==%d", event->parameter);
 			break;
 		}
@@ -797,48 +718,27 @@
 static void send_command(struct cardstate *cs, const char *cmd, int cid,
 			 int dle, gfp_t kmallocflags)
 {
-	size_t cmdlen, buflen;
-	char *cmdpos, *cmdbuf, *cmdtail;
+	struct cmdbuf_t *cb;
+	size_t buflen;
 
-	cmdlen = strlen(cmd);
-	buflen = 11 + cmdlen;
-	if (unlikely(buflen <= cmdlen)) {
-		dev_err(cs->dev, "integer overflow in buflen\n");
+	buflen = strlen(cmd) + 12; /* DLE ( A T 1 2 3 4 5 <cmd> DLE ) \0 */
+	cb = kmalloc(sizeof(struct cmdbuf_t) + buflen, kmallocflags);
+	if (!cb) {
+		dev_err(cs->dev, "%s: out of memory\n", __func__);
 		return;
 	}
-
-	cmdbuf = kmalloc(buflen, kmallocflags);
-	if (unlikely(!cmdbuf)) {
-		dev_err(cs->dev, "out of memory\n");
-		return;
-	}
-
-	cmdpos = cmdbuf + 9;
-	cmdtail = cmdpos + cmdlen;
-	memcpy(cmdpos, cmd, cmdlen);
-
-	if (cid > 0 && cid <= 65535) {
-		do {
-			*--cmdpos = '0' + cid % 10;
-			cid /= 10;
-			++cmdlen;
-		} while (cid);
-	}
-
-	cmdlen += 2;
-	*--cmdpos = 'T';
-	*--cmdpos = 'A';
-
-	if (dle) {
-		cmdlen += 4;
-		*--cmdpos = '(';
-		*--cmdpos = 0x10;
-		*cmdtail++ = 0x10;
-		*cmdtail++ = ')';
-	}
-
-	cs->ops->write_cmd(cs, cmdpos, cmdlen, NULL);
-	kfree(cmdbuf);
+	if (cid > 0 && cid <= 65535)
+		cb->len = snprintf(cb->buf, buflen,
+				  dle ? "\020(AT%d%s\020)" : "AT%d%s",
+				  cid, cmd);
+	else
+		cb->len = snprintf(cb->buf, buflen,
+				  dle ? "\020(AT%s\020)" : "AT%s",
+				  cmd);
+	cb->offset = 0;
+	cb->next = NULL;
+	cb->wake_tasklet = NULL;
+	cs->ops->write_cmd(cs, cb);
 }
 
 static struct at_state_t *at_state_from_cid(struct cardstate *cs, int cid)
@@ -1240,8 +1140,22 @@
 		break;
 	case ACT_HUPMODEM:
 		/* send "+++" (hangup in unimodem mode) */
-		if (cs->connected)
-			cs->ops->write_cmd(cs, "+++", 3, NULL);
+		if (cs->connected) {
+			struct cmdbuf_t *cb;
+
+			cb = kmalloc(sizeof(struct cmdbuf_t) + 3, GFP_ATOMIC);
+			if (!cb) {
+				dev_err(cs->dev, "%s: out of memory\n",
+					__func__);
+				return;
+			}
+			memcpy(cb->buf, "+++", 3);
+			cb->len = 3;
+			cb->offset = 0;
+			cb->next = NULL;
+			cb->wake_tasklet = NULL;
+			cs->ops->write_cmd(cs, cb);
+		}
 		break;
 	case ACT_RING:
 		/* get fresh AT state structure for new CID */
@@ -1855,19 +1769,13 @@
 				gig_dbg(DEBUG_EVENT, "Scheduling PC_CIDMODE");
 				cs->commands_pending = 1;
 				return;
-#ifdef GIG_MAYINITONDIAL
 			case M_UNKNOWN:
 				schedule_init(cs, MS_INIT);
 				return;
-#endif
 			}
 			bcs->at_state.pending_commands &= ~PC_CID;
 			cs->curchannel = bcs->channel;
-#ifdef GIG_RETRYCID
 			cs->retry_count = 2;
-#else
-			cs->retry_count = 1;
-#endif
 			schedule_sequence(cs, &cs->at_state, SEQ_CID);
 			return;
 		}
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index 8738b08..a69512f 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -46,13 +46,6 @@
 
 #define RBUFSIZE 8192
 
-/* compile time options */
-#define GIG_MAJOR 0
-
-#define GIG_MAYINITONDIAL
-#define GIG_RETRYCID
-#define GIG_X75
-
 #define GIG_TICK 100		/* in milliseconds */
 
 /* timeout values (unit: 1 sec) */
@@ -193,9 +186,8 @@
 /* variables in struct at_state_t */
 #define VAR_ZSAU	0
 #define VAR_ZDLE	1
-#define VAR_ZVLS	2
-#define VAR_ZCTP	3
-#define VAR_NUM		4
+#define VAR_ZCTP	2
+#define VAR_NUM		3
 
 #define STR_NMBR	0
 #define STR_ZCPN	1
@@ -574,9 +566,7 @@
 struct gigaset_ops {
 	/* Called from ev-layer.c/interface.c for sending AT commands to the
 	   device */
-	int (*write_cmd)(struct cardstate *cs,
-			 const unsigned char *buf, int len,
-			 struct tasklet_struct *wake_tasklet);
+	int (*write_cmd)(struct cardstate *cs, struct cmdbuf_t *cb);
 
 	/* Called from interface.c for additional device control */
 	int (*write_room)(struct cardstate *cs);
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
index f01c3c2..34bca37 100644
--- a/drivers/isdn/gigaset/i4l.c
+++ b/drivers/isdn/gigaset/i4l.c
@@ -419,6 +419,8 @@
 	dev_err(bcs->cs->dev, "out of memory\n");
 	for (i = 0; i < AT_NUM; ++i)
 		kfree(commands[i]);
+	kfree(commands);
+	gigaset_free_channel(bcs);
 	return -ENOMEM;
 }
 
@@ -643,9 +645,7 @@
 	iif->maxbufsize = MAX_BUF_SIZE;
 	iif->features = ISDN_FEATURE_L2_TRANS |
 		ISDN_FEATURE_L2_HDLC |
-#ifdef GIG_X75
 		ISDN_FEATURE_L2_X75I |
-#endif
 		ISDN_FEATURE_L3_TRANS |
 		ISDN_FEATURE_P_EURO;
 	iif->hl_hdrlen = HW_HDR_LEN;		/* Area for storing ack */
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index c9f28dd..bb710d16 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -339,7 +339,8 @@
 static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
 	struct cardstate *cs;
-	int retval = -ENODEV;
+	struct cmdbuf_t *cb;
+	int retval;
 
 	cs = (struct cardstate *) tty->driver_data;
 	if (!cs) {
@@ -355,18 +356,39 @@
 	if (!cs->connected) {
 		gig_dbg(DEBUG_IF, "not connected");
 		retval = -ENODEV;
-	} else if (!cs->open_count)
+		goto done;
+	}
+	if (!cs->open_count) {
 		dev_warn(cs->dev, "%s: device not opened\n", __func__);
-	else if (cs->mstate != MS_LOCKED) {
+		retval = -ENODEV;
+		goto done;
+	}
+	if (cs->mstate != MS_LOCKED) {
 		dev_warn(cs->dev, "can't write to unlocked device\n");
 		retval = -EBUSY;
-	} else {
-		retval = cs->ops->write_cmd(cs, buf, count,
-					    &cs->if_wake_tasklet);
+		goto done;
+	}
+	if (count <= 0) {
+		/* nothing to do */
+		retval = 0;
+		goto done;
 	}
 
-	mutex_unlock(&cs->mutex);
+	cb = kmalloc(sizeof(struct cmdbuf_t) + count, GFP_KERNEL);
+	if (!cb) {
+		dev_err(cs->dev, "%s: out of memory\n", __func__);
+		retval = -ENOMEM;
+		goto done;
+	}
 
+	memcpy(cb->buf, buf, count);
+	cb->len = count;
+	cb->offset = 0;
+	cb->next = NULL;
+	cb->wake_tasklet = &cs->if_wake_tasklet;
+	retval = cs->ops->write_cmd(cs, cb);
+done:
+	mutex_unlock(&cs->mutex);
 	return retval;
 }
 
@@ -655,7 +677,6 @@
 		goto enomem;
 
 	tty->magic =		TTY_DRIVER_MAGIC,
-	tty->major =		GIG_MAJOR,
 	tty->type =		TTY_DRIVER_TYPE_SERIAL,
 	tty->subtype =		SERIAL_TYPE_NORMAL,
 	tty->flags =		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index e96c058..d151dcb 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -241,30 +241,13 @@
  * return value:
  *	number of bytes queued, or error code < 0
  */
-static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
-			     int len, struct tasklet_struct *wake_tasklet)
+static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb)
 {
-	struct cmdbuf_t *cb;
 	unsigned long flags;
 
 	gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
 				DEBUG_TRANSCMD : DEBUG_LOCKCMD,
-			   "CMD Transmit", len, buf);
-
-	if (len <= 0)
-		return 0;
-
-	cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC);
-	if (!cb) {
-		dev_err(cs->dev, "%s: out of memory!\n", __func__);
-		return -ENOMEM;
-	}
-
-	memcpy(cb->buf, buf, len);
-	cb->len = len;
-	cb->offset = 0;
-	cb->next = NULL;
-	cb->wake_tasklet = wake_tasklet;
+			   "CMD Transmit", cb->len, cb->buf);
 
 	spin_lock_irqsave(&cs->cmdlock, flags);
 	cb->prev = cs->lastcmdbuf;
@@ -272,9 +255,9 @@
 		cs->lastcmdbuf->next = cb;
 	else {
 		cs->cmdbuf = cb;
-		cs->curlen = len;
+		cs->curlen = cb->len;
 	}
-	cs->cmdbytes += len;
+	cs->cmdbytes += cb->len;
 	cs->lastcmdbuf = cb;
 	spin_unlock_irqrestore(&cs->cmdlock, flags);
 
@@ -282,7 +265,7 @@
 	if (cs->connected)
 		tasklet_schedule(&cs->write_tasklet);
 	spin_unlock_irqrestore(&cs->lock, flags);
-	return len;
+	return cb->len;
 }
 
 /*
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index 76dbb20..4a66338 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -39,7 +39,8 @@
 #define GIGASET_MODULENAME "usb_gigaset"
 #define GIGASET_DEVNAME    "ttyGU"
 
-#define IF_WRITEBUF 2000	/* arbitrary limit */
+/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */
+#define IF_WRITEBUF 264
 
 /* Values for the Gigaset M105 Data */
 #define USB_M105_VENDOR_ID	0x0681
@@ -493,29 +494,13 @@
 }
 
 /* Send command to device. */
-static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
-			     int len, struct tasklet_struct *wake_tasklet)
+static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb)
 {
-	struct cmdbuf_t *cb;
 	unsigned long flags;
 
 	gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
 			     DEBUG_TRANSCMD : DEBUG_LOCKCMD,
-			   "CMD Transmit", len, buf);
-
-	if (len <= 0)
-		return 0;
-	cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC);
-	if (!cb) {
-		dev_err(cs->dev, "%s: out of memory\n", __func__);
-		return -ENOMEM;
-	}
-
-	memcpy(cb->buf, buf, len);
-	cb->len = len;
-	cb->offset = 0;
-	cb->next = NULL;
-	cb->wake_tasklet = wake_tasklet;
+			   "CMD Transmit", cb->len, cb->buf);
 
 	spin_lock_irqsave(&cs->cmdlock, flags);
 	cb->prev = cs->lastcmdbuf;
@@ -523,9 +508,9 @@
 		cs->lastcmdbuf->next = cb;
 	else {
 		cs->cmdbuf = cb;
-		cs->curlen = len;
+		cs->curlen = cb->len;
 	}
-	cs->cmdbytes += len;
+	cs->cmdbytes += cb->len;
 	cs->lastcmdbuf = cb;
 	spin_unlock_irqrestore(&cs->cmdlock, flags);
 
@@ -533,7 +518,7 @@
 	if (cs->connected)
 		tasklet_schedule(&cs->write_tasklet);
 	spin_unlock_irqrestore(&cs->lock, flags);
-	return len;
+	return cb->len;
 }
 
 static int gigaset_write_room(struct cardstate *cs)
diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c
index 1e85f74..f1d464f 100644
--- a/drivers/isdn/hardware/eicon/divamnt.c
+++ b/drivers/isdn/hardware/eicon/divamnt.c
@@ -14,7 +14,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include "platform.h"
@@ -22,6 +22,7 @@
 #include "divasync.h"
 #include "debug_if.h"
 
+static DEFINE_MUTEX(maint_mutex);
 static char *main_revision = "$Revision: 1.32.6.10 $";
 
 static int major;
@@ -130,7 +131,7 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&maint_mutex);
 	/* only one open is allowed, so we test
 	   it atomically */
 	if (test_and_set_bit(0, &opened))
@@ -139,7 +140,7 @@
 		filep->private_data = NULL;
 		ret = nonseekable_open(ino, filep);
 	}
-	unlock_kernel();
+	mutex_unlock(&maint_mutex);
 	return ret;
 }
 
diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c
index f577719..42d3b834 100644
--- a/drivers/isdn/hardware/eicon/divasi.c
+++ b/drivers/isdn/hardware/eicon/divasi.c
@@ -18,7 +18,6 @@
 #include <linux/proc_fs.h>
 #include <linux/skbuff.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 
 #include "platform.h"
@@ -402,7 +401,6 @@
 
 static int um_idi_open(struct inode *inode, struct file *file)
 {
-	cycle_kernel_lock();
 	return (0);
 }
 
diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
index fbbcb27..ed9c555 100644
--- a/drivers/isdn/hardware/eicon/divasmain.c
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -21,7 +21,6 @@
 #include <linux/list.h>
 #include <linux/poll.h>
 #include <linux/kmod.h>
-#include <linux/smp_lock.h>
 
 #include "platform.h"
 #undef ID_MASK
@@ -113,41 +112,40 @@
   This table should be sorted by PCI device ID
   */
 static struct pci_device_id divas_pci_tbl[] = {
-/* Diva Server BRI-2M PCI 0xE010 */
-	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRA,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_MAESTRA_PCI},
-/* Diva Server 4BRI-8M PCI 0xE012 */
-	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAQ,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_Q_8M_PCI},
-/* Diva Server 4BRI-8M 2.0 PCI 0xE013 */
-	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAQ_U,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_Q_8M_V2_PCI},
-/* Diva Server PRI-30M PCI 0xE014 */
-	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_P_30M_PCI},
-/* Diva Server PRI 2.0 adapter 0xE015 */
-	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_P_30M_V2_PCI},
-/* Diva Server Voice 4BRI-8M PCI 0xE016 */
-	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_4BRI_VOIP,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_Q_8M_PCI},
-/* Diva Server Voice 4BRI-8M 2.0 PCI 0xE017 */
-	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_4BRI_2_VOIP,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI},
-/* Diva Server BRI-2M 2.0 PCI 0xE018 */
-	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_BRI2M_2,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_B_2M_V2_PCI},
-/* Diva Server Voice PRI 2.0 PCI 0xE019 */
-	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2_VOIP,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	 CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI},
-/* Diva Server 2FX 0xE01A */
-	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_2F,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_B_2F_PCI},
-/* Diva Server Voice BRI-2M 2.0 PCI 0xE01B */
-	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_BRI2M_2_VOIP,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI},
-	{0,}			/* 0 terminated list. */
+	/* Diva Server BRI-2M PCI 0xE010 */
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_MAESTRA),
+		CARDTYPE_MAESTRA_PCI },
+	/* Diva Server 4BRI-8M PCI 0xE012 */
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_MAESTRAQ),
+		CARDTYPE_DIVASRV_Q_8M_PCI },
+	/* Diva Server 4BRI-8M 2.0 PCI 0xE013 */
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_MAESTRAQ_U),
+		CARDTYPE_DIVASRV_Q_8M_V2_PCI },
+	/* Diva Server PRI-30M PCI 0xE014 */
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_MAESTRAP),
+		CARDTYPE_DIVASRV_P_30M_PCI },
+	/* Diva Server PRI 2.0 adapter 0xE015 */
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2),
+		CARDTYPE_DIVASRV_P_30M_V2_PCI },
+	/* Diva Server Voice 4BRI-8M PCI 0xE016 */
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_4BRI_VOIP),
+		CARDTYPE_DIVASRV_VOICE_Q_8M_PCI },
+	/* Diva Server Voice 4BRI-8M 2.0 PCI 0xE017 */
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_4BRI_2_VOIP),
+		CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI },
+	/* Diva Server BRI-2M 2.0 PCI 0xE018 */
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_BRI2M_2),
+		CARDTYPE_DIVASRV_B_2M_V2_PCI },
+	/* Diva Server Voice PRI 2.0 PCI 0xE019 */
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2_VOIP),
+		CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI },
+	/* Diva Server 2FX 0xE01A */
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_2F),
+		CARDTYPE_DIVASRV_B_2F_PCI },
+	/* Diva Server Voice BRI-2M 2.0 PCI 0xE01B */
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_BRI2M_2_VOIP),
+		CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI },
+	{ 0, }			/* 0 terminated list. */
 };
 MODULE_DEVICE_TABLE(pci, divas_pci_tbl);
 
@@ -581,7 +579,6 @@
  */
 static int divas_open(struct inode *inode, struct file *file)
 {
-	cycle_kernel_lock();
 	return (0);
 }
 
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index d317195..4e3780d 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -5354,12 +5354,9 @@
 	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
 		PCI_SUBDEVICE_ID_CCD_JHSE1, 0, 0, H(25)}, /* Junghanns E1 */
 
-	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_ANY_ID, PCI_ANY_ID,
-		0, 0, 0},
-	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_ANY_ID, PCI_ANY_ID,
-		0, 0, 0},
-	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_ANY_ID, PCI_ANY_ID,
-		0, 0, 0},
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC4S), 0 },
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC8S), 0 },
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFCE1), 0 },
 	{0, }
 };
 #undef H
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index 65ded05..15d323b 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -2188,52 +2188,52 @@
 
 static struct pci_device_id hfc_ids[] =
 {
-	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[0]},
-	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[1]},
-	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[2]},
-	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[3]},
-	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[4]},
-	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[5]},
-	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[6]},
-	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[7]},
-	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[8]},
-	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[9]},
-	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B700,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[10]},
-	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B701,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[11]},
-	{PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[12]},
-	{PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[13]},
-	{PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[14]},
-	{PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[15]},
-	{PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[16]},
-	{PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[17]},
-	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[18]},
-	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[19]},
-	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[20]},
-	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[21]},
-	{PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[22]},
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0),
+		(unsigned long) &hfc_map[0] },
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B000),
+		(unsigned long) &hfc_map[1] },
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B006),
+		(unsigned long) &hfc_map[2] },
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B007),
+		(unsigned long) &hfc_map[3] },
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B008),
+		(unsigned long) &hfc_map[4] },
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B009),
+		(unsigned long) &hfc_map[5] },
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00A),
+		(unsigned long) &hfc_map[6] },
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00B),
+		(unsigned long) &hfc_map[7] },
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00C),
+		(unsigned long) &hfc_map[8] },
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B100),
+		(unsigned long) &hfc_map[9] },
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B700),
+		(unsigned long) &hfc_map[10] },
+	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B701),
+		(unsigned long) &hfc_map[11] },
+	{ PCI_VDEVICE(ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1),
+		(unsigned long) &hfc_map[12] },
+	{ PCI_VDEVICE(ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675),
+		(unsigned long) &hfc_map[13] },
+	{ PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT),
+		(unsigned long) &hfc_map[14] },
+	{ PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_A1T),
+		(unsigned long) &hfc_map[15] },
+	{ PCI_VDEVICE(ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575),
+		(unsigned long) &hfc_map[16] },
+	{ PCI_VDEVICE(ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0),
+		(unsigned long) &hfc_map[17] },
+	{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E),
+		(unsigned long) &hfc_map[18] },
+	{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_E),
+		(unsigned long) &hfc_map[19] },
+	{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A),
+		(unsigned long) &hfc_map[20] },
+	{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_A),
+		(unsigned long) &hfc_map[21] },
+	{ PCI_VDEVICE(SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2),
+		(unsigned long) &hfc_map[22] },
 	{},
 };
 
diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
index 4975976..d2dd61d 100644
--- a/drivers/isdn/hardware/mISDN/mISDNinfineon.c
+++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
@@ -125,36 +125,25 @@
 #define PCI_SUB_ID_SEDLBAUER            0x01
 
 static struct pci_device_id infineon_ids[] __devinitdata = {
-	{ PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20},
-	{ PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20_U,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20U},
-	{ PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA201,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA201},
-	{ PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA202,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA202},
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20), INF_DIVA20 },
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20_U), INF_DIVA20U },
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA201), INF_DIVA201 },
+	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA202), INF_DIVA202 },
 	{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
 	  PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0,
-	  INF_SPEEDWIN},
+	  INF_SPEEDWIN },
 	{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
-	  PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3},
-	{ PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS1000},
-	{ PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_QS3000,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS3000},
-	{ PCI_VENDOR_ID_SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_NICCY},
+	  PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3 },
+	{ PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_MICROLINK), INF_QS1000 },
+	{ PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_QS3000), INF_QS3000 },
+	{ PCI_VDEVICE(SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY), INF_NICCY },
 	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
 	  PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0,
-	  INF_SCT_1},
-	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R685,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R685},
-	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R753,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
-	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
-	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_OLITEC,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
+	  INF_SCT_1 },
+	{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R685), INF_GAZEL_R685 },
+	{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R753), INF_GAZEL_R753 },
+	{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO), INF_GAZEL_R753 },
+	{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_OLITEC), INF_GAZEL_R753 },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, infineon_ids);
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 544cf4b..6f9afcd 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1909,68 +1909,68 @@
 
 static struct pci_device_id hisax_pci_tbl[] __devinitdata = {
 #ifdef CONFIG_HISAX_FRITZPCI
-	{PCI_VENDOR_ID_AVM,      PCI_DEVICE_ID_AVM_A1,           PCI_ANY_ID, PCI_ANY_ID},
+	{PCI_VDEVICE(AVM,      PCI_DEVICE_ID_AVM_A1)			},
 #endif
 #ifdef CONFIG_HISAX_DIEHLDIVA
-	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA20,     PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA20_U,   PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA201,    PCI_ANY_ID, PCI_ANY_ID},
-//#########################################################################################	
-	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA202,    PCI_ANY_ID, PCI_ANY_ID},
-//#########################################################################################	
+	{PCI_VDEVICE(EICON,    PCI_DEVICE_ID_EICON_DIVA20)		},
+	{PCI_VDEVICE(EICON,    PCI_DEVICE_ID_EICON_DIVA20_U)	},
+	{PCI_VDEVICE(EICON,    PCI_DEVICE_ID_EICON_DIVA201)		},
+/*##########################################################################*/
+	{PCI_VDEVICE(EICON,    PCI_DEVICE_ID_EICON_DIVA202)		},
+/*##########################################################################*/
 #endif
 #ifdef CONFIG_HISAX_ELSA
-	{PCI_VENDOR_ID_ELSA,     PCI_DEVICE_ID_ELSA_MICROLINK,   PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_ELSA,     PCI_DEVICE_ID_ELSA_QS3000,      PCI_ANY_ID, PCI_ANY_ID},
+	{PCI_VDEVICE(ELSA,     PCI_DEVICE_ID_ELSA_MICROLINK)	},
+	{PCI_VDEVICE(ELSA,     PCI_DEVICE_ID_ELSA_QS3000)		},
 #endif
 #ifdef CONFIG_HISAX_GAZEL
-	{PCI_VENDOR_ID_PLX,      PCI_DEVICE_ID_PLX_R685,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_PLX,      PCI_DEVICE_ID_PLX_R753,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_PLX,      PCI_DEVICE_ID_PLX_DJINN_ITOO,   PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_PLX,      PCI_DEVICE_ID_PLX_OLITEC,       PCI_ANY_ID, PCI_ANY_ID},
+	{PCI_VDEVICE(PLX,      PCI_DEVICE_ID_PLX_R685)			},
+	{PCI_VDEVICE(PLX,      PCI_DEVICE_ID_PLX_R753)			},
+	{PCI_VDEVICE(PLX,      PCI_DEVICE_ID_PLX_DJINN_ITOO)	},
+	{PCI_VDEVICE(PLX,      PCI_DEVICE_ID_PLX_OLITEC)		},
 #endif
 #ifdef CONFIG_HISAX_SCT_QUADRO
-	{PCI_VENDOR_ID_PLX,      PCI_DEVICE_ID_PLX_9050,         PCI_ANY_ID, PCI_ANY_ID},
+	{PCI_VDEVICE(PLX,      PCI_DEVICE_ID_PLX_9050)			},
 #endif
 #ifdef CONFIG_HISAX_NICCY
-	{PCI_VENDOR_ID_SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY,   PCI_ANY_ID,PCI_ANY_ID},
+	{PCI_VDEVICE(SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY)	},
 #endif
 #ifdef CONFIG_HISAX_SEDLBAUER
-	{PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,     PCI_ANY_ID,PCI_ANY_ID},
+	{PCI_VDEVICE(TIGERJET, PCI_DEVICE_ID_TIGERJET_100)		},
 #endif
 #if defined(CONFIG_HISAX_NETJET) || defined(CONFIG_HISAX_NETJET_U)
-	{PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300,     PCI_ANY_ID,PCI_ANY_ID},
+	{PCI_VDEVICE(TIGERJET, PCI_DEVICE_ID_TIGERJET_300)		},
 #endif
 #if defined(CONFIG_HISAX_TELESPCI) || defined(CONFIG_HISAX_SCT_QUADRO)
-	{PCI_VENDOR_ID_ZORAN,    PCI_DEVICE_ID_ZORAN_36120,      PCI_ANY_ID,PCI_ANY_ID},
+	{PCI_VDEVICE(ZORAN,    PCI_DEVICE_ID_ZORAN_36120)		},
 #endif
 #ifdef CONFIG_HISAX_W6692
-	{PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH,  PCI_ANY_ID,PCI_ANY_ID},
-	{PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692,    PCI_ANY_ID,PCI_ANY_ID},
+	{PCI_VDEVICE(DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH)	},
+	{PCI_VDEVICE(WINBOND2, PCI_DEVICE_ID_WINBOND2_6692)		},
 #endif
 #ifdef CONFIG_HISAX_HFC_PCI
-	{PCI_VENDOR_ID_CCD,      PCI_DEVICE_ID_CCD_2BD0,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_CCD,      PCI_DEVICE_ID_CCD_B000,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_CCD,      PCI_DEVICE_ID_CCD_B006,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_CCD,      PCI_DEVICE_ID_CCD_B007,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_CCD,      PCI_DEVICE_ID_CCD_B008,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_CCD,      PCI_DEVICE_ID_CCD_B009,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_CCD,      PCI_DEVICE_ID_CCD_B00A,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_CCD,      PCI_DEVICE_ID_CCD_B00B,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_CCD,      PCI_DEVICE_ID_CCD_B00C,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_CCD,      PCI_DEVICE_ID_CCD_B100,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_CCD,      PCI_DEVICE_ID_CCD_B700,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_CCD,      PCI_DEVICE_ID_CCD_B701,         PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_ABOCOM,   PCI_DEVICE_ID_ABOCOM_2BD1,      PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_ASUSTEK,  PCI_DEVICE_ID_ASUSTEK_0675,     PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_BERKOM,   PCI_DEVICE_ID_BERKOM_T_CONCEPT, PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_BERKOM,   PCI_DEVICE_ID_BERKOM_A1T,       PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_ANIGMA,   PCI_DEVICE_ID_ANIGMA_MC145575,  PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_ZOLTRIX,  PCI_DEVICE_ID_ZOLTRIX_2BD0,     PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_DIGI,     PCI_DEVICE_ID_DIGI_DF_M_IOM2_E, PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_DIGI,     PCI_DEVICE_ID_DIGI_DF_M_E,      PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_DIGI,     PCI_DEVICE_ID_DIGI_DF_M_IOM2_A, PCI_ANY_ID, PCI_ANY_ID},
-	{PCI_VENDOR_ID_DIGI,     PCI_DEVICE_ID_DIGI_DF_M_A,      PCI_ANY_ID, PCI_ANY_ID},
+	{PCI_VDEVICE(CCD,      PCI_DEVICE_ID_CCD_2BD0)			},
+	{PCI_VDEVICE(CCD,      PCI_DEVICE_ID_CCD_B000)			},
+	{PCI_VDEVICE(CCD,      PCI_DEVICE_ID_CCD_B006)			},
+	{PCI_VDEVICE(CCD,      PCI_DEVICE_ID_CCD_B007)			},
+	{PCI_VDEVICE(CCD,      PCI_DEVICE_ID_CCD_B008)			},
+	{PCI_VDEVICE(CCD,      PCI_DEVICE_ID_CCD_B009)			},
+	{PCI_VDEVICE(CCD,      PCI_DEVICE_ID_CCD_B00A)			},
+	{PCI_VDEVICE(CCD,      PCI_DEVICE_ID_CCD_B00B)			},
+	{PCI_VDEVICE(CCD,      PCI_DEVICE_ID_CCD_B00C)			},
+	{PCI_VDEVICE(CCD,      PCI_DEVICE_ID_CCD_B100)			},
+	{PCI_VDEVICE(CCD,      PCI_DEVICE_ID_CCD_B700)			},
+	{PCI_VDEVICE(CCD,      PCI_DEVICE_ID_CCD_B701)			},
+	{PCI_VDEVICE(ABOCOM,   PCI_DEVICE_ID_ABOCOM_2BD1)		},
+	{PCI_VDEVICE(ASUSTEK,  PCI_DEVICE_ID_ASUSTEK_0675)		},
+	{PCI_VDEVICE(BERKOM,   PCI_DEVICE_ID_BERKOM_T_CONCEPT)	},
+	{PCI_VDEVICE(BERKOM,   PCI_DEVICE_ID_BERKOM_A1T)		},
+	{PCI_VDEVICE(ANIGMA,   PCI_DEVICE_ID_ANIGMA_MC145575)	},
+	{PCI_VDEVICE(ZOLTRIX,  PCI_DEVICE_ID_ZOLTRIX_2BD0)		},
+	{PCI_VDEVICE(DIGI,     PCI_DEVICE_ID_DIGI_DF_M_IOM2_E)	},
+	{PCI_VDEVICE(DIGI,     PCI_DEVICE_ID_DIGI_DF_M_E)		},
+	{PCI_VDEVICE(DIGI,     PCI_DEVICE_ID_DIGI_DF_M_IOM2_A)	},
+	{PCI_VDEVICE(DIGI,     PCI_DEVICE_ID_DIGI_DF_M_A)		},
 #endif
 	{ }				/* Terminating entry */
 };
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
index 8b853d5..c0771f9 100644
--- a/drivers/isdn/hisax/q931.c
+++ b/drivers/isdn/hisax/q931.c
@@ -1152,20 +1152,11 @@
 {
 	register int i;
 	register char *t = txt;
-	register u_char w;
 
 	for (i = 0; i < cnt; i++) {
 		*t++ = ' ';
-		w = (p[i] >> 4) & 0x0f;
-		if (w < 10)
-			*t++ = '0' + w;
-		else
-			*t++ = 'A' - 10 + w;
-		w = p[i] & 0x0f;
-		if (w < 10)
-			*t++ = '0' + w;
-		else
-			*t++ = 'A' - 10 + w;
+		*t++ = hex_asc_hi(p[i]);
+		*t++ = hex_asc_lo(p[i]);
 	}
 	*t++ = 0;
 	return (t - txt);
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 8096646..96b3e39 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -17,11 +17,12 @@
 #include <linux/proc_fs.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <net/net_namespace.h>
 
 #include "hysdn_defs.h"
 
+static DEFINE_MUTEX(hysdn_conf_mutex);
 static char *hysdn_procconf_revision = "$Revision: 1.8.6.4 $";
 
 #define INFO_OUT_LEN 80		/* length of info line including lf */
@@ -234,7 +235,7 @@
 	char *cp, *tmp;
 
 	/* now search the addressed card */
-	lock_kernel();
+	mutex_lock(&hysdn_conf_mutex);
 	card = card_root;
 	while (card) {
 		pd = card->procconf;
@@ -243,7 +244,7 @@
 		card = card->next;	/* search next entry */
 	}
 	if (!card) {
-		unlock_kernel();
+		mutex_unlock(&hysdn_conf_mutex);
 		return (-ENODEV);	/* device is unknown/invalid */
 	}
 	if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
@@ -255,7 +256,7 @@
 		/* write only access -> write boot file or conf line */
 
 		if (!(cnf = kmalloc(sizeof(struct conf_writedata), GFP_KERNEL))) {
-			unlock_kernel();
+			mutex_unlock(&hysdn_conf_mutex);
 			return (-EFAULT);
 		}
 		cnf->card = card;
@@ -267,7 +268,7 @@
 		/* read access -> output card info data */
 
 		if (!(tmp = kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) {
-			unlock_kernel();
+			mutex_unlock(&hysdn_conf_mutex);
 			return (-EFAULT);	/* out of memory */
 		}
 		filep->private_data = tmp;	/* start of string */
@@ -301,10 +302,10 @@
 		*cp++ = '\n';
 		*cp = 0;	/* end of string */
 	} else {		/* simultaneous read/write access forbidden ! */
-		unlock_kernel();
+		mutex_unlock(&hysdn_conf_mutex);
 		return (-EPERM);	/* no permission this time */
 	}
-	unlock_kernel();
+	mutex_unlock(&hysdn_conf_mutex);
 	return nonseekable_open(ino, filep);
 }				/* hysdn_conf_open */
 
@@ -319,7 +320,7 @@
 	int retval = 0;
 	struct proc_dir_entry *pd;
 
-	lock_kernel();
+	mutex_lock(&hysdn_conf_mutex);
 	/* search the addressed card */
 	card = card_root;
 	while (card) {
@@ -329,7 +330,7 @@
 		card = card->next;	/* search next entry */
 	}
 	if (!card) {
-		unlock_kernel();
+		mutex_unlock(&hysdn_conf_mutex);
 		return (-ENODEV);	/* device is unknown/invalid */
 	}
 	if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
@@ -352,7 +353,7 @@
 
 		kfree(filep->private_data);	/* release memory */
 	}
-	unlock_kernel();
+	mutex_unlock(&hysdn_conf_mutex);
 	return (retval);
 }				/* hysdn_conf_close */
 
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index e83f6fd..2ee93d0 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -15,13 +15,15 @@
 #include <linux/proc_fs.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
 
 #include "hysdn_defs.h"
 
 /* the proc subdir for the interface is defined in the procconf module */
 extern struct proc_dir_entry *hysdn_proc_entry;
 
+static DEFINE_MUTEX(hysdn_log_mutex);
 static void put_log_buffer(hysdn_card * card, char *cp);
 
 /*************************************************/
@@ -154,10 +156,9 @@
 hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
 {
 	unsigned long u = 0;
-	int found = 0;
-	unsigned char *cp, valbuf[128];
-	long base = 10;
-	hysdn_card *card = (hysdn_card *) file->private_data;
+	int rc;
+	unsigned char valbuf[128];
+	hysdn_card *card = file->private_data;
 
 	if (count > (sizeof(valbuf) - 1))
 		count = sizeof(valbuf) - 1;	/* limit length */
@@ -165,32 +166,10 @@
 		return (-EFAULT);	/* copy failed */
 
 	valbuf[count] = 0;	/* terminating 0 */
-	cp = valbuf;
-	if ((count > 2) && (valbuf[0] == '0') && (valbuf[1] == 'x')) {
-		cp += 2;	/* pointer after hex modifier */
-		base = 16;
-	}
-	/* scan the input for debug flags */
-	while (*cp) {
-		if ((*cp >= '0') && (*cp <= '9')) {
-			found = 1;
-			u *= base;	/* adjust to next digit */
-			u += *cp++ - '0';
-			continue;
-		}
-		if (base != 16)
-			break;	/* end of number */
 
-		if ((*cp >= 'a') && (*cp <= 'f')) {
-			found = 1;
-			u *= base;	/* adjust to next digit */
-			u += *cp++ - 'a' + 10;
-			continue;
-		}
-		break;		/* terminated */
-	}
+	rc = strict_strtoul(valbuf, 0, &u);
 
-	if (found) {
+	if (rc == 0) {
 		card->debug_flags = u;	/* remember debug flags */
 		hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags);
 	}
@@ -251,7 +230,7 @@
 	struct procdata *pd = NULL;
 	unsigned long flags;
 
-	lock_kernel();
+	mutex_lock(&hysdn_log_mutex);
 	card = card_root;
 	while (card) {
 		pd = card->proclog;
@@ -260,7 +239,7 @@
 		card = card->next;	/* search next entry */
 	}
 	if (!card) {
-		unlock_kernel();
+		mutex_unlock(&hysdn_log_mutex);
 		return (-ENODEV);	/* device is unknown/invalid */
 	}
 	filep->private_data = card;	/* remember our own card */
@@ -278,10 +257,10 @@
 			filep->private_data = &pd->log_head;
 		spin_unlock_irqrestore(&card->hysdn_lock, flags);
 	} else {		/* simultaneous read/write access forbidden ! */
-		unlock_kernel();
+		mutex_unlock(&hysdn_log_mutex);
 		return (-EPERM);	/* no permission this time */
 	}
-	unlock_kernel();
+	mutex_unlock(&hysdn_log_mutex);
 	return nonseekable_open(ino, filep);
 }				/* hysdn_log_open */
 
@@ -300,7 +279,7 @@
 	hysdn_card *card;
 	int retval = 0;
 
-	lock_kernel();
+	mutex_lock(&hysdn_log_mutex);
 	if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
 		/* write only access -> write debug level written */
 		retval = 0;	/* success */
@@ -339,7 +318,7 @@
 					kfree(inf);
 				}
 	}			/* read access */
-	unlock_kernel();
+	mutex_unlock(&hysdn_log_mutex);
 
 	return (retval);
 }				/* hysdn_log_close */
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index a44cdb4..15632bd 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -17,7 +17,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/isdn.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include "isdn_common.h"
 #include "isdn_tty.h"
 #include "isdn_net.h"
@@ -42,6 +42,7 @@
 
 isdn_dev *dev;
 
+static DEFINE_MUTEX(isdn_mutex);
 static char *isdn_revision = "$Revision: 1.1.2.3 $";
 
 extern char *isdn_net_revision;
@@ -1070,7 +1071,7 @@
 	int retval;
 	char *p;
 
-	lock_kernel();
+	mutex_lock(&isdn_mutex);
 	if (minor == ISDN_MINOR_STATUS) {
 		if (!file->private_data) {
 			if (file->f_flags & O_NONBLOCK) {
@@ -1163,7 +1164,7 @@
 #endif
 	retval = -ENODEV;
  out:
-	unlock_kernel();
+	mutex_unlock(&isdn_mutex);
 	return retval;
 }
 
@@ -1180,7 +1181,7 @@
 	if (!dev->drivers)
 		return -ENODEV;
 
-	lock_kernel();
+	mutex_lock(&isdn_mutex);
 	if (minor <= ISDN_MINOR_BMAX) {
 		printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
 		drvidx = isdn_minor2drv(minor);
@@ -1225,7 +1226,7 @@
 #endif
 	retval = -ENODEV;
  out:
-	unlock_kernel();
+	mutex_unlock(&isdn_mutex);
 	return retval;
 }
 
@@ -1236,7 +1237,7 @@
 	unsigned int minor = iminor(file->f_path.dentry->d_inode);
 	int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
 
-	lock_kernel();
+	mutex_lock(&isdn_mutex);
 	if (minor == ISDN_MINOR_STATUS) {
 		poll_wait(file, &(dev->info_waitq), wait);
 		/* mask = POLLOUT | POLLWRNORM; */
@@ -1266,7 +1267,7 @@
 #endif
 	mask = POLLERR;
  out:
-	unlock_kernel();
+	mutex_unlock(&isdn_mutex);
 	return mask;
 }
 
@@ -1727,9 +1728,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&isdn_mutex);
 	ret = isdn_ioctl(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&isdn_mutex);
 
 	return ret;
 }
@@ -1745,7 +1746,7 @@
 	int chidx;
 	int retval = -ENODEV;
 
-	lock_kernel();
+	mutex_lock(&isdn_mutex);
 	if (minor == ISDN_MINOR_STATUS) {
 		infostruct *p;
 
@@ -1796,7 +1797,7 @@
 #endif
  out:
 	nonseekable_open(ino, filep);
-	unlock_kernel();
+	mutex_unlock(&isdn_mutex);
 	return retval;
 }
 
@@ -1805,7 +1806,7 @@
 {
 	uint minor = iminor(ino);
 
-	lock_kernel();
+	mutex_lock(&isdn_mutex);
 	if (minor == ISDN_MINOR_STATUS) {
 		infostruct *p = dev->infochain;
 		infostruct *q = NULL;
@@ -1839,7 +1840,7 @@
 #endif
 
  out:
-	unlock_kernel();
+	mutex_unlock(&isdn_mutex);
 	return 0;
 }
 
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 8c85d1e..26d44c3 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -2924,16 +2924,17 @@
 		cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
 		cfg->dialwait = lp->dialwait / HZ;
 		if (lp->slave) {
-			if (strlen(lp->slave->name) > 8)
+			if (strlen(lp->slave->name) >= 10)
 				strcpy(cfg->slave, "too-long");
 			else
 				strcpy(cfg->slave, lp->slave->name);
 		} else
 			cfg->slave[0] = '\0';
 		if (lp->master) {
-			if (strlen(lp->master->name) > 8)
+			if (strlen(lp->master->name) >= 10)
 				strcpy(cfg->master, "too-long");
-			strcpy(cfg->master, lp->master->name);
+			else
+				strcpy(cfg->master, lp->master->name);
 		} else
 			cfg->master[0] = '\0';
 		return 0;
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index f37b8f6..fe824e0 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -449,14 +449,9 @@
 
 	/* uprog.len is unsigned short, so no overflow here */
 	len = uprog.len * sizeof(struct sock_filter);
-	code = kmalloc(len, GFP_KERNEL);
-	if (code == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(code, uprog.filter, len)) {
-		kfree(code);
-		return -EFAULT;
-	}
+	code = memdup_user(uprog.filter, len);
+	if (IS_ERR(code))
+		return PTR_ERR(code);
 
 	err = sk_chk_filter(code, uprog.len);
 	if (err) {
@@ -482,7 +477,7 @@
 	struct isdn_ppp_comp_data data;
 	void __user *argp = (void __user *)arg;
 
-	is = (struct ippp_struct *) file->private_data;
+	is = file->private_data;
 	lp = is->lp;
 
 	if (is->debug & 0x1)
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index fc8454d..51dc60d 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -2636,12 +2636,6 @@
 		if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
 			return;
 		}
-#ifdef CONFIG_ISDN_AUDIO
-		if ( !info->vonline )
-			tty_ldisc_flush(info->tty);
-#else
-		tty_ldisc_flush(info->tty);
-#endif
 		if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
 		    (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
 		       (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c
index 81048b8..de43c8c 100644
--- a/drivers/isdn/mISDN/timerdev.c
+++ b/drivers/isdn/mISDN/timerdev.c
@@ -24,9 +24,10 @@
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/mISDNif.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include "core.h"
 
+static DEFINE_MUTEX(mISDN_mutex);
 static u_int	*debug;
 
 
@@ -224,7 +225,7 @@
 	if (*debug & DEBUG_TIMER)
 		printk(KERN_DEBUG "%s(%p, %x, %lx)\n", __func__,
 		    filep, cmd, arg);
-	lock_kernel();
+	mutex_lock(&mISDN_mutex);
 	switch (cmd) {
 	case IMADDTIMER:
 		if (get_user(tout, (int __user *)arg)) {
@@ -256,7 +257,7 @@
 	default:
 		ret = -EINVAL;
 	}
-	unlock_kernel();
+	mutex_unlock(&mISDN_mutex);
 	return ret;
 }
 
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
index 123c1d6..1507d2e 100644
--- a/drivers/isdn/pcbit/drv.c
+++ b/drivers/isdn/pcbit/drv.c
@@ -411,14 +411,10 @@
 			return -EINVAL;
 		}
 
-		cbuf = kmalloc(len, GFP_KERNEL);
-		if (!cbuf)
-			return -ENOMEM;
+		cbuf = memdup_user(buf, len);
+		if (IS_ERR(cbuf))
+			return PTR_ERR(cbuf);
 
-		if (copy_from_user(cbuf, buf, len)) {
-			kfree(cbuf);
-			return -EFAULT;
-		}
 		memcpy_toio(dev->sh_mem, cbuf, len);
 		kfree(cbuf);
 		return len;
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
index 1081091..43c5dc35 100644
--- a/drivers/isdn/sc/ioctl.c
+++ b/drivers/isdn/sc/ioctl.c
@@ -215,19 +215,13 @@
 		pr_debug("%s: DCBIOSETSPID: ioctl received\n",
 				sc_adapter[card]->devicename);
 
-		spid = kmalloc(SCIOC_SPIDSIZE, GFP_KERNEL);
-		if(!spid) {
-			kfree(rcvmsg);
-			return -ENOMEM;
-		}
-
 		/*
 		 * Get the spid from user space
 		 */
-		if (copy_from_user(spid, data->dataptr, SCIOC_SPIDSIZE)) {
+		spid = memdup_user(data->dataptr, SCIOC_SPIDSIZE);
+		if (IS_ERR(spid)) {
 			kfree(rcvmsg);
-			kfree(spid);
-			return -EFAULT;
+			return PTR_ERR(spid);
 		}
 
 		pr_debug("%s: SCIOCSETSPID: setting channel %d spid to %s\n", 
@@ -296,18 +290,13 @@
 		pr_debug("%s: SCIOSETDN: ioctl received\n",
 				sc_adapter[card]->devicename);
 
-		dn = kmalloc(SCIOC_DNSIZE, GFP_KERNEL);
-		if (!dn) {
-			kfree(rcvmsg);
-			return -ENOMEM;
-		}
 		/*
 		 * Get the spid from user space
 		 */
-		if (copy_from_user(dn, data->dataptr, SCIOC_DNSIZE)) {
+		dn = memdup_user(data->dataptr, SCIOC_DNSIZE);
+		if (IS_ERR(dn)) {
 			kfree(rcvmsg);
-			kfree(dn);
-			return -EFAULT;
+			return PTR_ERR(dn);
 		}
 
 		pr_debug("%s: SCIOCSETDN: setting channel %d dn to %s\n", 
diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig
index d22a8ec..999a825 100644
--- a/drivers/media/IR/Kconfig
+++ b/drivers/media/IR/Kconfig
@@ -8,6 +8,17 @@
 	depends on IR_CORE
 	default IR_CORE
 
+config LIRC
+	tristate
+	default y
+
+	---help---
+	   Enable this option to build the Linux Infrared Remote
+	   Control (LIRC) core device interface driver. The LIRC
+	   interface passes raw IR to and from userspace, where the
+	   LIRC daemon handles protocol decoding for IR reception ann
+	   encoding for IR transmitting (aka "blasting").
+
 source "drivers/media/IR/keymaps/Kconfig"
 
 config IR_NEC_DECODER
@@ -33,6 +44,7 @@
 config IR_RC6_DECODER
 	tristate "Enable IR raw decoder for the RC6 protocol"
 	depends on IR_CORE
+	select BITREVERSE
 	default y
 
 	---help---
@@ -42,6 +54,7 @@
 config IR_JVC_DECODER
 	tristate "Enable IR raw decoder for the JVC protocol"
 	depends on IR_CORE
+	select BITREVERSE
 	default y
 
 	---help---
@@ -57,6 +70,16 @@
 	   Enable this option if you have an infrared remote control which
 	   uses the Sony protocol, and you need software decoding support.
 
+config IR_LIRC_CODEC
+	tristate "Enable IR to LIRC bridge"
+	depends on IR_CORE
+	depends on LIRC
+	default y
+
+	---help---
+	   Enable this option to pass raw IR to and from userspace via
+	   the LIRC interface.
+
 config IR_IMON
 	tristate "SoundGraph iMON Receiver and Display"
 	depends on USB_ARCH_HAS_HCD
@@ -68,3 +91,15 @@
 
 	   To compile this driver as a module, choose M here: the
 	   module will be called imon.
+
+config IR_MCEUSB
+	tristate "Windows Media Center Ed. eHome Infrared Transceiver"
+	depends on USB_ARCH_HAS_HCD
+	depends on IR_CORE
+	select USB
+	---help---
+	   Say Y here if you want to use a Windows Media Center Edition
+	   eHome Infrared Transceiver.
+
+	   To compile this driver as a module, choose M here: the
+	   module will be called mceusb.
diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile
index b998fcc..2ae4f3a 100644
--- a/drivers/media/IR/Makefile
+++ b/drivers/media/IR/Makefile
@@ -5,11 +5,14 @@
 
 obj-$(CONFIG_IR_CORE) += ir-core.o
 obj-$(CONFIG_VIDEO_IR) += ir-common.o
+obj-$(CONFIG_LIRC) += lirc_dev.o
 obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
 obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
 obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
 obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
 obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
+obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
 
 # stand-alone IR receivers/transmitters
 obj-$(CONFIG_IR_IMON) += imon.o
+obj-$(CONFIG_IR_MCEUSB) += mceusb.o
diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c
index 4bbd45f..65c125e 100644
--- a/drivers/media/IR/imon.c
+++ b/drivers/media/IR/imon.c
@@ -407,7 +407,7 @@
 	struct imon_context *ictx = NULL;
 	int retval = 0;
 
-	ictx = (struct imon_context *)file->private_data;
+	ictx = file->private_data;
 
 	if (!ictx) {
 		err("%s: no context for device", __func__);
@@ -812,7 +812,7 @@
 	const unsigned char vfd_packet6[] = {
 		0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
 
-	ictx = (struct imon_context *)file->private_data;
+	ictx = file->private_data;
 	if (!ictx) {
 		err("%s: no context for device", __func__);
 		return -ENODEV;
@@ -896,7 +896,7 @@
 	int retval = 0;
 	struct imon_context *ictx;
 
-	ictx = (struct imon_context *)file->private_data;
+	ictx = file->private_data;
 	if (!ictx) {
 		err("%s: no context for device", __func__);
 		return -ENODEV;
@@ -1943,7 +1943,7 @@
 	return ictx;
 
 urb_submit_failed:
-	input_unregister_device(ictx->idev);
+	ir_input_unregister(ictx->idev);
 	input_free_device(ictx->idev);
 idev_setup_failed:
 find_endpoint_failed:
@@ -2067,6 +2067,7 @@
 		detected_display_type = IMON_DISPLAY_TYPE_VFD;
 		break;
 	/* iMON LCD, MCE IR */
+	case 0x9e:
 	case 0x9f:
 		dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
 		detected_display_type = IMON_DISPLAY_TYPE_LCD;
@@ -2306,7 +2307,7 @@
 	if (ifnum == 0) {
 		ictx->dev_present_intf0 = false;
 		usb_kill_urb(ictx->rx_urb_intf0);
-		input_unregister_device(ictx->idev);
+		ir_input_unregister(ictx->idev);
 		if (ictx->display_supported) {
 			if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
 				usb_deregister_dev(interface, &imon_lcd_class);
diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
index 9a5e65a..babd520 100644
--- a/drivers/media/IR/ir-core-priv.h
+++ b/drivers/media/IR/ir-core-priv.h
@@ -22,17 +22,62 @@
 struct ir_raw_handler {
 	struct list_head list;
 
+	u64 protocols; /* which are handled by this handler */
 	int (*decode)(struct input_dev *input_dev, struct ir_raw_event event);
+
+	/* These two should only be used by the lirc decoder */
 	int (*raw_register)(struct input_dev *input_dev);
 	int (*raw_unregister)(struct input_dev *input_dev);
 };
 
 struct ir_raw_event_ctrl {
+	struct list_head		list;		/* to keep track of raw clients */
 	struct work_struct		rx_work;	/* for the rx decoding workqueue */
 	struct kfifo			kfifo;		/* fifo for the pulse/space durations */
 	ktime_t				last_event;	/* when last event occurred */
 	enum raw_event_type		last_type;	/* last event type */
 	struct input_dev		*input_dev;	/* pointer to the parent input_dev */
+	u64				enabled_protocols; /* enabled raw protocol decoders */
+
+	/* raw decoder state follows */
+	struct ir_raw_event prev_ev;
+	struct nec_dec {
+		int state;
+		unsigned count;
+		u32 bits;
+	} nec;
+	struct rc5_dec {
+		int state;
+		u32 bits;
+		unsigned count;
+		unsigned wanted_bits;
+	} rc5;
+	struct rc6_dec {
+		int state;
+		u8 header;
+		u32 body;
+		bool toggle;
+		unsigned count;
+		unsigned wanted_bits;
+	} rc6;
+	struct sony_dec {
+		int state;
+		u32 bits;
+		unsigned count;
+	} sony;
+	struct jvc_dec {
+		int state;
+		u16 bits;
+		u16 old_bits;
+		unsigned count;
+		bool first;
+		bool toggle;
+	} jvc;
+	struct lirc_codec {
+		struct ir_input_dev *ir_dev;
+		struct lirc_driver *drv;
+		int lircdata;
+	} lirc;
 };
 
 /* macros for IR decoders */
@@ -74,6 +119,7 @@
 /*
  * Routines from ir-raw-event.c to be used internally and by decoders
  */
+u64 ir_raw_get_allowed_protocols(void);
 int ir_raw_event_register(struct input_dev *input_dev);
 void ir_raw_event_unregister(struct input_dev *input_dev);
 int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
@@ -123,4 +169,12 @@
 #define load_sony_decode()	0
 #endif
 
+/* from ir-lirc-codec.c */
+#ifdef CONFIG_IR_LIRC_CODEC_MODULE
+#define load_lirc_codec()	request_module("ir-lirc-codec")
+#else
+#define load_lirc_codec()	0
+#endif
+
+
 #endif /* _IR_RAW_EVENT */
diff --git a/drivers/media/IR/ir-jvc-decoder.c b/drivers/media/IR/ir-jvc-decoder.c
index 0b80494..8894d8b 100644
--- a/drivers/media/IR/ir-jvc-decoder.c
+++ b/drivers/media/IR/ir-jvc-decoder.c
@@ -25,10 +25,6 @@
 #define JVC_TRAILER_PULSE	(1  * JVC_UNIT)
 #define	JVC_TRAILER_SPACE	(35 * JVC_UNIT)
 
-/* Used to register jvc_decoder clients */
-static LIST_HEAD(decoder_list);
-DEFINE_SPINLOCK(decoder_lock);
-
 enum jvc_state {
 	STATE_INACTIVE,
 	STATE_HEADER_SPACE,
@@ -38,87 +34,6 @@
 	STATE_TRAILER_SPACE,
 };
 
-struct decoder_data {
-	struct list_head	list;
-	struct ir_input_dev	*ir_dev;
-	int			enabled:1;
-
-	/* State machine control */
-	enum jvc_state		state;
-	u16			jvc_bits;
-	u16			jvc_old_bits;
-	unsigned		count;
-	bool			first;
-	bool			toggle;
-};
-
-
-/**
- * get_decoder_data()	- gets decoder data
- * @input_dev:	input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
-{
-	struct decoder_data *data = NULL;
-
-	spin_lock(&decoder_lock);
-	list_for_each_entry(data, &decoder_list, list) {
-		if (data->ir_dev == ir_dev)
-			break;
-	}
-	spin_unlock(&decoder_lock);
-	return data;
-}
-
-static ssize_t store_enabled(struct device *d,
-			     struct device_attribute *mattr,
-			     const char *buf,
-			     size_t len)
-{
-	unsigned long value;
-	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	struct decoder_data *data = get_decoder_data(ir_dev);
-
-	if (!data)
-		return -EINVAL;
-
-	if (strict_strtoul(buf, 10, &value) || value > 1)
-		return -EINVAL;
-
-	data->enabled = value;
-
-	return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-			     struct device_attribute *mattr, char *buf)
-{
-	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	struct decoder_data *data = get_decoder_data(ir_dev);
-
-	if (!data)
-		return -EINVAL;
-
-	if (data->enabled)
-		return sprintf(buf, "1\n");
-	else
-	return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-	&dev_attr_enabled.attr,
-	NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-	.name	= "jvc_decoder",
-	.attrs	= decoder_attributes,
-};
-
 /**
  * ir_jvc_decode() - Decode one JVC pulse or space
  * @input_dev:	the struct input_dev descriptor of the device
@@ -128,14 +43,10 @@
  */
 static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 {
-	struct decoder_data *data;
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	struct jvc_dec *data = &ir_dev->raw->jvc;
 
-	data = get_decoder_data(ir_dev);
-	if (!data)
-		return -EINVAL;
-
-	if (!data->enabled)
+	if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC))
 		return 0;
 
 	if (IS_RESET(ev)) {
@@ -188,9 +99,9 @@
 		if (ev.pulse)
 			break;
 
-		data->jvc_bits <<= 1;
+		data->bits <<= 1;
 		if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
-			data->jvc_bits |= 1;
+			data->bits |= 1;
 			decrease_duration(&ev, JVC_BIT_1_SPACE);
 		} else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
 			decrease_duration(&ev, JVC_BIT_0_SPACE);
@@ -223,13 +134,13 @@
 
 		if (data->first) {
 			u32 scancode;
-			scancode = (bitrev8((data->jvc_bits >> 8) & 0xff) << 8) |
-				   (bitrev8((data->jvc_bits >> 0) & 0xff) << 0);
+			scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
+				   (bitrev8((data->bits >> 0) & 0xff) << 0);
 			IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
 			ir_keydown(input_dev, scancode, data->toggle);
 			data->first = false;
-			data->jvc_old_bits = data->jvc_bits;
-		} else if (data->jvc_bits == data->jvc_old_bits) {
+			data->old_bits = data->bits;
+		} else if (data->bits == data->old_bits) {
 			IR_dprintk(1, "JVC repeat\n");
 			ir_repeat(input_dev);
 		} else {
@@ -249,54 +160,9 @@
 	return -EINVAL;
 }
 
-static int ir_jvc_register(struct input_dev *input_dev)
-{
-	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	struct decoder_data *data;
-	int rc;
-
-	rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-	if (rc < 0)
-		return rc;
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-		return -ENOMEM;
-	}
-
-	data->ir_dev = ir_dev;
-	data->enabled = 1;
-
-	spin_lock(&decoder_lock);
-	list_add_tail(&data->list, &decoder_list);
-	spin_unlock(&decoder_lock);
-
-	return 0;
-}
-
-static int ir_jvc_unregister(struct input_dev *input_dev)
-{
-	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	static struct decoder_data *data;
-
-	data = get_decoder_data(ir_dev);
-	if (!data)
-		return 0;
-
-	sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
-	spin_lock(&decoder_lock);
-	list_del(&data->list);
-	spin_unlock(&decoder_lock);
-
-	return 0;
-}
-
 static struct ir_raw_handler jvc_handler = {
+	.protocols	= IR_TYPE_JVC,
 	.decode		= ir_jvc_decode,
-	.raw_register	= ir_jvc_register,
-	.raw_unregister	= ir_jvc_unregister,
 };
 
 static int __init ir_jvc_decode_init(void)
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index 94a8577..15a0f19 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -497,8 +497,9 @@
 				goto out_event;
 		}
 
-	IR_dprintk(1, "Registered input device on %s for %s remote.\n",
-		   driver_name, rc_tab->name);
+	IR_dprintk(1, "Registered input device on %s for %s remote%s.\n",
+		   driver_name, rc_tab->name,
+		   ir_dev->props->driver_type == RC_DRIVER_IR_RAW ? " in raw mode" : "");
 
 	return 0;
 
diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c
new file mode 100644
index 0000000..3ba482d
--- /dev/null
+++ b/drivers/media/IR/ir-lirc-codec.c
@@ -0,0 +1,278 @@
+/* ir-lirc-codec.c - ir-core to classic lirc interface bridge
+ *
+ * Copyright (C) 2010 by Jarod Wilson <jarod@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 version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+#include <media/ir-core.h>
+#include "ir-core-priv.h"
+
+#define LIRCBUF_SIZE 256
+
+/**
+ * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the
+ *		      lircd userspace daemon for decoding.
+ * @input_dev:	the struct input_dev descriptor of the device
+ * @duration:	the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the lirc interfaces aren't wired up.
+ */
+static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+
+	if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC))
+		return 0;
+
+	if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf)
+		return -EINVAL;
+
+	IR_dprintk(2, "LIRC data transfer started (%uus %s)\n",
+		   TO_US(ev.duration), TO_STR(ev.pulse));
+
+	ir_dev->raw->lirc.lircdata += ev.duration / 1000;
+	if (ev.pulse)
+		ir_dev->raw->lirc.lircdata |= PULSE_BIT;
+
+	lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
+			  (unsigned char *) &ir_dev->raw->lirc.lircdata);
+	wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll);
+
+	ir_dev->raw->lirc.lircdata = 0;
+
+	return 0;
+}
+
+static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf,
+				   size_t n, loff_t *ppos)
+{
+	struct lirc_codec *lirc;
+	struct ir_input_dev *ir_dev;
+	int *txbuf; /* buffer with values to transmit */
+	int ret = 0, count;
+
+	lirc = lirc_get_pdata(file);
+	if (!lirc)
+		return -EFAULT;
+
+	if (n % sizeof(int))
+		return -EINVAL;
+
+	count = n / sizeof(int);
+	if (count > LIRCBUF_SIZE || count % 2 == 0)
+		return -EINVAL;
+
+	txbuf = memdup_user(buf, n);
+	if (IS_ERR(txbuf))
+		return PTR_ERR(txbuf);
+
+	ir_dev = lirc->ir_dev;
+	if (!ir_dev) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	if (ir_dev->props && ir_dev->props->tx_ir)
+		ret = ir_dev->props->tx_ir(ir_dev->props->priv, txbuf, (u32)n);
+
+out:
+	kfree(txbuf);
+	return ret;
+}
+
+static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+	struct lirc_codec *lirc;
+	struct ir_input_dev *ir_dev;
+	int ret = 0;
+	void *drv_data;
+	unsigned long val;
+
+	lirc = lirc_get_pdata(filep);
+	if (!lirc)
+		return -EFAULT;
+
+	ir_dev = lirc->ir_dev;
+	if (!ir_dev || !ir_dev->props || !ir_dev->props->priv)
+		return -EFAULT;
+
+	drv_data = ir_dev->props->priv;
+
+	switch (cmd) {
+	case LIRC_SET_TRANSMITTER_MASK:
+		ret = get_user(val, (unsigned long *)arg);
+		if (ret)
+			return ret;
+
+		if (ir_dev->props && ir_dev->props->s_tx_mask)
+			ret = ir_dev->props->s_tx_mask(drv_data, (u32)val);
+		else
+			return -EINVAL;
+		break;
+
+	case LIRC_SET_SEND_CARRIER:
+		ret = get_user(val, (unsigned long *)arg);
+		if (ret)
+			return ret;
+
+		if (ir_dev->props && ir_dev->props->s_tx_carrier)
+			ir_dev->props->s_tx_carrier(drv_data, (u32)val);
+		else
+			return -EINVAL;
+		break;
+
+	case LIRC_GET_SEND_MODE:
+		val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK;
+		ret = put_user(val, (unsigned long *)arg);
+		break;
+
+	case LIRC_SET_SEND_MODE:
+		ret = get_user(val, (unsigned long *)arg);
+		if (ret)
+			return ret;
+
+		if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK))
+			return -EINVAL;
+		break;
+
+	default:
+		return lirc_dev_fop_ioctl(filep, cmd, arg);
+	}
+
+	return ret;
+}
+
+static int ir_lirc_open(void *data)
+{
+	return 0;
+}
+
+static void ir_lirc_close(void *data)
+{
+	return;
+}
+
+static struct file_operations lirc_fops = {
+	.owner		= THIS_MODULE,
+	.write		= ir_lirc_transmit_ir,
+	.unlocked_ioctl	= ir_lirc_ioctl,
+	.read		= lirc_dev_fop_read,
+	.poll		= lirc_dev_fop_poll,
+	.open		= lirc_dev_fop_open,
+	.release	= lirc_dev_fop_close,
+};
+
+static int ir_lirc_register(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	struct lirc_driver *drv;
+	struct lirc_buffer *rbuf;
+	int rc = -ENOMEM;
+	unsigned long features;
+
+	drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+	if (!drv)
+		return rc;
+
+	rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+	if (!rbuf)
+		goto rbuf_alloc_failed;
+
+	rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE);
+	if (rc)
+		goto rbuf_init_failed;
+
+	features = LIRC_CAN_REC_MODE2;
+	if (ir_dev->props->tx_ir) {
+		features |= LIRC_CAN_SEND_PULSE;
+		if (ir_dev->props->s_tx_mask)
+			features |= LIRC_CAN_SET_TRANSMITTER_MASK;
+		if (ir_dev->props->s_tx_carrier)
+			features |= LIRC_CAN_SET_SEND_CARRIER;
+	}
+
+	snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)",
+		 ir_dev->driver_name);
+	drv->minor = -1;
+	drv->features = features;
+	drv->data = &ir_dev->raw->lirc;
+	drv->rbuf = rbuf;
+	drv->set_use_inc = &ir_lirc_open;
+	drv->set_use_dec = &ir_lirc_close;
+	drv->code_length = sizeof(struct ir_raw_event) * 8;
+	drv->fops = &lirc_fops;
+	drv->dev = &ir_dev->dev;
+	drv->owner = THIS_MODULE;
+
+	drv->minor = lirc_register_driver(drv);
+	if (drv->minor < 0) {
+		rc = -ENODEV;
+		goto lirc_register_failed;
+	}
+
+	ir_dev->raw->lirc.drv = drv;
+	ir_dev->raw->lirc.ir_dev = ir_dev;
+	ir_dev->raw->lirc.lircdata = PULSE_MASK;
+
+	return 0;
+
+lirc_register_failed:
+rbuf_init_failed:
+	kfree(rbuf);
+rbuf_alloc_failed:
+	kfree(drv);
+
+	return rc;
+}
+
+static int ir_lirc_unregister(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	struct lirc_codec *lirc = &ir_dev->raw->lirc;
+
+	lirc_unregister_driver(lirc->drv->minor);
+	lirc_buffer_free(lirc->drv->rbuf);
+	kfree(lirc->drv);
+
+	return 0;
+}
+
+static struct ir_raw_handler lirc_handler = {
+	.protocols	= IR_TYPE_LIRC,
+	.decode		= ir_lirc_decode,
+	.raw_register	= ir_lirc_register,
+	.raw_unregister	= ir_lirc_unregister,
+};
+
+static int __init ir_lirc_codec_init(void)
+{
+	ir_raw_handler_register(&lirc_handler);
+
+	printk(KERN_INFO "IR LIRC bridge handler initialized\n");
+	return 0;
+}
+
+static void __exit ir_lirc_codec_exit(void)
+{
+	ir_raw_handler_unregister(&lirc_handler);
+}
+
+module_init(ir_lirc_codec_init);
+module_exit(ir_lirc_codec_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("LIRC IR handler bridge");
diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c
index ba79233..52e0f37 100644
--- a/drivers/media/IR/ir-nec-decoder.c
+++ b/drivers/media/IR/ir-nec-decoder.c
@@ -27,10 +27,6 @@
 #define	NEC_TRAILER_PULSE	(1  * NEC_UNIT)
 #define	NEC_TRAILER_SPACE	(10 * NEC_UNIT) /* even longer in reality */
 
-/* Used to register nec_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
 enum nec_state {
 	STATE_INACTIVE,
 	STATE_HEADER_SPACE,
@@ -40,84 +36,6 @@
 	STATE_TRAILER_SPACE,
 };
 
-struct decoder_data {
-	struct list_head	list;
-	struct ir_input_dev	*ir_dev;
-	int			enabled:1;
-
-	/* State machine control */
-	enum nec_state		state;
-	u32			nec_bits;
-	unsigned		count;
-};
-
-
-/**
- * get_decoder_data()	- gets decoder data
- * @input_dev:	input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
-{
-	struct decoder_data *data = NULL;
-
-	spin_lock(&decoder_lock);
-	list_for_each_entry(data, &decoder_list, list) {
-		if (data->ir_dev == ir_dev)
-			break;
-	}
-	spin_unlock(&decoder_lock);
-	return data;
-}
-
-static ssize_t store_enabled(struct device *d,
-			     struct device_attribute *mattr,
-			     const char *buf,
-			     size_t len)
-{
-	unsigned long value;
-	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	struct decoder_data *data = get_decoder_data(ir_dev);
-
-	if (!data)
-		return -EINVAL;
-
-	if (strict_strtoul(buf, 10, &value) || value > 1)
-		return -EINVAL;
-
-	data->enabled = value;
-
-	return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-			     struct device_attribute *mattr, char *buf)
-{
-	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	struct decoder_data *data = get_decoder_data(ir_dev);
-
-	if (!data)
-		return -EINVAL;
-
-	if (data->enabled)
-		return sprintf(buf, "1\n");
-	else
-	return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-	&dev_attr_enabled.attr,
-	NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-	.name	= "nec_decoder",
-	.attrs	= decoder_attributes,
-};
-
 /**
  * ir_nec_decode() - Decode one NEC pulse or space
  * @input_dev:	the struct input_dev descriptor of the device
@@ -127,16 +45,12 @@
  */
 static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 {
-	struct decoder_data *data;
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	struct nec_dec *data = &ir_dev->raw->nec;
 	u32 scancode;
 	u8 address, not_address, command, not_command;
 
-	data = get_decoder_data(ir_dev);
-	if (!data)
-		return -EINVAL;
-
-	if (!data->enabled)
+	if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC))
 		return 0;
 
 	if (IS_RESET(ev)) {
@@ -191,9 +105,9 @@
 		if (ev.pulse)
 			break;
 
-		data->nec_bits <<= 1;
+		data->bits <<= 1;
 		if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2))
-			data->nec_bits |= 1;
+			data->bits |= 1;
 		else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
 			break;
 		data->count++;
@@ -222,14 +136,14 @@
 		if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
 			break;
 
-		address     = bitrev8((data->nec_bits >> 24) & 0xff);
-		not_address = bitrev8((data->nec_bits >> 16) & 0xff);
-		command	    = bitrev8((data->nec_bits >>  8) & 0xff);
-		not_command = bitrev8((data->nec_bits >>  0) & 0xff);
+		address     = bitrev8((data->bits >> 24) & 0xff);
+		not_address = bitrev8((data->bits >> 16) & 0xff);
+		command	    = bitrev8((data->bits >>  8) & 0xff);
+		not_command = bitrev8((data->bits >>  0) & 0xff);
 
 		if ((command ^ not_command) != 0xff) {
 			IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
-				   data->nec_bits);
+				   data->bits);
 			break;
 		}
 
@@ -256,54 +170,9 @@
 	return -EINVAL;
 }
 
-static int ir_nec_register(struct input_dev *input_dev)
-{
-	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	struct decoder_data *data;
-	int rc;
-
-	rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-	if (rc < 0)
-		return rc;
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-		return -ENOMEM;
-	}
-
-	data->ir_dev = ir_dev;
-	data->enabled = 1;
-
-	spin_lock(&decoder_lock);
-	list_add_tail(&data->list, &decoder_list);
-	spin_unlock(&decoder_lock);
-
-	return 0;
-}
-
-static int ir_nec_unregister(struct input_dev *input_dev)
-{
-	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	static struct decoder_data *data;
-
-	data = get_decoder_data(ir_dev);
-	if (!data)
-		return 0;
-
-	sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
-	spin_lock(&decoder_lock);
-	list_del(&data->list);
-	spin_unlock(&decoder_lock);
-
-	return 0;
-}
-
 static struct ir_raw_handler nec_handler = {
+	.protocols	= IR_TYPE_NEC,
 	.decode		= ir_nec_decode,
-	.raw_register	= ir_nec_register,
-	.raw_unregister	= ir_nec_unregister,
 };
 
 static int __init ir_nec_decode_init(void)
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
index ea68a3f..6f192ef 100644
--- a/drivers/media/IR/ir-raw-event.c
+++ b/drivers/media/IR/ir-raw-event.c
@@ -20,35 +20,13 @@
 /* Define the max number of pulse/space transitions to buffer */
 #define MAX_IR_EVENT_SIZE      512
 
-/* Used to handle IR raw handler extensions */
-static LIST_HEAD(ir_raw_handler_list);
-static DEFINE_SPINLOCK(ir_raw_handler_lock);
+/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
+static LIST_HEAD(ir_raw_client_list);
 
-/**
- * RUN_DECODER()	- runs an operation on all IR decoders
- * @ops:	IR raw handler operation to be called
- * @arg:	arguments to be passed to the callback
- *
- * Calls ir_raw_handler::ops for all registered IR handlers. It prevents
- * new decode addition/removal while running, by locking ir_raw_handler_lock
- * mutex. If an error occurs, it stops the ops. Otherwise, it returns a sum
- * of the return codes.
- */
-#define RUN_DECODER(ops, ...) ({					    \
-	struct ir_raw_handler		*_ir_raw_handler;		    \
-	int _sumrc = 0, _rc;						    \
-	spin_lock(&ir_raw_handler_lock);				    \
-	list_for_each_entry(_ir_raw_handler, &ir_raw_handler_list, list) {  \
-		if (_ir_raw_handler->ops) {				    \
-			_rc = _ir_raw_handler->ops(__VA_ARGS__);	    \
-			if (_rc < 0)					    \
-				break;					    \
-			_sumrc += _rc;					    \
-		}							    \
-	}								    \
-	spin_unlock(&ir_raw_handler_lock);				    \
-	_sumrc;								    \
-})
+/* Used to handle IR raw handler extensions */
+static DEFINE_SPINLOCK(ir_raw_handler_lock);
+static LIST_HEAD(ir_raw_handler_list);
+static u64 available_protocols;
 
 #ifdef MODULE
 /* Used to load the decoders */
@@ -58,57 +36,17 @@
 static void ir_raw_event_work(struct work_struct *work)
 {
 	struct ir_raw_event ev;
+	struct ir_raw_handler *handler;
 	struct ir_raw_event_ctrl *raw =
 		container_of(work, struct ir_raw_event_ctrl, rx_work);
 
-	while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev))
-		RUN_DECODER(decode, raw->input_dev, ev);
-}
-
-int ir_raw_event_register(struct input_dev *input_dev)
-{
-	struct ir_input_dev *ir = input_get_drvdata(input_dev);
-	int rc;
-
-	ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
-	if (!ir->raw)
-		return -ENOMEM;
-
-	ir->raw->input_dev = input_dev;
-	INIT_WORK(&ir->raw->rx_work, ir_raw_event_work);
-
-	rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
-			 GFP_KERNEL);
-	if (rc < 0) {
-		kfree(ir->raw);
-		ir->raw = NULL;
-		return rc;
+	while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) {
+		spin_lock(&ir_raw_handler_lock);
+		list_for_each_entry(handler, &ir_raw_handler_list, list)
+			handler->decode(raw->input_dev, ev);
+		spin_unlock(&ir_raw_handler_lock);
+		raw->prev_ev = ev;
 	}
-
-	rc = RUN_DECODER(raw_register, input_dev);
-	if (rc < 0) {
-		kfifo_free(&ir->raw->kfifo);
-		kfree(ir->raw);
-		ir->raw = NULL;
-		return rc;
-	}
-
-	return rc;
-}
-
-void ir_raw_event_unregister(struct input_dev *input_dev)
-{
-	struct ir_input_dev *ir = input_get_drvdata(input_dev);
-
-	if (!ir->raw)
-		return;
-
-	cancel_work_sync(&ir->raw->rx_work);
-	RUN_DECODER(raw_unregister, input_dev);
-
-	kfifo_free(&ir->raw->kfifo);
-	kfree(ir->raw);
-	ir->raw = NULL;
 }
 
 /**
@@ -204,23 +142,103 @@
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 
+/* used internally by the sysfs interface */
+u64
+ir_raw_get_allowed_protocols()
+{
+	u64 protocols;
+	spin_lock(&ir_raw_handler_lock);
+	protocols = available_protocols;
+	spin_unlock(&ir_raw_handler_lock);
+	return protocols;
+}
+
+/*
+ * Used to (un)register raw event clients
+ */
+int ir_raw_event_register(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir = input_get_drvdata(input_dev);
+	int rc;
+	struct ir_raw_handler *handler;
+
+	ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
+	if (!ir->raw)
+		return -ENOMEM;
+
+	ir->raw->input_dev = input_dev;
+	INIT_WORK(&ir->raw->rx_work, ir_raw_event_work);
+	ir->raw->enabled_protocols = ~0;
+	rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
+			 GFP_KERNEL);
+	if (rc < 0) {
+		kfree(ir->raw);
+		ir->raw = NULL;
+		return rc;
+	}
+
+	spin_lock(&ir_raw_handler_lock);
+	list_add_tail(&ir->raw->list, &ir_raw_client_list);
+	list_for_each_entry(handler, &ir_raw_handler_list, list)
+		if (handler->raw_register)
+			handler->raw_register(ir->raw->input_dev);
+	spin_unlock(&ir_raw_handler_lock);
+
+	return 0;
+}
+
+void ir_raw_event_unregister(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir = input_get_drvdata(input_dev);
+	struct ir_raw_handler *handler;
+
+	if (!ir->raw)
+		return;
+
+	cancel_work_sync(&ir->raw->rx_work);
+
+	spin_lock(&ir_raw_handler_lock);
+	list_del(&ir->raw->list);
+	list_for_each_entry(handler, &ir_raw_handler_list, list)
+		if (handler->raw_unregister)
+			handler->raw_unregister(ir->raw->input_dev);
+	spin_unlock(&ir_raw_handler_lock);
+
+	kfifo_free(&ir->raw->kfifo);
+	kfree(ir->raw);
+	ir->raw = NULL;
+}
+
 /*
  * Extension interface - used to register the IR decoders
  */
 
 int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
 {
+	struct ir_raw_event_ctrl *raw;
+
 	spin_lock(&ir_raw_handler_lock);
 	list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
+	if (ir_raw_handler->raw_register)
+		list_for_each_entry(raw, &ir_raw_client_list, list)
+			ir_raw_handler->raw_register(raw->input_dev);
+	available_protocols |= ir_raw_handler->protocols;
 	spin_unlock(&ir_raw_handler_lock);
+
 	return 0;
 }
 EXPORT_SYMBOL(ir_raw_handler_register);
 
 void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
 {
+	struct ir_raw_event_ctrl *raw;
+
 	spin_lock(&ir_raw_handler_lock);
 	list_del(&ir_raw_handler->list);
+	if (ir_raw_handler->raw_unregister)
+		list_for_each_entry(raw, &ir_raw_client_list, list)
+			ir_raw_handler->raw_unregister(raw->input_dev);
+	available_protocols &= ~ir_raw_handler->protocols;
 	spin_unlock(&ir_raw_handler_lock);
 }
 EXPORT_SYMBOL(ir_raw_handler_unregister);
@@ -235,6 +253,7 @@
 	load_rc6_decode();
 	load_jvc_decode();
 	load_sony_decode();
+	load_lirc_codec();
 
 	/* If needed, we may later add some init code. In this case,
 	   it is needed to change the CONFIG_MODULE test at ir-core.h
diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c
index 23cdb1b..df4770d9 100644
--- a/drivers/media/IR/ir-rc5-decoder.c
+++ b/drivers/media/IR/ir-rc5-decoder.c
@@ -30,10 +30,6 @@
 #define RC5_BIT_END		(1 * RC5_UNIT)
 #define RC5X_SPACE		(4 * RC5_UNIT)
 
-/* Used to register rc5_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
 enum rc5_state {
 	STATE_INACTIVE,
 	STATE_BIT_START,
@@ -42,87 +38,6 @@
 	STATE_FINISHED,
 };
 
-struct decoder_data {
-	struct list_head	list;
-	struct ir_input_dev	*ir_dev;
-	int			enabled:1;
-
-	/* State machine control */
-	enum rc5_state		state;
-	u32			rc5_bits;
-	struct ir_raw_event	prev_ev;
-	unsigned		count;
-	unsigned		wanted_bits;
-};
-
-
-/**
- * get_decoder_data()	- gets decoder data
- * @input_dev:	input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-
-static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
-{
-	struct decoder_data *data = NULL;
-
-	spin_lock(&decoder_lock);
-	list_for_each_entry(data, &decoder_list, list) {
-		if (data->ir_dev == ir_dev)
-			break;
-	}
-	spin_unlock(&decoder_lock);
-	return data;
-}
-
-static ssize_t store_enabled(struct device *d,
-			     struct device_attribute *mattr,
-			     const char *buf,
-			     size_t len)
-{
-	unsigned long value;
-	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	struct decoder_data *data = get_decoder_data(ir_dev);
-
-	if (!data)
-		return -EINVAL;
-
-	if (strict_strtoul(buf, 10, &value) || value > 1)
-		return -EINVAL;
-
-	data->enabled = value;
-
-	return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-			     struct device_attribute *mattr, char *buf)
-{
-	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	struct decoder_data *data = get_decoder_data(ir_dev);
-
-	if (!data)
-		return -EINVAL;
-
-	if (data->enabled)
-		return sprintf(buf, "1\n");
-	else
-	return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-	&dev_attr_enabled.attr,
-	NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-	.name	= "rc5_decoder",
-	.attrs	= decoder_attributes,
-};
-
 /**
  * ir_rc5_decode() - Decode one RC-5 pulse or space
  * @input_dev:	the struct input_dev descriptor of the device
@@ -132,17 +47,13 @@
  */
 static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 {
-	struct decoder_data *data;
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	struct rc5_dec *data = &ir_dev->raw->rc5;
 	u8 toggle;
 	u32 scancode;
 
-	data = get_decoder_data(ir_dev);
-	if (!data)
-		return -EINVAL;
-
-	if (!data->enabled)
-		return 0;
+        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5))
+                return 0;
 
 	if (IS_RESET(ev)) {
 		data->state = STATE_INACTIVE;
@@ -176,16 +87,15 @@
 		if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
 			break;
 
-		data->rc5_bits <<= 1;
+		data->bits <<= 1;
 		if (!ev.pulse)
-			data->rc5_bits |= 1;
+			data->bits |= 1;
 		data->count++;
-		data->prev_ev = ev;
 		data->state = STATE_BIT_END;
 		return 0;
 
 	case STATE_BIT_END:
-		if (!is_transition(&ev, &data->prev_ev))
+		if (!is_transition(&ev, &ir_dev->raw->prev_ev))
 			break;
 
 		if (data->count == data->wanted_bits)
@@ -217,11 +127,11 @@
 		if (data->wanted_bits == RC5X_NBITS) {
 			/* RC5X */
 			u8 xdata, command, system;
-			xdata    = (data->rc5_bits & 0x0003F) >> 0;
-			command  = (data->rc5_bits & 0x00FC0) >> 6;
-			system   = (data->rc5_bits & 0x1F000) >> 12;
-			toggle   = (data->rc5_bits & 0x20000) ? 1 : 0;
-			command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
+			xdata    = (data->bits & 0x0003F) >> 0;
+			command  = (data->bits & 0x00FC0) >> 6;
+			system   = (data->bits & 0x1F000) >> 12;
+			toggle   = (data->bits & 0x20000) ? 1 : 0;
+			command += (data->bits & 0x01000) ? 0 : 0x40;
 			scancode = system << 16 | command << 8 | xdata;
 
 			IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
@@ -230,10 +140,10 @@
 		} else {
 			/* RC5 */
 			u8 command, system;
-			command  = (data->rc5_bits & 0x0003F) >> 0;
-			system   = (data->rc5_bits & 0x007C0) >> 6;
-			toggle   = (data->rc5_bits & 0x00800) ? 1 : 0;
-			command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
+			command  = (data->bits & 0x0003F) >> 0;
+			system   = (data->bits & 0x007C0) >> 6;
+			toggle   = (data->bits & 0x00800) ? 1 : 0;
+			command += (data->bits & 0x01000) ? 0 : 0x40;
 			scancode = system << 8 | command;
 
 			IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
@@ -252,54 +162,9 @@
 	return -EINVAL;
 }
 
-static int ir_rc5_register(struct input_dev *input_dev)
-{
-	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	struct decoder_data *data;
-	int rc;
-
-	rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-	if (rc < 0)
-		return rc;
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-		return -ENOMEM;
-	}
-
-	data->ir_dev = ir_dev;
-	data->enabled = 1;
-
-	spin_lock(&decoder_lock);
-	list_add_tail(&data->list, &decoder_list);
-	spin_unlock(&decoder_lock);
-
-	return 0;
-}
-
-static int ir_rc5_unregister(struct input_dev *input_dev)
-{
-	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	static struct decoder_data *data;
-
-	data = get_decoder_data(ir_dev);
-	if (!data)
-		return 0;
-
-	sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
-	spin_lock(&decoder_lock);
-	list_del(&data->list);
-	spin_unlock(&decoder_lock);
-
-	return 0;
-}
-
 static struct ir_raw_handler rc5_handler = {
+	.protocols	= IR_TYPE_RC5,
 	.decode		= ir_rc5_decode,
-	.raw_register	= ir_rc5_register,
-	.raw_unregister	= ir_rc5_unregister,
 };
 
 static int __init ir_rc5_decode_init(void)
diff --git a/drivers/media/IR/ir-rc6-decoder.c b/drivers/media/IR/ir-rc6-decoder.c
index 2bf479f..f1624b8 100644
--- a/drivers/media/IR/ir-rc6-decoder.c
+++ b/drivers/media/IR/ir-rc6-decoder.c
@@ -36,10 +36,6 @@
 #define RC6_STARTBIT_MASK	0x08	/* for the header bits */
 #define RC6_6A_MCE_TOGGLE_MASK	0x8000	/* for the body bits */
 
-/* Used to register rc6_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
 enum rc6_mode {
 	RC6_MODE_0,
 	RC6_MODE_6A,
@@ -58,89 +54,8 @@
 	STATE_FINISHED,
 };
 
-struct decoder_data {
-	struct list_head	list;
-	struct ir_input_dev	*ir_dev;
-	int			enabled:1;
-
-	/* State machine control */
-	enum rc6_state		state;
-	u8			header;
-	u32			body;
-	struct ir_raw_event	prev_ev;
-	bool			toggle;
-	unsigned		count;
-	unsigned		wanted_bits;
-};
-
-
-/**
- * get_decoder_data()	- gets decoder data
- * @input_dev:	input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
+static enum rc6_mode rc6_mode(struct rc6_dec *data)
 {
-	struct decoder_data *data = NULL;
-
-	spin_lock(&decoder_lock);
-	list_for_each_entry(data, &decoder_list, list) {
-		if (data->ir_dev == ir_dev)
-			break;
-	}
-	spin_unlock(&decoder_lock);
-	return data;
-}
-
-static ssize_t store_enabled(struct device *d,
-			     struct device_attribute *mattr,
-			     const char *buf,
-			     size_t len)
-{
-	unsigned long value;
-	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	struct decoder_data *data = get_decoder_data(ir_dev);
-
-	if (!data)
-		return -EINVAL;
-
-	if (strict_strtoul(buf, 10, &value) || value > 1)
-		return -EINVAL;
-
-	data->enabled = value;
-
-	return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-			     struct device_attribute *mattr, char *buf)
-{
-	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	struct decoder_data *data = get_decoder_data(ir_dev);
-
-	if (!data)
-		return -EINVAL;
-
-	if (data->enabled)
-		return sprintf(buf, "1\n");
-	else
-	return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-	&dev_attr_enabled.attr,
-	NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-	.name	= "rc6_decoder",
-	.attrs	= decoder_attributes,
-};
-
-static enum rc6_mode rc6_mode(struct decoder_data *data) {
 	switch (data->header & RC6_MODE_MASK) {
 	case 0:
 		return RC6_MODE_0;
@@ -162,16 +77,12 @@
  */
 static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 {
-	struct decoder_data *data;
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	struct rc6_dec *data = &ir_dev->raw->rc6;
 	u32 scancode;
 	u8 toggle;
 
-	data = get_decoder_data(ir_dev);
-	if (!data)
-		return -EINVAL;
-
-	if (!data->enabled)
+	if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6))
 		return 0;
 
 	if (IS_RESET(ev)) {
@@ -223,12 +134,11 @@
 		if (ev.pulse)
 			data->header |= 1;
 		data->count++;
-		data->prev_ev = ev;
 		data->state = STATE_HEADER_BIT_END;
 		return 0;
 
 	case STATE_HEADER_BIT_END:
-		if (!is_transition(&ev, &data->prev_ev))
+		if (!is_transition(&ev, &ir_dev->raw->prev_ev))
 			break;
 
 		if (data->count == RC6_HEADER_NBITS)
@@ -244,12 +154,11 @@
 			break;
 
 		data->toggle = ev.pulse;
-		data->prev_ev = ev;
 		data->state = STATE_TOGGLE_END;
 		return 0;
 
 	case STATE_TOGGLE_END:
-		if (!is_transition(&ev, &data->prev_ev) ||
+		if (!is_transition(&ev, &ir_dev->raw->prev_ev) ||
 		    !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
 			break;
 
@@ -259,7 +168,6 @@
 		}
 
 		data->state = STATE_BODY_BIT_START;
-		data->prev_ev = ev;
 		decrease_duration(&ev, RC6_TOGGLE_END);
 		data->count = 0;
 
@@ -291,13 +199,11 @@
 		if (ev.pulse)
 			data->body |= 1;
 		data->count++;
-		data->prev_ev = ev;
-
 		data->state = STATE_BODY_BIT_END;
 		return 0;
 
 	case STATE_BODY_BIT_END:
-		if (!is_transition(&ev, &data->prev_ev))
+		if (!is_transition(&ev, &ir_dev->raw->prev_ev))
 			break;
 
 		if (data->count == data->wanted_bits)
@@ -348,54 +254,9 @@
 	return -EINVAL;
 }
 
-static int ir_rc6_register(struct input_dev *input_dev)
-{
-	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	struct decoder_data *data;
-	int rc;
-
-	rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-	if (rc < 0)
-		return rc;
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-		return -ENOMEM;
-	}
-
-	data->ir_dev = ir_dev;
-	data->enabled = 1;
-
-	spin_lock(&decoder_lock);
-	list_add_tail(&data->list, &decoder_list);
-	spin_unlock(&decoder_lock);
-
-	return 0;
-}
-
-static int ir_rc6_unregister(struct input_dev *input_dev)
-{
-	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	static struct decoder_data *data;
-
-	data = get_decoder_data(ir_dev);
-	if (!data)
-		return 0;
-
-	sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
-	spin_lock(&decoder_lock);
-	list_del(&data->list);
-	spin_unlock(&decoder_lock);
-
-	return 0;
-}
-
 static struct ir_raw_handler rc6_handler = {
+	.protocols	= IR_TYPE_RC6,
 	.decode		= ir_rc6_decode,
-	.raw_register	= ir_rc6_register,
-	.raw_unregister	= ir_rc6_unregister,
 };
 
 static int __init ir_rc6_decode_init(void)
diff --git a/drivers/media/IR/ir-sony-decoder.c b/drivers/media/IR/ir-sony-decoder.c
index 9f440c5..b9074f0 100644
--- a/drivers/media/IR/ir-sony-decoder.c
+++ b/drivers/media/IR/ir-sony-decoder.c
@@ -23,10 +23,6 @@
 #define SONY_BIT_SPACE		(1 * SONY_UNIT)
 #define SONY_TRAILER_SPACE	(10 * SONY_UNIT) /* minimum */
 
-/* Used to register sony_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
 enum sony_state {
 	STATE_INACTIVE,
 	STATE_HEADER_SPACE,
@@ -35,84 +31,6 @@
 	STATE_FINISHED,
 };
 
-struct decoder_data {
-	struct list_head	list;
-	struct ir_input_dev	*ir_dev;
-	int			enabled:1;
-
-	/* State machine control */
-	enum sony_state		state;
-	u32			sony_bits;
-	unsigned		count;
-};
-
-
-/**
- * get_decoder_data()	- gets decoder data
- * @input_dev:	input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
-{
-	struct decoder_data *data = NULL;
-
-	spin_lock(&decoder_lock);
-	list_for_each_entry(data, &decoder_list, list) {
-		if (data->ir_dev == ir_dev)
-			break;
-	}
-	spin_unlock(&decoder_lock);
-	return data;
-}
-
-static ssize_t store_enabled(struct device *d,
-			     struct device_attribute *mattr,
-			     const char *buf,
-			     size_t len)
-{
-	unsigned long value;
-	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	struct decoder_data *data = get_decoder_data(ir_dev);
-
-	if (!data)
-		return -EINVAL;
-
-	if (strict_strtoul(buf, 10, &value) || value > 1)
-		return -EINVAL;
-
-	data->enabled = value;
-
-	return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-			     struct device_attribute *mattr, char *buf)
-{
-	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	struct decoder_data *data = get_decoder_data(ir_dev);
-
-	if (!data)
-		return -EINVAL;
-
-	if (data->enabled)
-		return sprintf(buf, "1\n");
-	else
-	return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-	&dev_attr_enabled.attr,
-	NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-	.name	= "sony_decoder",
-	.attrs	= decoder_attributes,
-};
-
 /**
  * ir_sony_decode() - Decode one Sony pulse or space
  * @input_dev:	the struct input_dev descriptor of the device
@@ -122,16 +40,12 @@
  */
 static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
 {
-	struct decoder_data *data;
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	struct sony_dec *data = &ir_dev->raw->sony;
 	u32 scancode;
 	u8 device, subdevice, function;
 
-	data = get_decoder_data(ir_dev);
-	if (!data)
-		return -EINVAL;
-
-	if (!data->enabled)
+	if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY))
 		return 0;
 
 	if (IS_RESET(ev)) {
@@ -172,9 +86,9 @@
 		if (!ev.pulse)
 			break;
 
-		data->sony_bits <<= 1;
+		data->bits <<= 1;
 		if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2))
-			data->sony_bits |= 1;
+			data->bits |= 1;
 		else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2))
 			break;
 
@@ -208,19 +122,19 @@
 
 		switch (data->count) {
 		case 12:
-			device    = bitrev8((data->sony_bits <<  3) & 0xF8);
+			device    = bitrev8((data->bits <<  3) & 0xF8);
 			subdevice = 0;
-			function  = bitrev8((data->sony_bits >>  4) & 0xFE);
+			function  = bitrev8((data->bits >>  4) & 0xFE);
 			break;
 		case 15:
-			device    = bitrev8((data->sony_bits >>  0) & 0xFF);
+			device    = bitrev8((data->bits >>  0) & 0xFF);
 			subdevice = 0;
-			function  = bitrev8((data->sony_bits >>  7) & 0xFD);
+			function  = bitrev8((data->bits >>  7) & 0xFD);
 			break;
 		case 20:
-			device    = bitrev8((data->sony_bits >>  5) & 0xF8);
-			subdevice = bitrev8((data->sony_bits >>  0) & 0xFF);
-			function  = bitrev8((data->sony_bits >> 12) & 0xFE);
+			device    = bitrev8((data->bits >>  5) & 0xF8);
+			subdevice = bitrev8((data->bits >>  0) & 0xFF);
+			function  = bitrev8((data->bits >> 12) & 0xFE);
 			break;
 		default:
 			IR_dprintk(1, "Sony invalid bitcount %u\n", data->count);
@@ -241,54 +155,9 @@
 	return -EINVAL;
 }
 
-static int ir_sony_register(struct input_dev *input_dev)
-{
-	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	struct decoder_data *data;
-	int rc;
-
-	rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-	if (rc < 0)
-		return rc;
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-		return -ENOMEM;
-	}
-
-	data->ir_dev = ir_dev;
-	data->enabled = 1;
-
-	spin_lock(&decoder_lock);
-	list_add_tail(&data->list, &decoder_list);
-	spin_unlock(&decoder_lock);
-
-	return 0;
-}
-
-static int ir_sony_unregister(struct input_dev *input_dev)
-{
-	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-	static struct decoder_data *data;
-
-	data = get_decoder_data(ir_dev);
-	if (!data)
-		return 0;
-
-	sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
-	spin_lock(&decoder_lock);
-	list_del(&data->list);
-	spin_unlock(&decoder_lock);
-
-	return 0;
-}
-
 static struct ir_raw_handler sony_handler = {
+	.protocols	= IR_TYPE_SONY,
 	.decode		= ir_sony_decode,
-	.raw_register	= ir_sony_register,
-	.raw_unregister	= ir_sony_unregister,
 };
 
 static int __init ir_sony_decode_init(void)
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
index 2098dd1..6273047 100644
--- a/drivers/media/IR/ir-sysfs.c
+++ b/drivers/media/IR/ir-sysfs.c
@@ -33,125 +33,172 @@
 	.devnode	= ir_devnode,
 };
 
+static struct {
+	u64	type;
+	char	*name;
+} proto_names[] = {
+	{ IR_TYPE_UNKNOWN,	"unknown"	},
+	{ IR_TYPE_RC5,		"rc-5"		},
+	{ IR_TYPE_NEC,		"nec"		},
+	{ IR_TYPE_RC6,		"rc-6"		},
+	{ IR_TYPE_JVC,		"jvc"		},
+	{ IR_TYPE_SONY,		"sony"		},
+	{ IR_TYPE_LIRC,		"lirc"		},
+};
+
+#define PROTO_NONE	"none"
+
 /**
- * show_protocol() - shows the current IR protocol
+ * show_protocols() - shows the current IR protocol(s)
  * @d:		the device descriptor
  * @mattr:	the device attribute struct (unused)
  * @buf:	a pointer to the output buffer
  *
- * This routine is a callback routine for input read the IR protocol type.
- * it is trigged by reading /sys/class/rc/rc?/current_protocol.
- * It returns the protocol name, as understood by the driver.
+ * This routine is a callback routine for input read the IR protocol type(s).
+ * it is trigged by reading /sys/class/rc/rc?/protocols.
+ * It returns the protocol names of supported protocols.
+ * Enabled protocols are printed in brackets.
  */
-static ssize_t show_protocol(struct device *d,
-			     struct device_attribute *mattr, char *buf)
+static ssize_t show_protocols(struct device *d,
+			      struct device_attribute *mattr, char *buf)
 {
-	char *s;
 	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	u64 ir_type = ir_dev->rc_tab.ir_type;
+	u64 allowed, enabled;
+	char *tmp = buf;
+	int i;
 
-	IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type);
+	if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
+		enabled = ir_dev->rc_tab.ir_type;
+		allowed = ir_dev->props->allowed_protos;
+	} else {
+		enabled = ir_dev->raw->enabled_protocols;
+		allowed = ir_raw_get_allowed_protocols();
+	}
 
-	/* FIXME: doesn't support multiple protocols at the same time */
-	if (ir_type == IR_TYPE_UNKNOWN)
-		s = "Unknown";
-	else if (ir_type == IR_TYPE_RC5)
-		s = "rc-5";
-	else if (ir_type == IR_TYPE_NEC)
-		s = "nec";
-	else if (ir_type == IR_TYPE_RC6)
-		s = "rc6";
-	else if (ir_type == IR_TYPE_JVC)
-		s = "jvc";
-	else if (ir_type == IR_TYPE_SONY)
-		s = "sony";
-	else
-		s = "other";
+	IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
+		   (long long)allowed,
+		   (long long)enabled);
 
-	return sprintf(buf, "%s\n", s);
+	for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
+		if (allowed & enabled & proto_names[i].type)
+			tmp += sprintf(tmp, "[%s] ", proto_names[i].name);
+		else if (allowed & proto_names[i].type)
+			tmp += sprintf(tmp, "%s ", proto_names[i].name);
+	}
+
+	if (tmp != buf)
+		tmp--;
+	*tmp = '\n';
+	return tmp + 1 - buf;
 }
 
 /**
- * store_protocol() - shows the current IR protocol
+ * store_protocols() - changes the current IR protocol(s)
  * @d:		the device descriptor
  * @mattr:	the device attribute struct (unused)
  * @buf:	a pointer to the input buffer
  * @len:	length of the input buffer
  *
  * This routine is a callback routine for changing the IR protocol type.
- * it is trigged by reading /sys/class/rc/rc?/current_protocol.
- * It changes the IR the protocol name, if the IR type is recognized
- * by the driver.
- * If an unknown protocol name is used, returns -EINVAL.
+ * It is trigged by writing to /sys/class/rc/rc?/protocols.
+ * Writing "+proto" will add a protocol to the list of enabled protocols.
+ * Writing "-proto" will remove a protocol from the list of enabled protocols.
+ * Writing "proto" will enable only "proto".
+ * Writing "none" will disable all protocols.
+ * Returns -EINVAL if an invalid protocol combination or unknown protocol name
+ * is used, otherwise @len.
  */
-static ssize_t store_protocol(struct device *d,
-			      struct device_attribute *mattr,
-			      const char *data,
-			      size_t len)
+static ssize_t store_protocols(struct device *d,
+			       struct device_attribute *mattr,
+			       const char *data,
+			       size_t len)
 {
 	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-	u64 ir_type = 0;
-	int rc = -EINVAL;
+	bool enable, disable;
+	const char *tmp;
+	u64 type;
+	u64 mask;
+	int rc, i, count = 0;
 	unsigned long flags;
-	char *buf;
 
-	while ((buf = strsep((char **) &data, " \n")) != NULL) {
-		if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5"))
-			ir_type |= IR_TYPE_RC5;
-		if (!strcasecmp(buf, "nec"))
-			ir_type |= IR_TYPE_NEC;
-		if (!strcasecmp(buf, "jvc"))
-			ir_type |= IR_TYPE_JVC;
-		if (!strcasecmp(buf, "sony"))
-			ir_type |= IR_TYPE_SONY;
+	if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
+		type = ir_dev->rc_tab.ir_type;
+	else
+		type = ir_dev->raw->enabled_protocols;
+
+	while ((tmp = strsep((char **) &data, " \n")) != NULL) {
+		if (!*tmp)
+			break;
+
+		if (*tmp == '+') {
+			enable = true;
+			disable = false;
+			tmp++;
+		} else if (*tmp == '-') {
+			enable = false;
+			disable = true;
+			tmp++;
+		} else {
+			enable = false;
+			disable = false;
+		}
+
+		if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) {
+			tmp += sizeof(PROTO_NONE);
+			mask = 0;
+			count++;
+		} else {
+			for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
+				if (!strncasecmp(tmp, proto_names[i].name, strlen(proto_names[i].name))) {
+					tmp += strlen(proto_names[i].name);
+					mask = proto_names[i].type;
+					break;
+				}
+			}
+			if (i == ARRAY_SIZE(proto_names)) {
+				IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
+				return -EINVAL;
+			}
+			count++;
+		}
+
+		if (enable)
+			type |= mask;
+		else if (disable)
+			type &= ~mask;
+		else
+			type = mask;
 	}
 
-	if (!ir_type) {
-		IR_dprintk(1, "Unknown protocol\n");
+	if (!count) {
+		IR_dprintk(1, "Protocol not specified\n");
 		return -EINVAL;
 	}
 
-	if (ir_dev->props && ir_dev->props->change_protocol)
+	if (ir_dev->props && ir_dev->props->change_protocol) {
 		rc = ir_dev->props->change_protocol(ir_dev->props->priv,
-						    ir_type);
-
-	if (rc < 0) {
-		IR_dprintk(1, "Error setting protocol to %lld\n",
-			   (long long)ir_type);
-		return -EINVAL;
+						    type);
+		if (rc < 0) {
+			IR_dprintk(1, "Error setting protocols to 0x%llx\n",
+				   (long long)type);
+			return -EINVAL;
+		}
 	}
 
-	spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
-	ir_dev->rc_tab.ir_type = ir_type;
-	spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
+	if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
+		spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
+		ir_dev->rc_tab.ir_type = type;
+		spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
+	} else {
+		ir_dev->raw->enabled_protocols = type;
+	}
 
-	IR_dprintk(1, "Current protocol(s) is(are) %lld\n",
-		   (long long)ir_type);
+	IR_dprintk(1, "Current protocol(s): 0x%llx\n",
+		   (long long)type);
 
 	return len;
 }
 
-static ssize_t show_supported_protocols(struct device *d,
-			     struct device_attribute *mattr, char *buf)
-{
-	char *orgbuf = buf;
-	struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-
-	/* FIXME: doesn't support multiple protocols at the same time */
-	if (ir_dev->props->allowed_protos == IR_TYPE_UNKNOWN)
-		buf += sprintf(buf, "unknown ");
-	if (ir_dev->props->allowed_protos & IR_TYPE_RC5)
-		buf += sprintf(buf, "rc-5 ");
-	if (ir_dev->props->allowed_protos & IR_TYPE_NEC)
-		buf += sprintf(buf, "nec ");
-	if (buf == orgbuf)
-		buf += sprintf(buf, "other ");
-
-	buf += sprintf(buf - 1, "\n");
-
-	return buf - orgbuf;
-}
-
 #define ADD_HOTPLUG_VAR(fmt, val...)					\
 	do {								\
 		int err = add_uevent_var(env, fmt, val);		\
@@ -159,7 +206,7 @@
 			return err;					\
 	} while (0)
 
-static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env)
+static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 {
 	struct ir_input_dev *ir_dev = dev_get_drvdata(device);
 
@@ -174,34 +221,26 @@
 /*
  * Static device attribute struct with the sysfs attributes for IR's
  */
-static DEVICE_ATTR(protocol, S_IRUGO | S_IWUSR,
-		   show_protocol, store_protocol);
+static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR,
+		   show_protocols, store_protocols);
 
-static DEVICE_ATTR(supported_protocols, S_IRUGO | S_IWUSR,
-		   show_supported_protocols, NULL);
-
-static struct attribute *ir_hw_dev_attrs[] = {
-	&dev_attr_protocol.attr,
-	&dev_attr_supported_protocols.attr,
+static struct attribute *rc_dev_attrs[] = {
+	&dev_attr_protocols.attr,
 	NULL,
 };
 
-static struct attribute_group ir_hw_dev_attr_grp = {
-	.attrs	= ir_hw_dev_attrs,
+static struct attribute_group rc_dev_attr_grp = {
+	.attrs	= rc_dev_attrs,
 };
 
-static const struct attribute_group *ir_hw_dev_attr_groups[] = {
-	&ir_hw_dev_attr_grp,
+static const struct attribute_group *rc_dev_attr_groups[] = {
+	&rc_dev_attr_grp,
 	NULL
 };
 
 static struct device_type rc_dev_type = {
-	.groups		= ir_hw_dev_attr_groups,
-	.uevent		= ir_dev_uevent,
-};
-
-static struct device_type ir_raw_dev_type = {
-	.uevent		= ir_dev_uevent,
+	.groups		= rc_dev_attr_groups,
+	.uevent		= rc_dev_uevent,
 };
 
 /**
@@ -221,11 +260,7 @@
 	if (unlikely(devno < 0))
 		return devno;
 
-	if (ir_dev->props) {
-		if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
-			ir_dev->dev.type = &rc_dev_type;
-	} else
-		ir_dev->dev.type = &ir_raw_dev_type;
+	ir_dev->dev.type = &rc_dev_type;
 
 	ir_dev->dev.class = &ir_input_class;
 	ir_dev->dev.parent = input_dev->dev.parent;
diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile
index aea649f..cbee062 100644
--- a/drivers/media/IR/keymaps/Makefile
+++ b/drivers/media/IR/keymaps/Makefile
@@ -14,6 +14,8 @@
 			rc-budget-ci-old.o \
 			rc-cinergy-1400.o \
 			rc-cinergy.o \
+			rc-dib0700-nec.o \
+			rc-dib0700-rc5.o \
 			rc-dm1105-nec.o \
 			rc-dntv-live-dvb-t.o \
 			rc-dntv-live-dvbt-pro.o \
@@ -37,6 +39,7 @@
 			rc-kaiomy.o \
 			rc-kworld-315u.o \
 			rc-kworld-plus-tv-analog.o \
+			rc-lirc.o \
 			rc-manli.o \
 			rc-msi-tvanywhere.o \
 			rc-msi-tvanywhere-plus.o \
@@ -57,6 +60,7 @@
 			rc-pv951.o \
 			rc-rc5-hauppauge-new.o \
 			rc-rc5-tv.o \
+			rc-rc6-mce.o \
 			rc-real-audio-220-32-keys.o \
 			rc-tbs-nec.o \
 			rc-terratec-cinergy-xs.o \
diff --git a/drivers/media/IR/keymaps/rc-dib0700-nec.c b/drivers/media/IR/keymaps/rc-dib0700-nec.c
new file mode 100644
index 0000000..ae18320
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-dib0700-nec.c
@@ -0,0 +1,124 @@
+/* rc-dvb0700-big.c - Keytable for devices in dvb0700
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * TODO: This table is a real mess, as it merges RC codes from several
+ * devices into a big table. It also has both RC-5 and NEC codes inside.
+ * It should be broken into small tables, and the protocols should properly
+ * be indentificated.
+ *
+ * The table were imported from dib0700_devices.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode dib0700_nec_table[] = {
+	/* Key codes for the Pixelview SBTVD remote */
+	{ 0x8613, KEY_MUTE },
+	{ 0x8612, KEY_POWER },
+	{ 0x8601, KEY_1 },
+	{ 0x8602, KEY_2 },
+	{ 0x8603, KEY_3 },
+	{ 0x8604, KEY_4 },
+	{ 0x8605, KEY_5 },
+	{ 0x8606, KEY_6 },
+	{ 0x8607, KEY_7 },
+	{ 0x8608, KEY_8 },
+	{ 0x8609, KEY_9 },
+	{ 0x8600, KEY_0 },
+	{ 0x860d, KEY_CHANNELUP },
+	{ 0x8619, KEY_CHANNELDOWN },
+	{ 0x8610, KEY_VOLUMEUP },
+	{ 0x860c, KEY_VOLUMEDOWN },
+
+	{ 0x860a, KEY_CAMERA },
+	{ 0x860b, KEY_ZOOM },
+	{ 0x861b, KEY_BACKSPACE },
+	{ 0x8615, KEY_ENTER },
+
+	{ 0x861d, KEY_UP },
+	{ 0x861e, KEY_DOWN },
+	{ 0x860e, KEY_LEFT },
+	{ 0x860f, KEY_RIGHT },
+
+	{ 0x8618, KEY_RECORD },
+	{ 0x861a, KEY_STOP },
+
+	/* Key codes for the EvolutePC TVWay+ remote */
+	{ 0x7a00, KEY_MENU },
+	{ 0x7a01, KEY_RECORD },
+	{ 0x7a02, KEY_PLAY },
+	{ 0x7a03, KEY_STOP },
+	{ 0x7a10, KEY_CHANNELUP },
+	{ 0x7a11, KEY_CHANNELDOWN },
+	{ 0x7a12, KEY_VOLUMEUP },
+	{ 0x7a13, KEY_VOLUMEDOWN },
+	{ 0x7a40, KEY_POWER },
+	{ 0x7a41, KEY_MUTE },
+
+	/* Key codes for the Elgato EyeTV Diversity silver remote */
+	{ 0x4501, KEY_POWER },
+	{ 0x4502, KEY_MUTE },
+	{ 0x4503, KEY_1 },
+	{ 0x4504, KEY_2 },
+	{ 0x4505, KEY_3 },
+	{ 0x4506, KEY_4 },
+	{ 0x4507, KEY_5 },
+	{ 0x4508, KEY_6 },
+	{ 0x4509, KEY_7 },
+	{ 0x450a, KEY_8 },
+	{ 0x450b, KEY_9 },
+	{ 0x450c, KEY_LAST },
+	{ 0x450d, KEY_0 },
+	{ 0x450e, KEY_ENTER },
+	{ 0x450f, KEY_RED },
+	{ 0x4510, KEY_CHANNELUP },
+	{ 0x4511, KEY_GREEN },
+	{ 0x4512, KEY_VOLUMEDOWN },
+	{ 0x4513, KEY_OK },
+	{ 0x4514, KEY_VOLUMEUP },
+	{ 0x4515, KEY_YELLOW },
+	{ 0x4516, KEY_CHANNELDOWN },
+	{ 0x4517, KEY_BLUE },
+	{ 0x4518, KEY_LEFT }, /* Skip backwards */
+	{ 0x4519, KEY_PLAYPAUSE },
+	{ 0x451a, KEY_RIGHT }, /* Skip forward */
+	{ 0x451b, KEY_REWIND },
+	{ 0x451c, KEY_L }, /* Live */
+	{ 0x451d, KEY_FASTFORWARD },
+	{ 0x451e, KEY_STOP }, /* 'Reveal' for Teletext */
+	{ 0x451f, KEY_MENU }, /* KEY_TEXT for Teletext */
+	{ 0x4540, KEY_RECORD }, /* Font 'Size' for Teletext */
+	{ 0x4541, KEY_SCREEN }, /*  Full screen toggle, 'Hold' for Teletext */
+	{ 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */
+};
+
+static struct rc_keymap dib0700_nec_map = {
+	.map = {
+		.scan    = dib0700_nec_table,
+		.size    = ARRAY_SIZE(dib0700_nec_table),
+		.ir_type = IR_TYPE_NEC,
+		.name    = RC_MAP_DIB0700_NEC_TABLE,
+	}
+};
+
+static int __init init_rc_map(void)
+{
+	return ir_register_map(&dib0700_nec_map);
+}
+
+static void __exit exit_rc_map(void)
+{
+	ir_unregister_map(&dib0700_nec_map);
+}
+
+module_init(init_rc_map)
+module_exit(exit_rc_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-dib0700-rc5.c b/drivers/media/IR/keymaps/rc-dib0700-rc5.c
new file mode 100644
index 0000000..4a4797c
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-dib0700-rc5.c
@@ -0,0 +1,235 @@
+/* rc-dvb0700-big.c - Keytable for devices in dvb0700
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * TODO: This table is a real mess, as it merges RC codes from several
+ * devices into a big table. It also has both RC-5 and NEC codes inside.
+ * It should be broken into small tables, and the protocols should properly
+ * be indentificated.
+ *
+ * The table were imported from dib0700_devices.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode dib0700_rc5_table[] = {
+	/* Key codes for the tiny Pinnacle remote*/
+	{ 0x0700, KEY_MUTE },
+	{ 0x0701, KEY_MENU }, /* Pinnacle logo */
+	{ 0x0739, KEY_POWER },
+	{ 0x0703, KEY_VOLUMEUP },
+	{ 0x0709, KEY_VOLUMEDOWN },
+	{ 0x0706, KEY_CHANNELUP },
+	{ 0x070c, KEY_CHANNELDOWN },
+	{ 0x070f, KEY_1 },
+	{ 0x0715, KEY_2 },
+	{ 0x0710, KEY_3 },
+	{ 0x0718, KEY_4 },
+	{ 0x071b, KEY_5 },
+	{ 0x071e, KEY_6 },
+	{ 0x0711, KEY_7 },
+	{ 0x0721, KEY_8 },
+	{ 0x0712, KEY_9 },
+	{ 0x0727, KEY_0 },
+	{ 0x0724, KEY_SCREEN }, /* 'Square' key */
+	{ 0x072a, KEY_TEXT },   /* 'T' key */
+	{ 0x072d, KEY_REWIND },
+	{ 0x0730, KEY_PLAY },
+	{ 0x0733, KEY_FASTFORWARD },
+	{ 0x0736, KEY_RECORD },
+	{ 0x073c, KEY_STOP },
+	{ 0x073f, KEY_CANCEL }, /* '?' key */
+
+	/* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
+	{ 0xeb01, KEY_POWER },
+	{ 0xeb02, KEY_1 },
+	{ 0xeb03, KEY_2 },
+	{ 0xeb04, KEY_3 },
+	{ 0xeb05, KEY_4 },
+	{ 0xeb06, KEY_5 },
+	{ 0xeb07, KEY_6 },
+	{ 0xeb08, KEY_7 },
+	{ 0xeb09, KEY_8 },
+	{ 0xeb0a, KEY_9 },
+	{ 0xeb0b, KEY_VIDEO },
+	{ 0xeb0c, KEY_0 },
+	{ 0xeb0d, KEY_REFRESH },
+	{ 0xeb0f, KEY_EPG },
+	{ 0xeb10, KEY_UP },
+	{ 0xeb11, KEY_LEFT },
+	{ 0xeb12, KEY_OK },
+	{ 0xeb13, KEY_RIGHT },
+	{ 0xeb14, KEY_DOWN },
+	{ 0xeb16, KEY_INFO },
+	{ 0xeb17, KEY_RED },
+	{ 0xeb18, KEY_GREEN },
+	{ 0xeb19, KEY_YELLOW },
+	{ 0xeb1a, KEY_BLUE },
+	{ 0xeb1b, KEY_CHANNELUP },
+	{ 0xeb1c, KEY_VOLUMEUP },
+	{ 0xeb1d, KEY_MUTE },
+	{ 0xeb1e, KEY_VOLUMEDOWN },
+	{ 0xeb1f, KEY_CHANNELDOWN },
+	{ 0xeb40, KEY_PAUSE },
+	{ 0xeb41, KEY_HOME },
+	{ 0xeb42, KEY_MENU }, /* DVD Menu */
+	{ 0xeb43, KEY_SUBTITLE },
+	{ 0xeb44, KEY_TEXT }, /* Teletext */
+	{ 0xeb45, KEY_DELETE },
+	{ 0xeb46, KEY_TV },
+	{ 0xeb47, KEY_DVD },
+	{ 0xeb48, KEY_STOP },
+	{ 0xeb49, KEY_VIDEO },
+	{ 0xeb4a, KEY_AUDIO }, /* Music */
+	{ 0xeb4b, KEY_SCREEN }, /* Pic */
+	{ 0xeb4c, KEY_PLAY },
+	{ 0xeb4d, KEY_BACK },
+	{ 0xeb4e, KEY_REWIND },
+	{ 0xeb4f, KEY_FASTFORWARD },
+	{ 0xeb54, KEY_PREVIOUS },
+	{ 0xeb58, KEY_RECORD },
+	{ 0xeb5c, KEY_NEXT },
+
+	/* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
+	{ 0x1e00, KEY_0 },
+	{ 0x1e01, KEY_1 },
+	{ 0x1e02, KEY_2 },
+	{ 0x1e03, KEY_3 },
+	{ 0x1e04, KEY_4 },
+	{ 0x1e05, KEY_5 },
+	{ 0x1e06, KEY_6 },
+	{ 0x1e07, KEY_7 },
+	{ 0x1e08, KEY_8 },
+	{ 0x1e09, KEY_9 },
+	{ 0x1e0a, KEY_KPASTERISK },
+	{ 0x1e0b, KEY_RED },
+	{ 0x1e0c, KEY_RADIO },
+	{ 0x1e0d, KEY_MENU },
+	{ 0x1e0e, KEY_GRAVE }, /* # */
+	{ 0x1e0f, KEY_MUTE },
+	{ 0x1e10, KEY_VOLUMEUP },
+	{ 0x1e11, KEY_VOLUMEDOWN },
+	{ 0x1e12, KEY_CHANNEL },
+	{ 0x1e14, KEY_UP },
+	{ 0x1e15, KEY_DOWN },
+	{ 0x1e16, KEY_LEFT },
+	{ 0x1e17, KEY_RIGHT },
+	{ 0x1e18, KEY_VIDEO },
+	{ 0x1e19, KEY_AUDIO },
+	{ 0x1e1a, KEY_MEDIA },
+	{ 0x1e1b, KEY_EPG },
+	{ 0x1e1c, KEY_TV },
+	{ 0x1e1e, KEY_NEXT },
+	{ 0x1e1f, KEY_BACK },
+	{ 0x1e20, KEY_CHANNELUP },
+	{ 0x1e21, KEY_CHANNELDOWN },
+	{ 0x1e24, KEY_LAST }, /* Skip backwards */
+	{ 0x1e25, KEY_OK },
+	{ 0x1e29, KEY_BLUE},
+	{ 0x1e2e, KEY_GREEN },
+	{ 0x1e30, KEY_PAUSE },
+	{ 0x1e32, KEY_REWIND },
+	{ 0x1e34, KEY_FASTFORWARD },
+	{ 0x1e35, KEY_PLAY },
+	{ 0x1e36, KEY_STOP },
+	{ 0x1e37, KEY_RECORD },
+	{ 0x1e38, KEY_YELLOW },
+	{ 0x1e3b, KEY_GOTO },
+	{ 0x1e3d, KEY_POWER },
+
+	/* Key codes for the Leadtek Winfast DTV Dongle */
+	{ 0x0042, KEY_POWER },
+	{ 0x077c, KEY_TUNER },
+	{ 0x0f4e, KEY_PRINT }, /* PREVIEW */
+	{ 0x0840, KEY_SCREEN }, /* full screen toggle*/
+	{ 0x0f71, KEY_DOT }, /* frequency */
+	{ 0x0743, KEY_0 },
+	{ 0x0c41, KEY_1 },
+	{ 0x0443, KEY_2 },
+	{ 0x0b7f, KEY_3 },
+	{ 0x0e41, KEY_4 },
+	{ 0x0643, KEY_5 },
+	{ 0x097f, KEY_6 },
+	{ 0x0d7e, KEY_7 },
+	{ 0x057c, KEY_8 },
+	{ 0x0a40, KEY_9 },
+	{ 0x0e4e, KEY_CLEAR },
+	{ 0x047c, KEY_CHANNEL }, /* show channel number */
+	{ 0x0f41, KEY_LAST }, /* recall */
+	{ 0x0342, KEY_MUTE },
+	{ 0x064c, KEY_RESERVED }, /* PIP button*/
+	{ 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */
+	{ 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
+	{ 0x0b70, KEY_RECORD },
+	{ 0x037d, KEY_VOLUMEUP },
+	{ 0x017d, KEY_VOLUMEDOWN },
+	{ 0x0242, KEY_CHANNELUP },
+	{ 0x007d, KEY_CHANNELDOWN },
+
+	/* Key codes for Nova-TD "credit card" remote control. */
+	{ 0x1d00, KEY_0 },
+	{ 0x1d01, KEY_1 },
+	{ 0x1d02, KEY_2 },
+	{ 0x1d03, KEY_3 },
+	{ 0x1d04, KEY_4 },
+	{ 0x1d05, KEY_5 },
+	{ 0x1d06, KEY_6 },
+	{ 0x1d07, KEY_7 },
+	{ 0x1d08, KEY_8 },
+	{ 0x1d09, KEY_9 },
+	{ 0x1d0a, KEY_TEXT },
+	{ 0x1d0d, KEY_MENU },
+	{ 0x1d0f, KEY_MUTE },
+	{ 0x1d10, KEY_VOLUMEUP },
+	{ 0x1d11, KEY_VOLUMEDOWN },
+	{ 0x1d12, KEY_CHANNEL },
+	{ 0x1d14, KEY_UP },
+	{ 0x1d15, KEY_DOWN },
+	{ 0x1d16, KEY_LEFT },
+	{ 0x1d17, KEY_RIGHT },
+	{ 0x1d1c, KEY_TV },
+	{ 0x1d1e, KEY_NEXT },
+	{ 0x1d1f, KEY_BACK },
+	{ 0x1d20, KEY_CHANNELUP },
+	{ 0x1d21, KEY_CHANNELDOWN },
+	{ 0x1d24, KEY_LAST },
+	{ 0x1d25, KEY_OK },
+	{ 0x1d30, KEY_PAUSE },
+	{ 0x1d32, KEY_REWIND },
+	{ 0x1d34, KEY_FASTFORWARD },
+	{ 0x1d35, KEY_PLAY },
+	{ 0x1d36, KEY_STOP },
+	{ 0x1d37, KEY_RECORD },
+	{ 0x1d3b, KEY_GOTO },
+	{ 0x1d3d, KEY_POWER },
+};
+
+static struct rc_keymap dib0700_rc5_map = {
+	.map = {
+		.scan    = dib0700_rc5_table,
+		.size    = ARRAY_SIZE(dib0700_rc5_table),
+		.ir_type = IR_TYPE_RC5,
+		.name    = RC_MAP_DIB0700_RC5_TABLE,
+	}
+};
+
+static int __init init_rc_map(void)
+{
+	return ir_register_map(&dib0700_rc5_map);
+}
+
+static void __exit exit_rc_map(void)
+{
+	ir_unregister_map(&dib0700_rc5_map);
+}
+
+module_init(init_rc_map)
+module_exit(exit_rc_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-lirc.c b/drivers/media/IR/keymaps/rc-lirc.c
new file mode 100644
index 0000000..43fcf90
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-lirc.c
@@ -0,0 +1,41 @@
+/* rc-lirc.c - Empty dummy keytable, for use when its preferred to pass
+ * all raw IR data to the lirc userspace decoder.
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/ir-core.h>
+
+static struct ir_scancode lirc[] = {
+	{ },
+};
+
+static struct rc_keymap lirc_map = {
+	.map = {
+		.scan    = lirc,
+		.size    = ARRAY_SIZE(lirc),
+		.ir_type = IR_TYPE_LIRC,
+		.name    = RC_MAP_LIRC,
+	}
+};
+
+static int __init init_rc_map_lirc(void)
+{
+	return ir_register_map(&lirc_map);
+}
+
+static void __exit exit_rc_map_lirc(void)
+{
+	ir_unregister_map(&lirc_map);
+}
+
+module_init(init_rc_map_lirc)
+module_exit(exit_rc_map_lirc)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-rc6-mce.c b/drivers/media/IR/keymaps/rc-rc6-mce.c
new file mode 100644
index 0000000..c6726a8
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-rc6-mce.c
@@ -0,0 +1,105 @@
+/* rc-rc6-mce.c - Keytable for Windows Media Center RC-6 remotes for use
+ * with the Media Center Edition eHome Infrared Transceiver.
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode rc6_mce[] = {
+	{ 0x800f0415, KEY_REWIND },
+	{ 0x800f0414, KEY_FASTFORWARD },
+	{ 0x800f041b, KEY_PREVIOUS },
+	{ 0x800f041a, KEY_NEXT },
+
+	{ 0x800f0416, KEY_PLAY },
+	{ 0x800f0418, KEY_PAUSE },
+	{ 0x800f0419, KEY_STOP },
+	{ 0x800f0417, KEY_RECORD },
+
+	{ 0x800f041e, KEY_UP },
+	{ 0x800f041f, KEY_DOWN },
+	{ 0x800f0420, KEY_LEFT },
+	{ 0x800f0421, KEY_RIGHT },
+
+	{ 0x800f040b, KEY_ENTER },
+	{ 0x800f0422, KEY_OK },
+	{ 0x800f0423, KEY_EXIT },
+	{ 0x800f040a, KEY_DELETE },
+
+	{ 0x800f040e, KEY_MUTE },
+	{ 0x800f0410, KEY_VOLUMEUP },
+	{ 0x800f0411, KEY_VOLUMEDOWN },
+	{ 0x800f0412, KEY_CHANNELUP },
+	{ 0x800f0413, KEY_CHANNELDOWN },
+
+	{ 0x800f0401, KEY_NUMERIC_1 },
+	{ 0x800f0402, KEY_NUMERIC_2 },
+	{ 0x800f0403, KEY_NUMERIC_3 },
+	{ 0x800f0404, KEY_NUMERIC_4 },
+	{ 0x800f0405, KEY_NUMERIC_5 },
+	{ 0x800f0406, KEY_NUMERIC_6 },
+	{ 0x800f0407, KEY_NUMERIC_7 },
+	{ 0x800f0408, KEY_NUMERIC_8 },
+	{ 0x800f0409, KEY_NUMERIC_9 },
+	{ 0x800f0400, KEY_NUMERIC_0 },
+
+	{ 0x800f041d, KEY_NUMERIC_STAR },
+	{ 0x800f041c, KEY_NUMERIC_POUND },
+
+	{ 0x800f0446, KEY_TV },
+	{ 0x800f0447, KEY_AUDIO }, /* My Music */
+	{ 0x800f0448, KEY_PVR }, /* RecordedTV */
+	{ 0x800f0449, KEY_CAMERA },
+	{ 0x800f044a, KEY_VIDEO },
+	{ 0x800f0424, KEY_DVD },
+	{ 0x800f0425, KEY_TUNER }, /* LiveTV */
+	{ 0x800f0450, KEY_RADIO },
+
+	{ 0x800f044c, KEY_LANGUAGE },
+	{ 0x800f0427, KEY_ZOOM }, /* Aspect */
+
+	{ 0x800f045b, KEY_RED },
+	{ 0x800f045c, KEY_GREEN },
+	{ 0x800f045d, KEY_YELLOW },
+	{ 0x800f045e, KEY_BLUE },
+
+	{ 0x800f040f, KEY_INFO },
+	{ 0x800f0426, KEY_EPG }, /* Guide */
+	{ 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
+	{ 0x800f044d, KEY_TITLE },
+
+	{ 0x800f040c, KEY_POWER },
+	{ 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
+
+};
+
+static struct rc_keymap rc6_mce_map = {
+	.map = {
+		.scan    = rc6_mce,
+		.size    = ARRAY_SIZE(rc6_mce),
+		.ir_type = IR_TYPE_RC6,
+		.name    = RC_MAP_RC6_MCE,
+	}
+};
+
+static int __init init_rc_map_rc6_mce(void)
+{
+	return ir_register_map(&rc6_mce_map);
+}
+
+static void __exit exit_rc_map_rc6_mce(void)
+{
+	ir_unregister_map(&rc6_mce_map);
+}
+
+module_init(init_rc_map_rc6_mce)
+module_exit(exit_rc_map_rc6_mce)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c
new file mode 100644
index 0000000..899891b
--- /dev/null
+++ b/drivers/media/IR/lirc_dev.c
@@ -0,0 +1,764 @@
+/*
+ * LIRC base driver
+ *
+ * by Artur Lipowski <alipowski@interia.pl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/unistd.h>
+#include <linux/kthread.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+static int debug;
+
+#define IRCTL_DEV_NAME	"BaseRemoteCtl"
+#define NOPLUG		-1
+#define LOGHEAD		"lirc_dev (%s[%d]): "
+
+static dev_t lirc_base_dev;
+
+struct irctl {
+	struct lirc_driver d;
+	int attached;
+	int open;
+
+	struct mutex irctl_lock;
+	struct lirc_buffer *buf;
+	unsigned int chunk_size;
+
+	struct task_struct *task;
+	long jiffies_to_wait;
+
+	struct cdev cdev;
+};
+
+static DEFINE_MUTEX(lirc_dev_lock);
+
+static struct irctl *irctls[MAX_IRCTL_DEVICES];
+
+/* Only used for sysfs but defined to void otherwise */
+static struct class *lirc_class;
+
+/*  helper function
+ *  initializes the irctl structure
+ */
+static void init_irctl(struct irctl *ir)
+{
+	dev_dbg(ir->d.dev, LOGHEAD "initializing irctl\n",
+		ir->d.name, ir->d.minor);
+	mutex_init(&ir->irctl_lock);
+	ir->d.minor = NOPLUG;
+}
+
+static void cleanup(struct irctl *ir)
+{
+	dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor);
+
+	device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
+
+	if (ir->buf != ir->d.rbuf) {
+		lirc_buffer_free(ir->buf);
+		kfree(ir->buf);
+	}
+	ir->buf = NULL;
+}
+
+/*  helper function
+ *  reads key codes from driver and puts them into buffer
+ *  returns 0 on success
+ */
+static int add_to_buf(struct irctl *ir)
+{
+	if (ir->d.add_to_buf) {
+		int res = -ENODATA;
+		int got_data = 0;
+
+		/*
+		 * service the device as long as it is returning
+		 * data and we have space
+		 */
+get_data:
+		res = ir->d.add_to_buf(ir->d.data, ir->buf);
+		if (res == 0) {
+			got_data++;
+			goto get_data;
+		}
+
+		if (res == -ENODEV)
+			kthread_stop(ir->task);
+
+		return got_data ? 0 : res;
+	}
+
+	return 0;
+}
+
+/* main function of the polling thread
+ */
+static int lirc_thread(void *irctl)
+{
+	struct irctl *ir = irctl;
+
+	dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n",
+		ir->d.name, ir->d.minor);
+
+	do {
+		if (ir->open) {
+			if (ir->jiffies_to_wait) {
+				set_current_state(TASK_INTERRUPTIBLE);
+				schedule_timeout(ir->jiffies_to_wait);
+			}
+			if (kthread_should_stop())
+				break;
+			if (!add_to_buf(ir))
+				wake_up_interruptible(&ir->buf->wait_poll);
+		} else {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+		}
+	} while (!kthread_should_stop());
+
+	dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n",
+		ir->d.name, ir->d.minor);
+
+	return 0;
+}
+
+
+static struct file_operations fops = {
+	.owner		= THIS_MODULE,
+	.read		= lirc_dev_fop_read,
+	.write		= lirc_dev_fop_write,
+	.poll		= lirc_dev_fop_poll,
+	.unlocked_ioctl	= lirc_dev_fop_ioctl,
+	.open		= lirc_dev_fop_open,
+	.release	= lirc_dev_fop_close,
+};
+
+static int lirc_cdev_add(struct irctl *ir)
+{
+	int retval;
+	struct lirc_driver *d = &ir->d;
+
+	if (d->fops) {
+		cdev_init(&ir->cdev, d->fops);
+		ir->cdev.owner = d->owner;
+	} else {
+		cdev_init(&ir->cdev, &fops);
+		ir->cdev.owner = THIS_MODULE;
+	}
+	kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor);
+
+	retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
+	if (retval)
+		kobject_put(&ir->cdev.kobj);
+
+	return retval;
+}
+
+int lirc_register_driver(struct lirc_driver *d)
+{
+	struct irctl *ir;
+	int minor;
+	int bytes_in_key;
+	unsigned int chunk_size;
+	unsigned int buffer_size;
+	int err;
+
+	if (!d) {
+		printk(KERN_ERR "lirc_dev: lirc_register_driver: "
+		       "driver pointer must be not NULL!\n");
+		err = -EBADRQC;
+		goto out;
+	}
+
+	if (MAX_IRCTL_DEVICES <= d->minor) {
+		dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+			"\"minor\" must be between 0 and %d (%d)!\n",
+			MAX_IRCTL_DEVICES-1, d->minor);
+		err = -EBADRQC;
+		goto out;
+	}
+
+	if (1 > d->code_length || (BUFLEN * 8) < d->code_length) {
+		dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+			"code length in bits for minor (%d) "
+			"must be less than %d!\n",
+			d->minor, BUFLEN * 8);
+		err = -EBADRQC;
+		goto out;
+	}
+
+	dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n",
+		d->sample_rate);
+	if (d->sample_rate) {
+		if (2 > d->sample_rate || HZ < d->sample_rate) {
+			dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+				"sample_rate must be between 2 and %d!\n", HZ);
+			err = -EBADRQC;
+			goto out;
+		}
+		if (!d->add_to_buf) {
+			dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+				"add_to_buf cannot be NULL when "
+				"sample_rate is set\n");
+			err = -EBADRQC;
+			goto out;
+		}
+	} else if (!(d->fops && d->fops->read) && !d->rbuf) {
+		dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+			"fops->read and rbuf cannot all be NULL!\n");
+		err = -EBADRQC;
+		goto out;
+	} else if (!d->rbuf) {
+		if (!(d->fops && d->fops->read && d->fops->poll &&
+		      d->fops->unlocked_ioctl)) {
+			dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+				"neither read, poll nor unlocked_ioctl can be NULL!\n");
+			err = -EBADRQC;
+			goto out;
+		}
+	}
+
+	mutex_lock(&lirc_dev_lock);
+
+	minor = d->minor;
+
+	if (minor < 0) {
+		/* find first free slot for driver */
+		for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++)
+			if (!irctls[minor])
+				break;
+		if (MAX_IRCTL_DEVICES == minor) {
+			dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+				"no free slots for drivers!\n");
+			err = -ENOMEM;
+			goto out_lock;
+		}
+	} else if (irctls[minor]) {
+		dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+			"minor (%d) just registered!\n", minor);
+		err = -EBUSY;
+		goto out_lock;
+	}
+
+	ir = kzalloc(sizeof(struct irctl), GFP_KERNEL);
+	if (!ir) {
+		err = -ENOMEM;
+		goto out_lock;
+	}
+	init_irctl(ir);
+	irctls[minor] = ir;
+	d->minor = minor;
+
+	if (d->sample_rate) {
+		ir->jiffies_to_wait = HZ / d->sample_rate;
+	} else {
+		/* it means - wait for external event in task queue */
+		ir->jiffies_to_wait = 0;
+	}
+
+	/* some safety check 8-) */
+	d->name[sizeof(d->name)-1] = '\0';
+
+	bytes_in_key = BITS_TO_LONGS(d->code_length) +
+			(d->code_length % 8 ? 1 : 0);
+	buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key;
+	chunk_size  = d->chunk_size  ? d->chunk_size  : bytes_in_key;
+
+	if (d->rbuf) {
+		ir->buf = d->rbuf;
+	} else {
+		ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+		if (!ir->buf) {
+			err = -ENOMEM;
+			goto out_lock;
+		}
+		err = lirc_buffer_init(ir->buf, chunk_size, buffer_size);
+		if (err) {
+			kfree(ir->buf);
+			goto out_lock;
+		}
+	}
+	ir->chunk_size = ir->buf->chunk_size;
+
+	if (d->features == 0)
+		d->features = LIRC_CAN_REC_LIRCCODE;
+
+	ir->d = *d;
+	ir->d.minor = minor;
+
+	device_create(lirc_class, ir->d.dev,
+		      MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL,
+		      "lirc%u", ir->d.minor);
+
+	if (d->sample_rate) {
+		/* try to fire up polling thread */
+		ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev");
+		if (IS_ERR(ir->task)) {
+			dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+				"cannot run poll thread for minor = %d\n",
+				d->minor);
+			err = -ECHILD;
+			goto out_sysfs;
+		}
+	}
+
+	err = lirc_cdev_add(ir);
+	if (err)
+		goto out_sysfs;
+
+	ir->attached = 1;
+	mutex_unlock(&lirc_dev_lock);
+
+	dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n",
+		 ir->d.name, ir->d.minor);
+	return minor;
+
+out_sysfs:
+	device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
+out_lock:
+	mutex_unlock(&lirc_dev_lock);
+out:
+	return err;
+}
+EXPORT_SYMBOL(lirc_register_driver);
+
+int lirc_unregister_driver(int minor)
+{
+	struct irctl *ir;
+
+	if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
+		printk(KERN_ERR "lirc_dev: lirc_unregister_driver: "
+		       "\"minor (%d)\" must be between 0 and %d!\n",
+		       minor, MAX_IRCTL_DEVICES-1);
+		return -EBADRQC;
+	}
+
+	ir = irctls[minor];
+
+	mutex_lock(&lirc_dev_lock);
+
+	if (ir->d.minor != minor) {
+		printk(KERN_ERR "lirc_dev: lirc_unregister_driver: "
+		       "minor (%d) device not registered!", minor);
+		mutex_unlock(&lirc_dev_lock);
+		return -ENOENT;
+	}
+
+	/* end up polling thread */
+	if (ir->task)
+		kthread_stop(ir->task);
+
+	dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n",
+		ir->d.name, ir->d.minor);
+
+	ir->attached = 0;
+	if (ir->open) {
+		dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n",
+			ir->d.name, ir->d.minor);
+		wake_up_interruptible(&ir->buf->wait_poll);
+		mutex_lock(&ir->irctl_lock);
+		ir->d.set_use_dec(ir->d.data);
+		module_put(ir->d.owner);
+		mutex_unlock(&ir->irctl_lock);
+		cdev_del(&ir->cdev);
+	} else {
+		cleanup(ir);
+		cdev_del(&ir->cdev);
+		kfree(ir);
+		irctls[minor] = NULL;
+	}
+
+	mutex_unlock(&lirc_dev_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(lirc_unregister_driver);
+
+int lirc_dev_fop_open(struct inode *inode, struct file *file)
+{
+	struct irctl *ir;
+	int retval = 0;
+
+	if (iminor(inode) >= MAX_IRCTL_DEVICES) {
+		printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n",
+		       iminor(inode));
+		return -ENODEV;
+	}
+
+	if (mutex_lock_interruptible(&lirc_dev_lock))
+		return -ERESTARTSYS;
+
+	ir = irctls[iminor(inode)];
+	if (!ir) {
+		retval = -ENODEV;
+		goto error;
+	}
+	file->private_data = ir;
+
+	dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor);
+
+	if (ir->d.minor == NOPLUG) {
+		retval = -ENODEV;
+		goto error;
+	}
+
+	if (ir->open) {
+		retval = -EBUSY;
+		goto error;
+	}
+
+	if (try_module_get(ir->d.owner)) {
+		++ir->open;
+		retval = ir->d.set_use_inc(ir->d.data);
+
+		if (retval) {
+			module_put(ir->d.owner);
+			--ir->open;
+		} else {
+			lirc_buffer_clear(ir->buf);
+		}
+		if (ir->task)
+			wake_up_process(ir->task);
+	}
+
+error:
+	if (ir)
+		dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n",
+			ir->d.name, ir->d.minor, retval);
+
+	mutex_unlock(&lirc_dev_lock);
+
+	return retval;
+}
+EXPORT_SYMBOL(lirc_dev_fop_open);
+
+int lirc_dev_fop_close(struct inode *inode, struct file *file)
+{
+	struct irctl *ir = irctls[iminor(inode)];
+
+	dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
+
+	WARN_ON(mutex_lock_killable(&lirc_dev_lock));
+
+	--ir->open;
+	if (ir->attached) {
+		ir->d.set_use_dec(ir->d.data);
+		module_put(ir->d.owner);
+	} else {
+		cleanup(ir);
+		irctls[ir->d.minor] = NULL;
+		kfree(ir);
+	}
+
+	mutex_unlock(&lirc_dev_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(lirc_dev_fop_close);
+
+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
+{
+	struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+	unsigned int ret;
+
+	dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor);
+
+	if (!ir->attached) {
+		mutex_unlock(&ir->irctl_lock);
+		return POLLERR;
+	}
+
+	poll_wait(file, &ir->buf->wait_poll, wait);
+
+	if (ir->buf)
+		if (lirc_buffer_empty(ir->buf))
+			ret = 0;
+		else
+			ret = POLLIN | POLLRDNORM;
+	else
+		ret = POLLERR;
+
+	dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n",
+		ir->d.name, ir->d.minor, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(lirc_dev_fop_poll);
+
+long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned long mode;
+	int result = 0;
+	struct irctl *ir = file->private_data;
+
+	dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n",
+		ir->d.name, ir->d.minor, cmd);
+
+	if (ir->d.minor == NOPLUG || !ir->attached) {
+		dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n",
+			ir->d.name, ir->d.minor);
+		return -ENODEV;
+	}
+
+	mutex_lock(&ir->irctl_lock);
+
+	switch (cmd) {
+	case LIRC_GET_FEATURES:
+		result = put_user(ir->d.features, (unsigned long *)arg);
+		break;
+	case LIRC_GET_REC_MODE:
+		if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
+			result = -ENOSYS;
+			break;
+		}
+
+		result = put_user(LIRC_REC2MODE
+				  (ir->d.features & LIRC_CAN_REC_MASK),
+				  (unsigned long *)arg);
+		break;
+	case LIRC_SET_REC_MODE:
+		if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
+			result = -ENOSYS;
+			break;
+		}
+
+		result = get_user(mode, (unsigned long *)arg);
+		if (!result && !(LIRC_MODE2REC(mode) & ir->d.features))
+			result = -EINVAL;
+		/*
+		 * FIXME: We should actually set the mode somehow but
+		 * for now, lirc_serial doesn't support mode changing either
+		 */
+		break;
+	case LIRC_GET_LENGTH:
+		result = put_user(ir->d.code_length, (unsigned long *)arg);
+		break;
+	case LIRC_GET_MIN_TIMEOUT:
+		if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
+		    ir->d.min_timeout == 0) {
+			result = -ENOSYS;
+			break;
+		}
+
+		result = put_user(ir->d.min_timeout, (unsigned long *)arg);
+		break;
+	case LIRC_GET_MAX_TIMEOUT:
+		if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
+		    ir->d.max_timeout == 0) {
+			result = -ENOSYS;
+			break;
+		}
+
+		result = put_user(ir->d.max_timeout, (unsigned long *)arg);
+		break;
+	default:
+		result = -EINVAL;
+	}
+
+	dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n",
+		ir->d.name, ir->d.minor, result);
+
+	mutex_unlock(&ir->irctl_lock);
+
+	return result;
+}
+EXPORT_SYMBOL(lirc_dev_fop_ioctl);
+
+ssize_t lirc_dev_fop_read(struct file *file,
+			  char *buffer,
+			  size_t length,
+			  loff_t *ppos)
+{
+	struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+	unsigned char buf[ir->chunk_size];
+	int ret = 0, written = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
+
+	if (mutex_lock_interruptible(&ir->irctl_lock))
+		return -ERESTARTSYS;
+	if (!ir->attached) {
+		mutex_unlock(&ir->irctl_lock);
+		return -ENODEV;
+	}
+
+	if (length % ir->chunk_size) {
+		dev_dbg(ir->d.dev, LOGHEAD "read result = -EINVAL\n",
+			ir->d.name, ir->d.minor);
+		mutex_unlock(&ir->irctl_lock);
+		return -EINVAL;
+	}
+
+	/*
+	 * we add ourselves to the task queue before buffer check
+	 * to avoid losing scan code (in case when queue is awaken somewhere
+	 * between while condition checking and scheduling)
+	 */
+	add_wait_queue(&ir->buf->wait_poll, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	/*
+	 * while we didn't provide 'length' bytes, device is opened in blocking
+	 * mode and 'copy_to_user' is happy, wait for data.
+	 */
+	while (written < length && ret == 0) {
+		if (lirc_buffer_empty(ir->buf)) {
+			/* According to the read(2) man page, 'written' can be
+			 * returned as less than 'length', instead of blocking
+			 * again, returning -EWOULDBLOCK, or returning
+			 * -ERESTARTSYS */
+			if (written)
+				break;
+			if (file->f_flags & O_NONBLOCK) {
+				ret = -EWOULDBLOCK;
+				break;
+			}
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+
+			mutex_unlock(&ir->irctl_lock);
+			schedule();
+			set_current_state(TASK_INTERRUPTIBLE);
+
+			if (mutex_lock_interruptible(&ir->irctl_lock)) {
+				ret = -ERESTARTSYS;
+				remove_wait_queue(&ir->buf->wait_poll, &wait);
+				set_current_state(TASK_RUNNING);
+				goto out_unlocked;
+			}
+
+			if (!ir->attached) {
+				ret = -ENODEV;
+				break;
+			}
+		} else {
+			lirc_buffer_read(ir->buf, buf);
+			ret = copy_to_user((void *)buffer+written, buf,
+					   ir->buf->chunk_size);
+			written += ir->buf->chunk_size;
+		}
+	}
+
+	remove_wait_queue(&ir->buf->wait_poll, &wait);
+	set_current_state(TASK_RUNNING);
+	mutex_unlock(&ir->irctl_lock);
+
+out_unlocked:
+	dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n",
+		ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret);
+
+	return ret ? ret : written;
+}
+EXPORT_SYMBOL(lirc_dev_fop_read);
+
+void *lirc_get_pdata(struct file *file)
+{
+	void *data = NULL;
+
+	if (file && file->f_dentry && file->f_dentry->d_inode &&
+	    file->f_dentry->d_inode->i_rdev) {
+		struct irctl *ir;
+		ir = irctls[iminor(file->f_dentry->d_inode)];
+		data = ir->d.data;
+	}
+
+	return data;
+}
+EXPORT_SYMBOL(lirc_get_pdata);
+
+
+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer,
+			   size_t length, loff_t *ppos)
+{
+	struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+
+	dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor);
+
+	if (!ir->attached)
+		return -ENODEV;
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(lirc_dev_fop_write);
+
+
+static int __init lirc_dev_init(void)
+{
+	int retval;
+
+	lirc_class = class_create(THIS_MODULE, "lirc");
+	if (IS_ERR(lirc_class)) {
+		retval = PTR_ERR(lirc_class);
+		printk(KERN_ERR "lirc_dev: class_create failed\n");
+		goto error;
+	}
+
+	retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES,
+				     IRCTL_DEV_NAME);
+	if (retval) {
+		class_destroy(lirc_class);
+		printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n");
+		goto error;
+	}
+
+
+	printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, "
+	       "major %d \n", MAJOR(lirc_base_dev));
+
+error:
+	return retval;
+}
+
+
+
+static void __exit lirc_dev_exit(void)
+{
+	class_destroy(lirc_class);
+	unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES);
+	printk(KERN_INFO "lirc_dev: module unloaded\n");
+}
+
+module_init(lirc_dev_init);
+module_exit(lirc_dev_exit);
+
+MODULE_DESCRIPTION("LIRC base driver module");
+MODULE_AUTHOR("Artur Lipowski");
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c
new file mode 100644
index 0000000..78bf7f7
--- /dev/null
+++ b/drivers/media/IR/mceusb.c
@@ -0,0 +1,1143 @@
+/*
+ * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan
+ * Conti, Martin Blatter and Daniel Melander, the latter of which was
+ * in turn also based on the lirc_atiusb driver by Paul Miller. The
+ * two mce drivers were merged into one by Jarod Wilson, with transmit
+ * support for the 1st-gen device added primarily by Patrick Calhoun,
+ * with a bit of tweaks by Jarod. Debugging improvements and proper
+ * support for what appears to be 3rd-gen hardware added by Jarod.
+ * Initial port from lirc driver to ir-core drivery by Jarod, based
+ * partially on a port to an earlier proposed IR infrastructure by
+ * Jon Smirl, which included enhancements and simplifications to the
+ * incoming IR buffer parsing routines.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/input.h>
+#include <media/ir-core.h>
+#include <media/ir-common.h>
+
+#define DRIVER_VERSION	"1.91"
+#define DRIVER_AUTHOR	"Jarod Wilson <jarod@wilsonet.com>"
+#define DRIVER_DESC	"Windows Media Center Ed. eHome Infrared Transceiver " \
+			"device driver"
+#define DRIVER_NAME	"mceusb"
+
+#define USB_BUFLEN	32	/* USB reception buffer length */
+#define USB_CTRL_MSG_SZ	2	/* Size of usb ctrl msg on gen1 hw */
+#define MCE_G1_INIT_MSGS 40	/* Init messages on gen1 hw to throw out */
+
+/* MCE constants */
+#define MCE_CMDBUF_SIZE	384 /* MCE Command buffer length */
+#define MCE_TIME_UNIT	50 /* Approx 50us resolution */
+#define MCE_CODE_LENGTH	5 /* Normal length of packet (with header) */
+#define MCE_PACKET_SIZE	4 /* Normal length of packet (without header) */
+#define MCE_PACKET_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */
+#define MCE_CONTROL_HEADER 0x9F /* MCE status header */
+#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */
+#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */
+#define MCE_DEFAULT_TX_MASK 0x03 /* Val opts: TX1=0x01, TX2=0x02, ALL=0x03 */
+#define MCE_PULSE_BIT	0x80 /* Pulse bit, MSB set == PULSE else SPACE */
+#define MCE_PULSE_MASK	0x7F /* Pulse mask */
+#define MCE_MAX_PULSE_LENGTH 0x7F /* Longest transmittable pulse symbol */
+#define MCE_PACKET_LENGTH_MASK  0x1F /* Packet length mask */
+
+
+/* module parameters */
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+/* general constants */
+#define SEND_FLAG_IN_PROGRESS	1
+#define SEND_FLAG_COMPLETE	2
+#define RECV_FLAG_IN_PROGRESS	3
+#define RECV_FLAG_COMPLETE	4
+
+#define MCEUSB_RX		1
+#define MCEUSB_TX		2
+
+#define VENDOR_PHILIPS		0x0471
+#define VENDOR_SMK		0x0609
+#define VENDOR_TATUNG		0x1460
+#define VENDOR_GATEWAY		0x107b
+#define VENDOR_SHUTTLE		0x1308
+#define VENDOR_SHUTTLE2		0x051c
+#define VENDOR_MITSUMI		0x03ee
+#define VENDOR_TOPSEED		0x1784
+#define VENDOR_RICAVISION	0x179d
+#define VENDOR_ITRON		0x195d
+#define VENDOR_FIC		0x1509
+#define VENDOR_LG		0x043e
+#define VENDOR_MICROSOFT	0x045e
+#define VENDOR_FORMOSA		0x147a
+#define VENDOR_FINTEK		0x1934
+#define VENDOR_PINNACLE		0x2304
+#define VENDOR_ECS		0x1019
+#define VENDOR_WISTRON		0x0fb8
+#define VENDOR_COMPRO		0x185b
+#define VENDOR_NORTHSTAR	0x04eb
+#define VENDOR_REALTEK		0x0bda
+#define VENDOR_TIVO		0x105a
+
+static struct usb_device_id mceusb_dev_table[] = {
+	/* Original Microsoft MCE IR Transceiver (often HP-branded) */
+	{ USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
+	/* Philips Infrared Transceiver - Sahara branded */
+	{ USB_DEVICE(VENDOR_PHILIPS, 0x0608) },
+	/* Philips Infrared Transceiver - HP branded */
+	{ USB_DEVICE(VENDOR_PHILIPS, 0x060c) },
+	/* Philips SRM5100 */
+	{ USB_DEVICE(VENDOR_PHILIPS, 0x060d) },
+	/* Philips Infrared Transceiver - Omaura */
+	{ USB_DEVICE(VENDOR_PHILIPS, 0x060f) },
+	/* Philips Infrared Transceiver - Spinel plus */
+	{ USB_DEVICE(VENDOR_PHILIPS, 0x0613) },
+	/* Philips eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_PHILIPS, 0x0815) },
+	/* Realtek MCE IR Receiver */
+	{ USB_DEVICE(VENDOR_REALTEK, 0x0161) },
+	/* SMK/Toshiba G83C0004D410 */
+	{ USB_DEVICE(VENDOR_SMK, 0x031d) },
+	/* SMK eHome Infrared Transceiver (Sony VAIO) */
+	{ USB_DEVICE(VENDOR_SMK, 0x0322) },
+	/* bundled with Hauppauge PVR-150 */
+	{ USB_DEVICE(VENDOR_SMK, 0x0334) },
+	/* SMK eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_SMK, 0x0338) },
+	/* Tatung eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_TATUNG, 0x9150) },
+	/* Shuttle eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_SHUTTLE, 0xc001) },
+	/* Shuttle eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_SHUTTLE2, 0xc001) },
+	/* Gateway eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_GATEWAY, 0x3009) },
+	/* Mitsumi */
+	{ USB_DEVICE(VENDOR_MITSUMI, 0x2501) },
+	/* Topseed eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0001) },
+	/* Topseed HP eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0006) },
+	/* Topseed eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0007) },
+	/* Topseed eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
+	/* Topseed eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x000a) },
+	/* Topseed eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0011) },
+	/* Ricavision internal Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_RICAVISION, 0x0010) },
+	/* Itron ione Libra Q-11 */
+	{ USB_DEVICE(VENDOR_ITRON, 0x7002) },
+	/* FIC eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_FIC, 0x9242) },
+	/* LG eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_LG, 0x9803) },
+	/* Microsoft MCE Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_MICROSOFT, 0x00a0) },
+	/* Formosa eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_FORMOSA, 0xe015) },
+	/* Formosa21 / eHome Infrared Receiver */
+	{ USB_DEVICE(VENDOR_FORMOSA, 0xe016) },
+	/* Formosa aim / Trust MCE Infrared Receiver */
+	{ USB_DEVICE(VENDOR_FORMOSA, 0xe017) },
+	/* Formosa Industrial Computing / Beanbag Emulation Device */
+	{ USB_DEVICE(VENDOR_FORMOSA, 0xe018) },
+	/* Formosa21 / eHome Infrared Receiver */
+	{ USB_DEVICE(VENDOR_FORMOSA, 0xe03a) },
+	/* Formosa Industrial Computing AIM IR605/A */
+	{ USB_DEVICE(VENDOR_FORMOSA, 0xe03c) },
+	/* Formosa Industrial Computing */
+	{ USB_DEVICE(VENDOR_FORMOSA, 0xe03e) },
+	/* Fintek eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_FINTEK, 0x0602) },
+	/* Fintek eHome Infrared Transceiver (in the AOpen MP45) */
+	{ USB_DEVICE(VENDOR_FINTEK, 0x0702) },
+	/* Pinnacle Remote Kit */
+	{ USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
+	/* Elitegroup Computer Systems IR */
+	{ USB_DEVICE(VENDOR_ECS, 0x0f38) },
+	/* Wistron Corp. eHome Infrared Receiver */
+	{ USB_DEVICE(VENDOR_WISTRON, 0x0002) },
+	/* Compro K100 */
+	{ USB_DEVICE(VENDOR_COMPRO, 0x3020) },
+	/* Compro K100 v2 */
+	{ USB_DEVICE(VENDOR_COMPRO, 0x3082) },
+	/* Northstar Systems, Inc. eHome Infrared Transceiver */
+	{ USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) },
+	/* TiVo PC IR Receiver */
+	{ USB_DEVICE(VENDOR_TIVO, 0x2000) },
+	/* Terminating entry */
+	{ }
+};
+
+static struct usb_device_id gen3_list[] = {
+	{ USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
+	{}
+};
+
+static struct usb_device_id microsoft_gen1_list[] = {
+	{ USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
+	{}
+};
+
+static struct usb_device_id std_tx_mask_list[] = {
+	{ USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
+	{ USB_DEVICE(VENDOR_PHILIPS, 0x060c) },
+	{ USB_DEVICE(VENDOR_SMK, 0x031d) },
+	{ USB_DEVICE(VENDOR_SMK, 0x0322) },
+	{ USB_DEVICE(VENDOR_SMK, 0x0334) },
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0001) },
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0006) },
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0007) },
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x000a) },
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0011) },
+	{ USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
+	{}
+};
+
+/* data structure for each usb transceiver */
+struct mceusb_dev {
+	/* ir-core bits */
+	struct ir_input_dev *irdev;
+	struct ir_dev_props *props;
+	struct ir_raw_event rawir;
+
+	/* core device bits */
+	struct device *dev;
+	struct input_dev *idev;
+
+	/* usb */
+	struct usb_device *usbdev;
+	struct urb *urb_in;
+	struct usb_endpoint_descriptor *usb_ep_in;
+	struct usb_endpoint_descriptor *usb_ep_out;
+
+	/* buffers and dma */
+	unsigned char *buf_in;
+	unsigned int len_in;
+	u8 cmd;		/* MCE command type */
+	u8 rem;		/* Remaining IR data bytes in packet */
+	dma_addr_t dma_in;
+	dma_addr_t dma_out;
+
+	struct {
+		u32 connected:1;
+		u32 tx_mask_inverted:1;
+		u32 microsoft_gen1:1;
+		u32 reserved:29;
+	} flags;
+
+	/* transmit support */
+	int send_flags;
+	u32 carrier;
+	unsigned char tx_mask;
+
+	char name[128];
+	char phys[64];
+};
+
+/*
+ * MCE Device Command Strings
+ * Device command responses vary from device to device...
+ * - DEVICE_RESET resets the hardware to its default state
+ * - GET_REVISION fetches the hardware/software revision, common
+ *   replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42
+ * - GET_CARRIER_FREQ gets the carrier mode and frequency of the
+ *   device, with replies in the form of 9f 06 MM FF, where MM is 0-3,
+ *   meaning clk of 10000000, 2500000, 625000 or 156250, and FF is
+ *   ((clk / frequency) - 1)
+ * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us,
+ *   response in the form of 9f 0c msb lsb
+ * - GET_TX_BITMASK fetches the transmitter bitmask, replies in
+ *   the form of 9f 08 bm, where bm is the bitmask
+ * - GET_RX_SENSOR fetches the RX sensor setting -- long-range
+ *   general use one or short-range learning one, in the form of
+ *   9f 14 ss, where ss is either 01 for long-range or 02 for short
+ * - SET_CARRIER_FREQ sets a new carrier mode and frequency
+ * - SET_TX_BITMASK sets the transmitter bitmask
+ * - SET_RX_TIMEOUT sets the receiver timeout
+ * - SET_RX_SENSOR sets which receiver sensor to use
+ */
+static char DEVICE_RESET[]	= {0x00, 0xff, 0xaa};
+static char GET_REVISION[]	= {0xff, 0x0b};
+static char GET_UNKNOWN[]	= {0xff, 0x18};
+static char GET_UNKNOWN2[]	= {0x9f, 0x05};
+static char GET_CARRIER_FREQ[]	= {0x9f, 0x07};
+static char GET_RX_TIMEOUT[]	= {0x9f, 0x0d};
+static char GET_TX_BITMASK[]	= {0x9f, 0x13};
+static char GET_RX_SENSOR[]	= {0x9f, 0x15};
+/* sub in desired values in lower byte or bytes for full command */
+/* FIXME: make use of these for transmit.
+static char SET_CARRIER_FREQ[]	= {0x9f, 0x06, 0x00, 0x00};
+static char SET_TX_BITMASK[]	= {0x9f, 0x08, 0x00};
+static char SET_RX_TIMEOUT[]	= {0x9f, 0x0c, 0x00, 0x00};
+static char SET_RX_SENSOR[]	= {0x9f, 0x14, 0x00};
+*/
+
+static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
+				 int len, bool out)
+{
+	char codes[USB_BUFLEN * 3 + 1];
+	char inout[9];
+	int i;
+	u8 cmd, subcmd, data1, data2;
+	struct device *dev = ir->dev;
+	int idx = 0;
+
+	/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
+	if (ir->flags.microsoft_gen1 && !out)
+		idx = 2;
+
+	if (len <= idx)
+		return;
+
+	for (i = 0; i < len && i < USB_BUFLEN; i++)
+		snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF);
+
+	dev_info(dev, "%sx data: %s (length=%d)\n",
+		 (out ? "t" : "r"), codes, len);
+
+	if (out)
+		strcpy(inout, "Request\0");
+	else
+		strcpy(inout, "Got\0");
+
+	cmd    = buf[idx] & 0xff;
+	subcmd = buf[idx + 1] & 0xff;
+	data1  = buf[idx + 2] & 0xff;
+	data2  = buf[idx + 3] & 0xff;
+
+	switch (cmd) {
+	case 0x00:
+		if (subcmd == 0xff && data1 == 0xaa)
+			dev_info(dev, "Device reset requested\n");
+		else
+			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+				 cmd, subcmd);
+		break;
+	case 0xff:
+		switch (subcmd) {
+		case 0x0b:
+			if (len == 2)
+				dev_info(dev, "Get hw/sw rev?\n");
+			else
+				dev_info(dev, "hw/sw rev 0x%02x 0x%02x "
+					 "0x%02x 0x%02x\n", data1, data2,
+					 buf[idx + 4], buf[idx + 5]);
+			break;
+		case 0xaa:
+			dev_info(dev, "Device reset requested\n");
+			break;
+		case 0xfe:
+			dev_info(dev, "Previous command not supported\n");
+			break;
+		case 0x18:
+		case 0x1b:
+		default:
+			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+				 cmd, subcmd);
+			break;
+		}
+		break;
+	case 0x9f:
+		switch (subcmd) {
+		case 0x03:
+			dev_info(dev, "Ping\n");
+			break;
+		case 0x04:
+			dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
+				 data1, data2);
+			break;
+		case 0x06:
+			dev_info(dev, "%s carrier mode and freq of "
+				 "0x%02x 0x%02x\n", inout, data1, data2);
+			break;
+		case 0x07:
+			dev_info(dev, "Get carrier mode and freq\n");
+			break;
+		case 0x08:
+			dev_info(dev, "%s transmit blaster mask of 0x%02x\n",
+				 inout, data1);
+			break;
+		case 0x0c:
+			/* value is in units of 50us, so x*50/100 or x/2 ms */
+			dev_info(dev, "%s receive timeout of %d ms\n",
+				 inout, ((data1 << 8) | data2) / 2);
+			break;
+		case 0x0d:
+			dev_info(dev, "Get receive timeout\n");
+			break;
+		case 0x13:
+			dev_info(dev, "Get transmit blaster mask\n");
+			break;
+		case 0x14:
+			dev_info(dev, "%s %s-range receive sensor in use\n",
+				 inout, data1 == 0x02 ? "short" : "long");
+			break;
+		case 0x15:
+			if (len == 2)
+				dev_info(dev, "Get receive sensor\n");
+			else
+				dev_info(dev, "Received pulse count is %d\n",
+					 ((data1 << 8) | data2));
+			break;
+		case 0xfe:
+			dev_info(dev, "Error! Hardware is likely wedged...\n");
+			break;
+		case 0x05:
+		case 0x09:
+		case 0x0f:
+		default:
+			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+				 cmd, subcmd);
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void usb_async_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct mceusb_dev *ir;
+	int len;
+
+	if (!urb)
+		return;
+
+	ir = urb->context;
+	if (ir) {
+		len = urb->actual_length;
+
+		dev_dbg(ir->dev, "callback called (status=%d len=%d)\n",
+			urb->status, len);
+
+		if (debug)
+			mceusb_dev_printdata(ir, urb->transfer_buffer,
+					     len, true);
+	}
+
+}
+
+/* request incoming or send outgoing usb packet - used to initialize remote */
+static void mce_request_packet(struct mceusb_dev *ir,
+			       struct usb_endpoint_descriptor *ep,
+			       unsigned char *data, int size, int urb_type)
+{
+	int res;
+	struct urb *async_urb;
+	struct device *dev = ir->dev;
+	unsigned char *async_buf;
+
+	if (urb_type == MCEUSB_TX) {
+		async_urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (unlikely(!async_urb)) {
+			dev_err(dev, "Error, couldn't allocate urb!\n");
+			return;
+		}
+
+		async_buf = kzalloc(size, GFP_KERNEL);
+		if (!async_buf) {
+			dev_err(dev, "Error, couldn't allocate buf!\n");
+			usb_free_urb(async_urb);
+			return;
+		}
+
+		/* outbound data */
+		usb_fill_int_urb(async_urb, ir->usbdev,
+			usb_sndintpipe(ir->usbdev, ep->bEndpointAddress),
+			async_buf, size, (usb_complete_t) usb_async_callback,
+			ir, ep->bInterval);
+		memcpy(async_buf, data, size);
+
+	} else if (urb_type == MCEUSB_RX) {
+		/* standard request */
+		async_urb = ir->urb_in;
+		ir->send_flags = RECV_FLAG_IN_PROGRESS;
+
+	} else {
+		dev_err(dev, "Error! Unknown urb type %d\n", urb_type);
+		return;
+	}
+
+	dev_dbg(dev, "receive request called (size=%#x)\n", size);
+
+	async_urb->transfer_buffer_length = size;
+	async_urb->dev = ir->usbdev;
+
+	res = usb_submit_urb(async_urb, GFP_ATOMIC);
+	if (res) {
+		dev_dbg(dev, "receive request FAILED! (res=%d)\n", res);
+		return;
+	}
+	dev_dbg(dev, "receive request complete (res=%d)\n", res);
+}
+
+static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
+{
+	mce_request_packet(ir, ir->usb_ep_out, data, size, MCEUSB_TX);
+}
+
+static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size)
+{
+	mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_RX);
+}
+
+/* Send data out the IR blaster port(s) */
+static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
+{
+	struct mceusb_dev *ir = priv;
+	int i, ret = 0;
+	int count, cmdcount = 0;
+	unsigned char *cmdbuf; /* MCE command buffer */
+	long signal_duration = 0; /* Singnal length in us */
+	struct timeval start_time, end_time;
+
+	do_gettimeofday(&start_time);
+
+	count = n / sizeof(int);
+
+	cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL);
+	if (!cmdbuf)
+		return -ENOMEM;
+
+	/* MCE tx init header */
+	cmdbuf[cmdcount++] = MCE_CONTROL_HEADER;
+	cmdbuf[cmdcount++] = 0x08;
+	cmdbuf[cmdcount++] = ir->tx_mask;
+
+	/* Generate mce packet data */
+	for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
+		signal_duration += txbuf[i];
+		txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
+
+		do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
+
+			/* Insert mce packet header every 4th entry */
+			if ((cmdcount < MCE_CMDBUF_SIZE) &&
+			    (cmdcount - MCE_TX_HEADER_LENGTH) %
+			     MCE_CODE_LENGTH == 0)
+				cmdbuf[cmdcount++] = MCE_PACKET_HEADER;
+
+			/* Insert mce packet data */
+			if (cmdcount < MCE_CMDBUF_SIZE)
+				cmdbuf[cmdcount++] =
+					(txbuf[i] < MCE_PULSE_BIT ?
+					 txbuf[i] : MCE_MAX_PULSE_LENGTH) |
+					 (i & 1 ? 0x00 : MCE_PULSE_BIT);
+			else {
+				ret = -EINVAL;
+				goto out;
+			}
+
+		} while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) &&
+			 (txbuf[i] -= MCE_MAX_PULSE_LENGTH));
+	}
+
+	/* Fix packet length in last header */
+	cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] =
+		0x80 + (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH - 1;
+
+	/* Check if we have room for the empty packet at the end */
+	if (cmdcount >= MCE_CMDBUF_SIZE) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* All mce commands end with an empty packet (0x80) */
+	cmdbuf[cmdcount++] = 0x80;
+
+	/* Transmit the command to the mce device */
+	mce_async_out(ir, cmdbuf, cmdcount);
+
+	/*
+	 * The lircd gap calculation expects the write function to
+	 * wait the time it takes for the ircommand to be sent before
+	 * it returns.
+	 */
+	do_gettimeofday(&end_time);
+	signal_duration -= (end_time.tv_usec - start_time.tv_usec) +
+			   (end_time.tv_sec - start_time.tv_sec) * 1000000;
+
+	/* delay with the closest number of ticks */
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(usecs_to_jiffies(signal_duration));
+
+out:
+	kfree(cmdbuf);
+	return ret ? ret : n;
+}
+
+/* Sets active IR outputs -- mce devices typically (all?) have two */
+static int mceusb_set_tx_mask(void *priv, u32 mask)
+{
+	struct mceusb_dev *ir = priv;
+
+	if (ir->flags.tx_mask_inverted)
+		ir->tx_mask = (mask != 0x03 ? mask ^ 0x03 : mask) << 1;
+	else
+		ir->tx_mask = mask;
+
+	return 0;
+}
+
+/* Sets the send carrier frequency and mode */
+static int mceusb_set_tx_carrier(void *priv, u32 carrier)
+{
+	struct mceusb_dev *ir = priv;
+	int clk = 10000000;
+	int prescaler = 0, divisor = 0;
+	unsigned char cmdbuf[4] = { 0x9f, 0x06, 0x00, 0x00 };
+
+	/* Carrier has changed */
+	if (ir->carrier != carrier) {
+
+		if (carrier == 0) {
+			ir->carrier = carrier;
+			cmdbuf[2] = 0x01;
+			cmdbuf[3] = 0x80;
+			dev_dbg(ir->dev, "%s: disabling carrier "
+				"modulation\n", __func__);
+			mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+			return carrier;
+		}
+
+		for (prescaler = 0; prescaler < 4; ++prescaler) {
+			divisor = (clk >> (2 * prescaler)) / carrier;
+			if (divisor <= 0xFF) {
+				ir->carrier = carrier;
+				cmdbuf[2] = prescaler;
+				cmdbuf[3] = divisor;
+				dev_dbg(ir->dev, "%s: requesting %u HZ "
+					"carrier\n", __func__, carrier);
+
+				/* Transmit new carrier to mce device */
+				mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+				return carrier;
+			}
+		}
+
+		return -EINVAL;
+
+	}
+
+	return carrier;
+}
+
+static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
+{
+	struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
+	int i, start_index = 0;
+	u8 hdr = MCE_CONTROL_HEADER;
+
+	/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
+	if (ir->flags.microsoft_gen1)
+		start_index = 2;
+
+	for (i = start_index; i < buf_len;) {
+		if (ir->rem == 0) {
+			/* decode mce packets of the form (84),AA,BB,CC,DD */
+			/* IR data packets can span USB messages - rem */
+			hdr = ir->buf_in[i];
+			ir->rem = (hdr & MCE_PACKET_LENGTH_MASK);
+			ir->cmd = (hdr & ~MCE_PACKET_LENGTH_MASK);
+			dev_dbg(ir->dev, "New data. rem: 0x%02x, cmd: 0x%02x\n",
+				ir->rem, ir->cmd);
+			i++;
+		}
+
+		/* don't process MCE commands */
+		if (hdr == MCE_CONTROL_HEADER || hdr == 0xff) {
+			ir->rem = 0;
+			return;
+		}
+
+		for (; (ir->rem > 0) && (i < buf_len); i++) {
+			ir->rem--;
+
+			rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
+			rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
+					 * MCE_TIME_UNIT * 1000;
+
+			if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) {
+				if (ir->rawir.pulse == rawir.pulse)
+					ir->rawir.duration += rawir.duration;
+				else {
+					ir->rawir.duration = rawir.duration;
+					ir->rawir.pulse = rawir.pulse;
+				}
+				continue;
+			}
+			rawir.duration += ir->rawir.duration;
+			ir->rawir.duration = 0;
+			ir->rawir.pulse = rawir.pulse;
+
+			dev_dbg(ir->dev, "Storing %s with duration %d\n",
+				rawir.pulse ? "pulse" : "space",
+				rawir.duration);
+
+			ir_raw_event_store(ir->idev, &rawir);
+		}
+
+		if (ir->buf_in[i] == 0x80 || ir->buf_in[i] == 0x9f)
+			ir->rem = 0;
+
+		dev_dbg(ir->dev, "calling ir_raw_event_handle\n");
+		ir_raw_event_handle(ir->idev);
+	}
+}
+
+static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
+{
+	struct mceusb_dev *ir;
+	int buf_len;
+
+	if (!urb)
+		return;
+
+	ir = urb->context;
+	if (!ir) {
+		usb_unlink_urb(urb);
+		return;
+	}
+
+	buf_len = urb->actual_length;
+
+	if (debug)
+		mceusb_dev_printdata(ir, urb->transfer_buffer, buf_len, false);
+
+	if (ir->send_flags == RECV_FLAG_IN_PROGRESS) {
+		ir->send_flags = SEND_FLAG_COMPLETE;
+		dev_dbg(&ir->irdev->dev, "setup answer received %d bytes\n",
+			buf_len);
+	}
+
+	switch (urb->status) {
+	/* success */
+	case 0:
+		mceusb_process_ir_data(ir, buf_len);
+		break;
+
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		usb_unlink_urb(urb);
+		return;
+
+	case -EPIPE:
+	default:
+		break;
+	}
+
+	usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static void mceusb_gen1_init(struct mceusb_dev *ir)
+{
+	int ret;
+	int maxp = ir->len_in;
+	struct device *dev = ir->dev;
+	char *data;
+
+	data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL);
+	if (!data) {
+		dev_err(dev, "%s: memory allocation failed!\n", __func__);
+		return;
+	}
+
+	/*
+	 * This is a strange one. Windows issues a set address to the device
+	 * on the receive control pipe and expect a certain value pair back
+	 */
+	ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+			      USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0,
+			      data, USB_CTRL_MSG_SZ, HZ * 3);
+	dev_dbg(dev, "%s - ret = %d\n", __func__, ret);
+	dev_dbg(dev, "%s - data[0] = %d, data[1] = %d\n",
+		__func__, data[0], data[1]);
+
+	/* set feature: bit rate 38400 bps */
+	ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
+			      USB_REQ_SET_FEATURE, USB_TYPE_VENDOR,
+			      0xc04e, 0x0000, NULL, 0, HZ * 3);
+
+	dev_dbg(dev, "%s - ret = %d\n", __func__, ret);
+
+	/* bRequest 4: set char length to 8 bits */
+	ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
+			      4, USB_TYPE_VENDOR,
+			      0x0808, 0x0000, NULL, 0, HZ * 3);
+	dev_dbg(dev, "%s - retB = %d\n", __func__, ret);
+
+	/* bRequest 2: set handshaking to use DTR/DSR */
+	ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
+			      2, USB_TYPE_VENDOR,
+			      0x0000, 0x0100, NULL, 0, HZ * 3);
+	dev_dbg(dev, "%s - retC = %d\n", __func__, ret);
+
+	/* device reset */
+	mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+	mce_sync_in(ir, NULL, maxp);
+
+	/* get hw/sw revision? */
+	mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
+	mce_sync_in(ir, NULL, maxp);
+
+	kfree(data);
+};
+
+static void mceusb_gen2_init(struct mceusb_dev *ir)
+{
+	int maxp = ir->len_in;
+
+	/* device reset */
+	mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+	mce_sync_in(ir, NULL, maxp);
+
+	/* get hw/sw revision? */
+	mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
+	mce_sync_in(ir, NULL, maxp);
+
+	/* unknown what the next two actually return... */
+	mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN));
+	mce_sync_in(ir, NULL, maxp);
+	mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2));
+	mce_sync_in(ir, NULL, maxp);
+}
+
+static void mceusb_get_parameters(struct mceusb_dev *ir)
+{
+	int maxp = ir->len_in;
+
+	/* get the carrier and frequency */
+	mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ));
+	mce_sync_in(ir, NULL, maxp);
+
+	/* get the transmitter bitmask */
+	mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
+	mce_sync_in(ir, NULL, maxp);
+
+	/* get receiver timeout value */
+	mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT));
+	mce_sync_in(ir, NULL, maxp);
+
+	/* get receiver sensor setting */
+	mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR));
+	mce_sync_in(ir, NULL, maxp);
+}
+
+static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
+{
+	struct input_dev *idev;
+	struct ir_dev_props *props;
+	struct ir_input_dev *irdev;
+	struct device *dev = ir->dev;
+	int ret = -ENODEV;
+
+	idev = input_allocate_device();
+	if (!idev) {
+		dev_err(dev, "remote input dev allocation failed\n");
+		goto idev_alloc_failed;
+	}
+
+	ret = -ENOMEM;
+	props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
+	if (!props) {
+		dev_err(dev, "remote ir dev props allocation failed\n");
+		goto props_alloc_failed;
+	}
+
+	irdev = kzalloc(sizeof(struct ir_input_dev), GFP_KERNEL);
+	if (!irdev) {
+		dev_err(dev, "remote ir input dev allocation failed\n");
+		goto ir_dev_alloc_failed;
+	}
+
+	snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome "
+		 "Infrared Remote Transceiver (%04x:%04x)",
+		 le16_to_cpu(ir->usbdev->descriptor.idVendor),
+		 le16_to_cpu(ir->usbdev->descriptor.idProduct));
+
+	idev->name = ir->name;
+	usb_make_path(ir->usbdev, ir->phys, sizeof(ir->phys));
+	strlcat(ir->phys, "/input0", sizeof(ir->phys));
+	idev->phys = ir->phys;
+
+	props->priv = ir;
+	props->driver_type = RC_DRIVER_IR_RAW;
+	props->allowed_protos = IR_TYPE_ALL;
+	props->s_tx_mask = mceusb_set_tx_mask;
+	props->s_tx_carrier = mceusb_set_tx_carrier;
+	props->tx_ir = mceusb_tx_ir;
+
+	ir->props = props;
+	ir->irdev = irdev;
+
+	input_set_drvdata(idev, irdev);
+
+	ret = ir_input_register(idev, RC_MAP_RC6_MCE, props, DRIVER_NAME);
+	if (ret < 0) {
+		dev_err(dev, "remote input device register failed\n");
+		goto irdev_failed;
+	}
+
+	return idev;
+
+irdev_failed:
+	kfree(irdev);
+ir_dev_alloc_failed:
+	kfree(props);
+props_alloc_failed:
+	input_free_device(idev);
+idev_alloc_failed:
+	return NULL;
+}
+
+static int __devinit mceusb_dev_probe(struct usb_interface *intf,
+				      const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_host_interface *idesc;
+	struct usb_endpoint_descriptor *ep = NULL;
+	struct usb_endpoint_descriptor *ep_in = NULL;
+	struct usb_endpoint_descriptor *ep_out = NULL;
+	struct usb_host_config *config;
+	struct mceusb_dev *ir = NULL;
+	int pipe, maxp, i;
+	char buf[63], name[128] = "";
+	bool is_gen3;
+	bool is_microsoft_gen1;
+	bool tx_mask_inverted;
+
+	dev_dbg(&intf->dev, ": %s called\n", __func__);
+
+	config = dev->actconfig;
+	idesc  = intf->cur_altsetting;
+
+	is_gen3 = usb_match_id(intf, gen3_list) ? 1 : 0;
+	is_microsoft_gen1 = usb_match_id(intf, microsoft_gen1_list) ? 1 : 0;
+	tx_mask_inverted = usb_match_id(intf, std_tx_mask_list) ? 0 : 1;
+
+	/* step through the endpoints to find first bulk in and out endpoint */
+	for (i = 0; i < idesc->desc.bNumEndpoints; ++i) {
+		ep = &idesc->endpoint[i].desc;
+
+		if ((ep_in == NULL)
+			&& ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+			    == USB_DIR_IN)
+			&& (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+			    == USB_ENDPOINT_XFER_BULK)
+			|| ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+			    == USB_ENDPOINT_XFER_INT))) {
+
+			ep_in = ep;
+			ep_in->bmAttributes = USB_ENDPOINT_XFER_INT;
+			ep_in->bInterval = 1;
+			dev_dbg(&intf->dev, ": acceptable inbound endpoint "
+				"found\n");
+		}
+
+		if ((ep_out == NULL)
+			&& ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+			    == USB_DIR_OUT)
+			&& (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+			    == USB_ENDPOINT_XFER_BULK)
+			|| ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+			    == USB_ENDPOINT_XFER_INT))) {
+
+			ep_out = ep;
+			ep_out->bmAttributes = USB_ENDPOINT_XFER_INT;
+			ep_out->bInterval = 1;
+			dev_dbg(&intf->dev, ": acceptable outbound endpoint "
+				"found\n");
+		}
+	}
+	if (ep_in == NULL) {
+		dev_dbg(&intf->dev, ": inbound and/or endpoint not found\n");
+		return -ENODEV;
+	}
+
+	pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress);
+	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+	ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL);
+	if (!ir)
+		goto mem_alloc_fail;
+
+	ir->buf_in = usb_alloc_coherent(dev, maxp, GFP_ATOMIC, &ir->dma_in);
+	if (!ir->buf_in)
+		goto buf_in_alloc_fail;
+
+	ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ir->urb_in)
+		goto urb_in_alloc_fail;
+
+	ir->usbdev = dev;
+	ir->dev = &intf->dev;
+	ir->len_in = maxp;
+	ir->flags.microsoft_gen1 = is_microsoft_gen1;
+	ir->flags.tx_mask_inverted = tx_mask_inverted;
+
+	/* Saving usb interface data for use by the transmitter routine */
+	ir->usb_ep_in = ep_in;
+	ir->usb_ep_out = ep_out;
+
+	if (dev->descriptor.iManufacturer
+	    && usb_string(dev, dev->descriptor.iManufacturer,
+			  buf, sizeof(buf)) > 0)
+		strlcpy(name, buf, sizeof(name));
+	if (dev->descriptor.iProduct
+	    && usb_string(dev, dev->descriptor.iProduct,
+			  buf, sizeof(buf)) > 0)
+		snprintf(name + strlen(name), sizeof(name) - strlen(name),
+			 " %s", buf);
+
+	ir->idev = mceusb_init_input_dev(ir);
+	if (!ir->idev)
+		goto input_dev_fail;
+
+	/* flush buffers on the device */
+	mce_sync_in(ir, NULL, maxp);
+	mce_sync_in(ir, NULL, maxp);
+
+	/* wire up inbound data handler */
+	usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in,
+		maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval);
+	ir->urb_in->transfer_dma = ir->dma_in;
+	ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* initialize device */
+	if (ir->flags.microsoft_gen1)
+		mceusb_gen1_init(ir);
+	else if (!is_gen3)
+		mceusb_gen2_init(ir);
+
+	mceusb_get_parameters(ir);
+
+	mceusb_set_tx_mask(ir, MCE_DEFAULT_TX_MASK);
+
+	usb_set_intfdata(intf, ir);
+
+	dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name,
+		 dev->bus->busnum, dev->devnum);
+
+	return 0;
+
+	/* Error-handling path */
+input_dev_fail:
+	usb_free_urb(ir->urb_in);
+urb_in_alloc_fail:
+	usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in);
+buf_in_alloc_fail:
+	kfree(ir);
+mem_alloc_fail:
+	dev_err(&intf->dev, "%s: device setup failed!\n", __func__);
+
+	return -ENOMEM;
+}
+
+
+static void __devexit mceusb_dev_disconnect(struct usb_interface *intf)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct mceusb_dev *ir = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+
+	if (!ir)
+		return;
+
+	ir->usbdev = NULL;
+	ir_input_unregister(ir->idev);
+	usb_kill_urb(ir->urb_in);
+	usb_free_urb(ir->urb_in);
+	usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
+
+	kfree(ir);
+}
+
+static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct mceusb_dev *ir = usb_get_intfdata(intf);
+	dev_info(ir->dev, "suspend\n");
+	usb_kill_urb(ir->urb_in);
+	return 0;
+}
+
+static int mceusb_dev_resume(struct usb_interface *intf)
+{
+	struct mceusb_dev *ir = usb_get_intfdata(intf);
+	dev_info(ir->dev, "resume\n");
+	if (usb_submit_urb(ir->urb_in, GFP_ATOMIC))
+		return -EIO;
+	return 0;
+}
+
+static struct usb_driver mceusb_dev_driver = {
+	.name =		DRIVER_NAME,
+	.probe =	mceusb_dev_probe,
+	.disconnect =	mceusb_dev_disconnect,
+	.suspend =	mceusb_dev_suspend,
+	.resume =	mceusb_dev_resume,
+	.reset_resume =	mceusb_dev_resume,
+	.id_table =	mceusb_dev_table
+};
+
+static int __init mceusb_dev_init(void)
+{
+	int ret;
+
+	ret = usb_register(&mceusb_dev_driver);
+	if (ret < 0)
+		printk(KERN_ERR DRIVER_NAME
+		       ": usb register failed, result = %d\n", ret);
+
+	return ret;
+}
+
+static void __exit mceusb_dev_exit(void)
+{
+	usb_deregister(&mceusb_dev_driver);
+}
+
+module_init(mceusb_dev_init);
+module_exit(mceusb_dev_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, mceusb_dev_table);
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 7364b96..4da2a54c 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -57,7 +57,7 @@
 	BUG_ON(in_interrupt());
 
 	videobuf_waiton(&buf->vb,0,0);
-	videobuf_dma_unmap(q, dma);
+	videobuf_dma_unmap(q->dev, dma);
 	videobuf_dma_free(dma);
 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index 74e2b56..8224c30 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -375,7 +375,7 @@
 
 static int vbi_open(struct saa7146_dev *dev, struct file *file)
 {
-	struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+	struct saa7146_fh *fh = file->private_data;
 
 	u32 arbtr_ctrl	= saa7146_read(dev, PCI_BT_V1);
 	int ret = 0;
@@ -437,7 +437,7 @@
 
 static void vbi_close(struct saa7146_dev *dev, struct file *file)
 {
-	struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+	struct saa7146_fh *fh = file->private_data;
 	struct saa7146_vv *vv = dev->vv_data;
 	DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
 
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index b8b2c55..a212a91 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -1370,7 +1370,7 @@
 
 static int video_open(struct saa7146_dev *dev, struct file *file)
 {
-	struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+	struct saa7146_fh *fh = file->private_data;
 	struct saa7146_format *sfmt;
 
 	fh->video_fmt.width = 384;
@@ -1394,7 +1394,7 @@
 
 static void video_close(struct saa7146_dev *dev, struct file *file)
 {
-	struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+	struct saa7146_fh *fh = file->private_data;
 	struct saa7146_vv *vv = dev->vv_data;
 	struct videobuf_queue *q = &fh->video_q;
 	int err;
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
index b2e1545..7955e49 100644
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ b/drivers/media/common/tuners/tda18271-fe.c
@@ -1249,7 +1249,7 @@
 				     struct tda18271_config *cfg)
 {
 	struct tda18271_priv *priv = NULL;
-	int instance;
+	int instance, ret;
 
 	mutex_lock(&tda18271_list_mutex);
 
@@ -1268,10 +1268,12 @@
 		priv->cal_initialized = false;
 		mutex_init(&priv->lock);
 
-		if (tda_fail(tda18271_get_id(fe)))
+		ret = tda18271_get_id(fe);
+		if (tda_fail(ret))
 			goto fail;
 
-		if (tda_fail(tda18271_assign_map_layout(fe)))
+		ret = tda18271_assign_map_layout(fe);
+		if (tda_fail(ret))
 			goto fail;
 
 		mutex_lock(&priv->lock);
diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c
index 8cf2ab6..f8ee29e 100644
--- a/drivers/media/common/tuners/tuner-simple.c
+++ b/drivers/media/common/tuners/tuner-simple.c
@@ -546,14 +546,11 @@
 	struct tuner_simple_priv *priv = fe->tuner_priv;
 	u8 config, cb;
 	u16 div;
-	struct tunertype *tun;
 	u8 buffer[4];
 	int rc, IFPCoff, i;
 	enum param_type desired_type;
 	struct tuner_params *t_params;
 
-	tun = priv->tun;
-
 	/* IFPCoff = Video Intermediate Frequency - Vif:
 		940  =16*58.75  NTSC/J (Japan)
 		732  =16*45.75  M/N STD
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index 432003d..d2b2c12 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -217,6 +217,7 @@
 	return XC_RESULT_SUCCESS;
 }
 
+#if 0
 /* This routine is never used because the only time we read data from the
    i2c bus is when we read registers, and we want that to be an atomic i2c
    transaction in case we are on a multi-master bus */
@@ -231,6 +232,27 @@
 	}
 	return 0;
 }
+#endif
+
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
+{
+	u8 buf[2] = { reg >> 8, reg & 0xff };
+	u8 bval[2] = { 0, 0 };
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->i2c_props.addr,
+			.flags = 0, .buf = &buf[0], .len = 2 },
+		{ .addr = priv->i2c_props.addr,
+			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+	};
+
+	if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
+		printk(KERN_WARNING "xc5000: I2C read failed\n");
+		return -EREMOTEIO;
+	}
+
+	*val = (bval[0] << 8) | bval[1];
+	return XC_RESULT_SUCCESS;
+}
 
 static void xc_wait(int wait_ms)
 {
@@ -275,20 +297,14 @@
 	if (result == XC_RESULT_SUCCESS) {
 		/* wait for busy flag to clear */
 		while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
-			buf[0] = 0;
-			buf[1] = XREG_BUSY;
-
-			result = xc_send_i2c_data(priv, buf, 2);
+			result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf);
 			if (result == XC_RESULT_SUCCESS) {
-				result = xc_read_i2c_data(priv, buf, 2);
-				if (result == XC_RESULT_SUCCESS) {
-					if ((buf[0] == 0) && (buf[1] == 0)) {
-						/* busy flag cleared */
+				if ((buf[0] == 0) && (buf[1] == 0)) {
+					/* busy flag cleared */
 					break;
-					} else {
-						xc_wait(5); /* wait 5 ms */
-						WatchDogTimer--;
-					}
+				} else {
+					xc_wait(5); /* wait 5 ms */
+					WatchDogTimer--;
 				}
 			}
 		}
@@ -526,25 +542,6 @@
 	return found;
 }
 
-static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
-{
-	u8 buf[2] = { reg >> 8, reg & 0xff };
-	u8 bval[2] = { 0, 0 };
-	struct i2c_msg msg[2] = {
-		{ .addr = priv->i2c_props.addr,
-			.flags = 0, .buf = &buf[0], .len = 2 },
-		{ .addr = priv->i2c_props.addr,
-			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
-	};
-
-	if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
-		printk(KERN_WARNING "xc5000: I2C read failed\n");
-		return -EREMOTEIO;
-	}
-
-	*val = (bval[0] << 8) | bval[1];
-	return XC_RESULT_SUCCESS;
-}
 
 static int xc5000_fwupload(struct dvb_frontend *fe)
 {
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index 770243c..cf87051 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -565,7 +565,7 @@
 	int result = 0;
 
 	lock_kernel();
-	dvbdev = (struct dvb_device *)file->private_data;
+	dvbdev = file->private_data;
 	state = (struct dst_state *)dvbdev->priv;
 	p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
 	p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 425862f..0042306 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -207,7 +207,7 @@
 	}
 	/* TODO */
 	dvbdev->users--;
-	if(dvbdev->users==-1 && dmxdev->exit==1) {
+	if (dvbdev->users == 1 && dmxdev->exit == 1) {
 		fops_put(file->f_op);
 		file->f_op = NULL;
 		mutex_unlock(&dmxdev->mutex);
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index ef259a0..cb97e6b 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1318,8 +1318,11 @@
 
 		fragbuf[0] = connection_id;
 		fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
-		if ((status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen)) != 0)
+		status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen);
+		if (status) {
+			status = -EFAULT;
 			goto exit;
+		}
 
 		timeout = jiffies + HZ / 2;
 		written = 0;
@@ -1494,8 +1497,11 @@
 
 	hdr[0] = slot;
 	hdr[1] = connection_id;
-	if ((status = copy_to_user(buf, hdr, 2)) != 0)
+	status = copy_to_user(buf, hdr, 2);
+	if (status) {
+		status = -EFAULT;
 		goto exit;
+	}
 	status = pktlen;
 
 exit:
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 977ddba..4a88a3e 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1130,13 +1130,9 @@
 	if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
 		return -EINVAL;
 
-	p = kmalloc(count, GFP_USER);
-	if (!p)
-		return -ENOMEM;
-	if (copy_from_user(p, buf, count)) {
-		kfree(p);
-		return -EFAULT;
-	}
+	p = memdup_user(buf, count);
+	if (IS_ERR(p))
+		return PTR_ERR(p);
 	if (mutex_lock_interruptible(&dvbdemux->mutex)) {
 		kfree(p);
 		return -ERESTARTSYS;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 44ae89e..4d45b7d 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -465,7 +465,7 @@
 	if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
 		fepriv->delay = fepriv->min_delay;
 
-		/* peform a tune */
+		/* perform a tune */
 		retval = dvb_frontend_swzigzag_autotune(fe,
 							fepriv->check_wrapped);
 		if (retval < 0) {
@@ -791,7 +791,7 @@
 	return 0;
 }
 
-static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
+static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
 					u32 *freq_min, u32 *freq_max)
 {
 	*freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
@@ -815,7 +815,7 @@
 	u32 freq_max;
 
 	/* range check: frequency */
-	dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
+	dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max);
 	if ((freq_min && parms->frequency < freq_min) ||
 	    (freq_max && parms->frequency > freq_max)) {
 		printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
@@ -1627,7 +1627,7 @@
 	case FE_GET_INFO: {
 		struct dvb_frontend_info* info = parg;
 		memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
-		dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max);
+		dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max);
 
 		/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
 		 * do it, it is done for it. */
@@ -1726,7 +1726,7 @@
 			 * (stv0299 for instance) take longer than 8msec to
 			 * respond to a set_voltage command.  Those switches
 			 * need custom routines to switch properly.  For all
-			 * other frontends, the following shoule work ok.
+			 * other frontends, the following should work ok.
 			 * Dish network legacy switches (as used by Dish500)
 			 * are controlled by sending 9-bit command words
 			 * spaced 8msec apart.
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index b6cbb1d..a5c3637 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -37,7 +37,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_a800_table[] = {
+static struct ir_scancode ir_codes_a800_table[] = {
 	{ 0x0201, KEY_PROG1 },       /* SOURCE */
 	{ 0x0200, KEY_POWER },       /* POWER */
 	{ 0x0205, KEY_1 },           /* 1 */
@@ -146,10 +146,12 @@
 	.power_ctrl       = a800_power_ctrl,
 	.identify_state   = a800_identify_state,
 
-	.rc_interval      = DEFAULT_RC_INTERVAL,
-	.rc_key_map       = ir_codes_a800_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_a800_table),
-	.rc_query         = a800_rc_query,
+	.rc.legacy = {
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = ir_codes_a800_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_a800_table),
+		.rc_query         = a800_rc_query,
+	},
 
 	.i2c_algo         = &dibusb_i2c_algo,
 
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
index b41fa87..696207f 100644
--- a/drivers/media/dvb/dvb-usb/af9005-remote.c
+++ b/drivers/media/dvb/dvb-usb/af9005-remote.c
@@ -33,7 +33,7 @@
 
 #define deb_decode(args...)   dprintk(dvb_usb_af9005_remote_debug,0x01,args)
 
-struct dvb_usb_rc_key ir_codes_af9005_table[] = {
+struct ir_scancode ir_codes_af9005_table[] = {
 
 	{0x01b7, KEY_POWER},
 	{0x01a7, KEY_VOLUMEUP},
@@ -133,7 +133,7 @@
 			for (i = 0; i < ir_codes_af9005_table_size; i++) {
 				if (rc5_custom(&ir_codes_af9005_table[i]) == cust
 				    && rc5_data(&ir_codes_af9005_table[i]) == dat) {
-					*event = ir_codes_af9005_table[i].event;
+					*event = ir_codes_af9005_table[i].keycode;
 					*state = REMOTE_KEY_PRESSED;
 					deb_decode
 					    ("key pressed, event %x\n", *event);
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
index cfd6107..8ecba88 100644
--- a/drivers/media/dvb/dvb-usb/af9005.c
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -54,50 +54,6 @@
 	int led_state;
 };
 
-static int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen,
-			  u8 *rbuf, u16 rlen, int delay_ms)
-{
-	int actlen, ret = -ENOMEM;
-
-	if (wbuf == NULL || wlen == 0)
-		return -EINVAL;
-
-	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
-		return ret;
-
-	deb_xfer(">>> ");
-	debug_dump(wbuf, wlen, deb_xfer);
-
-	ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
-						    2), wbuf, wlen,
-			   &actlen, 2000);
-
-	if (ret)
-		err("bulk message failed: %d (%d/%d)", ret, wlen, actlen);
-	else
-		ret = actlen != wlen ? -1 : 0;
-
-	/* an answer is expected, and no error before */
-	if (!ret && rbuf && rlen) {
-		if (delay_ms)
-			msleep(delay_ms);
-
-		ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
-							    0x01), rbuf,
-				   rlen, &actlen, 2000);
-
-		if (ret)
-			err("recv bulk message failed: %d", ret);
-		else {
-			deb_xfer("<<< ");
-			debug_dump(rbuf, actlen, deb_xfer);
-		}
-	}
-
-	mutex_unlock(&d->usb_mutex);
-	return ret;
-}
-
 static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
 			      int readwrite, int type, u8 * values, int len)
 {
@@ -146,7 +102,7 @@
 		obuf[8] = values[0];
 	obuf[7] = command;
 
-	ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
+	ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
 	if (ret)
 		return ret;
 
@@ -534,7 +490,7 @@
 	buf[6] = wlen;
 	for (i = 0; i < wlen; i++)
 		buf[7 + i] = wbuf[i];
-	ret = af9005_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
+	ret = dvb_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
 	if (ret)
 		return ret;
 	if (ibuf[2] != 0x27) {
@@ -581,7 +537,7 @@
 
 	obuf[6] = len;
 	obuf[7] = address;
-	ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
+	ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
 	if (ret)
 		return ret;
 	if (ibuf[2] != 0x2b) {
@@ -882,7 +838,7 @@
 	obuf[2] = 0x40;		/* read remote */
 	obuf[3] = 1;		/* rest of packet length */
 	obuf[4] = st->sequence++;	/* sequence number */
-	ret = af9005_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
+	ret = dvb_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
 	if (ret) {
 		err("rc query failed");
 		return ret;
@@ -1069,10 +1025,15 @@
 
 	.i2c_algo = &af9005_i2c_algo,
 
-	.rc_interval = 200,
-	.rc_key_map = NULL,
-	.rc_key_map_size = 0,
-	.rc_query = af9005_rc_query,
+	.rc.legacy = {
+		.rc_interval = 200,
+		.rc_key_map = NULL,
+		.rc_key_map_size = 0,
+		.rc_query = af9005_rc_query,
+	},
+
+	.generic_bulk_ctrl_endpoint          = 2,
+	.generic_bulk_ctrl_endpoint_response = 1,
 
 	.num_device_descs = 3,
 	.devices = {
@@ -1113,10 +1074,10 @@
 	rc_keys_size = symbol_request(ir_codes_af9005_table_size);
 	if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
 		err("af9005_rc_decode function not found, disabling remote");
-		af9005_properties.rc_query = NULL;
+		af9005_properties.rc.legacy.rc_query = NULL;
 	} else {
-		af9005_properties.rc_key_map = rc_keys;
-		af9005_properties.rc_key_map_size = *rc_keys_size;
+		af9005_properties.rc.legacy.rc_key_map = rc_keys;
+		af9005_properties.rc.legacy.rc_key_map_size = *rc_keys_size;
 	}
 
 	return 0;
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h
index 088e708..3c1fbd1 100644
--- a/drivers/media/dvb/dvb-usb/af9005.h
+++ b/drivers/media/dvb/dvb-usb/af9005.h
@@ -3490,7 +3490,7 @@
 /* remote control decoder */
 extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len,
 			    u32 * event, int *state);
-extern struct dvb_usb_rc_key ir_codes_af9005_table[];
+extern struct ir_scancode ir_codes_af9005_table[];
 extern int ir_codes_af9005_table_size;
 
 #endif
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 66c7c3e..ea1ed3b 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -735,7 +735,7 @@
 
 struct af9015_setup {
 	unsigned int id;
-	struct dvb_usb_rc_key *rc_key_map;
+	struct ir_scancode *rc_key_map;
 	unsigned int rc_key_map_size;
 	u8 *ir_table;
 	unsigned int ir_table_size;
@@ -847,8 +847,8 @@
 	}
 
 	if (table) {
-		props->rc_key_map = table->rc_key_map;
-		props->rc_key_map_size = table->rc_key_map_size;
+		props->rc.legacy.rc_key_map = table->rc_key_map;
+		props->rc.legacy.rc_key_map_size = table->rc_key_map_size;
 		af9015_config.ir_table = table->ir_table;
 		af9015_config.ir_table_size = table->ir_table_size;
 	}
@@ -878,8 +878,8 @@
 	deb_info("%s: IR mode:%d\n", __func__, val);
 	for (i = 0; i < af9015_properties_count; i++) {
 		if (val == AF9015_IR_MODE_DISABLED) {
-			af9015_properties[i].rc_key_map = NULL;
-			af9015_properties[i].rc_key_map_size  = 0;
+			af9015_properties[i].rc.legacy.rc_key_map = NULL;
+			af9015_properties[i].rc.legacy.rc_key_map_size  = 0;
 		} else
 			af9015_set_remote_config(udev, &af9015_properties[i]);
 	}
@@ -1063,7 +1063,7 @@
 {
 	u8 buf[8];
 	struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf};
-	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
 	int i, ret;
 
 	memset(buf, 0, sizeof(buf));
@@ -1075,10 +1075,10 @@
 	*event = 0;
 	*state = REMOTE_NO_KEY_PRESSED;
 
-	for (i = 0; i < d->props.rc_key_map_size; i++) {
+	for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
 		if (!buf[1] && rc5_custom(&keymap[i]) == buf[0] &&
 		    rc5_data(&keymap[i]) == buf[2]) {
-			*event = keymap[i].event;
+			*event = keymap[i].keycode;
 			*state = REMOTE_KEY_PRESSED;
 			break;
 		}
@@ -1299,6 +1299,7 @@
 	{USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV2000DS)},
 /* 30 */{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_UB383_T)},
 	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_4)},
+	{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
 	{0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1353,8 +1354,10 @@
 
 		.identify_state = af9015_identify_state,
 
-		.rc_query         = af9015_rc_query,
-		.rc_interval      = 150,
+		.rc.legacy = {
+			.rc_query         = af9015_rc_query,
+			.rc_interval      = 150,
+		},
 
 		.i2c_algo = &af9015_i2c_algo,
 
@@ -1460,8 +1463,10 @@
 
 		.identify_state = af9015_identify_state,
 
-		.rc_query         = af9015_rc_query,
-		.rc_interval      = 150,
+		.rc.legacy = {
+			.rc_query         = af9015_rc_query,
+			.rc_interval      = 150,
+		},
 
 		.i2c_algo = &af9015_i2c_algo,
 
@@ -1567,12 +1572,14 @@
 
 		.identify_state = af9015_identify_state,
 
-		.rc_query         = af9015_rc_query,
-		.rc_interval      = 150,
+		.rc.legacy = {
+			.rc_query         = af9015_rc_query,
+			.rc_interval      = 150,
+		},
 
 		.i2c_algo = &af9015_i2c_algo,
 
-		.num_device_descs = 8, /* max 9 */
+		.num_device_descs = 9, /* max 9 */
 		.devices = {
 			{
 				.name = "AverMedia AVerTV Volar GPS 805 (A805)",
@@ -1617,6 +1624,11 @@
 				.cold_ids = {&af9015_usb_table[30], NULL},
 				.warm_ids = {NULL},
 			},
+			{
+				.name = "AverMedia AVerTV Volar M (A815Mac)",
+				.cold_ids = {&af9015_usb_table[32], NULL},
+				.warm_ids = {NULL},
+			},
 		}
 	},
 };
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
index 63b2a49..c8e9349 100644
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ b/drivers/media/dvb/dvb-usb/af9015.h
@@ -123,7 +123,7 @@
 
 /* LeadTek - Y04G0051 */
 /* Leadtek WinFast DTV Dongle Gold */
-static struct dvb_usb_rc_key ir_codes_af9015_table_leadtek[] = {
+static struct ir_scancode ir_codes_af9015_table_leadtek[] = {
 	{ 0x001e, KEY_1 },
 	{ 0x001f, KEY_2 },
 	{ 0x0020, KEY_3 },
@@ -227,7 +227,7 @@
 };
 
 /* TwinHan AzureWave AD-TU700(704J) */
-static struct dvb_usb_rc_key ir_codes_af9015_table_twinhan[] = {
+static struct ir_scancode ir_codes_af9015_table_twinhan[] = {
 	{ 0x053f, KEY_POWER },
 	{ 0x0019, KEY_FAVORITES },    /* Favorite List */
 	{ 0x0004, KEY_TEXT },         /* Teletext */
@@ -338,7 +338,7 @@
 };
 
 /* A-Link DTU(m) */
-static struct dvb_usb_rc_key ir_codes_af9015_table_a_link[] = {
+static struct ir_scancode ir_codes_af9015_table_a_link[] = {
 	{ 0x001e, KEY_1 },
 	{ 0x001f, KEY_2 },
 	{ 0x0020, KEY_3 },
@@ -381,7 +381,7 @@
 };
 
 /* MSI DIGIVOX mini II V3.0 */
-static struct dvb_usb_rc_key ir_codes_af9015_table_msi[] = {
+static struct ir_scancode ir_codes_af9015_table_msi[] = {
 	{ 0x001e, KEY_1 },
 	{ 0x001f, KEY_2 },
 	{ 0x0020, KEY_3 },
@@ -424,7 +424,7 @@
 };
 
 /* MYGICTV U718 */
-static struct dvb_usb_rc_key ir_codes_af9015_table_mygictv[] = {
+static struct ir_scancode ir_codes_af9015_table_mygictv[] = {
 	{ 0x003d, KEY_SWITCHVIDEOMODE },
 					  /* TV / AV */
 	{ 0x0545, KEY_POWER },
@@ -550,7 +550,7 @@
 };
 
 /* AverMedia Volar X */
-static struct dvb_usb_rc_key ir_codes_af9015_table_avermedia[] = {
+static struct ir_scancode ir_codes_af9015_table_avermedia[] = {
 	{ 0x053d, KEY_PROG1 },       /* SOURCE */
 	{ 0x0512, KEY_POWER },       /* POWER */
 	{ 0x051e, KEY_1 },           /* 1 */
@@ -656,7 +656,7 @@
 };
 
 /* Digittrade DVB-T USB Stick */
-static struct dvb_usb_rc_key ir_codes_af9015_table_digittrade[] = {
+static struct ir_scancode ir_codes_af9015_table_digittrade[] = {
 	{ 0x010f, KEY_LAST },	/* RETURN */
 	{ 0x0517, KEY_TEXT },	/* TELETEXT */
 	{ 0x0108, KEY_EPG },	/* EPG */
@@ -719,7 +719,7 @@
 };
 
 /* TREKSTOR DVB-T USB Stick */
-static struct dvb_usb_rc_key ir_codes_af9015_table_trekstor[] = {
+static struct ir_scancode ir_codes_af9015_table_trekstor[] = {
 	{ 0x0704, KEY_AGAIN },		/* Home */
 	{ 0x0705, KEY_MUTE },		/* Mute */
 	{ 0x0706, KEY_UP },			/* Up */
@@ -782,7 +782,7 @@
 };
 
 /* MSI DIGIVOX mini III */
-static struct dvb_usb_rc_key ir_codes_af9015_table_msi_digivox_iii[] = {
+static struct ir_scancode ir_codes_af9015_table_msi_digivox_iii[] = {
 	{ 0x0713, KEY_POWER },       /* [red power button] */
 	{ 0x073b, KEY_VIDEO },       /* Source */
 	{ 0x073e, KEY_ZOOM },        /* Zoom */
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index faca1ad..4685259 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -377,7 +377,7 @@
 static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
 	u8 buf[] = {CMD_GET_IR_CODE};
-	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
 	u8 ircode[2];
 	int i, ret;
 
@@ -388,10 +388,10 @@
 	*event = 0;
 	*state = REMOTE_NO_KEY_PRESSED;
 
-	for (i = 0; i < d->props.rc_key_map_size; i++) {
+	for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
 		if (rc5_custom(&keymap[i]) == ircode[0] &&
 		    rc5_data(&keymap[i]) == ircode[1]) {
-			*event = keymap[i].event;
+			*event = keymap[i].keycode;
 			*state = REMOTE_KEY_PRESSED;
 			return 0;
 		}
@@ -399,7 +399,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_anysee_table[] = {
+static struct ir_scancode ir_codes_anysee_table[] = {
 	{ 0x0100, KEY_0 },
 	{ 0x0101, KEY_1 },
 	{ 0x0102, KEY_2 },
@@ -463,6 +463,11 @@
 	if (intf->num_altsetting < 1)
 		return -ENODEV;
 
+	/*
+	 * Anysee is always warm (its USB-bridge, Cypress FX2, uploads
+	 * firmware from eeprom).  If dvb_usb_device_init() succeeds that
+	 * means d is a valid pointer.
+	 */
 	ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d,
 		adapter_nr);
 	if (ret)
@@ -479,10 +484,7 @@
 	if (ret)
 		return ret;
 
-	if (d)
-		ret = anysee_init(d);
-
-	return ret;
+	return anysee_init(d);
 }
 
 static struct usb_device_id anysee_table[] = {
@@ -518,10 +520,12 @@
 		}
 	},
 
-	.rc_key_map       = ir_codes_anysee_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_anysee_table),
-	.rc_query         = anysee_rc_query,
-	.rc_interval      = 200,  /* windows driver uses 500ms */
+	.rc.legacy = {
+		.rc_key_map       = ir_codes_anysee_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_anysee_table),
+		.rc_query         = anysee_rc_query,
+		.rc_interval      = 200,  /* windows driver uses 500ms */
+	},
 
 	.i2c_algo         = &anysee_i2c_algo,
 
diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c
index 6681ac1..62c5828 100644
--- a/drivers/media/dvb/dvb-usb/az6027.c
+++ b/drivers/media/dvb/dvb-usb/az6027.c
@@ -386,7 +386,7 @@
 }
 
 /* keys for the enclosed remote control */
-static struct dvb_usb_rc_key ir_codes_az6027_table[] = {
+static struct ir_scancode ir_codes_az6027_table[] = {
 	{ 0x01, KEY_1 },
 	{ 0x02, KEY_2 },
 };
@@ -1125,10 +1125,13 @@
 	.power_ctrl       = az6027_power_ctrl,
 	.read_mac_address = az6027_read_mac_addr,
  */
-	.rc_key_map       = ir_codes_az6027_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_az6027_table),
-	.rc_interval      = 400,
-	.rc_query         = az6027_rc_query,
+	.rc.legacy = {
+		.rc_key_map       = ir_codes_az6027_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_az6027_table),
+		.rc_interval      = 400,
+		.rc_query         = az6027_rc_query,
+	},
+
 	.i2c_algo         = &az6027_i2c_algo,
 
 	.num_device_descs = 5,
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
index 5a9c14b..4f5aa83f 100644
--- a/drivers/media/dvb/dvb-usb/cinergyT2-core.c
+++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
@@ -84,7 +84,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_cinergyt2_table[] = {
+static struct ir_scancode ir_codes_cinergyt2_table[] = {
 	{ 0x0401, KEY_POWER },
 	{ 0x0402, KEY_1 },
 	{ 0x0403, KEY_2 },
@@ -217,10 +217,12 @@
 
 	.power_ctrl       = cinergyt2_power_ctrl,
 
-	.rc_interval      = 50,
-	.rc_key_map       = ir_codes_cinergyt2_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_cinergyt2_table),
-	.rc_query         = cinergyt2_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 50,
+		.rc_key_map       = ir_codes_cinergyt2_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_cinergyt2_table),
+		.rc_query         = cinergyt2_rc_query,
+	},
 
 	.generic_bulk_ctrl_endpoint = 1,
 
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 11e9e85..cd9f362 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -385,7 +385,7 @@
 
 static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
 	u8 ircode[4];
 	int i;
 
@@ -394,10 +394,10 @@
 	*event = 0;
 	*state = REMOTE_NO_KEY_PRESSED;
 
-	for (i = 0; i < d->props.rc_key_map_size; i++) {
+	for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
 		if (rc5_custom(&keymap[i]) == ircode[2] &&
 		    rc5_data(&keymap[i]) == ircode[3]) {
-			*event = keymap[i].event;
+			*event = keymap[i].keycode;
 			*state = REMOTE_KEY_PRESSED;
 
 			return 0;
@@ -410,7 +410,7 @@
 static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
 				    int *state)
 {
-	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
 	u8 ircode[4];
 	int i;
 	struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
@@ -422,10 +422,10 @@
 	if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
 		return 0;
 
-	for (i = 0; i < d->props.rc_key_map_size; i++) {
+	for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
 		if (rc5_custom(&keymap[i]) == ircode[1] &&
 		    rc5_data(&keymap[i]) == ircode[2]) {
-			*event = keymap[i].event;
+			*event = keymap[i].keycode;
 			*state = REMOTE_KEY_PRESSED;
 
 			return 0;
@@ -438,7 +438,7 @@
 static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
 		int *state)
 {
-	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
 	u8 ircode[2];
 	int i;
 
@@ -448,10 +448,10 @@
 	if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
 		return 0;
 
-	for (i = 0; i < d->props.rc_key_map_size; i++) {
+	for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
 		if (rc5_custom(&keymap[i]) == ircode[0] &&
 		    rc5_data(&keymap[i]) == ircode[1]) {
-			*event = keymap[i].event;
+			*event = keymap[i].keycode;
 			*state = REMOTE_KEY_PRESSED;
 
 			return 0;
@@ -461,7 +461,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_dvico_mce_table[] = {
+static struct ir_scancode ir_codes_dvico_mce_table[] = {
 	{ 0xfe02, KEY_TV },
 	{ 0xfe0e, KEY_MP3 },
 	{ 0xfe1a, KEY_DVD },
@@ -509,7 +509,7 @@
 	{ 0xfe4e, KEY_POWER },
 };
 
-static struct dvb_usb_rc_key ir_codes_dvico_portable_table[] = {
+static struct ir_scancode ir_codes_dvico_portable_table[] = {
 	{ 0xfc02, KEY_SETUP },       /* Profile */
 	{ 0xfc43, KEY_POWER2 },
 	{ 0xfc06, KEY_EPG },
@@ -548,7 +548,7 @@
 	{ 0xfc00, KEY_UNKNOWN },    /* HD */
 };
 
-static struct dvb_usb_rc_key ir_codes_d680_dmb_table[] = {
+static struct ir_scancode ir_codes_d680_dmb_table[] = {
 	{ 0x0038, KEY_UNKNOWN },	/* TV/AV */
 	{ 0x080c, KEY_ZOOM },
 	{ 0x0800, KEY_0 },
@@ -923,7 +923,7 @@
 		return -EIO;
 
 	/* try to determine if there is no IR decoder on the I2C bus */
-	for (i = 0; adap->dev->props.rc_key_map != NULL && i < 5; i++) {
+	for (i = 0; adap->dev->props.rc.legacy.rc_key_map != NULL && i < 5; i++) {
 		msleep(20);
 		if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
 			goto no_IR;
@@ -931,7 +931,7 @@
 			continue;
 		if (ircode[2] + ircode[3] != 0xff) {
 no_IR:
-			adap->dev->props.rc_key_map = NULL;
+			adap->dev->props.rc.legacy.rc_key_map = NULL;
 			info("No IR receiver detected on this device.");
 			break;
 		}
@@ -1451,10 +1451,12 @@
 
 	.i2c_algo         = &cxusb_i2c_algo,
 
-	.rc_interval      = 100,
-	.rc_key_map       = ir_codes_dvico_portable_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
-	.rc_query         = cxusb_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_key_map       = ir_codes_dvico_portable_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
+		.rc_query         = cxusb_rc_query,
+	},
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
@@ -1502,10 +1504,12 @@
 
 	.i2c_algo         = &cxusb_i2c_algo,
 
-	.rc_interval      = 150,
-	.rc_key_map       = ir_codes_dvico_mce_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
-	.rc_query         = cxusb_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 150,
+		.rc_key_map       = ir_codes_dvico_mce_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
+		.rc_query         = cxusb_rc_query,
+	},
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
@@ -1561,10 +1565,12 @@
 
 	.i2c_algo         = &cxusb_i2c_algo,
 
-	.rc_interval      = 100,
-	.rc_key_map       = ir_codes_dvico_portable_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
-	.rc_query         = cxusb_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_key_map       = ir_codes_dvico_portable_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
+		.rc_query         = cxusb_rc_query,
+	},
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 	.num_device_descs = 1,
@@ -1611,10 +1617,12 @@
 
 	.i2c_algo         = &cxusb_i2c_algo,
 
-	.rc_interval      = 100,
-	.rc_key_map       = ir_codes_dvico_portable_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
-	.rc_query         = cxusb_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_key_map       = ir_codes_dvico_portable_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
+		.rc_query         = cxusb_rc_query,
+	},
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
@@ -1660,10 +1668,12 @@
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
-	.rc_interval      = 100,
-	.rc_key_map       = ir_codes_dvico_mce_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
-	.rc_query         = cxusb_bluebird2_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_key_map       = ir_codes_dvico_mce_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
+		.rc_query         = cxusb_bluebird2_rc_query,
+	},
 
 	.num_device_descs = 1,
 	.devices = {
@@ -1708,10 +1718,12 @@
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
-	.rc_interval      = 100,
-	.rc_key_map       = ir_codes_dvico_portable_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
-	.rc_query         = cxusb_bluebird2_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_key_map       = ir_codes_dvico_portable_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
+		.rc_query         = cxusb_bluebird2_rc_query,
+	},
 
 	.num_device_descs = 1,
 	.devices = {
@@ -1758,10 +1770,12 @@
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
-	.rc_interval      = 100,
-	.rc_key_map       = ir_codes_dvico_portable_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
-	.rc_query         = cxusb_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_key_map       = ir_codes_dvico_portable_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_portable_table),
+		.rc_query         = cxusb_rc_query,
+	},
 
 	.num_device_descs = 1,
 	.devices = {
@@ -1849,10 +1863,12 @@
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
-	.rc_interval      = 100,
-	.rc_key_map       = ir_codes_dvico_mce_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
-	.rc_query         = cxusb_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_key_map       = ir_codes_dvico_mce_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dvico_mce_table),
+		.rc_query         = cxusb_rc_query,
+	},
 
 	.num_device_descs = 1,
 	.devices = {
@@ -1897,10 +1913,12 @@
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
-	.rc_interval      = 100,
-	.rc_key_map       = ir_codes_d680_dmb_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_d680_dmb_table),
-	.rc_query         = cxusb_d680_dmb_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_key_map       = ir_codes_d680_dmb_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_d680_dmb_table),
+		.rc_query         = cxusb_d680_dmb_rc_query,
+	},
 
 	.num_device_descs = 1,
 	.devices = {
@@ -1946,10 +1964,12 @@
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
-	.rc_interval      = 100,
-	.rc_key_map       = ir_codes_d680_dmb_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_d680_dmb_table),
-	.rc_query         = cxusb_d680_dmb_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_key_map       = ir_codes_d680_dmb_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_d680_dmb_table),
+		.rc_query         = cxusb_d680_dmb_rc_query,
+	},
 
 	.num_device_descs = 1,
 	.devices = {
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index 83fc24a..c2c9d23 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -60,6 +60,7 @@
 extern struct i2c_algorithm dib0700_i2c_algo;
 extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
 			struct dvb_usb_device_description **desc, int *cold);
+extern int dib0700_change_protocol(void *priv, u64 ir_type);
 
 extern int dib0700_device_count;
 extern int dvb_usb_dib0700_ir_proto;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 4f961d2..fe81834 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -13,10 +13,6 @@
 module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
 
-int dvb_usb_dib0700_ir_proto = 1;
-module_param(dvb_usb_dib0700_ir_proto, int, 0644);
-MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6).");
-
 static int nb_packet_buffer_size = 21;
 module_param(nb_packet_buffer_size, int, 0644);
 MODULE_PARM_DESC(nb_packet_buffer_size,
@@ -53,7 +49,7 @@
 	int status;
 
 	deb_data(">>> ");
-	debug_dump(tx,txlen,deb_data);
+	debug_dump(tx, txlen, deb_data);
 
 	status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0),
 		tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen,
@@ -98,7 +94,7 @@
 		deb_info("ep 0 read error (status = %d)\n",status);
 
 	deb_data("<<< ");
-	debug_dump(rx,rxlen,deb_data);
+	debug_dump(rx, rxlen, deb_data);
 
 	return status; /* length in case of success */
 }
@@ -106,28 +102,29 @@
 int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
 {
 	u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) };
-	return dib0700_ctrl_wr(d,buf,3);
+	return dib0700_ctrl_wr(d, buf, sizeof(buf));
 }
 
 static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
 {
-    struct dib0700_state *st = d->priv;
-    u8 b[3];
-    int ret;
+	struct dib0700_state *st = d->priv;
+	u8 b[3];
+	int ret;
 
-    if (st->fw_version >= 0x10201) {
-	b[0] = REQUEST_SET_USB_XFER_LEN;
-	b[1] = (nb_ts_packets >> 8)&0xff;
-	b[2] = nb_ts_packets & 0xff;
+	if (st->fw_version >= 0x10201) {
+		b[0] = REQUEST_SET_USB_XFER_LEN;
+		b[1] = (nb_ts_packets >> 8) & 0xff;
+		b[2] = nb_ts_packets & 0xff;
 
-	deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
+		deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
 
-	ret = dib0700_ctrl_wr(d, b, 3);
-    } else {
-	deb_info("this firmware does not allow to change the USB xfer len\n");
-	ret = -EIO;
-    }
-    return ret;
+		ret = dib0700_ctrl_wr(d, b, sizeof(b));
+	} else {
+		deb_info("this firmware does not allow to change the USB xfer len\n");
+		ret = -EIO;
+	}
+
+	return ret;
 }
 
 /*
@@ -178,7 +175,8 @@
 			value = ((en_start << 7) | (en_stop << 6) |
 				 (msg[i].len & 0x3F)) << 8 | i2c_dest;
 			/* I2C ctrl + FE bus; */
-			index = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+			index = ((gen_mode << 6) & 0xC0) |
+				((bus_mode << 4) & 0x30);
 
 			result = usb_control_msg(d->udev,
 						 usb_rcvctrlpipe(d->udev, 0),
@@ -198,11 +196,12 @@
 		} else {
 			/* Write request */
 			buf[0] = REQUEST_NEW_I2C_WRITE;
-			buf[1] = (msg[i].addr << 1);
+			buf[1] = msg[i].addr << 1;
 			buf[2] = (en_start << 7) | (en_stop << 6) |
 				(msg[i].len & 0x3F);
 			/* I2C ctrl + FE bus; */
-			buf[3] = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+			buf[3] = ((gen_mode << 6) & 0xC0) |
+				 ((bus_mode << 4) & 0x30);
 			/* The Actual i2c payload */
 			memcpy(&buf[4], msg[i].buf, msg[i].len);
 
@@ -240,7 +239,7 @@
 
 	for (i = 0; i < num; i++) {
 		/* fill in the address */
-		buf[1] = (msg[i].addr << 1);
+		buf[1] = msg[i].addr << 1;
 		/* fill the buffer */
 		memcpy(&buf[2], msg[i].buf, msg[i].len);
 
@@ -368,7 +367,8 @@
 	u8 buf[260];
 
 	while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
-		deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",hx.addr, hx.len, hx.chk);
+		deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",
+				hx.addr, hx.len, hx.chk);
 
 		buf[0] = hx.len;
 		buf[1] = (hx.addr >> 8) & 0xff;
@@ -408,16 +408,16 @@
 				  REQUEST_GET_VERSION,
 				  USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
 				  b, sizeof(b), USB_CTRL_GET_TIMEOUT);
-	fw_version = (b[8] << 24)  | (b[9] << 16)  | (b[10] << 8) | b[11];
+	fw_version = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11];
 
 	/* set the buffer size - DVB-USB is allocating URB buffers
 	 * only after the firwmare download was successful */
 	for (i = 0; i < dib0700_device_count; i++) {
 		for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters;
 				adap_num++) {
-			if (fw_version >= 0x10201)
+			if (fw_version >= 0x10201) {
 				dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
-			else {
+			} else {
 				/* for fw version older than 1.20.1,
 				 * the buffersize has to be n times 512 */
 				dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
@@ -453,7 +453,7 @@
 	if (st->disable_streaming_master_mode == 1)
 		b[2] = 0x00;
 	else
-		b[2] = (0x01 << 4); /* Master mode */
+		b[2] = 0x01 << 4; /* Master mode */
 
 	b[3] = 0x00;
 
@@ -466,11 +466,44 @@
 
 	b[2] |= st->channel_state;
 
-	deb_info("data for streaming: %x %x\n",b[1],b[2]);
+	deb_info("data for streaming: %x %x\n", b[1], b[2]);
 
 	return dib0700_ctrl_wr(adap->dev, b, 4);
 }
 
+int dib0700_change_protocol(void *priv, u64 ir_type)
+{
+	struct dvb_usb_device *d = priv;
+	struct dib0700_state *st = d->priv;
+	u8 rc_setup[3] = { REQUEST_SET_RC, 0, 0 };
+	int new_proto, ret;
+
+	/* Set the IR mode */
+	if (ir_type == IR_TYPE_RC5)
+		new_proto = 1;
+	else if (ir_type == IR_TYPE_NEC)
+		new_proto = 0;
+	else if (ir_type == IR_TYPE_RC6) {
+		if (st->fw_version < 0x10200)
+			return -EINVAL;
+
+		new_proto = 2;
+	} else
+		return -EINVAL;
+
+	rc_setup[1] = new_proto;
+
+	ret = dib0700_ctrl_wr(d, rc_setup, sizeof(rc_setup));
+	if (ret < 0) {
+		err("ir protocol setup failed");
+		return ret;
+	}
+
+	d->props.rc.core.protocol = ir_type;
+
+	return ret;
+}
+
 /* Number of keypresses to ignore before start repeating */
 #define RC_REPEAT_DELAY_V1_20 10
 
@@ -478,7 +511,13 @@
 struct dib0700_rc_response {
 	u8 report_id;
 	u8 data_state;
-	u16 system;
+	union {
+		u16 system16;
+		struct {
+			u8 system;
+			u8 not_system;
+		};
+	};
 	u8 data;
 	u8 not_data;
 };
@@ -487,14 +526,10 @@
 static void dib0700_rc_urb_completion(struct urb *purb)
 {
 	struct dvb_usb_device *d = purb->context;
-	struct dvb_usb_rc_key *keymap;
 	struct dib0700_state *st;
-	struct dib0700_rc_response poll_reply;
-	u8 *buf;
-	int found = 0;
-	u32 event;
-	int state;
-	int i;
+	struct dib0700_rc_response *poll_reply;
+	u32 uninitialized_var(keycode);
+	u8 toggle;
 
 	deb_info("%s()\n", __func__);
 	if (d == NULL)
@@ -506,9 +541,8 @@
 		return;
 	}
 
-	keymap = d->props.rc_key_map;
 	st = d->priv;
-	buf = (u8 *)purb->transfer_buffer;
+	poll_reply = purb->transfer_buffer;
 
 	if (purb->status < 0) {
 		deb_info("discontinuing polling\n");
@@ -521,104 +555,52 @@
 		goto resubmit;
 	}
 
-	/* Set initial results in case we exit the function early */
-	event = 0;
-	state = REMOTE_NO_KEY_PRESSED;
+	deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n",
+		 poll_reply->report_id, poll_reply->data_state,
+		 poll_reply->system, poll_reply->not_system,
+		 poll_reply->data, poll_reply->not_data,
+		 purb->actual_length);
 
-	deb_data("IR raw %02X %02X %02X %02X %02X %02X (len %d)\n", buf[0],
-		 buf[1], buf[2], buf[3], buf[4], buf[5], purb->actual_length);
-
-	switch (dvb_usb_dib0700_ir_proto) {
-	case 0:
-		/* NEC Protocol */
-		poll_reply.report_id  = 0;
-		poll_reply.data_state = 1;
-		poll_reply.system     = buf[2];
-		poll_reply.data       = buf[4];
-		poll_reply.not_data   = buf[5];
+	switch (d->props.rc.core.protocol) {
+	case IR_TYPE_NEC:
+		toggle = 0;
 
 		/* NEC protocol sends repeat code as 0 0 0 FF */
-		if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
-		    && (poll_reply.not_data == 0xff)) {
-			poll_reply.data_state = 2;
+		if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00)
+		    && (poll_reply->not_data == 0xff)) {
+			poll_reply->data_state = 2;
 			break;
 		}
+
+		if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
+			deb_data("NEC extended protocol\n");
+			/* NEC extended code - 24 bits */
+			keycode = poll_reply->system16 << 8 | poll_reply->data;
+		} else {
+			deb_data("NEC normal protocol\n");
+			/* normal NEC code - 16 bits */
+			keycode = poll_reply->system << 8 | poll_reply->data;
+		}
+
 		break;
 	default:
+		deb_data("RC5 protocol\n");
 		/* RC5 Protocol */
-		poll_reply.report_id  = buf[0];
-		poll_reply.data_state = buf[1];
-		poll_reply.system     = (buf[2] << 8) | buf[3];
-		poll_reply.data       = buf[4];
-		poll_reply.not_data   = buf[5];
+		toggle = poll_reply->report_id;
+		keycode = poll_reply->system16 << 8 | poll_reply->data;
+
 		break;
 	}
 
-	if ((poll_reply.data + poll_reply.not_data) != 0xff) {
+	if ((poll_reply->data + poll_reply->not_data) != 0xff) {
 		/* Key failed integrity check */
 		err("key failed integrity check: %04x %02x %02x",
-		    poll_reply.system,
-		    poll_reply.data, poll_reply.not_data);
+		    poll_reply->system,
+		    poll_reply->data, poll_reply->not_data);
 		goto resubmit;
 	}
 
-	deb_data("rid=%02x ds=%02x sm=%04x d=%02x nd=%02x\n",
-		 poll_reply.report_id, poll_reply.data_state,
-		 poll_reply.system, poll_reply.data, poll_reply.not_data);
-
-	/* Find the key in the map */
-	for (i = 0; i < d->props.rc_key_map_size; i++) {
-		if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
-		    rc5_data(&keymap[i]) == poll_reply.data) {
-			event = keymap[i].event;
-			found = 1;
-			break;
-		}
-	}
-
-	if (found == 0) {
-		err("Unknown remote controller key: %04x %02x %02x",
-		    poll_reply.system, poll_reply.data, poll_reply.not_data);
-		d->last_event = 0;
-		goto resubmit;
-	}
-
-	if (poll_reply.data_state == 1) {
-		/* New key hit */
-		st->rc_counter = 0;
-		event = keymap[i].event;
-		state = REMOTE_KEY_PRESSED;
-		d->last_event = keymap[i].event;
-	} else if (poll_reply.data_state == 2) {
-		/* Key repeated */
-		st->rc_counter++;
-
-		/* prevents unwanted double hits */
-		if (st->rc_counter > RC_REPEAT_DELAY_V1_20) {
-			event = d->last_event;
-			state = REMOTE_KEY_PRESSED;
-			st->rc_counter = RC_REPEAT_DELAY_V1_20;
-		}
-	} else {
-		err("Unknown data state [%d]", poll_reply.data_state);
-	}
-
-	switch (state) {
-	case REMOTE_NO_KEY_PRESSED:
-		break;
-	case REMOTE_KEY_PRESSED:
-		deb_info("key pressed\n");
-		d->last_event = event;
-	case REMOTE_KEY_REPEAT:
-		deb_info("key repeated\n");
-		input_event(d->rc_input_dev, EV_KEY, event, 1);
-		input_sync(d->rc_input_dev);
-		input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
-		input_sync(d->rc_input_dev);
-		break;
-	default:
-		break;
-	}
+	ir_keydown(d->rc_input_dev, keycode, toggle);
 
 resubmit:
 	/* Clean the buffer before we requeue */
@@ -631,21 +613,10 @@
 int dib0700_rc_setup(struct dvb_usb_device *d)
 {
 	struct dib0700_state *st = d->priv;
-	u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
 	struct urb *purb;
 	int ret;
-	int i;
 
-	if (d->props.rc_key_map == NULL)
-		return 0;
-
-	/* Set the IR mode */
-	i = dib0700_ctrl_wr(d, rc_setup, 3);
-	if (i<0) {
-		err("ir protocol setup failed");
-		return -1;
-	}
-
+	/* Poll-based. Don't initialize bulk mode */
 	if (st->fw_version < 0x10200)
 		return 0;
 
@@ -653,14 +624,14 @@
 	purb = usb_alloc_urb(0, GFP_KERNEL);
 	if (purb == NULL) {
 		err("rc usb alloc urb failed\n");
-		return -1;
+		return -ENOMEM;
 	}
 
 	purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
 	if (purb->transfer_buffer == NULL) {
 		err("rc kzalloc failed\n");
 		usb_free_urb(purb);
-		return -1;
+		return -ENOMEM;
 	}
 
 	purb->status = -EINPROGRESS;
@@ -669,12 +640,10 @@
 			  dib0700_rc_urb_completion, d);
 
 	ret = usb_submit_urb(purb, GFP_ATOMIC);
-	if (ret != 0) {
+	if (ret)
 		err("rc submit urb failed\n");
-		return -1;
-	}
 
-	return 0;
+	return ret;
 }
 
 static int dib0700_probe(struct usb_interface *intf,
@@ -698,6 +667,15 @@
 			st->fw_version = fw_version;
 			st->nb_packet_buffer_size = (u32)nb_packet_buffer_size;
 
+			/* Disable polling mode on newer firmwares */
+			if (st->fw_version >= 0x10200)
+				dev->props.rc.core.bulk_mode = true;
+			else
+				dev->props.rc.core.bulk_mode = false;
+
+			/* Need a higher delay, to avoid wrong repeat */
+			dev->rc_input_dev->rep[REP_DELAY] = 500;
+
 			dib0700_rc_setup(dev);
 
 			return 0;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 800800a..f634d2e 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -473,16 +473,19 @@
 /* Number of keypresses to ignore before start repeating */
 #define RC_REPEAT_DELAY 6
 
-static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+/*
+ * This function is used only when firmware is < 1.20 version. Newer
+ * firmwares use bulk mode, with functions implemented at dib0700_core,
+ * at dib0700_rc_urb_completion()
+ */
+static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
 {
 	u8 key[4];
+	u32 keycode;
+	u8 toggle;
 	int i;
-	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
 	struct dib0700_state *st = d->priv;
 
-	*event = 0;
-	*state = REMOTE_NO_KEY_PRESSED;
-
 	if (st->fw_version >= 0x10200) {
 		/* For 1.20 firmware , We need to keep the RC polling
 		   callback so we can reuse the input device setup in
@@ -491,348 +494,45 @@
 		return 0;
 	}
 
-	i=dib0700_ctrl_rd(d,rc_request,2,key,4);
-	if (i<=0) {
+	i = dib0700_ctrl_rd(d, rc_request, 2, key, 4);
+	if (i <= 0) {
 		err("RC Query Failed");
 		return -1;
 	}
 
 	/* losing half of KEY_0 events from Philipps rc5 remotes.. */
-	if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0;
+	if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 0)
+		return 0;
 
 	/* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]);  */
 
 	dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */
 
-	switch (dvb_usb_dib0700_ir_proto) {
-	case 0: {
+	d->last_event = 0;
+	switch (d->props.rc.core.protocol) {
+	case IR_TYPE_NEC:
 		/* NEC protocol sends repeat code as 0 0 0 FF */
 		if ((key[3-2] == 0x00) && (key[3-3] == 0x00) &&
-		    (key[3] == 0xFF)) {
-			st->rc_counter++;
-			if (st->rc_counter > RC_REPEAT_DELAY) {
-				*event = d->last_event;
-				*state = REMOTE_KEY_PRESSED;
-				st->rc_counter = RC_REPEAT_DELAY;
-			}
-			return 0;
+		    (key[3] == 0xff))
+			keycode = d->last_event;
+		else {
+			keycode = key[3-2] << 8 | key[3-3];
+			d->last_event = keycode;
 		}
-		for (i=0;i<d->props.rc_key_map_size; i++) {
-			if (rc5_custom(&keymap[i]) == key[3-2] &&
-			    rc5_data(&keymap[i]) == key[3-3]) {
-				st->rc_counter = 0;
-				*event = keymap[i].event;
-				*state = REMOTE_KEY_PRESSED;
-				d->last_event = keymap[i].event;
-				return 0;
-			}
-		}
-		break;
-	}
-	default: {
-		/* RC-5 protocol changes toggle bit on new keypress */
-		for (i = 0; i < d->props.rc_key_map_size; i++) {
-			if (rc5_custom(&keymap[i]) == key[3-2] &&
-			    rc5_data(&keymap[i]) == key[3-3]) {
-				if (d->last_event == keymap[i].event &&
-					key[3-1] == st->rc_toggle) {
-					st->rc_counter++;
-					/* prevents unwanted double hits */
-					if (st->rc_counter > RC_REPEAT_DELAY) {
-						*event = d->last_event;
-						*state = REMOTE_KEY_PRESSED;
-						st->rc_counter = RC_REPEAT_DELAY;
-					}
 
-					return 0;
-				}
-				st->rc_counter = 0;
-				*event = keymap[i].event;
-				*state = REMOTE_KEY_PRESSED;
-				st->rc_toggle = key[3-1];
-				d->last_event = keymap[i].event;
-				return 0;
-			}
-		}
+		ir_keydown(d->rc_input_dev, keycode, 0);
+		break;
+	default:
+		/* RC-5 protocol changes toggle bit on new keypress */
+		keycode = key[3-2] << 8 | key[3-3];
+		toggle = key[3-1];
+		ir_keydown(d->rc_input_dev, keycode, toggle);
+
 		break;
 	}
-	}
-	err("Unknown remote controller key: %2X %2X %2X %2X", (int) key[3-2], (int) key[3-3], (int) key[3-1], (int) key[3]);
-	d->last_event = 0;
 	return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_dib0700_table[] = {
-	/* Key codes for the tiny Pinnacle remote*/
-	{ 0x0700, KEY_MUTE },
-	{ 0x0701, KEY_MENU }, /* Pinnacle logo */
-	{ 0x0739, KEY_POWER },
-	{ 0x0703, KEY_VOLUMEUP },
-	{ 0x0709, KEY_VOLUMEDOWN },
-	{ 0x0706, KEY_CHANNELUP },
-	{ 0x070c, KEY_CHANNELDOWN },
-	{ 0x070f, KEY_1 },
-	{ 0x0715, KEY_2 },
-	{ 0x0710, KEY_3 },
-	{ 0x0718, KEY_4 },
-	{ 0x071b, KEY_5 },
-	{ 0x071e, KEY_6 },
-	{ 0x0711, KEY_7 },
-	{ 0x0721, KEY_8 },
-	{ 0x0712, KEY_9 },
-	{ 0x0727, KEY_0 },
-	{ 0x0724, KEY_SCREEN }, /* 'Square' key */
-	{ 0x072a, KEY_TEXT },   /* 'T' key */
-	{ 0x072d, KEY_REWIND },
-	{ 0x0730, KEY_PLAY },
-	{ 0x0733, KEY_FASTFORWARD },
-	{ 0x0736, KEY_RECORD },
-	{ 0x073c, KEY_STOP },
-	{ 0x073f, KEY_CANCEL }, /* '?' key */
-	/* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
-	{ 0xeb01, KEY_POWER },
-	{ 0xeb02, KEY_1 },
-	{ 0xeb03, KEY_2 },
-	{ 0xeb04, KEY_3 },
-	{ 0xeb05, KEY_4 },
-	{ 0xeb06, KEY_5 },
-	{ 0xeb07, KEY_6 },
-	{ 0xeb08, KEY_7 },
-	{ 0xeb09, KEY_8 },
-	{ 0xeb0a, KEY_9 },
-	{ 0xeb0b, KEY_VIDEO },
-	{ 0xeb0c, KEY_0 },
-	{ 0xeb0d, KEY_REFRESH },
-	{ 0xeb0f, KEY_EPG },
-	{ 0xeb10, KEY_UP },
-	{ 0xeb11, KEY_LEFT },
-	{ 0xeb12, KEY_OK },
-	{ 0xeb13, KEY_RIGHT },
-	{ 0xeb14, KEY_DOWN },
-	{ 0xeb16, KEY_INFO },
-	{ 0xeb17, KEY_RED },
-	{ 0xeb18, KEY_GREEN },
-	{ 0xeb19, KEY_YELLOW },
-	{ 0xeb1a, KEY_BLUE },
-	{ 0xeb1b, KEY_CHANNELUP },
-	{ 0xeb1c, KEY_VOLUMEUP },
-	{ 0xeb1d, KEY_MUTE },
-	{ 0xeb1e, KEY_VOLUMEDOWN },
-	{ 0xeb1f, KEY_CHANNELDOWN },
-	{ 0xeb40, KEY_PAUSE },
-	{ 0xeb41, KEY_HOME },
-	{ 0xeb42, KEY_MENU }, /* DVD Menu */
-	{ 0xeb43, KEY_SUBTITLE },
-	{ 0xeb44, KEY_TEXT }, /* Teletext */
-	{ 0xeb45, KEY_DELETE },
-	{ 0xeb46, KEY_TV },
-	{ 0xeb47, KEY_DVD },
-	{ 0xeb48, KEY_STOP },
-	{ 0xeb49, KEY_VIDEO },
-	{ 0xeb4a, KEY_AUDIO }, /* Music */
-	{ 0xeb4b, KEY_SCREEN }, /* Pic */
-	{ 0xeb4c, KEY_PLAY },
-	{ 0xeb4d, KEY_BACK },
-	{ 0xeb4e, KEY_REWIND },
-	{ 0xeb4f, KEY_FASTFORWARD },
-	{ 0xeb54, KEY_PREVIOUS },
-	{ 0xeb58, KEY_RECORD },
-	{ 0xeb5c, KEY_NEXT },
-
-	/* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
-	{ 0x1e00, KEY_0 },
-	{ 0x1e01, KEY_1 },
-	{ 0x1e02, KEY_2 },
-	{ 0x1e03, KEY_3 },
-	{ 0x1e04, KEY_4 },
-	{ 0x1e05, KEY_5 },
-	{ 0x1e06, KEY_6 },
-	{ 0x1e07, KEY_7 },
-	{ 0x1e08, KEY_8 },
-	{ 0x1e09, KEY_9 },
-	{ 0x1e0a, KEY_KPASTERISK },
-	{ 0x1e0b, KEY_RED },
-	{ 0x1e0c, KEY_RADIO },
-	{ 0x1e0d, KEY_MENU },
-	{ 0x1e0e, KEY_GRAVE }, /* # */
-	{ 0x1e0f, KEY_MUTE },
-	{ 0x1e10, KEY_VOLUMEUP },
-	{ 0x1e11, KEY_VOLUMEDOWN },
-	{ 0x1e12, KEY_CHANNEL },
-	{ 0x1e14, KEY_UP },
-	{ 0x1e15, KEY_DOWN },
-	{ 0x1e16, KEY_LEFT },
-	{ 0x1e17, KEY_RIGHT },
-	{ 0x1e18, KEY_VIDEO },
-	{ 0x1e19, KEY_AUDIO },
-	{ 0x1e1a, KEY_MEDIA },
-	{ 0x1e1b, KEY_EPG },
-	{ 0x1e1c, KEY_TV },
-	{ 0x1e1e, KEY_NEXT },
-	{ 0x1e1f, KEY_BACK },
-	{ 0x1e20, KEY_CHANNELUP },
-	{ 0x1e21, KEY_CHANNELDOWN },
-	{ 0x1e24, KEY_LAST }, /* Skip backwards */
-	{ 0x1e25, KEY_OK },
-	{ 0x1e29, KEY_BLUE},
-	{ 0x1e2e, KEY_GREEN },
-	{ 0x1e30, KEY_PAUSE },
-	{ 0x1e32, KEY_REWIND },
-	{ 0x1e34, KEY_FASTFORWARD },
-	{ 0x1e35, KEY_PLAY },
-	{ 0x1e36, KEY_STOP },
-	{ 0x1e37, KEY_RECORD },
-	{ 0x1e38, KEY_YELLOW },
-	{ 0x1e3b, KEY_GOTO },
-	{ 0x1e3d, KEY_POWER },
-
-	/* Key codes for the Leadtek Winfast DTV Dongle */
-	{ 0x0042, KEY_POWER },
-	{ 0x077c, KEY_TUNER },
-	{ 0x0f4e, KEY_PRINT }, /* PREVIEW */
-	{ 0x0840, KEY_SCREEN }, /* full screen toggle*/
-	{ 0x0f71, KEY_DOT }, /* frequency */
-	{ 0x0743, KEY_0 },
-	{ 0x0c41, KEY_1 },
-	{ 0x0443, KEY_2 },
-	{ 0x0b7f, KEY_3 },
-	{ 0x0e41, KEY_4 },
-	{ 0x0643, KEY_5 },
-	{ 0x097f, KEY_6 },
-	{ 0x0d7e, KEY_7 },
-	{ 0x057c, KEY_8 },
-	{ 0x0a40, KEY_9 },
-	{ 0x0e4e, KEY_CLEAR },
-	{ 0x047c, KEY_CHANNEL }, /* show channel number */
-	{ 0x0f41, KEY_LAST }, /* recall */
-	{ 0x0342, KEY_MUTE },
-	{ 0x064c, KEY_RESERVED }, /* PIP button*/
-	{ 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */
-	{ 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
-	{ 0x0b70, KEY_RECORD },
-	{ 0x037d, KEY_VOLUMEUP },
-	{ 0x017d, KEY_VOLUMEDOWN },
-	{ 0x0242, KEY_CHANNELUP },
-	{ 0x007d, KEY_CHANNELDOWN },
-
-	/* Key codes for Nova-TD "credit card" remote control. */
-	{ 0x1d00, KEY_0 },
-	{ 0x1d01, KEY_1 },
-	{ 0x1d02, KEY_2 },
-	{ 0x1d03, KEY_3 },
-	{ 0x1d04, KEY_4 },
-	{ 0x1d05, KEY_5 },
-	{ 0x1d06, KEY_6 },
-	{ 0x1d07, KEY_7 },
-	{ 0x1d08, KEY_8 },
-	{ 0x1d09, KEY_9 },
-	{ 0x1d0a, KEY_TEXT },
-	{ 0x1d0d, KEY_MENU },
-	{ 0x1d0f, KEY_MUTE },
-	{ 0x1d10, KEY_VOLUMEUP },
-	{ 0x1d11, KEY_VOLUMEDOWN },
-	{ 0x1d12, KEY_CHANNEL },
-	{ 0x1d14, KEY_UP },
-	{ 0x1d15, KEY_DOWN },
-	{ 0x1d16, KEY_LEFT },
-	{ 0x1d17, KEY_RIGHT },
-	{ 0x1d1c, KEY_TV },
-	{ 0x1d1e, KEY_NEXT },
-	{ 0x1d1f, KEY_BACK },
-	{ 0x1d20, KEY_CHANNELUP },
-	{ 0x1d21, KEY_CHANNELDOWN },
-	{ 0x1d24, KEY_LAST },
-	{ 0x1d25, KEY_OK },
-	{ 0x1d30, KEY_PAUSE },
-	{ 0x1d32, KEY_REWIND },
-	{ 0x1d34, KEY_FASTFORWARD },
-	{ 0x1d35, KEY_PLAY },
-	{ 0x1d36, KEY_STOP },
-	{ 0x1d37, KEY_RECORD },
-	{ 0x1d3b, KEY_GOTO },
-	{ 0x1d3d, KEY_POWER },
-
-	/* Key codes for the Pixelview SBTVD remote (proto NEC) */
-	{ 0x8613, KEY_MUTE },
-	{ 0x8612, KEY_POWER },
-	{ 0x8601, KEY_1 },
-	{ 0x8602, KEY_2 },
-	{ 0x8603, KEY_3 },
-	{ 0x8604, KEY_4 },
-	{ 0x8605, KEY_5 },
-	{ 0x8606, KEY_6 },
-	{ 0x8607, KEY_7 },
-	{ 0x8608, KEY_8 },
-	{ 0x8609, KEY_9 },
-	{ 0x8600, KEY_0 },
-	{ 0x860d, KEY_CHANNELUP },
-	{ 0x8619, KEY_CHANNELDOWN },
-	{ 0x8610, KEY_VOLUMEUP },
-	{ 0x860c, KEY_VOLUMEDOWN },
-
-	{ 0x860a, KEY_CAMERA },
-	{ 0x860b, KEY_ZOOM },
-	{ 0x861b, KEY_BACKSPACE },
-	{ 0x8615, KEY_ENTER },
-
-	{ 0x861d, KEY_UP },
-	{ 0x861e, KEY_DOWN },
-	{ 0x860e, KEY_LEFT },
-	{ 0x860f, KEY_RIGHT },
-
-	{ 0x8618, KEY_RECORD },
-	{ 0x861a, KEY_STOP },
-
-	/* Key codes for the EvolutePC TVWay+ remote (proto NEC) */
-	{ 0x7a00, KEY_MENU },
-	{ 0x7a01, KEY_RECORD },
-	{ 0x7a02, KEY_PLAY },
-	{ 0x7a03, KEY_STOP },
-	{ 0x7a10, KEY_CHANNELUP },
-	{ 0x7a11, KEY_CHANNELDOWN },
-	{ 0x7a12, KEY_VOLUMEUP },
-	{ 0x7a13, KEY_VOLUMEDOWN },
-	{ 0x7a40, KEY_POWER },
-	{ 0x7a41, KEY_MUTE },
-
-	/* Key codes for the Elgato EyeTV Diversity silver remote,
-	   set dvb_usb_dib0700_ir_proto=0 */
-	{ 0x4501, KEY_POWER },
-	{ 0x4502, KEY_MUTE },
-	{ 0x4503, KEY_1 },
-	{ 0x4504, KEY_2 },
-	{ 0x4505, KEY_3 },
-	{ 0x4506, KEY_4 },
-	{ 0x4507, KEY_5 },
-	{ 0x4508, KEY_6 },
-	{ 0x4509, KEY_7 },
-	{ 0x450a, KEY_8 },
-	{ 0x450b, KEY_9 },
-	{ 0x450c, KEY_LAST },
-	{ 0x450d, KEY_0 },
-	{ 0x450e, KEY_ENTER },
-	{ 0x450f, KEY_RED },
-	{ 0x4510, KEY_CHANNELUP },
-	{ 0x4511, KEY_GREEN },
-	{ 0x4512, KEY_VOLUMEDOWN },
-	{ 0x4513, KEY_OK },
-	{ 0x4514, KEY_VOLUMEUP },
-	{ 0x4515, KEY_YELLOW },
-	{ 0x4516, KEY_CHANNELDOWN },
-	{ 0x4517, KEY_BLUE },
-	{ 0x4518, KEY_LEFT }, /* Skip backwards */
-	{ 0x4519, KEY_PLAYPAUSE },
-	{ 0x451a, KEY_RIGHT }, /* Skip forward */
-	{ 0x451b, KEY_REWIND },
-	{ 0x451c, KEY_L }, /* Live */
-	{ 0x451d, KEY_FASTFORWARD },
-	{ 0x451e, KEY_STOP }, /* 'Reveal' for Teletext */
-	{ 0x451f, KEY_MENU }, /* KEY_TEXT for Teletext */
-	{ 0x4540, KEY_RECORD }, /* Font 'Size' for Teletext */
-	{ 0x4541, KEY_SCREEN }, /*  Full screen toggle, 'Hold' for Teletext */
-	{ 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */
-};
-
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
 static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
 	BAND_UHF | BAND_VHF,
@@ -2168,10 +1868,17 @@
 			}
 		},
 
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = ir_codes_dib0700_table,
-		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-		.rc_query         = dib0700_rc_query
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
 		.num_adapters = 2,
@@ -2197,10 +1904,17 @@
 			},
 		},
 
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = ir_codes_dib0700_table,
-		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-		.rc_query         = dib0700_rc_query
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
 		.num_adapters = 2,
@@ -2251,11 +1965,17 @@
 
 		},
 
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = ir_codes_dib0700_table,
-		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-		.rc_query         = dib0700_rc_query
-
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
 		.num_adapters = 1,
@@ -2288,10 +2008,18 @@
 			}
 		},
 
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = ir_codes_dib0700_table,
-		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-		.rc_query         = dib0700_rc_query
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
 		.num_adapters = 1,
@@ -2358,11 +2086,18 @@
 			},
 		},
 
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = ir_codes_dib0700_table,
-		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-		.rc_query         = dib0700_rc_query
-
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
 		.num_adapters = 1,
@@ -2397,11 +2132,18 @@
 			},
 		},
 
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = ir_codes_dib0700_table,
-		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-		.rc_query         = dib0700_rc_query
-
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
 		.num_adapters = 2,
@@ -2431,7 +2173,7 @@
 			}
 		},
 
-		.num_device_descs = 7,
+		.num_device_descs = 6,
 		.devices = {
 			{   "DiBcom STK7070PD reference design",
 				{ &dib0700_usb_id_table[17], NULL },
@@ -2458,15 +2200,69 @@
 				{ &dib0700_usb_id_table[44], NULL },
 				{ NULL },
 			},
+		},
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 2,
+		.adapter = {
+			{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = stk7070pd_frontend_attach0,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			}, {
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+				.pid_filter_count = 32,
+				.pid_filter       = stk70x0p_pid_filter,
+				.pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+				.frontend_attach  = stk7070pd_frontend_attach1,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			}
+		},
+
+		.num_device_descs = 1,
+		.devices = {
 			{   "Elgato EyeTV Diversity",
 				{ &dib0700_usb_id_table[68], NULL },
 				{ NULL },
 			},
 		},
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = ir_codes_dib0700_table,
-		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-		.rc_query         = dib0700_rc_query
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_NEC_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
 		.num_adapters = 1,
@@ -2525,10 +2321,19 @@
 				{ NULL },
 			},
 		},
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = ir_codes_dib0700_table,
-		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-		.rc_query         = dib0700_rc_query
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 		.num_adapters = 1,
 		.adapter = {
@@ -2554,10 +2359,19 @@
 				{ NULL },
 			},
 		},
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = ir_codes_dib0700_table,
-		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-		.rc_query         = dib0700_rc_query
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 		.num_adapters = 1,
 		.adapter = {
@@ -2615,10 +2429,19 @@
 				{ NULL },
 			},
 		},
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = ir_codes_dib0700_table,
-		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-		.rc_query         = dib0700_rc_query
+
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 		.num_adapters = 1,
 		.adapter = {
@@ -2653,11 +2476,18 @@
 			},
 		},
 
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = ir_codes_dib0700_table,
-		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-		.rc_query         = dib0700_rc_query
-
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_NEC_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 		.num_adapters = 2,
 		.adapter = {
@@ -2697,10 +2527,18 @@
 			},
 		},
 
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = ir_codes_dib0700_table,
-		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-		.rc_query         = dib0700_rc_query
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 		.num_adapters = 1,
 		.adapter = {
@@ -2728,10 +2566,18 @@
 			},
 		},
 
-		.rc_interval      = DEFAULT_RC_INTERVAL,
-		.rc_key_map       = ir_codes_dib0700_table,
-		.rc_key_map_size  = ARRAY_SIZE(ir_codes_dib0700_table),
-		.rc_query         = dib0700_rc_query
+		.rc.core = {
+			.rc_interval      = DEFAULT_RC_INTERVAL,
+			.rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+			.module_name	  = "dib0700",
+			.rc_query         = dib0700_rc_query_old_firmware,
+			.rc_props = {
+				.allowed_protos = IR_TYPE_RC5 |
+						  IR_TYPE_RC6 |
+						  IR_TYPE_NEC,
+				.change_protocol = dib0700_change_protocol,
+			},
+		},
 	},
 };
 
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index bc08bc0..ba991aa 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -327,7 +327,7 @@
 /*
  * common remote control stuff
  */
-struct dvb_usb_rc_key ir_codes_dibusb_table[] = {
+struct ir_scancode ir_codes_dibusb_table[] = {
 	/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
 	{ 0x0016, KEY_POWER },
 	{ 0x0010, KEY_MUTE },
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index eb2e6f0..8e3c0d2 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -211,10 +211,12 @@
 
 	.power_ctrl       = dibusb_power_ctrl,
 
-	.rc_interval      = DEFAULT_RC_INTERVAL,
-	.rc_key_map       = ir_codes_dibusb_table,
-	.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
-	.rc_query         = dibusb_rc_query,
+	.rc.legacy = {
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = ir_codes_dibusb_table,
+		.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+		.rc_query         = dibusb_rc_query,
+	},
 
 	.i2c_algo         = &dibusb_i2c_algo,
 
@@ -295,10 +297,12 @@
 	},
 	.power_ctrl       = dibusb_power_ctrl,
 
-	.rc_interval      = DEFAULT_RC_INTERVAL,
-	.rc_key_map       = ir_codes_dibusb_table,
-	.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
-	.rc_query         = dibusb_rc_query,
+	.rc.legacy = {
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = ir_codes_dibusb_table,
+		.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+		.rc_query         = dibusb_rc_query,
+	},
 
 	.i2c_algo         = &dibusb_i2c_algo,
 
@@ -359,10 +363,12 @@
 	},
 	.power_ctrl       = dibusb2_0_power_ctrl,
 
-	.rc_interval      = DEFAULT_RC_INTERVAL,
-	.rc_key_map       = ir_codes_dibusb_table,
-	.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
-	.rc_query         = dibusb_rc_query,
+	.rc.legacy = {
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = ir_codes_dibusb_table,
+		.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+		.rc_query         = dibusb_rc_query,
+	},
 
 	.i2c_algo         = &dibusb_i2c_algo,
 
@@ -416,10 +422,12 @@
 	},
 	.power_ctrl       = dibusb2_0_power_ctrl,
 
-	.rc_interval      = DEFAULT_RC_INTERVAL,
-	.rc_key_map       = ir_codes_dibusb_table,
-	.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
-	.rc_query         = dibusb_rc_query,
+	.rc.legacy = {
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = ir_codes_dibusb_table,
+		.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+		.rc_query         = dibusb_rc_query,
+	},
 
 	.i2c_algo         = &dibusb_i2c_algo,
 
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
index 588308e..1cbc41c 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c
@@ -81,10 +81,12 @@
 	},
 	.power_ctrl       = dibusb2_0_power_ctrl,
 
-	.rc_interval      = DEFAULT_RC_INTERVAL,
-	.rc_key_map       = ir_codes_dibusb_table,
-	.rc_key_map_size  = 111, /* FIXME */
-	.rc_query         = dibusb_rc_query,
+	.rc.legacy = {
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = ir_codes_dibusb_table,
+		.rc_key_map_size  = 111, /* FIXME */
+		.rc_query         = dibusb_rc_query,
+	},
 
 	.i2c_algo         = &dibusb_i2c_algo,
 
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
index 3d50ac5..61a6bf3 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -124,7 +124,7 @@
 #define DEFAULT_RC_INTERVAL 150
 //#define DEFAULT_RC_INTERVAL 100000
 
-extern struct dvb_usb_rc_key ir_codes_dibusb_table[];
+extern struct ir_scancode ir_codes_dibusb_table[];
 extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *);
 extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *);
 
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index e826077..13d006b 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -161,7 +161,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_digitv_table[] = {
+static struct ir_scancode ir_codes_digitv_table[] = {
 	{ 0x5f55, KEY_0 },
 	{ 0x6f55, KEY_1 },
 	{ 0x9f55, KEY_2 },
@@ -237,10 +237,10 @@
 	/* if something is inside the buffer, simulate key press */
 	if (key[1] != 0)
 	{
-		  for (i = 0; i < d->props.rc_key_map_size; i++) {
-			if (rc5_custom(&d->props.rc_key_map[i]) == key[1] &&
-			    rc5_data(&d->props.rc_key_map[i]) == key[2]) {
-				*event = d->props.rc_key_map[i].event;
+		  for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
+			if (rc5_custom(&d->props.rc.legacy.rc_key_map[i]) == key[1] &&
+			    rc5_data(&d->props.rc.legacy.rc_key_map[i]) == key[2]) {
+				*event = d->props.rc.legacy.rc_key_map[i].keycode;
 				*state = REMOTE_KEY_PRESSED;
 				return 0;
 			}
@@ -310,10 +310,12 @@
 	},
 	.identify_state   = digitv_identify_state,
 
-	.rc_interval      = 1000,
-	.rc_key_map       = ir_codes_digitv_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_digitv_table),
-	.rc_query         = digitv_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 1000,
+		.rc_key_map       = ir_codes_digitv_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_digitv_table),
+		.rc_query         = digitv_rc_query,
+	},
 
 	.i2c_algo         = &digitv_i2c_algo,
 
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index f57e590..ca495e0 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -57,7 +57,7 @@
 
 /* remote control */
 /* key list for the tiny remote control (Yakumo, don't know about the others) */
-static struct dvb_usb_rc_key ir_codes_dtt200u_table[] = {
+static struct ir_scancode ir_codes_dtt200u_table[] = {
 	{ 0x8001, KEY_MUTE },
 	{ 0x8002, KEY_CHANNELDOWN },
 	{ 0x8003, KEY_VOLUMEDOWN },
@@ -161,10 +161,12 @@
 	},
 	.power_ctrl      = dtt200u_power_ctrl,
 
-	.rc_interval     = 300,
-	.rc_key_map      = ir_codes_dtt200u_table,
-	.rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
-	.rc_query        = dtt200u_rc_query,
+	.rc.legacy = {
+		.rc_interval     = 300,
+		.rc_key_map      = ir_codes_dtt200u_table,
+		.rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+		.rc_query        = dtt200u_rc_query,
+	},
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
@@ -206,10 +208,12 @@
 	},
 	.power_ctrl      = dtt200u_power_ctrl,
 
-	.rc_interval     = 300,
-	.rc_key_map      = ir_codes_dtt200u_table,
-	.rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
-	.rc_query        = dtt200u_rc_query,
+	.rc.legacy = {
+		.rc_interval     = 300,
+		.rc_key_map      = ir_codes_dtt200u_table,
+		.rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+		.rc_query        = dtt200u_rc_query,
+	},
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
@@ -251,10 +255,12 @@
 	},
 	.power_ctrl      = dtt200u_power_ctrl,
 
-	.rc_interval     = 300,
-	.rc_key_map      = ir_codes_dtt200u_table,
-	.rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
-	.rc_query        = dtt200u_rc_query,
+	.rc.legacy = {
+		.rc_interval     = 300,
+		.rc_key_map      = ir_codes_dtt200u_table,
+		.rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+		.rc_query        = dtt200u_rc_query,
+	},
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
@@ -296,10 +302,12 @@
 	},
 	.power_ctrl      = dtt200u_power_ctrl,
 
-	.rc_interval     = 300,
-	.rc_key_map      = ir_codes_dtt200u_table,
-	.rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
-	.rc_query        = dtt200u_rc_query,
+	.rc.legacy = {
+		.rc_interval     = 300,
+		.rc_key_map      = ir_codes_dtt200u_table,
+		.rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+		.rc_query        = dtt200u_rc_query,
+	},
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index b4afe6f..1a774d5 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -197,6 +197,7 @@
 #define USB_PID_AVERMEDIA_A310				0xa310
 #define USB_PID_AVERMEDIA_A850				0x850a
 #define USB_PID_AVERMEDIA_A805				0xa805
+#define USB_PID_AVERMEDIA_A815M				0x815a
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TECHNOTREND_CONNECT_CT3650		0x300d
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index 5d91f70..2e3ea0f 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -15,7 +15,7 @@
 
 /* debug */
 int dvb_usb_debug;
-module_param_named(debug,dvb_usb_debug, int, 0644);
+module_param_named(debug, dvb_usb_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256  (or-able))." DVB_USB_DEBUG_STATUS);
 
 int dvb_usb_disable_rc_polling;
@@ -29,7 +29,7 @@
 static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
 {
 	struct dvb_usb_adapter *adap;
-	int ret,n;
+	int ret, n;
 
 	for (n = 0; n < d->props.num_adapters; n++) {
 		adap = &d->adapter[n];
@@ -38,7 +38,7 @@
 
 		memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
 
-/* speed - when running at FULL speed we need a HW PID filter */
+		/* speed - when running at FULL speed we need a HW PID filter */
 		if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
 			err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
 			return -ENODEV;
@@ -46,7 +46,7 @@
 
 		if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
 			(adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
-			info("will use the device's hardware PID filter (table count: %d).",adap->props.pid_filter_count);
+			info("will use the device's hardware PID filter (table count: %d).", adap->props.pid_filter_count);
 			adap->pid_filtering  = 1;
 			adap->max_feed_count = adap->props.pid_filter_count;
 		} else {
@@ -64,9 +64,9 @@
 		}
 
 		if (adap->props.size_of_priv > 0) {
-			adap->priv = kzalloc(adap->props.size_of_priv,GFP_KERNEL);
+			adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL);
 			if (adap->priv == NULL) {
-				err("no memory for priv for adapter %d.",n);
+				err("no memory for priv for adapter %d.", n);
 				return -ENOMEM;
 			}
 		}
@@ -86,8 +86,8 @@
 	 * sometimes a timeout occures, this helps
 	 */
 	if (d->props.generic_bulk_ctrl_endpoint != 0) {
-		usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
-		usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
+		usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+		usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
 	}
 
 	return 0;
@@ -96,6 +96,7 @@
 static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
 {
 	int n;
+
 	for (n = 0; n < d->num_adapters_initialized; n++) {
 		dvb_usb_adapter_frontend_exit(&d->adapter[n]);
 		dvb_usb_adapter_dvb_exit(&d->adapter[n]);
@@ -111,11 +112,11 @@
 /* general initialization functions */
 static int dvb_usb_exit(struct dvb_usb_device *d)
 {
-	deb_info("state before exiting everything: %x\n",d->state);
+	deb_info("state before exiting everything: %x\n", d->state);
 	dvb_usb_remote_exit(d);
 	dvb_usb_adapter_exit(d);
 	dvb_usb_i2c_exit(d);
-	deb_info("state should be zero now: %x\n",d->state);
+	deb_info("state should be zero now: %x\n", d->state);
 	d->state = DVB_USB_STATE_INIT;
 	kfree(d->priv);
 	kfree(d);
@@ -132,14 +133,14 @@
 	d->state = DVB_USB_STATE_INIT;
 
 	if (d->props.size_of_priv > 0) {
-		d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL);
+		d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL);
 		if (d->priv == NULL) {
 			err("no memory for priv in 'struct dvb_usb_device'");
 			return -ENOMEM;
 		}
 	}
 
-/* check the capabilities and set appropriate variables */
+	/* check the capabilities and set appropriate variables */
 	dvb_usb_device_power_ctrl(d, 1);
 
 	if ((ret = dvb_usb_i2c_init(d)) ||
@@ -157,16 +158,17 @@
 }
 
 /* determine the name and the state of the just found USB device */
-static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_device_properties *props, int *cold)
+static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold)
 {
-	int i,j;
+	int i, j;
 	struct dvb_usb_device_description *desc = NULL;
+
 	*cold = -1;
 
 	for (i = 0; i < props->num_device_descs; i++) {
 
 		for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) {
-			deb_info("check for cold %x %x\n",props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
+			deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
 			if (props->devices[i].cold_ids[j]->idVendor  == le16_to_cpu(udev->descriptor.idVendor) &&
 				props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
 				*cold = 1;
@@ -179,7 +181,7 @@
 			break;
 
 		for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) {
-			deb_info("check for warm %x %x\n",props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
+			deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
 			if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
 				props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
 				*cold = 0;
@@ -190,7 +192,7 @@
 	}
 
 	if (desc != NULL && props->identify_state != NULL)
-		props->identify_state(udev,props,&desc,cold);
+		props->identify_state(udev, props, &desc, cold);
 
 	return desc;
 }
@@ -202,7 +204,7 @@
 	else
 		d->powered--;
 
-	if (d->powered == 0 || (onoff && d->powered == 1)) { // when switching from 1 to 0 or from 0 to 1
+	if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */
 		deb_info("power control: %d\n", onoff);
 		if (d->props.power_ctrl)
 			return d->props.power_ctrl(d, onoff);
@@ -222,32 +224,32 @@
 	struct dvb_usb_device *d = NULL;
 	struct dvb_usb_device_description *desc = NULL;
 
-	int ret = -ENOMEM,cold=0;
+	int ret = -ENOMEM, cold = 0;
 
 	if (du != NULL)
 		*du = NULL;
 
-	if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
+	if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) {
 		deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
 		return -ENODEV;
 	}
 
 	if (cold) {
-		info("found a '%s' in cold state, will try to load a firmware",desc->name);
-		ret = dvb_usb_download_firmware(udev,props);
+		info("found a '%s' in cold state, will try to load a firmware", desc->name);
+		ret = dvb_usb_download_firmware(udev, props);
 		if (!props->no_reconnect || ret != 0)
 			return ret;
 	}
 
-	info("found a '%s' in warm state.",desc->name);
-		d = kzalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
+	info("found a '%s' in warm state.", desc->name);
+	d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
 	if (d == NULL) {
 		err("no memory for 'struct dvb_usb_device'");
 		return -ENOMEM;
 	}
 
 	d->udev = udev;
-	memcpy(&d->props,props,sizeof(struct dvb_usb_device_properties));
+	memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties));
 	d->desc = desc;
 	d->owner = owner;
 
@@ -259,9 +261,9 @@
 	ret = dvb_usb_init(d, adapter_nums);
 
 	if (ret == 0)
-		info("%s successfully initialized and connected.",desc->name);
+		info("%s successfully initialized and connected.", desc->name);
 	else
-		info("%s error while loading driver (%d)",desc->name,ret);
+		info("%s error while loading driver (%d)", desc->name, ret);
 	return ret;
 }
 EXPORT_SYMBOL(dvb_usb_device_init);
@@ -271,12 +273,12 @@
 	struct dvb_usb_device *d = usb_get_intfdata(intf);
 	const char *name = "generic DVB-USB module";
 
-	usb_set_intfdata(intf,NULL);
+	usb_set_intfdata(intf, NULL);
 	if (d != NULL && d->desc != NULL) {
 		name = d->desc->name;
 		dvb_usb_exit(d);
 	}
-	info("%s successfully deinitialized and disconnected.",name);
+	info("%s successfully deinitialized and disconnected.", name);
 
 }
 EXPORT_SYMBOL(dvb_usb_device_exit);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 852fe89..b579fed 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -8,29 +8,29 @@
 #include "dvb-usb-common.h"
 #include <linux/usb/input.h>
 
-static int dvb_usb_getkeycode(struct input_dev *dev,
+static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
 				unsigned int scancode, unsigned int *keycode)
 {
 	struct dvb_usb_device *d = input_get_drvdata(dev);
 
-	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
 	int i;
 
 	/* See if we can match the raw key code. */
-	for (i = 0; i < d->props.rc_key_map_size; i++)
-		if (keymap[i].scan == scancode) {
-			*keycode = keymap[i].event;
+	for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+		if (keymap[i].scancode == scancode) {
+			*keycode = keymap[i].keycode;
 			return 0;
 		}
 
 	/*
 	 * If is there extra space, returns KEY_RESERVED,
-	 * otherwise, input core won't let dvb_usb_setkeycode
+	 * otherwise, input core won't let legacy_dvb_usb_setkeycode
 	 * to work
 	 */
-	for (i = 0; i < d->props.rc_key_map_size; i++)
-		if (keymap[i].event == KEY_RESERVED ||
-		    keymap[i].event == KEY_UNKNOWN) {
+	for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+		if (keymap[i].keycode == KEY_RESERVED ||
+		    keymap[i].keycode == KEY_UNKNOWN) {
 			*keycode = KEY_RESERVED;
 			return 0;
 		}
@@ -38,27 +38,27 @@
 	return -EINVAL;
 }
 
-static int dvb_usb_setkeycode(struct input_dev *dev,
+static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
 				unsigned int scancode, unsigned int keycode)
 {
 	struct dvb_usb_device *d = input_get_drvdata(dev);
 
-	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
 	int i;
 
 	/* Search if it is replacing an existing keycode */
-	for (i = 0; i < d->props.rc_key_map_size; i++)
-		if (keymap[i].scan == scancode) {
-			keymap[i].event = keycode;
+	for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+		if (keymap[i].scancode == scancode) {
+			keymap[i].keycode = keycode;
 			return 0;
 		}
 
 	/* Search if is there a clean entry. If so, use it */
-	for (i = 0; i < d->props.rc_key_map_size; i++)
-		if (keymap[i].event == KEY_RESERVED ||
-		    keymap[i].event == KEY_UNKNOWN) {
-			keymap[i].scan = scancode;
-			keymap[i].event = keycode;
+	for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+		if (keymap[i].keycode == KEY_RESERVED ||
+		    keymap[i].keycode == KEY_UNKNOWN) {
+			keymap[i].scancode = scancode;
+			keymap[i].keycode = keycode;
 			return 0;
 		}
 
@@ -78,7 +78,7 @@
  *
  * TODO: Fix the repeat rate of the input device.
  */
-static void dvb_usb_read_remote_control(struct work_struct *work)
+static void legacy_dvb_usb_read_remote_control(struct work_struct *work)
 {
 	struct dvb_usb_device *d =
 		container_of(work, struct dvb_usb_device, rc_query_work.work);
@@ -92,7 +92,7 @@
 	if (dvb_usb_disable_rc_polling)
 		return;
 
-	if (d->props.rc_query(d,&event,&state)) {
+	if (d->props.rc.legacy.rc_query(d,&event,&state)) {
 		err("error while querying for an remote control event.");
 		goto schedule;
 	}
@@ -151,18 +151,117 @@
 */
 
 schedule:
-	schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
+	schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval));
+}
+
+static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d,
+				      struct input_dev *input_dev)
+{
+	int i, err, rc_interval;
+
+	input_dev->getkeycode = legacy_dvb_usb_getkeycode;
+	input_dev->setkeycode = legacy_dvb_usb_setkeycode;
+
+	/* set the bits for the keys */
+	deb_rc("key map size: %d\n", d->props.rc.legacy.rc_key_map_size);
+	for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
+		deb_rc("setting bit for event %d item %d\n",
+			d->props.rc.legacy.rc_key_map[i].keycode, i);
+		set_bit(d->props.rc.legacy.rc_key_map[i].keycode, input_dev->keybit);
+	}
+
+	/* setting these two values to non-zero, we have to manage key repeats */
+	input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval;
+	input_dev->rep[REP_DELAY]  = d->props.rc.legacy.rc_interval + 150;
+
+	input_set_drvdata(input_dev, d);
+
+	err = input_register_device(input_dev);
+	if (err)
+		input_free_device(input_dev);
+
+	rc_interval = d->props.rc.legacy.rc_interval;
+
+	INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control);
+
+	info("schedule remote query interval to %d msecs.", rc_interval);
+	schedule_delayed_work(&d->rc_query_work,
+			      msecs_to_jiffies(rc_interval));
+
+	d->state |= DVB_USB_STATE_REMOTE;
+
+	return err;
+}
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+ *
+ * TODO: Fix the repeat rate of the input device.
+ */
+static void dvb_usb_read_remote_control(struct work_struct *work)
+{
+	struct dvb_usb_device *d =
+		container_of(work, struct dvb_usb_device, rc_query_work.work);
+	int err;
+
+	/* TODO: need a lock here.  We can simply skip checking for the remote control
+	   if we're busy. */
+
+	/* when the parameter has been set to 1 via sysfs while the
+	 * driver was running, or when bulk mode is enabled after IR init
+	 */
+	if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode)
+		return;
+
+	err = d->props.rc.core.rc_query(d);
+	if (err)
+		err("error %d while querying for an remote control event.", err);
+
+	schedule_delayed_work(&d->rc_query_work,
+			      msecs_to_jiffies(d->props.rc.core.rc_interval));
+}
+
+static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d,
+				       struct input_dev *input_dev)
+{
+	int err, rc_interval;
+
+	d->props.rc.core.rc_props.priv = d;
+	err = ir_input_register(input_dev,
+				 d->props.rc.core.rc_codes,
+				 &d->props.rc.core.rc_props,
+				 d->props.rc.core.module_name);
+	if (err < 0)
+		return err;
+
+	if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode)
+		return 0;
+
+	/* Polling mode - initialize a work queue for handling it */
+	INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
+
+	rc_interval = d->props.rc.core.rc_interval;
+
+	info("schedule remote query interval to %d msecs.", rc_interval);
+	schedule_delayed_work(&d->rc_query_work,
+			      msecs_to_jiffies(rc_interval));
+
+	return 0;
 }
 
 int dvb_usb_remote_init(struct dvb_usb_device *d)
 {
 	struct input_dev *input_dev;
-	int i;
 	int err;
 
-	if (d->props.rc_key_map == NULL ||
-		d->props.rc_query == NULL ||
-		dvb_usb_disable_rc_polling)
+	if (dvb_usb_disable_rc_polling)
+		return 0;
+
+	if (d->props.rc.legacy.rc_key_map && d->props.rc.legacy.rc_query)
+		d->props.rc.mode = DVB_RC_LEGACY;
+	else if (d->props.rc.core.rc_codes)
+		d->props.rc.mode = DVB_RC_CORE;
+	else
 		return 0;
 
 	usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
@@ -177,39 +276,19 @@
 	input_dev->phys = d->rc_phys;
 	usb_to_input_id(d->udev, &input_dev->id);
 	input_dev->dev.parent = &d->udev->dev;
-	input_dev->getkeycode = dvb_usb_getkeycode;
-	input_dev->setkeycode = dvb_usb_setkeycode;
-
-	/* set the bits for the keys */
-	deb_rc("key map size: %d\n", d->props.rc_key_map_size);
-	for (i = 0; i < d->props.rc_key_map_size; i++) {
-		deb_rc("setting bit for event %d item %d\n",
-			d->props.rc_key_map[i].event, i);
-		set_bit(d->props.rc_key_map[i].event, input_dev->keybit);
-	}
 
 	/* Start the remote-control polling. */
-	if (d->props.rc_interval < 40)
-		d->props.rc_interval = 100; /* default */
-
-	/* setting these two values to non-zero, we have to manage key repeats */
-	input_dev->rep[REP_PERIOD] = d->props.rc_interval;
-	input_dev->rep[REP_DELAY]  = d->props.rc_interval + 150;
-
-	input_set_drvdata(input_dev, d);
-
-	err = input_register_device(input_dev);
-	if (err) {
-		input_free_device(input_dev);
-		return err;
-	}
+	if (d->props.rc.legacy.rc_interval < 40)
+		d->props.rc.legacy.rc_interval = 100; /* default */
 
 	d->rc_input_dev = input_dev;
 
-	INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
-
-	info("schedule remote query interval to %d msecs.", d->props.rc_interval);
-	schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
+	if (d->props.rc.mode == DVB_RC_LEGACY)
+		err = legacy_dvb_usb_remote_init(d, input_dev);
+	else
+		err = rc_core_dvb_usb_remote_init(d, input_dev);
+	if (err)
+		return err;
 
 	d->state |= DVB_USB_STATE_REMOTE;
 
@@ -221,7 +300,10 @@
 	if (d->state & DVB_USB_STATE_REMOTE) {
 		cancel_rearming_delayed_work(&d->rc_query_work);
 		flush_scheduled_work();
-		input_unregister_device(d->rc_input_dev);
+		if (d->props.rc.mode == DVB_RC_LEGACY)
+			input_unregister_device(d->rc_input_dev);
+		else
+			ir_input_unregister(d->rc_input_dev);
 	}
 	d->state &= ~DVB_USB_STATE_REMOTE;
 	return 0;
@@ -234,7 +316,7 @@
 		u8 keybuf[5], u32 *event, int *state)
 {
 	int i;
-	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
 	*event = 0;
 	*state = REMOTE_NO_KEY_PRESSED;
 	switch (keybuf[0]) {
@@ -247,10 +329,10 @@
 				break;
 			}
 			/* See if we can match the raw key code. */
-			for (i = 0; i < d->props.rc_key_map_size; i++)
+			for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
 				if (rc5_custom(&keymap[i]) == keybuf[1] &&
 					rc5_data(&keymap[i]) == keybuf[3]) {
-					*event = keymap[i].event;
+					*event = keymap[i].keycode;
 					*state = REMOTE_KEY_PRESSED;
 					return 0;
 				}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index 4a9f676..34f7b3b 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -14,6 +14,7 @@
 #include <linux/usb.h>
 #include <linux/firmware.h>
 #include <linux/mutex.h>
+#include <media/ir-core.h>
 
 #include "dvb_frontend.h"
 #include "dvb_demux.h"
@@ -74,30 +75,19 @@
 	struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
 };
 
-/**
- * struct dvb_usb_rc_key - a remote control key and its input-event
- * @custom: the vendor/custom part of the key
- * @data: the actual key part
- * @event: the input event assigned to key identified by custom and data
- */
-struct dvb_usb_rc_key {
-	u16 scan;
-	u32 event;
-};
-
-static inline u8 rc5_custom(struct dvb_usb_rc_key *key)
+static inline u8 rc5_custom(struct ir_scancode *key)
 {
-	return (key->scan >> 8) & 0xff;
+	return (key->scancode >> 8) & 0xff;
 }
 
-static inline u8 rc5_data(struct dvb_usb_rc_key *key)
+static inline u8 rc5_data(struct ir_scancode *key)
 {
-	return key->scan & 0xff;
+	return key->scancode & 0xff;
 }
 
-static inline u8 rc5_scan(struct dvb_usb_rc_key *key)
+static inline u8 rc5_scan(struct ir_scancode *key)
 {
-	return key->scan & 0xffff;
+	return key->scancode & 0xffff;
 }
 
 struct dvb_usb_device;
@@ -168,6 +158,55 @@
 };
 
 /**
+ * struct dvb_rc_legacy - old properties of remote controller
+ * @rc_key_map: a hard-wired array of struct ir_scancode (NULL to disable
+ *  remote control handling).
+ * @rc_key_map_size: number of items in @rc_key_map.
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ */
+struct dvb_rc_legacy {
+/* remote control properties */
+#define REMOTE_NO_KEY_PRESSED      0x00
+#define REMOTE_KEY_PRESSED         0x01
+#define REMOTE_KEY_REPEAT          0x02
+	struct ir_scancode  *rc_key_map;
+	int rc_key_map_size;
+	int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
+	int rc_interval;
+};
+
+/**
+ * struct dvb_rc properties of remote controller, using rc-core
+ * @rc_codes: name of rc codes table
+ * @protocol: type of protocol(s) currently used by the driver
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ * @rc_props: remote controller properties
+ * @bulk_mode: device supports bulk mode for RC (disable polling mode)
+ */
+struct dvb_rc {
+	char *rc_codes;
+	u64 protocol;
+	char *module_name;
+	int (*rc_query) (struct dvb_usb_device *d);
+	int rc_interval;
+	struct ir_dev_props rc_props;
+	bool bulk_mode;				/* uses bulk mode */
+};
+
+/**
+ * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one
+ *		       based on rc-core
+ * This is initialized/used only inside dvb-usb-remote.c.
+ * It shouldn't be set by the drivers.
+ */
+enum dvb_usb_mode {
+	DVB_RC_LEGACY,
+	DVB_RC_CORE,
+};
+
+/**
  * struct dvb_usb_device_properties - properties of a dvb-usb-device
  * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
  *  download.
@@ -185,11 +224,7 @@
  * @identify_state: called to determine the state (cold or warm), when it
  *  is not distinguishable by the USB IDs.
  *
- * @rc_key_map: a hard-wired array of struct dvb_usb_rc_key (NULL to disable
- *  remote control handling).
- * @rc_key_map_size: number of items in @rc_key_map.
- * @rc_query: called to query an event event.
- * @rc_interval: time in ms between two queries.
+ * @rc: remote controller properties
  *
  * @i2c_algo: i2c_algorithm if the device has I2CoverUSB.
  *
@@ -233,14 +268,11 @@
 	int (*identify_state)   (struct usb_device *, struct dvb_usb_device_properties *,
 			struct dvb_usb_device_description **, int *);
 
-/* remote control properties */
-#define REMOTE_NO_KEY_PRESSED      0x00
-#define REMOTE_KEY_PRESSED         0x01
-#define REMOTE_KEY_REPEAT          0x02
-	struct dvb_usb_rc_key  *rc_key_map;
-	int rc_key_map_size;
-	int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
-	int rc_interval;
+	struct {
+		enum dvb_usb_mode mode;	/* Drivers shouldn't touch on it */
+		struct dvb_rc_legacy legacy;
+		struct dvb_rc core;
+	} rc;
 
 	struct i2c_algorithm *i2c_algo;
 
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index e8fb853..774df88 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -74,7 +74,7 @@
 		"on firmware-problems."
 
 struct ir_codes_dvb_usb_table_table {
-	struct dvb_usb_rc_key *rc_keys;
+	struct ir_scancode *rc_keys;
 	int rc_keys_size;
 };
 
@@ -948,7 +948,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_dw210x_table[] = {
+static struct ir_scancode ir_codes_dw210x_table[] = {
 	{ 0xf80a, KEY_Q },		/*power*/
 	{ 0xf80c, KEY_M },		/*mute*/
 	{ 0xf811, KEY_1 },
@@ -982,7 +982,7 @@
 	{ 0xf81b, KEY_B },		/*recall*/
 };
 
-static struct dvb_usb_rc_key ir_codes_tevii_table[] = {
+static struct ir_scancode ir_codes_tevii_table[] = {
 	{ 0xf80a, KEY_POWER },
 	{ 0xf80c, KEY_MUTE },
 	{ 0xf811, KEY_1 },
@@ -1032,7 +1032,7 @@
 	{ 0xf858, KEY_SWITCHVIDEOMODE },
 };
 
-static struct dvb_usb_rc_key ir_codes_tbs_table[] = {
+static struct ir_scancode ir_codes_tbs_table[] = {
 	{ 0xf884, KEY_POWER },
 	{ 0xf894, KEY_MUTE },
 	{ 0xf887, KEY_1 },
@@ -1075,8 +1075,8 @@
 
 static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
-	int keymap_size = d->props.rc_key_map_size;
+	struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
+	int keymap_size = d->props.rc.legacy.rc_key_map_size;
 	u8 key[2];
 	struct i2c_msg msg = {
 		.addr = DW2102_RC_QUERY,
@@ -1096,7 +1096,7 @@
 		for (i = 0; i < keymap_size ; i++) {
 			if (rc5_data(&keymap[i]) == msg.buf[0]) {
 				*state = REMOTE_KEY_PRESSED;
-				*event = keymap[i].event;
+				*event = keymap[i].keycode;
 				break;
 			}
 
@@ -1185,13 +1185,13 @@
 		/* init registers */
 		switch (dev->descriptor.idProduct) {
 		case USB_PID_PROF_1100:
-			s6x0_properties.rc_key_map = ir_codes_tbs_table;
-			s6x0_properties.rc_key_map_size =
+			s6x0_properties.rc.legacy.rc_key_map = ir_codes_tbs_table;
+			s6x0_properties.rc.legacy.rc_key_map_size =
 					ARRAY_SIZE(ir_codes_tbs_table);
 			break;
 		case USB_PID_TEVII_S650:
-			dw2104_properties.rc_key_map = ir_codes_tevii_table;
-			dw2104_properties.rc_key_map_size =
+			dw2104_properties.rc.legacy.rc_key_map = ir_codes_tevii_table;
+			dw2104_properties.rc.legacy.rc_key_map_size =
 					ARRAY_SIZE(ir_codes_tevii_table);
 		case USB_PID_DW2104:
 			reset = 1;
@@ -1255,10 +1255,13 @@
 	.no_reconnect = 1,
 
 	.i2c_algo = &dw2102_serit_i2c_algo,
-	.rc_key_map = ir_codes_dw210x_table,
-	.rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
-	.rc_interval = 150,
-	.rc_query = dw2102_rc_query,
+
+	.rc.legacy = {
+		.rc_key_map = ir_codes_dw210x_table,
+		.rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
+		.rc_interval = 150,
+		.rc_query = dw2102_rc_query,
+	},
 
 	.generic_bulk_ctrl_endpoint = 0x81,
 	/* parameter for the MPEG2-data transfer */
@@ -1306,10 +1309,12 @@
 	.no_reconnect = 1,
 
 	.i2c_algo = &dw2104_i2c_algo,
-	.rc_key_map = ir_codes_dw210x_table,
-	.rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
-	.rc_interval = 150,
-	.rc_query = dw2102_rc_query,
+	.rc.legacy = {
+		.rc_key_map = ir_codes_dw210x_table,
+		.rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
+		.rc_interval = 150,
+		.rc_query = dw2102_rc_query,
+	},
 
 	.generic_bulk_ctrl_endpoint = 0x81,
 	/* parameter for the MPEG2-data transfer */
@@ -1353,10 +1358,12 @@
 	.no_reconnect = 1,
 
 	.i2c_algo = &dw3101_i2c_algo,
-	.rc_key_map = ir_codes_dw210x_table,
-	.rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
-	.rc_interval = 150,
-	.rc_query = dw2102_rc_query,
+	.rc.legacy = {
+		.rc_key_map = ir_codes_dw210x_table,
+		.rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
+		.rc_interval = 150,
+		.rc_query = dw2102_rc_query,
+	},
 
 	.generic_bulk_ctrl_endpoint = 0x81,
 	/* parameter for the MPEG2-data transfer */
@@ -1396,10 +1403,12 @@
 	.no_reconnect = 1,
 
 	.i2c_algo = &s6x0_i2c_algo,
-	.rc_key_map = ir_codes_tevii_table,
-	.rc_key_map_size = ARRAY_SIZE(ir_codes_tevii_table),
-	.rc_interval = 150,
-	.rc_query = dw2102_rc_query,
+	.rc.legacy = {
+		.rc_key_map = ir_codes_tevii_table,
+		.rc_key_map_size = ARRAY_SIZE(ir_codes_tevii_table),
+		.rc_interval = 150,
+		.rc_query = dw2102_rc_query,
+	},
 
 	.generic_bulk_ctrl_endpoint = 0x81,
 	.num_adapters = 1,
@@ -1459,8 +1468,8 @@
 	/* fill only different fields */
 	p7500->firmware = "dvb-usb-p7500.fw";
 	p7500->devices[0] = d7500;
-	p7500->rc_key_map = ir_codes_tbs_table;
-	p7500->rc_key_map_size = ARRAY_SIZE(ir_codes_tbs_table);
+	p7500->rc.legacy.rc_key_map = ir_codes_tbs_table;
+	p7500->rc.legacy.rc_key_map_size = ARRAY_SIZE(ir_codes_tbs_table);
 	p7500->adapter->frontend_attach = prof_7500_frontend_attach;
 
 	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
index 7a7f1b2..dbdb534 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -349,7 +349,7 @@
 			 * FE_CAN_QAM_16 is for compatibility
 			 * (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
 			 */
-			FE_CAN_QPSK | FE_CAN_QAM_16
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_TURBO_FEC
 	},
 
 	.release = gp8psk_fe_release,
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index c211fef..bdef1a1 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -69,7 +69,7 @@
 	int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
 
 	/* Remote controller init. */
-	if (d->props.rc_query) {
+	if (d->props.rc.legacy.rc_query) {
 		deb("Initialising remote control\n");
 		while (rc_seq->address) {
 			if ((ret = m920x_write(d->udev, M9206_CORE,
@@ -142,9 +142,9 @@
 	if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
 		goto unlock;
 
-	for (i = 0; i < d->props.rc_key_map_size; i++)
-		if (rc5_data(&d->props.rc_key_map[i]) == rc_state[1]) {
-			*event = d->props.rc_key_map[i].event;
+	for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+		if (rc5_data(&d->props.rc.legacy.rc_key_map[i]) == rc_state[1]) {
+			*event = d->props.rc.legacy.rc_key_map[i].keycode;
 
 			switch(rc_state[0]) {
 			case 0x80:
@@ -589,7 +589,7 @@
 };
 
 /* ir keymaps */
-static struct dvb_usb_rc_key ir_codes_megasky_table [] = {
+static struct ir_scancode ir_codes_megasky_table[] = {
 	{ 0x0012, KEY_POWER },
 	{ 0x001e, KEY_CYCLEWINDOWS }, /* min/max */
 	{ 0x0002, KEY_CHANNELUP },
@@ -608,7 +608,7 @@
 	{ 0x000e, KEY_COFFEE }, /* "MTS" */
 };
 
-static struct dvb_usb_rc_key ir_codes_tvwalkertwin_table [] = {
+static struct ir_scancode ir_codes_tvwalkertwin_table[] = {
 	{ 0x0001, KEY_ZOOM }, /* Full Screen */
 	{ 0x0002, KEY_CAMERA }, /* snapshot */
 	{ 0x0003, KEY_MUTE },
@@ -628,7 +628,7 @@
 	{ 0x001e, KEY_VOLUMEUP },
 };
 
-static struct dvb_usb_rc_key ir_codes_pinnacle310e_table[] = {
+static struct ir_scancode ir_codes_pinnacle310e_table[] = {
 	{ 0x16, KEY_POWER },
 	{ 0x17, KEY_FAVORITES },
 	{ 0x0f, KEY_TEXT },
@@ -784,10 +784,12 @@
 	.firmware = "dvb-usb-megasky-02.fw",
 	.download_firmware = m920x_firmware_download,
 
-	.rc_interval      = 100,
-	.rc_key_map       = ir_codes_megasky_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_megasky_table),
-	.rc_query         = m920x_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_key_map       = ir_codes_megasky_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_megasky_table),
+		.rc_query         = m920x_rc_query,
+	},
 
 	.size_of_priv     = sizeof(struct m920x_state),
 
@@ -885,10 +887,12 @@
 	.firmware = "dvb-usb-tvwalkert.fw",
 	.download_firmware = m920x_firmware_download,
 
-	.rc_interval      = 100,
-	.rc_key_map       = ir_codes_tvwalkertwin_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_tvwalkertwin_table),
-	.rc_query         = m920x_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_key_map       = ir_codes_tvwalkertwin_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_tvwalkertwin_table),
+		.rc_query         = m920x_rc_query,
+	},
 
 	.size_of_priv     = sizeof(struct m920x_state),
 
@@ -992,10 +996,12 @@
 	.usb_ctrl = DEVICE_SPECIFIC,
 	.download_firmware = NULL,
 
-	.rc_interval      = 100,
-	.rc_key_map       = ir_codes_pinnacle310e_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_pinnacle310e_table),
-	.rc_query         = m920x_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_key_map       = ir_codes_pinnacle310e_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_pinnacle310e_table),
+		.rc_query         = m920x_rc_query,
+	},
 
 	.size_of_priv     = sizeof(struct m920x_state),
 
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index d195a58..181f36a 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -21,7 +21,7 @@
 #define deb_ee(args...) dprintk(debug,0x02,args)
 
 /* Hauppauge NOVA-T USB2 keys */
-static struct dvb_usb_rc_key ir_codes_haupp_table [] = {
+static struct ir_scancode ir_codes_haupp_table[] = {
 	{ 0x1e00, KEY_0 },
 	{ 0x1e01, KEY_1 },
 	{ 0x1e02, KEY_2 },
@@ -98,7 +98,7 @@
 					deb_rc("c: %x, d: %x\n", rc5_data(&ir_codes_haupp_table[i]),
 								 rc5_custom(&ir_codes_haupp_table[i]));
 
-					*event = ir_codes_haupp_table[i].event;
+					*event = ir_codes_haupp_table[i].keycode;
 					*state = REMOTE_KEY_PRESSED;
 					if (st->old_toggle == toggle) {
 						if (st->last_repeat_count++ < 2)
@@ -195,10 +195,12 @@
 	.power_ctrl       = dibusb2_0_power_ctrl,
 	.read_mac_address = nova_t_read_mac_address,
 
-	.rc_interval      = 100,
-	.rc_key_map       = ir_codes_haupp_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_haupp_table),
-	.rc_query         = nova_t_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 100,
+		.rc_key_map       = ir_codes_haupp_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_haupp_table),
+		.rc_query         = nova_t_rc_query,
+	},
 
 	.i2c_algo         = &dibusb_i2c_algo,
 
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index dfb81ff..6b22ec6 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -331,7 +331,7 @@
 	return 0;
 }
 
-static struct dvb_usb_rc_key ir_codes_opera1_table[] = {
+static struct ir_scancode ir_codes_opera1_table[] = {
 	{0x5fa0, KEY_1},
 	{0x51af, KEY_2},
 	{0x5da2, KEY_3},
@@ -407,9 +407,9 @@
 		for (i = 0; i < ARRAY_SIZE(ir_codes_opera1_table); i++) {
 			if (rc5_scan(&ir_codes_opera1_table[i]) == (send_key & 0xffff)) {
 				*state = REMOTE_KEY_PRESSED;
-				*event = ir_codes_opera1_table[i].event;
+				*event = ir_codes_opera1_table[i].keycode;
 				opst->last_key_pressed =
-					ir_codes_opera1_table[i].event;
+					ir_codes_opera1_table[i].keycode;
 				break;
 			}
 			opst->last_key_pressed = 0;
@@ -498,10 +498,12 @@
 	.power_ctrl = opera1_power_ctrl,
 	.i2c_algo = &opera1_i2c_algo,
 
-	.rc_key_map = ir_codes_opera1_table,
-	.rc_key_map_size = ARRAY_SIZE(ir_codes_opera1_table),
-	.rc_interval = 200,
-	.rc_query = opera1_rc_query,
+	.rc.legacy = {
+		.rc_key_map = ir_codes_opera1_table,
+		.rc_key_map_size = ARRAY_SIZE(ir_codes_opera1_table),
+		.rc_interval = 200,
+		.rc_query = opera1_rc_query,
+	},
 	.read_mac_address = opera1_read_mac_address,
 	.generic_bulk_ctrl_endpoint = 0x00,
 	/* parameter for the MPEG2-data transfer */
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
index 4d33245..5c9f327 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ b/drivers/media/dvb/dvb-usb/vp702x.c
@@ -174,7 +174,7 @@
 }
 
 /* keys for the enclosed remote control */
-static struct dvb_usb_rc_key ir_codes_vp702x_table[] = {
+static struct ir_scancode ir_codes_vp702x_table[] = {
 	{ 0x0001, KEY_1 },
 	{ 0x0002, KEY_2 },
 };
@@ -200,7 +200,7 @@
 	for (i = 0; i < ARRAY_SIZE(ir_codes_vp702x_table); i++)
 		if (rc5_custom(&ir_codes_vp702x_table[i]) == key[1]) {
 			*state = REMOTE_KEY_PRESSED;
-			*event = ir_codes_vp702x_table[i].event;
+			*event = ir_codes_vp702x_table[i].keycode;
 			break;
 		}
 	return 0;
@@ -283,10 +283,12 @@
 	},
 	.read_mac_address = vp702x_read_mac_addr,
 
-	.rc_key_map       = ir_codes_vp702x_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_vp702x_table),
-	.rc_interval      = 400,
-	.rc_query         = vp702x_rc_query,
+	.rc.legacy = {
+		.rc_key_map       = ir_codes_vp702x_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_vp702x_table),
+		.rc_interval      = 400,
+		.rc_query         = vp702x_rc_query,
+	},
 
 	.num_device_descs = 1,
 	.devices = {
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 036893f..f13791c 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -99,7 +99,7 @@
 
 /* The keymapping struct. Somehow this should be loaded to the driver, but
  * currently it is hardcoded. */
-static struct dvb_usb_rc_key ir_codes_vp7045_table[] = {
+static struct ir_scancode ir_codes_vp7045_table[] = {
 	{ 0x0016, KEY_POWER },
 	{ 0x0010, KEY_MUTE },
 	{ 0x0003, KEY_1 },
@@ -168,7 +168,7 @@
 	for (i = 0; i < ARRAY_SIZE(ir_codes_vp7045_table); i++)
 		if (rc5_data(&ir_codes_vp7045_table[i]) == key) {
 			*state = REMOTE_KEY_PRESSED;
-			*event = ir_codes_vp7045_table[i].event;
+			*event = ir_codes_vp7045_table[i].keycode;
 			break;
 		}
 	return 0;
@@ -259,10 +259,12 @@
 	.power_ctrl       = vp7045_power_ctrl,
 	.read_mac_address = vp7045_read_mac_addr,
 
-	.rc_interval      = 400,
-	.rc_key_map       = ir_codes_vp7045_table,
-	.rc_key_map_size  = ARRAY_SIZE(ir_codes_vp7045_table),
-	.rc_query         = vp7045_rc_query,
+	.rc.legacy = {
+		.rc_interval      = 400,
+		.rc_key_map       = ir_codes_vp7045_table,
+		.rc_key_map_size  = ARRAY_SIZE(ir_codes_vp7045_table),
+		.rc_query         = vp7045_rc_query,
+	},
 
 	.num_device_descs = 2,
 	.devices = {
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index cd7f9b7..51d578a 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -584,6 +584,7 @@
 config DVB_LGS8GXX
 	tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator"
 	depends on DVB_CORE && I2C
+	select FW_LOADER
 	default m if DVB_FE_CUSTOMISE
 	help
 	  A DMB-TH tuner module. Say Y when you want to support this frontend.
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c
index 12e018b..dac917f 100644
--- a/drivers/media/dvb/frontends/af9013.c
+++ b/drivers/media/dvb/frontends/af9013.c
@@ -1,5 +1,5 @@
 /*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ * Afatech AF9013 demodulator driver
  *
  * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
  *
@@ -761,6 +761,10 @@
 
 	state->frequency = params->frequency;
 
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe, params);
+
 	/* program CFOE coefficients */
 	ret = af9013_set_coeff(state, params->u.ofdm.bandwidth);
 	if (ret)
@@ -791,10 +795,6 @@
 	if (ret)
 		goto error;
 
-	/* program tuner */
-	if (fe->ops.tuner_ops.set_params)
-		fe->ops.tuner_ops.set_params(fe, params);
-
 	/* program TPS and bandwidth, check if auto mode needed */
 	ret = af9013_set_ofdm_params(state, &params->u.ofdm, &auto_mode);
 	if (ret)
@@ -1184,21 +1184,43 @@
 	u8 tmp;
 	*status = 0;
 
-	/* TPS lock */
-	ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp);
-	if (ret)
-		goto error;
-	if (tmp)
-		*status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
-
 	/* MPEG2 lock */
 	ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp);
 	if (ret)
 		goto error;
 	if (tmp)
-		*status |= FE_HAS_SYNC | FE_HAS_LOCK;
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+			FE_HAS_SYNC | FE_HAS_LOCK;
 
-	if (!(*status & FE_HAS_SIGNAL)) {
+	if (!*status) {
+		/* TPS lock */
+		ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp);
+		if (ret)
+			goto error;
+		if (tmp)
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+				FE_HAS_VITERBI;
+	}
+
+	if (!*status) {
+		/* CFO lock */
+		ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp);
+		if (ret)
+			goto error;
+		if (tmp)
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+	}
+
+	if (!*status) {
+		/* SFOE lock */
+		ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp);
+		if (ret)
+			goto error;
+		if (tmp)
+			*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+	}
+
+	if (!*status) {
 		/* AGC lock */
 		ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp);
 		if (ret)
@@ -1207,24 +1229,6 @@
 			*status |= FE_HAS_SIGNAL;
 	}
 
-	if (!(*status & FE_HAS_CARRIER)) {
-		/* CFO lock */
-		ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp);
-		if (ret)
-			goto error;
-		if (tmp)
-			*status |= FE_HAS_CARRIER;
-	}
-
-	if (!(*status & FE_HAS_CARRIER)) {
-		/* SFOE lock */
-		ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp);
-		if (ret)
-			goto error;
-		if (tmp)
-			*status |= FE_HAS_CARRIER;
-	}
-
 	ret = af9013_update_statistics(fe);
 
 error:
@@ -1574,7 +1578,7 @@
 {
 	int ret;
 	struct af9013_state *state = NULL;
-	u8 buf[3], i;
+	u8 buf[4], i;
 
 	/* allocate memory for the internal state */
 	state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL);
@@ -1607,12 +1611,12 @@
 	}
 
 	/* firmware version */
-	for (i = 0; i < 3; i++) {
+	for (i = 0; i < 4; i++) {
 		ret = af9013_read_reg(state, 0x5103 + i, &buf[i]);
 		if (ret)
 			goto error;
 	}
-	info("firmware version:%d.%d.%d", buf[0], buf[1], buf[2]);
+	info("firmware version:%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]);
 
 	/* settings for mp2if */
 	if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) {
diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h
index e90fa92..72c71bb 100644
--- a/drivers/media/dvb/frontends/af9013.h
+++ b/drivers/media/dvb/frontends/af9013.h
@@ -1,5 +1,5 @@
 /*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ * Afatech AF9013 demodulator driver
  *
  * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
  *
diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb/frontends/af9013_priv.h
index 163e251..0fd42b7 100644
--- a/drivers/media/dvb/frontends/af9013_priv.h
+++ b/drivers/media/dvb/frontends/af9013_priv.h
@@ -1,5 +1,5 @@
 /*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ * Afatech AF9013 demodulator driver
  *
  * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
  *
@@ -132,6 +132,8 @@
 	{ 0xd740, 2, 1, 0x00 },
 	{ 0xd740, 3, 1, 0x01 },
 	{ 0xd3c1, 4, 1, 0x01 },
+	{ 0x9124, 0, 8, 0x58 },
+	{ 0x9125, 0, 2, 0x02 },
 	{ 0xd3a2, 0, 8, 0x00 },
 	{ 0xd3a3, 0, 8, 0x04 },
 	{ 0xd305, 0, 8, 0x32 },
@@ -143,7 +145,7 @@
 	{ 0x911b, 0, 1, 0x01 },
 	{ 0x9bce, 0, 4, 0x02 },
 	{ 0x9116, 0, 1, 0x01 },
-	{ 0x9bd1, 0, 1, 0x01 },
+	{ 0x9122, 0, 8, 0xd0 },
 	{ 0xd2e0, 0, 8, 0xd0 },
 	{ 0xd2e9, 0, 4, 0x0d },
 	{ 0xd38c, 0, 8, 0xfc },
@@ -165,7 +167,6 @@
 	{ 0xd081, 4, 4, 0x09 },
 	{ 0xd098, 4, 4, 0x0f },
 	{ 0xd098, 0, 4, 0x03 },
-	{ 0xdbc0, 3, 1, 0x01 },
 	{ 0xdbc0, 4, 1, 0x01 },
 	{ 0xdbc7, 0, 8, 0x08 },
 	{ 0xdbc8, 4, 4, 0x00 },
@@ -179,6 +180,7 @@
 	{ 0xd0f0, 0, 7, 0x1a },
 	{ 0xd0f1, 4, 1, 0x01 },
 	{ 0xd0f2, 0, 8, 0x0c },
+	{ 0xd101, 5, 3, 0x06 },
 	{ 0xd103, 0, 4, 0x08 },
 	{ 0xd0f8, 0, 7, 0x20 },
 	{ 0xd111, 5, 1, 0x00 },
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index ad4c8cf..e80c597 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -38,11 +38,10 @@
 #define DRIVER_DESC "DiBcom 3000M-B DVB-T demodulator"
 #define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
 
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
 static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
-#endif
+
 #define deb_info(args...) dprintk(0x01,args)
 #define deb_i2c(args...)  dprintk(0x02,args)
 #define deb_srch(args...) dprintk(0x04,args)
@@ -51,12 +50,6 @@
 #define deb_setf(args...) dprintk(0x04,args)
 #define deb_getf(args...) dprintk(0x08,args)
 
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
-#endif
-
 static int dib3000_read_reg(struct dib3000_state *state, u16 reg)
 {
 	u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h
index 1a12747..16c5265 100644
--- a/drivers/media/dvb/frontends/dib3000mb_priv.h
+++ b/drivers/media/dvb/frontends/dib3000mb_priv.h
@@ -37,12 +37,8 @@
 
 /* debug */
 
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
 #define dprintk(level,args...) \
     do { if ((debug & level)) { printk(args); } } while (0)
-#else
-#define dprintk(args...) do { } while (0)
-#endif
 
 /* mask for enabling a specific pid for the pid_filter */
 #define DIB3000_ACTIVATE_PID_FILTERING	(0x2000)
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index afad252..088e7fa 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -822,7 +822,7 @@
 
 	dmcst = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
 	if (dmcst == NULL)
-		return -ENODEV;
+		return -ENOMEM;
 
 	dmcst->i2c_adap = i2c;
 
diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c
index d69c775..3272881 100644
--- a/drivers/media/dvb/frontends/lgdt3305.c
+++ b/drivers/media/dvb/frontends/lgdt3305.c
@@ -1,7 +1,9 @@
 /*
- *    Support for LGDT3305 - VSB/QAM
+ *    Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
  *
- *    Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
+ *    Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *    LGDT3304 support by Jarod Wilson <jarod@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
@@ -65,6 +67,8 @@
 
 /* ------------------------------------------------------------------------ */
 
+/* FIXME: verify & document the LGDT3304 registers */
+
 #define LGDT3305_GEN_CTRL_1                   0x0000
 #define LGDT3305_GEN_CTRL_2                   0x0001
 #define LGDT3305_GEN_CTRL_3                   0x0002
@@ -358,7 +362,12 @@
 	case QAM_256:
 		agcdelay = 0x046b;
 		rfbw     = 0x8889;
-		ifbw     = 0x8888;
+		/* FIXME: investigate optimal ifbw & rfbw values for the
+		 *        DT3304 and re-write this switch..case block */
+		if (state->cfg->demod_chip == LGDT3304)
+			ifbw = 0x6666;
+		else /* (state->cfg->demod_chip == LGDT3305) */
+			ifbw = 0x8888;
 		break;
 	default:
 		return -EINVAL;
@@ -410,8 +419,18 @@
 	lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen);
 
 	/* control agc function */
-	lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
-	lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
+	switch (state->cfg->demod_chip) {
+	case LGDT3304:
+		lgdt3305_write_reg(state, 0x0314, 0xe1 | lockdten << 1);
+		lgdt3305_set_reg_bit(state, 0x030e, 2, acqen);
+		break;
+	case LGDT3305:
+		lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
+		lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
+		break;
+	default:
+		return -EINVAL;
+	}
 
 	return lgdt3305_rfagc_loop(state, param);
 }
@@ -577,61 +596,79 @@
 	struct lgdt3305_state *state = fe->demodulator_priv;
 	int ret;
 
+	static struct lgdt3305_reg lgdt3304_init_data[] = {
+		{ .reg = LGDT3305_GEN_CTRL_1,           .val = 0x03, },
+		{ .reg = 0x000d,                        .val = 0x02, },
+		{ .reg = 0x000e,                        .val = 0x02, },
+		{ .reg = LGDT3305_DGTL_AGC_REF_1,       .val = 0x32, },
+		{ .reg = LGDT3305_DGTL_AGC_REF_2,       .val = 0xc4, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_1,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_2,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_3,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_4,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTRL_7,            .val = 0xf9, },
+		{ .reg = 0x0112,                        .val = 0x17, },
+		{ .reg = 0x0113,                        .val = 0x15, },
+		{ .reg = 0x0114,                        .val = 0x18, },
+		{ .reg = 0x0115,                        .val = 0xff, },
+		{ .reg = 0x0116,                        .val = 0x3c, },
+		{ .reg = 0x0214,                        .val = 0x67, },
+		{ .reg = 0x0424,                        .val = 0x8d, },
+		{ .reg = 0x0427,                        .val = 0x12, },
+		{ .reg = 0x0428,                        .val = 0x4f, },
+		{ .reg = LGDT3305_IFBW_1,               .val = 0x80, },
+		{ .reg = LGDT3305_IFBW_2,               .val = 0x00, },
+		{ .reg = 0x030a,                        .val = 0x08, },
+		{ .reg = 0x030b,                        .val = 0x9b, },
+		{ .reg = 0x030d,                        .val = 0x00, },
+		{ .reg = 0x030e,                        .val = 0x1c, },
+		{ .reg = 0x0314,                        .val = 0xe1, },
+		{ .reg = 0x000d,                        .val = 0x82, },
+		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x5b, },
+		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x5b, },
+	};
+
 	static struct lgdt3305_reg lgdt3305_init_data[] = {
-		{ .reg = LGDT3305_GEN_CTRL_1,
-		  .val = 0x03, },
-		{ .reg = LGDT3305_GEN_CTRL_2,
-		  .val = 0xb0, },
-		{ .reg = LGDT3305_GEN_CTRL_3,
-		  .val = 0x01, },
-		{ .reg = LGDT3305_GEN_CONTROL,
-		  .val = 0x6f, },
-		{ .reg = LGDT3305_GEN_CTRL_4,
-		  .val = 0x03, },
-		{ .reg = LGDT3305_DGTL_AGC_REF_1,
-		  .val = 0x32, },
-		{ .reg = LGDT3305_DGTL_AGC_REF_2,
-		  .val = 0xc4, },
-		{ .reg = LGDT3305_CR_CTR_FREQ_1,
-		  .val = 0x00, },
-		{ .reg = LGDT3305_CR_CTR_FREQ_2,
-		  .val = 0x00, },
-		{ .reg = LGDT3305_CR_CTR_FREQ_3,
-		  .val = 0x00, },
-		{ .reg = LGDT3305_CR_CTR_FREQ_4,
-		  .val = 0x00, },
-		{ .reg = LGDT3305_CR_CTRL_7,
-		  .val = 0x79, },
-		{ .reg = LGDT3305_AGC_POWER_REF_1,
-		  .val = 0x32, },
-		{ .reg = LGDT3305_AGC_POWER_REF_2,
-		  .val = 0xc4, },
-		{ .reg = LGDT3305_AGC_DELAY_PT_1,
-		  .val = 0x0d, },
-		{ .reg = LGDT3305_AGC_DELAY_PT_2,
-		  .val = 0x30, },
-		{ .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1,
-		  .val = 0x80, },
-		{ .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2,
-		  .val = 0x00, },
-		{ .reg = LGDT3305_IFBW_1,
-		  .val = 0x80, },
-		{ .reg = LGDT3305_IFBW_2,
-		  .val = 0x00, },
-		{ .reg = LGDT3305_AGC_CTRL_1,
-		  .val = 0x30, },
-		{ .reg = LGDT3305_AGC_CTRL_4,
-		  .val = 0x61, },
-		{ .reg = LGDT3305_FEC_BLOCK_CTRL,
-		  .val = 0xff, },
-		{ .reg = LGDT3305_TP_CTRL_1,
-		  .val = 0x1b, },
+		{ .reg = LGDT3305_GEN_CTRL_1,           .val = 0x03, },
+		{ .reg = LGDT3305_GEN_CTRL_2,           .val = 0xb0, },
+		{ .reg = LGDT3305_GEN_CTRL_3,           .val = 0x01, },
+		{ .reg = LGDT3305_GEN_CONTROL,          .val = 0x6f, },
+		{ .reg = LGDT3305_GEN_CTRL_4,           .val = 0x03, },
+		{ .reg = LGDT3305_DGTL_AGC_REF_1,       .val = 0x32, },
+		{ .reg = LGDT3305_DGTL_AGC_REF_2,       .val = 0xc4, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_1,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_2,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_3,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTR_FREQ_4,        .val = 0x00, },
+		{ .reg = LGDT3305_CR_CTRL_7,            .val = 0x79, },
+		{ .reg = LGDT3305_AGC_POWER_REF_1,      .val = 0x32, },
+		{ .reg = LGDT3305_AGC_POWER_REF_2,      .val = 0xc4, },
+		{ .reg = LGDT3305_AGC_DELAY_PT_1,       .val = 0x0d, },
+		{ .reg = LGDT3305_AGC_DELAY_PT_2,       .val = 0x30, },
+		{ .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1, .val = 0x80, },
+		{ .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2, .val = 0x00, },
+		{ .reg = LGDT3305_IFBW_1,               .val = 0x80, },
+		{ .reg = LGDT3305_IFBW_2,               .val = 0x00, },
+		{ .reg = LGDT3305_AGC_CTRL_1,           .val = 0x30, },
+		{ .reg = LGDT3305_AGC_CTRL_4,           .val = 0x61, },
+		{ .reg = LGDT3305_FEC_BLOCK_CTRL,       .val = 0xff, },
+		{ .reg = LGDT3305_TP_CTRL_1,            .val = 0x1b, },
 	};
 
 	lg_dbg("\n");
 
-	ret = lgdt3305_write_regs(state, lgdt3305_init_data,
-				  ARRAY_SIZE(lgdt3305_init_data));
+	switch (state->cfg->demod_chip) {
+	case LGDT3304:
+		ret = lgdt3305_write_regs(state, lgdt3304_init_data,
+					  ARRAY_SIZE(lgdt3304_init_data));
+		break;
+	case LGDT3305:
+		ret = lgdt3305_write_regs(state, lgdt3305_init_data,
+					  ARRAY_SIZE(lgdt3305_init_data));
+		break;
+	default:
+		ret = -EINVAL;
+	}
 	if (lg_fail(ret))
 		goto fail;
 
@@ -640,6 +677,76 @@
 	return ret;
 }
 
+static int lgdt3304_set_parameters(struct dvb_frontend *fe,
+				   struct dvb_frontend_parameters *param)
+{
+	struct lgdt3305_state *state = fe->demodulator_priv;
+	int ret;
+
+	lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation);
+
+	if (fe->ops.tuner_ops.set_params) {
+		ret = fe->ops.tuner_ops.set_params(fe, param);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+		if (lg_fail(ret))
+			goto fail;
+		state->current_frequency = param->frequency;
+	}
+
+	ret = lgdt3305_set_modulation(state, param);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lgdt3305_passband_digital_agc(state, param);
+	if (lg_fail(ret))
+		goto fail;
+
+	ret = lgdt3305_agc_setup(state, param);
+	if (lg_fail(ret))
+		goto fail;
+
+	/* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */
+	switch (param->u.vsb.modulation) {
+	case VSB_8:
+		lgdt3305_write_reg(state, 0x030d, 0x00);
+		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f);
+		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, 0x0c);
+		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, 0xac);
+		lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, 0xba);
+		break;
+	case QAM_64:
+	case QAM_256:
+		lgdt3305_write_reg(state, 0x030d, 0x14);
+		ret = lgdt3305_set_if(state, param);
+		if (lg_fail(ret))
+			goto fail;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+
+	ret = lgdt3305_spectral_inversion(state, param,
+					  state->cfg->spectral_inversion
+					  ? 1 : 0);
+	if (lg_fail(ret))
+		goto fail;
+
+	state->current_modulation = param->u.vsb.modulation;
+
+	ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
+	if (lg_fail(ret))
+		goto fail;
+
+	/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
+	ret = lgdt3305_mpeg_mode_polarity(state,
+					  state->cfg->tpclk_edge,
+					  state->cfg->tpvalid_polarity);
+fail:
+	return ret;
+}
+
 static int lgdt3305_set_parameters(struct dvb_frontend *fe,
 				   struct dvb_frontend_parameters *param)
 {
@@ -848,6 +955,10 @@
 	switch (state->current_modulation) {
 	case QAM_256:
 	case QAM_64:
+		/* signal bit is unreliable on the DT3304 in QAM mode */
+		if (((LGDT3304 == state->cfg->demod_chip)) && (cr_lock))
+			*status |= FE_HAS_SIGNAL;
+
 		ret = lgdt3305_read_fec_lock_status(state, &fec_lock);
 		if (lg_fail(ret))
 			goto fail;
@@ -993,6 +1104,7 @@
 	kfree(state);
 }
 
+static struct dvb_frontend_ops lgdt3304_ops;
 static struct dvb_frontend_ops lgdt3305_ops;
 
 struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
@@ -1013,11 +1125,21 @@
 	state->cfg = config;
 	state->i2c_adap = i2c_adap;
 
-	memcpy(&state->frontend.ops, &lgdt3305_ops,
-	       sizeof(struct dvb_frontend_ops));
+	switch (config->demod_chip) {
+	case LGDT3304:
+		memcpy(&state->frontend.ops, &lgdt3304_ops,
+		       sizeof(struct dvb_frontend_ops));
+		break;
+	case LGDT3305:
+		memcpy(&state->frontend.ops, &lgdt3305_ops,
+		       sizeof(struct dvb_frontend_ops));
+		break;
+	default:
+		goto fail;
+	}
 	state->frontend.demodulator_priv = state;
 
-	/* verify that we're talking to a lg dt3305 */
+	/* verify that we're talking to a lg dt3304/5 */
 	ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val);
 	if ((lg_fail(ret)) | (val == 0))
 		goto fail;
@@ -1036,12 +1158,35 @@
 
 	return &state->frontend;
 fail:
-	lg_warn("unable to detect LGDT3305 hardware\n");
+	lg_warn("unable to detect %s hardware\n",
+		config->demod_chip ? "LGDT3304" : "LGDT3305");
 	kfree(state);
 	return NULL;
 }
 EXPORT_SYMBOL(lgdt3305_attach);
 
+static struct dvb_frontend_ops lgdt3304_ops = {
+	.info = {
+		.name = "LG Electronics LGDT3304 VSB/QAM Frontend",
+		.type               = FE_ATSC,
+		.frequency_min      = 54000000,
+		.frequency_max      = 858000000,
+		.frequency_stepsize = 62500,
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+	.i2c_gate_ctrl        = lgdt3305_i2c_gate_ctrl,
+	.init                 = lgdt3305_init,
+	.set_frontend         = lgdt3304_set_parameters,
+	.get_frontend         = lgdt3305_get_frontend,
+	.get_tune_settings    = lgdt3305_get_tune_settings,
+	.read_status          = lgdt3305_read_status,
+	.read_ber             = lgdt3305_read_ber,
+	.read_signal_strength = lgdt3305_read_signal_strength,
+	.read_snr             = lgdt3305_read_snr,
+	.read_ucblocks        = lgdt3305_read_ucblocks,
+	.release              = lgdt3305_release,
+};
+
 static struct dvb_frontend_ops lgdt3305_ops = {
 	.info = {
 		.name = "LG Electronics LGDT3305 VSB/QAM Frontend",
@@ -1065,10 +1210,10 @@
 	.release              = lgdt3305_release,
 };
 
-MODULE_DESCRIPTION("LG Electronics LGDT3305 ATSC/QAM-B Demodulator Driver");
+MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver");
 MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.1");
+MODULE_VERSION("0.2");
 
 /*
  * Local variables:
diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h
index 9cb11c9..02172ec 100644
--- a/drivers/media/dvb/frontends/lgdt3305.h
+++ b/drivers/media/dvb/frontends/lgdt3305.h
@@ -1,7 +1,7 @@
 /*
- *    Support for LGDT3305 - VSB/QAM
+ *    Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
  *
- *    Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
+ *    Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.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
@@ -41,6 +41,11 @@
 	LGDT3305_TP_VALID_HIGH = 1,
 };
 
+enum lgdt_demod_chip_type {
+	LGDT3305 = 0,
+	LGDT3304 = 1,
+};
+
 struct lgdt3305_config {
 	u8 i2c_addr;
 
@@ -65,6 +70,7 @@
 	enum lgdt3305_mpeg_mode mpeg_mode;
 	enum lgdt3305_tp_clock_edge tpclk_edge;
 	enum lgdt3305_tp_valid_polarity tpvalid_polarity;
+	enum lgdt_demod_chip_type demod_chip;
 };
 
 #if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
index dee5396..5ea28ae 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.c
+++ b/drivers/media/dvb/frontends/lgs8gxx.c
@@ -24,6 +24,7 @@
  */
 
 #include <asm/div64.h>
+#include <linux/firmware.h>
 
 #include "dvb_frontend.h"
 
@@ -46,42 +47,6 @@
 MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
 "Signal strength calculation is slow.(default:on).");
 
-static const u8 lgs8g75_initdat[] = {
-	0x01, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xE4, 0xF5, 0xA8, 0xF5, 0xB8, 0xF5, 0x88, 0xF5,
-	0x89, 0xF5, 0x87, 0x75, 0xD0, 0x00, 0x11, 0x50,
-	0x11, 0x50, 0xF4, 0xF5, 0x80, 0xF5, 0x90, 0xF5,
-	0xA0, 0xF5, 0xB0, 0x75, 0x81, 0x30, 0x80, 0x01,
-	0x32, 0x90, 0x80, 0x12, 0x74, 0xFF, 0xF0, 0x90,
-	0x80, 0x13, 0x74, 0x1F, 0xF0, 0x90, 0x80, 0x23,
-	0x74, 0x01, 0xF0, 0x90, 0x80, 0x22, 0xF0, 0x90,
-	0x00, 0x48, 0x74, 0x00, 0xF0, 0x90, 0x80, 0x4D,
-	0x74, 0x05, 0xF0, 0x90, 0x80, 0x09, 0xE0, 0x60,
-	0x21, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x1B, 0x12,
-	0x00, 0xDD, 0x14, 0x60, 0x15, 0x12, 0x00, 0xDD,
-	0x14, 0x60, 0x0F, 0x12, 0x00, 0xDD, 0x14, 0x60,
-	0x09, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x03, 0x12,
-	0x00, 0xDD, 0x90, 0x80, 0x42, 0xE0, 0x60, 0x0B,
-	0x14, 0x60, 0x0C, 0x14, 0x60, 0x0D, 0x14, 0x60,
-	0x0E, 0x01, 0xB3, 0x74, 0x04, 0x01, 0xB9, 0x74,
-	0x05, 0x01, 0xB9, 0x74, 0x07, 0x01, 0xB9, 0x74,
-	0x0A, 0xC0, 0xE0, 0x74, 0xC8, 0x12, 0x00, 0xE2,
-	0xD0, 0xE0, 0x14, 0x70, 0xF4, 0x90, 0x80, 0x09,
-	0xE0, 0x70, 0xAE, 0x12, 0x00, 0xF6, 0x12, 0x00,
-	0xFE, 0x90, 0x00, 0x48, 0xE0, 0x04, 0xF0, 0x90,
-	0x80, 0x4E, 0xF0, 0x01, 0x73, 0x90, 0x80, 0x08,
-	0xF0, 0x22, 0xF8, 0x7A, 0x0C, 0x79, 0xFD, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9,
-	0xF6, 0xDA, 0xF2, 0xD8, 0xEE, 0x22, 0x90, 0x80,
-	0x65, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, 0x80,
-	0x65, 0xE0, 0x44, 0xC2, 0xF0, 0x22
-};
-
 /* LGS8GXX internal helper functions */
 
 static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
@@ -627,9 +592,14 @@
 
 static int lgs8g75_init_data(struct lgs8gxx_state *priv)
 {
-	const u8 *p = lgs8g75_initdat;
+	const struct firmware *fw;
+	int rc;
 	int i;
 
+	rc = request_firmware(&fw, "lgs8g75.fw", &priv->i2c->dev);
+	if (rc)
+		return rc;
+
 	lgs8gxx_write_reg(priv, 0xC6, 0x40);
 
 	lgs8gxx_write_reg(priv, 0x3D, 0x04);
@@ -640,16 +610,16 @@
 	lgs8gxx_write_reg(priv, 0x3B, 0x00);
 	lgs8gxx_write_reg(priv, 0x38, 0x00);
 
-	for (i = 0; i < sizeof(lgs8g75_initdat); i++) {
+	for (i = 0; i < fw->size; i++) {
 		lgs8gxx_write_reg(priv, 0x38, 0x00);
 		lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff));
 		lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8));
-		lgs8gxx_write_reg(priv, 0x3C, *p);
-		p++;
+		lgs8gxx_write_reg(priv, 0x3C, fw->data[i]);
 	}
 
 	lgs8gxx_write_reg(priv, 0x38, 0x00);
 
+	release_firmware(fw);
 	return 0;
 }
 
diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb/frontends/mb86a16.c
index 599d1aa..33b6323 100644
--- a/drivers/media/dvb/frontends/mb86a16.c
+++ b/drivers/media/dvb/frontends/mb86a16.c
@@ -1833,7 +1833,6 @@
 
 	.get_frontend_algo		= mb86a16_frontend_algo,
 	.search				= mb86a16_search,
-	.read_status			= mb86a16_read_status,
 	.init				= mb86a16_init,
 	.sleep				= mb86a16_sleep,
 	.read_status			= mb86a16_read_status,
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c
index 4e2a7c8..93f6a75 100644
--- a/drivers/media/dvb/frontends/tda10048.c
+++ b/drivers/media/dvb/frontends/tda10048.c
@@ -25,6 +25,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/math64.h>
 #include <asm/div64.h>
 #include "dvb_frontend.h"
 #include "dvb_math.h"
@@ -49,8 +50,8 @@
 #define TDA10048_CONF_C4_1         0x1E
 #define TDA10048_CONF_C4_2         0x1F
 #define TDA10048_CODE_IN_RAM       0x20
-#define TDA10048_CHANNEL_INFO_1_R  0x22
-#define TDA10048_CHANNEL_INFO_2_R  0x23
+#define TDA10048_CHANNEL_INFO1_R   0x22
+#define TDA10048_CHANNEL_INFO2_R   0x23
 #define TDA10048_CHANNEL_INFO1     0x24
 #define TDA10048_CHANNEL_INFO2     0x25
 #define TDA10048_TIME_ERROR_R      0x26
@@ -63,8 +64,8 @@
 #define TDA10048_IT_STAT           0x32
 #define TDA10048_DSP_AD_LSB        0x3C
 #define TDA10048_DSP_AD_MSB        0x3D
-#define TDA10048_DSP_REF_LSB       0x3E
-#define TDA10048_DSP_REF_MSB       0x3F
+#define TDA10048_DSP_REG_LSB       0x3E
+#define TDA10048_DSP_REG_MSB       0x3F
 #define TDA10048_CONF_TRISTATE1    0x44
 #define TDA10048_CONF_TRISTATE2    0x45
 #define TDA10048_CONF_POLARITY     0x46
@@ -112,7 +113,7 @@
 #define TDA10048_FREE_REG_1        0xB2
 #define TDA10048_FREE_REG_2        0xB3
 #define TDA10048_CONF_C3_1         0xC0
-#define TDA10048_CYBER_CTRL        0xC2
+#define TDA10048_CVBER_CTRL        0xC2
 #define TDA10048_CBER_NMAX_LSB     0xC4
 #define TDA10048_CBER_NMAX_MSB     0xC5
 #define TDA10048_CBER_LSB          0xC6
@@ -120,7 +121,7 @@
 #define TDA10048_VBER_LSB          0xC8
 #define TDA10048_VBER_MID          0xC9
 #define TDA10048_VBER_MSB          0xCA
-#define TDA10048_CYBER_LUT         0xCC
+#define TDA10048_CVBER_LUT         0xCC
 #define TDA10048_UNCOR_CTRL        0xCD
 #define TDA10048_UNCOR_CPT_LSB     0xCE
 #define TDA10048_UNCOR_CPT_MSB     0xCF
@@ -183,7 +184,7 @@
 	{ TDA10048_AGC_IF_MAX, 0xff },
 	{ TDA10048_AGC_THRESHOLD_MSB, 0x00 },
 	{ TDA10048_AGC_THRESHOLD_LSB, 0x70 },
-	{ TDA10048_CYBER_CTRL, 0x38 },
+	{ TDA10048_CVBER_CTRL, 0x38 },
 	{ TDA10048_AGC_GAINS, 0x12 },
 	{ TDA10048_CONF_XO, 0x00 },
 	{ TDA10048_CONF_TS1, 0x07 },
@@ -688,7 +689,7 @@
 		p->guard_interval =  GUARD_INTERVAL_1_4;
 		break;
 	}
-	switch (val & 0x02) {
+	switch (val & 0x03) {
 	case 0:
 		p->transmission_mode = TRANSMISSION_MODE_2K;
 		break;
@@ -765,6 +766,8 @@
 
 	/* Enable demod TPS auto detection and begin acquisition */
 	tda10048_writereg(state, TDA10048_AUTO, 0x57);
+	/* trigger cber and vber acquisition */
+	tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x3B);
 
 	return 0;
 }
@@ -830,12 +833,27 @@
 static int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
 	struct tda10048_state *state = fe->demodulator_priv;
+	static u32 cber_current;
+	u32 cber_nmax;
+	u64 cber_tmp;
 
 	dprintk(1, "%s()\n", __func__);
 
-	/* TODO: A reset may be required here */
-	*ber = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
-		tda10048_readreg(state, TDA10048_CBER_LSB);
+	/* update cber on interrupt */
+	if (tda10048_readreg(state, TDA10048_SOFT_IT_C3) & 0x01) {
+		cber_tmp = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
+			tda10048_readreg(state, TDA10048_CBER_LSB);
+		cber_nmax = tda10048_readreg(state, TDA10048_CBER_NMAX_MSB) << 8 |
+			tda10048_readreg(state, TDA10048_CBER_NMAX_LSB);
+		cber_tmp *= 100000000;
+		cber_tmp *= 2;
+		cber_tmp = div_u64(cber_tmp, (cber_nmax * 32) + 1);
+		cber_current = (u32)cber_tmp;
+		/* retrigger cber acquisition */
+		tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x39);
+	}
+	/* actual cber is (*ber)/1e8 */
+	*ber = cber_current;
 
 	return 0;
 }
@@ -1015,6 +1033,9 @@
 
 	*ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 |
 		tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB);
+	/* clear the uncorrected TS packets counter when saturated */
+	if (*ucblocks == 0xFFFF)
+		tda10048_writereg(state, TDA10048_UNCOR_CTRL, 0x80);
 
 	return 0;
 }
diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig
index f7b72a3..decdeda 100644
--- a/drivers/media/dvb/mantis/Kconfig
+++ b/drivers/media/dvb/mantis/Kconfig
@@ -10,9 +10,15 @@
 config DVB_MANTIS
 	tristate "MANTIS based cards"
 	depends on MANTIS_CORE && DVB_CORE && PCI && I2C
-	select DVB_MB86A16
-	select DVB_ZL10353
-	select DVB_STV0299
+	select DVB_MB86A16 if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	select DVB_STB0899 if !DVB_FE_CUSTOMISE
+	select DVB_STB6100 if !DVB_FE_CUSTOMISE
+	select DVB_TDA665x if !DVB_FE_CUSTOMISE
+	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
 	select DVB_PLL
 	help
 	  Support for PCI cards based on the Mantis PCI bridge.
@@ -23,7 +29,7 @@
 config DVB_HOPPER
 	tristate "HOPPER based cards"
 	depends on MANTIS_CORE && DVB_CORE && PCI && I2C
-	select DVB_ZL10353
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
 	select DVB_PLL
 	help
 	  Support for PCI cards based on the Hopper  PCI bridge.
diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c
index 3d4e466..a99489b 100644
--- a/drivers/media/dvb/mantis/mantis_input.c
+++ b/drivers/media/dvb/mantis/mantis_input.c
@@ -19,7 +19,7 @@
 */
 
 #include <linux/input.h>
-#include <media/ir-common.h>
+#include <media/ir-core.h>
 #include <linux/pci.h>
 
 #include "dmxdev.h"
@@ -104,7 +104,6 @@
 int mantis_input_init(struct mantis_pci *mantis)
 {
 	struct input_dev *rc;
-	struct ir_input_state rc_state;
 	char name[80], dev[80];
 	int err;
 
@@ -120,8 +119,6 @@
 	rc->name = name;
 	rc->phys = dev;
 
-	ir_input_init(rc, &rc_state, IR_TYPE_OTHER);
-
 	rc->id.bustype	= BUS_PCI;
 	rc->id.vendor	= mantis->vendor_id;
 	rc->id.product	= mantis->device_id;
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
index cff77e2..25b43e5 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -64,9 +64,11 @@
 		.type	= SMS_NOVA_B0,
 		.fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
 		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+		.rc_codes = RC_MAP_RC5_HAUPPAUGE_NEW,
 		.board_cfg.leds_power = 26,
 		.board_cfg.led0 = 27,
 		.board_cfg.led1 = 28,
+		.board_cfg.ir = 9,
 		.led_power = 26,
 		.led_lo    = 27,
 		.led_hi    = 28,
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
index 8f19fc0..d8cdf75 100644
--- a/drivers/media/dvb/siano/sms-cards.h
+++ b/drivers/media/dvb/siano/sms-cards.h
@@ -75,7 +75,7 @@
 	enum sms_device_type_st type;
 	char *name, *fw[DEVICE_MODE_MAX];
 	struct sms_board_gpio_cfg board_cfg;
-	enum ir_kb_type ir_kb_type;
+	char *rc_codes;				/* Name of IR codes table */
 
 	/* gpios */
 	int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
index a19f649..7f2c94a1 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -116,9 +116,7 @@
 			return entry;
 		}
 	}
-	entry = (struct smscore_registry_entry_t *)
-			kmalloc(sizeof(struct smscore_registry_entry_t),
-				GFP_KERNEL);
+	entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL);
 	if (entry) {
 		entry->mode = default_mode;
 		strcpy(entry->devpath, devpath);
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
index a56eac7..d0e4639 100644
--- a/drivers/media/dvb/siano/smsir.c
+++ b/drivers/media/dvb/siano/smsir.c
@@ -4,6 +4,11 @@
  MDTV receiver kernel modules.
  Copyright (C) 2006-2009, Uri Shkolnik
 
+ Copyright (c) 2010 - Mauro Carvalho Chehab
+	- Ported the driver to use rc-core
+	- IR raw event decoding is now done at rc-core
+	- Code almost re-written
+
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 2 of the License, or
@@ -27,226 +32,28 @@
 #include "smsir.h"
 #include "sms-cards.h"
 
-/* In order to add new IR remote control -
- * 1) Add it to the <enum ir_kb_type> @ smsir,h,
- * 2) Add its map to keyboard_layout_maps below
- * 3) Set your board (sms-cards sub-module) to use it
- */
-
-static struct keyboard_layout_map_t keyboard_layout_maps[] = {
-		[SMS_IR_KB_DEFAULT_TV] = {
-			.ir_protocol = IR_RC5,
-			.rc5_kbd_address = KEYBOARD_ADDRESS_TV1,
-			.keyboard_layout_map = {
-					KEY_0, KEY_1, KEY_2,
-					KEY_3, KEY_4, KEY_5,
-					KEY_6, KEY_7, KEY_8,
-					KEY_9, 0, 0, KEY_POWER,
-					KEY_MUTE, 0, 0,
-					KEY_VOLUMEUP, KEY_VOLUMEDOWN,
-					KEY_BRIGHTNESSUP,
-					KEY_BRIGHTNESSDOWN, KEY_CHANNELUP,
-					KEY_CHANNELDOWN,
-					0, 0, 0, 0, 0, 0, 0, 0,
-					0, 0, 0, 0, 0, 0, 0, 0,
-					0, 0, 0, 0, 0, 0, 0, 0,
-					0, 0, 0, 0, 0, 0, 0, 0,
-					0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-			}
-		},
-		[SMS_IR_KB_HCW_SILVER] = {
-			.ir_protocol = IR_RC5,
-			.rc5_kbd_address = KEYBOARD_ADDRESS_LIGHTING1,
-			.keyboard_layout_map = {
-					KEY_0, KEY_1, KEY_2,
-					KEY_3, KEY_4, KEY_5,
-					KEY_6, KEY_7, KEY_8,
-					KEY_9, KEY_TEXT, KEY_RED,
-					KEY_RADIO, KEY_MENU,
-					KEY_SUBTITLE,
-					KEY_MUTE, KEY_VOLUMEUP,
-					KEY_VOLUMEDOWN, KEY_PREVIOUS, 0,
-					KEY_UP, KEY_DOWN, KEY_LEFT,
-					KEY_RIGHT, KEY_VIDEO, KEY_AUDIO,
-					KEY_MHP, KEY_EPG, KEY_TV,
-					0, KEY_NEXTSONG, KEY_EXIT,
-					KEY_CHANNELUP, 	KEY_CHANNELDOWN,
-					KEY_CHANNEL, 0,
-					KEY_PREVIOUSSONG, KEY_ENTER,
-					KEY_SLEEP, 0, 0, KEY_BLUE,
-					0, 0, 0, 0, KEY_GREEN, 0,
-					KEY_PAUSE, 0, KEY_REWIND,
-					0, KEY_FASTFORWARD, KEY_PLAY,
-					KEY_STOP, KEY_RECORD,
-					KEY_YELLOW, 0, 0, KEY_SELECT,
-					KEY_ZOOM, KEY_POWER, 0, 0
-			}
-		},
-		{ } /* Terminating entry */
-};
-
-static u32 ir_pos;
-static u32 ir_word;
-static u32 ir_toggle;
-
-#define RC5_PUSH_BIT(dst, bit, pos)	\
-	{ dst <<= 1; dst |= bit; pos++; }
-
-
-static void sms_ir_rc5_event(struct smscore_device_t *coredev,
-				u32 toggle, u32 addr, u32 cmd)
-{
-	bool toggle_changed;
-	u16 keycode;
-
-	sms_log("IR RC5 word: address %d, command %d, toggle %d",
-				addr, cmd, toggle);
-
-	toggle_changed = ir_toggle != toggle;
-	/* keep toggle */
-	ir_toggle = toggle;
-
-	if (addr !=
-		keyboard_layout_maps[coredev->ir.ir_kb_type].rc5_kbd_address)
-		return; /* Check for valid address */
-
-	keycode =
-		keyboard_layout_maps
-		[coredev->ir.ir_kb_type].keyboard_layout_map[cmd];
-
-	if (!toggle_changed &&
-			(keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN))
-		return; /* accept only repeated volume, reject other keys */
-
-	sms_log("kernel input keycode (from ir) %d", keycode);
-	input_report_key(coredev->ir.input_dev, keycode, 1);
-	input_sync(coredev->ir.input_dev);
-
-}
-
-/* decode raw bit pattern to RC5 code */
-/* taken from ir-functions.c */
-static u32 ir_rc5_decode(unsigned int code)
-{
-/*	unsigned int org_code = code;*/
-	unsigned int pair;
-	unsigned int rc5 = 0;
-	int i;
-
-	for (i = 0; i < 14; ++i) {
-		pair = code & 0x3;
-		code >>= 2;
-
-		rc5 <<= 1;
-		switch (pair) {
-		case 0:
-		case 2:
-			break;
-		case 1:
-			rc5 |= 1;
-			break;
-		case 3:
-/*	dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/
-			sms_log("bad code");
-			return 0;
-		}
-	}
-/*
-	dprintk(1, "ir-common: code=%x, rc5=%x, start=%x,
-		toggle=%x, address=%x, "
-		"instr=%x\n", rc5, org_code, RC5_START(rc5),
-		RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
-*/
-	return rc5;
-}
-
-static void sms_rc5_parse_word(struct smscore_device_t *coredev)
-{
-	#define RC5_START(x)    (((x)>>12)&3)
-	#define RC5_TOGGLE(x)   (((x)>>11)&1)
-	#define RC5_ADDR(x)     (((x)>>6)&0x1F)
-	#define RC5_INSTR(x)    ((x)&0x3F)
-
-	int i, j;
-	u32 rc5_word = 0;
-
-	/* Reverse the IR word direction */
-	for (i = 0 ; i < 28 ; i++)
-		RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j)
-
-	rc5_word = ir_rc5_decode(rc5_word);
-	/* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
-
-	sms_ir_rc5_event(coredev,
-				RC5_TOGGLE(rc5_word),
-				RC5_ADDR(rc5_word),
-				RC5_INSTR(rc5_word));
-}
-
-
-static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev,
-		s32 ir_sample)
-{
-	#define RC5_TIME_GRANULARITY	200
-	#define RC5_DEF_BIT_TIME		889
-	#define RC5_MAX_SAME_BIT_CONT	4
-	#define RC5_WORD_LEN			27 /* 28 bit */
-
-	u32 i, j;
-	s32 delta_time;
-	u32 time = (ir_sample > 0) ? ir_sample : (0-ir_sample);
-	u32 level = (ir_sample < 0) ? 0 : 1;
-
-	for (i = RC5_MAX_SAME_BIT_CONT; i > 0; i--) {
-		delta_time = time - (i*RC5_DEF_BIT_TIME) + RC5_TIME_GRANULARITY;
-		if (delta_time < 0)
-			continue; /* not so many consecutive bits */
-		if (delta_time > (2 * RC5_TIME_GRANULARITY)) {
-			/* timeout */
-			if (ir_pos == (RC5_WORD_LEN-1))
-				/* complete last bit */
-				RC5_PUSH_BIT(ir_word, level, ir_pos)
-
-			if (ir_pos == RC5_WORD_LEN)
-				sms_rc5_parse_word(coredev);
-			else if (ir_pos) /* timeout within a word */
-				sms_log("IR error parsing a word");
-
-			ir_pos = 0;
-			ir_word = 0;
-			/* sms_log("timeout %d", time); */
-			break;
-		}
-		/* The time is within the range of this number of bits */
-		for (j = 0 ; j < i ; j++)
-			RC5_PUSH_BIT(ir_word, level, ir_pos)
-
-		break;
-	}
-}
+#define MODULE_NAME "smsmdtv"
 
 void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
 {
-	#define IR_DATA_RECEIVE_MAX_LEN	520 /* 128*4 + 4 + 4 */
-	u32 i;
-	enum ir_protocol ir_protocol =
-			keyboard_layout_maps[coredev->ir.ir_kb_type]
-					     .ir_protocol;
-	s32 *samples;
-	int count = len>>2;
+	int i;
+	const s32 *samples = (const void *)buf;
 
-	samples = (s32 *)buf;
-/*	sms_log("IR buffer received, length = %d", count);*/
+	for (i = 0; i < len >> 2; i++) {
+		struct ir_raw_event ev;
 
-	for (i = 0; i < count; i++)
-		if (ir_protocol == IR_RC5)
-			sms_rc5_accumulate_bits(coredev, samples[i]);
-	/*  IR_RCMM not implemented */
+		ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
+		ev.pulse = (samples[i] > 0) ? false : true;
+
+		ir_raw_event_store(coredev->ir.input_dev, &ev);
+	}
+	ir_raw_event_handle(coredev->ir.input_dev);
 }
 
 int sms_ir_init(struct smscore_device_t *coredev)
 {
 	struct input_dev *input_dev;
+	int board_id = smscore_get_board_id(coredev);
 
 	sms_log("Allocating input device");
 	input_dev = input_allocate_device();
@@ -256,33 +63,38 @@
 	}
 
 	coredev->ir.input_dev = input_dev;
-	coredev->ir.ir_kb_type =
-		sms_get_board(smscore_get_board_id(coredev))->ir_kb_type;
-	coredev->ir.keyboard_layout_map =
-		keyboard_layout_maps[coredev->ir.ir_kb_type].
-				keyboard_layout_map;
-	sms_log("IR remote keyboard type is %d", coredev->ir.ir_kb_type);
 
 	coredev->ir.controller = 0;	/* Todo: vega/nova SPI number */
 	coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
 	sms_log("IR port %d, timeout %d ms",
 			coredev->ir.controller, coredev->ir.timeout);
 
-	snprintf(coredev->ir.name,
-				IR_DEV_NAME_MAX_LEN,
-				"SMS IR w/kbd type %d",
-				coredev->ir.ir_kb_type);
+	snprintf(coredev->ir.name, sizeof(coredev->ir.name),
+		 "SMS IR (%s)", sms_get_board(board_id)->name);
+
+	strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys));
+	strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys));
+
 	input_dev->name = coredev->ir.name;
-	input_dev->phys = coredev->ir.name;
+	input_dev->phys = coredev->ir.phys;
 	input_dev->dev.parent = coredev->device;
 
-	/* Key press events only */
-	input_dev->evbit[0] = BIT_MASK(EV_KEY);
-	input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+#if 0
+	/* TODO: properly initialize the parameters bellow */
+	input_dev->id.bustype = BUS_USB;
+	input_dev->id.version = 1;
+	input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+	input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+#endif
+
+	coredev->ir.props.priv = coredev;
+	coredev->ir.props.driver_type = RC_DRIVER_IR_RAW;
+	coredev->ir.props.allowed_protos = IR_TYPE_ALL;
 
 	sms_log("Input device (IR) %s is set for key events", input_dev->name);
 
-	if (input_register_device(input_dev)) {
+	if (ir_input_register(input_dev, sms_get_board(board_id)->rc_codes,
+			      &coredev->ir.props, MODULE_NAME)) {
 		sms_err("Failed to register device");
 		input_free_device(input_dev);
 		return -EACCES;
@@ -294,8 +106,7 @@
 void sms_ir_exit(struct smscore_device_t *coredev)
 {
 	if (coredev->ir.input_dev)
-		input_unregister_device(coredev->ir.input_dev);
+		ir_input_unregister(coredev->ir.input_dev);
 
 	sms_log("");
 }
-
diff --git a/drivers/media/dvb/siano/smsir.h b/drivers/media/dvb/siano/smsir.h
index b7d703e..926e247 100644
--- a/drivers/media/dvb/siano/smsir.h
+++ b/drivers/media/dvb/siano/smsir.h
@@ -4,6 +4,11 @@
 MDTV receiver kernel modules.
 Copyright (C) 2006-2009, Uri Shkolnik
 
+ Copyright (c) 2010 - Mauro Carvalho Chehab
+	- Ported the driver to use rc-core
+	- IR raw event decoding is now done at rc-core
+	- Code almost re-written
+
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 2 of the License, or
@@ -23,63 +28,21 @@
 #define __SMS_IR_H__
 
 #include <linux/input.h>
+#include <media/ir-core.h>
 
-#define IR_DEV_NAME_MAX_LEN		23 /* "SMS IR kbd type nn\0" */
-#define IR_KEYBOARD_LAYOUT_SIZE	64
 #define IR_DEFAULT_TIMEOUT		100
 
-enum ir_kb_type {
-	SMS_IR_KB_DEFAULT_TV,
-	SMS_IR_KB_HCW_SILVER
-};
-
-enum rc5_keyboard_address {
-	KEYBOARD_ADDRESS_TV1 = 0,
-	KEYBOARD_ADDRESS_TV2 = 1,
-	KEYBOARD_ADDRESS_TELETEXT = 2,
-	KEYBOARD_ADDRESS_VIDEO = 3,
-	KEYBOARD_ADDRESS_LV1 = 4,
-	KEYBOARD_ADDRESS_VCR1 = 5,
-	KEYBOARD_ADDRESS_VCR2 = 6,
-	KEYBOARD_ADDRESS_EXPERIMENTAL = 7,
-	KEYBOARD_ADDRESS_SAT1 = 8,
-	KEYBOARD_ADDRESS_CAMERA = 9,
-	KEYBOARD_ADDRESS_SAT2 = 10,
-	KEYBOARD_ADDRESS_CDV = 12,
-	KEYBOARD_ADDRESS_CAMCORDER = 13,
-	KEYBOARD_ADDRESS_PRE_AMP = 16,
-	KEYBOARD_ADDRESS_TUNER = 17,
-	KEYBOARD_ADDRESS_RECORDER1 = 18,
-	KEYBOARD_ADDRESS_PRE_AMP1 = 19,
-	KEYBOARD_ADDRESS_CD_PLAYER = 20,
-	KEYBOARD_ADDRESS_PHONO = 21,
-	KEYBOARD_ADDRESS_SATA = 22,
-	KEYBOARD_ADDRESS_RECORDER2 = 23,
-	KEYBOARD_ADDRESS_CDR = 26,
-	KEYBOARD_ADDRESS_LIGHTING = 29,
-	KEYBOARD_ADDRESS_LIGHTING1 = 30, /* KEYBOARD_ADDRESS_HCW_SILVER */
-	KEYBOARD_ADDRESS_PHONE = 31,
-	KEYBOARD_ADDRESS_NOT_RC5 = 0xFFFF
-};
-
-enum ir_protocol {
-	IR_RC5,
-	IR_RCMM
-};
-
-struct keyboard_layout_map_t {
-	enum ir_protocol ir_protocol;
-	enum rc5_keyboard_address rc5_kbd_address;
-	u16 keyboard_layout_map[IR_KEYBOARD_LAYOUT_SIZE];
-};
-
 struct smscore_device_t;
 
 struct ir_t {
 	struct input_dev *input_dev;
-	enum ir_kb_type ir_kb_type;
-	char name[IR_DEV_NAME_MAX_LEN+1];
-	u16 *keyboard_layout_map;
+	char name[40];
+	char phys[32];
+
+	char *rc_codes;
+	u64 protocol;
+	struct ir_dev_props props;
+
 	u32 timeout;
 	u32 controller;
 };
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
index a9c27fb..50d4338 100644
--- a/drivers/media/dvb/siano/smsusb.c
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -352,8 +352,7 @@
 	params.num_buffers = MAX_BUFFERS;
 	params.sendrequest_handler = smsusb_sendrequest;
 	params.context = dev;
-	snprintf(params.devpath, sizeof(params.devpath),
-		 "usb\\%d-%s", dev->udev->bus->busnum, dev->udev->devpath);
+	usb_make_path(dev->udev, params.devpath, sizeof(params.devpath));
 
 	/* register in smscore */
 	rc = smscore_register_device(&params, &dev->coredev);
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 47075fc..9927a59 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -748,7 +748,7 @@
 		struct v4l2_tuner *tuner)
 {
 	struct si470x_device *radio = video_drvdata(file);
-	int retval = -EINVAL;
+	int retval = 0;
 
 	/* safety checks */
 	retval = si470x_disconnect_check(radio);
diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c
index ab63dd5..fc7f4b7 100644
--- a/drivers/media/radio/si4713-i2c.c
+++ b/drivers/media/radio/si4713-i2c.c
@@ -1009,8 +1009,10 @@
 			goto exit;
 		}
 		rval = copy_from_user(ps_name, control->string, len);
-		if (rval < 0)
+		if (rval) {
+			rval = -EFAULT;
 			goto exit;
+		}
 		ps_name[len] = '\0';
 
 		if (strlen(ps_name) % vqc.step) {
@@ -1031,8 +1033,10 @@
 			goto exit;
 		}
 		rval = copy_from_user(radio_text, control->string, len);
-		if (rval < 0)
+		if (rval) {
+			rval = -EFAULT;
 			goto exit;
+		}
 		radio_text[len] = '\0';
 
 		if (strlen(radio_text) % vqc.step) {
@@ -1367,6 +1371,8 @@
 		}
 		rval = copy_to_user(control->string, sdev->rds_info.ps_name,
 					strlen(sdev->rds_info.ps_name) + 1);
+		if (rval)
+			rval = -EFAULT;
 		break;
 
 	case V4L2_CID_RDS_TX_RADIO_TEXT:
@@ -1377,6 +1383,8 @@
 		}
 		rval = copy_to_user(control->string, sdev->rds_info.radio_text,
 					strlen(sdev->rds_info.radio_text) + 1);
+		if (rval)
+			rval = -EFAULT;
 		break;
 
 	default:
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 27e2acc..2e15903 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -517,19 +517,6 @@
 
 endmenu # encoder / decoder chips
 
-config DISPLAY_DAVINCI_DM646X_EVM
-	tristate "DM646x EVM Video Display"
-	depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
-	select VIDEOBUF_DMA_CONTIG
-	select VIDEO_DAVINCI_VPIF
-	select VIDEO_ADV7343
-	select VIDEO_THS7303
-	help
-	  Support for DM6467 based display device.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called vpif_display.
-
 config VIDEO_SH_VOU
 	tristate "SuperH VOU video output driver"
 	depends on VIDEO_DEV && ARCH_SHMOBILE
@@ -537,29 +524,22 @@
 	help
 	  Support for the Video Output Unit (VOU) on SuperH SoCs.
 
-config CAPTURE_DAVINCI_DM646X_EVM
-	tristate "DM646x EVM Video Capture"
-	depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+config VIDEO_VIU
+	tristate "Freescale VIU Video Driver"
+	depends on VIDEO_V4L2 && PPC_MPC512x
 	select VIDEOBUF_DMA_CONTIG
-	select VIDEO_DAVINCI_VPIF
-	help
-	  Support for DM6467 based capture device.
+	default y
+	---help---
+	  Support for Freescale VIU video driver. This device captures
+	  video data, or overlays video on DIU frame buffer.
 
-	  To compile this driver as a module, choose M here: the
-	  module will be called vpif_capture.
-
-config VIDEO_DAVINCI_VPIF
-	tristate "DaVinci VPIF Driver"
-	depends on DISPLAY_DAVINCI_DM646X_EVM
-	help
-	  Support for DaVinci VPIF Driver.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called vpif.
+	  Say Y here if you want to enable VIU device on MPC5121e Rev2+.
+	  In doubt, say N.
 
 config VIDEO_VIVI
 	tristate "Virtual Video Driver"
-	depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FONTS
+	depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
+	depends on (FRAMEBUFFER_CONSOLE || STI_CONSOLE) && FONTS
 	select FONT_8x16
 	select VIDEOBUF_VMALLOC
 	default n
@@ -570,66 +550,7 @@
 	  Say Y here if you want to test video apps or debug V4L devices.
 	  In doubt, say N.
 
-config VIDEO_VPSS_SYSTEM
-	tristate "VPSS System module driver"
-	depends on ARCH_DAVINCI
-	help
-	  Support for vpss system module for video driver
-
-config VIDEO_VPFE_CAPTURE
-	tristate "VPFE Video Capture Driver"
-	depends on VIDEO_V4L2 && ARCH_DAVINCI
-	select VIDEOBUF_DMA_CONTIG
-	help
-	  Support for DMXXXX VPFE based frame grabber. This is the
-	  common V4L2 module for following DMXXX SoCs from Texas
-	  Instruments:- DM6446 & DM355.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called vpfe-capture.
-
-config VIDEO_DM6446_CCDC
-	tristate "DM6446 CCDC HW module"
-	depends on ARCH_DAVINCI_DM644x && VIDEO_VPFE_CAPTURE
-	select VIDEO_VPSS_SYSTEM
-	default y
-	help
-	   Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
-	   with decoder modules such as TVP5146 over BT656 or
-	   sensor module such as MT9T001 over a raw interface. This
-	   module configures the interface and CCDC/ISIF to do
-	   video frame capture from slave decoders.
-
-	   To compile this driver as a module, choose M here: the
-	   module will be called vpfe.
-
-config VIDEO_DM355_CCDC
-	tristate "DM355 CCDC HW module"
-	depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
-	select VIDEO_VPSS_SYSTEM
-	default y
-	help
-	   Enables DM355 CCD hw module. DM355 CCDC hw interfaces
-	   with decoder modules such as TVP5146 over BT656 or
-	   sensor module such as MT9T001 over a raw interface. This
-	   module configures the interface and CCDC/ISIF to do
-	   video frame capture from a slave decoders
-
-	   To compile this driver as a module, choose M here: the
-	   module will be called vpfe.
-
-config VIDEO_ISIF
-	tristate "ISIF HW module"
-	depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
-	select VIDEO_VPSS_SYSTEM
-	default y
-	help
-	   Enables ISIF hw module. This is the hardware module for
-	   configuring ISIF in VPFE to capture Raw Bayer RGB data  from
-	   a image sensor or YUV data from a YUV source.
-
-	   To compile this driver as a module, choose M here: the
-	   module will be called vpfe.
+source "drivers/media/video/davinci/Kconfig"
 
 source "drivers/media/video/omap/Kconfig"
 
@@ -955,6 +876,12 @@
 	---help---
 	  This is a v4l2 driver for the PXA27x Quick Capture Interface
 
+config VIDEO_SH_MOBILE_CSI2
+	tristate "SuperH Mobile MIPI CSI-2 Interface driver"
+	depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK
+	---help---
+	  This is a v4l2 driver for the SuperH MIPI CSI-2 Interface
+
 config VIDEO_SH_MOBILE_CEU
 	tristate "SuperH Mobile CEU Interface driver"
 	depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
@@ -1013,61 +940,6 @@
 
 source "drivers/media/video/et61x251/Kconfig"
 
-config VIDEO_OVCAMCHIP
-	tristate "OmniVision Camera Chip support (DEPRECATED)"
-	depends on I2C && VIDEO_V4L1
-	default n
-	---help---
-	  This driver is DEPRECATED please use the gspca ov519 module
-	  instead. Note that for the ov511 / ov518 support of the gspca module
-	  you need atleast version 0.6.0 of libv4l and for the w9968cf
-	  atleast version 0.6.3 of libv4l.
-
-	  Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
-	  This driver is intended to be used with the ov511 and w9968cf USB
-	  camera drivers.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called ovcamchip.
-
-config USB_W9968CF
-	tristate "USB W996[87]CF JPEG Dual Mode Camera support (DEPRECATED)"
-	depends on VIDEO_V4L1 && I2C && VIDEO_OVCAMCHIP
-	default n
-	---help---
-	  This driver is DEPRECATED please use the gspca ov519 module
-	  instead. Note that for the w9968cf support of the gspca module
-	  you need atleast version 0.6.3 of libv4l.
-
-	  Say Y here if you want support for cameras based on OV681 or
-	  Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
-
-	  This driver has an optional plugin, which is distributed as a
-	  separate module only (released under GPL). It allows to use higher
-	  resolutions and framerates, but cannot be included in the official
-	  Linux kernel for performance purposes.
-
-	  See <file:Documentation/video4linux/w9968cf.txt> for more info.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called w9968cf.
-
-config USB_OV511
-	tristate "USB OV511 Camera support (DEPRECATED)"
-	depends on VIDEO_V4L1
-	default n
-	---help---
-	  This driver is DEPRECATED please use the gspca ov519 module
-	  instead. Note that for the ov511 / ov518 support of the gspca module
-	  you need atleast version 0.6.0 of libv4l.
-
-	  Say Y here if you want to connect this type of camera to your
-	  computer's USB port. See <file:Documentation/video4linux/ov511.txt>
-	  for more information and for a list of supported cameras.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called ov511.
-
 config USB_SE401
 	tristate "USB SE401 Camera support"
 	depends on VIDEO_V4L1
@@ -1081,25 +953,6 @@
 
 source "drivers/media/video/sn9c102/Kconfig"
 
-config USB_STV680
-	tristate "USB STV680 (Pencam) Camera support (DEPRECATED)"
-	depends on VIDEO_V4L1
-	default n
-	---help---
-	  This driver is DEPRECATED please use the gspca stv0680 module
-	  instead. Note that for the gspca stv0680 module you need
-	  atleast version 0.6.3 of libv4l.
-
-	  Say Y here if you want to connect this type of camera to your
-	  computer's USB port. This includes the Pencam line of cameras.
-	  See <file:Documentation/video4linux/stv680.txt> for more information
-	  and for a list of supported cameras.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called stv680.
-
-source "drivers/media/video/zc0301/Kconfig"
-
 source "drivers/media/video/pwc/Kconfig"
 
 config USB_ZR364XX
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index b08bd2b..1051ecc6 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -105,7 +105,6 @@
 obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
 obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
-obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
 obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
 obj-$(CONFIG_VIDEO_MXB) += mxb.o
 obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
@@ -127,17 +126,13 @@
 obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
 
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
-obj-$(CONFIG_USB_OV511)         += ov511.o
 obj-$(CONFIG_USB_SE401)         += se401.o
-obj-$(CONFIG_USB_STV680)        += stv680.o
-obj-$(CONFIG_USB_W9968CF)       += w9968cf.o
 obj-$(CONFIG_USB_ZR364XX)       += zr364xx.o
 obj-$(CONFIG_USB_STKWEBCAM)     += stkwebcam.o
 
 obj-$(CONFIG_USB_SN9C102)       += sn9c102/
 obj-$(CONFIG_USB_ET61X251)      += et61x251/
 obj-$(CONFIG_USB_PWC)           += pwc/
-obj-$(CONFIG_USB_ZC0301)        += zc0301/
 obj-$(CONFIG_USB_GSPCA)         += gspca/
 
 obj-$(CONFIG_VIDEO_HDPVR)	+= hdpvr/
@@ -151,6 +146,7 @@
 obj-$(CONFIG_VIDEO_IVTV) += ivtv/
 obj-$(CONFIG_VIDEO_CX18) += cx18/
 
+obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
@@ -165,6 +161,7 @@
 obj-$(CONFIG_VIDEO_MX2)			+= mx2_camera.o
 obj-$(CONFIG_VIDEO_MX3)			+= mx3_camera.o
 obj-$(CONFIG_VIDEO_PXA27x)		+= pxa_camera.o
+obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2)	+= sh_mobile_csi2.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)	+= sh_mobile_ceu_camera.o
 
 obj-$(CONFIG_ARCH_DAVINCI)		+= davinci/
@@ -178,7 +175,7 @@
 
 obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 
-obj-$(CONFIG_ARCH_DAVINCI)	+= davinci/
+obj-y	+= davinci/
 
 obj-$(CONFIG_ARCH_OMAP)	+= omap/
 
diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c
index 1573392..b388654 100644
--- a/drivers/media/video/ak881x.c
+++ b/drivers/media/video/ak881x.c
@@ -126,7 +126,7 @@
 	v4l_bound_align_image(&mf->width, 0, 720, 2,
 			      &mf->height, 0, ak881x->lines, 1, 0);
 	mf->field	= V4L2_FIELD_INTERLACED;
-	mf->code	= V4L2_MBUS_FMT_YUYV8_2X8_LE;
+	mf->code	= V4L2_MBUS_FMT_YUYV8_2X8;
 	mf->colorspace	= V4L2_COLORSPACE_SMPTE170M;
 
 	return 0;
@@ -136,7 +136,7 @@
 			     struct v4l2_mbus_framefmt *mf)
 {
 	if (mf->field != V4L2_FIELD_INTERLACED ||
-	    mf->code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+	    mf->code != V4L2_MBUS_FMT_YUYV8_2X8)
 		return -EINVAL;
 
 	return ak881x_try_g_mbus_fmt(sd, mf);
@@ -148,7 +148,7 @@
 	if (index)
 		return -EINVAL;
 
-	*code = V4L2_MBUS_FMT_YUYV8_2X8_LE;
+	*code = V4L2_MBUS_FMT_YUYV8_2X8;
 	return 0;
 }
 
diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile
index 4d26231..5c7f2f7 100644
--- a/drivers/media/video/au0828/Makefile
+++ b/drivers/media/video/au0828/Makefile
@@ -1,4 +1,4 @@
-au0828-objs	:= au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o
+au0828-objs	:= au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o au0828-vbi.o
 
 obj-$(CONFIG_VIDEO_AU0828) += au0828.o
 
diff --git a/drivers/media/video/au0828/au0828-vbi.c b/drivers/media/video/au0828/au0828-vbi.c
new file mode 100644
index 0000000..63f5930
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-vbi.c
@@ -0,0 +1,138 @@
+/*
+   au0828-vbi.c - VBI driver for au0828
+
+   Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+
+   This work was sponsored by GetWellNetwork 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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include "au0828.h"
+
+static unsigned int vbibufs = 5;
+module_param(vbibufs, int, 0644);
+MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
+
+/* ------------------------------------------------------------------ */
+
+static void
+free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
+{
+	struct au0828_fh     *fh  = vq->priv_data;
+	struct au0828_dev    *dev = fh->dev;
+	unsigned long flags = 0;
+	if (in_interrupt())
+		BUG();
+
+	/* We used to wait for the buffer to finish here, but this didn't work
+	   because, as we were keeping the state as VIDEOBUF_QUEUED,
+	   videobuf_queue_cancel marked it as finished for us.
+	   (Also, it could wedge forever if the hardware was misconfigured.)
+
+	   This should be safe; by the time we get here, the buffer isn't
+	   queued anymore. If we ever start marking the buffers as
+	   VIDEOBUF_ACTIVE, it won't be, though.
+	*/
+	spin_lock_irqsave(&dev->slock, flags);
+	if (dev->isoc_ctl.vbi_buf == buf)
+		dev->isoc_ctl.vbi_buf = NULL;
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	videobuf_vmalloc_free(&buf->vb);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	struct au0828_fh     *fh  = q->priv_data;
+	struct au0828_dev    *dev = fh->dev;
+
+	*size = dev->vbi_width * dev->vbi_height * 2;
+
+	if (0 == *count)
+		*count = vbibufs;
+	if (*count < 2)
+		*count = 2;
+	if (*count > 32)
+		*count = 32;
+	return 0;
+}
+
+static int
+vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+	    enum v4l2_field field)
+{
+	struct au0828_fh     *fh  = q->priv_data;
+	struct au0828_dev    *dev = fh->dev;
+	struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+	int                  rc = 0;
+
+	buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
+
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	buf->vb.width  = dev->vbi_width;
+	buf->vb.height = dev->vbi_height;
+	buf->vb.field  = field;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		rc = videobuf_iolock(q, &buf->vb, NULL);
+		if (rc < 0)
+			goto fail;
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+fail:
+	free_buffer(q, buf);
+	return rc;
+}
+
+static void
+vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct au0828_buffer    *buf     = container_of(vb,
+							struct au0828_buffer,
+							vb);
+	struct au0828_fh        *fh      = vq->priv_data;
+	struct au0828_dev       *dev     = fh->dev;
+	struct au0828_dmaqueue  *vbiq    = &dev->vbiq;
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue, &vbiq->active);
+}
+
+static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+	free_buffer(q, buf);
+}
+
+struct videobuf_queue_ops au0828_vbi_qops = {
+	.buf_setup    = vbi_setup,
+	.buf_prepare  = vbi_prepare,
+	.buf_queue    = vbi_queue,
+	.buf_release  = vbi_release,
+};
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
index 52f25aa..7989a7b 100644
--- a/drivers/media/video/au0828/au0828-video.c
+++ b/drivers/media/video/au0828/au0828-video.c
@@ -314,6 +314,23 @@
 	wake_up(&buf->vb.done);
 }
 
+static inline void vbi_buffer_filled(struct au0828_dev *dev,
+				     struct au0828_dmaqueue *dma_q,
+				     struct au0828_buffer *buf)
+{
+	/* Advice that buffer was filled */
+	au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+	buf->vb.state = VIDEOBUF_DONE;
+	buf->vb.field_count++;
+	do_gettimeofday(&buf->vb.ts);
+
+	dev->isoc_ctl.vbi_buf = NULL;
+
+	list_del(&buf->vb.queue);
+	wake_up(&buf->vb.done);
+}
+
 /*
  * Identify the buffer header type and properly handles
  */
@@ -327,6 +344,9 @@
 	int  linesdone, currlinedone, offset, lencopy, remain;
 	int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */
 
+	if (len == 0)
+		return;
+
 	if (dma_q->pos + len > buf->vb.size)
 		len = buf->vb.size - dma_q->pos;
 
@@ -414,17 +434,98 @@
 	return;
 }
 
+static void au0828_copy_vbi(struct au0828_dev *dev,
+			      struct au0828_dmaqueue  *dma_q,
+			      struct au0828_buffer *buf,
+			      unsigned char *p,
+			      unsigned char *outp, unsigned long len)
+{
+	unsigned char *startwrite, *startread;
+	int bytesperline;
+	int i, j = 0;
+
+	if (dev == NULL) {
+		au0828_isocdbg("dev is null\n");
+		return;
+	}
+
+	if (dma_q == NULL) {
+		au0828_isocdbg("dma_q is null\n");
+		return;
+	}
+	if (buf == NULL)
+		return;
+	if (p == NULL) {
+		au0828_isocdbg("p is null\n");
+		return;
+	}
+	if (outp == NULL) {
+		au0828_isocdbg("outp is null\n");
+		return;
+	}
+
+	bytesperline = dev->vbi_width;
+
+	if (dma_q->pos + len > buf->vb.size)
+		len = buf->vb.size - dma_q->pos;
+
+	startread = p;
+	startwrite = outp + (dma_q->pos / 2);
+
+	/* Make sure the bottom field populates the second half of the frame */
+	if (buf->top_field == 0)
+		startwrite += bytesperline * dev->vbi_height;
+
+	for (i = 0; i < len; i += 2)
+		startwrite[j++] = startread[i+1];
+
+	dma_q->pos += len;
+}
+
+
+/*
+ * video-buf generic routine to get the next available VBI buffer
+ */
+static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q,
+				    struct au0828_buffer **buf)
+{
+	struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vbiq);
+	char *outp;
+
+	if (list_empty(&dma_q->active)) {
+		au0828_isocdbg("No active queue to serve\n");
+		dev->isoc_ctl.vbi_buf = NULL;
+		*buf = NULL;
+		return;
+	}
+
+	/* Get the next buffer */
+	*buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
+	/* Cleans up buffer - Usefull for testing for frame/URB loss */
+	outp = videobuf_to_vmalloc(&(*buf)->vb);
+	memset(outp, 0x00, (*buf)->vb.size);
+
+	dev->isoc_ctl.vbi_buf = *buf;
+
+	return;
+}
+
 /*
  * Controls the isoc copy of each urb packet
  */
 static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
 {
 	struct au0828_buffer    *buf;
+	struct au0828_buffer    *vbi_buf;
 	struct au0828_dmaqueue  *dma_q = urb->context;
+	struct au0828_dmaqueue  *vbi_dma_q = &dev->vbiq;
 	unsigned char *outp = NULL;
+	unsigned char *vbioutp = NULL;
 	int i, len = 0, rc = 1;
 	unsigned char *p;
 	unsigned char fbyte;
+	unsigned int vbi_field_size;
+	unsigned int remain, lencopy;
 
 	if (!dev)
 		return 0;
@@ -443,6 +544,10 @@
 	if (buf != NULL)
 		outp = videobuf_to_vmalloc(&buf->vb);
 
+	vbi_buf = dev->isoc_ctl.vbi_buf;
+	if (vbi_buf != NULL)
+		vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
+
 	for (i = 0; i < urb->number_of_packets; i++) {
 		int status = urb->iso_frame_desc[i].status;
 
@@ -472,6 +577,19 @@
 			au0828_isocdbg("Video frame %s\n",
 				       (fbyte & 0x40) ? "odd" : "even");
 			if (!(fbyte & 0x40)) {
+				/* VBI */
+				if (vbi_buf != NULL)
+					vbi_buffer_filled(dev,
+							  vbi_dma_q,
+							  vbi_buf);
+				vbi_get_next_buf(vbi_dma_q, &vbi_buf);
+				if (vbi_buf == NULL)
+					vbioutp = NULL;
+				else
+					vbioutp = videobuf_to_vmalloc(
+						&vbi_buf->vb);
+
+				/* Video */
 				if (buf != NULL)
 					buffer_filled(dev, dma_q, buf);
 				get_next_buf(dma_q, &buf);
@@ -488,9 +606,36 @@
 					buf->top_field = 0;
 			}
 
+			if (vbi_buf != NULL) {
+				if (fbyte & 0x40)
+					vbi_buf->top_field = 1;
+				else
+					vbi_buf->top_field = 0;
+			}
+
+			dev->vbi_read = 0;
+			vbi_dma_q->pos = 0;
 			dma_q->pos = 0;
 		}
-		if (buf != NULL)
+
+		vbi_field_size = dev->vbi_width * dev->vbi_height * 2;
+		if (dev->vbi_read < vbi_field_size) {
+			remain  = vbi_field_size - dev->vbi_read;
+			if (len < remain)
+				lencopy = len;
+			else
+				lencopy = remain;
+
+			if (vbi_buf != NULL)
+				au0828_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+						vbioutp, len);
+
+			len -= lencopy;
+			p += lencopy;
+			dev->vbi_read += lencopy;
+		}
+
+		if (dev->vbi_read >= vbi_field_size && buf != NULL)
 			au0828_copy_video(dev, dma_q, buf, p, outp, len);
 	}
 	return rc;
@@ -642,7 +787,7 @@
 	au0828_writereg(d, 0x114, 0xa0);
 	au0828_writereg(d, 0x115, 0x05);
 	/* set y position */
-	au0828_writereg(d, 0x112, 0x02);
+	au0828_writereg(d, 0x112, 0x00);
 	au0828_writereg(d, 0x113, 0x00);
 	au0828_writereg(d, 0x116, 0xf2);
 	au0828_writereg(d, 0x117, 0x00);
@@ -703,47 +848,83 @@
 
 
 /* Usage lock check functions */
-static int res_get(struct au0828_fh *fh)
+static int res_get(struct au0828_fh *fh, unsigned int bit)
 {
-	struct au0828_dev *dev = fh->dev;
-	int		 rc   = 0;
+	struct au0828_dev    *dev = fh->dev;
 
-	/* This instance already has stream_on */
-	if (fh->stream_on)
-		return rc;
+	if (fh->resources & bit)
+		/* have it already allocated */
+		return 1;
 
-	if (dev->stream_on)
-		return -EBUSY;
-
-	dev->stream_on = 1;
-	fh->stream_on  = 1;
-	return rc;
+	/* is it free? */
+	mutex_lock(&dev->lock);
+	if (dev->resources & bit) {
+		/* no, someone else uses it */
+		mutex_unlock(&dev->lock);
+		return 0;
+	}
+	/* it's free, grab it */
+	fh->resources  |= bit;
+	dev->resources |= bit;
+	dprintk(1, "res: get %d\n", bit);
+	mutex_unlock(&dev->lock);
+	return 1;
 }
 
-static int res_check(struct au0828_fh *fh)
+static int res_check(struct au0828_fh *fh, unsigned int bit)
 {
-	return fh->stream_on;
+	return fh->resources & bit;
 }
 
-static void res_free(struct au0828_fh *fh)
+static int res_locked(struct au0828_dev *dev, unsigned int bit)
 {
-	struct au0828_dev *dev = fh->dev;
+	return dev->resources & bit;
+}
 
-	fh->stream_on = 0;
-	dev->stream_on = 0;
+static void res_free(struct au0828_fh *fh, unsigned int bits)
+{
+	struct au0828_dev    *dev = fh->dev;
+
+	BUG_ON((fh->resources & bits) != bits);
+
+	mutex_lock(&dev->lock);
+	fh->resources  &= ~bits;
+	dev->resources &= ~bits;
+	dprintk(1, "res: put %d\n", bits);
+	mutex_unlock(&dev->lock);
+}
+
+static int get_ressource(struct au0828_fh *fh)
+{
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return AU0828_RESOURCE_VIDEO;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		return AU0828_RESOURCE_VBI;
+	default:
+		BUG();
+		return 0;
+	}
 }
 
 static int au0828_v4l2_open(struct file *filp)
 {
 	int ret = 0;
+	struct video_device *vdev = video_devdata(filp);
 	struct au0828_dev *dev = video_drvdata(filp);
 	struct au0828_fh *fh;
-	int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	int type;
 
-#ifdef VBI_IS_WORKING
-	if (video_devdata(filp)->vfl_type == VFL_TYPE_GRABBER)
+	switch (vdev->vfl_type) {
+	case VFL_TYPE_GRABBER:
+		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		break;
+	case VFL_TYPE_VBI:
 		type = V4L2_BUF_TYPE_VBI_CAPTURE;
-#endif
+		break;
+	default:
+		return -EINVAL;
+	}
 
 	fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL);
 	if (NULL == fh) {
@@ -781,10 +962,21 @@
 	dev->users++;
 
 	videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
-				    NULL, &dev->slock, fh->type,
+				    NULL, &dev->slock,
+				    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 				    V4L2_FIELD_INTERLACED,
 				    sizeof(struct au0828_buffer), fh);
 
+	/* VBI Setup */
+	dev->vbi_width = 720;
+	dev->vbi_height = 1;
+	videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops,
+				    NULL, &dev->slock,
+				    V4L2_BUF_TYPE_VBI_CAPTURE,
+				    V4L2_FIELD_SEQ_TB,
+				    sizeof(struct au0828_buffer), fh);
+
+
 	return ret;
 }
 
@@ -794,17 +986,19 @@
 	struct au0828_fh *fh = filp->private_data;
 	struct au0828_dev *dev = fh->dev;
 
-	mutex_lock(&dev->lock);
-	if (res_check(fh))
-		res_free(fh);
+	if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
+		videobuf_stop(&fh->vb_vidq);
+		res_free(fh, AU0828_RESOURCE_VIDEO);
+	}
+
+	if (res_check(fh, AU0828_RESOURCE_VBI)) {
+		videobuf_stop(&fh->vb_vbiq);
+		res_free(fh, AU0828_RESOURCE_VBI);
+	}
 
 	if (dev->users == 1) {
-		videobuf_stop(&fh->vb_vidq);
-		videobuf_mmap_free(&fh->vb_vidq);
-
 		if (dev->dev_state & DEV_DISCONNECTED) {
 			au0828_analog_unregister(dev);
-			mutex_unlock(&dev->lock);
 			kfree(dev);
 			return 0;
 		}
@@ -823,10 +1017,11 @@
 			printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
 	}
 
+	videobuf_mmap_free(&fh->vb_vidq);
+	videobuf_mmap_free(&fh->vb_vbiq);
 	kfree(fh);
 	dev->users--;
 	wake_up_interruptible_nr(&dev->open, 1);
-	mutex_unlock(&dev->lock);
 	return 0;
 }
 
@@ -842,16 +1037,21 @@
 		return rc;
 
 	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		mutex_lock(&dev->lock);
-		rc = res_get(fh);
-		mutex_unlock(&dev->lock);
-
-		if (unlikely(rc < 0))
-			return rc;
+		if (res_locked(dev, AU0828_RESOURCE_VIDEO))
+			return -EBUSY;
 
 		return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
 					filp->f_flags & O_NONBLOCK);
 	}
+
+	if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		if (!res_get(fh, AU0828_RESOURCE_VBI))
+			return -EBUSY;
+
+		return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
+					    filp->f_flags & O_NONBLOCK);
+	}
+
 	return 0;
 }
 
@@ -865,17 +1065,17 @@
 	if (rc < 0)
 		return rc;
 
-	mutex_lock(&dev->lock);
-	rc = res_get(fh);
-	mutex_unlock(&dev->lock);
-
-	if (unlikely(rc < 0))
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		if (!res_get(fh, AU0828_RESOURCE_VIDEO))
+			return POLLERR;
+		return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		if (!res_get(fh, AU0828_RESOURCE_VBI))
+			return POLLERR;
+		return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
+	} else {
 		return POLLERR;
-
-	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
-		return POLLERR;
-
-	return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+	}
 }
 
 static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
@@ -888,14 +1088,10 @@
 	if (rc < 0)
 		return rc;
 
-	mutex_lock(&dev->lock);
-	rc = res_get(fh);
-	mutex_unlock(&dev->lock);
-
-	if (unlikely(rc < 0))
-		return rc;
-
-	rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+	else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
 
 	return rc;
 }
@@ -911,14 +1107,6 @@
 	maxwidth = 720;
 	maxheight = 480;
 
-#ifdef VBI_IS_WORKING
-	if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
-		dprintk(1, "VBI format set: to be supported!\n");
-		return 0;
-	}
-	if (format->type == V4L2_BUF_TYPE_VBI_CAPTURE)
-		return 0;
-#endif
 	if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
@@ -999,9 +1187,7 @@
 
 	/*set the device capabilities */
 	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-#ifdef VBI_IS_WORKING
 		V4L2_CAP_VBI_CAPTURE |
-#endif
 		V4L2_CAP_AUDIO |
 		V4L2_CAP_READWRITE |
 		V4L2_CAP_STREAMING |
@@ -1056,20 +1242,21 @@
 	struct au0828_dev *dev = fh->dev;
 	int rc;
 
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	mutex_lock(&dev->lock);
+
 	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
 		printk(KERN_INFO "%s queue busy\n", __func__);
 		rc = -EBUSY;
 		goto out;
 	}
 
-	if (dev->stream_on && !fh->stream_on) {
-		printk(KERN_INFO "%s device in use by another fh\n", __func__);
-		rc = -EBUSY;
-		goto out;
-	}
-
-	return au0828_set_format(dev, VIDIOC_S_FMT, f);
+	rc = au0828_set_format(dev, VIDIOC_S_FMT, f);
 out:
+	mutex_unlock(&dev->lock);
 	return rc;
 }
 
@@ -1300,6 +1487,29 @@
 	return 0;
 }
 
+
+/* RAW VBI ioctls */
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+				struct v4l2_format *format)
+{
+	struct au0828_fh      *fh  = priv;
+	struct au0828_dev     *dev = fh->dev;
+
+	format->fmt.vbi.samples_per_line = dev->vbi_width;
+	format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+	format->fmt.vbi.offset = 0;
+	format->fmt.vbi.flags = 0;
+	format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+
+	format->fmt.vbi.count[0] = dev->vbi_height;
+	format->fmt.vbi.count[1] = dev->vbi_height;
+	format->fmt.vbi.start[0] = 21;
+	format->fmt.vbi.start[1] = 284;
+
+	return 0;
+}
+
 static int vidioc_g_chip_ident(struct file *file, void *priv,
 	       struct v4l2_dbg_chip_ident *chip)
 {
@@ -1345,25 +1555,32 @@
 static int vidioc_streamon(struct file *file, void *priv,
 			   enum v4l2_buf_type type)
 {
-	struct au0828_fh *fh = priv;
-	struct au0828_dev *dev = fh->dev;
-	int rc;
+	struct au0828_fh      *fh  = priv;
+	struct au0828_dev     *dev = fh->dev;
+	int                   rc = -EINVAL;
 
 	rc = check_dev(dev);
 	if (rc < 0)
 		return rc;
 
+	if (unlikely(type != fh->type))
+		return -EINVAL;
+
+	dprintk(1, "vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
+		fh, type, fh->resources, dev->resources);
+
+	if (unlikely(!res_get(fh, get_ressource(fh))))
+		return -EBUSY;
+
 	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 		au0828_analog_stream_enable(dev);
 		v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
 	}
 
-	mutex_lock(&dev->lock);
-	rc = res_get(fh);
-
-	if (likely(rc >= 0))
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		rc = videobuf_streamon(&fh->vb_vidq);
-	mutex_unlock(&dev->lock);
+	else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		rc = videobuf_streamon(&fh->vb_vbiq);
 
 	return rc;
 }
@@ -1371,38 +1588,42 @@
 static int vidioc_streamoff(struct file *file, void *priv,
 			    enum v4l2_buf_type type)
 {
-	struct au0828_fh *fh = priv;
-	struct au0828_dev *dev = fh->dev;
-	int i;
-	int ret;
-	int rc;
+	struct au0828_fh      *fh  = priv;
+	struct au0828_dev     *dev = fh->dev;
+	int                   rc;
+	int                   i;
 
 	rc = check_dev(dev);
 	if (rc < 0)
 		return rc;
 
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
 		return -EINVAL;
 	if (type != fh->type)
 		return -EINVAL;
 
-	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+	dprintk(1, "vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
+		fh, type, fh->resources, dev->resources);
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 		v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
-		ret = au0828_stream_interrupt(dev);
-		if (ret != 0)
-			return ret;
-	}
+		rc = au0828_stream_interrupt(dev);
+		if (rc != 0)
+			return rc;
 
-	for (i = 0; i < AU0828_MAX_INPUT; i++) {
-		if (AUVI_INPUT(i).audio_setup == NULL)
-			continue;
-		(AUVI_INPUT(i).audio_setup)(dev, 0);
-	}
+		for (i = 0; i < AU0828_MAX_INPUT; i++) {
+			if (AUVI_INPUT(i).audio_setup == NULL)
+				continue;
+			(AUVI_INPUT(i).audio_setup)(dev, 0);
+		}
 
-	mutex_lock(&dev->lock);
-	videobuf_streamoff(&fh->vb_vidq);
-	res_free(fh);
-	mutex_unlock(&dev->lock);
+		videobuf_streamoff(&fh->vb_vidq);
+		res_free(fh, AU0828_RESOURCE_VIDEO);
+	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		videobuf_streamoff(&fh->vb_vbiq);
+		res_free(fh, AU0828_RESOURCE_VBI);
+	}
 
 	return 0;
 }
@@ -1527,19 +1748,11 @@
 	.vidioc_g_fmt_vid_cap       = vidioc_g_fmt_vid_cap,
 	.vidioc_try_fmt_vid_cap     = vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap       = vidioc_s_fmt_vid_cap,
-#ifdef VBI_IS_WORKING
 	.vidioc_g_fmt_vbi_cap       = vidioc_g_fmt_vbi_cap,
-	.vidioc_try_fmt_vbi_cap     = vidioc_s_fmt_vbi_cap,
-	.vidioc_s_fmt_vbi_cap       = vidioc_s_fmt_vbi_cap,
-#endif
+	.vidioc_s_fmt_vbi_cap       = vidioc_g_fmt_vbi_cap,
 	.vidioc_g_audio             = vidioc_g_audio,
 	.vidioc_s_audio             = vidioc_s_audio,
 	.vidioc_cropcap             = vidioc_cropcap,
-#ifdef VBI_IS_WORKING
-	.vidioc_g_fmt_sliced_vbi_cap   = vidioc_g_fmt_sliced_vbi_cap,
-	.vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
-	.vidioc_s_fmt_sliced_vbi_cap   = vidioc_try_set_sliced_vbi_cap,
-#endif
 	.vidioc_reqbufs             = vidioc_reqbufs,
 	.vidioc_querybuf            = vidioc_querybuf,
 	.vidioc_qbuf                = vidioc_qbuf,
@@ -1621,8 +1834,11 @@
 	spin_lock_init(&dev->slock);
 	mutex_init(&dev->lock);
 
+	/* init video dma queues */
 	INIT_LIST_HEAD(&dev->vidq.active);
 	INIT_LIST_HEAD(&dev->vidq.queued);
+	INIT_LIST_HEAD(&dev->vbiq.active);
+	INIT_LIST_HEAD(&dev->vbiq.queued);
 
 	dev->width = NTSC_STD_W;
 	dev->height = NTSC_STD_H;
@@ -1638,26 +1854,23 @@
 		return -ENOMEM;
 	}
 
-#ifdef VBI_IS_WORKING
+	/* allocate the VBI struct */
 	dev->vbi_dev = video_device_alloc();
 	if (NULL == dev->vbi_dev) {
 		dprintk(1, "Can't allocate vbi_device.\n");
 		kfree(dev->vdev);
 		return -ENOMEM;
 	}
-#endif
 
 	/* Fill the video capture device struct */
 	*dev->vdev = au0828_video_template;
 	dev->vdev->parent = &dev->usbdev->dev;
 	strcpy(dev->vdev->name, "au0828a video");
 
-#ifdef VBI_IS_WORKING
 	/* Setup the VBI device */
 	*dev->vbi_dev = au0828_video_template;
 	dev->vbi_dev->parent = &dev->usbdev->dev;
 	strcpy(dev->vbi_dev->name, "au0828a vbi");
-#endif
 
 	/* Register the v4l2 device */
 	video_set_drvdata(dev->vdev, dev);
@@ -1669,7 +1882,6 @@
 		return -ENODEV;
 	}
 
-#ifdef VBI_IS_WORKING
 	/* Register the vbi device */
 	video_set_drvdata(dev->vbi_dev, dev);
 	retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1);
@@ -1680,7 +1892,6 @@
 		video_device_release(dev->vdev);
 		return -ENODEV;
 	}
-#endif
 
 	dprintk(1, "%s completed!\n", __func__);
 
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
index 207f32d..9905bc4 100644
--- a/drivers/media/video/au0828/au0828.h
+++ b/drivers/media/video/au0828/au0828.h
@@ -60,6 +60,10 @@
 
 #define AU0828_MAX_INPUT        4
 
+/* au0828 resource types (used for res_get/res_lock etc */
+#define AU0828_RESOURCE_VIDEO 0x01
+#define AU0828_RESOURCE_VBI   0x02
+
 enum au0828_itype {
 	AU0828_VMUX_UNDEFINED = 0,
 	AU0828_VMUX_COMPOSITE,
@@ -115,8 +119,10 @@
 
 struct au0828_fh {
 	struct au0828_dev *dev;
-	unsigned int  stream_on:1;	/* Locks streams */
+	unsigned int  resources;
+
 	struct videobuf_queue        vb_vidq;
+	struct videobuf_queue        vb_vbiq;
 	enum v4l2_buf_type           type;
 };
 
@@ -145,7 +151,8 @@
 	int				tmp_buf_len;
 
 		/* Stores already requested buffers */
-	struct au0828_buffer    	*buf;
+	struct au0828_buffer		*buf;
+	struct au0828_buffer		*vbi_buf;
 
 		/* Stores the number of received fields */
 	int				nfields;
@@ -194,11 +201,14 @@
 	/* Analog */
 	struct v4l2_device v4l2_dev;
 	int users;
-	unsigned int stream_on:1;	/* Locks streams */
+	unsigned int resources;	/* resources in use */
 	struct video_device *vdev;
 	struct video_device *vbi_dev;
 	int width;
 	int height;
+	int vbi_width;
+	int vbi_height;
+	u32 vbi_read;
 	u32 field_size;
 	u32 frame_size;
 	u32 bytesperline;
@@ -219,6 +229,7 @@
 
 	/* Isoc control struct */
 	struct au0828_dmaqueue vidq;
+	struct au0828_dmaqueue vbiq;
 	struct au0828_usb_isoc_ctl isoc_ctl;
 	spinlock_t slock;
 
@@ -278,6 +289,9 @@
 extern int au0828_dvb_register(struct au0828_dev *dev);
 extern void au0828_dvb_unregister(struct au0828_dev *dev);
 
+/* au0828-vbi.c */
+extern struct videobuf_queue_ops au0828_vbi_qops;
+
 #define dprintk(level, fmt, arg...)\
 	do { if (au0828_debug & level)\
 		printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index c24b1c1..0fa9f39 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -583,7 +583,7 @@
 
 	BUG_ON(in_interrupt());
 	videobuf_waiton(&buf->vb,0,0);
-	videobuf_dma_unmap(q, dma);
+	videobuf_dma_unmap(q->dev, dma);
 	videobuf_dma_free(dma);
 	btcx_riscmem_free(btv->c.pci,&buf->bottom);
 	btcx_riscmem_free(btv->c.pci,&buf->top);
diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
index ef1f893..58d193f 100644
--- a/drivers/media/video/cpia_usb.c
+++ b/drivers/media/video/cpia_usb.c
@@ -584,7 +584,6 @@
 {
 	struct cam_data *cam = usb_get_intfdata(intf);
 	struct usb_cpia *ucpia;
-	struct usb_device *udev;
 
 	usb_set_intfdata(intf, NULL);
 	if (!cam)
@@ -606,8 +605,6 @@
 	if (waitqueue_active(&ucpia->wq_stream))
 		wake_up_interruptible(&ucpia->wq_stream);
 
-	udev = interface_to_usbdev(intf);
-
 	ucpia->curbuff = ucpia->workbuff = NULL;
 
 	vfree(ucpia->buffers[2]);
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 20eaf38..d679240 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -1081,7 +1081,7 @@
 		    unsigned long arg)
 {
 	struct video_device *vfd = video_devdata(filp);
-	struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
+	struct cx18_open_id *id = filp->private_data;
 	struct cx18 *cx = id->cx;
 	long res;
 
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index d639186..2014dae 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -408,10 +408,18 @@
 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1275,
 	}, {
 		.subvendor = 0x0070,
+		.subdevice = 0x221d,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1275,
+	}, {
+		.subvendor = 0x0070,
 		.subdevice = 0x2251,
 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1255,
 	}, {
 		.subvendor = 0x0070,
+		.subdevice = 0x2259,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1255,
+	}, {
+		.subvendor = 0x0070,
 		.subdevice = 0x2291,
 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
 	}, {
@@ -419,6 +427,38 @@
 		.subdevice = 0x2295,
 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
 	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x2299,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x229d,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x22f0,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x22f1,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1255,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x22f2,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1275,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x22f3,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x22f4,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+	}, {
+		.subvendor = 0x0070,
+		.subdevice = 0x22f5,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+	}, {
 		.subvendor = 0x14f1,
 		.subdevice = 0x8651,
 		.card      = CX23885_BOARD_MYGICA_X8506,
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 0dde57e..ff76f64 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -1142,7 +1142,7 @@
 
 	BUG_ON(in_interrupt());
 	videobuf_waiton(&buf->vb, 0, 0);
-	videobuf_dma_unmap(q, dma);
+	videobuf_dma_unmap(q->dev, dma);
 	videobuf_dma_free(dma);
 	btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -1953,8 +1953,12 @@
 		goto fail_irq;
 	}
 
-	err = request_irq(pci_dev->irq, cx23885_irq,
-			  IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+	if (!pci_enable_msi(pci_dev))
+		err = request_irq(pci_dev->irq, cx23885_irq,
+				  IRQF_DISABLED, dev->name, dev);
+	else
+		err = request_irq(pci_dev->irq, cx23885_irq,
+				  IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
 	if (err < 0) {
 		printk(KERN_ERR "%s: can't get IRQ %d\n",
 		       dev->name, pci_dev->irq);
@@ -2000,6 +2004,7 @@
 
 	/* unregister stuff */
 	free_irq(pci_dev->irq, dev);
+	pci_disable_msi(pci_dev);
 
 	cx23885_dev_unregister(dev);
 	v4l2_device_unregister(v4l2_dev);
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 0a199d7..3d70af2 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -991,7 +991,7 @@
 	ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
 					&dev->pci->dev, adapter_nr, 0,
 					cx23885_dvb_fe_ioctl_override);
-	if (!ret)
+	if (ret)
 		return ret;
 
 	/* init CI & MAC */
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
index 5de6ba9..d0b1613 100644
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -37,161 +37,55 @@
 
 #include <linux/input.h>
 #include <linux/slab.h>
-#include <media/ir-common.h>
+#include <media/ir-core.h>
 #include <media/v4l2-subdev.h>
 
 #include "cx23885.h"
 
-#define RC5_BITS		14
-#define RC5_HALF_BITS		(2*RC5_BITS)
-#define RC5_HALF_BITS_MASK	((1 << RC5_HALF_BITS) - 1)
-
-#define RC5_START_BITS_NORMAL	0x3 /* Command range  0 -  63 */
-#define RC5_START_BITS_EXTENDED	0x2 /* Command range 64 - 127 */
-
-#define RC5_EXTENDED_COMMAND_OFFSET	64
-
 #define MODULE_NAME "cx23885"
 
-static inline unsigned int rc5_command(u32 rc5_baseband)
+static void convert_measurement(u32 x, struct ir_raw_event *y)
 {
-	return RC5_INSTR(rc5_baseband) +
-		((RC5_START(rc5_baseband) == RC5_START_BITS_EXTENDED)
-			? RC5_EXTENDED_COMMAND_OFFSET : 0);
+	if (x == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) {
+		y->pulse = false;
+		y->duration = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
+		return;
+	}
+
+	y->pulse = (x & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? true : false;
+	y->duration = x & V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
 }
 
-static void cx23885_input_process_raw_rc5(struct cx23885_dev *dev)
+static void cx23885_input_process_measurements(struct cx23885_dev *dev,
+					       bool overrun)
 {
-	struct card_ir *ir_input = dev->ir_input;
-	unsigned int code, command;
-	u32 rc5;
+	struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir;
+	struct ir_raw_event kernel_ir_event;
 
-	/* Ignore codes that are too short to be valid RC-5 */
-	if (ir_input->last_bit < (RC5_HALF_BITS - 1))
-		return;
-
-	/* The library has the manchester coding backwards; XOR to adapt. */
-	code = (ir_input->code & RC5_HALF_BITS_MASK) ^ RC5_HALF_BITS_MASK;
-	rc5 = ir_rc5_decode(code);
-
-	switch (RC5_START(rc5)) {
-	case RC5_START_BITS_NORMAL:
-		break;
-	case RC5_START_BITS_EXTENDED:
-		/* Don't allow if the remote only emits standard commands */
-		if (ir_input->start == RC5_START_BITS_NORMAL)
-			return;
-		break;
-	default:
-		return;
-	}
-
-	if (ir_input->addr != RC5_ADDR(rc5))
-		return;
-
-	/* Don't generate a keypress for RC-5 auto-repeated keypresses */
-	command = rc5_command(rc5);
-	if (RC5_TOGGLE(rc5) != RC5_TOGGLE(ir_input->last_rc5) ||
-	    command != rc5_command(ir_input->last_rc5) ||
-	    /* Catch T == 0, CMD == 0 (e.g. '0') as first keypress after init */
-	    RC5_START(ir_input->last_rc5) == 0) {
-		/* This keypress is differnet: not an auto repeat */
-		ir_input_nokey(ir_input->dev, &ir_input->ir);
-		ir_input_keydown(ir_input->dev, &ir_input->ir, command);
-	}
-	ir_input->last_rc5 = rc5;
-
-	/* Schedule when we should do the key up event: ir_input_nokey() */
-	mod_timer(&ir_input->timer_keyup,
-		  jiffies + msecs_to_jiffies(ir_input->rc5_key_timeout));
-}
-
-static void cx23885_input_next_pulse_width_rc5(struct cx23885_dev *dev,
-					       u32 ns_pulse)
-{
-	const int rc5_quarterbit_ns = 444444; /* 32 cycles/36 kHz/2 = 444 us */
-	struct card_ir *ir_input = dev->ir_input;
-	int i, level, quarterbits, halfbits;
-
-	if (!ir_input->active) {
-		ir_input->active = 1;
-		/* assume an initial space that we may not detect or measure */
-		ir_input->code = 0;
-		ir_input->last_bit = 0;
-	}
-
-	if (ns_pulse == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) {
-		ir_input->last_bit++; /* Account for the final space */
-		ir_input->active = 0;
-		cx23885_input_process_raw_rc5(dev);
-		return;
-	}
-
-	level = (ns_pulse & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? 1 : 0;
-
-	/* Skip any leading space to sync to the start bit */
-	if (ir_input->last_bit == 0 && level == 0)
-		return;
-
-	/*
-	 * With valid RC-5 we can get up to two consecutive half-bits in a
-	 * single pulse measurment.  Experiments have shown that the duration
-	 * of a half-bit can vary.  Make sure we always end up with an even
-	 * number of quarter bits at the same level (mark or space).
-	 */
-	ns_pulse &= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
-	quarterbits = ns_pulse / rc5_quarterbit_ns;
-	if (quarterbits & 1)
-		quarterbits++;
-	halfbits = quarterbits / 2;
-
-	for (i = 0; i < halfbits; i++) {
-		ir_input->last_bit++;
-		ir_input->code |= (level << ir_input->last_bit);
-
-		if (ir_input->last_bit >= RC5_HALF_BITS-1) {
-			ir_input->active = 0;
-			cx23885_input_process_raw_rc5(dev);
-			/*
-			 * If level is 1, a leading mark is invalid for RC5.
-			 * If level is 0, we scan past extra intial space.
-			 * Either way we don't want to reactivate collecting
-			 * marks or spaces here with any left over half-bits.
-			 */
-			break;
-		}
-	}
-}
-
-static void cx23885_input_process_pulse_widths_rc5(struct cx23885_dev *dev,
-						   bool add_eom)
-{
-	struct card_ir *ir_input = dev->ir_input;
-	struct ir_input_state *ir_input_state = &ir_input->ir;
-
-	u32 ns_pulse[RC5_HALF_BITS+1];
-	ssize_t num = 0;
+	u32 sd_ir_data[64];
+	ssize_t num;
 	int count, i;
+	bool handle = false;
 
 	do {
-		v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ns_pulse,
-				 sizeof(ns_pulse), &num);
+		num = 0;
+		v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) sd_ir_data,
+				 sizeof(sd_ir_data), &num);
 
 		count = num / sizeof(u32);
 
-		/* Append an end of Rx seq, if the caller requested */
-		if (add_eom && count < ARRAY_SIZE(ns_pulse)) {
-			ns_pulse[count] = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END;
-			count++;
+		for (i = 0; i < count; i++) {
+			convert_measurement(sd_ir_data[i], &kernel_ir_event);
+			ir_raw_event_store(kernel_ir->inp_dev,
+					   &kernel_ir_event);
+			handle = true;
 		}
-
-		/* Just drain the Rx FIFO, if we're called, but not RC-5 */
-		if (ir_input_state->ir_type != IR_TYPE_RC5)
-			continue;
-
-		for (i = 0; i < count; i++)
-			cx23885_input_next_pulse_width_rc5(dev, ns_pulse[i]);
 	} while (num != 0);
+
+	if (overrun)
+		ir_raw_event_reset(kernel_ir->inp_dev);
+	else if (handle)
+		ir_raw_event_handle(kernel_ir->inp_dev);
 }
 
 void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
@@ -230,7 +124,7 @@
 	}
 
 	if (data_available)
-		cx23885_input_process_pulse_widths_rc5(dev, overrun);
+		cx23885_input_process_measurements(dev, overrun);
 
 	if (overrun) {
 		/* If there was a FIFO overrun, clear & restart the device */
@@ -241,34 +135,15 @@
 	}
 }
 
-static void cx23885_input_ir_start(struct cx23885_dev *dev)
+static int cx23885_input_ir_start(struct cx23885_dev *dev)
 {
-	struct card_ir *ir_input = dev->ir_input;
-	struct ir_input_state *ir_input_state = &ir_input->ir;
 	struct v4l2_subdev_ir_parameters params;
 
 	if (dev->sd_ir == NULL)
-		return;
+		return -ENODEV;
 
 	atomic_set(&dev->ir_input_stopping, 0);
 
-	/* keyup timer set up, if needed */
-	switch (dev->board) {
-	case CX23885_BOARD_HAUPPAUGE_HVR1850:
-	case CX23885_BOARD_HAUPPAUGE_HVR1290:
-		setup_timer(&ir_input->timer_keyup,
-			    ir_rc5_timer_keyup,	/* Not actually RC-5 specific */
-			    (unsigned long) ir_input);
-		if (ir_input_state->ir_type == IR_TYPE_RC5) {
-			/*
-			 * RC-5 repeats a held key every
-			 * 64 bits * (2 * 32/36000) sec/bit = 113.778 ms
-			 */
-			ir_input->rc5_key_timeout = 115;
-		}
-		break;
-	}
-
 	v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
 	switch (dev->board) {
 	case CX23885_BOARD_HAUPPAUGE_HVR1850:
@@ -299,11 +174,21 @@
 		break;
 	}
 	v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+	return 0;
+}
+
+static int cx23885_input_ir_open(void *priv)
+{
+	struct cx23885_kernel_ir *kernel_ir = priv;
+
+	if (kernel_ir->cx == NULL)
+		return -ENODEV;
+
+	return cx23885_input_ir_start(kernel_ir->cx);
 }
 
 static void cx23885_input_ir_stop(struct cx23885_dev *dev)
 {
-	struct card_ir *ir_input = dev->ir_input;
 	struct v4l2_subdev_ir_parameters params;
 
 	if (dev->sd_ir == NULL)
@@ -327,21 +212,26 @@
 	}
 
 	flush_scheduled_work();
+}
 
-	switch (dev->board) {
-	case CX23885_BOARD_HAUPPAUGE_HVR1850:
-	case CX23885_BOARD_HAUPPAUGE_HVR1290:
-		del_timer_sync(&ir_input->timer_keyup);
-		break;
-	}
+static void cx23885_input_ir_close(void *priv)
+{
+	struct cx23885_kernel_ir *kernel_ir = priv;
+
+	if (kernel_ir->cx != NULL)
+		cx23885_input_ir_stop(kernel_ir->cx);
 }
 
 int cx23885_input_init(struct cx23885_dev *dev)
 {
-	struct card_ir *ir;
-	struct input_dev *input_dev;
-	char *ir_codes = NULL;
-	int ir_type, ir_addr, ir_start;
+	struct cx23885_kernel_ir *kernel_ir;
+	struct input_dev *inp_dev;
+	struct ir_dev_props *props;
+
+	char *rc_map;
+	enum rc_driver_type driver_type;
+	unsigned long allowed_protos;
+
 	int ret;
 
 	/*
@@ -354,53 +244,59 @@
 	switch (dev->board) {
 	case CX23885_BOARD_HAUPPAUGE_HVR1850:
 	case CX23885_BOARD_HAUPPAUGE_HVR1290:
-		/* Parameters for the grey Hauppauge remote for the HVR-1850 */
-		ir_codes = RC_MAP_HAUPPAUGE_NEW;
-		ir_type = IR_TYPE_RC5;
-		ir_addr = 0x1e; /* RC-5 system bits emitted by the remote */
-		ir_start = RC5_START_BITS_NORMAL; /* A basic RC-5 remote */
+		/* Integrated CX23888 IR controller */
+		driver_type = RC_DRIVER_IR_RAW;
+		allowed_protos = IR_TYPE_ALL;
+		/* The grey Hauppauge RC-5 remote */
+		rc_map = RC_MAP_RC5_HAUPPAUGE_NEW;
 		break;
-	}
-	if (ir_codes == NULL)
+	default:
 		return -ENODEV;
+	}
 
-	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!ir || !input_dev) {
+	/* cx23885 board instance kernel IR state */
+	kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL);
+	if (kernel_ir == NULL)
+		return -ENOMEM;
+
+	kernel_ir->cx = dev;
+	kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)",
+				    cx23885_boards[dev->board].name);
+	kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0",
+				    pci_name(dev->pci));
+
+	/* input device */
+	inp_dev = input_allocate_device();
+	if (inp_dev == NULL) {
 		ret = -ENOMEM;
 		goto err_out_free;
 	}
 
-	ir->dev = input_dev;
-	ir->addr = ir_addr;
-	ir->start = ir_start;
-
-	/* init input device */
-	snprintf(ir->name, sizeof(ir->name), "cx23885 IR (%s)",
-		 cx23885_boards[dev->board].name);
-	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci));
-
-	ret = ir_input_init(input_dev, &ir->ir, ir_type);
-	if (ret < 0)
-		goto err_out_free;
-
-	input_dev->name = ir->name;
-	input_dev->phys = ir->phys;
-	input_dev->id.bustype = BUS_PCI;
-	input_dev->id.version = 1;
+	kernel_ir->inp_dev = inp_dev;
+	inp_dev->name = kernel_ir->name;
+	inp_dev->phys = kernel_ir->phys;
+	inp_dev->id.bustype = BUS_PCI;
+	inp_dev->id.version = 1;
 	if (dev->pci->subsystem_vendor) {
-		input_dev->id.vendor  = dev->pci->subsystem_vendor;
-		input_dev->id.product = dev->pci->subsystem_device;
+		inp_dev->id.vendor  = dev->pci->subsystem_vendor;
+		inp_dev->id.product = dev->pci->subsystem_device;
 	} else {
-		input_dev->id.vendor  = dev->pci->vendor;
-		input_dev->id.product = dev->pci->device;
+		inp_dev->id.vendor  = dev->pci->vendor;
+		inp_dev->id.product = dev->pci->device;
 	}
-	input_dev->dev.parent = &dev->pci->dev;
+	inp_dev->dev.parent = &dev->pci->dev;
 
-	dev->ir_input = ir;
-	cx23885_input_ir_start(dev);
+	/* kernel ir device properties */
+	props = &kernel_ir->props;
+	props->driver_type = driver_type;
+	props->allowed_protos = allowed_protos;
+	props->priv = kernel_ir;
+	props->open = cx23885_input_ir_open;
+	props->close = cx23885_input_ir_close;
 
-	ret = ir_input_register(ir->dev, ir_codes, NULL, MODULE_NAME);
+	/* Go */
+	dev->kernel_ir = kernel_ir;
+	ret = ir_input_register(inp_dev, rc_map, props, MODULE_NAME);
 	if (ret)
 		goto err_out_stop;
 
@@ -408,9 +304,12 @@
 
 err_out_stop:
 	cx23885_input_ir_stop(dev);
-	dev->ir_input = NULL;
+	dev->kernel_ir = NULL;
+	/* TODO: double check clean-up of kernel_ir->inp_dev */
 err_out_free:
-	kfree(ir);
+	kfree(kernel_ir->phys);
+	kfree(kernel_ir->name);
+	kfree(kernel_ir);
 	return ret;
 }
 
@@ -419,9 +318,11 @@
 	/* Always stop the IR hardware from generating interrupts */
 	cx23885_input_ir_stop(dev);
 
-	if (dev->ir_input == NULL)
+	if (dev->kernel_ir == NULL)
 		return;
-	ir_input_unregister(dev->ir_input->dev);
-	kfree(dev->ir_input);
-	dev->ir_input = NULL;
+	ir_input_unregister(dev->kernel_ir->inp_dev);
+	kfree(dev->kernel_ir->phys);
+	kfree(dev->kernel_ir->name);
+	kfree(dev->kernel_ir);
+	dev->kernel_ir = NULL;
 }
diff --git a/drivers/media/video/cx23885/cx23885-ir.c b/drivers/media/video/cx23885/cx23885-ir.c
index 9a677eb..6ceabd4 100644
--- a/drivers/media/video/cx23885/cx23885-ir.c
+++ b/drivers/media/video/cx23885/cx23885-ir.c
@@ -53,7 +53,7 @@
 	if (events == 0)
 		return;
 
-	if (dev->ir_input)
+	if (dev->kernel_ir)
 		cx23885_input_rx_work_handler(dev, events);
 }
 
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index 8d6a55e..a33f2b7 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -30,6 +30,7 @@
 #include <media/tveeprom.h>
 #include <media/videobuf-dma-sg.h>
 #include <media/videobuf-dvb.h>
+#include <media/ir-core.h>
 
 #include "btcx-risc.h"
 #include "cx23885-reg.h"
@@ -304,6 +305,15 @@
 	void                       *port_priv;
 };
 
+struct cx23885_kernel_ir {
+	struct cx23885_dev	*cx;
+	char			*name;
+	char			*phys;
+
+	struct input_dev	*inp_dev;
+	struct ir_dev_props	props;
+};
+
 struct cx23885_dev {
 	atomic_t                   refcount;
 	struct v4l2_device 	   v4l2_dev;
@@ -363,7 +373,7 @@
 	struct work_struct	   ir_tx_work;
 	unsigned long		   ir_tx_notifications;
 
-	struct card_ir		   *ir_input;
+	struct cx23885_kernel_ir   *kernel_ir;
 	atomic_t		   ir_input_stopping;
 
 	/* V4l */
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 33082c9..4f383cd 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -54,6 +54,12 @@
 	Data type declarations - Can be moded to a header file later
  ****************************************************************************/
 
+struct cx88_audio_buffer {
+	unsigned int               bpl;
+	struct btcx_riscmem        risc;
+	struct videobuf_dmabuf     dma;
+};
+
 struct cx88_audio_dev {
 	struct cx88_core           *core;
 	struct cx88_dmaqueue       q;
@@ -75,7 +81,7 @@
 
 	struct videobuf_dmabuf     *dma_risc;
 
-	struct cx88_buffer	   *buf;
+	struct cx88_audio_buffer   *buf;
 
 	struct snd_pcm_substream   *substream;
 };
@@ -123,7 +129,7 @@
 
 static int _cx88_start_audio_dma(snd_cx88_card_t *chip)
 {
-	struct cx88_buffer   *buf = chip->buf;
+	struct cx88_audio_buffer *buf = chip->buf;
 	struct cx88_core *core=chip->core;
 	struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
 
@@ -283,7 +289,7 @@
 	BUG_ON(!chip->dma_size);
 
 	dprintk(2,"Freeing buffer\n");
-	videobuf_sg_dma_unmap(&chip->pci->dev, chip->dma_risc);
+	videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
 	videobuf_dma_free(chip->dma_risc);
 	btcx_riscmem_free(chip->pci,&chip->buf->risc);
 	kfree(chip->buf);
@@ -376,7 +382,7 @@
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
 	struct videobuf_dmabuf *dma;
 
-	struct cx88_buffer *buf;
+	struct cx88_audio_buffer *buf;
 	int ret;
 
 	if (substream->runtime->dma_area) {
@@ -391,30 +397,25 @@
 	BUG_ON(!chip->dma_size);
 	BUG_ON(chip->num_periods & (chip->num_periods-1));
 
-	buf = videobuf_sg_alloc(sizeof(*buf));
+	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
 	if (NULL == buf)
 		return -ENOMEM;
 
-	buf->vb.memory = V4L2_MEMORY_MMAP;
-	buf->vb.field  = V4L2_FIELD_NONE;
-	buf->vb.width  = chip->period_size;
-	buf->bpl       = chip->period_size;
-	buf->vb.height = chip->num_periods;
-	buf->vb.size   = chip->dma_size;
+	buf->bpl = chip->period_size;
 
-	dma = videobuf_to_dma(&buf->vb);
+	dma = &buf->dma;
 	videobuf_dma_init(dma);
 	ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
-			(PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
+			(PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
 	if (ret < 0)
 		goto error;
 
-	ret = videobuf_sg_dma_map(&chip->pci->dev, dma);
+	ret = videobuf_dma_map(&chip->pci->dev, dma);
 	if (ret < 0)
 		goto error;
 
 	ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
-				   buf->vb.width, buf->vb.height, 1);
+				   chip->period_size, chip->num_periods, 1);
 	if (ret < 0)
 		goto error;
 
@@ -422,12 +423,10 @@
 	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
 	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 
-	buf->vb.state = VIDEOBUF_PREPARED;
-
 	chip->buf = buf;
 	chip->dma_risc = dma;
 
-	substream->runtime->dma_area = chip->dma_risc->vmalloc;
+	substream->runtime->dma_area = chip->dma_risc->vaddr;
 	substream->runtime->dma_bytes = chip->dma_size;
 	substream->runtime->dma_addr = 0;
 	return 0;
@@ -740,7 +739,7 @@
 
 	pci_set_master(pci);
 
-	chip = (snd_cx88_card_t *) card->private_data;
+	chip = card->private_data;
 
 	core = cx88_core_get(pci);
 	if (NULL == core) {
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 2918a6e..e8416b7 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -45,6 +45,10 @@
 module_param(latency,int,0444);
 MODULE_PARM_DESC(latency,"pci latency timer");
 
+static int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(latency, "Disable IR support");
+
 #define info_printk(core, fmt, arg...) \
 	printk(KERN_INFO "%s: " fmt, core->name , ## arg)
 
@@ -3498,7 +3502,10 @@
 	}
 
 	cx88_card_setup(core);
-	cx88_ir_init(core, pci);
+	if (!disable_ir) {
+		cx88_i2c_init_ir(core);
+		cx88_ir_init(core, pci);
+	}
 
 	return core;
 }
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 8b21457..85eb266f 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -218,7 +218,7 @@
 
 	BUG_ON(in_interrupt());
 	videobuf_waiton(&buf->vb,0,0);
-	videobuf_dma_unmap(q, dma);
+	videobuf_dma_unmap(q->dev, dma);
 	videobuf_dma_free(dma);
 	btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index fb39f11..375ad53 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -181,6 +181,11 @@
 	} else
 		printk("%s: i2c register FAILED\n", core->name);
 
+	return core->i2c_rc;
+}
+
+void cx88_i2c_init_ir(struct cx88_core *core)
+{
 	/* Instantiate the IR receiver device, if present */
 	if (0 == core->i2c_rc) {
 		struct i2c_board_info info;
@@ -207,7 +212,6 @@
 			}
 		}
 	}
-	return core->i2c_rc;
 }
 
 /* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index e185289..eccc5e4 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 
 #include "cx88.h"
+#include <media/ir-core.h>
 #include <media/ir-common.h>
 
 #define MODULE_NAME "cx88xx"
@@ -39,8 +40,8 @@
 struct cx88_IR {
 	struct cx88_core *core;
 	struct input_dev *input;
-	struct ir_input_state ir;
 	struct ir_dev_props props;
+	u64 ir_type;
 
 	int users;
 
@@ -51,7 +52,6 @@
 	u32 sampling;
 	u32 samples[16];
 	int scount;
-	unsigned long release;
 
 	/* poll external decoder */
 	int polling;
@@ -125,29 +125,21 @@
 
 		data = (data << 4) | ((gpio_key & 0xf0) >> 4);
 
-		ir_input_keydown(ir->input, &ir->ir, data);
-		ir_input_nokey(ir->input, &ir->ir);
+		ir_keydown(ir->input, data, 0);
 
 	} else if (ir->mask_keydown) {
 		/* bit set on keydown */
-		if (gpio & ir->mask_keydown) {
-			ir_input_keydown(ir->input, &ir->ir, data);
-		} else {
-			ir_input_nokey(ir->input, &ir->ir);
-		}
+		if (gpio & ir->mask_keydown)
+			ir_keydown(ir->input, data, 0);
 
 	} else if (ir->mask_keyup) {
 		/* bit cleared on keydown */
-		if (0 == (gpio & ir->mask_keyup)) {
-			ir_input_keydown(ir->input, &ir->ir, data);
-		} else {
-			ir_input_nokey(ir->input, &ir->ir);
-		}
+		if (0 == (gpio & ir->mask_keyup))
+			ir_keydown(ir->input, data, 0);
 
 	} else {
 		/* can't distinguish keydown/up :-/ */
-		ir_input_keydown(ir->input, &ir->ir, data);
-		ir_input_nokey(ir->input, &ir->ir);
+		ir_keydown(ir->input, data, 0);
 	}
 }
 
@@ -439,9 +431,7 @@
 	snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
 	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
 
-	err = ir_input_init(input_dev, &ir->ir, ir_type);
-	if (err < 0)
-		goto err_out_free;
+	ir->ir_type = ir_type;
 
 	input_dev->name = ir->name;
 	input_dev->phys = ir->phys;
@@ -516,8 +506,6 @@
 	}
 	if (!ir->scount) {
 		/* nothing to sample */
-		if (ir->ir.keypressed && time_after(jiffies, ir->release))
-			ir_input_nokey(ir->input, &ir->ir);
 		return;
 	}
 
@@ -553,7 +541,7 @@
 
 		if (ircode == 0) { /* key still pressed */
 			ir_dprintk("pulse distance decoded repeat code\n");
-			ir->release = jiffies + msecs_to_jiffies(120);
+			ir_repeat(ir->input);
 			break;
 		}
 
@@ -567,10 +555,8 @@
 			break;
 		}
 
-		ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0x7f);
-
-		ir_input_keydown(ir->input, &ir->ir, (ircode >> 16) & 0x7f);
-		ir->release = jiffies + msecs_to_jiffies(120);
+		ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0xff);
+		ir_keydown(ir->input, (ircode >> 16) & 0xff, 0);
 		break;
 	case CX88_BOARD_HAUPPAUGE:
 	case CX88_BOARD_HAUPPAUGE_DVB_T1:
@@ -606,16 +592,16 @@
 		if ( dev != 0x1e && dev != 0x1f )
 			/* not a hauppauge remote */
 			break;
-		ir_input_keydown(ir->input, &ir->ir, code);
-		ir->release = jiffies + msecs_to_jiffies(120);
+		ir_keydown(ir->input, code, toggle);
 		break;
 	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
 		ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
 		ir_dprintk("biphase decoded: %x\n", ircode);
 		if ((ircode & 0xfffff000) != 0x3000)
 			break;
-		ir_input_keydown(ir->input, &ir->ir, ircode & 0x3f);
-		ir->release = jiffies + msecs_to_jiffies(120);
+		/* Note: bit 0x800 being the toggle is assumed, not checked
+		   with real hardware  */
+		ir_keydown(ir->input, ircode & 0x3f, ircode & 0x0800 ? 1 : 0);
 		break;
 	}
 
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index bdb03d3..33d161a 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -636,6 +636,7 @@
 /* cx88-i2c.c                                                  */
 
 extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci);
+extern void cx88_i2c_init_ir(struct cx88_core *core);
 
 
 /* ----------------------------------------------------------- */
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
index 0f50508..5b176bd 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/media/video/dabusb.c
@@ -706,16 +706,11 @@
 	switch (cmd) {
 
 	case IOCTL_DAB_BULK:
-		pbulk = kmalloc(sizeof (bulk_transfer_t), GFP_KERNEL);
+		pbulk = memdup_user((void __user *)arg,
+				    sizeof(bulk_transfer_t));
 
-		if (!pbulk) {
-			ret = -ENOMEM;
-			break;
-		}
-
-		if (copy_from_user (pbulk, (void __user *) arg, sizeof (bulk_transfer_t))) {
-			ret = -EFAULT;
-			kfree (pbulk);
+		if (IS_ERR(pbulk)) {
+			ret = PTR_ERR(pbulk);
 			break;
 		}
 
diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig
new file mode 100644
index 0000000..6b19540
--- /dev/null
+++ b/drivers/media/video/davinci/Kconfig
@@ -0,0 +1,93 @@
+config DISPLAY_DAVINCI_DM646X_EVM
+	tristate "DM646x EVM Video Display"
+	depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+	select VIDEOBUF_DMA_CONTIG
+	select VIDEO_DAVINCI_VPIF
+	select VIDEO_ADV7343
+	select VIDEO_THS7303
+	help
+	  Support for DM6467 based display device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vpif_display.
+
+config CAPTURE_DAVINCI_DM646X_EVM
+	tristate "DM646x EVM Video Capture"
+	depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+	select VIDEOBUF_DMA_CONTIG
+	select VIDEO_DAVINCI_VPIF
+	help
+	  Support for DM6467 based capture device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vpif_capture.
+
+config VIDEO_DAVINCI_VPIF
+	tristate "DaVinci VPIF Driver"
+	depends on DISPLAY_DAVINCI_DM646X_EVM
+	help
+	  Support for DaVinci VPIF Driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vpif.
+
+config VIDEO_VPSS_SYSTEM
+	tristate "VPSS System module driver"
+	depends on ARCH_DAVINCI
+	help
+	  Support for vpss system module for video driver
+
+config VIDEO_VPFE_CAPTURE
+	tristate "VPFE Video Capture Driver"
+	depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3)
+	select VIDEOBUF_DMA_CONTIG
+	help
+	  Support for DMx/AMx VPFE based frame grabber. This is the
+	  common V4L2 module for following DMx/AMx SoCs from Texas
+	  Instruments:- DM6446, DM365, DM355 & AM3517/05.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vpfe-capture.
+
+config VIDEO_DM6446_CCDC
+	tristate "DM6446 CCDC HW module"
+	depends on VIDEO_VPFE_CAPTURE
+	select VIDEO_VPSS_SYSTEM
+	default y
+	help
+	   Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
+	   with decoder modules such as TVP5146 over BT656 or
+	   sensor module such as MT9T001 over a raw interface. This
+	   module configures the interface and CCDC/ISIF to do
+	   video frame capture from slave decoders.
+
+	   To compile this driver as a module, choose M here: the
+	   module will be called vpfe.
+
+config VIDEO_DM355_CCDC
+	tristate "DM355 CCDC HW module"
+	depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
+	select VIDEO_VPSS_SYSTEM
+	default y
+	help
+	   Enables DM355 CCD hw module. DM355 CCDC hw interfaces
+	   with decoder modules such as TVP5146 over BT656 or
+	   sensor module such as MT9T001 over a raw interface. This
+	   module configures the interface and CCDC/ISIF to do
+	   video frame capture from a slave decoders
+
+	   To compile this driver as a module, choose M here: the
+	   module will be called vpfe.
+
+config VIDEO_ISIF
+	tristate "ISIF HW module"
+	depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
+	select VIDEO_VPSS_SYSTEM
+	default y
+	help
+	   Enables ISIF hw module. This is the hardware module for
+	   configuring ISIF in VPFE to capture Raw Bayer RGB data  from
+	   a image sensor or YUV data from a YUV source.
+
+	   To compile this driver as a module, choose M here: the
+	   module will be called vpfe.
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 3a4fd85..ffbe544 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -158,6 +158,22 @@
 	{ -1,			-1,	-1,		-1},
 };
 
+/*
+ * KWorld PlusTV 340U and UB435-Q (ATSC) GPIOs map:
+ * EM_GPIO_0 - currently unknown
+ * EM_GPIO_1 - LED disable/enable (1 = off, 0 = on)
+ * EM_GPIO_2 - currently unknown
+ * EM_GPIO_3 - currently unknown
+ * EM_GPIO_4 - TDA18271HD/C1 tuner (1 = active, 0 = in reset)
+ * EM_GPIO_5 - LGDT3304 ATSC/QAM demod (1 = active, 0 = in reset)
+ * EM_GPIO_6 - currently unknown
+ * EM_GPIO_7 - currently unknown
+ */
+static struct em28xx_reg_seq kworld_a340_digital[] = {
+	{EM28XX_R08_GPIO,	0x6d,		~EM_GPIO_4,	10},
+	{ -1,			-1,		-1,		-1},
+};
+
 /* Pinnacle Hybrid Pro eb1a:2881 */
 static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
 	{EM28XX_R08_GPIO,	0xfd,   ~EM_GPIO_4,	10},
@@ -1667,6 +1683,16 @@
 		.tuner_gpio    = reddo_dvb_c_usb_box,
 		.has_dvb       = 1,
 	},
+	/* 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold
+	 * initially as the KWorld PlusTV 340U, then as the UB435-Q.
+	 * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 */
+	[EM2870_BOARD_KWORLD_A340] = {
+		.name       = "KWorld PlusTV 340U or UB435-Q (ATSC)",
+		.tuner_type = TUNER_ABSENT,	/* Digital-only TDA18271HD */
+		.has_dvb    = 1,
+		.dvb_gpio   = kworld_a340_digital,
+		.tuner_gpio = default_tuner_gpio,
+	},
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -1788,6 +1814,8 @@
 			.driver_info = EM2820_BOARD_IODATA_GVMVP_SZ },
 	{ USB_DEVICE(0xeb1a, 0x50a6),
 			.driver_info = EM2860_BOARD_GADMEI_UTV330 },
+	{ USB_DEVICE(0x1b80, 0xa340),
+			.driver_info = EM2870_BOARD_KWORLD_A340 },
 	{ },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index cf1d8c3..3ac8d30 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -30,11 +30,13 @@
 #include "tuner-simple.h"
 
 #include "lgdt330x.h"
+#include "lgdt3305.h"
 #include "zl10353.h"
 #include "s5h1409.h"
 #include "mt352.h"
 #include "mt352_priv.h" /* FIXME */
 #include "tda1002x.h"
+#include "tda18271.h"
 
 MODULE_DESCRIPTION("driver for em28xx based DVB cards");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -231,6 +233,18 @@
 	.demod_chip = LGDT3303,
 };
 
+static struct lgdt3305_config em2870_lgdt3304_dev = {
+	.i2c_addr           = 0x0e,
+	.demod_chip         = LGDT3304,
+	.spectral_inversion = 1,
+	.deny_i2c_rptr      = 1,
+	.mpeg_mode          = LGDT3305_MPEG_PARALLEL,
+	.tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
+	.tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+	.vsb_if_khz         = 3250,
+	.qam_if_khz         = 4000,
+};
+
 static struct zl10353_config em28xx_zl10353_with_xc3028 = {
 	.demod_address = (0x1e >> 1),
 	.no_tuner = 1,
@@ -247,6 +261,17 @@
 	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
 };
 
+static struct tda18271_std_map kworld_a340_std_map = {
+	.atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 0,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 1,
+		      .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config kworld_a340_config = {
+	.std_map           = &kworld_a340_std_map,
+};
+
 static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
 	.demod_address = (0x1e >> 1),
 	.no_tuner = 1,
@@ -572,6 +597,14 @@
 			}
 		}
 		break;
+	case EM2870_BOARD_KWORLD_A340:
+		dvb->frontend = dvb_attach(lgdt3305_attach,
+					   &em2870_lgdt3304_dev,
+					   &dev->i2c_adap);
+		if (dvb->frontend != NULL)
+			dvb_attach(tda18271_attach, dvb->frontend, 0x60,
+				   &dev->i2c_adap, &kworld_a340_config);
+		break;
 	default:
 		em28xx_errdev("/2: The frontend of your DVB/ATSC card"
 				" isn't supported yet\n");
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 5c3fd94..6759cd5 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -65,17 +65,14 @@
 struct em28xx_IR {
 	struct em28xx *dev;
 	struct input_dev *input;
-	struct ir_input_state ir;
 	char name[32];
 	char phys[32];
 
 	/* poll external decoder */
 	int polling;
 	struct delayed_work work;
-	unsigned int last_toggle:1;
 	unsigned int full_code:1;
 	unsigned int last_readcount;
-	unsigned int repeat_interval;
 
 	int  (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
 
@@ -291,67 +288,39 @@
 static void em28xx_ir_handle_key(struct em28xx_IR *ir)
 {
 	int result;
-	int do_sendkey = 0;
 	struct em28xx_ir_poll_result poll_result;
 
 	/* read the registers containing the IR status */
 	result = ir->get_key(ir, &poll_result);
-	if (result < 0) {
+	if (unlikely(result < 0)) {
 		dprintk("ir->get_key() failed %d\n", result);
 		return;
 	}
 
-	dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x%02x\n",
-		poll_result.toggle_bit, poll_result.read_count,
-		ir->last_readcount, poll_result.rc_address,
-		poll_result.rc_data[0]);
-
-	if (ir->dev->chip_id == CHIP_ID_EM2874) {
-		/* The em2874 clears the readcount field every time the
-		   register is read.  The em2860/2880 datasheet says that it
-		   is supposed to clear the readcount, but it doesn't.  So with
-		   the em2874, we are looking for a non-zero read count as
-		   opposed to a readcount that is incrementing */
-		ir->last_readcount = 0;
-	}
-
-	if (poll_result.read_count == 0) {
-		/* The button has not been pressed since the last read */
-	} else if (ir->last_toggle != poll_result.toggle_bit) {
-		/* A button has been pressed */
-		dprintk("button has been pressed\n");
-		ir->last_toggle = poll_result.toggle_bit;
-		ir->repeat_interval = 0;
-		do_sendkey = 1;
-	} else if (poll_result.toggle_bit == ir->last_toggle &&
-		   poll_result.read_count > 0 &&
-		   poll_result.read_count != ir->last_readcount) {
-		/* The button is still being held down */
-		dprintk("button being held down\n");
-
-		/* Debouncer for first keypress */
-		if (ir->repeat_interval++ > 9) {
-			/* Start repeating after 1 second */
-			do_sendkey = 1;
-		}
-	}
-
-	if (do_sendkey) {
-		dprintk("sending keypress\n");
-
+	if (unlikely(poll_result.read_count != ir->last_readcount)) {
+		dprintk("%s: toggle: %d, count: %d, key 0x%02x%02x\n", __func__,
+			poll_result.toggle_bit, poll_result.read_count,
+			poll_result.rc_address, poll_result.rc_data[0]);
 		if (ir->full_code)
-			ir_input_keydown(ir->input, &ir->ir,
-					 poll_result.rc_address << 8 |
-					 poll_result.rc_data[0]);
+			ir_keydown(ir->input,
+				   poll_result.rc_address << 8 |
+				   poll_result.rc_data[0],
+				   poll_result.toggle_bit);
 		else
-			ir_input_keydown(ir->input, &ir->ir,
-					 poll_result.rc_data[0]);
+			ir_keydown(ir->input,
+				   poll_result.rc_data[0],
+				   poll_result.toggle_bit);
 
-		ir_input_nokey(ir->input, &ir->ir);
+		if (ir->dev->chip_id == CHIP_ID_EM2874)
+			/* The em2874 clears the readcount field every time the
+			   register is read.  The em2860/2880 datasheet says that it
+			   is supposed to clear the readcount, but it doesn't.  So with
+			   the em2874, we are looking for a non-zero read count as
+			   opposed to a readcount that is incrementing */
+			ir->last_readcount = 0;
+		else
+			ir->last_readcount = poll_result.read_count;
 	}
-
-	ir->last_readcount = poll_result.read_count;
-	return;
 }
 
 static void em28xx_ir_work(struct work_struct *work)
@@ -466,11 +435,6 @@
 	usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
 	strlcat(ir->phys, "/input0", sizeof(ir->phys));
 
-	/* Set IR protocol */
-	err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER);
-	if (err < 0)
-		goto err_out_free;
-
 	input_dev->name = ir->name;
 	input_dev->phys = ir->phys;
 	input_dev->id.bustype = BUS_USB;
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 20090e3..7b9ec6e 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -654,12 +654,12 @@
 		}
 
 		if (buf != NULL && dev->capture_type == 2) {
-			if (len > 4 && p[0] == 0x88 && p[1] == 0x88 &&
+			if (len >= 4 && p[0] == 0x88 && p[1] == 0x88 &&
 			    p[2] == 0x88 && p[3] == 0x88) {
 				p += 4;
 				len -= 4;
 			}
-			if (len > 4 && p[0] == 0x22 && p[1] == 0x5a) {
+			if (len >= 4 && p[0] == 0x22 && p[1] == 0x5a) {
 				em28xx_isocdbg("Video frame %d, len=%i, %s\n",
 					       p[2], len, (p[2] & 1) ?
 					       "odd" : "even");
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index b252d1b..1c61a6b 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -32,6 +32,7 @@
 #include <linux/i2c.h>
 #include <linux/mutex.h>
 #include <media/ir-kbd-i2c.h>
+#include <media/ir-core.h>
 #if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
 #include <media/videobuf-dvb.h>
 #endif
@@ -113,6 +114,7 @@
 #define EM2870_BOARD_REDDO_DVB_C_USB_BOX          73
 #define EM2800_BOARD_VC211A			  74
 #define EM2882_BOARD_DIKOM_DK300		  75
+#define EM2870_BOARD_KWORLD_A340		  76
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c
new file mode 100644
index 0000000..8f1c94f
--- /dev/null
+++ b/drivers/media/video/fsl-viu.c
@@ -0,0 +1,1632 @@
+/*
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ *  Freescale VIU video driver
+ *
+ *  Authors: Hongjun Chen <hong-jun.chen@freescale.com>
+ *	     Porting to 2.6.35 by DENX Software Engineering,
+ *	     Anatolij Gustschin <agust@denx.de>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/version.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf-dma-contig.h>
+
+#define DRV_NAME		"fsl_viu"
+#define VIU_MAJOR_VERSION	0
+#define VIU_MINOR_VERSION	5
+#define VIU_RELEASE		0
+#define VIU_VERSION		KERNEL_VERSION(VIU_MAJOR_VERSION, \
+					       VIU_MINOR_VERSION, \
+					       VIU_RELEASE)
+
+#define BUFFER_TIMEOUT		msecs_to_jiffies(500)  /* 0.5 seconds */
+
+#define	VIU_VID_MEM_LIMIT	4	/* Video memory limit, in Mb */
+
+/* I2C address of video decoder chip is 0x4A */
+#define VIU_VIDEO_DECODER_ADDR	0x25
+
+/* supported controls */
+static struct v4l2_queryctrl viu_qctrl[] = {
+	{
+		.id            = V4L2_CID_BRIGHTNESS,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Brightness",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 127,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_CONTRAST,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Contrast",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 0x1,
+		.default_value = 0x10,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_SATURATION,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Saturation",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 0x1,
+		.default_value = 127,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_HUE,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Hue",
+		.minimum       = -128,
+		.maximum       = 127,
+		.step          = 0x1,
+		.default_value = 0,
+		.flags         = 0,
+	}
+};
+
+static int qctl_regs[ARRAY_SIZE(viu_qctrl)];
+
+static int info_level;
+
+#define dprintk(level, fmt, arg...)					\
+	do {								\
+		if (level <= info_level)				\
+			printk(KERN_DEBUG "viu: " fmt , ## arg);	\
+	} while (0)
+
+/*
+ * Basic structures
+ */
+struct viu_fmt {
+	char  name[32];
+	u32   fourcc;		/* v4l2 format id */
+	u32   pixelformat;
+	int   depth;
+};
+
+static struct viu_fmt formats[] = {
+	{
+		.name		= "RGB-16 (5/B-6/G-5/R)",
+		.fourcc		= V4L2_PIX_FMT_RGB565,
+		.pixelformat	= V4L2_PIX_FMT_RGB565,
+		.depth		= 16,
+	}, {
+		.name		= "RGB-32 (A-R-G-B)",
+		.fourcc		= V4L2_PIX_FMT_RGB32,
+		.pixelformat	= V4L2_PIX_FMT_RGB32,
+		.depth		= 32,
+	}
+};
+
+struct viu_dev;
+struct viu_buf;
+
+/* buffer for one video frame */
+struct viu_buf {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+	struct viu_fmt *fmt;
+};
+
+struct viu_dmaqueue {
+	struct viu_dev		*dev;
+	struct list_head	active;
+	struct list_head	queued;
+	struct timer_list	timeout;
+};
+
+struct viu_status {
+	u32 field_irq;
+	u32 vsync_irq;
+	u32 hsync_irq;
+	u32 vstart_irq;
+	u32 dma_end_irq;
+	u32 error_irq;
+};
+
+struct viu_reg {
+	u32 status_cfg;
+	u32 luminance;
+	u32 chroma_r;
+	u32 chroma_g;
+	u32 chroma_b;
+	u32 field_base_addr;
+	u32 dma_inc;
+	u32 picture_count;
+	u32 req_alarm;
+	u32 alpha;
+} __attribute__ ((packed));
+
+struct viu_dev {
+	struct v4l2_device	v4l2_dev;
+	struct mutex		lock;
+	spinlock_t		slock;
+	int			users;
+
+	struct device		*dev;
+	/* various device info */
+	struct video_device	*vdev;
+	struct viu_dmaqueue	vidq;
+	enum v4l2_field		capfield;
+	int			field;
+	int			first;
+	int			dma_done;
+
+	/* Hardware register area */
+	struct viu_reg		*vr;
+
+	/* Interrupt vector */
+	int			irq;
+	struct viu_status	irqs;
+
+	/* video overlay */
+	struct v4l2_framebuffer	ovbuf;
+	struct viu_fmt		*ovfmt;
+	unsigned int		ovenable;
+	enum v4l2_field		ovfield;
+
+	/* crop */
+	struct v4l2_rect	crop_current;
+
+	/* clock pointer */
+	struct clk		*clk;
+
+	/* decoder */
+	struct v4l2_subdev	*decoder;
+};
+
+struct viu_fh {
+	struct viu_dev		*dev;
+
+	/* video capture */
+	struct videobuf_queue	vb_vidq;
+	spinlock_t		vbq_lock; /* spinlock for the videobuf queue */
+
+	/* video overlay */
+	struct v4l2_window	win;
+	struct v4l2_clip	clips[1];
+
+	/* video capture */
+	struct viu_fmt		*fmt;
+	int			width, height, sizeimage;
+	enum v4l2_buf_type	type;
+};
+
+static struct viu_reg reg_val;
+
+/*
+ * Macro definitions of VIU registers
+ */
+
+/* STATUS_CONFIG register */
+enum status_config {
+	SOFT_RST		= 1 << 0,
+
+	ERR_MASK		= 0x0f << 4,	/* Error code mask */
+	ERR_NO			= 0x00,		/* No error */
+	ERR_DMA_V		= 0x01 << 4,	/* DMA in vertical active */
+	ERR_DMA_VB		= 0x02 << 4,	/* DMA in vertical blanking */
+	ERR_LINE_TOO_LONG	= 0x04 << 4,	/* Line too long */
+	ERR_TOO_MANG_LINES	= 0x05 << 4,	/* Too many lines in field */
+	ERR_LINE_TOO_SHORT	= 0x06 << 4,	/* Line too short */
+	ERR_NOT_ENOUGH_LINE	= 0x07 << 4,	/* Not enough lines in field */
+	ERR_FIFO_OVERFLOW	= 0x08 << 4,	/* FIFO overflow */
+	ERR_FIFO_UNDERFLOW	= 0x09 << 4,	/* FIFO underflow */
+	ERR_1bit_ECC		= 0x0a << 4,	/* One bit ECC error */
+	ERR_MORE_ECC		= 0x0b << 4,	/* Two/more bits ECC error */
+
+	INT_FIELD_EN		= 0x01 << 8,	/* Enable field interrupt */
+	INT_VSYNC_EN		= 0x01 << 9,	/* Enable vsync interrupt */
+	INT_HSYNC_EN		= 0x01 << 10,	/* Enable hsync interrupt */
+	INT_VSTART_EN		= 0x01 << 11,	/* Enable vstart interrupt */
+	INT_DMA_END_EN		= 0x01 << 12,	/* Enable DMA end interrupt */
+	INT_ERROR_EN		= 0x01 << 13,	/* Enable error interrupt */
+	INT_ECC_EN		= 0x01 << 14,	/* Enable ECC interrupt */
+
+	INT_FIELD_STATUS	= 0x01 << 16,	/* field interrupt status */
+	INT_VSYNC_STATUS	= 0x01 << 17,	/* vsync interrupt status */
+	INT_HSYNC_STATUS	= 0x01 << 18,	/* hsync interrupt status */
+	INT_VSTART_STATUS	= 0x01 << 19,	/* vstart interrupt status */
+	INT_DMA_END_STATUS	= 0x01 << 20,	/* DMA end interrupt status */
+	INT_ERROR_STATUS	= 0x01 << 21,	/* error interrupt status */
+
+	DMA_ACT			= 0x01 << 27,	/* Enable DMA transfer */
+	FIELD_NO		= 0x01 << 28,	/* Field number */
+	DITHER_ON		= 0x01 << 29,	/* Dithering is on */
+	ROUND_ON		= 0x01 << 30,	/* Round is on */
+	MODE_32BIT		= 0x01 << 31,	/* Data in RGBa888,
+						 * 0 in RGB565
+						 */
+};
+
+#define norm_maxw()	720
+#define norm_maxh()	576
+
+#define INT_ALL_STATUS	(INT_FIELD_STATUS | INT_VSYNC_STATUS | \
+			 INT_HSYNC_STATUS | INT_VSTART_STATUS | \
+			 INT_DMA_END_STATUS | INT_ERROR_STATUS)
+
+#define NUM_FORMATS	ARRAY_SIZE(formats)
+
+static irqreturn_t viu_intr(int irq, void *dev_id);
+
+struct viu_fmt *format_by_fourcc(int fourcc)
+{
+	int i;
+
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (formats[i].pixelformat == fourcc)
+			return formats + i;
+	}
+
+	dprintk(0, "unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
+	return NULL;
+}
+
+void viu_start_dma(struct viu_dev *dev)
+{
+	struct viu_reg *vr = dev->vr;
+
+	dev->field = 0;
+
+	/* Enable DMA operation */
+	out_be32(&vr->status_cfg, SOFT_RST);
+	out_be32(&vr->status_cfg, INT_FIELD_EN);
+}
+
+void viu_stop_dma(struct viu_dev *dev)
+{
+	struct viu_reg *vr = dev->vr;
+	int cnt = 100;
+	u32 status_cfg;
+
+	out_be32(&vr->status_cfg, 0);
+
+	/* Clear pending interrupts */
+	status_cfg = in_be32(&vr->status_cfg);
+	if (status_cfg & 0x3f0000)
+		out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
+
+	if (status_cfg & DMA_ACT) {
+		do {
+			status_cfg = in_be32(&vr->status_cfg);
+			if (status_cfg & INT_DMA_END_STATUS)
+				break;
+		} while (cnt--);
+
+		if (cnt < 0) {
+			/* timed out, issue soft reset */
+			out_be32(&vr->status_cfg, SOFT_RST);
+			out_be32(&vr->status_cfg, 0);
+		} else {
+			/* clear DMA_END and other pending irqs */
+			out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
+		}
+	}
+
+	dev->field = 0;
+}
+
+static int restart_video_queue(struct viu_dmaqueue *vidq)
+{
+	struct viu_buf *buf, *prev;
+
+	dprintk(1, "%s vidq=0x%08lx\n", __func__, (unsigned long)vidq);
+	if (!list_empty(&vidq->active)) {
+		buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
+		dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+			buf, buf->vb.i);
+
+		viu_stop_dma(vidq->dev);
+
+		/* cancel all outstanding capture requests */
+		list_for_each_entry_safe(buf, prev, &vidq->active, vb.queue) {
+			list_del(&buf->vb.queue);
+			buf->vb.state = VIDEOBUF_ERROR;
+			wake_up(&buf->vb.done);
+		}
+		mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+		return 0;
+	}
+
+	prev = NULL;
+	for (;;) {
+		if (list_empty(&vidq->queued))
+			return 0;
+		buf = list_entry(vidq->queued.next, struct viu_buf, vb.queue);
+		if (prev == NULL) {
+			list_del(&buf->vb.queue);
+			list_add_tail(&buf->vb.queue, &vidq->active);
+
+			dprintk(1, "Restarting video dma\n");
+			viu_stop_dma(vidq->dev);
+			viu_start_dma(vidq->dev);
+
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+			dprintk(2, "[%p/%d] restart_queue - first active\n",
+				buf, buf->vb.i);
+
+		} else if (prev->vb.width  == buf->vb.width  &&
+			   prev->vb.height == buf->vb.height &&
+			   prev->fmt       == buf->fmt) {
+			list_del(&buf->vb.queue);
+			list_add_tail(&buf->vb.queue, &vidq->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			dprintk(2, "[%p/%d] restart_queue - move to active\n",
+				buf, buf->vb.i);
+		} else {
+			return 0;
+		}
+		prev = buf;
+	}
+}
+
+static void viu_vid_timeout(unsigned long data)
+{
+	struct viu_dev *dev = (struct viu_dev *)data;
+	struct viu_buf *buf;
+	struct viu_dmaqueue *vidq = &dev->vidq;
+
+	while (!list_empty(&vidq->active)) {
+		buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
+		list_del(&buf->vb.queue);
+		buf->vb.state = VIDEOBUF_ERROR;
+		wake_up(&buf->vb.done);
+		dprintk(1, "viu/0: [%p/%d] timeout\n", buf, buf->vb.i);
+	}
+
+	restart_video_queue(vidq);
+}
+
+/*
+ * Videobuf operations
+ */
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+			unsigned int *size)
+{
+	struct viu_fh *fh = vq->priv_data;
+
+	*size = fh->width * fh->height * fh->fmt->depth >> 3;
+	if (*count == 0)
+		*count = 32;
+
+	while (*size * *count > VIU_VID_MEM_LIMIT * 1024 * 1024)
+		(*count)--;
+
+	dprintk(1, "%s, count=%d, size=%d\n", __func__, *count, *size);
+	return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf)
+{
+	struct videobuf_buffer *vb = &buf->vb;
+	void *vaddr = NULL;
+
+	BUG_ON(in_interrupt());
+
+	videobuf_waiton(&buf->vb, 0, 0);
+
+	if (vq->int_ops && vq->int_ops->vaddr)
+		vaddr = vq->int_ops->vaddr(vb);
+
+	if (vaddr)
+		videobuf_dma_contig_free(vq, &buf->vb);
+
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf)
+{
+	struct viu_reg *vr = dev->vr;
+	int bpp;
+
+	/* setup the DMA base address */
+	reg_val.field_base_addr = videobuf_to_dma_contig(&buf->vb);
+
+	dprintk(1, "buffer_activate [%p/%d]: dma addr 0x%lx\n",
+		buf, buf->vb.i, (unsigned long)reg_val.field_base_addr);
+
+	/* interlace is on by default, set horizontal DMA increment */
+	reg_val.status_cfg = 0;
+	bpp = buf->fmt->depth >> 3;
+	switch (bpp) {
+	case 2:
+		reg_val.status_cfg &= ~MODE_32BIT;
+		reg_val.dma_inc = buf->vb.width * 2;
+		break;
+	case 4:
+		reg_val.status_cfg |= MODE_32BIT;
+		reg_val.dma_inc = buf->vb.width * 4;
+		break;
+	default:
+		dprintk(0, "doesn't support color depth(%d)\n",
+			bpp * 8);
+		return -EINVAL;
+	}
+
+	/* setup picture_count register */
+	reg_val.picture_count = (buf->vb.height / 2) << 16 |
+				buf->vb.width;
+
+	reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
+
+	buf->vb.state = VIDEOBUF_ACTIVE;
+	dev->capfield = buf->vb.field;
+
+	/* reset dma increment if needed */
+	if (!V4L2_FIELD_HAS_BOTH(buf->vb.field))
+		reg_val.dma_inc = 0;
+
+	out_be32(&vr->dma_inc, reg_val.dma_inc);
+	out_be32(&vr->picture_count, reg_val.picture_count);
+	out_be32(&vr->field_base_addr, reg_val.field_base_addr);
+	mod_timer(&dev->vidq.timeout, jiffies + BUFFER_TIMEOUT);
+	return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq,
+			  struct videobuf_buffer *vb,
+			  enum v4l2_field field)
+{
+	struct viu_fh  *fh  = vq->priv_data;
+	struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
+	int rc;
+
+	BUG_ON(fh->fmt == NULL);
+
+	if (fh->width  < 48 || fh->width  > norm_maxw() ||
+	    fh->height < 32 || fh->height > norm_maxh())
+		return -EINVAL;
+	buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+	if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	if (buf->fmt       != fh->fmt	 ||
+	    buf->vb.width  != fh->width  ||
+	    buf->vb.height != fh->height ||
+	    buf->vb.field  != field) {
+		buf->fmt       = fh->fmt;
+		buf->vb.width  = fh->width;
+		buf->vb.height = fh->height;
+		buf->vb.field  = field;
+	}
+
+	if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+		rc = videobuf_iolock(vq, &buf->vb, NULL);
+		if (rc != 0)
+			goto fail;
+
+		buf->vb.width  = fh->width;
+		buf->vb.height = fh->height;
+		buf->vb.field  = field;
+		buf->fmt       = fh->fmt;
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+fail:
+	free_buffer(vq, buf);
+	return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct viu_buf       *buf     = container_of(vb, struct viu_buf, vb);
+	struct viu_fh        *fh      = vq->priv_data;
+	struct viu_dev       *dev     = fh->dev;
+	struct viu_dmaqueue  *vidq    = &dev->vidq;
+	struct viu_buf       *prev;
+
+	if (!list_empty(&vidq->queued)) {
+		dprintk(1, "adding vb queue=0x%08lx\n",
+				(unsigned long)&buf->vb.queue);
+		dprintk(1, "vidq pointer 0x%p, queued 0x%p\n",
+				vidq, &vidq->queued);
+		dprintk(1, "dev %p, queued: self %p, next %p, head %p\n",
+			dev, &vidq->queued, vidq->queued.next,
+			vidq->queued.prev);
+		list_add_tail(&buf->vb.queue, &vidq->queued);
+		buf->vb.state = VIDEOBUF_QUEUED;
+		dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
+			buf, buf->vb.i);
+	} else if (list_empty(&vidq->active)) {
+		dprintk(1, "adding vb active=0x%08lx\n",
+				(unsigned long)&buf->vb.queue);
+		list_add_tail(&buf->vb.queue, &vidq->active);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+		dprintk(2, "[%p/%d] buffer_queue - first active\n",
+			buf, buf->vb.i);
+
+		buffer_activate(dev, buf);
+	} else {
+		dprintk(1, "adding vb queue2=0x%08lx\n",
+				(unsigned long)&buf->vb.queue);
+		prev = list_entry(vidq->active.prev, struct viu_buf, vb.queue);
+		if (prev->vb.width  == buf->vb.width  &&
+		    prev->vb.height == buf->vb.height &&
+		    prev->fmt       == buf->fmt) {
+			list_add_tail(&buf->vb.queue, &vidq->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+				buf, buf->vb.i);
+		} else {
+			list_add_tail(&buf->vb.queue, &vidq->queued);
+			buf->vb.state = VIDEOBUF_QUEUED;
+			dprintk(2, "[%p/%d] buffer_queue - first queued\n",
+				buf, buf->vb.i);
+		}
+	}
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+				struct videobuf_buffer *vb)
+{
+	struct viu_buf *buf  = container_of(vb, struct viu_buf, vb);
+	struct viu_fh  *fh   = vq->priv_data;
+	struct viu_dev *dev  = (struct viu_dev *)fh->dev;
+
+	viu_stop_dma(dev);
+	free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops viu_video_qops = {
+	.buf_setup      = buffer_setup,
+	.buf_prepare    = buffer_prepare,
+	.buf_queue      = buffer_queue,
+	.buf_release    = buffer_release,
+};
+
+/*
+ * IOCTL vidioc handling
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	strcpy(cap->driver, "viu");
+	strcpy(cap->card, "viu");
+	cap->version = VIU_VERSION;
+	cap->capabilities =	V4L2_CAP_VIDEO_CAPTURE |
+				V4L2_CAP_STREAMING     |
+				V4L2_CAP_VIDEO_OVERLAY |
+				V4L2_CAP_READWRITE;
+	return 0;
+}
+
+static int vidioc_enum_fmt(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	int index = f->index;
+
+	if (f->index > NUM_FORMATS)
+		return -EINVAL;
+
+	strlcpy(f->description, formats[index].name, sizeof(f->description));
+	f->pixelformat = formats[index].fourcc;
+	return 0;
+}
+
+static int vidioc_g_fmt_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct viu_fh *fh = priv;
+
+	f->fmt.pix.width        = fh->width;
+	f->fmt.pix.height       = fh->height;
+	f->fmt.pix.field        = fh->vb_vidq.field;
+	f->fmt.pix.pixelformat  = fh->fmt->pixelformat;
+	f->fmt.pix.bytesperline =
+			(f->fmt.pix.width * fh->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage	= fh->sizeimage;
+	return 0;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct viu_fmt *fmt;
+	enum v4l2_field field;
+	unsigned int maxw, maxh;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (!fmt) {
+		dprintk(1, "Fourcc format (0x%08x) invalid.",
+			f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	field = f->fmt.pix.field;
+
+	if (field == V4L2_FIELD_ANY) {
+		field = V4L2_FIELD_INTERLACED;
+	} else if (field != V4L2_FIELD_INTERLACED) {
+		dprintk(1, "Field type invalid.\n");
+		return -EINVAL;
+	}
+
+	maxw  = norm_maxw();
+	maxh  = norm_maxh();
+
+	f->fmt.pix.field = field;
+	if (f->fmt.pix.height < 32)
+		f->fmt.pix.height = 32;
+	if (f->fmt.pix.height > maxh)
+		f->fmt.pix.height = maxh;
+	if (f->fmt.pix.width < 48)
+		f->fmt.pix.width = 48;
+	if (f->fmt.pix.width > maxw)
+		f->fmt.pix.width = maxw;
+	f->fmt.pix.width &= ~0x03;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fmt->depth) >> 3;
+
+	return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct viu_fh *fh = priv;
+	int ret;
+
+	ret = vidioc_try_fmt_cap(file, fh, f);
+	if (ret < 0)
+		return ret;
+
+	fh->fmt           = format_by_fourcc(f->fmt.pix.pixelformat);
+	fh->width         = f->fmt.pix.width;
+	fh->height        = f->fmt.pix.height;
+	fh->sizeimage     = f->fmt.pix.sizeimage;
+	fh->vb_vidq.field = f->fmt.pix.field;
+	fh->type          = f->type;
+	dprintk(1, "set to pixelformat '%4.6s'\n", (char *)&fh->fmt->name);
+	return 0;
+}
+
+static int vidioc_g_fmt_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct viu_fh *fh = priv;
+
+	f->fmt.win = fh->win;
+	return 0;
+}
+
+static int verify_preview(struct viu_dev *dev, struct v4l2_window *win)
+{
+	enum v4l2_field field;
+	int maxw, maxh;
+
+	if (dev->ovbuf.base == NULL)
+		return -EINVAL;
+	if (dev->ovfmt == NULL)
+		return -EINVAL;
+	if (win->w.width < 48 || win->w.height < 32)
+		return -EINVAL;
+
+	field = win->field;
+	maxw  = dev->crop_current.width;
+	maxh  = dev->crop_current.height;
+
+	if (field == V4L2_FIELD_ANY) {
+		field = (win->w.height > maxh/2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_TOP;
+	}
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		maxh = maxh / 2;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	win->field = field;
+	if (win->w.width > maxw)
+		win->w.width = maxw;
+	if (win->w.height > maxh)
+		win->w.height = maxh;
+	return 0;
+}
+
+inline void viu_activate_overlay(struct viu_reg *viu_reg)
+{
+	struct viu_reg *vr = viu_reg;
+
+	out_be32(&vr->field_base_addr, reg_val.field_base_addr);
+	out_be32(&vr->dma_inc, reg_val.dma_inc);
+	out_be32(&vr->picture_count, reg_val.picture_count);
+}
+
+static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh)
+{
+	int bpp;
+
+	dprintk(1, "%s %dx%d %s\n", __func__,
+		fh->win.w.width, fh->win.w.height, dev->ovfmt->name);
+
+	reg_val.status_cfg = 0;
+
+	/* setup window */
+	reg_val.picture_count = (fh->win.w.height / 2) << 16 |
+				fh->win.w.width;
+
+	/* setup color depth and dma increment */
+	bpp = dev->ovfmt->depth / 8;
+	switch (bpp) {
+	case 2:
+		reg_val.status_cfg &= ~MODE_32BIT;
+		reg_val.dma_inc = fh->win.w.width * 2;
+		break;
+	case 4:
+		reg_val.status_cfg |= MODE_32BIT;
+		reg_val.dma_inc = fh->win.w.width * 4;
+		break;
+	default:
+		dprintk(0, "device doesn't support color depth(%d)\n",
+			bpp * 8);
+		return -EINVAL;
+	}
+
+	dev->ovfield = fh->win.field;
+	if (!V4L2_FIELD_HAS_BOTH(dev->ovfield))
+		reg_val.dma_inc = 0;
+
+	reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
+
+	/* setup the base address of the overlay buffer */
+	reg_val.field_base_addr = (u32)dev->ovbuf.base;
+
+	dev->ovenable = 1;
+	viu_activate_overlay(dev->vr);
+
+	/* start dma */
+	viu_start_dma(dev);
+	return 0;
+}
+
+static int vidioc_s_fmt_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct viu_fh  *fh  = priv;
+	struct viu_dev *dev = (struct viu_dev *)fh->dev;
+	unsigned long  flags;
+	int err;
+
+	err = verify_preview(dev, &f->fmt.win);
+	if (err)
+		return err;
+
+	mutex_lock(&dev->lock);
+	fh->win = f->fmt.win;
+
+	spin_lock_irqsave(&dev->slock, flags);
+	viu_start_preview(dev, fh);
+	spin_unlock_irqrestore(&dev->slock, flags);
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int vidioc_try_fmt_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	return 0;
+}
+
+int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
+{
+	struct viu_fh  *fh = priv;
+	struct viu_dev *dev = fh->dev;
+	struct v4l2_framebuffer *fb = arg;
+
+	*fb = dev->ovbuf;
+	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+	return 0;
+}
+
+int vidioc_s_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
+{
+	struct viu_fh  *fh = priv;
+	struct viu_dev *dev = fh->dev;
+	struct v4l2_framebuffer *fb = arg;
+	struct viu_fmt *fmt;
+
+	if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	/* check args */
+	fmt = format_by_fourcc(fb->fmt.pixelformat);
+	if (fmt == NULL)
+		return -EINVAL;
+
+	/* ok, accept it */
+	dev->ovbuf = *fb;
+	dev->ovfmt = fmt;
+	if (dev->ovbuf.fmt.bytesperline == 0) {
+		dev->ovbuf.fmt.bytesperline =
+			dev->ovbuf.fmt.width * fmt->depth / 8;
+	}
+	return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+				struct v4l2_requestbuffers *p)
+{
+	struct viu_fh *fh = priv;
+
+	return videobuf_reqbufs(&fh->vb_vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+					struct v4l2_buffer *p)
+{
+	struct viu_fh *fh = priv;
+
+	return videobuf_querybuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct viu_fh *fh = priv;
+
+	return videobuf_qbuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct viu_fh *fh = priv;
+
+	return videobuf_dqbuf(&fh->vb_vidq, p,
+				file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct viu_fh *fh = priv;
+
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (fh->type != i)
+		return -EINVAL;
+
+	return videobuf_streamon(&fh->vb_vidq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct viu_fh  *fh = priv;
+
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (fh->type != i)
+		return -EINVAL;
+
+	return videobuf_streamoff(&fh->vb_vidq);
+}
+
+#define decoder_call(viu, o, f, args...) \
+	v4l2_subdev_call(viu->decoder, o, f, ##args)
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct viu_fh *fh = priv;
+
+	decoder_call(fh->dev, core, s_std, *id);
+	return 0;
+}
+
+/* only one input in this driver */
+static int vidioc_enum_input(struct file *file, void *priv,
+					struct v4l2_input *inp)
+{
+	struct viu_fh *fh = priv;
+
+	if (inp->index != 0)
+		return -EINVAL;
+
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	inp->std = fh->dev->vdev->tvnorms;
+	strcpy(inp->name, "Camera");
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct viu_fh *fh = priv;
+
+	if (i > 1)
+		return -EINVAL;
+
+	decoder_call(fh->dev, video, s_routing, i, 0, 0);
+	return 0;
+}
+
+/* Controls */
+static int vidioc_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+		if (qc->id && qc->id == viu_qctrl[i].id) {
+			memcpy(qc, &(viu_qctrl[i]), sizeof(*qc));
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+		if (ctrl->id == viu_qctrl[i].id) {
+			ctrl->value = qctl_regs[i];
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+static int vidioc_s_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+		if (ctrl->id == viu_qctrl[i].id) {
+			if (ctrl->value < viu_qctrl[i].minimum
+				|| ctrl->value > viu_qctrl[i].maximum)
+					return -ERANGE;
+			qctl_regs[i] = ctrl->value;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+inline void viu_activate_next_buf(struct viu_dev *dev,
+				struct viu_dmaqueue *viuq)
+{
+	struct viu_dmaqueue *vidq = viuq;
+	struct viu_buf *buf;
+
+	/* launch another DMA operation for an active/queued buffer */
+	if (!list_empty(&vidq->active)) {
+		buf = list_entry(vidq->active.next, struct viu_buf,
+					vb.queue);
+		dprintk(1, "start another queued buffer: 0x%p\n", buf);
+		buffer_activate(dev, buf);
+	} else if (!list_empty(&vidq->queued)) {
+		buf = list_entry(vidq->queued.next, struct viu_buf,
+					vb.queue);
+		list_del(&buf->vb.queue);
+
+		dprintk(1, "start another queued buffer: 0x%p\n", buf);
+		list_add_tail(&buf->vb.queue, &vidq->active);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buffer_activate(dev, buf);
+	}
+}
+
+inline void viu_default_settings(struct viu_reg *viu_reg)
+{
+	struct viu_reg *vr = viu_reg;
+
+	out_be32(&vr->luminance, 0x9512A254);
+	out_be32(&vr->chroma_r, 0x03310000);
+	out_be32(&vr->chroma_g, 0x06600F38);
+	out_be32(&vr->chroma_b, 0x00000409);
+	out_be32(&vr->alpha, 0x000000ff);
+	out_be32(&vr->req_alarm, 0x00000090);
+	dprintk(1, "status reg: 0x%08x, field base: 0x%08x\n",
+		in_be32(&vr->status_cfg), in_be32(&vr->field_base_addr));
+}
+
+static void viu_overlay_intr(struct viu_dev *dev, u32 status)
+{
+	struct viu_reg *vr = dev->vr;
+
+	if (status & INT_DMA_END_STATUS)
+		dev->dma_done = 1;
+
+	if (status & INT_FIELD_STATUS) {
+		if (dev->dma_done) {
+			u32 addr = reg_val.field_base_addr;
+
+			dev->dma_done = 0;
+			if (status & FIELD_NO)
+				addr += reg_val.dma_inc;
+
+			out_be32(&vr->field_base_addr, addr);
+			out_be32(&vr->dma_inc, reg_val.dma_inc);
+			out_be32(&vr->status_cfg,
+				 (status & 0xffc0ffff) |
+				 (status & INT_ALL_STATUS) |
+				 reg_val.status_cfg);
+		} else if (status & INT_VSYNC_STATUS) {
+			out_be32(&vr->status_cfg,
+				 (status & 0xffc0ffff) |
+				 (status & INT_ALL_STATUS) |
+				 reg_val.status_cfg);
+		}
+	}
+}
+
+static void viu_capture_intr(struct viu_dev *dev, u32 status)
+{
+	struct viu_dmaqueue *vidq = &dev->vidq;
+	struct viu_reg *vr = dev->vr;
+	struct viu_buf *buf;
+	int field_num;
+	int need_two;
+	int dma_done = 0;
+
+	field_num = status & FIELD_NO;
+	need_two = V4L2_FIELD_HAS_BOTH(dev->capfield);
+
+	if (status & INT_DMA_END_STATUS) {
+		dma_done = 1;
+		if (((field_num == 0) && (dev->field == 0)) ||
+		    (field_num && (dev->field == 1)))
+			dev->field++;
+	}
+
+	if (status & INT_FIELD_STATUS) {
+		dprintk(1, "irq: field %d, done %d\n",
+			!!field_num, dma_done);
+		if (unlikely(dev->first)) {
+			if (field_num == 0) {
+				dev->first = 0;
+				dprintk(1, "activate first buf\n");
+				viu_activate_next_buf(dev, vidq);
+			} else
+				dprintk(1, "wait field 0\n");
+			return;
+		}
+
+		/* setup buffer address for next dma operation */
+		if (!list_empty(&vidq->active)) {
+			u32 addr = reg_val.field_base_addr;
+
+			if (field_num && need_two) {
+				addr += reg_val.dma_inc;
+				dprintk(1, "field 1, 0x%lx, dev field %d\n",
+					(unsigned long)addr, dev->field);
+			}
+			out_be32(&vr->field_base_addr, addr);
+			out_be32(&vr->dma_inc, reg_val.dma_inc);
+			out_be32(&vr->status_cfg,
+				 (status & 0xffc0ffff) |
+				 (status & INT_ALL_STATUS) |
+				 reg_val.status_cfg);
+			return;
+		}
+	}
+
+	if (dma_done && field_num && (dev->field == 2)) {
+		dev->field = 0;
+		buf = list_entry(vidq->active.next,
+				 struct viu_buf, vb.queue);
+		dprintk(1, "viu/0: [%p/%d] 0x%lx/0x%lx: dma complete\n",
+			buf, buf->vb.i,
+			(unsigned long)videobuf_to_dma_contig(&buf->vb),
+			(unsigned long)in_be32(&vr->field_base_addr));
+
+		if (waitqueue_active(&buf->vb.done)) {
+			list_del(&buf->vb.queue);
+			do_gettimeofday(&buf->vb.ts);
+			buf->vb.state = VIDEOBUF_DONE;
+			buf->vb.field_count++;
+			wake_up(&buf->vb.done);
+		}
+		/* activate next dma buffer */
+		viu_activate_next_buf(dev, vidq);
+	}
+}
+
+static irqreturn_t viu_intr(int irq, void *dev_id)
+{
+	struct viu_dev *dev  = (struct viu_dev *)dev_id;
+	struct viu_reg *vr = dev->vr;
+	u32 status;
+	u32 error;
+
+	status = in_be32(&vr->status_cfg);
+
+	if (status & INT_ERROR_STATUS) {
+		dev->irqs.error_irq++;
+		error = status & ERR_MASK;
+		if (error)
+			dprintk(1, "Err: error(%d), times:%d!\n",
+				error >> 4, dev->irqs.error_irq);
+		/* Clear interrupt error bit and error flags */
+		out_be32(&vr->status_cfg,
+			 (status & 0xffc0ffff) | INT_ERROR_STATUS);
+	}
+
+	if (status & INT_DMA_END_STATUS) {
+		dev->irqs.dma_end_irq++;
+		dev->dma_done = 1;
+		dprintk(2, "VIU DMA end interrupt times: %d\n",
+					dev->irqs.dma_end_irq);
+	}
+
+	if (status & INT_HSYNC_STATUS)
+		dev->irqs.hsync_irq++;
+
+	if (status & INT_FIELD_STATUS) {
+		dev->irqs.field_irq++;
+		dprintk(2, "VIU field interrupt times: %d\n",
+					dev->irqs.field_irq);
+	}
+
+	if (status & INT_VSTART_STATUS)
+		dev->irqs.vstart_irq++;
+
+	if (status & INT_VSYNC_STATUS) {
+		dev->irqs.vsync_irq++;
+		dprintk(2, "VIU vsync interrupt times: %d\n",
+			dev->irqs.vsync_irq);
+	}
+
+	/* clear all pending irqs */
+	status = in_be32(&vr->status_cfg);
+	out_be32(&vr->status_cfg,
+		 (status & 0xffc0ffff) | (status & INT_ALL_STATUS));
+
+	if (dev->ovenable) {
+		viu_overlay_intr(dev, status);
+		return IRQ_HANDLED;
+	}
+
+	/* Capture mode */
+	viu_capture_intr(dev, status);
+	return IRQ_HANDLED;
+}
+
+/*
+ * File operations for the device
+ */
+static int viu_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct viu_dev *dev = video_get_drvdata(vdev);
+	struct viu_fh *fh;
+	struct viu_reg *vr;
+	int minor = vdev->minor;
+	u32 status_cfg;
+	int i;
+
+	dprintk(1, "viu: open (minor=%d)\n", minor);
+
+	dev->users++;
+	if (dev->users > 1) {
+		dev->users--;
+		return -EBUSY;
+	}
+
+	vr = dev->vr;
+
+	dprintk(1, "open minor=%d type=%s users=%d\n", minor,
+		v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
+
+	/* allocate and initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (!fh) {
+		dev->users--;
+		return -ENOMEM;
+	}
+
+	file->private_data = fh;
+	fh->dev = dev;
+
+	fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_RGB32);
+	fh->width    = norm_maxw();
+	fh->height   = norm_maxh();
+	dev->crop_current.width  = fh->width;
+	dev->crop_current.height = fh->height;
+
+	/* Put all controls at a sane state */
+	for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++)
+		qctl_regs[i] = viu_qctrl[i].default_value;
+
+	dprintk(1, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n",
+		(unsigned long)fh, (unsigned long)dev,
+		(unsigned long)&dev->vidq);
+	dprintk(1, "Open: list_empty queued=%d\n",
+		list_empty(&dev->vidq.queued));
+	dprintk(1, "Open: list_empty active=%d\n",
+		list_empty(&dev->vidq.active));
+
+	viu_default_settings(vr);
+
+	status_cfg = in_be32(&vr->status_cfg);
+	out_be32(&vr->status_cfg,
+		 status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN |
+				INT_FIELD_EN | INT_VSTART_EN |
+				INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN));
+
+	status_cfg = in_be32(&vr->status_cfg);
+	out_be32(&vr->status_cfg, status_cfg | INT_ALL_STATUS);
+
+	spin_lock_init(&fh->vbq_lock);
+	videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops,
+				       dev->dev, &fh->vbq_lock,
+				       fh->type, V4L2_FIELD_INTERLACED,
+				       sizeof(struct viu_buf), fh);
+	return 0;
+}
+
+static ssize_t viu_read(struct file *file, char __user *data, size_t count,
+			loff_t *ppos)
+{
+	struct viu_fh *fh = file->private_data;
+	struct viu_dev *dev = fh->dev;
+	int ret = 0;
+
+	dprintk(2, "%s\n", __func__);
+	if (dev->ovenable)
+		dev->ovenable = 0;
+
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		viu_start_dma(dev);
+		ret = videobuf_read_stream(&fh->vb_vidq, data, count,
+				ppos, 0, file->f_flags & O_NONBLOCK);
+		return ret;
+	}
+	return 0;
+}
+
+static unsigned int viu_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct viu_fh *fh = file->private_data;
+	struct videobuf_queue *q = &fh->vb_vidq;
+
+	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+		return POLLERR;
+
+	return videobuf_poll_stream(file, q, wait);
+}
+
+static int viu_release(struct file *file)
+{
+	struct viu_fh *fh = file->private_data;
+	struct viu_dev *dev = fh->dev;
+	int minor = video_devdata(file)->minor;
+
+	viu_stop_dma(dev);
+	videobuf_stop(&fh->vb_vidq);
+
+	kfree(fh);
+
+	dev->users--;
+	dprintk(1, "close (minor=%d, users=%d)\n",
+		minor, dev->users);
+	return 0;
+}
+
+void viu_reset(struct viu_reg *reg)
+{
+	out_be32(&reg->status_cfg, 0);
+	out_be32(&reg->luminance, 0x9512a254);
+	out_be32(&reg->chroma_r, 0x03310000);
+	out_be32(&reg->chroma_g, 0x06600f38);
+	out_be32(&reg->chroma_b, 0x00000409);
+	out_be32(&reg->field_base_addr, 0);
+	out_be32(&reg->dma_inc, 0);
+	out_be32(&reg->picture_count, 0x01e002d0);
+	out_be32(&reg->req_alarm, 0x00000090);
+	out_be32(&reg->alpha, 0x000000ff);
+}
+
+static int viu_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct viu_fh *fh = file->private_data;
+	int ret;
+
+	dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+	ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+
+	dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n",
+		(unsigned long)vma->vm_start,
+		(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+		ret);
+
+	return ret;
+}
+
+static struct v4l2_file_operations viu_fops = {
+	.owner		= THIS_MODULE,
+	.open		= viu_open,
+	.release	= viu_release,
+	.read		= viu_read,
+	.poll		= viu_poll,
+	.ioctl		= video_ioctl2, /* V4L2 ioctl handler */
+	.mmap		= viu_mmap,
+};
+
+static const struct v4l2_ioctl_ops viu_ioctl_ops = {
+	.vidioc_querycap	= vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_cap,
+	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_cap,
+	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_cap,
+	.vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay,
+	.vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay,
+	.vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay,
+	.vidioc_g_fbuf	      = vidioc_g_fbuf,
+	.vidioc_s_fbuf	      = vidioc_s_fbuf,
+	.vidioc_reqbufs       = vidioc_reqbufs,
+	.vidioc_querybuf      = vidioc_querybuf,
+	.vidioc_qbuf          = vidioc_qbuf,
+	.vidioc_dqbuf         = vidioc_dqbuf,
+	.vidioc_s_std         = vidioc_s_std,
+	.vidioc_enum_input    = vidioc_enum_input,
+	.vidioc_g_input       = vidioc_g_input,
+	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_queryctrl     = vidioc_queryctrl,
+	.vidioc_g_ctrl        = vidioc_g_ctrl,
+	.vidioc_s_ctrl        = vidioc_s_ctrl,
+	.vidioc_streamon      = vidioc_streamon,
+	.vidioc_streamoff     = vidioc_streamoff,
+};
+
+static struct video_device viu_template = {
+	.name		= "FSL viu",
+	.fops		= &viu_fops,
+	.minor		= -1,
+	.ioctl_ops	= &viu_ioctl_ops,
+	.release	= video_device_release,
+
+	.tvnorms        = V4L2_STD_NTSC_M | V4L2_STD_PAL,
+	.current_norm   = V4L2_STD_NTSC_M,
+};
+
+static int __devinit viu_of_probe(struct of_device *op,
+				  const struct of_device_id *match)
+{
+	struct viu_dev *viu_dev;
+	struct video_device *vdev;
+	struct resource r;
+	struct viu_reg __iomem *viu_regs;
+	struct i2c_adapter *ad;
+	int ret, viu_irq;
+
+	ret = of_address_to_resource(op->dev.of_node, 0, &r);
+	if (ret) {
+		dev_err(&op->dev, "Can't parse device node resource\n");
+		return -ENODEV;
+	}
+
+	viu_irq = irq_of_parse_and_map(op->dev.of_node, 0);
+	if (viu_irq == NO_IRQ) {
+		dev_err(&op->dev, "Error while mapping the irq\n");
+		return -EINVAL;
+	}
+
+	/* request mem region */
+	if (!devm_request_mem_region(&op->dev, r.start,
+				     sizeof(struct viu_reg), DRV_NAME)) {
+		dev_err(&op->dev, "Error while requesting mem region\n");
+		ret = -EBUSY;
+		goto err;
+	}
+
+	/* remap registers */
+	viu_regs = devm_ioremap(&op->dev, r.start, sizeof(struct viu_reg));
+	if (!viu_regs) {
+		dev_err(&op->dev, "Can't map register set\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	/* Prepare our private structure */
+	viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_ATOMIC);
+	if (!viu_dev) {
+		dev_err(&op->dev, "Can't allocate private structure\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	viu_dev->vr = viu_regs;
+	viu_dev->irq = viu_irq;
+	viu_dev->dev = &op->dev;
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&viu_dev->vidq.active);
+	INIT_LIST_HEAD(&viu_dev->vidq.queued);
+
+	/* initialize locks */
+	mutex_init(&viu_dev->lock);
+
+	snprintf(viu_dev->v4l2_dev.name,
+		 sizeof(viu_dev->v4l2_dev.name), "%s", "VIU");
+	ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev);
+	if (ret < 0) {
+		dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret);
+		goto err;
+	}
+
+	ad = i2c_get_adapter(0);
+	viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad,
+			"saa7115", "saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
+
+	viu_dev->vidq.timeout.function = viu_vid_timeout;
+	viu_dev->vidq.timeout.data     = (unsigned long)viu_dev;
+	init_timer(&viu_dev->vidq.timeout);
+	viu_dev->first = 1;
+
+	/* Allocate memory for video device */
+	vdev = video_device_alloc();
+	if (vdev == NULL) {
+		ret = -ENOMEM;
+		goto err_vdev;
+	}
+
+	memcpy(vdev, &viu_template, sizeof(viu_template));
+
+	vdev->v4l2_dev = &viu_dev->v4l2_dev;
+
+	viu_dev->vdev = vdev;
+
+	video_set_drvdata(viu_dev->vdev, viu_dev);
+
+	ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1);
+	if (ret < 0) {
+		video_device_release(viu_dev->vdev);
+		goto err_vdev;
+	}
+
+	/* enable VIU clock */
+	viu_dev->clk = clk_get(&op->dev, "viu_clk");
+	if (IS_ERR(viu_dev->clk)) {
+		dev_err(&op->dev, "failed to find the clock module!\n");
+		ret = -ENODEV;
+		goto err_clk;
+	} else {
+		clk_enable(viu_dev->clk);
+	}
+
+	/* reset VIU module */
+	viu_reset(viu_dev->vr);
+
+	/* install interrupt handler */
+	if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) {
+		dev_err(&op->dev, "Request VIU IRQ failed.\n");
+		ret = -ENODEV;
+		goto err_irq;
+	}
+
+	dev_info(&op->dev, "Freescale VIU Video Capture Board\n");
+	return ret;
+
+err_irq:
+	clk_disable(viu_dev->clk);
+	clk_put(viu_dev->clk);
+err_clk:
+	video_unregister_device(viu_dev->vdev);
+err_vdev:
+	i2c_put_adapter(ad);
+	v4l2_device_unregister(&viu_dev->v4l2_dev);
+err:
+	irq_dispose_mapping(viu_irq);
+	return ret;
+}
+
+static int __devexit viu_of_remove(struct of_device *op)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+	struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+	struct v4l2_subdev *sdev = list_entry(v4l2_dev->subdevs.next,
+					      struct v4l2_subdev, list);
+	struct i2c_client *client = v4l2_get_subdevdata(sdev);
+
+	free_irq(dev->irq, (void *)dev);
+	irq_dispose_mapping(dev->irq);
+
+	clk_disable(dev->clk);
+	clk_put(dev->clk);
+
+	video_unregister_device(dev->vdev);
+	i2c_put_adapter(client->adapter);
+	v4l2_device_unregister(&dev->v4l2_dev);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int viu_suspend(struct of_device *op, pm_message_t state)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+	struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+
+	clk_disable(dev->clk);
+	return 0;
+}
+
+static int viu_resume(struct of_device *op)
+{
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+	struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+
+	clk_enable(dev->clk);
+	return 0;
+}
+#endif
+
+/*
+ * Initialization and module stuff
+ */
+static struct of_device_id mpc512x_viu_of_match[] = {
+	{
+		.compatible = "fsl,mpc5121-viu",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match);
+
+static struct of_platform_driver viu_of_platform_driver = {
+	.probe = viu_of_probe,
+	.remove = __devexit_p(viu_of_remove),
+#ifdef CONFIG_PM
+	.suspend = viu_suspend,
+	.resume = viu_resume,
+#endif
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = mpc512x_viu_of_match,
+	},
+};
+
+static int __init viu_init(void)
+{
+	return of_register_platform_driver(&viu_of_platform_driver);
+}
+
+static void __exit viu_exit(void)
+{
+	of_unregister_platform_driver(&viu_of_platform_driver);
+}
+
+module_init(viu_init);
+module_exit(viu_exit);
+
+MODULE_DESCRIPTION("Freescale Video-In(VIU)");
+MODULE_AUTHOR("Hongjun Chen");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index 5d920e5..23db0c2 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -246,6 +246,15 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called gspca_spca561.
 
+config USB_GSPCA_SPCA1528
+	tristate "SPCA1528 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the SPCA1528 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_spca1528.
+
 config USB_GSPCA_SQ905
 	tristate "SQ Technologies SQ905 based USB Camera Driver"
 	depends on VIDEO_V4L2 && USB_GSPCA
@@ -264,6 +273,15 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called gspca_sq905c.
 
+config USB_GSPCA_SQ930X
+	tristate "SQ Technologies SQ930X based USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the SQ930X chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_sq930x.
+
 config USB_GSPCA_STK014
 	tristate "Syntek DV4000 (STK014) USB Camera Driver"
 	depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index 6e4cf1c..f6616db 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -23,8 +23,10 @@
 obj-$(CONFIG_USB_GSPCA_SPCA506)  += gspca_spca506.o
 obj-$(CONFIG_USB_GSPCA_SPCA508)  += gspca_spca508.o
 obj-$(CONFIG_USB_GSPCA_SPCA561)  += gspca_spca561.o
+obj-$(CONFIG_USB_GSPCA_SPCA1528) += gspca_spca1528.o
 obj-$(CONFIG_USB_GSPCA_SQ905)    += gspca_sq905.o
 obj-$(CONFIG_USB_GSPCA_SQ905C)   += gspca_sq905c.o
+obj-$(CONFIG_USB_GSPCA_SQ930X)   += gspca_sq930x.o
 obj-$(CONFIG_USB_GSPCA_SUNPLUS)  += gspca_sunplus.o
 obj-$(CONFIG_USB_GSPCA_STK014)   += gspca_stk014.o
 obj-$(CONFIG_USB_GSPCA_STV0680)  += gspca_stv0680.o
@@ -58,8 +60,10 @@
 gspca_spca506-objs  := spca506.o
 gspca_spca508-objs  := spca508.o
 gspca_spca561-objs  := spca561.o
+gspca_spca1528-objs := spca1528.o
 gspca_sq905-objs    := sq905.o
 gspca_sq905c-objs   := sq905c.o
+gspca_sq930x-objs   := sq930x.o
 gspca_stk014-objs   := stk014.o
 gspca_stv0680-objs  := stv0680.o
 gspca_sunplus-objs  := sunplus.o
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
index 19fe6b2..d6a7577 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/video/gspca/conex.c
@@ -41,7 +41,7 @@
 #define QUALITY_MAX 60
 #define QUALITY_DEF 40
 
-	u8 *jpeg_hdr;
+	u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* V4L2 controls supported by the driver */
@@ -845,9 +845,6 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	/* create the JPEG header */
-	sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-	if (!sd->jpeg_hdr)
-		return -ENOMEM;
 	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
 			0x22);		/* JPEG 411 */
 	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -862,11 +859,8 @@
 /* called on streamoff with alt 0 and on disconnect */
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
 	int retry = 50;
 
-	kfree(sd->jpeg_hdr);
-
 	if (!gspca_dev->present)
 		return;
 	reg_w_val(gspca_dev, 0x0000, 0x00);
diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c
index 58b696f..3747a1d 100644
--- a/drivers/media/video/gspca/cpia1.c
+++ b/drivers/media/video/gspca/cpia1.c
@@ -1760,22 +1760,19 @@
 	    data[25] == sd->params.roi.colEnd &&
 	    data[26] == sd->params.roi.rowStart &&
 	    data[27] == sd->params.roi.rowEnd) {
-		struct gspca_frame *frame = gspca_get_i_frame(gspca_dev);
+		u8 *image;
 
 		atomic_set(&sd->cam_exposure, data[39] * 2);
 		atomic_set(&sd->fps, data[41]);
 
-		if (frame == NULL) {
-			gspca_dev->last_packet_type = DISCARD_PACKET;
-			return;
-		}
-
 		/* Check for proper EOF for last frame */
-		if ((frame->data_end - frame->data) > 4 &&
-		    frame->data_end[-4] == 0xff &&
-		    frame->data_end[-3] == 0xff &&
-		    frame->data_end[-2] == 0xff &&
-		    frame->data_end[-1] == 0xff)
+		image = gspca_dev->image;
+		if (image != NULL &&
+		    gspca_dev->image_len > 4 &&
+		    image[gspca_dev->image_len - 4] == 0xff &&
+		    image[gspca_dev->image_len - 3] == 0xff &&
+		    image[gspca_dev->image_len - 2] == 0xff &&
+		    image[gspca_dev->image_len - 1] == 0xff)
 			gspca_frame_add(gspca_dev, LAST_PACKET,
 						NULL, 0);
 
diff --git a/drivers/media/video/gspca/gl860/gl860-mi2020.c b/drivers/media/video/gspca/gl860/gl860-mi2020.c
index 7c31b4f..57782e0 100644
--- a/drivers/media/video/gspca/gl860/gl860-mi2020.c
+++ b/drivers/media/video/gspca/gl860/gl860-mi2020.c
@@ -1,6 +1,7 @@
 /* Subdriver for the GL860 chip with the MI2020 sensor
- * Author Olivier LORIN, from Ice/Soro2005's logs(A), Fret_saw/Hulkie's
- * logs(B) and Tricid"s logs(C). With the help of Kytrix/BUGabundo/Blazercist.
+ * Author Olivier LORIN, from logs by Iceman/Soro2005 + Fret_saw/Hulkie/Tricid
+ * with the help of Kytrix/BUGabundo/Blazercist.
+ * Driver achieved thanks to a webcam gift by Kytrix.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,47 +21,70 @@
 
 #include "gl860.h"
 
+static u8 dat_wbal1[] = {0x8c, 0xa2, 0x0c};
+
 static u8 dat_bright1[] = {0x8c, 0xa2, 0x06};
 static u8 dat_bright3[] = {0x8c, 0xa1, 0x02};
 static u8 dat_bright4[] = {0x90, 0x00, 0x0f};
 static u8 dat_bright5[] = {0x8c, 0xa1, 0x03};
 static u8 dat_bright6[] = {0x90, 0x00, 0x05};
 
-static u8 dat_dummy1[] = {0x90, 0x00, 0x06};
-/*static u8 dummy2[] = {0x8c, 0xa1, 0x02};*/
-/*static u8 dummy3[] = {0x90, 0x00, 0x1f};*/
-
 static u8 dat_hvflip1[] = {0x8c, 0x27, 0x19};
 static u8 dat_hvflip3[] = {0x8c, 0x27, 0x3b};
 static u8 dat_hvflip5[] = {0x8c, 0xa1, 0x03};
 static u8 dat_hvflip6[] = {0x90, 0x00, 0x06};
 
+static struct idxdata tbl_middle_hvflip_low[] = {
+	{0x33, "\x90\x00\x06"},
+	{6, "\xff\xff\xff"},
+	{0x33, "\x90\x00\x06"},
+	{6, "\xff\xff\xff"},
+	{0x33, "\x90\x00\x06"},
+	{6, "\xff\xff\xff"},
+	{0x33, "\x90\x00\x06"},
+	{6, "\xff\xff\xff"},
+};
+
+static struct idxdata tbl_middle_hvflip_big[] = {
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa1\x20"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
+	{102, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x20"},
+	{0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+};
+
+static struct idxdata tbl_end_hvflip[] = {
+	{0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+	{6, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+	{6, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+	{6, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+};
+
 static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 };
 
 static u8 dat_multi5[] = { 0x8c, 0xa1, 0x03 };
 static u8 dat_multi6[] = { 0x90, 0x00, 0x05 };
 
-static struct validx tbl_common1[] = {
-	{0x0000, 0x0000},
-	{1, 0xffff}, /* msleep(35); */
-	{0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d}, {0x0000, 0x00c0},
-	{0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0004, 0x00d8},
-	{0x0000, 0x0058}, {0x0002, 0x0004}, {0x0041, 0x0000},
+static struct validx tbl_init_at_startup[] = {
+	{0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001,0x00c1},
+	{0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d},
+	{53, 0xffff},
+	{0x0040, 0x0000}, {0x0063, 0x0006},
 };
 
-static struct validx tbl_common2[] = {
-	{0x006a, 0x0007},
-	{35, 0xffff},
-	{0x00ef, 0x0006},
-	{35, 0xffff},
-	{0x006a, 0x000d},
-	{35, 0xffff},
-	{0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2},
+static struct validx tbl_common_0B[] = {
+	{0x0002, 0x0004}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a,0x000d},
+	{0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042,0x00c2},
 	{0x0004, 0x00d8}, {0x0000, 0x0058}, {0x0041, 0x0000},
 };
 
-static struct idxdata tbl_common3[] = {
-	{0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"},
+static struct idxdata tbl_common_3B[] = {
+	{0x33, "\x86\x25\x01"}, {0x33, "\x86\x25\x00"},
+	{2, "\xff\xff\xff"},
+	{0x30, "\x1a\x0a\xcc"}, {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"},
 	{6, "\xff\xff\xff"}, /* 12 */
 	{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
 	{2, "\xff\xff\xff"}, /* - */
@@ -98,85 +122,58 @@
 	{0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
 	{0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
 	{0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
-	{1, "\xff\xff\xff"},
 	{0x33, "\x78\x00\x00"},
-	{1, "\xff\xff\xff"},
+	{2, "\xff\xff\xff"},
 	{0x35, "\xb8\x1f\x20"}, {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x10"},
 	{0x33, "\x8c\xa2\x07"}, {0x33, "\x90\x00\x08"}, {0x33, "\x8c\xa2\x42"},
 	{0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x4a"}, {0x33, "\x90\x00\x8c"},
 	{0x35, "\xba\xfa\x08"}, {0x33, "\x8c\xa2\x02"}, {0x33, "\x90\x00\x22"},
-	{0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"},
-};
-
-static struct idxdata tbl_common4[] = {
-	{0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa0"}, {0x33, "\x8c\xa4\x08"},
+	{0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"}, {0x33, "\x8c\xa4\x04"},
+	{0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"}, {0x33, "\x90\x00\x00"},
+	{0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0c"},
+	{0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"}, {0x33, "\x90\x00\x04"},
+	{0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"}, {0x33, "\x8c\xa1\x03"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
+	{0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x25"},
+	{0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"},
+	{0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x47"},
+	{0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x02\x84"},
+	{0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"}, {0x33, "\x8c\x27\x07"},
+	{0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"}, {0x33, "\x90\x04\xb0"},
+	{0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x0f"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"}, {0x33, "\x90\x04\xbd"},
+	{0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"}, {0x33, "\x8c\x27\x15"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
+	{0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, {0x33, "\x8c\x27\x1b"},
+	{0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"}, {0x33, "\x90\x01\x02"},
+	{0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"}, {0x33, "\x8c\x27\x21"},
+	{0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"}, {0x33, "\x90\x02\x85"},
+	{0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x27"},
+	{0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"}, {0x33, "\x90\x20\x20"},
+	{0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"}, {0x33, "\x8c\x27\x2d"},
+	{0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"}, {0x33, "\x90\x00\x04"},
+	{0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x33"},
+	{0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"}, {0x33, "\x90\x06\x4b"},
+	{0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x39"},
+	{0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"},
+	{0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x41"},
+	{0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"}, {0x33, "\x90\x04\xed"},
+	{0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x51"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"}, {0x33, "\x90\x03\x20"},
+	{0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x57"},
+	{0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"}, {0x33, "\x90\x00\x00"},
+	{0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x63"},
+	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"}, {0x33, "\x90\x04\xb0"},
+	{0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\xa4\x08"},
 	{0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"},
 	{0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"},
-	{0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa0"},
-	{0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc0"}, {0x33, "\x8c\x24\x15"},
-	{0x33, "\x90\x00\xa0"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\xc0"},
-};
-
-static struct idxdata tbl_common5[] = {
-	{0x33, "\x8c\xa4\x04"}, {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"},
-	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"},
-	{0x33, "\x8c\xa2\x0c"}, {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"},
-	{0x33, "\x90\x00\x04"}, {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"},
-	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"},
-	/* msleep(53); */
-	{0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"},
-	{0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"},
-	{0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"},
-	{0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"},
-	{0x33, "\x90\x02\x84"}, {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"},
-	{0x33, "\x8c\x27\x07"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"},
-	{0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"},
-	{0x33, "\x8c\x27\x0f"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"},
-	{0x33, "\x90\x04\xbd"}, {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"},
-	{0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"},
-	{0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"},
-	{0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"},
-	{0x33, "\x90\x01\x02"}, {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"},
-	{0x33, "\x8c\x27\x21"}, {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"},
-	{0x33, "\x90\x02\x85"}, {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"},
-	{0x33, "\x8c\x27\x27"}, {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"},
-	{0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"},
-	{0x33, "\x8c\x27\x2d"}, {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"},
-	{0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"},
-	{0x33, "\x8c\x27\x33"}, {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"},
-	{0x33, "\x90\x06\x4b"}, {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"},
-	{0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"},
-	{0x33, "\x90\x00\x24"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"},
-	{0x33, "\x8c\x27\x41"}, {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"},
-	{0x33, "\x90\x04\xed"}, {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"},
-	{0x33, "\x8c\x27\x51"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"},
-	{0x33, "\x90\x03\x20"}, {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"},
-	{0x33, "\x8c\x27\x57"}, {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"},
-	{0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"},
-	{0x33, "\x8c\x27\x63"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"},
-	{0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"},
-	{0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"},
-	{0x33, "\x90\x00\x21"}, {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"},
-	{0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"},
-	{0x33, "\x90\x00\xa1"}, {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"},
-	{0x33, "\x8c\x24\x15"},
-};
-
-static struct validx tbl_init_at_startup[] = {
-	{0x0000, 0x0000},
-	{53, 0xffff},
-	{0x0010, 0x0010},
-	{53, 0xffff},
-	{0x0008, 0x00c0},
-	{53, 0xffff},
-	{0x0001, 0x00c1},
-	{53, 0xffff},
-	{0x0001, 0x00c2},
-	{53, 0xffff},
-	{0x0020, 0x0006},
-	{53, 0xffff},
-	{0x006a, 0x000d},
-	{53, 0xffff},
+	{0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa1"},
+	{0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"}, {0x33, "\x8c\x24\x15"},
+	{0x33, "\x90\x00\x6a"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\x80"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
+	{2, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
+	{3, "\xff\xff\xff"},
 };
 
 static struct idxdata tbl_init_post_alt_low1[] = {
@@ -209,7 +206,7 @@
 	{2, "\xff\xff\xff"},
 	{0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
 	{0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
-	{2, "\xff\xff\xff"}, /* - * */
+	{2, "\xff\xff\xff"},
 	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
 	{2, "\xff\xff\xff"},
 	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
@@ -217,61 +214,15 @@
 	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
 	{2, "\xff\xff\xff"},
 	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
-	{1, "\xff\xff\xff"},
 };
 
-static struct idxdata tbl_init_post_alt_low4[] = {
-	{0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
-	{0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
-	{0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
-	{0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"},
-	{0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"},
-	{0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"},
-	{0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"},
-	{0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"},
-	{0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"},
-	{0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"},
-	{0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"},
-	{0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"},
-	{0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"},
-	{0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"},
-	{0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"},
-	{0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"},
-	{0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"},
-	{0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"},
-	{0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"},
-	{0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"},
-	{0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"},
-	{0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"},
-	{0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"},
-	{0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
-	{0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
-	{0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"},
-	/* Flip/Mirror h/v=1 */
-	{0x33, "\x90\x00\x3c"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"},
-	{0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"}, {0x33, "\x8c\xa1\x03"},
-	{0x33, "\x90\x00\x06"},
-	{130, "\xff\xff\xff"},
-	{0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"},
-	{0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"},
-	{100, "\xff\xff\xff"},
-	/* ?? */
-	{0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"},
-	{0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
-	{0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
-	/* Brigthness=70 */
-	{0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x46"}, {0x33, "\x8c\xa1\x02"},
-	{0x33, "\x90\x00\x0f"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
-	/* Sharpness=20 */
-	{0x32, "\x6c\x14\x08"},
-};
-
-static struct idxdata tbl_init_post_alt_big1[] = {
+static struct idxdata tbl_init_post_alt_big[] = {
 	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
 	{2, "\xff\xff\xff"},
 	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
 	{2, "\xff\xff\xff"},
 	{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
+	{2, "\xff\xff\xff"},
 	{0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x03"},
 	{0x33, "\x90\x00\x05"},
 	{2, "\xff\xff\xff"},
@@ -285,9 +236,17 @@
 	{0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x34"}, {0x33, "\x90\x00\x03"},
 	{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x2e\x01\x00"},
 	{0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+	{0x33, "\x8c\x27\x97"}, {0x33, "\x90\x01\x00"},
+	{51, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
+	{0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
+	{51, "\xff\xff\xff"},
+	{0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"},
+	{0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+	{51, "\xff\xff\xff"},
 };
 
-static struct idxdata tbl_init_post_alt_big2[] = {
+static struct idxdata tbl_init_post_alt_3B[] = {
 	{0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
 	{0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
 	{0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
@@ -316,17 +275,6 @@
 	{0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
 };
 
-static struct idxdata tbl_init_post_alt_big3[] = {
-	{0x33, "\x8c\xa1\x02"},
-	{0x33, "\x90\x00\x1f"},
-	{0x33, "\x8c\xa1\x02"},
-	{0x33, "\x90\x00\x1f"},
-	{0x33, "\x8c\xa1\x02"},
-	{0x33, "\x90\x00\x1f"},
-	{0x33, "\x8c\xa1\x02"},
-	{0x33, "\x90\x00\x1f"},
-};
-
 static u8 *dat_640  = "\xd0\x02\xd1\x08\xd2\xe1\xd3\x02\xd4\x10\xd5\x81";
 static u8 *dat_800  = "\xd0\x02\xd1\x10\xd2\x57\xd3\x02\xd4\x18\xd5\x21";
 static u8 *dat_1280 = "\xd0\x02\xd1\x20\xd2\x01\xd3\x02\xd4\x28\xd5\x01";
@@ -351,7 +299,7 @@
 	sd->vcur.gamma      =  0;
 	sd->vcur.hue        =  0;
 	sd->vcur.saturation = 60;
-	sd->vcur.whitebal   = 50;
+	sd->vcur.whitebal   =  0; /* 50, not done by hardware */
 	sd->vcur.mirror = 0;
 	sd->vcur.flip   = 0;
 	sd->vcur.AC50Hz = 1;
@@ -361,17 +309,12 @@
 	sd->vmax.sharpness  =  40;
 	sd->vmax.contrast   =   3;
 	sd->vmax.gamma      =   2;
-	sd->vmax.hue        =   0 + 1; /* 200 */
-	sd->vmax.saturation =   0;     /* 100 */
-	sd->vmax.whitebal   =   0;     /* 100 */
+	sd->vmax.hue        =   0 + 1; /* 200, not done by hardware */
+	sd->vmax.saturation =   0;     /* 100, not done by hardware */
+	sd->vmax.whitebal   =   2;     /* 100, not done by hardware */
 	sd->vmax.mirror = 1;
 	sd->vmax.flip   = 1;
 	sd->vmax.AC50Hz = 1;
-	if (_MI2020b_) {
-		sd->vmax.contrast  = 0;
-		sd->vmax.gamma     = 0;
-		sd->vmax.backlight = 0;
-	}
 
 	sd->dev_camera_settings = mi2020_camera_settings;
 	sd->dev_init_at_startup = mi2020_init_at_startup;
@@ -384,51 +327,9 @@
 
 static void common(struct gspca_dev *gspca_dev)
 {
-	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
-
-	if (_MI2020b_) {
-		fetch_validx(gspca_dev, tbl_common1, ARRAY_SIZE(tbl_common1));
-	} else {
-		if (_MI2020_)
-			ctrl_out(gspca_dev, 0x40,  1, 0x0008, 0x0004,  0, NULL);
-		else
-			ctrl_out(gspca_dev, 0x40,  1, 0x0002, 0x0004,  0, NULL);
-		msleep(35);
-		fetch_validx(gspca_dev, tbl_common2, ARRAY_SIZE(tbl_common2));
-	}
-	ctrl_out(gspca_dev, 0x40,  3, 0x7a00, 0x0033,  3, "\x86\x25\x01");
-	ctrl_out(gspca_dev, 0x40,  3, 0x7a00, 0x0033,  3, "\x86\x25\x00");
-	msleep(2); /* - * */
-	ctrl_out(gspca_dev, 0x40,  3, 0x7a00, 0x0030,  3, "\x1a\x0a\xcc");
-	if (reso == IMAGE_1600)
-		msleep(2); /* 1600 */
-	fetch_idxdata(gspca_dev, tbl_common3, ARRAY_SIZE(tbl_common3));
-
-	if (_MI2020b_ || _MI2020_)
-		fetch_idxdata(gspca_dev, tbl_common4,
-				ARRAY_SIZE(tbl_common4));
-
-	fetch_idxdata(gspca_dev, tbl_common5, ARRAY_SIZE(tbl_common5));
-	if (_MI2020b_ || _MI2020_) {
-		/* Different from fret */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x78");
-		/* Same as fret */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17");
-		/* Different from fret */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x90");
-	} else {
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x6a");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x80");
-	}
-	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
-	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x05");
-	msleep(2);
-	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
-	if (reso == IMAGE_1600)
-		msleep(14); /* 1600 */
-	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x06");
-	msleep(2);
+	fetch_validx(gspca_dev, tbl_common_0B, ARRAY_SIZE(tbl_common_0B));
+	fetch_idxdata(gspca_dev, tbl_common_3B, ARRAY_SIZE(tbl_common_3B));
+	ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
 }
 
 static int mi2020_init_at_startup(struct gspca_dev *gspca_dev)
@@ -441,8 +342,16 @@
 	fetch_validx(gspca_dev, tbl_init_at_startup,
 			ARRAY_SIZE(tbl_init_at_startup));
 
+	ctrl_out(gspca_dev, 0x40,  1, 0x7a00, 0x8030,  0, NULL);
+	ctrl_in(gspca_dev, 0xc0,  2, 0x7a00, 0x8030,  1, &c);
+
 	common(gspca_dev);
 
+	msleep(61);
+/*	ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000,  0, NULL); */
+/*	msleep(36); */
+	ctrl_out(gspca_dev, 0x40,  1, 0x0001, 0x0000,  0, NULL);
+
 	return 0;
 }
 
@@ -450,17 +359,17 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	sd->mirrorMask = 0;
+	sd->mirrorMask =  0;
+	sd->vold.hue   = -1;
 
-	sd->vold.backlight  = -1;
+	/* These controls need to be reset */
 	sd->vold.brightness = -1;
 	sd->vold.sharpness  = -1;
-	sd->vold.contrast   = -1;
-	sd->vold.gamma  = -1;
-	sd->vold.hue    = -1;
-	sd->vold.mirror = -1;
-	sd->vold.flip   = -1;
-	sd->vold.AC50Hz = -1;
+
+	/* If not different from default, they do not need to be set */
+	sd->vold.contrast  = 0;
+	sd->vold.gamma     = 0;
+	sd->vold.backlight = 0;
 
 	mi2020_init_post_alt(gspca_dev);
 
@@ -472,10 +381,10 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
 
-	s32 backlight = sd->vcur.backlight;
 	s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
 	s32 flip   = (((sd->vcur.flip   > 0) ^ sd->mirrorMask) > 0);
 	s32 freq   = (sd->vcur.AC50Hz  > 0);
+	s32 wbal   = sd->vcur.whitebal;
 
 	u8 dat_freq2[] = {0x90, 0x00, 0x80};
 	u8 dat_multi1[] = {0x8c, 0xa7, 0x00};
@@ -484,6 +393,7 @@
 	u8 dat_multi4[] = {0x90, 0x00, 0x00};
 	u8 dat_hvflip2[] = {0x90, 0x04, 0x6c};
 	u8 dat_hvflip4[] = {0x90, 0x00, 0x24};
+	u8 dat_wbal2[] = {0x90, 0x00, 0x00};
 	u8 c;
 
 	sd->nbIm = -1;
@@ -491,23 +401,26 @@
 	dat_freq2[2] = freq ? 0xc0 : 0x80;
 	dat_multi1[2] = 0x9d;
 	dat_multi3[2] = dat_multi1[2] + 1;
-	dat_multi4[2] = dat_multi2[2] = backlight;
+	if (wbal == 0) {
+		dat_multi4[2] = dat_multi2[2] = 0;
+		dat_wbal2[2] = 0x17;
+	} else if (wbal == 1) {
+		dat_multi4[2] = dat_multi2[2] = 0;
+		dat_wbal2[2] = 0x35;
+	} else if (wbal == 2) {
+		dat_multi4[2] = dat_multi2[2] = 0x20;
+		dat_wbal2[2] = 0x17;
+	}
 	dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror);
 	dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror);
 
 	msleep(200);
-
 	ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
-	msleep(3); /* 35 * */
+	msleep(2);
 
 	common(gspca_dev);
 
-	ctrl_out(gspca_dev, 0x40,  1, 0x0041, 0x0000,  0, NULL);
-	msleep(70);
-
-	if (_MI2020b_)
-		ctrl_out(gspca_dev, 0x40,  1, 0x0040, 0x0000,  0, NULL);
-
+	msleep(142);
 	ctrl_out(gspca_dev, 0x40,  1, 0x0010, 0x0010,  0, NULL);
 	ctrl_out(gspca_dev, 0x40,  1, 0x0003, 0x00c1,  0, NULL);
 	ctrl_out(gspca_dev, 0x40,  1, 0x0042, 0x00c2,  0, NULL);
@@ -523,8 +436,7 @@
 			ctrl_out(gspca_dev, 0x40,  3, 0x0000, 0x0200,
 				12, dat_800);
 
-		if (_MI2020c_)
-			fetch_idxdata(gspca_dev, tbl_init_post_alt_low1,
+		fetch_idxdata(gspca_dev, tbl_init_post_alt_low1,
 					ARRAY_SIZE(tbl_init_post_alt_low1));
 
 		if (reso == IMAGE_800)
@@ -534,87 +446,10 @@
 		fetch_idxdata(gspca_dev, tbl_init_post_alt_low3,
 				ARRAY_SIZE(tbl_init_post_alt_low3));
 
-		if (_MI2020b_) {
-			ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
-			ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
-			ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
-			msleep(150);
-		} else if (_MI2020c_) {
-			ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
-			ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
-			ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
-			msleep(120);
-			ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
-			msleep(30);
-		} else if (_MI2020_) {
-			ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
-			ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
-			ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
-			msleep(120);
-			ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
-			msleep(30);
-		}
-
-		/* AC power frequency */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
-		msleep(20);
-		/* backlight */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
-		/* at init time but not after */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17");
-		/* finish the backlight */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
-		msleep(5);/* " */
-
-		if (_MI2020c_) {
-			fetch_idxdata(gspca_dev, tbl_init_post_alt_low4,
-					ARRAY_SIZE(tbl_init_post_alt_low4));
-		} else {
-			ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
-			msleep(14); /* 0xd8 */
-
-			/* flip/mirror */
-			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-					3, dat_hvflip1);
-			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-					3, dat_hvflip2);
-			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-					3, dat_hvflip3);
-			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-					3, dat_hvflip4);
-			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-					3, dat_hvflip5);
-			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-					3, dat_hvflip6);
-			msleep(21);
-			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-					3, dat_dummy1);
-			msleep(5);
-			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-					3, dat_dummy1);
-			msleep(5);
-			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-					3, dat_dummy1);
-			msleep(5);
-			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-					3, dat_dummy1);
-			msleep(5);
-			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-					3, dat_dummy1);
-			msleep(5);
-			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
-					3, dat_dummy1);
-			/* end of flip/mirror main part */
-			msleep(246); /* 146 */
-
-			sd->nbIm = 0;
-		}
+		ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
+		msleep(120);
 		break;
 
 	case IMAGE_1280:
@@ -643,108 +478,62 @@
 					3, "\x90\x04\xb0");
 		}
 
-		fetch_idxdata(gspca_dev, tbl_init_post_alt_big1,
-				ARRAY_SIZE(tbl_init_post_alt_big1));
+		fetch_idxdata(gspca_dev, tbl_init_post_alt_big,
+				ARRAY_SIZE(tbl_init_post_alt_big));
 
-		if (reso == IMAGE_1600)
-			msleep(13); /* 1600 */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x27\x97");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x01\x00");
-		msleep(53);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
-		if (reso == IMAGE_1600)
-			msleep(13); /* 1600 */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
-		msleep(53);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02");
-		if (reso == IMAGE_1600)
-			msleep(13); /* 1600 */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
-		msleep(53);
-
-		if (_MI2020b_) {
-			ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
-			if (reso == IMAGE_1600)
-				msleep(500); /* 1600 */
-			ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
-			ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
-			msleep(1850);
-		} else if (_MI2020c_ || _MI2020_) {
-			ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
-			ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
-			ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
-			msleep(1850);
-			ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
-			msleep(30);
-		}
-
-		/* AC power frequency */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
-		msleep(20);
-		/* backlight */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
-		/* at init time but not after */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17");
-		/* finish the backlight */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
-		msleep(6); /* " */
-
-		ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
-		msleep(14);
-
-		if (_MI2020c_)
-			fetch_idxdata(gspca_dev, tbl_init_post_alt_big2,
-					ARRAY_SIZE(tbl_init_post_alt_big2));
-
-		/* flip/mirror */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
-		/* end of flip/mirror main part */
-		msleep(16);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
-		if (reso == IMAGE_1600)
-			msleep(25); /* 1600 */
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
-		msleep(103);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
-		sd->nbIm = 0;
-
-		if (_MI2020c_)
-			fetch_idxdata(gspca_dev, tbl_init_post_alt_big3,
-					ARRAY_SIZE(tbl_init_post_alt_big3));
+		ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
+		ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
+		msleep(1850);
 	}
 
+	ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
+	msleep(40);
+
+	/* AC power frequency */
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
+	msleep(33);
+	/* light source */
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+	msleep(7);
+	ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
+
+	fetch_idxdata(gspca_dev, tbl_init_post_alt_3B,
+			ARRAY_SIZE(tbl_init_post_alt_3B));
+
+	/* hvflip */
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
+	ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
+	msleep(250);
+
+	if (reso == IMAGE_640 || reso == IMAGE_800)
+		fetch_idxdata(gspca_dev, tbl_middle_hvflip_low,
+				ARRAY_SIZE(tbl_middle_hvflip_low));
+	else
+		fetch_idxdata(gspca_dev, tbl_middle_hvflip_big,
+				ARRAY_SIZE(tbl_middle_hvflip_big));
+
+	fetch_idxdata(gspca_dev, tbl_end_hvflip,
+			ARRAY_SIZE(tbl_end_hvflip));
+
+	sd->nbIm = 0;
+
 	sd->vold.mirror    = mirror;
 	sd->vold.flip      = flip;
 	sd->vold.AC50Hz    = freq;
-	sd->vold.backlight = backlight;
+	sd->vold.whitebal  = wbal;
 
 	mi2020_camera_settings(gspca_dev);
 
@@ -772,6 +561,7 @@
 static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
 
 	s32 backlight = sd->vcur.backlight;
 	s32 bright =  sd->vcur.brightness;
@@ -782,6 +572,7 @@
 	s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
 	s32 flip   = (((sd->vcur.flip   > 0) ^ sd->mirrorMask) > 0);
 	s32 freq   = (sd->vcur.AC50Hz > 0);
+	s32 wbal   = sd->vcur.whitebal;
 
 	u8 dat_sharp[] = {0x6c, 0x00, 0x08};
 	u8 dat_bright2[] = {0x90, 0x00, 0x00};
@@ -792,6 +583,7 @@
 	u8 dat_multi4[] = {0x90, 0x00, 0x00};
 	u8 dat_hvflip2[] = {0x90, 0x04, 0x6c};
 	u8 dat_hvflip4[] = {0x90, 0x00, 0x24};
+	u8 dat_wbal2[] = {0x90, 0x00, 0x00};
 
 	/* Less than 4 images received -> too early to set the settings */
 	if (sd->nbIm < 4) {
@@ -809,41 +601,95 @@
 		msleep(20);
 	}
 
+	if (wbal != sd->vold.whitebal) {
+		sd->vold.whitebal = wbal;
+		if (wbal < 0 || wbal > sd->vmax.whitebal)
+			wbal = 0;
+
+		dat_multi1[2] = 0x9d;
+		dat_multi3[2] = dat_multi1[2] + 1;
+		if (wbal == 0) {
+			dat_multi4[2] = dat_multi2[2] = 0;
+			dat_wbal2[2] = 0x17;
+		} else if (wbal == 1) {
+			dat_multi4[2] = dat_multi2[2] = 0;
+			dat_wbal2[2] = 0x35;
+		} else if (wbal == 2) {
+			dat_multi4[2] = dat_multi2[2] = 0x20;
+			dat_wbal2[2] = 0x17;
+		}
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+	}
+
 	if (mirror != sd->vold.mirror || flip != sd->vold.flip) {
 		sd->vold.mirror = mirror;
 		sd->vold.flip   = flip;
 
 		dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror);
 		dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror);
+
+		fetch_idxdata(gspca_dev, tbl_init_post_alt_3B,
+				ARRAY_SIZE(tbl_init_post_alt_3B));
+
 		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
 		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
 		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
 		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
 		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
 		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
-		msleep(130);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
-		msleep(6);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
-		msleep(6);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
-		msleep(6);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
-		msleep(6);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
-		msleep(6);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
-		msleep(6);
+		msleep(40);
 
-		/* Sometimes present, sometimes not, useful? */
-		/* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
-		 * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
-		 * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
-		 * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
-		 * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
-		 * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
-		 * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
-		 * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);*/
+		if (reso == IMAGE_640 || reso == IMAGE_800)
+			fetch_idxdata(gspca_dev, tbl_middle_hvflip_low,
+					ARRAY_SIZE(tbl_middle_hvflip_low));
+		else
+			fetch_idxdata(gspca_dev, tbl_middle_hvflip_big,
+					ARRAY_SIZE(tbl_middle_hvflip_big));
+
+		fetch_idxdata(gspca_dev, tbl_end_hvflip,
+				ARRAY_SIZE(tbl_end_hvflip));
+	}
+
+	if (bright != sd->vold.brightness) {
+		sd->vold.brightness = bright;
+		if (bright < 0 || bright > sd->vmax.brightness)
+			bright = 0;
+
+		dat_bright2[2] = bright;
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6);
+	}
+
+	if (cntr != sd->vold.contrast || gam != sd->vold.gamma) {
+		sd->vold.contrast = cntr;
+		if (cntr < 0 || cntr > sd->vmax.contrast)
+			cntr = 0;
+		sd->vold.gamma = gam;
+		if (gam < 0 || gam > sd->vmax.gamma)
+			gam = 0;
+
+		dat_multi1[2] = 0x6d;
+		dat_multi3[2] = dat_multi1[2] + 1;
+		if (cntr == 0)
+			cntr = 4;
+		dat_multi4[2] = dat_multi2[2] = cntr * 0x10 + 2 - gam;
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
+		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
 	}
 
 	if (backlight != sd->vold.backlight) {
@@ -862,52 +708,6 @@
 		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
 	}
 
-	if (gam != sd->vold.gamma) {
-		sd->vold.gamma = gam;
-		if (gam < 0 || gam > sd->vmax.gamma)
-			gam = 0;
-
-		dat_multi1[2] = 0x6d;
-		dat_multi3[2] = dat_multi1[2] + 1;
-		dat_multi4[2] = dat_multi2[2] = 0x40 + gam;
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
-	}
-
-	if (cntr != sd->vold.contrast) {
-		sd->vold.contrast = cntr;
-		if (cntr < 0 || cntr > sd->vmax.contrast)
-			cntr = 0;
-
-		dat_multi1[2] = 0x6d;
-		dat_multi3[2] = dat_multi1[2] + 1;
-		dat_multi4[2] = dat_multi2[2] = 0x12 + 16 * cntr;
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
-	}
-
-	if (bright != sd->vold.brightness) {
-		sd->vold.brightness = bright;
-		if (bright < 0 || bright > sd->vmax.brightness)
-			bright = 0;
-
-		dat_bright2[2] = bright;
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5);
-		ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6);
-	}
-
 	if (sharp != sd->vold.sharpness) {
 		sd->vold.sharpness = sharp;
 		if (sharp < 0 || sharp > sd->vmax.sharpness)
@@ -928,9 +728,6 @@
 static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev)
 {
 	ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
-	msleep(20);
-	if (_MI2020c_ || _MI2020_)
-		ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL);
-	else
-		ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
+	msleep(40);
+	ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL);
 }
diff --git a/drivers/media/video/gspca/gl860/gl860-ov9655.c b/drivers/media/video/gspca/gl860/gl860-ov9655.c
index d412694..5ae9619 100644
--- a/drivers/media/video/gspca/gl860/gl860-ov9655.c
+++ b/drivers/media/video/gspca/gl860/gl860-ov9655.c
@@ -69,7 +69,7 @@
 	"\xd0\x01\xd1\x08\xd2\xe0\xd3\x01" "\xd4\x10\xd5\x80"
 };
 
-static u8 *tbl_800[] = {
+static u8 *tbl_1280[] = {
 	"\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01"
 	,
 	"\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x01\x0b\x57\x0e\x61"
@@ -217,7 +217,7 @@
 
 	ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
 
-	tbl = (reso == IMAGE_640) ? tbl_640 : tbl_800;
+	tbl = (reso == IMAGE_640) ? tbl_640 : tbl_1280;
 
 	ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
 			tbl_length[0], tbl[0]);
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c
index 9e42476..e86eb8b 100644
--- a/drivers/media/video/gspca/gl860/gl860.c
+++ b/drivers/media/video/gspca/gl860/gl860.c
@@ -63,7 +63,7 @@
 \
 	sd->vcur.thename = val;\
 	if (gspca_dev->streaming)\
-		sd->dev_camera_settings(gspca_dev);\
+		sd->waitSet = 1;\
 	return 0;\
 } \
 static int sd_get_##thename(struct gspca_dev *gspca_dev, s32 *val)\
@@ -91,7 +91,6 @@
 /* control table */
 static struct ctrl sd_ctrls_mi1320[GL860_NCTRLS];
 static struct ctrl sd_ctrls_mi2020[GL860_NCTRLS];
-static struct ctrl sd_ctrls_mi2020b[GL860_NCTRLS];
 static struct ctrl sd_ctrls_ov2640[GL860_NCTRLS];
 static struct ctrl sd_ctrls_ov9655[GL860_NCTRLS];
 
@@ -121,8 +120,6 @@
 		sd_ctrls = sd_ctrls_mi1320;
 	else if (_MI2020_)
 		sd_ctrls = sd_ctrls_mi2020;
-	else if (_MI2020b_)
-		sd_ctrls = sd_ctrls_mi2020b;
 	else if (_OV2640_)
 		sd_ctrls = sd_ctrls_ov2640;
 	else if (_OV9655_)
@@ -187,19 +184,6 @@
 	.dq_callback = sd_callback,
 };
 
-static const struct sd_desc sd_desc_mi2020b = {
-	.name        = MODULE_NAME,
-	.ctrls       = sd_ctrls_mi2020b,
-	.nctrls      = GL860_NCTRLS,
-	.config      = sd_config,
-	.init        = sd_init,
-	.isoc_init   = sd_isoc_init,
-	.start       = sd_start,
-	.stop0       = sd_stop0,
-	.pkt_scan    = sd_pkt_scan,
-	.dq_callback = sd_callback,
-};
-
 static const struct sd_desc sd_desc_ov2640 = {
 	.name        = MODULE_NAME,
 	.ctrls       = sd_ctrls_ov2640,
@@ -235,9 +219,9 @@
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 0
 	},
-	{ 800,  600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+	{ 800,  598, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
 		.bytesperline = 800,
-		.sizeimage = 800 * 600,
+		.sizeimage = 800 * 598,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 1
 	},
@@ -247,9 +231,9 @@
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 2
 	},
-	{1600, 1200, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+	{1600, 1198, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
 		.bytesperline = 1600,
-		.sizeimage = 1600 * 1200,
+		.sizeimage = 1600 * 1198,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 3
 	},
@@ -344,8 +328,6 @@
 		sd->sensor = ID_OV9655;
 	else if (strcmp(sensor, "MI2020") == 0)
 		sd->sensor = ID_MI2020;
-	else if (strcmp(sensor, "MI2020b") == 0)
-		sd->sensor = ID_MI2020b;
 
 	/* Get sensor and set the suitable init/start/../stop functions */
 	if (gl860_guess_sensor(gspca_dev, vendor_id, product_id) == -1)
@@ -369,13 +351,6 @@
 		dev_init_settings   = mi2020_init_settings;
 		break;
 
-	case ID_MI2020b:
-		gspca_dev->sd_desc = &sd_desc_mi2020b;
-		cam->cam_mode = mi2020_mode;
-		cam->nmodes = ARRAY_SIZE(mi2020_mode);
-		dev_init_settings   = mi2020_init_settings;
-		break;
-
 	case ID_OV2640:
 		gspca_dev->sd_desc = &sd_desc_ov2640;
 		cam->cam_mode = ov2640_mode;
@@ -620,10 +595,7 @@
 	else if (len > 1 && r < len)
 		PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len);
 
-	if ((_MI2020_ || _MI2020b_ || _MI2020c_) && (val || index))
-		msleep(1);
-	if (_OV2640_)
-		msleep(1);
+	msleep(1);
 
 	return r;
 }
@@ -767,8 +739,6 @@
 		PDEBUG(D_PROBE, "05e3:f191 sensor MI1320 (1.3M)");
 	} else if (_MI2020_) {
 		PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 (2.0M)");
-	} else if (_MI2020b_) {
-		PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 alt. driver (2.0M)");
 	} else if (_OV9655_) {
 		PDEBUG(D_PROBE, "05e3:0503 sensor OV9655 (1.3M)");
 	} else if (_OV2640_) {
diff --git a/drivers/media/video/gspca/gl860/gl860.h b/drivers/media/video/gspca/gl860/gl860.h
index 305061f..49ad4ac 100644
--- a/drivers/media/video/gspca/gl860/gl860.h
+++ b/drivers/media/video/gspca/gl860/gl860.h
@@ -32,19 +32,16 @@
 #define ID_OV2640   2
 #define ID_OV9655   4
 #define ID_MI2020   8
-#define ID_MI2020b 16
 
 #define _MI1320_  (((struct sd *) gspca_dev)->sensor == ID_MI1320)
 #define _MI2020_  (((struct sd *) gspca_dev)->sensor == ID_MI2020)
-#define _MI2020b_ (((struct sd *) gspca_dev)->sensor == ID_MI2020b)
-#define _MI2020c_ 0
 #define _OV2640_  (((struct sd *) gspca_dev)->sensor == ID_OV2640)
 #define _OV9655_  (((struct sd *) gspca_dev)->sensor == ID_OV9655)
 
 #define IMAGE_640   0
 #define IMAGE_800   1
 #define IMAGE_1280  2
-#define IMAGE_1600 3
+#define IMAGE_1600  3
 
 struct sd_gl860 {
 	u16 backlight;
@@ -75,10 +72,10 @@
 	int  (*dev_camera_settings)(struct gspca_dev *);
 
 	u8   swapRB;
-	u8  mirrorMask;
-	u8  sensor;
-	s32 nbIm;
-	s32 nbRightUp;
+	u8   mirrorMask;
+	u8   sensor;
+	s32  nbIm;
+	s32  nbRightUp;
 	u8   waitSet;
 };
 
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 678675b..d951b0f 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -201,7 +201,7 @@
 
 	buffer_len = le16_to_cpu(ep->wMaxPacketSize);
 	interval = ep->bInterval;
-	PDEBUG(D_PROBE, "found int in endpoint: 0x%x, "
+	PDEBUG(D_CONF, "found int in endpoint: 0x%x, "
 		"buffer_len=%u, interval=%u",
 		ep->bEndpointAddress, buffer_len, interval);
 
@@ -226,7 +226,7 @@
 	gspca_dev->int_urb = urb;
 	ret = usb_submit_urb(urb, GFP_KERNEL);
 	if (ret < 0) {
-		PDEBUG(D_ERR, "submit URB failed with error %i", ret);
+		PDEBUG(D_ERR, "submit int URB failed with error %i", ret);
 		goto error_submit;
 	}
 	return ret;
@@ -294,19 +294,6 @@
 }
 #endif
 
-/* get the current input frame buffer */
-struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev)
-{
-	struct gspca_frame *frame;
-
-	frame = gspca_dev->cur_frame;
-	if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
-				!= V4L2_BUF_FLAG_QUEUED)
-		return NULL;
-	return frame;
-}
-EXPORT_SYMBOL(gspca_get_i_frame);
-
 /*
  * fill a video frame from an URB and resubmit
  */
@@ -439,20 +426,20 @@
 
 	PDEBUG(D_PACK, "add t:%d l:%d",	packet_type, len);
 
-	/* check the availability of the frame buffer */
-	frame = gspca_dev->cur_frame;
-	if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
-					!= V4L2_BUF_FLAG_QUEUED) {
-		gspca_dev->last_packet_type = DISCARD_PACKET;
-		return;
-	}
-
-	/* when start of a new frame, if the current frame buffer
-	 * is not queued, discard the whole frame */
 	if (packet_type == FIRST_PACKET) {
-		frame->data_end = frame->data;
+		i = atomic_read(&gspca_dev->fr_i);
+
+		/* if there are no queued buffer, discard the whole frame */
+		if (i == atomic_read(&gspca_dev->fr_q)) {
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+			return;
+		}
+		j = gspca_dev->fr_queue[i];
+		frame = &gspca_dev->frame[j];
 		frame->v4l2_buf.timestamp = ktime_to_timeval(ktime_get());
 		frame->v4l2_buf.sequence = ++gspca_dev->sequence;
+		gspca_dev->image = frame->data;
+		gspca_dev->image_len = 0;
 	} else if (gspca_dev->last_packet_type == DISCARD_PACKET) {
 		if (packet_type == LAST_PACKET)
 			gspca_dev->last_packet_type = packet_type;
@@ -461,34 +448,37 @@
 
 	/* append the packet to the frame buffer */
 	if (len > 0) {
-		if (frame->data_end - frame->data + len
-						 > frame->v4l2_buf.length) {
-			PDEBUG(D_ERR|D_PACK, "frame overflow %zd > %d",
-				frame->data_end - frame->data + len,
-				frame->v4l2_buf.length);
+		if (gspca_dev->image_len + len > gspca_dev->frsz) {
+			PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d",
+				gspca_dev->image_len + len,
+				gspca_dev->frsz);
 			packet_type = DISCARD_PACKET;
 		} else {
-			memcpy(frame->data_end, data, len);
-			frame->data_end += len;
+			memcpy(gspca_dev->image + gspca_dev->image_len,
+				data, len);
+			gspca_dev->image_len += len;
 		}
 	}
 	gspca_dev->last_packet_type = packet_type;
 
-	/* if last packet, wake up the application and advance in the queue */
+	/* if last packet, invalidate packet concatenation until
+	 * next first packet, wake up the application and advance
+	 * in the queue */
 	if (packet_type == LAST_PACKET) {
-		frame->v4l2_buf.bytesused = frame->data_end - frame->data;
-		frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
-		frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
-		wake_up_interruptible(&gspca_dev->wq);	/* event = new frame */
-		i = (gspca_dev->fr_i + 1) % gspca_dev->nframes;
-		gspca_dev->fr_i = i;
-		PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d",
-			frame->v4l2_buf.bytesused,
-			gspca_dev->fr_q,
-			i,
-			gspca_dev->fr_o);
+		i = atomic_read(&gspca_dev->fr_i);
 		j = gspca_dev->fr_queue[i];
-		gspca_dev->cur_frame = &gspca_dev->frame[j];
+		frame = &gspca_dev->frame[j];
+		frame->v4l2_buf.bytesused = gspca_dev->image_len;
+		frame->v4l2_buf.flags = (frame->v4l2_buf.flags
+					 | V4L2_BUF_FLAG_DONE)
+					& ~V4L2_BUF_FLAG_QUEUED;
+		i = (i + 1) % GSPCA_MAX_FRAMES;
+		atomic_set(&gspca_dev->fr_i, i);
+		wake_up_interruptible(&gspca_dev->wq);	/* event = new frame */
+		PDEBUG(D_FRAM, "frame complete len:%d",
+			frame->v4l2_buf.bytesused);
+		gspca_dev->image = NULL;
+		gspca_dev->image_len = 0;
 	}
 }
 EXPORT_SYMBOL(gspca_frame_add);
@@ -506,36 +496,6 @@
 	return 0;
 }
 
-static void *rvmalloc(long size)
-{
-	void *mem;
-	unsigned long adr;
-
-	mem = vmalloc_32(size);
-	if (mem != NULL) {
-		adr = (unsigned long) mem;
-		while (size > 0) {
-			SetPageReserved(vmalloc_to_page((void *) adr));
-			adr += PAGE_SIZE;
-			size -= PAGE_SIZE;
-		}
-	}
-	return mem;
-}
-
-static void rvfree(void *mem, long size)
-{
-	unsigned long adr;
-
-	adr = (unsigned long) mem;
-	while (size > 0) {
-		ClearPageReserved(vmalloc_to_page((void *) adr));
-		adr += PAGE_SIZE;
-		size -= PAGE_SIZE;
-	}
-	vfree(mem);
-}
-
 static int frame_alloc(struct gspca_dev *gspca_dev,
 			unsigned int count)
 {
@@ -548,9 +508,9 @@
 	PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
 	frsz = PAGE_ALIGN(frsz);
 	gspca_dev->frsz = frsz;
-	if (count > GSPCA_MAX_FRAMES)
-		count = GSPCA_MAX_FRAMES;
-	gspca_dev->frbuf = rvmalloc(frsz * count);
+	if (count >= GSPCA_MAX_FRAMES)
+		count = GSPCA_MAX_FRAMES - 1;
+	gspca_dev->frbuf = vmalloc_32(frsz * count);
 	if (!gspca_dev->frbuf) {
 		err("frame alloc failed");
 		return -ENOMEM;
@@ -565,14 +525,12 @@
 		frame->v4l2_buf.length = frsz;
 		frame->v4l2_buf.memory = gspca_dev->memory;
 		frame->v4l2_buf.sequence = 0;
-		frame->data = frame->data_end =
-					gspca_dev->frbuf + i * frsz;
+		frame->data = gspca_dev->frbuf + i * frsz;
 		frame->v4l2_buf.m.offset = i * frsz;
 	}
-	gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
-	gspca_dev->cur_frame = &gspca_dev->frame[0];
-	gspca_dev->last_packet_type = DISCARD_PACKET;
-	gspca_dev->sequence = 0;
+	atomic_set(&gspca_dev->fr_q, 0);
+	atomic_set(&gspca_dev->fr_i, 0);
+	gspca_dev->fr_o = 0;
 	return 0;
 }
 
@@ -582,8 +540,7 @@
 
 	PDEBUG(D_STREAM, "frame free");
 	if (gspca_dev->frbuf != NULL) {
-		rvfree(gspca_dev->frbuf,
-			gspca_dev->nframes * gspca_dev->frsz);
+		vfree(gspca_dev->frbuf);
 		gspca_dev->frbuf = NULL;
 		for (i = 0; i < gspca_dev->nframes; i++)
 			gspca_dev->frame[i].data = NULL;
@@ -683,12 +640,16 @@
 				   : USB_ENDPOINT_XFER_ISOC;
 	i = gspca_dev->alt;			/* previous alt setting */
 	if (gspca_dev->cam.reverse_alts) {
+		if (gspca_dev->audio)
+			i++;
 		while (++i < gspca_dev->nbalt) {
 			ep = alt_xfer(&intf->altsetting[i], xfer);
 			if (ep)
 				break;
 		}
 	} else {
+		if (gspca_dev->audio)
+			i--;
 		while (--i >= 0) {
 			ep = alt_xfer(&intf->altsetting[i], xfer);
 			if (ep)
@@ -811,6 +772,12 @@
 		goto out;
 	}
 
+	/* reset the streaming variables */
+	gspca_dev->image = NULL;
+	gspca_dev->image_len = 0;
+	gspca_dev->last_packet_type = DISCARD_PACKET;
+	gspca_dev->sequence = 0;
+
 	gspca_dev->usb_err = 0;
 
 	/* set the higher alternate setting and
@@ -1433,34 +1400,6 @@
 	return ret;
 }
 
-/*fixme: have an audio flag in gspca_dev?*/
-static int vidioc_s_audio(struct file *file, void *priv,
-			 struct v4l2_audio *audio)
-{
-	if (audio->index != 0)
-		return -EINVAL;
-	return 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-			 struct v4l2_audio *audio)
-{
-	strcpy(audio->name, "Microphone");
-	return 0;
-}
-
-static int vidioc_enumaudio(struct file *file, void *priv,
-			 struct v4l2_audio *audio)
-{
-	if (audio->index != 0)
-		return -EINVAL;
-
-	strcpy(audio->name, "Microphone");
-	audio->capability = 0;
-	audio->mode = 0;
-	return 0;
-}
-
 static int vidioc_querymenu(struct file *file, void *priv,
 			    struct v4l2_querymenu *qmenu)
 {
@@ -1504,7 +1443,8 @@
 	struct gspca_dev *gspca_dev = priv;
 	int i, ret = 0, streaming;
 
-	switch (rb->memory) {
+	i = rb->memory;			/* (avoid compilation warning) */
+	switch (i) {
 	case GSPCA_MEMORY_READ:			/* (internal call) */
 	case V4L2_MEMORY_MMAP:
 	case V4L2_MEMORY_USERPTR:
@@ -1626,7 +1566,7 @@
 				enum v4l2_buf_type buf_type)
 {
 	struct gspca_dev *gspca_dev = priv;
-	int i, ret;
+	int ret;
 
 	if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
@@ -1650,12 +1590,10 @@
 	gspca_stream_off(gspca_dev);
 	mutex_unlock(&gspca_dev->usb_lock);
 
-	/* empty the application queues */
-	for (i = 0; i < gspca_dev->nframes; i++)
-		gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS;
-	gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
-	gspca_dev->last_packet_type = DISCARD_PACKET;
-	gspca_dev->sequence = 0;
+	/* empty the transfer queues */
+	atomic_set(&gspca_dev->fr_q, 0);
+	atomic_set(&gspca_dev->fr_i, 0);
+	gspca_dev->fr_o = 0;
 	ret = 0;
 out:
 	mutex_unlock(&gspca_dev->queue_lock);
@@ -1732,7 +1670,7 @@
 	int n;
 
 	n = parm->parm.capture.readbuffers;
-	if (n == 0 || n > GSPCA_MAX_FRAMES)
+	if (n == 0 || n >= GSPCA_MAX_FRAMES)
 		parm->parm.capture.readbuffers = gspca_dev->nbufread;
 	else
 		gspca_dev->nbufread = n;
@@ -1755,49 +1693,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv,
-			struct video_mbuf *mbuf)
-{
-	struct gspca_dev *gspca_dev = file->private_data;
-	int i;
-
-	PDEBUG(D_STREAM, "cgmbuf");
-	if (gspca_dev->nframes == 0) {
-		int ret;
-
-		{
-			struct v4l2_format fmt;
-
-			fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-			i = gspca_dev->cam.nmodes - 1;	/* highest mode */
-			fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
-			fmt.fmt.pix.height = gspca_dev->cam.cam_mode[i].height;
-			fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
-			ret = vidioc_s_fmt_vid_cap(file, priv, &fmt);
-			if (ret != 0)
-				return ret;
-		}
-		{
-			struct v4l2_requestbuffers rb;
-
-			memset(&rb, 0, sizeof rb);
-			rb.count = 4;
-			rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-			rb.memory = V4L2_MEMORY_MMAP;
-			ret = vidioc_reqbufs(file, priv, &rb);
-			if (ret != 0)
-				return ret;
-		}
-	}
-	mbuf->frames = gspca_dev->nframes;
-	mbuf->size = gspca_dev->frsz * gspca_dev->nframes;
-	for (i = 0; i < mbuf->frames; i++)
-		mbuf->offsets[i] = gspca_dev->frame[i].v4l2_buf.m.offset;
-	return 0;
-}
-#endif
-
 static int dev_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct gspca_dev *gspca_dev = file->private_data;
@@ -1838,12 +1733,7 @@
 		ret = -EINVAL;
 		goto out;
 	}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	/* v4l1 maps all the buffers */
-	if (i != 0
-	    || size != frame->v4l2_buf.length * gspca_dev->nframes)
-#endif
-	    if (size != frame->v4l2_buf.length) {
+	if (size != frame->v4l2_buf.length) {
 		PDEBUG(D_STREAM, "mmap bad size");
 		ret = -EINVAL;
 		goto out;
@@ -1883,21 +1773,17 @@
 static int frame_wait(struct gspca_dev *gspca_dev,
 			int nonblock_ing)
 {
-	struct gspca_frame *frame;
-	int i, j, ret;
+	int i, ret;
 
 	/* check if a frame is ready */
 	i = gspca_dev->fr_o;
-	j = gspca_dev->fr_queue[i];
-	frame = &gspca_dev->frame[j];
-
-	if (!(frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE)) {
+	if (i == atomic_read(&gspca_dev->fr_i)) {
 		if (nonblock_ing)
 			return -EAGAIN;
 
 		/* wait till a frame is ready */
 		ret = wait_event_interruptible_timeout(gspca_dev->wq,
-			(frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) ||
+			i != atomic_read(&gspca_dev->fr_i) ||
 			!gspca_dev->streaming || !gspca_dev->present,
 			msecs_to_jiffies(3000));
 		if (ret < 0)
@@ -1906,11 +1792,7 @@
 			return -EIO;
 	}
 
-	gspca_dev->fr_o = (i + 1) % gspca_dev->nframes;
-	PDEBUG(D_FRAM, "frame wait q:%d i:%d o:%d",
-		gspca_dev->fr_q,
-		gspca_dev->fr_i,
-		gspca_dev->fr_o);
+	gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES;
 
 	if (gspca_dev->sd_desc->dq_callback) {
 		mutex_lock(&gspca_dev->usb_lock);
@@ -1919,7 +1801,7 @@
 			gspca_dev->sd_desc->dq_callback(gspca_dev);
 		mutex_unlock(&gspca_dev->usb_lock);
 	}
-	return j;
+	return gspca_dev->fr_queue[i];
 }
 
 /*
@@ -2024,15 +1906,9 @@
 	}
 
 	/* put the buffer in the 'queued' queue */
-	i = gspca_dev->fr_q;
+	i = atomic_read(&gspca_dev->fr_q);
 	gspca_dev->fr_queue[i] = index;
-	if (gspca_dev->fr_i == i)
-		gspca_dev->cur_frame = frame;
-	gspca_dev->fr_q = (i + 1) % gspca_dev->nframes;
-	PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d",
-		gspca_dev->fr_q,
-		gspca_dev->fr_i,
-		gspca_dev->fr_o);
+	atomic_set(&gspca_dev->fr_q, (i + 1) % GSPCA_MAX_FRAMES);
 
 	v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
 	v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE;
@@ -2088,7 +1964,7 @@
 static unsigned int dev_poll(struct file *file, poll_table *wait)
 {
 	struct gspca_dev *gspca_dev = file->private_data;
-	int i, ret;
+	int ret;
 
 	PDEBUG(D_FRAM, "poll");
 
@@ -2106,11 +1982,9 @@
 	if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)
 		return POLLERR;
 
-	/* check the next incoming buffer */
-	i = gspca_dev->fr_o;
-	i = gspca_dev->fr_queue[i];
-	if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
-		ret = POLLIN | POLLRDNORM;	/* something to read */
+	/* check if an image has been received */
+	if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i))
+		ret = POLLIN | POLLRDNORM;	/* yes */
 	else
 		ret = 0;
 	mutex_unlock(&gspca_dev->queue_lock);
@@ -2214,9 +2088,6 @@
 	.vidioc_queryctrl	= vidioc_queryctrl,
 	.vidioc_g_ctrl		= vidioc_g_ctrl,
 	.vidioc_s_ctrl		= vidioc_s_ctrl,
-	.vidioc_g_audio		= vidioc_g_audio,
-	.vidioc_s_audio		= vidioc_s_audio,
-	.vidioc_enumaudio	= vidioc_enumaudio,
 	.vidioc_querymenu	= vidioc_querymenu,
 	.vidioc_enum_input	= vidioc_enum_input,
 	.vidioc_g_input		= vidioc_g_input,
@@ -2235,9 +2106,6 @@
 	.vidioc_s_register	= vidioc_s_register,
 #endif
 	.vidioc_g_chip_ident	= vidioc_g_chip_ident,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf          = vidiocgmbuf,
-#endif
 };
 
 static struct video_device gspca_template = {
@@ -2253,31 +2121,18 @@
  * This function must be called by the sub-driver when it is
  * called for probing a new device.
  */
-int gspca_dev_probe(struct usb_interface *intf,
+int gspca_dev_probe2(struct usb_interface *intf,
 		const struct usb_device_id *id,
 		const struct sd_desc *sd_desc,
 		int dev_size,
 		struct module *module)
 {
-	struct usb_interface_descriptor *interface;
 	struct gspca_dev *gspca_dev;
 	struct usb_device *dev = interface_to_usbdev(intf);
 	int ret;
 
 	PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct);
 
-	/* we don't handle multi-config cameras */
-	if (dev->descriptor.bNumConfigurations != 1) {
-		PDEBUG(D_ERR, "Too many config");
-		return -ENODEV;
-	}
-
-	/* the USB video interface must be the first one */
-	interface = &intf->cur_altsetting->desc;
-	if (dev->config->desc.bNumInterfaces != 1 &&
-	    interface->bInterfaceNumber != 0)
-		return -ENODEV;
-
 	/* create the device */
 	if (dev_size < sizeof *gspca_dev)
 		dev_size = sizeof *gspca_dev;
@@ -2293,8 +2148,26 @@
 		goto out;
 	}
 	gspca_dev->dev = dev;
-	gspca_dev->iface = interface->bInterfaceNumber;
+	gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber;
 	gspca_dev->nbalt = intf->num_altsetting;
+
+	/* check if any audio device */
+	if (dev->config->desc.bNumInterfaces != 1) {
+		int i;
+		struct usb_interface *intf2;
+
+		for (i = 0; i < dev->config->desc.bNumInterfaces; i++) {
+			intf2 = dev->config->interface[i];
+			if (intf2 != NULL
+			 && intf2->altsetting != NULL
+			 && intf2->altsetting->desc.bInterfaceClass ==
+					 USB_CLASS_AUDIO) {
+				gspca_dev->audio = 1;
+				break;
+			}
+		}
+	}
+
 	gspca_dev->sd_desc = sd_desc;
 	gspca_dev->nbufread = 2;
 	gspca_dev->empty_packet = -1;	/* don't check the empty packets */
@@ -2345,6 +2218,31 @@
 	kfree(gspca_dev);
 	return ret;
 }
+EXPORT_SYMBOL(gspca_dev_probe2);
+
+/* same function as the previous one, but check the interface */
+int gspca_dev_probe(struct usb_interface *intf,
+		const struct usb_device_id *id,
+		const struct sd_desc *sd_desc,
+		int dev_size,
+		struct module *module)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+
+	/* we don't handle multi-config cameras */
+	if (dev->descriptor.bNumConfigurations != 1) {
+		PDEBUG(D_ERR, "%04x:%04x too many config",
+				id->idVendor, id->idProduct);
+		return -ENODEV;
+	}
+
+	/* the USB video interface must be the first one */
+	if (dev->config->desc.bNumInterfaces != 1
+	 && intf->cur_altsetting->desc.bInterfaceNumber != 0)
+		return -ENODEV;
+
+	return gspca_dev_probe2(intf, id, sd_desc, dev_size, module);
+}
 EXPORT_SYMBOL(gspca_dev_probe);
 
 /*
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 8b963df..b749c36 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -7,7 +7,6 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <linux/mutex.h>
-#include <linux/slab.h>
 
 /* compilation option */
 #define GSPCA_DEBUG 1
@@ -148,7 +147,6 @@
 
 struct gspca_frame {
 	__u8 *data;			/* frame buffer */
-	__u8 *data_end;			/* end of frame while filling */
 	int vma_use_count;
 	struct v4l2_buffer v4l2_buf;
 };
@@ -177,13 +175,14 @@
 
 	__u8 *frbuf;				/* buffer for nframes */
 	struct gspca_frame frame[GSPCA_MAX_FRAMES];
-	struct gspca_frame *cur_frame;		/* frame beeing filled */
+	u8 *image;				/* image beeing filled */
 	__u32 frsz;				/* frame size */
-	char nframes;				/* number of frames */
-	char fr_i;				/* frame being filled */
-	char fr_q;				/* next frame to queue */
-	char fr_o;				/* next frame to dequeue */
+	u32 image_len;				/* current length of image */
+	atomic_t fr_q;				/* next frame to queue */
+	atomic_t fr_i;				/* frame being filled */
 	signed char fr_queue[GSPCA_MAX_FRAMES];	/* frame queue */
+	char nframes;				/* number of frames */
+	u8 fr_o;				/* next frame to dequeue */
 	__u8 last_packet_type;
 	__s8 empty_packet;		/* if (-1) don't check empty packets */
 	__u8 streaming;
@@ -199,6 +198,7 @@
 	struct mutex read_lock;		/* read protection */
 	struct mutex queue_lock;	/* ISOC queue protection */
 	int usb_err;			/* USB error - protected by usb_lock */
+	u16 pkt_size;			/* ISOC packet size */
 #ifdef CONFIG_PM
 	char frozen;			/* suspend - resume */
 #endif
@@ -209,7 +209,7 @@
 	__u8 iface;			/* USB interface number */
 	__u8 alt;			/* USB alternate setting */
 	__u8 nbalt;			/* number of USB alternate settings */
-	u16 pkt_size;			/* ISOC packet size */
+	u8 audio;			/* presence of audio device */
 };
 
 int gspca_dev_probe(struct usb_interface *intf,
@@ -217,12 +217,16 @@
 		const struct sd_desc *sd_desc,
 		int dev_size,
 		struct module *module);
+int gspca_dev_probe2(struct usb_interface *intf,
+		const struct usb_device_id *id,
+		const struct sd_desc *sd_desc,
+		int dev_size,
+		struct module *module);
 void gspca_disconnect(struct usb_interface *intf);
 void gspca_frame_add(struct gspca_dev *gspca_dev,
 			enum gspca_packet_type packet_type,
 			const u8 *data,
 			int len);
-struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev);
 #ifdef CONFIG_PM
 int gspca_suspend(struct usb_interface *intf, pm_message_t message);
 int gspca_resume(struct usb_interface *intf);
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c
index 84ecd56..12d9cf4 100644
--- a/drivers/media/video/gspca/jeilinj.c
+++ b/drivers/media/video/gspca/jeilinj.c
@@ -50,7 +50,7 @@
 	struct workqueue_struct *work_thread;
 	u8 quality;				 /* image quality */
 	u8 jpegqual;				/* webcam quality */
-	u8 *jpeg_hdr;
+	u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 	struct jlj_command {
@@ -282,7 +282,6 @@
 	destroy_workqueue(dev->work_thread);
 	dev->work_thread = NULL;
 	mutex_lock(&gspca_dev->usb_lock);
-	kfree(dev->jpeg_hdr);
 }
 
 /* this function is called at probe and resume time */
@@ -298,9 +297,6 @@
 	int ret;
 
 	/* create the JPEG header */
-	dev->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-	if (dev->jpeg_hdr == NULL)
-		return -ENOMEM;
 	jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width,
 			0x21);          /* JPEG 422 */
 	jpeg_set_qual(dev->jpeg_hdr, dev->quality);
diff --git a/drivers/media/video/gspca/m5602/m5602_bridge.h b/drivers/media/video/gspca/m5602/m5602_bridge.h
index 1127a40..51af3ee 100644
--- a/drivers/media/video/gspca/m5602/m5602_bridge.h
+++ b/drivers/media/video/gspca/m5602/m5602_bridge.h
@@ -19,6 +19,7 @@
 #ifndef M5602_BRIDGE_H_
 #define M5602_BRIDGE_H_
 
+#include <linux/slab.h>
 #include "gspca.h"
 
 #define MODULE_NAME "ALi m5602"
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
index 4294c75..b073d66 100644
--- a/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/drivers/media/video/gspca/m5602/m5602_core.c
@@ -305,30 +305,23 @@
 		       sd->frame_count);
 
 	} else {
-		struct gspca_frame *frame;
 		int cur_frame_len;
 
-		frame = gspca_get_i_frame(gspca_dev);
-		if (frame == NULL) {
-			gspca_dev->last_packet_type = DISCARD_PACKET;
-			return;
-		}
-
-		cur_frame_len = frame->data_end - frame->data;
+		cur_frame_len = gspca_dev->image_len;
 		/* Remove urb header */
 		data += 4;
 		len -= 4;
 
-		if (cur_frame_len + len <= frame->v4l2_buf.length) {
+		if (cur_frame_len + len <= gspca_dev->frsz) {
 			PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes",
 			       sd->frame_count, len);
 
 			gspca_frame_add(gspca_dev, INTER_PACKET,
 					data, len);
-		} else if (frame->v4l2_buf.length - cur_frame_len > 0) {
+		} else {
 			/* Add the remaining data up to frame size */
 			gspca_frame_add(gspca_dev, INTER_PACKET, data,
-				    frame->v4l2_buf.length - cur_frame_len);
+				    gspca_dev->frsz - cur_frame_len);
 		}
 	}
 }
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
index 6b3be4f..fbd9154 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
@@ -17,7 +17,6 @@
  */
 
 #include <linux/kthread.h>
-#include <linux/slab.h>
 #include "m5602_s5k83a.h"
 
 static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index 3d9229e..031f719 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -41,7 +41,7 @@
 #define QUALITY_MAX 70
 #define QUALITY_DEF 50
 
-	u8 *jpeg_hdr;
+	u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* V4L2 controls supported by the driver */
@@ -200,9 +200,6 @@
 	int i;
 
 	/* create the JPEG header */
-	sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-	if (!sd->jpeg_hdr)
-		return -ENOMEM;
 	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
 			0x21);		/* JPEG 422 */
 	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -317,13 +314,6 @@
 		PDEBUG(D_ERR, "Camera Stop failed");
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	kfree(sd->jpeg_hdr);
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
@@ -486,7 +476,6 @@
 	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
 	.get_jcomp = sd_get_jcomp,
 	.set_jcomp = sd_set_jcomp,
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index f36e11a..2b2cbdb 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -41,6 +41,11 @@
 #include <linux/input.h>
 #include "gspca.h"
 
+/* The jpeg_hdr is used by w996Xcf only */
+/* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */
+#define CONEX_CAM
+#include "jpeg.h"
+
 MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("OV519 USB Camera Driver");
 MODULE_LICENSE("GPL");
@@ -90,6 +95,7 @@
 #define QUALITY_DEF 50
 
 	__u8 stopped;		/* Streaming is temporarily paused */
+	__u8 first_frame;
 
 	__u8 frame_rate;	/* current Framerate */
 	__u8 clockdiv;		/* clockdiv override */
@@ -115,7 +121,7 @@
 	int sensor_height;
 	int sensor_reg_cache[256];
 
-	u8 *jpeg_hdr;
+	u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* Note this is a bit of a hack, but the w9968cf driver needs the code for all
@@ -3147,7 +3153,7 @@
 	sd->autobrightness = AUTOBRIGHT_DEF;
 	if (sd->sensor == SEN_OV7670) {
 		sd->freq = OV7670_FREQ_DEF;
-		gspca_dev->ctrl_dis = 1 << FREQ_IDX;
+		gspca_dev->ctrl_dis = (1 << FREQ_IDX) | (1 << COLOR_IDX);
 	} else {
 		sd->freq = FREQ_DEF;
 		gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) |
@@ -3961,6 +3967,8 @@
 	sd_reset_snapshot(gspca_dev);
 	sd->snapshot_pressed = 0;
 
+	sd->first_frame = 3;
+
 	ret = ov51x_restart(sd);
 	if (ret < 0)
 		goto out;
@@ -4153,13 +4161,23 @@
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
 {
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+
 	/* A short read signals EOF */
 	if (len < OVFX2_BULK_SIZE) {
-		gspca_frame_add(gspca_dev, LAST_PACKET, data, len);
+		/* If the frame is short, and it is one of the first ones
+		   the sensor and bridge are still syncing, so drop it. */
+		if (sd->first_frame) {
+			sd->first_frame--;
+			if (gspca_dev->image_len <
+				  sd->gspca_dev.width * sd->gspca_dev.height)
+				gspca_dev->last_packet_type = DISCARD_PACKET;
+		}
+		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
 		gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
-		return;
 	}
-	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index dc1e4ef..96cb3a9 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -987,13 +987,8 @@
 					data + 12, len - 12);
 		/* If this packet is marked as EOF, end the frame */
 		} else if (data[1] & UVC_STREAM_EOF) {
-			struct gspca_frame *frame;
-
 			sd->last_pts = 0;
-			frame = gspca_get_i_frame(gspca_dev);
-			if (frame == NULL)
-				goto discard;
-			if (frame->data_end - frame->data + (len - 12) !=
+			if (gspca_dev->image_len + len - 12 !=
 			    gspca_dev->width * gspca_dev->height * 2) {
 				PDEBUG(D_PACK, "wrong sized frame");
 				goto discard;
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c
index 2a68220..a66df07 100644
--- a/drivers/media/video/gspca/pac7302.c
+++ b/drivers/media/video/gspca/pac7302.c
@@ -402,7 +402,7 @@
 	memcpy(gspca_dev->usb_buf, buffer, len);
 	ret = usb_control_msg(gspca_dev->dev,
 			usb_sndctrlpipe(gspca_dev->dev, 0),
-			1,		/* request */
+			0,		/* request */
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			0,		/* value */
 			index, gspca_dev->usb_buf, len,
@@ -804,7 +804,6 @@
 };
 
 static void pac_start_frame(struct gspca_dev *gspca_dev,
-		struct gspca_frame *frame,
 		__u16 lines, __u16 samples_per_line)
 {
 	unsigned char tmpbuf[4];
@@ -829,19 +828,13 @@
 			int len)			/* iso packet length */
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	struct gspca_frame *frame;
+	u8 *image;
 	unsigned char *sof;
 
 	sof = pac_find_sof(&sd->sof_read, data, len);
 	if (sof) {
 		int n, lum_offset, footer_length;
 
-		frame = gspca_get_i_frame(gspca_dev);
-		if (frame == NULL) {
-			gspca_dev->last_packet_type = DISCARD_PACKET;
-			return;
-		}
-
 		/* 6 bytes after the FF D9 EOF marker a number of lumination
 		   bytes are send corresponding to different parts of the
 		   image, the 14th and 15th byte after the EOF seem to
@@ -852,16 +845,17 @@
 		/* Finish decoding current frame */
 		n = (sof - data) - (footer_length + sizeof pac_sof_marker);
 		if (n < 0) {
-			frame->data_end += n;
+			gspca_dev->image_len += n;
 			n = 0;
+		} else {
+			gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
 		}
-		gspca_frame_add(gspca_dev, INTER_PACKET,
-					data, n);
-		if (gspca_dev->last_packet_type != DISCARD_PACKET &&
-				frame->data_end[-2] == 0xff &&
-				frame->data_end[-1] == 0xd9)
-			gspca_frame_add(gspca_dev, LAST_PACKET,
-						NULL, 0);
+
+		image = gspca_dev->image;
+		if (image != NULL
+		 && image[gspca_dev->image_len - 2] == 0xff
+		 && image[gspca_dev->image_len - 1] == 0xd9)
+			gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
 
 		n = sof - data;
 		len -= n;
@@ -877,7 +871,7 @@
 
 		/* Start the new frame with the jpeg header */
 		/* The PAC7302 has the image rotated 90 degrees */
-		pac_start_frame(gspca_dev, frame,
+		pac_start_frame(gspca_dev,
 			gspca_dev->width, gspca_dev->height);
 	}
 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
@@ -1200,6 +1194,7 @@
 	{USB_DEVICE(0x093a, 0x2621)},
 	{USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
 	{USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
+	{USB_DEVICE(0x093a, 0x2625)},
 	{USB_DEVICE(0x093a, 0x2626)},
 	{USB_DEVICE(0x093a, 0x2628)},
 	{USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 44fed96..1cb7e99 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -270,7 +270,7 @@
 	memcpy(gspca_dev->usb_buf, buffer, len);
 	ret = usb_control_msg(gspca_dev->dev,
 			usb_sndctrlpipe(gspca_dev->dev, 0),
-			1,		/* request */
+			0,		/* request */
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			0,		/* value */
 			index, gspca_dev->usb_buf, len,
@@ -599,7 +599,6 @@
 };
 
 static void pac_start_frame(struct gspca_dev *gspca_dev,
-		struct gspca_frame *frame,
 		__u16 lines, __u16 samples_per_line)
 {
 	unsigned char tmpbuf[4];
@@ -624,19 +623,13 @@
 			int len)			/* iso packet length */
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	u8 *image;
 	unsigned char *sof;
-	struct gspca_frame *frame;
 
 	sof = pac_find_sof(&sd->sof_read, data, len);
 	if (sof) {
 		int n, lum_offset, footer_length;
 
-		frame = gspca_get_i_frame(gspca_dev);
-		if (frame == NULL) {
-			gspca_dev->last_packet_type = DISCARD_PACKET;
-			return;
-		}
-
 		/* 6 bytes after the FF D9 EOF marker a number of lumination
 		   bytes are send corresponding to different parts of the
 		   image, the 14th and 15th byte after the EOF seem to
@@ -647,16 +640,16 @@
 		/* Finish decoding current frame */
 		n = (sof - data) - (footer_length + sizeof pac_sof_marker);
 		if (n < 0) {
-			frame->data_end += n;
+			gspca_dev->image_len += n;
 			n = 0;
+		} else {
+			gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
 		}
-		gspca_frame_add(gspca_dev, INTER_PACKET,
-					data, n);
-		if (gspca_dev->last_packet_type != DISCARD_PACKET &&
-				frame->data_end[-2] == 0xff &&
-				frame->data_end[-1] == 0xd9)
-			gspca_frame_add(gspca_dev, LAST_PACKET,
-						NULL, 0);
+		image = gspca_dev->image;
+		if (image != NULL
+		 && image[gspca_dev->image_len - 2] == 0xff
+		 && image[gspca_dev->image_len - 1] == 0xd9)
+			gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
 
 		n = sof - data;
 		len -= n;
@@ -671,7 +664,7 @@
 			atomic_set(&sd->avg_lum, -1);
 
 		/* Start the new frame with the jpeg header */
-		pac_start_frame(gspca_dev, frame,
+		pac_start_frame(gspca_dev,
 			gspca_dev->height, gspca_dev->width);
 	}
 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 644a7fd..83a718f 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -20,7 +20,6 @@
 
 #ifdef CONFIG_INPUT
 #include <linux/input.h>
-#include <linux/slab.h>
 #endif
 
 #include "gspca.h"
@@ -89,7 +88,7 @@
 	u8 hstart;
 	u8 vstart;
 
-	u8 *jpeg_hdr;
+	u8 jpeg_hdr[JPEG_HDR_SZ];
 	u8 quality;
 
 	u8 flags;
@@ -2162,10 +2161,6 @@
 	int height = gspca_dev->height;
 	u8 fmt, scale = 0;
 
-	sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-	if (sd->jpeg_hdr == NULL)
-		return -ENOMEM;
-
 	jpeg_define(sd->jpeg_hdr, height, width,
 			0x21);
 	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -2197,8 +2192,8 @@
 	}
 
 	configure_sensor_output(gspca_dev, mode);
-	reg_w(gspca_dev, 0x1100, sd->jpeg_hdr + JPEG_QT0_OFFSET, 64);
-	reg_w(gspca_dev, 0x1140, sd->jpeg_hdr + JPEG_QT1_OFFSET, 64);
+	reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
+	reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
 	reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
 	reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
 	reg_w1(gspca_dev, 0x1189, scale);
@@ -2226,12 +2221,6 @@
 	reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	kfree(sd->jpeg_hdr);
-}
-
 static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -2397,7 +2386,6 @@
 	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
 #ifdef CONFIG_INPUT
 	.int_pkt_scan = sd_int_pkt_scan,
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index 95354a3..204bb3a 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -1251,16 +1251,10 @@
 	if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
 		/* In raw mode we sometimes get some garbage after the frame
 		   ignore this */
-		struct gspca_frame *frame;
 		int used;
 		int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
 
-		frame = gspca_get_i_frame(gspca_dev);
-		if (frame == NULL) {
-			gspca_dev->last_packet_type = DISCARD_PACKET;
-			return;
-		}
-		used = frame->data_end - frame->data;
+		used = gspca_dev->image_len;
 		if (used + len > size)
 			len = size - used;
 	}
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 176c5b3..ee17b03 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -22,7 +22,6 @@
 #define MODULE_NAME "sonixj"
 
 #include <linux/input.h>
-#include <linux/slab.h>
 #include "gspca.h"
 #include "jpeg.h"
 
@@ -392,7 +391,7 @@
 
 static const u8 sn_hv7131[0x1c] = {
 /*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
-	0x00,	0x03,	0x64,	0x00,	0x1a,	0x20,	0x20,	0x20,
+	0x00,	0x03,	0x60,	0x00,	0x1a,	0x20,	0x20,	0x20,
 /*	reg8	reg9	rega	regb	regc	regd	rege	regf */
 	0x81,	0x11,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
 /*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
@@ -403,7 +402,7 @@
 
 static const u8 sn_mi0360[0x1c] = {
 /*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
-	0x00,	0x61,	0x44,	0x00,	0x1a,	0x20,	0x20,	0x20,
+	0x00,	0x61,	0x40,	0x00,	0x1a,	0x20,	0x20,	0x20,
 /*	reg8	reg9	rega	regb	regc	regd	rege	regf */
 	0x81,	0x5d,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
 /*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
@@ -1644,6 +1643,7 @@
 			  const u8 *sn9c1xx)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	u8 reg0102[2];
 	const u8 *reg9a;
 	static const u8 reg9a_def[] =
 		{0x00, 0x40, 0x20, 0x00, 0x00, 0x00};
@@ -1656,7 +1656,11 @@
 	reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
 
 	/* configure gpio */
-	reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
+	reg0102[0] = sn9c1xx[1];
+	reg0102[1] = sn9c1xx[2];
+	if (gspca_dev->audio)
+		reg0102[1] |= 0x04;	/* keep the audio connection */
+	reg_w(gspca_dev, 0x01, reg0102, 2);
 	reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
 	reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);
 	switch (sd->sensor) {
@@ -1737,13 +1741,12 @@
 		reg_w1(gspca_dev, 0x01, 0x40);
 		break;
 	case SENSOR_PO2030N:
+	case SENSOR_OV7660:
 		reg_w1(gspca_dev, 0x01, 0x63);
 		reg_w1(gspca_dev, 0x17, 0x20);
 		reg_w1(gspca_dev, 0x01, 0x62);
 		reg_w1(gspca_dev, 0x01, 0x42);
 		break;
-	case SENSOR_OV7660:
-		/* fall thru */
 	case SENSOR_SP80708:
 		reg_w1(gspca_dev, 0x01, 0x63);
 		reg_w1(gspca_dev, 0x17, 0x20);
@@ -1816,7 +1819,7 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	const u8 *sn9c1xx;
-	u8 regGpio[] = { 0x29, 0x74 };
+	u8 regGpio[] = { 0x29, 0x74 };		/* with audio */
 	u8 regF1;
 
 	/* setup a selector by bridge */
@@ -1856,7 +1859,7 @@
 			po2030n_probe(gspca_dev);
 			break;
 		}
-		regGpio[1] = 0x70;
+		regGpio[1] = 0x70;		/* no audio */
 		reg_w(gspca_dev, 0x01, regGpio, 2);
 		break;
 	default:
@@ -2274,7 +2277,7 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int i;
-	u8 reg1, reg2, reg17;
+	u8 reg1, reg17;
 	const u8 *sn9c1xx;
 	const u8 (*init)[8];
 	int mode;
@@ -2304,23 +2307,6 @@
 	/* initialize the sensor */
 	i2c_w_seq(gspca_dev, sensor_init[sd->sensor]);
 
-	switch (sd->sensor) {
-	case SENSOR_ADCM1700:
-		reg2 = 0x60;
-		break;
-	case SENSOR_OM6802:
-		reg2 = 0x71;
-		break;
-	case SENSOR_SP80708:
-		reg2 = 0x62;
-		break;
-	default:
-		reg2 = 0x40;
-		break;
-	}
-	reg_w1(gspca_dev, 0x02, reg2);
-	reg_w1(gspca_dev, 0x02, reg2);
-
 	reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]);
 	reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]);
 	reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]);
diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c
new file mode 100644
index 0000000..3f514eb
--- /dev/null
+++ b/drivers/media/video/gspca/spca1528.c
@@ -0,0 +1,605 @@
+/*
+ * spca1528 subdriver
+ *
+ * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "spca1528"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("SPCA1528 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	u8 brightness;
+	u8 contrast;
+	u8 hue;
+	u8 color;
+	u8 sharpness;
+
+	u8 pkt_seq;
+
+	u8 jpeg_hdr[JPEG_HDR_SZ];
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+
+static const struct ctrl sd_ctrls[] = {
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define BRIGHTNESS_DEF 128
+		.default_value = BRIGHTNESS_DEF,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 8,
+		.step    = 1,
+#define CONTRAST_DEF 1
+		.default_value = CONTRAST_DEF,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+	{
+	    {
+		.id      = V4L2_CID_HUE,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Hue",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define HUE_DEF 0
+		.default_value = HUE_DEF,
+	    },
+	    .set = sd_sethue,
+	    .get = sd_gethue,
+	},
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Saturation",
+		.minimum = 0,
+		.maximum = 8,
+		.step    = 1,
+#define COLOR_DEF 1
+		.default_value = COLOR_DEF,
+	    },
+	    .set = sd_setcolor,
+	    .get = sd_getcolor,
+	},
+	{
+	    {
+		.id	 = V4L2_CID_SHARPNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Sharpness",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define SHARPNESS_DEF 0
+		.default_value = SHARPNESS_DEF,
+	    },
+	    .set = sd_setsharpness,
+	    .get = sd_getsharpness,
+	},
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+/*		(does not work correctly)
+	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144 * 5 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 3},
+*/
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 4 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 2},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+};
+
+/* read <len> bytes to gspca usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+			u8 req,
+			u16 index,
+			int len)
+{
+#if USB_BUF_SZ < 64
+#error "USB buffer too small"
+#endif
+	struct usb_device *dev = gspca_dev->dev;
+	int ret;
+
+	if (gspca_dev->usb_err < 0)
+		return;
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0x0000,			/* value */
+			index,
+			gspca_dev->usb_buf, len,
+			500);
+	PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", req, index,
+			 gspca_dev->usb_buf[0]);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_r err %d", ret);
+		gspca_dev->usb_err = ret;
+	}
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+			u8 req,
+			u16 value,
+			u16 index)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret;
+
+	if (gspca_dev->usb_err < 0)
+		return;
+	PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index);
+	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			req,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index,
+			NULL, 0, 500);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_w err %d", ret);
+		gspca_dev->usb_err = ret;
+	}
+}
+
+static void reg_wb(struct gspca_dev *gspca_dev,
+			u8 req,
+			u16 value,
+			u16 index,
+			u8 byte)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret;
+
+	if (gspca_dev->usb_err < 0)
+		return;
+	PDEBUG(D_USBO, "SET %02x %04x %04x %02x", req, value, index, byte);
+	gspca_dev->usb_buf[0] = byte;
+	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			req,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index,
+			gspca_dev->usb_buf, 1, 500);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_w err %d", ret);
+		gspca_dev->usb_err = ret;
+	}
+}
+
+static void wait_status_0(struct gspca_dev *gspca_dev)
+{
+	int i;
+
+	i = 20;
+	do {
+		reg_r(gspca_dev, 0x21, 0x0000, 1);
+		if (gspca_dev->usb_buf[0] == 0)
+			return;
+		msleep(30);
+	} while (--i > 0);
+	PDEBUG(D_ERR, "wait_status_0 timeout");
+	gspca_dev->usb_err = -ETIME;
+}
+
+static void wait_status_1(struct gspca_dev *gspca_dev)
+{
+	int i;
+
+	i = 10;
+	do {
+		reg_r(gspca_dev, 0x21, 0x0001, 1);
+		msleep(10);
+		if (gspca_dev->usb_buf[0] == 1) {
+			reg_wb(gspca_dev, 0x21, 0x0000, 0x0001, 0x00);
+			reg_r(gspca_dev, 0x21, 0x0001, 1);
+			return;
+		}
+	} while (--i > 0);
+	PDEBUG(D_ERR, "wait_status_1 timeout");
+	gspca_dev->usb_err = -ETIME;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_wb(gspca_dev, 0xc0, 0x0000, 0x00c0, sd->brightness);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_wb(gspca_dev, 0xc1, 0x0000, 0x00c1, sd->contrast);
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_wb(gspca_dev, 0xc2, 0x0000, 0x0000, sd->hue);
+}
+
+static void setcolor(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_wb(gspca_dev, 0xc3, 0x0000, 0x00c3, sd->color);
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_wb(gspca_dev, 0xc4, 0x0000, 0x00c4, sd->sharpness);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	gspca_dev->cam.cam_mode = vga_mode;
+	gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
+	gspca_dev->cam.npkt = 128; /* number of packets per ISOC message */
+			/*fixme: 256 in ms-win traces*/
+
+	sd->brightness = BRIGHTNESS_DEF;
+	sd->contrast = CONTRAST_DEF;
+	sd->hue = HUE_DEF;
+	sd->color = COLOR_DEF;
+	sd->sharpness = SHARPNESS_DEF;
+
+	gspca_dev->nbalt = 4;		/* use alternate setting 3 */
+
+	return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	reg_w(gspca_dev, 0x00, 0x0001, 0x2067);
+	reg_w(gspca_dev, 0x00, 0x00d0, 0x206b);
+	reg_w(gspca_dev, 0x00, 0x0000, 0x206c);
+	reg_w(gspca_dev, 0x00, 0x0001, 0x2069);
+	msleep(8);
+	reg_w(gspca_dev, 0x00, 0x00c0, 0x206b);
+	reg_w(gspca_dev, 0x00, 0x0000, 0x206c);
+	reg_w(gspca_dev, 0x00, 0x0001, 0x2069);
+
+	reg_r(gspca_dev, 0x20, 0x0000, 1);
+	reg_r(gspca_dev, 0x20, 0x0000, 5);
+	reg_r(gspca_dev, 0x23, 0x0000, 64);
+	PDEBUG(D_PROBE, "%s%s", &gspca_dev->usb_buf[0x1c],
+				&gspca_dev->usb_buf[0x30]);
+	reg_r(gspca_dev, 0x23, 0x0001, 64);
+	return gspca_dev->usb_err;
+}
+
+/* function called at start time before URB creation */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+	u8 mode;
+
+	reg_r(gspca_dev, 0x00, 0x2520, 1);
+	wait_status_0(gspca_dev);
+	reg_w(gspca_dev, 0xc5, 0x0003, 0x0000);
+	wait_status_1(gspca_dev);
+
+	wait_status_0(gspca_dev);
+	mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+	reg_wb(gspca_dev, 0x25, 0x0000, 0x0004, mode);
+	reg_r(gspca_dev, 0x25, 0x0004, 1);
+	reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06);
+	reg_r(gspca_dev, 0x27, 0x0000, 1);
+	return gspca_dev->usb_err;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* initialize the JPEG header */
+	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+			0x22);		/* JPEG 411 */
+
+	/* the JPEG quality seems to be 82% */
+	jpeg_set_qual(sd->jpeg_hdr, 82);
+
+	/* set the controls */
+	setbrightness(gspca_dev);
+	setcontrast(gspca_dev);
+	sethue(gspca_dev);
+	setcolor(gspca_dev);
+	setsharpness(gspca_dev);
+
+	msleep(5);
+	reg_r(gspca_dev, 0x00, 0x2520, 1);
+	msleep(8);
+
+	/* start the capture */
+	wait_status_0(gspca_dev);
+	reg_w(gspca_dev, 0x31, 0x0000, 0x0004);
+	wait_status_1(gspca_dev);
+	wait_status_0(gspca_dev);
+	msleep(200);
+
+	sd->pkt_seq = 0;
+	return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	/* stop the capture */
+	wait_status_0(gspca_dev);
+	reg_w(gspca_dev, 0x31, 0x0000, 0x0000);
+	wait_status_1(gspca_dev);
+	wait_status_0(gspca_dev);
+}
+
+/* move a packet adding 0x00 after 0xff */
+static void add_packet(struct gspca_dev *gspca_dev,
+			u8 *data,
+			int len)
+{
+	int i;
+
+	i = 0;
+	do {
+		if (data[i] == 0xff) {
+			gspca_frame_add(gspca_dev, INTER_PACKET,
+					data, i + 1);
+			len -= i;
+			data += i;
+			*data = 0x00;
+			i = 0;
+		}
+	} while (++i < len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	static const u8 ffd9[] = {0xff, 0xd9};
+
+	/* image packets start with:
+	 *	02 8n
+	 * with <n> bit:
+	 *	0x01: even (0) / odd (1) image
+	 *	0x02: end of image when set
+	 */
+	if (len < 3)
+		return;				/* empty packet */
+	if (*data == 0x02) {
+		if (data[1] & 0x02) {
+			sd->pkt_seq = !(data[1] & 1);
+			add_packet(gspca_dev, data + 2, len - 2);
+			gspca_frame_add(gspca_dev, LAST_PACKET,
+					ffd9, 2);
+			return;
+		}
+		if ((data[1] & 1) != sd->pkt_seq)
+			goto err;
+		if (gspca_dev->last_packet_type == LAST_PACKET)
+			gspca_frame_add(gspca_dev, FIRST_PACKET,
+					sd->jpeg_hdr, JPEG_HDR_SZ);
+		add_packet(gspca_dev, data + 2, len - 2);
+		return;
+	}
+err:
+	gspca_dev->last_packet_type = DISCARD_PACKET;
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return gspca_dev->usb_err;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return gspca_dev->usb_err;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->hue = val;
+	if (gspca_dev->streaming)
+		sethue(gspca_dev);
+	return gspca_dev->usb_err;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->hue;
+	return 0;
+}
+
+static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->color = val;
+	if (gspca_dev->streaming)
+		setcolor(gspca_dev);
+	return gspca_dev->usb_err;
+}
+
+static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->color;
+	return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->sharpness = val;
+	if (gspca_dev->streaming)
+		setsharpness(gspca_dev);
+	return gspca_dev->usb_err;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->sharpness;
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.init = sd_init,
+	.isoc_init = sd_isoc_init,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x04fc, 0x1528)},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	/* the video interface for isochronous transfer is 1 */
+	if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
+		return -ENODEV;
+
+	return gspca_dev_probe2(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	int ret;
+
+	ret = usb_register(&sd_driver);
+	if (ret < 0)
+		return ret;
+	info("registered");
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
index b866c73..c02beb6 100644
--- a/drivers/media/video/gspca/spca500.c
+++ b/drivers/media/video/gspca/spca500.c
@@ -57,7 +57,7 @@
 #define PalmPixDC85 13
 #define ToptroIndus 14
 
-	u8 *jpeg_hdr;
+	u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* V4L2 controls supported by the driver */
@@ -669,9 +669,6 @@
 	__u8 xmult, ymult;
 
 	/* create the JPEG header */
-	sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-	if (!sd->jpeg_hdr)
-		return -ENOMEM;
 	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
 			0x22);		/* JPEG 411 */
 	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -891,13 +888,6 @@
 		gspca_dev->usb_buf[0]);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	kfree(sd->jpeg_hdr);
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
@@ -1055,7 +1045,6 @@
 	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
 	.get_jcomp = sd_get_jcomp,
 	.set_jcomp = sd_set_jcomp,
diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c
new file mode 100644
index 0000000..37cee5e
--- /dev/null
+++ b/drivers/media/video/gspca/sq930x.c
@@ -0,0 +1,1402 @@
+/*
+ * SQ930x subdriver
+ *
+ * Copyright (C) 2010 Jean-François Moine <http://moinejf.free.fr>
+ * Copyright (C) 2006 -2008 Gerard Klaver <gerard at gkall dot hobby dot nl>
+ * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sq930x"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>\n"
+		"Gerard Klaver <gerard at gkall dot hobby dot nl\n"
+		"Sam Revitch <samr7@cs.washington.edu>");
+MODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+#define BULK_TRANSFER_LEN 5128
+
+/* Structure to hold all of our device specific stuff */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	u16 expo;
+	u8 gain;
+
+	u8 quality;		/* webcam quality 0..3 */
+#define QUALITY_DEF 1
+
+	u8 gpio[2];
+
+	u8 eof_len;
+	u8 do_ctrl;
+
+	u8 sensor;
+enum {
+	SENSOR_ICX098BQ,
+	SENSOR_LZ24BP,
+	SENSOR_MI0360,
+	SENSOR_MT9V111,
+	SENSOR_OV7660,
+	SENSOR_OV9630,
+} sensors;
+	u8 type;
+#define Generic 0
+#define Creative_live_motion 1
+
+	u8 jpeg_hdr[JPEG_HDR_SZ];
+};
+
+static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static const struct ctrl sd_ctrls[] = {
+	{
+	    {
+		.id = V4L2_CID_EXPOSURE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Exposure",
+		.minimum = 0x0001,
+		.maximum = 0x0fff,
+		.step = 1,
+#define EXPO_DEF 0x027d
+		.default_value = EXPO_DEF,
+	    },
+	    .set = sd_setexpo,
+	    .get = sd_getexpo,
+	},
+	{
+	    {
+		.id = V4L2_CID_GAIN,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Gain",
+		.minimum = 0x01,
+		.maximum = 0xff,
+		.step = 1,
+#define GAIN_DEF 0x61
+		.default_value = GAIN_DEF,
+	    },
+	    .set = sd_setgain,
+	    .get = sd_getgain,
+	},
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+	{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 160,
+		.sizeimage = 160 * 120 * 5 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 4 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 1},
+	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480 * 3 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 2},
+};
+
+/* JPEG quality indexed by webcam quality */
+#define QUAL_0 90
+#define QUAL_1 85
+#define QUAL_2 75
+#define QUAL_3 70
+static const u8 quality_tb[4] = { QUAL_0, QUAL_1, QUAL_2, QUAL_3 };
+
+/* sq930x registers */
+#define SQ930_CTRL_UCBUS_IO	0x0001
+#define SQ930_CTRL_I2C_IO	0x0002
+#define SQ930_CTRL_GPIO		0x0005
+#define SQ930_CTRL_CAP_START	0x0010
+#define SQ930_CTRL_CAP_STOP	0x0011
+#define SQ930_CTRL_SET_EXPOSURE 0x001d
+#define SQ930_CTRL_RESET	0x001e
+#define SQ930_CTRL_GET_DEV_INFO 0x001f
+
+/* gpio 1 (8..15) */
+#define SQ930_GPIO_DFL_I2C_SDA	0x0001
+#define SQ930_GPIO_DFL_I2C_SCL	0x0002
+#define SQ930_GPIO_RSTBAR	0x0004
+#define SQ930_GPIO_EXTRA1	0x0040
+#define SQ930_GPIO_EXTRA2	0x0080
+/* gpio 3 (24..31) */
+#define SQ930_GPIO_POWER	0x0200
+#define SQ930_GPIO_DFL_LED	0x1000
+
+struct ucbus_write_cmd {
+	u16	bw_addr;
+	u8	bw_data;
+};
+struct i2c_write_cmd {
+	u8	reg;
+	u16	val;
+};
+
+static const struct ucbus_write_cmd icx098bq_start_0[] = {
+	{0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce},
+	{0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e},
+	{0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02},
+	{0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02},
+	{0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00},
+	{0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04},
+	{0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00},
+	{0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48},
+	{0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
+	{0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
+	{0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff},
+	{0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
+	{0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00},
+	{0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
+	{0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
+	{0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c},
+	{0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30},
+	{0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30},
+	{0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc},
+	{0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
+	{0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00},
+	{0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00},
+	{0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa},
+	{0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa},
+	{0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
+	{0xf800, 0x03}
+};
+static const struct ucbus_write_cmd icx098bq_start_1[] = {
+	{0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+	{0xf5f4, 0xc0},
+	{0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+	{0xf5f4, 0xc0},
+	{0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+	{0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd icx098bq_start_2[] = {
+	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00},
+	{0xf807, 0x7f}, {0xf800, 0x03},
+	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00},
+	{0xf807, 0x7f}, {0xf800, 0x03},
+	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0},
+	{0xf807, 0x7f}, {0xf800, 0x03},
+	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
+	{0xf807, 0x7f}, {0xf800, 0x03}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_0[] = {
+	{0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe},
+	{0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06},
+	{0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02},
+	{0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00},
+	{0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00},
+	{0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03},
+	{0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00},
+	{0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48},
+	{0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
+	{0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
+	{0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0},
+	{0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
+	{0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00},
+	{0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
+	{0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
+	{0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30},
+	{0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c},
+	{0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c},
+	{0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d},
+	{0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
+	{0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d},
+	{0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d},
+	{0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04},
+	{0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04},
+	{0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
+	{0xf800, 0x03}
+};
+static const struct ucbus_write_cmd lz24bp_start_1_gen[] = {
+	{0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+	{0xf5f4, 0xb3},
+	{0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+	{0xf5f4, 0xb3},
+	{0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+	{0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_1_clm[] = {
+	{0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
+	{0xf5f4, 0xc0},
+	{0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
+	{0xf5f4, 0xc0},
+	{0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+	{0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_2[] = {
+	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00},
+	{0xf807, 0x7f}, {0xf800, 0x03},
+	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00},
+	{0xf807, 0x7f}, {0xf800, 0x03},
+	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48},
+	{0xf807, 0x7f}, {0xf800, 0x03},
+	{0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
+	{0xf807, 0x7f}, {0xf800, 0x03}
+};
+
+static const struct ucbus_write_cmd mi0360_start_0[] = {
+	{0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc},
+	{0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00}
+};
+static const struct i2c_write_cmd mi0360_init_23[] = {
+	{0x30, 0x0040},		/* reserved - def 0x0005 */
+	{0x31, 0x0000},		/* reserved - def 0x002a */
+	{0x34, 0x0100},		/* reserved - def 0x0100 */
+	{0x3d, 0x068f},		/* reserved - def 0x068f */
+};
+static const struct i2c_write_cmd mi0360_init_24[] = {
+	{0x03, 0x01e5},		/* window height */
+	{0x04, 0x0285},		/* window width */
+};
+static const struct i2c_write_cmd mi0360_init_25[] = {
+	{0x35, 0x0020},		/* global gain */
+	{0x2b, 0x0020},		/* green1 gain */
+	{0x2c, 0x002a},		/* blue gain */
+	{0x2d, 0x0028},		/* red gain */
+	{0x2e, 0x0020},		/* green2 gain */
+};
+static const struct ucbus_write_cmd mi0360_start_1[] = {
+	{0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+	{0xf5f4, 0xa6},
+	{0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+	{0xf5f4, 0xa6},
+	{0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+	{0xf5f9, 0x00}
+};
+static const struct i2c_write_cmd mi0360_start_2[] = {
+	{0x62, 0x041d},		/* reserved - def 0x0418 */
+};
+static const struct i2c_write_cmd mi0360_start_3[] = {
+	{0x05, 0x007b},		/* horiz blanking */
+};
+static const struct i2c_write_cmd mi0360_start_4[] = {
+	{0x05, 0x03f5},		/* horiz blanking */
+};
+
+static const struct i2c_write_cmd mt9v111_init_0[] = {
+	{0x01, 0x0001},		/* select IFP/SOC registers */
+	{0x06, 0x300c},		/* operating mode control */
+	{0x08, 0xcc00},		/* output format control (RGB) */
+	{0x01, 0x0004},		/* select core registers */
+};
+static const struct i2c_write_cmd mt9v111_init_1[] = {
+	{0x03, 0x01e5},		/* window height */
+	{0x04, 0x0285},		/* window width */
+};
+static const struct i2c_write_cmd mt9v111_init_2[] = {
+	{0x30, 0x7800},
+	{0x31, 0x0000},
+	{0x07, 0x3002},		/* output control */
+	{0x35, 0x0020},		/* global gain */
+	{0x2b, 0x0020},		/* green1 gain */
+	{0x2c, 0x0020},		/* blue gain */
+	{0x2d, 0x0020},		/* red gain */
+	{0x2e, 0x0020},		/* green2 gain */
+};
+static const struct ucbus_write_cmd mt9v111_start_1[] = {
+	{0xf5f0, 0x11}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+	{0xf5f4, 0xaa},
+	{0xf5f0, 0x51}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+	{0xf5f4, 0xaa},
+	{0xf5fa, 0x00}, {0xf5f6, 0x0a}, {0xf5f7, 0x0a}, {0xf5f8, 0x0a},
+	{0xf5f9, 0x0a}
+};
+static const struct i2c_write_cmd mt9v111_init_3[] = {
+	{0x62, 0x0405},
+};
+static const struct i2c_write_cmd mt9v111_init_4[] = {
+	{0x05, 0x00ce},		/* horizontal blanking */
+};
+
+static const struct ucbus_write_cmd ov7660_start_0[] = {
+	{0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0xc0},
+	{0xf334, 0x39}, {0xf335, 0xe7}, {0xf33f, 0x03}
+};
+
+static const struct ucbus_write_cmd ov9630_start_0[] = {
+	{0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0x00},
+	{0xf334, 0x3e}, {0xf335, 0xf8}, {0xf33f, 0x03}
+};
+
+static const struct cap_s {
+	u8	cc_sizeid;
+	u8	cc_bytes[32];
+} capconfig[4][3] = {
+	[SENSOR_ICX098BQ] = {
+		{0,				/* JPEG, 160x120 */
+		  {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
+		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+		   0x02, 0x8b, 0x00, 0x8b, 0x00, 0x41, 0x01, 0x41,
+		   0x01, 0x41, 0x01, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+		{2,				/* JPEG, 320x240 */
+		  {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
+		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+		   0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f,
+		   0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+		{4,				/* JPEG, 640x480 */
+		  {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xf0,
+		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+		   0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f,
+		   0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} },
+	},
+	[SENSOR_LZ24BP] = {
+		{0,				/* JPEG, 160x120 */
+		  {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
+		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+		   0x02, 0x8b, 0x00, 0x8b, 0x00, 0x41, 0x01, 0x41,
+		   0x01, 0x41, 0x01, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+		{2,				/* JPEG, 320x240 */
+		  {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee,
+		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+		   0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f,
+		   0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+		{4,				/* JPEG, 640x480 */
+		  {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xf0,
+		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+		   0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f,
+		   0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} },
+	},
+	[SENSOR_MI0360] = {
+		{0,				/* JPEG, 160x120 */
+		  {0x05, 0x3d, 0x20, 0x0b, 0x00, 0xbd, 0x02, 0x0b,
+		   0x02, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+		   0x02, 0x01, 0x01, 0x01, 0x01, 0x9f, 0x00, 0x9f,
+		   0x00, 0x9f, 0x01, 0x05, 0xa0, 0x00, 0x80, 0x00} },
+		{2,				/* JPEG, 320x240 */
+		  {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
+/*fixme				       03		       e3 */
+		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+		   0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f,
+		   0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+		{4,				/* JPEG, 640x480 */
+		  {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe3,
+		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+		   0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f,
+		   0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} },
+	},
+	[SENSOR_MT9V111] = {
+		{0,				/* JPEG, 160x120 */
+		  {0x05, 0x3d, 0x20, 0x0b, 0x00, 0xbd, 0x02, 0x0b,
+		   0x02, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+		   0x02, 0x01, 0x01, 0x01, 0x01, 0x9f, 0x00, 0x9f,
+		   0x00, 0x9f, 0x01, 0x05, 0xa0, 0x00, 0x80, 0x00} },
+		{2,				/* JPEG, 320x240 */
+		  {0x01, 0x02, 0x20, 0x03, 0x20, 0x82, 0x02, 0xe3,
+		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+		   0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f,
+		   0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+		{4,				/* JPEG, 640x480 */
+		  {0x01, 0x02, 0x20, 0x03, 0x20, 0x82, 0x02, 0xe3,
+		   0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+		   0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f,
+		   0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} },
+	},
+};
+
+struct sensor_s {
+	const char *name;
+	u8 i2c_addr;
+	u8 i2c_dum;
+	u8 gpio[5];
+	u8 cmd_len;
+	const struct ucbus_write_cmd *cmd;
+};
+
+static const struct sensor_s sensor_tb[] = {
+	[SENSOR_ICX098BQ] = {
+		"icx098bp",
+		0x00, 0x00,
+		{0,
+		 SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+		 SQ930_GPIO_DFL_I2C_SDA,
+		 0,
+		 SQ930_GPIO_RSTBAR
+		},
+		8, icx098bq_start_0
+	    },
+	[SENSOR_LZ24BP] = {
+		"lz24bp",
+		0x00, 0x00,
+		{0,
+		 SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+		 SQ930_GPIO_DFL_I2C_SDA,
+		 0,
+		 SQ930_GPIO_RSTBAR
+		},
+		8, lz24bp_start_0
+	    },
+	[SENSOR_MI0360] = {
+		"mi0360",
+		0x5d, 0x80,
+		{SQ930_GPIO_RSTBAR,
+		 SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+		 SQ930_GPIO_DFL_I2C_SDA,
+		 0,
+		 0
+		},
+		7, mi0360_start_0
+	    },
+	[SENSOR_MT9V111] = {
+		"mt9v111",
+		0x5c, 0x7f,
+		{SQ930_GPIO_RSTBAR,
+		 SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+		 SQ930_GPIO_DFL_I2C_SDA,
+		 0,
+		 0
+		},
+		7, mi0360_start_0
+	    },
+	[SENSOR_OV7660] = {
+		"ov7660",
+		0x21, 0x00,
+		{0,
+		 SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+		 SQ930_GPIO_DFL_I2C_SDA,
+		 0,
+		 SQ930_GPIO_RSTBAR
+		},
+		7, ov7660_start_0
+	    },
+	[SENSOR_OV9630] = {
+		"ov9630",
+		0x30, 0x00,
+		{0,
+		 SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+		 SQ930_GPIO_DFL_I2C_SDA,
+		 0,
+		 SQ930_GPIO_RSTBAR
+		},
+		7, ov9630_start_0
+	    },
+};
+
+static void reg_r(struct gspca_dev *gspca_dev,
+		u16 value, int len)
+{
+	int ret;
+
+	if (gspca_dev->usb_err < 0)
+		return;
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
+			0x0c,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, 0, gspca_dev->usb_buf, len,
+			500);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_r %04x failed %d", value, ret);
+		gspca_dev->usb_err = ret;
+	}
+}
+
+static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
+{
+	int ret;
+
+	if (gspca_dev->usb_err < 0)
+		return;
+	PDEBUG(D_USBO, "reg_w v: %04x i: %04x", value, index);
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			0x0c,			/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0,
+			500);
+	msleep(30);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_w %04x %04x failed %d", value, index, ret);
+		gspca_dev->usb_err = ret;
+	}
+}
+
+static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index,
+		const u8 *data, int len)
+{
+	int ret;
+
+	if (gspca_dev->usb_err < 0)
+		return;
+	PDEBUG(D_USBO, "reg_wb v: %04x i: %04x %02x...%02x",
+			value, index, *data, data[len - 1]);
+	memcpy(gspca_dev->usb_buf, data, len);
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			0x0c,			/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, gspca_dev->usb_buf, len,
+			1000);
+	msleep(30);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_wb %04x %04x failed %d", value, index, ret);
+		gspca_dev->usb_err = ret;
+	}
+}
+
+static void i2c_write(struct sd *sd,
+			const struct i2c_write_cmd *cmd,
+			int ncmds)
+{
+	struct gspca_dev *gspca_dev = &sd->gspca_dev;
+	const struct sensor_s *sensor;
+	u16 val, idx;
+	u8 *buf;
+	int ret;
+
+	if (gspca_dev->usb_err < 0)
+		return;
+
+	sensor = &sensor_tb[sd->sensor];
+
+	val = (sensor->i2c_addr << 8) | SQ930_CTRL_I2C_IO;
+	idx = (cmd->val & 0xff00) | cmd->reg;
+
+	buf = gspca_dev->usb_buf;
+	*buf++ = sensor->i2c_dum;
+	*buf++ = cmd->val;
+
+	while (--ncmds > 0) {
+		cmd++;
+		*buf++ = cmd->reg;
+		*buf++ = cmd->val >> 8;
+		*buf++ = sensor->i2c_dum;
+		*buf++ = cmd->val;
+	}
+
+	PDEBUG(D_USBO, "i2c_w v: %04x i: %04x %02x...%02x",
+			val, idx, gspca_dev->usb_buf[0], buf[-1]);
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			0x0c,			/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			val, idx,
+			gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
+			500);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "i2c_write failed %d", ret);
+		gspca_dev->usb_err = ret;
+	}
+}
+
+static void ucbus_write(struct gspca_dev *gspca_dev,
+			const struct ucbus_write_cmd *cmd,
+			int ncmds,
+			int batchsize)
+{
+	u8 *buf;
+	u16 val, idx;
+	int len, ret;
+
+	if (gspca_dev->usb_err < 0)
+		return;
+
+#ifdef GSPCA_DEBUG
+	if ((batchsize - 1) * 3 > USB_BUF_SZ) {
+		err("Bug: usb_buf overflow");
+		gspca_dev->usb_err = -ENOMEM;
+		return;
+	}
+#endif
+
+	for (;;) {
+		len = ncmds;
+		if (len > batchsize)
+			len = batchsize;
+		ncmds -= len;
+
+		val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO;
+		idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8);
+
+		buf = gspca_dev->usb_buf;
+		while (--len > 0) {
+			cmd++;
+			*buf++ = cmd->bw_addr;
+			*buf++ = cmd->bw_addr >> 8;
+			*buf++ = cmd->bw_data;
+		}
+		if (buf != gspca_dev->usb_buf)
+			PDEBUG(D_USBO, "ucbus v: %04x i: %04x %02x...%02x",
+					val, idx,
+					gspca_dev->usb_buf[0], buf[-1]);
+		else
+			PDEBUG(D_USBO, "ucbus v: %04x i: %04x",
+					val, idx);
+		ret = usb_control_msg(gspca_dev->dev,
+				usb_sndctrlpipe(gspca_dev->dev, 0),
+				0x0c,			/* request */
+			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				val, idx,
+				gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
+				500);
+		if (ret < 0) {
+			PDEBUG(D_ERR, "ucbus_write failed %d", ret);
+			gspca_dev->usb_err = ret;
+			return;
+		}
+		msleep(30);
+		if (ncmds <= 0)
+			break;
+		cmd++;
+	}
+}
+
+static void gpio_set(struct sd *sd, u16 val, u16 mask)
+{
+	struct gspca_dev *gspca_dev = &sd->gspca_dev;
+
+	if (mask & 0x00ff) {
+		sd->gpio[0] &= ~mask;
+		sd->gpio[0] |= val;
+		reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO,
+			~sd->gpio[0] << 8);
+	}
+	mask >>= 8;
+	val >>= 8;
+	if (mask) {
+		sd->gpio[1] &= ~mask;
+		sd->gpio[1] |= val;
+		reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO,
+			~sd->gpio[1] << 8);
+	}
+}
+
+static void gpio_init(struct sd *sd,
+			const u8 *gpio)
+{
+	gpio_set(sd, *gpio++, 0x000f);
+	gpio_set(sd, *gpio++, 0x000f);
+	gpio_set(sd, *gpio++, 0x000f);
+	gpio_set(sd, *gpio++, 0x000f);
+	gpio_set(sd, *gpio, 0x000f);
+}
+
+static void bridge_init(struct sd *sd)
+{
+	static const struct ucbus_write_cmd clkfreq_cmd = {
+				0xf031, 0	/* SQ930_CLKFREQ_60MHZ */
+	};
+
+	ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1);
+
+	gpio_set(sd, SQ930_GPIO_POWER, 0xff00);
+}
+
+static void cmos_probe(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	const struct sensor_s *sensor;
+	static const u8 probe_order[] = {
+/*		SENSOR_LZ24BP,		(tested as ccd) */
+		SENSOR_OV9630,
+		SENSOR_MI0360,
+		SENSOR_OV7660,
+		SENSOR_MT9V111,
+	};
+
+	for (i = 0; i < ARRAY_SIZE(probe_order); i++) {
+		sensor = &sensor_tb[probe_order[i]];
+		ucbus_write(&sd->gspca_dev, sensor->cmd, sensor->cmd_len, 8);
+		gpio_init(sd, sensor->gpio);
+		msleep(100);
+		reg_r(gspca_dev, (sensor->i2c_addr << 8) | 0x001c, 1);
+		msleep(100);
+		if (gspca_dev->usb_buf[0] != 0)
+			break;
+	}
+	if (i >= ARRAY_SIZE(probe_order))
+		PDEBUG(D_PROBE, "Unknown sensor");
+	else
+		sd->sensor = probe_order[i];
+}
+
+static void mt9v111_init(struct gspca_dev *gspca_dev)
+{
+	int i, nwait;
+	static const u8 cmd_001b[] = {
+		0x00, 0x3b, 0xf6, 0x01, 0x03, 0x02, 0x00, 0x00,
+		0x00, 0x00, 0x00
+	};
+	static const u8 cmd_011b[][7] = {
+		{0x10, 0x01, 0x66, 0x08, 0x00, 0x00, 0x00},
+		{0x01, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x00},
+		{0x20, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00},
+		{0x02, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00},
+	};
+
+	reg_wb(gspca_dev, 0x001b, 0x0000, cmd_001b, sizeof cmd_001b);
+	for (i = 0; i < ARRAY_SIZE(cmd_011b); i++) {
+		reg_wb(gspca_dev, 0x001b, 0x0000, cmd_011b[i],
+				ARRAY_SIZE(cmd_011b[0]));
+		msleep(400);
+		nwait = 20;
+		for (;;) {
+			reg_r(gspca_dev, 0x031b, 1);
+			if (gspca_dev->usb_buf[0] == 0
+			 || gspca_dev->usb_err != 0)
+				break;
+			if (--nwait < 0) {
+				PDEBUG(D_PROBE, "mt9v111_init timeout");
+				gspca_dev->usb_err = -ETIME;
+				return;
+			}
+			msleep(50);
+		}
+	}
+}
+
+static void global_init(struct sd *sd, int first_time)
+{
+	switch (sd->sensor) {
+	case SENSOR_ICX098BQ:
+		if (first_time)
+			ucbus_write(&sd->gspca_dev,
+					icx098bq_start_0,
+					8, 8);
+		gpio_init(sd, sensor_tb[sd->sensor].gpio);
+		break;
+	case SENSOR_LZ24BP:
+		if (sd->type != Creative_live_motion)
+			gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff);
+		else
+			gpio_set(sd, 0, 0x00ff);
+		msleep(50);
+		if (first_time)
+			ucbus_write(&sd->gspca_dev,
+					lz24bp_start_0,
+					8, 8);
+		gpio_init(sd, sensor_tb[sd->sensor].gpio);
+		break;
+	case SENSOR_MI0360:
+		if (first_time)
+			ucbus_write(&sd->gspca_dev,
+					mi0360_start_0,
+					ARRAY_SIZE(mi0360_start_0),
+					8);
+		gpio_init(sd, sensor_tb[sd->sensor].gpio);
+		gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2);
+		break;
+	default:
+/*	case SENSOR_MT9V111: */
+		if (first_time)
+			mt9v111_init(&sd->gspca_dev);
+		else
+			gpio_init(sd, sensor_tb[sd->sensor].gpio);
+		break;
+	}
+}
+
+static void lz24bp_ppl(struct sd *sd, u16 ppl)
+{
+	struct ucbus_write_cmd cmds[2] = {
+		{0xf810, ppl >> 8},
+		{0xf811, ppl}
+	};
+
+	ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i, integclks, intstartclk, frameclks, min_frclk;
+	const struct sensor_s *sensor;
+	u16 cmd;
+	u8 buf[15];
+
+	integclks = sd->expo;
+	i = 0;
+	cmd = SQ930_CTRL_SET_EXPOSURE;
+
+	switch (sd->sensor) {
+	case SENSOR_ICX098BQ:			/* ccd */
+	case SENSOR_LZ24BP:
+		min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f;
+		if (integclks >= min_frclk) {
+			intstartclk = 0;
+			frameclks = integclks;
+		} else {
+			intstartclk = min_frclk - integclks;
+			frameclks = min_frclk;
+		}
+		buf[i++] = intstartclk >> 8;
+		buf[i++] = intstartclk;
+		buf[i++] = frameclks >> 8;
+		buf[i++] = frameclks;
+		buf[i++] = sd->gain;
+		break;
+	default:				/* cmos */
+/*	case SENSOR_MI0360: */
+/*	case SENSOR_MT9V111: */
+		cmd |= 0x0100;
+		sensor = &sensor_tb[sd->sensor];
+		buf[i++] = sensor->i2c_addr;	/* i2c_slave_addr */
+		buf[i++] = 0x08;	/* 2 * ni2c */
+		buf[i++] = 0x09;	/* reg = shutter width */
+		buf[i++] = integclks >> 8; /* val H */
+		buf[i++] = sensor->i2c_dum;
+		buf[i++] = integclks;	/* val L */
+		buf[i++] = 0x35;	/* reg = global gain */
+		buf[i++] = 0x00;	/* val H */
+		buf[i++] = sensor->i2c_dum;
+		buf[i++] = sd->gain;	/* val L */
+		buf[i++] = 0x00;
+		buf[i++] = 0x00;
+		buf[i++] = 0x00;
+		buf[i++] = 0x00;
+		buf[i++] = 0x83;
+		break;
+	}
+	reg_wb(gspca_dev, cmd, 0, buf, i);
+}
+
+/* This function is called at probe time just before sd_init */
+static int sd_config(struct gspca_dev *gspca_dev,
+		const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam = &gspca_dev->cam;
+
+	sd->sensor = id->driver_info >> 8;
+	sd->type = id->driver_info;
+
+	cam->cam_mode = vga_mode;
+	cam->nmodes = ARRAY_SIZE(vga_mode);
+
+	cam->bulk = 1;
+	cam->bulk_size = BULK_TRANSFER_LEN;
+/*	cam->bulk_nurbs = 2;	fixme: if no setexpo sync */
+
+	sd->quality = QUALITY_DEF;
+	sd->gain = GAIN_DEF;
+	sd->expo = EXPO_DEF;
+
+	return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gpio[0] = sd->gpio[1] = 0xff;	/* force gpio rewrite */
+
+/*fixme: is this needed for icx098bp and mi0360?
+	if (sd->sensor != SENSOR_LZ24BP)
+		reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000);
+ */
+
+	reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8);
+/* it returns:
+ * 03 00 12 93 0b f6 c9 00	live! ultra
+ * 03 00 07 93 0b f6 ca 00	live! ultra for notebook
+ * 03 00 12 93 0b fe c8 00	Trust WB-3500T
+ * 02 00 06 93 0b fe c8 00	Joy-IT 318S
+ * 03 00 12 93 0b f6 cf 00	icam tracer - sensor icx098bq
+ * 02 00 12 93 0b fe cf 00	ProQ Motion Webcam
+ *
+ * byte
+ * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit)
+ * 1: 00
+ * 2: 06 / 07 / 12 = mode webcam? firmware??
+ * 3: 93 chip = 930b (930b or 930c)
+ * 4: 0b
+ * 5: f6 = cdd (icx098bq, lz24bp) / fe or de = cmos (i2c) (other sensors)
+ * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam?
+ * 7: 00
+ */
+	PDEBUG(D_PROBE, "info: %02x %02x %02x %02x %02x %02x %02x %02x",
+			gspca_dev->usb_buf[0],
+			gspca_dev->usb_buf[1],
+			gspca_dev->usb_buf[2],
+			gspca_dev->usb_buf[3],
+			gspca_dev->usb_buf[4],
+			gspca_dev->usb_buf[5],
+			gspca_dev->usb_buf[6],
+			gspca_dev->usb_buf[7]);
+
+	bridge_init(sd);
+
+	if (sd->sensor == SENSOR_MI0360) {
+
+		/* no sensor probe for icam tracer */
+		if (gspca_dev->usb_buf[5] == 0xf6) {	/* if CMOS */
+			sd->sensor = SENSOR_ICX098BQ;
+			gspca_dev->cam.cam_mode = &vga_mode[1];
+			gspca_dev->cam.nmodes = 1;	/* only 320x240 */
+		} else {
+			cmos_probe(gspca_dev);
+		}
+	}
+
+	PDEBUG(D_PROBE, "Sensor %s", sensor_tb[sd->sensor].name);
+
+	global_init(sd, 1);
+	return gspca_dev->usb_err;
+}
+
+/* special function to create the quantization tables of the JPEG header */
+static void sd_jpeg_set_qual(u8 *jpeg_hdr,
+				int quality)
+{
+	int i, sc1, sc2;
+
+	quality = quality_tb[quality];	/* convert to JPEG quality */
+/*
+ * approximative qualities for Y and U/V:
+ *	quant = 0:94%/91% 1:91%/87% 2:82%/73% 3:69%/56%
+ * should have:
+ *	quant = 0:94%/91% 1:91%/87.5% 2:81.5%/72% 3:69%/54.5%
+ */
+	sc1 = 200 - quality * 2;
+	quality = quality * 7 / 5 - 40;		/* UV quality */
+	sc2 = 200 - quality * 2;
+	for (i = 0; i < 64; i++) {
+		jpeg_hdr[JPEG_QT0_OFFSET + i] =
+			(jpeg_head[JPEG_QT0_OFFSET + i] * sc1 + 50) / 100;
+		jpeg_hdr[JPEG_QT1_OFFSET + i] =
+			(jpeg_head[JPEG_QT1_OFFSET + i] * sc2 + 50) / 100;
+	}
+}
+
+/* send the start/stop commands to the webcam */
+static void send_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	const struct cap_s *cap;
+	int mode, quality;
+
+	mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+	cap = &capconfig[sd->sensor][mode];
+	quality = sd->quality;
+	reg_wb(gspca_dev, (quality << 12)
+				 | 0x0a00	/* 900 for Bayer */
+				 | SQ930_CTRL_CAP_START,
+			0x0500			/* a00 for Bayer */
+				 | cap->cc_sizeid,
+			cap->cc_bytes, 32);
+};
+static void send_stop(struct gspca_dev *gspca_dev)
+{
+	reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0);
+};
+
+/* function called at start time before URB creation */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	gspca_dev->cam.bulk_nurbs = 1;	/* there must be one URB only */
+	sd->do_ctrl = 0;
+	return 0;
+}
+
+/* start the capture */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int mode;
+
+	/* initialize the JPEG header */
+	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+			0x21);		/* JPEG 422 */
+	sd_jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
+	bridge_init(sd);
+	global_init(sd, 0);
+	msleep(100);
+
+	switch (sd->sensor) {
+	case SENSOR_ICX098BQ:
+		ucbus_write(gspca_dev, icx098bq_start_0,
+				ARRAY_SIZE(icx098bq_start_0),
+				8);
+		ucbus_write(gspca_dev, icx098bq_start_1,
+				ARRAY_SIZE(icx098bq_start_1),
+				5);
+		ucbus_write(gspca_dev, icx098bq_start_2,
+				ARRAY_SIZE(icx098bq_start_2),
+				6);
+		msleep(50);
+
+		/* 1st start */
+		send_start(gspca_dev);
+		gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
+		msleep(70);
+		reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000);
+		gpio_set(sd, 0x7f, 0x00ff);
+
+		/* 2nd start */
+		send_start(gspca_dev);
+		gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
+		goto out;
+	case SENSOR_LZ24BP:
+		ucbus_write(gspca_dev, lz24bp_start_0,
+				ARRAY_SIZE(lz24bp_start_0),
+				8);
+		if (sd->type != Creative_live_motion)
+			ucbus_write(gspca_dev, lz24bp_start_1_gen,
+					ARRAY_SIZE(lz24bp_start_1_gen),
+					5);
+		else
+			ucbus_write(gspca_dev, lz24bp_start_1_clm,
+					ARRAY_SIZE(lz24bp_start_1_clm),
+					5);
+		ucbus_write(gspca_dev, lz24bp_start_2,
+				ARRAY_SIZE(lz24bp_start_2),
+				6);
+		mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+		lz24bp_ppl(sd, mode == 2 ? 0x0564 : 0x0310);
+		msleep(10);
+		break;
+	case SENSOR_MI0360:
+		ucbus_write(gspca_dev, mi0360_start_0,
+				ARRAY_SIZE(mi0360_start_0),
+				8);
+		i2c_write(sd, mi0360_init_23,
+				ARRAY_SIZE(mi0360_init_23));
+		i2c_write(sd, mi0360_init_24,
+				ARRAY_SIZE(mi0360_init_24));
+		i2c_write(sd, mi0360_init_25,
+				ARRAY_SIZE(mi0360_init_25));
+		ucbus_write(gspca_dev, mi0360_start_1,
+				ARRAY_SIZE(mi0360_start_1),
+				5);
+		i2c_write(sd, mi0360_start_2,
+				ARRAY_SIZE(mi0360_start_2));
+		i2c_write(sd, mi0360_start_3,
+				ARRAY_SIZE(mi0360_start_3));
+
+		/* 1st start */
+		send_start(gspca_dev);
+		msleep(60);
+		reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000);
+
+		i2c_write(sd,
+			mi0360_start_4, ARRAY_SIZE(mi0360_start_4));
+		break;
+	default:
+/*	case SENSOR_MT9V111: */
+		ucbus_write(gspca_dev, mi0360_start_0,
+				ARRAY_SIZE(mi0360_start_0),
+				8);
+		i2c_write(sd, mt9v111_init_0,
+				ARRAY_SIZE(mt9v111_init_0));
+		i2c_write(sd, mt9v111_init_1,
+				ARRAY_SIZE(mt9v111_init_1));
+		i2c_write(sd, mt9v111_init_2,
+				ARRAY_SIZE(mt9v111_init_2));
+		ucbus_write(gspca_dev, mt9v111_start_1,
+				ARRAY_SIZE(mt9v111_start_1),
+				8);
+		i2c_write(sd, mt9v111_init_3,
+				ARRAY_SIZE(mt9v111_init_3));
+		i2c_write(sd, mt9v111_init_4,
+				ARRAY_SIZE(mt9v111_init_4));
+		break;
+	}
+
+	send_start(gspca_dev);
+out:
+	msleep(1000);
+
+	sd->eof_len = 0;	/* init packet scan */
+
+	if (sd->sensor == SENSOR_MT9V111)
+		gpio_set(sd, SQ930_GPIO_DFL_LED, SQ930_GPIO_DFL_LED);
+
+	sd->do_ctrl = 1;	/* set the exposure */
+
+	return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_MT9V111)
+		gpio_set(sd, 0, SQ930_GPIO_DFL_LED);
+	send_stop(gspca_dev);
+}
+
+/* function called when the application gets a new frame */
+/* It sets the exposure if required and restart the bulk transfer. */
+static void sd_dq_callback(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0)
+		return;
+	sd->do_ctrl = 0;
+
+	setexposure(gspca_dev);
+
+	gspca_dev->cam.bulk_nurbs = 1;
+	ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC);
+	if (ret < 0)
+		PDEBUG(D_ERR|D_PACK, "sd_dq_callback() err %d", ret);
+
+	/* wait a little time, otherwise the webcam crashes */
+	msleep(100);
+}
+
+/* move a packet adding 0x00 after 0xff */
+static void add_packet(struct gspca_dev *gspca_dev,
+			u8 *data,
+			int len)
+{
+	int i;
+
+	i = 0;
+	do {
+		if (data[i] == 0xff) {
+			gspca_frame_add(gspca_dev, INTER_PACKET,
+					data, i + 1);
+			len -= i;
+			data += i;
+			*data = 0x00;
+			i = 0;
+		}
+	} while (++i < len);
+	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+/* end a frame and start a new one */
+static void eof_sof(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	static const u8 ffd9[] = {0xff, 0xd9};
+
+	/* if control set, stop bulk transfer */
+	if (sd->do_ctrl
+	 && gspca_dev->last_packet_type == INTER_PACKET)
+		gspca_dev->cam.bulk_nurbs = 0;
+	gspca_frame_add(gspca_dev, LAST_PACKET,
+			ffd9, 2);
+	gspca_frame_add(gspca_dev, FIRST_PACKET,
+			sd->jpeg_hdr, JPEG_HDR_SZ);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data,		/* isoc packet */
+			int len)		/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 *p;
+	int l;
+
+	len -= 8;	/* ignore last 8 bytes (00 00 55 aa 55 aa 00 00) */
+
+	/*
+	 * the end/start of frame is indicated by
+	 *	0x00 * 16 -  0xab * 8
+	 * aligned on 8 bytes boundary
+	 */
+	if (sd->eof_len != 0) {		/* if 'abababab' in previous pkt */
+		if (*((u32 *) data) == 0xabababab) {
+				/*fixme: should remove previous 0000ababab*/
+			eof_sof(gspca_dev);
+			data += 4;
+			len -= 4;
+		}
+		sd->eof_len = 0;
+	}
+	p = data;
+	l = len;
+	for (;;) {
+		if (*((u32 *) p) == 0xabababab) {
+			if (l < 8) {		/* (may be 4 only) */
+				sd->eof_len = 1;
+				break;
+			}
+			if (*((u32 *) p + 1) == 0xabababab) {
+				add_packet(gspca_dev, data, p - data - 16);
+						/* remove previous zeros */
+				eof_sof(gspca_dev);
+				p += 8;
+				l -= 8;
+				if (l <= 0)
+					return;
+				len = l;
+				data = p;
+				continue;
+			}
+		}
+		p += 4;
+		l -= 4;
+		if (l <= 0)
+			break;
+	}
+	add_packet(gspca_dev, data, len);
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gain = val;
+	if (gspca_dev->streaming)
+		sd->do_ctrl = 1;
+	return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->gain;
+	return 0;
+}
+static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->expo = val;
+	if (gspca_dev->streaming)
+		sd->do_ctrl = 1;
+	return 0;
+}
+
+static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->expo;
+	return 0;
+}
+
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+			struct v4l2_jpegcompression *jcomp)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int quality;
+
+	if (jcomp->quality >= (QUAL_0 + QUAL_1) / 2)
+		quality = 0;
+	else if (jcomp->quality >= (QUAL_1 + QUAL_2) / 2)
+		quality = 1;
+	else if (jcomp->quality >= (QUAL_2 + QUAL_3) / 2)
+		quality = 2;
+	else
+		quality = 3;
+
+	if (quality != sd->quality) {
+		sd->quality = quality;
+		if (gspca_dev->streaming) {
+			send_stop(gspca_dev);
+			sd_jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+			msleep(70);
+			send_start(gspca_dev);
+		}
+	}
+	return gspca_dev->usb_err;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+			struct v4l2_jpegcompression *jcomp)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	memset(jcomp, 0, sizeof *jcomp);
+	jcomp->quality = quality_tb[sd->quality];
+	jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+			| V4L2_JPEG_MARKER_DQT;
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name   = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.init   = sd_init,
+	.isoc_init = sd_isoc_init,
+	.start  = sd_start,
+	.stopN  = sd_stopN,
+	.pkt_scan = sd_pkt_scan,
+	.dq_callback = sd_dq_callback,
+	.get_jcomp = sd_get_jcomp,
+	.set_jcomp = sd_set_jcomp,
+};
+
+/* Table of supported USB devices */
+#define ST(sensor, type) \
+	.driver_info = (SENSOR_ ## sensor << 8) \
+			| (type)
+static const __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)},
+	{USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)},
+	{USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)},
+	{USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)},
+	{USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)},
+	{USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+			THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name	    = MODULE_NAME,
+	.id_table   = device_table,
+	.probe	    = sd_probe,
+	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend    = gspca_suspend,
+	.resume     = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	int ret;
+
+	ret = usb_register(&sd_driver);
+	if (ret < 0)
+		return ret;
+	info("registered");
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
index 0fb5342..2aedf4b 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/video/gspca/stk014.c
@@ -36,11 +36,11 @@
 	unsigned char colors;
 	unsigned char lightfreq;
 	u8 quality;
-#define QUALITY_MIN 60
+#define QUALITY_MIN 70
 #define QUALITY_MAX 95
-#define QUALITY_DEF 80
+#define QUALITY_DEF 88
 
-	u8 *jpeg_hdr;
+	u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* V4L2 controls supported by the driver */
@@ -337,9 +337,6 @@
 	int ret, value;
 
 	/* create the JPEG header */
-	sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-	if (!sd->jpeg_hdr)
-		return -ENOMEM;
 	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
 			0x22);		/* JPEG 411 */
 	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -412,13 +409,6 @@
 	PDEBUG(D_STREAM, "camera stopped");
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	kfree(sd->jpeg_hdr);
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
@@ -578,7 +568,6 @@
 	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
 	.querymenu = sd_querymenu,
 	.get_jcomp = sd_get_jcomp,
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h
index 992ce53..053a27e 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.h
@@ -30,6 +30,7 @@
 #ifndef STV06XX_H_
 #define STV06XX_H_
 
+#include <linux/slab.h>
 #include "gspca.h"
 
 #define MODULE_NAME "STV06xx"
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index d0a133a..9494f86 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -54,7 +54,7 @@
 #define MegapixV4 4
 #define MegaImageVI 5
 
-	u8 *jpeg_hdr;
+	u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* V4L2 controls supported by the driver */
@@ -842,9 +842,6 @@
 	int enable;
 
 	/* create the JPEG header */
-	sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-	if (!sd->jpeg_hdr)
-		return -ENOMEM;
 	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
 			0x22);		/* JPEG 411 */
 	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -954,13 +951,6 @@
 	}
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	kfree(sd->jpeg_hdr);
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
@@ -1162,7 +1152,6 @@
 	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
 	.get_jcomp = sd_get_jcomp,
 	.set_jcomp = sd_set_jcomp,
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index 6301437..2a0f12d 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -1,5 +1,7 @@
 /*
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * T613 subdriver
+ *
+ * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,6 +28,7 @@
 
 #define MODULE_NAME "t613"
 
+#include <linux/slab.h>
 #include "gspca.h"
 
 #define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
@@ -44,18 +47,20 @@
 	u8 gamma;
 	u8 sharpness;
 	u8 freq;
-	u8 red_balance; /* split balance */
-	u8 blue_balance;
-	u8 global_gain; /* aka gain */
-	u8 whitebalance; /* set default r/g/b and activate */
+	u8 red_gain;
+	u8 blue_gain;
+	u8 green_gain;
+	u8 awb; /* set default r/g/b and activate */
 	u8 mirror;
 	u8 effect;
 
 	u8 sensor;
-#define SENSOR_OM6802 0
-#define SENSOR_OTHER 1
-#define SENSOR_TAS5130A 2
-#define SENSOR_LT168G 3     /* must verify if this is the actual model */
+enum {
+	SENSOR_OM6802,
+	SENSOR_OTHER,
+	SENSOR_TAS5130A,
+	SENSOR_LT168G,		/* must verify if this is the actual model */
+} sensors;
 };
 
 /* V4L2 controls supported by the driver */
@@ -74,24 +79,22 @@
 static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
 
+static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
 
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val);
-
-static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_querymenu(struct gspca_dev *gspca_dev,
 			struct v4l2_querymenu *menu);
 
-
 static const struct ctrl sd_ctrls[] = {
 	{
 	 {
@@ -177,8 +180,8 @@
 #define MIRROR_DEF 0
 	  .default_value = MIRROR_DEF,
 	  },
-	 .set = sd_setflip,
-	 .get = sd_getflip
+	 .set = sd_setmirror,
+	 .get = sd_getmirror
 	},
 	{
 	 {
@@ -198,15 +201,15 @@
 	 {
 	  .id =  V4L2_CID_AUTO_WHITE_BALANCE,
 	  .type = V4L2_CTRL_TYPE_INTEGER,
-	  .name = "White Balance",
+	  .name = "Auto White Balance",
 	  .minimum = 0,
 	  .maximum = 1,
 	  .step = 1,
-#define WHITE_BALANCE_DEF 0
-	  .default_value = WHITE_BALANCE_DEF,
+#define AWB_DEF 0
+	  .default_value = AWB_DEF,
 	  },
-	 .set = sd_setwhitebalance,
-	 .get = sd_getwhitebalance
+	 .set = sd_setawb,
+	 .get = sd_getawb
 	},
 	{
 	 {
@@ -244,11 +247,11 @@
 	    .minimum = 0x10,
 	    .maximum = 0x40,
 	    .step    = 1,
-#define BLUE_BALANCE_DEF 0x20
-	    .default_value = BLUE_BALANCE_DEF,
+#define BLUE_GAIN_DEF 0x20
+	    .default_value = BLUE_GAIN_DEF,
 	 },
-	.set = sd_setblue_balance,
-	.get = sd_getblue_balance,
+	.set = sd_setblue_gain,
+	.get = sd_getblue_gain,
 	},
 	{
 	 {
@@ -258,11 +261,11 @@
 	    .minimum = 0x10,
 	    .maximum = 0x40,
 	    .step    = 1,
-#define RED_BALANCE_DEF 0x20
-	    .default_value = RED_BALANCE_DEF,
+#define RED_GAIN_DEF 0x20
+	    .default_value = RED_GAIN_DEF,
 	 },
-	.set = sd_setred_balance,
-	.get = sd_getred_balance,
+	.set = sd_setred_gain,
+	.get = sd_getred_gain,
 	},
 	{
 	 {
@@ -272,24 +275,14 @@
 	    .minimum = 0x10,
 	    .maximum = 0x40,
 	    .step    = 1,
-#define global_gain_DEF  0x20
-	    .default_value = global_gain_DEF,
+#define GAIN_DEF  0x20
+	    .default_value = GAIN_DEF,
 	 },
-	.set = sd_setglobal_gain,
-	.get = sd_getglobal_gain,
+	.set = sd_setgain,
+	.get = sd_getgain,
 	},
 };
 
-static char *effects_control[] = {
-	"Normal",
-	"Emboss",		/* disabled */
-	"Monochrome",
-	"Sepia",
-	"Sketch",
-	"Sun Effect",		/* disabled */
-	"Negative",
-};
-
 static const struct v4l2_pix_format vga_mode_t16[] = {
 	{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 		.bytesperline = 160,
@@ -327,7 +320,6 @@
 	const u8 data1[10];
 	const u8 data2[9];
 	const u8 data3[9];
-	const u8 data4[4];
 	const u8 data5[6];
 	const u8 stream[4];
 };
@@ -375,7 +367,7 @@
 };
 
 static const struct additional_sensor_data sensor_data[] = {
-    {				/* 0: OM6802 */
+[SENSOR_OM6802] = {
 	.n3 =
 		{0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
 	.n4 = n4_om6802,
@@ -392,14 +384,12 @@
 	.data3 =
 		{0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
 		 0xff},
-	.data4 =	/*Freq (50/60Hz). Splitted for test purpose */
-		{0x66, 0xca, 0xa8, 0xf0},
 	.data5 =	/* this could be removed later */
 		{0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
 	.stream =
 		{0x0b, 0x04, 0x0a, 0x78},
     },
-    {				/* 1: OTHER */
+[SENSOR_OTHER] = {
 	.n3 =
 		{0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
 	.n4 = n4_other,
@@ -416,14 +406,12 @@
 	.data3 =
 		{0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
 		 0xd9},
-	.data4 =
-		{0x66, 0x00, 0xa8, 0xa8},
 	.data5 =
 		{0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
 	.stream =
 		{0x0b, 0x04, 0x0a, 0x00},
     },
-    {				/* 2: TAS5130A */
+[SENSOR_TAS5130A] = {
 	.n3 =
 		{0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
 	.n4 = n4_tas5130a,
@@ -440,14 +428,12 @@
 	.data3 =
 		{0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
 		 0xe0},
-	.data4 =	/* Freq (50/60Hz). Splitted for test purpose */
-		{0x66, 0x00, 0xa8, 0xe8},
 	.data5 =
 		{0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
 	.stream =
 		{0x0b, 0x04, 0x0a, 0x40},
     },
-    {				/* 3: LT168G */
+[SENSOR_LT168G] = {
 	.n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
 	.n4 = n4_lt168g,
 	.n4sz = sizeof n4_lt168g,
@@ -460,7 +446,6 @@
 		 0xff},
 	.data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
 		 0xff},
-	.data4 = {0x66, 0x41, 0xa8, 0xf0},
 	.data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
 	.stream = {0x0b, 0x04, 0x0a, 0x28},
     },
@@ -469,6 +454,15 @@
 #define MAX_EFFECTS 7
 /* easily done by soft, this table could be removed,
  * i keep it here just in case */
+static char *effects_control[MAX_EFFECTS] = {
+	"Normal",
+	"Emboss",		/* disabled */
+	"Monochrome",
+	"Sepia",
+	"Sketch",
+	"Sun Effect",		/* disabled */
+	"Negative",
+};
 static const u8 effects_table[MAX_EFFECTS][6] = {
 	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00},	/* Normal */
 	{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04},	/* Repujar */
@@ -480,40 +474,41 @@
 };
 
 static const u8 gamma_table[GAMMA_MAX][17] = {
-	{0x00, 0x3e, 0x69, 0x85, 0x95, 0xa1, 0xae, 0xb9,	/* 0 */
-	 0xc2, 0xcb, 0xd4, 0xdb, 0xe3, 0xea, 0xf1, 0xf8,
+/* gamma table from cam1690.ini */
+	{0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21,	/* 0 */
+	 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
 	 0xff},
-	{0x00, 0x33, 0x5a, 0x75, 0x85, 0x93, 0xa1, 0xad,	/* 1 */
-	 0xb7, 0xc2, 0xcb, 0xd4, 0xde, 0xe7, 0xf0, 0xf7,
+	{0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d,	/* 1 */
+	 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
 	 0xff},
-	{0x00, 0x2f, 0x51, 0x6b, 0x7c, 0x8a, 0x99, 0xa6,	/* 2 */
-	 0xb1, 0xbc, 0xc6, 0xd0, 0xdb, 0xe4, 0xed, 0xf6,
+	{0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35,	/* 2 */
+	 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
 	 0xff},
-	{0x00, 0x29, 0x48, 0x60, 0x72, 0x81, 0x90, 0x9e,	/* 3 */
-	 0xaa, 0xb5, 0xbf, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
+	{0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f,	/* 3 */
+	 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
 	 0xff},
-	{0x00, 0x23, 0x3f, 0x55, 0x68, 0x77, 0x86, 0x95,	/* 4 */
-	 0xa2, 0xad, 0xb9, 0xc6, 0xd2, 0xde, 0xe9, 0xf4,
+	{0x00, 0x04, 0x0B, 0x15, 0x20, 0x2d, 0x3b, 0x4a,	/* 4 */
+	 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
 	 0xff},
-	{0x00, 0x1b, 0x33, 0x48, 0x59, 0x69, 0x79, 0x87,	/* 5 */
-	 0x96, 0xa3, 0xb1, 0xbe, 0xcc, 0xda, 0xe7, 0xf3,
+	{0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58,	/* 5 */
+	 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
 	 0xff},
-	{0x00, 0x02, 0x10, 0x20, 0x32, 0x40, 0x57, 0x67,	/* 6 */
+	{0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67,	/* 6 */
 	 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
 	 0xff},
-	{0x00, 0x02, 0x14, 0x26, 0x38, 0x4a, 0x60, 0x70,	/* 7 */
+	{0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,	/* 7 */
 	 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
 	 0xff},
-	{0x00, 0x10, 0x22, 0x35, 0x47, 0x5a, 0x69, 0x79,	/* 8 */
-	 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe0, 0xf0,
+	{0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79,	/* 8 */
+	 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
 	 0xff},
-	{0x00, 0x10, 0x26, 0x40, 0x54, 0x65, 0x75, 0x84,	/* 9 */
-	 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd6, 0xe0, 0xf0,
+	{0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84,	/* 9 */
+	 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
 	 0xff},
-	{0x00, 0x18, 0x2b, 0x44, 0x60, 0x70, 0x80, 0x8e,	/* 10 */
-	 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xd8, 0xe2, 0xf0,
+	{0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e,	/* 10 */
+	 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
 	 0xff},
-	{0x00, 0x1a, 0x34, 0x52, 0x66, 0x7e, 0x8d, 0x9b,	/* 11 */
+	{0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b,	/* 11 */
 	 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
 	 0xff},
 	{0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8,	/* 12 */
@@ -577,12 +572,11 @@
 	} else {
 		u8 *tmpbuf;
 
-		tmpbuf = kmalloc(len, GFP_KERNEL);
+		tmpbuf = kmemdup(buffer, len, GFP_KERNEL);
 		if (!tmpbuf) {
 			err("Out of memory");
 			return;
 		}
-		memcpy(tmpbuf, buffer, len);
 		usb_control_msg(gspca_dev->dev,
 				usb_sndctrlpipe(gspca_dev->dev, 0),
 				0,
@@ -625,7 +619,6 @@
 		kfree(tmpbuf);
 }
 
-/* Reported as OM6802*/
 static void om6802_sensor_init(struct gspca_dev *gspca_dev)
 {
 	int i;
@@ -703,12 +696,12 @@
 	sd->autogain = AUTOGAIN_DEF;
 	sd->mirror = MIRROR_DEF;
 	sd->freq = FREQ_DEF;
-	sd->whitebalance = WHITE_BALANCE_DEF;
+	sd->awb = AWB_DEF;
 	sd->sharpness = SHARPNESS_DEF;
 	sd->effect = EFFECTS_DEF;
-	sd->red_balance = RED_BALANCE_DEF;
-	sd->blue_balance = BLUE_BALANCE_DEF;
-	sd->global_gain = global_gain_DEF;
+	sd->red_gain = RED_GAIN_DEF;
+	sd->blue_gain = BLUE_GAIN_DEF;
+	sd->green_gain = GAIN_DEF * 3 - RED_GAIN_DEF - BLUE_GAIN_DEF;
 
 	return 0;
 }
@@ -761,40 +754,59 @@
 	reg_w_ixbuf(gspca_dev, 0x90,
 		gamma_table[sd->gamma], sizeof gamma_table[0]);
 }
-static void setglobalgain(struct gspca_dev *gspca_dev)
-{
 
+static void setRGB(struct gspca_dev *gspca_dev)
+{
 	struct sd *sd = (struct sd *) gspca_dev;
-	reg_w(gspca_dev, (sd->red_balance  << 8) + 0x87);
-	reg_w(gspca_dev, (sd->blue_balance << 8) + 0x88);
-	reg_w(gspca_dev, (sd->global_gain  << 8) + 0x89);
+	u8 all_gain_reg[6] =
+		{0x87, 0x00, 0x88, 0x00, 0x89, 0x00};
+
+	all_gain_reg[1] = sd->red_gain;
+	all_gain_reg[3] = sd->blue_gain;
+	all_gain_reg[5] = sd->green_gain;
+	reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
 }
 
-/* Generic fnc for r/b balance, exposure and whitebalance */
-static void setbalance(struct gspca_dev *gspca_dev)
+/* Generic fnc for r/b balance, exposure and awb */
+static void setawb(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	u16 reg80;
 
-	/* on whitebalance leave defaults values */
-	if (sd->whitebalance) {
-		reg_w(gspca_dev, 0x3c80);
-	} else {
-		reg_w(gspca_dev, 0x3880);
+	reg80 = (sensor_data[sd->sensor].reg80 << 8) | 0x80;
+
+	/* on awb leave defaults values */
+	if (!sd->awb) {
 		/* shoud we wait here.. */
-		/* update and reset 'global gain' with webcam parameters */
-		sd->red_balance = reg_r(gspca_dev, 0x0087);
-		sd->blue_balance = reg_r(gspca_dev, 0x0088);
-		sd->global_gain = reg_r(gspca_dev, 0x0089);
-		setglobalgain(gspca_dev);
+		/* update and reset RGB gains with webcam values */
+		sd->red_gain = reg_r(gspca_dev, 0x0087);
+		sd->blue_gain = reg_r(gspca_dev, 0x0088);
+		sd->green_gain = reg_r(gspca_dev, 0x0089);
+		reg80 &= ~0x0400;		/* AWB off */
 	}
-
+	reg_w(gspca_dev, reg80);
+	reg_w(gspca_dev, reg80);
 }
 
-
-
-static void setwhitebalance(struct gspca_dev *gspca_dev)
+static void init_gains(struct gspca_dev *gspca_dev)
 {
-	setbalance(gspca_dev);
+	struct sd *sd = (struct sd *) gspca_dev;
+	u16 reg80;
+	u8 all_gain_reg[8] =
+		{0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00};
+
+	all_gain_reg[1] = sd->red_gain;
+	all_gain_reg[3] = sd->blue_gain;
+	all_gain_reg[5] = sd->green_gain;
+	reg80 = sensor_data[sd->sensor].reg80;
+	if (!sd->awb)
+		reg80 &= ~0x04;
+	all_gain_reg[7] = reg80;
+	reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
+
+	reg_w(gspca_dev, (sd->red_gain  << 8) + 0x87);
+	reg_w(gspca_dev, (sd->blue_gain << 8) + 0x88);
+	reg_w(gspca_dev, (sd->green_gain  << 8) + 0x89);
 }
 
 static void setsharpness(struct gspca_dev *gspca_dev)
@@ -807,6 +819,38 @@
 	reg_w(gspca_dev, reg_to_write);
 }
 
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	u8 reg66;
+	u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };
+
+	switch (sd->sensor) {
+	case SENSOR_LT168G:
+		if (sd->freq != 0)
+			freq[3] = 0xa8;
+		reg66 = 0x41;
+		break;
+	case SENSOR_OM6802:
+		reg66 = 0xca;
+		break;
+	default:
+		reg66 = 0x40;
+		break;
+	}
+	switch (sd->freq) {
+	case 0:				/* no flicker */
+		freq[3] = 0xf0;
+		break;
+	case 2:				/* 60Hz */
+		reg66 &= ~0x40;
+		break;
+	}
+	freq[1] = reg66;
+
+	reg_w_buf(gspca_dev, freq, sizeof freq);
+}
+
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
@@ -901,13 +945,9 @@
 	setgamma(gspca_dev);
 	setcolors(gspca_dev);
 	setsharpness(gspca_dev);
-	setwhitebalance(gspca_dev);
+	init_gains(gspca_dev);
+	setfreq(gspca_dev);
 
-	reg_w(gspca_dev, 0x2087);	/* tied to white balance? */
-	reg_w(gspca_dev, 0x2088);
-	reg_w(gspca_dev, 0x2089);
-
-	reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
 	reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
 	reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
 	reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
@@ -926,16 +966,16 @@
 	return 0;
 }
 
-static void setflip(struct gspca_dev *gspca_dev)
+static void setmirror(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	u8 flipcmd[8] =
+	u8 hflipcmd[8] =
 		{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
 
 	if (sd->mirror)
-		flipcmd[3] = 0x01;
+		hflipcmd[3] = 0x01;
 
-	reg_w_buf(gspca_dev, flipcmd, sizeof flipcmd);
+	reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
 }
 
 static void seteffect(struct gspca_dev *gspca_dev)
@@ -956,17 +996,6 @@
 		reg_w(gspca_dev, 0xfaa6);
 }
 
-static void setlightfreq(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
-
-	if (sd->freq == 2)	/* 60hz */
-		freq[1] = 0x00;
-
-	reg_w_buf(gspca_dev, freq, sizeof freq);
-}
-
 /* Is this really needed?
  * i added some module parameters for test with some users */
 static void poll_sensor(struct gspca_dev *gspca_dev)
@@ -979,9 +1008,7 @@
 	static const u8 poll2[] =
 		{0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
 		 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
-	static const u8 poll3[] =
-		{0x87, 0x3f, 0x88, 0x20, 0x89, 0x2d};
-	static const u8 poll4[] =
+	static const u8 noise03[] =	/* (some differences / ms-drv) */
 		{0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
 		 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
 		 0xc2, 0x80, 0xc3, 0x10};
@@ -989,8 +1016,7 @@
 	PDEBUG(D_STREAM, "[Sensor requires polling]");
 	reg_w_buf(gspca_dev, poll1, sizeof poll1);
 	reg_w_buf(gspca_dev, poll2, sizeof poll2);
-	reg_w_buf(gspca_dev, poll3, sizeof poll3);
-	reg_w_buf(gspca_dev, poll4, sizeof poll4);
+	reg_w_buf(gspca_dev, noise03, sizeof noise03);
 }
 
 static int sd_start(struct gspca_dev *gspca_dev)
@@ -1025,12 +1051,7 @@
 	case SENSOR_OM6802:
 		om6802_sensor_init(gspca_dev);
 		break;
-	case SENSOR_LT168G:
-		break;
-	case SENSOR_OTHER:
-		break;
-	default:
-/*	case SENSOR_TAS5130A: */
+	case SENSOR_TAS5130A:
 		i = 0;
 		for (;;) {
 			reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
@@ -1047,7 +1068,7 @@
 		break;
 	}
 	sensor = &sensor_data[sd->sensor];
-	reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
+	setfreq(gspca_dev);
 	reg_r(gspca_dev, 0x0012);
 	reg_w_buf(gspca_dev, t2, sizeof t2);
 	reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
@@ -1080,7 +1101,7 @@
 			u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
 {
-	static u8 ffd9[] = { 0xff, 0xd9 };
+	int pkt_type;
 
 	if (data[0] == 0x5a) {
 		/* Control Packet, after this came the header again,
@@ -1090,84 +1111,88 @@
 	}
 	data += 2;
 	len -= 2;
-	if (data[0] == 0xff && data[1] == 0xd8) {
-		/* extra bytes....., could be processed too but would be
-		 * a waste of time, right now leave the application and
-		 * libjpeg do it for ourserlves.. */
-		gspca_frame_add(gspca_dev, LAST_PACKET,
-					ffd9, 2);
-		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
-		return;
-	}
-
-	if (data[len - 2] == 0xff && data[len - 1] == 0xd9) {
-		/* Just in case, i have seen packets with the marker,
-		 * other's do not include it... */
-		len -= 2;
-	}
-	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+	if (data[0] == 0xff && data[1] == 0xd8)
+		pkt_type = FIRST_PACKET;
+	else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)
+		pkt_type = LAST_PACKET;
+	else
+		pkt_type = INTER_PACKET;
+	gspca_frame_add(gspca_dev, pkt_type, data, len);
 }
 
-
-static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	sd->blue_balance = val;
+	sd->blue_gain = val;
 	if (gspca_dev->streaming)
 		reg_w(gspca_dev, (val << 8) + 0x88);
 	return 0;
 }
 
-static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	*val = sd->blue_balance;
+	*val = sd->blue_gain;
 	return 0;
 }
 
-static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	sd->red_balance = val;
+	sd->red_gain = val;
 	if (gspca_dev->streaming)
 		reg_w(gspca_dev, (val << 8) + 0x87);
 
 	return 0;
 }
 
-static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	*val = sd->red_balance;
+	*val = sd->red_gain;
 	return 0;
 }
 
-
-
-static int sd_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	u16 psg, nsg;
 
-	sd->global_gain = val;
+	psg = sd->red_gain + sd->blue_gain + sd->green_gain;
+	nsg = val * 3;
+	sd->red_gain = sd->red_gain * nsg / psg;
+	if (sd->red_gain > 0x40)
+		sd->red_gain = 0x40;
+	else if (sd->red_gain < 0x10)
+		sd->red_gain = 0x10;
+	sd->blue_gain = sd->blue_gain * nsg / psg;
+	if (sd->blue_gain > 0x40)
+		sd->blue_gain = 0x40;
+	else if (sd->blue_gain < 0x10)
+		sd->blue_gain = 0x10;
+	sd->green_gain = sd->green_gain * nsg / psg;
+	if (sd->green_gain > 0x40)
+		sd->green_gain = 0x40;
+	else if (sd->green_gain < 0x10)
+		sd->green_gain = 0x10;
+
 	if (gspca_dev->streaming)
-		setglobalgain(gspca_dev);
-
+		setRGB(gspca_dev);
 	return 0;
 }
 
-static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	*val = sd->global_gain;
+	*val = (sd->red_gain + sd->blue_gain + sd->green_gain) / 3;
 	return 0;
 }
 
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -1186,35 +1211,35 @@
 	return *val;
 }
 
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	sd->whitebalance = val;
+	sd->awb = val;
 	if (gspca_dev->streaming)
-		setwhitebalance(gspca_dev);
+		setawb(gspca_dev);
 	return 0;
 }
 
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	*val = sd->whitebalance;
+	*val = sd->awb;
 	return *val;
 }
 
-static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->mirror = val;
 	if (gspca_dev->streaming)
-		setflip(gspca_dev);
+		setmirror(gspca_dev);
 	return 0;
 }
 
-static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -1300,7 +1325,7 @@
 
 	sd->freq = val;
 	if (gspca_dev->streaming)
-		setlightfreq(gspca_dev);
+		setfreq(gspca_dev);
 	return 0;
 }
 
@@ -1368,7 +1393,8 @@
 	case V4L2_CID_EFFECTS:
 		if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
 			strncpy((char *) menu->name,
-				effects_control[menu->index], 32);
+				effects_control[menu->index],
+				sizeof menu->name);
 			return 0;
 		}
 		break;
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
index c7b6eb1..d9c5bf3 100644
--- a/drivers/media/video/gspca/tv8532.c
+++ b/drivers/media/video/gspca/tv8532.c
@@ -30,29 +30,46 @@
 struct sd {
 	struct gspca_dev gspca_dev;	/* !! must be the first item */
 
-	__u16 brightness;
+	__u16 exposure;
+	__u16 gain;
 
 	__u8 packet;
 };
 
 /* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
 
 static const struct ctrl sd_ctrls[] = {
 	{
 	 {
-	  .id = V4L2_CID_BRIGHTNESS,
+	  .id = V4L2_CID_EXPOSURE,
 	  .type = V4L2_CTRL_TYPE_INTEGER,
-	  .name = "Brightness",
+	  .name = "Exposure",
 	  .minimum = 1,
-	  .maximum = 0x15f,	/* = 352 - 1 */
+	  .maximum = 0x18f,
 	  .step = 1,
-#define BRIGHTNESS_DEF 0x14c
-	  .default_value = BRIGHTNESS_DEF,
+#define EXPOSURE_DEF 0x18f
+	  .default_value = EXPOSURE_DEF,
 	  },
-	 .set = sd_setbrightness,
-	 .get = sd_getbrightness,
+	 .set = sd_setexposure,
+	 .get = sd_getexposure,
+	 },
+	{
+	 {
+	  .id = V4L2_CID_GAIN,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Gain",
+	  .minimum = 0,
+	  .maximum = 0x7ff,
+	  .step = 1,
+#define GAIN_DEF 0x100
+	  .default_value = GAIN_DEF,
+	  },
+	 .set = sd_setgain,
+	 .get = sd_getgain,
 	 },
 };
 
@@ -92,6 +109,14 @@
 #define R14_AD_ROW_BEGINL 0x14
 #define R15_AD_ROWBEGINH  0x15
 #define R1C_AD_EXPOSE_TIMEL 0x1c
+#define R20_GAIN_G1L	0x20
+#define R21_GAIN_G1H	0x21
+#define R22_GAIN_RL	0x22
+#define R23_GAIN_RH	0x23
+#define R24_GAIN_BL	0x24
+#define R25_GAIN_BH	0x25
+#define R26_GAIN_G2L	0x26
+#define R27_GAIN_G2H	0x27
 #define R28_QUANT	0x28
 #define R29_LINE	0x29
 #define R2C_POLARITY	0x2c
@@ -129,18 +154,6 @@
 	{0x05, 0x09, 0xf1},
 };
 
-static int reg_r(struct gspca_dev *gspca_dev,
-		 __u16 index)
-{
-	usb_control_msg(gspca_dev->dev,
-			usb_rcvctrlpipe(gspca_dev->dev, 0),
-			0x03,
-			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			0,	/* value */
-			index, gspca_dev->usb_buf, 1,
-			500);
-	return gspca_dev->usb_buf[0];
-}
 
 /* write 1 byte */
 static void reg_w1(struct gspca_dev *gspca_dev,
@@ -183,7 +196,6 @@
 	}
 	reg_w1(gspca_dev, R07_TABLE_LEN, i);
 	reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
-	msleep(10);
 }
 
 /* this function is called at probe time */
@@ -197,53 +209,13 @@
 	cam->cam_mode = sif_mode;
 	cam->nmodes = ARRAY_SIZE(sif_mode);
 
-	sd->brightness = BRIGHTNESS_DEF;
+	sd->exposure = EXPOSURE_DEF;
+	sd->gain = GAIN_DEF;
 	return 0;
 }
 
-static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev)
-{
-	int i;
-	static u8 reg_tb[] = {
-		R0C_AD_WIDTHL,
-		R0D_AD_WIDTHH,
-		R28_QUANT,
-		R29_LINE,
-		R2C_POLARITY,
-		R2D_POINT,
-		R2E_POINTH,
-		R2F_POINTB,
-		R30_POINTBH,
-		R2A_HIGH_BUDGET,
-		R2B_LOW_BUDGET,
-		R34_VID,
-		R35_VIDH,
-		R36_PID,
-		R37_PIDH,
-		R83_AD_IDH,
-		R10_AD_COL_BEGINL,
-		R11_AD_COL_BEGINH,
-		R14_AD_ROW_BEGINL,
-		R15_AD_ROWBEGINH,
-		0
-	};
-
-	i = 0;
-	do {
-		reg_r(gspca_dev, reg_tb[i]);
-		i++;
-	} while (reg_tb[i] != 0);
-}
-
 static void tv_8532_setReg(struct gspca_dev *gspca_dev)
 {
-	reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44);
-						/* begin active line */
-	reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00);
-						/* mirror and digital gain */
-	reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
-						/* = 0x84 */
-
 	reg_w1(gspca_dev, R3B_Test3, 0x0a);	/* Test0Sel = 10 */
 	/******************************************************/
 	reg_w1(gspca_dev, R0E_AD_HEIGHTL, 0x90);
@@ -255,101 +227,44 @@
 						/* mirror and digital gain */
 	reg_w1(gspca_dev, R14_AD_ROW_BEGINL, 0x0a);
 
-	reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
 	reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x02);
-
-	reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
-
 	reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
 	reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
 						/* = 0x84 */
 }
 
-static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
-{
-	int i;
-
-	/* strange polling from tgc */
-	for (i = 0; i < 10; i++) {
-		reg_w1(gspca_dev, R2C_POLARITY, 0x10);
-		reg_w1(gspca_dev, R00_PART_CONTROL,
-				LATENT_CHANGE | EXPO_CHANGE);
-		reg_w1(gspca_dev, R31_UPD, 0x01);
-	}
-}
-
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
 	tv_8532WriteEEprom(gspca_dev);
 
-	reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32);	/* slope begin 1,7V,
-							 * slope rate 2 */
-	reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00);
-	tv_8532ReadRegisters(gspca_dev);
-	reg_w1(gspca_dev, R3B_Test3, 0x0b);
-	reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190);
-	reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f);
-	reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8);
-	reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
-
-	/*******************************************************************/
-	reg_w1(gspca_dev, R28_QUANT, 0x90);
-					/* no compress - fixed Q - quant 0 */
-	reg_w1(gspca_dev, R29_LINE, 0x81);
-					/* 0x84; // CIF | 4 packet 0x29 */
-
-	/************************************************/
-	reg_w1(gspca_dev, R2C_POLARITY, 0x10);
-						/* 0x48; //0x08; 0x2c */
-	reg_w1(gspca_dev, R2D_POINT, 0x14);
-						/* 0x38; 0x2d */
-	reg_w1(gspca_dev, R2E_POINTH, 0x01);
-						/* 0x04; 0x2e */
-	reg_w1(gspca_dev, R2F_POINTB, 0x12);
-						/* 0x04; 0x2f */
-	reg_w1(gspca_dev, R30_POINTBH, 0x01);
-						/* 0x04; 0x30 */
-	reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
-						/* 0x00<-0x84 */
-	/*************************************************/
-	reg_w1(gspca_dev, R31_UPD, 0x01);	/* update registers */
-	msleep(200);
-	reg_w1(gspca_dev, R31_UPD, 0x00);		/* end update */
-	/*************************************************/
-	tv_8532_setReg(gspca_dev);
-	/*************************************************/
-	reg_w1(gspca_dev, R3B_Test3, 0x0b);	/* Test0Sel = 11 = GPIO */
-	/*************************************************/
-	tv_8532_setReg(gspca_dev);
-	/*************************************************/
-	tv_8532_PollReg(gspca_dev);
 	return 0;
 }
 
-static void setbrightness(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->brightness);
+	reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->exposure);
 	reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
 						/* 0x84 */
 }
 
+static void setgain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_w2(gspca_dev, R20_GAIN_G1L, sd->gain);
+	reg_w2(gspca_dev, R22_GAIN_RL, sd->gain);
+	reg_w2(gspca_dev, R24_GAIN_BL, sd->gain);
+	reg_w2(gspca_dev, R26_GAIN_G2L, sd->gain);
+}
+
 /* -- start the camera -- */
 static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32);	/* slope begin 1,7V,
-							 * slope rate 2 */
-	reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00);
-	tv_8532ReadRegisters(gspca_dev);
-	reg_w1(gspca_dev, R3B_Test3, 0x0b);
-
-	reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190);
-	setbrightness(gspca_dev);
-
 	reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8);		/* 0x20; 0x0c */
 	reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
 
@@ -371,19 +286,15 @@
 	reg_w1(gspca_dev, R2E_POINTH, 0x01);
 	reg_w1(gspca_dev, R2F_POINTB, 0x12);
 	reg_w1(gspca_dev, R30_POINTBH, 0x01);
-	reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
+
+	tv_8532_setReg(gspca_dev);
+
+	setexposure(gspca_dev);
+	setgain(gspca_dev);
+
 	/************************************************/
 	reg_w1(gspca_dev, R31_UPD, 0x01);	/* update registers */
 	msleep(200);
-	reg_w1(gspca_dev, R31_UPD, 0x00);		/* end update */
-	/************************************************/
-	tv_8532_setReg(gspca_dev);
-	/************************************************/
-	reg_w1(gspca_dev, R3B_Test3, 0x0b);	/* Test0Sel = 11 = GPIO */
-	/************************************************/
-	tv_8532_setReg(gspca_dev);
-	/************************************************/
-	tv_8532_PollReg(gspca_dev);
 	reg_w1(gspca_dev, R31_UPD, 0x00);	/* end update */
 
 	gspca_dev->empty_packet = 0;		/* check the empty packets */
@@ -428,21 +339,39 @@
 			data + gspca_dev->width + 5, gspca_dev->width);
 }
 
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	sd->brightness = val;
+	sd->exposure = val;
 	if (gspca_dev->streaming)
-		setbrightness(gspca_dev);
+		setexposure(gspca_dev);
 	return 0;
 }
 
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	*val = sd->brightness;
+	*val = sd->exposure;
+	return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gain = val;
+	if (gspca_dev->streaming)
+		setgain(gspca_dev);
+	return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->gain;
 	return 0;
 }
 
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index 732c3df..031266a 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -2748,11 +2748,11 @@
 	{0xb3, 0x04, 0x15, 0xcc},
 	{0xb3, 0x20, 0x00, 0xcc},
 	{0xb3, 0x21, 0x00, 0xcc},
-	{0xb3, 0x22, 0x04, 0xcc},
+	{0xb3, 0x22, 0x04, 0xcc},	/* sensor height = 1024 */
 	{0xb3, 0x23, 0x00, 0xcc},
 	{0xb3, 0x14, 0x00, 0xcc},
 	{0xb3, 0x15, 0x00, 0xcc},
-	{0xb3, 0x16, 0x04, 0xcc},
+	{0xb3, 0x16, 0x04, 0xcc},	/* sensor width = 1280 */
 	{0xb3, 0x17, 0xff, 0xcc},
 	{0xb3, 0x2c, 0x03, 0xcc},
 	{0xb3, 0x2d, 0x56, 0xcc},
@@ -2919,7 +2919,7 @@
 	{0x00, 0x20, 0x11, 0xaa},
 	{0x00, 0x33, 0x38, 0xaa},
 	{0x00, 0xbb, 0x0d, 0xaa},
-	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x22, 0x01, 0xcc},	/* change to 640x480 */
 	{0xb3, 0x23, 0xe0, 0xcc},
 	{0xb3, 0x16, 0x02, 0xcc},
 	{0xb3, 0x17, 0x7f, 0xcc},
@@ -2935,7 +2935,7 @@
 	{0x00, 0x20, 0x33, 0xaa},
 	{0x00, 0x33, 0x38, 0xaa},
 	{0x00, 0xbb, 0x0d, 0xaa},
-	{0xb3, 0x22, 0x00, 0xcc},
+	{0xb3, 0x22, 0x00, 0xcc},	/* change to 320x240 */
 	{0xb3, 0x23, 0xf0, 0xcc},
 	{0xb3, 0x16, 0x01, 0xcc},
 	{0xb3, 0x17, 0x3f, 0xcc},
@@ -3068,37 +3068,84 @@
 };
 
 /* read 'len' bytes in gspca_dev->usb_buf */
-static void reg_r(struct gspca_dev *gspca_dev,
+static void reg_r_i(struct gspca_dev *gspca_dev,
 		  u16 req,
 		  u16 index,
 		  u16 len)
 {
-	usb_control_msg(gspca_dev->dev,
+	int ret;
+
+	if (gspca_dev->usb_err < 0)
+		return;
+	ret = usb_control_msg(gspca_dev->dev,
 			usb_rcvctrlpipe(gspca_dev->dev, 0),
 			req,
 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			1,			/* value */
 			index, gspca_dev->usb_buf, len,
 			500);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_r err %d", ret);
+		gspca_dev->usb_err = ret;
+	}
+}
+static void reg_r(struct gspca_dev *gspca_dev,
+		  u16 req,
+		  u16 index,
+		  u16 len)
+{
+	reg_r_i(gspca_dev, req, index, len);
+#ifdef GSPCA_DEBUG
+	if (gspca_dev->usb_err < 0)
+		return;
+	if (len == 1)
+		PDEBUG(D_USBI, "GET %02x 0001 %04x %02x", req, index,
+				gspca_dev->usb_buf[0]);
+	else
+		PDEBUG(D_USBI, "GET %02x 0001 %04x %02x %02x %02x",
+				req, index,
+				gspca_dev->usb_buf[0],
+				gspca_dev->usb_buf[1],
+				gspca_dev->usb_buf[2]);
+#endif
 }
 
-static void reg_w(struct usb_device *dev,
+static void reg_w_i(struct gspca_dev *gspca_dev,
 			    u16 req,
 			    u16 value,
 			    u16 index)
 {
-	usb_control_msg(dev,
-			usb_sndctrlpipe(dev, 0),
+	int ret;
+
+	if (gspca_dev->usb_err < 0)
+		return;
+	ret = usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
 			req,
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			value, index, NULL, 0,
 			500);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_w err %d", ret);
+		gspca_dev->usb_err = ret;
+	}
+}
+static void reg_w(struct gspca_dev *gspca_dev,
+			    u16 req,
+			    u16 value,
+			    u16 index)
+{
+#ifdef GSPCA_DEBUG
+	if (gspca_dev->usb_err < 0)
+		return;
+	PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index);
+#endif
+	reg_w_i(gspca_dev, req, value, index);
 }
 
 static u16 read_sensor_register(struct gspca_dev *gspca_dev,
 				u16 address)
 {
-	struct usb_device *dev = gspca_dev->dev;
 	u8 ldata, mdata, hdata;
 	int retry = 50;
 
@@ -3108,8 +3155,8 @@
 			gspca_dev->usb_buf[0]);
 		return 0;
 	}
-	reg_w(dev, 0xa0, address, 0xb33a);
-	reg_w(dev, 0xa0, 0x02, 0xb339);
+	reg_w(gspca_dev, 0xa0, address, 0xb33a);
+	reg_w(gspca_dev, 0xa0, 0x02, 0xb339);
 
 	do {
 		reg_r(gspca_dev, 0xa1, 0xb33b, 1);
@@ -3136,15 +3183,15 @@
 static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	struct usb_device *dev = gspca_dev->dev;
 	int i, n;
 	u16 value;
 	const struct sensor_info *ptsensor_info;
 
 /*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/
 	if (sd->flags & FL_SAMSUNG) {
-		reg_w(dev, 0xa0, 0x01, 0xb301);
-		reg_w(dev, 0x89, 0xf0ff, 0xffff); /* select the back sensor */
+		reg_w(gspca_dev, 0xa0, 0x01, 0xb301);
+		reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff);
+						/* select the back sensor */
 	}
 
 	reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
@@ -3158,13 +3205,13 @@
 		n = ARRAY_SIZE(vc0323_probe_data);
 	}
 	for (i = 0; i < n; i++) {
-		reg_w(dev, 0xa0, 0x02, 0xb334);
-		reg_w(dev, 0xa0, ptsensor_info->m1, 0xb300);
-		reg_w(dev, 0xa0, ptsensor_info->m2, 0xb300);
-		reg_w(dev, 0xa0, 0x01, 0xb308);
-		reg_w(dev, 0xa0, 0x0c, 0xb309);
-		reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
-		reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
+		reg_w(gspca_dev, 0xa0, 0x02, 0xb334);
+		reg_w(gspca_dev, 0xa0, ptsensor_info->m1, 0xb300);
+		reg_w(gspca_dev, 0xa0, ptsensor_info->m2, 0xb300);
+		reg_w(gspca_dev, 0xa0, 0x01, 0xb308);
+		reg_w(gspca_dev, 0xa0, 0x0c, 0xb309);
+		reg_w(gspca_dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
+		reg_w(gspca_dev, 0xa0, ptsensor_info->op, 0xb301);
 		value = read_sensor_register(gspca_dev, ptsensor_info->IdAdd);
 		if (value == 0 && ptsensor_info->IdAdd == 0x82)
 			value = read_sensor_register(gspca_dev, 0x83);
@@ -3192,26 +3239,33 @@
 			u8 reg, const u8 *val,
 			u8 size)		/* 1 or 2 */
 {
-	struct usb_device *dev = gspca_dev->dev;
 	int retry;
 
-	reg_r(gspca_dev, 0xa1, 0xb33f, 1);
+#ifdef GSPCA_DEBUG
+	if (gspca_dev->usb_err < 0)
+		return;
+	if (size == 1)
+		PDEBUG(D_USBO, "i2c_w %02x %02x", reg, *val);
+	else
+		PDEBUG(D_USBO, "i2c_w %02x %02x%02x", reg, *val, val[1]);
+#endif
+	reg_r_i(gspca_dev, 0xa1, 0xb33f, 1);
 /*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/
-	reg_w(dev, 0xa0, size, 0xb334);
-	reg_w(dev, 0xa0, reg, 0xb33a);
-	reg_w(dev, 0xa0, val[0], 0xb336);
+	reg_w_i(gspca_dev, 0xa0, size, 0xb334);
+	reg_w_i(gspca_dev, 0xa0, reg, 0xb33a);
+	reg_w_i(gspca_dev, 0xa0, val[0], 0xb336);
 	if (size > 1)
-		reg_w(dev, 0xa0, val[1], 0xb337);
-	reg_w(dev, 0xa0, 0x01, 0xb339);
+		reg_w_i(gspca_dev, 0xa0, val[1], 0xb337);
+	reg_w_i(gspca_dev, 0xa0, 0x01, 0xb339);
 	retry = 4;
 	do {
-		reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+		reg_r_i(gspca_dev, 0xa1, 0xb33b, 1);
 		if (gspca_dev->usb_buf[0] == 0)
 			break;
 		msleep(20);
 	} while (--retry > 0);
 	if (retry <= 0)
-		PDEBUG(D_ERR, "i2c_write failed");
+		PDEBUG(D_ERR, "i2c_write timeout");
 }
 
 static void put_tab_to_reg(struct gspca_dev *gspca_dev,
@@ -3221,13 +3275,12 @@
 	u16 ad = addr;
 
 	for (j = 0; j < tabsize; j++)
-		reg_w(gspca_dev->dev, 0xa0, tab[j], ad++);
+		reg_w(gspca_dev, 0xa0, tab[j], ad++);
 }
 
 static void usb_exchange(struct gspca_dev *gspca_dev,
 			const u8 data[][4])
 {
-	struct usb_device *dev = gspca_dev->dev;
 	int i = 0;
 
 	for (;;) {
@@ -3235,7 +3288,7 @@
 		default:
 			return;
 		case 0xcc:			/* normal write */
-			reg_w(dev, 0xa0, data[i][2],
+			reg_w(gspca_dev, 0xa0, data[i][2],
 					(data[i][0]) << 8 | data[i][1]);
 			break;
 		case 0xaa:			/* i2c op */
@@ -3259,7 +3312,6 @@
 			const struct usb_device_id *id)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	struct usb_device *dev = gspca_dev->dev;
 	struct cam *cam;
 	int sensor;
 	static u8 npkt[] = {	/* number of packets per ISOC message */
@@ -3363,13 +3415,6 @@
 	if (sd->sensor == SENSOR_OV7670)
 		sd->flags |= FL_HFLIP | FL_VFLIP;
 
-	if (sd->bridge == BRIDGE_VC0321) {
-		reg_r(gspca_dev, 0x8a, 0, 3);
-		reg_w(dev, 0x87, 0x00, 0x0f0f);
-
-		reg_r(gspca_dev, 0x8b, 0, 3);
-		reg_w(dev, 0x88, 0x00, 0x0202);
-	}
 	return 0;
 }
 
@@ -3378,15 +3423,21 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	if (sd->sensor == SENSOR_POxxxx) {
-		reg_r(gspca_dev, 0xa1, 0xb300, 1);
-		if (gspca_dev->usb_buf[0] != 0) {
-			reg_w(gspca_dev->dev, 0xa0, 0x26, 0xb300);
-			reg_w(gspca_dev->dev, 0xa0, 0x04, 0xb300);
-			reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb300);
+	if (sd->bridge == BRIDGE_VC0321) {
+		reg_r(gspca_dev, 0x8a, 0, 3);
+		reg_w(gspca_dev, 0x87, 0x00, 0x0f0f);
+		reg_r(gspca_dev, 0x8b, 0, 3);
+		reg_w(gspca_dev, 0x88, 0x00, 0x0202);
+		if (sd->sensor == SENSOR_POxxxx) {
+			reg_r(gspca_dev, 0xa1, 0xb300, 1);
+			if (gspca_dev->usb_buf[0] != 0) {
+				reg_w(gspca_dev, 0xa0, 0x26, 0xb300);
+				reg_w(gspca_dev, 0xa0, 0x04, 0xb300);
+				reg_w(gspca_dev, 0xa0, 0x00, 0xb300);
+			}
 		}
 	}
-	return 0;
+	return gspca_dev->usb_err;
 }
 
 static void setbrightness(struct gspca_dev *gspca_dev)
@@ -3516,17 +3567,17 @@
 
 /*fixme: back sensor only*/
 	if (sd->flags & FL_SAMSUNG) {
-		reg_w(gspca_dev->dev, 0x89, 0xf0ff, 0xffff);
-		reg_w(gspca_dev->dev, 0xa9, 0x8348, 0x000e);
-		reg_w(gspca_dev->dev, 0xa9, 0x0000, 0x001a);
+		reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff);
+		reg_w(gspca_dev, 0xa9, 0x8348, 0x000e);
+		reg_w(gspca_dev, 0xa9, 0x0000, 0x001a);
 	}
 
 	/* Assume start use the good resolution from gspca_dev->mode */
 	if (sd->bridge == BRIDGE_VC0321) {
-		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec);
-		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed);
-		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee);
-		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef);
+		reg_w(gspca_dev, 0xa0, 0xff, 0xbfec);
+		reg_w(gspca_dev, 0xa0, 0xff, 0xbfed);
+		reg_w(gspca_dev, 0xa0, 0xff, 0xbfee);
+		reg_w(gspca_dev, 0xa0, 0xff, 0xbfef);
 		sd->image_offset = 46;
 	} else {
 		if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].pixelformat
@@ -3617,7 +3668,7 @@
 			init = poxxxx_initVGA;
 		usb_exchange(gspca_dev, init);
 		reg_r(gspca_dev, 0x8c, 0x0000, 3);
-		reg_w(gspca_dev->dev, 0xa0,
+		reg_w(gspca_dev, 0xa0,
 				gspca_dev->usb_buf[2] & 1 ? 0 : 1,
 				0xb35c);
 		msleep(300);
@@ -3635,10 +3686,10 @@
 		switch (sd->sensor) {
 		case SENSOR_PO1200:
 		case SENSOR_HV7131R:
-			reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415);
+			reg_w(gspca_dev, 0x89, 0x0400, 0x1415);
 			break;
 		case SENSOR_MI1310_SOC:
-			reg_w(gspca_dev->dev, 0x89, 0x058c, 0x0000);
+			reg_w(gspca_dev, 0x89, 0x058c, 0x0000);
 			break;
 		}
 		msleep(100);
@@ -3648,9 +3699,9 @@
 	}
 	switch (sd->sensor) {
 	case SENSOR_OV7670:
-		reg_w(gspca_dev->dev, 0x87, 0xffff, 0xffff);
-		reg_w(gspca_dev->dev, 0x88, 0xff00, 0xf0f1);
-		reg_w(gspca_dev->dev, 0xa0, 0x0000, 0xbfff);
+		reg_w(gspca_dev, 0x87, 0xffff, 0xffff);
+		reg_w(gspca_dev, 0x88, 0xff00, 0xf0f1);
+		reg_w(gspca_dev, 0xa0, 0x0000, 0xbfff);
 		break;
 	case SENSOR_POxxxx:
 		setcolors(gspca_dev);
@@ -3659,51 +3710,49 @@
 
 		/* led on */
 		msleep(80);
-		reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+		reg_w(gspca_dev, 0x89, 0xffff, 0xfdff);
 		usb_exchange(gspca_dev, poxxxx_init_end_2);
 		break;
 	}
-	return 0;
+	return gspca_dev->usb_err;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-	struct usb_device *dev = gspca_dev->dev;
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	switch (sd->sensor) {
 	case SENSOR_MI1310_SOC:
-		reg_w(dev, 0x89, 0x058c, 0x00ff);
+		reg_w(gspca_dev, 0x89, 0x058c, 0x00ff);
 		break;
 	case SENSOR_POxxxx:
 		return;
 	default:
 		if (!(sd->flags & FL_SAMSUNG))
-			reg_w(dev, 0x89, 0xffff, 0xffff);
+			reg_w(gspca_dev, 0x89, 0xffff, 0xffff);
 		break;
 	}
-	reg_w(dev, 0xa0, 0x01, 0xb301);
-	reg_w(dev, 0xa0, 0x09, 0xb003);
+	reg_w(gspca_dev, 0xa0, 0x01, 0xb301);
+	reg_w(gspca_dev, 0xa0, 0x09, 0xb003);
 }
 
 /* called on streamoff with alt 0 and on disconnect */
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
-	struct usb_device *dev = gspca_dev->dev;
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	if (!gspca_dev->present)
 		return;
 /*fixme: is this useful?*/
 	if (sd->sensor == SENSOR_MI1310_SOC)
-		reg_w(dev, 0x89, 0x058c, 0x00ff);
+		reg_w(gspca_dev, 0x89, 0x058c, 0x00ff);
 	else if (!(sd->flags & FL_SAMSUNG))
-		reg_w(dev, 0x89, 0xffff, 0xffff);
+		reg_w(gspca_dev, 0x89, 0xffff, 0xffff);
 
 	if (sd->sensor == SENSOR_POxxxx) {
-		reg_w(dev, 0xa0, 0x26, 0xb300);
-		reg_w(dev, 0xa0, 0x04, 0xb300);
-		reg_w(dev, 0xa0, 0x00, 0xb300);
+		reg_w(gspca_dev, 0xa0, 0x26, 0xb300);
+		reg_w(gspca_dev, 0xa0, 0x04, 0xb300);
+		reg_w(gspca_dev, 0xa0, 0x00, 0xb300);
 	}
 }
 
@@ -3726,17 +3775,12 @@
 	/* The vc0321 sends some additional data after sending the complete
 	 * frame, we ignore this. */
 	if (sd->bridge == BRIDGE_VC0321) {
-		struct gspca_frame *frame;
-		int l;
+		int size, l;
 
-		frame = gspca_get_i_frame(gspca_dev);
-		if (frame == NULL) {
-			gspca_dev->last_packet_type = DISCARD_PACKET;
-			return;
-		}
-		l = frame->data_end - frame->data;
-		if (len > frame->v4l2_buf.length - l)
-			len = frame->v4l2_buf.length - l;
+		l = gspca_dev->image_len;
+		size = gspca_dev->frsz;
+		if (len > size - l)
+			len = size - l;
 	}
 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
@@ -3748,7 +3792,7 @@
 	sd->brightness = val;
 	if (gspca_dev->streaming)
 		setbrightness(gspca_dev);
-	return 0;
+	return gspca_dev->usb_err;
 }
 
 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3766,7 +3810,7 @@
 	sd->contrast = val;
 	if (gspca_dev->streaming)
 		setcontrast(gspca_dev);
-	return 0;
+	return gspca_dev->usb_err;
 }
 
 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3784,7 +3828,7 @@
 	sd->colors = val;
 	if (gspca_dev->streaming)
 		setcolors(gspca_dev);
-	return 0;
+	return gspca_dev->usb_err;
 }
 
 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3802,7 +3846,7 @@
 	sd->hflip = val;
 	if (gspca_dev->streaming)
 		sethvflip(gspca_dev);
-	return 0;
+	return gspca_dev->usb_err;
 }
 
 static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3820,7 +3864,7 @@
 	sd->vflip = val;
 	if (gspca_dev->streaming)
 		sethvflip(gspca_dev);
-	return 0;
+	return gspca_dev->usb_err;
 }
 
 static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3838,7 +3882,7 @@
 	sd->lightfreq = val;
 	if (gspca_dev->streaming)
 		setlightfreq(gspca_dev);
-	return 0;
+	return gspca_dev->usb_err;
 }
 
 static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3856,7 +3900,7 @@
 	sd->sharpness = val;
 	if (gspca_dev->streaming)
 		setsharpness(gspca_dev);
-	return 0;
+	return gspca_dev->usb_err;
 }
 
 static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
diff --git a/drivers/media/video/gspca/w996Xcf.c b/drivers/media/video/gspca/w996Xcf.c
index 2fffe20..38a6859 100644
--- a/drivers/media/video/gspca/w996Xcf.c
+++ b/drivers/media/video/gspca/w996Xcf.c
@@ -31,14 +31,10 @@
    the sensor drivers to v4l2 sub drivers, and properly split of this
    driver from ov519.c */
 
-/* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */
-#define CONEX_CAM
-#include "jpeg.h"
-
 #define W9968CF_I2C_BUS_DELAY    4 /* delay in us for I2C bit r/w operations */
 
-#define Y_QUANTABLE (sd->jpeg_hdr + JPEG_QT0_OFFSET)
-#define UV_QUANTABLE (sd->jpeg_hdr + JPEG_QT1_OFFSET)
+#define Y_QUANTABLE (&sd->jpeg_hdr[JPEG_QT0_OFFSET])
+#define UV_QUANTABLE (&sd->jpeg_hdr[JPEG_QT1_OFFSET])
 
 static const struct v4l2_pix_format w9968cf_vga_mode[] = {
 	{160, 120, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE,
@@ -509,11 +505,6 @@
 	if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
 	    V4L2_PIX_FMT_JPEG) {
 		/* We may get called multiple times (usb isoc bw negotiat.) */
-		if (!sd->jpeg_hdr)
-			sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-		if (!sd->jpeg_hdr)
-			return -ENOMEM;
-
 		jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height,
 			    sd->gspca_dev.width, 0x22); /* JPEG 420 */
 		jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -562,9 +553,6 @@
 		reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */
 		reg_w(sd, 0x16, 0x0000); /* stop video capture */
 	}
-
-	kfree(sd->jpeg_hdr);
-	sd->jpeg_hdr = NULL;
 }
 
 /* The w9968cf docs say that a 0 sized packet means EOF (and also SOF
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index d02aa5c..4473f0f 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -22,7 +22,6 @@
 #define MODULE_NAME "zc3xx"
 
 #include <linux/input.h>
-#include <linux/slab.h>
 #include "gspca.h"
 #include "jpeg.h"
 
@@ -40,15 +39,16 @@
 struct sd {
 	struct gspca_dev gspca_dev;	/* !! must be the first item */
 
+	u8 brightness;
 	u8 contrast;
 	u8 gamma;
 	u8 autogain;
 	u8 lightfreq;
 	u8 sharpness;
 	u8 quality;			/* image quality */
-#define QUALITY_MIN 40
-#define QUALITY_MAX 60
-#define QUALITY_DEF 50
+#define QUALITY_MIN 50
+#define QUALITY_MAX 80
+#define QUALITY_DEF 70
 
 	u8 sensor;		/* Type of image sensor chip */
 /* !! values used in different tables */
@@ -75,10 +75,12 @@
 #define SENSOR_MAX 19
 	unsigned short chip_revision;
 
-	u8 *jpeg_hdr;
+	u8 jpeg_hdr[JPEG_HDR_SZ];
 };
 
 /* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
@@ -93,6 +95,20 @@
 static const struct ctrl sd_ctrls[] = {
 	{
 	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+#define BRIGHTNESS_DEF 128
+		.default_value = BRIGHTNESS_DEF,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+	{
+	    {
 		.id      = V4L2_CID_CONTRAST,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
 		.name    = "Contrast",
@@ -132,7 +148,7 @@
 	    .set = sd_setautogain,
 	    .get = sd_getautogain,
 	},
-#define LIGHTFREQ_IDX 3
+#define LIGHTFREQ_IDX 4
 	{
 	    {
 		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -6011,9 +6027,12 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	struct usb_device *dev = gspca_dev->dev;
 	const u8 *Tgamma;
-	int g, i, k, adj, gp;
+	int g, i, brightness, contrast, adj, gp1, gp2;
 	u8 gr[16];
-	static const u8 delta_tb[16] =		/* delta for contrast */
+	static const u8 delta_b[16] =		/* delta for brightness */
+		{0x50, 0x38, 0x2d, 0x28, 0x24, 0x21, 0x1e, 0x1d,
+		 0x1d, 0x1b, 0x1b, 0x1b, 0x19, 0x18, 0x18, 0x18};
+	static const u8 delta_c[16] =		/* delta for contrast */
 		{0x2c, 0x1a, 0x12, 0x0c, 0x0a, 0x06, 0x06, 0x06,
 		 0x04, 0x06, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02};
 	static const u8 gamma_tb[6][16] = {
@@ -6033,30 +6052,30 @@
 
 	Tgamma = gamma_tb[sd->gamma - 1];
 
-	k = ((int) sd->contrast - 128);		/* -128 / 128 */
+	contrast = ((int) sd->contrast - 128);		/* -128 / 127 */
+	brightness = ((int) sd->brightness - 128);	/* -128 / 92 */
 	adj = 0;
-	gp = 0;
+	gp1 = gp2 = 0;
 	for (i = 0; i < 16; i++) {
-		g = Tgamma[i] - delta_tb[i] * k / 256 - adj / 2;
+		g = Tgamma[i] + delta_b[i] * brightness / 256
+				- delta_c[i] * contrast / 256 - adj / 2;
 		if (g > 0xff)
 			g = 0xff;
 		else if (g < 0)
 			g = 0;
 		reg_w(dev, g, 0x0120 + i);	/* gamma */
-		if (k > 0)
+		if (contrast > 0)
 			adj--;
-		else
+		else if (contrast < 0)
 			adj++;
-
-		if (i != 0) {
-			if (gp == 0)
-				gr[i - 1] = 0;
-			else
-				gr[i - 1] = g - gp;
-		}
-		gp = g;
+		if (i > 1)
+			gr[i - 1] = (g - gp2) / 2;
+		else if (i != 0)
+			gr[0] = gp1 == 0 ? 0 : (g - gp1);
+		gp2 = gp1;
+		gp1 = g;
 	}
-	gr[15] = gr[14] / 2;
+	gr[15] = (0xff - gp2) / 2;
 	for (i = 0; i < 16; i++)
 		reg_w(dev, gr[i], 0x0130 + i);	/* gradient */
 }
@@ -6744,6 +6763,7 @@
 		cam->nmodes = ARRAY_SIZE(broken_vga_mode);
 		break;
 	}
+	sd->brightness = BRIGHTNESS_DEF;
 	sd->contrast = CONTRAST_DEF;
 	sd->gamma = gamma[sd->sensor];
 	sd->autogain = AUTOGAIN_DEF;
@@ -6798,9 +6818,6 @@
 	};
 
 	/* create the JPEG header */
-	sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
-	if (!sd->jpeg_hdr)
-		return -ENOMEM;
 	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
 			0x21);		/* JPEG 422 */
 	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -6918,10 +6935,6 @@
 		reg_w(dev, 0x00, 0x0007);	/* (from win traces) */
 		reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
 		break;
-	case SENSOR_PAS202B:
-		reg_w(dev, 0x32, 0x0007);	/* (from win traces) */
-		reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
-		break;
 	}
 	return 0;
 }
@@ -6931,7 +6944,6 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	kfree(sd->jpeg_hdr);
 	if (!gspca_dev->present)
 		return;
 	send_unknown(gspca_dev->dev, sd->sensor);
@@ -6962,6 +6974,24 @@
 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->brightness;
+	return 0;
+}
+
 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -7163,9 +7193,7 @@
 	{USB_DEVICE(0x046d, 0x08aa)},
 	{USB_DEVICE(0x046d, 0x08ac)},
 	{USB_DEVICE(0x046d, 0x08ad)},
-#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE
 	{USB_DEVICE(0x046d, 0x08ae)},
-#endif
 	{USB_DEVICE(0x046d, 0x08af)},
 	{USB_DEVICE(0x046d, 0x08b9)},
 	{USB_DEVICE(0x046d, 0x08d7)},
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index 830d47b..0cae5b8 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -286,6 +286,8 @@
 		goto error;
 	}
 
+	dev->workqueue = 0;
+
 	/* register v4l2_device early so it can be used for printks */
 	if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
 		err("v4l2_device_register failed");
@@ -380,6 +382,9 @@
 
 error:
 	if (dev) {
+		/* Destroy single thread */
+		if (dev->workqueue)
+			destroy_workqueue(dev->workqueue);
 		/* this frees allocated memory */
 		hdpvr_delete(dev);
 	}
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index c338f3f..4863a21 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -394,7 +394,7 @@
 
 static int hdpvr_release(struct file *file)
 {
-	struct hdpvr_fh		*fh  = (struct hdpvr_fh *)file->private_data;
+	struct hdpvr_fh		*fh  = file->private_data;
 	struct hdpvr_device	*dev = fh->dev;
 
 	if (!dev)
@@ -518,7 +518,7 @@
 static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
 {
 	struct hdpvr_buffer *buf = NULL;
-	struct hdpvr_fh *fh = (struct hdpvr_fh *)filp->private_data;
+	struct hdpvr_fh *fh = filp->private_data;
 	struct hdpvr_device *dev = fh->dev;
 	unsigned int mask = 0;
 
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 29d4397..27ae8bb 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -47,7 +47,7 @@
 #include <linux/i2c-id.h>
 #include <linux/workqueue.h>
 
-#include <media/ir-common.h>
+#include <media/ir-core.h>
 #include <media/ir-kbd-i2c.h>
 
 /* ----------------------------------------------------------------------- */
@@ -272,11 +272,8 @@
 		return;
 	}
 
-	if (0 == rc) {
-		ir_input_nokey(ir->input, &ir->ir);
-	} else {
-		ir_input_keydown(ir->input, &ir->ir, ir_key);
-	}
+	if (rc)
+		ir_keydown(ir->input, ir_key, 0);
 }
 
 static void ir_work(struct work_struct *work)
@@ -439,10 +436,7 @@
 		 dev_name(&client->dev));
 
 	/* init + register input device */
-	err = ir_input_init(input_dev, &ir->ir, ir_type);
-	if (err < 0)
-		goto err_out_free;
-
+	ir->ir_type = ir_type;
 	input_dev->id.bustype = BUS_I2C;
 	input_dev->name       = ir->name;
 	input_dev->phys       = ir->phys;
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 1b79475..90daa6e 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -130,6 +130,9 @@
 static int ivtv_pci_latency = 1;
 
 int ivtv_debug;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int ivtv_fw_debug;
+#endif
 
 static int tunertype = -1;
 static int newi2c = -1;
@@ -141,6 +144,9 @@
 module_param_string(secam, secam, sizeof(secam), 0644);
 module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
 module_param_named(debug,ivtv_debug, int, 0644);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+module_param_named(fw_debug, ivtv_fw_debug, int, 0644);
+#endif
 module_param(ivtv_pci_latency, int, 0644);
 module_param(ivtv_yuv_mode, int, 0644);
 module_param(ivtv_yuv_threshold, int, 0644);
@@ -217,6 +223,10 @@
 		 "\t\t\t 256/0x0100: yuv\n"
 		 "\t\t\t 512/0x0200: i2c\n"
 		 "\t\t\t1024/0x0400: high volume\n");
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+MODULE_PARM_DESC(fw_debug,
+		 "Enable code for debugging firmware problems.  Default: 0\n");
+#endif
 MODULE_PARM_DESC(ivtv_pci_latency,
 		 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
 		 "\t\t\tDefault: Yes");
@@ -1425,12 +1435,16 @@
 EXPORT_SYMBOL(ivtv_vapi_result);
 EXPORT_SYMBOL(ivtv_clear_irq_mask);
 EXPORT_SYMBOL(ivtv_debug);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+EXPORT_SYMBOL(ivtv_fw_debug);
+#endif
 EXPORT_SYMBOL(ivtv_reset_ir_gpio);
 EXPORT_SYMBOL(ivtv_udma_setup);
 EXPORT_SYMBOL(ivtv_udma_unmap);
 EXPORT_SYMBOL(ivtv_udma_alloc);
 EXPORT_SYMBOL(ivtv_udma_prepare);
 EXPORT_SYMBOL(ivtv_init_on_first_open);
+EXPORT_SYMBOL(ivtv_firmware_check);
 
 module_init(module_start);
 module_exit(module_cleanup);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 5b45fd2..bd084df 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -122,6 +122,9 @@
 
 /* debugging */
 extern int ivtv_debug;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+extern int ivtv_fw_debug;
+#endif
 
 #define IVTV_DBGFLG_WARN    (1 << 0)
 #define IVTV_DBGFLG_INFO    (1 << 1)
@@ -734,6 +737,7 @@
 	struct v4l2_rect osd_rect;      /* current OSD position and size */
 	struct v4l2_rect main_rect;     /* current Main window position and size */
 	struct osd_info *osd_info;      /* ivtvfb private OSD info */
+	void (*ivtvfb_restore)(struct ivtv *itv); /* Used for a warm start */
 };
 
 static inline struct ivtv *to_ivtv(struct v4l2_device *v4l2_dev)
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 3c2cc27..a6a2cdb 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -32,6 +32,7 @@
 #include "ivtv-yuv.h"
 #include "ivtv-ioctl.h"
 #include "ivtv-cards.h"
+#include "ivtv-firmware.h"
 #include <media/v4l2-event.h>
 #include <media/saa7115.h>
 
@@ -526,6 +527,7 @@
 {
 	struct ivtv *itv = id->itv;
 	struct ivtv_stream *s = &itv->streams[id->type];
+	int rc;
 
 	if (atomic_read(&itv->decoding) == 0) {
 		if (ivtv_claim_stream(id, s->type)) {
@@ -533,7 +535,13 @@
 			IVTV_DEBUG_WARN("start decode, stream already claimed\n");
 			return -EBUSY;
 		}
-		ivtv_start_v4l2_decode_stream(s, 0);
+		rc = ivtv_start_v4l2_decode_stream(s, 0);
+		if (rc < 0) {
+			if (rc == -EAGAIN)
+				rc = ivtv_start_v4l2_decode_stream(s, 0);
+			if (rc < 0)
+				return rc;
+		}
 	}
 	if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
 		return ivtv_set_speed(itv, speed);
@@ -912,12 +920,32 @@
 
 static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
 {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	struct video_device *vdev = video_devdata(filp);
+#endif
 	struct ivtv *itv = s->itv;
 	struct ivtv_open_id *item;
 	int res = 0;
 
 	IVTV_DEBUG_FILE("open %s\n", s->name);
 
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	/* Unless ivtv_fw_debug is set, error out if firmware dead. */
+	if (ivtv_fw_debug) {
+		IVTV_WARN("Opening %s with dead firmware lockout disabled\n",
+			  video_device_node_name(vdev));
+		IVTV_WARN("Selected firmware errors will be ignored\n");
+	} else {
+#else
+	if (1) {
+#endif
+		res = ivtv_firmware_check(itv, "ivtv_serialized_open");
+		if (res == -EAGAIN)
+			res = ivtv_firmware_check(itv, "ivtv_serialized_open");
+		if (res < 0)
+			return -EIO;
+	}
+
 	if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
 		test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
 		return -EBUSY;
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index a71e8ba..d8bf2b0 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -23,7 +23,10 @@
 #include "ivtv-mailbox.h"
 #include "ivtv-firmware.h"
 #include "ivtv-yuv.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-cards.h"
 #include <linux/firmware.h>
+#include <media/saa7127.h>
 
 #define IVTV_MASK_SPU_ENABLE 		0xFFFFFFFE
 #define IVTV_MASK_VPU_ENABLE15 		0xFFFFFFF6
@@ -271,3 +274,122 @@
 	}
 	ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
 }
+
+/* Try to restart the card & restore previous settings */
+int ivtv_firmware_restart(struct ivtv *itv)
+{
+	int rc = 0;
+	v4l2_std_id std;
+	struct ivtv_open_id fh;
+	fh.itv = itv;
+
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
+		/* Display test image during restart */
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+		    SAA7127_INPUT_TYPE_TEST_IMAGE,
+		    itv->card->video_outputs[itv->active_output].video_output,
+		    0);
+
+	mutex_lock(&itv->udma.lock);
+
+	rc = ivtv_firmware_init(itv);
+	if (rc) {
+		mutex_unlock(&itv->udma.lock);
+		return rc;
+	}
+
+	/* Allow settings to reload */
+	ivtv_mailbox_cache_invalidate(itv);
+
+	/* Restore video standard */
+	std = itv->std;
+	itv->std = 0;
+	ivtv_s_std(NULL, &fh, &std);
+
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+		ivtv_init_mpeg_decoder(itv);
+
+		/* Restore framebuffer if active */
+		if (itv->ivtvfb_restore)
+			itv->ivtvfb_restore(itv);
+
+		/* Restore alpha settings */
+		ivtv_set_osd_alpha(itv);
+
+		/* Restore normal output */
+		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+		    SAA7127_INPUT_TYPE_NORMAL,
+		    itv->card->video_outputs[itv->active_output].video_output,
+		    0);
+	}
+
+	mutex_unlock(&itv->udma.lock);
+	return rc;
+}
+
+/* Check firmware running state. The checks fall through
+   allowing multiple failures to be logged. */
+int ivtv_firmware_check(struct ivtv *itv, char *where)
+{
+	int res = 0;
+
+	/* Check encoder is still running */
+	if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0) < 0) {
+		IVTV_WARN("Encoder has died : %s\n", where);
+		res = -1;
+	}
+
+	/* Also check audio. Only check if not in use & encoder is okay */
+	if (!res && !atomic_read(&itv->capturing) &&
+	    (!atomic_read(&itv->decoding) ||
+	     (atomic_read(&itv->decoding) < 2 && test_bit(IVTV_F_I_DEC_YUV,
+							     &itv->i_flags)))) {
+
+		if (ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12) < 0) {
+			IVTV_WARN("Audio has died (Encoder OK) : %s\n", where);
+			res = -2;
+		}
+	}
+
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+		/* Second audio check. Skip if audio already failed */
+		if (res != -2 && read_dec(0x100) != read_dec(0x104)) {
+			/* Wait & try again to be certain. */
+			ivtv_msleep_timeout(14, 0);
+			if (read_dec(0x100) != read_dec(0x104)) {
+				IVTV_WARN("Audio has died (Decoder) : %s\n",
+					  where);
+				res = -1;
+			}
+		}
+
+		/* Check decoder is still running */
+		if (ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0) < 0) {
+			IVTV_WARN("Decoder has died : %s\n", where);
+			res = -1;
+		}
+	}
+
+	/* If something failed & currently idle, try to reload */
+	if (res && !atomic_read(&itv->capturing) &&
+						!atomic_read(&itv->decoding)) {
+		IVTV_INFO("Detected in %s that firmware had failed - "
+			  "Reloading\n", where);
+		res = ivtv_firmware_restart(itv);
+		/*
+		 * Even if restarted ok, still signal a problem had occured.
+		 * The caller can come through this function again to check
+		 * if things are really ok after the restart.
+		 */
+		if (!res) {
+			IVTV_INFO("Firmware restart okay\n");
+			res = -EAGAIN;
+		} else {
+			IVTV_INFO("Firmware restart failed\n");
+		}
+	} else if (res) {
+		res = -EIO;
+	}
+
+	return res;
+}
diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h
index 041ba94..52bb4e5 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.h
+++ b/drivers/media/video/ivtv/ivtv-firmware.h
@@ -26,5 +26,6 @@
 void ivtv_firmware_versions(struct ivtv *itv);
 void ivtv_halt_firmware(struct ivtv *itv);
 void ivtv_init_mpeg_decoder(struct ivtv *itv);
+int ivtv_firmware_check(struct ivtv *itv, char *where);
 
 #endif
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index 84577f6..e3ce967 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -377,3 +377,11 @@
 	for (i = 0; i < argc; i++, p++)
 		data[i] = readl(p);
 }
+
+/* Wipe api cache */
+void ivtv_mailbox_cache_invalidate(struct ivtv *itv)
+{
+	int i;
+	for (i = 0; i < 256; i++)
+		itv->api_cache[i].last_jiffies = 0;
+}
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h
index 8247662..2c834d2 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.h
+++ b/drivers/media/video/ivtv/ivtv-mailbox.h
@@ -30,5 +30,6 @@
 int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
 int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
 int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
+void ivtv_mailbox_cache_invalidate(struct ivtv *itv);
 
 #endif
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index a937e2f..55df419 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -42,6 +42,7 @@
 #include "ivtv-yuv.h"
 #include "ivtv-cards.h"
 #include "ivtv-streams.h"
+#include "ivtv-firmware.h"
 #include <media/v4l2-event.h>
 
 static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
@@ -674,12 +675,14 @@
 	/* Decoder sometimes dies here, so wait a moment */
 	ivtv_msleep_timeout(10, 0);
 
-	return 0;
+	/* Known failure point for firmware, so check */
+	return ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream");
 }
 
 int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
 {
 	struct ivtv *itv = s->itv;
+	int rc;
 
 	if (s->vdev == NULL)
 		return -EINVAL;
@@ -689,7 +692,11 @@
 
 	IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
 
-	ivtv_setup_v4l2_decode_stream(s);
+	rc = ivtv_setup_v4l2_decode_stream(s);
+	if (rc < 0) {
+		clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+		return rc;
+	}
 
 	/* set dma size to 65536 bytes */
 	ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
index b530dec..b67a404 100644
--- a/drivers/media/video/ivtv/ivtv-version.h
+++ b/drivers/media/video/ivtv/ivtv-version.h
@@ -23,7 +23,7 @@
 #define IVTV_DRIVER_NAME "ivtv"
 #define IVTV_DRIVER_VERSION_MAJOR 1
 #define IVTV_DRIVER_VERSION_MINOR 4
-#define IVTV_DRIVER_VERSION_PATCHLEVEL 1
+#define IVTV_DRIVER_VERSION_PATCHLEVEL 2
 
 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
 #define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 9ff3425..be03a71 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -53,6 +53,7 @@
 #include "ivtv-i2c.h"
 #include "ivtv-udma.h"
 #include "ivtv-mailbox.h"
+#include "ivtv-firmware.h"
 
 /* card parameters */
 static int ivtvfb_card_id = -1;
@@ -178,6 +179,12 @@
 	struct fb_info ivtvfb_info;
 	struct fb_var_screeninfo ivtvfb_defined;
 	struct fb_fix_screeninfo ivtvfb_fix;
+
+	/* Used for a warm start */
+	struct fb_var_screeninfo fbvar_cur;
+	int blank_cur;
+	u32 palette_cur[256];
+	u32 pan_cur;
 };
 
 struct ivtv_osd_coords {
@@ -199,6 +206,7 @@
 	u32 data[CX2341X_MBOX_MAX_DATA];
 	int rc;
 
+	ivtv_firmware_check(itv, "ivtvfb_get_framebuffer");
 	rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
 	*fbbase = data[0];
 	*fblength = data[1];
@@ -581,8 +589,10 @@
 	ivtv_window.height = var->yres;
 
 	/* Minimum margin cannot be 0, as X won't allow such a mode */
-	if (!var->upper_margin) var->upper_margin++;
-	if (!var->left_margin) var->left_margin++;
+	if (!var->upper_margin)
+		var->upper_margin++;
+	if (!var->left_margin)
+		var->left_margin++;
 	ivtv_window.top = var->upper_margin - 1;
 	ivtv_window.left = var->left_margin - 1;
 
@@ -595,6 +605,9 @@
 	/* Force update of yuv registers */
 	itv->yuv_info.yuv_forced_update = 1;
 
+	/* Keep a copy of these settings */
+	memcpy(&oi->fbvar_cur, var, sizeof(oi->fbvar_cur));
+
 	IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
 		      var->xres, var->yres,
 		      var->xres_virtual, var->yres_virtual,
@@ -829,6 +842,8 @@
 	itv->yuv_info.osd_y_pan = var->yoffset;
 	/* Force update of yuv registers */
 	itv->yuv_info.yuv_forced_update = 1;
+	/* Remember this value */
+	itv->osd_info->pan_cur = osd_pan_index;
 	return 0;
 }
 
@@ -842,6 +857,7 @@
 	rc = ivtvfb_set_var(itv, &info->var);
 	ivtvfb_pan_display(&info->var, info);
 	ivtvfb_get_fix(itv, &info->fix);
+	ivtv_firmware_check(itv, "ivtvfb_set_par");
 	return rc;
 }
 
@@ -859,6 +875,7 @@
 	if (info->var.bits_per_pixel <= 8) {
 		write_reg(regno, 0x02a30);
 		write_reg(color, 0x02a34);
+		itv->osd_info->palette_cur[regno] = color;
 		return 0;
 	}
 	if (regno >= 16)
@@ -911,6 +928,7 @@
 		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
 		break;
 	}
+	itv->osd_info->blank_cur = blank_mode;
 	return 0;
 }
 
@@ -929,6 +947,21 @@
 	.fb_blank       = ivtvfb_blank,
 };
 
+/* Restore hardware after firmware restart */
+static void ivtvfb_restore(struct ivtv *itv)
+{
+	struct osd_info *oi = itv->osd_info;
+	int i;
+
+	ivtvfb_set_var(itv, &oi->fbvar_cur);
+	ivtvfb_blank(oi->blank_cur, &oi->ivtvfb_info);
+	for (i = 0; i < 256; i++) {
+		write_reg(i, 0x02a30);
+		write_reg(oi->palette_cur[i], 0x02a34);
+	}
+	write_reg(oi->pan_cur, 0x02a0c);
+}
+
 /* Initialization */
 
 
@@ -1192,6 +1225,9 @@
 	/* Enable the osd */
 	ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
 
+	/* Enable restart */
+	itv->ivtvfb_restore = ivtvfb_restore;
+
 	/* Allocate DMA */
 	ivtv_udma_alloc(itv);
 	return 0;
@@ -1203,7 +1239,7 @@
 	struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
 	struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
 
-	if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
 		if (ivtvfb_init_card(itv) == 0) {
 			IVTVFB_INFO("Framebuffer registered on %s\n",
 					itv->v4l2_dev.name);
@@ -1219,13 +1255,14 @@
 	struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
 	struct osd_info *oi = itv->osd_info;
 
-	if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
 		if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
 			IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n",
 				       itv->instance);
 			return 0;
 		}
 		IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
+		itv->ivtvfb_restore = NULL;
 		ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info);
 		ivtvfb_release_buffers(itv);
 		itv->osd_video_pbase = 0;
diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c
index 10ddecc..4525335 100644
--- a/drivers/media/video/mem2mem_testdev.c
+++ b/drivers/media/video/mem2mem_testdev.c
@@ -903,14 +903,14 @@
 static unsigned int m2mtest_poll(struct file *file,
 				 struct poll_table_struct *wait)
 {
-	struct m2mtest_ctx *ctx = (struct m2mtest_ctx *)file->private_data;
+	struct m2mtest_ctx *ctx = file->private_data;
 
 	return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
 }
 
 static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct m2mtest_ctx *ctx = (struct m2mtest_ctx *)file->private_data;
+	struct m2mtest_ctx *ctx = file->private_data;
 
 	return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
 }
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index fbd0fc7..31cc3d0 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -143,10 +143,10 @@
 }
 
 static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
-	{V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG},
-	{V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG},
-	{V4L2_MBUS_FMT_YUYV8_2X8_BE, V4L2_COLORSPACE_JPEG},
-	{V4L2_MBUS_FMT_YVYU8_2X8_BE, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG},
 	{V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
 	{V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
 	{V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
@@ -505,22 +505,22 @@
 	case V4L2_MBUS_FMT_RGB565_2X8_LE:
 		ret = mt9m111_setfmt_rgb565(client);
 		break;
-	case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+	case V4L2_MBUS_FMT_UYVY8_2X8:
 		mt9m111->swap_yuv_y_chromas = 0;
 		mt9m111->swap_yuv_cb_cr = 0;
 		ret = mt9m111_setfmt_yuv(client);
 		break;
-	case V4L2_MBUS_FMT_YVYU8_2X8_BE:
+	case V4L2_MBUS_FMT_VYUY8_2X8:
 		mt9m111->swap_yuv_y_chromas = 0;
 		mt9m111->swap_yuv_cb_cr = 1;
 		ret = mt9m111_setfmt_yuv(client);
 		break;
-	case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+	case V4L2_MBUS_FMT_YUYV8_2X8:
 		mt9m111->swap_yuv_y_chromas = 1;
 		mt9m111->swap_yuv_cb_cr = 0;
 		ret = mt9m111_setfmt_yuv(client);
 		break;
-	case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+	case V4L2_MBUS_FMT_YVYU8_2X8:
 		mt9m111->swap_yuv_y_chromas = 1;
 		mt9m111->swap_yuv_cb_cr = 1;
 		ret = mt9m111_setfmt_yuv(client);
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c
index e4bf1db..8ec47e4 100644
--- a/drivers/media/video/mt9t112.c
+++ b/drivers/media/video/mt9t112.c
@@ -121,22 +121,22 @@
 
 static const struct mt9t112_format mt9t112_cfmts[] = {
 	{
-		.code		= V4L2_MBUS_FMT_YUYV8_2X8_BE,
+		.code		= V4L2_MBUS_FMT_UYVY8_2X8,
 		.colorspace	= V4L2_COLORSPACE_JPEG,
 		.fmt		= 1,
 		.order		= 0,
 	}, {
-		.code		= V4L2_MBUS_FMT_YVYU8_2X8_BE,
+		.code		= V4L2_MBUS_FMT_VYUY8_2X8,
 		.colorspace	= V4L2_COLORSPACE_JPEG,
 		.fmt		= 1,
 		.order		= 1,
 	}, {
-		.code		= V4L2_MBUS_FMT_YUYV8_2X8_LE,
+		.code		= V4L2_MBUS_FMT_YUYV8_2X8,
 		.colorspace	= V4L2_COLORSPACE_JPEG,
 		.fmt		= 1,
 		.order		= 2,
 	}, {
-		.code		= V4L2_MBUS_FMT_YVYU8_2X8_LE,
+		.code		= V4L2_MBUS_FMT_YVYU8_2X8,
 		.colorspace	= V4L2_COLORSPACE_JPEG,
 		.fmt		= 1,
 		.order		= 3,
@@ -972,7 +972,7 @@
 	struct v4l2_rect *rect = &a->c;
 
 	return mt9t112_set_params(client, rect->width, rect->height,
-				 V4L2_MBUS_FMT_YUYV8_2X8_BE);
+				 V4L2_MBUS_FMT_UYVY8_2X8);
 }
 
 static int mt9t112_g_fmt(struct v4l2_subdev *sd,
@@ -983,7 +983,7 @@
 
 	if (!priv->format) {
 		int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT,
-					     V4L2_MBUS_FMT_YUYV8_2X8_BE);
+					     V4L2_MBUS_FMT_UYVY8_2X8);
 		if (ret < 0)
 			return ret;
 	}
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index 929073e..4ed51b1 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -2545,19 +2545,11 @@
 			/* set the update mode */
 			if (def_display->caps &
 					OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
-				if (dssdrv->enable_te)
-					dssdrv->enable_te(def_display, 1);
-				if (dssdrv->set_update_mode)
-					dssdrv->set_update_mode(def_display,
-							OMAP_DSS_UPDATE_AUTO);
-#else	/* MANUAL_UPDATE */
 				if (dssdrv->enable_te)
 					dssdrv->enable_te(def_display, 0);
 				if (dssdrv->set_update_mode)
 					dssdrv->set_update_mode(def_display,
 							OMAP_DSS_UPDATE_MANUAL);
-#endif
 			} else {
 				if (dssdrv->set_update_mode)
 					dssdrv->set_update_mode(def_display,
diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c
index f85b2ed..926a5aa 100644
--- a/drivers/media/video/omap24xxcam.c
+++ b/drivers/media/video/omap24xxcam.c
@@ -426,7 +426,7 @@
 			     dma->direction);
 		dma->direction = DMA_NONE;
 	} else {
-		videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
+		videobuf_dma_unmap(vbq->dev, videobuf_to_dma(vb));
 		videobuf_dma_free(videobuf_to_dma(vb));
 	}
 
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
deleted file mode 100644
index a109120..0000000
--- a/drivers/media/video/ov511.c
+++ /dev/null
@@ -1,5995 +0,0 @@
-/*
- * OmniVision OV511 Camera-to-USB Bridge Driver
- *
- * Copyright (c) 1999-2003 Mark W. McClelland
- * Original decompression code Copyright 1998-2000 OmniVision Technologies
- * Many improvements by Bret Wallach <bwallac1@san.rr.com>
- * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
- * Snapshot code by Kevin Moore
- * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
- * Changes by Claudio Matsuoka <claudio@conectiva.com>
- * Original SAA7111A code by Dave Perks <dperks@ibm.net>
- * URB error messages from pwc driver by Nemosoft
- * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
- * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others
- *
- * Based on the Linux CPiA driver written by Peter Pregler,
- * Scott J. Bertin and Johannes Erdfelt.
- *
- * Please see the file: Documentation/usb/ov511.txt
- * and the website at:  http://alpha.dyndns.org/ov511
- * for more info.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <linux/pagemap.h>
-#include <asm/processor.h>
-#include <linux/mm.h>
-#include <linux/device.h>
-
-#if defined (__i386__)
-	#include <asm/cpufeature.h>
-#endif
-
-#include "ov511.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.64 for Linux 2.5"
-#define EMAIL "mark@alpha.dyndns.org"
-#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
-& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
-<cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
-#define DRIVER_DESC "ov511 USB Camera Driver"
-
-#define OV511_I2C_RETRIES 3
-#define ENABLE_Y_QUANTABLE 1
-#define ENABLE_UV_QUANTABLE 1
-
-#define OV511_MAX_UNIT_VIDEO 16
-
-/* Pixel count * bytes per YUV420 pixel (1.5) */
-#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2)
-
-#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval))
-
-/* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */
-#define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024)
-
-#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
-
-/**********************************************************************
- * Module Parameters
- * (See ov511.txt for detailed descriptions of these)
- **********************************************************************/
-
-/* These variables (and all static globals) default to zero */
-static int autobright		= 1;
-static int autogain		= 1;
-static int autoexp		= 1;
-static int debug;
-static int snapshot;
-static int cams			= 1;
-static int compress;
-static int testpat;
-static int dumppix;
-static int led 			= 1;
-static int dump_bridge;
-static int dump_sensor;
-static int printph;
-static int phy			= 0x1f;
-static int phuv			= 0x05;
-static int pvy			= 0x06;
-static int pvuv			= 0x06;
-static int qhy			= 0x14;
-static int qhuv			= 0x03;
-static int qvy			= 0x04;
-static int qvuv			= 0x04;
-static int lightfreq;
-static int bandingfilter;
-static int clockdiv		= -1;
-static int packetsize		= -1;
-static int framedrop		= -1;
-static int fastset;
-static int force_palette;
-static int backlight;
-/* Bitmask marking allocated devices from 0 to OV511_MAX_UNIT_VIDEO */
-static unsigned long ov511_devused;
-static int unit_video[OV511_MAX_UNIT_VIDEO];
-static int remove_zeros;
-static int mirror;
-static int ov518_color;
-
-module_param(autobright, int, 0);
-MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
-module_param(autogain, int, 0);
-MODULE_PARM_DESC(autogain, "Sensor automatically changes gain");
-module_param(autoexp, int, 0);
-MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure");
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug,
-  "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max");
-module_param(snapshot, int, 0);
-MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
-module_param(cams, int, 0);
-MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
-module_param(compress, int, 0);
-MODULE_PARM_DESC(compress, "Turn on compression");
-module_param(testpat, int, 0);
-MODULE_PARM_DESC(testpat,
-  "Replace image with vertical bar testpattern (only partially working)");
-module_param(dumppix, int, 0);
-MODULE_PARM_DESC(dumppix, "Dump raw pixel data");
-module_param(led, int, 0);
-MODULE_PARM_DESC(led,
-  "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)");
-module_param(dump_bridge, int, 0);
-MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers");
-module_param(dump_sensor, int, 0);
-MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers");
-module_param(printph, int, 0);
-MODULE_PARM_DESC(printph, "Print frame start/end headers");
-module_param(phy, int, 0);
-MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)");
-module_param(phuv, int, 0);
-MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)");
-module_param(pvy, int, 0);
-MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)");
-module_param(pvuv, int, 0);
-MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)");
-module_param(qhy, int, 0);
-MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)");
-module_param(qhuv, int, 0);
-MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)");
-module_param(qvy, int, 0);
-MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)");
-module_param(qvuv, int, 0);
-MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)");
-module_param(lightfreq, int, 0);
-MODULE_PARM_DESC(lightfreq,
-  "Light frequency. Set to 50 or 60 Hz, or zero for default settings");
-module_param(bandingfilter, int, 0);
-MODULE_PARM_DESC(bandingfilter,
-  "Enable banding filter (to reduce effects of fluorescent lighting)");
-module_param(clockdiv, int, 0);
-MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value");
-module_param(packetsize, int, 0);
-MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size");
-module_param(framedrop, int, 0);
-MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting");
-module_param(fastset, int, 0);
-MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately");
-module_param(force_palette, int, 0);
-MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
-module_param(backlight, int, 0);
-MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
-static unsigned int num_uv;
-module_param_array(unit_video, int, &num_uv, 0);
-MODULE_PARM_DESC(unit_video,
-  "Force use of specific minor number(s). 0 is not allowed.");
-module_param(remove_zeros, int, 0);
-MODULE_PARM_DESC(remove_zeros,
-  "Remove zero-padding from uncompressed incoming data");
-module_param(mirror, int, 0);
-MODULE_PARM_DESC(mirror, "Reverse image horizontally");
-module_param(ov518_color, int, 0);
-MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)");
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-/**********************************************************************
- * Miscellaneous Globals
- **********************************************************************/
-
-static struct usb_driver ov511_driver;
-
-/* Number of times to retry a failed I2C transaction. Increase this if you
- * are getting "Failed to read sensor ID..." */
-static const int i2c_detect_tries = 5;
-
-static struct usb_device_id device_table [] = {
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
-	{ USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
-	{ }  /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, device_table);
-
-static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
-static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
-static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
-static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
-
-/**********************************************************************
- * Symbolic Names
- **********************************************************************/
-
-/* Known OV511-based cameras */
-static struct symbolic_list camlist[] = {
-	{   0, "Generic Camera (no ID)" },
-	{   1, "Mustek WCam 3X" },
-	{   3, "D-Link DSB-C300" },
-	{   4, "Generic OV511/OV7610" },
-	{   5, "Puretek PT-6007" },
-	{   6, "Lifeview USB Life TV (NTSC)" },
-	{  21, "Creative Labs WebCam 3" },
-	{  22, "Lifeview USB Life TV (PAL D/K+B/G)" },
-	{  36, "Koala-Cam" },
-	{  38, "Lifeview USB Life TV (PAL)" },
-	{  41, "Samsung Anycam MPC-M10" },
-	{  43, "Mtekvision Zeca MV402" },
-	{  46, "Suma eON" },
-	{  70, "Lifeview USB Life TV (PAL/SECAM)" },
-	{ 100, "Lifeview RoboCam" },
-	{ 102, "AverMedia InterCam Elite" },
-	{ 112, "MediaForte MV300" },	/* or OV7110 evaluation kit */
-	{ 134, "Ezonics EZCam II" },
-	{ 192, "Webeye 2000B" },
-	{ 253, "Alpha Vision Tech. AlphaCam SE" },
-	{  -1, NULL }
-};
-
-/* Video4Linux1 Palettes */
-static struct symbolic_list v4l1_plist[] = {
-	{ VIDEO_PALETTE_GREY,	"GREY" },
-	{ VIDEO_PALETTE_HI240,	"HI240" },
-	{ VIDEO_PALETTE_RGB565,	"RGB565" },
-	{ VIDEO_PALETTE_RGB24,	"RGB24" },
-	{ VIDEO_PALETTE_RGB32,	"RGB32" },
-	{ VIDEO_PALETTE_RGB555,	"RGB555" },
-	{ VIDEO_PALETTE_YUV422,	"YUV422" },
-	{ VIDEO_PALETTE_YUYV,	"YUYV" },
-	{ VIDEO_PALETTE_UYVY,	"UYVY" },
-	{ VIDEO_PALETTE_YUV420,	"YUV420" },
-	{ VIDEO_PALETTE_YUV411,	"YUV411" },
-	{ VIDEO_PALETTE_RAW,	"RAW" },
-	{ VIDEO_PALETTE_YUV422P,"YUV422P" },
-	{ VIDEO_PALETTE_YUV411P,"YUV411P" },
-	{ VIDEO_PALETTE_YUV420P,"YUV420P" },
-	{ VIDEO_PALETTE_YUV410P,"YUV410P" },
-	{ -1, NULL }
-};
-
-static struct symbolic_list brglist[] = {
-	{ BRG_OV511,		"OV511" },
-	{ BRG_OV511PLUS,	"OV511+" },
-	{ BRG_OV518,		"OV518" },
-	{ BRG_OV518PLUS,	"OV518+" },
-	{ -1, NULL }
-};
-
-static struct symbolic_list senlist[] = {
-	{ SEN_OV76BE,	"OV76BE" },
-	{ SEN_OV7610,	"OV7610" },
-	{ SEN_OV7620,	"OV7620" },
-	{ SEN_OV7620AE,	"OV7620AE" },
-	{ SEN_OV6620,	"OV6620" },
-	{ SEN_OV6630,	"OV6630" },
-	{ SEN_OV6630AE,	"OV6630AE" },
-	{ SEN_OV6630AF,	"OV6630AF" },
-	{ SEN_OV8600,	"OV8600" },
-	{ SEN_KS0127,	"KS0127" },
-	{ SEN_KS0127B,	"KS0127B" },
-	{ SEN_SAA7111A,	"SAA7111A" },
-	{ -1, NULL }
-};
-
-/* URB error codes: */
-static struct symbolic_list urb_errlist[] = {
-	{ -ENOSR,	"Buffer error (overrun)" },
-	{ -EPIPE,	"Stalled (device not responding)" },
-	{ -EOVERFLOW,	"Babble (device sends too much data)" },
-	{ -EPROTO,	"Bit-stuff error (bad cable?)" },
-	{ -EILSEQ,	"CRC/Timeout (bad cable?)" },
-	{ -ETIME,	"Device does not respond to token" },
-	{ -ETIMEDOUT,	"Device does not respond to command" },
-	{ -1, NULL }
-};
-
-/**********************************************************************
- * Memory management
- **********************************************************************/
-static void *
-rvmalloc(unsigned long size)
-{
-	void *mem;
-	unsigned long adr;
-
-	size = PAGE_ALIGN(size);
-	mem = vmalloc_32(size);
-	if (!mem)
-		return NULL;
-
-	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-	adr = (unsigned long) mem;
-	while (size > 0) {
-		SetPageReserved(vmalloc_to_page((void *)adr));
-		adr += PAGE_SIZE;
-		size -= PAGE_SIZE;
-	}
-
-	return mem;
-}
-
-static void
-rvfree(void *mem, unsigned long size)
-{
-	unsigned long adr;
-
-	if (!mem)
-		return;
-
-	adr = (unsigned long) mem;
-	while ((long) size > 0) {
-		ClearPageReserved(vmalloc_to_page((void *)adr));
-		adr += PAGE_SIZE;
-		size -= PAGE_SIZE;
-	}
-	vfree(mem);
-}
-
-/**********************************************************************
- *
- * Register I/O
- *
- **********************************************************************/
-
-/* Write an OV51x register */
-static int
-reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
-{
-	int rc;
-
-	PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-	mutex_lock(&ov->cbuf_lock);
-	ov->cbuf[0] = value;
-	rc = usb_control_msg(ov->dev,
-			     usb_sndctrlpipe(ov->dev, 0),
-			     (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
-			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			     0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-	mutex_unlock(&ov->cbuf_lock);
-
-	if (rc < 0)
-		err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
-
-	return rc;
-}
-
-/* Read from an OV51x register */
-/* returns: negative is error, pos or zero is data */
-static int
-reg_r(struct usb_ov511 *ov, unsigned char reg)
-{
-	int rc;
-
-	mutex_lock(&ov->cbuf_lock);
-	rc = usb_control_msg(ov->dev,
-			     usb_rcvctrlpipe(ov->dev, 0),
-			     (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
-			     USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			     0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-
-	if (rc < 0) {
-		err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
-	} else {
-		rc = ov->cbuf[0];
-		PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
-	}
-
-	mutex_unlock(&ov->cbuf_lock);
-
-	return rc;
-}
-
-/*
- * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-static int
-reg_w_mask(struct usb_ov511 *ov,
-	   unsigned char reg,
-	   unsigned char value,
-	   unsigned char mask)
-{
-	int ret;
-	unsigned char oldval, newval;
-
-	ret = reg_r(ov, reg);
-	if (ret < 0)
-		return ret;
-
-	oldval = (unsigned char) ret;
-	oldval &= (~mask);		/* Clear the masked bits */
-	value &= mask;			/* Enforce mask on value */
-	newval = oldval | value;	/* Set the desired bits */
-
-	return (reg_w(ov, reg, newval));
-}
-
-/*
- * Writes multiple (n) byte value to a single register. Only valid with certain
- * registers (0x30 and 0xc4 - 0xce).
- */
-static int
-ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
-{
-	int rc;
-
-	PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
-
-	mutex_lock(&ov->cbuf_lock);
-
-	*((__le32 *)ov->cbuf) = __cpu_to_le32(val);
-
-	rc = usb_control_msg(ov->dev,
-			     usb_sndctrlpipe(ov->dev, 0),
-			     1 /* REG_IO */,
-			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			     0, (__u16)reg, ov->cbuf, n, 1000);
-	mutex_unlock(&ov->cbuf_lock);
-
-	if (rc < 0)
-		err("reg write multiple: error %d: %s", rc,
-		    symbolic(urb_errlist, rc));
-
-	return rc;
-}
-
-static int
-ov511_upload_quan_tables(struct usb_ov511 *ov)
-{
-	unsigned char *pYTable = yQuanTable511;
-	unsigned char *pUVTable = uvQuanTable511;
-	unsigned char val0, val1;
-	int i, rc, reg = R511_COMP_LUT_BEGIN;
-
-	PDEBUG(4, "Uploading quantization tables");
-
-	for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) {
-		if (ENABLE_Y_QUANTABLE)	{
-			val0 = *pYTable++;
-			val1 = *pYTable++;
-			val0 &= 0x0f;
-			val1 &= 0x0f;
-			val0 |= val1 << 4;
-			rc = reg_w(ov, reg, val0);
-			if (rc < 0)
-				return rc;
-		}
-
-		if (ENABLE_UV_QUANTABLE) {
-			val0 = *pUVTable++;
-			val1 = *pUVTable++;
-			val0 &= 0x0f;
-			val1 &= 0x0f;
-			val0 |= val1 << 4;
-			rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0);
-			if (rc < 0)
-				return rc;
-		}
-
-		reg++;
-	}
-
-	return 0;
-}
-
-/* OV518 quantization tables are 8x4 (instead of 8x8) */
-static int
-ov518_upload_quan_tables(struct usb_ov511 *ov)
-{
-	unsigned char *pYTable = yQuanTable518;
-	unsigned char *pUVTable = uvQuanTable518;
-	unsigned char val0, val1;
-	int i, rc, reg = R511_COMP_LUT_BEGIN;
-
-	PDEBUG(4, "Uploading quantization tables");
-
-	for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) {
-		if (ENABLE_Y_QUANTABLE) {
-			val0 = *pYTable++;
-			val1 = *pYTable++;
-			val0 &= 0x0f;
-			val1 &= 0x0f;
-			val0 |= val1 << 4;
-			rc = reg_w(ov, reg, val0);
-			if (rc < 0)
-				return rc;
-		}
-
-		if (ENABLE_UV_QUANTABLE) {
-			val0 = *pUVTable++;
-			val1 = *pUVTable++;
-			val0 &= 0x0f;
-			val1 &= 0x0f;
-			val0 |= val1 << 4;
-			rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0);
-			if (rc < 0)
-				return rc;
-		}
-
-		reg++;
-	}
-
-	return 0;
-}
-
-static int
-ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)
-{
-	int rc;
-
-	/* Setting bit 0 not allowed on 518/518Plus */
-	if (ov->bclass == BCL_OV518)
-		reset_type &= 0xfe;
-
-	PDEBUG(4, "Reset: type=0x%02X", reset_type);
-
-	rc = reg_w(ov, R51x_SYS_RESET, reset_type);
-	rc = reg_w(ov, R51x_SYS_RESET, 0);
-
-	if (rc < 0)
-		err("reset: command failed");
-
-	return rc;
-}
-
-/**********************************************************************
- *
- * Low-level I2C I/O functions
- *
- **********************************************************************/
-
-/* NOTE: Do not call this function directly!
- * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from i2c_w(). Note that this function
- * always succeeds regardless of whether the sensor is present and working.
- */
-static int
-ov518_i2c_write_internal(struct usb_ov511 *ov,
-			 unsigned char reg,
-			 unsigned char value)
-{
-	int rc;
-
-	PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-	/* Select camera register */
-	rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-	if (rc < 0)
-		return rc;
-
-	/* Write "value" to I2C data port of OV511 */
-	rc = reg_w(ov, R51x_I2C_DATA, value);
-	if (rc < 0)
-		return rc;
-
-	/* Initiate 3-byte write cycle */
-	rc = reg_w(ov, R518_I2C_CTL, 0x01);
-	if (rc < 0)
-		return rc;
-
-	return 0;
-}
-
-/* NOTE: Do not call this function directly! */
-static int
-ov511_i2c_write_internal(struct usb_ov511 *ov,
-			 unsigned char reg,
-			 unsigned char value)
-{
-	int rc, retries;
-
-	PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-	/* Three byte write cycle */
-	for (retries = OV511_I2C_RETRIES; ; ) {
-		/* Select camera register */
-		rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-		if (rc < 0)
-			break;
-
-		/* Write "value" to I2C data port of OV511 */
-		rc = reg_w(ov, R51x_I2C_DATA, value);
-		if (rc < 0)
-			break;
-
-		/* Initiate 3-byte write cycle */
-		rc = reg_w(ov, R511_I2C_CTL, 0x01);
-		if (rc < 0)
-			break;
-
-		/* Retry until idle */
-		do {
-			rc = reg_r(ov, R511_I2C_CTL);
-		} while (rc > 0 && ((rc&1) == 0));
-		if (rc < 0)
-			break;
-
-		/* Ack? */
-		if ((rc&2) == 0) {
-			rc = 0;
-			break;
-		}
-#if 0
-		/* I2C abort */
-		reg_w(ov, R511_I2C_CTL, 0x10);
-#endif
-		if (--retries < 0) {
-			err("i2c write retries exhausted");
-			rc = -1;
-			break;
-		}
-	}
-
-	return rc;
-}
-
-/* NOTE: Do not call this function directly!
- * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from i2c_r(). Note that this function
- * always succeeds regardless of whether the sensor is present and working.
- */
-static int
-ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
-{
-	int rc, value;
-
-	/* Select camera register */
-	rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-	if (rc < 0)
-		return rc;
-
-	/* Initiate 2-byte write cycle */
-	rc = reg_w(ov, R518_I2C_CTL, 0x03);
-	if (rc < 0)
-		return rc;
-
-	/* Initiate 2-byte read cycle */
-	rc = reg_w(ov, R518_I2C_CTL, 0x05);
-	if (rc < 0)
-		return rc;
-
-	value = reg_r(ov, R51x_I2C_DATA);
-
-	PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-	return value;
-}
-
-/* NOTE: Do not call this function directly!
- * returns: negative is error, pos or zero is data */
-static int
-ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
-{
-	int rc, value, retries;
-
-	/* Two byte write cycle */
-	for (retries = OV511_I2C_RETRIES; ; ) {
-		/* Select camera register */
-		rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-		if (rc < 0)
-			return rc;
-
-		/* Initiate 2-byte write cycle */
-		rc = reg_w(ov, R511_I2C_CTL, 0x03);
-		if (rc < 0)
-			return rc;
-
-		/* Retry until idle */
-		do {
-			rc = reg_r(ov, R511_I2C_CTL);
-		} while (rc > 0 && ((rc & 1) == 0));
-		if (rc < 0)
-			return rc;
-
-		if ((rc&2) == 0) /* Ack? */
-			break;
-
-		/* I2C abort */
-		reg_w(ov, R511_I2C_CTL, 0x10);
-
-		if (--retries < 0) {
-			err("i2c write retries exhausted");
-			return -1;
-		}
-	}
-
-	/* Two byte read cycle */
-	for (retries = OV511_I2C_RETRIES; ; ) {
-		/* Initiate 2-byte read cycle */
-		rc = reg_w(ov, R511_I2C_CTL, 0x05);
-		if (rc < 0)
-			return rc;
-
-		/* Retry until idle */
-		do {
-			rc = reg_r(ov, R511_I2C_CTL);
-		} while (rc > 0 && ((rc&1) == 0));
-		if (rc < 0)
-			return rc;
-
-		if ((rc&2) == 0) /* Ack? */
-			break;
-
-		/* I2C abort */
-		rc = reg_w(ov, R511_I2C_CTL, 0x10);
-		if (rc < 0)
-			return rc;
-
-		if (--retries < 0) {
-			err("i2c read retries exhausted");
-			return -1;
-		}
-	}
-
-	value = reg_r(ov, R51x_I2C_DATA);
-
-	PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-	/* This is needed to make i2c_w() work */
-	rc = reg_w(ov, R511_I2C_CTL, 0x05);
-	if (rc < 0)
-		return rc;
-
-	return value;
-}
-
-/* returns: negative is error, pos or zero is data */
-static int
-i2c_r(struct usb_ov511 *ov, unsigned char reg)
-{
-	int rc;
-
-	mutex_lock(&ov->i2c_lock);
-
-	if (ov->bclass == BCL_OV518)
-		rc = ov518_i2c_read_internal(ov, reg);
-	else
-		rc = ov511_i2c_read_internal(ov, reg);
-
-	mutex_unlock(&ov->i2c_lock);
-
-	return rc;
-}
-
-static int
-i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
-{
-	int rc;
-
-	mutex_lock(&ov->i2c_lock);
-
-	if (ov->bclass == BCL_OV518)
-		rc = ov518_i2c_write_internal(ov, reg, value);
-	else
-		rc = ov511_i2c_write_internal(ov, reg, value);
-
-	mutex_unlock(&ov->i2c_lock);
-
-	return rc;
-}
-
-/* Do not call this function directly! */
-static int
-ov51x_i2c_write_mask_internal(struct usb_ov511 *ov,
-			      unsigned char reg,
-			      unsigned char value,
-			      unsigned char mask)
-{
-	int rc;
-	unsigned char oldval, newval;
-
-	if (mask == 0xff) {
-		newval = value;
-	} else {
-		if (ov->bclass == BCL_OV518)
-			rc = ov518_i2c_read_internal(ov, reg);
-		else
-			rc = ov511_i2c_read_internal(ov, reg);
-		if (rc < 0)
-			return rc;
-
-		oldval = (unsigned char) rc;
-		oldval &= (~mask);		/* Clear the masked bits */
-		value &= mask;			/* Enforce mask on value */
-		newval = oldval | value;	/* Set the desired bits */
-	}
-
-	if (ov->bclass == BCL_OV518)
-		return (ov518_i2c_write_internal(ov, reg, newval));
-	else
-		return (ov511_i2c_write_internal(ov, reg, newval));
-}
-
-/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-static int
-i2c_w_mask(struct usb_ov511 *ov,
-	   unsigned char reg,
-	   unsigned char value,
-	   unsigned char mask)
-{
-	int rc;
-
-	mutex_lock(&ov->i2c_lock);
-	rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-	mutex_unlock(&ov->i2c_lock);
-
-	return rc;
-}
-
-/* Set the read and write slave IDs. The "slave" argument is the write slave,
- * and the read slave will be set to (slave + 1). ov->i2c_lock should be held
- * when calling this. This should not be called from outside the i2c I/O
- * functions.
- */
-static int
-i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave)
-{
-	int rc;
-
-	rc = reg_w(ov, R51x_I2C_W_SID, slave);
-	if (rc < 0)
-		return rc;
-
-	rc = reg_w(ov, R51x_I2C_R_SID, slave + 1);
-	if (rc < 0)
-		return rc;
-
-	return 0;
-}
-
-/* Write to a specific I2C slave ID and register, using the specified mask */
-static int
-i2c_w_slave(struct usb_ov511 *ov,
-	    unsigned char slave,
-	    unsigned char reg,
-	    unsigned char value,
-	    unsigned char mask)
-{
-	int rc = 0;
-
-	mutex_lock(&ov->i2c_lock);
-
-	/* Set new slave IDs */
-	rc = i2c_set_slave_internal(ov, slave);
-	if (rc < 0)
-		goto out;
-
-	rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-
-out:
-	/* Restore primary IDs */
-	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
-		err("Couldn't restore primary I2C slave");
-
-	mutex_unlock(&ov->i2c_lock);
-	return rc;
-}
-
-/* Read from a specific I2C slave ID and register */
-static int
-i2c_r_slave(struct usb_ov511 *ov,
-	    unsigned char slave,
-	    unsigned char reg)
-{
-	int rc;
-
-	mutex_lock(&ov->i2c_lock);
-
-	/* Set new slave IDs */
-	rc = i2c_set_slave_internal(ov, slave);
-	if (rc < 0)
-		goto out;
-
-	if (ov->bclass == BCL_OV518)
-		rc = ov518_i2c_read_internal(ov, reg);
-	else
-		rc = ov511_i2c_read_internal(ov, reg);
-
-out:
-	/* Restore primary IDs */
-	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
-		err("Couldn't restore primary I2C slave");
-
-	mutex_unlock(&ov->i2c_lock);
-	return rc;
-}
-
-/* Sets I2C read and write slave IDs. Returns <0 for error */
-static int
-ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
-{
-	int rc;
-
-	mutex_lock(&ov->i2c_lock);
-
-	rc = i2c_set_slave_internal(ov, sid);
-	if (rc < 0)
-		goto out;
-
-	// FIXME: Is this actually necessary?
-	rc = ov51x_reset(ov, OV511_RESET_NOREGS);
-out:
-	mutex_unlock(&ov->i2c_lock);
-	return rc;
-}
-
-static int
-write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
-{
-	int rc;
-
-	while (pRegvals->bus != OV511_DONE_BUS) {
-		if (pRegvals->bus == OV511_REG_BUS) {
-			if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-				return rc;
-		} else if (pRegvals->bus == OV511_I2C_BUS) {
-			if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-				return rc;
-		} else {
-			err("Bad regval array");
-			return -1;
-		}
-		pRegvals++;
-	}
-	return 0;
-}
-
-#ifdef OV511_DEBUG
-static void
-dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
-{
-	int i, rc;
-
-	for (i = reg1; i <= regn; i++) {
-		rc = i2c_r(ov, i);
-		dev_info(&ov->dev->dev, "Sensor[0x%02X] = 0x%02X\n", i, rc);
-	}
-}
-
-static void
-dump_i2c_regs(struct usb_ov511 *ov)
-{
-	dev_info(&ov->dev->dev, "I2C REGS\n");
-	dump_i2c_range(ov, 0x00, 0x7C);
-}
-
-static void
-dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
-{
-	int i, rc;
-
-	for (i = reg1; i <= regn; i++) {
-		rc = reg_r(ov, i);
-		dev_info(&ov->dev->dev, "OV511[0x%02X] = 0x%02X\n", i, rc);
-	}
-}
-
-static void
-ov511_dump_regs(struct usb_ov511 *ov)
-{
-	dev_info(&ov->dev->dev, "CAMERA INTERFACE REGS\n");
-	dump_reg_range(ov, 0x10, 0x1f);
-	dev_info(&ov->dev->dev, "DRAM INTERFACE REGS\n");
-	dump_reg_range(ov, 0x20, 0x23);
-	dev_info(&ov->dev->dev, "ISO FIFO REGS\n");
-	dump_reg_range(ov, 0x30, 0x31);
-	dev_info(&ov->dev->dev, "PIO REGS\n");
-	dump_reg_range(ov, 0x38, 0x39);
-	dump_reg_range(ov, 0x3e, 0x3e);
-	dev_info(&ov->dev->dev, "I2C REGS\n");
-	dump_reg_range(ov, 0x40, 0x49);
-	dev_info(&ov->dev->dev, "SYSTEM CONTROL REGS\n");
-	dump_reg_range(ov, 0x50, 0x55);
-	dump_reg_range(ov, 0x5e, 0x5f);
-	dev_info(&ov->dev->dev, "OmniCE REGS\n");
-	dump_reg_range(ov, 0x70, 0x79);
-	/* NOTE: Quantization tables are not readable. You will get the value
-	 * in reg. 0x79 for every table register */
-	dump_reg_range(ov, 0x80, 0x9f);
-	dump_reg_range(ov, 0xa0, 0xbf);
-
-}
-
-static void
-ov518_dump_regs(struct usb_ov511 *ov)
-{
-	dev_info(&ov->dev->dev, "VIDEO MODE REGS\n");
-	dump_reg_range(ov, 0x20, 0x2f);
-	dev_info(&ov->dev->dev, "DATA PUMP AND SNAPSHOT REGS\n");
-	dump_reg_range(ov, 0x30, 0x3f);
-	dev_info(&ov->dev->dev, "I2C REGS\n");
-	dump_reg_range(ov, 0x40, 0x4f);
-	dev_info(&ov->dev->dev, "SYSTEM CONTROL AND VENDOR REGS\n");
-	dump_reg_range(ov, 0x50, 0x5f);
-	dev_info(&ov->dev->dev, "60 - 6F\n");
-	dump_reg_range(ov, 0x60, 0x6f);
-	dev_info(&ov->dev->dev, "70 - 7F\n");
-	dump_reg_range(ov, 0x70, 0x7f);
-	dev_info(&ov->dev->dev, "Y QUANTIZATION TABLE\n");
-	dump_reg_range(ov, 0x80, 0x8f);
-	dev_info(&ov->dev->dev, "UV QUANTIZATION TABLE\n");
-	dump_reg_range(ov, 0x90, 0x9f);
-	dev_info(&ov->dev->dev, "A0 - BF\n");
-	dump_reg_range(ov, 0xa0, 0xbf);
-	dev_info(&ov->dev->dev, "CBR\n");
-	dump_reg_range(ov, 0xc0, 0xcf);
-}
-#endif
-
-/*****************************************************************************/
-
-/* Temporarily stops OV511 from functioning. Must do this before changing
- * registers while the camera is streaming */
-static inline int
-ov51x_stop(struct usb_ov511 *ov)
-{
-	PDEBUG(4, "stopping");
-	ov->stopped = 1;
-	if (ov->bclass == BCL_OV518)
-		return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a));
-	else
-		return (reg_w(ov, R51x_SYS_RESET, 0x3d));
-}
-
-/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
- * actually stopped (for performance). */
-static inline int
-ov51x_restart(struct usb_ov511 *ov)
-{
-	if (ov->stopped) {
-		PDEBUG(4, "restarting");
-		ov->stopped = 0;
-
-		/* Reinitialize the stream */
-		if (ov->bclass == BCL_OV518)
-			reg_w(ov, 0x2f, 0x80);
-
-		return (reg_w(ov, R51x_SYS_RESET, 0x00));
-	}
-
-	return 0;
-}
-
-/* Sleeps until no frames are active. Returns !0 if got signal */
-static int
-ov51x_wait_frames_inactive(struct usb_ov511 *ov)
-{
-	return wait_event_interruptible(ov->wq, ov->curframe < 0);
-}
-
-/* Resets the hardware snapshot button */
-static void
-ov51x_clear_snapshot(struct usb_ov511 *ov)
-{
-	if (ov->bclass == BCL_OV511) {
-		reg_w(ov, R51x_SYS_SNAP, 0x00);
-		reg_w(ov, R51x_SYS_SNAP, 0x02);
-		reg_w(ov, R51x_SYS_SNAP, 0x00);
-	} else if (ov->bclass == BCL_OV518) {
-		dev_warn(&ov->dev->dev,
-			 "snapshot reset not supported yet on OV518(+)\n");
-	} else {
-		dev_err(&ov->dev->dev, "clear snap: invalid bridge type\n");
-	}
-}
-
-#if 0
-/* Checks the status of the snapshot button. Returns 1 if it was pressed since
- * it was last cleared, and zero in all other cases (including errors) */
-static int
-ov51x_check_snapshot(struct usb_ov511 *ov)
-{
-	int ret, status = 0;
-
-	if (ov->bclass == BCL_OV511) {
-		ret = reg_r(ov, R51x_SYS_SNAP);
-		if (ret < 0) {
-			dev_err(&ov->dev->dev,
-				"Error checking snspshot status (%d)\n", ret);
-		} else if (ret & 0x08) {
-			status = 1;
-		}
-	} else if (ov->bclass == BCL_OV518) {
-		dev_warn(&ov->dev->dev,
-			 "snapshot check not supported yet on OV518(+)\n");
-	} else {
-		dev_err(&ov->dev->dev, "clear snap: invalid bridge type\n");
-	}
-
-	return status;
-}
-#endif
-
-/* This does an initial reset of an OmniVision sensor and ensures that I2C
- * is synchronized. Returns <0 for failure.
- */
-static int
-init_ov_sensor(struct usb_ov511 *ov)
-{
-	int i, success;
-
-	/* Reset the sensor */
-	if (i2c_w(ov, 0x12, 0x80) < 0)
-		return -EIO;
-
-	/* Wait for it to initialize */
-	msleep(150);
-
-	for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
-		if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
-		    (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
-			success = 1;
-			continue;
-		}
-
-		/* Reset the sensor */
-		if (i2c_w(ov, 0x12, 0x80) < 0)
-			return -EIO;
-		/* Wait for it to initialize */
-		msleep(150);
-		/* Dummy read to sync I2C */
-		if (i2c_r(ov, 0x00) < 0)
-			return -EIO;
-	}
-
-	if (!success)
-		return -EIO;
-
-	PDEBUG(1, "I2C synced in %d attempt(s)", i);
-
-	return 0;
-}
-
-static int
-ov511_set_packet_size(struct usb_ov511 *ov, int size)
-{
-	int alt, mult;
-
-	if (ov51x_stop(ov) < 0)
-		return -EIO;
-
-	mult = size >> 5;
-
-	if (ov->bridge == BRG_OV511) {
-		if (size == 0)
-			alt = OV511_ALT_SIZE_0;
-		else if (size == 257)
-			alt = OV511_ALT_SIZE_257;
-		else if (size == 513)
-			alt = OV511_ALT_SIZE_513;
-		else if (size == 769)
-			alt = OV511_ALT_SIZE_769;
-		else if (size == 993)
-			alt = OV511_ALT_SIZE_993;
-		else {
-			err("Set packet size: invalid size (%d)", size);
-			return -EINVAL;
-		}
-	} else if (ov->bridge == BRG_OV511PLUS) {
-		if (size == 0)
-			alt = OV511PLUS_ALT_SIZE_0;
-		else if (size == 33)
-			alt = OV511PLUS_ALT_SIZE_33;
-		else if (size == 129)
-			alt = OV511PLUS_ALT_SIZE_129;
-		else if (size == 257)
-			alt = OV511PLUS_ALT_SIZE_257;
-		else if (size == 385)
-			alt = OV511PLUS_ALT_SIZE_385;
-		else if (size == 513)
-			alt = OV511PLUS_ALT_SIZE_513;
-		else if (size == 769)
-			alt = OV511PLUS_ALT_SIZE_769;
-		else if (size == 961)
-			alt = OV511PLUS_ALT_SIZE_961;
-		else {
-			err("Set packet size: invalid size (%d)", size);
-			return -EINVAL;
-		}
-	} else {
-		err("Set packet size: Invalid bridge type");
-		return -EINVAL;
-	}
-
-	PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt);
-
-	if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0)
-		return -EIO;
-
-	if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
-		err("Set packet size: set interface error");
-		return -EBUSY;
-	}
-
-	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-		return -EIO;
-
-	ov->packet_size = size;
-
-	if (ov51x_restart(ov) < 0)
-		return -EIO;
-
-	return 0;
-}
-
-/* Note: Unlike the OV511/OV511+, the size argument does NOT include the
- * optional packet number byte. The actual size *is* stored in ov->packet_size,
- * though. */
-static int
-ov518_set_packet_size(struct usb_ov511 *ov, int size)
-{
-	int alt;
-
-	if (ov51x_stop(ov) < 0)
-		return -EIO;
-
-	if (ov->bclass == BCL_OV518) {
-		if (size == 0)
-			alt = OV518_ALT_SIZE_0;
-		else if (size == 128)
-			alt = OV518_ALT_SIZE_128;
-		else if (size == 256)
-			alt = OV518_ALT_SIZE_256;
-		else if (size == 384)
-			alt = OV518_ALT_SIZE_384;
-		else if (size == 512)
-			alt = OV518_ALT_SIZE_512;
-		else if (size == 640)
-			alt = OV518_ALT_SIZE_640;
-		else if (size == 768)
-			alt = OV518_ALT_SIZE_768;
-		else if (size == 896)
-			alt = OV518_ALT_SIZE_896;
-		else {
-			err("Set packet size: invalid size (%d)", size);
-			return -EINVAL;
-		}
-	} else {
-		err("Set packet size: Invalid bridge type");
-		return -EINVAL;
-	}
-
-	PDEBUG(3, "%d, alt=%d", size, alt);
-
-	ov->packet_size = size;
-	if (size > 0) {
-		/* Program ISO FIFO size reg (packet number isn't included) */
-		ov518_reg_w32(ov, 0x30, size, 2);
-
-		if (ov->packet_numbering)
-			++ov->packet_size;
-	}
-
-	if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
-		err("Set packet size: set interface error");
-		return -EBUSY;
-	}
-
-	/* Initialize the stream */
-	if (reg_w(ov, 0x2f, 0x80) < 0)
-		return -EIO;
-
-	if (ov51x_restart(ov) < 0)
-		return -EIO;
-
-	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-		return -EIO;
-
-	return 0;
-}
-
-/* Upload compression params and quantization tables. Returns 0 for success. */
-static int
-ov511_init_compression(struct usb_ov511 *ov)
-{
-	int rc = 0;
-
-	if (!ov->compress_inited) {
-		reg_w(ov, 0x70, phy);
-		reg_w(ov, 0x71, phuv);
-		reg_w(ov, 0x72, pvy);
-		reg_w(ov, 0x73, pvuv);
-		reg_w(ov, 0x74, qhy);
-		reg_w(ov, 0x75, qhuv);
-		reg_w(ov, 0x76, qvy);
-		reg_w(ov, 0x77, qvuv);
-
-		if (ov511_upload_quan_tables(ov) < 0) {
-			err("Error uploading quantization tables");
-			rc = -EIO;
-			goto out;
-		}
-	}
-
-	ov->compress_inited = 1;
-out:
-	return rc;
-}
-
-/* Upload compression params and quantization tables. Returns 0 for success. */
-static int
-ov518_init_compression(struct usb_ov511 *ov)
-{
-	int rc = 0;
-
-	if (!ov->compress_inited) {
-		if (ov518_upload_quan_tables(ov) < 0) {
-			err("Error uploading quantization tables");
-			rc = -EIO;
-			goto out;
-		}
-	}
-
-	ov->compress_inited = 1;
-out:
-	return rc;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's contrast setting to "val" */
-static int
-sensor_set_contrast(struct usb_ov511 *ov, unsigned short val)
-{
-	int rc;
-
-	PDEBUG(3, "%d", val);
-
-	if (ov->stop_during_set)
-		if (ov51x_stop(ov) < 0)
-			return -EIO;
-
-	switch (ov->sensor) {
-	case SEN_OV7610:
-	case SEN_OV6620:
-	{
-		rc = i2c_w(ov, OV7610_REG_CNT, val >> 8);
-		if (rc < 0)
-			goto out;
-		break;
-	}
-	case SEN_OV6630:
-	{
-		rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f);
-		if (rc < 0)
-			goto out;
-		break;
-	}
-	case SEN_OV7620:
-	{
-		unsigned char ctab[] = {
-			0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
-			0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
-		};
-
-		/* Use Y gamma control instead. Bit 0 enables it. */
-		rc = i2c_w(ov, 0x64, ctab[val>>12]);
-		if (rc < 0)
-			goto out;
-		break;
-	}
-	case SEN_SAA7111A:
-	{
-		rc = i2c_w(ov, 0x0b, val >> 9);
-		if (rc < 0)
-			goto out;
-		break;
-	}
-	default:
-	{
-		PDEBUG(3, "Unsupported with this sensor");
-		rc = -EPERM;
-		goto out;
-	}
-	}
-
-	rc = 0;		/* Success */
-	ov->contrast = val;
-out:
-	if (ov51x_restart(ov) < 0)
-		return -EIO;
-
-	return rc;
-}
-
-/* Gets sensor's contrast setting */
-static int
-sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val)
-{
-	int rc;
-
-	switch (ov->sensor) {
-	case SEN_OV7610:
-	case SEN_OV6620:
-		rc = i2c_r(ov, OV7610_REG_CNT);
-		if (rc < 0)
-			return rc;
-		else
-			*val = rc << 8;
-		break;
-	case SEN_OV6630:
-		rc = i2c_r(ov, OV7610_REG_CNT);
-		if (rc < 0)
-			return rc;
-		else
-			*val = rc << 12;
-		break;
-	case SEN_OV7620:
-		/* Use Y gamma reg instead. Bit 0 is the enable bit. */
-		rc = i2c_r(ov, 0x64);
-		if (rc < 0)
-			return rc;
-		else
-			*val = (rc & 0xfe) << 8;
-		break;
-	case SEN_SAA7111A:
-		*val = ov->contrast;
-		break;
-	default:
-		PDEBUG(3, "Unsupported with this sensor");
-		return -EPERM;
-	}
-
-	PDEBUG(3, "%d", *val);
-	ov->contrast = *val;
-
-	return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's brightness setting to "val" */
-static int
-sensor_set_brightness(struct usb_ov511 *ov, unsigned short val)
-{
-	int rc;
-
-	PDEBUG(4, "%d", val);
-
-	if (ov->stop_during_set)
-		if (ov51x_stop(ov) < 0)
-			return -EIO;
-
-	switch (ov->sensor) {
-	case SEN_OV7610:
-	case SEN_OV76BE:
-	case SEN_OV6620:
-	case SEN_OV6630:
-		rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
-		if (rc < 0)
-			goto out;
-		break;
-	case SEN_OV7620:
-		/* 7620 doesn't like manual changes when in auto mode */
-		if (!ov->auto_brt) {
-			rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
-			if (rc < 0)
-				goto out;
-		}
-		break;
-	case SEN_SAA7111A:
-		rc = i2c_w(ov, 0x0a, val >> 8);
-		if (rc < 0)
-			goto out;
-		break;
-	default:
-		PDEBUG(3, "Unsupported with this sensor");
-		rc = -EPERM;
-		goto out;
-	}
-
-	rc = 0;		/* Success */
-	ov->brightness = val;
-out:
-	if (ov51x_restart(ov) < 0)
-		return -EIO;
-
-	return rc;
-}
-
-/* Gets sensor's brightness setting */
-static int
-sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val)
-{
-	int rc;
-
-	switch (ov->sensor) {
-	case SEN_OV7610:
-	case SEN_OV76BE:
-	case SEN_OV7620:
-	case SEN_OV6620:
-	case SEN_OV6630:
-		rc = i2c_r(ov, OV7610_REG_BRT);
-		if (rc < 0)
-			return rc;
-		else
-			*val = rc << 8;
-		break;
-	case SEN_SAA7111A:
-		*val = ov->brightness;
-		break;
-	default:
-		PDEBUG(3, "Unsupported with this sensor");
-		return -EPERM;
-	}
-
-	PDEBUG(3, "%d", *val);
-	ov->brightness = *val;
-
-	return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's saturation (color intensity) setting to "val" */
-static int
-sensor_set_saturation(struct usb_ov511 *ov, unsigned short val)
-{
-	int rc;
-
-	PDEBUG(3, "%d", val);
-
-	if (ov->stop_during_set)
-		if (ov51x_stop(ov) < 0)
-			return -EIO;
-
-	switch (ov->sensor) {
-	case SEN_OV7610:
-	case SEN_OV76BE:
-	case SEN_OV6620:
-	case SEN_OV6630:
-		rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
-		if (rc < 0)
-			goto out;
-		break;
-	case SEN_OV7620:
-//		/* Use UV gamma control instead. Bits 0 & 7 are reserved. */
-//		rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e);
-//		if (rc < 0)
-//			goto out;
-		rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
-		if (rc < 0)
-			goto out;
-		break;
-	case SEN_SAA7111A:
-		rc = i2c_w(ov, 0x0c, val >> 9);
-		if (rc < 0)
-			goto out;
-		break;
-	default:
-		PDEBUG(3, "Unsupported with this sensor");
-		rc = -EPERM;
-		goto out;
-	}
-
-	rc = 0;		/* Success */
-	ov->colour = val;
-out:
-	if (ov51x_restart(ov) < 0)
-		return -EIO;
-
-	return rc;
-}
-
-/* Gets sensor's saturation (color intensity) setting */
-static int
-sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val)
-{
-	int rc;
-
-	switch (ov->sensor) {
-	case SEN_OV7610:
-	case SEN_OV76BE:
-	case SEN_OV6620:
-	case SEN_OV6630:
-		rc = i2c_r(ov, OV7610_REG_SAT);
-		if (rc < 0)
-			return rc;
-		else
-			*val = rc << 8;
-		break;
-	case SEN_OV7620:
-//		/* Use UV gamma reg instead. Bits 0 & 7 are reserved. */
-//		rc = i2c_r(ov, 0x62);
-//		if (rc < 0)
-//			return rc;
-//		else
-//			*val = (rc & 0x7e) << 9;
-		rc = i2c_r(ov, OV7610_REG_SAT);
-		if (rc < 0)
-			return rc;
-		else
-			*val = rc << 8;
-		break;
-	case SEN_SAA7111A:
-		*val = ov->colour;
-		break;
-	default:
-		PDEBUG(3, "Unsupported with this sensor");
-		return -EPERM;
-	}
-
-	PDEBUG(3, "%d", *val);
-	ov->colour = *val;
-
-	return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's hue (red/blue balance) setting to "val" */
-static int
-sensor_set_hue(struct usb_ov511 *ov, unsigned short val)
-{
-	int rc;
-
-	PDEBUG(3, "%d", val);
-
-	if (ov->stop_during_set)
-		if (ov51x_stop(ov) < 0)
-			return -EIO;
-
-	switch (ov->sensor) {
-	case SEN_OV7610:
-	case SEN_OV6620:
-	case SEN_OV6630:
-		rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8));
-		if (rc < 0)
-			goto out;
-
-		rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8);
-		if (rc < 0)
-			goto out;
-		break;
-	case SEN_OV7620:
-// Hue control is causing problems. I will enable it once it's fixed.
-#if 0
-		rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb);
-		if (rc < 0)
-			goto out;
-
-		rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb);
-		if (rc < 0)
-			goto out;
-#endif
-		break;
-	case SEN_SAA7111A:
-		rc = i2c_w(ov, 0x0d, (val + 32768) >> 8);
-		if (rc < 0)
-			goto out;
-		break;
-	default:
-		PDEBUG(3, "Unsupported with this sensor");
-		rc = -EPERM;
-		goto out;
-	}
-
-	rc = 0;		/* Success */
-	ov->hue = val;
-out:
-	if (ov51x_restart(ov) < 0)
-		return -EIO;
-
-	return rc;
-}
-
-/* Gets sensor's hue (red/blue balance) setting */
-static int
-sensor_get_hue(struct usb_ov511 *ov, unsigned short *val)
-{
-	int rc;
-
-	switch (ov->sensor) {
-	case SEN_OV7610:
-	case SEN_OV6620:
-	case SEN_OV6630:
-		rc = i2c_r(ov, OV7610_REG_BLUE);
-		if (rc < 0)
-			return rc;
-		else
-			*val = rc << 8;
-		break;
-	case SEN_OV7620:
-		rc = i2c_r(ov, 0x7a);
-		if (rc < 0)
-			return rc;
-		else
-			*val = rc << 8;
-		break;
-	case SEN_SAA7111A:
-		*val = ov->hue;
-		break;
-	default:
-		PDEBUG(3, "Unsupported with this sensor");
-		return -EPERM;
-	}
-
-	PDEBUG(3, "%d", *val);
-	ov->hue = *val;
-
-	return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-static int
-sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p)
-{
-	int rc;
-
-	PDEBUG(4, "sensor_set_picture");
-
-	ov->whiteness = p->whiteness;
-
-	/* Don't return error if a setting is unsupported, or rest of settings
-	 * will not be performed */
-
-	rc = sensor_set_contrast(ov, p->contrast);
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	rc = sensor_set_brightness(ov, p->brightness);
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	rc = sensor_set_saturation(ov, p->colour);
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	rc = sensor_set_hue(ov, p->hue);
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	return 0;
-}
-
-static int
-sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p)
-{
-	int rc;
-
-	PDEBUG(4, "sensor_get_picture");
-
-	/* Don't return error if a setting is unsupported, or rest of settings
-	 * will not be performed */
-
-	rc = sensor_get_contrast(ov, &(p->contrast));
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	rc = sensor_get_brightness(ov, &(p->brightness));
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	rc = sensor_get_saturation(ov, &(p->colour));
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	rc = sensor_get_hue(ov, &(p->hue));
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	p->whiteness = 105 << 8;
-
-	return 0;
-}
-
-#if 0
-// FIXME: Exposure range is only 0x00-0x7f in interlace mode
-/* Sets current exposure for sensor. This only has an effect if auto-exposure
- * is off */
-static inline int
-sensor_set_exposure(struct usb_ov511 *ov, unsigned char val)
-{
-	int rc;
-
-	PDEBUG(3, "%d", val);
-
-	if (ov->stop_during_set)
-		if (ov51x_stop(ov) < 0)
-			return -EIO;
-
-	switch (ov->sensor) {
-	case SEN_OV6620:
-	case SEN_OV6630:
-	case SEN_OV7610:
-	case SEN_OV7620:
-	case SEN_OV76BE:
-	case SEN_OV8600:
-		rc = i2c_w(ov, 0x10, val);
-		if (rc < 0)
-			goto out;
-
-		break;
-	case SEN_KS0127:
-	case SEN_KS0127B:
-	case SEN_SAA7111A:
-		PDEBUG(3, "Unsupported with this sensor");
-		return -EPERM;
-	default:
-		err("Sensor not supported for set_exposure");
-		return -EINVAL;
-	}
-
-	rc = 0;		/* Success */
-	ov->exposure = val;
-out:
-	if (ov51x_restart(ov) < 0)
-		return -EIO;
-
-	return rc;
-}
-#endif
-
-/* Gets current exposure level from sensor, regardless of whether it is under
- * manual control. */
-static int
-sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val)
-{
-	int rc;
-
-	switch (ov->sensor) {
-	case SEN_OV7610:
-	case SEN_OV6620:
-	case SEN_OV6630:
-	case SEN_OV7620:
-	case SEN_OV76BE:
-	case SEN_OV8600:
-		rc = i2c_r(ov, 0x10);
-		if (rc < 0)
-			return rc;
-		else
-			*val = rc;
-		break;
-	case SEN_KS0127:
-	case SEN_KS0127B:
-	case SEN_SAA7111A:
-		val = NULL;
-		PDEBUG(3, "Unsupported with this sensor");
-		return -EPERM;
-	default:
-		err("Sensor not supported for get_exposure");
-		return -EINVAL;
-	}
-
-	PDEBUG(3, "%d", *val);
-	ov->exposure = *val;
-
-	return 0;
-}
-
-/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
-static void
-ov51x_led_control(struct usb_ov511 *ov, int enable)
-{
-	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-	if (ov->bridge == BRG_OV511PLUS)
-		reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0);
-	else if (ov->bclass == BCL_OV518)
-		reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02);
-
-	return;
-}
-
-/* Matches the sensor's internal frame rate to the lighting frequency.
- * Valid frequencies are:
- *	50 - 50Hz, for European and Asian lighting
- *	60 - 60Hz, for American lighting
- *
- * Tested with: OV7610, OV7620, OV76BE, OV6620
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_light_freq(struct usb_ov511 *ov, int freq)
-{
-	int sixty;
-
-	PDEBUG(4, "%d Hz", freq);
-
-	if (freq == 60)
-		sixty = 1;
-	else if (freq == 50)
-		sixty = 0;
-	else {
-		err("Invalid light freq (%d Hz)", freq);
-		return -EINVAL;
-	}
-
-	switch (ov->sensor) {
-	case SEN_OV7610:
-		i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
-		i2c_w(ov, 0x2b, sixty?0x00:0xac);
-		i2c_w_mask(ov, 0x13, 0x10, 0x10);
-		i2c_w_mask(ov, 0x13, 0x00, 0x10);
-		break;
-	case SEN_OV7620:
-	case SEN_OV76BE:
-	case SEN_OV8600:
-		i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
-		i2c_w(ov, 0x2b, sixty?0x00:0xac);
-		i2c_w_mask(ov, 0x76, 0x01, 0x01);
-		break;
-	case SEN_OV6620:
-	case SEN_OV6630:
-		i2c_w(ov, 0x2b, sixty?0xa8:0x28);
-		i2c_w(ov, 0x2a, sixty?0x84:0xa4);
-		break;
-	case SEN_KS0127:
-	case SEN_KS0127B:
-	case SEN_SAA7111A:
-		PDEBUG(5, "Unsupported with this sensor");
-		return -EPERM;
-	default:
-		err("Sensor not supported for set_light_freq");
-		return -EINVAL;
-	}
-
-	ov->lightfreq = freq;
-
-	return 0;
-}
-
-/* If enable is true, turn on the sensor's banding filter, otherwise turn it
- * off. This filter tries to reduce the pattern of horizontal light/dark bands
- * caused by some (usually fluorescent) lighting. The light frequency must be
- * set either before or after enabling it with ov51x_set_light_freq().
- *
- * Tested with: OV7610, OV7620, OV76BE, OV6620.
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_banding_filter(struct usb_ov511 *ov, int enable)
-{
-	int rc;
-
-	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-	if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
-		|| ov->sensor == SEN_SAA7111A) {
-		PDEBUG(5, "Unsupported with this sensor");
-		return -EPERM;
-	}
-
-	rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04);
-	if (rc < 0)
-		return rc;
-
-	ov->bandfilt = enable;
-
-	return 0;
-}
-
-/* If enable is true, turn on the sensor's auto brightness control, otherwise
- * turn it off.
- *
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_auto_brightness(struct usb_ov511 *ov, int enable)
-{
-	int rc;
-
-	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-	if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
-		|| ov->sensor == SEN_SAA7111A) {
-		PDEBUG(5, "Unsupported with this sensor");
-		return -EPERM;
-	}
-
-	rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10);
-	if (rc < 0)
-		return rc;
-
-	ov->auto_brt = enable;
-
-	return 0;
-}
-
-/* If enable is true, turn on the sensor's auto exposure control, otherwise
- * turn it off.
- *
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_auto_exposure(struct usb_ov511 *ov, int enable)
-{
-	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-	switch (ov->sensor) {
-	case SEN_OV7610:
-		i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80);
-		break;
-	case SEN_OV6620:
-	case SEN_OV7620:
-	case SEN_OV76BE:
-	case SEN_OV8600:
-		i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01);
-		break;
-	case SEN_OV6630:
-		i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10);
-		break;
-	case SEN_KS0127:
-	case SEN_KS0127B:
-	case SEN_SAA7111A:
-		PDEBUG(5, "Unsupported with this sensor");
-		return -EPERM;
-	default:
-		err("Sensor not supported for set_auto_exposure");
-		return -EINVAL;
-	}
-
-	ov->auto_exp = enable;
-
-	return 0;
-}
-
-/* Modifies the sensor's exposure algorithm to allow proper exposure of objects
- * that are illuminated from behind.
- *
- * Tested with: OV6620, OV7620
- * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_backlight(struct usb_ov511 *ov, int enable)
-{
-	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-	switch (ov->sensor) {
-	case SEN_OV7620:
-	case SEN_OV8600:
-		i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0);
-		i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
-		i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
-		break;
-	case SEN_OV6620:
-		i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0);
-		i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
-		i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80);
-		break;
-	case SEN_OV6630:
-		i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0);
-		i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
-		i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
-		break;
-	case SEN_OV7610:
-	case SEN_OV76BE:
-	case SEN_KS0127:
-	case SEN_KS0127B:
-	case SEN_SAA7111A:
-		PDEBUG(5, "Unsupported with this sensor");
-		return -EPERM;
-	default:
-		err("Sensor not supported for set_backlight");
-		return -EINVAL;
-	}
-
-	ov->backlight = enable;
-
-	return 0;
-}
-
-static int
-sensor_set_mirror(struct usb_ov511 *ov, int enable)
-{
-	PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-	switch (ov->sensor) {
-	case SEN_OV6620:
-	case SEN_OV6630:
-	case SEN_OV7610:
-	case SEN_OV7620:
-	case SEN_OV76BE:
-	case SEN_OV8600:
-		i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40);
-		break;
-	case SEN_KS0127:
-	case SEN_KS0127B:
-	case SEN_SAA7111A:
-		PDEBUG(5, "Unsupported with this sensor");
-		return -EPERM;
-	default:
-		err("Sensor not supported for set_mirror");
-		return -EINVAL;
-	}
-
-	ov->mirror = enable;
-
-	return 0;
-}
-
-/* Returns number of bits per pixel (regardless of where they are located;
- * planar or not), or zero for unsupported format.
- */
-static inline int
-get_depth(int palette)
-{
-	switch (palette) {
-	case VIDEO_PALETTE_GREY:    return 8;
-	case VIDEO_PALETTE_YUV420:  return 12;
-	case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
-	default:		    return 0;  /* Invalid format */
-	}
-}
-
-/* Bytes per frame. Used by read(). Return of 0 indicates error */
-static inline long int
-get_frame_length(struct ov511_frame *frame)
-{
-	if (!frame)
-		return 0;
-	else
-		return ((frame->width * frame->height
-			 * get_depth(frame->format)) >> 3);
-}
-
-static int
-mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height,
-			 int mode, int sub_flag, int qvga)
-{
-	int clock;
-
-	/******** Mode (VGA/QVGA) and sensor specific regs ********/
-
-	switch (ov->sensor) {
-	case SEN_OV7610:
-		i2c_w(ov, 0x14, qvga?0x24:0x04);
-// FIXME: Does this improve the image quality or frame rate?
-#if 0
-		i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
-		i2c_w(ov, 0x24, 0x10);
-		i2c_w(ov, 0x25, qvga?0x40:0x8a);
-		i2c_w(ov, 0x2f, qvga?0x30:0xb0);
-		i2c_w(ov, 0x35, qvga?0x1c:0x9c);
-#endif
-		break;
-	case SEN_OV7620:
-//		i2c_w(ov, 0x2b, 0x00);
-		i2c_w(ov, 0x14, qvga?0xa4:0x84);
-		i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
-		i2c_w(ov, 0x24, qvga?0x20:0x3a);
-		i2c_w(ov, 0x25, qvga?0x30:0x60);
-		i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
-		i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0);
-		i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
-		break;
-	case SEN_OV76BE:
-//		i2c_w(ov, 0x2b, 0x00);
-		i2c_w(ov, 0x14, qvga?0xa4:0x84);
-// FIXME: Enable this once 7620AE uses 7620 initial settings
-#if 0
-		i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
-		i2c_w(ov, 0x24, qvga?0x20:0x3a);
-		i2c_w(ov, 0x25, qvga?0x30:0x60);
-		i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
-		i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0);
-		i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
-#endif
-		break;
-	case SEN_OV6620:
-		i2c_w(ov, 0x14, qvga?0x24:0x04);
-		break;
-	case SEN_OV6630:
-		i2c_w(ov, 0x14, qvga?0xa0:0x80);
-		break;
-	default:
-		err("Invalid sensor");
-		return -EINVAL;
-	}
-
-	/******** Palette-specific regs ********/
-
-	if (mode == VIDEO_PALETTE_GREY) {
-		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
-			/* these aren't valid on the OV6620/OV7620/6630? */
-			i2c_w_mask(ov, 0x0e, 0x40, 0x40);
-		}
-
-		if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
-		    && ov518_color) {
-			i2c_w_mask(ov, 0x12, 0x00, 0x10);
-			i2c_w_mask(ov, 0x13, 0x00, 0x20);
-		} else {
-			i2c_w_mask(ov, 0x13, 0x20, 0x20);
-		}
-	} else {
-		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
-			/* not valid on the OV6620/OV7620/6630? */
-			i2c_w_mask(ov, 0x0e, 0x00, 0x40);
-		}
-
-		/* The OV518 needs special treatment. Although both the OV518
-		 * and the OV6630 support a 16-bit video bus, only the 8 bit Y
-		 * bus is actually used. The UV bus is tied to ground.
-		 * Therefore, the OV6630 needs to be in 8-bit multiplexed
-		 * output mode */
-
-		if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
-		    && ov518_color) {
-			i2c_w_mask(ov, 0x12, 0x10, 0x10);
-			i2c_w_mask(ov, 0x13, 0x20, 0x20);
-		} else {
-			i2c_w_mask(ov, 0x13, 0x00, 0x20);
-		}
-	}
-
-	/******** Clock programming ********/
-
-	/* The OV6620 needs special handling. This prevents the
-	 * severe banding that normally occurs */
-	if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630)
-	{
-		/* Clock down */
-
-		i2c_w(ov, 0x2a, 0x04);
-
-		if (ov->compress) {
-//			clock = 0;    /* This ensures the highest frame rate */
-			clock = 3;
-		} else if (clockdiv == -1) {   /* If user didn't override it */
-			clock = 3;    /* Gives better exposure time */
-		} else {
-			clock = clockdiv;
-		}
-
-		PDEBUG(4, "Setting clock divisor to %d", clock);
-
-		i2c_w(ov, 0x11, clock);
-
-		i2c_w(ov, 0x2a, 0x84);
-		/* This next setting is critical. It seems to improve
-		 * the gain or the contrast. The "reserved" bits seem
-		 * to have some effect in this case. */
-		i2c_w(ov, 0x2d, 0x85);
-	}
-	else
-	{
-		if (ov->compress) {
-			clock = 1;    /* This ensures the highest frame rate */
-		} else if (clockdiv == -1) {   /* If user didn't override it */
-			/* Calculate and set the clock divisor */
-			clock = ((sub_flag ? ov->subw * ov->subh
-				  : width * height)
-				 * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2)
-				 / 66000;
-		} else {
-			clock = clockdiv;
-		}
-
-		PDEBUG(4, "Setting clock divisor to %d", clock);
-
-		i2c_w(ov, 0x11, clock);
-	}
-
-	/******** Special Features ********/
-
-	if (framedrop >= 0)
-		i2c_w(ov, 0x16, framedrop);
-
-	/* Test Pattern */
-	i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02);
-
-	/* Enable auto white balance */
-	i2c_w_mask(ov, 0x12, 0x04, 0x04);
-
-	// This will go away as soon as ov51x_mode_init_sensor_regs()
-	// is fully tested.
-	/* 7620/6620/6630? don't have register 0x35, so play it safe */
-	if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
-		if (width == 640 && height == 480)
-			i2c_w(ov, 0x35, 0x9e);
-		else
-			i2c_w(ov, 0x35, 0x1e);
-	}
-
-	return 0;
-}
-
-static int
-set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode,
-		     int sub_flag)
-{
-	int ret;
-	int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize;
-	int hoffset, voffset, hwscale = 0, vwscale = 0;
-
-	/* The different sensor ICs handle setting up of window differently.
-	 * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */
-	switch (ov->sensor) {
-	case SEN_OV7610:
-	case SEN_OV76BE:
-		hwsbase = 0x38;
-		hwebase = 0x3a;
-		vwsbase = vwebase = 0x05;
-		break;
-	case SEN_OV6620:
-	case SEN_OV6630:
-		hwsbase = 0x38;
-		hwebase = 0x3a;
-		vwsbase = 0x05;
-		vwebase = 0x06;
-		break;
-	case SEN_OV7620:
-		hwsbase = 0x2f;		/* From 7620.SET (spec is wrong) */
-		hwebase = 0x2f;
-		vwsbase = vwebase = 0x05;
-		break;
-	default:
-		err("Invalid sensor");
-		return -EINVAL;
-	}
-
-	if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) {
-		/* Note: OV518(+) does downsample on its own) */
-		if ((width > 176 && height > 144)
-		    || ov->bclass == BCL_OV518) {  /* CIF */
-			ret = mode_init_ov_sensor_regs(ov, width, height,
-				mode, sub_flag, 0);
-			if (ret < 0)
-				return ret;
-			hwscale = 1;
-			vwscale = 1;  /* The datasheet says 0; it's wrong */
-			hwsize = 352;
-			vwsize = 288;
-		} else if (width > 176 || height > 144) {
-			err("Illegal dimensions");
-			return -EINVAL;
-		} else {			    /* QCIF */
-			ret = mode_init_ov_sensor_regs(ov, width, height,
-				mode, sub_flag, 1);
-			if (ret < 0)
-				return ret;
-			hwsize = 176;
-			vwsize = 144;
-		}
-	} else {
-		if (width > 320 && height > 240) {  /* VGA */
-			ret = mode_init_ov_sensor_regs(ov, width, height,
-				mode, sub_flag, 0);
-			if (ret < 0)
-				return ret;
-			hwscale = 2;
-			vwscale = 1;
-			hwsize = 640;
-			vwsize = 480;
-		} else if (width > 320 || height > 240) {
-			err("Illegal dimensions");
-			return -EINVAL;
-		} else {			    /* QVGA */
-			ret = mode_init_ov_sensor_regs(ov, width, height,
-				mode, sub_flag, 1);
-			if (ret < 0)
-				return ret;
-			hwscale = 1;
-			hwsize = 320;
-			vwsize = 240;
-		}
-	}
-
-	/* Center the window */
-	hoffset = ((hwsize - width) / 2) >> hwscale;
-	voffset = ((vwsize - height) / 2) >> vwscale;
-
-	/* FIXME! - This needs to be changed to support 160x120 and 6620!!! */
-	if (sub_flag) {
-		i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale));
-		i2c_w(ov, 0x18,	hwebase+((ov->subx+ov->subw)>>hwscale));
-		i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale));
-		i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale));
-	} else {
-		i2c_w(ov, 0x17, hwsbase + hoffset);
-		i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale));
-		i2c_w(ov, 0x19, vwsbase + voffset);
-		i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale));
-	}
-
-#ifdef OV511_DEBUG
-	if (dump_sensor)
-		dump_i2c_regs(ov);
-#endif
-
-	return 0;
-}
-
-/* Set up the OV511/OV511+ with the given image parameters.
- *
- * Do not put any sensor-specific code in here (including I2C I/O functions)
- */
-static int
-ov511_mode_init_regs(struct usb_ov511 *ov,
-		     int width, int height, int mode, int sub_flag)
-{
-	int hsegs, vsegs;
-
-	if (sub_flag) {
-		width = ov->subw;
-		height = ov->subh;
-	}
-
-	PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
-	       width, height, mode, sub_flag);
-
-	// FIXME: This should be moved to a 7111a-specific function once
-	// subcapture is dealt with properly
-	if (ov->sensor == SEN_SAA7111A) {
-		if (width == 320 && height == 240) {
-			/* No need to do anything special */
-		} else if (width == 640 && height == 480) {
-			/* Set the OV511 up as 320x480, but keep the
-			 * V4L resolution as 640x480 */
-			width = 320;
-		} else {
-			err("SAA7111A only allows 320x240 or 640x480");
-			return -EINVAL;
-		}
-	}
-
-	/* Make sure width and height are a multiple of 8 */
-	if (width % 8 || height % 8) {
-		err("Invalid size (%d, %d) (mode = %d)", width, height, mode);
-		return -EINVAL;
-	}
-
-	if (width < ov->minwidth || height < ov->minheight) {
-		err("Requested dimensions are too small");
-		return -EINVAL;
-	}
-
-	if (ov51x_stop(ov) < 0)
-		return -EIO;
-
-	if (mode == VIDEO_PALETTE_GREY) {
-		reg_w(ov, R511_CAM_UV_EN, 0x00);
-		reg_w(ov, R511_SNAP_UV_EN, 0x00);
-		reg_w(ov, R511_SNAP_OPTS, 0x01);
-	} else {
-		reg_w(ov, R511_CAM_UV_EN, 0x01);
-		reg_w(ov, R511_SNAP_UV_EN, 0x01);
-		reg_w(ov, R511_SNAP_OPTS, 0x03);
-	}
-
-	/* Here I'm assuming that snapshot size == image size.
-	 * I hope that's always true. --claudio
-	 */
-	hsegs = (width >> 3) - 1;
-	vsegs = (height >> 3) - 1;
-
-	reg_w(ov, R511_CAM_PXCNT, hsegs);
-	reg_w(ov, R511_CAM_LNCNT, vsegs);
-	reg_w(ov, R511_CAM_PXDIV, 0x00);
-	reg_w(ov, R511_CAM_LNDIV, 0x00);
-
-	/* YUV420, low pass filter on */
-	reg_w(ov, R511_CAM_OPTS, 0x03);
-
-	/* Snapshot additions */
-	reg_w(ov, R511_SNAP_PXCNT, hsegs);
-	reg_w(ov, R511_SNAP_LNCNT, vsegs);
-	reg_w(ov, R511_SNAP_PXDIV, 0x00);
-	reg_w(ov, R511_SNAP_LNDIV, 0x00);
-
-	if (ov->compress) {
-		/* Enable Y and UV quantization and compression */
-		reg_w(ov, R511_COMP_EN, 0x07);
-		reg_w(ov, R511_COMP_LUT_EN, 0x03);
-		ov51x_reset(ov, OV511_RESET_OMNICE);
-	}
-
-	if (ov51x_restart(ov) < 0)
-		return -EIO;
-
-	return 0;
-}
-
-/* Sets up the OV518/OV518+ with the given image parameters
- *
- * OV518 needs a completely different approach, until we can figure out what
- * the individual registers do. Also, only 15 FPS is supported now.
- *
- * Do not put any sensor-specific code in here (including I2C I/O functions)
- */
-static int
-ov518_mode_init_regs(struct usb_ov511 *ov,
-		     int width, int height, int mode, int sub_flag)
-{
-	int hsegs, vsegs, hi_res;
-
-	if (sub_flag) {
-		width = ov->subw;
-		height = ov->subh;
-	}
-
-	PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
-	       width, height, mode, sub_flag);
-
-	if (width % 16 || height % 8) {
-		err("Invalid size (%d, %d)", width, height);
-		return -EINVAL;
-	}
-
-	if (width < ov->minwidth || height < ov->minheight) {
-		err("Requested dimensions are too small");
-		return -EINVAL;
-	}
-
-	if (width >= 320 && height >= 240) {
-		hi_res = 1;
-	} else if (width >= 320 || height >= 240) {
-		err("Invalid width/height combination (%d, %d)", width, height);
-		return -EINVAL;
-	} else {
-		hi_res = 0;
-	}
-
-	if (ov51x_stop(ov) < 0)
-		return -EIO;
-
-	/******** Set the mode ********/
-
-	reg_w(ov, 0x2b, 0);
-	reg_w(ov, 0x2c, 0);
-	reg_w(ov, 0x2d, 0);
-	reg_w(ov, 0x2e, 0);
-	reg_w(ov, 0x3b, 0);
-	reg_w(ov, 0x3c, 0);
-	reg_w(ov, 0x3d, 0);
-	reg_w(ov, 0x3e, 0);
-
-	if (ov->bridge == BRG_OV518 && ov518_color) {
-		/* OV518 needs U and V swapped */
-		i2c_w_mask(ov, 0x15, 0x00, 0x01);
-
-		if (mode == VIDEO_PALETTE_GREY) {
-			/* Set 16-bit input format (UV data are ignored) */
-			reg_w_mask(ov, 0x20, 0x00, 0x08);
-
-			/* Set 8-bit (4:0:0) output format */
-			reg_w_mask(ov, 0x28, 0x00, 0xf0);
-			reg_w_mask(ov, 0x38, 0x00, 0xf0);
-		} else {
-			/* Set 8-bit (YVYU) input format */
-			reg_w_mask(ov, 0x20, 0x08, 0x08);
-
-			/* Set 12-bit (4:2:0) output format */
-			reg_w_mask(ov, 0x28, 0x80, 0xf0);
-			reg_w_mask(ov, 0x38, 0x80, 0xf0);
-		}
-	} else {
-		reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
-		reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
-	}
-
-	hsegs = width / 16;
-	vsegs = height / 4;
-
-	reg_w(ov, 0x29, hsegs);
-	reg_w(ov, 0x2a, vsegs);
-
-	reg_w(ov, 0x39, hsegs);
-	reg_w(ov, 0x3a, vsegs);
-
-	/* Windows driver does this here; who knows why */
-	reg_w(ov, 0x2f, 0x80);
-
-	/******** Set the framerate (to 15 FPS) ********/
-
-	/* Mode independent, but framerate dependent, regs */
-	reg_w(ov, 0x51, 0x02);	/* Clock divider; lower==faster */
-	reg_w(ov, 0x22, 0x18);
-	reg_w(ov, 0x23, 0xff);
-
-	if (ov->bridge == BRG_OV518PLUS)
-		reg_w(ov, 0x21, 0x19);
-	else
-		reg_w(ov, 0x71, 0x19);	/* Compression-related? */
-
-	// FIXME: Sensor-specific
-	/* Bit 5 is what matters here. Of course, it is "reserved" */
-	i2c_w(ov, 0x54, 0x23);
-
-	reg_w(ov, 0x2f, 0x80);
-
-	if (ov->bridge == BRG_OV518PLUS) {
-		reg_w(ov, 0x24, 0x94);
-		reg_w(ov, 0x25, 0x90);
-		ov518_reg_w32(ov, 0xc4,    400, 2);	/* 190h   */
-		ov518_reg_w32(ov, 0xc6,    540, 2);	/* 21ch   */
-		ov518_reg_w32(ov, 0xc7,    540, 2);	/* 21ch   */
-		ov518_reg_w32(ov, 0xc8,    108, 2);	/* 6ch    */
-		ov518_reg_w32(ov, 0xca, 131098, 3);	/* 2001ah */
-		ov518_reg_w32(ov, 0xcb,    532, 2);	/* 214h   */
-		ov518_reg_w32(ov, 0xcc,   2400, 2);	/* 960h   */
-		ov518_reg_w32(ov, 0xcd,     32, 2);	/* 20h    */
-		ov518_reg_w32(ov, 0xce,    608, 2);	/* 260h   */
-	} else {
-		reg_w(ov, 0x24, 0x9f);
-		reg_w(ov, 0x25, 0x90);
-		ov518_reg_w32(ov, 0xc4,    400, 2);	/* 190h   */
-		ov518_reg_w32(ov, 0xc6,    500, 2);	/* 1f4h   */
-		ov518_reg_w32(ov, 0xc7,    500, 2);	/* 1f4h   */
-		ov518_reg_w32(ov, 0xc8,    142, 2);	/* 8eh    */
-		ov518_reg_w32(ov, 0xca, 131098, 3);	/* 2001ah */
-		ov518_reg_w32(ov, 0xcb,    532, 2);	/* 214h   */
-		ov518_reg_w32(ov, 0xcc,   2000, 2);	/* 7d0h   */
-		ov518_reg_w32(ov, 0xcd,     32, 2);	/* 20h    */
-		ov518_reg_w32(ov, 0xce,    608, 2);	/* 260h   */
-	}
-
-	reg_w(ov, 0x2f, 0x80);
-
-	if (ov51x_restart(ov) < 0)
-		return -EIO;
-
-	/* Reset it just for good measure */
-	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-		return -EIO;
-
-	return 0;
-}
-
-/* This is a wrapper around the OV511, OV518, and sensor specific functions */
-static int
-mode_init_regs(struct usb_ov511 *ov,
-	       int width, int height, int mode, int sub_flag)
-{
-	int rc = 0;
-
-	if (!ov || !ov->dev)
-		return -EFAULT;
-
-	if (ov->bclass == BCL_OV518) {
-		rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag);
-	} else {
-		rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag);
-	}
-
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	switch (ov->sensor) {
-	case SEN_OV7610:
-	case SEN_OV7620:
-	case SEN_OV76BE:
-	case SEN_OV8600:
-	case SEN_OV6620:
-	case SEN_OV6630:
-		rc = set_ov_sensor_window(ov, width, height, mode, sub_flag);
-		break;
-	case SEN_KS0127:
-	case SEN_KS0127B:
-		err("KS0127-series decoders not supported yet");
-		rc = -EINVAL;
-		break;
-	case SEN_SAA7111A:
-//		rc = mode_init_saa_sensor_regs(ov, width, height, mode,
-//					       sub_flag);
-
-		PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f));
-		break;
-	default:
-		err("Unknown sensor");
-		rc = -EINVAL;
-	}
-
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	/* Sensor-independent settings */
-	rc = sensor_set_auto_brightness(ov, ov->auto_brt);
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	rc = sensor_set_auto_exposure(ov, ov->auto_exp);
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	rc = sensor_set_banding_filter(ov, bandingfilter);
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	if (ov->lightfreq) {
-		rc = sensor_set_light_freq(ov, lightfreq);
-		if (FATAL_ERROR(rc))
-			return rc;
-	}
-
-	rc = sensor_set_backlight(ov, ov->backlight);
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	rc = sensor_set_mirror(ov, ov->mirror);
-	if (FATAL_ERROR(rc))
-		return rc;
-
-	return 0;
-}
-
-/* This sets the default image parameters. This is useful for apps that use
- * read() and do not set these.
- */
-static int
-ov51x_set_default_params(struct usb_ov511 *ov)
-{
-	int i;
-
-	/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
-	 * (using read() instead). */
-	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov->frame[i].width = ov->maxwidth;
-		ov->frame[i].height = ov->maxheight;
-		ov->frame[i].bytes_read = 0;
-		if (force_palette)
-			ov->frame[i].format = force_palette;
-		else
-			ov->frame[i].format = VIDEO_PALETTE_YUV420;
-
-		ov->frame[i].depth = get_depth(ov->frame[i].format);
-	}
-
-	PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight,
-	       symbolic(v4l1_plist, ov->frame[0].format));
-
-	/* Initialize to max width/height, YUV420 or RGB24 (if supported) */
-	if (mode_init_regs(ov, ov->maxwidth, ov->maxheight,
-			   ov->frame[0].format, 0) < 0)
-		return -EINVAL;
-
-	return 0;
-}
-
-/**********************************************************************
- *
- * Video decoder stuff
- *
- **********************************************************************/
-
-/* Set analog input port of decoder */
-static int
-decoder_set_input(struct usb_ov511 *ov, int input)
-{
-	PDEBUG(4, "port %d", input);
-
-	switch (ov->sensor) {
-	case SEN_SAA7111A:
-	{
-		/* Select mode */
-		i2c_w_mask(ov, 0x02, input, 0x07);
-		/* Bypass chrominance trap for modes 4..7 */
-		i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80);
-		break;
-	}
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/* Get ASCII name of video input */
-static int
-decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
-{
-	switch (ov->sensor) {
-	case SEN_SAA7111A:
-	{
-		if (input < 0 || input > 7)
-			return -EINVAL;
-		else if (input < 4)
-			sprintf(name, "CVBS-%d", input);
-		else // if (input < 8)
-			sprintf(name, "S-Video-%d", input - 4);
-		break;
-	}
-	default:
-		sprintf(name, "%s", "Camera");
-	}
-
-	return 0;
-}
-
-/* Set norm (NTSC, PAL, SECAM, AUTO) */
-static int
-decoder_set_norm(struct usb_ov511 *ov, int norm)
-{
-	PDEBUG(4, "%d", norm);
-
-	switch (ov->sensor) {
-	case SEN_SAA7111A:
-	{
-		int reg_8, reg_e;
-
-		if (norm == VIDEO_MODE_NTSC) {
-			reg_8 = 0x40;	/* 60 Hz */
-			reg_e = 0x00;	/* NTSC M / PAL BGHI */
-		} else if (norm == VIDEO_MODE_PAL) {
-			reg_8 = 0x00;	/* 50 Hz */
-			reg_e = 0x00;	/* NTSC M / PAL BGHI */
-		} else if (norm == VIDEO_MODE_AUTO) {
-			reg_8 = 0x80;	/* Auto field detect */
-			reg_e = 0x00;	/* NTSC M / PAL BGHI */
-		} else if (norm == VIDEO_MODE_SECAM) {
-			reg_8 = 0x00;	/* 50 Hz */
-			reg_e = 0x50;	/* SECAM / PAL 4.43 */
-		} else {
-			return -EINVAL;
-		}
-
-		i2c_w_mask(ov, 0x08, reg_8, 0xc0);
-		i2c_w_mask(ov, 0x0e, reg_e, 0x70);
-		break;
-	}
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/**********************************************************************
- *
- * Raw data parsing
- *
- **********************************************************************/
-
-/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
- * image at pOut is specified by w.
- */
-static inline void
-make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
-{
-	unsigned char *pOut1 = pOut;
-	int x, y;
-
-	for (y = 0; y < 8; y++) {
-		pOut1 = pOut;
-		for (x = 0; x < 8; x++) {
-			*pOut1++ = *pIn++;
-		}
-		pOut += w;
-	}
-}
-
-/*
- * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments.
- * The segments represent 4 squares of 8x8 pixels as follows:
- *
- *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
- *      8  9 ... 15    72  73 ...  79        200 201 ... 207
- *           ...              ...                    ...
- *     56 57 ... 63   120 121 ... 127        248 249 ... 255
- *
- */
-static void
-yuv400raw_to_yuv400p(struct ov511_frame *frame,
-		     unsigned char *pIn0, unsigned char *pOut0)
-{
-	int x, y;
-	unsigned char *pIn, *pOut, *pOutLine;
-
-	/* Copy Y */
-	pIn = pIn0;
-	pOutLine = pOut0;
-	for (y = 0; y < frame->rawheight - 1; y += 8) {
-		pOut = pOutLine;
-		for (x = 0; x < frame->rawwidth - 1; x += 8) {
-			make_8x8(pIn, pOut, frame->rawwidth);
-			pIn += 64;
-			pOut += 8;
-		}
-		pOutLine += 8 * frame->rawwidth;
-	}
-}
-
-/*
- * For YUV 4:2:0 images, the data show up in 384 byte segments.
- * The first 64 bytes of each segment are U, the next 64 are V.  The U and
- * V are arranged as follows:
- *
- *      0  1 ...  7
- *      8  9 ... 15
- *           ...
- *     56 57 ... 63
- *
- * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
- *
- * The next 256 bytes are full resolution Y data and represent 4 squares
- * of 8x8 pixels as follows:
- *
- *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
- *      8  9 ... 15    72  73 ...  79        200 201 ... 207
- *           ...              ...                    ...
- *     56 57 ... 63   120 121 ... 127   ...  248 249 ... 255
- *
- * Note that the U and V data in one segment represent a 16 x 16 pixel
- * area, but the Y data represent a 32 x 8 pixel area. If the width is not an
- * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the
- * next horizontal stripe.
- *
- * If dumppix module param is set, _parse_data just dumps the incoming segments,
- * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
- * this puts the data on the standard output and can be analyzed with the
- * parseppm.c utility I wrote.  That's a much faster way for figuring out how
- * these data are scrambled.
- */
-
-/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0.
- *
- * FIXME: Currently only handles width and height that are multiples of 16
- */
-static void
-yuv420raw_to_yuv420p(struct ov511_frame *frame,
-		     unsigned char *pIn0, unsigned char *pOut0)
-{
-	int k, x, y;
-	unsigned char *pIn, *pOut, *pOutLine;
-	const unsigned int a = frame->rawwidth * frame->rawheight;
-	const unsigned int w = frame->rawwidth / 2;
-
-	/* Copy U and V */
-	pIn = pIn0;
-	pOutLine = pOut0 + a;
-	for (y = 0; y < frame->rawheight - 1; y += 16) {
-		pOut = pOutLine;
-		for (x = 0; x < frame->rawwidth - 1; x += 16) {
-			make_8x8(pIn, pOut, w);
-			make_8x8(pIn + 64, pOut + a/4, w);
-			pIn += 384;
-			pOut += 8;
-		}
-		pOutLine += 8 * w;
-	}
-
-	/* Copy Y */
-	pIn = pIn0 + 128;
-	pOutLine = pOut0;
-	k = 0;
-	for (y = 0; y < frame->rawheight - 1; y += 8) {
-		pOut = pOutLine;
-		for (x = 0; x < frame->rawwidth - 1; x += 8) {
-			make_8x8(pIn, pOut, frame->rawwidth);
-			pIn += 64;
-			pOut += 8;
-			if ((++k) > 3) {
-				k = 0;
-				pIn += 128;
-			}
-		}
-		pOutLine += 8 * frame->rawwidth;
-	}
-}
-
-/**********************************************************************
- *
- * Decompression
- *
- **********************************************************************/
-
-static int
-request_decompressor(struct usb_ov511 *ov)
-{
-	if (ov->bclass == BCL_OV511 || ov->bclass == BCL_OV518) {
-		err("No decompressor available");
-	} else {
-		err("Unknown bridge");
-	}
-
-	return -ENOSYS;
-}
-
-static void
-decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
-	   unsigned char *pIn0, unsigned char *pOut0)
-{
-	if (!ov->decomp_ops)
-		if (request_decompressor(ov))
-			return;
-
-}
-
-/**********************************************************************
- *
- * Format conversion
- *
- **********************************************************************/
-
-/* Fuses even and odd fields together, and doubles width.
- * INPUT: an odd field followed by an even field at pIn0, in YUV planar format
- * OUTPUT: a normal YUV planar image, with correct aspect ratio
- */
-static void
-deinterlace(struct ov511_frame *frame, int rawformat,
-	    unsigned char *pIn0, unsigned char *pOut0)
-{
-	const int fieldheight = frame->rawheight / 2;
-	const int fieldpix = fieldheight * frame->rawwidth;
-	const int w = frame->width;
-	int x, y;
-	unsigned char *pInEven, *pInOdd, *pOut;
-
-	PDEBUG(5, "fieldheight=%d", fieldheight);
-
-	if (frame->rawheight != frame->height) {
-		err("invalid height");
-		return;
-	}
-
-	if ((frame->rawwidth * 2) != frame->width) {
-		err("invalid width");
-		return;
-	}
-
-	/* Y */
-	pInOdd = pIn0;
-	pInEven = pInOdd + fieldpix;
-	pOut = pOut0;
-	for (y = 0; y < fieldheight; y++) {
-		for (x = 0; x < frame->rawwidth; x++) {
-			*pOut = *pInEven;
-			*(pOut+1) = *pInEven++;
-			*(pOut+w) = *pInOdd;
-			*(pOut+w+1) = *pInOdd++;
-			pOut += 2;
-		}
-		pOut += w;
-	}
-
-	if (rawformat == RAWFMT_YUV420) {
-	/* U */
-		pInOdd = pIn0 + fieldpix * 2;
-		pInEven = pInOdd + fieldpix / 4;
-		for (y = 0; y < fieldheight / 2; y++) {
-			for (x = 0; x < frame->rawwidth / 2; x++) {
-				*pOut = *pInEven;
-				*(pOut+1) = *pInEven++;
-				*(pOut+w/2) = *pInOdd;
-				*(pOut+w/2+1) = *pInOdd++;
-				pOut += 2;
-			}
-			pOut += w/2;
-		}
-	/* V */
-		pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2;
-		pInEven = pInOdd + fieldpix / 4;
-		for (y = 0; y < fieldheight / 2; y++) {
-			for (x = 0; x < frame->rawwidth / 2; x++) {
-				*pOut = *pInEven;
-				*(pOut+1) = *pInEven++;
-				*(pOut+w/2) = *pInOdd;
-				*(pOut+w/2+1) = *pInOdd++;
-				pOut += 2;
-			}
-			pOut += w/2;
-		}
-	}
-}
-
-static void
-ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
-		/* Deinterlace frame, if necessary */
-		if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
-			if (frame->compressed)
-				decompress(ov, frame, frame->rawdata,
-						 frame->tempdata);
-			else
-				yuv400raw_to_yuv400p(frame, frame->rawdata,
-						     frame->tempdata);
-
-			deinterlace(frame, RAWFMT_YUV400, frame->tempdata,
-				    frame->data);
-		} else {
-			if (frame->compressed)
-				decompress(ov, frame, frame->rawdata,
-						 frame->data);
-			else
-				yuv400raw_to_yuv400p(frame, frame->rawdata,
-						     frame->data);
-		}
-}
-
-/* Process raw YUV420 data into standard YUV420P */
-static void
-ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
-	/* Deinterlace frame, if necessary */
-	if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
-		if (frame->compressed)
-			decompress(ov, frame, frame->rawdata, frame->tempdata);
-		else
-			yuv420raw_to_yuv420p(frame, frame->rawdata,
-					     frame->tempdata);
-
-		deinterlace(frame, RAWFMT_YUV420, frame->tempdata,
-			    frame->data);
-	} else {
-		if (frame->compressed)
-			decompress(ov, frame, frame->rawdata, frame->data);
-		else
-			yuv420raw_to_yuv420p(frame, frame->rawdata,
-					     frame->data);
-	}
-}
-
-/* Post-processes the specified frame. This consists of:
- * 	1. Decompress frame, if necessary
- *	2. Deinterlace frame and scale to proper size, if necessary
- * 	3. Convert from YUV planar to destination format, if necessary
- * 	4. Fix the RGB offset, if necessary
- */
-static void
-ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
-	if (dumppix) {
-		memset(frame->data, 0,
-			MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
-		PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
-		memcpy(frame->data, frame->rawdata, frame->bytes_recvd);
-	} else {
-		switch (frame->format) {
-		case VIDEO_PALETTE_GREY:
-			ov51x_postprocess_grey(ov, frame);
-			break;
-		case VIDEO_PALETTE_YUV420:
-		case VIDEO_PALETTE_YUV420P:
-			ov51x_postprocess_yuv420(ov, frame);
-			break;
-		default:
-			err("Cannot convert data to %s",
-			    symbolic(v4l1_plist, frame->format));
-		}
-	}
-}
-
-/**********************************************************************
- *
- * OV51x data transfer, IRQ handler
- *
- **********************************************************************/
-
-static inline void
-ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
-{
-	int num, offset;
-	int pnum = in[ov->packet_size - 1];		/* Get packet number */
-	int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
-	struct ov511_frame *frame = &ov->frame[ov->curframe];
-	struct timeval *ts;
-
-	/* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
-	 * byte non-zero. The EOF packet has image width/height in the
-	 * 10th and 11th bytes. The 9th byte is given as follows:
-	 *
-	 * bit 7: EOF
-	 *     6: compression enabled
-	 *     5: 422/420/400 modes
-	 *     4: 422/420/400 modes
-	 *     3: 1
-	 *     2: snapshot button on
-	 *     1: snapshot frame
-	 *     0: even/odd field
-	 */
-
-	if (printph) {
-		dev_info(&ov->dev->dev,
-			 "ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
-			 pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
-			 in[7], in[8], in[9], in[10], in[11]);
-	}
-
-	/* Check for SOF/EOF packet */
-	if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) ||
-	    (~in[8] & 0x08))
-		goto check_middle;
-
-	/* Frame end */
-	if (in[8] & 0x80) {
-		ts = (struct timeval *)(frame->data
-		      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
-		do_gettimeofday(ts);
-
-		/* Get the actual frame size from the EOF header */
-		frame->rawwidth = ((int)(in[9]) + 1) * 8;
-		frame->rawheight = ((int)(in[10]) + 1) * 8;
-
-		PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d",
-			ov->curframe, pnum, frame->rawwidth, frame->rawheight,
-			frame->bytes_recvd);
-
-		/* Validate the header data */
-		RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-		RESTRICT_TO_RANGE(frame->rawheight, ov->minheight,
-				  ov->maxheight);
-
-		/* Don't allow byte count to exceed buffer size */
-		RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
-
-		if (frame->scanstate == STATE_LINES) {
-			int nextf;
-
-			frame->grabstate = FRAME_DONE;
-			wake_up_interruptible(&frame->wq);
-
-			/* If next frame is ready or grabbing,
-			 * point to it */
-			nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
-			if (ov->frame[nextf].grabstate == FRAME_READY
-			    || ov->frame[nextf].grabstate == FRAME_GRABBING) {
-				ov->curframe = nextf;
-				ov->frame[nextf].scanstate = STATE_SCANNING;
-			} else {
-				if (frame->grabstate == FRAME_DONE) {
-					PDEBUG(4, "** Frame done **");
-				} else {
-					PDEBUG(4, "Frame not ready? state = %d",
-						ov->frame[nextf].grabstate);
-				}
-
-				ov->curframe = -1;
-			}
-		} else {
-			PDEBUG(5, "Frame done, but not scanning");
-		}
-		/* Image corruption caused by misplaced frame->segment = 0
-		 * fixed by carlosf@conectiva.com.br
-		 */
-	} else {
-		/* Frame start */
-		PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-
-		/* Check to see if it's a snapshot frame */
-		/* FIXME?? Should the snapshot reset go here? Performance? */
-		if (in[8] & 0x02) {
-			frame->snapshot = 1;
-			PDEBUG(3, "snapshot detected");
-		}
-
-		frame->scanstate = STATE_LINES;
-		frame->bytes_recvd = 0;
-		frame->compressed = in[8] & 0x40;
-	}
-
-check_middle:
-	/* Are we in a frame? */
-	if (frame->scanstate != STATE_LINES) {
-		PDEBUG(5, "Not in a frame; packet skipped");
-		return;
-	}
-
-	/* If frame start, skip header */
-	if (frame->bytes_recvd == 0)
-		offset = 9;
-	else
-		offset = 0;
-
-	num = n - offset - 1;
-
-	/* Dump all data exactly as received */
-	if (dumppix == 2) {
-		frame->bytes_recvd += n - 1;
-		if (frame->bytes_recvd <= max_raw)
-			memcpy(frame->rawdata + frame->bytes_recvd - (n - 1),
-				in, n - 1);
-		else
-			PDEBUG(3, "Raw data buffer overrun!! (%d)",
-				frame->bytes_recvd - max_raw);
-	} else if (!frame->compressed && !remove_zeros) {
-		frame->bytes_recvd += num;
-		if (frame->bytes_recvd <= max_raw)
-			memcpy(frame->rawdata + frame->bytes_recvd - num,
-				in + offset, num);
-		else
-			PDEBUG(3, "Raw data buffer overrun!! (%d)",
-				frame->bytes_recvd - max_raw);
-	} else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
-		int b, read = 0, allzero, copied = 0;
-		if (offset) {
-			frame->bytes_recvd += 32 - offset;	// Bytes out
-			memcpy(frame->rawdata,	in + offset, 32 - offset);
-			read += 32;
-		}
-
-		while (read < n - 1) {
-			allzero = 1;
-			for (b = 0; b < 32; b++) {
-				if (in[read + b]) {
-					allzero = 0;
-					break;
-				}
-			}
-
-			if (allzero) {
-				/* Don't copy it */
-			} else {
-				if (frame->bytes_recvd + copied + 32 <= max_raw)
-				{
-					memcpy(frame->rawdata
-						+ frame->bytes_recvd + copied,
-						in + read, 32);
-					copied += 32;
-				} else {
-					PDEBUG(3, "Raw data buffer overrun!!");
-				}
-			}
-			read += 32;
-		}
-
-		frame->bytes_recvd += copied;
-	}
-}
-
-static inline void
-ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
-{
-	int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
-	struct ov511_frame *frame = &ov->frame[ov->curframe];
-	struct timeval *ts;
-
-	/* Don't copy the packet number byte */
-	if (ov->packet_numbering)
-		--n;
-
-	/* A false positive here is likely, until OVT gives me
-	 * the definitive SOF/EOF format */
-	if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
-		if (printph) {
-			dev_info(&ov->dev->dev,
-				 "ph: %2x %2x %2x %2x %2x %2x %2x %2x\n",
-				 in[0], in[1], in[2], in[3], in[4], in[5],
-				 in[6], in[7]);
-		}
-
-		if (frame->scanstate == STATE_LINES) {
-			PDEBUG(4, "Detected frame end/start");
-			goto eof;
-		} else { //scanstate == STATE_SCANNING
-			/* Frame start */
-			PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-			goto sof;
-		}
-	} else {
-		goto check_middle;
-	}
-
-eof:
-	ts = (struct timeval *)(frame->data
-	      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
-	do_gettimeofday(ts);
-
-	PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
-		ov->curframe,
-		(int)(in[9]), (int)(in[10]), frame->bytes_recvd);
-
-	// FIXME: Since we don't know the header formats yet,
-	// there is no way to know what the actual image size is
-	frame->rawwidth = frame->width;
-	frame->rawheight = frame->height;
-
-	/* Validate the header data */
-	RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-	RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
-
-	/* Don't allow byte count to exceed buffer size */
-	RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
-
-	if (frame->scanstate == STATE_LINES) {
-		int nextf;
-
-		frame->grabstate = FRAME_DONE;
-		wake_up_interruptible(&frame->wq);
-
-		/* If next frame is ready or grabbing,
-		 * point to it */
-		nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
-		if (ov->frame[nextf].grabstate == FRAME_READY
-		    || ov->frame[nextf].grabstate == FRAME_GRABBING) {
-			ov->curframe = nextf;
-			ov->frame[nextf].scanstate = STATE_SCANNING;
-			frame = &ov->frame[nextf];
-		} else {
-			if (frame->grabstate == FRAME_DONE) {
-				PDEBUG(4, "** Frame done **");
-			} else {
-				PDEBUG(4, "Frame not ready? state = %d",
-				       ov->frame[nextf].grabstate);
-			}
-
-			ov->curframe = -1;
-			PDEBUG(4, "SOF dropped (no active frame)");
-			return;  /* Nowhere to store this frame */
-		}
-	}
-sof:
-	PDEBUG(4, "Starting capture on frame %d", frame->framenum);
-
-// Snapshot not reverse-engineered yet.
-#if 0
-	/* Check to see if it's a snapshot frame */
-	/* FIXME?? Should the snapshot reset go here? Performance? */
-	if (in[8] & 0x02) {
-		frame->snapshot = 1;
-		PDEBUG(3, "snapshot detected");
-	}
-#endif
-	frame->scanstate = STATE_LINES;
-	frame->bytes_recvd = 0;
-	frame->compressed = 1;
-
-check_middle:
-	/* Are we in a frame? */
-	if (frame->scanstate != STATE_LINES) {
-		PDEBUG(4, "scanstate: no SOF yet");
-		return;
-	}
-
-	/* Dump all data exactly as received */
-	if (dumppix == 2) {
-		frame->bytes_recvd += n;
-		if (frame->bytes_recvd <= max_raw)
-			memcpy(frame->rawdata + frame->bytes_recvd - n, in, n);
-		else
-			PDEBUG(3, "Raw data buffer overrun!! (%d)",
-				frame->bytes_recvd - max_raw);
-	} else {
-		/* All incoming data are divided into 8-byte segments. If the
-		 * segment contains all zero bytes, it must be skipped. These
-		 * zero-segments allow the OV518 to mainain a constant data rate
-		 * regardless of the effectiveness of the compression. Segments
-		 * are aligned relative to the beginning of each isochronous
-		 * packet. The first segment in each image is a header (the
-		 * decompressor skips it later).
-		 */
-
-		int b, read = 0, allzero, copied = 0;
-
-		while (read < n) {
-			allzero = 1;
-			for (b = 0; b < 8; b++) {
-				if (in[read + b]) {
-					allzero = 0;
-					break;
-				}
-			}
-
-			if (allzero) {
-			/* Don't copy it */
-			} else {
-				if (frame->bytes_recvd + copied + 8 <= max_raw)
-				{
-					memcpy(frame->rawdata
-						+ frame->bytes_recvd + copied,
-						in + read, 8);
-					copied += 8;
-				} else {
-					PDEBUG(3, "Raw data buffer overrun!!");
-				}
-			}
-			read += 8;
-		}
-		frame->bytes_recvd += copied;
-	}
-}
-
-static void
-ov51x_isoc_irq(struct urb *urb)
-{
-	int i;
-	struct usb_ov511 *ov;
-	struct ov511_sbuf *sbuf;
-
-	if (!urb->context) {
-		PDEBUG(4, "no context");
-		return;
-	}
-
-	sbuf = urb->context;
-	ov = sbuf->ov;
-
-	if (!ov || !ov->dev || !ov->user) {
-		PDEBUG(4, "no device, or not open");
-		return;
-	}
-
-	if (!ov->streaming) {
-		PDEBUG(4, "hmmm... not streaming, but got interrupt");
-		return;
-	}
-
-	if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
-		PDEBUG(4, "URB unlinked");
-		return;
-	}
-
-	if (urb->status != -EINPROGRESS && urb->status != 0) {
-		err("ERROR: urb->status=%d: %s", urb->status,
-		    symbolic(urb_errlist, urb->status));
-	}
-
-	/* Copy the data received into our frame buffer */
-	PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n,
-	       urb->number_of_packets);
-	for (i = 0; i < urb->number_of_packets; i++) {
-		/* Warning: Don't call *_move_data() if no frame active! */
-		if (ov->curframe >= 0) {
-			int n = urb->iso_frame_desc[i].actual_length;
-			int st = urb->iso_frame_desc[i].status;
-			unsigned char *cdata;
-
-			urb->iso_frame_desc[i].actual_length = 0;
-			urb->iso_frame_desc[i].status = 0;
-
-			cdata = urb->transfer_buffer
-				+ urb->iso_frame_desc[i].offset;
-
-			if (!n) {
-				PDEBUG(4, "Zero-length packet");
-				continue;
-			}
-
-			if (st)
-				PDEBUG(2, "data error: [%d] len=%d, status=%d",
-				       i, n, st);
-
-			if (ov->bclass == BCL_OV511)
-				ov511_move_data(ov, cdata, n);
-			else if (ov->bclass == BCL_OV518)
-				ov518_move_data(ov, cdata, n);
-			else
-				err("Unknown bridge device (%d)", ov->bridge);
-
-		} else if (waitqueue_active(&ov->wq)) {
-			wake_up_interruptible(&ov->wq);
-		}
-	}
-
-	/* Resubmit this URB */
-	urb->dev = ov->dev;
-	if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
-		err("usb_submit_urb() ret %d", i);
-
-	return;
-}
-
-/****************************************************************************
- *
- * Stream initialization and termination
- *
- ***************************************************************************/
-
-static int
-ov51x_init_isoc(struct usb_ov511 *ov)
-{
-	struct urb *urb;
-	int fx, err, n, i, size;
-
-	PDEBUG(3, "*** Initializing capture ***");
-
-	ov->curframe = -1;
-
-	if (ov->bridge == BRG_OV511) {
-		if (cams == 1)
-			size = 993;
-		else if (cams == 2)
-			size = 513;
-		else if (cams == 3 || cams == 4)
-			size = 257;
-		else {
-			err("\"cams\" parameter too high!");
-			return -1;
-		}
-	} else if (ov->bridge == BRG_OV511PLUS) {
-		if (cams == 1)
-			size = 961;
-		else if (cams == 2)
-			size = 513;
-		else if (cams == 3 || cams == 4)
-			size = 257;
-		else if (cams >= 5 && cams <= 8)
-			size = 129;
-		else if (cams >= 9 && cams <= 31)
-			size = 33;
-		else {
-			err("\"cams\" parameter too high!");
-			return -1;
-		}
-	} else if (ov->bclass == BCL_OV518) {
-		if (cams == 1)
-			size = 896;
-		else if (cams == 2)
-			size = 512;
-		else if (cams == 3 || cams == 4)
-			size = 256;
-		else if (cams >= 5 && cams <= 8)
-			size = 128;
-		else {
-			err("\"cams\" parameter too high!");
-			return -1;
-		}
-	} else {
-		err("invalid bridge type");
-		return -1;
-	}
-
-	// FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now
-	if (ov->bclass == BCL_OV518) {
-		if (packetsize == -1) {
-			ov518_set_packet_size(ov, 640);
-		} else {
-			dev_info(&ov->dev->dev, "Forcing packet size to %d\n",
-				 packetsize);
-			ov518_set_packet_size(ov, packetsize);
-		}
-	} else {
-		if (packetsize == -1) {
-			ov511_set_packet_size(ov, size);
-		} else {
-			dev_info(&ov->dev->dev, "Forcing packet size to %d\n",
-				 packetsize);
-			ov511_set_packet_size(ov, packetsize);
-		}
-	}
-
-	for (n = 0; n < OV511_NUMSBUF; n++) {
-		urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
-		if (!urb) {
-			err("init isoc: usb_alloc_urb ret. NULL");
-			for (i = 0; i < n; i++)
-				usb_free_urb(ov->sbuf[i].urb);
-			return -ENOMEM;
-		}
-		ov->sbuf[n].urb = urb;
-		urb->dev = ov->dev;
-		urb->context = &ov->sbuf[n];
-		urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS);
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->transfer_buffer = ov->sbuf[n].data;
-		urb->complete = ov51x_isoc_irq;
-		urb->number_of_packets = FRAMES_PER_DESC;
-		urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC;
-		urb->interval = 1;
-		for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
-			urb->iso_frame_desc[fx].offset = ov->packet_size * fx;
-			urb->iso_frame_desc[fx].length = ov->packet_size;
-		}
-	}
-
-	ov->streaming = 1;
-
-	for (n = 0; n < OV511_NUMSBUF; n++) {
-		ov->sbuf[n].urb->dev = ov->dev;
-		err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL);
-		if (err) {
-			err("init isoc: usb_submit_urb(%d) ret %d", n, err);
-			return err;
-		}
-	}
-
-	return 0;
-}
-
-static void
-ov51x_unlink_isoc(struct usb_ov511 *ov)
-{
-	int n;
-
-	/* Unschedule all of the iso td's */
-	for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
-		if (ov->sbuf[n].urb) {
-			usb_kill_urb(ov->sbuf[n].urb);
-			usb_free_urb(ov->sbuf[n].urb);
-			ov->sbuf[n].urb = NULL;
-		}
-	}
-}
-
-static void
-ov51x_stop_isoc(struct usb_ov511 *ov)
-{
-	if (!ov->streaming || !ov->dev)
-		return;
-
-	PDEBUG(3, "*** Stopping capture ***");
-
-	if (ov->bclass == BCL_OV518)
-		ov518_set_packet_size(ov, 0);
-	else
-		ov511_set_packet_size(ov, 0);
-
-	ov->streaming = 0;
-
-	ov51x_unlink_isoc(ov);
-}
-
-static int
-ov51x_new_frame(struct usb_ov511 *ov, int framenum)
-{
-	struct ov511_frame *frame;
-	int newnum;
-
-	PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum);
-
-	if (!ov->dev)
-		return -1;
-
-	/* If we're not grabbing a frame right now and the other frame is */
-	/* ready to be grabbed into, then use it instead */
-	if (ov->curframe == -1) {
-		newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES;
-		if (ov->frame[newnum].grabstate == FRAME_READY)
-			framenum = newnum;
-	} else
-		return 0;
-
-	frame = &ov->frame[framenum];
-
-	PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum,
-	       frame->width, frame->height);
-
-	frame->grabstate = FRAME_GRABBING;
-	frame->scanstate = STATE_SCANNING;
-	frame->snapshot = 0;
-
-	ov->curframe = framenum;
-
-	/* Make sure it's not too big */
-	if (frame->width > ov->maxwidth)
-		frame->width = ov->maxwidth;
-
-	frame->width &= ~7L;		/* Multiple of 8 */
-
-	if (frame->height > ov->maxheight)
-		frame->height = ov->maxheight;
-
-	frame->height &= ~3L;		/* Multiple of 4 */
-
-	return 0;
-}
-
-/****************************************************************************
- *
- * Buffer management
- *
- ***************************************************************************/
-
-/*
- * - You must acquire buf_lock before entering this function.
- * - Because this code will free any non-null pointer, you must be sure to null
- *   them if you explicitly free them somewhere else!
- */
-static void
-ov51x_do_dealloc(struct usb_ov511 *ov)
-{
-	int i;
-	PDEBUG(4, "entered");
-
-	if (ov->fbuf) {
-		rvfree(ov->fbuf, OV511_NUMFRAMES
-		       * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
-		ov->fbuf = NULL;
-	}
-
-	vfree(ov->rawfbuf);
-	ov->rawfbuf = NULL;
-
-	vfree(ov->tempfbuf);
-	ov->tempfbuf = NULL;
-
-	for (i = 0; i < OV511_NUMSBUF; i++) {
-		kfree(ov->sbuf[i].data);
-		ov->sbuf[i].data = NULL;
-	}
-
-	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov->frame[i].data = NULL;
-		ov->frame[i].rawdata = NULL;
-		ov->frame[i].tempdata = NULL;
-		if (ov->frame[i].compbuf) {
-			free_page((unsigned long) ov->frame[i].compbuf);
-			ov->frame[i].compbuf = NULL;
-		}
-	}
-
-	PDEBUG(4, "buffer memory deallocated");
-	ov->buf_state = BUF_NOT_ALLOCATED;
-	PDEBUG(4, "leaving");
-}
-
-static int
-ov51x_alloc(struct usb_ov511 *ov)
-{
-	int i;
-	const int w = ov->maxwidth;
-	const int h = ov->maxheight;
-	const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h);
-	const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
-
-	PDEBUG(4, "entered");
-	mutex_lock(&ov->buf_lock);
-
-	if (ov->buf_state == BUF_ALLOCATED)
-		goto out;
-
-	ov->fbuf = rvmalloc(data_bufsize);
-	if (!ov->fbuf)
-		goto error;
-
-	ov->rawfbuf = vmalloc(raw_bufsize);
-	if (!ov->rawfbuf)
-		goto error;
-
-	memset(ov->rawfbuf, 0, raw_bufsize);
-
-	ov->tempfbuf = vmalloc(raw_bufsize);
-	if (!ov->tempfbuf)
-		goto error;
-
-	memset(ov->tempfbuf, 0, raw_bufsize);
-
-	for (i = 0; i < OV511_NUMSBUF; i++) {
-		ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
-			MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
-		if (!ov->sbuf[i].data)
-			goto error;
-
-		PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
-	}
-
-	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
-		ov->frame[i].rawdata = ov->rawfbuf
-		 + i * MAX_RAW_DATA_SIZE(w, h);
-		ov->frame[i].tempdata = ov->tempfbuf
-		 + i * MAX_RAW_DATA_SIZE(w, h);
-
-		ov->frame[i].compbuf =
-		 (unsigned char *) __get_free_page(GFP_KERNEL);
-		if (!ov->frame[i].compbuf)
-			goto error;
-
-		PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
-	}
-
-	ov->buf_state = BUF_ALLOCATED;
-out:
-	mutex_unlock(&ov->buf_lock);
-	PDEBUG(4, "leaving");
-	return 0;
-error:
-	ov51x_do_dealloc(ov);
-	mutex_unlock(&ov->buf_lock);
-	PDEBUG(4, "errored");
-	return -ENOMEM;
-}
-
-static void
-ov51x_dealloc(struct usb_ov511 *ov)
-{
-	PDEBUG(4, "entered");
-	mutex_lock(&ov->buf_lock);
-	ov51x_do_dealloc(ov);
-	mutex_unlock(&ov->buf_lock);
-	PDEBUG(4, "leaving");
-}
-
-/****************************************************************************
- *
- * V4L 1 API
- *
- ***************************************************************************/
-
-static int
-ov51x_v4l1_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct usb_ov511 *ov = video_get_drvdata(vdev);
-	int err, i;
-
-	PDEBUG(4, "opening");
-
-	mutex_lock(&ov->lock);
-
-	err = -EBUSY;
-	if (ov->user)
-		goto out;
-
-	ov->sub_flag = 0;
-
-	/* In case app doesn't set them... */
-	err = ov51x_set_default_params(ov);
-	if (err < 0)
-		goto out;
-
-	/* Make sure frames are reset */
-	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov->frame[i].grabstate = FRAME_UNUSED;
-		ov->frame[i].bytes_read = 0;
-	}
-
-	/* If compression is on, make sure now that a
-	 * decompressor can be loaded */
-	if (ov->compress && !ov->decomp_ops) {
-		err = request_decompressor(ov);
-		if (err && !dumppix)
-			goto out;
-	}
-
-	err = ov51x_alloc(ov);
-	if (err < 0)
-		goto out;
-
-	err = ov51x_init_isoc(ov);
-	if (err) {
-		ov51x_dealloc(ov);
-		goto out;
-	}
-
-	ov->user++;
-	file->private_data = vdev;
-
-	if (ov->led_policy == LED_AUTO)
-		ov51x_led_control(ov, 1);
-
-out:
-	mutex_unlock(&ov->lock);
-	return err;
-}
-
-static int
-ov51x_v4l1_close(struct file *file)
-{
-	struct video_device *vdev = file->private_data;
-	struct usb_ov511 *ov = video_get_drvdata(vdev);
-
-	PDEBUG(4, "ov511_close");
-
-	mutex_lock(&ov->lock);
-
-	ov->user--;
-	ov51x_stop_isoc(ov);
-
-	if (ov->led_policy == LED_AUTO)
-		ov51x_led_control(ov, 0);
-
-	if (ov->dev)
-		ov51x_dealloc(ov);
-
-	mutex_unlock(&ov->lock);
-
-	/* Device unplugged while open. Only a minimum of unregistration is done
-	 * here; the disconnect callback already did the rest. */
-	if (!ov->dev) {
-		mutex_lock(&ov->cbuf_lock);
-		kfree(ov->cbuf);
-		ov->cbuf = NULL;
-		mutex_unlock(&ov->cbuf_lock);
-
-		ov51x_dealloc(ov);
-		kfree(ov);
-		ov = NULL;
-	}
-
-	file->private_data = NULL;
-	return 0;
-}
-
-/* Do not call this function directly! */
-static long
-ov51x_v4l1_ioctl_internal(struct file *file, unsigned int cmd, void *arg)
-{
-	struct video_device *vdev = file->private_data;
-	struct usb_ov511 *ov = video_get_drvdata(vdev);
-	PDEBUG(5, "IOCtl: 0x%X", cmd);
-
-	if (!ov->dev)
-		return -EIO;
-
-	switch (cmd) {
-	case VIDIOCGCAP:
-	{
-		struct video_capability *b = arg;
-
-		PDEBUG(4, "VIDIOCGCAP");
-
-		memset(b, 0, sizeof(struct video_capability));
-		sprintf(b->name, "%s USB Camera",
-			symbolic(brglist, ov->bridge));
-		b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
-		b->channels = ov->num_inputs;
-		b->audios = 0;
-		b->maxwidth = ov->maxwidth;
-		b->maxheight = ov->maxheight;
-		b->minwidth = ov->minwidth;
-		b->minheight = ov->minheight;
-
-		return 0;
-	}
-	case VIDIOCGCHAN:
-	{
-		struct video_channel *v = arg;
-
-		PDEBUG(4, "VIDIOCGCHAN");
-
-		if ((unsigned)(v->channel) >= ov->num_inputs) {
-			err("Invalid channel (%d)", v->channel);
-			return -EINVAL;
-		}
-
-		v->norm = ov->norm;
-		v->type = VIDEO_TYPE_CAMERA;
-		v->flags = 0;
-//		v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
-		v->tuners = 0;
-		decoder_get_input_name(ov, v->channel, v->name);
-
-		return 0;
-	}
-	case VIDIOCSCHAN:
-	{
-		struct video_channel *v = arg;
-		int err;
-
-		PDEBUG(4, "VIDIOCSCHAN");
-
-		/* Make sure it's not a camera */
-		if (!ov->has_decoder) {
-			if (v->channel == 0)
-				return 0;
-			else
-				return -EINVAL;
-		}
-
-		if (v->norm != VIDEO_MODE_PAL &&
-		    v->norm != VIDEO_MODE_NTSC &&
-		    v->norm != VIDEO_MODE_SECAM &&
-		    v->norm != VIDEO_MODE_AUTO) {
-			err("Invalid norm (%d)", v->norm);
-			return -EINVAL;
-		}
-
-		if ((unsigned)(v->channel) >= ov->num_inputs) {
-			err("Invalid channel (%d)", v->channel);
-			return -EINVAL;
-		}
-
-		err = decoder_set_input(ov, v->channel);
-		if (err)
-			return err;
-
-		err = decoder_set_norm(ov, v->norm);
-		if (err)
-			return err;
-
-		return 0;
-	}
-	case VIDIOCGPICT:
-	{
-		struct video_picture *p = arg;
-
-		PDEBUG(4, "VIDIOCGPICT");
-
-		memset(p, 0, sizeof(struct video_picture));
-		if (sensor_get_picture(ov, p))
-			return -EIO;
-
-		/* Can we get these from frame[0]? -claudio? */
-		p->depth = ov->frame[0].depth;
-		p->palette = ov->frame[0].format;
-
-		return 0;
-	}
-	case VIDIOCSPICT:
-	{
-		struct video_picture *p = arg;
-		int i, rc;
-
-		PDEBUG(4, "VIDIOCSPICT");
-
-		if (!get_depth(p->palette))
-			return -EINVAL;
-
-		if (sensor_set_picture(ov, p))
-			return -EIO;
-
-		if (force_palette && p->palette != force_palette) {
-			dev_info(&ov->dev->dev, "Palette rejected (%s)\n",
-			     symbolic(v4l1_plist, p->palette));
-			return -EINVAL;
-		}
-
-		// FIXME: Format should be independent of frames
-		if (p->palette != ov->frame[0].format) {
-			PDEBUG(4, "Detected format change");
-
-			rc = ov51x_wait_frames_inactive(ov);
-			if (rc)
-				return rc;
-
-			mode_init_regs(ov, ov->frame[0].width,
-				ov->frame[0].height, p->palette, ov->sub_flag);
-		}
-
-		PDEBUG(4, "Setting depth=%d, palette=%s",
-		       p->depth, symbolic(v4l1_plist, p->palette));
-
-		for (i = 0; i < OV511_NUMFRAMES; i++) {
-			ov->frame[i].depth = p->depth;
-			ov->frame[i].format = p->palette;
-		}
-
-		return 0;
-	}
-	case VIDIOCGCAPTURE:
-	{
-		int *vf = arg;
-
-		PDEBUG(4, "VIDIOCGCAPTURE");
-
-		ov->sub_flag = *vf;
-		return 0;
-	}
-	case VIDIOCSCAPTURE:
-	{
-		struct video_capture *vc = arg;
-
-		PDEBUG(4, "VIDIOCSCAPTURE");
-
-		if (vc->flags)
-			return -EINVAL;
-		if (vc->decimation)
-			return -EINVAL;
-
-		vc->x &= ~3L;
-		vc->y &= ~1L;
-		vc->y &= ~31L;
-
-		if (vc->width == 0)
-			vc->width = 32;
-
-		vc->height /= 16;
-		vc->height *= 16;
-		if (vc->height == 0)
-			vc->height = 16;
-
-		ov->subx = vc->x;
-		ov->suby = vc->y;
-		ov->subw = vc->width;
-		ov->subh = vc->height;
-
-		return 0;
-	}
-	case VIDIOCSWIN:
-	{
-		struct video_window *vw = arg;
-		int i, rc;
-
-		PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
-
-#if 0
-		if (vw->flags)
-			return -EINVAL;
-		if (vw->clipcount)
-			return -EINVAL;
-		if (vw->height != ov->maxheight)
-			return -EINVAL;
-		if (vw->width != ov->maxwidth)
-			return -EINVAL;
-#endif
-
-		rc = ov51x_wait_frames_inactive(ov);
-		if (rc)
-			return rc;
-
-		rc = mode_init_regs(ov, vw->width, vw->height,
-			ov->frame[0].format, ov->sub_flag);
-		if (rc < 0)
-			return rc;
-
-		for (i = 0; i < OV511_NUMFRAMES; i++) {
-			ov->frame[i].width = vw->width;
-			ov->frame[i].height = vw->height;
-		}
-
-		return 0;
-	}
-	case VIDIOCGWIN:
-	{
-		struct video_window *vw = arg;
-
-		memset(vw, 0, sizeof(struct video_window));
-		vw->x = 0;		/* FIXME */
-		vw->y = 0;
-		vw->width = ov->frame[0].width;
-		vw->height = ov->frame[0].height;
-		vw->flags = 30;
-
-		PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height);
-
-		return 0;
-	}
-	case VIDIOCGMBUF:
-	{
-		struct video_mbuf *vm = arg;
-		int i;
-
-		PDEBUG(4, "VIDIOCGMBUF");
-
-		memset(vm, 0, sizeof(struct video_mbuf));
-		vm->size = OV511_NUMFRAMES
-			   * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
-		vm->frames = OV511_NUMFRAMES;
-
-		vm->offsets[0] = 0;
-		for (i = 1; i < OV511_NUMFRAMES; i++) {
-			vm->offsets[i] = vm->offsets[i-1]
-			   + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
-		}
-
-		return 0;
-	}
-	case VIDIOCMCAPTURE:
-	{
-		struct video_mmap *vm = arg;
-		int rc, depth;
-		unsigned int f = vm->frame;
-
-		PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
-			vm->height, symbolic(v4l1_plist, vm->format));
-
-		depth = get_depth(vm->format);
-		if (!depth) {
-			PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)",
-			       symbolic(v4l1_plist, vm->format));
-			return -EINVAL;
-		}
-
-		if (f >= OV511_NUMFRAMES) {
-			err("VIDIOCMCAPTURE: invalid frame (%d)", f);
-			return -EINVAL;
-		}
-
-		if (vm->width > ov->maxwidth
-		    || vm->height > ov->maxheight) {
-			err("VIDIOCMCAPTURE: requested dimensions too big");
-			return -EINVAL;
-		}
-
-		if (ov->frame[f].grabstate == FRAME_GRABBING) {
-			PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
-			return -EBUSY;
-		}
-
-		if (force_palette && (vm->format != force_palette)) {
-			PDEBUG(2, "palette rejected (%s)",
-			       symbolic(v4l1_plist, vm->format));
-			return -EINVAL;
-		}
-
-		if ((ov->frame[f].width != vm->width) ||
-		    (ov->frame[f].height != vm->height) ||
-		    (ov->frame[f].format != vm->format) ||
-		    (ov->frame[f].sub_flag != ov->sub_flag) ||
-		    (ov->frame[f].depth != depth)) {
-			PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
-
-			rc = ov51x_wait_frames_inactive(ov);
-			if (rc)
-				return rc;
-
-			rc = mode_init_regs(ov, vm->width, vm->height,
-				vm->format, ov->sub_flag);
-#if 0
-			if (rc < 0) {
-				PDEBUG(1, "Got error while initializing regs ");
-				return ret;
-			}
-#endif
-			ov->frame[f].width = vm->width;
-			ov->frame[f].height = vm->height;
-			ov->frame[f].format = vm->format;
-			ov->frame[f].sub_flag = ov->sub_flag;
-			ov->frame[f].depth = depth;
-		}
-
-		/* Mark it as ready */
-		ov->frame[f].grabstate = FRAME_READY;
-
-		PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f);
-
-		return ov51x_new_frame(ov, f);
-	}
-	case VIDIOCSYNC:
-	{
-		unsigned int fnum = *((unsigned int *) arg);
-		struct ov511_frame *frame;
-		int rc;
-
-		if (fnum >= OV511_NUMFRAMES) {
-			err("VIDIOCSYNC: invalid frame (%d)", fnum);
-			return -EINVAL;
-		}
-
-		frame = &ov->frame[fnum];
-
-		PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum,
-		       frame->grabstate);
-
-		switch (frame->grabstate) {
-		case FRAME_UNUSED:
-			return -EINVAL;
-		case FRAME_READY:
-		case FRAME_GRABBING:
-		case FRAME_ERROR:
-redo:
-			if (!ov->dev)
-				return -EIO;
-
-			rc = wait_event_interruptible(frame->wq,
-			    (frame->grabstate == FRAME_DONE)
-			    || (frame->grabstate == FRAME_ERROR));
-
-			if (rc)
-				return rc;
-
-			if (frame->grabstate == FRAME_ERROR) {
-				if ((rc = ov51x_new_frame(ov, fnum)) < 0)
-					return rc;
-				goto redo;
-			}
-			/* Fall through */
-		case FRAME_DONE:
-			if (ov->snap_enabled && !frame->snapshot) {
-				if ((rc = ov51x_new_frame(ov, fnum)) < 0)
-					return rc;
-				goto redo;
-			}
-
-			frame->grabstate = FRAME_UNUSED;
-
-			/* Reset the hardware snapshot button */
-			/* FIXME - Is this the best place for this? */
-			if ((ov->snap_enabled) && (frame->snapshot)) {
-				frame->snapshot = 0;
-				ov51x_clear_snapshot(ov);
-			}
-
-			/* Decompression, format conversion, etc... */
-			ov51x_postprocess(ov, frame);
-
-			break;
-		} /* end switch */
-
-		return 0;
-	}
-	case VIDIOCGFBUF:
-	{
-		struct video_buffer *vb = arg;
-
-		PDEBUG(4, "VIDIOCGFBUF");
-
-		memset(vb, 0, sizeof(struct video_buffer));
-
-		return 0;
-	}
-	case VIDIOCGUNIT:
-	{
-		struct video_unit *vu = arg;
-
-		PDEBUG(4, "VIDIOCGUNIT");
-
-		memset(vu, 0, sizeof(struct video_unit));
-
-		vu->video = ov->vdev->minor;
-		vu->vbi = VIDEO_NO_UNIT;
-		vu->radio = VIDEO_NO_UNIT;
-		vu->audio = VIDEO_NO_UNIT;
-		vu->teletext = VIDEO_NO_UNIT;
-
-		return 0;
-	}
-	case OV511IOC_WI2C:
-	{
-		struct ov511_i2c_struct *w = arg;
-
-		return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask);
-	}
-	case OV511IOC_RI2C:
-	{
-		struct ov511_i2c_struct *r = arg;
-		int rc;
-
-		rc = i2c_r_slave(ov, r->slave, r->reg);
-		if (rc < 0)
-			return rc;
-
-		r->value = rc;
-		return 0;
-	}
-	default:
-		PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
-		return -ENOIOCTLCMD;
-	} /* end switch */
-
-	return 0;
-}
-
-static long
-ov51x_v4l1_ioctl(struct file *file,
-		 unsigned int cmd, unsigned long arg)
-{
-	struct video_device *vdev = file->private_data;
-	struct usb_ov511 *ov = video_get_drvdata(vdev);
-	int rc;
-
-	if (mutex_lock_interruptible(&ov->lock))
-		return -EINTR;
-
-	rc = video_usercopy(file, cmd, arg, ov51x_v4l1_ioctl_internal);
-
-	mutex_unlock(&ov->lock);
-	return rc;
-}
-
-static ssize_t
-ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
-{
-	struct video_device *vdev = file->private_data;
-	int noblock = file->f_flags&O_NONBLOCK;
-	unsigned long count = cnt;
-	struct usb_ov511 *ov = video_get_drvdata(vdev);
-	int i, rc = 0, frmx = -1;
-	struct ov511_frame *frame;
-
-	if (mutex_lock_interruptible(&ov->lock))
-		return -EINTR;
-
-	PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
-
-	if (!vdev || !buf) {
-		rc = -EFAULT;
-		goto error;
-	}
-
-	if (!ov->dev) {
-		rc = -EIO;
-		goto error;
-	}
-
-// FIXME: Only supports two frames
-	/* See if a frame is completed, then use it. */
-	if (ov->frame[0].grabstate >= FRAME_DONE)	/* _DONE or _ERROR */
-		frmx = 0;
-	else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
-		frmx = 1;
-
-	/* If nonblocking we return immediately */
-	if (noblock && (frmx == -1)) {
-		rc = -EAGAIN;
-		goto error;
-	}
-
-	/* If no FRAME_DONE, look for a FRAME_GRABBING state. */
-	/* See if a frame is in process (grabbing), then use it. */
-	if (frmx == -1) {
-		if (ov->frame[0].grabstate == FRAME_GRABBING)
-			frmx = 0;
-		else if (ov->frame[1].grabstate == FRAME_GRABBING)
-			frmx = 1;
-	}
-
-	/* If no frame is active, start one. */
-	if (frmx == -1) {
-		if ((rc = ov51x_new_frame(ov, frmx = 0))) {
-			err("read: ov51x_new_frame error");
-			goto error;
-		}
-	}
-
-	frame = &ov->frame[frmx];
-
-restart:
-	if (!ov->dev) {
-		rc = -EIO;
-		goto error;
-	}
-
-	/* Wait while we're grabbing the image */
-	PDEBUG(4, "Waiting image grabbing");
-	rc = wait_event_interruptible(frame->wq,
-		(frame->grabstate == FRAME_DONE)
-		|| (frame->grabstate == FRAME_ERROR));
-
-	if (rc)
-		goto error;
-
-	PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate);
-	PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd);
-
-	if (frame->grabstate == FRAME_ERROR) {
-		frame->bytes_read = 0;
-		err("** ick! ** Errored frame %d", ov->curframe);
-		if (ov51x_new_frame(ov, frmx)) {
-			err("read: ov51x_new_frame error");
-			goto error;
-		}
-		goto restart;
-	}
-
-
-	/* Repeat until we get a snapshot frame */
-	if (ov->snap_enabled)
-		PDEBUG(4, "Waiting snapshot frame");
-	if (ov->snap_enabled && !frame->snapshot) {
-		frame->bytes_read = 0;
-		if ((rc = ov51x_new_frame(ov, frmx))) {
-			err("read: ov51x_new_frame error");
-			goto error;
-		}
-		goto restart;
-	}
-
-	/* Clear the snapshot */
-	if (ov->snap_enabled && frame->snapshot) {
-		frame->snapshot = 0;
-		ov51x_clear_snapshot(ov);
-	}
-
-	/* Decompression, format conversion, etc... */
-	ov51x_postprocess(ov, frame);
-
-	PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx,
-		frame->bytes_read,
-		get_frame_length(frame));
-
-	/* copy bytes to user space; we allow for partials reads */
-//	if ((count + frame->bytes_read)
-//	    > get_frame_length((struct ov511_frame *)frame))
-//		count = frame->scanlength - frame->bytes_read;
-
-	/* FIXME - count hardwired to be one frame... */
-	count = get_frame_length(frame);
-
-	PDEBUG(4, "Copy to user space: %ld bytes", count);
-	if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) {
-		PDEBUG(4, "Copy failed! %d bytes not copied", i);
-		rc = -EFAULT;
-		goto error;
-	}
-
-	frame->bytes_read += count;
-	PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld",
-		count, frame->bytes_read);
-
-	/* If all data have been read... */
-	if (frame->bytes_read
-	    >= get_frame_length(frame)) {
-		frame->bytes_read = 0;
-
-// FIXME: Only supports two frames
-		/* Mark it as available to be used again. */
-		ov->frame[frmx].grabstate = FRAME_UNUSED;
-		if ((rc = ov51x_new_frame(ov, !frmx))) {
-			err("ov51x_new_frame returned error");
-			goto error;
-		}
-	}
-
-	PDEBUG(4, "read finished, returning %ld (sweet)", count);
-
-	mutex_unlock(&ov->lock);
-	return count;
-
-error:
-	mutex_unlock(&ov->lock);
-	return rc;
-}
-
-static int
-ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct video_device *vdev = file->private_data;
-	unsigned long start = vma->vm_start;
-	unsigned long size  = vma->vm_end - vma->vm_start;
-	struct usb_ov511 *ov = video_get_drvdata(vdev);
-	unsigned long page, pos;
-
-	if (ov->dev == NULL)
-		return -EIO;
-
-	PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
-
-	if (size > (((OV511_NUMFRAMES
-		      * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)
-		      + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
-		return -EINVAL;
-
-	if (mutex_lock_interruptible(&ov->lock))
-		return -EINTR;
-
-	pos = (unsigned long)ov->fbuf;
-	while (size > 0) {
-		page = vmalloc_to_pfn((void *)pos);
-		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			mutex_unlock(&ov->lock);
-			return -EAGAIN;
-		}
-		start += PAGE_SIZE;
-		pos += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
-	}
-
-	mutex_unlock(&ov->lock);
-	return 0;
-}
-
-static const struct v4l2_file_operations ov511_fops = {
-	.owner =	THIS_MODULE,
-	.open =		ov51x_v4l1_open,
-	.release =	ov51x_v4l1_close,
-	.read =		ov51x_v4l1_read,
-	.mmap =		ov51x_v4l1_mmap,
-	.ioctl =	ov51x_v4l1_ioctl,
-};
-
-static struct video_device vdev_template = {
-	.name =		"OV511 USB Camera",
-	.fops =		&ov511_fops,
-	.release =	video_device_release,
-};
-
-/****************************************************************************
- *
- * OV511 and sensor configuration
- *
- ***************************************************************************/
-
-/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
- * the same register settings as the OV7610, since they are very similar.
- */
-static int
-ov7xx0_configure(struct usb_ov511 *ov)
-{
-	int i, success;
-	int rc;
-
-	/* Lawrence Glaister <lg@jfm.bc.ca> reports:
-	 *
-	 * Register 0x0f in the 7610 has the following effects:
-	 *
-	 * 0x85 (AEC method 1): Best overall, good contrast range
-	 * 0x45 (AEC method 2): Very overexposed
-	 * 0xa5 (spec sheet default): Ok, but the black level is
-	 *	shifted resulting in loss of contrast
-	 * 0x05 (old driver setting): very overexposed, too much
-	 *	contrast
-	 */
-	static struct ov511_regvals aRegvalsNorm7610[] = {
-		{ OV511_I2C_BUS, 0x10, 0xff },
-		{ OV511_I2C_BUS, 0x16, 0x06 },
-		{ OV511_I2C_BUS, 0x28, 0x24 },
-		{ OV511_I2C_BUS, 0x2b, 0xac },
-		{ OV511_I2C_BUS, 0x12, 0x00 },
-		{ OV511_I2C_BUS, 0x38, 0x81 },
-		{ OV511_I2C_BUS, 0x28, 0x24 },	/* 0c */
-		{ OV511_I2C_BUS, 0x0f, 0x85 },	/* lg's setting */
-		{ OV511_I2C_BUS, 0x15, 0x01 },
-		{ OV511_I2C_BUS, 0x20, 0x1c },
-		{ OV511_I2C_BUS, 0x23, 0x2a },
-		{ OV511_I2C_BUS, 0x24, 0x10 },
-		{ OV511_I2C_BUS, 0x25, 0x8a },
-		{ OV511_I2C_BUS, 0x26, 0xa2 },
-		{ OV511_I2C_BUS, 0x27, 0xc2 },
-		{ OV511_I2C_BUS, 0x2a, 0x04 },
-		{ OV511_I2C_BUS, 0x2c, 0xfe },
-		{ OV511_I2C_BUS, 0x2d, 0x93 },
-		{ OV511_I2C_BUS, 0x30, 0x71 },
-		{ OV511_I2C_BUS, 0x31, 0x60 },
-		{ OV511_I2C_BUS, 0x32, 0x26 },
-		{ OV511_I2C_BUS, 0x33, 0x20 },
-		{ OV511_I2C_BUS, 0x34, 0x48 },
-		{ OV511_I2C_BUS, 0x12, 0x24 },
-		{ OV511_I2C_BUS, 0x11, 0x01 },
-		{ OV511_I2C_BUS, 0x0c, 0x24 },
-		{ OV511_I2C_BUS, 0x0d, 0x24 },
-		{ OV511_DONE_BUS, 0x0, 0x00 },
-	};
-
-	static struct ov511_regvals aRegvalsNorm7620[] = {
-		{ OV511_I2C_BUS, 0x00, 0x00 },
-		{ OV511_I2C_BUS, 0x01, 0x80 },
-		{ OV511_I2C_BUS, 0x02, 0x80 },
-		{ OV511_I2C_BUS, 0x03, 0xc0 },
-		{ OV511_I2C_BUS, 0x06, 0x60 },
-		{ OV511_I2C_BUS, 0x07, 0x00 },
-		{ OV511_I2C_BUS, 0x0c, 0x24 },
-		{ OV511_I2C_BUS, 0x0c, 0x24 },
-		{ OV511_I2C_BUS, 0x0d, 0x24 },
-		{ OV511_I2C_BUS, 0x11, 0x01 },
-		{ OV511_I2C_BUS, 0x12, 0x24 },
-		{ OV511_I2C_BUS, 0x13, 0x01 },
-		{ OV511_I2C_BUS, 0x14, 0x84 },
-		{ OV511_I2C_BUS, 0x15, 0x01 },
-		{ OV511_I2C_BUS, 0x16, 0x03 },
-		{ OV511_I2C_BUS, 0x17, 0x2f },
-		{ OV511_I2C_BUS, 0x18, 0xcf },
-		{ OV511_I2C_BUS, 0x19, 0x06 },
-		{ OV511_I2C_BUS, 0x1a, 0xf5 },
-		{ OV511_I2C_BUS, 0x1b, 0x00 },
-		{ OV511_I2C_BUS, 0x20, 0x18 },
-		{ OV511_I2C_BUS, 0x21, 0x80 },
-		{ OV511_I2C_BUS, 0x22, 0x80 },
-		{ OV511_I2C_BUS, 0x23, 0x00 },
-		{ OV511_I2C_BUS, 0x26, 0xa2 },
-		{ OV511_I2C_BUS, 0x27, 0xea },
-		{ OV511_I2C_BUS, 0x28, 0x20 },
-		{ OV511_I2C_BUS, 0x29, 0x00 },
-		{ OV511_I2C_BUS, 0x2a, 0x10 },
-		{ OV511_I2C_BUS, 0x2b, 0x00 },
-		{ OV511_I2C_BUS, 0x2c, 0x88 },
-		{ OV511_I2C_BUS, 0x2d, 0x91 },
-		{ OV511_I2C_BUS, 0x2e, 0x80 },
-		{ OV511_I2C_BUS, 0x2f, 0x44 },
-		{ OV511_I2C_BUS, 0x60, 0x27 },
-		{ OV511_I2C_BUS, 0x61, 0x02 },
-		{ OV511_I2C_BUS, 0x62, 0x5f },
-		{ OV511_I2C_BUS, 0x63, 0xd5 },
-		{ OV511_I2C_BUS, 0x64, 0x57 },
-		{ OV511_I2C_BUS, 0x65, 0x83 },
-		{ OV511_I2C_BUS, 0x66, 0x55 },
-		{ OV511_I2C_BUS, 0x67, 0x92 },
-		{ OV511_I2C_BUS, 0x68, 0xcf },
-		{ OV511_I2C_BUS, 0x69, 0x76 },
-		{ OV511_I2C_BUS, 0x6a, 0x22 },
-		{ OV511_I2C_BUS, 0x6b, 0x00 },
-		{ OV511_I2C_BUS, 0x6c, 0x02 },
-		{ OV511_I2C_BUS, 0x6d, 0x44 },
-		{ OV511_I2C_BUS, 0x6e, 0x80 },
-		{ OV511_I2C_BUS, 0x6f, 0x1d },
-		{ OV511_I2C_BUS, 0x70, 0x8b },
-		{ OV511_I2C_BUS, 0x71, 0x00 },
-		{ OV511_I2C_BUS, 0x72, 0x14 },
-		{ OV511_I2C_BUS, 0x73, 0x54 },
-		{ OV511_I2C_BUS, 0x74, 0x00 },
-		{ OV511_I2C_BUS, 0x75, 0x8e },
-		{ OV511_I2C_BUS, 0x76, 0x00 },
-		{ OV511_I2C_BUS, 0x77, 0xff },
-		{ OV511_I2C_BUS, 0x78, 0x80 },
-		{ OV511_I2C_BUS, 0x79, 0x80 },
-		{ OV511_I2C_BUS, 0x7a, 0x80 },
-		{ OV511_I2C_BUS, 0x7b, 0xe2 },
-		{ OV511_I2C_BUS, 0x7c, 0x00 },
-		{ OV511_DONE_BUS, 0x0, 0x00 },
-	};
-
-	PDEBUG(4, "starting configuration");
-
-	/* This looks redundant, but is necessary for WebCam 3 */
-	ov->primary_i2c_slave = OV7xx0_SID;
-	if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
-		return -1;
-
-	if (init_ov_sensor(ov) >= 0) {
-		PDEBUG(1, "OV7xx0 sensor initalized (method 1)");
-	} else {
-		/* Reset the 76xx */
-		if (i2c_w(ov, 0x12, 0x80) < 0)
-			return -1;
-
-		/* Wait for it to initialize */
-		msleep(150);
-
-		i = 0;
-		success = 0;
-		while (i <= i2c_detect_tries) {
-			if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
-			    (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
-				success = 1;
-				break;
-			} else {
-				i++;
-			}
-		}
-
-// Was (i == i2c_detect_tries) previously. This obviously used to always report
-// success. Whether anyone actually depended on that bug is unknown
-		if ((i >= i2c_detect_tries) && (success == 0)) {
-			err("Failed to read sensor ID. You might not have an");
-			err("OV7610/20, or it may be not responding. Report");
-			err("this to " EMAIL);
-			err("This is only a warning. You can attempt to use");
-			err("your camera anyway");
-// Only issue a warning for now
-//			return -1;
-		} else {
-			PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1);
-		}
-	}
-
-	/* Detect sensor (sub)type */
-	rc = i2c_r(ov, OV7610_REG_COM_I);
-
-	if (rc < 0) {
-		err("Error detecting sensor type");
-		return -1;
-	} else if ((rc & 3) == 3) {
-		dev_info(&ov->dev->dev, "Sensor is an OV7610\n");
-		ov->sensor = SEN_OV7610;
-	} else if ((rc & 3) == 1) {
-		/* I don't know what's different about the 76BE yet. */
-		if (i2c_r(ov, 0x15) & 1)
-			dev_info(&ov->dev->dev, "Sensor is an OV7620AE\n");
-		else
-			dev_info(&ov->dev->dev, "Sensor is an OV76BE\n");
-
-		/* OV511+ will return all zero isoc data unless we
-		 * configure the sensor as a 7620. Someone needs to
-		 * find the exact reg. setting that causes this. */
-		if (ov->bridge == BRG_OV511PLUS) {
-			dev_info(&ov->dev->dev,
-				 "Enabling 511+/7620AE workaround\n");
-			ov->sensor = SEN_OV7620;
-		} else {
-			ov->sensor = SEN_OV76BE;
-		}
-	} else if ((rc & 3) == 0) {
-		dev_info(&ov->dev->dev, "Sensor is an OV7620\n");
-		ov->sensor = SEN_OV7620;
-	} else {
-		err("Unknown image sensor version: %d", rc & 3);
-		return -1;
-	}
-
-	if (ov->sensor == SEN_OV7620) {
-		PDEBUG(4, "Writing 7620 registers");
-		if (write_regvals(ov, aRegvalsNorm7620))
-			return -1;
-	} else {
-		PDEBUG(4, "Writing 7610 registers");
-		if (write_regvals(ov, aRegvalsNorm7610))
-			return -1;
-	}
-
-	/* Set sensor-specific vars */
-	ov->maxwidth = 640;
-	ov->maxheight = 480;
-	ov->minwidth = 64;
-	ov->minheight = 48;
-
-	// FIXME: These do not match the actual settings yet
-	ov->brightness = 0x80 << 8;
-	ov->contrast = 0x80 << 8;
-	ov->colour = 0x80 << 8;
-	ov->hue = 0x80 << 8;
-
-	return 0;
-}
-
-/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
-static int
-ov6xx0_configure(struct usb_ov511 *ov)
-{
-	int rc;
-
-	static struct ov511_regvals aRegvalsNorm6x20[] = {
-		{ OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
-		{ OV511_I2C_BUS, 0x11, 0x01 },
-		{ OV511_I2C_BUS, 0x03, 0x60 },
-		{ OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
-		{ OV511_I2C_BUS, 0x07, 0xa8 },
-		/* The ratio of 0x0c and 0x0d  controls the white point */
-		{ OV511_I2C_BUS, 0x0c, 0x24 },
-		{ OV511_I2C_BUS, 0x0d, 0x24 },
-		{ OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */
-		{ OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */
-		{ OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */
-		{ OV511_I2C_BUS, 0x14, 0x04 },
-		/* 0x16: 0x06 helps frame stability with moving objects */
-		{ OV511_I2C_BUS, 0x16, 0x06 },
-//		{ OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
-		{ OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
-		/* 0x28: 0x05 Selects RGB format if RGB on */
-		{ OV511_I2C_BUS, 0x28, 0x05 },
-		{ OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
-//		{ OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
-		{ OV511_I2C_BUS, 0x2d, 0x99 },
-		{ OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Processing Parameter */
-		{ OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */
-		{ OV511_I2C_BUS, 0x38, 0x8b },
-		{ OV511_I2C_BUS, 0x39, 0x40 },
-
-		{ OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
-		{ OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
-		{ OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
-
-		{ OV511_I2C_BUS, 0x3d, 0x80 },
-		/* These next two registers (0x4a, 0x4b) are undocumented. They
-		 * control the color balance */
-		{ OV511_I2C_BUS, 0x4a, 0x80 },
-		{ OV511_I2C_BUS, 0x4b, 0x80 },
-		{ OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */
-		{ OV511_I2C_BUS, 0x4e, 0xc1 },
-		{ OV511_I2C_BUS, 0x4f, 0x04 },
-// Do 50-53 have any effect?
-// Toggle 0x12[2] off and on here?
-		{ OV511_DONE_BUS, 0x0, 0x00 },	/* END MARKER */
-	};
-
-	static struct ov511_regvals aRegvalsNorm6x30[] = {
-	/*OK*/	{ OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
-		{ OV511_I2C_BUS, 0x11, 0x00 },
-	/*OK*/	{ OV511_I2C_BUS, 0x03, 0x60 },
-	/*0A?*/	{ OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
-		{ OV511_I2C_BUS, 0x07, 0xa8 },
-		/* The ratio of 0x0c and 0x0d  controls the white point */
-	/*OK*/	{ OV511_I2C_BUS, 0x0c, 0x24 },
-	/*OK*/	{ OV511_I2C_BUS, 0x0d, 0x24 },
-	/*A*/	{ OV511_I2C_BUS, 0x0e, 0x20 },
-//	/*04?*/	{ OV511_I2C_BUS, 0x14, 0x80 },
-		{ OV511_I2C_BUS, 0x16, 0x03 },
-//	/*OK*/	{ OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
-		// 21 & 22? The suggested values look wrong. Go with default
-	/*A*/	{ OV511_I2C_BUS, 0x23, 0xc0 },
-	/*A*/	{ OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default
-//	/*OK*/	{ OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
-
-		/* 0x28: 0x05 Selects RGB format if RGB on */
-//	/*04?*/	{ OV511_I2C_BUS, 0x28, 0x05 },
-//	/*04?*/	{ OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus
-
-	/*OK*/	{ OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
-//	/*OK*/	{ OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
-		{ OV511_I2C_BUS, 0x2d, 0x99 },
-//	/*A*/	{ OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620
-//	/*d2?*/	{ OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */
-//	/*8b?*/	{ OV511_I2C_BUS, 0x38, 0x83 },
-//	/*40?*/	{ OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7
-//		{ OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
-//		{ OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
-//		{ OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
-		{ OV511_I2C_BUS, 0x3d, 0x80 },
-//	/*A*/	{ OV511_I2C_BUS, 0x3f, 0x0e },
-
-		/* These next two registers (0x4a, 0x4b) are undocumented. They
-		 * control the color balance */
-//	/*OK?*/	{ OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
-//	/*OK?*/	{ OV511_I2C_BUS, 0x4b, 0x80 },
-		{ OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
-	/*c1?*/	{ OV511_I2C_BUS, 0x4e, 0x40 },
-
-		/* UV average mode, color killer: strongest */
-		{ OV511_I2C_BUS, 0x4f, 0x07 },
-
-		{ OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */
-		{ OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */
-		{ OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */
-		{ OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */
-		{ OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */
-//		{ OV511_I2C_BUS, 0x5c, 0x10 },
-		{ OV511_DONE_BUS, 0x0, 0x00 },	/* END MARKER */
-	};
-
-	PDEBUG(4, "starting sensor configuration");
-
-	if (init_ov_sensor(ov) < 0) {
-		err("Failed to read sensor ID. You might not have an OV6xx0,");
-		err("or it may be not responding. Report this to " EMAIL);
-		return -1;
-	} else {
-		PDEBUG(1, "OV6xx0 sensor detected");
-	}
-
-	/* Detect sensor (sub)type */
-	rc = i2c_r(ov, OV7610_REG_COM_I);
-
-	if (rc < 0) {
-		err("Error detecting sensor type");
-		return -1;
-	}
-
-	if ((rc & 3) == 0) {
-		ov->sensor = SEN_OV6630;
-		dev_info(&ov->dev->dev, "Sensor is an OV6630\n");
-	} else if ((rc & 3) == 1) {
-		ov->sensor = SEN_OV6620;
-		dev_info(&ov->dev->dev, "Sensor is an OV6620\n");
-	} else if ((rc & 3) == 2) {
-		ov->sensor = SEN_OV6630;
-		dev_info(&ov->dev->dev, "Sensor is an OV6630AE\n");
-	} else if ((rc & 3) == 3) {
-		ov->sensor = SEN_OV6630;
-		dev_info(&ov->dev->dev, "Sensor is an OV6630AF\n");
-	}
-
-	/* Set sensor-specific vars */
-	ov->maxwidth = 352;
-	ov->maxheight = 288;
-	ov->minwidth = 64;
-	ov->minheight = 48;
-
-	// FIXME: These do not match the actual settings yet
-	ov->brightness = 0x80 << 8;
-	ov->contrast = 0x80 << 8;
-	ov->colour = 0x80 << 8;
-	ov->hue = 0x80 << 8;
-
-	if (ov->sensor == SEN_OV6620) {
-		PDEBUG(4, "Writing 6x20 registers");
-		if (write_regvals(ov, aRegvalsNorm6x20))
-			return -1;
-	} else {
-		PDEBUG(4, "Writing 6x30 registers");
-		if (write_regvals(ov, aRegvalsNorm6x30))
-			return -1;
-	}
-
-	return 0;
-}
-
-/* This initializes the KS0127 and KS0127B video decoders. */
-static int
-ks0127_configure(struct usb_ov511 *ov)
-{
-	int rc;
-
-// FIXME: I don't know how to sync or reset it yet
-#if 0
-	if (ov51x_init_ks_sensor(ov) < 0) {
-		err("Failed to initialize the KS0127");
-		return -1;
-	} else {
-		PDEBUG(1, "KS012x(B) sensor detected");
-	}
-#endif
-
-	/* Detect decoder subtype */
-	rc = i2c_r(ov, 0x00);
-	if (rc < 0) {
-		err("Error detecting sensor type");
-		return -1;
-	} else if (rc & 0x08) {
-		rc = i2c_r(ov, 0x3d);
-		if (rc < 0) {
-			err("Error detecting sensor type");
-			return -1;
-		} else if ((rc & 0x0f) == 0) {
-			dev_info(&ov->dev->dev, "Sensor is a KS0127\n");
-			ov->sensor = SEN_KS0127;
-		} else if ((rc & 0x0f) == 9) {
-			dev_info(&ov->dev->dev, "Sensor is a KS0127B Rev. A\n");
-			ov->sensor = SEN_KS0127B;
-		}
-	} else {
-		err("Error: Sensor is an unsupported KS0122");
-		return -1;
-	}
-
-	/* Set sensor-specific vars */
-	ov->maxwidth = 640;
-	ov->maxheight = 480;
-	ov->minwidth = 64;
-	ov->minheight = 48;
-
-	// FIXME: These do not match the actual settings yet
-	ov->brightness = 0x80 << 8;
-	ov->contrast = 0x80 << 8;
-	ov->colour = 0x80 << 8;
-	ov->hue = 0x80 << 8;
-
-	/* This device is not supported yet. Bail out now... */
-	err("This sensor is not supported yet.");
-	return -1;
-
-	return 0;
-}
-
-/* This initializes the SAA7111A video decoder. */
-static int
-saa7111a_configure(struct usb_ov511 *ov)
-{
-	int rc;
-
-	/* Since there is no register reset command, all registers must be
-	 * written, otherwise gives erratic results */
-	static struct ov511_regvals aRegvalsNormSAA7111A[] = {
-		{ OV511_I2C_BUS, 0x06, 0xce },
-		{ OV511_I2C_BUS, 0x07, 0x00 },
-		{ OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */
-		{ OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */
-		{ OV511_I2C_BUS, 0x00, 0x00 },
-		{ OV511_I2C_BUS, 0x01, 0x00 },
-		{ OV511_I2C_BUS, 0x03, 0x23 },
-		{ OV511_I2C_BUS, 0x04, 0x00 },
-		{ OV511_I2C_BUS, 0x05, 0x00 },
-		{ OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */
-		{ OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */
-		{ OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */
-		{ OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */
-		{ OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */
-		{ OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */
-		{ OV511_I2C_BUS, 0x0f, 0x00 },
-		{ OV511_I2C_BUS, 0x11, 0x0c },
-		{ OV511_I2C_BUS, 0x12, 0x00 },
-		{ OV511_I2C_BUS, 0x13, 0x00 },
-		{ OV511_I2C_BUS, 0x14, 0x00 },
-		{ OV511_I2C_BUS, 0x15, 0x00 },
-		{ OV511_I2C_BUS, 0x16, 0x00 },
-		{ OV511_I2C_BUS, 0x17, 0x00 },
-		{ OV511_I2C_BUS, 0x02, 0xc0 },	/* Composite input 0 */
-		{ OV511_DONE_BUS, 0x0, 0x00 },
-	};
-
-// FIXME: I don't know how to sync or reset it yet
-#if 0
-	if (ov51x_init_saa_sensor(ov) < 0) {
-		err("Failed to initialize the SAA7111A");
-		return -1;
-	} else {
-		PDEBUG(1, "SAA7111A sensor detected");
-	}
-#endif
-
-	/* 640x480 not supported with PAL */
-	if (ov->pal) {
-		ov->maxwidth = 320;
-		ov->maxheight = 240;		/* Even field only */
-	} else {
-		ov->maxwidth = 640;
-		ov->maxheight = 480;		/* Even/Odd fields */
-	}
-
-	ov->minwidth = 320;
-	ov->minheight = 240;		/* Even field only */
-
-	ov->has_decoder = 1;
-	ov->num_inputs = 8;
-	ov->norm = VIDEO_MODE_AUTO;
-	ov->stop_during_set = 0;	/* Decoder guarantees stable image */
-
-	/* Decoder doesn't change these values, so we use these instead of
-	 * acutally reading the registers (which doesn't work) */
-	ov->brightness = 0x80 << 8;
-	ov->contrast = 0x40 << 9;
-	ov->colour = 0x40 << 9;
-	ov->hue = 32768;
-
-	PDEBUG(4, "Writing SAA7111A registers");
-	if (write_regvals(ov, aRegvalsNormSAA7111A))
-		return -1;
-
-	/* Detect version of decoder. This must be done after writing the
-	 * initial regs or the decoder will lock up. */
-	rc = i2c_r(ov, 0x00);
-
-	if (rc < 0) {
-		err("Error detecting sensor version");
-		return -1;
-	} else {
-		dev_info(&ov->dev->dev,
-			 "Sensor is an SAA7111A (version 0x%x)\n", rc);
-		ov->sensor = SEN_SAA7111A;
-	}
-
-	// FIXME: Fix this for OV518(+)
-	/* Latch to negative edge of clock. Otherwise, we get incorrect
-	 * colors and jitter in the digital signal. */
-	if (ov->bclass == BCL_OV511)
-		reg_w(ov, 0x11, 0x00);
-	else
-		dev_warn(&ov->dev->dev,
-			 "SAA7111A not yet supported with OV518/OV518+\n");
-
-	return 0;
-}
-
-/* This initializes the OV511/OV511+ and the sensor */
-static int
-ov511_configure(struct usb_ov511 *ov)
-{
-	static struct ov511_regvals aRegvalsInit511[] = {
-		{ OV511_REG_BUS, R51x_SYS_RESET,	0x7f },
-		{ OV511_REG_BUS, R51x_SYS_INIT,		0x01 },
-		{ OV511_REG_BUS, R51x_SYS_RESET,	0x7f },
-		{ OV511_REG_BUS, R51x_SYS_INIT,		0x01 },
-		{ OV511_REG_BUS, R51x_SYS_RESET,	0x3f },
-		{ OV511_REG_BUS, R51x_SYS_INIT,		0x01 },
-		{ OV511_REG_BUS, R51x_SYS_RESET,	0x3d },
-		{ OV511_DONE_BUS, 0x0, 0x00},
-	};
-
-	static struct ov511_regvals aRegvalsNorm511[] = {
-		{ OV511_REG_BUS, R511_DRAM_FLOW_CTL, 	0x01 },
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 },
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
-		{ OV511_REG_BUS, R511_FIFO_OPTS,	0x1f },
-		{ OV511_REG_BUS, R511_COMP_EN,		0x00 },
-		{ OV511_REG_BUS, R511_COMP_LUT_EN,	0x03 },
-		{ OV511_DONE_BUS, 0x0, 0x00 },
-	};
-
-	static struct ov511_regvals aRegvalsNorm511Plus[] = {
-		{ OV511_REG_BUS, R511_DRAM_FLOW_CTL,	0xff },
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 },
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
-		{ OV511_REG_BUS, R511_FIFO_OPTS,	0xff },
-		{ OV511_REG_BUS, R511_COMP_EN,		0x00 },
-		{ OV511_REG_BUS, R511_COMP_LUT_EN,	0x03 },
-		{ OV511_DONE_BUS, 0x0, 0x00 },
-	};
-
-	PDEBUG(4, "");
-
-	ov->customid = reg_r(ov, R511_SYS_CUST_ID);
-	if (ov->customid < 0) {
-		err("Unable to read camera bridge registers");
-		goto error;
-	}
-
-	PDEBUG (1, "CustomID = %d", ov->customid);
-	ov->desc = symbolic(camlist, ov->customid);
-	dev_info(&ov->dev->dev, "model: %s\n", ov->desc);
-
-	if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
-		err("Camera type (%d) not recognized", ov->customid);
-		err("Please notify " EMAIL " of the name,");
-		err("manufacturer, model, and this number of your camera.");
-		err("Also include the output of the detection process.");
-	}
-
-	if (ov->customid == 70)		/* USB Life TV (PAL/SECAM) */
-		ov->pal = 1;
-
-	if (write_regvals(ov, aRegvalsInit511))
-		goto error;
-
-	if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
-		ov51x_led_control(ov, 0);
-
-	/* The OV511+ has undocumented bits in the flow control register.
-	 * Setting it to 0xff fixes the corruption with moving objects. */
-	if (ov->bridge == BRG_OV511) {
-		if (write_regvals(ov, aRegvalsNorm511))
-			goto error;
-	} else if (ov->bridge == BRG_OV511PLUS) {
-		if (write_regvals(ov, aRegvalsNorm511Plus))
-			goto error;
-	} else {
-		err("Invalid bridge");
-	}
-
-	if (ov511_init_compression(ov))
-		goto error;
-
-	ov->packet_numbering = 1;
-	ov511_set_packet_size(ov, 0);
-
-	ov->snap_enabled = snapshot;
-
-	/* Test for 7xx0 */
-	PDEBUG(3, "Testing for 0V7xx0");
-	ov->primary_i2c_slave = OV7xx0_SID;
-	if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
-		goto error;
-
-	if (i2c_w(ov, 0x12, 0x80) < 0) {
-		/* Test for 6xx0 */
-		PDEBUG(3, "Testing for 0V6xx0");
-		ov->primary_i2c_slave = OV6xx0_SID;
-		if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
-			goto error;
-
-		if (i2c_w(ov, 0x12, 0x80) < 0) {
-			/* Test for 8xx0 */
-			PDEBUG(3, "Testing for 0V8xx0");
-			ov->primary_i2c_slave = OV8xx0_SID;
-			if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
-				goto error;
-
-			if (i2c_w(ov, 0x12, 0x80) < 0) {
-				/* Test for SAA7111A */
-				PDEBUG(3, "Testing for SAA7111A");
-				ov->primary_i2c_slave = SAA7111A_SID;
-				if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0)
-					goto error;
-
-				if (i2c_w(ov, 0x0d, 0x00) < 0) {
-					/* Test for KS0127 */
-					PDEBUG(3, "Testing for KS0127");
-					ov->primary_i2c_slave = KS0127_SID;
-					if (ov51x_set_slave_ids(ov, KS0127_SID) < 0)
-						goto error;
-
-					if (i2c_w(ov, 0x10, 0x00) < 0) {
-						err("Can't determine sensor slave IDs");
-						goto error;
-					} else {
-						if (ks0127_configure(ov) < 0) {
-							err("Failed to configure KS0127");
-							goto error;
-						}
-					}
-				} else {
-					if (saa7111a_configure(ov) < 0) {
-						err("Failed to configure SAA7111A");
-						goto error;
-					}
-				}
-			} else {
-				err("Detected unsupported OV8xx0 sensor");
-				goto error;
-			}
-		} else {
-			if (ov6xx0_configure(ov) < 0) {
-				err("Failed to configure OV6xx0");
-				goto error;
-			}
-		}
-	} else {
-		if (ov7xx0_configure(ov) < 0) {
-			err("Failed to configure OV7xx0");
-			goto error;
-		}
-	}
-
-	return 0;
-
-error:
-	err("OV511 Config failed");
-
-	return -EBUSY;
-}
-
-/* This initializes the OV518/OV518+ and the sensor */
-static int
-ov518_configure(struct usb_ov511 *ov)
-{
-	/* For 518 and 518+ */
-	static struct ov511_regvals aRegvalsInit518[] = {
-		{ OV511_REG_BUS, R51x_SYS_RESET,	0x40 },
-		{ OV511_REG_BUS, R51x_SYS_INIT,		0xe1 },
-		{ OV511_REG_BUS, R51x_SYS_RESET,	0x3e },
-		{ OV511_REG_BUS, R51x_SYS_INIT,		0xe1 },
-		{ OV511_REG_BUS, R51x_SYS_RESET,	0x00 },
-		{ OV511_REG_BUS, R51x_SYS_INIT,		0xe1 },
-		{ OV511_REG_BUS, 0x46,			0x00 },
-		{ OV511_REG_BUS, 0x5d,			0x03 },
-		{ OV511_DONE_BUS, 0x0, 0x00},
-	};
-
-	static struct ov511_regvals aRegvalsNorm518[] = {
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 }, /* Reset */
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 }, /* Enable */
-		{ OV511_REG_BUS, 0x31, 			0x0f },
-		{ OV511_REG_BUS, 0x5d,			0x03 },
-		{ OV511_REG_BUS, 0x24,			0x9f },
-		{ OV511_REG_BUS, 0x25,			0x90 },
-		{ OV511_REG_BUS, 0x20,			0x00 },
-		{ OV511_REG_BUS, 0x51,			0x04 },
-		{ OV511_REG_BUS, 0x71,			0x19 },
-		{ OV511_DONE_BUS, 0x0, 0x00 },
-	};
-
-	static struct ov511_regvals aRegvalsNorm518Plus[] = {
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 }, /* Reset */
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 }, /* Enable */
-		{ OV511_REG_BUS, 0x31, 			0x0f },
-		{ OV511_REG_BUS, 0x5d,			0x03 },
-		{ OV511_REG_BUS, 0x24,			0x9f },
-		{ OV511_REG_BUS, 0x25,			0x90 },
-		{ OV511_REG_BUS, 0x20,			0x60 },
-		{ OV511_REG_BUS, 0x51,			0x02 },
-		{ OV511_REG_BUS, 0x71,			0x19 },
-		{ OV511_REG_BUS, 0x40,			0xff },
-		{ OV511_REG_BUS, 0x41,			0x42 },
-		{ OV511_REG_BUS, 0x46,			0x00 },
-		{ OV511_REG_BUS, 0x33,			0x04 },
-		{ OV511_REG_BUS, 0x21,			0x19 },
-		{ OV511_REG_BUS, 0x3f,			0x10 },
-		{ OV511_DONE_BUS, 0x0, 0x00 },
-	};
-
-	PDEBUG(4, "");
-
-	/* First 5 bits of custom ID reg are a revision ID on OV518 */
-	dev_info(&ov->dev->dev, "Device revision %d\n",
-		 0x1F & reg_r(ov, R511_SYS_CUST_ID));
-
-	/* Give it the default description */
-	ov->desc = symbolic(camlist, 0);
-
-	if (write_regvals(ov, aRegvalsInit518))
-		goto error;
-
-	/* Set LED GPIO pin to output mode */
-	if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0)
-		goto error;
-
-	/* LED is off by default with OV518; have to explicitly turn it on */
-	if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
-		ov51x_led_control(ov, 0);
-	else
-		ov51x_led_control(ov, 1);
-
-	/* Don't require compression if dumppix is enabled; otherwise it's
-	 * required. OV518 has no uncompressed mode, to save RAM. */
-	if (!dumppix && !ov->compress) {
-		ov->compress = 1;
-		dev_warn(&ov->dev->dev,
-			 "Compression required with OV518...enabling\n");
-	}
-
-	if (ov->bridge == BRG_OV518) {
-		if (write_regvals(ov, aRegvalsNorm518))
-			goto error;
-	} else if (ov->bridge == BRG_OV518PLUS) {
-		if (write_regvals(ov, aRegvalsNorm518Plus))
-			goto error;
-	} else {
-		err("Invalid bridge");
-	}
-
-	if (reg_w(ov, 0x2f, 0x80) < 0)
-		goto error;
-
-	if (ov518_init_compression(ov))
-		goto error;
-
-	if (ov->bridge == BRG_OV518)
-	{
-		struct usb_interface *ifp;
-		struct usb_host_interface *alt;
-		__u16 mxps = 0;
-
-		ifp = usb_ifnum_to_if(ov->dev, 0);
-		if (ifp) {
-			alt = usb_altnum_to_altsetting(ifp, 7);
-			if (alt)
-				mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
-		}
-
-		/* Some OV518s have packet numbering by default, some don't */
-		if (mxps == 897)
-			ov->packet_numbering = 1;
-		else
-			ov->packet_numbering = 0;
-	} else {
-		/* OV518+ has packet numbering turned on by default */
-		ov->packet_numbering = 1;
-	}
-
-	ov518_set_packet_size(ov, 0);
-
-	ov->snap_enabled = snapshot;
-
-	/* Test for 76xx */
-	ov->primary_i2c_slave = OV7xx0_SID;
-	if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
-		goto error;
-
-	/* The OV518 must be more aggressive about sensor detection since
-	 * I2C write will never fail if the sensor is not present. We have
-	 * to try to initialize the sensor to detect its presence */
-
-	if (init_ov_sensor(ov) < 0) {
-		/* Test for 6xx0 */
-		ov->primary_i2c_slave = OV6xx0_SID;
-		if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
-			goto error;
-
-		if (init_ov_sensor(ov) < 0) {
-			/* Test for 8xx0 */
-			ov->primary_i2c_slave = OV8xx0_SID;
-			if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
-				goto error;
-
-			if (init_ov_sensor(ov) < 0) {
-				err("Can't determine sensor slave IDs");
-				goto error;
-			} else {
-				err("Detected unsupported OV8xx0 sensor");
-				goto error;
-			}
-		} else {
-			if (ov6xx0_configure(ov) < 0) {
-				err("Failed to configure OV6xx0");
-				goto error;
-			}
-		}
-	} else {
-		if (ov7xx0_configure(ov) < 0) {
-			err("Failed to configure OV7xx0");
-			goto error;
-		}
-	}
-
-	ov->maxwidth = 352;
-	ov->maxheight = 288;
-
-	// The OV518 cannot go as low as the sensor can
-	ov->minwidth = 160;
-	ov->minheight = 120;
-
-	return 0;
-
-error:
-	err("OV518 Config failed");
-
-	return -EBUSY;
-}
-
-/****************************************************************************
- *  sysfs
- ***************************************************************************/
-
-static inline struct usb_ov511 *cd_to_ov(struct device *cd)
-{
-	struct video_device *vdev = to_video_device(cd);
-	return video_get_drvdata(vdev);
-}
-
-static ssize_t show_custom_id(struct device *cd,
-			      struct device_attribute *attr, char *buf)
-{
-	struct usb_ov511 *ov = cd_to_ov(cd);
-	return sprintf(buf, "%d\n", ov->customid);
-}
-static DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
-
-static ssize_t show_model(struct device *cd,
-			  struct device_attribute *attr, char *buf)
-{
-	struct usb_ov511 *ov = cd_to_ov(cd);
-	return sprintf(buf, "%s\n", ov->desc);
-}
-static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
-
-static ssize_t show_bridge(struct device *cd,
-			   struct device_attribute *attr, char *buf)
-{
-	struct usb_ov511 *ov = cd_to_ov(cd);
-	return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge));
-}
-static DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
-
-static ssize_t show_sensor(struct device *cd,
-			   struct device_attribute *attr, char *buf)
-{
-	struct usb_ov511 *ov = cd_to_ov(cd);
-	return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor));
-}
-static DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
-
-static ssize_t show_brightness(struct device *cd,
-			       struct device_attribute *attr, char *buf)
-{
-	struct usb_ov511 *ov = cd_to_ov(cd);
-	unsigned short x;
-
-	if (!ov->dev)
-		return -ENODEV;
-	sensor_get_brightness(ov, &x);
-	return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
-
-static ssize_t show_saturation(struct device *cd,
-			       struct device_attribute *attr, char *buf)
-{
-	struct usb_ov511 *ov = cd_to_ov(cd);
-	unsigned short x;
-
-	if (!ov->dev)
-		return -ENODEV;
-	sensor_get_saturation(ov, &x);
-	return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
-
-static ssize_t show_contrast(struct device *cd,
-			     struct device_attribute *attr, char *buf)
-{
-	struct usb_ov511 *ov = cd_to_ov(cd);
-	unsigned short x;
-
-	if (!ov->dev)
-		return -ENODEV;
-	sensor_get_contrast(ov, &x);
-	return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
-
-static ssize_t show_hue(struct device *cd,
-			struct device_attribute *attr, char *buf)
-{
-	struct usb_ov511 *ov = cd_to_ov(cd);
-	unsigned short x;
-
-	if (!ov->dev)
-		return -ENODEV;
-	sensor_get_hue(ov, &x);
-	return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
-
-static ssize_t show_exposure(struct device *cd,
-			     struct device_attribute *attr, char *buf)
-{
-	struct usb_ov511 *ov = cd_to_ov(cd);
-	unsigned char exp = 0;
-
-	if (!ov->dev)
-		return -ENODEV;
-	sensor_get_exposure(ov, &exp);
-	return sprintf(buf, "%d\n", exp);
-}
-static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
-
-static int ov_create_sysfs(struct video_device *vdev)
-{
-	int rc;
-
-	rc = device_create_file(&vdev->dev, &dev_attr_custom_id);
-	if (rc) goto err;
-	rc = device_create_file(&vdev->dev, &dev_attr_model);
-	if (rc) goto err_id;
-	rc = device_create_file(&vdev->dev, &dev_attr_bridge);
-	if (rc) goto err_model;
-	rc = device_create_file(&vdev->dev, &dev_attr_sensor);
-	if (rc) goto err_bridge;
-	rc = device_create_file(&vdev->dev, &dev_attr_brightness);
-	if (rc) goto err_sensor;
-	rc = device_create_file(&vdev->dev, &dev_attr_saturation);
-	if (rc) goto err_bright;
-	rc = device_create_file(&vdev->dev, &dev_attr_contrast);
-	if (rc) goto err_sat;
-	rc = device_create_file(&vdev->dev, &dev_attr_hue);
-	if (rc) goto err_contrast;
-	rc = device_create_file(&vdev->dev, &dev_attr_exposure);
-	if (rc) goto err_hue;
-
-	return 0;
-
-err_hue:
-	device_remove_file(&vdev->dev, &dev_attr_hue);
-err_contrast:
-	device_remove_file(&vdev->dev, &dev_attr_contrast);
-err_sat:
-	device_remove_file(&vdev->dev, &dev_attr_saturation);
-err_bright:
-	device_remove_file(&vdev->dev, &dev_attr_brightness);
-err_sensor:
-	device_remove_file(&vdev->dev, &dev_attr_sensor);
-err_bridge:
-	device_remove_file(&vdev->dev, &dev_attr_bridge);
-err_model:
-	device_remove_file(&vdev->dev, &dev_attr_model);
-err_id:
-	device_remove_file(&vdev->dev, &dev_attr_custom_id);
-err:
-	return rc;
-}
-
-/****************************************************************************
- *  USB routines
- ***************************************************************************/
-
-static int
-ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-	struct usb_device *dev = interface_to_usbdev(intf);
-	struct usb_interface_descriptor *idesc;
-	struct usb_ov511 *ov;
-	int i, rc, nr;
-
-	PDEBUG(1, "probing for device...");
-
-	/* We don't handle multi-config cameras */
-	if (dev->descriptor.bNumConfigurations != 1)
-		return -ENODEV;
-
-	idesc = &intf->cur_altsetting->desc;
-
-	if (idesc->bInterfaceClass != 0xFF)
-		return -ENODEV;
-	if (idesc->bInterfaceSubClass != 0x00)
-		return -ENODEV;
-
-	if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
-		err("couldn't kmalloc ov struct");
-		goto error_out;
-	}
-
-	ov->dev = dev;
-	ov->iface = idesc->bInterfaceNumber;
-	ov->led_policy = led;
-	ov->compress = compress;
-	ov->lightfreq = lightfreq;
-	ov->num_inputs = 1;	   /* Video decoder init functs. change this */
-	ov->stop_during_set = !fastset;
-	ov->backlight = backlight;
-	ov->mirror = mirror;
-	ov->auto_brt = autobright;
-	ov->auto_gain = autogain;
-	ov->auto_exp = autoexp;
-
-	switch (le16_to_cpu(dev->descriptor.idProduct)) {
-	case PROD_OV511:
-		ov->bridge = BRG_OV511;
-		ov->bclass = BCL_OV511;
-		break;
-	case PROD_OV511PLUS:
-		ov->bridge = BRG_OV511PLUS;
-		ov->bclass = BCL_OV511;
-		break;
-	case PROD_OV518:
-		ov->bridge = BRG_OV518;
-		ov->bclass = BCL_OV518;
-		break;
-	case PROD_OV518PLUS:
-		ov->bridge = BRG_OV518PLUS;
-		ov->bclass = BCL_OV518;
-		break;
-	case PROD_ME2CAM:
-		if (le16_to_cpu(dev->descriptor.idVendor) != VEND_MATTEL)
-			goto error;
-		ov->bridge = BRG_OV511PLUS;
-		ov->bclass = BCL_OV511;
-		break;
-	default:
-		err("Unknown product ID 0x%04x", le16_to_cpu(dev->descriptor.idProduct));
-		goto error;
-	}
-
-	dev_info(&intf->dev, "USB %s video device found\n",
-		 symbolic(brglist, ov->bridge));
-
-	init_waitqueue_head(&ov->wq);
-
-	mutex_init(&ov->lock);	/* to 1 == available */
-	mutex_init(&ov->buf_lock);
-	mutex_init(&ov->i2c_lock);
-	mutex_init(&ov->cbuf_lock);
-
-	ov->buf_state = BUF_NOT_ALLOCATED;
-
-	if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) {
-		err("usb_make_path error");
-		goto error;
-	}
-
-	/* Allocate control transfer buffer. */
-	/* Must be kmalloc()'ed, for DMA compatibility */
-	ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL);
-	if (!ov->cbuf)
-		goto error;
-
-	if (ov->bclass == BCL_OV518) {
-		if (ov518_configure(ov) < 0)
-			goto error;
-	} else {
-		if (ov511_configure(ov) < 0)
-			goto error;
-	}
-
-	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov->frame[i].framenum = i;
-		init_waitqueue_head(&ov->frame[i].wq);
-	}
-
-	for (i = 0; i < OV511_NUMSBUF; i++) {
-		ov->sbuf[i].ov = ov;
-		spin_lock_init(&ov->sbuf[i].lock);
-		ov->sbuf[i].n = i;
-	}
-
-	/* Unnecessary? (This is done on open(). Need to make sure variables
-	 * are properly initialized without this before removing it, though). */
-	if (ov51x_set_default_params(ov) < 0)
-		goto error;
-
-#ifdef OV511_DEBUG
-	if (dump_bridge) {
-		if (ov->bclass == BCL_OV511)
-			ov511_dump_regs(ov);
-		else
-			ov518_dump_regs(ov);
-	}
-#endif
-
-	ov->vdev = video_device_alloc();
-	if (!ov->vdev)
-		goto error;
-
-	memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev));
-	ov->vdev->parent = &intf->dev;
-	video_set_drvdata(ov->vdev, ov);
-
-	mutex_lock(&ov->lock);
-
-	/* Check to see next free device and mark as used */
-	nr = find_first_zero_bit(&ov511_devused, OV511_MAX_UNIT_VIDEO);
-
-	/* Registers device */
-	if (unit_video[nr] != 0)
-		rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER,
-					   unit_video[nr]);
-	else
-		rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1);
-
-	if (rc < 0) {
-		err("video_register_device failed");
-		mutex_unlock(&ov->lock);
-		goto error;
-	}
-
-	/* Mark device as used */
-	ov511_devused |= 1 << nr;
-	ov->nr = nr;
-
-	dev_info(&intf->dev, "Device at %s registered to %s\n",
-		 ov->usb_path, video_device_node_name(ov->vdev));
-
-	usb_set_intfdata(intf, ov);
-	if (ov_create_sysfs(ov->vdev)) {
-		err("ov_create_sysfs failed");
-		ov511_devused &= ~(1 << nr);
-		mutex_unlock(&ov->lock);
-		goto error;
-	}
-
-	mutex_unlock(&ov->lock);
-
-	return 0;
-
-error:
-	if (ov->vdev) {
-		if (!video_is_registered(ov->vdev))
-			video_device_release(ov->vdev);
-		else
-			video_unregister_device(ov->vdev);
-		ov->vdev = NULL;
-	}
-
-	if (ov->cbuf) {
-		mutex_lock(&ov->cbuf_lock);
-		kfree(ov->cbuf);
-		ov->cbuf = NULL;
-		mutex_unlock(&ov->cbuf_lock);
-	}
-
-	kfree(ov);
-	ov = NULL;
-
-error_out:
-	err("Camera initialization failed");
-	return -EIO;
-}
-
-static void
-ov51x_disconnect(struct usb_interface *intf)
-{
-	struct usb_ov511 *ov = usb_get_intfdata(intf);
-	int n;
-
-	PDEBUG(3, "");
-
-	mutex_lock(&ov->lock);
-	usb_set_intfdata (intf, NULL);
-
-	/* Free device number */
-	ov511_devused &= ~(1 << ov->nr);
-
-	if (ov->vdev)
-		video_unregister_device(ov->vdev);
-
-	for (n = 0; n < OV511_NUMFRAMES; n++)
-		ov->frame[n].grabstate = FRAME_ERROR;
-
-	ov->curframe = -1;
-
-	/* This will cause the process to request another frame */
-	for (n = 0; n < OV511_NUMFRAMES; n++)
-		wake_up_interruptible(&ov->frame[n].wq);
-
-	wake_up_interruptible(&ov->wq);
-
-	ov->streaming = 0;
-	ov51x_unlink_isoc(ov);
-	mutex_unlock(&ov->lock);
-
-	ov->dev = NULL;
-
-	/* Free the memory */
-	if (!ov->user) {
-		mutex_lock(&ov->cbuf_lock);
-		kfree(ov->cbuf);
-		ov->cbuf = NULL;
-		mutex_unlock(&ov->cbuf_lock);
-
-		ov51x_dealloc(ov);
-		kfree(ov);
-		ov = NULL;
-	}
-
-	PDEBUG(3, "Disconnect complete");
-}
-
-static struct usb_driver ov511_driver = {
-	.name =		"ov511",
-	.id_table =	device_table,
-	.probe =	ov51x_probe,
-	.disconnect =	ov51x_disconnect
-};
-
-/****************************************************************************
- *
- *  Module routines
- *
- ***************************************************************************/
-
-static int __init
-usb_ov511_init(void)
-{
-	int retval;
-
-	retval = usb_register(&ov511_driver);
-	if (retval)
-		goto out;
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
-out:
-	return retval;
-}
-
-static void __exit
-usb_ov511_exit(void)
-{
-	usb_deregister(&ov511_driver);
-	printk(KERN_INFO KBUILD_MODNAME ": driver deregistered\n");
-}
-
-module_init(usb_ov511_init);
-module_exit(usb_ov511_exit);
-
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
deleted file mode 100644
index c450c92..0000000
--- a/drivers/media/video/ov511.h
+++ /dev/null
@@ -1,573 +0,0 @@
-#ifndef __LINUX_OV511_H
-#define __LINUX_OV511_H
-
-#include <asm/uaccess.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-#define OV511_DEBUG	/* Turn on debug messages */
-
-#ifdef OV511_DEBUG
-	#define PDEBUG(level, fmt, args...) \
-		if (debug >= (level))	\
-			printk(KERN_INFO KBUILD_MODNAME "[%s:%d] \n" fmt, \
-		__func__, __LINE__ , ## args)
-#else
-	#define PDEBUG(level, fmt, args...) do {} while(0)
-#endif
-
-/* This macro restricts an int variable to an inclusive range */
-#define RESTRICT_TO_RANGE(v,mi,ma) { \
-	if ((v) < (mi)) (v) = (mi); \
-	else if ((v) > (ma)) (v) = (ma); \
-}
-
-/* --------------------------------- */
-/* DEFINES FOR OV511 AND OTHER CHIPS */
-/* --------------------------------- */
-
-/* USB IDs */
-#define VEND_OMNIVISION	0x05A9
-#define PROD_OV511	0x0511
-#define PROD_OV511PLUS	0xA511
-#define PROD_OV518	0x0518
-#define PROD_OV518PLUS	0xA518
-
-#define VEND_MATTEL	0x0813
-#define PROD_ME2CAM	0x0002
-
-/* --------------------------------- */
-/*     OV51x REGISTER MNEMONICS      */
-/* --------------------------------- */
-
-/* Camera interface register numbers */
-#define R511_CAM_DELAY		0x10
-#define R511_CAM_EDGE		0x11
-#define R511_CAM_PXCNT		0x12
-#define R511_CAM_LNCNT		0x13
-#define R511_CAM_PXDIV		0x14
-#define R511_CAM_LNDIV		0x15
-#define R511_CAM_UV_EN		0x16
-#define R511_CAM_LINE_MODE	0x17
-#define R511_CAM_OPTS		0x18
-
-/* Snapshot mode camera interface register numbers */
-#define R511_SNAP_FRAME		0x19
-#define R511_SNAP_PXCNT		0x1A
-#define R511_SNAP_LNCNT		0x1B
-#define R511_SNAP_PXDIV		0x1C
-#define R511_SNAP_LNDIV		0x1D
-#define R511_SNAP_UV_EN		0x1E
-#define R511_SNAP_OPTS		0x1F
-
-/* DRAM register numbers */
-#define R511_DRAM_FLOW_CTL	0x20
-#define R511_DRAM_ARCP		0x21
-#define R511_DRAM_MRC		0x22
-#define R511_DRAM_RFC		0x23
-
-/* ISO FIFO register numbers */
-#define R51x_FIFO_PSIZE		0x30	/* 2 bytes wide w/ OV518(+) */
-#define R511_FIFO_OPTS		0x31
-
-/* Parallel IO register numbers */
-#define R511_PIO_OPTS		0x38
-#define R511_PIO_DATA		0x39
-#define R511_PIO_BIST		0x3E
-#define R518_GPIO_IN		0x55	/* OV518(+) only */
-#define R518_GPIO_OUT		0x56	/* OV518(+) only */
-#define R518_GPIO_CTL		0x57	/* OV518(+) only */
-#define R518_GPIO_PULSE_IN	0x58	/* OV518(+) only */
-#define R518_GPIO_PULSE_CLEAR	0x59	/* OV518(+) only */
-#define R518_GPIO_PULSE_POL	0x5a	/* OV518(+) only */
-#define R518_GPIO_PULSE_EN	0x5b	/* OV518(+) only */
-#define R518_GPIO_RESET		0x5c	/* OV518(+) only */
-
-/* I2C registers */
-#define R511_I2C_CTL		0x40
-#define R518_I2C_CTL		0x47	/* OV518(+) only */
-#define R51x_I2C_W_SID		0x41
-#define R51x_I2C_SADDR_3	0x42
-#define R51x_I2C_SADDR_2	0x43
-#define R51x_I2C_R_SID		0x44
-#define R51x_I2C_DATA		0x45
-#define R51x_I2C_CLOCK		0x46
-#define R51x_I2C_TIMEOUT	0x47
-
-/* I2C snapshot registers */
-#define R511_SI2C_SADDR_3	0x48
-#define R511_SI2C_DATA		0x49
-
-/* System control registers */
-#define R51x_SYS_RESET		0x50
-		/* Reset type definitions */
-#define 	OV511_RESET_UDC		0x01
-#define 	OV511_RESET_I2C		0x02
-#define 	OV511_RESET_FIFO	0x04
-#define 	OV511_RESET_OMNICE	0x08
-#define 	OV511_RESET_DRAM	0x10
-#define 	OV511_RESET_CAM_INT	0x20
-#define 	OV511_RESET_OV511	0x40
-#define 	OV511_RESET_NOREGS	0x3F /* All but OV511 & regs */
-#define 	OV511_RESET_ALL		0x7F
-
-#define R511_SYS_CLOCK_DIV	0x51
-#define R51x_SYS_SNAP		0x52
-#define R51x_SYS_INIT         	0x53
-#define R511_SYS_PWR_CLK	0x54 /* OV511+/OV518(+) only */
-#define R511_SYS_LED_CTL	0x55 /* OV511+ only */
-#define R511_SYS_USER		0x5E
-#define R511_SYS_CUST_ID	0x5F
-
-/* OmniCE (compression) registers */
-#define R511_COMP_PHY		0x70
-#define R511_COMP_PHUV		0x71
-#define R511_COMP_PVY		0x72
-#define R511_COMP_PVUV		0x73
-#define R511_COMP_QHY		0x74
-#define R511_COMP_QHUV		0x75
-#define R511_COMP_QVY		0x76
-#define R511_COMP_QVUV		0x77
-#define R511_COMP_EN		0x78
-#define R511_COMP_LUT_EN	0x79
-#define R511_COMP_LUT_BEGIN	0x80
-
-/* --------------------------------- */
-/*         ALTERNATE NUMBERS         */
-/* --------------------------------- */
-
-/* Alternate numbers for various max packet sizes (OV511 only) */
-#define OV511_ALT_SIZE_992	0
-#define OV511_ALT_SIZE_993	1
-#define OV511_ALT_SIZE_768	2
-#define OV511_ALT_SIZE_769	3
-#define OV511_ALT_SIZE_512	4
-#define OV511_ALT_SIZE_513	5
-#define OV511_ALT_SIZE_257	6
-#define OV511_ALT_SIZE_0	7
-
-/* Alternate numbers for various max packet sizes (OV511+ only) */
-#define OV511PLUS_ALT_SIZE_0	0
-#define OV511PLUS_ALT_SIZE_33	1
-#define OV511PLUS_ALT_SIZE_129	2
-#define OV511PLUS_ALT_SIZE_257	3
-#define OV511PLUS_ALT_SIZE_385	4
-#define OV511PLUS_ALT_SIZE_513	5
-#define OV511PLUS_ALT_SIZE_769	6
-#define OV511PLUS_ALT_SIZE_961	7
-
-/* Alternate numbers for various max packet sizes (OV518(+) only) */
-#define OV518_ALT_SIZE_0	0
-#define OV518_ALT_SIZE_128	1
-#define OV518_ALT_SIZE_256	2
-#define OV518_ALT_SIZE_384	3
-#define OV518_ALT_SIZE_512	4
-#define OV518_ALT_SIZE_640	5
-#define OV518_ALT_SIZE_768	6
-#define OV518_ALT_SIZE_896	7
-
-/* --------------------------------- */
-/*     OV7610 REGISTER MNEMONICS     */
-/* --------------------------------- */
-
-/* OV7610 registers */
-#define OV7610_REG_GAIN          0x00	/* gain setting (5:0) */
-#define OV7610_REG_BLUE          0x01	/* blue channel balance */
-#define OV7610_REG_RED           0x02	/* red channel balance */
-#define OV7610_REG_SAT           0x03	/* saturation */
-					/* 04 reserved */
-#define OV7610_REG_CNT           0x05	/* Y contrast */
-#define OV7610_REG_BRT           0x06	/* Y brightness */
-					/* 08-0b reserved */
-#define OV7610_REG_BLUE_BIAS     0x0C	/* blue channel bias (5:0) */
-#define OV7610_REG_RED_BIAS      0x0D	/* read channel bias (5:0) */
-#define OV7610_REG_GAMMA_COEFF   0x0E	/* gamma settings */
-#define OV7610_REG_WB_RANGE      0x0F	/* AEC/ALC/S-AWB settings */
-#define OV7610_REG_EXP           0x10	/* manual exposure setting */
-#define OV7610_REG_CLOCK         0x11	/* polarity/clock prescaler */
-#define OV7610_REG_COM_A         0x12	/* misc common regs */
-#define OV7610_REG_COM_B         0x13	/* misc common regs */
-#define OV7610_REG_COM_C         0x14	/* misc common regs */
-#define OV7610_REG_COM_D         0x15	/* misc common regs */
-#define OV7610_REG_FIELD_DIVIDE  0x16	/* field interval/mode settings */
-#define OV7610_REG_HWIN_START    0x17	/* horizontal window start */
-#define OV7610_REG_HWIN_END      0x18	/* horizontal window end */
-#define OV7610_REG_VWIN_START    0x19	/* vertical window start */
-#define OV7610_REG_VWIN_END      0x1A	/* vertical window end */
-#define OV7610_REG_PIXEL_SHIFT   0x1B	/* pixel shift */
-#define OV7610_REG_ID_HIGH       0x1C	/* manufacturer ID MSB */
-#define OV7610_REG_ID_LOW        0x1D	/* manufacturer ID LSB */
-					/* 0e-0f reserved */
-#define OV7610_REG_COM_E         0x20	/* misc common regs */
-#define OV7610_REG_YOFFSET       0x21	/* Y channel offset */
-#define OV7610_REG_UOFFSET       0x22	/* U channel offset */
-					/* 23 reserved */
-#define OV7610_REG_ECW           0x24	/* Exposure white level for AEC */
-#define OV7610_REG_ECB           0x25	/* Exposure black level for AEC */
-#define OV7610_REG_COM_F         0x26	/* misc settings */
-#define OV7610_REG_COM_G         0x27	/* misc settings */
-#define OV7610_REG_COM_H         0x28	/* misc settings */
-#define OV7610_REG_COM_I         0x29	/* misc settings */
-#define OV7610_REG_FRAMERATE_H   0x2A	/* frame rate MSB + misc */
-#define OV7610_REG_FRAMERATE_L   0x2B	/* frame rate LSB */
-#define OV7610_REG_ALC           0x2C	/* Auto Level Control settings */
-#define OV7610_REG_COM_J         0x2D	/* misc settings */
-#define OV7610_REG_VOFFSET       0x2E	/* V channel offset adjustment */
-#define OV7610_REG_ARRAY_BIAS	 0x2F	/* Array bias -- don't change */
-					/* 30-32 reserved */
-#define OV7610_REG_YGAMMA        0x33	/* misc gamma settings (7:6) */
-#define OV7610_REG_BIAS_ADJUST   0x34	/* misc bias settings */
-#define OV7610_REG_COM_L         0x35	/* misc settings */
-					/* 36-37 reserved */
-#define OV7610_REG_COM_K         0x38	/* misc registers */
-
-/* --------------------------------- */
-/*           I2C ADDRESSES           */
-/* --------------------------------- */
-
-#define OV7xx0_SID   0x42
-#define OV6xx0_SID   0xC0
-#define OV8xx0_SID   0xA0
-#define KS0127_SID   0xD8
-#define SAA7111A_SID 0x48
-
-/* --------------------------------- */
-/*       MISCELLANEOUS DEFINES       */
-/* --------------------------------- */
-
-#define I2C_CLOCK_PRESCALER 	0x03
-
-#define FRAMES_PER_DESC		10	/* FIXME - What should this be? */
-#define MAX_FRAME_SIZE_PER_DESC	993	/* For statically allocated stuff */
-#define PIXELS_PER_SEG		256	/* Pixels per segment */
-
-#define OV511_ENDPOINT_ADDRESS	1	/* Isoc endpoint number */
-
-#define OV511_NUMFRAMES	2
-#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
-	#error "OV511_NUMFRAMES is too high"
-#endif
-
-#define OV511_NUMSBUF		2
-
-/* Control transfers use up to 4 bytes */
-#define OV511_CBUF_SIZE		4
-
-/* Size of usb_make_path() buffer */
-#define OV511_USB_PATH_LEN	64
-
-/* Bridge types */
-enum {
-	BRG_UNKNOWN,
-	BRG_OV511,
-	BRG_OV511PLUS,
-	BRG_OV518,
-	BRG_OV518PLUS,
-};
-
-/* Bridge classes */
-enum {
-	BCL_UNKNOWN,
-	BCL_OV511,
-	BCL_OV518,
-};
-
-/* Sensor types */
-enum {
-	SEN_UNKNOWN,
-	SEN_OV76BE,
-	SEN_OV7610,
-	SEN_OV7620,
-	SEN_OV7620AE,
-	SEN_OV6620,
-	SEN_OV6630,
-	SEN_OV6630AE,
-	SEN_OV6630AF,
-	SEN_OV8600,
-	SEN_KS0127,
-	SEN_KS0127B,
-	SEN_SAA7111A,
-};
-
-enum {
-	STATE_SCANNING,		/* Scanning for start */
-	STATE_HEADER,		/* Parsing header */
-	STATE_LINES,		/* Parsing lines */
-};
-
-/* Buffer states */
-enum {
-	BUF_NOT_ALLOCATED,
-	BUF_ALLOCATED,
-};
-
-/* --------- Definition of ioctl interface --------- */
-
-#define OV511_INTERFACE_VER 101
-
-/* LED options */
-enum {
-	LED_OFF,
-	LED_ON,
-	LED_AUTO,
-};
-
-/* Raw frame formats */
-enum {
-	RAWFMT_INVALID,
-	RAWFMT_YUV400,
-	RAWFMT_YUV420,
-	RAWFMT_YUV422,
-	RAWFMT_GBR422,
-};
-
-struct ov511_i2c_struct {
-	unsigned char slave; /* Write slave ID (read ID - 1) */
-	unsigned char reg;   /* Index of register */
-	unsigned char value; /* User sets this w/ write, driver does w/ read */
-	unsigned char mask;  /* Bits to be changed. Not used with read ops */
-};
-
-/* ioctls */
-#define OV511IOC_WI2C     _IOW('v', BASE_VIDIOCPRIVATE + 5, \
-			       struct ov511_i2c_struct)
-#define OV511IOC_RI2C    _IOWR('v', BASE_VIDIOCPRIVATE + 6, \
-			       struct ov511_i2c_struct)
-/* ------------- End IOCTL interface -------------- */
-
-struct usb_ov511;		/* Forward declaration */
-
-struct ov511_sbuf {
-	struct usb_ov511 *ov;
-	unsigned char *data;
-	struct urb *urb;
-	spinlock_t lock;
-	int n;
-};
-
-enum {
-	FRAME_UNUSED,		/* Unused (no MCAPTURE) */
-	FRAME_READY,		/* Ready to start grabbing */
-	FRAME_GRABBING,		/* In the process of being grabbed into */
-	FRAME_DONE,		/* Finished grabbing, but not been synced yet */
-	FRAME_ERROR,		/* Something bad happened while processing */
-};
-
-struct ov511_regvals {
-	enum {
-		OV511_DONE_BUS,
-		OV511_REG_BUS,
-		OV511_I2C_BUS,
-	} bus;
-	unsigned char reg;
-	unsigned char val;
-};
-
-struct ov511_frame {
-	int framenum;		/* Index of this frame */
-	unsigned char *data;	/* Frame buffer */
-	unsigned char *tempdata; /* Temp buffer for multi-stage conversions */
-	unsigned char *rawdata;	/* Raw camera data buffer */
-	unsigned char *compbuf;	/* Temp buffer for decompressor */
-
-	int depth;		/* Bytes per pixel */
-	int width;		/* Width application is expecting */
-	int height;		/* Height application is expecting */
-
-	int rawwidth;		/* Actual width of frame sent from camera */
-	int rawheight;		/* Actual height of frame sent from camera */
-
-	int sub_flag;		/* Sub-capture mode for this frame? */
-	unsigned int format;	/* Format for this frame */
-	int compressed;		/* Is frame compressed? */
-
-	volatile int grabstate;	/* State of grabbing */
-	int scanstate;		/* State of scanning */
-
-	int bytes_recvd;	/* Number of image bytes received from camera */
-
-	long bytes_read;	/* Amount that has been read() */
-
-	wait_queue_head_t wq;	/* Processes waiting */
-
-	int snapshot;		/* True if frame was a snapshot */
-};
-
-#define DECOMP_INTERFACE_VER 4
-
-/* Compression module operations */
-struct ov51x_decomp_ops {
-	int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *,
-			  int, int, int);
-	int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *,
-			  int, int, int);
-	int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *,
-			  int, int, int);
-	struct module *owner;
-};
-
-struct usb_ov511 {
-	struct video_device *vdev;
-	struct usb_device *dev;
-
-	int customid;
-	char *desc;
-	unsigned char iface;
-	char usb_path[OV511_USB_PATH_LEN];
-
-	/* Determined by sensor type */
-	int maxwidth;
-	int maxheight;
-	int minwidth;
-	int minheight;
-
-	int brightness;
-	int colour;
-	int contrast;
-	int hue;
-	int whiteness;
-	int exposure;
-	int auto_brt;		/* Auto brightness enabled flag */
-	int auto_gain;		/* Auto gain control enabled flag */
-	int auto_exp;		/* Auto exposure enabled flag */
-	int backlight;		/* Backlight exposure algorithm flag */
-	int mirror;		/* Image is reversed horizontally */
-
-	int led_policy;		/* LED: off|on|auto; OV511+ only */
-
-	struct mutex lock;	/* Serializes user-accessible operations */
-	int user;		/* user count for exclusive use */
-
-	int streaming;		/* Are we streaming Isochronous? */
-	int grabbing;		/* Are we grabbing? */
-
-	int compress;		/* Should the next frame be compressed? */
-	int compress_inited;	/* Are compression params uploaded? */
-
-	int lightfreq;		/* Power (lighting) frequency */
-	int bandfilt;		/* Banding filter enabled flag */
-
-	unsigned char *fbuf;	/* Videodev buffer area */
-	unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */
-	unsigned char *rawfbuf;	/* Raw camera data buffer area */
-
-	int sub_flag;		/* Pix Array subcapture on flag */
-	int subx;		/* Pix Array subcapture x offset */
-	int suby;		/* Pix Array subcapture y offset */
-	int subw;		/* Pix Array subcapture width */
-	int subh;		/* Pix Array subcapture height */
-
-	int curframe;		/* Current receiving sbuf */
-	struct ov511_frame frame[OV511_NUMFRAMES];
-
-	struct ov511_sbuf sbuf[OV511_NUMSBUF];
-
-	wait_queue_head_t wq;	/* Processes waiting */
-
-	int snap_enabled;	/* Snapshot mode enabled */
-
-	int bridge;		/* Type of bridge (BRG_*) */
-	int bclass;		/* Class of bridge (BCL_*) */
-	int sensor;		/* Type of image sensor chip (SEN_*) */
-
-	int packet_size;	/* Frame size per isoc desc */
-	int packet_numbering;	/* Is ISO frame numbering enabled? */
-
-	/* Framebuffer/sbuf management */
-	int buf_state;
-	struct mutex buf_lock;
-
-	struct ov51x_decomp_ops *decomp_ops;
-
-	/* Stop streaming while changing picture settings */
-	int stop_during_set;
-
-	int stopped;		/* Streaming is temporarily paused */
-
-	/* Video decoder stuff */
-	int input;		/* Composite, S-VIDEO, etc... */
-	int num_inputs;		/* Number of inputs */
-	int norm; 		/* NTSC / PAL / SECAM */
-	int has_decoder;	/* Device has a video decoder */
-	int pal;		/* Device is designed for PAL resolution */
-
-	/* ov511 device number ID */
-	int nr;			/* Stores a device number */
-
-	/* I2C interface */
-	struct mutex i2c_lock;	  /* Protect I2C controller regs */
-	unsigned char primary_i2c_slave;  /* I2C write id of sensor */
-
-	/* Control transaction stuff */
-	unsigned char *cbuf;		/* Buffer for payload */
-	struct mutex cbuf_lock;
-};
-
-/* Used to represent a list of values and their respective symbolic names */
-struct symbolic_list {
-	int num;
-	char *name;
-};
-
-#define NOT_DEFINED_STR "Unknown"
-
-/* Returns the name of the matching element in the symbolic_list array. The
- * end of the list must be marked with an element that has a NULL name.
- */
-static inline char *
-symbolic(struct symbolic_list list[], int num)
-{
-	int i;
-
-	for (i = 0; list[i].name != NULL; i++)
-			if (list[i].num == num)
-				return (list[i].name);
-
-	return (NOT_DEFINED_STR);
-}
-
-/* Compression stuff */
-
-#define OV511_QUANTABLESIZE	64
-#define OV518_QUANTABLESIZE	32
-
-#define OV511_YQUANTABLE { \
-	0, 1, 1, 2, 2, 3, 3, 4, \
-	1, 1, 1, 2, 2, 3, 4, 4, \
-	1, 1, 2, 2, 3, 4, 4, 4, \
-	2, 2, 2, 3, 4, 4, 4, 4, \
-	2, 2, 3, 4, 4, 5, 5, 5, \
-	3, 3, 4, 4, 5, 5, 5, 5, \
-	3, 4, 4, 4, 5, 5, 5, 5, \
-	4, 4, 4, 4, 5, 5, 5, 5  \
-}
-
-#define OV511_UVQUANTABLE { \
-	0, 2, 2, 3, 4, 4, 4, 4, \
-	2, 2, 2, 4, 4, 4, 4, 4, \
-	2, 2, 3, 4, 4, 4, 4, 4, \
-	3, 4, 4, 4, 4, 4, 4, 4, \
-	4, 4, 4, 4, 4, 4, 4, 4, \
-	4, 4, 4, 4, 4, 4, 4, 4, \
-	4, 4, 4, 4, 4, 4, 4, 4, \
-	4, 4, 4, 4, 4, 4, 4, 4  \
-}
-
-#define OV518_YQUANTABLE { \
-	5, 4, 5, 6, 6, 7, 7, 7, \
-	5, 5, 5, 5, 6, 7, 7, 7, \
-	6, 6, 6, 6, 7, 7, 7, 8, \
-	7, 7, 6, 7, 7, 7, 8, 8  \
-}
-
-#define OV518_UVQUANTABLE { \
-	6, 6, 6, 7, 7, 7, 7, 7, \
-	6, 6, 6, 7, 7, 7, 7, 7, \
-	6, 6, 6, 7, 7, 7, 7, 8, \
-	7, 7, 7, 7, 7, 7, 8, 8  \
-}
-
-#endif
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index 34034a7..25eb5d6 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -440,21 +440,21 @@
  */
 static const struct ov772x_color_format ov772x_cfmts[] = {
 	{
-		.code		= V4L2_MBUS_FMT_YUYV8_2X8_LE,
+		.code		= V4L2_MBUS_FMT_YUYV8_2X8,
 		.colorspace	= V4L2_COLORSPACE_JPEG,
 		.dsp3		= 0x0,
 		.com3		= SWAP_YUV,
 		.com7		= OFMT_YUV,
 	},
 	{
-		.code		= V4L2_MBUS_FMT_YVYU8_2X8_LE,
+		.code		= V4L2_MBUS_FMT_YVYU8_2X8,
 		.colorspace	= V4L2_COLORSPACE_JPEG,
 		.dsp3		= UV_ON,
 		.com3		= SWAP_YUV,
 		.com7		= OFMT_YUV,
 	},
 	{
-		.code		= V4L2_MBUS_FMT_YUYV8_2X8_BE,
+		.code		= V4L2_MBUS_FMT_UYVY8_2X8,
 		.colorspace	= V4L2_COLORSPACE_JPEG,
 		.dsp3		= 0x0,
 		.com3		= 0x0,
@@ -960,7 +960,7 @@
 	if (!priv->win || !priv->cfmt) {
 		u32 width = VGA_WIDTH, height = VGA_HEIGHT;
 		int ret = ov772x_set_params(client, &width, &height,
-					    V4L2_MBUS_FMT_YUYV8_2X8_LE);
+					    V4L2_MBUS_FMT_YUYV8_2X8);
 		if (ret < 0)
 			return ret;
 	}
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
index 7ce9e05..40cdfab 100644
--- a/drivers/media/video/ov9640.c
+++ b/drivers/media/video/ov9640.c
@@ -155,7 +155,7 @@
 };
 
 static enum v4l2_mbus_pixelcode ov9640_codes[] = {
-	V4L2_MBUS_FMT_YUYV8_2X8_BE,
+	V4L2_MBUS_FMT_UYVY8_2X8,
 	V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
 	V4L2_MBUS_FMT_RGB565_2X8_LE,
 };
@@ -430,7 +430,7 @@
 {
 	switch (code) {
 	default:
-	case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+	case V4L2_MBUS_FMT_UYVY8_2X8:
 		alt->com12	= OV9640_COM12_YUV_AVG;
 		alt->com13	= OV9640_COM13_Y_DELAY_EN |
 					OV9640_COM13_YUV_DLY(0x01);
@@ -493,7 +493,7 @@
 	}
 
 	/* select color matrix configuration for given color encoding */
-	if (code == V4L2_MBUS_FMT_YUYV8_2X8_BE) {
+	if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
 		matrix_regs	= ov9640_regs_yuv;
 		matrix_regs_len	= ARRAY_SIZE(ov9640_regs_yuv);
 	} else {
@@ -579,8 +579,8 @@
 		cspace = V4L2_COLORSPACE_SRGB;
 		break;
 	default:
-		code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
-	case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+		code = V4L2_MBUS_FMT_UYVY8_2X8;
+	case V4L2_MBUS_FMT_UYVY8_2X8:
 		cspace = V4L2_COLORSPACE_JPEG;
 	}
 
@@ -606,8 +606,8 @@
 		mf->colorspace = V4L2_COLORSPACE_SRGB;
 		break;
 	default:
-		mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
-	case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+		mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+	case V4L2_MBUS_FMT_UYVY8_2X8:
 		mf->colorspace = V4L2_COLORSPACE_JPEG;
 	}
 
diff --git a/drivers/media/video/ovcamchip/Makefile b/drivers/media/video/ovcamchip/Makefile
deleted file mode 100644
index cba4cdf..0000000
--- a/drivers/media/video/ovcamchip/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-ovcamchip-objs     := ovcamchip_core.o ov6x20.o ov6x30.o ov7x10.o ov7x20.o \
-		      ov76be.o
-
-obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip.o
diff --git a/drivers/media/video/ovcamchip/ov6x20.c b/drivers/media/video/ovcamchip/ov6x20.c
deleted file mode 100644
index c04130d..0000000
--- a/drivers/media/video/ovcamchip/ov6x20.c
+++ /dev/null
@@ -1,414 +0,0 @@
-/* OmniVision OV6620/OV6120 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN		0x00	/* gain [5:0] */
-#define REG_BLUE		0x01	/* blue gain */
-#define REG_RED			0x02	/* red gain */
-#define REG_SAT			0x03	/* saturation */
-#define REG_CNT			0x05	/* Y contrast */
-#define REG_BRT			0x06	/* Y brightness */
-#define REG_WB_BLUE		0x0C	/* WB blue ratio [5:0] */
-#define REG_WB_RED		0x0D	/* WB red ratio [5:0] */
-#define REG_EXP			0x10	/* exposure */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3A
-#define VWSBASE 0x05
-#define VWEBASE 0x06
-
-struct ov6x20 {
-	int auto_brt;
-	int auto_exp;
-	int backlight;
-	int bandfilt;
-	int mirror;
-};
-
-/* Initial values for use with OV511/OV511+ cameras */
-static struct ovcamchip_regvals regvals_init_6x20_511[] = {
-	{ 0x12, 0x80 }, /* reset */
-	{ 0x11, 0x01 },
-	{ 0x03, 0x60 },
-	{ 0x05, 0x7f }, /* For when autoadjust is off */
-	{ 0x07, 0xa8 },
-	{ 0x0c, 0x24 },
-	{ 0x0d, 0x24 },
-	{ 0x0f, 0x15 }, /* COMS */
-	{ 0x10, 0x75 }, /* AEC Exposure time */
-	{ 0x12, 0x24 }, /* Enable AGC and AWB */
-	{ 0x14, 0x04 },
-	{ 0x16, 0x03 },
-	{ 0x26, 0xb2 }, /* BLC enable */
-	/* 0x28: 0x05 Selects RGB format if RGB on */
-	{ 0x28, 0x05 },
-	{ 0x2a, 0x04 }, /* Disable framerate adjust */
-	{ 0x2d, 0x99 },
-	{ 0x33, 0xa0 }, /* Color Processing Parameter */
-	{ 0x34, 0xd2 }, /* Max A/D range */
-	{ 0x38, 0x8b },
-	{ 0x39, 0x40 },
-
-	{ 0x3c, 0x39 }, /* Enable AEC mode changing */
-	{ 0x3c, 0x3c }, /* Change AEC mode */
-	{ 0x3c, 0x24 }, /* Disable AEC mode changing */
-
-	{ 0x3d, 0x80 },
-	/* These next two registers (0x4a, 0x4b) are undocumented. They
-	 * control the color balance */
-	{ 0x4a, 0x80 },
-	{ 0x4b, 0x80 },
-	{ 0x4d, 0xd2 }, /* This reduces noise a bit */
-	{ 0x4e, 0xc1 },
-	{ 0x4f, 0x04 },
-	{ 0xff, 0xff },	/* END MARKER */
-};
-
-/* Initial values for use with OV518 cameras */
-static struct ovcamchip_regvals regvals_init_6x20_518[] = {
-	{ 0x12, 0x80 }, /* Do a reset */
-	{ 0x03, 0xc0 }, /* Saturation */
-	{ 0x05, 0x8a }, /* Contrast */
-	{ 0x0c, 0x24 }, /* AWB blue */
-	{ 0x0d, 0x24 }, /* AWB red */
-	{ 0x0e, 0x8d }, /* Additional 2x gain */
-	{ 0x0f, 0x25 }, /* Black expanding level = 1.3V */
-	{ 0x11, 0x01 }, /* Clock div. */
-	{ 0x12, 0x24 }, /* Enable AGC and AWB */
-	{ 0x13, 0x01 }, /* (default) */
-	{ 0x14, 0x80 }, /* Set reserved bit 7 */
-	{ 0x15, 0x01 }, /* (default) */
-	{ 0x16, 0x03 }, /* (default) */
-	{ 0x17, 0x38 }, /* (default) */
-	{ 0x18, 0xea }, /* (default) */
-	{ 0x19, 0x04 },
-	{ 0x1a, 0x93 },
-	{ 0x1b, 0x00 }, /* (default) */
-	{ 0x1e, 0xc4 }, /* (default) */
-	{ 0x1f, 0x04 }, /* (default) */
-	{ 0x20, 0x20 }, /* Enable 1st stage aperture correction */
-	{ 0x21, 0x10 }, /* Y offset */
-	{ 0x22, 0x88 }, /* U offset */
-	{ 0x23, 0xc0 }, /* Set XTAL power level */
-	{ 0x24, 0x53 }, /* AEC bright ratio */
-	{ 0x25, 0x7a }, /* AEC black ratio */
-	{ 0x26, 0xb2 }, /* BLC enable */
-	{ 0x27, 0xa2 }, /* Full output range */
-	{ 0x28, 0x01 }, /* (default) */
-	{ 0x29, 0x00 }, /* (default) */
-	{ 0x2a, 0x84 }, /* (default) */
-	{ 0x2b, 0xa8 }, /* Set custom frame rate */
-	{ 0x2c, 0xa0 }, /* (reserved) */
-	{ 0x2d, 0x95 }, /* Enable banding filter */
-	{ 0x2e, 0x88 }, /* V offset */
-	{ 0x33, 0x22 }, /* Luminance gamma on */
-	{ 0x34, 0xc7 }, /* A/D bias */
-	{ 0x36, 0x12 }, /* (reserved) */
-	{ 0x37, 0x63 }, /* (reserved) */
-	{ 0x38, 0x8b }, /* Quick AEC/AEB */
-	{ 0x39, 0x00 }, /* (default) */
-	{ 0x3a, 0x0f }, /* (default) */
-	{ 0x3b, 0x3c }, /* (default) */
-	{ 0x3c, 0x5c }, /* AEC controls */
-	{ 0x3d, 0x80 }, /* Drop 1 (bad) frame when AEC change */
-	{ 0x3e, 0x80 }, /* (default) */
-	{ 0x3f, 0x02 }, /* (default) */
-	{ 0x40, 0x10 }, /* (reserved) */
-	{ 0x41, 0x10 }, /* (reserved) */
-	{ 0x42, 0x00 }, /* (reserved) */
-	{ 0x43, 0x7f }, /* (reserved) */
-	{ 0x44, 0x80 }, /* (reserved) */
-	{ 0x45, 0x1c }, /* (reserved) */
-	{ 0x46, 0x1c }, /* (reserved) */
-	{ 0x47, 0x80 }, /* (reserved) */
-	{ 0x48, 0x5f }, /* (reserved) */
-	{ 0x49, 0x00 }, /* (reserved) */
-	{ 0x4a, 0x00 }, /* Color balance (undocumented) */
-	{ 0x4b, 0x80 }, /* Color balance (undocumented) */
-	{ 0x4c, 0x58 }, /* (reserved) */
-	{ 0x4d, 0xd2 }, /* U *= .938, V *= .838 */
-	{ 0x4e, 0xa0 }, /* (default) */
-	{ 0x4f, 0x04 }, /* UV 3-point average */
-	{ 0x50, 0xff }, /* (reserved) */
-	{ 0x51, 0x58 }, /* (reserved) */
-	{ 0x52, 0xc0 }, /* (reserved) */
-	{ 0x53, 0x42 }, /* (reserved) */
-	{ 0x27, 0xa6 }, /* Enable manual offset adj. (reg 21 & 22) */
-	{ 0x12, 0x20 },
-	{ 0x12, 0x24 },
-
-	{ 0xff, 0xff },	/* END MARKER */
-};
-
-/* This initializes the OV6x20 camera chip and relevant variables. */
-static int ov6x20_init(struct i2c_client *c)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov6x20 *s;
-	int rc;
-
-	DDEBUG(4, &c->dev, "entered");
-
-	switch (c->adapter->id) {
-	case I2C_HW_SMBUS_OV511:
-		rc = ov_write_regvals(c, regvals_init_6x20_511);
-		break;
-	case I2C_HW_SMBUS_OV518:
-		rc = ov_write_regvals(c, regvals_init_6x20_518);
-		break;
-	default:
-		dev_err(&c->dev, "ov6x20: Unsupported adapter\n");
-		rc = -ENODEV;
-	}
-
-	if (rc < 0)
-		return rc;
-
-	ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
-	if (!s)
-		return -ENOMEM;
-
-	s->auto_brt = 1;
-	s->auto_exp = 1;
-
-	return rc;
-}
-
-static int ov6x20_free(struct i2c_client *c)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-
-	kfree(ov->spriv);
-	return 0;
-}
-
-static int ov6x20_set_control(struct i2c_client *c,
-			      struct ovcamchip_control *ctl)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov6x20 *s = ov->spriv;
-	int rc;
-	int v = ctl->value;
-
-	switch (ctl->id) {
-	case OVCAMCHIP_CID_CONT:
-		rc = ov_write(c, REG_CNT, v >> 8);
-		break;
-	case OVCAMCHIP_CID_BRIGHT:
-		rc = ov_write(c, REG_BRT, v >> 8);
-		break;
-	case OVCAMCHIP_CID_SAT:
-		rc = ov_write(c, REG_SAT, v >> 8);
-		break;
-	case OVCAMCHIP_CID_HUE:
-		rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write(c, REG_BLUE, v >> 8);
-		break;
-	case OVCAMCHIP_CID_EXP:
-		rc = ov_write(c, REG_EXP, v);
-		break;
-	case OVCAMCHIP_CID_FREQ:
-	{
-		int sixty = (v == 60);
-
-		rc = ov_write(c, 0x2b, sixty?0xa8:0x28);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write(c, 0x2a, sixty?0x84:0xa4);
-		break;
-	}
-	case OVCAMCHIP_CID_BANDFILT:
-		rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
-		s->bandfilt = v;
-		break;
-	case OVCAMCHIP_CID_AUTOBRIGHT:
-		rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
-		s->auto_brt = v;
-		break;
-	case OVCAMCHIP_CID_AUTOEXP:
-		rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
-		s->auto_exp = v;
-		break;
-	case OVCAMCHIP_CID_BACKLIGHT:
-	{
-		rc = ov_write_mask(c, 0x4e, v?0xe0:0xc0, 0xe0);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write_mask(c, 0x0e, v?0x80:0x00, 0x80);
-		s->backlight = v;
-		break;
-	}
-	case OVCAMCHIP_CID_MIRROR:
-		rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
-		s->mirror = v;
-		break;
-	default:
-		DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-		return -EPERM;
-	}
-
-out:
-	DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
-	return rc;
-}
-
-static int ov6x20_get_control(struct i2c_client *c,
-			      struct ovcamchip_control *ctl)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov6x20 *s = ov->spriv;
-	int rc = 0;
-	unsigned char val = 0;
-
-	switch (ctl->id) {
-	case OVCAMCHIP_CID_CONT:
-		rc = ov_read(c, REG_CNT, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_BRIGHT:
-		rc = ov_read(c, REG_BRT, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_SAT:
-		rc = ov_read(c, REG_SAT, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_HUE:
-		rc = ov_read(c, REG_BLUE, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_EXP:
-		rc = ov_read(c, REG_EXP, &val);
-		ctl->value = val;
-		break;
-	case OVCAMCHIP_CID_BANDFILT:
-		ctl->value = s->bandfilt;
-		break;
-	case OVCAMCHIP_CID_AUTOBRIGHT:
-		ctl->value = s->auto_brt;
-		break;
-	case OVCAMCHIP_CID_AUTOEXP:
-		ctl->value = s->auto_exp;
-		break;
-	case OVCAMCHIP_CID_BACKLIGHT:
-		ctl->value = s->backlight;
-		break;
-	case OVCAMCHIP_CID_MIRROR:
-		ctl->value = s->mirror;
-		break;
-	default:
-		DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-		return -EPERM;
-	}
-
-	DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
-	return rc;
-}
-
-static int ov6x20_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
-	/******** QCIF-specific regs ********/
-
-	ov_write(c, 0x14, win->quarter?0x24:0x04);
-
-	/******** Palette-specific regs ********/
-
-	/* OV518 needs 8 bit multiplexed in color mode, and 16 bit in B&W */
-	if (c->adapter->id == I2C_HW_SMBUS_OV518) {
-		if (win->format == VIDEO_PALETTE_GREY)
-			ov_write_mask(c, 0x13, 0x00, 0x20);
-		else
-			ov_write_mask(c, 0x13, 0x20, 0x20);
-	} else {
-		if (win->format == VIDEO_PALETTE_GREY)
-			ov_write_mask(c, 0x13, 0x20, 0x20);
-		else
-			ov_write_mask(c, 0x13, 0x00, 0x20);
-	}
-
-	/******** Clock programming ********/
-
-	/* The OV6620 needs special handling. This prevents the
-	 * severe banding that normally occurs */
-
-	/* Clock down */
-	ov_write(c, 0x2a, 0x04);
-
-	ov_write(c, 0x11, win->clockdiv);
-
-	ov_write(c, 0x2a, 0x84);
-	/* This next setting is critical. It seems to improve
-	 * the gain or the contrast. The "reserved" bits seem
-	 * to have some effect in this case. */
-	ov_write(c, 0x2d, 0x85); /* FIXME: This messes up banding filter */
-
-	return 0;
-}
-
-static int ov6x20_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
-	int ret, hwscale, vwscale;
-
-	ret = ov6x20_mode_init(c, win);
-	if (ret < 0)
-		return ret;
-
-	if (win->quarter) {
-		hwscale = 0;
-		vwscale = 0;
-	} else {
-		hwscale = 1;
-		vwscale = 1;	/* The datasheet says 0; it's wrong */
-	}
-
-	ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
-	ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
-	ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
-	ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
-	return 0;
-}
-
-static int ov6x20_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
-	switch (cmd) {
-	case OVCAMCHIP_CMD_S_CTRL:
-		return ov6x20_set_control(c, arg);
-	case OVCAMCHIP_CMD_G_CTRL:
-		return ov6x20_get_control(c, arg);
-	case OVCAMCHIP_CMD_S_MODE:
-		return ov6x20_set_window(c, arg);
-	default:
-		DDEBUG(2, &c->dev, "command not supported: %d", cmd);
-		return -ENOIOCTLCMD;
-	}
-}
-
-struct ovcamchip_ops ov6x20_ops = {
-	.init    =	ov6x20_init,
-	.free    =	ov6x20_free,
-	.command =	ov6x20_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov6x30.c b/drivers/media/video/ovcamchip/ov6x30.c
deleted file mode 100644
index 73b94f5..0000000
--- a/drivers/media/video/ovcamchip/ov6x30.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/* OmniVision OV6630/OV6130 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN		0x00	/* gain [5:0] */
-#define REG_BLUE		0x01	/* blue gain */
-#define REG_RED			0x02	/* red gain */
-#define REG_SAT			0x03	/* saturation [7:3] */
-#define REG_CNT			0x05	/* Y contrast [3:0] */
-#define REG_BRT			0x06	/* Y brightness */
-#define REG_SHARP		0x07	/* sharpness */
-#define REG_WB_BLUE		0x0C	/* WB blue ratio [5:0] */
-#define REG_WB_RED		0x0D	/* WB red ratio [5:0] */
-#define REG_EXP			0x10	/* exposure */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3A
-#define VWSBASE 0x05
-#define VWEBASE 0x06
-
-struct ov6x30 {
-	int auto_brt;
-	int auto_exp;
-	int backlight;
-	int bandfilt;
-	int mirror;
-};
-
-static struct ovcamchip_regvals regvals_init_6x30[] = {
-	{ 0x12, 0x80 }, /* reset */
-	{ 0x00, 0x1f }, /* Gain */
-	{ 0x01, 0x99 }, /* Blue gain */
-	{ 0x02, 0x7c }, /* Red gain */
-	{ 0x03, 0xc0 }, /* Saturation */
-	{ 0x05, 0x0a }, /* Contrast */
-	{ 0x06, 0x95 }, /* Brightness */
-	{ 0x07, 0x2d }, /* Sharpness */
-	{ 0x0c, 0x20 },
-	{ 0x0d, 0x20 },
-	{ 0x0e, 0x20 },
-	{ 0x0f, 0x05 },
-	{ 0x10, 0x9a }, /* "exposure check" */
-	{ 0x11, 0x00 }, /* Pixel clock = fastest */
-	{ 0x12, 0x24 }, /* Enable AGC and AWB */
-	{ 0x13, 0x21 },
-	{ 0x14, 0x80 },
-	{ 0x15, 0x01 },
-	{ 0x16, 0x03 },
-	{ 0x17, 0x38 },
-	{ 0x18, 0xea },
-	{ 0x19, 0x04 },
-	{ 0x1a, 0x93 },
-	{ 0x1b, 0x00 },
-	{ 0x1e, 0xc4 },
-	{ 0x1f, 0x04 },
-	{ 0x20, 0x20 },
-	{ 0x21, 0x10 },
-	{ 0x22, 0x88 },
-	{ 0x23, 0xc0 }, /* Crystal circuit power level */
-	{ 0x25, 0x9a }, /* Increase AEC black pixel ratio */
-	{ 0x26, 0xb2 }, /* BLC enable */
-	{ 0x27, 0xa2 },
-	{ 0x28, 0x00 },
-	{ 0x29, 0x00 },
-	{ 0x2a, 0x84 }, /* (keep) */
-	{ 0x2b, 0xa8 }, /* (keep) */
-	{ 0x2c, 0xa0 },
-	{ 0x2d, 0x95 },	/* Enable auto-brightness */
-	{ 0x2e, 0x88 },
-	{ 0x33, 0x26 },
-	{ 0x34, 0x03 },
-	{ 0x36, 0x8f },
-	{ 0x37, 0x80 },
-	{ 0x38, 0x83 },
-	{ 0x39, 0x80 },
-	{ 0x3a, 0x0f },
-	{ 0x3b, 0x3c },
-	{ 0x3c, 0x1a },
-	{ 0x3d, 0x80 },
-	{ 0x3e, 0x80 },
-	{ 0x3f, 0x0e },
-	{ 0x40, 0x00 }, /* White bal */
-	{ 0x41, 0x00 }, /* White bal */
-	{ 0x42, 0x80 },
-	{ 0x43, 0x3f }, /* White bal */
-	{ 0x44, 0x80 },
-	{ 0x45, 0x20 },
-	{ 0x46, 0x20 },
-	{ 0x47, 0x80 },
-	{ 0x48, 0x7f },
-	{ 0x49, 0x00 },
-	{ 0x4a, 0x00 },
-	{ 0x4b, 0x80 },
-	{ 0x4c, 0xd0 },
-	{ 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
-	{ 0x4e, 0x40 },
-	{ 0x4f, 0x07 }, /* UV average mode, color killer: strongest */
-	{ 0x50, 0xff },
-	{ 0x54, 0x23 }, /* Max AGC gain: 18dB */
-	{ 0x55, 0xff },
-	{ 0x56, 0x12 },
-	{ 0x57, 0x81 }, /* (default) */
-	{ 0x58, 0x75 },
-	{ 0x59, 0x01 }, /* AGC dark current compensation: +1 */
-	{ 0x5a, 0x2c },
-	{ 0x5b, 0x0f }, /* AWB chrominance levels */
-	{ 0x5c, 0x10 },
-	{ 0x3d, 0x80 },
-	{ 0x27, 0xa6 },
-	/* Toggle AWB off and on */
-	{ 0x12, 0x20 },
-	{ 0x12, 0x24 },
-
-	{ 0xff, 0xff },	/* END MARKER */
-};
-
-/* This initializes the OV6x30 camera chip and relevant variables. */
-static int ov6x30_init(struct i2c_client *c)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov6x30 *s;
-	int rc;
-
-	DDEBUG(4, &c->dev, "entered");
-
-	rc = ov_write_regvals(c, regvals_init_6x30);
-	if (rc < 0)
-		return rc;
-
-	ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
-	if (!s)
-		return -ENOMEM;
-
-	s->auto_brt = 1;
-	s->auto_exp = 1;
-
-	return rc;
-}
-
-static int ov6x30_free(struct i2c_client *c)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-
-	kfree(ov->spriv);
-	return 0;
-}
-
-static int ov6x30_set_control(struct i2c_client *c,
-			      struct ovcamchip_control *ctl)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov6x30 *s = ov->spriv;
-	int rc;
-	int v = ctl->value;
-
-	switch (ctl->id) {
-	case OVCAMCHIP_CID_CONT:
-		rc = ov_write_mask(c, REG_CNT, v >> 12, 0x0f);
-		break;
-	case OVCAMCHIP_CID_BRIGHT:
-		rc = ov_write(c, REG_BRT, v >> 8);
-		break;
-	case OVCAMCHIP_CID_SAT:
-		rc = ov_write(c, REG_SAT, v >> 8);
-		break;
-	case OVCAMCHIP_CID_HUE:
-		rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write(c, REG_BLUE, v >> 8);
-		break;
-	case OVCAMCHIP_CID_EXP:
-		rc = ov_write(c, REG_EXP, v);
-		break;
-	case OVCAMCHIP_CID_FREQ:
-	{
-		int sixty = (v == 60);
-
-		rc = ov_write(c, 0x2b, sixty?0xa8:0x28);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write(c, 0x2a, sixty?0x84:0xa4);
-		break;
-	}
-	case OVCAMCHIP_CID_BANDFILT:
-		rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
-		s->bandfilt = v;
-		break;
-	case OVCAMCHIP_CID_AUTOBRIGHT:
-		rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
-		s->auto_brt = v;
-		break;
-	case OVCAMCHIP_CID_AUTOEXP:
-		rc = ov_write_mask(c, 0x28, v?0x00:0x10, 0x10);
-		s->auto_exp = v;
-		break;
-	case OVCAMCHIP_CID_BACKLIGHT:
-	{
-		rc = ov_write_mask(c, 0x4e, v?0x80:0x60, 0xe0);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write_mask(c, 0x28, v?0x02:0x00, 0x02);
-		s->backlight = v;
-		break;
-	}
-	case OVCAMCHIP_CID_MIRROR:
-		rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
-		s->mirror = v;
-		break;
-	default:
-		DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-		return -EPERM;
-	}
-
-out:
-	DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
-	return rc;
-}
-
-static int ov6x30_get_control(struct i2c_client *c,
-			      struct ovcamchip_control *ctl)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov6x30 *s = ov->spriv;
-	int rc = 0;
-	unsigned char val = 0;
-
-	switch (ctl->id) {
-	case OVCAMCHIP_CID_CONT:
-		rc = ov_read(c, REG_CNT, &val);
-		ctl->value = (val & 0x0f) << 12;
-		break;
-	case OVCAMCHIP_CID_BRIGHT:
-		rc = ov_read(c, REG_BRT, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_SAT:
-		rc = ov_read(c, REG_SAT, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_HUE:
-		rc = ov_read(c, REG_BLUE, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_EXP:
-		rc = ov_read(c, REG_EXP, &val);
-		ctl->value = val;
-		break;
-	case OVCAMCHIP_CID_BANDFILT:
-		ctl->value = s->bandfilt;
-		break;
-	case OVCAMCHIP_CID_AUTOBRIGHT:
-		ctl->value = s->auto_brt;
-		break;
-	case OVCAMCHIP_CID_AUTOEXP:
-		ctl->value = s->auto_exp;
-		break;
-	case OVCAMCHIP_CID_BACKLIGHT:
-		ctl->value = s->backlight;
-		break;
-	case OVCAMCHIP_CID_MIRROR:
-		ctl->value = s->mirror;
-		break;
-	default:
-		DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-		return -EPERM;
-	}
-
-	DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
-	return rc;
-}
-
-static int ov6x30_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
-	/******** QCIF-specific regs ********/
-
-	ov_write_mask(c, 0x14, win->quarter?0x20:0x00, 0x20);
-
-	/******** Palette-specific regs ********/
-
-	if (win->format == VIDEO_PALETTE_GREY) {
-		if (c->adapter->id == I2C_HW_SMBUS_OV518) {
-			/* Do nothing - we're already in 8-bit mode */
-		} else {
-			ov_write_mask(c, 0x13, 0x20, 0x20);
-		}
-	} else {
-		/* The OV518 needs special treatment. Although both the OV518
-		 * and the OV6630 support a 16-bit video bus, only the 8 bit Y
-		 * bus is actually used. The UV bus is tied to ground.
-		 * Therefore, the OV6630 needs to be in 8-bit multiplexed
-		 * output mode */
-
-		if (c->adapter->id == I2C_HW_SMBUS_OV518) {
-			/* Do nothing - we want to stay in 8-bit mode */
-			/* Warning: Messing with reg 0x13 breaks OV518 color */
-		} else {
-			ov_write_mask(c, 0x13, 0x00, 0x20);
-		}
-	}
-
-	/******** Clock programming ********/
-
-	ov_write(c, 0x11, win->clockdiv);
-
-	return 0;
-}
-
-static int ov6x30_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
-	int ret, hwscale, vwscale;
-
-	ret = ov6x30_mode_init(c, win);
-	if (ret < 0)
-		return ret;
-
-	if (win->quarter) {
-		hwscale = 0;
-		vwscale = 0;
-	} else {
-		hwscale = 1;
-		vwscale = 1;	/* The datasheet says 0; it's wrong */
-	}
-
-	ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
-	ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
-	ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
-	ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
-	return 0;
-}
-
-static int ov6x30_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
-	switch (cmd) {
-	case OVCAMCHIP_CMD_S_CTRL:
-		return ov6x30_set_control(c, arg);
-	case OVCAMCHIP_CMD_G_CTRL:
-		return ov6x30_get_control(c, arg);
-	case OVCAMCHIP_CMD_S_MODE:
-		return ov6x30_set_window(c, arg);
-	default:
-		DDEBUG(2, &c->dev, "command not supported: %d", cmd);
-		return -ENOIOCTLCMD;
-	}
-}
-
-struct ovcamchip_ops ov6x30_ops = {
-	.init    =	ov6x30_init,
-	.free    =	ov6x30_free,
-	.command =	ov6x30_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov76be.c b/drivers/media/video/ovcamchip/ov76be.c
deleted file mode 100644
index 11f6be9..0000000
--- a/drivers/media/video/ovcamchip/ov76be.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* OmniVision OV76BE Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* OV7610 registers: Since the OV76BE is undocumented, we'll settle for these
- * for now. */
-#define REG_GAIN		0x00	/* gain [5:0] */
-#define REG_BLUE		0x01	/* blue channel balance */
-#define REG_RED			0x02	/* red channel balance */
-#define REG_SAT			0x03	/* saturation */
-#define REG_CNT			0x05	/* Y contrast */
-#define REG_BRT			0x06	/* Y brightness */
-#define REG_BLUE_BIAS		0x0C	/* blue channel bias [5:0] */
-#define REG_RED_BIAS		0x0D	/* red channel bias [5:0] */
-#define REG_GAMMA_COEFF		0x0E	/* gamma settings */
-#define REG_WB_RANGE		0x0F	/* AEC/ALC/S-AWB settings */
-#define REG_EXP			0x10	/* manual exposure setting */
-#define REG_CLOCK		0x11	/* polarity/clock prescaler */
-#define REG_FIELD_DIVIDE	0x16	/* field interval/mode settings */
-#define REG_HWIN_START		0x17	/* horizontal window start */
-#define REG_HWIN_END		0x18	/* horizontal window end */
-#define REG_VWIN_START		0x19	/* vertical window start */
-#define REG_VWIN_END		0x1A	/* vertical window end */
-#define REG_PIXEL_SHIFT   	0x1B	/* pixel shift */
-#define REG_YOFFSET		0x21	/* Y channel offset */
-#define REG_UOFFSET		0x22	/* U channel offset */
-#define REG_ECW			0x24	/* exposure white level for AEC */
-#define REG_ECB			0x25	/* exposure black level for AEC */
-#define REG_FRAMERATE_H		0x2A	/* frame rate MSB + misc */
-#define REG_FRAMERATE_L		0x2B	/* frame rate LSB */
-#define REG_ALC			0x2C	/* Auto Level Control settings */
-#define REG_VOFFSET		0x2E	/* V channel offset adjustment */
-#define REG_ARRAY_BIAS		0x2F	/* array bias -- don't change */
-#define REG_YGAMMA		0x33	/* misc gamma settings [7:6] */
-#define REG_BIAS_ADJUST		0x34	/* misc bias settings */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3a
-#define VWSBASE 0x05
-#define VWEBASE 0x05
-
-struct ov76be {
-	int auto_brt;
-	int auto_exp;
-	int bandfilt;
-	int mirror;
-};
-
-/* NOTE: These are the same as the 7x10 settings, but should eventually be
- * optimized for the OV76BE */
-static struct ovcamchip_regvals regvals_init_76be[] = {
-	{ 0x10, 0xff },
-	{ 0x16, 0x03 },
-	{ 0x28, 0x24 },
-	{ 0x2b, 0xac },
-	{ 0x12, 0x00 },
-	{ 0x38, 0x81 },
-	{ 0x28, 0x24 },	/* 0c */
-	{ 0x0f, 0x85 },	/* lg's setting */
-	{ 0x15, 0x01 },
-	{ 0x20, 0x1c },
-	{ 0x23, 0x2a },
-	{ 0x24, 0x10 },
-	{ 0x25, 0x8a },
-	{ 0x26, 0xa2 },
-	{ 0x27, 0xc2 },
-	{ 0x2a, 0x04 },
-	{ 0x2c, 0xfe },
-	{ 0x2d, 0x93 },
-	{ 0x30, 0x71 },
-	{ 0x31, 0x60 },
-	{ 0x32, 0x26 },
-	{ 0x33, 0x20 },
-	{ 0x34, 0x48 },
-	{ 0x12, 0x24 },
-	{ 0x11, 0x01 },
-	{ 0x0c, 0x24 },
-	{ 0x0d, 0x24 },
-	{ 0xff, 0xff },	/* END MARKER */
-};
-
-/* This initializes the OV76be camera chip and relevant variables. */
-static int ov76be_init(struct i2c_client *c)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov76be *s;
-	int rc;
-
-	DDEBUG(4, &c->dev, "entered");
-
-	rc = ov_write_regvals(c, regvals_init_76be);
-	if (rc < 0)
-		return rc;
-
-	ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
-	if (!s)
-		return -ENOMEM;
-
-	s->auto_brt = 1;
-	s->auto_exp = 1;
-
-	return rc;
-}
-
-static int ov76be_free(struct i2c_client *c)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-
-	kfree(ov->spriv);
-	return 0;
-}
-
-static int ov76be_set_control(struct i2c_client *c,
-			      struct ovcamchip_control *ctl)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov76be *s = ov->spriv;
-	int rc;
-	int v = ctl->value;
-
-	switch (ctl->id) {
-	case OVCAMCHIP_CID_BRIGHT:
-		rc = ov_write(c, REG_BRT, v >> 8);
-		break;
-	case OVCAMCHIP_CID_SAT:
-		rc = ov_write(c, REG_SAT, v >> 8);
-		break;
-	case OVCAMCHIP_CID_EXP:
-		rc = ov_write(c, REG_EXP, v);
-		break;
-	case OVCAMCHIP_CID_FREQ:
-	{
-		int sixty = (v == 60);
-
-		rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write(c, 0x2b, sixty?0x00:0xac);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write_mask(c, 0x76, 0x01, 0x01);
-		break;
-	}
-	case OVCAMCHIP_CID_BANDFILT:
-		rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
-		s->bandfilt = v;
-		break;
-	case OVCAMCHIP_CID_AUTOBRIGHT:
-		rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
-		s->auto_brt = v;
-		break;
-	case OVCAMCHIP_CID_AUTOEXP:
-		rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
-		s->auto_exp = v;
-		break;
-	case OVCAMCHIP_CID_MIRROR:
-		rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
-		s->mirror = v;
-		break;
-	default:
-		DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-		return -EPERM;
-	}
-
-out:
-	DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
-	return rc;
-}
-
-static int ov76be_get_control(struct i2c_client *c,
-			      struct ovcamchip_control *ctl)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov76be *s = ov->spriv;
-	int rc = 0;
-	unsigned char val = 0;
-
-	switch (ctl->id) {
-	case OVCAMCHIP_CID_BRIGHT:
-		rc = ov_read(c, REG_BRT, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_SAT:
-		rc = ov_read(c, REG_SAT, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_EXP:
-		rc = ov_read(c, REG_EXP, &val);
-		ctl->value = val;
-		break;
-	case OVCAMCHIP_CID_BANDFILT:
-		ctl->value = s->bandfilt;
-		break;
-	case OVCAMCHIP_CID_AUTOBRIGHT:
-		ctl->value = s->auto_brt;
-		break;
-	case OVCAMCHIP_CID_AUTOEXP:
-		ctl->value = s->auto_exp;
-		break;
-	case OVCAMCHIP_CID_MIRROR:
-		ctl->value = s->mirror;
-		break;
-	default:
-		DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-		return -EPERM;
-	}
-
-	DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
-	return rc;
-}
-
-static int ov76be_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
-	int qvga = win->quarter;
-
-	/******** QVGA-specific regs ********/
-
-	ov_write(c, 0x14, qvga?0xa4:0x84);
-
-	/******** Palette-specific regs ********/
-
-	if (win->format == VIDEO_PALETTE_GREY) {
-		ov_write_mask(c, 0x0e, 0x40, 0x40);
-		ov_write_mask(c, 0x13, 0x20, 0x20);
-	} else {
-		ov_write_mask(c, 0x0e, 0x00, 0x40);
-		ov_write_mask(c, 0x13, 0x00, 0x20);
-	}
-
-	/******** Clock programming ********/
-
-	ov_write(c, 0x11, win->clockdiv);
-
-	/******** Resolution-specific ********/
-
-	if (win->width == 640 && win->height == 480)
-		ov_write(c, 0x35, 0x9e);
-	else
-		ov_write(c, 0x35, 0x1e);
-
-	return 0;
-}
-
-static int ov76be_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
-	int ret, hwscale, vwscale;
-
-	ret = ov76be_mode_init(c, win);
-	if (ret < 0)
-		return ret;
-
-	if (win->quarter) {
-		hwscale = 1;
-		vwscale = 0;
-	} else {
-		hwscale = 2;
-		vwscale = 1;
-	}
-
-	ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
-	ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
-	ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
-	ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
-	return 0;
-}
-
-static int ov76be_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
-	switch (cmd) {
-	case OVCAMCHIP_CMD_S_CTRL:
-		return ov76be_set_control(c, arg);
-	case OVCAMCHIP_CMD_G_CTRL:
-		return ov76be_get_control(c, arg);
-	case OVCAMCHIP_CMD_S_MODE:
-		return ov76be_set_window(c, arg);
-	default:
-		DDEBUG(2, &c->dev, "command not supported: %d", cmd);
-		return -ENOIOCTLCMD;
-	}
-}
-
-struct ovcamchip_ops ov76be_ops = {
-	.init    =	ov76be_init,
-	.free    =	ov76be_free,
-	.command =	ov76be_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov7x10.c b/drivers/media/video/ovcamchip/ov7x10.c
deleted file mode 100644
index 5206e79..0000000
--- a/drivers/media/video/ovcamchip/ov7x10.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/* OmniVision OV7610/OV7110 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN		0x00	/* gain [5:0] */
-#define REG_BLUE		0x01	/* blue channel balance */
-#define REG_RED			0x02	/* red channel balance */
-#define REG_SAT			0x03	/* saturation */
-#define REG_CNT			0x05	/* Y contrast */
-#define REG_BRT			0x06	/* Y brightness */
-#define REG_BLUE_BIAS		0x0C	/* blue channel bias [5:0] */
-#define REG_RED_BIAS		0x0D	/* red channel bias [5:0] */
-#define REG_GAMMA_COEFF		0x0E	/* gamma settings */
-#define REG_WB_RANGE		0x0F	/* AEC/ALC/S-AWB settings */
-#define REG_EXP			0x10	/* manual exposure setting */
-#define REG_CLOCK		0x11	/* polarity/clock prescaler */
-#define REG_FIELD_DIVIDE	0x16	/* field interval/mode settings */
-#define REG_HWIN_START		0x17	/* horizontal window start */
-#define REG_HWIN_END		0x18	/* horizontal window end */
-#define REG_VWIN_START		0x19	/* vertical window start */
-#define REG_VWIN_END		0x1A	/* vertical window end */
-#define REG_PIXEL_SHIFT   	0x1B	/* pixel shift */
-#define REG_YOFFSET		0x21	/* Y channel offset */
-#define REG_UOFFSET		0x22	/* U channel offset */
-#define REG_ECW			0x24	/* exposure white level for AEC */
-#define REG_ECB			0x25	/* exposure black level for AEC */
-#define REG_FRAMERATE_H		0x2A	/* frame rate MSB + misc */
-#define REG_FRAMERATE_L		0x2B	/* frame rate LSB */
-#define REG_ALC			0x2C	/* Auto Level Control settings */
-#define REG_VOFFSET		0x2E	/* V channel offset adjustment */
-#define REG_ARRAY_BIAS		0x2F	/* array bias -- don't change */
-#define REG_YGAMMA		0x33	/* misc gamma settings [7:6] */
-#define REG_BIAS_ADJUST		0x34	/* misc bias settings */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3a
-#define VWSBASE 0x05
-#define VWEBASE 0x05
-
-struct ov7x10 {
-	int auto_brt;
-	int auto_exp;
-	int bandfilt;
-	int mirror;
-};
-
-/* Lawrence Glaister <lg@jfm.bc.ca> reports:
- *
- * Register 0x0f in the 7610 has the following effects:
- *
- * 0x85 (AEC method 1): Best overall, good contrast range
- * 0x45 (AEC method 2): Very overexposed
- * 0xa5 (spec sheet default): Ok, but the black level is
- *	shifted resulting in loss of contrast
- * 0x05 (old driver setting): very overexposed, too much
- *	contrast
- */
-static struct ovcamchip_regvals regvals_init_7x10[] = {
-	{ 0x10, 0xff },
-	{ 0x16, 0x03 },
-	{ 0x28, 0x24 },
-	{ 0x2b, 0xac },
-	{ 0x12, 0x00 },
-	{ 0x38, 0x81 },
-	{ 0x28, 0x24 },	/* 0c */
-	{ 0x0f, 0x85 },	/* lg's setting */
-	{ 0x15, 0x01 },
-	{ 0x20, 0x1c },
-	{ 0x23, 0x2a },
-	{ 0x24, 0x10 },
-	{ 0x25, 0x8a },
-	{ 0x26, 0xa2 },
-	{ 0x27, 0xc2 },
-	{ 0x2a, 0x04 },
-	{ 0x2c, 0xfe },
-	{ 0x2d, 0x93 },
-	{ 0x30, 0x71 },
-	{ 0x31, 0x60 },
-	{ 0x32, 0x26 },
-	{ 0x33, 0x20 },
-	{ 0x34, 0x48 },
-	{ 0x12, 0x24 },
-	{ 0x11, 0x01 },
-	{ 0x0c, 0x24 },
-	{ 0x0d, 0x24 },
-	{ 0xff, 0xff },	/* END MARKER */
-};
-
-/* This initializes the OV7x10 camera chip and relevant variables. */
-static int ov7x10_init(struct i2c_client *c)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov7x10 *s;
-	int rc;
-
-	DDEBUG(4, &c->dev, "entered");
-
-	rc = ov_write_regvals(c, regvals_init_7x10);
-	if (rc < 0)
-		return rc;
-
-	ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
-	if (!s)
-		return -ENOMEM;
-
-	s->auto_brt = 1;
-	s->auto_exp = 1;
-
-	return rc;
-}
-
-static int ov7x10_free(struct i2c_client *c)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-
-	kfree(ov->spriv);
-	return 0;
-}
-
-static int ov7x10_set_control(struct i2c_client *c,
-			      struct ovcamchip_control *ctl)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov7x10 *s = ov->spriv;
-	int rc;
-	int v = ctl->value;
-
-	switch (ctl->id) {
-	case OVCAMCHIP_CID_CONT:
-		rc = ov_write(c, REG_CNT, v >> 8);
-		break;
-	case OVCAMCHIP_CID_BRIGHT:
-		rc = ov_write(c, REG_BRT, v >> 8);
-		break;
-	case OVCAMCHIP_CID_SAT:
-		rc = ov_write(c, REG_SAT, v >> 8);
-		break;
-	case OVCAMCHIP_CID_HUE:
-		rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write(c, REG_BLUE, v >> 8);
-		break;
-	case OVCAMCHIP_CID_EXP:
-		rc = ov_write(c, REG_EXP, v);
-		break;
-	case OVCAMCHIP_CID_FREQ:
-	{
-		int sixty = (v == 60);
-
-		rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write(c, 0x2b, sixty?0x00:0xac);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write_mask(c, 0x13, 0x10, 0x10);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write_mask(c, 0x13, 0x00, 0x10);
-		break;
-	}
-	case OVCAMCHIP_CID_BANDFILT:
-		rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
-		s->bandfilt = v;
-		break;
-	case OVCAMCHIP_CID_AUTOBRIGHT:
-		rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
-		s->auto_brt = v;
-		break;
-	case OVCAMCHIP_CID_AUTOEXP:
-		rc = ov_write_mask(c, 0x29, v?0x00:0x80, 0x80);
-		s->auto_exp = v;
-		break;
-	case OVCAMCHIP_CID_MIRROR:
-		rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
-		s->mirror = v;
-		break;
-	default:
-		DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-		return -EPERM;
-	}
-
-out:
-	DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
-	return rc;
-}
-
-static int ov7x10_get_control(struct i2c_client *c,
-			      struct ovcamchip_control *ctl)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov7x10 *s = ov->spriv;
-	int rc = 0;
-	unsigned char val = 0;
-
-	switch (ctl->id) {
-	case OVCAMCHIP_CID_CONT:
-		rc = ov_read(c, REG_CNT, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_BRIGHT:
-		rc = ov_read(c, REG_BRT, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_SAT:
-		rc = ov_read(c, REG_SAT, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_HUE:
-		rc = ov_read(c, REG_BLUE, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_EXP:
-		rc = ov_read(c, REG_EXP, &val);
-		ctl->value = val;
-		break;
-	case OVCAMCHIP_CID_BANDFILT:
-		ctl->value = s->bandfilt;
-		break;
-	case OVCAMCHIP_CID_AUTOBRIGHT:
-		ctl->value = s->auto_brt;
-		break;
-	case OVCAMCHIP_CID_AUTOEXP:
-		ctl->value = s->auto_exp;
-		break;
-	case OVCAMCHIP_CID_MIRROR:
-		ctl->value = s->mirror;
-		break;
-	default:
-		DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-		return -EPERM;
-	}
-
-	DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
-	return rc;
-}
-
-static int ov7x10_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
-	int qvga = win->quarter;
-
-	/******** QVGA-specific regs ********/
-
-	ov_write(c, 0x14, qvga?0x24:0x04);
-
-	/******** Palette-specific regs ********/
-
-	if (win->format == VIDEO_PALETTE_GREY) {
-		ov_write_mask(c, 0x0e, 0x40, 0x40);
-		ov_write_mask(c, 0x13, 0x20, 0x20);
-	} else {
-		ov_write_mask(c, 0x0e, 0x00, 0x40);
-		ov_write_mask(c, 0x13, 0x00, 0x20);
-	}
-
-	/******** Clock programming ********/
-
-	ov_write(c, 0x11, win->clockdiv);
-
-	/******** Resolution-specific ********/
-
-	if (win->width == 640 && win->height == 480)
-		ov_write(c, 0x35, 0x9e);
-	else
-		ov_write(c, 0x35, 0x1e);
-
-	return 0;
-}
-
-static int ov7x10_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
-	int ret, hwscale, vwscale;
-
-	ret = ov7x10_mode_init(c, win);
-	if (ret < 0)
-		return ret;
-
-	if (win->quarter) {
-		hwscale = 1;
-		vwscale = 0;
-	} else {
-		hwscale = 2;
-		vwscale = 1;
-	}
-
-	ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
-	ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
-	ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
-	ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
-	return 0;
-}
-
-static int ov7x10_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
-	switch (cmd) {
-	case OVCAMCHIP_CMD_S_CTRL:
-		return ov7x10_set_control(c, arg);
-	case OVCAMCHIP_CMD_G_CTRL:
-		return ov7x10_get_control(c, arg);
-	case OVCAMCHIP_CMD_S_MODE:
-		return ov7x10_set_window(c, arg);
-	default:
-		DDEBUG(2, &c->dev, "command not supported: %d", cmd);
-		return -ENOIOCTLCMD;
-	}
-}
-
-struct ovcamchip_ops ov7x10_ops = {
-	.init    =	ov7x10_init,
-	.free    =	ov7x10_free,
-	.command =	ov7x10_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov7x20.c b/drivers/media/video/ovcamchip/ov7x20.c
deleted file mode 100644
index 8e26ae3..0000000
--- a/drivers/media/video/ovcamchip/ov7x20.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/* OmniVision OV7620/OV7120 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * OV7620 fixes by Charl P. Botha <cpbotha@ieee.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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN		0x00	/* gain [5:0] */
-#define REG_BLUE		0x01	/* blue gain */
-#define REG_RED			0x02	/* red gain */
-#define REG_SAT			0x03	/* saturation */
-#define REG_BRT			0x06	/* Y brightness */
-#define REG_SHARP		0x07	/* analog sharpness */
-#define REG_BLUE_BIAS		0x0C	/* WB blue ratio [5:0] */
-#define REG_RED_BIAS		0x0D	/* WB red ratio [5:0] */
-#define REG_EXP			0x10	/* exposure */
-
-/* Default control settings. Values are in terms of V4L2 controls. */
-#define OV7120_DFL_BRIGHT     0x60
-#define OV7620_DFL_BRIGHT     0x60
-#define OV7120_DFL_SAT        0xb0
-#define OV7620_DFL_SAT        0xc0
-#define DFL_AUTO_EXP             1
-#define DFL_AUTO_GAIN            1
-#define OV7120_DFL_GAIN       0x00
-#define OV7620_DFL_GAIN       0x00
-/* NOTE: Since autoexposure is the default, these aren't programmed into the
- * OV7x20 chip. They are just here because V4L2 expects a default */
-#define OV7120_DFL_EXP        0x7f
-#define OV7620_DFL_EXP        0x7f
-
-/* Window parameters */
-#define HWSBASE 0x2F	/* From 7620.SET (spec is wrong) */
-#define HWEBASE 0x2F
-#define VWSBASE 0x05
-#define VWEBASE 0x05
-
-struct ov7x20 {
-	int auto_brt;
-	int auto_exp;
-	int auto_gain;
-	int backlight;
-	int bandfilt;
-	int mirror;
-};
-
-/* Contrast look-up table */
-static unsigned char ctab[] = {
-	0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
-	0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
-};
-
-/* Settings for (Black & White) OV7120 camera chip */
-static struct ovcamchip_regvals regvals_init_7120[] = {
-	{ 0x12, 0x80 }, /* reset */
-	{ 0x13, 0x00 }, /* Autoadjust off */
-	{ 0x12, 0x20 }, /* Disable AWB */
-	{ 0x13, DFL_AUTO_GAIN?0x01:0x00 }, /* Autoadjust on (if desired) */
-	{ 0x00, OV7120_DFL_GAIN },
-	{ 0x01, 0x80 },
-	{ 0x02, 0x80 },
-	{ 0x03, OV7120_DFL_SAT },
-	{ 0x06, OV7120_DFL_BRIGHT },
-	{ 0x07, 0x00 },
-	{ 0x0c, 0x20 },
-	{ 0x0d, 0x20 },
-	{ 0x11, 0x01 },
-	{ 0x14, 0x84 },
-	{ 0x15, 0x01 },
-	{ 0x16, 0x03 },
-	{ 0x17, 0x2f },
-	{ 0x18, 0xcf },
-	{ 0x19, 0x06 },
-	{ 0x1a, 0xf5 },
-	{ 0x1b, 0x00 },
-	{ 0x20, 0x08 },
-	{ 0x21, 0x80 },
-	{ 0x22, 0x80 },
-	{ 0x23, 0x00 },
-	{ 0x26, 0xa0 },
-	{ 0x27, 0xfa },
-	{ 0x28, 0x20 }, /* DON'T set bit 6. It is for the OV7620 only */
-	{ 0x29, DFL_AUTO_EXP?0x00:0x80 },
-	{ 0x2a, 0x10 },
-	{ 0x2b, 0x00 },
-	{ 0x2c, 0x88 },
-	{ 0x2d, 0x95 },
-	{ 0x2e, 0x80 },
-	{ 0x2f, 0x44 },
-	{ 0x60, 0x20 },
-	{ 0x61, 0x02 },
-	{ 0x62, 0x5f },
-	{ 0x63, 0xd5 },
-	{ 0x64, 0x57 },
-	{ 0x65, 0x83 }, /* OV says "don't change this value" */
-	{ 0x66, 0x55 },
-	{ 0x67, 0x92 },
-	{ 0x68, 0xcf },
-	{ 0x69, 0x76 },
-	{ 0x6a, 0x22 },
-	{ 0x6b, 0xe2 },
-	{ 0x6c, 0x40 },
-	{ 0x6d, 0x48 },
-	{ 0x6e, 0x80 },
-	{ 0x6f, 0x0d },
-	{ 0x70, 0x89 },
-	{ 0x71, 0x00 },
-	{ 0x72, 0x14 },
-	{ 0x73, 0x54 },
-	{ 0x74, 0xa0 },
-	{ 0x75, 0x8e },
-	{ 0x76, 0x00 },
-	{ 0x77, 0xff },
-	{ 0x78, 0x80 },
-	{ 0x79, 0x80 },
-	{ 0x7a, 0x80 },
-	{ 0x7b, 0xe6 },
-	{ 0x7c, 0x00 },
-	{ 0x24, 0x3a },
-	{ 0x25, 0x60 },
-	{ 0xff, 0xff },	/* END MARKER */
-};
-
-/* Settings for (color) OV7620 camera chip */
-static struct ovcamchip_regvals regvals_init_7620[] = {
-	{ 0x12, 0x80 }, /* reset */
-	{ 0x00, OV7620_DFL_GAIN },
-	{ 0x01, 0x80 },
-	{ 0x02, 0x80 },
-	{ 0x03, OV7620_DFL_SAT },
-	{ 0x06, OV7620_DFL_BRIGHT },
-	{ 0x07, 0x00 },
-	{ 0x0c, 0x24 },
-	{ 0x0c, 0x24 },
-	{ 0x0d, 0x24 },
-	{ 0x11, 0x01 },
-	{ 0x12, 0x24 },
-	{ 0x13, DFL_AUTO_GAIN?0x01:0x00 },
-	{ 0x14, 0x84 },
-	{ 0x15, 0x01 },
-	{ 0x16, 0x03 },
-	{ 0x17, 0x2f },
-	{ 0x18, 0xcf },
-	{ 0x19, 0x06 },
-	{ 0x1a, 0xf5 },
-	{ 0x1b, 0x00 },
-	{ 0x20, 0x18 },
-	{ 0x21, 0x80 },
-	{ 0x22, 0x80 },
-	{ 0x23, 0x00 },
-	{ 0x26, 0xa2 },
-	{ 0x27, 0xea },
-	{ 0x28, 0x20 },
-	{ 0x29, DFL_AUTO_EXP?0x00:0x80 },
-	{ 0x2a, 0x10 },
-	{ 0x2b, 0x00 },
-	{ 0x2c, 0x88 },
-	{ 0x2d, 0x91 },
-	{ 0x2e, 0x80 },
-	{ 0x2f, 0x44 },
-	{ 0x60, 0x27 },
-	{ 0x61, 0x02 },
-	{ 0x62, 0x5f },
-	{ 0x63, 0xd5 },
-	{ 0x64, 0x57 },
-	{ 0x65, 0x83 },
-	{ 0x66, 0x55 },
-	{ 0x67, 0x92 },
-	{ 0x68, 0xcf },
-	{ 0x69, 0x76 },
-	{ 0x6a, 0x22 },
-	{ 0x6b, 0x00 },
-	{ 0x6c, 0x02 },
-	{ 0x6d, 0x44 },
-	{ 0x6e, 0x80 },
-	{ 0x6f, 0x1d },
-	{ 0x70, 0x8b },
-	{ 0x71, 0x00 },
-	{ 0x72, 0x14 },
-	{ 0x73, 0x54 },
-	{ 0x74, 0x00 },
-	{ 0x75, 0x8e },
-	{ 0x76, 0x00 },
-	{ 0x77, 0xff },
-	{ 0x78, 0x80 },
-	{ 0x79, 0x80 },
-	{ 0x7a, 0x80 },
-	{ 0x7b, 0xe2 },
-	{ 0x7c, 0x00 },
-	{ 0xff, 0xff },	/* END MARKER */
-};
-
-/* Returns index into the specified look-up table, with 'n' elements, for which
- * the value is greater than or equal to "val". If a match isn't found, (n-1)
- * is returned. The entries in the table must be in ascending order. */
-static inline int ov7x20_lut_find(unsigned char lut[], int n, unsigned char val)
-{
-	int i = 0;
-
-	while (lut[i] < val && i < n)
-		i++;
-
-	return i;
-}
-
-/* This initializes the OV7x20 camera chip and relevant variables. */
-static int ov7x20_init(struct i2c_client *c)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov7x20 *s;
-	int rc;
-
-	DDEBUG(4, &c->dev, "entered");
-
-	if (ov->mono)
-		rc = ov_write_regvals(c, regvals_init_7120);
-	else
-		rc = ov_write_regvals(c, regvals_init_7620);
-
-	if (rc < 0)
-		return rc;
-
-	ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
-	if (!s)
-		return -ENOMEM;
-
-	s->auto_brt = 1;
-	s->auto_exp = DFL_AUTO_EXP;
-	s->auto_gain = DFL_AUTO_GAIN;
-
-	return 0;
-}
-
-static int ov7x20_free(struct i2c_client *c)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-
-	kfree(ov->spriv);
-	return 0;
-}
-
-static int ov7x20_set_v4l1_control(struct i2c_client *c,
-				   struct ovcamchip_control *ctl)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov7x20 *s = ov->spriv;
-	int rc;
-	int v = ctl->value;
-
-	switch (ctl->id) {
-	case OVCAMCHIP_CID_CONT:
-	{
-		/* Use Y gamma control instead. Bit 0 enables it. */
-		rc = ov_write(c, 0x64, ctab[v >> 12]);
-		break;
-	}
-	case OVCAMCHIP_CID_BRIGHT:
-		/* 7620 doesn't like manual changes when in auto mode */
-		if (!s->auto_brt)
-			rc = ov_write(c, REG_BRT, v >> 8);
-		else
-			rc = 0;
-		break;
-	case OVCAMCHIP_CID_SAT:
-		rc = ov_write(c, REG_SAT, v >> 8);
-		break;
-	case OVCAMCHIP_CID_EXP:
-		if (!s->auto_exp)
-			rc = ov_write(c, REG_EXP, v);
-		else
-			rc = -EBUSY;
-		break;
-	case OVCAMCHIP_CID_FREQ:
-	{
-		int sixty = (v == 60);
-
-		rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write(c, 0x2b, sixty?0x00:0xac);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write_mask(c, 0x76, 0x01, 0x01);
-		break;
-	}
-	case OVCAMCHIP_CID_BANDFILT:
-		rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
-		s->bandfilt = v;
-		break;
-	case OVCAMCHIP_CID_AUTOBRIGHT:
-		rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
-		s->auto_brt = v;
-		break;
-	case OVCAMCHIP_CID_AUTOEXP:
-		rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
-		s->auto_exp = v;
-		break;
-	case OVCAMCHIP_CID_BACKLIGHT:
-	{
-		rc = ov_write_mask(c, 0x68, v?0xe0:0xc0, 0xe0);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
-		if (rc < 0)
-			goto out;
-
-		rc = ov_write_mask(c, 0x28, v?0x02:0x00, 0x02);
-		s->backlight = v;
-		break;
-	}
-	case OVCAMCHIP_CID_MIRROR:
-		rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
-		s->mirror = v;
-		break;
-	default:
-		DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-		return -EPERM;
-	}
-
-out:
-	DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
-	return rc;
-}
-
-static int ov7x20_get_v4l1_control(struct i2c_client *c,
-				   struct ovcamchip_control *ctl)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	struct ov7x20 *s = ov->spriv;
-	int rc = 0;
-	unsigned char val = 0;
-
-	switch (ctl->id) {
-	case OVCAMCHIP_CID_CONT:
-		rc = ov_read(c, 0x64, &val);
-		ctl->value = ov7x20_lut_find(ctab, 16, val) << 12;
-		break;
-	case OVCAMCHIP_CID_BRIGHT:
-		rc = ov_read(c, REG_BRT, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_SAT:
-		rc = ov_read(c, REG_SAT, &val);
-		ctl->value = val << 8;
-		break;
-	case OVCAMCHIP_CID_EXP:
-		rc = ov_read(c, REG_EXP, &val);
-		ctl->value = val;
-		break;
-	case OVCAMCHIP_CID_BANDFILT:
-		ctl->value = s->bandfilt;
-		break;
-	case OVCAMCHIP_CID_AUTOBRIGHT:
-		ctl->value = s->auto_brt;
-		break;
-	case OVCAMCHIP_CID_AUTOEXP:
-		ctl->value = s->auto_exp;
-		break;
-	case OVCAMCHIP_CID_BACKLIGHT:
-		ctl->value = s->backlight;
-		break;
-	case OVCAMCHIP_CID_MIRROR:
-		ctl->value = s->mirror;
-		break;
-	default:
-		DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
-		return -EPERM;
-	}
-
-	DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
-	return rc;
-}
-
-static int ov7x20_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	int qvga = win->quarter;
-
-	/******** QVGA-specific regs ********/
-	ov_write_mask(c, 0x14, qvga?0x20:0x00, 0x20);
-	ov_write_mask(c, 0x28, qvga?0x00:0x20, 0x20);
-	ov_write(c, 0x24, qvga?0x20:0x3a);
-	ov_write(c, 0x25, qvga?0x30:0x60);
-	ov_write_mask(c, 0x2d, qvga?0x40:0x00, 0x40);
-	if (!ov->mono)
-		ov_write_mask(c, 0x67, qvga?0xf0:0x90, 0xf0);
-	ov_write_mask(c, 0x74, qvga?0x20:0x00, 0x20);
-
-	/******** Clock programming ********/
-
-	ov_write(c, 0x11, win->clockdiv);
-
-	return 0;
-}
-
-static int ov7x20_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
-	int ret, hwscale, vwscale;
-
-	ret = ov7x20_mode_init(c, win);
-	if (ret < 0)
-		return ret;
-
-	if (win->quarter) {
-		hwscale = 1;
-		vwscale = 0;
-	} else {
-		hwscale = 2;
-		vwscale = 1;
-	}
-
-	ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
-	ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
-	ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
-	ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
-	return 0;
-}
-
-static int ov7x20_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
-	switch (cmd) {
-	case OVCAMCHIP_CMD_S_CTRL:
-		return ov7x20_set_v4l1_control(c, arg);
-	case OVCAMCHIP_CMD_G_CTRL:
-		return ov7x20_get_v4l1_control(c, arg);
-	case OVCAMCHIP_CMD_S_MODE:
-		return ov7x20_set_window(c, arg);
-	default:
-		DDEBUG(2, &c->dev, "command not supported: %d", cmd);
-		return -ENOIOCTLCMD;
-	}
-}
-
-struct ovcamchip_ops ov7x20_ops = {
-	.init    =	ov7x20_init,
-	.free    =	ov7x20_free,
-	.command =	ov7x20_command,
-};
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
deleted file mode 100644
index d573d84..0000000
--- a/drivers/media/video/ovcamchip/ovcamchip_core.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/* Shared Code for OmniVision Camera Chip Drivers
- *
- * Copyright (c) 2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv.h>
-#include "ovcamchip_priv.h"
-
-#define DRIVER_VERSION "v2.27 for Linux 2.6"
-#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org>"
-#define DRIVER_DESC "OV camera chip I2C driver"
-
-#define PINFO(fmt, args...) printk(KERN_INFO "ovcamchip: " fmt "\n" , ## args);
-#define PERROR(fmt, args...) printk(KERN_ERR "ovcamchip: " fmt "\n" , ## args);
-
-#ifdef DEBUG
-int ovcamchip_debug = 0;
-static int debug;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug,
-  "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=all");
-#endif
-
-/* By default, let bridge driver tell us if chip is monochrome. mono=0
- * will ignore that and always treat chips as color. mono=1 will force
- * monochrome mode for all chips. */
-static int mono = -1;
-module_param(mono, int, 0);
-MODULE_PARM_DESC(mono,
-  "1=chips are monochrome (OVx1xx), 0=force color, -1=autodetect (default)");
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-
-/* Registers common to all chips, that are needed for detection */
-#define GENERIC_REG_ID_HIGH       0x1C	/* manufacturer ID MSB */
-#define GENERIC_REG_ID_LOW        0x1D	/* manufacturer ID LSB */
-#define GENERIC_REG_COM_I         0x29	/* misc ID bits */
-
-static char *chip_names[NUM_CC_TYPES] = {
-	[CC_UNKNOWN]	= "Unknown chip",
-	[CC_OV76BE]	= "OV76BE",
-	[CC_OV7610]	= "OV7610",
-	[CC_OV7620]	= "OV7620",
-	[CC_OV7620AE]	= "OV7620AE",
-	[CC_OV6620]	= "OV6620",
-	[CC_OV6630]	= "OV6630",
-	[CC_OV6630AE]	= "OV6630AE",
-	[CC_OV6630AF]	= "OV6630AF",
-};
-
-/* ----------------------------------------------------------------------- */
-
-int ov_write_regvals(struct i2c_client *c, struct ovcamchip_regvals *rvals)
-{
-	int rc;
-
-	while (rvals->reg != 0xff) {
-		rc = ov_write(c, rvals->reg, rvals->val);
-		if (rc < 0)
-			return rc;
-		rvals++;
-	}
-
-	return 0;
-}
-
-/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-int ov_write_mask(struct i2c_client *c,
-		  unsigned char reg,
-		  unsigned char value,
-		  unsigned char mask)
-{
-	int rc;
-	unsigned char oldval, newval;
-
-	if (mask == 0xff) {
-		newval = value;
-	} else {
-		rc = ov_read(c, reg, &oldval);
-		if (rc < 0)
-			return rc;
-
-		oldval &= (~mask);		/* Clear the masked bits */
-		value &= mask;			/* Enforce mask on value */
-		newval = oldval | value;	/* Set the desired bits */
-	}
-
-	return ov_write(c, reg, newval);
-}
-
-/* ----------------------------------------------------------------------- */
-
-/* Reset the chip and ensure that I2C is synchronized. Returns <0 if failure.
- */
-static int init_camchip(struct i2c_client *c)
-{
-	int i, success;
-	unsigned char high, low;
-
-	/* Reset the chip */
-	ov_write(c, 0x12, 0x80);
-
-	/* Wait for it to initialize */
-	msleep(150);
-
-	for (i = 0, success = 0; i < I2C_DETECT_RETRIES && !success; i++) {
-		if (ov_read(c, GENERIC_REG_ID_HIGH, &high) >= 0) {
-			if (ov_read(c, GENERIC_REG_ID_LOW, &low) >= 0) {
-				if (high == 0x7F && low == 0xA2) {
-					success = 1;
-					continue;
-				}
-			}
-		}
-
-		/* Reset the chip */
-		ov_write(c, 0x12, 0x80);
-
-		/* Wait for it to initialize */
-		msleep(150);
-
-		/* Dummy read to sync I2C */
-		ov_read(c, 0x00, &low);
-	}
-
-	if (!success)
-		return -EIO;
-
-	PDEBUG(1, "I2C synced in %d attempt(s)", i);
-
-	return 0;
-}
-
-/* This detects the OV7610, OV7620, or OV76BE chip. */
-static int ov7xx0_detect(struct i2c_client *c)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	int rc;
-	unsigned char val;
-
-	PDEBUG(4, "");
-
-	/* Detect chip (sub)type */
-	rc = ov_read(c, GENERIC_REG_COM_I, &val);
-	if (rc < 0) {
-		PERROR("Error detecting ov7xx0 type");
-		return rc;
-	}
-
-	if ((val & 3) == 3) {
-		PINFO("Camera chip is an OV7610");
-		ov->subtype = CC_OV7610;
-	} else if ((val & 3) == 1) {
-		rc = ov_read(c, 0x15, &val);
-		if (rc < 0) {
-			PERROR("Error detecting ov7xx0 type");
-			return rc;
-		}
-
-		if (val & 1) {
-			PINFO("Camera chip is an OV7620AE");
-			/* OV7620 is a close enough match for now. There are
-			 * some definite differences though, so this should be
-			 * fixed */
-			ov->subtype = CC_OV7620;
-		} else {
-			PINFO("Camera chip is an OV76BE");
-			ov->subtype = CC_OV76BE;
-		}
-	} else if ((val & 3) == 0) {
-		PINFO("Camera chip is an OV7620");
-		ov->subtype = CC_OV7620;
-	} else {
-		PERROR("Unknown camera chip version: %d", val & 3);
-		return -ENOSYS;
-	}
-
-	if (ov->subtype == CC_OV76BE)
-		ov->sops = &ov76be_ops;
-	else if (ov->subtype == CC_OV7620)
-		ov->sops = &ov7x20_ops;
-	else
-		ov->sops = &ov7x10_ops;
-
-	return 0;
-}
-
-/* This detects the OV6620, OV6630, OV6630AE, or OV6630AF chip. */
-static int ov6xx0_detect(struct i2c_client *c)
-{
-	struct ovcamchip *ov = i2c_get_clientdata(c);
-	int rc;
-	unsigned char val;
-
-	PDEBUG(4, "");
-
-	/* Detect chip (sub)type */
-	rc = ov_read(c, GENERIC_REG_COM_I, &val);
-	if (rc < 0) {
-		PERROR("Error detecting ov6xx0 type");
-		return -1;
-	}
-
-	if ((val & 3) == 0) {
-		ov->subtype = CC_OV6630;
-		PINFO("Camera chip is an OV6630");
-	} else if ((val & 3) == 1) {
-		ov->subtype = CC_OV6620;
-		PINFO("Camera chip is an OV6620");
-	} else if ((val & 3) == 2) {
-		ov->subtype = CC_OV6630;
-		PINFO("Camera chip is an OV6630AE");
-	} else if ((val & 3) == 3) {
-		ov->subtype = CC_OV6630;
-		PINFO("Camera chip is an OV6630AF");
-	}
-
-	if (ov->subtype == CC_OV6620)
-		ov->sops = &ov6x20_ops;
-	else
-		ov->sops = &ov6x30_ops;
-
-	return 0;
-}
-
-static int ovcamchip_detect(struct i2c_client *c)
-{
-	/* Ideally we would just try a single register write and see if it NAKs.
-	 * That isn't possible since the OV518 can't report I2C transaction
-	 * failures. So, we have to try to initialize the chip (i.e. reset it
-	 * and check the ID registers) to detect its presence. */
-
-	/* Test for 7xx0 */
-	PDEBUG(3, "Testing for 0V7xx0");
-	if (init_camchip(c) < 0)
-		return -ENODEV;
-	/* 7-bit addresses with bit 0 set are for the OV7xx0 */
-	if (c->addr & 1) {
-		if (ov7xx0_detect(c) < 0) {
-			PERROR("Failed to init OV7xx0");
-			return -EIO;
-		}
-		return 0;
-	}
-	/* Test for 6xx0 */
-	PDEBUG(3, "Testing for 0V6xx0");
-	if (ov6xx0_detect(c) < 0) {
-		PERROR("Failed to init OV6xx0");
-		return -EIO;
-	}
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static long ovcamchip_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
-	struct ovcamchip *ov = to_ovcamchip(sd);
-	struct i2c_client *c = v4l2_get_subdevdata(sd);
-
-	if (!ov->initialized &&
-	    cmd != OVCAMCHIP_CMD_Q_SUBTYPE &&
-	    cmd != OVCAMCHIP_CMD_INITIALIZE) {
-		v4l2_err(sd, "Camera chip not initialized yet!\n");
-		return -EPERM;
-	}
-
-	switch (cmd) {
-	case OVCAMCHIP_CMD_Q_SUBTYPE:
-	{
-		*(int *)arg = ov->subtype;
-		return 0;
-	}
-	case OVCAMCHIP_CMD_INITIALIZE:
-	{
-		int rc;
-
-		if (mono == -1)
-			ov->mono = *(int *)arg;
-		else
-			ov->mono = mono;
-
-		if (ov->mono) {
-			if (ov->subtype != CC_OV7620)
-				v4l2_warn(sd, "Monochrome not "
-					"implemented for this chip\n");
-			else
-				v4l2_info(sd, "Initializing chip as "
-					"monochrome\n");
-		}
-
-		rc = ov->sops->init(c);
-		if (rc < 0)
-			return rc;
-
-		ov->initialized = 1;
-		return 0;
-	}
-	default:
-		return ov->sops->command(c, cmd, arg);
-	}
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct v4l2_subdev_core_ops ovcamchip_core_ops = {
-	.ioctl = ovcamchip_ioctl,
-};
-
-static const struct v4l2_subdev_ops ovcamchip_ops = {
-	.core = &ovcamchip_core_ops,
-};
-
-static int ovcamchip_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
-{
-	struct ovcamchip *ov;
-	struct v4l2_subdev *sd;
-	int rc = 0;
-
-	ov = kzalloc(sizeof *ov, GFP_KERNEL);
-	if (!ov) {
-		rc = -ENOMEM;
-		goto no_ov;
-	}
-	sd = &ov->sd;
-	v4l2_i2c_subdev_init(sd, client, &ovcamchip_ops);
-
-	rc = ovcamchip_detect(client);
-	if (rc < 0)
-		goto error;
-
-	v4l_info(client, "%s found @ 0x%02x (%s)\n",
-			chip_names[ov->subtype], client->addr << 1, client->adapter->name);
-
-	PDEBUG(1, "Camera chip detection complete");
-
-	return rc;
-error:
-	kfree(ov);
-no_ov:
-	PDEBUG(1, "returning %d", rc);
-	return rc;
-}
-
-static int ovcamchip_remove(struct i2c_client *client)
-{
-	struct v4l2_subdev *sd = i2c_get_clientdata(client);
-	struct ovcamchip *ov = to_ovcamchip(sd);
-	int rc;
-
-	v4l2_device_unregister_subdev(sd);
-	rc = ov->sops->free(client);
-	if (rc < 0)
-		return rc;
-
-	kfree(ov);
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct i2c_device_id ovcamchip_id[] = {
-	{ "ovcamchip", 0 },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, ovcamchip_id);
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
-	.name = "ovcamchip",
-	.probe = ovcamchip_probe,
-	.remove = ovcamchip_remove,
-	.id_table = ovcamchip_id,
-};
diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h
deleted file mode 100644
index 4f07b78..0000000
--- a/drivers/media/video/ovcamchip/ovcamchip_priv.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* OmniVision* camera chip driver private definitions for core code and
- * chip-specific code
- *
- * Copyright (c) 1999-2004 Mark McClelland
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
- *
- * * OmniVision is a trademark of OmniVision Technologies, Inc. This driver
- * is not sponsored or developed by them.
- */
-
-#ifndef __LINUX_OVCAMCHIP_PRIV_H
-#define __LINUX_OVCAMCHIP_PRIV_H
-
-#include <linux/i2c.h>
-#include <media/v4l2-subdev.h>
-#include <media/ovcamchip.h>
-
-#ifdef DEBUG
-extern int ovcamchip_debug;
-#endif
-
-#define PDEBUG(level, fmt, args...) \
-	if (ovcamchip_debug >= (level))	pr_debug("[%s:%d] " fmt "\n", \
-		__func__, __LINE__ , ## args)
-
-#define DDEBUG(level, dev, fmt, args...) \
-	if (ovcamchip_debug >= (level))	dev_dbg(dev, "[%s:%d] " fmt "\n", \
-		__func__, __LINE__ , ## args)
-
-/* Number of times to retry chip detection. Increase this if you are getting
- * "Failed to init camera chip" */
-#define I2C_DETECT_RETRIES	10
-
-struct ovcamchip_regvals {
-	unsigned char reg;
-	unsigned char val;
-};
-
-struct ovcamchip_ops {
-	int (*init)(struct i2c_client *);
-	int (*free)(struct i2c_client *);
-	int (*command)(struct i2c_client *, unsigned int, void *);
-};
-
-struct ovcamchip {
-	struct v4l2_subdev sd;
-	struct ovcamchip_ops *sops;
-	void *spriv;               /* Private data for OV7x10.c etc... */
-	int subtype;               /* = SEN_OV7610 etc... */
-	int mono;                  /* Monochrome chip? (invalid until init) */
-	int initialized;           /* OVCAMCHIP_CMD_INITIALIZE was successful */
-};
-
-static inline struct ovcamchip *to_ovcamchip(struct v4l2_subdev *sd)
-{
-	return container_of(sd, struct ovcamchip, sd);
-}
-
-extern struct ovcamchip_ops ov6x20_ops;
-extern struct ovcamchip_ops ov6x30_ops;
-extern struct ovcamchip_ops ov7x10_ops;
-extern struct ovcamchip_ops ov7x20_ops;
-extern struct ovcamchip_ops ov76be_ops;
-
-/* --------------------------------- */
-/*              I2C I/O              */
-/* --------------------------------- */
-
-static inline int ov_read(struct i2c_client *c, unsigned char reg,
-			  unsigned char *value)
-{
-	int rc;
-
-	rc = i2c_smbus_read_byte_data(c, reg);
-	*value = (unsigned char) rc;
-	return rc;
-}
-
-static inline int ov_write(struct i2c_client *c, unsigned char reg,
-			   unsigned char value )
-{
-	return i2c_smbus_write_byte_data(c, reg, value);
-}
-
-/* --------------------------------- */
-/*        FUNCTION PROTOTYPES        */
-/* --------------------------------- */
-
-/* Functions in ovcamchip_core.c */
-
-extern int ov_write_regvals(struct i2c_client *c,
-			    struct ovcamchip_regvals *rvals);
-
-extern int ov_write_mask(struct i2c_client *c, unsigned char reg,
-			 unsigned char value, unsigned char mask);
-
-#endif
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
index b482478..bba6115 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
@@ -223,7 +223,10 @@
 				   " pvr2_ioread_setup (setup) id=%p",cp);
 			pvr2_stream_kill(sp);
 			ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT);
-			if (ret < 0) return ret;
+			if (ret < 0) {
+				mutex_unlock(&cp->mutex);
+				return ret;
+			}
 			for (idx = 0; idx < BUFFER_COUNT; idx++) {
 				bp = pvr2_stream_get_buffer(sp,idx);
 				pvr2_buffer_set_buffer(bp,
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index fb242f6..9de7d59 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -276,7 +276,7 @@
 	 * longer in STATE_QUEUED or STATE_ACTIVE
 	 */
 	videobuf_waiton(&buf->vb, 0, 0);
-	videobuf_dma_unmap(vq, dma);
+	videobuf_dma_unmap(vq->dev, dma);
 	videobuf_dma_free(dma);
 
 	for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
@@ -1284,7 +1284,7 @@
 	}
 
 	switch (code) {
-	case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+	case V4L2_MBUS_FMT_UYVY8_2X8:
 		formats++;
 		if (xlate) {
 			xlate->host_fmt	= &pxa_camera_formats[0];
@@ -1293,9 +1293,9 @@
 			dev_dbg(dev, "Providing format %s using code %d\n",
 				pxa_camera_formats[0].name, code);
 		}
-	case V4L2_MBUS_FMT_YVYU8_2X8_BE:
-	case V4L2_MBUS_FMT_YUYV8_2X8_LE:
-	case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+	case V4L2_MBUS_FMT_VYUY8_2X8:
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+	case V4L2_MBUS_FMT_YVYU8_2X8:
 	case V4L2_MBUS_FMT_RGB565_2X8_LE:
 	case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
 		if (xlate)
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
index 47fd207..ce78fff 100644
--- a/drivers/media/video/rj54n1cb0c.c
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -1,5 +1,5 @@
 /*
- * Driver for RJ54N1CB0C CMOS Image Sensor from Micron
+ * Driver for RJ54N1CB0C CMOS Image Sensor from Sharp
  *
  * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
  *
@@ -127,8 +127,8 @@
 }
 
 static const struct rj54n1_datafmt rj54n1_colour_fmts[] = {
-	{V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG},
-	{V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+	{V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
 	{V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
 	{V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
 	{V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
@@ -1046,12 +1046,12 @@
 
 	/* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
 	switch (mf->code) {
-	case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+	case V4L2_MBUS_FMT_YUYV8_2X8:
 		ret = reg_write(client, RJ54N1_OUT_SEL, 0);
 		if (!ret)
 			ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
 		break;
-	case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+	case V4L2_MBUS_FMT_YVYU8_2X8:
 		ret = reg_write(client, RJ54N1_OUT_SEL, 0);
 		if (!ret)
 			ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index 3c7a79f..8ec7c9a 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -191,7 +191,6 @@
 struct s2255_dmaqueue {
 	struct list_head	active;
 	struct s2255_dev	*dev;
-	int			channel;
 };
 
 /* for firmware loading, fw_state */
@@ -226,51 +225,60 @@
 };
 
 struct s2255_fmt; /*forward declaration */
+struct s2255_dev;
+
+struct s2255_channel {
+	struct video_device	vdev;
+	int			resources;
+	struct s2255_dmaqueue	vidq;
+	struct s2255_bufferi	buffer;
+	struct s2255_mode	mode;
+	/* jpeg compression */
+	struct v4l2_jpegcompression jc;
+	/* capture parameters (for high quality mode full size) */
+	struct v4l2_captureparm cap_parm;
+	int			cur_frame;
+	int			last_frame;
+
+	int			b_acquire;
+	/* allocated image size */
+	unsigned long		req_image_size;
+	/* received packet size */
+	unsigned long		pkt_size;
+	int			bad_payload;
+	unsigned long		frame_count;
+	/* if JPEG image */
+	int                     jpg_size;
+	/* if channel configured to default state */
+	int                     configured;
+	wait_queue_head_t       wait_setmode;
+	int                     setmode_ready;
+	/* video status items */
+	int                     vidstatus;
+	wait_queue_head_t       wait_vidstatus;
+	int                     vidstatus_ready;
+	unsigned int		width;
+	unsigned int		height;
+	const struct s2255_fmt	*fmt;
+	int idx; /* channel number on device, 0-3 */
+};
+
 
 struct s2255_dev {
-	struct video_device	vdev[MAX_CHANNELS];
+	struct s2255_channel    channel[MAX_CHANNELS];
 	struct v4l2_device 	v4l2_dev;
-	atomic_t                channels; /* number of channels registered */
+	atomic_t                num_channels;
 	int			frames;
 	struct mutex		lock;
 	struct mutex		open_lock;
-	int			resources[MAX_CHANNELS];
 	struct usb_device	*udev;
 	struct usb_interface	*interface;
 	u8			read_endpoint;
-
-	struct s2255_dmaqueue	vidq[MAX_CHANNELS];
 	struct timer_list	timer;
 	struct s2255_fw	*fw_data;
 	struct s2255_pipeinfo	pipe;
-	struct s2255_bufferi	buffer[MAX_CHANNELS];
-	struct s2255_mode	mode[MAX_CHANNELS];
-	/* jpeg compression */
-	struct v4l2_jpegcompression jc[MAX_CHANNELS];
-	/* capture parameters (for high quality mode full size) */
-	struct v4l2_captureparm cap_parm[MAX_CHANNELS];
-	const struct s2255_fmt	*cur_fmt[MAX_CHANNELS];
-	int			cur_frame[MAX_CHANNELS];
-	int			last_frame[MAX_CHANNELS];
 	u32			cc;	/* current channel */
-	int			b_acquire[MAX_CHANNELS];
-	/* allocated image size */
-	unsigned long		req_image_size[MAX_CHANNELS];
-	/* received packet size */
-	unsigned long		pkt_size[MAX_CHANNELS];
-	int			bad_payload[MAX_CHANNELS];
-	unsigned long		frame_count[MAX_CHANNELS];
 	int			frame_ready;
-	/* if JPEG image */
-	int                     jpg_size[MAX_CHANNELS];
-	/* if channel configured to default state */
-	int                     chn_configured[MAX_CHANNELS];
-	wait_queue_head_t       wait_setmode[MAX_CHANNELS];
-	int                     setmode_ready[MAX_CHANNELS];
-	/* video status items */
-	int                     vidstatus[MAX_CHANNELS];
-	wait_queue_head_t       wait_vidstatus[MAX_CHANNELS];
-	int                     vidstatus_ready[MAX_CHANNELS];
 	int                     chn_ready;
 	spinlock_t              slock;
 	/* dsp firmware version (f2255usb.bin) */
@@ -298,16 +306,10 @@
 
 struct s2255_fh {
 	struct s2255_dev	*dev;
-	const struct s2255_fmt	*fmt;
-	unsigned int		width;
-	unsigned int		height;
 	struct videobuf_queue	vb_vidq;
 	enum v4l2_buf_type	type;
-	int			channel;
-	/* mode below is the desired mode.
-	   mode in s2255_dev is the current mode that was last set */
-	struct s2255_mode	mode;
-	int			resources[MAX_CHANNELS];
+	struct s2255_channel	*channel;
+	int			resources;
 };
 
 /* current cypress EEPROM firmware version */
@@ -360,12 +362,11 @@
 
 static int s2255_start_readpipe(struct s2255_dev *dev);
 static void s2255_stop_readpipe(struct s2255_dev *dev);
-static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn);
-static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn);
-static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
-			   int chn, int jpgsize);
-static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
-			  struct s2255_mode *mode);
+static int s2255_start_acquire(struct s2255_channel *channel);
+static int s2255_stop_acquire(struct s2255_channel *channel);
+static void s2255_fillbuff(struct s2255_channel *chn, struct s2255_buffer *buf,
+			   int jpgsize);
+static int s2255_set_mode(struct s2255_channel *chan, struct s2255_mode *mode);
 static int s2255_board_shutdown(struct s2255_dev *dev);
 static void s2255_fwload_start(struct s2255_dev *dev, int reset);
 static void s2255_destroy(struct s2255_dev *dev);
@@ -577,10 +578,11 @@
 
 }
 
-static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize)
+static int s2255_got_frame(struct s2255_channel *channel, int jpgsize)
 {
-	struct s2255_dmaqueue *dma_q = &dev->vidq[chn];
+	struct s2255_dmaqueue *dma_q = &channel->vidq;
 	struct s2255_buffer *buf;
+	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
 	unsigned long flags = 0;
 	int rc = 0;
 	spin_lock_irqsave(&dev->slock, flags);
@@ -593,7 +595,7 @@
 			 struct s2255_buffer, vb.queue);
 	list_del(&buf->vb.queue);
 	do_gettimeofday(&buf->vb.ts);
-	s2255_fillbuff(dev, buf, dma_q->channel, jpgsize);
+	s2255_fillbuff(channel, buf, jpgsize);
 	wake_up(&buf->vb.done);
 	dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
 unlock:
@@ -621,8 +623,8 @@
  *                  http://v4l.videotechnology.com/
  *
  */
-static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
-			   int chn, int jpgsize)
+static void s2255_fillbuff(struct s2255_channel *channel,
+			   struct s2255_buffer *buf, int jpgsize)
 {
 	int pos = 0;
 	struct timeval ts;
@@ -633,12 +635,11 @@
 
 	if (!vbuf)
 		return;
-
-	last_frame = dev->last_frame[chn];
+	last_frame = channel->last_frame;
 	if (last_frame != -1) {
-		frm = &dev->buffer[chn].frame[last_frame];
+		frm = &channel->buffer.frame[last_frame];
 		tmpbuf =
-		    (const char *)dev->buffer[chn].frame[last_frame].lpvbits;
+		    (const char *)channel->buffer.frame[last_frame].lpvbits;
 		switch (buf->fmt->fourcc) {
 		case V4L2_PIX_FMT_YUYV:
 		case V4L2_PIX_FMT_UYVY:
@@ -661,7 +662,7 @@
 		default:
 			printk(KERN_DEBUG "s2255: unknown format?\n");
 		}
-		dev->last_frame[chn] = -1;
+		channel->last_frame = -1;
 	} else {
 		printk(KERN_ERR "s2255: =======no frame\n");
 		return;
@@ -671,7 +672,7 @@
 		(unsigned long)vbuf, pos);
 	/* tell v4l buffer was filled */
 
-	buf->vb.field_count = dev->frame_count[chn] * 2;
+	buf->vb.field_count = channel->frame_count * 2;
 	do_gettimeofday(&ts);
 	buf->vb.ts = ts;
 	buf->vb.state = VIDEOBUF_DONE;
@@ -686,8 +687,8 @@
 			unsigned int *size)
 {
 	struct s2255_fh *fh = vq->priv_data;
-
-	*size = fh->width * fh->height * (fh->fmt->depth >> 3);
+	struct s2255_channel *channel = fh->channel;
+	*size = channel->width * channel->height * (channel->fmt->depth >> 3);
 
 	if (0 == *count)
 		*count = S2255_DEF_BUFS;
@@ -710,30 +711,31 @@
 			  enum v4l2_field field)
 {
 	struct s2255_fh *fh = vq->priv_data;
+	struct s2255_channel *channel = fh->channel;
 	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
 	int rc;
+	int w = channel->width;
+	int h = channel->height;
 	dprintk(4, "%s, field=%d\n", __func__, field);
-	if (fh->fmt == NULL)
+	if (channel->fmt == NULL)
 		return -EINVAL;
 
-	if ((fh->width < norm_minw(&fh->dev->vdev[fh->channel])) ||
-	    (fh->width > norm_maxw(&fh->dev->vdev[fh->channel])) ||
-	    (fh->height < norm_minh(&fh->dev->vdev[fh->channel])) ||
-	    (fh->height > norm_maxh(&fh->dev->vdev[fh->channel]))) {
+	if ((w < norm_minw(&channel->vdev)) ||
+	    (w > norm_maxw(&channel->vdev)) ||
+	    (h < norm_minh(&channel->vdev)) ||
+	    (h > norm_maxh(&channel->vdev))) {
 		dprintk(4, "invalid buffer prepare\n");
 		return -EINVAL;
 	}
-
-	buf->vb.size = fh->width * fh->height * (fh->fmt->depth >> 3);
-
+	buf->vb.size = w * h * (channel->fmt->depth >> 3);
 	if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
 		dprintk(4, "invalid buffer prepare\n");
 		return -EINVAL;
 	}
 
-	buf->fmt = fh->fmt;
-	buf->vb.width = fh->width;
-	buf->vb.height = fh->height;
+	buf->fmt = channel->fmt;
+	buf->vb.width = w;
+	buf->vb.height = h;
 	buf->vb.field = field;
 
 	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
@@ -753,8 +755,8 @@
 {
 	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
 	struct s2255_fh *fh = vq->priv_data;
-	struct s2255_dev *dev = fh->dev;
-	struct s2255_dmaqueue *vidq = &dev->vidq[fh->channel];
+	struct s2255_channel *channel = fh->channel;
+	struct s2255_dmaqueue *vidq = &channel->vidq;
 	dprintk(1, "%s\n", __func__);
 	buf->vb.state = VIDEOBUF_QUEUED;
 	list_add_tail(&buf->vb.queue, &vidq->active);
@@ -765,7 +767,7 @@
 {
 	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
 	struct s2255_fh *fh = vq->priv_data;
-	dprintk(4, "%s %d\n", __func__, fh->channel);
+	dprintk(4, "%s %d\n", __func__, fh->channel->idx);
 	free_buffer(vq, buf);
 }
 
@@ -777,39 +779,43 @@
 };
 
 
-static int res_get(struct s2255_dev *dev, struct s2255_fh *fh)
+static int res_get(struct s2255_fh *fh)
 {
+	struct s2255_dev *dev = fh->dev;
 	/* is it free? */
+	struct s2255_channel *channel = fh->channel;
 	mutex_lock(&dev->lock);
-	if (dev->resources[fh->channel]) {
+	if (channel->resources) {
 		/* no, someone else uses it */
 		mutex_unlock(&dev->lock);
 		return 0;
 	}
 	/* it's free, grab it */
-	dev->resources[fh->channel] = 1;
-	fh->resources[fh->channel] = 1;
+	channel->resources = 1;
+	fh->resources = 1;
 	dprintk(1, "s2255: res: get\n");
 	mutex_unlock(&dev->lock);
 	return 1;
 }
 
-static int res_locked(struct s2255_dev *dev, struct s2255_fh *fh)
+static int res_locked(struct s2255_fh *fh)
 {
-	return dev->resources[fh->channel];
+	return fh->channel->resources;
 }
 
 static int res_check(struct s2255_fh *fh)
 {
-	return fh->resources[fh->channel];
+	return fh->resources;
 }
 
 
-static void res_free(struct s2255_dev *dev, struct s2255_fh *fh)
+static void res_free(struct s2255_fh *fh)
 {
+	struct s2255_channel *channel = fh->channel;
+	struct s2255_dev *dev = fh->dev;
 	mutex_lock(&dev->lock);
-	dev->resources[fh->channel] = 0;
-	fh->resources[fh->channel] = 0;
+	channel->resources = 0;
+	fh->resources = 0;
 	mutex_unlock(&dev->lock);
 	dprintk(1, "res: put\n");
 }
@@ -869,12 +875,13 @@
 			    struct v4l2_format *f)
 {
 	struct s2255_fh *fh = priv;
+	struct s2255_channel *channel = fh->channel;
 
-	f->fmt.pix.width = fh->width;
-	f->fmt.pix.height = fh->height;
+	f->fmt.pix.width = channel->width;
+	f->fmt.pix.height = channel->height;
 	f->fmt.pix.field = fh->vb_vidq.field;
-	f->fmt.pix.pixelformat = fh->fmt->fourcc;
-	f->fmt.pix.bytesperline = f->fmt.pix.width * (fh->fmt->depth >> 3);
+	f->fmt.pix.pixelformat = channel->fmt->fourcc;
+	f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3);
 	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
 	return 0;
 }
@@ -886,11 +893,10 @@
 	enum v4l2_field field;
 	int  b_any_field = 0;
 	struct s2255_fh *fh = priv;
-	struct s2255_dev *dev = fh->dev;
+	struct s2255_channel *channel = fh->channel;
 	int is_ntsc;
-
 	is_ntsc =
-	    (dev->vdev[fh->channel].current_norm & V4L2_STD_NTSC) ? 1 : 0;
+		(channel->vdev.current_norm & V4L2_STD_NTSC) ? 1 : 0;
 
 	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
 
@@ -982,8 +988,10 @@
 			    struct v4l2_format *f)
 {
 	struct s2255_fh *fh = priv;
+	struct s2255_channel *channel = fh->channel;
 	const struct s2255_fmt *fmt;
 	struct videobuf_queue *q = &fh->vb_vidq;
+	struct s2255_mode mode;
 	int ret;
 	int norm;
 
@@ -1005,54 +1013,61 @@
 		goto out_s_fmt;
 	}
 
-	if (res_locked(fh->dev, fh)) {
+	if (res_locked(fh)) {
 		dprintk(1, "%s: channel busy\n", __func__);
 		ret = -EBUSY;
 		goto out_s_fmt;
 	}
-
-	fh->fmt = fmt;
-	fh->width = f->fmt.pix.width;
-	fh->height = f->fmt.pix.height;
+	mode = channel->mode;
+	channel->fmt = fmt;
+	channel->width = f->fmt.pix.width;
+	channel->height = f->fmt.pix.height;
 	fh->vb_vidq.field = f->fmt.pix.field;
 	fh->type = f->type;
-	norm = norm_minw(&fh->dev->vdev[fh->channel]);
-	if (fh->width > norm_minw(&fh->dev->vdev[fh->channel])) {
-		if (fh->height > norm_minh(&fh->dev->vdev[fh->channel])) {
-			if (fh->dev->cap_parm[fh->channel].capturemode &
+	norm = norm_minw(&channel->vdev);
+	if (channel->width > norm_minw(&channel->vdev)) {
+		if (channel->height > norm_minh(&channel->vdev)) {
+			if (channel->cap_parm.capturemode &
 			    V4L2_MODE_HIGHQUALITY)
-				fh->mode.scale = SCALE_4CIFSI;
+				mode.scale = SCALE_4CIFSI;
 			else
-				fh->mode.scale = SCALE_4CIFS;
+				mode.scale = SCALE_4CIFS;
 		} else
-			fh->mode.scale = SCALE_2CIFS;
+			mode.scale = SCALE_2CIFS;
 
 	} else {
-		fh->mode.scale = SCALE_1CIFS;
+		mode.scale = SCALE_1CIFS;
 	}
-
 	/* color mode */
-	switch (fh->fmt->fourcc) {
+	switch (channel->fmt->fourcc) {
 	case V4L2_PIX_FMT_GREY:
-		fh->mode.color &= ~MASK_COLOR;
-		fh->mode.color |= COLOR_Y8;
+		mode.color &= ~MASK_COLOR;
+		mode.color |= COLOR_Y8;
 		break;
 	case V4L2_PIX_FMT_JPEG:
-		fh->mode.color &= ~MASK_COLOR;
-		fh->mode.color |= COLOR_JPG;
-		fh->mode.color |= (fh->dev->jc[fh->channel].quality << 8);
+		mode.color &= ~MASK_COLOR;
+		mode.color |= COLOR_JPG;
+		mode.color |= (channel->jc.quality << 8);
 		break;
 	case V4L2_PIX_FMT_YUV422P:
-		fh->mode.color &= ~MASK_COLOR;
-		fh->mode.color |= COLOR_YUVPL;
+		mode.color &= ~MASK_COLOR;
+		mode.color |= COLOR_YUVPL;
 		break;
 	case V4L2_PIX_FMT_YUYV:
 	case V4L2_PIX_FMT_UYVY:
 	default:
-		fh->mode.color &= ~MASK_COLOR;
-		fh->mode.color |= COLOR_YUVPK;
+		mode.color &= ~MASK_COLOR;
+		mode.color |= COLOR_YUVPK;
 		break;
 	}
+	if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR))
+		mode.restart = 1;
+	else if (mode.scale != channel->mode.scale)
+		mode.restart = 1;
+	else if (mode.format != channel->mode.format)
+		mode.restart = 1;
+	channel->mode = mode;
+	(void) s2255_set_mode(channel, &mode);
 	ret = 0;
 out_s_fmt:
 	mutex_unlock(&q->vb_lock);
@@ -1197,26 +1212,27 @@
  * When the restart parameter is set, we sleep for ONE frame to allow the
  * DSP time to get the new frame
  */
-static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
+static int s2255_set_mode(struct s2255_channel *channel,
 			  struct s2255_mode *mode)
 {
 	int res;
 	__le32 *buffer;
 	unsigned long chn_rev;
+	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
 	mutex_lock(&dev->lock);
-	chn_rev = G_chnmap[chn];
-	dprintk(3, "%s channel %lu\n", __func__, chn);
+	chn_rev = G_chnmap[channel->idx];
+	dprintk(3, "%s channel: %d\n", __func__, channel->idx);
 	/* if JPEG, set the quality */
 	if ((mode->color & MASK_COLOR) == COLOR_JPG) {
 		mode->color &= ~MASK_COLOR;
 		mode->color |= COLOR_JPG;
 		mode->color &= ~MASK_JPG_QUALITY;
-		mode->color |= (dev->jc[chn].quality << 8);
+		mode->color |= (channel->jc.quality << 8);
 	}
 	/* save the mode */
-	dev->mode[chn] = *mode;
-	dev->req_image_size[chn] = get_transfer_size(mode);
-	dprintk(1, "%s: reqsize %ld\n", __func__, dev->req_image_size[chn]);
+	channel->mode = *mode;
+	channel->req_image_size = get_transfer_size(mode);
+	dprintk(1, "%s: reqsize %ld\n", __func__, channel->req_image_size);
 	buffer = kzalloc(512, GFP_KERNEL);
 	if (buffer == NULL) {
 		dev_err(&dev->udev->dev, "out of mem\n");
@@ -1227,38 +1243,38 @@
 	buffer[0] = IN_DATA_TOKEN;
 	buffer[1] = (__le32) cpu_to_le32(chn_rev);
 	buffer[2] = CMD_SET_MODE;
-	memcpy(&buffer[3], &dev->mode[chn], sizeof(struct s2255_mode));
-	dev->setmode_ready[chn] = 0;
+	memcpy(&buffer[3], &channel->mode, sizeof(struct s2255_mode));
+	channel->setmode_ready = 0;
 	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
 	if (debug)
 		s2255_print_cfg(dev, mode);
 	kfree(buffer);
 	/* wait at least 3 frames before continuing */
 	if (mode->restart) {
-		wait_event_timeout(dev->wait_setmode[chn],
-				   (dev->setmode_ready[chn] != 0),
+		wait_event_timeout(channel->wait_setmode,
+				   (channel->setmode_ready != 0),
 				   msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
-		if (dev->setmode_ready[chn] != 1) {
+		if (channel->setmode_ready != 1) {
 			printk(KERN_DEBUG "s2255: no set mode response\n");
 			res = -EFAULT;
 		}
 	}
 	/* clear the restart flag */
-	dev->mode[chn].restart = 0;
+	channel->mode.restart = 0;
 	mutex_unlock(&dev->lock);
-	dprintk(1, "%s chn %lu, result: %d\n", __func__, chn, res);
+	dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res);
 	return res;
 }
 
-static int s2255_cmd_status(struct s2255_dev *dev, unsigned long chn,
-			    u32 *pstatus)
+static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
 {
 	int res;
 	__le32 *buffer;
 	u32 chn_rev;
+	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
 	mutex_lock(&dev->lock);
-	chn_rev = G_chnmap[chn];
-	dprintk(4, "%s chan %lu\n", __func__, chn);
+	chn_rev = G_chnmap[channel->idx];
+	dprintk(4, "%s chan %d\n", __func__, channel->idx);
 	buffer = kzalloc(512, GFP_KERNEL);
 	if (buffer == NULL) {
 		dev_err(&dev->udev->dev, "out of mem\n");
@@ -1270,17 +1286,17 @@
 	buffer[1] = (__le32) cpu_to_le32(chn_rev);
 	buffer[2] = CMD_STATUS;
 	*pstatus = 0;
-	dev->vidstatus_ready[chn] = 0;
+	channel->vidstatus_ready = 0;
 	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
 	kfree(buffer);
-	wait_event_timeout(dev->wait_vidstatus[chn],
-			   (dev->vidstatus_ready[chn] != 0),
+	wait_event_timeout(channel->wait_vidstatus,
+			   (channel->vidstatus_ready != 0),
 			   msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT));
-	if (dev->vidstatus_ready[chn] != 1) {
+	if (channel->vidstatus_ready != 1) {
 		printk(KERN_DEBUG "s2255: no vidstatus response\n");
 		res = -EFAULT;
 	}
-	*pstatus = dev->vidstatus[chn];
+	*pstatus = channel->vidstatus;
 	dprintk(4, "%s, vid status %d\n", __func__, *pstatus);
 	mutex_unlock(&dev->lock);
 	return res;
@@ -1291,9 +1307,7 @@
 	int res;
 	struct s2255_fh *fh = priv;
 	struct s2255_dev *dev = fh->dev;
-	struct s2255_mode *new_mode;
-	struct s2255_mode *old_mode;
-	int chn;
+	struct s2255_channel *channel = fh->channel;
 	int j;
 	dprintk(4, "%s\n", __func__);
 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -1305,51 +1319,32 @@
 		return -EINVAL;
 	}
 
-	if (!res_get(dev, fh)) {
+	if (!res_get(fh)) {
 		s2255_dev_err(&dev->udev->dev, "stream busy\n");
 		return -EBUSY;
 	}
-
-	/* send a set mode command everytime with restart.
-	   in case we switch resolutions or other parameters */
-	chn = fh->channel;
-	new_mode = &fh->mode;
-	old_mode = &fh->dev->mode[chn];
-
-	if ((new_mode->color & MASK_COLOR) != (old_mode->color & MASK_COLOR))
-		new_mode->restart = 1;
-	else if (new_mode->scale != old_mode->scale)
-		new_mode->restart = 1;
-	else if (new_mode->format != old_mode->format)
-		new_mode->restart = 1;
-
-	s2255_set_mode(dev, chn, new_mode);
-	new_mode->restart = 0;
-	*old_mode = *new_mode;
-	dev->cur_fmt[chn] = fh->fmt;
-	dev->last_frame[chn] = -1;
-	dev->bad_payload[chn] = 0;
-	dev->cur_frame[chn] = 0;
-	dev->frame_count[chn] = 0;
+	channel->last_frame = -1;
+	channel->bad_payload = 0;
+	channel->cur_frame = 0;
+	channel->frame_count = 0;
 	for (j = 0; j < SYS_FRAMES; j++) {
-		dev->buffer[chn].frame[j].ulState = S2255_READ_IDLE;
-		dev->buffer[chn].frame[j].cur_size = 0;
+		channel->buffer.frame[j].ulState = S2255_READ_IDLE;
+		channel->buffer.frame[j].cur_size = 0;
 	}
 	res = videobuf_streamon(&fh->vb_vidq);
 	if (res == 0) {
-		s2255_start_acquire(dev, chn);
-		dev->b_acquire[chn] = 1;
-	} else {
-		res_free(dev, fh);
-	}
+		s2255_start_acquire(channel);
+		channel->b_acquire = 1;
+	} else
+		res_free(fh);
+
 	return res;
 }
 
 static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 {
 	struct s2255_fh *fh = priv;
-	struct s2255_dev *dev = fh->dev;
-	dprintk(4, "%s\n, channel: %d", __func__, fh->channel);
+	dprintk(4, "%s\n, channel: %d", __func__, fh->channel->idx);
 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 		printk(KERN_ERR "invalid fh type0\n");
 		return -EINVAL;
@@ -1358,16 +1353,16 @@
 		printk(KERN_ERR "invalid type i\n");
 		return -EINVAL;
 	}
-	s2255_stop_acquire(dev, fh->channel);
+	s2255_stop_acquire(fh->channel);
 	videobuf_streamoff(&fh->vb_vidq);
-	res_free(dev, fh);
+	res_free(fh);
 	return 0;
 }
 
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
 {
 	struct s2255_fh *fh = priv;
-	struct s2255_mode *mode;
+	struct s2255_mode mode;
 	struct videobuf_queue *q = &fh->vb_vidq;
 	int ret = 0;
 	mutex_lock(&q->vb_lock);
@@ -1376,29 +1371,32 @@
 		ret = -EBUSY;
 		goto out_s_std;
 	}
-	if (res_locked(fh->dev, fh)) {
+	if (res_locked(fh)) {
 		dprintk(1, "can't change standard after started\n");
 		ret = -EBUSY;
 		goto out_s_std;
 	}
-	mode = &fh->mode;
+	mode = fh->channel->mode;
 	if (*i & V4L2_STD_NTSC) {
 		dprintk(4, "%s NTSC\n", __func__);
 		/* if changing format, reset frame decimation/intervals */
-		if (mode->format != FORMAT_NTSC) {
-			mode->format = FORMAT_NTSC;
-			mode->fdec = FDEC_1;
+		if (mode.format != FORMAT_NTSC) {
+			mode.restart = 1;
+			mode.format = FORMAT_NTSC;
+			mode.fdec = FDEC_1;
 		}
 	} else if (*i & V4L2_STD_PAL) {
 		dprintk(4, "%s PAL\n", __func__);
-		mode->format = FORMAT_PAL;
-		if (mode->format != FORMAT_PAL) {
-			mode->format = FORMAT_PAL;
-			mode->fdec = FDEC_1;
+		if (mode.format != FORMAT_PAL) {
+			mode.restart = 1;
+			mode.format = FORMAT_PAL;
+			mode.fdec = FDEC_1;
 		}
 	} else {
 		ret = -EINVAL;
 	}
+	if (mode.restart)
+		s2255_set_mode(fh->channel, &mode);
 out_s_std:
 	mutex_unlock(&q->vb_lock);
 	return ret;
@@ -1416,6 +1414,7 @@
 {
 	struct s2255_fh *fh = priv;
 	struct s2255_dev *dev = fh->dev;
+	struct s2255_channel *channel = fh->channel;
 	u32 status = 0;
 	if (inp->index != 0)
 		return -EINVAL;
@@ -1424,7 +1423,7 @@
 	inp->status = 0;
 	if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) {
 		int rc;
-		rc = s2255_cmd_status(dev, fh->channel, &status);
+		rc = s2255_cmd_status(fh->channel, &status);
 		dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status);
 		if (rc == 0)
 			inp->status =  (status & 0x01) ? 0
@@ -1436,7 +1435,7 @@
 		strlcpy(inp->name, "Composite", sizeof(inp->name));
 		break;
 	case 0x2257:
-		strlcpy(inp->name, (fh->channel < 2) ? "Composite" : "S-Video",
+		strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video",
 			sizeof(inp->name));
 		break;
 	}
@@ -1460,6 +1459,7 @@
 			    struct v4l2_queryctrl *qc)
 {
 	struct s2255_fh *fh = priv;
+	struct s2255_channel *channel = fh->channel;
 	struct s2255_dev *dev = fh->dev;
 	switch (qc->id) {
 	case V4L2_CID_BRIGHTNESS:
@@ -1477,7 +1477,7 @@
 	case V4L2_CID_PRIVATE_COLORFILTER:
 		if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
 			return -EINVAL;
-		if ((dev->pid == 0x2257) && (fh->channel > 1))
+		if ((dev->pid == 0x2257) && (channel->idx > 1))
 			return -EINVAL;
 		strlcpy(qc->name, "Color Filter", sizeof(qc->name));
 		qc->type = V4L2_CTRL_TYPE_MENU;
@@ -1499,25 +1499,26 @@
 {
 	struct s2255_fh *fh = priv;
 	struct s2255_dev *dev = fh->dev;
+	struct s2255_channel *channel = fh->channel;
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = fh->mode.bright;
+		ctrl->value = channel->mode.bright;
 		break;
 	case V4L2_CID_CONTRAST:
-		ctrl->value = fh->mode.contrast;
+		ctrl->value = channel->mode.contrast;
 		break;
 	case V4L2_CID_SATURATION:
-		ctrl->value = fh->mode.saturation;
+		ctrl->value = channel->mode.saturation;
 		break;
 	case V4L2_CID_HUE:
-		ctrl->value = fh->mode.hue;
+		ctrl->value = channel->mode.hue;
 		break;
 	case V4L2_CID_PRIVATE_COLORFILTER:
 		if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
 			return -EINVAL;
-		if ((dev->pid == 0x2257) && (fh->channel > 1))
+		if ((dev->pid == 0x2257) && (channel->idx > 1))
 			return -EINVAL;
-		ctrl->value = !((fh->mode.color & MASK_INPUT_TYPE) >> 16);
+		ctrl->value = !((channel->mode.color & MASK_INPUT_TYPE) >> 16);
 		break;
 	default:
 		return -EINVAL;
@@ -1530,41 +1531,42 @@
 			 struct v4l2_control *ctrl)
 {
 	struct s2255_fh *fh = priv;
-	struct s2255_dev *dev = fh->dev;
-	struct s2255_mode *mode;
-	mode = &fh->mode;
+	struct s2255_channel *channel = fh->channel;
+	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+	struct s2255_mode mode;
+	mode = channel->mode;
 	dprintk(4, "%s\n", __func__);
 	/* update the mode to the corresponding value */
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		mode->bright = ctrl->value;
+		mode.bright = ctrl->value;
 		break;
 	case V4L2_CID_CONTRAST:
-		mode->contrast = ctrl->value;
+		mode.contrast = ctrl->value;
 		break;
 	case V4L2_CID_HUE:
-		mode->hue = ctrl->value;
+		mode.hue = ctrl->value;
 		break;
 	case V4L2_CID_SATURATION:
-		mode->saturation = ctrl->value;
+		mode.saturation = ctrl->value;
 		break;
 	case V4L2_CID_PRIVATE_COLORFILTER:
 		if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
 			return -EINVAL;
-		if ((dev->pid == 0x2257) && (fh->channel > 1))
+		if ((dev->pid == 0x2257) && (channel->idx > 1))
 			return -EINVAL;
-		mode->color &= ~MASK_INPUT_TYPE;
-		mode->color |= ((ctrl->value ? 0 : 1) << 16);
+		mode.color &= ~MASK_INPUT_TYPE;
+		mode.color |= ((ctrl->value ? 0 : 1) << 16);
 		break;
 	default:
 		return -EINVAL;
 	}
-	mode->restart = 0;
+	mode.restart = 0;
 	/* set mode here.  Note: stream does not need restarted.
 	   some V4L programs restart stream unnecessarily
 	   after a s_crtl.
 	*/
-	s2255_set_mode(dev, fh->channel, mode);
+	s2255_set_mode(fh->channel, &mode);
 	return 0;
 }
 
@@ -1572,8 +1574,8 @@
 			 struct v4l2_jpegcompression *jc)
 {
 	struct s2255_fh *fh = priv;
-	struct s2255_dev *dev = fh->dev;
-	*jc = dev->jc[fh->channel];
+	struct s2255_channel *channel = fh->channel;
+	*jc = channel->jc;
 	dprintk(2, "%s: quality %d\n", __func__, jc->quality);
 	return 0;
 }
@@ -1582,10 +1584,10 @@
 			 struct v4l2_jpegcompression *jc)
 {
 	struct s2255_fh *fh = priv;
-	struct s2255_dev *dev = fh->dev;
+	struct s2255_channel *channel = fh->channel;
 	if (jc->quality < 0 || jc->quality > 100)
 		return -EINVAL;
-	dev->jc[fh->channel].quality = jc->quality;
+	channel->jc.quality = jc->quality;
 	dprintk(2, "%s: quality %d\n", __func__, jc->quality);
 	return 0;
 }
@@ -1594,17 +1596,17 @@
 			 struct v4l2_streamparm *sp)
 {
 	struct s2255_fh *fh = priv;
-	struct s2255_dev *dev = fh->dev;
 	__u32 def_num, def_dem;
+	struct s2255_channel *channel = fh->channel;
 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 	memset(sp, 0, sizeof(struct v4l2_streamparm));
 	sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-	sp->parm.capture.capturemode = dev->cap_parm[fh->channel].capturemode;
-	def_num = (fh->mode.format == FORMAT_NTSC) ? 1001 : 1000;
-	def_dem = (fh->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+	sp->parm.capture.capturemode = channel->cap_parm.capturemode;
+	def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000;
+	def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000;
 	sp->parm.capture.timeperframe.denominator = def_dem;
-	switch (fh->mode.fdec) {
+	switch (channel->mode.fdec) {
 	default:
 	case FDEC_1:
 		sp->parm.capture.timeperframe.numerator = def_num;
@@ -1630,17 +1632,19 @@
 			 struct v4l2_streamparm *sp)
 {
 	struct s2255_fh *fh = priv;
-	struct s2255_dev *dev = fh->dev;
+	struct s2255_channel *channel = fh->channel;
+	struct s2255_mode mode;
 	int fdec = FDEC_1;
 	__u32 def_num, def_dem;
 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
+	mode = channel->mode;
 	/* high quality capture mode requires a stream restart */
-	if (dev->cap_parm[fh->channel].capturemode
-	    != sp->parm.capture.capturemode && res_locked(fh->dev, fh))
+	if (channel->cap_parm.capturemode
+	    != sp->parm.capture.capturemode && res_locked(fh))
 		return -EBUSY;
-	def_num = (fh->mode.format == FORMAT_NTSC) ? 1001 : 1000;
-	def_dem = (fh->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+	def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000;
+	def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000;
 	if (def_dem != sp->parm.capture.timeperframe.denominator)
 		sp->parm.capture.timeperframe.numerator = def_num;
 	else if (sp->parm.capture.timeperframe.numerator <= def_num)
@@ -1655,9 +1659,9 @@
 		sp->parm.capture.timeperframe.numerator = def_num * 5;
 		fdec = FDEC_5;
 	}
-	fh->mode.fdec = fdec;
+	mode.fdec = fdec;
 	sp->parm.capture.timeperframe.denominator = def_dem;
-	s2255_set_mode(dev, fh->channel, &fh->mode);
+	s2255_set_mode(channel, &mode);
 	dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
 		__func__,
 		sp->parm.capture.capturemode,
@@ -1707,24 +1711,13 @@
 static int s2255_open(struct file *file)
 {
 	struct video_device *vdev = video_devdata(file);
-	struct s2255_dev *dev = video_drvdata(file);
+	struct s2255_channel *channel = video_drvdata(file);
+	struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
 	struct s2255_fh *fh;
 	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	int i = 0;
-	int cur_channel = -1;
 	int state;
 	dprintk(1, "s2255: open called (dev=%s)\n",
 		video_device_node_name(vdev));
-
-	for (i = 0; i < MAX_CHANNELS; i++) {
-		if (&dev->vdev[i] == vdev) {
-			cur_channel = i;
-			break;
-		}
-	}
-	if (i == MAX_CHANNELS)
-		return -ENODEV;
-
 	/*
 	 * open lock necessary to prevent multiple instances
 	 * of v4l-conf (or other programs) from simultaneously
@@ -1806,24 +1799,20 @@
 	file->private_data = fh;
 	fh->dev = dev;
 	fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	fh->mode = dev->mode[cur_channel];
-	fh->fmt = dev->cur_fmt[cur_channel];
-	/* default 4CIF NTSC */
-	fh->width = LINE_SZ_4CIFS_NTSC;
-	fh->height = NUM_LINES_4CIFS_NTSC * 2;
-	fh->channel = cur_channel;
-	/* configure channel to default state */
-	if (!dev->chn_configured[cur_channel]) {
-		s2255_set_mode(dev, cur_channel, &fh->mode);
-		dev->chn_configured[cur_channel] = 1;
+	fh->channel = channel;
+	if (!channel->configured) {
+		/* configure channel to default state */
+		channel->fmt = &formats[0];
+		s2255_set_mode(channel, &channel->mode);
+		channel->configured = 1;
 	}
 	dprintk(1, "%s: dev=%s type=%s\n", __func__,
 		video_device_node_name(vdev), v4l2_type_names[type]);
 	dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__,
 		(unsigned long)fh, (unsigned long)dev,
-		(unsigned long)&dev->vidq[cur_channel]);
+		(unsigned long)&channel->vidq);
 	dprintk(4, "%s: list_empty active=%d\n", __func__,
-		list_empty(&dev->vidq[cur_channel].active));
+		list_empty(&channel->vidq.active));
 	videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
 				    NULL, &dev->slock,
 				    fh->type,
@@ -1865,6 +1854,7 @@
 	mutex_destroy(&dev->open_lock);
 	mutex_destroy(&dev->lock);
 	usb_put_dev(dev->udev);
+	v4l2_device_unregister(&dev->v4l2_dev);
 	dprintk(1, "%s", __func__);
 	kfree(dev);
 }
@@ -1874,14 +1864,15 @@
 	struct s2255_fh *fh = file->private_data;
 	struct s2255_dev *dev = fh->dev;
 	struct video_device *vdev = video_devdata(file);
+	struct s2255_channel *channel = fh->channel;
 	if (!dev)
 		return -ENODEV;
 	/* turn off stream */
 	if (res_check(fh)) {
-		if (dev->b_acquire[fh->channel])
-			s2255_stop_acquire(dev, fh->channel);
+		if (channel->b_acquire)
+			s2255_stop_acquire(fh->channel);
 		videobuf_streamoff(&fh->vb_vidq);
-		res_free(dev, fh);
+		res_free(fh);
 	}
 	videobuf_mmap_free(&fh->vb_vidq);
 	dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev));
@@ -1945,9 +1936,10 @@
 
 static void s2255_video_device_release(struct video_device *vdev)
 {
-	struct s2255_dev *dev = video_get_drvdata(vdev);
-	dprintk(4, "%s, chnls: %d \n", __func__, atomic_read(&dev->channels));
-	if (atomic_dec_and_test(&dev->channels))
+	struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
+	dprintk(4, "%s, chnls: %d \n", __func__,
+		atomic_read(&dev->num_channels));
+	if (atomic_dec_and_test(&dev->num_channels))
 		s2255_destroy(dev);
 	return;
 }
@@ -1966,47 +1958,48 @@
 	int ret;
 	int i;
 	int cur_nr = video_nr;
+	struct s2255_channel *channel;
 	ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
 	if (ret)
 		return ret;
 	/* initialize all video 4 linux */
 	/* register 4 video devices */
 	for (i = 0; i < MAX_CHANNELS; i++) {
-		INIT_LIST_HEAD(&dev->vidq[i].active);
-		dev->vidq[i].dev = dev;
-		dev->vidq[i].channel = i;
+		channel = &dev->channel[i];
+		INIT_LIST_HEAD(&channel->vidq.active);
+		channel->vidq.dev = dev;
 		/* register 4 video devices */
-		memcpy(&dev->vdev[i], &template, sizeof(struct video_device));
-		dev->vdev[i].v4l2_dev = &dev->v4l2_dev;
-		video_set_drvdata(&dev->vdev[i], dev);
+		channel->vdev = template;
+		channel->vdev.v4l2_dev = &dev->v4l2_dev;
+		video_set_drvdata(&channel->vdev, channel);
 		if (video_nr == -1)
-			ret = video_register_device(&dev->vdev[i],
+			ret = video_register_device(&channel->vdev,
 						    VFL_TYPE_GRABBER,
 						    video_nr);
 		else
-			ret = video_register_device(&dev->vdev[i],
+			ret = video_register_device(&channel->vdev,
 						    VFL_TYPE_GRABBER,
 						    cur_nr + i);
+
 		if (ret) {
 			dev_err(&dev->udev->dev,
 				"failed to register video device!\n");
 			break;
 		}
-		atomic_inc(&dev->channels);
+		atomic_inc(&dev->num_channels);
 		v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
-			  video_device_node_name(&dev->vdev[i]));
+			  video_device_node_name(&channel->vdev));
 
 	}
-
 	printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %d.%d\n",
 	       S2255_MAJOR_VERSION,
 	       S2255_MINOR_VERSION);
 	/* if no channels registered, return error and probe will fail*/
-	if (atomic_read(&dev->channels) == 0) {
+	if (atomic_read(&dev->num_channels) == 0) {
 		v4l2_device_unregister(&dev->v4l2_dev);
 		return ret;
 	}
-	if (atomic_read(&dev->channels) != MAX_CHANNELS)
+	if (atomic_read(&dev->num_channels) != MAX_CHANNELS)
 		printk(KERN_WARNING "s2255: Not all channels available.\n");
 	return 0;
 }
@@ -2033,12 +2026,11 @@
 	s32 idx = -1;
 	struct s2255_framei *frm;
 	unsigned char *pdata;
-
+	struct s2255_channel *channel;
 	dprintk(100, "buffer to user\n");
-
-	idx = dev->cur_frame[dev->cc];
-	frm = &dev->buffer[dev->cc].frame[idx];
-
+	channel = &dev->channel[dev->cc];
+	idx = channel->cur_frame;
+	frm = &channel->buffer.frame[idx];
 	if (frm->ulState == S2255_READ_IDLE) {
 		int jj;
 		unsigned int cc;
@@ -2063,16 +2055,18 @@
 				}
 				/* reverse it */
 				dev->cc = G_chnmap[cc];
+				channel = &dev->channel[dev->cc];
 				payload =  pdword[3];
-				if (payload > dev->req_image_size[dev->cc]) {
-					dev->bad_payload[dev->cc]++;
+				if (payload > channel->req_image_size) {
+					channel->bad_payload++;
 					/* discard the bad frame */
 					return -EINVAL;
 				}
-				dev->pkt_size[dev->cc] = payload;
-				dev->jpg_size[dev->cc] = pdword[4];
+				channel->pkt_size = payload;
+				channel->jpg_size = pdword[4];
 				break;
 			case S2255_MARKER_RESPONSE:
+
 				pdata += DEF_USB_BLOCK;
 				jj += DEF_USB_BLOCK;
 				if (pdword[1] >= MAX_CHANNELS)
@@ -2080,12 +2074,13 @@
 				cc = G_chnmap[pdword[1]];
 				if (cc >= MAX_CHANNELS)
 					break;
+				channel = &dev->channel[cc];
 				switch (pdword[2]) {
 				case S2255_RESPONSE_SETMODE:
 					/* check if channel valid */
 					/* set mode ready */
-					dev->setmode_ready[cc] = 1;
-					wake_up(&dev->wait_setmode[cc]);
+					channel->setmode_ready = 1;
+					wake_up(&channel->wait_setmode);
 					dprintk(5, "setmode ready %d\n", cc);
 					break;
 				case S2255_RESPONSE_FW:
@@ -2099,9 +2094,9 @@
 					wake_up(&dev->fw_data->wait_fw);
 					break;
 				case S2255_RESPONSE_STATUS:
-					dev->vidstatus[cc] = pdword[3];
-					dev->vidstatus_ready[cc] = 1;
-					wake_up(&dev->wait_vidstatus[cc]);
+					channel->vidstatus = pdword[3];
+					channel->vidstatus_ready = 1;
+					wake_up(&channel->wait_vidstatus);
 					dprintk(5, "got vidstatus %x chan %d\n",
 						pdword[3], cc);
 					break;
@@ -2118,13 +2113,11 @@
 		if (!bframe)
 			return -EINVAL;
 	}
-
-
-	idx = dev->cur_frame[dev->cc];
-	frm = &dev->buffer[dev->cc].frame[idx];
-
+	channel = &dev->channel[dev->cc];
+	idx = channel->cur_frame;
+	frm = &channel->buffer.frame[idx];
 	/* search done.  now find out if should be acquiring on this channel */
-	if (!dev->b_acquire[dev->cc]) {
+	if (!channel->b_acquire) {
 		/* we found a frame, but this channel is turned off */
 		frm->ulState = S2255_READ_IDLE;
 		return -EINVAL;
@@ -2149,30 +2142,28 @@
 
 	copy_size = (pipe_info->cur_transfer_size - offset);
 
-	size = dev->pkt_size[dev->cc] - PREFIX_SIZE;
+	size = channel->pkt_size - PREFIX_SIZE;
 
 	/* sanity check on pdest */
-	if ((copy_size + frm->cur_size) < dev->req_image_size[dev->cc])
+	if ((copy_size + frm->cur_size) < channel->req_image_size)
 		memcpy(pdest, psrc, copy_size);
 
 	frm->cur_size += copy_size;
 	dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size);
 
 	if (frm->cur_size >= size) {
-
-		u32 cc = dev->cc;
 		dprintk(2, "****************[%d]Buffer[%d]full*************\n",
-			cc, idx);
-		dev->last_frame[cc] = dev->cur_frame[cc];
-		dev->cur_frame[cc]++;
+			dev->cc, idx);
+		channel->last_frame = channel->cur_frame;
+		channel->cur_frame++;
 		/* end of system frame ring buffer, start at zero */
-		if ((dev->cur_frame[cc] == SYS_FRAMES) ||
-		    (dev->cur_frame[cc] == dev->buffer[cc].dwFrames))
-			dev->cur_frame[cc] = 0;
+		if ((channel->cur_frame == SYS_FRAMES) ||
+		    (channel->cur_frame == channel->buffer.dwFrames))
+			channel->cur_frame = 0;
 		/* frame ready */
-		if (dev->b_acquire[cc])
-			s2255_got_frame(dev, cc, dev->jpg_size[cc]);
-		dev->frame_count[cc]++;
+		if (channel->b_acquire)
+			s2255_got_frame(channel, channel->jpg_size);
+		channel->frame_count++;
 		frm->ulState = S2255_READ_IDLE;
 		frm->cur_size = 0;
 
@@ -2245,16 +2236,12 @@
  * Create the system ring buffer to copy frames into from the
  * usb read pipe.
  */
-static int s2255_create_sys_buffers(struct s2255_dev *dev, unsigned long chn)
+static int s2255_create_sys_buffers(struct s2255_channel *channel)
 {
 	unsigned long i;
 	unsigned long reqsize;
 	dprintk(1, "create sys buffers\n");
-	if (chn >= MAX_CHANNELS)
-		return -1;
-
-	dev->buffer[chn].dwFrames = SYS_FRAMES;
-
+	channel->buffer.dwFrames = SYS_FRAMES;
 	/* always allocate maximum size(PAL) for system buffers */
 	reqsize = SYS_FRAMES_MAXSIZE;
 
@@ -2263,42 +2250,40 @@
 
 	for (i = 0; i < SYS_FRAMES; i++) {
 		/* allocate the frames */
-		dev->buffer[chn].frame[i].lpvbits = vmalloc(reqsize);
-
-		dprintk(1, "valloc %p chan %lu, idx %lu, pdata %p\n",
-			&dev->buffer[chn].frame[i], chn, i,
-			dev->buffer[chn].frame[i].lpvbits);
-		dev->buffer[chn].frame[i].size = reqsize;
-		if (dev->buffer[chn].frame[i].lpvbits == NULL) {
+		channel->buffer.frame[i].lpvbits = vmalloc(reqsize);
+		dprintk(1, "valloc %p chan %d, idx %lu, pdata %p\n",
+			&channel->buffer.frame[i], channel->idx, i,
+			channel->buffer.frame[i].lpvbits);
+		channel->buffer.frame[i].size = reqsize;
+		if (channel->buffer.frame[i].lpvbits == NULL) {
 			printk(KERN_INFO "out of memory.  using less frames\n");
-			dev->buffer[chn].dwFrames = i;
+			channel->buffer.dwFrames = i;
 			break;
 		}
 	}
 
 	/* make sure internal states are set */
 	for (i = 0; i < SYS_FRAMES; i++) {
-		dev->buffer[chn].frame[i].ulState = 0;
-		dev->buffer[chn].frame[i].cur_size = 0;
+		channel->buffer.frame[i].ulState = 0;
+		channel->buffer.frame[i].cur_size = 0;
 	}
 
-	dev->cur_frame[chn] = 0;
-	dev->last_frame[chn] = -1;
+	channel->cur_frame = 0;
+	channel->last_frame = -1;
 	return 0;
 }
 
-static int s2255_release_sys_buffers(struct s2255_dev *dev,
-				     unsigned long channel)
+static int s2255_release_sys_buffers(struct s2255_channel *channel)
 {
 	unsigned long i;
 	dprintk(1, "release sys buffers\n");
 	for (i = 0; i < SYS_FRAMES; i++) {
-		if (dev->buffer[channel].frame[i].lpvbits) {
+		if (channel->buffer.frame[i].lpvbits) {
 			dprintk(1, "vfree %p\n",
-				dev->buffer[channel].frame[i].lpvbits);
-			vfree(dev->buffer[channel].frame[i].lpvbits);
+				channel->buffer.frame[i].lpvbits);
+			vfree(channel->buffer.frame[i].lpvbits);
 		}
-		dev->buffer[channel].frame[i].lpvbits = NULL;
+		channel->buffer.frame[i].lpvbits = NULL;
 	}
 	return 0;
 }
@@ -2335,17 +2320,20 @@
 			fw_ver & 0xff);
 
 	for (j = 0; j < MAX_CHANNELS; j++) {
-		dev->b_acquire[j] = 0;
-		dev->mode[j] = mode_def;
+		struct s2255_channel *channel = &dev->channel[j];
+		channel->b_acquire = 0;
+		channel->mode = mode_def;
 		if (dev->pid == 0x2257 && j > 1)
-			dev->mode[j].color |= (1 << 16);
-		dev->jc[j].quality = S2255_DEF_JPEG_QUAL;
-		dev->cur_fmt[j] = &formats[0];
-		dev->mode[j].restart = 1;
-		dev->req_image_size[j] = get_transfer_size(&mode_def);
-		dev->frame_count[j] = 0;
+			channel->mode.color |= (1 << 16);
+		channel->jc.quality = S2255_DEF_JPEG_QUAL;
+		channel->width = LINE_SZ_4CIFS_NTSC;
+		channel->height = NUM_LINES_4CIFS_NTSC * 2;
+		channel->fmt = &formats[0];
+		channel->mode.restart = 1;
+		channel->req_image_size = get_transfer_size(&mode_def);
+		channel->frame_count = 0;
 		/* create the system buffers */
-		s2255_create_sys_buffers(dev, j);
+		s2255_create_sys_buffers(channel);
 	}
 	/* start read pipe */
 	s2255_start_readpipe(dev);
@@ -2359,14 +2347,12 @@
 	dprintk(1, "%s: dev: %p", __func__,  dev);
 
 	for (i = 0; i < MAX_CHANNELS; i++) {
-		if (dev->b_acquire[i])
-			s2255_stop_acquire(dev, i);
+		if (dev->channel[i].b_acquire)
+			s2255_stop_acquire(&dev->channel[i]);
 	}
-
 	s2255_stop_readpipe(dev);
-
 	for (i = 0; i < MAX_CHANNELS; i++)
-		s2255_release_sys_buffers(dev, i);
+		s2255_release_sys_buffers(&dev->channel[i]);
 	/* release transfer buffer */
 	kfree(dev->pipe.transfer_buffer);
 	return 0;
@@ -2459,29 +2445,26 @@
 }
 
 /* starts acquisition process */
-static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn)
+static int s2255_start_acquire(struct s2255_channel *channel)
 {
 	unsigned char *buffer;
 	int res;
 	unsigned long chn_rev;
 	int j;
-	if (chn >= MAX_CHANNELS) {
-		dprintk(2, "start acquire failed, bad channel %lu\n", chn);
-		return -1;
-	}
-	chn_rev = G_chnmap[chn];
+	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+	chn_rev = G_chnmap[channel->idx];
 	buffer = kzalloc(512, GFP_KERNEL);
 	if (buffer == NULL) {
 		dev_err(&dev->udev->dev, "out of mem\n");
 		return -ENOMEM;
 	}
 
-	dev->last_frame[chn] = -1;
-	dev->bad_payload[chn] = 0;
-	dev->cur_frame[chn] = 0;
+	channel->last_frame = -1;
+	channel->bad_payload = 0;
+	channel->cur_frame = 0;
 	for (j = 0; j < SYS_FRAMES; j++) {
-		dev->buffer[chn].frame[j].ulState = 0;
-		dev->buffer[chn].frame[j].cur_size = 0;
+		channel->buffer.frame[j].ulState = 0;
+		channel->buffer.frame[j].cur_size = 0;
 	}
 
 	/* send the start command */
@@ -2492,21 +2475,18 @@
 	if (res != 0)
 		dev_err(&dev->udev->dev, "CMD_START error\n");
 
-	dprintk(2, "start acquire exit[%lu] %d \n", chn, res);
+	dprintk(2, "start acquire exit[%d] %d \n", channel->idx, res);
 	kfree(buffer);
 	return 0;
 }
 
-static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn)
+static int s2255_stop_acquire(struct s2255_channel *channel)
 {
 	unsigned char *buffer;
 	int res;
 	unsigned long chn_rev;
-	if (chn >= MAX_CHANNELS) {
-		dprintk(2, "stop acquire failed, bad channel %lu\n", chn);
-		return -1;
-	}
-	chn_rev = G_chnmap[chn];
+	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+	chn_rev = G_chnmap[channel->idx];
 	buffer = kzalloc(512, GFP_KERNEL);
 	if (buffer == NULL) {
 		dev_err(&dev->udev->dev, "out of mem\n");
@@ -2520,8 +2500,8 @@
 	if (res != 0)
 		dev_err(&dev->udev->dev, "CMD_STOP error\n");
 	kfree(buffer);
-	dev->b_acquire[chn] = 0;
-	dprintk(4, "%s: chn %lu, res %d\n", __func__, chn, res);
+	channel->b_acquire = 0;
+	dprintk(4, "%s: chn %d, res %d\n", __func__, channel->idx, res);
 	return res;
 }
 
@@ -2575,7 +2555,7 @@
 		s2255_dev_err(&interface->dev, "out of memory\n");
 		return -ENOMEM;
 	}
-	atomic_set(&dev->channels, 0);
+	atomic_set(&dev->num_channels, 0);
 	dev->pid = id->idProduct;
 	dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
 	if (!dev->fw_data)
@@ -2612,8 +2592,10 @@
 	dev->timer.data = (unsigned long)dev->fw_data;
 	init_waitqueue_head(&dev->fw_data->wait_fw);
 	for (i = 0; i < MAX_CHANNELS; i++) {
-		init_waitqueue_head(&dev->wait_setmode[i]);
-		init_waitqueue_head(&dev->wait_vidstatus[i]);
+		struct s2255_channel *channel = &dev->channel[i];
+		dev->channel[i].idx = i;
+		init_waitqueue_head(&channel->wait_setmode);
+		init_waitqueue_head(&channel->wait_vidstatus);
 	}
 
 	dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2651,7 +2633,7 @@
 			printk(KERN_INFO "s2255: f2255usb.bin out of date.\n");
 		if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER)
 			printk(KERN_WARNING "s2255: 2257 requires firmware %d"
-			       "or above.\n", S2255_MIN_DSP_COLORFILTER);
+			       " or above.\n", S2255_MIN_DSP_COLORFILTER);
 	}
 	usb_reset_device(dev->udev);
 	/* load 2255 board specific */
@@ -2693,25 +2675,23 @@
 {
 	struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface));
 	int i;
-	int channels = atomic_read(&dev->channels);
-	v4l2_device_unregister(&dev->v4l2_dev);
+	int channels = atomic_read(&dev->num_channels);
+	v4l2_device_disconnect(&dev->v4l2_dev);
 	/*see comments in the uvc_driver.c usb disconnect function */
-	atomic_inc(&dev->channels);
+	atomic_inc(&dev->num_channels);
 	/* unregister each video device. */
-	for (i = 0; i < channels; i++) {
-		if (video_is_registered(&dev->vdev[i]))
-			video_unregister_device(&dev->vdev[i]);
-	}
+	for (i = 0; i < channels; i++)
+		video_unregister_device(&dev->channel[i].vdev);
 	/* wake up any of our timers */
 	atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
 	wake_up(&dev->fw_data->wait_fw);
 	for (i = 0; i < MAX_CHANNELS; i++) {
-		dev->setmode_ready[i] = 1;
-		wake_up(&dev->wait_setmode[i]);
-		dev->vidstatus_ready[i] = 1;
-		wake_up(&dev->wait_vidstatus[i]);
+		dev->channel[i].setmode_ready = 1;
+		wake_up(&dev->channel[i].wait_setmode);
+		dev->channel[i].vidstatus_ready = 1;
+		wake_up(&dev->channel[i].wait_vidstatus);
 	}
-	if (atomic_dec_and_test(&dev->channels))
+	if (atomic_dec_and_test(&dev->num_channels))
 		s2255_destroy(dev);
 	dev_info(&interface->dev, "%s\n", __func__);
 }
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index d3bd82a..10460fd 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -630,7 +630,7 @@
 	/* release the old buffer */
 	if (substream->runtime->dma_area) {
 		saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
-		videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+		videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
 		dsp_buffer_free(dev);
 		substream->runtime->dma_area = NULL;
 	}
@@ -646,12 +646,12 @@
 		return err;
 	}
 
-	if (0 != (err = videobuf_sg_dma_map(&dev->pci->dev, &dev->dmasound.dma))) {
+	if (0 != (err = videobuf_dma_map(&dev->pci->dev, &dev->dmasound.dma))) {
 		dsp_buffer_free(dev);
 		return err;
 	}
 	if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) {
-		videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+		videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
 		dsp_buffer_free(dev);
 		return err;
 	}
@@ -660,7 +660,7 @@
 						dev->dmasound.dma.sglen,
 						0))) {
 		saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
-		videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+		videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
 		dsp_buffer_free(dev);
 		return err;
 	}
@@ -669,7 +669,7 @@
 	   byte, but it doesn't work. So I allocate the DMA using the
 	   V4L functions, and force ALSA to use that as the DMA area */
 
-	substream->runtime->dma_area = dev->dmasound.dma.vmalloc;
+	substream->runtime->dma_area = dev->dmasound.dma.vaddr;
 	substream->runtime->dma_bytes = dev->dmasound.bufsize;
 	substream->runtime->dma_addr = 0;
 
@@ -696,7 +696,7 @@
 
 	if (substream->runtime->dma_area) {
 		saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
-		videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+		videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
 		dsp_buffer_free(dev);
 		substream->runtime->dma_area = NULL;
 	}
@@ -1080,7 +1080,7 @@
 	/* Card "creation" */
 
 	card->private_free = snd_saa7134_free;
-	chip = (snd_card_saa7134_t *) card->private_data;
+	chip = card->private_data;
 
 	spin_lock_init(&chip->lock);
 	spin_lock_init(&chip->mixer_lock);
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 07f6bb8..ec697fc 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -5462,6 +5462,30 @@
 			.amux = TV,
 		},
 	},
+	[SAA7134_BOARD_TECHNOTREND_BUDGET_T3000] = {
+		.name           = "TechoTrend TT-budget T-3000",
+		.tuner_type     = TUNER_PHILIPS_TD1316,
+		.audio_clock    = 0x00187de7,
+		.radio_type     = UNSET,
+		.tuner_addr     = 0x63,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = TV,
+			.tv     = 1,
+		}, {
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE2,
+		}, {
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		} },
+	},
 
 };
 
@@ -6631,6 +6655,12 @@
 		.subdevice    = 0x6655,
 		.driver_data  = SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S,
 	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x13c2,
+		.subdevice    = 0x2804,
+		.driver_data  = SAA7134_BOARD_TECHNOTREND_BUDGET_T3000,
+	}, {
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -7320,6 +7350,7 @@
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
 	case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
 	case SAA7134_BOARD_ASUS_EUROPA_HYBRID:
+	case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
 	{
 
 		/* The Philips EUROPA based hybrid boards have the tuner
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 90f2318..40bc635 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -256,7 +256,7 @@
 	BUG_ON(in_interrupt());
 
 	videobuf_waiton(&buf->vb,0,0);
-	videobuf_dma_unmap(q, dma);
+	videobuf_dma_unmap(q->dev, dma);
 	videobuf_dma_free(dma);
 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 31e82be..f26fe76 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -481,6 +481,17 @@
 	.request_firmware = philips_tda1004x_request_firmware
 };
 
+static struct tda1004x_config technotrend_budget_t3000_config = {
+	.demod_address = 0x8,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_4M,
+	.agc_config    = TDA10046_AGC_DEFAULT,
+	.if_freq       = TDA10046_FREQ_3617,
+	.tuner_address = 0x63,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
 /* ------------------------------------------------------------------
  * tda 1004x based cards with philips silicon tuner
  */
@@ -1168,6 +1179,18 @@
 			fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
 		}
 		break;
+	case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
+		fe0->dvb.frontend = dvb_attach(tda10046_attach,
+					       &technotrend_budget_t3000_config,
+					       &dev->i2c_adap);
+		if (fe0->dvb.frontend) {
+			dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+			fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+			fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+			fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+			fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+		}
+		break;
 	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
 		fe0->dvb.frontend = dvb_attach(tda10046_attach,
 					       &philips_tu1216_61_config,
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 756a1ca..c040a18 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -304,6 +304,7 @@
 #define SAA7134_BOARD_BEHOLD_H7             178
 #define SAA7134_BOARD_BEHOLD_A7             179
 #define SAA7134_BOARD_AVERMEDIA_M733A       180
+#define SAA7134_BOARD_TECHNOTREND_BUDGET_T3000 181
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 961bfa2..2b24bd0 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -633,6 +633,12 @@
 		cdwdr_width *= 2;
 	}
 
+	/* CSI2 special configuration */
+	if (pcdev->pdata->csi2_dev) {
+		in_width = ((in_width - 2) * 2);
+		left_offset *= 2;
+	}
+
 	/* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */
 	camor = left_offset | (top_offset << 16);
 
@@ -743,16 +749,16 @@
 	case V4L2_PIX_FMT_NV16:
 	case V4L2_PIX_FMT_NV61:
 		switch (cam->code) {
-		case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+		case V4L2_MBUS_FMT_UYVY8_2X8:
 			value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */
 			break;
-		case V4L2_MBUS_FMT_YVYU8_2X8_BE:
+		case V4L2_MBUS_FMT_VYUY8_2X8:
 			value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */
 			break;
-		case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+		case V4L2_MBUS_FMT_YUYV8_2X8:
 			value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */
 			break;
-		case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+		case V4L2_MBUS_FMT_YVYU8_2X8:
 			value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */
 			break;
 		default:
@@ -767,6 +773,11 @@
 	value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
 	value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
 	value |= pcdev->is_16bit ? 1 << 12 : 0;
+
+	/* CSI2 mode */
+	if (pcdev->pdata->csi2_dev)
+		value |= 3 << 12;
+
 	ceu_write(pcdev, CAMCR, value);
 
 	ceu_write(pcdev, CAPCR, 0x00300000);
@@ -883,6 +894,8 @@
 {
 	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 	struct device *dev = icd->dev.parent;
+	struct soc_camera_host *ici = to_soc_camera_host(dev);
+	struct sh_mobile_ceu_dev *pcdev = ici->priv;
 	int ret, k, n;
 	int formats = 0;
 	struct sh_mobile_ceu_cam *cam;
@@ -896,19 +909,19 @@
 
 	fmt = soc_mbus_get_fmtdesc(code);
 	if (!fmt) {
-		dev_err(icd->dev.parent,
-			"Invalid format code #%u: %d\n", idx, code);
+		dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
 		return -EINVAL;
 	}
 
-	ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
-	if (ret < 0)
-		return 0;
+	if (!pcdev->pdata->csi2_dev) {
+		ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
+		if (ret < 0)
+			return 0;
+	}
 
 	if (!icd->host_priv) {
 		struct v4l2_mbus_framefmt mf;
 		struct v4l2_rect rect;
-		struct device *dev = icd->dev.parent;
 		int shift = 0;
 
 		/* FIXME: subwindow is lost between close / open */
@@ -927,7 +940,8 @@
 			/* Try 2560x1920, 1280x960, 640x480, 320x240 */
 			mf.width	= 2560 >> shift;
 			mf.height	= 1920 >> shift;
-			ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+			ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+							 s_mbus_fmt, &mf);
 			if (ret < 0)
 				return ret;
 			shift++;
@@ -965,10 +979,10 @@
 		cam->extra_fmt = NULL;
 
 	switch (code) {
-	case V4L2_MBUS_FMT_YUYV8_2X8_BE:
-	case V4L2_MBUS_FMT_YVYU8_2X8_BE:
-	case V4L2_MBUS_FMT_YUYV8_2X8_LE:
-	case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+	case V4L2_MBUS_FMT_VYUY8_2X8:
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+	case V4L2_MBUS_FMT_YVYU8_2X8:
 		if (cam->extra_fmt)
 			break;
 
@@ -1005,7 +1019,7 @@
 		xlate->code	= code;
 		xlate++;
 		dev_dbg(dev, "Providing format %s in pass-through mode\n",
-			xlate->host_fmt->name);
+			fmt->name);
 	}
 
 	return formats;
@@ -1228,7 +1242,8 @@
 	struct v4l2_cropcap cap;
 	int ret;
 
-	ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf);
+	ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+					 s_mbus_fmt, mf);
 	if (ret < 0)
 		return ret;
 
@@ -1257,7 +1272,8 @@
 		tmp_h = min(2 * tmp_h, max_height);
 		mf->width = tmp_w;
 		mf->height = tmp_h;
-		ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf);
+		ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+						 s_mbus_fmt, mf);
 		dev_geo(dev, "Camera scaled to %ux%u\n",
 			mf->width, mf->height);
 		if (ret < 0) {
@@ -1514,7 +1530,8 @@
 	struct device *dev = icd->dev.parent;
 	__u32 pixfmt = pix->pixelformat;
 	const struct soc_camera_format_xlate *xlate;
-	unsigned int ceu_sub_width, ceu_sub_height;
+	/* Keep Compiler Happy */
+	unsigned int ceu_sub_width = 0, ceu_sub_height = 0;
 	u16 scale_v, scale_h;
 	int ret;
 	bool image_mode;
@@ -1569,8 +1586,8 @@
 
 	/* Done with the camera. Now see if we can improve the result */
 
-	dev_geo(dev, "Camera %d fmt %ux%u, requested %ux%u\n",
-		ret, mf.width, mf.height, pix->width, pix->height);
+	dev_geo(dev, "fmt %ux%u, requested %ux%u\n",
+		mf.width, mf.height, pix->width, pix->height);
 	if (ret < 0)
 		return ret;
 
@@ -1634,6 +1651,9 @@
 	int width, height;
 	int ret;
 
+	dev_geo(icd->dev.parent, "TRY_FMT(pix=0x%x, %ux%u)\n",
+		 pixfmt, pix->width, pix->height);
+
 	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
 	if (!xlate) {
 		dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
@@ -1660,7 +1680,7 @@
 	mf.code		= xlate->code;
 	mf.colorspace	= pix->colorspace;
 
-	ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+	ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, try_mbus_fmt, &mf);
 	if (ret < 0)
 		return ret;
 
@@ -1684,7 +1704,8 @@
 			 */
 			mf.width = 2560;
 			mf.height = 1920;
-			ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+			ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+							 try_mbus_fmt, &mf);
 			if (ret < 0) {
 				/* Shouldn't actually happen... */
 				dev_err(icd->dev.parent,
@@ -1699,6 +1720,9 @@
 			pix->height = height;
 	}
 
+	dev_geo(icd->dev.parent, "%s(): return %d, fmt 0x%x, %ux%u\n",
+		__func__, ret, pix->pixelformat, pix->width, pix->height);
+
 	return ret;
 }
 
@@ -1853,6 +1877,30 @@
 	.num_controls	= ARRAY_SIZE(sh_mobile_ceu_controls),
 };
 
+struct bus_wait {
+	struct notifier_block	notifier;
+	struct completion	completion;
+	struct device		*dev;
+};
+
+static int bus_notify(struct notifier_block *nb,
+		      unsigned long action, void *data)
+{
+	struct device *dev = data;
+	struct bus_wait *wait = container_of(nb, struct bus_wait, notifier);
+
+	if (wait->dev != dev)
+		return NOTIFY_DONE;
+
+	switch (action) {
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		/* Protect from module unloading */
+		wait_for_completion(&wait->completion);
+		return NOTIFY_OK;
+	}
+	return NOTIFY_DONE;
+}
+
 static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
 {
 	struct sh_mobile_ceu_dev *pcdev;
@@ -1860,6 +1908,11 @@
 	void __iomem *base;
 	unsigned int irq;
 	int err = 0;
+	struct bus_wait wait = {
+		.completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion),
+		.notifier.notifier_call = bus_notify,
+	};
+	struct device *csi2;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	irq = platform_get_irq(pdev, 0);
@@ -1931,12 +1984,54 @@
 	pcdev->ici.drv_name = dev_name(&pdev->dev);
 	pcdev->ici.ops = &sh_mobile_ceu_host_ops;
 
+	/* CSI2 interfacing */
+	csi2 = pcdev->pdata->csi2_dev;
+	if (csi2) {
+		wait.dev = csi2;
+
+		err = bus_register_notifier(&platform_bus_type, &wait.notifier);
+		if (err < 0)
+			goto exit_free_clk;
+
+		/*
+		 * From this point the driver module will not unload, until
+		 * we complete the completion.
+		 */
+
+		if (!csi2->driver || !csi2->driver->owner) {
+			complete(&wait.completion);
+			/* Either too late, or probing failed */
+			bus_unregister_notifier(&platform_bus_type, &wait.notifier);
+			err = -ENXIO;
+			goto exit_free_clk;
+		}
+
+		/*
+		 * The module is still loaded, in the worst case it is hanging
+		 * in device release on our completion. So, _now_ dereferencing
+		 * the "owner" is safe!
+		 */
+
+		err = try_module_get(csi2->driver->owner);
+
+		/* Let notifier complete, if it has been locked */
+		complete(&wait.completion);
+		bus_unregister_notifier(&platform_bus_type, &wait.notifier);
+		if (!err) {
+			err = -ENODEV;
+			goto exit_free_clk;
+		}
+	}
+
 	err = soc_camera_host_register(&pcdev->ici);
 	if (err)
-		goto exit_free_clk;
+		goto exit_module_put;
 
 	return 0;
 
+exit_module_put:
+	if (csi2 && csi2->driver)
+		module_put(csi2->driver->owner);
 exit_free_clk:
 	pm_runtime_disable(&pdev->dev);
 	free_irq(pcdev->irq, pcdev);
@@ -1956,6 +2051,7 @@
 	struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
 	struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
 					struct sh_mobile_ceu_dev, ici);
+	struct device *csi2 = pcdev->pdata->csi2_dev;
 
 	soc_camera_host_unregister(soc_host);
 	pm_runtime_disable(&pdev->dev);
@@ -1963,7 +2059,10 @@
 	if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
 		dma_release_declared_memory(&pdev->dev);
 	iounmap(pcdev->base);
+	if (csi2 && csi2->driver)
+		module_put(csi2->driver->owner);
 	kfree(pcdev);
+
 	return 0;
 }
 
@@ -1995,6 +2094,8 @@
 
 static int __init sh_mobile_ceu_init(void)
 {
+	/* Whatever return code */
+	request_module("sh_mobile_csi2");
 	return platform_driver_register(&sh_mobile_ceu_driver);
 }
 
diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c
new file mode 100644
index 0000000..84a6468
--- /dev/null
+++ b/drivers/media/video/sh_mobile_csi2.c
@@ -0,0 +1,354 @@
+/*
+ * Driver for the SH-Mobile MIPI CSI-2 unit
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/sh_mobile_csi2.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#define SH_CSI2_TREF	0x00
+#define SH_CSI2_SRST	0x04
+#define SH_CSI2_PHYCNT	0x08
+#define SH_CSI2_CHKSUM	0x0C
+#define SH_CSI2_VCDT	0x10
+
+struct sh_csi2 {
+	struct v4l2_subdev		subdev;
+	struct list_head		list;
+	struct notifier_block		notifier;
+	unsigned int			irq;
+	void __iomem			*base;
+	struct platform_device		*pdev;
+	struct sh_csi2_client_config	*client;
+};
+
+static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_mbus_framefmt *mf)
+{
+	struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+	struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+
+	if (mf->width > 8188)
+		mf->width = 8188;
+	else if (mf->width & 1)
+		mf->width &= ~1;
+
+	switch (pdata->type) {
+	case SH_CSI2C:
+		switch (mf->code) {
+		case V4L2_MBUS_FMT_UYVY8_2X8:		/* YUV422 */
+		case V4L2_MBUS_FMT_YUYV8_1_5X8:		/* YUV420 */
+		case V4L2_MBUS_FMT_GREY8_1X8:		/* RAW8 */
+		case V4L2_MBUS_FMT_SBGGR8_1X8:
+		case V4L2_MBUS_FMT_SGRBG8_1X8:
+			break;
+		default:
+			/* All MIPI CSI-2 devices must support one of primary formats */
+			mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
+		}
+		break;
+	case SH_CSI2I:
+		switch (mf->code) {
+		case V4L2_MBUS_FMT_GREY8_1X8:		/* RAW8 */
+		case V4L2_MBUS_FMT_SBGGR8_1X8:
+		case V4L2_MBUS_FMT_SGRBG8_1X8:
+		case V4L2_MBUS_FMT_SBGGR10_1X10:	/* RAW10 */
+		case V4L2_MBUS_FMT_SBGGR12_1X12:	/* RAW12 */
+			break;
+		default:
+			/* All MIPI CSI-2 devices must support one of primary formats */
+			mf->code = V4L2_MBUS_FMT_SBGGR8_1X8;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * We have done our best in try_fmt to try and tell the sensor, which formats
+ * we support. If now the configuration is unsuitable for us we can only
+ * error out.
+ */
+static int sh_csi2_s_fmt(struct v4l2_subdev *sd,
+			 struct v4l2_mbus_framefmt *mf)
+{
+	struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+	u32 tmp = (priv->client->channel & 3) << 8;
+
+	dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+	if (mf->width > 8188 || mf->width & 1)
+		return -EINVAL;
+
+	switch (mf->code) {
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		tmp |= 0x1e;	/* YUV422 8 bit */
+		break;
+	case V4L2_MBUS_FMT_YUYV8_1_5X8:
+		tmp |= 0x18;	/* YUV420 8 bit */
+		break;
+	case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+		tmp |= 0x21;	/* RGB555 */
+		break;
+	case V4L2_MBUS_FMT_RGB565_2X8_BE:
+		tmp |= 0x22;	/* RGB565 */
+		break;
+	case V4L2_MBUS_FMT_GREY8_1X8:
+	case V4L2_MBUS_FMT_SBGGR8_1X8:
+	case V4L2_MBUS_FMT_SGRBG8_1X8:
+		tmp |= 0x2a;	/* RAW8 */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	iowrite32(tmp, priv->base + SH_CSI2_VCDT);
+
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = {
+	.s_mbus_fmt	= sh_csi2_s_fmt,
+	.try_mbus_fmt	= sh_csi2_try_fmt,
+};
+
+static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops;
+
+static struct v4l2_subdev_ops sh_csi2_subdev_ops = {
+	.core	= &sh_csi2_subdev_core_ops,
+	.video	= &sh_csi2_subdev_video_ops,
+};
+
+static void sh_csi2_hwinit(struct sh_csi2 *priv)
+{
+	struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+	__u32 tmp = 0x10; /* Enable MIPI CSI clock lane */
+
+	/* Reflect registers immediately */
+	iowrite32(0x00000001, priv->base + SH_CSI2_TREF);
+	/* reset CSI2 harware */
+	iowrite32(0x00000001, priv->base + SH_CSI2_SRST);
+	udelay(5);
+	iowrite32(0x00000000, priv->base + SH_CSI2_SRST);
+
+	if (priv->client->lanes & 3)
+		tmp |= priv->client->lanes & 3;
+	else
+		/* Default - both lanes */
+		tmp |= 3;
+
+	if (priv->client->phy == SH_CSI2_PHY_MAIN)
+		tmp |= 0x8000;
+
+	iowrite32(tmp, priv->base + SH_CSI2_PHYCNT);
+
+	tmp = 0;
+	if (pdata->flags & SH_CSI2_ECC)
+		tmp |= 2;
+	if (pdata->flags & SH_CSI2_CRC)
+		tmp |= 1;
+	iowrite32(tmp, priv->base + SH_CSI2_CHKSUM);
+}
+
+static int sh_csi2_set_bus_param(struct soc_camera_device *icd,
+				 unsigned long flags)
+{
+	return 0;
+}
+
+static unsigned long sh_csi2_query_bus_param(struct soc_camera_device *icd)
+{
+	struct soc_camera_link *icl = to_soc_camera_link(icd);
+	const unsigned long flags = SOCAM_PCLK_SAMPLE_RISING |
+		SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
+		SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_DATA_ACTIVE_HIGH;
+
+	return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+static int sh_csi2_notify(struct notifier_block *nb,
+			  unsigned long action, void *data)
+{
+	struct device *dev = data;
+	struct soc_camera_device *icd = to_soc_camera_dev(dev);
+	struct v4l2_device *v4l2_dev = dev_get_drvdata(dev->parent);
+	struct sh_csi2 *priv =
+		container_of(nb, struct sh_csi2, notifier);
+	struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+	int ret, i;
+
+	for (i = 0; i < pdata->num_clients; i++)
+		if (&pdata->clients[i].pdev->dev == icd->pdev)
+			break;
+
+	dev_dbg(dev, "%s(%p): action = %lu, found #%d\n", __func__, dev, action, i);
+
+	if (i == pdata->num_clients)
+		return NOTIFY_DONE;
+
+	switch (action) {
+	case BUS_NOTIFY_BOUND_DRIVER:
+		snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s",
+			 dev_name(v4l2_dev->dev), ".mipi-csi");
+		ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev);
+		dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
+		if (ret < 0)
+			return NOTIFY_DONE;
+
+		priv->client = pdata->clients + i;
+
+		icd->ops->set_bus_param		= sh_csi2_set_bus_param;
+		icd->ops->query_bus_param	= sh_csi2_query_bus_param;
+
+		pm_runtime_get_sync(v4l2_get_subdevdata(&priv->subdev));
+
+		sh_csi2_hwinit(priv);
+		break;
+	case BUS_NOTIFY_UNBIND_DRIVER:
+		priv->client = NULL;
+
+		/* Driver is about to be unbound */
+		icd->ops->set_bus_param		= NULL;
+		icd->ops->query_bus_param	= NULL;
+
+		v4l2_device_unregister_subdev(&priv->subdev);
+
+		pm_runtime_put(v4l2_get_subdevdata(&priv->subdev));
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static __devinit int sh_csi2_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	unsigned int irq;
+	int ret;
+	struct sh_csi2 *priv;
+	/* Platform data specify the PHY, lanes, ECC, CRC */
+	struct sh_csi2_pdata *pdata = pdev->dev.platform_data;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	/* Interrupt unused so far */
+	irq = platform_get_irq(pdev, 0);
+
+	if (!res || (int)irq <= 0 || !pdata) {
+		dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n");
+		return -ENODEV;
+	}
+
+	/* TODO: Add support for CSI2I. Careful: different register layout! */
+	if (pdata->type != SH_CSI2C) {
+		dev_err(&pdev->dev, "Only CSI2C supported ATM.\n");
+		return -EINVAL;
+	}
+
+	priv = kzalloc(sizeof(struct sh_csi2), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->irq = irq;
+	priv->notifier.notifier_call = sh_csi2_notify;
+
+	/* We MUST attach after the MIPI sensor */
+	ret = bus_register_notifier(&soc_camera_bus_type, &priv->notifier);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "CSI2 cannot register notifier\n");
+		goto ernotify;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+		dev_err(&pdev->dev, "CSI2 register region already claimed\n");
+		ret = -EBUSY;
+		goto ereqreg;
+	}
+
+	priv->base = ioremap(res->start, resource_size(res));
+	if (!priv->base) {
+		ret = -ENXIO;
+		dev_err(&pdev->dev, "Unable to ioremap CSI2 registers.\n");
+		goto eremap;
+	}
+
+	priv->pdev = pdev;
+
+	v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops);
+	v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
+
+	platform_set_drvdata(pdev, priv);
+
+	pm_runtime_enable(&pdev->dev);
+
+	dev_dbg(&pdev->dev, "CSI2 probed.\n");
+
+	return 0;
+
+eremap:
+	release_mem_region(res->start, resource_size(res));
+ereqreg:
+	bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
+ernotify:
+	kfree(priv);
+
+	return ret;
+}
+
+static __devexit int sh_csi2_remove(struct platform_device *pdev)
+{
+	struct sh_csi2 *priv = platform_get_drvdata(pdev);
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
+	pm_runtime_disable(&pdev->dev);
+	iounmap(priv->base);
+	release_mem_region(res->start, resource_size(res));
+	platform_set_drvdata(pdev, NULL);
+	kfree(priv);
+
+	return 0;
+}
+
+static struct platform_driver __refdata sh_csi2_pdrv = {
+	.remove  = __devexit_p(sh_csi2_remove),
+	.driver  = {
+		.name	= "sh-mobile-csi2",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init sh_csi2_init(void)
+{
+	return platform_driver_probe(&sh_csi2_pdrv, sh_csi2_probe);
+}
+
+static void __exit sh_csi2_exit(void)
+{
+	platform_driver_unregister(&sh_csi2_pdrv);
+}
+
+module_init(sh_csi2_init);
+module_exit(sh_csi2_exit);
+
+MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sh-mobile-csi2");
diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c
index f5b892a..d394187 100644
--- a/drivers/media/video/sh_vou.c
+++ b/drivers/media/video/sh_vou.c
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/slab.h>
 #include <linux/version.h>
 #include <linux/videodev2.h>
 
@@ -57,7 +58,7 @@
 };
 
 #define VOU_MAX_IMAGE_WIDTH	720
-#define VOU_MAX_IMAGE_HEIGHT	480
+#define VOU_MAX_IMAGE_HEIGHT	576
 
 struct sh_vou_device {
 	struct v4l2_device v4l2_dev;
@@ -527,20 +528,17 @@
 static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
 {
 	/* The compiler cannot know, that best and idx will indeed be set */
-	unsigned int best_err = UINT_MAX, best = 0, width_max, height_max;
+	unsigned int best_err = UINT_MAX, best = 0, img_height_max;
 	int i, idx = 0;
 
-	if (std & V4L2_STD_525_60) {
-		width_max = 858;
-		height_max = 262;
-	} else {
-		width_max = 864;
-		height_max = 312;
-	}
+	if (std & V4L2_STD_525_60)
+		img_height_max = 480;
+	else
+		img_height_max = 576;
 
 	/* Image width must be a multiple of 4 */
 	v4l_bound_align_image(&geo->in_width, 0, VOU_MAX_IMAGE_WIDTH, 2,
-			      &geo->in_height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+			      &geo->in_height, 0, img_height_max, 1, 0);
 
 	/* Select scales to come as close as possible to the output image */
 	for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) {
@@ -573,7 +571,7 @@
 		unsigned int found = geo->output.height * vou_scale_v_den[i] /
 			vou_scale_v_num[i];
 
-		if (found > VOU_MAX_IMAGE_HEIGHT)
+		if (found > img_height_max)
 			/* scales increase */
 			break;
 
@@ -597,15 +595,18 @@
  */
 static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
 {
-	unsigned int best_err = UINT_MAX, best, width_max, height_max;
+	unsigned int best_err = UINT_MAX, best, width_max, height_max,
+		img_height_max;
 	int i, idx;
 
 	if (std & V4L2_STD_525_60) {
 		width_max = 858;
 		height_max = 262 * 2;
+		img_height_max = 480;
 	} else {
 		width_max = 864;
 		height_max = 312 * 2;
+		img_height_max = 576;
 	}
 
 	/* Select scales to come as close as possible to the output image */
@@ -644,7 +645,7 @@
 		unsigned int found = geo->in_height * vou_scale_v_num[i] /
 			vou_scale_v_den[i];
 
-		if (found > VOU_MAX_IMAGE_HEIGHT)
+		if (found > img_height_max)
 			/* scales increase */
 			break;
 
@@ -673,11 +674,12 @@
 	struct video_device *vdev = video_devdata(file);
 	struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
 	struct v4l2_pix_format *pix = &fmt->fmt.pix;
+	unsigned int img_height_max;
 	int pix_idx;
 	struct sh_vou_geometry geo;
 	struct v4l2_mbus_framefmt mbfmt = {
 		/* Revisit: is this the correct code? */
-		.code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+		.code = V4L2_MBUS_FMT_YUYV8_2X8,
 		.field = V4L2_FIELD_INTERLACED,
 		.colorspace = V4L2_COLORSPACE_SMPTE170M,
 	};
@@ -701,9 +703,14 @@
 	if (pix_idx == ARRAY_SIZE(vou_fmt))
 		return -EINVAL;
 
+	if (vou_dev->std & V4L2_STD_525_60)
+		img_height_max = 480;
+	else
+		img_height_max = 576;
+
 	/* Image width must be a multiple of 4 */
 	v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2,
-			      &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+			      &pix->height, 0, img_height_max, 1, 0);
 
 	geo.in_width = pix->width;
 	geo.in_height = pix->height;
@@ -724,8 +731,8 @@
 
 	/* Sanity checks */
 	if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
-	    (unsigned)mbfmt.height > VOU_MAX_IMAGE_HEIGHT ||
-	    mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+	    (unsigned)mbfmt.height > img_height_max ||
+	    mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
 		return -EIO;
 
 	if (mbfmt.width != geo.output.width ||
@@ -936,10 +943,11 @@
 	struct sh_vou_geometry geo;
 	struct v4l2_mbus_framefmt mbfmt = {
 		/* Revisit: is this the correct code? */
-		.code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+		.code = V4L2_MBUS_FMT_YUYV8_2X8,
 		.field = V4L2_FIELD_INTERLACED,
 		.colorspace = V4L2_COLORSPACE_SMPTE170M,
 	};
+	unsigned int img_height_max;
 	int ret;
 
 	dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u@%u:%u\n", __func__,
@@ -948,14 +956,19 @@
 	if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
 		return -EINVAL;
 
+	if (vou_dev->std & V4L2_STD_525_60)
+		img_height_max = 480;
+	else
+		img_height_max = 576;
+
 	v4l_bound_align_image(&rect->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
-			      &rect->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+			      &rect->height, 0, img_height_max, 1, 0);
 
 	if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH)
 		rect->left = VOU_MAX_IMAGE_WIDTH - rect->width;
 
-	if (rect->height + rect->top > VOU_MAX_IMAGE_HEIGHT)
-		rect->top = VOU_MAX_IMAGE_HEIGHT - rect->height;
+	if (rect->height + rect->top > img_height_max)
+		rect->top = img_height_max - rect->height;
 
 	geo.output = *rect;
 	geo.in_width = pix->width;
@@ -980,8 +993,8 @@
 
 	/* Sanity checks */
 	if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
-	    (unsigned)mbfmt.height > VOU_MAX_IMAGE_HEIGHT ||
-	    mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+	    (unsigned)mbfmt.height > img_height_max ||
+	    mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
 		return -EIO;
 
 	geo.output.width = mbfmt.width;
@@ -1329,13 +1342,13 @@
 	rect->left		= 0;
 	rect->top		= 0;
 	rect->width		= VOU_MAX_IMAGE_WIDTH;
-	rect->height		= VOU_MAX_IMAGE_HEIGHT;
+	rect->height		= 480;
 	pix->width		= VOU_MAX_IMAGE_WIDTH;
-	pix->height		= VOU_MAX_IMAGE_HEIGHT;
+	pix->height		= 480;
 	pix->pixelformat	= V4L2_PIX_FMT_YVYU;
 	pix->field		= V4L2_FIELD_NONE;
 	pix->bytesperline	= VOU_MAX_IMAGE_WIDTH * 2;
-	pix->sizeimage		= VOU_MAX_IMAGE_WIDTH * 2 * VOU_MAX_IMAGE_HEIGHT;
+	pix->sizeimage		= VOU_MAX_IMAGE_WIDTH * 2 * 480;
 	pix->colorspace		= V4L2_COLORSPACE_SMPTE170M;
 
 	region = request_mem_region(reg_res->start, resource_size(reg_res),
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 475757b..f203293 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -1107,13 +1107,14 @@
 	return ret;
 }
 
-static struct bus_type soc_camera_bus_type = {
+struct bus_type soc_camera_bus_type = {
 	.name		= "soc-camera",
 	.probe		= soc_camera_probe,
 	.remove		= soc_camera_remove,
 	.suspend	= soc_camera_suspend,
 	.resume		= soc_camera_resume,
 };
+EXPORT_SYMBOL_GPL(soc_camera_bus_type);
 
 static struct device_driver ic_drv = {
 	.name	= "camera",
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c
index 248c986..bf406e8 100644
--- a/drivers/media/video/soc_camera_platform.c
+++ b/drivers/media/video/soc_camera_platform.c
@@ -56,8 +56,8 @@
 	return p->bus_param;
 }
 
-static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd,
-				       struct v4l2_mbus_framefmt *mf)
+static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd,
+					struct v4l2_mbus_framefmt *mf)
 {
 	struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
 
@@ -65,6 +65,7 @@
 	mf->height	= p->format.height;
 	mf->code	= p->format.code;
 	mf->colorspace	= p->format.colorspace;
+	mf->field	= p->format.field;
 
 	return 0;
 }
@@ -83,10 +84,45 @@
 	return 0;
 }
 
+static int soc_camera_platform_g_crop(struct v4l2_subdev *sd,
+				      struct v4l2_crop *a)
+{
+	struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+	a->c.left	= 0;
+	a->c.top	= 0;
+	a->c.width	= p->format.width;
+	a->c.height	= p->format.height;
+	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int soc_camera_platform_cropcap(struct v4l2_subdev *sd,
+				       struct v4l2_cropcap *a)
+{
+	struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+	a->bounds.left			= 0;
+	a->bounds.top			= 0;
+	a->bounds.width			= p->format.width;
+	a->bounds.height		= p->format.height;
+	a->defrect			= a->bounds;
+	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->pixelaspect.numerator	= 1;
+	a->pixelaspect.denominator	= 1;
+
+	return 0;
+}
+
 static struct v4l2_subdev_video_ops platform_subdev_video_ops = {
 	.s_stream	= soc_camera_platform_s_stream,
-	.try_mbus_fmt	= soc_camera_platform_try_fmt,
 	.enum_mbus_fmt	= soc_camera_platform_enum_fmt,
+	.cropcap	= soc_camera_platform_cropcap,
+	.g_crop		= soc_camera_platform_g_crop,
+	.try_mbus_fmt	= soc_camera_platform_fill_fmt,
+	.g_mbus_fmt	= soc_camera_platform_fill_fmt,
+	.s_mbus_fmt	= soc_camera_platform_fill_fmt,
 };
 
 static struct v4l2_subdev_ops platform_subdev_ops = {
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c
index 8b63b65..9139121 100644
--- a/drivers/media/video/soc_mediabus.c
+++ b/drivers/media/video/soc_mediabus.c
@@ -18,28 +18,28 @@
 #define MBUS_IDX(f) (V4L2_MBUS_FMT_ ## f - V4L2_MBUS_FMT_FIXED - 1)
 
 static const struct soc_mbus_pixelfmt mbus_fmt[] = {
-	[MBUS_IDX(YUYV8_2X8_LE)] = {
+	[MBUS_IDX(YUYV8_2X8)] = {
 		.fourcc			= V4L2_PIX_FMT_YUYV,
 		.name			= "YUYV",
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
 	},
-	[MBUS_IDX(YVYU8_2X8_LE)] = {
+	[MBUS_IDX(YVYU8_2X8)] = {
 		.fourcc			= V4L2_PIX_FMT_YVYU,
 		.name			= "YVYU",
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
 	},
-	[MBUS_IDX(YUYV8_2X8_BE)] = {
+	[MBUS_IDX(UYVY8_2X8)] = {
 		.fourcc			= V4L2_PIX_FMT_UYVY,
 		.name			= "UYVY",
 		.bits_per_sample	= 8,
 		.packing		= SOC_MBUS_PACKING_2X8_PADHI,
 		.order			= SOC_MBUS_ORDER_LE,
 	},
-	[MBUS_IDX(YVYU8_2X8_BE)] = {
+	[MBUS_IDX(VYUY8_2X8)] = {
 		.fourcc			= V4L2_PIX_FMT_VYUY,
 		.name			= "VYUY",
 		.bits_per_sample	= 8,
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
deleted file mode 100644
index 5938ad8..0000000
--- a/drivers/media/video/stv680.c
+++ /dev/null
@@ -1,1565 +0,0 @@
-/*
- *  STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net)
- *
- * Thanks to STMicroelectronics for information on the usb commands, and
- * to Steve Miller at STM for his help and encouragement while I was
- * writing this driver.
- *
- * This driver is based heavily on the
- * Endpoints (formerly known as AOX) se401 USB Camera Driver
- * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
- *
- * Still somewhat based on the Linux ov511 driver.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * History:
- * ver 0.1 October, 2001. Initial attempt.
- *
- * ver 0.2 November, 2001. Fixed asbility to resize, added brightness
- *                         function, made more stable (?)
- *
- * ver 0.21 Nov, 2001.     Added gamma correction and white balance,
- *                         due to Alexander Schwartz. Still trying to
- *                         improve stablility. Moved stuff into stv680.h
- *
- * ver 0.22 Nov, 2001.	   Added sharpen function (by Michael Sweet,
- *                         mike@easysw.com) from GIMP, also used in pencam.
- *                         Simple, fast, good integer math routine.
- *
- * ver 0.23 Dec, 2001 (gkh)
- * 			   Took out sharpen function, ran code through
- * 			   Lindent, and did other minor tweaks to get
- * 			   things to work properly with 2.5.1
- *
- * ver 0.24 Jan, 2002 (kjs)
- *                         Fixed the problem with webcam crashing after
- *                         two pictures. Changed the way pic is halved to
- *                         improve quality. Got rid of green line around
- *                         frame. Fix brightness reset when changing size
- *                         bug. Adjusted gamma filters slightly.
- *
- * ver 0.25 Jan, 2002 (kjs)
- *			   Fixed a bug in which the driver sometimes attempted
- *			   to set to a non-supported size. This allowed
- *			   gnomemeeting to work.
- *			   Fixed proc entry removal bug.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/pagemap.h>
-#include <linux/errno.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-#include "stv680.h"
-
-static int video_nr = -1;
-
-static int swapRGB;	/* 0 = default for auto select */
-
-/* 0 = default to allow auto select; -1 = swap never, +1 = swap always */
-static int swapRGB_on;
-
-static unsigned int debug;
-
-#define PDEBUG(level, fmt, args...) \
-	do { \
-	if (debug >= level)	\
-		printk(KERN_INFO KBUILD_MODNAME " [%s:%d] \n" fmt,	\
-			__func__, __LINE__ , ## args);	\
-	} while (0)
-
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.25"
-#define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
-#define DRIVER_DESC "STV0680 USB Camera Driver"
-
-MODULE_AUTHOR (DRIVER_AUTHOR);
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_LICENSE ("GPL");
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC (debug, "Debug enabled or not");
-module_param(swapRGB_on, int, 0);
-MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
-module_param(video_nr, int, 0);
-
-/********************************************************************
- *
- * Memory management
- *
- * This is a shameless copy from the USB-cpia driver (linux kernel
- * version 2.3.29 or so, I have no idea what this code actually does ;).
- * Actually it seems to be a copy of a shameless copy of the bttv-driver.
- * Or that is a copy of a shameless copy of ... (To the powers: is there
- * no generic kernel-function to do this sort of stuff?)
- *
- * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
- * there will be one, but apparentely not yet -jerdfelt
- *
- * So I copied it again for the ov511 driver -claudio
- *
- * Same for the se401 driver -Jeroen
- *
- * And the STV0680 driver - Kevin
- ********************************************************************/
-static void *rvmalloc (unsigned long size)
-{
-	void *mem;
-	unsigned long adr;
-
-	size = PAGE_ALIGN(size);
-	mem = vmalloc_32 (size);
-	if (!mem)
-		return NULL;
-
-	memset (mem, 0, size);	/* Clear the ram out, no junk to the user */
-	adr = (unsigned long) mem;
-	while (size > 0) {
-		SetPageReserved(vmalloc_to_page((void *)adr));
-		adr += PAGE_SIZE;
-		size -= PAGE_SIZE;
-	}
-	return mem;
-}
-
-static void rvfree (void *mem, unsigned long size)
-{
-	unsigned long adr;
-
-	if (!mem)
-		return;
-
-	adr = (unsigned long) mem;
-	while ((long) size > 0) {
-		ClearPageReserved(vmalloc_to_page((void *)adr));
-		adr += PAGE_SIZE;
-		size -= PAGE_SIZE;
-	}
-	vfree (mem);
-}
-
-
-/*********************************************************************
- * pencam read/write functions
- ********************************************************************/
-
-static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size)
-{
-	int ret = -1;
-
-	switch (set) {
-	case 0:		/*  0xc1  */
-		ret = usb_control_msg (stv680->udev,
-				       usb_rcvctrlpipe (stv680->udev, 0),
-				       req,
-				       (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
-				       value, 0, buffer, size, PENCAM_TIMEOUT);
-		break;
-
-	case 1:		/*  0x41  */
-		ret = usb_control_msg (stv680->udev,
-				       usb_sndctrlpipe (stv680->udev, 0),
-				       req,
-				       (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
-				       value, 0, buffer, size, PENCAM_TIMEOUT);
-		break;
-
-	case 2:		/*  0x80  */
-		ret = usb_control_msg (stv680->udev,
-				       usb_rcvctrlpipe (stv680->udev, 0),
-				       req,
-				       (USB_DIR_IN | USB_RECIP_DEVICE),
-				       value, 0, buffer, size, PENCAM_TIMEOUT);
-		break;
-
-	case 3:		/*  0x40  */
-		ret = usb_control_msg (stv680->udev,
-				       usb_sndctrlpipe (stv680->udev, 0),
-				       req,
-				       (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
-				       value, 0, buffer, size, PENCAM_TIMEOUT);
-		break;
-
-	}
-	if ((ret < 0) && (req != 0x0a)) {
-		PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret);
-	}
-	return ret;
-}
-
-static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate)
-{
-
-	if (configuration != dev->udev->actconfig->desc.bConfigurationValue
-			|| usb_reset_configuration (dev->udev) < 0) {
-		PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration);
-		return -1;
-	}
-	if (usb_set_interface (dev->udev, interface, alternate) < 0) {
-		PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate);
-		return -1;
-	}
-	return 0;
-}
-
-static int stv_stop_video (struct usb_stv *dev)
-{
-	int i;
-	unsigned char *buf;
-
-	buf = kmalloc (40, GFP_KERNEL);
-	if (buf == NULL) {
-		PDEBUG (0, "STV(e): Out of (small buf) memory");
-		return -1;
-	}
-
-	/* this is a high priority command; it stops all lower order commands */
-	if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) {
-		i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02);	/* Get Last Error; 2 = busy */
-		PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buf[0], buf[1]);
-	} else {
-		PDEBUG (1, "STV(i): Camera reset to idle mode.");
-	}
-
-	if ((i = stv_set_config (dev, 1, 0, 0)) < 0)
-		PDEBUG (1, "STV(e): Reset config during exit failed");
-
-	/*  get current mode  */
-	buf[0] = 0xf0;
-	if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08)	/* get mode */
-		PDEBUG (0, "STV(e): Stop_video: problem setting original mode");
-	if (dev->origMode != buf[0]) {
-		memset (buf, 0, 8);
-		buf[0] = (unsigned char) dev->origMode;
-		if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) {
-			PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed");
-			i = -1;
-		}
-		buf[0] = 0xf0;
-		i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08);
-		if ((i != 0x08) || (buf[0] != dev->origMode)) {
-			PDEBUG (0, "STV(e): camera NOT set to original resolution.");
-			i = -1;
-		} else
-			PDEBUG (0, "STV(i): Camera set to original resolution");
-	}
-	/* origMode */
-	kfree(buf);
-	return i;
-}
-
-static int stv_set_video_mode (struct usb_stv *dev)
-{
-	int i, stop_video = 1;
-	unsigned char *buf;
-
-	buf = kmalloc (40, GFP_KERNEL);
-	if (buf == NULL) {
-		PDEBUG (0, "STV(e): Out of (small buf) memory");
-		return -1;
-	}
-
-	if ((i = stv_set_config (dev, 1, 0, 0)) < 0) {
-		kfree(buf);
-		return i;
-	}
-
-	i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12);
-	if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) {
-		PDEBUG (1, "STV(e): Could not get descriptor 0100.");
-		goto error;
-	}
-
-	/*  set alternate interface 1 */
-	if ((i = stv_set_config (dev, 1, 0, 1)) < 0)
-		goto error;
-
-	if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10)
-		goto error;
-	PDEBUG (1, "STV(i): Setting video mode.");
-	/*  Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240)  */
-	if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) {
-		stop_video = 0;
-		goto error;
-	}
-	goto exit;
-
-error:
-	kfree(buf);
-	if (stop_video == 1)
-		stv_stop_video (dev);
-	return -1;
-
-exit:
-	kfree(buf);
-	return 0;
-}
-
-static int stv_init (struct usb_stv *stv680)
-{
-	int i = 0;
-	unsigned char *buffer;
-	unsigned long int bufsize;
-
-	buffer = kzalloc (40, GFP_KERNEL);
-	if (buffer == NULL) {
-		PDEBUG (0, "STV(e): Out of (small buf) memory");
-		return -1;
-	}
-	udelay (100);
-
-	/* set config 1, interface 0, alternate 0 */
-	if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) {
-		kfree(buffer);
-		PDEBUG (0, "STV(e): set config 1,0,0 failed");
-		return -1;
-	}
-	/* ping camera to be sure STV0680 is present */
-	if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02)
-		goto error;
-	if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) {
-		PDEBUG (1, "STV(e): camera ping failed!!");
-		goto error;
-	}
-
-	/* get camera descriptor */
-	if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09)
-		goto error;
-	i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22);
-	if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) {
-		PDEBUG (1, "STV(e): Could not get descriptor 0200.");
-		goto error;
-	}
-	if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02)
-		goto error;
-	if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24)
-		goto error;
-	if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
-		goto error;
-
-	stv680->SupportedModes = buffer[7];
-	i = stv680->SupportedModes;
-	stv680->CIF = 0;
-	stv680->VGA = 0;
-	stv680->QVGA = 0;
-	if (i & 1)
-		stv680->CIF = 1;
-	if (i & 2)
-		stv680->VGA = 1;
-	if (i & 8)
-		stv680->QVGA = 1;
-	if (stv680->SupportedModes == 0) {
-		PDEBUG (0, "STV(e): There are NO supported STV680 modes!!");
-		i = -1;
-		goto error;
-	} else {
-		if (stv680->CIF)
-			PDEBUG (0, "STV(i): CIF is supported");
-		if (stv680->QVGA)
-			PDEBUG (0, "STV(i): QVGA is supported");
-	}
-	/* FW rev, ASIC rev, sensor ID  */
-	PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]);
-	PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]);
-	PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4));
-
-	/*  set alternate interface 1 */
-	if ((i = stv_set_config (stv680, 1, 0, 1)) < 0)
-		goto error;
-
-	if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
-		goto error;
-	if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08)
-		goto error;
-	i = buffer[3];
-	PDEBUG (0, "STV(i): Camera has %i pictures.", i);
-
-	/*  get current mode */
-	if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08)
-		goto error;
-	stv680->origMode = buffer[0];	/* 01 = VGA, 03 = QVGA, 00 = CIF */
-
-	/* This will attemp CIF mode, if supported. If not, set to QVGA  */
-	memset (buffer, 0, 8);
-	if (stv680->CIF)
-		buffer[0] = 0x00;
-	else if (stv680->QVGA)
-		buffer[0] = 0x03;
-	if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) {
-		PDEBUG (0, "STV(i): Set_Camera_Mode failed");
-		i = -1;
-		goto error;
-	}
-	buffer[0] = 0xf0;
-	stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08);
-	if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) {
-		PDEBUG (0, "STV(e): Error setting camera video mode!");
-		i = -1;
-		goto error;
-	} else {
-		if (buffer[0] == 0) {
-			stv680->VideoMode = 0x0000;
-			PDEBUG (0, "STV(i): Video Mode set to CIF");
-		}
-		if (buffer[0] == 0x03) {
-			stv680->VideoMode = 0x0300;
-			PDEBUG (0, "STV(i): Video Mode set to QVGA");
-		}
-	}
-	if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10)
-		goto error;
-	bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]);
-	stv680->cwidth = (buffer[4] << 8) | (buffer[5]);	/* ->camera = 322, 356, 644  */
-	stv680->cheight = (buffer[6] << 8) | (buffer[7]);	/* ->camera = 242, 292, 484  */
-	stv680->origGain = buffer[12];
-
-	goto exit;
-
-error:
-	i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02);	/* Get Last Error */
-	PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buffer[0], buffer[1]);
-	kfree(buffer);
-	return -1;
-
-exit:
-	kfree(buffer);
-
-	/* video = 320x240, 352x288 */
-	if (stv680->CIF == 1) {
-		stv680->maxwidth = 352;
-		stv680->maxheight = 288;
-		stv680->vwidth = 352;
-		stv680->vheight = 288;
-	}
-	if (stv680->QVGA == 1) {
-		stv680->maxwidth = 320;
-		stv680->maxheight = 240;
-		stv680->vwidth = 320;
-		stv680->vheight = 240;
-	}
-
-	stv680->rawbufsize = bufsize;	/* must be ./. by 8 */
-	stv680->maxframesize = bufsize * 3;	/* RGB size */
-	PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight);
-	PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize);
-
-	/* some default values */
-	stv680->bulk_in_endpointAddr = 0x82;
-	stv680->dropped = 0;
-	stv680->error = 0;
-	stv680->framecount = 0;
-	stv680->readcount = 0;
-	stv680->streaming = 0;
-	/* bright, white, colour, hue, contrast are set by software, not in stv0680 */
-	stv680->brightness = 32767;
-	stv680->chgbright = 0;
-	stv680->whiteness = 0;	/* only for greyscale */
-	stv680->colour = 32767;
-	stv680->contrast = 32767;
-	stv680->hue = 32767;
-	stv680->palette = STV_VIDEO_PALETTE;
-	stv680->depth = 24;	/* rgb24 bits */
-	if ((swapRGB_on == 0) && (swapRGB == 0))
-		PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
-	else if ((swapRGB_on == 0) && (swapRGB == 1))
-		PDEBUG (1, "STV(i): swapRGB is (auto) ON");
-	else if (swapRGB_on == 1)
-		PDEBUG (1, "STV(i): swapRGB is (forced) ON");
-	else if (swapRGB_on == -1)
-		PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
-
-	if (stv_set_video_mode (stv680) < 0) {
-		PDEBUG (0, "STV(e): Could not set video mode in stv_init");
-		return -1;
-	}
-
-	return 0;
-}
-
-/***************** last of pencam  routines  *******************/
-
-/****************************************************************************
- *  sysfs
- ***************************************************************************/
-#define stv680_file(name, variable, field)				\
-static ssize_t show_##name(struct device *class_dev,			\
-			   struct device_attribute *attr, char *buf)	\
-{									\
-	struct video_device *vdev = to_video_device(class_dev);		\
-	struct usb_stv *stv = video_get_drvdata(vdev);			\
-	return sprintf(buf, field, stv->variable);			\
-}									\
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
-
-stv680_file(model, camera_name, "%s\n");
-stv680_file(in_use, user, "%d\n");
-stv680_file(streaming, streaming, "%d\n");
-stv680_file(palette, palette, "%i\n");
-stv680_file(frames_total, readcount, "%d\n");
-stv680_file(frames_read, framecount, "%d\n");
-stv680_file(packets_dropped, dropped, "%d\n");
-stv680_file(decoding_errors, error, "%d\n");
-
-static int stv680_create_sysfs_files(struct video_device *vdev)
-{
-	int rc;
-
-	rc = device_create_file(&vdev->dev, &dev_attr_model);
-	if (rc) goto err;
-	rc = device_create_file(&vdev->dev, &dev_attr_in_use);
-	if (rc) goto err_model;
-	rc = device_create_file(&vdev->dev, &dev_attr_streaming);
-	if (rc) goto err_inuse;
-	rc = device_create_file(&vdev->dev, &dev_attr_palette);
-	if (rc) goto err_stream;
-	rc = device_create_file(&vdev->dev, &dev_attr_frames_total);
-	if (rc) goto err_pal;
-	rc = device_create_file(&vdev->dev, &dev_attr_frames_read);
-	if (rc) goto err_framtot;
-	rc = device_create_file(&vdev->dev, &dev_attr_packets_dropped);
-	if (rc) goto err_framread;
-	rc = device_create_file(&vdev->dev, &dev_attr_decoding_errors);
-	if (rc) goto err_dropped;
-
-	return 0;
-
-err_dropped:
-	device_remove_file(&vdev->dev, &dev_attr_packets_dropped);
-err_framread:
-	device_remove_file(&vdev->dev, &dev_attr_frames_read);
-err_framtot:
-	device_remove_file(&vdev->dev, &dev_attr_frames_total);
-err_pal:
-	device_remove_file(&vdev->dev, &dev_attr_palette);
-err_stream:
-	device_remove_file(&vdev->dev, &dev_attr_streaming);
-err_inuse:
-	device_remove_file(&vdev->dev, &dev_attr_in_use);
-err_model:
-	device_remove_file(&vdev->dev, &dev_attr_model);
-err:
-	PDEBUG(0, "STV(e): Could not create sysfs files");
-	return rc;
-}
-
-static void stv680_remove_sysfs_files(struct video_device *vdev)
-{
-	device_remove_file(&vdev->dev, &dev_attr_model);
-	device_remove_file(&vdev->dev, &dev_attr_in_use);
-	device_remove_file(&vdev->dev, &dev_attr_streaming);
-	device_remove_file(&vdev->dev, &dev_attr_palette);
-	device_remove_file(&vdev->dev, &dev_attr_frames_total);
-	device_remove_file(&vdev->dev, &dev_attr_frames_read);
-	device_remove_file(&vdev->dev, &dev_attr_packets_dropped);
-	device_remove_file(&vdev->dev, &dev_attr_decoding_errors);
-}
-
-/********************************************************************
- * Camera control
- *******************************************************************/
-
-static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p)
-{
-	/* This sets values for v4l interface. max/min = 65535/0  */
-
-	p->brightness = stv680->brightness;
-	p->whiteness = stv680->whiteness;	/* greyscale */
-	p->colour = stv680->colour;
-	p->contrast = stv680->contrast;
-	p->hue = stv680->hue;
-	p->palette = stv680->palette;
-	p->depth = stv680->depth;
-	return 0;
-}
-
-static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p)
-{
-	/* See above stv680_get_pict  */
-
-	if (p->palette != STV_VIDEO_PALETTE) {
-		PDEBUG (2, "STV(e): Palette set error in _set_pic");
-		return 1;
-	}
-
-	if (stv680->brightness != p->brightness) {
-		stv680->chgbright = 1;
-		stv680->brightness = p->brightness;
-	}
-
-	stv680->whiteness = p->whiteness;	/* greyscale */
-	stv680->colour = p->colour;
-	stv680->contrast = p->contrast;
-	stv680->hue = p->hue;
-	stv680->palette = p->palette;
-	stv680->depth = p->depth;
-
-	return 0;
-}
-
-static void stv680_video_irq (struct urb *urb)
-{
-	struct usb_stv *stv680 = urb->context;
-	int length = urb->actual_length;
-
-	if (length < stv680->rawbufsize)
-		PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length);
-
-	/* ohoh... */
-	if (!stv680->streaming)
-		return;
-
-	if (!stv680->udev) {
-		PDEBUG (0, "STV(e): device vapourished in video_irq");
-		return;
-	}
-
-	/* 0 sized packets happen if we are to fast, but sometimes the camera
-	   keeps sending them forever...
-	 */
-	if (length && !urb->status) {
-		stv680->nullpackets = 0;
-		switch (stv680->scratch[stv680->scratch_next].state) {
-		case BUFFER_READY:
-		case BUFFER_BUSY:
-			stv680->dropped++;
-			break;
-
-		case BUFFER_UNUSED:
-			memcpy (stv680->scratch[stv680->scratch_next].data,
-				(unsigned char *) urb->transfer_buffer, length);
-			stv680->scratch[stv680->scratch_next].state = BUFFER_READY;
-			stv680->scratch[stv680->scratch_next].length = length;
-			if (waitqueue_active (&stv680->wq)) {
-				wake_up_interruptible (&stv680->wq);
-			}
-			stv680->scratch_overflow = 0;
-			stv680->scratch_next++;
-			if (stv680->scratch_next >= STV680_NUMSCRATCH)
-				stv680->scratch_next = 0;
-			break;
-		}		/* switch  */
-	} else {
-		stv680->nullpackets++;
-		if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
-			if (waitqueue_active (&stv680->wq)) {
-				wake_up_interruptible (&stv680->wq);
-			}
-		}
-	}			/*  if - else */
-
-	/* Resubmit urb for new data */
-	urb->status = 0;
-	urb->dev = stv680->udev;
-	if (usb_submit_urb (urb, GFP_ATOMIC))
-		PDEBUG (0, "STV(e): urb burned down in video irq");
-	return;
-}				/*  _video_irq  */
-
-static int stv680_start_stream (struct usb_stv *stv680)
-{
-	struct urb *urb;
-	int err = 0, i;
-
-	stv680->streaming = 1;
-
-	/* Do some memory allocation */
-	for (i = 0; i < STV680_NUMFRAMES; i++) {
-		stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize;
-		stv680->frame[i].curpix = 0;
-	}
-	/* packet size = 4096  */
-	for (i = 0; i < STV680_NUMSBUF; i++) {
-		stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
-		if (stv680->sbuf[i].data == NULL) {
-			PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i);
-			goto nomem_err;
-		}
-	}
-
-	stv680->scratch_next = 0;
-	stv680->scratch_use = 0;
-	stv680->scratch_overflow = 0;
-	for (i = 0; i < STV680_NUMSCRATCH; i++) {
-		stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
-		if (stv680->scratch[i].data == NULL) {
-			PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i);
-			goto nomem_err;
-		}
-		stv680->scratch[i].state = BUFFER_UNUSED;
-	}
-
-	for (i = 0; i < STV680_NUMSBUF; i++) {
-		urb = usb_alloc_urb (0, GFP_KERNEL);
-		if (!urb)
-			goto nomem_err;
-
-		/* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */
-		usb_fill_bulk_urb (urb, stv680->udev,
-				   usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr),
-				   stv680->sbuf[i].data, stv680->rawbufsize,
-				   stv680_video_irq, stv680);
-		stv680->urb[i] = urb;
-		err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
-		if (err) {
-			PDEBUG (0, "STV(e): urb burned down with err "
-				   "%d in start stream %d", err, i);
-			goto nomem_err;
-		}
-	}			/* i STV680_NUMSBUF */
-
-	stv680->framecount = 0;
-	return 0;
-
- nomem_err:
-	for (i = 0; i < STV680_NUMSBUF; i++) {
-		usb_kill_urb(stv680->urb[i]);
-		usb_free_urb(stv680->urb[i]);
-		stv680->urb[i] = NULL;
-		kfree(stv680->sbuf[i].data);
-		stv680->sbuf[i].data = NULL;
-	}
-	/* used in irq, free only as all URBs are dead */
-	for (i = 0; i < STV680_NUMSCRATCH; i++) {
-		kfree(stv680->scratch[i].data);
-		stv680->scratch[i].data = NULL;
-	}
-	return -ENOMEM;
-
-}
-
-static int stv680_stop_stream (struct usb_stv *stv680)
-{
-	int i;
-
-	if (!stv680->streaming || !stv680->udev)
-		return 1;
-
-	stv680->streaming = 0;
-
-	for (i = 0; i < STV680_NUMSBUF; i++)
-		if (stv680->urb[i]) {
-			usb_kill_urb (stv680->urb[i]);
-			usb_free_urb (stv680->urb[i]);
-			stv680->urb[i] = NULL;
-			kfree(stv680->sbuf[i].data);
-		}
-	for (i = 0; i < STV680_NUMSCRATCH; i++) {
-		kfree(stv680->scratch[i].data);
-		stv680->scratch[i].data = NULL;
-	}
-
-	return 0;
-}
-
-static int stv680_set_size (struct usb_stv *stv680, int width, int height)
-{
-	int wasstreaming = stv680->streaming;
-
-	/* Check to see if we need to change */
-	if ((stv680->vwidth == width) && (stv680->vheight == height))
-		return 0;
-
-	PDEBUG (1, "STV(i): size request for %i x %i", width, height);
-	/* Check for a valid mode */
-	if ((!width || !height) || ((width & 1) || (height & 1))) {
-		PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
-		return 1;
-	}
-
-	if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) {
-		width = stv680->maxwidth / 2;
-		height = stv680->maxheight / 2;
-	} else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) {
-		width = 160;
-		height = 120;
-	} else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) {
-		width = 176;
-		height = 144;
-	} else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) {
-		width = 320;
-		height = 240;
-	} else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) {
-		width = 352;
-		height = 288;
-	} else {
-		PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
-		return 1;
-	}
-
-	/* Stop a current stream and start it again at the new size */
-	if (wasstreaming)
-		stv680_stop_stream (stv680);
-	stv680->vwidth = width;
-	stv680->vheight = height;
-	PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight);
-	if (wasstreaming)
-		stv680_start_stream (stv680);
-
-	return 0;
-}
-
-/**********************************************************************
- * Video Decoding
- **********************************************************************/
-
-/*******  routines from the pencam program; hey, they work!  ********/
-
-/*
- * STV0680 Vision Camera Chipset Driver
- * Copyright (C) 2000 Adam Harrison <adam@antispin.org>
-*/
-
-#define RED 0
-#define GREEN 1
-#define BLUE 2
-#define AD(x, y, w) (((y)*(w)+(x))*3)
-
-static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer)
-{
-	int x, y, i;
-	int w = stv680->cwidth;
-	int vw = stv680->cwidth, vh = stv680->cheight;
-	unsigned int p = 0;
-	int colour = 0, bayer = 0;
-	unsigned char *raw = buffer->data;
-	struct stv680_frame *frame = &stv680->frame[stv680->curframe];
-	unsigned char *output = frame->data;
-	unsigned char *temp = frame->data;
-	int offset = buffer->offset;
-
-	if (frame->curpix == 0) {
-		if (frame->grabstate == FRAME_READY) {
-			frame->grabstate = FRAME_GRABBING;
-		}
-	}
-	if (offset != frame->curpix) {	/* Regard frame as lost :( */
-		frame->curpix = 0;
-		stv680->error++;
-		return;
-	}
-
-	if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
-		vw = 320;
-		vh = 240;
-	}
-	if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
-		vw = 352;
-		vh = 288;
-	}
-
-	memset (output, 0, 3 * vw * vh);	/* clear output matrix. */
-
-	for (y = 0; y < vh; y++) {
-		for (x = 0; x < vw; x++) {
-			if (x & 1)
-				p = *(raw + y * w + (x >> 1));
-			else
-				p = *(raw + y * w + (x >> 1) + (w >> 1));
-
-			if (y & 1)
-				bayer = 2;
-			else
-				bayer = 0;
-			if (x & 1)
-				bayer++;
-
-			switch (bayer) {
-			case 0:
-			case 3:
-				colour = 1;
-				break;
-			case 1:
-				colour = 0;
-				break;
-			case 2:
-				colour = 2;
-				break;
-			}
-			i = (y * vw + x) * 3;
-			*(output + i + colour) = (unsigned char) p;
-		}		/* for x */
-
-	}			/* for y */
-
-	/****** gamma correction plus hardcoded white balance */
-	/* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code.
-	   Correction values red[], green[], blue[], are generated by
-	   (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255.
-	   White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and
-	   converted to unsigned char. Values are in stv680.h  */
-
-	for (y = 0; y < vh; y++) {
-		for (x = 0; x < vw; x++) {
-			i = (y * vw + x) * 3;
-			*(output + i) = red[*(output + i)];
-			*(output + i + 1) = green[*(output + i + 1)];
-			*(output + i + 2) = blue[*(output + i + 2)];
-		}
-	}
-
-	/******  bayer demosaic  ******/
-	for (y = 1; y < (vh - 1); y++) {
-		for (x = 1; x < (vw - 1); x++) {	/* work out pixel type */
-			if (y & 1)
-				bayer = 0;
-			else
-				bayer = 2;
-			if (!(x & 1))
-				bayer++;
-
-			switch (bayer) {
-			case 0:	/* green. blue lr, red tb */
-				*(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1;
-				*(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1;
-				break;
-
-			case 1:	/* blue. green lrtb, red diagonals */
-				*(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
-				*(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2;
-				break;
-
-			case 2:	/* red. green lrtb, blue diagonals */
-				*(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
-				*(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2;
-				break;
-
-			case 3:	/* green. red lr, blue tb */
-				*(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1;
-				*(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1;
-				break;
-			}	/* switch */
-		}		/* for x */
-	}			/* for y  - end demosaic  */
-
-	/* fix top and bottom row, left and right side */
-	i = vw * 3;
-	memcpy (output, (output + i), i);
-	memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
-	for (y = 0; y < vh; y++) {
-		i = y * vw * 3;
-		memcpy ((output + i), (output + i + 3), 3);
-		memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
-	}
-
-	/*  process all raw data, then trim to size if necessary */
-	if ((stv680->vwidth == 160) || (stv680->vwidth == 176))  {
-		i = 0;
-		for (y = 0; y < vh; y++) {
-			if (!(y & 1)) {
-				for (x = 0; x < vw; x++) {
-					p = (y * vw + x) * 3;
-					if (!(x & 1)) {
-						*(output + i) = *(output + p);
-						*(output + i + 1) = *(output + p + 1);
-						*(output + i + 2) = *(output + p + 2);
-						i += 3;
-					}
-				}  /* for x */
-			}
-		}  /* for y */
-	}
-	/* reset to proper width */
-	if ((stv680->vwidth == 160)) {
-		vw = 160;
-		vh = 120;
-	}
-	if ((stv680->vwidth == 176)) {
-		vw = 176;
-		vh = 144;
-	}
-
-	/* output is RGB; some programs want BGR  */
-	/* swapRGB_on=0 -> program decides;  swapRGB_on=1, always swap */
-	/* swapRGB_on=-1, never swap */
-	if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
-		for (y = 0; y < vh; y++) {
-			for (x = 0; x < vw; x++) {
-				i = (y * vw + x) * 3;
-				*(temp) = *(output + i);
-				*(output + i) = *(output + i + 2);
-				*(output + i + 2) = *(temp);
-			}
-		}
-	}
-	/* brightness */
-	if (stv680->chgbright == 1) {
-		if (stv680->brightness >= 32767) {
-			p = (stv680->brightness - 32767) / 256;
-			for (x = 0; x < (vw * vh * 3); x++) {
-				if ((*(output + x) + (unsigned char) p) > 255)
-					*(output + x) = 255;
-				else
-					*(output + x) += (unsigned char) p;
-			}	/* for */
-		} else {
-			p = (32767 - stv680->brightness) / 256;
-			for (x = 0; x < (vw * vh * 3); x++) {
-				if ((unsigned char) p > *(output + x))
-					*(output + x) = 0;
-				else
-					*(output + x) -= (unsigned char) p;
-			}	/* for */
-		}		/* else */
-	}
-	/* if */
-	frame->curpix = 0;
-	frame->curlinepix = 0;
-	frame->grabstate = FRAME_DONE;
-	stv680->framecount++;
-	stv680->readcount++;
-	if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) {
-		stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1);
-	}
-
-}				/* bayer_unshuffle */
-
-/*******  end routines from the pencam program  *********/
-
-static int stv680_newframe (struct usb_stv *stv680, int framenr)
-{
-	int errors = 0;
-
-	while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) {
-		if (!stv680->frame[framenr].curpix) {
-			errors++;
-		}
-		wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY));
-
-		if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
-			stv680->nullpackets = 0;
-			PDEBUG (2, "STV(i): too many null length packets, restarting capture");
-			stv680_stop_stream (stv680);
-			stv680_start_stream (stv680);
-		} else {
-			if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) {
-				stv680->frame[framenr].grabstate = FRAME_ERROR;
-				PDEBUG (2, "STV(e): FRAME_ERROR in _newframe");
-				return -EIO;
-			}
-			stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY;
-
-			bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]);
-
-			stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED;
-			stv680->scratch_use++;
-			if (stv680->scratch_use >= STV680_NUMSCRATCH)
-				stv680->scratch_use = 0;
-			if (errors > STV680_MAX_ERRORS) {
-				errors = 0;
-				PDEBUG (2, "STV(i): too many errors, restarting capture");
-				stv680_stop_stream (stv680);
-				stv680_start_stream (stv680);
-			}
-		}		/* else */
-	}			/* while */
-	return 0;
-}
-
-/*********************************************************************
- * Video4Linux
- *********************************************************************/
-
-static int stv_open(struct file *file)
-{
-	struct video_device *dev = video_devdata(file);
-	struct usb_stv *stv680 = video_get_drvdata(dev);
-	int err = 0;
-
-	/* we are called with the BKL held */
-	lock_kernel();
-	stv680->user = 1;
-	err = stv_init (stv680);	/* main initialization routine for camera */
-
-	if (err >= 0) {
-		stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES);
-		if (!stv680->fbuf) {
-			PDEBUG (0, "STV(e): Could not rvmalloc frame bufer");
-			err = -ENOMEM;
-		}
-		file->private_data = dev;
-	}
-	if (err)
-		stv680->user = 0;
-	unlock_kernel();
-
-	return err;
-}
-
-static int stv_close(struct file *file)
-{
-	struct video_device *dev = file->private_data;
-	struct usb_stv *stv680 = video_get_drvdata(dev);
-	int i;
-
-	for (i = 0; i < STV680_NUMFRAMES; i++)
-		stv680->frame[i].grabstate = FRAME_UNUSED;
-	if (stv680->streaming)
-		stv680_stop_stream (stv680);
-
-	if ((i = stv_stop_video (stv680)) < 0)
-		PDEBUG (1, "STV(e): stop_video failed in stv_close");
-
-	rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES);
-	stv680->user = 0;
-
-	if (stv680->removed) {
-		kfree(stv680);
-		stv680 = NULL;
-		PDEBUG (0, "STV(i): device unregistered");
-	}
-	file->private_data = NULL;
-	return 0;
-}
-
-static long stv680_do_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
-	struct video_device *vdev = file->private_data;
-	struct usb_stv *stv680 = video_get_drvdata(vdev);
-
-	if (!stv680->udev)
-		return -EIO;
-
-	switch (cmd) {
-	case VIDIOCGCAP:{
-			struct video_capability *b = arg;
-
-			strcpy (b->name, stv680->camera_name);
-			b->type = VID_TYPE_CAPTURE;
-			b->channels = 1;
-			b->audios = 0;
-			b->maxwidth = stv680->maxwidth;
-			b->maxheight = stv680->maxheight;
-			b->minwidth = stv680->maxwidth / 2;
-			b->minheight = stv680->maxheight / 2;
-			return 0;
-		}
-	case VIDIOCGCHAN:{
-			struct video_channel *v = arg;
-
-			if (v->channel != 0)
-				return -EINVAL;
-			v->flags = 0;
-			v->tuners = 0;
-			v->type = VIDEO_TYPE_CAMERA;
-			strcpy (v->name, "STV Camera");
-			return 0;
-		}
-	case VIDIOCSCHAN:{
-			struct video_channel *v = arg;
-			if (v->channel != 0)
-				return -EINVAL;
-			return 0;
-		}
-	case VIDIOCGPICT:{
-			struct video_picture *p = arg;
-
-			stv680_get_pict (stv680, p);
-			return 0;
-		}
-	case VIDIOCSPICT:{
-			struct video_picture *p = arg;
-
-			if (stv680_set_pict (stv680, p))
-				return -EINVAL;
-			return 0;
-		}
-	case VIDIOCSWIN:{
-			struct video_window *vw = arg;
-
-			if (vw->flags)
-				return -EINVAL;
-			if (vw->clipcount)
-				return -EINVAL;
-			if (vw->width != stv680->vwidth) {
-				if (stv680_set_size (stv680, vw->width, vw->height)) {
-					PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN");
-					return -EINVAL;
-				}
-			}
-			return 0;
-		}
-	case VIDIOCGWIN:{
-			struct video_window *vw = arg;
-
-			vw->x = 0;	/* FIXME */
-			vw->y = 0;
-			vw->chromakey = 0;
-			vw->flags = 0;
-			vw->clipcount = 0;
-			vw->width = stv680->vwidth;
-			vw->height = stv680->vheight;
-			return 0;
-		}
-	case VIDIOCGMBUF:{
-			struct video_mbuf *vm = arg;
-			int i;
-
-			memset (vm, 0, sizeof (*vm));
-			vm->size = STV680_NUMFRAMES * stv680->maxframesize;
-			vm->frames = STV680_NUMFRAMES;
-			for (i = 0; i < STV680_NUMFRAMES; i++)
-				vm->offsets[i] = stv680->maxframesize * i;
-			return 0;
-		}
-	case VIDIOCMCAPTURE:{
-			struct video_mmap *vm = arg;
-
-			if (vm->format != STV_VIDEO_PALETTE) {
-				PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
-					vm->format, STV_VIDEO_PALETTE);
-				if ((vm->format == 3) && (swapRGB_on == 0))  {
-					PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
-					/* this may fix those apps (e.g., xawtv) that want BGR */
-					swapRGB = 1;
-				}
-				return -EINVAL;
-			}
-			if (vm->frame >= STV680_NUMFRAMES) {
-				PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
-				return -EINVAL;
-			}
-			if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR)
-			    || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) {
-				PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
-					stv680->frame[vm->frame].grabstate);
-				return -EBUSY;
-			}
-			/* Is this according to the v4l spec??? */
-			if (stv680->vwidth != vm->width) {
-				if (stv680_set_size (stv680, vm->width, vm->height)) {
-					PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed");
-					return -EINVAL;
-				}
-			}
-			stv680->frame[vm->frame].grabstate = FRAME_READY;
-
-			if (!stv680->streaming)
-				stv680_start_stream (stv680);
-
-			return 0;
-		}
-	case VIDIOCSYNC:{
-			int *frame = arg;
-			int ret = 0;
-
-			if (*frame < 0 || *frame >= STV680_NUMFRAMES) {
-				PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC");
-				return -EINVAL;
-			}
-			ret = stv680_newframe (stv680, *frame);
-			stv680->frame[*frame].grabstate = FRAME_UNUSED;
-			return ret;
-		}
-	case VIDIOCGFBUF:{
-			struct video_buffer *vb = arg;
-
-			memset (vb, 0, sizeof (*vb));
-			return 0;
-		}
-	case VIDIOCKEY:
-		return 0;
-	case VIDIOCCAPTURE:
-		{
-			PDEBUG (2, "STV(e): VIDIOCCAPTURE failed");
-			return -EINVAL;
-		}
-	case VIDIOCSFBUF:
-	case VIDIOCGTUNER:
-	case VIDIOCSTUNER:
-	case VIDIOCGFREQ:
-	case VIDIOCSFREQ:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-		return -EINVAL;
-	default:
-		return -ENOIOCTLCMD;
-	}			/* end switch */
-
-	return 0;
-}
-
-static long stv680_ioctl(struct file *file,
-			unsigned int cmd, unsigned long arg)
-{
-	return video_usercopy(file, cmd, arg, stv680_do_ioctl);
-}
-
-static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
-{
-	struct video_device *dev = file->private_data;
-	struct usb_stv *stv680 = video_get_drvdata(dev);
-	unsigned long start = vma->vm_start;
-	unsigned long size  = vma->vm_end-vma->vm_start;
-	unsigned long page, pos;
-
-	mutex_lock(&stv680->lock);
-
-	if (stv680->udev == NULL) {
-		mutex_unlock(&stv680->lock);
-		return -EIO;
-	}
-	if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
-		    & ~(PAGE_SIZE - 1))) {
-		mutex_unlock(&stv680->lock);
-		return -EINVAL;
-	}
-	pos = (unsigned long) stv680->fbuf;
-	while (size > 0) {
-		page = vmalloc_to_pfn((void *)pos);
-		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			mutex_unlock(&stv680->lock);
-			return -EAGAIN;
-		}
-		start += PAGE_SIZE;
-		pos += PAGE_SIZE;
-		if (size > PAGE_SIZE)
-			size -= PAGE_SIZE;
-		else
-			size = 0;
-	}
-	mutex_unlock(&stv680->lock);
-
-	return 0;
-}
-
-static ssize_t stv680_read (struct file *file, char __user *buf,
-			size_t count, loff_t *ppos)
-{
-	struct video_device *dev = file->private_data;
-	unsigned long int realcount = count;
-	int ret = 0;
-	struct usb_stv *stv680 = video_get_drvdata(dev);
-	unsigned long int i;
-
-	if (STV680_NUMFRAMES != 2) {
-		PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!");
-		return -1;
-	}
-	if (stv680->udev == NULL)
-		return -EIO;
-	if (realcount > (stv680->vwidth * stv680->vheight * 3))
-		realcount = stv680->vwidth * stv680->vheight * 3;
-
-	/* Shouldn't happen: */
-	if (stv680->frame[0].grabstate == FRAME_GRABBING) {
-		PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read");
-		return -EBUSY;
-	}
-	stv680->frame[0].grabstate = FRAME_READY;
-	stv680->frame[1].grabstate = FRAME_UNUSED;
-	stv680->curframe = 0;
-
-	if (!stv680->streaming)
-		stv680_start_stream (stv680);
-
-	if (!stv680->streaming) {
-		ret = stv680_newframe (stv680, 0);	/* ret should = 0 */
-	}
-
-	ret = stv680_newframe (stv680, 0);
-
-	if (!ret) {
-		if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) {
-			PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i);
-			return -EFAULT;
-		}
-	} else {
-		realcount = ret;
-	}
-	stv680->frame[0].grabstate = FRAME_UNUSED;
-	return realcount;
-}				/* stv680_read */
-
-static const struct v4l2_file_operations stv680_fops = {
-	.owner =	THIS_MODULE,
-	.open =		stv_open,
-	.release =     	stv_close,
-	.read =		stv680_read,
-	.mmap =		stv680_mmap,
-	.ioctl =        stv680_ioctl,
-};
-static struct video_device stv680_template = {
-	.name =		"STV0680 USB camera",
-	.fops =         &stv680_fops,
-	.release =	video_device_release,
-};
-
-static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id)
-{
-	struct usb_device *dev = interface_to_usbdev(intf);
-	struct usb_host_interface *interface;
-	struct usb_stv *stv680 = NULL;
-	char *camera_name = NULL;
-	int retval = 0;
-
-	/* We don't handle multi-config cameras */
-	if (dev->descriptor.bNumConfigurations != 1) {
-		PDEBUG (0, "STV(e): Number of Configurations != 1");
-		return -ENODEV;
-	}
-
-	interface = &intf->altsetting[0];
-	/* Is it a STV680? */
-	if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) &&
-	    (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) {
-		camera_name = "STV0680";
-		PDEBUG (0, "STV(i): STV0680 camera found.");
-	} else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) &&
-		   (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) {
-		camera_name = "Creative WebCam Go Mini";
-		PDEBUG (0, "STV(i): Creative WebCam Go Mini found.");
-	} else {
-		PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values.");
-		PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer.");
-		retval = -ENODEV;
-		goto error;
-	}
-	/* We found one */
-	if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
-		PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
-		retval = -ENOMEM;
-		goto error;
-	}
-
-	stv680->udev = dev;
-	stv680->camera_name = camera_name;
-
-	stv680->vdev = video_device_alloc();
-	if (!stv680->vdev) {
-		retval = -ENOMEM;
-		goto error;
-	}
-	memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template));
-	stv680->vdev->parent = &intf->dev;
-	video_set_drvdata(stv680->vdev, stv680);
-
-	memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name));
-	init_waitqueue_head (&stv680->wq);
-	mutex_init (&stv680->lock);
-	wmb ();
-
-	if (video_register_device(stv680->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
-		PDEBUG (0, "STV(e): video_register_device failed");
-		retval = -EIO;
-		goto error_vdev;
-	}
-	PDEBUG(0, "STV(i): registered new video device: %s",
-		video_device_node_name(stv680->vdev));
-
-	usb_set_intfdata (intf, stv680);
-	retval = stv680_create_sysfs_files(stv680->vdev);
-	if (retval)
-		goto error_unreg;
-	return 0;
-
-error_unreg:
-	video_unregister_device(stv680->vdev);
-error_vdev:
-	video_device_release(stv680->vdev);
-error:
-	kfree(stv680);
-	return retval;
-}
-
-static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680)
-{
-	int i;
-
-	stv680->udev = NULL;
-	stv680->frame[0].grabstate = FRAME_ERROR;
-	stv680->frame[1].grabstate = FRAME_ERROR;
-	stv680->streaming = 0;
-
-	wake_up_interruptible (&stv680->wq);
-
-	for (i = 0; i < STV680_NUMSBUF; i++)
-		if (stv680->urb[i]) {
-			usb_kill_urb (stv680->urb[i]);
-			usb_free_urb (stv680->urb[i]);
-			stv680->urb[i] = NULL;
-			kfree(stv680->sbuf[i].data);
-		}
-	for (i = 0; i < STV680_NUMSCRATCH; i++)
-		kfree(stv680->scratch[i].data);
-	PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name);
-
-	/* Free the memory */
-	kfree(stv680);
-}
-
-static void stv680_disconnect (struct usb_interface *intf)
-{
-	struct usb_stv *stv680 = usb_get_intfdata (intf);
-
-	usb_set_intfdata (intf, NULL);
-
-	if (stv680) {
-		/* We don't want people trying to open up the device */
-		if (stv680->vdev) {
-			stv680_remove_sysfs_files(stv680->vdev);
-			video_unregister_device(stv680->vdev);
-			stv680->vdev = NULL;
-		}
-		if (!stv680->user) {
-			usb_stv680_remove_disconnected (stv680);
-		} else {
-			stv680->removed = 1;
-		}
-	}
-}
-
-static struct usb_driver stv680_driver = {
-	.name =		"stv680",
-	.probe =	stv680_probe,
-	.disconnect =	stv680_disconnect,
-	.id_table =	device_table
-};
-
-/********************************************************************
- *  Module routines
- ********************************************************************/
-
-static int __init usb_stv680_init (void)
-{
-	if (usb_register (&stv680_driver) < 0) {
-		PDEBUG (0, "STV(e): Could not setup STV0680 driver");
-		return -1;
-	}
-	PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION);
-
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-	return 0;
-}
-
-static void __exit usb_stv680_exit (void)
-{
-	usb_deregister (&stv680_driver);
-	PDEBUG (0, "STV(i): driver deregistered");
-}
-
-module_init (usb_stv680_init);
-module_exit (usb_stv680_exit);
diff --git a/drivers/media/video/stv680.h b/drivers/media/video/stv680.h
deleted file mode 100644
index a08f1b0..0000000
--- a/drivers/media/video/stv680.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/****************************************************************************
- *
- *  Filename: stv680.h
- *
- *  Description:
- *     This is a USB driver for STV0680 based usb video cameras.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- ****************************************************************************/
-
-/* size of usb transfers */
-#define STV680_PACKETSIZE	4096
-
-/* number of queued bulk transfers to use, may have problems if > 1 */
-#define STV680_NUMSBUF		1
-
-/* number of frames supported by the v4l part */
-#define STV680_NUMFRAMES	2
-
-/* scratch buffers for passing data to the decoders: 2 or 4 are good */
-#define STV680_NUMSCRATCH	2
-
-/* number of nul sized packets to receive before kicking the camera */
-#define STV680_MAX_NULLPACKETS	200
-
-/* number of decoding errors before kicking the camera */
-#define STV680_MAX_ERRORS	100
-
-#define USB_PENCAM_VENDOR_ID	0x0553
-#define USB_PENCAM_PRODUCT_ID	0x0202
-
-#define USB_CREATIVEGOMINI_VENDOR_ID	0x041e
-#define USB_CREATIVEGOMINI_PRODUCT_ID	0x4007
-
-#define PENCAM_TIMEOUT          1000
-/* fmt 4 */
-#define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
-
-static struct usb_device_id device_table[] = {
-	{USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
-	{USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)},
-	{}
-};
-MODULE_DEVICE_TABLE (usb, device_table);
-
-struct stv680_sbuf {
-	unsigned char *data;
-};
-
-enum {
-	FRAME_UNUSED,		/* Unused (no MCAPTURE) */
-	FRAME_READY,		/* Ready to start grabbing */
-	FRAME_GRABBING,		/* In the process of being grabbed into */
-	FRAME_DONE,		/* Finished grabbing, but not been synced yet */
-	FRAME_ERROR,		/* Something bad happened while processing */
-};
-
-enum {
-	BUFFER_UNUSED,
-	BUFFER_READY,
-	BUFFER_BUSY,
-	BUFFER_DONE,
-};
-
-/* raw camera data <- sbuf (urb transfer buf) */
-struct stv680_scratch {
-	unsigned char *data;
-	volatile int state;
-	int offset;
-	int length;
-};
-
-/* processed data for display ends up here, after bayer */
-struct stv680_frame {
-	unsigned char *data;	/* Frame buffer */
-	volatile int grabstate;	/* State of grabbing */
-	unsigned char *curline;
-	int curlinepix;
-	int curpix;
-};
-
-/* this is almost the video structure uvd_t, with extra parameters for stv */
-struct usb_stv {
-	struct video_device *vdev;
-
-	struct usb_device *udev;
-
-	unsigned char bulk_in_endpointAddr;	/* __u8  the address of the bulk in endpoint */
-	char *camera_name;
-
-	unsigned int VideoMode;	/* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */
-	int SupportedModes;
-	int CIF;
-	int VGA;
-	int QVGA;
-	int cwidth;		/* camera width */
-	int cheight;		/* camera height */
-	int maxwidth;		/* max video width */
-	int maxheight;		/* max video height */
-	int vwidth;		/* current width for video window */
-	int vheight;		/* current height for video window */
-	unsigned long int rawbufsize;
-	unsigned long int maxframesize;	/* rawbufsize * 3 for RGB */
-
-	int origGain;
-	int origMode;		/* original camera mode */
-
-	struct mutex lock;	/* to lock the structure */
-	int user;		/* user count for exclusive use */
-	int removed;		/* device disconnected */
-	int streaming;		/* Are we streaming video? */
-	char *fbuf;		/* Videodev buffer area */
-	struct urb *urb[STV680_NUMSBUF];	/* # of queued bulk transfers */
-	int curframe;		/* Current receiving frame */
-	struct stv680_frame frame[STV680_NUMFRAMES];	/* # frames supported by v4l part */
-	int readcount;
-	int framecount;
-	int error;
-	int dropped;
-	int scratch_next;
-	int scratch_use;
-	int scratch_overflow;
-	struct stv680_scratch scratch[STV680_NUMSCRATCH];	/* for decoders */
-	struct stv680_sbuf sbuf[STV680_NUMSBUF];
-
-	unsigned int brightness;
-	unsigned int chgbright;
-	unsigned int whiteness;
-	unsigned int colour;
-	unsigned int contrast;
-	unsigned int hue;
-	unsigned int palette;
-	unsigned int depth;	/* rgb24 in bits */
-
-	wait_queue_head_t wq;	/* Processes waiting */
-
-	int nullpackets;
-};
-
-
-static const unsigned char red[256] = {
-	0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
-	18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42,
-	44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69,
-	71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87,
-	88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101,
-	102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
-	114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124,
-	125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134,
-	134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143,
-	143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151,
-	152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159,
-	159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166,
-	167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173,
-	173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179,
-	180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186,
-	187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192,
-	192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197,
-	198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204,
-	204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209,
-	209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215,
-	215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219,
-	220, 220, 221, 221
-};
-
-static const unsigned char green[256] = {
-	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
-	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
-	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
-	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
-	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
-	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
-	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
-	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
-	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
-	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
-	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
-	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
-	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
-	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
-	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
-	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
-	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
-	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
-	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
-	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
-	245, 245, 246, 246
-};
-
-static const unsigned char blue[256] = {
-	0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
-	23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51,
-	55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84,
-	86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106,
-	107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124,
-	125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138,
-	139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151,
-	152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163,
-	165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174,
-	176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184,
-	185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194,
-	194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203,
-	204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212,
-	212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220,
-	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
-	228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235,
-	235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242,
-	243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249,
-	249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255
-};
diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/video/tlg2300/pd-main.c
index 256cc55..4555f4a 100644
--- a/drivers/media/video/tlg2300/pd-main.c
+++ b/drivers/media/video/tlg2300/pd-main.c
@@ -227,12 +227,11 @@
 
 	fwlength = fw->size;
 
-	fwbuf = kzalloc(fwlength, GFP_KERNEL);
+	fwbuf = kmemdup(fw->data, fwlength, GFP_KERNEL);
 	if (!fwbuf) {
 		ret = -ENOMEM;
 		goto out;
 	}
-	memcpy(fwbuf, fw->data, fwlength);
 
 	max_packet_size = udev->ep_out[0x1]->desc.wMaxPacketSize;
 	log("\t\t download size : %d", (int)max_packet_size);
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index 445dc93..a727962 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -768,7 +768,7 @@
 
 	mf->width	= priv->scale->width;
 	mf->height	= priv->scale->height;
-	mf->code	= V4L2_MBUS_FMT_YUYV8_2X8_BE;
+	mf->code	= V4L2_MBUS_FMT_UYVY8_2X8;
 	mf->colorspace	= V4L2_COLORSPACE_JPEG;
 	mf->field	= V4L2_FIELD_INTERLACED_BT;
 
@@ -797,7 +797,7 @@
 	/*
 	 * check color format
 	 */
-	if (mf->code != V4L2_MBUS_FMT_YUYV8_2X8_BE)
+	if (mf->code != V4L2_MBUS_FMT_UYVY8_2X8)
 		return -EINVAL;
 
 	mf->colorspace = V4L2_COLORSPACE_JPEG;
@@ -824,7 +824,7 @@
 		return -EINVAL;
 	}
 
-	mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+	mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
 	mf->colorspace = V4L2_COLORSPACE_JPEG;
 
 	/*
@@ -909,7 +909,7 @@
 	if (index)
 		return -EINVAL;
 
-	*code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+	*code = V4L2_MBUS_FMT_UYVY8_2X8;
 	return 0;
 }
 
diff --git a/drivers/media/video/usbvideo/Kconfig b/drivers/media/video/usbvideo/Kconfig
index adb1c04..d6e1695 100644
--- a/drivers/media/video/usbvideo/Kconfig
+++ b/drivers/media/video/usbvideo/Kconfig
@@ -37,17 +37,3 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called konicawc.
 
-config USB_QUICKCAM_MESSENGER
-	tristate "USB Logitech Quickcam Messenger (DEPRECATED)"
-	depends on VIDEO_V4L1
-	select VIDEO_USBVIDEO
-	---help---
-	  This driver is DEPRECATED please use the gspca stv06xx module
-	  instead.
-
-	  Say Y or M here to enable support for the USB Logitech Quickcam
-	  Messenger webcam.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called quickcam_messenger.
-
diff --git a/drivers/media/video/usbvideo/Makefile b/drivers/media/video/usbvideo/Makefile
index 4a1b144..bb52eb8 100644
--- a/drivers/media/video/usbvideo/Makefile
+++ b/drivers/media/video/usbvideo/Makefile
@@ -2,4 +2,3 @@
 obj-$(CONFIG_USB_IBMCAM)        += ibmcam.o ultracam.o
 obj-$(CONFIG_USB_KONICAWC)      += konicawc.o
 obj-$(CONFIG_USB_VICAM)         += vicam.o
-obj-$(CONFIG_USB_QUICKCAM_MESSENGER)	+= quickcam_messenger.o
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
deleted file mode 100644
index fbd665f..0000000
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ /dev/null
@@ -1,1126 +0,0 @@
-/*
- * Driver for Logitech Quickcam Messenger usb video camera
- * Copyright (C) Jaya Kumar
- *
- * This work was sponsored by CIS(M) Sdn Bhd.
- * History:
- * 05/08/2006 - Jaya Kumar
- * I wrote this based on the konicawc by Simon Evans.
- * -
- * Full credit for reverse engineering and creating an initial
- * working linux driver for the VV6422 goes to the qce-ga project by
- * Tuukka Toivonen, Jochen Hoenicke, Peter McConnell,
- * Cristiano De Michele, Georg Acher, Jean-Frederic Clere as well as
- * others.
- * ---
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/usb/input.h>
-#include <linux/slab.h>
-
-#include "usbvideo.h"
-#include "quickcam_messenger.h"
-
-/*
- * Version Information
- */
-
-#ifdef CONFIG_USB_DEBUG
-static int debug;
-#define DEBUG(n, format, arg...) \
-	if (n <= debug) {	 \
-		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \
-	}
-#else
-#define DEBUG(n, arg...)
-static const int debug;
-#endif
-
-#define DRIVER_VERSION "v0.01"
-#define DRIVER_DESC "Logitech Quickcam Messenger USB"
-
-#define USB_LOGITECH_VENDOR_ID	0x046D
-#define USB_QCM_PRODUCT_ID	0x08F0
-
-#define MAX_CAMERAS	1
-
-#define MAX_COLOUR	32768
-#define MAX_HUE		32768
-#define MAX_BRIGHTNESS	32768
-#define MAX_CONTRAST	32768
-#define MAX_WHITENESS	32768
-
-static int size = SIZE_320X240;
-static int colour = MAX_COLOUR;
-static int hue = MAX_HUE;
-static int brightness =	MAX_BRIGHTNESS;
-static int contrast =	MAX_CONTRAST;
-static int whiteness =	MAX_WHITENESS;
-
-static struct usbvideo *cams;
-
-static struct usb_device_id qcm_table [] = {
-	{ USB_DEVICE(USB_LOGITECH_VENDOR_ID, USB_QCM_PRODUCT_ID) },
-	{ }
-};
-MODULE_DEVICE_TABLE(usb, qcm_table);
-
-#ifdef CONFIG_INPUT
-static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
-{
-	struct input_dev *input_dev;
-	int error;
-
-	usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
-	strlcat(cam->input_physname, "/input0", sizeof(cam->input_physname));
-
-	cam->input = input_dev = input_allocate_device();
-	if (!input_dev) {
-		dev_warn(&dev->dev, "insufficient mem for cam input device\n");
-		return;
-	}
-
-	input_dev->name = "QCM button";
-	input_dev->phys = cam->input_physname;
-	usb_to_input_id(dev, &input_dev->id);
-	input_dev->dev.parent = &dev->dev;
-
-	input_dev->evbit[0] = BIT_MASK(EV_KEY);
-	input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
-
-	error = input_register_device(cam->input);
-	if (error) {
-		dev_warn(&dev->dev,
-			 "Failed to register camera's input device, err: %d\n",
-			 error);
-		input_free_device(cam->input);
-		cam->input = NULL;
-	}
-}
-
-static void qcm_unregister_input(struct qcm *cam)
-{
-	if (cam->input) {
-		input_unregister_device(cam->input);
-		cam->input = NULL;
-	}
-}
-
-static void qcm_report_buttonstat(struct qcm *cam)
-{
-	if (cam->input) {
-		input_report_key(cam->input, KEY_CAMERA, cam->button_sts);
-		input_sync(cam->input);
-	}
-}
-
-static void qcm_int_irq(struct urb *urb)
-{
-	int ret;
-	struct uvd *uvd = urb->context;
-	struct qcm *cam;
-
-	if (!CAMERA_IS_OPERATIONAL(uvd))
-		return;
-
-	if (!uvd->streaming)
-		return;
-
-	uvd->stats.urb_count++;
-
-	if (urb->status < 0)
-		uvd->stats.iso_err_count++;
-	else {
-		if (urb->actual_length > 0 ) {
-			cam = (struct qcm *) uvd->user_data;
-			if (cam->button_sts_buf == 0x88)
-				cam->button_sts = 0x0;
-			else if (cam->button_sts_buf == 0x80)
-				cam->button_sts = 0x1;
-			qcm_report_buttonstat(cam);
-		}
-	}
-
-	ret = usb_submit_urb(urb, GFP_ATOMIC);
-	if (ret < 0)
-		err("usb_submit_urb error (%d)", ret);
-}
-
-static int qcm_setup_input_int(struct qcm *cam, struct uvd *uvd)
-{
-	int errflag;
-	usb_fill_int_urb(cam->button_urb, uvd->dev,
-			usb_rcvintpipe(uvd->dev, uvd->video_endp + 1),
-			&cam->button_sts_buf,
-			1,
-			qcm_int_irq,
-			uvd, 16);
-
-	errflag = usb_submit_urb(cam->button_urb, GFP_KERNEL);
-	if (errflag)
-		err ("usb_submit_int ret %d", errflag);
-	return errflag;
-}
-
-static void qcm_stop_int_data(struct qcm *cam)
-{
-	usb_kill_urb(cam->button_urb);
-}
-
-static int qcm_alloc_int_urb(struct qcm *cam)
-{
-	cam->button_urb = usb_alloc_urb(0, GFP_KERNEL);
-
-	if (!cam->button_urb)
-		return -ENOMEM;
-
-	return 0;
-}
-
-static void qcm_free_int(struct qcm *cam)
-{
-	usb_free_urb(cam->button_urb);
-}
-#endif /* CONFIG_INPUT */
-
-static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val)
-{
-	int ret;
-
-	/* we'll wait up to 3 slices but no more */
-	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-		reg, 0, &val, 1, 3*HZ);
-	return ret;
-}
-
-static int qcm_stv_setw(struct usb_device *dev, u16 reg, __le16 val)
-{
-	int ret;
-
-	/* we'll wait up to 3 slices but no more */
-	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-		reg, 0, &val, 2, 3*HZ);
-	return ret;
-}
-
-static int qcm_stv_getw(struct usb_device *dev, unsigned short reg,
-							__le16 *val)
-{
-	int ret;
-
-	/* we'll wait up to 3 slices but no more */
-	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-		0x04, USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
-		reg, 0, val, 2, 3*HZ);
-	return ret;
-}
-
-static int qcm_camera_on(struct uvd *uvd)
-{
-	int ret;
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x01));
-	return 0;
-}
-
-static int qcm_camera_off(struct uvd *uvd)
-{
-	int ret;
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
-	return 0;
-}
-
-static void qcm_hsv2rgb(u16 hue, u16 sat, u16 val, u16 *r, u16 *g, u16 *b)
-{
-	unsigned int segment, valsat;
-	signed int   h = (signed int) hue;
-	unsigned int s = (sat - 32768) * 2;	/* rescale */
-	unsigned int v = val;
-	unsigned int p;
-
-	/*
-	the registers controlling gain are 8 bit of which
-	we affect only the last 4 bits with our gain.
-	we know that if saturation is 0, (unsaturated) then
-	we're grayscale (center axis of the colour cone) so
-	we set rgb=value. we use a formula obtained from
-	wikipedia to map the cone to the RGB plane. it's
-	as follows for the human value case of h=0..360,
-	s=0..1, v=0..1
-	h_i = h/60 % 6 , f = h/60 - h_i , p = v(1-s)
-	q = v(1 - f*s) , t = v(1 - (1-f)s)
-	h_i==0 => r=v , g=t, b=p
-	h_i==1 => r=q , g=v, b=p
-	h_i==2 => r=p , g=v, b=t
-	h_i==3 => r=p , g=q, b=v
-	h_i==4 => r=t , g=p, b=v
-	h_i==5 => r=v , g=p, b=q
-	the bottom side (the point) and the stuff just up
-	of that is black so we simplify those two cases.
-	*/
-	if (sat < 32768) {
-		/* anything less than this is unsaturated */
-		*r = val;
-		*g = val;
-		*b = val;
-		return;
-	}
-	if (val <= (0xFFFF/8)) {
-		/* anything less than this is black */
-		*r = 0;
-		*g = 0;
-		*b = 0;
-		return;
-	}
-
-	/* the rest of this code is copying tukkat's
-	implementation of the hsv2rgb conversion as taken
-	from qc-usb-messenger code. the 10923 is 0xFFFF/6
-	to divide the cone into 6 sectors.  */
-
-	segment = (h + 10923) & 0xFFFF;
-	segment = segment*3 >> 16;		/* 0..2: 0=R, 1=G, 2=B */
-	hue -= segment * 21845;			/* -10923..10923 */
-	h = hue;
-	h *= 3;
-	valsat = v*s >> 16;			/* 0..65534 */
-	p = v - valsat;
-	if (h >= 0) {
-		unsigned int t = v - (valsat * (32769 - h) >> 15);
-		switch (segment) {
-		case 0:	/* R-> */
-			*r = v;
-			*g = t;
-			*b = p;
-			break;
-		case 1:	/* G-> */
-			*r = p;
-			*g = v;
-			*b = t;
-			break;
-		case 2:	/* B-> */
-			*r = t;
-			*g = p;
-			*b = v;
-			break;
-		}
-	} else {
-		unsigned int q = v - (valsat * (32769 + h) >> 15);
-		switch (segment) {
-		case 0:	/* ->R */
-			*r = v;
-			*g = p;
-			*b = q;
-			break;
-		case 1:	/* ->G */
-			*r = q;
-			*g = v;
-			*b = p;
-			break;
-		case 2:	/* ->B */
-			*r = p;
-			*g = q;
-			*b = v;
-			break;
-		}
-	}
-}
-
-static int qcm_sensor_set_gains(struct uvd *uvd, u16 hue,
-	u16 saturation, u16 value)
-{
-	int ret;
-	u16 r=0,g=0,b=0;
-
-	/* this code is based on qc-usb-messenger */
-	qcm_hsv2rgb(hue, saturation, value, &r, &g, &b);
-
-	r >>= 12;
-	g >>= 12;
-	b >>= 12;
-
-	/* min val is 8 */
-	r = max((u16) 8, r);
-	g = max((u16) 8, g);
-	b = max((u16) 8, b);
-
-	r |= 0x30;
-	g |= 0x30;
-	b |= 0x30;
-
-	/* set the r,g,b gain registers */
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x0509, r));
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050A, g));
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050B, b));
-
-	/* doing as qc-usb did */
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050C, 0x2A));
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050D, 0x01));
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
-
-	return 0;
-}
-
-static int qcm_sensor_set_exposure(struct uvd *uvd, int exposure)
-{
-	int ret;
-	int formedval;
-
-	/* calculation was from qc-usb-messenger driver */
-	formedval = ( exposure >> 12 );
-
-	/* max value for formedval is 14 */
-	formedval = min(formedval, 14);
-
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev,
-			0x143A, 0xF0 | formedval));
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
-	return 0;
-}
-
-static int qcm_sensor_setlevels(struct uvd *uvd, int brightness, int contrast,
-					int hue, int colour)
-{
-	int ret;
-	/* brightness is exposure, contrast is gain, colour is saturation */
-	CHECK_RET(ret,
-		qcm_sensor_set_exposure(uvd, brightness));
-	CHECK_RET(ret, qcm_sensor_set_gains(uvd, hue, colour, contrast));
-
-	return 0;
-}
-
-static int qcm_sensor_setsize(struct uvd *uvd, u8 size)
-{
-	int ret;
-
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x1505, size));
-	return 0;
-}
-
-static int qcm_sensor_set_shutter(struct uvd *uvd, int whiteness)
-{
-	int ret;
-	/* some rescaling as done by the qc-usb-messenger code */
-	if (whiteness > 0xC000)
-		whiteness = 0xC000 + (whiteness & 0x3FFF)*8;
-
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143D,
-				(whiteness >> 8) & 0xFF));
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143E,
-				(whiteness >> 16) & 0x03));
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
-
-	return 0;
-}
-
-static int qcm_sensor_init(struct uvd *uvd)
-{
-	struct qcm *cam = (struct qcm *) uvd->user_data;
-	int ret;
-	int i;
-
-	for (i=0; i < ARRAY_SIZE(regval_table) ; i++) {
-		CHECK_RET(ret, qcm_stv_setb(uvd->dev,
-					regval_table[i].reg,
-					regval_table[i].val));
-	}
-
-	CHECK_RET(ret, qcm_stv_setw(uvd->dev, 0x15c1,
-				cpu_to_le16(ISOC_PACKET_SIZE)));
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x15c3, 0x08));
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143f, 0x01));
-
-	CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
-
-	CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
-
-	CHECK_RET(ret, qcm_sensor_setlevels(uvd, uvd->vpic.brightness,
-			uvd->vpic.contrast, uvd->vpic.hue, uvd->vpic.colour));
-
-	CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
-	CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
-
-	return 0;
-}
-
-static int qcm_set_camera_size(struct uvd *uvd)
-{
-	int ret;
-	struct qcm *cam = (struct qcm *) uvd->user_data;
-
-	CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
-	cam->width = camera_sizes[cam->size].width;
-	cam->height = camera_sizes[cam->size].height;
-	uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-
-	return 0;
-}
-
-static int qcm_setup_on_open(struct uvd *uvd)
-{
-	int ret;
-
-	CHECK_RET(ret, qcm_sensor_set_gains(uvd, uvd->vpic.hue,
-				uvd->vpic.colour, uvd->vpic.contrast));
-	CHECK_RET(ret, qcm_sensor_set_exposure(uvd, uvd->vpic.brightness));
-	CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
-	CHECK_RET(ret, qcm_set_camera_size(uvd));
-	CHECK_RET(ret, qcm_camera_on(uvd));
-	return 0;
-}
-
-static void qcm_adjust_picture(struct uvd *uvd)
-{
-	int ret;
-	struct qcm *cam = (struct qcm *) uvd->user_data;
-
-	ret = qcm_camera_off(uvd);
-	if (ret) {
-		err("can't turn camera off. abandoning pic adjustment");
-		return;
-	}
-
-	/* if there's been a change in contrast, hue, or
-	colour then we need to recalculate hsv in order
-	to update gains */
-	if ((cam->contrast != uvd->vpic.contrast) ||
-		(cam->hue != uvd->vpic.hue) ||
-		(cam->colour != uvd->vpic.colour)) {
-		cam->contrast = uvd->vpic.contrast;
-		cam->hue = uvd->vpic.hue;
-		cam->colour = uvd->vpic.colour;
-		ret = qcm_sensor_set_gains(uvd, cam->hue, cam->colour,
-						cam->contrast);
-		if (ret) {
-			err("can't set gains. abandoning pic adjustment");
-			return;
-		}
-	}
-
-	if (cam->brightness != uvd->vpic.brightness) {
-		cam->brightness = uvd->vpic.brightness;
-		ret = qcm_sensor_set_exposure(uvd, cam->brightness);
-		if (ret) {
-			err("can't set exposure. abandoning pic adjustment");
-			return;
-		}
-	}
-
-	if (cam->whiteness != uvd->vpic.whiteness) {
-		cam->whiteness = uvd->vpic.whiteness;
-		qcm_sensor_set_shutter(uvd, cam->whiteness);
-		if (ret) {
-			err("can't set shutter. abandoning pic adjustment");
-			return;
-		}
-	}
-
-	ret = qcm_camera_on(uvd);
-	if (ret) {
-		err("can't reenable camera. pic adjustment failed");
-		return;
-	}
-}
-
-static int qcm_process_frame(struct uvd *uvd, u8 *cdata, int framelen)
-{
-	int datalen;
-	int totaldata;
-	struct framehdr {
-		__be16 id;
-		__be16 len;
-	};
-	struct framehdr *fhdr;
-
-	totaldata = 0;
-	while (framelen) {
-		fhdr = (struct framehdr *) cdata;
-		datalen = be16_to_cpu(fhdr->len);
-		framelen -= 4;
-		cdata += 4;
-
-		if ((fhdr->id) == cpu_to_be16(0x8001)) {
-			RingQueue_Enqueue(&uvd->dp, marker, 4);
-			totaldata += 4;
-			continue;
-		}
-		if ((fhdr->id & cpu_to_be16(0xFF00)) == cpu_to_be16(0x0200)) {
-			RingQueue_Enqueue(&uvd->dp, cdata, datalen);
-			totaldata += datalen;
-		}
-		framelen -= datalen;
-		cdata += datalen;
-	}
-	return totaldata;
-}
-
-static int qcm_compress_iso(struct uvd *uvd, struct urb *dataurb)
-{
-	int totlen;
-	int i;
-	unsigned char *cdata;
-
-	totlen=0;
-	for (i = 0; i < dataurb->number_of_packets; i++) {
-		int n = dataurb->iso_frame_desc[i].actual_length;
-		int st = dataurb->iso_frame_desc[i].status;
-
-		cdata = dataurb->transfer_buffer +
-			dataurb->iso_frame_desc[i].offset;
-
-		if (st < 0) {
-			dev_warn(&uvd->dev->dev,
-				 "Data error: packet=%d. len=%d. status=%d.\n",
-				 i, n, st);
-			uvd->stats.iso_err_count++;
-			continue;
-		}
-		if (!n)
-			continue;
-
-		totlen += qcm_process_frame(uvd, cdata, n);
-	}
-	return totlen;
-}
-
-static void resubmit_urb(struct uvd *uvd, struct urb *urb)
-{
-	int ret;
-
-	urb->dev = uvd->dev;
-	ret = usb_submit_urb(urb, GFP_ATOMIC);
-	if (ret)
-		err("usb_submit_urb error (%d)", ret);
-}
-
-static void qcm_isoc_irq(struct urb *urb)
-{
-	int len;
-	struct uvd *uvd = urb->context;
-
-	if (!CAMERA_IS_OPERATIONAL(uvd))
-		return;
-
-	if (!uvd->streaming)
-		return;
-
-	uvd->stats.urb_count++;
-
-	if (!urb->actual_length) {
-		resubmit_urb(uvd, urb);
-		return;
-	}
-
-	len = qcm_compress_iso(uvd, urb);
-	resubmit_urb(uvd, urb);
-	uvd->stats.urb_length = len;
-	uvd->stats.data_count += len;
-	if (len)
-		RingQueue_WakeUpInterruptible(&uvd->dp);
-}
-
-static int qcm_start_data(struct uvd *uvd)
-{
-	struct qcm *cam = (struct qcm *) uvd->user_data;
-	int i;
-	int errflag;
-	int pktsz;
-	int err;
-
-	pktsz = uvd->iso_packet_len;
-	if (!CAMERA_IS_OPERATIONAL(uvd)) {
-		err("Camera is not operational");
-		return -EFAULT;
-	}
-
-	err = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltActive);
-	if (err < 0) {
-		err("usb_set_interface error");
-		uvd->last_error = err;
-		return -EBUSY;
-	}
-
-	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-		int j, k;
-		struct urb *urb = uvd->sbuf[i].urb;
-		urb->dev = uvd->dev;
-		urb->context = uvd;
-		urb->pipe = usb_rcvisocpipe(uvd->dev, uvd->video_endp);
-		urb->interval = 1;
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->transfer_buffer = uvd->sbuf[i].data;
-		urb->complete = qcm_isoc_irq;
-		urb->number_of_packets = FRAMES_PER_DESC;
-		urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
-		for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
-			urb->iso_frame_desc[j].offset = k;
-			urb->iso_frame_desc[j].length = pktsz;
-		}
-	}
-
-	uvd->streaming = 1;
-	uvd->curframe = -1;
-	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-		errflag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
-		if (errflag)
-			err ("usb_submit_isoc(%d) ret %d", i, errflag);
-	}
-
-	CHECK_RET(err, qcm_setup_input_int(cam, uvd));
-	CHECK_RET(err, qcm_camera_on(uvd));
-	return 0;
-}
-
-static void qcm_stop_data(struct uvd *uvd)
-{
-	struct qcm *cam;
-	int i, j;
-	int ret;
-
-	if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
-		return;
-	cam = (struct qcm *) uvd->user_data;
-
-	ret = qcm_camera_off(uvd);
-	if (ret)
-		dev_warn(&uvd->dev->dev, "couldn't turn the cam off.\n");
-
-	uvd->streaming = 0;
-
-	/* Unschedule all of the iso td's */
-	for (i=0; i < USBVIDEO_NUMSBUF; i++)
-		usb_kill_urb(uvd->sbuf[i].urb);
-
-	qcm_stop_int_data(cam);
-
-	if (!uvd->remove_pending) {
-		/* Set packet size to 0 */
-		j = usb_set_interface(uvd->dev, uvd->iface,
-					uvd->ifaceAltInactive);
-		if (j < 0) {
-			err("usb_set_interface() error %d.", j);
-			uvd->last_error = j;
-		}
-	}
-}
-
-static void qcm_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
-{
-	struct qcm *cam = (struct qcm *) uvd->user_data;
-	int x;
-	struct rgb *rgbL0;
-	struct rgb *rgbL1;
-	struct bayL0 *bayL0;
-	struct bayL1 *bayL1;
-	int hor,ver,hordel,verdel;
-	assert(frame != NULL);
-
-	switch (cam->size) {
-	case SIZE_160X120:
-		hor = 162; ver = 124; hordel = 1; verdel = 2;
-		break;
-	case SIZE_320X240:
-	default:
-		hor = 324; ver = 248; hordel = 2; verdel = 4;
-		break;
-	}
-
-	if (frame->scanstate == ScanState_Scanning) {
-		while (RingQueue_GetLength(&uvd->dp) >=
-			 4 + (hor*verdel + hordel)) {
-			if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
-			    (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
-			    (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
-			    (RING_QUEUE_PEEK(&uvd->dp, 3) == 0xff)) {
-				frame->curline = 0;
-				frame->scanstate = ScanState_Lines;
-				frame->frameState = FrameState_Grabbing;
-				RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
-			/*
-			* if we're starting, we need to discard the first
-			* 4 lines of y bayer data
-			* and the first 2 gr elements of x bayer data
-			*/
-				RING_QUEUE_DEQUEUE_BYTES(&uvd->dp,
-							(hor*verdel + hordel));
-				break;
-			}
-			RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
-		}
-	}
-
-	if (frame->scanstate == ScanState_Scanning)
-		return;
-
-	/* now we can start processing bayer data so long as we have at least
-	* 2 lines worth of data. this is the simplest demosaicing method that
-	* I could think of. I use each 2x2 bayer element without interpolation
-	* to generate 4 rgb pixels.
-	*/
-	while ( frame->curline < cam->height &&
-		(RingQueue_GetLength(&uvd->dp) >= hor*2)) {
-		/* get 2 lines of bayer for demosaicing
-		 * into 2 lines of RGB */
-		RingQueue_Dequeue(&uvd->dp, cam->scratch, hor*2);
-		bayL0 = (struct bayL0 *) cam->scratch;
-		bayL1 = (struct bayL1 *) (cam->scratch + hor);
-		/* frame->curline is the rgb y line */
-		rgbL0 = (struct rgb *)
-				( frame->data + (cam->width*3*frame->curline));
-		/* w/2 because we're already doing 2 pixels */
-		rgbL1 = rgbL0 + (cam->width/2);
-
-		for (x=0; x < cam->width; x+=2) {
-			rgbL0->r = bayL0->r;
-			rgbL0->g = bayL0->g;
-			rgbL0->b = bayL1->b;
-
-			rgbL0->r2 = bayL0->r;
-			rgbL0->g2 = bayL1->g;
-			rgbL0->b2 = bayL1->b;
-
-			rgbL1->r = bayL0->r;
-			rgbL1->g = bayL1->g;
-			rgbL1->b = bayL1->b;
-
-			rgbL1->r2 = bayL0->r;
-			rgbL1->g2 = bayL1->g;
-			rgbL1->b2 = bayL1->b;
-
-			rgbL0++;
-			rgbL1++;
-
-			bayL0++;
-			bayL1++;
-		}
-
-		frame->seqRead_Length += cam->width*3*2;
-		frame->curline += 2;
-	}
-	/* See if we filled the frame */
-	if (frame->curline == cam->height) {
-		frame->frameState = FrameState_Done_Hold;
-		frame->curline = 0;
-		uvd->curframe = -1;
-		uvd->stats.frame_num++;
-	}
-}
-
-/* taken from konicawc */
-static int qcm_set_video_mode(struct uvd *uvd, struct video_window *vw)
-{
-	int ret;
-	int newsize;
-	int oldsize;
-	int x = vw->width;
-	int y = vw->height;
-	struct qcm *cam = (struct qcm *) uvd->user_data;
-
-	if (x > 0 && y > 0) {
-		DEBUG(2, "trying to find size %d,%d", x, y);
-		for (newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
-			if ((camera_sizes[newsize].width == x) &&
-				(camera_sizes[newsize].height == y))
-				break;
-		}
-	} else
-		newsize = cam->size;
-
-	if (newsize > MAX_FRAME_SIZE) {
-		DEBUG(1, "couldn't find size %d,%d", x, y);
-		return -EINVAL;
-	}
-
-	if (newsize == cam->size) {
-		DEBUG(1, "Nothing to do");
-		return 0;
-	}
-
-	qcm_stop_data(uvd);
-
-	if (cam->size != newsize) {
-		oldsize = cam->size;
-		cam->size = newsize;
-		ret = qcm_set_camera_size(uvd);
-		if (ret) {
-			err("Couldn't set camera size, err=%d",ret);
-			/* restore the original size */
-			cam->size = oldsize;
-			return ret;
-		}
-	}
-
-	/* Flush the input queue and clear any current frame in progress */
-
-	RingQueue_Flush(&uvd->dp);
-	if (uvd->curframe != -1) {
-		uvd->frame[uvd->curframe].curline = 0;
-		uvd->frame[uvd->curframe].seqRead_Length = 0;
-		uvd->frame[uvd->curframe].seqRead_Index = 0;
-	}
-
-	CHECK_RET(ret, qcm_start_data(uvd));
-	return 0;
-}
-
-static int qcm_configure_video(struct uvd *uvd)
-{
-	int ret;
-	memset(&uvd->vpic, 0, sizeof(uvd->vpic));
-	memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
-	uvd->vpic.colour = colour;
-	uvd->vpic.hue = hue;
-	uvd->vpic.brightness = brightness;
-	uvd->vpic.contrast = contrast;
-	uvd->vpic.whiteness = whiteness;
-	uvd->vpic.depth = 24;
-	uvd->vpic.palette = VIDEO_PALETTE_RGB24;
-
-	memset(&uvd->vcap, 0, sizeof(uvd->vcap));
-	strcpy(uvd->vcap.name, "QCM USB Camera");
-	uvd->vcap.type = VID_TYPE_CAPTURE;
-	uvd->vcap.channels = 1;
-	uvd->vcap.audios = 0;
-
-	uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
-	uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
-	uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
-	uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
-
-	memset(&uvd->vchan, 0, sizeof(uvd->vchan));
-	uvd->vchan.flags = 0 ;
-	uvd->vchan.tuners = 0;
-	uvd->vchan.channel = 0;
-	uvd->vchan.type = VIDEO_TYPE_CAMERA;
-	strcpy(uvd->vchan.name, "Camera");
-
-	CHECK_RET(ret, qcm_sensor_init(uvd));
-	return 0;
-}
-
-static int qcm_probe(struct usb_interface *intf,
-			const struct usb_device_id *devid)
-{
-	int err;
-	struct uvd *uvd;
-	struct usb_device *dev = interface_to_usbdev(intf);
-	struct qcm *cam;
-	size_t buffer_size;
-	unsigned char video_ep;
-	struct usb_host_interface *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	int i,j;
-	unsigned int ifacenum, ifacenum_inact=0;
-	__le16 sensor_id;
-
-	/* we don't support multiconfig cams */
-	if (dev->descriptor.bNumConfigurations != 1)
-		return -ENODEV;
-
-	/* first check for the video interface and not
-	* the audio interface */
-	interface = &intf->cur_altsetting[0];
-	if ((interface->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
-		|| (interface->desc.bInterfaceSubClass !=
-			USB_CLASS_VENDOR_SPEC))
-		return -ENODEV;
-
-	/*
-	walk through each endpoint in each setting in the interface
-	stop when we find the one that's an isochronous IN endpoint.
-	*/
-	for (i=0; i < intf->num_altsetting; i++) {
-		interface = &intf->cur_altsetting[i];
-		ifacenum = interface->desc.bAlternateSetting;
-		/* walk the end points */
-		for (j=0; j < interface->desc.bNumEndpoints; j++) {
-			endpoint = &interface->endpoint[j].desc;
-
-			if (usb_endpoint_dir_out(endpoint))
-				continue; /* not input then not good */
-
-			buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
-			if (!buffer_size) {
-				ifacenum_inact = ifacenum;
-				continue; /* 0 pkt size is not what we want */
-			}
-
-			if (usb_endpoint_xfer_isoc(endpoint)) {
-				video_ep = endpoint->bEndpointAddress;
-				/* break out of the search */
-				goto good_videoep;
-			}
-		}
-	}
-	/* failed out since nothing useful was found */
-	err("No suitable endpoint was found\n");
-	return -ENODEV;
-
-good_videoep:
-	/* disable isochronous stream before doing anything else */
-	err = qcm_stv_setb(dev, STV_ISO_ENABLE, 0);
-	if (err < 0) {
-		err("Failed to disable sensor stream");
-		return -EIO;
-	}
-
-	/*
-	Check that this is the same unknown sensor that is known to work. This
-	sensor is suspected to be the ST VV6422C001. I'll check the same value
-	that the qc-usb driver checks. This value is probably not even the
-	sensor ID since it matches the USB dev ID. Oh well. If it doesn't
-	match, it's probably a diff sensor so exit and apologize.
-	*/
-	err = qcm_stv_getw(dev, CMOS_SENSOR_IDREV, &sensor_id);
-	if (err < 0) {
-		err("Couldn't read sensor values. Err %d\n",err);
-		return err;
-	}
-	if (sensor_id != cpu_to_le16(0x08F0)) {
-		err("Sensor ID %x != %x. Unsupported. Sorry\n",
-			le16_to_cpu(sensor_id), (0x08F0));
-		return -ENODEV;
-	}
-
-	uvd = usbvideo_AllocateDevice(cams);
-	if (!uvd)
-		return -ENOMEM;
-
-	cam = (struct qcm *) uvd->user_data;
-
-	/* buf for doing demosaicing */
-	cam->scratch = kmalloc(324*2, GFP_KERNEL);
-	if (!cam->scratch) /* uvd freed in dereg */
-		return -ENOMEM;
-
-	/* yes, if we fail after here, cam->scratch gets freed
-	by qcm_free_uvd */
-
-	err = qcm_alloc_int_urb(cam);
-	if (err < 0)
-		return err;
-
-	/* yes, if we fail after here, int urb gets freed
-	by qcm_free_uvd */
-
-	RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
-	cam->width = camera_sizes[size].width;
-	cam->height = camera_sizes[size].height;
-	cam->size = size;
-
-	uvd->debug = debug;
-	uvd->flags = 0;
-	uvd->dev = dev;
-	uvd->iface = intf->altsetting->desc.bInterfaceNumber;
-	uvd->ifaceAltActive = ifacenum;
-	uvd->ifaceAltInactive = ifacenum_inact;
-	uvd->video_endp = video_ep;
-	uvd->iso_packet_len = buffer_size;
-	uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
-	uvd->defaultPalette = VIDEO_PALETTE_RGB24;
-	uvd->canvas = VIDEOSIZE(320, 240);
-	uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-	err = qcm_configure_video(uvd);
-	if (err) {
-		err("failed to configure video settings");
-		return err;
-	}
-
-	err = usbvideo_RegisterVideoDevice(uvd);
-	if (err) { /* the uvd gets freed in Deregister */
-		err("usbvideo_RegisterVideoDevice() failed.");
-		return err;
-	}
-
-	uvd->max_frame_size = (320 * 240 * 3);
-	qcm_register_input(cam, dev);
-	usb_set_intfdata(intf, uvd);
-	return 0;
-}
-
-static void qcm_free_uvd(struct uvd *uvd)
-{
-	struct qcm *cam = (struct qcm *) uvd->user_data;
-
-	kfree(cam->scratch);
-	qcm_unregister_input(cam);
-	qcm_free_int(cam);
-}
-
-static struct usbvideo_cb qcm_driver = {
-	.probe = 		qcm_probe,
-	.setupOnOpen = 		qcm_setup_on_open,
-	.processData = 		qcm_process_isoc,
-	.setVideoMode = 	qcm_set_video_mode,
-	.startDataPump = 	qcm_start_data,
-	.stopDataPump = 	qcm_stop_data,
-	.adjustPicture = 	qcm_adjust_picture,
-	.userFree = 		qcm_free_uvd
-};
-
-static int __init qcm_init(void)
-{
-	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-	       DRIVER_DESC "\n");
-
-	return usbvideo_register(
-		&cams,
-		MAX_CAMERAS,
-		sizeof(struct qcm),
-		"QCM",
-		&qcm_driver,
-		THIS_MODULE,
-		qcm_table);
-}
-
-static void __exit qcm_exit(void)
-{
-	usbvideo_Deregister(&cams);
-}
-
-module_param(size, int, 0);
-MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 320x240");
-module_param(colour, int, 0);
-MODULE_PARM_DESC(colour, "Initial colour");
-module_param(hue, int, 0);
-MODULE_PARM_DESC(hue, "Initial hue");
-module_param(brightness, int, 0);
-MODULE_PARM_DESC(brightness, "Initial brightness");
-module_param(contrast, int, 0);
-MODULE_PARM_DESC(contrast, "Initial contrast");
-module_param(whiteness, int, 0);
-MODULE_PARM_DESC(whiteness, "Initial whiteness");
-
-#ifdef CONFIG_USB_DEBUG
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-#endif
-
-module_init(qcm_init);
-module_exit(qcm_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jaya Kumar");
-MODULE_DESCRIPTION("QCM USB Camera");
-MODULE_SUPPORTED_DEVICE("QCM USB Camera");
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.h b/drivers/media/video/usbvideo/quickcam_messenger.h
deleted file mode 100644
index 17ace39..0000000
--- a/drivers/media/video/usbvideo/quickcam_messenger.h
+++ /dev/null
@@ -1,112 +0,0 @@
-#ifndef quickcam_messenger_h
-#define quickcam_messenger_h
-
-#ifndef CONFIG_INPUT
-/* if we're not using input we dummy out these functions */
-#define qcm_register_input(...)
-#define qcm_unregister_input(...)
-#define qcm_report_buttonstat(...)
-#define qcm_setup_input_int(...) 0
-#define qcm_stop_int_data(...)
-#define qcm_alloc_int_urb(...) 0
-#define qcm_free_int(...)
-#endif
-
-
-#define CHECK_RET(ret, expr) \
-	if ((ret = expr) < 0) return ret
-
-/* Control Registers for the STVV6422 ASIC
- * - this define is taken from the qc-usb-messenger code
- */
-#define STV_ISO_ENABLE		0x1440
-#define ISOC_PACKET_SIZE	1023
-
-/* Chip identification number including revision indicator */
-#define CMOS_SENSOR_IDREV	0xE00A
-
-struct rgb {
-	u8 b;
-	u8 g;
-	u8 r;
-	u8 b2;
-	u8 g2;
-	u8 r2;
-};
-
-struct bayL0 {
-	u8 g;
-	u8 r;
-};
-
-struct bayL1 {
-	u8 b;
-	u8 g;
-};
-
-struct cam_size {
-	u16	width;
-	u16	height;
-	u8	cmd;
-};
-
-static const struct cam_size camera_sizes[] = {
-	{ 160, 120, 0xf },
-	{ 320, 240, 0x2 },
-};
-
-enum frame_sizes {
-	SIZE_160X120	= 0,
-	SIZE_320X240	= 1,
-};
-
-#define MAX_FRAME_SIZE SIZE_320X240
-
-struct qcm {
-	u16 colour;
-	u16 hue;
-	u16 brightness;
-	u16 contrast;
-	u16 whiteness;
-
-	u8 size;
-	int height;
-	int width;
-	u8 *scratch;
-	struct urb *button_urb;
-	u8 button_sts;
-	u8 button_sts_buf;
-
-#ifdef CONFIG_INPUT
-	struct input_dev *input;
-	char input_physname[64];
-#endif
-};
-
-struct regval {
-	u16 reg;
-	u8 val;
-};
-/* this table is derived from the
-qc-usb-messenger code */
-static const struct regval regval_table[] = {
-	{ STV_ISO_ENABLE, 0x00 },
-	{ 0x1436, 0x00 }, { 0x1432, 0x03 },
-	{ 0x143a, 0xF9 }, { 0x0509, 0x38 },
-	{ 0x050a, 0x38 }, { 0x050b, 0x38 },
-	{ 0x050c, 0x2A }, { 0x050d, 0x01 },
-	{ 0x1431, 0x00 }, { 0x1433, 0x34 },
-	{ 0x1438, 0x18 }, { 0x1439, 0x00 },
-	{ 0x143b, 0x05 }, { 0x143c, 0x00 },
-	{ 0x143e, 0x01 }, { 0x143d, 0x00 },
-	{ 0x1442, 0xe2 }, { 0x1500, 0xd0 },
-	{ 0x1500, 0xd0 }, { 0x1500, 0x50 },
-	{ 0x1501, 0xaf }, { 0x1502, 0xc2 },
-	{ 0x1503, 0x45 }, { 0x1505, 0x02 },
-	{ 0x150e, 0x8e }, { 0x150f, 0x37 },
-	{ 0x15c0, 0x00 },
-};
-
-static const unsigned char marker[] = { 0x00, 0xff, 0x00, 0xFF };
-
-#endif /* quickcam_messenger_h */
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 27a79f0..a350fad 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -606,6 +606,26 @@
 		.set		= uvc_ctrl_set_zoom,
 	},
 	{
+		.id		= V4L2_CID_PAN_ABSOLUTE,
+		.name		= "Pan (Absolute)",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= UVC_CT_PANTILT_ABSOLUTE_CONTROL,
+		.size		= 32,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_TILT_ABSOLUTE,
+		.name		= "Tilt (Absolute)",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= UVC_CT_PANTILT_ABSOLUTE_CONTROL,
+		.size		= 32,
+		.offset		= 32,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
 		.id		= V4L2_CID_PRIVACY,
 		.name		= "Privacy",
 		.entity		= UVC_GUID_UVC_CAMERA,
@@ -623,7 +643,7 @@
 
 static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
 {
-	return ctrl->data + id * ctrl->info->size;
+	return ctrl->uvc_data + id * ctrl->info->size;
 }
 
 static inline int uvc_test_bit(const __u8 *data, int bit)
@@ -678,6 +698,14 @@
 	int offset = mapping->offset;
 	__u8 mask;
 
+	/* According to the v4l2 spec, writing any value to a button control
+	 * should result in the action belonging to the button control being
+	 * triggered. UVC devices however want to see a 1 written -> override
+	 * value.
+	 */
+	if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON)
+		value = -1;
+
 	data += offset / 8;
 	offset &= 7;
 
@@ -1265,13 +1293,15 @@
  * Control and mapping handling
  */
 
-static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
+static int uvc_ctrl_add_ctrl(struct uvc_device *dev,
 	struct uvc_control_info *info)
 {
 	struct uvc_entity *entity;
 	struct uvc_control *ctrl = NULL;
-	int ret, found = 0;
+	int ret = 0, found = 0;
 	unsigned int i;
+	u8 *uvc_info;
+	u8 *uvc_data;
 
 	list_for_each_entry(entity, &dev->entities, list) {
 		if (!uvc_entity_match_guid(entity, info->entity))
@@ -1290,56 +1320,69 @@
 	}
 
 	if (!found)
-		return;
+		return 0;
+
+	uvc_data = kmalloc(info->size * UVC_CTRL_DATA_LAST + 1, GFP_KERNEL);
+	if (uvc_data == NULL)
+		return -ENOMEM;
+
+	uvc_info = uvc_data + info->size * UVC_CTRL_DATA_LAST;
 
 	if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
 		/* Check if the device control information and length match
 		 * the user supplied information.
 		 */
-		__u32 flags;
-		__le16 size;
-		__u8 inf;
-
 		ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id,
-			dev->intfnum, info->selector, (__u8 *)&size, 2);
+				     dev->intfnum, info->selector, uvc_data, 2);
 		if (ret < 0) {
 			uvc_trace(UVC_TRACE_CONTROL,
 				"GET_LEN failed on control %pUl/%u (%d).\n",
 				info->entity, info->selector, ret);
-			return;
+			goto done;
 		}
 
-		if (info->size != le16_to_cpu(size)) {
+		if (info->size != le16_to_cpu(*(__le16 *)uvc_data)) {
 			uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u size "
 				"doesn't match user supplied value.\n",
 				info->entity, info->selector);
-			return;
+			ret = -EINVAL;
+			goto done;
 		}
 
 		ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
-			dev->intfnum, info->selector, &inf, 1);
+				     dev->intfnum, info->selector, uvc_info, 1);
 		if (ret < 0) {
 			uvc_trace(UVC_TRACE_CONTROL,
 				"GET_INFO failed on control %pUl/%u (%d).\n",
 				info->entity, info->selector, ret);
-			return;
+			goto done;
 		}
 
-		flags = info->flags;
-		if (((flags & UVC_CONTROL_GET_CUR) && !(inf & (1 << 0))) ||
-		    ((flags & UVC_CONTROL_SET_CUR) && !(inf & (1 << 1)))) {
+		if (((info->flags & UVC_CONTROL_GET_CUR) &&
+		    !(*uvc_info & UVC_CONTROL_CAP_GET)) ||
+		    ((info->flags & UVC_CONTROL_SET_CUR) &&
+		    !(*uvc_info & UVC_CONTROL_CAP_SET))) {
 			uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u flags "
 				"don't match supported operations.\n",
 				info->entity, info->selector);
-			return;
+			ret = -EINVAL;
+			goto done;
 		}
 	}
 
 	ctrl->info = info;
-	ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_DATA_LAST, GFP_KERNEL);
+	ctrl->uvc_data = uvc_data;
+	ctrl->uvc_info = uvc_info;
+
 	uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
 		"entity %u\n", ctrl->info->entity, ctrl->info->selector,
 		dev->udev->devpath, entity->id);
+
+done:
+	if (ret < 0)
+		kfree(uvc_data);
+
+	return ret;
 }
 
 /*
@@ -1572,12 +1615,34 @@
 
 	list_for_each_entry(entity, &dev->entities, list) {
 		for (i = 0; i < entity->ncontrols; ++i)
-			kfree(entity->controls[i].data);
+			kfree(entity->controls[i].uvc_data);
 
 		kfree(entity->controls);
 	}
 }
 
+void uvc_ctrl_cleanup(void)
+{
+	struct uvc_control_info *info;
+	struct uvc_control_info *ni;
+	struct uvc_control_mapping *mapping;
+	struct uvc_control_mapping *nm;
+
+	list_for_each_entry_safe(info, ni, &uvc_driver.controls, list) {
+		if (!(info->flags & UVC_CONTROL_EXTENSION))
+			continue;
+
+		list_for_each_entry_safe(mapping, nm, &info->mappings, list) {
+			list_del(&mapping->list);
+			kfree(mapping->menu_info);
+			kfree(mapping);
+		}
+
+		list_del(&info->list);
+		kfree(info);
+	}
+}
+
 void uvc_ctrl_init(void)
 {
 	struct uvc_control_info *ctrl = uvc_ctrls;
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 838b56f..7eaf99b 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -637,14 +637,13 @@
 	}
 	streaming->header.bControlSize = n;
 
-	streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
+	streaming->header.bmaControls = kmemdup(&buffer[size], p * n,
+						GFP_KERNEL);
 	if (streaming->header.bmaControls == NULL) {
 		ret = -ENOMEM;
 		goto error;
 	}
 
-	memcpy(streaming->header.bmaControls, &buffer[size], p*n);
-
 	buflen -= buffer[0];
 	buffer += buffer[0];
 
@@ -2174,6 +2173,15 @@
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_EXTRAFIELDS },
+	/* Manta MM-353 Plako */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x18ec,
+	  .idProduct		= 0x3188,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
 	/* FSC WebCam V30S */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2261,6 +2269,7 @@
 static void __exit uvc_cleanup(void)
 {
 	usb_deregister(&uvc_driver.driver);
+	uvc_ctrl_cleanup();
 }
 
 module_init(uvc_init);
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 7c9ab29..86db326 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -29,6 +29,71 @@
 #include "uvcvideo.h"
 
 /* ------------------------------------------------------------------------
+ * UVC ioctls
+ */
+static int uvc_ioctl_ctrl_map(struct uvc_xu_control_mapping *xmap, int old)
+{
+	struct uvc_control_mapping *map;
+	unsigned int size;
+	int ret;
+
+	map = kzalloc(sizeof *map, GFP_KERNEL);
+	if (map == NULL)
+		return -ENOMEM;
+
+	map->id = xmap->id;
+	memcpy(map->name, xmap->name, sizeof map->name);
+	memcpy(map->entity, xmap->entity, sizeof map->entity);
+	map->selector = xmap->selector;
+	map->size = xmap->size;
+	map->offset = xmap->offset;
+	map->v4l2_type = xmap->v4l2_type;
+	map->data_type = xmap->data_type;
+
+	switch (xmap->v4l2_type) {
+	case V4L2_CTRL_TYPE_INTEGER:
+	case V4L2_CTRL_TYPE_BOOLEAN:
+	case V4L2_CTRL_TYPE_BUTTON:
+		break;
+
+	case V4L2_CTRL_TYPE_MENU:
+		if (old) {
+			ret = -EINVAL;
+			goto done;
+		}
+
+		size = xmap->menu_count * sizeof(*map->menu_info);
+		map->menu_info = kmalloc(size, GFP_KERNEL);
+		if (map->menu_info == NULL) {
+			ret = -ENOMEM;
+			goto done;
+		}
+
+		if (copy_from_user(map->menu_info, xmap->menu_info, size)) {
+			ret = -EFAULT;
+			goto done;
+		}
+
+		map->menu_count = xmap->menu_count;
+		break;
+
+	default:
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = uvc_ctrl_add_mapping(map);
+
+done:
+	if (ret < 0) {
+		kfree(map->menu_info);
+		kfree(map);
+	}
+
+	return ret;
+}
+
+/* ------------------------------------------------------------------------
  * V4L2 interface
  */
 
@@ -451,7 +516,7 @@
 
 static int uvc_v4l2_release(struct file *file)
 {
-	struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+	struct uvc_fh *handle = file->private_data;
 	struct uvc_streaming *stream = handle->stream;
 
 	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
@@ -482,7 +547,7 @@
 static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
 	struct video_device *vdev = video_devdata(file);
-	struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+	struct uvc_fh *handle = file->private_data;
 	struct uvc_video_chain *chain = handle->chain;
 	struct uvc_streaming *stream = handle->stream;
 	long ret = 0;
@@ -963,6 +1028,9 @@
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 
+		if (xinfo->size == 0)
+			return -EINVAL;
+
 		info = kzalloc(sizeof *info, GFP_KERNEL);
 		if (info == NULL)
 			return -ENOMEM;
@@ -974,7 +1042,8 @@
 		info->flags = xinfo->flags;
 
 		info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
-				UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF;
+			       UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF |
+			       UVC_CONTROL_EXTENSION;
 
 		ret = uvc_ctrl_add_info(info);
 		if (ret < 0)
@@ -982,32 +1051,12 @@
 		break;
 	}
 
+	case UVCIOC_CTRL_MAP_OLD:
 	case UVCIOC_CTRL_MAP:
-	{
-		struct uvc_xu_control_mapping *xmap = arg;
-		struct uvc_control_mapping *map;
-
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 
-		map = kzalloc(sizeof *map, GFP_KERNEL);
-		if (map == NULL)
-			return -ENOMEM;
-
-		map->id = xmap->id;
-		memcpy(map->name, xmap->name, sizeof map->name);
-		memcpy(map->entity, xmap->entity, sizeof map->entity);
-		map->selector = xmap->selector;
-		map->size = xmap->size;
-		map->offset = xmap->offset;
-		map->v4l2_type = xmap->v4l2_type;
-		map->data_type = xmap->data_type;
-
-		ret = uvc_ctrl_add_mapping(map);
-		if (ret < 0)
-			kfree(map);
-		break;
-	}
+		return uvc_ioctl_ctrl_map(arg, cmd == UVCIOC_CTRL_MAP_OLD);
 
 	case UVCIOC_CTRL_GET:
 		return uvc_xu_ctrl_query(chain, arg, 0);
@@ -1067,7 +1116,7 @@
 
 static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+	struct uvc_fh *handle = file->private_data;
 	struct uvc_streaming *stream = handle->stream;
 	struct uvc_video_queue *queue = &stream->queue;
 	struct uvc_buffer *uninitialized_var(buffer);
@@ -1122,7 +1171,7 @@
 
 static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
 {
-	struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+	struct uvc_fh *handle = file->private_data;
 	struct uvc_streaming *stream = handle->stream;
 
 	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index d1f8840..ac27245 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -27,6 +27,8 @@
 #define UVC_CONTROL_RESTORE	(1 << 6)
 /* Control can be updated by the camera. */
 #define UVC_CONTROL_AUTO_UPDATE	(1 << 7)
+/* Control is an extension unit control. */
+#define UVC_CONTROL_EXTENSION	(1 << 8)
 
 #define UVC_CONTROL_GET_RANGE	(UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
 				 UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
@@ -40,6 +42,15 @@
 	__u32 flags;
 };
 
+struct uvc_menu_info {
+	__u32 value;
+	__u8 name[32];
+};
+
+struct uvc_xu_control_mapping_old {
+	__u8 reserved[64];
+};
+
 struct uvc_xu_control_mapping {
 	__u32 id;
 	__u8 name[32];
@@ -50,6 +61,11 @@
 	__u8 offset;
 	enum v4l2_ctrl_type v4l2_type;
 	__u32 data_type;
+
+	struct uvc_menu_info __user *menu_info;
+	__u32 menu_count;
+
+	__u32 reserved[4];
 };
 
 struct uvc_xu_control {
@@ -60,6 +76,7 @@
 };
 
 #define UVCIOC_CTRL_ADD		_IOW('U', 1, struct uvc_xu_control_info)
+#define UVCIOC_CTRL_MAP_OLD	_IOWR('U', 2, struct uvc_xu_control_mapping_old)
 #define UVCIOC_CTRL_MAP		_IOWR('U', 2, struct uvc_xu_control_mapping)
 #define UVCIOC_CTRL_GET		_IOWR('U', 3, struct uvc_xu_control)
 #define UVCIOC_CTRL_SET		_IOW('U', 4, struct uvc_xu_control)
@@ -179,30 +196,6 @@
 /* TODO: Put the most frequently accessed fields at the beginning of
  * structures to maximize cache efficiency.
  */
-struct uvc_streaming_control {
-	__u16 bmHint;
-	__u8  bFormatIndex;
-	__u8  bFrameIndex;
-	__u32 dwFrameInterval;
-	__u16 wKeyFrameRate;
-	__u16 wPFrameRate;
-	__u16 wCompQuality;
-	__u16 wCompWindowSize;
-	__u16 wDelay;
-	__u32 dwMaxVideoFrameSize;
-	__u32 dwMaxPayloadTransferSize;
-	__u32 dwClockFrequency;
-	__u8  bmFramingInfo;
-	__u8  bPreferedVersion;
-	__u8  bMinVersion;
-	__u8  bMaxVersion;
-};
-
-struct uvc_menu_info {
-	__u32 value;
-	__u8 name[32];
-};
-
 struct uvc_control_info {
 	struct list_head list;
 	struct list_head mappings;
@@ -250,7 +243,8 @@
 	     modified : 1,
 	     cached : 1;
 
-	__u8 *data;
+	__u8 *uvc_data;
+	__u8 *uvc_info;
 };
 
 struct uvc_format_desc {
@@ -625,6 +619,7 @@
 extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
 extern int uvc_ctrl_resume_device(struct uvc_device *dev);
 extern void uvc_ctrl_init(void);
+extern void uvc_ctrl_cleanup(void);
 
 extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
 extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 0ca7ec9..9e89bf61 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -410,7 +410,7 @@
 	int minor_offset = 0;
 	int minor_cnt = VIDEO_NUM_DEVICES;
 	const char *name_base;
-	void *priv = video_get_drvdata(vdev);
+	void *priv = vdev->dev.p;
 
 	/* A minor value of -1 marks this video device as never
 	   having been registered */
@@ -536,9 +536,9 @@
 
 	/* Part 4: register the device with sysfs */
 	memset(&vdev->dev, 0, sizeof(vdev->dev));
-	/* The memset above cleared the device's drvdata, so
+	/* The memset above cleared the device's device_private, so
 	   put back the copy we made earlier. */
-	video_set_drvdata(vdev, priv);
+	vdev->dev.p = priv;
 	vdev->dev.class = &video_class;
 	vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
 	if (vdev->parent)
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index 7d33784..ce1595b 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -52,18 +52,18 @@
 #define CALL(q, f, arg...)						\
 	((q->int_ops->f) ? q->int_ops->f(arg) : 0)
 
-struct videobuf_buffer *videobuf_alloc(struct videobuf_queue *q)
+struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q)
 {
 	struct videobuf_buffer *vb;
 
 	BUG_ON(q->msize < sizeof(*vb));
 
-	if (!q->int_ops || !q->int_ops->alloc) {
+	if (!q->int_ops || !q->int_ops->alloc_vb) {
 		printk(KERN_ERR "No specific ops defined!\n");
 		BUG();
 	}
 
-	vb = q->int_ops->alloc(q->msize);
+	vb = q->int_ops->alloc_vb(q->msize);
 	if (NULL != vb) {
 		init_waitqueue_head(&vb->done);
 		vb->magic = MAGIC_BUFFER;
@@ -71,7 +71,7 @@
 
 	return vb;
 }
-EXPORT_SYMBOL_GPL(videobuf_alloc);
+EXPORT_SYMBOL_GPL(videobuf_alloc_vb);
 
 #define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE &&\
 				vb->state != VIDEOBUF_QUEUED)
@@ -195,6 +195,45 @@
 }
 EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);
 
+/**
+ * __videobuf_free() - free all the buffers and their control structures
+ *
+ * This function can only be called if streaming/reading is off, i.e. no buffers
+ * are under control of the driver.
+ */
+/* Locking: Caller holds q->vb_lock */
+static int __videobuf_free(struct videobuf_queue *q)
+{
+	int i;
+
+	dprintk(1, "%s\n", __func__);
+	if (!q)
+		return 0;
+
+	if (q->streaming || q->reading) {
+		dprintk(1, "Cannot free buffers when streaming or reading\n");
+		return -EBUSY;
+	}
+
+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+
+	for (i = 0; i < VIDEO_MAX_FRAME; i++)
+		if (q->bufs[i] && q->bufs[i]->map) {
+			dprintk(1, "Cannot free mmapped buffers\n");
+			return -EBUSY;
+		}
+
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		q->ops->buf_release(q, q->bufs[i]);
+		kfree(q->bufs[i]);
+		q->bufs[i] = NULL;
+	}
+
+	return 0;
+}
+
 /* Locking: Caller holds q->vb_lock */
 void videobuf_queue_cancel(struct videobuf_queue *q)
 {
@@ -308,36 +347,11 @@
 	b->sequence  = vb->field_count >> 1;
 }
 
-/* Locking: Caller holds q->vb_lock */
-static int __videobuf_mmap_free(struct videobuf_queue *q)
-{
-	int i;
-
-	if (!q)
-		return 0;
-
-	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
-
-	for (i = 0; i < VIDEO_MAX_FRAME; i++)
-		if (q->bufs[i] && q->bufs[i]->map)
-			return -EBUSY;
-
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (NULL == q->bufs[i])
-			continue;
-		q->ops->buf_release(q, q->bufs[i]);
-		kfree(q->bufs[i]);
-		q->bufs[i] = NULL;
-	}
-
-	return 0;
-}
-
 int videobuf_mmap_free(struct videobuf_queue *q)
 {
 	int ret;
 	mutex_lock(&q->vb_lock);
-	ret = __videobuf_mmap_free(q);
+	ret = __videobuf_free(q);
 	mutex_unlock(&q->vb_lock);
 	return ret;
 }
@@ -353,13 +367,13 @@
 
 	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-	err = __videobuf_mmap_free(q);
+	err = __videobuf_free(q);
 	if (0 != err)
 		return err;
 
 	/* Allocate and initialize buffers */
 	for (i = 0; i < bcount; i++) {
-		q->bufs[i] = videobuf_alloc(q);
+		q->bufs[i] = videobuf_alloc_vb(q);
 
 		if (NULL == q->bufs[i])
 			break;
@@ -766,7 +780,7 @@
 	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
 	/* setup stuff */
-	q->read_buf = videobuf_alloc(q);
+	q->read_buf = videobuf_alloc_vb(q);
 	if (NULL == q->read_buf)
 		return -ENOMEM;
 
@@ -871,7 +885,7 @@
 	if (NULL == q->read_buf) {
 		/* need to capture a new frame */
 		retval = -ENOMEM;
-		q->read_buf = videobuf_alloc(q);
+		q->read_buf = videobuf_alloc_vb(q);
 
 		dprintk(1, "video alloc=0x%p\n", q->read_buf);
 		if (NULL == q->read_buf)
@@ -970,7 +984,7 @@
 	int i;
 
 	videobuf_queue_cancel(q);
-	__videobuf_mmap_free(q);
+	__videobuf_free(q);
 	INIT_LIST_HEAD(&q->stream);
 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 		if (NULL == q->bufs[i])
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index 74730c6..372b87e 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -190,7 +190,7 @@
 	return ret;
 }
 
-static struct videobuf_buffer *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
 {
 	struct videobuf_dma_contig_memory *mem;
 	struct videobuf_buffer *vb;
@@ -280,8 +280,6 @@
 		return -ENOMEM;
 
 	buf->map = map;
-	map->start = vma->vm_start;
-	map->end = vma->vm_end;
 	map->q = q;
 
 	buf->baddr = vma->vm_start;
@@ -338,7 +336,7 @@
 static struct videobuf_qtype_ops qops = {
 	.magic        = MAGIC_QTYPE_OPS,
 
-	.alloc        = __videobuf_alloc,
+	.alloc_vb     = __videobuf_alloc_vb,
 	.iolock       = __videobuf_iolock,
 	.mmap_mapper  = __videobuf_mmap_mapper,
 	.vaddr        = __videobuf_to_vaddr,
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 8359e6b..06f9a9c 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -57,7 +57,13 @@
 
 /* --------------------------------------------------------------------- */
 
-struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
+/*
+ * Return a scatterlist for some page-aligned vmalloc()'ed memory
+ * block (NULL on errors).  Memory for the scatterlist is allocated
+ * using kmalloc.  The caller must free the memory.
+ */
+static struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt,
+						  int nr_pages)
 {
 	struct scatterlist *sglist;
 	struct page *pg;
@@ -81,10 +87,14 @@
 	vfree(sglist);
 	return NULL;
 }
-EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
 
-struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages,
-					 int offset)
+/*
+ * Return a scatterlist for a an array of userpages (NULL on errors).
+ * Memory for the scatterlist is allocated using kmalloc.  The caller
+ * must free the memory.
+ */
+static struct scatterlist *videobuf_pages_to_sg(struct page **pages,
+						int nr_pages, int offset)
 {
 	struct scatterlist *sglist;
 	int i;
@@ -201,17 +211,17 @@
 	dprintk(1, "init kernel [%d pages]\n", nr_pages);
 
 	dma->direction = direction;
-	dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
-	if (NULL == dma->vmalloc) {
+	dma->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
+	if (NULL == dma->vaddr) {
 		dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
 		return -ENOMEM;
 	}
 
 	dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n",
-				(unsigned long)dma->vmalloc,
+				(unsigned long)dma->vaddr,
 				nr_pages << PAGE_SHIFT);
 
-	memset(dma->vmalloc, 0, nr_pages << PAGE_SHIFT);
+	memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT);
 	dma->nr_pages = nr_pages;
 
 	return 0;
@@ -235,7 +245,7 @@
 }
 EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
 
-int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
+int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
 {
 	MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
 	BUG_ON(0 == dma->nr_pages);
@@ -244,8 +254,8 @@
 		dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
 						   dma->offset);
 	}
-	if (dma->vmalloc) {
-		dma->sglist = videobuf_vmalloc_to_sg(dma->vmalloc,
+	if (dma->vaddr) {
+		dma->sglist = videobuf_vmalloc_to_sg(dma->vaddr,
 						     dma->nr_pages);
 	}
 	if (dma->bus_addr) {
@@ -263,7 +273,7 @@
 		return -ENOMEM;
 	}
 	if (!dma->bus_addr) {
-		dma->sglen = dma_map_sg(q->dev, dma->sglist,
+		dma->sglen = dma_map_sg(dev, dma->sglist,
 					dma->nr_pages, dma->direction);
 		if (0 == dma->sglen) {
 			printk(KERN_WARNING
@@ -279,14 +289,14 @@
 }
 EXPORT_SYMBOL_GPL(videobuf_dma_map);
 
-int videobuf_dma_unmap(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
+int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma)
 {
 	MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
 
 	if (!dma->sglen)
 		return 0;
 
-	dma_unmap_sg(q->dev, dma->sglist, dma->sglen, dma->direction);
+	dma_unmap_sg(dev, dma->sglist, dma->sglen, dma->direction);
 
 	vfree(dma->sglist);
 	dma->sglist = NULL;
@@ -309,8 +319,8 @@
 		dma->pages = NULL;
 	}
 
-	vfree(dma->vmalloc);
-	dma->vmalloc = NULL;
+	vfree(dma->vaddr);
+	dma->vaddr = NULL;
 
 	if (dma->bus_addr)
 		dma->bus_addr = 0;
@@ -322,28 +332,6 @@
 
 /* --------------------------------------------------------------------- */
 
-int videobuf_sg_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
-{
-	struct videobuf_queue q;
-
-	q.dev = dev;
-
-	return videobuf_dma_map(&q, dma);
-}
-EXPORT_SYMBOL_GPL(videobuf_sg_dma_map);
-
-int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma)
-{
-	struct videobuf_queue q;
-
-	q.dev = dev;
-
-	return videobuf_dma_unmap(&q, dma);
-}
-EXPORT_SYMBOL_GPL(videobuf_sg_dma_unmap);
-
-/* --------------------------------------------------------------------- */
-
 static void videobuf_vm_open(struct vm_area_struct *vma)
 {
 	struct videobuf_mapping *map = vma->vm_private_data;
@@ -428,7 +416,7 @@
 	struct videobuf_dma_sg_memory
  */
 
-static struct videobuf_buffer *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
 {
 	struct videobuf_dma_sg_memory *mem;
 	struct videobuf_buffer *vb;
@@ -456,7 +444,7 @@
 
 	MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
 
-	return mem->dma.vmalloc;
+	return mem->dma.vaddr;
 }
 
 static int __videobuf_iolock(struct videobuf_queue *q,
@@ -520,7 +508,7 @@
 	default:
 		BUG();
 	}
-	err = videobuf_dma_map(q, &mem->dma);
+	err = videobuf_dma_map(q->dev, &mem->dma);
 	if (0 != err)
 		return err;
 
@@ -620,8 +608,6 @@
 	}
 
 	map->count    = 1;
-	map->start    = vma->vm_start;
-	map->end      = vma->vm_end;
 	map->q        = q;
 	vma->vm_ops   = &videobuf_vm_ops;
 	vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
@@ -638,7 +624,7 @@
 static struct videobuf_qtype_ops sg_ops = {
 	.magic        = MAGIC_QTYPE_OPS,
 
-	.alloc        = __videobuf_alloc,
+	.alloc_vb     = __videobuf_alloc_vb,
 	.iolock       = __videobuf_iolock,
 	.sync         = __videobuf_sync,
 	.mmap_mapper  = __videobuf_mmap_mapper,
@@ -654,7 +640,7 @@
 
 	q.msize = size;
 
-	return videobuf_alloc(&q);
+	return videobuf_alloc_vb(&q);
 }
 EXPORT_SYMBOL_GPL(videobuf_sg_alloc);
 
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index 583728f..e7fe31d 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -102,10 +102,10 @@
 				   called with IRQ's disabled
 				 */
 				dprintk(1, "%s: buf[%d] freeing (%p)\n",
-					__func__, i, mem->vmalloc);
+					__func__, i, mem->vaddr);
 
-				vfree(mem->vmalloc);
-				mem->vmalloc = NULL;
+				vfree(mem->vaddr);
+				mem->vaddr = NULL;
 			}
 
 			q->bufs[i]->map   = NULL;
@@ -135,7 +135,7 @@
 	struct videobuf_dma_sg_memory
  */
 
-static struct videobuf_buffer *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
 {
 	struct videobuf_vmalloc_memory *mem;
 	struct videobuf_buffer *vb;
@@ -170,7 +170,7 @@
 		dprintk(1, "%s memory method MMAP\n", __func__);
 
 		/* All handling should be done by __videobuf_mmap_mapper() */
-		if (!mem->vmalloc) {
+		if (!mem->vaddr) {
 			printk(KERN_ERR "memory is not alloced/mmapped.\n");
 			return -EINVAL;
 		}
@@ -189,13 +189,13 @@
 		 * read() method.
 		 */
 
-		mem->vmalloc = vmalloc_user(pages);
-		if (!mem->vmalloc) {
+		mem->vaddr = vmalloc_user(pages);
+		if (!mem->vaddr) {
 			printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
 			return -ENOMEM;
 		}
 		dprintk(1, "vmalloc is at addr %p (%d pages)\n",
-			mem->vmalloc, pages);
+			mem->vaddr, pages);
 
 #if 0
 		int rc;
@@ -245,8 +245,6 @@
 		return -ENOMEM;
 
 	buf->map = map;
-	map->start = vma->vm_start;
-	map->end   = vma->vm_end;
 	map->q     = q;
 
 	buf->baddr = vma->vm_start;
@@ -256,18 +254,18 @@
 	MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 
 	pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
-	mem->vmalloc = vmalloc_user(pages);
-	if (!mem->vmalloc) {
+	mem->vaddr = vmalloc_user(pages);
+	if (!mem->vaddr) {
 		printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
 		goto error;
 	}
-	dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vmalloc, pages);
+	dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages);
 
 	/* Try to remap memory */
-	retval = remap_vmalloc_range(vma, mem->vmalloc, 0);
+	retval = remap_vmalloc_range(vma, mem->vaddr, 0);
 	if (retval < 0) {
 		printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
-		vfree(mem->vmalloc);
+		vfree(mem->vaddr);
 		goto error;
 	}
 
@@ -293,7 +291,7 @@
 static struct videobuf_qtype_ops qops = {
 	.magic        = MAGIC_QTYPE_OPS,
 
-	.alloc        = __videobuf_alloc,
+	.alloc_vb     = __videobuf_alloc_vb,
 	.iolock       = __videobuf_iolock,
 	.mmap_mapper  = __videobuf_mmap_mapper,
 	.vaddr        = videobuf_to_vmalloc,
@@ -319,7 +317,7 @@
 	BUG_ON(!mem);
 	MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 
-	return mem->vmalloc;
+	return mem->vaddr;
 }
 EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
 
@@ -341,8 +339,8 @@
 
 	MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 
-	vfree(mem->vmalloc);
-	mem->vmalloc = NULL;
+	vfree(mem->vaddr);
+	mem->vaddr = NULL;
 
 	return;
 }
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
deleted file mode 100644
index d807eea..0000000
--- a/drivers/media/video/w9968cf.c
+++ /dev/null
@@ -1,3620 +0,0 @@
-/***************************************************************************
- * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
- *                                                                         *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * - Memory management code from bttv driver by Ralph Metzler,             *
- *   Marcus Metzler and Gerd Knorr.                                        *
- * - I2C interface to kernel, high-level image sensor control routines and *
- *   some symbolic names from OV511 driver by Mark W. McClelland.          *
- * - Low-level I2C fast write function by Piotr Czerczak.                  *
- * - Low-level I2C read function by Frederic Jouault.                      *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/ioctl.h>
-#include <linux/delay.h>
-#include <linux/stddef.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-#include <linux/page-flags.h>
-#include <linux/videodev.h>
-#include <media/v4l2-ioctl.h>
-
-#include "w9968cf.h"
-#include "w9968cf_decoder.h"
-
-static struct w9968cf_vpp_t* w9968cf_vpp;
-static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
-
-static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
-static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */
-
-static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */
-
-
-/****************************************************************************
- * Module macros and parameters                                             *
- ****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, winbond_id_table);
-
-MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(W9968CF_MODULE_NAME);
-MODULE_VERSION(W9968CF_MODULE_VERSION);
-MODULE_LICENSE(W9968CF_MODULE_LICENSE);
-MODULE_SUPPORTED_DEVICE("Video");
-
-static unsigned short simcams = W9968CF_SIMCAMS;
-static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
-static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-				     W9968CF_PACKET_SIZE};
-static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-				       W9968CF_BUFFERS};
-static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-			      W9968CF_DOUBLE_BUFFER};
-static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING};
-static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] =
-				      W9968CF_FILTER_TYPE};
-static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW};
-static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-					 W9968CF_DECOMPRESSION};
-static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING};
-static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0};
-static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB};
-static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT};
-static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP};
-static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-				     W9968CF_LIGHTFREQ};
-static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]=
-			      W9968CF_BANDINGFILTER};
-static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV};
-static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT};
-static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR};
-static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME};
-static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-				    W9968CF_BRIGHTNESS};
-static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE};
-static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR};
-static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-				  W9968CF_CONTRAST};
-static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] =
-				   W9968CF_WHITENESS};
-#ifdef W9968CF_DEBUG
-static unsigned short debug = W9968CF_DEBUG_LEVEL;
-static int specific_debug = W9968CF_SPECIFIC_DEBUG;
-#endif
-
-static unsigned int param_nv[24]; /* number of values per parameter */
-
-module_param(simcams, ushort, 0644);
-module_param_array(video_nr, short, &param_nv[0], 0444);
-module_param_array(packet_size, uint, &param_nv[1], 0444);
-module_param_array(max_buffers, ushort, &param_nv[2], 0444);
-module_param_array(double_buffer, bool, &param_nv[3], 0444);
-module_param_array(clamping, bool, &param_nv[4], 0444);
-module_param_array(filter_type, ushort, &param_nv[5], 0444);
-module_param_array(largeview, bool, &param_nv[6], 0444);
-module_param_array(decompression, ushort, &param_nv[7], 0444);
-module_param_array(upscaling, bool, &param_nv[8], 0444);
-module_param_array(force_palette, ushort, &param_nv[9], 0444);
-module_param_array(force_rgb, ushort, &param_nv[10], 0444);
-module_param_array(autobright, bool, &param_nv[11], 0444);
-module_param_array(autoexp, bool, &param_nv[12], 0444);
-module_param_array(lightfreq, ushort, &param_nv[13], 0444);
-module_param_array(bandingfilter, bool, &param_nv[14], 0444);
-module_param_array(clockdiv, short, &param_nv[15], 0444);
-module_param_array(backlight, bool, &param_nv[16], 0444);
-module_param_array(mirror, bool, &param_nv[17], 0444);
-module_param_array(monochrome, bool, &param_nv[18], 0444);
-module_param_array(brightness, uint, &param_nv[19], 0444);
-module_param_array(hue, uint, &param_nv[20], 0444);
-module_param_array(colour, uint, &param_nv[21], 0444);
-module_param_array(contrast, uint, &param_nv[22], 0444);
-module_param_array(whiteness, uint, &param_nv[23], 0444);
-#ifdef W9968CF_DEBUG
-module_param(debug, ushort, 0644);
-module_param(specific_debug, bool, 0644);
-#endif
-
-MODULE_PARM_DESC(simcams,
-		 "\n<n> Number of cameras allowed to stream simultaneously."
-		 "\nn may vary from 0 to "
-		 __MODULE_STRING(W9968CF_MAX_DEVICES)"."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"."
-		 "\n");
-MODULE_PARM_DESC(video_nr,
-		 "\n<-1|n[,...]> Specify V4L minor mode number."
-		 "\n -1 = use next available (default)"
-		 "\n  n = use minor number n (integer >= 0)"
-		 "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES)
-		 " cameras this way."
-		 "\nFor example:"
-		 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-		 "\nthe second camera and use auto for the first"
-		 "\none and for every other camera."
-		 "\n");
-MODULE_PARM_DESC(packet_size,
-		 "\n<n[,...]> Specify the maximum data payload"
-		 "\nsize in bytes for alternate settings, for each device."
-		 "\nn is scaled between 63 and 1023 "
-		 "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")."
-		 "\n");
-MODULE_PARM_DESC(max_buffers,
-		 "\n<n[,...]> For advanced users."
-		 "\nSpecify the maximum number of video frame buffers"
-		 "\nto allocate for each device, from 2 to "
-		 __MODULE_STRING(W9968CF_MAX_BUFFERS)
-		 ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")."
-		 "\n");
-MODULE_PARM_DESC(double_buffer,
-		 "\n<0|1[,...]> "
-		 "Hardware double buffering: 0 disabled, 1 enabled."
-		 "\nIt should be enabled if you want smooth video output: if"
-		 "\nyou obtain out of sync. video, disable it, or try to"
-		 "\ndecrease the 'clockdiv' module parameter value."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(clamping,
-		 "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(filter_type,
-		 "\n<0|1|2[,...]> Video filter type."
-		 "\n0 none, 1 (1-2-1) 3-tap filter, "
-		 "2 (2-3-6-3-2) 5-tap filter."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE)
-		 " for every device."
-		 "\nThe filter is used to reduce noise and aliasing artifacts"
-		 "\nproduced by the CCD or CMOS image sensor, and the scaling"
-		 " process."
-		 "\n");
-MODULE_PARM_DESC(largeview,
-		 "\n<0|1[,...]> Large view: 0 disabled, 1 enabled."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(upscaling,
-		 "\n<0|1[,...]> Software scaling (for non-compressed video):"
-		 "\n0 disabled, 1 enabled."
-		 "\nDisable it if you have a slow CPU or you don't have"
-		 " enough memory."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING)
-		 " for every device."
-		 "\nIf 'w9968cf-vpp' is not present, this parameter is"
-		 " set to 0."
-		 "\n");
-MODULE_PARM_DESC(decompression,
-		 "\n<0|1|2[,...]> Software video decompression:"
-		 "\n- 0 disables decompression (doesn't allow formats needing"
-		 " decompression)"
-		 "\n- 1 forces decompression (allows formats needing"
-		 " decompression only);"
-		 "\n- 2 allows any permitted formats."
-		 "\nFormats supporting compressed video are YUV422P and"
-		 " YUV420P/YUV420 "
-		 "\nin any resolutions where both width and height are "
-		 "a multiple of 16."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION)
-		 " for every device."
-		 "\nIf 'w9968cf-vpp' is not present, forcing decompression is "
-		 "\nnot allowed; in this case this parameter is set to 2."
-		 "\n");
-MODULE_PARM_DESC(force_palette,
-		 "\n<0"
-		 "|" __MODULE_STRING(VIDEO_PALETTE_UYVY)
-		 "|" __MODULE_STRING(VIDEO_PALETTE_YUV420)
-		 "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P)
-		 "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P)
-		 "|" __MODULE_STRING(VIDEO_PALETTE_YUYV)
-		 "|" __MODULE_STRING(VIDEO_PALETTE_YUV422)
-		 "|" __MODULE_STRING(VIDEO_PALETTE_GREY)
-		 "|" __MODULE_STRING(VIDEO_PALETTE_RGB555)
-		 "|" __MODULE_STRING(VIDEO_PALETTE_RGB565)
-		 "|" __MODULE_STRING(VIDEO_PALETTE_RGB24)
-		 "|" __MODULE_STRING(VIDEO_PALETTE_RGB32)
-		 "[,...]>"
-		 " Force picture palette."
-		 "\nIn order:"
-		 "\n- 0 allows any of the following formats:"
-		 "\n- UYVY    16 bpp - Original video, compression disabled"
-		 "\n- YUV420  12 bpp - Original video, compression enabled"
-		 "\n- YUV422P 16 bpp - Original video, compression enabled"
-		 "\n- YUV420P 12 bpp - Original video, compression enabled"
-		 "\n- YUVY    16 bpp - Software conversion from UYVY"
-		 "\n- YUV422  16 bpp - Software conversion from UYVY"
-		 "\n- GREY     8 bpp - Software conversion from UYVY"
-		 "\n- RGB555  16 bpp - Software conversion from UYVY"
-		 "\n- RGB565  16 bpp - Software conversion from UYVY"
-		 "\n- RGB24   24 bpp - Software conversion from UYVY"
-		 "\n- RGB32   32 bpp - Software conversion from UYVY"
-		 "\nWhen not 0, this parameter will override 'decompression'."
-		 "\nDefault value is 0 for every device."
-		 "\nInitial palette is "
-		 __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"."
-		 "\nIf 'w9968cf-vpp' is not present, this parameter is"
-		 " set to 9 (UYVY)."
-		 "\n");
-MODULE_PARM_DESC(force_rgb,
-		 "\n<0|1[,...]> Read RGB video data instead of BGR:"
-		 "\n 1 = use RGB component ordering."
-		 "\n 0 = use BGR component ordering."
-		 "\nThis parameter has effect when using RGBX palettes only."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(autobright,
-		 "\n<0|1[,...]> Image sensor automatically changes brightness:"
-		 "\n 0 = no, 1 = yes"
-		 "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(autoexp,
-		 "\n<0|1[,...]> Image sensor automatically changes exposure:"
-		 "\n 0 = no, 1 = yes"
-		 "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(lightfreq,
-		 "\n<50|60[,...]> Light frequency in Hz:"
-		 "\n 50 for European and Asian lighting,"
-		 " 60 for American lighting."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(bandingfilter,
-		 "\n<0|1[,...]> Banding filter to reduce effects of"
-		 " fluorescent lighting:"
-		 "\n 0 disabled, 1 enabled."
-		 "\nThis filter tries to reduce the pattern of horizontal"
-		 "\nlight/dark bands caused by some (usually fluorescent)"
-		 " lighting."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(clockdiv,
-		 "\n<-1|n[,...]> "
-		 "Force pixel clock divisor to a specific value (for experts):"
-		 "\n  n may vary from 0 to 127."
-		 "\n -1 for automatic value."
-		 "\nSee also the 'double_buffer' module parameter."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(backlight,
-		 "\n<0|1[,...]> Objects are lit from behind:"
-		 "\n 0 = no, 1 = yes"
-		 "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(mirror,
-		 "\n<0|1[,...]> Reverse image horizontally:"
-		 "\n 0 = no, 1 = yes"
-		 "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(monochrome,
-		 "\n<0|1[,...]> Use image sensor as monochrome sensor:"
-		 "\n 0 = no, 1 = yes"
-		 "\nNot all the sensors support monochrome color."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(brightness,
-		 "\n<n[,...]> Set picture brightness (0-65535)."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS)
-		 " for every device."
-		 "\nThis parameter has no effect if 'autobright' is enabled."
-		 "\n");
-MODULE_PARM_DESC(hue,
-		 "\n<n[,...]> Set picture hue (0-65535)."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_HUE)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(colour,
-		 "\n<n[,...]> Set picture saturation (0-65535)."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(contrast,
-		 "\n<n[,...]> Set picture contrast (0-65535)."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST)
-		 " for every device."
-		 "\n");
-MODULE_PARM_DESC(whiteness,
-		 "\n<n[,...]> Set picture whiteness (0-65535)."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS)
-		 " for every device."
-		 "\n");
-#ifdef W9968CF_DEBUG
-MODULE_PARM_DESC(debug,
-		 "\n<n> Debugging information level, from 0 to 6:"
-		 "\n0 = none (use carefully)"
-		 "\n1 = critical errors"
-		 "\n2 = significant informations"
-		 "\n3 = configuration or general messages"
-		 "\n4 = warnings"
-		 "\n5 = called functions"
-		 "\n6 = function internals"
-		 "\nLevel 5 and 6 are useful for testing only, when only "
-		 "one device is used."
-		 "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"."
-		 "\n");
-MODULE_PARM_DESC(specific_debug,
-		 "\n<0|1> Enable or disable specific debugging messages:"
-		 "\n0 = print messages concerning every level"
-		 " <= 'debug' level."
-		 "\n1 = print messages concerning the level"
-		 " indicated by 'debug'."
-		 "\nDefault value is "
-		 __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"."
-		 "\n");
-#endif /* W9968CF_DEBUG */
-
-
-
-/****************************************************************************
- * Some prototypes                                                          *
- ****************************************************************************/
-
-/* Video4linux interface */
-static const struct v4l2_file_operations w9968cf_fops;
-static int w9968cf_open(struct file *);
-static int w9968cf_release(struct file *);
-static int w9968cf_mmap(struct file *, struct vm_area_struct *);
-static long w9968cf_ioctl(struct file *, unsigned, unsigned long);
-static ssize_t w9968cf_read(struct file *, char __user *, size_t, loff_t *);
-static long w9968cf_v4l_ioctl(struct file *, unsigned int,
-			     void __user *);
-
-/* USB-specific */
-static int w9968cf_start_transfer(struct w9968cf_device*);
-static int w9968cf_stop_transfer(struct w9968cf_device*);
-static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index);
-static int w9968cf_read_reg(struct w9968cf_device*, u16 index);
-static int w9968cf_write_fsb(struct w9968cf_device*, u16* data);
-static int w9968cf_write_sb(struct w9968cf_device*, u16 value);
-static int w9968cf_read_sb(struct w9968cf_device*);
-static int w9968cf_upload_quantizationtables(struct w9968cf_device*);
-static void w9968cf_urb_complete(struct urb *urb);
-
-/* Low-level I2C (SMBus) I/O */
-static int w9968cf_smbus_start(struct w9968cf_device*);
-static int w9968cf_smbus_stop(struct w9968cf_device*);
-static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v);
-static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v);
-static int w9968cf_smbus_write_ack(struct w9968cf_device*);
-static int w9968cf_smbus_read_ack(struct w9968cf_device*);
-static int w9968cf_smbus_refresh_bus(struct w9968cf_device*);
-static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
-				      u16 address, u8* value);
-static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address,
-					   u8 subaddress, u8* value);
-static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*,
-				       u16 address, u8 subaddress);
-static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*,
-						u16 address, u8 subaddress,
-						u8 value);
-
-/* I2C interface to kernel */
-static int w9968cf_i2c_init(struct w9968cf_device*);
-static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
-				  unsigned short flags, char read_write,
-				  u8 command, int size, union i2c_smbus_data*);
-static u32 w9968cf_i2c_func(struct i2c_adapter*);
-
-/* Memory management */
-static void* rvmalloc(unsigned long size);
-static void rvfree(void *mem, unsigned long size);
-static void w9968cf_deallocate_memory(struct w9968cf_device*);
-static int  w9968cf_allocate_memory(struct w9968cf_device*);
-
-/* High-level image sensor control functions */
-static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val);
-static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val);
-static int w9968cf_sensor_cmd(struct w9968cf_device*,
-			      unsigned int cmd, void *arg);
-static int w9968cf_sensor_init(struct w9968cf_device*);
-static int w9968cf_sensor_update_settings(struct w9968cf_device*);
-static int w9968cf_sensor_get_picture(struct w9968cf_device*);
-static int w9968cf_sensor_update_picture(struct w9968cf_device*,
-					 struct video_picture pict);
-
-/* Other helper functions */
-static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*,
-				     enum w9968cf_model_id,
-				     const unsigned short dev_nr);
-static void w9968cf_adjust_configuration(struct w9968cf_device*);
-static int w9968cf_turn_on_led(struct w9968cf_device*);
-static int w9968cf_init_chip(struct w9968cf_device*);
-static inline u16 w9968cf_valid_palette(u16 palette);
-static inline u16 w9968cf_valid_depth(u16 palette);
-static inline u8 w9968cf_need_decompression(u16 palette);
-static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture);
-static int w9968cf_set_window(struct w9968cf_device*, struct video_window);
-static int w9968cf_postprocess_frame(struct w9968cf_device*,
-				     struct w9968cf_frame_t*);
-static int w9968cf_adjust_window_size(struct w9968cf_device*, u32 *w, u32 *h);
-static void w9968cf_init_framelist(struct w9968cf_device*);
-static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);
-static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
-static void w9968cf_release_resources(struct w9968cf_device*);
-
-
-
-/****************************************************************************
- * Symbolic names                                                           *
- ****************************************************************************/
-
-/* Used to represent a list of values and their respective symbolic names */
-struct w9968cf_symbolic_list {
-	const int num;
-	const char *name;
-};
-
-/*--------------------------------------------------------------------------
-  Returns the name of the matching element in the symbolic_list array. The
-  end of the list must be marked with an element that has a NULL name.
-  --------------------------------------------------------------------------*/
-static inline const char *
-symbolic(struct w9968cf_symbolic_list list[], const int num)
-{
-	int i;
-
-	for (i = 0; list[i].name != NULL; i++)
-		if (list[i].num == num)
-			return (list[i].name);
-
-	return "Unknown";
-}
-
-static struct w9968cf_symbolic_list camlist[] = {
-	{ W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" },
-	{ W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" },
-
-	/* Other cameras (having the same descriptors as Generic W996[87]CF) */
-	{ W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" },
-	{ W9986CF_MOD_AAU, "AVerMedia AVerTV USB" },
-	{ W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" },
-	{ W9968CF_MOD_LL, "Lebon LDC-035A" },
-	{ W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" },
-	{ W9968CF_MOD_OOE, "OmniVision OV8610-EDE" },
-	{ W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" },
-	{ W9968CF_MOD_PDPII, "Pretec Digi Pen-II" },
-	{ W9968CF_MOD_PDP480, "Pretec DigiPen-480" },
-
-	{  -1, NULL }
-};
-
-static struct w9968cf_symbolic_list senlist[] = {
-	{ CC_OV76BE,   "OV76BE" },
-	{ CC_OV7610,   "OV7610" },
-	{ CC_OV7620,   "OV7620" },
-	{ CC_OV7620AE, "OV7620AE" },
-	{ CC_OV6620,   "OV6620" },
-	{ CC_OV6630,   "OV6630" },
-	{ CC_OV6630AE, "OV6630AE" },
-	{ CC_OV6630AF, "OV6630AF" },
-	{ -1, NULL }
-};
-
-/* Video4Linux1 palettes */
-static struct w9968cf_symbolic_list v4l1_plist[] = {
-	{ VIDEO_PALETTE_GREY,    "GREY" },
-	{ VIDEO_PALETTE_HI240,   "HI240" },
-	{ VIDEO_PALETTE_RGB565,  "RGB565" },
-	{ VIDEO_PALETTE_RGB24,   "RGB24" },
-	{ VIDEO_PALETTE_RGB32,   "RGB32" },
-	{ VIDEO_PALETTE_RGB555,  "RGB555" },
-	{ VIDEO_PALETTE_YUV422,  "YUV422" },
-	{ VIDEO_PALETTE_YUYV,    "YUYV" },
-	{ VIDEO_PALETTE_UYVY,    "UYVY" },
-	{ VIDEO_PALETTE_YUV420,  "YUV420" },
-	{ VIDEO_PALETTE_YUV411,  "YUV411" },
-	{ VIDEO_PALETTE_RAW,     "RAW" },
-	{ VIDEO_PALETTE_YUV422P, "YUV422P" },
-	{ VIDEO_PALETTE_YUV411P, "YUV411P" },
-	{ VIDEO_PALETTE_YUV420P, "YUV420P" },
-	{ VIDEO_PALETTE_YUV410P, "YUV410P" },
-	{ -1, NULL }
-};
-
-/* Decoder error codes: */
-static struct w9968cf_symbolic_list decoder_errlist[] = {
-	{ W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" },
-	{ W9968CF_DEC_ERR_BUF_OVERFLOW,   "Buffer overflow" },
-	{ W9968CF_DEC_ERR_NO_SOI,         "SOI marker not found" },
-	{ W9968CF_DEC_ERR_NO_SOF0,        "SOF0 marker not found" },
-	{ W9968CF_DEC_ERR_NO_SOS,         "SOS marker not found" },
-	{ W9968CF_DEC_ERR_NO_EOI,         "EOI marker not found" },
-	{ -1, NULL }
-};
-
-/* URB error codes: */
-static struct w9968cf_symbolic_list urb_errlist[] = {
-	{ -ENOMEM,    "No memory for allocation of internal structures" },
-	{ -ENOSPC,    "The host controller's bandwidth is already consumed" },
-	{ -ENOENT,    "URB was canceled by unlink_urb" },
-	{ -EXDEV,     "ISO transfer only partially completed" },
-	{ -EAGAIN,    "Too match scheduled for the future" },
-	{ -ENXIO,     "URB already queued" },
-	{ -EFBIG,     "Too much ISO frames requested" },
-	{ -ENOSR,     "Buffer error (overrun)" },
-	{ -EPIPE,     "Specified endpoint is stalled (device not responding)"},
-	{ -EOVERFLOW, "Babble (too much data)" },
-	{ -EPROTO,    "Bit-stuff error (bad cable?)" },
-	{ -EILSEQ,    "CRC/Timeout" },
-	{ -ETIME,     "Device does not respond to token" },
-	{ -ETIMEDOUT, "Device does not respond to command" },
-	{ -1, NULL }
-};
-
-/****************************************************************************
- * Memory management functions                                              *
- ****************************************************************************/
-static void* rvmalloc(unsigned long size)
-{
-	void* mem;
-	unsigned long adr;
-
-	size = PAGE_ALIGN(size);
-	mem = vmalloc_32(size);
-	if (!mem)
-		return NULL;
-
-	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-	adr = (unsigned long) mem;
-	while (size > 0) {
-		SetPageReserved(vmalloc_to_page((void *)adr));
-		adr += PAGE_SIZE;
-		size -= PAGE_SIZE;
-	}
-
-	return mem;
-}
-
-
-static void rvfree(void* mem, unsigned long size)
-{
-	unsigned long adr;
-
-	if (!mem)
-		return;
-
-	adr = (unsigned long) mem;
-	while ((long) size > 0) {
-		ClearPageReserved(vmalloc_to_page((void *)adr));
-		adr += PAGE_SIZE;
-		size -= PAGE_SIZE;
-	}
-	vfree(mem);
-}
-
-
-/*--------------------------------------------------------------------------
-  Deallocate previously allocated memory.
-  --------------------------------------------------------------------------*/
-static void w9968cf_deallocate_memory(struct w9968cf_device* cam)
-{
-	u8 i;
-
-	/* Free the isochronous transfer buffers */
-	for (i = 0; i < W9968CF_URBS; i++) {
-		kfree(cam->transfer_buffer[i]);
-		cam->transfer_buffer[i] = NULL;
-	}
-
-	/* Free temporary frame buffer */
-	if (cam->frame_tmp.buffer) {
-		rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size);
-		cam->frame_tmp.buffer = NULL;
-	}
-
-	/* Free helper buffer */
-	if (cam->frame_vpp.buffer) {
-		rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size);
-		cam->frame_vpp.buffer = NULL;
-	}
-
-	/* Free video frame buffers */
-	if (cam->frame[0].buffer) {
-		rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size);
-		cam->frame[0].buffer = NULL;
-	}
-
-	cam->nbuffers = 0;
-
-	DBG(5, "Memory successfully deallocated")
-}
-
-
-/*--------------------------------------------------------------------------
-  Allocate memory buffers for USB transfers and video frames.
-  This function is called by open() only.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_allocate_memory(struct w9968cf_device* cam)
-{
-	const u16 p_size = wMaxPacketSize[cam->altsetting-1];
-	void* buff = NULL;
-	unsigned long hw_bufsize, vpp_bufsize;
-	u8 i, bpp;
-
-	/* NOTE: Deallocation is done elsewhere in case of error */
-
-	/* Calculate the max amount of raw data per frame from the device */
-	hw_bufsize = cam->maxwidth*cam->maxheight*2;
-
-	/* Calculate the max buf. size needed for post-processing routines */
-	bpp = (w9968cf_vpp) ? 4 : 2;
-	if (cam->upscaling)
-		vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp,
-				  cam->maxwidth*cam->maxheight*bpp);
-	else
-		vpp_bufsize = cam->maxwidth*cam->maxheight*bpp;
-
-	/* Allocate memory for the isochronous transfer buffers */
-	for (i = 0; i < W9968CF_URBS; i++) {
-		if (!(cam->transfer_buffer[i] =
-		      kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
-			DBG(1, "Couldn't allocate memory for the isochronous "
-			       "transfer buffers (%u bytes)",
-			    p_size * W9968CF_ISO_PACKETS)
-			return -ENOMEM;
-		}
-	}
-
-	/* Allocate memory for the temporary frame buffer */
-	if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) {
-		DBG(1, "Couldn't allocate memory for the temporary "
-		       "video frame buffer (%lu bytes)", hw_bufsize)
-		return -ENOMEM;
-	}
-	cam->frame_tmp.size = hw_bufsize;
-	cam->frame_tmp.number = -1;
-
-	/* Allocate memory for the helper buffer */
-	if (w9968cf_vpp) {
-		if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) {
-			DBG(1, "Couldn't allocate memory for the helper buffer"
-			       " (%lu bytes)", vpp_bufsize)
-			return -ENOMEM;
-		}
-		cam->frame_vpp.size = vpp_bufsize;
-	} else
-		cam->frame_vpp.buffer = NULL;
-
-	/* Allocate memory for video frame buffers */
-	cam->nbuffers = cam->max_buffers;
-	while (cam->nbuffers >= 2) {
-		if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize)))
-			break;
-		else
-			cam->nbuffers--;
-	}
-
-	if (!buff) {
-		DBG(1, "Couldn't allocate memory for the video frame buffers")
-		cam->nbuffers = 0;
-		return -ENOMEM;
-	}
-
-	if (cam->nbuffers != cam->max_buffers)
-		DBG(2, "Couldn't allocate memory for %u video frame buffers. "
-		       "Only memory for %u buffers has been allocated",
-		    cam->max_buffers, cam->nbuffers)
-
-	for (i = 0; i < cam->nbuffers; i++) {
-		cam->frame[i].buffer = buff + i*vpp_bufsize;
-		cam->frame[i].size = vpp_bufsize;
-		cam->frame[i].number = i;
-		/* Circular list */
-		if (i != cam->nbuffers-1)
-			cam->frame[i].next = &cam->frame[i+1];
-		else
-			cam->frame[i].next = &cam->frame[0];
-		cam->frame[i].status = F_UNUSED;
-	}
-
-	DBG(5, "Memory successfully allocated")
-	return 0;
-}
-
-
-
-/****************************************************************************
- * USB-specific functions                                                   *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
-  This is an handler function which is called after the URBs are completed.
-  It collects multiple data packets coming from the camera by putting them
-  into frame buffers: one or more zero data length data packets are used to
-  mark the end of a video frame; the first non-zero data packet is the start
-  of the next video frame; if an error is encountered in a packet, the entire
-  video frame is discarded and grabbed again.
-  If there are no requested frames in the FIFO list, packets are collected into
-  a temporary buffer.
-  --------------------------------------------------------------------------*/
-static void w9968cf_urb_complete(struct urb *urb)
-{
-	struct w9968cf_device* cam = (struct w9968cf_device*)urb->context;
-	struct w9968cf_frame_t** f;
-	unsigned int len, status;
-	void* pos;
-	u8 i;
-	int err = 0;
-
-	if ((!cam->streaming) || cam->disconnected) {
-		DBG(4, "Got interrupt, but not streaming")
-		return;
-	}
-
-	/* "(*f)" will be used instead of "cam->frame_current" */
-	f = &cam->frame_current;
-
-	/* If a frame has been requested and we are grabbing into
-	   the temporary frame, we'll switch to that requested frame */
-	if ((*f) == &cam->frame_tmp && *cam->requested_frame) {
-		if (cam->frame_tmp.status == F_GRABBING) {
-			w9968cf_pop_frame(cam, &cam->frame_current);
-			(*f)->status = F_GRABBING;
-			(*f)->length = cam->frame_tmp.length;
-			memcpy((*f)->buffer, cam->frame_tmp.buffer,
-			       (*f)->length);
-			DBG(6, "Switched from temp. frame to frame #%d",
-			    (*f)->number)
-		}
-	}
-
-	for (i = 0; i < urb->number_of_packets; i++) {
-		len = urb->iso_frame_desc[i].actual_length;
-		status = urb->iso_frame_desc[i].status;
-		pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
-		if (status && len != 0) {
-			DBG(4, "URB failed, error in data packet "
-			       "(error #%u, %s)",
-			    status, symbolic(urb_errlist, status))
-			(*f)->status = F_ERROR;
-			continue;
-		}
-
-		if (len) { /* start of frame */
-
-			if ((*f)->status == F_UNUSED) {
-				(*f)->status = F_GRABBING;
-				(*f)->length = 0;
-			}
-
-			/* Buffer overflows shouldn't happen, however...*/
-			if ((*f)->length + len > (*f)->size) {
-				DBG(4, "Buffer overflow: bad data packets")
-				(*f)->status = F_ERROR;
-			}
-
-			if ((*f)->status == F_GRABBING) {
-				memcpy((*f)->buffer + (*f)->length, pos, len);
-				(*f)->length += len;
-			}
-
-		} else if ((*f)->status == F_GRABBING) { /* end of frame */
-
-			DBG(6, "Frame #%d successfully grabbed", (*f)->number)
-
-			if (cam->vpp_flag & VPP_DECOMPRESSION) {
-				err = w9968cf_vpp->check_headers((*f)->buffer,
-								 (*f)->length);
-				if (err) {
-					DBG(4, "Skip corrupted frame: %s",
-					    symbolic(decoder_errlist, err))
-					(*f)->status = F_UNUSED;
-					continue; /* grab this frame again */
-				}
-			}
-
-			(*f)->status = F_READY;
-			(*f)->queued = 0;
-
-			/* Take a pointer to the new frame from the FIFO list.
-			   If the list is empty,we'll use the temporary frame*/
-			if (*cam->requested_frame)
-				w9968cf_pop_frame(cam, &cam->frame_current);
-			else {
-				cam->frame_current = &cam->frame_tmp;
-				(*f)->status = F_UNUSED;
-			}
-
-		} else if ((*f)->status == F_ERROR)
-			(*f)->status = F_UNUSED; /* grab it again */
-
-		PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d",
-		      (unsigned long)(*f)->length, i, len, (*f)->status)
-
-	} /* end for */
-
-	/* Resubmit this URB */
-	urb->dev = cam->usbdev;
-	urb->status = 0;
-	spin_lock(&cam->urb_lock);
-	if (cam->streaming)
-		if ((err = usb_submit_urb(urb, GFP_ATOMIC))) {
-			cam->misconfigured = 1;
-			DBG(1, "Couldn't resubmit the URB: error %d, %s",
-			    err, symbolic(urb_errlist, err))
-		}
-	spin_unlock(&cam->urb_lock);
-
-	/* Wake up the user process */
-	wake_up_interruptible(&cam->wait_queue);
-}
-
-
-/*---------------------------------------------------------------------------
-  Setup the URB structures for the isochronous transfer.
-  Submit the URBs so that the data transfer begins.
-  Return 0 on success, a negative number otherwise.
-  ---------------------------------------------------------------------------*/
-static int w9968cf_start_transfer(struct w9968cf_device* cam)
-{
-	struct usb_device *udev = cam->usbdev;
-	struct urb* urb;
-	const u16 p_size = wMaxPacketSize[cam->altsetting-1];
-	u16 w, h, d;
-	int vidcapt;
-	u32 t_size;
-	int err = 0;
-	s8 i, j;
-
-	for (i = 0; i < W9968CF_URBS; i++) {
-		urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL);
-		if (!urb) {
-			for (j = 0; j < i; j++)
-				usb_free_urb(cam->urb[j]);
-			DBG(1, "Couldn't allocate the URB structures")
-			return -ENOMEM;
-		}
-
-		cam->urb[i] = urb;
-		urb->dev = udev;
-		urb->context = (void*)cam;
-		urb->pipe = usb_rcvisocpipe(udev, 1);
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->number_of_packets = W9968CF_ISO_PACKETS;
-		urb->complete = w9968cf_urb_complete;
-		urb->transfer_buffer = cam->transfer_buffer[i];
-		urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS;
-		urb->interval = 1;
-		for (j = 0; j < W9968CF_ISO_PACKETS; j++) {
-			urb->iso_frame_desc[j].offset = p_size*j;
-			urb->iso_frame_desc[j].length = p_size;
-		}
-	}
-
-	/* Transfer size per frame, in WORD ! */
-	d = cam->hw_depth;
-	w = cam->hw_width;
-	h = cam->hw_height;
-
-	t_size = (w*h*d)/16;
-
-	err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
-	err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
-
-	/* Transfer size */
-	err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */
-	err += w9968cf_write_reg(cam, t_size >> 16, 0x3e);    /* high bits */
-
-	if (cam->vpp_flag & VPP_DECOMPRESSION)
-		err += w9968cf_upload_quantizationtables(cam);
-
-	vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */
-	err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */
-
-	err += usb_set_interface(udev, 0, cam->altsetting);
-	err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */
-
-	if (err || (vidcapt < 0)) {
-		for (i = 0; i < W9968CF_URBS; i++)
-			usb_free_urb(cam->urb[i]);
-		DBG(1, "Couldn't tell the camera to start the data transfer")
-		return err;
-	}
-
-	w9968cf_init_framelist(cam);
-
-	/* Begin to grab into the temporary buffer */
-	cam->frame_tmp.status = F_UNUSED;
-	cam->frame_tmp.queued = 0;
-	cam->frame_current = &cam->frame_tmp;
-
-	if (!(cam->vpp_flag & VPP_DECOMPRESSION))
-		DBG(5, "Isochronous transfer size: %lu bytes/frame",
-		    (unsigned long)t_size*2)
-
-	DBG(5, "Starting the isochronous transfer...")
-
-	cam->streaming = 1;
-
-	/* Submit the URBs */
-	for (i = 0; i < W9968CF_URBS; i++) {
-		err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
-		if (err) {
-			cam->streaming = 0;
-			for (j = i-1; j >= 0; j--) {
-				usb_kill_urb(cam->urb[j]);
-				usb_free_urb(cam->urb[j]);
-			}
-			DBG(1, "Couldn't send a transfer request to the "
-			       "USB core (error #%d, %s)", err,
-			    symbolic(urb_errlist, err))
-			return err;
-		}
-	}
-
-	return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Stop the isochronous transfer and set alternate setting to 0 (0Mb/s).
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_stop_transfer(struct w9968cf_device* cam)
-{
-	struct usb_device *udev = cam->usbdev;
-	unsigned long lock_flags;
-	int err = 0;
-	s8 i;
-
-	if (!cam->streaming)
-		return 0;
-
-	/* This avoids race conditions with usb_submit_urb()
-	   in the URB completition handler */
-	spin_lock_irqsave(&cam->urb_lock, lock_flags);
-	cam->streaming = 0;
-	spin_unlock_irqrestore(&cam->urb_lock, lock_flags);
-
-	for (i = W9968CF_URBS-1; i >= 0; i--)
-		if (cam->urb[i]) {
-			usb_kill_urb(cam->urb[i]);
-			usb_free_urb(cam->urb[i]);
-			cam->urb[i] = NULL;
-		}
-
-	if (cam->disconnected)
-		goto exit;
-
-	err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */
-	err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */
-	err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */
-	err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */
-
-	if (err) {
-		DBG(2, "Failed to tell the camera to stop the isochronous "
-		       "transfer. However this is not a critical error.")
-		return -EIO;
-	}
-
-exit:
-	DBG(5, "Isochronous transfer stopped")
-	return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write a W9968CF register.
-  Return 0 on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index)
-{
-	struct usb_device* udev = cam->usbdev;
-	int res;
-
-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
-			      USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-			      value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT);
-
-	if (res < 0)
-		DBG(4, "Failed to write a register "
-		       "(value 0x%04X, index 0x%02X, error #%d, %s)",
-		    value, index, res, symbolic(urb_errlist, res))
-
-	return (res >= 0) ? 0 : -1;
-}
-
-
-/*--------------------------------------------------------------------------
-  Read a W9968CF register.
-  Return the register value on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index)
-{
-	struct usb_device* udev = cam->usbdev;
-	u16* buff = cam->control_buffer;
-	int res;
-
-	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1,
-			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			      0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT);
-
-	if (res < 0)
-		DBG(4, "Failed to read a register "
-		       "(index 0x%02X, error #%d, %s)",
-		    index, res, symbolic(urb_errlist, res))
-
-	return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write 64-bit data to the fast serial bus registers.
-  Return 0 on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data)
-{
-	struct usb_device* udev = cam->usbdev;
-	u16 value;
-	int res;
-
-	value = *data++;
-
-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
-			      USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-			      value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT);
-
-	if (res < 0)
-		DBG(4, "Failed to write the FSB registers "
-		       "(error #%d, %s)", res, symbolic(urb_errlist, res))
-
-	return (res >= 0) ? 0 : -1;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write data to the serial bus control register.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value)
-{
-	int err = 0;
-
-	err = w9968cf_write_reg(cam, value, 0x01);
-	udelay(W9968CF_I2C_BUS_DELAY);
-
-	return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Read data from the serial bus control register.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_read_sb(struct w9968cf_device* cam)
-{
-	int v = 0;
-
-	v = w9968cf_read_reg(cam, 0x01);
-	udelay(W9968CF_I2C_BUS_DELAY);
-
-	return v;
-}
-
-
-/*--------------------------------------------------------------------------
-  Upload quantization tables for the JPEG compression.
-  This function is called by w9968cf_start_transfer().
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam)
-{
-	u16 a, b;
-	int err = 0, i, j;
-
-	err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */
-
-	for (i = 0, j = 0; i < 32; i++, j += 2) {
-		a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8);
-		b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8);
-		err += w9968cf_write_reg(cam, a, 0x40+i);
-		err += w9968cf_write_reg(cam, b, 0x60+i);
-	}
-	err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */
-
-	return err;
-}
-
-
-
-/****************************************************************************
- * Low-level I2C I/O functions.                                             *
- * The adapter supports the following I2C transfer functions:               *
- * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only)           *
- * i2c_adap_read_byte_data()                                                *
- * i2c_adap_read_byte()                                                     *
- ****************************************************************************/
-
-static int w9968cf_smbus_start(struct w9968cf_device* cam)
-{
-	int err = 0;
-
-	err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
-	err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
-	return err;
-}
-
-
-static int w9968cf_smbus_stop(struct w9968cf_device* cam)
-{
-	int err = 0;
-
-	err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
-	err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
-
-	return err;
-}
-
-
-static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v)
-{
-	u8 bit;
-	int err = 0, sda;
-
-	for (bit = 0 ; bit < 8 ; bit++) {
-		sda = (v & 0x80) ? 2 : 0;
-		v <<= 1;
-		/* SDE=1, SDA=sda, SCL=0 */
-		err += w9968cf_write_sb(cam, 0x10 | sda);
-		/* SDE=1, SDA=sda, SCL=1 */
-		err += w9968cf_write_sb(cam, 0x11 | sda);
-		/* SDE=1, SDA=sda, SCL=0 */
-		err += w9968cf_write_sb(cam, 0x10 | sda);
-	}
-
-	return err;
-}
-
-
-static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v)
-{
-	u8 bit;
-	int err = 0;
-
-	*v = 0;
-	for (bit = 0 ; bit < 8 ; bit++) {
-		*v <<= 1;
-		err += w9968cf_write_sb(cam, 0x0013);
-		*v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0;
-		err += w9968cf_write_sb(cam, 0x0012);
-	}
-
-	return err;
-}
-
-
-static int w9968cf_smbus_write_ack(struct w9968cf_device* cam)
-{
-	int err = 0;
-
-	err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-	err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
-	err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
-	return err;
-}
-
-
-static int w9968cf_smbus_read_ack(struct w9968cf_device* cam)
-{
-	int err = 0, sda;
-
-	err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
-	sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */
-	err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */
-	if (sda < 0)
-		err += sda;
-	if (sda == 1) {
-		DBG(6, "Couldn't receive the ACK")
-		err += -1;
-	}
-
-	return err;
-}
-
-
-/* This seems to refresh the communication through the serial bus */
-static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam)
-{
-	int err = 0, j;
-
-	for (j = 1; j <= 10; j++) {
-		err = w9968cf_write_reg(cam, 0x0020, 0x01);
-		err += w9968cf_write_reg(cam, 0x0000, 0x01);
-		if (err)
-			break;
-	}
-
-	return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
-static int
-w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam,
-				     u16 address, u8 subaddress,u8 value)
-{
-	u16* data = cam->data_buffer;
-	int err = 0;
-
-	err += w9968cf_smbus_refresh_bus(cam);
-
-	/* Enable SBUS outputs */
-	err += w9968cf_write_sb(cam, 0x0020);
-
-	data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0);
-	data[0] |= (address & 0x40) ? 0x4000 : 0x0;
-	data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0);
-	data[1] |= (address & 0x20) ? 0x0150 : 0x0;
-	data[1] |= (address & 0x10) ? 0x5400 : 0x0;
-	data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0);
-	data[2] |= (address & 0x04) ? 0x0540 : 0x0;
-	data[2] |= (address & 0x02) ? 0x5000 : 0x0;
-	data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0);
-	data[3] |= (address & 0x01) ? 0x0054 : 0x0;
-
-	err += w9968cf_write_fsb(cam, data);
-
-	data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0);
-	data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0;
-	data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0;
-	data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0);
-	data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0;
-	data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0;
-	data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0;
-	data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0);
-	data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0;
-	data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0;
-	data[3] = 0x001d;
-
-	err += w9968cf_write_fsb(cam, data);
-
-	data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
-	data[0] |= (value & 0x40) ? 0x0540 : 0x0;
-	data[0] |= (value & 0x20) ? 0x5000 : 0x0;
-	data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0);
-	data[1] |= (value & 0x10) ? 0x0054 : 0x0;
-	data[1] |= (value & 0x08) ? 0x1500 : 0x0;
-	data[1] |= (value & 0x04) ? 0x4000 : 0x0;
-	data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0);
-	data[2] |= (value & 0x02) ? 0x0150 : 0x0;
-	data[2] |= (value & 0x01) ? 0x5400 : 0x0;
-	data[3] = 0xfe1d;
-
-	err += w9968cf_write_fsb(cam, data);
-
-	/* Disable SBUS outputs */
-	err += w9968cf_write_sb(cam, 0x0000);
-
-	if (!err)
-		DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X "
-		       "value 0x%02X", address, subaddress, value)
-	else
-		DBG(5, "I2C write byte data failed, addr.0x%04X, "
-		       "subaddr.0x%02X, value 0x%02X",
-		    address, subaddress, value)
-
-	return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
-static int
-w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam,
-				u16 address, u8 subaddress,
-				u8* value)
-{
-	int err = 0;
-
-	/* Serial data enable */
-	err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */
-
-	err += w9968cf_smbus_start(cam);
-	err += w9968cf_smbus_write_byte(cam, address);
-	err += w9968cf_smbus_read_ack(cam);
-	err += w9968cf_smbus_write_byte(cam, subaddress);
-	err += w9968cf_smbus_read_ack(cam);
-	err += w9968cf_smbus_stop(cam);
-	err += w9968cf_smbus_start(cam);
-	err += w9968cf_smbus_write_byte(cam, address + 1);
-	err += w9968cf_smbus_read_ack(cam);
-	err += w9968cf_smbus_read_byte(cam, value);
-	err += w9968cf_smbus_write_ack(cam);
-	err += w9968cf_smbus_stop(cam);
-
-	/* Serial data disable */
-	err += w9968cf_write_sb(cam, 0x0000);
-
-	if (!err)
-		DBG(5, "I2C read byte data done, addr.0x%04X, "
-		       "subaddr.0x%02X, value 0x%02X",
-		    address, subaddress, *value)
-	else
-		DBG(5, "I2C read byte data failed, addr.0x%04X, "
-		       "subaddr.0x%02X, wrong value 0x%02X",
-		    address, subaddress, *value)
-
-	return err;
-}
-
-
-/* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */
-static int
-w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
-			   u16 address, u8* value)
-{
-	int err = 0;
-
-	/* Serial data enable */
-	err += w9968cf_write_sb(cam, 0x0013);
-
-	err += w9968cf_smbus_start(cam);
-	err += w9968cf_smbus_write_byte(cam, address + 1);
-	err += w9968cf_smbus_read_ack(cam);
-	err += w9968cf_smbus_read_byte(cam, value);
-	err += w9968cf_smbus_write_ack(cam);
-	err += w9968cf_smbus_stop(cam);
-
-	/* Serial data disable */
-	err += w9968cf_write_sb(cam, 0x0000);
-
-	if (!err)
-		DBG(5, "I2C read byte done, addr.0x%04X, "
-		       "value 0x%02X", address, *value)
-	else
-		DBG(5, "I2C read byte failed, addr.0x%04X, "
-		       "wrong value 0x%02X", address, *value)
-
-	return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Value [A] P */
-static int
-w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam,
-			    u16 address, u8 value)
-{
-	DBG(4, "i2c_write_byte() is an unsupported transfer mode")
-	return -EINVAL;
-}
-
-
-
-/****************************************************************************
- * I2C interface to kernel                                                  *
- ****************************************************************************/
-
-static int
-w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
-		       unsigned short flags, char read_write, u8 command,
-		       int size, union i2c_smbus_data *data)
-{
-	struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
-	struct w9968cf_device *cam = to_cam(v4l2_dev);
-	u8 i;
-	int err = 0;
-
-	if (size == I2C_SMBUS_BYTE) {
-		/* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
-		addr <<= 1;
-
-		if (read_write == I2C_SMBUS_WRITE)
-			err = w9968cf_i2c_adap_write_byte(cam, addr, command);
-		else if (read_write == I2C_SMBUS_READ)
-			for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
-				err = w9968cf_i2c_adap_read_byte(cam, addr,
-							 &data->byte);
-				if (err) {
-					if (w9968cf_smbus_refresh_bus(cam)) {
-						err = -EIO;
-						break;
-					}
-				} else
-					break;
-			}
-	} else if (size == I2C_SMBUS_BYTE_DATA) {
-		addr <<= 1;
-
-		if (read_write == I2C_SMBUS_WRITE)
-			err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr,
-							  command, data->byte);
-		else if (read_write == I2C_SMBUS_READ) {
-			for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
-				err = w9968cf_i2c_adap_read_byte_data(cam,addr,
-							 command, &data->byte);
-				if (err) {
-					if (w9968cf_smbus_refresh_bus(cam)) {
-						err = -EIO;
-						break;
-					}
-				} else
-					break;
-			}
-
-		} else
-			return -EINVAL;
-
-	} else {
-		DBG(4, "Unsupported I2C transfer mode (%d)", size)
-		return -EINVAL;
-	}
-	return err;
-}
-
-
-static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
-{
-	return I2C_FUNC_SMBUS_READ_BYTE |
-	       I2C_FUNC_SMBUS_READ_BYTE_DATA  |
-	       I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
-}
-
-
-static int w9968cf_i2c_init(struct w9968cf_device* cam)
-{
-	int err = 0;
-
-	static struct i2c_algorithm algo = {
-		.smbus_xfer =    w9968cf_i2c_smbus_xfer,
-		.functionality = w9968cf_i2c_func,
-	};
-
-	static struct i2c_adapter adap = {
-		.owner =             THIS_MODULE,
-		.algo =              &algo,
-	};
-
-	memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
-	strcpy(cam->i2c_adapter.name, "w9968cf");
-	cam->i2c_adapter.dev.parent = &cam->usbdev->dev;
-	i2c_set_adapdata(&cam->i2c_adapter, &cam->v4l2_dev);
-
-	DBG(6, "Registering I2C adapter with kernel...")
-
-	err = i2c_add_adapter(&cam->i2c_adapter);
-	if (err)
-		DBG(1, "Failed to register the I2C adapter")
-	else
-		DBG(5, "I2C adapter registered")
-
-	return err;
-}
-
-
-
-/****************************************************************************
- * Helper functions                                                         *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
-  Turn on the LED on some webcams. A beep should be heard too.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_turn_on_led(struct w9968cf_device* cam)
-{
-	int err = 0;
-
-	err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */
-	err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
-	err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
-	err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */
-	err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */
-	err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */
-
-	if (err)
-		DBG(2, "Couldn't turn on the LED")
-
-	DBG(5, "LED turned on")
-
-	return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write some registers for the device initialization.
-  This function is called once on open().
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_init_chip(struct w9968cf_device* cam)
-{
-	unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2,
-		      y0 = 0x0000,
-		      u0 = y0 + hw_bufsize/2,
-		      v0 = u0 + hw_bufsize/4,
-		      y1 = v0 + hw_bufsize/4,
-		      u1 = y1 + hw_bufsize/2,
-		      v1 = u1 + hw_bufsize/4;
-	int err = 0;
-
-	err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */
-	err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */
-
-	err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */
-	err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */
-
-	err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */
-	err += w9968cf_write_reg(cam, y0 >> 16, 0x21);    /* Y buf.0, high */
-	err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */
-	err += w9968cf_write_reg(cam, u0 >> 16, 0x25);    /* U buf.0, high */
-	err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */
-	err += w9968cf_write_reg(cam, v0 >> 16, 0x29);    /* V buf.0, high */
-
-	err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */
-	err += w9968cf_write_reg(cam, y1 >> 16, 0x23);    /* Y buf.1, high */
-	err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */
-	err += w9968cf_write_reg(cam, u1 >> 16, 0x27);    /* U buf.1, high */
-	err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */
-	err += w9968cf_write_reg(cam, v1 >> 16, 0x2b);    /* V buf.1, high */
-
-	err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */
-	err += w9968cf_write_reg(cam, y1 >> 16, 0x33);    /* JPEG buf 0 high */
-
-	err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */
-	err += w9968cf_write_reg(cam, y1 >> 16, 0x35);    /* JPEG bug 1 high */
-
-	err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */
-	err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/
-	err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */
-	err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */
-
-	err += w9968cf_set_picture(cam, cam->picture); /* this before */
-	err += w9968cf_set_window(cam, cam->window);
-
-	if (err)
-		DBG(1, "Chip initialization failed")
-	else
-		DBG(5, "Chip successfully initialized")
-
-	return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Return non-zero if the palette is supported, 0 otherwise.
-  --------------------------------------------------------------------------*/
-static inline u16 w9968cf_valid_palette(u16 palette)
-{
-	u8 i = 0;
-	while (w9968cf_formatlist[i].palette != 0) {
-		if (palette == w9968cf_formatlist[i].palette)
-			return palette;
-		i++;
-	}
-	return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Return the depth corresponding to the given palette.
-  Palette _must_ be supported !
-  --------------------------------------------------------------------------*/
-static inline u16 w9968cf_valid_depth(u16 palette)
-{
-	u8 i=0;
-	while (w9968cf_formatlist[i].palette != palette)
-		i++;
-
-	return w9968cf_formatlist[i].depth;
-}
-
-
-/*--------------------------------------------------------------------------
-  Return non-zero if the format requires decompression, 0 otherwise.
-  --------------------------------------------------------------------------*/
-static inline u8 w9968cf_need_decompression(u16 palette)
-{
-	u8 i = 0;
-	while (w9968cf_formatlist[i].palette != 0) {
-		if (palette == w9968cf_formatlist[i].palette)
-			return w9968cf_formatlist[i].compression;
-		i++;
-	}
-	return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Change the picture settings of the camera.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
-{
-	u16 fmt, hw_depth, hw_palette, reg_v = 0x0000;
-	int err = 0;
-
-	/* Make sure we are using a valid depth */
-	pict.depth = w9968cf_valid_depth(pict.palette);
-
-	fmt = pict.palette;
-
-	hw_depth = pict.depth; /* depth used by the winbond chip */
-	hw_palette = pict.palette; /* palette used by the winbond chip */
-
-	/* VS & HS polarities */
-	reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11);
-
-	switch (fmt)
-	{
-		case VIDEO_PALETTE_UYVY:
-			reg_v |= 0x0000;
-			cam->vpp_flag = VPP_NONE;
-			break;
-		case VIDEO_PALETTE_YUV422P:
-			reg_v |= 0x0002;
-			cam->vpp_flag = VPP_DECOMPRESSION;
-			break;
-		case VIDEO_PALETTE_YUV420:
-		case VIDEO_PALETTE_YUV420P:
-			reg_v |= 0x0003;
-			cam->vpp_flag = VPP_DECOMPRESSION;
-			break;
-		case VIDEO_PALETTE_YUYV:
-		case VIDEO_PALETTE_YUV422:
-			reg_v |= 0x0000;
-			cam->vpp_flag = VPP_SWAP_YUV_BYTES;
-			hw_palette = VIDEO_PALETTE_UYVY;
-			break;
-		/* Original video is used instead of RGBX palettes.
-		   Software conversion later. */
-		case VIDEO_PALETTE_GREY:
-		case VIDEO_PALETTE_RGB555:
-		case VIDEO_PALETTE_RGB565:
-		case VIDEO_PALETTE_RGB24:
-		case VIDEO_PALETTE_RGB32:
-			reg_v |= 0x0000; /* UYVY 16 bit is used */
-			hw_depth = 16;
-			hw_palette = VIDEO_PALETTE_UYVY;
-			cam->vpp_flag = VPP_UYVY_TO_RGBX;
-			break;
-	}
-
-	/* NOTE: due to memory issues, it is better to disable the hardware
-		 double buffering during compression */
-	if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION))
-		reg_v |= 0x0080;
-
-	if (cam->clamping)
-		reg_v |= 0x0020;
-
-	if (cam->filter_type == 1)
-		reg_v |= 0x0008;
-	else if (cam->filter_type == 2)
-		reg_v |= 0x000c;
-
-	if ((err = w9968cf_write_reg(cam, reg_v, 0x16)))
-		goto error;
-
-	if ((err = w9968cf_sensor_update_picture(cam, pict)))
-		goto error;
-
-	/* If all went well, update the device data structure */
-	memcpy(&cam->picture, &pict, sizeof(pict));
-	cam->hw_depth = hw_depth;
-	cam->hw_palette = hw_palette;
-
-	/* Settings changed, so we clear the frame buffers */
-	memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
-
-	DBG(4, "Palette is %s, depth is %u bpp",
-	    symbolic(v4l1_plist, pict.palette), pict.depth)
-
-	return 0;
-
-error:
-	DBG(1, "Failed to change picture settings")
-	return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Change the capture area size of the camera.
-  This function _must_ be called _after_ w9968cf_set_picture().
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
-{
-	u16 x, y, w, h, scx, scy, cw, ch, ax, ay;
-	unsigned long fw, fh;
-	struct ovcamchip_window s_win;
-	int err = 0;
-
-	/* Work around to avoid FP arithmetics */
-	#define SC(x) ((x) << 10)
-	#define UNSC(x) ((x) >> 10)
-
-	/* Make sure we are using a supported resolution */
-	if ((err = w9968cf_adjust_window_size(cam, &win.width, &win.height)))
-		goto error;
-
-	/* Scaling factors */
-	fw = SC(win.width) / cam->maxwidth;
-	fh = SC(win.height) / cam->maxheight;
-
-	/* Set up the width and height values used by the chip */
-	if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) {
-		cam->vpp_flag |= VPP_UPSCALE;
-		/* Calculate largest w,h mantaining the same w/h ratio */
-		w = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh;
-		h = (fw >= fh) ? SC(win.height)/fw : cam->maxheight;
-		if (w < cam->minwidth) /* just in case */
-			w = cam->minwidth;
-		if (h < cam->minheight) /* just in case */
-			h = cam->minheight;
-	} else {
-		cam->vpp_flag &= ~VPP_UPSCALE;
-		w = win.width;
-		h = win.height;
-	}
-
-	/* x,y offsets of the cropped area */
-	scx = cam->start_cropx;
-	scy = cam->start_cropy;
-
-	/* Calculate cropped area manteining the right w/h ratio */
-	if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) {
-		cw = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh;
-		ch = (fw >= fh) ? SC(win.height)/fw : cam->maxheight;
-	} else {
-		cw = w;
-		ch = h;
-	}
-
-	/* Setup the window of the sensor */
-	s_win.format = VIDEO_PALETTE_UYVY;
-	s_win.width = cam->maxwidth;
-	s_win.height = cam->maxheight;
-	s_win.quarter = 0; /* full progressive video */
-
-	/* Center it */
-	s_win.x = (s_win.width - cw) / 2;
-	s_win.y = (s_win.height - ch) / 2;
-
-	/* Clock divisor */
-	if (cam->clockdiv >= 0)
-		s_win.clockdiv = cam->clockdiv; /* manual override */
-	else
-		switch (cam->sensor) {
-			case CC_OV6620:
-				s_win.clockdiv = 0;
-				break;
-			case CC_OV6630:
-				s_win.clockdiv = 0;
-				break;
-			case CC_OV76BE:
-			case CC_OV7610:
-			case CC_OV7620:
-				s_win.clockdiv = 0;
-				break;
-			default:
-				s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR;
-		}
-
-	/* We have to scale win.x and win.y offsets */
-	if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
-	     || (cam->vpp_flag & VPP_UPSCALE) ) {
-		ax = SC(win.x)/fw;
-		ay = SC(win.y)/fh;
-	} else {
-		ax = win.x;
-		ay = win.y;
-	}
-
-	if ((ax + cw) > cam->maxwidth)
-		ax = cam->maxwidth - cw;
-
-	if ((ay + ch) > cam->maxheight)
-		ay = cam->maxheight - ch;
-
-	/* Adjust win.x, win.y */
-	if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
-	     || (cam->vpp_flag & VPP_UPSCALE) ) {
-		win.x = UNSC(ax*fw);
-		win.y = UNSC(ay*fh);
-	} else {
-		win.x = ax;
-		win.y = ay;
-	}
-
-	/* Offsets used by the chip */
-	x = ax + s_win.x;
-	y = ay + s_win.y;
-
-	/* Go ! */
-	if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win)))
-		goto error;
-
-	err += w9968cf_write_reg(cam, scx + x, 0x10);
-	err += w9968cf_write_reg(cam, scy + y, 0x11);
-	err += w9968cf_write_reg(cam, scx + x + cw, 0x12);
-	err += w9968cf_write_reg(cam, scy + y + ch, 0x13);
-	err += w9968cf_write_reg(cam, w, 0x14);
-	err += w9968cf_write_reg(cam, h, 0x15);
-
-	/* JPEG width & height */
-	err += w9968cf_write_reg(cam, w, 0x30);
-	err += w9968cf_write_reg(cam, h, 0x31);
-
-	/* Y & UV frame buffer strides (in WORD) */
-	if (cam->vpp_flag & VPP_DECOMPRESSION) {
-		err += w9968cf_write_reg(cam, w/2, 0x2c);
-		err += w9968cf_write_reg(cam, w/4, 0x2d);
-	} else
-		err += w9968cf_write_reg(cam, w, 0x2c);
-
-	if (err)
-		goto error;
-
-	/* If all went well, update the device data structure */
-	memcpy(&cam->window, &win, sizeof(win));
-	cam->hw_width = w;
-	cam->hw_height = h;
-
-	/* Settings changed, so we clear the frame buffers */
-	memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
-
-	DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)",
-	    win.width, win.height, win.x, win.y)
-
-	PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, "
-	      "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u",
-	      x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y,
-	      win.width, win.height)
-
-	return 0;
-
-error:
-	DBG(1, "Failed to change the capture area size")
-	return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Adjust the asked values for window width and height.
-  Return 0 on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_adjust_window_size(struct w9968cf_device *cam, u32 *width, u32 *height)
-{
-	unsigned int maxw, maxh, align;
-
-	maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
-	       w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
-			   : cam->maxwidth;
-	maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
-	       w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
-			   : cam->maxheight;
-	align = (cam->vpp_flag & VPP_DECOMPRESSION) ? 4 : 0;
-
-	v4l_bound_align_image(width, cam->minwidth, maxw, align,
-			      height, cam->minheight, maxh, align, 0);
-
-	PDBGG("Window size adjusted w=%u, h=%u ", *width, *height)
-
-	return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Initialize the FIFO list of requested frames.
-  --------------------------------------------------------------------------*/
-static void w9968cf_init_framelist(struct w9968cf_device* cam)
-{
-	u8 i;
-
-	for (i = 0; i < cam->nbuffers; i++) {
-		cam->requested_frame[i] = NULL;
-		cam->frame[i].queued = 0;
-		cam->frame[i].status = F_UNUSED;
-	}
-}
-
-
-/*--------------------------------------------------------------------------
-  Add a frame in the FIFO list of requested frames.
-  This function is called in process context.
-  --------------------------------------------------------------------------*/
-static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num)
-{
-	u8 f;
-	unsigned long lock_flags;
-
-	spin_lock_irqsave(&cam->flist_lock, lock_flags);
-
-	for (f=0; cam->requested_frame[f] != NULL; f++);
-	cam->requested_frame[f] = &cam->frame[f_num];
-	cam->frame[f_num].queued = 1;
-	cam->frame[f_num].status = F_UNUSED; /* clear the status */
-
-	spin_unlock_irqrestore(&cam->flist_lock, lock_flags);
-
-	DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f)
-}
-
-
-/*--------------------------------------------------------------------------
-  Read, store and remove the first pointer in the FIFO list of requested
-  frames. This function is called in interrupt context.
-  --------------------------------------------------------------------------*/
-static void
-w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep)
-{
-	u8 i;
-
-	spin_lock(&cam->flist_lock);
-
-	*framep = cam->requested_frame[0];
-
-	/* Shift the list of pointers */
-	for (i = 0; i < cam->nbuffers-1; i++)
-		cam->requested_frame[i] = cam->requested_frame[i+1];
-	cam->requested_frame[i] = NULL;
-
-	spin_unlock(&cam->flist_lock);
-
-	DBG(6,"Popped frame #%d from the list", (*framep)->number)
-}
-
-
-/*--------------------------------------------------------------------------
-  High-level video post-processing routine on grabbed frames.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_postprocess_frame(struct w9968cf_device* cam,
-			  struct w9968cf_frame_t* fr)
-{
-	void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp;
-	u16 w = cam->window.width,
-	    h = cam->window.height,
-	    d = cam->picture.depth,
-	    fmt = cam->picture.palette,
-	    rgb = cam->force_rgb,
-	    hw_w = cam->hw_width,
-	    hw_h = cam->hw_height,
-	    hw_d = cam->hw_depth;
-	int err = 0;
-
-	#define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;}
-
-	if (cam->vpp_flag & VPP_DECOMPRESSION) {
-		memcpy(pOut, pIn, fr->length);
-		_PSWAP(pIn, pOut)
-		err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut);
-		PDBGG("Compressed frame length: %lu",(unsigned long)fr->length)
-		fr->length = (hw_w*hw_h*hw_d)/8;
-		_PSWAP(pIn, pOut)
-		if (err) {
-			DBG(4, "An error occurred while decoding the frame: "
-			       "%s", symbolic(decoder_errlist, err))
-			return err;
-		} else
-			DBG(6, "Frame decoded")
-	}
-
-	if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) {
-		w9968cf_vpp->swap_yuvbytes(pIn, fr->length);
-		DBG(6, "Original UYVY component ordering changed")
-	}
-
-	if (cam->vpp_flag & VPP_UPSCALE) {
-		w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h);
-		fr->length = (w*h*hw_d)/8;
-		_PSWAP(pIn, pOut)
-		DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u",
-		    hw_w, hw_h, hw_d, w, h)
-	}
-
-	if (cam->vpp_flag & VPP_UYVY_TO_RGBX) {
-		w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb);
-		fr->length = (w*h*d)/8;
-		_PSWAP(pIn, pOut)
-		DBG(6, "UYVY-16bit to %s conversion done",
-		    symbolic(v4l1_plist, fmt))
-	}
-
-	if (pOut == fr->buffer)
-		memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length);
-
-	return 0;
-}
-
-
-
-/****************************************************************************
- * Image sensor control routines                                            *
- ****************************************************************************/
-
-static int
-w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val)
-{
-	struct ovcamchip_control ctl;
-	int err;
-
-	ctl.id = cid;
-	ctl.value = val;
-
-	err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl);
-
-	return err;
-}
-
-
-static int
-w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
-{
-	struct ovcamchip_control ctl;
-	int err;
-
-	ctl.id = cid;
-
-	err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl);
-	if (!err)
-		*val = ctl.value;
-
-	return err;
-}
-
-
-static int
-w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
-{
-	int rc;
-
-	rc = v4l2_subdev_call(cam->sensor_sd, core, ioctl, cmd, arg);
-	/* The I2C driver returns -EPERM on non-supported controls */
-	return (rc < 0 && rc != -EPERM) ? rc : 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Update some settings of the image sensor.
-  Returns: 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_sensor_update_settings(struct w9968cf_device* cam)
-{
-	int err = 0;
-
-	/* Auto brightness */
-	err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT,
-					 cam->auto_brt);
-	if (err)
-		return err;
-
-	/* Auto exposure */
-	err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP,
-					 cam->auto_exp);
-	if (err)
-		return err;
-
-	/* Banding filter */
-	err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT,
-					 cam->bandfilt);
-	if (err)
-		return err;
-
-	/* Light frequency */
-	err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ,
-					 cam->lightfreq);
-	if (err)
-		return err;
-
-	/* Back light */
-	err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT,
-					 cam->backlight);
-	if (err)
-		return err;
-
-	/* Mirror */
-	err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR,
-					 cam->mirror);
-	if (err)
-		return err;
-
-	return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Get some current picture settings from the image sensor and update the
-  internal 'picture' structure of the camera.
-  Returns: 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_sensor_get_picture(struct w9968cf_device* cam)
-{
-	int err, v;
-
-	err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v);
-	if (err)
-		return err;
-	cam->picture.contrast = v;
-
-	err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v);
-	if (err)
-		return err;
-	cam->picture.brightness = v;
-
-	err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v);
-	if (err)
-		return err;
-	cam->picture.colour = v;
-
-	err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v);
-	if (err)
-		return err;
-	cam->picture.hue = v;
-
-	DBG(5, "Got picture settings from the image sensor")
-
-	PDBGG("Brightness, contrast, hue, colour, whiteness are "
-	      "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast,
-	      cam->picture.hue, cam->picture.colour, cam->picture.whiteness)
-
-	return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Update picture settings of the image sensor.
-  Returns: 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_sensor_update_picture(struct w9968cf_device* cam,
-			      struct video_picture pict)
-{
-	int err = 0;
-
-	if ((!cam->sensor_initialized)
-	    || pict.contrast != cam->picture.contrast) {
-		err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT,
-						 pict.contrast);
-		if (err)
-			goto fail;
-		DBG(4, "Contrast changed from %u to %u",
-		    cam->picture.contrast, pict.contrast)
-		cam->picture.contrast = pict.contrast;
-	}
-
-	if (((!cam->sensor_initialized) ||
-	    pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) {
-		err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT,
-						 pict.brightness);
-		if (err)
-			goto fail;
-		DBG(4, "Brightness changed from %u to %u",
-		    cam->picture.brightness, pict.brightness)
-		cam->picture.brightness = pict.brightness;
-	}
-
-	if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) {
-		err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT,
-						 pict.colour);
-		if (err)
-			goto fail;
-		DBG(4, "Colour changed from %u to %u",
-		    cam->picture.colour, pict.colour)
-		cam->picture.colour = pict.colour;
-	}
-
-	if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) {
-		err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE,
-						 pict.hue);
-		if (err)
-			goto fail;
-		DBG(4, "Hue changed from %u to %u",
-		    cam->picture.hue, pict.hue)
-		cam->picture.hue = pict.hue;
-	}
-
-	return 0;
-
-fail:
-	DBG(4, "Failed to change sensor picture setting")
-	return err;
-}
-
-
-
-/****************************************************************************
- * Camera configuration                                                     *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
-  This function is called when a supported image sensor is detected.
-  Return 0 if the initialization succeeds, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_sensor_init(struct w9968cf_device* cam)
-{
-	int err = 0;
-
-	if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE,
-				      &cam->monochrome)))
-		goto error;
-
-	if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE,
-				      &cam->sensor)))
-		goto error;
-
-	/* NOTE: Make sure width and height are a multiple of 16 */
-	switch (v4l2_i2c_subdev_addr(cam->sensor_sd)) {
-		case OV6xx0_SID:
-			cam->maxwidth = 352;
-			cam->maxheight = 288;
-			cam->minwidth = 64;
-			cam->minheight = 48;
-			break;
-		case OV7xx0_SID:
-			cam->maxwidth = 640;
-			cam->maxheight = 480;
-			cam->minwidth = 64;
-			cam->minheight = 48;
-			break;
-		default:
-			DBG(1, "Not supported image sensor detected for %s",
-			    symbolic(camlist, cam->id))
-			return -EINVAL;
-	}
-
-	/* These values depend on the ones in the ovxxx0.c sources */
-	switch (cam->sensor) {
-		case CC_OV7620:
-			cam->start_cropx = 287;
-			cam->start_cropy = 35;
-			/* Seems to work around a bug in the image sensor */
-			cam->vs_polarity = 1;
-			cam->hs_polarity = 1;
-			break;
-		default:
-			cam->start_cropx = 320;
-			cam->start_cropy = 35;
-			cam->vs_polarity = 1;
-			cam->hs_polarity = 0;
-	}
-
-	if ((err = w9968cf_sensor_update_settings(cam)))
-		goto error;
-
-	if ((err = w9968cf_sensor_update_picture(cam, cam->picture)))
-		goto error;
-
-	cam->sensor_initialized = 1;
-
-	DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor))
-	return 0;
-
-error:
-	cam->sensor_initialized = 0;
-	cam->sensor = CC_UNKNOWN;
-	DBG(1, "Image sensor initialization failed for %s (%s). "
-	       "Try to detach and attach this device again",
-	    symbolic(camlist, cam->id), video_device_node_name(cam->v4ldev))
-	return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Fill some basic fields in the main device data structure.
-  This function is called once on w9968cf_usb_probe() for each recognized
-  camera.
-  --------------------------------------------------------------------------*/
-static void
-w9968cf_configure_camera(struct w9968cf_device* cam,
-			 struct usb_device* udev,
-			 enum w9968cf_model_id mod_id,
-			 const unsigned short dev_nr)
-{
-	mutex_init(&cam->fileop_mutex);
-	init_waitqueue_head(&cam->open);
-	spin_lock_init(&cam->urb_lock);
-	spin_lock_init(&cam->flist_lock);
-
-	cam->users = 0;
-	cam->disconnected = 0;
-	cam->id = mod_id;
-	cam->sensor = CC_UNKNOWN;
-	cam->sensor_initialized = 0;
-
-	/* Calculate the alternate setting number (from 1 to 16)
-	   according to the 'packet_size' module parameter */
-	if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE)
-		packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE;
-	for (cam->altsetting = 1;
-	     packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1];
-	     cam->altsetting++);
-
-	cam->max_buffers = (max_buffers[dev_nr] < 2 ||
-			    max_buffers[dev_nr] > W9968CF_MAX_BUFFERS)
-			   ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr];
-
-	cam->double_buffer = (double_buffer[dev_nr] == 0 ||
-			      double_buffer[dev_nr] == 1)
-			     ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER;
-
-	cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1)
-			? (u8)clamping[dev_nr] : W9968CF_CLAMPING;
-
-	cam->filter_type = (filter_type[dev_nr] == 0 ||
-			    filter_type[dev_nr] == 1 ||
-			    filter_type[dev_nr] == 2)
-			   ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE;
-
-	cam->capture = 1;
-
-	cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1)
-			 ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW;
-
-	cam->decompression = (decompression[dev_nr] == 0 ||
-			      decompression[dev_nr] == 1 ||
-			      decompression[dev_nr] == 2)
-			     ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION;
-
-	cam->upscaling = (upscaling[dev_nr] == 0 ||
-			  upscaling[dev_nr] == 1)
-			 ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING;
-
-	cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1)
-			? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT;
-
-	cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1)
-			? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP;
-
-	cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60)
-			 ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ;
-
-	cam->bandfilt = (bandingfilter[dev_nr] == 0 ||
-			 bandingfilter[dev_nr] == 1)
-			? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER;
-
-	cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1)
-			 ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT;
-
-	cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0)
-			? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV;
-
-	cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1)
-		      ? (u8)mirror[dev_nr] : W9968CF_MIRROR;
-
-	cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1)
-			  ? monochrome[dev_nr] : W9968CF_MONOCHROME;
-
-	cam->picture.brightness = (u16)brightness[dev_nr];
-	cam->picture.hue = (u16)hue[dev_nr];
-	cam->picture.colour = (u16)colour[dev_nr];
-	cam->picture.contrast = (u16)contrast[dev_nr];
-	cam->picture.whiteness = (u16)whiteness[dev_nr];
-	if (w9968cf_valid_palette((u16)force_palette[dev_nr])) {
-		cam->picture.palette = (u16)force_palette[dev_nr];
-		cam->force_palette = 1;
-	} else {
-		cam->force_palette = 0;
-		if (cam->decompression == 0)
-			cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF;
-		else if (cam->decompression == 1)
-			cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE;
-		else
-			cam->picture.palette = W9968CF_PALETTE_DECOMP_ON;
-	}
-	cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
-
-	cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1)
-			 ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB;
-
-	cam->window.x = 0;
-	cam->window.y = 0;
-	cam->window.width = W9968CF_WIDTH;
-	cam->window.height = W9968CF_HEIGHT;
-	cam->window.chromakey = 0;
-	cam->window.clipcount = 0;
-	cam->window.flags = 0;
-
-	DBG(3, "%s configured with settings #%u:",
-	    symbolic(camlist, cam->id), dev_nr)
-
-	DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes",
-	    wMaxPacketSize[cam->altsetting-1])
-
-	DBG(3, "- Number of requested video frame buffers: %u",
-	    cam->max_buffers)
-
-	if (cam->double_buffer)
-		DBG(3, "- Hardware double buffering enabled")
-	else
-		DBG(3, "- Hardware double buffering disabled")
-
-	if (cam->filter_type == 0)
-		DBG(3, "- Video filtering disabled")
-	else if (cam->filter_type == 1)
-		DBG(3, "- Video filtering enabled: type 1-2-1")
-	else if (cam->filter_type == 2)
-		DBG(3, "- Video filtering enabled: type 2-3-6-3-2")
-
-	if (cam->clamping)
-		DBG(3, "- Video data clamping (CCIR-601 format) enabled")
-	else
-		DBG(3, "- Video data clamping (CCIR-601 format) disabled")
-
-	if (cam->largeview)
-		DBG(3, "- Large view enabled")
-	else
-		DBG(3, "- Large view disabled")
-
-	if ((cam->decompression) == 0 && (!cam->force_palette))
-		DBG(3, "- Decompression disabled")
-	else if ((cam->decompression) == 1 && (!cam->force_palette))
-		DBG(3, "- Decompression forced")
-	else if ((cam->decompression) == 2 && (!cam->force_palette))
-		DBG(3, "- Decompression allowed")
-
-	if (cam->upscaling)
-		DBG(3, "- Software image scaling enabled")
-	else
-		DBG(3, "- Software image scaling disabled")
-
-	if (cam->force_palette)
-		DBG(3, "- Image palette forced to %s",
-		    symbolic(v4l1_plist, cam->picture.palette))
-
-	if (cam->force_rgb)
-		DBG(3, "- RGB component ordering will be used instead of BGR")
-
-	if (cam->auto_brt)
-		DBG(3, "- Auto brightness enabled")
-	else
-		DBG(3, "- Auto brightness disabled")
-
-	if (cam->auto_exp)
-		DBG(3, "- Auto exposure enabled")
-	else
-		DBG(3, "- Auto exposure disabled")
-
-	if (cam->backlight)
-		DBG(3, "- Backlight exposure algorithm enabled")
-	else
-		DBG(3, "- Backlight exposure algorithm disabled")
-
-	if (cam->mirror)
-		DBG(3, "- Mirror enabled")
-	else
-		DBG(3, "- Mirror disabled")
-
-	if (cam->bandfilt)
-		DBG(3, "- Banding filter enabled")
-	else
-		DBG(3, "- Banding filter disabled")
-
-	DBG(3, "- Power lighting frequency: %u", cam->lightfreq)
-
-	if (cam->clockdiv == -1)
-		DBG(3, "- Automatic clock divisor enabled")
-	else
-		DBG(3, "- Clock divisor: %d", cam->clockdiv)
-
-	if (cam->monochrome)
-		DBG(3, "- Image sensor used as monochrome")
-	else
-		DBG(3, "- Image sensor not used as monochrome")
-}
-
-
-/*--------------------------------------------------------------------------
-  If the video post-processing module is not loaded, some parameters
-  must be overridden.
-  --------------------------------------------------------------------------*/
-static void w9968cf_adjust_configuration(struct w9968cf_device* cam)
-{
-	if (!w9968cf_vpp) {
-		if (cam->decompression == 1) {
-			cam->decompression = 2;
-			DBG(2, "Video post-processing module not found: "
-			       "'decompression' parameter forced to 2")
-		}
-		if (cam->upscaling) {
-			cam->upscaling = 0;
-			DBG(2, "Video post-processing module not found: "
-			       "'upscaling' parameter forced to 0")
-		}
-		if (cam->picture.palette != VIDEO_PALETTE_UYVY) {
-			cam->force_palette = 0;
-			DBG(2, "Video post-processing module not found: "
-			       "'force_palette' parameter forced to 0")
-		}
-		cam->picture.palette = VIDEO_PALETTE_UYVY;
-		cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
-	}
-}
-
-
-/*--------------------------------------------------------------------------
-  Release the resources used by the driver.
-  This function is called on disconnect
-  (or on close if deallocation has been deferred)
-  --------------------------------------------------------------------------*/
-static void w9968cf_release_resources(struct w9968cf_device* cam)
-{
-	mutex_lock(&w9968cf_devlist_mutex);
-
-	DBG(2, "V4L device deregistered: %s",
-	    video_device_node_name(cam->v4ldev))
-
-	video_unregister_device(cam->v4ldev);
-	list_del(&cam->v4llist);
-	i2c_del_adapter(&cam->i2c_adapter);
-	w9968cf_deallocate_memory(cam);
-	kfree(cam->control_buffer);
-	kfree(cam->data_buffer);
-	v4l2_device_unregister(&cam->v4l2_dev);
-
-	mutex_unlock(&w9968cf_devlist_mutex);
-}
-
-
-
-/****************************************************************************
- * Video4Linux interface                                                    *
- ****************************************************************************/
-
-static int w9968cf_open(struct file *filp)
-{
-	struct w9968cf_device* cam;
-	int err;
-
-	/* This the only safe way to prevent race conditions with disconnect */
-	if (!down_read_trylock(&w9968cf_disconnect))
-		return -EAGAIN;
-
-	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-	mutex_lock(&cam->dev_mutex);
-
-	if (cam->sensor == CC_UNKNOWN) {
-		DBG(2, "No supported image sensor has been detected by the "
-		       "'ovcamchip' module for the %s (%s). Make sure "
-		       "it is loaded *before* (re)connecting the camera.",
-		    symbolic(camlist, cam->id),
-		    video_device_node_name(cam->v4ldev))
-		mutex_unlock(&cam->dev_mutex);
-		up_read(&w9968cf_disconnect);
-		return -ENODEV;
-	}
-
-	if (cam->users) {
-		DBG(2, "%s (%s) has been already occupied by '%s'",
-		    symbolic(camlist, cam->id),
-		    video_device_node_name(cam->v4ldev), cam->command)
-		if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
-			mutex_unlock(&cam->dev_mutex);
-			up_read(&w9968cf_disconnect);
-			return -EWOULDBLOCK;
-		}
-		mutex_unlock(&cam->dev_mutex);
-		err = wait_event_interruptible_exclusive(cam->open,
-							 cam->disconnected ||
-							 !cam->users);
-		if (err) {
-			up_read(&w9968cf_disconnect);
-			return err;
-		}
-		if (cam->disconnected) {
-			up_read(&w9968cf_disconnect);
-			return -ENODEV;
-		}
-		mutex_lock(&cam->dev_mutex);
-	}
-
-	DBG(5, "Opening '%s', %s ...",
-	    symbolic(camlist, cam->id), video_device_node_name(cam->v4ldev))
-
-	cam->streaming = 0;
-	cam->misconfigured = 0;
-
-	w9968cf_adjust_configuration(cam);
-
-	if ((err = w9968cf_allocate_memory(cam)))
-		goto deallocate_memory;
-
-	if ((err = w9968cf_init_chip(cam)))
-		goto deallocate_memory;
-
-	if ((err = w9968cf_start_transfer(cam)))
-		goto deallocate_memory;
-
-	filp->private_data = cam;
-
-	cam->users++;
-	strcpy(cam->command, current->comm);
-
-	init_waitqueue_head(&cam->wait_queue);
-
-	DBG(5, "Video device is open")
-
-	mutex_unlock(&cam->dev_mutex);
-	up_read(&w9968cf_disconnect);
-
-	return 0;
-
-deallocate_memory:
-	w9968cf_deallocate_memory(cam);
-	DBG(2, "Failed to open the video device")
-	mutex_unlock(&cam->dev_mutex);
-	up_read(&w9968cf_disconnect);
-	return err;
-}
-
-
-static int w9968cf_release(struct file *filp)
-{
-	struct w9968cf_device* cam;
-
-	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-	mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
-
-	w9968cf_stop_transfer(cam);
-
-	if (cam->disconnected) {
-		w9968cf_release_resources(cam);
-		mutex_unlock(&cam->dev_mutex);
-		kfree(cam);
-		return 0;
-	}
-
-	cam->users--;
-	w9968cf_deallocate_memory(cam);
-	wake_up_interruptible_nr(&cam->open, 1);
-
-	DBG(5, "Video device closed")
-	mutex_unlock(&cam->dev_mutex);
-	return 0;
-}
-
-
-static ssize_t
-w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
-	struct w9968cf_device* cam;
-	struct w9968cf_frame_t* fr;
-	int err = 0;
-
-	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-	if (filp->f_flags & O_NONBLOCK)
-		return -EWOULDBLOCK;
-
-	if (mutex_lock_interruptible(&cam->fileop_mutex))
-		return -ERESTARTSYS;
-
-	if (cam->disconnected) {
-		DBG(2, "Device not present")
-		mutex_unlock(&cam->fileop_mutex);
-		return -ENODEV;
-	}
-
-	if (cam->misconfigured) {
-		DBG(2, "The camera is misconfigured. Close and open it again.")
-		mutex_unlock(&cam->fileop_mutex);
-		return -EIO;
-	}
-
-	if (!cam->frame[0].queued)
-		w9968cf_push_frame(cam, 0);
-
-	if (!cam->frame[1].queued)
-		w9968cf_push_frame(cam, 1);
-
-	err = wait_event_interruptible(cam->wait_queue,
-				       cam->frame[0].status == F_READY ||
-				       cam->frame[1].status == F_READY ||
-				       cam->disconnected);
-	if (err) {
-		mutex_unlock(&cam->fileop_mutex);
-		return err;
-	}
-	if (cam->disconnected) {
-		mutex_unlock(&cam->fileop_mutex);
-		return -ENODEV;
-	}
-
-	fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1];
-
-	if (w9968cf_vpp)
-		w9968cf_postprocess_frame(cam, fr);
-
-	if (count > fr->length)
-		count = fr->length;
-
-	if (copy_to_user(buf, fr->buffer, count)) {
-		fr->status = F_UNUSED;
-		mutex_unlock(&cam->fileop_mutex);
-		return -EFAULT;
-	}
-	*f_pos += count;
-
-	fr->status = F_UNUSED;
-
-	DBG(5, "%zu bytes read", count)
-
-	mutex_unlock(&cam->fileop_mutex);
-	return count;
-}
-
-
-static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma)
-{
-	struct w9968cf_device* cam = (struct w9968cf_device*)
-				     video_get_drvdata(video_devdata(filp));
-	unsigned long vsize = vma->vm_end - vma->vm_start,
-		      psize = cam->nbuffers * cam->frame[0].size,
-		      start = vma->vm_start,
-		      pos = (unsigned long)cam->frame[0].buffer,
-		      page;
-
-	if (cam->disconnected) {
-		DBG(2, "Device not present")
-		return -ENODEV;
-	}
-
-	if (cam->misconfigured) {
-		DBG(2, "The camera is misconfigured. Close and open it again")
-		return -EIO;
-	}
-
-	PDBGG("mmapping %lu bytes...", vsize)
-
-	if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT))
-		return -EINVAL;
-
-	while (vsize > 0) {
-		page = vmalloc_to_pfn((void *)pos);
-		if (remap_pfn_range(vma, start, page + vma->vm_pgoff,
-						PAGE_SIZE, vma->vm_page_prot))
-			return -EAGAIN;
-		start += PAGE_SIZE;
-		pos += PAGE_SIZE;
-		vsize -= PAGE_SIZE;
-	}
-
-	DBG(5, "mmap method successfully called")
-	return 0;
-}
-
-
-static long
-w9968cf_ioctl(struct file *filp,
-	      unsigned int cmd, unsigned long arg)
-{
-	struct w9968cf_device* cam;
-	long err;
-
-	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-	if (mutex_lock_interruptible(&cam->fileop_mutex))
-		return -ERESTARTSYS;
-
-	if (cam->disconnected) {
-		DBG(2, "Device not present")
-		mutex_unlock(&cam->fileop_mutex);
-		return -ENODEV;
-	}
-
-	if (cam->misconfigured) {
-		DBG(2, "The camera is misconfigured. Close and open it again.")
-		mutex_unlock(&cam->fileop_mutex);
-		return -EIO;
-	}
-
-	err = w9968cf_v4l_ioctl(filp, cmd, (void __user *)arg);
-
-	mutex_unlock(&cam->fileop_mutex);
-	return err;
-}
-
-
-static long w9968cf_v4l_ioctl(struct file *filp,
-			     unsigned int cmd, void __user *arg)
-{
-	struct w9968cf_device* cam;
-	const char* v4l1_ioctls[] = {
-		"?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER",
-		"GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF",
-		"SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO",
-		"SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE",
-		"SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE",
-		"GVBIFMT", "SVBIFMT"
-	};
-
-	#define V4L1_IOCTL(cmd) \
-		((_IOC_NR((cmd)) < ARRAY_SIZE(v4l1_ioctls)) ? \
-		v4l1_ioctls[_IOC_NR((cmd))] : "?")
-
-	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-	switch (cmd) {
-
-	case VIDIOCGCAP: /* get video capability */
-	{
-		struct video_capability cap = {
-			.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
-			.channels = 1,
-			.audios = 0,
-			.minwidth = cam->minwidth,
-			.minheight = cam->minheight,
-		};
-		sprintf(cap.name, "W996[87]CF USB Camera");
-		cap.maxwidth = (cam->upscaling && w9968cf_vpp)
-			       ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
-				 : cam->maxwidth;
-		cap.maxheight = (cam->upscaling && w9968cf_vpp)
-				? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
-				  : cam->maxheight;
-
-		if (copy_to_user(arg, &cap, sizeof(cap)))
-			return -EFAULT;
-
-		DBG(5, "VIDIOCGCAP successfully called")
-		return 0;
-	}
-
-	case VIDIOCGCHAN: /* get video channel informations */
-	{
-		struct video_channel chan;
-		if (copy_from_user(&chan, arg, sizeof(chan)))
-			return -EFAULT;
-
-		if (chan.channel != 0)
-			return -EINVAL;
-
-		strcpy(chan.name, "Camera");
-		chan.tuners = 0;
-		chan.flags = 0;
-		chan.type = VIDEO_TYPE_CAMERA;
-		chan.norm = VIDEO_MODE_AUTO;
-
-		if (copy_to_user(arg, &chan, sizeof(chan)))
-			return -EFAULT;
-
-		DBG(5, "VIDIOCGCHAN successfully called")
-		return 0;
-	}
-
-	case VIDIOCSCHAN: /* set active channel */
-	{
-		struct video_channel chan;
-
-		if (copy_from_user(&chan, arg, sizeof(chan)))
-			return -EFAULT;
-
-		if (chan.channel != 0)
-			return -EINVAL;
-
-		DBG(5, "VIDIOCSCHAN successfully called")
-		return 0;
-	}
-
-	case VIDIOCGPICT: /* get image properties of the picture */
-	{
-		if (w9968cf_sensor_get_picture(cam))
-			return -EIO;
-
-		if (copy_to_user(arg, &cam->picture, sizeof(cam->picture)))
-			return -EFAULT;
-
-		DBG(5, "VIDIOCGPICT successfully called")
-		return 0;
-	}
-
-	case VIDIOCSPICT: /* change picture settings */
-	{
-		struct video_picture pict;
-		int err = 0;
-
-		if (copy_from_user(&pict, arg, sizeof(pict)))
-			return -EFAULT;
-
-		if ( (cam->force_palette || !w9968cf_vpp)
-		     && pict.palette != cam->picture.palette ) {
-			DBG(4, "Palette %s rejected: only %s is allowed",
-			    symbolic(v4l1_plist, pict.palette),
-			    symbolic(v4l1_plist, cam->picture.palette))
-			return -EINVAL;
-		}
-
-		if (!w9968cf_valid_palette(pict.palette)) {
-			DBG(4, "Palette %s not supported. VIDIOCSPICT failed",
-			    symbolic(v4l1_plist, pict.palette))
-			return -EINVAL;
-		}
-
-		if (!cam->force_palette) {
-		   if (cam->decompression == 0) {
-		      if (w9968cf_need_decompression(pict.palette)) {
-			 DBG(4, "Decompression disabled: palette %s is not "
-				"allowed. VIDIOCSPICT failed",
-			     symbolic(v4l1_plist, pict.palette))
-			 return -EINVAL;
-		      }
-		   } else if (cam->decompression == 1) {
-		      if (!w9968cf_need_decompression(pict.palette)) {
-			 DBG(4, "Decompression forced: palette %s is not "
-				"allowed. VIDIOCSPICT failed",
-			     symbolic(v4l1_plist, pict.palette))
-			 return -EINVAL;
-		      }
-		   }
-		}
-
-		if (pict.depth != w9968cf_valid_depth(pict.palette)) {
-			DBG(4, "Requested depth %u bpp is not valid for %s "
-			       "palette: ignored and changed to %u bpp",
-			    pict.depth, symbolic(v4l1_plist, pict.palette),
-			    w9968cf_valid_depth(pict.palette))
-			pict.depth = w9968cf_valid_depth(pict.palette);
-		}
-
-		if (pict.palette != cam->picture.palette) {
-			if(*cam->requested_frame
-			   || cam->frame_current->queued) {
-				err = wait_event_interruptible
-				      ( cam->wait_queue,
-					cam->disconnected ||
-					(!*cam->requested_frame &&
-					 !cam->frame_current->queued) );
-				if (err)
-					return err;
-				if (cam->disconnected)
-					return -ENODEV;
-			}
-
-			if (w9968cf_stop_transfer(cam))
-				goto ioctl_fail;
-
-			if (w9968cf_set_picture(cam, pict))
-				goto ioctl_fail;
-
-			if (w9968cf_start_transfer(cam))
-				goto ioctl_fail;
-
-		} else if (w9968cf_sensor_update_picture(cam, pict))
-			return -EIO;
-
-
-		DBG(5, "VIDIOCSPICT successfully called")
-		return 0;
-	}
-
-	case VIDIOCSWIN: /* set capture area */
-	{
-		struct video_window win;
-		int err = 0;
-
-		if (copy_from_user(&win, arg, sizeof(win)))
-			return -EFAULT;
-
-		DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, "
-		       "x=%u, y=%u, %ux%u", win.clipcount, win.flags,
-		    win.x, win.y, win.width, win.height)
-
-		if (win.clipcount != 0 || win.flags != 0)
-			return -EINVAL;
-
-		if ((err = w9968cf_adjust_window_size(cam, &win.width,
-						      &win.height))) {
-			DBG(4, "Resolution not supported (%ux%u). "
-			       "VIDIOCSWIN failed", win.width, win.height)
-			return err;
-		}
-
-		if (win.x != cam->window.x ||
-		    win.y != cam->window.y ||
-		    win.width != cam->window.width ||
-		    win.height != cam->window.height) {
-			if(*cam->requested_frame
-			   || cam->frame_current->queued) {
-				err = wait_event_interruptible
-				      ( cam->wait_queue,
-					cam->disconnected ||
-					(!*cam->requested_frame &&
-					 !cam->frame_current->queued) );
-				if (err)
-					return err;
-				if (cam->disconnected)
-					return -ENODEV;
-			}
-
-			if (w9968cf_stop_transfer(cam))
-				goto ioctl_fail;
-
-			/* This _must_ be called before set_window() */
-			if (w9968cf_set_picture(cam, cam->picture))
-				goto ioctl_fail;
-
-			if (w9968cf_set_window(cam, win))
-				goto ioctl_fail;
-
-			if (w9968cf_start_transfer(cam))
-				goto ioctl_fail;
-		}
-
-		DBG(5, "VIDIOCSWIN successfully called. ")
-		return 0;
-	}
-
-	case VIDIOCGWIN: /* get current window properties */
-	{
-		if (copy_to_user(arg,&cam->window,sizeof(struct video_window)))
-			return -EFAULT;
-
-		DBG(5, "VIDIOCGWIN successfully called")
-		return 0;
-	}
-
-	case VIDIOCGMBUF: /* request for memory (mapped) buffer */
-	{
-		struct video_mbuf mbuf;
-		u8 i;
-
-		mbuf.size = cam->nbuffers * cam->frame[0].size;
-		mbuf.frames = cam->nbuffers;
-		for (i = 0; i < cam->nbuffers; i++)
-			mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer -
-					  (unsigned long)cam->frame[0].buffer;
-
-		if (copy_to_user(arg, &mbuf, sizeof(mbuf)))
-			return -EFAULT;
-
-		DBG(5, "VIDIOCGMBUF successfully called")
-		return 0;
-	}
-
-	case VIDIOCMCAPTURE: /* start the capture to a frame */
-	{
-		struct video_mmap mmap;
-		struct w9968cf_frame_t* fr;
-		u32 w, h;
-		int err = 0;
-
-		if (copy_from_user(&mmap, arg, sizeof(mmap)))
-			return -EFAULT;
-
-		DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d",
-		    mmap.frame, symbolic(v4l1_plist, mmap.format),
-		    mmap.width, mmap.height)
-
-		if (mmap.frame >= cam->nbuffers) {
-			DBG(4, "Invalid frame number (%u). "
-			       "VIDIOCMCAPTURE failed", mmap.frame)
-			return -EINVAL;
-		}
-
-		if (mmap.format!=cam->picture.palette &&
-		    (cam->force_palette || !w9968cf_vpp)) {
-			DBG(4, "Palette %s rejected: only %s is allowed",
-			    symbolic(v4l1_plist, mmap.format),
-			    symbolic(v4l1_plist, cam->picture.palette))
-			return -EINVAL;
-		}
-
-		if (!w9968cf_valid_palette(mmap.format)) {
-			DBG(4, "Palette %s not supported. "
-			       "VIDIOCMCAPTURE failed",
-			    symbolic(v4l1_plist, mmap.format))
-			return -EINVAL;
-		}
-
-		if (!cam->force_palette) {
-		   if (cam->decompression == 0) {
-		      if (w9968cf_need_decompression(mmap.format)) {
-			 DBG(4, "Decompression disabled: palette %s is not "
-				"allowed. VIDIOCSPICT failed",
-			     symbolic(v4l1_plist, mmap.format))
-			 return -EINVAL;
-		      }
-		   } else if (cam->decompression == 1) {
-		      if (!w9968cf_need_decompression(mmap.format)) {
-			 DBG(4, "Decompression forced: palette %s is not "
-				"allowed. VIDIOCSPICT failed",
-			     symbolic(v4l1_plist, mmap.format))
-			 return -EINVAL;
-		      }
-		   }
-		}
-
-		w = mmap.width; h = mmap.height;
-		err = w9968cf_adjust_window_size(cam, &w, &h);
-		mmap.width = w; mmap.height = h;
-		if (err) {
-			DBG(4, "Resolution not supported (%dx%d). "
-			       "VIDIOCMCAPTURE failed",
-			    mmap.width, mmap.height)
-			return err;
-		}
-
-		fr = &cam->frame[mmap.frame];
-
-		if (mmap.width  != cam->window.width ||
-		    mmap.height != cam->window.height ||
-		    mmap.format != cam->picture.palette) {
-
-			struct video_window win;
-			struct video_picture pict;
-
-			if(*cam->requested_frame
-			   || cam->frame_current->queued) {
-				DBG(6, "VIDIOCMCAPTURE. Change settings for "
-				       "frame #%u: %dx%d, format %s. Wait...",
-				    mmap.frame, mmap.width, mmap.height,
-				    symbolic(v4l1_plist, mmap.format))
-				err = wait_event_interruptible
-				      ( cam->wait_queue,
-					cam->disconnected ||
-					(!*cam->requested_frame &&
-					 !cam->frame_current->queued) );
-				if (err)
-					return err;
-				if (cam->disconnected)
-					return -ENODEV;
-			}
-
-			memcpy(&win, &cam->window, sizeof(win));
-			memcpy(&pict, &cam->picture, sizeof(pict));
-			win.width = mmap.width;
-			win.height = mmap.height;
-			pict.palette = mmap.format;
-
-			if (w9968cf_stop_transfer(cam))
-				goto ioctl_fail;
-
-			/* This before set_window */
-			if (w9968cf_set_picture(cam, pict))
-				goto ioctl_fail;
-
-			if (w9968cf_set_window(cam, win))
-				goto ioctl_fail;
-
-			if (w9968cf_start_transfer(cam))
-				goto ioctl_fail;
-
-		} else 	if (fr->queued) {
-
-			DBG(6, "Wait until frame #%u is free", mmap.frame)
-
-			err = wait_event_interruptible(cam->wait_queue,
-						       cam->disconnected ||
-						       (!fr->queued));
-			if (err)
-				return err;
-			if (cam->disconnected)
-				return -ENODEV;
-		}
-
-		w9968cf_push_frame(cam, mmap.frame);
-		DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame)
-		return 0;
-	}
-
-	case VIDIOCSYNC: /* wait until the capture of a frame is finished */
-	{
-		unsigned int f_num;
-		struct w9968cf_frame_t* fr;
-		int err = 0;
-
-		if (copy_from_user(&f_num, arg, sizeof(f_num)))
-			return -EFAULT;
-
-		if (f_num >= cam->nbuffers) {
-			DBG(4, "Invalid frame number (%u). "
-			       "VIDIOCMCAPTURE failed", f_num)
-			return -EINVAL;
-		}
-
-		DBG(6, "VIDIOCSYNC called for frame #%u", f_num)
-
-		fr = &cam->frame[f_num];
-
-		switch (fr->status) {
-		case F_UNUSED:
-			if (!fr->queued) {
-				DBG(4, "VIDIOSYNC: Frame #%u not requested!",
-				    f_num)
-				return -EFAULT;
-			}
-		case F_ERROR:
-		case F_GRABBING:
-			err = wait_event_interruptible(cam->wait_queue,
-						       (fr->status == F_READY)
-						       || cam->disconnected);
-			if (err)
-				return err;
-			if (cam->disconnected)
-				return -ENODEV;
-			break;
-		case F_READY:
-			break;
-		}
-
-		if (w9968cf_vpp)
-			w9968cf_postprocess_frame(cam, fr);
-
-		fr->status = F_UNUSED;
-
-		DBG(5, "VIDIOCSYNC(%u) successfully called", f_num)
-		return 0;
-	}
-
-	case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/
-	{
-		struct video_unit unit = {
-			.video = cam->v4ldev->minor,
-			.vbi = VIDEO_NO_UNIT,
-			.radio = VIDEO_NO_UNIT,
-			.audio = VIDEO_NO_UNIT,
-			.teletext = VIDEO_NO_UNIT,
-		};
-
-		if (copy_to_user(arg, &unit, sizeof(unit)))
-			return -EFAULT;
-
-		DBG(5, "VIDIOCGUNIT successfully called")
-		return 0;
-	}
-
-	case VIDIOCKEY:
-		return 0;
-
-	case VIDIOCGFBUF:
-	{
-		if (clear_user(arg, sizeof(struct video_buffer)))
-			return -EFAULT;
-
-		DBG(5, "VIDIOCGFBUF successfully called")
-		return 0;
-	}
-
-	case VIDIOCGTUNER:
-	{
-		struct video_tuner tuner;
-		if (copy_from_user(&tuner, arg, sizeof(tuner)))
-			return -EFAULT;
-
-		if (tuner.tuner != 0)
-			return -EINVAL;
-
-		strcpy(tuner.name, "no_tuner");
-		tuner.rangelow = 0;
-		tuner.rangehigh = 0;
-		tuner.flags = VIDEO_TUNER_NORM;
-		tuner.mode = VIDEO_MODE_AUTO;
-		tuner.signal = 0xffff;
-
-		if (copy_to_user(arg, &tuner, sizeof(tuner)))
-			return -EFAULT;
-
-		DBG(5, "VIDIOCGTUNER successfully called")
-		return 0;
-	}
-
-	case VIDIOCSTUNER:
-	{
-		struct video_tuner tuner;
-		if (copy_from_user(&tuner, arg, sizeof(tuner)))
-			return -EFAULT;
-
-		if (tuner.tuner != 0)
-			return -EINVAL;
-
-		if (tuner.mode != VIDEO_MODE_AUTO)
-			return -EINVAL;
-
-		DBG(5, "VIDIOCSTUNER successfully called")
-		return 0;
-	}
-
-	case VIDIOCSFBUF:
-	case VIDIOCCAPTURE:
-	case VIDIOCGFREQ:
-	case VIDIOCSFREQ:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-	case VIDIOCSPLAYMODE:
-	case VIDIOCSWRITEMODE:
-	case VIDIOCGPLAYINFO:
-	case VIDIOCSMICROCODE:
-	case VIDIOCGVBIFMT:
-	case VIDIOCSVBIFMT:
-		DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s "
-		       "(type 0x%01X, "
-		       "n. 0x%01X, "
-		       "dir. 0x%01X, "
-		       "size 0x%02X)",
-		    V4L1_IOCTL(cmd),
-		    _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
-
-		return -EINVAL;
-
-	default:
-		DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s "
-		       "type 0x%01X, "
-		       "n. 0x%01X, "
-		       "dir. 0x%01X, "
-		       "size 0x%02X",
-		    V4L1_IOCTL(cmd),
-		    _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
-
-		return -ENOIOCTLCMD;
-
-	} /* end of switch */
-
-ioctl_fail:
-	cam->misconfigured = 1;
-	DBG(1, "VIDIOC%s failed because of hardware problems. "
-	       "To use the camera, close and open it again.", V4L1_IOCTL(cmd))
-	return -EFAULT;
-}
-
-
-static const struct v4l2_file_operations w9968cf_fops = {
-	.owner =   THIS_MODULE,
-	.open =    w9968cf_open,
-	.release = w9968cf_release,
-	.read =    w9968cf_read,
-	.ioctl =   w9968cf_ioctl,
-	.mmap =    w9968cf_mmap,
-};
-
-
-
-/****************************************************************************
- * USB probe and V4L registration, disconnect and id_table[] definition     *
- ****************************************************************************/
-
-static int
-w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct w9968cf_device* cam;
-	int err = 0;
-	enum w9968cf_model_id mod_id;
-	struct list_head* ptr;
-	u8 sc = 0; /* number of simultaneous cameras */
-	static unsigned short dev_nr; /* 0 - we are handling device number n */
-	static unsigned short addrs[] = {
-		OV7xx0_SID,
-		OV6xx0_SID,
-		I2C_CLIENT_END
-	};
-
-	if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[0].idVendor &&
-	    le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
-		mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */
-	else if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[1].idVendor &&
-		 le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct)
-		mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */
-	else
-		return -ENODEV;
-
-	cam = (struct w9968cf_device*)
-		  kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
-	if (!cam)
-		return -ENOMEM;
-
-	err = v4l2_device_register(&intf->dev, &cam->v4l2_dev);
-	if (err)
-		goto fail0;
-
-	mutex_init(&cam->dev_mutex);
-	mutex_lock(&cam->dev_mutex);
-
-	cam->usbdev = udev;
-
-	DBG(2, "%s detected", symbolic(camlist, mod_id))
-
-	if (simcams > W9968CF_MAX_DEVICES)
-		simcams = W9968CF_SIMCAMS;
-
-	/* How many cameras are connected ? */
-	mutex_lock(&w9968cf_devlist_mutex);
-	list_for_each(ptr, &w9968cf_dev_list)
-		sc++;
-	mutex_unlock(&w9968cf_devlist_mutex);
-
-	if (sc >= simcams) {
-		DBG(2, "Device rejected: too many connected cameras "
-		       "(max. %u)", simcams)
-		err = -EPERM;
-		goto fail;
-	}
-
-
-	/* Allocate 2 bytes of memory for camera control USB transfers */
-	if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) {
-		DBG(1,"Couldn't allocate memory for camera control transfers")
-		err = -ENOMEM;
-		goto fail;
-	}
-
-	/* Allocate 8 bytes of memory for USB data transfers to the FSB */
-	if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) {
-		DBG(1, "Couldn't allocate memory for data "
-		       "transfers to the FSB")
-		err = -ENOMEM;
-		goto fail;
-	}
-
-	/* Register the V4L device */
-	cam->v4ldev = video_device_alloc();
-	if (!cam->v4ldev) {
-		DBG(1, "Could not allocate memory for a V4L structure")
-		err = -ENOMEM;
-		goto fail;
-	}
-
-	strcpy(cam->v4ldev->name, symbolic(camlist, mod_id));
-	cam->v4ldev->fops = &w9968cf_fops;
-	cam->v4ldev->release = video_device_release;
-	video_set_drvdata(cam->v4ldev, cam);
-	cam->v4ldev->v4l2_dev = &cam->v4l2_dev;
-
-	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-				    video_nr[dev_nr]);
-	if (err) {
-		DBG(1, "V4L device registration failed")
-		if (err == -ENFILE && video_nr[dev_nr] == -1)
-			DBG(2, "Couldn't find a free /dev/videoX node")
-		video_nr[dev_nr] = -1;
-		dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
-		goto fail;
-	}
-
-	DBG(2, "V4L device registered as %s",
-	    video_device_node_name(cam->v4ldev))
-
-	/* Set some basic constants */
-	w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
-
-	/* Add a new entry into the list of V4L registered devices */
-	mutex_lock(&w9968cf_devlist_mutex);
-	list_add(&cam->v4llist, &w9968cf_dev_list);
-	mutex_unlock(&w9968cf_devlist_mutex);
-	dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-	w9968cf_turn_on_led(cam);
-
-	w9968cf_i2c_init(cam);
-	cam->sensor_sd = v4l2_i2c_new_subdev(&cam->v4l2_dev,
-			&cam->i2c_adapter,
-			"ovcamchip", "ovcamchip", 0, addrs);
-
-	usb_set_intfdata(intf, cam);
-	mutex_unlock(&cam->dev_mutex);
-
-	err = w9968cf_sensor_init(cam);
-	return 0;
-
-fail: /* Free unused memory */
-	kfree(cam->control_buffer);
-	kfree(cam->data_buffer);
-	if (cam->v4ldev)
-		video_device_release(cam->v4ldev);
-	mutex_unlock(&cam->dev_mutex);
-	v4l2_device_unregister(&cam->v4l2_dev);
-fail0:
-	kfree(cam);
-	return err;
-}
-
-
-static void w9968cf_usb_disconnect(struct usb_interface* intf)
-{
-	struct w9968cf_device* cam =
-	   (struct w9968cf_device*)usb_get_intfdata(intf);
-
-	if (cam) {
-		down_write(&w9968cf_disconnect);
-		/* Prevent concurrent accesses to data */
-		mutex_lock(&cam->dev_mutex);
-
-		cam->disconnected = 1;
-
-		DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id));
-
-		v4l2_device_disconnect(&cam->v4l2_dev);
-
-		wake_up_interruptible_all(&cam->open);
-
-		if (cam->users) {
-			DBG(2, "The device is open (%s)! "
-			       "Process name: %s. Deregistration and memory "
-			       "deallocation are deferred on close.",
-			    video_device_node_name(cam->v4ldev), cam->command)
-			cam->misconfigured = 1;
-			w9968cf_stop_transfer(cam);
-			wake_up_interruptible(&cam->wait_queue);
-		} else
-			w9968cf_release_resources(cam);
-
-		mutex_unlock(&cam->dev_mutex);
-		up_write(&w9968cf_disconnect);
-
-		if (!cam->users) {
-			kfree(cam);
-		}
-	}
-}
-
-
-static struct usb_driver w9968cf_usb_driver = {
-	.name =       "w9968cf",
-	.id_table =   winbond_id_table,
-	.probe =      w9968cf_usb_probe,
-	.disconnect = w9968cf_usb_disconnect,
-};
-
-
-
-/****************************************************************************
- * Module init, exit and intermodule communication                          *
- ****************************************************************************/
-
-static int __init w9968cf_module_init(void)
-{
-	int err;
-
-	KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
-	KDBG(3, W9968CF_MODULE_AUTHOR)
-
-	if ((err = usb_register(&w9968cf_usb_driver)))
-		return err;
-
-	return 0;
-}
-
-
-static void __exit w9968cf_module_exit(void)
-{
-	/* w9968cf_usb_disconnect() will be called */
-	usb_deregister(&w9968cf_usb_driver);
-
-	KDBG(2, W9968CF_MODULE_NAME" deregistered")
-}
-
-
-module_init(w9968cf_module_init);
-module_exit(w9968cf_module_exit);
-
diff --git a/drivers/media/video/w9968cf.h b/drivers/media/video/w9968cf.h
deleted file mode 100644
index 73ad864..0000000
--- a/drivers/media/video/w9968cf.h
+++ /dev/null
@@ -1,333 +0,0 @@
-/***************************************************************************
- * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
- *                                                                         *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _W9968CF_H_
-#define _W9968CF_H_
-
-#include <linux/videodev2.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-#include <linux/device.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#include <linux/param.h>
-#include <linux/types.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-
-#include <media/v4l2-device.h>
-#include <media/ovcamchip.h>
-
-#include "w9968cf_vpp.h"
-
-
-/****************************************************************************
- * Default values                                                           *
- ****************************************************************************/
-
-#define W9968CF_VPPMOD_LOAD     1  /* automatic 'w9968cf-vpp' module loading */
-
-/* Comment/uncomment the following line to enable/disable debugging messages */
-#define W9968CF_DEBUG
-
-/* These have effect only if W9968CF_DEBUG is defined */
-#define W9968CF_DEBUG_LEVEL    2 /* from 0 to 6. 0 for no debug informations */
-#define W9968CF_SPECIFIC_DEBUG 0 /* 0 or 1 */
-
-#define W9968CF_MAX_DEVICES    32
-#define W9968CF_SIMCAMS        W9968CF_MAX_DEVICES /* simultaneous cameras */
-
-#define W9968CF_MAX_BUFFERS   32
-#define W9968CF_BUFFERS       2 /* n. of frame buffers from 2 to MAX_BUFFERS */
-
-/* Maximum data payload sizes in bytes for alternate settings */
-static const u16 wMaxPacketSize[] = {1023, 959, 895, 831, 767, 703, 639, 575,
-				      511, 447, 383, 319, 255, 191, 127,  63};
-#define W9968CF_PACKET_SIZE      1023 /* according to wMaxPacketSizes[] */
-#define W9968CF_MIN_PACKET_SIZE  63 /* minimum value */
-#define W9968CF_ISO_PACKETS      5 /* n.of packets for isochronous transfers */
-#define W9968CF_USB_CTRL_TIMEOUT 1000 /* timeout (ms) for usb control commands */
-#define W9968CF_URBS             2 /* n. of scheduled URBs for ISO transfer */
-
-#define W9968CF_I2C_BUS_DELAY    4 /* delay in us for I2C bit r/w operations */
-#define W9968CF_I2C_RW_RETRIES   15 /* number of max I2C r/w retries */
-
-/* Available video formats */
-struct w9968cf_format {
-	const u16 palette;
-	const u16 depth;
-	const u8 compression;
-};
-
-static const struct w9968cf_format w9968cf_formatlist[] = {
-	{ VIDEO_PALETTE_UYVY,    16, 0 }, /* original video */
-	{ VIDEO_PALETTE_YUV422P, 16, 1 }, /* with JPEG compression */
-	{ VIDEO_PALETTE_YUV420P, 12, 1 }, /* with JPEG compression */
-	{ VIDEO_PALETTE_YUV420,  12, 1 }, /* same as YUV420P */
-	{ VIDEO_PALETTE_YUYV,    16, 0 }, /* software conversion */
-	{ VIDEO_PALETTE_YUV422,  16, 0 }, /* software conversion */
-	{ VIDEO_PALETTE_GREY,     8, 0 }, /* software conversion */
-	{ VIDEO_PALETTE_RGB555,  16, 0 }, /* software conversion */
-	{ VIDEO_PALETTE_RGB565,  16, 0 }, /* software conversion */
-	{ VIDEO_PALETTE_RGB24,   24, 0 }, /* software conversion */
-	{ VIDEO_PALETTE_RGB32,   32, 0 }, /* software conversion */
-	{ 0,                      0, 0 }  /* 0 is a terminating entry */
-};
-
-#define W9968CF_DECOMPRESSION    2 /* decomp:0=disable,1=force,2=any formats */
-#define W9968CF_PALETTE_DECOMP_OFF   VIDEO_PALETTE_UYVY    /* when decomp=0 */
-#define W9968CF_PALETTE_DECOMP_FORCE VIDEO_PALETTE_YUV420P /* when decomp=1 */
-#define W9968CF_PALETTE_DECOMP_ON    VIDEO_PALETTE_UYVY    /* when decomp=2 */
-
-#define W9968CF_FORCE_RGB        0  /* read RGB instead of BGR, yes=1/no=0 */
-
-#define W9968CF_MAX_WIDTH      800 /* Has effect if up-scaling is on */
-#define W9968CF_MAX_HEIGHT     600 /* Has effect if up-scaling is on */
-#define W9968CF_WIDTH          320 /* from 128 to 352, multiple of 16 */
-#define W9968CF_HEIGHT         240 /* from  96 to 288, multiple of 16 */
-
-#define W9968CF_CLAMPING       0 /* 0 disable, 1 enable video data clamping */
-#define W9968CF_FILTER_TYPE    0 /* 0 disable  1 (1-2-1), 2 (2-3-6-3-2) */
-#define W9968CF_DOUBLE_BUFFER  1 /* 0 disable, 1 enable double buffer */
-#define W9968CF_LARGEVIEW      1 /* 0 disable, 1 enable */
-#define W9968CF_UPSCALING      0 /* 0 disable, 1 enable */
-
-#define W9968CF_MONOCHROME     0 /* 0 not monochrome, 1 monochrome sensor */
-#define W9968CF_BRIGHTNESS     31000 /* from 0 to 65535 */
-#define W9968CF_HUE            32768 /* from 0 to 65535 */
-#define W9968CF_COLOUR         32768 /* from 0 to 65535 */
-#define W9968CF_CONTRAST       50000 /* from 0 to 65535 */
-#define W9968CF_WHITENESS      32768 /* from 0 to 65535 */
-
-#define W9968CF_AUTOBRIGHT     0 /* 0 disable, 1 enable automatic brightness */
-#define W9968CF_AUTOEXP        1 /* 0 disable, 1 enable automatic exposure */
-#define W9968CF_LIGHTFREQ      50 /* light frequency. 50Hz (Europe) or 60Hz */
-#define W9968CF_BANDINGFILTER  0 /* 0 disable, 1 enable banding filter */
-#define W9968CF_BACKLIGHT      0 /* 0 or 1, 1=object is lit from behind */
-#define W9968CF_MIRROR         0 /* 0 or 1 [don't] reverse image horizontally*/
-
-#define W9968CF_CLOCKDIV         -1 /* -1 = automatic clock divisor */
-#define W9968CF_DEF_CLOCKDIVISOR  0 /* default sensor clock divisor value */
-
-
-/****************************************************************************
- * Globals                                                                  *
- ****************************************************************************/
-
-#define W9968CF_MODULE_NAME     "V4L driver for W996[87]CF JPEG USB " \
-				"Dual Mode Camera Chip"
-#define W9968CF_MODULE_VERSION  "1:1.34-basic"
-#define W9968CF_MODULE_AUTHOR   "(C) 2002-2004 Luca Risolia"
-#define W9968CF_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
-#define W9968CF_MODULE_LICENSE  "GPL"
-
-static const struct usb_device_id winbond_id_table[] = {
-	{
-		/* Creative Labs Video Blaster WebCam Go Plus */
-		USB_DEVICE(0x041e, 0x4003),
-		.driver_info = (unsigned long)"w9968cf",
-	},
-	{
-		/* Generic W996[87]CF JPEG USB Dual Mode Camera */
-		USB_DEVICE(0x1046, 0x9967),
-		.driver_info = (unsigned long)"w9968cf",
-	},
-	{ } /* terminating entry */
-};
-
-/* W996[87]CF camera models, internal ids: */
-enum w9968cf_model_id {
-	W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */
-	W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/
-	W9968CF_MOD_ADPVDMA = 21, /* Aroma Digi Pen VGA Dual Mode ADG-5000 */
-	W9986CF_MOD_AAU = 31,     /* AVerMedia AVerTV USB */
-	W9968CF_MOD_CLVBWG = 34,  /* Creative Labs Video Blaster WebCam Go */
-	W9968CF_MOD_LL = 37,      /* Lebon LDC-035A */
-	W9968CF_MOD_EEEMC = 40,   /* Ezonics EZ-802 EZMega Cam */
-	W9968CF_MOD_OOE = 42,     /* OmniVision OV8610-EDE */
-	W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */
-	W9968CF_MOD_PDPII = 46,   /* Pretec Digi Pen-II */
-	W9968CF_MOD_PDP480 = 49,  /* Pretec DigiPen-480 */
-};
-
-enum w9968cf_frame_status {
-	F_READY,            /* finished grabbing & ready to be read/synced */
-	F_GRABBING,         /* in the process of being grabbed into */
-	F_ERROR,            /* something bad happened while processing */
-	F_UNUSED            /* unused (no VIDIOCMCAPTURE) */
-};
-
-struct w9968cf_frame_t {
-	void* buffer;
-	unsigned long size;
-	u32 length;
-	int number;
-	enum w9968cf_frame_status status;
-	struct w9968cf_frame_t* next;
-	u8 queued;
-};
-
-enum w9968cf_vpp_flag {
-	VPP_NONE = 0x00,
-	VPP_UPSCALE = 0x01,
-	VPP_SWAP_YUV_BYTES = 0x02,
-	VPP_DECOMPRESSION = 0x04,
-	VPP_UYVY_TO_RGBX = 0x08,
-};
-
-/* Main device driver structure */
-struct w9968cf_device {
-	enum w9968cf_model_id id;   /* private device identifier */
-
-	struct v4l2_device v4l2_dev;
-	struct video_device* v4ldev; /* -> V4L structure */
-	struct list_head v4llist;    /* entry of the list of V4L cameras */
-
-	struct usb_device* usbdev;           /* -> main USB structure */
-	struct urb* urb[W9968CF_URBS];       /* -> USB request block structs */
-	void* transfer_buffer[W9968CF_URBS]; /* -> ISO transfer buffers */
-	u16* control_buffer;                 /* -> buffer for control req.*/
-	u16* data_buffer;                    /* -> data to send to the FSB */
-
-	struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS];
-	struct w9968cf_frame_t frame_tmp; /* temporary frame */
-	struct w9968cf_frame_t frame_vpp; /* helper frame.*/
-	struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */
-	struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS];
-
-	u8 max_buffers,   /* number of requested buffers */
-	   force_palette, /* yes=1/no=0 */
-	   force_rgb,     /* read RGB instead of BGR, yes=1, no=0 */
-	   double_buffer, /* hardware double buffering yes=1/no=0 */
-	   clamping,      /* video data clamping yes=1/no=0 */
-	   filter_type,   /* 0=disabled, 1=3 tap, 2=5 tap filter */
-	   capture,       /* 0=disabled, 1=enabled */
-	   largeview,     /* 0=disabled, 1=enabled */
-	   decompression, /* 0=disabled, 1=forced, 2=allowed */
-	   upscaling;     /* software image scaling, 0=enabled, 1=disabled */
-
-	struct video_picture picture; /* current picture settings */
-	struct video_window window;   /* current window settings */
-
-	u16 hw_depth,    /* depth (used by the chip) */
-	    hw_palette,  /* palette (used by the chip) */
-	    hw_width,    /* width (used by the chip) */
-	    hw_height,   /* height (used by the chip) */
-	    hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
-	    vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
-	    start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/
-	    start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/
-
-	enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */
-
-	u8 nbuffers,      /* number of allocated frame buffers */
-	   altsetting,    /* camera alternate setting */
-	   disconnected,  /* flag: yes=1, no=0 */
-	   misconfigured, /* flag: yes=1, no=0 */
-	   users,         /* flag: number of users holding the device */
-	   streaming;     /* flag: yes=1, no=0 */
-
-	u8 sensor_initialized; /* flag: yes=1, no=0 */
-
-	/* Determined by the image sensor type: */
-	int sensor,       /* type of image sensor chip (CC_*) */
-	    monochrome;   /* image sensor is (probably) monochrome */
-	u16 maxwidth,     /* maximum width supported by the image sensor */
-	    maxheight,    /* maximum height supported by the image sensor */
-	    minwidth,     /* minimum width supported by the image sensor */
-	    minheight;    /* minimum height supported by the image sensor */
-	u8  auto_brt,     /* auto brightness enabled flag */
-	    auto_exp,     /* auto exposure enabled flag */
-	    backlight,    /* backlight exposure algorithm flag */
-	    mirror,       /* image is reversed horizontally */
-	    lightfreq,    /* power (lighting) frequency */
-	    bandfilt;     /* banding filter enabled flag */
-	s8  clockdiv;     /* clock divisor */
-
-	/* I2C interface to kernel */
-	struct i2c_adapter i2c_adapter;
-	struct v4l2_subdev *sensor_sd;
-
-	/* Locks */
-	struct mutex dev_mutex,    /* for probe, disconnect,open and close */
-			 fileop_mutex; /* for read and ioctl */
-	spinlock_t urb_lock,   /* for submit_urb() and unlink_urb() */
-		   flist_lock; /* for requested frame list accesses */
-	wait_queue_head_t open, wait_queue;
-
-	char command[16]; /* name of the program holding the device */
-};
-
-static inline struct w9968cf_device *to_cam(struct v4l2_device *v4l2_dev)
-{
-	return container_of(v4l2_dev, struct w9968cf_device, v4l2_dev);
-}
-
-
-/****************************************************************************
- * Macros for debugging                                                     *
- ****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef W9968CF_DEBUG
-/* For device specific debugging messages */
-#	define DBG(level, fmt, args...)                                       \
-{                                                                             \
-	if ( ((specific_debug) && (debug == (level))) ||                      \
-	     ((!specific_debug) && (debug >= (level))) ) {                    \
-		if ((level) == 1)                                             \
-			v4l2_err(&cam->v4l2_dev, fmt "\n", ## args);          \
-		else if ((level) == 2 || (level) == 3)                        \
-			v4l2_info(&cam->v4l2_dev, fmt "\n", ## args);         \
-		else if ((level) == 4)                                        \
-			v4l2_warn(&cam->v4l2_dev, fmt "\n", ## args);         \
-		else if ((level) >= 5)                                        \
-			v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n",        \
-				 __func__, __LINE__ , ## args);               \
-	}                                                                     \
-}
-/* For generic kernel (not device specific) messages */
-#	define KDBG(level, fmt, args...)                                      \
-{                                                                             \
-	if ( ((specific_debug) && (debug == (level))) ||                      \
-	     ((!specific_debug) && (debug >= (level))) ) {                    \
-		if ((level) >= 1 && (level) <= 4)                             \
-			pr_info("w9968cf: " fmt "\n", ## args);               \
-		else if ((level) >= 5)                                        \
-			pr_debug("w9968cf: [%s:%d] " fmt "\n", __func__,  \
-				 __LINE__ , ## args);                         \
-	}                                                                     \
-}
-#else
-	/* Not debugging: nothing */
-#	define DBG(level, fmt, args...) do {;} while(0);
-#	define KDBG(level, fmt, args...) do {;} while(0);
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...)                                                    \
-v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
-
-#endif /* _W9968CF_H_ */
diff --git a/drivers/media/video/w9968cf_decoder.h b/drivers/media/video/w9968cf_decoder.h
deleted file mode 100644
index 59decbf..0000000
--- a/drivers/media/video/w9968cf_decoder.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/***************************************************************************
- * Video decoder for the W996[87]CF driver for Linux.                      *
- *                                                                         *
- * Copyright (C) 2003 2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _W9968CF_DECODER_H_
-#define _W9968CF_DECODER_H_
-
-/* Comment/uncomment this for high/low quality of compressed video */
-#define W9968CF_DEC_FAST_LOWQUALITY_VIDEO
-
-#ifdef W9968CF_DEC_FAST_LOWQUALITY_VIDEO
-static const unsigned char Y_QUANTABLE[64] = {
-	16,  11,  10,  16,  24,  40,  51,  61,
-	12,  12,  14,  19,  26,  58,  60,  55,
-	14,  13,  16,  24,  40,  57,  69,  56,
-	14,  17,  22,  29,  51,  87,  80,  62,
-	18,  22,  37,  56,  68, 109, 103,  77,
-	24,  35,  55,  64,  81, 104, 113,  92,
-	49,  64,  78,  87, 103, 121, 120, 101,
-	72,  92,  95,  98, 112, 100, 103,  99
-};
-
-static const unsigned char UV_QUANTABLE[64] = {
-	17,  18,  24,  47,  99,  99,  99,  99,
-	18,  21,  26,  66,  99,  99,  99,  99,
-	24,  26,  56,  99,  99,  99,  99,  99,
-	47,  66,  99,  99,  99,  99,  99,  99,
-	99,  99,  99,  99,  99,  99,  99,  99,
-	99,  99,  99,  99,  99,  99,  99,  99,
-	99,  99,  99,  99,  99,  99,  99,  99,
-	99,  99,  99,  99,  99,  99,  99,  99
-};
-#else
-static const unsigned char Y_QUANTABLE[64] = {
-	 8,   5,   5,   8,  12,  20,  25,  30,
-	 6,   6,   7,   9,  13,  29,  30,  27,
-	 7,   6,   8,  12,  20,  28,  34,  28,
-	 7,   8,  11,  14,  25,  43,  40,  31,
-	 9,  11,  18,  28,  34,  54,  51,  38,
-	12,  17,  27,  32,  40,  52,  56,  46,
-	24,  32,  39,  43,  51,  60,  60,  50,
-	36,  46,  47,  49,  56,  50,  51,  49
-};
-
-static const unsigned char UV_QUANTABLE[64] = {
-	 8,   9,  12,  23,  49,  49,  49,  49,
-	 9,  10,  13,  33,  49,  49,  49,  49,
-	12,  13,  28,  49,  49,  49,  49,  49,
-	23,  33,  49,  49,  49,  49,  49,  49,
-	49,  49,  49,  49,  49,  49,  49,  49,
-	49,  49,  49,  49,  49,  49,  49,  49,
-	49,  49,  49,  49,  49,  49,  49,  49,
-	49,  49,  49,  49,  49,  49,  49,  49
-};
-#endif
-
-#define W9968CF_DEC_ERR_CORRUPTED_DATA  -1
-#define W9968CF_DEC_ERR_BUF_OVERFLOW    -2
-#define W9968CF_DEC_ERR_NO_SOI          -3
-#define W9968CF_DEC_ERR_NO_SOF0         -4
-#define W9968CF_DEC_ERR_NO_SOS          -5
-#define W9968CF_DEC_ERR_NO_EOI          -6
-
-extern void w9968cf_init_decoder(void);
-extern int w9968cf_check_headers(const unsigned char* Pin,
-				 const unsigned long BUF_SIZE);
-extern int w9968cf_decode(const char* Pin, const unsigned long BUF_SIZE,
-			  const unsigned W, const unsigned H, char* Pout);
-
-#endif /* _W9968CF_DECODER_H_ */
diff --git a/drivers/media/video/w9968cf_vpp.h b/drivers/media/video/w9968cf_vpp.h
deleted file mode 100644
index 88c9b6c..0000000
--- a/drivers/media/video/w9968cf_vpp.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/***************************************************************************
- * Interface for video post-processing functions for the W996[87]CF driver *
- * for Linux.                                                              *
- *                                                                         *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _W9968CF_VPP_H_
-#define _W9968CF_VPP_H_
-
-#include <linux/module.h>
-#include <asm/types.h>
-
-struct w9968cf_vpp_t {
-	struct module* owner;
-	int (*check_headers)(const unsigned char*, const unsigned long);
-	int (*decode)(const char*, const unsigned long, const unsigned,
-		      const unsigned, char*);
-	void (*swap_yuvbytes)(void*, unsigned long);
-	void (*uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8);
-	void (*scale_up)(u8*, u8*, u16, u16, u16, u16, u16);
-
-	u8 busy; /* read-only flag: module is/is not in use */
-};
-
-#endif /* _W9968CF_VPP_H_ */
diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig
deleted file mode 100644
index a7e610e..0000000
--- a/drivers/media/video/zc0301/Kconfig
+++ /dev/null
@@ -1,15 +0,0 @@
-config USB_ZC0301
-	tristate "USB ZC0301[P] webcam support (DEPRECATED)"
-	depends on VIDEO_V4L2
-	default n
-	---help---
-	  This driver is DEPRECATED please use the gspca zc3xx module
-	  instead.
-
-	  Say Y here if you want support for cameras based on the ZC0301 or
-	  ZC0301P Image Processors and Control Chips.
-
-	  See <file:Documentation/video4linux/zc0301.txt> for more info.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called zc0301.
diff --git a/drivers/media/video/zc0301/Makefile b/drivers/media/video/zc0301/Makefile
deleted file mode 100644
index d9e6d97..0000000
--- a/drivers/media/video/zc0301/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-zc0301-objs     := zc0301_core.o zc0301_pb0330.o zc0301_pas202bcb.o
-
-obj-$(CONFIG_USB_ZC0301)        += zc0301.o
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
deleted file mode 100644
index b1b5cce..0000000
--- a/drivers/media/video/zc0301/zc0301.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ZC0301[P] Image Processor and Control Chip              *
- *                                                                         *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _ZC0301_H_
-#define _ZC0301_H_
-
-#include <linux/version.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/types.h>
-#include <linux/param.h>
-#include <linux/mutex.h>
-#include <linux/rwsem.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/kref.h>
-
-#include "zc0301_sensor.h"
-
-/*****************************************************************************/
-
-#define ZC0301_DEBUG
-#define ZC0301_DEBUG_LEVEL         2
-#define ZC0301_MAX_DEVICES         64
-#define ZC0301_FORCE_MUNMAP        0
-#define ZC0301_MAX_FRAMES          32
-#define ZC0301_COMPRESSION_QUALITY 0
-#define ZC0301_URBS                2
-#define ZC0301_ISO_PACKETS         7
-#define ZC0301_ALTERNATE_SETTING   7
-#define ZC0301_URB_TIMEOUT         msecs_to_jiffies(2 * ZC0301_ISO_PACKETS)
-#define ZC0301_CTRL_TIMEOUT        100
-#define ZC0301_FRAME_TIMEOUT       2
-
-/*****************************************************************************/
-
-ZC0301_ID_TABLE
-ZC0301_SENSOR_TABLE
-
-enum zc0301_frame_state {
-	F_UNUSED,
-	F_QUEUED,
-	F_GRABBING,
-	F_DONE,
-	F_ERROR,
-};
-
-struct zc0301_frame_t {
-	void* bufmem;
-	struct v4l2_buffer buf;
-	enum zc0301_frame_state state;
-	struct list_head frame;
-	unsigned long vma_use_count;
-};
-
-enum zc0301_dev_state {
-	DEV_INITIALIZED = 0x01,
-	DEV_DISCONNECTED = 0x02,
-	DEV_MISCONFIGURED = 0x04,
-};
-
-enum zc0301_io_method {
-	IO_NONE,
-	IO_READ,
-	IO_MMAP,
-};
-
-enum zc0301_stream_state {
-	STREAM_OFF,
-	STREAM_INTERRUPT,
-	STREAM_ON,
-};
-
-struct zc0301_module_param {
-	u8 force_munmap;
-	u16 frame_timeout;
-};
-
-static DECLARE_RWSEM(zc0301_dev_lock);
-
-struct zc0301_device {
-	struct video_device* v4ldev;
-
-	struct zc0301_sensor sensor;
-
-	struct usb_device* usbdev;
-	struct urb* urb[ZC0301_URBS];
-	void* transfer_buffer[ZC0301_URBS];
-	u8* control_buffer;
-
-	struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES];
-	struct list_head inqueue, outqueue;
-	u32 frame_count, nbuffers, nreadbuffers;
-
-	enum zc0301_io_method io;
-	enum zc0301_stream_state stream;
-
-	struct v4l2_jpegcompression compression;
-
-	struct zc0301_module_param module_param;
-
-	struct kref kref;
-	enum zc0301_dev_state state;
-	u8 users;
-
-	struct completion probe;
-	struct mutex open_mutex, fileop_mutex;
-	spinlock_t queue_lock;
-	wait_queue_head_t wait_open, wait_frame, wait_stream;
-};
-
-/*****************************************************************************/
-
-struct zc0301_device*
-zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id)
-{
-	return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
-}
-
-void
-zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor)
-{
-	memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor));
-}
-
-/*****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef ZC0301_DEBUG
-#	define DBG(level, fmt, args...)                                       \
-do {                                                                          \
-	if (debug >= (level)) {                                               \
-		if ((level) == 1)                                             \
-			dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
-		else if ((level) == 2)                                        \
-			dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
-		else if ((level) >= 3)                                        \
-			dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",   \
-				 __FILE__, __func__, __LINE__ , ## args); \
-	}                                                                     \
-} while (0)
-#	define KDBG(level, fmt, args...)                                      \
-do {                                                                          \
-	if (debug >= (level)) {                                               \
-		if ((level) == 1 || (level) == 2)                             \
-			pr_info("zc0301: " fmt "\n", ## args);                \
-		else if ((level) == 3)                                        \
-			pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__,   \
-				 __func__, __LINE__ , ## args);           \
-	}                                                                     \
-} while (0)
-#	define V4LDBG(level, name, cmd)                                       \
-do {                                                                          \
-	if (debug >= (level))                                                 \
-		v4l_print_ioctl(name, cmd);                                   \
-} while (0)
-#else
-#	define DBG(level, fmt, args...) do {;} while(0)
-#	define KDBG(level, fmt, args...) do {;} while(0)
-#	define V4LDBG(level, name, cmd) do {;} while(0)
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__,   \
-	 __LINE__ , ## args)
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
-
-#endif /* _ZC0301_H_ */
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
deleted file mode 100644
index bb51cfb..0000000
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ /dev/null
@@ -1,2098 +0,0 @@
-/***************************************************************************
- * Video4Linux2 driver for ZC0301[P] Image Processor and Control Chip      *
- *                                                                         *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * Informations about the chip internals needed to enable the I2C protocol *
- * have been taken from the documentation of the ZC030x Video4Linux1       *
- * driver written by Andrew Birkett <andy@nobugs.org>                      *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
-#include <linux/poll.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/page-flags.h>
-#include <asm/byteorder.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "zc0301.h"
-
-/*****************************************************************************/
-
-#define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301[P] "                    \
-			      "Image Processor and Control Chip"
-#define ZC0301_MODULE_AUTHOR  "(C) 2006-2007 Luca Risolia"
-#define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
-#define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.10"
-#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 10)
-
-/*****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, zc0301_id_table);
-
-MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(ZC0301_MODULE_NAME);
-MODULE_VERSION(ZC0301_MODULE_VERSION);
-MODULE_LICENSE(ZC0301_MODULE_LICENSE);
-
-static short video_nr[] = {[0 ... ZC0301_MAX_DEVICES-1] = -1};
-module_param_array(video_nr, short, NULL, 0444);
-MODULE_PARM_DESC(video_nr,
-		 "\n<-1|n[,...]> Specify V4L2 minor mode number."
-		 "\n -1 = use next available (default)"
-		 "\n  n = use minor number n (integer >= 0)"
-		 "\nYou can specify up to "
-		 __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way."
-		 "\nFor example:"
-		 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-		 "\nthe second registered camera and use auto for the first"
-		 "\none and for every other camera."
-		 "\n");
-
-static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] =
-			       ZC0301_FORCE_MUNMAP};
-module_param_array(force_munmap, bool, NULL, 0444);
-MODULE_PARM_DESC(force_munmap,
-		 "\n<0|1[,...]> Force the application to unmap previously"
-		 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
-		 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
-		 "\nthis feature. This parameter is specific for each"
-		 "\ndetected camera."
-		 "\n 0 = do not force memory unmapping"
-		 "\n 1 = force memory unmapping (save memory)"
-		 "\nDefault value is "__MODULE_STRING(ZC0301_FORCE_MUNMAP)"."
-		 "\n");
-
-static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
-				       ZC0301_FRAME_TIMEOUT};
-module_param_array(frame_timeout, uint, NULL, 0644);
-MODULE_PARM_DESC(frame_timeout,
-		 "\n<n[,...]> Timeout for a video frame in seconds."
-		 "\nThis parameter is specific for each detected camera."
-		 "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"."
-		 "\n");
-
-#ifdef ZC0301_DEBUG
-static unsigned short debug = ZC0301_DEBUG_LEVEL;
-module_param(debug, ushort, 0644);
-MODULE_PARM_DESC(debug,
-		 "\n<n> Debugging information level, from 0 to 3:"
-		 "\n0 = none (use carefully)"
-		 "\n1 = critical errors"
-		 "\n2 = significant informations"
-		 "\n3 = more verbose messages"
-		 "\nLevel 3 is useful for testing only, when only "
-		 "one device is used."
-		 "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"."
-		 "\n");
-#endif
-
-/*****************************************************************************/
-
-static u32
-zc0301_request_buffers(struct zc0301_device* cam, u32 count,
-		       enum zc0301_io_method io)
-{
-	struct v4l2_pix_format* p = &(cam->sensor.pix_format);
-	struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
-	const size_t imagesize = cam->module_param.force_munmap ||
-				 io == IO_READ ?
-				 (p->width * p->height * p->priv) / 8 :
-				 (r->width * r->height * p->priv) / 8;
-	void* buff = NULL;
-	u32 i;
-
-	if (count > ZC0301_MAX_FRAMES)
-		count = ZC0301_MAX_FRAMES;
-
-	cam->nbuffers = count;
-	while (cam->nbuffers > 0) {
-		if ((buff = vmalloc_32_user(cam->nbuffers *
-					    PAGE_ALIGN(imagesize))))
-			break;
-		cam->nbuffers--;
-	}
-
-	for (i = 0; i < cam->nbuffers; i++) {
-		cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
-		cam->frame[i].buf.index = i;
-		cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
-		cam->frame[i].buf.length = imagesize;
-		cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		cam->frame[i].buf.sequence = 0;
-		cam->frame[i].buf.field = V4L2_FIELD_NONE;
-		cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
-		cam->frame[i].buf.flags = 0;
-	}
-
-	return cam->nbuffers;
-}
-
-
-static void zc0301_release_buffers(struct zc0301_device* cam)
-{
-	if (cam->nbuffers) {
-		vfree(cam->frame[0].bufmem);
-		cam->nbuffers = 0;
-	}
-	cam->frame_current = NULL;
-}
-
-
-static void zc0301_empty_framequeues(struct zc0301_device* cam)
-{
-	u32 i;
-
-	INIT_LIST_HEAD(&cam->inqueue);
-	INIT_LIST_HEAD(&cam->outqueue);
-
-	for (i = 0; i < ZC0301_MAX_FRAMES; i++) {
-		cam->frame[i].state = F_UNUSED;
-		cam->frame[i].buf.bytesused = 0;
-	}
-}
-
-
-static void zc0301_requeue_outqueue(struct zc0301_device* cam)
-{
-	struct zc0301_frame_t *i;
-
-	list_for_each_entry(i, &cam->outqueue, frame) {
-		i->state = F_QUEUED;
-		list_add(&i->frame, &cam->inqueue);
-	}
-
-	INIT_LIST_HEAD(&cam->outqueue);
-}
-
-
-static void zc0301_queue_unusedframes(struct zc0301_device* cam)
-{
-	unsigned long lock_flags;
-	u32 i;
-
-	for (i = 0; i < cam->nbuffers; i++)
-		if (cam->frame[i].state == F_UNUSED) {
-			cam->frame[i].state = F_QUEUED;
-			spin_lock_irqsave(&cam->queue_lock, lock_flags);
-			list_add_tail(&cam->frame[i].frame, &cam->inqueue);
-			spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-		}
-}
-
-/*****************************************************************************/
-
-int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value)
-{
-	struct usb_device* udev = cam->usbdev;
-	int res;
-
-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40,
-			      value, index, NULL, 0, ZC0301_CTRL_TIMEOUT);
-	if (res < 0) {
-		DBG(3, "Failed to write a register (index 0x%04X, "
-		       "value 0x%02X, error %d)",index, value, res);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int zc0301_read_reg(struct zc0301_device* cam, u16 index)
-{
-	struct usb_device* udev = cam->usbdev;
-	u8* buff = cam->control_buffer;
-	int res;
-
-	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0,
-			      0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT);
-	if (res < 0)
-		DBG(3, "Failed to read a register (index 0x%04X, error %d)",
-		    index, res);
-
-	PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff));
-
-	return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length)
-{
-	int err = 0, res, r0, r1;
-
-	err += zc0301_write_reg(cam, 0x0092, address);
-	err += zc0301_write_reg(cam, 0x0090, 0x02);
-
-	msleep(1);
-
-	res = zc0301_read_reg(cam, 0x0091);
-	if (res < 0)
-		err += res;
-	r0 = zc0301_read_reg(cam, 0x0095);
-	if (r0 < 0)
-		err += r0;
-	r1 = zc0301_read_reg(cam, 0x0096);
-	if (r1 < 0)
-		err += r1;
-
-	res = (length <= 1) ? r0 : r0 | (r1 << 8);
-
-	if (err)
-		DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X",
-		    address, res);
-
-
-	PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res);
-
-	return err ? -1 : res;
-}
-
-
-int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value)
-{
-	int err = 0, res;
-
-	err += zc0301_write_reg(cam, 0x0092, address);
-	err += zc0301_write_reg(cam, 0x0093, value & 0xff);
-	err += zc0301_write_reg(cam, 0x0094, value >> 8);
-	err += zc0301_write_reg(cam, 0x0090, 0x01);
-
-	msleep(1);
-
-	res = zc0301_read_reg(cam, 0x0091);
-	if (res < 0)
-		err += res;
-
-	if (err)
-		DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X",
-		    address, value);
-
-	PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value);
-
-	return err ? -1 : 0;
-}
-
-/*****************************************************************************/
-
-static void zc0301_urb_complete(struct urb *urb)
-{
-	struct zc0301_device* cam = urb->context;
-	struct zc0301_frame_t** f;
-	size_t imagesize;
-	u8 i;
-	int err = 0;
-
-	if (urb->status == -ENOENT)
-		return;
-
-	f = &cam->frame_current;
-
-	if (cam->stream == STREAM_INTERRUPT) {
-		cam->stream = STREAM_OFF;
-		if ((*f))
-			(*f)->state = F_QUEUED;
-		DBG(3, "Stream interrupted");
-		wake_up(&cam->wait_stream);
-	}
-
-	if (cam->state & DEV_DISCONNECTED)
-		return;
-
-	if (cam->state & DEV_MISCONFIGURED) {
-		wake_up_interruptible(&cam->wait_frame);
-		return;
-	}
-
-	if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
-		goto resubmit_urb;
-
-	if (!(*f))
-		(*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t,
-				  frame);
-
-	imagesize = (cam->sensor.pix_format.width *
-		     cam->sensor.pix_format.height *
-		     cam->sensor.pix_format.priv) / 8;
-
-	for (i = 0; i < urb->number_of_packets; i++) {
-		unsigned int len, status;
-		void *pos;
-		u16* soi;
-		u8 sof;
-
-		len = urb->iso_frame_desc[i].actual_length;
-		status = urb->iso_frame_desc[i].status;
-		pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
-		if (status) {
-			DBG(3, "Error in isochronous frame");
-			(*f)->state = F_ERROR;
-			continue;
-		}
-
-		sof = (*(soi = pos) == 0xd8ff);
-
-		PDBGG("Isochrnous frame: length %u, #%u i,", len, i);
-
-		if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
-start_of_frame:
-			if (sof) {
-				(*f)->state = F_GRABBING;
-				(*f)->buf.bytesused = 0;
-				do_gettimeofday(&(*f)->buf.timestamp);
-				DBG(3, "SOF detected: new video frame");
-			}
-
-		if ((*f)->state == F_GRABBING) {
-			if (sof && (*f)->buf.bytesused)
-					goto end_of_frame;
-
-			if ((*f)->buf.bytesused + len > imagesize) {
-				DBG(3, "Video frame size exceeded");
-				(*f)->state = F_ERROR;
-				continue;
-			}
-
-			memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len);
-			(*f)->buf.bytesused += len;
-
-			if ((*f)->buf.bytesused == imagesize) {
-				u32 b;
-end_of_frame:
-				b = (*f)->buf.bytesused;
-				(*f)->state = F_DONE;
-				(*f)->buf.sequence= ++cam->frame_count;
-				spin_lock(&cam->queue_lock);
-				list_move_tail(&(*f)->frame, &cam->outqueue);
-				if (!list_empty(&cam->inqueue))
-					(*f) = list_entry(cam->inqueue.next,
-						       struct zc0301_frame_t,
-							  frame);
-				else
-					(*f) = NULL;
-				spin_unlock(&cam->queue_lock);
-				DBG(3, "Video frame captured: : %lu bytes",
-				       (unsigned long)(b));
-
-				if (!(*f))
-					goto resubmit_urb;
-
-				if (sof)
-					goto start_of_frame;
-			}
-		}
-	}
-
-resubmit_urb:
-	urb->dev = cam->usbdev;
-	err = usb_submit_urb(urb, GFP_ATOMIC);
-	if (err < 0 && err != -EPERM) {
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "usb_submit_urb() failed");
-	}
-
-	wake_up_interruptible(&cam->wait_frame);
-}
-
-
-static int zc0301_start_transfer(struct zc0301_device* cam)
-{
-	struct usb_device *udev = cam->usbdev;
-	struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
-						     usb_ifnum_to_if(udev, 0),
-						     ZC0301_ALTERNATE_SETTING);
-	const unsigned int psz = le16_to_cpu(altsetting->
-					     endpoint[0].desc.wMaxPacketSize);
-	struct urb* urb;
-	s8 i, j;
-	int err = 0;
-
-	for (i = 0; i < ZC0301_URBS; i++) {
-		cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz,
-						  GFP_KERNEL);
-		if (!cam->transfer_buffer[i]) {
-			err = -ENOMEM;
-			DBG(1, "Not enough memory");
-			goto free_buffers;
-		}
-	}
-
-	for (i = 0; i < ZC0301_URBS; i++) {
-		urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL);
-		cam->urb[i] = urb;
-		if (!urb) {
-			err = -ENOMEM;
-			DBG(1, "usb_alloc_urb() failed");
-			goto free_urbs;
-		}
-		urb->dev = udev;
-		urb->context = cam;
-		urb->pipe = usb_rcvisocpipe(udev, 1);
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->number_of_packets = ZC0301_ISO_PACKETS;
-		urb->complete = zc0301_urb_complete;
-		urb->transfer_buffer = cam->transfer_buffer[i];
-		urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS;
-		urb->interval = 1;
-		for (j = 0; j < ZC0301_ISO_PACKETS; j++) {
-			urb->iso_frame_desc[j].offset = psz * j;
-			urb->iso_frame_desc[j].length = psz;
-		}
-	}
-
-	err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING);
-	if (err) {
-		DBG(1, "usb_set_interface() failed");
-		goto free_urbs;
-	}
-
-	cam->frame_current = NULL;
-
-	for (i = 0; i < ZC0301_URBS; i++) {
-		err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
-		if (err) {
-			for (j = i-1; j >= 0; j--)
-				usb_kill_urb(cam->urb[j]);
-			DBG(1, "usb_submit_urb() failed, error %d", err);
-			goto free_urbs;
-		}
-	}
-
-	return 0;
-
-free_urbs:
-	for (i = 0; (i < ZC0301_URBS) && cam->urb[i]; i++)
-		usb_free_urb(cam->urb[i]);
-
-free_buffers:
-	for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++)
-		kfree(cam->transfer_buffer[i]);
-
-	return err;
-}
-
-
-static int zc0301_stop_transfer(struct zc0301_device* cam)
-{
-	struct usb_device *udev = cam->usbdev;
-	s8 i;
-	int err = 0;
-
-	if (cam->state & DEV_DISCONNECTED)
-		return 0;
-
-	for (i = ZC0301_URBS-1; i >= 0; i--) {
-		usb_kill_urb(cam->urb[i]);
-		usb_free_urb(cam->urb[i]);
-		kfree(cam->transfer_buffer[i]);
-	}
-
-	err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
-	if (err)
-		DBG(3, "usb_set_interface() failed");
-
-	return err;
-}
-
-
-static int zc0301_stream_interrupt(struct zc0301_device* cam)
-{
-	long timeout;
-
-	cam->stream = STREAM_INTERRUPT;
-	timeout = wait_event_timeout(cam->wait_stream,
-				     (cam->stream == STREAM_OFF) ||
-				     (cam->state & DEV_DISCONNECTED),
-				     ZC0301_URB_TIMEOUT);
-	if (cam->state & DEV_DISCONNECTED)
-		return -ENODEV;
-	else if (cam->stream != STREAM_OFF) {
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "URB timeout reached. The camera is misconfigured. To "
-		       "use it, close and open %s again.",
-		    video_device_node_name(cam->v4ldev));
-		return -EIO;
-	}
-
-	return 0;
-}
-
-/*****************************************************************************/
-
-static int
-zc0301_set_compression(struct zc0301_device* cam,
-		       struct v4l2_jpegcompression* compression)
-{
-	int r, err = 0;
-
-	if ((r = zc0301_read_reg(cam, 0x0008)) < 0)
-		err += r;
-	err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality);
-
-	return err ? -EIO : 0;
-}
-
-
-static int zc0301_init(struct zc0301_device* cam)
-{
-	struct zc0301_sensor* s = &cam->sensor;
-	struct v4l2_control ctrl;
-	struct v4l2_queryctrl *qctrl;
-	struct v4l2_rect* rect;
-	u8 i = 0;
-	int err = 0;
-
-	if (!(cam->state & DEV_INITIALIZED)) {
-		mutex_init(&cam->open_mutex);
-		init_waitqueue_head(&cam->wait_open);
-		qctrl = s->qctrl;
-		rect = &(s->cropcap.defrect);
-		cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
-	} else { /* use current values */
-		qctrl = s->_qctrl;
-		rect = &(s->_rect);
-	}
-
-	if (s->init) {
-		err = s->init(cam);
-		if (err) {
-			DBG(3, "Sensor initialization failed");
-			return err;
-		}
-	}
-
-	if ((err = zc0301_set_compression(cam, &cam->compression))) {
-		DBG(3, "set_compression() failed");
-		return err;
-	}
-
-	if (s->set_crop)
-		if ((err = s->set_crop(cam, rect))) {
-			DBG(3, "set_crop() failed");
-			return err;
-		}
-
-	if (s->set_ctrl) {
-		for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-			if (s->qctrl[i].id != 0 &&
-			    !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
-				ctrl.id = s->qctrl[i].id;
-				ctrl.value = qctrl[i].default_value;
-				err = s->set_ctrl(cam, &ctrl);
-				if (err) {
-					DBG(3, "Set %s control failed",
-					    s->qctrl[i].name);
-					return err;
-				}
-				DBG(3, "Image sensor supports '%s' control",
-				    s->qctrl[i].name);
-			}
-	}
-
-	if (!(cam->state & DEV_INITIALIZED)) {
-		mutex_init(&cam->fileop_mutex);
-		spin_lock_init(&cam->queue_lock);
-		init_waitqueue_head(&cam->wait_frame);
-		init_waitqueue_head(&cam->wait_stream);
-		cam->nreadbuffers = 2;
-		memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
-		memcpy(&(s->_rect), &(s->cropcap.defrect),
-		       sizeof(struct v4l2_rect));
-		cam->state |= DEV_INITIALIZED;
-	}
-
-	DBG(2, "Initialization succeeded");
-	return 0;
-}
-
-/*****************************************************************************/
-
-static void zc0301_release_resources(struct kref *kref)
-{
-	struct zc0301_device *cam = container_of(kref, struct zc0301_device,
-						 kref);
-	DBG(2, "V4L2 device %s deregistered",
-	    video_device_node_name(cam->v4ldev));
-	video_set_drvdata(cam->v4ldev, NULL);
-	video_unregister_device(cam->v4ldev);
-	usb_put_dev(cam->usbdev);
-	kfree(cam->control_buffer);
-	kfree(cam);
-}
-
-
-static int zc0301_open(struct file *filp)
-{
-	struct zc0301_device* cam;
-	int err = 0;
-
-	if (!down_read_trylock(&zc0301_dev_lock))
-		return -EAGAIN;
-
-	cam = video_drvdata(filp);
-
-	if (wait_for_completion_interruptible(&cam->probe)) {
-		up_read(&zc0301_dev_lock);
-		return -ERESTARTSYS;
-	}
-
-	kref_get(&cam->kref);
-
-	if (mutex_lock_interruptible(&cam->open_mutex)) {
-		kref_put(&cam->kref, zc0301_release_resources);
-		up_read(&zc0301_dev_lock);
-		return -ERESTARTSYS;
-	}
-
-	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present");
-		err = -ENODEV;
-		goto out;
-	}
-
-	if (cam->users) {
-		DBG(2, "Device %s is busy...",
-		    video_device_node_name(cam->v4ldev));
-		DBG(3, "Simultaneous opens are not supported");
-		if ((filp->f_flags & O_NONBLOCK) ||
-		    (filp->f_flags & O_NDELAY)) {
-			err = -EWOULDBLOCK;
-			goto out;
-		}
-		DBG(2, "A blocking open() has been requested. Wait for the "
-		       "device to be released...");
-		up_read(&zc0301_dev_lock);
-		err = wait_event_interruptible_exclusive(cam->wait_open,
-						(cam->state & DEV_DISCONNECTED)
-							 || !cam->users);
-		down_read(&zc0301_dev_lock);
-		if (err)
-			goto out;
-		if (cam->state & DEV_DISCONNECTED) {
-			err = -ENODEV;
-			goto out;
-		}
-	}
-
-	if (cam->state & DEV_MISCONFIGURED) {
-		err = zc0301_init(cam);
-		if (err) {
-			DBG(1, "Initialization failed again. "
-			       "I will retry on next open().");
-			goto out;
-		}
-		cam->state &= ~DEV_MISCONFIGURED;
-	}
-
-	if ((err = zc0301_start_transfer(cam)))
-		goto out;
-
-	filp->private_data = cam;
-	cam->users++;
-	cam->io = IO_NONE;
-	cam->stream = STREAM_OFF;
-	cam->nbuffers = 0;
-	cam->frame_count = 0;
-	zc0301_empty_framequeues(cam);
-
-	DBG(3, "Video device %s is open",
-	    video_device_node_name(cam->v4ldev));
-
-out:
-	mutex_unlock(&cam->open_mutex);
-	if (err)
-		kref_put(&cam->kref, zc0301_release_resources);
-	up_read(&zc0301_dev_lock);
-	return err;
-}
-
-
-static int zc0301_release(struct file *filp)
-{
-	struct zc0301_device* cam;
-
-	down_write(&zc0301_dev_lock);
-
-	cam = video_drvdata(filp);
-
-	zc0301_stop_transfer(cam);
-	zc0301_release_buffers(cam);
-	cam->users--;
-	wake_up_interruptible_nr(&cam->wait_open, 1);
-
-	DBG(3, "Video device %s closed",
-	    video_device_node_name(cam->v4ldev));
-
-	kref_put(&cam->kref, zc0301_release_resources);
-
-	up_write(&zc0301_dev_lock);
-
-	return 0;
-}
-
-
-static ssize_t
-zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
-	struct zc0301_device *cam = video_drvdata(filp);
-	struct zc0301_frame_t* f, * i;
-	unsigned long lock_flags;
-	long timeout;
-	int err = 0;
-
-	if (mutex_lock_interruptible(&cam->fileop_mutex))
-		return -ERESTARTSYS;
-
-	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present");
-		mutex_unlock(&cam->fileop_mutex);
-		return -ENODEV;
-	}
-
-	if (cam->state & DEV_MISCONFIGURED) {
-		DBG(1, "The camera is misconfigured. Close and open it "
-		       "again.");
-		mutex_unlock(&cam->fileop_mutex);
-		return -EIO;
-	}
-
-	if (cam->io == IO_MMAP) {
-		DBG(3, "Close and open the device again to choose the read "
-		       "method");
-		mutex_unlock(&cam->fileop_mutex);
-		return -EBUSY;
-	}
-
-	if (cam->io == IO_NONE) {
-		if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
-			DBG(1, "read() failed, not enough memory");
-			mutex_unlock(&cam->fileop_mutex);
-			return -ENOMEM;
-		}
-		cam->io = IO_READ;
-		cam->stream = STREAM_ON;
-	}
-
-	if (list_empty(&cam->inqueue)) {
-		if (!list_empty(&cam->outqueue))
-			zc0301_empty_framequeues(cam);
-		zc0301_queue_unusedframes(cam);
-	}
-
-	if (!count) {
-		mutex_unlock(&cam->fileop_mutex);
-		return 0;
-	}
-
-	if (list_empty(&cam->outqueue)) {
-		if (filp->f_flags & O_NONBLOCK) {
-			mutex_unlock(&cam->fileop_mutex);
-			return -EAGAIN;
-		}
-		timeout = wait_event_interruptible_timeout
-			  ( cam->wait_frame,
-			    (!list_empty(&cam->outqueue)) ||
-			    (cam->state & DEV_DISCONNECTED) ||
-			    (cam->state & DEV_MISCONFIGURED),
-			    msecs_to_jiffies(
-				cam->module_param.frame_timeout * 1000
-			    )
-			  );
-		if (timeout < 0) {
-			mutex_unlock(&cam->fileop_mutex);
-			return timeout;
-		}
-		if (cam->state & DEV_DISCONNECTED) {
-			mutex_unlock(&cam->fileop_mutex);
-			return -ENODEV;
-		}
-		if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
-			mutex_unlock(&cam->fileop_mutex);
-			return -EIO;
-		}
-	}
-
-	f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame);
-
-	if (count > f->buf.bytesused)
-		count = f->buf.bytesused;
-
-	if (copy_to_user(buf, f->bufmem, count)) {
-		err = -EFAULT;
-		goto exit;
-	}
-	*f_pos += count;
-
-exit:
-	spin_lock_irqsave(&cam->queue_lock, lock_flags);
-	list_for_each_entry(i, &cam->outqueue, frame)
-		i->state = F_UNUSED;
-	INIT_LIST_HEAD(&cam->outqueue);
-	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-	zc0301_queue_unusedframes(cam);
-
-	PDBGG("Frame #%lu, bytes read: %zu",
-	      (unsigned long)f->buf.index, count);
-
-	mutex_unlock(&cam->fileop_mutex);
-
-	return err ? err : count;
-}
-
-
-static unsigned int zc0301_poll(struct file *filp, poll_table *wait)
-{
-	struct zc0301_device *cam = video_drvdata(filp);
-	struct zc0301_frame_t* f;
-	unsigned long lock_flags;
-	unsigned int mask = 0;
-
-	if (mutex_lock_interruptible(&cam->fileop_mutex))
-		return POLLERR;
-
-	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present");
-		goto error;
-	}
-
-	if (cam->state & DEV_MISCONFIGURED) {
-		DBG(1, "The camera is misconfigured. Close and open it "
-		       "again.");
-		goto error;
-	}
-
-	if (cam->io == IO_NONE) {
-		if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
-			DBG(1, "poll() failed, not enough memory");
-			goto error;
-		}
-		cam->io = IO_READ;
-		cam->stream = STREAM_ON;
-	}
-
-	if (cam->io == IO_READ) {
-		spin_lock_irqsave(&cam->queue_lock, lock_flags);
-		list_for_each_entry(f, &cam->outqueue, frame)
-			f->state = F_UNUSED;
-		INIT_LIST_HEAD(&cam->outqueue);
-		spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-		zc0301_queue_unusedframes(cam);
-	}
-
-	poll_wait(filp, &cam->wait_frame, wait);
-
-	if (!list_empty(&cam->outqueue))
-		mask |= POLLIN | POLLRDNORM;
-
-	mutex_unlock(&cam->fileop_mutex);
-
-	return mask;
-
-error:
-	mutex_unlock(&cam->fileop_mutex);
-	return POLLERR;
-}
-
-
-static void zc0301_vm_open(struct vm_area_struct* vma)
-{
-	struct zc0301_frame_t* f = vma->vm_private_data;
-	f->vma_use_count++;
-}
-
-
-static void zc0301_vm_close(struct vm_area_struct* vma)
-{
-	/* NOTE: buffers are not freed here */
-	struct zc0301_frame_t* f = vma->vm_private_data;
-	f->vma_use_count--;
-}
-
-
-static const struct vm_operations_struct zc0301_vm_ops = {
-	.open = zc0301_vm_open,
-	.close = zc0301_vm_close,
-};
-
-
-static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
-{
-	struct zc0301_device *cam = video_drvdata(filp);
-	unsigned long size = vma->vm_end - vma->vm_start,
-		      start = vma->vm_start;
-	void *pos;
-	u32 i;
-
-	if (mutex_lock_interruptible(&cam->fileop_mutex))
-		return -ERESTARTSYS;
-
-	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present");
-		mutex_unlock(&cam->fileop_mutex);
-		return -ENODEV;
-	}
-
-	if (cam->state & DEV_MISCONFIGURED) {
-		DBG(1, "The camera is misconfigured. Close and open it "
-		       "again.");
-		mutex_unlock(&cam->fileop_mutex);
-		return -EIO;
-	}
-
-	if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
-		mutex_unlock(&cam->fileop_mutex);
-		return -EACCES;
-	}
-
-	if (cam->io != IO_MMAP ||
-	    size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-		mutex_unlock(&cam->fileop_mutex);
-		return -EINVAL;
-	}
-
-	for (i = 0; i < cam->nbuffers; i++) {
-		if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
-			break;
-	}
-	if (i == cam->nbuffers) {
-		mutex_unlock(&cam->fileop_mutex);
-		return -EINVAL;
-	}
-
-	vma->vm_flags |= VM_IO;
-	vma->vm_flags |= VM_RESERVED;
-
-	pos = cam->frame[i].bufmem;
-	while (size > 0) { /* size is page-aligned */
-		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-			mutex_unlock(&cam->fileop_mutex);
-			return -EAGAIN;
-		}
-		start += PAGE_SIZE;
-		pos += PAGE_SIZE;
-		size -= PAGE_SIZE;
-	}
-
-	vma->vm_ops = &zc0301_vm_ops;
-	vma->vm_private_data = &cam->frame[i];
-	zc0301_vm_open(vma);
-
-	mutex_unlock(&cam->fileop_mutex);
-
-	return 0;
-}
-
-/*****************************************************************************/
-
-static int
-zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg)
-{
-	struct v4l2_capability cap = {
-		.driver = "zc0301",
-		.version = ZC0301_MODULE_VERSION_CODE,
-		.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
-				V4L2_CAP_STREAMING,
-	};
-
-	strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
-	if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
-		strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev),
-			sizeof(cap.bus_info));
-
-	if (copy_to_user(arg, &cap, sizeof(cap)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg)
-{
-	struct v4l2_input i;
-
-	if (copy_from_user(&i, arg, sizeof(i)))
-		return -EFAULT;
-
-	if (i.index)
-		return -EINVAL;
-
-	memset(&i, 0, sizeof(i));
-	strcpy(i.name, "Camera");
-	i.type = V4L2_INPUT_TYPE_CAMERA;
-
-	if (copy_to_user(arg, &i, sizeof(i)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg)
-{
-	int index = 0;
-
-	if (copy_to_user(arg, &index, sizeof(index)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg)
-{
-	int index;
-
-	if (copy_from_user(&index, arg, sizeof(index)))
-		return -EFAULT;
-
-	if (index != 0)
-		return -EINVAL;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg)
-{
-	struct zc0301_sensor* s = &cam->sensor;
-	struct v4l2_queryctrl qc;
-	u8 i;
-
-	if (copy_from_user(&qc, arg, sizeof(qc)))
-		return -EFAULT;
-
-	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-		if (qc.id && qc.id == s->qctrl[i].id) {
-			memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
-			if (copy_to_user(arg, &qc, sizeof(qc)))
-				return -EFAULT;
-			return 0;
-		}
-
-	return -EINVAL;
-}
-
-
-static int
-zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg)
-{
-	struct zc0301_sensor* s = &cam->sensor;
-	struct v4l2_control ctrl;
-	int err = 0;
-	u8 i;
-
-	if (!s->get_ctrl && !s->set_ctrl)
-		return -EINVAL;
-
-	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-		return -EFAULT;
-
-	if (!s->get_ctrl) {
-		for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-			if (ctrl.id == s->qctrl[i].id) {
-				ctrl.value = s->_qctrl[i].default_value;
-				goto exit;
-			}
-		return -EINVAL;
-	} else
-		err = s->get_ctrl(cam, &ctrl);
-
-exit:
-	if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
-		return -EFAULT;
-
-	return err;
-}
-
-
-static int
-zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg)
-{
-	struct zc0301_sensor* s = &cam->sensor;
-	struct v4l2_control ctrl;
-	u8 i;
-	int err = 0;
-
-	if (!s->set_ctrl)
-		return -EINVAL;
-
-	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-		return -EFAULT;
-
-	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) {
-		if (ctrl.id == s->qctrl[i].id) {
-			if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
-				return -EINVAL;
-			if (ctrl.value < s->qctrl[i].minimum ||
-			    ctrl.value > s->qctrl[i].maximum)
-				return -ERANGE;
-			ctrl.value -= ctrl.value % s->qctrl[i].step;
-			break;
-		}
-	}
-	if (i == ARRAY_SIZE(s->qctrl))
-		return -EINVAL;
-	if ((err = s->set_ctrl(cam, &ctrl)))
-		return err;
-
-	s->_qctrl[i].default_value = ctrl.value;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg)
-{
-	struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
-
-	cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	cc->pixelaspect.numerator = 1;
-	cc->pixelaspect.denominator = 1;
-
-	if (copy_to_user(arg, cc, sizeof(*cc)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg)
-{
-	struct zc0301_sensor* s = &cam->sensor;
-	struct v4l2_crop crop = {
-		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-	};
-
-	memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
-
-	if (copy_to_user(arg, &crop, sizeof(crop)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
-{
-	struct zc0301_sensor* s = &cam->sensor;
-	struct v4l2_crop crop;
-	struct v4l2_rect* rect;
-	struct v4l2_rect* bounds = &(s->cropcap.bounds);
-	const enum zc0301_stream_state stream = cam->stream;
-	const u32 nbuffers = cam->nbuffers;
-	u32 i;
-	int err = 0;
-
-	if (copy_from_user(&crop, arg, sizeof(crop)))
-		return -EFAULT;
-
-	rect = &(crop.c);
-
-	if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	if (cam->module_param.force_munmap)
-		for (i = 0; i < cam->nbuffers; i++)
-			if (cam->frame[i].vma_use_count) {
-				DBG(3, "VIDIOC_S_CROP failed. "
-				       "Unmap the buffers first.");
-				return -EBUSY;
-			}
-
-	if (!s->set_crop) {
-		memcpy(rect, &(s->_rect), sizeof(*rect));
-		if (copy_to_user(arg, &crop, sizeof(crop)))
-			return -EFAULT;
-		return 0;
-	}
-
-	rect->left &= ~7L;
-	rect->top &= ~7L;
-	if (rect->width < 8)
-		rect->width = 8;
-	if (rect->height < 8)
-		rect->height = 8;
-	if (rect->width > bounds->width)
-		rect->width = bounds->width;
-	if (rect->height > bounds->height)
-		rect->height = bounds->height;
-	if (rect->left < bounds->left)
-		rect->left = bounds->left;
-	if (rect->top < bounds->top)
-		rect->top = bounds->top;
-	if (rect->left + rect->width > bounds->left + bounds->width)
-		rect->left = bounds->left+bounds->width - rect->width;
-	if (rect->top + rect->height > bounds->top + bounds->height)
-		rect->top = bounds->top+bounds->height - rect->height;
-	rect->width &= ~7L;
-	rect->height &= ~7L;
-
-	if (cam->stream == STREAM_ON)
-		if ((err = zc0301_stream_interrupt(cam)))
-			return err;
-
-	if (copy_to_user(arg, &crop, sizeof(crop))) {
-		cam->stream = stream;
-		return -EFAULT;
-	}
-
-	if (cam->module_param.force_munmap || cam->io == IO_READ)
-		zc0301_release_buffers(cam);
-
-	if (s->set_crop)
-		err += s->set_crop(cam, rect);
-
-	if (err) { /* atomic, no rollback in ioctl() */
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
-		       "use the camera, close and open %s again.",
-		    video_device_node_name(cam->v4ldev));
-		return -EIO;
-	}
-
-	s->pix_format.width = rect->width;
-	s->pix_format.height = rect->height;
-	memcpy(&(s->_rect), rect, sizeof(*rect));
-
-	if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-	    nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
-		       "use the camera, close and open %s again.",
-		    video_device_node_name(cam->v4ldev));
-		return -ENOMEM;
-	}
-
-	if (cam->io == IO_READ)
-		zc0301_empty_framequeues(cam);
-	else if (cam->module_param.force_munmap)
-		zc0301_requeue_outqueue(cam);
-
-	cam->stream = stream;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_enum_framesizes(struct zc0301_device* cam, void __user * arg)
-{
-	struct v4l2_frmsizeenum frmsize;
-
-	if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
-		return -EFAULT;
-
-	if (frmsize.index != 0 && frmsize.index != 1)
-		return -EINVAL;
-
-	if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG)
-		return -EINVAL;
-
-	frmsize.type = V4L2_FRMSIZE_TYPE_DISCRETE;
-
-	if (frmsize.index == 1) {
-		frmsize.discrete.width = cam->sensor.cropcap.defrect.width;
-		frmsize.discrete.height = cam->sensor.cropcap.defrect.height;
-	}
-	memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
-
-	if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
-{
-	struct v4l2_fmtdesc fmtd;
-
-	if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
-		return -EFAULT;
-
-	if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	if (fmtd.index == 0) {
-		strcpy(fmtd.description, "JPEG");
-		fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
-		fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
-	} else
-		return -EINVAL;
-
-	fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
-
-	if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg)
-{
-	struct v4l2_format format;
-	struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
-
-	if (copy_from_user(&format, arg, sizeof(format)))
-		return -EFAULT;
-
-	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	pfmt->bytesperline = 0;
-	pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
-	pfmt->field = V4L2_FIELD_NONE;
-	memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
-
-	if (copy_to_user(arg, &format, sizeof(format)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
-			void __user * arg)
-{
-	struct zc0301_sensor* s = &cam->sensor;
-	struct v4l2_format format;
-	struct v4l2_pix_format* pix;
-	struct v4l2_pix_format* pfmt = &(s->pix_format);
-	struct v4l2_rect* bounds = &(s->cropcap.bounds);
-	struct v4l2_rect rect;
-	const enum zc0301_stream_state stream = cam->stream;
-	const u32 nbuffers = cam->nbuffers;
-	u32 i;
-	int err = 0;
-
-	if (copy_from_user(&format, arg, sizeof(format)))
-		return -EFAULT;
-
-	pix = &(format.fmt.pix);
-
-	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	memcpy(&rect, &(s->_rect), sizeof(rect));
-
-	if (!s->set_crop) {
-		pix->width = rect.width;
-		pix->height = rect.height;
-	} else {
-		rect.width = pix->width;
-		rect.height = pix->height;
-	}
-
-	if (rect.width < 8)
-		rect.width = 8;
-	if (rect.height < 8)
-		rect.height = 8;
-	if (rect.width > bounds->left + bounds->width - rect.left)
-		rect.width = bounds->left + bounds->width - rect.left;
-	if (rect.height > bounds->top + bounds->height - rect.top)
-		rect.height = bounds->top + bounds->height - rect.top;
-	rect.width &= ~7L;
-	rect.height &= ~7L;
-
-	pix->width = rect.width;
-	pix->height = rect.height;
-	pix->pixelformat = pfmt->pixelformat;
-	pix->priv = pfmt->priv;
-	pix->colorspace = pfmt->colorspace;
-	pix->bytesperline = 0;
-	pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
-	pix->field = V4L2_FIELD_NONE;
-
-	if (cmd == VIDIOC_TRY_FMT) {
-		if (copy_to_user(arg, &format, sizeof(format)))
-			return -EFAULT;
-		return 0;
-	}
-
-	if (cam->module_param.force_munmap)
-		for (i = 0; i < cam->nbuffers; i++)
-			if (cam->frame[i].vma_use_count) {
-				DBG(3, "VIDIOC_S_FMT failed. "
-				       "Unmap the buffers first.");
-				return -EBUSY;
-			}
-
-	if (cam->stream == STREAM_ON)
-		if ((err = zc0301_stream_interrupt(cam)))
-			return err;
-
-	if (copy_to_user(arg, &format, sizeof(format))) {
-		cam->stream = stream;
-		return -EFAULT;
-	}
-
-	if (cam->module_param.force_munmap || cam->io == IO_READ)
-		zc0301_release_buffers(cam);
-
-	if (s->set_crop)
-		err += s->set_crop(cam, &rect);
-
-	if (err) { /* atomic, no rollback in ioctl() */
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
-		       "use the camera, close and open %s again.",
-		    video_device_node_name(cam->v4ldev));
-		return -EIO;
-	}
-
-	memcpy(pfmt, pix, sizeof(*pix));
-	memcpy(&(s->_rect), &rect, sizeof(rect));
-
-	if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-	    nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
-		       "use the camera, close and open %s again.",
-		    video_device_node_name(cam->v4ldev));
-		return -ENOMEM;
-	}
-
-	if (cam->io == IO_READ)
-		zc0301_empty_framequeues(cam);
-	else if (cam->module_param.force_munmap)
-		zc0301_requeue_outqueue(cam);
-
-	cam->stream = stream;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg)
-{
-	if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg)
-{
-	struct v4l2_jpegcompression jc;
-	const enum zc0301_stream_state stream = cam->stream;
-	int err = 0;
-
-	if (copy_from_user(&jc, arg, sizeof(jc)))
-		return -EFAULT;
-
-	if (jc.quality != 0)
-		return -EINVAL;
-
-	if (cam->stream == STREAM_ON)
-		if ((err = zc0301_stream_interrupt(cam)))
-			return err;
-
-	err += zc0301_set_compression(cam, &jc);
-	if (err) { /* atomic, no rollback in ioctl() */
-		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
-		       "problems. To use the camera, close and open %s again.",
-		       video_device_node_name(cam->v4ldev));
-		return -EIO;
-	}
-
-	cam->compression.quality = jc.quality;
-
-	cam->stream = stream;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
-{
-	struct v4l2_requestbuffers rb;
-	u32 i;
-	int err;
-
-	if (copy_from_user(&rb, arg, sizeof(rb)))
-		return -EFAULT;
-
-	if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-	    rb.memory != V4L2_MEMORY_MMAP)
-		return -EINVAL;
-
-	if (cam->io == IO_READ) {
-		DBG(3, "Close and open the device again to choose the mmap "
-		       "I/O method");
-		return -EBUSY;
-	}
-
-	for (i = 0; i < cam->nbuffers; i++)
-		if (cam->frame[i].vma_use_count) {
-			DBG(3, "VIDIOC_REQBUFS failed. "
-			       "Previous buffers are still mapped.");
-			return -EBUSY;
-		}
-
-	if (cam->stream == STREAM_ON)
-		if ((err = zc0301_stream_interrupt(cam)))
-			return err;
-
-	zc0301_empty_framequeues(cam);
-
-	zc0301_release_buffers(cam);
-	if (rb.count)
-		rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP);
-
-	if (copy_to_user(arg, &rb, sizeof(rb))) {
-		zc0301_release_buffers(cam);
-		cam->io = IO_NONE;
-		return -EFAULT;
-	}
-
-	cam->io = rb.count ? IO_MMAP : IO_NONE;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg)
-{
-	struct v4l2_buffer b;
-
-	if (copy_from_user(&b, arg, sizeof(b)))
-		return -EFAULT;
-
-	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-	    b.index >= cam->nbuffers || cam->io != IO_MMAP)
-		return -EINVAL;
-
-	memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
-
-	if (cam->frame[b.index].vma_use_count)
-		b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-	if (cam->frame[b.index].state == F_DONE)
-		b.flags |= V4L2_BUF_FLAG_DONE;
-	else if (cam->frame[b.index].state != F_UNUSED)
-		b.flags |= V4L2_BUF_FLAG_QUEUED;
-
-	if (copy_to_user(arg, &b, sizeof(b)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg)
-{
-	struct v4l2_buffer b;
-	unsigned long lock_flags;
-
-	if (copy_from_user(&b, arg, sizeof(b)))
-		return -EFAULT;
-
-	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-	    b.index >= cam->nbuffers || cam->io != IO_MMAP)
-		return -EINVAL;
-
-	if (cam->frame[b.index].state != F_UNUSED)
-		return -EINVAL;
-
-	cam->frame[b.index].state = F_QUEUED;
-
-	spin_lock_irqsave(&cam->queue_lock, lock_flags);
-	list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
-	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-	PDBGG("Frame #%lu queued", (unsigned long)b.index);
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp,
-		    void __user * arg)
-{
-	struct v4l2_buffer b;
-	struct zc0301_frame_t *f;
-	unsigned long lock_flags;
-	long timeout;
-
-	if (copy_from_user(&b, arg, sizeof(b)))
-		return -EFAULT;
-
-	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
-		return -EINVAL;
-
-	if (list_empty(&cam->outqueue)) {
-		if (cam->stream == STREAM_OFF)
-			return -EINVAL;
-		if (filp->f_flags & O_NONBLOCK)
-			return -EAGAIN;
-		timeout = wait_event_interruptible_timeout
-			  ( cam->wait_frame,
-			    (!list_empty(&cam->outqueue)) ||
-			    (cam->state & DEV_DISCONNECTED) ||
-			    (cam->state & DEV_MISCONFIGURED),
-			    cam->module_param.frame_timeout *
-			    1000 * msecs_to_jiffies(1) );
-		if (timeout < 0)
-			return timeout;
-		if (cam->state & DEV_DISCONNECTED)
-			return -ENODEV;
-		if (!timeout || (cam->state & DEV_MISCONFIGURED))
-			return -EIO;
-	}
-
-	spin_lock_irqsave(&cam->queue_lock, lock_flags);
-	f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame);
-	list_del(cam->outqueue.next);
-	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-	f->state = F_UNUSED;
-
-	memcpy(&b, &f->buf, sizeof(b));
-	if (f->vma_use_count)
-		b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-	if (copy_to_user(arg, &b, sizeof(b)))
-		return -EFAULT;
-
-	PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
-{
-	int type;
-
-	if (copy_from_user(&type, arg, sizeof(type)))
-		return -EFAULT;
-
-	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-		return -EINVAL;
-
-	cam->stream = STREAM_ON;
-
-	DBG(3, "Stream on");
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg)
-{
-	int type, err;
-
-	if (copy_from_user(&type, arg, sizeof(type)))
-		return -EFAULT;
-
-	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-		return -EINVAL;
-
-	if (cam->stream == STREAM_ON)
-		if ((err = zc0301_stream_interrupt(cam)))
-			return err;
-
-	zc0301_empty_framequeues(cam);
-
-	DBG(3, "Stream off");
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg)
-{
-	struct v4l2_streamparm sp;
-
-	if (copy_from_user(&sp, arg, sizeof(sp)))
-		return -EFAULT;
-
-	if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	sp.parm.capture.extendedmode = 0;
-	sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-	if (copy_to_user(arg, &sp, sizeof(sp)))
-		return -EFAULT;
-
-	return 0;
-}
-
-
-static int
-zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg)
-{
-	struct v4l2_streamparm sp;
-
-	if (copy_from_user(&sp, arg, sizeof(sp)))
-		return -EFAULT;
-
-	if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	sp.parm.capture.extendedmode = 0;
-
-	if (sp.parm.capture.readbuffers == 0)
-		sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-	if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES)
-		sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES;
-
-	if (copy_to_user(arg, &sp, sizeof(sp)))
-		return -EFAULT;
-
-	cam->nreadbuffers = sp.parm.capture.readbuffers;
-
-	return 0;
-}
-
-
-static long zc0301_ioctl_v4l2(struct file *filp,
-			     unsigned int cmd, void __user *arg)
-{
-	struct zc0301_device *cam = video_drvdata(filp);
-
-	switch (cmd) {
-
-	case VIDIOC_QUERYCAP:
-		return zc0301_vidioc_querycap(cam, arg);
-
-	case VIDIOC_ENUMINPUT:
-		return zc0301_vidioc_enuminput(cam, arg);
-
-	case VIDIOC_G_INPUT:
-		return zc0301_vidioc_g_input(cam, arg);
-
-	case VIDIOC_S_INPUT:
-		return zc0301_vidioc_s_input(cam, arg);
-
-	case VIDIOC_QUERYCTRL:
-		return zc0301_vidioc_query_ctrl(cam, arg);
-
-	case VIDIOC_G_CTRL:
-		return zc0301_vidioc_g_ctrl(cam, arg);
-
-	case VIDIOC_S_CTRL:
-		return zc0301_vidioc_s_ctrl(cam, arg);
-
-	case VIDIOC_CROPCAP:
-		return zc0301_vidioc_cropcap(cam, arg);
-
-	case VIDIOC_G_CROP:
-		return zc0301_vidioc_g_crop(cam, arg);
-
-	case VIDIOC_S_CROP:
-		return zc0301_vidioc_s_crop(cam, arg);
-
-	case VIDIOC_ENUM_FMT:
-		return zc0301_vidioc_enum_fmt(cam, arg);
-
-	case VIDIOC_G_FMT:
-		return zc0301_vidioc_g_fmt(cam, arg);
-
-	case VIDIOC_TRY_FMT:
-	case VIDIOC_S_FMT:
-		return zc0301_vidioc_try_s_fmt(cam, cmd, arg);
-
-	case VIDIOC_ENUM_FRAMESIZES:
-		return zc0301_vidioc_enum_framesizes(cam, arg);
-
-	case VIDIOC_G_JPEGCOMP:
-		return zc0301_vidioc_g_jpegcomp(cam, arg);
-
-	case VIDIOC_S_JPEGCOMP:
-		return zc0301_vidioc_s_jpegcomp(cam, arg);
-
-	case VIDIOC_REQBUFS:
-		return zc0301_vidioc_reqbufs(cam, arg);
-
-	case VIDIOC_QUERYBUF:
-		return zc0301_vidioc_querybuf(cam, arg);
-
-	case VIDIOC_QBUF:
-		return zc0301_vidioc_qbuf(cam, arg);
-
-	case VIDIOC_DQBUF:
-		return zc0301_vidioc_dqbuf(cam, filp, arg);
-
-	case VIDIOC_STREAMON:
-		return zc0301_vidioc_streamon(cam, arg);
-
-	case VIDIOC_STREAMOFF:
-		return zc0301_vidioc_streamoff(cam, arg);
-
-	case VIDIOC_G_PARM:
-		return zc0301_vidioc_g_parm(cam, arg);
-
-	case VIDIOC_S_PARM:
-		return zc0301_vidioc_s_parm(cam, arg);
-
-	case VIDIOC_G_STD:
-	case VIDIOC_S_STD:
-	case VIDIOC_QUERYSTD:
-	case VIDIOC_ENUMSTD:
-	case VIDIOC_QUERYMENU:
-	case VIDIOC_ENUM_FRAMEINTERVALS:
-		return -EINVAL;
-
-	default:
-		return -EINVAL;
-
-	}
-}
-
-
-static long zc0301_ioctl(struct file *filp,
-			unsigned int cmd, unsigned long arg)
-{
-	struct zc0301_device *cam = video_drvdata(filp);
-	int err = 0;
-
-	if (mutex_lock_interruptible(&cam->fileop_mutex))
-		return -ERESTARTSYS;
-
-	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present");
-		mutex_unlock(&cam->fileop_mutex);
-		return -ENODEV;
-	}
-
-	if (cam->state & DEV_MISCONFIGURED) {
-		DBG(1, "The camera is misconfigured. Close and open it "
-		       "again.");
-		mutex_unlock(&cam->fileop_mutex);
-		return -EIO;
-	}
-
-	V4LDBG(3, "zc0301", cmd);
-
-	err = zc0301_ioctl_v4l2(filp, cmd, (void __user *)arg);
-
-	mutex_unlock(&cam->fileop_mutex);
-
-	return err;
-}
-
-
-static const struct v4l2_file_operations zc0301_fops = {
-	.owner =   THIS_MODULE,
-	.open =    zc0301_open,
-	.release = zc0301_release,
-	.ioctl =   zc0301_ioctl,
-	.read =    zc0301_read,
-	.poll =    zc0301_poll,
-	.mmap =    zc0301_mmap,
-};
-
-/*****************************************************************************/
-
-static int
-zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct zc0301_device* cam;
-	static unsigned int dev_nr;
-	unsigned int i;
-	int err = 0;
-
-	if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL)))
-		return -ENOMEM;
-
-	cam->usbdev = udev;
-
-	if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) {
-		DBG(1, "kmalloc() failed");
-		err = -ENOMEM;
-		goto fail;
-	}
-
-	if (!(cam->v4ldev = video_device_alloc())) {
-		DBG(1, "video_device_alloc() failed");
-		err = -ENOMEM;
-		goto fail;
-	}
-
-	DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
-	       "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
-
-	for  (i = 0; zc0301_sensor_table[i]; i++) {
-		err = zc0301_sensor_table[i](cam);
-		if (!err)
-			break;
-	}
-
-	if (!err)
-		DBG(2, "%s image sensor detected", cam->sensor.name);
-	else {
-		DBG(1, "No supported image sensor detected");
-		err = -ENODEV;
-		goto fail;
-	}
-
-	if (zc0301_init(cam)) {
-		DBG(1, "Initialization failed. I will retry on open().");
-		cam->state |= DEV_MISCONFIGURED;
-	}
-
-	strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera");
-	cam->v4ldev->fops = &zc0301_fops;
-	cam->v4ldev->release = video_device_release;
-	cam->v4ldev->parent = &udev->dev;
-	video_set_drvdata(cam->v4ldev, cam);
-
-	init_completion(&cam->probe);
-
-	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-				    video_nr[dev_nr]);
-	if (err) {
-		DBG(1, "V4L2 device registration failed");
-		if (err == -ENFILE && video_nr[dev_nr] == -1)
-			DBG(1, "Free /dev/videoX node not found");
-		video_nr[dev_nr] = -1;
-		dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
-		complete_all(&cam->probe);
-		goto fail;
-	}
-
-	DBG(2, "V4L2 device registered as %s",
-	    video_device_node_name(cam->v4ldev));
-
-	cam->module_param.force_munmap = force_munmap[dev_nr];
-	cam->module_param.frame_timeout = frame_timeout[dev_nr];
-
-	dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-	usb_set_intfdata(intf, cam);
-	kref_init(&cam->kref);
-	usb_get_dev(cam->usbdev);
-
-	complete_all(&cam->probe);
-
-	return 0;
-
-fail:
-	if (cam) {
-		kfree(cam->control_buffer);
-		if (cam->v4ldev)
-			video_device_release(cam->v4ldev);
-		kfree(cam);
-	}
-	return err;
-}
-
-
-static void zc0301_usb_disconnect(struct usb_interface* intf)
-{
-	struct zc0301_device* cam;
-
-	down_write(&zc0301_dev_lock);
-
-	cam = usb_get_intfdata(intf);
-
-	DBG(2, "Disconnecting %s...", cam->v4ldev->name);
-
-	if (cam->users) {
-		DBG(2, "Device %s is open! Deregistration and "
-		       "memory deallocation are deferred.",
-		    video_device_node_name(cam->v4ldev));
-		cam->state |= DEV_MISCONFIGURED;
-		zc0301_stop_transfer(cam);
-		cam->state |= DEV_DISCONNECTED;
-		wake_up_interruptible(&cam->wait_frame);
-		wake_up(&cam->wait_stream);
-	} else
-		cam->state |= DEV_DISCONNECTED;
-
-	wake_up_interruptible_all(&cam->wait_open);
-
-	kref_put(&cam->kref, zc0301_release_resources);
-
-	up_write(&zc0301_dev_lock);
-}
-
-
-static struct usb_driver zc0301_usb_driver = {
-	.name =       "zc0301",
-	.id_table =   zc0301_id_table,
-	.probe =      zc0301_usb_probe,
-	.disconnect = zc0301_usb_disconnect,
-};
-
-/*****************************************************************************/
-
-static int __init zc0301_module_init(void)
-{
-	int err = 0;
-
-	KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION);
-	KDBG(3, ZC0301_MODULE_AUTHOR);
-
-	if ((err = usb_register(&zc0301_usb_driver)))
-		KDBG(1, "usb_register() failed");
-
-	return err;
-}
-
-
-static void __exit zc0301_module_exit(void)
-{
-	usb_deregister(&zc0301_usb_driver);
-}
-
-
-module_init(zc0301_module_init);
-module_exit(zc0301_module_exit);
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
deleted file mode 100644
index 24b0dfb..0000000
--- a/drivers/media/video/zc0301/zc0301_pas202bcb.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC0301 Image        *
- * Processor and Control Chip                                              *
- *                                                                         *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
- * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-/*
-   NOTE: Sensor controls are disabled for now, becouse changing them while
-	 streaming sometimes results in out-of-sync video frames. We'll use
-	 the default initialization, until we know how to stop and start video
-	 in the chip. However, the image quality still looks good under various
-	 light conditions.
-*/
-
-#include <linux/delay.h>
-#include "zc0301_sensor.h"
-
-
-static struct zc0301_sensor pas202bcb;
-
-
-static int pas202bcb_init(struct zc0301_device* cam)
-{
-	int err = 0;
-
-	err += zc0301_write_reg(cam, 0x0002, 0x00);
-	err += zc0301_write_reg(cam, 0x0003, 0x02);
-	err += zc0301_write_reg(cam, 0x0004, 0x80);
-	err += zc0301_write_reg(cam, 0x0005, 0x01);
-	err += zc0301_write_reg(cam, 0x0006, 0xE0);
-	err += zc0301_write_reg(cam, 0x0098, 0x00);
-	err += zc0301_write_reg(cam, 0x009A, 0x03);
-	err += zc0301_write_reg(cam, 0x011A, 0x00);
-	err += zc0301_write_reg(cam, 0x011C, 0x03);
-	err += zc0301_write_reg(cam, 0x009B, 0x01);
-	err += zc0301_write_reg(cam, 0x009C, 0xE6);
-	err += zc0301_write_reg(cam, 0x009D, 0x02);
-	err += zc0301_write_reg(cam, 0x009E, 0x86);
-
-	err += zc0301_i2c_write(cam, 0x02, 0x02);
-	err += zc0301_i2c_write(cam, 0x0A, 0x01);
-	err += zc0301_i2c_write(cam, 0x0B, 0x01);
-	err += zc0301_i2c_write(cam, 0x0D, 0x00);
-	err += zc0301_i2c_write(cam, 0x12, 0x05);
-	err += zc0301_i2c_write(cam, 0x13, 0x63);
-	err += zc0301_i2c_write(cam, 0x15, 0x70);
-
-	err += zc0301_write_reg(cam, 0x0101, 0xB7);
-	err += zc0301_write_reg(cam, 0x0100, 0x0D);
-	err += zc0301_write_reg(cam, 0x0189, 0x06);
-	err += zc0301_write_reg(cam, 0x01AD, 0x00);
-	err += zc0301_write_reg(cam, 0x01C5, 0x03);
-	err += zc0301_write_reg(cam, 0x01CB, 0x13);
-	err += zc0301_write_reg(cam, 0x0250, 0x08);
-	err += zc0301_write_reg(cam, 0x0301, 0x08);
-	err += zc0301_write_reg(cam, 0x018D, 0x70);
-	err += zc0301_write_reg(cam, 0x0008, 0x03);
-	err += zc0301_write_reg(cam, 0x01C6, 0x04);
-	err += zc0301_write_reg(cam, 0x01CB, 0x07);
-	err += zc0301_write_reg(cam, 0x0120, 0x11);
-	err += zc0301_write_reg(cam, 0x0121, 0x37);
-	err += zc0301_write_reg(cam, 0x0122, 0x58);
-	err += zc0301_write_reg(cam, 0x0123, 0x79);
-	err += zc0301_write_reg(cam, 0x0124, 0x91);
-	err += zc0301_write_reg(cam, 0x0125, 0xA6);
-	err += zc0301_write_reg(cam, 0x0126, 0xB8);
-	err += zc0301_write_reg(cam, 0x0127, 0xC7);
-	err += zc0301_write_reg(cam, 0x0128, 0xD3);
-	err += zc0301_write_reg(cam, 0x0129, 0xDE);
-	err += zc0301_write_reg(cam, 0x012A, 0xE6);
-	err += zc0301_write_reg(cam, 0x012B, 0xED);
-	err += zc0301_write_reg(cam, 0x012C, 0xF3);
-	err += zc0301_write_reg(cam, 0x012D, 0xF8);
-	err += zc0301_write_reg(cam, 0x012E, 0xFB);
-	err += zc0301_write_reg(cam, 0x012F, 0xFF);
-	err += zc0301_write_reg(cam, 0x0130, 0x26);
-	err += zc0301_write_reg(cam, 0x0131, 0x23);
-	err += zc0301_write_reg(cam, 0x0132, 0x20);
-	err += zc0301_write_reg(cam, 0x0133, 0x1C);
-	err += zc0301_write_reg(cam, 0x0134, 0x16);
-	err += zc0301_write_reg(cam, 0x0135, 0x13);
-	err += zc0301_write_reg(cam, 0x0136, 0x10);
-	err += zc0301_write_reg(cam, 0x0137, 0x0D);
-	err += zc0301_write_reg(cam, 0x0138, 0x0B);
-	err += zc0301_write_reg(cam, 0x0139, 0x09);
-	err += zc0301_write_reg(cam, 0x013A, 0x07);
-	err += zc0301_write_reg(cam, 0x013B, 0x06);
-	err += zc0301_write_reg(cam, 0x013C, 0x05);
-	err += zc0301_write_reg(cam, 0x013D, 0x04);
-	err += zc0301_write_reg(cam, 0x013E, 0x03);
-	err += zc0301_write_reg(cam, 0x013F, 0x02);
-	err += zc0301_write_reg(cam, 0x010A, 0x4C);
-	err += zc0301_write_reg(cam, 0x010B, 0xF5);
-	err += zc0301_write_reg(cam, 0x010C, 0xFF);
-	err += zc0301_write_reg(cam, 0x010D, 0xF9);
-	err += zc0301_write_reg(cam, 0x010E, 0x51);
-	err += zc0301_write_reg(cam, 0x010F, 0xF5);
-	err += zc0301_write_reg(cam, 0x0110, 0xFB);
-	err += zc0301_write_reg(cam, 0x0111, 0xED);
-	err += zc0301_write_reg(cam, 0x0112, 0x5F);
-	err += zc0301_write_reg(cam, 0x0180, 0x00);
-	err += zc0301_write_reg(cam, 0x0019, 0x00);
-	err += zc0301_write_reg(cam, 0x0087, 0x20);
-	err += zc0301_write_reg(cam, 0x0088, 0x21);
-
-	err += zc0301_i2c_write(cam, 0x20, 0x02);
-	err += zc0301_i2c_write(cam, 0x21, 0x1B);
-	err += zc0301_i2c_write(cam, 0x03, 0x44);
-	err += zc0301_i2c_write(cam, 0x0E, 0x01);
-	err += zc0301_i2c_write(cam, 0x0F, 0x00);
-
-	err += zc0301_write_reg(cam, 0x01A9, 0x14);
-	err += zc0301_write_reg(cam, 0x01AA, 0x24);
-	err += zc0301_write_reg(cam, 0x0190, 0x00);
-	err += zc0301_write_reg(cam, 0x0191, 0x02);
-	err += zc0301_write_reg(cam, 0x0192, 0x1B);
-	err += zc0301_write_reg(cam, 0x0195, 0x00);
-	err += zc0301_write_reg(cam, 0x0196, 0x00);
-	err += zc0301_write_reg(cam, 0x0197, 0x4D);
-	err += zc0301_write_reg(cam, 0x018C, 0x10);
-	err += zc0301_write_reg(cam, 0x018F, 0x20);
-	err += zc0301_write_reg(cam, 0x001D, 0x44);
-	err += zc0301_write_reg(cam, 0x001E, 0x6F);
-	err += zc0301_write_reg(cam, 0x001F, 0xAD);
-	err += zc0301_write_reg(cam, 0x0020, 0xEB);
-	err += zc0301_write_reg(cam, 0x0087, 0x0F);
-	err += zc0301_write_reg(cam, 0x0088, 0x0E);
-	err += zc0301_write_reg(cam, 0x0180, 0x40);
-	err += zc0301_write_reg(cam, 0x0192, 0x1B);
-	err += zc0301_write_reg(cam, 0x0191, 0x02);
-	err += zc0301_write_reg(cam, 0x0190, 0x00);
-	err += zc0301_write_reg(cam, 0x0116, 0x1D);
-	err += zc0301_write_reg(cam, 0x0117, 0x40);
-	err += zc0301_write_reg(cam, 0x0118, 0x99);
-	err += zc0301_write_reg(cam, 0x0180, 0x42);
-	err += zc0301_write_reg(cam, 0x0116, 0x1D);
-	err += zc0301_write_reg(cam, 0x0117, 0x40);
-	err += zc0301_write_reg(cam, 0x0118, 0x99);
-	err += zc0301_write_reg(cam, 0x0007, 0x00);
-
-	err += zc0301_i2c_write(cam, 0x11, 0x01);
-
-	msleep(100);
-
-	return err;
-}
-
-
-static int pas202bcb_get_ctrl(struct zc0301_device* cam,
-			      struct v4l2_control* ctrl)
-{
-	switch (ctrl->id) {
-	case V4L2_CID_EXPOSURE:
-		{
-			int r1 = zc0301_i2c_read(cam, 0x04, 1),
-			    r2 = zc0301_i2c_read(cam, 0x05, 1);
-			if (r1 < 0 || r2 < 0)
-				return -EIO;
-			ctrl->value = (r1 << 6) | (r2 & 0x3f);
-		}
-		return 0;
-	case V4L2_CID_RED_BALANCE:
-		if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0)
-			return -EIO;
-		ctrl->value &= 0x0f;
-		return 0;
-	case V4L2_CID_BLUE_BALANCE:
-		if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0)
-			return -EIO;
-		ctrl->value &= 0x0f;
-		return 0;
-	case V4L2_CID_GAIN:
-		if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0)
-			return -EIO;
-		ctrl->value &= 0x1f;
-		return 0;
-	case ZC0301_V4L2_CID_GREEN_BALANCE:
-		if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0)
-			return -EIO;
-		ctrl->value &= 0x0f;
-		return 0;
-	case ZC0301_V4L2_CID_DAC_MAGNITUDE:
-		if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0)
-			return -EIO;
-		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-
-
-static int pas202bcb_set_ctrl(struct zc0301_device* cam,
-			      const struct v4l2_control* ctrl)
-{
-	int err = 0;
-
-	switch (ctrl->id) {
-	case V4L2_CID_EXPOSURE:
-		err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6);
-		err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f);
-		break;
-	case V4L2_CID_RED_BALANCE:
-		err += zc0301_i2c_write(cam, 0x09, ctrl->value);
-		break;
-	case V4L2_CID_BLUE_BALANCE:
-		err += zc0301_i2c_write(cam, 0x07, ctrl->value);
-		break;
-	case V4L2_CID_GAIN:
-		err += zc0301_i2c_write(cam, 0x10, ctrl->value);
-		break;
-	case ZC0301_V4L2_CID_GREEN_BALANCE:
-		err += zc0301_i2c_write(cam, 0x08, ctrl->value);
-		break;
-	case ZC0301_V4L2_CID_DAC_MAGNITUDE:
-		err += zc0301_i2c_write(cam, 0x0c, ctrl->value);
-		break;
-	default:
-		return -EINVAL;
-	}
-	err += zc0301_i2c_write(cam, 0x11, 0x01);
-
-	return err ? -EIO : 0;
-}
-
-
-static struct zc0301_sensor pas202bcb = {
-	.name = "PAS202BCB",
-	.init = &pas202bcb_init,
-	.qctrl = {
-		{
-			.id = V4L2_CID_EXPOSURE,
-			.type = V4L2_CTRL_TYPE_INTEGER,
-			.name = "exposure",
-			.minimum = 0x01e5,
-			.maximum = 0x3fff,
-			.step = 0x0001,
-			.default_value = 0x01e5,
-			.flags = V4L2_CTRL_FLAG_DISABLED,
-		},
-		{
-			.id = V4L2_CID_GAIN,
-			.type = V4L2_CTRL_TYPE_INTEGER,
-			.name = "global gain",
-			.minimum = 0x00,
-			.maximum = 0x1f,
-			.step = 0x01,
-			.default_value = 0x0c,
-			.flags = V4L2_CTRL_FLAG_DISABLED,
-		},
-		{
-			.id = ZC0301_V4L2_CID_DAC_MAGNITUDE,
-			.type = V4L2_CTRL_TYPE_INTEGER,
-			.name = "DAC magnitude",
-			.minimum = 0x00,
-			.maximum = 0xff,
-			.step = 0x01,
-			.default_value = 0x00,
-			.flags = V4L2_CTRL_FLAG_DISABLED,
-		},
-		{
-			.id = V4L2_CID_RED_BALANCE,
-			.type = V4L2_CTRL_TYPE_INTEGER,
-			.name = "red balance",
-			.minimum = 0x00,
-			.maximum = 0x0f,
-			.step = 0x01,
-			.default_value = 0x01,
-			.flags = V4L2_CTRL_FLAG_DISABLED,
-		},
-		{
-			.id = V4L2_CID_BLUE_BALANCE,
-			.type = V4L2_CTRL_TYPE_INTEGER,
-			.name = "blue balance",
-			.minimum = 0x00,
-			.maximum = 0x0f,
-			.step = 0x01,
-			.default_value = 0x05,
-			.flags = V4L2_CTRL_FLAG_DISABLED,
-		},
-		{
-			.id = ZC0301_V4L2_CID_GREEN_BALANCE,
-			.type = V4L2_CTRL_TYPE_INTEGER,
-			.name = "green balance",
-			.minimum = 0x00,
-			.maximum = 0x0f,
-			.step = 0x01,
-			.default_value = 0x00,
-			.flags = V4L2_CTRL_FLAG_DISABLED,
-		},
-	},
-	.get_ctrl = &pas202bcb_get_ctrl,
-	.set_ctrl = &pas202bcb_set_ctrl,
-	.cropcap = {
-		.bounds = {
-			.left = 0,
-			.top = 0,
-			.width = 640,
-			.height = 480,
-		},
-		.defrect = {
-			.left = 0,
-			.top = 0,
-			.width = 640,
-			.height = 480,
-		},
-	},
-	.pix_format = {
-		.width = 640,
-		.height = 480,
-		.pixelformat = V4L2_PIX_FMT_JPEG,
-		.priv = 8,
-		.colorspace = V4L2_COLORSPACE_JPEG,
-	},
-};
-
-
-int zc0301_probe_pas202bcb(struct zc0301_device* cam)
-{
-	int r0 = 0, r1 = 0, err = 0;
-	unsigned int pid = 0;
-
-	err += zc0301_write_reg(cam, 0x0000, 0x01);
-	err += zc0301_write_reg(cam, 0x0010, 0x0e);
-	err += zc0301_write_reg(cam, 0x0001, 0x01);
-	err += zc0301_write_reg(cam, 0x0012, 0x03);
-	err += zc0301_write_reg(cam, 0x0012, 0x01);
-	err += zc0301_write_reg(cam, 0x008d, 0x08);
-
-	msleep(10);
-
-	r0 = zc0301_i2c_read(cam, 0x00, 1);
-	r1 = zc0301_i2c_read(cam, 0x01, 1);
-
-	if (r0 < 0 || r1 < 0 || err)
-		return -EIO;
-
-	pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
-	if (pid != 0x017)
-		return -ENODEV;
-
-	zc0301_attach_sensor(cam, &pas202bcb);
-
-	return 0;
-}
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
deleted file mode 100644
index 9519aba..0000000
--- a/drivers/media/video/zc0301/zc0301_pb0330.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/***************************************************************************
- * Plug-in for PB-0330 image sensor connected to the ZC0301P Image         *
- * Processor and Control Chip                                              *
- *                                                                         *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
- * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "zc0301_sensor.h"
-
-
-static struct zc0301_sensor pb0330;
-
-
-static int pb0330_init(struct zc0301_device* cam)
-{
-	int err = 0;
-
-	err += zc0301_write_reg(cam, 0x0000, 0x01);
-	err += zc0301_write_reg(cam, 0x0008, 0x03);
-	err += zc0301_write_reg(cam, 0x0010, 0x0A);
-	err += zc0301_write_reg(cam, 0x0002, 0x00);
-	err += zc0301_write_reg(cam, 0x0003, 0x02);
-	err += zc0301_write_reg(cam, 0x0004, 0x80);
-	err += zc0301_write_reg(cam, 0x0005, 0x01);
-	err += zc0301_write_reg(cam, 0x0006, 0xE0);
-	err += zc0301_write_reg(cam, 0x0001, 0x01);
-	err += zc0301_write_reg(cam, 0x0012, 0x05);
-	err += zc0301_write_reg(cam, 0x0012, 0x07);
-	err += zc0301_write_reg(cam, 0x0098, 0x00);
-	err += zc0301_write_reg(cam, 0x009A, 0x00);
-	err += zc0301_write_reg(cam, 0x011A, 0x00);
-	err += zc0301_write_reg(cam, 0x011C, 0x00);
-	err += zc0301_write_reg(cam, 0x0012, 0x05);
-
-	err += zc0301_i2c_write(cam, 0x01, 0x0006);
-	err += zc0301_i2c_write(cam, 0x02, 0x0011);
-	err += zc0301_i2c_write(cam, 0x03, 0x01E7);
-	err += zc0301_i2c_write(cam, 0x04, 0x0287);
-	err += zc0301_i2c_write(cam, 0x06, 0x0003);
-	err += zc0301_i2c_write(cam, 0x07, 0x3002);
-	err += zc0301_i2c_write(cam, 0x20, 0x1100);
-	err += zc0301_i2c_write(cam, 0x2F, 0xF7B0);
-	err += zc0301_i2c_write(cam, 0x30, 0x0005);
-	err += zc0301_i2c_write(cam, 0x31, 0x0000);
-	err += zc0301_i2c_write(cam, 0x34, 0x0100);
-	err += zc0301_i2c_write(cam, 0x35, 0x0060);
-	err += zc0301_i2c_write(cam, 0x3D, 0x068F);
-	err += zc0301_i2c_write(cam, 0x40, 0x01E0);
-	err += zc0301_i2c_write(cam, 0x58, 0x0078);
-	err += zc0301_i2c_write(cam, 0x62, 0x0411);
-
-	err += zc0301_write_reg(cam, 0x0087, 0x10);
-	err += zc0301_write_reg(cam, 0x0101, 0x37);
-	err += zc0301_write_reg(cam, 0x0012, 0x05);
-	err += zc0301_write_reg(cam, 0x0100, 0x0D);
-	err += zc0301_write_reg(cam, 0x0189, 0x06);
-	err += zc0301_write_reg(cam, 0x01AD, 0x00);
-	err += zc0301_write_reg(cam, 0x01C5, 0x03);
-	err += zc0301_write_reg(cam, 0x01CB, 0x13);
-	err += zc0301_write_reg(cam, 0x0250, 0x08);
-	err += zc0301_write_reg(cam, 0x0301, 0x08);
-	err += zc0301_write_reg(cam, 0x01A8, 0x60);
-	err += zc0301_write_reg(cam, 0x018D, 0x6C);
-	err += zc0301_write_reg(cam, 0x01AD, 0x09);
-	err += zc0301_write_reg(cam, 0x01AE, 0x15);
-	err += zc0301_write_reg(cam, 0x010A, 0x50);
-	err += zc0301_write_reg(cam, 0x010B, 0xF8);
-	err += zc0301_write_reg(cam, 0x010C, 0xF8);
-	err += zc0301_write_reg(cam, 0x010D, 0xF8);
-	err += zc0301_write_reg(cam, 0x010E, 0x50);
-	err += zc0301_write_reg(cam, 0x010F, 0xF8);
-	err += zc0301_write_reg(cam, 0x0110, 0xF8);
-	err += zc0301_write_reg(cam, 0x0111, 0xF8);
-	err += zc0301_write_reg(cam, 0x0112, 0x50);
-	err += zc0301_write_reg(cam, 0x0008, 0x03);
-	err += zc0301_write_reg(cam, 0x01C6, 0x08);
-	err += zc0301_write_reg(cam, 0x01CB, 0x0F);
-	err += zc0301_write_reg(cam, 0x010A, 0x50);
-	err += zc0301_write_reg(cam, 0x010B, 0xF8);
-	err += zc0301_write_reg(cam, 0x010C, 0xF8);
-	err += zc0301_write_reg(cam, 0x010D, 0xF8);
-	err += zc0301_write_reg(cam, 0x010E, 0x50);
-	err += zc0301_write_reg(cam, 0x010F, 0xF8);
-	err += zc0301_write_reg(cam, 0x0110, 0xF8);
-	err += zc0301_write_reg(cam, 0x0111, 0xF8);
-	err += zc0301_write_reg(cam, 0x0112, 0x50);
-	err += zc0301_write_reg(cam, 0x0180, 0x00);
-	err += zc0301_write_reg(cam, 0x0019, 0x00);
-
-	err += zc0301_i2c_write(cam, 0x05, 0x0066);
-	err += zc0301_i2c_write(cam, 0x09, 0x02B2);
-	err += zc0301_i2c_write(cam, 0x10, 0x0002);
-
-	err += zc0301_write_reg(cam, 0x011D, 0x60);
-	err += zc0301_write_reg(cam, 0x0190, 0x00);
-	err += zc0301_write_reg(cam, 0x0191, 0x07);
-	err += zc0301_write_reg(cam, 0x0192, 0x8C);
-	err += zc0301_write_reg(cam, 0x0195, 0x00);
-	err += zc0301_write_reg(cam, 0x0196, 0x00);
-	err += zc0301_write_reg(cam, 0x0197, 0x8A);
-	err += zc0301_write_reg(cam, 0x018C, 0x10);
-	err += zc0301_write_reg(cam, 0x018F, 0x20);
-	err += zc0301_write_reg(cam, 0x01A9, 0x14);
-	err += zc0301_write_reg(cam, 0x01AA, 0x24);
-	err += zc0301_write_reg(cam, 0x001D, 0xD7);
-	err += zc0301_write_reg(cam, 0x001E, 0xF0);
-	err += zc0301_write_reg(cam, 0x001F, 0xF8);
-	err += zc0301_write_reg(cam, 0x0020, 0xFF);
-	err += zc0301_write_reg(cam, 0x01AD, 0x09);
-	err += zc0301_write_reg(cam, 0x01AE, 0x15);
-	err += zc0301_write_reg(cam, 0x0180, 0x40);
-	err += zc0301_write_reg(cam, 0x0180, 0x42);
-
-	msleep(100);
-
-	return err;
-}
-
-
-static struct zc0301_sensor pb0330 = {
-	.name = "PB-0330",
-	.init = &pb0330_init,
-	.cropcap = {
-		.bounds = {
-			.left = 0,
-			.top = 0,
-			.width = 640,
-			.height = 480,
-		},
-		.defrect = {
-			.left = 0,
-			.top = 0,
-			.width = 640,
-			.height = 480,
-		},
-	},
-	.pix_format = {
-		.width = 640,
-		.height = 480,
-		.pixelformat = V4L2_PIX_FMT_JPEG,
-		.priv = 8,
-		.colorspace = V4L2_COLORSPACE_JPEG,
-	},
-};
-
-
-int zc0301_probe_pb0330(struct zc0301_device* cam)
-{
-	int r0, err = 0;
-
-	err += zc0301_write_reg(cam, 0x0000, 0x01);
-	err += zc0301_write_reg(cam, 0x0010, 0x0a);
-	err += zc0301_write_reg(cam, 0x0001, 0x01);
-	err += zc0301_write_reg(cam, 0x0012, 0x03);
-	err += zc0301_write_reg(cam, 0x0012, 0x01);
-
-	msleep(10);
-
-	r0 = zc0301_i2c_read(cam, 0x00, 2);
-
-	if (r0 < 0 || err)
-		return -EIO;
-
-	if (r0 != 0x8243)
-		return -ENODEV;
-
-	zc0301_attach_sensor(cam, &pb0330);
-
-	return 0;
-}
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
deleted file mode 100644
index 0be783c..0000000
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/***************************************************************************
- * API for image sensors connected to the ZC0301[P] Image Processor and    *
- * Control Chip                                                            *
- *                                                                         *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _ZC0301_SENSOR_H_
-#define _ZC0301_SENSOR_H_
-
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/device.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-
-struct zc0301_device;
-struct zc0301_sensor;
-
-/*****************************************************************************/
-
-extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
-extern int zc0301_probe_pb0330(struct zc0301_device* cam);
-
-#define ZC0301_SENSOR_TABLE                                                   \
-/* Weak detections must go at the end of the list */                          \
-static int (*zc0301_sensor_table[])(struct zc0301_device*) = {                \
-	&zc0301_probe_pas202bcb,                                              \
-	&zc0301_probe_pb0330,                                                 \
-	NULL,                                                                 \
-};
-
-extern struct zc0301_device*
-zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id);
-
-extern void
-zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
-
-#define ZC0301_USB_DEVICE(vend, prod, intclass)                               \
-	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
-		       USB_DEVICE_ID_MATCH_INT_CLASS,                         \
-	.idVendor = (vend),                                                   \
-	.idProduct = (prod),                                                  \
-	.bInterfaceClass = (intclass)
-
-#if !defined CONFIG_USB_GSPCA_ZC3XX && !defined CONFIG_USB_GSPCA_ZC3XX_MODULE
-#define ZC0301_ID_TABLE                                                       \
-static const struct usb_device_id zc0301_id_table[] =  {                      \
-	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
-	{ ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */           \
-	{ }                                                                   \
-};
-#else
-#define ZC0301_ID_TABLE                                                       \
-static const struct usb_device_id zc0301_id_table[] =  {                      \
-	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
-	{ }                                                                   \
-};
-#endif
-
-/*****************************************************************************/
-
-extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value);
-extern int zc0301_read_reg(struct zc0301_device*, u16 index);
-extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value);
-extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length);
-
-/*****************************************************************************/
-
-#define ZC0301_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
-#define ZC0301_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
-#define ZC0301_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1)
-
-struct zc0301_sensor {
-	char name[32];
-
-	struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS];
-	struct v4l2_cropcap cropcap;
-	struct v4l2_pix_format pix_format;
-
-	int (*init)(struct zc0301_device*);
-	int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl);
-	int (*set_ctrl)(struct zc0301_device*,
-			const struct v4l2_control* ctrl);
-	int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect);
-
-	/* Private */
-	struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS];
-	struct v4l2_rect _rect;
-};
-
-#endif /* _ZC0301_SENSOR_H_ */
diff --git a/drivers/media/video/zoran/videocodec.c b/drivers/media/video/zoran/videocodec.c
index cf24956..c010716 100644
--- a/drivers/media/video/zoran/videocodec.c
+++ b/drivers/media/video/zoran/videocodec.c
@@ -107,15 +107,14 @@
 			if (!try_module_get(h->codec->owner))
 				return NULL;
 
-			codec =
-			    kmalloc(sizeof(struct videocodec), GFP_KERNEL);
+			codec = kmemdup(h->codec, sizeof(struct videocodec),
+					GFP_KERNEL);
 			if (!codec) {
 				dprintk(1,
 					KERN_ERR
 					"videocodec_attach: no mem\n");
 				goto out_module_put;
 			}
-			memcpy(codec, h->codec, sizeof(struct videocodec));
 
 			snprintf(codec->name, sizeof(codec->name),
 				 "%s[%d]", codec->name, h->attached);
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 14d162f..b88a244 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -115,6 +115,7 @@
 	" and halt Firmware on fault - (default=0)");
 
 
+static char	MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS][50];
 
 #ifdef MFCNT
 static int mfcounter = 0;
@@ -213,7 +214,7 @@
 static void	mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
 static void	mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
 static void	mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
-static void	mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
+static void	mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx);
 static int	mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
 static void	mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
 
@@ -490,7 +491,7 @@
 		else if (ioc->bus_type == SPI)
 			mpt_spi_log_info(ioc, log_info);
 		else if (ioc->bus_type == SAS)
-			mpt_sas_log_info(ioc, log_info);
+			mpt_sas_log_info(ioc, log_info, cb_idx);
 	}
 
 	if (ioc_stat & MPI_IOCSTATUS_MASK)
@@ -644,7 +645,7 @@
  *	considered an error by the caller.
  */
 u8
-mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
+mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)
 {
 	u8 cb_idx;
 	last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
@@ -659,6 +660,8 @@
 			MptDriverClass[cb_idx] = dclass;
 			MptEvHandlers[cb_idx] = NULL;
 			last_drv_idx = cb_idx;
+			memcpy(MptCallbacksName[cb_idx], func_name,
+			    strlen(func_name) > 50 ? 50 : strlen(func_name));
 			break;
 		}
 	}
@@ -1632,6 +1635,7 @@
 		} else {
 			printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
 			    ioc->name, pci_name(pdev));
+			pci_release_selected_regions(pdev, ioc->bars);
 			return r;
 		}
 	} else {
@@ -1645,6 +1649,7 @@
 		} else {
 			printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
 			    ioc->name, pci_name(pdev));
+			pci_release_selected_regions(pdev, ioc->bars);
 			return r;
 		}
 	}
@@ -1675,6 +1680,7 @@
 	if (mem == NULL) {
 		printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
 			" memory!\n", ioc->name);
+		pci_release_selected_regions(pdev, ioc->bars);
 		return -EINVAL;
 	}
 	ioc->memmap = mem;
@@ -1770,7 +1776,6 @@
 	ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;		/* avoid div by zero! */
 	ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
 
-	ioc->pcidev = pdev;
 
 	spin_lock_init(&ioc->taskmgmt_lock);
 	mutex_init(&ioc->internal_cmds.mutex);
@@ -1913,6 +1918,9 @@
 		ioc->msi_enable = 0;
 		break;
 	}
+
+	ioc->fw_events_off = 1;
+
 	if (ioc->errata_flag_1064)
 		pci_disable_io_access(pdev);
 
@@ -2051,7 +2059,6 @@
 
 	mpt_adapter_dispose(ioc);
 
-	pci_set_drvdata(pdev, NULL);
 }
 
 /**************************************************************************
@@ -5062,8 +5069,9 @@
 		if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
 			goto out;
 		if (!timeleft) {
-			printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
-			    ioc->name, __func__);
+			printk(MYIOC_s_WARN_FMT
+			       "Issuing Reset from %s!!, doorbell=0x%08x\n",
+			       ioc->name, __func__, mpt_GetIocState(ioc, 0));
 			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
 			mpt_free_msg_frame(ioc, mf);
 		}
@@ -6454,8 +6462,9 @@
 	mutex_unlock(&ioc->mptbase_cmds.mutex);
 	if (issue_hard_reset) {
 		issue_hard_reset = 0;
-		printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
-		    ioc->name, __func__);
+		printk(MYIOC_s_WARN_FMT
+		       "Issuing Reset from %s!!, doorbell=0x%08x\n",
+		       ioc->name, __func__, mpt_GetIocState(ioc, 0));
 		if (retry_count == 0) {
 			if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
 				retry_count++;
@@ -6971,6 +6980,7 @@
 
 	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
 	if (ioc->taskmgmt_in_progress) {
+		ioc->ioc_reset_in_progress = 0;
 		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 		return -1;
 	}
@@ -7144,7 +7154,8 @@
 	rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
 	if (rc != 0) {
 		printk(KERN_WARNING MYNAM
-		    ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name);
+		       ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
+		       rc, ioc->name, mpt_GetIocState(ioc, 0));
 	} else {
 		if (ioc->hard_resets < -1)
 			ioc->hard_resets++;
@@ -7997,7 +8008,7 @@
  *	Refer to lsi/mpi_log_sas.h.
  **/
 static void
-mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
+mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)
 {
 union loginfo_type {
 	u32	loginfo;
@@ -8051,21 +8062,22 @@
 	if (sub_code_desc != NULL)
 		printk(MYIOC_s_INFO_FMT
 			"LogInfo(0x%08x): Originator={%s}, Code={%s},"
-			" SubCode={%s}\n",
+			" SubCode={%s} cb_idx %s\n",
 			ioc->name, log_info, originator_desc, code_desc,
-			sub_code_desc);
+			sub_code_desc, MptCallbacksName[cb_idx]);
 	else if (code_desc != NULL)
 		printk(MYIOC_s_INFO_FMT
 			"LogInfo(0x%08x): Originator={%s}, Code={%s},"
-			" SubCode(0x%04x)\n",
+			" SubCode(0x%04x) cb_idx %s\n",
 			ioc->name, log_info, originator_desc, code_desc,
-			sas_loginfo.dw.subcode);
+			sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);
 	else
 		printk(MYIOC_s_INFO_FMT
 			"LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
-			" SubCode(0x%04x)\n",
+			" SubCode(0x%04x) cb_idx %s\n",
 			ioc->name, log_info, originator_desc,
-			sas_loginfo.dw.code, sas_loginfo.dw.subcode);
+			sas_loginfo.dw.code, sas_loginfo.dw.subcode,
+			MptCallbacksName[cb_idx]);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -8430,7 +8442,8 @@
 	/*  Register ourselves (mptbase) in order to facilitate
 	 *  EventNotification handling.
 	 */
-	mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
+	mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,
+	    "mptbase_reply");
 
 	/* Register for hard reset handling callbacks.
 	 */
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index b613eb3..23ed3de 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -76,8 +76,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2008 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"3.04.15"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.04.15"
+#define MPT_LINUX_VERSION_COMMON	"3.04.17"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.04.17"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -396,6 +396,8 @@
 	u8			 raidVolume;	/* set, if RAID Volume */
 	u8			 type;		/* byte 0 of Inquiry data */
 	u8			 deleted;	/* target in process of being removed */
+	u8			 inDMD;		/* currently in the device
+						   removal delay timer */
 	u32			 num_luns;
 } VirtTarget;
 
@@ -580,6 +582,7 @@
 typedef void (*MPT_ADD_SGE)(void *pAddr, u32 flagslength, dma_addr_t dma_addr);
 typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length,
 		dma_addr_t dma_addr);
+typedef void (*MPT_SCHEDULE_TARGET_RESET)(void *ioc);
 
 /*
  *  Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
@@ -601,7 +604,7 @@
 	u16			 nvdata_version_default;
 	int			 debug_level;
 	u8			 io_missing_delay;
-	u8			 device_missing_delay;
+	u16			 device_missing_delay;
 	SYSIF_REGS __iomem	*chip;		/* == c8817000 (mmap) */
 	SYSIF_REGS __iomem	*pio_chip;	/* Programmed IO (downloadboot) */
 	u8			 bus_type;
@@ -738,6 +741,7 @@
 	int			 taskmgmt_in_progress;
 	u8			 taskmgmt_quiesce_io;
 	u8			 ioc_reset_in_progress;
+	MPT_SCHEDULE_TARGET_RESET schedule_target_reset;
 	struct work_struct	 sas_persist_task;
 
 	struct work_struct	 fc_setup_reset_work;
@@ -922,7 +926,8 @@
 extern int	 mpt_suspend(struct pci_dev *pdev, pm_message_t state);
 extern int	 mpt_resume(struct pci_dev *pdev);
 #endif
-extern u8	 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
+extern u8	 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass,
+		char *func_name);
 extern void	 mpt_deregister(u8 cb_idx);
 extern int	 mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc);
 extern void	 mpt_event_deregister(u8 cb_idx);
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index f06b291..d8ddfdf 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -261,10 +261,16 @@
 	/* We are done, issue wake up
 	 */
 	if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
-		if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT)
+		if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
 			mpt_clear_taskmgmt_in_progress_flag(ioc);
-		ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
-		complete(&ioc->ioctl_cmds.done);
+			ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+			complete(&ioc->ioctl_cmds.done);
+			if (ioc->bus_type == SAS)
+				ioc->schedule_target_reset(ioc);
+		} else {
+			ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+			complete(&ioc->ioctl_cmds.done);
+		}
 	}
 
  out_continuation:
@@ -298,6 +304,8 @@
 		mpt_clear_taskmgmt_in_progress_flag(ioc);
 		ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
 		complete(&ioc->taskmgmt_cmds.done);
+		if (ioc->bus_type == SAS)
+			ioc->schedule_target_reset(ioc);
 		return 1;
 	}
 	return 0;
@@ -946,9 +954,12 @@
 			mpt_free_msg_frame(iocp, mf);
 			goto fwdl_out;
 		}
-		if (!timeleft)
+		if (!timeleft) {
+			printk(MYIOC_s_WARN_FMT
+			       "FW download timeout, doorbell=0x%08x\n",
+			       iocp->name, mpt_GetIocState(iocp, 0));
 			mptctl_timeout_expired(iocp, mf);
-		else
+		} else
 			goto retry_wait;
 		goto fwdl_out;
 	}
@@ -2293,6 +2304,10 @@
 			goto done_free_mem;
 		}
 		if (!timeleft) {
+			printk(MYIOC_s_WARN_FMT
+			       "mpt cmd timeout, doorbell=0x%08x"
+			       " function=0x%x\n",
+			       ioc->name, mpt_GetIocState(ioc, 0), function);
 			if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
 				mutex_unlock(&ioc->taskmgmt_cmds.mutex);
 			mptctl_timeout_expired(ioc, mf);
@@ -2600,9 +2615,12 @@
 			mpt_free_msg_frame(ioc, mf);
 			goto out;
 		}
-		if (!timeleft)
+		if (!timeleft) {
+			printk(MYIOC_s_WARN_FMT
+			       "HOST INFO command timeout, doorbell=0x%08x\n",
+			       ioc->name, mpt_GetIocState(ioc, 0));
 			mptctl_timeout_expired(ioc, mf);
-		else
+		} else
 			goto retry_wait;
 		goto out;
 	}
@@ -3000,7 +3018,8 @@
 	 *  Install our handler
 	 */
 	++where;
-	mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER);
+	mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER,
+	    "mptctl_reply");
 	if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) {
 		printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
 		misc_deregister(&mptctl_miscdev);
@@ -3008,7 +3027,8 @@
 		goto out_fail;
 	}
 
-	mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
+	mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER,
+	    "mptctl_taskmgmt_reply");
 	if (!mptctl_taskmgmt_id || mptctl_taskmgmt_id >= MPT_MAX_PROTOCOL_DRIVERS) {
 		printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
 		mpt_deregister(mptctl_id);
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index b5f03ad..e15220f 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -1472,9 +1472,12 @@
 	if (!mptfc_transport_template)
 		return -ENODEV;
 
-	mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
-	mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
-	mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
+	mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER,
+	    "mptscsih_scandv_complete");
+	mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER,
+	    "mptscsih_scandv_complete");
+	mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER,
+	    "mptscsih_scandv_complete");
 
 	mpt_event_register(mptfcDoneCtx, mptfc_event_process);
 	mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset);
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index 4fa9665..cbe9607 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -1452,7 +1452,9 @@
 {
 	show_mptmod_ver(LANAME, LANVER);
 
-	if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) <= 0) {
+	LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER,
+				"lan_reply");
+	if (LanCtx <= 0) {
 		printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n");
 		return -EBUSY;
 	}
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index ac000e8..83a5115 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -57,6 +57,7 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_sas.h>
+#include <scsi/scsi_transport.h>
 #include <scsi/scsi_dbg.h>
 
 #include "mptbase.h"
@@ -126,6 +127,7 @@
 static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
 static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
 static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
+void	mptsas_schedule_target_reset(void *ioc);
 
 static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
 					MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
@@ -1139,6 +1141,44 @@
 }
 
 /**
+ * mptsas_schedule_target_reset- send pending target reset
+ * @iocp: per adapter object
+ *
+ * This function will delete scheduled target reset from the list and
+ * try to send next target reset. This will be called from completion
+ * context of any Task managment command.
+ */
+
+void
+mptsas_schedule_target_reset(void *iocp)
+{
+	MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp);
+	MPT_SCSI_HOST	*hd = shost_priv(ioc->sh);
+	struct list_head *head = &hd->target_reset_list;
+	struct mptsas_target_reset_event	*target_reset_list;
+	u8		id, channel;
+	/*
+	 * issue target reset to next device in the queue
+	 */
+
+	head = &hd->target_reset_list;
+	if (list_empty(head))
+		return;
+
+	target_reset_list = list_entry(head->next,
+		struct mptsas_target_reset_event, list);
+
+	id = target_reset_list->sas_event_data.TargetID;
+	channel = target_reset_list->sas_event_data.Bus;
+	target_reset_list->time_count = jiffies;
+
+	if (mptsas_target_reset(ioc, channel, id))
+		target_reset_list->target_reset_issued = 1;
+	return;
+}
+
+
+/**
  *	mptsas_taskmgmt_complete - complete SAS task management function
  *	@ioc: Pointer to MPT_ADAPTER structure
  *
@@ -1222,28 +1262,12 @@
 	 * enable work queue to remove device from upper layers
 	 */
 	list_del(&target_reset_list->list);
-	if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
+	if (!ioc->fw_events_off)
 		mptsas_queue_device_delete(ioc,
 			&target_reset_list->sas_event_data);
 
 
-	/*
-	 * issue target reset to next device in the queue
-	 */
-
-	head = &hd->target_reset_list;
-	if (list_empty(head))
-		return 1;
-
-	target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
-	    list);
-
-	id = target_reset_list->sas_event_data.TargetID;
-	channel = target_reset_list->sas_event_data.Bus;
-	target_reset_list->time_count = jiffies;
-
-	if (mptsas_target_reset(ioc, channel, id))
-		target_reset_list->target_reset_issued = 1;
+	ioc->schedule_target_reset(ioc);
 
 	return 1;
 }
@@ -1889,6 +1913,48 @@
 	return mptscsih_qcmd(SCpnt,done);
 }
 
+/**
+ *	mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout
+ *		if the device under question is currently in the
+ *		device removal delay.
+ *	@sc: scsi command that the midlayer is about to time out
+ *
+ **/
+static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc)
+{
+	MPT_SCSI_HOST *hd;
+	MPT_ADAPTER   *ioc;
+	VirtDevice    *vdevice;
+	enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
+
+	hd = shost_priv(sc->device->host);
+	if (hd == NULL) {
+		printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n",
+		    __func__, sc);
+		goto done;
+	}
+
+	ioc = hd->ioc;
+	if (ioc->bus_type != SAS) {
+		printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n",
+		    __func__, sc);
+		goto done;
+	}
+
+	vdevice = sc->device->hostdata;
+	if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD
+		|| vdevice->vtarget->deleted)) {
+		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed "
+		    "or in device removal delay (sc=%p)\n",
+		    ioc->name, __func__, sc));
+		rc = BLK_EH_RESET_TIMER;
+		goto done;
+	}
+
+done:
+	return rc;
+}
+
 
 static struct scsi_host_template mptsas_driver_template = {
 	.module				= THIS_MODULE,
@@ -2364,7 +2430,7 @@
 	SasIOUnitPage1_t *buffer;
 	dma_addr_t dma_handle;
 	int error;
-	u16 device_missing_delay;
+	u8 device_missing_delay;
 
 	memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
 	memset(&cfg, 0, sizeof(CONFIGPARMS));
@@ -2401,7 +2467,7 @@
 
 	ioc->io_missing_delay  =
 	    le16_to_cpu(buffer->IODeviceMissingDelay);
-	device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
+	device_missing_delay = buffer->ReportDeviceMissingDelay;
 	ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
 	    (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
 	    device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
@@ -2549,6 +2615,7 @@
 	device_info->sas_address = le64_to_cpu(sas_address);
 	device_info->device_info =
 	    le32_to_cpu(buffer->DeviceInfo);
+	device_info->flags = le16_to_cpu(buffer->Flags);
 
  out_free_consistent:
 	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
@@ -2960,6 +3027,7 @@
 	struct sas_phy *phy;
 	struct sas_port *port;
 	int error = 0;
+	VirtTarget *vtarget;
 
 	if (!dev) {
 		error = -ENODEV;
@@ -3182,6 +3250,16 @@
 					rphy_to_expander_device(rphy));
 	}
 
+	/* If the device exists,verify it wasn't previously flagged
+	as a missing device.  If so, clear it */
+	vtarget = mptsas_find_vtarget(ioc,
+	    phy_info->attached.channel,
+	    phy_info->attached.id);
+	if (vtarget && vtarget->inDMD) {
+		printk(KERN_INFO "Device returned, unsetting inDMD\n");
+		vtarget->inDMD = 0;
+	}
+
  out:
 	return error;
 }
@@ -3635,9 +3713,42 @@
 		    MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
 			phy_info->phy->negotiated_linkrate =
 			    SAS_LINK_RATE_FAILED;
-		else
+		else {
 			phy_info->phy->negotiated_linkrate =
 			    SAS_LINK_RATE_UNKNOWN;
+			if (ioc->device_missing_delay &&
+			    mptsas_is_end_device(&phy_info->attached)) {
+				struct scsi_device		*sdev;
+				VirtDevice			*vdevice;
+				u8	channel, id;
+				id = phy_info->attached.id;
+				channel = phy_info->attached.channel;
+				devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+				"Link down for fw_id %d:fw_channel %d\n",
+				    ioc->name, phy_info->attached.id,
+				    phy_info->attached.channel));
+
+				shost_for_each_device(sdev, ioc->sh) {
+					vdevice = sdev->hostdata;
+					if ((vdevice == NULL) ||
+						(vdevice->vtarget == NULL))
+						continue;
+					if ((vdevice->vtarget->tflags &
+					    MPT_TARGET_FLAGS_RAID_COMPONENT ||
+					    vdevice->vtarget->raidVolume))
+						continue;
+					if (vdevice->vtarget->id == id &&
+						vdevice->vtarget->channel ==
+						channel)
+						devtprintk(ioc,
+						printk(MYIOC_s_DEBUG_FMT
+						"SDEV OUTSTANDING CMDS"
+						"%d\n", ioc->name,
+						sdev->device_busy));
+				}
+
+			}
+		}
 	}
  out:
 	mptsas_free_fw_event(ioc, fw_event);
@@ -3840,6 +3951,13 @@
 		      MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
 			continue;
 
+		/* If there is no FW B_T mapping for this device then continue
+		 * */
+		if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+			|| !(sas_device.flags &
+			MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+			continue;
+
 		phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
 		if (!phy_info)
 			continue;
@@ -4149,6 +4267,14 @@
 			phys_disk.PhysDiskID))
 			continue;
 
+		/* If there is no FW B_T mapping for this device then continue
+		 * */
+		if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+			|| !(sas_device.flags &
+			MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+			continue;
+
+
 		phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
 		    sas_device.sas_address);
 		mptsas_add_end_device(ioc, phy_info);
@@ -4171,6 +4297,7 @@
 	struct mptsas_devinfo sas_device;
 	VirtTarget *vtarget;
 	int i;
+	struct mptsas_portinfo *port_info;
 
 	switch (hot_plug_info->event_type) {
 
@@ -4199,12 +4326,47 @@
 		    (hot_plug_info->channel << 8) +
 		    hot_plug_info->id);
 
+		/* If there is no FW B_T mapping for this device then break
+		 * */
+		if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+			|| !(sas_device.flags &
+			MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+			break;
+
 		if (!sas_device.handle)
 			return;
 
 		phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
-		if (!phy_info)
+		/* Only For SATA Device ADD */
+		if (!phy_info && (sas_device.device_info &
+				MPI_SAS_DEVICE_INFO_SATA_DEVICE)) {
+			devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+				"%s %d SATA HOT PLUG: "
+				"parent handle of device %x\n", ioc->name,
+				__func__, __LINE__, sas_device.handle_parent));
+			port_info = mptsas_find_portinfo_by_handle(ioc,
+				sas_device.handle_parent);
+
+			if (port_info == ioc->hba_port_info)
+				mptsas_probe_hba_phys(ioc);
+			else if (port_info)
+				mptsas_expander_refresh(ioc, port_info);
+			else {
+				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+					"%s %d port info is NULL\n",
+					ioc->name, __func__, __LINE__));
+				break;
+			}
+			phy_info = mptsas_refreshing_device_handles
+				(ioc, &sas_device);
+		}
+
+		if (!phy_info) {
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+				"%s %d phy info is NULL\n",
+				ioc->name, __func__, __LINE__));
 			break;
+		}
 
 		if (mptsas_get_rphy(phy_info))
 			break;
@@ -4241,6 +4403,13 @@
 			break;
 		}
 
+		/* If there is no FW B_T mapping for this device then break
+		 * */
+		if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+			|| !(sas_device.flags &
+			MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+			break;
+
 		phy_info = mptsas_find_phyinfo_by_sas_address(
 		    ioc, sas_device.sas_address);
 
@@ -4294,6 +4463,13 @@
 			break;
 		}
 
+		/* If there is no FW B_T mapping for this device then break
+		 * */
+		if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+			|| !(sas_device.flags &
+			MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+			break;
+
 		phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
 				sas_device.sas_address);
 		if (!phy_info) {
@@ -4727,8 +4903,9 @@
 	mutex_unlock(&ioc->taskmgmt_cmds.mutex);
 
 	if (issue_reset) {
-		printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
-		    ioc->name, __func__);
+		printk(MYIOC_s_WARN_FMT
+		       "Issuing Reset from %s!! doorbell=0x%08x\n",
+		       ioc->name, __func__, mpt_GetIocState(ioc, 0));
 		mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
 	}
 	mptsas_free_fw_event(ioc, fw_event);
@@ -4816,12 +4993,47 @@
 	{
 		EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
 		    (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
+		u16	ioc_stat;
+		ioc_stat = le16_to_cpu(reply->IOCStatus);
 
 		if (sas_event_data->ReasonCode ==
 		    MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
 			mptsas_target_reset_queue(ioc, sas_event_data);
 			return 0;
 		}
+		if (sas_event_data->ReasonCode ==
+			MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
+			ioc->device_missing_delay &&
+			(ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) {
+			VirtTarget *vtarget = NULL;
+			u8		id, channel;
+			u32	 log_info = le32_to_cpu(reply->IOCLogInfo);
+
+			id = sas_event_data->TargetID;
+			channel = sas_event_data->Bus;
+
+			vtarget = mptsas_find_vtarget(ioc, channel, id);
+			if (vtarget) {
+				devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+				    "LogInfo (0x%x) available for "
+				   "INTERNAL_DEVICE_RESET"
+				   "fw_id %d fw_channel %d\n", ioc->name,
+				   log_info, id, channel));
+				if (vtarget->raidVolume) {
+					devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+					"Skipping Raid Volume for inDMD\n",
+					ioc->name));
+				} else {
+					devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+					"Setting device flag inDMD\n",
+					ioc->name));
+					vtarget->inDMD = 1;
+				}
+
+			}
+
+		}
+
 		break;
 	}
 	case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
@@ -4924,7 +5136,7 @@
 	ioc->DoneCtx = mptsasDoneCtx;
 	ioc->TaskCtx = mptsasTaskCtx;
 	ioc->InternalCtx = mptsasInternalCtx;
-
+	ioc->schedule_target_reset = &mptsas_schedule_target_reset;
 	/*  Added sanity check on readiness of the MPT adapter.
 	 */
 	if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
@@ -5154,14 +5366,20 @@
 	    sas_attach_transport(&mptsas_transport_functions);
 	if (!mptsas_transport_template)
 		return -ENODEV;
+	mptsas_transport_template->eh_timed_out = mptsas_eh_timed_out;
 
-	mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
-	mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
+	mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER,
+	    "mptscsih_io_done");
+	mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER,
+	    "mptscsih_taskmgmt_complete");
 	mptsasInternalCtx =
-		mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
-	mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
+		mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER,
+		    "mptscsih_scandv_complete");
+	mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER,
+	    "mptsas_mgmt_done");
 	mptsasDeviceResetCtx =
-		mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
+		mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER,
+		    "mptsas_taskmgmt_complete");
 
 	mpt_event_register(mptsasDoneCtx, mptsas_event_process);
 	mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h
index 7b249ed..57e86ab 100644
--- a/drivers/message/fusion/mptsas.h
+++ b/drivers/message/fusion/mptsas.h
@@ -140,6 +140,7 @@
 	u64	sas_address;    /* WWN of this device,
 				   SATA is assigned by HBA,expander */
 	u32	device_info;	/* bitfield detailed info about this device */
+	u16	flags;		/* sas device pg0 flags */
 };
 
 /*
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 5c53624..59b8f53 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -664,6 +664,7 @@
 		u32	 log_info;
 
 		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
 		scsi_state = pScsiReply->SCSIState;
 		scsi_status = pScsiReply->SCSIStatus;
 		xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
@@ -738,13 +739,36 @@
 
 		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
 			if ( ioc->bus_type == SAS ) {
-				u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
-				if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
-					if ((log_info & SAS_LOGINFO_MASK)
-					    == SAS_LOGINFO_NEXUS_LOSS) {
-						sc->result = (DID_BUS_BUSY << 16);
-						break;
-					}
+				u16 ioc_status =
+				    le16_to_cpu(pScsiReply->IOCStatus);
+				if ((ioc_status &
+					MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
+					&&
+					((log_info & SAS_LOGINFO_MASK) ==
+					SAS_LOGINFO_NEXUS_LOSS)) {
+						VirtDevice *vdevice =
+						sc->device->hostdata;
+
+					    /* flag the device as being in
+					     * device removal delay so we can
+					     * notify the midlayer to hold off
+					     * on timeout eh */
+						if (vdevice && vdevice->
+							vtarget &&
+							vdevice->vtarget->
+							raidVolume)
+							printk(KERN_INFO
+							"Skipping Raid Volume"
+							"for inDMD\n");
+						else if (vdevice &&
+							vdevice->vtarget)
+							vdevice->vtarget->
+								inDMD = 1;
+
+					    sc->result =
+						    (DID_TRANSPORT_DISRUPTED
+						    << 16);
+					    break;
 				}
 			} else if (ioc->bus_type == FC) {
 				/*
@@ -1704,8 +1728,9 @@
 
 	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
 	if (issue_hard_reset) {
-		printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
-			ioc->name, __func__);
+		printk(MYIOC_s_WARN_FMT
+		       "Issuing Reset from %s!! doorbell=0x%08x\n",
+		       ioc->name, __func__, mpt_GetIocState(ioc, 0));
 		retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
 		mpt_free_msg_frame(ioc, mf);
 	}
@@ -2132,6 +2157,8 @@
 		mpt_clear_taskmgmt_in_progress_flag(ioc);
 		ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
 		complete(&ioc->taskmgmt_cmds.done);
+		if (ioc->bus_type == SAS)
+			ioc->schedule_target_reset(ioc);
 		return 1;
 	}
 	return 0;
@@ -2459,6 +2486,8 @@
 		ioc->name,sdev->tagged_supported, sdev->simple_tags,
 		sdev->ordered_tags));
 
+	blk_queue_dma_alignment (sdev->request_queue, 512 - 1);
+
 	return 0;
 }
 
@@ -3045,8 +3074,11 @@
 			goto out;
 		}
 		if (!timeleft) {
-			printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
-			    ioc->name, __func__);
+			printk(MYIOC_s_WARN_FMT
+			       "Issuing Reset from %s!! doorbell=0x%08xh"
+			       " cmd=0x%02x\n",
+			       ioc->name, __func__, mpt_GetIocState(ioc, 0),
+			       cmd);
 			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
 			mpt_free_msg_frame(ioc, mf);
 		}
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 1abaa5d..0e28031 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -1551,9 +1551,12 @@
 	if (!mptspi_transport_template)
 		return -ENODEV;
 
-	mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER);
-	mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER);
-	mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER);
+	mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER,
+	    "mptscsih_io_done");
+	mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER,
+	    "mptscsih_taskmgmt_complete");
+	mptspiInternalCtx = mpt_register(mptscsih_scandv_complete,
+	    MPTSPI_DRIVER, "mptscsih_scandv_complete");
 
 	mpt_event_register(mptspiDoneCtx, mptspi_event_process);
 	mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset);
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
index 48c84a5..00e5fcac8 100644
--- a/drivers/misc/enclosure.c
+++ b/drivers/misc/enclosure.c
@@ -285,8 +285,11 @@
 	cdev->groups = enclosure_groups;
 
 	err = device_register(cdev);
-	if (err)
-		ERR_PTR(err);
+	if (err) {
+		ecomp->number = -1;
+		put_device(cdev);
+		return ERR_PTR(err);
+	}
 
 	return ecomp;
 }
diff --git a/drivers/net/3c527.h b/drivers/net/3c527.h
index 75e28fe..d693b8d 100644
--- a/drivers/net/3c527.h
+++ b/drivers/net/3c527.h
@@ -34,7 +34,7 @@
 {
  	u16 mbox;
  	u16 data[1];
-} __attribute((packed));
+} __packed;
 
 struct skb_header
 {
@@ -43,7 +43,7 @@
 	u16 next;	/* Do not change! */
 	u16 length;
 	u32 data;
-} __attribute((packed));
+} __packed;
 
 struct mc32_stats
 {
@@ -68,7 +68,7 @@
 	u32 dataA[6];
 	u16 dataB[5];
 	u32 dataC[14];
-} __attribute((packed));
+} __packed;
 
 #define STATUS_MASK	0x0F
 #define COMPLETED	(1<<7)
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index d75803e..c754d88 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -435,7 +435,6 @@
    First the windows.  There are eight register windows, with the command
    and status registers available in each.
    */
-#define EL3WINDOW(win_num) iowrite16(SelectWindow + (win_num), ioaddr + EL3_CMD)
 #define EL3_CMD 0x0e
 #define EL3_STATUS 0x0e
 
@@ -645,10 +644,51 @@
 	u16 deferred;						/* Resend these interrupts when we
 										 * bale from the ISR */
 	u16 io_size;						/* Size of PCI region (for release_region) */
-	spinlock_t lock;					/* Serialise access to device & its vortex_private */
-	struct mii_if_info mii;				/* MII lib hooks/info */
+
+	/* Serialises access to hardware other than MII and variables below.
+	 * The lock hierarchy is rtnl_lock > lock > mii_lock > window_lock. */
+	spinlock_t lock;
+
+	spinlock_t mii_lock;		/* Serialises access to MII */
+	struct mii_if_info mii;		/* MII lib hooks/info */
+	spinlock_t window_lock;		/* Serialises access to windowed regs */
+	int window;			/* Register window */
 };
 
+static void window_set(struct vortex_private *vp, int window)
+{
+	if (window != vp->window) {
+		iowrite16(SelectWindow + window, vp->ioaddr + EL3_CMD);
+		vp->window = window;
+	}
+}
+
+#define DEFINE_WINDOW_IO(size)						\
+static u ## size							\
+window_read ## size(struct vortex_private *vp, int window, int addr)	\
+{									\
+	unsigned long flags;						\
+	u ## size ret;							\
+	spin_lock_irqsave(&vp->window_lock, flags);			\
+	window_set(vp, window);						\
+	ret = ioread ## size(vp->ioaddr + addr);			\
+	spin_unlock_irqrestore(&vp->window_lock, flags);		\
+	return ret;							\
+}									\
+static void								\
+window_write ## size(struct vortex_private *vp, u ## size value,	\
+		     int window, int addr)				\
+{									\
+	unsigned long flags;						\
+	spin_lock_irqsave(&vp->window_lock, flags);			\
+	window_set(vp, window);						\
+	iowrite ## size(value, vp->ioaddr + addr);			\
+	spin_unlock_irqrestore(&vp->window_lock, flags);		\
+}
+DEFINE_WINDOW_IO(8)
+DEFINE_WINDOW_IO(16)
+DEFINE_WINDOW_IO(32)
+
 #ifdef CONFIG_PCI
 #define DEVICE_PCI(dev) (((dev)->bus == &pci_bus_type) ? to_pci_dev((dev)) : NULL)
 #else
@@ -711,7 +751,7 @@
 static int vortex_up(struct net_device *dev);
 static void vortex_down(struct net_device *dev, int final);
 static int vortex_open(struct net_device *dev);
-static void mdio_sync(void __iomem *ioaddr, int bits);
+static void mdio_sync(struct vortex_private *vp, int bits);
 static int mdio_read(struct net_device *dev, int phy_id, int location);
 static void mdio_write(struct net_device *vp, int phy_id, int location, int value);
 static void vortex_timer(unsigned long arg);
@@ -980,10 +1020,16 @@
 	ioaddr = pci_iomap(pdev, pci_bar, 0);
 	if (!ioaddr) /* If mapping fails, fall-back to BAR 0... */
 		ioaddr = pci_iomap(pdev, 0, 0);
+	if (!ioaddr) {
+		pci_disable_device(pdev);
+		rc = -ENOMEM;
+		goto out;
+	}
 
 	rc = vortex_probe1(&pdev->dev, ioaddr, pdev->irq,
 			   ent->driver_data, unit);
 	if (rc < 0) {
+		pci_iounmap(pdev, ioaddr);
 		pci_disable_device(pdev);
 		goto out;
 	}
@@ -1119,6 +1165,7 @@
 	vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0;
 	vp->io_size = vci->io_size;
 	vp->card_idx = card_idx;
+	vp->window = -1;
 
 	/* module list only for Compaq device */
 	if (gendev == NULL) {
@@ -1154,6 +1201,8 @@
 	}
 
 	spin_lock_init(&vp->lock);
+	spin_lock_init(&vp->mii_lock);
+	spin_lock_init(&vp->window_lock);
 	vp->gendev = gendev;
 	vp->mii.dev = dev;
 	vp->mii.mdio_read = mdio_read;
@@ -1205,7 +1254,6 @@
 	vp->mii.force_media = vp->full_duplex;
 	vp->options = option;
 	/* Read the station address from the EEPROM. */
-	EL3WINDOW(0);
 	{
 		int base;
 
@@ -1218,14 +1266,15 @@
 
 		for (i = 0; i < 0x40; i++) {
 			int timer;
-			iowrite16(base + i, ioaddr + Wn0EepromCmd);
+			window_write16(vp, base + i, 0, Wn0EepromCmd);
 			/* Pause for at least 162 us. for the read to take place. */
 			for (timer = 10; timer >= 0; timer--) {
 				udelay(162);
-				if ((ioread16(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
+				if ((window_read16(vp, 0, Wn0EepromCmd) &
+				     0x8000) == 0)
 					break;
 			}
-			eeprom[i] = ioread16(ioaddr + Wn0EepromData);
+			eeprom[i] = window_read16(vp, 0, Wn0EepromData);
 		}
 	}
 	for (i = 0; i < 0x18; i++)
@@ -1250,9 +1299,8 @@
 		pr_err("*** EEPROM MAC address is invalid.\n");
 		goto free_ring;	/* With every pack */
 	}
-	EL3WINDOW(2);
 	for (i = 0; i < 6; i++)
-		iowrite8(dev->dev_addr[i], ioaddr + i);
+		window_write8(vp, dev->dev_addr[i], 2, i);
 
 	if (print_info)
 		pr_cont(", IRQ %d\n", dev->irq);
@@ -1261,8 +1309,7 @@
 		pr_warning(" *** Warning: IRQ %d is unlikely to work! ***\n",
 			   dev->irq);
 
-	EL3WINDOW(4);
-	step = (ioread8(ioaddr + Wn4_NetDiag) & 0x1e) >> 1;
+	step = (window_read8(vp, 4, Wn4_NetDiag) & 0x1e) >> 1;
 	if (print_info) {
 		pr_info("  product code %02x%02x rev %02x.%d date %02d-%02d-%02d\n",
 			eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14],
@@ -1285,17 +1332,15 @@
 				(unsigned long long)pci_resource_start(pdev, 2),
 				vp->cb_fn_base);
 		}
-		EL3WINDOW(2);
 
-		n = ioread16(ioaddr + Wn2_ResetOptions) & ~0x4010;
+		n = window_read16(vp, 2, Wn2_ResetOptions) & ~0x4010;
 		if (vp->drv_flags & INVERT_LED_PWR)
 			n |= 0x10;
 		if (vp->drv_flags & INVERT_MII_PWR)
 			n |= 0x4000;
-		iowrite16(n, ioaddr + Wn2_ResetOptions);
+		window_write16(vp, n, 2, Wn2_ResetOptions);
 		if (vp->drv_flags & WNO_XCVR_PWR) {
-			EL3WINDOW(0);
-			iowrite16(0x0800, ioaddr);
+			window_write16(vp, 0x0800, 0, 0);
 		}
 	}
 
@@ -1313,14 +1358,13 @@
 	{
 		static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
 		unsigned int config;
-		EL3WINDOW(3);
-		vp->available_media = ioread16(ioaddr + Wn3_Options);
+		vp->available_media = window_read16(vp, 3, Wn3_Options);
 		if ((vp->available_media & 0xff) == 0)		/* Broken 3c916 */
 			vp->available_media = 0x40;
-		config = ioread32(ioaddr + Wn3_Config);
+		config = window_read32(vp, 3, Wn3_Config);
 		if (print_info) {
 			pr_debug("  Internal config register is %4.4x, transceivers %#x.\n",
-				config, ioread16(ioaddr + Wn3_Options));
+				config, window_read16(vp, 3, Wn3_Options));
 			pr_info("  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
 				   8 << RAM_SIZE(config),
 				   RAM_WIDTH(config) ? "word" : "byte",
@@ -1346,11 +1390,10 @@
 	if ((vp->available_media & 0x40) || (vci->drv_flags & HAS_NWAY) ||
 		dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
 		int phy, phy_idx = 0;
-		EL3WINDOW(4);
 		mii_preamble_required++;
 		if (vp->drv_flags & EXTRA_PREAMBLE)
 			mii_preamble_required++;
-		mdio_sync(ioaddr, 32);
+		mdio_sync(vp, 32);
 		mdio_read(dev, 24, MII_BMSR);
 		for (phy = 0; phy < 32 && phy_idx < 1; phy++) {
 			int mii_status, phyx;
@@ -1478,18 +1521,17 @@
 vortex_set_duplex(struct net_device *dev)
 {
 	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
 
 	pr_info("%s:  setting %s-duplex.\n",
 		dev->name, (vp->full_duplex) ? "full" : "half");
 
-	EL3WINDOW(3);
 	/* Set the full-duplex bit. */
-	iowrite16(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
-		 	(vp->large_frames ? 0x40 : 0) |
-			((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ?
-					0x100 : 0),
-			ioaddr + Wn3_MAC_Ctrl);
+	window_write16(vp,
+		       ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
+		       (vp->large_frames ? 0x40 : 0) |
+		       ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ?
+			0x100 : 0),
+		       3, Wn3_MAC_Ctrl);
 }
 
 static void vortex_check_media(struct net_device *dev, unsigned int init)
@@ -1529,8 +1571,7 @@
 	}
 
 	/* Before initializing select the active media port. */
-	EL3WINDOW(3);
-	config = ioread32(ioaddr + Wn3_Config);
+	config = window_read32(vp, 3, Wn3_Config);
 
 	if (vp->media_override != 7) {
 		pr_info("%s: Media override to transceiver %d (%s).\n",
@@ -1577,10 +1618,9 @@
 	config = BFINS(config, dev->if_port, 20, 4);
 	if (vortex_debug > 6)
 		pr_debug("vortex_up(): writing 0x%x to InternalConfig\n", config);
-	iowrite32(config, ioaddr + Wn3_Config);
+	window_write32(vp, config, 3, Wn3_Config);
 
 	if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
-		EL3WINDOW(4);
 		mii_reg1 = mdio_read(dev, vp->phys[0], MII_BMSR);
 		mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA);
 		vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0);
@@ -1601,51 +1641,46 @@
 	iowrite16(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
 
 	if (vortex_debug > 1) {
-		EL3WINDOW(4);
 		pr_debug("%s: vortex_up() irq %d media status %4.4x.\n",
-			   dev->name, dev->irq, ioread16(ioaddr + Wn4_Media));
+			   dev->name, dev->irq, window_read16(vp, 4, Wn4_Media));
 	}
 
 	/* Set the station address and mask in window 2 each time opened. */
-	EL3WINDOW(2);
 	for (i = 0; i < 6; i++)
-		iowrite8(dev->dev_addr[i], ioaddr + i);
+		window_write8(vp, dev->dev_addr[i], 2, i);
 	for (; i < 12; i+=2)
-		iowrite16(0, ioaddr + i);
+		window_write16(vp, 0, 2, i);
 
 	if (vp->cb_fn_base) {
-		unsigned short n = ioread16(ioaddr + Wn2_ResetOptions) & ~0x4010;
+		unsigned short n = window_read16(vp, 2, Wn2_ResetOptions) & ~0x4010;
 		if (vp->drv_flags & INVERT_LED_PWR)
 			n |= 0x10;
 		if (vp->drv_flags & INVERT_MII_PWR)
 			n |= 0x4000;
-		iowrite16(n, ioaddr + Wn2_ResetOptions);
+		window_write16(vp, n, 2, Wn2_ResetOptions);
 	}
 
 	if (dev->if_port == XCVR_10base2)
 		/* Start the thinnet transceiver. We should really wait 50ms...*/
 		iowrite16(StartCoax, ioaddr + EL3_CMD);
 	if (dev->if_port != XCVR_NWAY) {
-		EL3WINDOW(4);
-		iowrite16((ioread16(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) |
-			 media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
+		window_write16(vp,
+			       (window_read16(vp, 4, Wn4_Media) &
+				~(Media_10TP|Media_SQE)) |
+			       media_tbl[dev->if_port].media_bits,
+			       4, Wn4_Media);
 	}
 
 	/* Switch to the stats window, and clear all stats by reading. */
 	iowrite16(StatsDisable, ioaddr + EL3_CMD);
-	EL3WINDOW(6);
 	for (i = 0; i < 10; i++)
-		ioread8(ioaddr + i);
-	ioread16(ioaddr + 10);
-	ioread16(ioaddr + 12);
+		window_read8(vp, 6, i);
+	window_read16(vp, 6, 10);
+	window_read16(vp, 6, 12);
 	/* New: On the Vortex we must also clear the BadSSD counter. */
-	EL3WINDOW(4);
-	ioread8(ioaddr + 12);
+	window_read8(vp, 4, 12);
 	/* ..and on the Boomerang we enable the extra statistics bits. */
-	iowrite16(0x0040, ioaddr + Wn4_NetDiag);
-
-	/* Switch to register set 7 for normal use. */
-	EL3WINDOW(7);
+	window_write16(vp, 0x0040, 4, Wn4_NetDiag);
 
 	if (vp->full_bus_master_rx) { /* Boomerang bus master. */
 		vp->cur_rx = vp->dirty_rx = 0;
@@ -1763,7 +1798,7 @@
 	void __iomem *ioaddr = vp->ioaddr;
 	int next_tick = 60*HZ;
 	int ok = 0;
-	int media_status, old_window;
+	int media_status;
 
 	if (vortex_debug > 2) {
 		pr_debug("%s: Media selection timer tick happened, %s.\n",
@@ -1771,10 +1806,7 @@
 		pr_debug("dev->watchdog_timeo=%d\n", dev->watchdog_timeo);
 	}
 
-	disable_irq_lockdep(dev->irq);
-	old_window = ioread16(ioaddr + EL3_CMD) >> 13;
-	EL3WINDOW(4);
-	media_status = ioread16(ioaddr + Wn4_Media);
+	media_status = window_read16(vp, 4, Wn4_Media);
 	switch (dev->if_port) {
 	case XCVR_10baseT:  case XCVR_100baseTx:  case XCVR_100baseFx:
 		if (media_status & Media_LnkBeat) {
@@ -1794,10 +1826,7 @@
 	case XCVR_MII: case XCVR_NWAY:
 		{
 			ok = 1;
-			/* Interrupts are already disabled */
-			spin_lock(&vp->lock);
 			vortex_check_media(dev, 0);
-			spin_unlock(&vp->lock);
 		}
 		break;
 	  default:					/* Other media types handled by Tx timeouts. */
@@ -1816,6 +1845,8 @@
 	if (!ok) {
 		unsigned int config;
 
+		spin_lock_irq(&vp->lock);
+
 		do {
 			dev->if_port = media_tbl[dev->if_port].next;
 		} while ( ! (vp->available_media & media_tbl[dev->if_port].mask));
@@ -1830,19 +1861,22 @@
 					   dev->name, media_tbl[dev->if_port].name);
 			next_tick = media_tbl[dev->if_port].wait;
 		}
-		iowrite16((media_status & ~(Media_10TP|Media_SQE)) |
-			 media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
+		window_write16(vp,
+			       (media_status & ~(Media_10TP|Media_SQE)) |
+			       media_tbl[dev->if_port].media_bits,
+			       4, Wn4_Media);
 
-		EL3WINDOW(3);
-		config = ioread32(ioaddr + Wn3_Config);
+		config = window_read32(vp, 3, Wn3_Config);
 		config = BFINS(config, dev->if_port, 20, 4);
-		iowrite32(config, ioaddr + Wn3_Config);
+		window_write32(vp, config, 3, Wn3_Config);
 
 		iowrite16(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
 			 ioaddr + EL3_CMD);
 		if (vortex_debug > 1)
 			pr_debug("wrote 0x%08x to Wn3_Config\n", config);
 		/* AKPM: FIXME: Should reset Rx & Tx here.  P60 of 3c90xc.pdf */
+
+		spin_unlock_irq(&vp->lock);
 	}
 
 leave_media_alone:
@@ -1850,8 +1884,6 @@
 	  pr_debug("%s: Media selection timer finished, %s.\n",
 			 dev->name, media_tbl[dev->if_port].name);
 
-	EL3WINDOW(old_window);
-	enable_irq_lockdep(dev->irq);
 	mod_timer(&vp->timer, RUN_AT(next_tick));
 	if (vp->deferred)
 		iowrite16(FakeIntr, ioaddr + EL3_CMD);
@@ -1865,12 +1897,11 @@
 	pr_err("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
 		   dev->name, ioread8(ioaddr + TxStatus),
 		   ioread16(ioaddr + EL3_STATUS));
-	EL3WINDOW(4);
 	pr_err("  diagnostics: net %04x media %04x dma %08x fifo %04x\n",
-			ioread16(ioaddr + Wn4_NetDiag),
-			ioread16(ioaddr + Wn4_Media),
+			window_read16(vp, 4, Wn4_NetDiag),
+			window_read16(vp, 4, Wn4_Media),
 			ioread32(ioaddr + PktStatus),
-			ioread16(ioaddr + Wn4_FIFODiag));
+			window_read16(vp, 4, Wn4_FIFODiag));
 	/* Slight code bloat to be user friendly. */
 	if ((ioread8(ioaddr + TxStatus) & 0x88) == 0x88)
 		pr_err("%s: Transmitter encountered 16 collisions --"
@@ -1917,9 +1948,6 @@
 	/* Issue Tx Enable */
 	iowrite16(TxEnable, ioaddr + EL3_CMD);
 	dev->trans_start = jiffies; /* prevent tx timeout */
-
-	/* Switch to register set 7 for normal use. */
-	EL3WINDOW(7);
 }
 
 /*
@@ -1980,10 +2008,10 @@
 			ioread16(ioaddr + EL3_STATUS) & StatsFull) {
 			pr_warning("%s: Updating statistics failed, disabling "
 				   "stats as an interrupt source.\n", dev->name);
-			EL3WINDOW(5);
-			iowrite16(SetIntrEnb | (ioread16(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD);
+			iowrite16(SetIntrEnb |
+				  (window_read16(vp, 5, 10) & ~StatsFull),
+				  ioaddr + EL3_CMD);
 			vp->intr_enable &= ~StatsFull;
-			EL3WINDOW(7);
 			DoneDidThat++;
 		}
 	}
@@ -1993,8 +2021,7 @@
 	}
 	if (status & HostError) {
 		u16 fifo_diag;
-		EL3WINDOW(4);
-		fifo_diag = ioread16(ioaddr + Wn4_FIFODiag);
+		fifo_diag = window_read16(vp, 4, Wn4_FIFODiag);
 		pr_err("%s: Host error, FIFO diagnostic register %4.4x.\n",
 			   dev->name, fifo_diag);
 		/* Adapter failure requires Tx/Rx reset and reinit. */
@@ -2043,9 +2070,13 @@
 	if (vp->bus_master) {
 		/* Set the bus-master controller to transfer the packet. */
 		int len = (skb->len + 3) & ~3;
-		iowrite32(vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len, PCI_DMA_TODEVICE),
-				ioaddr + Wn7_MasterAddr);
+		vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len,
+						PCI_DMA_TODEVICE);
+		spin_lock_irq(&vp->window_lock);
+		window_set(vp, 7);
+		iowrite32(vp->tx_skb_dma, ioaddr + Wn7_MasterAddr);
 		iowrite16(len, ioaddr + Wn7_MasterLen);
+		spin_unlock_irq(&vp->window_lock);
 		vp->tx_skb = skb;
 		iowrite16(StartDMADown, ioaddr + EL3_CMD);
 		/* netif_wake_queue() will be called at the DMADone interrupt. */
@@ -2217,6 +2248,9 @@
 		pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n",
 			   dev->name, status, ioread8(ioaddr + Timer));
 
+	spin_lock(&vp->window_lock);
+	window_set(vp, 7);
+
 	do {
 		if (vortex_debug > 5)
 				pr_debug("%s: In interrupt loop, status %4.4x.\n",
@@ -2275,6 +2309,8 @@
 		iowrite16(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
 	} while ((status = ioread16(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
 
+	spin_unlock(&vp->window_lock);
+
 	if (vortex_debug > 4)
 		pr_debug("%s: exiting interrupt, status %4.4x.\n",
 			   dev->name, status);
@@ -2760,85 +2796,58 @@
 static void update_stats(void __iomem *ioaddr, struct net_device *dev)
 {
 	struct vortex_private *vp = netdev_priv(dev);
-	int old_window = ioread16(ioaddr + EL3_CMD);
 
-	if (old_window == 0xffff)	/* Chip suspended or ejected. */
-		return;
 	/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
 	/* Switch to the stats window, and read everything. */
-	EL3WINDOW(6);
-	dev->stats.tx_carrier_errors		+= ioread8(ioaddr + 0);
-	dev->stats.tx_heartbeat_errors		+= ioread8(ioaddr + 1);
-	dev->stats.tx_window_errors		+= ioread8(ioaddr + 4);
-	dev->stats.rx_fifo_errors		+= ioread8(ioaddr + 5);
-	dev->stats.tx_packets			+= ioread8(ioaddr + 6);
-	dev->stats.tx_packets			+= (ioread8(ioaddr + 9)&0x30) << 4;
-	/* Rx packets	*/			ioread8(ioaddr + 7);   /* Must read to clear */
+	dev->stats.tx_carrier_errors		+= window_read8(vp, 6, 0);
+	dev->stats.tx_heartbeat_errors		+= window_read8(vp, 6, 1);
+	dev->stats.tx_window_errors		+= window_read8(vp, 6, 4);
+	dev->stats.rx_fifo_errors		+= window_read8(vp, 6, 5);
+	dev->stats.tx_packets			+= window_read8(vp, 6, 6);
+	dev->stats.tx_packets			+= (window_read8(vp, 6, 9) &
+						    0x30) << 4;
+	/* Rx packets	*/			window_read8(vp, 6, 7);   /* Must read to clear */
 	/* Don't bother with register 9, an extension of registers 6&7.
 	   If we do use the 6&7 values the atomic update assumption above
 	   is invalid. */
-	dev->stats.rx_bytes 			+= ioread16(ioaddr + 10);
-	dev->stats.tx_bytes 			+= ioread16(ioaddr + 12);
+	dev->stats.rx_bytes 			+= window_read16(vp, 6, 10);
+	dev->stats.tx_bytes 			+= window_read16(vp, 6, 12);
 	/* Extra stats for get_ethtool_stats() */
-	vp->xstats.tx_multiple_collisions	+= ioread8(ioaddr + 2);
-	vp->xstats.tx_single_collisions         += ioread8(ioaddr + 3);
-	vp->xstats.tx_deferred			+= ioread8(ioaddr + 8);
-	EL3WINDOW(4);
-	vp->xstats.rx_bad_ssd			+= ioread8(ioaddr + 12);
+	vp->xstats.tx_multiple_collisions	+= window_read8(vp, 6, 2);
+	vp->xstats.tx_single_collisions         += window_read8(vp, 6, 3);
+	vp->xstats.tx_deferred			+= window_read8(vp, 6, 8);
+	vp->xstats.rx_bad_ssd			+= window_read8(vp, 4, 12);
 
 	dev->stats.collisions = vp->xstats.tx_multiple_collisions
 		+ vp->xstats.tx_single_collisions
 		+ vp->xstats.tx_max_collisions;
 
 	{
-		u8 up = ioread8(ioaddr + 13);
+		u8 up = window_read8(vp, 4, 13);
 		dev->stats.rx_bytes += (up & 0x0f) << 16;
 		dev->stats.tx_bytes += (up & 0xf0) << 12;
 	}
-
-	EL3WINDOW(old_window >> 13);
 }
 
 static int vortex_nway_reset(struct net_device *dev)
 {
 	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	unsigned long flags;
-	int rc;
 
-	spin_lock_irqsave(&vp->lock, flags);
-	EL3WINDOW(4);
-	rc = mii_nway_restart(&vp->mii);
-	spin_unlock_irqrestore(&vp->lock, flags);
-	return rc;
+	return mii_nway_restart(&vp->mii);
 }
 
 static int vortex_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	unsigned long flags;
-	int rc;
 
-	spin_lock_irqsave(&vp->lock, flags);
-	EL3WINDOW(4);
-	rc = mii_ethtool_gset(&vp->mii, cmd);
-	spin_unlock_irqrestore(&vp->lock, flags);
-	return rc;
+	return mii_ethtool_gset(&vp->mii, cmd);
 }
 
 static int vortex_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	unsigned long flags;
-	int rc;
 
-	spin_lock_irqsave(&vp->lock, flags);
-	EL3WINDOW(4);
-	rc = mii_ethtool_sset(&vp->mii, cmd);
-	spin_unlock_irqrestore(&vp->lock, flags);
-	return rc;
+	return mii_ethtool_sset(&vp->mii, cmd);
 }
 
 static u32 vortex_get_msglevel(struct net_device *dev)
@@ -2909,6 +2918,36 @@
 	}
 }
 
+static void vortex_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct vortex_private *vp = netdev_priv(dev);
+
+	spin_lock_irq(&vp->lock);
+	wol->supported = WAKE_MAGIC;
+
+	wol->wolopts = 0;
+	if (vp->enable_wol)
+		wol->wolopts |= WAKE_MAGIC;
+	spin_unlock_irq(&vp->lock);
+}
+
+static int vortex_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct vortex_private *vp = netdev_priv(dev);
+	if (wol->wolopts & ~WAKE_MAGIC)
+		return -EINVAL;
+
+	spin_lock_irq(&vp->lock);
+	if (wol->wolopts & WAKE_MAGIC)
+		vp->enable_wol = 1;
+	else
+		vp->enable_wol = 0;
+	acpi_set_WOL(dev);
+	spin_unlock_irq(&vp->lock);
+
+	return 0;
+}
+
 static const struct ethtool_ops vortex_ethtool_ops = {
 	.get_drvinfo		= vortex_get_drvinfo,
 	.get_strings            = vortex_get_strings,
@@ -2920,6 +2959,8 @@
 	.set_settings           = vortex_set_settings,
 	.get_link               = ethtool_op_get_link,
 	.nway_reset             = vortex_nway_reset,
+	.get_wol                = vortex_get_wol,
+	.set_wol                = vortex_set_wol,
 };
 
 #ifdef CONFIG_PCI
@@ -2930,7 +2971,6 @@
 {
 	int err;
 	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
 	unsigned long flags;
 	pci_power_t state = 0;
 
@@ -2942,7 +2982,6 @@
 	if(state != 0)
 		pci_set_power_state(VORTEX_PCI(vp), PCI_D0);
 	spin_lock_irqsave(&vp->lock, flags);
-	EL3WINDOW(4);
 	err = generic_mii_ioctl(&vp->mii, if_mii(rq), cmd, NULL);
 	spin_unlock_irqrestore(&vp->lock, flags);
 	if(state != 0)
@@ -2985,8 +3024,6 @@
 static void set_8021q_mode(struct net_device *dev, int enable)
 {
 	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	int old_window = ioread16(ioaddr + EL3_CMD);
 	int mac_ctrl;
 
 	if ((vp->drv_flags&IS_CYCLONE) || (vp->drv_flags&IS_TORNADO)) {
@@ -2997,28 +3034,23 @@
 		if (enable)
 			max_pkt_size += 4;	/* 802.1Q VLAN tag */
 
-		EL3WINDOW(3);
-		iowrite16(max_pkt_size, ioaddr+Wn3_MaxPktSize);
+		window_write16(vp, max_pkt_size, 3, Wn3_MaxPktSize);
 
 		/* set VlanEtherType to let the hardware checksumming
 		   treat tagged frames correctly */
-		EL3WINDOW(7);
-		iowrite16(VLAN_ETHER_TYPE, ioaddr+Wn7_VlanEtherType);
+		window_write16(vp, VLAN_ETHER_TYPE, 7, Wn7_VlanEtherType);
 	} else {
 		/* on older cards we have to enable large frames */
 
 		vp->large_frames = dev->mtu > 1500 || enable;
 
-		EL3WINDOW(3);
-		mac_ctrl = ioread16(ioaddr+Wn3_MAC_Ctrl);
+		mac_ctrl = window_read16(vp, 3, Wn3_MAC_Ctrl);
 		if (vp->large_frames)
 			mac_ctrl |= 0x40;
 		else
 			mac_ctrl &= ~0x40;
-		iowrite16(mac_ctrl, ioaddr+Wn3_MAC_Ctrl);
+		window_write16(vp, mac_ctrl, 3, Wn3_MAC_Ctrl);
 	}
-
-	EL3WINDOW(old_window);
 }
 #else
 
@@ -3037,7 +3069,10 @@
 /* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
    met by back-to-back PCI I/O cycles, but we insert a delay to avoid
    "overclocking" issues. */
-#define mdio_delay() ioread32(mdio_addr)
+static void mdio_delay(struct vortex_private *vp)
+{
+	window_read32(vp, 4, Wn4_PhysicalMgmt);
+}
 
 #define MDIO_SHIFT_CLK	0x01
 #define MDIO_DIR_WRITE	0x04
@@ -3048,16 +3083,15 @@
 
 /* Generate the preamble required for initial synchronization and
    a few older transceivers. */
-static void mdio_sync(void __iomem *ioaddr, int bits)
+static void mdio_sync(struct vortex_private *vp, int bits)
 {
-	void __iomem *mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
 	/* Establish sync by sending at least 32 logic ones. */
 	while (-- bits >= 0) {
-		iowrite16(MDIO_DATA_WRITE1, mdio_addr);
-		mdio_delay();
-		iowrite16(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
+		window_write16(vp, MDIO_DATA_WRITE1, 4, Wn4_PhysicalMgmt);
+		mdio_delay(vp);
+		window_write16(vp, MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK,
+			       4, Wn4_PhysicalMgmt);
+		mdio_delay(vp);
 	}
 }
 
@@ -3065,59 +3099,70 @@
 {
 	int i;
 	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
 	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
 	unsigned int retval = 0;
-	void __iomem *mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+	spin_lock_bh(&vp->mii_lock);
 
 	if (mii_preamble_required)
-		mdio_sync(ioaddr, 32);
+		mdio_sync(vp, 32);
 
 	/* Shift the read command bits out. */
 	for (i = 14; i >= 0; i--) {
 		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-		iowrite16(dataval, mdio_addr);
-		mdio_delay();
-		iowrite16(dataval | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
+		window_write16(vp, dataval, 4, Wn4_PhysicalMgmt);
+		mdio_delay(vp);
+		window_write16(vp, dataval | MDIO_SHIFT_CLK,
+			       4, Wn4_PhysicalMgmt);
+		mdio_delay(vp);
 	}
 	/* Read the two transition, 16 data, and wire-idle bits. */
 	for (i = 19; i > 0; i--) {
-		iowrite16(MDIO_ENB_IN, mdio_addr);
-		mdio_delay();
-		retval = (retval << 1) | ((ioread16(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
-		iowrite16(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
+		window_write16(vp, MDIO_ENB_IN, 4, Wn4_PhysicalMgmt);
+		mdio_delay(vp);
+		retval = (retval << 1) |
+			((window_read16(vp, 4, Wn4_PhysicalMgmt) &
+			  MDIO_DATA_READ) ? 1 : 0);
+		window_write16(vp, MDIO_ENB_IN | MDIO_SHIFT_CLK,
+			       4, Wn4_PhysicalMgmt);
+		mdio_delay(vp);
 	}
+
+	spin_unlock_bh(&vp->mii_lock);
+
 	return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
 }
 
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
 {
 	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
 	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
-	void __iomem *mdio_addr = ioaddr + Wn4_PhysicalMgmt;
 	int i;
 
+	spin_lock_bh(&vp->mii_lock);
+
 	if (mii_preamble_required)
-		mdio_sync(ioaddr, 32);
+		mdio_sync(vp, 32);
 
 	/* Shift the command bits out. */
 	for (i = 31; i >= 0; i--) {
 		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-		iowrite16(dataval, mdio_addr);
-		mdio_delay();
-		iowrite16(dataval | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
+		window_write16(vp, dataval, 4, Wn4_PhysicalMgmt);
+		mdio_delay(vp);
+		window_write16(vp, dataval | MDIO_SHIFT_CLK,
+			       4, Wn4_PhysicalMgmt);
+		mdio_delay(vp);
 	}
 	/* Leave the interface idle. */
 	for (i = 1; i >= 0; i--) {
-		iowrite16(MDIO_ENB_IN, mdio_addr);
-		mdio_delay();
-		iowrite16(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
+		window_write16(vp, MDIO_ENB_IN, 4, Wn4_PhysicalMgmt);
+		mdio_delay(vp);
+		window_write16(vp, MDIO_ENB_IN | MDIO_SHIFT_CLK,
+			       4, Wn4_PhysicalMgmt);
+		mdio_delay(vp);
 	}
+
+	spin_unlock_bh(&vp->mii_lock);
 }
 
 /* ACPI: Advanced Configuration and Power Interface. */
@@ -3131,8 +3176,7 @@
 
 	if (vp->enable_wol) {
 		/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
-		EL3WINDOW(7);
-		iowrite16(2, ioaddr + 0x0c);
+		window_write16(vp, 2, 7, 0x0c);
 		/* The RxFilter must accept the WOL frames. */
 		iowrite16(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
 		iowrite16(RxEnable, ioaddr + EL3_CMD);
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 284a5f4..4a4f6b8 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -322,7 +322,7 @@
 	__le32			rx_ok_mcast;
 	__le16			tx_abort;
 	__le16			tx_underrun;
-} __attribute__((packed));
+} __packed;
 
 struct cp_extra_stats {
 	unsigned long		rx_frags;
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 97d8068..f5166dc 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -662,7 +662,7 @@
 /* read MMIO register */
 #define RTL_R8(reg)		ioread8 (ioaddr + (reg))
 #define RTL_R16(reg)		ioread16 (ioaddr + (reg))
-#define RTL_R32(reg)		((unsigned long) ioread32 (ioaddr + (reg)))
+#define RTL_R32(reg)		ioread32 (ioaddr + (reg))
 
 
 static const u16 rtl8139_intr_mask =
@@ -862,7 +862,7 @@
 	/* if unknown chip, assume array element #0, original RTL-8139 in this case */
 	i = 0;
 	dev_dbg(&pdev->dev, "unknown chip version, assuming RTL-8139\n");
-	dev_dbg(&pdev->dev, "TxConfig = 0x%lx\n", RTL_R32 (TxConfig));
+	dev_dbg(&pdev->dev, "TxConfig = 0x%x\n", RTL_R32 (TxConfig));
 	tp->chipset = 0;
 
 match:
@@ -1643,7 +1643,7 @@
 	netdev_dbg(dev, "Tx queue start entry %ld  dirty entry %ld\n",
 		   tp->cur_tx, tp->dirty_tx);
 	for (i = 0; i < NUM_TX_DESC; i++)
-		netdev_dbg(dev, "Tx descriptor %d is %08lx%s\n",
+		netdev_dbg(dev, "Tx descriptor %d is %08x%s\n",
 			   i, RTL_R32(TxStatus0 + (i * 4)),
 			   i == tp->dirty_tx % NUM_TX_DESC ?
 			   " (queue head)" : "");
@@ -2487,7 +2487,7 @@
 	int rx_mode;
 	u32 tmp;
 
-	netdev_dbg(dev, "rtl8139_set_rx_mode(%04x) done -- Rx config %08lx\n",
+	netdev_dbg(dev, "rtl8139_set_rx_mode(%04x) done -- Rx config %08x\n",
 		   dev->flags, RTL_R32(RxConfig));
 
 	/* Note: do not reorder, GCC is clever about common statements. */
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index dd8dc15..e2c9c5b 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -525,7 +525,21 @@
 }
 #endif
 
-static inline void init_rx_bufs(struct net_device *dev)
+static inline void remove_rx_bufs(struct net_device *dev)
+{
+	struct i596_private *lp = dev->ml_priv;
+	struct i596_rbd *rbd;
+	int i;
+
+	for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
+		if (rbd->skb == NULL)
+			break;
+		dev_kfree_skb(rbd->skb);
+		rbd->skb = NULL;
+	}
+}
+
+static inline int init_rx_bufs(struct net_device *dev)
 {
 	struct i596_private *lp = dev->ml_priv;
 	int i;
@@ -537,8 +551,11 @@
 	for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
 		struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
 
-		if (skb == NULL)
-			panic("82596: alloc_skb() failed");
+		if (skb == NULL) {
+			remove_rx_bufs(dev);
+			return -ENOMEM;
+		}
+
 		skb->dev = dev;
 		rbd->v_next = rbd+1;
 		rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
@@ -574,19 +591,8 @@
 	rfd->v_next = lp->rfds;
 	rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds));
 	rfd->cmd = CMD_EOL|CMD_FLEX;
-}
 
-static inline void remove_rx_bufs(struct net_device *dev)
-{
-	struct i596_private *lp = dev->ml_priv;
-	struct i596_rbd *rbd;
-	int i;
-
-	for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
-		if (rbd->skb == NULL)
-			break;
-		dev_kfree_skb(rbd->skb);
-	}
+	return 0;
 }
 
 
@@ -1009,20 +1015,35 @@
 	}
 #ifdef ENABLE_MVME16x_NET
 	if (MACH_IS_MVME16x) {
-		if (request_irq(0x56, i596_error, 0, "i82596_error", dev))
-			return -EAGAIN;
+		if (request_irq(0x56, i596_error, 0, "i82596_error", dev)) {
+			res = -EAGAIN;
+			goto err_irq_dev;
+		}
 	}
 #endif
-	init_rx_bufs(dev);
+	res = init_rx_bufs(dev);
+	if (res)
+		goto err_irq_56;
 
 	netif_start_queue(dev);
 
-	/* Initialize the 82596 memory */
 	if (init_i596_mem(dev)) {
 		res = -EAGAIN;
-		free_irq(dev->irq, dev);
+		goto err_queue;
 	}
 
+	return 0;
+
+err_queue:
+	netif_stop_queue(dev);
+	remove_rx_bufs(dev);
+err_irq_56:
+#ifdef ENABLE_MVME16x_NET
+	free_irq(0x56, dev);
+err_irq_dev:
+#endif
+	free_irq(dev->irq, dev);
+
 	return res;
 }
 
@@ -1488,6 +1509,9 @@
 	}
 #endif
 
+#ifdef ENABLE_MVME16x_NET
+	free_irq(0x56, dev);
+#endif
 	free_irq(dev->irq, dev);
 	remove_rx_bufs(dev);
 
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index ce2fcdd..ebe6839 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -530,14 +530,15 @@
 	depends on SUPERH && \
 		(CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \
 		 CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \
-		 CPU_SUBTYPE_SH7724)
+		 CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7757)
 	select CRC32
 	select MII
 	select MDIO_BITBANG
 	select PHYLIB
 	help
 	  Renesas SuperH Ethernet device driver.
-	  This driver support SH7710, SH7712, SH7763, SH7619, and SH7724.
+	  This driver supporting CPUs are:
+		- SH7710, SH7712, SH7763, SH7619, SH7724, and SH7757.
 
 config SUNLANCE
 	tristate "Sun LANCE support"
@@ -1463,7 +1464,7 @@
 config CS89x0
 	tristate "CS89x0 support"
 	depends on NET_ETHERNET && (ISA || EISA || MACH_IXDP2351 \
-		|| ARCH_IXDP2X01 || ARCH_PNX010X || MACH_MX31ADS)
+		|| ARCH_IXDP2X01 || MACH_MX31ADS)
 	---help---
 	  Support for CS89x0 chipset based Ethernet cards. If you have a
 	  network (Ethernet) card of this type, say Y and read the
@@ -1477,7 +1478,7 @@
 config CS89x0_NONISA_IRQ
 	def_bool y
 	depends on CS89x0 != n
-	depends on MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X || MACH_MX31ADS
+	depends on MACH_IXDP2351 || ARCH_IXDP2X01 || MACH_MX31ADS
 
 config TC35815
 	tristate "TOSHIBA TC35815 Ethernet support"
@@ -1659,6 +1660,7 @@
 	depends on NET_PCI && PCI
 	select CRC32
 	select MII
+	select PHYLIB
 	help
 	  This is a driver for the R6040 Fast Ethernet MACs found in the
 	  the RDC R-321x System-on-chips.
@@ -1748,11 +1750,12 @@
 	  Please email feedback to <torben.mathiasen@compaq.com>.
 
 config KS8842
-	tristate "Micrel KSZ8842"
-	depends on HAS_IOMEM
+	tristate "Micrel KSZ8841/42 with generic bus interface"
+	depends on HAS_IOMEM && DMA_ENGINE
 	help
-	  This platform driver is for Micrel KSZ8842 / KS8842
-	  2-port ethernet switch chip (managed, VLAN, QoS).
+	 This platform driver is for KSZ8841(1-port) / KS8842(2-port)
+	 ethernet switch chip (managed, VLAN, QoS) from Micrel or
+	 Timberdale(FPGA).
 
 config KS8851
        tristate "Micrel KS8851 SPI"
@@ -2601,6 +2604,29 @@
 	  To compile this driver as a module choose M here; the module
 	  will be called cxgb4.
 
+config CHELSIO_T4VF_DEPENDS
+	tristate
+	depends on PCI && INET
+	default y
+
+config CHELSIO_T4VF
+	tristate "Chelsio Communications T4 Virtual Function Ethernet support"
+	depends on CHELSIO_T4VF_DEPENDS
+	help
+	  This driver supports Chelsio T4-based gigabit and 10Gb Ethernet
+	  adapters with PCI-E SR-IOV Virtual Functions.
+
+	  For general information about Chelsio and our products, visit
+	  our website at <http://www.chelsio.com>.
+
+	  For customer support, please visit our customer support page at
+	  <http://www.chelsio.com/support.htm>.
+
+	  Please send feedback to <linux-bugs@chelsio.com>.
+
+	  To compile this driver as a module choose M here; the module
+	  will be called cxgb4vf.
+
 config EHEA
 	tristate "eHEA Ethernet support"
 	depends on IBMEBUS && INET && SPARSEMEM
@@ -2614,7 +2640,6 @@
 config ENIC
 	tristate "Cisco VIC Ethernet NIC Support"
 	depends on PCI && INET
-	select INET_LRO
 	help
 	  This enables the support for the Cisco VIC Ethernet card.
 
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 0a0512a..56e8c27 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -20,6 +20,7 @@
 obj-$(CONFIG_CHELSIO_T1) += chelsio/
 obj-$(CONFIG_CHELSIO_T3) += cxgb3/
 obj-$(CONFIG_CHELSIO_T4) += cxgb4/
+obj-$(CONFIG_CHELSIO_T4VF) += cxgb4vf/
 obj-$(CONFIG_EHEA) += ehea/
 obj-$(CONFIG_CAN) += can/
 obj-$(CONFIG_BONDING) += bonding/
@@ -83,8 +84,7 @@
 obj-$(CONFIG_TIGON3) += tg3.o
 obj-$(CONFIG_BNX2) += bnx2.o
 obj-$(CONFIG_CNIC) += cnic.o
-obj-$(CONFIG_BNX2X) += bnx2x.o
-bnx2x-objs := bnx2x_main.o bnx2x_link.o
+obj-$(CONFIG_BNX2X) += bnx2x/
 spidernet-y += spider_net.o spider_net_ethtool.o
 obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o
 obj-$(CONFIG_GELIC_NET) += ps3_gelic.o
@@ -275,7 +275,7 @@
 obj-$(CONFIG_USB_ZD1201)        += usb/
 obj-$(CONFIG_USB_IPHETH)        += usb/
 
-obj-y += wireless/
+obj-$(CONFIG_WLAN) += wireless/
 obj-$(CONFIG_NET_TULIP) += tulip/
 obj-$(CONFIG_HAMRADIO) += hamradio/
 obj-$(CONFIG_IRDA) += irda/
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 3b79c6c..9bb405b 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -218,12 +218,6 @@
 #ifdef CONFIG_EL1		/* 3c501 */
 	{el1_probe, 0},
 #endif
-#ifdef CONFIG_WAVELAN		/* WaveLAN */
-	{wavelan_probe, 0},
-#endif
-#ifdef CONFIG_ARLAN		/* Aironet */
-	{arlan_probe, 0},
-#endif
 #ifdef CONFIG_EL16		/* 3c507 */
 	{el16_probe, 0},
 #endif
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index b9115a7..5181e93 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -211,7 +211,7 @@
 	retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
 	if (retval) {
 		printk (" nothing! Unable to get IRQ %d.\n", dev->irq);
-		goto out1;
+		goto out;
 	}
 
 	printk(" IRQ %d, %s port\n", dev->irq, port_name[dev->if_port]);
diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c
index 355797f..42fce91 100644
--- a/drivers/net/arcnet/capmode.c
+++ b/drivers/net/arcnet/capmode.c
@@ -37,69 +37,6 @@
 
 #define VERSION "arcnet: cap mode (`c') encapsulation support loaded.\n"
 
-
-static void rx(struct net_device *dev, int bufnum,
-	       struct archdr *pkthdr, int length);
-static int build_header(struct sk_buff *skb,
-			struct net_device *dev,
-			unsigned short type,
-			uint8_t daddr);
-static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
-		      int bufnum);
-static int ack_tx(struct net_device *dev, int acked);
-
-
-static struct ArcProto capmode_proto =
-{
-	'r',
-	XMTU,
-	0,
-       	rx,
-	build_header,
-	prepare_tx,
-	NULL,
-	ack_tx
-};
-
-
-static void arcnet_cap_init(void)
-{
-	int count;
-
-	for (count = 1; count <= 8; count++)
-		if (arc_proto_map[count] == arc_proto_default)
-			arc_proto_map[count] = &capmode_proto;
-
-	/* for cap mode, we only set the bcast proto if there's no better one */
-	if (arc_bcast_proto == arc_proto_default)
-		arc_bcast_proto = &capmode_proto;
-
-	arc_proto_default = &capmode_proto;
-	arc_raw_proto = &capmode_proto;
-}
-
-
-#ifdef MODULE
-
-static int __init capmode_module_init(void)
-{
-	printk(VERSION);
-	arcnet_cap_init();
-	return 0;
-}
-
-static void __exit capmode_module_exit(void)
-{
-	arcnet_unregister_proto(&capmode_proto);
-}
-module_init(capmode_module_init);
-module_exit(capmode_module_exit);
-
-MODULE_LICENSE("GPL");
-#endif				/* MODULE */
-
-
-
 /* packet receiver */
 static void rx(struct net_device *dev, int bufnum,
 	       struct archdr *pkthdr, int length)
@@ -231,65 +168,107 @@
 	BUGMSG(D_DURING, "prepare_tx: length=%d ofs=%d\n",
 	       length,ofs);
 
-	// Copy the arcnet-header + the protocol byte down:
+	/* Copy the arcnet-header + the protocol byte down: */
 	lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
 	lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft.cap.proto,
 			    sizeof(pkt->soft.cap.proto));
 
-	// Skip the extra integer we have written into it as a cookie
-	// but write the rest of the message:
+	/* Skip the extra integer we have written into it as a cookie
+	   but write the rest of the message: */
 	lp->hw.copy_to_card(dev, bufnum, ofs+1,
 			    ((unsigned char*)&pkt->soft.cap.mes),length-1);
 
 	lp->lastload_dest = hard->dest;
 
-	return 1;		/* done */
+	return 1;	/* done */
 }
 
-
 static int ack_tx(struct net_device *dev, int acked)
 {
-  struct arcnet_local *lp = netdev_priv(dev);
-  struct sk_buff *ackskb;
-  struct archdr *ackpkt;
-  int length=sizeof(struct arc_cap);
+	struct arcnet_local *lp = netdev_priv(dev);
+	struct sk_buff *ackskb;
+	struct archdr *ackpkt;
+	int length=sizeof(struct arc_cap);
 
-  BUGMSG(D_DURING, "capmode: ack_tx: protocol: %x: result: %d\n",
-	 lp->outgoing.skb->protocol, acked);
+	BUGMSG(D_DURING, "capmode: ack_tx: protocol: %x: result: %d\n",
+		lp->outgoing.skb->protocol, acked);
 
-  BUGLVL(D_SKB) arcnet_dump_skb(dev, lp->outgoing.skb, "ack_tx");
+	BUGLVL(D_SKB) arcnet_dump_skb(dev, lp->outgoing.skb, "ack_tx");
 
-  /* Now alloc a skb to send back up through the layers: */
-  ackskb = alloc_skb(length + ARC_HDR_SIZE , GFP_ATOMIC);
-  if (ackskb == NULL) {
-	  BUGMSG(D_NORMAL, "Memory squeeze, can't acknowledge.\n");
-	  goto free_outskb;
-  }
+	/* Now alloc a skb to send back up through the layers: */
+	ackskb = alloc_skb(length + ARC_HDR_SIZE , GFP_ATOMIC);
+	if (ackskb == NULL) {
+		BUGMSG(D_NORMAL, "Memory squeeze, can't acknowledge.\n");
+		goto free_outskb;
+	}
 
-  skb_put(ackskb, length + ARC_HDR_SIZE );
-  ackskb->dev = dev;
+	skb_put(ackskb, length + ARC_HDR_SIZE );
+	ackskb->dev = dev;
 
-  skb_reset_mac_header(ackskb);
-  ackpkt = (struct archdr *)skb_mac_header(ackskb);
-  /* skb_pull(ackskb, ARC_HDR_SIZE); */
+	skb_reset_mac_header(ackskb);
+	ackpkt = (struct archdr *)skb_mac_header(ackskb);
+	/* skb_pull(ackskb, ARC_HDR_SIZE); */
 
+	skb_copy_from_linear_data(lp->outgoing.skb, ackpkt,
+				  ARC_HDR_SIZE + sizeof(struct arc_cap));
+	ackpkt->soft.cap.proto = 0; /* using protocol 0 for acknowledge */
+	ackpkt->soft.cap.mes.ack=acked;
 
-  skb_copy_from_linear_data(lp->outgoing.skb, ackpkt,
-		ARC_HDR_SIZE + sizeof(struct arc_cap));
-  ackpkt->soft.cap.proto=0; /* using protocol 0 for acknowledge */
-  ackpkt->soft.cap.mes.ack=acked;
+	BUGMSG(D_PROTO, "Ackknowledge for cap packet %x.\n",
+			*((int*)&ackpkt->soft.cap.cookie[0]));
 
-  BUGMSG(D_PROTO, "Ackknowledge for cap packet %x.\n",
-	 *((int*)&ackpkt->soft.cap.cookie[0]));
+	ackskb->protocol = cpu_to_be16(ETH_P_ARCNET);
 
-  ackskb->protocol = cpu_to_be16(ETH_P_ARCNET);
+	BUGLVL(D_SKB) arcnet_dump_skb(dev, ackskb, "ack_tx_recv");
+	netif_rx(ackskb);
 
-  BUGLVL(D_SKB) arcnet_dump_skb(dev, ackskb, "ack_tx_recv");
-  netif_rx(ackskb);
+free_outskb:
+	dev_kfree_skb_irq(lp->outgoing.skb);
+	lp->outgoing.proto = NULL; /* We are always finished when in this protocol */
 
- free_outskb:
-  dev_kfree_skb_irq(lp->outgoing.skb);
-  lp->outgoing.proto = NULL; /* We are always finished when in this protocol */
-
-  return 0;
+	return 0;
 }
+
+static struct ArcProto capmode_proto =
+{
+	'r',
+	XMTU,
+	0,
+	rx,
+	build_header,
+	prepare_tx,
+	NULL,
+	ack_tx
+};
+
+static void arcnet_cap_init(void)
+{
+	int count;
+
+	for (count = 1; count <= 8; count++)
+		if (arc_proto_map[count] == arc_proto_default)
+			arc_proto_map[count] = &capmode_proto;
+
+	/* for cap mode, we only set the bcast proto if there's no better one */
+	if (arc_bcast_proto == arc_proto_default)
+		arc_bcast_proto = &capmode_proto;
+
+	arc_proto_default = &capmode_proto;
+	arc_raw_proto = &capmode_proto;
+}
+
+static int __init capmode_module_init(void)
+{
+	printk(VERSION);
+	arcnet_cap_init();
+	return 0;
+}
+
+static void __exit capmode_module_exit(void)
+{
+	arcnet_unregister_proto(&capmode_proto);
+}
+module_init(capmode_module_init);
+module_exit(capmode_module_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c
index 0402da3..3727282 100644
--- a/drivers/net/arcnet/com20020-isa.c
+++ b/drivers/net/arcnet/com20020-isa.c
@@ -90,14 +90,14 @@
 		outb(0, _INTMASK);
 		dev->irq = probe_irq_off(airqmask);
 
-		if (dev->irq <= 0) {
+		if ((int)dev->irq <= 0) {
 			BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed first time\n");
 			airqmask = probe_irq_on();
 			outb(NORXflag, _INTMASK);
 			udelay(5);
 			outb(0, _INTMASK);
 			dev->irq = probe_irq_off(airqmask);
-			if (dev->irq <= 0) {
+			if ((int)dev->irq <= 0) {
 				BUGMSG(D_NORMAL, "Autoprobe IRQ failed.\n");
 				err = -ENODEV;
 				goto out;
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c
index 4cb4018..eb27976 100644
--- a/drivers/net/arcnet/com90io.c
+++ b/drivers/net/arcnet/com90io.c
@@ -213,7 +213,7 @@
 		outb(0, _INTMASK);
 		dev->irq = probe_irq_off(airqmask);
 
-		if (dev->irq <= 0) {
+		if ((int)dev->irq <= 0) {
 			BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed\n");
 			goto err_out;
 		}
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
index 24df032..4f1cc71 100644
--- a/drivers/net/arm/ixp4xx_eth.c
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -738,6 +738,17 @@
 	struct netdev_hw_addr *ha;
 	u8 diffs[ETH_ALEN], *addr;
 	int i;
+	static const u8 allmulti[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+	if (dev->flags & IFF_ALLMULTI) {
+		for (i = 0; i < ETH_ALEN; i++) {
+			__raw_writel(allmulti[i], &port->regs->mcast_addr[i]);
+			__raw_writel(allmulti[i], &port->regs->mcast_mask[i]);
+		}
+		__raw_writel(DEFAULT_RX_CNTRL0 | RX_CNTRL0_ADDR_FLTR_EN,
+			&port->regs->rx_control[0]);
+		return;
+	}
 
 	if ((dev->flags & IFF_PROMISC) || netdev_mc_empty(dev)) {
 		__raw_writel(DEFAULT_RX_CNTRL0 & ~RX_CNTRL0_ADDR_FLTR_EN,
@@ -771,7 +782,8 @@
 
 	if (!netif_running(dev))
 		return -EINVAL;
-	return phy_mii_ioctl(port->phydev, if_mii(req), cmd);
+
+	return phy_mii_ioctl(port->phydev, req, cmd);
 }
 
 /* ethtool support */
diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c
index 2e85246..4545d5a 100644
--- a/drivers/net/arm/w90p910_ether.c
+++ b/drivers/net/arm/w90p910_ether.c
@@ -822,6 +822,9 @@
 	w90p910_set_global_maccmd(dev);
 	w90p910_enable_rx(dev, 1);
 
+	clk_enable(ether->rmiiclk);
+	clk_enable(ether->clk);
+
 	ether->rx_packets = 0x0;
 	ether->rx_bytes = 0x0;
 
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index 93185f5..8987689 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -811,10 +811,8 @@
 	/* No statistic counters on the chip to update. */
 
 	/* Disable the IRQ on boards of fmv18x where it is feasible. */
-	if (lp->jumpered) {
+	if (lp->jumpered)
 		outb(0x00, ioaddr + IOCONFIG1);
-		free_irq(dev->irq, dev);
-	}
 
 	/* Power-down the chip.  Green, green, green! */
 	outb(0x00, ioaddr + CONFIG_1);
diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h
index 84ae905..52abbbd 100644
--- a/drivers/net/atl1c/atl1c.h
+++ b/drivers/net/atl1c/atl1c.h
@@ -73,7 +73,8 @@
 #define FULL_DUPLEX        2
 
 #define AT_RX_BUF_SIZE		(ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN)
-#define MAX_JUMBO_FRAME_SIZE 	(9*1024)
+#define MAX_JUMBO_FRAME_SIZE	(6*1024)
+#define MAX_TSO_FRAME_SIZE      (7*1024)
 #define MAX_TX_OFFLOAD_THRESH	(9*1024)
 
 #define AT_MAX_RECEIVE_QUEUE    4
@@ -87,10 +88,11 @@
 #define AT_MAX_INT_WORK		5
 #define AT_TWSI_EEPROM_TIMEOUT 	100
 #define AT_HW_MAX_IDLE_DELAY 	10
-#define AT_SUSPEND_LINK_TIMEOUT 28
+#define AT_SUSPEND_LINK_TIMEOUT 100
 
 #define AT_ASPM_L0S_TIMER	6
 #define AT_ASPM_L1_TIMER	12
+#define AT_LCKDET_TIMER		12
 
 #define ATL1C_PCIE_L0S_L1_DISABLE 	0x01
 #define ATL1C_PCIE_PHY_RESET		0x02
@@ -316,6 +318,7 @@
 	athr_l2c_b,
 	athr_l2c_b2,
 	athr_l1d,
+	athr_l1d_2,
 };
 
 enum atl1c_trans_queue {
@@ -392,6 +395,8 @@
 	u16 subsystem_id;
 	u16 subsystem_vendor_id;
 	u8 revision_id;
+	u16 phy_id1;
+	u16 phy_id2;
 
 	u32 intr_mask;
 	u8 dmaw_dly_cnt;
diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c
index f1389d6..d8501f0 100644
--- a/drivers/net/atl1c/atl1c_hw.c
+++ b/drivers/net/atl1c/atl1c_hw.c
@@ -37,6 +37,9 @@
 	if (data & TWSI_DEBUG_DEV_EXIST)
 		return 1;
 
+	AT_READ_REG(hw, REG_MASTER_CTRL, &data);
+	if (data & MASTER_CTRL_OTP_SEL)
+		return 1;
 	return 0;
 }
 
@@ -69,6 +72,8 @@
 	u32 i;
 	u32 otp_ctrl_data;
 	u32 twsi_ctrl_data;
+	u32 ltssm_ctrl_data;
+	u32 wol_data;
 	u8  eth_addr[ETH_ALEN];
 	u16 phy_data;
 	bool raise_vol = false;
@@ -104,6 +109,15 @@
 			udelay(20);
 			raise_vol = true;
 		}
+		/* close open bit of ReadOnly*/
+		AT_READ_REG(hw, REG_LTSSM_ID_CTRL, &ltssm_ctrl_data);
+		ltssm_ctrl_data &= ~LTSSM_ID_EN_WRO;
+		AT_WRITE_REG(hw, REG_LTSSM_ID_CTRL, ltssm_ctrl_data);
+
+		/* clear any WOL settings */
+		AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
+		AT_READ_REG(hw, REG_WOL_CTRL, &wol_data);
+
 
 		AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
 		twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
@@ -119,17 +133,15 @@
 	}
 	/* Disable OTP_CLK */
 	if ((hw->nic_type == athr_l1c || hw->nic_type == athr_l2c)) {
-		if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
-			otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
-			AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
-			AT_WRITE_FLUSH(hw);
-			msleep(1);
-		}
+		otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
+		AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+		msleep(1);
 	}
 	if (raise_vol) {
 		if (hw->nic_type == athr_l2c_b ||
 		    hw->nic_type == athr_l2c_b2 ||
-		    hw->nic_type == athr_l1d) {
+		    hw->nic_type == athr_l1d ||
+		    hw->nic_type == athr_l1d_2) {
 			atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
 			if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
 				goto out;
@@ -456,14 +468,22 @@
 
 	if (hw->nic_type == athr_l2c_b ||
 	    hw->nic_type == athr_l2c_b2 ||
-	    hw->nic_type == athr_l1d) {
+	    hw->nic_type == athr_l1d ||
+	    hw->nic_type == athr_l1d_2) {
 		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
 		atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data);
 		atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xFFF7);
 		msleep(20);
 	}
-
-	/*Enable PHY LinkChange Interrupt */
+	if (hw->nic_type == athr_l1d) {
+		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
+		atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x929D);
+	}
+	if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b2
+		|| hw->nic_type == athr_l2c || hw->nic_type == athr_l2c) {
+		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
+		atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
+	}
 	err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data);
 	if (err) {
 		if (netif_msg_hw(adapter))
@@ -482,12 +502,10 @@
 	struct pci_dev *pdev = adapter->pdev;
 	int ret_val;
 	u16 mii_bmcr_data = BMCR_RESET;
-	u16 phy_id1, phy_id2;
 
-	if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &phy_id1) != 0) ||
-		(atl1c_read_phy_reg(hw, MII_PHYSID2, &phy_id2) != 0)) {
-			if (netif_msg_link(adapter))
-				dev_err(&pdev->dev, "Error get phy ID\n");
+	if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id1) != 0) ||
+		(atl1c_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id2) != 0)) {
+		dev_err(&pdev->dev, "Error get phy ID\n");
 		return -1;
 	}
 	switch (hw->media_type) {
@@ -572,6 +590,65 @@
 	return 0;
 }
 
+int atl1c_phy_power_saving(struct atl1c_hw *hw)
+{
+	struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
+	struct pci_dev *pdev = adapter->pdev;
+	int ret = 0;
+	u16 autoneg_advertised = ADVERTISED_10baseT_Half;
+	u16 save_autoneg_advertised;
+	u16 phy_data;
+	u16 mii_lpa_data;
+	u16 speed = SPEED_0;
+	u16 duplex = FULL_DUPLEX;
+	int i;
+
+	atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+	atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+	if (phy_data & BMSR_LSTATUS) {
+		atl1c_read_phy_reg(hw, MII_LPA, &mii_lpa_data);
+		if (mii_lpa_data & LPA_10FULL)
+			autoneg_advertised = ADVERTISED_10baseT_Full;
+		else if (mii_lpa_data & LPA_10HALF)
+			autoneg_advertised = ADVERTISED_10baseT_Half;
+		else if (mii_lpa_data & LPA_100HALF)
+			autoneg_advertised = ADVERTISED_100baseT_Half;
+		else if (mii_lpa_data & LPA_100FULL)
+			autoneg_advertised = ADVERTISED_100baseT_Full;
+
+		save_autoneg_advertised = hw->autoneg_advertised;
+		hw->phy_configured = false;
+		hw->autoneg_advertised = autoneg_advertised;
+		if (atl1c_restart_autoneg(hw) != 0) {
+			dev_dbg(&pdev->dev, "phy autoneg failed\n");
+			ret = -1;
+		}
+		hw->autoneg_advertised = save_autoneg_advertised;
+
+		if (mii_lpa_data) {
+			for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
+				mdelay(100);
+				atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+				atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+				if (phy_data & BMSR_LSTATUS) {
+					if (atl1c_get_speed_and_duplex(hw, &speed,
+									&duplex) != 0)
+						dev_dbg(&pdev->dev,
+							"get speed and duplex failed\n");
+					break;
+				}
+			}
+		}
+	} else {
+		speed = SPEED_10;
+		duplex = HALF_DUPLEX;
+	}
+	adapter->link_speed = speed;
+	adapter->link_duplex = duplex;
+
+	return ret;
+}
+
 int atl1c_restart_autoneg(struct atl1c_hw *hw)
 {
 	int err = 0;
diff --git a/drivers/net/atl1c/atl1c_hw.h b/drivers/net/atl1c/atl1c_hw.h
index 1eeb3ed..3dd6759 100644
--- a/drivers/net/atl1c/atl1c_hw.h
+++ b/drivers/net/atl1c/atl1c_hw.h
@@ -42,7 +42,7 @@
 int atl1c_phy_init(struct atl1c_hw *hw);
 int atl1c_check_eeprom_exist(struct atl1c_hw *hw);
 int atl1c_restart_autoneg(struct atl1c_hw *hw);
-
+int atl1c_phy_power_saving(struct atl1c_hw *hw);
 /* register definition */
 #define REG_DEVICE_CAP              	0x5C
 #define DEVICE_CAP_MAX_PAYLOAD_MASK     0x7
@@ -120,6 +120,12 @@
 #define REG_PCIE_PHYMISC	    	0x1000
 #define PCIE_PHYMISC_FORCE_RCV_DET	0x4
 
+#define REG_PCIE_PHYMISC2		0x1004
+#define PCIE_PHYMISC2_SERDES_CDR_MASK	0x3
+#define PCIE_PHYMISC2_SERDES_CDR_SHIFT	16
+#define PCIE_PHYMISC2_SERDES_TH_MASK	0x3
+#define PCIE_PHYMISC2_SERDES_TH_SHIFT	18
+
 #define REG_TWSI_DEBUG			0x1108
 #define TWSI_DEBUG_DEV_EXIST		0x20000000
 
@@ -150,24 +156,28 @@
 #define PM_CTRL_ASPM_L0S_EN		0x00001000
 #define PM_CTRL_CLK_SWH_L1		0x00002000
 #define PM_CTRL_CLK_PWM_VER1_1		0x00004000
-#define PM_CTRL_PCIE_RECV		0x00008000
+#define PM_CTRL_RCVR_WT_TIMER		0x00008000
 #define PM_CTRL_L1_ENTRY_TIMER_MASK	0xF
 #define PM_CTRL_L1_ENTRY_TIMER_SHIFT	16
 #define PM_CTRL_PM_REQ_TIMER_MASK	0xF
 #define PM_CTRL_PM_REQ_TIMER_SHIFT	20
-#define PM_CTRL_LCKDET_TIMER_MASK	0x3F
+#define PM_CTRL_LCKDET_TIMER_MASK	0xF
 #define PM_CTRL_LCKDET_TIMER_SHIFT	24
 #define PM_CTRL_EN_BUFS_RX_L0S		0x10000000
 #define PM_CTRL_SA_DLY_EN		0x20000000
 #define PM_CTRL_MAC_ASPM_CHK		0x40000000
 #define PM_CTRL_HOTRST			0x80000000
 
+#define REG_LTSSM_ID_CTRL		0x12FC
+#define LTSSM_ID_EN_WRO			0x1000
 /* Selene Master Control Register */
 #define REG_MASTER_CTRL			0x1400
 #define MASTER_CTRL_SOFT_RST            0x1
 #define MASTER_CTRL_TEST_MODE_MASK	0x3
 #define MASTER_CTRL_TEST_MODE_SHIFT	2
 #define MASTER_CTRL_BERT_START		0x10
+#define MASTER_CTRL_OOB_DIS_OFF		0x40
+#define MASTER_CTRL_SA_TIMER_EN		0x80
 #define MASTER_CTRL_MTIMER_EN           0x100
 #define MASTER_CTRL_MANUAL_INT          0x200
 #define MASTER_CTRL_TX_ITIMER_EN	0x400
@@ -220,6 +230,12 @@
 		GPHY_CTRL_PWDOWN_HW	|\
 		GPHY_CTRL_PHY_IDDQ)
 
+#define GPHY_CTRL_POWER_SAVING (	\
+		GPHY_CTRL_SEL_ANA_RST	|\
+		GPHY_CTRL_HIB_EN	|\
+		GPHY_CTRL_HIB_PULSE	|\
+		GPHY_CTRL_PWDOWN_HW	|\
+		GPHY_CTRL_PHY_IDDQ)
 /* Block IDLE Status Register */
 #define REG_IDLE_STATUS  		0x1410
 #define IDLE_STATUS_MASK		0x00FF
@@ -287,6 +303,14 @@
 #define SERDES_LOCK_DETECT          	0x1  /* SerDes lock detected. This signal
 					      * comes from Analog SerDes */
 #define SERDES_LOCK_DETECT_EN       	0x2  /* 1: Enable SerDes Lock detect function */
+#define SERDES_LOCK_STS_SELFB_PLL_SHIFT 0xE
+#define SERDES_LOCK_STS_SELFB_PLL_MASK  0x3
+#define SERDES_OVCLK_18_25		0x0
+#define SERDES_OVCLK_12_18		0x1
+#define SERDES_OVCLK_0_4		0x2
+#define SERDES_OVCLK_4_12		0x3
+#define SERDES_MAC_CLK_SLOWDOWN		0x20000
+#define SERDES_PYH_CLK_SLOWDOWN		0x40000
 
 /* MAC Control Register  */
 #define REG_MAC_CTRL         		0x1480
@@ -693,6 +717,21 @@
 #define REG_MAC_TX_STATUS_BIN 		0x1760
 #define REG_MAC_TX_STATUS_END 		0x17c0
 
+#define REG_CLK_GATING_CTRL		0x1814
+#define CLK_GATING_DMAW_EN		0x0001
+#define CLK_GATING_DMAR_EN		0x0002
+#define CLK_GATING_TXQ_EN		0x0004
+#define CLK_GATING_RXQ_EN		0x0008
+#define CLK_GATING_TXMAC_EN		0x0010
+#define CLK_GATING_RXMAC_EN		0x0020
+
+#define CLK_GATING_EN_ALL	(CLK_GATING_DMAW_EN |\
+				 CLK_GATING_DMAR_EN |\
+				 CLK_GATING_TXQ_EN  |\
+				 CLK_GATING_RXQ_EN  |\
+				 CLK_GATING_TXMAC_EN|\
+				 CLK_GATING_RXMAC_EN)
+
 /* DEBUG ADDR */
 #define REG_DEBUG_DATA0 		0x1900
 #define REG_DEBUG_DATA1 		0x1904
@@ -734,6 +773,10 @@
 
 #define MII_PHYSID1			0x02
 #define MII_PHYSID2			0x03
+#define L1D_MPW_PHYID1			0xD01C  /* V7 */
+#define L1D_MPW_PHYID2			0xD01D  /* V1-V6 */
+#define L1D_MPW_PHYID3			0xD01E  /* V8 */
+
 
 /* Autoneg Advertisement Register */
 #define MII_ADVERTISE			0x04
diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
index 1c3c046..c7b8ef5 100644
--- a/drivers/net/atl1c/atl1c_main.c
+++ b/drivers/net/atl1c/atl1c_main.c
@@ -21,7 +21,7 @@
 
 #include "atl1c.h"
 
-#define ATL1C_DRV_VERSION "1.0.0.2-NAPI"
+#define ATL1C_DRV_VERSION "1.0.1.0-NAPI"
 char atl1c_driver_name[] = "atl1c";
 char atl1c_driver_version[] = ATL1C_DRV_VERSION;
 #define PCI_DEVICE_ID_ATTANSIC_L2C      0x1062
@@ -29,7 +29,7 @@
 #define PCI_DEVICE_ID_ATHEROS_L2C_B	0x2060 /* AR8152 v1.1 Fast 10/100 */
 #define PCI_DEVICE_ID_ATHEROS_L2C_B2	0x2062 /* AR8152 v2.0 Fast 10/100 */
 #define PCI_DEVICE_ID_ATHEROS_L1D	0x1073 /* AR8151 v1.0 Gigabit 1000 */
-
+#define PCI_DEVICE_ID_ATHEROS_L1D_2_0	0x1083 /* AR8151 v2.0 Gigabit 1000 */
 #define L2CB_V10			0xc0
 #define L2CB_V11			0xc1
 
@@ -97,7 +97,28 @@
 
 static const u32 atl1c_default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
 	NETIF_MSG_LINK | NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP;
+static void atl1c_pcie_patch(struct atl1c_hw *hw)
+{
+	u32 data;
 
+	AT_READ_REG(hw, REG_PCIE_PHYMISC, &data);
+	data |= PCIE_PHYMISC_FORCE_RCV_DET;
+	AT_WRITE_REG(hw, REG_PCIE_PHYMISC, data);
+
+	if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V10) {
+		AT_READ_REG(hw, REG_PCIE_PHYMISC2, &data);
+
+		data &= ~(PCIE_PHYMISC2_SERDES_CDR_MASK <<
+			PCIE_PHYMISC2_SERDES_CDR_SHIFT);
+		data |= 3 << PCIE_PHYMISC2_SERDES_CDR_SHIFT;
+		data &= ~(PCIE_PHYMISC2_SERDES_TH_MASK <<
+			PCIE_PHYMISC2_SERDES_TH_SHIFT);
+		data |= 3 << PCIE_PHYMISC2_SERDES_TH_SHIFT;
+		AT_WRITE_REG(hw, REG_PCIE_PHYMISC2, data);
+	}
+}
+
+/* FIXME: no need any more ? */
 /*
  * atl1c_init_pcie - init PCIE module
  */
@@ -127,6 +148,11 @@
 	data &= ~PCIE_UC_SERVRITY_FCP;
 	AT_WRITE_REG(hw, REG_PCIE_UC_SEVERITY, data);
 
+	AT_READ_REG(hw, REG_LTSSM_ID_CTRL, &data);
+	data &= ~LTSSM_ID_EN_WRO;
+	AT_WRITE_REG(hw, REG_LTSSM_ID_CTRL, data);
+
+	atl1c_pcie_patch(hw);
 	if (flag & ATL1C_PCIE_L0S_L1_DISABLE)
 		atl1c_disable_l0s_l1(hw);
 	if (flag & ATL1C_PCIE_PHY_RESET)
@@ -135,7 +161,7 @@
 		AT_WRITE_REG(hw, REG_GPHY_CTRL,
 			GPHY_CTRL_DEFAULT | GPHY_CTRL_EXT_RESET);
 
-	msleep(1);
+	msleep(5);
 }
 
 /*
@@ -159,6 +185,7 @@
 {
 	atomic_inc(&adapter->irq_sem);
 	AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
+	AT_WRITE_REG(&adapter->hw, REG_ISR, ISR_DIS_INT);
 	AT_WRITE_FLUSH(&adapter->hw);
 	synchronize_irq(adapter->pdev->irq);
 }
@@ -231,15 +258,15 @@
 
 	if ((phy_data & BMSR_LSTATUS) == 0) {
 		/* link down */
-		if (netif_carrier_ok(netdev)) {
-			hw->hibernate = true;
-			if (atl1c_stop_mac(hw) != 0)
-				if (netif_msg_hw(adapter))
-					dev_warn(&pdev->dev,
-						"stop mac failed\n");
-			atl1c_set_aspm(hw, false);
-		}
+		hw->hibernate = true;
+		if (atl1c_stop_mac(hw) != 0)
+			if (netif_msg_hw(adapter))
+				dev_warn(&pdev->dev, "stop mac failed\n");
+		atl1c_set_aspm(hw, false);
 		netif_carrier_off(netdev);
+		netif_stop_queue(netdev);
+		atl1c_phy_reset(hw);
+		atl1c_phy_init(&adapter->hw);
 	} else {
 		/* Link Up */
 		hw->hibernate = false;
@@ -308,6 +335,7 @@
 	netdev = adapter->netdev;
 
 	if (adapter->work_event & ATL1C_WORK_EVENT_RESET) {
+		adapter->work_event &= ~ATL1C_WORK_EVENT_RESET;
 		netif_device_detach(netdev);
 		atl1c_down(adapter);
 		atl1c_up(adapter);
@@ -315,8 +343,11 @@
 		return;
 	}
 
-	if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE)
+	if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE) {
+		adapter->work_event &= ~ATL1C_WORK_EVENT_LINK_CHANGE;
 		atl1c_check_link_status(adapter);
+	}
+	return;
 }
 
 
@@ -476,6 +507,13 @@
 		netdev->mtu = new_mtu;
 		adapter->hw.max_frame_size = new_mtu;
 		atl1c_set_rxbufsize(adapter, netdev);
+		if (new_mtu > MAX_TSO_FRAME_SIZE) {
+			adapter->netdev->features &= ~NETIF_F_TSO;
+			adapter->netdev->features &= ~NETIF_F_TSO6;
+		} else {
+			adapter->netdev->features |= NETIF_F_TSO;
+			adapter->netdev->features |= NETIF_F_TSO6;
+		}
 		atl1c_down(adapter);
 		atl1c_up(adapter);
 		clear_bit(__AT_RESETTING, &adapter->flags);
@@ -613,6 +651,9 @@
 	case PCI_DEVICE_ID_ATHEROS_L1D:
 		hw->nic_type = athr_l1d;
 		break;
+	case PCI_DEVICE_ID_ATHEROS_L1D_2_0:
+		hw->nic_type = athr_l1d_2;
+		break;
 	default:
 		break;
 	}
@@ -627,9 +668,7 @@
 	AT_READ_REG(hw, REG_PHY_STATUS, &phy_status_data);
 	AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
 
-	hw->ctrl_flags = ATL1C_INTR_CLEAR_ON_READ |
-			 ATL1C_INTR_MODRT_ENABLE  |
-			 ATL1C_RX_IPV6_CHKSUM	  |
+	hw->ctrl_flags = ATL1C_INTR_MODRT_ENABLE  |
 			 ATL1C_TXQ_MODE_ENHANCE;
 	if (link_ctrl_data & LINK_CTRL_L0S_EN)
 		hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT;
@@ -637,12 +676,12 @@
 		hw->ctrl_flags |= ATL1C_ASPM_L1_SUPPORT;
 	if (link_ctrl_data & LINK_CTRL_EXT_SYNC)
 		hw->ctrl_flags |= ATL1C_LINK_EXT_SYNC;
+	hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
 
 	if (hw->nic_type == athr_l1c ||
-	    hw->nic_type == athr_l1d) {
-		hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
+	    hw->nic_type == athr_l1d ||
+	    hw->nic_type == athr_l1d_2)
 		hw->link_cap_flags |= ATL1C_LINK_CAP_1000M;
-	}
 	return 0;
 }
 /*
@@ -657,6 +696,8 @@
 {
 	struct atl1c_hw *hw   = &adapter->hw;
 	struct pci_dev	*pdev = adapter->pdev;
+	u32 revision;
+
 
 	adapter->wol = 0;
 	adapter->link_speed = SPEED_0;
@@ -669,7 +710,8 @@
 	hw->device_id = pdev->device;
 	hw->subsystem_vendor_id = pdev->subsystem_vendor;
 	hw->subsystem_id = pdev->subsystem_device;
-
+	AT_READ_REG(hw, PCI_CLASS_REVISION, &revision);
+	hw->revision_id = revision & 0xFF;
 	/* before link up, we assume hibernate is true */
 	hw->hibernate = true;
 	hw->media_type = MEDIA_TYPE_AUTO_SENSOR;
@@ -974,6 +1016,7 @@
 	struct atl1c_cmb *cmb = (struct atl1c_cmb *) &adapter->cmb;
 	struct atl1c_smb *smb = (struct atl1c_smb *) &adapter->smb;
 	int i;
+	u32 data;
 
 	/* TPD */
 	AT_WRITE_REG(hw, REG_TX_BASE_ADDR_HI,
@@ -1017,6 +1060,23 @@
 			(u32)((smb->dma & AT_DMA_HI_ADDR_MASK) >> 32));
 	AT_WRITE_REG(hw, REG_SMB_BASE_ADDR_LO,
 			(u32)(smb->dma & AT_DMA_LO_ADDR_MASK));
+	if (hw->nic_type == athr_l2c_b) {
+		AT_WRITE_REG(hw, REG_SRAM_RXF_LEN, 0x02a0L);
+		AT_WRITE_REG(hw, REG_SRAM_TXF_LEN, 0x0100L);
+		AT_WRITE_REG(hw, REG_SRAM_RXF_ADDR, 0x029f0000L);
+		AT_WRITE_REG(hw, REG_SRAM_RFD0_INFO, 0x02bf02a0L);
+		AT_WRITE_REG(hw, REG_SRAM_TXF_ADDR, 0x03bf02c0L);
+		AT_WRITE_REG(hw, REG_SRAM_TRD_ADDR, 0x03df03c0L);
+		AT_WRITE_REG(hw, REG_TXF_WATER_MARK, 0);	/* TX watermark, to enter l1 state.*/
+		AT_WRITE_REG(hw, REG_RXD_DMA_CTRL, 0);		/* RXD threshold.*/
+	}
+	if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d_2) {
+			/* Power Saving for L2c_B */
+		AT_READ_REG(hw, REG_SERDES_LOCK, &data);
+		data |= SERDES_MAC_CLK_SLOWDOWN;
+		data |= SERDES_PYH_CLK_SLOWDOWN;
+		AT_WRITE_REG(hw, REG_SERDES_LOCK, data);
+	}
 	/* Load all of base address above */
 	AT_WRITE_REG(hw, REG_LOAD_PTR, 1);
 }
@@ -1029,6 +1089,7 @@
 	u16 tx_offload_thresh;
 	u32 txq_ctrl_data;
 	u32 extra_size = 0;     /* Jumbo frame threshold in QWORD unit */
+	u32 max_pay_load_data;
 
 	extra_size = ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
 	tx_offload_thresh = MAX_TX_OFFLOAD_THRESH;
@@ -1046,8 +1107,11 @@
 			TXQ_NUM_TPD_BURST_SHIFT;
 	if (hw->ctrl_flags & ATL1C_TXQ_MODE_ENHANCE)
 		txq_ctrl_data |= TXQ_CTRL_ENH_MODE;
-	txq_ctrl_data |= (atl1c_pay_load_size[hw->dmar_block] &
+	max_pay_load_data = (atl1c_pay_load_size[hw->dmar_block] &
 			TXQ_TXF_BURST_NUM_MASK) << TXQ_TXF_BURST_NUM_SHIFT;
+	if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2)
+		max_pay_load_data >>= 1;
+	txq_ctrl_data |= max_pay_load_data;
 
 	AT_WRITE_REG(hw, REG_TXQ_CTRL, txq_ctrl_data);
 }
@@ -1078,7 +1142,7 @@
 	rxq_ctrl_data |= (hw->rss_hash_bits & RSS_HASH_BITS_MASK) <<
 			RSS_HASH_BITS_SHIFT;
 	if (hw->ctrl_flags & ATL1C_ASPM_CTRL_MON)
-		rxq_ctrl_data |= (ASPM_THRUPUT_LIMIT_100M &
+		rxq_ctrl_data |= (ASPM_THRUPUT_LIMIT_1M &
 			ASPM_THRUPUT_LIMIT_MASK) << ASPM_THRUPUT_LIMIT_SHIFT;
 
 	AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data);
@@ -1198,21 +1262,23 @@
 {
 	struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
 	struct pci_dev *pdev = adapter->pdev;
-	int ret;
+	u32 master_ctrl_data = 0;
 
 	AT_WRITE_REG(hw, REG_IMR, 0);
 	AT_WRITE_REG(hw, REG_ISR, ISR_DIS_INT);
 
-	ret = atl1c_stop_mac(hw);
-	if (ret)
-		return ret;
+	atl1c_stop_mac(hw);
 	/*
 	 * Issue Soft Reset to the MAC.  This will reset the chip's
 	 * transmit, receive, DMA.  It will not effect
 	 * the current PCI configuration.  The global reset bit is self-
 	 * clearing, and should clear within a microsecond.
 	 */
-	AT_WRITE_REGW(hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST);
+	AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
+	master_ctrl_data |= MASTER_CTRL_OOB_DIS_OFF;
+	AT_WRITE_REGW(hw, REG_MASTER_CTRL, ((master_ctrl_data | MASTER_CTRL_SOFT_RST)
+			& 0xFFFF));
+
 	AT_WRITE_FLUSH(hw);
 	msleep(10);
 	/* Wait at least 10ms for All module to be Idle */
@@ -1253,42 +1319,39 @@
 {
 	u32 pm_ctrl_data;
 	u32 link_ctrl_data;
+	u32 link_l1_timer = 0xF;
 
 	AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data);
 	AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
-	pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1;
 
+	pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1;
 	pm_ctrl_data &=  ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
 			PM_CTRL_L1_ENTRY_TIMER_SHIFT);
 	pm_ctrl_data &= ~(PM_CTRL_LCKDET_TIMER_MASK <<
-			  PM_CTRL_LCKDET_TIMER_SHIFT);
+			PM_CTRL_LCKDET_TIMER_SHIFT);
+	pm_ctrl_data |= AT_LCKDET_TIMER	<< PM_CTRL_LCKDET_TIMER_SHIFT;
 
-	pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
-	pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
-	pm_ctrl_data |= PM_CTRL_RBER_EN;
-	pm_ctrl_data |= PM_CTRL_SDES_EN;
-
-	if (hw->nic_type == athr_l2c_b ||
-	    hw->nic_type == athr_l1d ||
-	    hw->nic_type == athr_l2c_b2) {
+	if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d ||
+		hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) {
 		link_ctrl_data &= ~LINK_CTRL_EXT_SYNC;
 		if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE)) {
-			if (hw->nic_type == athr_l2c_b &&
-			    hw->revision_id == L2CB_V10)
+			if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V10)
 				link_ctrl_data |= LINK_CTRL_EXT_SYNC;
 		}
 
 		AT_WRITE_REG(hw, REG_LINK_CTRL, link_ctrl_data);
 
-		pm_ctrl_data |= PM_CTRL_PCIE_RECV;
-		pm_ctrl_data |= AT_ASPM_L1_TIMER << PM_CTRL_PM_REQ_TIMER_SHIFT;
-		pm_ctrl_data &= ~PM_CTRL_EN_BUFS_RX_L0S;
+		pm_ctrl_data |= PM_CTRL_RCVR_WT_TIMER;
+		pm_ctrl_data &= ~(PM_CTRL_PM_REQ_TIMER_MASK <<
+			PM_CTRL_PM_REQ_TIMER_SHIFT);
+		pm_ctrl_data |= AT_ASPM_L1_TIMER <<
+			PM_CTRL_PM_REQ_TIMER_SHIFT;
 		pm_ctrl_data &= ~PM_CTRL_SA_DLY_EN;
 		pm_ctrl_data &= ~PM_CTRL_HOTRST;
 		pm_ctrl_data |= 1 << PM_CTRL_L1_ENTRY_TIMER_SHIFT;
 		pm_ctrl_data |= PM_CTRL_SERDES_PD_EX_L1;
 	}
-
+	pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
 	if (linkup) {
 		pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
 		pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
@@ -1297,27 +1360,26 @@
 		if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT)
 			pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN;
 
-		if (hw->nic_type == athr_l2c_b ||
-		    hw->nic_type == athr_l1d ||
-		    hw->nic_type == athr_l2c_b2) {
+		if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d ||
+			hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) {
 			if (hw->nic_type == athr_l2c_b)
 				if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE))
-					pm_ctrl_data &= PM_CTRL_ASPM_L0S_EN;
+					pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
 			pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
 			pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
 			pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
 			pm_ctrl_data |= PM_CTRL_CLK_SWH_L1;
-			if (hw->adapter->link_speed == SPEED_100 ||
-			    hw->adapter->link_speed == SPEED_1000) {
-				pm_ctrl_data &=
-					~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
-					  PM_CTRL_L1_ENTRY_TIMER_SHIFT);
-				if (hw->nic_type == athr_l1d)
-					pm_ctrl_data |= 0xF <<
-						PM_CTRL_L1_ENTRY_TIMER_SHIFT;
-				else
-					pm_ctrl_data |= 7 <<
-						PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+		if (hw->adapter->link_speed == SPEED_100 ||
+				hw->adapter->link_speed == SPEED_1000) {
+				pm_ctrl_data &=  ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
+					PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+				if (hw->nic_type == athr_l2c_b)
+					link_l1_timer = 7;
+				else if (hw->nic_type == athr_l2c_b2 ||
+					hw->nic_type == athr_l1d_2)
+					link_l1_timer = 4;
+				pm_ctrl_data |= link_l1_timer <<
+					PM_CTRL_L1_ENTRY_TIMER_SHIFT;
 			}
 		} else {
 			pm_ctrl_data |= PM_CTRL_SERDES_L1_EN;
@@ -1326,24 +1388,12 @@
 			pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
 			pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
 			pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
-		}
-		atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
-		if (hw->adapter->link_speed == SPEED_10)
-			if (hw->nic_type == athr_l1d)
-				atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0xB69D);
-			else
-				atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
-		else if (hw->adapter->link_speed == SPEED_100)
-			atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB2DD);
-		else
-			atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x96DD);
 
+		}
 	} else {
-		pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
 		pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
 		pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
 		pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
-
 		pm_ctrl_data |= PM_CTRL_CLK_SWH_L1;
 
 		if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT)
@@ -1351,8 +1401,9 @@
 		else
 			pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
 	}
-
 	AT_WRITE_REG(hw, REG_PM_CTRL, pm_ctrl_data);
+
+	return;
 }
 
 static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter)
@@ -1391,7 +1442,8 @@
 		mac_ctrl_data |= MAC_CTRL_MC_ALL_EN;
 
 	mac_ctrl_data |= MAC_CTRL_SINGLE_PAUSE_EN;
-	if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2) {
+	if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2 ||
+	    hw->nic_type == athr_l1d_2) {
 		mac_ctrl_data |= MAC_CTRL_SPEED_MODE_SW;
 		mac_ctrl_data |= MAC_CTRL_HASH_ALG_CRC32;
 	}
@@ -1409,6 +1461,7 @@
 	struct atl1c_hw *hw = &adapter->hw;
 	u32 master_ctrl_data = 0;
 	u32 intr_modrt_data;
+	u32 data;
 
 	/* clear interrupt status */
 	AT_WRITE_REG(hw, REG_ISR, 0xFFFFFFFF);
@@ -1418,6 +1471,15 @@
 	 * HW will enable self to assert interrupt event to system after
 	 * waiting x-time for software to notify it accept interrupt.
 	 */
+
+	data = CLK_GATING_EN_ALL;
+	if (hw->ctrl_flags & ATL1C_CLK_GATING_EN) {
+		if (hw->nic_type == athr_l2c_b)
+			data &= ~CLK_GATING_RXMAC_EN;
+	} else
+		data = 0;
+	AT_WRITE_REG(hw, REG_CLK_GATING_CTRL, data);
+
 	AT_WRITE_REG(hw, REG_INT_RETRIG_TIMER,
 		hw->ict & INT_RETRIG_TIMER_MASK);
 
@@ -1436,6 +1498,7 @@
 	if (hw->ctrl_flags & ATL1C_INTR_CLEAR_ON_READ)
 		master_ctrl_data |= MASTER_CTRL_INT_RDCLR;
 
+	master_ctrl_data |= MASTER_CTRL_SA_TIMER_EN;
 	AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
 
 	if (hw->ctrl_flags & ATL1C_CMB_ENABLE) {
@@ -1624,11 +1687,9 @@
 					"atl1c hardware error (status = 0x%x)\n",
 					status & ISR_ERROR);
 			/* reset MAC */
-			hw->intr_mask &= ~ISR_ERROR;
-			AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
 			adapter->work_event |= ATL1C_WORK_EVENT_RESET;
 			schedule_work(&adapter->common_task);
-			break;
+			return IRQ_HANDLED;
 		}
 
 		if (status & ISR_OVER)
@@ -2303,7 +2364,6 @@
 	napi_disable(&adapter->napi);
 	atl1c_irq_disable(adapter);
 	atl1c_free_irq(adapter);
-	AT_WRITE_REG(&adapter->hw, REG_ISR, ISR_DIS_INT);
 	/* reset MAC to disable all RX/TX */
 	atl1c_reset_mac(&adapter->hw);
 	msleep(1);
@@ -2387,79 +2447,68 @@
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct atl1c_adapter *adapter = netdev_priv(netdev);
 	struct atl1c_hw *hw = &adapter->hw;
-	u32 ctrl;
-	u32 mac_ctrl_data;
-	u32 master_ctrl_data;
+	u32 mac_ctrl_data = 0;
+	u32 master_ctrl_data = 0;
 	u32 wol_ctrl_data = 0;
-	u16 mii_bmsr_data;
-	u16 save_autoneg_advertised;
-	u16 mii_intr_status_data;
+	u16 mii_intr_status_data = 0;
 	u32 wufc = adapter->wol;
-	u32 i;
 	int retval = 0;
 
+	atl1c_disable_l0s_l1(hw);
 	if (netif_running(netdev)) {
 		WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
 		atl1c_down(adapter);
 	}
 	netif_device_detach(netdev);
-	atl1c_disable_l0s_l1(hw);
 	retval = pci_save_state(pdev);
 	if (retval)
 		return retval;
-	if (wufc) {
-		AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
-		master_ctrl_data &= ~MASTER_CTRL_CLK_SEL_DIS;
 
-		/* get link status */
-		atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
-		atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
-		save_autoneg_advertised = hw->autoneg_advertised;
-		hw->autoneg_advertised = ADVERTISED_10baseT_Half;
-		if (atl1c_restart_autoneg(hw) != 0)
-			if (netif_msg_link(adapter))
-				dev_warn(&pdev->dev, "phy autoneg failed\n");
-		hw->phy_configured = false; /* re-init PHY when resume */
-		hw->autoneg_advertised = save_autoneg_advertised;
+	if (wufc)
+		if (atl1c_phy_power_saving(hw) != 0)
+			dev_dbg(&pdev->dev, "phy power saving failed");
+
+	AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
+	AT_READ_REG(hw, REG_MAC_CTRL, &mac_ctrl_data);
+
+	master_ctrl_data &= ~MASTER_CTRL_CLK_SEL_DIS;
+	mac_ctrl_data &= ~(MAC_CTRL_PRMLEN_MASK << MAC_CTRL_PRMLEN_SHIFT);
+	mac_ctrl_data |= (((u32)adapter->hw.preamble_len &
+			MAC_CTRL_PRMLEN_MASK) <<
+			MAC_CTRL_PRMLEN_SHIFT);
+	mac_ctrl_data &= ~(MAC_CTRL_SPEED_MASK << MAC_CTRL_SPEED_SHIFT);
+	mac_ctrl_data &= ~MAC_CTRL_DUPLX;
+
+	if (wufc) {
+		mac_ctrl_data |= MAC_CTRL_RX_EN;
+		if (adapter->link_speed == SPEED_1000 ||
+			adapter->link_speed == SPEED_0) {
+			mac_ctrl_data |= atl1c_mac_speed_1000 <<
+					MAC_CTRL_SPEED_SHIFT;
+			mac_ctrl_data |= MAC_CTRL_DUPLX;
+		} else
+			mac_ctrl_data |= atl1c_mac_speed_10_100 <<
+					MAC_CTRL_SPEED_SHIFT;
+
+		if (adapter->link_duplex == DUPLEX_FULL)
+			mac_ctrl_data |= MAC_CTRL_DUPLX;
+
 		/* turn on magic packet wol */
 		if (wufc & AT_WUFC_MAG)
-			wol_ctrl_data = WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
+			wol_ctrl_data |= WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
 
 		if (wufc & AT_WUFC_LNKC) {
-			for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
-				msleep(100);
-				atl1c_read_phy_reg(hw, MII_BMSR,
-					(u16 *)&mii_bmsr_data);
-				if (mii_bmsr_data & BMSR_LSTATUS)
-					break;
-			}
-			if ((mii_bmsr_data & BMSR_LSTATUS) == 0)
-				if (netif_msg_link(adapter))
-					dev_warn(&pdev->dev,
-						"%s: Link may change"
-						"when suspend\n",
-						atl1c_driver_name);
 			wol_ctrl_data |=  WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN;
 			/* only link up can wake up */
 			if (atl1c_write_phy_reg(hw, MII_IER, IER_LINK_UP) != 0) {
-				if (netif_msg_link(adapter))
-					dev_err(&pdev->dev,
-						"%s: read write phy "
-						"register failed.\n",
-						atl1c_driver_name);
-				goto wol_dis;
+				dev_dbg(&pdev->dev, "%s: read write phy "
+						  "register failed.\n",
+						  atl1c_driver_name);
 			}
 		}
 		/* clear phy interrupt */
 		atl1c_read_phy_reg(hw, MII_ISR, &mii_intr_status_data);
 		/* Config MAC Ctrl register */
-		mac_ctrl_data = MAC_CTRL_RX_EN;
-		/* set to 10/100M halt duplex */
-		mac_ctrl_data |= atl1c_mac_speed_10_100 << MAC_CTRL_SPEED_SHIFT;
-		mac_ctrl_data |= (((u32)adapter->hw.preamble_len &
-				 MAC_CTRL_PRMLEN_MASK) <<
-				 MAC_CTRL_PRMLEN_SHIFT);
-
 		if (adapter->vlgrp)
 			mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
 
@@ -2467,37 +2516,30 @@
 		if (wufc & AT_WUFC_MAG)
 			mac_ctrl_data |= MAC_CTRL_BC_EN;
 
-		if (netif_msg_hw(adapter))
-			dev_dbg(&pdev->dev,
-				"%s: suspend MAC=0x%x\n",
-				atl1c_driver_name, mac_ctrl_data);
+		dev_dbg(&pdev->dev,
+			"%s: suspend MAC=0x%x\n",
+			atl1c_driver_name, mac_ctrl_data);
 		AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
 		AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data);
 		AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
 
 		/* pcie patch */
-		AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
-		ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
-		AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
+		device_set_wakeup_enable(&pdev->dev, 1);
 
-		pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
-		goto suspend_exit;
+		AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT |
+			GPHY_CTRL_EXT_RESET);
+		pci_prepare_to_sleep(pdev);
+	} else {
+		AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_POWER_SAVING);
+		master_ctrl_data |= MASTER_CTRL_CLK_SEL_DIS;
+		mac_ctrl_data |= atl1c_mac_speed_10_100 << MAC_CTRL_SPEED_SHIFT;
+		mac_ctrl_data |= MAC_CTRL_DUPLX;
+		AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
+		AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
+		AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
+		hw->phy_configured = false; /* re-init PHY when resume */
+		pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
 	}
-wol_dis:
-
-	/* WOL disabled */
-	AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
-
-	/* pcie patch */
-	AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
-	ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
-	AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
-
-	atl1c_phy_disable(hw);
-	hw->phy_configured = false; /* re-init PHY when resume */
-
-	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
-suspend_exit:
 
 	pci_disable_device(pdev);
 	pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -2516,9 +2558,19 @@
 	pci_enable_wake(pdev, PCI_D3cold, 0);
 
 	AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0);
+	atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE |
+			ATL1C_PCIE_PHY_RESET);
 
 	atl1c_phy_reset(&adapter->hw);
 	atl1c_reset_mac(&adapter->hw);
+	atl1c_phy_init(&adapter->hw);
+
+#if 0
+	AT_READ_REG(&adapter->hw, REG_PM_CTRLSTAT, &pm_data);
+	pm_data &= ~PM_CTRLSTAT_PME_EN;
+	AT_WRITE_REG(&adapter->hw, REG_PM_CTRLSTAT, pm_data);
+#endif
+
 	netif_device_attach(netdev);
 	if (netif_running(netdev))
 		atl1c_up(adapter);
diff --git a/drivers/net/atlx/atl1.h b/drivers/net/atlx/atl1.h
index 146372f..9c0ddb2 100644
--- a/drivers/net/atlx/atl1.h
+++ b/drivers/net/atlx/atl1.h
@@ -436,8 +436,8 @@
 	__le16 buf_len;		/* Size of the receive buffer in host memory */
 	u16 coalese;		/* Update consumer index to host after the
 				 * reception of this frame */
-	/* __attribute__ ((packed)) is required */
-} __attribute__ ((packed));
+	/* __packed is required */
+} __packed;
 
 /*
  * The L1 transmit packet descriptor is comprised of four 32-bit words.
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index ece6128..386d4fe 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -978,7 +978,7 @@
 	if (!aup->phy_dev)
 		return -EINVAL; /* PHY not controllable */
 
-	return phy_mii_ioctl(aup->phy_dev, if_mii(rq), cmd);
+	return phy_mii_ioctl(aup->phy_dev, rq, cmd);
 }
 
 static const struct net_device_ops au1000_netdev_ops = {
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index 55c9958..20e946b 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -481,8 +481,10 @@
 		return ret;
 
 	ret = ax_ei_open(dev);
-	if (ret)
+	if (ret) {
+		free_irq(dev->irq, dev);
 		return ret;
+	}
 
 	/* turn the phy on (if turned off) */
 
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 293f9c1..37617ab 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -135,7 +135,6 @@
 
 static void b44_init_hw(struct b44 *, int);
 
-static int dma_desc_align_mask;
 static int dma_desc_sync_size;
 static int instance;
 
@@ -150,9 +149,8 @@
 						unsigned long offset,
 						enum dma_data_direction dir)
 {
-	ssb_dma_sync_single_range_for_device(sdev, dma_base,
-					     offset & dma_desc_align_mask,
-					     dma_desc_sync_size, dir);
+	dma_sync_single_for_device(sdev->dma_dev, dma_base + offset,
+				   dma_desc_sync_size, dir);
 }
 
 static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
@@ -160,9 +158,8 @@
 					     unsigned long offset,
 					     enum dma_data_direction dir)
 {
-	ssb_dma_sync_single_range_for_cpu(sdev, dma_base,
-					  offset & dma_desc_align_mask,
-					  dma_desc_sync_size, dir);
+	dma_sync_single_for_cpu(sdev->dma_dev, dma_base + offset,
+				dma_desc_sync_size, dir);
 }
 
 static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
@@ -608,10 +605,10 @@
 
 		BUG_ON(skb == NULL);
 
-		ssb_dma_unmap_single(bp->sdev,
-				     rp->mapping,
-				     skb->len,
-				     DMA_TO_DEVICE);
+		dma_unmap_single(bp->sdev->dma_dev,
+				 rp->mapping,
+				 skb->len,
+				 DMA_TO_DEVICE);
 		rp->skb = NULL;
 		dev_kfree_skb_irq(skb);
 	}
@@ -648,29 +645,29 @@
 	if (skb == NULL)
 		return -ENOMEM;
 
-	mapping = ssb_dma_map_single(bp->sdev, skb->data,
-				     RX_PKT_BUF_SZ,
-				     DMA_FROM_DEVICE);
+	mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
+				 RX_PKT_BUF_SZ,
+				 DMA_FROM_DEVICE);
 
 	/* Hardware bug work-around, the chip is unable to do PCI DMA
 	   to/from anything above 1GB :-( */
-	if (ssb_dma_mapping_error(bp->sdev, mapping) ||
+	if (dma_mapping_error(bp->sdev->dma_dev, mapping) ||
 		mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
 		/* Sigh... */
-		if (!ssb_dma_mapping_error(bp->sdev, mapping))
-			ssb_dma_unmap_single(bp->sdev, mapping,
+		if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
+			dma_unmap_single(bp->sdev->dma_dev, mapping,
 					     RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
 		dev_kfree_skb_any(skb);
 		skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
 		if (skb == NULL)
 			return -ENOMEM;
-		mapping = ssb_dma_map_single(bp->sdev, skb->data,
-					     RX_PKT_BUF_SZ,
-					     DMA_FROM_DEVICE);
-		if (ssb_dma_mapping_error(bp->sdev, mapping) ||
-			mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
-			if (!ssb_dma_mapping_error(bp->sdev, mapping))
-				ssb_dma_unmap_single(bp->sdev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
+		mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
+					 RX_PKT_BUF_SZ,
+					 DMA_FROM_DEVICE);
+		if (dma_mapping_error(bp->sdev->dma_dev, mapping) ||
+		    mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
+			if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
+				dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
 			dev_kfree_skb_any(skb);
 			return -ENOMEM;
 		}
@@ -745,9 +742,9 @@
 					     dest_idx * sizeof(*dest_desc),
 					     DMA_BIDIRECTIONAL);
 
-	ssb_dma_sync_single_for_device(bp->sdev, dest_map->mapping,
-				       RX_PKT_BUF_SZ,
-				       DMA_FROM_DEVICE);
+	dma_sync_single_for_device(bp->sdev->dma_dev, dest_map->mapping,
+				   RX_PKT_BUF_SZ,
+				   DMA_FROM_DEVICE);
 }
 
 static int b44_rx(struct b44 *bp, int budget)
@@ -767,9 +764,9 @@
 		struct rx_header *rh;
 		u16 len;
 
-		ssb_dma_sync_single_for_cpu(bp->sdev, map,
-					    RX_PKT_BUF_SZ,
-					    DMA_FROM_DEVICE);
+		dma_sync_single_for_cpu(bp->sdev->dma_dev, map,
+					RX_PKT_BUF_SZ,
+					DMA_FROM_DEVICE);
 		rh = (struct rx_header *) skb->data;
 		len = le16_to_cpu(rh->len);
 		if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) ||
@@ -801,8 +798,8 @@
 			skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
 			if (skb_size < 0)
 				goto drop_it;
-			ssb_dma_unmap_single(bp->sdev, map,
-					     skb_size, DMA_FROM_DEVICE);
+			dma_unmap_single(bp->sdev->dma_dev, map,
+					 skb_size, DMA_FROM_DEVICE);
 			/* Leave out rx_header */
 			skb_put(skb, len + RX_PKT_OFFSET);
 			skb_pull(skb, RX_PKT_OFFSET);
@@ -954,24 +951,24 @@
 		goto err_out;
 	}
 
-	mapping = ssb_dma_map_single(bp->sdev, skb->data, len, DMA_TO_DEVICE);
-	if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
+	mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE);
+	if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
 		struct sk_buff *bounce_skb;
 
 		/* Chip can't handle DMA to/from >1GB, use bounce buffer */
-		if (!ssb_dma_mapping_error(bp->sdev, mapping))
-			ssb_dma_unmap_single(bp->sdev, mapping, len,
+		if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
+			dma_unmap_single(bp->sdev->dma_dev, mapping, len,
 					     DMA_TO_DEVICE);
 
 		bounce_skb = __netdev_alloc_skb(dev, len, GFP_ATOMIC | GFP_DMA);
 		if (!bounce_skb)
 			goto err_out;
 
-		mapping = ssb_dma_map_single(bp->sdev, bounce_skb->data,
-					     len, DMA_TO_DEVICE);
-		if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
-			if (!ssb_dma_mapping_error(bp->sdev, mapping))
-				ssb_dma_unmap_single(bp->sdev, mapping,
+		mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data,
+					 len, DMA_TO_DEVICE);
+		if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
+			if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
+				dma_unmap_single(bp->sdev->dma_dev, mapping,
 						     len, DMA_TO_DEVICE);
 			dev_kfree_skb_any(bounce_skb);
 			goto err_out;
@@ -1068,8 +1065,8 @@
 
 		if (rp->skb == NULL)
 			continue;
-		ssb_dma_unmap_single(bp->sdev, rp->mapping, RX_PKT_BUF_SZ,
-				     DMA_FROM_DEVICE);
+		dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ,
+				 DMA_FROM_DEVICE);
 		dev_kfree_skb_any(rp->skb);
 		rp->skb = NULL;
 	}
@@ -1080,8 +1077,8 @@
 
 		if (rp->skb == NULL)
 			continue;
-		ssb_dma_unmap_single(bp->sdev, rp->mapping, rp->skb->len,
-				     DMA_TO_DEVICE);
+		dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len,
+				 DMA_TO_DEVICE);
 		dev_kfree_skb_any(rp->skb);
 		rp->skb = NULL;
 	}
@@ -1103,14 +1100,12 @@
 	memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
 
 	if (bp->flags & B44_FLAG_RX_RING_HACK)
-		ssb_dma_sync_single_for_device(bp->sdev, bp->rx_ring_dma,
-					       DMA_TABLE_BYTES,
-					       DMA_BIDIRECTIONAL);
+		dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma,
+					   DMA_TABLE_BYTES, DMA_BIDIRECTIONAL);
 
 	if (bp->flags & B44_FLAG_TX_RING_HACK)
-		ssb_dma_sync_single_for_device(bp->sdev, bp->tx_ring_dma,
-					       DMA_TABLE_BYTES,
-					       DMA_TO_DEVICE);
+		dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma,
+					   DMA_TABLE_BYTES, DMA_TO_DEVICE);
 
 	for (i = 0; i < bp->rx_pending; i++) {
 		if (b44_alloc_rx_skb(bp, -1, i) < 0)
@@ -1130,27 +1125,23 @@
 	bp->tx_buffers = NULL;
 	if (bp->rx_ring) {
 		if (bp->flags & B44_FLAG_RX_RING_HACK) {
-			ssb_dma_unmap_single(bp->sdev, bp->rx_ring_dma,
-					     DMA_TABLE_BYTES,
-					     DMA_BIDIRECTIONAL);
+			dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma,
+					 DMA_TABLE_BYTES, DMA_BIDIRECTIONAL);
 			kfree(bp->rx_ring);
 		} else
-			ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
-						bp->rx_ring, bp->rx_ring_dma,
-						GFP_KERNEL);
+			dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
+					  bp->rx_ring, bp->rx_ring_dma);
 		bp->rx_ring = NULL;
 		bp->flags &= ~B44_FLAG_RX_RING_HACK;
 	}
 	if (bp->tx_ring) {
 		if (bp->flags & B44_FLAG_TX_RING_HACK) {
-			ssb_dma_unmap_single(bp->sdev, bp->tx_ring_dma,
-					     DMA_TABLE_BYTES,
-					     DMA_TO_DEVICE);
+			dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma,
+					 DMA_TABLE_BYTES, DMA_TO_DEVICE);
 			kfree(bp->tx_ring);
 		} else
-			ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
-						bp->tx_ring, bp->tx_ring_dma,
-						GFP_KERNEL);
+			dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
+					  bp->tx_ring, bp->tx_ring_dma);
 		bp->tx_ring = NULL;
 		bp->flags &= ~B44_FLAG_TX_RING_HACK;
 	}
@@ -1175,7 +1166,8 @@
 		goto out_err;
 
 	size = DMA_TABLE_BYTES;
-	bp->rx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->rx_ring_dma, gfp);
+	bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size,
+					 &bp->rx_ring_dma, gfp);
 	if (!bp->rx_ring) {
 		/* Allocation may have failed due to pci_alloc_consistent
 		   insisting on use of GFP_DMA, which is more restrictive
@@ -1187,11 +1179,11 @@
 		if (!rx_ring)
 			goto out_err;
 
-		rx_ring_dma = ssb_dma_map_single(bp->sdev, rx_ring,
-						 DMA_TABLE_BYTES,
-						 DMA_BIDIRECTIONAL);
+		rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring,
+					     DMA_TABLE_BYTES,
+					     DMA_BIDIRECTIONAL);
 
-		if (ssb_dma_mapping_error(bp->sdev, rx_ring_dma) ||
+		if (dma_mapping_error(bp->sdev->dma_dev, rx_ring_dma) ||
 			rx_ring_dma + size > DMA_BIT_MASK(30)) {
 			kfree(rx_ring);
 			goto out_err;
@@ -1202,7 +1194,8 @@
 		bp->flags |= B44_FLAG_RX_RING_HACK;
 	}
 
-	bp->tx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->tx_ring_dma, gfp);
+	bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size,
+					 &bp->tx_ring_dma, gfp);
 	if (!bp->tx_ring) {
 		/* Allocation may have failed due to ssb_dma_alloc_consistent
 		   insisting on use of GFP_DMA, which is more restrictive
@@ -1214,11 +1207,11 @@
 		if (!tx_ring)
 			goto out_err;
 
-		tx_ring_dma = ssb_dma_map_single(bp->sdev, tx_ring,
-			                    DMA_TABLE_BYTES,
-			                    DMA_TO_DEVICE);
+		tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring,
+					     DMA_TABLE_BYTES,
+					     DMA_TO_DEVICE);
 
-		if (ssb_dma_mapping_error(bp->sdev, tx_ring_dma) ||
+		if (dma_mapping_error(bp->sdev->dma_dev, tx_ring_dma) ||
 			tx_ring_dma + size > DMA_BIT_MASK(30)) {
 			kfree(tx_ring);
 			goto out_err;
@@ -2176,12 +2169,14 @@
 			"Failed to powerup the bus\n");
 		goto err_out_free_dev;
 	}
-	err = ssb_dma_set_mask(sdev, DMA_BIT_MASK(30));
-	if (err) {
+
+	if (dma_set_mask(sdev->dma_dev, DMA_BIT_MASK(30)) ||
+	    dma_set_coherent_mask(sdev->dma_dev, DMA_BIT_MASK(30))) {
 		dev_err(sdev->dev,
 			"Required 30BIT DMA mask unsupported by the system\n");
 		goto err_out_powerdown;
 	}
+
 	err = b44_get_invariants(bp);
 	if (err) {
 		dev_err(sdev->dev,
@@ -2344,7 +2339,6 @@
 	int err;
 
 	/* Setup paramaters for syncing RX/TX DMA descriptors */
-	dma_desc_align_mask = ~(dma_desc_align_size - 1);
 	dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
 
 	err = b44_pci_init();
diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c
index faf5add..0d2c5da 100644
--- a/drivers/net/bcm63xx_enet.c
+++ b/drivers/net/bcm63xx_enet.c
@@ -1496,7 +1496,7 @@
 	if (priv->has_phy) {
 		if (!priv->phydev)
 			return -ENODEV;
-		return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
+		return phy_mii_ioctl(priv->phydev, rq, cmd);
 	} else {
 		struct mii_if_info mii;
 
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index b46be49..99197bd 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -33,7 +33,7 @@
 
 #include "be_hw.h"
 
-#define DRV_VER			"2.102.147u"
+#define DRV_VER			"2.103.175u"
 #define DRV_NAME		"be2net"
 #define BE_NAME			"ServerEngines BladeEngine2 10Gbps NIC"
 #define BE3_NAME		"ServerEngines BladeEngine3 10Gbps NIC"
@@ -220,7 +220,16 @@
 	struct be_rx_page_info page_info_tbl[RX_Q_LEN];
 };
 
+struct be_vf_cfg {
+	unsigned char vf_mac_addr[ETH_ALEN];
+	u32 vf_if_handle;
+	u32 vf_pmac_id;
+	u16 vf_vlan_tag;
+	u32 vf_tx_rate;
+};
+
 #define BE_NUM_MSIX_VECTORS		2	/* 1 each for Tx and Rx */
+#define BE_INVALID_PMAC_ID		0xffffffff
 struct be_adapter {
 	struct pci_dev *pdev;
 	struct net_device *netdev;
@@ -276,23 +285,26 @@
 	u32 port_num;
 	bool promiscuous;
 	bool wol;
-	u32 cap;
+	u32 function_mode;
 	u32 rx_fc;		/* Rx flow control */
 	u32 tx_fc;		/* Tx flow control */
+	bool ue_detected;
+	bool stats_ioctl_sent;
 	int link_speed;
 	u8 port_type;
 	u8 transceiver;
+	u8 autoneg;
 	u8 generation;		/* BladeEngine ASIC generation */
 	u32 flash_status;
 	struct completion flash_compl;
 
 	bool sriov_enabled;
-	u32 vf_if_handle[BE_MAX_VF];
-	u32 vf_pmac_id[BE_MAX_VF];
+	struct be_vf_cfg vf_cfg[BE_MAX_VF];
 	u8 base_eq_id;
+	u8 is_virtfn;
 };
 
-#define be_physfn(adapter) (!adapter->pdev->is_virtfn)
+#define be_physfn(adapter) (!adapter->is_virtfn)
 
 /* BladeEngine Generation numbers */
 #define BE_GEN2 2
@@ -392,6 +404,15 @@
 	return val;
 }
 
+static inline void be_check_sriov_fn_type(struct be_adapter *adapter)
+{
+	u8 data;
+
+	pci_write_config_byte(adapter->pdev, 0xFE, 0xAA);
+	pci_read_config_byte(adapter->pdev, 0xFE, &data);
+	adapter->is_virtfn = (data != 0xAA);
+}
+
 extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
 		u16 num_popped);
 extern void be_link_status_update(struct be_adapter *adapter, bool link_up);
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index b9ad799..3d30549 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -25,6 +25,8 @@
 
 	val |= mccq->id & DB_MCCQ_RING_ID_MASK;
 	val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
+
+	wmb();
 	iowrite32(val, adapter->db + DB_MCCQ_OFFSET);
 }
 
@@ -73,8 +75,10 @@
 			be_dws_le_to_cpu(&resp->hw_stats,
 						sizeof(resp->hw_stats));
 			netdev_stats_update(adapter);
+			adapter->stats_ioctl_sent = false;
 		}
-	} else if (compl_status != MCC_STATUS_NOT_SUPPORTED) {
+	} else if ((compl_status != MCC_STATUS_NOT_SUPPORTED) &&
+		   (compl->tag0 != OPCODE_COMMON_NTWK_MAC_QUERY)) {
 		extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
 				CQE_STATUS_EXTD_MASK;
 		dev_warn(&adapter->pdev->dev,
@@ -186,7 +190,7 @@
 
 static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
 {
-	int cnt = 0, wait = 5;
+	int msecs = 0;
 	u32 ready;
 
 	do {
@@ -201,15 +205,15 @@
 		if (ready)
 			break;
 
-		if (cnt > 4000000) {
+		if (msecs > 4000) {
 			dev_err(&adapter->pdev->dev, "mbox poll timed out\n");
+			be_dump_ue(adapter);
 			return -1;
 		}
 
-		if (cnt > 50)
-			wait = 200;
-		cnt += wait;
-		udelay(wait);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(msecs_to_jiffies(1));
+		msecs++;
 	} while (true);
 
 	return 0;
@@ -948,6 +952,7 @@
 	sge->len = cpu_to_le32(nonemb_cmd->size);
 
 	be_mcc_notify(adapter);
+	adapter->stats_ioctl_sent = true;
 
 err:
 	spin_unlock_bh(&adapter->mcc_lock);
@@ -1256,7 +1261,7 @@
 }
 
 /* Uses mbox */
-int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *cap)
+int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *mode)
 {
 	struct be_mcc_wrb *wrb;
 	struct be_cmd_req_query_fw_cfg *req;
@@ -1277,7 +1282,7 @@
 	if (!status) {
 		struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb);
 		*port_num = le32_to_cpu(resp->phys_port);
-		*cap = le32_to_cpu(resp->function_cap);
+		*mode = le32_to_cpu(resp->function_mode);
 	}
 
 	spin_unlock(&adapter->mbox_lock);
@@ -1694,3 +1699,71 @@
 	spin_unlock_bh(&adapter->mcc_lock);
 	return status;
 }
+
+int be_cmd_get_phy_info(struct be_adapter *adapter, struct be_dma_mem *cmd)
+{
+	struct be_mcc_wrb *wrb;
+	struct be_cmd_req_get_phy_info *req;
+	struct be_sge *sge;
+	int status;
+
+	spin_lock_bh(&adapter->mcc_lock);
+
+	wrb = wrb_from_mccq(adapter);
+	if (!wrb) {
+		status = -EBUSY;
+		goto err;
+	}
+
+	req = cmd->va;
+	sge = nonembedded_sgl(wrb);
+
+	be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
+				OPCODE_COMMON_GET_PHY_DETAILS);
+
+	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+			OPCODE_COMMON_GET_PHY_DETAILS,
+			sizeof(*req));
+
+	sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma));
+	sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF);
+	sge->len = cpu_to_le32(cmd->size);
+
+	status = be_mcc_notify_wait(adapter);
+err:
+	spin_unlock_bh(&adapter->mcc_lock);
+	return status;
+}
+
+int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain)
+{
+	struct be_mcc_wrb *wrb;
+	struct be_cmd_req_set_qos *req;
+	int status;
+
+	spin_lock_bh(&adapter->mcc_lock);
+
+	wrb = wrb_from_mccq(adapter);
+	if (!wrb) {
+		status = -EBUSY;
+		goto err;
+	}
+
+	req = embedded_payload(wrb);
+
+	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
+				OPCODE_COMMON_SET_QOS);
+
+	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+			OPCODE_COMMON_SET_QOS, sizeof(*req));
+
+	req->hdr.domain = domain;
+	req->valid_bits = BE_QOS_BITS_NIC;
+	req->max_bps_nic = bps;
+
+	status = be_mcc_notify_wait(adapter);
+
+err:
+	spin_unlock_bh(&adapter->mcc_lock);
+	return status;
+}
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
index 763dc19..bdc10a2 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -124,6 +124,7 @@
 #define OPCODE_COMMON_CQ_CREATE				12
 #define OPCODE_COMMON_EQ_CREATE				13
 #define OPCODE_COMMON_MCC_CREATE        		21
+#define OPCODE_COMMON_SET_QOS				28
 #define OPCODE_COMMON_SEEPROM_READ			30
 #define OPCODE_COMMON_NTWK_RX_FILTER    		34
 #define OPCODE_COMMON_GET_FW_VERSION			35
@@ -144,6 +145,7 @@
 #define OPCODE_COMMON_ENABLE_DISABLE_BEACON		69
 #define OPCODE_COMMON_GET_BEACON_STATE			70
 #define OPCODE_COMMON_READ_TRANSRECV_DATA		73
+#define OPCODE_COMMON_GET_PHY_DETAILS			102
 
 #define OPCODE_ETH_ACPI_CONFIG				2
 #define OPCODE_ETH_PROMISCUOUS				3
@@ -747,7 +749,7 @@
 	u32 be_config_number;
 	u32 asic_revision;
 	u32 phys_port;
-	u32 function_cap;
+	u32 function_mode;
 	u32 rsvd[26];
 };
 
@@ -869,6 +871,46 @@
 	u8 seeprom_data[BE_READ_SEEPROM_LEN];
 };
 
+enum {
+	PHY_TYPE_CX4_10GB = 0,
+	PHY_TYPE_XFP_10GB,
+	PHY_TYPE_SFP_1GB,
+	PHY_TYPE_SFP_PLUS_10GB,
+	PHY_TYPE_KR_10GB,
+	PHY_TYPE_KX4_10GB,
+	PHY_TYPE_BASET_10GB,
+	PHY_TYPE_BASET_1GB,
+	PHY_TYPE_DISABLED = 255
+};
+
+struct be_cmd_req_get_phy_info {
+	struct be_cmd_req_hdr hdr;
+	u8 rsvd0[24];
+};
+struct be_cmd_resp_get_phy_info {
+	struct be_cmd_req_hdr hdr;
+	u16 phy_type;
+	u16 interface_type;
+	u32 misc_params;
+	u32 future_use[4];
+};
+
+/*********************** Set QOS ***********************/
+
+#define BE_QOS_BITS_NIC				1
+
+struct be_cmd_req_set_qos {
+	struct be_cmd_req_hdr hdr;
+	u32 valid_bits;
+	u32 max_bps_nic;
+	u32 rsvd[7];
+};
+
+struct be_cmd_resp_set_qos {
+	struct be_cmd_resp_hdr hdr;
+	u32 rsvd;
+};
+
 extern int be_pci_fnum_get(struct be_adapter *adapter);
 extern int be_cmd_POST(struct be_adapter *adapter);
 extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
@@ -947,4 +989,8 @@
 				struct be_dma_mem *nonemb_cmd);
 extern int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
 				u8 loopback_type, u8 enable);
+extern int be_cmd_get_phy_info(struct be_adapter *adapter,
+		struct be_dma_mem *cmd);
+extern int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain);
+extern void be_dump_ue(struct be_adapter *adapter);
 
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index 200e985..cd16243 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -314,15 +314,19 @@
 static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
 	struct be_adapter *adapter = netdev_priv(netdev);
-	u8 mac_speed = 0, connector = 0;
+	struct be_dma_mem phy_cmd;
+	struct be_cmd_resp_get_phy_info *resp;
+	u8 mac_speed = 0;
 	u16 link_speed = 0;
 	bool link_up = false;
 	int status;
+	u16 intf_type;
 
-	if (adapter->link_speed < 0) {
+	if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) {
 		status = be_cmd_link_status_query(adapter, &link_up,
 						&mac_speed, &link_speed);
 
+		be_link_status_update(adapter, link_up);
 		/* link_speed is in units of 10 Mbps */
 		if (link_speed) {
 			ecmd->speed = link_speed*10;
@@ -337,40 +341,57 @@
 			}
 		}
 
-		status = be_cmd_read_port_type(adapter, adapter->port_num,
-						&connector);
+		phy_cmd.size = sizeof(struct be_cmd_req_get_phy_info);
+		phy_cmd.va = pci_alloc_consistent(adapter->pdev, phy_cmd.size,
+					&phy_cmd.dma);
+		if (!phy_cmd.va) {
+			dev_err(&adapter->pdev->dev, "Memory alloc failure\n");
+			return -ENOMEM;
+		}
+		status = be_cmd_get_phy_info(adapter, &phy_cmd);
 		if (!status) {
-			switch (connector) {
-			case 7:
+			resp = (struct be_cmd_resp_get_phy_info *) phy_cmd.va;
+			intf_type = le16_to_cpu(resp->interface_type);
+
+			switch (intf_type) {
+			case PHY_TYPE_XFP_10GB:
+			case PHY_TYPE_SFP_1GB:
+			case PHY_TYPE_SFP_PLUS_10GB:
 				ecmd->port = PORT_FIBRE;
-				ecmd->transceiver = XCVR_EXTERNAL;
-				break;
-			case 0:
-				ecmd->port = PORT_TP;
-				ecmd->transceiver = XCVR_EXTERNAL;
 				break;
 			default:
 				ecmd->port = PORT_TP;
-				ecmd->transceiver = XCVR_INTERNAL;
 				break;
 			}
-		} else {
-			ecmd->port = PORT_AUI;
+
+			switch (intf_type) {
+			case PHY_TYPE_KR_10GB:
+			case PHY_TYPE_KX4_10GB:
+				ecmd->autoneg = AUTONEG_ENABLE;
 			ecmd->transceiver = XCVR_INTERNAL;
+				break;
+			default:
+				ecmd->autoneg = AUTONEG_DISABLE;
+				ecmd->transceiver = XCVR_EXTERNAL;
+				break;
+			}
 		}
 
 		/* Save for future use */
 		adapter->link_speed = ecmd->speed;
 		adapter->port_type = ecmd->port;
 		adapter->transceiver = ecmd->transceiver;
+		adapter->autoneg = ecmd->autoneg;
+		pci_free_consistent(adapter->pdev, phy_cmd.size,
+					phy_cmd.va, phy_cmd.dma);
 	} else {
 		ecmd->speed = adapter->link_speed;
 		ecmd->port = adapter->port_type;
 		ecmd->transceiver = adapter->transceiver;
+		ecmd->autoneg = adapter->autoneg;
 	}
 
 	ecmd->duplex = DUPLEX_FULL;
-	ecmd->autoneg = AUTONEG_DISABLE;
 	ecmd->phy_address = adapter->port_num;
 	switch (ecmd->port) {
 	case PORT_FIBRE:
@@ -384,6 +405,13 @@
 		break;
 	}
 
+	if (ecmd->autoneg) {
+		ecmd->supported |= SUPPORTED_1000baseT_Full;
+		ecmd->supported |= SUPPORTED_Autoneg;
+		ecmd->advertising |= (ADVERTISED_10000baseT_Full |
+				ADVERTISED_1000baseT_Full);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h
index 3f1b7c3..5d38046 100644
--- a/drivers/net/benet/be_hw.h
+++ b/drivers/net/benet/be_hw.h
@@ -56,6 +56,16 @@
 #define PCICFG_PM_CONTROL_OFFSET		0x44
 #define PCICFG_PM_CONTROL_MASK			0x108	/* bits 3 & 8 */
 
+/********* Online Control Registers *******/
+#define PCICFG_ONLINE0				0xB0
+#define PCICFG_ONLINE1				0xB4
+
+/********* UE Status and Mask Registers ***/
+#define PCICFG_UE_STATUS_LOW			0xA0
+#define PCICFG_UE_STATUS_HIGH			0xA4
+#define PCICFG_UE_STATUS_LOW_MASK		0xA8
+#define PCICFG_UE_STATUS_HI_MASK		0xAC
+
 /********* ISR0 Register offset **********/
 #define CEV_ISR0_OFFSET 			0xC18
 #define CEV_ISR_SIZE				4
@@ -192,7 +202,7 @@
 	u8 event;
 	u8 crc;
 	u8 forward;
-	u8 ipsec;
+	u8 lso6;
 	u8 mgmt;
 	u8 ipcs;
 	u8 udpcs;
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 54b1427..74e146f 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -40,6 +40,76 @@
 	{ 0 }
 };
 MODULE_DEVICE_TABLE(pci, be_dev_ids);
+/* UE Status Low CSR */
+static char *ue_status_low_desc[] = {
+	"CEV",
+	"CTX",
+	"DBUF",
+	"ERX",
+	"Host",
+	"MPU",
+	"NDMA",
+	"PTC ",
+	"RDMA ",
+	"RXF ",
+	"RXIPS ",
+	"RXULP0 ",
+	"RXULP1 ",
+	"RXULP2 ",
+	"TIM ",
+	"TPOST ",
+	"TPRE ",
+	"TXIPS ",
+	"TXULP0 ",
+	"TXULP1 ",
+	"UC ",
+	"WDMA ",
+	"TXULP2 ",
+	"HOST1 ",
+	"P0_OB_LINK ",
+	"P1_OB_LINK ",
+	"HOST_GPIO ",
+	"MBOX ",
+	"AXGMAC0",
+	"AXGMAC1",
+	"JTAG",
+	"MPU_INTPEND"
+};
+/* UE Status High CSR */
+static char *ue_status_hi_desc[] = {
+	"LPCMEMHOST",
+	"MGMT_MAC",
+	"PCS0ONLINE",
+	"MPU_IRAM",
+	"PCS1ONLINE",
+	"PCTL0",
+	"PCTL1",
+	"PMEM",
+	"RR",
+	"TXPB",
+	"RXPP",
+	"XAUI",
+	"TXP",
+	"ARM",
+	"IPC",
+	"HOST2",
+	"HOST3",
+	"HOST4",
+	"HOST5",
+	"HOST6",
+	"HOST7",
+	"HOST8",
+	"HOST9",
+	"NETC"
+	"Unknown",
+	"Unknown",
+	"Unknown",
+	"Unknown",
+	"Unknown",
+	"Unknown",
+	"Unknown",
+	"Unknown"
+};
 
 static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
 {
@@ -89,6 +159,8 @@
 	u32 val = 0;
 	val |= qid & DB_RQ_RING_ID_MASK;
 	val |= posted << DB_RQ_NUM_POSTED_SHIFT;
+
+	wmb();
 	iowrite32(val, adapter->db + DB_RQ_OFFSET);
 }
 
@@ -97,6 +169,8 @@
 	u32 val = 0;
 	val |= qid & DB_TXULP_RING_ID_MASK;
 	val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT;
+
+	wmb();
 	iowrite32(val, adapter->db + DB_TXULP1_OFFSET);
 }
 
@@ -373,10 +447,12 @@
 
 	AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1);
 
-	if (skb_shinfo(skb)->gso_segs > 1 && skb_shinfo(skb)->gso_size) {
+	if (skb_is_gso(skb)) {
 		AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso, hdr, 1);
 		AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso_mss,
 			hdr, skb_shinfo(skb)->gso_size);
+		if (skb_is_gso_v6(skb))
+			AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso6, hdr, 1);
 	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		if (is_tcp_pkt(skb))
 			AMAP_SET_BITS(struct amap_eth_hdr_wrb, tcpcs, hdr, 1);
@@ -546,11 +622,18 @@
  * A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE.
  * If the user configures more, place BE in vlan promiscuous mode.
  */
-static int be_vid_config(struct be_adapter *adapter)
+static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
 {
 	u16 vtag[BE_NUM_VLANS_SUPPORTED];
 	u16 ntags = 0, i;
 	int status = 0;
+	u32 if_handle;
+
+	if (vf) {
+		if_handle = adapter->vf_cfg[vf_num].vf_if_handle;
+		vtag[0] = cpu_to_le16(adapter->vf_cfg[vf_num].vf_vlan_tag);
+		status = be_cmd_vlan_config(adapter, if_handle, vtag, 1, 1, 0);
+	}
 
 	if (adapter->vlans_added <= adapter->max_vlans)  {
 		/* Construct VLAN Table to give to HW */
@@ -566,6 +649,7 @@
 		status = be_cmd_vlan_config(adapter, adapter->if_handle,
 					NULL, 0, 1, 1);
 	}
+
 	return status;
 }
 
@@ -586,27 +670,28 @@
 {
 	struct be_adapter *adapter = netdev_priv(netdev);
 
+	adapter->vlans_added++;
 	if (!be_physfn(adapter))
 		return;
 
 	adapter->vlan_tag[vid] = 1;
-	adapter->vlans_added++;
 	if (adapter->vlans_added <= (adapter->max_vlans + 1))
-		be_vid_config(adapter);
+		be_vid_config(adapter, false, 0);
 }
 
 static void be_vlan_rem_vid(struct net_device *netdev, u16 vid)
 {
 	struct be_adapter *adapter = netdev_priv(netdev);
 
+	adapter->vlans_added--;
+	vlan_group_set_device(adapter->vlan_grp, vid, NULL);
+
 	if (!be_physfn(adapter))
 		return;
 
 	adapter->vlan_tag[vid] = 0;
-	vlan_group_set_device(adapter->vlan_grp, vid, NULL);
-	adapter->vlans_added--;
 	if (adapter->vlans_added <= adapter->max_vlans)
-		be_vid_config(adapter);
+		be_vid_config(adapter, false, 0);
 }
 
 static void be_set_multicast_list(struct net_device *netdev)
@@ -650,14 +735,93 @@
 	if (!is_valid_ether_addr(mac) || (vf >= num_vfs))
 		return -EINVAL;
 
-	status = be_cmd_pmac_del(adapter, adapter->vf_if_handle[vf],
-				adapter->vf_pmac_id[vf]);
+	if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
+		status = be_cmd_pmac_del(adapter,
+					adapter->vf_cfg[vf].vf_if_handle,
+					adapter->vf_cfg[vf].vf_pmac_id);
 
-	status = be_cmd_pmac_add(adapter, mac, adapter->vf_if_handle[vf],
-				&adapter->vf_pmac_id[vf]);
-	if (!status)
+	status = be_cmd_pmac_add(adapter, mac,
+				adapter->vf_cfg[vf].vf_if_handle,
+				&adapter->vf_cfg[vf].vf_pmac_id);
+
+	if (status)
 		dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n",
 				mac, vf);
+	else
+		memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN);
+
+	return status;
+}
+
+static int be_get_vf_config(struct net_device *netdev, int vf,
+			struct ifla_vf_info *vi)
+{
+	struct be_adapter *adapter = netdev_priv(netdev);
+
+	if (!adapter->sriov_enabled)
+		return -EPERM;
+
+	if (vf >= num_vfs)
+		return -EINVAL;
+
+	vi->vf = vf;
+	vi->tx_rate = adapter->vf_cfg[vf].vf_tx_rate;
+	vi->vlan = adapter->vf_cfg[vf].vf_vlan_tag;
+	vi->qos = 0;
+	memcpy(&vi->mac, adapter->vf_cfg[vf].vf_mac_addr, ETH_ALEN);
+
+	return 0;
+}
+
+static int be_set_vf_vlan(struct net_device *netdev,
+			int vf, u16 vlan, u8 qos)
+{
+	struct be_adapter *adapter = netdev_priv(netdev);
+	int status = 0;
+
+	if (!adapter->sriov_enabled)
+		return -EPERM;
+
+	if ((vf >= num_vfs) || (vlan > 4095))
+		return -EINVAL;
+
+	if (vlan) {
+		adapter->vf_cfg[vf].vf_vlan_tag = vlan;
+		adapter->vlans_added++;
+	} else {
+		adapter->vf_cfg[vf].vf_vlan_tag = 0;
+		adapter->vlans_added--;
+	}
+
+	status = be_vid_config(adapter, true, vf);
+
+	if (status)
+		dev_info(&adapter->pdev->dev,
+				"VLAN %d config on VF %d failed\n", vlan, vf);
+	return status;
+}
+
+static int be_set_vf_tx_rate(struct net_device *netdev,
+			int vf, int rate)
+{
+	struct be_adapter *adapter = netdev_priv(netdev);
+	int status = 0;
+
+	if (!adapter->sriov_enabled)
+		return -EPERM;
+
+	if ((vf >= num_vfs) || (rate < 0))
+		return -EINVAL;
+
+	if (rate > 10000)
+		rate = 10000;
+
+	adapter->vf_cfg[vf].vf_tx_rate = rate;
+	status = be_cmd_set_qos(adapter, rate / 10, vf);
+
+	if (status)
+		dev_info(&adapter->pdev->dev,
+				"tx rate %d on VF %d failed\n", rate, vf);
 	return status;
 }
 
@@ -869,7 +1033,7 @@
 
 	/* vlanf could be wrongly set in some cards.
 	 * ignore if vtm is not set */
-	if ((adapter->cap & 0x400) && !vtm)
+	if ((adapter->function_mode & 0x400) && !vtm)
 		vlanf = 0;
 
 	if (unlikely(vlanf)) {
@@ -909,7 +1073,7 @@
 
 	/* vlanf could be wrongly set in some cards.
 	 * ignore if vtm is not set */
-	if ((adapter->cap & 0x400) && !vtm)
+	if ((adapter->function_mode & 0x400) && !vtm)
 		vlanf = 0;
 
 	skb = napi_get_frags(&eq_obj->napi);
@@ -971,6 +1135,7 @@
 	if (rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] == 0)
 		return NULL;
 
+	rmb();
 	be_dws_le_to_cpu(rxcp, sizeof(*rxcp));
 
 	queue_tail_inc(&adapter->rx_obj.cq);
@@ -1064,6 +1229,7 @@
 	if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0)
 		return NULL;
 
+	rmb();
 	be_dws_le_to_cpu(txcp, sizeof(*txcp));
 
 	txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] = 0;
@@ -1111,6 +1277,7 @@
 	if (!eqe->evt)
 		return NULL;
 
+	rmb();
 	eqe->evt = le32_to_cpu(eqe->evt);
 	queue_tail_inc(&eq_obj->q);
 	return eqe;
@@ -1576,12 +1743,66 @@
 	return 1;
 }
 
+static inline bool be_detect_ue(struct be_adapter *adapter)
+{
+	u32 online0 = 0, online1 = 0;
+
+	pci_read_config_dword(adapter->pdev, PCICFG_ONLINE0, &online0);
+
+	pci_read_config_dword(adapter->pdev, PCICFG_ONLINE1, &online1);
+
+	if (!online0 || !online1) {
+		adapter->ue_detected = true;
+		dev_err(&adapter->pdev->dev,
+			"UE Detected!! online0=%d online1=%d\n",
+			online0, online1);
+		return true;
+	}
+
+	return false;
+}
+
+void be_dump_ue(struct be_adapter *adapter)
+{
+	u32 ue_status_lo, ue_status_hi, ue_status_lo_mask, ue_status_hi_mask;
+	u32 i;
+
+	pci_read_config_dword(adapter->pdev,
+				PCICFG_UE_STATUS_LOW, &ue_status_lo);
+	pci_read_config_dword(adapter->pdev,
+				PCICFG_UE_STATUS_HIGH, &ue_status_hi);
+	pci_read_config_dword(adapter->pdev,
+				PCICFG_UE_STATUS_LOW_MASK, &ue_status_lo_mask);
+	pci_read_config_dword(adapter->pdev,
+				PCICFG_UE_STATUS_HI_MASK, &ue_status_hi_mask);
+
+	ue_status_lo = (ue_status_lo & (~ue_status_lo_mask));
+	ue_status_hi = (ue_status_hi & (~ue_status_hi_mask));
+
+	if (ue_status_lo) {
+		for (i = 0; ue_status_lo; ue_status_lo >>= 1, i++) {
+			if (ue_status_lo & 1)
+				dev_err(&adapter->pdev->dev,
+				"UE: %s bit set\n", ue_status_low_desc[i]);
+		}
+	}
+	if (ue_status_hi) {
+		for (i = 0; ue_status_hi; ue_status_hi >>= 1, i++) {
+			if (ue_status_hi & 1)
+				dev_err(&adapter->pdev->dev,
+				"UE: %s bit set\n", ue_status_hi_desc[i]);
+		}
+	}
+
+}
+
 static void be_worker(struct work_struct *work)
 {
 	struct be_adapter *adapter =
 		container_of(work, struct be_adapter, work.work);
 
-	be_cmd_get_stats(adapter, &adapter->stats.cmd);
+	if (!adapter->stats_ioctl_sent)
+		be_cmd_get_stats(adapter, &adapter->stats.cmd);
 
 	/* Set EQ delay */
 	be_rx_eqd_update(adapter);
@@ -1593,6 +1814,10 @@
 		adapter->rx_post_starved = false;
 		be_post_rx_frags(adapter);
 	}
+	if (!adapter->ue_detected) {
+		if (be_detect_ue(adapter))
+			be_dump_ue(adapter);
+	}
 
 	schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
 }
@@ -1620,9 +1845,11 @@
 
 static void be_sriov_enable(struct be_adapter *adapter)
 {
+	be_check_sriov_fn_type(adapter);
 #ifdef CONFIG_PCI_IOV
-	int status;
 	if (be_physfn(adapter) && num_vfs) {
+		int status;
+
 		status = pci_enable_sriov(adapter->pdev, num_vfs);
 		adapter->sriov_enabled = status ? false : true;
 	}
@@ -1735,6 +1962,44 @@
 	adapter->isr_registered = false;
 }
 
+static int be_close(struct net_device *netdev)
+{
+	struct be_adapter *adapter = netdev_priv(netdev);
+	struct be_eq_obj *rx_eq = &adapter->rx_eq;
+	struct be_eq_obj *tx_eq = &adapter->tx_eq;
+	int vec;
+
+	cancel_delayed_work_sync(&adapter->work);
+
+	be_async_mcc_disable(adapter);
+
+	netif_stop_queue(netdev);
+	netif_carrier_off(netdev);
+	adapter->link_up = false;
+
+	be_intr_set(adapter, false);
+
+	if (adapter->msix_enabled) {
+		vec = be_msix_vec_get(adapter, tx_eq->q.id);
+		synchronize_irq(vec);
+		vec = be_msix_vec_get(adapter, rx_eq->q.id);
+		synchronize_irq(vec);
+	} else {
+		synchronize_irq(netdev->irq);
+	}
+	be_irq_unregister(adapter);
+
+	napi_disable(&rx_eq->napi);
+	napi_disable(&tx_eq->napi);
+
+	/* Wait for all pending tx completions to arrive so that
+	 * all tx skbs are freed.
+	 */
+	be_tx_compl_clean(adapter);
+
+	return 0;
+}
+
 static int be_open(struct net_device *netdev)
 {
 	struct be_adapter *adapter = netdev_priv(netdev);
@@ -1765,27 +2030,29 @@
 	/* Now that interrupts are on we can process async mcc */
 	be_async_mcc_enable(adapter);
 
+	schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
+
 	status = be_cmd_link_status_query(adapter, &link_up, &mac_speed,
 			&link_speed);
 	if (status)
-		goto ret_sts;
+		goto err;
 	be_link_status_update(adapter, link_up);
 
-	if (be_physfn(adapter))
-		status = be_vid_config(adapter);
-	if (status)
-		goto ret_sts;
-
 	if (be_physfn(adapter)) {
+		status = be_vid_config(adapter, false, 0);
+		if (status)
+			goto err;
+
 		status = be_cmd_set_flow_control(adapter,
 				adapter->tx_fc, adapter->rx_fc);
 		if (status)
-			goto ret_sts;
+			goto err;
 	}
 
-	schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
-ret_sts:
-	return status;
+	return 0;
+err:
+	be_close(adapter->netdev);
+	return -EIO;
 }
 
 static int be_setup_wol(struct be_adapter *adapter, bool enable)
@@ -1853,13 +2120,15 @@
 			cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED
 					| BE_IF_FLAGS_BROADCAST;
 			status = be_cmd_if_create(adapter, cap_flags, en_flags,
-					mac, true, &adapter->vf_if_handle[vf],
+					mac, true,
+					&adapter->vf_cfg[vf].vf_if_handle,
 					NULL, vf+1);
 			if (status) {
 				dev_err(&adapter->pdev->dev,
 				"Interface Create failed for VF %d\n", vf);
 				goto if_destroy;
 			}
+			adapter->vf_cfg[vf].vf_pmac_id = BE_INVALID_PMAC_ID;
 			vf++;
 		}
 	} else if (!be_physfn(adapter)) {
@@ -1893,8 +2162,9 @@
 	be_tx_queues_destroy(adapter);
 if_destroy:
 	for (vf = 0; vf < num_vfs; vf++)
-		if (adapter->vf_if_handle[vf])
-			be_cmd_if_destroy(adapter, adapter->vf_if_handle[vf]);
+		if (adapter->vf_cfg[vf].vf_if_handle)
+			be_cmd_if_destroy(adapter,
+					adapter->vf_cfg[vf].vf_if_handle);
 	be_cmd_if_destroy(adapter, adapter->if_handle);
 do_none:
 	return status;
@@ -1913,43 +2183,6 @@
 	return 0;
 }
 
-static int be_close(struct net_device *netdev)
-{
-	struct be_adapter *adapter = netdev_priv(netdev);
-	struct be_eq_obj *rx_eq = &adapter->rx_eq;
-	struct be_eq_obj *tx_eq = &adapter->tx_eq;
-	int vec;
-
-	cancel_delayed_work_sync(&adapter->work);
-
-	be_async_mcc_disable(adapter);
-
-	netif_stop_queue(netdev);
-	netif_carrier_off(netdev);
-	adapter->link_up = false;
-
-	be_intr_set(adapter, false);
-
-	if (adapter->msix_enabled) {
-		vec = be_msix_vec_get(adapter, tx_eq->q.id);
-		synchronize_irq(vec);
-		vec = be_msix_vec_get(adapter, rx_eq->q.id);
-		synchronize_irq(vec);
-	} else {
-		synchronize_irq(netdev->irq);
-	}
-	be_irq_unregister(adapter);
-
-	napi_disable(&rx_eq->napi);
-	napi_disable(&tx_eq->napi);
-
-	/* Wait for all pending tx completions to arrive so that
-	 * all tx skbs are freed.
-	 */
-	be_tx_compl_clean(adapter);
-
-	return 0;
-}
 
 #define FW_FILE_HDR_SIGN 	"ServerEngines Corp. "
 char flash_cookie[2][16] =	{"*** SE FLAS",
@@ -2174,7 +2407,10 @@
 	.ndo_vlan_rx_register	= be_vlan_register,
 	.ndo_vlan_rx_add_vid	= be_vlan_add_vid,
 	.ndo_vlan_rx_kill_vid	= be_vlan_rem_vid,
-	.ndo_set_vf_mac		= be_set_vf_mac
+	.ndo_set_vf_mac		= be_set_vf_mac,
+	.ndo_set_vf_vlan	= be_set_vf_vlan,
+	.ndo_set_vf_tx_rate	= be_set_vf_tx_rate,
+	.ndo_get_vf_config	= be_get_vf_config
 };
 
 static void be_netdev_init(struct net_device *netdev)
@@ -2183,7 +2419,7 @@
 
 	netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
 		NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_CSUM |
-		NETIF_F_GRO;
+		NETIF_F_GRO | NETIF_F_TSO6;
 
 	netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_CSUM;
 
@@ -2393,7 +2629,7 @@
 		return status;
 
 	status = be_cmd_query_fw_cfg(adapter,
-				&adapter->port_num, &adapter->cap);
+				&adapter->port_num, &adapter->function_mode);
 	if (status)
 		return status;
 
@@ -2413,7 +2649,7 @@
 		memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
 	}
 
-	if (adapter->cap & 0x400)
+	if (adapter->function_mode & 0x400)
 		adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/4;
 	else
 		adapter->max_vlans = BE_NUM_VLANS_SUPPORTED;
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 368f333..012613f 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -922,61 +922,73 @@
 # define bfin_tx_hwtstamp(dev, skb)
 #endif
 
-static void adjust_tx_list(void)
+static inline void _tx_reclaim_skb(void)
 {
-	int timeout_cnt = MAX_TIMEOUT_CNT;
-
-	if (tx_list_head->status.status_word != 0 &&
-	    current_tx_ptr != tx_list_head) {
-		goto adjust_head;	/* released something, just return; */
-	}
-
-	/*
-	 * if nothing released, check wait condition
-	 * current's next can not be the head,
-	 * otherwise the dma will not stop as we want
-	 */
-	if (current_tx_ptr->next->next == tx_list_head) {
-		while (tx_list_head->status.status_word == 0) {
-			udelay(10);
-			if (tx_list_head->status.status_word != 0 ||
-			    !(bfin_read_DMA2_IRQ_STATUS() & DMA_RUN)) {
-				goto adjust_head;
-			}
-			if (timeout_cnt-- < 0) {
-				printk(KERN_ERR DRV_NAME
-				": wait for adjust tx list head timeout\n");
-				break;
-			}
-		}
-		if (tx_list_head->status.status_word != 0) {
-			goto adjust_head;
-		}
-	}
-
-	return;
-
-adjust_head:
 	do {
 		tx_list_head->desc_a.config &= ~DMAEN;
 		tx_list_head->status.status_word = 0;
 		if (tx_list_head->skb) {
 			dev_kfree_skb(tx_list_head->skb);
 			tx_list_head->skb = NULL;
-		} else {
-			printk(KERN_ERR DRV_NAME
-			       ": no sk_buff in a transmitted frame!\n");
 		}
 		tx_list_head = tx_list_head->next;
-	} while (tx_list_head->status.status_word != 0 &&
-		 current_tx_ptr != tx_list_head);
-	return;
 
+	} while (tx_list_head->status.status_word != 0);
+}
+
+static void tx_reclaim_skb(struct bfin_mac_local *lp)
+{
+	int timeout_cnt = MAX_TIMEOUT_CNT;
+
+	if (tx_list_head->status.status_word != 0)
+		_tx_reclaim_skb();
+
+	if (current_tx_ptr->next == tx_list_head) {
+		while (tx_list_head->status.status_word == 0) {
+			/* slow down polling to avoid too many queue stop. */
+			udelay(10);
+			/* reclaim skb if DMA is not running. */
+			if (!(bfin_read_DMA2_IRQ_STATUS() & DMA_RUN))
+				break;
+			if (timeout_cnt-- < 0)
+				break;
+		}
+
+		if (timeout_cnt >= 0)
+			_tx_reclaim_skb();
+		else
+			netif_stop_queue(lp->ndev);
+	}
+
+	if (current_tx_ptr->next != tx_list_head &&
+		netif_queue_stopped(lp->ndev))
+		netif_wake_queue(lp->ndev);
+
+	if (tx_list_head != current_tx_ptr) {
+		/* shorten the timer interval if tx queue is stopped */
+		if (netif_queue_stopped(lp->ndev))
+			lp->tx_reclaim_timer.expires =
+				jiffies + (TX_RECLAIM_JIFFIES >> 4);
+		else
+			lp->tx_reclaim_timer.expires =
+				jiffies + TX_RECLAIM_JIFFIES;
+
+		mod_timer(&lp->tx_reclaim_timer,
+			lp->tx_reclaim_timer.expires);
+	}
+
+	return;
+}
+
+static void tx_reclaim_skb_timeout(unsigned long lp)
+{
+	tx_reclaim_skb((struct bfin_mac_local *)lp);
 }
 
 static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
 				struct net_device *dev)
 {
+	struct bfin_mac_local *lp = netdev_priv(dev);
 	u16 *data;
 	u32 data_align = (unsigned long)(skb->data) & 0x3;
 	union skb_shared_tx *shtx = skb_tx(skb);
@@ -1009,8 +1021,6 @@
 			skb->len);
 		current_tx_ptr->desc_a.start_addr =
 			(u32)current_tx_ptr->packet;
-		if (current_tx_ptr->status.status_word != 0)
-			current_tx_ptr->status.status_word = 0;
 		blackfin_dcache_flush_range(
 			(u32)current_tx_ptr->packet,
 			(u32)(current_tx_ptr->packet + skb->len + 2));
@@ -1022,6 +1032,9 @@
 	 */
 	SSYNC();
 
+	/* always clear status buffer before start tx dma */
+	current_tx_ptr->status.status_word = 0;
+
 	/* enable this packet's dma */
 	current_tx_ptr->desc_a.config |= DMAEN;
 
@@ -1037,13 +1050,14 @@
 	bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);
 
 out:
-	adjust_tx_list();
-
 	bfin_tx_hwtstamp(dev, skb);
 
 	current_tx_ptr = current_tx_ptr->next;
 	dev->stats.tx_packets++;
 	dev->stats.tx_bytes += (skb->len);
+
+	tx_reclaim_skb(lp);
+
 	return NETDEV_TX_OK;
 }
 
@@ -1167,8 +1181,11 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void bfin_mac_poll(struct net_device *dev)
 {
+	struct bfin_mac_local *lp = netdev_priv(dev);
+
 	disable_irq(IRQ_MAC_RX);
 	bfin_mac_interrupt(IRQ_MAC_RX, dev);
+	tx_reclaim_skb(lp);
 	enable_irq(IRQ_MAC_RX);
 }
 #endif				/* CONFIG_NET_POLL_CONTROLLER */
@@ -1232,12 +1249,27 @@
 /* Our watchdog timed out. Called by the networking layer */
 static void bfin_mac_timeout(struct net_device *dev)
 {
+	struct bfin_mac_local *lp = netdev_priv(dev);
+
 	pr_debug("%s: %s\n", dev->name, __func__);
 
 	bfin_mac_disable();
 
-	/* reset tx queue */
-	tx_list_tail = tx_list_head->next;
+	del_timer(&lp->tx_reclaim_timer);
+
+	/* reset tx queue and free skb */
+	while (tx_list_head != current_tx_ptr) {
+		tx_list_head->desc_a.config &= ~DMAEN;
+		tx_list_head->status.status_word = 0;
+		if (tx_list_head->skb) {
+			dev_kfree_skb(tx_list_head->skb);
+			tx_list_head->skb = NULL;
+		}
+		tx_list_head = tx_list_head->next;
+	}
+
+	if (netif_queue_stopped(lp->ndev))
+		netif_wake_queue(lp->ndev);
 
 	bfin_mac_enable();
 
@@ -1430,6 +1462,7 @@
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 	platform_set_drvdata(pdev, ndev);
 	lp = netdev_priv(ndev);
+	lp->ndev = ndev;
 
 	/* Grab the MAC address in the MAC */
 	*(__le32 *) (&(ndev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
@@ -1485,6 +1518,10 @@
 	ndev->netdev_ops = &bfin_mac_netdev_ops;
 	ndev->ethtool_ops = &bfin_mac_ethtool_ops;
 
+	init_timer(&lp->tx_reclaim_timer);
+	lp->tx_reclaim_timer.data = (unsigned long)lp;
+	lp->tx_reclaim_timer.function = tx_reclaim_skb_timeout;
+
 	spin_lock_init(&lp->lock);
 
 	/* now, enable interrupts */
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
index 1ae7b82..04e4050 100644
--- a/drivers/net/bfin_mac.h
+++ b/drivers/net/bfin_mac.h
@@ -13,9 +13,12 @@
 #include <linux/net_tstamp.h>
 #include <linux/clocksource.h>
 #include <linux/timecompare.h>
+#include <linux/timer.h>
 
 #define BFIN_MAC_CSUM_OFFLOAD
 
+#define TX_RECLAIM_JIFFIES (HZ / 5)
+
 struct dma_descriptor {
 	struct dma_descriptor *next_dma_desc;
 	unsigned long start_addr;
@@ -68,6 +71,8 @@
 
 	int wol;		/* Wake On Lan */
 	int irq_wake_requested;
+	struct timer_list tx_reclaim_timer;
+	struct net_device *ndev;
 
 	/* MII and PHY stuffs */
 	int old_link;          /* used by bf537_adjust_link */
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 1174322..e6a803f 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -58,8 +58,8 @@
 #include "bnx2_fw.h"
 
 #define DRV_MODULE_NAME		"bnx2"
-#define DRV_MODULE_VERSION	"2.0.15"
-#define DRV_MODULE_RELDATE	"May 4, 2010"
+#define DRV_MODULE_VERSION	"2.0.17"
+#define DRV_MODULE_RELDATE	"July 18, 2010"
 #define FW_MIPS_FILE_06		"bnx2/bnx2-mips-06-5.0.0.j6.fw"
 #define FW_RV2P_FILE_06		"bnx2/bnx2-rv2p-06-5.0.0.j3.fw"
 #define FW_MIPS_FILE_09		"bnx2/bnx2-mips-09-5.0.0.j15.fw"
@@ -253,7 +253,8 @@
 {
 	u32 diff;
 
-	smp_mb();
+	/* Tell compiler to fetch tx_prod and tx_cons from memory. */
+	barrier();
 
 	/* The ring uses 256 indices for 255 entries, one of them
 	 * needs to be skipped.
@@ -692,9 +693,9 @@
 		struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
 
 		if (txr->tx_desc_ring) {
-			pci_free_consistent(bp->pdev, TXBD_RING_SIZE,
-					    txr->tx_desc_ring,
-					    txr->tx_desc_mapping);
+			dma_free_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
+					  txr->tx_desc_ring,
+					  txr->tx_desc_mapping);
 			txr->tx_desc_ring = NULL;
 		}
 		kfree(txr->tx_buf_ring);
@@ -714,9 +715,9 @@
 
 		for (j = 0; j < bp->rx_max_ring; j++) {
 			if (rxr->rx_desc_ring[j])
-				pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
-						    rxr->rx_desc_ring[j],
-						    rxr->rx_desc_mapping[j]);
+				dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
+						  rxr->rx_desc_ring[j],
+						  rxr->rx_desc_mapping[j]);
 			rxr->rx_desc_ring[j] = NULL;
 		}
 		vfree(rxr->rx_buf_ring);
@@ -724,9 +725,9 @@
 
 		for (j = 0; j < bp->rx_max_pg_ring; j++) {
 			if (rxr->rx_pg_desc_ring[j])
-				pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
-						    rxr->rx_pg_desc_ring[j],
-						    rxr->rx_pg_desc_mapping[j]);
+				dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
+						  rxr->rx_pg_desc_ring[j],
+						  rxr->rx_pg_desc_mapping[j]);
 			rxr->rx_pg_desc_ring[j] = NULL;
 		}
 		vfree(rxr->rx_pg_ring);
@@ -748,8 +749,8 @@
 			return -ENOMEM;
 
 		txr->tx_desc_ring =
-			pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE,
-					     &txr->tx_desc_mapping);
+			dma_alloc_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
+					   &txr->tx_desc_mapping, GFP_KERNEL);
 		if (txr->tx_desc_ring == NULL)
 			return -ENOMEM;
 	}
@@ -776,8 +777,10 @@
 
 		for (j = 0; j < bp->rx_max_ring; j++) {
 			rxr->rx_desc_ring[j] =
-				pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
-						     &rxr->rx_desc_mapping[j]);
+				dma_alloc_coherent(&bp->pdev->dev,
+						   RXBD_RING_SIZE,
+						   &rxr->rx_desc_mapping[j],
+						   GFP_KERNEL);
 			if (rxr->rx_desc_ring[j] == NULL)
 				return -ENOMEM;
 
@@ -795,8 +798,10 @@
 
 		for (j = 0; j < bp->rx_max_pg_ring; j++) {
 			rxr->rx_pg_desc_ring[j] =
-				pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
-						&rxr->rx_pg_desc_mapping[j]);
+				dma_alloc_coherent(&bp->pdev->dev,
+						   RXBD_RING_SIZE,
+						   &rxr->rx_pg_desc_mapping[j],
+						   GFP_KERNEL);
 			if (rxr->rx_pg_desc_ring[j] == NULL)
 				return -ENOMEM;
 
@@ -816,16 +821,16 @@
 
 	for (i = 0; i < bp->ctx_pages; i++) {
 		if (bp->ctx_blk[i]) {
-			pci_free_consistent(bp->pdev, BCM_PAGE_SIZE,
-					    bp->ctx_blk[i],
-					    bp->ctx_blk_mapping[i]);
+			dma_free_coherent(&bp->pdev->dev, BCM_PAGE_SIZE,
+					  bp->ctx_blk[i],
+					  bp->ctx_blk_mapping[i]);
 			bp->ctx_blk[i] = NULL;
 		}
 	}
 	if (bnapi->status_blk.msi) {
-		pci_free_consistent(bp->pdev, bp->status_stats_size,
-				    bnapi->status_blk.msi,
-				    bp->status_blk_mapping);
+		dma_free_coherent(&bp->pdev->dev, bp->status_stats_size,
+				  bnapi->status_blk.msi,
+				  bp->status_blk_mapping);
 		bnapi->status_blk.msi = NULL;
 		bp->stats_blk = NULL;
 	}
@@ -846,8 +851,8 @@
 	bp->status_stats_size = status_blk_size +
 				sizeof(struct statistics_block);
 
-	status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,
-					  &bp->status_blk_mapping);
+	status_blk = dma_alloc_coherent(&bp->pdev->dev, bp->status_stats_size,
+					&bp->status_blk_mapping, GFP_KERNEL);
 	if (status_blk == NULL)
 		goto alloc_mem_err;
 
@@ -860,7 +865,7 @@
 	bnapi->hw_rx_cons_ptr =
 		&bnapi->status_blk.msi->status_rx_quick_consumer_index0;
 	if (bp->flags & BNX2_FLAG_MSIX_CAP) {
-		for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) {
+		for (i = 1; i < bp->irq_nvecs; i++) {
 			struct status_block_msix *sblk;
 
 			bnapi = &bp->bnx2_napi[i];
@@ -885,9 +890,10 @@
 		if (bp->ctx_pages == 0)
 			bp->ctx_pages = 1;
 		for (i = 0; i < bp->ctx_pages; i++) {
-			bp->ctx_blk[i] = pci_alloc_consistent(bp->pdev,
+			bp->ctx_blk[i] = dma_alloc_coherent(&bp->pdev->dev,
 						BCM_PAGE_SIZE,
-						&bp->ctx_blk_mapping[i]);
+						&bp->ctx_blk_mapping[i],
+						GFP_KERNEL);
 			if (bp->ctx_blk[i] == NULL)
 				goto alloc_mem_err;
 		}
@@ -1446,7 +1452,8 @@
 static void
 bnx2_enable_forced_2g5(struct bnx2 *bp)
 {
-	u32 bmcr;
+	u32 uninitialized_var(bmcr);
+	int err;
 
 	if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
 		return;
@@ -1456,22 +1463,28 @@
 
 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
 			       MII_BNX2_BLK_ADDR_SERDES_DIG);
-		bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
-		val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
-		val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
-		bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+		if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
+			val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
+			val |= MII_BNX2_SD_MISC1_FORCE |
+				MII_BNX2_SD_MISC1_FORCE_2_5G;
+			bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+		}
 
 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
 			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
-		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+		err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
 
 	} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
-		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
-		bmcr |= BCM5708S_BMCR_FORCE_2500;
+		err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+		if (!err)
+			bmcr |= BCM5708S_BMCR_FORCE_2500;
 	} else {
 		return;
 	}
 
+	if (err)
+		return;
+
 	if (bp->autoneg & AUTONEG_SPEED) {
 		bmcr &= ~BMCR_ANENABLE;
 		if (bp->req_duplex == DUPLEX_FULL)
@@ -1483,7 +1496,8 @@
 static void
 bnx2_disable_forced_2g5(struct bnx2 *bp)
 {
-	u32 bmcr;
+	u32 uninitialized_var(bmcr);
+	int err;
 
 	if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
 		return;
@@ -1493,21 +1507,26 @@
 
 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
 			       MII_BNX2_BLK_ADDR_SERDES_DIG);
-		bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
-		val &= ~MII_BNX2_SD_MISC1_FORCE;
-		bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+		if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
+			val &= ~MII_BNX2_SD_MISC1_FORCE;
+			bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+		}
 
 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
 			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
-		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+		err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
 
 	} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
-		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
-		bmcr &= ~BCM5708S_BMCR_FORCE_2500;
+		err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+		if (!err)
+			bmcr &= ~BCM5708S_BMCR_FORCE_2500;
 	} else {
 		return;
 	}
 
+	if (err)
+		return;
+
 	if (bp->autoneg & AUTONEG_SPEED)
 		bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
 	bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
@@ -2651,19 +2670,19 @@
 }
 
 static inline int
-bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
+bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
 {
 	dma_addr_t mapping;
 	struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
 	struct rx_bd *rxbd =
 		&rxr->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)];
-	struct page *page = alloc_page(GFP_ATOMIC);
+	struct page *page = alloc_page(gfp);
 
 	if (!page)
 		return -ENOMEM;
-	mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
+	mapping = dma_map_page(&bp->pdev->dev, page, 0, PAGE_SIZE,
 			       PCI_DMA_FROMDEVICE);
-	if (pci_dma_mapping_error(bp->pdev, mapping)) {
+	if (dma_mapping_error(&bp->pdev->dev, mapping)) {
 		__free_page(page);
 		return -EIO;
 	}
@@ -2684,15 +2703,15 @@
 	if (!page)
 		return;
 
-	pci_unmap_page(bp->pdev, dma_unmap_addr(rx_pg, mapping), PAGE_SIZE,
-		       PCI_DMA_FROMDEVICE);
+	dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(rx_pg, mapping),
+		       PAGE_SIZE, PCI_DMA_FROMDEVICE);
 
 	__free_page(page);
 	rx_pg->page = NULL;
 }
 
 static inline int
-bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
+bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
 {
 	struct sk_buff *skb;
 	struct sw_bd *rx_buf = &rxr->rx_buf_ring[index];
@@ -2700,7 +2719,7 @@
 	struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
 	unsigned long align;
 
-	skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
+	skb = __netdev_alloc_skb(bp->dev, bp->rx_buf_size, gfp);
 	if (skb == NULL) {
 		return -ENOMEM;
 	}
@@ -2708,9 +2727,9 @@
 	if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
 		skb_reserve(skb, BNX2_RX_ALIGN - align);
 
-	mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
-		PCI_DMA_FROMDEVICE);
-	if (pci_dma_mapping_error(bp->pdev, mapping)) {
+	mapping = dma_map_single(&bp->pdev->dev, skb->data, bp->rx_buf_use_size,
+				 PCI_DMA_FROMDEVICE);
+	if (dma_mapping_error(&bp->pdev->dev, mapping)) {
 		dev_kfree_skb(skb);
 		return -EIO;
 	}
@@ -2816,7 +2835,7 @@
 			}
 		}
 
-		pci_unmap_single(bp->pdev, dma_unmap_addr(tx_buf, mapping),
+		dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
 			skb_headlen(skb), PCI_DMA_TODEVICE);
 
 		tx_buf->skb = NULL;
@@ -2825,7 +2844,7 @@
 		for (i = 0; i < last; i++) {
 			sw_cons = NEXT_TX_BD(sw_cons);
 
-			pci_unmap_page(bp->pdev,
+			dma_unmap_page(&bp->pdev->dev,
 				dma_unmap_addr(
 					&txr->tx_buf_ring[TX_RING_IDX(sw_cons)],
 					mapping),
@@ -2932,7 +2951,7 @@
 	cons_rx_buf = &rxr->rx_buf_ring[cons];
 	prod_rx_buf = &rxr->rx_buf_ring[prod];
 
-	pci_dma_sync_single_for_device(bp->pdev,
+	dma_sync_single_for_device(&bp->pdev->dev,
 		dma_unmap_addr(cons_rx_buf, mapping),
 		BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
 
@@ -2961,7 +2980,7 @@
 	int err;
 	u16 prod = ring_idx & 0xffff;
 
-	err = bnx2_alloc_rx_skb(bp, rxr, prod);
+	err = bnx2_alloc_rx_skb(bp, rxr, prod, GFP_ATOMIC);
 	if (unlikely(err)) {
 		bnx2_reuse_rx_skb(bp, rxr, skb, (u16) (ring_idx >> 16), prod);
 		if (hdr_len) {
@@ -2974,7 +2993,7 @@
 	}
 
 	skb_reserve(skb, BNX2_RX_OFFSET);
-	pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size,
+	dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
 			 PCI_DMA_FROMDEVICE);
 
 	if (hdr_len == 0) {
@@ -3026,7 +3045,8 @@
 			rx_pg->page = NULL;
 
 			err = bnx2_alloc_rx_page(bp, rxr,
-						 RX_PG_RING_IDX(pg_prod));
+						 RX_PG_RING_IDX(pg_prod),
+						 GFP_ATOMIC);
 			if (unlikely(err)) {
 				rxr->rx_pg_cons = pg_cons;
 				rxr->rx_pg_prod = pg_prod;
@@ -3035,7 +3055,7 @@
 				return err;
 			}
 
-			pci_unmap_page(bp->pdev, mapping_old,
+			dma_unmap_page(&bp->pdev->dev, mapping_old,
 				       PAGE_SIZE, PCI_DMA_FROMDEVICE);
 
 			frag_size -= frag_len;
@@ -3106,7 +3126,7 @@
 
 		dma_addr = dma_unmap_addr(rx_buf, mapping);
 
-		pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
+		dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr,
 			BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
 			PCI_DMA_FROMDEVICE);
 
@@ -3206,6 +3226,10 @@
 					      L2_FHDR_ERRORS_UDP_XSUM)) == 0))
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
 		}
+		if ((bp->dev->features & NETIF_F_RXHASH) &&
+		    ((status & L2_FHDR_STATUS_USE_RXHASH) ==
+		     L2_FHDR_STATUS_USE_RXHASH))
+			skb->rxhash = rx_hdr->l2_fhdr_hash;
 
 		skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
 
@@ -5162,7 +5186,7 @@
 
 	ring_prod = prod = rxr->rx_pg_prod;
 	for (i = 0; i < bp->rx_pg_ring_size; i++) {
-		if (bnx2_alloc_rx_page(bp, rxr, ring_prod) < 0) {
+		if (bnx2_alloc_rx_page(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
 			netdev_warn(bp->dev, "init'ed rx page ring %d with %d/%d pages only\n",
 				    ring_num, i, bp->rx_pg_ring_size);
 			break;
@@ -5174,7 +5198,7 @@
 
 	ring_prod = prod = rxr->rx_prod;
 	for (i = 0; i < bp->rx_ring_size; i++) {
-		if (bnx2_alloc_rx_skb(bp, rxr, ring_prod) < 0) {
+		if (bnx2_alloc_rx_skb(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
 			netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
 				    ring_num, i, bp->rx_ring_size);
 			break;
@@ -5320,7 +5344,7 @@
 				continue;
 			}
 
-			pci_unmap_single(bp->pdev,
+			dma_unmap_single(&bp->pdev->dev,
 					 dma_unmap_addr(tx_buf, mapping),
 					 skb_headlen(skb),
 					 PCI_DMA_TODEVICE);
@@ -5331,7 +5355,7 @@
 			j++;
 			for (k = 0; k < last; k++, j++) {
 				tx_buf = &txr->tx_buf_ring[TX_RING_IDX(j)];
-				pci_unmap_page(bp->pdev,
+				dma_unmap_page(&bp->pdev->dev,
 					dma_unmap_addr(tx_buf, mapping),
 					skb_shinfo(skb)->frags[k].size,
 					PCI_DMA_TODEVICE);
@@ -5361,7 +5385,7 @@
 			if (skb == NULL)
 				continue;
 
-			pci_unmap_single(bp->pdev,
+			dma_unmap_single(&bp->pdev->dev,
 					 dma_unmap_addr(rx_buf, mapping),
 					 bp->rx_buf_use_size,
 					 PCI_DMA_FROMDEVICE);
@@ -5714,9 +5738,9 @@
 	for (i = 14; i < pkt_size; i++)
 		packet[i] = (unsigned char) (i & 0xff);
 
-	map = pci_map_single(bp->pdev, skb->data, pkt_size,
-		PCI_DMA_TODEVICE);
-	if (pci_dma_mapping_error(bp->pdev, map)) {
+	map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size,
+			     PCI_DMA_TODEVICE);
+	if (dma_mapping_error(&bp->pdev->dev, map)) {
 		dev_kfree_skb(skb);
 		return -EIO;
 	}
@@ -5754,7 +5778,7 @@
 
 	udelay(5);
 
-	pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
+	dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE);
 	dev_kfree_skb(skb);
 
 	if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
@@ -5771,7 +5795,7 @@
 	rx_hdr = rx_buf->desc;
 	skb_reserve(rx_skb, BNX2_RX_OFFSET);
 
-	pci_dma_sync_single_for_cpu(bp->pdev,
+	dma_sync_single_for_cpu(&bp->pdev->dev,
 		dma_unmap_addr(rx_buf, mapping),
 		bp->rx_buf_size, PCI_DMA_FROMDEVICE);
 
@@ -6129,7 +6153,7 @@
 static void
 bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
 {
-	int i, rc;
+	int i, total_vecs, 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);
@@ -6148,13 +6172,29 @@
 		msix_ent[i].vector = 0;
 	}
 
-	rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC);
+	total_vecs = msix_vecs;
+#ifdef BCM_CNIC
+	total_vecs++;
+#endif
+	rc = -ENOSPC;
+	while (total_vecs >= BNX2_MIN_MSIX_VEC) {
+		rc = pci_enable_msix(bp->pdev, msix_ent, total_vecs);
+		if (rc <= 0)
+			break;
+		if (rc > 0)
+			total_vecs = rc;
+	}
+
 	if (rc != 0)
 		return;
 
+	msix_vecs = total_vecs;
+#ifdef BCM_CNIC
+	msix_vecs--;
+#endif
 	bp->irq_nvecs = msix_vecs;
 	bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
-	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
+	for (i = 0; i < total_vecs; i++) {
 		bp->irq_tbl[i].vector = msix_ent[i].vector;
 		snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
 		bp->irq_tbl[i].handler = bnx2_msi_1shot;
@@ -6172,7 +6212,7 @@
 	bp->irq_nvecs = 1;
 	bp->irq_tbl[0].vector = bp->pdev->irq;
 
-	if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi && cpus > 1)
+	if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
 		bnx2_enable_msix(bp, msix_vecs);
 
 	if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
@@ -6296,9 +6336,14 @@
 bnx2_dump_state(struct bnx2 *bp)
 {
 	struct net_device *dev = bp->dev;
-	u32 mcp_p0, mcp_p1;
+	u32 mcp_p0, mcp_p1, val1, val2;
 
-	netdev_err(dev, "DEBUG: intr_sem[%x]\n", atomic_read(&bp->intr_sem));
+	pci_read_config_dword(bp->pdev, PCI_COMMAND, &val1);
+	netdev_err(dev, "DEBUG: intr_sem[%x] PCI_CMD[%08x]\n",
+		   atomic_read(&bp->intr_sem), val1);
+	pci_read_config_dword(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &val1);
+	pci_read_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, &val2);
+	netdev_err(dev, "DEBUG: PCI_PM[%08x] PCI_MISC_CFG[%08x]\n", val1, val2);
 	netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] EMAC_RX_STATUS[%08x]\n",
 		   REG_RD(bp, BNX2_EMAC_TX_STATUS),
 		   REG_RD(bp, BNX2_EMAC_RX_STATUS));
@@ -6434,8 +6479,8 @@
 	} else
 		mss = 0;
 
-	mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
-	if (pci_dma_mapping_error(bp->pdev, mapping)) {
+	mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
+	if (dma_mapping_error(&bp->pdev->dev, mapping)) {
 		dev_kfree_skb(skb);
 		return NETDEV_TX_OK;
 	}
@@ -6463,9 +6508,9 @@
 		txbd = &txr->tx_desc_ring[ring_prod];
 
 		len = frag->size;
-		mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
-			len, PCI_DMA_TODEVICE);
-		if (pci_dma_mapping_error(bp->pdev, mapping))
+		mapping = dma_map_page(&bp->pdev->dev, frag->page, frag->page_offset,
+				       len, PCI_DMA_TODEVICE);
+		if (dma_mapping_error(&bp->pdev->dev, mapping))
 			goto dma_error;
 		dma_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
 				   mapping);
@@ -6490,6 +6535,13 @@
 
 	if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
 		netif_tx_stop_queue(txq);
+
+		/* netif_tx_stop_queue() must be done before checking
+		 * tx index in bnx2_tx_avail() below, because in
+		 * bnx2_tx_int(), we update tx index before checking for
+		 * netif_tx_queue_stopped().
+		 */
+		smp_mb();
 		if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
 			netif_tx_wake_queue(txq);
 	}
@@ -6504,7 +6556,7 @@
 	ring_prod = TX_RING_IDX(prod);
 	tx_buf = &txr->tx_buf_ring[ring_prod];
 	tx_buf->skb = NULL;
-	pci_unmap_single(bp->pdev, dma_unmap_addr(tx_buf, mapping),
+	dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
 			 skb_headlen(skb), PCI_DMA_TODEVICE);
 
 	/* unmap remaining mapped pages */
@@ -6512,7 +6564,7 @@
 		prod = NEXT_TX_BD(prod);
 		ring_prod = TX_RING_IDX(prod);
 		tx_buf = &txr->tx_buf_ring[ring_prod];
-		pci_unmap_page(bp->pdev, dma_unmap_addr(tx_buf, mapping),
+		dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
 			       skb_shinfo(skb)->frags[i].size,
 			       PCI_DMA_TODEVICE);
 	}
@@ -6567,36 +6619,25 @@
 		temp_stats[i] += hw_stats[i];
 }
 
-#define GET_64BIT_NET_STATS64(ctr)				\
-	(unsigned long) ((unsigned long) (ctr##_hi) << 32) +	\
-	(unsigned long) (ctr##_lo)
+#define GET_64BIT_NET_STATS64(ctr)		\
+	(((u64) (ctr##_hi) << 32) + (u64) (ctr##_lo))
 
-#define GET_64BIT_NET_STATS32(ctr)				\
-	(ctr##_lo)
-
-#if (BITS_PER_LONG == 64)
 #define GET_64BIT_NET_STATS(ctr)				\
 	GET_64BIT_NET_STATS64(bp->stats_blk->ctr) +		\
 	GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
-#else
-#define GET_64BIT_NET_STATS(ctr)				\
-	GET_64BIT_NET_STATS32(bp->stats_blk->ctr) +		\
-	GET_64BIT_NET_STATS32(bp->temp_stats_blk->ctr)
-#endif
 
 #define GET_32BIT_NET_STATS(ctr)				\
 	(unsigned long) (bp->stats_blk->ctr +			\
 			 bp->temp_stats_blk->ctr)
 
-static struct net_device_stats *
-bnx2_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *
+bnx2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
 {
 	struct bnx2 *bp = netdev_priv(dev);
-	struct net_device_stats *net_stats = &dev->stats;
 
-	if (bp->stats_blk == NULL) {
+	if (bp->stats_blk == NULL)
 		return net_stats;
-	}
+
 	net_stats->rx_packets =
 		GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
 		GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
@@ -6614,7 +6655,7 @@
 		GET_64BIT_NET_STATS(stat_IfHCOutOctets);
 
 	net_stats->multicast =
-		GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts);
+		GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts);
 
 	net_stats->collisions =
 		GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
@@ -7545,6 +7586,12 @@
 		return (ethtool_op_set_tx_csum(dev, data));
 }
 
+static int
+bnx2_set_flags(struct net_device *dev, u32 data)
+{
+	return ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH);
+}
+
 static const struct ethtool_ops bnx2_ethtool_ops = {
 	.get_settings		= bnx2_get_settings,
 	.set_settings		= bnx2_set_settings,
@@ -7574,6 +7621,8 @@
 	.phys_id		= bnx2_phys_id,
 	.get_ethtool_stats	= bnx2_get_ethtool_stats,
 	.get_sset_count		= bnx2_get_sset_count,
+	.set_flags		= bnx2_set_flags,
+	.get_flags		= ethtool_op_get_flags,
 };
 
 /* Called with rtnl_lock */
@@ -8259,7 +8308,7 @@
 	.ndo_open		= bnx2_open,
 	.ndo_start_xmit		= bnx2_start_xmit,
 	.ndo_stop		= bnx2_close,
-	.ndo_get_stats		= bnx2_get_stats,
+	.ndo_get_stats64	= bnx2_get_stats64,
 	.ndo_set_rx_mode	= bnx2_set_rx_mode,
 	.ndo_do_ioctl		= bnx2_ioctl,
 	.ndo_validate_addr	= eth_validate_addr,
@@ -8320,7 +8369,8 @@
 	memcpy(dev->dev_addr, bp->mac_addr, 6);
 	memcpy(dev->perm_addr, bp->mac_addr, 6);
 
-	dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO;
+	dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO |
+			 NETIF_F_RXHASH;
 	vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG);
 	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
 		dev->features |= NETIF_F_IPV6_CSUM;
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index ddaa3fc..2104c10 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -295,6 +295,9 @@
 		#define L2_FHDR_ERRORS_TCP_XSUM		(1<<28)
 		#define L2_FHDR_ERRORS_UDP_XSUM		(1<<31)
 
+		#define L2_FHDR_STATUS_USE_RXHASH	\
+			(L2_FHDR_STATUS_TCP_SEGMENT | L2_FHDR_STATUS_RSS_HASH)
+
 	u32 l2_fhdr_hash;
 #if defined(__BIG_ENDIAN)
 	u16 l2_fhdr_pkt_len;
@@ -6634,9 +6637,12 @@
 
 #define BNX2_MAX_MSIX_HW_VEC	9
 #define BNX2_MAX_MSIX_VEC	9
-#define BNX2_BASE_VEC		0
-#define BNX2_TX_VEC		1
-#define BNX2_TX_INT_NUM	(BNX2_TX_VEC << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT)
+#ifdef BCM_CNIC
+#define BNX2_MIN_MSIX_VEC	2
+#else
+#define BNX2_MIN_MSIX_VEC	1
+#endif
+
 
 struct bnx2_irq {
 	irq_handler_t	handler;
diff --git a/drivers/net/bnx2x/Makefile b/drivers/net/bnx2x/Makefile
new file mode 100644
index 0000000..084afce
--- /dev/null
+++ b/drivers/net/bnx2x/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for Broadcom 10-Gigabit ethernet driver
+#
+
+obj-$(CONFIG_BNX2X) += bnx2x.o
+
+bnx2x-objs := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x/bnx2x.h
similarity index 84%
rename from drivers/net/bnx2x.h
rename to drivers/net/bnx2x/bnx2x.h
index bb0872a..53af9c9 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x/bnx2x.h
@@ -20,6 +20,10 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
+#define DRV_MODULE_VERSION      "1.52.53-3"
+#define DRV_MODULE_RELDATE      "2010/18/04"
+#define BNX2X_BC_VER            0x040200
+
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define BCM_VLAN			1
 #endif
@@ -32,7 +36,7 @@
 
 #if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
 #define BCM_CNIC 1
-#include "cnic_if.h"
+#include "../cnic_if.h"
 #endif
 
 
@@ -45,10 +49,12 @@
 #endif
 
 #include <linux/mdio.h>
+#include <linux/pci.h>
 #include "bnx2x_reg.h"
 #include "bnx2x_fw_defs.h"
 #include "bnx2x_hsi.h"
 #include "bnx2x_link.h"
+#include "bnx2x_stats.h"
 
 /* error/debug prints */
 
@@ -106,6 +112,7 @@
 		dev_info(&bp->pdev->dev, __fmt, ##__args);	 \
 } while (0)
 
+void bnx2x_panic_dump(struct bnx2x *bp);
 
 #ifdef BNX2X_STOP_ON_ERROR
 #define bnx2x_panic() do { \
@@ -248,43 +255,6 @@
 #define NEXT_SGE_MASK_ELEM(el)		(((el) + 1) & RX_SGE_MASK_LEN_MASK)
 
 
-struct bnx2x_eth_q_stats {
-	u32 total_bytes_received_hi;
-	u32 total_bytes_received_lo;
-	u32 total_bytes_transmitted_hi;
-	u32 total_bytes_transmitted_lo;
-	u32 total_unicast_packets_received_hi;
-	u32 total_unicast_packets_received_lo;
-	u32 total_multicast_packets_received_hi;
-	u32 total_multicast_packets_received_lo;
-	u32 total_broadcast_packets_received_hi;
-	u32 total_broadcast_packets_received_lo;
-	u32 total_unicast_packets_transmitted_hi;
-	u32 total_unicast_packets_transmitted_lo;
-	u32 total_multicast_packets_transmitted_hi;
-	u32 total_multicast_packets_transmitted_lo;
-	u32 total_broadcast_packets_transmitted_hi;
-	u32 total_broadcast_packets_transmitted_lo;
-	u32 valid_bytes_received_hi;
-	u32 valid_bytes_received_lo;
-
-	u32 error_bytes_received_hi;
-	u32 error_bytes_received_lo;
-	u32 etherstatsoverrsizepkts_hi;
-	u32 etherstatsoverrsizepkts_lo;
-	u32 no_buff_discard_hi;
-	u32 no_buff_discard_lo;
-
-	u32 driver_xoff;
-	u32 rx_err_discard_pkt;
-	u32 rx_skb_alloc_failed;
-	u32 hw_csum_err;
-};
-
-#define BNX2X_NUM_Q_STATS		13
-#define Q_STATS_OFFSET32(stat_name) \
-			(offsetof(struct bnx2x_eth_q_stats, stat_name) / 4)
-
 struct bnx2x_fastpath {
 
 	struct napi_struct	napi;
@@ -593,27 +563,6 @@
 
 /* port */
 
-struct nig_stats {
-	u32 brb_discard;
-	u32 brb_packet;
-	u32 brb_truncate;
-	u32 flow_ctrl_discard;
-	u32 flow_ctrl_octets;
-	u32 flow_ctrl_packet;
-	u32 mng_discard;
-	u32 mng_octet_inp;
-	u32 mng_octet_out;
-	u32 mng_packet_inp;
-	u32 mng_packet_out;
-	u32 pbf_octets;
-	u32 pbf_packet;
-	u32 safc_inp;
-	u32 egress_mac_pkt0_lo;
-	u32 egress_mac_pkt0_hi;
-	u32 egress_mac_pkt1_lo;
-	u32 egress_mac_pkt1_hi;
-};
-
 struct bnx2x_port {
 	u32			pmf;
 
@@ -641,156 +590,6 @@
 /* end of port */
 
 
-enum bnx2x_stats_event {
-	STATS_EVENT_PMF = 0,
-	STATS_EVENT_LINK_UP,
-	STATS_EVENT_UPDATE,
-	STATS_EVENT_STOP,
-	STATS_EVENT_MAX
-};
-
-enum bnx2x_stats_state {
-	STATS_STATE_DISABLED = 0,
-	STATS_STATE_ENABLED,
-	STATS_STATE_MAX
-};
-
-struct bnx2x_eth_stats {
-	u32 total_bytes_received_hi;
-	u32 total_bytes_received_lo;
-	u32 total_bytes_transmitted_hi;
-	u32 total_bytes_transmitted_lo;
-	u32 total_unicast_packets_received_hi;
-	u32 total_unicast_packets_received_lo;
-	u32 total_multicast_packets_received_hi;
-	u32 total_multicast_packets_received_lo;
-	u32 total_broadcast_packets_received_hi;
-	u32 total_broadcast_packets_received_lo;
-	u32 total_unicast_packets_transmitted_hi;
-	u32 total_unicast_packets_transmitted_lo;
-	u32 total_multicast_packets_transmitted_hi;
-	u32 total_multicast_packets_transmitted_lo;
-	u32 total_broadcast_packets_transmitted_hi;
-	u32 total_broadcast_packets_transmitted_lo;
-	u32 valid_bytes_received_hi;
-	u32 valid_bytes_received_lo;
-
-	u32 error_bytes_received_hi;
-	u32 error_bytes_received_lo;
-	u32 etherstatsoverrsizepkts_hi;
-	u32 etherstatsoverrsizepkts_lo;
-	u32 no_buff_discard_hi;
-	u32 no_buff_discard_lo;
-
-	u32 rx_stat_ifhcinbadoctets_hi;
-	u32 rx_stat_ifhcinbadoctets_lo;
-	u32 tx_stat_ifhcoutbadoctets_hi;
-	u32 tx_stat_ifhcoutbadoctets_lo;
-	u32 rx_stat_dot3statsfcserrors_hi;
-	u32 rx_stat_dot3statsfcserrors_lo;
-	u32 rx_stat_dot3statsalignmenterrors_hi;
-	u32 rx_stat_dot3statsalignmenterrors_lo;
-	u32 rx_stat_dot3statscarriersenseerrors_hi;
-	u32 rx_stat_dot3statscarriersenseerrors_lo;
-	u32 rx_stat_falsecarriererrors_hi;
-	u32 rx_stat_falsecarriererrors_lo;
-	u32 rx_stat_etherstatsundersizepkts_hi;
-	u32 rx_stat_etherstatsundersizepkts_lo;
-	u32 rx_stat_dot3statsframestoolong_hi;
-	u32 rx_stat_dot3statsframestoolong_lo;
-	u32 rx_stat_etherstatsfragments_hi;
-	u32 rx_stat_etherstatsfragments_lo;
-	u32 rx_stat_etherstatsjabbers_hi;
-	u32 rx_stat_etherstatsjabbers_lo;
-	u32 rx_stat_maccontrolframesreceived_hi;
-	u32 rx_stat_maccontrolframesreceived_lo;
-	u32 rx_stat_bmac_xpf_hi;
-	u32 rx_stat_bmac_xpf_lo;
-	u32 rx_stat_bmac_xcf_hi;
-	u32 rx_stat_bmac_xcf_lo;
-	u32 rx_stat_xoffstateentered_hi;
-	u32 rx_stat_xoffstateentered_lo;
-	u32 rx_stat_xonpauseframesreceived_hi;
-	u32 rx_stat_xonpauseframesreceived_lo;
-	u32 rx_stat_xoffpauseframesreceived_hi;
-	u32 rx_stat_xoffpauseframesreceived_lo;
-	u32 tx_stat_outxonsent_hi;
-	u32 tx_stat_outxonsent_lo;
-	u32 tx_stat_outxoffsent_hi;
-	u32 tx_stat_outxoffsent_lo;
-	u32 tx_stat_flowcontroldone_hi;
-	u32 tx_stat_flowcontroldone_lo;
-	u32 tx_stat_etherstatscollisions_hi;
-	u32 tx_stat_etherstatscollisions_lo;
-	u32 tx_stat_dot3statssinglecollisionframes_hi;
-	u32 tx_stat_dot3statssinglecollisionframes_lo;
-	u32 tx_stat_dot3statsmultiplecollisionframes_hi;
-	u32 tx_stat_dot3statsmultiplecollisionframes_lo;
-	u32 tx_stat_dot3statsdeferredtransmissions_hi;
-	u32 tx_stat_dot3statsdeferredtransmissions_lo;
-	u32 tx_stat_dot3statsexcessivecollisions_hi;
-	u32 tx_stat_dot3statsexcessivecollisions_lo;
-	u32 tx_stat_dot3statslatecollisions_hi;
-	u32 tx_stat_dot3statslatecollisions_lo;
-	u32 tx_stat_etherstatspkts64octets_hi;
-	u32 tx_stat_etherstatspkts64octets_lo;
-	u32 tx_stat_etherstatspkts65octetsto127octets_hi;
-	u32 tx_stat_etherstatspkts65octetsto127octets_lo;
-	u32 tx_stat_etherstatspkts128octetsto255octets_hi;
-	u32 tx_stat_etherstatspkts128octetsto255octets_lo;
-	u32 tx_stat_etherstatspkts256octetsto511octets_hi;
-	u32 tx_stat_etherstatspkts256octetsto511octets_lo;
-	u32 tx_stat_etherstatspkts512octetsto1023octets_hi;
-	u32 tx_stat_etherstatspkts512octetsto1023octets_lo;
-	u32 tx_stat_etherstatspkts1024octetsto1522octets_hi;
-	u32 tx_stat_etherstatspkts1024octetsto1522octets_lo;
-	u32 tx_stat_etherstatspktsover1522octets_hi;
-	u32 tx_stat_etherstatspktsover1522octets_lo;
-	u32 tx_stat_bmac_2047_hi;
-	u32 tx_stat_bmac_2047_lo;
-	u32 tx_stat_bmac_4095_hi;
-	u32 tx_stat_bmac_4095_lo;
-	u32 tx_stat_bmac_9216_hi;
-	u32 tx_stat_bmac_9216_lo;
-	u32 tx_stat_bmac_16383_hi;
-	u32 tx_stat_bmac_16383_lo;
-	u32 tx_stat_dot3statsinternalmactransmiterrors_hi;
-	u32 tx_stat_dot3statsinternalmactransmiterrors_lo;
-	u32 tx_stat_bmac_ufl_hi;
-	u32 tx_stat_bmac_ufl_lo;
-
-	u32 pause_frames_received_hi;
-	u32 pause_frames_received_lo;
-	u32 pause_frames_sent_hi;
-	u32 pause_frames_sent_lo;
-
-	u32 etherstatspkts1024octetsto1522octets_hi;
-	u32 etherstatspkts1024octetsto1522octets_lo;
-	u32 etherstatspktsover1522octets_hi;
-	u32 etherstatspktsover1522octets_lo;
-
-	u32 brb_drop_hi;
-	u32 brb_drop_lo;
-	u32 brb_truncate_hi;
-	u32 brb_truncate_lo;
-
-	u32 mac_filter_discard;
-	u32 xxoverflow_discard;
-	u32 brb_truncate_discard;
-	u32 mac_discard;
-
-	u32 driver_xoff;
-	u32 rx_err_discard_pkt;
-	u32 rx_skb_alloc_failed;
-	u32 hw_csum_err;
-
-	u32 nig_timer_max;
-};
-
-#define BNX2X_NUM_STATS			43
-#define STATS_OFFSET32(stat_name) \
-			(offsetof(struct bnx2x_eth_stats, stat_name) / 4)
-
 
 #ifdef BCM_CNIC
 #define MAX_CONTEXT			15
@@ -1006,6 +805,8 @@
 
 	int			multi_mode;
 	int			num_queues;
+	int			disable_tpa;
+	int			int_mode;
 
 	u32			rx_mode;
 #define BNX2X_RX_MODE_NONE		0
@@ -1134,6 +935,10 @@
 void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val);
 void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
 			       u32 addr, u32 len);
+void bnx2x_calc_fc_adv(struct bnx2x *bp);
+int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
+		  u32 data_hi, u32 data_lo, int common);
+void bnx2x_update_coalesce(struct bnx2x *bp);
 
 static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 			   int wait)
@@ -1375,6 +1180,18 @@
 #define BNX2X_VPD_LEN			128
 #define VENDOR_ID_LEN			4
 
+#ifdef BNX2X_MAIN
+#define BNX2X_EXTERN
+#else
+#define BNX2X_EXTERN extern
+#endif
+
+BNX2X_EXTERN int load_count[3]; /* 0-common, 1-port0, 2-port1 */
+
 /* MISC_REG_RESET_REG - this is here for the hsi to work don't touch */
 
+extern void bnx2x_set_ethtool_ops(struct net_device *netdev);
+
+void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx);
+
 #endif /* bnx2x.h */
diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c
new file mode 100644
index 0000000..02bf710
--- /dev/null
+++ b/drivers/net/bnx2x/bnx2x_cmn.c
@@ -0,0 +1,2252 @@
+/* bnx2x_cmn.c: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007-2010 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
+ * Based on code from Michael Chan's bnx2 driver
+ * UDP CSUM errata workaround by Arik Gendelman
+ * Slowpath and fastpath rework by Vladislav Zolotarov
+ * Statistics and Link management by Yitchak Gertner
+ *
+ */
+
+
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ip6_checksum.h>
+#include "bnx2x_cmn.h"
+
+#ifdef BCM_VLAN
+#include <linux/if_vlan.h>
+#endif
+
+static int bnx2x_poll(struct napi_struct *napi, int budget);
+
+/* free skb in the packet ring at pos idx
+ * return idx of last bd freed
+ */
+static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+			     u16 idx)
+{
+	struct sw_tx_bd *tx_buf = &fp->tx_buf_ring[idx];
+	struct eth_tx_start_bd *tx_start_bd;
+	struct eth_tx_bd *tx_data_bd;
+	struct sk_buff *skb = tx_buf->skb;
+	u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons;
+	int nbd;
+
+	/* prefetch skb end pointer to speedup dev_kfree_skb() */
+	prefetch(&skb->end);
+
+	DP(BNX2X_MSG_OFF, "pkt_idx %d  buff @(%p)->skb %p\n",
+	   idx, tx_buf, skb);
+
+	/* unmap first bd */
+	DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx);
+	tx_start_bd = &fp->tx_desc_ring[bd_idx].start_bd;
+	dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd),
+			 BD_UNMAP_LEN(tx_start_bd), PCI_DMA_TODEVICE);
+
+	nbd = le16_to_cpu(tx_start_bd->nbd) - 1;
+#ifdef BNX2X_STOP_ON_ERROR
+	if ((nbd - 1) > (MAX_SKB_FRAGS + 2)) {
+		BNX2X_ERR("BAD nbd!\n");
+		bnx2x_panic();
+	}
+#endif
+	new_cons = nbd + tx_buf->first_bd;
+
+	/* Get the next bd */
+	bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+
+	/* Skip a parse bd... */
+	--nbd;
+	bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+
+	/* ...and the TSO split header bd since they have no mapping */
+	if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) {
+		--nbd;
+		bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+	}
+
+	/* now free frags */
+	while (nbd > 0) {
+
+		DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx);
+		tx_data_bd = &fp->tx_desc_ring[bd_idx].reg_bd;
+		dma_unmap_page(&bp->pdev->dev, BD_UNMAP_ADDR(tx_data_bd),
+			       BD_UNMAP_LEN(tx_data_bd), DMA_TO_DEVICE);
+		if (--nbd)
+			bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+	}
+
+	/* release skb */
+	WARN_ON(!skb);
+	dev_kfree_skb(skb);
+	tx_buf->first_bd = 0;
+	tx_buf->skb = NULL;
+
+	return new_cons;
+}
+
+int bnx2x_tx_int(struct bnx2x_fastpath *fp)
+{
+	struct bnx2x *bp = fp->bp;
+	struct netdev_queue *txq;
+	u16 hw_cons, sw_cons, bd_cons = fp->tx_bd_cons;
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return -1;
+#endif
+
+	txq = netdev_get_tx_queue(bp->dev, fp->index);
+	hw_cons = le16_to_cpu(*fp->tx_cons_sb);
+	sw_cons = fp->tx_pkt_cons;
+
+	while (sw_cons != hw_cons) {
+		u16 pkt_cons;
+
+		pkt_cons = TX_BD(sw_cons);
+
+		/* prefetch(bp->tx_buf_ring[pkt_cons].skb); */
+
+		DP(NETIF_MSG_TX_DONE, "hw_cons %u  sw_cons %u  pkt_cons %u\n",
+		   hw_cons, sw_cons, pkt_cons);
+
+/*		if (NEXT_TX_IDX(sw_cons) != hw_cons) {
+			rmb();
+			prefetch(fp->tx_buf_ring[NEXT_TX_IDX(sw_cons)].skb);
+		}
+*/
+		bd_cons = bnx2x_free_tx_pkt(bp, fp, pkt_cons);
+		sw_cons++;
+	}
+
+	fp->tx_pkt_cons = sw_cons;
+	fp->tx_bd_cons = bd_cons;
+
+	/* Need to make the tx_bd_cons update visible to start_xmit()
+	 * before checking for netif_tx_queue_stopped().  Without the
+	 * memory barrier, there is a small possibility that
+	 * start_xmit() will miss it and cause the queue to be stopped
+	 * forever.
+	 */
+	smp_mb();
+
+	/* TBD need a thresh? */
+	if (unlikely(netif_tx_queue_stopped(txq))) {
+		/* Taking tx_lock() is needed to prevent reenabling the queue
+		 * while it's empty. This could have happen if rx_action() gets
+		 * suspended in bnx2x_tx_int() after the condition before
+		 * netif_tx_wake_queue(), while tx_action (bnx2x_start_xmit()):
+		 *
+		 * stops the queue->sees fresh tx_bd_cons->releases the queue->
+		 * sends some packets consuming the whole queue again->
+		 * stops the queue
+		 */
+
+		__netif_tx_lock(txq, smp_processor_id());
+
+		if ((netif_tx_queue_stopped(txq)) &&
+		    (bp->state == BNX2X_STATE_OPEN) &&
+		    (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3))
+			netif_tx_wake_queue(txq);
+
+		__netif_tx_unlock(txq);
+	}
+	return 0;
+}
+
+static inline void bnx2x_update_last_max_sge(struct bnx2x_fastpath *fp,
+					     u16 idx)
+{
+	u16 last_max = fp->last_max_sge;
+
+	if (SUB_S16(idx, last_max) > 0)
+		fp->last_max_sge = idx;
+}
+
+static void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp,
+				  struct eth_fast_path_rx_cqe *fp_cqe)
+{
+	struct bnx2x *bp = fp->bp;
+	u16 sge_len = SGE_PAGE_ALIGN(le16_to_cpu(fp_cqe->pkt_len) -
+				     le16_to_cpu(fp_cqe->len_on_bd)) >>
+		      SGE_PAGE_SHIFT;
+	u16 last_max, last_elem, first_elem;
+	u16 delta = 0;
+	u16 i;
+
+	if (!sge_len)
+		return;
+
+	/* First mark all used pages */
+	for (i = 0; i < sge_len; i++)
+		SGE_MASK_CLEAR_BIT(fp, RX_SGE(le16_to_cpu(fp_cqe->sgl[i])));
+
+	DP(NETIF_MSG_RX_STATUS, "fp_cqe->sgl[%d] = %d\n",
+	   sge_len - 1, le16_to_cpu(fp_cqe->sgl[sge_len - 1]));
+
+	/* Here we assume that the last SGE index is the biggest */
+	prefetch((void *)(fp->sge_mask));
+	bnx2x_update_last_max_sge(fp, le16_to_cpu(fp_cqe->sgl[sge_len - 1]));
+
+	last_max = RX_SGE(fp->last_max_sge);
+	last_elem = last_max >> RX_SGE_MASK_ELEM_SHIFT;
+	first_elem = RX_SGE(fp->rx_sge_prod) >> RX_SGE_MASK_ELEM_SHIFT;
+
+	/* If ring is not full */
+	if (last_elem + 1 != first_elem)
+		last_elem++;
+
+	/* Now update the prod */
+	for (i = first_elem; i != last_elem; i = NEXT_SGE_MASK_ELEM(i)) {
+		if (likely(fp->sge_mask[i]))
+			break;
+
+		fp->sge_mask[i] = RX_SGE_MASK_ELEM_ONE_MASK;
+		delta += RX_SGE_MASK_ELEM_SZ;
+	}
+
+	if (delta > 0) {
+		fp->rx_sge_prod += delta;
+		/* clear page-end entries */
+		bnx2x_clear_sge_mask_next_elems(fp);
+	}
+
+	DP(NETIF_MSG_RX_STATUS,
+	   "fp->last_max_sge = %d  fp->rx_sge_prod = %d\n",
+	   fp->last_max_sge, fp->rx_sge_prod);
+}
+
+static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
+			    struct sk_buff *skb, u16 cons, u16 prod)
+{
+	struct bnx2x *bp = fp->bp;
+	struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons];
+	struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod];
+	struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod];
+	dma_addr_t mapping;
+
+	/* move empty skb from pool to prod and map it */
+	prod_rx_buf->skb = fp->tpa_pool[queue].skb;
+	mapping = dma_map_single(&bp->pdev->dev, fp->tpa_pool[queue].skb->data,
+				 bp->rx_buf_size, DMA_FROM_DEVICE);
+	dma_unmap_addr_set(prod_rx_buf, mapping, mapping);
+
+	/* move partial skb from cons to pool (don't unmap yet) */
+	fp->tpa_pool[queue] = *cons_rx_buf;
+
+	/* mark bin state as start - print error if current state != stop */
+	if (fp->tpa_state[queue] != BNX2X_TPA_STOP)
+		BNX2X_ERR("start of bin not in stop [%d]\n", queue);
+
+	fp->tpa_state[queue] = BNX2X_TPA_START;
+
+	/* point prod_bd to new skb */
+	prod_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+	prod_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+
+#ifdef BNX2X_STOP_ON_ERROR
+	fp->tpa_queue_used |= (1 << queue);
+#ifdef _ASM_GENERIC_INT_L64_H
+	DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%lx\n",
+#else
+	DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%llx\n",
+#endif
+	   fp->tpa_queue_used);
+#endif
+}
+
+static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+			       struct sk_buff *skb,
+			       struct eth_fast_path_rx_cqe *fp_cqe,
+			       u16 cqe_idx)
+{
+	struct sw_rx_page *rx_pg, old_rx_pg;
+	u16 len_on_bd = le16_to_cpu(fp_cqe->len_on_bd);
+	u32 i, frag_len, frag_size, pages;
+	int err;
+	int j;
+
+	frag_size = le16_to_cpu(fp_cqe->pkt_len) - len_on_bd;
+	pages = SGE_PAGE_ALIGN(frag_size) >> SGE_PAGE_SHIFT;
+
+	/* This is needed in order to enable forwarding support */
+	if (frag_size)
+		skb_shinfo(skb)->gso_size = min((u32)SGE_PAGE_SIZE,
+					       max(frag_size, (u32)len_on_bd));
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (pages > min_t(u32, 8, MAX_SKB_FRAGS)*SGE_PAGE_SIZE*PAGES_PER_SGE) {
+		BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n",
+			  pages, cqe_idx);
+		BNX2X_ERR("fp_cqe->pkt_len = %d  fp_cqe->len_on_bd = %d\n",
+			  fp_cqe->pkt_len, len_on_bd);
+		bnx2x_panic();
+		return -EINVAL;
+	}
+#endif
+
+	/* Run through the SGL and compose the fragmented skb */
+	for (i = 0, j = 0; i < pages; i += PAGES_PER_SGE, j++) {
+		u16 sge_idx = RX_SGE(le16_to_cpu(fp_cqe->sgl[j]));
+
+		/* FW gives the indices of the SGE as if the ring is an array
+		   (meaning that "next" element will consume 2 indices) */
+		frag_len = min(frag_size, (u32)(SGE_PAGE_SIZE*PAGES_PER_SGE));
+		rx_pg = &fp->rx_page_ring[sge_idx];
+		old_rx_pg = *rx_pg;
+
+		/* If we fail to allocate a substitute page, we simply stop
+		   where we are and drop the whole packet */
+		err = bnx2x_alloc_rx_sge(bp, fp, sge_idx);
+		if (unlikely(err)) {
+			fp->eth_q_stats.rx_skb_alloc_failed++;
+			return err;
+		}
+
+		/* Unmap the page as we r going to pass it to the stack */
+		dma_unmap_page(&bp->pdev->dev,
+			       dma_unmap_addr(&old_rx_pg, mapping),
+			       SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
+
+		/* Add one frag and update the appropriate fields in the skb */
+		skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len);
+
+		skb->data_len += frag_len;
+		skb->truesize += frag_len;
+		skb->len += frag_len;
+
+		frag_size -= frag_len;
+	}
+
+	return 0;
+}
+
+static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+			   u16 queue, int pad, int len, union eth_rx_cqe *cqe,
+			   u16 cqe_idx)
+{
+	struct sw_rx_bd *rx_buf = &fp->tpa_pool[queue];
+	struct sk_buff *skb = rx_buf->skb;
+	/* alloc new skb */
+	struct sk_buff *new_skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
+
+	/* Unmap skb in the pool anyway, as we are going to change
+	   pool entry status to BNX2X_TPA_STOP even if new skb allocation
+	   fails. */
+	dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping),
+			 bp->rx_buf_size, DMA_FROM_DEVICE);
+
+	if (likely(new_skb)) {
+		/* fix ip xsum and give it to the stack */
+		/* (no need to map the new skb) */
+#ifdef BCM_VLAN
+		int is_vlan_cqe =
+			(le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
+			 PARSING_FLAGS_VLAN);
+		int is_not_hwaccel_vlan_cqe =
+			(is_vlan_cqe && (!(bp->flags & HW_VLAN_RX_FLAG)));
+#endif
+
+		prefetch(skb);
+		prefetch(((char *)(skb)) + 128);
+
+#ifdef BNX2X_STOP_ON_ERROR
+		if (pad + len > bp->rx_buf_size) {
+			BNX2X_ERR("skb_put is about to fail...  "
+				  "pad %d  len %d  rx_buf_size %d\n",
+				  pad, len, bp->rx_buf_size);
+			bnx2x_panic();
+			return;
+		}
+#endif
+
+		skb_reserve(skb, pad);
+		skb_put(skb, len);
+
+		skb->protocol = eth_type_trans(skb, bp->dev);
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+		{
+			struct iphdr *iph;
+
+			iph = (struct iphdr *)skb->data;
+#ifdef BCM_VLAN
+			/* If there is no Rx VLAN offloading -
+			   take VLAN tag into an account */
+			if (unlikely(is_not_hwaccel_vlan_cqe))
+				iph = (struct iphdr *)((u8 *)iph + VLAN_HLEN);
+#endif
+			iph->check = 0;
+			iph->check = ip_fast_csum((u8 *)iph, iph->ihl);
+		}
+
+		if (!bnx2x_fill_frag_skb(bp, fp, skb,
+					 &cqe->fast_path_cqe, cqe_idx)) {
+#ifdef BCM_VLAN
+			if ((bp->vlgrp != NULL) && is_vlan_cqe &&
+			    (!is_not_hwaccel_vlan_cqe))
+				vlan_gro_receive(&fp->napi, bp->vlgrp,
+						 le16_to_cpu(cqe->fast_path_cqe.
+							     vlan_tag), skb);
+			else
+#endif
+				napi_gro_receive(&fp->napi, skb);
+		} else {
+			DP(NETIF_MSG_RX_STATUS, "Failed to allocate new pages"
+			   " - dropping packet!\n");
+			dev_kfree_skb(skb);
+		}
+
+
+		/* put new skb in bin */
+		fp->tpa_pool[queue].skb = new_skb;
+
+	} else {
+		/* else drop the packet and keep the buffer in the bin */
+		DP(NETIF_MSG_RX_STATUS,
+		   "Failed to allocate new skb - dropping packet!\n");
+		fp->eth_q_stats.rx_skb_alloc_failed++;
+	}
+
+	fp->tpa_state[queue] = BNX2X_TPA_STOP;
+}
+
+/* Set Toeplitz hash value in the skb using the value from the
+ * CQE (calculated by HW).
+ */
+static inline void bnx2x_set_skb_rxhash(struct bnx2x *bp, union eth_rx_cqe *cqe,
+					struct sk_buff *skb)
+{
+	/* Set Toeplitz hash from CQE */
+	if ((bp->dev->features & NETIF_F_RXHASH) &&
+	    (cqe->fast_path_cqe.status_flags &
+	     ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG))
+		skb->rxhash =
+		le32_to_cpu(cqe->fast_path_cqe.rss_hash_result);
+}
+
+int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
+{
+	struct bnx2x *bp = fp->bp;
+	u16 bd_cons, bd_prod, bd_prod_fw, comp_ring_cons;
+	u16 hw_comp_cons, sw_comp_cons, sw_comp_prod;
+	int rx_pkt = 0;
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return 0;
+#endif
+
+	/* CQ "next element" is of the size of the regular element,
+	   that's why it's ok here */
+	hw_comp_cons = le16_to_cpu(*fp->rx_cons_sb);
+	if ((hw_comp_cons & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
+		hw_comp_cons++;
+
+	bd_cons = fp->rx_bd_cons;
+	bd_prod = fp->rx_bd_prod;
+	bd_prod_fw = bd_prod;
+	sw_comp_cons = fp->rx_comp_cons;
+	sw_comp_prod = fp->rx_comp_prod;
+
+	/* Memory barrier necessary as speculative reads of the rx
+	 * buffer can be ahead of the index in the status block
+	 */
+	rmb();
+
+	DP(NETIF_MSG_RX_STATUS,
+	   "queue[%d]:  hw_comp_cons %u  sw_comp_cons %u\n",
+	   fp->index, hw_comp_cons, sw_comp_cons);
+
+	while (sw_comp_cons != hw_comp_cons) {
+		struct sw_rx_bd *rx_buf = NULL;
+		struct sk_buff *skb;
+		union eth_rx_cqe *cqe;
+		u8 cqe_fp_flags;
+		u16 len, pad;
+
+		comp_ring_cons = RCQ_BD(sw_comp_cons);
+		bd_prod = RX_BD(bd_prod);
+		bd_cons = RX_BD(bd_cons);
+
+		/* Prefetch the page containing the BD descriptor
+		   at producer's index. It will be needed when new skb is
+		   allocated */
+		prefetch((void *)(PAGE_ALIGN((unsigned long)
+					     (&fp->rx_desc_ring[bd_prod])) -
+				  PAGE_SIZE + 1));
+
+		cqe = &fp->rx_comp_ring[comp_ring_cons];
+		cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
+
+		DP(NETIF_MSG_RX_STATUS, "CQE type %x  err %x  status %x"
+		   "  queue %x  vlan %x  len %u\n", CQE_TYPE(cqe_fp_flags),
+		   cqe_fp_flags, cqe->fast_path_cqe.status_flags,
+		   le32_to_cpu(cqe->fast_path_cqe.rss_hash_result),
+		   le16_to_cpu(cqe->fast_path_cqe.vlan_tag),
+		   le16_to_cpu(cqe->fast_path_cqe.pkt_len));
+
+		/* is this a slowpath msg? */
+		if (unlikely(CQE_TYPE(cqe_fp_flags))) {
+			bnx2x_sp_event(fp, cqe);
+			goto next_cqe;
+
+		/* this is an rx packet */
+		} else {
+			rx_buf = &fp->rx_buf_ring[bd_cons];
+			skb = rx_buf->skb;
+			prefetch(skb);
+			len = le16_to_cpu(cqe->fast_path_cqe.pkt_len);
+			pad = cqe->fast_path_cqe.placement_offset;
+
+			/* If CQE is marked both TPA_START and TPA_END
+			   it is a non-TPA CQE */
+			if ((!fp->disable_tpa) &&
+			    (TPA_TYPE(cqe_fp_flags) !=
+					(TPA_TYPE_START | TPA_TYPE_END))) {
+				u16 queue = cqe->fast_path_cqe.queue_index;
+
+				if (TPA_TYPE(cqe_fp_flags) == TPA_TYPE_START) {
+					DP(NETIF_MSG_RX_STATUS,
+					   "calling tpa_start on queue %d\n",
+					   queue);
+
+					bnx2x_tpa_start(fp, queue, skb,
+							bd_cons, bd_prod);
+
+					/* Set Toeplitz hash for an LRO skb */
+					bnx2x_set_skb_rxhash(bp, cqe, skb);
+
+					goto next_rx;
+				}
+
+				if (TPA_TYPE(cqe_fp_flags) == TPA_TYPE_END) {
+					DP(NETIF_MSG_RX_STATUS,
+					   "calling tpa_stop on queue %d\n",
+					   queue);
+
+					if (!BNX2X_RX_SUM_FIX(cqe))
+						BNX2X_ERR("STOP on none TCP "
+							  "data\n");
+
+					/* This is a size of the linear data
+					   on this skb */
+					len = le16_to_cpu(cqe->fast_path_cqe.
+								len_on_bd);
+					bnx2x_tpa_stop(bp, fp, queue, pad,
+						    len, cqe, comp_ring_cons);
+#ifdef BNX2X_STOP_ON_ERROR
+					if (bp->panic)
+						return 0;
+#endif
+
+					bnx2x_update_sge_prod(fp,
+							&cqe->fast_path_cqe);
+					goto next_cqe;
+				}
+			}
+
+			dma_sync_single_for_device(&bp->pdev->dev,
+					dma_unmap_addr(rx_buf, mapping),
+						   pad + RX_COPY_THRESH,
+						   DMA_FROM_DEVICE);
+			prefetch(((char *)(skb)) + 128);
+
+			/* is this an error packet? */
+			if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) {
+				DP(NETIF_MSG_RX_ERR,
+				   "ERROR  flags %x  rx packet %u\n",
+				   cqe_fp_flags, sw_comp_cons);
+				fp->eth_q_stats.rx_err_discard_pkt++;
+				goto reuse_rx;
+			}
+
+			/* Since we don't have a jumbo ring
+			 * copy small packets if mtu > 1500
+			 */
+			if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) &&
+			    (len <= RX_COPY_THRESH)) {
+				struct sk_buff *new_skb;
+
+				new_skb = netdev_alloc_skb(bp->dev,
+							   len + pad);
+				if (new_skb == NULL) {
+					DP(NETIF_MSG_RX_ERR,
+					   "ERROR  packet dropped "
+					   "because of alloc failure\n");
+					fp->eth_q_stats.rx_skb_alloc_failed++;
+					goto reuse_rx;
+				}
+
+				/* aligned copy */
+				skb_copy_from_linear_data_offset(skb, pad,
+						    new_skb->data + pad, len);
+				skb_reserve(new_skb, pad);
+				skb_put(new_skb, len);
+
+				bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod);
+
+				skb = new_skb;
+
+			} else
+			if (likely(bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0)) {
+				dma_unmap_single(&bp->pdev->dev,
+					dma_unmap_addr(rx_buf, mapping),
+						 bp->rx_buf_size,
+						 DMA_FROM_DEVICE);
+				skb_reserve(skb, pad);
+				skb_put(skb, len);
+
+			} else {
+				DP(NETIF_MSG_RX_ERR,
+				   "ERROR  packet dropped because "
+				   "of alloc failure\n");
+				fp->eth_q_stats.rx_skb_alloc_failed++;
+reuse_rx:
+				bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod);
+				goto next_rx;
+			}
+
+			skb->protocol = eth_type_trans(skb, bp->dev);
+
+			/* Set Toeplitz hash for a none-LRO skb */
+			bnx2x_set_skb_rxhash(bp, cqe, skb);
+
+			skb->ip_summed = CHECKSUM_NONE;
+			if (bp->rx_csum) {
+				if (likely(BNX2X_RX_CSUM_OK(cqe)))
+					skb->ip_summed = CHECKSUM_UNNECESSARY;
+				else
+					fp->eth_q_stats.hw_csum_err++;
+			}
+		}
+
+		skb_record_rx_queue(skb, fp->index);
+
+#ifdef BCM_VLAN
+		if ((bp->vlgrp != NULL) && (bp->flags & HW_VLAN_RX_FLAG) &&
+		    (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
+		     PARSING_FLAGS_VLAN))
+			vlan_gro_receive(&fp->napi, bp->vlgrp,
+				le16_to_cpu(cqe->fast_path_cqe.vlan_tag), skb);
+		else
+#endif
+			napi_gro_receive(&fp->napi, skb);
+
+
+next_rx:
+		rx_buf->skb = NULL;
+
+		bd_cons = NEXT_RX_IDX(bd_cons);
+		bd_prod = NEXT_RX_IDX(bd_prod);
+		bd_prod_fw = NEXT_RX_IDX(bd_prod_fw);
+		rx_pkt++;
+next_cqe:
+		sw_comp_prod = NEXT_RCQ_IDX(sw_comp_prod);
+		sw_comp_cons = NEXT_RCQ_IDX(sw_comp_cons);
+
+		if (rx_pkt == budget)
+			break;
+	} /* while */
+
+	fp->rx_bd_cons = bd_cons;
+	fp->rx_bd_prod = bd_prod_fw;
+	fp->rx_comp_cons = sw_comp_cons;
+	fp->rx_comp_prod = sw_comp_prod;
+
+	/* Update producers */
+	bnx2x_update_rx_prod(bp, fp, bd_prod_fw, sw_comp_prod,
+			     fp->rx_sge_prod);
+
+	fp->rx_pkt += rx_pkt;
+	fp->rx_calls++;
+
+	return rx_pkt;
+}
+
+static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
+{
+	struct bnx2x_fastpath *fp = fp_cookie;
+	struct bnx2x *bp = fp->bp;
+
+	/* Return here if interrupt is disabled */
+	if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
+		DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
+		return IRQ_HANDLED;
+	}
+
+	DP(BNX2X_MSG_FP, "got an MSI-X interrupt on IDX:SB [%d:%d]\n",
+	   fp->index, fp->sb_id);
+	bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0);
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return IRQ_HANDLED;
+#endif
+
+	/* Handle Rx and Tx according to MSI-X vector */
+	prefetch(fp->rx_cons_sb);
+	prefetch(fp->tx_cons_sb);
+	prefetch(&fp->status_blk->u_status_block.status_block_index);
+	prefetch(&fp->status_blk->c_status_block.status_block_index);
+	napi_schedule(&bnx2x_fp(bp, fp->index, napi));
+
+	return IRQ_HANDLED;
+}
+
+
+/* HW Lock for shared dual port PHYs */
+void bnx2x_acquire_phy_lock(struct bnx2x *bp)
+{
+	mutex_lock(&bp->port.phy_mutex);
+
+	if (bp->port.need_hw_lock)
+		bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_MDIO);
+}
+
+void bnx2x_release_phy_lock(struct bnx2x *bp)
+{
+	if (bp->port.need_hw_lock)
+		bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_MDIO);
+
+	mutex_unlock(&bp->port.phy_mutex);
+}
+
+void bnx2x_link_report(struct bnx2x *bp)
+{
+	if (bp->flags & MF_FUNC_DIS) {
+		netif_carrier_off(bp->dev);
+		netdev_err(bp->dev, "NIC Link is Down\n");
+		return;
+	}
+
+	if (bp->link_vars.link_up) {
+		u16 line_speed;
+
+		if (bp->state == BNX2X_STATE_OPEN)
+			netif_carrier_on(bp->dev);
+		netdev_info(bp->dev, "NIC Link is Up, ");
+
+		line_speed = bp->link_vars.line_speed;
+		if (IS_E1HMF(bp)) {
+			u16 vn_max_rate;
+
+			vn_max_rate =
+				((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
+				 FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
+			if (vn_max_rate < line_speed)
+				line_speed = vn_max_rate;
+		}
+		pr_cont("%d Mbps ", line_speed);
+
+		if (bp->link_vars.duplex == DUPLEX_FULL)
+			pr_cont("full duplex");
+		else
+			pr_cont("half duplex");
+
+		if (bp->link_vars.flow_ctrl != BNX2X_FLOW_CTRL_NONE) {
+			if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) {
+				pr_cont(", receive ");
+				if (bp->link_vars.flow_ctrl &
+				    BNX2X_FLOW_CTRL_TX)
+					pr_cont("& transmit ");
+			} else {
+				pr_cont(", transmit ");
+			}
+			pr_cont("flow control ON");
+		}
+		pr_cont("\n");
+
+	} else { /* link_down */
+		netif_carrier_off(bp->dev);
+		netdev_err(bp->dev, "NIC Link is Down\n");
+	}
+}
+
+void bnx2x_init_rx_rings(struct bnx2x *bp)
+{
+	int func = BP_FUNC(bp);
+	int max_agg_queues = CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 :
+					      ETH_MAX_AGGREGATION_QUEUES_E1H;
+	u16 ring_prod, cqe_ring_prod;
+	int i, j;
+
+	bp->rx_buf_size = bp->dev->mtu + ETH_OVREHEAD + BNX2X_RX_ALIGN;
+	DP(NETIF_MSG_IFUP,
+	   "mtu %d  rx_buf_size %d\n", bp->dev->mtu, bp->rx_buf_size);
+
+	if (bp->flags & TPA_ENABLE_FLAG) {
+
+		for_each_queue(bp, j) {
+			struct bnx2x_fastpath *fp = &bp->fp[j];
+
+			for (i = 0; i < max_agg_queues; i++) {
+				fp->tpa_pool[i].skb =
+				   netdev_alloc_skb(bp->dev, bp->rx_buf_size);
+				if (!fp->tpa_pool[i].skb) {
+					BNX2X_ERR("Failed to allocate TPA "
+						  "skb pool for queue[%d] - "
+						  "disabling TPA on this "
+						  "queue!\n", j);
+					bnx2x_free_tpa_pool(bp, fp, i);
+					fp->disable_tpa = 1;
+					break;
+				}
+				dma_unmap_addr_set((struct sw_rx_bd *)
+							&bp->fp->tpa_pool[i],
+						   mapping, 0);
+				fp->tpa_state[i] = BNX2X_TPA_STOP;
+			}
+		}
+	}
+
+	for_each_queue(bp, j) {
+		struct bnx2x_fastpath *fp = &bp->fp[j];
+
+		fp->rx_bd_cons = 0;
+		fp->rx_cons_sb = BNX2X_RX_SB_INDEX;
+		fp->rx_bd_cons_sb = BNX2X_RX_SB_BD_INDEX;
+
+		/* "next page" elements initialization */
+		/* SGE ring */
+		for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
+			struct eth_rx_sge *sge;
+
+			sge = &fp->rx_sge_ring[RX_SGE_CNT * i - 2];
+			sge->addr_hi =
+				cpu_to_le32(U64_HI(fp->rx_sge_mapping +
+					BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
+			sge->addr_lo =
+				cpu_to_le32(U64_LO(fp->rx_sge_mapping +
+					BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
+		}
+
+		bnx2x_init_sge_ring_bit_mask(fp);
+
+		/* RX BD ring */
+		for (i = 1; i <= NUM_RX_RINGS; i++) {
+			struct eth_rx_bd *rx_bd;
+
+			rx_bd = &fp->rx_desc_ring[RX_DESC_CNT * i - 2];
+			rx_bd->addr_hi =
+				cpu_to_le32(U64_HI(fp->rx_desc_mapping +
+					    BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
+			rx_bd->addr_lo =
+				cpu_to_le32(U64_LO(fp->rx_desc_mapping +
+					    BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
+		}
+
+		/* CQ ring */
+		for (i = 1; i <= NUM_RCQ_RINGS; i++) {
+			struct eth_rx_cqe_next_page *nextpg;
+
+			nextpg = (struct eth_rx_cqe_next_page *)
+				&fp->rx_comp_ring[RCQ_DESC_CNT * i - 1];
+			nextpg->addr_hi =
+				cpu_to_le32(U64_HI(fp->rx_comp_mapping +
+					   BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
+			nextpg->addr_lo =
+				cpu_to_le32(U64_LO(fp->rx_comp_mapping +
+					   BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
+		}
+
+		/* Allocate SGEs and initialize the ring elements */
+		for (i = 0, ring_prod = 0;
+		     i < MAX_RX_SGE_CNT*NUM_RX_SGE_PAGES; i++) {
+
+			if (bnx2x_alloc_rx_sge(bp, fp, ring_prod) < 0) {
+				BNX2X_ERR("was only able to allocate "
+					  "%d rx sges\n", i);
+				BNX2X_ERR("disabling TPA for queue[%d]\n", j);
+				/* Cleanup already allocated elements */
+				bnx2x_free_rx_sge_range(bp, fp, ring_prod);
+				bnx2x_free_tpa_pool(bp, fp, max_agg_queues);
+				fp->disable_tpa = 1;
+				ring_prod = 0;
+				break;
+			}
+			ring_prod = NEXT_SGE_IDX(ring_prod);
+		}
+		fp->rx_sge_prod = ring_prod;
+
+		/* Allocate BDs and initialize BD ring */
+		fp->rx_comp_cons = 0;
+		cqe_ring_prod = ring_prod = 0;
+		for (i = 0; i < bp->rx_ring_size; i++) {
+			if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) {
+				BNX2X_ERR("was only able to allocate "
+					  "%d rx skbs on queue[%d]\n", i, j);
+				fp->eth_q_stats.rx_skb_alloc_failed++;
+				break;
+			}
+			ring_prod = NEXT_RX_IDX(ring_prod);
+			cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod);
+			WARN_ON(ring_prod <= i);
+		}
+
+		fp->rx_bd_prod = ring_prod;
+		/* must not have more available CQEs than BDs */
+		fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT,
+					 cqe_ring_prod);
+		fp->rx_pkt = fp->rx_calls = 0;
+
+		/* Warning!
+		 * this will generate an interrupt (to the TSTORM)
+		 * must only be done after chip is initialized
+		 */
+		bnx2x_update_rx_prod(bp, fp, ring_prod, fp->rx_comp_prod,
+				     fp->rx_sge_prod);
+		if (j != 0)
+			continue;
+
+		REG_WR(bp, BAR_USTRORM_INTMEM +
+		       USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func),
+		       U64_LO(fp->rx_comp_mapping));
+		REG_WR(bp, BAR_USTRORM_INTMEM +
+		       USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func) + 4,
+		       U64_HI(fp->rx_comp_mapping));
+	}
+}
+static void bnx2x_free_tx_skbs(struct bnx2x *bp)
+{
+	int i;
+
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		u16 bd_cons = fp->tx_bd_cons;
+		u16 sw_prod = fp->tx_pkt_prod;
+		u16 sw_cons = fp->tx_pkt_cons;
+
+		while (sw_cons != sw_prod) {
+			bd_cons = bnx2x_free_tx_pkt(bp, fp, TX_BD(sw_cons));
+			sw_cons++;
+		}
+	}
+}
+
+static void bnx2x_free_rx_skbs(struct bnx2x *bp)
+{
+	int i, j;
+
+	for_each_queue(bp, j) {
+		struct bnx2x_fastpath *fp = &bp->fp[j];
+
+		for (i = 0; i < NUM_RX_BD; i++) {
+			struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i];
+			struct sk_buff *skb = rx_buf->skb;
+
+			if (skb == NULL)
+				continue;
+
+			dma_unmap_single(&bp->pdev->dev,
+					 dma_unmap_addr(rx_buf, mapping),
+					 bp->rx_buf_size, DMA_FROM_DEVICE);
+
+			rx_buf->skb = NULL;
+			dev_kfree_skb(skb);
+		}
+		if (!fp->disable_tpa)
+			bnx2x_free_tpa_pool(bp, fp, CHIP_IS_E1(bp) ?
+					    ETH_MAX_AGGREGATION_QUEUES_E1 :
+					    ETH_MAX_AGGREGATION_QUEUES_E1H);
+	}
+}
+
+void bnx2x_free_skbs(struct bnx2x *bp)
+{
+	bnx2x_free_tx_skbs(bp);
+	bnx2x_free_rx_skbs(bp);
+}
+
+static void bnx2x_free_msix_irqs(struct bnx2x *bp)
+{
+	int i, offset = 1;
+
+	free_irq(bp->msix_table[0].vector, bp->dev);
+	DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
+	   bp->msix_table[0].vector);
+
+#ifdef BCM_CNIC
+	offset++;
+#endif
+	for_each_queue(bp, i) {
+		DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq  "
+		   "state %x\n", i, bp->msix_table[i + offset].vector,
+		   bnx2x_fp(bp, i, state));
+
+		free_irq(bp->msix_table[i + offset].vector, &bp->fp[i]);
+	}
+}
+
+void bnx2x_free_irq(struct bnx2x *bp, bool disable_only)
+{
+	if (bp->flags & USING_MSIX_FLAG) {
+		if (!disable_only)
+			bnx2x_free_msix_irqs(bp);
+		pci_disable_msix(bp->pdev);
+		bp->flags &= ~USING_MSIX_FLAG;
+
+	} else if (bp->flags & USING_MSI_FLAG) {
+		if (!disable_only)
+			free_irq(bp->pdev->irq, bp->dev);
+		pci_disable_msi(bp->pdev);
+		bp->flags &= ~USING_MSI_FLAG;
+
+	} else if (!disable_only)
+		free_irq(bp->pdev->irq, bp->dev);
+}
+
+static int bnx2x_enable_msix(struct bnx2x *bp)
+{
+	int i, rc, offset = 1;
+	int igu_vec = 0;
+
+	bp->msix_table[0].entry = igu_vec;
+	DP(NETIF_MSG_IFUP, "msix_table[0].entry = %d (slowpath)\n", igu_vec);
+
+#ifdef BCM_CNIC
+	igu_vec = BP_L_ID(bp) + offset;
+	bp->msix_table[1].entry = igu_vec;
+	DP(NETIF_MSG_IFUP, "msix_table[1].entry = %d (CNIC)\n", igu_vec);
+	offset++;
+#endif
+	for_each_queue(bp, i) {
+		igu_vec = BP_L_ID(bp) + offset + i;
+		bp->msix_table[i + offset].entry = igu_vec;
+		DP(NETIF_MSG_IFUP, "msix_table[%d].entry = %d "
+		   "(fastpath #%u)\n", i + offset, igu_vec, i);
+	}
+
+	rc = pci_enable_msix(bp->pdev, &bp->msix_table[0],
+			     BNX2X_NUM_QUEUES(bp) + offset);
+
+	/*
+	 * reconfigure number of tx/rx queues according to available
+	 * MSI-X vectors
+	 */
+	if (rc >= BNX2X_MIN_MSIX_VEC_CNT) {
+		/* vectors available for FP */
+		int fp_vec = rc - BNX2X_MSIX_VEC_FP_START;
+
+		DP(NETIF_MSG_IFUP,
+		   "Trying to use less MSI-X vectors: %d\n", rc);
+
+		rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], rc);
+
+		if (rc) {
+			DP(NETIF_MSG_IFUP,
+			   "MSI-X is not attainable  rc %d\n", rc);
+			return rc;
+		}
+
+		bp->num_queues = min(bp->num_queues, fp_vec);
+
+		DP(NETIF_MSG_IFUP, "New queue configuration set: %d\n",
+				  bp->num_queues);
+	} else if (rc) {
+		DP(NETIF_MSG_IFUP, "MSI-X is not attainable  rc %d\n", rc);
+		return rc;
+	}
+
+	bp->flags |= USING_MSIX_FLAG;
+
+	return 0;
+}
+
+static int bnx2x_req_msix_irqs(struct bnx2x *bp)
+{
+	int i, rc, offset = 1;
+
+	rc = request_irq(bp->msix_table[0].vector, bnx2x_msix_sp_int, 0,
+			 bp->dev->name, bp->dev);
+	if (rc) {
+		BNX2X_ERR("request sp irq failed\n");
+		return -EBUSY;
+	}
+
+#ifdef BCM_CNIC
+	offset++;
+#endif
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+		snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
+			 bp->dev->name, i);
+
+		rc = request_irq(bp->msix_table[i + offset].vector,
+				 bnx2x_msix_fp_int, 0, fp->name, fp);
+		if (rc) {
+			BNX2X_ERR("request fp #%d irq failed  rc %d\n", i, rc);
+			bnx2x_free_msix_irqs(bp);
+			return -EBUSY;
+		}
+
+		fp->state = BNX2X_FP_STATE_IRQ;
+	}
+
+	i = BNX2X_NUM_QUEUES(bp);
+	netdev_info(bp->dev, "using MSI-X  IRQs: sp %d  fp[%d] %d"
+	       " ... fp[%d] %d\n",
+	       bp->msix_table[0].vector,
+	       0, bp->msix_table[offset].vector,
+	       i - 1, bp->msix_table[offset + i - 1].vector);
+
+	return 0;
+}
+
+static int bnx2x_enable_msi(struct bnx2x *bp)
+{
+	int rc;
+
+	rc = pci_enable_msi(bp->pdev);
+	if (rc) {
+		DP(NETIF_MSG_IFUP, "MSI is not attainable\n");
+		return -1;
+	}
+	bp->flags |= USING_MSI_FLAG;
+
+	return 0;
+}
+
+static int bnx2x_req_irq(struct bnx2x *bp)
+{
+	unsigned long flags;
+	int rc;
+
+	if (bp->flags & USING_MSI_FLAG)
+		flags = 0;
+	else
+		flags = IRQF_SHARED;
+
+	rc = request_irq(bp->pdev->irq, bnx2x_interrupt, flags,
+			 bp->dev->name, bp->dev);
+	if (!rc)
+		bnx2x_fp(bp, 0, state) = BNX2X_FP_STATE_IRQ;
+
+	return rc;
+}
+
+static void bnx2x_napi_enable(struct bnx2x *bp)
+{
+	int i;
+
+	for_each_queue(bp, i)
+		napi_enable(&bnx2x_fp(bp, i, napi));
+}
+
+static void bnx2x_napi_disable(struct bnx2x *bp)
+{
+	int i;
+
+	for_each_queue(bp, i)
+		napi_disable(&bnx2x_fp(bp, i, napi));
+}
+
+void bnx2x_netif_start(struct bnx2x *bp)
+{
+	int intr_sem;
+
+	intr_sem = atomic_dec_and_test(&bp->intr_sem);
+	smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
+	if (intr_sem) {
+		if (netif_running(bp->dev)) {
+			bnx2x_napi_enable(bp);
+			bnx2x_int_enable(bp);
+			if (bp->state == BNX2X_STATE_OPEN)
+				netif_tx_wake_all_queues(bp->dev);
+		}
+	}
+}
+
+void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
+{
+	bnx2x_int_disable_sync(bp, disable_hw);
+	bnx2x_napi_disable(bp);
+	netif_tx_disable(bp->dev);
+}
+static int bnx2x_set_num_queues(struct bnx2x *bp)
+{
+	int rc = 0;
+
+	switch (bp->int_mode) {
+	case INT_MODE_INTx:
+	case INT_MODE_MSI:
+		bp->num_queues = 1;
+		DP(NETIF_MSG_IFUP, "set number of queues to 1\n");
+		break;
+	default:
+		/* Set number of queues according to bp->multi_mode value */
+		bnx2x_set_num_queues_msix(bp);
+
+		DP(NETIF_MSG_IFUP, "set number of queues to %d\n",
+		   bp->num_queues);
+
+		/* if we can't use MSI-X we only need one fp,
+		 * so try to enable MSI-X with the requested number of fp's
+		 * and fallback to MSI or legacy INTx with one fp
+		 */
+		rc = bnx2x_enable_msix(bp);
+		if (rc)
+			/* failed to enable MSI-X */
+			bp->num_queues = 1;
+		break;
+	}
+	bp->dev->real_num_tx_queues = bp->num_queues;
+	return rc;
+}
+
+/* must be called with rtnl_lock */
+int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
+{
+	u32 load_code;
+	int i, rc;
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return -EPERM;
+#endif
+
+	bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
+
+	rc = bnx2x_set_num_queues(bp);
+
+	if (bnx2x_alloc_mem(bp)) {
+		bnx2x_free_irq(bp, true);
+		return -ENOMEM;
+	}
+
+	for_each_queue(bp, i)
+		bnx2x_fp(bp, i, disable_tpa) =
+					((bp->flags & TPA_ENABLE_FLAG) == 0);
+
+	for_each_queue(bp, i)
+		netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
+			       bnx2x_poll, 128);
+
+	bnx2x_napi_enable(bp);
+
+	if (bp->flags & USING_MSIX_FLAG) {
+		rc = bnx2x_req_msix_irqs(bp);
+		if (rc) {
+			bnx2x_free_irq(bp, true);
+			goto load_error1;
+		}
+	} else {
+		/* Fall to INTx if failed to enable MSI-X due to lack of
+		   memory (in bnx2x_set_num_queues()) */
+		if ((rc != -ENOMEM) && (bp->int_mode != INT_MODE_INTx))
+			bnx2x_enable_msi(bp);
+		bnx2x_ack_int(bp);
+		rc = bnx2x_req_irq(bp);
+		if (rc) {
+			BNX2X_ERR("IRQ request failed  rc %d, aborting\n", rc);
+			bnx2x_free_irq(bp, true);
+			goto load_error1;
+		}
+		if (bp->flags & USING_MSI_FLAG) {
+			bp->dev->irq = bp->pdev->irq;
+			netdev_info(bp->dev, "using MSI  IRQ %d\n",
+				    bp->pdev->irq);
+		}
+	}
+
+	/* Send LOAD_REQUEST command to MCP
+	   Returns the type of LOAD command:
+	   if it is the first port to be initialized
+	   common blocks should be initialized, otherwise - not
+	*/
+	if (!BP_NOMCP(bp)) {
+		load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ);
+		if (!load_code) {
+			BNX2X_ERR("MCP response failure, aborting\n");
+			rc = -EBUSY;
+			goto load_error2;
+		}
+		if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) {
+			rc = -EBUSY; /* other port in diagnostic mode */
+			goto load_error2;
+		}
+
+	} else {
+		int port = BP_PORT(bp);
+
+		DP(NETIF_MSG_IFUP, "NO MCP - load counts      %d, %d, %d\n",
+		   load_count[0], load_count[1], load_count[2]);
+		load_count[0]++;
+		load_count[1 + port]++;
+		DP(NETIF_MSG_IFUP, "NO MCP - new load counts  %d, %d, %d\n",
+		   load_count[0], load_count[1], load_count[2]);
+		if (load_count[0] == 1)
+			load_code = FW_MSG_CODE_DRV_LOAD_COMMON;
+		else if (load_count[1 + port] == 1)
+			load_code = FW_MSG_CODE_DRV_LOAD_PORT;
+		else
+			load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION;
+	}
+
+	if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
+	    (load_code == FW_MSG_CODE_DRV_LOAD_PORT))
+		bp->port.pmf = 1;
+	else
+		bp->port.pmf = 0;
+	DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
+
+	/* Initialize HW */
+	rc = bnx2x_init_hw(bp, load_code);
+	if (rc) {
+		BNX2X_ERR("HW init failed, aborting\n");
+		bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
+		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
+		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+		goto load_error2;
+	}
+
+	/* Setup NIC internals and enable interrupts */
+	bnx2x_nic_init(bp, load_code);
+
+	if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) &&
+	    (bp->common.shmem2_base))
+		SHMEM2_WR(bp, dcc_support,
+			  (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
+			   SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
+
+	/* Send LOAD_DONE command to MCP */
+	if (!BP_NOMCP(bp)) {
+		load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
+		if (!load_code) {
+			BNX2X_ERR("MCP response failure, aborting\n");
+			rc = -EBUSY;
+			goto load_error3;
+		}
+	}
+
+	bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
+
+	rc = bnx2x_setup_leading(bp);
+	if (rc) {
+		BNX2X_ERR("Setup leading failed!\n");
+#ifndef BNX2X_STOP_ON_ERROR
+		goto load_error3;
+#else
+		bp->panic = 1;
+		return -EBUSY;
+#endif
+	}
+
+	if (CHIP_IS_E1H(bp))
+		if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) {
+			DP(NETIF_MSG_IFUP, "mf_cfg function disabled\n");
+			bp->flags |= MF_FUNC_DIS;
+		}
+
+	if (bp->state == BNX2X_STATE_OPEN) {
+#ifdef BCM_CNIC
+		/* Enable Timer scan */
+		REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 1);
+#endif
+		for_each_nondefault_queue(bp, i) {
+			rc = bnx2x_setup_multi(bp, i);
+			if (rc)
+#ifdef BCM_CNIC
+				goto load_error4;
+#else
+				goto load_error3;
+#endif
+		}
+
+		if (CHIP_IS_E1(bp))
+			bnx2x_set_eth_mac_addr_e1(bp, 1);
+		else
+			bnx2x_set_eth_mac_addr_e1h(bp, 1);
+#ifdef BCM_CNIC
+		/* Set iSCSI L2 MAC */
+		mutex_lock(&bp->cnic_mutex);
+		if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD) {
+			bnx2x_set_iscsi_eth_mac_addr(bp, 1);
+			bp->cnic_flags |= BNX2X_CNIC_FLAG_MAC_SET;
+			bnx2x_init_sb(bp, bp->cnic_sb, bp->cnic_sb_mapping,
+				      CNIC_SB_ID(bp));
+		}
+		mutex_unlock(&bp->cnic_mutex);
+#endif
+	}
+
+	if (bp->port.pmf)
+		bnx2x_initial_phy_init(bp, load_mode);
+
+	/* Start fast path */
+	switch (load_mode) {
+	case LOAD_NORMAL:
+		if (bp->state == BNX2X_STATE_OPEN) {
+			/* Tx queue should be only reenabled */
+			netif_tx_wake_all_queues(bp->dev);
+		}
+		/* Initialize the receive filter. */
+		bnx2x_set_rx_mode(bp->dev);
+		break;
+
+	case LOAD_OPEN:
+		netif_tx_start_all_queues(bp->dev);
+		if (bp->state != BNX2X_STATE_OPEN)
+			netif_tx_disable(bp->dev);
+		/* Initialize the receive filter. */
+		bnx2x_set_rx_mode(bp->dev);
+		break;
+
+	case LOAD_DIAG:
+		/* Initialize the receive filter. */
+		bnx2x_set_rx_mode(bp->dev);
+		bp->state = BNX2X_STATE_DIAG;
+		break;
+
+	default:
+		break;
+	}
+
+	if (!bp->port.pmf)
+		bnx2x__link_status_update(bp);
+
+	/* start the timer */
+	mod_timer(&bp->timer, jiffies + bp->current_interval);
+
+#ifdef BCM_CNIC
+	bnx2x_setup_cnic_irq_info(bp);
+	if (bp->state == BNX2X_STATE_OPEN)
+		bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD);
+#endif
+	bnx2x_inc_load_cnt(bp);
+
+	return 0;
+
+#ifdef BCM_CNIC
+load_error4:
+	/* Disable Timer scan */
+	REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 0);
+#endif
+load_error3:
+	bnx2x_int_disable_sync(bp, 1);
+	if (!BP_NOMCP(bp)) {
+		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
+		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+	}
+	bp->port.pmf = 0;
+	/* Free SKBs, SGEs, TPA pool and driver internals */
+	bnx2x_free_skbs(bp);
+	for_each_queue(bp, i)
+		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
+load_error2:
+	/* Release IRQs */
+	bnx2x_free_irq(bp, false);
+load_error1:
+	bnx2x_napi_disable(bp);
+	for_each_queue(bp, i)
+		netif_napi_del(&bnx2x_fp(bp, i, napi));
+	bnx2x_free_mem(bp);
+
+	return rc;
+}
+
+/* must be called with rtnl_lock */
+int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
+{
+	int i;
+
+	if (bp->state == BNX2X_STATE_CLOSED) {
+		/* Interface has been removed - nothing to recover */
+		bp->recovery_state = BNX2X_RECOVERY_DONE;
+		bp->is_leader = 0;
+		bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESERVED_08);
+		smp_wmb();
+
+		return -EINVAL;
+	}
+
+#ifdef BCM_CNIC
+	bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD);
+#endif
+	bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
+
+	/* Set "drop all" */
+	bp->rx_mode = BNX2X_RX_MODE_NONE;
+	bnx2x_set_storm_rx_mode(bp);
+
+	/* Disable HW interrupts, NAPI and Tx */
+	bnx2x_netif_stop(bp, 1);
+	netif_carrier_off(bp->dev);
+
+	del_timer_sync(&bp->timer);
+	SHMEM_WR(bp, func_mb[BP_FUNC(bp)].drv_pulse_mb,
+		 (DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq));
+	bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+
+	/* Release IRQs */
+	bnx2x_free_irq(bp, false);
+
+	/* Cleanup the chip if needed */
+	if (unload_mode != UNLOAD_RECOVERY)
+		bnx2x_chip_cleanup(bp, unload_mode);
+
+	bp->port.pmf = 0;
+
+	/* Free SKBs, SGEs, TPA pool and driver internals */
+	bnx2x_free_skbs(bp);
+	for_each_queue(bp, i)
+		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
+	for_each_queue(bp, i)
+		netif_napi_del(&bnx2x_fp(bp, i, napi));
+	bnx2x_free_mem(bp);
+
+	bp->state = BNX2X_STATE_CLOSED;
+
+	/* The last driver must disable a "close the gate" if there is no
+	 * parity attention or "process kill" pending.
+	 */
+	if ((!bnx2x_dec_load_cnt(bp)) && (!bnx2x_chk_parity_attn(bp)) &&
+	    bnx2x_reset_is_done(bp))
+		bnx2x_disable_close_the_gate(bp);
+
+	/* Reset MCP mail box sequence if there is on going recovery */
+	if (unload_mode == UNLOAD_RECOVERY)
+		bp->fw_seq = 0;
+
+	return 0;
+}
+int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
+{
+	u16 pmcsr;
+
+	pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
+
+	switch (state) {
+	case PCI_D0:
+		pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
+				      ((pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
+				       PCI_PM_CTRL_PME_STATUS));
+
+		if (pmcsr & PCI_PM_CTRL_STATE_MASK)
+			/* delay required during transition out of D3hot */
+			msleep(20);
+		break;
+
+	case PCI_D3hot:
+		/* If there are other clients above don't
+		   shut down the power */
+		if (atomic_read(&bp->pdev->enable_cnt) != 1)
+			return 0;
+		/* Don't shut down the power for emulation and FPGA */
+		if (CHIP_REV_IS_SLOW(bp))
+			return 0;
+
+		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+		pmcsr |= 3;
+
+		if (bp->wol)
+			pmcsr |= PCI_PM_CTRL_PME_ENABLE;
+
+		pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
+				      pmcsr);
+
+		/* No more memory access after this point until
+		* device is brought back to D0.
+		*/
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+
+/*
+ * net_device service functions
+ */
+
+static int bnx2x_poll(struct napi_struct *napi, int budget)
+{
+	int work_done = 0;
+	struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath,
+						 napi);
+	struct bnx2x *bp = fp->bp;
+
+	while (1) {
+#ifdef BNX2X_STOP_ON_ERROR
+		if (unlikely(bp->panic)) {
+			napi_complete(napi);
+			return 0;
+		}
+#endif
+
+		if (bnx2x_has_tx_work(fp))
+			bnx2x_tx_int(fp);
+
+		if (bnx2x_has_rx_work(fp)) {
+			work_done += bnx2x_rx_int(fp, budget - work_done);
+
+			/* must not complete if we consumed full budget */
+			if (work_done >= budget)
+				break;
+		}
+
+		/* Fall out from the NAPI loop if needed */
+		if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
+			bnx2x_update_fpsb_idx(fp);
+		/* bnx2x_has_rx_work() reads the status block, thus we need
+		 * to ensure that status block indices have been actually read
+		 * (bnx2x_update_fpsb_idx) prior to this check
+		 * (bnx2x_has_rx_work) so that we won't write the "newer"
+		 * value of the status block to IGU (if there was a DMA right
+		 * after bnx2x_has_rx_work and if there is no rmb, the memory
+		 * reading (bnx2x_update_fpsb_idx) may be postponed to right
+		 * before bnx2x_ack_sb). In this case there will never be
+		 * another interrupt until there is another update of the
+		 * status block, while there is still unhandled work.
+		 */
+			rmb();
+
+			if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
+				napi_complete(napi);
+				/* Re-enable interrupts */
+				bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID,
+					     le16_to_cpu(fp->fp_c_idx),
+					     IGU_INT_NOP, 1);
+				bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID,
+					     le16_to_cpu(fp->fp_u_idx),
+					     IGU_INT_ENABLE, 1);
+				break;
+			}
+		}
+	}
+
+	return work_done;
+}
+
+
+/* we split the first BD into headers and data BDs
+ * to ease the pain of our fellow microcode engineers
+ * we use one mapping for both BDs
+ * So far this has only been observed to happen
+ * in Other Operating Systems(TM)
+ */
+static noinline u16 bnx2x_tx_split(struct bnx2x *bp,
+				   struct bnx2x_fastpath *fp,
+				   struct sw_tx_bd *tx_buf,
+				   struct eth_tx_start_bd **tx_bd, u16 hlen,
+				   u16 bd_prod, int nbd)
+{
+	struct eth_tx_start_bd *h_tx_bd = *tx_bd;
+	struct eth_tx_bd *d_tx_bd;
+	dma_addr_t mapping;
+	int old_len = le16_to_cpu(h_tx_bd->nbytes);
+
+	/* first fix first BD */
+	h_tx_bd->nbd = cpu_to_le16(nbd);
+	h_tx_bd->nbytes = cpu_to_le16(hlen);
+
+	DP(NETIF_MSG_TX_QUEUED,	"TSO split header size is %d "
+	   "(%x:%x) nbd %d\n", h_tx_bd->nbytes, h_tx_bd->addr_hi,
+	   h_tx_bd->addr_lo, h_tx_bd->nbd);
+
+	/* now get a new data BD
+	 * (after the pbd) and fill it */
+	bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+	d_tx_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
+
+	mapping = HILO_U64(le32_to_cpu(h_tx_bd->addr_hi),
+			   le32_to_cpu(h_tx_bd->addr_lo)) + hlen;
+
+	d_tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+	d_tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+	d_tx_bd->nbytes = cpu_to_le16(old_len - hlen);
+
+	/* this marks the BD as one that has no individual mapping */
+	tx_buf->flags |= BNX2X_TSO_SPLIT_BD;
+
+	DP(NETIF_MSG_TX_QUEUED,
+	   "TSO split data size is %d (%x:%x)\n",
+	   d_tx_bd->nbytes, d_tx_bd->addr_hi, d_tx_bd->addr_lo);
+
+	/* update tx_bd */
+	*tx_bd = (struct eth_tx_start_bd *)d_tx_bd;
+
+	return bd_prod;
+}
+
+static inline u16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
+{
+	if (fix > 0)
+		csum = (u16) ~csum_fold(csum_sub(csum,
+				csum_partial(t_header - fix, fix, 0)));
+
+	else if (fix < 0)
+		csum = (u16) ~csum_fold(csum_add(csum,
+				csum_partial(t_header, -fix, 0)));
+
+	return swab16(csum);
+}
+
+static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
+{
+	u32 rc;
+
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		rc = XMIT_PLAIN;
+
+	else {
+		if (skb->protocol == htons(ETH_P_IPV6)) {
+			rc = XMIT_CSUM_V6;
+			if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+				rc |= XMIT_CSUM_TCP;
+
+		} else {
+			rc = XMIT_CSUM_V4;
+			if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+				rc |= XMIT_CSUM_TCP;
+		}
+	}
+
+	if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+		rc |= (XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP);
+
+	else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+		rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6);
+
+	return rc;
+}
+
+#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
+/* check if packet requires linearization (packet is too fragmented)
+   no need to check fragmentation if page size > 8K (there will be no
+   violation to FW restrictions) */
+static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb,
+			     u32 xmit_type)
+{
+	int to_copy = 0;
+	int hlen = 0;
+	int first_bd_sz = 0;
+
+	/* 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */
+	if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - 3)) {
+
+		if (xmit_type & XMIT_GSO) {
+			unsigned short lso_mss = skb_shinfo(skb)->gso_size;
+			/* Check if LSO packet needs to be copied:
+			   3 = 1 (for headers BD) + 2 (for PBD and last BD) */
+			int wnd_size = MAX_FETCH_BD - 3;
+			/* Number of windows to check */
+			int num_wnds = skb_shinfo(skb)->nr_frags - wnd_size;
+			int wnd_idx = 0;
+			int frag_idx = 0;
+			u32 wnd_sum = 0;
+
+			/* Headers length */
+			hlen = (int)(skb_transport_header(skb) - skb->data) +
+				tcp_hdrlen(skb);
+
+			/* Amount of data (w/o headers) on linear part of SKB*/
+			first_bd_sz = skb_headlen(skb) - hlen;
+
+			wnd_sum  = first_bd_sz;
+
+			/* Calculate the first sum - it's special */
+			for (frag_idx = 0; frag_idx < wnd_size - 1; frag_idx++)
+				wnd_sum +=
+					skb_shinfo(skb)->frags[frag_idx].size;
+
+			/* If there was data on linear skb data - check it */
+			if (first_bd_sz > 0) {
+				if (unlikely(wnd_sum < lso_mss)) {
+					to_copy = 1;
+					goto exit_lbl;
+				}
+
+				wnd_sum -= first_bd_sz;
+			}
+
+			/* Others are easier: run through the frag list and
+			   check all windows */
+			for (wnd_idx = 0; wnd_idx <= num_wnds; wnd_idx++) {
+				wnd_sum +=
+			  skb_shinfo(skb)->frags[wnd_idx + wnd_size - 1].size;
+
+				if (unlikely(wnd_sum < lso_mss)) {
+					to_copy = 1;
+					break;
+				}
+				wnd_sum -=
+					skb_shinfo(skb)->frags[wnd_idx].size;
+			}
+		} else {
+			/* in non-LSO too fragmented packet should always
+			   be linearized */
+			to_copy = 1;
+		}
+	}
+
+exit_lbl:
+	if (unlikely(to_copy))
+		DP(NETIF_MSG_TX_QUEUED,
+		   "Linearization IS REQUIRED for %s packet. "
+		   "num_frags %d  hlen %d  first_bd_sz %d\n",
+		   (xmit_type & XMIT_GSO) ? "LSO" : "non-LSO",
+		   skb_shinfo(skb)->nr_frags, hlen, first_bd_sz);
+
+	return to_copy;
+}
+#endif
+
+/* called with netif_tx_lock
+ * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call
+ * netif_wake_queue()
+ */
+netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	struct bnx2x_fastpath *fp;
+	struct netdev_queue *txq;
+	struct sw_tx_bd *tx_buf;
+	struct eth_tx_start_bd *tx_start_bd;
+	struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
+	struct eth_tx_parse_bd *pbd = NULL;
+	u16 pkt_prod, bd_prod;
+	int nbd, fp_index;
+	dma_addr_t mapping;
+	u32 xmit_type = bnx2x_xmit_type(bp, skb);
+	int i;
+	u8 hlen = 0;
+	__le16 pkt_size = 0;
+	struct ethhdr *eth;
+	u8 mac_type = UNICAST_ADDRESS;
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return NETDEV_TX_BUSY;
+#endif
+
+	fp_index = skb_get_queue_mapping(skb);
+	txq = netdev_get_tx_queue(dev, fp_index);
+
+	fp = &bp->fp[fp_index];
+
+	if (unlikely(bnx2x_tx_avail(fp) < (skb_shinfo(skb)->nr_frags + 3))) {
+		fp->eth_q_stats.driver_xoff++;
+		netif_tx_stop_queue(txq);
+		BNX2X_ERR("BUG! Tx ring full when queue awake!\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	DP(NETIF_MSG_TX_QUEUED, "SKB: summed %x  protocol %x  protocol(%x,%x)"
+	   "  gso type %x  xmit_type %x\n",
+	   skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr,
+	   ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type);
+
+	eth = (struct ethhdr *)skb->data;
+
+	/* set flag according to packet type (UNICAST_ADDRESS is default)*/
+	if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
+		if (is_broadcast_ether_addr(eth->h_dest))
+			mac_type = BROADCAST_ADDRESS;
+		else
+			mac_type = MULTICAST_ADDRESS;
+	}
+
+#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
+	/* First, check if we need to linearize the skb (due to FW
+	   restrictions). No need to check fragmentation if page size > 8K
+	   (there will be no violation to FW restrictions) */
+	if (bnx2x_pkt_req_lin(bp, skb, xmit_type)) {
+		/* Statistics of linearization */
+		bp->lin_cnt++;
+		if (skb_linearize(skb) != 0) {
+			DP(NETIF_MSG_TX_QUEUED, "SKB linearization failed - "
+			   "silently dropping this SKB\n");
+			dev_kfree_skb_any(skb);
+			return NETDEV_TX_OK;
+		}
+	}
+#endif
+
+	/*
+	Please read carefully. First we use one BD which we mark as start,
+	then we have a parsing info BD (used for TSO or xsum),
+	and only then we have the rest of the TSO BDs.
+	(don't forget to mark the last one as last,
+	and to unmap only AFTER you write to the BD ...)
+	And above all, all pdb sizes are in words - NOT DWORDS!
+	*/
+
+	pkt_prod = fp->tx_pkt_prod++;
+	bd_prod = TX_BD(fp->tx_bd_prod);
+
+	/* get a tx_buf and first BD */
+	tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)];
+	tx_start_bd = &fp->tx_desc_ring[bd_prod].start_bd;
+
+	tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
+	tx_start_bd->general_data =  (mac_type <<
+					ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT);
+	/* header nbd */
+	tx_start_bd->general_data |= (1 << ETH_TX_START_BD_HDR_NBDS_SHIFT);
+
+	/* remember the first BD of the packet */
+	tx_buf->first_bd = fp->tx_bd_prod;
+	tx_buf->skb = skb;
+	tx_buf->flags = 0;
+
+	DP(NETIF_MSG_TX_QUEUED,
+	   "sending pkt %u @%p  next_idx %u  bd %u @%p\n",
+	   pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_start_bd);
+
+#ifdef BCM_VLAN
+	if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb) &&
+	    (bp->flags & HW_VLAN_TX_FLAG)) {
+		tx_start_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb));
+		tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG;
+	} else
+#endif
+		tx_start_bd->vlan = cpu_to_le16(pkt_prod);
+
+	/* turn on parsing and get a BD */
+	bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+	pbd = &fp->tx_desc_ring[bd_prod].parse_bd;
+
+	memset(pbd, 0, sizeof(struct eth_tx_parse_bd));
+
+	if (xmit_type & XMIT_CSUM) {
+		hlen = (skb_network_header(skb) - skb->data) / 2;
+
+		/* for now NS flag is not used in Linux */
+		pbd->global_data =
+			(hlen | ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
+				 ETH_TX_PARSE_BD_LLC_SNAP_EN_SHIFT));
+
+		pbd->ip_hlen = (skb_transport_header(skb) -
+				skb_network_header(skb)) / 2;
+
+		hlen += pbd->ip_hlen + tcp_hdrlen(skb) / 2;
+
+		pbd->total_hlen = cpu_to_le16(hlen);
+		hlen = hlen*2;
+
+		tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_L4_CSUM;
+
+		if (xmit_type & XMIT_CSUM_V4)
+			tx_start_bd->bd_flags.as_bitfield |=
+						ETH_TX_BD_FLAGS_IP_CSUM;
+		else
+			tx_start_bd->bd_flags.as_bitfield |=
+						ETH_TX_BD_FLAGS_IPV6;
+
+		if (xmit_type & XMIT_CSUM_TCP) {
+			pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check);
+
+		} else {
+			s8 fix = SKB_CS_OFF(skb); /* signed! */
+
+			pbd->global_data |= ETH_TX_PARSE_BD_UDP_CS_FLG;
+
+			DP(NETIF_MSG_TX_QUEUED,
+			   "hlen %d  fix %d  csum before fix %x\n",
+			   le16_to_cpu(pbd->total_hlen), fix, SKB_CS(skb));
+
+			/* HW bug: fixup the CSUM */
+			pbd->tcp_pseudo_csum =
+				bnx2x_csum_fix(skb_transport_header(skb),
+					       SKB_CS(skb), fix);
+
+			DP(NETIF_MSG_TX_QUEUED, "csum after fix %x\n",
+			   pbd->tcp_pseudo_csum);
+		}
+	}
+
+	mapping = dma_map_single(&bp->pdev->dev, skb->data,
+				 skb_headlen(skb), DMA_TO_DEVICE);
+
+	tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+	tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+	nbd = skb_shinfo(skb)->nr_frags + 2; /* start_bd + pbd + frags */
+	tx_start_bd->nbd = cpu_to_le16(nbd);
+	tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb));
+	pkt_size = tx_start_bd->nbytes;
+
+	DP(NETIF_MSG_TX_QUEUED, "first bd @%p  addr (%x:%x)  nbd %d"
+	   "  nbytes %d  flags %x  vlan %x\n",
+	   tx_start_bd, tx_start_bd->addr_hi, tx_start_bd->addr_lo,
+	   le16_to_cpu(tx_start_bd->nbd), le16_to_cpu(tx_start_bd->nbytes),
+	   tx_start_bd->bd_flags.as_bitfield, le16_to_cpu(tx_start_bd->vlan));
+
+	if (xmit_type & XMIT_GSO) {
+
+		DP(NETIF_MSG_TX_QUEUED,
+		   "TSO packet len %d  hlen %d  total len %d  tso size %d\n",
+		   skb->len, hlen, skb_headlen(skb),
+		   skb_shinfo(skb)->gso_size);
+
+		tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO;
+
+		if (unlikely(skb_headlen(skb) > hlen))
+			bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd,
+						 hlen, bd_prod, ++nbd);
+
+		pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+		pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq);
+		pbd->tcp_flags = pbd_tcp_flags(skb);
+
+		if (xmit_type & XMIT_GSO_V4) {
+			pbd->ip_id = swab16(ip_hdr(skb)->id);
+			pbd->tcp_pseudo_csum =
+				swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+							  ip_hdr(skb)->daddr,
+							  0, IPPROTO_TCP, 0));
+
+		} else
+			pbd->tcp_pseudo_csum =
+				swab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+							&ipv6_hdr(skb)->daddr,
+							0, IPPROTO_TCP, 0));
+
+		pbd->global_data |= ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN;
+	}
+	tx_data_bd = (struct eth_tx_bd *)tx_start_bd;
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+		bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+		tx_data_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
+		if (total_pkt_bd == NULL)
+			total_pkt_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
+
+		mapping = dma_map_page(&bp->pdev->dev, frag->page,
+				       frag->page_offset,
+				       frag->size, DMA_TO_DEVICE);
+
+		tx_data_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+		tx_data_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+		tx_data_bd->nbytes = cpu_to_le16(frag->size);
+		le16_add_cpu(&pkt_size, frag->size);
+
+		DP(NETIF_MSG_TX_QUEUED,
+		   "frag %d  bd @%p  addr (%x:%x)  nbytes %d\n",
+		   i, tx_data_bd, tx_data_bd->addr_hi, tx_data_bd->addr_lo,
+		   le16_to_cpu(tx_data_bd->nbytes));
+	}
+
+	DP(NETIF_MSG_TX_QUEUED, "last bd @%p\n", tx_data_bd);
+
+	bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+
+	/* now send a tx doorbell, counting the next BD
+	 * if the packet contains or ends with it
+	 */
+	if (TX_BD_POFF(bd_prod) < nbd)
+		nbd++;
+
+	if (total_pkt_bd != NULL)
+		total_pkt_bd->total_pkt_bytes = pkt_size;
+
+	if (pbd)
+		DP(NETIF_MSG_TX_QUEUED,
+		   "PBD @%p  ip_data %x  ip_hlen %u  ip_id %u  lso_mss %u"
+		   "  tcp_flags %x  xsum %x  seq %u  hlen %u\n",
+		   pbd, pbd->global_data, pbd->ip_hlen, pbd->ip_id,
+		   pbd->lso_mss, pbd->tcp_flags, pbd->tcp_pseudo_csum,
+		   pbd->tcp_send_seq, le16_to_cpu(pbd->total_hlen));
+
+	DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %d  bd %u\n", nbd, bd_prod);
+
+	/*
+	 * Make sure that the BD data is updated before updating the producer
+	 * since FW might read the BD right after the producer is updated.
+	 * This is only applicable for weak-ordered memory model archs such
+	 * as IA-64. The following barrier is also mandatory since FW will
+	 * assumes packets must have BDs.
+	 */
+	wmb();
+
+	fp->tx_db.data.prod += nbd;
+	barrier();
+	DOORBELL(bp, fp->index, fp->tx_db.raw);
+
+	mmiowb();
+
+	fp->tx_bd_prod += nbd;
+
+	if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) {
+		netif_tx_stop_queue(txq);
+
+		/* paired memory barrier is in bnx2x_tx_int(), we have to keep
+		 * ordering of set_bit() in netif_tx_stop_queue() and read of
+		 * fp->bd_tx_cons */
+		smp_mb();
+
+		fp->eth_q_stats.driver_xoff++;
+		if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)
+			netif_tx_wake_queue(txq);
+	}
+	fp->tx_pkt++;
+
+	return NETDEV_TX_OK;
+}
+/* called with rtnl_lock */
+int bnx2x_change_mac_addr(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (!is_valid_ether_addr((u8 *)(addr->sa_data)))
+		return -EINVAL;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	if (netif_running(dev)) {
+		if (CHIP_IS_E1(bp))
+			bnx2x_set_eth_mac_addr_e1(bp, 1);
+		else
+			bnx2x_set_eth_mac_addr_e1h(bp, 1);
+	}
+
+	return 0;
+}
+
+/* called with rtnl_lock */
+int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int rc = 0;
+
+	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+		return -EAGAIN;
+	}
+
+	if ((new_mtu > ETH_MAX_JUMBO_PACKET_SIZE) ||
+	    ((new_mtu + ETH_HLEN) < ETH_MIN_PACKET_SIZE))
+		return -EINVAL;
+
+	/* This does not race with packet allocation
+	 * because the actual alloc size is
+	 * only updated as part of load
+	 */
+	dev->mtu = new_mtu;
+
+	if (netif_running(dev)) {
+		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+		rc = bnx2x_nic_load(bp, LOAD_NORMAL);
+	}
+
+	return rc;
+}
+
+void bnx2x_tx_timeout(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (!bp->panic)
+		bnx2x_panic();
+#endif
+	/* This allows the netif to be shutdown gracefully before resetting */
+	schedule_delayed_work(&bp->reset_task, 0);
+}
+
+#ifdef BCM_VLAN
+/* called with rtnl_lock */
+void bnx2x_vlan_rx_register(struct net_device *dev,
+				   struct vlan_group *vlgrp)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	bp->vlgrp = vlgrp;
+
+	/* Set flags according to the required capabilities */
+	bp->flags &= ~(HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
+
+	if (dev->features & NETIF_F_HW_VLAN_TX)
+		bp->flags |= HW_VLAN_TX_FLAG;
+
+	if (dev->features & NETIF_F_HW_VLAN_RX)
+		bp->flags |= HW_VLAN_RX_FLAG;
+
+	if (netif_running(dev))
+		bnx2x_set_client_config(bp);
+}
+
+#endif
+int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct bnx2x *bp;
+
+	if (!dev) {
+		dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
+		return -ENODEV;
+	}
+	bp = netdev_priv(dev);
+
+	rtnl_lock();
+
+	pci_save_state(pdev);
+
+	if (!netif_running(dev)) {
+		rtnl_unlock();
+		return 0;
+	}
+
+	netif_device_detach(dev);
+
+	bnx2x_nic_unload(bp, UNLOAD_CLOSE);
+
+	bnx2x_set_power_state(bp, pci_choose_state(pdev, state));
+
+	rtnl_unlock();
+
+	return 0;
+}
+
+int bnx2x_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct bnx2x *bp;
+	int rc;
+
+	if (!dev) {
+		dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
+		return -ENODEV;
+	}
+	bp = netdev_priv(dev);
+
+	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+		return -EAGAIN;
+	}
+
+	rtnl_lock();
+
+	pci_restore_state(pdev);
+
+	if (!netif_running(dev)) {
+		rtnl_unlock();
+		return 0;
+	}
+
+	bnx2x_set_power_state(bp, PCI_D0);
+	netif_device_attach(dev);
+
+	rc = bnx2x_nic_load(bp, LOAD_OPEN);
+
+	rtnl_unlock();
+
+	return rc;
+}
diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h
new file mode 100644
index 0000000..d1979b1
--- /dev/null
+++ b/drivers/net/bnx2x/bnx2x_cmn.h
@@ -0,0 +1,652 @@
+/* bnx2x_cmn.h: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007-2010 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
+ * Based on code from Michael Chan's bnx2 driver
+ * UDP CSUM errata workaround by Arik Gendelman
+ * Slowpath and fastpath rework by Vladislav Zolotarov
+ * Statistics and Link management by Yitchak Gertner
+ *
+ */
+#ifndef BNX2X_CMN_H
+#define BNX2X_CMN_H
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+
+
+#include "bnx2x.h"
+
+
+/*********************** Interfaces ****************************
+ *  Functions that need to be implemented by each driver version
+ */
+
+/**
+ * Initialize link parameters structure variables.
+ *
+ * @param bp
+ * @param load_mode
+ *
+ * @return u8
+ */
+u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode);
+
+/**
+ * Configure hw according to link parameters structure.
+ *
+ * @param bp
+ */
+void bnx2x_link_set(struct bnx2x *bp);
+
+/**
+ * Query link status
+ *
+ * @param bp
+ *
+ * @return 0 - link is UP
+ */
+u8 bnx2x_link_test(struct bnx2x *bp);
+
+/**
+ * Handles link status change
+ *
+ * @param bp
+ */
+void bnx2x__link_status_update(struct bnx2x *bp);
+
+/**
+ * MSI-X slowpath interrupt handler
+ *
+ * @param irq
+ * @param dev_instance
+ *
+ * @return irqreturn_t
+ */
+irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance);
+
+/**
+ * non MSI-X interrupt handler
+ *
+ * @param irq
+ * @param dev_instance
+ *
+ * @return irqreturn_t
+ */
+irqreturn_t bnx2x_interrupt(int irq, void *dev_instance);
+#ifdef BCM_CNIC
+
+/**
+ * Send command to cnic driver
+ *
+ * @param bp
+ * @param cmd
+ */
+int bnx2x_cnic_notify(struct bnx2x *bp, int cmd);
+
+/**
+ * Provides cnic information for proper interrupt handling
+ *
+ * @param bp
+ */
+void bnx2x_setup_cnic_irq_info(struct bnx2x *bp);
+#endif
+
+/**
+ * Enable HW interrupts.
+ *
+ * @param bp
+ */
+void bnx2x_int_enable(struct bnx2x *bp);
+
+/**
+ * Disable interrupts. This function ensures that there are no
+ * ISRs or SP DPCs (sp_task) are running after it returns.
+ *
+ * @param bp
+ * @param disable_hw if true, disable HW interrupts.
+ */
+void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw);
+
+/**
+ * Init HW blocks according to current initialization stage:
+ * COMMON, PORT or FUNCTION.
+ *
+ * @param bp
+ * @param load_code: COMMON, PORT or FUNCTION
+ *
+ * @return int
+ */
+int bnx2x_init_hw(struct bnx2x *bp, u32 load_code);
+
+/**
+ * Init driver internals:
+ *  - rings
+ *  - status blocks
+ *  - etc.
+ *
+ * @param bp
+ * @param load_code COMMON, PORT or FUNCTION
+ */
+void bnx2x_nic_init(struct bnx2x *bp, u32 load_code);
+
+/**
+ * Allocate driver's memory.
+ *
+ * @param bp
+ *
+ * @return int
+ */
+int bnx2x_alloc_mem(struct bnx2x *bp);
+
+/**
+ * Release driver's memory.
+ *
+ * @param bp
+ */
+void bnx2x_free_mem(struct bnx2x *bp);
+
+/**
+ * Bring up a leading (the first) eth Client.
+ *
+ * @param bp
+ *
+ * @return int
+ */
+int bnx2x_setup_leading(struct bnx2x *bp);
+
+/**
+ * Setup non-leading eth Client.
+ *
+ * @param bp
+ * @param fp
+ *
+ * @return int
+ */
+int bnx2x_setup_multi(struct bnx2x *bp, int index);
+
+/**
+ * Set number of quueus according to mode and number of available
+ * msi-x vectors
+ *
+ * @param bp
+ *
+ */
+void bnx2x_set_num_queues_msix(struct bnx2x *bp);
+
+/**
+ * Cleanup chip internals:
+ * - Cleanup MAC configuration.
+ * - Close clients.
+ * - etc.
+ *
+ * @param bp
+ * @param unload_mode
+ */
+void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode);
+
+/**
+ * Acquire HW lock.
+ *
+ * @param bp
+ * @param resource Resource bit which was locked
+ *
+ * @return int
+ */
+int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource);
+
+/**
+ * Release HW lock.
+ *
+ * @param bp driver handle
+ * @param resource Resource bit which was locked
+ *
+ * @return int
+ */
+int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource);
+
+/**
+ * Configure eth MAC address in the HW according to the value in
+ * netdev->dev_addr for 57711
+ *
+ * @param bp driver handle
+ * @param set
+ */
+void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set);
+
+/**
+ * Configure eth MAC address in the HW according to the value in
+ * netdev->dev_addr for 57710
+ *
+ * @param bp driver handle
+ * @param set
+ */
+void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set);
+
+#ifdef BCM_CNIC
+/**
+ * Set iSCSI MAC(s) at the next enties in the CAM after the ETH
+ * MAC(s). The function will wait until the ramrod completion
+ * returns.
+ *
+ * @param bp driver handle
+ * @param set set or clear the CAM entry
+ *
+ * @return 0 if cussess, -ENODEV if ramrod doesn't return.
+ */
+int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set);
+#endif
+
+/**
+ * Initialize status block in FW and HW
+ *
+ * @param bp driver handle
+ * @param sb host_status_block
+ * @param dma_addr_t mapping
+ * @param int sb_id
+ */
+void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb,
+			  dma_addr_t mapping, int sb_id);
+
+/**
+ * Reconfigure FW/HW according to dev->flags rx mode
+ *
+ * @param dev net_device
+ *
+ */
+void bnx2x_set_rx_mode(struct net_device *dev);
+
+/**
+ * Configure MAC filtering rules in a FW.
+ *
+ * @param bp driver handle
+ */
+void bnx2x_set_storm_rx_mode(struct bnx2x *bp);
+
+/* Parity errors related */
+void bnx2x_inc_load_cnt(struct bnx2x *bp);
+u32 bnx2x_dec_load_cnt(struct bnx2x *bp);
+bool bnx2x_chk_parity_attn(struct bnx2x *bp);
+bool bnx2x_reset_is_done(struct bnx2x *bp);
+void bnx2x_disable_close_the_gate(struct bnx2x *bp);
+
+/**
+ * Perform statistics handling according to event
+ *
+ * @param bp driver handle
+ * @param even tbnx2x_stats_event
+ */
+void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
+
+/**
+ * Configures FW with client paramteres (like HW VLAN removal)
+ * for each active client.
+ *
+ * @param bp
+ */
+void bnx2x_set_client_config(struct bnx2x *bp);
+
+/**
+ * Handle sp events
+ *
+ * @param fp fastpath handle for the event
+ * @param rr_cqe eth_rx_cqe
+ */
+void bnx2x_sp_event(struct bnx2x_fastpath *fp,  union eth_rx_cqe *rr_cqe);
+
+
+static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
+{
+	struct host_status_block *fpsb = fp->status_blk;
+
+	barrier(); /* status block is written to by the chip */
+	fp->fp_c_idx = fpsb->c_status_block.status_block_index;
+	fp->fp_u_idx = fpsb->u_status_block.status_block_index;
+}
+
+static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
+					struct bnx2x_fastpath *fp,
+					u16 bd_prod, u16 rx_comp_prod,
+					u16 rx_sge_prod)
+{
+	struct ustorm_eth_rx_producers rx_prods = {0};
+	int i;
+
+	/* Update producers */
+	rx_prods.bd_prod = bd_prod;
+	rx_prods.cqe_prod = rx_comp_prod;
+	rx_prods.sge_prod = rx_sge_prod;
+
+	/*
+	 * Make sure that the BD and SGE data is updated before updating the
+	 * producers since FW might read the BD/SGE right after the producer
+	 * is updated.
+	 * This is only applicable for weak-ordered memory model archs such
+	 * as IA-64. The following barrier is also mandatory since FW will
+	 * assumes BDs must have buffers.
+	 */
+	wmb();
+
+	for (i = 0; i < sizeof(struct ustorm_eth_rx_producers)/4; i++)
+		REG_WR(bp, BAR_USTRORM_INTMEM +
+		       USTORM_RX_PRODS_OFFSET(BP_PORT(bp), fp->cl_id) + i*4,
+		       ((u32 *)&rx_prods)[i]);
+
+	mmiowb(); /* keep prod updates ordered */
+
+	DP(NETIF_MSG_RX_STATUS,
+	   "queue[%d]:  wrote  bd_prod %u  cqe_prod %u  sge_prod %u\n",
+	   fp->index, bd_prod, rx_comp_prod, rx_sge_prod);
+}
+
+
+
+static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
+				u8 storm, u16 index, u8 op, u8 update)
+{
+	u32 hc_addr = (HC_REG_COMMAND_REG + BP_PORT(bp)*32 +
+		       COMMAND_REG_INT_ACK);
+	struct igu_ack_register igu_ack;
+
+	igu_ack.status_block_index = index;
+	igu_ack.sb_id_and_flags =
+			((sb_id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) |
+			 (storm << IGU_ACK_REGISTER_STORM_ID_SHIFT) |
+			 (update << IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT) |
+			 (op << IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT));
+
+	DP(BNX2X_MSG_OFF, "write 0x%08x to HC addr 0x%x\n",
+	   (*(u32 *)&igu_ack), hc_addr);
+	REG_WR(bp, hc_addr, (*(u32 *)&igu_ack));
+
+	/* Make sure that ACK is written */
+	mmiowb();
+	barrier();
+}
+static inline u16 bnx2x_ack_int(struct bnx2x *bp)
+{
+	u32 hc_addr = (HC_REG_COMMAND_REG + BP_PORT(bp)*32 +
+		       COMMAND_REG_SIMD_MASK);
+	u32 result = REG_RD(bp, hc_addr);
+
+	DP(BNX2X_MSG_OFF, "read 0x%08x from HC addr 0x%x\n",
+	   result, hc_addr);
+
+	return result;
+}
+
+/*
+ * fast path service functions
+ */
+
+static inline int bnx2x_has_tx_work_unload(struct bnx2x_fastpath *fp)
+{
+	/* Tell compiler that consumer and producer can change */
+	barrier();
+	return (fp->tx_pkt_prod != fp->tx_pkt_cons);
+}
+
+static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp)
+{
+	s16 used;
+	u16 prod;
+	u16 cons;
+
+	prod = fp->tx_bd_prod;
+	cons = fp->tx_bd_cons;
+
+	/* NUM_TX_RINGS = number of "next-page" entries
+	   It will be used as a threshold */
+	used = SUB_S16(prod, cons) + (s16)NUM_TX_RINGS;
+
+#ifdef BNX2X_STOP_ON_ERROR
+	WARN_ON(used < 0);
+	WARN_ON(used > fp->bp->tx_ring_size);
+	WARN_ON((fp->bp->tx_ring_size - used) > MAX_TX_AVAIL);
+#endif
+
+	return (s16)(fp->bp->tx_ring_size) - used;
+}
+
+static inline int bnx2x_has_tx_work(struct bnx2x_fastpath *fp)
+{
+	u16 hw_cons;
+
+	/* Tell compiler that status block fields can change */
+	barrier();
+	hw_cons = le16_to_cpu(*fp->tx_cons_sb);
+	return hw_cons != fp->tx_pkt_cons;
+}
+
+static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
+				     struct bnx2x_fastpath *fp, u16 index)
+{
+	struct sw_rx_page *sw_buf = &fp->rx_page_ring[index];
+	struct page *page = sw_buf->page;
+	struct eth_rx_sge *sge = &fp->rx_sge_ring[index];
+
+	/* Skip "next page" elements */
+	if (!page)
+		return;
+
+	dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping),
+		       SGE_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE);
+	__free_pages(page, PAGES_PER_SGE_SHIFT);
+
+	sw_buf->page = NULL;
+	sge->addr_hi = 0;
+	sge->addr_lo = 0;
+}
+
+static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp,
+					   struct bnx2x_fastpath *fp, int last)
+{
+	int i;
+
+	for (i = 0; i < last; i++)
+		bnx2x_free_rx_sge(bp, fp, i);
+}
+
+static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp,
+				     struct bnx2x_fastpath *fp, u16 index)
+{
+	struct page *page = alloc_pages(GFP_ATOMIC, PAGES_PER_SGE_SHIFT);
+	struct sw_rx_page *sw_buf = &fp->rx_page_ring[index];
+	struct eth_rx_sge *sge = &fp->rx_sge_ring[index];
+	dma_addr_t mapping;
+
+	if (unlikely(page == NULL))
+		return -ENOMEM;
+
+	mapping = dma_map_page(&bp->pdev->dev, page, 0,
+			       SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
+	if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
+		__free_pages(page, PAGES_PER_SGE_SHIFT);
+		return -ENOMEM;
+	}
+
+	sw_buf->page = page;
+	dma_unmap_addr_set(sw_buf, mapping, mapping);
+
+	sge->addr_hi = cpu_to_le32(U64_HI(mapping));
+	sge->addr_lo = cpu_to_le32(U64_LO(mapping));
+
+	return 0;
+}
+static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
+				     struct bnx2x_fastpath *fp, u16 index)
+{
+	struct sk_buff *skb;
+	struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index];
+	struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index];
+	dma_addr_t mapping;
+
+	skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
+	if (unlikely(skb == NULL))
+		return -ENOMEM;
+
+	mapping = dma_map_single(&bp->pdev->dev, skb->data, bp->rx_buf_size,
+				 DMA_FROM_DEVICE);
+	if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
+		dev_kfree_skb(skb);
+		return -ENOMEM;
+	}
+
+	rx_buf->skb = skb;
+	dma_unmap_addr_set(rx_buf, mapping, mapping);
+
+	rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+	rx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+
+	return 0;
+}
+
+/* note that we are not allocating a new skb,
+ * we are just moving one from cons to prod
+ * we are not creating a new mapping,
+ * so there is no need to check for dma_mapping_error().
+ */
+static inline void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp,
+			       struct sk_buff *skb, u16 cons, u16 prod)
+{
+	struct bnx2x *bp = fp->bp;
+	struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons];
+	struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod];
+	struct eth_rx_bd *cons_bd = &fp->rx_desc_ring[cons];
+	struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod];
+
+	dma_sync_single_for_device(&bp->pdev->dev,
+				   dma_unmap_addr(cons_rx_buf, mapping),
+				   RX_COPY_THRESH, DMA_FROM_DEVICE);
+
+	prod_rx_buf->skb = cons_rx_buf->skb;
+	dma_unmap_addr_set(prod_rx_buf, mapping,
+			   dma_unmap_addr(cons_rx_buf, mapping));
+	*prod_bd = *cons_bd;
+}
+
+static inline void bnx2x_clear_sge_mask_next_elems(struct bnx2x_fastpath *fp)
+{
+	int i, j;
+
+	for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
+		int idx = RX_SGE_CNT * i - 1;
+
+		for (j = 0; j < 2; j++) {
+			SGE_MASK_CLEAR_BIT(fp, idx);
+			idx--;
+		}
+	}
+}
+
+static inline void bnx2x_init_sge_ring_bit_mask(struct bnx2x_fastpath *fp)
+{
+	/* Set the mask to all 1-s: it's faster to compare to 0 than to 0xf-s */
+	memset(fp->sge_mask, 0xff,
+	       (NUM_RX_SGE >> RX_SGE_MASK_ELEM_SHIFT)*sizeof(u64));
+
+	/* Clear the two last indices in the page to 1:
+	   these are the indices that correspond to the "next" element,
+	   hence will never be indicated and should be removed from
+	   the calculations. */
+	bnx2x_clear_sge_mask_next_elems(fp);
+}
+static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
+				       struct bnx2x_fastpath *fp, int last)
+{
+	int i;
+
+	for (i = 0; i < last; i++) {
+		struct sw_rx_bd *rx_buf = &(fp->tpa_pool[i]);
+		struct sk_buff *skb = rx_buf->skb;
+
+		if (skb == NULL) {
+			DP(NETIF_MSG_IFDOWN, "tpa bin %d empty on free\n", i);
+			continue;
+		}
+
+		if (fp->tpa_state[i] == BNX2X_TPA_START)
+			dma_unmap_single(&bp->pdev->dev,
+					 dma_unmap_addr(rx_buf, mapping),
+					 bp->rx_buf_size, DMA_FROM_DEVICE);
+
+		dev_kfree_skb(skb);
+		rx_buf->skb = NULL;
+	}
+}
+
+
+static inline void bnx2x_init_tx_ring(struct bnx2x *bp)
+{
+	int i, j;
+
+	for_each_queue(bp, j) {
+		struct bnx2x_fastpath *fp = &bp->fp[j];
+
+		for (i = 1; i <= NUM_TX_RINGS; i++) {
+			struct eth_tx_next_bd *tx_next_bd =
+				&fp->tx_desc_ring[TX_DESC_CNT * i - 1].next_bd;
+
+			tx_next_bd->addr_hi =
+				cpu_to_le32(U64_HI(fp->tx_desc_mapping +
+					    BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
+			tx_next_bd->addr_lo =
+				cpu_to_le32(U64_LO(fp->tx_desc_mapping +
+					    BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
+		}
+
+		fp->tx_db.data.header.header = DOORBELL_HDR_DB_TYPE;
+		fp->tx_db.data.zero_fill1 = 0;
+		fp->tx_db.data.prod = 0;
+
+		fp->tx_pkt_prod = 0;
+		fp->tx_pkt_cons = 0;
+		fp->tx_bd_prod = 0;
+		fp->tx_bd_cons = 0;
+		fp->tx_cons_sb = BNX2X_TX_SB_INDEX;
+		fp->tx_pkt = 0;
+	}
+}
+static inline int bnx2x_has_rx_work(struct bnx2x_fastpath *fp)
+{
+	u16 rx_cons_sb;
+
+	/* Tell compiler that status block fields can change */
+	barrier();
+	rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb);
+	if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
+		rx_cons_sb++;
+	return (fp->rx_comp_cons != rx_cons_sb);
+}
+
+/* HW Lock for shared dual port PHYs */
+void bnx2x_acquire_phy_lock(struct bnx2x *bp);
+void bnx2x_release_phy_lock(struct bnx2x *bp);
+
+void bnx2x_link_report(struct bnx2x *bp);
+int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget);
+int bnx2x_tx_int(struct bnx2x_fastpath *fp);
+void bnx2x_init_rx_rings(struct bnx2x *bp);
+netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+int bnx2x_change_mac_addr(struct net_device *dev, void *p);
+void bnx2x_tx_timeout(struct net_device *dev);
+void bnx2x_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp);
+void bnx2x_netif_start(struct bnx2x *bp);
+void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw);
+void bnx2x_free_irq(struct bnx2x *bp, bool disable_only);
+int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state);
+int bnx2x_resume(struct pci_dev *pdev);
+void bnx2x_free_skbs(struct bnx2x *bp);
+int bnx2x_change_mtu(struct net_device *dev, int new_mtu);
+int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode);
+int bnx2x_nic_load(struct bnx2x *bp, int load_mode);
+int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state);
+
+#endif /* BNX2X_CMN_H */
diff --git a/drivers/net/bnx2x_dump.h b/drivers/net/bnx2x/bnx2x_dump.h
similarity index 100%
rename from drivers/net/bnx2x_dump.h
rename to drivers/net/bnx2x/bnx2x_dump.h
diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c
new file mode 100644
index 0000000..8b75b05
--- /dev/null
+++ b/drivers/net/bnx2x/bnx2x_ethtool.c
@@ -0,0 +1,1971 @@
+/* bnx2x_ethtool.c: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007-2010 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
+ * Based on code from Michael Chan's bnx2 driver
+ * UDP CSUM errata workaround by Arik Gendelman
+ * Slowpath and fastpath rework by Vladislav Zolotarov
+ * Statistics and Link management by Yitchak Gertner
+ *
+ */
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/crc32.h>
+
+
+#include "bnx2x.h"
+#include "bnx2x_cmn.h"
+#include "bnx2x_dump.h"
+
+
+static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	cmd->supported = bp->port.supported;
+	cmd->advertising = bp->port.advertising;
+
+	if ((bp->state == BNX2X_STATE_OPEN) &&
+	    !(bp->flags & MF_FUNC_DIS) &&
+	    (bp->link_vars.link_up)) {
+		cmd->speed = bp->link_vars.line_speed;
+		cmd->duplex = bp->link_vars.duplex;
+		if (IS_E1HMF(bp)) {
+			u16 vn_max_rate;
+
+			vn_max_rate =
+				((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
+				FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
+			if (vn_max_rate < cmd->speed)
+				cmd->speed = vn_max_rate;
+		}
+	} else {
+		cmd->speed = -1;
+		cmd->duplex = -1;
+	}
+
+	if (bp->link_params.switch_cfg == SWITCH_CFG_10G) {
+		u32 ext_phy_type =
+			XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+
+		switch (ext_phy_type) {
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+			cmd->port = PORT_FIBRE;
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
+			cmd->port = PORT_TP;
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
+			BNX2X_ERR("XGXS PHY Failure detected 0x%x\n",
+				  bp->link_params.ext_phy_config);
+			break;
+
+		default:
+			DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
+			   bp->link_params.ext_phy_config);
+			break;
+		}
+	} else
+		cmd->port = PORT_TP;
+
+	cmd->phy_address = bp->mdio.prtad;
+	cmd->transceiver = XCVR_INTERNAL;
+
+	if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
+		cmd->autoneg = AUTONEG_ENABLE;
+	else
+		cmd->autoneg = AUTONEG_DISABLE;
+
+	cmd->maxtxpkt = 0;
+	cmd->maxrxpkt = 0;
+
+	DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
+	   DP_LEVEL "  supported 0x%x  advertising 0x%x  speed %d\n"
+	   DP_LEVEL "  duplex %d  port %d  phy_address %d  transceiver %d\n"
+	   DP_LEVEL "  autoneg %d  maxtxpkt %d  maxrxpkt %d\n",
+	   cmd->cmd, cmd->supported, cmd->advertising, cmd->speed,
+	   cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
+	   cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
+
+	return 0;
+}
+
+static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	u32 advertising;
+
+	if (IS_E1HMF(bp))
+		return 0;
+
+	DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
+	   DP_LEVEL "  supported 0x%x  advertising 0x%x  speed %d\n"
+	   DP_LEVEL "  duplex %d  port %d  phy_address %d  transceiver %d\n"
+	   DP_LEVEL "  autoneg %d  maxtxpkt %d  maxrxpkt %d\n",
+	   cmd->cmd, cmd->supported, cmd->advertising, cmd->speed,
+	   cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
+	   cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
+
+	if (cmd->autoneg == AUTONEG_ENABLE) {
+		if (!(bp->port.supported & SUPPORTED_Autoneg)) {
+			DP(NETIF_MSG_LINK, "Autoneg not supported\n");
+			return -EINVAL;
+		}
+
+		/* advertise the requested speed and duplex if supported */
+		cmd->advertising &= bp->port.supported;
+
+		bp->link_params.req_line_speed = SPEED_AUTO_NEG;
+		bp->link_params.req_duplex = DUPLEX_FULL;
+		bp->port.advertising |= (ADVERTISED_Autoneg |
+					 cmd->advertising);
+
+	} else { /* forced speed */
+		/* advertise the requested speed and duplex if supported */
+		switch (cmd->speed) {
+		case SPEED_10:
+			if (cmd->duplex == DUPLEX_FULL) {
+				if (!(bp->port.supported &
+				      SUPPORTED_10baseT_Full)) {
+					DP(NETIF_MSG_LINK,
+					   "10M full not supported\n");
+					return -EINVAL;
+				}
+
+				advertising = (ADVERTISED_10baseT_Full |
+					       ADVERTISED_TP);
+			} else {
+				if (!(bp->port.supported &
+				      SUPPORTED_10baseT_Half)) {
+					DP(NETIF_MSG_LINK,
+					   "10M half not supported\n");
+					return -EINVAL;
+				}
+
+				advertising = (ADVERTISED_10baseT_Half |
+					       ADVERTISED_TP);
+			}
+			break;
+
+		case SPEED_100:
+			if (cmd->duplex == DUPLEX_FULL) {
+				if (!(bp->port.supported &
+						SUPPORTED_100baseT_Full)) {
+					DP(NETIF_MSG_LINK,
+					   "100M full not supported\n");
+					return -EINVAL;
+				}
+
+				advertising = (ADVERTISED_100baseT_Full |
+					       ADVERTISED_TP);
+			} else {
+				if (!(bp->port.supported &
+						SUPPORTED_100baseT_Half)) {
+					DP(NETIF_MSG_LINK,
+					   "100M half not supported\n");
+					return -EINVAL;
+				}
+
+				advertising = (ADVERTISED_100baseT_Half |
+					       ADVERTISED_TP);
+			}
+			break;
+
+		case SPEED_1000:
+			if (cmd->duplex != DUPLEX_FULL) {
+				DP(NETIF_MSG_LINK, "1G half not supported\n");
+				return -EINVAL;
+			}
+
+			if (!(bp->port.supported & SUPPORTED_1000baseT_Full)) {
+				DP(NETIF_MSG_LINK, "1G full not supported\n");
+				return -EINVAL;
+			}
+
+			advertising = (ADVERTISED_1000baseT_Full |
+				       ADVERTISED_TP);
+			break;
+
+		case SPEED_2500:
+			if (cmd->duplex != DUPLEX_FULL) {
+				DP(NETIF_MSG_LINK,
+				   "2.5G half not supported\n");
+				return -EINVAL;
+			}
+
+			if (!(bp->port.supported & SUPPORTED_2500baseX_Full)) {
+				DP(NETIF_MSG_LINK,
+				   "2.5G full not supported\n");
+				return -EINVAL;
+			}
+
+			advertising = (ADVERTISED_2500baseX_Full |
+				       ADVERTISED_TP);
+			break;
+
+		case SPEED_10000:
+			if (cmd->duplex != DUPLEX_FULL) {
+				DP(NETIF_MSG_LINK, "10G half not supported\n");
+				return -EINVAL;
+			}
+
+			if (!(bp->port.supported & SUPPORTED_10000baseT_Full)) {
+				DP(NETIF_MSG_LINK, "10G full not supported\n");
+				return -EINVAL;
+			}
+
+			advertising = (ADVERTISED_10000baseT_Full |
+				       ADVERTISED_FIBRE);
+			break;
+
+		default:
+			DP(NETIF_MSG_LINK, "Unsupported speed\n");
+			return -EINVAL;
+		}
+
+		bp->link_params.req_line_speed = cmd->speed;
+		bp->link_params.req_duplex = cmd->duplex;
+		bp->port.advertising = advertising;
+	}
+
+	DP(NETIF_MSG_LINK, "req_line_speed %d\n"
+	   DP_LEVEL "  req_duplex %d  advertising 0x%x\n",
+	   bp->link_params.req_line_speed, bp->link_params.req_duplex,
+	   bp->port.advertising);
+
+	if (netif_running(dev)) {
+		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+		bnx2x_link_set(bp);
+	}
+
+	return 0;
+}
+
+#define IS_E1_ONLINE(info)	(((info) & RI_E1_ONLINE) == RI_E1_ONLINE)
+#define IS_E1H_ONLINE(info)	(((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE)
+
+static int bnx2x_get_regs_len(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int regdump_len = 0;
+	int i;
+
+	if (CHIP_IS_E1(bp)) {
+		for (i = 0; i < REGS_COUNT; i++)
+			if (IS_E1_ONLINE(reg_addrs[i].info))
+				regdump_len += reg_addrs[i].size;
+
+		for (i = 0; i < WREGS_COUNT_E1; i++)
+			if (IS_E1_ONLINE(wreg_addrs_e1[i].info))
+				regdump_len += wreg_addrs_e1[i].size *
+					(1 + wreg_addrs_e1[i].read_regs_count);
+
+	} else { /* E1H */
+		for (i = 0; i < REGS_COUNT; i++)
+			if (IS_E1H_ONLINE(reg_addrs[i].info))
+				regdump_len += reg_addrs[i].size;
+
+		for (i = 0; i < WREGS_COUNT_E1H; i++)
+			if (IS_E1H_ONLINE(wreg_addrs_e1h[i].info))
+				regdump_len += wreg_addrs_e1h[i].size *
+					(1 + wreg_addrs_e1h[i].read_regs_count);
+	}
+	regdump_len *= 4;
+	regdump_len += sizeof(struct dump_hdr);
+
+	return regdump_len;
+}
+
+static void bnx2x_get_regs(struct net_device *dev,
+			   struct ethtool_regs *regs, void *_p)
+{
+	u32 *p = _p, i, j;
+	struct bnx2x *bp = netdev_priv(dev);
+	struct dump_hdr dump_hdr = {0};
+
+	regs->version = 0;
+	memset(p, 0, regs->len);
+
+	if (!netif_running(bp->dev))
+		return;
+
+	dump_hdr.hdr_size = (sizeof(struct dump_hdr) / 4) - 1;
+	dump_hdr.dump_sign = dump_sign_all;
+	dump_hdr.xstorm_waitp = REG_RD(bp, XSTORM_WAITP_ADDR);
+	dump_hdr.tstorm_waitp = REG_RD(bp, TSTORM_WAITP_ADDR);
+	dump_hdr.ustorm_waitp = REG_RD(bp, USTORM_WAITP_ADDR);
+	dump_hdr.cstorm_waitp = REG_RD(bp, CSTORM_WAITP_ADDR);
+	dump_hdr.info = CHIP_IS_E1(bp) ? RI_E1_ONLINE : RI_E1H_ONLINE;
+
+	memcpy(p, &dump_hdr, sizeof(struct dump_hdr));
+	p += dump_hdr.hdr_size + 1;
+
+	if (CHIP_IS_E1(bp)) {
+		for (i = 0; i < REGS_COUNT; i++)
+			if (IS_E1_ONLINE(reg_addrs[i].info))
+				for (j = 0; j < reg_addrs[i].size; j++)
+					*p++ = REG_RD(bp,
+						      reg_addrs[i].addr + j*4);
+
+	} else { /* E1H */
+		for (i = 0; i < REGS_COUNT; i++)
+			if (IS_E1H_ONLINE(reg_addrs[i].info))
+				for (j = 0; j < reg_addrs[i].size; j++)
+					*p++ = REG_RD(bp,
+						      reg_addrs[i].addr + j*4);
+	}
+}
+
+#define PHY_FW_VER_LEN			10
+
+static void bnx2x_get_drvinfo(struct net_device *dev,
+			      struct ethtool_drvinfo *info)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	u8 phy_fw_ver[PHY_FW_VER_LEN];
+
+	strcpy(info->driver, DRV_MODULE_NAME);
+	strcpy(info->version, DRV_MODULE_VERSION);
+
+	phy_fw_ver[0] = '\0';
+	if (bp->port.pmf) {
+		bnx2x_acquire_phy_lock(bp);
+		bnx2x_get_ext_phy_fw_version(&bp->link_params,
+					     (bp->state != BNX2X_STATE_CLOSED),
+					     phy_fw_ver, PHY_FW_VER_LEN);
+		bnx2x_release_phy_lock(bp);
+	}
+
+	strncpy(info->fw_version, bp->fw_ver, 32);
+	snprintf(info->fw_version + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
+		 "bc %d.%d.%d%s%s",
+		 (bp->common.bc_ver & 0xff0000) >> 16,
+		 (bp->common.bc_ver & 0xff00) >> 8,
+		 (bp->common.bc_ver & 0xff),
+		 ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
+	strcpy(info->bus_info, pci_name(bp->pdev));
+	info->n_stats = BNX2X_NUM_STATS;
+	info->testinfo_len = BNX2X_NUM_TESTS;
+	info->eedump_len = bp->common.flash_size;
+	info->regdump_len = bnx2x_get_regs_len(dev);
+}
+
+static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (bp->flags & NO_WOL_FLAG) {
+		wol->supported = 0;
+		wol->wolopts = 0;
+	} else {
+		wol->supported = WAKE_MAGIC;
+		if (bp->wol)
+			wol->wolopts = WAKE_MAGIC;
+		else
+			wol->wolopts = 0;
+	}
+	memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (wol->wolopts & ~WAKE_MAGIC)
+		return -EINVAL;
+
+	if (wol->wolopts & WAKE_MAGIC) {
+		if (bp->flags & NO_WOL_FLAG)
+			return -EINVAL;
+
+		bp->wol = 1;
+	} else
+		bp->wol = 0;
+
+	return 0;
+}
+
+static u32 bnx2x_get_msglevel(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	return bp->msg_enable;
+}
+
+static void bnx2x_set_msglevel(struct net_device *dev, u32 level)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (capable(CAP_NET_ADMIN))
+		bp->msg_enable = level;
+}
+
+static int bnx2x_nway_reset(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (!bp->port.pmf)
+		return 0;
+
+	if (netif_running(dev)) {
+		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+		bnx2x_link_set(bp);
+	}
+
+	return 0;
+}
+
+static u32 bnx2x_get_link(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (bp->flags & MF_FUNC_DIS)
+		return 0;
+
+	return bp->link_vars.link_up;
+}
+
+static int bnx2x_get_eeprom_len(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	return bp->common.flash_size;
+}
+
+static int bnx2x_acquire_nvram_lock(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	int count, i;
+	u32 val = 0;
+
+	/* adjust timeout for emulation/FPGA */
+	count = NVRAM_TIMEOUT_COUNT;
+	if (CHIP_REV_IS_SLOW(bp))
+		count *= 100;
+
+	/* request access to nvram interface */
+	REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB,
+	       (MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port));
+
+	for (i = 0; i < count*10; i++) {
+		val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB);
+		if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))
+			break;
+
+		udelay(5);
+	}
+
+	if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) {
+		DP(BNX2X_MSG_NVM, "cannot get access to nvram interface\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int bnx2x_release_nvram_lock(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	int count, i;
+	u32 val = 0;
+
+	/* adjust timeout for emulation/FPGA */
+	count = NVRAM_TIMEOUT_COUNT;
+	if (CHIP_REV_IS_SLOW(bp))
+		count *= 100;
+
+	/* relinquish nvram interface */
+	REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB,
+	       (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << port));
+
+	for (i = 0; i < count*10; i++) {
+		val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB);
+		if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)))
+			break;
+
+		udelay(5);
+	}
+
+	if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) {
+		DP(BNX2X_MSG_NVM, "cannot free access to nvram interface\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void bnx2x_enable_nvram_access(struct bnx2x *bp)
+{
+	u32 val;
+
+	val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE);
+
+	/* enable both bits, even on read */
+	REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE,
+	       (val | MCPR_NVM_ACCESS_ENABLE_EN |
+		      MCPR_NVM_ACCESS_ENABLE_WR_EN));
+}
+
+static void bnx2x_disable_nvram_access(struct bnx2x *bp)
+{
+	u32 val;
+
+	val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE);
+
+	/* disable both bits, even after read */
+	REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE,
+	       (val & ~(MCPR_NVM_ACCESS_ENABLE_EN |
+			MCPR_NVM_ACCESS_ENABLE_WR_EN)));
+}
+
+static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, __be32 *ret_val,
+				  u32 cmd_flags)
+{
+	int count, i, rc;
+	u32 val;
+
+	/* build the command word */
+	cmd_flags |= MCPR_NVM_COMMAND_DOIT;
+
+	/* need to clear DONE bit separately */
+	REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
+
+	/* address of the NVRAM to read from */
+	REG_WR(bp, MCP_REG_MCPR_NVM_ADDR,
+	       (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE));
+
+	/* issue a read command */
+	REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
+
+	/* adjust timeout for emulation/FPGA */
+	count = NVRAM_TIMEOUT_COUNT;
+	if (CHIP_REV_IS_SLOW(bp))
+		count *= 100;
+
+	/* wait for completion */
+	*ret_val = 0;
+	rc = -EBUSY;
+	for (i = 0; i < count; i++) {
+		udelay(5);
+		val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND);
+
+		if (val & MCPR_NVM_COMMAND_DONE) {
+			val = REG_RD(bp, MCP_REG_MCPR_NVM_READ);
+			/* we read nvram data in cpu order
+			 * but ethtool sees it as an array of bytes
+			 * converting to big-endian will do the work */
+			*ret_val = cpu_to_be32(val);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf,
+			    int buf_size)
+{
+	int rc;
+	u32 cmd_flags;
+	__be32 val;
+
+	if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) {
+		DP(BNX2X_MSG_NVM,
+		   "Invalid parameter: offset 0x%x  buf_size 0x%x\n",
+		   offset, buf_size);
+		return -EINVAL;
+	}
+
+	if (offset + buf_size > bp->common.flash_size) {
+		DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +"
+				  " buf_size (0x%x) > flash_size (0x%x)\n",
+		   offset, buf_size, bp->common.flash_size);
+		return -EINVAL;
+	}
+
+	/* request access to nvram interface */
+	rc = bnx2x_acquire_nvram_lock(bp);
+	if (rc)
+		return rc;
+
+	/* enable access to nvram interface */
+	bnx2x_enable_nvram_access(bp);
+
+	/* read the first word(s) */
+	cmd_flags = MCPR_NVM_COMMAND_FIRST;
+	while ((buf_size > sizeof(u32)) && (rc == 0)) {
+		rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags);
+		memcpy(ret_buf, &val, 4);
+
+		/* advance to the next dword */
+		offset += sizeof(u32);
+		ret_buf += sizeof(u32);
+		buf_size -= sizeof(u32);
+		cmd_flags = 0;
+	}
+
+	if (rc == 0) {
+		cmd_flags |= MCPR_NVM_COMMAND_LAST;
+		rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags);
+		memcpy(ret_buf, &val, 4);
+	}
+
+	/* disable access to nvram interface */
+	bnx2x_disable_nvram_access(bp);
+	bnx2x_release_nvram_lock(bp);
+
+	return rc;
+}
+
+static int bnx2x_get_eeprom(struct net_device *dev,
+			    struct ethtool_eeprom *eeprom, u8 *eebuf)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int rc;
+
+	if (!netif_running(dev))
+		return -EAGAIN;
+
+	DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n"
+	   DP_LEVEL "  magic 0x%x  offset 0x%x (%d)  len 0x%x (%d)\n",
+	   eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset,
+	   eeprom->len, eeprom->len);
+
+	/* parameters already validated in ethtool_get_eeprom */
+
+	rc = bnx2x_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
+
+	return rc;
+}
+
+static int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val,
+				   u32 cmd_flags)
+{
+	int count, i, rc;
+
+	/* build the command word */
+	cmd_flags |= MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WR;
+
+	/* need to clear DONE bit separately */
+	REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
+
+	/* write the data */
+	REG_WR(bp, MCP_REG_MCPR_NVM_WRITE, val);
+
+	/* address of the NVRAM to write to */
+	REG_WR(bp, MCP_REG_MCPR_NVM_ADDR,
+	       (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE));
+
+	/* issue the write command */
+	REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
+
+	/* adjust timeout for emulation/FPGA */
+	count = NVRAM_TIMEOUT_COUNT;
+	if (CHIP_REV_IS_SLOW(bp))
+		count *= 100;
+
+	/* wait for completion */
+	rc = -EBUSY;
+	for (i = 0; i < count; i++) {
+		udelay(5);
+		val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND);
+		if (val & MCPR_NVM_COMMAND_DONE) {
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+#define BYTE_OFFSET(offset)		(8 * (offset & 0x03))
+
+static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf,
+			      int buf_size)
+{
+	int rc;
+	u32 cmd_flags;
+	u32 align_offset;
+	__be32 val;
+
+	if (offset + buf_size > bp->common.flash_size) {
+		DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +"
+				  " buf_size (0x%x) > flash_size (0x%x)\n",
+		   offset, buf_size, bp->common.flash_size);
+		return -EINVAL;
+	}
+
+	/* request access to nvram interface */
+	rc = bnx2x_acquire_nvram_lock(bp);
+	if (rc)
+		return rc;
+
+	/* enable access to nvram interface */
+	bnx2x_enable_nvram_access(bp);
+
+	cmd_flags = (MCPR_NVM_COMMAND_FIRST | MCPR_NVM_COMMAND_LAST);
+	align_offset = (offset & ~0x03);
+	rc = bnx2x_nvram_read_dword(bp, align_offset, &val, cmd_flags);
+
+	if (rc == 0) {
+		val &= ~(0xff << BYTE_OFFSET(offset));
+		val |= (*data_buf << BYTE_OFFSET(offset));
+
+		/* nvram data is returned as an array of bytes
+		 * convert it back to cpu order */
+		val = be32_to_cpu(val);
+
+		rc = bnx2x_nvram_write_dword(bp, align_offset, val,
+					     cmd_flags);
+	}
+
+	/* disable access to nvram interface */
+	bnx2x_disable_nvram_access(bp);
+	bnx2x_release_nvram_lock(bp);
+
+	return rc;
+}
+
+static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf,
+			     int buf_size)
+{
+	int rc;
+	u32 cmd_flags;
+	u32 val;
+	u32 written_so_far;
+
+	if (buf_size == 1)	/* ethtool */
+		return bnx2x_nvram_write1(bp, offset, data_buf, buf_size);
+
+	if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) {
+		DP(BNX2X_MSG_NVM,
+		   "Invalid parameter: offset 0x%x  buf_size 0x%x\n",
+		   offset, buf_size);
+		return -EINVAL;
+	}
+
+	if (offset + buf_size > bp->common.flash_size) {
+		DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +"
+				  " buf_size (0x%x) > flash_size (0x%x)\n",
+		   offset, buf_size, bp->common.flash_size);
+		return -EINVAL;
+	}
+
+	/* request access to nvram interface */
+	rc = bnx2x_acquire_nvram_lock(bp);
+	if (rc)
+		return rc;
+
+	/* enable access to nvram interface */
+	bnx2x_enable_nvram_access(bp);
+
+	written_so_far = 0;
+	cmd_flags = MCPR_NVM_COMMAND_FIRST;
+	while ((written_so_far < buf_size) && (rc == 0)) {
+		if (written_so_far == (buf_size - sizeof(u32)))
+			cmd_flags |= MCPR_NVM_COMMAND_LAST;
+		else if (((offset + 4) % NVRAM_PAGE_SIZE) == 0)
+			cmd_flags |= MCPR_NVM_COMMAND_LAST;
+		else if ((offset % NVRAM_PAGE_SIZE) == 0)
+			cmd_flags |= MCPR_NVM_COMMAND_FIRST;
+
+		memcpy(&val, data_buf, 4);
+
+		rc = bnx2x_nvram_write_dword(bp, offset, val, cmd_flags);
+
+		/* advance to the next dword */
+		offset += sizeof(u32);
+		data_buf += sizeof(u32);
+		written_so_far += sizeof(u32);
+		cmd_flags = 0;
+	}
+
+	/* disable access to nvram interface */
+	bnx2x_disable_nvram_access(bp);
+	bnx2x_release_nvram_lock(bp);
+
+	return rc;
+}
+
+static int bnx2x_set_eeprom(struct net_device *dev,
+			    struct ethtool_eeprom *eeprom, u8 *eebuf)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int port = BP_PORT(bp);
+	int rc = 0;
+
+	if (!netif_running(dev))
+		return -EAGAIN;
+
+	DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n"
+	   DP_LEVEL "  magic 0x%x  offset 0x%x (%d)  len 0x%x (%d)\n",
+	   eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset,
+	   eeprom->len, eeprom->len);
+
+	/* parameters already validated in ethtool_set_eeprom */
+
+	/* PHY eeprom can be accessed only by the PMF */
+	if ((eeprom->magic >= 0x50485900) && (eeprom->magic <= 0x504859FF) &&
+	    !bp->port.pmf)
+		return -EINVAL;
+
+	if (eeprom->magic == 0x50485950) {
+		/* 'PHYP' (0x50485950): prepare phy for FW upgrade */
+		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+
+		bnx2x_acquire_phy_lock(bp);
+		rc |= bnx2x_link_reset(&bp->link_params,
+				       &bp->link_vars, 0);
+		if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+					PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101)
+			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
+				       MISC_REGISTERS_GPIO_HIGH, port);
+		bnx2x_release_phy_lock(bp);
+		bnx2x_link_report(bp);
+
+	} else if (eeprom->magic == 0x50485952) {
+		/* 'PHYR' (0x50485952): re-init link after FW upgrade */
+		if (bp->state == BNX2X_STATE_OPEN) {
+			bnx2x_acquire_phy_lock(bp);
+			rc |= bnx2x_link_reset(&bp->link_params,
+					       &bp->link_vars, 1);
+
+			rc |= bnx2x_phy_init(&bp->link_params,
+					     &bp->link_vars);
+			bnx2x_release_phy_lock(bp);
+			bnx2x_calc_fc_adv(bp);
+		}
+	} else if (eeprom->magic == 0x53985943) {
+		/* 'PHYC' (0x53985943): PHY FW upgrade completed */
+		if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+				       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) {
+			u8 ext_phy_addr =
+			     XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config);
+
+			/* DSP Remove Download Mode */
+			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
+				       MISC_REGISTERS_GPIO_LOW, port);
+
+			bnx2x_acquire_phy_lock(bp);
+
+			bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
+
+			/* wait 0.5 sec to allow it to run */
+			msleep(500);
+			bnx2x_ext_phy_hw_reset(bp, port);
+			msleep(500);
+			bnx2x_release_phy_lock(bp);
+		}
+	} else
+		rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
+
+	return rc;
+}
+static int bnx2x_get_coalesce(struct net_device *dev,
+			      struct ethtool_coalesce *coal)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	memset(coal, 0, sizeof(struct ethtool_coalesce));
+
+	coal->rx_coalesce_usecs = bp->rx_ticks;
+	coal->tx_coalesce_usecs = bp->tx_ticks;
+
+	return 0;
+}
+
+static int bnx2x_set_coalesce(struct net_device *dev,
+			      struct ethtool_coalesce *coal)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	bp->rx_ticks = (u16)coal->rx_coalesce_usecs;
+	if (bp->rx_ticks > BNX2X_MAX_COALESCE_TOUT)
+		bp->rx_ticks = BNX2X_MAX_COALESCE_TOUT;
+
+	bp->tx_ticks = (u16)coal->tx_coalesce_usecs;
+	if (bp->tx_ticks > BNX2X_MAX_COALESCE_TOUT)
+		bp->tx_ticks = BNX2X_MAX_COALESCE_TOUT;
+
+	if (netif_running(dev))
+		bnx2x_update_coalesce(bp);
+
+	return 0;
+}
+
+static void bnx2x_get_ringparam(struct net_device *dev,
+				struct ethtool_ringparam *ering)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	ering->rx_max_pending = MAX_RX_AVAIL;
+	ering->rx_mini_max_pending = 0;
+	ering->rx_jumbo_max_pending = 0;
+
+	ering->rx_pending = bp->rx_ring_size;
+	ering->rx_mini_pending = 0;
+	ering->rx_jumbo_pending = 0;
+
+	ering->tx_max_pending = MAX_TX_AVAIL;
+	ering->tx_pending = bp->tx_ring_size;
+}
+
+static int bnx2x_set_ringparam(struct net_device *dev,
+			       struct ethtool_ringparam *ering)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int rc = 0;
+
+	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+		return -EAGAIN;
+	}
+
+	if ((ering->rx_pending > MAX_RX_AVAIL) ||
+	    (ering->tx_pending > MAX_TX_AVAIL) ||
+	    (ering->tx_pending <= MAX_SKB_FRAGS + 4))
+		return -EINVAL;
+
+	bp->rx_ring_size = ering->rx_pending;
+	bp->tx_ring_size = ering->tx_pending;
+
+	if (netif_running(dev)) {
+		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+		rc = bnx2x_nic_load(bp, LOAD_NORMAL);
+	}
+
+	return rc;
+}
+
+static void bnx2x_get_pauseparam(struct net_device *dev,
+				 struct ethtool_pauseparam *epause)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	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 & 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",
+	   epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause);
+}
+
+static int bnx2x_set_pauseparam(struct net_device *dev,
+				struct ethtool_pauseparam *epause)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (IS_E1HMF(bp))
+		return 0;
+
+	DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n"
+	   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 = BNX2X_FLOW_CTRL_AUTO;
+
+	if (epause->rx_pause)
+		bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_RX;
+
+	if (epause->tx_pause)
+		bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_TX;
+
+	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)) {
+			DP(NETIF_MSG_LINK, "autoneg not supported\n");
+			return -EINVAL;
+		}
+
+		if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
+			bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
+	}
+
+	DP(NETIF_MSG_LINK,
+	   "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl);
+
+	if (netif_running(dev)) {
+		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+		bnx2x_link_set(bp);
+	}
+
+	return 0;
+}
+
+static int bnx2x_set_flags(struct net_device *dev, u32 data)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int changed = 0;
+	int rc = 0;
+
+	if (data & ~(ETH_FLAG_LRO | ETH_FLAG_RXHASH))
+		return -EINVAL;
+
+	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+		return -EAGAIN;
+	}
+
+	/* TPA requires Rx CSUM offloading */
+	if ((data & ETH_FLAG_LRO) && bp->rx_csum) {
+		if (!bp->disable_tpa) {
+			if (!(dev->features & NETIF_F_LRO)) {
+				dev->features |= NETIF_F_LRO;
+				bp->flags |= TPA_ENABLE_FLAG;
+				changed = 1;
+			}
+		} else
+			rc = -EINVAL;
+	} else if (dev->features & NETIF_F_LRO) {
+		dev->features &= ~NETIF_F_LRO;
+		bp->flags &= ~TPA_ENABLE_FLAG;
+		changed = 1;
+	}
+
+	if (data & ETH_FLAG_RXHASH)
+		dev->features |= NETIF_F_RXHASH;
+	else
+		dev->features &= ~NETIF_F_RXHASH;
+
+	if (changed && netif_running(dev)) {
+		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+		rc = bnx2x_nic_load(bp, LOAD_NORMAL);
+	}
+
+	return rc;
+}
+
+static u32 bnx2x_get_rx_csum(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	return bp->rx_csum;
+}
+
+static int bnx2x_set_rx_csum(struct net_device *dev, u32 data)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int rc = 0;
+
+	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+		return -EAGAIN;
+	}
+
+	bp->rx_csum = data;
+
+	/* Disable TPA, when Rx CSUM is disabled. Otherwise all
+	   TPA'ed packets will be discarded due to wrong TCP CSUM */
+	if (!data) {
+		u32 flags = ethtool_op_get_flags(dev);
+
+		rc = bnx2x_set_flags(dev, (flags & ~ETH_FLAG_LRO));
+	}
+
+	return rc;
+}
+
+static int bnx2x_set_tso(struct net_device *dev, u32 data)
+{
+	if (data) {
+		dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+		dev->features |= NETIF_F_TSO6;
+	} else {
+		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
+		dev->features &= ~NETIF_F_TSO6;
+	}
+
+	return 0;
+}
+
+static const struct {
+	char string[ETH_GSTRING_LEN];
+} bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = {
+	{ "register_test (offline)" },
+	{ "memory_test (offline)" },
+	{ "loopback_test (offline)" },
+	{ "nvram_test (online)" },
+	{ "interrupt_test (online)" },
+	{ "link_test (online)" },
+	{ "idle check (online)" }
+};
+
+static int bnx2x_test_registers(struct bnx2x *bp)
+{
+	int idx, i, rc = -ENODEV;
+	u32 wr_val = 0;
+	int port = BP_PORT(bp);
+	static const struct {
+		u32 offset0;
+		u32 offset1;
+		u32 mask;
+	} reg_tbl[] = {
+/* 0 */		{ BRB1_REG_PAUSE_LOW_THRESHOLD_0,      4, 0x000003ff },
+		{ DORQ_REG_DB_ADDR0,                   4, 0xffffffff },
+		{ HC_REG_AGG_INT_0,                    4, 0x000003ff },
+		{ PBF_REG_MAC_IF0_ENABLE,              4, 0x00000001 },
+		{ PBF_REG_P0_INIT_CRD,                 4, 0x000007ff },
+		{ PRS_REG_CID_PORT_0,                  4, 0x00ffffff },
+		{ PXP2_REG_PSWRQ_CDU0_L2P,             4, 0x000fffff },
+		{ PXP2_REG_RQ_CDU0_EFIRST_MEM_ADDR,    8, 0x0003ffff },
+		{ PXP2_REG_PSWRQ_TM0_L2P,              4, 0x000fffff },
+		{ PXP2_REG_RQ_USDM0_EFIRST_MEM_ADDR,   8, 0x0003ffff },
+/* 10 */	{ PXP2_REG_PSWRQ_TSDM0_L2P,            4, 0x000fffff },
+		{ QM_REG_CONNNUM_0,                    4, 0x000fffff },
+		{ TM_REG_LIN0_MAX_ACTIVE_CID,          4, 0x0003ffff },
+		{ SRC_REG_KEYRSS0_0,                  40, 0xffffffff },
+		{ SRC_REG_KEYRSS0_7,                  40, 0xffffffff },
+		{ XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 4, 0x00000001 },
+		{ XCM_REG_WU_DA_CNT_CMD00,             4, 0x00000003 },
+		{ XCM_REG_GLB_DEL_ACK_MAX_CNT_0,       4, 0x000000ff },
+		{ NIG_REG_LLH0_T_BIT,                  4, 0x00000001 },
+		{ NIG_REG_EMAC0_IN_EN,                 4, 0x00000001 },
+/* 20 */	{ NIG_REG_BMAC0_IN_EN,                 4, 0x00000001 },
+		{ NIG_REG_XCM0_OUT_EN,                 4, 0x00000001 },
+		{ NIG_REG_BRB0_OUT_EN,                 4, 0x00000001 },
+		{ NIG_REG_LLH0_XCM_MASK,               4, 0x00000007 },
+		{ NIG_REG_LLH0_ACPI_PAT_6_LEN,        68, 0x000000ff },
+		{ NIG_REG_LLH0_ACPI_PAT_0_CRC,        68, 0xffffffff },
+		{ NIG_REG_LLH0_DEST_MAC_0_0,         160, 0xffffffff },
+		{ NIG_REG_LLH0_DEST_IP_0_1,          160, 0xffffffff },
+		{ NIG_REG_LLH0_IPV4_IPV6_0,          160, 0x00000001 },
+		{ NIG_REG_LLH0_DEST_UDP_0,           160, 0x0000ffff },
+/* 30 */	{ NIG_REG_LLH0_DEST_TCP_0,           160, 0x0000ffff },
+		{ NIG_REG_LLH0_VLAN_ID_0,            160, 0x00000fff },
+		{ NIG_REG_XGXS_SERDES0_MODE_SEL,       4, 0x00000001 },
+		{ NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0, 4, 0x00000001 },
+		{ NIG_REG_STATUS_INTERRUPT_PORT0,      4, 0x07ffffff },
+		{ NIG_REG_XGXS0_CTRL_EXTREMOTEMDIOST, 24, 0x00000001 },
+		{ NIG_REG_SERDES0_CTRL_PHY_ADDR,      16, 0x0000001f },
+
+		{ 0xffffffff, 0, 0x00000000 }
+	};
+
+	if (!netif_running(bp->dev))
+		return rc;
+
+	/* Repeat the test twice:
+	   First by writing 0x00000000, second by writing 0xffffffff */
+	for (idx = 0; idx < 2; idx++) {
+
+		switch (idx) {
+		case 0:
+			wr_val = 0;
+			break;
+		case 1:
+			wr_val = 0xffffffff;
+			break;
+		}
+
+		for (i = 0; reg_tbl[i].offset0 != 0xffffffff; i++) {
+			u32 offset, mask, save_val, val;
+
+			offset = reg_tbl[i].offset0 + port*reg_tbl[i].offset1;
+			mask = reg_tbl[i].mask;
+
+			save_val = REG_RD(bp, offset);
+
+			REG_WR(bp, offset, (wr_val & mask));
+			val = REG_RD(bp, offset);
+
+			/* Restore the original register's value */
+			REG_WR(bp, offset, save_val);
+
+			/* verify value is as expected */
+			if ((val & mask) != (wr_val & mask)) {
+				DP(NETIF_MSG_PROBE,
+				   "offset 0x%x: val 0x%x != 0x%x mask 0x%x\n",
+				   offset, val, wr_val, mask);
+				goto test_reg_exit;
+			}
+		}
+	}
+
+	rc = 0;
+
+test_reg_exit:
+	return rc;
+}
+
+static int bnx2x_test_memory(struct bnx2x *bp)
+{
+	int i, j, rc = -ENODEV;
+	u32 val;
+	static const struct {
+		u32 offset;
+		int size;
+	} mem_tbl[] = {
+		{ CCM_REG_XX_DESCR_TABLE,   CCM_REG_XX_DESCR_TABLE_SIZE },
+		{ CFC_REG_ACTIVITY_COUNTER, CFC_REG_ACTIVITY_COUNTER_SIZE },
+		{ CFC_REG_LINK_LIST,        CFC_REG_LINK_LIST_SIZE },
+		{ DMAE_REG_CMD_MEM,         DMAE_REG_CMD_MEM_SIZE },
+		{ TCM_REG_XX_DESCR_TABLE,   TCM_REG_XX_DESCR_TABLE_SIZE },
+		{ UCM_REG_XX_DESCR_TABLE,   UCM_REG_XX_DESCR_TABLE_SIZE },
+		{ XCM_REG_XX_DESCR_TABLE,   XCM_REG_XX_DESCR_TABLE_SIZE },
+
+		{ 0xffffffff, 0 }
+	};
+	static const struct {
+		char *name;
+		u32 offset;
+		u32 e1_mask;
+		u32 e1h_mask;
+	} prty_tbl[] = {
+		{ "CCM_PRTY_STS",  CCM_REG_CCM_PRTY_STS,   0x3ffc0, 0 },
+		{ "CFC_PRTY_STS",  CFC_REG_CFC_PRTY_STS,   0x2,     0x2 },
+		{ "DMAE_PRTY_STS", DMAE_REG_DMAE_PRTY_STS, 0,       0 },
+		{ "TCM_PRTY_STS",  TCM_REG_TCM_PRTY_STS,   0x3ffc0, 0 },
+		{ "UCM_PRTY_STS",  UCM_REG_UCM_PRTY_STS,   0x3ffc0, 0 },
+		{ "XCM_PRTY_STS",  XCM_REG_XCM_PRTY_STS,   0x3ffc1, 0 },
+
+		{ NULL, 0xffffffff, 0, 0 }
+	};
+
+	if (!netif_running(bp->dev))
+		return rc;
+
+	/* Go through all the memories */
+	for (i = 0; mem_tbl[i].offset != 0xffffffff; i++)
+		for (j = 0; j < mem_tbl[i].size; j++)
+			REG_RD(bp, mem_tbl[i].offset + j*4);
+
+	/* Check the parity status */
+	for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) {
+		val = REG_RD(bp, prty_tbl[i].offset);
+		if ((CHIP_IS_E1(bp) && (val & ~(prty_tbl[i].e1_mask))) ||
+		    (CHIP_IS_E1H(bp) && (val & ~(prty_tbl[i].e1h_mask)))) {
+			DP(NETIF_MSG_HW,
+			   "%s is 0x%x\n", prty_tbl[i].name, val);
+			goto test_mem_exit;
+		}
+	}
+
+	rc = 0;
+
+test_mem_exit:
+	return rc;
+}
+
+static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up)
+{
+	int cnt = 1000;
+
+	if (link_up)
+		while (bnx2x_link_test(bp) && cnt--)
+			msleep(10);
+}
+
+static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
+{
+	unsigned int pkt_size, num_pkts, i;
+	struct sk_buff *skb;
+	unsigned char *packet;
+	struct bnx2x_fastpath *fp_rx = &bp->fp[0];
+	struct bnx2x_fastpath *fp_tx = &bp->fp[0];
+	u16 tx_start_idx, tx_idx;
+	u16 rx_start_idx, rx_idx;
+	u16 pkt_prod, bd_prod;
+	struct sw_tx_bd *tx_buf;
+	struct eth_tx_start_bd *tx_start_bd;
+	struct eth_tx_parse_bd *pbd = NULL;
+	dma_addr_t mapping;
+	union eth_rx_cqe *cqe;
+	u8 cqe_fp_flags;
+	struct sw_rx_bd *rx_buf;
+	u16 len;
+	int rc = -ENODEV;
+
+	/* check the loopback mode */
+	switch (loopback_mode) {
+	case BNX2X_PHY_LOOPBACK:
+		if (bp->link_params.loopback_mode != LOOPBACK_XGXS_10)
+			return -EINVAL;
+		break;
+	case BNX2X_MAC_LOOPBACK:
+		bp->link_params.loopback_mode = LOOPBACK_BMAC;
+		bnx2x_phy_init(&bp->link_params, &bp->link_vars);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* prepare the loopback packet */
+	pkt_size = (((bp->dev->mtu < ETH_MAX_PACKET_SIZE) ?
+		     bp->dev->mtu : ETH_MAX_PACKET_SIZE) + ETH_HLEN);
+	skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
+	if (!skb) {
+		rc = -ENOMEM;
+		goto test_loopback_exit;
+	}
+	packet = skb_put(skb, pkt_size);
+	memcpy(packet, bp->dev->dev_addr, ETH_ALEN);
+	memset(packet + ETH_ALEN, 0, ETH_ALEN);
+	memset(packet + 2*ETH_ALEN, 0x77, (ETH_HLEN - 2*ETH_ALEN));
+	for (i = ETH_HLEN; i < pkt_size; i++)
+		packet[i] = (unsigned char) (i & 0xff);
+
+	/* send the loopback packet */
+	num_pkts = 0;
+	tx_start_idx = le16_to_cpu(*fp_tx->tx_cons_sb);
+	rx_start_idx = le16_to_cpu(*fp_rx->rx_cons_sb);
+
+	pkt_prod = fp_tx->tx_pkt_prod++;
+	tx_buf = &fp_tx->tx_buf_ring[TX_BD(pkt_prod)];
+	tx_buf->first_bd = fp_tx->tx_bd_prod;
+	tx_buf->skb = skb;
+	tx_buf->flags = 0;
+
+	bd_prod = TX_BD(fp_tx->tx_bd_prod);
+	tx_start_bd = &fp_tx->tx_desc_ring[bd_prod].start_bd;
+	mapping = dma_map_single(&bp->pdev->dev, skb->data,
+				 skb_headlen(skb), DMA_TO_DEVICE);
+	tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+	tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+	tx_start_bd->nbd = cpu_to_le16(2); /* start + pbd */
+	tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb));
+	tx_start_bd->vlan = cpu_to_le16(pkt_prod);
+	tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
+	tx_start_bd->general_data = ((UNICAST_ADDRESS <<
+				ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT) | 1);
+
+	/* turn on parsing and get a BD */
+	bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+	pbd = &fp_tx->tx_desc_ring[bd_prod].parse_bd;
+
+	memset(pbd, 0, sizeof(struct eth_tx_parse_bd));
+
+	wmb();
+
+	fp_tx->tx_db.data.prod += 2;
+	barrier();
+	DOORBELL(bp, fp_tx->index, fp_tx->tx_db.raw);
+
+	mmiowb();
+
+	num_pkts++;
+	fp_tx->tx_bd_prod += 2; /* start + pbd */
+
+	udelay(100);
+
+	tx_idx = le16_to_cpu(*fp_tx->tx_cons_sb);
+	if (tx_idx != tx_start_idx + num_pkts)
+		goto test_loopback_exit;
+
+	rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb);
+	if (rx_idx != rx_start_idx + num_pkts)
+		goto test_loopback_exit;
+
+	cqe = &fp_rx->rx_comp_ring[RCQ_BD(fp_rx->rx_comp_cons)];
+	cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
+	if (CQE_TYPE(cqe_fp_flags) || (cqe_fp_flags & ETH_RX_ERROR_FALGS))
+		goto test_loopback_rx_exit;
+
+	len = le16_to_cpu(cqe->fast_path_cqe.pkt_len);
+	if (len != pkt_size)
+		goto test_loopback_rx_exit;
+
+	rx_buf = &fp_rx->rx_buf_ring[RX_BD(fp_rx->rx_bd_cons)];
+	skb = rx_buf->skb;
+	skb_reserve(skb, cqe->fast_path_cqe.placement_offset);
+	for (i = ETH_HLEN; i < pkt_size; i++)
+		if (*(skb->data + i) != (unsigned char) (i & 0xff))
+			goto test_loopback_rx_exit;
+
+	rc = 0;
+
+test_loopback_rx_exit:
+
+	fp_rx->rx_bd_cons = NEXT_RX_IDX(fp_rx->rx_bd_cons);
+	fp_rx->rx_bd_prod = NEXT_RX_IDX(fp_rx->rx_bd_prod);
+	fp_rx->rx_comp_cons = NEXT_RCQ_IDX(fp_rx->rx_comp_cons);
+	fp_rx->rx_comp_prod = NEXT_RCQ_IDX(fp_rx->rx_comp_prod);
+
+	/* Update producers */
+	bnx2x_update_rx_prod(bp, fp_rx, fp_rx->rx_bd_prod, fp_rx->rx_comp_prod,
+			     fp_rx->rx_sge_prod);
+
+test_loopback_exit:
+	bp->link_params.loopback_mode = LOOPBACK_NONE;
+
+	return rc;
+}
+
+static int bnx2x_test_loopback(struct bnx2x *bp, u8 link_up)
+{
+	int rc = 0, res;
+
+	if (BP_NOMCP(bp))
+		return rc;
+
+	if (!netif_running(bp->dev))
+		return BNX2X_LOOPBACK_FAILED;
+
+	bnx2x_netif_stop(bp, 1);
+	bnx2x_acquire_phy_lock(bp);
+
+	res = bnx2x_run_loopback(bp, BNX2X_PHY_LOOPBACK, link_up);
+	if (res) {
+		DP(NETIF_MSG_PROBE, "  PHY loopback failed  (res %d)\n", res);
+		rc |= BNX2X_PHY_LOOPBACK_FAILED;
+	}
+
+	res = bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK, link_up);
+	if (res) {
+		DP(NETIF_MSG_PROBE, "  MAC loopback failed  (res %d)\n", res);
+		rc |= BNX2X_MAC_LOOPBACK_FAILED;
+	}
+
+	bnx2x_release_phy_lock(bp);
+	bnx2x_netif_start(bp);
+
+	return rc;
+}
+
+#define CRC32_RESIDUAL			0xdebb20e3
+
+static int bnx2x_test_nvram(struct bnx2x *bp)
+{
+	static const struct {
+		int offset;
+		int size;
+	} nvram_tbl[] = {
+		{     0,  0x14 }, /* bootstrap */
+		{  0x14,  0xec }, /* dir */
+		{ 0x100, 0x350 }, /* manuf_info */
+		{ 0x450,  0xf0 }, /* feature_info */
+		{ 0x640,  0x64 }, /* upgrade_key_info */
+		{ 0x6a4,  0x64 },
+		{ 0x708,  0x70 }, /* manuf_key_info */
+		{ 0x778,  0x70 },
+		{     0,     0 }
+	};
+	__be32 buf[0x350 / 4];
+	u8 *data = (u8 *)buf;
+	int i, rc;
+	u32 magic, crc;
+
+	if (BP_NOMCP(bp))
+		return 0;
+
+	rc = bnx2x_nvram_read(bp, 0, data, 4);
+	if (rc) {
+		DP(NETIF_MSG_PROBE, "magic value read (rc %d)\n", rc);
+		goto test_nvram_exit;
+	}
+
+	magic = be32_to_cpu(buf[0]);
+	if (magic != 0x669955aa) {
+		DP(NETIF_MSG_PROBE, "magic value (0x%08x)\n", magic);
+		rc = -ENODEV;
+		goto test_nvram_exit;
+	}
+
+	for (i = 0; nvram_tbl[i].size; i++) {
+
+		rc = bnx2x_nvram_read(bp, nvram_tbl[i].offset, data,
+				      nvram_tbl[i].size);
+		if (rc) {
+			DP(NETIF_MSG_PROBE,
+			   "nvram_tbl[%d] read data (rc %d)\n", i, rc);
+			goto test_nvram_exit;
+		}
+
+		crc = ether_crc_le(nvram_tbl[i].size, data);
+		if (crc != CRC32_RESIDUAL) {
+			DP(NETIF_MSG_PROBE,
+			   "nvram_tbl[%d] crc value (0x%08x)\n", i, crc);
+			rc = -ENODEV;
+			goto test_nvram_exit;
+		}
+	}
+
+test_nvram_exit:
+	return rc;
+}
+
+static int bnx2x_test_intr(struct bnx2x *bp)
+{
+	struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config);
+	int i, rc;
+
+	if (!netif_running(bp->dev))
+		return -ENODEV;
+
+	config->hdr.length = 0;
+	if (CHIP_IS_E1(bp))
+		/* use last unicast entries */
+		config->hdr.offset = (BP_PORT(bp) ? 63 : 31);
+	else
+		config->hdr.offset = BP_FUNC(bp);
+	config->hdr.client_id = bp->fp->cl_id;
+	config->hdr.reserved1 = 0;
+
+	bp->set_mac_pending++;
+	smp_wmb();
+	rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
+			   U64_HI(bnx2x_sp_mapping(bp, mac_config)),
+			   U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
+	if (rc == 0) {
+		for (i = 0; i < 10; i++) {
+			if (!bp->set_mac_pending)
+				break;
+			smp_rmb();
+			msleep_interruptible(10);
+		}
+		if (i == 10)
+			rc = -ENODEV;
+	}
+
+	return rc;
+}
+
+static void bnx2x_self_test(struct net_device *dev,
+			    struct ethtool_test *etest, u64 *buf)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+		etest->flags |= ETH_TEST_FL_FAILED;
+		return;
+	}
+
+	memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS);
+
+	if (!netif_running(dev))
+		return;
+
+	/* offline tests are not supported in MF mode */
+	if (IS_E1HMF(bp))
+		etest->flags &= ~ETH_TEST_FL_OFFLINE;
+
+	if (etest->flags & ETH_TEST_FL_OFFLINE) {
+		int port = BP_PORT(bp);
+		u32 val;
+		u8 link_up;
+
+		/* save current value of input enable for TX port IF */
+		val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4);
+		/* disable input for TX port IF */
+		REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
+
+		link_up = (bnx2x_link_test(bp) == 0);
+		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+		bnx2x_nic_load(bp, LOAD_DIAG);
+		/* wait until link state is restored */
+		bnx2x_wait_for_link(bp, link_up);
+
+		if (bnx2x_test_registers(bp) != 0) {
+			buf[0] = 1;
+			etest->flags |= ETH_TEST_FL_FAILED;
+		}
+		if (bnx2x_test_memory(bp) != 0) {
+			buf[1] = 1;
+			etest->flags |= ETH_TEST_FL_FAILED;
+		}
+		buf[2] = bnx2x_test_loopback(bp, link_up);
+		if (buf[2] != 0)
+			etest->flags |= ETH_TEST_FL_FAILED;
+
+		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+
+		/* restore input for TX port IF */
+		REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, val);
+
+		bnx2x_nic_load(bp, LOAD_NORMAL);
+		/* wait until link state is restored */
+		bnx2x_wait_for_link(bp, link_up);
+	}
+	if (bnx2x_test_nvram(bp) != 0) {
+		buf[3] = 1;
+		etest->flags |= ETH_TEST_FL_FAILED;
+	}
+	if (bnx2x_test_intr(bp) != 0) {
+		buf[4] = 1;
+		etest->flags |= ETH_TEST_FL_FAILED;
+	}
+	if (bp->port.pmf)
+		if (bnx2x_link_test(bp) != 0) {
+			buf[5] = 1;
+			etest->flags |= ETH_TEST_FL_FAILED;
+		}
+
+#ifdef BNX2X_EXTRA_DEBUG
+	bnx2x_panic_dump(bp);
+#endif
+}
+
+static const struct {
+	long offset;
+	int size;
+	u8 string[ETH_GSTRING_LEN];
+} bnx2x_q_stats_arr[BNX2X_NUM_Q_STATS] = {
+/* 1 */	{ Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%d]: rx_bytes" },
+	{ Q_STATS_OFFSET32(error_bytes_received_hi),
+						8, "[%d]: rx_error_bytes" },
+	{ Q_STATS_OFFSET32(total_unicast_packets_received_hi),
+						8, "[%d]: rx_ucast_packets" },
+	{ Q_STATS_OFFSET32(total_multicast_packets_received_hi),
+						8, "[%d]: rx_mcast_packets" },
+	{ Q_STATS_OFFSET32(total_broadcast_packets_received_hi),
+						8, "[%d]: rx_bcast_packets" },
+	{ Q_STATS_OFFSET32(no_buff_discard_hi),	8, "[%d]: rx_discards" },
+	{ Q_STATS_OFFSET32(rx_err_discard_pkt),
+					 4, "[%d]: rx_phy_ip_err_discards"},
+	{ Q_STATS_OFFSET32(rx_skb_alloc_failed),
+					 4, "[%d]: rx_skb_alloc_discard" },
+	{ Q_STATS_OFFSET32(hw_csum_err), 4, "[%d]: rx_csum_offload_errors" },
+
+/* 10 */{ Q_STATS_OFFSET32(total_bytes_transmitted_hi),	8, "[%d]: tx_bytes" },
+	{ Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi),
+						8, "[%d]: tx_ucast_packets" },
+	{ Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi),
+						8, "[%d]: tx_mcast_packets" },
+	{ Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
+						8, "[%d]: tx_bcast_packets" }
+};
+
+static const struct {
+	long offset;
+	int size;
+	u32 flags;
+#define STATS_FLAGS_PORT		1
+#define STATS_FLAGS_FUNC		2
+#define STATS_FLAGS_BOTH		(STATS_FLAGS_FUNC | STATS_FLAGS_PORT)
+	u8 string[ETH_GSTRING_LEN];
+} bnx2x_stats_arr[BNX2X_NUM_STATS] = {
+/* 1 */	{ STATS_OFFSET32(total_bytes_received_hi),
+				8, STATS_FLAGS_BOTH, "rx_bytes" },
+	{ STATS_OFFSET32(error_bytes_received_hi),
+				8, STATS_FLAGS_BOTH, "rx_error_bytes" },
+	{ STATS_OFFSET32(total_unicast_packets_received_hi),
+				8, STATS_FLAGS_BOTH, "rx_ucast_packets" },
+	{ STATS_OFFSET32(total_multicast_packets_received_hi),
+				8, STATS_FLAGS_BOTH, "rx_mcast_packets" },
+	{ STATS_OFFSET32(total_broadcast_packets_received_hi),
+				8, STATS_FLAGS_BOTH, "rx_bcast_packets" },
+	{ STATS_OFFSET32(rx_stat_dot3statsfcserrors_hi),
+				8, STATS_FLAGS_PORT, "rx_crc_errors" },
+	{ STATS_OFFSET32(rx_stat_dot3statsalignmenterrors_hi),
+				8, STATS_FLAGS_PORT, "rx_align_errors" },
+	{ STATS_OFFSET32(rx_stat_etherstatsundersizepkts_hi),
+				8, STATS_FLAGS_PORT, "rx_undersize_packets" },
+	{ STATS_OFFSET32(etherstatsoverrsizepkts_hi),
+				8, STATS_FLAGS_PORT, "rx_oversize_packets" },
+/* 10 */{ STATS_OFFSET32(rx_stat_etherstatsfragments_hi),
+				8, STATS_FLAGS_PORT, "rx_fragments" },
+	{ STATS_OFFSET32(rx_stat_etherstatsjabbers_hi),
+				8, STATS_FLAGS_PORT, "rx_jabbers" },
+	{ STATS_OFFSET32(no_buff_discard_hi),
+				8, STATS_FLAGS_BOTH, "rx_discards" },
+	{ STATS_OFFSET32(mac_filter_discard),
+				4, STATS_FLAGS_PORT, "rx_filtered_packets" },
+	{ STATS_OFFSET32(xxoverflow_discard),
+				4, STATS_FLAGS_PORT, "rx_fw_discards" },
+	{ STATS_OFFSET32(brb_drop_hi),
+				8, STATS_FLAGS_PORT, "rx_brb_discard" },
+	{ STATS_OFFSET32(brb_truncate_hi),
+				8, STATS_FLAGS_PORT, "rx_brb_truncate" },
+	{ STATS_OFFSET32(pause_frames_received_hi),
+				8, STATS_FLAGS_PORT, "rx_pause_frames" },
+	{ STATS_OFFSET32(rx_stat_maccontrolframesreceived_hi),
+				8, STATS_FLAGS_PORT, "rx_mac_ctrl_frames" },
+	{ STATS_OFFSET32(nig_timer_max),
+			4, STATS_FLAGS_PORT, "rx_constant_pause_events" },
+/* 20 */{ STATS_OFFSET32(rx_err_discard_pkt),
+				4, STATS_FLAGS_BOTH, "rx_phy_ip_err_discards"},
+	{ STATS_OFFSET32(rx_skb_alloc_failed),
+				4, STATS_FLAGS_BOTH, "rx_skb_alloc_discard" },
+	{ STATS_OFFSET32(hw_csum_err),
+				4, STATS_FLAGS_BOTH, "rx_csum_offload_errors" },
+
+	{ STATS_OFFSET32(total_bytes_transmitted_hi),
+				8, STATS_FLAGS_BOTH, "tx_bytes" },
+	{ STATS_OFFSET32(tx_stat_ifhcoutbadoctets_hi),
+				8, STATS_FLAGS_PORT, "tx_error_bytes" },
+	{ STATS_OFFSET32(total_unicast_packets_transmitted_hi),
+				8, STATS_FLAGS_BOTH, "tx_ucast_packets" },
+	{ STATS_OFFSET32(total_multicast_packets_transmitted_hi),
+				8, STATS_FLAGS_BOTH, "tx_mcast_packets" },
+	{ STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
+				8, STATS_FLAGS_BOTH, "tx_bcast_packets" },
+	{ STATS_OFFSET32(tx_stat_dot3statsinternalmactransmiterrors_hi),
+				8, STATS_FLAGS_PORT, "tx_mac_errors" },
+	{ STATS_OFFSET32(rx_stat_dot3statscarriersenseerrors_hi),
+				8, STATS_FLAGS_PORT, "tx_carrier_errors" },
+/* 30 */{ STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi),
+				8, STATS_FLAGS_PORT, "tx_single_collisions" },
+	{ STATS_OFFSET32(tx_stat_dot3statsmultiplecollisionframes_hi),
+				8, STATS_FLAGS_PORT, "tx_multi_collisions" },
+	{ STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi),
+				8, STATS_FLAGS_PORT, "tx_deferred" },
+	{ STATS_OFFSET32(tx_stat_dot3statsexcessivecollisions_hi),
+				8, STATS_FLAGS_PORT, "tx_excess_collisions" },
+	{ STATS_OFFSET32(tx_stat_dot3statslatecollisions_hi),
+				8, STATS_FLAGS_PORT, "tx_late_collisions" },
+	{ STATS_OFFSET32(tx_stat_etherstatscollisions_hi),
+				8, STATS_FLAGS_PORT, "tx_total_collisions" },
+	{ STATS_OFFSET32(tx_stat_etherstatspkts64octets_hi),
+				8, STATS_FLAGS_PORT, "tx_64_byte_packets" },
+	{ STATS_OFFSET32(tx_stat_etherstatspkts65octetsto127octets_hi),
+			8, STATS_FLAGS_PORT, "tx_65_to_127_byte_packets" },
+	{ STATS_OFFSET32(tx_stat_etherstatspkts128octetsto255octets_hi),
+			8, STATS_FLAGS_PORT, "tx_128_to_255_byte_packets" },
+	{ STATS_OFFSET32(tx_stat_etherstatspkts256octetsto511octets_hi),
+			8, STATS_FLAGS_PORT, "tx_256_to_511_byte_packets" },
+/* 40 */{ STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi),
+			8, STATS_FLAGS_PORT, "tx_512_to_1023_byte_packets" },
+	{ STATS_OFFSET32(etherstatspkts1024octetsto1522octets_hi),
+			8, STATS_FLAGS_PORT, "tx_1024_to_1522_byte_packets" },
+	{ STATS_OFFSET32(etherstatspktsover1522octets_hi),
+			8, STATS_FLAGS_PORT, "tx_1523_to_9022_byte_packets" },
+	{ STATS_OFFSET32(pause_frames_sent_hi),
+				8, STATS_FLAGS_PORT, "tx_pause_frames" }
+};
+
+#define IS_PORT_STAT(i) \
+	((bnx2x_stats_arr[i].flags & STATS_FLAGS_BOTH) == STATS_FLAGS_PORT)
+#define IS_FUNC_STAT(i)		(bnx2x_stats_arr[i].flags & STATS_FLAGS_FUNC)
+#define IS_E1HMF_MODE_STAT(bp) \
+			(IS_E1HMF(bp) && !(bp->msg_enable & BNX2X_MSG_STATS))
+
+static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int i, num_stats;
+
+	switch (stringset) {
+	case ETH_SS_STATS:
+		if (is_multi(bp)) {
+			num_stats = BNX2X_NUM_Q_STATS * bp->num_queues;
+			if (!IS_E1HMF_MODE_STAT(bp))
+				num_stats += BNX2X_NUM_STATS;
+		} else {
+			if (IS_E1HMF_MODE_STAT(bp)) {
+				num_stats = 0;
+				for (i = 0; i < BNX2X_NUM_STATS; i++)
+					if (IS_FUNC_STAT(i))
+						num_stats++;
+			} else
+				num_stats = BNX2X_NUM_STATS;
+		}
+		return num_stats;
+
+	case ETH_SS_TEST:
+		return BNX2X_NUM_TESTS;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int i, j, k;
+
+	switch (stringset) {
+	case ETH_SS_STATS:
+		if (is_multi(bp)) {
+			k = 0;
+			for_each_queue(bp, i) {
+				for (j = 0; j < BNX2X_NUM_Q_STATS; j++)
+					sprintf(buf + (k + j)*ETH_GSTRING_LEN,
+						bnx2x_q_stats_arr[j].string, i);
+				k += BNX2X_NUM_Q_STATS;
+			}
+			if (IS_E1HMF_MODE_STAT(bp))
+				break;
+			for (j = 0; j < BNX2X_NUM_STATS; j++)
+				strcpy(buf + (k + j)*ETH_GSTRING_LEN,
+				       bnx2x_stats_arr[j].string);
+		} else {
+			for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
+				if (IS_E1HMF_MODE_STAT(bp) && IS_PORT_STAT(i))
+					continue;
+				strcpy(buf + j*ETH_GSTRING_LEN,
+				       bnx2x_stats_arr[i].string);
+				j++;
+			}
+		}
+		break;
+
+	case ETH_SS_TEST:
+		memcpy(buf, bnx2x_tests_str_arr, sizeof(bnx2x_tests_str_arr));
+		break;
+	}
+}
+
+static void bnx2x_get_ethtool_stats(struct net_device *dev,
+				    struct ethtool_stats *stats, u64 *buf)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	u32 *hw_stats, *offset;
+	int i, j, k;
+
+	if (is_multi(bp)) {
+		k = 0;
+		for_each_queue(bp, i) {
+			hw_stats = (u32 *)&bp->fp[i].eth_q_stats;
+			for (j = 0; j < BNX2X_NUM_Q_STATS; j++) {
+				if (bnx2x_q_stats_arr[j].size == 0) {
+					/* skip this counter */
+					buf[k + j] = 0;
+					continue;
+				}
+				offset = (hw_stats +
+					  bnx2x_q_stats_arr[j].offset);
+				if (bnx2x_q_stats_arr[j].size == 4) {
+					/* 4-byte counter */
+					buf[k + j] = (u64) *offset;
+					continue;
+				}
+				/* 8-byte counter */
+				buf[k + j] = HILO_U64(*offset, *(offset + 1));
+			}
+			k += BNX2X_NUM_Q_STATS;
+		}
+		if (IS_E1HMF_MODE_STAT(bp))
+			return;
+		hw_stats = (u32 *)&bp->eth_stats;
+		for (j = 0; j < BNX2X_NUM_STATS; j++) {
+			if (bnx2x_stats_arr[j].size == 0) {
+				/* skip this counter */
+				buf[k + j] = 0;
+				continue;
+			}
+			offset = (hw_stats + bnx2x_stats_arr[j].offset);
+			if (bnx2x_stats_arr[j].size == 4) {
+				/* 4-byte counter */
+				buf[k + j] = (u64) *offset;
+				continue;
+			}
+			/* 8-byte counter */
+			buf[k + j] = HILO_U64(*offset, *(offset + 1));
+		}
+	} else {
+		hw_stats = (u32 *)&bp->eth_stats;
+		for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
+			if (IS_E1HMF_MODE_STAT(bp) && IS_PORT_STAT(i))
+				continue;
+			if (bnx2x_stats_arr[i].size == 0) {
+				/* skip this counter */
+				buf[j] = 0;
+				j++;
+				continue;
+			}
+			offset = (hw_stats + bnx2x_stats_arr[i].offset);
+			if (bnx2x_stats_arr[i].size == 4) {
+				/* 4-byte counter */
+				buf[j] = (u64) *offset;
+				j++;
+				continue;
+			}
+			/* 8-byte counter */
+			buf[j] = HILO_U64(*offset, *(offset + 1));
+			j++;
+		}
+	}
+}
+
+static int bnx2x_phys_id(struct net_device *dev, u32 data)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int i;
+
+	if (!netif_running(dev))
+		return 0;
+
+	if (!bp->port.pmf)
+		return 0;
+
+	if (data == 0)
+		data = 2;
+
+	for (i = 0; i < (data * 2); i++) {
+		if ((i % 2) == 0)
+			bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
+				      SPEED_1000);
+		else
+			bnx2x_set_led(&bp->link_params, LED_MODE_OFF, 0);
+
+		msleep_interruptible(500);
+		if (signal_pending(current))
+			break;
+	}
+
+	if (bp->link_vars.link_up)
+		bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
+			      bp->link_vars.line_speed);
+
+	return 0;
+}
+
+static const struct ethtool_ops bnx2x_ethtool_ops = {
+	.get_settings		= bnx2x_get_settings,
+	.set_settings		= bnx2x_set_settings,
+	.get_drvinfo		= bnx2x_get_drvinfo,
+	.get_regs_len		= bnx2x_get_regs_len,
+	.get_regs		= bnx2x_get_regs,
+	.get_wol		= bnx2x_get_wol,
+	.set_wol		= bnx2x_set_wol,
+	.get_msglevel		= bnx2x_get_msglevel,
+	.set_msglevel		= bnx2x_set_msglevel,
+	.nway_reset		= bnx2x_nway_reset,
+	.get_link		= bnx2x_get_link,
+	.get_eeprom_len		= bnx2x_get_eeprom_len,
+	.get_eeprom		= bnx2x_get_eeprom,
+	.set_eeprom		= bnx2x_set_eeprom,
+	.get_coalesce		= bnx2x_get_coalesce,
+	.set_coalesce		= bnx2x_set_coalesce,
+	.get_ringparam		= bnx2x_get_ringparam,
+	.set_ringparam		= bnx2x_set_ringparam,
+	.get_pauseparam		= bnx2x_get_pauseparam,
+	.set_pauseparam		= bnx2x_set_pauseparam,
+	.get_rx_csum		= bnx2x_get_rx_csum,
+	.set_rx_csum		= bnx2x_set_rx_csum,
+	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.set_tx_csum		= ethtool_op_set_tx_hw_csum,
+	.set_flags		= bnx2x_set_flags,
+	.get_flags		= ethtool_op_get_flags,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= ethtool_op_set_sg,
+	.get_tso		= ethtool_op_get_tso,
+	.set_tso		= bnx2x_set_tso,
+	.self_test		= bnx2x_self_test,
+	.get_sset_count		= bnx2x_get_sset_count,
+	.get_strings		= bnx2x_get_strings,
+	.phys_id		= bnx2x_phys_id,
+	.get_ethtool_stats	= bnx2x_get_ethtool_stats,
+};
+
+void bnx2x_set_ethtool_ops(struct net_device *netdev)
+{
+	SET_ETHTOOL_OPS(netdev, &bnx2x_ethtool_ops);
+}
diff --git a/drivers/net/bnx2x_fw_defs.h b/drivers/net/bnx2x/bnx2x_fw_defs.h
similarity index 100%
rename from drivers/net/bnx2x_fw_defs.h
rename to drivers/net/bnx2x/bnx2x_fw_defs.h
diff --git a/drivers/net/bnx2x_fw_file_hdr.h b/drivers/net/bnx2x/bnx2x_fw_file_hdr.h
similarity index 100%
rename from drivers/net/bnx2x_fw_file_hdr.h
rename to drivers/net/bnx2x/bnx2x_fw_file_hdr.h
diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h
similarity index 100%
rename from drivers/net/bnx2x_hsi.h
rename to drivers/net/bnx2x/bnx2x_hsi.h
diff --git a/drivers/net/bnx2x_init.h b/drivers/net/bnx2x/bnx2x_init.h
similarity index 100%
rename from drivers/net/bnx2x_init.h
rename to drivers/net/bnx2x/bnx2x_init.h
diff --git a/drivers/net/bnx2x_init_ops.h b/drivers/net/bnx2x/bnx2x_init_ops.h
similarity index 100%
rename from drivers/net/bnx2x_init_ops.h
rename to drivers/net/bnx2x/bnx2x_init_ops.h
diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c
similarity index 99%
rename from drivers/net/bnx2x_link.c
rename to drivers/net/bnx2x/bnx2x_link.c
index ff70be8..0383e30 100644
--- a/drivers/net/bnx2x_link.c
+++ b/drivers/net/bnx2x/bnx2x_link.c
@@ -4266,14 +4266,16 @@
 					       MDIO_PMA_REG_10G_CTRL2, 0x0008);
 			}
 
-			/* Set 2-wire transfer rate to 400Khz since 100Khz
-			is not operational */
+			/* Set 2-wire transfer rate of SFP+ module EEPROM
+			 * to 100Khz since some DACs(direct attached cables) do
+			 * not work at 400Khz.
+			 */
 			bnx2x_cl45_write(bp, params->port,
 				       ext_phy_type,
 				       ext_phy_addr,
 				       MDIO_PMA_DEVAD,
 				       MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
-				       0xa101);
+				       0xa001);
 
 			/* Set TX PreEmphasis if needed */
 			if ((params->feature_config_flags &
diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x/bnx2x_link.h
similarity index 100%
rename from drivers/net/bnx2x_link.h
rename to drivers/net/bnx2x/bnx2x_link.h
diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c
new file mode 100644
index 0000000..b4ec2b0
--- /dev/null
+++ b/drivers/net/bnx2x/bnx2x_main.c
@@ -0,0 +1,8040 @@
+/* bnx2x_main.c: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007-2010 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
+ * Based on code from Michael Chan's bnx2 driver
+ * UDP CSUM errata workaround by Arik Gendelman
+ * Slowpath and fastpath rework by Vladislav Zolotarov
+ * Statistics and Link management by Yitchak Gertner
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/device.h>  /* for dev_info() */
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+#include <linux/time.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include <linux/workqueue.h>
+#include <linux/crc32.h>
+#include <linux/crc32c.h>
+#include <linux/prefetch.h>
+#include <linux/zlib.h>
+#include <linux/io.h>
+#include <linux/stringify.h>
+
+#define BNX2X_MAIN
+#include "bnx2x.h"
+#include "bnx2x_init.h"
+#include "bnx2x_init_ops.h"
+#include "bnx2x_cmn.h"
+
+
+#include <linux/firmware.h>
+#include "bnx2x_fw_file_hdr.h"
+/* FW files */
+#define FW_FILE_VERSION					\
+	__stringify(BCM_5710_FW_MAJOR_VERSION) "."	\
+	__stringify(BCM_5710_FW_MINOR_VERSION) "."	\
+	__stringify(BCM_5710_FW_REVISION_VERSION) "."	\
+	__stringify(BCM_5710_FW_ENGINEERING_VERSION)
+#define FW_FILE_NAME_E1		"bnx2x-e1-" FW_FILE_VERSION ".fw"
+#define FW_FILE_NAME_E1H	"bnx2x-e1h-" FW_FILE_VERSION ".fw"
+
+/* Time in jiffies before concluding the transmitter is hung */
+#define TX_TIMEOUT		(5*HZ)
+
+static char version[] __devinitdata =
+	"Broadcom NetXtreme II 5771x 10Gigabit Ethernet Driver "
+	DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("Eliezer Tamir");
+MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710/57711/57711E Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+MODULE_FIRMWARE(FW_FILE_NAME_E1);
+MODULE_FIRMWARE(FW_FILE_NAME_E1H);
+
+static int multi_mode = 1;
+module_param(multi_mode, int, 0);
+MODULE_PARM_DESC(multi_mode, " Multi queue mode "
+			     "(0 Disable; 1 Enable (default))");
+
+static int num_queues;
+module_param(num_queues, int, 0);
+MODULE_PARM_DESC(num_queues, " Number of queues for multi_mode=1"
+				" (default is as a number of CPUs)");
+
+static int disable_tpa;
+module_param(disable_tpa, int, 0);
+MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature");
+
+static int int_mode;
+module_param(int_mode, int, 0);
+MODULE_PARM_DESC(int_mode, " Force interrupt mode other then MSI-X "
+				"(1 INT#x; 2 MSI)");
+
+static int dropless_fc;
+module_param(dropless_fc, int, 0);
+MODULE_PARM_DESC(dropless_fc, " Pause on exhausted host ring");
+
+static int poll;
+module_param(poll, int, 0);
+MODULE_PARM_DESC(poll, " Use polling (for debug)");
+
+static int mrrs = -1;
+module_param(mrrs, int, 0);
+MODULE_PARM_DESC(mrrs, " Force Max Read Req Size (0..3) (for debug)");
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, " Default debug msglevel");
+
+static struct workqueue_struct *bnx2x_wq;
+
+enum bnx2x_board_type {
+	BCM57710 = 0,
+	BCM57711 = 1,
+	BCM57711E = 2,
+};
+
+/* indexed by board_type, above */
+static struct {
+	char *name;
+} board_info[] __devinitdata = {
+	{ "Broadcom NetXtreme II BCM57710 XGb" },
+	{ "Broadcom NetXtreme II BCM57711 XGb" },
+	{ "Broadcom NetXtreme II BCM57711E XGb" }
+};
+
+
+static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = {
+	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 },
+	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 },
+	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E },
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl);
+
+/****************************************************************************
+* General service functions
+****************************************************************************/
+
+/* used only at init
+ * locking is done by mcp
+ */
+void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val)
+{
+	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
+	pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val);
+	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
+			       PCICFG_VENDOR_ID_OFFSET);
+}
+
+static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr)
+{
+	u32 val;
+
+	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
+	pci_read_config_dword(bp->pdev, PCICFG_GRC_DATA, &val);
+	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
+			       PCICFG_VENDOR_ID_OFFSET);
+
+	return val;
+}
+
+const u32 dmae_reg_go_c[] = {
+	DMAE_REG_GO_C0, DMAE_REG_GO_C1, DMAE_REG_GO_C2, DMAE_REG_GO_C3,
+	DMAE_REG_GO_C4, DMAE_REG_GO_C5, DMAE_REG_GO_C6, DMAE_REG_GO_C7,
+	DMAE_REG_GO_C8, DMAE_REG_GO_C9, DMAE_REG_GO_C10, DMAE_REG_GO_C11,
+	DMAE_REG_GO_C12, DMAE_REG_GO_C13, DMAE_REG_GO_C14, DMAE_REG_GO_C15
+};
+
+/* copy command into DMAE command memory and set DMAE command go */
+void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx)
+{
+	u32 cmd_offset;
+	int i;
+
+	cmd_offset = (DMAE_REG_CMD_MEM + sizeof(struct dmae_command) * idx);
+	for (i = 0; i < (sizeof(struct dmae_command)/4); i++) {
+		REG_WR(bp, cmd_offset + i*4, *(((u32 *)dmae) + i));
+
+		DP(BNX2X_MSG_OFF, "DMAE cmd[%d].%d (0x%08x) : 0x%08x\n",
+		   idx, i, cmd_offset + i*4, *(((u32 *)dmae) + i));
+	}
+	REG_WR(bp, dmae_reg_go_c[idx], 1);
+}
+
+void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
+		      u32 len32)
+{
+	struct dmae_command dmae;
+	u32 *wb_comp = bnx2x_sp(bp, wb_comp);
+	int cnt = 200;
+
+	if (!bp->dmae_ready) {
+		u32 *data = bnx2x_sp(bp, wb_data[0]);
+
+		DP(BNX2X_MSG_OFF, "DMAE is not ready (dst_addr %08x  len32 %d)"
+		   "  using indirect\n", dst_addr, len32);
+		bnx2x_init_ind_wr(bp, dst_addr, data, len32);
+		return;
+	}
+
+	memset(&dmae, 0, sizeof(struct dmae_command));
+
+	dmae.opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+		       DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+		       DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+		       DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+		       DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+		       (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+		       (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+	dmae.src_addr_lo = U64_LO(dma_addr);
+	dmae.src_addr_hi = U64_HI(dma_addr);
+	dmae.dst_addr_lo = dst_addr >> 2;
+	dmae.dst_addr_hi = 0;
+	dmae.len = len32;
+	dmae.comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
+	dmae.comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
+	dmae.comp_val = DMAE_COMP_VAL;
+
+	DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n"
+	   DP_LEVEL "src_addr  [%x:%08x]  len [%d *4]  "
+		    "dst_addr [%x:%08x (%08x)]\n"
+	   DP_LEVEL "comp_addr [%x:%08x]  comp_val 0x%08x\n",
+	   dmae.opcode, dmae.src_addr_hi, dmae.src_addr_lo,
+	   dmae.len, dmae.dst_addr_hi, dmae.dst_addr_lo, dst_addr,
+	   dmae.comp_addr_hi, dmae.comp_addr_lo, dmae.comp_val);
+	DP(BNX2X_MSG_OFF, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n",
+	   bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
+	   bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
+
+	mutex_lock(&bp->dmae_mutex);
+
+	*wb_comp = 0;
+
+	bnx2x_post_dmae(bp, &dmae, INIT_DMAE_C(bp));
+
+	udelay(5);
+
+	while (*wb_comp != DMAE_COMP_VAL) {
+		DP(BNX2X_MSG_OFF, "wb_comp 0x%08x\n", *wb_comp);
+
+		if (!cnt) {
+			BNX2X_ERR("DMAE timeout!\n");
+			break;
+		}
+		cnt--;
+		/* adjust delay for emulation/FPGA */
+		if (CHIP_REV_IS_SLOW(bp))
+			msleep(100);
+		else
+			udelay(5);
+	}
+
+	mutex_unlock(&bp->dmae_mutex);
+}
+
+void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
+{
+	struct dmae_command dmae;
+	u32 *wb_comp = bnx2x_sp(bp, wb_comp);
+	int cnt = 200;
+
+	if (!bp->dmae_ready) {
+		u32 *data = bnx2x_sp(bp, wb_data[0]);
+		int i;
+
+		DP(BNX2X_MSG_OFF, "DMAE is not ready (src_addr %08x  len32 %d)"
+		   "  using indirect\n", src_addr, len32);
+		for (i = 0; i < len32; i++)
+			data[i] = bnx2x_reg_rd_ind(bp, src_addr + i*4);
+		return;
+	}
+
+	memset(&dmae, 0, sizeof(struct dmae_command));
+
+	dmae.opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+		       DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+		       DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+		       DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+		       DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+		       (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+		       (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+	dmae.src_addr_lo = src_addr >> 2;
+	dmae.src_addr_hi = 0;
+	dmae.dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data));
+	dmae.dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data));
+	dmae.len = len32;
+	dmae.comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
+	dmae.comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
+	dmae.comp_val = DMAE_COMP_VAL;
+
+	DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n"
+	   DP_LEVEL "src_addr  [%x:%08x]  len [%d *4]  "
+		    "dst_addr [%x:%08x (%08x)]\n"
+	   DP_LEVEL "comp_addr [%x:%08x]  comp_val 0x%08x\n",
+	   dmae.opcode, dmae.src_addr_hi, dmae.src_addr_lo,
+	   dmae.len, dmae.dst_addr_hi, dmae.dst_addr_lo, src_addr,
+	   dmae.comp_addr_hi, dmae.comp_addr_lo, dmae.comp_val);
+
+	mutex_lock(&bp->dmae_mutex);
+
+	memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4);
+	*wb_comp = 0;
+
+	bnx2x_post_dmae(bp, &dmae, INIT_DMAE_C(bp));
+
+	udelay(5);
+
+	while (*wb_comp != DMAE_COMP_VAL) {
+
+		if (!cnt) {
+			BNX2X_ERR("DMAE timeout!\n");
+			break;
+		}
+		cnt--;
+		/* adjust delay for emulation/FPGA */
+		if (CHIP_REV_IS_SLOW(bp))
+			msleep(100);
+		else
+			udelay(5);
+	}
+	DP(BNX2X_MSG_OFF, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n",
+	   bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
+	   bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
+
+	mutex_unlock(&bp->dmae_mutex);
+}
+
+void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
+			       u32 addr, u32 len)
+{
+	int dmae_wr_max = DMAE_LEN32_WR_MAX(bp);
+	int offset = 0;
+
+	while (len > dmae_wr_max) {
+		bnx2x_write_dmae(bp, phys_addr + offset,
+				 addr + offset, dmae_wr_max);
+		offset += dmae_wr_max * 4;
+		len -= dmae_wr_max;
+	}
+
+	bnx2x_write_dmae(bp, phys_addr + offset, addr + offset, len);
+}
+
+/* used only for slowpath so not inlined */
+static void bnx2x_wb_wr(struct bnx2x *bp, int reg, u32 val_hi, u32 val_lo)
+{
+	u32 wb_write[2];
+
+	wb_write[0] = val_hi;
+	wb_write[1] = val_lo;
+	REG_WR_DMAE(bp, reg, wb_write, 2);
+}
+
+#ifdef USE_WB_RD
+static u64 bnx2x_wb_rd(struct bnx2x *bp, int reg)
+{
+	u32 wb_data[2];
+
+	REG_RD_DMAE(bp, reg, wb_data, 2);
+
+	return HILO_U64(wb_data[0], wb_data[1]);
+}
+#endif
+
+static int bnx2x_mc_assert(struct bnx2x *bp)
+{
+	char last_idx;
+	int i, rc = 0;
+	u32 row0, row1, row2, row3;
+
+	/* XSTORM */
+	last_idx = REG_RD8(bp, BAR_XSTRORM_INTMEM +
+			   XSTORM_ASSERT_LIST_INDEX_OFFSET);
+	if (last_idx)
+		BNX2X_ERR("XSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
+
+	/* print the asserts */
+	for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
+
+		row0 = REG_RD(bp, BAR_XSTRORM_INTMEM +
+			      XSTORM_ASSERT_LIST_OFFSET(i));
+		row1 = REG_RD(bp, BAR_XSTRORM_INTMEM +
+			      XSTORM_ASSERT_LIST_OFFSET(i) + 4);
+		row2 = REG_RD(bp, BAR_XSTRORM_INTMEM +
+			      XSTORM_ASSERT_LIST_OFFSET(i) + 8);
+		row3 = REG_RD(bp, BAR_XSTRORM_INTMEM +
+			      XSTORM_ASSERT_LIST_OFFSET(i) + 12);
+
+		if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
+			BNX2X_ERR("XSTORM_ASSERT_INDEX 0x%x = 0x%08x"
+				  " 0x%08x 0x%08x 0x%08x\n",
+				  i, row3, row2, row1, row0);
+			rc++;
+		} else {
+			break;
+		}
+	}
+
+	/* TSTORM */
+	last_idx = REG_RD8(bp, BAR_TSTRORM_INTMEM +
+			   TSTORM_ASSERT_LIST_INDEX_OFFSET);
+	if (last_idx)
+		BNX2X_ERR("TSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
+
+	/* print the asserts */
+	for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
+
+		row0 = REG_RD(bp, BAR_TSTRORM_INTMEM +
+			      TSTORM_ASSERT_LIST_OFFSET(i));
+		row1 = REG_RD(bp, BAR_TSTRORM_INTMEM +
+			      TSTORM_ASSERT_LIST_OFFSET(i) + 4);
+		row2 = REG_RD(bp, BAR_TSTRORM_INTMEM +
+			      TSTORM_ASSERT_LIST_OFFSET(i) + 8);
+		row3 = REG_RD(bp, BAR_TSTRORM_INTMEM +
+			      TSTORM_ASSERT_LIST_OFFSET(i) + 12);
+
+		if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
+			BNX2X_ERR("TSTORM_ASSERT_INDEX 0x%x = 0x%08x"
+				  " 0x%08x 0x%08x 0x%08x\n",
+				  i, row3, row2, row1, row0);
+			rc++;
+		} else {
+			break;
+		}
+	}
+
+	/* CSTORM */
+	last_idx = REG_RD8(bp, BAR_CSTRORM_INTMEM +
+			   CSTORM_ASSERT_LIST_INDEX_OFFSET);
+	if (last_idx)
+		BNX2X_ERR("CSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
+
+	/* print the asserts */
+	for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
+
+		row0 = REG_RD(bp, BAR_CSTRORM_INTMEM +
+			      CSTORM_ASSERT_LIST_OFFSET(i));
+		row1 = REG_RD(bp, BAR_CSTRORM_INTMEM +
+			      CSTORM_ASSERT_LIST_OFFSET(i) + 4);
+		row2 = REG_RD(bp, BAR_CSTRORM_INTMEM +
+			      CSTORM_ASSERT_LIST_OFFSET(i) + 8);
+		row3 = REG_RD(bp, BAR_CSTRORM_INTMEM +
+			      CSTORM_ASSERT_LIST_OFFSET(i) + 12);
+
+		if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
+			BNX2X_ERR("CSTORM_ASSERT_INDEX 0x%x = 0x%08x"
+				  " 0x%08x 0x%08x 0x%08x\n",
+				  i, row3, row2, row1, row0);
+			rc++;
+		} else {
+			break;
+		}
+	}
+
+	/* USTORM */
+	last_idx = REG_RD8(bp, BAR_USTRORM_INTMEM +
+			   USTORM_ASSERT_LIST_INDEX_OFFSET);
+	if (last_idx)
+		BNX2X_ERR("USTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
+
+	/* print the asserts */
+	for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
+
+		row0 = REG_RD(bp, BAR_USTRORM_INTMEM +
+			      USTORM_ASSERT_LIST_OFFSET(i));
+		row1 = REG_RD(bp, BAR_USTRORM_INTMEM +
+			      USTORM_ASSERT_LIST_OFFSET(i) + 4);
+		row2 = REG_RD(bp, BAR_USTRORM_INTMEM +
+			      USTORM_ASSERT_LIST_OFFSET(i) + 8);
+		row3 = REG_RD(bp, BAR_USTRORM_INTMEM +
+			      USTORM_ASSERT_LIST_OFFSET(i) + 12);
+
+		if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
+			BNX2X_ERR("USTORM_ASSERT_INDEX 0x%x = 0x%08x"
+				  " 0x%08x 0x%08x 0x%08x\n",
+				  i, row3, row2, row1, row0);
+			rc++;
+		} else {
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static void bnx2x_fw_dump(struct bnx2x *bp)
+{
+	u32 addr;
+	u32 mark, offset;
+	__be32 data[9];
+	int word;
+
+	if (BP_NOMCP(bp)) {
+		BNX2X_ERR("NO MCP - can not dump\n");
+		return;
+	}
+
+	addr = bp->common.shmem_base - 0x0800 + 4;
+	mark = REG_RD(bp, addr);
+	mark = MCP_REG_MCPR_SCRATCH + ((mark + 0x3) & ~0x3) - 0x08000000;
+	pr_err("begin fw dump (mark 0x%x)\n", mark);
+
+	pr_err("");
+	for (offset = mark; offset <= bp->common.shmem_base; offset += 0x8*4) {
+		for (word = 0; word < 8; word++)
+			data[word] = htonl(REG_RD(bp, offset + 4*word));
+		data[8] = 0x0;
+		pr_cont("%s", (char *)data);
+	}
+	for (offset = addr + 4; offset <= mark; offset += 0x8*4) {
+		for (word = 0; word < 8; word++)
+			data[word] = htonl(REG_RD(bp, offset + 4*word));
+		data[8] = 0x0;
+		pr_cont("%s", (char *)data);
+	}
+	pr_err("end of fw dump\n");
+}
+
+void bnx2x_panic_dump(struct bnx2x *bp)
+{
+	int i;
+	u16 j, start, end;
+
+	bp->stats_state = STATS_STATE_DISABLED;
+	DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");
+
+	BNX2X_ERR("begin crash dump -----------------\n");
+
+	/* Indices */
+	/* Common */
+	BNX2X_ERR("def_c_idx(0x%x)  def_u_idx(0x%x)  def_x_idx(0x%x)"
+		  "  def_t_idx(0x%x)  def_att_idx(0x%x)  attn_state(0x%x)"
+		  "  spq_prod_idx(0x%x)\n",
+		  bp->def_c_idx, bp->def_u_idx, bp->def_x_idx, bp->def_t_idx,
+		  bp->def_att_idx, bp->attn_state, bp->spq_prod_idx);
+
+	/* Rx */
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		BNX2X_ERR("fp%d: rx_bd_prod(0x%x)  rx_bd_cons(0x%x)"
+			  "  *rx_bd_cons_sb(0x%x)  rx_comp_prod(0x%x)"
+			  "  rx_comp_cons(0x%x)  *rx_cons_sb(0x%x)\n",
+			  i, fp->rx_bd_prod, fp->rx_bd_cons,
+			  le16_to_cpu(*fp->rx_bd_cons_sb), fp->rx_comp_prod,
+			  fp->rx_comp_cons, le16_to_cpu(*fp->rx_cons_sb));
+		BNX2X_ERR("     rx_sge_prod(0x%x)  last_max_sge(0x%x)"
+			  "  fp_u_idx(0x%x) *sb_u_idx(0x%x)\n",
+			  fp->rx_sge_prod, fp->last_max_sge,
+			  le16_to_cpu(fp->fp_u_idx),
+			  fp->status_blk->u_status_block.status_block_index);
+	}
+
+	/* Tx */
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		BNX2X_ERR("fp%d: tx_pkt_prod(0x%x)  tx_pkt_cons(0x%x)"
+			  "  tx_bd_prod(0x%x)  tx_bd_cons(0x%x)"
+			  "  *tx_cons_sb(0x%x)\n",
+			  i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod,
+			  fp->tx_bd_cons, le16_to_cpu(*fp->tx_cons_sb));
+		BNX2X_ERR("     fp_c_idx(0x%x)  *sb_c_idx(0x%x)"
+			  "  tx_db_prod(0x%x)\n", le16_to_cpu(fp->fp_c_idx),
+			  fp->status_blk->c_status_block.status_block_index,
+			  fp->tx_db.data.prod);
+	}
+
+	/* Rings */
+	/* Rx */
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10);
+		end = RX_BD(le16_to_cpu(*fp->rx_cons_sb) + 503);
+		for (j = start; j != end; j = RX_BD(j + 1)) {
+			u32 *rx_bd = (u32 *)&fp->rx_desc_ring[j];
+			struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j];
+
+			BNX2X_ERR("fp%d: rx_bd[%x]=[%x:%x]  sw_bd=[%p]\n",
+				  i, j, rx_bd[1], rx_bd[0], sw_bd->skb);
+		}
+
+		start = RX_SGE(fp->rx_sge_prod);
+		end = RX_SGE(fp->last_max_sge);
+		for (j = start; j != end; j = RX_SGE(j + 1)) {
+			u32 *rx_sge = (u32 *)&fp->rx_sge_ring[j];
+			struct sw_rx_page *sw_page = &fp->rx_page_ring[j];
+
+			BNX2X_ERR("fp%d: rx_sge[%x]=[%x:%x]  sw_page=[%p]\n",
+				  i, j, rx_sge[1], rx_sge[0], sw_page->page);
+		}
+
+		start = RCQ_BD(fp->rx_comp_cons - 10);
+		end = RCQ_BD(fp->rx_comp_cons + 503);
+		for (j = start; j != end; j = RCQ_BD(j + 1)) {
+			u32 *cqe = (u32 *)&fp->rx_comp_ring[j];
+
+			BNX2X_ERR("fp%d: cqe[%x]=[%x:%x:%x:%x]\n",
+				  i, j, cqe[0], cqe[1], cqe[2], cqe[3]);
+		}
+	}
+
+	/* Tx */
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		start = TX_BD(le16_to_cpu(*fp->tx_cons_sb) - 10);
+		end = TX_BD(le16_to_cpu(*fp->tx_cons_sb) + 245);
+		for (j = start; j != end; j = TX_BD(j + 1)) {
+			struct sw_tx_bd *sw_bd = &fp->tx_buf_ring[j];
+
+			BNX2X_ERR("fp%d: packet[%x]=[%p,%x]\n",
+				  i, j, sw_bd->skb, sw_bd->first_bd);
+		}
+
+		start = TX_BD(fp->tx_bd_cons - 10);
+		end = TX_BD(fp->tx_bd_cons + 254);
+		for (j = start; j != end; j = TX_BD(j + 1)) {
+			u32 *tx_bd = (u32 *)&fp->tx_desc_ring[j];
+
+			BNX2X_ERR("fp%d: tx_bd[%x]=[%x:%x:%x:%x]\n",
+				  i, j, tx_bd[0], tx_bd[1], tx_bd[2], tx_bd[3]);
+		}
+	}
+
+	bnx2x_fw_dump(bp);
+	bnx2x_mc_assert(bp);
+	BNX2X_ERR("end crash dump -----------------\n");
+}
+
+void bnx2x_int_enable(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
+	u32 val = REG_RD(bp, addr);
+	int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
+	int msi = (bp->flags & USING_MSI_FLAG) ? 1 : 0;
+
+	if (msix) {
+		val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+			 HC_CONFIG_0_REG_INT_LINE_EN_0);
+		val |= (HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
+			HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+	} else if (msi) {
+		val &= ~HC_CONFIG_0_REG_INT_LINE_EN_0;
+		val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+			HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
+			HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+	} else {
+		val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+			HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
+			HC_CONFIG_0_REG_INT_LINE_EN_0 |
+			HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+
+		DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)\n",
+		   val, port, addr);
+
+		REG_WR(bp, addr, val);
+
+		val &= ~HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0;
+	}
+
+	DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)  mode %s\n",
+	   val, port, addr, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
+
+	REG_WR(bp, addr, val);
+	/*
+	 * Ensure that HC_CONFIG is written before leading/trailing edge config
+	 */
+	mmiowb();
+	barrier();
+
+	if (CHIP_IS_E1H(bp)) {
+		/* init leading/trailing edge */
+		if (IS_E1HMF(bp)) {
+			val = (0xee0f | (1 << (BP_E1HVN(bp) + 4)));
+			if (bp->port.pmf)
+				/* enable nig and gpio3 attention */
+				val |= 0x1100;
+		} else
+			val = 0xffff;
+
+		REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
+		REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
+	}
+
+	/* Make sure that interrupts are indeed enabled from here on */
+	mmiowb();
+}
+
+static void bnx2x_int_disable(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
+	u32 val = REG_RD(bp, addr);
+
+	val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+		 HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
+		 HC_CONFIG_0_REG_INT_LINE_EN_0 |
+		 HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+
+	DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)\n",
+	   val, port, addr);
+
+	/* flush all outstanding writes */
+	mmiowb();
+
+	REG_WR(bp, addr, val);
+	if (REG_RD(bp, addr) != val)
+		BNX2X_ERR("BUG! proper val not read from IGU!\n");
+}
+
+void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
+{
+	int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
+	int i, offset;
+
+	/* disable interrupt handling */
+	atomic_inc(&bp->intr_sem);
+	smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
+	if (disable_hw)
+		/* prevent the HW from sending interrupts */
+		bnx2x_int_disable(bp);
+
+	/* make sure all ISRs are done */
+	if (msix) {
+		synchronize_irq(bp->msix_table[0].vector);
+		offset = 1;
+#ifdef BCM_CNIC
+		offset++;
+#endif
+		for_each_queue(bp, i)
+			synchronize_irq(bp->msix_table[i + offset].vector);
+	} else
+		synchronize_irq(bp->pdev->irq);
+
+	/* make sure sp_task is not running */
+	cancel_delayed_work(&bp->sp_task);
+	flush_workqueue(bnx2x_wq);
+}
+
+/* fast path */
+
+/*
+ * General service functions
+ */
+
+/* Return true if succeeded to acquire the lock */
+static bool bnx2x_trylock_hw_lock(struct bnx2x *bp, u32 resource)
+{
+	u32 lock_status;
+	u32 resource_bit = (1 << resource);
+	int func = BP_FUNC(bp);
+	u32 hw_lock_control_reg;
+
+	DP(NETIF_MSG_HW, "Trying to take a lock on resource %d\n", resource);
+
+	/* Validating that the resource is within range */
+	if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
+		DP(NETIF_MSG_HW,
+		   "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
+		   resource, HW_LOCK_MAX_RESOURCE_VALUE);
+		return -EINVAL;
+	}
+
+	if (func <= 5)
+		hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
+	else
+		hw_lock_control_reg =
+				(MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
+
+	/* Try to acquire the lock */
+	REG_WR(bp, hw_lock_control_reg + 4, resource_bit);
+	lock_status = REG_RD(bp, hw_lock_control_reg);
+	if (lock_status & resource_bit)
+		return true;
+
+	DP(NETIF_MSG_HW, "Failed to get a lock on resource %d\n", resource);
+	return false;
+}
+
+
+#ifdef BCM_CNIC
+static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid);
+#endif
+
+void bnx2x_sp_event(struct bnx2x_fastpath *fp,
+			   union eth_rx_cqe *rr_cqe)
+{
+	struct bnx2x *bp = fp->bp;
+	int cid = SW_CID(rr_cqe->ramrod_cqe.conn_and_cmd_data);
+	int command = CQE_CMD(rr_cqe->ramrod_cqe.conn_and_cmd_data);
+
+	DP(BNX2X_MSG_SP,
+	   "fp %d  cid %d  got ramrod #%d  state is %x  type is %d\n",
+	   fp->index, cid, command, bp->state,
+	   rr_cqe->ramrod_cqe.ramrod_type);
+
+	bp->spq_left++;
+
+	if (fp->index) {
+		switch (command | fp->state) {
+		case (RAMROD_CMD_ID_ETH_CLIENT_SETUP |
+						BNX2X_FP_STATE_OPENING):
+			DP(NETIF_MSG_IFUP, "got MULTI[%d] setup ramrod\n",
+			   cid);
+			fp->state = BNX2X_FP_STATE_OPEN;
+			break;
+
+		case (RAMROD_CMD_ID_ETH_HALT | BNX2X_FP_STATE_HALTING):
+			DP(NETIF_MSG_IFDOWN, "got MULTI[%d] halt ramrod\n",
+			   cid);
+			fp->state = BNX2X_FP_STATE_HALTED;
+			break;
+
+		default:
+			BNX2X_ERR("unexpected MC reply (%d)  "
+				  "fp[%d] state is %x\n",
+				  command, fp->index, fp->state);
+			break;
+		}
+		mb(); /* force bnx2x_wait_ramrod() to see the change */
+		return;
+	}
+
+	switch (command | bp->state) {
+	case (RAMROD_CMD_ID_ETH_PORT_SETUP | BNX2X_STATE_OPENING_WAIT4_PORT):
+		DP(NETIF_MSG_IFUP, "got setup ramrod\n");
+		bp->state = BNX2X_STATE_OPEN;
+		break;
+
+	case (RAMROD_CMD_ID_ETH_HALT | BNX2X_STATE_CLOSING_WAIT4_HALT):
+		DP(NETIF_MSG_IFDOWN, "got halt ramrod\n");
+		bp->state = BNX2X_STATE_CLOSING_WAIT4_DELETE;
+		fp->state = BNX2X_FP_STATE_HALTED;
+		break;
+
+	case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_CLOSING_WAIT4_HALT):
+		DP(NETIF_MSG_IFDOWN, "got delete ramrod for MULTI[%d]\n", cid);
+		bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_CLOSED;
+		break;
+
+#ifdef BCM_CNIC
+	case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_OPEN):
+		DP(NETIF_MSG_IFDOWN, "got delete ramrod for CID %d\n", cid);
+		bnx2x_cnic_cfc_comp(bp, cid);
+		break;
+#endif
+
+	case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_OPEN):
+	case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_DIAG):
+		DP(NETIF_MSG_IFUP, "got set mac ramrod\n");
+		bp->set_mac_pending--;
+		smp_wmb();
+		break;
+
+	case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT):
+		DP(NETIF_MSG_IFDOWN, "got (un)set mac ramrod\n");
+		bp->set_mac_pending--;
+		smp_wmb();
+		break;
+
+	default:
+		BNX2X_ERR("unexpected MC reply (%d)  bp->state is %x\n",
+			  command, bp->state);
+		break;
+	}
+	mb(); /* force bnx2x_wait_ramrod() to see the change */
+}
+
+irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
+{
+	struct bnx2x *bp = netdev_priv(dev_instance);
+	u16 status = bnx2x_ack_int(bp);
+	u16 mask;
+	int i;
+
+	/* Return here if interrupt is shared and it's not for us */
+	if (unlikely(status == 0)) {
+		DP(NETIF_MSG_INTR, "not our interrupt!\n");
+		return IRQ_NONE;
+	}
+	DP(NETIF_MSG_INTR, "got an interrupt  status 0x%x\n", status);
+
+	/* Return here if interrupt is disabled */
+	if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
+		DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
+		return IRQ_HANDLED;
+	}
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return IRQ_HANDLED;
+#endif
+
+	for (i = 0; i < BNX2X_NUM_QUEUES(bp); i++) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		mask = 0x2 << fp->sb_id;
+		if (status & mask) {
+			/* Handle Rx and Tx according to SB id */
+			prefetch(fp->rx_cons_sb);
+			prefetch(&fp->status_blk->u_status_block.
+						status_block_index);
+			prefetch(fp->tx_cons_sb);
+			prefetch(&fp->status_blk->c_status_block.
+						status_block_index);
+			napi_schedule(&bnx2x_fp(bp, fp->index, napi));
+			status &= ~mask;
+		}
+	}
+
+#ifdef BCM_CNIC
+	mask = 0x2 << CNIC_SB_ID(bp);
+	if (status & (mask | 0x1)) {
+		struct cnic_ops *c_ops = NULL;
+
+		rcu_read_lock();
+		c_ops = rcu_dereference(bp->cnic_ops);
+		if (c_ops)
+			c_ops->cnic_handler(bp->cnic_data, NULL);
+		rcu_read_unlock();
+
+		status &= ~mask;
+	}
+#endif
+
+	if (unlikely(status & 0x1)) {
+		queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+
+		status &= ~0x1;
+		if (!status)
+			return IRQ_HANDLED;
+	}
+
+	if (unlikely(status))
+		DP(NETIF_MSG_INTR, "got an unknown interrupt! (status 0x%x)\n",
+		   status);
+
+	return IRQ_HANDLED;
+}
+
+/* end of fast path */
+
+
+/* Link */
+
+/*
+ * General service functions
+ */
+
+int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource)
+{
+	u32 lock_status;
+	u32 resource_bit = (1 << resource);
+	int func = BP_FUNC(bp);
+	u32 hw_lock_control_reg;
+	int cnt;
+
+	/* Validating that the resource is within range */
+	if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
+		DP(NETIF_MSG_HW,
+		   "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
+		   resource, HW_LOCK_MAX_RESOURCE_VALUE);
+		return -EINVAL;
+	}
+
+	if (func <= 5) {
+		hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
+	} else {
+		hw_lock_control_reg =
+				(MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
+	}
+
+	/* Validating that the resource is not already taken */
+	lock_status = REG_RD(bp, hw_lock_control_reg);
+	if (lock_status & resource_bit) {
+		DP(NETIF_MSG_HW, "lock_status 0x%x  resource_bit 0x%x\n",
+		   lock_status, resource_bit);
+		return -EEXIST;
+	}
+
+	/* Try for 5 second every 5ms */
+	for (cnt = 0; cnt < 1000; cnt++) {
+		/* Try to acquire the lock */
+		REG_WR(bp, hw_lock_control_reg + 4, resource_bit);
+		lock_status = REG_RD(bp, hw_lock_control_reg);
+		if (lock_status & resource_bit)
+			return 0;
+
+		msleep(5);
+	}
+	DP(NETIF_MSG_HW, "Timeout\n");
+	return -EAGAIN;
+}
+
+int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource)
+{
+	u32 lock_status;
+	u32 resource_bit = (1 << resource);
+	int func = BP_FUNC(bp);
+	u32 hw_lock_control_reg;
+
+	DP(NETIF_MSG_HW, "Releasing a lock on resource %d\n", resource);
+
+	/* Validating that the resource is within range */
+	if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
+		DP(NETIF_MSG_HW,
+		   "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
+		   resource, HW_LOCK_MAX_RESOURCE_VALUE);
+		return -EINVAL;
+	}
+
+	if (func <= 5) {
+		hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
+	} else {
+		hw_lock_control_reg =
+				(MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
+	}
+
+	/* Validating that the resource is currently taken */
+	lock_status = REG_RD(bp, hw_lock_control_reg);
+	if (!(lock_status & resource_bit)) {
+		DP(NETIF_MSG_HW, "lock_status 0x%x  resource_bit 0x%x\n",
+		   lock_status, resource_bit);
+		return -EFAULT;
+	}
+
+	REG_WR(bp, hw_lock_control_reg, resource_bit);
+	return 0;
+}
+
+
+int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port)
+{
+	/* The GPIO should be swapped if swap register is set and active */
+	int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
+			 REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
+	int gpio_shift = gpio_num +
+			(gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
+	u32 gpio_mask = (1 << gpio_shift);
+	u32 gpio_reg;
+	int value;
+
+	if (gpio_num > MISC_REGISTERS_GPIO_3) {
+		BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
+		return -EINVAL;
+	}
+
+	/* read GPIO value */
+	gpio_reg = REG_RD(bp, MISC_REG_GPIO);
+
+	/* get the requested pin value */
+	if ((gpio_reg & gpio_mask) == gpio_mask)
+		value = 1;
+	else
+		value = 0;
+
+	DP(NETIF_MSG_LINK, "pin %d  value 0x%x\n", gpio_num, value);
+
+	return value;
+}
+
+int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port)
+{
+	/* The GPIO should be swapped if swap register is set and active */
+	int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
+			 REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
+	int gpio_shift = gpio_num +
+			(gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
+	u32 gpio_mask = (1 << gpio_shift);
+	u32 gpio_reg;
+
+	if (gpio_num > MISC_REGISTERS_GPIO_3) {
+		BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
+		return -EINVAL;
+	}
+
+	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
+	/* read GPIO and mask except the float bits */
+	gpio_reg = (REG_RD(bp, MISC_REG_GPIO) & MISC_REGISTERS_GPIO_FLOAT);
+
+	switch (mode) {
+	case MISC_REGISTERS_GPIO_OUTPUT_LOW:
+		DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output low\n",
+		   gpio_num, gpio_shift);
+		/* clear FLOAT and set CLR */
+		gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
+		gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_CLR_POS);
+		break;
+
+	case MISC_REGISTERS_GPIO_OUTPUT_HIGH:
+		DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output high\n",
+		   gpio_num, gpio_shift);
+		/* clear FLOAT and set SET */
+		gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
+		gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_SET_POS);
+		break;
+
+	case MISC_REGISTERS_GPIO_INPUT_HI_Z:
+		DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> input\n",
+		   gpio_num, gpio_shift);
+		/* set FLOAT */
+		gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
+		break;
+
+	default:
+		break;
+	}
+
+	REG_WR(bp, MISC_REG_GPIO, gpio_reg);
+	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
+
+	return 0;
+}
+
+int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port)
+{
+	/* The GPIO should be swapped if swap register is set and active */
+	int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
+			 REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
+	int gpio_shift = gpio_num +
+			(gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
+	u32 gpio_mask = (1 << gpio_shift);
+	u32 gpio_reg;
+
+	if (gpio_num > MISC_REGISTERS_GPIO_3) {
+		BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
+		return -EINVAL;
+	}
+
+	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
+	/* read GPIO int */
+	gpio_reg = REG_RD(bp, MISC_REG_GPIO_INT);
+
+	switch (mode) {
+	case MISC_REGISTERS_GPIO_INT_OUTPUT_CLR:
+		DP(NETIF_MSG_LINK, "Clear GPIO INT %d (shift %d) -> "
+				   "output low\n", gpio_num, gpio_shift);
+		/* clear SET and set CLR */
+		gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_INT_SET_POS);
+		gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_INT_CLR_POS);
+		break;
+
+	case MISC_REGISTERS_GPIO_INT_OUTPUT_SET:
+		DP(NETIF_MSG_LINK, "Set GPIO INT %d (shift %d) -> "
+				   "output high\n", gpio_num, gpio_shift);
+		/* clear CLR and set SET */
+		gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_INT_CLR_POS);
+		gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_INT_SET_POS);
+		break;
+
+	default:
+		break;
+	}
+
+	REG_WR(bp, MISC_REG_GPIO_INT, gpio_reg);
+	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
+
+	return 0;
+}
+
+static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode)
+{
+	u32 spio_mask = (1 << spio_num);
+	u32 spio_reg;
+
+	if ((spio_num < MISC_REGISTERS_SPIO_4) ||
+	    (spio_num > MISC_REGISTERS_SPIO_7)) {
+		BNX2X_ERR("Invalid SPIO %d\n", spio_num);
+		return -EINVAL;
+	}
+
+	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_SPIO);
+	/* read SPIO and mask except the float bits */
+	spio_reg = (REG_RD(bp, MISC_REG_SPIO) & MISC_REGISTERS_SPIO_FLOAT);
+
+	switch (mode) {
+	case MISC_REGISTERS_SPIO_OUTPUT_LOW:
+		DP(NETIF_MSG_LINK, "Set SPIO %d -> output low\n", spio_num);
+		/* clear FLOAT and set CLR */
+		spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
+		spio_reg |=  (spio_mask << MISC_REGISTERS_SPIO_CLR_POS);
+		break;
+
+	case MISC_REGISTERS_SPIO_OUTPUT_HIGH:
+		DP(NETIF_MSG_LINK, "Set SPIO %d -> output high\n", spio_num);
+		/* clear FLOAT and set SET */
+		spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
+		spio_reg |=  (spio_mask << MISC_REGISTERS_SPIO_SET_POS);
+		break;
+
+	case MISC_REGISTERS_SPIO_INPUT_HI_Z:
+		DP(NETIF_MSG_LINK, "Set SPIO %d -> input\n", spio_num);
+		/* set FLOAT */
+		spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
+		break;
+
+	default:
+		break;
+	}
+
+	REG_WR(bp, MISC_REG_SPIO, spio_reg);
+	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_SPIO);
+
+	return 0;
+}
+
+void bnx2x_calc_fc_adv(struct bnx2x *bp)
+{
+	switch (bp->link_vars.ieee_fc &
+		MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK) {
+	case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE:
+		bp->port.advertising &= ~(ADVERTISED_Asym_Pause |
+					  ADVERTISED_Pause);
+		break;
+
+	case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH:
+		bp->port.advertising |= (ADVERTISED_Asym_Pause |
+					 ADVERTISED_Pause);
+		break;
+
+	case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC:
+		bp->port.advertising |= ADVERTISED_Asym_Pause;
+		break;
+
+	default:
+		bp->port.advertising &= ~(ADVERTISED_Asym_Pause |
+					  ADVERTISED_Pause);
+		break;
+	}
+}
+
+
+u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
+{
+	if (!BP_NOMCP(bp)) {
+		u8 rc;
+
+		/* Initialize link parameters structure variables */
+		/* It is recommended to turn off RX FC for jumbo frames
+		   for better performance */
+		if (bp->dev->mtu > 5000)
+			bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_TX;
+		else
+			bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH;
+
+		bnx2x_acquire_phy_lock(bp);
+
+		if (load_mode == LOAD_DIAG)
+			bp->link_params.loopback_mode = LOOPBACK_XGXS_10;
+
+		rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars);
+
+		bnx2x_release_phy_lock(bp);
+
+		bnx2x_calc_fc_adv(bp);
+
+		if (CHIP_REV_IS_SLOW(bp) && bp->link_vars.link_up) {
+			bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
+			bnx2x_link_report(bp);
+		}
+
+		return rc;
+	}
+	BNX2X_ERR("Bootcode is missing - can not initialize link\n");
+	return -EINVAL;
+}
+
+void bnx2x_link_set(struct bnx2x *bp)
+{
+	if (!BP_NOMCP(bp)) {
+		bnx2x_acquire_phy_lock(bp);
+		bnx2x_phy_init(&bp->link_params, &bp->link_vars);
+		bnx2x_release_phy_lock(bp);
+
+		bnx2x_calc_fc_adv(bp);
+	} else
+		BNX2X_ERR("Bootcode is missing - can not set link\n");
+}
+
+static void bnx2x__link_reset(struct bnx2x *bp)
+{
+	if (!BP_NOMCP(bp)) {
+		bnx2x_acquire_phy_lock(bp);
+		bnx2x_link_reset(&bp->link_params, &bp->link_vars, 1);
+		bnx2x_release_phy_lock(bp);
+	} else
+		BNX2X_ERR("Bootcode is missing - can not reset link\n");
+}
+
+u8 bnx2x_link_test(struct bnx2x *bp)
+{
+	u8 rc = 0;
+
+	if (!BP_NOMCP(bp)) {
+		bnx2x_acquire_phy_lock(bp);
+		rc = bnx2x_test_link(&bp->link_params, &bp->link_vars);
+		bnx2x_release_phy_lock(bp);
+	} else
+		BNX2X_ERR("Bootcode is missing - can not test link\n");
+
+	return rc;
+}
+
+static void bnx2x_init_port_minmax(struct bnx2x *bp)
+{
+	u32 r_param = bp->link_vars.line_speed / 8;
+	u32 fair_periodic_timeout_usec;
+	u32 t_fair;
+
+	memset(&(bp->cmng.rs_vars), 0,
+	       sizeof(struct rate_shaping_vars_per_port));
+	memset(&(bp->cmng.fair_vars), 0, sizeof(struct fairness_vars_per_port));
+
+	/* 100 usec in SDM ticks = 25 since each tick is 4 usec */
+	bp->cmng.rs_vars.rs_periodic_timeout = RS_PERIODIC_TIMEOUT_USEC / 4;
+
+	/* this is the threshold below which no timer arming will occur
+	   1.25 coefficient is for the threshold to be a little bigger
+	   than the real time, to compensate for timer in-accuracy */
+	bp->cmng.rs_vars.rs_threshold =
+				(RS_PERIODIC_TIMEOUT_USEC * r_param * 5) / 4;
+
+	/* resolution of fairness timer */
+	fair_periodic_timeout_usec = QM_ARB_BYTES / r_param;
+	/* for 10G it is 1000usec. for 1G it is 10000usec. */
+	t_fair = T_FAIR_COEF / bp->link_vars.line_speed;
+
+	/* this is the threshold below which we won't arm the timer anymore */
+	bp->cmng.fair_vars.fair_threshold = QM_ARB_BYTES;
+
+	/* we multiply by 1e3/8 to get bytes/msec.
+	   We don't want the credits to pass a credit
+	   of the t_fair*FAIR_MEM (algorithm resolution) */
+	bp->cmng.fair_vars.upper_bound = r_param * t_fair * FAIR_MEM;
+	/* since each tick is 4 usec */
+	bp->cmng.fair_vars.fairness_timeout = fair_periodic_timeout_usec / 4;
+}
+
+/* Calculates the sum of vn_min_rates.
+   It's needed for further normalizing of the min_rates.
+   Returns:
+     sum of vn_min_rates.
+       or
+     0 - if all the min_rates are 0.
+     In the later case fainess algorithm should be deactivated.
+     If not all min_rates are zero then those that are zeroes will be set to 1.
+ */
+static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
+{
+	int all_zero = 1;
+	int port = BP_PORT(bp);
+	int vn;
+
+	bp->vn_weight_sum = 0;
+	for (vn = VN_0; vn < E1HVN_MAX; vn++) {
+		int func = 2*vn + port;
+		u32 vn_cfg = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
+		u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
+				   FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
+
+		/* Skip hidden vns */
+		if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE)
+			continue;
+
+		/* If min rate is zero - set it to 1 */
+		if (!vn_min_rate)
+			vn_min_rate = DEF_MIN_RATE;
+		else
+			all_zero = 0;
+
+		bp->vn_weight_sum += vn_min_rate;
+	}
+
+	/* ... only if all min rates are zeros - disable fairness */
+	if (all_zero) {
+		bp->cmng.flags.cmng_enables &=
+					~CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
+		DP(NETIF_MSG_IFUP, "All MIN values are zeroes"
+		   "  fairness will be disabled\n");
+	} else
+		bp->cmng.flags.cmng_enables |=
+					CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
+}
+
+static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
+{
+	struct rate_shaping_vars_per_vn m_rs_vn;
+	struct fairness_vars_per_vn m_fair_vn;
+	u32 vn_cfg = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
+	u16 vn_min_rate, vn_max_rate;
+	int i;
+
+	/* If function is hidden - set min and max to zeroes */
+	if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE) {
+		vn_min_rate = 0;
+		vn_max_rate = 0;
+
+	} else {
+		vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
+				FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
+		/* If min rate is zero - set it to 1 */
+		if (!vn_min_rate)
+			vn_min_rate = DEF_MIN_RATE;
+		vn_max_rate = ((vn_cfg & FUNC_MF_CFG_MAX_BW_MASK) >>
+				FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
+	}
+	DP(NETIF_MSG_IFUP,
+	   "func %d: vn_min_rate %d  vn_max_rate %d  vn_weight_sum %d\n",
+	   func, vn_min_rate, vn_max_rate, bp->vn_weight_sum);
+
+	memset(&m_rs_vn, 0, sizeof(struct rate_shaping_vars_per_vn));
+	memset(&m_fair_vn, 0, sizeof(struct fairness_vars_per_vn));
+
+	/* global vn counter - maximal Mbps for this vn */
+	m_rs_vn.vn_counter.rate = vn_max_rate;
+
+	/* quota - number of bytes transmitted in this period */
+	m_rs_vn.vn_counter.quota =
+				(vn_max_rate * RS_PERIODIC_TIMEOUT_USEC) / 8;
+
+	if (bp->vn_weight_sum) {
+		/* credit for each period of the fairness algorithm:
+		   number of bytes in T_FAIR (the vn share the port rate).
+		   vn_weight_sum should not be larger than 10000, thus
+		   T_FAIR_COEF / (8 * vn_weight_sum) will always be greater
+		   than zero */
+		m_fair_vn.vn_credit_delta =
+			max_t(u32, (vn_min_rate * (T_FAIR_COEF /
+						   (8 * bp->vn_weight_sum))),
+			      (bp->cmng.fair_vars.fair_threshold * 2));
+		DP(NETIF_MSG_IFUP, "m_fair_vn.vn_credit_delta %d\n",
+		   m_fair_vn.vn_credit_delta);
+	}
+
+	/* Store it to internal memory */
+	for (i = 0; i < sizeof(struct rate_shaping_vars_per_vn)/4; i++)
+		REG_WR(bp, BAR_XSTRORM_INTMEM +
+		       XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(func) + i * 4,
+		       ((u32 *)(&m_rs_vn))[i]);
+
+	for (i = 0; i < sizeof(struct fairness_vars_per_vn)/4; i++)
+		REG_WR(bp, BAR_XSTRORM_INTMEM +
+		       XSTORM_FAIRNESS_PER_VN_VARS_OFFSET(func) + i * 4,
+		       ((u32 *)(&m_fair_vn))[i]);
+}
+
+
+/* This function is called upon link interrupt */
+static void bnx2x_link_attn(struct bnx2x *bp)
+{
+	u32 prev_link_status = bp->link_vars.link_status;
+	/* Make sure that we are synced with the current statistics */
+	bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+
+	bnx2x_link_update(&bp->link_params, &bp->link_vars);
+
+	if (bp->link_vars.link_up) {
+
+		/* dropless flow control */
+		if (CHIP_IS_E1H(bp) && bp->dropless_fc) {
+			int port = BP_PORT(bp);
+			u32 pause_enabled = 0;
+
+			if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
+				pause_enabled = 1;
+
+			REG_WR(bp, BAR_USTRORM_INTMEM +
+			       USTORM_ETH_PAUSE_ENABLED_OFFSET(port),
+			       pause_enabled);
+		}
+
+		if (bp->link_vars.mac_type == MAC_TYPE_BMAC) {
+			struct host_port_stats *pstats;
+
+			pstats = bnx2x_sp(bp, port_stats);
+			/* reset old bmac stats */
+			memset(&(pstats->mac_stx[0]), 0,
+			       sizeof(struct mac_stx));
+		}
+		if (bp->state == BNX2X_STATE_OPEN)
+			bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
+	}
+
+	/* indicate link status only if link status actually changed */
+	if (prev_link_status != bp->link_vars.link_status)
+		bnx2x_link_report(bp);
+
+	if (IS_E1HMF(bp)) {
+		int port = BP_PORT(bp);
+		int func;
+		int vn;
+
+		/* Set the attention towards other drivers on the same port */
+		for (vn = VN_0; vn < E1HVN_MAX; vn++) {
+			if (vn == BP_E1HVN(bp))
+				continue;
+
+			func = ((vn << 1) | port);
+			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
+			       (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
+		}
+
+		if (bp->link_vars.link_up) {
+			int i;
+
+			/* Init rate shaping and fairness contexts */
+			bnx2x_init_port_minmax(bp);
+
+			for (vn = VN_0; vn < E1HVN_MAX; vn++)
+				bnx2x_init_vn_minmax(bp, 2*vn + port);
+
+			/* Store it to internal memory */
+			for (i = 0;
+			     i < sizeof(struct cmng_struct_per_port) / 4; i++)
+				REG_WR(bp, BAR_XSTRORM_INTMEM +
+				  XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i*4,
+				       ((u32 *)(&bp->cmng))[i]);
+		}
+	}
+}
+
+void bnx2x__link_status_update(struct bnx2x *bp)
+{
+	if ((bp->state != BNX2X_STATE_OPEN) || (bp->flags & MF_FUNC_DIS))
+		return;
+
+	bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
+
+	if (bp->link_vars.link_up)
+		bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
+	else
+		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+
+	bnx2x_calc_vn_weight_sum(bp);
+
+	/* indicate link status */
+	bnx2x_link_report(bp);
+}
+
+static void bnx2x_pmf_update(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	u32 val;
+
+	bp->port.pmf = 1;
+	DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
+
+	/* enable nig attention */
+	val = (0xff0f | (1 << (BP_E1HVN(bp) + 4)));
+	REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
+	REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
+
+	bnx2x_stats_handle(bp, STATS_EVENT_PMF);
+}
+
+/* end of Link */
+
+/* slow path */
+
+/*
+ * General service functions
+ */
+
+/* send the MCP a request, block until there is a reply */
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
+{
+	int func = BP_FUNC(bp);
+	u32 seq = ++bp->fw_seq;
+	u32 rc = 0;
+	u32 cnt = 1;
+	u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10;
+
+	mutex_lock(&bp->fw_mb_mutex);
+	SHMEM_WR(bp, func_mb[func].drv_mb_header, (command | seq));
+	DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq));
+
+	do {
+		/* let the FW do it's magic ... */
+		msleep(delay);
+
+		rc = SHMEM_RD(bp, func_mb[func].fw_mb_header);
+
+		/* Give the FW up to 5 second (500*10ms) */
+	} while ((seq != (rc & FW_MSG_SEQ_NUMBER_MASK)) && (cnt++ < 500));
+
+	DP(BNX2X_MSG_MCP, "[after %d ms] read (%x) seq is (%x) from FW MB\n",
+	   cnt*delay, rc, seq);
+
+	/* is this a reply to our command? */
+	if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK))
+		rc &= FW_MSG_CODE_MASK;
+	else {
+		/* FW BUG! */
+		BNX2X_ERR("FW failed to respond!\n");
+		bnx2x_fw_dump(bp);
+		rc = 0;
+	}
+	mutex_unlock(&bp->fw_mb_mutex);
+
+	return rc;
+}
+
+static void bnx2x_e1h_disable(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+
+	netif_tx_disable(bp->dev);
+
+	REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
+
+	netif_carrier_off(bp->dev);
+}
+
+static void bnx2x_e1h_enable(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+
+	REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1);
+
+	/* Tx queue should be only reenabled */
+	netif_tx_wake_all_queues(bp->dev);
+
+	/*
+	 * Should not call netif_carrier_on since it will be called if the link
+	 * is up when checking for link state
+	 */
+}
+
+static void bnx2x_update_min_max(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	int vn, i;
+
+	/* Init rate shaping and fairness contexts */
+	bnx2x_init_port_minmax(bp);
+
+	bnx2x_calc_vn_weight_sum(bp);
+
+	for (vn = VN_0; vn < E1HVN_MAX; vn++)
+		bnx2x_init_vn_minmax(bp, 2*vn + port);
+
+	if (bp->port.pmf) {
+		int func;
+
+		/* Set the attention towards other drivers on the same port */
+		for (vn = VN_0; vn < E1HVN_MAX; vn++) {
+			if (vn == BP_E1HVN(bp))
+				continue;
+
+			func = ((vn << 1) | port);
+			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
+			       (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
+		}
+
+		/* Store it to internal memory */
+		for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++)
+			REG_WR(bp, BAR_XSTRORM_INTMEM +
+			       XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i*4,
+			       ((u32 *)(&bp->cmng))[i]);
+	}
+}
+
+static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
+{
+	DP(BNX2X_MSG_MCP, "dcc_event 0x%x\n", dcc_event);
+
+	if (dcc_event & DRV_STATUS_DCC_DISABLE_ENABLE_PF) {
+
+		/*
+		 * This is the only place besides the function initialization
+		 * where the bp->flags can change so it is done without any
+		 * locks
+		 */
+		if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) {
+			DP(NETIF_MSG_IFDOWN, "mf_cfg function disabled\n");
+			bp->flags |= MF_FUNC_DIS;
+
+			bnx2x_e1h_disable(bp);
+		} else {
+			DP(NETIF_MSG_IFUP, "mf_cfg function enabled\n");
+			bp->flags &= ~MF_FUNC_DIS;
+
+			bnx2x_e1h_enable(bp);
+		}
+		dcc_event &= ~DRV_STATUS_DCC_DISABLE_ENABLE_PF;
+	}
+	if (dcc_event & DRV_STATUS_DCC_BANDWIDTH_ALLOCATION) {
+
+		bnx2x_update_min_max(bp);
+		dcc_event &= ~DRV_STATUS_DCC_BANDWIDTH_ALLOCATION;
+	}
+
+	/* Report results to MCP */
+	if (dcc_event)
+		bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_FAILURE);
+	else
+		bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK);
+}
+
+/* must be called under the spq lock */
+static inline struct eth_spe *bnx2x_sp_get_next(struct bnx2x *bp)
+{
+	struct eth_spe *next_spe = bp->spq_prod_bd;
+
+	if (bp->spq_prod_bd == bp->spq_last_bd) {
+		bp->spq_prod_bd = bp->spq;
+		bp->spq_prod_idx = 0;
+		DP(NETIF_MSG_TIMER, "end of spq\n");
+	} else {
+		bp->spq_prod_bd++;
+		bp->spq_prod_idx++;
+	}
+	return next_spe;
+}
+
+/* must be called under the spq lock */
+static inline void bnx2x_sp_prod_update(struct bnx2x *bp)
+{
+	int func = BP_FUNC(bp);
+
+	/* Make sure that BD data is updated before writing the producer */
+	wmb();
+
+	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
+	       bp->spq_prod_idx);
+	mmiowb();
+}
+
+/* the slow path queue is odd since completions arrive on the fastpath ring */
+int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
+			 u32 data_hi, u32 data_lo, int common)
+{
+	struct eth_spe *spe;
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return -EIO;
+#endif
+
+	spin_lock_bh(&bp->spq_lock);
+
+	if (!bp->spq_left) {
+		BNX2X_ERR("BUG! SPQ ring full!\n");
+		spin_unlock_bh(&bp->spq_lock);
+		bnx2x_panic();
+		return -EBUSY;
+	}
+
+	spe = bnx2x_sp_get_next(bp);
+
+	/* CID needs port number to be encoded int it */
+	spe->hdr.conn_and_cmd_data =
+			cpu_to_le32((command << SPE_HDR_CMD_ID_SHIFT) |
+				    HW_CID(bp, cid));
+	spe->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE);
+	if (common)
+		spe->hdr.type |=
+			cpu_to_le16((1 << SPE_HDR_COMMON_RAMROD_SHIFT));
+
+	spe->data.mac_config_addr.hi = cpu_to_le32(data_hi);
+	spe->data.mac_config_addr.lo = cpu_to_le32(data_lo);
+
+	bp->spq_left--;
+
+	DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/,
+	   "SPQE[%x] (%x:%x)  command %d  hw_cid %x  data (%x:%x)  left %x\n",
+	   bp->spq_prod_idx, (u32)U64_HI(bp->spq_mapping),
+	   (u32)(U64_LO(bp->spq_mapping) +
+	   (void *)bp->spq_prod_bd - (void *)bp->spq), command,
+	   HW_CID(bp, cid), data_hi, data_lo, bp->spq_left);
+
+	bnx2x_sp_prod_update(bp);
+	spin_unlock_bh(&bp->spq_lock);
+	return 0;
+}
+
+/* acquire split MCP access lock register */
+static int bnx2x_acquire_alr(struct bnx2x *bp)
+{
+	u32 j, val;
+	int rc = 0;
+
+	might_sleep();
+	for (j = 0; j < 1000; j++) {
+		val = (1UL << 31);
+		REG_WR(bp, GRCBASE_MCP + 0x9c, val);
+		val = REG_RD(bp, GRCBASE_MCP + 0x9c);
+		if (val & (1L << 31))
+			break;
+
+		msleep(5);
+	}
+	if (!(val & (1L << 31))) {
+		BNX2X_ERR("Cannot acquire MCP access lock register\n");
+		rc = -EBUSY;
+	}
+
+	return rc;
+}
+
+/* release split MCP access lock register */
+static void bnx2x_release_alr(struct bnx2x *bp)
+{
+	REG_WR(bp, GRCBASE_MCP + 0x9c, 0);
+}
+
+static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp)
+{
+	struct host_def_status_block *def_sb = bp->def_status_blk;
+	u16 rc = 0;
+
+	barrier(); /* status block is written to by the chip */
+	if (bp->def_att_idx != def_sb->atten_status_block.attn_bits_index) {
+		bp->def_att_idx = def_sb->atten_status_block.attn_bits_index;
+		rc |= 1;
+	}
+	if (bp->def_c_idx != def_sb->c_def_status_block.status_block_index) {
+		bp->def_c_idx = def_sb->c_def_status_block.status_block_index;
+		rc |= 2;
+	}
+	if (bp->def_u_idx != def_sb->u_def_status_block.status_block_index) {
+		bp->def_u_idx = def_sb->u_def_status_block.status_block_index;
+		rc |= 4;
+	}
+	if (bp->def_x_idx != def_sb->x_def_status_block.status_block_index) {
+		bp->def_x_idx = def_sb->x_def_status_block.status_block_index;
+		rc |= 8;
+	}
+	if (bp->def_t_idx != def_sb->t_def_status_block.status_block_index) {
+		bp->def_t_idx = def_sb->t_def_status_block.status_block_index;
+		rc |= 16;
+	}
+	return rc;
+}
+
+/*
+ * slow path service functions
+ */
+
+static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
+{
+	int port = BP_PORT(bp);
+	u32 hc_addr = (HC_REG_COMMAND_REG + port*32 +
+		       COMMAND_REG_ATTN_BITS_SET);
+	u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
+			      MISC_REG_AEU_MASK_ATTN_FUNC_0;
+	u32 nig_int_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 :
+				       NIG_REG_MASK_INTERRUPT_PORT0;
+	u32 aeu_mask;
+	u32 nig_mask = 0;
+
+	if (bp->attn_state & asserted)
+		BNX2X_ERR("IGU ERROR\n");
+
+	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port);
+	aeu_mask = REG_RD(bp, aeu_addr);
+
+	DP(NETIF_MSG_HW, "aeu_mask %x  newly asserted %x\n",
+	   aeu_mask, asserted);
+	aeu_mask &= ~(asserted & 0x3ff);
+	DP(NETIF_MSG_HW, "new mask %x\n", aeu_mask);
+
+	REG_WR(bp, aeu_addr, aeu_mask);
+	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port);
+
+	DP(NETIF_MSG_HW, "attn_state %x\n", bp->attn_state);
+	bp->attn_state |= asserted;
+	DP(NETIF_MSG_HW, "new state %x\n", bp->attn_state);
+
+	if (asserted & ATTN_HARD_WIRED_MASK) {
+		if (asserted & ATTN_NIG_FOR_FUNC) {
+
+			bnx2x_acquire_phy_lock(bp);
+
+			/* save nig interrupt mask */
+			nig_mask = REG_RD(bp, nig_int_mask_addr);
+			REG_WR(bp, nig_int_mask_addr, 0);
+
+			bnx2x_link_attn(bp);
+
+			/* handle unicore attn? */
+		}
+		if (asserted & ATTN_SW_TIMER_4_FUNC)
+			DP(NETIF_MSG_HW, "ATTN_SW_TIMER_4_FUNC!\n");
+
+		if (asserted & GPIO_2_FUNC)
+			DP(NETIF_MSG_HW, "GPIO_2_FUNC!\n");
+
+		if (asserted & GPIO_3_FUNC)
+			DP(NETIF_MSG_HW, "GPIO_3_FUNC!\n");
+
+		if (asserted & GPIO_4_FUNC)
+			DP(NETIF_MSG_HW, "GPIO_4_FUNC!\n");
+
+		if (port == 0) {
+			if (asserted & ATTN_GENERAL_ATTN_1) {
+				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_1!\n");
+				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_1, 0x0);
+			}
+			if (asserted & ATTN_GENERAL_ATTN_2) {
+				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_2!\n");
+				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_2, 0x0);
+			}
+			if (asserted & ATTN_GENERAL_ATTN_3) {
+				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_3!\n");
+				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_3, 0x0);
+			}
+		} else {
+			if (asserted & ATTN_GENERAL_ATTN_4) {
+				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_4!\n");
+				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_4, 0x0);
+			}
+			if (asserted & ATTN_GENERAL_ATTN_5) {
+				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_5!\n");
+				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_5, 0x0);
+			}
+			if (asserted & ATTN_GENERAL_ATTN_6) {
+				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_6!\n");
+				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_6, 0x0);
+			}
+		}
+
+	} /* if hardwired */
+
+	DP(NETIF_MSG_HW, "about to mask 0x%08x at HC addr 0x%x\n",
+	   asserted, hc_addr);
+	REG_WR(bp, hc_addr, asserted);
+
+	/* now set back the mask */
+	if (asserted & ATTN_NIG_FOR_FUNC) {
+		REG_WR(bp, nig_int_mask_addr, nig_mask);
+		bnx2x_release_phy_lock(bp);
+	}
+}
+
+static inline void bnx2x_fan_failure(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+
+	/* mark the failure */
+	bp->link_params.ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+	bp->link_params.ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
+	SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config,
+		 bp->link_params.ext_phy_config);
+
+	/* log the failure */
+	netdev_err(bp->dev, "Fan Failure on Network Controller has caused"
+	       " the driver to shutdown the card to prevent permanent"
+	       " damage.  Please contact OEM Support for assistance\n");
+}
+
+static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
+{
+	int port = BP_PORT(bp);
+	int reg_offset;
+	u32 val, swap_val, swap_override;
+
+	reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
+			     MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+
+	if (attn & AEU_INPUTS_ATTN_BITS_SPIO5) {
+
+		val = REG_RD(bp, reg_offset);
+		val &= ~AEU_INPUTS_ATTN_BITS_SPIO5;
+		REG_WR(bp, reg_offset, val);
+
+		BNX2X_ERR("SPIO5 hw attention\n");
+
+		/* Fan failure attention */
+		switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+			/* Low power mode is controlled by GPIO 2 */
+			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+				       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
+			/* The PHY reset is controlled by GPIO 1 */
+			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+				       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+			/* The PHY reset is controlled by GPIO 1 */
+			/* fake the port number to cancel the swap done in
+			   set_gpio() */
+			swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+			swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+			port = (swap_val && swap_override) ^ 1;
+			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+				       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
+			break;
+
+		default:
+			break;
+		}
+		bnx2x_fan_failure(bp);
+	}
+
+	if (attn & (AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 |
+		    AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1)) {
+		bnx2x_acquire_phy_lock(bp);
+		bnx2x_handle_module_detect_int(&bp->link_params);
+		bnx2x_release_phy_lock(bp);
+	}
+
+	if (attn & HW_INTERRUT_ASSERT_SET_0) {
+
+		val = REG_RD(bp, reg_offset);
+		val &= ~(attn & HW_INTERRUT_ASSERT_SET_0);
+		REG_WR(bp, reg_offset, val);
+
+		BNX2X_ERR("FATAL HW block attention set0 0x%x\n",
+			  (u32)(attn & HW_INTERRUT_ASSERT_SET_0));
+		bnx2x_panic();
+	}
+}
+
+static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn)
+{
+	u32 val;
+
+	if (attn & AEU_INPUTS_ATTN_BITS_DOORBELLQ_HW_INTERRUPT) {
+
+		val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR);
+		BNX2X_ERR("DB hw attention 0x%x\n", val);
+		/* DORQ discard attention */
+		if (val & 0x2)
+			BNX2X_ERR("FATAL error from DORQ\n");
+	}
+
+	if (attn & HW_INTERRUT_ASSERT_SET_1) {
+
+		int port = BP_PORT(bp);
+		int reg_offset;
+
+		reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1 :
+				     MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1);
+
+		val = REG_RD(bp, reg_offset);
+		val &= ~(attn & HW_INTERRUT_ASSERT_SET_1);
+		REG_WR(bp, reg_offset, val);
+
+		BNX2X_ERR("FATAL HW block attention set1 0x%x\n",
+			  (u32)(attn & HW_INTERRUT_ASSERT_SET_1));
+		bnx2x_panic();
+	}
+}
+
+static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn)
+{
+	u32 val;
+
+	if (attn & AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) {
+
+		val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR);
+		BNX2X_ERR("CFC hw attention 0x%x\n", val);
+		/* CFC error attention */
+		if (val & 0x2)
+			BNX2X_ERR("FATAL error from CFC\n");
+	}
+
+	if (attn & AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) {
+
+		val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0);
+		BNX2X_ERR("PXP hw attention 0x%x\n", val);
+		/* RQ_USDMDP_FIFO_OVERFLOW */
+		if (val & 0x18000)
+			BNX2X_ERR("FATAL error from PXP\n");
+	}
+
+	if (attn & HW_INTERRUT_ASSERT_SET_2) {
+
+		int port = BP_PORT(bp);
+		int reg_offset;
+
+		reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_2 :
+				     MISC_REG_AEU_ENABLE1_FUNC_0_OUT_2);
+
+		val = REG_RD(bp, reg_offset);
+		val &= ~(attn & HW_INTERRUT_ASSERT_SET_2);
+		REG_WR(bp, reg_offset, val);
+
+		BNX2X_ERR("FATAL HW block attention set2 0x%x\n",
+			  (u32)(attn & HW_INTERRUT_ASSERT_SET_2));
+		bnx2x_panic();
+	}
+}
+
+static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
+{
+	u32 val;
+
+	if (attn & EVEREST_GEN_ATTN_IN_USE_MASK) {
+
+		if (attn & BNX2X_PMF_LINK_ASSERT) {
+			int func = BP_FUNC(bp);
+
+			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0);
+			bp->mf_config = SHMEM_RD(bp,
+					   mf_cfg.func_mf_config[func].config);
+			val = SHMEM_RD(bp, func_mb[func].drv_status);
+			if (val & DRV_STATUS_DCC_EVENT_MASK)
+				bnx2x_dcc_event(bp,
+					    (val & DRV_STATUS_DCC_EVENT_MASK));
+			bnx2x__link_status_update(bp);
+			if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
+				bnx2x_pmf_update(bp);
+
+		} else if (attn & BNX2X_MC_ASSERT_BITS) {
+
+			BNX2X_ERR("MC assert!\n");
+			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_10, 0);
+			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_9, 0);
+			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_8, 0);
+			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_7, 0);
+			bnx2x_panic();
+
+		} else if (attn & BNX2X_MCP_ASSERT) {
+
+			BNX2X_ERR("MCP assert!\n");
+			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_11, 0);
+			bnx2x_fw_dump(bp);
+
+		} else
+			BNX2X_ERR("Unknown HW assert! (attn 0x%x)\n", attn);
+	}
+
+	if (attn & EVEREST_LATCHED_ATTN_IN_USE_MASK) {
+		BNX2X_ERR("LATCHED attention 0x%08x (masked)\n", attn);
+		if (attn & BNX2X_GRC_TIMEOUT) {
+			val = CHIP_IS_E1H(bp) ?
+				REG_RD(bp, MISC_REG_GRC_TIMEOUT_ATTN) : 0;
+			BNX2X_ERR("GRC time-out 0x%08x\n", val);
+		}
+		if (attn & BNX2X_GRC_RSV) {
+			val = CHIP_IS_E1H(bp) ?
+				REG_RD(bp, MISC_REG_GRC_RSV_ATTN) : 0;
+			BNX2X_ERR("GRC reserved 0x%08x\n", val);
+		}
+		REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x7ff);
+	}
+}
+
+#define BNX2X_MISC_GEN_REG      MISC_REG_GENERIC_POR_1
+#define LOAD_COUNTER_BITS	16 /* Number of bits for load counter */
+#define LOAD_COUNTER_MASK	(((u32)0x1 << LOAD_COUNTER_BITS) - 1)
+#define RESET_DONE_FLAG_MASK	(~LOAD_COUNTER_MASK)
+#define RESET_DONE_FLAG_SHIFT	LOAD_COUNTER_BITS
+#define CHIP_PARITY_SUPPORTED(bp)   (CHIP_IS_E1(bp) || CHIP_IS_E1H(bp))
+/*
+ * should be run under rtnl lock
+ */
+static inline void bnx2x_set_reset_done(struct bnx2x *bp)
+{
+	u32 val	= REG_RD(bp, BNX2X_MISC_GEN_REG);
+	val &= ~(1 << RESET_DONE_FLAG_SHIFT);
+	REG_WR(bp, BNX2X_MISC_GEN_REG, val);
+	barrier();
+	mmiowb();
+}
+
+/*
+ * should be run under rtnl lock
+ */
+static inline void bnx2x_set_reset_in_progress(struct bnx2x *bp)
+{
+	u32 val	= REG_RD(bp, BNX2X_MISC_GEN_REG);
+	val |= (1 << 16);
+	REG_WR(bp, BNX2X_MISC_GEN_REG, val);
+	barrier();
+	mmiowb();
+}
+
+/*
+ * should be run under rtnl lock
+ */
+bool bnx2x_reset_is_done(struct bnx2x *bp)
+{
+	u32 val	= REG_RD(bp, BNX2X_MISC_GEN_REG);
+	DP(NETIF_MSG_HW, "GEN_REG_VAL=0x%08x\n", val);
+	return (val & RESET_DONE_FLAG_MASK) ? false : true;
+}
+
+/*
+ * should be run under rtnl lock
+ */
+inline void bnx2x_inc_load_cnt(struct bnx2x *bp)
+{
+	u32 val1, val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+
+	DP(NETIF_MSG_HW, "Old GEN_REG_VAL=0x%08x\n", val);
+
+	val1 = ((val & LOAD_COUNTER_MASK) + 1) & LOAD_COUNTER_MASK;
+	REG_WR(bp, BNX2X_MISC_GEN_REG, (val & RESET_DONE_FLAG_MASK) | val1);
+	barrier();
+	mmiowb();
+}
+
+/*
+ * should be run under rtnl lock
+ */
+u32 bnx2x_dec_load_cnt(struct bnx2x *bp)
+{
+	u32 val1, val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+
+	DP(NETIF_MSG_HW, "Old GEN_REG_VAL=0x%08x\n", val);
+
+	val1 = ((val & LOAD_COUNTER_MASK) - 1) & LOAD_COUNTER_MASK;
+	REG_WR(bp, BNX2X_MISC_GEN_REG, (val & RESET_DONE_FLAG_MASK) | val1);
+	barrier();
+	mmiowb();
+
+	return val1;
+}
+
+/*
+ * should be run under rtnl lock
+ */
+static inline u32 bnx2x_get_load_cnt(struct bnx2x *bp)
+{
+	return REG_RD(bp, BNX2X_MISC_GEN_REG) & LOAD_COUNTER_MASK;
+}
+
+static inline void bnx2x_clear_load_cnt(struct bnx2x *bp)
+{
+	u32 val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+	REG_WR(bp, BNX2X_MISC_GEN_REG, val & (~LOAD_COUNTER_MASK));
+}
+
+static inline void _print_next_block(int idx, const char *blk)
+{
+	if (idx)
+		pr_cont(", ");
+	pr_cont("%s", blk);
+}
+
+static inline int bnx2x_print_blocks_with_parity0(u32 sig, int par_num)
+{
+	int i = 0;
+	u32 cur_bit = 0;
+	for (i = 0; sig; i++) {
+		cur_bit = ((u32)0x1 << i);
+		if (sig & cur_bit) {
+			switch (cur_bit) {
+			case AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR:
+				_print_next_block(par_num++, "BRB");
+				break;
+			case AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR:
+				_print_next_block(par_num++, "PARSER");
+				break;
+			case AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR:
+				_print_next_block(par_num++, "TSDM");
+				break;
+			case AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR:
+				_print_next_block(par_num++, "SEARCHER");
+				break;
+			case AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR:
+				_print_next_block(par_num++, "TSEMI");
+				break;
+			}
+
+			/* Clear the bit */
+			sig &= ~cur_bit;
+		}
+	}
+
+	return par_num;
+}
+
+static inline int bnx2x_print_blocks_with_parity1(u32 sig, int par_num)
+{
+	int i = 0;
+	u32 cur_bit = 0;
+	for (i = 0; sig; i++) {
+		cur_bit = ((u32)0x1 << i);
+		if (sig & cur_bit) {
+			switch (cur_bit) {
+			case AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR:
+				_print_next_block(par_num++, "PBCLIENT");
+				break;
+			case AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR:
+				_print_next_block(par_num++, "QM");
+				break;
+			case AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR:
+				_print_next_block(par_num++, "XSDM");
+				break;
+			case AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR:
+				_print_next_block(par_num++, "XSEMI");
+				break;
+			case AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR:
+				_print_next_block(par_num++, "DOORBELLQ");
+				break;
+			case AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR:
+				_print_next_block(par_num++, "VAUX PCI CORE");
+				break;
+			case AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR:
+				_print_next_block(par_num++, "DEBUG");
+				break;
+			case AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR:
+				_print_next_block(par_num++, "USDM");
+				break;
+			case AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR:
+				_print_next_block(par_num++, "USEMI");
+				break;
+			case AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR:
+				_print_next_block(par_num++, "UPB");
+				break;
+			case AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR:
+				_print_next_block(par_num++, "CSDM");
+				break;
+			}
+
+			/* Clear the bit */
+			sig &= ~cur_bit;
+		}
+	}
+
+	return par_num;
+}
+
+static inline int bnx2x_print_blocks_with_parity2(u32 sig, int par_num)
+{
+	int i = 0;
+	u32 cur_bit = 0;
+	for (i = 0; sig; i++) {
+		cur_bit = ((u32)0x1 << i);
+		if (sig & cur_bit) {
+			switch (cur_bit) {
+			case AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR:
+				_print_next_block(par_num++, "CSEMI");
+				break;
+			case AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR:
+				_print_next_block(par_num++, "PXP");
+				break;
+			case AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR:
+				_print_next_block(par_num++,
+					"PXPPCICLOCKCLIENT");
+				break;
+			case AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR:
+				_print_next_block(par_num++, "CFC");
+				break;
+			case AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR:
+				_print_next_block(par_num++, "CDU");
+				break;
+			case AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR:
+				_print_next_block(par_num++, "IGU");
+				break;
+			case AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR:
+				_print_next_block(par_num++, "MISC");
+				break;
+			}
+
+			/* Clear the bit */
+			sig &= ~cur_bit;
+		}
+	}
+
+	return par_num;
+}
+
+static inline int bnx2x_print_blocks_with_parity3(u32 sig, int par_num)
+{
+	int i = 0;
+	u32 cur_bit = 0;
+	for (i = 0; sig; i++) {
+		cur_bit = ((u32)0x1 << i);
+		if (sig & cur_bit) {
+			switch (cur_bit) {
+			case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY:
+				_print_next_block(par_num++, "MCP ROM");
+				break;
+			case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY:
+				_print_next_block(par_num++, "MCP UMP RX");
+				break;
+			case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY:
+				_print_next_block(par_num++, "MCP UMP TX");
+				break;
+			case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY:
+				_print_next_block(par_num++, "MCP SCPAD");
+				break;
+			}
+
+			/* Clear the bit */
+			sig &= ~cur_bit;
+		}
+	}
+
+	return par_num;
+}
+
+static inline bool bnx2x_parity_attn(struct bnx2x *bp, u32 sig0, u32 sig1,
+				     u32 sig2, u32 sig3)
+{
+	if ((sig0 & HW_PRTY_ASSERT_SET_0) || (sig1 & HW_PRTY_ASSERT_SET_1) ||
+	    (sig2 & HW_PRTY_ASSERT_SET_2) || (sig3 & HW_PRTY_ASSERT_SET_3)) {
+		int par_num = 0;
+		DP(NETIF_MSG_HW, "Was parity error: HW block parity attention: "
+			"[0]:0x%08x [1]:0x%08x "
+			"[2]:0x%08x [3]:0x%08x\n",
+			  sig0 & HW_PRTY_ASSERT_SET_0,
+			  sig1 & HW_PRTY_ASSERT_SET_1,
+			  sig2 & HW_PRTY_ASSERT_SET_2,
+			  sig3 & HW_PRTY_ASSERT_SET_3);
+		printk(KERN_ERR"%s: Parity errors detected in blocks: ",
+		       bp->dev->name);
+		par_num = bnx2x_print_blocks_with_parity0(
+			sig0 & HW_PRTY_ASSERT_SET_0, par_num);
+		par_num = bnx2x_print_blocks_with_parity1(
+			sig1 & HW_PRTY_ASSERT_SET_1, par_num);
+		par_num = bnx2x_print_blocks_with_parity2(
+			sig2 & HW_PRTY_ASSERT_SET_2, par_num);
+		par_num = bnx2x_print_blocks_with_parity3(
+			sig3 & HW_PRTY_ASSERT_SET_3, par_num);
+		printk("\n");
+		return true;
+	} else
+		return false;
+}
+
+bool bnx2x_chk_parity_attn(struct bnx2x *bp)
+{
+	struct attn_route attn;
+	int port = BP_PORT(bp);
+
+	attn.sig[0] = REG_RD(bp,
+		MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 +
+			     port*4);
+	attn.sig[1] = REG_RD(bp,
+		MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 +
+			     port*4);
+	attn.sig[2] = REG_RD(bp,
+		MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 +
+			     port*4);
+	attn.sig[3] = REG_RD(bp,
+		MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 +
+			     port*4);
+
+	return bnx2x_parity_attn(bp, attn.sig[0], attn.sig[1], attn.sig[2],
+					attn.sig[3]);
+}
+
+static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
+{
+	struct attn_route attn, *group_mask;
+	int port = BP_PORT(bp);
+	int index;
+	u32 reg_addr;
+	u32 val;
+	u32 aeu_mask;
+
+	/* need to take HW lock because MCP or other port might also
+	   try to handle this event */
+	bnx2x_acquire_alr(bp);
+
+	if (bnx2x_chk_parity_attn(bp)) {
+		bp->recovery_state = BNX2X_RECOVERY_INIT;
+		bnx2x_set_reset_in_progress(bp);
+		schedule_delayed_work(&bp->reset_task, 0);
+		/* Disable HW interrupts */
+		bnx2x_int_disable(bp);
+		bnx2x_release_alr(bp);
+		/* In case of parity errors don't handle attentions so that
+		 * other function would "see" parity errors.
+		 */
+		return;
+	}
+
+	attn.sig[0] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + port*4);
+	attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4);
+	attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4);
+	attn.sig[3] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + port*4);
+	DP(NETIF_MSG_HW, "attn: %08x %08x %08x %08x\n",
+	   attn.sig[0], attn.sig[1], attn.sig[2], attn.sig[3]);
+
+	for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
+		if (deasserted & (1 << index)) {
+			group_mask = &bp->attn_group[index];
+
+			DP(NETIF_MSG_HW, "group[%d]: %08x %08x %08x %08x\n",
+			   index, group_mask->sig[0], group_mask->sig[1],
+			   group_mask->sig[2], group_mask->sig[3]);
+
+			bnx2x_attn_int_deasserted3(bp,
+					attn.sig[3] & group_mask->sig[3]);
+			bnx2x_attn_int_deasserted1(bp,
+					attn.sig[1] & group_mask->sig[1]);
+			bnx2x_attn_int_deasserted2(bp,
+					attn.sig[2] & group_mask->sig[2]);
+			bnx2x_attn_int_deasserted0(bp,
+					attn.sig[0] & group_mask->sig[0]);
+		}
+	}
+
+	bnx2x_release_alr(bp);
+
+	reg_addr = (HC_REG_COMMAND_REG + port*32 + COMMAND_REG_ATTN_BITS_CLR);
+
+	val = ~deasserted;
+	DP(NETIF_MSG_HW, "about to mask 0x%08x at HC addr 0x%x\n",
+	   val, reg_addr);
+	REG_WR(bp, reg_addr, val);
+
+	if (~bp->attn_state & deasserted)
+		BNX2X_ERR("IGU ERROR\n");
+
+	reg_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
+			  MISC_REG_AEU_MASK_ATTN_FUNC_0;
+
+	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port);
+	aeu_mask = REG_RD(bp, reg_addr);
+
+	DP(NETIF_MSG_HW, "aeu_mask %x  newly deasserted %x\n",
+	   aeu_mask, deasserted);
+	aeu_mask |= (deasserted & 0x3ff);
+	DP(NETIF_MSG_HW, "new mask %x\n", aeu_mask);
+
+	REG_WR(bp, reg_addr, aeu_mask);
+	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port);
+
+	DP(NETIF_MSG_HW, "attn_state %x\n", bp->attn_state);
+	bp->attn_state &= ~deasserted;
+	DP(NETIF_MSG_HW, "new state %x\n", bp->attn_state);
+}
+
+static void bnx2x_attn_int(struct bnx2x *bp)
+{
+	/* read local copy of bits */
+	u32 attn_bits = le32_to_cpu(bp->def_status_blk->atten_status_block.
+								attn_bits);
+	u32 attn_ack = le32_to_cpu(bp->def_status_blk->atten_status_block.
+								attn_bits_ack);
+	u32 attn_state = bp->attn_state;
+
+	/* look for changed bits */
+	u32 asserted   =  attn_bits & ~attn_ack & ~attn_state;
+	u32 deasserted = ~attn_bits &  attn_ack &  attn_state;
+
+	DP(NETIF_MSG_HW,
+	   "attn_bits %x  attn_ack %x  asserted %x  deasserted %x\n",
+	   attn_bits, attn_ack, asserted, deasserted);
+
+	if (~(attn_bits ^ attn_ack) & (attn_bits ^ attn_state))
+		BNX2X_ERR("BAD attention state\n");
+
+	/* handle bits that were raised */
+	if (asserted)
+		bnx2x_attn_int_asserted(bp, asserted);
+
+	if (deasserted)
+		bnx2x_attn_int_deasserted(bp, deasserted);
+}
+
+static void bnx2x_sp_task(struct work_struct *work)
+{
+	struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work);
+	u16 status;
+
+	/* Return here if interrupt is disabled */
+	if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
+		DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
+		return;
+	}
+
+	status = bnx2x_update_dsb_idx(bp);
+/*	if (status == 0)				     */
+/*		BNX2X_ERR("spurious slowpath interrupt!\n"); */
+
+	DP(NETIF_MSG_INTR, "got a slowpath interrupt (status 0x%x)\n", status);
+
+	/* HW attentions */
+	if (status & 0x1) {
+		bnx2x_attn_int(bp);
+		status &= ~0x1;
+	}
+
+	/* CStorm events: STAT_QUERY */
+	if (status & 0x2) {
+		DP(BNX2X_MSG_SP, "CStorm events: STAT_QUERY\n");
+		status &= ~0x2;
+	}
+
+	if (unlikely(status))
+		DP(NETIF_MSG_INTR, "got an unknown interrupt! (status 0x%x)\n",
+		   status);
+
+	bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, le16_to_cpu(bp->def_att_idx),
+		     IGU_INT_NOP, 1);
+	bnx2x_ack_sb(bp, DEF_SB_ID, USTORM_ID, le16_to_cpu(bp->def_u_idx),
+		     IGU_INT_NOP, 1);
+	bnx2x_ack_sb(bp, DEF_SB_ID, CSTORM_ID, le16_to_cpu(bp->def_c_idx),
+		     IGU_INT_NOP, 1);
+	bnx2x_ack_sb(bp, DEF_SB_ID, XSTORM_ID, le16_to_cpu(bp->def_x_idx),
+		     IGU_INT_NOP, 1);
+	bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, le16_to_cpu(bp->def_t_idx),
+		     IGU_INT_ENABLE, 1);
+}
+
+irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
+{
+	struct net_device *dev = dev_instance;
+	struct bnx2x *bp = netdev_priv(dev);
+
+	/* Return here if interrupt is disabled */
+	if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
+		DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
+		return IRQ_HANDLED;
+	}
+
+	bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, 0, IGU_INT_DISABLE, 0);
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return IRQ_HANDLED;
+#endif
+
+#ifdef BCM_CNIC
+	{
+		struct cnic_ops *c_ops;
+
+		rcu_read_lock();
+		c_ops = rcu_dereference(bp->cnic_ops);
+		if (c_ops)
+			c_ops->cnic_handler(bp->cnic_data, NULL);
+		rcu_read_unlock();
+	}
+#endif
+	queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+
+	return IRQ_HANDLED;
+}
+
+/* end of slow path */
+
+static void bnx2x_timer(unsigned long data)
+{
+	struct bnx2x *bp = (struct bnx2x *) data;
+
+	if (!netif_running(bp->dev))
+		return;
+
+	if (atomic_read(&bp->intr_sem) != 0)
+		goto timer_restart;
+
+	if (poll) {
+		struct bnx2x_fastpath *fp = &bp->fp[0];
+		int rc;
+
+		bnx2x_tx_int(fp);
+		rc = bnx2x_rx_int(fp, 1000);
+	}
+
+	if (!BP_NOMCP(bp)) {
+		int func = BP_FUNC(bp);
+		u32 drv_pulse;
+		u32 mcp_pulse;
+
+		++bp->fw_drv_pulse_wr_seq;
+		bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK;
+		/* TBD - add SYSTEM_TIME */
+		drv_pulse = bp->fw_drv_pulse_wr_seq;
+		SHMEM_WR(bp, func_mb[func].drv_pulse_mb, drv_pulse);
+
+		mcp_pulse = (SHMEM_RD(bp, func_mb[func].mcp_pulse_mb) &
+			     MCP_PULSE_SEQ_MASK);
+		/* The delta between driver pulse and mcp response
+		 * should be 1 (before mcp response) or 0 (after mcp response)
+		 */
+		if ((drv_pulse != mcp_pulse) &&
+		    (drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK))) {
+			/* someone lost a heartbeat... */
+			BNX2X_ERR("drv_pulse (0x%x) != mcp_pulse (0x%x)\n",
+				  drv_pulse, mcp_pulse);
+		}
+	}
+
+	if (bp->state == BNX2X_STATE_OPEN)
+		bnx2x_stats_handle(bp, STATS_EVENT_UPDATE);
+
+timer_restart:
+	mod_timer(&bp->timer, jiffies + bp->current_interval);
+}
+
+/* end of Statistics */
+
+/* nic init */
+
+/*
+ * nic init service functions
+ */
+
+static void bnx2x_zero_sb(struct bnx2x *bp, int sb_id)
+{
+	int port = BP_PORT(bp);
+
+	/* "CSTORM" */
+	bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
+			CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, sb_id), 0,
+			CSTORM_SB_STATUS_BLOCK_U_SIZE / 4);
+	bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
+			CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id), 0,
+			CSTORM_SB_STATUS_BLOCK_C_SIZE / 4);
+}
+
+void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb,
+			  dma_addr_t mapping, int sb_id)
+{
+	int port = BP_PORT(bp);
+	int func = BP_FUNC(bp);
+	int index;
+	u64 section;
+
+	/* USTORM */
+	section = ((u64)mapping) + offsetof(struct host_status_block,
+					    u_status_block);
+	sb->u_status_block.status_block_id = sb_id;
+
+	REG_WR(bp, BAR_CSTRORM_INTMEM +
+	       CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, sb_id), U64_LO(section));
+	REG_WR(bp, BAR_CSTRORM_INTMEM +
+	       ((CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, sb_id)) + 4),
+	       U64_HI(section));
+	REG_WR8(bp, BAR_CSTRORM_INTMEM + FP_USB_FUNC_OFF +
+		CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, sb_id), func);
+
+	for (index = 0; index < HC_USTORM_SB_NUM_INDICES; index++)
+		REG_WR16(bp, BAR_CSTRORM_INTMEM +
+			 CSTORM_SB_HC_DISABLE_U_OFFSET(port, sb_id, index), 1);
+
+	/* CSTORM */
+	section = ((u64)mapping) + offsetof(struct host_status_block,
+					    c_status_block);
+	sb->c_status_block.status_block_id = sb_id;
+
+	REG_WR(bp, BAR_CSTRORM_INTMEM +
+	       CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, sb_id), U64_LO(section));
+	REG_WR(bp, BAR_CSTRORM_INTMEM +
+	       ((CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, sb_id)) + 4),
+	       U64_HI(section));
+	REG_WR8(bp, BAR_CSTRORM_INTMEM + FP_CSB_FUNC_OFF +
+		CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id), func);
+
+	for (index = 0; index < HC_CSTORM_SB_NUM_INDICES; index++)
+		REG_WR16(bp, BAR_CSTRORM_INTMEM +
+			 CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id, index), 1);
+
+	bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
+}
+
+static void bnx2x_zero_def_sb(struct bnx2x *bp)
+{
+	int func = BP_FUNC(bp);
+
+	bnx2x_init_fill(bp, TSEM_REG_FAST_MEMORY +
+			TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
+			sizeof(struct tstorm_def_status_block)/4);
+	bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
+			CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(func), 0,
+			sizeof(struct cstorm_def_status_block_u)/4);
+	bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
+			CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(func), 0,
+			sizeof(struct cstorm_def_status_block_c)/4);
+	bnx2x_init_fill(bp, XSEM_REG_FAST_MEMORY +
+			XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
+			sizeof(struct xstorm_def_status_block)/4);
+}
+
+static void bnx2x_init_def_sb(struct bnx2x *bp,
+			      struct host_def_status_block *def_sb,
+			      dma_addr_t mapping, int sb_id)
+{
+	int port = BP_PORT(bp);
+	int func = BP_FUNC(bp);
+	int index, val, reg_offset;
+	u64 section;
+
+	/* ATTN */
+	section = ((u64)mapping) + offsetof(struct host_def_status_block,
+					    atten_status_block);
+	def_sb->atten_status_block.status_block_id = sb_id;
+
+	bp->attn_state = 0;
+
+	reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
+			     MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+
+	for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
+		bp->attn_group[index].sig[0] = REG_RD(bp,
+						     reg_offset + 0x10*index);
+		bp->attn_group[index].sig[1] = REG_RD(bp,
+					       reg_offset + 0x4 + 0x10*index);
+		bp->attn_group[index].sig[2] = REG_RD(bp,
+					       reg_offset + 0x8 + 0x10*index);
+		bp->attn_group[index].sig[3] = REG_RD(bp,
+					       reg_offset + 0xc + 0x10*index);
+	}
+
+	reg_offset = (port ? HC_REG_ATTN_MSG1_ADDR_L :
+			     HC_REG_ATTN_MSG0_ADDR_L);
+
+	REG_WR(bp, reg_offset, U64_LO(section));
+	REG_WR(bp, reg_offset + 4, U64_HI(section));
+
+	reg_offset = (port ? HC_REG_ATTN_NUM_P1 : HC_REG_ATTN_NUM_P0);
+
+	val = REG_RD(bp, reg_offset);
+	val |= sb_id;
+	REG_WR(bp, reg_offset, val);
+
+	/* USTORM */
+	section = ((u64)mapping) + offsetof(struct host_def_status_block,
+					    u_def_status_block);
+	def_sb->u_def_status_block.status_block_id = sb_id;
+
+	REG_WR(bp, BAR_CSTRORM_INTMEM +
+	       CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(func), U64_LO(section));
+	REG_WR(bp, BAR_CSTRORM_INTMEM +
+	       ((CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(func)) + 4),
+	       U64_HI(section));
+	REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_USB_FUNC_OFF +
+		CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(func), func);
+
+	for (index = 0; index < HC_USTORM_DEF_SB_NUM_INDICES; index++)
+		REG_WR16(bp, BAR_CSTRORM_INTMEM +
+			 CSTORM_DEF_SB_HC_DISABLE_U_OFFSET(func, index), 1);
+
+	/* CSTORM */
+	section = ((u64)mapping) + offsetof(struct host_def_status_block,
+					    c_def_status_block);
+	def_sb->c_def_status_block.status_block_id = sb_id;
+
+	REG_WR(bp, BAR_CSTRORM_INTMEM +
+	       CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(func), U64_LO(section));
+	REG_WR(bp, BAR_CSTRORM_INTMEM +
+	       ((CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(func)) + 4),
+	       U64_HI(section));
+	REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_CSB_FUNC_OFF +
+		CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(func), func);
+
+	for (index = 0; index < HC_CSTORM_DEF_SB_NUM_INDICES; index++)
+		REG_WR16(bp, BAR_CSTRORM_INTMEM +
+			 CSTORM_DEF_SB_HC_DISABLE_C_OFFSET(func, index), 1);
+
+	/* TSTORM */
+	section = ((u64)mapping) + offsetof(struct host_def_status_block,
+					    t_def_status_block);
+	def_sb->t_def_status_block.status_block_id = sb_id;
+
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section));
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       ((TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4),
+	       U64_HI(section));
+	REG_WR8(bp, BAR_TSTRORM_INTMEM + DEF_TSB_FUNC_OFF +
+		TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func);
+
+	for (index = 0; index < HC_TSTORM_DEF_SB_NUM_INDICES; index++)
+		REG_WR16(bp, BAR_TSTRORM_INTMEM +
+			 TSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1);
+
+	/* XSTORM */
+	section = ((u64)mapping) + offsetof(struct host_def_status_block,
+					    x_def_status_block);
+	def_sb->x_def_status_block.status_block_id = sb_id;
+
+	REG_WR(bp, BAR_XSTRORM_INTMEM +
+	       XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section));
+	REG_WR(bp, BAR_XSTRORM_INTMEM +
+	       ((XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4),
+	       U64_HI(section));
+	REG_WR8(bp, BAR_XSTRORM_INTMEM + DEF_XSB_FUNC_OFF +
+		XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func);
+
+	for (index = 0; index < HC_XSTORM_DEF_SB_NUM_INDICES; index++)
+		REG_WR16(bp, BAR_XSTRORM_INTMEM +
+			 XSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1);
+
+	bp->stats_pending = 0;
+	bp->set_mac_pending = 0;
+
+	bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
+}
+
+void bnx2x_update_coalesce(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	int i;
+
+	for_each_queue(bp, i) {
+		int sb_id = bp->fp[i].sb_id;
+
+		/* HC_INDEX_U_ETH_RX_CQ_CONS */
+		REG_WR8(bp, BAR_CSTRORM_INTMEM +
+			CSTORM_SB_HC_TIMEOUT_U_OFFSET(port, sb_id,
+						      U_SB_ETH_RX_CQ_INDEX),
+			bp->rx_ticks/(4 * BNX2X_BTR));
+		REG_WR16(bp, BAR_CSTRORM_INTMEM +
+			 CSTORM_SB_HC_DISABLE_U_OFFSET(port, sb_id,
+						       U_SB_ETH_RX_CQ_INDEX),
+			 (bp->rx_ticks/(4 * BNX2X_BTR)) ? 0 : 1);
+
+		/* HC_INDEX_C_ETH_TX_CQ_CONS */
+		REG_WR8(bp, BAR_CSTRORM_INTMEM +
+			CSTORM_SB_HC_TIMEOUT_C_OFFSET(port, sb_id,
+						      C_SB_ETH_TX_CQ_INDEX),
+			bp->tx_ticks/(4 * BNX2X_BTR));
+		REG_WR16(bp, BAR_CSTRORM_INTMEM +
+			 CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id,
+						       C_SB_ETH_TX_CQ_INDEX),
+			 (bp->tx_ticks/(4 * BNX2X_BTR)) ? 0 : 1);
+	}
+}
+
+static void bnx2x_init_sp_ring(struct bnx2x *bp)
+{
+	int func = BP_FUNC(bp);
+
+	spin_lock_init(&bp->spq_lock);
+
+	bp->spq_left = MAX_SPQ_PENDING;
+	bp->spq_prod_idx = 0;
+	bp->dsb_sp_prod = BNX2X_SP_DSB_INDEX;
+	bp->spq_prod_bd = bp->spq;
+	bp->spq_last_bd = bp->spq_prod_bd + MAX_SP_DESC_CNT;
+
+	REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PAGE_BASE_OFFSET(func),
+	       U64_LO(bp->spq_mapping));
+	REG_WR(bp,
+	       XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PAGE_BASE_OFFSET(func) + 4,
+	       U64_HI(bp->spq_mapping));
+
+	REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PROD_OFFSET(func),
+	       bp->spq_prod_idx);
+}
+
+static void bnx2x_init_context(struct bnx2x *bp)
+{
+	int i;
+
+	/* Rx */
+	for_each_queue(bp, i) {
+		struct eth_context *context = bnx2x_sp(bp, context[i].eth);
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+		u8 cl_id = fp->cl_id;
+
+		context->ustorm_st_context.common.sb_index_numbers =
+						BNX2X_RX_SB_INDEX_NUM;
+		context->ustorm_st_context.common.clientId = cl_id;
+		context->ustorm_st_context.common.status_block_id = fp->sb_id;
+		context->ustorm_st_context.common.flags =
+			(USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT |
+			 USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS);
+		context->ustorm_st_context.common.statistics_counter_id =
+						cl_id;
+		context->ustorm_st_context.common.mc_alignment_log_size =
+						BNX2X_RX_ALIGN_SHIFT;
+		context->ustorm_st_context.common.bd_buff_size =
+						bp->rx_buf_size;
+		context->ustorm_st_context.common.bd_page_base_hi =
+						U64_HI(fp->rx_desc_mapping);
+		context->ustorm_st_context.common.bd_page_base_lo =
+						U64_LO(fp->rx_desc_mapping);
+		if (!fp->disable_tpa) {
+			context->ustorm_st_context.common.flags |=
+				USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA;
+			context->ustorm_st_context.common.sge_buff_size =
+				(u16)min_t(u32, SGE_PAGE_SIZE*PAGES_PER_SGE,
+					   0xffff);
+			context->ustorm_st_context.common.sge_page_base_hi =
+						U64_HI(fp->rx_sge_mapping);
+			context->ustorm_st_context.common.sge_page_base_lo =
+						U64_LO(fp->rx_sge_mapping);
+
+			context->ustorm_st_context.common.max_sges_for_packet =
+				SGE_PAGE_ALIGN(bp->dev->mtu) >> SGE_PAGE_SHIFT;
+			context->ustorm_st_context.common.max_sges_for_packet =
+				((context->ustorm_st_context.common.
+				  max_sges_for_packet + PAGES_PER_SGE - 1) &
+				 (~(PAGES_PER_SGE - 1))) >> PAGES_PER_SGE_SHIFT;
+		}
+
+		context->ustorm_ag_context.cdu_usage =
+			CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i),
+					       CDU_REGION_NUMBER_UCM_AG,
+					       ETH_CONNECTION_TYPE);
+
+		context->xstorm_ag_context.cdu_reserved =
+			CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i),
+					       CDU_REGION_NUMBER_XCM_AG,
+					       ETH_CONNECTION_TYPE);
+	}
+
+	/* Tx */
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+		struct eth_context *context =
+			bnx2x_sp(bp, context[i].eth);
+
+		context->cstorm_st_context.sb_index_number =
+						C_SB_ETH_TX_CQ_INDEX;
+		context->cstorm_st_context.status_block_id = fp->sb_id;
+
+		context->xstorm_st_context.tx_bd_page_base_hi =
+						U64_HI(fp->tx_desc_mapping);
+		context->xstorm_st_context.tx_bd_page_base_lo =
+						U64_LO(fp->tx_desc_mapping);
+		context->xstorm_st_context.statistics_data = (fp->cl_id |
+				XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE);
+	}
+}
+
+static void bnx2x_init_ind_table(struct bnx2x *bp)
+{
+	int func = BP_FUNC(bp);
+	int i;
+
+	if (bp->multi_mode == ETH_RSS_MODE_DISABLED)
+		return;
+
+	DP(NETIF_MSG_IFUP,
+	   "Initializing indirection table  multi_mode %d\n", bp->multi_mode);
+	for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++)
+		REG_WR8(bp, BAR_TSTRORM_INTMEM +
+			TSTORM_INDIRECTION_TABLE_OFFSET(func) + i,
+			bp->fp->cl_id + (i % bp->num_queues));
+}
+
+void bnx2x_set_client_config(struct bnx2x *bp)
+{
+	struct tstorm_eth_client_config tstorm_client = {0};
+	int port = BP_PORT(bp);
+	int i;
+
+	tstorm_client.mtu = bp->dev->mtu;
+	tstorm_client.config_flags =
+				(TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE |
+				 TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE);
+#ifdef BCM_VLAN
+	if (bp->rx_mode && bp->vlgrp && (bp->flags & HW_VLAN_RX_FLAG)) {
+		tstorm_client.config_flags |=
+				TSTORM_ETH_CLIENT_CONFIG_VLAN_REM_ENABLE;
+		DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
+	}
+#endif
+
+	for_each_queue(bp, i) {
+		tstorm_client.statistics_counter_id = bp->fp[i].cl_id;
+
+		REG_WR(bp, BAR_TSTRORM_INTMEM +
+		       TSTORM_CLIENT_CONFIG_OFFSET(port, bp->fp[i].cl_id),
+		       ((u32 *)&tstorm_client)[0]);
+		REG_WR(bp, BAR_TSTRORM_INTMEM +
+		       TSTORM_CLIENT_CONFIG_OFFSET(port, bp->fp[i].cl_id) + 4,
+		       ((u32 *)&tstorm_client)[1]);
+	}
+
+	DP(BNX2X_MSG_OFF, "tstorm_client: 0x%08x 0x%08x\n",
+	   ((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]);
+}
+
+void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
+{
+	struct tstorm_eth_mac_filter_config tstorm_mac_filter = {0};
+	int mode = bp->rx_mode;
+	int mask = bp->rx_mode_cl_mask;
+	int func = BP_FUNC(bp);
+	int port = BP_PORT(bp);
+	int i;
+	/* All but management unicast packets should pass to the host as well */
+	u32 llh_mask =
+		NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST |
+		NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST |
+		NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN |
+		NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN;
+
+	DP(NETIF_MSG_IFUP, "rx mode %d  mask 0x%x\n", mode, mask);
+
+	switch (mode) {
+	case BNX2X_RX_MODE_NONE: /* no Rx */
+		tstorm_mac_filter.ucast_drop_all = mask;
+		tstorm_mac_filter.mcast_drop_all = mask;
+		tstorm_mac_filter.bcast_drop_all = mask;
+		break;
+
+	case BNX2X_RX_MODE_NORMAL:
+		tstorm_mac_filter.bcast_accept_all = mask;
+		break;
+
+	case BNX2X_RX_MODE_ALLMULTI:
+		tstorm_mac_filter.mcast_accept_all = mask;
+		tstorm_mac_filter.bcast_accept_all = mask;
+		break;
+
+	case BNX2X_RX_MODE_PROMISC:
+		tstorm_mac_filter.ucast_accept_all = mask;
+		tstorm_mac_filter.mcast_accept_all = mask;
+		tstorm_mac_filter.bcast_accept_all = mask;
+		/* pass management unicast packets as well */
+		llh_mask |= NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST;
+		break;
+
+	default:
+		BNX2X_ERR("BAD rx mode (%d)\n", mode);
+		break;
+	}
+
+	REG_WR(bp,
+	       (port ? NIG_REG_LLH1_BRB1_DRV_MASK : NIG_REG_LLH0_BRB1_DRV_MASK),
+	       llh_mask);
+
+	for (i = 0; i < sizeof(struct tstorm_eth_mac_filter_config)/4; i++) {
+		REG_WR(bp, BAR_TSTRORM_INTMEM +
+		       TSTORM_MAC_FILTER_CONFIG_OFFSET(func) + i * 4,
+		       ((u32 *)&tstorm_mac_filter)[i]);
+
+/*		DP(NETIF_MSG_IFUP, "tstorm_mac_filter[%d]: 0x%08x\n", i,
+		   ((u32 *)&tstorm_mac_filter)[i]); */
+	}
+
+	if (mode != BNX2X_RX_MODE_NONE)
+		bnx2x_set_client_config(bp);
+}
+
+static void bnx2x_init_internal_common(struct bnx2x *bp)
+{
+	int i;
+
+	/* Zero this manually as its initialization is
+	   currently missing in the initTool */
+	for (i = 0; i < (USTORM_AGG_DATA_SIZE >> 2); i++)
+		REG_WR(bp, BAR_USTRORM_INTMEM +
+		       USTORM_AGG_DATA_OFFSET + i * 4, 0);
+}
+
+static void bnx2x_init_internal_port(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+
+	REG_WR(bp,
+	       BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_U_OFFSET(port), BNX2X_BTR);
+	REG_WR(bp,
+	       BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_C_OFFSET(port), BNX2X_BTR);
+	REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_HC_BTR_OFFSET(port), BNX2X_BTR);
+	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(port), BNX2X_BTR);
+}
+
+static void bnx2x_init_internal_func(struct bnx2x *bp)
+{
+	struct tstorm_eth_function_common_config tstorm_config = {0};
+	struct stats_indication_flags stats_flags = {0};
+	int port = BP_PORT(bp);
+	int func = BP_FUNC(bp);
+	int i, j;
+	u32 offset;
+	u16 max_agg_size;
+
+	tstorm_config.config_flags = RSS_FLAGS(bp);
+
+	if (is_multi(bp))
+		tstorm_config.rss_result_mask = MULTI_MASK;
+
+	/* Enable TPA if needed */
+	if (bp->flags & TPA_ENABLE_FLAG)
+		tstorm_config.config_flags |=
+			TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA;
+
+	if (IS_E1HMF(bp))
+		tstorm_config.config_flags |=
+				TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM;
+
+	tstorm_config.leading_client_id = BP_L_ID(bp);
+
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(func),
+	       (*(u32 *)&tstorm_config));
+
+	bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx until link is up */
+	bp->rx_mode_cl_mask = (1 << BP_L_ID(bp));
+	bnx2x_set_storm_rx_mode(bp);
+
+	for_each_queue(bp, i) {
+		u8 cl_id = bp->fp[i].cl_id;
+
+		/* reset xstorm per client statistics */
+		offset = BAR_XSTRORM_INTMEM +
+			 XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cl_id);
+		for (j = 0;
+		     j < sizeof(struct xstorm_per_client_stats) / 4; j++)
+			REG_WR(bp, offset + j*4, 0);
+
+		/* reset tstorm per client statistics */
+		offset = BAR_TSTRORM_INTMEM +
+			 TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cl_id);
+		for (j = 0;
+		     j < sizeof(struct tstorm_per_client_stats) / 4; j++)
+			REG_WR(bp, offset + j*4, 0);
+
+		/* reset ustorm per client statistics */
+		offset = BAR_USTRORM_INTMEM +
+			 USTORM_PER_COUNTER_ID_STATS_OFFSET(port, cl_id);
+		for (j = 0;
+		     j < sizeof(struct ustorm_per_client_stats) / 4; j++)
+			REG_WR(bp, offset + j*4, 0);
+	}
+
+	/* Init statistics related context */
+	stats_flags.collect_eth = 1;
+
+	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(func),
+	       ((u32 *)&stats_flags)[0]);
+	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(func) + 4,
+	       ((u32 *)&stats_flags)[1]);
+
+	REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(func),
+	       ((u32 *)&stats_flags)[0]);
+	REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(func) + 4,
+	       ((u32 *)&stats_flags)[1]);
+
+	REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_STATS_FLAGS_OFFSET(func),
+	       ((u32 *)&stats_flags)[0]);
+	REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_STATS_FLAGS_OFFSET(func) + 4,
+	       ((u32 *)&stats_flags)[1]);
+
+	REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(func),
+	       ((u32 *)&stats_flags)[0]);
+	REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(func) + 4,
+	       ((u32 *)&stats_flags)[1]);
+
+	REG_WR(bp, BAR_XSTRORM_INTMEM +
+	       XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func),
+	       U64_LO(bnx2x_sp_mapping(bp, fw_stats)));
+	REG_WR(bp, BAR_XSTRORM_INTMEM +
+	       XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func) + 4,
+	       U64_HI(bnx2x_sp_mapping(bp, fw_stats)));
+
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func),
+	       U64_LO(bnx2x_sp_mapping(bp, fw_stats)));
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func) + 4,
+	       U64_HI(bnx2x_sp_mapping(bp, fw_stats)));
+
+	REG_WR(bp, BAR_USTRORM_INTMEM +
+	       USTORM_ETH_STATS_QUERY_ADDR_OFFSET(func),
+	       U64_LO(bnx2x_sp_mapping(bp, fw_stats)));
+	REG_WR(bp, BAR_USTRORM_INTMEM +
+	       USTORM_ETH_STATS_QUERY_ADDR_OFFSET(func) + 4,
+	       U64_HI(bnx2x_sp_mapping(bp, fw_stats)));
+
+	if (CHIP_IS_E1H(bp)) {
+		REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNCTION_MODE_OFFSET,
+			IS_E1HMF(bp));
+		REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNCTION_MODE_OFFSET,
+			IS_E1HMF(bp));
+		REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNCTION_MODE_OFFSET,
+			IS_E1HMF(bp));
+		REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNCTION_MODE_OFFSET,
+			IS_E1HMF(bp));
+
+		REG_WR16(bp, BAR_XSTRORM_INTMEM + XSTORM_E1HOV_OFFSET(func),
+			 bp->e1hov);
+	}
+
+	/* Init CQ ring mapping and aggregation size, the FW limit is 8 frags */
+	max_agg_size = min_t(u32, (min_t(u32, 8, MAX_SKB_FRAGS) *
+				   SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff);
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		REG_WR(bp, BAR_USTRORM_INTMEM +
+		       USTORM_CQE_PAGE_BASE_OFFSET(port, fp->cl_id),
+		       U64_LO(fp->rx_comp_mapping));
+		REG_WR(bp, BAR_USTRORM_INTMEM +
+		       USTORM_CQE_PAGE_BASE_OFFSET(port, fp->cl_id) + 4,
+		       U64_HI(fp->rx_comp_mapping));
+
+		/* Next page */
+		REG_WR(bp, BAR_USTRORM_INTMEM +
+		       USTORM_CQE_PAGE_NEXT_OFFSET(port, fp->cl_id),
+		       U64_LO(fp->rx_comp_mapping + BCM_PAGE_SIZE));
+		REG_WR(bp, BAR_USTRORM_INTMEM +
+		       USTORM_CQE_PAGE_NEXT_OFFSET(port, fp->cl_id) + 4,
+		       U64_HI(fp->rx_comp_mapping + BCM_PAGE_SIZE));
+
+		REG_WR16(bp, BAR_USTRORM_INTMEM +
+			 USTORM_MAX_AGG_SIZE_OFFSET(port, fp->cl_id),
+			 max_agg_size);
+	}
+
+	/* dropless flow control */
+	if (CHIP_IS_E1H(bp)) {
+		struct ustorm_eth_rx_pause_data_e1h rx_pause = {0};
+
+		rx_pause.bd_thr_low = 250;
+		rx_pause.cqe_thr_low = 250;
+		rx_pause.cos = 1;
+		rx_pause.sge_thr_low = 0;
+		rx_pause.bd_thr_high = 350;
+		rx_pause.cqe_thr_high = 350;
+		rx_pause.sge_thr_high = 0;
+
+		for_each_queue(bp, i) {
+			struct bnx2x_fastpath *fp = &bp->fp[i];
+
+			if (!fp->disable_tpa) {
+				rx_pause.sge_thr_low = 150;
+				rx_pause.sge_thr_high = 250;
+			}
+
+
+			offset = BAR_USTRORM_INTMEM +
+				 USTORM_ETH_RING_PAUSE_DATA_OFFSET(port,
+								   fp->cl_id);
+			for (j = 0;
+			     j < sizeof(struct ustorm_eth_rx_pause_data_e1h)/4;
+			     j++)
+				REG_WR(bp, offset + j*4,
+				       ((u32 *)&rx_pause)[j]);
+		}
+	}
+
+	memset(&(bp->cmng), 0, sizeof(struct cmng_struct_per_port));
+
+	/* Init rate shaping and fairness contexts */
+	if (IS_E1HMF(bp)) {
+		int vn;
+
+		/* During init there is no active link
+		   Until link is up, set link rate to 10Gbps */
+		bp->link_vars.line_speed = SPEED_10000;
+		bnx2x_init_port_minmax(bp);
+
+		if (!BP_NOMCP(bp))
+			bp->mf_config =
+			      SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
+		bnx2x_calc_vn_weight_sum(bp);
+
+		for (vn = VN_0; vn < E1HVN_MAX; vn++)
+			bnx2x_init_vn_minmax(bp, 2*vn + port);
+
+		/* Enable rate shaping and fairness */
+		bp->cmng.flags.cmng_enables |=
+					CMNG_FLAGS_PER_PORT_RATE_SHAPING_VN;
+
+	} else {
+		/* rate shaping and fairness are disabled */
+		DP(NETIF_MSG_IFUP,
+		   "single function mode  minmax will be disabled\n");
+	}
+
+
+	/* Store cmng structures to internal memory */
+	if (bp->port.pmf)
+		for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++)
+			REG_WR(bp, BAR_XSTRORM_INTMEM +
+			       XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i * 4,
+			       ((u32 *)(&bp->cmng))[i]);
+}
+
+static void bnx2x_init_internal(struct bnx2x *bp, u32 load_code)
+{
+	switch (load_code) {
+	case FW_MSG_CODE_DRV_LOAD_COMMON:
+		bnx2x_init_internal_common(bp);
+		/* no break */
+
+	case FW_MSG_CODE_DRV_LOAD_PORT:
+		bnx2x_init_internal_port(bp);
+		/* no break */
+
+	case FW_MSG_CODE_DRV_LOAD_FUNCTION:
+		bnx2x_init_internal_func(bp);
+		break;
+
+	default:
+		BNX2X_ERR("Unknown load_code (0x%x) from MCP\n", load_code);
+		break;
+	}
+}
+
+void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
+{
+	int i;
+
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		fp->bp = bp;
+		fp->state = BNX2X_FP_STATE_CLOSED;
+		fp->index = i;
+		fp->cl_id = BP_L_ID(bp) + i;
+#ifdef BCM_CNIC
+		fp->sb_id = fp->cl_id + 1;
+#else
+		fp->sb_id = fp->cl_id;
+#endif
+		DP(NETIF_MSG_IFUP,
+		   "queue[%d]:  bnx2x_init_sb(%p,%p)  cl_id %d  sb %d\n",
+		   i, bp, fp->status_blk, fp->cl_id, fp->sb_id);
+		bnx2x_init_sb(bp, fp->status_blk, fp->status_blk_mapping,
+			      fp->sb_id);
+		bnx2x_update_fpsb_idx(fp);
+	}
+
+	/* ensure status block indices were read */
+	rmb();
+
+
+	bnx2x_init_def_sb(bp, bp->def_status_blk, bp->def_status_blk_mapping,
+			  DEF_SB_ID);
+	bnx2x_update_dsb_idx(bp);
+	bnx2x_update_coalesce(bp);
+	bnx2x_init_rx_rings(bp);
+	bnx2x_init_tx_ring(bp);
+	bnx2x_init_sp_ring(bp);
+	bnx2x_init_context(bp);
+	bnx2x_init_internal(bp, load_code);
+	bnx2x_init_ind_table(bp);
+	bnx2x_stats_init(bp);
+
+	/* At this point, we are ready for interrupts */
+	atomic_set(&bp->intr_sem, 0);
+
+	/* flush all before enabling interrupts */
+	mb();
+	mmiowb();
+
+	bnx2x_int_enable(bp);
+
+	/* Check for SPIO5 */
+	bnx2x_attn_int_deasserted0(bp,
+		REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + BP_PORT(bp)*4) &
+				   AEU_INPUTS_ATTN_BITS_SPIO5);
+}
+
+/* end of nic init */
+
+/*
+ * gzip service functions
+ */
+
+static int bnx2x_gunzip_init(struct bnx2x *bp)
+{
+	bp->gunzip_buf = dma_alloc_coherent(&bp->pdev->dev, FW_BUF_SIZE,
+					    &bp->gunzip_mapping, GFP_KERNEL);
+	if (bp->gunzip_buf  == NULL)
+		goto gunzip_nomem1;
+
+	bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL);
+	if (bp->strm  == NULL)
+		goto gunzip_nomem2;
+
+	bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(),
+				      GFP_KERNEL);
+	if (bp->strm->workspace == NULL)
+		goto gunzip_nomem3;
+
+	return 0;
+
+gunzip_nomem3:
+	kfree(bp->strm);
+	bp->strm = NULL;
+
+gunzip_nomem2:
+	dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf,
+			  bp->gunzip_mapping);
+	bp->gunzip_buf = NULL;
+
+gunzip_nomem1:
+	netdev_err(bp->dev, "Cannot allocate firmware buffer for"
+	       " un-compression\n");
+	return -ENOMEM;
+}
+
+static void bnx2x_gunzip_end(struct bnx2x *bp)
+{
+	kfree(bp->strm->workspace);
+
+	kfree(bp->strm);
+	bp->strm = NULL;
+
+	if (bp->gunzip_buf) {
+		dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf,
+				  bp->gunzip_mapping);
+		bp->gunzip_buf = NULL;
+	}
+}
+
+static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len)
+{
+	int n, rc;
+
+	/* check gzip header */
+	if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED)) {
+		BNX2X_ERR("Bad gzip header\n");
+		return -EINVAL;
+	}
+
+	n = 10;
+
+#define FNAME				0x8
+
+	if (zbuf[3] & FNAME)
+		while ((zbuf[n++] != 0) && (n < len));
+
+	bp->strm->next_in = (typeof(bp->strm->next_in))zbuf + n;
+	bp->strm->avail_in = len - n;
+	bp->strm->next_out = bp->gunzip_buf;
+	bp->strm->avail_out = FW_BUF_SIZE;
+
+	rc = zlib_inflateInit2(bp->strm, -MAX_WBITS);
+	if (rc != Z_OK)
+		return rc;
+
+	rc = zlib_inflate(bp->strm, Z_FINISH);
+	if ((rc != Z_OK) && (rc != Z_STREAM_END))
+		netdev_err(bp->dev, "Firmware decompression error: %s\n",
+			   bp->strm->msg);
+
+	bp->gunzip_outlen = (FW_BUF_SIZE - bp->strm->avail_out);
+	if (bp->gunzip_outlen & 0x3)
+		netdev_err(bp->dev, "Firmware decompression error:"
+				    " gunzip_outlen (%d) not aligned\n",
+				bp->gunzip_outlen);
+	bp->gunzip_outlen >>= 2;
+
+	zlib_inflateEnd(bp->strm);
+
+	if (rc == Z_STREAM_END)
+		return 0;
+
+	return rc;
+}
+
+/* nic load/unload */
+
+/*
+ * General service functions
+ */
+
+/* send a NIG loopback debug packet */
+static void bnx2x_lb_pckt(struct bnx2x *bp)
+{
+	u32 wb_write[3];
+
+	/* Ethernet source and destination addresses */
+	wb_write[0] = 0x55555555;
+	wb_write[1] = 0x55555555;
+	wb_write[2] = 0x20;		/* SOP */
+	REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3);
+
+	/* NON-IP protocol */
+	wb_write[0] = 0x09000000;
+	wb_write[1] = 0x55555555;
+	wb_write[2] = 0x10;		/* EOP, eop_bvalid = 0 */
+	REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3);
+}
+
+/* some of the internal memories
+ * are not directly readable from the driver
+ * to test them we send debug packets
+ */
+static int bnx2x_int_mem_test(struct bnx2x *bp)
+{
+	int factor;
+	int count, i;
+	u32 val = 0;
+
+	if (CHIP_REV_IS_FPGA(bp))
+		factor = 120;
+	else if (CHIP_REV_IS_EMUL(bp))
+		factor = 200;
+	else
+		factor = 1;
+
+	DP(NETIF_MSG_HW, "start part1\n");
+
+	/* Disable inputs of parser neighbor blocks */
+	REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0);
+	REG_WR(bp, TCM_REG_PRS_IFEN, 0x0);
+	REG_WR(bp, CFC_REG_DEBUG0, 0x1);
+	REG_WR(bp, NIG_REG_PRS_REQ_IN_EN, 0x0);
+
+	/*  Write 0 to parser credits for CFC search request */
+	REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0);
+
+	/* send Ethernet packet */
+	bnx2x_lb_pckt(bp);
+
+	/* TODO do i reset NIG statistic? */
+	/* Wait until NIG register shows 1 packet of size 0x10 */
+	count = 1000 * factor;
+	while (count) {
+
+		bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2);
+		val = *bnx2x_sp(bp, wb_data[0]);
+		if (val == 0x10)
+			break;
+
+		msleep(10);
+		count--;
+	}
+	if (val != 0x10) {
+		BNX2X_ERR("NIG timeout  val = 0x%x\n", val);
+		return -1;
+	}
+
+	/* Wait until PRS register shows 1 packet */
+	count = 1000 * factor;
+	while (count) {
+		val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS);
+		if (val == 1)
+			break;
+
+		msleep(10);
+		count--;
+	}
+	if (val != 0x1) {
+		BNX2X_ERR("PRS timeout val = 0x%x\n", val);
+		return -2;
+	}
+
+	/* Reset and init BRB, PRS */
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x03);
+	msleep(50);
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x03);
+	msleep(50);
+	bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE);
+
+	DP(NETIF_MSG_HW, "part2\n");
+
+	/* Disable inputs of parser neighbor blocks */
+	REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0);
+	REG_WR(bp, TCM_REG_PRS_IFEN, 0x0);
+	REG_WR(bp, CFC_REG_DEBUG0, 0x1);
+	REG_WR(bp, NIG_REG_PRS_REQ_IN_EN, 0x0);
+
+	/* Write 0 to parser credits for CFC search request */
+	REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0);
+
+	/* send 10 Ethernet packets */
+	for (i = 0; i < 10; i++)
+		bnx2x_lb_pckt(bp);
+
+	/* Wait until NIG register shows 10 + 1
+	   packets of size 11*0x10 = 0xb0 */
+	count = 1000 * factor;
+	while (count) {
+
+		bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2);
+		val = *bnx2x_sp(bp, wb_data[0]);
+		if (val == 0xb0)
+			break;
+
+		msleep(10);
+		count--;
+	}
+	if (val != 0xb0) {
+		BNX2X_ERR("NIG timeout  val = 0x%x\n", val);
+		return -3;
+	}
+
+	/* Wait until PRS register shows 2 packets */
+	val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS);
+	if (val != 2)
+		BNX2X_ERR("PRS timeout  val = 0x%x\n", val);
+
+	/* Write 1 to parser credits for CFC search request */
+	REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x1);
+
+	/* Wait until PRS register shows 3 packets */
+	msleep(10 * factor);
+	/* Wait until NIG register shows 1 packet of size 0x10 */
+	val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS);
+	if (val != 3)
+		BNX2X_ERR("PRS timeout  val = 0x%x\n", val);
+
+	/* clear NIG EOP FIFO */
+	for (i = 0; i < 11; i++)
+		REG_RD(bp, NIG_REG_INGRESS_EOP_LB_FIFO);
+	val = REG_RD(bp, NIG_REG_INGRESS_EOP_LB_EMPTY);
+	if (val != 1) {
+		BNX2X_ERR("clear of NIG failed\n");
+		return -4;
+	}
+
+	/* Reset and init BRB, PRS, NIG */
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x03);
+	msleep(50);
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x03);
+	msleep(50);
+	bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE);
+#ifndef BCM_CNIC
+	/* set NIC mode */
+	REG_WR(bp, PRS_REG_NIC_MODE, 1);
+#endif
+
+	/* Enable inputs of parser neighbor blocks */
+	REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x7fffffff);
+	REG_WR(bp, TCM_REG_PRS_IFEN, 0x1);
+	REG_WR(bp, CFC_REG_DEBUG0, 0x0);
+	REG_WR(bp, NIG_REG_PRS_REQ_IN_EN, 0x1);
+
+	DP(NETIF_MSG_HW, "done\n");
+
+	return 0; /* OK */
+}
+
+static void enable_blocks_attention(struct bnx2x *bp)
+{
+	REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0);
+	REG_WR(bp, PXP_REG_PXP_INT_MASK_1, 0);
+	REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0);
+	REG_WR(bp, CFC_REG_CFC_INT_MASK, 0);
+	REG_WR(bp, QM_REG_QM_INT_MASK, 0);
+	REG_WR(bp, TM_REG_TM_INT_MASK, 0);
+	REG_WR(bp, XSDM_REG_XSDM_INT_MASK_0, 0);
+	REG_WR(bp, XSDM_REG_XSDM_INT_MASK_1, 0);
+	REG_WR(bp, XCM_REG_XCM_INT_MASK, 0);
+/*	REG_WR(bp, XSEM_REG_XSEM_INT_MASK_0, 0); */
+/*	REG_WR(bp, XSEM_REG_XSEM_INT_MASK_1, 0); */
+	REG_WR(bp, USDM_REG_USDM_INT_MASK_0, 0);
+	REG_WR(bp, USDM_REG_USDM_INT_MASK_1, 0);
+	REG_WR(bp, UCM_REG_UCM_INT_MASK, 0);
+/*	REG_WR(bp, USEM_REG_USEM_INT_MASK_0, 0); */
+/*	REG_WR(bp, USEM_REG_USEM_INT_MASK_1, 0); */
+	REG_WR(bp, GRCBASE_UPB + PB_REG_PB_INT_MASK, 0);
+	REG_WR(bp, CSDM_REG_CSDM_INT_MASK_0, 0);
+	REG_WR(bp, CSDM_REG_CSDM_INT_MASK_1, 0);
+	REG_WR(bp, CCM_REG_CCM_INT_MASK, 0);
+/*	REG_WR(bp, CSEM_REG_CSEM_INT_MASK_0, 0); */
+/*	REG_WR(bp, CSEM_REG_CSEM_INT_MASK_1, 0); */
+	if (CHIP_REV_IS_FPGA(bp))
+		REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0, 0x580000);
+	else
+		REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0, 0x480000);
+	REG_WR(bp, TSDM_REG_TSDM_INT_MASK_0, 0);
+	REG_WR(bp, TSDM_REG_TSDM_INT_MASK_1, 0);
+	REG_WR(bp, TCM_REG_TCM_INT_MASK, 0);
+/*	REG_WR(bp, TSEM_REG_TSEM_INT_MASK_0, 0); */
+/*	REG_WR(bp, TSEM_REG_TSEM_INT_MASK_1, 0); */
+	REG_WR(bp, CDU_REG_CDU_INT_MASK, 0);
+	REG_WR(bp, DMAE_REG_DMAE_INT_MASK, 0);
+/*	REG_WR(bp, MISC_REG_MISC_INT_MASK, 0); */
+	REG_WR(bp, PBF_REG_PBF_INT_MASK, 0X18);		/* bit 3,4 masked */
+}
+
+static const struct {
+	u32 addr;
+	u32 mask;
+} bnx2x_parity_mask[] = {
+	{PXP_REG_PXP_PRTY_MASK, 0xffffffff},
+	{PXP2_REG_PXP2_PRTY_MASK_0, 0xffffffff},
+	{PXP2_REG_PXP2_PRTY_MASK_1, 0xffffffff},
+	{HC_REG_HC_PRTY_MASK, 0xffffffff},
+	{MISC_REG_MISC_PRTY_MASK, 0xffffffff},
+	{QM_REG_QM_PRTY_MASK, 0x0},
+	{DORQ_REG_DORQ_PRTY_MASK, 0x0},
+	{GRCBASE_UPB + PB_REG_PB_PRTY_MASK, 0x0},
+	{GRCBASE_XPB + PB_REG_PB_PRTY_MASK, 0x0},
+	{SRC_REG_SRC_PRTY_MASK, 0x4}, /* bit 2 */
+	{CDU_REG_CDU_PRTY_MASK, 0x0},
+	{CFC_REG_CFC_PRTY_MASK, 0x0},
+	{DBG_REG_DBG_PRTY_MASK, 0x0},
+	{DMAE_REG_DMAE_PRTY_MASK, 0x0},
+	{BRB1_REG_BRB1_PRTY_MASK, 0x0},
+	{PRS_REG_PRS_PRTY_MASK, (1<<6)},/* bit 6 */
+	{TSDM_REG_TSDM_PRTY_MASK, 0x18},/* bit 3,4 */
+	{CSDM_REG_CSDM_PRTY_MASK, 0x8},	/* bit 3 */
+	{USDM_REG_USDM_PRTY_MASK, 0x38},/* bit 3,4,5 */
+	{XSDM_REG_XSDM_PRTY_MASK, 0x8},	/* bit 3 */
+	{TSEM_REG_TSEM_PRTY_MASK_0, 0x0},
+	{TSEM_REG_TSEM_PRTY_MASK_1, 0x0},
+	{USEM_REG_USEM_PRTY_MASK_0, 0x0},
+	{USEM_REG_USEM_PRTY_MASK_1, 0x0},
+	{CSEM_REG_CSEM_PRTY_MASK_0, 0x0},
+	{CSEM_REG_CSEM_PRTY_MASK_1, 0x0},
+	{XSEM_REG_XSEM_PRTY_MASK_0, 0x0},
+	{XSEM_REG_XSEM_PRTY_MASK_1, 0x0}
+};
+
+static void enable_blocks_parity(struct bnx2x *bp)
+{
+	int i, mask_arr_len =
+		sizeof(bnx2x_parity_mask)/(sizeof(bnx2x_parity_mask[0]));
+
+	for (i = 0; i < mask_arr_len; i++)
+		REG_WR(bp, bnx2x_parity_mask[i].addr,
+			bnx2x_parity_mask[i].mask);
+}
+
+
+static void bnx2x_reset_common(struct bnx2x *bp)
+{
+	/* reset_common */
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
+	       0xd3ffff7f);
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403);
+}
+
+static void bnx2x_init_pxp(struct bnx2x *bp)
+{
+	u16 devctl;
+	int r_order, w_order;
+
+	pci_read_config_word(bp->pdev,
+			     bp->pcie_cap + PCI_EXP_DEVCTL, &devctl);
+	DP(NETIF_MSG_HW, "read 0x%x from devctl\n", devctl);
+	w_order = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
+	if (bp->mrrs == -1)
+		r_order = ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12);
+	else {
+		DP(NETIF_MSG_HW, "force read order to %d\n", bp->mrrs);
+		r_order = bp->mrrs;
+	}
+
+	bnx2x_init_pxp_arb(bp, r_order, w_order);
+}
+
+static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
+{
+	int is_required;
+	u32 val;
+	int port;
+
+	if (BP_NOMCP(bp))
+		return;
+
+	is_required = 0;
+	val = SHMEM_RD(bp, dev_info.shared_hw_config.config2) &
+	      SHARED_HW_CFG_FAN_FAILURE_MASK;
+
+	if (val == SHARED_HW_CFG_FAN_FAILURE_ENABLED)
+		is_required = 1;
+
+	/*
+	 * The fan failure mechanism is usually related to the PHY type since
+	 * the power consumption of the board is affected by the PHY. Currently,
+	 * fan is required for most designs with SFX7101, BCM8727 and BCM8481.
+	 */
+	else if (val == SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE)
+		for (port = PORT_0; port < PORT_MAX; port++) {
+			u32 phy_type =
+				SHMEM_RD(bp, dev_info.port_hw_config[port].
+					 external_phy_config) &
+				PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+			is_required |=
+				((phy_type ==
+				  PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) ||
+				 (phy_type ==
+				  PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
+				 (phy_type ==
+				  PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481));
+		}
+
+	DP(NETIF_MSG_HW, "fan detection setting: %d\n", is_required);
+
+	if (is_required == 0)
+		return;
+
+	/* Fan failure is indicated by SPIO 5 */
+	bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5,
+		       MISC_REGISTERS_SPIO_INPUT_HI_Z);
+
+	/* set to active low mode */
+	val = REG_RD(bp, MISC_REG_SPIO_INT);
+	val |= ((1 << MISC_REGISTERS_SPIO_5) <<
+					MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
+	REG_WR(bp, MISC_REG_SPIO_INT, val);
+
+	/* enable interrupt to signal the IGU */
+	val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
+	val |= (1 << MISC_REGISTERS_SPIO_5);
+	REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
+}
+
+static int bnx2x_init_common(struct bnx2x *bp)
+{
+	u32 val, i;
+#ifdef BCM_CNIC
+	u32 wb_write[2];
+#endif
+
+	DP(BNX2X_MSG_MCP, "starting common init  func %d\n", BP_FUNC(bp));
+
+	bnx2x_reset_common(bp);
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff);
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, 0xfffc);
+
+	bnx2x_init_block(bp, MISC_BLOCK, COMMON_STAGE);
+	if (CHIP_IS_E1H(bp))
+		REG_WR(bp, MISC_REG_E1HMF_MODE, IS_E1HMF(bp));
+
+	REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x100);
+	msleep(30);
+	REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x0);
+
+	bnx2x_init_block(bp, PXP_BLOCK, COMMON_STAGE);
+	if (CHIP_IS_E1(bp)) {
+		/* enable HW interrupt from PXP on USDM overflow
+		   bit 16 on INT_MASK_0 */
+		REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0);
+	}
+
+	bnx2x_init_block(bp, PXP2_BLOCK, COMMON_STAGE);
+	bnx2x_init_pxp(bp);
+
+#ifdef __BIG_ENDIAN
+	REG_WR(bp, PXP2_REG_RQ_QM_ENDIAN_M, 1);
+	REG_WR(bp, PXP2_REG_RQ_TM_ENDIAN_M, 1);
+	REG_WR(bp, PXP2_REG_RQ_SRC_ENDIAN_M, 1);
+	REG_WR(bp, PXP2_REG_RQ_CDU_ENDIAN_M, 1);
+	REG_WR(bp, PXP2_REG_RQ_DBG_ENDIAN_M, 1);
+	/* make sure this value is 0 */
+	REG_WR(bp, PXP2_REG_RQ_HC_ENDIAN_M, 0);
+
+/*	REG_WR(bp, PXP2_REG_RD_PBF_SWAP_MODE, 1); */
+	REG_WR(bp, PXP2_REG_RD_QM_SWAP_MODE, 1);
+	REG_WR(bp, PXP2_REG_RD_TM_SWAP_MODE, 1);
+	REG_WR(bp, PXP2_REG_RD_SRC_SWAP_MODE, 1);
+	REG_WR(bp, PXP2_REG_RD_CDURD_SWAP_MODE, 1);
+#endif
+
+	REG_WR(bp, PXP2_REG_RQ_CDU_P_SIZE, 2);
+#ifdef BCM_CNIC
+	REG_WR(bp, PXP2_REG_RQ_TM_P_SIZE, 5);
+	REG_WR(bp, PXP2_REG_RQ_QM_P_SIZE, 5);
+	REG_WR(bp, PXP2_REG_RQ_SRC_P_SIZE, 5);
+#endif
+
+	if (CHIP_REV_IS_FPGA(bp) && CHIP_IS_E1H(bp))
+		REG_WR(bp, PXP2_REG_PGL_TAGS_LIMIT, 0x1);
+
+	/* let the HW do it's magic ... */
+	msleep(100);
+	/* finish PXP init */
+	val = REG_RD(bp, PXP2_REG_RQ_CFG_DONE);
+	if (val != 1) {
+		BNX2X_ERR("PXP2 CFG failed\n");
+		return -EBUSY;
+	}
+	val = REG_RD(bp, PXP2_REG_RD_INIT_DONE);
+	if (val != 1) {
+		BNX2X_ERR("PXP2 RD_INIT failed\n");
+		return -EBUSY;
+	}
+
+	REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0);
+	REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0);
+
+	bnx2x_init_block(bp, DMAE_BLOCK, COMMON_STAGE);
+
+	/* clean the DMAE memory */
+	bp->dmae_ready = 1;
+	bnx2x_init_fill(bp, TSEM_REG_PRAM, 0, 8);
+
+	bnx2x_init_block(bp, TCM_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, UCM_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, CCM_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, XCM_BLOCK, COMMON_STAGE);
+
+	bnx2x_read_dmae(bp, XSEM_REG_PASSIVE_BUFFER, 3);
+	bnx2x_read_dmae(bp, CSEM_REG_PASSIVE_BUFFER, 3);
+	bnx2x_read_dmae(bp, TSEM_REG_PASSIVE_BUFFER, 3);
+	bnx2x_read_dmae(bp, USEM_REG_PASSIVE_BUFFER, 3);
+
+	bnx2x_init_block(bp, QM_BLOCK, COMMON_STAGE);
+
+#ifdef BCM_CNIC
+	wb_write[0] = 0;
+	wb_write[1] = 0;
+	for (i = 0; i < 64; i++) {
+		REG_WR(bp, QM_REG_BASEADDR + i*4, 1024 * 4 * (i%16));
+		bnx2x_init_ind_wr(bp, QM_REG_PTRTBL + i*8, wb_write, 2);
+
+		if (CHIP_IS_E1H(bp)) {
+			REG_WR(bp, QM_REG_BASEADDR_EXT_A + i*4, 1024*4*(i%16));
+			bnx2x_init_ind_wr(bp, QM_REG_PTRTBL_EXT_A + i*8,
+					  wb_write, 2);
+		}
+	}
+#endif
+	/* soft reset pulse */
+	REG_WR(bp, QM_REG_SOFT_RESET, 1);
+	REG_WR(bp, QM_REG_SOFT_RESET, 0);
+
+#ifdef BCM_CNIC
+	bnx2x_init_block(bp, TIMERS_BLOCK, COMMON_STAGE);
+#endif
+
+	bnx2x_init_block(bp, DQ_BLOCK, COMMON_STAGE);
+	REG_WR(bp, DORQ_REG_DPM_CID_OFST, BCM_PAGE_SHIFT);
+	if (!CHIP_REV_IS_SLOW(bp)) {
+		/* enable hw interrupt from doorbell Q */
+		REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0);
+	}
+
+	bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE);
+	REG_WR(bp, PRS_REG_A_PRSU_20, 0xf);
+#ifndef BCM_CNIC
+	/* set NIC mode */
+	REG_WR(bp, PRS_REG_NIC_MODE, 1);
+#endif
+	if (CHIP_IS_E1H(bp))
+		REG_WR(bp, PRS_REG_E1HOV_MODE, IS_E1HMF(bp));
+
+	bnx2x_init_block(bp, TSDM_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, CSDM_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, USDM_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, XSDM_BLOCK, COMMON_STAGE);
+
+	bnx2x_init_fill(bp, TSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp));
+	bnx2x_init_fill(bp, USEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp));
+	bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp));
+	bnx2x_init_fill(bp, XSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp));
+
+	bnx2x_init_block(bp, TSEM_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, USEM_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, CSEM_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, XSEM_BLOCK, COMMON_STAGE);
+
+	/* sync semi rtc */
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
+	       0x80000000);
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET,
+	       0x80000000);
+
+	bnx2x_init_block(bp, UPB_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, XPB_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, PBF_BLOCK, COMMON_STAGE);
+
+	REG_WR(bp, SRC_REG_SOFT_RST, 1);
+	for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4)
+		REG_WR(bp, i, random32());
+	bnx2x_init_block(bp, SRCH_BLOCK, COMMON_STAGE);
+#ifdef BCM_CNIC
+	REG_WR(bp, SRC_REG_KEYSEARCH_0, 0x63285672);
+	REG_WR(bp, SRC_REG_KEYSEARCH_1, 0x24b8f2cc);
+	REG_WR(bp, SRC_REG_KEYSEARCH_2, 0x223aef9b);
+	REG_WR(bp, SRC_REG_KEYSEARCH_3, 0x26001e3a);
+	REG_WR(bp, SRC_REG_KEYSEARCH_4, 0x7ae91116);
+	REG_WR(bp, SRC_REG_KEYSEARCH_5, 0x5ce5230b);
+	REG_WR(bp, SRC_REG_KEYSEARCH_6, 0x298d8adf);
+	REG_WR(bp, SRC_REG_KEYSEARCH_7, 0x6eb0ff09);
+	REG_WR(bp, SRC_REG_KEYSEARCH_8, 0x1830f82f);
+	REG_WR(bp, SRC_REG_KEYSEARCH_9, 0x01e46be7);
+#endif
+	REG_WR(bp, SRC_REG_SOFT_RST, 0);
+
+	if (sizeof(union cdu_context) != 1024)
+		/* we currently assume that a context is 1024 bytes */
+		dev_alert(&bp->pdev->dev, "please adjust the size "
+					  "of cdu_context(%ld)\n",
+			 (long)sizeof(union cdu_context));
+
+	bnx2x_init_block(bp, CDU_BLOCK, COMMON_STAGE);
+	val = (4 << 24) + (0 << 12) + 1024;
+	REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val);
+
+	bnx2x_init_block(bp, CFC_BLOCK, COMMON_STAGE);
+	REG_WR(bp, CFC_REG_INIT_REG, 0x7FF);
+	/* enable context validation interrupt from CFC */
+	REG_WR(bp, CFC_REG_CFC_INT_MASK, 0);
+
+	/* set the thresholds to prevent CFC/CDU race */
+	REG_WR(bp, CFC_REG_DEBUG0, 0x20020000);
+
+	bnx2x_init_block(bp, HC_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, MISC_AEU_BLOCK, COMMON_STAGE);
+
+	bnx2x_init_block(bp, PXPCS_BLOCK, COMMON_STAGE);
+	/* Reset PCIE errors for debug */
+	REG_WR(bp, 0x2814, 0xffffffff);
+	REG_WR(bp, 0x3820, 0xffffffff);
+
+	bnx2x_init_block(bp, EMAC0_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, EMAC1_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, DBU_BLOCK, COMMON_STAGE);
+	bnx2x_init_block(bp, DBG_BLOCK, COMMON_STAGE);
+
+	bnx2x_init_block(bp, NIG_BLOCK, COMMON_STAGE);
+	if (CHIP_IS_E1H(bp)) {
+		REG_WR(bp, NIG_REG_LLH_MF_MODE, IS_E1HMF(bp));
+		REG_WR(bp, NIG_REG_LLH_E1HOV_MODE, IS_E1HMF(bp));
+	}
+
+	if (CHIP_REV_IS_SLOW(bp))
+		msleep(200);
+
+	/* finish CFC init */
+	val = reg_poll(bp, CFC_REG_LL_INIT_DONE, 1, 100, 10);
+	if (val != 1) {
+		BNX2X_ERR("CFC LL_INIT failed\n");
+		return -EBUSY;
+	}
+	val = reg_poll(bp, CFC_REG_AC_INIT_DONE, 1, 100, 10);
+	if (val != 1) {
+		BNX2X_ERR("CFC AC_INIT failed\n");
+		return -EBUSY;
+	}
+	val = reg_poll(bp, CFC_REG_CAM_INIT_DONE, 1, 100, 10);
+	if (val != 1) {
+		BNX2X_ERR("CFC CAM_INIT failed\n");
+		return -EBUSY;
+	}
+	REG_WR(bp, CFC_REG_DEBUG0, 0);
+
+	/* read NIG statistic
+	   to see if this is our first up since powerup */
+	bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2);
+	val = *bnx2x_sp(bp, wb_data[0]);
+
+	/* do internal memory self test */
+	if ((CHIP_IS_E1(bp)) && (val == 0) && bnx2x_int_mem_test(bp)) {
+		BNX2X_ERR("internal mem self test failed\n");
+		return -EBUSY;
+	}
+
+	switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
+	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+		bp->port.need_hw_lock = 1;
+		break;
+
+	default:
+		break;
+	}
+
+	bnx2x_setup_fan_failure_detection(bp);
+
+	/* clear PXP2 attentions */
+	REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0);
+
+	enable_blocks_attention(bp);
+	if (CHIP_PARITY_SUPPORTED(bp))
+		enable_blocks_parity(bp);
+
+	if (!BP_NOMCP(bp)) {
+		bnx2x_acquire_phy_lock(bp);
+		bnx2x_common_init_phy(bp, bp->common.shmem_base);
+		bnx2x_release_phy_lock(bp);
+	} else
+		BNX2X_ERR("Bootcode is missing - can not initialize link\n");
+
+	return 0;
+}
+
+static int bnx2x_init_port(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	int init_stage = port ? PORT1_STAGE : PORT0_STAGE;
+	u32 low, high;
+	u32 val;
+
+	DP(BNX2X_MSG_MCP, "starting port init  port %d\n", port);
+
+	REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0);
+
+	bnx2x_init_block(bp, PXP_BLOCK, init_stage);
+	bnx2x_init_block(bp, PXP2_BLOCK, init_stage);
+
+	bnx2x_init_block(bp, TCM_BLOCK, init_stage);
+	bnx2x_init_block(bp, UCM_BLOCK, init_stage);
+	bnx2x_init_block(bp, CCM_BLOCK, init_stage);
+	bnx2x_init_block(bp, XCM_BLOCK, init_stage);
+
+#ifdef BCM_CNIC
+	REG_WR(bp, QM_REG_CONNNUM_0 + port*4, 1024/16 - 1);
+
+	bnx2x_init_block(bp, TIMERS_BLOCK, init_stage);
+	REG_WR(bp, TM_REG_LIN0_SCAN_TIME + port*4, 20);
+	REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + port*4, 31);
+#endif
+
+	bnx2x_init_block(bp, DQ_BLOCK, init_stage);
+
+	bnx2x_init_block(bp, BRB1_BLOCK, init_stage);
+	if (CHIP_REV_IS_SLOW(bp) && !CHIP_IS_E1H(bp)) {
+		/* no pause for emulation and FPGA */
+		low = 0;
+		high = 513;
+	} else {
+		if (IS_E1HMF(bp))
+			low = ((bp->flags & ONE_PORT_FLAG) ? 160 : 246);
+		else if (bp->dev->mtu > 4096) {
+			if (bp->flags & ONE_PORT_FLAG)
+				low = 160;
+			else {
+				val = bp->dev->mtu;
+				/* (24*1024 + val*4)/256 */
+				low = 96 + (val/64) + ((val % 64) ? 1 : 0);
+			}
+		} else
+			low = ((bp->flags & ONE_PORT_FLAG) ? 80 : 160);
+		high = low + 56;	/* 14*1024/256 */
+	}
+	REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_0 + port*4, low);
+	REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0 + port*4, high);
+
+
+	bnx2x_init_block(bp, PRS_BLOCK, init_stage);
+
+	bnx2x_init_block(bp, TSDM_BLOCK, init_stage);
+	bnx2x_init_block(bp, CSDM_BLOCK, init_stage);
+	bnx2x_init_block(bp, USDM_BLOCK, init_stage);
+	bnx2x_init_block(bp, XSDM_BLOCK, init_stage);
+
+	bnx2x_init_block(bp, TSEM_BLOCK, init_stage);
+	bnx2x_init_block(bp, USEM_BLOCK, init_stage);
+	bnx2x_init_block(bp, CSEM_BLOCK, init_stage);
+	bnx2x_init_block(bp, XSEM_BLOCK, init_stage);
+
+	bnx2x_init_block(bp, UPB_BLOCK, init_stage);
+	bnx2x_init_block(bp, XPB_BLOCK, init_stage);
+
+	bnx2x_init_block(bp, PBF_BLOCK, init_stage);
+
+	/* configure PBF to work without PAUSE mtu 9000 */
+	REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
+
+	/* update threshold */
+	REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, (9040/16));
+	/* update init credit */
+	REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, (9040/16) + 553 - 22);
+
+	/* probe changes */
+	REG_WR(bp, PBF_REG_INIT_P0 + port*4, 1);
+	msleep(5);
+	REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0);
+
+#ifdef BCM_CNIC
+	bnx2x_init_block(bp, SRCH_BLOCK, init_stage);
+#endif
+	bnx2x_init_block(bp, CDU_BLOCK, init_stage);
+	bnx2x_init_block(bp, CFC_BLOCK, init_stage);
+
+	if (CHIP_IS_E1(bp)) {
+		REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0);
+		REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0);
+	}
+	bnx2x_init_block(bp, HC_BLOCK, init_stage);
+
+	bnx2x_init_block(bp, MISC_AEU_BLOCK, init_stage);
+	/* init aeu_mask_attn_func_0/1:
+	 *  - SF mode: bits 3-7 are masked. only bits 0-2 are in use
+	 *  - MF mode: bit 3 is masked. bits 0-2 are in use as in SF
+	 *             bits 4-7 are used for "per vn group attention" */
+	REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4,
+	       (IS_E1HMF(bp) ? 0xF7 : 0x7));
+
+	bnx2x_init_block(bp, PXPCS_BLOCK, init_stage);
+	bnx2x_init_block(bp, EMAC0_BLOCK, init_stage);
+	bnx2x_init_block(bp, EMAC1_BLOCK, init_stage);
+	bnx2x_init_block(bp, DBU_BLOCK, init_stage);
+	bnx2x_init_block(bp, DBG_BLOCK, init_stage);
+
+	bnx2x_init_block(bp, NIG_BLOCK, init_stage);
+
+	REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);
+
+	if (CHIP_IS_E1H(bp)) {
+		/* 0x2 disable e1hov, 0x1 enable */
+		REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK_MF + port*4,
+		       (IS_E1HMF(bp) ? 0x1 : 0x2));
+
+		{
+			REG_WR(bp, NIG_REG_LLFC_ENABLE_0 + port*4, 0);
+			REG_WR(bp, NIG_REG_LLFC_OUT_EN_0 + port*4, 0);
+			REG_WR(bp, NIG_REG_PAUSE_ENABLE_0 + port*4, 1);
+		}
+	}
+
+	bnx2x_init_block(bp, MCP_BLOCK, init_stage);
+	bnx2x_init_block(bp, DMAE_BLOCK, init_stage);
+
+	switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
+	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+		{
+		u32 swap_val, swap_override, aeu_gpio_mask, offset;
+
+		bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
+			       MISC_REGISTERS_GPIO_INPUT_HI_Z, port);
+
+		/* The GPIO should be swapped if the swap register is
+		   set and active */
+		swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+		swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+
+		/* Select function upon port-swap configuration */
+		if (port == 0) {
+			offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
+			aeu_gpio_mask = (swap_val && swap_override) ?
+				AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
+				AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
+		} else {
+			offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
+			aeu_gpio_mask = (swap_val && swap_override) ?
+				AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
+				AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
+		}
+		val = REG_RD(bp, offset);
+		/* add GPIO3 to group */
+		val |= aeu_gpio_mask;
+		REG_WR(bp, offset, val);
+		}
+		break;
+
+	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+		/* add SPIO 5 to group 0 */
+		{
+		u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
+				       MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+		val = REG_RD(bp, reg_addr);
+		val |= AEU_INPUTS_ATTN_BITS_SPIO5;
+		REG_WR(bp, reg_addr, val);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	bnx2x__link_reset(bp);
+
+	return 0;
+}
+
+#define ILT_PER_FUNC		(768/2)
+#define FUNC_ILT_BASE(func)	(func * ILT_PER_FUNC)
+/* the phys address is shifted right 12 bits and has an added
+   1=valid bit added to the 53rd bit
+   then since this is a wide register(TM)
+   we split it into two 32 bit writes
+ */
+#define ONCHIP_ADDR1(x)		((u32)(((u64)x >> 12) & 0xFFFFFFFF))
+#define ONCHIP_ADDR2(x)		((u32)((1 << 20) | ((u64)x >> 44)))
+#define PXP_ONE_ILT(x)		(((x) << 10) | x)
+#define PXP_ILT_RANGE(f, l)	(((l) << 10) | f)
+
+#ifdef BCM_CNIC
+#define CNIC_ILT_LINES		127
+#define CNIC_CTX_PER_ILT	16
+#else
+#define CNIC_ILT_LINES		0
+#endif
+
+static void bnx2x_ilt_wr(struct bnx2x *bp, u32 index, dma_addr_t addr)
+{
+	int reg;
+
+	if (CHIP_IS_E1H(bp))
+		reg = PXP2_REG_RQ_ONCHIP_AT_B0 + index*8;
+	else /* E1 */
+		reg = PXP2_REG_RQ_ONCHIP_AT + index*8;
+
+	bnx2x_wb_wr(bp, reg, ONCHIP_ADDR1(addr), ONCHIP_ADDR2(addr));
+}
+
+static int bnx2x_init_func(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	int func = BP_FUNC(bp);
+	u32 addr, val;
+	int i;
+
+	DP(BNX2X_MSG_MCP, "starting func init  func %d\n", func);
+
+	/* set MSI reconfigure capability */
+	addr = (port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0);
+	val = REG_RD(bp, addr);
+	val |= HC_CONFIG_0_REG_MSI_ATTN_EN_0;
+	REG_WR(bp, addr, val);
+
+	i = FUNC_ILT_BASE(func);
+
+	bnx2x_ilt_wr(bp, i, bnx2x_sp_mapping(bp, context));
+	if (CHIP_IS_E1H(bp)) {
+		REG_WR(bp, PXP2_REG_RQ_CDU_FIRST_ILT, i);
+		REG_WR(bp, PXP2_REG_RQ_CDU_LAST_ILT, i + CNIC_ILT_LINES);
+	} else /* E1 */
+		REG_WR(bp, PXP2_REG_PSWRQ_CDU0_L2P + func*4,
+		       PXP_ILT_RANGE(i, i + CNIC_ILT_LINES));
+
+#ifdef BCM_CNIC
+	i += 1 + CNIC_ILT_LINES;
+	bnx2x_ilt_wr(bp, i, bp->timers_mapping);
+	if (CHIP_IS_E1(bp))
+		REG_WR(bp, PXP2_REG_PSWRQ_TM0_L2P + func*4, PXP_ONE_ILT(i));
+	else {
+		REG_WR(bp, PXP2_REG_RQ_TM_FIRST_ILT, i);
+		REG_WR(bp, PXP2_REG_RQ_TM_LAST_ILT, i);
+	}
+
+	i++;
+	bnx2x_ilt_wr(bp, i, bp->qm_mapping);
+	if (CHIP_IS_E1(bp))
+		REG_WR(bp, PXP2_REG_PSWRQ_QM0_L2P + func*4, PXP_ONE_ILT(i));
+	else {
+		REG_WR(bp, PXP2_REG_RQ_QM_FIRST_ILT, i);
+		REG_WR(bp, PXP2_REG_RQ_QM_LAST_ILT, i);
+	}
+
+	i++;
+	bnx2x_ilt_wr(bp, i, bp->t1_mapping);
+	if (CHIP_IS_E1(bp))
+		REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i));
+	else {
+		REG_WR(bp, PXP2_REG_RQ_SRC_FIRST_ILT, i);
+		REG_WR(bp, PXP2_REG_RQ_SRC_LAST_ILT, i);
+	}
+
+	/* tell the searcher where the T2 table is */
+	REG_WR(bp, SRC_REG_COUNTFREE0 + port*4, 16*1024/64);
+
+	bnx2x_wb_wr(bp, SRC_REG_FIRSTFREE0 + port*16,
+		    U64_LO(bp->t2_mapping), U64_HI(bp->t2_mapping));
+
+	bnx2x_wb_wr(bp, SRC_REG_LASTFREE0 + port*16,
+		    U64_LO((u64)bp->t2_mapping + 16*1024 - 64),
+		    U64_HI((u64)bp->t2_mapping + 16*1024 - 64));
+
+	REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + port*4, 10);
+#endif
+
+	if (CHIP_IS_E1H(bp)) {
+		bnx2x_init_block(bp, MISC_BLOCK, FUNC0_STAGE + func);
+		bnx2x_init_block(bp, TCM_BLOCK, FUNC0_STAGE + func);
+		bnx2x_init_block(bp, UCM_BLOCK, FUNC0_STAGE + func);
+		bnx2x_init_block(bp, CCM_BLOCK, FUNC0_STAGE + func);
+		bnx2x_init_block(bp, XCM_BLOCK, FUNC0_STAGE + func);
+		bnx2x_init_block(bp, TSEM_BLOCK, FUNC0_STAGE + func);
+		bnx2x_init_block(bp, USEM_BLOCK, FUNC0_STAGE + func);
+		bnx2x_init_block(bp, CSEM_BLOCK, FUNC0_STAGE + func);
+		bnx2x_init_block(bp, XSEM_BLOCK, FUNC0_STAGE + func);
+
+		REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1);
+		REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port*8, bp->e1hov);
+	}
+
+	/* HC init per function */
+	if (CHIP_IS_E1H(bp)) {
+		REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0);
+
+		REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0);
+		REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0);
+	}
+	bnx2x_init_block(bp, HC_BLOCK, FUNC0_STAGE + func);
+
+	/* Reset PCIE errors for debug */
+	REG_WR(bp, 0x2114, 0xffffffff);
+	REG_WR(bp, 0x2120, 0xffffffff);
+
+	return 0;
+}
+
+int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
+{
+	int i, rc = 0;
+
+	DP(BNX2X_MSG_MCP, "function %d  load_code %x\n",
+	   BP_FUNC(bp), load_code);
+
+	bp->dmae_ready = 0;
+	mutex_init(&bp->dmae_mutex);
+	rc = bnx2x_gunzip_init(bp);
+	if (rc)
+		return rc;
+
+	switch (load_code) {
+	case FW_MSG_CODE_DRV_LOAD_COMMON:
+		rc = bnx2x_init_common(bp);
+		if (rc)
+			goto init_hw_err;
+		/* no break */
+
+	case FW_MSG_CODE_DRV_LOAD_PORT:
+		bp->dmae_ready = 1;
+		rc = bnx2x_init_port(bp);
+		if (rc)
+			goto init_hw_err;
+		/* no break */
+
+	case FW_MSG_CODE_DRV_LOAD_FUNCTION:
+		bp->dmae_ready = 1;
+		rc = bnx2x_init_func(bp);
+		if (rc)
+			goto init_hw_err;
+		break;
+
+	default:
+		BNX2X_ERR("Unknown load_code (0x%x) from MCP\n", load_code);
+		break;
+	}
+
+	if (!BP_NOMCP(bp)) {
+		int func = BP_FUNC(bp);
+
+		bp->fw_drv_pulse_wr_seq =
+				(SHMEM_RD(bp, func_mb[func].drv_pulse_mb) &
+				 DRV_PULSE_SEQ_MASK);
+		DP(BNX2X_MSG_MCP, "drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
+	}
+
+	/* this needs to be done before gunzip end */
+	bnx2x_zero_def_sb(bp);
+	for_each_queue(bp, i)
+		bnx2x_zero_sb(bp, BP_L_ID(bp) + i);
+#ifdef BCM_CNIC
+	bnx2x_zero_sb(bp, BP_L_ID(bp) + i);
+#endif
+
+init_hw_err:
+	bnx2x_gunzip_end(bp);
+
+	return rc;
+}
+
+void bnx2x_free_mem(struct bnx2x *bp)
+{
+
+#define BNX2X_PCI_FREE(x, y, size) \
+	do { \
+		if (x) { \
+			dma_free_coherent(&bp->pdev->dev, size, x, y); \
+			x = NULL; \
+			y = 0; \
+		} \
+	} while (0)
+
+#define BNX2X_FREE(x) \
+	do { \
+		if (x) { \
+			vfree(x); \
+			x = NULL; \
+		} \
+	} while (0)
+
+	int i;
+
+	/* fastpath */
+	/* Common */
+	for_each_queue(bp, i) {
+
+		/* status blocks */
+		BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk),
+			       bnx2x_fp(bp, i, status_blk_mapping),
+			       sizeof(struct host_status_block));
+	}
+	/* Rx */
+	for_each_queue(bp, i) {
+
+		/* fastpath rx rings: rx_buf rx_desc rx_comp */
+		BNX2X_FREE(bnx2x_fp(bp, i, rx_buf_ring));
+		BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_desc_ring),
+			       bnx2x_fp(bp, i, rx_desc_mapping),
+			       sizeof(struct eth_rx_bd) * NUM_RX_BD);
+
+		BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_comp_ring),
+			       bnx2x_fp(bp, i, rx_comp_mapping),
+			       sizeof(struct eth_fast_path_rx_cqe) *
+			       NUM_RCQ_BD);
+
+		/* SGE ring */
+		BNX2X_FREE(bnx2x_fp(bp, i, rx_page_ring));
+		BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_sge_ring),
+			       bnx2x_fp(bp, i, rx_sge_mapping),
+			       BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
+	}
+	/* Tx */
+	for_each_queue(bp, i) {
+
+		/* fastpath tx rings: tx_buf tx_desc */
+		BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring));
+		BNX2X_PCI_FREE(bnx2x_fp(bp, i, tx_desc_ring),
+			       bnx2x_fp(bp, i, tx_desc_mapping),
+			       sizeof(union eth_tx_bd_types) * NUM_TX_BD);
+	}
+	/* end of fastpath */
+
+	BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping,
+		       sizeof(struct host_def_status_block));
+
+	BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping,
+		       sizeof(struct bnx2x_slowpath));
+
+#ifdef BCM_CNIC
+	BNX2X_PCI_FREE(bp->t1, bp->t1_mapping, 64*1024);
+	BNX2X_PCI_FREE(bp->t2, bp->t2_mapping, 16*1024);
+	BNX2X_PCI_FREE(bp->timers, bp->timers_mapping, 8*1024);
+	BNX2X_PCI_FREE(bp->qm, bp->qm_mapping, 128*1024);
+	BNX2X_PCI_FREE(bp->cnic_sb, bp->cnic_sb_mapping,
+		       sizeof(struct host_status_block));
+#endif
+	BNX2X_PCI_FREE(bp->spq, bp->spq_mapping, BCM_PAGE_SIZE);
+
+#undef BNX2X_PCI_FREE
+#undef BNX2X_KFREE
+}
+
+int bnx2x_alloc_mem(struct bnx2x *bp)
+{
+
+#define BNX2X_PCI_ALLOC(x, y, size) \
+	do { \
+		x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
+		if (x == NULL) \
+			goto alloc_mem_err; \
+		memset(x, 0, size); \
+	} while (0)
+
+#define BNX2X_ALLOC(x, size) \
+	do { \
+		x = vmalloc(size); \
+		if (x == NULL) \
+			goto alloc_mem_err; \
+		memset(x, 0, size); \
+	} while (0)
+
+	int i;
+
+	/* fastpath */
+	/* Common */
+	for_each_queue(bp, i) {
+		bnx2x_fp(bp, i, bp) = bp;
+
+		/* status blocks */
+		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, status_blk),
+				&bnx2x_fp(bp, i, status_blk_mapping),
+				sizeof(struct host_status_block));
+	}
+	/* Rx */
+	for_each_queue(bp, i) {
+
+		/* fastpath rx rings: rx_buf rx_desc rx_comp */
+		BNX2X_ALLOC(bnx2x_fp(bp, i, rx_buf_ring),
+				sizeof(struct sw_rx_bd) * NUM_RX_BD);
+		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_desc_ring),
+				&bnx2x_fp(bp, i, rx_desc_mapping),
+				sizeof(struct eth_rx_bd) * NUM_RX_BD);
+
+		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_comp_ring),
+				&bnx2x_fp(bp, i, rx_comp_mapping),
+				sizeof(struct eth_fast_path_rx_cqe) *
+				NUM_RCQ_BD);
+
+		/* SGE ring */
+		BNX2X_ALLOC(bnx2x_fp(bp, i, rx_page_ring),
+				sizeof(struct sw_rx_page) * NUM_RX_SGE);
+		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_sge_ring),
+				&bnx2x_fp(bp, i, rx_sge_mapping),
+				BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
+	}
+	/* Tx */
+	for_each_queue(bp, i) {
+
+		/* fastpath tx rings: tx_buf tx_desc */
+		BNX2X_ALLOC(bnx2x_fp(bp, i, tx_buf_ring),
+				sizeof(struct sw_tx_bd) * NUM_TX_BD);
+		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, tx_desc_ring),
+				&bnx2x_fp(bp, i, tx_desc_mapping),
+				sizeof(union eth_tx_bd_types) * NUM_TX_BD);
+	}
+	/* end of fastpath */
+
+	BNX2X_PCI_ALLOC(bp->def_status_blk, &bp->def_status_blk_mapping,
+			sizeof(struct host_def_status_block));
+
+	BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
+			sizeof(struct bnx2x_slowpath));
+
+#ifdef BCM_CNIC
+	BNX2X_PCI_ALLOC(bp->t1, &bp->t1_mapping, 64*1024);
+
+	/* allocate searcher T2 table
+	   we allocate 1/4 of alloc num for T2
+	  (which is not entered into the ILT) */
+	BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, 16*1024);
+
+	/* Initialize T2 (for 1024 connections) */
+	for (i = 0; i < 16*1024; i += 64)
+		*(u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64;
+
+	/* Timer block array (8*MAX_CONN) phys uncached for now 1024 conns */
+	BNX2X_PCI_ALLOC(bp->timers, &bp->timers_mapping, 8*1024);
+
+	/* QM queues (128*MAX_CONN) */
+	BNX2X_PCI_ALLOC(bp->qm, &bp->qm_mapping, 128*1024);
+
+	BNX2X_PCI_ALLOC(bp->cnic_sb, &bp->cnic_sb_mapping,
+			sizeof(struct host_status_block));
+#endif
+
+	/* Slow path ring */
+	BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE);
+
+	return 0;
+
+alloc_mem_err:
+	bnx2x_free_mem(bp);
+	return -ENOMEM;
+
+#undef BNX2X_PCI_ALLOC
+#undef BNX2X_ALLOC
+}
+
+
+/*
+ * Init service functions
+ */
+
+/**
+ * Sets a MAC in a CAM for a few L2 Clients for E1 chip
+ *
+ * @param bp driver descriptor
+ * @param set set or clear an entry (1 or 0)
+ * @param mac pointer to a buffer containing a MAC
+ * @param cl_bit_vec bit vector of clients to register a MAC for
+ * @param cam_offset offset in a CAM to use
+ * @param with_bcast set broadcast MAC as well
+ */
+static void bnx2x_set_mac_addr_e1_gen(struct bnx2x *bp, int set, u8 *mac,
+				      u32 cl_bit_vec, u8 cam_offset,
+				      u8 with_bcast)
+{
+	struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config);
+	int port = BP_PORT(bp);
+
+	/* CAM allocation
+	 * unicasts 0-31:port0 32-63:port1
+	 * multicast 64-127:port0 128-191:port1
+	 */
+	config->hdr.length = 1 + (with_bcast ? 1 : 0);
+	config->hdr.offset = cam_offset;
+	config->hdr.client_id = 0xff;
+	config->hdr.reserved1 = 0;
+
+	/* primary MAC */
+	config->config_table[0].cam_entry.msb_mac_addr =
+					swab16(*(u16 *)&mac[0]);
+	config->config_table[0].cam_entry.middle_mac_addr =
+					swab16(*(u16 *)&mac[2]);
+	config->config_table[0].cam_entry.lsb_mac_addr =
+					swab16(*(u16 *)&mac[4]);
+	config->config_table[0].cam_entry.flags = cpu_to_le16(port);
+	if (set)
+		config->config_table[0].target_table_entry.flags = 0;
+	else
+		CAM_INVALIDATE(config->config_table[0]);
+	config->config_table[0].target_table_entry.clients_bit_vector =
+						cpu_to_le32(cl_bit_vec);
+	config->config_table[0].target_table_entry.vlan_id = 0;
+
+	DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x)\n",
+	   (set ? "setting" : "clearing"),
+	   config->config_table[0].cam_entry.msb_mac_addr,
+	   config->config_table[0].cam_entry.middle_mac_addr,
+	   config->config_table[0].cam_entry.lsb_mac_addr);
+
+	/* broadcast */
+	if (with_bcast) {
+		config->config_table[1].cam_entry.msb_mac_addr =
+			cpu_to_le16(0xffff);
+		config->config_table[1].cam_entry.middle_mac_addr =
+			cpu_to_le16(0xffff);
+		config->config_table[1].cam_entry.lsb_mac_addr =
+			cpu_to_le16(0xffff);
+		config->config_table[1].cam_entry.flags = cpu_to_le16(port);
+		if (set)
+			config->config_table[1].target_table_entry.flags =
+					TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST;
+		else
+			CAM_INVALIDATE(config->config_table[1]);
+		config->config_table[1].target_table_entry.clients_bit_vector =
+							cpu_to_le32(cl_bit_vec);
+		config->config_table[1].target_table_entry.vlan_id = 0;
+	}
+
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
+		      U64_HI(bnx2x_sp_mapping(bp, mac_config)),
+		      U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
+}
+
+/**
+ * Sets a MAC in a CAM for a few L2 Clients for E1H chip
+ *
+ * @param bp driver descriptor
+ * @param set set or clear an entry (1 or 0)
+ * @param mac pointer to a buffer containing a MAC
+ * @param cl_bit_vec bit vector of clients to register a MAC for
+ * @param cam_offset offset in a CAM to use
+ */
+static void bnx2x_set_mac_addr_e1h_gen(struct bnx2x *bp, int set, u8 *mac,
+				       u32 cl_bit_vec, u8 cam_offset)
+{
+	struct mac_configuration_cmd_e1h *config =
+		(struct mac_configuration_cmd_e1h *)bnx2x_sp(bp, mac_config);
+
+	config->hdr.length = 1;
+	config->hdr.offset = cam_offset;
+	config->hdr.client_id = 0xff;
+	config->hdr.reserved1 = 0;
+
+	/* primary MAC */
+	config->config_table[0].msb_mac_addr =
+					swab16(*(u16 *)&mac[0]);
+	config->config_table[0].middle_mac_addr =
+					swab16(*(u16 *)&mac[2]);
+	config->config_table[0].lsb_mac_addr =
+					swab16(*(u16 *)&mac[4]);
+	config->config_table[0].clients_bit_vector =
+					cpu_to_le32(cl_bit_vec);
+	config->config_table[0].vlan_id = 0;
+	config->config_table[0].e1hov_id = cpu_to_le16(bp->e1hov);
+	if (set)
+		config->config_table[0].flags = BP_PORT(bp);
+	else
+		config->config_table[0].flags =
+				MAC_CONFIGURATION_ENTRY_E1H_ACTION_TYPE;
+
+	DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x)  E1HOV %d  CLID mask %d\n",
+	   (set ? "setting" : "clearing"),
+	   config->config_table[0].msb_mac_addr,
+	   config->config_table[0].middle_mac_addr,
+	   config->config_table[0].lsb_mac_addr, bp->e1hov, cl_bit_vec);
+
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
+		      U64_HI(bnx2x_sp_mapping(bp, mac_config)),
+		      U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
+}
+
+static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
+			     int *state_p, int poll)
+{
+	/* can take a while if any port is running */
+	int cnt = 5000;
+
+	DP(NETIF_MSG_IFUP, "%s for state to become %x on IDX [%d]\n",
+	   poll ? "polling" : "waiting", state, idx);
+
+	might_sleep();
+	while (cnt--) {
+		if (poll) {
+			bnx2x_rx_int(bp->fp, 10);
+			/* if index is different from 0
+			 * the reply for some commands will
+			 * be on the non default queue
+			 */
+			if (idx)
+				bnx2x_rx_int(&bp->fp[idx], 10);
+		}
+
+		mb(); /* state is changed by bnx2x_sp_event() */
+		if (*state_p == state) {
+#ifdef BNX2X_STOP_ON_ERROR
+			DP(NETIF_MSG_IFUP, "exit  (cnt %d)\n", 5000 - cnt);
+#endif
+			return 0;
+		}
+
+		msleep(1);
+
+		if (bp->panic)
+			return -EIO;
+	}
+
+	/* timeout! */
+	BNX2X_ERR("timeout %s for state %x on IDX [%d]\n",
+		  poll ? "polling" : "waiting", state, idx);
+#ifdef BNX2X_STOP_ON_ERROR
+	bnx2x_panic();
+#endif
+
+	return -EBUSY;
+}
+
+void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set)
+{
+	bp->set_mac_pending++;
+	smp_wmb();
+
+	bnx2x_set_mac_addr_e1h_gen(bp, set, bp->dev->dev_addr,
+				   (1 << bp->fp->cl_id), BP_FUNC(bp));
+
+	/* Wait for a completion */
+	bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
+}
+
+void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set)
+{
+	bp->set_mac_pending++;
+	smp_wmb();
+
+	bnx2x_set_mac_addr_e1_gen(bp, set, bp->dev->dev_addr,
+				  (1 << bp->fp->cl_id), (BP_PORT(bp) ? 32 : 0),
+				  1);
+
+	/* Wait for a completion */
+	bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
+}
+
+#ifdef BCM_CNIC
+/**
+ * Set iSCSI MAC(s) at the next enties in the CAM after the ETH
+ * MAC(s). This function will wait until the ramdord completion
+ * returns.
+ *
+ * @param bp driver handle
+ * @param set set or clear the CAM entry
+ *
+ * @return 0 if cussess, -ENODEV if ramrod doesn't return.
+ */
+int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set)
+{
+	u32 cl_bit_vec = (1 << BCM_ISCSI_ETH_CL_ID);
+
+	bp->set_mac_pending++;
+	smp_wmb();
+
+	/* Send a SET_MAC ramrod */
+	if (CHIP_IS_E1(bp))
+		bnx2x_set_mac_addr_e1_gen(bp, set, bp->iscsi_mac,
+				  cl_bit_vec, (BP_PORT(bp) ? 32 : 0) + 2,
+				  1);
+	else
+		/* CAM allocation for E1H
+		* unicasts: by func number
+		* multicast: 20+FUNC*20, 20 each
+		*/
+		bnx2x_set_mac_addr_e1h_gen(bp, set, bp->iscsi_mac,
+				   cl_bit_vec, E1H_FUNC_MAX + BP_FUNC(bp));
+
+	/* Wait for a completion when setting */
+	bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
+
+	return 0;
+}
+#endif
+
+int bnx2x_setup_leading(struct bnx2x *bp)
+{
+	int rc;
+
+	/* reset IGU state */
+	bnx2x_ack_sb(bp, bp->fp[0].sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
+
+	/* SETUP ramrod */
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_SETUP, 0, 0, 0, 0);
+
+	/* Wait for completion */
+	rc = bnx2x_wait_ramrod(bp, BNX2X_STATE_OPEN, 0, &(bp->state), 0);
+
+	return rc;
+}
+
+int bnx2x_setup_multi(struct bnx2x *bp, int index)
+{
+	struct bnx2x_fastpath *fp = &bp->fp[index];
+
+	/* reset IGU state */
+	bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
+
+	/* SETUP ramrod */
+	fp->state = BNX2X_FP_STATE_OPENING;
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_SETUP, index, 0,
+		      fp->cl_id, 0);
+
+	/* Wait for completion */
+	return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_OPEN, index,
+				 &(fp->state), 0);
+}
+
+
+void bnx2x_set_num_queues_msix(struct bnx2x *bp)
+{
+
+	switch (bp->multi_mode) {
+	case ETH_RSS_MODE_DISABLED:
+		bp->num_queues = 1;
+		break;
+
+	case ETH_RSS_MODE_REGULAR:
+		if (num_queues)
+			bp->num_queues = min_t(u32, num_queues,
+						  BNX2X_MAX_QUEUES(bp));
+		else
+			bp->num_queues = min_t(u32, num_online_cpus(),
+						  BNX2X_MAX_QUEUES(bp));
+		break;
+
+
+	default:
+		bp->num_queues = 1;
+		break;
+	}
+}
+
+
+
+static int bnx2x_stop_multi(struct bnx2x *bp, int index)
+{
+	struct bnx2x_fastpath *fp = &bp->fp[index];
+	int rc;
+
+	/* halt the connection */
+	fp->state = BNX2X_FP_STATE_HALTING;
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, index, 0, fp->cl_id, 0);
+
+	/* Wait for completion */
+	rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, index,
+			       &(fp->state), 1);
+	if (rc) /* timeout */
+		return rc;
+
+	/* delete cfc entry */
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CFC_DEL, index, 0, 0, 1);
+
+	/* Wait for completion */
+	rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_CLOSED, index,
+			       &(fp->state), 1);
+	return rc;
+}
+
+static int bnx2x_stop_leading(struct bnx2x *bp)
+{
+	__le16 dsb_sp_prod_idx;
+	/* if the other port is handling traffic,
+	   this can take a lot of time */
+	int cnt = 500;
+	int rc;
+
+	might_sleep();
+
+	/* Send HALT ramrod */
+	bp->fp[0].state = BNX2X_FP_STATE_HALTING;
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, 0, 0, bp->fp->cl_id, 0);
+
+	/* Wait for completion */
+	rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, 0,
+			       &(bp->fp[0].state), 1);
+	if (rc) /* timeout */
+		return rc;
+
+	dsb_sp_prod_idx = *bp->dsb_sp_prod;
+
+	/* Send PORT_DELETE ramrod */
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_DEL, 0, 0, 0, 1);
+
+	/* Wait for completion to arrive on default status block
+	   we are going to reset the chip anyway
+	   so there is not much to do if this times out
+	 */
+	while (dsb_sp_prod_idx == *bp->dsb_sp_prod) {
+		if (!cnt) {
+			DP(NETIF_MSG_IFDOWN, "timeout waiting for port del "
+			   "dsb_sp_prod 0x%x != dsb_sp_prod_idx 0x%x\n",
+			   *bp->dsb_sp_prod, dsb_sp_prod_idx);
+#ifdef BNX2X_STOP_ON_ERROR
+			bnx2x_panic();
+#endif
+			rc = -EBUSY;
+			break;
+		}
+		cnt--;
+		msleep(1);
+		rmb(); /* Refresh the dsb_sp_prod */
+	}
+	bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD;
+	bp->fp[0].state = BNX2X_FP_STATE_CLOSED;
+
+	return rc;
+}
+
+static void bnx2x_reset_func(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	int func = BP_FUNC(bp);
+	int base, i;
+
+	/* Configure IGU */
+	REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0);
+	REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0);
+
+#ifdef BCM_CNIC
+	/* Disable Timer scan */
+	REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 0);
+	/*
+	 * Wait for at least 10ms and up to 2 second for the timers scan to
+	 * complete
+	 */
+	for (i = 0; i < 200; i++) {
+		msleep(10);
+		if (!REG_RD(bp, TM_REG_LIN0_SCAN_ON + port*4))
+			break;
+	}
+#endif
+	/* Clear ILT */
+	base = FUNC_ILT_BASE(func);
+	for (i = base; i < base + ILT_PER_FUNC; i++)
+		bnx2x_ilt_wr(bp, i, 0);
+}
+
+static void bnx2x_reset_port(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	u32 val;
+
+	REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0);
+
+	/* Do not rcv packets to BRB */
+	REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK + port*4, 0x0);
+	/* Do not direct rcv packets that are not for MCP to the BRB */
+	REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_NOT_MCP :
+			   NIG_REG_LLH0_BRB1_NOT_MCP), 0x0);
+
+	/* Configure AEU */
+	REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, 0);
+
+	msleep(100);
+	/* Check for BRB port occupancy */
+	val = REG_RD(bp, BRB1_REG_PORT_NUM_OCC_BLOCKS_0 + port*4);
+	if (val)
+		DP(NETIF_MSG_IFDOWN,
+		   "BRB1 is not empty  %d blocks are occupied\n", val);
+
+	/* TODO: Close Doorbell port? */
+}
+
+static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code)
+{
+	DP(BNX2X_MSG_MCP, "function %d  reset_code %x\n",
+	   BP_FUNC(bp), reset_code);
+
+	switch (reset_code) {
+	case FW_MSG_CODE_DRV_UNLOAD_COMMON:
+		bnx2x_reset_port(bp);
+		bnx2x_reset_func(bp);
+		bnx2x_reset_common(bp);
+		break;
+
+	case FW_MSG_CODE_DRV_UNLOAD_PORT:
+		bnx2x_reset_port(bp);
+		bnx2x_reset_func(bp);
+		break;
+
+	case FW_MSG_CODE_DRV_UNLOAD_FUNCTION:
+		bnx2x_reset_func(bp);
+		break;
+
+	default:
+		BNX2X_ERR("Unknown reset_code (0x%x) from MCP\n", reset_code);
+		break;
+	}
+}
+
+void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
+{
+	int port = BP_PORT(bp);
+	u32 reset_code = 0;
+	int i, cnt, rc;
+
+	/* Wait until tx fastpath tasks complete */
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		cnt = 1000;
+		while (bnx2x_has_tx_work_unload(fp)) {
+
+			bnx2x_tx_int(fp);
+			if (!cnt) {
+				BNX2X_ERR("timeout waiting for queue[%d]\n",
+					  i);
+#ifdef BNX2X_STOP_ON_ERROR
+				bnx2x_panic();
+				return -EBUSY;
+#else
+				break;
+#endif
+			}
+			cnt--;
+			msleep(1);
+		}
+	}
+	/* Give HW time to discard old tx messages */
+	msleep(1);
+
+	if (CHIP_IS_E1(bp)) {
+		struct mac_configuration_cmd *config =
+						bnx2x_sp(bp, mcast_config);
+
+		bnx2x_set_eth_mac_addr_e1(bp, 0);
+
+		for (i = 0; i < config->hdr.length; i++)
+			CAM_INVALIDATE(config->config_table[i]);
+
+		config->hdr.length = i;
+		if (CHIP_REV_IS_SLOW(bp))
+			config->hdr.offset = BNX2X_MAX_EMUL_MULTI*(1 + port);
+		else
+			config->hdr.offset = BNX2X_MAX_MULTICAST*(1 + port);
+		config->hdr.client_id = bp->fp->cl_id;
+		config->hdr.reserved1 = 0;
+
+		bp->set_mac_pending++;
+		smp_wmb();
+
+		bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
+			      U64_HI(bnx2x_sp_mapping(bp, mcast_config)),
+			      U64_LO(bnx2x_sp_mapping(bp, mcast_config)), 0);
+
+	} else { /* E1H */
+		REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
+
+		bnx2x_set_eth_mac_addr_e1h(bp, 0);
+
+		for (i = 0; i < MC_HASH_SIZE; i++)
+			REG_WR(bp, MC_HASH_OFFSET(bp, i), 0);
+
+		REG_WR(bp, MISC_REG_E1HMF_MODE, 0);
+	}
+#ifdef BCM_CNIC
+	/* Clear iSCSI L2 MAC */
+	mutex_lock(&bp->cnic_mutex);
+	if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) {
+		bnx2x_set_iscsi_eth_mac_addr(bp, 0);
+		bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET;
+	}
+	mutex_unlock(&bp->cnic_mutex);
+#endif
+
+	if (unload_mode == UNLOAD_NORMAL)
+		reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
+
+	else if (bp->flags & NO_WOL_FLAG)
+		reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP;
+
+	else if (bp->wol) {
+		u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+		u8 *mac_addr = bp->dev->dev_addr;
+		u32 val;
+		/* The mac address is written to entries 1-4 to
+		   preserve entry 0 which is used by the PMF */
+		u8 entry = (BP_E1HVN(bp) + 1)*8;
+
+		val = (mac_addr[0] << 8) | mac_addr[1];
+		EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry, val);
+
+		val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
+		      (mac_addr[4] << 8) | mac_addr[5];
+		EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry + 4, val);
+
+		reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN;
+
+	} else
+		reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
+
+	/* Close multi and leading connections
+	   Completions for ramrods are collected in a synchronous way */
+	for_each_nondefault_queue(bp, i)
+		if (bnx2x_stop_multi(bp, i))
+			goto unload_error;
+
+	rc = bnx2x_stop_leading(bp);
+	if (rc) {
+		BNX2X_ERR("Stop leading failed!\n");
+#ifdef BNX2X_STOP_ON_ERROR
+		return -EBUSY;
+#else
+		goto unload_error;
+#endif
+	}
+
+unload_error:
+	if (!BP_NOMCP(bp))
+		reset_code = bnx2x_fw_command(bp, reset_code);
+	else {
+		DP(NETIF_MSG_IFDOWN, "NO MCP - load counts      %d, %d, %d\n",
+		   load_count[0], load_count[1], load_count[2]);
+		load_count[0]--;
+		load_count[1 + port]--;
+		DP(NETIF_MSG_IFDOWN, "NO MCP - new load counts  %d, %d, %d\n",
+		   load_count[0], load_count[1], load_count[2]);
+		if (load_count[0] == 0)
+			reset_code = FW_MSG_CODE_DRV_UNLOAD_COMMON;
+		else if (load_count[1 + port] == 0)
+			reset_code = FW_MSG_CODE_DRV_UNLOAD_PORT;
+		else
+			reset_code = FW_MSG_CODE_DRV_UNLOAD_FUNCTION;
+	}
+
+	if ((reset_code == FW_MSG_CODE_DRV_UNLOAD_COMMON) ||
+	    (reset_code == FW_MSG_CODE_DRV_UNLOAD_PORT))
+		bnx2x__link_reset(bp);
+
+	/* Reset the chip */
+	bnx2x_reset_chip(bp, reset_code);
+
+	/* Report UNLOAD_DONE to MCP */
+	if (!BP_NOMCP(bp))
+		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+
+}
+
+void bnx2x_disable_close_the_gate(struct bnx2x *bp)
+{
+	u32 val;
+
+	DP(NETIF_MSG_HW, "Disabling \"close the gates\"\n");
+
+	if (CHIP_IS_E1(bp)) {
+		int port = BP_PORT(bp);
+		u32 addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
+			MISC_REG_AEU_MASK_ATTN_FUNC_0;
+
+		val = REG_RD(bp, addr);
+		val &= ~(0x300);
+		REG_WR(bp, addr, val);
+	} else if (CHIP_IS_E1H(bp)) {
+		val = REG_RD(bp, MISC_REG_AEU_GENERAL_MASK);
+		val &= ~(MISC_AEU_GENERAL_MASK_REG_AEU_PXP_CLOSE_MASK |
+			 MISC_AEU_GENERAL_MASK_REG_AEU_NIG_CLOSE_MASK);
+		REG_WR(bp, MISC_REG_AEU_GENERAL_MASK, val);
+	}
+}
+
+
+/* Close gates #2, #3 and #4: */
+static void bnx2x_set_234_gates(struct bnx2x *bp, bool close)
+{
+	u32 val, addr;
+
+	/* Gates #2 and #4a are closed/opened for "not E1" only */
+	if (!CHIP_IS_E1(bp)) {
+		/* #4 */
+		val = REG_RD(bp, PXP_REG_HST_DISCARD_DOORBELLS);
+		REG_WR(bp, PXP_REG_HST_DISCARD_DOORBELLS,
+		       close ? (val | 0x1) : (val & (~(u32)1)));
+		/* #2 */
+		val = REG_RD(bp, PXP_REG_HST_DISCARD_INTERNAL_WRITES);
+		REG_WR(bp, PXP_REG_HST_DISCARD_INTERNAL_WRITES,
+		       close ? (val | 0x1) : (val & (~(u32)1)));
+	}
+
+	/* #3 */
+	addr = BP_PORT(bp) ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
+	val = REG_RD(bp, addr);
+	REG_WR(bp, addr, (!close) ? (val | 0x1) : (val & (~(u32)1)));
+
+	DP(NETIF_MSG_HW, "%s gates #2, #3 and #4\n",
+		close ? "closing" : "opening");
+	mmiowb();
+}
+
+#define SHARED_MF_CLP_MAGIC  0x80000000 /* `magic' bit */
+
+static void bnx2x_clp_reset_prep(struct bnx2x *bp, u32 *magic_val)
+{
+	/* Do some magic... */
+	u32 val = MF_CFG_RD(bp, shared_mf_config.clp_mb);
+	*magic_val = val & SHARED_MF_CLP_MAGIC;
+	MF_CFG_WR(bp, shared_mf_config.clp_mb, val | SHARED_MF_CLP_MAGIC);
+}
+
+/* Restore the value of the `magic' bit.
+ *
+ * @param pdev Device handle.
+ * @param magic_val Old value of the `magic' bit.
+ */
+static void bnx2x_clp_reset_done(struct bnx2x *bp, u32 magic_val)
+{
+	/* Restore the `magic' bit value... */
+	/* u32 val = SHMEM_RD(bp, mf_cfg.shared_mf_config.clp_mb);
+	SHMEM_WR(bp, mf_cfg.shared_mf_config.clp_mb,
+		(val & (~SHARED_MF_CLP_MAGIC)) | magic_val); */
+	u32 val = MF_CFG_RD(bp, shared_mf_config.clp_mb);
+	MF_CFG_WR(bp, shared_mf_config.clp_mb,
+		(val & (~SHARED_MF_CLP_MAGIC)) | magic_val);
+}
+
+/* Prepares for MCP reset: takes care of CLP configurations.
+ *
+ * @param bp
+ * @param magic_val Old value of 'magic' bit.
+ */
+static void bnx2x_reset_mcp_prep(struct bnx2x *bp, u32 *magic_val)
+{
+	u32 shmem;
+	u32 validity_offset;
+
+	DP(NETIF_MSG_HW, "Starting\n");
+
+	/* Set `magic' bit in order to save MF config */
+	if (!CHIP_IS_E1(bp))
+		bnx2x_clp_reset_prep(bp, magic_val);
+
+	/* Get shmem offset */
+	shmem = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+	validity_offset = offsetof(struct shmem_region, validity_map[0]);
+
+	/* Clear validity map flags */
+	if (shmem > 0)
+		REG_WR(bp, shmem + validity_offset, 0);
+}
+
+#define MCP_TIMEOUT      5000   /* 5 seconds (in ms) */
+#define MCP_ONE_TIMEOUT  100    /* 100 ms */
+
+/* Waits for MCP_ONE_TIMEOUT or MCP_ONE_TIMEOUT*10,
+ * depending on the HW type.
+ *
+ * @param bp
+ */
+static inline void bnx2x_mcp_wait_one(struct bnx2x *bp)
+{
+	/* special handling for emulation and FPGA,
+	   wait 10 times longer */
+	if (CHIP_REV_IS_SLOW(bp))
+		msleep(MCP_ONE_TIMEOUT*10);
+	else
+		msleep(MCP_ONE_TIMEOUT);
+}
+
+static int bnx2x_reset_mcp_comp(struct bnx2x *bp, u32 magic_val)
+{
+	u32 shmem, cnt, validity_offset, val;
+	int rc = 0;
+
+	msleep(100);
+
+	/* Get shmem offset */
+	shmem = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+	if (shmem == 0) {
+		BNX2X_ERR("Shmem 0 return failure\n");
+		rc = -ENOTTY;
+		goto exit_lbl;
+	}
+
+	validity_offset = offsetof(struct shmem_region, validity_map[0]);
+
+	/* Wait for MCP to come up */
+	for (cnt = 0; cnt < (MCP_TIMEOUT / MCP_ONE_TIMEOUT); cnt++) {
+		/* TBD: its best to check validity map of last port.
+		 * currently checks on port 0.
+		 */
+		val = REG_RD(bp, shmem + validity_offset);
+		DP(NETIF_MSG_HW, "shmem 0x%x validity map(0x%x)=0x%x\n", shmem,
+		   shmem + validity_offset, val);
+
+		/* check that shared memory is valid. */
+		if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+		    == (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+			break;
+
+		bnx2x_mcp_wait_one(bp);
+	}
+
+	DP(NETIF_MSG_HW, "Cnt=%d Shmem validity map 0x%x\n", cnt, val);
+
+	/* Check that shared memory is valid. This indicates that MCP is up. */
+	if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) !=
+	    (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) {
+		BNX2X_ERR("Shmem signature not present. MCP is not up !!\n");
+		rc = -ENOTTY;
+		goto exit_lbl;
+	}
+
+exit_lbl:
+	/* Restore the `magic' bit value */
+	if (!CHIP_IS_E1(bp))
+		bnx2x_clp_reset_done(bp, magic_val);
+
+	return rc;
+}
+
+static void bnx2x_pxp_prep(struct bnx2x *bp)
+{
+	if (!CHIP_IS_E1(bp)) {
+		REG_WR(bp, PXP2_REG_RD_START_INIT, 0);
+		REG_WR(bp, PXP2_REG_RQ_RBC_DONE, 0);
+		REG_WR(bp, PXP2_REG_RQ_CFG_DONE, 0);
+		mmiowb();
+	}
+}
+
+/*
+ * Reset the whole chip except for:
+ *      - PCIE core
+ *      - PCI Glue, PSWHST, PXP/PXP2 RF (all controlled by
+ *              one reset bit)
+ *      - IGU
+ *      - MISC (including AEU)
+ *      - GRC
+ *      - RBCN, RBCP
+ */
+static void bnx2x_process_kill_chip_reset(struct bnx2x *bp)
+{
+	u32 not_reset_mask1, reset_mask1, not_reset_mask2, reset_mask2;
+
+	not_reset_mask1 =
+		MISC_REGISTERS_RESET_REG_1_RST_HC |
+		MISC_REGISTERS_RESET_REG_1_RST_PXPV |
+		MISC_REGISTERS_RESET_REG_1_RST_PXP;
+
+	not_reset_mask2 =
+		MISC_REGISTERS_RESET_REG_2_RST_MDIO |
+		MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE |
+		MISC_REGISTERS_RESET_REG_2_RST_EMAC1_HARD_CORE |
+		MISC_REGISTERS_RESET_REG_2_RST_MISC_CORE |
+		MISC_REGISTERS_RESET_REG_2_RST_RBCN |
+		MISC_REGISTERS_RESET_REG_2_RST_GRC  |
+		MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_REG_HARD_CORE |
+		MISC_REGISTERS_RESET_REG_2_RST_MCP_N_HARD_CORE_RST_B;
+
+	reset_mask1 = 0xffffffff;
+
+	if (CHIP_IS_E1(bp))
+		reset_mask2 = 0xffff;
+	else
+		reset_mask2 = 0x1ffff;
+
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
+	       reset_mask1 & (~not_reset_mask1));
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+	       reset_mask2 & (~not_reset_mask2));
+
+	barrier();
+	mmiowb();
+
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, reset_mask1);
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, reset_mask2);
+	mmiowb();
+}
+
+static int bnx2x_process_kill(struct bnx2x *bp)
+{
+	int cnt = 1000;
+	u32 val = 0;
+	u32 sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1, pgl_exp_rom2;
+
+
+	/* Empty the Tetris buffer, wait for 1s */
+	do {
+		sr_cnt  = REG_RD(bp, PXP2_REG_RD_SR_CNT);
+		blk_cnt = REG_RD(bp, PXP2_REG_RD_BLK_CNT);
+		port_is_idle_0 = REG_RD(bp, PXP2_REG_RD_PORT_IS_IDLE_0);
+		port_is_idle_1 = REG_RD(bp, PXP2_REG_RD_PORT_IS_IDLE_1);
+		pgl_exp_rom2 = REG_RD(bp, PXP2_REG_PGL_EXP_ROM2);
+		if ((sr_cnt == 0x7e) && (blk_cnt == 0xa0) &&
+		    ((port_is_idle_0 & 0x1) == 0x1) &&
+		    ((port_is_idle_1 & 0x1) == 0x1) &&
+		    (pgl_exp_rom2 == 0xffffffff))
+			break;
+		msleep(1);
+	} while (cnt-- > 0);
+
+	if (cnt <= 0) {
+		DP(NETIF_MSG_HW, "Tetris buffer didn't get empty or there"
+			  " are still"
+			  " outstanding read requests after 1s!\n");
+		DP(NETIF_MSG_HW, "sr_cnt=0x%08x, blk_cnt=0x%08x,"
+			  " port_is_idle_0=0x%08x,"
+			  " port_is_idle_1=0x%08x, pgl_exp_rom2=0x%08x\n",
+			  sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1,
+			  pgl_exp_rom2);
+		return -EAGAIN;
+	}
+
+	barrier();
+
+	/* Close gates #2, #3 and #4 */
+	bnx2x_set_234_gates(bp, true);
+
+	/* TBD: Indicate that "process kill" is in progress to MCP */
+
+	/* Clear "unprepared" bit */
+	REG_WR(bp, MISC_REG_UNPREPARED, 0);
+	barrier();
+
+	/* Make sure all is written to the chip before the reset */
+	mmiowb();
+
+	/* Wait for 1ms to empty GLUE and PCI-E core queues,
+	 * PSWHST, GRC and PSWRD Tetris buffer.
+	 */
+	msleep(1);
+
+	/* Prepare to chip reset: */
+	/* MCP */
+	bnx2x_reset_mcp_prep(bp, &val);
+
+	/* PXP */
+	bnx2x_pxp_prep(bp);
+	barrier();
+
+	/* reset the chip */
+	bnx2x_process_kill_chip_reset(bp);
+	barrier();
+
+	/* Recover after reset: */
+	/* MCP */
+	if (bnx2x_reset_mcp_comp(bp, val))
+		return -EAGAIN;
+
+	/* PXP */
+	bnx2x_pxp_prep(bp);
+
+	/* Open the gates #2, #3 and #4 */
+	bnx2x_set_234_gates(bp, false);
+
+	/* TBD: IGU/AEU preparation bring back the AEU/IGU to a
+	 * reset state, re-enable attentions. */
+
+	return 0;
+}
+
+static int bnx2x_leader_reset(struct bnx2x *bp)
+{
+	int rc = 0;
+	/* Try to recover after the failure */
+	if (bnx2x_process_kill(bp)) {
+		printk(KERN_ERR "%s: Something bad had happen! Aii!\n",
+		       bp->dev->name);
+		rc = -EAGAIN;
+		goto exit_leader_reset;
+	}
+
+	/* Clear "reset is in progress" bit and update the driver state */
+	bnx2x_set_reset_done(bp);
+	bp->recovery_state = BNX2X_RECOVERY_DONE;
+
+exit_leader_reset:
+	bp->is_leader = 0;
+	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESERVED_08);
+	smp_wmb();
+	return rc;
+}
+
+/* Assumption: runs under rtnl lock. This together with the fact
+ * that it's called only from bnx2x_reset_task() ensure that it
+ * will never be called when netif_running(bp->dev) is false.
+ */
+static void bnx2x_parity_recover(struct bnx2x *bp)
+{
+	DP(NETIF_MSG_HW, "Handling parity\n");
+	while (1) {
+		switch (bp->recovery_state) {
+		case BNX2X_RECOVERY_INIT:
+			DP(NETIF_MSG_HW, "State is BNX2X_RECOVERY_INIT\n");
+			/* Try to get a LEADER_LOCK HW lock */
+			if (bnx2x_trylock_hw_lock(bp,
+				HW_LOCK_RESOURCE_RESERVED_08))
+				bp->is_leader = 1;
+
+			/* Stop the driver */
+			/* If interface has been removed - break */
+			if (bnx2x_nic_unload(bp, UNLOAD_RECOVERY))
+				return;
+
+			bp->recovery_state = BNX2X_RECOVERY_WAIT;
+			/* Ensure "is_leader" and "recovery_state"
+			 *  update values are seen on other CPUs
+			 */
+			smp_wmb();
+			break;
+
+		case BNX2X_RECOVERY_WAIT:
+			DP(NETIF_MSG_HW, "State is BNX2X_RECOVERY_WAIT\n");
+			if (bp->is_leader) {
+				u32 load_counter = bnx2x_get_load_cnt(bp);
+				if (load_counter) {
+					/* Wait until all other functions get
+					 * down.
+					 */
+					schedule_delayed_work(&bp->reset_task,
+								HZ/10);
+					return;
+				} else {
+					/* If all other functions got down -
+					 * try to bring the chip back to
+					 * normal. In any case it's an exit
+					 * point for a leader.
+					 */
+					if (bnx2x_leader_reset(bp) ||
+					bnx2x_nic_load(bp, LOAD_NORMAL)) {
+						printk(KERN_ERR"%s: Recovery "
+						"has failed. Power cycle is "
+						"needed.\n", bp->dev->name);
+						/* Disconnect this device */
+						netif_device_detach(bp->dev);
+						/* Block ifup for all function
+						 * of this ASIC until
+						 * "process kill" or power
+						 * cycle.
+						 */
+						bnx2x_set_reset_in_progress(bp);
+						/* Shut down the power */
+						bnx2x_set_power_state(bp,
+								PCI_D3hot);
+						return;
+					}
+
+					return;
+				}
+			} else { /* non-leader */
+				if (!bnx2x_reset_is_done(bp)) {
+					/* Try to get a LEADER_LOCK HW lock as
+					 * long as a former leader may have
+					 * been unloaded by the user or
+					 * released a leadership by another
+					 * reason.
+					 */
+					if (bnx2x_trylock_hw_lock(bp,
+					    HW_LOCK_RESOURCE_RESERVED_08)) {
+						/* I'm a leader now! Restart a
+						 * switch case.
+						 */
+						bp->is_leader = 1;
+						break;
+					}
+
+					schedule_delayed_work(&bp->reset_task,
+								HZ/10);
+					return;
+
+				} else { /* A leader has completed
+					  * the "process kill". It's an exit
+					  * point for a non-leader.
+					  */
+					bnx2x_nic_load(bp, LOAD_NORMAL);
+					bp->recovery_state =
+						BNX2X_RECOVERY_DONE;
+					smp_wmb();
+					return;
+				}
+			}
+		default:
+			return;
+		}
+	}
+}
+
+/* bnx2x_nic_unload() flushes the bnx2x_wq, thus reset task is
+ * scheduled on a general queue in order to prevent a dead lock.
+ */
+static void bnx2x_reset_task(struct work_struct *work)
+{
+	struct bnx2x *bp = container_of(work, struct bnx2x, reset_task.work);
+
+#ifdef BNX2X_STOP_ON_ERROR
+	BNX2X_ERR("reset task called but STOP_ON_ERROR defined"
+		  " so reset not done to allow debug dump,\n"
+	 KERN_ERR " you will need to reboot when done\n");
+	return;
+#endif
+
+	rtnl_lock();
+
+	if (!netif_running(bp->dev))
+		goto reset_task_exit;
+
+	if (unlikely(bp->recovery_state != BNX2X_RECOVERY_DONE))
+		bnx2x_parity_recover(bp);
+	else {
+		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+		bnx2x_nic_load(bp, LOAD_NORMAL);
+	}
+
+reset_task_exit:
+	rtnl_unlock();
+}
+
+/* end of nic load/unload */
+
+/*
+ * Init service functions
+ */
+
+static inline u32 bnx2x_get_pretend_reg(struct bnx2x *bp, int func)
+{
+	switch (func) {
+	case 0: return PXP2_REG_PGL_PRETEND_FUNC_F0;
+	case 1:	return PXP2_REG_PGL_PRETEND_FUNC_F1;
+	case 2:	return PXP2_REG_PGL_PRETEND_FUNC_F2;
+	case 3:	return PXP2_REG_PGL_PRETEND_FUNC_F3;
+	case 4:	return PXP2_REG_PGL_PRETEND_FUNC_F4;
+	case 5:	return PXP2_REG_PGL_PRETEND_FUNC_F5;
+	case 6:	return PXP2_REG_PGL_PRETEND_FUNC_F6;
+	case 7:	return PXP2_REG_PGL_PRETEND_FUNC_F7;
+	default:
+		BNX2X_ERR("Unsupported function index: %d\n", func);
+		return (u32)(-1);
+	}
+}
+
+static void bnx2x_undi_int_disable_e1h(struct bnx2x *bp, int orig_func)
+{
+	u32 reg = bnx2x_get_pretend_reg(bp, orig_func), new_val;
+
+	/* Flush all outstanding writes */
+	mmiowb();
+
+	/* Pretend to be function 0 */
+	REG_WR(bp, reg, 0);
+	/* Flush the GRC transaction (in the chip) */
+	new_val = REG_RD(bp, reg);
+	if (new_val != 0) {
+		BNX2X_ERR("Hmmm... Pretend register wasn't updated: (0,%d)!\n",
+			  new_val);
+		BUG();
+	}
+
+	/* From now we are in the "like-E1" mode */
+	bnx2x_int_disable(bp);
+
+	/* Flush all outstanding writes */
+	mmiowb();
+
+	/* Restore the original funtion settings */
+	REG_WR(bp, reg, orig_func);
+	new_val = REG_RD(bp, reg);
+	if (new_val != orig_func) {
+		BNX2X_ERR("Hmmm... Pretend register wasn't updated: (%d,%d)!\n",
+			  orig_func, new_val);
+		BUG();
+	}
+}
+
+static inline void bnx2x_undi_int_disable(struct bnx2x *bp, int func)
+{
+	if (CHIP_IS_E1H(bp))
+		bnx2x_undi_int_disable_e1h(bp, func);
+	else
+		bnx2x_int_disable(bp);
+}
+
+static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
+{
+	u32 val;
+
+	/* Check if there is any driver already loaded */
+	val = REG_RD(bp, MISC_REG_UNPREPARED);
+	if (val == 0x1) {
+		/* Check if it is the UNDI driver
+		 * UNDI driver initializes CID offset for normal bell to 0x7
+		 */
+		bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
+		val = REG_RD(bp, DORQ_REG_NORM_CID_OFST);
+		if (val == 0x7) {
+			u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
+			/* save our func */
+			int func = BP_FUNC(bp);
+			u32 swap_en;
+			u32 swap_val;
+
+			/* clear the UNDI indication */
+			REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0);
+
+			BNX2X_DEV_INFO("UNDI is active! reset device\n");
+
+			/* try unload UNDI on port 0 */
+			bp->func = 0;
+			bp->fw_seq =
+			       (SHMEM_RD(bp, func_mb[bp->func].drv_mb_header) &
+				DRV_MSG_SEQ_NUMBER_MASK);
+			reset_code = bnx2x_fw_command(bp, reset_code);
+
+			/* if UNDI is loaded on the other port */
+			if (reset_code != FW_MSG_CODE_DRV_UNLOAD_COMMON) {
+
+				/* send "DONE" for previous unload */
+				bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+
+				/* unload UNDI on port 1 */
+				bp->func = 1;
+				bp->fw_seq =
+			       (SHMEM_RD(bp, func_mb[bp->func].drv_mb_header) &
+					DRV_MSG_SEQ_NUMBER_MASK);
+				reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
+
+				bnx2x_fw_command(bp, reset_code);
+			}
+
+			/* now it's safe to release the lock */
+			bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
+
+			bnx2x_undi_int_disable(bp, func);
+
+			/* close input traffic and wait for it */
+			/* Do not rcv packets to BRB */
+			REG_WR(bp,
+			      (BP_PORT(bp) ? NIG_REG_LLH1_BRB1_DRV_MASK :
+					     NIG_REG_LLH0_BRB1_DRV_MASK), 0x0);
+			/* Do not direct rcv packets that are not for MCP to
+			 * the BRB */
+			REG_WR(bp,
+			       (BP_PORT(bp) ? NIG_REG_LLH1_BRB1_NOT_MCP :
+					      NIG_REG_LLH0_BRB1_NOT_MCP), 0x0);
+			/* clear AEU */
+			REG_WR(bp,
+			     (BP_PORT(bp) ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
+					    MISC_REG_AEU_MASK_ATTN_FUNC_0), 0);
+			msleep(10);
+
+			/* save NIG port swap info */
+			swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+			swap_en = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+			/* reset device */
+			REG_WR(bp,
+			       GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
+			       0xd3ffffff);
+			REG_WR(bp,
+			       GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+			       0x1403);
+			/* take the NIG out of reset and restore swap values */
+			REG_WR(bp,
+			       GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET,
+			       MISC_REGISTERS_RESET_REG_1_RST_NIG);
+			REG_WR(bp, NIG_REG_PORT_SWAP, swap_val);
+			REG_WR(bp, NIG_REG_STRAP_OVERRIDE, swap_en);
+
+			/* send unload done to the MCP */
+			bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+
+			/* restore our func and fw_seq */
+			bp->func = func;
+			bp->fw_seq =
+			       (SHMEM_RD(bp, func_mb[bp->func].drv_mb_header) &
+				DRV_MSG_SEQ_NUMBER_MASK);
+
+		} else
+			bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
+	}
+}
+
+static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
+{
+	u32 val, val2, val3, val4, id;
+	u16 pmc;
+
+	/* Get the chip revision id and number. */
+	/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
+	val = REG_RD(bp, MISC_REG_CHIP_NUM);
+	id = ((val & 0xffff) << 16);
+	val = REG_RD(bp, MISC_REG_CHIP_REV);
+	id |= ((val & 0xf) << 12);
+	val = REG_RD(bp, MISC_REG_CHIP_METAL);
+	id |= ((val & 0xff) << 4);
+	val = REG_RD(bp, MISC_REG_BOND_ID);
+	id |= (val & 0xf);
+	bp->common.chip_id = id;
+	bp->link_params.chip_id = bp->common.chip_id;
+	BNX2X_DEV_INFO("chip ID is 0x%x\n", id);
+
+	val = (REG_RD(bp, 0x2874) & 0x55);
+	if ((bp->common.chip_id & 0x1) ||
+	    (CHIP_IS_E1(bp) && val) || (CHIP_IS_E1H(bp) && (val == 0x55))) {
+		bp->flags |= ONE_PORT_FLAG;
+		BNX2X_DEV_INFO("single port device\n");
+	}
+
+	val = REG_RD(bp, MCP_REG_MCPR_NVM_CFG4);
+	bp->common.flash_size = (NVRAM_1MB_SIZE <<
+				 (val & MCPR_NVM_CFG4_FLASH_SIZE));
+	BNX2X_DEV_INFO("flash_size 0x%x (%d)\n",
+		       bp->common.flash_size, bp->common.flash_size);
+
+	bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+	bp->common.shmem2_base = REG_RD(bp, MISC_REG_GENERIC_CR_0);
+	bp->link_params.shmem_base = bp->common.shmem_base;
+	BNX2X_DEV_INFO("shmem offset 0x%x  shmem2 offset 0x%x\n",
+		       bp->common.shmem_base, bp->common.shmem2_base);
+
+	if (!bp->common.shmem_base ||
+	    (bp->common.shmem_base < 0xA0000) ||
+	    (bp->common.shmem_base >= 0xC0000)) {
+		BNX2X_DEV_INFO("MCP not active\n");
+		bp->flags |= NO_MCP_FLAG;
+		return;
+	}
+
+	val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]);
+	if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+		!= (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+		BNX2X_ERROR("BAD MCP validity signature\n");
+
+	bp->common.hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config);
+	BNX2X_DEV_INFO("hw_config 0x%08x\n", bp->common.hw_config);
+
+	bp->link_params.hw_led_mode = ((bp->common.hw_config &
+					SHARED_HW_CFG_LED_MODE_MASK) >>
+				       SHARED_HW_CFG_LED_MODE_SHIFT);
+
+	bp->link_params.feature_config_flags = 0;
+	val = SHMEM_RD(bp, dev_info.shared_feature_config.config);
+	if (val & SHARED_FEAT_CFG_OVERRIDE_PREEMPHASIS_CFG_ENABLED)
+		bp->link_params.feature_config_flags |=
+				FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED;
+	else
+		bp->link_params.feature_config_flags &=
+				~FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED;
+
+	val = SHMEM_RD(bp, dev_info.bc_rev) >> 8;
+	bp->common.bc_ver = val;
+	BNX2X_DEV_INFO("bc_ver %X\n", val);
+	if (val < BNX2X_BC_VER) {
+		/* for now only warn
+		 * later we might need to enforce this */
+		BNX2X_ERROR("This driver needs bc_ver %X but found %X, "
+			    "please upgrade BC\n", BNX2X_BC_VER, val);
+	}
+	bp->link_params.feature_config_flags |=
+		(val >= REQ_BC_VER_4_VRFY_OPT_MDL) ?
+		FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY : 0;
+
+	if (BP_E1HVN(bp) == 0) {
+		pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc);
+		bp->flags |= (pmc & PCI_PM_CAP_PME_D3cold) ? 0 : NO_WOL_FLAG;
+	} else {
+		/* no WOL capability for E1HVN != 0 */
+		bp->flags |= NO_WOL_FLAG;
+	}
+	BNX2X_DEV_INFO("%sWoL capable\n",
+		       (bp->flags & NO_WOL_FLAG) ? "not " : "");
+
+	val = SHMEM_RD(bp, dev_info.shared_hw_config.part_num);
+	val2 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[4]);
+	val3 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[8]);
+	val4 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[12]);
+
+	dev_info(&bp->pdev->dev, "part number %X-%X-%X-%X\n",
+		 val, val2, val3, val4);
+}
+
+static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
+						    u32 switch_cfg)
+{
+	int port = BP_PORT(bp);
+	u32 ext_phy_type;
+
+	switch (switch_cfg) {
+	case SWITCH_CFG_1G:
+		BNX2X_DEV_INFO("switch_cfg 0x%x (1G)\n", switch_cfg);
+
+		ext_phy_type =
+			SERDES_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+		switch (ext_phy_type) {
+		case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n",
+				       ext_phy_type);
+
+			bp->port.supported |= (SUPPORTED_10baseT_Half |
+					       SUPPORTED_10baseT_Full |
+					       SUPPORTED_100baseT_Half |
+					       SUPPORTED_100baseT_Full |
+					       SUPPORTED_1000baseT_Full |
+					       SUPPORTED_2500baseX_Full |
+					       SUPPORTED_TP |
+					       SUPPORTED_FIBRE |
+					       SUPPORTED_Autoneg |
+					       SUPPORTED_Pause |
+					       SUPPORTED_Asym_Pause);
+			break;
+
+		case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (5482)\n",
+				       ext_phy_type);
+
+			bp->port.supported |= (SUPPORTED_10baseT_Half |
+					       SUPPORTED_10baseT_Full |
+					       SUPPORTED_100baseT_Half |
+					       SUPPORTED_100baseT_Full |
+					       SUPPORTED_1000baseT_Full |
+					       SUPPORTED_TP |
+					       SUPPORTED_FIBRE |
+					       SUPPORTED_Autoneg |
+					       SUPPORTED_Pause |
+					       SUPPORTED_Asym_Pause);
+			break;
+
+		default:
+			BNX2X_ERR("NVRAM config error. "
+				  "BAD SerDes ext_phy_config 0x%x\n",
+				  bp->link_params.ext_phy_config);
+			return;
+		}
+
+		bp->port.phy_addr = REG_RD(bp, NIG_REG_SERDES0_CTRL_PHY_ADDR +
+					   port*0x10);
+		BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr);
+		break;
+
+	case SWITCH_CFG_10G:
+		BNX2X_DEV_INFO("switch_cfg 0x%x (10G)\n", switch_cfg);
+
+		ext_phy_type =
+			XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+		switch (ext_phy_type) {
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n",
+				       ext_phy_type);
+
+			bp->port.supported |= (SUPPORTED_10baseT_Half |
+					       SUPPORTED_10baseT_Full |
+					       SUPPORTED_100baseT_Half |
+					       SUPPORTED_100baseT_Full |
+					       SUPPORTED_1000baseT_Full |
+					       SUPPORTED_2500baseX_Full |
+					       SUPPORTED_10000baseT_Full |
+					       SUPPORTED_TP |
+					       SUPPORTED_FIBRE |
+					       SUPPORTED_Autoneg |
+					       SUPPORTED_Pause |
+					       SUPPORTED_Asym_Pause);
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (8072)\n",
+				       ext_phy_type);
+
+			bp->port.supported |= (SUPPORTED_10000baseT_Full |
+					       SUPPORTED_1000baseT_Full |
+					       SUPPORTED_FIBRE |
+					       SUPPORTED_Autoneg |
+					       SUPPORTED_Pause |
+					       SUPPORTED_Asym_Pause);
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (8073)\n",
+				       ext_phy_type);
+
+			bp->port.supported |= (SUPPORTED_10000baseT_Full |
+					       SUPPORTED_2500baseX_Full |
+					       SUPPORTED_1000baseT_Full |
+					       SUPPORTED_FIBRE |
+					       SUPPORTED_Autoneg |
+					       SUPPORTED_Pause |
+					       SUPPORTED_Asym_Pause);
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (8705)\n",
+				       ext_phy_type);
+
+			bp->port.supported |= (SUPPORTED_10000baseT_Full |
+					       SUPPORTED_FIBRE |
+					       SUPPORTED_Pause |
+					       SUPPORTED_Asym_Pause);
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (8706)\n",
+				       ext_phy_type);
+
+			bp->port.supported |= (SUPPORTED_10000baseT_Full |
+					       SUPPORTED_1000baseT_Full |
+					       SUPPORTED_FIBRE |
+					       SUPPORTED_Pause |
+					       SUPPORTED_Asym_Pause);
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (8726)\n",
+				       ext_phy_type);
+
+			bp->port.supported |= (SUPPORTED_10000baseT_Full |
+					       SUPPORTED_1000baseT_Full |
+					       SUPPORTED_Autoneg |
+					       SUPPORTED_FIBRE |
+					       SUPPORTED_Pause |
+					       SUPPORTED_Asym_Pause);
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (8727)\n",
+				       ext_phy_type);
+
+			bp->port.supported |= (SUPPORTED_10000baseT_Full |
+					       SUPPORTED_1000baseT_Full |
+					       SUPPORTED_Autoneg |
+					       SUPPORTED_FIBRE |
+					       SUPPORTED_Pause |
+					       SUPPORTED_Asym_Pause);
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n",
+				       ext_phy_type);
+
+			bp->port.supported |= (SUPPORTED_10000baseT_Full |
+					       SUPPORTED_TP |
+					       SUPPORTED_Autoneg |
+					       SUPPORTED_Pause |
+					       SUPPORTED_Asym_Pause);
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (BCM8481)\n",
+				       ext_phy_type);
+
+			bp->port.supported |= (SUPPORTED_10baseT_Half |
+					       SUPPORTED_10baseT_Full |
+					       SUPPORTED_100baseT_Half |
+					       SUPPORTED_100baseT_Full |
+					       SUPPORTED_1000baseT_Full |
+					       SUPPORTED_10000baseT_Full |
+					       SUPPORTED_TP |
+					       SUPPORTED_Autoneg |
+					       SUPPORTED_Pause |
+					       SUPPORTED_Asym_Pause);
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
+			BNX2X_ERR("XGXS PHY Failure detected 0x%x\n",
+				  bp->link_params.ext_phy_config);
+			break;
+
+		default:
+			BNX2X_ERR("NVRAM config error. "
+				  "BAD XGXS ext_phy_config 0x%x\n",
+				  bp->link_params.ext_phy_config);
+			return;
+		}
+
+		bp->port.phy_addr = REG_RD(bp, NIG_REG_XGXS0_CTRL_PHY_ADDR +
+					   port*0x18);
+		BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr);
+
+		break;
+
+	default:
+		BNX2X_ERR("BAD switch_cfg link_config 0x%x\n",
+			  bp->port.link_config);
+		return;
+	}
+	bp->link_params.phy_addr = bp->port.phy_addr;
+
+	/* mask what we support according to speed_cap_mask */
+	if (!(bp->link_params.speed_cap_mask &
+				PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF))
+		bp->port.supported &= ~SUPPORTED_10baseT_Half;
+
+	if (!(bp->link_params.speed_cap_mask &
+				PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL))
+		bp->port.supported &= ~SUPPORTED_10baseT_Full;
+
+	if (!(bp->link_params.speed_cap_mask &
+				PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF))
+		bp->port.supported &= ~SUPPORTED_100baseT_Half;
+
+	if (!(bp->link_params.speed_cap_mask &
+				PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL))
+		bp->port.supported &= ~SUPPORTED_100baseT_Full;
+
+	if (!(bp->link_params.speed_cap_mask &
+					PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))
+		bp->port.supported &= ~(SUPPORTED_1000baseT_Half |
+					SUPPORTED_1000baseT_Full);
+
+	if (!(bp->link_params.speed_cap_mask &
+					PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
+		bp->port.supported &= ~SUPPORTED_2500baseX_Full;
+
+	if (!(bp->link_params.speed_cap_mask &
+					PORT_HW_CFG_SPEED_CAPABILITY_D0_10G))
+		bp->port.supported &= ~SUPPORTED_10000baseT_Full;
+
+	BNX2X_DEV_INFO("supported 0x%x\n", bp->port.supported);
+}
+
+static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
+{
+	bp->link_params.req_duplex = DUPLEX_FULL;
+
+	switch (bp->port.link_config & PORT_FEATURE_LINK_SPEED_MASK) {
+	case PORT_FEATURE_LINK_SPEED_AUTO:
+		if (bp->port.supported & SUPPORTED_Autoneg) {
+			bp->link_params.req_line_speed = SPEED_AUTO_NEG;
+			bp->port.advertising = bp->port.supported;
+		} else {
+			u32 ext_phy_type =
+			    XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+
+			if ((ext_phy_type ==
+			     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
+			    (ext_phy_type ==
+			     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706)) {
+				/* force 10G, no AN */
+				bp->link_params.req_line_speed = SPEED_10000;
+				bp->port.advertising =
+						(ADVERTISED_10000baseT_Full |
+						 ADVERTISED_FIBRE);
+				break;
+			}
+			BNX2X_ERR("NVRAM config error. "
+				  "Invalid link_config 0x%x"
+				  "  Autoneg not supported\n",
+				  bp->port.link_config);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_10M_FULL:
+		if (bp->port.supported & SUPPORTED_10baseT_Full) {
+			bp->link_params.req_line_speed = SPEED_10;
+			bp->port.advertising = (ADVERTISED_10baseT_Full |
+						ADVERTISED_TP);
+		} else {
+			BNX2X_ERROR("NVRAM config error. "
+				    "Invalid link_config 0x%x"
+				    "  speed_cap_mask 0x%x\n",
+				    bp->port.link_config,
+				    bp->link_params.speed_cap_mask);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_10M_HALF:
+		if (bp->port.supported & SUPPORTED_10baseT_Half) {
+			bp->link_params.req_line_speed = SPEED_10;
+			bp->link_params.req_duplex = DUPLEX_HALF;
+			bp->port.advertising = (ADVERTISED_10baseT_Half |
+						ADVERTISED_TP);
+		} else {
+			BNX2X_ERROR("NVRAM config error. "
+				    "Invalid link_config 0x%x"
+				    "  speed_cap_mask 0x%x\n",
+				    bp->port.link_config,
+				    bp->link_params.speed_cap_mask);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_100M_FULL:
+		if (bp->port.supported & SUPPORTED_100baseT_Full) {
+			bp->link_params.req_line_speed = SPEED_100;
+			bp->port.advertising = (ADVERTISED_100baseT_Full |
+						ADVERTISED_TP);
+		} else {
+			BNX2X_ERROR("NVRAM config error. "
+				    "Invalid link_config 0x%x"
+				    "  speed_cap_mask 0x%x\n",
+				    bp->port.link_config,
+				    bp->link_params.speed_cap_mask);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_100M_HALF:
+		if (bp->port.supported & SUPPORTED_100baseT_Half) {
+			bp->link_params.req_line_speed = SPEED_100;
+			bp->link_params.req_duplex = DUPLEX_HALF;
+			bp->port.advertising = (ADVERTISED_100baseT_Half |
+						ADVERTISED_TP);
+		} else {
+			BNX2X_ERROR("NVRAM config error. "
+				    "Invalid link_config 0x%x"
+				    "  speed_cap_mask 0x%x\n",
+				    bp->port.link_config,
+				    bp->link_params.speed_cap_mask);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_1G:
+		if (bp->port.supported & SUPPORTED_1000baseT_Full) {
+			bp->link_params.req_line_speed = SPEED_1000;
+			bp->port.advertising = (ADVERTISED_1000baseT_Full |
+						ADVERTISED_TP);
+		} else {
+			BNX2X_ERROR("NVRAM config error. "
+				    "Invalid link_config 0x%x"
+				    "  speed_cap_mask 0x%x\n",
+				    bp->port.link_config,
+				    bp->link_params.speed_cap_mask);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_2_5G:
+		if (bp->port.supported & SUPPORTED_2500baseX_Full) {
+			bp->link_params.req_line_speed = SPEED_2500;
+			bp->port.advertising = (ADVERTISED_2500baseX_Full |
+						ADVERTISED_TP);
+		} else {
+			BNX2X_ERROR("NVRAM config error. "
+				    "Invalid link_config 0x%x"
+				    "  speed_cap_mask 0x%x\n",
+				    bp->port.link_config,
+				    bp->link_params.speed_cap_mask);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_10G_CX4:
+	case PORT_FEATURE_LINK_SPEED_10G_KX4:
+	case PORT_FEATURE_LINK_SPEED_10G_KR:
+		if (bp->port.supported & SUPPORTED_10000baseT_Full) {
+			bp->link_params.req_line_speed = SPEED_10000;
+			bp->port.advertising = (ADVERTISED_10000baseT_Full |
+						ADVERTISED_FIBRE);
+		} else {
+			BNX2X_ERROR("NVRAM config error. "
+				    "Invalid link_config 0x%x"
+				    "  speed_cap_mask 0x%x\n",
+				    bp->port.link_config,
+				    bp->link_params.speed_cap_mask);
+			return;
+		}
+		break;
+
+	default:
+		BNX2X_ERROR("NVRAM config error. "
+			    "BAD link speed link_config 0x%x\n",
+			    bp->port.link_config);
+		bp->link_params.req_line_speed = SPEED_AUTO_NEG;
+		bp->port.advertising = bp->port.supported;
+		break;
+	}
+
+	bp->link_params.req_flow_ctrl = (bp->port.link_config &
+					 PORT_FEATURE_FLOW_CONTROL_MASK);
+	if ((bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
+	    !(bp->port.supported & SUPPORTED_Autoneg))
+		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",
+		       bp->link_params.req_line_speed,
+		       bp->link_params.req_duplex,
+		       bp->link_params.req_flow_ctrl, bp->port.advertising);
+}
+
+static void __devinit bnx2x_set_mac_buf(u8 *mac_buf, u32 mac_lo, u16 mac_hi)
+{
+	mac_hi = cpu_to_be16(mac_hi);
+	mac_lo = cpu_to_be32(mac_lo);
+	memcpy(mac_buf, &mac_hi, sizeof(mac_hi));
+	memcpy(mac_buf + sizeof(mac_hi), &mac_lo, sizeof(mac_lo));
+}
+
+static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	u32 val, val2;
+	u32 config;
+	u16 i;
+	u32 ext_phy_type;
+
+	bp->link_params.bp = bp;
+	bp->link_params.port = port;
+
+	bp->link_params.lane_config =
+		SHMEM_RD(bp, dev_info.port_hw_config[port].lane_config);
+	bp->link_params.ext_phy_config =
+		SHMEM_RD(bp,
+			 dev_info.port_hw_config[port].external_phy_config);
+	/* BCM8727_NOC => BCM8727 no over current */
+	if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+	    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC) {
+		bp->link_params.ext_phy_config &=
+			~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+		bp->link_params.ext_phy_config |=
+			PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727;
+		bp->link_params.feature_config_flags |=
+			FEATURE_CONFIG_BCM8727_NOC;
+	}
+
+	bp->link_params.speed_cap_mask =
+		SHMEM_RD(bp,
+			 dev_info.port_hw_config[port].speed_capability_mask);
+
+	bp->port.link_config =
+		SHMEM_RD(bp, dev_info.port_feature_config[port].link_config);
+
+	/* Get the 4 lanes xgxs config rx and tx */
+	for (i = 0; i < 2; i++) {
+		val = SHMEM_RD(bp,
+			   dev_info.port_hw_config[port].xgxs_config_rx[i<<1]);
+		bp->link_params.xgxs_config_rx[i << 1] = ((val>>16) & 0xffff);
+		bp->link_params.xgxs_config_rx[(i << 1) + 1] = (val & 0xffff);
+
+		val = SHMEM_RD(bp,
+			   dev_info.port_hw_config[port].xgxs_config_tx[i<<1]);
+		bp->link_params.xgxs_config_tx[i << 1] = ((val>>16) & 0xffff);
+		bp->link_params.xgxs_config_tx[(i << 1) + 1] = (val & 0xffff);
+	}
+
+	/* If the device is capable of WoL, set the default state according
+	 * to the HW
+	 */
+	config = SHMEM_RD(bp, dev_info.port_feature_config[port].config);
+	bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
+		   (config & PORT_FEATURE_WOL_ENABLED));
+
+	BNX2X_DEV_INFO("lane_config 0x%08x  ext_phy_config 0x%08x"
+		       "  speed_cap_mask 0x%08x  link_config 0x%08x\n",
+		       bp->link_params.lane_config,
+		       bp->link_params.ext_phy_config,
+		       bp->link_params.speed_cap_mask, bp->port.link_config);
+
+	bp->link_params.switch_cfg |= (bp->port.link_config &
+				       PORT_FEATURE_CONNECTED_SWITCH_MASK);
+	bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg);
+
+	bnx2x_link_settings_requested(bp);
+
+	/*
+	 * If connected directly, work with the internal PHY, otherwise, work
+	 * with the external PHY
+	 */
+	ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+	if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
+		bp->mdio.prtad = bp->link_params.phy_addr;
+
+	else if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
+		 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN))
+		bp->mdio.prtad =
+			XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config);
+
+	val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
+	val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
+	bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2);
+	memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN);
+	memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
+
+#ifdef BCM_CNIC
+	val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_upper);
+	val = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_lower);
+	bnx2x_set_mac_buf(bp->iscsi_mac, val, val2);
+#endif
+}
+
+static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
+{
+	int func = BP_FUNC(bp);
+	u32 val, val2;
+	int rc = 0;
+
+	bnx2x_get_common_hwinfo(bp);
+
+	bp->e1hov = 0;
+	bp->e1hmf = 0;
+	if (CHIP_IS_E1H(bp) && !BP_NOMCP(bp)) {
+		bp->mf_config =
+			SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
+
+		val = (SHMEM_RD(bp, mf_cfg.func_mf_config[FUNC_0].e1hov_tag) &
+		       FUNC_MF_CFG_E1HOV_TAG_MASK);
+		if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT)
+			bp->e1hmf = 1;
+		BNX2X_DEV_INFO("%s function mode\n",
+			       IS_E1HMF(bp) ? "multi" : "single");
+
+		if (IS_E1HMF(bp)) {
+			val = (SHMEM_RD(bp, mf_cfg.func_mf_config[func].
+								e1hov_tag) &
+			       FUNC_MF_CFG_E1HOV_TAG_MASK);
+			if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) {
+				bp->e1hov = val;
+				BNX2X_DEV_INFO("E1HOV for func %d is %d "
+					       "(0x%04x)\n",
+					       func, bp->e1hov, bp->e1hov);
+			} else {
+				BNX2X_ERROR("No valid E1HOV for func %d,"
+					    "  aborting\n", func);
+				rc = -EPERM;
+			}
+		} else {
+			if (BP_E1HVN(bp)) {
+				BNX2X_ERROR("VN %d in single function mode,"
+					    "  aborting\n", BP_E1HVN(bp));
+				rc = -EPERM;
+			}
+		}
+	}
+
+	if (!BP_NOMCP(bp)) {
+		bnx2x_get_port_hwinfo(bp);
+
+		bp->fw_seq = (SHMEM_RD(bp, func_mb[func].drv_mb_header) &
+			      DRV_MSG_SEQ_NUMBER_MASK);
+		BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
+	}
+
+	if (IS_E1HMF(bp)) {
+		val2 = SHMEM_RD(bp, mf_cfg.func_mf_config[func].mac_upper);
+		val = SHMEM_RD(bp,  mf_cfg.func_mf_config[func].mac_lower);
+		if ((val2 != FUNC_MF_CFG_UPPERMAC_DEFAULT) &&
+		    (val != FUNC_MF_CFG_LOWERMAC_DEFAULT)) {
+			bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff);
+			bp->dev->dev_addr[1] = (u8)(val2 & 0xff);
+			bp->dev->dev_addr[2] = (u8)(val >> 24 & 0xff);
+			bp->dev->dev_addr[3] = (u8)(val >> 16 & 0xff);
+			bp->dev->dev_addr[4] = (u8)(val >> 8  & 0xff);
+			bp->dev->dev_addr[5] = (u8)(val & 0xff);
+			memcpy(bp->link_params.mac_addr, bp->dev->dev_addr,
+			       ETH_ALEN);
+			memcpy(bp->dev->perm_addr, bp->dev->dev_addr,
+			       ETH_ALEN);
+		}
+
+		return rc;
+	}
+
+	if (BP_NOMCP(bp)) {
+		/* only supposed to happen on emulation/FPGA */
+		BNX2X_ERROR("warning: random MAC workaround active\n");
+		random_ether_addr(bp->dev->dev_addr);
+		memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
+	}
+
+	return rc;
+}
+
+static void __devinit bnx2x_read_fwinfo(struct bnx2x *bp)
+{
+	int cnt, i, block_end, rodi;
+	char vpd_data[BNX2X_VPD_LEN+1];
+	char str_id_reg[VENDOR_ID_LEN+1];
+	char str_id_cap[VENDOR_ID_LEN+1];
+	u8 len;
+
+	cnt = pci_read_vpd(bp->pdev, 0, BNX2X_VPD_LEN, vpd_data);
+	memset(bp->fw_ver, 0, sizeof(bp->fw_ver));
+
+	if (cnt < BNX2X_VPD_LEN)
+		goto out_not_found;
+
+	i = pci_vpd_find_tag(vpd_data, 0, BNX2X_VPD_LEN,
+			     PCI_VPD_LRDT_RO_DATA);
+	if (i < 0)
+		goto out_not_found;
+
+
+	block_end = i + PCI_VPD_LRDT_TAG_SIZE +
+		    pci_vpd_lrdt_size(&vpd_data[i]);
+
+	i += PCI_VPD_LRDT_TAG_SIZE;
+
+	if (block_end > BNX2X_VPD_LEN)
+		goto out_not_found;
+
+	rodi = pci_vpd_find_info_keyword(vpd_data, i, block_end,
+				   PCI_VPD_RO_KEYWORD_MFR_ID);
+	if (rodi < 0)
+		goto out_not_found;
+
+	len = pci_vpd_info_field_size(&vpd_data[rodi]);
+
+	if (len != VENDOR_ID_LEN)
+		goto out_not_found;
+
+	rodi += PCI_VPD_INFO_FLD_HDR_SIZE;
+
+	/* vendor specific info */
+	snprintf(str_id_reg, VENDOR_ID_LEN + 1, "%04x", PCI_VENDOR_ID_DELL);
+	snprintf(str_id_cap, VENDOR_ID_LEN + 1, "%04X", PCI_VENDOR_ID_DELL);
+	if (!strncmp(str_id_reg, &vpd_data[rodi], VENDOR_ID_LEN) ||
+	    !strncmp(str_id_cap, &vpd_data[rodi], VENDOR_ID_LEN)) {
+
+		rodi = pci_vpd_find_info_keyword(vpd_data, i, block_end,
+						PCI_VPD_RO_KEYWORD_VENDOR0);
+		if (rodi >= 0) {
+			len = pci_vpd_info_field_size(&vpd_data[rodi]);
+
+			rodi += PCI_VPD_INFO_FLD_HDR_SIZE;
+
+			if (len < 32 && (len + rodi) <= BNX2X_VPD_LEN) {
+				memcpy(bp->fw_ver, &vpd_data[rodi], len);
+				bp->fw_ver[len] = ' ';
+			}
+		}
+		return;
+	}
+out_not_found:
+	return;
+}
+
+static int __devinit bnx2x_init_bp(struct bnx2x *bp)
+{
+	int func = BP_FUNC(bp);
+	int timer_interval;
+	int rc;
+
+	/* Disable interrupt handling until HW is initialized */
+	atomic_set(&bp->intr_sem, 1);
+	smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
+	mutex_init(&bp->port.phy_mutex);
+	mutex_init(&bp->fw_mb_mutex);
+	spin_lock_init(&bp->stats_lock);
+#ifdef BCM_CNIC
+	mutex_init(&bp->cnic_mutex);
+#endif
+
+	INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
+	INIT_DELAYED_WORK(&bp->reset_task, bnx2x_reset_task);
+
+	rc = bnx2x_get_hwinfo(bp);
+
+	bnx2x_read_fwinfo(bp);
+	/* need to reset chip if undi was active */
+	if (!BP_NOMCP(bp))
+		bnx2x_undi_unload(bp);
+
+	if (CHIP_REV_IS_FPGA(bp))
+		dev_err(&bp->pdev->dev, "FPGA detected\n");
+
+	if (BP_NOMCP(bp) && (func == 0))
+		dev_err(&bp->pdev->dev, "MCP disabled, "
+					"must load devices in order!\n");
+
+	/* Set multi queue mode */
+	if ((multi_mode != ETH_RSS_MODE_DISABLED) &&
+	    ((int_mode == INT_MODE_INTx) || (int_mode == INT_MODE_MSI))) {
+		dev_err(&bp->pdev->dev, "Multi disabled since int_mode "
+					"requested is not MSI-X\n");
+		multi_mode = ETH_RSS_MODE_DISABLED;
+	}
+	bp->multi_mode = multi_mode;
+	bp->int_mode = int_mode;
+
+	bp->dev->features |= NETIF_F_GRO;
+
+	/* Set TPA flags */
+	if (disable_tpa) {
+		bp->flags &= ~TPA_ENABLE_FLAG;
+		bp->dev->features &= ~NETIF_F_LRO;
+	} else {
+		bp->flags |= TPA_ENABLE_FLAG;
+		bp->dev->features |= NETIF_F_LRO;
+	}
+	bp->disable_tpa = disable_tpa;
+
+	if (CHIP_IS_E1(bp))
+		bp->dropless_fc = 0;
+	else
+		bp->dropless_fc = dropless_fc;
+
+	bp->mrrs = mrrs;
+
+	bp->tx_ring_size = MAX_TX_AVAIL;
+	bp->rx_ring_size = MAX_RX_AVAIL;
+
+	bp->rx_csum = 1;
+
+	/* make sure that the numbers are in the right granularity */
+	bp->tx_ticks = (50 / (4 * BNX2X_BTR)) * (4 * BNX2X_BTR);
+	bp->rx_ticks = (25 / (4 * BNX2X_BTR)) * (4 * BNX2X_BTR);
+
+	timer_interval = (CHIP_REV_IS_SLOW(bp) ? 5*HZ : HZ);
+	bp->current_interval = (poll ? poll : timer_interval);
+
+	init_timer(&bp->timer);
+	bp->timer.expires = jiffies + bp->current_interval;
+	bp->timer.data = (unsigned long) bp;
+	bp->timer.function = bnx2x_timer;
+
+	return rc;
+}
+
+
+/****************************************************************************
+* General service functions
+****************************************************************************/
+
+/* called with rtnl_lock */
+static int bnx2x_open(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	netif_carrier_off(dev);
+
+	bnx2x_set_power_state(bp, PCI_D0);
+
+	if (!bnx2x_reset_is_done(bp)) {
+		do {
+			/* Reset MCP mail box sequence if there is on going
+			 * recovery
+			 */
+			bp->fw_seq = 0;
+
+			/* If it's the first function to load and reset done
+			 * is still not cleared it may mean that. We don't
+			 * check the attention state here because it may have
+			 * already been cleared by a "common" reset but we
+			 * shell proceed with "process kill" anyway.
+			 */
+			if ((bnx2x_get_load_cnt(bp) == 0) &&
+				bnx2x_trylock_hw_lock(bp,
+				HW_LOCK_RESOURCE_RESERVED_08) &&
+				(!bnx2x_leader_reset(bp))) {
+				DP(NETIF_MSG_HW, "Recovered in open\n");
+				break;
+			}
+
+			bnx2x_set_power_state(bp, PCI_D3hot);
+
+			printk(KERN_ERR"%s: Recovery flow hasn't been properly"
+			" completed yet. Try again later. If u still see this"
+			" message after a few retries then power cycle is"
+			" required.\n", bp->dev->name);
+
+			return -EAGAIN;
+		} while (0);
+	}
+
+	bp->recovery_state = BNX2X_RECOVERY_DONE;
+
+	return bnx2x_nic_load(bp, LOAD_OPEN);
+}
+
+/* called with rtnl_lock */
+static int bnx2x_close(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	/* Unload the driver, release IRQs */
+	bnx2x_nic_unload(bp, UNLOAD_CLOSE);
+	bnx2x_set_power_state(bp, PCI_D3hot);
+
+	return 0;
+}
+
+/* called with netif_tx_lock from dev_mcast.c */
+void bnx2x_set_rx_mode(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	u32 rx_mode = BNX2X_RX_MODE_NORMAL;
+	int port = BP_PORT(bp);
+
+	if (bp->state != BNX2X_STATE_OPEN) {
+		DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state);
+		return;
+	}
+
+	DP(NETIF_MSG_IFUP, "dev->flags = %x\n", dev->flags);
+
+	if (dev->flags & IFF_PROMISC)
+		rx_mode = BNX2X_RX_MODE_PROMISC;
+
+	else if ((dev->flags & IFF_ALLMULTI) ||
+		 ((netdev_mc_count(dev) > BNX2X_MAX_MULTICAST) &&
+		  CHIP_IS_E1(bp)))
+		rx_mode = BNX2X_RX_MODE_ALLMULTI;
+
+	else { /* some multicasts */
+		if (CHIP_IS_E1(bp)) {
+			int i, old, offset;
+			struct netdev_hw_addr *ha;
+			struct mac_configuration_cmd *config =
+						bnx2x_sp(bp, mcast_config);
+
+			i = 0;
+			netdev_for_each_mc_addr(ha, dev) {
+				config->config_table[i].
+					cam_entry.msb_mac_addr =
+					swab16(*(u16 *)&ha->addr[0]);
+				config->config_table[i].
+					cam_entry.middle_mac_addr =
+					swab16(*(u16 *)&ha->addr[2]);
+				config->config_table[i].
+					cam_entry.lsb_mac_addr =
+					swab16(*(u16 *)&ha->addr[4]);
+				config->config_table[i].cam_entry.flags =
+							cpu_to_le16(port);
+				config->config_table[i].
+					target_table_entry.flags = 0;
+				config->config_table[i].target_table_entry.
+					clients_bit_vector =
+						cpu_to_le32(1 << BP_L_ID(bp));
+				config->config_table[i].
+					target_table_entry.vlan_id = 0;
+
+				DP(NETIF_MSG_IFUP,
+				   "setting MCAST[%d] (%04x:%04x:%04x)\n", i,
+				   config->config_table[i].
+						cam_entry.msb_mac_addr,
+				   config->config_table[i].
+						cam_entry.middle_mac_addr,
+				   config->config_table[i].
+						cam_entry.lsb_mac_addr);
+				i++;
+			}
+			old = config->hdr.length;
+			if (old > i) {
+				for (; i < old; i++) {
+					if (CAM_IS_INVALID(config->
+							   config_table[i])) {
+						/* already invalidated */
+						break;
+					}
+					/* invalidate */
+					CAM_INVALIDATE(config->
+						       config_table[i]);
+				}
+			}
+
+			if (CHIP_REV_IS_SLOW(bp))
+				offset = BNX2X_MAX_EMUL_MULTI*(1 + port);
+			else
+				offset = BNX2X_MAX_MULTICAST*(1 + port);
+
+			config->hdr.length = i;
+			config->hdr.offset = offset;
+			config->hdr.client_id = bp->fp->cl_id;
+			config->hdr.reserved1 = 0;
+
+			bp->set_mac_pending++;
+			smp_wmb();
+
+			bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
+				   U64_HI(bnx2x_sp_mapping(bp, mcast_config)),
+				   U64_LO(bnx2x_sp_mapping(bp, mcast_config)),
+				      0);
+		} else { /* E1H */
+			/* Accept one or more multicasts */
+			struct netdev_hw_addr *ha;
+			u32 mc_filter[MC_HASH_SIZE];
+			u32 crc, bit, regidx;
+			int i;
+
+			memset(mc_filter, 0, 4 * MC_HASH_SIZE);
+
+			netdev_for_each_mc_addr(ha, dev) {
+				DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n",
+				   ha->addr);
+
+				crc = crc32c_le(0, ha->addr, ETH_ALEN);
+				bit = (crc >> 24) & 0xff;
+				regidx = bit >> 5;
+				bit &= 0x1f;
+				mc_filter[regidx] |= (1 << bit);
+			}
+
+			for (i = 0; i < MC_HASH_SIZE; i++)
+				REG_WR(bp, MC_HASH_OFFSET(bp, i),
+				       mc_filter[i]);
+		}
+	}
+
+	bp->rx_mode = rx_mode;
+	bnx2x_set_storm_rx_mode(bp);
+}
+
+
+/* called with rtnl_lock */
+static int bnx2x_mdio_read(struct net_device *netdev, int prtad,
+			   int devad, u16 addr)
+{
+	struct bnx2x *bp = netdev_priv(netdev);
+	u16 value;
+	int rc;
+	u32 phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+
+	DP(NETIF_MSG_LINK, "mdio_read: prtad 0x%x, devad 0x%x, addr 0x%x\n",
+	   prtad, devad, addr);
+
+	if (prtad != bp->mdio.prtad) {
+		DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n",
+		   prtad, bp->mdio.prtad);
+		return -EINVAL;
+	}
+
+	/* The HW expects different devad if CL22 is used */
+	devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad;
+
+	bnx2x_acquire_phy_lock(bp);
+	rc = bnx2x_cl45_read(bp, BP_PORT(bp), phy_type, prtad,
+			     devad, addr, &value);
+	bnx2x_release_phy_lock(bp);
+	DP(NETIF_MSG_LINK, "mdio_read_val 0x%x rc = 0x%x\n", value, rc);
+
+	if (!rc)
+		rc = value;
+	return rc;
+}
+
+/* called with rtnl_lock */
+static int bnx2x_mdio_write(struct net_device *netdev, int prtad, int devad,
+			    u16 addr, u16 value)
+{
+	struct bnx2x *bp = netdev_priv(netdev);
+	u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+	int rc;
+
+	DP(NETIF_MSG_LINK, "mdio_write: prtad 0x%x, devad 0x%x, addr 0x%x,"
+			   " value 0x%x\n", prtad, devad, addr, value);
+
+	if (prtad != bp->mdio.prtad) {
+		DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n",
+		   prtad, bp->mdio.prtad);
+		return -EINVAL;
+	}
+
+	/* The HW expects different devad if CL22 is used */
+	devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad;
+
+	bnx2x_acquire_phy_lock(bp);
+	rc = bnx2x_cl45_write(bp, BP_PORT(bp), ext_phy_type, prtad,
+			      devad, addr, value);
+	bnx2x_release_phy_lock(bp);
+	return rc;
+}
+
+/* called with rtnl_lock */
+static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	struct mii_ioctl_data *mdio = if_mii(ifr);
+
+	DP(NETIF_MSG_LINK, "ioctl: phy id 0x%x, reg 0x%x, val_in 0x%x\n",
+	   mdio->phy_id, mdio->reg_num, mdio->val_in);
+
+	if (!netif_running(dev))
+		return -EAGAIN;
+
+	return mdio_mii_ioctl(&bp->mdio, mdio, cmd);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void poll_bnx2x(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	disable_irq(bp->pdev->irq);
+	bnx2x_interrupt(bp->pdev->irq, dev);
+	enable_irq(bp->pdev->irq);
+}
+#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
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= poll_bnx2x,
+#endif
+};
+
+static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
+				    struct net_device *dev)
+{
+	struct bnx2x *bp;
+	int rc;
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	bp = netdev_priv(dev);
+
+	bp->dev = dev;
+	bp->pdev = pdev;
+	bp->flags = 0;
+	bp->func = PCI_FUNC(pdev->devfn);
+
+	rc = pci_enable_device(pdev);
+	if (rc) {
+		dev_err(&bp->pdev->dev,
+			"Cannot enable PCI device, aborting\n");
+		goto err_out;
+	}
+
+	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+		dev_err(&bp->pdev->dev,
+			"Cannot find PCI device base address, aborting\n");
+		rc = -ENODEV;
+		goto err_out_disable;
+	}
+
+	if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+		dev_err(&bp->pdev->dev, "Cannot find second PCI device"
+		       " base address, aborting\n");
+		rc = -ENODEV;
+		goto err_out_disable;
+	}
+
+	if (atomic_read(&pdev->enable_cnt) == 1) {
+		rc = pci_request_regions(pdev, DRV_MODULE_NAME);
+		if (rc) {
+			dev_err(&bp->pdev->dev,
+				"Cannot obtain PCI resources, aborting\n");
+			goto err_out_disable;
+		}
+
+		pci_set_master(pdev);
+		pci_save_state(pdev);
+	}
+
+	bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	if (bp->pm_cap == 0) {
+		dev_err(&bp->pdev->dev,
+			"Cannot find power management capability, aborting\n");
+		rc = -EIO;
+		goto err_out_release;
+	}
+
+	bp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	if (bp->pcie_cap == 0) {
+		dev_err(&bp->pdev->dev,
+			"Cannot find PCI Express capability, aborting\n");
+		rc = -EIO;
+		goto err_out_release;
+	}
+
+	if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) == 0) {
+		bp->flags |= USING_DAC_FLAG;
+		if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)) != 0) {
+			dev_err(&bp->pdev->dev, "dma_set_coherent_mask"
+			       " failed, aborting\n");
+			rc = -EIO;
+			goto err_out_release;
+		}
+
+	} else if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
+		dev_err(&bp->pdev->dev,
+			"System does not support DMA, aborting\n");
+		rc = -EIO;
+		goto err_out_release;
+	}
+
+	dev->mem_start = pci_resource_start(pdev, 0);
+	dev->base_addr = dev->mem_start;
+	dev->mem_end = pci_resource_end(pdev, 0);
+
+	dev->irq = pdev->irq;
+
+	bp->regview = pci_ioremap_bar(pdev, 0);
+	if (!bp->regview) {
+		dev_err(&bp->pdev->dev,
+			"Cannot map register space, aborting\n");
+		rc = -ENOMEM;
+		goto err_out_release;
+	}
+
+	bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
+					min_t(u64, BNX2X_DB_SIZE,
+					      pci_resource_len(pdev, 2)));
+	if (!bp->doorbells) {
+		dev_err(&bp->pdev->dev,
+			"Cannot map doorbell space, aborting\n");
+		rc = -ENOMEM;
+		goto err_out_unmap;
+	}
+
+	bnx2x_set_power_state(bp, PCI_D0);
+
+	/* clean indirect addresses */
+	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
+			       PCICFG_VENDOR_ID_OFFSET);
+	REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0 + BP_PORT(bp)*16, 0);
+	REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0 + BP_PORT(bp)*16, 0);
+	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);
+
+	/* Reset the load counter */
+	bnx2x_clear_load_cnt(bp);
+
+	dev->watchdog_timeo = TX_TIMEOUT;
+
+	dev->netdev_ops = &bnx2x_netdev_ops;
+	bnx2x_set_ethtool_ops(dev);
+	dev->features |= NETIF_F_SG;
+	dev->features |= NETIF_F_HW_CSUM;
+	if (bp->flags & USING_DAC_FLAG)
+		dev->features |= NETIF_F_HIGHDMA;
+	dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+	dev->features |= NETIF_F_TSO6;
+#ifdef BCM_VLAN
+	dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
+	bp->flags |= (HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
+
+	dev->vlan_features |= NETIF_F_SG;
+	dev->vlan_features |= NETIF_F_HW_CSUM;
+	if (bp->flags & USING_DAC_FLAG)
+		dev->vlan_features |= NETIF_F_HIGHDMA;
+	dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+	dev->vlan_features |= NETIF_F_TSO6;
+#endif
+
+	/* get_port_hwinfo() will set prtad and mmds properly */
+	bp->mdio.prtad = MDIO_PRTAD_NONE;
+	bp->mdio.mmds = 0;
+	bp->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+	bp->mdio.dev = dev;
+	bp->mdio.mdio_read = bnx2x_mdio_read;
+	bp->mdio.mdio_write = bnx2x_mdio_write;
+
+	return 0;
+
+err_out_unmap:
+	if (bp->regview) {
+		iounmap(bp->regview);
+		bp->regview = NULL;
+	}
+	if (bp->doorbells) {
+		iounmap(bp->doorbells);
+		bp->doorbells = NULL;
+	}
+
+err_out_release:
+	if (atomic_read(&pdev->enable_cnt) == 1)
+		pci_release_regions(pdev);
+
+err_out_disable:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+
+err_out:
+	return rc;
+}
+
+static void __devinit bnx2x_get_pcie_width_speed(struct bnx2x *bp,
+						 int *width, int *speed)
+{
+	u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL);
+
+	*width = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT;
+
+	/* return value of 1=2.5GHz 2=5GHz */
+	*speed = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT;
+}
+
+static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
+{
+	const struct firmware *firmware = bp->firmware;
+	struct bnx2x_fw_file_hdr *fw_hdr;
+	struct bnx2x_fw_file_section *sections;
+	u32 offset, len, num_ops;
+	u16 *ops_offsets;
+	int i;
+	const u8 *fw_ver;
+
+	if (firmware->size < sizeof(struct bnx2x_fw_file_hdr))
+		return -EINVAL;
+
+	fw_hdr = (struct bnx2x_fw_file_hdr *)firmware->data;
+	sections = (struct bnx2x_fw_file_section *)fw_hdr;
+
+	/* Make sure none of the offsets and sizes make us read beyond
+	 * the end of the firmware data */
+	for (i = 0; i < sizeof(*fw_hdr) / sizeof(*sections); i++) {
+		offset = be32_to_cpu(sections[i].offset);
+		len = be32_to_cpu(sections[i].len);
+		if (offset + len > firmware->size) {
+			dev_err(&bp->pdev->dev,
+				"Section %d length is out of bounds\n", i);
+			return -EINVAL;
+		}
+	}
+
+	/* Likewise for the init_ops offsets */
+	offset = be32_to_cpu(fw_hdr->init_ops_offsets.offset);
+	ops_offsets = (u16 *)(firmware->data + offset);
+	num_ops = be32_to_cpu(fw_hdr->init_ops.len) / sizeof(struct raw_op);
+
+	for (i = 0; i < be32_to_cpu(fw_hdr->init_ops_offsets.len) / 2; i++) {
+		if (be16_to_cpu(ops_offsets[i]) > num_ops) {
+			dev_err(&bp->pdev->dev,
+				"Section offset %d is out of bounds\n", i);
+			return -EINVAL;
+		}
+	}
+
+	/* Check FW version */
+	offset = be32_to_cpu(fw_hdr->fw_version.offset);
+	fw_ver = firmware->data + offset;
+	if ((fw_ver[0] != BCM_5710_FW_MAJOR_VERSION) ||
+	    (fw_ver[1] != BCM_5710_FW_MINOR_VERSION) ||
+	    (fw_ver[2] != BCM_5710_FW_REVISION_VERSION) ||
+	    (fw_ver[3] != BCM_5710_FW_ENGINEERING_VERSION)) {
+		dev_err(&bp->pdev->dev,
+			"Bad FW version:%d.%d.%d.%d. Should be %d.%d.%d.%d\n",
+		       fw_ver[0], fw_ver[1], fw_ver[2],
+		       fw_ver[3], BCM_5710_FW_MAJOR_VERSION,
+		       BCM_5710_FW_MINOR_VERSION,
+		       BCM_5710_FW_REVISION_VERSION,
+		       BCM_5710_FW_ENGINEERING_VERSION);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline void be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n)
+{
+	const __be32 *source = (const __be32 *)_source;
+	u32 *target = (u32 *)_target;
+	u32 i;
+
+	for (i = 0; i < n/4; i++)
+		target[i] = be32_to_cpu(source[i]);
+}
+
+/*
+   Ops array is stored in the following format:
+   {op(8bit), offset(24bit, big endian), data(32bit, big endian)}
+ */
+static inline void bnx2x_prep_ops(const u8 *_source, u8 *_target, u32 n)
+{
+	const __be32 *source = (const __be32 *)_source;
+	struct raw_op *target = (struct raw_op *)_target;
+	u32 i, j, tmp;
+
+	for (i = 0, j = 0; i < n/8; i++, j += 2) {
+		tmp = be32_to_cpu(source[j]);
+		target[i].op = (tmp >> 24) & 0xff;
+		target[i].offset = tmp & 0xffffff;
+		target[i].raw_data = be32_to_cpu(source[j + 1]);
+	}
+}
+
+static inline void be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n)
+{
+	const __be16 *source = (const __be16 *)_source;
+	u16 *target = (u16 *)_target;
+	u32 i;
+
+	for (i = 0; i < n/2; i++)
+		target[i] = be16_to_cpu(source[i]);
+}
+
+#define BNX2X_ALLOC_AND_SET(arr, lbl, func)				\
+do {									\
+	u32 len = be32_to_cpu(fw_hdr->arr.len);				\
+	bp->arr = kmalloc(len, GFP_KERNEL);				\
+	if (!bp->arr) {							\
+		pr_err("Failed to allocate %d bytes for "#arr"\n", len); \
+		goto lbl;						\
+	}								\
+	func(bp->firmware->data + be32_to_cpu(fw_hdr->arr.offset),	\
+	     (u8 *)bp->arr, len);					\
+} while (0)
+
+static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev)
+{
+	const char *fw_file_name;
+	struct bnx2x_fw_file_hdr *fw_hdr;
+	int rc;
+
+	if (CHIP_IS_E1(bp))
+		fw_file_name = FW_FILE_NAME_E1;
+	else if (CHIP_IS_E1H(bp))
+		fw_file_name = FW_FILE_NAME_E1H;
+	else {
+		dev_err(dev, "Unsupported chip revision\n");
+		return -EINVAL;
+	}
+
+	dev_info(dev, "Loading %s\n", fw_file_name);
+
+	rc = request_firmware(&bp->firmware, fw_file_name, dev);
+	if (rc) {
+		dev_err(dev, "Can't load firmware file %s\n", fw_file_name);
+		goto request_firmware_exit;
+	}
+
+	rc = bnx2x_check_firmware(bp);
+	if (rc) {
+		dev_err(dev, "Corrupt firmware file %s\n", fw_file_name);
+		goto request_firmware_exit;
+	}
+
+	fw_hdr = (struct bnx2x_fw_file_hdr *)bp->firmware->data;
+
+	/* Initialize the pointers to the init arrays */
+	/* Blob */
+	BNX2X_ALLOC_AND_SET(init_data, request_firmware_exit, be32_to_cpu_n);
+
+	/* Opcodes */
+	BNX2X_ALLOC_AND_SET(init_ops, init_ops_alloc_err, bnx2x_prep_ops);
+
+	/* Offsets */
+	BNX2X_ALLOC_AND_SET(init_ops_offsets, init_offsets_alloc_err,
+			    be16_to_cpu_n);
+
+	/* STORMs firmware */
+	INIT_TSEM_INT_TABLE_DATA(bp) = bp->firmware->data +
+			be32_to_cpu(fw_hdr->tsem_int_table_data.offset);
+	INIT_TSEM_PRAM_DATA(bp)      = bp->firmware->data +
+			be32_to_cpu(fw_hdr->tsem_pram_data.offset);
+	INIT_USEM_INT_TABLE_DATA(bp) = bp->firmware->data +
+			be32_to_cpu(fw_hdr->usem_int_table_data.offset);
+	INIT_USEM_PRAM_DATA(bp)      = bp->firmware->data +
+			be32_to_cpu(fw_hdr->usem_pram_data.offset);
+	INIT_XSEM_INT_TABLE_DATA(bp) = bp->firmware->data +
+			be32_to_cpu(fw_hdr->xsem_int_table_data.offset);
+	INIT_XSEM_PRAM_DATA(bp)      = bp->firmware->data +
+			be32_to_cpu(fw_hdr->xsem_pram_data.offset);
+	INIT_CSEM_INT_TABLE_DATA(bp) = bp->firmware->data +
+			be32_to_cpu(fw_hdr->csem_int_table_data.offset);
+	INIT_CSEM_PRAM_DATA(bp)      = bp->firmware->data +
+			be32_to_cpu(fw_hdr->csem_pram_data.offset);
+
+	return 0;
+
+init_offsets_alloc_err:
+	kfree(bp->init_ops);
+init_ops_alloc_err:
+	kfree(bp->init_data);
+request_firmware_exit:
+	release_firmware(bp->firmware);
+
+	return rc;
+}
+
+
+static int __devinit bnx2x_init_one(struct pci_dev *pdev,
+				    const struct pci_device_id *ent)
+{
+	struct net_device *dev = NULL;
+	struct bnx2x *bp;
+	int pcie_width, pcie_speed;
+	int rc;
+
+	/* dev zeroed in init_etherdev */
+	dev = alloc_etherdev_mq(sizeof(*bp), MAX_CONTEXT);
+	if (!dev) {
+		dev_err(&pdev->dev, "Cannot allocate net device\n");
+		return -ENOMEM;
+	}
+
+	bp = netdev_priv(dev);
+	bp->msg_enable = debug;
+
+	pci_set_drvdata(pdev, dev);
+
+	rc = bnx2x_init_dev(pdev, dev);
+	if (rc < 0) {
+		free_netdev(dev);
+		return rc;
+	}
+
+	rc = bnx2x_init_bp(bp);
+	if (rc)
+		goto init_one_exit;
+
+	/* Set init arrays */
+	rc = bnx2x_init_firmware(bp, &pdev->dev);
+	if (rc) {
+		dev_err(&pdev->dev, "Error loading firmware\n");
+		goto init_one_exit;
+	}
+
+	rc = register_netdev(dev);
+	if (rc) {
+		dev_err(&pdev->dev, "Cannot register net device\n");
+		goto init_one_exit;
+	}
+
+	bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed);
+	netdev_info(dev, "%s (%c%d) PCI-E x%d %s found at mem %lx,"
+	       " IRQ %d, ", board_info[ent->driver_data].name,
+	       (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4),
+	       pcie_width, (pcie_speed == 2) ? "5GHz (Gen2)" : "2.5GHz",
+	       dev->base_addr, bp->pdev->irq);
+	pr_cont("node addr %pM\n", dev->dev_addr);
+
+	return 0;
+
+init_one_exit:
+	if (bp->regview)
+		iounmap(bp->regview);
+
+	if (bp->doorbells)
+		iounmap(bp->doorbells);
+
+	free_netdev(dev);
+
+	if (atomic_read(&pdev->enable_cnt) == 1)
+		pci_release_regions(pdev);
+
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+
+	return rc;
+}
+
+static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct bnx2x *bp;
+
+	if (!dev) {
+		dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
+		return;
+	}
+	bp = netdev_priv(dev);
+
+	unregister_netdev(dev);
+
+	/* Make sure RESET task is not scheduled before continuing */
+	cancel_delayed_work_sync(&bp->reset_task);
+
+	kfree(bp->init_ops_offsets);
+	kfree(bp->init_ops);
+	kfree(bp->init_data);
+	release_firmware(bp->firmware);
+
+	if (bp->regview)
+		iounmap(bp->regview);
+
+	if (bp->doorbells)
+		iounmap(bp->doorbells);
+
+	free_netdev(dev);
+
+	if (atomic_read(&pdev->enable_cnt) == 1)
+		pci_release_regions(pdev);
+
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
+{
+	int i;
+
+	bp->state = BNX2X_STATE_ERROR;
+
+	bp->rx_mode = BNX2X_RX_MODE_NONE;
+
+	bnx2x_netif_stop(bp, 0);
+	netif_carrier_off(bp->dev);
+
+	del_timer_sync(&bp->timer);
+	bp->stats_state = STATS_STATE_DISABLED;
+	DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");
+
+	/* Release IRQs */
+	bnx2x_free_irq(bp, false);
+
+	if (CHIP_IS_E1(bp)) {
+		struct mac_configuration_cmd *config =
+						bnx2x_sp(bp, mcast_config);
+
+		for (i = 0; i < config->hdr.length; i++)
+			CAM_INVALIDATE(config->config_table[i]);
+	}
+
+	/* Free SKBs, SGEs, TPA pool and driver internals */
+	bnx2x_free_skbs(bp);
+	for_each_queue(bp, i)
+		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
+	for_each_queue(bp, i)
+		netif_napi_del(&bnx2x_fp(bp, i, napi));
+	bnx2x_free_mem(bp);
+
+	bp->state = BNX2X_STATE_CLOSED;
+
+	return 0;
+}
+
+static void bnx2x_eeh_recover(struct bnx2x *bp)
+{
+	u32 val;
+
+	mutex_init(&bp->port.phy_mutex);
+
+	bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+	bp->link_params.shmem_base = bp->common.shmem_base;
+	BNX2X_DEV_INFO("shmem offset is 0x%x\n", bp->common.shmem_base);
+
+	if (!bp->common.shmem_base ||
+	    (bp->common.shmem_base < 0xA0000) ||
+	    (bp->common.shmem_base >= 0xC0000)) {
+		BNX2X_DEV_INFO("MCP not active\n");
+		bp->flags |= NO_MCP_FLAG;
+		return;
+	}
+
+	val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]);
+	if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+		!= (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+		BNX2X_ERR("BAD MCP validity signature\n");
+
+	if (!BP_NOMCP(bp)) {
+		bp->fw_seq = (SHMEM_RD(bp, func_mb[BP_FUNC(bp)].drv_mb_header)
+			      & DRV_MSG_SEQ_NUMBER_MASK);
+		BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
+	}
+}
+
+/**
+ * bnx2x_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t bnx2x_io_error_detected(struct pci_dev *pdev,
+						pci_channel_state_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct bnx2x *bp = netdev_priv(dev);
+
+	rtnl_lock();
+
+	netif_device_detach(dev);
+
+	if (state == pci_channel_io_perm_failure) {
+		rtnl_unlock();
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+
+	if (netif_running(dev))
+		bnx2x_eeh_nic_unload(bp);
+
+	pci_disable_device(pdev);
+
+	rtnl_unlock();
+
+	/* Request a slot reset */
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * bnx2x_io_slot_reset - called after the PCI bus has been reset
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ */
+static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct bnx2x *bp = netdev_priv(dev);
+
+	rtnl_lock();
+
+	if (pci_enable_device(pdev)) {
+		dev_err(&pdev->dev,
+			"Cannot re-enable PCI device after reset\n");
+		rtnl_unlock();
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+
+	pci_set_master(pdev);
+	pci_restore_state(pdev);
+
+	if (netif_running(dev))
+		bnx2x_set_power_state(bp, PCI_D0);
+
+	rtnl_unlock();
+
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * bnx2x_io_resume - called when traffic can start flowing again
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation.
+ */
+static void bnx2x_io_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+		return;
+	}
+
+	rtnl_lock();
+
+	bnx2x_eeh_recover(bp);
+
+	if (netif_running(dev))
+		bnx2x_nic_load(bp, LOAD_NORMAL);
+
+	netif_device_attach(dev);
+
+	rtnl_unlock();
+}
+
+static struct pci_error_handlers bnx2x_err_handler = {
+	.error_detected = bnx2x_io_error_detected,
+	.slot_reset     = bnx2x_io_slot_reset,
+	.resume         = bnx2x_io_resume,
+};
+
+static struct pci_driver bnx2x_pci_driver = {
+	.name        = DRV_MODULE_NAME,
+	.id_table    = bnx2x_pci_tbl,
+	.probe       = bnx2x_init_one,
+	.remove      = __devexit_p(bnx2x_remove_one),
+	.suspend     = bnx2x_suspend,
+	.resume      = bnx2x_resume,
+	.err_handler = &bnx2x_err_handler,
+};
+
+static int __init bnx2x_init(void)
+{
+	int ret;
+
+	pr_info("%s", version);
+
+	bnx2x_wq = create_singlethread_workqueue("bnx2x");
+	if (bnx2x_wq == NULL) {
+		pr_err("Cannot create workqueue\n");
+		return -ENOMEM;
+	}
+
+	ret = pci_register_driver(&bnx2x_pci_driver);
+	if (ret) {
+		pr_err("Cannot register driver\n");
+		destroy_workqueue(bnx2x_wq);
+	}
+	return ret;
+}
+
+static void __exit bnx2x_cleanup(void)
+{
+	pci_unregister_driver(&bnx2x_pci_driver);
+
+	destroy_workqueue(bnx2x_wq);
+}
+
+module_init(bnx2x_init);
+module_exit(bnx2x_cleanup);
+
+#ifdef BCM_CNIC
+
+/* count denotes the number of new completions we have seen */
+static void bnx2x_cnic_sp_post(struct bnx2x *bp, int count)
+{
+	struct eth_spe *spe;
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return;
+#endif
+
+	spin_lock_bh(&bp->spq_lock);
+	bp->cnic_spq_pending -= count;
+
+	for (; bp->cnic_spq_pending < bp->cnic_eth_dev.max_kwqe_pending;
+	     bp->cnic_spq_pending++) {
+
+		if (!bp->cnic_kwq_pending)
+			break;
+
+		spe = bnx2x_sp_get_next(bp);
+		*spe = *bp->cnic_kwq_cons;
+
+		bp->cnic_kwq_pending--;
+
+		DP(NETIF_MSG_TIMER, "pending on SPQ %d, on KWQ %d count %d\n",
+		   bp->cnic_spq_pending, bp->cnic_kwq_pending, count);
+
+		if (bp->cnic_kwq_cons == bp->cnic_kwq_last)
+			bp->cnic_kwq_cons = bp->cnic_kwq;
+		else
+			bp->cnic_kwq_cons++;
+	}
+	bnx2x_sp_prod_update(bp);
+	spin_unlock_bh(&bp->spq_lock);
+}
+
+static int bnx2x_cnic_sp_queue(struct net_device *dev,
+			       struct kwqe_16 *kwqes[], u32 count)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int i;
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return -EIO;
+#endif
+
+	spin_lock_bh(&bp->spq_lock);
+
+	for (i = 0; i < count; i++) {
+		struct eth_spe *spe = (struct eth_spe *)kwqes[i];
+
+		if (bp->cnic_kwq_pending == MAX_SP_DESC_CNT)
+			break;
+
+		*bp->cnic_kwq_prod = *spe;
+
+		bp->cnic_kwq_pending++;
+
+		DP(NETIF_MSG_TIMER, "L5 SPQE %x %x %x:%x pos %d\n",
+		   spe->hdr.conn_and_cmd_data, spe->hdr.type,
+		   spe->data.mac_config_addr.hi,
+		   spe->data.mac_config_addr.lo,
+		   bp->cnic_kwq_pending);
+
+		if (bp->cnic_kwq_prod == bp->cnic_kwq_last)
+			bp->cnic_kwq_prod = bp->cnic_kwq;
+		else
+			bp->cnic_kwq_prod++;
+	}
+
+	spin_unlock_bh(&bp->spq_lock);
+
+	if (bp->cnic_spq_pending < bp->cnic_eth_dev.max_kwqe_pending)
+		bnx2x_cnic_sp_post(bp, 0);
+
+	return i;
+}
+
+static int bnx2x_cnic_ctl_send(struct bnx2x *bp, struct cnic_ctl_info *ctl)
+{
+	struct cnic_ops *c_ops;
+	int rc = 0;
+
+	mutex_lock(&bp->cnic_mutex);
+	c_ops = bp->cnic_ops;
+	if (c_ops)
+		rc = c_ops->cnic_ctl(bp->cnic_data, ctl);
+	mutex_unlock(&bp->cnic_mutex);
+
+	return rc;
+}
+
+static int bnx2x_cnic_ctl_send_bh(struct bnx2x *bp, struct cnic_ctl_info *ctl)
+{
+	struct cnic_ops *c_ops;
+	int rc = 0;
+
+	rcu_read_lock();
+	c_ops = rcu_dereference(bp->cnic_ops);
+	if (c_ops)
+		rc = c_ops->cnic_ctl(bp->cnic_data, ctl);
+	rcu_read_unlock();
+
+	return rc;
+}
+
+/*
+ * for commands that have no data
+ */
+int bnx2x_cnic_notify(struct bnx2x *bp, int cmd)
+{
+	struct cnic_ctl_info ctl = {0};
+
+	ctl.cmd = cmd;
+
+	return bnx2x_cnic_ctl_send(bp, &ctl);
+}
+
+static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid)
+{
+	struct cnic_ctl_info ctl;
+
+	/* first we tell CNIC and only then we count this as a completion */
+	ctl.cmd = CNIC_CTL_COMPLETION_CMD;
+	ctl.data.comp.cid = cid;
+
+	bnx2x_cnic_ctl_send_bh(bp, &ctl);
+	bnx2x_cnic_sp_post(bp, 1);
+}
+
+static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int rc = 0;
+
+	switch (ctl->cmd) {
+	case DRV_CTL_CTXTBL_WR_CMD: {
+		u32 index = ctl->data.io.offset;
+		dma_addr_t addr = ctl->data.io.dma_addr;
+
+		bnx2x_ilt_wr(bp, index, addr);
+		break;
+	}
+
+	case DRV_CTL_COMPLETION_CMD: {
+		int count = ctl->data.comp.comp_count;
+
+		bnx2x_cnic_sp_post(bp, count);
+		break;
+	}
+
+	/* rtnl_lock is held.  */
+	case DRV_CTL_START_L2_CMD: {
+		u32 cli = ctl->data.ring.client_id;
+
+		bp->rx_mode_cl_mask |= (1 << cli);
+		bnx2x_set_storm_rx_mode(bp);
+		break;
+	}
+
+	/* rtnl_lock is held.  */
+	case DRV_CTL_STOP_L2_CMD: {
+		u32 cli = ctl->data.ring.client_id;
+
+		bp->rx_mode_cl_mask &= ~(1 << cli);
+		bnx2x_set_storm_rx_mode(bp);
+		break;
+	}
+
+	default:
+		BNX2X_ERR("unknown command %x\n", ctl->cmd);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+void bnx2x_setup_cnic_irq_info(struct bnx2x *bp)
+{
+	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+	if (bp->flags & USING_MSIX_FLAG) {
+		cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
+		cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
+		cp->irq_arr[0].vector = bp->msix_table[1].vector;
+	} else {
+		cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
+		cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
+	}
+	cp->irq_arr[0].status_blk = bp->cnic_sb;
+	cp->irq_arr[0].status_blk_num = CNIC_SB_ID(bp);
+	cp->irq_arr[1].status_blk = bp->def_status_blk;
+	cp->irq_arr[1].status_blk_num = DEF_SB_ID;
+
+	cp->num_irq = 2;
+}
+
+static int bnx2x_register_cnic(struct net_device *dev, struct cnic_ops *ops,
+			       void *data)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+	if (ops == NULL)
+		return -EINVAL;
+
+	if (atomic_read(&bp->intr_sem) != 0)
+		return -EBUSY;
+
+	bp->cnic_kwq = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!bp->cnic_kwq)
+		return -ENOMEM;
+
+	bp->cnic_kwq_cons = bp->cnic_kwq;
+	bp->cnic_kwq_prod = bp->cnic_kwq;
+	bp->cnic_kwq_last = bp->cnic_kwq + MAX_SP_DESC_CNT;
+
+	bp->cnic_spq_pending = 0;
+	bp->cnic_kwq_pending = 0;
+
+	bp->cnic_data = data;
+
+	cp->num_irq = 0;
+	cp->drv_state = CNIC_DRV_STATE_REGD;
+
+	bnx2x_init_sb(bp, bp->cnic_sb, bp->cnic_sb_mapping, CNIC_SB_ID(bp));
+
+	bnx2x_setup_cnic_irq_info(bp);
+	bnx2x_set_iscsi_eth_mac_addr(bp, 1);
+	bp->cnic_flags |= BNX2X_CNIC_FLAG_MAC_SET;
+	rcu_assign_pointer(bp->cnic_ops, ops);
+
+	return 0;
+}
+
+static int bnx2x_unregister_cnic(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+	mutex_lock(&bp->cnic_mutex);
+	if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) {
+		bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET;
+		bnx2x_set_iscsi_eth_mac_addr(bp, 0);
+	}
+	cp->drv_state = 0;
+	rcu_assign_pointer(bp->cnic_ops, NULL);
+	mutex_unlock(&bp->cnic_mutex);
+	synchronize_rcu();
+	kfree(bp->cnic_kwq);
+	bp->cnic_kwq = NULL;
+
+	return 0;
+}
+
+struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+	cp->drv_owner = THIS_MODULE;
+	cp->chip_id = CHIP_ID(bp);
+	cp->pdev = bp->pdev;
+	cp->io_base = bp->regview;
+	cp->io_base2 = bp->doorbells;
+	cp->max_kwqe_pending = 8;
+	cp->ctx_blk_size = CNIC_CTX_PER_ILT * sizeof(union cdu_context);
+	cp->ctx_tbl_offset = FUNC_ILT_BASE(BP_FUNC(bp)) + 1;
+	cp->ctx_tbl_len = CNIC_ILT_LINES;
+	cp->starting_cid = BCM_CNIC_CID_START;
+	cp->drv_submit_kwqes_16 = bnx2x_cnic_sp_queue;
+	cp->drv_ctl = bnx2x_drv_ctl;
+	cp->drv_register_cnic = bnx2x_register_cnic;
+	cp->drv_unregister_cnic = bnx2x_unregister_cnic;
+
+	return cp;
+}
+EXPORT_SYMBOL(bnx2x_cnic_probe);
+
+#endif /* BCM_CNIC */
+
diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h
similarity index 100%
rename from drivers/net/bnx2x_reg.h
rename to drivers/net/bnx2x/bnx2x_reg.h
diff --git a/drivers/net/bnx2x/bnx2x_stats.c b/drivers/net/bnx2x/bnx2x_stats.c
new file mode 100644
index 0000000..c747244
--- /dev/null
+++ b/drivers/net/bnx2x/bnx2x_stats.c
@@ -0,0 +1,1411 @@
+/* bnx2x_stats.c: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007-2010 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
+ * Based on code from Michael Chan's bnx2 driver
+ * UDP CSUM errata workaround by Arik Gendelman
+ * Slowpath and fastpath rework by Vladislav Zolotarov
+ * Statistics and Link management by Yitchak Gertner
+ *
+ */
+ #include "bnx2x_cmn.h"
+ #include "bnx2x_stats.h"
+
+/* Statistics */
+
+/****************************************************************************
+* Macros
+****************************************************************************/
+
+/* sum[hi:lo] += add[hi:lo] */
+#define ADD_64(s_hi, a_hi, s_lo, a_lo) \
+	do { \
+		s_lo += a_lo; \
+		s_hi += a_hi + ((s_lo < a_lo) ? 1 : 0); \
+	} while (0)
+
+/* difference = minuend - subtrahend */
+#define DIFF_64(d_hi, m_hi, s_hi, d_lo, m_lo, s_lo) \
+	do { \
+		if (m_lo < s_lo) { \
+			/* underflow */ \
+			d_hi = m_hi - s_hi; \
+			if (d_hi > 0) { \
+				/* we can 'loan' 1 */ \
+				d_hi--; \
+				d_lo = m_lo + (UINT_MAX - s_lo) + 1; \
+			} else { \
+				/* m_hi <= s_hi */ \
+				d_hi = 0; \
+				d_lo = 0; \
+			} \
+		} else { \
+			/* m_lo >= s_lo */ \
+			if (m_hi < s_hi) { \
+				d_hi = 0; \
+				d_lo = 0; \
+			} else { \
+				/* m_hi >= s_hi */ \
+				d_hi = m_hi - s_hi; \
+				d_lo = m_lo - s_lo; \
+			} \
+		} \
+	} while (0)
+
+#define UPDATE_STAT64(s, t) \
+	do { \
+		DIFF_64(diff.hi, new->s##_hi, pstats->mac_stx[0].t##_hi, \
+			diff.lo, new->s##_lo, pstats->mac_stx[0].t##_lo); \
+		pstats->mac_stx[0].t##_hi = new->s##_hi; \
+		pstats->mac_stx[0].t##_lo = new->s##_lo; \
+		ADD_64(pstats->mac_stx[1].t##_hi, diff.hi, \
+		       pstats->mac_stx[1].t##_lo, diff.lo); \
+	} while (0)
+
+#define UPDATE_STAT64_NIG(s, t) \
+	do { \
+		DIFF_64(diff.hi, new->s##_hi, old->s##_hi, \
+			diff.lo, new->s##_lo, old->s##_lo); \
+		ADD_64(estats->t##_hi, diff.hi, \
+		       estats->t##_lo, diff.lo); \
+	} while (0)
+
+/* sum[hi:lo] += add */
+#define ADD_EXTEND_64(s_hi, s_lo, a) \
+	do { \
+		s_lo += a; \
+		s_hi += (s_lo < a) ? 1 : 0; \
+	} while (0)
+
+#define UPDATE_EXTEND_STAT(s) \
+	do { \
+		ADD_EXTEND_64(pstats->mac_stx[1].s##_hi, \
+			      pstats->mac_stx[1].s##_lo, \
+			      new->s); \
+	} while (0)
+
+#define UPDATE_EXTEND_TSTAT(s, t) \
+	do { \
+		diff = le32_to_cpu(tclient->s) - le32_to_cpu(old_tclient->s); \
+		old_tclient->s = tclient->s; \
+		ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
+	} while (0)
+
+#define UPDATE_EXTEND_USTAT(s, t) \
+	do { \
+		diff = le32_to_cpu(uclient->s) - le32_to_cpu(old_uclient->s); \
+		old_uclient->s = uclient->s; \
+		ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
+	} while (0)
+
+#define UPDATE_EXTEND_XSTAT(s, t) \
+	do { \
+		diff = le32_to_cpu(xclient->s) - le32_to_cpu(old_xclient->s); \
+		old_xclient->s = xclient->s; \
+		ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
+	} while (0)
+
+/* minuend -= subtrahend */
+#define SUB_64(m_hi, s_hi, m_lo, s_lo) \
+	do { \
+		DIFF_64(m_hi, m_hi, s_hi, m_lo, m_lo, s_lo); \
+	} while (0)
+
+/* minuend[hi:lo] -= subtrahend */
+#define SUB_EXTEND_64(m_hi, m_lo, s) \
+	do { \
+		SUB_64(m_hi, 0, m_lo, s); \
+	} while (0)
+
+#define SUB_EXTEND_USTAT(s, t) \
+	do { \
+		diff = le32_to_cpu(uclient->s) - le32_to_cpu(old_uclient->s); \
+		SUB_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
+	} while (0)
+
+/*
+ * General service functions
+ */
+
+static inline long bnx2x_hilo(u32 *hiref)
+{
+	u32 lo = *(hiref + 1);
+#if (BITS_PER_LONG == 64)
+	u32 hi = *hiref;
+
+	return HILO_U64(hi, lo);
+#else
+	return lo;
+#endif
+}
+
+/*
+ * Init service functions
+ */
+
+
+static void bnx2x_storm_stats_post(struct bnx2x *bp)
+{
+	if (!bp->stats_pending) {
+		struct eth_query_ramrod_data ramrod_data = {0};
+		int i, rc;
+
+		spin_lock_bh(&bp->stats_lock);
+
+		ramrod_data.drv_counter = bp->stats_counter++;
+		ramrod_data.collect_port = bp->port.pmf ? 1 : 0;
+		for_each_queue(bp, i)
+			ramrod_data.ctr_id_vector |= (1 << bp->fp[i].cl_id);
+
+		rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_STAT_QUERY, 0,
+				   ((u32 *)&ramrod_data)[1],
+				   ((u32 *)&ramrod_data)[0], 0);
+		if (rc == 0) {
+			/* stats ramrod has it's own slot on the spq */
+			bp->spq_left++;
+			bp->stats_pending = 1;
+		}
+
+		spin_unlock_bh(&bp->stats_lock);
+	}
+}
+
+static void bnx2x_hw_stats_post(struct bnx2x *bp)
+{
+	struct dmae_command *dmae = &bp->stats_dmae;
+	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+	*stats_comp = DMAE_COMP_VAL;
+	if (CHIP_REV_IS_SLOW(bp))
+		return;
+
+	/* loader */
+	if (bp->executer_idx) {
+		int loader_idx = PMF_DMAE_C(bp);
+
+		memset(dmae, 0, sizeof(struct dmae_command));
+
+		dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+				DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
+				DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+				DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+				DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+				(BP_PORT(bp) ? DMAE_CMD_PORT_1 :
+					       DMAE_CMD_PORT_0) |
+				(BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+		dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, dmae[0]));
+		dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, dmae[0]));
+		dmae->dst_addr_lo = (DMAE_REG_CMD_MEM +
+				     sizeof(struct dmae_command) *
+				     (loader_idx + 1)) >> 2;
+		dmae->dst_addr_hi = 0;
+		dmae->len = sizeof(struct dmae_command) >> 2;
+		if (CHIP_IS_E1(bp))
+			dmae->len--;
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx + 1] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+
+		*stats_comp = 0;
+		bnx2x_post_dmae(bp, dmae, loader_idx);
+
+	} else if (bp->func_stx) {
+		*stats_comp = 0;
+		bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));
+	}
+}
+
+static int bnx2x_stats_comp(struct bnx2x *bp)
+{
+	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+	int cnt = 10;
+
+	might_sleep();
+	while (*stats_comp != DMAE_COMP_VAL) {
+		if (!cnt) {
+			BNX2X_ERR("timeout waiting for stats finished\n");
+			break;
+		}
+		cnt--;
+		msleep(1);
+	}
+	return 1;
+}
+
+/*
+ * Statistics service functions
+ */
+
+static void bnx2x_stats_pmf_update(struct bnx2x *bp)
+{
+	struct dmae_command *dmae;
+	u32 opcode;
+	int loader_idx = PMF_DMAE_C(bp);
+	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+	/* sanity */
+	if (!IS_E1HMF(bp) || !bp->port.pmf || !bp->port.port_stx) {
+		BNX2X_ERR("BUG!\n");
+		return;
+	}
+
+	bp->executer_idx = 0;
+
+	opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+		  DMAE_CMD_C_ENABLE |
+		  DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+		  DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+		  DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+		  (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+		  (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+
+	dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+	dmae->opcode = (opcode | DMAE_CMD_C_DST_GRC);
+	dmae->src_addr_lo = bp->port.port_stx >> 2;
+	dmae->src_addr_hi = 0;
+	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
+	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
+	dmae->len = DMAE_LEN32_RD_MAX;
+	dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+	dmae->comp_addr_hi = 0;
+	dmae->comp_val = 1;
+
+	dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+	dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
+	dmae->src_addr_lo = (bp->port.port_stx >> 2) + DMAE_LEN32_RD_MAX;
+	dmae->src_addr_hi = 0;
+	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats) +
+				   DMAE_LEN32_RD_MAX * 4);
+	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats) +
+				   DMAE_LEN32_RD_MAX * 4);
+	dmae->len = (sizeof(struct host_port_stats) >> 2) - DMAE_LEN32_RD_MAX;
+	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+	dmae->comp_val = DMAE_COMP_VAL;
+
+	*stats_comp = 0;
+	bnx2x_hw_stats_post(bp);
+	bnx2x_stats_comp(bp);
+}
+
+static void bnx2x_port_stats_init(struct bnx2x *bp)
+{
+	struct dmae_command *dmae;
+	int port = BP_PORT(bp);
+	int vn = BP_E1HVN(bp);
+	u32 opcode;
+	int loader_idx = PMF_DMAE_C(bp);
+	u32 mac_addr;
+	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+	/* sanity */
+	if (!bp->link_vars.link_up || !bp->port.pmf) {
+		BNX2X_ERR("BUG!\n");
+		return;
+	}
+
+	bp->executer_idx = 0;
+
+	/* MCP */
+	opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+		  DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
+		  DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+		  DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+		  DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+		  (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+		  (vn << DMAE_CMD_E1HVN_SHIFT));
+
+	if (bp->port.port_stx) {
+
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = opcode;
+		dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
+		dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
+		dmae->dst_addr_lo = bp->port.port_stx >> 2;
+		dmae->dst_addr_hi = 0;
+		dmae->len = sizeof(struct host_port_stats) >> 2;
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+	}
+
+	if (bp->func_stx) {
+
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = opcode;
+		dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
+		dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
+		dmae->dst_addr_lo = bp->func_stx >> 2;
+		dmae->dst_addr_hi = 0;
+		dmae->len = sizeof(struct host_func_stats) >> 2;
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+	}
+
+	/* MAC */
+	opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+		  DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
+		  DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+		  DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+		  DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+		  (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+		  (vn << DMAE_CMD_E1HVN_SHIFT));
+
+	if (bp->link_vars.mac_type == MAC_TYPE_BMAC) {
+
+		mac_addr = (port ? NIG_REG_INGRESS_BMAC1_MEM :
+				   NIG_REG_INGRESS_BMAC0_MEM);
+
+		/* BIGMAC_REGISTER_TX_STAT_GTPKT ..
+		   BIGMAC_REGISTER_TX_STAT_GTBYT */
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = opcode;
+		dmae->src_addr_lo = (mac_addr +
+				     BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2;
+		dmae->src_addr_hi = 0;
+		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats));
+		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats));
+		dmae->len = (8 + BIGMAC_REGISTER_TX_STAT_GTBYT -
+			     BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2;
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+
+		/* BIGMAC_REGISTER_RX_STAT_GR64 ..
+		   BIGMAC_REGISTER_RX_STAT_GRIPJ */
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = opcode;
+		dmae->src_addr_lo = (mac_addr +
+				     BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
+		dmae->src_addr_hi = 0;
+		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
+				offsetof(struct bmac_stats, rx_stat_gr64_lo));
+		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
+				offsetof(struct bmac_stats, rx_stat_gr64_lo));
+		dmae->len = (8 + BIGMAC_REGISTER_RX_STAT_GRIPJ -
+			     BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+
+	} else if (bp->link_vars.mac_type == MAC_TYPE_EMAC) {
+
+		mac_addr = (port ? GRCBASE_EMAC1 : GRCBASE_EMAC0);
+
+		/* EMAC_REG_EMAC_RX_STAT_AC (EMAC_REG_EMAC_RX_STAT_AC_COUNT)*/
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = opcode;
+		dmae->src_addr_lo = (mac_addr +
+				     EMAC_REG_EMAC_RX_STAT_AC) >> 2;
+		dmae->src_addr_hi = 0;
+		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats));
+		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats));
+		dmae->len = EMAC_REG_EMAC_RX_STAT_AC_COUNT;
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+
+		/* EMAC_REG_EMAC_RX_STAT_AC_28 */
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = opcode;
+		dmae->src_addr_lo = (mac_addr +
+				     EMAC_REG_EMAC_RX_STAT_AC_28) >> 2;
+		dmae->src_addr_hi = 0;
+		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
+		     offsetof(struct emac_stats, rx_stat_falsecarriererrors));
+		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
+		     offsetof(struct emac_stats, rx_stat_falsecarriererrors));
+		dmae->len = 1;
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+
+		/* EMAC_REG_EMAC_TX_STAT_AC (EMAC_REG_EMAC_TX_STAT_AC_COUNT)*/
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = opcode;
+		dmae->src_addr_lo = (mac_addr +
+				     EMAC_REG_EMAC_TX_STAT_AC) >> 2;
+		dmae->src_addr_hi = 0;
+		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
+			offsetof(struct emac_stats, tx_stat_ifhcoutoctets));
+		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
+			offsetof(struct emac_stats, tx_stat_ifhcoutoctets));
+		dmae->len = EMAC_REG_EMAC_TX_STAT_AC_COUNT;
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+	}
+
+	/* NIG */
+	dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+	dmae->opcode = opcode;
+	dmae->src_addr_lo = (port ? NIG_REG_STAT1_BRB_DISCARD :
+				    NIG_REG_STAT0_BRB_DISCARD) >> 2;
+	dmae->src_addr_hi = 0;
+	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats));
+	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats));
+	dmae->len = (sizeof(struct nig_stats) - 4*sizeof(u32)) >> 2;
+	dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+	dmae->comp_addr_hi = 0;
+	dmae->comp_val = 1;
+
+	dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+	dmae->opcode = opcode;
+	dmae->src_addr_lo = (port ? NIG_REG_STAT1_EGRESS_MAC_PKT0 :
+				    NIG_REG_STAT0_EGRESS_MAC_PKT0) >> 2;
+	dmae->src_addr_hi = 0;
+	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats) +
+			offsetof(struct nig_stats, egress_mac_pkt0_lo));
+	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats) +
+			offsetof(struct nig_stats, egress_mac_pkt0_lo));
+	dmae->len = (2*sizeof(u32)) >> 2;
+	dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+	dmae->comp_addr_hi = 0;
+	dmae->comp_val = 1;
+
+	dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+	dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+			DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+			DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+			DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+			DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+			(port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+			(vn << DMAE_CMD_E1HVN_SHIFT));
+	dmae->src_addr_lo = (port ? NIG_REG_STAT1_EGRESS_MAC_PKT1 :
+				    NIG_REG_STAT0_EGRESS_MAC_PKT1) >> 2;
+	dmae->src_addr_hi = 0;
+	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats) +
+			offsetof(struct nig_stats, egress_mac_pkt1_lo));
+	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats) +
+			offsetof(struct nig_stats, egress_mac_pkt1_lo));
+	dmae->len = (2*sizeof(u32)) >> 2;
+	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+	dmae->comp_val = DMAE_COMP_VAL;
+
+	*stats_comp = 0;
+}
+
+static void bnx2x_func_stats_init(struct bnx2x *bp)
+{
+	struct dmae_command *dmae = &bp->stats_dmae;
+	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+	/* sanity */
+	if (!bp->func_stx) {
+		BNX2X_ERR("BUG!\n");
+		return;
+	}
+
+	bp->executer_idx = 0;
+	memset(dmae, 0, sizeof(struct dmae_command));
+
+	dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+			DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+			DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+			DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+			DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+			(BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+			(BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+	dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
+	dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
+	dmae->dst_addr_lo = bp->func_stx >> 2;
+	dmae->dst_addr_hi = 0;
+	dmae->len = sizeof(struct host_func_stats) >> 2;
+	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+	dmae->comp_val = DMAE_COMP_VAL;
+
+	*stats_comp = 0;
+}
+
+static void bnx2x_stats_start(struct bnx2x *bp)
+{
+	if (bp->port.pmf)
+		bnx2x_port_stats_init(bp);
+
+	else if (bp->func_stx)
+		bnx2x_func_stats_init(bp);
+
+	bnx2x_hw_stats_post(bp);
+	bnx2x_storm_stats_post(bp);
+}
+
+static void bnx2x_stats_pmf_start(struct bnx2x *bp)
+{
+	bnx2x_stats_comp(bp);
+	bnx2x_stats_pmf_update(bp);
+	bnx2x_stats_start(bp);
+}
+
+static void bnx2x_stats_restart(struct bnx2x *bp)
+{
+	bnx2x_stats_comp(bp);
+	bnx2x_stats_start(bp);
+}
+
+static void bnx2x_bmac_stats_update(struct bnx2x *bp)
+{
+	struct bmac_stats *new = bnx2x_sp(bp, mac_stats.bmac_stats);
+	struct host_port_stats *pstats = bnx2x_sp(bp, port_stats);
+	struct bnx2x_eth_stats *estats = &bp->eth_stats;
+	struct {
+		u32 lo;
+		u32 hi;
+	} diff;
+
+	UPDATE_STAT64(rx_stat_grerb, rx_stat_ifhcinbadoctets);
+	UPDATE_STAT64(rx_stat_grfcs, rx_stat_dot3statsfcserrors);
+	UPDATE_STAT64(rx_stat_grund, rx_stat_etherstatsundersizepkts);
+	UPDATE_STAT64(rx_stat_grovr, rx_stat_dot3statsframestoolong);
+	UPDATE_STAT64(rx_stat_grfrg, rx_stat_etherstatsfragments);
+	UPDATE_STAT64(rx_stat_grjbr, rx_stat_etherstatsjabbers);
+	UPDATE_STAT64(rx_stat_grxcf, rx_stat_maccontrolframesreceived);
+	UPDATE_STAT64(rx_stat_grxpf, rx_stat_xoffstateentered);
+	UPDATE_STAT64(rx_stat_grxpf, rx_stat_bmac_xpf);
+	UPDATE_STAT64(tx_stat_gtxpf, tx_stat_outxoffsent);
+	UPDATE_STAT64(tx_stat_gtxpf, tx_stat_flowcontroldone);
+	UPDATE_STAT64(tx_stat_gt64, tx_stat_etherstatspkts64octets);
+	UPDATE_STAT64(tx_stat_gt127,
+				tx_stat_etherstatspkts65octetsto127octets);
+	UPDATE_STAT64(tx_stat_gt255,
+				tx_stat_etherstatspkts128octetsto255octets);
+	UPDATE_STAT64(tx_stat_gt511,
+				tx_stat_etherstatspkts256octetsto511octets);
+	UPDATE_STAT64(tx_stat_gt1023,
+				tx_stat_etherstatspkts512octetsto1023octets);
+	UPDATE_STAT64(tx_stat_gt1518,
+				tx_stat_etherstatspkts1024octetsto1522octets);
+	UPDATE_STAT64(tx_stat_gt2047, tx_stat_bmac_2047);
+	UPDATE_STAT64(tx_stat_gt4095, tx_stat_bmac_4095);
+	UPDATE_STAT64(tx_stat_gt9216, tx_stat_bmac_9216);
+	UPDATE_STAT64(tx_stat_gt16383, tx_stat_bmac_16383);
+	UPDATE_STAT64(tx_stat_gterr,
+				tx_stat_dot3statsinternalmactransmiterrors);
+	UPDATE_STAT64(tx_stat_gtufl, tx_stat_bmac_ufl);
+
+	estats->pause_frames_received_hi =
+				pstats->mac_stx[1].rx_stat_bmac_xpf_hi;
+	estats->pause_frames_received_lo =
+				pstats->mac_stx[1].rx_stat_bmac_xpf_lo;
+
+	estats->pause_frames_sent_hi =
+				pstats->mac_stx[1].tx_stat_outxoffsent_hi;
+	estats->pause_frames_sent_lo =
+				pstats->mac_stx[1].tx_stat_outxoffsent_lo;
+}
+
+static void bnx2x_emac_stats_update(struct bnx2x *bp)
+{
+	struct emac_stats *new = bnx2x_sp(bp, mac_stats.emac_stats);
+	struct host_port_stats *pstats = bnx2x_sp(bp, port_stats);
+	struct bnx2x_eth_stats *estats = &bp->eth_stats;
+
+	UPDATE_EXTEND_STAT(rx_stat_ifhcinbadoctets);
+	UPDATE_EXTEND_STAT(tx_stat_ifhcoutbadoctets);
+	UPDATE_EXTEND_STAT(rx_stat_dot3statsfcserrors);
+	UPDATE_EXTEND_STAT(rx_stat_dot3statsalignmenterrors);
+	UPDATE_EXTEND_STAT(rx_stat_dot3statscarriersenseerrors);
+	UPDATE_EXTEND_STAT(rx_stat_falsecarriererrors);
+	UPDATE_EXTEND_STAT(rx_stat_etherstatsundersizepkts);
+	UPDATE_EXTEND_STAT(rx_stat_dot3statsframestoolong);
+	UPDATE_EXTEND_STAT(rx_stat_etherstatsfragments);
+	UPDATE_EXTEND_STAT(rx_stat_etherstatsjabbers);
+	UPDATE_EXTEND_STAT(rx_stat_maccontrolframesreceived);
+	UPDATE_EXTEND_STAT(rx_stat_xoffstateentered);
+	UPDATE_EXTEND_STAT(rx_stat_xonpauseframesreceived);
+	UPDATE_EXTEND_STAT(rx_stat_xoffpauseframesreceived);
+	UPDATE_EXTEND_STAT(tx_stat_outxonsent);
+	UPDATE_EXTEND_STAT(tx_stat_outxoffsent);
+	UPDATE_EXTEND_STAT(tx_stat_flowcontroldone);
+	UPDATE_EXTEND_STAT(tx_stat_etherstatscollisions);
+	UPDATE_EXTEND_STAT(tx_stat_dot3statssinglecollisionframes);
+	UPDATE_EXTEND_STAT(tx_stat_dot3statsmultiplecollisionframes);
+	UPDATE_EXTEND_STAT(tx_stat_dot3statsdeferredtransmissions);
+	UPDATE_EXTEND_STAT(tx_stat_dot3statsexcessivecollisions);
+	UPDATE_EXTEND_STAT(tx_stat_dot3statslatecollisions);
+	UPDATE_EXTEND_STAT(tx_stat_etherstatspkts64octets);
+	UPDATE_EXTEND_STAT(tx_stat_etherstatspkts65octetsto127octets);
+	UPDATE_EXTEND_STAT(tx_stat_etherstatspkts128octetsto255octets);
+	UPDATE_EXTEND_STAT(tx_stat_etherstatspkts256octetsto511octets);
+	UPDATE_EXTEND_STAT(tx_stat_etherstatspkts512octetsto1023octets);
+	UPDATE_EXTEND_STAT(tx_stat_etherstatspkts1024octetsto1522octets);
+	UPDATE_EXTEND_STAT(tx_stat_etherstatspktsover1522octets);
+	UPDATE_EXTEND_STAT(tx_stat_dot3statsinternalmactransmiterrors);
+
+	estats->pause_frames_received_hi =
+			pstats->mac_stx[1].rx_stat_xonpauseframesreceived_hi;
+	estats->pause_frames_received_lo =
+			pstats->mac_stx[1].rx_stat_xonpauseframesreceived_lo;
+	ADD_64(estats->pause_frames_received_hi,
+	       pstats->mac_stx[1].rx_stat_xoffpauseframesreceived_hi,
+	       estats->pause_frames_received_lo,
+	       pstats->mac_stx[1].rx_stat_xoffpauseframesreceived_lo);
+
+	estats->pause_frames_sent_hi =
+			pstats->mac_stx[1].tx_stat_outxonsent_hi;
+	estats->pause_frames_sent_lo =
+			pstats->mac_stx[1].tx_stat_outxonsent_lo;
+	ADD_64(estats->pause_frames_sent_hi,
+	       pstats->mac_stx[1].tx_stat_outxoffsent_hi,
+	       estats->pause_frames_sent_lo,
+	       pstats->mac_stx[1].tx_stat_outxoffsent_lo);
+}
+
+static int bnx2x_hw_stats_update(struct bnx2x *bp)
+{
+	struct nig_stats *new = bnx2x_sp(bp, nig_stats);
+	struct nig_stats *old = &(bp->port.old_nig_stats);
+	struct host_port_stats *pstats = bnx2x_sp(bp, port_stats);
+	struct bnx2x_eth_stats *estats = &bp->eth_stats;
+	struct {
+		u32 lo;
+		u32 hi;
+	} diff;
+
+	if (bp->link_vars.mac_type == MAC_TYPE_BMAC)
+		bnx2x_bmac_stats_update(bp);
+
+	else if (bp->link_vars.mac_type == MAC_TYPE_EMAC)
+		bnx2x_emac_stats_update(bp);
+
+	else { /* unreached */
+		BNX2X_ERR("stats updated by DMAE but no MAC active\n");
+		return -1;
+	}
+
+	ADD_EXTEND_64(pstats->brb_drop_hi, pstats->brb_drop_lo,
+		      new->brb_discard - old->brb_discard);
+	ADD_EXTEND_64(estats->brb_truncate_hi, estats->brb_truncate_lo,
+		      new->brb_truncate - old->brb_truncate);
+
+	UPDATE_STAT64_NIG(egress_mac_pkt0,
+					etherstatspkts1024octetsto1522octets);
+	UPDATE_STAT64_NIG(egress_mac_pkt1, etherstatspktsover1522octets);
+
+	memcpy(old, new, sizeof(struct nig_stats));
+
+	memcpy(&(estats->rx_stat_ifhcinbadoctets_hi), &(pstats->mac_stx[1]),
+	       sizeof(struct mac_stx));
+	estats->brb_drop_hi = pstats->brb_drop_hi;
+	estats->brb_drop_lo = pstats->brb_drop_lo;
+
+	pstats->host_port_stats_start = ++pstats->host_port_stats_end;
+
+	if (!BP_NOMCP(bp)) {
+		u32 nig_timer_max =
+			SHMEM_RD(bp, port_mb[BP_PORT(bp)].stat_nig_timer);
+		if (nig_timer_max != estats->nig_timer_max) {
+			estats->nig_timer_max = nig_timer_max;
+			BNX2X_ERR("NIG timer max (%u)\n",
+				  estats->nig_timer_max);
+		}
+	}
+
+	return 0;
+}
+
+static int bnx2x_storm_stats_update(struct bnx2x *bp)
+{
+	struct eth_stats_query *stats = bnx2x_sp(bp, fw_stats);
+	struct tstorm_per_port_stats *tport =
+					&stats->tstorm_common.port_statistics;
+	struct host_func_stats *fstats = bnx2x_sp(bp, func_stats);
+	struct bnx2x_eth_stats *estats = &bp->eth_stats;
+	int i;
+	u16 cur_stats_counter;
+
+	/* Make sure we use the value of the counter
+	 * used for sending the last stats ramrod.
+	 */
+	spin_lock_bh(&bp->stats_lock);
+	cur_stats_counter = bp->stats_counter - 1;
+	spin_unlock_bh(&bp->stats_lock);
+
+	memcpy(&(fstats->total_bytes_received_hi),
+	       &(bnx2x_sp(bp, func_stats_base)->total_bytes_received_hi),
+	       sizeof(struct host_func_stats) - 2*sizeof(u32));
+	estats->error_bytes_received_hi = 0;
+	estats->error_bytes_received_lo = 0;
+	estats->etherstatsoverrsizepkts_hi = 0;
+	estats->etherstatsoverrsizepkts_lo = 0;
+	estats->no_buff_discard_hi = 0;
+	estats->no_buff_discard_lo = 0;
+
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+		int cl_id = fp->cl_id;
+		struct tstorm_per_client_stats *tclient =
+				&stats->tstorm_common.client_statistics[cl_id];
+		struct tstorm_per_client_stats *old_tclient = &fp->old_tclient;
+		struct ustorm_per_client_stats *uclient =
+				&stats->ustorm_common.client_statistics[cl_id];
+		struct ustorm_per_client_stats *old_uclient = &fp->old_uclient;
+		struct xstorm_per_client_stats *xclient =
+				&stats->xstorm_common.client_statistics[cl_id];
+		struct xstorm_per_client_stats *old_xclient = &fp->old_xclient;
+		struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
+		u32 diff;
+
+		/* are storm stats valid? */
+		if (le16_to_cpu(xclient->stats_counter) != cur_stats_counter) {
+			DP(BNX2X_MSG_STATS, "[%d] stats not updated by xstorm"
+			   "  xstorm counter (0x%x) != stats_counter (0x%x)\n",
+			   i, xclient->stats_counter, cur_stats_counter + 1);
+			return -1;
+		}
+		if (le16_to_cpu(tclient->stats_counter) != cur_stats_counter) {
+			DP(BNX2X_MSG_STATS, "[%d] stats not updated by tstorm"
+			   "  tstorm counter (0x%x) != stats_counter (0x%x)\n",
+			   i, tclient->stats_counter, cur_stats_counter + 1);
+			return -2;
+		}
+		if (le16_to_cpu(uclient->stats_counter) != cur_stats_counter) {
+			DP(BNX2X_MSG_STATS, "[%d] stats not updated by ustorm"
+			   "  ustorm counter (0x%x) != stats_counter (0x%x)\n",
+			   i, uclient->stats_counter, cur_stats_counter + 1);
+			return -4;
+		}
+
+		qstats->total_bytes_received_hi =
+			le32_to_cpu(tclient->rcv_broadcast_bytes.hi);
+		qstats->total_bytes_received_lo =
+			le32_to_cpu(tclient->rcv_broadcast_bytes.lo);
+
+		ADD_64(qstats->total_bytes_received_hi,
+		       le32_to_cpu(tclient->rcv_multicast_bytes.hi),
+		       qstats->total_bytes_received_lo,
+		       le32_to_cpu(tclient->rcv_multicast_bytes.lo));
+
+		ADD_64(qstats->total_bytes_received_hi,
+		       le32_to_cpu(tclient->rcv_unicast_bytes.hi),
+		       qstats->total_bytes_received_lo,
+		       le32_to_cpu(tclient->rcv_unicast_bytes.lo));
+
+		SUB_64(qstats->total_bytes_received_hi,
+		       le32_to_cpu(uclient->bcast_no_buff_bytes.hi),
+		       qstats->total_bytes_received_lo,
+		       le32_to_cpu(uclient->bcast_no_buff_bytes.lo));
+
+		SUB_64(qstats->total_bytes_received_hi,
+		       le32_to_cpu(uclient->mcast_no_buff_bytes.hi),
+		       qstats->total_bytes_received_lo,
+		       le32_to_cpu(uclient->mcast_no_buff_bytes.lo));
+
+		SUB_64(qstats->total_bytes_received_hi,
+		       le32_to_cpu(uclient->ucast_no_buff_bytes.hi),
+		       qstats->total_bytes_received_lo,
+		       le32_to_cpu(uclient->ucast_no_buff_bytes.lo));
+
+		qstats->valid_bytes_received_hi =
+					qstats->total_bytes_received_hi;
+		qstats->valid_bytes_received_lo =
+					qstats->total_bytes_received_lo;
+
+		qstats->error_bytes_received_hi =
+				le32_to_cpu(tclient->rcv_error_bytes.hi);
+		qstats->error_bytes_received_lo =
+				le32_to_cpu(tclient->rcv_error_bytes.lo);
+
+		ADD_64(qstats->total_bytes_received_hi,
+		       qstats->error_bytes_received_hi,
+		       qstats->total_bytes_received_lo,
+		       qstats->error_bytes_received_lo);
+
+		UPDATE_EXTEND_TSTAT(rcv_unicast_pkts,
+					total_unicast_packets_received);
+		UPDATE_EXTEND_TSTAT(rcv_multicast_pkts,
+					total_multicast_packets_received);
+		UPDATE_EXTEND_TSTAT(rcv_broadcast_pkts,
+					total_broadcast_packets_received);
+		UPDATE_EXTEND_TSTAT(packets_too_big_discard,
+					etherstatsoverrsizepkts);
+		UPDATE_EXTEND_TSTAT(no_buff_discard, no_buff_discard);
+
+		SUB_EXTEND_USTAT(ucast_no_buff_pkts,
+					total_unicast_packets_received);
+		SUB_EXTEND_USTAT(mcast_no_buff_pkts,
+					total_multicast_packets_received);
+		SUB_EXTEND_USTAT(bcast_no_buff_pkts,
+					total_broadcast_packets_received);
+		UPDATE_EXTEND_USTAT(ucast_no_buff_pkts, no_buff_discard);
+		UPDATE_EXTEND_USTAT(mcast_no_buff_pkts, no_buff_discard);
+		UPDATE_EXTEND_USTAT(bcast_no_buff_pkts, no_buff_discard);
+
+		qstats->total_bytes_transmitted_hi =
+				le32_to_cpu(xclient->unicast_bytes_sent.hi);
+		qstats->total_bytes_transmitted_lo =
+				le32_to_cpu(xclient->unicast_bytes_sent.lo);
+
+		ADD_64(qstats->total_bytes_transmitted_hi,
+		       le32_to_cpu(xclient->multicast_bytes_sent.hi),
+		       qstats->total_bytes_transmitted_lo,
+		       le32_to_cpu(xclient->multicast_bytes_sent.lo));
+
+		ADD_64(qstats->total_bytes_transmitted_hi,
+		       le32_to_cpu(xclient->broadcast_bytes_sent.hi),
+		       qstats->total_bytes_transmitted_lo,
+		       le32_to_cpu(xclient->broadcast_bytes_sent.lo));
+
+		UPDATE_EXTEND_XSTAT(unicast_pkts_sent,
+					total_unicast_packets_transmitted);
+		UPDATE_EXTEND_XSTAT(multicast_pkts_sent,
+					total_multicast_packets_transmitted);
+		UPDATE_EXTEND_XSTAT(broadcast_pkts_sent,
+					total_broadcast_packets_transmitted);
+
+		old_tclient->checksum_discard = tclient->checksum_discard;
+		old_tclient->ttl0_discard = tclient->ttl0_discard;
+
+		ADD_64(fstats->total_bytes_received_hi,
+		       qstats->total_bytes_received_hi,
+		       fstats->total_bytes_received_lo,
+		       qstats->total_bytes_received_lo);
+		ADD_64(fstats->total_bytes_transmitted_hi,
+		       qstats->total_bytes_transmitted_hi,
+		       fstats->total_bytes_transmitted_lo,
+		       qstats->total_bytes_transmitted_lo);
+		ADD_64(fstats->total_unicast_packets_received_hi,
+		       qstats->total_unicast_packets_received_hi,
+		       fstats->total_unicast_packets_received_lo,
+		       qstats->total_unicast_packets_received_lo);
+		ADD_64(fstats->total_multicast_packets_received_hi,
+		       qstats->total_multicast_packets_received_hi,
+		       fstats->total_multicast_packets_received_lo,
+		       qstats->total_multicast_packets_received_lo);
+		ADD_64(fstats->total_broadcast_packets_received_hi,
+		       qstats->total_broadcast_packets_received_hi,
+		       fstats->total_broadcast_packets_received_lo,
+		       qstats->total_broadcast_packets_received_lo);
+		ADD_64(fstats->total_unicast_packets_transmitted_hi,
+		       qstats->total_unicast_packets_transmitted_hi,
+		       fstats->total_unicast_packets_transmitted_lo,
+		       qstats->total_unicast_packets_transmitted_lo);
+		ADD_64(fstats->total_multicast_packets_transmitted_hi,
+		       qstats->total_multicast_packets_transmitted_hi,
+		       fstats->total_multicast_packets_transmitted_lo,
+		       qstats->total_multicast_packets_transmitted_lo);
+		ADD_64(fstats->total_broadcast_packets_transmitted_hi,
+		       qstats->total_broadcast_packets_transmitted_hi,
+		       fstats->total_broadcast_packets_transmitted_lo,
+		       qstats->total_broadcast_packets_transmitted_lo);
+		ADD_64(fstats->valid_bytes_received_hi,
+		       qstats->valid_bytes_received_hi,
+		       fstats->valid_bytes_received_lo,
+		       qstats->valid_bytes_received_lo);
+
+		ADD_64(estats->error_bytes_received_hi,
+		       qstats->error_bytes_received_hi,
+		       estats->error_bytes_received_lo,
+		       qstats->error_bytes_received_lo);
+		ADD_64(estats->etherstatsoverrsizepkts_hi,
+		       qstats->etherstatsoverrsizepkts_hi,
+		       estats->etherstatsoverrsizepkts_lo,
+		       qstats->etherstatsoverrsizepkts_lo);
+		ADD_64(estats->no_buff_discard_hi, qstats->no_buff_discard_hi,
+		       estats->no_buff_discard_lo, qstats->no_buff_discard_lo);
+	}
+
+	ADD_64(fstats->total_bytes_received_hi,
+	       estats->rx_stat_ifhcinbadoctets_hi,
+	       fstats->total_bytes_received_lo,
+	       estats->rx_stat_ifhcinbadoctets_lo);
+
+	memcpy(estats, &(fstats->total_bytes_received_hi),
+	       sizeof(struct host_func_stats) - 2*sizeof(u32));
+
+	ADD_64(estats->etherstatsoverrsizepkts_hi,
+	       estats->rx_stat_dot3statsframestoolong_hi,
+	       estats->etherstatsoverrsizepkts_lo,
+	       estats->rx_stat_dot3statsframestoolong_lo);
+	ADD_64(estats->error_bytes_received_hi,
+	       estats->rx_stat_ifhcinbadoctets_hi,
+	       estats->error_bytes_received_lo,
+	       estats->rx_stat_ifhcinbadoctets_lo);
+
+	if (bp->port.pmf) {
+		estats->mac_filter_discard =
+				le32_to_cpu(tport->mac_filter_discard);
+		estats->xxoverflow_discard =
+				le32_to_cpu(tport->xxoverflow_discard);
+		estats->brb_truncate_discard =
+				le32_to_cpu(tport->brb_truncate_discard);
+		estats->mac_discard = le32_to_cpu(tport->mac_discard);
+	}
+
+	fstats->host_func_stats_start = ++fstats->host_func_stats_end;
+
+	bp->stats_pending = 0;
+
+	return 0;
+}
+
+static void bnx2x_net_stats_update(struct bnx2x *bp)
+{
+	struct bnx2x_eth_stats *estats = &bp->eth_stats;
+	struct net_device_stats *nstats = &bp->dev->stats;
+	int i;
+
+	nstats->rx_packets =
+		bnx2x_hilo(&estats->total_unicast_packets_received_hi) +
+		bnx2x_hilo(&estats->total_multicast_packets_received_hi) +
+		bnx2x_hilo(&estats->total_broadcast_packets_received_hi);
+
+	nstats->tx_packets =
+		bnx2x_hilo(&estats->total_unicast_packets_transmitted_hi) +
+		bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi) +
+		bnx2x_hilo(&estats->total_broadcast_packets_transmitted_hi);
+
+	nstats->rx_bytes = bnx2x_hilo(&estats->total_bytes_received_hi);
+
+	nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi);
+
+	nstats->rx_dropped = estats->mac_discard;
+	for_each_queue(bp, i)
+		nstats->rx_dropped +=
+			le32_to_cpu(bp->fp[i].old_tclient.checksum_discard);
+
+	nstats->tx_dropped = 0;
+
+	nstats->multicast =
+		bnx2x_hilo(&estats->total_multicast_packets_received_hi);
+
+	nstats->collisions =
+		bnx2x_hilo(&estats->tx_stat_etherstatscollisions_hi);
+
+	nstats->rx_length_errors =
+		bnx2x_hilo(&estats->rx_stat_etherstatsundersizepkts_hi) +
+		bnx2x_hilo(&estats->etherstatsoverrsizepkts_hi);
+	nstats->rx_over_errors = bnx2x_hilo(&estats->brb_drop_hi) +
+				 bnx2x_hilo(&estats->brb_truncate_hi);
+	nstats->rx_crc_errors =
+		bnx2x_hilo(&estats->rx_stat_dot3statsfcserrors_hi);
+	nstats->rx_frame_errors =
+		bnx2x_hilo(&estats->rx_stat_dot3statsalignmenterrors_hi);
+	nstats->rx_fifo_errors = bnx2x_hilo(&estats->no_buff_discard_hi);
+	nstats->rx_missed_errors = estats->xxoverflow_discard;
+
+	nstats->rx_errors = nstats->rx_length_errors +
+			    nstats->rx_over_errors +
+			    nstats->rx_crc_errors +
+			    nstats->rx_frame_errors +
+			    nstats->rx_fifo_errors +
+			    nstats->rx_missed_errors;
+
+	nstats->tx_aborted_errors =
+		bnx2x_hilo(&estats->tx_stat_dot3statslatecollisions_hi) +
+		bnx2x_hilo(&estats->tx_stat_dot3statsexcessivecollisions_hi);
+	nstats->tx_carrier_errors =
+		bnx2x_hilo(&estats->rx_stat_dot3statscarriersenseerrors_hi);
+	nstats->tx_fifo_errors = 0;
+	nstats->tx_heartbeat_errors = 0;
+	nstats->tx_window_errors = 0;
+
+	nstats->tx_errors = nstats->tx_aborted_errors +
+			    nstats->tx_carrier_errors +
+	    bnx2x_hilo(&estats->tx_stat_dot3statsinternalmactransmiterrors_hi);
+}
+
+static void bnx2x_drv_stats_update(struct bnx2x *bp)
+{
+	struct bnx2x_eth_stats *estats = &bp->eth_stats;
+	int i;
+
+	estats->driver_xoff = 0;
+	estats->rx_err_discard_pkt = 0;
+	estats->rx_skb_alloc_failed = 0;
+	estats->hw_csum_err = 0;
+	for_each_queue(bp, i) {
+		struct bnx2x_eth_q_stats *qstats = &bp->fp[i].eth_q_stats;
+
+		estats->driver_xoff += qstats->driver_xoff;
+		estats->rx_err_discard_pkt += qstats->rx_err_discard_pkt;
+		estats->rx_skb_alloc_failed += qstats->rx_skb_alloc_failed;
+		estats->hw_csum_err += qstats->hw_csum_err;
+	}
+}
+
+static void bnx2x_stats_update(struct bnx2x *bp)
+{
+	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+	if (*stats_comp != DMAE_COMP_VAL)
+		return;
+
+	if (bp->port.pmf)
+		bnx2x_hw_stats_update(bp);
+
+	if (bnx2x_storm_stats_update(bp) && (bp->stats_pending++ == 3)) {
+		BNX2X_ERR("storm stats were not updated for 3 times\n");
+		bnx2x_panic();
+		return;
+	}
+
+	bnx2x_net_stats_update(bp);
+	bnx2x_drv_stats_update(bp);
+
+	if (netif_msg_timer(bp)) {
+		struct bnx2x_eth_stats *estats = &bp->eth_stats;
+		int i;
+
+		printk(KERN_DEBUG "%s: brb drops %u  brb truncate %u\n",
+		       bp->dev->name,
+		       estats->brb_drop_lo, estats->brb_truncate_lo);
+
+		for_each_queue(bp, i) {
+			struct bnx2x_fastpath *fp = &bp->fp[i];
+			struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
+
+			printk(KERN_DEBUG "%s: rx usage(%4u)  *rx_cons_sb(%u)"
+					  "  rx pkt(%lu)  rx calls(%lu %lu)\n",
+			       fp->name, (le16_to_cpu(*fp->rx_cons_sb) -
+			       fp->rx_comp_cons),
+			       le16_to_cpu(*fp->rx_cons_sb),
+			       bnx2x_hilo(&qstats->
+					  total_unicast_packets_received_hi),
+			       fp->rx_calls, fp->rx_pkt);
+		}
+
+		for_each_queue(bp, i) {
+			struct bnx2x_fastpath *fp = &bp->fp[i];
+			struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
+			struct netdev_queue *txq =
+				netdev_get_tx_queue(bp->dev, i);
+
+			printk(KERN_DEBUG "%s: tx avail(%4u)  *tx_cons_sb(%u)"
+					  "  tx pkt(%lu) tx calls (%lu)"
+					  "  %s (Xoff events %u)\n",
+			       fp->name, bnx2x_tx_avail(fp),
+			       le16_to_cpu(*fp->tx_cons_sb),
+			       bnx2x_hilo(&qstats->
+					  total_unicast_packets_transmitted_hi),
+			       fp->tx_pkt,
+			       (netif_tx_queue_stopped(txq) ? "Xoff" : "Xon"),
+			       qstats->driver_xoff);
+		}
+	}
+
+	bnx2x_hw_stats_post(bp);
+	bnx2x_storm_stats_post(bp);
+}
+
+static void bnx2x_port_stats_stop(struct bnx2x *bp)
+{
+	struct dmae_command *dmae;
+	u32 opcode;
+	int loader_idx = PMF_DMAE_C(bp);
+	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+	bp->executer_idx = 0;
+
+	opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+		  DMAE_CMD_C_ENABLE |
+		  DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+		  DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+		  DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+		  (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+		  (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+
+	if (bp->port.port_stx) {
+
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		if (bp->func_stx)
+			dmae->opcode = (opcode | DMAE_CMD_C_DST_GRC);
+		else
+			dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
+		dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
+		dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
+		dmae->dst_addr_lo = bp->port.port_stx >> 2;
+		dmae->dst_addr_hi = 0;
+		dmae->len = sizeof(struct host_port_stats) >> 2;
+		if (bp->func_stx) {
+			dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+			dmae->comp_addr_hi = 0;
+			dmae->comp_val = 1;
+		} else {
+			dmae->comp_addr_lo =
+				U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+			dmae->comp_addr_hi =
+				U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+			dmae->comp_val = DMAE_COMP_VAL;
+
+			*stats_comp = 0;
+		}
+	}
+
+	if (bp->func_stx) {
+
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
+		dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
+		dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
+		dmae->dst_addr_lo = bp->func_stx >> 2;
+		dmae->dst_addr_hi = 0;
+		dmae->len = sizeof(struct host_func_stats) >> 2;
+		dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+		dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+		dmae->comp_val = DMAE_COMP_VAL;
+
+		*stats_comp = 0;
+	}
+}
+
+static void bnx2x_stats_stop(struct bnx2x *bp)
+{
+	int update = 0;
+
+	bnx2x_stats_comp(bp);
+
+	if (bp->port.pmf)
+		update = (bnx2x_hw_stats_update(bp) == 0);
+
+	update |= (bnx2x_storm_stats_update(bp) == 0);
+
+	if (update) {
+		bnx2x_net_stats_update(bp);
+
+		if (bp->port.pmf)
+			bnx2x_port_stats_stop(bp);
+
+		bnx2x_hw_stats_post(bp);
+		bnx2x_stats_comp(bp);
+	}
+}
+
+static void bnx2x_stats_do_nothing(struct bnx2x *bp)
+{
+}
+
+static const struct {
+	void (*action)(struct bnx2x *bp);
+	enum bnx2x_stats_state next_state;
+} bnx2x_stats_stm[STATS_STATE_MAX][STATS_EVENT_MAX] = {
+/* state	event	*/
+{
+/* DISABLED	PMF	*/ {bnx2x_stats_pmf_update, STATS_STATE_DISABLED},
+/*		LINK_UP	*/ {bnx2x_stats_start,      STATS_STATE_ENABLED},
+/*		UPDATE	*/ {bnx2x_stats_do_nothing, STATS_STATE_DISABLED},
+/*		STOP	*/ {bnx2x_stats_do_nothing, STATS_STATE_DISABLED}
+},
+{
+/* ENABLED	PMF	*/ {bnx2x_stats_pmf_start,  STATS_STATE_ENABLED},
+/*		LINK_UP	*/ {bnx2x_stats_restart,    STATS_STATE_ENABLED},
+/*		UPDATE	*/ {bnx2x_stats_update,     STATS_STATE_ENABLED},
+/*		STOP	*/ {bnx2x_stats_stop,       STATS_STATE_DISABLED}
+}
+};
+
+void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
+{
+	enum bnx2x_stats_state state;
+
+	if (unlikely(bp->panic))
+		return;
+
+	/* Protect a state change flow */
+	spin_lock_bh(&bp->stats_lock);
+	state = bp->stats_state;
+	bp->stats_state = bnx2x_stats_stm[state][event].next_state;
+	spin_unlock_bh(&bp->stats_lock);
+
+	bnx2x_stats_stm[state][event].action(bp);
+
+	if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
+		DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
+		   state, event, bp->stats_state);
+}
+
+static void bnx2x_port_stats_base_init(struct bnx2x *bp)
+{
+	struct dmae_command *dmae;
+	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+	/* sanity */
+	if (!bp->port.pmf || !bp->port.port_stx) {
+		BNX2X_ERR("BUG!\n");
+		return;
+	}
+
+	bp->executer_idx = 0;
+
+	dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+	dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+			DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+			DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+			DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+			DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+			(BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+			(BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+	dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
+	dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
+	dmae->dst_addr_lo = bp->port.port_stx >> 2;
+	dmae->dst_addr_hi = 0;
+	dmae->len = sizeof(struct host_port_stats) >> 2;
+	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+	dmae->comp_val = DMAE_COMP_VAL;
+
+	*stats_comp = 0;
+	bnx2x_hw_stats_post(bp);
+	bnx2x_stats_comp(bp);
+}
+
+static void bnx2x_func_stats_base_init(struct bnx2x *bp)
+{
+	int vn, vn_max = IS_E1HMF(bp) ? E1HVN_MAX : E1VN_MAX;
+	int port = BP_PORT(bp);
+	int func;
+	u32 func_stx;
+
+	/* sanity */
+	if (!bp->port.pmf || !bp->func_stx) {
+		BNX2X_ERR("BUG!\n");
+		return;
+	}
+
+	/* save our func_stx */
+	func_stx = bp->func_stx;
+
+	for (vn = VN_0; vn < vn_max; vn++) {
+		func = 2*vn + port;
+
+		bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param);
+		bnx2x_func_stats_init(bp);
+		bnx2x_hw_stats_post(bp);
+		bnx2x_stats_comp(bp);
+	}
+
+	/* restore our func_stx */
+	bp->func_stx = func_stx;
+}
+
+static void bnx2x_func_stats_base_update(struct bnx2x *bp)
+{
+	struct dmae_command *dmae = &bp->stats_dmae;
+	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+	/* sanity */
+	if (!bp->func_stx) {
+		BNX2X_ERR("BUG!\n");
+		return;
+	}
+
+	bp->executer_idx = 0;
+	memset(dmae, 0, sizeof(struct dmae_command));
+
+	dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+			DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+			DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+			DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+			DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+			(BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+			(BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+	dmae->src_addr_lo = bp->func_stx >> 2;
+	dmae->src_addr_hi = 0;
+	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats_base));
+	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats_base));
+	dmae->len = sizeof(struct host_func_stats) >> 2;
+	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+	dmae->comp_val = DMAE_COMP_VAL;
+
+	*stats_comp = 0;
+	bnx2x_hw_stats_post(bp);
+	bnx2x_stats_comp(bp);
+}
+
+void bnx2x_stats_init(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	int func = BP_FUNC(bp);
+	int i;
+
+	bp->stats_pending = 0;
+	bp->executer_idx = 0;
+	bp->stats_counter = 0;
+
+	/* port and func stats for management */
+	if (!BP_NOMCP(bp)) {
+		bp->port.port_stx = SHMEM_RD(bp, port_mb[port].port_stx);
+		bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param);
+
+	} else {
+		bp->port.port_stx = 0;
+		bp->func_stx = 0;
+	}
+	DP(BNX2X_MSG_STATS, "port_stx 0x%x  func_stx 0x%x\n",
+	   bp->port.port_stx, bp->func_stx);
+
+	/* port stats */
+	memset(&(bp->port.old_nig_stats), 0, sizeof(struct nig_stats));
+	bp->port.old_nig_stats.brb_discard =
+			REG_RD(bp, NIG_REG_STAT0_BRB_DISCARD + port*0x38);
+	bp->port.old_nig_stats.brb_truncate =
+			REG_RD(bp, NIG_REG_STAT0_BRB_TRUNCATE + port*0x38);
+	REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT0 + port*0x50,
+		    &(bp->port.old_nig_stats.egress_mac_pkt0_lo), 2);
+	REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT1 + port*0x50,
+		    &(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2);
+
+	/* function stats */
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		memset(&fp->old_tclient, 0,
+		       sizeof(struct tstorm_per_client_stats));
+		memset(&fp->old_uclient, 0,
+		       sizeof(struct ustorm_per_client_stats));
+		memset(&fp->old_xclient, 0,
+		       sizeof(struct xstorm_per_client_stats));
+		memset(&fp->eth_q_stats, 0, sizeof(struct bnx2x_eth_q_stats));
+	}
+
+	memset(&bp->dev->stats, 0, sizeof(struct net_device_stats));
+	memset(&bp->eth_stats, 0, sizeof(struct bnx2x_eth_stats));
+
+	bp->stats_state = STATS_STATE_DISABLED;
+
+	if (bp->port.pmf) {
+		if (bp->port.port_stx)
+			bnx2x_port_stats_base_init(bp);
+
+		if (bp->func_stx)
+			bnx2x_func_stats_base_init(bp);
+
+	} else if (bp->func_stx)
+		bnx2x_func_stats_base_update(bp);
+}
diff --git a/drivers/net/bnx2x/bnx2x_stats.h b/drivers/net/bnx2x/bnx2x_stats.h
new file mode 100644
index 0000000..38a4e90
--- /dev/null
+++ b/drivers/net/bnx2x/bnx2x_stats.h
@@ -0,0 +1,239 @@
+/* bnx2x_stats.h: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007-2010 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
+ * Based on code from Michael Chan's bnx2 driver
+ */
+
+#ifndef BNX2X_STATS_H
+#define BNX2X_STATS_H
+
+#include <linux/types.h>
+
+struct bnx2x_eth_q_stats {
+	u32 total_bytes_received_hi;
+	u32 total_bytes_received_lo;
+	u32 total_bytes_transmitted_hi;
+	u32 total_bytes_transmitted_lo;
+	u32 total_unicast_packets_received_hi;
+	u32 total_unicast_packets_received_lo;
+	u32 total_multicast_packets_received_hi;
+	u32 total_multicast_packets_received_lo;
+	u32 total_broadcast_packets_received_hi;
+	u32 total_broadcast_packets_received_lo;
+	u32 total_unicast_packets_transmitted_hi;
+	u32 total_unicast_packets_transmitted_lo;
+	u32 total_multicast_packets_transmitted_hi;
+	u32 total_multicast_packets_transmitted_lo;
+	u32 total_broadcast_packets_transmitted_hi;
+	u32 total_broadcast_packets_transmitted_lo;
+	u32 valid_bytes_received_hi;
+	u32 valid_bytes_received_lo;
+
+	u32 error_bytes_received_hi;
+	u32 error_bytes_received_lo;
+	u32 etherstatsoverrsizepkts_hi;
+	u32 etherstatsoverrsizepkts_lo;
+	u32 no_buff_discard_hi;
+	u32 no_buff_discard_lo;
+
+	u32 driver_xoff;
+	u32 rx_err_discard_pkt;
+	u32 rx_skb_alloc_failed;
+	u32 hw_csum_err;
+};
+
+#define BNX2X_NUM_Q_STATS		13
+#define Q_STATS_OFFSET32(stat_name) \
+			(offsetof(struct bnx2x_eth_q_stats, stat_name) / 4)
+
+struct nig_stats {
+	u32 brb_discard;
+	u32 brb_packet;
+	u32 brb_truncate;
+	u32 flow_ctrl_discard;
+	u32 flow_ctrl_octets;
+	u32 flow_ctrl_packet;
+	u32 mng_discard;
+	u32 mng_octet_inp;
+	u32 mng_octet_out;
+	u32 mng_packet_inp;
+	u32 mng_packet_out;
+	u32 pbf_octets;
+	u32 pbf_packet;
+	u32 safc_inp;
+	u32 egress_mac_pkt0_lo;
+	u32 egress_mac_pkt0_hi;
+	u32 egress_mac_pkt1_lo;
+	u32 egress_mac_pkt1_hi;
+};
+
+
+enum bnx2x_stats_event {
+	STATS_EVENT_PMF = 0,
+	STATS_EVENT_LINK_UP,
+	STATS_EVENT_UPDATE,
+	STATS_EVENT_STOP,
+	STATS_EVENT_MAX
+};
+
+enum bnx2x_stats_state {
+	STATS_STATE_DISABLED = 0,
+	STATS_STATE_ENABLED,
+	STATS_STATE_MAX
+};
+
+struct bnx2x_eth_stats {
+	u32 total_bytes_received_hi;
+	u32 total_bytes_received_lo;
+	u32 total_bytes_transmitted_hi;
+	u32 total_bytes_transmitted_lo;
+	u32 total_unicast_packets_received_hi;
+	u32 total_unicast_packets_received_lo;
+	u32 total_multicast_packets_received_hi;
+	u32 total_multicast_packets_received_lo;
+	u32 total_broadcast_packets_received_hi;
+	u32 total_broadcast_packets_received_lo;
+	u32 total_unicast_packets_transmitted_hi;
+	u32 total_unicast_packets_transmitted_lo;
+	u32 total_multicast_packets_transmitted_hi;
+	u32 total_multicast_packets_transmitted_lo;
+	u32 total_broadcast_packets_transmitted_hi;
+	u32 total_broadcast_packets_transmitted_lo;
+	u32 valid_bytes_received_hi;
+	u32 valid_bytes_received_lo;
+
+	u32 error_bytes_received_hi;
+	u32 error_bytes_received_lo;
+	u32 etherstatsoverrsizepkts_hi;
+	u32 etherstatsoverrsizepkts_lo;
+	u32 no_buff_discard_hi;
+	u32 no_buff_discard_lo;
+
+	u32 rx_stat_ifhcinbadoctets_hi;
+	u32 rx_stat_ifhcinbadoctets_lo;
+	u32 tx_stat_ifhcoutbadoctets_hi;
+	u32 tx_stat_ifhcoutbadoctets_lo;
+	u32 rx_stat_dot3statsfcserrors_hi;
+	u32 rx_stat_dot3statsfcserrors_lo;
+	u32 rx_stat_dot3statsalignmenterrors_hi;
+	u32 rx_stat_dot3statsalignmenterrors_lo;
+	u32 rx_stat_dot3statscarriersenseerrors_hi;
+	u32 rx_stat_dot3statscarriersenseerrors_lo;
+	u32 rx_stat_falsecarriererrors_hi;
+	u32 rx_stat_falsecarriererrors_lo;
+	u32 rx_stat_etherstatsundersizepkts_hi;
+	u32 rx_stat_etherstatsundersizepkts_lo;
+	u32 rx_stat_dot3statsframestoolong_hi;
+	u32 rx_stat_dot3statsframestoolong_lo;
+	u32 rx_stat_etherstatsfragments_hi;
+	u32 rx_stat_etherstatsfragments_lo;
+	u32 rx_stat_etherstatsjabbers_hi;
+	u32 rx_stat_etherstatsjabbers_lo;
+	u32 rx_stat_maccontrolframesreceived_hi;
+	u32 rx_stat_maccontrolframesreceived_lo;
+	u32 rx_stat_bmac_xpf_hi;
+	u32 rx_stat_bmac_xpf_lo;
+	u32 rx_stat_bmac_xcf_hi;
+	u32 rx_stat_bmac_xcf_lo;
+	u32 rx_stat_xoffstateentered_hi;
+	u32 rx_stat_xoffstateentered_lo;
+	u32 rx_stat_xonpauseframesreceived_hi;
+	u32 rx_stat_xonpauseframesreceived_lo;
+	u32 rx_stat_xoffpauseframesreceived_hi;
+	u32 rx_stat_xoffpauseframesreceived_lo;
+	u32 tx_stat_outxonsent_hi;
+	u32 tx_stat_outxonsent_lo;
+	u32 tx_stat_outxoffsent_hi;
+	u32 tx_stat_outxoffsent_lo;
+	u32 tx_stat_flowcontroldone_hi;
+	u32 tx_stat_flowcontroldone_lo;
+	u32 tx_stat_etherstatscollisions_hi;
+	u32 tx_stat_etherstatscollisions_lo;
+	u32 tx_stat_dot3statssinglecollisionframes_hi;
+	u32 tx_stat_dot3statssinglecollisionframes_lo;
+	u32 tx_stat_dot3statsmultiplecollisionframes_hi;
+	u32 tx_stat_dot3statsmultiplecollisionframes_lo;
+	u32 tx_stat_dot3statsdeferredtransmissions_hi;
+	u32 tx_stat_dot3statsdeferredtransmissions_lo;
+	u32 tx_stat_dot3statsexcessivecollisions_hi;
+	u32 tx_stat_dot3statsexcessivecollisions_lo;
+	u32 tx_stat_dot3statslatecollisions_hi;
+	u32 tx_stat_dot3statslatecollisions_lo;
+	u32 tx_stat_etherstatspkts64octets_hi;
+	u32 tx_stat_etherstatspkts64octets_lo;
+	u32 tx_stat_etherstatspkts65octetsto127octets_hi;
+	u32 tx_stat_etherstatspkts65octetsto127octets_lo;
+	u32 tx_stat_etherstatspkts128octetsto255octets_hi;
+	u32 tx_stat_etherstatspkts128octetsto255octets_lo;
+	u32 tx_stat_etherstatspkts256octetsto511octets_hi;
+	u32 tx_stat_etherstatspkts256octetsto511octets_lo;
+	u32 tx_stat_etherstatspkts512octetsto1023octets_hi;
+	u32 tx_stat_etherstatspkts512octetsto1023octets_lo;
+	u32 tx_stat_etherstatspkts1024octetsto1522octets_hi;
+	u32 tx_stat_etherstatspkts1024octetsto1522octets_lo;
+	u32 tx_stat_etherstatspktsover1522octets_hi;
+	u32 tx_stat_etherstatspktsover1522octets_lo;
+	u32 tx_stat_bmac_2047_hi;
+	u32 tx_stat_bmac_2047_lo;
+	u32 tx_stat_bmac_4095_hi;
+	u32 tx_stat_bmac_4095_lo;
+	u32 tx_stat_bmac_9216_hi;
+	u32 tx_stat_bmac_9216_lo;
+	u32 tx_stat_bmac_16383_hi;
+	u32 tx_stat_bmac_16383_lo;
+	u32 tx_stat_dot3statsinternalmactransmiterrors_hi;
+	u32 tx_stat_dot3statsinternalmactransmiterrors_lo;
+	u32 tx_stat_bmac_ufl_hi;
+	u32 tx_stat_bmac_ufl_lo;
+
+	u32 pause_frames_received_hi;
+	u32 pause_frames_received_lo;
+	u32 pause_frames_sent_hi;
+	u32 pause_frames_sent_lo;
+
+	u32 etherstatspkts1024octetsto1522octets_hi;
+	u32 etherstatspkts1024octetsto1522octets_lo;
+	u32 etherstatspktsover1522octets_hi;
+	u32 etherstatspktsover1522octets_lo;
+
+	u32 brb_drop_hi;
+	u32 brb_drop_lo;
+	u32 brb_truncate_hi;
+	u32 brb_truncate_lo;
+
+	u32 mac_filter_discard;
+	u32 xxoverflow_discard;
+	u32 brb_truncate_discard;
+	u32 mac_discard;
+
+	u32 driver_xoff;
+	u32 rx_err_discard_pkt;
+	u32 rx_skb_alloc_failed;
+	u32 hw_csum_err;
+
+	u32 nig_timer_max;
+};
+
+#define BNX2X_NUM_STATS			43
+#define STATS_OFFSET32(stat_name) \
+			(offsetof(struct bnx2x_eth_stats, stat_name) / 4)
+
+/* Forward declaration */
+struct bnx2x;
+
+
+void bnx2x_stats_init(struct bnx2x *bp);
+
+extern const u32 dmae_reg_go_c[];
+extern int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
+			 u32 data_hi, u32 data_lo, int common);
+
+
+#endif /* BNX2X_STATS_H */
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
deleted file mode 100644
index 46167c0..0000000
--- a/drivers/net/bnx2x_main.c
+++ /dev/null
@@ -1,13928 +0,0 @@
-/* bnx2x_main.c: Broadcom Everest network driver.
- *
- * Copyright (c) 2007-2010 Broadcom Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation.
- *
- * Maintained by: Eilon Greenstein <eilong@broadcom.com>
- * Written by: Eliezer Tamir
- * Based on code from Michael Chan's bnx2 driver
- * UDP CSUM errata workaround by Arik Gendelman
- * Slowpath and fastpath rework by Vladislav Zolotarov
- * Statistics and Link management by Yitchak Gertner
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/device.h>  /* for dev_info() */
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/dma-mapping.h>
-#include <linux/bitops.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <asm/byteorder.h>
-#include <linux/time.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/if_vlan.h>
-#include <net/ip.h>
-#include <net/tcp.h>
-#include <net/checksum.h>
-#include <net/ip6_checksum.h>
-#include <linux/workqueue.h>
-#include <linux/crc32.h>
-#include <linux/crc32c.h>
-#include <linux/prefetch.h>
-#include <linux/zlib.h>
-#include <linux/io.h>
-#include <linux/stringify.h>
-
-
-#include "bnx2x.h"
-#include "bnx2x_init.h"
-#include "bnx2x_init_ops.h"
-#include "bnx2x_dump.h"
-
-#define DRV_MODULE_VERSION	"1.52.53-2"
-#define DRV_MODULE_RELDATE	"2010/21/07"
-#define BNX2X_BC_VER		0x040200
-
-#include <linux/firmware.h>
-#include "bnx2x_fw_file_hdr.h"
-/* FW files */
-#define FW_FILE_VERSION					\
-	__stringify(BCM_5710_FW_MAJOR_VERSION) "."	\
-	__stringify(BCM_5710_FW_MINOR_VERSION) "."	\
-	__stringify(BCM_5710_FW_REVISION_VERSION) "."	\
-	__stringify(BCM_5710_FW_ENGINEERING_VERSION)
-#define FW_FILE_NAME_E1		"bnx2x-e1-" FW_FILE_VERSION ".fw"
-#define FW_FILE_NAME_E1H	"bnx2x-e1h-" FW_FILE_VERSION ".fw"
-
-/* Time in jiffies before concluding the transmitter is hung */
-#define TX_TIMEOUT		(5*HZ)
-
-static char version[] __devinitdata =
-	"Broadcom NetXtreme II 5771x 10Gigabit Ethernet Driver "
-	DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
-
-MODULE_AUTHOR("Eliezer Tamir");
-MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710/57711/57711E Driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_MODULE_VERSION);
-MODULE_FIRMWARE(FW_FILE_NAME_E1);
-MODULE_FIRMWARE(FW_FILE_NAME_E1H);
-
-static int multi_mode = 1;
-module_param(multi_mode, int, 0);
-MODULE_PARM_DESC(multi_mode, " Multi queue mode "
-			     "(0 Disable; 1 Enable (default))");
-
-static int num_queues;
-module_param(num_queues, int, 0);
-MODULE_PARM_DESC(num_queues, " Number of queues for multi_mode=1"
-				" (default is as a number of CPUs)");
-
-static int disable_tpa;
-module_param(disable_tpa, int, 0);
-MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature");
-
-static int int_mode;
-module_param(int_mode, int, 0);
-MODULE_PARM_DESC(int_mode, " Force interrupt mode other then MSI-X "
-				"(1 INT#x; 2 MSI)");
-
-static int dropless_fc;
-module_param(dropless_fc, int, 0);
-MODULE_PARM_DESC(dropless_fc, " Pause on exhausted host ring");
-
-static int poll;
-module_param(poll, int, 0);
-MODULE_PARM_DESC(poll, " Use polling (for debug)");
-
-static int mrrs = -1;
-module_param(mrrs, int, 0);
-MODULE_PARM_DESC(mrrs, " Force Max Read Req Size (0..3) (for debug)");
-
-static int debug;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, " Default debug msglevel");
-
-static int load_count[3]; /* 0-common, 1-port0, 2-port1 */
-
-static struct workqueue_struct *bnx2x_wq;
-
-enum bnx2x_board_type {
-	BCM57710 = 0,
-	BCM57711 = 1,
-	BCM57711E = 2,
-};
-
-/* indexed by board_type, above */
-static struct {
-	char *name;
-} board_info[] __devinitdata = {
-	{ "Broadcom NetXtreme II BCM57710 XGb" },
-	{ "Broadcom NetXtreme II BCM57711 XGb" },
-	{ "Broadcom NetXtreme II BCM57711E XGb" }
-};
-
-
-static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = {
-	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 },
-	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 },
-	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E },
-	{ 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl);
-
-/****************************************************************************
-* General service functions
-****************************************************************************/
-
-/* used only at init
- * locking is done by mcp
- */
-void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val)
-{
-	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
-	pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val);
-	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
-			       PCICFG_VENDOR_ID_OFFSET);
-}
-
-static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr)
-{
-	u32 val;
-
-	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
-	pci_read_config_dword(bp->pdev, PCICFG_GRC_DATA, &val);
-	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
-			       PCICFG_VENDOR_ID_OFFSET);
-
-	return val;
-}
-
-static const u32 dmae_reg_go_c[] = {
-	DMAE_REG_GO_C0, DMAE_REG_GO_C1, DMAE_REG_GO_C2, DMAE_REG_GO_C3,
-	DMAE_REG_GO_C4, DMAE_REG_GO_C5, DMAE_REG_GO_C6, DMAE_REG_GO_C7,
-	DMAE_REG_GO_C8, DMAE_REG_GO_C9, DMAE_REG_GO_C10, DMAE_REG_GO_C11,
-	DMAE_REG_GO_C12, DMAE_REG_GO_C13, DMAE_REG_GO_C14, DMAE_REG_GO_C15
-};
-
-/* copy command into DMAE command memory and set DMAE command go */
-static void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae,
-			    int idx)
-{
-	u32 cmd_offset;
-	int i;
-
-	cmd_offset = (DMAE_REG_CMD_MEM + sizeof(struct dmae_command) * idx);
-	for (i = 0; i < (sizeof(struct dmae_command)/4); i++) {
-		REG_WR(bp, cmd_offset + i*4, *(((u32 *)dmae) + i));
-
-		DP(BNX2X_MSG_OFF, "DMAE cmd[%d].%d (0x%08x) : 0x%08x\n",
-		   idx, i, cmd_offset + i*4, *(((u32 *)dmae) + i));
-	}
-	REG_WR(bp, dmae_reg_go_c[idx], 1);
-}
-
-void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
-		      u32 len32)
-{
-	struct dmae_command dmae;
-	u32 *wb_comp = bnx2x_sp(bp, wb_comp);
-	int cnt = 200;
-
-	if (!bp->dmae_ready) {
-		u32 *data = bnx2x_sp(bp, wb_data[0]);
-
-		DP(BNX2X_MSG_OFF, "DMAE is not ready (dst_addr %08x  len32 %d)"
-		   "  using indirect\n", dst_addr, len32);
-		bnx2x_init_ind_wr(bp, dst_addr, data, len32);
-		return;
-	}
-
-	memset(&dmae, 0, sizeof(struct dmae_command));
-
-	dmae.opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
-		       DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
-		       DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
-		       DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
-		       DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
-		       (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
-		       (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
-	dmae.src_addr_lo = U64_LO(dma_addr);
-	dmae.src_addr_hi = U64_HI(dma_addr);
-	dmae.dst_addr_lo = dst_addr >> 2;
-	dmae.dst_addr_hi = 0;
-	dmae.len = len32;
-	dmae.comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
-	dmae.comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
-	dmae.comp_val = DMAE_COMP_VAL;
-
-	DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n"
-	   DP_LEVEL "src_addr  [%x:%08x]  len [%d *4]  "
-		    "dst_addr [%x:%08x (%08x)]\n"
-	   DP_LEVEL "comp_addr [%x:%08x]  comp_val 0x%08x\n",
-	   dmae.opcode, dmae.src_addr_hi, dmae.src_addr_lo,
-	   dmae.len, dmae.dst_addr_hi, dmae.dst_addr_lo, dst_addr,
-	   dmae.comp_addr_hi, dmae.comp_addr_lo, dmae.comp_val);
-	DP(BNX2X_MSG_OFF, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n",
-	   bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
-	   bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
-
-	mutex_lock(&bp->dmae_mutex);
-
-	*wb_comp = 0;
-
-	bnx2x_post_dmae(bp, &dmae, INIT_DMAE_C(bp));
-
-	udelay(5);
-
-	while (*wb_comp != DMAE_COMP_VAL) {
-		DP(BNX2X_MSG_OFF, "wb_comp 0x%08x\n", *wb_comp);
-
-		if (!cnt) {
-			BNX2X_ERR("DMAE timeout!\n");
-			break;
-		}
-		cnt--;
-		/* adjust delay for emulation/FPGA */
-		if (CHIP_REV_IS_SLOW(bp))
-			msleep(100);
-		else
-			udelay(5);
-	}
-
-	mutex_unlock(&bp->dmae_mutex);
-}
-
-void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
-{
-	struct dmae_command dmae;
-	u32 *wb_comp = bnx2x_sp(bp, wb_comp);
-	int cnt = 200;
-
-	if (!bp->dmae_ready) {
-		u32 *data = bnx2x_sp(bp, wb_data[0]);
-		int i;
-
-		DP(BNX2X_MSG_OFF, "DMAE is not ready (src_addr %08x  len32 %d)"
-		   "  using indirect\n", src_addr, len32);
-		for (i = 0; i < len32; i++)
-			data[i] = bnx2x_reg_rd_ind(bp, src_addr + i*4);
-		return;
-	}
-
-	memset(&dmae, 0, sizeof(struct dmae_command));
-
-	dmae.opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
-		       DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
-		       DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
-		       DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
-		       DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
-		       (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
-		       (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
-	dmae.src_addr_lo = src_addr >> 2;
-	dmae.src_addr_hi = 0;
-	dmae.dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data));
-	dmae.dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data));
-	dmae.len = len32;
-	dmae.comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
-	dmae.comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
-	dmae.comp_val = DMAE_COMP_VAL;
-
-	DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n"
-	   DP_LEVEL "src_addr  [%x:%08x]  len [%d *4]  "
-		    "dst_addr [%x:%08x (%08x)]\n"
-	   DP_LEVEL "comp_addr [%x:%08x]  comp_val 0x%08x\n",
-	   dmae.opcode, dmae.src_addr_hi, dmae.src_addr_lo,
-	   dmae.len, dmae.dst_addr_hi, dmae.dst_addr_lo, src_addr,
-	   dmae.comp_addr_hi, dmae.comp_addr_lo, dmae.comp_val);
-
-	mutex_lock(&bp->dmae_mutex);
-
-	memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4);
-	*wb_comp = 0;
-
-	bnx2x_post_dmae(bp, &dmae, INIT_DMAE_C(bp));
-
-	udelay(5);
-
-	while (*wb_comp != DMAE_COMP_VAL) {
-
-		if (!cnt) {
-			BNX2X_ERR("DMAE timeout!\n");
-			break;
-		}
-		cnt--;
-		/* adjust delay for emulation/FPGA */
-		if (CHIP_REV_IS_SLOW(bp))
-			msleep(100);
-		else
-			udelay(5);
-	}
-	DP(BNX2X_MSG_OFF, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n",
-	   bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
-	   bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
-
-	mutex_unlock(&bp->dmae_mutex);
-}
-
-void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
-			       u32 addr, u32 len)
-{
-	int dmae_wr_max = DMAE_LEN32_WR_MAX(bp);
-	int offset = 0;
-
-	while (len > dmae_wr_max) {
-		bnx2x_write_dmae(bp, phys_addr + offset,
-				 addr + offset, dmae_wr_max);
-		offset += dmae_wr_max * 4;
-		len -= dmae_wr_max;
-	}
-
-	bnx2x_write_dmae(bp, phys_addr + offset, addr + offset, len);
-}
-
-/* used only for slowpath so not inlined */
-static void bnx2x_wb_wr(struct bnx2x *bp, int reg, u32 val_hi, u32 val_lo)
-{
-	u32 wb_write[2];
-
-	wb_write[0] = val_hi;
-	wb_write[1] = val_lo;
-	REG_WR_DMAE(bp, reg, wb_write, 2);
-}
-
-#ifdef USE_WB_RD
-static u64 bnx2x_wb_rd(struct bnx2x *bp, int reg)
-{
-	u32 wb_data[2];
-
-	REG_RD_DMAE(bp, reg, wb_data, 2);
-
-	return HILO_U64(wb_data[0], wb_data[1]);
-}
-#endif
-
-static int bnx2x_mc_assert(struct bnx2x *bp)
-{
-	char last_idx;
-	int i, rc = 0;
-	u32 row0, row1, row2, row3;
-
-	/* XSTORM */
-	last_idx = REG_RD8(bp, BAR_XSTRORM_INTMEM +
-			   XSTORM_ASSERT_LIST_INDEX_OFFSET);
-	if (last_idx)
-		BNX2X_ERR("XSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
-
-	/* print the asserts */
-	for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
-
-		row0 = REG_RD(bp, BAR_XSTRORM_INTMEM +
-			      XSTORM_ASSERT_LIST_OFFSET(i));
-		row1 = REG_RD(bp, BAR_XSTRORM_INTMEM +
-			      XSTORM_ASSERT_LIST_OFFSET(i) + 4);
-		row2 = REG_RD(bp, BAR_XSTRORM_INTMEM +
-			      XSTORM_ASSERT_LIST_OFFSET(i) + 8);
-		row3 = REG_RD(bp, BAR_XSTRORM_INTMEM +
-			      XSTORM_ASSERT_LIST_OFFSET(i) + 12);
-
-		if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
-			BNX2X_ERR("XSTORM_ASSERT_INDEX 0x%x = 0x%08x"
-				  " 0x%08x 0x%08x 0x%08x\n",
-				  i, row3, row2, row1, row0);
-			rc++;
-		} else {
-			break;
-		}
-	}
-
-	/* TSTORM */
-	last_idx = REG_RD8(bp, BAR_TSTRORM_INTMEM +
-			   TSTORM_ASSERT_LIST_INDEX_OFFSET);
-	if (last_idx)
-		BNX2X_ERR("TSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
-
-	/* print the asserts */
-	for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
-
-		row0 = REG_RD(bp, BAR_TSTRORM_INTMEM +
-			      TSTORM_ASSERT_LIST_OFFSET(i));
-		row1 = REG_RD(bp, BAR_TSTRORM_INTMEM +
-			      TSTORM_ASSERT_LIST_OFFSET(i) + 4);
-		row2 = REG_RD(bp, BAR_TSTRORM_INTMEM +
-			      TSTORM_ASSERT_LIST_OFFSET(i) + 8);
-		row3 = REG_RD(bp, BAR_TSTRORM_INTMEM +
-			      TSTORM_ASSERT_LIST_OFFSET(i) + 12);
-
-		if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
-			BNX2X_ERR("TSTORM_ASSERT_INDEX 0x%x = 0x%08x"
-				  " 0x%08x 0x%08x 0x%08x\n",
-				  i, row3, row2, row1, row0);
-			rc++;
-		} else {
-			break;
-		}
-	}
-
-	/* CSTORM */
-	last_idx = REG_RD8(bp, BAR_CSTRORM_INTMEM +
-			   CSTORM_ASSERT_LIST_INDEX_OFFSET);
-	if (last_idx)
-		BNX2X_ERR("CSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
-
-	/* print the asserts */
-	for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
-
-		row0 = REG_RD(bp, BAR_CSTRORM_INTMEM +
-			      CSTORM_ASSERT_LIST_OFFSET(i));
-		row1 = REG_RD(bp, BAR_CSTRORM_INTMEM +
-			      CSTORM_ASSERT_LIST_OFFSET(i) + 4);
-		row2 = REG_RD(bp, BAR_CSTRORM_INTMEM +
-			      CSTORM_ASSERT_LIST_OFFSET(i) + 8);
-		row3 = REG_RD(bp, BAR_CSTRORM_INTMEM +
-			      CSTORM_ASSERT_LIST_OFFSET(i) + 12);
-
-		if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
-			BNX2X_ERR("CSTORM_ASSERT_INDEX 0x%x = 0x%08x"
-				  " 0x%08x 0x%08x 0x%08x\n",
-				  i, row3, row2, row1, row0);
-			rc++;
-		} else {
-			break;
-		}
-	}
-
-	/* USTORM */
-	last_idx = REG_RD8(bp, BAR_USTRORM_INTMEM +
-			   USTORM_ASSERT_LIST_INDEX_OFFSET);
-	if (last_idx)
-		BNX2X_ERR("USTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
-
-	/* print the asserts */
-	for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
-
-		row0 = REG_RD(bp, BAR_USTRORM_INTMEM +
-			      USTORM_ASSERT_LIST_OFFSET(i));
-		row1 = REG_RD(bp, BAR_USTRORM_INTMEM +
-			      USTORM_ASSERT_LIST_OFFSET(i) + 4);
-		row2 = REG_RD(bp, BAR_USTRORM_INTMEM +
-			      USTORM_ASSERT_LIST_OFFSET(i) + 8);
-		row3 = REG_RD(bp, BAR_USTRORM_INTMEM +
-			      USTORM_ASSERT_LIST_OFFSET(i) + 12);
-
-		if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
-			BNX2X_ERR("USTORM_ASSERT_INDEX 0x%x = 0x%08x"
-				  " 0x%08x 0x%08x 0x%08x\n",
-				  i, row3, row2, row1, row0);
-			rc++;
-		} else {
-			break;
-		}
-	}
-
-	return rc;
-}
-
-static void bnx2x_fw_dump(struct bnx2x *bp)
-{
-	u32 addr;
-	u32 mark, offset;
-	__be32 data[9];
-	int word;
-
-	if (BP_NOMCP(bp)) {
-		BNX2X_ERR("NO MCP - can not dump\n");
-		return;
-	}
-
-	addr = bp->common.shmem_base - 0x0800 + 4;
-	mark = REG_RD(bp, addr);
-	mark = MCP_REG_MCPR_SCRATCH + ((mark + 0x3) & ~0x3) - 0x08000000;
-	pr_err("begin fw dump (mark 0x%x)\n", mark);
-
-	pr_err("");
-	for (offset = mark; offset <= bp->common.shmem_base; offset += 0x8*4) {
-		for (word = 0; word < 8; word++)
-			data[word] = htonl(REG_RD(bp, offset + 4*word));
-		data[8] = 0x0;
-		pr_cont("%s", (char *)data);
-	}
-	for (offset = addr + 4; offset <= mark; offset += 0x8*4) {
-		for (word = 0; word < 8; word++)
-			data[word] = htonl(REG_RD(bp, offset + 4*word));
-		data[8] = 0x0;
-		pr_cont("%s", (char *)data);
-	}
-	pr_err("end of fw dump\n");
-}
-
-static void bnx2x_panic_dump(struct bnx2x *bp)
-{
-	int i;
-	u16 j, start, end;
-
-	bp->stats_state = STATS_STATE_DISABLED;
-	DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");
-
-	BNX2X_ERR("begin crash dump -----------------\n");
-
-	/* Indices */
-	/* Common */
-	BNX2X_ERR("def_c_idx(0x%x)  def_u_idx(0x%x)  def_x_idx(0x%x)"
-		  "  def_t_idx(0x%x)  def_att_idx(0x%x)  attn_state(0x%x)"
-		  "  spq_prod_idx(0x%x)\n",
-		  bp->def_c_idx, bp->def_u_idx, bp->def_x_idx, bp->def_t_idx,
-		  bp->def_att_idx, bp->attn_state, bp->spq_prod_idx);
-
-	/* Rx */
-	for_each_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-
-		BNX2X_ERR("fp%d: rx_bd_prod(0x%x)  rx_bd_cons(0x%x)"
-			  "  *rx_bd_cons_sb(0x%x)  rx_comp_prod(0x%x)"
-			  "  rx_comp_cons(0x%x)  *rx_cons_sb(0x%x)\n",
-			  i, fp->rx_bd_prod, fp->rx_bd_cons,
-			  le16_to_cpu(*fp->rx_bd_cons_sb), fp->rx_comp_prod,
-			  fp->rx_comp_cons, le16_to_cpu(*fp->rx_cons_sb));
-		BNX2X_ERR("     rx_sge_prod(0x%x)  last_max_sge(0x%x)"
-			  "  fp_u_idx(0x%x) *sb_u_idx(0x%x)\n",
-			  fp->rx_sge_prod, fp->last_max_sge,
-			  le16_to_cpu(fp->fp_u_idx),
-			  fp->status_blk->u_status_block.status_block_index);
-	}
-
-	/* Tx */
-	for_each_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-
-		BNX2X_ERR("fp%d: tx_pkt_prod(0x%x)  tx_pkt_cons(0x%x)"
-			  "  tx_bd_prod(0x%x)  tx_bd_cons(0x%x)"
-			  "  *tx_cons_sb(0x%x)\n",
-			  i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod,
-			  fp->tx_bd_cons, le16_to_cpu(*fp->tx_cons_sb));
-		BNX2X_ERR("     fp_c_idx(0x%x)  *sb_c_idx(0x%x)"
-			  "  tx_db_prod(0x%x)\n", le16_to_cpu(fp->fp_c_idx),
-			  fp->status_blk->c_status_block.status_block_index,
-			  fp->tx_db.data.prod);
-	}
-
-	/* Rings */
-	/* Rx */
-	for_each_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-
-		start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10);
-		end = RX_BD(le16_to_cpu(*fp->rx_cons_sb) + 503);
-		for (j = start; j != end; j = RX_BD(j + 1)) {
-			u32 *rx_bd = (u32 *)&fp->rx_desc_ring[j];
-			struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j];
-
-			BNX2X_ERR("fp%d: rx_bd[%x]=[%x:%x]  sw_bd=[%p]\n",
-				  i, j, rx_bd[1], rx_bd[0], sw_bd->skb);
-		}
-
-		start = RX_SGE(fp->rx_sge_prod);
-		end = RX_SGE(fp->last_max_sge);
-		for (j = start; j != end; j = RX_SGE(j + 1)) {
-			u32 *rx_sge = (u32 *)&fp->rx_sge_ring[j];
-			struct sw_rx_page *sw_page = &fp->rx_page_ring[j];
-
-			BNX2X_ERR("fp%d: rx_sge[%x]=[%x:%x]  sw_page=[%p]\n",
-				  i, j, rx_sge[1], rx_sge[0], sw_page->page);
-		}
-
-		start = RCQ_BD(fp->rx_comp_cons - 10);
-		end = RCQ_BD(fp->rx_comp_cons + 503);
-		for (j = start; j != end; j = RCQ_BD(j + 1)) {
-			u32 *cqe = (u32 *)&fp->rx_comp_ring[j];
-
-			BNX2X_ERR("fp%d: cqe[%x]=[%x:%x:%x:%x]\n",
-				  i, j, cqe[0], cqe[1], cqe[2], cqe[3]);
-		}
-	}
-
-	/* Tx */
-	for_each_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-
-		start = TX_BD(le16_to_cpu(*fp->tx_cons_sb) - 10);
-		end = TX_BD(le16_to_cpu(*fp->tx_cons_sb) + 245);
-		for (j = start; j != end; j = TX_BD(j + 1)) {
-			struct sw_tx_bd *sw_bd = &fp->tx_buf_ring[j];
-
-			BNX2X_ERR("fp%d: packet[%x]=[%p,%x]\n",
-				  i, j, sw_bd->skb, sw_bd->first_bd);
-		}
-
-		start = TX_BD(fp->tx_bd_cons - 10);
-		end = TX_BD(fp->tx_bd_cons + 254);
-		for (j = start; j != end; j = TX_BD(j + 1)) {
-			u32 *tx_bd = (u32 *)&fp->tx_desc_ring[j];
-
-			BNX2X_ERR("fp%d: tx_bd[%x]=[%x:%x:%x:%x]\n",
-				  i, j, tx_bd[0], tx_bd[1], tx_bd[2], tx_bd[3]);
-		}
-	}
-
-	bnx2x_fw_dump(bp);
-	bnx2x_mc_assert(bp);
-	BNX2X_ERR("end crash dump -----------------\n");
-}
-
-static void bnx2x_int_enable(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
-	u32 val = REG_RD(bp, addr);
-	int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
-	int msi = (bp->flags & USING_MSI_FLAG) ? 1 : 0;
-
-	if (msix) {
-		val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
-			 HC_CONFIG_0_REG_INT_LINE_EN_0);
-		val |= (HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
-			HC_CONFIG_0_REG_ATTN_BIT_EN_0);
-	} else if (msi) {
-		val &= ~HC_CONFIG_0_REG_INT_LINE_EN_0;
-		val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
-			HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
-			HC_CONFIG_0_REG_ATTN_BIT_EN_0);
-	} else {
-		val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
-			HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
-			HC_CONFIG_0_REG_INT_LINE_EN_0 |
-			HC_CONFIG_0_REG_ATTN_BIT_EN_0);
-
-		DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)\n",
-		   val, port, addr);
-
-		REG_WR(bp, addr, val);
-
-		val &= ~HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0;
-	}
-
-	DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)  mode %s\n",
-	   val, port, addr, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
-
-	REG_WR(bp, addr, val);
-	/*
-	 * Ensure that HC_CONFIG is written before leading/trailing edge config
-	 */
-	mmiowb();
-	barrier();
-
-	if (CHIP_IS_E1H(bp)) {
-		/* init leading/trailing edge */
-		if (IS_E1HMF(bp)) {
-			val = (0xee0f | (1 << (BP_E1HVN(bp) + 4)));
-			if (bp->port.pmf)
-				/* enable nig and gpio3 attention */
-				val |= 0x1100;
-		} else
-			val = 0xffff;
-
-		REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
-		REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
-	}
-
-	/* Make sure that interrupts are indeed enabled from here on */
-	mmiowb();
-}
-
-static void bnx2x_int_disable(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
-	u32 val = REG_RD(bp, addr);
-
-	val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
-		 HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
-		 HC_CONFIG_0_REG_INT_LINE_EN_0 |
-		 HC_CONFIG_0_REG_ATTN_BIT_EN_0);
-
-	DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)\n",
-	   val, port, addr);
-
-	/* flush all outstanding writes */
-	mmiowb();
-
-	REG_WR(bp, addr, val);
-	if (REG_RD(bp, addr) != val)
-		BNX2X_ERR("BUG! proper val not read from IGU!\n");
-}
-
-static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
-{
-	int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
-	int i, offset;
-
-	/* disable interrupt handling */
-	atomic_inc(&bp->intr_sem);
-	smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
-
-	if (disable_hw)
-		/* prevent the HW from sending interrupts */
-		bnx2x_int_disable(bp);
-
-	/* make sure all ISRs are done */
-	if (msix) {
-		synchronize_irq(bp->msix_table[0].vector);
-		offset = 1;
-#ifdef BCM_CNIC
-		offset++;
-#endif
-		for_each_queue(bp, i)
-			synchronize_irq(bp->msix_table[i + offset].vector);
-	} else
-		synchronize_irq(bp->pdev->irq);
-
-	/* make sure sp_task is not running */
-	cancel_delayed_work(&bp->sp_task);
-	flush_workqueue(bnx2x_wq);
-}
-
-/* fast path */
-
-/*
- * General service functions
- */
-
-/* Return true if succeeded to acquire the lock */
-static bool bnx2x_trylock_hw_lock(struct bnx2x *bp, u32 resource)
-{
-	u32 lock_status;
-	u32 resource_bit = (1 << resource);
-	int func = BP_FUNC(bp);
-	u32 hw_lock_control_reg;
-
-	DP(NETIF_MSG_HW, "Trying to take a lock on resource %d\n", resource);
-
-	/* Validating that the resource is within range */
-	if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
-		DP(NETIF_MSG_HW,
-		   "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
-		   resource, HW_LOCK_MAX_RESOURCE_VALUE);
-		return -EINVAL;
-	}
-
-	if (func <= 5)
-		hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
-	else
-		hw_lock_control_reg =
-				(MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
-
-	/* Try to acquire the lock */
-	REG_WR(bp, hw_lock_control_reg + 4, resource_bit);
-	lock_status = REG_RD(bp, hw_lock_control_reg);
-	if (lock_status & resource_bit)
-		return true;
-
-	DP(NETIF_MSG_HW, "Failed to get a lock on resource %d\n", resource);
-	return false;
-}
-
-static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
-				u8 storm, u16 index, u8 op, u8 update)
-{
-	u32 hc_addr = (HC_REG_COMMAND_REG + BP_PORT(bp)*32 +
-		       COMMAND_REG_INT_ACK);
-	struct igu_ack_register igu_ack;
-
-	igu_ack.status_block_index = index;
-	igu_ack.sb_id_and_flags =
-			((sb_id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) |
-			 (storm << IGU_ACK_REGISTER_STORM_ID_SHIFT) |
-			 (update << IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT) |
-			 (op << IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT));
-
-	DP(BNX2X_MSG_OFF, "write 0x%08x to HC addr 0x%x\n",
-	   (*(u32 *)&igu_ack), hc_addr);
-	REG_WR(bp, hc_addr, (*(u32 *)&igu_ack));
-
-	/* Make sure that ACK is written */
-	mmiowb();
-	barrier();
-}
-
-static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
-{
-	struct host_status_block *fpsb = fp->status_blk;
-
-	barrier(); /* status block is written to by the chip */
-	fp->fp_c_idx = fpsb->c_status_block.status_block_index;
-	fp->fp_u_idx = fpsb->u_status_block.status_block_index;
-}
-
-static u16 bnx2x_ack_int(struct bnx2x *bp)
-{
-	u32 hc_addr = (HC_REG_COMMAND_REG + BP_PORT(bp)*32 +
-		       COMMAND_REG_SIMD_MASK);
-	u32 result = REG_RD(bp, hc_addr);
-
-	DP(BNX2X_MSG_OFF, "read 0x%08x from HC addr 0x%x\n",
-	   result, hc_addr);
-
-	return result;
-}
-
-
-/*
- * fast path service functions
- */
-
-static inline int bnx2x_has_tx_work_unload(struct bnx2x_fastpath *fp)
-{
-	/* Tell compiler that consumer and producer can change */
-	barrier();
-	return (fp->tx_pkt_prod != fp->tx_pkt_cons);
-}
-
-/* free skb in the packet ring at pos idx
- * return idx of last bd freed
- */
-static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp,
-			     u16 idx)
-{
-	struct sw_tx_bd *tx_buf = &fp->tx_buf_ring[idx];
-	struct eth_tx_start_bd *tx_start_bd;
-	struct eth_tx_bd *tx_data_bd;
-	struct sk_buff *skb = tx_buf->skb;
-	u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons;
-	int nbd;
-
-	/* prefetch skb end pointer to speedup dev_kfree_skb() */
-	prefetch(&skb->end);
-
-	DP(BNX2X_MSG_OFF, "pkt_idx %d  buff @(%p)->skb %p\n",
-	   idx, tx_buf, skb);
-
-	/* unmap first bd */
-	DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx);
-	tx_start_bd = &fp->tx_desc_ring[bd_idx].start_bd;
-	dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd),
-			 BD_UNMAP_LEN(tx_start_bd), PCI_DMA_TODEVICE);
-
-	nbd = le16_to_cpu(tx_start_bd->nbd) - 1;
-#ifdef BNX2X_STOP_ON_ERROR
-	if ((nbd - 1) > (MAX_SKB_FRAGS + 2)) {
-		BNX2X_ERR("BAD nbd!\n");
-		bnx2x_panic();
-	}
-#endif
-	new_cons = nbd + tx_buf->first_bd;
-
-	/* Get the next bd */
-	bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
-
-	/* Skip a parse bd... */
-	--nbd;
-	bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
-
-	/* ...and the TSO split header bd since they have no mapping */
-	if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) {
-		--nbd;
-		bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
-	}
-
-	/* now free frags */
-	while (nbd > 0) {
-
-		DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx);
-		tx_data_bd = &fp->tx_desc_ring[bd_idx].reg_bd;
-		dma_unmap_page(&bp->pdev->dev, BD_UNMAP_ADDR(tx_data_bd),
-			       BD_UNMAP_LEN(tx_data_bd), DMA_TO_DEVICE);
-		if (--nbd)
-			bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
-	}
-
-	/* release skb */
-	WARN_ON(!skb);
-	dev_kfree_skb(skb);
-	tx_buf->first_bd = 0;
-	tx_buf->skb = NULL;
-
-	return new_cons;
-}
-
-static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp)
-{
-	s16 used;
-	u16 prod;
-	u16 cons;
-
-	prod = fp->tx_bd_prod;
-	cons = fp->tx_bd_cons;
-
-	/* NUM_TX_RINGS = number of "next-page" entries
-	   It will be used as a threshold */
-	used = SUB_S16(prod, cons) + (s16)NUM_TX_RINGS;
-
-#ifdef BNX2X_STOP_ON_ERROR
-	WARN_ON(used < 0);
-	WARN_ON(used > fp->bp->tx_ring_size);
-	WARN_ON((fp->bp->tx_ring_size - used) > MAX_TX_AVAIL);
-#endif
-
-	return (s16)(fp->bp->tx_ring_size) - used;
-}
-
-static inline int bnx2x_has_tx_work(struct bnx2x_fastpath *fp)
-{
-	u16 hw_cons;
-
-	/* Tell compiler that status block fields can change */
-	barrier();
-	hw_cons = le16_to_cpu(*fp->tx_cons_sb);
-	return hw_cons != fp->tx_pkt_cons;
-}
-
-static int bnx2x_tx_int(struct bnx2x_fastpath *fp)
-{
-	struct bnx2x *bp = fp->bp;
-	struct netdev_queue *txq;
-	u16 hw_cons, sw_cons, bd_cons = fp->tx_bd_cons;
-
-#ifdef BNX2X_STOP_ON_ERROR
-	if (unlikely(bp->panic))
-		return -1;
-#endif
-
-	txq = netdev_get_tx_queue(bp->dev, fp->index);
-	hw_cons = le16_to_cpu(*fp->tx_cons_sb);
-	sw_cons = fp->tx_pkt_cons;
-
-	while (sw_cons != hw_cons) {
-		u16 pkt_cons;
-
-		pkt_cons = TX_BD(sw_cons);
-
-		/* prefetch(bp->tx_buf_ring[pkt_cons].skb); */
-
-		DP(NETIF_MSG_TX_DONE, "hw_cons %u  sw_cons %u  pkt_cons %u\n",
-		   hw_cons, sw_cons, pkt_cons);
-
-/*		if (NEXT_TX_IDX(sw_cons) != hw_cons) {
-			rmb();
-			prefetch(fp->tx_buf_ring[NEXT_TX_IDX(sw_cons)].skb);
-		}
-*/
-		bd_cons = bnx2x_free_tx_pkt(bp, fp, pkt_cons);
-		sw_cons++;
-	}
-
-	fp->tx_pkt_cons = sw_cons;
-	fp->tx_bd_cons = bd_cons;
-
-	/* Need to make the tx_bd_cons update visible to start_xmit()
-	 * before checking for netif_tx_queue_stopped().  Without the
-	 * memory barrier, there is a small possibility that
-	 * start_xmit() will miss it and cause the queue to be stopped
-	 * forever.
-	 */
-	smp_mb();
-
-	/* TBD need a thresh? */
-	if (unlikely(netif_tx_queue_stopped(txq))) {
-		/* Taking tx_lock() is needed to prevent reenabling the queue
-		 * while it's empty. This could have happen if rx_action() gets
-		 * suspended in bnx2x_tx_int() after the condition before
-		 * netif_tx_wake_queue(), while tx_action (bnx2x_start_xmit()):
-		 *
-		 * stops the queue->sees fresh tx_bd_cons->releases the queue->
-		 * sends some packets consuming the whole queue again->
-		 * stops the queue
-		 */
-
-		__netif_tx_lock(txq, smp_processor_id());
-
-		if ((netif_tx_queue_stopped(txq)) &&
-		    (bp->state == BNX2X_STATE_OPEN) &&
-		    (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3))
-			netif_tx_wake_queue(txq);
-
-		__netif_tx_unlock(txq);
-	}
-	return 0;
-}
-
-#ifdef BCM_CNIC
-static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid);
-#endif
-
-static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
-			   union eth_rx_cqe *rr_cqe)
-{
-	struct bnx2x *bp = fp->bp;
-	int cid = SW_CID(rr_cqe->ramrod_cqe.conn_and_cmd_data);
-	int command = CQE_CMD(rr_cqe->ramrod_cqe.conn_and_cmd_data);
-
-	DP(BNX2X_MSG_SP,
-	   "fp %d  cid %d  got ramrod #%d  state is %x  type is %d\n",
-	   fp->index, cid, command, bp->state,
-	   rr_cqe->ramrod_cqe.ramrod_type);
-
-	bp->spq_left++;
-
-	if (fp->index) {
-		switch (command | fp->state) {
-		case (RAMROD_CMD_ID_ETH_CLIENT_SETUP |
-						BNX2X_FP_STATE_OPENING):
-			DP(NETIF_MSG_IFUP, "got MULTI[%d] setup ramrod\n",
-			   cid);
-			fp->state = BNX2X_FP_STATE_OPEN;
-			break;
-
-		case (RAMROD_CMD_ID_ETH_HALT | BNX2X_FP_STATE_HALTING):
-			DP(NETIF_MSG_IFDOWN, "got MULTI[%d] halt ramrod\n",
-			   cid);
-			fp->state = BNX2X_FP_STATE_HALTED;
-			break;
-
-		default:
-			BNX2X_ERR("unexpected MC reply (%d)  "
-				  "fp[%d] state is %x\n",
-				  command, fp->index, fp->state);
-			break;
-		}
-		mb(); /* force bnx2x_wait_ramrod() to see the change */
-		return;
-	}
-
-	switch (command | bp->state) {
-	case (RAMROD_CMD_ID_ETH_PORT_SETUP | BNX2X_STATE_OPENING_WAIT4_PORT):
-		DP(NETIF_MSG_IFUP, "got setup ramrod\n");
-		bp->state = BNX2X_STATE_OPEN;
-		break;
-
-	case (RAMROD_CMD_ID_ETH_HALT | BNX2X_STATE_CLOSING_WAIT4_HALT):
-		DP(NETIF_MSG_IFDOWN, "got halt ramrod\n");
-		bp->state = BNX2X_STATE_CLOSING_WAIT4_DELETE;
-		fp->state = BNX2X_FP_STATE_HALTED;
-		break;
-
-	case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_CLOSING_WAIT4_HALT):
-		DP(NETIF_MSG_IFDOWN, "got delete ramrod for MULTI[%d]\n", cid);
-		bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_CLOSED;
-		break;
-
-#ifdef BCM_CNIC
-	case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_OPEN):
-		DP(NETIF_MSG_IFDOWN, "got delete ramrod for CID %d\n", cid);
-		bnx2x_cnic_cfc_comp(bp, cid);
-		break;
-#endif
-
-	case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_OPEN):
-	case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_DIAG):
-		DP(NETIF_MSG_IFUP, "got set mac ramrod\n");
-		bp->set_mac_pending--;
-		smp_wmb();
-		break;
-
-	case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT):
-		DP(NETIF_MSG_IFDOWN, "got (un)set mac ramrod\n");
-		bp->set_mac_pending--;
-		smp_wmb();
-		break;
-
-	default:
-		BNX2X_ERR("unexpected MC reply (%d)  bp->state is %x\n",
-			  command, bp->state);
-		break;
-	}
-	mb(); /* force bnx2x_wait_ramrod() to see the change */
-}
-
-static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
-				     struct bnx2x_fastpath *fp, u16 index)
-{
-	struct sw_rx_page *sw_buf = &fp->rx_page_ring[index];
-	struct page *page = sw_buf->page;
-	struct eth_rx_sge *sge = &fp->rx_sge_ring[index];
-
-	/* Skip "next page" elements */
-	if (!page)
-		return;
-
-	dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping),
-		       SGE_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE);
-	__free_pages(page, PAGES_PER_SGE_SHIFT);
-
-	sw_buf->page = NULL;
-	sge->addr_hi = 0;
-	sge->addr_lo = 0;
-}
-
-static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp,
-					   struct bnx2x_fastpath *fp, int last)
-{
-	int i;
-
-	for (i = 0; i < last; i++)
-		bnx2x_free_rx_sge(bp, fp, i);
-}
-
-static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp,
-				     struct bnx2x_fastpath *fp, u16 index)
-{
-	struct page *page = alloc_pages(GFP_ATOMIC, PAGES_PER_SGE_SHIFT);
-	struct sw_rx_page *sw_buf = &fp->rx_page_ring[index];
-	struct eth_rx_sge *sge = &fp->rx_sge_ring[index];
-	dma_addr_t mapping;
-
-	if (unlikely(page == NULL))
-		return -ENOMEM;
-
-	mapping = dma_map_page(&bp->pdev->dev, page, 0,
-			       SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
-	if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
-		__free_pages(page, PAGES_PER_SGE_SHIFT);
-		return -ENOMEM;
-	}
-
-	sw_buf->page = page;
-	dma_unmap_addr_set(sw_buf, mapping, mapping);
-
-	sge->addr_hi = cpu_to_le32(U64_HI(mapping));
-	sge->addr_lo = cpu_to_le32(U64_LO(mapping));
-
-	return 0;
-}
-
-static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
-				     struct bnx2x_fastpath *fp, u16 index)
-{
-	struct sk_buff *skb;
-	struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index];
-	struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index];
-	dma_addr_t mapping;
-
-	skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
-	if (unlikely(skb == NULL))
-		return -ENOMEM;
-
-	mapping = dma_map_single(&bp->pdev->dev, skb->data, bp->rx_buf_size,
-				 DMA_FROM_DEVICE);
-	if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
-		dev_kfree_skb(skb);
-		return -ENOMEM;
-	}
-
-	rx_buf->skb = skb;
-	dma_unmap_addr_set(rx_buf, mapping, mapping);
-
-	rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
-	rx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
-
-	return 0;
-}
-
-/* note that we are not allocating a new skb,
- * we are just moving one from cons to prod
- * we are not creating a new mapping,
- * so there is no need to check for dma_mapping_error().
- */
-static void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp,
-			       struct sk_buff *skb, u16 cons, u16 prod)
-{
-	struct bnx2x *bp = fp->bp;
-	struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons];
-	struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod];
-	struct eth_rx_bd *cons_bd = &fp->rx_desc_ring[cons];
-	struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod];
-
-	dma_sync_single_for_device(&bp->pdev->dev,
-				   dma_unmap_addr(cons_rx_buf, mapping),
-				   RX_COPY_THRESH, DMA_FROM_DEVICE);
-
-	prod_rx_buf->skb = cons_rx_buf->skb;
-	dma_unmap_addr_set(prod_rx_buf, mapping,
-			   dma_unmap_addr(cons_rx_buf, mapping));
-	*prod_bd = *cons_bd;
-}
-
-static inline void bnx2x_update_last_max_sge(struct bnx2x_fastpath *fp,
-					     u16 idx)
-{
-	u16 last_max = fp->last_max_sge;
-
-	if (SUB_S16(idx, last_max) > 0)
-		fp->last_max_sge = idx;
-}
-
-static void bnx2x_clear_sge_mask_next_elems(struct bnx2x_fastpath *fp)
-{
-	int i, j;
-
-	for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
-		int idx = RX_SGE_CNT * i - 1;
-
-		for (j = 0; j < 2; j++) {
-			SGE_MASK_CLEAR_BIT(fp, idx);
-			idx--;
-		}
-	}
-}
-
-static void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp,
-				  struct eth_fast_path_rx_cqe *fp_cqe)
-{
-	struct bnx2x *bp = fp->bp;
-	u16 sge_len = SGE_PAGE_ALIGN(le16_to_cpu(fp_cqe->pkt_len) -
-				     le16_to_cpu(fp_cqe->len_on_bd)) >>
-		      SGE_PAGE_SHIFT;
-	u16 last_max, last_elem, first_elem;
-	u16 delta = 0;
-	u16 i;
-
-	if (!sge_len)
-		return;
-
-	/* First mark all used pages */
-	for (i = 0; i < sge_len; i++)
-		SGE_MASK_CLEAR_BIT(fp, RX_SGE(le16_to_cpu(fp_cqe->sgl[i])));
-
-	DP(NETIF_MSG_RX_STATUS, "fp_cqe->sgl[%d] = %d\n",
-	   sge_len - 1, le16_to_cpu(fp_cqe->sgl[sge_len - 1]));
-
-	/* Here we assume that the last SGE index is the biggest */
-	prefetch((void *)(fp->sge_mask));
-	bnx2x_update_last_max_sge(fp, le16_to_cpu(fp_cqe->sgl[sge_len - 1]));
-
-	last_max = RX_SGE(fp->last_max_sge);
-	last_elem = last_max >> RX_SGE_MASK_ELEM_SHIFT;
-	first_elem = RX_SGE(fp->rx_sge_prod) >> RX_SGE_MASK_ELEM_SHIFT;
-
-	/* If ring is not full */
-	if (last_elem + 1 != first_elem)
-		last_elem++;
-
-	/* Now update the prod */
-	for (i = first_elem; i != last_elem; i = NEXT_SGE_MASK_ELEM(i)) {
-		if (likely(fp->sge_mask[i]))
-			break;
-
-		fp->sge_mask[i] = RX_SGE_MASK_ELEM_ONE_MASK;
-		delta += RX_SGE_MASK_ELEM_SZ;
-	}
-
-	if (delta > 0) {
-		fp->rx_sge_prod += delta;
-		/* clear page-end entries */
-		bnx2x_clear_sge_mask_next_elems(fp);
-	}
-
-	DP(NETIF_MSG_RX_STATUS,
-	   "fp->last_max_sge = %d  fp->rx_sge_prod = %d\n",
-	   fp->last_max_sge, fp->rx_sge_prod);
-}
-
-static inline void bnx2x_init_sge_ring_bit_mask(struct bnx2x_fastpath *fp)
-{
-	/* Set the mask to all 1-s: it's faster to compare to 0 than to 0xf-s */
-	memset(fp->sge_mask, 0xff,
-	       (NUM_RX_SGE >> RX_SGE_MASK_ELEM_SHIFT)*sizeof(u64));
-
-	/* Clear the two last indices in the page to 1:
-	   these are the indices that correspond to the "next" element,
-	   hence will never be indicated and should be removed from
-	   the calculations. */
-	bnx2x_clear_sge_mask_next_elems(fp);
-}
-
-static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
-			    struct sk_buff *skb, u16 cons, u16 prod)
-{
-	struct bnx2x *bp = fp->bp;
-	struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons];
-	struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod];
-	struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod];
-	dma_addr_t mapping;
-
-	/* move empty skb from pool to prod and map it */
-	prod_rx_buf->skb = fp->tpa_pool[queue].skb;
-	mapping = dma_map_single(&bp->pdev->dev, fp->tpa_pool[queue].skb->data,
-				 bp->rx_buf_size, DMA_FROM_DEVICE);
-	dma_unmap_addr_set(prod_rx_buf, mapping, mapping);
-
-	/* move partial skb from cons to pool (don't unmap yet) */
-	fp->tpa_pool[queue] = *cons_rx_buf;
-
-	/* mark bin state as start - print error if current state != stop */
-	if (fp->tpa_state[queue] != BNX2X_TPA_STOP)
-		BNX2X_ERR("start of bin not in stop [%d]\n", queue);
-
-	fp->tpa_state[queue] = BNX2X_TPA_START;
-
-	/* point prod_bd to new skb */
-	prod_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
-	prod_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
-
-#ifdef BNX2X_STOP_ON_ERROR
-	fp->tpa_queue_used |= (1 << queue);
-#ifdef _ASM_GENERIC_INT_L64_H
-	DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%lx\n",
-#else
-	DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%llx\n",
-#endif
-	   fp->tpa_queue_used);
-#endif
-}
-
-static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
-			       struct sk_buff *skb,
-			       struct eth_fast_path_rx_cqe *fp_cqe,
-			       u16 cqe_idx)
-{
-	struct sw_rx_page *rx_pg, old_rx_pg;
-	u16 len_on_bd = le16_to_cpu(fp_cqe->len_on_bd);
-	u32 i, frag_len, frag_size, pages;
-	int err;
-	int j;
-
-	frag_size = le16_to_cpu(fp_cqe->pkt_len) - len_on_bd;
-	pages = SGE_PAGE_ALIGN(frag_size) >> SGE_PAGE_SHIFT;
-
-	/* This is needed in order to enable forwarding support */
-	if (frag_size)
-		skb_shinfo(skb)->gso_size = min((u32)SGE_PAGE_SIZE,
-					       max(frag_size, (u32)len_on_bd));
-
-#ifdef BNX2X_STOP_ON_ERROR
-	if (pages > min_t(u32, 8, MAX_SKB_FRAGS)*SGE_PAGE_SIZE*PAGES_PER_SGE) {
-		BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n",
-			  pages, cqe_idx);
-		BNX2X_ERR("fp_cqe->pkt_len = %d  fp_cqe->len_on_bd = %d\n",
-			  fp_cqe->pkt_len, len_on_bd);
-		bnx2x_panic();
-		return -EINVAL;
-	}
-#endif
-
-	/* Run through the SGL and compose the fragmented skb */
-	for (i = 0, j = 0; i < pages; i += PAGES_PER_SGE, j++) {
-		u16 sge_idx = RX_SGE(le16_to_cpu(fp_cqe->sgl[j]));
-
-		/* FW gives the indices of the SGE as if the ring is an array
-		   (meaning that "next" element will consume 2 indices) */
-		frag_len = min(frag_size, (u32)(SGE_PAGE_SIZE*PAGES_PER_SGE));
-		rx_pg = &fp->rx_page_ring[sge_idx];
-		old_rx_pg = *rx_pg;
-
-		/* If we fail to allocate a substitute page, we simply stop
-		   where we are and drop the whole packet */
-		err = bnx2x_alloc_rx_sge(bp, fp, sge_idx);
-		if (unlikely(err)) {
-			fp->eth_q_stats.rx_skb_alloc_failed++;
-			return err;
-		}
-
-		/* Unmap the page as we r going to pass it to the stack */
-		dma_unmap_page(&bp->pdev->dev,
-			       dma_unmap_addr(&old_rx_pg, mapping),
-			       SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
-
-		/* Add one frag and update the appropriate fields in the skb */
-		skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len);
-
-		skb->data_len += frag_len;
-		skb->truesize += frag_len;
-		skb->len += frag_len;
-
-		frag_size -= frag_len;
-	}
-
-	return 0;
-}
-
-static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
-			   u16 queue, int pad, int len, union eth_rx_cqe *cqe,
-			   u16 cqe_idx)
-{
-	struct sw_rx_bd *rx_buf = &fp->tpa_pool[queue];
-	struct sk_buff *skb = rx_buf->skb;
-	/* alloc new skb */
-	struct sk_buff *new_skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
-
-	/* Unmap skb in the pool anyway, as we are going to change
-	   pool entry status to BNX2X_TPA_STOP even if new skb allocation
-	   fails. */
-	dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping),
-			 bp->rx_buf_size, DMA_FROM_DEVICE);
-
-	if (likely(new_skb)) {
-		/* fix ip xsum and give it to the stack */
-		/* (no need to map the new skb) */
-#ifdef BCM_VLAN
-		int is_vlan_cqe =
-			(le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
-			 PARSING_FLAGS_VLAN);
-		int is_not_hwaccel_vlan_cqe =
-			(is_vlan_cqe && (!(bp->flags & HW_VLAN_RX_FLAG)));
-#endif
-
-		prefetch(skb);
-		prefetch(((char *)(skb)) + 128);
-
-#ifdef BNX2X_STOP_ON_ERROR
-		if (pad + len > bp->rx_buf_size) {
-			BNX2X_ERR("skb_put is about to fail...  "
-				  "pad %d  len %d  rx_buf_size %d\n",
-				  pad, len, bp->rx_buf_size);
-			bnx2x_panic();
-			return;
-		}
-#endif
-
-		skb_reserve(skb, pad);
-		skb_put(skb, len);
-
-		skb->protocol = eth_type_trans(skb, bp->dev);
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-
-		{
-			struct iphdr *iph;
-
-			iph = (struct iphdr *)skb->data;
-#ifdef BCM_VLAN
-			/* If there is no Rx VLAN offloading -
-			   take VLAN tag into an account */
-			if (unlikely(is_not_hwaccel_vlan_cqe))
-				iph = (struct iphdr *)((u8 *)iph + VLAN_HLEN);
-#endif
-			iph->check = 0;
-			iph->check = ip_fast_csum((u8 *)iph, iph->ihl);
-		}
-
-		if (!bnx2x_fill_frag_skb(bp, fp, skb,
-					 &cqe->fast_path_cqe, cqe_idx)) {
-#ifdef BCM_VLAN
-			if ((bp->vlgrp != NULL) && is_vlan_cqe &&
-			    (!is_not_hwaccel_vlan_cqe))
-				vlan_gro_receive(&fp->napi, bp->vlgrp,
-						 le16_to_cpu(cqe->fast_path_cqe.
-							     vlan_tag), skb);
-			else
-#endif
-				napi_gro_receive(&fp->napi, skb);
-		} else {
-			DP(NETIF_MSG_RX_STATUS, "Failed to allocate new pages"
-			   " - dropping packet!\n");
-			dev_kfree_skb(skb);
-		}
-
-
-		/* put new skb in bin */
-		fp->tpa_pool[queue].skb = new_skb;
-
-	} else {
-		/* else drop the packet and keep the buffer in the bin */
-		DP(NETIF_MSG_RX_STATUS,
-		   "Failed to allocate new skb - dropping packet!\n");
-		fp->eth_q_stats.rx_skb_alloc_failed++;
-	}
-
-	fp->tpa_state[queue] = BNX2X_TPA_STOP;
-}
-
-static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
-					struct bnx2x_fastpath *fp,
-					u16 bd_prod, u16 rx_comp_prod,
-					u16 rx_sge_prod)
-{
-	struct ustorm_eth_rx_producers rx_prods = {0};
-	int i;
-
-	/* Update producers */
-	rx_prods.bd_prod = bd_prod;
-	rx_prods.cqe_prod = rx_comp_prod;
-	rx_prods.sge_prod = rx_sge_prod;
-
-	/*
-	 * Make sure that the BD and SGE data is updated before updating the
-	 * producers since FW might read the BD/SGE right after the producer
-	 * is updated.
-	 * This is only applicable for weak-ordered memory model archs such
-	 * as IA-64. The following barrier is also mandatory since FW will
-	 * assumes BDs must have buffers.
-	 */
-	wmb();
-
-	for (i = 0; i < sizeof(struct ustorm_eth_rx_producers)/4; i++)
-		REG_WR(bp, BAR_USTRORM_INTMEM +
-		       USTORM_RX_PRODS_OFFSET(BP_PORT(bp), fp->cl_id) + i*4,
-		       ((u32 *)&rx_prods)[i]);
-
-	mmiowb(); /* keep prod updates ordered */
-
-	DP(NETIF_MSG_RX_STATUS,
-	   "queue[%d]:  wrote  bd_prod %u  cqe_prod %u  sge_prod %u\n",
-	   fp->index, bd_prod, rx_comp_prod, rx_sge_prod);
-}
-
-static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
-{
-	struct bnx2x *bp = fp->bp;
-	u16 bd_cons, bd_prod, bd_prod_fw, comp_ring_cons;
-	u16 hw_comp_cons, sw_comp_cons, sw_comp_prod;
-	int rx_pkt = 0;
-
-#ifdef BNX2X_STOP_ON_ERROR
-	if (unlikely(bp->panic))
-		return 0;
-#endif
-
-	/* CQ "next element" is of the size of the regular element,
-	   that's why it's ok here */
-	hw_comp_cons = le16_to_cpu(*fp->rx_cons_sb);
-	if ((hw_comp_cons & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
-		hw_comp_cons++;
-
-	bd_cons = fp->rx_bd_cons;
-	bd_prod = fp->rx_bd_prod;
-	bd_prod_fw = bd_prod;
-	sw_comp_cons = fp->rx_comp_cons;
-	sw_comp_prod = fp->rx_comp_prod;
-
-	/* Memory barrier necessary as speculative reads of the rx
-	 * buffer can be ahead of the index in the status block
-	 */
-	rmb();
-
-	DP(NETIF_MSG_RX_STATUS,
-	   "queue[%d]:  hw_comp_cons %u  sw_comp_cons %u\n",
-	   fp->index, hw_comp_cons, sw_comp_cons);
-
-	while (sw_comp_cons != hw_comp_cons) {
-		struct sw_rx_bd *rx_buf = NULL;
-		struct sk_buff *skb;
-		union eth_rx_cqe *cqe;
-		u8 cqe_fp_flags, cqe_fp_status_flags;
-		u16 len, pad;
-
-		comp_ring_cons = RCQ_BD(sw_comp_cons);
-		bd_prod = RX_BD(bd_prod);
-		bd_cons = RX_BD(bd_cons);
-
-		/* Prefetch the page containing the BD descriptor
-		   at producer's index. It will be needed when new skb is
-		   allocated */
-		prefetch((void *)(PAGE_ALIGN((unsigned long)
-					     (&fp->rx_desc_ring[bd_prod])) -
-				  PAGE_SIZE + 1));
-
-		cqe = &fp->rx_comp_ring[comp_ring_cons];
-		cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
-		cqe_fp_status_flags = cqe->fast_path_cqe.status_flags;
-
-		DP(NETIF_MSG_RX_STATUS, "CQE type %x  err %x  status %x"
-		   "  queue %x  vlan %x  len %u\n", CQE_TYPE(cqe_fp_flags),
-		   cqe_fp_flags, cqe->fast_path_cqe.status_flags,
-		   le32_to_cpu(cqe->fast_path_cqe.rss_hash_result),
-		   le16_to_cpu(cqe->fast_path_cqe.vlan_tag),
-		   le16_to_cpu(cqe->fast_path_cqe.pkt_len));
-
-		/* is this a slowpath msg? */
-		if (unlikely(CQE_TYPE(cqe_fp_flags))) {
-			bnx2x_sp_event(fp, cqe);
-			goto next_cqe;
-
-		/* this is an rx packet */
-		} else {
-			rx_buf = &fp->rx_buf_ring[bd_cons];
-			skb = rx_buf->skb;
-			prefetch(skb);
-			len = le16_to_cpu(cqe->fast_path_cqe.pkt_len);
-			pad = cqe->fast_path_cqe.placement_offset;
-
-			/* If CQE is marked both TPA_START and TPA_END
-			   it is a non-TPA CQE */
-			if ((!fp->disable_tpa) &&
-			    (TPA_TYPE(cqe_fp_flags) !=
-					(TPA_TYPE_START | TPA_TYPE_END))) {
-				u16 queue = cqe->fast_path_cqe.queue_index;
-
-				if (TPA_TYPE(cqe_fp_flags) == TPA_TYPE_START) {
-					DP(NETIF_MSG_RX_STATUS,
-					   "calling tpa_start on queue %d\n",
-					   queue);
-
-					bnx2x_tpa_start(fp, queue, skb,
-							bd_cons, bd_prod);
-					goto next_rx;
-				}
-
-				if (TPA_TYPE(cqe_fp_flags) == TPA_TYPE_END) {
-					DP(NETIF_MSG_RX_STATUS,
-					   "calling tpa_stop on queue %d\n",
-					   queue);
-
-					if (!BNX2X_RX_SUM_FIX(cqe))
-						BNX2X_ERR("STOP on none TCP "
-							  "data\n");
-
-					/* This is a size of the linear data
-					   on this skb */
-					len = le16_to_cpu(cqe->fast_path_cqe.
-								len_on_bd);
-					bnx2x_tpa_stop(bp, fp, queue, pad,
-						    len, cqe, comp_ring_cons);
-#ifdef BNX2X_STOP_ON_ERROR
-					if (bp->panic)
-						return 0;
-#endif
-
-					bnx2x_update_sge_prod(fp,
-							&cqe->fast_path_cqe);
-					goto next_cqe;
-				}
-			}
-
-			dma_sync_single_for_device(&bp->pdev->dev,
-					dma_unmap_addr(rx_buf, mapping),
-						   pad + RX_COPY_THRESH,
-						   DMA_FROM_DEVICE);
-			prefetch(((char *)(skb)) + 128);
-
-			/* is this an error packet? */
-			if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) {
-				DP(NETIF_MSG_RX_ERR,
-				   "ERROR  flags %x  rx packet %u\n",
-				   cqe_fp_flags, sw_comp_cons);
-				fp->eth_q_stats.rx_err_discard_pkt++;
-				goto reuse_rx;
-			}
-
-			/* Since we don't have a jumbo ring
-			 * copy small packets if mtu > 1500
-			 */
-			if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) &&
-			    (len <= RX_COPY_THRESH)) {
-				struct sk_buff *new_skb;
-
-				new_skb = netdev_alloc_skb(bp->dev,
-							   len + pad);
-				if (new_skb == NULL) {
-					DP(NETIF_MSG_RX_ERR,
-					   "ERROR  packet dropped "
-					   "because of alloc failure\n");
-					fp->eth_q_stats.rx_skb_alloc_failed++;
-					goto reuse_rx;
-				}
-
-				/* aligned copy */
-				skb_copy_from_linear_data_offset(skb, pad,
-						    new_skb->data + pad, len);
-				skb_reserve(new_skb, pad);
-				skb_put(new_skb, len);
-
-				bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod);
-
-				skb = new_skb;
-
-			} else
-			if (likely(bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0)) {
-				dma_unmap_single(&bp->pdev->dev,
-					dma_unmap_addr(rx_buf, mapping),
-						 bp->rx_buf_size,
-						 DMA_FROM_DEVICE);
-				skb_reserve(skb, pad);
-				skb_put(skb, len);
-
-			} else {
-				DP(NETIF_MSG_RX_ERR,
-				   "ERROR  packet dropped because "
-				   "of alloc failure\n");
-				fp->eth_q_stats.rx_skb_alloc_failed++;
-reuse_rx:
-				bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod);
-				goto next_rx;
-			}
-
-			skb->protocol = eth_type_trans(skb, bp->dev);
-
-			if ((bp->dev->features & NETIF_F_RXHASH) &&
-			    (cqe_fp_status_flags &
-			     ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG))
-				skb->rxhash = le32_to_cpu(
-				    cqe->fast_path_cqe.rss_hash_result);
-
-			skb->ip_summed = CHECKSUM_NONE;
-			if (bp->rx_csum) {
-				if (likely(BNX2X_RX_CSUM_OK(cqe)))
-					skb->ip_summed = CHECKSUM_UNNECESSARY;
-				else
-					fp->eth_q_stats.hw_csum_err++;
-			}
-		}
-
-		skb_record_rx_queue(skb, fp->index);
-
-#ifdef BCM_VLAN
-		if ((bp->vlgrp != NULL) && (bp->flags & HW_VLAN_RX_FLAG) &&
-		    (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
-		     PARSING_FLAGS_VLAN))
-			vlan_gro_receive(&fp->napi, bp->vlgrp,
-				le16_to_cpu(cqe->fast_path_cqe.vlan_tag), skb);
-		else
-#endif
-			napi_gro_receive(&fp->napi, skb);
-
-
-next_rx:
-		rx_buf->skb = NULL;
-
-		bd_cons = NEXT_RX_IDX(bd_cons);
-		bd_prod = NEXT_RX_IDX(bd_prod);
-		bd_prod_fw = NEXT_RX_IDX(bd_prod_fw);
-		rx_pkt++;
-next_cqe:
-		sw_comp_prod = NEXT_RCQ_IDX(sw_comp_prod);
-		sw_comp_cons = NEXT_RCQ_IDX(sw_comp_cons);
-
-		if (rx_pkt == budget)
-			break;
-	} /* while */
-
-	fp->rx_bd_cons = bd_cons;
-	fp->rx_bd_prod = bd_prod_fw;
-	fp->rx_comp_cons = sw_comp_cons;
-	fp->rx_comp_prod = sw_comp_prod;
-
-	/* Update producers */
-	bnx2x_update_rx_prod(bp, fp, bd_prod_fw, sw_comp_prod,
-			     fp->rx_sge_prod);
-
-	fp->rx_pkt += rx_pkt;
-	fp->rx_calls++;
-
-	return rx_pkt;
-}
-
-static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
-{
-	struct bnx2x_fastpath *fp = fp_cookie;
-	struct bnx2x *bp = fp->bp;
-
-	/* Return here if interrupt is disabled */
-	if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
-		DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
-		return IRQ_HANDLED;
-	}
-
-	DP(BNX2X_MSG_FP, "got an MSI-X interrupt on IDX:SB [%d:%d]\n",
-	   fp->index, fp->sb_id);
-	bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0);
-
-#ifdef BNX2X_STOP_ON_ERROR
-	if (unlikely(bp->panic))
-		return IRQ_HANDLED;
-#endif
-
-	/* Handle Rx and Tx according to MSI-X vector */
-	prefetch(fp->rx_cons_sb);
-	prefetch(fp->tx_cons_sb);
-	prefetch(&fp->status_blk->u_status_block.status_block_index);
-	prefetch(&fp->status_blk->c_status_block.status_block_index);
-	napi_schedule(&bnx2x_fp(bp, fp->index, napi));
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
-{
-	struct bnx2x *bp = netdev_priv(dev_instance);
-	u16 status = bnx2x_ack_int(bp);
-	u16 mask;
-	int i;
-
-	/* Return here if interrupt is shared and it's not for us */
-	if (unlikely(status == 0)) {
-		DP(NETIF_MSG_INTR, "not our interrupt!\n");
-		return IRQ_NONE;
-	}
-	DP(NETIF_MSG_INTR, "got an interrupt  status 0x%x\n", status);
-
-	/* Return here if interrupt is disabled */
-	if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
-		DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
-		return IRQ_HANDLED;
-	}
-
-#ifdef BNX2X_STOP_ON_ERROR
-	if (unlikely(bp->panic))
-		return IRQ_HANDLED;
-#endif
-
-	for (i = 0; i < BNX2X_NUM_QUEUES(bp); i++) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-
-		mask = 0x2 << fp->sb_id;
-		if (status & mask) {
-			/* Handle Rx and Tx according to SB id */
-			prefetch(fp->rx_cons_sb);
-			prefetch(&fp->status_blk->u_status_block.
-						status_block_index);
-			prefetch(fp->tx_cons_sb);
-			prefetch(&fp->status_blk->c_status_block.
-						status_block_index);
-			napi_schedule(&bnx2x_fp(bp, fp->index, napi));
-			status &= ~mask;
-		}
-	}
-
-#ifdef BCM_CNIC
-	mask = 0x2 << CNIC_SB_ID(bp);
-	if (status & (mask | 0x1)) {
-		struct cnic_ops *c_ops = NULL;
-
-		rcu_read_lock();
-		c_ops = rcu_dereference(bp->cnic_ops);
-		if (c_ops)
-			c_ops->cnic_handler(bp->cnic_data, NULL);
-		rcu_read_unlock();
-
-		status &= ~mask;
-	}
-#endif
-
-	if (unlikely(status & 0x1)) {
-		queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
-
-		status &= ~0x1;
-		if (!status)
-			return IRQ_HANDLED;
-	}
-
-	if (unlikely(status))
-		DP(NETIF_MSG_INTR, "got an unknown interrupt! (status 0x%x)\n",
-		   status);
-
-	return IRQ_HANDLED;
-}
-
-/* end of fast path */
-
-static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
-
-/* Link */
-
-/*
- * General service functions
- */
-
-static int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource)
-{
-	u32 lock_status;
-	u32 resource_bit = (1 << resource);
-	int func = BP_FUNC(bp);
-	u32 hw_lock_control_reg;
-	int cnt;
-
-	/* Validating that the resource is within range */
-	if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
-		DP(NETIF_MSG_HW,
-		   "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
-		   resource, HW_LOCK_MAX_RESOURCE_VALUE);
-		return -EINVAL;
-	}
-
-	if (func <= 5) {
-		hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
-	} else {
-		hw_lock_control_reg =
-				(MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
-	}
-
-	/* Validating that the resource is not already taken */
-	lock_status = REG_RD(bp, hw_lock_control_reg);
-	if (lock_status & resource_bit) {
-		DP(NETIF_MSG_HW, "lock_status 0x%x  resource_bit 0x%x\n",
-		   lock_status, resource_bit);
-		return -EEXIST;
-	}
-
-	/* Try for 5 second every 5ms */
-	for (cnt = 0; cnt < 1000; cnt++) {
-		/* Try to acquire the lock */
-		REG_WR(bp, hw_lock_control_reg + 4, resource_bit);
-		lock_status = REG_RD(bp, hw_lock_control_reg);
-		if (lock_status & resource_bit)
-			return 0;
-
-		msleep(5);
-	}
-	DP(NETIF_MSG_HW, "Timeout\n");
-	return -EAGAIN;
-}
-
-static int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource)
-{
-	u32 lock_status;
-	u32 resource_bit = (1 << resource);
-	int func = BP_FUNC(bp);
-	u32 hw_lock_control_reg;
-
-	DP(NETIF_MSG_HW, "Releasing a lock on resource %d\n", resource);
-
-	/* Validating that the resource is within range */
-	if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
-		DP(NETIF_MSG_HW,
-		   "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
-		   resource, HW_LOCK_MAX_RESOURCE_VALUE);
-		return -EINVAL;
-	}
-
-	if (func <= 5) {
-		hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
-	} else {
-		hw_lock_control_reg =
-				(MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
-	}
-
-	/* Validating that the resource is currently taken */
-	lock_status = REG_RD(bp, hw_lock_control_reg);
-	if (!(lock_status & resource_bit)) {
-		DP(NETIF_MSG_HW, "lock_status 0x%x  resource_bit 0x%x\n",
-		   lock_status, resource_bit);
-		return -EFAULT;
-	}
-
-	REG_WR(bp, hw_lock_control_reg, resource_bit);
-	return 0;
-}
-
-/* HW Lock for shared dual port PHYs */
-static void bnx2x_acquire_phy_lock(struct bnx2x *bp)
-{
-	mutex_lock(&bp->port.phy_mutex);
-
-	if (bp->port.need_hw_lock)
-		bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_MDIO);
-}
-
-static void bnx2x_release_phy_lock(struct bnx2x *bp)
-{
-	if (bp->port.need_hw_lock)
-		bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_MDIO);
-
-	mutex_unlock(&bp->port.phy_mutex);
-}
-
-int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port)
-{
-	/* The GPIO should be swapped if swap register is set and active */
-	int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
-			 REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
-	int gpio_shift = gpio_num +
-			(gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
-	u32 gpio_mask = (1 << gpio_shift);
-	u32 gpio_reg;
-	int value;
-
-	if (gpio_num > MISC_REGISTERS_GPIO_3) {
-		BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
-		return -EINVAL;
-	}
-
-	/* read GPIO value */
-	gpio_reg = REG_RD(bp, MISC_REG_GPIO);
-
-	/* get the requested pin value */
-	if ((gpio_reg & gpio_mask) == gpio_mask)
-		value = 1;
-	else
-		value = 0;
-
-	DP(NETIF_MSG_LINK, "pin %d  value 0x%x\n", gpio_num, value);
-
-	return value;
-}
-
-int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port)
-{
-	/* The GPIO should be swapped if swap register is set and active */
-	int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
-			 REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
-	int gpio_shift = gpio_num +
-			(gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
-	u32 gpio_mask = (1 << gpio_shift);
-	u32 gpio_reg;
-
-	if (gpio_num > MISC_REGISTERS_GPIO_3) {
-		BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
-		return -EINVAL;
-	}
-
-	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
-	/* read GPIO and mask except the float bits */
-	gpio_reg = (REG_RD(bp, MISC_REG_GPIO) & MISC_REGISTERS_GPIO_FLOAT);
-
-	switch (mode) {
-	case MISC_REGISTERS_GPIO_OUTPUT_LOW:
-		DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output low\n",
-		   gpio_num, gpio_shift);
-		/* clear FLOAT and set CLR */
-		gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
-		gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_CLR_POS);
-		break;
-
-	case MISC_REGISTERS_GPIO_OUTPUT_HIGH:
-		DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output high\n",
-		   gpio_num, gpio_shift);
-		/* clear FLOAT and set SET */
-		gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
-		gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_SET_POS);
-		break;
-
-	case MISC_REGISTERS_GPIO_INPUT_HI_Z:
-		DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> input\n",
-		   gpio_num, gpio_shift);
-		/* set FLOAT */
-		gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
-		break;
-
-	default:
-		break;
-	}
-
-	REG_WR(bp, MISC_REG_GPIO, gpio_reg);
-	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
-
-	return 0;
-}
-
-int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port)
-{
-	/* The GPIO should be swapped if swap register is set and active */
-	int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
-			 REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
-	int gpio_shift = gpio_num +
-			(gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
-	u32 gpio_mask = (1 << gpio_shift);
-	u32 gpio_reg;
-
-	if (gpio_num > MISC_REGISTERS_GPIO_3) {
-		BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
-		return -EINVAL;
-	}
-
-	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
-	/* read GPIO int */
-	gpio_reg = REG_RD(bp, MISC_REG_GPIO_INT);
-
-	switch (mode) {
-	case MISC_REGISTERS_GPIO_INT_OUTPUT_CLR:
-		DP(NETIF_MSG_LINK, "Clear GPIO INT %d (shift %d) -> "
-				   "output low\n", gpio_num, gpio_shift);
-		/* clear SET and set CLR */
-		gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_INT_SET_POS);
-		gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_INT_CLR_POS);
-		break;
-
-	case MISC_REGISTERS_GPIO_INT_OUTPUT_SET:
-		DP(NETIF_MSG_LINK, "Set GPIO INT %d (shift %d) -> "
-				   "output high\n", gpio_num, gpio_shift);
-		/* clear CLR and set SET */
-		gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_INT_CLR_POS);
-		gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_INT_SET_POS);
-		break;
-
-	default:
-		break;
-	}
-
-	REG_WR(bp, MISC_REG_GPIO_INT, gpio_reg);
-	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
-
-	return 0;
-}
-
-static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode)
-{
-	u32 spio_mask = (1 << spio_num);
-	u32 spio_reg;
-
-	if ((spio_num < MISC_REGISTERS_SPIO_4) ||
-	    (spio_num > MISC_REGISTERS_SPIO_7)) {
-		BNX2X_ERR("Invalid SPIO %d\n", spio_num);
-		return -EINVAL;
-	}
-
-	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_SPIO);
-	/* read SPIO and mask except the float bits */
-	spio_reg = (REG_RD(bp, MISC_REG_SPIO) & MISC_REGISTERS_SPIO_FLOAT);
-
-	switch (mode) {
-	case MISC_REGISTERS_SPIO_OUTPUT_LOW:
-		DP(NETIF_MSG_LINK, "Set SPIO %d -> output low\n", spio_num);
-		/* clear FLOAT and set CLR */
-		spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
-		spio_reg |=  (spio_mask << MISC_REGISTERS_SPIO_CLR_POS);
-		break;
-
-	case MISC_REGISTERS_SPIO_OUTPUT_HIGH:
-		DP(NETIF_MSG_LINK, "Set SPIO %d -> output high\n", spio_num);
-		/* clear FLOAT and set SET */
-		spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
-		spio_reg |=  (spio_mask << MISC_REGISTERS_SPIO_SET_POS);
-		break;
-
-	case MISC_REGISTERS_SPIO_INPUT_HI_Z:
-		DP(NETIF_MSG_LINK, "Set SPIO %d -> input\n", spio_num);
-		/* set FLOAT */
-		spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
-		break;
-
-	default:
-		break;
-	}
-
-	REG_WR(bp, MISC_REG_SPIO, spio_reg);
-	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_SPIO);
-
-	return 0;
-}
-
-static void bnx2x_calc_fc_adv(struct bnx2x *bp)
-{
-	switch (bp->link_vars.ieee_fc &
-		MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK) {
-	case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE:
-		bp->port.advertising &= ~(ADVERTISED_Asym_Pause |
-					  ADVERTISED_Pause);
-		break;
-
-	case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH:
-		bp->port.advertising |= (ADVERTISED_Asym_Pause |
-					 ADVERTISED_Pause);
-		break;
-
-	case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC:
-		bp->port.advertising |= ADVERTISED_Asym_Pause;
-		break;
-
-	default:
-		bp->port.advertising &= ~(ADVERTISED_Asym_Pause |
-					  ADVERTISED_Pause);
-		break;
-	}
-}
-
-static void bnx2x_link_report(struct bnx2x *bp)
-{
-	if (bp->flags & MF_FUNC_DIS) {
-		netif_carrier_off(bp->dev);
-		netdev_err(bp->dev, "NIC Link is Down\n");
-		return;
-	}
-
-	if (bp->link_vars.link_up) {
-		u16 line_speed;
-
-		if (bp->state == BNX2X_STATE_OPEN)
-			netif_carrier_on(bp->dev);
-		netdev_info(bp->dev, "NIC Link is Up, ");
-
-		line_speed = bp->link_vars.line_speed;
-		if (IS_E1HMF(bp)) {
-			u16 vn_max_rate;
-
-			vn_max_rate =
-				((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
-				 FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
-			if (vn_max_rate < line_speed)
-				line_speed = vn_max_rate;
-		}
-		pr_cont("%d Mbps ", line_speed);
-
-		if (bp->link_vars.duplex == DUPLEX_FULL)
-			pr_cont("full duplex");
-		else
-			pr_cont("half duplex");
-
-		if (bp->link_vars.flow_ctrl != BNX2X_FLOW_CTRL_NONE) {
-			if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) {
-				pr_cont(", receive ");
-				if (bp->link_vars.flow_ctrl &
-				    BNX2X_FLOW_CTRL_TX)
-					pr_cont("& transmit ");
-			} else {
-				pr_cont(", transmit ");
-			}
-			pr_cont("flow control ON");
-		}
-		pr_cont("\n");
-
-	} else { /* link_down */
-		netif_carrier_off(bp->dev);
-		netdev_err(bp->dev, "NIC Link is Down\n");
-	}
-}
-
-static u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
-{
-	if (!BP_NOMCP(bp)) {
-		u8 rc;
-
-		/* Initialize link parameters structure variables */
-		/* It is recommended to turn off RX FC for jumbo frames
-		   for better performance */
-		if (bp->dev->mtu > 5000)
-			bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_TX;
-		else
-			bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH;
-
-		bnx2x_acquire_phy_lock(bp);
-
-		if (load_mode == LOAD_DIAG)
-			bp->link_params.loopback_mode = LOOPBACK_XGXS_10;
-
-		rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars);
-
-		bnx2x_release_phy_lock(bp);
-
-		bnx2x_calc_fc_adv(bp);
-
-		if (CHIP_REV_IS_SLOW(bp) && bp->link_vars.link_up) {
-			bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
-			bnx2x_link_report(bp);
-		}
-
-		return rc;
-	}
-	BNX2X_ERR("Bootcode is missing - can not initialize link\n");
-	return -EINVAL;
-}
-
-static void bnx2x_link_set(struct bnx2x *bp)
-{
-	if (!BP_NOMCP(bp)) {
-		bnx2x_acquire_phy_lock(bp);
-		bnx2x_phy_init(&bp->link_params, &bp->link_vars);
-		bnx2x_release_phy_lock(bp);
-
-		bnx2x_calc_fc_adv(bp);
-	} else
-		BNX2X_ERR("Bootcode is missing - can not set link\n");
-}
-
-static void bnx2x__link_reset(struct bnx2x *bp)
-{
-	if (!BP_NOMCP(bp)) {
-		bnx2x_acquire_phy_lock(bp);
-		bnx2x_link_reset(&bp->link_params, &bp->link_vars, 1);
-		bnx2x_release_phy_lock(bp);
-	} else
-		BNX2X_ERR("Bootcode is missing - can not reset link\n");
-}
-
-static u8 bnx2x_link_test(struct bnx2x *bp)
-{
-	u8 rc = 0;
-
-	if (!BP_NOMCP(bp)) {
-		bnx2x_acquire_phy_lock(bp);
-		rc = bnx2x_test_link(&bp->link_params, &bp->link_vars);
-		bnx2x_release_phy_lock(bp);
-	} else
-		BNX2X_ERR("Bootcode is missing - can not test link\n");
-
-	return rc;
-}
-
-static void bnx2x_init_port_minmax(struct bnx2x *bp)
-{
-	u32 r_param = bp->link_vars.line_speed / 8;
-	u32 fair_periodic_timeout_usec;
-	u32 t_fair;
-
-	memset(&(bp->cmng.rs_vars), 0,
-	       sizeof(struct rate_shaping_vars_per_port));
-	memset(&(bp->cmng.fair_vars), 0, sizeof(struct fairness_vars_per_port));
-
-	/* 100 usec in SDM ticks = 25 since each tick is 4 usec */
-	bp->cmng.rs_vars.rs_periodic_timeout = RS_PERIODIC_TIMEOUT_USEC / 4;
-
-	/* this is the threshold below which no timer arming will occur
-	   1.25 coefficient is for the threshold to be a little bigger
-	   than the real time, to compensate for timer in-accuracy */
-	bp->cmng.rs_vars.rs_threshold =
-				(RS_PERIODIC_TIMEOUT_USEC * r_param * 5) / 4;
-
-	/* resolution of fairness timer */
-	fair_periodic_timeout_usec = QM_ARB_BYTES / r_param;
-	/* for 10G it is 1000usec. for 1G it is 10000usec. */
-	t_fair = T_FAIR_COEF / bp->link_vars.line_speed;
-
-	/* this is the threshold below which we won't arm the timer anymore */
-	bp->cmng.fair_vars.fair_threshold = QM_ARB_BYTES;
-
-	/* we multiply by 1e3/8 to get bytes/msec.
-	   We don't want the credits to pass a credit
-	   of the t_fair*FAIR_MEM (algorithm resolution) */
-	bp->cmng.fair_vars.upper_bound = r_param * t_fair * FAIR_MEM;
-	/* since each tick is 4 usec */
-	bp->cmng.fair_vars.fairness_timeout = fair_periodic_timeout_usec / 4;
-}
-
-/* Calculates the sum of vn_min_rates.
-   It's needed for further normalizing of the min_rates.
-   Returns:
-     sum of vn_min_rates.
-       or
-     0 - if all the min_rates are 0.
-     In the later case fainess algorithm should be deactivated.
-     If not all min_rates are zero then those that are zeroes will be set to 1.
- */
-static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
-{
-	int all_zero = 1;
-	int port = BP_PORT(bp);
-	int vn;
-
-	bp->vn_weight_sum = 0;
-	for (vn = VN_0; vn < E1HVN_MAX; vn++) {
-		int func = 2*vn + port;
-		u32 vn_cfg = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
-		u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
-				   FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
-
-		/* Skip hidden vns */
-		if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE)
-			continue;
-
-		/* If min rate is zero - set it to 1 */
-		if (!vn_min_rate)
-			vn_min_rate = DEF_MIN_RATE;
-		else
-			all_zero = 0;
-
-		bp->vn_weight_sum += vn_min_rate;
-	}
-
-	/* ... only if all min rates are zeros - disable fairness */
-	if (all_zero) {
-		bp->cmng.flags.cmng_enables &=
-					~CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
-		DP(NETIF_MSG_IFUP, "All MIN values are zeroes"
-		   "  fairness will be disabled\n");
-	} else
-		bp->cmng.flags.cmng_enables |=
-					CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
-}
-
-static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
-{
-	struct rate_shaping_vars_per_vn m_rs_vn;
-	struct fairness_vars_per_vn m_fair_vn;
-	u32 vn_cfg = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
-	u16 vn_min_rate, vn_max_rate;
-	int i;
-
-	/* If function is hidden - set min and max to zeroes */
-	if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE) {
-		vn_min_rate = 0;
-		vn_max_rate = 0;
-
-	} else {
-		vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
-				FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
-		/* If min rate is zero - set it to 1 */
-		if (!vn_min_rate)
-			vn_min_rate = DEF_MIN_RATE;
-		vn_max_rate = ((vn_cfg & FUNC_MF_CFG_MAX_BW_MASK) >>
-				FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
-	}
-	DP(NETIF_MSG_IFUP,
-	   "func %d: vn_min_rate %d  vn_max_rate %d  vn_weight_sum %d\n",
-	   func, vn_min_rate, vn_max_rate, bp->vn_weight_sum);
-
-	memset(&m_rs_vn, 0, sizeof(struct rate_shaping_vars_per_vn));
-	memset(&m_fair_vn, 0, sizeof(struct fairness_vars_per_vn));
-
-	/* global vn counter - maximal Mbps for this vn */
-	m_rs_vn.vn_counter.rate = vn_max_rate;
-
-	/* quota - number of bytes transmitted in this period */
-	m_rs_vn.vn_counter.quota =
-				(vn_max_rate * RS_PERIODIC_TIMEOUT_USEC) / 8;
-
-	if (bp->vn_weight_sum) {
-		/* credit for each period of the fairness algorithm:
-		   number of bytes in T_FAIR (the vn share the port rate).
-		   vn_weight_sum should not be larger than 10000, thus
-		   T_FAIR_COEF / (8 * vn_weight_sum) will always be greater
-		   than zero */
-		m_fair_vn.vn_credit_delta =
-			max_t(u32, (vn_min_rate * (T_FAIR_COEF /
-						   (8 * bp->vn_weight_sum))),
-			      (bp->cmng.fair_vars.fair_threshold * 2));
-		DP(NETIF_MSG_IFUP, "m_fair_vn.vn_credit_delta %d\n",
-		   m_fair_vn.vn_credit_delta);
-	}
-
-	/* Store it to internal memory */
-	for (i = 0; i < sizeof(struct rate_shaping_vars_per_vn)/4; i++)
-		REG_WR(bp, BAR_XSTRORM_INTMEM +
-		       XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(func) + i * 4,
-		       ((u32 *)(&m_rs_vn))[i]);
-
-	for (i = 0; i < sizeof(struct fairness_vars_per_vn)/4; i++)
-		REG_WR(bp, BAR_XSTRORM_INTMEM +
-		       XSTORM_FAIRNESS_PER_VN_VARS_OFFSET(func) + i * 4,
-		       ((u32 *)(&m_fair_vn))[i]);
-}
-
-
-/* This function is called upon link interrupt */
-static void bnx2x_link_attn(struct bnx2x *bp)
-{
-	u32 prev_link_status = bp->link_vars.link_status;
-	/* Make sure that we are synced with the current statistics */
-	bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-
-	bnx2x_link_update(&bp->link_params, &bp->link_vars);
-
-	if (bp->link_vars.link_up) {
-
-		/* dropless flow control */
-		if (CHIP_IS_E1H(bp) && bp->dropless_fc) {
-			int port = BP_PORT(bp);
-			u32 pause_enabled = 0;
-
-			if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
-				pause_enabled = 1;
-
-			REG_WR(bp, BAR_USTRORM_INTMEM +
-			       USTORM_ETH_PAUSE_ENABLED_OFFSET(port),
-			       pause_enabled);
-		}
-
-		if (bp->link_vars.mac_type == MAC_TYPE_BMAC) {
-			struct host_port_stats *pstats;
-
-			pstats = bnx2x_sp(bp, port_stats);
-			/* reset old bmac stats */
-			memset(&(pstats->mac_stx[0]), 0,
-			       sizeof(struct mac_stx));
-		}
-		if (bp->state == BNX2X_STATE_OPEN)
-			bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
-	}
-
-	/* indicate link status only if link status actually changed */
-	if (prev_link_status != bp->link_vars.link_status)
-		bnx2x_link_report(bp);
-
-	if (IS_E1HMF(bp)) {
-		int port = BP_PORT(bp);
-		int func;
-		int vn;
-
-		/* Set the attention towards other drivers on the same port */
-		for (vn = VN_0; vn < E1HVN_MAX; vn++) {
-			if (vn == BP_E1HVN(bp))
-				continue;
-
-			func = ((vn << 1) | port);
-			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
-			       (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
-		}
-
-		if (bp->link_vars.link_up) {
-			int i;
-
-			/* Init rate shaping and fairness contexts */
-			bnx2x_init_port_minmax(bp);
-
-			for (vn = VN_0; vn < E1HVN_MAX; vn++)
-				bnx2x_init_vn_minmax(bp, 2*vn + port);
-
-			/* Store it to internal memory */
-			for (i = 0;
-			     i < sizeof(struct cmng_struct_per_port) / 4; i++)
-				REG_WR(bp, BAR_XSTRORM_INTMEM +
-				  XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i*4,
-				       ((u32 *)(&bp->cmng))[i]);
-		}
-	}
-}
-
-static void bnx2x__link_status_update(struct bnx2x *bp)
-{
-	if ((bp->state != BNX2X_STATE_OPEN) || (bp->flags & MF_FUNC_DIS))
-		return;
-
-	bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
-
-	if (bp->link_vars.link_up)
-		bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
-	else
-		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-
-	bnx2x_calc_vn_weight_sum(bp);
-
-	/* indicate link status */
-	bnx2x_link_report(bp);
-}
-
-static void bnx2x_pmf_update(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	u32 val;
-
-	bp->port.pmf = 1;
-	DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
-
-	/* enable nig attention */
-	val = (0xff0f | (1 << (BP_E1HVN(bp) + 4)));
-	REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
-	REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
-
-	bnx2x_stats_handle(bp, STATS_EVENT_PMF);
-}
-
-/* end of Link */
-
-/* slow path */
-
-/*
- * General service functions
- */
-
-/* send the MCP a request, block until there is a reply */
-u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
-{
-	int func = BP_FUNC(bp);
-	u32 seq = ++bp->fw_seq;
-	u32 rc = 0;
-	u32 cnt = 1;
-	u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10;
-
-	mutex_lock(&bp->fw_mb_mutex);
-	SHMEM_WR(bp, func_mb[func].drv_mb_header, (command | seq));
-	DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq));
-
-	do {
-		/* let the FW do it's magic ... */
-		msleep(delay);
-
-		rc = SHMEM_RD(bp, func_mb[func].fw_mb_header);
-
-		/* Give the FW up to 5 second (500*10ms) */
-	} while ((seq != (rc & FW_MSG_SEQ_NUMBER_MASK)) && (cnt++ < 500));
-
-	DP(BNX2X_MSG_MCP, "[after %d ms] read (%x) seq is (%x) from FW MB\n",
-	   cnt*delay, rc, seq);
-
-	/* is this a reply to our command? */
-	if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK))
-		rc &= FW_MSG_CODE_MASK;
-	else {
-		/* FW BUG! */
-		BNX2X_ERR("FW failed to respond!\n");
-		bnx2x_fw_dump(bp);
-		rc = 0;
-	}
-	mutex_unlock(&bp->fw_mb_mutex);
-
-	return rc;
-}
-
-static void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set);
-static void bnx2x_set_rx_mode(struct net_device *dev);
-
-static void bnx2x_e1h_disable(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-
-	netif_tx_disable(bp->dev);
-
-	REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
-
-	netif_carrier_off(bp->dev);
-}
-
-static void bnx2x_e1h_enable(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-
-	REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1);
-
-	/* Tx queue should be only reenabled */
-	netif_tx_wake_all_queues(bp->dev);
-
-	/*
-	 * Should not call netif_carrier_on since it will be called if the link
-	 * is up when checking for link state
-	 */
-}
-
-static void bnx2x_update_min_max(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	int vn, i;
-
-	/* Init rate shaping and fairness contexts */
-	bnx2x_init_port_minmax(bp);
-
-	bnx2x_calc_vn_weight_sum(bp);
-
-	for (vn = VN_0; vn < E1HVN_MAX; vn++)
-		bnx2x_init_vn_minmax(bp, 2*vn + port);
-
-	if (bp->port.pmf) {
-		int func;
-
-		/* Set the attention towards other drivers on the same port */
-		for (vn = VN_0; vn < E1HVN_MAX; vn++) {
-			if (vn == BP_E1HVN(bp))
-				continue;
-
-			func = ((vn << 1) | port);
-			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
-			       (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
-		}
-
-		/* Store it to internal memory */
-		for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++)
-			REG_WR(bp, BAR_XSTRORM_INTMEM +
-			       XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i*4,
-			       ((u32 *)(&bp->cmng))[i]);
-	}
-}
-
-static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
-{
-	DP(BNX2X_MSG_MCP, "dcc_event 0x%x\n", dcc_event);
-
-	if (dcc_event & DRV_STATUS_DCC_DISABLE_ENABLE_PF) {
-
-		/*
-		 * This is the only place besides the function initialization
-		 * where the bp->flags can change so it is done without any
-		 * locks
-		 */
-		if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) {
-			DP(NETIF_MSG_IFDOWN, "mf_cfg function disabled\n");
-			bp->flags |= MF_FUNC_DIS;
-
-			bnx2x_e1h_disable(bp);
-		} else {
-			DP(NETIF_MSG_IFUP, "mf_cfg function enabled\n");
-			bp->flags &= ~MF_FUNC_DIS;
-
-			bnx2x_e1h_enable(bp);
-		}
-		dcc_event &= ~DRV_STATUS_DCC_DISABLE_ENABLE_PF;
-	}
-	if (dcc_event & DRV_STATUS_DCC_BANDWIDTH_ALLOCATION) {
-
-		bnx2x_update_min_max(bp);
-		dcc_event &= ~DRV_STATUS_DCC_BANDWIDTH_ALLOCATION;
-	}
-
-	/* Report results to MCP */
-	if (dcc_event)
-		bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_FAILURE);
-	else
-		bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK);
-}
-
-/* must be called under the spq lock */
-static inline struct eth_spe *bnx2x_sp_get_next(struct bnx2x *bp)
-{
-	struct eth_spe *next_spe = bp->spq_prod_bd;
-
-	if (bp->spq_prod_bd == bp->spq_last_bd) {
-		bp->spq_prod_bd = bp->spq;
-		bp->spq_prod_idx = 0;
-		DP(NETIF_MSG_TIMER, "end of spq\n");
-	} else {
-		bp->spq_prod_bd++;
-		bp->spq_prod_idx++;
-	}
-	return next_spe;
-}
-
-/* must be called under the spq lock */
-static inline void bnx2x_sp_prod_update(struct bnx2x *bp)
-{
-	int func = BP_FUNC(bp);
-
-	/* Make sure that BD data is updated before writing the producer */
-	wmb();
-
-	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
-	       bp->spq_prod_idx);
-	mmiowb();
-}
-
-/* the slow path queue is odd since completions arrive on the fastpath ring */
-static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
-			 u32 data_hi, u32 data_lo, int common)
-{
-	struct eth_spe *spe;
-
-#ifdef BNX2X_STOP_ON_ERROR
-	if (unlikely(bp->panic))
-		return -EIO;
-#endif
-
-	spin_lock_bh(&bp->spq_lock);
-
-	if (!bp->spq_left) {
-		BNX2X_ERR("BUG! SPQ ring full!\n");
-		spin_unlock_bh(&bp->spq_lock);
-		bnx2x_panic();
-		return -EBUSY;
-	}
-
-	spe = bnx2x_sp_get_next(bp);
-
-	/* CID needs port number to be encoded int it */
-	spe->hdr.conn_and_cmd_data =
-			cpu_to_le32((command << SPE_HDR_CMD_ID_SHIFT) |
-				    HW_CID(bp, cid));
-	spe->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE);
-	if (common)
-		spe->hdr.type |=
-			cpu_to_le16((1 << SPE_HDR_COMMON_RAMROD_SHIFT));
-
-	spe->data.mac_config_addr.hi = cpu_to_le32(data_hi);
-	spe->data.mac_config_addr.lo = cpu_to_le32(data_lo);
-
-	bp->spq_left--;
-
-	DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/,
-	   "SPQE[%x] (%x:%x)  command %d  hw_cid %x  data (%x:%x)  left %x\n",
-	   bp->spq_prod_idx, (u32)U64_HI(bp->spq_mapping),
-	   (u32)(U64_LO(bp->spq_mapping) +
-	   (void *)bp->spq_prod_bd - (void *)bp->spq), command,
-	   HW_CID(bp, cid), data_hi, data_lo, bp->spq_left);
-
-	bnx2x_sp_prod_update(bp);
-	spin_unlock_bh(&bp->spq_lock);
-	return 0;
-}
-
-/* acquire split MCP access lock register */
-static int bnx2x_acquire_alr(struct bnx2x *bp)
-{
-	u32 j, val;
-	int rc = 0;
-
-	might_sleep();
-	for (j = 0; j < 1000; j++) {
-		val = (1UL << 31);
-		REG_WR(bp, GRCBASE_MCP + 0x9c, val);
-		val = REG_RD(bp, GRCBASE_MCP + 0x9c);
-		if (val & (1L << 31))
-			break;
-
-		msleep(5);
-	}
-	if (!(val & (1L << 31))) {
-		BNX2X_ERR("Cannot acquire MCP access lock register\n");
-		rc = -EBUSY;
-	}
-
-	return rc;
-}
-
-/* release split MCP access lock register */
-static void bnx2x_release_alr(struct bnx2x *bp)
-{
-	REG_WR(bp, GRCBASE_MCP + 0x9c, 0);
-}
-
-static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp)
-{
-	struct host_def_status_block *def_sb = bp->def_status_blk;
-	u16 rc = 0;
-
-	barrier(); /* status block is written to by the chip */
-	if (bp->def_att_idx != def_sb->atten_status_block.attn_bits_index) {
-		bp->def_att_idx = def_sb->atten_status_block.attn_bits_index;
-		rc |= 1;
-	}
-	if (bp->def_c_idx != def_sb->c_def_status_block.status_block_index) {
-		bp->def_c_idx = def_sb->c_def_status_block.status_block_index;
-		rc |= 2;
-	}
-	if (bp->def_u_idx != def_sb->u_def_status_block.status_block_index) {
-		bp->def_u_idx = def_sb->u_def_status_block.status_block_index;
-		rc |= 4;
-	}
-	if (bp->def_x_idx != def_sb->x_def_status_block.status_block_index) {
-		bp->def_x_idx = def_sb->x_def_status_block.status_block_index;
-		rc |= 8;
-	}
-	if (bp->def_t_idx != def_sb->t_def_status_block.status_block_index) {
-		bp->def_t_idx = def_sb->t_def_status_block.status_block_index;
-		rc |= 16;
-	}
-	return rc;
-}
-
-/*
- * slow path service functions
- */
-
-static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
-{
-	int port = BP_PORT(bp);
-	u32 hc_addr = (HC_REG_COMMAND_REG + port*32 +
-		       COMMAND_REG_ATTN_BITS_SET);
-	u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
-			      MISC_REG_AEU_MASK_ATTN_FUNC_0;
-	u32 nig_int_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 :
-				       NIG_REG_MASK_INTERRUPT_PORT0;
-	u32 aeu_mask;
-	u32 nig_mask = 0;
-
-	if (bp->attn_state & asserted)
-		BNX2X_ERR("IGU ERROR\n");
-
-	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port);
-	aeu_mask = REG_RD(bp, aeu_addr);
-
-	DP(NETIF_MSG_HW, "aeu_mask %x  newly asserted %x\n",
-	   aeu_mask, asserted);
-	aeu_mask &= ~(asserted & 0x3ff);
-	DP(NETIF_MSG_HW, "new mask %x\n", aeu_mask);
-
-	REG_WR(bp, aeu_addr, aeu_mask);
-	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port);
-
-	DP(NETIF_MSG_HW, "attn_state %x\n", bp->attn_state);
-	bp->attn_state |= asserted;
-	DP(NETIF_MSG_HW, "new state %x\n", bp->attn_state);
-
-	if (asserted & ATTN_HARD_WIRED_MASK) {
-		if (asserted & ATTN_NIG_FOR_FUNC) {
-
-			bnx2x_acquire_phy_lock(bp);
-
-			/* save nig interrupt mask */
-			nig_mask = REG_RD(bp, nig_int_mask_addr);
-			REG_WR(bp, nig_int_mask_addr, 0);
-
-			bnx2x_link_attn(bp);
-
-			/* handle unicore attn? */
-		}
-		if (asserted & ATTN_SW_TIMER_4_FUNC)
-			DP(NETIF_MSG_HW, "ATTN_SW_TIMER_4_FUNC!\n");
-
-		if (asserted & GPIO_2_FUNC)
-			DP(NETIF_MSG_HW, "GPIO_2_FUNC!\n");
-
-		if (asserted & GPIO_3_FUNC)
-			DP(NETIF_MSG_HW, "GPIO_3_FUNC!\n");
-
-		if (asserted & GPIO_4_FUNC)
-			DP(NETIF_MSG_HW, "GPIO_4_FUNC!\n");
-
-		if (port == 0) {
-			if (asserted & ATTN_GENERAL_ATTN_1) {
-				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_1!\n");
-				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_1, 0x0);
-			}
-			if (asserted & ATTN_GENERAL_ATTN_2) {
-				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_2!\n");
-				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_2, 0x0);
-			}
-			if (asserted & ATTN_GENERAL_ATTN_3) {
-				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_3!\n");
-				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_3, 0x0);
-			}
-		} else {
-			if (asserted & ATTN_GENERAL_ATTN_4) {
-				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_4!\n");
-				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_4, 0x0);
-			}
-			if (asserted & ATTN_GENERAL_ATTN_5) {
-				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_5!\n");
-				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_5, 0x0);
-			}
-			if (asserted & ATTN_GENERAL_ATTN_6) {
-				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_6!\n");
-				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_6, 0x0);
-			}
-		}
-
-	} /* if hardwired */
-
-	DP(NETIF_MSG_HW, "about to mask 0x%08x at HC addr 0x%x\n",
-	   asserted, hc_addr);
-	REG_WR(bp, hc_addr, asserted);
-
-	/* now set back the mask */
-	if (asserted & ATTN_NIG_FOR_FUNC) {
-		REG_WR(bp, nig_int_mask_addr, nig_mask);
-		bnx2x_release_phy_lock(bp);
-	}
-}
-
-static inline void bnx2x_fan_failure(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-
-	/* mark the failure */
-	bp->link_params.ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
-	bp->link_params.ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
-	SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config,
-		 bp->link_params.ext_phy_config);
-
-	/* log the failure */
-	netdev_err(bp->dev, "Fan Failure on Network Controller has caused"
-	       " the driver to shutdown the card to prevent permanent"
-	       " damage.  Please contact OEM Support for assistance\n");
-}
-
-static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
-{
-	int port = BP_PORT(bp);
-	int reg_offset;
-	u32 val, swap_val, swap_override;
-
-	reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
-			     MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
-
-	if (attn & AEU_INPUTS_ATTN_BITS_SPIO5) {
-
-		val = REG_RD(bp, reg_offset);
-		val &= ~AEU_INPUTS_ATTN_BITS_SPIO5;
-		REG_WR(bp, reg_offset, val);
-
-		BNX2X_ERR("SPIO5 hw attention\n");
-
-		/* Fan failure attention */
-		switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-			/* Low power mode is controlled by GPIO 2 */
-			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
-				       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
-			/* The PHY reset is controlled by GPIO 1 */
-			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
-				       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
-			break;
-
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-			/* The PHY reset is controlled by GPIO 1 */
-			/* fake the port number to cancel the swap done in
-			   set_gpio() */
-			swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
-			swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
-			port = (swap_val && swap_override) ^ 1;
-			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
-				       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
-			break;
-
-		default:
-			break;
-		}
-		bnx2x_fan_failure(bp);
-	}
-
-	if (attn & (AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 |
-		    AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1)) {
-		bnx2x_acquire_phy_lock(bp);
-		bnx2x_handle_module_detect_int(&bp->link_params);
-		bnx2x_release_phy_lock(bp);
-	}
-
-	if (attn & HW_INTERRUT_ASSERT_SET_0) {
-
-		val = REG_RD(bp, reg_offset);
-		val &= ~(attn & HW_INTERRUT_ASSERT_SET_0);
-		REG_WR(bp, reg_offset, val);
-
-		BNX2X_ERR("FATAL HW block attention set0 0x%x\n",
-			  (u32)(attn & HW_INTERRUT_ASSERT_SET_0));
-		bnx2x_panic();
-	}
-}
-
-static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn)
-{
-	u32 val;
-
-	if (attn & AEU_INPUTS_ATTN_BITS_DOORBELLQ_HW_INTERRUPT) {
-
-		val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR);
-		BNX2X_ERR("DB hw attention 0x%x\n", val);
-		/* DORQ discard attention */
-		if (val & 0x2)
-			BNX2X_ERR("FATAL error from DORQ\n");
-	}
-
-	if (attn & HW_INTERRUT_ASSERT_SET_1) {
-
-		int port = BP_PORT(bp);
-		int reg_offset;
-
-		reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1 :
-				     MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1);
-
-		val = REG_RD(bp, reg_offset);
-		val &= ~(attn & HW_INTERRUT_ASSERT_SET_1);
-		REG_WR(bp, reg_offset, val);
-
-		BNX2X_ERR("FATAL HW block attention set1 0x%x\n",
-			  (u32)(attn & HW_INTERRUT_ASSERT_SET_1));
-		bnx2x_panic();
-	}
-}
-
-static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn)
-{
-	u32 val;
-
-	if (attn & AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) {
-
-		val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR);
-		BNX2X_ERR("CFC hw attention 0x%x\n", val);
-		/* CFC error attention */
-		if (val & 0x2)
-			BNX2X_ERR("FATAL error from CFC\n");
-	}
-
-	if (attn & AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) {
-
-		val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0);
-		BNX2X_ERR("PXP hw attention 0x%x\n", val);
-		/* RQ_USDMDP_FIFO_OVERFLOW */
-		if (val & 0x18000)
-			BNX2X_ERR("FATAL error from PXP\n");
-	}
-
-	if (attn & HW_INTERRUT_ASSERT_SET_2) {
-
-		int port = BP_PORT(bp);
-		int reg_offset;
-
-		reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_2 :
-				     MISC_REG_AEU_ENABLE1_FUNC_0_OUT_2);
-
-		val = REG_RD(bp, reg_offset);
-		val &= ~(attn & HW_INTERRUT_ASSERT_SET_2);
-		REG_WR(bp, reg_offset, val);
-
-		BNX2X_ERR("FATAL HW block attention set2 0x%x\n",
-			  (u32)(attn & HW_INTERRUT_ASSERT_SET_2));
-		bnx2x_panic();
-	}
-}
-
-static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
-{
-	u32 val;
-
-	if (attn & EVEREST_GEN_ATTN_IN_USE_MASK) {
-
-		if (attn & BNX2X_PMF_LINK_ASSERT) {
-			int func = BP_FUNC(bp);
-
-			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0);
-			bp->mf_config = SHMEM_RD(bp,
-					   mf_cfg.func_mf_config[func].config);
-			val = SHMEM_RD(bp, func_mb[func].drv_status);
-			if (val & DRV_STATUS_DCC_EVENT_MASK)
-				bnx2x_dcc_event(bp,
-					    (val & DRV_STATUS_DCC_EVENT_MASK));
-			bnx2x__link_status_update(bp);
-			if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
-				bnx2x_pmf_update(bp);
-
-		} else if (attn & BNX2X_MC_ASSERT_BITS) {
-
-			BNX2X_ERR("MC assert!\n");
-			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_10, 0);
-			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_9, 0);
-			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_8, 0);
-			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_7, 0);
-			bnx2x_panic();
-
-		} else if (attn & BNX2X_MCP_ASSERT) {
-
-			BNX2X_ERR("MCP assert!\n");
-			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_11, 0);
-			bnx2x_fw_dump(bp);
-
-		} else
-			BNX2X_ERR("Unknown HW assert! (attn 0x%x)\n", attn);
-	}
-
-	if (attn & EVEREST_LATCHED_ATTN_IN_USE_MASK) {
-		BNX2X_ERR("LATCHED attention 0x%08x (masked)\n", attn);
-		if (attn & BNX2X_GRC_TIMEOUT) {
-			val = CHIP_IS_E1H(bp) ?
-				REG_RD(bp, MISC_REG_GRC_TIMEOUT_ATTN) : 0;
-			BNX2X_ERR("GRC time-out 0x%08x\n", val);
-		}
-		if (attn & BNX2X_GRC_RSV) {
-			val = CHIP_IS_E1H(bp) ?
-				REG_RD(bp, MISC_REG_GRC_RSV_ATTN) : 0;
-			BNX2X_ERR("GRC reserved 0x%08x\n", val);
-		}
-		REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x7ff);
-	}
-}
-
-static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode);
-static int bnx2x_nic_load(struct bnx2x *bp, int load_mode);
-
-
-#define BNX2X_MISC_GEN_REG      MISC_REG_GENERIC_POR_1
-#define LOAD_COUNTER_BITS	16 /* Number of bits for load counter */
-#define LOAD_COUNTER_MASK	(((u32)0x1 << LOAD_COUNTER_BITS) - 1)
-#define RESET_DONE_FLAG_MASK	(~LOAD_COUNTER_MASK)
-#define RESET_DONE_FLAG_SHIFT	LOAD_COUNTER_BITS
-#define CHIP_PARITY_SUPPORTED(bp)   (CHIP_IS_E1(bp) || CHIP_IS_E1H(bp))
-/*
- * should be run under rtnl lock
- */
-static inline void bnx2x_set_reset_done(struct bnx2x *bp)
-{
-	u32 val	= REG_RD(bp, BNX2X_MISC_GEN_REG);
-	val &= ~(1 << RESET_DONE_FLAG_SHIFT);
-	REG_WR(bp, BNX2X_MISC_GEN_REG, val);
-	barrier();
-	mmiowb();
-}
-
-/*
- * should be run under rtnl lock
- */
-static inline void bnx2x_set_reset_in_progress(struct bnx2x *bp)
-{
-	u32 val	= REG_RD(bp, BNX2X_MISC_GEN_REG);
-	val |= (1 << 16);
-	REG_WR(bp, BNX2X_MISC_GEN_REG, val);
-	barrier();
-	mmiowb();
-}
-
-/*
- * should be run under rtnl lock
- */
-static inline bool bnx2x_reset_is_done(struct bnx2x *bp)
-{
-	u32 val	= REG_RD(bp, BNX2X_MISC_GEN_REG);
-	DP(NETIF_MSG_HW, "GEN_REG_VAL=0x%08x\n", val);
-	return (val & RESET_DONE_FLAG_MASK) ? false : true;
-}
-
-/*
- * should be run under rtnl lock
- */
-static inline void bnx2x_inc_load_cnt(struct bnx2x *bp)
-{
-	u32 val1, val = REG_RD(bp, BNX2X_MISC_GEN_REG);
-
-	DP(NETIF_MSG_HW, "Old GEN_REG_VAL=0x%08x\n", val);
-
-	val1 = ((val & LOAD_COUNTER_MASK) + 1) & LOAD_COUNTER_MASK;
-	REG_WR(bp, BNX2X_MISC_GEN_REG, (val & RESET_DONE_FLAG_MASK) | val1);
-	barrier();
-	mmiowb();
-}
-
-/*
- * should be run under rtnl lock
- */
-static inline u32 bnx2x_dec_load_cnt(struct bnx2x *bp)
-{
-	u32 val1, val = REG_RD(bp, BNX2X_MISC_GEN_REG);
-
-	DP(NETIF_MSG_HW, "Old GEN_REG_VAL=0x%08x\n", val);
-
-	val1 = ((val & LOAD_COUNTER_MASK) - 1) & LOAD_COUNTER_MASK;
-	REG_WR(bp, BNX2X_MISC_GEN_REG, (val & RESET_DONE_FLAG_MASK) | val1);
-	barrier();
-	mmiowb();
-
-	return val1;
-}
-
-/*
- * should be run under rtnl lock
- */
-static inline u32 bnx2x_get_load_cnt(struct bnx2x *bp)
-{
-	return REG_RD(bp, BNX2X_MISC_GEN_REG) & LOAD_COUNTER_MASK;
-}
-
-static inline void bnx2x_clear_load_cnt(struct bnx2x *bp)
-{
-	u32 val = REG_RD(bp, BNX2X_MISC_GEN_REG);
-	REG_WR(bp, BNX2X_MISC_GEN_REG, val & (~LOAD_COUNTER_MASK));
-}
-
-static inline void _print_next_block(int idx, const char *blk)
-{
-	if (idx)
-		pr_cont(", ");
-	pr_cont("%s", blk);
-}
-
-static inline int bnx2x_print_blocks_with_parity0(u32 sig, int par_num)
-{
-	int i = 0;
-	u32 cur_bit = 0;
-	for (i = 0; sig; i++) {
-		cur_bit = ((u32)0x1 << i);
-		if (sig & cur_bit) {
-			switch (cur_bit) {
-			case AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR:
-				_print_next_block(par_num++, "BRB");
-				break;
-			case AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR:
-				_print_next_block(par_num++, "PARSER");
-				break;
-			case AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR:
-				_print_next_block(par_num++, "TSDM");
-				break;
-			case AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR:
-				_print_next_block(par_num++, "SEARCHER");
-				break;
-			case AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR:
-				_print_next_block(par_num++, "TSEMI");
-				break;
-			}
-
-			/* Clear the bit */
-			sig &= ~cur_bit;
-		}
-	}
-
-	return par_num;
-}
-
-static inline int bnx2x_print_blocks_with_parity1(u32 sig, int par_num)
-{
-	int i = 0;
-	u32 cur_bit = 0;
-	for (i = 0; sig; i++) {
-		cur_bit = ((u32)0x1 << i);
-		if (sig & cur_bit) {
-			switch (cur_bit) {
-			case AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR:
-				_print_next_block(par_num++, "PBCLIENT");
-				break;
-			case AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR:
-				_print_next_block(par_num++, "QM");
-				break;
-			case AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR:
-				_print_next_block(par_num++, "XSDM");
-				break;
-			case AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR:
-				_print_next_block(par_num++, "XSEMI");
-				break;
-			case AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR:
-				_print_next_block(par_num++, "DOORBELLQ");
-				break;
-			case AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR:
-				_print_next_block(par_num++, "VAUX PCI CORE");
-				break;
-			case AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR:
-				_print_next_block(par_num++, "DEBUG");
-				break;
-			case AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR:
-				_print_next_block(par_num++, "USDM");
-				break;
-			case AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR:
-				_print_next_block(par_num++, "USEMI");
-				break;
-			case AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR:
-				_print_next_block(par_num++, "UPB");
-				break;
-			case AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR:
-				_print_next_block(par_num++, "CSDM");
-				break;
-			}
-
-			/* Clear the bit */
-			sig &= ~cur_bit;
-		}
-	}
-
-	return par_num;
-}
-
-static inline int bnx2x_print_blocks_with_parity2(u32 sig, int par_num)
-{
-	int i = 0;
-	u32 cur_bit = 0;
-	for (i = 0; sig; i++) {
-		cur_bit = ((u32)0x1 << i);
-		if (sig & cur_bit) {
-			switch (cur_bit) {
-			case AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR:
-				_print_next_block(par_num++, "CSEMI");
-				break;
-			case AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR:
-				_print_next_block(par_num++, "PXP");
-				break;
-			case AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR:
-				_print_next_block(par_num++,
-					"PXPPCICLOCKCLIENT");
-				break;
-			case AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR:
-				_print_next_block(par_num++, "CFC");
-				break;
-			case AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR:
-				_print_next_block(par_num++, "CDU");
-				break;
-			case AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR:
-				_print_next_block(par_num++, "IGU");
-				break;
-			case AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR:
-				_print_next_block(par_num++, "MISC");
-				break;
-			}
-
-			/* Clear the bit */
-			sig &= ~cur_bit;
-		}
-	}
-
-	return par_num;
-}
-
-static inline int bnx2x_print_blocks_with_parity3(u32 sig, int par_num)
-{
-	int i = 0;
-	u32 cur_bit = 0;
-	for (i = 0; sig; i++) {
-		cur_bit = ((u32)0x1 << i);
-		if (sig & cur_bit) {
-			switch (cur_bit) {
-			case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY:
-				_print_next_block(par_num++, "MCP ROM");
-				break;
-			case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY:
-				_print_next_block(par_num++, "MCP UMP RX");
-				break;
-			case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY:
-				_print_next_block(par_num++, "MCP UMP TX");
-				break;
-			case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY:
-				_print_next_block(par_num++, "MCP SCPAD");
-				break;
-			}
-
-			/* Clear the bit */
-			sig &= ~cur_bit;
-		}
-	}
-
-	return par_num;
-}
-
-static inline bool bnx2x_parity_attn(struct bnx2x *bp, u32 sig0, u32 sig1,
-				     u32 sig2, u32 sig3)
-{
-	if ((sig0 & HW_PRTY_ASSERT_SET_0) || (sig1 & HW_PRTY_ASSERT_SET_1) ||
-	    (sig2 & HW_PRTY_ASSERT_SET_2) || (sig3 & HW_PRTY_ASSERT_SET_3)) {
-		int par_num = 0;
-		DP(NETIF_MSG_HW, "Was parity error: HW block parity attention: "
-			"[0]:0x%08x [1]:0x%08x "
-			"[2]:0x%08x [3]:0x%08x\n",
-			  sig0 & HW_PRTY_ASSERT_SET_0,
-			  sig1 & HW_PRTY_ASSERT_SET_1,
-			  sig2 & HW_PRTY_ASSERT_SET_2,
-			  sig3 & HW_PRTY_ASSERT_SET_3);
-		printk(KERN_ERR"%s: Parity errors detected in blocks: ",
-		       bp->dev->name);
-		par_num = bnx2x_print_blocks_with_parity0(
-			sig0 & HW_PRTY_ASSERT_SET_0, par_num);
-		par_num = bnx2x_print_blocks_with_parity1(
-			sig1 & HW_PRTY_ASSERT_SET_1, par_num);
-		par_num = bnx2x_print_blocks_with_parity2(
-			sig2 & HW_PRTY_ASSERT_SET_2, par_num);
-		par_num = bnx2x_print_blocks_with_parity3(
-			sig3 & HW_PRTY_ASSERT_SET_3, par_num);
-		printk("\n");
-		return true;
-	} else
-		return false;
-}
-
-static bool bnx2x_chk_parity_attn(struct bnx2x *bp)
-{
-	struct attn_route attn;
-	int port = BP_PORT(bp);
-
-	attn.sig[0] = REG_RD(bp,
-		MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 +
-			     port*4);
-	attn.sig[1] = REG_RD(bp,
-		MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 +
-			     port*4);
-	attn.sig[2] = REG_RD(bp,
-		MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 +
-			     port*4);
-	attn.sig[3] = REG_RD(bp,
-		MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 +
-			     port*4);
-
-	return bnx2x_parity_attn(bp, attn.sig[0], attn.sig[1], attn.sig[2],
-					attn.sig[3]);
-}
-
-static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
-{
-	struct attn_route attn, *group_mask;
-	int port = BP_PORT(bp);
-	int index;
-	u32 reg_addr;
-	u32 val;
-	u32 aeu_mask;
-
-	/* need to take HW lock because MCP or other port might also
-	   try to handle this event */
-	bnx2x_acquire_alr(bp);
-
-	if (bnx2x_chk_parity_attn(bp)) {
-		bp->recovery_state = BNX2X_RECOVERY_INIT;
-		bnx2x_set_reset_in_progress(bp);
-		schedule_delayed_work(&bp->reset_task, 0);
-		/* Disable HW interrupts */
-		bnx2x_int_disable(bp);
-		bnx2x_release_alr(bp);
-		/* In case of parity errors don't handle attentions so that
-		 * other function would "see" parity errors.
-		 */
-		return;
-	}
-
-	attn.sig[0] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + port*4);
-	attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4);
-	attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4);
-	attn.sig[3] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + port*4);
-	DP(NETIF_MSG_HW, "attn: %08x %08x %08x %08x\n",
-	   attn.sig[0], attn.sig[1], attn.sig[2], attn.sig[3]);
-
-	for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
-		if (deasserted & (1 << index)) {
-			group_mask = &bp->attn_group[index];
-
-			DP(NETIF_MSG_HW, "group[%d]: %08x %08x %08x %08x\n",
-			   index, group_mask->sig[0], group_mask->sig[1],
-			   group_mask->sig[2], group_mask->sig[3]);
-
-			bnx2x_attn_int_deasserted3(bp,
-					attn.sig[3] & group_mask->sig[3]);
-			bnx2x_attn_int_deasserted1(bp,
-					attn.sig[1] & group_mask->sig[1]);
-			bnx2x_attn_int_deasserted2(bp,
-					attn.sig[2] & group_mask->sig[2]);
-			bnx2x_attn_int_deasserted0(bp,
-					attn.sig[0] & group_mask->sig[0]);
-		}
-	}
-
-	bnx2x_release_alr(bp);
-
-	reg_addr = (HC_REG_COMMAND_REG + port*32 + COMMAND_REG_ATTN_BITS_CLR);
-
-	val = ~deasserted;
-	DP(NETIF_MSG_HW, "about to mask 0x%08x at HC addr 0x%x\n",
-	   val, reg_addr);
-	REG_WR(bp, reg_addr, val);
-
-	if (~bp->attn_state & deasserted)
-		BNX2X_ERR("IGU ERROR\n");
-
-	reg_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
-			  MISC_REG_AEU_MASK_ATTN_FUNC_0;
-
-	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port);
-	aeu_mask = REG_RD(bp, reg_addr);
-
-	DP(NETIF_MSG_HW, "aeu_mask %x  newly deasserted %x\n",
-	   aeu_mask, deasserted);
-	aeu_mask |= (deasserted & 0x3ff);
-	DP(NETIF_MSG_HW, "new mask %x\n", aeu_mask);
-
-	REG_WR(bp, reg_addr, aeu_mask);
-	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port);
-
-	DP(NETIF_MSG_HW, "attn_state %x\n", bp->attn_state);
-	bp->attn_state &= ~deasserted;
-	DP(NETIF_MSG_HW, "new state %x\n", bp->attn_state);
-}
-
-static void bnx2x_attn_int(struct bnx2x *bp)
-{
-	/* read local copy of bits */
-	u32 attn_bits = le32_to_cpu(bp->def_status_blk->atten_status_block.
-								attn_bits);
-	u32 attn_ack = le32_to_cpu(bp->def_status_blk->atten_status_block.
-								attn_bits_ack);
-	u32 attn_state = bp->attn_state;
-
-	/* look for changed bits */
-	u32 asserted   =  attn_bits & ~attn_ack & ~attn_state;
-	u32 deasserted = ~attn_bits &  attn_ack &  attn_state;
-
-	DP(NETIF_MSG_HW,
-	   "attn_bits %x  attn_ack %x  asserted %x  deasserted %x\n",
-	   attn_bits, attn_ack, asserted, deasserted);
-
-	if (~(attn_bits ^ attn_ack) & (attn_bits ^ attn_state))
-		BNX2X_ERR("BAD attention state\n");
-
-	/* handle bits that were raised */
-	if (asserted)
-		bnx2x_attn_int_asserted(bp, asserted);
-
-	if (deasserted)
-		bnx2x_attn_int_deasserted(bp, deasserted);
-}
-
-static void bnx2x_sp_task(struct work_struct *work)
-{
-	struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work);
-	u16 status;
-
-	/* Return here if interrupt is disabled */
-	if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
-		DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
-		return;
-	}
-
-	status = bnx2x_update_dsb_idx(bp);
-/*	if (status == 0)				     */
-/*		BNX2X_ERR("spurious slowpath interrupt!\n"); */
-
-	DP(NETIF_MSG_INTR, "got a slowpath interrupt (status 0x%x)\n", status);
-
-	/* HW attentions */
-	if (status & 0x1) {
-		bnx2x_attn_int(bp);
-		status &= ~0x1;
-	}
-
-	/* CStorm events: STAT_QUERY */
-	if (status & 0x2) {
-		DP(BNX2X_MSG_SP, "CStorm events: STAT_QUERY\n");
-		status &= ~0x2;
-	}
-
-	if (unlikely(status))
-		DP(NETIF_MSG_INTR, "got an unknown interrupt! (status 0x%x)\n",
-		   status);
-
-	bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, le16_to_cpu(bp->def_att_idx),
-		     IGU_INT_NOP, 1);
-	bnx2x_ack_sb(bp, DEF_SB_ID, USTORM_ID, le16_to_cpu(bp->def_u_idx),
-		     IGU_INT_NOP, 1);
-	bnx2x_ack_sb(bp, DEF_SB_ID, CSTORM_ID, le16_to_cpu(bp->def_c_idx),
-		     IGU_INT_NOP, 1);
-	bnx2x_ack_sb(bp, DEF_SB_ID, XSTORM_ID, le16_to_cpu(bp->def_x_idx),
-		     IGU_INT_NOP, 1);
-	bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, le16_to_cpu(bp->def_t_idx),
-		     IGU_INT_ENABLE, 1);
-}
-
-static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
-{
-	struct net_device *dev = dev_instance;
-	struct bnx2x *bp = netdev_priv(dev);
-
-	/* Return here if interrupt is disabled */
-	if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
-		DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
-		return IRQ_HANDLED;
-	}
-
-	bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, 0, IGU_INT_DISABLE, 0);
-
-#ifdef BNX2X_STOP_ON_ERROR
-	if (unlikely(bp->panic))
-		return IRQ_HANDLED;
-#endif
-
-#ifdef BCM_CNIC
-	{
-		struct cnic_ops *c_ops;
-
-		rcu_read_lock();
-		c_ops = rcu_dereference(bp->cnic_ops);
-		if (c_ops)
-			c_ops->cnic_handler(bp->cnic_data, NULL);
-		rcu_read_unlock();
-	}
-#endif
-	queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
-
-	return IRQ_HANDLED;
-}
-
-/* end of slow path */
-
-/* Statistics */
-
-/****************************************************************************
-* Macros
-****************************************************************************/
-
-/* sum[hi:lo] += add[hi:lo] */
-#define ADD_64(s_hi, a_hi, s_lo, a_lo) \
-	do { \
-		s_lo += a_lo; \
-		s_hi += a_hi + ((s_lo < a_lo) ? 1 : 0); \
-	} while (0)
-
-/* difference = minuend - subtrahend */
-#define DIFF_64(d_hi, m_hi, s_hi, d_lo, m_lo, s_lo) \
-	do { \
-		if (m_lo < s_lo) { \
-			/* underflow */ \
-			d_hi = m_hi - s_hi; \
-			if (d_hi > 0) { \
-				/* we can 'loan' 1 */ \
-				d_hi--; \
-				d_lo = m_lo + (UINT_MAX - s_lo) + 1; \
-			} else { \
-				/* m_hi <= s_hi */ \
-				d_hi = 0; \
-				d_lo = 0; \
-			} \
-		} else { \
-			/* m_lo >= s_lo */ \
-			if (m_hi < s_hi) { \
-				d_hi = 0; \
-				d_lo = 0; \
-			} else { \
-				/* m_hi >= s_hi */ \
-				d_hi = m_hi - s_hi; \
-				d_lo = m_lo - s_lo; \
-			} \
-		} \
-	} while (0)
-
-#define UPDATE_STAT64(s, t) \
-	do { \
-		DIFF_64(diff.hi, new->s##_hi, pstats->mac_stx[0].t##_hi, \
-			diff.lo, new->s##_lo, pstats->mac_stx[0].t##_lo); \
-		pstats->mac_stx[0].t##_hi = new->s##_hi; \
-		pstats->mac_stx[0].t##_lo = new->s##_lo; \
-		ADD_64(pstats->mac_stx[1].t##_hi, diff.hi, \
-		       pstats->mac_stx[1].t##_lo, diff.lo); \
-	} while (0)
-
-#define UPDATE_STAT64_NIG(s, t) \
-	do { \
-		DIFF_64(diff.hi, new->s##_hi, old->s##_hi, \
-			diff.lo, new->s##_lo, old->s##_lo); \
-		ADD_64(estats->t##_hi, diff.hi, \
-		       estats->t##_lo, diff.lo); \
-	} while (0)
-
-/* sum[hi:lo] += add */
-#define ADD_EXTEND_64(s_hi, s_lo, a) \
-	do { \
-		s_lo += a; \
-		s_hi += (s_lo < a) ? 1 : 0; \
-	} while (0)
-
-#define UPDATE_EXTEND_STAT(s) \
-	do { \
-		ADD_EXTEND_64(pstats->mac_stx[1].s##_hi, \
-			      pstats->mac_stx[1].s##_lo, \
-			      new->s); \
-	} while (0)
-
-#define UPDATE_EXTEND_TSTAT(s, t) \
-	do { \
-		diff = le32_to_cpu(tclient->s) - le32_to_cpu(old_tclient->s); \
-		old_tclient->s = tclient->s; \
-		ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
-	} while (0)
-
-#define UPDATE_EXTEND_USTAT(s, t) \
-	do { \
-		diff = le32_to_cpu(uclient->s) - le32_to_cpu(old_uclient->s); \
-		old_uclient->s = uclient->s; \
-		ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
-	} while (0)
-
-#define UPDATE_EXTEND_XSTAT(s, t) \
-	do { \
-		diff = le32_to_cpu(xclient->s) - le32_to_cpu(old_xclient->s); \
-		old_xclient->s = xclient->s; \
-		ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
-	} while (0)
-
-/* minuend -= subtrahend */
-#define SUB_64(m_hi, s_hi, m_lo, s_lo) \
-	do { \
-		DIFF_64(m_hi, m_hi, s_hi, m_lo, m_lo, s_lo); \
-	} while (0)
-
-/* minuend[hi:lo] -= subtrahend */
-#define SUB_EXTEND_64(m_hi, m_lo, s) \
-	do { \
-		SUB_64(m_hi, 0, m_lo, s); \
-	} while (0)
-
-#define SUB_EXTEND_USTAT(s, t) \
-	do { \
-		diff = le32_to_cpu(uclient->s) - le32_to_cpu(old_uclient->s); \
-		SUB_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
-	} while (0)
-
-/*
- * General service functions
- */
-
-static inline long bnx2x_hilo(u32 *hiref)
-{
-	u32 lo = *(hiref + 1);
-#if (BITS_PER_LONG == 64)
-	u32 hi = *hiref;
-
-	return HILO_U64(hi, lo);
-#else
-	return lo;
-#endif
-}
-
-/*
- * Init service functions
- */
-
-static void bnx2x_storm_stats_post(struct bnx2x *bp)
-{
-	if (!bp->stats_pending) {
-		struct eth_query_ramrod_data ramrod_data = {0};
-		int i, rc;
-
-		spin_lock_bh(&bp->stats_lock);
-
-		ramrod_data.drv_counter = bp->stats_counter++;
-		ramrod_data.collect_port = bp->port.pmf ? 1 : 0;
-		for_each_queue(bp, i)
-			ramrod_data.ctr_id_vector |= (1 << bp->fp[i].cl_id);
-
-		rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_STAT_QUERY, 0,
-				   ((u32 *)&ramrod_data)[1],
-				   ((u32 *)&ramrod_data)[0], 0);
-		if (rc == 0) {
-			/* stats ramrod has it's own slot on the spq */
-			bp->spq_left++;
-			bp->stats_pending = 1;
-		}
-
-		spin_unlock_bh(&bp->stats_lock);
-	}
-}
-
-static void bnx2x_hw_stats_post(struct bnx2x *bp)
-{
-	struct dmae_command *dmae = &bp->stats_dmae;
-	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
-	*stats_comp = DMAE_COMP_VAL;
-	if (CHIP_REV_IS_SLOW(bp))
-		return;
-
-	/* loader */
-	if (bp->executer_idx) {
-		int loader_idx = PMF_DMAE_C(bp);
-
-		memset(dmae, 0, sizeof(struct dmae_command));
-
-		dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
-				DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
-				DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
-				DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
-				DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
-				(BP_PORT(bp) ? DMAE_CMD_PORT_1 :
-					       DMAE_CMD_PORT_0) |
-				(BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
-		dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, dmae[0]));
-		dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, dmae[0]));
-		dmae->dst_addr_lo = (DMAE_REG_CMD_MEM +
-				     sizeof(struct dmae_command) *
-				     (loader_idx + 1)) >> 2;
-		dmae->dst_addr_hi = 0;
-		dmae->len = sizeof(struct dmae_command) >> 2;
-		if (CHIP_IS_E1(bp))
-			dmae->len--;
-		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx + 1] >> 2;
-		dmae->comp_addr_hi = 0;
-		dmae->comp_val = 1;
-
-		*stats_comp = 0;
-		bnx2x_post_dmae(bp, dmae, loader_idx);
-
-	} else if (bp->func_stx) {
-		*stats_comp = 0;
-		bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));
-	}
-}
-
-static int bnx2x_stats_comp(struct bnx2x *bp)
-{
-	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-	int cnt = 10;
-
-	might_sleep();
-	while (*stats_comp != DMAE_COMP_VAL) {
-		if (!cnt) {
-			BNX2X_ERR("timeout waiting for stats finished\n");
-			break;
-		}
-		cnt--;
-		msleep(1);
-	}
-	return 1;
-}
-
-/*
- * Statistics service functions
- */
-
-static void bnx2x_stats_pmf_update(struct bnx2x *bp)
-{
-	struct dmae_command *dmae;
-	u32 opcode;
-	int loader_idx = PMF_DMAE_C(bp);
-	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
-	/* sanity */
-	if (!IS_E1HMF(bp) || !bp->port.pmf || !bp->port.port_stx) {
-		BNX2X_ERR("BUG!\n");
-		return;
-	}
-
-	bp->executer_idx = 0;
-
-	opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
-		  DMAE_CMD_C_ENABLE |
-		  DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
-		  DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
-		  DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
-		  (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
-		  (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
-
-	dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-	dmae->opcode = (opcode | DMAE_CMD_C_DST_GRC);
-	dmae->src_addr_lo = bp->port.port_stx >> 2;
-	dmae->src_addr_hi = 0;
-	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
-	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
-	dmae->len = DMAE_LEN32_RD_MAX;
-	dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
-	dmae->comp_addr_hi = 0;
-	dmae->comp_val = 1;
-
-	dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-	dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
-	dmae->src_addr_lo = (bp->port.port_stx >> 2) + DMAE_LEN32_RD_MAX;
-	dmae->src_addr_hi = 0;
-	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats) +
-				   DMAE_LEN32_RD_MAX * 4);
-	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats) +
-				   DMAE_LEN32_RD_MAX * 4);
-	dmae->len = (sizeof(struct host_port_stats) >> 2) - DMAE_LEN32_RD_MAX;
-	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
-	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
-	dmae->comp_val = DMAE_COMP_VAL;
-
-	*stats_comp = 0;
-	bnx2x_hw_stats_post(bp);
-	bnx2x_stats_comp(bp);
-}
-
-static void bnx2x_port_stats_init(struct bnx2x *bp)
-{
-	struct dmae_command *dmae;
-	int port = BP_PORT(bp);
-	int vn = BP_E1HVN(bp);
-	u32 opcode;
-	int loader_idx = PMF_DMAE_C(bp);
-	u32 mac_addr;
-	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
-	/* sanity */
-	if (!bp->link_vars.link_up || !bp->port.pmf) {
-		BNX2X_ERR("BUG!\n");
-		return;
-	}
-
-	bp->executer_idx = 0;
-
-	/* MCP */
-	opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
-		  DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
-		  DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
-		  DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
-		  DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
-		  (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
-		  (vn << DMAE_CMD_E1HVN_SHIFT));
-
-	if (bp->port.port_stx) {
-
-		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-		dmae->opcode = opcode;
-		dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
-		dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
-		dmae->dst_addr_lo = bp->port.port_stx >> 2;
-		dmae->dst_addr_hi = 0;
-		dmae->len = sizeof(struct host_port_stats) >> 2;
-		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
-		dmae->comp_addr_hi = 0;
-		dmae->comp_val = 1;
-	}
-
-	if (bp->func_stx) {
-
-		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-		dmae->opcode = opcode;
-		dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
-		dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
-		dmae->dst_addr_lo = bp->func_stx >> 2;
-		dmae->dst_addr_hi = 0;
-		dmae->len = sizeof(struct host_func_stats) >> 2;
-		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
-		dmae->comp_addr_hi = 0;
-		dmae->comp_val = 1;
-	}
-
-	/* MAC */
-	opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
-		  DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
-		  DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
-		  DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
-		  DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
-		  (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
-		  (vn << DMAE_CMD_E1HVN_SHIFT));
-
-	if (bp->link_vars.mac_type == MAC_TYPE_BMAC) {
-
-		mac_addr = (port ? NIG_REG_INGRESS_BMAC1_MEM :
-				   NIG_REG_INGRESS_BMAC0_MEM);
-
-		/* BIGMAC_REGISTER_TX_STAT_GTPKT ..
-		   BIGMAC_REGISTER_TX_STAT_GTBYT */
-		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-		dmae->opcode = opcode;
-		dmae->src_addr_lo = (mac_addr +
-				     BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2;
-		dmae->src_addr_hi = 0;
-		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats));
-		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats));
-		dmae->len = (8 + BIGMAC_REGISTER_TX_STAT_GTBYT -
-			     BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2;
-		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
-		dmae->comp_addr_hi = 0;
-		dmae->comp_val = 1;
-
-		/* BIGMAC_REGISTER_RX_STAT_GR64 ..
-		   BIGMAC_REGISTER_RX_STAT_GRIPJ */
-		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-		dmae->opcode = opcode;
-		dmae->src_addr_lo = (mac_addr +
-				     BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
-		dmae->src_addr_hi = 0;
-		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
-				offsetof(struct bmac_stats, rx_stat_gr64_lo));
-		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
-				offsetof(struct bmac_stats, rx_stat_gr64_lo));
-		dmae->len = (8 + BIGMAC_REGISTER_RX_STAT_GRIPJ -
-			     BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
-		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
-		dmae->comp_addr_hi = 0;
-		dmae->comp_val = 1;
-
-	} else if (bp->link_vars.mac_type == MAC_TYPE_EMAC) {
-
-		mac_addr = (port ? GRCBASE_EMAC1 : GRCBASE_EMAC0);
-
-		/* EMAC_REG_EMAC_RX_STAT_AC (EMAC_REG_EMAC_RX_STAT_AC_COUNT)*/
-		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-		dmae->opcode = opcode;
-		dmae->src_addr_lo = (mac_addr +
-				     EMAC_REG_EMAC_RX_STAT_AC) >> 2;
-		dmae->src_addr_hi = 0;
-		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats));
-		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats));
-		dmae->len = EMAC_REG_EMAC_RX_STAT_AC_COUNT;
-		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
-		dmae->comp_addr_hi = 0;
-		dmae->comp_val = 1;
-
-		/* EMAC_REG_EMAC_RX_STAT_AC_28 */
-		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-		dmae->opcode = opcode;
-		dmae->src_addr_lo = (mac_addr +
-				     EMAC_REG_EMAC_RX_STAT_AC_28) >> 2;
-		dmae->src_addr_hi = 0;
-		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
-		     offsetof(struct emac_stats, rx_stat_falsecarriererrors));
-		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
-		     offsetof(struct emac_stats, rx_stat_falsecarriererrors));
-		dmae->len = 1;
-		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
-		dmae->comp_addr_hi = 0;
-		dmae->comp_val = 1;
-
-		/* EMAC_REG_EMAC_TX_STAT_AC (EMAC_REG_EMAC_TX_STAT_AC_COUNT)*/
-		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-		dmae->opcode = opcode;
-		dmae->src_addr_lo = (mac_addr +
-				     EMAC_REG_EMAC_TX_STAT_AC) >> 2;
-		dmae->src_addr_hi = 0;
-		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
-			offsetof(struct emac_stats, tx_stat_ifhcoutoctets));
-		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
-			offsetof(struct emac_stats, tx_stat_ifhcoutoctets));
-		dmae->len = EMAC_REG_EMAC_TX_STAT_AC_COUNT;
-		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
-		dmae->comp_addr_hi = 0;
-		dmae->comp_val = 1;
-	}
-
-	/* NIG */
-	dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-	dmae->opcode = opcode;
-	dmae->src_addr_lo = (port ? NIG_REG_STAT1_BRB_DISCARD :
-				    NIG_REG_STAT0_BRB_DISCARD) >> 2;
-	dmae->src_addr_hi = 0;
-	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats));
-	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats));
-	dmae->len = (sizeof(struct nig_stats) - 4*sizeof(u32)) >> 2;
-	dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
-	dmae->comp_addr_hi = 0;
-	dmae->comp_val = 1;
-
-	dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-	dmae->opcode = opcode;
-	dmae->src_addr_lo = (port ? NIG_REG_STAT1_EGRESS_MAC_PKT0 :
-				    NIG_REG_STAT0_EGRESS_MAC_PKT0) >> 2;
-	dmae->src_addr_hi = 0;
-	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats) +
-			offsetof(struct nig_stats, egress_mac_pkt0_lo));
-	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats) +
-			offsetof(struct nig_stats, egress_mac_pkt0_lo));
-	dmae->len = (2*sizeof(u32)) >> 2;
-	dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
-	dmae->comp_addr_hi = 0;
-	dmae->comp_val = 1;
-
-	dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-	dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
-			DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
-			DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
-			DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
-			DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
-			(port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
-			(vn << DMAE_CMD_E1HVN_SHIFT));
-	dmae->src_addr_lo = (port ? NIG_REG_STAT1_EGRESS_MAC_PKT1 :
-				    NIG_REG_STAT0_EGRESS_MAC_PKT1) >> 2;
-	dmae->src_addr_hi = 0;
-	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats) +
-			offsetof(struct nig_stats, egress_mac_pkt1_lo));
-	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats) +
-			offsetof(struct nig_stats, egress_mac_pkt1_lo));
-	dmae->len = (2*sizeof(u32)) >> 2;
-	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
-	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
-	dmae->comp_val = DMAE_COMP_VAL;
-
-	*stats_comp = 0;
-}
-
-static void bnx2x_func_stats_init(struct bnx2x *bp)
-{
-	struct dmae_command *dmae = &bp->stats_dmae;
-	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
-	/* sanity */
-	if (!bp->func_stx) {
-		BNX2X_ERR("BUG!\n");
-		return;
-	}
-
-	bp->executer_idx = 0;
-	memset(dmae, 0, sizeof(struct dmae_command));
-
-	dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
-			DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
-			DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
-			DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
-			DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
-			(BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
-			(BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
-	dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
-	dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
-	dmae->dst_addr_lo = bp->func_stx >> 2;
-	dmae->dst_addr_hi = 0;
-	dmae->len = sizeof(struct host_func_stats) >> 2;
-	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
-	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
-	dmae->comp_val = DMAE_COMP_VAL;
-
-	*stats_comp = 0;
-}
-
-static void bnx2x_stats_start(struct bnx2x *bp)
-{
-	if (bp->port.pmf)
-		bnx2x_port_stats_init(bp);
-
-	else if (bp->func_stx)
-		bnx2x_func_stats_init(bp);
-
-	bnx2x_hw_stats_post(bp);
-	bnx2x_storm_stats_post(bp);
-}
-
-static void bnx2x_stats_pmf_start(struct bnx2x *bp)
-{
-	bnx2x_stats_comp(bp);
-	bnx2x_stats_pmf_update(bp);
-	bnx2x_stats_start(bp);
-}
-
-static void bnx2x_stats_restart(struct bnx2x *bp)
-{
-	bnx2x_stats_comp(bp);
-	bnx2x_stats_start(bp);
-}
-
-static void bnx2x_bmac_stats_update(struct bnx2x *bp)
-{
-	struct bmac_stats *new = bnx2x_sp(bp, mac_stats.bmac_stats);
-	struct host_port_stats *pstats = bnx2x_sp(bp, port_stats);
-	struct bnx2x_eth_stats *estats = &bp->eth_stats;
-	struct {
-		u32 lo;
-		u32 hi;
-	} diff;
-
-	UPDATE_STAT64(rx_stat_grerb, rx_stat_ifhcinbadoctets);
-	UPDATE_STAT64(rx_stat_grfcs, rx_stat_dot3statsfcserrors);
-	UPDATE_STAT64(rx_stat_grund, rx_stat_etherstatsundersizepkts);
-	UPDATE_STAT64(rx_stat_grovr, rx_stat_dot3statsframestoolong);
-	UPDATE_STAT64(rx_stat_grfrg, rx_stat_etherstatsfragments);
-	UPDATE_STAT64(rx_stat_grjbr, rx_stat_etherstatsjabbers);
-	UPDATE_STAT64(rx_stat_grxcf, rx_stat_maccontrolframesreceived);
-	UPDATE_STAT64(rx_stat_grxpf, rx_stat_xoffstateentered);
-	UPDATE_STAT64(rx_stat_grxpf, rx_stat_bmac_xpf);
-	UPDATE_STAT64(tx_stat_gtxpf, tx_stat_outxoffsent);
-	UPDATE_STAT64(tx_stat_gtxpf, tx_stat_flowcontroldone);
-	UPDATE_STAT64(tx_stat_gt64, tx_stat_etherstatspkts64octets);
-	UPDATE_STAT64(tx_stat_gt127,
-				tx_stat_etherstatspkts65octetsto127octets);
-	UPDATE_STAT64(tx_stat_gt255,
-				tx_stat_etherstatspkts128octetsto255octets);
-	UPDATE_STAT64(tx_stat_gt511,
-				tx_stat_etherstatspkts256octetsto511octets);
-	UPDATE_STAT64(tx_stat_gt1023,
-				tx_stat_etherstatspkts512octetsto1023octets);
-	UPDATE_STAT64(tx_stat_gt1518,
-				tx_stat_etherstatspkts1024octetsto1522octets);
-	UPDATE_STAT64(tx_stat_gt2047, tx_stat_bmac_2047);
-	UPDATE_STAT64(tx_stat_gt4095, tx_stat_bmac_4095);
-	UPDATE_STAT64(tx_stat_gt9216, tx_stat_bmac_9216);
-	UPDATE_STAT64(tx_stat_gt16383, tx_stat_bmac_16383);
-	UPDATE_STAT64(tx_stat_gterr,
-				tx_stat_dot3statsinternalmactransmiterrors);
-	UPDATE_STAT64(tx_stat_gtufl, tx_stat_bmac_ufl);
-
-	estats->pause_frames_received_hi =
-				pstats->mac_stx[1].rx_stat_bmac_xpf_hi;
-	estats->pause_frames_received_lo =
-				pstats->mac_stx[1].rx_stat_bmac_xpf_lo;
-
-	estats->pause_frames_sent_hi =
-				pstats->mac_stx[1].tx_stat_outxoffsent_hi;
-	estats->pause_frames_sent_lo =
-				pstats->mac_stx[1].tx_stat_outxoffsent_lo;
-}
-
-static void bnx2x_emac_stats_update(struct bnx2x *bp)
-{
-	struct emac_stats *new = bnx2x_sp(bp, mac_stats.emac_stats);
-	struct host_port_stats *pstats = bnx2x_sp(bp, port_stats);
-	struct bnx2x_eth_stats *estats = &bp->eth_stats;
-
-	UPDATE_EXTEND_STAT(rx_stat_ifhcinbadoctets);
-	UPDATE_EXTEND_STAT(tx_stat_ifhcoutbadoctets);
-	UPDATE_EXTEND_STAT(rx_stat_dot3statsfcserrors);
-	UPDATE_EXTEND_STAT(rx_stat_dot3statsalignmenterrors);
-	UPDATE_EXTEND_STAT(rx_stat_dot3statscarriersenseerrors);
-	UPDATE_EXTEND_STAT(rx_stat_falsecarriererrors);
-	UPDATE_EXTEND_STAT(rx_stat_etherstatsundersizepkts);
-	UPDATE_EXTEND_STAT(rx_stat_dot3statsframestoolong);
-	UPDATE_EXTEND_STAT(rx_stat_etherstatsfragments);
-	UPDATE_EXTEND_STAT(rx_stat_etherstatsjabbers);
-	UPDATE_EXTEND_STAT(rx_stat_maccontrolframesreceived);
-	UPDATE_EXTEND_STAT(rx_stat_xoffstateentered);
-	UPDATE_EXTEND_STAT(rx_stat_xonpauseframesreceived);
-	UPDATE_EXTEND_STAT(rx_stat_xoffpauseframesreceived);
-	UPDATE_EXTEND_STAT(tx_stat_outxonsent);
-	UPDATE_EXTEND_STAT(tx_stat_outxoffsent);
-	UPDATE_EXTEND_STAT(tx_stat_flowcontroldone);
-	UPDATE_EXTEND_STAT(tx_stat_etherstatscollisions);
-	UPDATE_EXTEND_STAT(tx_stat_dot3statssinglecollisionframes);
-	UPDATE_EXTEND_STAT(tx_stat_dot3statsmultiplecollisionframes);
-	UPDATE_EXTEND_STAT(tx_stat_dot3statsdeferredtransmissions);
-	UPDATE_EXTEND_STAT(tx_stat_dot3statsexcessivecollisions);
-	UPDATE_EXTEND_STAT(tx_stat_dot3statslatecollisions);
-	UPDATE_EXTEND_STAT(tx_stat_etherstatspkts64octets);
-	UPDATE_EXTEND_STAT(tx_stat_etherstatspkts65octetsto127octets);
-	UPDATE_EXTEND_STAT(tx_stat_etherstatspkts128octetsto255octets);
-	UPDATE_EXTEND_STAT(tx_stat_etherstatspkts256octetsto511octets);
-	UPDATE_EXTEND_STAT(tx_stat_etherstatspkts512octetsto1023octets);
-	UPDATE_EXTEND_STAT(tx_stat_etherstatspkts1024octetsto1522octets);
-	UPDATE_EXTEND_STAT(tx_stat_etherstatspktsover1522octets);
-	UPDATE_EXTEND_STAT(tx_stat_dot3statsinternalmactransmiterrors);
-
-	estats->pause_frames_received_hi =
-			pstats->mac_stx[1].rx_stat_xonpauseframesreceived_hi;
-	estats->pause_frames_received_lo =
-			pstats->mac_stx[1].rx_stat_xonpauseframesreceived_lo;
-	ADD_64(estats->pause_frames_received_hi,
-	       pstats->mac_stx[1].rx_stat_xoffpauseframesreceived_hi,
-	       estats->pause_frames_received_lo,
-	       pstats->mac_stx[1].rx_stat_xoffpauseframesreceived_lo);
-
-	estats->pause_frames_sent_hi =
-			pstats->mac_stx[1].tx_stat_outxonsent_hi;
-	estats->pause_frames_sent_lo =
-			pstats->mac_stx[1].tx_stat_outxonsent_lo;
-	ADD_64(estats->pause_frames_sent_hi,
-	       pstats->mac_stx[1].tx_stat_outxoffsent_hi,
-	       estats->pause_frames_sent_lo,
-	       pstats->mac_stx[1].tx_stat_outxoffsent_lo);
-}
-
-static int bnx2x_hw_stats_update(struct bnx2x *bp)
-{
-	struct nig_stats *new = bnx2x_sp(bp, nig_stats);
-	struct nig_stats *old = &(bp->port.old_nig_stats);
-	struct host_port_stats *pstats = bnx2x_sp(bp, port_stats);
-	struct bnx2x_eth_stats *estats = &bp->eth_stats;
-	struct {
-		u32 lo;
-		u32 hi;
-	} diff;
-
-	if (bp->link_vars.mac_type == MAC_TYPE_BMAC)
-		bnx2x_bmac_stats_update(bp);
-
-	else if (bp->link_vars.mac_type == MAC_TYPE_EMAC)
-		bnx2x_emac_stats_update(bp);
-
-	else { /* unreached */
-		BNX2X_ERR("stats updated by DMAE but no MAC active\n");
-		return -1;
-	}
-
-	ADD_EXTEND_64(pstats->brb_drop_hi, pstats->brb_drop_lo,
-		      new->brb_discard - old->brb_discard);
-	ADD_EXTEND_64(estats->brb_truncate_hi, estats->brb_truncate_lo,
-		      new->brb_truncate - old->brb_truncate);
-
-	UPDATE_STAT64_NIG(egress_mac_pkt0,
-					etherstatspkts1024octetsto1522octets);
-	UPDATE_STAT64_NIG(egress_mac_pkt1, etherstatspktsover1522octets);
-
-	memcpy(old, new, sizeof(struct nig_stats));
-
-	memcpy(&(estats->rx_stat_ifhcinbadoctets_hi), &(pstats->mac_stx[1]),
-	       sizeof(struct mac_stx));
-	estats->brb_drop_hi = pstats->brb_drop_hi;
-	estats->brb_drop_lo = pstats->brb_drop_lo;
-
-	pstats->host_port_stats_start = ++pstats->host_port_stats_end;
-
-	if (!BP_NOMCP(bp)) {
-		u32 nig_timer_max =
-			SHMEM_RD(bp, port_mb[BP_PORT(bp)].stat_nig_timer);
-		if (nig_timer_max != estats->nig_timer_max) {
-			estats->nig_timer_max = nig_timer_max;
-			BNX2X_ERR("NIG timer max (%u)\n",
-				  estats->nig_timer_max);
-		}
-	}
-
-	return 0;
-}
-
-static int bnx2x_storm_stats_update(struct bnx2x *bp)
-{
-	struct eth_stats_query *stats = bnx2x_sp(bp, fw_stats);
-	struct tstorm_per_port_stats *tport =
-					&stats->tstorm_common.port_statistics;
-	struct host_func_stats *fstats = bnx2x_sp(bp, func_stats);
-	struct bnx2x_eth_stats *estats = &bp->eth_stats;
-	int i;
-	u16 cur_stats_counter;
-
-	/* Make sure we use the value of the counter
-	 * used for sending the last stats ramrod.
-	 */
-	spin_lock_bh(&bp->stats_lock);
-	cur_stats_counter = bp->stats_counter - 1;
-	spin_unlock_bh(&bp->stats_lock);
-
-	memcpy(&(fstats->total_bytes_received_hi),
-	       &(bnx2x_sp(bp, func_stats_base)->total_bytes_received_hi),
-	       sizeof(struct host_func_stats) - 2*sizeof(u32));
-	estats->error_bytes_received_hi = 0;
-	estats->error_bytes_received_lo = 0;
-	estats->etherstatsoverrsizepkts_hi = 0;
-	estats->etherstatsoverrsizepkts_lo = 0;
-	estats->no_buff_discard_hi = 0;
-	estats->no_buff_discard_lo = 0;
-
-	for_each_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-		int cl_id = fp->cl_id;
-		struct tstorm_per_client_stats *tclient =
-				&stats->tstorm_common.client_statistics[cl_id];
-		struct tstorm_per_client_stats *old_tclient = &fp->old_tclient;
-		struct ustorm_per_client_stats *uclient =
-				&stats->ustorm_common.client_statistics[cl_id];
-		struct ustorm_per_client_stats *old_uclient = &fp->old_uclient;
-		struct xstorm_per_client_stats *xclient =
-				&stats->xstorm_common.client_statistics[cl_id];
-		struct xstorm_per_client_stats *old_xclient = &fp->old_xclient;
-		struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
-		u32 diff;
-
-		/* are storm stats valid? */
-		if (le16_to_cpu(xclient->stats_counter) != cur_stats_counter) {
-			DP(BNX2X_MSG_STATS, "[%d] stats not updated by xstorm"
-			   "  xstorm counter (0x%x) != stats_counter (0x%x)\n",
-			   i, xclient->stats_counter, cur_stats_counter + 1);
-			return -1;
-		}
-		if (le16_to_cpu(tclient->stats_counter) != cur_stats_counter) {
-			DP(BNX2X_MSG_STATS, "[%d] stats not updated by tstorm"
-			   "  tstorm counter (0x%x) != stats_counter (0x%x)\n",
-			   i, tclient->stats_counter, cur_stats_counter + 1);
-			return -2;
-		}
-		if (le16_to_cpu(uclient->stats_counter) != cur_stats_counter) {
-			DP(BNX2X_MSG_STATS, "[%d] stats not updated by ustorm"
-			   "  ustorm counter (0x%x) != stats_counter (0x%x)\n",
-			   i, uclient->stats_counter, cur_stats_counter + 1);
-			return -4;
-		}
-
-		qstats->total_bytes_received_hi =
-			le32_to_cpu(tclient->rcv_broadcast_bytes.hi);
-		qstats->total_bytes_received_lo =
-			le32_to_cpu(tclient->rcv_broadcast_bytes.lo);
-
-		ADD_64(qstats->total_bytes_received_hi,
-		       le32_to_cpu(tclient->rcv_multicast_bytes.hi),
-		       qstats->total_bytes_received_lo,
-		       le32_to_cpu(tclient->rcv_multicast_bytes.lo));
-
-		ADD_64(qstats->total_bytes_received_hi,
-		       le32_to_cpu(tclient->rcv_unicast_bytes.hi),
-		       qstats->total_bytes_received_lo,
-		       le32_to_cpu(tclient->rcv_unicast_bytes.lo));
-
-		SUB_64(qstats->total_bytes_received_hi,
-		       le32_to_cpu(uclient->bcast_no_buff_bytes.hi),
-		       qstats->total_bytes_received_lo,
-		       le32_to_cpu(uclient->bcast_no_buff_bytes.lo));
-
-		SUB_64(qstats->total_bytes_received_hi,
-		       le32_to_cpu(uclient->mcast_no_buff_bytes.hi),
-		       qstats->total_bytes_received_lo,
-		       le32_to_cpu(uclient->mcast_no_buff_bytes.lo));
-
-		SUB_64(qstats->total_bytes_received_hi,
-		       le32_to_cpu(uclient->ucast_no_buff_bytes.hi),
-		       qstats->total_bytes_received_lo,
-		       le32_to_cpu(uclient->ucast_no_buff_bytes.lo));
-
-		qstats->valid_bytes_received_hi =
-					qstats->total_bytes_received_hi;
-		qstats->valid_bytes_received_lo =
-					qstats->total_bytes_received_lo;
-
-		qstats->error_bytes_received_hi =
-				le32_to_cpu(tclient->rcv_error_bytes.hi);
-		qstats->error_bytes_received_lo =
-				le32_to_cpu(tclient->rcv_error_bytes.lo);
-
-		ADD_64(qstats->total_bytes_received_hi,
-		       qstats->error_bytes_received_hi,
-		       qstats->total_bytes_received_lo,
-		       qstats->error_bytes_received_lo);
-
-		UPDATE_EXTEND_TSTAT(rcv_unicast_pkts,
-					total_unicast_packets_received);
-		UPDATE_EXTEND_TSTAT(rcv_multicast_pkts,
-					total_multicast_packets_received);
-		UPDATE_EXTEND_TSTAT(rcv_broadcast_pkts,
-					total_broadcast_packets_received);
-		UPDATE_EXTEND_TSTAT(packets_too_big_discard,
-					etherstatsoverrsizepkts);
-		UPDATE_EXTEND_TSTAT(no_buff_discard, no_buff_discard);
-
-		SUB_EXTEND_USTAT(ucast_no_buff_pkts,
-					total_unicast_packets_received);
-		SUB_EXTEND_USTAT(mcast_no_buff_pkts,
-					total_multicast_packets_received);
-		SUB_EXTEND_USTAT(bcast_no_buff_pkts,
-					total_broadcast_packets_received);
-		UPDATE_EXTEND_USTAT(ucast_no_buff_pkts, no_buff_discard);
-		UPDATE_EXTEND_USTAT(mcast_no_buff_pkts, no_buff_discard);
-		UPDATE_EXTEND_USTAT(bcast_no_buff_pkts, no_buff_discard);
-
-		qstats->total_bytes_transmitted_hi =
-				le32_to_cpu(xclient->unicast_bytes_sent.hi);
-		qstats->total_bytes_transmitted_lo =
-				le32_to_cpu(xclient->unicast_bytes_sent.lo);
-
-		ADD_64(qstats->total_bytes_transmitted_hi,
-		       le32_to_cpu(xclient->multicast_bytes_sent.hi),
-		       qstats->total_bytes_transmitted_lo,
-		       le32_to_cpu(xclient->multicast_bytes_sent.lo));
-
-		ADD_64(qstats->total_bytes_transmitted_hi,
-		       le32_to_cpu(xclient->broadcast_bytes_sent.hi),
-		       qstats->total_bytes_transmitted_lo,
-		       le32_to_cpu(xclient->broadcast_bytes_sent.lo));
-
-		UPDATE_EXTEND_XSTAT(unicast_pkts_sent,
-					total_unicast_packets_transmitted);
-		UPDATE_EXTEND_XSTAT(multicast_pkts_sent,
-					total_multicast_packets_transmitted);
-		UPDATE_EXTEND_XSTAT(broadcast_pkts_sent,
-					total_broadcast_packets_transmitted);
-
-		old_tclient->checksum_discard = tclient->checksum_discard;
-		old_tclient->ttl0_discard = tclient->ttl0_discard;
-
-		ADD_64(fstats->total_bytes_received_hi,
-		       qstats->total_bytes_received_hi,
-		       fstats->total_bytes_received_lo,
-		       qstats->total_bytes_received_lo);
-		ADD_64(fstats->total_bytes_transmitted_hi,
-		       qstats->total_bytes_transmitted_hi,
-		       fstats->total_bytes_transmitted_lo,
-		       qstats->total_bytes_transmitted_lo);
-		ADD_64(fstats->total_unicast_packets_received_hi,
-		       qstats->total_unicast_packets_received_hi,
-		       fstats->total_unicast_packets_received_lo,
-		       qstats->total_unicast_packets_received_lo);
-		ADD_64(fstats->total_multicast_packets_received_hi,
-		       qstats->total_multicast_packets_received_hi,
-		       fstats->total_multicast_packets_received_lo,
-		       qstats->total_multicast_packets_received_lo);
-		ADD_64(fstats->total_broadcast_packets_received_hi,
-		       qstats->total_broadcast_packets_received_hi,
-		       fstats->total_broadcast_packets_received_lo,
-		       qstats->total_broadcast_packets_received_lo);
-		ADD_64(fstats->total_unicast_packets_transmitted_hi,
-		       qstats->total_unicast_packets_transmitted_hi,
-		       fstats->total_unicast_packets_transmitted_lo,
-		       qstats->total_unicast_packets_transmitted_lo);
-		ADD_64(fstats->total_multicast_packets_transmitted_hi,
-		       qstats->total_multicast_packets_transmitted_hi,
-		       fstats->total_multicast_packets_transmitted_lo,
-		       qstats->total_multicast_packets_transmitted_lo);
-		ADD_64(fstats->total_broadcast_packets_transmitted_hi,
-		       qstats->total_broadcast_packets_transmitted_hi,
-		       fstats->total_broadcast_packets_transmitted_lo,
-		       qstats->total_broadcast_packets_transmitted_lo);
-		ADD_64(fstats->valid_bytes_received_hi,
-		       qstats->valid_bytes_received_hi,
-		       fstats->valid_bytes_received_lo,
-		       qstats->valid_bytes_received_lo);
-
-		ADD_64(estats->error_bytes_received_hi,
-		       qstats->error_bytes_received_hi,
-		       estats->error_bytes_received_lo,
-		       qstats->error_bytes_received_lo);
-		ADD_64(estats->etherstatsoverrsizepkts_hi,
-		       qstats->etherstatsoverrsizepkts_hi,
-		       estats->etherstatsoverrsizepkts_lo,
-		       qstats->etherstatsoverrsizepkts_lo);
-		ADD_64(estats->no_buff_discard_hi, qstats->no_buff_discard_hi,
-		       estats->no_buff_discard_lo, qstats->no_buff_discard_lo);
-	}
-
-	ADD_64(fstats->total_bytes_received_hi,
-	       estats->rx_stat_ifhcinbadoctets_hi,
-	       fstats->total_bytes_received_lo,
-	       estats->rx_stat_ifhcinbadoctets_lo);
-
-	memcpy(estats, &(fstats->total_bytes_received_hi),
-	       sizeof(struct host_func_stats) - 2*sizeof(u32));
-
-	ADD_64(estats->etherstatsoverrsizepkts_hi,
-	       estats->rx_stat_dot3statsframestoolong_hi,
-	       estats->etherstatsoverrsizepkts_lo,
-	       estats->rx_stat_dot3statsframestoolong_lo);
-	ADD_64(estats->error_bytes_received_hi,
-	       estats->rx_stat_ifhcinbadoctets_hi,
-	       estats->error_bytes_received_lo,
-	       estats->rx_stat_ifhcinbadoctets_lo);
-
-	if (bp->port.pmf) {
-		estats->mac_filter_discard =
-				le32_to_cpu(tport->mac_filter_discard);
-		estats->xxoverflow_discard =
-				le32_to_cpu(tport->xxoverflow_discard);
-		estats->brb_truncate_discard =
-				le32_to_cpu(tport->brb_truncate_discard);
-		estats->mac_discard = le32_to_cpu(tport->mac_discard);
-	}
-
-	fstats->host_func_stats_start = ++fstats->host_func_stats_end;
-
-	bp->stats_pending = 0;
-
-	return 0;
-}
-
-static void bnx2x_net_stats_update(struct bnx2x *bp)
-{
-	struct bnx2x_eth_stats *estats = &bp->eth_stats;
-	struct net_device_stats *nstats = &bp->dev->stats;
-	int i;
-
-	nstats->rx_packets =
-		bnx2x_hilo(&estats->total_unicast_packets_received_hi) +
-		bnx2x_hilo(&estats->total_multicast_packets_received_hi) +
-		bnx2x_hilo(&estats->total_broadcast_packets_received_hi);
-
-	nstats->tx_packets =
-		bnx2x_hilo(&estats->total_unicast_packets_transmitted_hi) +
-		bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi) +
-		bnx2x_hilo(&estats->total_broadcast_packets_transmitted_hi);
-
-	nstats->rx_bytes = bnx2x_hilo(&estats->total_bytes_received_hi);
-
-	nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi);
-
-	nstats->rx_dropped = estats->mac_discard;
-	for_each_queue(bp, i)
-		nstats->rx_dropped +=
-			le32_to_cpu(bp->fp[i].old_tclient.checksum_discard);
-
-	nstats->tx_dropped = 0;
-
-	nstats->multicast =
-		bnx2x_hilo(&estats->total_multicast_packets_received_hi);
-
-	nstats->collisions =
-		bnx2x_hilo(&estats->tx_stat_etherstatscollisions_hi);
-
-	nstats->rx_length_errors =
-		bnx2x_hilo(&estats->rx_stat_etherstatsundersizepkts_hi) +
-		bnx2x_hilo(&estats->etherstatsoverrsizepkts_hi);
-	nstats->rx_over_errors = bnx2x_hilo(&estats->brb_drop_hi) +
-				 bnx2x_hilo(&estats->brb_truncate_hi);
-	nstats->rx_crc_errors =
-		bnx2x_hilo(&estats->rx_stat_dot3statsfcserrors_hi);
-	nstats->rx_frame_errors =
-		bnx2x_hilo(&estats->rx_stat_dot3statsalignmenterrors_hi);
-	nstats->rx_fifo_errors = bnx2x_hilo(&estats->no_buff_discard_hi);
-	nstats->rx_missed_errors = estats->xxoverflow_discard;
-
-	nstats->rx_errors = nstats->rx_length_errors +
-			    nstats->rx_over_errors +
-			    nstats->rx_crc_errors +
-			    nstats->rx_frame_errors +
-			    nstats->rx_fifo_errors +
-			    nstats->rx_missed_errors;
-
-	nstats->tx_aborted_errors =
-		bnx2x_hilo(&estats->tx_stat_dot3statslatecollisions_hi) +
-		bnx2x_hilo(&estats->tx_stat_dot3statsexcessivecollisions_hi);
-	nstats->tx_carrier_errors =
-		bnx2x_hilo(&estats->rx_stat_dot3statscarriersenseerrors_hi);
-	nstats->tx_fifo_errors = 0;
-	nstats->tx_heartbeat_errors = 0;
-	nstats->tx_window_errors = 0;
-
-	nstats->tx_errors = nstats->tx_aborted_errors +
-			    nstats->tx_carrier_errors +
-	    bnx2x_hilo(&estats->tx_stat_dot3statsinternalmactransmiterrors_hi);
-}
-
-static void bnx2x_drv_stats_update(struct bnx2x *bp)
-{
-	struct bnx2x_eth_stats *estats = &bp->eth_stats;
-	int i;
-
-	estats->driver_xoff = 0;
-	estats->rx_err_discard_pkt = 0;
-	estats->rx_skb_alloc_failed = 0;
-	estats->hw_csum_err = 0;
-	for_each_queue(bp, i) {
-		struct bnx2x_eth_q_stats *qstats = &bp->fp[i].eth_q_stats;
-
-		estats->driver_xoff += qstats->driver_xoff;
-		estats->rx_err_discard_pkt += qstats->rx_err_discard_pkt;
-		estats->rx_skb_alloc_failed += qstats->rx_skb_alloc_failed;
-		estats->hw_csum_err += qstats->hw_csum_err;
-	}
-}
-
-static void bnx2x_stats_update(struct bnx2x *bp)
-{
-	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
-	if (*stats_comp != DMAE_COMP_VAL)
-		return;
-
-	if (bp->port.pmf)
-		bnx2x_hw_stats_update(bp);
-
-	if (bnx2x_storm_stats_update(bp) && (bp->stats_pending++ == 3)) {
-		BNX2X_ERR("storm stats were not updated for 3 times\n");
-		bnx2x_panic();
-		return;
-	}
-
-	bnx2x_net_stats_update(bp);
-	bnx2x_drv_stats_update(bp);
-
-	if (netif_msg_timer(bp)) {
-		struct bnx2x_eth_stats *estats = &bp->eth_stats;
-		int i;
-
-		printk(KERN_DEBUG "%s: brb drops %u  brb truncate %u\n",
-		       bp->dev->name,
-		       estats->brb_drop_lo, estats->brb_truncate_lo);
-
-		for_each_queue(bp, i) {
-			struct bnx2x_fastpath *fp = &bp->fp[i];
-			struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
-
-			printk(KERN_DEBUG "%s: rx usage(%4u)  *rx_cons_sb(%u)"
-					  "  rx pkt(%lu)  rx calls(%lu %lu)\n",
-			       fp->name, (le16_to_cpu(*fp->rx_cons_sb) -
-			       fp->rx_comp_cons),
-			       le16_to_cpu(*fp->rx_cons_sb),
-			       bnx2x_hilo(&qstats->
-					  total_unicast_packets_received_hi),
-			       fp->rx_calls, fp->rx_pkt);
-		}
-
-		for_each_queue(bp, i) {
-			struct bnx2x_fastpath *fp = &bp->fp[i];
-			struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
-			struct netdev_queue *txq =
-				netdev_get_tx_queue(bp->dev, i);
-
-			printk(KERN_DEBUG "%s: tx avail(%4u)  *tx_cons_sb(%u)"
-					  "  tx pkt(%lu) tx calls (%lu)"
-					  "  %s (Xoff events %u)\n",
-			       fp->name, bnx2x_tx_avail(fp),
-			       le16_to_cpu(*fp->tx_cons_sb),
-			       bnx2x_hilo(&qstats->
-					  total_unicast_packets_transmitted_hi),
-			       fp->tx_pkt,
-			       (netif_tx_queue_stopped(txq) ? "Xoff" : "Xon"),
-			       qstats->driver_xoff);
-		}
-	}
-
-	bnx2x_hw_stats_post(bp);
-	bnx2x_storm_stats_post(bp);
-}
-
-static void bnx2x_port_stats_stop(struct bnx2x *bp)
-{
-	struct dmae_command *dmae;
-	u32 opcode;
-	int loader_idx = PMF_DMAE_C(bp);
-	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
-	bp->executer_idx = 0;
-
-	opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
-		  DMAE_CMD_C_ENABLE |
-		  DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
-		  DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
-		  DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
-		  (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
-		  (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
-
-	if (bp->port.port_stx) {
-
-		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-		if (bp->func_stx)
-			dmae->opcode = (opcode | DMAE_CMD_C_DST_GRC);
-		else
-			dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
-		dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
-		dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
-		dmae->dst_addr_lo = bp->port.port_stx >> 2;
-		dmae->dst_addr_hi = 0;
-		dmae->len = sizeof(struct host_port_stats) >> 2;
-		if (bp->func_stx) {
-			dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
-			dmae->comp_addr_hi = 0;
-			dmae->comp_val = 1;
-		} else {
-			dmae->comp_addr_lo =
-				U64_LO(bnx2x_sp_mapping(bp, stats_comp));
-			dmae->comp_addr_hi =
-				U64_HI(bnx2x_sp_mapping(bp, stats_comp));
-			dmae->comp_val = DMAE_COMP_VAL;
-
-			*stats_comp = 0;
-		}
-	}
-
-	if (bp->func_stx) {
-
-		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-		dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
-		dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
-		dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
-		dmae->dst_addr_lo = bp->func_stx >> 2;
-		dmae->dst_addr_hi = 0;
-		dmae->len = sizeof(struct host_func_stats) >> 2;
-		dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
-		dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
-		dmae->comp_val = DMAE_COMP_VAL;
-
-		*stats_comp = 0;
-	}
-}
-
-static void bnx2x_stats_stop(struct bnx2x *bp)
-{
-	int update = 0;
-
-	bnx2x_stats_comp(bp);
-
-	if (bp->port.pmf)
-		update = (bnx2x_hw_stats_update(bp) == 0);
-
-	update |= (bnx2x_storm_stats_update(bp) == 0);
-
-	if (update) {
-		bnx2x_net_stats_update(bp);
-
-		if (bp->port.pmf)
-			bnx2x_port_stats_stop(bp);
-
-		bnx2x_hw_stats_post(bp);
-		bnx2x_stats_comp(bp);
-	}
-}
-
-static void bnx2x_stats_do_nothing(struct bnx2x *bp)
-{
-}
-
-static const struct {
-	void (*action)(struct bnx2x *bp);
-	enum bnx2x_stats_state next_state;
-} bnx2x_stats_stm[STATS_STATE_MAX][STATS_EVENT_MAX] = {
-/* state	event	*/
-{
-/* DISABLED	PMF	*/ {bnx2x_stats_pmf_update, STATS_STATE_DISABLED},
-/*		LINK_UP	*/ {bnx2x_stats_start,      STATS_STATE_ENABLED},
-/*		UPDATE	*/ {bnx2x_stats_do_nothing, STATS_STATE_DISABLED},
-/*		STOP	*/ {bnx2x_stats_do_nothing, STATS_STATE_DISABLED}
-},
-{
-/* ENABLED	PMF	*/ {bnx2x_stats_pmf_start,  STATS_STATE_ENABLED},
-/*		LINK_UP	*/ {bnx2x_stats_restart,    STATS_STATE_ENABLED},
-/*		UPDATE	*/ {bnx2x_stats_update,     STATS_STATE_ENABLED},
-/*		STOP	*/ {bnx2x_stats_stop,       STATS_STATE_DISABLED}
-}
-};
-
-static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
-{
-	enum bnx2x_stats_state state;
-
-	if (unlikely(bp->panic))
-		return;
-
-	/* Protect a state change flow */
-	spin_lock_bh(&bp->stats_lock);
-	state = bp->stats_state;
-	bp->stats_state = bnx2x_stats_stm[state][event].next_state;
-	spin_unlock_bh(&bp->stats_lock);
-
-	bnx2x_stats_stm[state][event].action(bp);
-
-	if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
-		DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
-		   state, event, bp->stats_state);
-}
-
-static void bnx2x_port_stats_base_init(struct bnx2x *bp)
-{
-	struct dmae_command *dmae;
-	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
-	/* sanity */
-	if (!bp->port.pmf || !bp->port.port_stx) {
-		BNX2X_ERR("BUG!\n");
-		return;
-	}
-
-	bp->executer_idx = 0;
-
-	dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
-	dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
-			DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
-			DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
-			DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
-			DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
-			(BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
-			(BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
-	dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
-	dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
-	dmae->dst_addr_lo = bp->port.port_stx >> 2;
-	dmae->dst_addr_hi = 0;
-	dmae->len = sizeof(struct host_port_stats) >> 2;
-	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
-	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
-	dmae->comp_val = DMAE_COMP_VAL;
-
-	*stats_comp = 0;
-	bnx2x_hw_stats_post(bp);
-	bnx2x_stats_comp(bp);
-}
-
-static void bnx2x_func_stats_base_init(struct bnx2x *bp)
-{
-	int vn, vn_max = IS_E1HMF(bp) ? E1HVN_MAX : E1VN_MAX;
-	int port = BP_PORT(bp);
-	int func;
-	u32 func_stx;
-
-	/* sanity */
-	if (!bp->port.pmf || !bp->func_stx) {
-		BNX2X_ERR("BUG!\n");
-		return;
-	}
-
-	/* save our func_stx */
-	func_stx = bp->func_stx;
-
-	for (vn = VN_0; vn < vn_max; vn++) {
-		func = 2*vn + port;
-
-		bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param);
-		bnx2x_func_stats_init(bp);
-		bnx2x_hw_stats_post(bp);
-		bnx2x_stats_comp(bp);
-	}
-
-	/* restore our func_stx */
-	bp->func_stx = func_stx;
-}
-
-static void bnx2x_func_stats_base_update(struct bnx2x *bp)
-{
-	struct dmae_command *dmae = &bp->stats_dmae;
-	u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
-	/* sanity */
-	if (!bp->func_stx) {
-		BNX2X_ERR("BUG!\n");
-		return;
-	}
-
-	bp->executer_idx = 0;
-	memset(dmae, 0, sizeof(struct dmae_command));
-
-	dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
-			DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
-			DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
-			DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
-			DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
-			(BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
-			(BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
-	dmae->src_addr_lo = bp->func_stx >> 2;
-	dmae->src_addr_hi = 0;
-	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats_base));
-	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats_base));
-	dmae->len = sizeof(struct host_func_stats) >> 2;
-	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
-	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
-	dmae->comp_val = DMAE_COMP_VAL;
-
-	*stats_comp = 0;
-	bnx2x_hw_stats_post(bp);
-	bnx2x_stats_comp(bp);
-}
-
-static void bnx2x_stats_init(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	int func = BP_FUNC(bp);
-	int i;
-
-	bp->stats_pending = 0;
-	bp->executer_idx = 0;
-	bp->stats_counter = 0;
-
-	/* port and func stats for management */
-	if (!BP_NOMCP(bp)) {
-		bp->port.port_stx = SHMEM_RD(bp, port_mb[port].port_stx);
-		bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param);
-
-	} else {
-		bp->port.port_stx = 0;
-		bp->func_stx = 0;
-	}
-	DP(BNX2X_MSG_STATS, "port_stx 0x%x  func_stx 0x%x\n",
-	   bp->port.port_stx, bp->func_stx);
-
-	/* port stats */
-	memset(&(bp->port.old_nig_stats), 0, sizeof(struct nig_stats));
-	bp->port.old_nig_stats.brb_discard =
-			REG_RD(bp, NIG_REG_STAT0_BRB_DISCARD + port*0x38);
-	bp->port.old_nig_stats.brb_truncate =
-			REG_RD(bp, NIG_REG_STAT0_BRB_TRUNCATE + port*0x38);
-	REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT0 + port*0x50,
-		    &(bp->port.old_nig_stats.egress_mac_pkt0_lo), 2);
-	REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT1 + port*0x50,
-		    &(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2);
-
-	/* function stats */
-	for_each_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-
-		memset(&fp->old_tclient, 0,
-		       sizeof(struct tstorm_per_client_stats));
-		memset(&fp->old_uclient, 0,
-		       sizeof(struct ustorm_per_client_stats));
-		memset(&fp->old_xclient, 0,
-		       sizeof(struct xstorm_per_client_stats));
-		memset(&fp->eth_q_stats, 0, sizeof(struct bnx2x_eth_q_stats));
-	}
-
-	memset(&bp->dev->stats, 0, sizeof(struct net_device_stats));
-	memset(&bp->eth_stats, 0, sizeof(struct bnx2x_eth_stats));
-
-	bp->stats_state = STATS_STATE_DISABLED;
-
-	if (bp->port.pmf) {
-		if (bp->port.port_stx)
-			bnx2x_port_stats_base_init(bp);
-
-		if (bp->func_stx)
-			bnx2x_func_stats_base_init(bp);
-
-	} else if (bp->func_stx)
-		bnx2x_func_stats_base_update(bp);
-}
-
-static void bnx2x_timer(unsigned long data)
-{
-	struct bnx2x *bp = (struct bnx2x *) data;
-
-	if (!netif_running(bp->dev))
-		return;
-
-	if (atomic_read(&bp->intr_sem) != 0)
-		goto timer_restart;
-
-	if (poll) {
-		struct bnx2x_fastpath *fp = &bp->fp[0];
-		int rc;
-
-		bnx2x_tx_int(fp);
-		rc = bnx2x_rx_int(fp, 1000);
-	}
-
-	if (!BP_NOMCP(bp)) {
-		int func = BP_FUNC(bp);
-		u32 drv_pulse;
-		u32 mcp_pulse;
-
-		++bp->fw_drv_pulse_wr_seq;
-		bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK;
-		/* TBD - add SYSTEM_TIME */
-		drv_pulse = bp->fw_drv_pulse_wr_seq;
-		SHMEM_WR(bp, func_mb[func].drv_pulse_mb, drv_pulse);
-
-		mcp_pulse = (SHMEM_RD(bp, func_mb[func].mcp_pulse_mb) &
-			     MCP_PULSE_SEQ_MASK);
-		/* The delta between driver pulse and mcp response
-		 * should be 1 (before mcp response) or 0 (after mcp response)
-		 */
-		if ((drv_pulse != mcp_pulse) &&
-		    (drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK))) {
-			/* someone lost a heartbeat... */
-			BNX2X_ERR("drv_pulse (0x%x) != mcp_pulse (0x%x)\n",
-				  drv_pulse, mcp_pulse);
-		}
-	}
-
-	if (bp->state == BNX2X_STATE_OPEN)
-		bnx2x_stats_handle(bp, STATS_EVENT_UPDATE);
-
-timer_restart:
-	mod_timer(&bp->timer, jiffies + bp->current_interval);
-}
-
-/* end of Statistics */
-
-/* nic init */
-
-/*
- * nic init service functions
- */
-
-static void bnx2x_zero_sb(struct bnx2x *bp, int sb_id)
-{
-	int port = BP_PORT(bp);
-
-	/* "CSTORM" */
-	bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
-			CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, sb_id), 0,
-			CSTORM_SB_STATUS_BLOCK_U_SIZE / 4);
-	bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
-			CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id), 0,
-			CSTORM_SB_STATUS_BLOCK_C_SIZE / 4);
-}
-
-static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb,
-			  dma_addr_t mapping, int sb_id)
-{
-	int port = BP_PORT(bp);
-	int func = BP_FUNC(bp);
-	int index;
-	u64 section;
-
-	/* USTORM */
-	section = ((u64)mapping) + offsetof(struct host_status_block,
-					    u_status_block);
-	sb->u_status_block.status_block_id = sb_id;
-
-	REG_WR(bp, BAR_CSTRORM_INTMEM +
-	       CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, sb_id), U64_LO(section));
-	REG_WR(bp, BAR_CSTRORM_INTMEM +
-	       ((CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, sb_id)) + 4),
-	       U64_HI(section));
-	REG_WR8(bp, BAR_CSTRORM_INTMEM + FP_USB_FUNC_OFF +
-		CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, sb_id), func);
-
-	for (index = 0; index < HC_USTORM_SB_NUM_INDICES; index++)
-		REG_WR16(bp, BAR_CSTRORM_INTMEM +
-			 CSTORM_SB_HC_DISABLE_U_OFFSET(port, sb_id, index), 1);
-
-	/* CSTORM */
-	section = ((u64)mapping) + offsetof(struct host_status_block,
-					    c_status_block);
-	sb->c_status_block.status_block_id = sb_id;
-
-	REG_WR(bp, BAR_CSTRORM_INTMEM +
-	       CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, sb_id), U64_LO(section));
-	REG_WR(bp, BAR_CSTRORM_INTMEM +
-	       ((CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, sb_id)) + 4),
-	       U64_HI(section));
-	REG_WR8(bp, BAR_CSTRORM_INTMEM + FP_CSB_FUNC_OFF +
-		CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id), func);
-
-	for (index = 0; index < HC_CSTORM_SB_NUM_INDICES; index++)
-		REG_WR16(bp, BAR_CSTRORM_INTMEM +
-			 CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id, index), 1);
-
-	bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
-}
-
-static void bnx2x_zero_def_sb(struct bnx2x *bp)
-{
-	int func = BP_FUNC(bp);
-
-	bnx2x_init_fill(bp, TSEM_REG_FAST_MEMORY +
-			TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
-			sizeof(struct tstorm_def_status_block)/4);
-	bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
-			CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(func), 0,
-			sizeof(struct cstorm_def_status_block_u)/4);
-	bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
-			CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(func), 0,
-			sizeof(struct cstorm_def_status_block_c)/4);
-	bnx2x_init_fill(bp, XSEM_REG_FAST_MEMORY +
-			XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
-			sizeof(struct xstorm_def_status_block)/4);
-}
-
-static void bnx2x_init_def_sb(struct bnx2x *bp,
-			      struct host_def_status_block *def_sb,
-			      dma_addr_t mapping, int sb_id)
-{
-	int port = BP_PORT(bp);
-	int func = BP_FUNC(bp);
-	int index, val, reg_offset;
-	u64 section;
-
-	/* ATTN */
-	section = ((u64)mapping) + offsetof(struct host_def_status_block,
-					    atten_status_block);
-	def_sb->atten_status_block.status_block_id = sb_id;
-
-	bp->attn_state = 0;
-
-	reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
-			     MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
-
-	for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
-		bp->attn_group[index].sig[0] = REG_RD(bp,
-						     reg_offset + 0x10*index);
-		bp->attn_group[index].sig[1] = REG_RD(bp,
-					       reg_offset + 0x4 + 0x10*index);
-		bp->attn_group[index].sig[2] = REG_RD(bp,
-					       reg_offset + 0x8 + 0x10*index);
-		bp->attn_group[index].sig[3] = REG_RD(bp,
-					       reg_offset + 0xc + 0x10*index);
-	}
-
-	reg_offset = (port ? HC_REG_ATTN_MSG1_ADDR_L :
-			     HC_REG_ATTN_MSG0_ADDR_L);
-
-	REG_WR(bp, reg_offset, U64_LO(section));
-	REG_WR(bp, reg_offset + 4, U64_HI(section));
-
-	reg_offset = (port ? HC_REG_ATTN_NUM_P1 : HC_REG_ATTN_NUM_P0);
-
-	val = REG_RD(bp, reg_offset);
-	val |= sb_id;
-	REG_WR(bp, reg_offset, val);
-
-	/* USTORM */
-	section = ((u64)mapping) + offsetof(struct host_def_status_block,
-					    u_def_status_block);
-	def_sb->u_def_status_block.status_block_id = sb_id;
-
-	REG_WR(bp, BAR_CSTRORM_INTMEM +
-	       CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(func), U64_LO(section));
-	REG_WR(bp, BAR_CSTRORM_INTMEM +
-	       ((CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(func)) + 4),
-	       U64_HI(section));
-	REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_USB_FUNC_OFF +
-		CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(func), func);
-
-	for (index = 0; index < HC_USTORM_DEF_SB_NUM_INDICES; index++)
-		REG_WR16(bp, BAR_CSTRORM_INTMEM +
-			 CSTORM_DEF_SB_HC_DISABLE_U_OFFSET(func, index), 1);
-
-	/* CSTORM */
-	section = ((u64)mapping) + offsetof(struct host_def_status_block,
-					    c_def_status_block);
-	def_sb->c_def_status_block.status_block_id = sb_id;
-
-	REG_WR(bp, BAR_CSTRORM_INTMEM +
-	       CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(func), U64_LO(section));
-	REG_WR(bp, BAR_CSTRORM_INTMEM +
-	       ((CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(func)) + 4),
-	       U64_HI(section));
-	REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_CSB_FUNC_OFF +
-		CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(func), func);
-
-	for (index = 0; index < HC_CSTORM_DEF_SB_NUM_INDICES; index++)
-		REG_WR16(bp, BAR_CSTRORM_INTMEM +
-			 CSTORM_DEF_SB_HC_DISABLE_C_OFFSET(func, index), 1);
-
-	/* TSTORM */
-	section = ((u64)mapping) + offsetof(struct host_def_status_block,
-					    t_def_status_block);
-	def_sb->t_def_status_block.status_block_id = sb_id;
-
-	REG_WR(bp, BAR_TSTRORM_INTMEM +
-	       TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section));
-	REG_WR(bp, BAR_TSTRORM_INTMEM +
-	       ((TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4),
-	       U64_HI(section));
-	REG_WR8(bp, BAR_TSTRORM_INTMEM + DEF_TSB_FUNC_OFF +
-		TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func);
-
-	for (index = 0; index < HC_TSTORM_DEF_SB_NUM_INDICES; index++)
-		REG_WR16(bp, BAR_TSTRORM_INTMEM +
-			 TSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1);
-
-	/* XSTORM */
-	section = ((u64)mapping) + offsetof(struct host_def_status_block,
-					    x_def_status_block);
-	def_sb->x_def_status_block.status_block_id = sb_id;
-
-	REG_WR(bp, BAR_XSTRORM_INTMEM +
-	       XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section));
-	REG_WR(bp, BAR_XSTRORM_INTMEM +
-	       ((XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4),
-	       U64_HI(section));
-	REG_WR8(bp, BAR_XSTRORM_INTMEM + DEF_XSB_FUNC_OFF +
-		XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func);
-
-	for (index = 0; index < HC_XSTORM_DEF_SB_NUM_INDICES; index++)
-		REG_WR16(bp, BAR_XSTRORM_INTMEM +
-			 XSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1);
-
-	bp->stats_pending = 0;
-	bp->set_mac_pending = 0;
-
-	bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
-}
-
-static void bnx2x_update_coalesce(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	int i;
-
-	for_each_queue(bp, i) {
-		int sb_id = bp->fp[i].sb_id;
-
-		/* HC_INDEX_U_ETH_RX_CQ_CONS */
-		REG_WR8(bp, BAR_CSTRORM_INTMEM +
-			CSTORM_SB_HC_TIMEOUT_U_OFFSET(port, sb_id,
-						      U_SB_ETH_RX_CQ_INDEX),
-			bp->rx_ticks/(4 * BNX2X_BTR));
-		REG_WR16(bp, BAR_CSTRORM_INTMEM +
-			 CSTORM_SB_HC_DISABLE_U_OFFSET(port, sb_id,
-						       U_SB_ETH_RX_CQ_INDEX),
-			 (bp->rx_ticks/(4 * BNX2X_BTR)) ? 0 : 1);
-
-		/* HC_INDEX_C_ETH_TX_CQ_CONS */
-		REG_WR8(bp, BAR_CSTRORM_INTMEM +
-			CSTORM_SB_HC_TIMEOUT_C_OFFSET(port, sb_id,
-						      C_SB_ETH_TX_CQ_INDEX),
-			bp->tx_ticks/(4 * BNX2X_BTR));
-		REG_WR16(bp, BAR_CSTRORM_INTMEM +
-			 CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id,
-						       C_SB_ETH_TX_CQ_INDEX),
-			 (bp->tx_ticks/(4 * BNX2X_BTR)) ? 0 : 1);
-	}
-}
-
-static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
-				       struct bnx2x_fastpath *fp, int last)
-{
-	int i;
-
-	for (i = 0; i < last; i++) {
-		struct sw_rx_bd *rx_buf = &(fp->tpa_pool[i]);
-		struct sk_buff *skb = rx_buf->skb;
-
-		if (skb == NULL) {
-			DP(NETIF_MSG_IFDOWN, "tpa bin %d empty on free\n", i);
-			continue;
-		}
-
-		if (fp->tpa_state[i] == BNX2X_TPA_START)
-			dma_unmap_single(&bp->pdev->dev,
-					 dma_unmap_addr(rx_buf, mapping),
-					 bp->rx_buf_size, DMA_FROM_DEVICE);
-
-		dev_kfree_skb(skb);
-		rx_buf->skb = NULL;
-	}
-}
-
-static void bnx2x_init_rx_rings(struct bnx2x *bp)
-{
-	int func = BP_FUNC(bp);
-	int max_agg_queues = CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 :
-					      ETH_MAX_AGGREGATION_QUEUES_E1H;
-	u16 ring_prod, cqe_ring_prod;
-	int i, j;
-
-	bp->rx_buf_size = bp->dev->mtu + ETH_OVREHEAD + BNX2X_RX_ALIGN;
-	DP(NETIF_MSG_IFUP,
-	   "mtu %d  rx_buf_size %d\n", bp->dev->mtu, bp->rx_buf_size);
-
-	if (bp->flags & TPA_ENABLE_FLAG) {
-
-		for_each_queue(bp, j) {
-			struct bnx2x_fastpath *fp = &bp->fp[j];
-
-			for (i = 0; i < max_agg_queues; i++) {
-				fp->tpa_pool[i].skb =
-				   netdev_alloc_skb(bp->dev, bp->rx_buf_size);
-				if (!fp->tpa_pool[i].skb) {
-					BNX2X_ERR("Failed to allocate TPA "
-						  "skb pool for queue[%d] - "
-						  "disabling TPA on this "
-						  "queue!\n", j);
-					bnx2x_free_tpa_pool(bp, fp, i);
-					fp->disable_tpa = 1;
-					break;
-				}
-				dma_unmap_addr_set((struct sw_rx_bd *)
-							&bp->fp->tpa_pool[i],
-						   mapping, 0);
-				fp->tpa_state[i] = BNX2X_TPA_STOP;
-			}
-		}
-	}
-
-	for_each_queue(bp, j) {
-		struct bnx2x_fastpath *fp = &bp->fp[j];
-
-		fp->rx_bd_cons = 0;
-		fp->rx_cons_sb = BNX2X_RX_SB_INDEX;
-		fp->rx_bd_cons_sb = BNX2X_RX_SB_BD_INDEX;
-
-		/* "next page" elements initialization */
-		/* SGE ring */
-		for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
-			struct eth_rx_sge *sge;
-
-			sge = &fp->rx_sge_ring[RX_SGE_CNT * i - 2];
-			sge->addr_hi =
-				cpu_to_le32(U64_HI(fp->rx_sge_mapping +
-					BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
-			sge->addr_lo =
-				cpu_to_le32(U64_LO(fp->rx_sge_mapping +
-					BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
-		}
-
-		bnx2x_init_sge_ring_bit_mask(fp);
-
-		/* RX BD ring */
-		for (i = 1; i <= NUM_RX_RINGS; i++) {
-			struct eth_rx_bd *rx_bd;
-
-			rx_bd = &fp->rx_desc_ring[RX_DESC_CNT * i - 2];
-			rx_bd->addr_hi =
-				cpu_to_le32(U64_HI(fp->rx_desc_mapping +
-					    BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
-			rx_bd->addr_lo =
-				cpu_to_le32(U64_LO(fp->rx_desc_mapping +
-					    BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
-		}
-
-		/* CQ ring */
-		for (i = 1; i <= NUM_RCQ_RINGS; i++) {
-			struct eth_rx_cqe_next_page *nextpg;
-
-			nextpg = (struct eth_rx_cqe_next_page *)
-				&fp->rx_comp_ring[RCQ_DESC_CNT * i - 1];
-			nextpg->addr_hi =
-				cpu_to_le32(U64_HI(fp->rx_comp_mapping +
-					   BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
-			nextpg->addr_lo =
-				cpu_to_le32(U64_LO(fp->rx_comp_mapping +
-					   BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
-		}
-
-		/* Allocate SGEs and initialize the ring elements */
-		for (i = 0, ring_prod = 0;
-		     i < MAX_RX_SGE_CNT*NUM_RX_SGE_PAGES; i++) {
-
-			if (bnx2x_alloc_rx_sge(bp, fp, ring_prod) < 0) {
-				BNX2X_ERR("was only able to allocate "
-					  "%d rx sges\n", i);
-				BNX2X_ERR("disabling TPA for queue[%d]\n", j);
-				/* Cleanup already allocated elements */
-				bnx2x_free_rx_sge_range(bp, fp, ring_prod);
-				bnx2x_free_tpa_pool(bp, fp, max_agg_queues);
-				fp->disable_tpa = 1;
-				ring_prod = 0;
-				break;
-			}
-			ring_prod = NEXT_SGE_IDX(ring_prod);
-		}
-		fp->rx_sge_prod = ring_prod;
-
-		/* Allocate BDs and initialize BD ring */
-		fp->rx_comp_cons = 0;
-		cqe_ring_prod = ring_prod = 0;
-		for (i = 0; i < bp->rx_ring_size; i++) {
-			if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) {
-				BNX2X_ERR("was only able to allocate "
-					  "%d rx skbs on queue[%d]\n", i, j);
-				fp->eth_q_stats.rx_skb_alloc_failed++;
-				break;
-			}
-			ring_prod = NEXT_RX_IDX(ring_prod);
-			cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod);
-			WARN_ON(ring_prod <= i);
-		}
-
-		fp->rx_bd_prod = ring_prod;
-		/* must not have more available CQEs than BDs */
-		fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT,
-					 cqe_ring_prod);
-		fp->rx_pkt = fp->rx_calls = 0;
-
-		/* Warning!
-		 * this will generate an interrupt (to the TSTORM)
-		 * must only be done after chip is initialized
-		 */
-		bnx2x_update_rx_prod(bp, fp, ring_prod, fp->rx_comp_prod,
-				     fp->rx_sge_prod);
-		if (j != 0)
-			continue;
-
-		REG_WR(bp, BAR_USTRORM_INTMEM +
-		       USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func),
-		       U64_LO(fp->rx_comp_mapping));
-		REG_WR(bp, BAR_USTRORM_INTMEM +
-		       USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func) + 4,
-		       U64_HI(fp->rx_comp_mapping));
-	}
-}
-
-static void bnx2x_init_tx_ring(struct bnx2x *bp)
-{
-	int i, j;
-
-	for_each_queue(bp, j) {
-		struct bnx2x_fastpath *fp = &bp->fp[j];
-
-		for (i = 1; i <= NUM_TX_RINGS; i++) {
-			struct eth_tx_next_bd *tx_next_bd =
-				&fp->tx_desc_ring[TX_DESC_CNT * i - 1].next_bd;
-
-			tx_next_bd->addr_hi =
-				cpu_to_le32(U64_HI(fp->tx_desc_mapping +
-					    BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
-			tx_next_bd->addr_lo =
-				cpu_to_le32(U64_LO(fp->tx_desc_mapping +
-					    BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
-		}
-
-		fp->tx_db.data.header.header = DOORBELL_HDR_DB_TYPE;
-		fp->tx_db.data.zero_fill1 = 0;
-		fp->tx_db.data.prod = 0;
-
-		fp->tx_pkt_prod = 0;
-		fp->tx_pkt_cons = 0;
-		fp->tx_bd_prod = 0;
-		fp->tx_bd_cons = 0;
-		fp->tx_cons_sb = BNX2X_TX_SB_INDEX;
-		fp->tx_pkt = 0;
-	}
-}
-
-static void bnx2x_init_sp_ring(struct bnx2x *bp)
-{
-	int func = BP_FUNC(bp);
-
-	spin_lock_init(&bp->spq_lock);
-
-	bp->spq_left = MAX_SPQ_PENDING;
-	bp->spq_prod_idx = 0;
-	bp->dsb_sp_prod = BNX2X_SP_DSB_INDEX;
-	bp->spq_prod_bd = bp->spq;
-	bp->spq_last_bd = bp->spq_prod_bd + MAX_SP_DESC_CNT;
-
-	REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PAGE_BASE_OFFSET(func),
-	       U64_LO(bp->spq_mapping));
-	REG_WR(bp,
-	       XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PAGE_BASE_OFFSET(func) + 4,
-	       U64_HI(bp->spq_mapping));
-
-	REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PROD_OFFSET(func),
-	       bp->spq_prod_idx);
-}
-
-static void bnx2x_init_context(struct bnx2x *bp)
-{
-	int i;
-
-	/* Rx */
-	for_each_queue(bp, i) {
-		struct eth_context *context = bnx2x_sp(bp, context[i].eth);
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-		u8 cl_id = fp->cl_id;
-
-		context->ustorm_st_context.common.sb_index_numbers =
-						BNX2X_RX_SB_INDEX_NUM;
-		context->ustorm_st_context.common.clientId = cl_id;
-		context->ustorm_st_context.common.status_block_id = fp->sb_id;
-		context->ustorm_st_context.common.flags =
-			(USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT |
-			 USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS);
-		context->ustorm_st_context.common.statistics_counter_id =
-						cl_id;
-		context->ustorm_st_context.common.mc_alignment_log_size =
-						BNX2X_RX_ALIGN_SHIFT;
-		context->ustorm_st_context.common.bd_buff_size =
-						bp->rx_buf_size;
-		context->ustorm_st_context.common.bd_page_base_hi =
-						U64_HI(fp->rx_desc_mapping);
-		context->ustorm_st_context.common.bd_page_base_lo =
-						U64_LO(fp->rx_desc_mapping);
-		if (!fp->disable_tpa) {
-			context->ustorm_st_context.common.flags |=
-				USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA;
-			context->ustorm_st_context.common.sge_buff_size =
-				(u16)min_t(u32, SGE_PAGE_SIZE*PAGES_PER_SGE,
-					   0xffff);
-			context->ustorm_st_context.common.sge_page_base_hi =
-						U64_HI(fp->rx_sge_mapping);
-			context->ustorm_st_context.common.sge_page_base_lo =
-						U64_LO(fp->rx_sge_mapping);
-
-			context->ustorm_st_context.common.max_sges_for_packet =
-				SGE_PAGE_ALIGN(bp->dev->mtu) >> SGE_PAGE_SHIFT;
-			context->ustorm_st_context.common.max_sges_for_packet =
-				((context->ustorm_st_context.common.
-				  max_sges_for_packet + PAGES_PER_SGE - 1) &
-				 (~(PAGES_PER_SGE - 1))) >> PAGES_PER_SGE_SHIFT;
-		}
-
-		context->ustorm_ag_context.cdu_usage =
-			CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i),
-					       CDU_REGION_NUMBER_UCM_AG,
-					       ETH_CONNECTION_TYPE);
-
-		context->xstorm_ag_context.cdu_reserved =
-			CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i),
-					       CDU_REGION_NUMBER_XCM_AG,
-					       ETH_CONNECTION_TYPE);
-	}
-
-	/* Tx */
-	for_each_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-		struct eth_context *context =
-			bnx2x_sp(bp, context[i].eth);
-
-		context->cstorm_st_context.sb_index_number =
-						C_SB_ETH_TX_CQ_INDEX;
-		context->cstorm_st_context.status_block_id = fp->sb_id;
-
-		context->xstorm_st_context.tx_bd_page_base_hi =
-						U64_HI(fp->tx_desc_mapping);
-		context->xstorm_st_context.tx_bd_page_base_lo =
-						U64_LO(fp->tx_desc_mapping);
-		context->xstorm_st_context.statistics_data = (fp->cl_id |
-				XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE);
-	}
-}
-
-static void bnx2x_init_ind_table(struct bnx2x *bp)
-{
-	int func = BP_FUNC(bp);
-	int i;
-
-	if (bp->multi_mode == ETH_RSS_MODE_DISABLED)
-		return;
-
-	DP(NETIF_MSG_IFUP,
-	   "Initializing indirection table  multi_mode %d\n", bp->multi_mode);
-	for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++)
-		REG_WR8(bp, BAR_TSTRORM_INTMEM +
-			TSTORM_INDIRECTION_TABLE_OFFSET(func) + i,
-			bp->fp->cl_id + (i % bp->num_queues));
-}
-
-static void bnx2x_set_client_config(struct bnx2x *bp)
-{
-	struct tstorm_eth_client_config tstorm_client = {0};
-	int port = BP_PORT(bp);
-	int i;
-
-	tstorm_client.mtu = bp->dev->mtu;
-	tstorm_client.config_flags =
-				(TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE |
-				 TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE);
-#ifdef BCM_VLAN
-	if (bp->rx_mode && bp->vlgrp && (bp->flags & HW_VLAN_RX_FLAG)) {
-		tstorm_client.config_flags |=
-				TSTORM_ETH_CLIENT_CONFIG_VLAN_REM_ENABLE;
-		DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
-	}
-#endif
-
-	for_each_queue(bp, i) {
-		tstorm_client.statistics_counter_id = bp->fp[i].cl_id;
-
-		REG_WR(bp, BAR_TSTRORM_INTMEM +
-		       TSTORM_CLIENT_CONFIG_OFFSET(port, bp->fp[i].cl_id),
-		       ((u32 *)&tstorm_client)[0]);
-		REG_WR(bp, BAR_TSTRORM_INTMEM +
-		       TSTORM_CLIENT_CONFIG_OFFSET(port, bp->fp[i].cl_id) + 4,
-		       ((u32 *)&tstorm_client)[1]);
-	}
-
-	DP(BNX2X_MSG_OFF, "tstorm_client: 0x%08x 0x%08x\n",
-	   ((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]);
-}
-
-static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
-{
-	struct tstorm_eth_mac_filter_config tstorm_mac_filter = {0};
-	int mode = bp->rx_mode;
-	int mask = bp->rx_mode_cl_mask;
-	int func = BP_FUNC(bp);
-	int port = BP_PORT(bp);
-	int i;
-	/* All but management unicast packets should pass to the host as well */
-	u32 llh_mask =
-		NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST |
-		NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST |
-		NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN |
-		NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN;
-
-	DP(NETIF_MSG_IFUP, "rx mode %d  mask 0x%x\n", mode, mask);
-
-	switch (mode) {
-	case BNX2X_RX_MODE_NONE: /* no Rx */
-		tstorm_mac_filter.ucast_drop_all = mask;
-		tstorm_mac_filter.mcast_drop_all = mask;
-		tstorm_mac_filter.bcast_drop_all = mask;
-		break;
-
-	case BNX2X_RX_MODE_NORMAL:
-		tstorm_mac_filter.bcast_accept_all = mask;
-		break;
-
-	case BNX2X_RX_MODE_ALLMULTI:
-		tstorm_mac_filter.mcast_accept_all = mask;
-		tstorm_mac_filter.bcast_accept_all = mask;
-		break;
-
-	case BNX2X_RX_MODE_PROMISC:
-		tstorm_mac_filter.ucast_accept_all = mask;
-		tstorm_mac_filter.mcast_accept_all = mask;
-		tstorm_mac_filter.bcast_accept_all = mask;
-		/* pass management unicast packets as well */
-		llh_mask |= NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST;
-		break;
-
-	default:
-		BNX2X_ERR("BAD rx mode (%d)\n", mode);
-		break;
-	}
-
-	REG_WR(bp,
-	       (port ? NIG_REG_LLH1_BRB1_DRV_MASK : NIG_REG_LLH0_BRB1_DRV_MASK),
-	       llh_mask);
-
-	for (i = 0; i < sizeof(struct tstorm_eth_mac_filter_config)/4; i++) {
-		REG_WR(bp, BAR_TSTRORM_INTMEM +
-		       TSTORM_MAC_FILTER_CONFIG_OFFSET(func) + i * 4,
-		       ((u32 *)&tstorm_mac_filter)[i]);
-
-/*		DP(NETIF_MSG_IFUP, "tstorm_mac_filter[%d]: 0x%08x\n", i,
-		   ((u32 *)&tstorm_mac_filter)[i]); */
-	}
-
-	if (mode != BNX2X_RX_MODE_NONE)
-		bnx2x_set_client_config(bp);
-}
-
-static void bnx2x_init_internal_common(struct bnx2x *bp)
-{
-	int i;
-
-	/* Zero this manually as its initialization is
-	   currently missing in the initTool */
-	for (i = 0; i < (USTORM_AGG_DATA_SIZE >> 2); i++)
-		REG_WR(bp, BAR_USTRORM_INTMEM +
-		       USTORM_AGG_DATA_OFFSET + i * 4, 0);
-}
-
-static void bnx2x_init_internal_port(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-
-	REG_WR(bp,
-	       BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_U_OFFSET(port), BNX2X_BTR);
-	REG_WR(bp,
-	       BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_C_OFFSET(port), BNX2X_BTR);
-	REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_HC_BTR_OFFSET(port), BNX2X_BTR);
-	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(port), BNX2X_BTR);
-}
-
-static void bnx2x_init_internal_func(struct bnx2x *bp)
-{
-	struct tstorm_eth_function_common_config tstorm_config = {0};
-	struct stats_indication_flags stats_flags = {0};
-	int port = BP_PORT(bp);
-	int func = BP_FUNC(bp);
-	int i, j;
-	u32 offset;
-	u16 max_agg_size;
-
-	tstorm_config.config_flags = RSS_FLAGS(bp);
-
-	if (is_multi(bp))
-		tstorm_config.rss_result_mask = MULTI_MASK;
-
-	/* Enable TPA if needed */
-	if (bp->flags & TPA_ENABLE_FLAG)
-		tstorm_config.config_flags |=
-			TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA;
-
-	if (IS_E1HMF(bp))
-		tstorm_config.config_flags |=
-				TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM;
-
-	tstorm_config.leading_client_id = BP_L_ID(bp);
-
-	REG_WR(bp, BAR_TSTRORM_INTMEM +
-	       TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(func),
-	       (*(u32 *)&tstorm_config));
-
-	bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx until link is up */
-	bp->rx_mode_cl_mask = (1 << BP_L_ID(bp));
-	bnx2x_set_storm_rx_mode(bp);
-
-	for_each_queue(bp, i) {
-		u8 cl_id = bp->fp[i].cl_id;
-
-		/* reset xstorm per client statistics */
-		offset = BAR_XSTRORM_INTMEM +
-			 XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cl_id);
-		for (j = 0;
-		     j < sizeof(struct xstorm_per_client_stats) / 4; j++)
-			REG_WR(bp, offset + j*4, 0);
-
-		/* reset tstorm per client statistics */
-		offset = BAR_TSTRORM_INTMEM +
-			 TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cl_id);
-		for (j = 0;
-		     j < sizeof(struct tstorm_per_client_stats) / 4; j++)
-			REG_WR(bp, offset + j*4, 0);
-
-		/* reset ustorm per client statistics */
-		offset = BAR_USTRORM_INTMEM +
-			 USTORM_PER_COUNTER_ID_STATS_OFFSET(port, cl_id);
-		for (j = 0;
-		     j < sizeof(struct ustorm_per_client_stats) / 4; j++)
-			REG_WR(bp, offset + j*4, 0);
-	}
-
-	/* Init statistics related context */
-	stats_flags.collect_eth = 1;
-
-	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(func),
-	       ((u32 *)&stats_flags)[0]);
-	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(func) + 4,
-	       ((u32 *)&stats_flags)[1]);
-
-	REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(func),
-	       ((u32 *)&stats_flags)[0]);
-	REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(func) + 4,
-	       ((u32 *)&stats_flags)[1]);
-
-	REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_STATS_FLAGS_OFFSET(func),
-	       ((u32 *)&stats_flags)[0]);
-	REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_STATS_FLAGS_OFFSET(func) + 4,
-	       ((u32 *)&stats_flags)[1]);
-
-	REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(func),
-	       ((u32 *)&stats_flags)[0]);
-	REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(func) + 4,
-	       ((u32 *)&stats_flags)[1]);
-
-	REG_WR(bp, BAR_XSTRORM_INTMEM +
-	       XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func),
-	       U64_LO(bnx2x_sp_mapping(bp, fw_stats)));
-	REG_WR(bp, BAR_XSTRORM_INTMEM +
-	       XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func) + 4,
-	       U64_HI(bnx2x_sp_mapping(bp, fw_stats)));
-
-	REG_WR(bp, BAR_TSTRORM_INTMEM +
-	       TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func),
-	       U64_LO(bnx2x_sp_mapping(bp, fw_stats)));
-	REG_WR(bp, BAR_TSTRORM_INTMEM +
-	       TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(func) + 4,
-	       U64_HI(bnx2x_sp_mapping(bp, fw_stats)));
-
-	REG_WR(bp, BAR_USTRORM_INTMEM +
-	       USTORM_ETH_STATS_QUERY_ADDR_OFFSET(func),
-	       U64_LO(bnx2x_sp_mapping(bp, fw_stats)));
-	REG_WR(bp, BAR_USTRORM_INTMEM +
-	       USTORM_ETH_STATS_QUERY_ADDR_OFFSET(func) + 4,
-	       U64_HI(bnx2x_sp_mapping(bp, fw_stats)));
-
-	if (CHIP_IS_E1H(bp)) {
-		REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNCTION_MODE_OFFSET,
-			IS_E1HMF(bp));
-		REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNCTION_MODE_OFFSET,
-			IS_E1HMF(bp));
-		REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNCTION_MODE_OFFSET,
-			IS_E1HMF(bp));
-		REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNCTION_MODE_OFFSET,
-			IS_E1HMF(bp));
-
-		REG_WR16(bp, BAR_XSTRORM_INTMEM + XSTORM_E1HOV_OFFSET(func),
-			 bp->e1hov);
-	}
-
-	/* Init CQ ring mapping and aggregation size, the FW limit is 8 frags */
-	max_agg_size = min_t(u32, (min_t(u32, 8, MAX_SKB_FRAGS) *
-				   SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff);
-	for_each_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-
-		REG_WR(bp, BAR_USTRORM_INTMEM +
-		       USTORM_CQE_PAGE_BASE_OFFSET(port, fp->cl_id),
-		       U64_LO(fp->rx_comp_mapping));
-		REG_WR(bp, BAR_USTRORM_INTMEM +
-		       USTORM_CQE_PAGE_BASE_OFFSET(port, fp->cl_id) + 4,
-		       U64_HI(fp->rx_comp_mapping));
-
-		/* Next page */
-		REG_WR(bp, BAR_USTRORM_INTMEM +
-		       USTORM_CQE_PAGE_NEXT_OFFSET(port, fp->cl_id),
-		       U64_LO(fp->rx_comp_mapping + BCM_PAGE_SIZE));
-		REG_WR(bp, BAR_USTRORM_INTMEM +
-		       USTORM_CQE_PAGE_NEXT_OFFSET(port, fp->cl_id) + 4,
-		       U64_HI(fp->rx_comp_mapping + BCM_PAGE_SIZE));
-
-		REG_WR16(bp, BAR_USTRORM_INTMEM +
-			 USTORM_MAX_AGG_SIZE_OFFSET(port, fp->cl_id),
-			 max_agg_size);
-	}
-
-	/* dropless flow control */
-	if (CHIP_IS_E1H(bp)) {
-		struct ustorm_eth_rx_pause_data_e1h rx_pause = {0};
-
-		rx_pause.bd_thr_low = 250;
-		rx_pause.cqe_thr_low = 250;
-		rx_pause.cos = 1;
-		rx_pause.sge_thr_low = 0;
-		rx_pause.bd_thr_high = 350;
-		rx_pause.cqe_thr_high = 350;
-		rx_pause.sge_thr_high = 0;
-
-		for_each_queue(bp, i) {
-			struct bnx2x_fastpath *fp = &bp->fp[i];
-
-			if (!fp->disable_tpa) {
-				rx_pause.sge_thr_low = 150;
-				rx_pause.sge_thr_high = 250;
-			}
-
-
-			offset = BAR_USTRORM_INTMEM +
-				 USTORM_ETH_RING_PAUSE_DATA_OFFSET(port,
-								   fp->cl_id);
-			for (j = 0;
-			     j < sizeof(struct ustorm_eth_rx_pause_data_e1h)/4;
-			     j++)
-				REG_WR(bp, offset + j*4,
-				       ((u32 *)&rx_pause)[j]);
-		}
-	}
-
-	memset(&(bp->cmng), 0, sizeof(struct cmng_struct_per_port));
-
-	/* Init rate shaping and fairness contexts */
-	if (IS_E1HMF(bp)) {
-		int vn;
-
-		/* During init there is no active link
-		   Until link is up, set link rate to 10Gbps */
-		bp->link_vars.line_speed = SPEED_10000;
-		bnx2x_init_port_minmax(bp);
-
-		if (!BP_NOMCP(bp))
-			bp->mf_config =
-			      SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
-		bnx2x_calc_vn_weight_sum(bp);
-
-		for (vn = VN_0; vn < E1HVN_MAX; vn++)
-			bnx2x_init_vn_minmax(bp, 2*vn + port);
-
-		/* Enable rate shaping and fairness */
-		bp->cmng.flags.cmng_enables |=
-					CMNG_FLAGS_PER_PORT_RATE_SHAPING_VN;
-
-	} else {
-		/* rate shaping and fairness are disabled */
-		DP(NETIF_MSG_IFUP,
-		   "single function mode  minmax will be disabled\n");
-	}
-
-
-	/* Store cmng structures to internal memory */
-	if (bp->port.pmf)
-		for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++)
-			REG_WR(bp, BAR_XSTRORM_INTMEM +
-			       XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i * 4,
-			       ((u32 *)(&bp->cmng))[i]);
-}
-
-static void bnx2x_init_internal(struct bnx2x *bp, u32 load_code)
-{
-	switch (load_code) {
-	case FW_MSG_CODE_DRV_LOAD_COMMON:
-		bnx2x_init_internal_common(bp);
-		/* no break */
-
-	case FW_MSG_CODE_DRV_LOAD_PORT:
-		bnx2x_init_internal_port(bp);
-		/* no break */
-
-	case FW_MSG_CODE_DRV_LOAD_FUNCTION:
-		bnx2x_init_internal_func(bp);
-		break;
-
-	default:
-		BNX2X_ERR("Unknown load_code (0x%x) from MCP\n", load_code);
-		break;
-	}
-}
-
-static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
-{
-	int i;
-
-	for_each_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-
-		fp->bp = bp;
-		fp->state = BNX2X_FP_STATE_CLOSED;
-		fp->index = i;
-		fp->cl_id = BP_L_ID(bp) + i;
-#ifdef BCM_CNIC
-		fp->sb_id = fp->cl_id + 1;
-#else
-		fp->sb_id = fp->cl_id;
-#endif
-		DP(NETIF_MSG_IFUP,
-		   "queue[%d]:  bnx2x_init_sb(%p,%p)  cl_id %d  sb %d\n",
-		   i, bp, fp->status_blk, fp->cl_id, fp->sb_id);
-		bnx2x_init_sb(bp, fp->status_blk, fp->status_blk_mapping,
-			      fp->sb_id);
-		bnx2x_update_fpsb_idx(fp);
-	}
-
-	/* ensure status block indices were read */
-	rmb();
-
-
-	bnx2x_init_def_sb(bp, bp->def_status_blk, bp->def_status_blk_mapping,
-			  DEF_SB_ID);
-	bnx2x_update_dsb_idx(bp);
-	bnx2x_update_coalesce(bp);
-	bnx2x_init_rx_rings(bp);
-	bnx2x_init_tx_ring(bp);
-	bnx2x_init_sp_ring(bp);
-	bnx2x_init_context(bp);
-	bnx2x_init_internal(bp, load_code);
-	bnx2x_init_ind_table(bp);
-	bnx2x_stats_init(bp);
-
-	/* At this point, we are ready for interrupts */
-	atomic_set(&bp->intr_sem, 0);
-
-	/* flush all before enabling interrupts */
-	mb();
-	mmiowb();
-
-	bnx2x_int_enable(bp);
-
-	/* Check for SPIO5 */
-	bnx2x_attn_int_deasserted0(bp,
-		REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + BP_PORT(bp)*4) &
-				   AEU_INPUTS_ATTN_BITS_SPIO5);
-}
-
-/* end of nic init */
-
-/*
- * gzip service functions
- */
-
-static int bnx2x_gunzip_init(struct bnx2x *bp)
-{
-	bp->gunzip_buf = dma_alloc_coherent(&bp->pdev->dev, FW_BUF_SIZE,
-					    &bp->gunzip_mapping, GFP_KERNEL);
-	if (bp->gunzip_buf  == NULL)
-		goto gunzip_nomem1;
-
-	bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL);
-	if (bp->strm  == NULL)
-		goto gunzip_nomem2;
-
-	bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(),
-				      GFP_KERNEL);
-	if (bp->strm->workspace == NULL)
-		goto gunzip_nomem3;
-
-	return 0;
-
-gunzip_nomem3:
-	kfree(bp->strm);
-	bp->strm = NULL;
-
-gunzip_nomem2:
-	dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf,
-			  bp->gunzip_mapping);
-	bp->gunzip_buf = NULL;
-
-gunzip_nomem1:
-	netdev_err(bp->dev, "Cannot allocate firmware buffer for"
-	       " un-compression\n");
-	return -ENOMEM;
-}
-
-static void bnx2x_gunzip_end(struct bnx2x *bp)
-{
-	kfree(bp->strm->workspace);
-
-	kfree(bp->strm);
-	bp->strm = NULL;
-
-	if (bp->gunzip_buf) {
-		dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf,
-				  bp->gunzip_mapping);
-		bp->gunzip_buf = NULL;
-	}
-}
-
-static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len)
-{
-	int n, rc;
-
-	/* check gzip header */
-	if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED)) {
-		BNX2X_ERR("Bad gzip header\n");
-		return -EINVAL;
-	}
-
-	n = 10;
-
-#define FNAME				0x8
-
-	if (zbuf[3] & FNAME)
-		while ((zbuf[n++] != 0) && (n < len));
-
-	bp->strm->next_in = (typeof(bp->strm->next_in))zbuf + n;
-	bp->strm->avail_in = len - n;
-	bp->strm->next_out = bp->gunzip_buf;
-	bp->strm->avail_out = FW_BUF_SIZE;
-
-	rc = zlib_inflateInit2(bp->strm, -MAX_WBITS);
-	if (rc != Z_OK)
-		return rc;
-
-	rc = zlib_inflate(bp->strm, Z_FINISH);
-	if ((rc != Z_OK) && (rc != Z_STREAM_END))
-		netdev_err(bp->dev, "Firmware decompression error: %s\n",
-			   bp->strm->msg);
-
-	bp->gunzip_outlen = (FW_BUF_SIZE - bp->strm->avail_out);
-	if (bp->gunzip_outlen & 0x3)
-		netdev_err(bp->dev, "Firmware decompression error:"
-				    " gunzip_outlen (%d) not aligned\n",
-				bp->gunzip_outlen);
-	bp->gunzip_outlen >>= 2;
-
-	zlib_inflateEnd(bp->strm);
-
-	if (rc == Z_STREAM_END)
-		return 0;
-
-	return rc;
-}
-
-/* nic load/unload */
-
-/*
- * General service functions
- */
-
-/* send a NIG loopback debug packet */
-static void bnx2x_lb_pckt(struct bnx2x *bp)
-{
-	u32 wb_write[3];
-
-	/* Ethernet source and destination addresses */
-	wb_write[0] = 0x55555555;
-	wb_write[1] = 0x55555555;
-	wb_write[2] = 0x20;		/* SOP */
-	REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3);
-
-	/* NON-IP protocol */
-	wb_write[0] = 0x09000000;
-	wb_write[1] = 0x55555555;
-	wb_write[2] = 0x10;		/* EOP, eop_bvalid = 0 */
-	REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3);
-}
-
-/* some of the internal memories
- * are not directly readable from the driver
- * to test them we send debug packets
- */
-static int bnx2x_int_mem_test(struct bnx2x *bp)
-{
-	int factor;
-	int count, i;
-	u32 val = 0;
-
-	if (CHIP_REV_IS_FPGA(bp))
-		factor = 120;
-	else if (CHIP_REV_IS_EMUL(bp))
-		factor = 200;
-	else
-		factor = 1;
-
-	DP(NETIF_MSG_HW, "start part1\n");
-
-	/* Disable inputs of parser neighbor blocks */
-	REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0);
-	REG_WR(bp, TCM_REG_PRS_IFEN, 0x0);
-	REG_WR(bp, CFC_REG_DEBUG0, 0x1);
-	REG_WR(bp, NIG_REG_PRS_REQ_IN_EN, 0x0);
-
-	/*  Write 0 to parser credits for CFC search request */
-	REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0);
-
-	/* send Ethernet packet */
-	bnx2x_lb_pckt(bp);
-
-	/* TODO do i reset NIG statistic? */
-	/* Wait until NIG register shows 1 packet of size 0x10 */
-	count = 1000 * factor;
-	while (count) {
-
-		bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2);
-		val = *bnx2x_sp(bp, wb_data[0]);
-		if (val == 0x10)
-			break;
-
-		msleep(10);
-		count--;
-	}
-	if (val != 0x10) {
-		BNX2X_ERR("NIG timeout  val = 0x%x\n", val);
-		return -1;
-	}
-
-	/* Wait until PRS register shows 1 packet */
-	count = 1000 * factor;
-	while (count) {
-		val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS);
-		if (val == 1)
-			break;
-
-		msleep(10);
-		count--;
-	}
-	if (val != 0x1) {
-		BNX2X_ERR("PRS timeout val = 0x%x\n", val);
-		return -2;
-	}
-
-	/* Reset and init BRB, PRS */
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x03);
-	msleep(50);
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x03);
-	msleep(50);
-	bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE);
-
-	DP(NETIF_MSG_HW, "part2\n");
-
-	/* Disable inputs of parser neighbor blocks */
-	REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0);
-	REG_WR(bp, TCM_REG_PRS_IFEN, 0x0);
-	REG_WR(bp, CFC_REG_DEBUG0, 0x1);
-	REG_WR(bp, NIG_REG_PRS_REQ_IN_EN, 0x0);
-
-	/* Write 0 to parser credits for CFC search request */
-	REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0);
-
-	/* send 10 Ethernet packets */
-	for (i = 0; i < 10; i++)
-		bnx2x_lb_pckt(bp);
-
-	/* Wait until NIG register shows 10 + 1
-	   packets of size 11*0x10 = 0xb0 */
-	count = 1000 * factor;
-	while (count) {
-
-		bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2);
-		val = *bnx2x_sp(bp, wb_data[0]);
-		if (val == 0xb0)
-			break;
-
-		msleep(10);
-		count--;
-	}
-	if (val != 0xb0) {
-		BNX2X_ERR("NIG timeout  val = 0x%x\n", val);
-		return -3;
-	}
-
-	/* Wait until PRS register shows 2 packets */
-	val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS);
-	if (val != 2)
-		BNX2X_ERR("PRS timeout  val = 0x%x\n", val);
-
-	/* Write 1 to parser credits for CFC search request */
-	REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x1);
-
-	/* Wait until PRS register shows 3 packets */
-	msleep(10 * factor);
-	/* Wait until NIG register shows 1 packet of size 0x10 */
-	val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS);
-	if (val != 3)
-		BNX2X_ERR("PRS timeout  val = 0x%x\n", val);
-
-	/* clear NIG EOP FIFO */
-	for (i = 0; i < 11; i++)
-		REG_RD(bp, NIG_REG_INGRESS_EOP_LB_FIFO);
-	val = REG_RD(bp, NIG_REG_INGRESS_EOP_LB_EMPTY);
-	if (val != 1) {
-		BNX2X_ERR("clear of NIG failed\n");
-		return -4;
-	}
-
-	/* Reset and init BRB, PRS, NIG */
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x03);
-	msleep(50);
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x03);
-	msleep(50);
-	bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE);
-#ifndef BCM_CNIC
-	/* set NIC mode */
-	REG_WR(bp, PRS_REG_NIC_MODE, 1);
-#endif
-
-	/* Enable inputs of parser neighbor blocks */
-	REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x7fffffff);
-	REG_WR(bp, TCM_REG_PRS_IFEN, 0x1);
-	REG_WR(bp, CFC_REG_DEBUG0, 0x0);
-	REG_WR(bp, NIG_REG_PRS_REQ_IN_EN, 0x1);
-
-	DP(NETIF_MSG_HW, "done\n");
-
-	return 0; /* OK */
-}
-
-static void enable_blocks_attention(struct bnx2x *bp)
-{
-	REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0);
-	REG_WR(bp, PXP_REG_PXP_INT_MASK_1, 0);
-	REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0);
-	REG_WR(bp, CFC_REG_CFC_INT_MASK, 0);
-	REG_WR(bp, QM_REG_QM_INT_MASK, 0);
-	REG_WR(bp, TM_REG_TM_INT_MASK, 0);
-	REG_WR(bp, XSDM_REG_XSDM_INT_MASK_0, 0);
-	REG_WR(bp, XSDM_REG_XSDM_INT_MASK_1, 0);
-	REG_WR(bp, XCM_REG_XCM_INT_MASK, 0);
-/*	REG_WR(bp, XSEM_REG_XSEM_INT_MASK_0, 0); */
-/*	REG_WR(bp, XSEM_REG_XSEM_INT_MASK_1, 0); */
-	REG_WR(bp, USDM_REG_USDM_INT_MASK_0, 0);
-	REG_WR(bp, USDM_REG_USDM_INT_MASK_1, 0);
-	REG_WR(bp, UCM_REG_UCM_INT_MASK, 0);
-/*	REG_WR(bp, USEM_REG_USEM_INT_MASK_0, 0); */
-/*	REG_WR(bp, USEM_REG_USEM_INT_MASK_1, 0); */
-	REG_WR(bp, GRCBASE_UPB + PB_REG_PB_INT_MASK, 0);
-	REG_WR(bp, CSDM_REG_CSDM_INT_MASK_0, 0);
-	REG_WR(bp, CSDM_REG_CSDM_INT_MASK_1, 0);
-	REG_WR(bp, CCM_REG_CCM_INT_MASK, 0);
-/*	REG_WR(bp, CSEM_REG_CSEM_INT_MASK_0, 0); */
-/*	REG_WR(bp, CSEM_REG_CSEM_INT_MASK_1, 0); */
-	if (CHIP_REV_IS_FPGA(bp))
-		REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0, 0x580000);
-	else
-		REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0, 0x480000);
-	REG_WR(bp, TSDM_REG_TSDM_INT_MASK_0, 0);
-	REG_WR(bp, TSDM_REG_TSDM_INT_MASK_1, 0);
-	REG_WR(bp, TCM_REG_TCM_INT_MASK, 0);
-/*	REG_WR(bp, TSEM_REG_TSEM_INT_MASK_0, 0); */
-/*	REG_WR(bp, TSEM_REG_TSEM_INT_MASK_1, 0); */
-	REG_WR(bp, CDU_REG_CDU_INT_MASK, 0);
-	REG_WR(bp, DMAE_REG_DMAE_INT_MASK, 0);
-/*	REG_WR(bp, MISC_REG_MISC_INT_MASK, 0); */
-	REG_WR(bp, PBF_REG_PBF_INT_MASK, 0X18);		/* bit 3,4 masked */
-}
-
-static const struct {
-	u32 addr;
-	u32 mask;
-} bnx2x_parity_mask[] = {
-	{PXP_REG_PXP_PRTY_MASK, 0xffffffff},
-	{PXP2_REG_PXP2_PRTY_MASK_0, 0xffffffff},
-	{PXP2_REG_PXP2_PRTY_MASK_1, 0xffffffff},
-	{HC_REG_HC_PRTY_MASK, 0xffffffff},
-	{MISC_REG_MISC_PRTY_MASK, 0xffffffff},
-	{QM_REG_QM_PRTY_MASK, 0x0},
-	{DORQ_REG_DORQ_PRTY_MASK, 0x0},
-	{GRCBASE_UPB + PB_REG_PB_PRTY_MASK, 0x0},
-	{GRCBASE_XPB + PB_REG_PB_PRTY_MASK, 0x0},
-	{SRC_REG_SRC_PRTY_MASK, 0x4}, /* bit 2 */
-	{CDU_REG_CDU_PRTY_MASK, 0x0},
-	{CFC_REG_CFC_PRTY_MASK, 0x0},
-	{DBG_REG_DBG_PRTY_MASK, 0x0},
-	{DMAE_REG_DMAE_PRTY_MASK, 0x0},
-	{BRB1_REG_BRB1_PRTY_MASK, 0x0},
-	{PRS_REG_PRS_PRTY_MASK, (1<<6)},/* bit 6 */
-	{TSDM_REG_TSDM_PRTY_MASK, 0x18},/* bit 3,4 */
-	{CSDM_REG_CSDM_PRTY_MASK, 0x8},	/* bit 3 */
-	{USDM_REG_USDM_PRTY_MASK, 0x38},/* bit 3,4,5 */
-	{XSDM_REG_XSDM_PRTY_MASK, 0x8},	/* bit 3 */
-	{TSEM_REG_TSEM_PRTY_MASK_0, 0x0},
-	{TSEM_REG_TSEM_PRTY_MASK_1, 0x0},
-	{USEM_REG_USEM_PRTY_MASK_0, 0x0},
-	{USEM_REG_USEM_PRTY_MASK_1, 0x0},
-	{CSEM_REG_CSEM_PRTY_MASK_0, 0x0},
-	{CSEM_REG_CSEM_PRTY_MASK_1, 0x0},
-	{XSEM_REG_XSEM_PRTY_MASK_0, 0x0},
-	{XSEM_REG_XSEM_PRTY_MASK_1, 0x0}
-};
-
-static void enable_blocks_parity(struct bnx2x *bp)
-{
-	int i, mask_arr_len =
-		sizeof(bnx2x_parity_mask)/(sizeof(bnx2x_parity_mask[0]));
-
-	for (i = 0; i < mask_arr_len; i++)
-		REG_WR(bp, bnx2x_parity_mask[i].addr,
-			bnx2x_parity_mask[i].mask);
-}
-
-
-static void bnx2x_reset_common(struct bnx2x *bp)
-{
-	/* reset_common */
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
-	       0xd3ffff7f);
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403);
-}
-
-static void bnx2x_init_pxp(struct bnx2x *bp)
-{
-	u16 devctl;
-	int r_order, w_order;
-
-	pci_read_config_word(bp->pdev,
-			     bp->pcie_cap + PCI_EXP_DEVCTL, &devctl);
-	DP(NETIF_MSG_HW, "read 0x%x from devctl\n", devctl);
-	w_order = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
-	if (bp->mrrs == -1)
-		r_order = ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12);
-	else {
-		DP(NETIF_MSG_HW, "force read order to %d\n", bp->mrrs);
-		r_order = bp->mrrs;
-	}
-
-	bnx2x_init_pxp_arb(bp, r_order, w_order);
-}
-
-static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
-{
-	int is_required;
-	u32 val;
-	int port;
-
-	if (BP_NOMCP(bp))
-		return;
-
-	is_required = 0;
-	val = SHMEM_RD(bp, dev_info.shared_hw_config.config2) &
-	      SHARED_HW_CFG_FAN_FAILURE_MASK;
-
-	if (val == SHARED_HW_CFG_FAN_FAILURE_ENABLED)
-		is_required = 1;
-
-	/*
-	 * The fan failure mechanism is usually related to the PHY type since
-	 * the power consumption of the board is affected by the PHY. Currently,
-	 * fan is required for most designs with SFX7101, BCM8727 and BCM8481.
-	 */
-	else if (val == SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE)
-		for (port = PORT_0; port < PORT_MAX; port++) {
-			u32 phy_type =
-				SHMEM_RD(bp, dev_info.port_hw_config[port].
-					 external_phy_config) &
-				PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
-			is_required |=
-				((phy_type ==
-				  PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) ||
-				 (phy_type ==
-				  PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
-				 (phy_type ==
-				  PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481));
-		}
-
-	DP(NETIF_MSG_HW, "fan detection setting: %d\n", is_required);
-
-	if (is_required == 0)
-		return;
-
-	/* Fan failure is indicated by SPIO 5 */
-	bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5,
-		       MISC_REGISTERS_SPIO_INPUT_HI_Z);
-
-	/* set to active low mode */
-	val = REG_RD(bp, MISC_REG_SPIO_INT);
-	val |= ((1 << MISC_REGISTERS_SPIO_5) <<
-					MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
-	REG_WR(bp, MISC_REG_SPIO_INT, val);
-
-	/* enable interrupt to signal the IGU */
-	val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
-	val |= (1 << MISC_REGISTERS_SPIO_5);
-	REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
-}
-
-static int bnx2x_init_common(struct bnx2x *bp)
-{
-	u32 val, i;
-#ifdef BCM_CNIC
-	u32 wb_write[2];
-#endif
-
-	DP(BNX2X_MSG_MCP, "starting common init  func %d\n", BP_FUNC(bp));
-
-	bnx2x_reset_common(bp);
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff);
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, 0xfffc);
-
-	bnx2x_init_block(bp, MISC_BLOCK, COMMON_STAGE);
-	if (CHIP_IS_E1H(bp))
-		REG_WR(bp, MISC_REG_E1HMF_MODE, IS_E1HMF(bp));
-
-	REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x100);
-	msleep(30);
-	REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x0);
-
-	bnx2x_init_block(bp, PXP_BLOCK, COMMON_STAGE);
-	if (CHIP_IS_E1(bp)) {
-		/* enable HW interrupt from PXP on USDM overflow
-		   bit 16 on INT_MASK_0 */
-		REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0);
-	}
-
-	bnx2x_init_block(bp, PXP2_BLOCK, COMMON_STAGE);
-	bnx2x_init_pxp(bp);
-
-#ifdef __BIG_ENDIAN
-	REG_WR(bp, PXP2_REG_RQ_QM_ENDIAN_M, 1);
-	REG_WR(bp, PXP2_REG_RQ_TM_ENDIAN_M, 1);
-	REG_WR(bp, PXP2_REG_RQ_SRC_ENDIAN_M, 1);
-	REG_WR(bp, PXP2_REG_RQ_CDU_ENDIAN_M, 1);
-	REG_WR(bp, PXP2_REG_RQ_DBG_ENDIAN_M, 1);
-	/* make sure this value is 0 */
-	REG_WR(bp, PXP2_REG_RQ_HC_ENDIAN_M, 0);
-
-/*	REG_WR(bp, PXP2_REG_RD_PBF_SWAP_MODE, 1); */
-	REG_WR(bp, PXP2_REG_RD_QM_SWAP_MODE, 1);
-	REG_WR(bp, PXP2_REG_RD_TM_SWAP_MODE, 1);
-	REG_WR(bp, PXP2_REG_RD_SRC_SWAP_MODE, 1);
-	REG_WR(bp, PXP2_REG_RD_CDURD_SWAP_MODE, 1);
-#endif
-
-	REG_WR(bp, PXP2_REG_RQ_CDU_P_SIZE, 2);
-#ifdef BCM_CNIC
-	REG_WR(bp, PXP2_REG_RQ_TM_P_SIZE, 5);
-	REG_WR(bp, PXP2_REG_RQ_QM_P_SIZE, 5);
-	REG_WR(bp, PXP2_REG_RQ_SRC_P_SIZE, 5);
-#endif
-
-	if (CHIP_REV_IS_FPGA(bp) && CHIP_IS_E1H(bp))
-		REG_WR(bp, PXP2_REG_PGL_TAGS_LIMIT, 0x1);
-
-	/* let the HW do it's magic ... */
-	msleep(100);
-	/* finish PXP init */
-	val = REG_RD(bp, PXP2_REG_RQ_CFG_DONE);
-	if (val != 1) {
-		BNX2X_ERR("PXP2 CFG failed\n");
-		return -EBUSY;
-	}
-	val = REG_RD(bp, PXP2_REG_RD_INIT_DONE);
-	if (val != 1) {
-		BNX2X_ERR("PXP2 RD_INIT failed\n");
-		return -EBUSY;
-	}
-
-	REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0);
-	REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0);
-
-	bnx2x_init_block(bp, DMAE_BLOCK, COMMON_STAGE);
-
-	/* clean the DMAE memory */
-	bp->dmae_ready = 1;
-	bnx2x_init_fill(bp, TSEM_REG_PRAM, 0, 8);
-
-	bnx2x_init_block(bp, TCM_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, UCM_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, CCM_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, XCM_BLOCK, COMMON_STAGE);
-
-	bnx2x_read_dmae(bp, XSEM_REG_PASSIVE_BUFFER, 3);
-	bnx2x_read_dmae(bp, CSEM_REG_PASSIVE_BUFFER, 3);
-	bnx2x_read_dmae(bp, TSEM_REG_PASSIVE_BUFFER, 3);
-	bnx2x_read_dmae(bp, USEM_REG_PASSIVE_BUFFER, 3);
-
-	bnx2x_init_block(bp, QM_BLOCK, COMMON_STAGE);
-
-#ifdef BCM_CNIC
-	wb_write[0] = 0;
-	wb_write[1] = 0;
-	for (i = 0; i < 64; i++) {
-		REG_WR(bp, QM_REG_BASEADDR + i*4, 1024 * 4 * (i%16));
-		bnx2x_init_ind_wr(bp, QM_REG_PTRTBL + i*8, wb_write, 2);
-
-		if (CHIP_IS_E1H(bp)) {
-			REG_WR(bp, QM_REG_BASEADDR_EXT_A + i*4, 1024*4*(i%16));
-			bnx2x_init_ind_wr(bp, QM_REG_PTRTBL_EXT_A + i*8,
-					  wb_write, 2);
-		}
-	}
-#endif
-	/* soft reset pulse */
-	REG_WR(bp, QM_REG_SOFT_RESET, 1);
-	REG_WR(bp, QM_REG_SOFT_RESET, 0);
-
-#ifdef BCM_CNIC
-	bnx2x_init_block(bp, TIMERS_BLOCK, COMMON_STAGE);
-#endif
-
-	bnx2x_init_block(bp, DQ_BLOCK, COMMON_STAGE);
-	REG_WR(bp, DORQ_REG_DPM_CID_OFST, BCM_PAGE_SHIFT);
-	if (!CHIP_REV_IS_SLOW(bp)) {
-		/* enable hw interrupt from doorbell Q */
-		REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0);
-	}
-
-	bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE);
-	REG_WR(bp, PRS_REG_A_PRSU_20, 0xf);
-#ifndef BCM_CNIC
-	/* set NIC mode */
-	REG_WR(bp, PRS_REG_NIC_MODE, 1);
-#endif
-	if (CHIP_IS_E1H(bp))
-		REG_WR(bp, PRS_REG_E1HOV_MODE, IS_E1HMF(bp));
-
-	bnx2x_init_block(bp, TSDM_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, CSDM_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, USDM_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, XSDM_BLOCK, COMMON_STAGE);
-
-	bnx2x_init_fill(bp, TSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp));
-	bnx2x_init_fill(bp, USEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp));
-	bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp));
-	bnx2x_init_fill(bp, XSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp));
-
-	bnx2x_init_block(bp, TSEM_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, USEM_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, CSEM_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, XSEM_BLOCK, COMMON_STAGE);
-
-	/* sync semi rtc */
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
-	       0x80000000);
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET,
-	       0x80000000);
-
-	bnx2x_init_block(bp, UPB_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, XPB_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, PBF_BLOCK, COMMON_STAGE);
-
-	REG_WR(bp, SRC_REG_SOFT_RST, 1);
-	for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4)
-		REG_WR(bp, i, random32());
-	bnx2x_init_block(bp, SRCH_BLOCK, COMMON_STAGE);
-#ifdef BCM_CNIC
-	REG_WR(bp, SRC_REG_KEYSEARCH_0, 0x63285672);
-	REG_WR(bp, SRC_REG_KEYSEARCH_1, 0x24b8f2cc);
-	REG_WR(bp, SRC_REG_KEYSEARCH_2, 0x223aef9b);
-	REG_WR(bp, SRC_REG_KEYSEARCH_3, 0x26001e3a);
-	REG_WR(bp, SRC_REG_KEYSEARCH_4, 0x7ae91116);
-	REG_WR(bp, SRC_REG_KEYSEARCH_5, 0x5ce5230b);
-	REG_WR(bp, SRC_REG_KEYSEARCH_6, 0x298d8adf);
-	REG_WR(bp, SRC_REG_KEYSEARCH_7, 0x6eb0ff09);
-	REG_WR(bp, SRC_REG_KEYSEARCH_8, 0x1830f82f);
-	REG_WR(bp, SRC_REG_KEYSEARCH_9, 0x01e46be7);
-#endif
-	REG_WR(bp, SRC_REG_SOFT_RST, 0);
-
-	if (sizeof(union cdu_context) != 1024)
-		/* we currently assume that a context is 1024 bytes */
-		dev_alert(&bp->pdev->dev, "please adjust the size "
-					  "of cdu_context(%ld)\n",
-			 (long)sizeof(union cdu_context));
-
-	bnx2x_init_block(bp, CDU_BLOCK, COMMON_STAGE);
-	val = (4 << 24) + (0 << 12) + 1024;
-	REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val);
-
-	bnx2x_init_block(bp, CFC_BLOCK, COMMON_STAGE);
-	REG_WR(bp, CFC_REG_INIT_REG, 0x7FF);
-	/* enable context validation interrupt from CFC */
-	REG_WR(bp, CFC_REG_CFC_INT_MASK, 0);
-
-	/* set the thresholds to prevent CFC/CDU race */
-	REG_WR(bp, CFC_REG_DEBUG0, 0x20020000);
-
-	bnx2x_init_block(bp, HC_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, MISC_AEU_BLOCK, COMMON_STAGE);
-
-	bnx2x_init_block(bp, PXPCS_BLOCK, COMMON_STAGE);
-	/* Reset PCIE errors for debug */
-	REG_WR(bp, 0x2814, 0xffffffff);
-	REG_WR(bp, 0x3820, 0xffffffff);
-
-	bnx2x_init_block(bp, EMAC0_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, EMAC1_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, DBU_BLOCK, COMMON_STAGE);
-	bnx2x_init_block(bp, DBG_BLOCK, COMMON_STAGE);
-
-	bnx2x_init_block(bp, NIG_BLOCK, COMMON_STAGE);
-	if (CHIP_IS_E1H(bp)) {
-		REG_WR(bp, NIG_REG_LLH_MF_MODE, IS_E1HMF(bp));
-		REG_WR(bp, NIG_REG_LLH_E1HOV_MODE, IS_E1HMF(bp));
-	}
-
-	if (CHIP_REV_IS_SLOW(bp))
-		msleep(200);
-
-	/* finish CFC init */
-	val = reg_poll(bp, CFC_REG_LL_INIT_DONE, 1, 100, 10);
-	if (val != 1) {
-		BNX2X_ERR("CFC LL_INIT failed\n");
-		return -EBUSY;
-	}
-	val = reg_poll(bp, CFC_REG_AC_INIT_DONE, 1, 100, 10);
-	if (val != 1) {
-		BNX2X_ERR("CFC AC_INIT failed\n");
-		return -EBUSY;
-	}
-	val = reg_poll(bp, CFC_REG_CAM_INIT_DONE, 1, 100, 10);
-	if (val != 1) {
-		BNX2X_ERR("CFC CAM_INIT failed\n");
-		return -EBUSY;
-	}
-	REG_WR(bp, CFC_REG_DEBUG0, 0);
-
-	/* read NIG statistic
-	   to see if this is our first up since powerup */
-	bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2);
-	val = *bnx2x_sp(bp, wb_data[0]);
-
-	/* do internal memory self test */
-	if ((CHIP_IS_E1(bp)) && (val == 0) && bnx2x_int_mem_test(bp)) {
-		BNX2X_ERR("internal mem self test failed\n");
-		return -EBUSY;
-	}
-
-	switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
-	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
-	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
-	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-		bp->port.need_hw_lock = 1;
-		break;
-
-	default:
-		break;
-	}
-
-	bnx2x_setup_fan_failure_detection(bp);
-
-	/* clear PXP2 attentions */
-	REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0);
-
-	enable_blocks_attention(bp);
-	if (CHIP_PARITY_SUPPORTED(bp))
-		enable_blocks_parity(bp);
-
-	if (!BP_NOMCP(bp)) {
-		bnx2x_acquire_phy_lock(bp);
-		bnx2x_common_init_phy(bp, bp->common.shmem_base);
-		bnx2x_release_phy_lock(bp);
-	} else
-		BNX2X_ERR("Bootcode is missing - can not initialize link\n");
-
-	return 0;
-}
-
-static int bnx2x_init_port(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	int init_stage = port ? PORT1_STAGE : PORT0_STAGE;
-	u32 low, high;
-	u32 val;
-
-	DP(BNX2X_MSG_MCP, "starting port init  port %d\n", port);
-
-	REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0);
-
-	bnx2x_init_block(bp, PXP_BLOCK, init_stage);
-	bnx2x_init_block(bp, PXP2_BLOCK, init_stage);
-
-	bnx2x_init_block(bp, TCM_BLOCK, init_stage);
-	bnx2x_init_block(bp, UCM_BLOCK, init_stage);
-	bnx2x_init_block(bp, CCM_BLOCK, init_stage);
-	bnx2x_init_block(bp, XCM_BLOCK, init_stage);
-
-#ifdef BCM_CNIC
-	REG_WR(bp, QM_REG_CONNNUM_0 + port*4, 1024/16 - 1);
-
-	bnx2x_init_block(bp, TIMERS_BLOCK, init_stage);
-	REG_WR(bp, TM_REG_LIN0_SCAN_TIME + port*4, 20);
-	REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + port*4, 31);
-#endif
-
-	bnx2x_init_block(bp, DQ_BLOCK, init_stage);
-
-	bnx2x_init_block(bp, BRB1_BLOCK, init_stage);
-	if (CHIP_REV_IS_SLOW(bp) && !CHIP_IS_E1H(bp)) {
-		/* no pause for emulation and FPGA */
-		low = 0;
-		high = 513;
-	} else {
-		if (IS_E1HMF(bp))
-			low = ((bp->flags & ONE_PORT_FLAG) ? 160 : 246);
-		else if (bp->dev->mtu > 4096) {
-			if (bp->flags & ONE_PORT_FLAG)
-				low = 160;
-			else {
-				val = bp->dev->mtu;
-				/* (24*1024 + val*4)/256 */
-				low = 96 + (val/64) + ((val % 64) ? 1 : 0);
-			}
-		} else
-			low = ((bp->flags & ONE_PORT_FLAG) ? 80 : 160);
-		high = low + 56;	/* 14*1024/256 */
-	}
-	REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_0 + port*4, low);
-	REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0 + port*4, high);
-
-
-	bnx2x_init_block(bp, PRS_BLOCK, init_stage);
-
-	bnx2x_init_block(bp, TSDM_BLOCK, init_stage);
-	bnx2x_init_block(bp, CSDM_BLOCK, init_stage);
-	bnx2x_init_block(bp, USDM_BLOCK, init_stage);
-	bnx2x_init_block(bp, XSDM_BLOCK, init_stage);
-
-	bnx2x_init_block(bp, TSEM_BLOCK, init_stage);
-	bnx2x_init_block(bp, USEM_BLOCK, init_stage);
-	bnx2x_init_block(bp, CSEM_BLOCK, init_stage);
-	bnx2x_init_block(bp, XSEM_BLOCK, init_stage);
-
-	bnx2x_init_block(bp, UPB_BLOCK, init_stage);
-	bnx2x_init_block(bp, XPB_BLOCK, init_stage);
-
-	bnx2x_init_block(bp, PBF_BLOCK, init_stage);
-
-	/* configure PBF to work without PAUSE mtu 9000 */
-	REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
-
-	/* update threshold */
-	REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, (9040/16));
-	/* update init credit */
-	REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, (9040/16) + 553 - 22);
-
-	/* probe changes */
-	REG_WR(bp, PBF_REG_INIT_P0 + port*4, 1);
-	msleep(5);
-	REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0);
-
-#ifdef BCM_CNIC
-	bnx2x_init_block(bp, SRCH_BLOCK, init_stage);
-#endif
-	bnx2x_init_block(bp, CDU_BLOCK, init_stage);
-	bnx2x_init_block(bp, CFC_BLOCK, init_stage);
-
-	if (CHIP_IS_E1(bp)) {
-		REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0);
-		REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0);
-	}
-	bnx2x_init_block(bp, HC_BLOCK, init_stage);
-
-	bnx2x_init_block(bp, MISC_AEU_BLOCK, init_stage);
-	/* init aeu_mask_attn_func_0/1:
-	 *  - SF mode: bits 3-7 are masked. only bits 0-2 are in use
-	 *  - MF mode: bit 3 is masked. bits 0-2 are in use as in SF
-	 *             bits 4-7 are used for "per vn group attention" */
-	REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4,
-	       (IS_E1HMF(bp) ? 0xF7 : 0x7));
-
-	bnx2x_init_block(bp, PXPCS_BLOCK, init_stage);
-	bnx2x_init_block(bp, EMAC0_BLOCK, init_stage);
-	bnx2x_init_block(bp, EMAC1_BLOCK, init_stage);
-	bnx2x_init_block(bp, DBU_BLOCK, init_stage);
-	bnx2x_init_block(bp, DBG_BLOCK, init_stage);
-
-	bnx2x_init_block(bp, NIG_BLOCK, init_stage);
-
-	REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);
-
-	if (CHIP_IS_E1H(bp)) {
-		/* 0x2 disable e1hov, 0x1 enable */
-		REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK_MF + port*4,
-		       (IS_E1HMF(bp) ? 0x1 : 0x2));
-
-		{
-			REG_WR(bp, NIG_REG_LLFC_ENABLE_0 + port*4, 0);
-			REG_WR(bp, NIG_REG_LLFC_OUT_EN_0 + port*4, 0);
-			REG_WR(bp, NIG_REG_PAUSE_ENABLE_0 + port*4, 1);
-		}
-	}
-
-	bnx2x_init_block(bp, MCP_BLOCK, init_stage);
-	bnx2x_init_block(bp, DMAE_BLOCK, init_stage);
-
-	switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
-	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-		{
-		u32 swap_val, swap_override, aeu_gpio_mask, offset;
-
-		bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
-			       MISC_REGISTERS_GPIO_INPUT_HI_Z, port);
-
-		/* The GPIO should be swapped if the swap register is
-		   set and active */
-		swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
-		swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
-
-		/* Select function upon port-swap configuration */
-		if (port == 0) {
-			offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
-			aeu_gpio_mask = (swap_val && swap_override) ?
-				AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
-				AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
-		} else {
-			offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
-			aeu_gpio_mask = (swap_val && swap_override) ?
-				AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
-				AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
-		}
-		val = REG_RD(bp, offset);
-		/* add GPIO3 to group */
-		val |= aeu_gpio_mask;
-		REG_WR(bp, offset, val);
-		}
-		break;
-
-	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-	case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-		/* add SPIO 5 to group 0 */
-		{
-		u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
-				       MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
-		val = REG_RD(bp, reg_addr);
-		val |= AEU_INPUTS_ATTN_BITS_SPIO5;
-		REG_WR(bp, reg_addr, val);
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	bnx2x__link_reset(bp);
-
-	return 0;
-}
-
-#define ILT_PER_FUNC		(768/2)
-#define FUNC_ILT_BASE(func)	(func * ILT_PER_FUNC)
-/* the phys address is shifted right 12 bits and has an added
-   1=valid bit added to the 53rd bit
-   then since this is a wide register(TM)
-   we split it into two 32 bit writes
- */
-#define ONCHIP_ADDR1(x)		((u32)(((u64)x >> 12) & 0xFFFFFFFF))
-#define ONCHIP_ADDR2(x)		((u32)((1 << 20) | ((u64)x >> 44)))
-#define PXP_ONE_ILT(x)		(((x) << 10) | x)
-#define PXP_ILT_RANGE(f, l)	(((l) << 10) | f)
-
-#ifdef BCM_CNIC
-#define CNIC_ILT_LINES		127
-#define CNIC_CTX_PER_ILT	16
-#else
-#define CNIC_ILT_LINES		0
-#endif
-
-static void bnx2x_ilt_wr(struct bnx2x *bp, u32 index, dma_addr_t addr)
-{
-	int reg;
-
-	if (CHIP_IS_E1H(bp))
-		reg = PXP2_REG_RQ_ONCHIP_AT_B0 + index*8;
-	else /* E1 */
-		reg = PXP2_REG_RQ_ONCHIP_AT + index*8;
-
-	bnx2x_wb_wr(bp, reg, ONCHIP_ADDR1(addr), ONCHIP_ADDR2(addr));
-}
-
-static int bnx2x_init_func(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	int func = BP_FUNC(bp);
-	u32 addr, val;
-	int i;
-
-	DP(BNX2X_MSG_MCP, "starting func init  func %d\n", func);
-
-	/* set MSI reconfigure capability */
-	addr = (port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0);
-	val = REG_RD(bp, addr);
-	val |= HC_CONFIG_0_REG_MSI_ATTN_EN_0;
-	REG_WR(bp, addr, val);
-
-	i = FUNC_ILT_BASE(func);
-
-	bnx2x_ilt_wr(bp, i, bnx2x_sp_mapping(bp, context));
-	if (CHIP_IS_E1H(bp)) {
-		REG_WR(bp, PXP2_REG_RQ_CDU_FIRST_ILT, i);
-		REG_WR(bp, PXP2_REG_RQ_CDU_LAST_ILT, i + CNIC_ILT_LINES);
-	} else /* E1 */
-		REG_WR(bp, PXP2_REG_PSWRQ_CDU0_L2P + func*4,
-		       PXP_ILT_RANGE(i, i + CNIC_ILT_LINES));
-
-#ifdef BCM_CNIC
-	i += 1 + CNIC_ILT_LINES;
-	bnx2x_ilt_wr(bp, i, bp->timers_mapping);
-	if (CHIP_IS_E1(bp))
-		REG_WR(bp, PXP2_REG_PSWRQ_TM0_L2P + func*4, PXP_ONE_ILT(i));
-	else {
-		REG_WR(bp, PXP2_REG_RQ_TM_FIRST_ILT, i);
-		REG_WR(bp, PXP2_REG_RQ_TM_LAST_ILT, i);
-	}
-
-	i++;
-	bnx2x_ilt_wr(bp, i, bp->qm_mapping);
-	if (CHIP_IS_E1(bp))
-		REG_WR(bp, PXP2_REG_PSWRQ_QM0_L2P + func*4, PXP_ONE_ILT(i));
-	else {
-		REG_WR(bp, PXP2_REG_RQ_QM_FIRST_ILT, i);
-		REG_WR(bp, PXP2_REG_RQ_QM_LAST_ILT, i);
-	}
-
-	i++;
-	bnx2x_ilt_wr(bp, i, bp->t1_mapping);
-	if (CHIP_IS_E1(bp))
-		REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i));
-	else {
-		REG_WR(bp, PXP2_REG_RQ_SRC_FIRST_ILT, i);
-		REG_WR(bp, PXP2_REG_RQ_SRC_LAST_ILT, i);
-	}
-
-	/* tell the searcher where the T2 table is */
-	REG_WR(bp, SRC_REG_COUNTFREE0 + port*4, 16*1024/64);
-
-	bnx2x_wb_wr(bp, SRC_REG_FIRSTFREE0 + port*16,
-		    U64_LO(bp->t2_mapping), U64_HI(bp->t2_mapping));
-
-	bnx2x_wb_wr(bp, SRC_REG_LASTFREE0 + port*16,
-		    U64_LO((u64)bp->t2_mapping + 16*1024 - 64),
-		    U64_HI((u64)bp->t2_mapping + 16*1024 - 64));
-
-	REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + port*4, 10);
-#endif
-
-	if (CHIP_IS_E1H(bp)) {
-		bnx2x_init_block(bp, MISC_BLOCK, FUNC0_STAGE + func);
-		bnx2x_init_block(bp, TCM_BLOCK, FUNC0_STAGE + func);
-		bnx2x_init_block(bp, UCM_BLOCK, FUNC0_STAGE + func);
-		bnx2x_init_block(bp, CCM_BLOCK, FUNC0_STAGE + func);
-		bnx2x_init_block(bp, XCM_BLOCK, FUNC0_STAGE + func);
-		bnx2x_init_block(bp, TSEM_BLOCK, FUNC0_STAGE + func);
-		bnx2x_init_block(bp, USEM_BLOCK, FUNC0_STAGE + func);
-		bnx2x_init_block(bp, CSEM_BLOCK, FUNC0_STAGE + func);
-		bnx2x_init_block(bp, XSEM_BLOCK, FUNC0_STAGE + func);
-
-		REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1);
-		REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port*8, bp->e1hov);
-	}
-
-	/* HC init per function */
-	if (CHIP_IS_E1H(bp)) {
-		REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0);
-
-		REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0);
-		REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0);
-	}
-	bnx2x_init_block(bp, HC_BLOCK, FUNC0_STAGE + func);
-
-	/* Reset PCIE errors for debug */
-	REG_WR(bp, 0x2114, 0xffffffff);
-	REG_WR(bp, 0x2120, 0xffffffff);
-
-	return 0;
-}
-
-static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
-{
-	int i, rc = 0;
-
-	DP(BNX2X_MSG_MCP, "function %d  load_code %x\n",
-	   BP_FUNC(bp), load_code);
-
-	bp->dmae_ready = 0;
-	mutex_init(&bp->dmae_mutex);
-	rc = bnx2x_gunzip_init(bp);
-	if (rc)
-		return rc;
-
-	switch (load_code) {
-	case FW_MSG_CODE_DRV_LOAD_COMMON:
-		rc = bnx2x_init_common(bp);
-		if (rc)
-			goto init_hw_err;
-		/* no break */
-
-	case FW_MSG_CODE_DRV_LOAD_PORT:
-		bp->dmae_ready = 1;
-		rc = bnx2x_init_port(bp);
-		if (rc)
-			goto init_hw_err;
-		/* no break */
-
-	case FW_MSG_CODE_DRV_LOAD_FUNCTION:
-		bp->dmae_ready = 1;
-		rc = bnx2x_init_func(bp);
-		if (rc)
-			goto init_hw_err;
-		break;
-
-	default:
-		BNX2X_ERR("Unknown load_code (0x%x) from MCP\n", load_code);
-		break;
-	}
-
-	if (!BP_NOMCP(bp)) {
-		int func = BP_FUNC(bp);
-
-		bp->fw_drv_pulse_wr_seq =
-				(SHMEM_RD(bp, func_mb[func].drv_pulse_mb) &
-				 DRV_PULSE_SEQ_MASK);
-		DP(BNX2X_MSG_MCP, "drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
-	}
-
-	/* this needs to be done before gunzip end */
-	bnx2x_zero_def_sb(bp);
-	for_each_queue(bp, i)
-		bnx2x_zero_sb(bp, BP_L_ID(bp) + i);
-#ifdef BCM_CNIC
-	bnx2x_zero_sb(bp, BP_L_ID(bp) + i);
-#endif
-
-init_hw_err:
-	bnx2x_gunzip_end(bp);
-
-	return rc;
-}
-
-static void bnx2x_free_mem(struct bnx2x *bp)
-{
-
-#define BNX2X_PCI_FREE(x, y, size) \
-	do { \
-		if (x) { \
-			dma_free_coherent(&bp->pdev->dev, size, x, y); \
-			x = NULL; \
-			y = 0; \
-		} \
-	} while (0)
-
-#define BNX2X_FREE(x) \
-	do { \
-		if (x) { \
-			vfree(x); \
-			x = NULL; \
-		} \
-	} while (0)
-
-	int i;
-
-	/* fastpath */
-	/* Common */
-	for_each_queue(bp, i) {
-
-		/* status blocks */
-		BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk),
-			       bnx2x_fp(bp, i, status_blk_mapping),
-			       sizeof(struct host_status_block));
-	}
-	/* Rx */
-	for_each_queue(bp, i) {
-
-		/* fastpath rx rings: rx_buf rx_desc rx_comp */
-		BNX2X_FREE(bnx2x_fp(bp, i, rx_buf_ring));
-		BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_desc_ring),
-			       bnx2x_fp(bp, i, rx_desc_mapping),
-			       sizeof(struct eth_rx_bd) * NUM_RX_BD);
-
-		BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_comp_ring),
-			       bnx2x_fp(bp, i, rx_comp_mapping),
-			       sizeof(struct eth_fast_path_rx_cqe) *
-			       NUM_RCQ_BD);
-
-		/* SGE ring */
-		BNX2X_FREE(bnx2x_fp(bp, i, rx_page_ring));
-		BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_sge_ring),
-			       bnx2x_fp(bp, i, rx_sge_mapping),
-			       BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
-	}
-	/* Tx */
-	for_each_queue(bp, i) {
-
-		/* fastpath tx rings: tx_buf tx_desc */
-		BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring));
-		BNX2X_PCI_FREE(bnx2x_fp(bp, i, tx_desc_ring),
-			       bnx2x_fp(bp, i, tx_desc_mapping),
-			       sizeof(union eth_tx_bd_types) * NUM_TX_BD);
-	}
-	/* end of fastpath */
-
-	BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping,
-		       sizeof(struct host_def_status_block));
-
-	BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping,
-		       sizeof(struct bnx2x_slowpath));
-
-#ifdef BCM_CNIC
-	BNX2X_PCI_FREE(bp->t1, bp->t1_mapping, 64*1024);
-	BNX2X_PCI_FREE(bp->t2, bp->t2_mapping, 16*1024);
-	BNX2X_PCI_FREE(bp->timers, bp->timers_mapping, 8*1024);
-	BNX2X_PCI_FREE(bp->qm, bp->qm_mapping, 128*1024);
-	BNX2X_PCI_FREE(bp->cnic_sb, bp->cnic_sb_mapping,
-		       sizeof(struct host_status_block));
-#endif
-	BNX2X_PCI_FREE(bp->spq, bp->spq_mapping, BCM_PAGE_SIZE);
-
-#undef BNX2X_PCI_FREE
-#undef BNX2X_KFREE
-}
-
-static int bnx2x_alloc_mem(struct bnx2x *bp)
-{
-
-#define BNX2X_PCI_ALLOC(x, y, size) \
-	do { \
-		x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
-		if (x == NULL) \
-			goto alloc_mem_err; \
-		memset(x, 0, size); \
-	} while (0)
-
-#define BNX2X_ALLOC(x, size) \
-	do { \
-		x = vmalloc(size); \
-		if (x == NULL) \
-			goto alloc_mem_err; \
-		memset(x, 0, size); \
-	} while (0)
-
-	int i;
-
-	/* fastpath */
-	/* Common */
-	for_each_queue(bp, i) {
-		bnx2x_fp(bp, i, bp) = bp;
-
-		/* status blocks */
-		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, status_blk),
-				&bnx2x_fp(bp, i, status_blk_mapping),
-				sizeof(struct host_status_block));
-	}
-	/* Rx */
-	for_each_queue(bp, i) {
-
-		/* fastpath rx rings: rx_buf rx_desc rx_comp */
-		BNX2X_ALLOC(bnx2x_fp(bp, i, rx_buf_ring),
-				sizeof(struct sw_rx_bd) * NUM_RX_BD);
-		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_desc_ring),
-				&bnx2x_fp(bp, i, rx_desc_mapping),
-				sizeof(struct eth_rx_bd) * NUM_RX_BD);
-
-		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_comp_ring),
-				&bnx2x_fp(bp, i, rx_comp_mapping),
-				sizeof(struct eth_fast_path_rx_cqe) *
-				NUM_RCQ_BD);
-
-		/* SGE ring */
-		BNX2X_ALLOC(bnx2x_fp(bp, i, rx_page_ring),
-				sizeof(struct sw_rx_page) * NUM_RX_SGE);
-		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_sge_ring),
-				&bnx2x_fp(bp, i, rx_sge_mapping),
-				BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
-	}
-	/* Tx */
-	for_each_queue(bp, i) {
-
-		/* fastpath tx rings: tx_buf tx_desc */
-		BNX2X_ALLOC(bnx2x_fp(bp, i, tx_buf_ring),
-				sizeof(struct sw_tx_bd) * NUM_TX_BD);
-		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, tx_desc_ring),
-				&bnx2x_fp(bp, i, tx_desc_mapping),
-				sizeof(union eth_tx_bd_types) * NUM_TX_BD);
-	}
-	/* end of fastpath */
-
-	BNX2X_PCI_ALLOC(bp->def_status_blk, &bp->def_status_blk_mapping,
-			sizeof(struct host_def_status_block));
-
-	BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
-			sizeof(struct bnx2x_slowpath));
-
-#ifdef BCM_CNIC
-	BNX2X_PCI_ALLOC(bp->t1, &bp->t1_mapping, 64*1024);
-
-	/* allocate searcher T2 table
-	   we allocate 1/4 of alloc num for T2
-	  (which is not entered into the ILT) */
-	BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, 16*1024);
-
-	/* Initialize T2 (for 1024 connections) */
-	for (i = 0; i < 16*1024; i += 64)
-		*(u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64;
-
-	/* Timer block array (8*MAX_CONN) phys uncached for now 1024 conns */
-	BNX2X_PCI_ALLOC(bp->timers, &bp->timers_mapping, 8*1024);
-
-	/* QM queues (128*MAX_CONN) */
-	BNX2X_PCI_ALLOC(bp->qm, &bp->qm_mapping, 128*1024);
-
-	BNX2X_PCI_ALLOC(bp->cnic_sb, &bp->cnic_sb_mapping,
-			sizeof(struct host_status_block));
-#endif
-
-	/* Slow path ring */
-	BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE);
-
-	return 0;
-
-alloc_mem_err:
-	bnx2x_free_mem(bp);
-	return -ENOMEM;
-
-#undef BNX2X_PCI_ALLOC
-#undef BNX2X_ALLOC
-}
-
-static void bnx2x_free_tx_skbs(struct bnx2x *bp)
-{
-	int i;
-
-	for_each_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-
-		u16 bd_cons = fp->tx_bd_cons;
-		u16 sw_prod = fp->tx_pkt_prod;
-		u16 sw_cons = fp->tx_pkt_cons;
-
-		while (sw_cons != sw_prod) {
-			bd_cons = bnx2x_free_tx_pkt(bp, fp, TX_BD(sw_cons));
-			sw_cons++;
-		}
-	}
-}
-
-static void bnx2x_free_rx_skbs(struct bnx2x *bp)
-{
-	int i, j;
-
-	for_each_queue(bp, j) {
-		struct bnx2x_fastpath *fp = &bp->fp[j];
-
-		for (i = 0; i < NUM_RX_BD; i++) {
-			struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i];
-			struct sk_buff *skb = rx_buf->skb;
-
-			if (skb == NULL)
-				continue;
-
-			dma_unmap_single(&bp->pdev->dev,
-					 dma_unmap_addr(rx_buf, mapping),
-					 bp->rx_buf_size, DMA_FROM_DEVICE);
-
-			rx_buf->skb = NULL;
-			dev_kfree_skb(skb);
-		}
-		if (!fp->disable_tpa)
-			bnx2x_free_tpa_pool(bp, fp, CHIP_IS_E1(bp) ?
-					    ETH_MAX_AGGREGATION_QUEUES_E1 :
-					    ETH_MAX_AGGREGATION_QUEUES_E1H);
-	}
-}
-
-static void bnx2x_free_skbs(struct bnx2x *bp)
-{
-	bnx2x_free_tx_skbs(bp);
-	bnx2x_free_rx_skbs(bp);
-}
-
-static void bnx2x_free_msix_irqs(struct bnx2x *bp)
-{
-	int i, offset = 1;
-
-	free_irq(bp->msix_table[0].vector, bp->dev);
-	DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
-	   bp->msix_table[0].vector);
-
-#ifdef BCM_CNIC
-	offset++;
-#endif
-	for_each_queue(bp, i) {
-		DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq  "
-		   "state %x\n", i, bp->msix_table[i + offset].vector,
-		   bnx2x_fp(bp, i, state));
-
-		free_irq(bp->msix_table[i + offset].vector, &bp->fp[i]);
-	}
-}
-
-static void bnx2x_free_irq(struct bnx2x *bp, bool disable_only)
-{
-	if (bp->flags & USING_MSIX_FLAG) {
-		if (!disable_only)
-			bnx2x_free_msix_irqs(bp);
-		pci_disable_msix(bp->pdev);
-		bp->flags &= ~USING_MSIX_FLAG;
-
-	} else if (bp->flags & USING_MSI_FLAG) {
-		if (!disable_only)
-			free_irq(bp->pdev->irq, bp->dev);
-		pci_disable_msi(bp->pdev);
-		bp->flags &= ~USING_MSI_FLAG;
-
-	} else if (!disable_only)
-		free_irq(bp->pdev->irq, bp->dev);
-}
-
-static int bnx2x_enable_msix(struct bnx2x *bp)
-{
-	int i, rc, offset = 1;
-	int igu_vec = 0;
-
-	bp->msix_table[0].entry = igu_vec;
-	DP(NETIF_MSG_IFUP, "msix_table[0].entry = %d (slowpath)\n", igu_vec);
-
-#ifdef BCM_CNIC
-	igu_vec = BP_L_ID(bp) + offset;
-	bp->msix_table[1].entry = igu_vec;
-	DP(NETIF_MSG_IFUP, "msix_table[1].entry = %d (CNIC)\n", igu_vec);
-	offset++;
-#endif
-	for_each_queue(bp, i) {
-		igu_vec = BP_L_ID(bp) + offset + i;
-		bp->msix_table[i + offset].entry = igu_vec;
-		DP(NETIF_MSG_IFUP, "msix_table[%d].entry = %d "
-		   "(fastpath #%u)\n", i + offset, igu_vec, i);
-	}
-
-	rc = pci_enable_msix(bp->pdev, &bp->msix_table[0],
-			     BNX2X_NUM_QUEUES(bp) + offset);
-
-	/*
-	 * reconfigure number of tx/rx queues according to available
-	 * MSI-X vectors
-	 */
-	if (rc >= BNX2X_MIN_MSIX_VEC_CNT) {
-		/* vectors available for FP */
-		int fp_vec = rc - BNX2X_MSIX_VEC_FP_START;
-
-		DP(NETIF_MSG_IFUP,
-		   "Trying to use less MSI-X vectors: %d\n", rc);
-
-		rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], rc);
-
-		if (rc) {
-			DP(NETIF_MSG_IFUP,
-			   "MSI-X is not attainable  rc %d\n", rc);
-			return rc;
-		}
-
-		bp->num_queues = min(bp->num_queues, fp_vec);
-
-		DP(NETIF_MSG_IFUP, "New queue configuration set: %d\n",
-				  bp->num_queues);
-	} else if (rc) {
-		DP(NETIF_MSG_IFUP, "MSI-X is not attainable  rc %d\n", rc);
-		return rc;
-	}
-
-	bp->flags |= USING_MSIX_FLAG;
-
-	return 0;
-}
-
-static int bnx2x_req_msix_irqs(struct bnx2x *bp)
-{
-	int i, rc, offset = 1;
-
-	rc = request_irq(bp->msix_table[0].vector, bnx2x_msix_sp_int, 0,
-			 bp->dev->name, bp->dev);
-	if (rc) {
-		BNX2X_ERR("request sp irq failed\n");
-		return -EBUSY;
-	}
-
-#ifdef BCM_CNIC
-	offset++;
-#endif
-	for_each_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-		snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
-			 bp->dev->name, i);
-
-		rc = request_irq(bp->msix_table[i + offset].vector,
-				 bnx2x_msix_fp_int, 0, fp->name, fp);
-		if (rc) {
-			BNX2X_ERR("request fp #%d irq failed  rc %d\n", i, rc);
-			bnx2x_free_msix_irqs(bp);
-			return -EBUSY;
-		}
-
-		fp->state = BNX2X_FP_STATE_IRQ;
-	}
-
-	i = BNX2X_NUM_QUEUES(bp);
-	netdev_info(bp->dev, "using MSI-X  IRQs: sp %d  fp[%d] %d"
-	       " ... fp[%d] %d\n",
-	       bp->msix_table[0].vector,
-	       0, bp->msix_table[offset].vector,
-	       i - 1, bp->msix_table[offset + i - 1].vector);
-
-	return 0;
-}
-
-static int bnx2x_enable_msi(struct bnx2x *bp)
-{
-	int rc;
-
-	rc = pci_enable_msi(bp->pdev);
-	if (rc) {
-		DP(NETIF_MSG_IFUP, "MSI is not attainable\n");
-		return -1;
-	}
-	bp->flags |= USING_MSI_FLAG;
-
-	return 0;
-}
-
-static int bnx2x_req_irq(struct bnx2x *bp)
-{
-	unsigned long flags;
-	int rc;
-
-	if (bp->flags & USING_MSI_FLAG)
-		flags = 0;
-	else
-		flags = IRQF_SHARED;
-
-	rc = request_irq(bp->pdev->irq, bnx2x_interrupt, flags,
-			 bp->dev->name, bp->dev);
-	if (!rc)
-		bnx2x_fp(bp, 0, state) = BNX2X_FP_STATE_IRQ;
-
-	return rc;
-}
-
-static void bnx2x_napi_enable(struct bnx2x *bp)
-{
-	int i;
-
-	for_each_queue(bp, i)
-		napi_enable(&bnx2x_fp(bp, i, napi));
-}
-
-static void bnx2x_napi_disable(struct bnx2x *bp)
-{
-	int i;
-
-	for_each_queue(bp, i)
-		napi_disable(&bnx2x_fp(bp, i, napi));
-}
-
-static void bnx2x_netif_start(struct bnx2x *bp)
-{
-	int intr_sem;
-
-	intr_sem = atomic_dec_and_test(&bp->intr_sem);
-	smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
-
-	if (intr_sem) {
-		if (netif_running(bp->dev)) {
-			bnx2x_napi_enable(bp);
-			bnx2x_int_enable(bp);
-			if (bp->state == BNX2X_STATE_OPEN)
-				netif_tx_wake_all_queues(bp->dev);
-		}
-	}
-}
-
-static void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
-{
-	bnx2x_int_disable_sync(bp, disable_hw);
-	bnx2x_napi_disable(bp);
-	netif_tx_disable(bp->dev);
-}
-
-/*
- * Init service functions
- */
-
-/**
- * Sets a MAC in a CAM for a few L2 Clients for E1 chip
- *
- * @param bp driver descriptor
- * @param set set or clear an entry (1 or 0)
- * @param mac pointer to a buffer containing a MAC
- * @param cl_bit_vec bit vector of clients to register a MAC for
- * @param cam_offset offset in a CAM to use
- * @param with_bcast set broadcast MAC as well
- */
-static void bnx2x_set_mac_addr_e1_gen(struct bnx2x *bp, int set, u8 *mac,
-				      u32 cl_bit_vec, u8 cam_offset,
-				      u8 with_bcast)
-{
-	struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config);
-	int port = BP_PORT(bp);
-
-	/* CAM allocation
-	 * unicasts 0-31:port0 32-63:port1
-	 * multicast 64-127:port0 128-191:port1
-	 */
-	config->hdr.length = 1 + (with_bcast ? 1 : 0);
-	config->hdr.offset = cam_offset;
-	config->hdr.client_id = 0xff;
-	config->hdr.reserved1 = 0;
-
-	/* primary MAC */
-	config->config_table[0].cam_entry.msb_mac_addr =
-					swab16(*(u16 *)&mac[0]);
-	config->config_table[0].cam_entry.middle_mac_addr =
-					swab16(*(u16 *)&mac[2]);
-	config->config_table[0].cam_entry.lsb_mac_addr =
-					swab16(*(u16 *)&mac[4]);
-	config->config_table[0].cam_entry.flags = cpu_to_le16(port);
-	if (set)
-		config->config_table[0].target_table_entry.flags = 0;
-	else
-		CAM_INVALIDATE(config->config_table[0]);
-	config->config_table[0].target_table_entry.clients_bit_vector =
-						cpu_to_le32(cl_bit_vec);
-	config->config_table[0].target_table_entry.vlan_id = 0;
-
-	DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x)\n",
-	   (set ? "setting" : "clearing"),
-	   config->config_table[0].cam_entry.msb_mac_addr,
-	   config->config_table[0].cam_entry.middle_mac_addr,
-	   config->config_table[0].cam_entry.lsb_mac_addr);
-
-	/* broadcast */
-	if (with_bcast) {
-		config->config_table[1].cam_entry.msb_mac_addr =
-			cpu_to_le16(0xffff);
-		config->config_table[1].cam_entry.middle_mac_addr =
-			cpu_to_le16(0xffff);
-		config->config_table[1].cam_entry.lsb_mac_addr =
-			cpu_to_le16(0xffff);
-		config->config_table[1].cam_entry.flags = cpu_to_le16(port);
-		if (set)
-			config->config_table[1].target_table_entry.flags =
-					TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST;
-		else
-			CAM_INVALIDATE(config->config_table[1]);
-		config->config_table[1].target_table_entry.clients_bit_vector =
-							cpu_to_le32(cl_bit_vec);
-		config->config_table[1].target_table_entry.vlan_id = 0;
-	}
-
-	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
-		      U64_HI(bnx2x_sp_mapping(bp, mac_config)),
-		      U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
-}
-
-/**
- * Sets a MAC in a CAM for a few L2 Clients for E1H chip
- *
- * @param bp driver descriptor
- * @param set set or clear an entry (1 or 0)
- * @param mac pointer to a buffer containing a MAC
- * @param cl_bit_vec bit vector of clients to register a MAC for
- * @param cam_offset offset in a CAM to use
- */
-static void bnx2x_set_mac_addr_e1h_gen(struct bnx2x *bp, int set, u8 *mac,
-				       u32 cl_bit_vec, u8 cam_offset)
-{
-	struct mac_configuration_cmd_e1h *config =
-		(struct mac_configuration_cmd_e1h *)bnx2x_sp(bp, mac_config);
-
-	config->hdr.length = 1;
-	config->hdr.offset = cam_offset;
-	config->hdr.client_id = 0xff;
-	config->hdr.reserved1 = 0;
-
-	/* primary MAC */
-	config->config_table[0].msb_mac_addr =
-					swab16(*(u16 *)&mac[0]);
-	config->config_table[0].middle_mac_addr =
-					swab16(*(u16 *)&mac[2]);
-	config->config_table[0].lsb_mac_addr =
-					swab16(*(u16 *)&mac[4]);
-	config->config_table[0].clients_bit_vector =
-					cpu_to_le32(cl_bit_vec);
-	config->config_table[0].vlan_id = 0;
-	config->config_table[0].e1hov_id = cpu_to_le16(bp->e1hov);
-	if (set)
-		config->config_table[0].flags = BP_PORT(bp);
-	else
-		config->config_table[0].flags =
-				MAC_CONFIGURATION_ENTRY_E1H_ACTION_TYPE;
-
-	DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x)  E1HOV %d  CLID mask %d\n",
-	   (set ? "setting" : "clearing"),
-	   config->config_table[0].msb_mac_addr,
-	   config->config_table[0].middle_mac_addr,
-	   config->config_table[0].lsb_mac_addr, bp->e1hov, cl_bit_vec);
-
-	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
-		      U64_HI(bnx2x_sp_mapping(bp, mac_config)),
-		      U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
-}
-
-static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
-			     int *state_p, int poll)
-{
-	/* can take a while if any port is running */
-	int cnt = 5000;
-
-	DP(NETIF_MSG_IFUP, "%s for state to become %x on IDX [%d]\n",
-	   poll ? "polling" : "waiting", state, idx);
-
-	might_sleep();
-	while (cnt--) {
-		if (poll) {
-			bnx2x_rx_int(bp->fp, 10);
-			/* if index is different from 0
-			 * the reply for some commands will
-			 * be on the non default queue
-			 */
-			if (idx)
-				bnx2x_rx_int(&bp->fp[idx], 10);
-		}
-
-		mb(); /* state is changed by bnx2x_sp_event() */
-		if (*state_p == state) {
-#ifdef BNX2X_STOP_ON_ERROR
-			DP(NETIF_MSG_IFUP, "exit  (cnt %d)\n", 5000 - cnt);
-#endif
-			return 0;
-		}
-
-		msleep(1);
-
-		if (bp->panic)
-			return -EIO;
-	}
-
-	/* timeout! */
-	BNX2X_ERR("timeout %s for state %x on IDX [%d]\n",
-		  poll ? "polling" : "waiting", state, idx);
-#ifdef BNX2X_STOP_ON_ERROR
-	bnx2x_panic();
-#endif
-
-	return -EBUSY;
-}
-
-static void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set)
-{
-	bp->set_mac_pending++;
-	smp_wmb();
-
-	bnx2x_set_mac_addr_e1h_gen(bp, set, bp->dev->dev_addr,
-				   (1 << bp->fp->cl_id), BP_FUNC(bp));
-
-	/* Wait for a completion */
-	bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
-}
-
-static void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set)
-{
-	bp->set_mac_pending++;
-	smp_wmb();
-
-	bnx2x_set_mac_addr_e1_gen(bp, set, bp->dev->dev_addr,
-				  (1 << bp->fp->cl_id), (BP_PORT(bp) ? 32 : 0),
-				  1);
-
-	/* Wait for a completion */
-	bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
-}
-
-#ifdef BCM_CNIC
-/**
- * Set iSCSI MAC(s) at the next enties in the CAM after the ETH
- * MAC(s). This function will wait until the ramdord completion
- * returns.
- *
- * @param bp driver handle
- * @param set set or clear the CAM entry
- *
- * @return 0 if cussess, -ENODEV if ramrod doesn't return.
- */
-static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set)
-{
-	u32 cl_bit_vec = (1 << BCM_ISCSI_ETH_CL_ID);
-
-	bp->set_mac_pending++;
-	smp_wmb();
-
-	/* Send a SET_MAC ramrod */
-	if (CHIP_IS_E1(bp))
-		bnx2x_set_mac_addr_e1_gen(bp, set, bp->iscsi_mac,
-				  cl_bit_vec, (BP_PORT(bp) ? 32 : 0) + 2,
-				  1);
-	else
-		/* CAM allocation for E1H
-		* unicasts: by func number
-		* multicast: 20+FUNC*20, 20 each
-		*/
-		bnx2x_set_mac_addr_e1h_gen(bp, set, bp->iscsi_mac,
-				   cl_bit_vec, E1H_FUNC_MAX + BP_FUNC(bp));
-
-	/* Wait for a completion when setting */
-	bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
-
-	return 0;
-}
-#endif
-
-static int bnx2x_setup_leading(struct bnx2x *bp)
-{
-	int rc;
-
-	/* reset IGU state */
-	bnx2x_ack_sb(bp, bp->fp[0].sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
-
-	/* SETUP ramrod */
-	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_SETUP, 0, 0, 0, 0);
-
-	/* Wait for completion */
-	rc = bnx2x_wait_ramrod(bp, BNX2X_STATE_OPEN, 0, &(bp->state), 0);
-
-	return rc;
-}
-
-static int bnx2x_setup_multi(struct bnx2x *bp, int index)
-{
-	struct bnx2x_fastpath *fp = &bp->fp[index];
-
-	/* reset IGU state */
-	bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
-
-	/* SETUP ramrod */
-	fp->state = BNX2X_FP_STATE_OPENING;
-	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_SETUP, index, 0,
-		      fp->cl_id, 0);
-
-	/* Wait for completion */
-	return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_OPEN, index,
-				 &(fp->state), 0);
-}
-
-static int bnx2x_poll(struct napi_struct *napi, int budget);
-
-static void bnx2x_set_num_queues_msix(struct bnx2x *bp)
-{
-
-	switch (bp->multi_mode) {
-	case ETH_RSS_MODE_DISABLED:
-		bp->num_queues = 1;
-		break;
-
-	case ETH_RSS_MODE_REGULAR:
-		if (num_queues)
-			bp->num_queues = min_t(u32, num_queues,
-						  BNX2X_MAX_QUEUES(bp));
-		else
-			bp->num_queues = min_t(u32, num_online_cpus(),
-						  BNX2X_MAX_QUEUES(bp));
-		break;
-
-
-	default:
-		bp->num_queues = 1;
-		break;
-	}
-}
-
-static int bnx2x_set_num_queues(struct bnx2x *bp)
-{
-	int rc = 0;
-
-	switch (int_mode) {
-	case INT_MODE_INTx:
-	case INT_MODE_MSI:
-		bp->num_queues = 1;
-		DP(NETIF_MSG_IFUP, "set number of queues to 1\n");
-		break;
-	default:
-		/* Set number of queues according to bp->multi_mode value */
-		bnx2x_set_num_queues_msix(bp);
-
-		DP(NETIF_MSG_IFUP, "set number of queues to %d\n",
-		   bp->num_queues);
-
-		/* if we can't use MSI-X we only need one fp,
-		 * so try to enable MSI-X with the requested number of fp's
-		 * and fallback to MSI or legacy INTx with one fp
-		 */
-		rc = bnx2x_enable_msix(bp);
-		if (rc)
-			/* failed to enable MSI-X */
-			bp->num_queues = 1;
-		break;
-	}
-	bp->dev->real_num_tx_queues = bp->num_queues;
-	return rc;
-}
-
-#ifdef BCM_CNIC
-static int bnx2x_cnic_notify(struct bnx2x *bp, int cmd);
-static void bnx2x_setup_cnic_irq_info(struct bnx2x *bp);
-#endif
-
-/* must be called with rtnl_lock */
-static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
-{
-	u32 load_code;
-	int i, rc;
-
-#ifdef BNX2X_STOP_ON_ERROR
-	if (unlikely(bp->panic))
-		return -EPERM;
-#endif
-
-	bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
-
-	rc = bnx2x_set_num_queues(bp);
-
-	if (bnx2x_alloc_mem(bp)) {
-		bnx2x_free_irq(bp, true);
-		return -ENOMEM;
-	}
-
-	for_each_queue(bp, i)
-		bnx2x_fp(bp, i, disable_tpa) =
-					((bp->flags & TPA_ENABLE_FLAG) == 0);
-
-	for_each_queue(bp, i)
-		netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
-			       bnx2x_poll, 128);
-
-	bnx2x_napi_enable(bp);
-
-	if (bp->flags & USING_MSIX_FLAG) {
-		rc = bnx2x_req_msix_irqs(bp);
-		if (rc) {
-			bnx2x_free_irq(bp, true);
-			goto load_error1;
-		}
-	} else {
-		/* Fall to INTx if failed to enable MSI-X due to lack of
-		   memory (in bnx2x_set_num_queues()) */
-		if ((rc != -ENOMEM) && (int_mode != INT_MODE_INTx))
-			bnx2x_enable_msi(bp);
-		bnx2x_ack_int(bp);
-		rc = bnx2x_req_irq(bp);
-		if (rc) {
-			BNX2X_ERR("IRQ request failed  rc %d, aborting\n", rc);
-			bnx2x_free_irq(bp, true);
-			goto load_error1;
-		}
-		if (bp->flags & USING_MSI_FLAG) {
-			bp->dev->irq = bp->pdev->irq;
-			netdev_info(bp->dev, "using MSI  IRQ %d\n",
-				    bp->pdev->irq);
-		}
-	}
-
-	/* Send LOAD_REQUEST command to MCP
-	   Returns the type of LOAD command:
-	   if it is the first port to be initialized
-	   common blocks should be initialized, otherwise - not
-	*/
-	if (!BP_NOMCP(bp)) {
-		load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ);
-		if (!load_code) {
-			BNX2X_ERR("MCP response failure, aborting\n");
-			rc = -EBUSY;
-			goto load_error2;
-		}
-		if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) {
-			rc = -EBUSY; /* other port in diagnostic mode */
-			goto load_error2;
-		}
-
-	} else {
-		int port = BP_PORT(bp);
-
-		DP(NETIF_MSG_IFUP, "NO MCP - load counts      %d, %d, %d\n",
-		   load_count[0], load_count[1], load_count[2]);
-		load_count[0]++;
-		load_count[1 + port]++;
-		DP(NETIF_MSG_IFUP, "NO MCP - new load counts  %d, %d, %d\n",
-		   load_count[0], load_count[1], load_count[2]);
-		if (load_count[0] == 1)
-			load_code = FW_MSG_CODE_DRV_LOAD_COMMON;
-		else if (load_count[1 + port] == 1)
-			load_code = FW_MSG_CODE_DRV_LOAD_PORT;
-		else
-			load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION;
-	}
-
-	if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
-	    (load_code == FW_MSG_CODE_DRV_LOAD_PORT))
-		bp->port.pmf = 1;
-	else
-		bp->port.pmf = 0;
-	DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
-
-	/* Initialize HW */
-	rc = bnx2x_init_hw(bp, load_code);
-	if (rc) {
-		BNX2X_ERR("HW init failed, aborting\n");
-		bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
-		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
-		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
-		goto load_error2;
-	}
-
-	/* Setup NIC internals and enable interrupts */
-	bnx2x_nic_init(bp, load_code);
-
-	if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) &&
-	    (bp->common.shmem2_base))
-		SHMEM2_WR(bp, dcc_support,
-			  (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
-			   SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
-
-	/* Send LOAD_DONE command to MCP */
-	if (!BP_NOMCP(bp)) {
-		load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
-		if (!load_code) {
-			BNX2X_ERR("MCP response failure, aborting\n");
-			rc = -EBUSY;
-			goto load_error3;
-		}
-	}
-
-	bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
-
-	rc = bnx2x_setup_leading(bp);
-	if (rc) {
-		BNX2X_ERR("Setup leading failed!\n");
-#ifndef BNX2X_STOP_ON_ERROR
-		goto load_error3;
-#else
-		bp->panic = 1;
-		return -EBUSY;
-#endif
-	}
-
-	if (CHIP_IS_E1H(bp))
-		if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) {
-			DP(NETIF_MSG_IFUP, "mf_cfg function disabled\n");
-			bp->flags |= MF_FUNC_DIS;
-		}
-
-	if (bp->state == BNX2X_STATE_OPEN) {
-#ifdef BCM_CNIC
-		/* Enable Timer scan */
-		REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 1);
-#endif
-		for_each_nondefault_queue(bp, i) {
-			rc = bnx2x_setup_multi(bp, i);
-			if (rc)
-#ifdef BCM_CNIC
-				goto load_error4;
-#else
-				goto load_error3;
-#endif
-		}
-
-		if (CHIP_IS_E1(bp))
-			bnx2x_set_eth_mac_addr_e1(bp, 1);
-		else
-			bnx2x_set_eth_mac_addr_e1h(bp, 1);
-#ifdef BCM_CNIC
-		/* Set iSCSI L2 MAC */
-		mutex_lock(&bp->cnic_mutex);
-		if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD) {
-			bnx2x_set_iscsi_eth_mac_addr(bp, 1);
-			bp->cnic_flags |= BNX2X_CNIC_FLAG_MAC_SET;
-			bnx2x_init_sb(bp, bp->cnic_sb, bp->cnic_sb_mapping,
-				      CNIC_SB_ID(bp));
-		}
-		mutex_unlock(&bp->cnic_mutex);
-#endif
-	}
-
-	if (bp->port.pmf)
-		bnx2x_initial_phy_init(bp, load_mode);
-
-	/* Start fast path */
-	switch (load_mode) {
-	case LOAD_NORMAL:
-		if (bp->state == BNX2X_STATE_OPEN) {
-			/* Tx queue should be only reenabled */
-			netif_tx_wake_all_queues(bp->dev);
-		}
-		/* Initialize the receive filter. */
-		bnx2x_set_rx_mode(bp->dev);
-		break;
-
-	case LOAD_OPEN:
-		netif_tx_start_all_queues(bp->dev);
-		if (bp->state != BNX2X_STATE_OPEN)
-			netif_tx_disable(bp->dev);
-		/* Initialize the receive filter. */
-		bnx2x_set_rx_mode(bp->dev);
-		break;
-
-	case LOAD_DIAG:
-		/* Initialize the receive filter. */
-		bnx2x_set_rx_mode(bp->dev);
-		bp->state = BNX2X_STATE_DIAG;
-		break;
-
-	default:
-		break;
-	}
-
-	if (!bp->port.pmf)
-		bnx2x__link_status_update(bp);
-
-	/* start the timer */
-	mod_timer(&bp->timer, jiffies + bp->current_interval);
-
-#ifdef BCM_CNIC
-	bnx2x_setup_cnic_irq_info(bp);
-	if (bp->state == BNX2X_STATE_OPEN)
-		bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD);
-#endif
-	bnx2x_inc_load_cnt(bp);
-
-	return 0;
-
-#ifdef BCM_CNIC
-load_error4:
-	/* Disable Timer scan */
-	REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 0);
-#endif
-load_error3:
-	bnx2x_int_disable_sync(bp, 1);
-	if (!BP_NOMCP(bp)) {
-		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
-		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
-	}
-	bp->port.pmf = 0;
-	/* Free SKBs, SGEs, TPA pool and driver internals */
-	bnx2x_free_skbs(bp);
-	for_each_queue(bp, i)
-		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
-load_error2:
-	/* Release IRQs */
-	bnx2x_free_irq(bp, false);
-load_error1:
-	bnx2x_napi_disable(bp);
-	for_each_queue(bp, i)
-		netif_napi_del(&bnx2x_fp(bp, i, napi));
-	bnx2x_free_mem(bp);
-
-	return rc;
-}
-
-static int bnx2x_stop_multi(struct bnx2x *bp, int index)
-{
-	struct bnx2x_fastpath *fp = &bp->fp[index];
-	int rc;
-
-	/* halt the connection */
-	fp->state = BNX2X_FP_STATE_HALTING;
-	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, index, 0, fp->cl_id, 0);
-
-	/* Wait for completion */
-	rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, index,
-			       &(fp->state), 1);
-	if (rc) /* timeout */
-		return rc;
-
-	/* delete cfc entry */
-	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CFC_DEL, index, 0, 0, 1);
-
-	/* Wait for completion */
-	rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_CLOSED, index,
-			       &(fp->state), 1);
-	return rc;
-}
-
-static int bnx2x_stop_leading(struct bnx2x *bp)
-{
-	__le16 dsb_sp_prod_idx;
-	/* if the other port is handling traffic,
-	   this can take a lot of time */
-	int cnt = 500;
-	int rc;
-
-	might_sleep();
-
-	/* Send HALT ramrod */
-	bp->fp[0].state = BNX2X_FP_STATE_HALTING;
-	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, 0, 0, bp->fp->cl_id, 0);
-
-	/* Wait for completion */
-	rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, 0,
-			       &(bp->fp[0].state), 1);
-	if (rc) /* timeout */
-		return rc;
-
-	dsb_sp_prod_idx = *bp->dsb_sp_prod;
-
-	/* Send PORT_DELETE ramrod */
-	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_DEL, 0, 0, 0, 1);
-
-	/* Wait for completion to arrive on default status block
-	   we are going to reset the chip anyway
-	   so there is not much to do if this times out
-	 */
-	while (dsb_sp_prod_idx == *bp->dsb_sp_prod) {
-		if (!cnt) {
-			DP(NETIF_MSG_IFDOWN, "timeout waiting for port del "
-			   "dsb_sp_prod 0x%x != dsb_sp_prod_idx 0x%x\n",
-			   *bp->dsb_sp_prod, dsb_sp_prod_idx);
-#ifdef BNX2X_STOP_ON_ERROR
-			bnx2x_panic();
-#endif
-			rc = -EBUSY;
-			break;
-		}
-		cnt--;
-		msleep(1);
-		rmb(); /* Refresh the dsb_sp_prod */
-	}
-	bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD;
-	bp->fp[0].state = BNX2X_FP_STATE_CLOSED;
-
-	return rc;
-}
-
-static void bnx2x_reset_func(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	int func = BP_FUNC(bp);
-	int base, i;
-
-	/* Configure IGU */
-	REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0);
-	REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0);
-
-#ifdef BCM_CNIC
-	/* Disable Timer scan */
-	REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 0);
-	/*
-	 * Wait for at least 10ms and up to 2 second for the timers scan to
-	 * complete
-	 */
-	for (i = 0; i < 200; i++) {
-		msleep(10);
-		if (!REG_RD(bp, TM_REG_LIN0_SCAN_ON + port*4))
-			break;
-	}
-#endif
-	/* Clear ILT */
-	base = FUNC_ILT_BASE(func);
-	for (i = base; i < base + ILT_PER_FUNC; i++)
-		bnx2x_ilt_wr(bp, i, 0);
-}
-
-static void bnx2x_reset_port(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	u32 val;
-
-	REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0);
-
-	/* Do not rcv packets to BRB */
-	REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK + port*4, 0x0);
-	/* Do not direct rcv packets that are not for MCP to the BRB */
-	REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_NOT_MCP :
-			   NIG_REG_LLH0_BRB1_NOT_MCP), 0x0);
-
-	/* Configure AEU */
-	REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, 0);
-
-	msleep(100);
-	/* Check for BRB port occupancy */
-	val = REG_RD(bp, BRB1_REG_PORT_NUM_OCC_BLOCKS_0 + port*4);
-	if (val)
-		DP(NETIF_MSG_IFDOWN,
-		   "BRB1 is not empty  %d blocks are occupied\n", val);
-
-	/* TODO: Close Doorbell port? */
-}
-
-static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code)
-{
-	DP(BNX2X_MSG_MCP, "function %d  reset_code %x\n",
-	   BP_FUNC(bp), reset_code);
-
-	switch (reset_code) {
-	case FW_MSG_CODE_DRV_UNLOAD_COMMON:
-		bnx2x_reset_port(bp);
-		bnx2x_reset_func(bp);
-		bnx2x_reset_common(bp);
-		break;
-
-	case FW_MSG_CODE_DRV_UNLOAD_PORT:
-		bnx2x_reset_port(bp);
-		bnx2x_reset_func(bp);
-		break;
-
-	case FW_MSG_CODE_DRV_UNLOAD_FUNCTION:
-		bnx2x_reset_func(bp);
-		break;
-
-	default:
-		BNX2X_ERR("Unknown reset_code (0x%x) from MCP\n", reset_code);
-		break;
-	}
-}
-
-static void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
-{
-	int port = BP_PORT(bp);
-	u32 reset_code = 0;
-	int i, cnt, rc;
-
-	/* Wait until tx fastpath tasks complete */
-	for_each_queue(bp, i) {
-		struct bnx2x_fastpath *fp = &bp->fp[i];
-
-		cnt = 1000;
-		while (bnx2x_has_tx_work_unload(fp)) {
-
-			bnx2x_tx_int(fp);
-			if (!cnt) {
-				BNX2X_ERR("timeout waiting for queue[%d]\n",
-					  i);
-#ifdef BNX2X_STOP_ON_ERROR
-				bnx2x_panic();
-				return -EBUSY;
-#else
-				break;
-#endif
-			}
-			cnt--;
-			msleep(1);
-		}
-	}
-	/* Give HW time to discard old tx messages */
-	msleep(1);
-
-	if (CHIP_IS_E1(bp)) {
-		struct mac_configuration_cmd *config =
-						bnx2x_sp(bp, mcast_config);
-
-		bnx2x_set_eth_mac_addr_e1(bp, 0);
-
-		for (i = 0; i < config->hdr.length; i++)
-			CAM_INVALIDATE(config->config_table[i]);
-
-		config->hdr.length = i;
-		if (CHIP_REV_IS_SLOW(bp))
-			config->hdr.offset = BNX2X_MAX_EMUL_MULTI*(1 + port);
-		else
-			config->hdr.offset = BNX2X_MAX_MULTICAST*(1 + port);
-		config->hdr.client_id = bp->fp->cl_id;
-		config->hdr.reserved1 = 0;
-
-		bp->set_mac_pending++;
-		smp_wmb();
-
-		bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
-			      U64_HI(bnx2x_sp_mapping(bp, mcast_config)),
-			      U64_LO(bnx2x_sp_mapping(bp, mcast_config)), 0);
-
-	} else { /* E1H */
-		REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
-
-		bnx2x_set_eth_mac_addr_e1h(bp, 0);
-
-		for (i = 0; i < MC_HASH_SIZE; i++)
-			REG_WR(bp, MC_HASH_OFFSET(bp, i), 0);
-
-		REG_WR(bp, MISC_REG_E1HMF_MODE, 0);
-	}
-#ifdef BCM_CNIC
-	/* Clear iSCSI L2 MAC */
-	mutex_lock(&bp->cnic_mutex);
-	if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) {
-		bnx2x_set_iscsi_eth_mac_addr(bp, 0);
-		bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET;
-	}
-	mutex_unlock(&bp->cnic_mutex);
-#endif
-
-	if (unload_mode == UNLOAD_NORMAL)
-		reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
-
-	else if (bp->flags & NO_WOL_FLAG)
-		reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP;
-
-	else if (bp->wol) {
-		u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
-		u8 *mac_addr = bp->dev->dev_addr;
-		u32 val;
-		/* The mac address is written to entries 1-4 to
-		   preserve entry 0 which is used by the PMF */
-		u8 entry = (BP_E1HVN(bp) + 1)*8;
-
-		val = (mac_addr[0] << 8) | mac_addr[1];
-		EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry, val);
-
-		val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
-		      (mac_addr[4] << 8) | mac_addr[5];
-		EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry + 4, val);
-
-		reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN;
-
-	} else
-		reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
-
-	/* Close multi and leading connections
-	   Completions for ramrods are collected in a synchronous way */
-	for_each_nondefault_queue(bp, i)
-		if (bnx2x_stop_multi(bp, i))
-			goto unload_error;
-
-	rc = bnx2x_stop_leading(bp);
-	if (rc) {
-		BNX2X_ERR("Stop leading failed!\n");
-#ifdef BNX2X_STOP_ON_ERROR
-		return -EBUSY;
-#else
-		goto unload_error;
-#endif
-	}
-
-unload_error:
-	if (!BP_NOMCP(bp))
-		reset_code = bnx2x_fw_command(bp, reset_code);
-	else {
-		DP(NETIF_MSG_IFDOWN, "NO MCP - load counts      %d, %d, %d\n",
-		   load_count[0], load_count[1], load_count[2]);
-		load_count[0]--;
-		load_count[1 + port]--;
-		DP(NETIF_MSG_IFDOWN, "NO MCP - new load counts  %d, %d, %d\n",
-		   load_count[0], load_count[1], load_count[2]);
-		if (load_count[0] == 0)
-			reset_code = FW_MSG_CODE_DRV_UNLOAD_COMMON;
-		else if (load_count[1 + port] == 0)
-			reset_code = FW_MSG_CODE_DRV_UNLOAD_PORT;
-		else
-			reset_code = FW_MSG_CODE_DRV_UNLOAD_FUNCTION;
-	}
-
-	if ((reset_code == FW_MSG_CODE_DRV_UNLOAD_COMMON) ||
-	    (reset_code == FW_MSG_CODE_DRV_UNLOAD_PORT))
-		bnx2x__link_reset(bp);
-
-	/* Reset the chip */
-	bnx2x_reset_chip(bp, reset_code);
-
-	/* Report UNLOAD_DONE to MCP */
-	if (!BP_NOMCP(bp))
-		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
-
-}
-
-static inline void bnx2x_disable_close_the_gate(struct bnx2x *bp)
-{
-	u32 val;
-
-	DP(NETIF_MSG_HW, "Disabling \"close the gates\"\n");
-
-	if (CHIP_IS_E1(bp)) {
-		int port = BP_PORT(bp);
-		u32 addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
-			MISC_REG_AEU_MASK_ATTN_FUNC_0;
-
-		val = REG_RD(bp, addr);
-		val &= ~(0x300);
-		REG_WR(bp, addr, val);
-	} else if (CHIP_IS_E1H(bp)) {
-		val = REG_RD(bp, MISC_REG_AEU_GENERAL_MASK);
-		val &= ~(MISC_AEU_GENERAL_MASK_REG_AEU_PXP_CLOSE_MASK |
-			 MISC_AEU_GENERAL_MASK_REG_AEU_NIG_CLOSE_MASK);
-		REG_WR(bp, MISC_REG_AEU_GENERAL_MASK, val);
-	}
-}
-
-/* must be called with rtnl_lock */
-static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
-{
-	int i;
-
-	if (bp->state == BNX2X_STATE_CLOSED) {
-		/* Interface has been removed - nothing to recover */
-		bp->recovery_state = BNX2X_RECOVERY_DONE;
-		bp->is_leader = 0;
-		bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESERVED_08);
-		smp_wmb();
-
-		return -EINVAL;
-	}
-
-#ifdef BCM_CNIC
-	bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD);
-#endif
-	bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
-
-	/* Set "drop all" */
-	bp->rx_mode = BNX2X_RX_MODE_NONE;
-	bnx2x_set_storm_rx_mode(bp);
-
-	/* Disable HW interrupts, NAPI and Tx */
-	bnx2x_netif_stop(bp, 1);
-	netif_carrier_off(bp->dev);
-
-	del_timer_sync(&bp->timer);
-	SHMEM_WR(bp, func_mb[BP_FUNC(bp)].drv_pulse_mb,
-		 (DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq));
-	bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-
-	/* Release IRQs */
-	bnx2x_free_irq(bp, false);
-
-	/* Cleanup the chip if needed */
-	if (unload_mode != UNLOAD_RECOVERY)
-		bnx2x_chip_cleanup(bp, unload_mode);
-
-	bp->port.pmf = 0;
-
-	/* Free SKBs, SGEs, TPA pool and driver internals */
-	bnx2x_free_skbs(bp);
-	for_each_queue(bp, i)
-		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
-	for_each_queue(bp, i)
-		netif_napi_del(&bnx2x_fp(bp, i, napi));
-	bnx2x_free_mem(bp);
-
-	bp->state = BNX2X_STATE_CLOSED;
-
-	/* The last driver must disable a "close the gate" if there is no
-	 * parity attention or "process kill" pending.
-	 */
-	if ((!bnx2x_dec_load_cnt(bp)) && (!bnx2x_chk_parity_attn(bp)) &&
-	    bnx2x_reset_is_done(bp))
-		bnx2x_disable_close_the_gate(bp);
-
-	/* Reset MCP mail box sequence if there is on going recovery */
-	if (unload_mode == UNLOAD_RECOVERY)
-		bp->fw_seq = 0;
-
-	return 0;
-}
-
-/* Close gates #2, #3 and #4: */
-static void bnx2x_set_234_gates(struct bnx2x *bp, bool close)
-{
-	u32 val, addr;
-
-	/* Gates #2 and #4a are closed/opened for "not E1" only */
-	if (!CHIP_IS_E1(bp)) {
-		/* #4 */
-		val = REG_RD(bp, PXP_REG_HST_DISCARD_DOORBELLS);
-		REG_WR(bp, PXP_REG_HST_DISCARD_DOORBELLS,
-		       close ? (val | 0x1) : (val & (~(u32)1)));
-		/* #2 */
-		val = REG_RD(bp, PXP_REG_HST_DISCARD_INTERNAL_WRITES);
-		REG_WR(bp, PXP_REG_HST_DISCARD_INTERNAL_WRITES,
-		       close ? (val | 0x1) : (val & (~(u32)1)));
-	}
-
-	/* #3 */
-	addr = BP_PORT(bp) ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
-	val = REG_RD(bp, addr);
-	REG_WR(bp, addr, (!close) ? (val | 0x1) : (val & (~(u32)1)));
-
-	DP(NETIF_MSG_HW, "%s gates #2, #3 and #4\n",
-		close ? "closing" : "opening");
-	mmiowb();
-}
-
-#define SHARED_MF_CLP_MAGIC  0x80000000 /* `magic' bit */
-
-static void bnx2x_clp_reset_prep(struct bnx2x *bp, u32 *magic_val)
-{
-	/* Do some magic... */
-	u32 val = MF_CFG_RD(bp, shared_mf_config.clp_mb);
-	*magic_val = val & SHARED_MF_CLP_MAGIC;
-	MF_CFG_WR(bp, shared_mf_config.clp_mb, val | SHARED_MF_CLP_MAGIC);
-}
-
-/* Restore the value of the `magic' bit.
- *
- * @param pdev Device handle.
- * @param magic_val Old value of the `magic' bit.
- */
-static void bnx2x_clp_reset_done(struct bnx2x *bp, u32 magic_val)
-{
-	/* Restore the `magic' bit value... */
-	/* u32 val = SHMEM_RD(bp, mf_cfg.shared_mf_config.clp_mb);
-	SHMEM_WR(bp, mf_cfg.shared_mf_config.clp_mb,
-		(val & (~SHARED_MF_CLP_MAGIC)) | magic_val); */
-	u32 val = MF_CFG_RD(bp, shared_mf_config.clp_mb);
-	MF_CFG_WR(bp, shared_mf_config.clp_mb,
-		(val & (~SHARED_MF_CLP_MAGIC)) | magic_val);
-}
-
-/* Prepares for MCP reset: takes care of CLP configurations.
- *
- * @param bp
- * @param magic_val Old value of 'magic' bit.
- */
-static void bnx2x_reset_mcp_prep(struct bnx2x *bp, u32 *magic_val)
-{
-	u32 shmem;
-	u32 validity_offset;
-
-	DP(NETIF_MSG_HW, "Starting\n");
-
-	/* Set `magic' bit in order to save MF config */
-	if (!CHIP_IS_E1(bp))
-		bnx2x_clp_reset_prep(bp, magic_val);
-
-	/* Get shmem offset */
-	shmem = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
-	validity_offset = offsetof(struct shmem_region, validity_map[0]);
-
-	/* Clear validity map flags */
-	if (shmem > 0)
-		REG_WR(bp, shmem + validity_offset, 0);
-}
-
-#define MCP_TIMEOUT      5000   /* 5 seconds (in ms) */
-#define MCP_ONE_TIMEOUT  100    /* 100 ms */
-
-/* Waits for MCP_ONE_TIMEOUT or MCP_ONE_TIMEOUT*10,
- * depending on the HW type.
- *
- * @param bp
- */
-static inline void bnx2x_mcp_wait_one(struct bnx2x *bp)
-{
-	/* special handling for emulation and FPGA,
-	   wait 10 times longer */
-	if (CHIP_REV_IS_SLOW(bp))
-		msleep(MCP_ONE_TIMEOUT*10);
-	else
-		msleep(MCP_ONE_TIMEOUT);
-}
-
-static int bnx2x_reset_mcp_comp(struct bnx2x *bp, u32 magic_val)
-{
-	u32 shmem, cnt, validity_offset, val;
-	int rc = 0;
-
-	msleep(100);
-
-	/* Get shmem offset */
-	shmem = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
-	if (shmem == 0) {
-		BNX2X_ERR("Shmem 0 return failure\n");
-		rc = -ENOTTY;
-		goto exit_lbl;
-	}
-
-	validity_offset = offsetof(struct shmem_region, validity_map[0]);
-
-	/* Wait for MCP to come up */
-	for (cnt = 0; cnt < (MCP_TIMEOUT / MCP_ONE_TIMEOUT); cnt++) {
-		/* TBD: its best to check validity map of last port.
-		 * currently checks on port 0.
-		 */
-		val = REG_RD(bp, shmem + validity_offset);
-		DP(NETIF_MSG_HW, "shmem 0x%x validity map(0x%x)=0x%x\n", shmem,
-		   shmem + validity_offset, val);
-
-		/* check that shared memory is valid. */
-		if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
-		    == (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
-			break;
-
-		bnx2x_mcp_wait_one(bp);
-	}
-
-	DP(NETIF_MSG_HW, "Cnt=%d Shmem validity map 0x%x\n", cnt, val);
-
-	/* Check that shared memory is valid. This indicates that MCP is up. */
-	if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) !=
-	    (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) {
-		BNX2X_ERR("Shmem signature not present. MCP is not up !!\n");
-		rc = -ENOTTY;
-		goto exit_lbl;
-	}
-
-exit_lbl:
-	/* Restore the `magic' bit value */
-	if (!CHIP_IS_E1(bp))
-		bnx2x_clp_reset_done(bp, magic_val);
-
-	return rc;
-}
-
-static void bnx2x_pxp_prep(struct bnx2x *bp)
-{
-	if (!CHIP_IS_E1(bp)) {
-		REG_WR(bp, PXP2_REG_RD_START_INIT, 0);
-		REG_WR(bp, PXP2_REG_RQ_RBC_DONE, 0);
-		REG_WR(bp, PXP2_REG_RQ_CFG_DONE, 0);
-		mmiowb();
-	}
-}
-
-/*
- * Reset the whole chip except for:
- *      - PCIE core
- *      - PCI Glue, PSWHST, PXP/PXP2 RF (all controlled by
- *              one reset bit)
- *      - IGU
- *      - MISC (including AEU)
- *      - GRC
- *      - RBCN, RBCP
- */
-static void bnx2x_process_kill_chip_reset(struct bnx2x *bp)
-{
-	u32 not_reset_mask1, reset_mask1, not_reset_mask2, reset_mask2;
-
-	not_reset_mask1 =
-		MISC_REGISTERS_RESET_REG_1_RST_HC |
-		MISC_REGISTERS_RESET_REG_1_RST_PXPV |
-		MISC_REGISTERS_RESET_REG_1_RST_PXP;
-
-	not_reset_mask2 =
-		MISC_REGISTERS_RESET_REG_2_RST_MDIO |
-		MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE |
-		MISC_REGISTERS_RESET_REG_2_RST_EMAC1_HARD_CORE |
-		MISC_REGISTERS_RESET_REG_2_RST_MISC_CORE |
-		MISC_REGISTERS_RESET_REG_2_RST_RBCN |
-		MISC_REGISTERS_RESET_REG_2_RST_GRC  |
-		MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_REG_HARD_CORE |
-		MISC_REGISTERS_RESET_REG_2_RST_MCP_N_HARD_CORE_RST_B;
-
-	reset_mask1 = 0xffffffff;
-
-	if (CHIP_IS_E1(bp))
-		reset_mask2 = 0xffff;
-	else
-		reset_mask2 = 0x1ffff;
-
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
-	       reset_mask1 & (~not_reset_mask1));
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
-	       reset_mask2 & (~not_reset_mask2));
-
-	barrier();
-	mmiowb();
-
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, reset_mask1);
-	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, reset_mask2);
-	mmiowb();
-}
-
-static int bnx2x_process_kill(struct bnx2x *bp)
-{
-	int cnt = 1000;
-	u32 val = 0;
-	u32 sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1, pgl_exp_rom2;
-
-
-	/* Empty the Tetris buffer, wait for 1s */
-	do {
-		sr_cnt  = REG_RD(bp, PXP2_REG_RD_SR_CNT);
-		blk_cnt = REG_RD(bp, PXP2_REG_RD_BLK_CNT);
-		port_is_idle_0 = REG_RD(bp, PXP2_REG_RD_PORT_IS_IDLE_0);
-		port_is_idle_1 = REG_RD(bp, PXP2_REG_RD_PORT_IS_IDLE_1);
-		pgl_exp_rom2 = REG_RD(bp, PXP2_REG_PGL_EXP_ROM2);
-		if ((sr_cnt == 0x7e) && (blk_cnt == 0xa0) &&
-		    ((port_is_idle_0 & 0x1) == 0x1) &&
-		    ((port_is_idle_1 & 0x1) == 0x1) &&
-		    (pgl_exp_rom2 == 0xffffffff))
-			break;
-		msleep(1);
-	} while (cnt-- > 0);
-
-	if (cnt <= 0) {
-		DP(NETIF_MSG_HW, "Tetris buffer didn't get empty or there"
-			  " are still"
-			  " outstanding read requests after 1s!\n");
-		DP(NETIF_MSG_HW, "sr_cnt=0x%08x, blk_cnt=0x%08x,"
-			  " port_is_idle_0=0x%08x,"
-			  " port_is_idle_1=0x%08x, pgl_exp_rom2=0x%08x\n",
-			  sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1,
-			  pgl_exp_rom2);
-		return -EAGAIN;
-	}
-
-	barrier();
-
-	/* Close gates #2, #3 and #4 */
-	bnx2x_set_234_gates(bp, true);
-
-	/* TBD: Indicate that "process kill" is in progress to MCP */
-
-	/* Clear "unprepared" bit */
-	REG_WR(bp, MISC_REG_UNPREPARED, 0);
-	barrier();
-
-	/* Make sure all is written to the chip before the reset */
-	mmiowb();
-
-	/* Wait for 1ms to empty GLUE and PCI-E core queues,
-	 * PSWHST, GRC and PSWRD Tetris buffer.
-	 */
-	msleep(1);
-
-	/* Prepare to chip reset: */
-	/* MCP */
-	bnx2x_reset_mcp_prep(bp, &val);
-
-	/* PXP */
-	bnx2x_pxp_prep(bp);
-	barrier();
-
-	/* reset the chip */
-	bnx2x_process_kill_chip_reset(bp);
-	barrier();
-
-	/* Recover after reset: */
-	/* MCP */
-	if (bnx2x_reset_mcp_comp(bp, val))
-		return -EAGAIN;
-
-	/* PXP */
-	bnx2x_pxp_prep(bp);
-
-	/* Open the gates #2, #3 and #4 */
-	bnx2x_set_234_gates(bp, false);
-
-	/* TBD: IGU/AEU preparation bring back the AEU/IGU to a
-	 * reset state, re-enable attentions. */
-
-	return 0;
-}
-
-static int bnx2x_leader_reset(struct bnx2x *bp)
-{
-	int rc = 0;
-	/* Try to recover after the failure */
-	if (bnx2x_process_kill(bp)) {
-		printk(KERN_ERR "%s: Something bad had happen! Aii!\n",
-		       bp->dev->name);
-		rc = -EAGAIN;
-		goto exit_leader_reset;
-	}
-
-	/* Clear "reset is in progress" bit and update the driver state */
-	bnx2x_set_reset_done(bp);
-	bp->recovery_state = BNX2X_RECOVERY_DONE;
-
-exit_leader_reset:
-	bp->is_leader = 0;
-	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESERVED_08);
-	smp_wmb();
-	return rc;
-}
-
-static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state);
-
-/* Assumption: runs under rtnl lock. This together with the fact
- * that it's called only from bnx2x_reset_task() ensure that it
- * will never be called when netif_running(bp->dev) is false.
- */
-static void bnx2x_parity_recover(struct bnx2x *bp)
-{
-	DP(NETIF_MSG_HW, "Handling parity\n");
-	while (1) {
-		switch (bp->recovery_state) {
-		case BNX2X_RECOVERY_INIT:
-			DP(NETIF_MSG_HW, "State is BNX2X_RECOVERY_INIT\n");
-			/* Try to get a LEADER_LOCK HW lock */
-			if (bnx2x_trylock_hw_lock(bp,
-				HW_LOCK_RESOURCE_RESERVED_08))
-				bp->is_leader = 1;
-
-			/* Stop the driver */
-			/* If interface has been removed - break */
-			if (bnx2x_nic_unload(bp, UNLOAD_RECOVERY))
-				return;
-
-			bp->recovery_state = BNX2X_RECOVERY_WAIT;
-			/* Ensure "is_leader" and "recovery_state"
-			 *  update values are seen on other CPUs
-			 */
-			smp_wmb();
-			break;
-
-		case BNX2X_RECOVERY_WAIT:
-			DP(NETIF_MSG_HW, "State is BNX2X_RECOVERY_WAIT\n");
-			if (bp->is_leader) {
-				u32 load_counter = bnx2x_get_load_cnt(bp);
-				if (load_counter) {
-					/* Wait until all other functions get
-					 * down.
-					 */
-					schedule_delayed_work(&bp->reset_task,
-								HZ/10);
-					return;
-				} else {
-					/* If all other functions got down -
-					 * try to bring the chip back to
-					 * normal. In any case it's an exit
-					 * point for a leader.
-					 */
-					if (bnx2x_leader_reset(bp) ||
-					bnx2x_nic_load(bp, LOAD_NORMAL)) {
-						printk(KERN_ERR"%s: Recovery "
-						"has failed. Power cycle is "
-						"needed.\n", bp->dev->name);
-						/* Disconnect this device */
-						netif_device_detach(bp->dev);
-						/* Block ifup for all function
-						 * of this ASIC until
-						 * "process kill" or power
-						 * cycle.
-						 */
-						bnx2x_set_reset_in_progress(bp);
-						/* Shut down the power */
-						bnx2x_set_power_state(bp,
-								PCI_D3hot);
-						return;
-					}
-
-					return;
-				}
-			} else { /* non-leader */
-				if (!bnx2x_reset_is_done(bp)) {
-					/* Try to get a LEADER_LOCK HW lock as
-					 * long as a former leader may have
-					 * been unloaded by the user or
-					 * released a leadership by another
-					 * reason.
-					 */
-					if (bnx2x_trylock_hw_lock(bp,
-					    HW_LOCK_RESOURCE_RESERVED_08)) {
-						/* I'm a leader now! Restart a
-						 * switch case.
-						 */
-						bp->is_leader = 1;
-						break;
-					}
-
-					schedule_delayed_work(&bp->reset_task,
-								HZ/10);
-					return;
-
-				} else { /* A leader has completed
-					  * the "process kill". It's an exit
-					  * point for a non-leader.
-					  */
-					bnx2x_nic_load(bp, LOAD_NORMAL);
-					bp->recovery_state =
-						BNX2X_RECOVERY_DONE;
-					smp_wmb();
-					return;
-				}
-			}
-		default:
-			return;
-		}
-	}
-}
-
-/* bnx2x_nic_unload() flushes the bnx2x_wq, thus reset task is
- * scheduled on a general queue in order to prevent a dead lock.
- */
-static void bnx2x_reset_task(struct work_struct *work)
-{
-	struct bnx2x *bp = container_of(work, struct bnx2x, reset_task.work);
-
-#ifdef BNX2X_STOP_ON_ERROR
-	BNX2X_ERR("reset task called but STOP_ON_ERROR defined"
-		  " so reset not done to allow debug dump,\n"
-	 KERN_ERR " you will need to reboot when done\n");
-	return;
-#endif
-
-	rtnl_lock();
-
-	if (!netif_running(bp->dev))
-		goto reset_task_exit;
-
-	if (unlikely(bp->recovery_state != BNX2X_RECOVERY_DONE))
-		bnx2x_parity_recover(bp);
-	else {
-		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
-		bnx2x_nic_load(bp, LOAD_NORMAL);
-	}
-
-reset_task_exit:
-	rtnl_unlock();
-}
-
-/* end of nic load/unload */
-
-/* ethtool_ops */
-
-/*
- * Init service functions
- */
-
-static inline u32 bnx2x_get_pretend_reg(struct bnx2x *bp, int func)
-{
-	switch (func) {
-	case 0: return PXP2_REG_PGL_PRETEND_FUNC_F0;
-	case 1:	return PXP2_REG_PGL_PRETEND_FUNC_F1;
-	case 2:	return PXP2_REG_PGL_PRETEND_FUNC_F2;
-	case 3:	return PXP2_REG_PGL_PRETEND_FUNC_F3;
-	case 4:	return PXP2_REG_PGL_PRETEND_FUNC_F4;
-	case 5:	return PXP2_REG_PGL_PRETEND_FUNC_F5;
-	case 6:	return PXP2_REG_PGL_PRETEND_FUNC_F6;
-	case 7:	return PXP2_REG_PGL_PRETEND_FUNC_F7;
-	default:
-		BNX2X_ERR("Unsupported function index: %d\n", func);
-		return (u32)(-1);
-	}
-}
-
-static void bnx2x_undi_int_disable_e1h(struct bnx2x *bp, int orig_func)
-{
-	u32 reg = bnx2x_get_pretend_reg(bp, orig_func), new_val;
-
-	/* Flush all outstanding writes */
-	mmiowb();
-
-	/* Pretend to be function 0 */
-	REG_WR(bp, reg, 0);
-	/* Flush the GRC transaction (in the chip) */
-	new_val = REG_RD(bp, reg);
-	if (new_val != 0) {
-		BNX2X_ERR("Hmmm... Pretend register wasn't updated: (0,%d)!\n",
-			  new_val);
-		BUG();
-	}
-
-	/* From now we are in the "like-E1" mode */
-	bnx2x_int_disable(bp);
-
-	/* Flush all outstanding writes */
-	mmiowb();
-
-	/* Restore the original funtion settings */
-	REG_WR(bp, reg, orig_func);
-	new_val = REG_RD(bp, reg);
-	if (new_val != orig_func) {
-		BNX2X_ERR("Hmmm... Pretend register wasn't updated: (%d,%d)!\n",
-			  orig_func, new_val);
-		BUG();
-	}
-}
-
-static inline void bnx2x_undi_int_disable(struct bnx2x *bp, int func)
-{
-	if (CHIP_IS_E1H(bp))
-		bnx2x_undi_int_disable_e1h(bp, func);
-	else
-		bnx2x_int_disable(bp);
-}
-
-static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
-{
-	u32 val;
-
-	/* Check if there is any driver already loaded */
-	val = REG_RD(bp, MISC_REG_UNPREPARED);
-	if (val == 0x1) {
-		/* Check if it is the UNDI driver
-		 * UNDI driver initializes CID offset for normal bell to 0x7
-		 */
-		bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
-		val = REG_RD(bp, DORQ_REG_NORM_CID_OFST);
-		if (val == 0x7) {
-			u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
-			/* save our func */
-			int func = BP_FUNC(bp);
-			u32 swap_en;
-			u32 swap_val;
-
-			/* clear the UNDI indication */
-			REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0);
-
-			BNX2X_DEV_INFO("UNDI is active! reset device\n");
-
-			/* try unload UNDI on port 0 */
-			bp->func = 0;
-			bp->fw_seq =
-			       (SHMEM_RD(bp, func_mb[bp->func].drv_mb_header) &
-				DRV_MSG_SEQ_NUMBER_MASK);
-			reset_code = bnx2x_fw_command(bp, reset_code);
-
-			/* if UNDI is loaded on the other port */
-			if (reset_code != FW_MSG_CODE_DRV_UNLOAD_COMMON) {
-
-				/* send "DONE" for previous unload */
-				bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
-
-				/* unload UNDI on port 1 */
-				bp->func = 1;
-				bp->fw_seq =
-			       (SHMEM_RD(bp, func_mb[bp->func].drv_mb_header) &
-					DRV_MSG_SEQ_NUMBER_MASK);
-				reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
-
-				bnx2x_fw_command(bp, reset_code);
-			}
-
-			/* now it's safe to release the lock */
-			bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
-
-			bnx2x_undi_int_disable(bp, func);
-
-			/* close input traffic and wait for it */
-			/* Do not rcv packets to BRB */
-			REG_WR(bp,
-			      (BP_PORT(bp) ? NIG_REG_LLH1_BRB1_DRV_MASK :
-					     NIG_REG_LLH0_BRB1_DRV_MASK), 0x0);
-			/* Do not direct rcv packets that are not for MCP to
-			 * the BRB */
-			REG_WR(bp,
-			       (BP_PORT(bp) ? NIG_REG_LLH1_BRB1_NOT_MCP :
-					      NIG_REG_LLH0_BRB1_NOT_MCP), 0x0);
-			/* clear AEU */
-			REG_WR(bp,
-			     (BP_PORT(bp) ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
-					    MISC_REG_AEU_MASK_ATTN_FUNC_0), 0);
-			msleep(10);
-
-			/* save NIG port swap info */
-			swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
-			swap_en = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
-			/* reset device */
-			REG_WR(bp,
-			       GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
-			       0xd3ffffff);
-			REG_WR(bp,
-			       GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
-			       0x1403);
-			/* take the NIG out of reset and restore swap values */
-			REG_WR(bp,
-			       GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET,
-			       MISC_REGISTERS_RESET_REG_1_RST_NIG);
-			REG_WR(bp, NIG_REG_PORT_SWAP, swap_val);
-			REG_WR(bp, NIG_REG_STRAP_OVERRIDE, swap_en);
-
-			/* send unload done to the MCP */
-			bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
-
-			/* restore our func and fw_seq */
-			bp->func = func;
-			bp->fw_seq =
-			       (SHMEM_RD(bp, func_mb[bp->func].drv_mb_header) &
-				DRV_MSG_SEQ_NUMBER_MASK);
-
-		} else
-			bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
-	}
-}
-
-static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
-{
-	u32 val, val2, val3, val4, id;
-	u16 pmc;
-
-	/* Get the chip revision id and number. */
-	/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
-	val = REG_RD(bp, MISC_REG_CHIP_NUM);
-	id = ((val & 0xffff) << 16);
-	val = REG_RD(bp, MISC_REG_CHIP_REV);
-	id |= ((val & 0xf) << 12);
-	val = REG_RD(bp, MISC_REG_CHIP_METAL);
-	id |= ((val & 0xff) << 4);
-	val = REG_RD(bp, MISC_REG_BOND_ID);
-	id |= (val & 0xf);
-	bp->common.chip_id = id;
-	bp->link_params.chip_id = bp->common.chip_id;
-	BNX2X_DEV_INFO("chip ID is 0x%x\n", id);
-
-	val = (REG_RD(bp, 0x2874) & 0x55);
-	if ((bp->common.chip_id & 0x1) ||
-	    (CHIP_IS_E1(bp) && val) || (CHIP_IS_E1H(bp) && (val == 0x55))) {
-		bp->flags |= ONE_PORT_FLAG;
-		BNX2X_DEV_INFO("single port device\n");
-	}
-
-	val = REG_RD(bp, MCP_REG_MCPR_NVM_CFG4);
-	bp->common.flash_size = (NVRAM_1MB_SIZE <<
-				 (val & MCPR_NVM_CFG4_FLASH_SIZE));
-	BNX2X_DEV_INFO("flash_size 0x%x (%d)\n",
-		       bp->common.flash_size, bp->common.flash_size);
-
-	bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
-	bp->common.shmem2_base = REG_RD(bp, MISC_REG_GENERIC_CR_0);
-	bp->link_params.shmem_base = bp->common.shmem_base;
-	BNX2X_DEV_INFO("shmem offset 0x%x  shmem2 offset 0x%x\n",
-		       bp->common.shmem_base, bp->common.shmem2_base);
-
-	if (!bp->common.shmem_base ||
-	    (bp->common.shmem_base < 0xA0000) ||
-	    (bp->common.shmem_base >= 0xC0000)) {
-		BNX2X_DEV_INFO("MCP not active\n");
-		bp->flags |= NO_MCP_FLAG;
-		return;
-	}
-
-	val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]);
-	if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
-		!= (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
-		BNX2X_ERROR("BAD MCP validity signature\n");
-
-	bp->common.hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config);
-	BNX2X_DEV_INFO("hw_config 0x%08x\n", bp->common.hw_config);
-
-	bp->link_params.hw_led_mode = ((bp->common.hw_config &
-					SHARED_HW_CFG_LED_MODE_MASK) >>
-				       SHARED_HW_CFG_LED_MODE_SHIFT);
-
-	bp->link_params.feature_config_flags = 0;
-	val = SHMEM_RD(bp, dev_info.shared_feature_config.config);
-	if (val & SHARED_FEAT_CFG_OVERRIDE_PREEMPHASIS_CFG_ENABLED)
-		bp->link_params.feature_config_flags |=
-				FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED;
-	else
-		bp->link_params.feature_config_flags &=
-				~FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED;
-
-	val = SHMEM_RD(bp, dev_info.bc_rev) >> 8;
-	bp->common.bc_ver = val;
-	BNX2X_DEV_INFO("bc_ver %X\n", val);
-	if (val < BNX2X_BC_VER) {
-		/* for now only warn
-		 * later we might need to enforce this */
-		BNX2X_ERROR("This driver needs bc_ver %X but found %X, "
-			    "please upgrade BC\n", BNX2X_BC_VER, val);
-	}
-	bp->link_params.feature_config_flags |=
-		(val >= REQ_BC_VER_4_VRFY_OPT_MDL) ?
-		FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY : 0;
-
-	if (BP_E1HVN(bp) == 0) {
-		pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc);
-		bp->flags |= (pmc & PCI_PM_CAP_PME_D3cold) ? 0 : NO_WOL_FLAG;
-	} else {
-		/* no WOL capability for E1HVN != 0 */
-		bp->flags |= NO_WOL_FLAG;
-	}
-	BNX2X_DEV_INFO("%sWoL capable\n",
-		       (bp->flags & NO_WOL_FLAG) ? "not " : "");
-
-	val = SHMEM_RD(bp, dev_info.shared_hw_config.part_num);
-	val2 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[4]);
-	val3 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[8]);
-	val4 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[12]);
-
-	dev_info(&bp->pdev->dev, "part number %X-%X-%X-%X\n",
-		 val, val2, val3, val4);
-}
-
-static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
-						    u32 switch_cfg)
-{
-	int port = BP_PORT(bp);
-	u32 ext_phy_type;
-
-	switch (switch_cfg) {
-	case SWITCH_CFG_1G:
-		BNX2X_DEV_INFO("switch_cfg 0x%x (1G)\n", switch_cfg);
-
-		ext_phy_type =
-			SERDES_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
-		switch (ext_phy_type) {
-		case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
-			BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n",
-				       ext_phy_type);
-
-			bp->port.supported |= (SUPPORTED_10baseT_Half |
-					       SUPPORTED_10baseT_Full |
-					       SUPPORTED_100baseT_Half |
-					       SUPPORTED_100baseT_Full |
-					       SUPPORTED_1000baseT_Full |
-					       SUPPORTED_2500baseX_Full |
-					       SUPPORTED_TP |
-					       SUPPORTED_FIBRE |
-					       SUPPORTED_Autoneg |
-					       SUPPORTED_Pause |
-					       SUPPORTED_Asym_Pause);
-			break;
-
-		case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
-			BNX2X_DEV_INFO("ext_phy_type 0x%x (5482)\n",
-				       ext_phy_type);
-
-			bp->port.supported |= (SUPPORTED_10baseT_Half |
-					       SUPPORTED_10baseT_Full |
-					       SUPPORTED_100baseT_Half |
-					       SUPPORTED_100baseT_Full |
-					       SUPPORTED_1000baseT_Full |
-					       SUPPORTED_TP |
-					       SUPPORTED_FIBRE |
-					       SUPPORTED_Autoneg |
-					       SUPPORTED_Pause |
-					       SUPPORTED_Asym_Pause);
-			break;
-
-		default:
-			BNX2X_ERR("NVRAM config error. "
-				  "BAD SerDes ext_phy_config 0x%x\n",
-				  bp->link_params.ext_phy_config);
-			return;
-		}
-
-		bp->port.phy_addr = REG_RD(bp, NIG_REG_SERDES0_CTRL_PHY_ADDR +
-					   port*0x10);
-		BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr);
-		break;
-
-	case SWITCH_CFG_10G:
-		BNX2X_DEV_INFO("switch_cfg 0x%x (10G)\n", switch_cfg);
-
-		ext_phy_type =
-			XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
-		switch (ext_phy_type) {
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
-			BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n",
-				       ext_phy_type);
-
-			bp->port.supported |= (SUPPORTED_10baseT_Half |
-					       SUPPORTED_10baseT_Full |
-					       SUPPORTED_100baseT_Half |
-					       SUPPORTED_100baseT_Full |
-					       SUPPORTED_1000baseT_Full |
-					       SUPPORTED_2500baseX_Full |
-					       SUPPORTED_10000baseT_Full |
-					       SUPPORTED_TP |
-					       SUPPORTED_FIBRE |
-					       SUPPORTED_Autoneg |
-					       SUPPORTED_Pause |
-					       SUPPORTED_Asym_Pause);
-			break;
-
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
-			BNX2X_DEV_INFO("ext_phy_type 0x%x (8072)\n",
-				       ext_phy_type);
-
-			bp->port.supported |= (SUPPORTED_10000baseT_Full |
-					       SUPPORTED_1000baseT_Full |
-					       SUPPORTED_FIBRE |
-					       SUPPORTED_Autoneg |
-					       SUPPORTED_Pause |
-					       SUPPORTED_Asym_Pause);
-			break;
-
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
-			BNX2X_DEV_INFO("ext_phy_type 0x%x (8073)\n",
-				       ext_phy_type);
-
-			bp->port.supported |= (SUPPORTED_10000baseT_Full |
-					       SUPPORTED_2500baseX_Full |
-					       SUPPORTED_1000baseT_Full |
-					       SUPPORTED_FIBRE |
-					       SUPPORTED_Autoneg |
-					       SUPPORTED_Pause |
-					       SUPPORTED_Asym_Pause);
-			break;
-
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
-			BNX2X_DEV_INFO("ext_phy_type 0x%x (8705)\n",
-				       ext_phy_type);
-
-			bp->port.supported |= (SUPPORTED_10000baseT_Full |
-					       SUPPORTED_FIBRE |
-					       SUPPORTED_Pause |
-					       SUPPORTED_Asym_Pause);
-			break;
-
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
-			BNX2X_DEV_INFO("ext_phy_type 0x%x (8706)\n",
-				       ext_phy_type);
-
-			bp->port.supported |= (SUPPORTED_10000baseT_Full |
-					       SUPPORTED_1000baseT_Full |
-					       SUPPORTED_FIBRE |
-					       SUPPORTED_Pause |
-					       SUPPORTED_Asym_Pause);
-			break;
-
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-			BNX2X_DEV_INFO("ext_phy_type 0x%x (8726)\n",
-				       ext_phy_type);
-
-			bp->port.supported |= (SUPPORTED_10000baseT_Full |
-					       SUPPORTED_1000baseT_Full |
-					       SUPPORTED_Autoneg |
-					       SUPPORTED_FIBRE |
-					       SUPPORTED_Pause |
-					       SUPPORTED_Asym_Pause);
-			break;
-
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-			BNX2X_DEV_INFO("ext_phy_type 0x%x (8727)\n",
-				       ext_phy_type);
-
-			bp->port.supported |= (SUPPORTED_10000baseT_Full |
-					       SUPPORTED_1000baseT_Full |
-					       SUPPORTED_Autoneg |
-					       SUPPORTED_FIBRE |
-					       SUPPORTED_Pause |
-					       SUPPORTED_Asym_Pause);
-			break;
-
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-			BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n",
-				       ext_phy_type);
-
-			bp->port.supported |= (SUPPORTED_10000baseT_Full |
-					       SUPPORTED_TP |
-					       SUPPORTED_Autoneg |
-					       SUPPORTED_Pause |
-					       SUPPORTED_Asym_Pause);
-			break;
-
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
-			BNX2X_DEV_INFO("ext_phy_type 0x%x (BCM8481)\n",
-				       ext_phy_type);
-
-			bp->port.supported |= (SUPPORTED_10baseT_Half |
-					       SUPPORTED_10baseT_Full |
-					       SUPPORTED_100baseT_Half |
-					       SUPPORTED_100baseT_Full |
-					       SUPPORTED_1000baseT_Full |
-					       SUPPORTED_10000baseT_Full |
-					       SUPPORTED_TP |
-					       SUPPORTED_Autoneg |
-					       SUPPORTED_Pause |
-					       SUPPORTED_Asym_Pause);
-			break;
-
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
-			BNX2X_ERR("XGXS PHY Failure detected 0x%x\n",
-				  bp->link_params.ext_phy_config);
-			break;
-
-		default:
-			BNX2X_ERR("NVRAM config error. "
-				  "BAD XGXS ext_phy_config 0x%x\n",
-				  bp->link_params.ext_phy_config);
-			return;
-		}
-
-		bp->port.phy_addr = REG_RD(bp, NIG_REG_XGXS0_CTRL_PHY_ADDR +
-					   port*0x18);
-		BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr);
-
-		break;
-
-	default:
-		BNX2X_ERR("BAD switch_cfg link_config 0x%x\n",
-			  bp->port.link_config);
-		return;
-	}
-	bp->link_params.phy_addr = bp->port.phy_addr;
-
-	/* mask what we support according to speed_cap_mask */
-	if (!(bp->link_params.speed_cap_mask &
-				PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF))
-		bp->port.supported &= ~SUPPORTED_10baseT_Half;
-
-	if (!(bp->link_params.speed_cap_mask &
-				PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL))
-		bp->port.supported &= ~SUPPORTED_10baseT_Full;
-
-	if (!(bp->link_params.speed_cap_mask &
-				PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF))
-		bp->port.supported &= ~SUPPORTED_100baseT_Half;
-
-	if (!(bp->link_params.speed_cap_mask &
-				PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL))
-		bp->port.supported &= ~SUPPORTED_100baseT_Full;
-
-	if (!(bp->link_params.speed_cap_mask &
-					PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))
-		bp->port.supported &= ~(SUPPORTED_1000baseT_Half |
-					SUPPORTED_1000baseT_Full);
-
-	if (!(bp->link_params.speed_cap_mask &
-					PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
-		bp->port.supported &= ~SUPPORTED_2500baseX_Full;
-
-	if (!(bp->link_params.speed_cap_mask &
-					PORT_HW_CFG_SPEED_CAPABILITY_D0_10G))
-		bp->port.supported &= ~SUPPORTED_10000baseT_Full;
-
-	BNX2X_DEV_INFO("supported 0x%x\n", bp->port.supported);
-}
-
-static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
-{
-	bp->link_params.req_duplex = DUPLEX_FULL;
-
-	switch (bp->port.link_config & PORT_FEATURE_LINK_SPEED_MASK) {
-	case PORT_FEATURE_LINK_SPEED_AUTO:
-		if (bp->port.supported & SUPPORTED_Autoneg) {
-			bp->link_params.req_line_speed = SPEED_AUTO_NEG;
-			bp->port.advertising = bp->port.supported;
-		} else {
-			u32 ext_phy_type =
-			    XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
-
-			if ((ext_phy_type ==
-			     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
-			    (ext_phy_type ==
-			     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706)) {
-				/* force 10G, no AN */
-				bp->link_params.req_line_speed = SPEED_10000;
-				bp->port.advertising =
-						(ADVERTISED_10000baseT_Full |
-						 ADVERTISED_FIBRE);
-				break;
-			}
-			BNX2X_ERR("NVRAM config error. "
-				  "Invalid link_config 0x%x"
-				  "  Autoneg not supported\n",
-				  bp->port.link_config);
-			return;
-		}
-		break;
-
-	case PORT_FEATURE_LINK_SPEED_10M_FULL:
-		if (bp->port.supported & SUPPORTED_10baseT_Full) {
-			bp->link_params.req_line_speed = SPEED_10;
-			bp->port.advertising = (ADVERTISED_10baseT_Full |
-						ADVERTISED_TP);
-		} else {
-			BNX2X_ERROR("NVRAM config error. "
-				    "Invalid link_config 0x%x"
-				    "  speed_cap_mask 0x%x\n",
-				    bp->port.link_config,
-				    bp->link_params.speed_cap_mask);
-			return;
-		}
-		break;
-
-	case PORT_FEATURE_LINK_SPEED_10M_HALF:
-		if (bp->port.supported & SUPPORTED_10baseT_Half) {
-			bp->link_params.req_line_speed = SPEED_10;
-			bp->link_params.req_duplex = DUPLEX_HALF;
-			bp->port.advertising = (ADVERTISED_10baseT_Half |
-						ADVERTISED_TP);
-		} else {
-			BNX2X_ERROR("NVRAM config error. "
-				    "Invalid link_config 0x%x"
-				    "  speed_cap_mask 0x%x\n",
-				    bp->port.link_config,
-				    bp->link_params.speed_cap_mask);
-			return;
-		}
-		break;
-
-	case PORT_FEATURE_LINK_SPEED_100M_FULL:
-		if (bp->port.supported & SUPPORTED_100baseT_Full) {
-			bp->link_params.req_line_speed = SPEED_100;
-			bp->port.advertising = (ADVERTISED_100baseT_Full |
-						ADVERTISED_TP);
-		} else {
-			BNX2X_ERROR("NVRAM config error. "
-				    "Invalid link_config 0x%x"
-				    "  speed_cap_mask 0x%x\n",
-				    bp->port.link_config,
-				    bp->link_params.speed_cap_mask);
-			return;
-		}
-		break;
-
-	case PORT_FEATURE_LINK_SPEED_100M_HALF:
-		if (bp->port.supported & SUPPORTED_100baseT_Half) {
-			bp->link_params.req_line_speed = SPEED_100;
-			bp->link_params.req_duplex = DUPLEX_HALF;
-			bp->port.advertising = (ADVERTISED_100baseT_Half |
-						ADVERTISED_TP);
-		} else {
-			BNX2X_ERROR("NVRAM config error. "
-				    "Invalid link_config 0x%x"
-				    "  speed_cap_mask 0x%x\n",
-				    bp->port.link_config,
-				    bp->link_params.speed_cap_mask);
-			return;
-		}
-		break;
-
-	case PORT_FEATURE_LINK_SPEED_1G:
-		if (bp->port.supported & SUPPORTED_1000baseT_Full) {
-			bp->link_params.req_line_speed = SPEED_1000;
-			bp->port.advertising = (ADVERTISED_1000baseT_Full |
-						ADVERTISED_TP);
-		} else {
-			BNX2X_ERROR("NVRAM config error. "
-				    "Invalid link_config 0x%x"
-				    "  speed_cap_mask 0x%x\n",
-				    bp->port.link_config,
-				    bp->link_params.speed_cap_mask);
-			return;
-		}
-		break;
-
-	case PORT_FEATURE_LINK_SPEED_2_5G:
-		if (bp->port.supported & SUPPORTED_2500baseX_Full) {
-			bp->link_params.req_line_speed = SPEED_2500;
-			bp->port.advertising = (ADVERTISED_2500baseX_Full |
-						ADVERTISED_TP);
-		} else {
-			BNX2X_ERROR("NVRAM config error. "
-				    "Invalid link_config 0x%x"
-				    "  speed_cap_mask 0x%x\n",
-				    bp->port.link_config,
-				    bp->link_params.speed_cap_mask);
-			return;
-		}
-		break;
-
-	case PORT_FEATURE_LINK_SPEED_10G_CX4:
-	case PORT_FEATURE_LINK_SPEED_10G_KX4:
-	case PORT_FEATURE_LINK_SPEED_10G_KR:
-		if (bp->port.supported & SUPPORTED_10000baseT_Full) {
-			bp->link_params.req_line_speed = SPEED_10000;
-			bp->port.advertising = (ADVERTISED_10000baseT_Full |
-						ADVERTISED_FIBRE);
-		} else {
-			BNX2X_ERROR("NVRAM config error. "
-				    "Invalid link_config 0x%x"
-				    "  speed_cap_mask 0x%x\n",
-				    bp->port.link_config,
-				    bp->link_params.speed_cap_mask);
-			return;
-		}
-		break;
-
-	default:
-		BNX2X_ERROR("NVRAM config error. "
-			    "BAD link speed link_config 0x%x\n",
-			    bp->port.link_config);
-		bp->link_params.req_line_speed = SPEED_AUTO_NEG;
-		bp->port.advertising = bp->port.supported;
-		break;
-	}
-
-	bp->link_params.req_flow_ctrl = (bp->port.link_config &
-					 PORT_FEATURE_FLOW_CONTROL_MASK);
-	if ((bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
-	    !(bp->port.supported & SUPPORTED_Autoneg))
-		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",
-		       bp->link_params.req_line_speed,
-		       bp->link_params.req_duplex,
-		       bp->link_params.req_flow_ctrl, bp->port.advertising);
-}
-
-static void __devinit bnx2x_set_mac_buf(u8 *mac_buf, u32 mac_lo, u16 mac_hi)
-{
-	mac_hi = cpu_to_be16(mac_hi);
-	mac_lo = cpu_to_be32(mac_lo);
-	memcpy(mac_buf, &mac_hi, sizeof(mac_hi));
-	memcpy(mac_buf + sizeof(mac_hi), &mac_lo, sizeof(mac_lo));
-}
-
-static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	u32 val, val2;
-	u32 config;
-	u16 i;
-	u32 ext_phy_type;
-
-	bp->link_params.bp = bp;
-	bp->link_params.port = port;
-
-	bp->link_params.lane_config =
-		SHMEM_RD(bp, dev_info.port_hw_config[port].lane_config);
-	bp->link_params.ext_phy_config =
-		SHMEM_RD(bp,
-			 dev_info.port_hw_config[port].external_phy_config);
-	/* BCM8727_NOC => BCM8727 no over current */
-	if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
-	    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC) {
-		bp->link_params.ext_phy_config &=
-			~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
-		bp->link_params.ext_phy_config |=
-			PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727;
-		bp->link_params.feature_config_flags |=
-			FEATURE_CONFIG_BCM8727_NOC;
-	}
-
-	bp->link_params.speed_cap_mask =
-		SHMEM_RD(bp,
-			 dev_info.port_hw_config[port].speed_capability_mask);
-
-	bp->port.link_config =
-		SHMEM_RD(bp, dev_info.port_feature_config[port].link_config);
-
-	/* Get the 4 lanes xgxs config rx and tx */
-	for (i = 0; i < 2; i++) {
-		val = SHMEM_RD(bp,
-			   dev_info.port_hw_config[port].xgxs_config_rx[i<<1]);
-		bp->link_params.xgxs_config_rx[i << 1] = ((val>>16) & 0xffff);
-		bp->link_params.xgxs_config_rx[(i << 1) + 1] = (val & 0xffff);
-
-		val = SHMEM_RD(bp,
-			   dev_info.port_hw_config[port].xgxs_config_tx[i<<1]);
-		bp->link_params.xgxs_config_tx[i << 1] = ((val>>16) & 0xffff);
-		bp->link_params.xgxs_config_tx[(i << 1) + 1] = (val & 0xffff);
-	}
-
-	/* If the device is capable of WoL, set the default state according
-	 * to the HW
-	 */
-	config = SHMEM_RD(bp, dev_info.port_feature_config[port].config);
-	bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
-		   (config & PORT_FEATURE_WOL_ENABLED));
-
-	BNX2X_DEV_INFO("lane_config 0x%08x  ext_phy_config 0x%08x"
-		       "  speed_cap_mask 0x%08x  link_config 0x%08x\n",
-		       bp->link_params.lane_config,
-		       bp->link_params.ext_phy_config,
-		       bp->link_params.speed_cap_mask, bp->port.link_config);
-
-	bp->link_params.switch_cfg |= (bp->port.link_config &
-				       PORT_FEATURE_CONNECTED_SWITCH_MASK);
-	bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg);
-
-	bnx2x_link_settings_requested(bp);
-
-	/*
-	 * If connected directly, work with the internal PHY, otherwise, work
-	 * with the external PHY
-	 */
-	ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
-	if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
-		bp->mdio.prtad = bp->link_params.phy_addr;
-
-	else if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
-		 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN))
-		bp->mdio.prtad =
-			XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config);
-
-	val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
-	val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
-	bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2);
-	memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN);
-	memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
-
-#ifdef BCM_CNIC
-	val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_upper);
-	val = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_lower);
-	bnx2x_set_mac_buf(bp->iscsi_mac, val, val2);
-#endif
-}
-
-static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
-{
-	int func = BP_FUNC(bp);
-	u32 val, val2;
-	int rc = 0;
-
-	bnx2x_get_common_hwinfo(bp);
-
-	bp->e1hov = 0;
-	bp->e1hmf = 0;
-	if (CHIP_IS_E1H(bp) && !BP_NOMCP(bp)) {
-		bp->mf_config =
-			SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
-
-		val = (SHMEM_RD(bp, mf_cfg.func_mf_config[FUNC_0].e1hov_tag) &
-		       FUNC_MF_CFG_E1HOV_TAG_MASK);
-		if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT)
-			bp->e1hmf = 1;
-		BNX2X_DEV_INFO("%s function mode\n",
-			       IS_E1HMF(bp) ? "multi" : "single");
-
-		if (IS_E1HMF(bp)) {
-			val = (SHMEM_RD(bp, mf_cfg.func_mf_config[func].
-								e1hov_tag) &
-			       FUNC_MF_CFG_E1HOV_TAG_MASK);
-			if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) {
-				bp->e1hov = val;
-				BNX2X_DEV_INFO("E1HOV for func %d is %d "
-					       "(0x%04x)\n",
-					       func, bp->e1hov, bp->e1hov);
-			} else {
-				BNX2X_ERROR("No valid E1HOV for func %d,"
-					    "  aborting\n", func);
-				rc = -EPERM;
-			}
-		} else {
-			if (BP_E1HVN(bp)) {
-				BNX2X_ERROR("VN %d in single function mode,"
-					    "  aborting\n", BP_E1HVN(bp));
-				rc = -EPERM;
-			}
-		}
-	}
-
-	if (!BP_NOMCP(bp)) {
-		bnx2x_get_port_hwinfo(bp);
-
-		bp->fw_seq = (SHMEM_RD(bp, func_mb[func].drv_mb_header) &
-			      DRV_MSG_SEQ_NUMBER_MASK);
-		BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
-	}
-
-	if (IS_E1HMF(bp)) {
-		val2 = SHMEM_RD(bp, mf_cfg.func_mf_config[func].mac_upper);
-		val = SHMEM_RD(bp,  mf_cfg.func_mf_config[func].mac_lower);
-		if ((val2 != FUNC_MF_CFG_UPPERMAC_DEFAULT) &&
-		    (val != FUNC_MF_CFG_LOWERMAC_DEFAULT)) {
-			bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff);
-			bp->dev->dev_addr[1] = (u8)(val2 & 0xff);
-			bp->dev->dev_addr[2] = (u8)(val >> 24 & 0xff);
-			bp->dev->dev_addr[3] = (u8)(val >> 16 & 0xff);
-			bp->dev->dev_addr[4] = (u8)(val >> 8  & 0xff);
-			bp->dev->dev_addr[5] = (u8)(val & 0xff);
-			memcpy(bp->link_params.mac_addr, bp->dev->dev_addr,
-			       ETH_ALEN);
-			memcpy(bp->dev->perm_addr, bp->dev->dev_addr,
-			       ETH_ALEN);
-		}
-
-		return rc;
-	}
-
-	if (BP_NOMCP(bp)) {
-		/* only supposed to happen on emulation/FPGA */
-		BNX2X_ERROR("warning: random MAC workaround active\n");
-		random_ether_addr(bp->dev->dev_addr);
-		memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
-	}
-
-	return rc;
-}
-
-static void __devinit bnx2x_read_fwinfo(struct bnx2x *bp)
-{
-	int cnt, i, block_end, rodi;
-	char vpd_data[BNX2X_VPD_LEN+1];
-	char str_id_reg[VENDOR_ID_LEN+1];
-	char str_id_cap[VENDOR_ID_LEN+1];
-	u8 len;
-
-	cnt = pci_read_vpd(bp->pdev, 0, BNX2X_VPD_LEN, vpd_data);
-	memset(bp->fw_ver, 0, sizeof(bp->fw_ver));
-
-	if (cnt < BNX2X_VPD_LEN)
-		goto out_not_found;
-
-	i = pci_vpd_find_tag(vpd_data, 0, BNX2X_VPD_LEN,
-			     PCI_VPD_LRDT_RO_DATA);
-	if (i < 0)
-		goto out_not_found;
-
-
-	block_end = i + PCI_VPD_LRDT_TAG_SIZE +
-		    pci_vpd_lrdt_size(&vpd_data[i]);
-
-	i += PCI_VPD_LRDT_TAG_SIZE;
-
-	if (block_end > BNX2X_VPD_LEN)
-		goto out_not_found;
-
-	rodi = pci_vpd_find_info_keyword(vpd_data, i, block_end,
-				   PCI_VPD_RO_KEYWORD_MFR_ID);
-	if (rodi < 0)
-		goto out_not_found;
-
-	len = pci_vpd_info_field_size(&vpd_data[rodi]);
-
-	if (len != VENDOR_ID_LEN)
-		goto out_not_found;
-
-	rodi += PCI_VPD_INFO_FLD_HDR_SIZE;
-
-	/* vendor specific info */
-	snprintf(str_id_reg, VENDOR_ID_LEN + 1, "%04x", PCI_VENDOR_ID_DELL);
-	snprintf(str_id_cap, VENDOR_ID_LEN + 1, "%04X", PCI_VENDOR_ID_DELL);
-	if (!strncmp(str_id_reg, &vpd_data[rodi], VENDOR_ID_LEN) ||
-	    !strncmp(str_id_cap, &vpd_data[rodi], VENDOR_ID_LEN)) {
-
-		rodi = pci_vpd_find_info_keyword(vpd_data, i, block_end,
-						PCI_VPD_RO_KEYWORD_VENDOR0);
-		if (rodi >= 0) {
-			len = pci_vpd_info_field_size(&vpd_data[rodi]);
-
-			rodi += PCI_VPD_INFO_FLD_HDR_SIZE;
-
-			if (len < 32 && (len + rodi) <= BNX2X_VPD_LEN) {
-				memcpy(bp->fw_ver, &vpd_data[rodi], len);
-				bp->fw_ver[len] = ' ';
-			}
-		}
-		return;
-	}
-out_not_found:
-	return;
-}
-
-static int __devinit bnx2x_init_bp(struct bnx2x *bp)
-{
-	int func = BP_FUNC(bp);
-	int timer_interval;
-	int rc;
-
-	/* Disable interrupt handling until HW is initialized */
-	atomic_set(&bp->intr_sem, 1);
-	smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
-
-	mutex_init(&bp->port.phy_mutex);
-	mutex_init(&bp->fw_mb_mutex);
-	spin_lock_init(&bp->stats_lock);
-#ifdef BCM_CNIC
-	mutex_init(&bp->cnic_mutex);
-#endif
-
-	INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
-	INIT_DELAYED_WORK(&bp->reset_task, bnx2x_reset_task);
-
-	rc = bnx2x_get_hwinfo(bp);
-
-	bnx2x_read_fwinfo(bp);
-	/* need to reset chip if undi was active */
-	if (!BP_NOMCP(bp))
-		bnx2x_undi_unload(bp);
-
-	if (CHIP_REV_IS_FPGA(bp))
-		dev_err(&bp->pdev->dev, "FPGA detected\n");
-
-	if (BP_NOMCP(bp) && (func == 0))
-		dev_err(&bp->pdev->dev, "MCP disabled, "
-					"must load devices in order!\n");
-
-	/* Set multi queue mode */
-	if ((multi_mode != ETH_RSS_MODE_DISABLED) &&
-	    ((int_mode == INT_MODE_INTx) || (int_mode == INT_MODE_MSI))) {
-		dev_err(&bp->pdev->dev, "Multi disabled since int_mode "
-					"requested is not MSI-X\n");
-		multi_mode = ETH_RSS_MODE_DISABLED;
-	}
-	bp->multi_mode = multi_mode;
-
-
-	bp->dev->features |= NETIF_F_GRO;
-
-	/* Set TPA flags */
-	if (disable_tpa) {
-		bp->flags &= ~TPA_ENABLE_FLAG;
-		bp->dev->features &= ~NETIF_F_LRO;
-	} else {
-		bp->flags |= TPA_ENABLE_FLAG;
-		bp->dev->features |= NETIF_F_LRO;
-	}
-
-	if (CHIP_IS_E1(bp))
-		bp->dropless_fc = 0;
-	else
-		bp->dropless_fc = dropless_fc;
-
-	bp->mrrs = mrrs;
-
-	bp->tx_ring_size = MAX_TX_AVAIL;
-	bp->rx_ring_size = MAX_RX_AVAIL;
-
-	bp->rx_csum = 1;
-
-	/* make sure that the numbers are in the right granularity */
-	bp->tx_ticks = (50 / (4 * BNX2X_BTR)) * (4 * BNX2X_BTR);
-	bp->rx_ticks = (25 / (4 * BNX2X_BTR)) * (4 * BNX2X_BTR);
-
-	timer_interval = (CHIP_REV_IS_SLOW(bp) ? 5*HZ : HZ);
-	bp->current_interval = (poll ? poll : timer_interval);
-
-	init_timer(&bp->timer);
-	bp->timer.expires = jiffies + bp->current_interval;
-	bp->timer.data = (unsigned long) bp;
-	bp->timer.function = bnx2x_timer;
-
-	return rc;
-}
-
-/*
- * ethtool service functions
- */
-
-/* All ethtool functions called with rtnl_lock */
-
-static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	cmd->supported = bp->port.supported;
-	cmd->advertising = bp->port.advertising;
-
-	if ((bp->state == BNX2X_STATE_OPEN) &&
-	    !(bp->flags & MF_FUNC_DIS) &&
-	    (bp->link_vars.link_up)) {
-		cmd->speed = bp->link_vars.line_speed;
-		cmd->duplex = bp->link_vars.duplex;
-		if (IS_E1HMF(bp)) {
-			u16 vn_max_rate;
-
-			vn_max_rate =
-				((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
-				FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
-			if (vn_max_rate < cmd->speed)
-				cmd->speed = vn_max_rate;
-		}
-	} else {
-		cmd->speed = -1;
-		cmd->duplex = -1;
-	}
-
-	if (bp->link_params.switch_cfg == SWITCH_CFG_10G) {
-		u32 ext_phy_type =
-			XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
-
-		switch (ext_phy_type) {
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-			cmd->port = PORT_FIBRE;
-			break;
-
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
-			cmd->port = PORT_TP;
-			break;
-
-		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
-			BNX2X_ERR("XGXS PHY Failure detected 0x%x\n",
-				  bp->link_params.ext_phy_config);
-			break;
-
-		default:
-			DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
-			   bp->link_params.ext_phy_config);
-			break;
-		}
-	} else
-		cmd->port = PORT_TP;
-
-	cmd->phy_address = bp->mdio.prtad;
-	cmd->transceiver = XCVR_INTERNAL;
-
-	if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
-		cmd->autoneg = AUTONEG_ENABLE;
-	else
-		cmd->autoneg = AUTONEG_DISABLE;
-
-	cmd->maxtxpkt = 0;
-	cmd->maxrxpkt = 0;
-
-	DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
-	   DP_LEVEL "  supported 0x%x  advertising 0x%x  speed %d\n"
-	   DP_LEVEL "  duplex %d  port %d  phy_address %d  transceiver %d\n"
-	   DP_LEVEL "  autoneg %d  maxtxpkt %d  maxrxpkt %d\n",
-	   cmd->cmd, cmd->supported, cmd->advertising, cmd->speed,
-	   cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
-	   cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
-
-	return 0;
-}
-
-static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	u32 advertising;
-
-	if (IS_E1HMF(bp))
-		return 0;
-
-	DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
-	   DP_LEVEL "  supported 0x%x  advertising 0x%x  speed %d\n"
-	   DP_LEVEL "  duplex %d  port %d  phy_address %d  transceiver %d\n"
-	   DP_LEVEL "  autoneg %d  maxtxpkt %d  maxrxpkt %d\n",
-	   cmd->cmd, cmd->supported, cmd->advertising, cmd->speed,
-	   cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
-	   cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
-
-	if (cmd->autoneg == AUTONEG_ENABLE) {
-		if (!(bp->port.supported & SUPPORTED_Autoneg)) {
-			DP(NETIF_MSG_LINK, "Autoneg not supported\n");
-			return -EINVAL;
-		}
-
-		/* advertise the requested speed and duplex if supported */
-		cmd->advertising &= bp->port.supported;
-
-		bp->link_params.req_line_speed = SPEED_AUTO_NEG;
-		bp->link_params.req_duplex = DUPLEX_FULL;
-		bp->port.advertising |= (ADVERTISED_Autoneg |
-					 cmd->advertising);
-
-	} else { /* forced speed */
-		/* advertise the requested speed and duplex if supported */
-		switch (cmd->speed) {
-		case SPEED_10:
-			if (cmd->duplex == DUPLEX_FULL) {
-				if (!(bp->port.supported &
-				      SUPPORTED_10baseT_Full)) {
-					DP(NETIF_MSG_LINK,
-					   "10M full not supported\n");
-					return -EINVAL;
-				}
-
-				advertising = (ADVERTISED_10baseT_Full |
-					       ADVERTISED_TP);
-			} else {
-				if (!(bp->port.supported &
-				      SUPPORTED_10baseT_Half)) {
-					DP(NETIF_MSG_LINK,
-					   "10M half not supported\n");
-					return -EINVAL;
-				}
-
-				advertising = (ADVERTISED_10baseT_Half |
-					       ADVERTISED_TP);
-			}
-			break;
-
-		case SPEED_100:
-			if (cmd->duplex == DUPLEX_FULL) {
-				if (!(bp->port.supported &
-						SUPPORTED_100baseT_Full)) {
-					DP(NETIF_MSG_LINK,
-					   "100M full not supported\n");
-					return -EINVAL;
-				}
-
-				advertising = (ADVERTISED_100baseT_Full |
-					       ADVERTISED_TP);
-			} else {
-				if (!(bp->port.supported &
-						SUPPORTED_100baseT_Half)) {
-					DP(NETIF_MSG_LINK,
-					   "100M half not supported\n");
-					return -EINVAL;
-				}
-
-				advertising = (ADVERTISED_100baseT_Half |
-					       ADVERTISED_TP);
-			}
-			break;
-
-		case SPEED_1000:
-			if (cmd->duplex != DUPLEX_FULL) {
-				DP(NETIF_MSG_LINK, "1G half not supported\n");
-				return -EINVAL;
-			}
-
-			if (!(bp->port.supported & SUPPORTED_1000baseT_Full)) {
-				DP(NETIF_MSG_LINK, "1G full not supported\n");
-				return -EINVAL;
-			}
-
-			advertising = (ADVERTISED_1000baseT_Full |
-				       ADVERTISED_TP);
-			break;
-
-		case SPEED_2500:
-			if (cmd->duplex != DUPLEX_FULL) {
-				DP(NETIF_MSG_LINK,
-				   "2.5G half not supported\n");
-				return -EINVAL;
-			}
-
-			if (!(bp->port.supported & SUPPORTED_2500baseX_Full)) {
-				DP(NETIF_MSG_LINK,
-				   "2.5G full not supported\n");
-				return -EINVAL;
-			}
-
-			advertising = (ADVERTISED_2500baseX_Full |
-				       ADVERTISED_TP);
-			break;
-
-		case SPEED_10000:
-			if (cmd->duplex != DUPLEX_FULL) {
-				DP(NETIF_MSG_LINK, "10G half not supported\n");
-				return -EINVAL;
-			}
-
-			if (!(bp->port.supported & SUPPORTED_10000baseT_Full)) {
-				DP(NETIF_MSG_LINK, "10G full not supported\n");
-				return -EINVAL;
-			}
-
-			advertising = (ADVERTISED_10000baseT_Full |
-				       ADVERTISED_FIBRE);
-			break;
-
-		default:
-			DP(NETIF_MSG_LINK, "Unsupported speed\n");
-			return -EINVAL;
-		}
-
-		bp->link_params.req_line_speed = cmd->speed;
-		bp->link_params.req_duplex = cmd->duplex;
-		bp->port.advertising = advertising;
-	}
-
-	DP(NETIF_MSG_LINK, "req_line_speed %d\n"
-	   DP_LEVEL "  req_duplex %d  advertising 0x%x\n",
-	   bp->link_params.req_line_speed, bp->link_params.req_duplex,
-	   bp->port.advertising);
-
-	if (netif_running(dev)) {
-		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-		bnx2x_link_set(bp);
-	}
-
-	return 0;
-}
-
-#define IS_E1_ONLINE(info)	(((info) & RI_E1_ONLINE) == RI_E1_ONLINE)
-#define IS_E1H_ONLINE(info)	(((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE)
-
-static int bnx2x_get_regs_len(struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	int regdump_len = 0;
-	int i;
-
-	if (CHIP_IS_E1(bp)) {
-		for (i = 0; i < REGS_COUNT; i++)
-			if (IS_E1_ONLINE(reg_addrs[i].info))
-				regdump_len += reg_addrs[i].size;
-
-		for (i = 0; i < WREGS_COUNT_E1; i++)
-			if (IS_E1_ONLINE(wreg_addrs_e1[i].info))
-				regdump_len += wreg_addrs_e1[i].size *
-					(1 + wreg_addrs_e1[i].read_regs_count);
-
-	} else { /* E1H */
-		for (i = 0; i < REGS_COUNT; i++)
-			if (IS_E1H_ONLINE(reg_addrs[i].info))
-				regdump_len += reg_addrs[i].size;
-
-		for (i = 0; i < WREGS_COUNT_E1H; i++)
-			if (IS_E1H_ONLINE(wreg_addrs_e1h[i].info))
-				regdump_len += wreg_addrs_e1h[i].size *
-					(1 + wreg_addrs_e1h[i].read_regs_count);
-	}
-	regdump_len *= 4;
-	regdump_len += sizeof(struct dump_hdr);
-
-	return regdump_len;
-}
-
-static void bnx2x_get_regs(struct net_device *dev,
-			   struct ethtool_regs *regs, void *_p)
-{
-	u32 *p = _p, i, j;
-	struct bnx2x *bp = netdev_priv(dev);
-	struct dump_hdr dump_hdr = {0};
-
-	regs->version = 0;
-	memset(p, 0, regs->len);
-
-	if (!netif_running(bp->dev))
-		return;
-
-	dump_hdr.hdr_size = (sizeof(struct dump_hdr) / 4) - 1;
-	dump_hdr.dump_sign = dump_sign_all;
-	dump_hdr.xstorm_waitp = REG_RD(bp, XSTORM_WAITP_ADDR);
-	dump_hdr.tstorm_waitp = REG_RD(bp, TSTORM_WAITP_ADDR);
-	dump_hdr.ustorm_waitp = REG_RD(bp, USTORM_WAITP_ADDR);
-	dump_hdr.cstorm_waitp = REG_RD(bp, CSTORM_WAITP_ADDR);
-	dump_hdr.info = CHIP_IS_E1(bp) ? RI_E1_ONLINE : RI_E1H_ONLINE;
-
-	memcpy(p, &dump_hdr, sizeof(struct dump_hdr));
-	p += dump_hdr.hdr_size + 1;
-
-	if (CHIP_IS_E1(bp)) {
-		for (i = 0; i < REGS_COUNT; i++)
-			if (IS_E1_ONLINE(reg_addrs[i].info))
-				for (j = 0; j < reg_addrs[i].size; j++)
-					*p++ = REG_RD(bp,
-						      reg_addrs[i].addr + j*4);
-
-	} else { /* E1H */
-		for (i = 0; i < REGS_COUNT; i++)
-			if (IS_E1H_ONLINE(reg_addrs[i].info))
-				for (j = 0; j < reg_addrs[i].size; j++)
-					*p++ = REG_RD(bp,
-						      reg_addrs[i].addr + j*4);
-	}
-}
-
-#define PHY_FW_VER_LEN			10
-
-static void bnx2x_get_drvinfo(struct net_device *dev,
-			      struct ethtool_drvinfo *info)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	u8 phy_fw_ver[PHY_FW_VER_LEN];
-
-	strcpy(info->driver, DRV_MODULE_NAME);
-	strcpy(info->version, DRV_MODULE_VERSION);
-
-	phy_fw_ver[0] = '\0';
-	if (bp->port.pmf) {
-		bnx2x_acquire_phy_lock(bp);
-		bnx2x_get_ext_phy_fw_version(&bp->link_params,
-					     (bp->state != BNX2X_STATE_CLOSED),
-					     phy_fw_ver, PHY_FW_VER_LEN);
-		bnx2x_release_phy_lock(bp);
-	}
-
-	strncpy(info->fw_version, bp->fw_ver, 32);
-	snprintf(info->fw_version + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
-		 "bc %d.%d.%d%s%s",
-		 (bp->common.bc_ver & 0xff0000) >> 16,
-		 (bp->common.bc_ver & 0xff00) >> 8,
-		 (bp->common.bc_ver & 0xff),
-		 ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
-	strcpy(info->bus_info, pci_name(bp->pdev));
-	info->n_stats = BNX2X_NUM_STATS;
-	info->testinfo_len = BNX2X_NUM_TESTS;
-	info->eedump_len = bp->common.flash_size;
-	info->regdump_len = bnx2x_get_regs_len(dev);
-}
-
-static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	if (bp->flags & NO_WOL_FLAG) {
-		wol->supported = 0;
-		wol->wolopts = 0;
-	} else {
-		wol->supported = WAKE_MAGIC;
-		if (bp->wol)
-			wol->wolopts = WAKE_MAGIC;
-		else
-			wol->wolopts = 0;
-	}
-	memset(&wol->sopass, 0, sizeof(wol->sopass));
-}
-
-static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	if (wol->wolopts & ~WAKE_MAGIC)
-		return -EINVAL;
-
-	if (wol->wolopts & WAKE_MAGIC) {
-		if (bp->flags & NO_WOL_FLAG)
-			return -EINVAL;
-
-		bp->wol = 1;
-	} else
-		bp->wol = 0;
-
-	return 0;
-}
-
-static u32 bnx2x_get_msglevel(struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	return bp->msg_enable;
-}
-
-static void bnx2x_set_msglevel(struct net_device *dev, u32 level)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	if (capable(CAP_NET_ADMIN))
-		bp->msg_enable = level;
-}
-
-static int bnx2x_nway_reset(struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	if (!bp->port.pmf)
-		return 0;
-
-	if (netif_running(dev)) {
-		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-		bnx2x_link_set(bp);
-	}
-
-	return 0;
-}
-
-static u32 bnx2x_get_link(struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	if (bp->flags & MF_FUNC_DIS)
-		return 0;
-
-	return bp->link_vars.link_up;
-}
-
-static int bnx2x_get_eeprom_len(struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	return bp->common.flash_size;
-}
-
-static int bnx2x_acquire_nvram_lock(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	int count, i;
-	u32 val = 0;
-
-	/* adjust timeout for emulation/FPGA */
-	count = NVRAM_TIMEOUT_COUNT;
-	if (CHIP_REV_IS_SLOW(bp))
-		count *= 100;
-
-	/* request access to nvram interface */
-	REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB,
-	       (MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port));
-
-	for (i = 0; i < count*10; i++) {
-		val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB);
-		if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))
-			break;
-
-		udelay(5);
-	}
-
-	if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) {
-		DP(BNX2X_MSG_NVM, "cannot get access to nvram interface\n");
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-static int bnx2x_release_nvram_lock(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	int count, i;
-	u32 val = 0;
-
-	/* adjust timeout for emulation/FPGA */
-	count = NVRAM_TIMEOUT_COUNT;
-	if (CHIP_REV_IS_SLOW(bp))
-		count *= 100;
-
-	/* relinquish nvram interface */
-	REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB,
-	       (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << port));
-
-	for (i = 0; i < count*10; i++) {
-		val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB);
-		if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)))
-			break;
-
-		udelay(5);
-	}
-
-	if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) {
-		DP(BNX2X_MSG_NVM, "cannot free access to nvram interface\n");
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-static void bnx2x_enable_nvram_access(struct bnx2x *bp)
-{
-	u32 val;
-
-	val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE);
-
-	/* enable both bits, even on read */
-	REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE,
-	       (val | MCPR_NVM_ACCESS_ENABLE_EN |
-		      MCPR_NVM_ACCESS_ENABLE_WR_EN));
-}
-
-static void bnx2x_disable_nvram_access(struct bnx2x *bp)
-{
-	u32 val;
-
-	val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE);
-
-	/* disable both bits, even after read */
-	REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE,
-	       (val & ~(MCPR_NVM_ACCESS_ENABLE_EN |
-			MCPR_NVM_ACCESS_ENABLE_WR_EN)));
-}
-
-static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, __be32 *ret_val,
-				  u32 cmd_flags)
-{
-	int count, i, rc;
-	u32 val;
-
-	/* build the command word */
-	cmd_flags |= MCPR_NVM_COMMAND_DOIT;
-
-	/* need to clear DONE bit separately */
-	REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
-
-	/* address of the NVRAM to read from */
-	REG_WR(bp, MCP_REG_MCPR_NVM_ADDR,
-	       (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE));
-
-	/* issue a read command */
-	REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
-
-	/* adjust timeout for emulation/FPGA */
-	count = NVRAM_TIMEOUT_COUNT;
-	if (CHIP_REV_IS_SLOW(bp))
-		count *= 100;
-
-	/* wait for completion */
-	*ret_val = 0;
-	rc = -EBUSY;
-	for (i = 0; i < count; i++) {
-		udelay(5);
-		val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND);
-
-		if (val & MCPR_NVM_COMMAND_DONE) {
-			val = REG_RD(bp, MCP_REG_MCPR_NVM_READ);
-			/* we read nvram data in cpu order
-			 * but ethtool sees it as an array of bytes
-			 * converting to big-endian will do the work */
-			*ret_val = cpu_to_be32(val);
-			rc = 0;
-			break;
-		}
-	}
-
-	return rc;
-}
-
-static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf,
-			    int buf_size)
-{
-	int rc;
-	u32 cmd_flags;
-	__be32 val;
-
-	if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) {
-		DP(BNX2X_MSG_NVM,
-		   "Invalid parameter: offset 0x%x  buf_size 0x%x\n",
-		   offset, buf_size);
-		return -EINVAL;
-	}
-
-	if (offset + buf_size > bp->common.flash_size) {
-		DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +"
-				  " buf_size (0x%x) > flash_size (0x%x)\n",
-		   offset, buf_size, bp->common.flash_size);
-		return -EINVAL;
-	}
-
-	/* request access to nvram interface */
-	rc = bnx2x_acquire_nvram_lock(bp);
-	if (rc)
-		return rc;
-
-	/* enable access to nvram interface */
-	bnx2x_enable_nvram_access(bp);
-
-	/* read the first word(s) */
-	cmd_flags = MCPR_NVM_COMMAND_FIRST;
-	while ((buf_size > sizeof(u32)) && (rc == 0)) {
-		rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags);
-		memcpy(ret_buf, &val, 4);
-
-		/* advance to the next dword */
-		offset += sizeof(u32);
-		ret_buf += sizeof(u32);
-		buf_size -= sizeof(u32);
-		cmd_flags = 0;
-	}
-
-	if (rc == 0) {
-		cmd_flags |= MCPR_NVM_COMMAND_LAST;
-		rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags);
-		memcpy(ret_buf, &val, 4);
-	}
-
-	/* disable access to nvram interface */
-	bnx2x_disable_nvram_access(bp);
-	bnx2x_release_nvram_lock(bp);
-
-	return rc;
-}
-
-static int bnx2x_get_eeprom(struct net_device *dev,
-			    struct ethtool_eeprom *eeprom, u8 *eebuf)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	int rc;
-
-	if (!netif_running(dev))
-		return -EAGAIN;
-
-	DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n"
-	   DP_LEVEL "  magic 0x%x  offset 0x%x (%d)  len 0x%x (%d)\n",
-	   eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset,
-	   eeprom->len, eeprom->len);
-
-	/* parameters already validated in ethtool_get_eeprom */
-
-	rc = bnx2x_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
-
-	return rc;
-}
-
-static int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val,
-				   u32 cmd_flags)
-{
-	int count, i, rc;
-
-	/* build the command word */
-	cmd_flags |= MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WR;
-
-	/* need to clear DONE bit separately */
-	REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
-
-	/* write the data */
-	REG_WR(bp, MCP_REG_MCPR_NVM_WRITE, val);
-
-	/* address of the NVRAM to write to */
-	REG_WR(bp, MCP_REG_MCPR_NVM_ADDR,
-	       (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE));
-
-	/* issue the write command */
-	REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
-
-	/* adjust timeout for emulation/FPGA */
-	count = NVRAM_TIMEOUT_COUNT;
-	if (CHIP_REV_IS_SLOW(bp))
-		count *= 100;
-
-	/* wait for completion */
-	rc = -EBUSY;
-	for (i = 0; i < count; i++) {
-		udelay(5);
-		val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND);
-		if (val & MCPR_NVM_COMMAND_DONE) {
-			rc = 0;
-			break;
-		}
-	}
-
-	return rc;
-}
-
-#define BYTE_OFFSET(offset)		(8 * (offset & 0x03))
-
-static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf,
-			      int buf_size)
-{
-	int rc;
-	u32 cmd_flags;
-	u32 align_offset;
-	__be32 val;
-
-	if (offset + buf_size > bp->common.flash_size) {
-		DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +"
-				  " buf_size (0x%x) > flash_size (0x%x)\n",
-		   offset, buf_size, bp->common.flash_size);
-		return -EINVAL;
-	}
-
-	/* request access to nvram interface */
-	rc = bnx2x_acquire_nvram_lock(bp);
-	if (rc)
-		return rc;
-
-	/* enable access to nvram interface */
-	bnx2x_enable_nvram_access(bp);
-
-	cmd_flags = (MCPR_NVM_COMMAND_FIRST | MCPR_NVM_COMMAND_LAST);
-	align_offset = (offset & ~0x03);
-	rc = bnx2x_nvram_read_dword(bp, align_offset, &val, cmd_flags);
-
-	if (rc == 0) {
-		val &= ~(0xff << BYTE_OFFSET(offset));
-		val |= (*data_buf << BYTE_OFFSET(offset));
-
-		/* nvram data is returned as an array of bytes
-		 * convert it back to cpu order */
-		val = be32_to_cpu(val);
-
-		rc = bnx2x_nvram_write_dword(bp, align_offset, val,
-					     cmd_flags);
-	}
-
-	/* disable access to nvram interface */
-	bnx2x_disable_nvram_access(bp);
-	bnx2x_release_nvram_lock(bp);
-
-	return rc;
-}
-
-static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf,
-			     int buf_size)
-{
-	int rc;
-	u32 cmd_flags;
-	u32 val;
-	u32 written_so_far;
-
-	if (buf_size == 1)	/* ethtool */
-		return bnx2x_nvram_write1(bp, offset, data_buf, buf_size);
-
-	if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) {
-		DP(BNX2X_MSG_NVM,
-		   "Invalid parameter: offset 0x%x  buf_size 0x%x\n",
-		   offset, buf_size);
-		return -EINVAL;
-	}
-
-	if (offset + buf_size > bp->common.flash_size) {
-		DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +"
-				  " buf_size (0x%x) > flash_size (0x%x)\n",
-		   offset, buf_size, bp->common.flash_size);
-		return -EINVAL;
-	}
-
-	/* request access to nvram interface */
-	rc = bnx2x_acquire_nvram_lock(bp);
-	if (rc)
-		return rc;
-
-	/* enable access to nvram interface */
-	bnx2x_enable_nvram_access(bp);
-
-	written_so_far = 0;
-	cmd_flags = MCPR_NVM_COMMAND_FIRST;
-	while ((written_so_far < buf_size) && (rc == 0)) {
-		if (written_so_far == (buf_size - sizeof(u32)))
-			cmd_flags |= MCPR_NVM_COMMAND_LAST;
-		else if (((offset + 4) % NVRAM_PAGE_SIZE) == 0)
-			cmd_flags |= MCPR_NVM_COMMAND_LAST;
-		else if ((offset % NVRAM_PAGE_SIZE) == 0)
-			cmd_flags |= MCPR_NVM_COMMAND_FIRST;
-
-		memcpy(&val, data_buf, 4);
-
-		rc = bnx2x_nvram_write_dword(bp, offset, val, cmd_flags);
-
-		/* advance to the next dword */
-		offset += sizeof(u32);
-		data_buf += sizeof(u32);
-		written_so_far += sizeof(u32);
-		cmd_flags = 0;
-	}
-
-	/* disable access to nvram interface */
-	bnx2x_disable_nvram_access(bp);
-	bnx2x_release_nvram_lock(bp);
-
-	return rc;
-}
-
-static int bnx2x_set_eeprom(struct net_device *dev,
-			    struct ethtool_eeprom *eeprom, u8 *eebuf)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	int port = BP_PORT(bp);
-	int rc = 0;
-
-	if (!netif_running(dev))
-		return -EAGAIN;
-
-	DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n"
-	   DP_LEVEL "  magic 0x%x  offset 0x%x (%d)  len 0x%x (%d)\n",
-	   eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset,
-	   eeprom->len, eeprom->len);
-
-	/* parameters already validated in ethtool_set_eeprom */
-
-	/* PHY eeprom can be accessed only by the PMF */
-	if ((eeprom->magic >= 0x50485900) && (eeprom->magic <= 0x504859FF) &&
-	    !bp->port.pmf)
-		return -EINVAL;
-
-	if (eeprom->magic == 0x50485950) {
-		/* 'PHYP' (0x50485950): prepare phy for FW upgrade */
-		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-
-		bnx2x_acquire_phy_lock(bp);
-		rc |= bnx2x_link_reset(&bp->link_params,
-				       &bp->link_vars, 0);
-		if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
-					PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101)
-			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
-				       MISC_REGISTERS_GPIO_HIGH, port);
-		bnx2x_release_phy_lock(bp);
-		bnx2x_link_report(bp);
-
-	} else if (eeprom->magic == 0x50485952) {
-		/* 'PHYR' (0x50485952): re-init link after FW upgrade */
-		if (bp->state == BNX2X_STATE_OPEN) {
-			bnx2x_acquire_phy_lock(bp);
-			rc |= bnx2x_link_reset(&bp->link_params,
-					       &bp->link_vars, 1);
-
-			rc |= bnx2x_phy_init(&bp->link_params,
-					     &bp->link_vars);
-			bnx2x_release_phy_lock(bp);
-			bnx2x_calc_fc_adv(bp);
-		}
-	} else if (eeprom->magic == 0x53985943) {
-		/* 'PHYC' (0x53985943): PHY FW upgrade completed */
-		if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
-				       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) {
-			u8 ext_phy_addr =
-			     XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config);
-
-			/* DSP Remove Download Mode */
-			bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
-				       MISC_REGISTERS_GPIO_LOW, port);
-
-			bnx2x_acquire_phy_lock(bp);
-
-			bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
-
-			/* wait 0.5 sec to allow it to run */
-			msleep(500);
-			bnx2x_ext_phy_hw_reset(bp, port);
-			msleep(500);
-			bnx2x_release_phy_lock(bp);
-		}
-	} else
-		rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
-
-	return rc;
-}
-
-static int bnx2x_get_coalesce(struct net_device *dev,
-			      struct ethtool_coalesce *coal)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	memset(coal, 0, sizeof(struct ethtool_coalesce));
-
-	coal->rx_coalesce_usecs = bp->rx_ticks;
-	coal->tx_coalesce_usecs = bp->tx_ticks;
-
-	return 0;
-}
-
-static int bnx2x_set_coalesce(struct net_device *dev,
-			      struct ethtool_coalesce *coal)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	bp->rx_ticks = (u16)coal->rx_coalesce_usecs;
-	if (bp->rx_ticks > BNX2X_MAX_COALESCE_TOUT)
-		bp->rx_ticks = BNX2X_MAX_COALESCE_TOUT;
-
-	bp->tx_ticks = (u16)coal->tx_coalesce_usecs;
-	if (bp->tx_ticks > BNX2X_MAX_COALESCE_TOUT)
-		bp->tx_ticks = BNX2X_MAX_COALESCE_TOUT;
-
-	if (netif_running(dev))
-		bnx2x_update_coalesce(bp);
-
-	return 0;
-}
-
-static void bnx2x_get_ringparam(struct net_device *dev,
-				struct ethtool_ringparam *ering)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	ering->rx_max_pending = MAX_RX_AVAIL;
-	ering->rx_mini_max_pending = 0;
-	ering->rx_jumbo_max_pending = 0;
-
-	ering->rx_pending = bp->rx_ring_size;
-	ering->rx_mini_pending = 0;
-	ering->rx_jumbo_pending = 0;
-
-	ering->tx_max_pending = MAX_TX_AVAIL;
-	ering->tx_pending = bp->tx_ring_size;
-}
-
-static int bnx2x_set_ringparam(struct net_device *dev,
-			       struct ethtool_ringparam *ering)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	int rc = 0;
-
-	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
-		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
-		return -EAGAIN;
-	}
-
-	if ((ering->rx_pending > MAX_RX_AVAIL) ||
-	    (ering->tx_pending > MAX_TX_AVAIL) ||
-	    (ering->tx_pending <= MAX_SKB_FRAGS + 4))
-		return -EINVAL;
-
-	bp->rx_ring_size = ering->rx_pending;
-	bp->tx_ring_size = ering->tx_pending;
-
-	if (netif_running(dev)) {
-		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
-		rc = bnx2x_nic_load(bp, LOAD_NORMAL);
-	}
-
-	return rc;
-}
-
-static void bnx2x_get_pauseparam(struct net_device *dev,
-				 struct ethtool_pauseparam *epause)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	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 & 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",
-	   epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause);
-}
-
-static int bnx2x_set_pauseparam(struct net_device *dev,
-				struct ethtool_pauseparam *epause)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	if (IS_E1HMF(bp))
-		return 0;
-
-	DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n"
-	   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 = BNX2X_FLOW_CTRL_AUTO;
-
-	if (epause->rx_pause)
-		bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_RX;
-
-	if (epause->tx_pause)
-		bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_TX;
-
-	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)) {
-			DP(NETIF_MSG_LINK, "autoneg not supported\n");
-			return -EINVAL;
-		}
-
-		if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
-			bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
-	}
-
-	DP(NETIF_MSG_LINK,
-	   "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl);
-
-	if (netif_running(dev)) {
-		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-		bnx2x_link_set(bp);
-	}
-
-	return 0;
-}
-
-static int bnx2x_set_flags(struct net_device *dev, u32 data)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	int changed = 0;
-	int rc = 0;
-
-	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
-		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
-		return -EAGAIN;
-	}
-
-	/* TPA requires Rx CSUM offloading */
-	if ((data & ETH_FLAG_LRO) && bp->rx_csum) {
-		if (!disable_tpa) {
-			if (!(dev->features & NETIF_F_LRO)) {
-				dev->features |= NETIF_F_LRO;
-				bp->flags |= TPA_ENABLE_FLAG;
-				changed = 1;
-			}
-		} else
-			rc = -EINVAL;
-	} else if (dev->features & NETIF_F_LRO) {
-		dev->features &= ~NETIF_F_LRO;
-		bp->flags &= ~TPA_ENABLE_FLAG;
-		changed = 1;
-	}
-
-	if (data & ETH_FLAG_RXHASH)
-		dev->features |= NETIF_F_RXHASH;
-	else
-		dev->features &= ~NETIF_F_RXHASH;
-
-	if (changed && netif_running(dev)) {
-		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
-		rc = bnx2x_nic_load(bp, LOAD_NORMAL);
-	}
-
-	return rc;
-}
-
-static u32 bnx2x_get_rx_csum(struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	return bp->rx_csum;
-}
-
-static int bnx2x_set_rx_csum(struct net_device *dev, u32 data)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	int rc = 0;
-
-	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
-		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
-		return -EAGAIN;
-	}
-
-	bp->rx_csum = data;
-
-	/* Disable TPA, when Rx CSUM is disabled. Otherwise all
-	   TPA'ed packets will be discarded due to wrong TCP CSUM */
-	if (!data) {
-		u32 flags = ethtool_op_get_flags(dev);
-
-		rc = bnx2x_set_flags(dev, (flags & ~ETH_FLAG_LRO));
-	}
-
-	return rc;
-}
-
-static int bnx2x_set_tso(struct net_device *dev, u32 data)
-{
-	if (data) {
-		dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
-		dev->features |= NETIF_F_TSO6;
-	} else {
-		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
-		dev->features &= ~NETIF_F_TSO6;
-	}
-
-	return 0;
-}
-
-static const struct {
-	char string[ETH_GSTRING_LEN];
-} bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = {
-	{ "register_test (offline)" },
-	{ "memory_test (offline)" },
-	{ "loopback_test (offline)" },
-	{ "nvram_test (online)" },
-	{ "interrupt_test (online)" },
-	{ "link_test (online)" },
-	{ "idle check (online)" }
-};
-
-static int bnx2x_test_registers(struct bnx2x *bp)
-{
-	int idx, i, rc = -ENODEV;
-	u32 wr_val = 0;
-	int port = BP_PORT(bp);
-	static const struct {
-		u32 offset0;
-		u32 offset1;
-		u32 mask;
-	} reg_tbl[] = {
-/* 0 */		{ BRB1_REG_PAUSE_LOW_THRESHOLD_0,      4, 0x000003ff },
-		{ DORQ_REG_DB_ADDR0,                   4, 0xffffffff },
-		{ HC_REG_AGG_INT_0,                    4, 0x000003ff },
-		{ PBF_REG_MAC_IF0_ENABLE,              4, 0x00000001 },
-		{ PBF_REG_P0_INIT_CRD,                 4, 0x000007ff },
-		{ PRS_REG_CID_PORT_0,                  4, 0x00ffffff },
-		{ PXP2_REG_PSWRQ_CDU0_L2P,             4, 0x000fffff },
-		{ PXP2_REG_RQ_CDU0_EFIRST_MEM_ADDR,    8, 0x0003ffff },
-		{ PXP2_REG_PSWRQ_TM0_L2P,              4, 0x000fffff },
-		{ PXP2_REG_RQ_USDM0_EFIRST_MEM_ADDR,   8, 0x0003ffff },
-/* 10 */	{ PXP2_REG_PSWRQ_TSDM0_L2P,            4, 0x000fffff },
-		{ QM_REG_CONNNUM_0,                    4, 0x000fffff },
-		{ TM_REG_LIN0_MAX_ACTIVE_CID,          4, 0x0003ffff },
-		{ SRC_REG_KEYRSS0_0,                  40, 0xffffffff },
-		{ SRC_REG_KEYRSS0_7,                  40, 0xffffffff },
-		{ XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 4, 0x00000001 },
-		{ XCM_REG_WU_DA_CNT_CMD00,             4, 0x00000003 },
-		{ XCM_REG_GLB_DEL_ACK_MAX_CNT_0,       4, 0x000000ff },
-		{ NIG_REG_LLH0_T_BIT,                  4, 0x00000001 },
-		{ NIG_REG_EMAC0_IN_EN,                 4, 0x00000001 },
-/* 20 */	{ NIG_REG_BMAC0_IN_EN,                 4, 0x00000001 },
-		{ NIG_REG_XCM0_OUT_EN,                 4, 0x00000001 },
-		{ NIG_REG_BRB0_OUT_EN,                 4, 0x00000001 },
-		{ NIG_REG_LLH0_XCM_MASK,               4, 0x00000007 },
-		{ NIG_REG_LLH0_ACPI_PAT_6_LEN,        68, 0x000000ff },
-		{ NIG_REG_LLH0_ACPI_PAT_0_CRC,        68, 0xffffffff },
-		{ NIG_REG_LLH0_DEST_MAC_0_0,         160, 0xffffffff },
-		{ NIG_REG_LLH0_DEST_IP_0_1,          160, 0xffffffff },
-		{ NIG_REG_LLH0_IPV4_IPV6_0,          160, 0x00000001 },
-		{ NIG_REG_LLH0_DEST_UDP_0,           160, 0x0000ffff },
-/* 30 */	{ NIG_REG_LLH0_DEST_TCP_0,           160, 0x0000ffff },
-		{ NIG_REG_LLH0_VLAN_ID_0,            160, 0x00000fff },
-		{ NIG_REG_XGXS_SERDES0_MODE_SEL,       4, 0x00000001 },
-		{ NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0, 4, 0x00000001 },
-		{ NIG_REG_STATUS_INTERRUPT_PORT0,      4, 0x07ffffff },
-		{ NIG_REG_XGXS0_CTRL_EXTREMOTEMDIOST, 24, 0x00000001 },
-		{ NIG_REG_SERDES0_CTRL_PHY_ADDR,      16, 0x0000001f },
-
-		{ 0xffffffff, 0, 0x00000000 }
-	};
-
-	if (!netif_running(bp->dev))
-		return rc;
-
-	/* Repeat the test twice:
-	   First by writing 0x00000000, second by writing 0xffffffff */
-	for (idx = 0; idx < 2; idx++) {
-
-		switch (idx) {
-		case 0:
-			wr_val = 0;
-			break;
-		case 1:
-			wr_val = 0xffffffff;
-			break;
-		}
-
-		for (i = 0; reg_tbl[i].offset0 != 0xffffffff; i++) {
-			u32 offset, mask, save_val, val;
-
-			offset = reg_tbl[i].offset0 + port*reg_tbl[i].offset1;
-			mask = reg_tbl[i].mask;
-
-			save_val = REG_RD(bp, offset);
-
-			REG_WR(bp, offset, (wr_val & mask));
-			val = REG_RD(bp, offset);
-
-			/* Restore the original register's value */
-			REG_WR(bp, offset, save_val);
-
-			/* verify value is as expected */
-			if ((val & mask) != (wr_val & mask)) {
-				DP(NETIF_MSG_PROBE,
-				   "offset 0x%x: val 0x%x != 0x%x mask 0x%x\n",
-				   offset, val, wr_val, mask);
-				goto test_reg_exit;
-			}
-		}
-	}
-
-	rc = 0;
-
-test_reg_exit:
-	return rc;
-}
-
-static int bnx2x_test_memory(struct bnx2x *bp)
-{
-	int i, j, rc = -ENODEV;
-	u32 val;
-	static const struct {
-		u32 offset;
-		int size;
-	} mem_tbl[] = {
-		{ CCM_REG_XX_DESCR_TABLE,   CCM_REG_XX_DESCR_TABLE_SIZE },
-		{ CFC_REG_ACTIVITY_COUNTER, CFC_REG_ACTIVITY_COUNTER_SIZE },
-		{ CFC_REG_LINK_LIST,        CFC_REG_LINK_LIST_SIZE },
-		{ DMAE_REG_CMD_MEM,         DMAE_REG_CMD_MEM_SIZE },
-		{ TCM_REG_XX_DESCR_TABLE,   TCM_REG_XX_DESCR_TABLE_SIZE },
-		{ UCM_REG_XX_DESCR_TABLE,   UCM_REG_XX_DESCR_TABLE_SIZE },
-		{ XCM_REG_XX_DESCR_TABLE,   XCM_REG_XX_DESCR_TABLE_SIZE },
-
-		{ 0xffffffff, 0 }
-	};
-	static const struct {
-		char *name;
-		u32 offset;
-		u32 e1_mask;
-		u32 e1h_mask;
-	} prty_tbl[] = {
-		{ "CCM_PRTY_STS",  CCM_REG_CCM_PRTY_STS,   0x3ffc0, 0 },
-		{ "CFC_PRTY_STS",  CFC_REG_CFC_PRTY_STS,   0x2,     0x2 },
-		{ "DMAE_PRTY_STS", DMAE_REG_DMAE_PRTY_STS, 0,       0 },
-		{ "TCM_PRTY_STS",  TCM_REG_TCM_PRTY_STS,   0x3ffc0, 0 },
-		{ "UCM_PRTY_STS",  UCM_REG_UCM_PRTY_STS,   0x3ffc0, 0 },
-		{ "XCM_PRTY_STS",  XCM_REG_XCM_PRTY_STS,   0x3ffc1, 0 },
-
-		{ NULL, 0xffffffff, 0, 0 }
-	};
-
-	if (!netif_running(bp->dev))
-		return rc;
-
-	/* Go through all the memories */
-	for (i = 0; mem_tbl[i].offset != 0xffffffff; i++)
-		for (j = 0; j < mem_tbl[i].size; j++)
-			REG_RD(bp, mem_tbl[i].offset + j*4);
-
-	/* Check the parity status */
-	for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) {
-		val = REG_RD(bp, prty_tbl[i].offset);
-		if ((CHIP_IS_E1(bp) && (val & ~(prty_tbl[i].e1_mask))) ||
-		    (CHIP_IS_E1H(bp) && (val & ~(prty_tbl[i].e1h_mask)))) {
-			DP(NETIF_MSG_HW,
-			   "%s is 0x%x\n", prty_tbl[i].name, val);
-			goto test_mem_exit;
-		}
-	}
-
-	rc = 0;
-
-test_mem_exit:
-	return rc;
-}
-
-static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up)
-{
-	int cnt = 1000;
-
-	if (link_up)
-		while (bnx2x_link_test(bp) && cnt--)
-			msleep(10);
-}
-
-static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
-{
-	unsigned int pkt_size, num_pkts, i;
-	struct sk_buff *skb;
-	unsigned char *packet;
-	struct bnx2x_fastpath *fp_rx = &bp->fp[0];
-	struct bnx2x_fastpath *fp_tx = &bp->fp[0];
-	u16 tx_start_idx, tx_idx;
-	u16 rx_start_idx, rx_idx;
-	u16 pkt_prod, bd_prod;
-	struct sw_tx_bd *tx_buf;
-	struct eth_tx_start_bd *tx_start_bd;
-	struct eth_tx_parse_bd *pbd = NULL;
-	dma_addr_t mapping;
-	union eth_rx_cqe *cqe;
-	u8 cqe_fp_flags;
-	struct sw_rx_bd *rx_buf;
-	u16 len;
-	int rc = -ENODEV;
-
-	/* check the loopback mode */
-	switch (loopback_mode) {
-	case BNX2X_PHY_LOOPBACK:
-		if (bp->link_params.loopback_mode != LOOPBACK_XGXS_10)
-			return -EINVAL;
-		break;
-	case BNX2X_MAC_LOOPBACK:
-		bp->link_params.loopback_mode = LOOPBACK_BMAC;
-		bnx2x_phy_init(&bp->link_params, &bp->link_vars);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* prepare the loopback packet */
-	pkt_size = (((bp->dev->mtu < ETH_MAX_PACKET_SIZE) ?
-		     bp->dev->mtu : ETH_MAX_PACKET_SIZE) + ETH_HLEN);
-	skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
-	if (!skb) {
-		rc = -ENOMEM;
-		goto test_loopback_exit;
-	}
-	packet = skb_put(skb, pkt_size);
-	memcpy(packet, bp->dev->dev_addr, ETH_ALEN);
-	memset(packet + ETH_ALEN, 0, ETH_ALEN);
-	memset(packet + 2*ETH_ALEN, 0x77, (ETH_HLEN - 2*ETH_ALEN));
-	for (i = ETH_HLEN; i < pkt_size; i++)
-		packet[i] = (unsigned char) (i & 0xff);
-
-	/* send the loopback packet */
-	num_pkts = 0;
-	tx_start_idx = le16_to_cpu(*fp_tx->tx_cons_sb);
-	rx_start_idx = le16_to_cpu(*fp_rx->rx_cons_sb);
-
-	pkt_prod = fp_tx->tx_pkt_prod++;
-	tx_buf = &fp_tx->tx_buf_ring[TX_BD(pkt_prod)];
-	tx_buf->first_bd = fp_tx->tx_bd_prod;
-	tx_buf->skb = skb;
-	tx_buf->flags = 0;
-
-	bd_prod = TX_BD(fp_tx->tx_bd_prod);
-	tx_start_bd = &fp_tx->tx_desc_ring[bd_prod].start_bd;
-	mapping = dma_map_single(&bp->pdev->dev, skb->data,
-				 skb_headlen(skb), DMA_TO_DEVICE);
-	tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
-	tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
-	tx_start_bd->nbd = cpu_to_le16(2); /* start + pbd */
-	tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb));
-	tx_start_bd->vlan = cpu_to_le16(pkt_prod);
-	tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
-	tx_start_bd->general_data = ((UNICAST_ADDRESS <<
-				ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT) | 1);
-
-	/* turn on parsing and get a BD */
-	bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
-	pbd = &fp_tx->tx_desc_ring[bd_prod].parse_bd;
-
-	memset(pbd, 0, sizeof(struct eth_tx_parse_bd));
-
-	wmb();
-
-	fp_tx->tx_db.data.prod += 2;
-	barrier();
-	DOORBELL(bp, fp_tx->index, fp_tx->tx_db.raw);
-
-	mmiowb();
-
-	num_pkts++;
-	fp_tx->tx_bd_prod += 2; /* start + pbd */
-
-	udelay(100);
-
-	tx_idx = le16_to_cpu(*fp_tx->tx_cons_sb);
-	if (tx_idx != tx_start_idx + num_pkts)
-		goto test_loopback_exit;
-
-	rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb);
-	if (rx_idx != rx_start_idx + num_pkts)
-		goto test_loopback_exit;
-
-	cqe = &fp_rx->rx_comp_ring[RCQ_BD(fp_rx->rx_comp_cons)];
-	cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
-	if (CQE_TYPE(cqe_fp_flags) || (cqe_fp_flags & ETH_RX_ERROR_FALGS))
-		goto test_loopback_rx_exit;
-
-	len = le16_to_cpu(cqe->fast_path_cqe.pkt_len);
-	if (len != pkt_size)
-		goto test_loopback_rx_exit;
-
-	rx_buf = &fp_rx->rx_buf_ring[RX_BD(fp_rx->rx_bd_cons)];
-	skb = rx_buf->skb;
-	skb_reserve(skb, cqe->fast_path_cqe.placement_offset);
-	for (i = ETH_HLEN; i < pkt_size; i++)
-		if (*(skb->data + i) != (unsigned char) (i & 0xff))
-			goto test_loopback_rx_exit;
-
-	rc = 0;
-
-test_loopback_rx_exit:
-
-	fp_rx->rx_bd_cons = NEXT_RX_IDX(fp_rx->rx_bd_cons);
-	fp_rx->rx_bd_prod = NEXT_RX_IDX(fp_rx->rx_bd_prod);
-	fp_rx->rx_comp_cons = NEXT_RCQ_IDX(fp_rx->rx_comp_cons);
-	fp_rx->rx_comp_prod = NEXT_RCQ_IDX(fp_rx->rx_comp_prod);
-
-	/* Update producers */
-	bnx2x_update_rx_prod(bp, fp_rx, fp_rx->rx_bd_prod, fp_rx->rx_comp_prod,
-			     fp_rx->rx_sge_prod);
-
-test_loopback_exit:
-	bp->link_params.loopback_mode = LOOPBACK_NONE;
-
-	return rc;
-}
-
-static int bnx2x_test_loopback(struct bnx2x *bp, u8 link_up)
-{
-	int rc = 0, res;
-
-	if (BP_NOMCP(bp))
-		return rc;
-
-	if (!netif_running(bp->dev))
-		return BNX2X_LOOPBACK_FAILED;
-
-	bnx2x_netif_stop(bp, 1);
-	bnx2x_acquire_phy_lock(bp);
-
-	res = bnx2x_run_loopback(bp, BNX2X_PHY_LOOPBACK, link_up);
-	if (res) {
-		DP(NETIF_MSG_PROBE, "  PHY loopback failed  (res %d)\n", res);
-		rc |= BNX2X_PHY_LOOPBACK_FAILED;
-	}
-
-	res = bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK, link_up);
-	if (res) {
-		DP(NETIF_MSG_PROBE, "  MAC loopback failed  (res %d)\n", res);
-		rc |= BNX2X_MAC_LOOPBACK_FAILED;
-	}
-
-	bnx2x_release_phy_lock(bp);
-	bnx2x_netif_start(bp);
-
-	return rc;
-}
-
-#define CRC32_RESIDUAL			0xdebb20e3
-
-static int bnx2x_test_nvram(struct bnx2x *bp)
-{
-	static const struct {
-		int offset;
-		int size;
-	} nvram_tbl[] = {
-		{     0,  0x14 }, /* bootstrap */
-		{  0x14,  0xec }, /* dir */
-		{ 0x100, 0x350 }, /* manuf_info */
-		{ 0x450,  0xf0 }, /* feature_info */
-		{ 0x640,  0x64 }, /* upgrade_key_info */
-		{ 0x6a4,  0x64 },
-		{ 0x708,  0x70 }, /* manuf_key_info */
-		{ 0x778,  0x70 },
-		{     0,     0 }
-	};
-	__be32 buf[0x350 / 4];
-	u8 *data = (u8 *)buf;
-	int i, rc;
-	u32 magic, crc;
-
-	if (BP_NOMCP(bp))
-		return 0;
-
-	rc = bnx2x_nvram_read(bp, 0, data, 4);
-	if (rc) {
-		DP(NETIF_MSG_PROBE, "magic value read (rc %d)\n", rc);
-		goto test_nvram_exit;
-	}
-
-	magic = be32_to_cpu(buf[0]);
-	if (magic != 0x669955aa) {
-		DP(NETIF_MSG_PROBE, "magic value (0x%08x)\n", magic);
-		rc = -ENODEV;
-		goto test_nvram_exit;
-	}
-
-	for (i = 0; nvram_tbl[i].size; i++) {
-
-		rc = bnx2x_nvram_read(bp, nvram_tbl[i].offset, data,
-				      nvram_tbl[i].size);
-		if (rc) {
-			DP(NETIF_MSG_PROBE,
-			   "nvram_tbl[%d] read data (rc %d)\n", i, rc);
-			goto test_nvram_exit;
-		}
-
-		crc = ether_crc_le(nvram_tbl[i].size, data);
-		if (crc != CRC32_RESIDUAL) {
-			DP(NETIF_MSG_PROBE,
-			   "nvram_tbl[%d] crc value (0x%08x)\n", i, crc);
-			rc = -ENODEV;
-			goto test_nvram_exit;
-		}
-	}
-
-test_nvram_exit:
-	return rc;
-}
-
-static int bnx2x_test_intr(struct bnx2x *bp)
-{
-	struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config);
-	int i, rc;
-
-	if (!netif_running(bp->dev))
-		return -ENODEV;
-
-	config->hdr.length = 0;
-	if (CHIP_IS_E1(bp))
-		/* use last unicast entries */
-		config->hdr.offset = (BP_PORT(bp) ? 63 : 31);
-	else
-		config->hdr.offset = BP_FUNC(bp);
-	config->hdr.client_id = bp->fp->cl_id;
-	config->hdr.reserved1 = 0;
-
-	bp->set_mac_pending++;
-	smp_wmb();
-	rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
-			   U64_HI(bnx2x_sp_mapping(bp, mac_config)),
-			   U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
-	if (rc == 0) {
-		for (i = 0; i < 10; i++) {
-			if (!bp->set_mac_pending)
-				break;
-			smp_rmb();
-			msleep_interruptible(10);
-		}
-		if (i == 10)
-			rc = -ENODEV;
-	}
-
-	return rc;
-}
-
-static void bnx2x_self_test(struct net_device *dev,
-			    struct ethtool_test *etest, u64 *buf)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
-		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
-		etest->flags |= ETH_TEST_FL_FAILED;
-		return;
-	}
-
-	memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS);
-
-	if (!netif_running(dev))
-		return;
-
-	/* offline tests are not supported in MF mode */
-	if (IS_E1HMF(bp))
-		etest->flags &= ~ETH_TEST_FL_OFFLINE;
-
-	if (etest->flags & ETH_TEST_FL_OFFLINE) {
-		int port = BP_PORT(bp);
-		u32 val;
-		u8 link_up;
-
-		/* save current value of input enable for TX port IF */
-		val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4);
-		/* disable input for TX port IF */
-		REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
-
-		link_up = (bnx2x_link_test(bp) == 0);
-		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
-		bnx2x_nic_load(bp, LOAD_DIAG);
-		/* wait until link state is restored */
-		bnx2x_wait_for_link(bp, link_up);
-
-		if (bnx2x_test_registers(bp) != 0) {
-			buf[0] = 1;
-			etest->flags |= ETH_TEST_FL_FAILED;
-		}
-		if (bnx2x_test_memory(bp) != 0) {
-			buf[1] = 1;
-			etest->flags |= ETH_TEST_FL_FAILED;
-		}
-		buf[2] = bnx2x_test_loopback(bp, link_up);
-		if (buf[2] != 0)
-			etest->flags |= ETH_TEST_FL_FAILED;
-
-		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
-
-		/* restore input for TX port IF */
-		REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, val);
-
-		bnx2x_nic_load(bp, LOAD_NORMAL);
-		/* wait until link state is restored */
-		bnx2x_wait_for_link(bp, link_up);
-	}
-	if (bnx2x_test_nvram(bp) != 0) {
-		buf[3] = 1;
-		etest->flags |= ETH_TEST_FL_FAILED;
-	}
-	if (bnx2x_test_intr(bp) != 0) {
-		buf[4] = 1;
-		etest->flags |= ETH_TEST_FL_FAILED;
-	}
-	if (bp->port.pmf)
-		if (bnx2x_link_test(bp) != 0) {
-			buf[5] = 1;
-			etest->flags |= ETH_TEST_FL_FAILED;
-		}
-
-#ifdef BNX2X_EXTRA_DEBUG
-	bnx2x_panic_dump(bp);
-#endif
-}
-
-static const struct {
-	long offset;
-	int size;
-	u8 string[ETH_GSTRING_LEN];
-} bnx2x_q_stats_arr[BNX2X_NUM_Q_STATS] = {
-/* 1 */	{ Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%d]: rx_bytes" },
-	{ Q_STATS_OFFSET32(error_bytes_received_hi),
-						8, "[%d]: rx_error_bytes" },
-	{ Q_STATS_OFFSET32(total_unicast_packets_received_hi),
-						8, "[%d]: rx_ucast_packets" },
-	{ Q_STATS_OFFSET32(total_multicast_packets_received_hi),
-						8, "[%d]: rx_mcast_packets" },
-	{ Q_STATS_OFFSET32(total_broadcast_packets_received_hi),
-						8, "[%d]: rx_bcast_packets" },
-	{ Q_STATS_OFFSET32(no_buff_discard_hi),	8, "[%d]: rx_discards" },
-	{ Q_STATS_OFFSET32(rx_err_discard_pkt),
-					 4, "[%d]: rx_phy_ip_err_discards"},
-	{ Q_STATS_OFFSET32(rx_skb_alloc_failed),
-					 4, "[%d]: rx_skb_alloc_discard" },
-	{ Q_STATS_OFFSET32(hw_csum_err), 4, "[%d]: rx_csum_offload_errors" },
-
-/* 10 */{ Q_STATS_OFFSET32(total_bytes_transmitted_hi),	8, "[%d]: tx_bytes" },
-	{ Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi),
-						8, "[%d]: tx_ucast_packets" },
-	{ Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi),
-						8, "[%d]: tx_mcast_packets" },
-	{ Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
-						8, "[%d]: tx_bcast_packets" }
-};
-
-static const struct {
-	long offset;
-	int size;
-	u32 flags;
-#define STATS_FLAGS_PORT		1
-#define STATS_FLAGS_FUNC		2
-#define STATS_FLAGS_BOTH		(STATS_FLAGS_FUNC | STATS_FLAGS_PORT)
-	u8 string[ETH_GSTRING_LEN];
-} bnx2x_stats_arr[BNX2X_NUM_STATS] = {
-/* 1 */	{ STATS_OFFSET32(total_bytes_received_hi),
-				8, STATS_FLAGS_BOTH, "rx_bytes" },
-	{ STATS_OFFSET32(error_bytes_received_hi),
-				8, STATS_FLAGS_BOTH, "rx_error_bytes" },
-	{ STATS_OFFSET32(total_unicast_packets_received_hi),
-				8, STATS_FLAGS_BOTH, "rx_ucast_packets" },
-	{ STATS_OFFSET32(total_multicast_packets_received_hi),
-				8, STATS_FLAGS_BOTH, "rx_mcast_packets" },
-	{ STATS_OFFSET32(total_broadcast_packets_received_hi),
-				8, STATS_FLAGS_BOTH, "rx_bcast_packets" },
-	{ STATS_OFFSET32(rx_stat_dot3statsfcserrors_hi),
-				8, STATS_FLAGS_PORT, "rx_crc_errors" },
-	{ STATS_OFFSET32(rx_stat_dot3statsalignmenterrors_hi),
-				8, STATS_FLAGS_PORT, "rx_align_errors" },
-	{ STATS_OFFSET32(rx_stat_etherstatsundersizepkts_hi),
-				8, STATS_FLAGS_PORT, "rx_undersize_packets" },
-	{ STATS_OFFSET32(etherstatsoverrsizepkts_hi),
-				8, STATS_FLAGS_PORT, "rx_oversize_packets" },
-/* 10 */{ STATS_OFFSET32(rx_stat_etherstatsfragments_hi),
-				8, STATS_FLAGS_PORT, "rx_fragments" },
-	{ STATS_OFFSET32(rx_stat_etherstatsjabbers_hi),
-				8, STATS_FLAGS_PORT, "rx_jabbers" },
-	{ STATS_OFFSET32(no_buff_discard_hi),
-				8, STATS_FLAGS_BOTH, "rx_discards" },
-	{ STATS_OFFSET32(mac_filter_discard),
-				4, STATS_FLAGS_PORT, "rx_filtered_packets" },
-	{ STATS_OFFSET32(xxoverflow_discard),
-				4, STATS_FLAGS_PORT, "rx_fw_discards" },
-	{ STATS_OFFSET32(brb_drop_hi),
-				8, STATS_FLAGS_PORT, "rx_brb_discard" },
-	{ STATS_OFFSET32(brb_truncate_hi),
-				8, STATS_FLAGS_PORT, "rx_brb_truncate" },
-	{ STATS_OFFSET32(pause_frames_received_hi),
-				8, STATS_FLAGS_PORT, "rx_pause_frames" },
-	{ STATS_OFFSET32(rx_stat_maccontrolframesreceived_hi),
-				8, STATS_FLAGS_PORT, "rx_mac_ctrl_frames" },
-	{ STATS_OFFSET32(nig_timer_max),
-			4, STATS_FLAGS_PORT, "rx_constant_pause_events" },
-/* 20 */{ STATS_OFFSET32(rx_err_discard_pkt),
-				4, STATS_FLAGS_BOTH, "rx_phy_ip_err_discards"},
-	{ STATS_OFFSET32(rx_skb_alloc_failed),
-				4, STATS_FLAGS_BOTH, "rx_skb_alloc_discard" },
-	{ STATS_OFFSET32(hw_csum_err),
-				4, STATS_FLAGS_BOTH, "rx_csum_offload_errors" },
-
-	{ STATS_OFFSET32(total_bytes_transmitted_hi),
-				8, STATS_FLAGS_BOTH, "tx_bytes" },
-	{ STATS_OFFSET32(tx_stat_ifhcoutbadoctets_hi),
-				8, STATS_FLAGS_PORT, "tx_error_bytes" },
-	{ STATS_OFFSET32(total_unicast_packets_transmitted_hi),
-				8, STATS_FLAGS_BOTH, "tx_ucast_packets" },
-	{ STATS_OFFSET32(total_multicast_packets_transmitted_hi),
-				8, STATS_FLAGS_BOTH, "tx_mcast_packets" },
-	{ STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
-				8, STATS_FLAGS_BOTH, "tx_bcast_packets" },
-	{ STATS_OFFSET32(tx_stat_dot3statsinternalmactransmiterrors_hi),
-				8, STATS_FLAGS_PORT, "tx_mac_errors" },
-	{ STATS_OFFSET32(rx_stat_dot3statscarriersenseerrors_hi),
-				8, STATS_FLAGS_PORT, "tx_carrier_errors" },
-/* 30 */{ STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi),
-				8, STATS_FLAGS_PORT, "tx_single_collisions" },
-	{ STATS_OFFSET32(tx_stat_dot3statsmultiplecollisionframes_hi),
-				8, STATS_FLAGS_PORT, "tx_multi_collisions" },
-	{ STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi),
-				8, STATS_FLAGS_PORT, "tx_deferred" },
-	{ STATS_OFFSET32(tx_stat_dot3statsexcessivecollisions_hi),
-				8, STATS_FLAGS_PORT, "tx_excess_collisions" },
-	{ STATS_OFFSET32(tx_stat_dot3statslatecollisions_hi),
-				8, STATS_FLAGS_PORT, "tx_late_collisions" },
-	{ STATS_OFFSET32(tx_stat_etherstatscollisions_hi),
-				8, STATS_FLAGS_PORT, "tx_total_collisions" },
-	{ STATS_OFFSET32(tx_stat_etherstatspkts64octets_hi),
-				8, STATS_FLAGS_PORT, "tx_64_byte_packets" },
-	{ STATS_OFFSET32(tx_stat_etherstatspkts65octetsto127octets_hi),
-			8, STATS_FLAGS_PORT, "tx_65_to_127_byte_packets" },
-	{ STATS_OFFSET32(tx_stat_etherstatspkts128octetsto255octets_hi),
-			8, STATS_FLAGS_PORT, "tx_128_to_255_byte_packets" },
-	{ STATS_OFFSET32(tx_stat_etherstatspkts256octetsto511octets_hi),
-			8, STATS_FLAGS_PORT, "tx_256_to_511_byte_packets" },
-/* 40 */{ STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi),
-			8, STATS_FLAGS_PORT, "tx_512_to_1023_byte_packets" },
-	{ STATS_OFFSET32(etherstatspkts1024octetsto1522octets_hi),
-			8, STATS_FLAGS_PORT, "tx_1024_to_1522_byte_packets" },
-	{ STATS_OFFSET32(etherstatspktsover1522octets_hi),
-			8, STATS_FLAGS_PORT, "tx_1523_to_9022_byte_packets" },
-	{ STATS_OFFSET32(pause_frames_sent_hi),
-				8, STATS_FLAGS_PORT, "tx_pause_frames" }
-};
-
-#define IS_PORT_STAT(i) \
-	((bnx2x_stats_arr[i].flags & STATS_FLAGS_BOTH) == STATS_FLAGS_PORT)
-#define IS_FUNC_STAT(i)		(bnx2x_stats_arr[i].flags & STATS_FLAGS_FUNC)
-#define IS_E1HMF_MODE_STAT(bp) \
-			(IS_E1HMF(bp) && !(bp->msg_enable & BNX2X_MSG_STATS))
-
-static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	int i, num_stats;
-
-	switch (stringset) {
-	case ETH_SS_STATS:
-		if (is_multi(bp)) {
-			num_stats = BNX2X_NUM_Q_STATS * bp->num_queues;
-			if (!IS_E1HMF_MODE_STAT(bp))
-				num_stats += BNX2X_NUM_STATS;
-		} else {
-			if (IS_E1HMF_MODE_STAT(bp)) {
-				num_stats = 0;
-				for (i = 0; i < BNX2X_NUM_STATS; i++)
-					if (IS_FUNC_STAT(i))
-						num_stats++;
-			} else
-				num_stats = BNX2X_NUM_STATS;
-		}
-		return num_stats;
-
-	case ETH_SS_TEST:
-		return BNX2X_NUM_TESTS;
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	int i, j, k;
-
-	switch (stringset) {
-	case ETH_SS_STATS:
-		if (is_multi(bp)) {
-			k = 0;
-			for_each_queue(bp, i) {
-				for (j = 0; j < BNX2X_NUM_Q_STATS; j++)
-					sprintf(buf + (k + j)*ETH_GSTRING_LEN,
-						bnx2x_q_stats_arr[j].string, i);
-				k += BNX2X_NUM_Q_STATS;
-			}
-			if (IS_E1HMF_MODE_STAT(bp))
-				break;
-			for (j = 0; j < BNX2X_NUM_STATS; j++)
-				strcpy(buf + (k + j)*ETH_GSTRING_LEN,
-				       bnx2x_stats_arr[j].string);
-		} else {
-			for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
-				if (IS_E1HMF_MODE_STAT(bp) && IS_PORT_STAT(i))
-					continue;
-				strcpy(buf + j*ETH_GSTRING_LEN,
-				       bnx2x_stats_arr[i].string);
-				j++;
-			}
-		}
-		break;
-
-	case ETH_SS_TEST:
-		memcpy(buf, bnx2x_tests_str_arr, sizeof(bnx2x_tests_str_arr));
-		break;
-	}
-}
-
-static void bnx2x_get_ethtool_stats(struct net_device *dev,
-				    struct ethtool_stats *stats, u64 *buf)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	u32 *hw_stats, *offset;
-	int i, j, k;
-
-	if (is_multi(bp)) {
-		k = 0;
-		for_each_queue(bp, i) {
-			hw_stats = (u32 *)&bp->fp[i].eth_q_stats;
-			for (j = 0; j < BNX2X_NUM_Q_STATS; j++) {
-				if (bnx2x_q_stats_arr[j].size == 0) {
-					/* skip this counter */
-					buf[k + j] = 0;
-					continue;
-				}
-				offset = (hw_stats +
-					  bnx2x_q_stats_arr[j].offset);
-				if (bnx2x_q_stats_arr[j].size == 4) {
-					/* 4-byte counter */
-					buf[k + j] = (u64) *offset;
-					continue;
-				}
-				/* 8-byte counter */
-				buf[k + j] = HILO_U64(*offset, *(offset + 1));
-			}
-			k += BNX2X_NUM_Q_STATS;
-		}
-		if (IS_E1HMF_MODE_STAT(bp))
-			return;
-		hw_stats = (u32 *)&bp->eth_stats;
-		for (j = 0; j < BNX2X_NUM_STATS; j++) {
-			if (bnx2x_stats_arr[j].size == 0) {
-				/* skip this counter */
-				buf[k + j] = 0;
-				continue;
-			}
-			offset = (hw_stats + bnx2x_stats_arr[j].offset);
-			if (bnx2x_stats_arr[j].size == 4) {
-				/* 4-byte counter */
-				buf[k + j] = (u64) *offset;
-				continue;
-			}
-			/* 8-byte counter */
-			buf[k + j] = HILO_U64(*offset, *(offset + 1));
-		}
-	} else {
-		hw_stats = (u32 *)&bp->eth_stats;
-		for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
-			if (IS_E1HMF_MODE_STAT(bp) && IS_PORT_STAT(i))
-				continue;
-			if (bnx2x_stats_arr[i].size == 0) {
-				/* skip this counter */
-				buf[j] = 0;
-				j++;
-				continue;
-			}
-			offset = (hw_stats + bnx2x_stats_arr[i].offset);
-			if (bnx2x_stats_arr[i].size == 4) {
-				/* 4-byte counter */
-				buf[j] = (u64) *offset;
-				j++;
-				continue;
-			}
-			/* 8-byte counter */
-			buf[j] = HILO_U64(*offset, *(offset + 1));
-			j++;
-		}
-	}
-}
-
-static int bnx2x_phys_id(struct net_device *dev, u32 data)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	int i;
-
-	if (!netif_running(dev))
-		return 0;
-
-	if (!bp->port.pmf)
-		return 0;
-
-	if (data == 0)
-		data = 2;
-
-	for (i = 0; i < (data * 2); i++) {
-		if ((i % 2) == 0)
-			bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
-				      SPEED_1000);
-		else
-			bnx2x_set_led(&bp->link_params, LED_MODE_OFF, 0);
-
-		msleep_interruptible(500);
-		if (signal_pending(current))
-			break;
-	}
-
-	if (bp->link_vars.link_up)
-		bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
-			      bp->link_vars.line_speed);
-
-	return 0;
-}
-
-static const struct ethtool_ops bnx2x_ethtool_ops = {
-	.get_settings		= bnx2x_get_settings,
-	.set_settings		= bnx2x_set_settings,
-	.get_drvinfo		= bnx2x_get_drvinfo,
-	.get_regs_len		= bnx2x_get_regs_len,
-	.get_regs		= bnx2x_get_regs,
-	.get_wol		= bnx2x_get_wol,
-	.set_wol		= bnx2x_set_wol,
-	.get_msglevel		= bnx2x_get_msglevel,
-	.set_msglevel		= bnx2x_set_msglevel,
-	.nway_reset		= bnx2x_nway_reset,
-	.get_link		= bnx2x_get_link,
-	.get_eeprom_len		= bnx2x_get_eeprom_len,
-	.get_eeprom		= bnx2x_get_eeprom,
-	.set_eeprom		= bnx2x_set_eeprom,
-	.get_coalesce		= bnx2x_get_coalesce,
-	.set_coalesce		= bnx2x_set_coalesce,
-	.get_ringparam		= bnx2x_get_ringparam,
-	.set_ringparam		= bnx2x_set_ringparam,
-	.get_pauseparam		= bnx2x_get_pauseparam,
-	.set_pauseparam		= bnx2x_set_pauseparam,
-	.get_rx_csum		= bnx2x_get_rx_csum,
-	.set_rx_csum		= bnx2x_set_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_hw_csum,
-	.set_flags		= bnx2x_set_flags,
-	.get_flags		= ethtool_op_get_flags,
-	.get_sg			= ethtool_op_get_sg,
-	.set_sg			= ethtool_op_set_sg,
-	.get_tso		= ethtool_op_get_tso,
-	.set_tso		= bnx2x_set_tso,
-	.self_test		= bnx2x_self_test,
-	.get_sset_count		= bnx2x_get_sset_count,
-	.get_strings		= bnx2x_get_strings,
-	.phys_id		= bnx2x_phys_id,
-	.get_ethtool_stats	= bnx2x_get_ethtool_stats,
-};
-
-/* end of ethtool_ops */
-
-/****************************************************************************
-* General service functions
-****************************************************************************/
-
-static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
-{
-	u16 pmcsr;
-
-	pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
-
-	switch (state) {
-	case PCI_D0:
-		pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
-				      ((pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
-				       PCI_PM_CTRL_PME_STATUS));
-
-		if (pmcsr & PCI_PM_CTRL_STATE_MASK)
-			/* delay required during transition out of D3hot */
-			msleep(20);
-		break;
-
-	case PCI_D3hot:
-		/* If there are other clients above don't
-		   shut down the power */
-		if (atomic_read(&bp->pdev->enable_cnt) != 1)
-			return 0;
-		/* Don't shut down the power for emulation and FPGA */
-		if (CHIP_REV_IS_SLOW(bp))
-			return 0;
-
-		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
-		pmcsr |= 3;
-
-		if (bp->wol)
-			pmcsr |= PCI_PM_CTRL_PME_ENABLE;
-
-		pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
-				      pmcsr);
-
-		/* No more memory access after this point until
-		* device is brought back to D0.
-		*/
-		break;
-
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static inline int bnx2x_has_rx_work(struct bnx2x_fastpath *fp)
-{
-	u16 rx_cons_sb;
-
-	/* Tell compiler that status block fields can change */
-	barrier();
-	rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb);
-	if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
-		rx_cons_sb++;
-	return (fp->rx_comp_cons != rx_cons_sb);
-}
-
-/*
- * net_device service functions
- */
-
-static int bnx2x_poll(struct napi_struct *napi, int budget)
-{
-	int work_done = 0;
-	struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath,
-						 napi);
-	struct bnx2x *bp = fp->bp;
-
-	while (1) {
-#ifdef BNX2X_STOP_ON_ERROR
-		if (unlikely(bp->panic)) {
-			napi_complete(napi);
-			return 0;
-		}
-#endif
-
-		if (bnx2x_has_tx_work(fp))
-			bnx2x_tx_int(fp);
-
-		if (bnx2x_has_rx_work(fp)) {
-			work_done += bnx2x_rx_int(fp, budget - work_done);
-
-			/* must not complete if we consumed full budget */
-			if (work_done >= budget)
-				break;
-		}
-
-		/* Fall out from the NAPI loop if needed */
-		if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
-			bnx2x_update_fpsb_idx(fp);
-		/* bnx2x_has_rx_work() reads the status block, thus we need
-		 * to ensure that status block indices have been actually read
-		 * (bnx2x_update_fpsb_idx) prior to this check
-		 * (bnx2x_has_rx_work) so that we won't write the "newer"
-		 * value of the status block to IGU (if there was a DMA right
-		 * after bnx2x_has_rx_work and if there is no rmb, the memory
-		 * reading (bnx2x_update_fpsb_idx) may be postponed to right
-		 * before bnx2x_ack_sb). In this case there will never be
-		 * another interrupt until there is another update of the
-		 * status block, while there is still unhandled work.
-		 */
-			rmb();
-
-			if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
-				napi_complete(napi);
-				/* Re-enable interrupts */
-				bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID,
-					     le16_to_cpu(fp->fp_c_idx),
-					     IGU_INT_NOP, 1);
-				bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID,
-					     le16_to_cpu(fp->fp_u_idx),
-					     IGU_INT_ENABLE, 1);
-				break;
-			}
-		}
-	}
-
-	return work_done;
-}
-
-
-/* we split the first BD into headers and data BDs
- * to ease the pain of our fellow microcode engineers
- * we use one mapping for both BDs
- * So far this has only been observed to happen
- * in Other Operating Systems(TM)
- */
-static noinline u16 bnx2x_tx_split(struct bnx2x *bp,
-				   struct bnx2x_fastpath *fp,
-				   struct sw_tx_bd *tx_buf,
-				   struct eth_tx_start_bd **tx_bd, u16 hlen,
-				   u16 bd_prod, int nbd)
-{
-	struct eth_tx_start_bd *h_tx_bd = *tx_bd;
-	struct eth_tx_bd *d_tx_bd;
-	dma_addr_t mapping;
-	int old_len = le16_to_cpu(h_tx_bd->nbytes);
-
-	/* first fix first BD */
-	h_tx_bd->nbd = cpu_to_le16(nbd);
-	h_tx_bd->nbytes = cpu_to_le16(hlen);
-
-	DP(NETIF_MSG_TX_QUEUED,	"TSO split header size is %d "
-	   "(%x:%x) nbd %d\n", h_tx_bd->nbytes, h_tx_bd->addr_hi,
-	   h_tx_bd->addr_lo, h_tx_bd->nbd);
-
-	/* now get a new data BD
-	 * (after the pbd) and fill it */
-	bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
-	d_tx_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
-
-	mapping = HILO_U64(le32_to_cpu(h_tx_bd->addr_hi),
-			   le32_to_cpu(h_tx_bd->addr_lo)) + hlen;
-
-	d_tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
-	d_tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
-	d_tx_bd->nbytes = cpu_to_le16(old_len - hlen);
-
-	/* this marks the BD as one that has no individual mapping */
-	tx_buf->flags |= BNX2X_TSO_SPLIT_BD;
-
-	DP(NETIF_MSG_TX_QUEUED,
-	   "TSO split data size is %d (%x:%x)\n",
-	   d_tx_bd->nbytes, d_tx_bd->addr_hi, d_tx_bd->addr_lo);
-
-	/* update tx_bd */
-	*tx_bd = (struct eth_tx_start_bd *)d_tx_bd;
-
-	return bd_prod;
-}
-
-static inline u16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
-{
-	if (fix > 0)
-		csum = (u16) ~csum_fold(csum_sub(csum,
-				csum_partial(t_header - fix, fix, 0)));
-
-	else if (fix < 0)
-		csum = (u16) ~csum_fold(csum_add(csum,
-				csum_partial(t_header, -fix, 0)));
-
-	return swab16(csum);
-}
-
-static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
-{
-	u32 rc;
-
-	if (skb->ip_summed != CHECKSUM_PARTIAL)
-		rc = XMIT_PLAIN;
-
-	else {
-		if (skb->protocol == htons(ETH_P_IPV6)) {
-			rc = XMIT_CSUM_V6;
-			if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
-				rc |= XMIT_CSUM_TCP;
-
-		} else {
-			rc = XMIT_CSUM_V4;
-			if (ip_hdr(skb)->protocol == IPPROTO_TCP)
-				rc |= XMIT_CSUM_TCP;
-		}
-	}
-
-	if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
-		rc |= (XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP);
-
-	else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
-		rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6);
-
-	return rc;
-}
-
-#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
-/* check if packet requires linearization (packet is too fragmented)
-   no need to check fragmentation if page size > 8K (there will be no
-   violation to FW restrictions) */
-static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb,
-			     u32 xmit_type)
-{
-	int to_copy = 0;
-	int hlen = 0;
-	int first_bd_sz = 0;
-
-	/* 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */
-	if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - 3)) {
-
-		if (xmit_type & XMIT_GSO) {
-			unsigned short lso_mss = skb_shinfo(skb)->gso_size;
-			/* Check if LSO packet needs to be copied:
-			   3 = 1 (for headers BD) + 2 (for PBD and last BD) */
-			int wnd_size = MAX_FETCH_BD - 3;
-			/* Number of windows to check */
-			int num_wnds = skb_shinfo(skb)->nr_frags - wnd_size;
-			int wnd_idx = 0;
-			int frag_idx = 0;
-			u32 wnd_sum = 0;
-
-			/* Headers length */
-			hlen = (int)(skb_transport_header(skb) - skb->data) +
-				tcp_hdrlen(skb);
-
-			/* Amount of data (w/o headers) on linear part of SKB*/
-			first_bd_sz = skb_headlen(skb) - hlen;
-
-			wnd_sum  = first_bd_sz;
-
-			/* Calculate the first sum - it's special */
-			for (frag_idx = 0; frag_idx < wnd_size - 1; frag_idx++)
-				wnd_sum +=
-					skb_shinfo(skb)->frags[frag_idx].size;
-
-			/* If there was data on linear skb data - check it */
-			if (first_bd_sz > 0) {
-				if (unlikely(wnd_sum < lso_mss)) {
-					to_copy = 1;
-					goto exit_lbl;
-				}
-
-				wnd_sum -= first_bd_sz;
-			}
-
-			/* Others are easier: run through the frag list and
-			   check all windows */
-			for (wnd_idx = 0; wnd_idx <= num_wnds; wnd_idx++) {
-				wnd_sum +=
-			  skb_shinfo(skb)->frags[wnd_idx + wnd_size - 1].size;
-
-				if (unlikely(wnd_sum < lso_mss)) {
-					to_copy = 1;
-					break;
-				}
-				wnd_sum -=
-					skb_shinfo(skb)->frags[wnd_idx].size;
-			}
-		} else {
-			/* in non-LSO too fragmented packet should always
-			   be linearized */
-			to_copy = 1;
-		}
-	}
-
-exit_lbl:
-	if (unlikely(to_copy))
-		DP(NETIF_MSG_TX_QUEUED,
-		   "Linearization IS REQUIRED for %s packet. "
-		   "num_frags %d  hlen %d  first_bd_sz %d\n",
-		   (xmit_type & XMIT_GSO) ? "LSO" : "non-LSO",
-		   skb_shinfo(skb)->nr_frags, hlen, first_bd_sz);
-
-	return to_copy;
-}
-#endif
-
-/* called with netif_tx_lock
- * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call
- * netif_wake_queue()
- */
-static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	struct bnx2x_fastpath *fp;
-	struct netdev_queue *txq;
-	struct sw_tx_bd *tx_buf;
-	struct eth_tx_start_bd *tx_start_bd;
-	struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
-	struct eth_tx_parse_bd *pbd = NULL;
-	u16 pkt_prod, bd_prod;
-	int nbd, fp_index;
-	dma_addr_t mapping;
-	u32 xmit_type = bnx2x_xmit_type(bp, skb);
-	int i;
-	u8 hlen = 0;
-	__le16 pkt_size = 0;
-	struct ethhdr *eth;
-	u8 mac_type = UNICAST_ADDRESS;
-
-#ifdef BNX2X_STOP_ON_ERROR
-	if (unlikely(bp->panic))
-		return NETDEV_TX_BUSY;
-#endif
-
-	fp_index = skb_get_queue_mapping(skb);
-	txq = netdev_get_tx_queue(dev, fp_index);
-
-	fp = &bp->fp[fp_index];
-
-	if (unlikely(bnx2x_tx_avail(fp) < (skb_shinfo(skb)->nr_frags + 3))) {
-		fp->eth_q_stats.driver_xoff++;
-		netif_tx_stop_queue(txq);
-		BNX2X_ERR("BUG! Tx ring full when queue awake!\n");
-		return NETDEV_TX_BUSY;
-	}
-
-	DP(NETIF_MSG_TX_QUEUED, "SKB: summed %x  protocol %x  protocol(%x,%x)"
-	   "  gso type %x  xmit_type %x\n",
-	   skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr,
-	   ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type);
-
-	eth = (struct ethhdr *)skb->data;
-
-	/* set flag according to packet type (UNICAST_ADDRESS is default)*/
-	if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
-		if (is_broadcast_ether_addr(eth->h_dest))
-			mac_type = BROADCAST_ADDRESS;
-		else
-			mac_type = MULTICAST_ADDRESS;
-	}
-
-#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
-	/* First, check if we need to linearize the skb (due to FW
-	   restrictions). No need to check fragmentation if page size > 8K
-	   (there will be no violation to FW restrictions) */
-	if (bnx2x_pkt_req_lin(bp, skb, xmit_type)) {
-		/* Statistics of linearization */
-		bp->lin_cnt++;
-		if (skb_linearize(skb) != 0) {
-			DP(NETIF_MSG_TX_QUEUED, "SKB linearization failed - "
-			   "silently dropping this SKB\n");
-			dev_kfree_skb_any(skb);
-			return NETDEV_TX_OK;
-		}
-	}
-#endif
-
-	/*
-	Please read carefully. First we use one BD which we mark as start,
-	then we have a parsing info BD (used for TSO or xsum),
-	and only then we have the rest of the TSO BDs.
-	(don't forget to mark the last one as last,
-	and to unmap only AFTER you write to the BD ...)
-	And above all, all pdb sizes are in words - NOT DWORDS!
-	*/
-
-	pkt_prod = fp->tx_pkt_prod++;
-	bd_prod = TX_BD(fp->tx_bd_prod);
-
-	/* get a tx_buf and first BD */
-	tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)];
-	tx_start_bd = &fp->tx_desc_ring[bd_prod].start_bd;
-
-	tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
-	tx_start_bd->general_data =  (mac_type <<
-					ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT);
-	/* header nbd */
-	tx_start_bd->general_data |= (1 << ETH_TX_START_BD_HDR_NBDS_SHIFT);
-
-	/* remember the first BD of the packet */
-	tx_buf->first_bd = fp->tx_bd_prod;
-	tx_buf->skb = skb;
-	tx_buf->flags = 0;
-
-	DP(NETIF_MSG_TX_QUEUED,
-	   "sending pkt %u @%p  next_idx %u  bd %u @%p\n",
-	   pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_start_bd);
-
-#ifdef BCM_VLAN
-	if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb) &&
-	    (bp->flags & HW_VLAN_TX_FLAG)) {
-		tx_start_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb));
-		tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG;
-	} else
-#endif
-		tx_start_bd->vlan = cpu_to_le16(pkt_prod);
-
-	/* turn on parsing and get a BD */
-	bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
-	pbd = &fp->tx_desc_ring[bd_prod].parse_bd;
-
-	memset(pbd, 0, sizeof(struct eth_tx_parse_bd));
-
-	if (xmit_type & XMIT_CSUM) {
-		hlen = (skb_network_header(skb) - skb->data) / 2;
-
-		/* for now NS flag is not used in Linux */
-		pbd->global_data =
-			(hlen | ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
-				 ETH_TX_PARSE_BD_LLC_SNAP_EN_SHIFT));
-
-		pbd->ip_hlen = (skb_transport_header(skb) -
-				skb_network_header(skb)) / 2;
-
-		hlen += pbd->ip_hlen + tcp_hdrlen(skb) / 2;
-
-		pbd->total_hlen = cpu_to_le16(hlen);
-		hlen = hlen*2;
-
-		tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_L4_CSUM;
-
-		if (xmit_type & XMIT_CSUM_V4)
-			tx_start_bd->bd_flags.as_bitfield |=
-						ETH_TX_BD_FLAGS_IP_CSUM;
-		else
-			tx_start_bd->bd_flags.as_bitfield |=
-						ETH_TX_BD_FLAGS_IPV6;
-
-		if (xmit_type & XMIT_CSUM_TCP) {
-			pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check);
-
-		} else {
-			s8 fix = SKB_CS_OFF(skb); /* signed! */
-
-			pbd->global_data |= ETH_TX_PARSE_BD_UDP_CS_FLG;
-
-			DP(NETIF_MSG_TX_QUEUED,
-			   "hlen %d  fix %d  csum before fix %x\n",
-			   le16_to_cpu(pbd->total_hlen), fix, SKB_CS(skb));
-
-			/* HW bug: fixup the CSUM */
-			pbd->tcp_pseudo_csum =
-				bnx2x_csum_fix(skb_transport_header(skb),
-					       SKB_CS(skb), fix);
-
-			DP(NETIF_MSG_TX_QUEUED, "csum after fix %x\n",
-			   pbd->tcp_pseudo_csum);
-		}
-	}
-
-	mapping = dma_map_single(&bp->pdev->dev, skb->data,
-				 skb_headlen(skb), DMA_TO_DEVICE);
-
-	tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
-	tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
-	nbd = skb_shinfo(skb)->nr_frags + 2; /* start_bd + pbd + frags */
-	tx_start_bd->nbd = cpu_to_le16(nbd);
-	tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb));
-	pkt_size = tx_start_bd->nbytes;
-
-	DP(NETIF_MSG_TX_QUEUED, "first bd @%p  addr (%x:%x)  nbd %d"
-	   "  nbytes %d  flags %x  vlan %x\n",
-	   tx_start_bd, tx_start_bd->addr_hi, tx_start_bd->addr_lo,
-	   le16_to_cpu(tx_start_bd->nbd), le16_to_cpu(tx_start_bd->nbytes),
-	   tx_start_bd->bd_flags.as_bitfield, le16_to_cpu(tx_start_bd->vlan));
-
-	if (xmit_type & XMIT_GSO) {
-
-		DP(NETIF_MSG_TX_QUEUED,
-		   "TSO packet len %d  hlen %d  total len %d  tso size %d\n",
-		   skb->len, hlen, skb_headlen(skb),
-		   skb_shinfo(skb)->gso_size);
-
-		tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO;
-
-		if (unlikely(skb_headlen(skb) > hlen))
-			bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd,
-						 hlen, bd_prod, ++nbd);
-
-		pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
-		pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq);
-		pbd->tcp_flags = pbd_tcp_flags(skb);
-
-		if (xmit_type & XMIT_GSO_V4) {
-			pbd->ip_id = swab16(ip_hdr(skb)->id);
-			pbd->tcp_pseudo_csum =
-				swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
-							  ip_hdr(skb)->daddr,
-							  0, IPPROTO_TCP, 0));
-
-		} else
-			pbd->tcp_pseudo_csum =
-				swab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-							&ipv6_hdr(skb)->daddr,
-							0, IPPROTO_TCP, 0));
-
-		pbd->global_data |= ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN;
-	}
-	tx_data_bd = (struct eth_tx_bd *)tx_start_bd;
-
-	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
-		bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
-		tx_data_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
-		if (total_pkt_bd == NULL)
-			total_pkt_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
-
-		mapping = dma_map_page(&bp->pdev->dev, frag->page,
-				       frag->page_offset,
-				       frag->size, DMA_TO_DEVICE);
-
-		tx_data_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
-		tx_data_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
-		tx_data_bd->nbytes = cpu_to_le16(frag->size);
-		le16_add_cpu(&pkt_size, frag->size);
-
-		DP(NETIF_MSG_TX_QUEUED,
-		   "frag %d  bd @%p  addr (%x:%x)  nbytes %d\n",
-		   i, tx_data_bd, tx_data_bd->addr_hi, tx_data_bd->addr_lo,
-		   le16_to_cpu(tx_data_bd->nbytes));
-	}
-
-	DP(NETIF_MSG_TX_QUEUED, "last bd @%p\n", tx_data_bd);
-
-	bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
-
-	/* now send a tx doorbell, counting the next BD
-	 * if the packet contains or ends with it
-	 */
-	if (TX_BD_POFF(bd_prod) < nbd)
-		nbd++;
-
-	if (total_pkt_bd != NULL)
-		total_pkt_bd->total_pkt_bytes = pkt_size;
-
-	if (pbd)
-		DP(NETIF_MSG_TX_QUEUED,
-		   "PBD @%p  ip_data %x  ip_hlen %u  ip_id %u  lso_mss %u"
-		   "  tcp_flags %x  xsum %x  seq %u  hlen %u\n",
-		   pbd, pbd->global_data, pbd->ip_hlen, pbd->ip_id,
-		   pbd->lso_mss, pbd->tcp_flags, pbd->tcp_pseudo_csum,
-		   pbd->tcp_send_seq, le16_to_cpu(pbd->total_hlen));
-
-	DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %d  bd %u\n", nbd, bd_prod);
-
-	/*
-	 * Make sure that the BD data is updated before updating the producer
-	 * since FW might read the BD right after the producer is updated.
-	 * This is only applicable for weak-ordered memory model archs such
-	 * as IA-64. The following barrier is also mandatory since FW will
-	 * assumes packets must have BDs.
-	 */
-	wmb();
-
-	fp->tx_db.data.prod += nbd;
-	barrier();
-	DOORBELL(bp, fp->index, fp->tx_db.raw);
-
-	mmiowb();
-
-	fp->tx_bd_prod += nbd;
-
-	if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) {
-		netif_tx_stop_queue(txq);
-
-		/* paired memory barrier is in bnx2x_tx_int(), we have to keep
-		 * ordering of set_bit() in netif_tx_stop_queue() and read of
-		 * fp->bd_tx_cons */
-		smp_mb();
-
-		fp->eth_q_stats.driver_xoff++;
-		if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)
-			netif_tx_wake_queue(txq);
-	}
-	fp->tx_pkt++;
-
-	return NETDEV_TX_OK;
-}
-
-/* called with rtnl_lock */
-static int bnx2x_open(struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	netif_carrier_off(dev);
-
-	bnx2x_set_power_state(bp, PCI_D0);
-
-	if (!bnx2x_reset_is_done(bp)) {
-		do {
-			/* Reset MCP mail box sequence if there is on going
-			 * recovery
-			 */
-			bp->fw_seq = 0;
-
-			/* If it's the first function to load and reset done
-			 * is still not cleared it may mean that. We don't
-			 * check the attention state here because it may have
-			 * already been cleared by a "common" reset but we
-			 * shell proceed with "process kill" anyway.
-			 */
-			if ((bnx2x_get_load_cnt(bp) == 0) &&
-				bnx2x_trylock_hw_lock(bp,
-				HW_LOCK_RESOURCE_RESERVED_08) &&
-				(!bnx2x_leader_reset(bp))) {
-				DP(NETIF_MSG_HW, "Recovered in open\n");
-				break;
-			}
-
-			bnx2x_set_power_state(bp, PCI_D3hot);
-
-			printk(KERN_ERR"%s: Recovery flow hasn't been properly"
-			" completed yet. Try again later. If u still see this"
-			" message after a few retries then power cycle is"
-			" required.\n", bp->dev->name);
-
-			return -EAGAIN;
-		} while (0);
-	}
-
-	bp->recovery_state = BNX2X_RECOVERY_DONE;
-
-	return bnx2x_nic_load(bp, LOAD_OPEN);
-}
-
-/* called with rtnl_lock */
-static int bnx2x_close(struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	/* Unload the driver, release IRQs */
-	bnx2x_nic_unload(bp, UNLOAD_CLOSE);
-	bnx2x_set_power_state(bp, PCI_D3hot);
-
-	return 0;
-}
-
-/* called with netif_tx_lock from dev_mcast.c */
-static void bnx2x_set_rx_mode(struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	u32 rx_mode = BNX2X_RX_MODE_NORMAL;
-	int port = BP_PORT(bp);
-
-	if (bp->state != BNX2X_STATE_OPEN) {
-		DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state);
-		return;
-	}
-
-	DP(NETIF_MSG_IFUP, "dev->flags = %x\n", dev->flags);
-
-	if (dev->flags & IFF_PROMISC)
-		rx_mode = BNX2X_RX_MODE_PROMISC;
-
-	else if ((dev->flags & IFF_ALLMULTI) ||
-		 ((netdev_mc_count(dev) > BNX2X_MAX_MULTICAST) &&
-		  CHIP_IS_E1(bp)))
-		rx_mode = BNX2X_RX_MODE_ALLMULTI;
-
-	else { /* some multicasts */
-		if (CHIP_IS_E1(bp)) {
-			int i, old, offset;
-			struct netdev_hw_addr *ha;
-			struct mac_configuration_cmd *config =
-						bnx2x_sp(bp, mcast_config);
-
-			i = 0;
-			netdev_for_each_mc_addr(ha, dev) {
-				config->config_table[i].
-					cam_entry.msb_mac_addr =
-					swab16(*(u16 *)&ha->addr[0]);
-				config->config_table[i].
-					cam_entry.middle_mac_addr =
-					swab16(*(u16 *)&ha->addr[2]);
-				config->config_table[i].
-					cam_entry.lsb_mac_addr =
-					swab16(*(u16 *)&ha->addr[4]);
-				config->config_table[i].cam_entry.flags =
-							cpu_to_le16(port);
-				config->config_table[i].
-					target_table_entry.flags = 0;
-				config->config_table[i].target_table_entry.
-					clients_bit_vector =
-						cpu_to_le32(1 << BP_L_ID(bp));
-				config->config_table[i].
-					target_table_entry.vlan_id = 0;
-
-				DP(NETIF_MSG_IFUP,
-				   "setting MCAST[%d] (%04x:%04x:%04x)\n", i,
-				   config->config_table[i].
-						cam_entry.msb_mac_addr,
-				   config->config_table[i].
-						cam_entry.middle_mac_addr,
-				   config->config_table[i].
-						cam_entry.lsb_mac_addr);
-				i++;
-			}
-			old = config->hdr.length;
-			if (old > i) {
-				for (; i < old; i++) {
-					if (CAM_IS_INVALID(config->
-							   config_table[i])) {
-						/* already invalidated */
-						break;
-					}
-					/* invalidate */
-					CAM_INVALIDATE(config->
-						       config_table[i]);
-				}
-			}
-
-			if (CHIP_REV_IS_SLOW(bp))
-				offset = BNX2X_MAX_EMUL_MULTI*(1 + port);
-			else
-				offset = BNX2X_MAX_MULTICAST*(1 + port);
-
-			config->hdr.length = i;
-			config->hdr.offset = offset;
-			config->hdr.client_id = bp->fp->cl_id;
-			config->hdr.reserved1 = 0;
-
-			bp->set_mac_pending++;
-			smp_wmb();
-
-			bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
-				   U64_HI(bnx2x_sp_mapping(bp, mcast_config)),
-				   U64_LO(bnx2x_sp_mapping(bp, mcast_config)),
-				      0);
-		} else { /* E1H */
-			/* Accept one or more multicasts */
-			struct netdev_hw_addr *ha;
-			u32 mc_filter[MC_HASH_SIZE];
-			u32 crc, bit, regidx;
-			int i;
-
-			memset(mc_filter, 0, 4 * MC_HASH_SIZE);
-
-			netdev_for_each_mc_addr(ha, dev) {
-				DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n",
-				   ha->addr);
-
-				crc = crc32c_le(0, ha->addr, ETH_ALEN);
-				bit = (crc >> 24) & 0xff;
-				regidx = bit >> 5;
-				bit &= 0x1f;
-				mc_filter[regidx] |= (1 << bit);
-			}
-
-			for (i = 0; i < MC_HASH_SIZE; i++)
-				REG_WR(bp, MC_HASH_OFFSET(bp, i),
-				       mc_filter[i]);
-		}
-	}
-
-	bp->rx_mode = rx_mode;
-	bnx2x_set_storm_rx_mode(bp);
-}
-
-/* called with rtnl_lock */
-static int bnx2x_change_mac_addr(struct net_device *dev, void *p)
-{
-	struct sockaddr *addr = p;
-	struct bnx2x *bp = netdev_priv(dev);
-
-	if (!is_valid_ether_addr((u8 *)(addr->sa_data)))
-		return -EINVAL;
-
-	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-	if (netif_running(dev)) {
-		if (CHIP_IS_E1(bp))
-			bnx2x_set_eth_mac_addr_e1(bp, 1);
-		else
-			bnx2x_set_eth_mac_addr_e1h(bp, 1);
-	}
-
-	return 0;
-}
-
-/* called with rtnl_lock */
-static int bnx2x_mdio_read(struct net_device *netdev, int prtad,
-			   int devad, u16 addr)
-{
-	struct bnx2x *bp = netdev_priv(netdev);
-	u16 value;
-	int rc;
-	u32 phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
-
-	DP(NETIF_MSG_LINK, "mdio_read: prtad 0x%x, devad 0x%x, addr 0x%x\n",
-	   prtad, devad, addr);
-
-	if (prtad != bp->mdio.prtad) {
-		DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n",
-		   prtad, bp->mdio.prtad);
-		return -EINVAL;
-	}
-
-	/* The HW expects different devad if CL22 is used */
-	devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad;
-
-	bnx2x_acquire_phy_lock(bp);
-	rc = bnx2x_cl45_read(bp, BP_PORT(bp), phy_type, prtad,
-			     devad, addr, &value);
-	bnx2x_release_phy_lock(bp);
-	DP(NETIF_MSG_LINK, "mdio_read_val 0x%x rc = 0x%x\n", value, rc);
-
-	if (!rc)
-		rc = value;
-	return rc;
-}
-
-/* called with rtnl_lock */
-static int bnx2x_mdio_write(struct net_device *netdev, int prtad, int devad,
-			    u16 addr, u16 value)
-{
-	struct bnx2x *bp = netdev_priv(netdev);
-	u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
-	int rc;
-
-	DP(NETIF_MSG_LINK, "mdio_write: prtad 0x%x, devad 0x%x, addr 0x%x,"
-			   " value 0x%x\n", prtad, devad, addr, value);
-
-	if (prtad != bp->mdio.prtad) {
-		DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n",
-		   prtad, bp->mdio.prtad);
-		return -EINVAL;
-	}
-
-	/* The HW expects different devad if CL22 is used */
-	devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad;
-
-	bnx2x_acquire_phy_lock(bp);
-	rc = bnx2x_cl45_write(bp, BP_PORT(bp), ext_phy_type, prtad,
-			      devad, addr, value);
-	bnx2x_release_phy_lock(bp);
-	return rc;
-}
-
-/* called with rtnl_lock */
-static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	struct mii_ioctl_data *mdio = if_mii(ifr);
-
-	DP(NETIF_MSG_LINK, "ioctl: phy id 0x%x, reg 0x%x, val_in 0x%x\n",
-	   mdio->phy_id, mdio->reg_num, mdio->val_in);
-
-	if (!netif_running(dev))
-		return -EAGAIN;
-
-	return mdio_mii_ioctl(&bp->mdio, mdio, cmd);
-}
-
-/* called with rtnl_lock */
-static int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	int rc = 0;
-
-	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
-		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
-		return -EAGAIN;
-	}
-
-	if ((new_mtu > ETH_MAX_JUMBO_PACKET_SIZE) ||
-	    ((new_mtu + ETH_HLEN) < ETH_MIN_PACKET_SIZE))
-		return -EINVAL;
-
-	/* This does not race with packet allocation
-	 * because the actual alloc size is
-	 * only updated as part of load
-	 */
-	dev->mtu = new_mtu;
-
-	if (netif_running(dev)) {
-		bnx2x_nic_unload(bp, UNLOAD_NORMAL);
-		rc = bnx2x_nic_load(bp, LOAD_NORMAL);
-	}
-
-	return rc;
-}
-
-static void bnx2x_tx_timeout(struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-#ifdef BNX2X_STOP_ON_ERROR
-	if (!bp->panic)
-		bnx2x_panic();
-#endif
-	/* This allows the netif to be shutdown gracefully before resetting */
-	schedule_delayed_work(&bp->reset_task, 0);
-}
-
-#ifdef BCM_VLAN
-/* called with rtnl_lock */
-static void bnx2x_vlan_rx_register(struct net_device *dev,
-				   struct vlan_group *vlgrp)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	bp->vlgrp = vlgrp;
-
-	/* Set flags according to the required capabilities */
-	bp->flags &= ~(HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
-
-	if (dev->features & NETIF_F_HW_VLAN_TX)
-		bp->flags |= HW_VLAN_TX_FLAG;
-
-	if (dev->features & NETIF_F_HW_VLAN_RX)
-		bp->flags |= HW_VLAN_RX_FLAG;
-
-	if (netif_running(dev))
-		bnx2x_set_client_config(bp);
-}
-
-#endif
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void poll_bnx2x(struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-
-	disable_irq(bp->pdev->irq);
-	bnx2x_interrupt(bp->pdev->irq, dev);
-	enable_irq(bp->pdev->irq);
-}
-#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
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller	= poll_bnx2x,
-#endif
-};
-
-static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
-				    struct net_device *dev)
-{
-	struct bnx2x *bp;
-	int rc;
-
-	SET_NETDEV_DEV(dev, &pdev->dev);
-	bp = netdev_priv(dev);
-
-	bp->dev = dev;
-	bp->pdev = pdev;
-	bp->flags = 0;
-	bp->func = PCI_FUNC(pdev->devfn);
-
-	rc = pci_enable_device(pdev);
-	if (rc) {
-		dev_err(&bp->pdev->dev,
-			"Cannot enable PCI device, aborting\n");
-		goto err_out;
-	}
-
-	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-		dev_err(&bp->pdev->dev,
-			"Cannot find PCI device base address, aborting\n");
-		rc = -ENODEV;
-		goto err_out_disable;
-	}
-
-	if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
-		dev_err(&bp->pdev->dev, "Cannot find second PCI device"
-		       " base address, aborting\n");
-		rc = -ENODEV;
-		goto err_out_disable;
-	}
-
-	if (atomic_read(&pdev->enable_cnt) == 1) {
-		rc = pci_request_regions(pdev, DRV_MODULE_NAME);
-		if (rc) {
-			dev_err(&bp->pdev->dev,
-				"Cannot obtain PCI resources, aborting\n");
-			goto err_out_disable;
-		}
-
-		pci_set_master(pdev);
-		pci_save_state(pdev);
-	}
-
-	bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
-	if (bp->pm_cap == 0) {
-		dev_err(&bp->pdev->dev,
-			"Cannot find power management capability, aborting\n");
-		rc = -EIO;
-		goto err_out_release;
-	}
-
-	bp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
-	if (bp->pcie_cap == 0) {
-		dev_err(&bp->pdev->dev,
-			"Cannot find PCI Express capability, aborting\n");
-		rc = -EIO;
-		goto err_out_release;
-	}
-
-	if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) == 0) {
-		bp->flags |= USING_DAC_FLAG;
-		if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)) != 0) {
-			dev_err(&bp->pdev->dev, "dma_set_coherent_mask"
-			       " failed, aborting\n");
-			rc = -EIO;
-			goto err_out_release;
-		}
-
-	} else if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
-		dev_err(&bp->pdev->dev,
-			"System does not support DMA, aborting\n");
-		rc = -EIO;
-		goto err_out_release;
-	}
-
-	dev->mem_start = pci_resource_start(pdev, 0);
-	dev->base_addr = dev->mem_start;
-	dev->mem_end = pci_resource_end(pdev, 0);
-
-	dev->irq = pdev->irq;
-
-	bp->regview = pci_ioremap_bar(pdev, 0);
-	if (!bp->regview) {
-		dev_err(&bp->pdev->dev,
-			"Cannot map register space, aborting\n");
-		rc = -ENOMEM;
-		goto err_out_release;
-	}
-
-	bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
-					min_t(u64, BNX2X_DB_SIZE,
-					      pci_resource_len(pdev, 2)));
-	if (!bp->doorbells) {
-		dev_err(&bp->pdev->dev,
-			"Cannot map doorbell space, aborting\n");
-		rc = -ENOMEM;
-		goto err_out_unmap;
-	}
-
-	bnx2x_set_power_state(bp, PCI_D0);
-
-	/* clean indirect addresses */
-	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
-			       PCICFG_VENDOR_ID_OFFSET);
-	REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0 + BP_PORT(bp)*16, 0);
-	REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0 + BP_PORT(bp)*16, 0);
-	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);
-
-	/* Reset the load counter */
-	bnx2x_clear_load_cnt(bp);
-
-	dev->watchdog_timeo = TX_TIMEOUT;
-
-	dev->netdev_ops = &bnx2x_netdev_ops;
-	dev->ethtool_ops = &bnx2x_ethtool_ops;
-	dev->features |= NETIF_F_SG;
-	dev->features |= NETIF_F_HW_CSUM;
-	if (bp->flags & USING_DAC_FLAG)
-		dev->features |= NETIF_F_HIGHDMA;
-	dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
-	dev->features |= NETIF_F_TSO6;
-#ifdef BCM_VLAN
-	dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
-	bp->flags |= (HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
-
-	dev->vlan_features |= NETIF_F_SG;
-	dev->vlan_features |= NETIF_F_HW_CSUM;
-	if (bp->flags & USING_DAC_FLAG)
-		dev->vlan_features |= NETIF_F_HIGHDMA;
-	dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
-	dev->vlan_features |= NETIF_F_TSO6;
-#endif
-
-	/* get_port_hwinfo() will set prtad and mmds properly */
-	bp->mdio.prtad = MDIO_PRTAD_NONE;
-	bp->mdio.mmds = 0;
-	bp->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
-	bp->mdio.dev = dev;
-	bp->mdio.mdio_read = bnx2x_mdio_read;
-	bp->mdio.mdio_write = bnx2x_mdio_write;
-
-	return 0;
-
-err_out_unmap:
-	if (bp->regview) {
-		iounmap(bp->regview);
-		bp->regview = NULL;
-	}
-	if (bp->doorbells) {
-		iounmap(bp->doorbells);
-		bp->doorbells = NULL;
-	}
-
-err_out_release:
-	if (atomic_read(&pdev->enable_cnt) == 1)
-		pci_release_regions(pdev);
-
-err_out_disable:
-	pci_disable_device(pdev);
-	pci_set_drvdata(pdev, NULL);
-
-err_out:
-	return rc;
-}
-
-static void __devinit bnx2x_get_pcie_width_speed(struct bnx2x *bp,
-						 int *width, int *speed)
-{
-	u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL);
-
-	*width = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT;
-
-	/* return value of 1=2.5GHz 2=5GHz */
-	*speed = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT;
-}
-
-static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
-{
-	const struct firmware *firmware = bp->firmware;
-	struct bnx2x_fw_file_hdr *fw_hdr;
-	struct bnx2x_fw_file_section *sections;
-	u32 offset, len, num_ops;
-	u16 *ops_offsets;
-	int i;
-	const u8 *fw_ver;
-
-	if (firmware->size < sizeof(struct bnx2x_fw_file_hdr))
-		return -EINVAL;
-
-	fw_hdr = (struct bnx2x_fw_file_hdr *)firmware->data;
-	sections = (struct bnx2x_fw_file_section *)fw_hdr;
-
-	/* Make sure none of the offsets and sizes make us read beyond
-	 * the end of the firmware data */
-	for (i = 0; i < sizeof(*fw_hdr) / sizeof(*sections); i++) {
-		offset = be32_to_cpu(sections[i].offset);
-		len = be32_to_cpu(sections[i].len);
-		if (offset + len > firmware->size) {
-			dev_err(&bp->pdev->dev,
-				"Section %d length is out of bounds\n", i);
-			return -EINVAL;
-		}
-	}
-
-	/* Likewise for the init_ops offsets */
-	offset = be32_to_cpu(fw_hdr->init_ops_offsets.offset);
-	ops_offsets = (u16 *)(firmware->data + offset);
-	num_ops = be32_to_cpu(fw_hdr->init_ops.len) / sizeof(struct raw_op);
-
-	for (i = 0; i < be32_to_cpu(fw_hdr->init_ops_offsets.len) / 2; i++) {
-		if (be16_to_cpu(ops_offsets[i]) > num_ops) {
-			dev_err(&bp->pdev->dev,
-				"Section offset %d is out of bounds\n", i);
-			return -EINVAL;
-		}
-	}
-
-	/* Check FW version */
-	offset = be32_to_cpu(fw_hdr->fw_version.offset);
-	fw_ver = firmware->data + offset;
-	if ((fw_ver[0] != BCM_5710_FW_MAJOR_VERSION) ||
-	    (fw_ver[1] != BCM_5710_FW_MINOR_VERSION) ||
-	    (fw_ver[2] != BCM_5710_FW_REVISION_VERSION) ||
-	    (fw_ver[3] != BCM_5710_FW_ENGINEERING_VERSION)) {
-		dev_err(&bp->pdev->dev,
-			"Bad FW version:%d.%d.%d.%d. Should be %d.%d.%d.%d\n",
-		       fw_ver[0], fw_ver[1], fw_ver[2],
-		       fw_ver[3], BCM_5710_FW_MAJOR_VERSION,
-		       BCM_5710_FW_MINOR_VERSION,
-		       BCM_5710_FW_REVISION_VERSION,
-		       BCM_5710_FW_ENGINEERING_VERSION);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static inline void be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n)
-{
-	const __be32 *source = (const __be32 *)_source;
-	u32 *target = (u32 *)_target;
-	u32 i;
-
-	for (i = 0; i < n/4; i++)
-		target[i] = be32_to_cpu(source[i]);
-}
-
-/*
-   Ops array is stored in the following format:
-   {op(8bit), offset(24bit, big endian), data(32bit, big endian)}
- */
-static inline void bnx2x_prep_ops(const u8 *_source, u8 *_target, u32 n)
-{
-	const __be32 *source = (const __be32 *)_source;
-	struct raw_op *target = (struct raw_op *)_target;
-	u32 i, j, tmp;
-
-	for (i = 0, j = 0; i < n/8; i++, j += 2) {
-		tmp = be32_to_cpu(source[j]);
-		target[i].op = (tmp >> 24) & 0xff;
-		target[i].offset = tmp & 0xffffff;
-		target[i].raw_data = be32_to_cpu(source[j + 1]);
-	}
-}
-
-static inline void be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n)
-{
-	const __be16 *source = (const __be16 *)_source;
-	u16 *target = (u16 *)_target;
-	u32 i;
-
-	for (i = 0; i < n/2; i++)
-		target[i] = be16_to_cpu(source[i]);
-}
-
-#define BNX2X_ALLOC_AND_SET(arr, lbl, func)				\
-do {									\
-	u32 len = be32_to_cpu(fw_hdr->arr.len);				\
-	bp->arr = kmalloc(len, GFP_KERNEL);				\
-	if (!bp->arr) {							\
-		pr_err("Failed to allocate %d bytes for "#arr"\n", len); \
-		goto lbl;						\
-	}								\
-	func(bp->firmware->data + be32_to_cpu(fw_hdr->arr.offset),	\
-	     (u8 *)bp->arr, len);					\
-} while (0)
-
-static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev)
-{
-	const char *fw_file_name;
-	struct bnx2x_fw_file_hdr *fw_hdr;
-	int rc;
-
-	if (CHIP_IS_E1(bp))
-		fw_file_name = FW_FILE_NAME_E1;
-	else if (CHIP_IS_E1H(bp))
-		fw_file_name = FW_FILE_NAME_E1H;
-	else {
-		dev_err(dev, "Unsupported chip revision\n");
-		return -EINVAL;
-	}
-
-	dev_info(dev, "Loading %s\n", fw_file_name);
-
-	rc = request_firmware(&bp->firmware, fw_file_name, dev);
-	if (rc) {
-		dev_err(dev, "Can't load firmware file %s\n", fw_file_name);
-		goto request_firmware_exit;
-	}
-
-	rc = bnx2x_check_firmware(bp);
-	if (rc) {
-		dev_err(dev, "Corrupt firmware file %s\n", fw_file_name);
-		goto request_firmware_exit;
-	}
-
-	fw_hdr = (struct bnx2x_fw_file_hdr *)bp->firmware->data;
-
-	/* Initialize the pointers to the init arrays */
-	/* Blob */
-	BNX2X_ALLOC_AND_SET(init_data, request_firmware_exit, be32_to_cpu_n);
-
-	/* Opcodes */
-	BNX2X_ALLOC_AND_SET(init_ops, init_ops_alloc_err, bnx2x_prep_ops);
-
-	/* Offsets */
-	BNX2X_ALLOC_AND_SET(init_ops_offsets, init_offsets_alloc_err,
-			    be16_to_cpu_n);
-
-	/* STORMs firmware */
-	INIT_TSEM_INT_TABLE_DATA(bp) = bp->firmware->data +
-			be32_to_cpu(fw_hdr->tsem_int_table_data.offset);
-	INIT_TSEM_PRAM_DATA(bp)      = bp->firmware->data +
-			be32_to_cpu(fw_hdr->tsem_pram_data.offset);
-	INIT_USEM_INT_TABLE_DATA(bp) = bp->firmware->data +
-			be32_to_cpu(fw_hdr->usem_int_table_data.offset);
-	INIT_USEM_PRAM_DATA(bp)      = bp->firmware->data +
-			be32_to_cpu(fw_hdr->usem_pram_data.offset);
-	INIT_XSEM_INT_TABLE_DATA(bp) = bp->firmware->data +
-			be32_to_cpu(fw_hdr->xsem_int_table_data.offset);
-	INIT_XSEM_PRAM_DATA(bp)      = bp->firmware->data +
-			be32_to_cpu(fw_hdr->xsem_pram_data.offset);
-	INIT_CSEM_INT_TABLE_DATA(bp) = bp->firmware->data +
-			be32_to_cpu(fw_hdr->csem_int_table_data.offset);
-	INIT_CSEM_PRAM_DATA(bp)      = bp->firmware->data +
-			be32_to_cpu(fw_hdr->csem_pram_data.offset);
-
-	return 0;
-
-init_offsets_alloc_err:
-	kfree(bp->init_ops);
-init_ops_alloc_err:
-	kfree(bp->init_data);
-request_firmware_exit:
-	release_firmware(bp->firmware);
-
-	return rc;
-}
-
-
-static int __devinit bnx2x_init_one(struct pci_dev *pdev,
-				    const struct pci_device_id *ent)
-{
-	struct net_device *dev = NULL;
-	struct bnx2x *bp;
-	int pcie_width, pcie_speed;
-	int rc;
-
-	/* dev zeroed in init_etherdev */
-	dev = alloc_etherdev_mq(sizeof(*bp), MAX_CONTEXT);
-	if (!dev) {
-		dev_err(&pdev->dev, "Cannot allocate net device\n");
-		return -ENOMEM;
-	}
-
-	bp = netdev_priv(dev);
-	bp->msg_enable = debug;
-
-	pci_set_drvdata(pdev, dev);
-
-	rc = bnx2x_init_dev(pdev, dev);
-	if (rc < 0) {
-		free_netdev(dev);
-		return rc;
-	}
-
-	rc = bnx2x_init_bp(bp);
-	if (rc)
-		goto init_one_exit;
-
-	/* Set init arrays */
-	rc = bnx2x_init_firmware(bp, &pdev->dev);
-	if (rc) {
-		dev_err(&pdev->dev, "Error loading firmware\n");
-		goto init_one_exit;
-	}
-
-	rc = register_netdev(dev);
-	if (rc) {
-		dev_err(&pdev->dev, "Cannot register net device\n");
-		goto init_one_exit;
-	}
-
-	bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed);
-	netdev_info(dev, "%s (%c%d) PCI-E x%d %s found at mem %lx,"
-	       " IRQ %d, ", board_info[ent->driver_data].name,
-	       (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4),
-	       pcie_width, (pcie_speed == 2) ? "5GHz (Gen2)" : "2.5GHz",
-	       dev->base_addr, bp->pdev->irq);
-	pr_cont("node addr %pM\n", dev->dev_addr);
-
-	return 0;
-
-init_one_exit:
-	if (bp->regview)
-		iounmap(bp->regview);
-
-	if (bp->doorbells)
-		iounmap(bp->doorbells);
-
-	free_netdev(dev);
-
-	if (atomic_read(&pdev->enable_cnt) == 1)
-		pci_release_regions(pdev);
-
-	pci_disable_device(pdev);
-	pci_set_drvdata(pdev, NULL);
-
-	return rc;
-}
-
-static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct bnx2x *bp;
-
-	if (!dev) {
-		dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
-		return;
-	}
-	bp = netdev_priv(dev);
-
-	unregister_netdev(dev);
-
-	/* Make sure RESET task is not scheduled before continuing */
-	cancel_delayed_work_sync(&bp->reset_task);
-
-	kfree(bp->init_ops_offsets);
-	kfree(bp->init_ops);
-	kfree(bp->init_data);
-	release_firmware(bp->firmware);
-
-	if (bp->regview)
-		iounmap(bp->regview);
-
-	if (bp->doorbells)
-		iounmap(bp->doorbells);
-
-	free_netdev(dev);
-
-	if (atomic_read(&pdev->enable_cnt) == 1)
-		pci_release_regions(pdev);
-
-	pci_disable_device(pdev);
-	pci_set_drvdata(pdev, NULL);
-}
-
-static int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct bnx2x *bp;
-
-	if (!dev) {
-		dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
-		return -ENODEV;
-	}
-	bp = netdev_priv(dev);
-
-	rtnl_lock();
-
-	pci_save_state(pdev);
-
-	if (!netif_running(dev)) {
-		rtnl_unlock();
-		return 0;
-	}
-
-	netif_device_detach(dev);
-
-	bnx2x_nic_unload(bp, UNLOAD_CLOSE);
-
-	bnx2x_set_power_state(bp, pci_choose_state(pdev, state));
-
-	rtnl_unlock();
-
-	return 0;
-}
-
-static int bnx2x_resume(struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct bnx2x *bp;
-	int rc;
-
-	if (!dev) {
-		dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
-		return -ENODEV;
-	}
-	bp = netdev_priv(dev);
-
-	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
-		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
-		return -EAGAIN;
-	}
-
-	rtnl_lock();
-
-	pci_restore_state(pdev);
-
-	if (!netif_running(dev)) {
-		rtnl_unlock();
-		return 0;
-	}
-
-	bnx2x_set_power_state(bp, PCI_D0);
-	netif_device_attach(dev);
-
-	rc = bnx2x_nic_load(bp, LOAD_OPEN);
-
-	rtnl_unlock();
-
-	return rc;
-}
-
-static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
-{
-	int i;
-
-	bp->state = BNX2X_STATE_ERROR;
-
-	bp->rx_mode = BNX2X_RX_MODE_NONE;
-
-	bnx2x_netif_stop(bp, 0);
-	netif_carrier_off(bp->dev);
-
-	del_timer_sync(&bp->timer);
-	bp->stats_state = STATS_STATE_DISABLED;
-	DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");
-
-	/* Release IRQs */
-	bnx2x_free_irq(bp, false);
-
-	if (CHIP_IS_E1(bp)) {
-		struct mac_configuration_cmd *config =
-						bnx2x_sp(bp, mcast_config);
-
-		for (i = 0; i < config->hdr.length; i++)
-			CAM_INVALIDATE(config->config_table[i]);
-	}
-
-	/* Free SKBs, SGEs, TPA pool and driver internals */
-	bnx2x_free_skbs(bp);
-	for_each_queue(bp, i)
-		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
-	for_each_queue(bp, i)
-		netif_napi_del(&bnx2x_fp(bp, i, napi));
-	bnx2x_free_mem(bp);
-
-	bp->state = BNX2X_STATE_CLOSED;
-
-	return 0;
-}
-
-static void bnx2x_eeh_recover(struct bnx2x *bp)
-{
-	u32 val;
-
-	mutex_init(&bp->port.phy_mutex);
-
-	bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
-	bp->link_params.shmem_base = bp->common.shmem_base;
-	BNX2X_DEV_INFO("shmem offset is 0x%x\n", bp->common.shmem_base);
-
-	if (!bp->common.shmem_base ||
-	    (bp->common.shmem_base < 0xA0000) ||
-	    (bp->common.shmem_base >= 0xC0000)) {
-		BNX2X_DEV_INFO("MCP not active\n");
-		bp->flags |= NO_MCP_FLAG;
-		return;
-	}
-
-	val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]);
-	if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
-		!= (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
-		BNX2X_ERR("BAD MCP validity signature\n");
-
-	if (!BP_NOMCP(bp)) {
-		bp->fw_seq = (SHMEM_RD(bp, func_mb[BP_FUNC(bp)].drv_mb_header)
-			      & DRV_MSG_SEQ_NUMBER_MASK);
-		BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
-	}
-}
-
-/**
- * bnx2x_io_error_detected - called when PCI error is detected
- * @pdev: Pointer to PCI device
- * @state: The current pci connection state
- *
- * This function is called after a PCI bus error affecting
- * this device has been detected.
- */
-static pci_ers_result_t bnx2x_io_error_detected(struct pci_dev *pdev,
-						pci_channel_state_t state)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct bnx2x *bp = netdev_priv(dev);
-
-	rtnl_lock();
-
-	netif_device_detach(dev);
-
-	if (state == pci_channel_io_perm_failure) {
-		rtnl_unlock();
-		return PCI_ERS_RESULT_DISCONNECT;
-	}
-
-	if (netif_running(dev))
-		bnx2x_eeh_nic_unload(bp);
-
-	pci_disable_device(pdev);
-
-	rtnl_unlock();
-
-	/* Request a slot reset */
-	return PCI_ERS_RESULT_NEED_RESET;
-}
-
-/**
- * bnx2x_io_slot_reset - called after the PCI bus has been reset
- * @pdev: Pointer to PCI device
- *
- * Restart the card from scratch, as if from a cold-boot.
- */
-static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct bnx2x *bp = netdev_priv(dev);
-
-	rtnl_lock();
-
-	if (pci_enable_device(pdev)) {
-		dev_err(&pdev->dev,
-			"Cannot re-enable PCI device after reset\n");
-		rtnl_unlock();
-		return PCI_ERS_RESULT_DISCONNECT;
-	}
-
-	pci_set_master(pdev);
-	pci_restore_state(pdev);
-
-	if (netif_running(dev))
-		bnx2x_set_power_state(bp, PCI_D0);
-
-	rtnl_unlock();
-
-	return PCI_ERS_RESULT_RECOVERED;
-}
-
-/**
- * bnx2x_io_resume - called when traffic can start flowing again
- * @pdev: Pointer to PCI device
- *
- * This callback is called when the error recovery driver tells us that
- * its OK to resume normal operation.
- */
-static void bnx2x_io_resume(struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct bnx2x *bp = netdev_priv(dev);
-
-	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
-		printk(KERN_ERR "Handling parity error recovery. Try again later\n");
-		return;
-	}
-
-	rtnl_lock();
-
-	bnx2x_eeh_recover(bp);
-
-	if (netif_running(dev))
-		bnx2x_nic_load(bp, LOAD_NORMAL);
-
-	netif_device_attach(dev);
-
-	rtnl_unlock();
-}
-
-static struct pci_error_handlers bnx2x_err_handler = {
-	.error_detected = bnx2x_io_error_detected,
-	.slot_reset     = bnx2x_io_slot_reset,
-	.resume         = bnx2x_io_resume,
-};
-
-static struct pci_driver bnx2x_pci_driver = {
-	.name        = DRV_MODULE_NAME,
-	.id_table    = bnx2x_pci_tbl,
-	.probe       = bnx2x_init_one,
-	.remove      = __devexit_p(bnx2x_remove_one),
-	.suspend     = bnx2x_suspend,
-	.resume      = bnx2x_resume,
-	.err_handler = &bnx2x_err_handler,
-};
-
-static int __init bnx2x_init(void)
-{
-	int ret;
-
-	pr_info("%s", version);
-
-	bnx2x_wq = create_singlethread_workqueue("bnx2x");
-	if (bnx2x_wq == NULL) {
-		pr_err("Cannot create workqueue\n");
-		return -ENOMEM;
-	}
-
-	ret = pci_register_driver(&bnx2x_pci_driver);
-	if (ret) {
-		pr_err("Cannot register driver\n");
-		destroy_workqueue(bnx2x_wq);
-	}
-	return ret;
-}
-
-static void __exit bnx2x_cleanup(void)
-{
-	pci_unregister_driver(&bnx2x_pci_driver);
-
-	destroy_workqueue(bnx2x_wq);
-}
-
-module_init(bnx2x_init);
-module_exit(bnx2x_cleanup);
-
-#ifdef BCM_CNIC
-
-/* count denotes the number of new completions we have seen */
-static void bnx2x_cnic_sp_post(struct bnx2x *bp, int count)
-{
-	struct eth_spe *spe;
-
-#ifdef BNX2X_STOP_ON_ERROR
-	if (unlikely(bp->panic))
-		return;
-#endif
-
-	spin_lock_bh(&bp->spq_lock);
-	bp->cnic_spq_pending -= count;
-
-	for (; bp->cnic_spq_pending < bp->cnic_eth_dev.max_kwqe_pending;
-	     bp->cnic_spq_pending++) {
-
-		if (!bp->cnic_kwq_pending)
-			break;
-
-		spe = bnx2x_sp_get_next(bp);
-		*spe = *bp->cnic_kwq_cons;
-
-		bp->cnic_kwq_pending--;
-
-		DP(NETIF_MSG_TIMER, "pending on SPQ %d, on KWQ %d count %d\n",
-		   bp->cnic_spq_pending, bp->cnic_kwq_pending, count);
-
-		if (bp->cnic_kwq_cons == bp->cnic_kwq_last)
-			bp->cnic_kwq_cons = bp->cnic_kwq;
-		else
-			bp->cnic_kwq_cons++;
-	}
-	bnx2x_sp_prod_update(bp);
-	spin_unlock_bh(&bp->spq_lock);
-}
-
-static int bnx2x_cnic_sp_queue(struct net_device *dev,
-			       struct kwqe_16 *kwqes[], u32 count)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	int i;
-
-#ifdef BNX2X_STOP_ON_ERROR
-	if (unlikely(bp->panic))
-		return -EIO;
-#endif
-
-	spin_lock_bh(&bp->spq_lock);
-
-	for (i = 0; i < count; i++) {
-		struct eth_spe *spe = (struct eth_spe *)kwqes[i];
-
-		if (bp->cnic_kwq_pending == MAX_SP_DESC_CNT)
-			break;
-
-		*bp->cnic_kwq_prod = *spe;
-
-		bp->cnic_kwq_pending++;
-
-		DP(NETIF_MSG_TIMER, "L5 SPQE %x %x %x:%x pos %d\n",
-		   spe->hdr.conn_and_cmd_data, spe->hdr.type,
-		   spe->data.mac_config_addr.hi,
-		   spe->data.mac_config_addr.lo,
-		   bp->cnic_kwq_pending);
-
-		if (bp->cnic_kwq_prod == bp->cnic_kwq_last)
-			bp->cnic_kwq_prod = bp->cnic_kwq;
-		else
-			bp->cnic_kwq_prod++;
-	}
-
-	spin_unlock_bh(&bp->spq_lock);
-
-	if (bp->cnic_spq_pending < bp->cnic_eth_dev.max_kwqe_pending)
-		bnx2x_cnic_sp_post(bp, 0);
-
-	return i;
-}
-
-static int bnx2x_cnic_ctl_send(struct bnx2x *bp, struct cnic_ctl_info *ctl)
-{
-	struct cnic_ops *c_ops;
-	int rc = 0;
-
-	mutex_lock(&bp->cnic_mutex);
-	c_ops = bp->cnic_ops;
-	if (c_ops)
-		rc = c_ops->cnic_ctl(bp->cnic_data, ctl);
-	mutex_unlock(&bp->cnic_mutex);
-
-	return rc;
-}
-
-static int bnx2x_cnic_ctl_send_bh(struct bnx2x *bp, struct cnic_ctl_info *ctl)
-{
-	struct cnic_ops *c_ops;
-	int rc = 0;
-
-	rcu_read_lock();
-	c_ops = rcu_dereference(bp->cnic_ops);
-	if (c_ops)
-		rc = c_ops->cnic_ctl(bp->cnic_data, ctl);
-	rcu_read_unlock();
-
-	return rc;
-}
-
-/*
- * for commands that have no data
- */
-static int bnx2x_cnic_notify(struct bnx2x *bp, int cmd)
-{
-	struct cnic_ctl_info ctl = {0};
-
-	ctl.cmd = cmd;
-
-	return bnx2x_cnic_ctl_send(bp, &ctl);
-}
-
-static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid)
-{
-	struct cnic_ctl_info ctl;
-
-	/* first we tell CNIC and only then we count this as a completion */
-	ctl.cmd = CNIC_CTL_COMPLETION_CMD;
-	ctl.data.comp.cid = cid;
-
-	bnx2x_cnic_ctl_send_bh(bp, &ctl);
-	bnx2x_cnic_sp_post(bp, 1);
-}
-
-static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	int rc = 0;
-
-	switch (ctl->cmd) {
-	case DRV_CTL_CTXTBL_WR_CMD: {
-		u32 index = ctl->data.io.offset;
-		dma_addr_t addr = ctl->data.io.dma_addr;
-
-		bnx2x_ilt_wr(bp, index, addr);
-		break;
-	}
-
-	case DRV_CTL_COMPLETION_CMD: {
-		int count = ctl->data.comp.comp_count;
-
-		bnx2x_cnic_sp_post(bp, count);
-		break;
-	}
-
-	/* rtnl_lock is held.  */
-	case DRV_CTL_START_L2_CMD: {
-		u32 cli = ctl->data.ring.client_id;
-
-		bp->rx_mode_cl_mask |= (1 << cli);
-		bnx2x_set_storm_rx_mode(bp);
-		break;
-	}
-
-	/* rtnl_lock is held.  */
-	case DRV_CTL_STOP_L2_CMD: {
-		u32 cli = ctl->data.ring.client_id;
-
-		bp->rx_mode_cl_mask &= ~(1 << cli);
-		bnx2x_set_storm_rx_mode(bp);
-		break;
-	}
-
-	default:
-		BNX2X_ERR("unknown command %x\n", ctl->cmd);
-		rc = -EINVAL;
-	}
-
-	return rc;
-}
-
-static void bnx2x_setup_cnic_irq_info(struct bnx2x *bp)
-{
-	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
-
-	if (bp->flags & USING_MSIX_FLAG) {
-		cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
-		cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
-		cp->irq_arr[0].vector = bp->msix_table[1].vector;
-	} else {
-		cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
-		cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
-	}
-	cp->irq_arr[0].status_blk = bp->cnic_sb;
-	cp->irq_arr[0].status_blk_num = CNIC_SB_ID(bp);
-	cp->irq_arr[1].status_blk = bp->def_status_blk;
-	cp->irq_arr[1].status_blk_num = DEF_SB_ID;
-
-	cp->num_irq = 2;
-}
-
-static int bnx2x_register_cnic(struct net_device *dev, struct cnic_ops *ops,
-			       void *data)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
-
-	if (ops == NULL)
-		return -EINVAL;
-
-	if (atomic_read(&bp->intr_sem) != 0)
-		return -EBUSY;
-
-	bp->cnic_kwq = kzalloc(PAGE_SIZE, GFP_KERNEL);
-	if (!bp->cnic_kwq)
-		return -ENOMEM;
-
-	bp->cnic_kwq_cons = bp->cnic_kwq;
-	bp->cnic_kwq_prod = bp->cnic_kwq;
-	bp->cnic_kwq_last = bp->cnic_kwq + MAX_SP_DESC_CNT;
-
-	bp->cnic_spq_pending = 0;
-	bp->cnic_kwq_pending = 0;
-
-	bp->cnic_data = data;
-
-	cp->num_irq = 0;
-	cp->drv_state = CNIC_DRV_STATE_REGD;
-
-	bnx2x_init_sb(bp, bp->cnic_sb, bp->cnic_sb_mapping, CNIC_SB_ID(bp));
-
-	bnx2x_setup_cnic_irq_info(bp);
-	bnx2x_set_iscsi_eth_mac_addr(bp, 1);
-	bp->cnic_flags |= BNX2X_CNIC_FLAG_MAC_SET;
-	rcu_assign_pointer(bp->cnic_ops, ops);
-
-	return 0;
-}
-
-static int bnx2x_unregister_cnic(struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
-
-	mutex_lock(&bp->cnic_mutex);
-	if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) {
-		bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET;
-		bnx2x_set_iscsi_eth_mac_addr(bp, 0);
-	}
-	cp->drv_state = 0;
-	rcu_assign_pointer(bp->cnic_ops, NULL);
-	mutex_unlock(&bp->cnic_mutex);
-	synchronize_rcu();
-	kfree(bp->cnic_kwq);
-	bp->cnic_kwq = NULL;
-
-	return 0;
-}
-
-struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
-{
-	struct bnx2x *bp = netdev_priv(dev);
-	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
-
-	cp->drv_owner = THIS_MODULE;
-	cp->chip_id = CHIP_ID(bp);
-	cp->pdev = bp->pdev;
-	cp->io_base = bp->regview;
-	cp->io_base2 = bp->doorbells;
-	cp->max_kwqe_pending = 8;
-	cp->ctx_blk_size = CNIC_CTX_PER_ILT * sizeof(union cdu_context);
-	cp->ctx_tbl_offset = FUNC_ILT_BASE(BP_FUNC(bp)) + 1;
-	cp->ctx_tbl_len = CNIC_ILT_LINES;
-	cp->starting_cid = BCM_CNIC_CID_START;
-	cp->drv_submit_kwqes_16 = bnx2x_cnic_sp_queue;
-	cp->drv_ctl = bnx2x_drv_ctl;
-	cp->drv_register_cnic = bnx2x_register_cnic;
-	cp->drv_unregister_cnic = bnx2x_unregister_cnic;
-
-	return cp;
-}
-EXPORT_SYMBOL(bnx2x_cnic_probe);
-
-#endif /* BCM_CNIC */
-
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 8d7dfd2..c746b33 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -233,34 +233,27 @@
 	_unlock_tx_hashtbl(bond);
 }
 
+static long long compute_gap(struct slave *slave)
+{
+	return (s64) (slave->speed << 20) - /* Convert to Megabit per sec */
+	       (s64) (SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */
+}
+
 /* Caller must hold bond lock for read */
 static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
 {
 	struct slave *slave, *least_loaded;
-	s64 max_gap;
-	int i, found = 0;
+	long long max_gap;
+	int i;
 
-	/* Find the first enabled slave */
-	bond_for_each_slave(bond, slave, i) {
-		if (SLAVE_IS_OK(slave)) {
-			found = 1;
-			break;
-		}
-	}
-
-	if (!found) {
-		return NULL;
-	}
-
-	least_loaded = slave;
-	max_gap = (s64)(slave->speed << 20) - /* Convert to Megabit per sec */
-			(s64)(SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */
+	least_loaded = NULL;
+	max_gap = LLONG_MIN;
 
 	/* Find the slave with the largest gap */
-	bond_for_each_slave_from(bond, slave, i, least_loaded) {
+	bond_for_each_slave(bond, slave, i) {
 		if (SLAVE_IS_OK(slave)) {
-			s64 gap = (s64)(slave->speed << 20) -
-					(s64)(SLAVE_TLB_INFO(slave).load << 3);
+			long long gap = compute_gap(slave);
+
 			if (max_gap < gap) {
 				least_loaded = slave;
 				max_gap = gap;
@@ -689,7 +682,7 @@
 			client_info->ntt = 0;
 		}
 
-		if (!list_empty(&bond->vlan_list)) {
+		if (bond->vlgrp) {
 			if (!vlan_get_tag(skb, &client_info->vlan_id))
 				client_info->tag = 1;
 		}
@@ -911,7 +904,7 @@
 		skb->priority = TC_PRIO_CONTROL;
 		skb->dev = slave->dev;
 
-		if (!list_empty(&bond->vlan_list)) {
+		if (bond->vlgrp) {
 			struct vlan_entry *vlan;
 
 			vlan = bond_next_vlan(bond,
diff --git a/drivers/net/bonding/bond_ipv6.c b/drivers/net/bonding/bond_ipv6.c
index 969ffed..121b073 100644
--- a/drivers/net/bonding/bond_ipv6.c
+++ b/drivers/net/bonding/bond_ipv6.c
@@ -178,6 +178,8 @@
 		}
 
 		list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+			if (!bond->vlgrp)
+				continue;
 			vlan_dev = vlan_group_get_device(bond->vlgrp,
 							 vlan->vlan_id);
 			if (vlan_dev == event_dev) {
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index c3d98dd..2cc4cfc 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -90,6 +90,7 @@
 #define BOND_LINK_ARP_INTERV	0
 
 static int max_bonds	= BOND_DEFAULT_MAX_BONDS;
+static int tx_queues	= BOND_DEFAULT_TX_QUEUES;
 static int num_grat_arp = 1;
 static int num_unsol_na = 1;
 static int miimon	= BOND_LINK_MON_INTERV;
@@ -106,10 +107,13 @@
 static char *arp_ip_target[BOND_MAX_ARP_TARGETS];
 static char *arp_validate;
 static char *fail_over_mac;
+static int all_slaves_active = 0;
 static struct bond_params bonding_defaults;
 
 module_param(max_bonds, int, 0);
 MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
+module_param(tx_queues, int, 0);
+MODULE_PARM_DESC(tx_queues, "Max number of transmit queues (default = 16)");
 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);
@@ -155,6 +159,10 @@
 MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
 module_param(fail_over_mac, charp, 0);
 MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC.  none (default), active or follow");
+module_param(all_slaves_active, int, 0);
+MODULE_PARM_DESC(all_slaves_active, "Keep all frames received on an interface"
+				     "by setting active flag for all slaves.  "
+				     "0 for never (default), 1 for always.");
 
 /*----------------------------- Global variables ----------------------------*/
 
@@ -168,7 +176,9 @@
 static int bond_mode	= BOND_MODE_ROUNDROBIN;
 static int xmit_hashtype = BOND_XMIT_POLICY_LAYER2;
 static int lacp_fast;
+#ifdef CONFIG_NET_POLL_CONTROLLER
 static int disable_netpoll = 1;
+#endif
 
 const struct bond_parm_tbl bond_lacp_tbl[] = {
 {	"slow",		AD_LACP_SLOW},
@@ -414,6 +424,7 @@
 {
 	unsigned short uninitialized_var(vlan_id);
 
+	/* Test vlan_list not vlgrp to catch and handle 802.1p tags */
 	if (!list_empty(&bond->vlan_list) &&
 	    !(slave_dev->features & NETIF_F_HW_VLAN_TX) &&
 	    vlan_get_tag(skb, &vlan_id) == 0) {
@@ -477,7 +488,9 @@
 	struct slave *slave;
 	int i;
 
+	write_lock(&bond->lock);
 	bond->vlgrp = grp;
+	write_unlock(&bond->lock);
 
 	bond_for_each_slave(bond, slave, i) {
 		struct net_device *slave_dev = slave->dev;
@@ -557,10 +570,8 @@
 	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))
-		goto out;
+	if (!bond->vlgrp)
+		return;
 
 	if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&
 	    slave_ops->ndo_vlan_rx_register)
@@ -568,13 +579,10 @@
 
 	if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||
 	    !(slave_ops->ndo_vlan_rx_add_vid))
-		goto out;
+		return;
 
 	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);
 }
 
 static void bond_del_vlans_from_slave(struct bonding *bond,
@@ -584,16 +592,16 @@
 	struct vlan_entry *vlan;
 	struct net_device *vlan_dev;
 
-	write_lock_bh(&bond->lock);
-
-	if (list_empty(&bond->vlan_list))
-		goto out;
+	if (!bond->vlgrp)
+		return;
 
 	if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||
 	    !(slave_ops->ndo_vlan_rx_kill_vid))
 		goto unreg;
 
 	list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+		if (!vlan->vlan_id)
+			continue;
 		/* Save and then restore vlan_dev in the grp array,
 		 * since the slave's driver might clear it.
 		 */
@@ -606,9 +614,6 @@
 	if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&
 	    slave_ops->ndo_vlan_rx_register)
 		slave_ops->ndo_vlan_rx_register(slave_dev, NULL);
-
-out:
-	write_unlock_bh(&bond->lock);
 }
 
 /*------------------------------- Link status -------------------------------*/
@@ -1433,7 +1438,7 @@
 	/* no need to lock since we're protected by rtnl_lock */
 	if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) {
 		pr_debug("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
-		if (!list_empty(&bond->vlan_list)) {
+		if (bond->vlgrp) {
 			pr_err("%s: Error: cannot enslave VLAN challenged slave %s on VLAN enabled bond %s\n",
 			       bond_dev->name, slave_dev->name, bond_dev->name);
 			return -EPERM;
@@ -1522,16 +1527,32 @@
 		}
 	}
 
+	/* If this is the first slave, then we need to set the master's hardware
+	 * address to be the same as the slave's. */
+	if (bond->slave_cnt == 0)
+		memcpy(bond->dev->dev_addr, slave_dev->dev_addr,
+		       slave_dev->addr_len);
+
+
 	new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
 	if (!new_slave) {
 		res = -ENOMEM;
 		goto err_undo_flags;
 	}
 
-	/* save slave's original flags before calling
-	 * netdev_set_master and dev_open
+	/*
+	 * Set the new_slave's queue_id to be zero.  Queue ID mapping
+	 * is set via sysfs or module option if desired.
 	 */
-	new_slave->original_flags = slave_dev->flags;
+	new_slave->queue_id = 0;
+
+	/* Save slave's original mtu and then set it to match the bond */
+	new_slave->original_mtu = slave_dev->mtu;
+	res = dev_set_mtu(slave_dev, bond->dev->mtu);
+	if (res) {
+		pr_debug("Error %d calling dev_set_mtu\n", res);
+		goto err_free;
+	}
 
 	/*
 	 * Save slave's original ("permanent") mac address for modes
@@ -1550,7 +1571,7 @@
 		res = dev_set_mac_address(slave_dev, &addr);
 		if (res) {
 			pr_debug("Error %d calling set_mac_address\n", res);
-			goto err_free;
+			goto err_restore_mtu;
 		}
 	}
 
@@ -1793,6 +1814,9 @@
 		dev_set_mac_address(slave_dev, &addr);
 	}
 
+err_restore_mtu:
+	dev_set_mtu(slave_dev, new_slave->original_mtu);
+
 err_free:
 	kfree(new_slave);
 
@@ -1913,7 +1937,7 @@
 		 */
 		memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
 
-		if (list_empty(&bond->vlan_list)) {
+		if (!bond->vlgrp) {
 			bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
 		} else {
 			pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
@@ -1980,6 +2004,8 @@
 		dev_set_mac_address(slave_dev, &addr);
 	}
 
+	dev_set_mtu(slave_dev, slave->original_mtu);
+
 	slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
 				   IFF_SLAVE_INACTIVE | IFF_BONDING |
 				   IFF_SLAVE_NEEDARP);
@@ -2103,9 +2129,9 @@
 	 */
 	memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
 
-	if (list_empty(&bond->vlan_list))
+	if (!bond->vlgrp) {
 		bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
-	else {
+	} else {
 		pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
 			   bond_dev->name, bond_dev->name);
 		pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
@@ -2538,7 +2564,7 @@
 		if (!targets[i])
 			break;
 		pr_debug("basa: target %x\n", targets[i]);
-		if (list_empty(&bond->vlan_list)) {
+		if (!bond->vlgrp) {
 			pr_debug("basa: empty vlan: arp_send\n");
 			bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
 				      bond->master_ip, 0);
@@ -2566,7 +2592,7 @@
 		/*
 		 * This target is not on a VLAN
 		 */
-		if (rt->u.dst.dev == bond->dev) {
+		if (rt->dst.dev == bond->dev) {
 			ip_rt_put(rt);
 			pr_debug("basa: rtdev == bond->dev: arp_send\n");
 			bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
@@ -2577,7 +2603,7 @@
 		vlan_id = 0;
 		list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
 			vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
-			if (vlan_dev == rt->u.dst.dev) {
+			if (vlan_dev == rt->dst.dev) {
 				vlan_id = vlan->vlan_id;
 				pr_debug("basa: vlan match on %s %d\n",
 				       vlan_dev->name, vlan_id);
@@ -2595,7 +2621,7 @@
 		if (net_ratelimit()) {
 			pr_warning("%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");
+				   rt->dst.dev ? rt->dst.dev->name : "NULL");
 		}
 		ip_rt_put(rt);
 	}
@@ -2627,6 +2653,9 @@
 				bond->master_ip, 0);
 	}
 
+	if (!bond->vlgrp)
+		return;
+
 	list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
 		vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
 		if (vlan->vlan_ip) {
@@ -3276,6 +3305,7 @@
 		else
 			seq_puts(seq, "Aggregator ID: N/A\n");
 	}
+	seq_printf(seq, "Slave queue ID: %d\n", slave->queue_id);
 }
 
 static int bond_info_seq_show(struct seq_file *seq, void *v)
@@ -3558,6 +3588,8 @@
 		}
 
 		list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+			if (!bond->vlgrp)
+				continue;
 			vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
 			if (vlan_dev == event_dev) {
 				switch (event) {
@@ -3785,50 +3817,49 @@
 	return 0;
 }
 
-static struct net_device_stats *bond_get_stats(struct net_device *bond_dev)
+static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
+						struct rtnl_link_stats64 *stats)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
-	struct net_device_stats *stats = &bond_dev->stats;
-	struct net_device_stats local_stats;
+	struct rtnl_link_stats64 temp;
 	struct slave *slave;
 	int i;
 
-	memset(&local_stats, 0, sizeof(struct net_device_stats));
+	memset(stats, 0, sizeof(*stats));
 
 	read_lock_bh(&bond->lock);
 
 	bond_for_each_slave(bond, slave, i) {
-		const struct net_device_stats *sstats = dev_get_stats(slave->dev);
+		const struct rtnl_link_stats64 *sstats =
+			dev_get_stats(slave->dev, &temp);
 
-		local_stats.rx_packets += sstats->rx_packets;
-		local_stats.rx_bytes += sstats->rx_bytes;
-		local_stats.rx_errors += sstats->rx_errors;
-		local_stats.rx_dropped += sstats->rx_dropped;
+		stats->rx_packets += sstats->rx_packets;
+		stats->rx_bytes += sstats->rx_bytes;
+		stats->rx_errors += sstats->rx_errors;
+		stats->rx_dropped += sstats->rx_dropped;
 
-		local_stats.tx_packets += sstats->tx_packets;
-		local_stats.tx_bytes += sstats->tx_bytes;
-		local_stats.tx_errors += sstats->tx_errors;
-		local_stats.tx_dropped += sstats->tx_dropped;
+		stats->tx_packets += sstats->tx_packets;
+		stats->tx_bytes += sstats->tx_bytes;
+		stats->tx_errors += sstats->tx_errors;
+		stats->tx_dropped += sstats->tx_dropped;
 
-		local_stats.multicast += sstats->multicast;
-		local_stats.collisions += sstats->collisions;
+		stats->multicast += sstats->multicast;
+		stats->collisions += sstats->collisions;
 
-		local_stats.rx_length_errors += sstats->rx_length_errors;
-		local_stats.rx_over_errors += sstats->rx_over_errors;
-		local_stats.rx_crc_errors += sstats->rx_crc_errors;
-		local_stats.rx_frame_errors += sstats->rx_frame_errors;
-		local_stats.rx_fifo_errors += sstats->rx_fifo_errors;
-		local_stats.rx_missed_errors += sstats->rx_missed_errors;
+		stats->rx_length_errors += sstats->rx_length_errors;
+		stats->rx_over_errors += sstats->rx_over_errors;
+		stats->rx_crc_errors += sstats->rx_crc_errors;
+		stats->rx_frame_errors += sstats->rx_frame_errors;
+		stats->rx_fifo_errors += sstats->rx_fifo_errors;
+		stats->rx_missed_errors += sstats->rx_missed_errors;
 
-		local_stats.tx_aborted_errors += sstats->tx_aborted_errors;
-		local_stats.tx_carrier_errors += sstats->tx_carrier_errors;
-		local_stats.tx_fifo_errors += sstats->tx_fifo_errors;
-		local_stats.tx_heartbeat_errors += sstats->tx_heartbeat_errors;
-		local_stats.tx_window_errors += sstats->tx_window_errors;
+		stats->tx_aborted_errors += sstats->tx_aborted_errors;
+		stats->tx_carrier_errors += sstats->tx_carrier_errors;
+		stats->tx_fifo_errors += sstats->tx_fifo_errors;
+		stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
+		stats->tx_window_errors += sstats->tx_window_errors;
 	}
 
-	memcpy(stats, &local_stats, sizeof(struct net_device_stats));
-
 	read_unlock_bh(&bond->lock);
 
 	return stats;
@@ -4412,9 +4443,59 @@
 	}
 }
 
+/*
+ * Lookup the slave that corresponds to a qid
+ */
+static inline int bond_slave_override(struct bonding *bond,
+				      struct sk_buff *skb)
+{
+	int i, res = 1;
+	struct slave *slave = NULL;
+	struct slave *check_slave;
+
+	read_lock(&bond->lock);
+
+	if (!BOND_IS_OK(bond) || !skb->queue_mapping)
+		goto out;
+
+	/* Find out if any slaves have the same mapping as this skb. */
+	bond_for_each_slave(bond, check_slave, i) {
+		if (check_slave->queue_id == skb->queue_mapping) {
+			slave = check_slave;
+			break;
+		}
+	}
+
+	/* If the slave isn't UP, use default transmit policy. */
+	if (slave && slave->queue_id && IS_UP(slave->dev) &&
+	    (slave->link == BOND_LINK_UP)) {
+		res = bond_dev_queue_xmit(bond, skb, slave->dev);
+	}
+
+out:
+	read_unlock(&bond->lock);
+	return res;
+}
+
+static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+	/*
+	 * This helper function exists to help dev_pick_tx get the correct
+	 * destination queue.  Using a helper function skips the a call to
+	 * skb_tx_hash and will put the skbs in the queue we expect on their
+	 * way down to the bonding driver.
+	 */
+	return skb->queue_mapping;
+}
+
 static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	const struct bonding *bond = netdev_priv(dev);
+	struct bonding *bond = netdev_priv(dev);
+
+	if (TX_QUEUE_OVERRIDE(bond->params.mode)) {
+		if (!bond_slave_override(bond, skb))
+			return NETDEV_TX_OK;
+	}
 
 	switch (bond->params.mode) {
 	case BOND_MODE_ROUNDROBIN:
@@ -4499,7 +4580,8 @@
 	.ndo_open		= bond_open,
 	.ndo_stop		= bond_close,
 	.ndo_start_xmit		= bond_start_xmit,
-	.ndo_get_stats		= bond_get_stats,
+	.ndo_select_queue	= bond_select_queue,
+	.ndo_get_stats64	= bond_get_stats,
 	.ndo_do_ioctl		= bond_do_ioctl,
 	.ndo_set_multicast_list	= bond_set_multicast_list,
 	.ndo_change_mtu		= bond_change_mtu,
@@ -4604,6 +4686,7 @@
 static void bond_uninit(struct net_device *bond_dev)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
+	struct vlan_entry *vlan, *tmp;
 
 	bond_netpoll_cleanup(bond_dev);
 
@@ -4617,6 +4700,11 @@
 	bond_remove_proc_entry(bond);
 
 	__hw_addr_flush(&bond->mc_list);
+
+	list_for_each_entry_safe(vlan, tmp, &bond->vlan_list, vlan_list) {
+		list_del(&vlan->vlan_list);
+		kfree(vlan);
+	}
 }
 
 /*------------------------- Module initialization ---------------------------*/
@@ -4767,6 +4855,20 @@
 		}
 	}
 
+	if (tx_queues < 1 || tx_queues > 255) {
+		pr_warning("Warning: tx_queues (%d) should be between "
+			   "1 and 255, resetting to %d\n",
+			   tx_queues, BOND_DEFAULT_TX_QUEUES);
+		tx_queues = BOND_DEFAULT_TX_QUEUES;
+	}
+
+	if ((all_slaves_active != 0) && (all_slaves_active != 1)) {
+		pr_warning("Warning: all_slaves_active module parameter (%d), "
+			   "not of valid value (0/1), so it was set to "
+			   "0\n", all_slaves_active);
+		all_slaves_active = 0;
+	}
+
 	/* reset values for TLB/ALB */
 	if ((bond_mode == BOND_MODE_TLB) ||
 	    (bond_mode == BOND_MODE_ALB)) {
@@ -4937,6 +5039,8 @@
 	params->primary[0] = 0;
 	params->primary_reselect = primary_reselect_value;
 	params->fail_over_mac = fail_over_mac_value;
+	params->tx_queues = tx_queues;
+	params->all_slaves_active = all_slaves_active;
 
 	if (primary) {
 		strncpy(params->primary, primary, IFNAMSIZ);
@@ -5023,8 +5127,8 @@
 
 	rtnl_lock();
 
-	bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
-				bond_setup);
+	bond_dev = alloc_netdev_mq(sizeof(struct bonding), name ? name : "",
+				bond_setup, tx_queues);
 	if (!bond_dev) {
 		pr_err("%s: eek! can't alloc netdev!\n", name);
 		rtnl_unlock();
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index b8bec08..c311aed 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -211,7 +211,8 @@
 /*
  * Set the slaves in the current bond.  The bond interface must be
  * up for this to succeed.
- * This function is largely the same flow as bonding_update_bonds().
+ * This is supposed to be only thin wrapper for bond_enslave and bond_release.
+ * All hard work should be done there.
  */
 static ssize_t bonding_store_slaves(struct device *d,
 				    struct device_attribute *attr,
@@ -219,10 +220,8 @@
 {
 	char command[IFNAMSIZ + 1] = { 0, };
 	char *ifname;
-	int i, res, found, ret = count;
-	u32 original_mtu;
-	struct slave *slave;
-	struct net_device *dev = NULL;
+	int res, ret = count;
+	struct net_device *dev;
 	struct bonding *bond = to_bond(d);
 
 	/* Quick sanity check -- is the bond interface up? */
@@ -231,8 +230,6 @@
 			   bond->dev->name);
 	}
 
-	/* Note:  We can't hold bond->lock here, as bond_create grabs it. */
-
 	if (!rtnl_trylock())
 		return restart_syscall();
 
@@ -242,90 +239,32 @@
 	    !dev_valid_name(ifname))
 		goto err_no_cmd;
 
-	if (command[0] == '+') {
+	dev = __dev_get_by_name(dev_net(bond->dev), ifname);
+	if (!dev) {
+		pr_info("%s: Interface %s does not exist!\n",
+			bond->dev->name, ifname);
+		ret = -ENODEV;
+		goto out;
+	}
 
-		/* Got a slave name in ifname.  Is it already in the list? */
-		found = 0;
-
-		dev = __dev_get_by_name(dev_net(bond->dev), ifname);
-		if (!dev) {
-			pr_info("%s: Interface %s does not exist!\n",
-				bond->dev->name, ifname);
-			ret = -ENODEV;
-			goto out;
-		}
-
-		if (dev->flags & IFF_UP) {
-			pr_err("%s: Error: Unable to enslave %s because it is already up.\n",
-			       bond->dev->name, dev->name);
-			ret = -EPERM;
-			goto out;
-		}
-
-		read_lock(&bond->lock);
-		bond_for_each_slave(bond, slave, i)
-			if (slave->dev == dev) {
-				pr_err("%s: Interface %s is already enslaved!\n",
-				       bond->dev->name, ifname);
-				ret = -EPERM;
-				read_unlock(&bond->lock);
-				goto out;
-			}
-		read_unlock(&bond->lock);
-
-		pr_info("%s: Adding slave %s.\n", bond->dev->name, ifname);
-
-		/* If this is the first slave, then we need to set
-		   the master's hardware address to be the same as the
-		   slave's. */
-		if (is_zero_ether_addr(bond->dev->dev_addr))
-			memcpy(bond->dev->dev_addr, dev->dev_addr,
-			       dev->addr_len);
-
-		/* Set the slave's MTU to match the bond */
-		original_mtu = dev->mtu;
-		res = dev_set_mtu(dev, bond->dev->mtu);
-		if (res) {
-			ret = res;
-			goto out;
-		}
-
+	switch (command[0]) {
+	case '+':
+		pr_info("%s: Adding slave %s.\n", bond->dev->name, dev->name);
 		res = bond_enslave(bond->dev, dev);
-		bond_for_each_slave(bond, slave, i)
-			if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0)
-				slave->original_mtu = original_mtu;
-		if (res)
-			ret = res;
+		break;
 
-		goto out;
+	case '-':
+		pr_info("%s: Removing slave %s.\n", bond->dev->name, dev->name);
+		res = bond_release(bond->dev, dev);
+		break;
+
+	default:
+		goto err_no_cmd;
 	}
 
-	if (command[0] == '-') {
-		dev = NULL;
-		original_mtu = 0;
-		bond_for_each_slave(bond, slave, i)
-			if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
-				dev = slave->dev;
-				original_mtu = slave->original_mtu;
-				break;
-			}
-		if (dev) {
-			pr_info("%s: Removing slave %s\n",
-				bond->dev->name, dev->name);
-				res = bond_release(bond->dev, dev);
-			if (res) {
-				ret = res;
-				goto out;
-			}
-			/* set the slave MTU to the default */
-			dev_set_mtu(dev, original_mtu);
-		} else {
-			pr_err("unable to remove non-existent slave %s for bond %s.\n",
-			       ifname, bond->dev->name);
-			ret = -ENODEV;
-		}
-		goto out;
-	}
+	if (res)
+		ret = res;
+	goto out;
 
 err_no_cmd:
 	pr_err("no command found in slaves file for bond %s. Use +ifname or -ifname.\n",
@@ -374,19 +313,26 @@
 		       bond->dev->name, (int)strlen(buf) - 1, buf);
 		ret = -EINVAL;
 		goto out;
-	} else {
-		if (bond->params.mode == BOND_MODE_8023AD)
-			bond_unset_master_3ad_flags(bond);
-
-		if (bond->params.mode == BOND_MODE_ALB)
-			bond_unset_master_alb_flags(bond);
-
-		bond->params.mode = new_value;
-		bond_set_mode_ops(bond, bond->params.mode);
-		pr_info("%s: setting mode to %s (%d).\n",
-			bond->dev->name, bond_mode_tbl[new_value].modename,
-		       new_value);
 	}
+	if ((new_value == BOND_MODE_ALB ||
+	     new_value == BOND_MODE_TLB) &&
+	    bond->params.arp_interval) {
+		pr_err("%s: %s mode is incompatible with arp monitoring.\n",
+		       bond->dev->name, bond_mode_tbl[new_value].modename);
+		ret = -EINVAL;
+		goto out;
+	}
+	if (bond->params.mode == BOND_MODE_8023AD)
+		bond_unset_master_3ad_flags(bond);
+
+	if (bond->params.mode == BOND_MODE_ALB)
+		bond_unset_master_alb_flags(bond);
+
+	bond->params.mode = new_value;
+	bond_set_mode_ops(bond, bond->params.mode);
+	pr_info("%s: setting mode to %s (%d).\n",
+		bond->dev->name, bond_mode_tbl[new_value].modename,
+		new_value);
 out:
 	return ret;
 }
@@ -571,7 +517,13 @@
 		ret = -EINVAL;
 		goto out;
 	}
-
+	if (bond->params.mode == BOND_MODE_ALB ||
+	    bond->params.mode == BOND_MODE_TLB) {
+		pr_info("%s: ARP monitoring cannot be used with ALB/TLB. Only MII monitoring is supported on %s.\n",
+			bond->dev->name, bond->dev->name);
+		ret = -EINVAL;
+		goto out;
+	}
 	pr_info("%s: Setting ARP monitoring interval to %d.\n",
 		bond->dev->name, new_value);
 	bond->params.arp_interval = new_value;
@@ -1472,7 +1424,173 @@
 }
 static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
 
+/*
+ * Show the queue_ids of the slaves in the current bond.
+ */
+static ssize_t bonding_show_queue_id(struct device *d,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct slave *slave;
+	int i, res = 0;
+	struct bonding *bond = to_bond(d);
 
+	if (!rtnl_trylock())
+		return restart_syscall();
+
+	read_lock(&bond->lock);
+	bond_for_each_slave(bond, slave, i) {
+		if (res > (PAGE_SIZE - IFNAMSIZ - 6)) {
+			/* not enough space for another interface_name:queue_id pair */
+			if ((PAGE_SIZE - res) > 10)
+				res = PAGE_SIZE - 10;
+			res += sprintf(buf + res, "++more++ ");
+			break;
+		}
+		res += sprintf(buf + res, "%s:%d ",
+			       slave->dev->name, slave->queue_id);
+	}
+	read_unlock(&bond->lock);
+	if (res)
+		buf[res-1] = '\n'; /* eat the leftover space */
+	rtnl_unlock();
+	return res;
+}
+
+/*
+ * Set the queue_ids of the  slaves in the current bond.  The bond
+ * interface must be enslaved for this to work.
+ */
+static ssize_t bonding_store_queue_id(struct device *d,
+				      struct device_attribute *attr,
+				      const char *buffer, size_t count)
+{
+	struct slave *slave, *update_slave;
+	struct bonding *bond = to_bond(d);
+	u16 qid;
+	int i, ret = count;
+	char *delim;
+	struct net_device *sdev = NULL;
+
+	if (!rtnl_trylock())
+		return restart_syscall();
+
+	/* delim will point to queue id if successful */
+	delim = strchr(buffer, ':');
+	if (!delim)
+		goto err_no_cmd;
+
+	/*
+	 * Terminate string that points to device name and bump it
+	 * up one, so we can read the queue id there.
+	 */
+	*delim = '\0';
+	if (sscanf(++delim, "%hd\n", &qid) != 1)
+		goto err_no_cmd;
+
+	/* Check buffer length, valid ifname and queue id */
+	if (strlen(buffer) > IFNAMSIZ ||
+	    !dev_valid_name(buffer) ||
+	    qid > bond->params.tx_queues)
+		goto err_no_cmd;
+
+	/* Get the pointer to that interface if it exists */
+	sdev = __dev_get_by_name(dev_net(bond->dev), buffer);
+	if (!sdev)
+		goto err_no_cmd;
+
+	read_lock(&bond->lock);
+
+	/* Search for thes slave and check for duplicate qids */
+	update_slave = NULL;
+	bond_for_each_slave(bond, slave, i) {
+		if (sdev == slave->dev)
+			/*
+			 * We don't need to check the matching
+			 * slave for dups, since we're overwriting it
+			 */
+			update_slave = slave;
+		else if (qid && qid == slave->queue_id) {
+			goto err_no_cmd_unlock;
+		}
+	}
+
+	if (!update_slave)
+		goto err_no_cmd_unlock;
+
+	/* Actually set the qids for the slave */
+	update_slave->queue_id = qid;
+
+	read_unlock(&bond->lock);
+out:
+	rtnl_unlock();
+	return ret;
+
+err_no_cmd_unlock:
+	read_unlock(&bond->lock);
+err_no_cmd:
+	pr_info("invalid input for queue_id set for %s.\n",
+		bond->dev->name);
+	ret = -EPERM;
+	goto out;
+}
+
+static DEVICE_ATTR(queue_id, S_IRUGO | S_IWUSR, bonding_show_queue_id,
+		   bonding_store_queue_id);
+
+
+/*
+ * Show and set the all_slaves_active flag.
+ */
+static ssize_t bonding_show_slaves_active(struct device *d,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	struct bonding *bond = to_bond(d);
+
+	return sprintf(buf, "%d\n", bond->params.all_slaves_active);
+}
+
+static ssize_t bonding_store_slaves_active(struct device *d,
+					   struct device_attribute *attr,
+					   const char *buf, size_t count)
+{
+	int i, new_value, ret = count;
+	struct bonding *bond = to_bond(d);
+	struct slave *slave;
+
+	if (sscanf(buf, "%d", &new_value) != 1) {
+		pr_err("%s: no all_slaves_active value specified.\n",
+		       bond->dev->name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (new_value == bond->params.all_slaves_active)
+		goto out;
+
+	if ((new_value == 0) || (new_value == 1)) {
+		bond->params.all_slaves_active = new_value;
+	} else {
+		pr_info("%s: Ignoring invalid all_slaves_active value %d.\n",
+			bond->dev->name, new_value);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	bond_for_each_slave(bond, slave, i) {
+		if (slave->state == BOND_STATE_BACKUP) {
+			if (new_value)
+				slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
+			else
+				slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
+		}
+	}
+out:
+	return count;
+}
+static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,
+		   bonding_show_slaves_active, bonding_store_slaves_active);
 
 static struct attribute *per_bond_attrs[] = {
 	&dev_attr_slaves.attr,
@@ -1499,6 +1617,8 @@
 	&dev_attr_ad_actor_key.attr,
 	&dev_attr_ad_partner_key.attr,
 	&dev_attr_ad_partner_mac.attr,
+	&dev_attr_queue_id.attr,
+	&dev_attr_all_slaves_active.attr,
 	NULL,
 };
 
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 2aa3367..c6fdd85 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -23,8 +23,8 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION	"3.6.0"
-#define DRV_RELDATE	"September 26, 2009"
+#define DRV_VERSION	"3.7.0"
+#define DRV_RELDATE	"June 2, 2010"
 #define DRV_NAME	"bonding"
 #define DRV_DESCRIPTION	"Ethernet Channel Bonding Driver"
 
@@ -60,6 +60,9 @@
 		 ((mode) == BOND_MODE_TLB)          ||	\
 		 ((mode) == BOND_MODE_ALB))
 
+#define TX_QUEUE_OVERRIDE(mode)				\
+			(((mode) == BOND_MODE_ACTIVEBACKUP) ||	\
+			 ((mode) == BOND_MODE_ROUNDROBIN))
 /*
  * Less bad way to call ioctl from within the kernel; this needs to be
  * done some other way to get the call out of interrupt context.
@@ -131,6 +134,8 @@
 	char primary[IFNAMSIZ];
 	int primary_reselect;
 	__be32 arp_targets[BOND_MAX_ARP_TARGETS];
+	int tx_queues;
+	int all_slaves_active;
 };
 
 struct bond_parm_tbl {
@@ -159,12 +164,12 @@
 	s8     link;    /* one of BOND_LINK_XXXX */
 	s8     new_link;
 	s8     state;   /* one of BOND_STATE_XXXX */
-	u32    original_flags;
 	u32    original_mtu;
 	u32    link_failure_count;
 	u8     perm_hwaddr[ETH_ALEN];
 	u16    speed;
 	u8     duplex;
+	u16    queue_id;
 	struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */
 	struct tlb_slave_info tlb_info;
 };
@@ -291,7 +296,8 @@
 	struct bonding *bond = netdev_priv(slave->dev->master);
 	if (!bond_is_lb(bond))
 		slave->state = BOND_STATE_BACKUP;
-	slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
+	if (!bond->params.all_slaves_active)
+		slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
 	if (slave_do_arp_validate(bond, slave))
 		slave->dev->priv_flags |= IFF_SLAVE_NEEDARP;
 }
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index 0b28e01..631a624 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -2,16 +2,32 @@
 # CAIF physical drivers
 #
 
-if CAIF
-
 comment "CAIF transport drivers"
 
 config CAIF_TTY
 	tristate "CAIF TTY transport driver"
+	depends on CAIF
 	default n
 	---help---
 	The CAIF TTY transport driver is a Line Discipline (ldisc)
 	identified as N_CAIF. When this ldisc is opened from user space
 	it will redirect the TTY's traffic into the CAIF stack.
 
-endif # CAIF
+config CAIF_SPI_SLAVE
+	tristate "CAIF SPI transport driver for slave interface"
+	depends on CAIF
+	default n
+	---help---
+	The CAIF Link layer SPI Protocol driver for Slave SPI interface.
+	This driver implements a platform driver to accommodate for a
+	platform specific SPI device. A sample CAIF SPI Platform device is
+	provided in Documentation/networking/caif/spi_porting.txt
+
+config CAIF_SPI_SYNC
+	bool "Next command and length in start of frame"
+	depends on CAIF_SPI_SLAVE
+	default n
+	---help---
+	Putting the next command and length in the start of the frame can
+	help to synchronize to the next transfer in case of over or under-runs.
+	This option also needs to be enabled on the modem.
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
index 52b6d1f..3a11d61 100644
--- a/drivers/net/caif/Makefile
+++ b/drivers/net/caif/Makefile
@@ -1,12 +1,10 @@
-ifeq ($(CONFIG_CAIF_DEBUG),1)
-CAIF_DBG_FLAGS := -DDEBUG
+ifeq ($(CONFIG_CAIF_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
 endif
 
-KBUILD_EXTRA_SYMBOLS=net/caif/Module.symvers
-
-ccflags-y := $(CAIF_FLAGS) $(CAIF_DBG_FLAGS)
-clean-dirs:= .tmp_versions
-clean-files:= Module.symvers modules.order *.cmd *~ \
-
 # Serial interface
 obj-$(CONFIG_CAIF_TTY) += caif_serial.o
+
+# SPI slave physical interfaces module
+cfspi_slave-objs := caif_spi.o caif_spi_slave.o
+obj-$(CONFIG_CAIF_SPI_SLAVE) += cfspi_slave.o
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index 09257ca..3df0c0f 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -174,6 +174,7 @@
 	struct ser_device *ser;
 	int ret;
 	u8 *p;
+
 	ser = tty->disc_data;
 
 	/*
@@ -221,6 +222,7 @@
 	struct tty_struct *tty;
 	struct sk_buff *skb;
 	int tty_wr, len, room;
+
 	tty = ser->tty;
 	ser->tx_started = true;
 
@@ -281,6 +283,7 @@
 static int caif_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ser_device *ser;
+
 	BUG_ON(dev == NULL);
 	ser = netdev_priv(dev);
 
@@ -299,6 +302,7 @@
 static void ldisc_tx_wakeup(struct tty_struct *tty)
 {
 	struct ser_device *ser;
+
 	ser = tty->disc_data;
 	BUG_ON(ser == NULL);
 	BUG_ON(ser->tty != tty);
@@ -348,6 +352,7 @@
 	struct ser_device *ser = tty->disc_data;
 	/* Remove may be called inside or outside of rtnl_lock */
 	int islocked = rtnl_is_locked();
+
 	if (!islocked)
 		rtnl_lock();
 	/* device is freed automagically by net-sysfs */
@@ -374,6 +379,7 @@
 static int register_ldisc(void)
 {
 	int result;
+
 	result = tty_register_ldisc(N_CAIF, &caif_ldisc);
 	if (result < 0) {
 		pr_err("cannot register CAIF ldisc=%d err=%d\n", N_CAIF,
@@ -391,12 +397,12 @@
 static void caifdev_setup(struct net_device *dev)
 {
 	struct ser_device *serdev = netdev_priv(dev);
+
 	dev->features = 0;
 	dev->netdev_ops = &netdev_ops;
 	dev->type = ARPHRD_CAIF;
 	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
 	dev->mtu = CAIF_MAX_MTU;
-	dev->hard_header_len = CAIF_NEEDED_HEADROOM;
 	dev->tx_queue_len = 0;
 	dev->destructor = free_netdev;
 	skb_queue_head_init(&serdev->head);
@@ -410,8 +416,6 @@
 
 static int caif_net_open(struct net_device *dev)
 {
-	struct ser_device *ser;
-	ser = netdev_priv(dev);
 	netif_wake_queue(dev);
 	return 0;
 }
@@ -425,6 +429,7 @@
 static int __init caif_ser_init(void)
 {
 	int ret;
+
 	ret = register_ldisc();
 	debugfsdir = debugfs_create_dir("caif_serial", NULL);
 	return ret;
@@ -435,6 +440,7 @@
 	struct ser_device *ser = NULL;
 	struct list_head *node;
 	struct list_head *_tmp;
+
 	list_for_each_safe(node, _tmp, &ser_list) {
 		ser = list_entry(node, struct ser_device, node);
 		dev_close(ser->dev);
diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c
new file mode 100644
index 0000000..f5058ff
--- /dev/null
+++ b/drivers/net/caif/caif_spi.c
@@ -0,0 +1,850 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author:  Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <linux/if_arp.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/caif_spi.h>
+
+#ifndef CONFIG_CAIF_SPI_SYNC
+#define FLAVOR "Flavour: Vanilla.\n"
+#else
+#define FLAVOR "Flavour: Master CMD&LEN at start.\n"
+#endif /* CONFIG_CAIF_SPI_SYNC */
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
+MODULE_DESCRIPTION("CAIF SPI driver");
+
+static int spi_loop;
+module_param(spi_loop, bool, S_IRUGO);
+MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
+
+/* SPI frame alignment. */
+module_param(spi_frm_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment.");
+
+/* SPI padding options. */
+module_param(spi_up_head_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment.");
+
+module_param(spi_up_tail_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_up_tail_align, "SPI uplink tail alignment.");
+
+module_param(spi_down_head_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_down_head_align, "SPI downlink head alignment.");
+
+module_param(spi_down_tail_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_down_tail_align, "SPI downlink tail alignment.");
+
+#ifdef CONFIG_ARM
+#define BYTE_HEX_FMT "%02X"
+#else
+#define BYTE_HEX_FMT "%02hhX"
+#endif
+
+#define SPI_MAX_PAYLOAD_SIZE 4096
+/*
+ * Threshold values for the SPI packet queue. Flowcontrol will be asserted
+ * when the number of packets exceeds HIGH_WATER_MARK. It will not be
+ * deasserted before the number of packets drops below LOW_WATER_MARK.
+ */
+#define LOW_WATER_MARK   100
+#define HIGH_WATER_MARK  (LOW_WATER_MARK*5)
+
+#ifdef CONFIG_UML
+
+/*
+ * We sometimes use UML for debugging, but it cannot handle
+ * dma_alloc_coherent so we have to wrap it.
+ */
+static inline void *dma_alloc(dma_addr_t *daddr)
+{
+	return kmalloc(SPI_DMA_BUF_LEN, GFP_KERNEL);
+}
+
+static inline void dma_free(void *cpu_addr, dma_addr_t handle)
+{
+	kfree(cpu_addr);
+}
+
+#else
+
+static inline void *dma_alloc(dma_addr_t *daddr)
+{
+	return dma_alloc_coherent(NULL, SPI_DMA_BUF_LEN, daddr,
+				GFP_KERNEL);
+}
+
+static inline void dma_free(void *cpu_addr, dma_addr_t handle)
+{
+	dma_free_coherent(NULL, SPI_DMA_BUF_LEN, cpu_addr, handle);
+}
+#endif	/* CONFIG_UML */
+
+#ifdef CONFIG_DEBUG_FS
+
+#define DEBUGFS_BUF_SIZE	4096
+
+static struct dentry *dbgfs_root;
+
+static inline void driver_debugfs_create(void)
+{
+	dbgfs_root = debugfs_create_dir(cfspi_spi_driver.driver.name, NULL);
+}
+
+static inline void driver_debugfs_remove(void)
+{
+	debugfs_remove(dbgfs_root);
+}
+
+static inline void dev_debugfs_rem(struct cfspi *cfspi)
+{
+	debugfs_remove(cfspi->dbgfs_frame);
+	debugfs_remove(cfspi->dbgfs_state);
+	debugfs_remove(cfspi->dbgfs_dir);
+}
+
+static int dbgfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t dbgfs_state(struct file *file, char __user *user_buf,
+			   size_t count, loff_t *ppos)
+{
+	char *buf;
+	int len = 0;
+	ssize_t size;
+	struct cfspi *cfspi = file->private_data;
+
+	buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return 0;
+
+	/* Print out debug information. */
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"CAIF SPI debug information:\n");
+
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), FLAVOR);
+
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"STATE: %d\n", cfspi->dbg_state);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Previous CMD: 0x%x\n", cfspi->pcmd);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Current CMD: 0x%x\n", cfspi->cmd);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Previous TX len: %d\n", cfspi->tx_ppck_len);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Previous RX len: %d\n", cfspi->rx_ppck_len);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Current TX len: %d\n", cfspi->tx_cpck_len);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Current RX len: %d\n", cfspi->rx_cpck_len);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Next TX len: %d\n", cfspi->tx_npck_len);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Next RX len: %d\n", cfspi->rx_npck_len);
+
+	if (len > DEBUGFS_BUF_SIZE)
+		len = DEBUGFS_BUF_SIZE;
+
+	size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return size;
+}
+
+static ssize_t print_frame(char *buf, size_t size, char *frm,
+			   size_t count, size_t cut)
+{
+	int len = 0;
+	int i;
+	for (i = 0; i < count; i++) {
+		len += snprintf((buf + len), (size - len),
+					"[0x" BYTE_HEX_FMT "]",
+					frm[i]);
+		if ((i == cut) && (count > (cut * 2))) {
+			/* Fast forward. */
+			i = count - cut;
+			len += snprintf((buf + len), (size - len),
+					"--- %u bytes skipped ---\n",
+					(int)(count - (cut * 2)));
+		}
+
+		if ((!(i % 10)) && i) {
+			len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+					"\n");
+		}
+	}
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), "\n");
+	return len;
+}
+
+static ssize_t dbgfs_frame(struct file *file, char __user *user_buf,
+			   size_t count, loff_t *ppos)
+{
+	char *buf;
+	int len = 0;
+	ssize_t size;
+	struct cfspi *cfspi;
+
+	cfspi = file->private_data;
+	buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return 0;
+
+	/* Print out debug information. */
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Current frame:\n");
+
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Tx data (Len: %d):\n", cfspi->tx_cpck_len);
+
+	len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
+			   cfspi->xfer.va_tx,
+			   (cfspi->tx_cpck_len + SPI_CMD_SZ), 100);
+
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Rx data (Len: %d):\n", cfspi->rx_cpck_len);
+
+	len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
+			   cfspi->xfer.va_rx,
+			   (cfspi->rx_cpck_len + SPI_CMD_SZ), 100);
+
+	size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return size;
+}
+
+static const struct file_operations dbgfs_state_fops = {
+	.open = dbgfs_open,
+	.read = dbgfs_state,
+	.owner = THIS_MODULE
+};
+
+static const struct file_operations dbgfs_frame_fops = {
+	.open = dbgfs_open,
+	.read = dbgfs_frame,
+	.owner = THIS_MODULE
+};
+
+static inline void dev_debugfs_add(struct cfspi *cfspi)
+{
+	cfspi->dbgfs_dir = debugfs_create_dir(cfspi->pdev->name, dbgfs_root);
+	cfspi->dbgfs_state = debugfs_create_file("state", S_IRUGO,
+						 cfspi->dbgfs_dir, cfspi,
+						 &dbgfs_state_fops);
+	cfspi->dbgfs_frame = debugfs_create_file("frame", S_IRUGO,
+						 cfspi->dbgfs_dir, cfspi,
+						 &dbgfs_frame_fops);
+}
+
+inline void cfspi_dbg_state(struct cfspi *cfspi, int state)
+{
+	cfspi->dbg_state = state;
+};
+#else
+
+static inline void driver_debugfs_create(void)
+{
+}
+
+static inline void driver_debugfs_remove(void)
+{
+}
+
+static inline void dev_debugfs_add(struct cfspi *cfspi)
+{
+}
+
+static inline void dev_debugfs_rem(struct cfspi *cfspi)
+{
+}
+
+inline void cfspi_dbg_state(struct cfspi *cfspi, int state)
+{
+}
+#endif				/* CONFIG_DEBUG_FS */
+
+static LIST_HEAD(cfspi_list);
+static spinlock_t cfspi_list_lock;
+
+/* SPI uplink head alignment. */
+static ssize_t show_up_head_align(struct device_driver *driver, char *buf)
+{
+	return sprintf(buf, "%d\n", spi_up_head_align);
+}
+
+static DRIVER_ATTR(up_head_align, S_IRUSR, show_up_head_align, NULL);
+
+/* SPI uplink tail alignment. */
+static ssize_t show_up_tail_align(struct device_driver *driver, char *buf)
+{
+	return sprintf(buf, "%d\n", spi_up_tail_align);
+}
+
+static DRIVER_ATTR(up_tail_align, S_IRUSR, show_up_tail_align, NULL);
+
+/* SPI downlink head alignment. */
+static ssize_t show_down_head_align(struct device_driver *driver, char *buf)
+{
+	return sprintf(buf, "%d\n", spi_down_head_align);
+}
+
+static DRIVER_ATTR(down_head_align, S_IRUSR, show_down_head_align, NULL);
+
+/* SPI downlink tail alignment. */
+static ssize_t show_down_tail_align(struct device_driver *driver, char *buf)
+{
+	return sprintf(buf, "%d\n", spi_down_tail_align);
+}
+
+static DRIVER_ATTR(down_tail_align, S_IRUSR, show_down_tail_align, NULL);
+
+/* SPI frame alignment. */
+static ssize_t show_frame_align(struct device_driver *driver, char *buf)
+{
+	return sprintf(buf, "%d\n", spi_frm_align);
+}
+
+static DRIVER_ATTR(frame_align, S_IRUSR, show_frame_align, NULL);
+
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
+{
+	u8 *dst = buf;
+	caif_assert(buf);
+
+	do {
+		struct sk_buff *skb;
+		struct caif_payload_info *info;
+		int spad = 0;
+		int epad;
+
+		skb = skb_dequeue(&cfspi->chead);
+		if (!skb)
+			break;
+
+		/*
+		 * Calculate length of frame including SPI padding.
+		 * The payload position is found in the control buffer.
+		 */
+		info = (struct caif_payload_info *)&skb->cb;
+
+		/*
+		 * Compute head offset i.e. number of bytes to add to
+		 * get the start of the payload aligned.
+		 */
+		if (spi_up_head_align) {
+			spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+			*dst = (u8)(spad - 1);
+			dst += spad;
+		}
+
+		/* Copy in CAIF frame. */
+		skb_copy_bits(skb, 0, dst, skb->len);
+		dst += skb->len;
+		cfspi->ndev->stats.tx_packets++;
+		cfspi->ndev->stats.tx_bytes += skb->len;
+
+		/*
+		 * Compute tail offset i.e. number of bytes to add to
+		 * get the complete CAIF frame aligned.
+		 */
+		epad = (skb->len + spad) & spi_up_tail_align;
+		dst += epad;
+
+		dev_kfree_skb(skb);
+
+	} while ((dst - buf) < len);
+
+	return dst - buf;
+}
+
+int cfspi_xmitlen(struct cfspi *cfspi)
+{
+	struct sk_buff *skb = NULL;
+	int frm_len = 0;
+	int pkts = 0;
+
+	/*
+	 * Decommit previously commited frames.
+	 * skb_queue_splice_tail(&cfspi->chead,&cfspi->qhead)
+	 */
+	while (skb_peek(&cfspi->chead)) {
+		skb = skb_dequeue_tail(&cfspi->chead);
+		skb_queue_head(&cfspi->qhead, skb);
+	}
+
+	do {
+		struct caif_payload_info *info = NULL;
+		int spad = 0;
+		int epad = 0;
+
+		skb = skb_dequeue(&cfspi->qhead);
+		if (!skb)
+			break;
+
+		/*
+		 * Calculate length of frame including SPI padding.
+		 * The payload position is found in the control buffer.
+		 */
+		info = (struct caif_payload_info *)&skb->cb;
+
+		/*
+		 * Compute head offset i.e. number of bytes to add to
+		 * get the start of the payload aligned.
+		 */
+		if (spi_up_head_align)
+			spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+
+		/*
+		 * Compute tail offset i.e. number of bytes to add to
+		 * get the complete CAIF frame aligned.
+		 */
+		epad = (skb->len + spad) & spi_up_tail_align;
+
+		if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) {
+			skb_queue_tail(&cfspi->chead, skb);
+			pkts++;
+			frm_len += skb->len + spad + epad;
+		} else {
+			/* Put back packet. */
+			skb_queue_head(&cfspi->qhead, skb);
+		}
+	} while (pkts <= CAIF_MAX_SPI_PKTS);
+
+	/*
+	 * Send flow on if previously sent flow off
+	 * and now go below the low water mark
+	 */
+	if (cfspi->flow_off_sent && cfspi->qhead.qlen < cfspi->qd_low_mark &&
+		cfspi->cfdev.flowctrl) {
+		cfspi->flow_off_sent = 0;
+		cfspi->cfdev.flowctrl(cfspi->ndev, 1);
+	}
+
+	return frm_len;
+}
+
+static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
+{
+	struct cfspi *cfspi = (struct cfspi *)ifc->priv;
+
+	if (!in_interrupt())
+		spin_lock(&cfspi->lock);
+	if (assert) {
+		set_bit(SPI_SS_ON, &cfspi->state);
+		set_bit(SPI_XFER, &cfspi->state);
+	} else {
+		set_bit(SPI_SS_OFF, &cfspi->state);
+	}
+	if (!in_interrupt())
+		spin_unlock(&cfspi->lock);
+
+	/* Wake up the xfer thread. */
+	wake_up_interruptible(&cfspi->wait);
+}
+
+static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc)
+{
+	struct cfspi *cfspi = (struct cfspi *)ifc->priv;
+
+	/* Transfer done, complete work queue */
+	complete(&cfspi->comp);
+}
+
+static int cfspi_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct cfspi *cfspi = NULL;
+	unsigned long flags;
+	if (!dev)
+		return -EINVAL;
+
+	cfspi = netdev_priv(dev);
+
+	skb_queue_tail(&cfspi->qhead, skb);
+
+	spin_lock_irqsave(&cfspi->lock, flags);
+	if (!test_and_set_bit(SPI_XFER, &cfspi->state)) {
+		/* Wake up xfer thread. */
+		wake_up_interruptible(&cfspi->wait);
+	}
+	spin_unlock_irqrestore(&cfspi->lock, flags);
+
+	/* Send flow off if number of bytes is above high water mark */
+	if (!cfspi->flow_off_sent &&
+		cfspi->qhead.qlen > cfspi->qd_high_mark &&
+		cfspi->cfdev.flowctrl) {
+		cfspi->flow_off_sent = 1;
+		cfspi->cfdev.flowctrl(cfspi->ndev, 0);
+	}
+
+	return 0;
+}
+
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
+{
+	u8 *src = buf;
+
+	caif_assert(buf != NULL);
+
+	do {
+		int res;
+		struct sk_buff *skb = NULL;
+		int spad = 0;
+		int epad = 0;
+		u8 *dst = NULL;
+		int pkt_len = 0;
+
+		/*
+		 * Compute head offset i.e. number of bytes added to
+		 * get the start of the payload aligned.
+		 */
+		if (spi_down_head_align) {
+			spad = 1 + *src;
+			src += spad;
+		}
+
+		/* Read length of CAIF frame (little endian). */
+		pkt_len = *src;
+		pkt_len |= ((*(src+1)) << 8) & 0xFF00;
+		pkt_len += 2;	/* Add FCS fields. */
+
+		/* Get a suitable caif packet and copy in data. */
+
+		skb = netdev_alloc_skb(cfspi->ndev, pkt_len + 1);
+		caif_assert(skb != NULL);
+
+		dst = skb_put(skb, pkt_len);
+		memcpy(dst, src, pkt_len);
+		src += pkt_len;
+
+		skb->protocol = htons(ETH_P_CAIF);
+		skb_reset_mac_header(skb);
+		skb->dev = cfspi->ndev;
+
+		/*
+		 * Push received packet up the stack.
+		 */
+		if (!spi_loop)
+			res = netif_rx_ni(skb);
+		else
+			res = cfspi_xmit(skb, cfspi->ndev);
+
+		if (!res) {
+			cfspi->ndev->stats.rx_packets++;
+			cfspi->ndev->stats.rx_bytes += pkt_len;
+		} else
+			cfspi->ndev->stats.rx_dropped++;
+
+		/*
+		 * Compute tail offset i.e. number of bytes added to
+		 * get the complete CAIF frame aligned.
+		 */
+		epad = (pkt_len + spad) & spi_down_tail_align;
+		src += epad;
+	} while ((src - buf) < len);
+
+	return src - buf;
+}
+
+static int cfspi_open(struct net_device *dev)
+{
+	netif_wake_queue(dev);
+	return 0;
+}
+
+static int cfspi_close(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	return 0;
+}
+static const struct net_device_ops cfspi_ops = {
+	.ndo_open = cfspi_open,
+	.ndo_stop = cfspi_close,
+	.ndo_start_xmit = cfspi_xmit
+};
+
+static void cfspi_setup(struct net_device *dev)
+{
+	struct cfspi *cfspi = netdev_priv(dev);
+	dev->features = 0;
+	dev->netdev_ops = &cfspi_ops;
+	dev->type = ARPHRD_CAIF;
+	dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+	dev->tx_queue_len = 0;
+	dev->mtu = SPI_MAX_PAYLOAD_SIZE;
+	dev->destructor = free_netdev;
+	skb_queue_head_init(&cfspi->qhead);
+	skb_queue_head_init(&cfspi->chead);
+	cfspi->cfdev.link_select = CAIF_LINK_HIGH_BANDW;
+	cfspi->cfdev.use_frag = false;
+	cfspi->cfdev.use_stx = false;
+	cfspi->cfdev.use_fcs = false;
+	cfspi->ndev = dev;
+}
+
+int cfspi_spi_probe(struct platform_device *pdev)
+{
+	struct cfspi *cfspi = NULL;
+	struct net_device *ndev;
+	struct cfspi_dev *dev;
+	int res;
+	dev = (struct cfspi_dev *)pdev->dev.platform_data;
+
+	ndev = alloc_netdev(sizeof(struct cfspi),
+			"cfspi%d", cfspi_setup);
+	if (!dev)
+		return -ENODEV;
+
+	cfspi = netdev_priv(ndev);
+	netif_stop_queue(ndev);
+	cfspi->ndev = ndev;
+	cfspi->pdev = pdev;
+
+	/* Set flow info */
+	cfspi->flow_off_sent = 0;
+	cfspi->qd_low_mark = LOW_WATER_MARK;
+	cfspi->qd_high_mark = HIGH_WATER_MARK;
+
+	/* Assign the SPI device. */
+	cfspi->dev = dev;
+	/* Assign the device ifc to this SPI interface. */
+	dev->ifc = &cfspi->ifc;
+
+	/* Allocate DMA buffers. */
+	cfspi->xfer.va_tx = dma_alloc(&cfspi->xfer.pa_tx);
+	if (!cfspi->xfer.va_tx) {
+		printk(KERN_WARNING
+		       "CFSPI: failed to allocate dma TX buffer.\n");
+		res = -ENODEV;
+		goto err_dma_alloc_tx;
+	}
+
+	cfspi->xfer.va_rx = dma_alloc(&cfspi->xfer.pa_rx);
+
+	if (!cfspi->xfer.va_rx) {
+		printk(KERN_WARNING
+		       "CFSPI: failed to allocate dma TX buffer.\n");
+		res = -ENODEV;
+		goto err_dma_alloc_rx;
+	}
+
+	/* Initialize the work queue. */
+	INIT_WORK(&cfspi->work, cfspi_xfer);
+
+	/* Initialize spin locks. */
+	spin_lock_init(&cfspi->lock);
+
+	/* Initialize flow control state. */
+	cfspi->flow_stop = false;
+
+	/* Initialize wait queue. */
+	init_waitqueue_head(&cfspi->wait);
+
+	/* Create work thread. */
+	cfspi->wq = create_singlethread_workqueue(dev->name);
+	if (!cfspi->wq) {
+		printk(KERN_WARNING "CFSPI: failed to create work queue.\n");
+		res = -ENODEV;
+		goto err_create_wq;
+	}
+
+	/* Initialize work queue. */
+	init_completion(&cfspi->comp);
+
+	/* Create debugfs entries. */
+	dev_debugfs_add(cfspi);
+
+	/* Set up the ifc. */
+	cfspi->ifc.ss_cb = cfspi_ss_cb;
+	cfspi->ifc.xfer_done_cb = cfspi_xfer_done_cb;
+	cfspi->ifc.priv = cfspi;
+
+	/* Add CAIF SPI device to list. */
+	spin_lock(&cfspi_list_lock);
+	list_add_tail(&cfspi->list, &cfspi_list);
+	spin_unlock(&cfspi_list_lock);
+
+	/* Schedule the work queue. */
+	queue_work(cfspi->wq, &cfspi->work);
+
+	/* Register network device. */
+	res = register_netdev(ndev);
+	if (res) {
+		printk(KERN_ERR "CFSPI: Reg. error: %d.\n", res);
+		goto err_net_reg;
+	}
+	return res;
+
+ err_net_reg:
+	dev_debugfs_rem(cfspi);
+	set_bit(SPI_TERMINATE, &cfspi->state);
+	wake_up_interruptible(&cfspi->wait);
+	destroy_workqueue(cfspi->wq);
+ err_create_wq:
+	dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
+ err_dma_alloc_rx:
+	dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx);
+ err_dma_alloc_tx:
+	free_netdev(ndev);
+
+	return res;
+}
+
+int cfspi_spi_remove(struct platform_device *pdev)
+{
+	struct list_head *list_node;
+	struct list_head *n;
+	struct cfspi *cfspi = NULL;
+	struct cfspi_dev *dev;
+
+	dev = (struct cfspi_dev *)pdev->dev.platform_data;
+	spin_lock(&cfspi_list_lock);
+	list_for_each_safe(list_node, n, &cfspi_list) {
+		cfspi = list_entry(list_node, struct cfspi, list);
+		/* Find the corresponding device. */
+		if (cfspi->dev == dev) {
+			/* Remove from list. */
+			list_del(list_node);
+			/* Free DMA buffers. */
+			dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
+			dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx);
+			set_bit(SPI_TERMINATE, &cfspi->state);
+			wake_up_interruptible(&cfspi->wait);
+			destroy_workqueue(cfspi->wq);
+			/* Destroy debugfs directory and files. */
+			dev_debugfs_rem(cfspi);
+			unregister_netdev(cfspi->ndev);
+			spin_unlock(&cfspi_list_lock);
+			return 0;
+		}
+	}
+	spin_unlock(&cfspi_list_lock);
+	return -ENODEV;
+}
+
+static void __exit cfspi_exit_module(void)
+{
+	struct list_head *list_node;
+	struct list_head *n;
+	struct cfspi *cfspi = NULL;
+
+	list_for_each_safe(list_node, n, &cfspi_list) {
+		cfspi = list_entry(list_node, struct cfspi, list);
+		platform_device_unregister(cfspi->pdev);
+	}
+
+	/* Destroy sysfs files. */
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_up_head_align);
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_up_tail_align);
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_down_head_align);
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_down_tail_align);
+	driver_remove_file(&cfspi_spi_driver.driver, &driver_attr_frame_align);
+	/* Unregister platform driver. */
+	platform_driver_unregister(&cfspi_spi_driver);
+	/* Destroy debugfs root directory. */
+	driver_debugfs_remove();
+}
+
+static int __init cfspi_init_module(void)
+{
+	int result;
+
+	/* Initialize spin lock. */
+	spin_lock_init(&cfspi_list_lock);
+
+	/* Register platform driver. */
+	result = platform_driver_register(&cfspi_spi_driver);
+	if (result) {
+		printk(KERN_ERR "Could not register platform SPI driver.\n");
+		goto err_dev_register;
+	}
+
+	/* Create sysfs files. */
+	result =
+	    driver_create_file(&cfspi_spi_driver.driver,
+			       &driver_attr_up_head_align);
+	if (result) {
+		printk(KERN_ERR "Sysfs creation failed 1.\n");
+		goto err_create_up_head_align;
+	}
+
+	result =
+	    driver_create_file(&cfspi_spi_driver.driver,
+			       &driver_attr_up_tail_align);
+	if (result) {
+		printk(KERN_ERR "Sysfs creation failed 2.\n");
+		goto err_create_up_tail_align;
+	}
+
+	result =
+	    driver_create_file(&cfspi_spi_driver.driver,
+			       &driver_attr_down_head_align);
+	if (result) {
+		printk(KERN_ERR "Sysfs creation failed 3.\n");
+		goto err_create_down_head_align;
+	}
+
+	result =
+	    driver_create_file(&cfspi_spi_driver.driver,
+			       &driver_attr_down_tail_align);
+	if (result) {
+		printk(KERN_ERR "Sysfs creation failed 4.\n");
+		goto err_create_down_tail_align;
+	}
+
+	result =
+	    driver_create_file(&cfspi_spi_driver.driver,
+			       &driver_attr_frame_align);
+	if (result) {
+		printk(KERN_ERR "Sysfs creation failed 5.\n");
+		goto err_create_frame_align;
+	}
+	driver_debugfs_create();
+	return result;
+
+ err_create_frame_align:
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_down_tail_align);
+ err_create_down_tail_align:
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_down_head_align);
+ err_create_down_head_align:
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_up_tail_align);
+ err_create_up_tail_align:
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_up_head_align);
+ err_create_up_head_align:
+ err_dev_register:
+	return result;
+}
+
+module_init(cfspi_init_module);
+module_exit(cfspi_exit_module);
diff --git a/drivers/net/caif/caif_spi_slave.c b/drivers/net/caif/caif_spi_slave.c
new file mode 100644
index 0000000..077ccf8
--- /dev/null
+++ b/drivers/net/caif/caif_spi_slave.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author:  Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/semaphore.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <net/caif/caif_spi.h>
+
+#ifndef CONFIG_CAIF_SPI_SYNC
+#define SPI_DATA_POS SPI_CMD_SZ
+static inline int forward_to_spi_cmd(struct cfspi *cfspi)
+{
+	return cfspi->rx_cpck_len;
+}
+#else
+#define SPI_DATA_POS 0
+static inline int forward_to_spi_cmd(struct cfspi *cfspi)
+{
+	return 0;
+}
+#endif
+
+int spi_frm_align = 2;
+int spi_up_head_align = 1;
+int spi_up_tail_align;
+int spi_down_head_align = 3;
+int spi_down_tail_align = 1;
+
+#ifdef CONFIG_DEBUG_FS
+static inline void debugfs_store_prev(struct cfspi *cfspi)
+{
+	/* Store previous command for debugging reasons.*/
+	cfspi->pcmd = cfspi->cmd;
+	/* Store previous transfer. */
+	cfspi->tx_ppck_len = cfspi->tx_cpck_len;
+	cfspi->rx_ppck_len = cfspi->rx_cpck_len;
+}
+#else
+static inline void debugfs_store_prev(struct cfspi *cfspi)
+{
+}
+#endif
+
+void cfspi_xfer(struct work_struct *work)
+{
+	struct cfspi *cfspi;
+	u8 *ptr = NULL;
+	unsigned long flags;
+	int ret;
+	cfspi = container_of(work, struct cfspi, work);
+
+	/* Initialize state. */
+	cfspi->cmd = SPI_CMD_EOT;
+
+	for (;;) {
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_WAITING);
+
+		/* Wait for master talk or transmit event. */
+		wait_event_interruptible(cfspi->wait,
+				 test_bit(SPI_XFER, &cfspi->state) ||
+				 test_bit(SPI_TERMINATE, &cfspi->state));
+
+		if (test_bit(SPI_TERMINATE, &cfspi->state))
+			return;
+
+#if CFSPI_DBG_PREFILL
+		/* Prefill buffers for easier debugging. */
+		memset(cfspi->xfer.va_tx, 0xFF, SPI_DMA_BUF_LEN);
+		memset(cfspi->xfer.va_rx, 0xFF, SPI_DMA_BUF_LEN);
+#endif	/* CFSPI_DBG_PREFILL */
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_AWAKE);
+
+	/* Check whether we have a committed frame. */
+		if (cfspi->tx_cpck_len) {
+			int len;
+
+			cfspi_dbg_state(cfspi, CFSPI_STATE_FETCH_PKT);
+
+			/* Copy commited SPI frames after the SPI indication. */
+			ptr = (u8 *) cfspi->xfer.va_tx;
+			ptr += SPI_IND_SZ;
+			len = cfspi_xmitfrm(cfspi, ptr, cfspi->tx_cpck_len);
+			WARN_ON(len != cfspi->tx_cpck_len);
+	}
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_GET_NEXT);
+
+		/* Get length of next frame to commit. */
+		cfspi->tx_npck_len = cfspi_xmitlen(cfspi);
+
+		WARN_ON(cfspi->tx_npck_len > SPI_DMA_BUF_LEN);
+
+		/*
+		 * Add indication and length at the beginning of the frame,
+		 * using little endian.
+		 */
+		ptr = (u8 *) cfspi->xfer.va_tx;
+		*ptr++ = SPI_CMD_IND;
+		*ptr++ = (SPI_CMD_IND  & 0xFF00) >> 8;
+		*ptr++ = cfspi->tx_npck_len & 0x00FF;
+		*ptr++ = (cfspi->tx_npck_len & 0xFF00) >> 8;
+
+		/* Calculate length of DMAs. */
+		cfspi->xfer.tx_dma_len = cfspi->tx_cpck_len + SPI_IND_SZ;
+		cfspi->xfer.rx_dma_len = cfspi->rx_cpck_len + SPI_CMD_SZ;
+
+		/* Add SPI TX frame alignment padding, if necessary. */
+		if (cfspi->tx_cpck_len &&
+			(cfspi->xfer.tx_dma_len % spi_frm_align)) {
+
+			cfspi->xfer.tx_dma_len += spi_frm_align -
+			    (cfspi->xfer.tx_dma_len % spi_frm_align);
+		}
+
+		/* Add SPI RX frame alignment padding, if necessary. */
+		if (cfspi->rx_cpck_len &&
+			(cfspi->xfer.rx_dma_len % spi_frm_align)) {
+
+			cfspi->xfer.rx_dma_len += spi_frm_align -
+			    (cfspi->xfer.rx_dma_len % spi_frm_align);
+		}
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_INIT_XFER);
+
+		/* Start transfer. */
+		ret = cfspi->dev->init_xfer(&cfspi->xfer, cfspi->dev);
+		WARN_ON(ret);
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_ACTIVE);
+
+		/*
+		 * TODO: We might be able to make an assumption if this is the
+		 * first loop. Make sure that minimum toggle time is respected.
+		 */
+		udelay(MIN_TRANSITION_TIME_USEC);
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_ACTIVE);
+
+		/* Signal that we are ready to recieve data. */
+		cfspi->dev->sig_xfer(true, cfspi->dev);
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_XFER_DONE);
+
+		/* Wait for transfer completion. */
+		wait_for_completion(&cfspi->comp);
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_XFER_DONE);
+
+		if (cfspi->cmd == SPI_CMD_EOT) {
+			/*
+			 * Clear the master talk bit. A xfer is always at
+			 *  least two bursts.
+			 */
+			clear_bit(SPI_SS_ON, &cfspi->state);
+		}
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_INACTIVE);
+
+		/* Make sure that the minimum toggle time is respected. */
+		if (SPI_XFER_TIME_USEC(cfspi->xfer.tx_dma_len,
+					cfspi->dev->clk_mhz) <
+			MIN_TRANSITION_TIME_USEC) {
+
+			udelay(MIN_TRANSITION_TIME_USEC -
+				SPI_XFER_TIME_USEC
+				(cfspi->xfer.tx_dma_len, cfspi->dev->clk_mhz));
+		}
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_INACTIVE);
+
+		/* De-assert transfer signal. */
+		cfspi->dev->sig_xfer(false, cfspi->dev);
+
+		/* Check whether we received a CAIF packet. */
+		if (cfspi->rx_cpck_len) {
+			int len;
+
+			cfspi_dbg_state(cfspi, CFSPI_STATE_DELIVER_PKT);
+
+			/* Parse SPI frame. */
+			ptr = ((u8 *)(cfspi->xfer.va_rx + SPI_DATA_POS));
+
+			len = cfspi_rxfrm(cfspi, ptr, cfspi->rx_cpck_len);
+			WARN_ON(len != cfspi->rx_cpck_len);
+		}
+
+		/* Check the next SPI command and length. */
+		ptr = (u8 *) cfspi->xfer.va_rx;
+
+		ptr += forward_to_spi_cmd(cfspi);
+
+		cfspi->cmd = *ptr++;
+		cfspi->cmd |= ((*ptr++) << 8) & 0xFF00;
+		cfspi->rx_npck_len = *ptr++;
+		cfspi->rx_npck_len |= ((*ptr++) << 8) & 0xFF00;
+
+		WARN_ON(cfspi->rx_npck_len > SPI_DMA_BUF_LEN);
+		WARN_ON(cfspi->cmd > SPI_CMD_EOT);
+
+		debugfs_store_prev(cfspi);
+
+		/* Check whether the master issued an EOT command. */
+		if (cfspi->cmd == SPI_CMD_EOT) {
+			/* Reset state. */
+			cfspi->tx_cpck_len = 0;
+			cfspi->rx_cpck_len = 0;
+		} else {
+			/* Update state. */
+			cfspi->tx_cpck_len = cfspi->tx_npck_len;
+			cfspi->rx_cpck_len = cfspi->rx_npck_len;
+		}
+
+		/*
+		 * Check whether we need to clear the xfer bit.
+		 * Spin lock needed for packet insertion.
+		 * Test and clear of different bits
+		 * are not supported.
+		 */
+		spin_lock_irqsave(&cfspi->lock, flags);
+		if (cfspi->cmd == SPI_CMD_EOT && !cfspi_xmitlen(cfspi)
+			&& !test_bit(SPI_SS_ON, &cfspi->state))
+			clear_bit(SPI_XFER, &cfspi->state);
+
+		spin_unlock_irqrestore(&cfspi->lock, flags);
+	}
+}
+
+struct platform_driver cfspi_spi_driver = {
+	.probe = cfspi_spi_probe,
+	.remove = cfspi_spi_remove,
+	.driver = {
+		   .name = "cfspi_sspi",
+		   .owner = THIS_MODULE,
+		   },
+};
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 2c5227c..9d9e453 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -73,6 +73,15 @@
 	  This driver can also be built as a module. If so, the module will be
 	  called janz-ican3.ko.
 
+config HAVE_CAN_FLEXCAN
+	bool
+
+config CAN_FLEXCAN
+	tristate "Support for Freescale FLEXCAN based chips"
+	depends on CAN_DEV && HAVE_CAN_FLEXCAN
+	---help---
+	  Say Y here if you want to support for Freescale FlexCAN.
+
 source "drivers/net/can/mscan/Kconfig"
 
 source "drivers/net/can/sja1000/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 9047cd0..0057537 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -16,5 +16,6 @@
 obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
 obj-$(CONFIG_CAN_BFIN)		+= bfin_can.o
 obj-$(CONFIG_CAN_JANZ_ICAN3)	+= janz-ican3.o
+obj-$(CONFIG_CAN_FLEXCAN)	+= flexcan.o
 
 ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
new file mode 100644
index 0000000..ef443a0
--- /dev/null
+++ b/drivers/net/can/flexcan.c
@@ -0,0 +1,1030 @@
+/*
+ * flexcan.c - FLEXCAN CAN controller driver
+ *
+ * Copyright (c) 2005-2006 Varma Electronics Oy
+ * Copyright (c) 2009 Sascha Hauer, Pengutronix
+ * Copyright (c) 2010 Marc Kleine-Budde, Pengutronix
+ *
+ * Based on code originally by Andrey Volkov <avolkov@varma-el.com>
+ *
+ * LICENCE:
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/netdevice.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/can/platform/flexcan.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <mach/clock.h>
+
+#define DRV_NAME			"flexcan"
+
+/* 8 for RX fifo and 2 error handling */
+#define FLEXCAN_NAPI_WEIGHT		(8 + 2)
+
+/* FLEXCAN module configuration register (CANMCR) bits */
+#define FLEXCAN_MCR_MDIS		BIT(31)
+#define FLEXCAN_MCR_FRZ			BIT(30)
+#define FLEXCAN_MCR_FEN			BIT(29)
+#define FLEXCAN_MCR_HALT		BIT(28)
+#define FLEXCAN_MCR_NOT_RDY		BIT(27)
+#define FLEXCAN_MCR_WAK_MSK		BIT(26)
+#define FLEXCAN_MCR_SOFTRST		BIT(25)
+#define FLEXCAN_MCR_FRZ_ACK		BIT(24)
+#define FLEXCAN_MCR_SUPV		BIT(23)
+#define FLEXCAN_MCR_SLF_WAK		BIT(22)
+#define FLEXCAN_MCR_WRN_EN		BIT(21)
+#define FLEXCAN_MCR_LPM_ACK		BIT(20)
+#define FLEXCAN_MCR_WAK_SRC		BIT(19)
+#define FLEXCAN_MCR_DOZE		BIT(18)
+#define FLEXCAN_MCR_SRX_DIS		BIT(17)
+#define FLEXCAN_MCR_BCC			BIT(16)
+#define FLEXCAN_MCR_LPRIO_EN		BIT(13)
+#define FLEXCAN_MCR_AEN			BIT(12)
+#define FLEXCAN_MCR_MAXMB(x)		((x) & 0xf)
+#define FLEXCAN_MCR_IDAM_A		(0 << 8)
+#define FLEXCAN_MCR_IDAM_B		(1 << 8)
+#define FLEXCAN_MCR_IDAM_C		(2 << 8)
+#define FLEXCAN_MCR_IDAM_D		(3 << 8)
+
+/* FLEXCAN control register (CANCTRL) bits */
+#define FLEXCAN_CTRL_PRESDIV(x)		(((x) & 0xff) << 24)
+#define FLEXCAN_CTRL_RJW(x)		(((x) & 0x03) << 22)
+#define FLEXCAN_CTRL_PSEG1(x)		(((x) & 0x07) << 19)
+#define FLEXCAN_CTRL_PSEG2(x)		(((x) & 0x07) << 16)
+#define FLEXCAN_CTRL_BOFF_MSK		BIT(15)
+#define FLEXCAN_CTRL_ERR_MSK		BIT(14)
+#define FLEXCAN_CTRL_CLK_SRC		BIT(13)
+#define FLEXCAN_CTRL_LPB		BIT(12)
+#define FLEXCAN_CTRL_TWRN_MSK		BIT(11)
+#define FLEXCAN_CTRL_RWRN_MSK		BIT(10)
+#define FLEXCAN_CTRL_SMP		BIT(7)
+#define FLEXCAN_CTRL_BOFF_REC		BIT(6)
+#define FLEXCAN_CTRL_TSYN		BIT(5)
+#define FLEXCAN_CTRL_LBUF		BIT(4)
+#define FLEXCAN_CTRL_LOM		BIT(3)
+#define FLEXCAN_CTRL_PROPSEG(x)		((x) & 0x07)
+#define FLEXCAN_CTRL_ERR_BUS		(FLEXCAN_CTRL_ERR_MSK)
+#define FLEXCAN_CTRL_ERR_STATE \
+	(FLEXCAN_CTRL_TWRN_MSK | FLEXCAN_CTRL_RWRN_MSK | \
+	 FLEXCAN_CTRL_BOFF_MSK)
+#define FLEXCAN_CTRL_ERR_ALL \
+	(FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE)
+
+/* FLEXCAN error and status register (ESR) bits */
+#define FLEXCAN_ESR_TWRN_INT		BIT(17)
+#define FLEXCAN_ESR_RWRN_INT		BIT(16)
+#define FLEXCAN_ESR_BIT1_ERR		BIT(15)
+#define FLEXCAN_ESR_BIT0_ERR		BIT(14)
+#define FLEXCAN_ESR_ACK_ERR		BIT(13)
+#define FLEXCAN_ESR_CRC_ERR		BIT(12)
+#define FLEXCAN_ESR_FRM_ERR		BIT(11)
+#define FLEXCAN_ESR_STF_ERR		BIT(10)
+#define FLEXCAN_ESR_TX_WRN		BIT(9)
+#define FLEXCAN_ESR_RX_WRN		BIT(8)
+#define FLEXCAN_ESR_IDLE		BIT(7)
+#define FLEXCAN_ESR_TXRX		BIT(6)
+#define FLEXCAN_EST_FLT_CONF_SHIFT	(4)
+#define FLEXCAN_ESR_FLT_CONF_MASK	(0x3 << FLEXCAN_EST_FLT_CONF_SHIFT)
+#define FLEXCAN_ESR_FLT_CONF_ACTIVE	(0x0 << FLEXCAN_EST_FLT_CONF_SHIFT)
+#define FLEXCAN_ESR_FLT_CONF_PASSIVE	(0x1 << FLEXCAN_EST_FLT_CONF_SHIFT)
+#define FLEXCAN_ESR_BOFF_INT		BIT(2)
+#define FLEXCAN_ESR_ERR_INT		BIT(1)
+#define FLEXCAN_ESR_WAK_INT		BIT(0)
+#define FLEXCAN_ESR_ERR_BUS \
+	(FLEXCAN_ESR_BIT1_ERR | FLEXCAN_ESR_BIT0_ERR | \
+	 FLEXCAN_ESR_ACK_ERR | FLEXCAN_ESR_CRC_ERR | \
+	 FLEXCAN_ESR_FRM_ERR | FLEXCAN_ESR_STF_ERR)
+#define FLEXCAN_ESR_ERR_STATE \
+	(FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | FLEXCAN_ESR_BOFF_INT)
+#define FLEXCAN_ESR_ERR_ALL \
+	(FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE)
+
+/* FLEXCAN interrupt flag register (IFLAG) bits */
+#define FLEXCAN_TX_BUF_ID		8
+#define FLEXCAN_IFLAG_BUF(x)		BIT(x)
+#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW	BIT(7)
+#define FLEXCAN_IFLAG_RX_FIFO_WARN	BIT(6)
+#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE	BIT(5)
+#define FLEXCAN_IFLAG_DEFAULT \
+	(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | \
+	 FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID))
+
+/* FLEXCAN message buffers */
+#define FLEXCAN_MB_CNT_CODE(x)		(((x) & 0xf) << 24)
+#define FLEXCAN_MB_CNT_SRR		BIT(22)
+#define FLEXCAN_MB_CNT_IDE		BIT(21)
+#define FLEXCAN_MB_CNT_RTR		BIT(20)
+#define FLEXCAN_MB_CNT_LENGTH(x)	(((x) & 0xf) << 16)
+#define FLEXCAN_MB_CNT_TIMESTAMP(x)	((x) & 0xffff)
+
+#define FLEXCAN_MB_CODE_MASK		(0xf0ffffff)
+
+/* Structure of the message buffer */
+struct flexcan_mb {
+	u32 can_ctrl;
+	u32 can_id;
+	u32 data[2];
+};
+
+/* Structure of the hardware registers */
+struct flexcan_regs {
+	u32 mcr;		/* 0x00 */
+	u32 ctrl;		/* 0x04 */
+	u32 timer;		/* 0x08 */
+	u32 _reserved1;		/* 0x0c */
+	u32 rxgmask;		/* 0x10 */
+	u32 rx14mask;		/* 0x14 */
+	u32 rx15mask;		/* 0x18 */
+	u32 ecr;		/* 0x1c */
+	u32 esr;		/* 0x20 */
+	u32 imask2;		/* 0x24 */
+	u32 imask1;		/* 0x28 */
+	u32 iflag2;		/* 0x2c */
+	u32 iflag1;		/* 0x30 */
+	u32 _reserved2[19];
+	struct flexcan_mb cantxfg[64];
+};
+
+struct flexcan_priv {
+	struct can_priv can;
+	struct net_device *dev;
+	struct napi_struct napi;
+
+	void __iomem *base;
+	u32 reg_esr;
+	u32 reg_ctrl_default;
+
+	struct clk *clk;
+	struct flexcan_platform_data *pdata;
+};
+
+static struct can_bittiming_const flexcan_bittiming_const = {
+	.name = DRV_NAME,
+	.tseg1_min = 4,
+	.tseg1_max = 16,
+	.tseg2_min = 2,
+	.tseg2_max = 8,
+	.sjw_max = 4,
+	.brp_min = 1,
+	.brp_max = 256,
+	.brp_inc = 1,
+};
+
+/*
+ * Swtich transceiver on or off
+ */
+static void flexcan_transceiver_switch(const struct flexcan_priv *priv, int on)
+{
+	if (priv->pdata && priv->pdata->transceiver_switch)
+		priv->pdata->transceiver_switch(on);
+}
+
+static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
+					      u32 reg_esr)
+{
+	return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
+		(reg_esr & FLEXCAN_ESR_ERR_BUS);
+}
+
+static inline void flexcan_chip_enable(struct flexcan_priv *priv)
+{
+	struct flexcan_regs __iomem *regs = priv->base;
+	u32 reg;
+
+	reg = readl(&regs->mcr);
+	reg &= ~FLEXCAN_MCR_MDIS;
+	writel(reg, &regs->mcr);
+
+	udelay(10);
+}
+
+static inline void flexcan_chip_disable(struct flexcan_priv *priv)
+{
+	struct flexcan_regs __iomem *regs = priv->base;
+	u32 reg;
+
+	reg = readl(&regs->mcr);
+	reg |= FLEXCAN_MCR_MDIS;
+	writel(reg, &regs->mcr);
+}
+
+static int flexcan_get_berr_counter(const struct net_device *dev,
+				    struct can_berr_counter *bec)
+{
+	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->base;
+	u32 reg = readl(&regs->ecr);
+
+	bec->txerr = (reg >> 0) & 0xff;
+	bec->rxerr = (reg >> 8) & 0xff;
+
+	return 0;
+}
+
+static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	struct flexcan_regs __iomem *regs = priv->base;
+	struct can_frame *cf = (struct can_frame *)skb->data;
+	u32 can_id;
+	u32 ctrl = FLEXCAN_MB_CNT_CODE(0xc) | (cf->can_dlc << 16);
+
+	if (can_dropped_invalid_skb(dev, skb))
+		return NETDEV_TX_OK;
+
+	netif_stop_queue(dev);
+
+	if (cf->can_id & CAN_EFF_FLAG) {
+		can_id = cf->can_id & CAN_EFF_MASK;
+		ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR;
+	} else {
+		can_id = (cf->can_id & CAN_SFF_MASK) << 18;
+	}
+
+	if (cf->can_id & CAN_RTR_FLAG)
+		ctrl |= FLEXCAN_MB_CNT_RTR;
+
+	if (cf->can_dlc > 0) {
+		u32 data = be32_to_cpup((__be32 *)&cf->data[0]);
+		writel(data, &regs->cantxfg[FLEXCAN_TX_BUF_ID].data[0]);
+	}
+	if (cf->can_dlc > 3) {
+		u32 data = be32_to_cpup((__be32 *)&cf->data[4]);
+		writel(data, &regs->cantxfg[FLEXCAN_TX_BUF_ID].data[1]);
+	}
+
+	writel(can_id, &regs->cantxfg[FLEXCAN_TX_BUF_ID].can_id);
+	writel(ctrl, &regs->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
+
+	kfree_skb(skb);
+
+	/* tx_packets is incremented in flexcan_irq */
+	stats->tx_bytes += cf->can_dlc;
+
+	return NETDEV_TX_OK;
+}
+
+static void do_bus_err(struct net_device *dev,
+		       struct can_frame *cf, u32 reg_esr)
+{
+	struct flexcan_priv *priv = netdev_priv(dev);
+	int rx_errors = 0, tx_errors = 0;
+
+	cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+
+	if (reg_esr & FLEXCAN_ESR_BIT1_ERR) {
+		dev_dbg(dev->dev.parent, "BIT1_ERR irq\n");
+		cf->data[2] |= CAN_ERR_PROT_BIT1;
+		tx_errors = 1;
+	}
+	if (reg_esr & FLEXCAN_ESR_BIT0_ERR) {
+		dev_dbg(dev->dev.parent, "BIT0_ERR irq\n");
+		cf->data[2] |= CAN_ERR_PROT_BIT0;
+		tx_errors = 1;
+	}
+	if (reg_esr & FLEXCAN_ESR_ACK_ERR) {
+		dev_dbg(dev->dev.parent, "ACK_ERR irq\n");
+		cf->can_id |= CAN_ERR_ACK;
+		cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
+		tx_errors = 1;
+	}
+	if (reg_esr & FLEXCAN_ESR_CRC_ERR) {
+		dev_dbg(dev->dev.parent, "CRC_ERR irq\n");
+		cf->data[2] |= CAN_ERR_PROT_BIT;
+		cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+		rx_errors = 1;
+	}
+	if (reg_esr & FLEXCAN_ESR_FRM_ERR) {
+		dev_dbg(dev->dev.parent, "FRM_ERR irq\n");
+		cf->data[2] |= CAN_ERR_PROT_FORM;
+		rx_errors = 1;
+	}
+	if (reg_esr & FLEXCAN_ESR_STF_ERR) {
+		dev_dbg(dev->dev.parent, "STF_ERR irq\n");
+		cf->data[2] |= CAN_ERR_PROT_STUFF;
+		rx_errors = 1;
+	}
+
+	priv->can.can_stats.bus_error++;
+	if (rx_errors)
+		dev->stats.rx_errors++;
+	if (tx_errors)
+		dev->stats.tx_errors++;
+}
+
+static int flexcan_poll_bus_err(struct net_device *dev, u32 reg_esr)
+{
+	struct sk_buff *skb;
+	struct can_frame *cf;
+
+	skb = alloc_can_err_skb(dev, &cf);
+	if (unlikely(!skb))
+		return 0;
+
+	do_bus_err(dev, cf, reg_esr);
+	netif_receive_skb(skb);
+
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += cf->can_dlc;
+
+	return 1;
+}
+
+static void do_state(struct net_device *dev,
+		     struct can_frame *cf, enum can_state new_state)
+{
+	struct flexcan_priv *priv = netdev_priv(dev);
+	struct can_berr_counter bec;
+
+	flexcan_get_berr_counter(dev, &bec);
+
+	switch (priv->can.state) {
+	case CAN_STATE_ERROR_ACTIVE:
+		/*
+		 * from: ERROR_ACTIVE
+		 * to  : ERROR_WARNING, ERROR_PASSIVE, BUS_OFF
+		 * =>  : there was a warning int
+		 */
+		if (new_state >= CAN_STATE_ERROR_WARNING &&
+		    new_state <= CAN_STATE_BUS_OFF) {
+			dev_dbg(dev->dev.parent, "Error Warning IRQ\n");
+			priv->can.can_stats.error_warning++;
+
+			cf->can_id |= CAN_ERR_CRTL;
+			cf->data[1] = (bec.txerr > bec.rxerr) ?
+				CAN_ERR_CRTL_TX_WARNING :
+				CAN_ERR_CRTL_RX_WARNING;
+		}
+	case CAN_STATE_ERROR_WARNING:	/* fallthrough */
+		/*
+		 * from: ERROR_ACTIVE, ERROR_WARNING
+		 * to  : ERROR_PASSIVE, BUS_OFF
+		 * =>  : error passive int
+		 */
+		if (new_state >= CAN_STATE_ERROR_PASSIVE &&
+		    new_state <= CAN_STATE_BUS_OFF) {
+			dev_dbg(dev->dev.parent, "Error Passive IRQ\n");
+			priv->can.can_stats.error_passive++;
+
+			cf->can_id |= CAN_ERR_CRTL;
+			cf->data[1] = (bec.txerr > bec.rxerr) ?
+				CAN_ERR_CRTL_TX_PASSIVE :
+				CAN_ERR_CRTL_RX_PASSIVE;
+		}
+		break;
+	case CAN_STATE_BUS_OFF:
+		dev_err(dev->dev.parent,
+			"BUG! hardware recovered automatically from BUS_OFF\n");
+		break;
+	default:
+		break;
+	}
+
+	/* process state changes depending on the new state */
+	switch (new_state) {
+	case CAN_STATE_ERROR_ACTIVE:
+		dev_dbg(dev->dev.parent, "Error Active\n");
+		cf->can_id |= CAN_ERR_PROT;
+		cf->data[2] = CAN_ERR_PROT_ACTIVE;
+		break;
+	case CAN_STATE_BUS_OFF:
+		cf->can_id |= CAN_ERR_BUSOFF;
+		can_bus_off(dev);
+		break;
+	default:
+		break;
+	}
+}
+
+static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
+{
+	struct flexcan_priv *priv = netdev_priv(dev);
+	struct sk_buff *skb;
+	struct can_frame *cf;
+	enum can_state new_state;
+	int flt;
+
+	flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK;
+	if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) {
+		if (likely(!(reg_esr & (FLEXCAN_ESR_TX_WRN |
+					FLEXCAN_ESR_RX_WRN))))
+			new_state = CAN_STATE_ERROR_ACTIVE;
+		else
+			new_state = CAN_STATE_ERROR_WARNING;
+	} else if (unlikely(flt == FLEXCAN_ESR_FLT_CONF_PASSIVE))
+		new_state = CAN_STATE_ERROR_PASSIVE;
+	else
+		new_state = CAN_STATE_BUS_OFF;
+
+	/* state hasn't changed */
+	if (likely(new_state == priv->can.state))
+		return 0;
+
+	skb = alloc_can_err_skb(dev, &cf);
+	if (unlikely(!skb))
+		return 0;
+
+	do_state(dev, cf, new_state);
+	priv->can.state = new_state;
+	netif_receive_skb(skb);
+
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += cf->can_dlc;
+
+	return 1;
+}
+
+static void flexcan_read_fifo(const struct net_device *dev,
+			      struct can_frame *cf)
+{
+	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->base;
+	struct flexcan_mb __iomem *mb = &regs->cantxfg[0];
+	u32 reg_ctrl, reg_id;
+
+	reg_ctrl = readl(&mb->can_ctrl);
+	reg_id = readl(&mb->can_id);
+	if (reg_ctrl & FLEXCAN_MB_CNT_IDE)
+		cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
+	else
+		cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
+
+	if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
+		cf->can_id |= CAN_RTR_FLAG;
+	cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
+
+	*(__be32 *)(cf->data + 0) = cpu_to_be32(readl(&mb->data[0]));
+	*(__be32 *)(cf->data + 4) = cpu_to_be32(readl(&mb->data[1]));
+
+	/* mark as read */
+	writel(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->iflag1);
+	readl(&regs->timer);
+}
+
+static int flexcan_read_frame(struct net_device *dev)
+{
+	struct net_device_stats *stats = &dev->stats;
+	struct can_frame *cf;
+	struct sk_buff *skb;
+
+	skb = alloc_can_skb(dev, &cf);
+	if (unlikely(!skb)) {
+		stats->rx_dropped++;
+		return 0;
+	}
+
+	flexcan_read_fifo(dev, cf);
+	netif_receive_skb(skb);
+
+	stats->rx_packets++;
+	stats->rx_bytes += cf->can_dlc;
+
+	return 1;
+}
+
+static int flexcan_poll(struct napi_struct *napi, int quota)
+{
+	struct net_device *dev = napi->dev;
+	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->base;
+	u32 reg_iflag1, reg_esr;
+	int work_done = 0;
+
+	/*
+	 * The error bits are cleared on read,
+	 * use saved value from irq handler.
+	 */
+	reg_esr = readl(&regs->esr) | priv->reg_esr;
+
+	/* handle state changes */
+	work_done += flexcan_poll_state(dev, reg_esr);
+
+	/* handle RX-FIFO */
+	reg_iflag1 = readl(&regs->iflag1);
+	while (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE &&
+	       work_done < quota) {
+		work_done += flexcan_read_frame(dev);
+		reg_iflag1 = readl(&regs->iflag1);
+	}
+
+	/* report bus errors */
+	if (flexcan_has_and_handle_berr(priv, reg_esr) && work_done < quota)
+		work_done += flexcan_poll_bus_err(dev, reg_esr);
+
+	if (work_done < quota) {
+		napi_complete(napi);
+		/* enable IRQs */
+		writel(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+		writel(priv->reg_ctrl_default, &regs->ctrl);
+	}
+
+	return work_done;
+}
+
+static irqreturn_t flexcan_irq(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct net_device_stats *stats = &dev->stats;
+	struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->base;
+	u32 reg_iflag1, reg_esr;
+
+	reg_iflag1 = readl(&regs->iflag1);
+	reg_esr = readl(&regs->esr);
+	writel(FLEXCAN_ESR_ERR_INT, &regs->esr);	/* ACK err IRQ */
+
+	/*
+	 * schedule NAPI in case of:
+	 * - rx IRQ
+	 * - state change IRQ
+	 * - bus error IRQ and bus error reporting is activated
+	 */
+	if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) ||
+	    (reg_esr & FLEXCAN_ESR_ERR_STATE) ||
+	    flexcan_has_and_handle_berr(priv, reg_esr)) {
+		/*
+		 * The error bits are cleared on read,
+		 * save them for later use.
+		 */
+		priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
+		writel(FLEXCAN_IFLAG_DEFAULT & ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE,
+		       &regs->imask1);
+		writel(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
+		       &regs->ctrl);
+		napi_schedule(&priv->napi);
+	}
+
+	/* FIFO overflow */
+	if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
+		writel(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, &regs->iflag1);
+		dev->stats.rx_over_errors++;
+		dev->stats.rx_errors++;
+	}
+
+	/* transmission complete interrupt */
+	if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
+		/* tx_bytes is incremented in flexcan_start_xmit */
+		stats->tx_packets++;
+		writel((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1);
+		netif_wake_queue(dev);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void flexcan_set_bittiming(struct net_device *dev)
+{
+	const struct flexcan_priv *priv = netdev_priv(dev);
+	const struct can_bittiming *bt = &priv->can.bittiming;
+	struct flexcan_regs __iomem *regs = priv->base;
+	u32 reg;
+
+	reg = readl(&regs->ctrl);
+	reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) |
+		 FLEXCAN_CTRL_RJW(0x3) |
+		 FLEXCAN_CTRL_PSEG1(0x7) |
+		 FLEXCAN_CTRL_PSEG2(0x7) |
+		 FLEXCAN_CTRL_PROPSEG(0x7) |
+		 FLEXCAN_CTRL_LPB |
+		 FLEXCAN_CTRL_SMP |
+		 FLEXCAN_CTRL_LOM);
+
+	reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) |
+		FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) |
+		FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) |
+		FLEXCAN_CTRL_RJW(bt->sjw - 1) |
+		FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1);
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
+		reg |= FLEXCAN_CTRL_LPB;
+	if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+		reg |= FLEXCAN_CTRL_LOM;
+	if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+		reg |= FLEXCAN_CTRL_SMP;
+
+	dev_info(dev->dev.parent, "writing ctrl=0x%08x\n", reg);
+	writel(reg, &regs->ctrl);
+
+	/* print chip status */
+	dev_dbg(dev->dev.parent, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
+		readl(&regs->mcr), readl(&regs->ctrl));
+}
+
+/*
+ * flexcan_chip_start
+ *
+ * this functions is entered with clocks enabled
+ *
+ */
+static int flexcan_chip_start(struct net_device *dev)
+{
+	struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->base;
+	unsigned int i;
+	int err;
+	u32 reg_mcr, reg_ctrl;
+
+	/* enable module */
+	flexcan_chip_enable(priv);
+
+	/* soft reset */
+	writel(FLEXCAN_MCR_SOFTRST, &regs->mcr);
+	udelay(10);
+
+	reg_mcr = readl(&regs->mcr);
+	if (reg_mcr & FLEXCAN_MCR_SOFTRST) {
+		dev_err(dev->dev.parent,
+			"Failed to softreset can module (mcr=0x%08x)\n",
+			reg_mcr);
+		err = -ENODEV;
+		goto out;
+	}
+
+	flexcan_set_bittiming(dev);
+
+	/*
+	 * MCR
+	 *
+	 * enable freeze
+	 * enable fifo
+	 * halt now
+	 * only supervisor access
+	 * enable warning int
+	 * choose format C
+	 *
+	 */
+	reg_mcr = readl(&regs->mcr);
+	reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
+		FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
+		FLEXCAN_MCR_IDAM_C;
+	dev_dbg(dev->dev.parent, "%s: writing mcr=0x%08x", __func__, reg_mcr);
+	writel(reg_mcr, &regs->mcr);
+
+	/*
+	 * CTRL
+	 *
+	 * disable timer sync feature
+	 *
+	 * disable auto busoff recovery
+	 * transmit lowest buffer first
+	 *
+	 * enable tx and rx warning interrupt
+	 * enable bus off interrupt
+	 * (== FLEXCAN_CTRL_ERR_STATE)
+	 *
+	 * _note_: we enable the "error interrupt"
+	 * (FLEXCAN_CTRL_ERR_MSK), too. Otherwise we don't get any
+	 * warning or bus passive interrupts.
+	 */
+	reg_ctrl = readl(&regs->ctrl);
+	reg_ctrl &= ~FLEXCAN_CTRL_TSYN;
+	reg_ctrl |= FLEXCAN_CTRL_BOFF_REC | FLEXCAN_CTRL_LBUF |
+		FLEXCAN_CTRL_ERR_STATE | FLEXCAN_CTRL_ERR_MSK;
+
+	/* save for later use */
+	priv->reg_ctrl_default = reg_ctrl;
+	dev_dbg(dev->dev.parent, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
+	writel(reg_ctrl, &regs->ctrl);
+
+	for (i = 0; i < ARRAY_SIZE(regs->cantxfg); i++) {
+		writel(0, &regs->cantxfg[i].can_ctrl);
+		writel(0, &regs->cantxfg[i].can_id);
+		writel(0, &regs->cantxfg[i].data[0]);
+		writel(0, &regs->cantxfg[i].data[1]);
+
+		/* put MB into rx queue */
+		writel(FLEXCAN_MB_CNT_CODE(0x4), &regs->cantxfg[i].can_ctrl);
+	}
+
+	/* acceptance mask/acceptance code (accept everything) */
+	writel(0x0, &regs->rxgmask);
+	writel(0x0, &regs->rx14mask);
+	writel(0x0, &regs->rx15mask);
+
+	flexcan_transceiver_switch(priv, 1);
+
+	/* synchronize with the can bus */
+	reg_mcr = readl(&regs->mcr);
+	reg_mcr &= ~FLEXCAN_MCR_HALT;
+	writel(reg_mcr, &regs->mcr);
+
+	priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+	/* enable FIFO interrupts */
+	writel(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+
+	/* print chip status */
+	dev_dbg(dev->dev.parent, "%s: reading mcr=0x%08x ctrl=0x%08x\n",
+		__func__, readl(&regs->mcr), readl(&regs->ctrl));
+
+	return 0;
+
+ out:
+	flexcan_chip_disable(priv);
+	return err;
+}
+
+/*
+ * flexcan_chip_stop
+ *
+ * this functions is entered with clocks enabled
+ *
+ */
+static void flexcan_chip_stop(struct net_device *dev)
+{
+	struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->base;
+	u32 reg;
+
+	/* Disable all interrupts */
+	writel(0, &regs->imask1);
+
+	/* Disable + halt module */
+	reg = readl(&regs->mcr);
+	reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT;
+	writel(reg, &regs->mcr);
+
+	flexcan_transceiver_switch(priv, 0);
+	priv->can.state = CAN_STATE_STOPPED;
+
+	return;
+}
+
+static int flexcan_open(struct net_device *dev)
+{
+	struct flexcan_priv *priv = netdev_priv(dev);
+	int err;
+
+	clk_enable(priv->clk);
+
+	err = open_candev(dev);
+	if (err)
+		goto out;
+
+	err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
+	if (err)
+		goto out_close;
+
+	/* start chip and queuing */
+	err = flexcan_chip_start(dev);
+	if (err)
+		goto out_close;
+	napi_enable(&priv->napi);
+	netif_start_queue(dev);
+
+	return 0;
+
+ out_close:
+	close_candev(dev);
+ out:
+	clk_disable(priv->clk);
+
+	return err;
+}
+
+static int flexcan_close(struct net_device *dev)
+{
+	struct flexcan_priv *priv = netdev_priv(dev);
+
+	netif_stop_queue(dev);
+	napi_disable(&priv->napi);
+	flexcan_chip_stop(dev);
+
+	free_irq(dev->irq, dev);
+	clk_disable(priv->clk);
+
+	close_candev(dev);
+
+	return 0;
+}
+
+static int flexcan_set_mode(struct net_device *dev, enum can_mode mode)
+{
+	int err;
+
+	switch (mode) {
+	case CAN_MODE_START:
+		err = flexcan_chip_start(dev);
+		if (err)
+			return err;
+
+		netif_wake_queue(dev);
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static const struct net_device_ops flexcan_netdev_ops = {
+	.ndo_open	= flexcan_open,
+	.ndo_stop	= flexcan_close,
+	.ndo_start_xmit	= flexcan_start_xmit,
+};
+
+static int __devinit register_flexcandev(struct net_device *dev)
+{
+	struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->base;
+	u32 reg, err;
+
+	clk_enable(priv->clk);
+
+	/* select "bus clock", chip must be disabled */
+	flexcan_chip_disable(priv);
+	reg = readl(&regs->ctrl);
+	reg |= FLEXCAN_CTRL_CLK_SRC;
+	writel(reg, &regs->ctrl);
+
+	flexcan_chip_enable(priv);
+
+	/* set freeze, halt and activate FIFO, restrict register access */
+	reg = readl(&regs->mcr);
+	reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
+		FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
+	writel(reg, &regs->mcr);
+
+	/*
+	 * Currently we only support newer versions of this core
+	 * featuring a RX FIFO. Older cores found on some Coldfire
+	 * derivates are not yet supported.
+	 */
+	reg = readl(&regs->mcr);
+	if (!(reg & FLEXCAN_MCR_FEN)) {
+		dev_err(dev->dev.parent,
+			"Could not enable RX FIFO, unsupported core\n");
+		err = -ENODEV;
+		goto out;
+	}
+
+	err = register_candev(dev);
+
+ out:
+	/* disable core and turn off clocks */
+	flexcan_chip_disable(priv);
+	clk_disable(priv->clk);
+
+	return err;
+}
+
+static void __devexit unregister_flexcandev(struct net_device *dev)
+{
+	unregister_candev(dev);
+}
+
+static int __devinit flexcan_probe(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	struct flexcan_priv *priv;
+	struct resource *mem;
+	struct clk *clk;
+	void __iomem *base;
+	resource_size_t mem_size;
+	int err, irq;
+
+	clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "no clock defined\n");
+		err = PTR_ERR(clk);
+		goto failed_clock;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+	if (!mem || irq <= 0) {
+		err = -ENODEV;
+		goto failed_get;
+	}
+
+	mem_size = resource_size(mem);
+	if (!request_mem_region(mem->start, mem_size, pdev->name)) {
+		err = -EBUSY;
+		goto failed_req;
+	}
+
+	base = ioremap(mem->start, mem_size);
+	if (!base) {
+		err = -ENOMEM;
+		goto failed_map;
+	}
+
+	dev = alloc_candev(sizeof(struct flexcan_priv), 0);
+	if (!dev) {
+		err = -ENOMEM;
+		goto failed_alloc;
+	}
+
+	dev->netdev_ops = &flexcan_netdev_ops;
+	dev->irq = irq;
+	dev->flags |= IFF_ECHO; /* we support local echo in hardware */
+
+	priv = netdev_priv(dev);
+	priv->can.clock.freq = clk_get_rate(clk);
+	priv->can.bittiming_const = &flexcan_bittiming_const;
+	priv->can.do_set_mode = flexcan_set_mode;
+	priv->can.do_get_berr_counter = flexcan_get_berr_counter;
+	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+		CAN_CTRLMODE_LISTENONLY	| CAN_CTRLMODE_3_SAMPLES |
+		CAN_CTRLMODE_BERR_REPORTING;
+	priv->base = base;
+	priv->dev = dev;
+	priv->clk = clk;
+	priv->pdata = pdev->dev.platform_data;
+
+	netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT);
+
+	dev_set_drvdata(&pdev->dev, dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	err = register_flexcandev(dev);
+	if (err) {
+		dev_err(&pdev->dev, "registering netdev failed\n");
+		goto failed_register;
+	}
+
+	dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
+		 priv->base, dev->irq);
+
+	return 0;
+
+ failed_register:
+	free_candev(dev);
+ failed_alloc:
+	iounmap(base);
+ failed_map:
+	release_mem_region(mem->start, mem_size);
+ failed_req:
+	clk_put(clk);
+ failed_get:
+ failed_clock:
+	return err;
+}
+
+static int __devexit flexcan_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct flexcan_priv *priv = netdev_priv(dev);
+	struct resource *mem;
+
+	unregister_flexcandev(dev);
+	platform_set_drvdata(pdev, NULL);
+	free_candev(dev);
+	iounmap(priv->base);
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, resource_size(mem));
+
+	clk_put(priv->clk);
+
+	return 0;
+}
+
+static struct platform_driver flexcan_driver = {
+	.driver.name = DRV_NAME,
+	.probe = flexcan_probe,
+	.remove = __devexit_p(flexcan_remove),
+};
+
+static int __init flexcan_init(void)
+{
+	pr_info("%s netdevice driver\n", DRV_NAME);
+	return platform_driver_register(&flexcan_driver);
+}
+
+static void __exit flexcan_exit(void)
+{
+	platform_driver_unregister(&flexcan_driver);
+	pr_info("%s: driver removed\n", DRV_NAME);
+}
+
+module_init(flexcan_init);
+module_exit(flexcan_exit);
+
+MODULE_AUTHOR("Sascha Hauer <kernel@pengutronix.de>, "
+	      "Marc Kleine-Budde <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN port driver for flexcan based chip");
diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h
index 4ff9664..b43e9f5 100644
--- a/drivers/net/can/mscan/mscan.h
+++ b/drivers/net/can/mscan/mscan.h
@@ -227,7 +227,7 @@
 		u16 time;			/* + 0x7c     0x3e */
 	} tx;
 	_MSCAN_RESERVED_(32, 2);		/* + 0x7e          */
-} __attribute__ ((packed));
+} __packed;
 
 #undef _MSCAN_RESERVED_
 #define MSCAN_REGION 	sizeof(struct mscan)
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index 97ff6fe..0452549 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -7,4 +7,10 @@
 	  This driver is for the one channel CPC-USB/ARM7 CAN/USB interface
 	  from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
 
+config CAN_ESD_USB2
+        tristate "ESD USB/2 CAN/USB interface"
+        ---help---
+          This driver supports the CAN-USB/2 interface
+          from esd electronic system design gmbh (http://www.esd.eu).
+
 endmenu
diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
index 0afd51d..fce3cf1 100644
--- a/drivers/net/can/usb/Makefile
+++ b/drivers/net/can/usb/Makefile
@@ -3,5 +3,6 @@
 #
 
 obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
+obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
 
 ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 1fc0871..e75f1a8 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -197,7 +197,7 @@
 };
 
 /* Main message type used between library and application */
-struct __attribute__ ((packed)) ems_cpc_msg {
+struct __packed ems_cpc_msg {
 	u8 type;	/* type of message */
 	u8 length;	/* length of data within union 'msg' */
 	u8 msgid;	/* confirmation handle */
diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c
new file mode 100644
index 0000000..05a5275
--- /dev/null
+++ b/drivers/net/can/usb/esd_usb2.c
@@ -0,0 +1,1132 @@
+/*
+ * CAN driver for esd CAN-USB/2
+ *
+ * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd.eu>");
+MODULE_DESCRIPTION("CAN driver for esd CAN-USB/2 interfaces");
+MODULE_LICENSE("GPL v2");
+
+/* Define these values to match your devices */
+#define USB_ESDGMBH_VENDOR_ID	0x0ab4
+#define USB_CANUSB2_PRODUCT_ID	0x0010
+
+#define ESD_USB2_CAN_CLOCK	60000000
+#define ESD_USB2_MAX_NETS	2
+
+/* USB2 commands */
+#define CMD_VERSION		1 /* also used for VERSION_REPLY */
+#define CMD_CAN_RX		2 /* device to host only */
+#define CMD_CAN_TX		3 /* also used for TX_DONE */
+#define CMD_SETBAUD		4 /* also used for SETBAUD_REPLY */
+#define CMD_TS			5 /* also used for TS_REPLY */
+#define CMD_IDADD		6 /* also used for IDADD_REPLY */
+
+/* esd CAN message flags - dlc field */
+#define ESD_RTR			0x10
+
+/* esd CAN message flags - id field */
+#define ESD_EXTID		0x20000000
+#define ESD_EVENT		0x40000000
+#define ESD_IDMASK		0x1fffffff
+
+/* esd CAN event ids used by this driver */
+#define ESD_EV_CAN_ERROR_EXT	2
+
+/* baudrate message flags */
+#define ESD_USB2_UBR		0x80000000
+#define ESD_USB2_LOM		0x40000000
+#define ESD_USB2_NO_BAUDRATE	0x7fffffff
+#define ESD_USB2_TSEG1_MIN	1
+#define ESD_USB2_TSEG1_MAX	16
+#define ESD_USB2_TSEG1_SHIFT	16
+#define ESD_USB2_TSEG2_MIN	1
+#define ESD_USB2_TSEG2_MAX	8
+#define ESD_USB2_TSEG2_SHIFT	20
+#define ESD_USB2_SJW_MAX	4
+#define ESD_USB2_SJW_SHIFT	14
+#define ESD_USB2_BRP_MIN	1
+#define ESD_USB2_BRP_MAX	1024
+#define ESD_USB2_BRP_INC	1
+#define ESD_USB2_3_SAMPLES	0x00800000
+
+/* esd IDADD message */
+#define ESD_ID_ENABLE		0x80
+#define ESD_MAX_ID_SEGMENT	64
+
+/* SJA1000 ECC register (emulated by usb2 firmware) */
+#define SJA1000_ECC_SEG		0x1F
+#define SJA1000_ECC_DIR		0x20
+#define SJA1000_ECC_ERR		0x06
+#define SJA1000_ECC_BIT		0x00
+#define SJA1000_ECC_FORM	0x40
+#define SJA1000_ECC_STUFF	0x80
+#define SJA1000_ECC_MASK	0xc0
+
+/* esd bus state event codes */
+#define ESD_BUSSTATE_MASK	0xc0
+#define ESD_BUSSTATE_WARN	0x40
+#define ESD_BUSSTATE_ERRPASSIVE	0x80
+#define ESD_BUSSTATE_BUSOFF	0xc0
+
+#define RX_BUFFER_SIZE		1024
+#define MAX_RX_URBS		4
+#define MAX_TX_URBS		16 /* must be power of 2 */
+
+struct header_msg {
+	u8 len; /* len is always the total message length in 32bit words */
+	u8 cmd;
+	u8 rsvd[2];
+};
+
+struct version_msg {
+	u8 len;
+	u8 cmd;
+	u8 rsvd;
+	u8 flags;
+	__le32 drv_version;
+};
+
+struct version_reply_msg {
+	u8 len;
+	u8 cmd;
+	u8 nets;
+	u8 features;
+	__le32 version;
+	u8 name[16];
+	__le32 rsvd;
+	__le32 ts;
+};
+
+struct rx_msg {
+	u8 len;
+	u8 cmd;
+	u8 net;
+	u8 dlc;
+	__le32 ts;
+	__le32 id; /* upper 3 bits contain flags */
+	u8 data[8];
+};
+
+struct tx_msg {
+	u8 len;
+	u8 cmd;
+	u8 net;
+	u8 dlc;
+	__le32 hnd;
+	__le32 id; /* upper 3 bits contain flags */
+	u8 data[8];
+};
+
+struct tx_done_msg {
+	u8 len;
+	u8 cmd;
+	u8 net;
+	u8 status;
+	__le32 hnd;
+	__le32 ts;
+};
+
+struct id_filter_msg {
+	u8 len;
+	u8 cmd;
+	u8 net;
+	u8 option;
+	__le32 mask[ESD_MAX_ID_SEGMENT + 1];
+};
+
+struct set_baudrate_msg {
+	u8 len;
+	u8 cmd;
+	u8 net;
+	u8 rsvd;
+	__le32 baud;
+};
+
+/* Main message type used between library and application */
+struct __attribute__ ((packed)) esd_usb2_msg {
+	union {
+		struct header_msg hdr;
+		struct version_msg version;
+		struct version_reply_msg version_reply;
+		struct rx_msg rx;
+		struct tx_msg tx;
+		struct tx_done_msg txdone;
+		struct set_baudrate_msg setbaud;
+		struct id_filter_msg filter;
+	} msg;
+};
+
+static struct usb_device_id esd_usb2_table[] = {
+	{USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, esd_usb2_table);
+
+struct esd_usb2_net_priv;
+
+struct esd_tx_urb_context {
+	struct esd_usb2_net_priv *priv;
+	u32 echo_index;
+	int dlc;
+};
+
+struct esd_usb2 {
+	struct usb_device *udev;
+	struct esd_usb2_net_priv *nets[ESD_USB2_MAX_NETS];
+
+	struct usb_anchor rx_submitted;
+
+	int net_count;
+	u32 version;
+	int rxinitdone;
+};
+
+struct esd_usb2_net_priv {
+	struct can_priv can; /* must be the first member */
+
+	atomic_t active_tx_jobs;
+	struct usb_anchor tx_submitted;
+	struct esd_tx_urb_context tx_contexts[MAX_TX_URBS];
+
+	int open_time;
+	struct esd_usb2 *usb2;
+	struct net_device *netdev;
+	int index;
+	u8 old_state;
+	struct can_berr_counter bec;
+};
+
+static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
+			      struct esd_usb2_msg *msg)
+{
+	struct net_device_stats *stats = &priv->netdev->stats;
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	u32 id = le32_to_cpu(msg->msg.rx.id) & ESD_IDMASK;
+
+	if (id == ESD_EV_CAN_ERROR_EXT) {
+		u8 state = msg->msg.rx.data[0];
+		u8 ecc = msg->msg.rx.data[1];
+		u8 txerr = msg->msg.rx.data[2];
+		u8 rxerr = msg->msg.rx.data[3];
+
+		skb = alloc_can_err_skb(priv->netdev, &cf);
+		if (skb == NULL) {
+			stats->rx_dropped++;
+			return;
+		}
+
+		if (state != priv->old_state) {
+			priv->old_state = state;
+
+			switch (state & ESD_BUSSTATE_MASK) {
+			case ESD_BUSSTATE_BUSOFF:
+				priv->can.state = CAN_STATE_BUS_OFF;
+				cf->can_id |= CAN_ERR_BUSOFF;
+				can_bus_off(priv->netdev);
+				break;
+			case ESD_BUSSTATE_WARN:
+				priv->can.state = CAN_STATE_ERROR_WARNING;
+				priv->can.can_stats.error_warning++;
+				break;
+			case ESD_BUSSTATE_ERRPASSIVE:
+				priv->can.state = CAN_STATE_ERROR_PASSIVE;
+				priv->can.can_stats.error_passive++;
+				break;
+			default:
+				priv->can.state = CAN_STATE_ERROR_ACTIVE;
+				break;
+			}
+		} else {
+			priv->can.can_stats.bus_error++;
+			stats->rx_errors++;
+
+			cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+
+			switch (ecc & SJA1000_ECC_MASK) {
+			case SJA1000_ECC_BIT:
+				cf->data[2] |= CAN_ERR_PROT_BIT;
+				break;
+			case SJA1000_ECC_FORM:
+				cf->data[2] |= CAN_ERR_PROT_FORM;
+				break;
+			case SJA1000_ECC_STUFF:
+				cf->data[2] |= CAN_ERR_PROT_STUFF;
+				break;
+			default:
+				cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+				cf->data[3] = ecc & SJA1000_ECC_SEG;
+				break;
+			}
+
+			/* Error occured during transmission? */
+			if (!(ecc & SJA1000_ECC_DIR))
+				cf->data[2] |= CAN_ERR_PROT_TX;
+
+			if (priv->can.state == CAN_STATE_ERROR_WARNING ||
+			    priv->can.state == CAN_STATE_ERROR_PASSIVE) {
+				cf->data[1] = (txerr > rxerr) ?
+					CAN_ERR_CRTL_TX_PASSIVE :
+					CAN_ERR_CRTL_RX_PASSIVE;
+			}
+			cf->data[6] = txerr;
+			cf->data[7] = rxerr;
+		}
+
+		netif_rx(skb);
+
+		priv->bec.txerr = txerr;
+		priv->bec.rxerr = rxerr;
+
+		stats->rx_packets++;
+		stats->rx_bytes += cf->can_dlc;
+	}
+}
+
+static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
+				struct esd_usb2_msg *msg)
+{
+	struct net_device_stats *stats = &priv->netdev->stats;
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	int i;
+	u32 id;
+
+	if (!netif_device_present(priv->netdev))
+		return;
+
+	id = le32_to_cpu(msg->msg.rx.id);
+
+	if (id & ESD_EVENT) {
+		esd_usb2_rx_event(priv, msg);
+	} else {
+		skb = alloc_can_skb(priv->netdev, &cf);
+		if (skb == NULL) {
+			stats->rx_dropped++;
+			return;
+		}
+
+		cf->can_id = id & ESD_IDMASK;
+		cf->can_dlc = get_can_dlc(msg->msg.rx.dlc);
+
+		if (id & ESD_EXTID)
+			cf->can_id |= CAN_EFF_FLAG;
+
+		if (msg->msg.rx.dlc & ESD_RTR) {
+			cf->can_id |= CAN_RTR_FLAG;
+		} else {
+			for (i = 0; i < cf->can_dlc; i++)
+				cf->data[i] = msg->msg.rx.data[i];
+		}
+
+		netif_rx(skb);
+
+		stats->rx_packets++;
+		stats->rx_bytes += cf->can_dlc;
+	}
+
+	return;
+}
+
+static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv,
+				 struct esd_usb2_msg *msg)
+{
+	struct net_device_stats *stats = &priv->netdev->stats;
+	struct net_device *netdev = priv->netdev;
+	struct esd_tx_urb_context *context;
+
+	if (!netif_device_present(netdev))
+		return;
+
+	context = &priv->tx_contexts[msg->msg.txdone.hnd & (MAX_TX_URBS - 1)];
+
+	if (!msg->msg.txdone.status) {
+		stats->tx_packets++;
+		stats->tx_bytes += context->dlc;
+		can_get_echo_skb(netdev, context->echo_index);
+	} else {
+		stats->tx_errors++;
+		can_free_echo_skb(netdev, context->echo_index);
+	}
+
+	/* Release context */
+	context->echo_index = MAX_TX_URBS;
+	atomic_dec(&priv->active_tx_jobs);
+
+	netif_wake_queue(netdev);
+}
+
+static void esd_usb2_read_bulk_callback(struct urb *urb)
+{
+	struct esd_usb2 *dev = urb->context;
+	int retval;
+	int pos = 0;
+	int i;
+
+	switch (urb->status) {
+	case 0: /* success */
+		break;
+
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+
+	default:
+		dev_info(dev->udev->dev.parent,
+			 "Rx URB aborted (%d)\n", urb->status);
+		goto resubmit_urb;
+	}
+
+	while (pos < urb->actual_length) {
+		struct esd_usb2_msg *msg;
+
+		msg = (struct esd_usb2_msg *)(urb->transfer_buffer + pos);
+
+		switch (msg->msg.hdr.cmd) {
+		case CMD_CAN_RX:
+			esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
+			break;
+
+		case CMD_CAN_TX:
+			esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net],
+					     msg);
+			break;
+		}
+
+		pos += msg->msg.hdr.len << 2;
+
+		if (pos > urb->actual_length) {
+			dev_err(dev->udev->dev.parent, "format error\n");
+			break;
+		}
+	}
+
+resubmit_urb:
+	usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
+			  urb->transfer_buffer, RX_BUFFER_SIZE,
+			  esd_usb2_read_bulk_callback, dev);
+
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval == -ENODEV) {
+		for (i = 0; i < dev->net_count; i++) {
+			if (dev->nets[i])
+				netif_device_detach(dev->nets[i]->netdev);
+		}
+	} else if (retval) {
+		dev_err(dev->udev->dev.parent,
+			"failed resubmitting read bulk urb: %d\n", retval);
+	}
+
+	return;
+}
+
+/*
+ * callback for bulk IN urb
+ */
+static void esd_usb2_write_bulk_callback(struct urb *urb)
+{
+	struct esd_tx_urb_context *context = urb->context;
+	struct esd_usb2_net_priv *priv;
+	struct esd_usb2 *dev;
+	struct net_device *netdev;
+	size_t size = sizeof(struct esd_usb2_msg);
+
+	WARN_ON(!context);
+
+	priv = context->priv;
+	netdev = priv->netdev;
+	dev = priv->usb2;
+
+	/* free up our allocated buffer */
+	usb_free_coherent(urb->dev, size,
+			  urb->transfer_buffer, urb->transfer_dma);
+
+	if (!netif_device_present(netdev))
+		return;
+
+	if (urb->status)
+		dev_info(netdev->dev.parent, "Tx URB aborted (%d)\n",
+			 urb->status);
+
+	netdev->trans_start = jiffies;
+}
+
+static ssize_t show_firmware(struct device *d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct usb_interface *intf = to_usb_interface(d);
+	struct esd_usb2 *dev = usb_get_intfdata(intf);
+
+	return sprintf(buf, "%d.%d.%d\n",
+		       (dev->version >> 12) & 0xf,
+		       (dev->version >> 8) & 0xf,
+		       dev->version & 0xff);
+}
+static DEVICE_ATTR(firmware, S_IRUGO, show_firmware, NULL);
+
+static ssize_t show_hardware(struct device *d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct usb_interface *intf = to_usb_interface(d);
+	struct esd_usb2 *dev = usb_get_intfdata(intf);
+
+	return sprintf(buf, "%d.%d.%d\n",
+		       (dev->version >> 28) & 0xf,
+		       (dev->version >> 24) & 0xf,
+		       (dev->version >> 16) & 0xff);
+}
+static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL);
+
+static ssize_t show_nets(struct device *d,
+			 struct device_attribute *attr, char *buf)
+{
+	struct usb_interface *intf = to_usb_interface(d);
+	struct esd_usb2 *dev = usb_get_intfdata(intf);
+
+	return sprintf(buf, "%d", dev->net_count);
+}
+static DEVICE_ATTR(nets, S_IRUGO, show_nets, NULL);
+
+static int esd_usb2_send_msg(struct esd_usb2 *dev, struct esd_usb2_msg *msg)
+{
+	int actual_length;
+
+	return usb_bulk_msg(dev->udev,
+			    usb_sndbulkpipe(dev->udev, 2),
+			    msg,
+			    msg->msg.hdr.len << 2,
+			    &actual_length,
+			    1000);
+}
+
+static int esd_usb2_wait_msg(struct esd_usb2 *dev,
+			     struct esd_usb2_msg *msg)
+{
+	int actual_length;
+
+	return usb_bulk_msg(dev->udev,
+			    usb_rcvbulkpipe(dev->udev, 1),
+			    msg,
+			    sizeof(*msg),
+			    &actual_length,
+			    1000);
+}
+
+static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
+{
+	int i, err = 0;
+
+	if (dev->rxinitdone)
+		return 0;
+
+	for (i = 0; i < MAX_RX_URBS; i++) {
+		struct urb *urb = NULL;
+		u8 *buf = NULL;
+
+		/* create a URB, and a buffer for it */
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!urb) {
+			dev_warn(dev->udev->dev.parent,
+				 "No memory left for URBs\n");
+			err = -ENOMEM;
+			break;
+		}
+
+		buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
+					 &urb->transfer_dma);
+		if (!buf) {
+			dev_warn(dev->udev->dev.parent,
+				 "No memory left for USB buffer\n");
+			err = -ENOMEM;
+			goto freeurb;
+		}
+
+		usb_fill_bulk_urb(urb, dev->udev,
+				  usb_rcvbulkpipe(dev->udev, 1),
+				  buf, RX_BUFFER_SIZE,
+				  esd_usb2_read_bulk_callback, dev);
+		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+		usb_anchor_urb(urb, &dev->rx_submitted);
+
+		err = usb_submit_urb(urb, GFP_KERNEL);
+		if (err) {
+			usb_unanchor_urb(urb);
+			usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
+					  urb->transfer_dma);
+		}
+
+freeurb:
+		/* Drop reference, USB core will take care of freeing it */
+		usb_free_urb(urb);
+		if (err)
+			break;
+	}
+
+	/* Did we submit any URBs */
+	if (i == 0) {
+		dev_err(dev->udev->dev.parent, "couldn't setup read URBs\n");
+		return err;
+	}
+
+	/* Warn if we've couldn't transmit all the URBs */
+	if (i < MAX_RX_URBS) {
+		dev_warn(dev->udev->dev.parent,
+			 "rx performance may be slow\n");
+	}
+
+	dev->rxinitdone = 1;
+	return 0;
+}
+
+/*
+ * Start interface
+ */
+static int esd_usb2_start(struct esd_usb2_net_priv *priv)
+{
+	struct esd_usb2 *dev = priv->usb2;
+	struct net_device *netdev = priv->netdev;
+	struct esd_usb2_msg msg;
+	int err, i;
+
+	/*
+	 * Enable all IDs
+	 * The IDADD message takes up to 64 32 bit bitmasks (2048 bits).
+	 * Each bit represents one 11 bit CAN identifier. A set bit
+	 * enables reception of the corresponding CAN identifier. A cleared
+	 * bit disabled this identifier. An additional bitmask value
+	 * following the CAN 2.0A bits is used to enable reception of
+	 * extended CAN frames. Only the LSB of this final mask is checked
+	 * for the complete 29 bit ID range. The IDADD message also allows
+	 * filter configuration for an ID subset. In this case you can add
+	 * the number of the starting bitmask (0..64) to the filter.option
+	 * field followed by only some bitmasks.
+	 */
+	msg.msg.hdr.cmd = CMD_IDADD;
+	msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
+	msg.msg.filter.net = priv->index;
+	msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
+	for (i = 0; i < ESD_MAX_ID_SEGMENT; i++)
+		msg.msg.filter.mask[i] = cpu_to_le32(0xffffffff);
+	/* enable 29bit extended IDs */
+	msg.msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001);
+
+	err = esd_usb2_send_msg(dev, &msg);
+	if (err)
+		goto failed;
+
+	err = esd_usb2_setup_rx_urbs(dev);
+	if (err)
+		goto failed;
+
+	priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+	return 0;
+
+failed:
+	if (err == -ENODEV)
+		netif_device_detach(netdev);
+
+	dev_err(netdev->dev.parent, "couldn't start device: %d\n", err);
+
+	return err;
+}
+
+static void unlink_all_urbs(struct esd_usb2 *dev)
+{
+	struct esd_usb2_net_priv *priv;
+	int i;
+
+	usb_kill_anchored_urbs(&dev->rx_submitted);
+	for (i = 0; i < dev->net_count; i++) {
+		priv = dev->nets[i];
+		if (priv) {
+			usb_kill_anchored_urbs(&priv->tx_submitted);
+			atomic_set(&priv->active_tx_jobs, 0);
+
+			for (i = 0; i < MAX_TX_URBS; i++)
+				priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+		}
+	}
+}
+
+static int esd_usb2_open(struct net_device *netdev)
+{
+	struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+	int err;
+
+	/* common open */
+	err = open_candev(netdev);
+	if (err)
+		return err;
+
+	/* finally start device */
+	err = esd_usb2_start(priv);
+	if (err) {
+		dev_warn(netdev->dev.parent,
+			 "couldn't start device: %d\n", err);
+		close_candev(netdev);
+		return err;
+	}
+
+	priv->open_time = jiffies;
+
+	netif_start_queue(netdev);
+
+	return 0;
+}
+
+static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
+				      struct net_device *netdev)
+{
+	struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+	struct esd_usb2 *dev = priv->usb2;
+	struct esd_tx_urb_context *context = NULL;
+	struct net_device_stats *stats = &netdev->stats;
+	struct can_frame *cf = (struct can_frame *)skb->data;
+	struct esd_usb2_msg *msg;
+	struct urb *urb;
+	u8 *buf;
+	int i, err;
+	int ret = NETDEV_TX_OK;
+	size_t size = sizeof(struct esd_usb2_msg);
+
+	if (can_dropped_invalid_skb(netdev, skb))
+		return NETDEV_TX_OK;
+
+	/* create a URB, and a buffer for it, and copy the data to the URB */
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb) {
+		dev_err(netdev->dev.parent, "No memory left for URBs\n");
+		stats->tx_dropped++;
+		dev_kfree_skb(skb);
+		goto nourbmem;
+	}
+
+	buf = usb_alloc_coherent(dev->udev, size, GFP_ATOMIC,
+				 &urb->transfer_dma);
+	if (!buf) {
+		dev_err(netdev->dev.parent, "No memory left for USB buffer\n");
+		stats->tx_dropped++;
+		dev_kfree_skb(skb);
+		goto nobufmem;
+	}
+
+	msg = (struct esd_usb2_msg *)buf;
+
+	msg->msg.hdr.len = 3; /* minimal length */
+	msg->msg.hdr.cmd = CMD_CAN_TX;
+	msg->msg.tx.net = priv->index;
+	msg->msg.tx.dlc = cf->can_dlc;
+	msg->msg.tx.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK);
+
+	if (cf->can_id & CAN_RTR_FLAG)
+		msg->msg.tx.dlc |= ESD_RTR;
+
+	if (cf->can_id & CAN_EFF_FLAG)
+		msg->msg.tx.id |= cpu_to_le32(ESD_EXTID);
+
+	for (i = 0; i < cf->can_dlc; i++)
+		msg->msg.tx.data[i] = cf->data[i];
+
+	msg->msg.hdr.len += (cf->can_dlc + 3) >> 2;
+
+	for (i = 0; i < MAX_TX_URBS; i++) {
+		if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
+			context = &priv->tx_contexts[i];
+			break;
+		}
+	}
+
+	/*
+	 * This may never happen.
+	 */
+	if (!context) {
+		dev_warn(netdev->dev.parent, "couldn't find free context\n");
+		ret = NETDEV_TX_BUSY;
+		goto releasebuf;
+	}
+
+	context->priv = priv;
+	context->echo_index = i;
+	context->dlc = cf->can_dlc;
+
+	/* hnd must not be 0 - MSB is stripped in txdone handling */
+	msg->msg.tx.hnd = 0x80000000 | i; /* returned in TX done message */
+
+	usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), buf,
+			  msg->msg.hdr.len << 2,
+			  esd_usb2_write_bulk_callback, context);
+
+	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	usb_anchor_urb(urb, &priv->tx_submitted);
+
+	can_put_echo_skb(skb, netdev, context->echo_index);
+
+	atomic_inc(&priv->active_tx_jobs);
+
+	/* Slow down tx path */
+	if (atomic_read(&priv->active_tx_jobs) >= MAX_TX_URBS)
+		netif_stop_queue(netdev);
+
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (err) {
+		can_free_echo_skb(netdev, context->echo_index);
+
+		atomic_dec(&priv->active_tx_jobs);
+		usb_unanchor_urb(urb);
+
+		stats->tx_dropped++;
+
+		if (err == -ENODEV)
+			netif_device_detach(netdev);
+		else
+			dev_warn(netdev->dev.parent, "failed tx_urb %d\n", err);
+
+		goto releasebuf;
+	}
+
+	netdev->trans_start = jiffies;
+
+	/*
+	 * Release our reference to this URB, the USB core will eventually free
+	 * it entirely.
+	 */
+	usb_free_urb(urb);
+
+	return NETDEV_TX_OK;
+
+releasebuf:
+	usb_free_coherent(dev->udev, size, buf, urb->transfer_dma);
+
+nobufmem:
+	usb_free_urb(urb);
+
+nourbmem:
+	return ret;
+}
+
+static int esd_usb2_close(struct net_device *netdev)
+{
+	struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+	struct esd_usb2_msg msg;
+	int i;
+
+	/* Disable all IDs (see esd_usb2_start()) */
+	msg.msg.hdr.cmd = CMD_IDADD;
+	msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
+	msg.msg.filter.net = priv->index;
+	msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
+	for (i = 0; i <= ESD_MAX_ID_SEGMENT; i++)
+		msg.msg.filter.mask[i] = 0;
+	if (esd_usb2_send_msg(priv->usb2, &msg) < 0)
+		dev_err(netdev->dev.parent, "sending idadd message failed\n");
+
+	/* set CAN controller to reset mode */
+	msg.msg.hdr.len = 2;
+	msg.msg.hdr.cmd = CMD_SETBAUD;
+	msg.msg.setbaud.net = priv->index;
+	msg.msg.setbaud.rsvd = 0;
+	msg.msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE);
+	if (esd_usb2_send_msg(priv->usb2, &msg) < 0)
+		dev_err(netdev->dev.parent, "sending setbaud message failed\n");
+
+	priv->can.state = CAN_STATE_STOPPED;
+
+	netif_stop_queue(netdev);
+
+	close_candev(netdev);
+
+	priv->open_time = 0;
+
+	return 0;
+}
+
+static const struct net_device_ops esd_usb2_netdev_ops = {
+	.ndo_open = esd_usb2_open,
+	.ndo_stop = esd_usb2_close,
+	.ndo_start_xmit = esd_usb2_start_xmit,
+};
+
+static struct can_bittiming_const esd_usb2_bittiming_const = {
+	.name = "esd_usb2",
+	.tseg1_min = ESD_USB2_TSEG1_MIN,
+	.tseg1_max = ESD_USB2_TSEG1_MAX,
+	.tseg2_min = ESD_USB2_TSEG2_MIN,
+	.tseg2_max = ESD_USB2_TSEG2_MAX,
+	.sjw_max = ESD_USB2_SJW_MAX,
+	.brp_min = ESD_USB2_BRP_MIN,
+	.brp_max = ESD_USB2_BRP_MAX,
+	.brp_inc = ESD_USB2_BRP_INC,
+};
+
+static int esd_usb2_set_bittiming(struct net_device *netdev)
+{
+	struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+	struct can_bittiming *bt = &priv->can.bittiming;
+	struct esd_usb2_msg msg;
+	u32 canbtr;
+
+	canbtr = ESD_USB2_UBR;
+	canbtr |= (bt->brp - 1) & (ESD_USB2_BRP_MAX - 1);
+	canbtr |= ((bt->sjw - 1) & (ESD_USB2_SJW_MAX - 1))
+		<< ESD_USB2_SJW_SHIFT;
+	canbtr |= ((bt->prop_seg + bt->phase_seg1 - 1)
+		   & (ESD_USB2_TSEG1_MAX - 1))
+		<< ESD_USB2_TSEG1_SHIFT;
+	canbtr |= ((bt->phase_seg2 - 1) & (ESD_USB2_TSEG2_MAX - 1))
+		<< ESD_USB2_TSEG2_SHIFT;
+	if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+		canbtr |= ESD_USB2_3_SAMPLES;
+
+	msg.msg.hdr.len = 2;
+	msg.msg.hdr.cmd = CMD_SETBAUD;
+	msg.msg.setbaud.net = priv->index;
+	msg.msg.setbaud.rsvd = 0;
+	msg.msg.setbaud.baud = cpu_to_le32(canbtr);
+
+	dev_info(netdev->dev.parent, "setting BTR=%#x\n", canbtr);
+
+	return esd_usb2_send_msg(priv->usb2, &msg);
+}
+
+static int esd_usb2_get_berr_counter(const struct net_device *netdev,
+				     struct can_berr_counter *bec)
+{
+	struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+
+	bec->txerr = priv->bec.txerr;
+	bec->rxerr = priv->bec.rxerr;
+
+	return 0;
+}
+
+static int esd_usb2_set_mode(struct net_device *netdev, enum can_mode mode)
+{
+	struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+
+	if (!priv->open_time)
+		return -EINVAL;
+
+	switch (mode) {
+	case CAN_MODE_START:
+		netif_wake_queue(netdev);
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
+{
+	struct esd_usb2 *dev = usb_get_intfdata(intf);
+	struct net_device *netdev;
+	struct esd_usb2_net_priv *priv;
+	int err = 0;
+	int i;
+
+	netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
+	if (!netdev) {
+		dev_err(&intf->dev, "couldn't alloc candev\n");
+		err = -ENOMEM;
+		goto done;
+	}
+
+	priv = netdev_priv(netdev);
+
+	init_usb_anchor(&priv->tx_submitted);
+	atomic_set(&priv->active_tx_jobs, 0);
+
+	for (i = 0; i < MAX_TX_URBS; i++)
+		priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+
+	priv->usb2 = dev;
+	priv->netdev = netdev;
+	priv->index = index;
+
+	priv->can.state = CAN_STATE_STOPPED;
+	priv->can.clock.freq = ESD_USB2_CAN_CLOCK;
+	priv->can.bittiming_const = &esd_usb2_bittiming_const;
+	priv->can.do_set_bittiming = esd_usb2_set_bittiming;
+	priv->can.do_set_mode = esd_usb2_set_mode;
+	priv->can.do_get_berr_counter = esd_usb2_get_berr_counter;
+	priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+
+	netdev->flags |= IFF_ECHO; /* we support local echo */
+
+	netdev->netdev_ops = &esd_usb2_netdev_ops;
+
+	SET_NETDEV_DEV(netdev, &intf->dev);
+
+	err = register_candev(netdev);
+	if (err) {
+		dev_err(&intf->dev,
+			"couldn't register CAN device: %d\n", err);
+		free_candev(netdev);
+		err = -ENOMEM;
+		goto done;
+	}
+
+	dev->nets[index] = priv;
+	dev_info(netdev->dev.parent, "device %s registered\n", netdev->name);
+
+done:
+	return err;
+}
+
+/*
+ * probe function for new USB2 devices
+ *
+ * check version information and number of available
+ * CAN interfaces
+ */
+static int esd_usb2_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct esd_usb2 *dev;
+	struct esd_usb2_msg msg;
+	int i, err;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		err = -ENOMEM;
+		goto done;
+	}
+
+	dev->udev = interface_to_usbdev(intf);
+
+	init_usb_anchor(&dev->rx_submitted);
+
+	usb_set_intfdata(intf, dev);
+
+	/* query number of CAN interfaces (nets) */
+	msg.msg.hdr.cmd = CMD_VERSION;
+	msg.msg.hdr.len = 2;
+	msg.msg.version.rsvd = 0;
+	msg.msg.version.flags = 0;
+	msg.msg.version.drv_version = 0;
+
+	err = esd_usb2_send_msg(dev, &msg);
+	if (err < 0) {
+		dev_err(&intf->dev, "sending version message failed\n");
+		goto free_dev;
+	}
+
+	err = esd_usb2_wait_msg(dev, &msg);
+	if (err < 0) {
+		dev_err(&intf->dev, "no version message answer\n");
+		goto free_dev;
+	}
+
+	dev->net_count = (int)msg.msg.version_reply.nets;
+	dev->version = le32_to_cpu(msg.msg.version_reply.version);
+
+	if (device_create_file(&intf->dev, &dev_attr_firmware))
+		dev_err(&intf->dev,
+			"Couldn't create device file for firmware\n");
+
+	if (device_create_file(&intf->dev, &dev_attr_hardware))
+		dev_err(&intf->dev,
+			"Couldn't create device file for hardware\n");
+
+	if (device_create_file(&intf->dev, &dev_attr_nets))
+		dev_err(&intf->dev,
+			"Couldn't create device file for nets\n");
+
+	/* do per device probing */
+	for (i = 0; i < dev->net_count; i++)
+		esd_usb2_probe_one_net(intf, i);
+
+	return 0;
+
+free_dev:
+	kfree(dev);
+done:
+	return err;
+}
+
+/*
+ * called by the usb core when the device is removed from the system
+ */
+static void esd_usb2_disconnect(struct usb_interface *intf)
+{
+	struct esd_usb2 *dev = usb_get_intfdata(intf);
+	struct net_device *netdev;
+	int i;
+
+	device_remove_file(&intf->dev, &dev_attr_firmware);
+	device_remove_file(&intf->dev, &dev_attr_hardware);
+	device_remove_file(&intf->dev, &dev_attr_nets);
+
+	usb_set_intfdata(intf, NULL);
+
+	if (dev) {
+		for (i = 0; i < dev->net_count; i++) {
+			if (dev->nets[i]) {
+				netdev = dev->nets[i]->netdev;
+				unregister_netdev(netdev);
+				free_candev(netdev);
+			}
+		}
+		unlink_all_urbs(dev);
+	}
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver esd_usb2_driver = {
+	.name = "esd_usb2",
+	.probe = esd_usb2_probe,
+	.disconnect = esd_usb2_disconnect,
+	.id_table = esd_usb2_table,
+};
+
+static int __init esd_usb2_init(void)
+{
+	int err;
+
+	/* register this driver with the USB subsystem */
+	err = usb_register(&esd_usb2_driver);
+
+	if (err) {
+		err("usb_register failed. Error number %d\n", err);
+		return err;
+	}
+
+	return 0;
+}
+module_init(esd_usb2_init);
+
+static void __exit esd_usb2_exit(void)
+{
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&esd_usb2_driver);
+}
+module_exit(esd_usb2_exit);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 04a03f7..28c88ee 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -107,12 +107,7 @@
 #define cas_page_unmap(x)    kunmap_atomic((x), KM_SKB_DATA_SOFTIRQ)
 #define CAS_NCPUS            num_online_cpus()
 
-#ifdef CONFIG_CASSINI_NAPI
-#define USE_NAPI
-#define cas_skb_release(x)  netif_receive_skb(x)
-#else
 #define cas_skb_release(x)  netif_rx(x)
-#endif
 
 /* select which firmware to use */
 #define USE_HP_WORKAROUND
@@ -3063,9 +3058,6 @@
 {
 	unsigned char *e = &cp->dev->dev_addr[0];
 	int i;
-#ifdef CONFIG_CASSINI_MULTICAST_REG_WRITE
-	u32 rxcfg;
-#endif
 	cas_mac_reset(cp);
 
 	/* setup core arbitration weight register */
@@ -3133,23 +3125,8 @@
 	writel(0xc200, cp->regs + REG_MAC_ADDRN(43));
 	writel(0x0180, cp->regs + REG_MAC_ADDRN(44));
 
-#ifndef CONFIG_CASSINI_MULTICAST_REG_WRITE
 	cp->mac_rx_cfg = cas_setup_multicast(cp);
-#else
-	/* WTZ: Do what Adrian did in cas_set_multicast. Doing
-	 * a writel does not seem to be necessary because Cassini
-	 * seems to preserve the configuration when we do the reset.
-	 * If the chip is in trouble, though, it is not clear if we
-	 * can really count on this behavior. cas_set_multicast uses
-	 * spin_lock_irqsave, but we are called only in cas_init_hw and
-	 * cas_init_hw is protected by cas_lock_all, which calls
-	 * spin_lock_irq (so it doesn't need to save the flags, and
-	 * we should be OK for the writel, as that is the only
-	 * difference).
-	 */
-	cp->mac_rx_cfg = rxcfg = cas_setup_multicast(cp);
-	writel(rxcfg, cp->regs + REG_MAC_RX_CFG);
-#endif
+
 	spin_lock(&cp->stat_lock[N_TX_RINGS]);
 	cas_clear_mac_err(cp);
 	spin_unlock(&cp->stat_lock[N_TX_RINGS]);
diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h
index fd17a00..dbc4787 100644
--- a/drivers/net/cassini.h
+++ b/drivers/net/cassini.h
@@ -2844,10 +2844,6 @@
 	atomic_t		reset_task_pending_all;
 #endif
 
-#ifdef CONFIG_CASSINI_QGE_DEBUG
-	atomic_t interrupt_seen; /* 1 if any interrupts are getting through */
-#endif
-
 	/* Link-down problem workaround */
 #define LINK_TRANSITION_UNKNOWN 	0
 #define LINK_TRANSITION_ON_FAILURE 	1
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 036b2df..092f31a 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -286,7 +286,6 @@
 	unsigned int            clock_mc3;
 	unsigned int            clock_mc4;
 	unsigned int            espi_nports;
-	unsigned int            clock_cspi;
 	unsigned int            clock_elmer0;
 	unsigned char           mdio_mdien;
 	unsigned char           mdio_mdiinv;
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index 53bde15..599d178 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -185,9 +185,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_CHELSIO_T1_COUGAR
-#include "cspi.h"
-#endif
 #ifdef CONFIG_CHELSIO_T1_1G
 #include "fpga_defs.h"
 
@@ -280,7 +277,7 @@
 	t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_CFG, val);
 }
 
-#if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
+#if defined(CONFIG_CHELSIO_T1_1G)
 /*
  * Elmer MI1 MDIO read/write operations.
  */
@@ -317,7 +314,7 @@
 	return 0;
 }
 
-#if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
+#if defined(CONFIG_CHELSIO_T1_1G)
 static const struct mdio_ops mi1_mdio_ops = {
 	.init = mi1_mdio_init,
 	.read = mi1_mdio_read,
@@ -752,31 +749,6 @@
 					 mod_detect ? "removed" : "inserted");
 		}
 		break;
-#ifdef CONFIG_CHELSIO_T1_COUGAR
-	case CHBT_BOARD_COUGAR:
-		if (adapter->params.nports == 1) {
-			if (cause & ELMER0_GP_BIT1) {         /* Vitesse MAC */
-				struct cmac *mac = adapter->port[0].mac;
-				mac->ops->interrupt_handler(mac);
-			}
-			if (cause & ELMER0_GP_BIT5) {     /* XPAK MOD_DETECT */
-			}
-		} else {
-			int i, port_bit;
-
-			for_each_port(adapter, i) {
-				port_bit = i ? i + 1 : 0;
-				if (!(cause & (1 << port_bit)))
-					continue;
-
-				phy = adapter->port[i].phy;
-				phy_cause = phy->ops->interrupt_handler(phy);
-				if (phy_cause & cphy_cause_link_change)
-					t1_link_changed(adapter, i);
-			}
-		}
-		break;
-#endif
 	}
 	t1_tpi_write(adapter, A_ELMER0_INT_CAUSE, cause);
 	return 0;
@@ -955,7 +927,6 @@
 	case CHBT_BOARD_N110:
 	case CHBT_BOARD_N210:
 	case CHBT_BOARD_CHT210:
-	case CHBT_BOARD_COUGAR:
 		t1_tpi_par(adapter, 0xf);
 		t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
 		break;
@@ -1004,10 +975,6 @@
 		       adapter->regs + A_MC5_CONFIG);
 	}
 
-#ifdef CONFIG_CHELSIO_T1_COUGAR
-	if (adapter->cspi && t1_cspi_init(adapter->cspi))
-		goto out_err;
-#endif
 	if (adapter->espi && t1_espi_init(adapter->espi, bi->chip_mac,
 					  bi->espi_nports))
 		goto out_err;
@@ -1061,10 +1028,6 @@
 		t1_tp_destroy(adapter->tp);
 	if (adapter->espi)
 		t1_espi_destroy(adapter->espi);
-#ifdef CONFIG_CHELSIO_T1_COUGAR
-	if (adapter->cspi)
-		t1_cspi_destroy(adapter->cspi);
-#endif
 }
 
 static void __devinit init_link_config(struct link_config *lc,
@@ -1084,14 +1047,6 @@
 	}
 }
 
-#ifdef CONFIG_CHELSIO_T1_COUGAR
-	if (bi->clock_cspi && !(adapter->cspi = t1_cspi_create(adapter))) {
-		pr_err("%s: CSPI initialization failed\n",
-		       adapter->name);
-		goto error;
-	}
-#endif
-
 /*
  * Allocate and initialize the data structures that hold the SW state of
  * the Terminator HW modules.
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 8047126..0961032 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -40,9 +40,9 @@
 
 #include "cnic_if.h"
 #include "bnx2.h"
-#include "bnx2x_reg.h"
-#include "bnx2x_fw_defs.h"
-#include "bnx2x_hsi.h"
+#include "bnx2x/bnx2x_reg.h"
+#include "bnx2x/bnx2x_fw_defs.h"
+#include "bnx2x/bnx2x_hsi.h"
 #include "../scsi/bnx2i/57xx_iscsi_constants.h"
 #include "../scsi/bnx2i/57xx_iscsi_hsi.h"
 #include "cnic.h"
@@ -257,7 +257,7 @@
 {
 	u32 i;
 
-	for (i = 0; i < MAX_ISCSI_TBL_SZ; i++) {
+	for (i = 0; i < cp->max_cid_space; i++) {
 		if (cp->ctx_tbl[i].cid == cid) {
 			*l5_cid = i;
 			return 0;
@@ -804,7 +804,7 @@
 	cnic_free_dma(dev, &cp->conn_buf_info);
 	cnic_free_dma(dev, &cp->kwq_info);
 	cnic_free_dma(dev, &cp->kwq_16_data_info);
-	cnic_free_dma(dev, &cp->kcq_info);
+	cnic_free_dma(dev, &cp->kcq1.dma);
 	kfree(cp->iscsi_tbl);
 	cp->iscsi_tbl = NULL;
 	kfree(cp->ctx_tbl);
@@ -863,6 +863,37 @@
 	return 0;
 }
 
+static int cnic_alloc_kcq(struct cnic_dev *dev, struct kcq_info *info)
+{
+	int err, i, is_bnx2 = 0;
+	struct kcqe **kcq;
+
+	if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags))
+		is_bnx2 = 1;
+
+	err = cnic_alloc_dma(dev, &info->dma, KCQ_PAGE_CNT, is_bnx2);
+	if (err)
+		return err;
+
+	kcq = (struct kcqe **) info->dma.pg_arr;
+	info->kcq = kcq;
+
+	if (is_bnx2)
+		return 0;
+
+	for (i = 0; i < KCQ_PAGE_CNT; i++) {
+		struct bnx2x_bd_chain_next *next =
+			(struct bnx2x_bd_chain_next *) &kcq[i][MAX_KCQE_CNT];
+		int j = i + 1;
+
+		if (j >= KCQ_PAGE_CNT)
+			j = 0;
+		next->addr_hi = (u64) info->dma.pg_map_arr[j] >> 32;
+		next->addr_lo = info->dma.pg_map_arr[j] & 0xffffffff;
+	}
+	return 0;
+}
+
 static int cnic_alloc_l2_rings(struct cnic_dev *dev, int pages)
 {
 	struct cnic_local *cp = dev->cnic_priv;
@@ -954,10 +985,9 @@
 		goto error;
 	cp->kwq = (struct kwqe **) cp->kwq_info.pg_arr;
 
-	ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 1);
+	ret = cnic_alloc_kcq(dev, &cp->kcq1);
 	if (ret)
 		goto error;
-	cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr;
 
 	ret = cnic_alloc_context(dev);
 	if (ret)
@@ -981,17 +1011,10 @@
 static int cnic_alloc_bnx2x_context(struct cnic_dev *dev)
 {
 	struct cnic_local *cp = dev->cnic_priv;
-	struct cnic_eth_dev *ethdev = cp->ethdev;
 	int ctx_blk_size = cp->ethdev->ctx_blk_size;
-	int total_mem, blks, i, cid_space;
+	int total_mem, blks, i;
 
-	if (BNX2X_ISCSI_START_CID < ethdev->starting_cid)
-		return -EINVAL;
-
-	cid_space = MAX_ISCSI_TBL_SZ +
-		    (BNX2X_ISCSI_START_CID - ethdev->starting_cid);
-
-	total_mem = BNX2X_CONTEXT_MEM_SIZE * cid_space;
+	total_mem = BNX2X_CONTEXT_MEM_SIZE * cp->max_cid_space;
 	blks = total_mem / ctx_blk_size;
 	if (total_mem % ctx_blk_size)
 		blks++;
@@ -1035,16 +1058,27 @@
 static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
 {
 	struct cnic_local *cp = dev->cnic_priv;
+	struct cnic_eth_dev *ethdev = cp->ethdev;
+	u32 start_cid = ethdev->starting_cid;
 	int i, j, n, ret, pages;
 	struct cnic_dma *kwq_16_dma = &cp->kwq_16_data_info;
 
+	cp->max_cid_space = MAX_ISCSI_TBL_SZ;
+	cp->iscsi_start_cid = start_cid;
+	if (start_cid < BNX2X_ISCSI_START_CID) {
+		u32 delta = BNX2X_ISCSI_START_CID - start_cid;
+
+		cp->iscsi_start_cid = BNX2X_ISCSI_START_CID;
+		cp->max_cid_space += delta;
+	}
+
 	cp->iscsi_tbl = kzalloc(sizeof(struct cnic_iscsi) * MAX_ISCSI_TBL_SZ,
 				GFP_KERNEL);
 	if (!cp->iscsi_tbl)
 		goto error;
 
 	cp->ctx_tbl = kzalloc(sizeof(struct cnic_context) *
-				  MAX_CNIC_L5_CONTEXT, GFP_KERNEL);
+				cp->max_cid_space, GFP_KERNEL);
 	if (!cp->ctx_tbl)
 		goto error;
 
@@ -1053,7 +1087,7 @@
 		cp->ctx_tbl[i].ulp_proto_id = CNIC_ULP_ISCSI;
 	}
 
-	pages = PAGE_ALIGN(MAX_CNIC_L5_CONTEXT * CNIC_KWQ16_DATA_SIZE) /
+	pages = PAGE_ALIGN(cp->max_cid_space * CNIC_KWQ16_DATA_SIZE) /
 		PAGE_SIZE;
 
 	ret = cnic_alloc_dma(dev, kwq_16_dma, pages, 0);
@@ -1061,7 +1095,7 @@
 		return -ENOMEM;
 
 	n = PAGE_SIZE / CNIC_KWQ16_DATA_SIZE;
-	for (i = 0, j = 0; i < MAX_ISCSI_TBL_SZ; i++) {
+	for (i = 0, j = 0; i < cp->max_cid_space; i++) {
 		long off = CNIC_KWQ16_DATA_SIZE * (i % n);
 
 		cp->ctx_tbl[i].kwqe_data = kwq_16_dma->pg_arr[j] + off;
@@ -1072,22 +1106,9 @@
 			j++;
 	}
 
-	ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 0);
+	ret = cnic_alloc_kcq(dev, &cp->kcq1);
 	if (ret)
 		goto error;
-	cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr;
-
-	for (i = 0; i < KCQ_PAGE_CNT; i++) {
-		struct bnx2x_bd_chain_next *next =
-			(struct bnx2x_bd_chain_next *)
-			&cp->kcq[i][MAX_KCQE_CNT];
-		int j = i + 1;
-
-		if (j >= KCQ_PAGE_CNT)
-			j = 0;
-		next->addr_hi = (u64) cp->kcq_info.pg_map_arr[j] >> 32;
-		next->addr_lo = cp->kcq_info.pg_map_arr[j] & 0xffffffff;
-	}
 
 	pages = PAGE_ALIGN(BNX2X_ISCSI_NUM_CONNECTIONS *
 			   BNX2X_ISCSI_CONN_BUF_SIZE) / PAGE_SIZE;
@@ -2120,18 +2141,20 @@
 	return idx;
 }
 
-static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod)
+static int cnic_get_kcqes(struct cnic_dev *dev, struct kcq_info *info)
 {
 	struct cnic_local *cp = dev->cnic_priv;
-	u16 i, ri, last;
+	u16 i, ri, hw_prod, last;
 	struct kcqe *kcqe;
 	int kcqe_cnt = 0, last_cnt = 0;
 
-	i = ri = last = *sw_prod;
+	i = ri = last = info->sw_prod_idx;
 	ri &= MAX_KCQ_IDX;
+	hw_prod = *info->hw_prod_idx_ptr;
+	hw_prod = cp->hw_idx(hw_prod);
 
 	while ((i != hw_prod) && (kcqe_cnt < MAX_COMPLETED_KCQE)) {
-		kcqe = &cp->kcq[KCQ_PG(ri)][KCQ_IDX(ri)];
+		kcqe = &info->kcq[KCQ_PG(ri)][KCQ_IDX(ri)];
 		cp->completed_kcq[kcqe_cnt++] = kcqe;
 		i = cp->next_idx(i);
 		ri = i & MAX_KCQ_IDX;
@@ -2141,7 +2164,7 @@
 		}
 	}
 
-	*sw_prod = last;
+	info->sw_prod_idx = last;
 	return last_cnt;
 }
 
@@ -2184,6 +2207,9 @@
 	u16 tx_cons = *cp->tx_cons_ptr;
 	int comp = 0;
 
+	if (!test_bit(CNIC_F_CNIC_UP, &cp->dev->flags))
+		return;
+
 	if (cp->tx_cons != tx_cons || cp->rx_cons != rx_cons) {
 		if (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags))
 			comp = cnic_l2_completion(cp);
@@ -2197,103 +2223,79 @@
 		clear_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags);
 }
 
-static int cnic_service_bnx2(void *data, void *status_blk)
+static u32 cnic_service_bnx2_queues(struct cnic_dev *dev)
 {
-	struct cnic_dev *dev = data;
-	struct status_block *sblk = status_blk;
 	struct cnic_local *cp = dev->cnic_priv;
-	u32 status_idx = sblk->status_idx;
-	u16 hw_prod, sw_prod;
+	u32 status_idx = (u16) *cp->kcq1.status_idx_ptr;
 	int kcqe_cnt;
 
-	if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
-		return status_idx;
-
 	cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
 
-	hw_prod = sblk->status_completion_producer_index;
-	sw_prod = cp->kcq_prod_idx;
-	while (sw_prod != hw_prod) {
-		kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod);
-		if (kcqe_cnt == 0)
-			goto done;
+	while ((kcqe_cnt = cnic_get_kcqes(dev, &cp->kcq1))) {
 
 		service_kcqes(dev, kcqe_cnt);
 
 		/* Tell compiler that status_blk fields can change. */
 		barrier();
-		if (status_idx != sblk->status_idx) {
-			status_idx = sblk->status_idx;
+		if (status_idx != *cp->kcq1.status_idx_ptr) {
+			status_idx = (u16) *cp->kcq1.status_idx_ptr;
 			cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
-			hw_prod = sblk->status_completion_producer_index;
 		} else
 			break;
 	}
 
-done:
-	CNIC_WR16(dev, cp->kcq_io_addr, sw_prod);
-
-	cp->kcq_prod_idx = sw_prod;
+	CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx);
 
 	cnic_chk_pkt_rings(cp);
+
 	return status_idx;
 }
 
+static int cnic_service_bnx2(void *data, void *status_blk)
+{
+	struct cnic_dev *dev = data;
+	struct cnic_local *cp = dev->cnic_priv;
+	u32 status_idx = *cp->kcq1.status_idx_ptr;
+
+	if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
+		return status_idx;
+
+	return cnic_service_bnx2_queues(dev);
+}
+
 static void cnic_service_bnx2_msix(unsigned long data)
 {
 	struct cnic_dev *dev = (struct cnic_dev *) data;
 	struct cnic_local *cp = dev->cnic_priv;
-	struct status_block_msix *status_blk = cp->status_blk.bnx2;
-	u32 status_idx = status_blk->status_idx;
-	u16 hw_prod, sw_prod;
-	int kcqe_cnt;
 
-	cp->kwq_con_idx = status_blk->status_cmd_consumer_index;
+	cp->last_status_idx = cnic_service_bnx2_queues(dev);
 
-	hw_prod = status_blk->status_completion_producer_index;
-	sw_prod = cp->kcq_prod_idx;
-	while (sw_prod != hw_prod) {
-		kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod);
-		if (kcqe_cnt == 0)
-			goto done;
-
-		service_kcqes(dev, kcqe_cnt);
-
-		/* Tell compiler that status_blk fields can change. */
-		barrier();
-		if (status_idx != status_blk->status_idx) {
-			status_idx = status_blk->status_idx;
-			cp->kwq_con_idx = status_blk->status_cmd_consumer_index;
-			hw_prod = status_blk->status_completion_producer_index;
-		} else
-			break;
-	}
-
-done:
-	CNIC_WR16(dev, cp->kcq_io_addr, sw_prod);
-	cp->kcq_prod_idx = sw_prod;
-
-	cnic_chk_pkt_rings(cp);
-
-	cp->last_status_idx = status_idx;
 	CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num |
 		BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx);
 }
 
+static void cnic_doirq(struct cnic_dev *dev)
+{
+	struct cnic_local *cp = dev->cnic_priv;
+	u16 prod = cp->kcq1.sw_prod_idx & MAX_KCQ_IDX;
+
+	if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags))) {
+		prefetch(cp->status_blk.gen);
+		prefetch(&cp->kcq1.kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
+
+		tasklet_schedule(&cp->cnic_irq_task);
+	}
+}
+
 static irqreturn_t cnic_irq(int irq, void *dev_instance)
 {
 	struct cnic_dev *dev = dev_instance;
 	struct cnic_local *cp = dev->cnic_priv;
-	u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX;
 
 	if (cp->ack_int)
 		cp->ack_int(dev);
 
-	prefetch(cp->status_blk.gen);
-	prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
-
-	if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags)))
-		tasklet_schedule(&cp->cnic_irq_task);
+	cnic_doirq(dev);
 
 	return IRQ_HANDLED;
 }
@@ -2324,60 +2326,50 @@
 			   IGU_INT_DISABLE, 0);
 }
 
-static void cnic_service_bnx2x_bh(unsigned long data)
+static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info)
 {
-	struct cnic_dev *dev = (struct cnic_dev *) data;
-	struct cnic_local *cp = dev->cnic_priv;
-	u16 hw_prod, sw_prod;
-	struct cstorm_status_block_c *sblk =
-		&cp->status_blk.bnx2x->c_status_block;
-	u32 status_idx = sblk->status_block_index;
+	u32 last_status = *info->status_idx_ptr;
 	int kcqe_cnt;
 
-	if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
-		return;
-
-	hw_prod = sblk->index_values[HC_INDEX_C_ISCSI_EQ_CONS];
-	hw_prod = cp->hw_idx(hw_prod);
-	sw_prod = cp->kcq_prod_idx;
-	while (sw_prod != hw_prod) {
-		kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod);
-		if (kcqe_cnt == 0)
-			goto done;
+	while ((kcqe_cnt = cnic_get_kcqes(dev, info))) {
 
 		service_kcqes(dev, kcqe_cnt);
 
 		/* Tell compiler that sblk fields can change. */
 		barrier();
-		if (status_idx == sblk->status_block_index)
+		if (last_status == *info->status_idx_ptr)
 			break;
 
-		status_idx = sblk->status_block_index;
-		hw_prod = sblk->index_values[HC_INDEX_C_ISCSI_EQ_CONS];
-		hw_prod = cp->hw_idx(hw_prod);
+		last_status = *info->status_idx_ptr;
 	}
+	return last_status;
+}
 
-done:
-	CNIC_WR16(dev, cp->kcq_io_addr, sw_prod + MAX_KCQ_IDX);
+static void cnic_service_bnx2x_bh(unsigned long data)
+{
+	struct cnic_dev *dev = (struct cnic_dev *) data;
+	struct cnic_local *cp = dev->cnic_priv;
+	u32 status_idx;
+
+	if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
+		return;
+
+	status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq1);
+
+	CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
 	cnic_ack_bnx2x_int(dev, cp->status_blk_num, CSTORM_ID,
 			   status_idx, IGU_INT_ENABLE, 1);
-
-	cp->kcq_prod_idx = sw_prod;
 }
 
 static int cnic_service_bnx2x(void *data, void *status_blk)
 {
 	struct cnic_dev *dev = data;
 	struct cnic_local *cp = dev->cnic_priv;
-	u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX;
 
-	if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags))) {
-		prefetch(cp->status_blk.bnx2x);
-		prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
+	if (!(cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX))
+		cnic_doirq(dev);
 
-		tasklet_schedule(&cp->cnic_irq_task);
-		cnic_chk_pkt_rings(cp);
-	}
+	cnic_chk_pkt_rings(cp);
 
 	return 0;
 }
@@ -2824,7 +2816,7 @@
 
 	err = ip_route_output_key(&init_net, &rt, &fl);
 	if (!err)
-		*dst = &rt->u.dst;
+		*dst = &rt->dst;
 	return err;
 #else
 	return -ENETUNREACH;
@@ -2996,7 +2988,7 @@
 static int cnic_cm_abort(struct cnic_sock *csk)
 {
 	struct cnic_local *cp = csk->dev->cnic_priv;
-	u32 opcode;
+	u32 opcode = L4_KCQE_OPCODE_VALUE_RESET_COMP;
 
 	if (!cnic_in_use(csk))
 		return -EINVAL;
@@ -3008,12 +3000,9 @@
 	 * connect was not successful.
 	 */
 
-	csk->state = L4_KCQE_OPCODE_VALUE_RESET_COMP;
-	if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
-		opcode = csk->state;
-	else
-		opcode = L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD;
 	cp->close_conn(csk, opcode);
+	if (csk->state != opcode)
+		return -EALREADY;
 
 	return 0;
 }
@@ -3026,6 +3015,8 @@
 	if (cnic_close_prep(csk)) {
 		csk->state = L4_KCQE_OPCODE_VALUE_CLOSE_COMP;
 		return cnic_cm_close_req(csk);
+	} else {
+		return -EALREADY;
 	}
 	return 0;
 }
@@ -3141,12 +3132,6 @@
 		break;
 
 	case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
-		if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
-			cnic_cm_upcall(cp, csk, opcode);
-			break;
-		} else if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags))
-			csk->state = opcode;
-		/* fall through */
 	case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
 	case L4_KCQE_OPCODE_VALUE_RESET_COMP:
 	case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE:
@@ -3202,19 +3187,22 @@
 
 static int cnic_ready_to_close(struct cnic_sock *csk, u32 opcode)
 {
-	if ((opcode == csk->state) ||
-	    (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED &&
-	     csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)) {
-		if (!test_and_set_bit(SK_F_CLOSING, &csk->flags))
-			return 1;
+	if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) {
+		/* Unsolicited RESET_COMP or RESET_RECEIVED */
+		opcode = L4_KCQE_OPCODE_VALUE_RESET_RECEIVED;
+		csk->state = opcode;
 	}
-	/* 57710+ only  workaround to handle unsolicited RESET_COMP
-	 * which will be treated like a RESET RCVD notification
-	 * which triggers the clean up procedure
+
+	/* 1. If event opcode matches the expected event in csk->state
+	 * 2. If the expected event is CLOSE_COMP, we accept any event
+	 * 3. If the expected event is 0, meaning the connection was never
+	 *    never established, we accept the opcode from cm_abort.
 	 */
-	else if (opcode == L4_KCQE_OPCODE_VALUE_RESET_COMP) {
+	if (opcode == csk->state || csk->state == 0 ||
+	    csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP) {
 		if (!test_and_set_bit(SK_F_CLOSING, &csk->flags)) {
-			csk->state = L4_KCQE_OPCODE_VALUE_RESET_RECEIVED;
+			if (csk->state == 0)
+				csk->state = opcode;
 			return 1;
 		}
 	}
@@ -3226,8 +3214,14 @@
 	struct cnic_dev *dev = csk->dev;
 	struct cnic_local *cp = dev->cnic_priv;
 
+	if (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED) {
+		cnic_cm_upcall(cp, csk, opcode);
+		return;
+	}
+
 	clear_bit(SK_F_CONNECT_START, &csk->flags);
 	cnic_close_conn(csk);
+	csk->state = opcode;
 	cnic_cm_upcall(cp, csk, opcode);
 }
 
@@ -3257,8 +3251,12 @@
 	case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
 	case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
 	case L4_KCQE_OPCODE_VALUE_RESET_COMP:
-		if (cnic_ready_to_close(csk, opcode))
-			cmd = L5CM_RAMROD_CMD_ID_SEARCHER_DELETE;
+		if (cnic_ready_to_close(csk, opcode)) {
+			if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
+				cmd = L5CM_RAMROD_CMD_ID_SEARCHER_DELETE;
+			else
+				close_complete = 1;
+		}
 		break;
 	case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE:
 		cmd = L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD;
@@ -3694,7 +3692,7 @@
 	struct cnic_local *cp = dev->cnic_priv;
 	struct cnic_eth_dev *ethdev = cp->ethdev;
 	struct status_block *sblk = cp->status_blk.gen;
-	u32 val;
+	u32 val, kcq_cid_addr, kwq_cid_addr;
 	int err;
 
 	cnic_set_bnx2_mac(dev);
@@ -3719,7 +3717,7 @@
 	cnic_init_context(dev, KWQ_CID);
 	cnic_init_context(dev, KCQ_CID);
 
-	cp->kwq_cid_addr = GET_CID_ADDR(KWQ_CID);
+	kwq_cid_addr = GET_CID_ADDR(KWQ_CID);
 	cp->kwq_io_addr = MB_GET_CID_ADDR(KWQ_CID) + L5_KRNLQ_HOST_QIDX;
 
 	cp->max_kwq_idx = MAX_KWQ_IDX;
@@ -3735,50 +3733,59 @@
 	/* Initialize the kernel work queue context. */
 	val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
 	      (BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
-	cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_TYPE, val);
+	cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_TYPE, val);
 
 	val = (BCM_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16;
-	cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
+	cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
 
 	val = ((BCM_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT;
-	cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
+	cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
 
 	val = (u32) ((u64) cp->kwq_info.pgtbl_map >> 32);
-	cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
+	cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
 
 	val = (u32) cp->kwq_info.pgtbl_map;
-	cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
+	cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
 
-	cp->kcq_cid_addr = GET_CID_ADDR(KCQ_CID);
-	cp->kcq_io_addr = MB_GET_CID_ADDR(KCQ_CID) + L5_KRNLQ_HOST_QIDX;
+	kcq_cid_addr = GET_CID_ADDR(KCQ_CID);
+	cp->kcq1.io_addr = MB_GET_CID_ADDR(KCQ_CID) + L5_KRNLQ_HOST_QIDX;
 
-	cp->kcq_prod_idx = 0;
+	cp->kcq1.sw_prod_idx = 0;
+	cp->kcq1.hw_prod_idx_ptr =
+		(u16 *) &sblk->status_completion_producer_index;
+
+	cp->kcq1.status_idx_ptr = (u16 *) &sblk->status_idx;
 
 	/* Initialize the kernel complete queue context. */
 	val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
 	      (BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
-	cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_TYPE, val);
+	cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_TYPE, val);
 
 	val = (BCM_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16;
-	cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
+	cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
 
 	val = ((BCM_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT;
-	cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
+	cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
 
-	val = (u32) ((u64) cp->kcq_info.pgtbl_map >> 32);
-	cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
+	val = (u32) ((u64) cp->kcq1.dma.pgtbl_map >> 32);
+	cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
 
-	val = (u32) cp->kcq_info.pgtbl_map;
-	cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
+	val = (u32) cp->kcq1.dma.pgtbl_map;
+	cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
 
 	cp->int_num = 0;
 	if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
+		struct status_block_msix *msblk = cp->status_blk.bnx2;
 		u32 sb_id = cp->status_blk_num;
 		u32 sb = BNX2_L2CTX_L5_STATUSB_NUM(sb_id);
 
+		cp->kcq1.hw_prod_idx_ptr =
+			(u16 *) &msblk->status_completion_producer_index;
+		cp->kcq1.status_idx_ptr = (u16 *) &msblk->status_idx;
+		cp->kwq_con_idx_ptr = (u16 *) &msblk->status_cmd_consumer_index;
 		cp->int_num = sb_id << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT;
-		cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
-		cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
+		cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
+		cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
 	}
 
 	/* Enable Commnad Scheduler notification when we write to the
@@ -4123,33 +4130,39 @@
 	u8 sb_id = cp->status_blk_num;
 
 	ret = cnic_init_id_tbl(&cp->cid_tbl, MAX_ISCSI_TBL_SZ,
-			       BNX2X_ISCSI_START_CID);
+			       cp->iscsi_start_cid);
 
 	if (ret)
 		return -ENOMEM;
 
-	cp->kcq_io_addr = BAR_CSTRORM_INTMEM +
+	cp->kcq1.io_addr = BAR_CSTRORM_INTMEM +
 			  CSTORM_ISCSI_EQ_PROD_OFFSET(func, 0);
-	cp->kcq_prod_idx = 0;
+	cp->kcq1.sw_prod_idx = 0;
+
+	cp->kcq1.hw_prod_idx_ptr =
+		&cp->status_blk.bnx2x->c_status_block.index_values[
+			HC_INDEX_C_ISCSI_EQ_CONS];
+	cp->kcq1.status_idx_ptr =
+		&cp->status_blk.bnx2x->c_status_block.status_block_index;
 
 	cnic_get_bnx2x_iscsi_info(dev);
 
 	/* Only 1 EQ */
-	CNIC_WR16(dev, cp->kcq_io_addr, MAX_KCQ_IDX);
+	CNIC_WR16(dev, cp->kcq1.io_addr, MAX_KCQ_IDX);
 	CNIC_WR(dev, BAR_CSTRORM_INTMEM +
 		CSTORM_ISCSI_EQ_CONS_OFFSET(func, 0), 0);
 	CNIC_WR(dev, BAR_CSTRORM_INTMEM +
 		CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(func, 0),
-		cp->kcq_info.pg_map_arr[1] & 0xffffffff);
+		cp->kcq1.dma.pg_map_arr[1] & 0xffffffff);
 	CNIC_WR(dev, BAR_CSTRORM_INTMEM +
 		CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(func, 0) + 4,
-		(u64) cp->kcq_info.pg_map_arr[1] >> 32);
+		(u64) cp->kcq1.dma.pg_map_arr[1] >> 32);
 	CNIC_WR(dev, BAR_CSTRORM_INTMEM +
 		CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(func, 0),
-		cp->kcq_info.pg_map_arr[0] & 0xffffffff);
+		cp->kcq1.dma.pg_map_arr[0] & 0xffffffff);
 	CNIC_WR(dev, BAR_CSTRORM_INTMEM +
 		CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(func, 0) + 4,
-		(u64) cp->kcq_info.pg_map_arr[0] >> 32);
+		(u64) cp->kcq1.dma.pg_map_arr[0] >> 32);
 	CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
 		CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(func, 0), 1);
 	CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
@@ -4377,7 +4390,7 @@
 		  0);
 	CNIC_WR(dev, BAR_CSTRORM_INTMEM +
 		CSTORM_ISCSI_EQ_CONS_OFFSET(cp->func, 0), 0);
-	CNIC_WR16(dev, cp->kcq_io_addr, 0);
+	CNIC_WR16(dev, cp->kcq1.io_addr, 0);
 	cnic_free_resc(dev);
 }
 
diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h
index 08b1235..275c361 100644
--- a/drivers/net/cnic.h
+++ b/drivers/net/cnic.h
@@ -169,6 +169,16 @@
 	} proto;
 };
 
+struct kcq_info {
+	struct cnic_dma	dma;
+	struct kcqe	**kcq;
+
+	u16		*hw_prod_idx_ptr;
+	u16		sw_prod_idx;
+	u16		*status_idx_ptr;
+	u32		io_addr;
+};
+
 struct cnic_local {
 
 	spinlock_t cnic_ulp_lock;
@@ -202,9 +212,6 @@
 	u16		rx_cons;
 	u16		tx_cons;
 
-	u32 kwq_cid_addr;
-	u32 kcq_cid_addr;
-
 	struct cnic_dma		kwq_info;
 	struct kwqe		**kwq;
 
@@ -218,11 +225,7 @@
 	u16		*kwq_con_idx_ptr;
 	u16		kwq_con_idx;
 
-	struct cnic_dma	kcq_info;
-	struct kcqe	**kcq;
-
-	u16		kcq_prod_idx;
-	u32		kcq_io_addr;
+	struct kcq_info	kcq1;
 
 	union {
 		void				*gen;
@@ -248,8 +251,10 @@
 	struct cnic_iscsi	*iscsi_tbl;
 	struct cnic_context	*ctx_tbl;
 	struct cnic_id_tbl	cid_tbl;
-	int			max_iscsi_conn;
 	atomic_t		iscsi_conn;
+	u32			iscsi_start_cid;
+
+	u32			max_cid_space;
 
 	/* per connection parameters */
 	int			num_iscsi_tasks;
diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h
index 0c55177..344c842 100644
--- a/drivers/net/cnic_if.h
+++ b/drivers/net/cnic_if.h
@@ -12,8 +12,8 @@
 #ifndef CNIC_IF_H
 #define CNIC_IF_H
 
-#define CNIC_MODULE_VERSION	"2.1.2"
-#define CNIC_MODULE_RELDATE	"May 26, 2010"
+#define CNIC_MODULE_VERSION	"2.1.3"
+#define CNIC_MODULE_RELDATE	"June 24, 2010"
 
 #define CNIC_ULP_RDMA		0
 #define CNIC_ULP_ISCSI		1
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
index 23786ee..e1f6156 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/cpmac.c
@@ -846,11 +846,8 @@
 		return -EINVAL;
 	if (!priv->phy)
 		return -EINVAL;
-	if ((cmd == SIOCGMIIPHY) || (cmd == SIOCGMIIREG) ||
-	    (cmd == SIOCSMIIREG))
-		return phy_mii_ioctl(priv->phy, if_mii(ifr), cmd);
 
-	return -EOPNOTSUPP;
+	return phy_mii_ioctl(priv->phy, ifr, cmd);
 }
 
 static int cpmac_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -964,7 +961,7 @@
 	struct sk_buff *skb;
 
 	mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs");
-	if (!request_mem_region(mem->start, mem->end - mem->start, dev->name)) {
+	if (!request_mem_region(mem->start, resource_size(mem), dev->name)) {
 		if (netif_msg_drv(priv))
 			printk(KERN_ERR "%s: failed to request registers\n",
 			       dev->name);
@@ -972,7 +969,7 @@
 		goto fail_reserve;
 	}
 
-	priv->regs = ioremap(mem->start, mem->end - mem->start);
+	priv->regs = ioremap(mem->start, resource_size(mem));
 	if (!priv->regs) {
 		if (netif_msg_drv(priv))
 			printk(KERN_ERR "%s: failed to remap registers\n",
@@ -1049,7 +1046,7 @@
 	iounmap(priv->regs);
 
 fail_remap:
-	release_mem_region(mem->start, mem->end - mem->start);
+	release_mem_region(mem->start, resource_size(mem));
 
 fail_reserve:
 	return res;
@@ -1077,7 +1074,7 @@
 	free_irq(dev->irq, dev);
 	iounmap(priv->regs);
 	mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs");
-	release_mem_region(mem->start, mem->end - mem->start);
+	release_mem_region(mem->start, resource_size(mem));
 	priv->rx_head = &priv->desc_ring[CPMAC_QUEUES];
 	for (i = 0; i < priv->ring_size; i++) {
 		if (priv->rx_head[i].skb) {
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 7e00027..81475cc 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -1702,11 +1702,7 @@
 
 	if (!current_speed) {
 		/* Make LED red, link is down */
-#if defined(CONFIG_ETRAX_NETWORK_RED_ON_NO_CONNECTION)
-		CRIS_LED_NETWORK_SET(CRIS_LED_RED);
-#else
 		CRIS_LED_NETWORK_SET(CRIS_LED_OFF);
-#endif
 	} else if (light_leds) {
 		if (current_speed == 10) {
 			CRIS_LED_NETWORK_SET(CRIS_LED_ORANGE);
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 2ccb9f1..d325e01 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -170,22 +170,12 @@
 /* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps
    them to system IRQ numbers. This mapping is card specific and is set to
    the configuration of the Cirrus Eval board for this chip. */
-#if defined(CONFIG_SH_HICOSH4)
-static unsigned int netcard_portlist[] __used __initdata =
-   { 0x0300, 0};
-static unsigned int cs8900_irq_map[] = {1,0,0,0};
-#elif defined(CONFIG_MACH_IXDP2351)
+#if defined(CONFIG_MACH_IXDP2351)
 static unsigned int netcard_portlist[] __used __initdata = {IXDP2351_VIRT_CS8900_BASE, 0};
 static unsigned int cs8900_irq_map[] = {IRQ_IXDP2351_CS8900, 0, 0, 0};
 #elif defined(CONFIG_ARCH_IXDP2X01)
 static unsigned int netcard_portlist[] __used __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
 static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
-#elif defined(CONFIG_ARCH_PNX010X)
-#include <mach/gpio.h>
-#define CIRRUS_DEFAULT_BASE	IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000)	/* = Physical address 0x48200000 */
-#define CIRRUS_DEFAULT_IRQ	VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */
-static unsigned int netcard_portlist[] __used __initdata = {CIRRUS_DEFAULT_BASE, 0};
-static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0};
 #elif defined(CONFIG_MACH_MX31ADS)
 #include <mach/board-mx31ads.h>
 static unsigned int netcard_portlist[] __used __initdata = {
@@ -218,7 +208,6 @@
 
 /* Information that need to be kept for each board. */
 struct net_local {
-	struct net_device_stats stats;
 	int chip_type;		/* one of: CS8900, CS8920, CS8920M */
 	char chip_revision;	/* revision letter of the chip ('A'...) */
 	int send_cmd;		/* the proper send command: TX_NOW, TX_AFTER_381, or TX_AFTER_ALL */
@@ -257,7 +246,7 @@
 static int get_eeprom_data(struct net_device *dev, int off, int len, int *buffer);
 static int get_eeprom_cksum(int off, int len, int *buffer);
 static int set_mac_address(struct net_device *dev, void *addr);
-static void count_rx_errors(int status, struct net_local *lp);
+static void count_rx_errors(int status, struct net_device *dev);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void net_poll_controller(struct net_device *dev);
 #endif
@@ -372,18 +361,6 @@
 {
 	__raw_writel(value, base_addr + (portno << 1));
 }
-#elif defined(CONFIG_ARCH_PNX010X)
-static u16
-readword(unsigned long base_addr, int portno)
-{
-	return inw(base_addr + (portno << 1));
-}
-
-static void
-writeword(unsigned long base_addr, int portno, u16 value)
-{
-	outw(value, base_addr + (portno << 1));
-}
 #else
 static u16
 readword(unsigned long base_addr, int portno)
@@ -546,30 +523,6 @@
 #endif
         }
 
-#ifdef CONFIG_ARCH_PNX010X
-	initialize_ebi();
-
-	/* Map GPIO registers for the pins connected to the CS8900a. */
-	if (map_cirrus_gpio() < 0)
-		return -ENODEV;
-
-	reset_cirrus();
-
-	/* Map event-router registers. */
-	if (map_event_router() < 0)
-		return -ENODEV;
-
-	enable_cirrus_irq();
-
-	unmap_cirrus_gpio();
-	unmap_event_router();
-
-	dev->base_addr = ioaddr;
-
-	for (i = 0 ; i < 3 ; i++)
-		readreg(dev, 0);
-#endif
-
 	/* Grab the region so we can find another board if autoIRQ fails. */
 	/* WTF is going on here? */
 	if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) {
@@ -579,12 +532,6 @@
 		goto out1;
 	}
 
-#ifdef CONFIG_SH_HICOSH4
-	/* truly reset the chip */
-	writeword(ioaddr, ADD_PORT, 0x0114);
-	writeword(ioaddr, DATA_PORT, 0x0040);
-#endif
-
 	/* if they give us an odd I/O address, then do ONE write to
            the address port, to get it back to address zero, where we
            expect to find the EISA signature word. An IO with a base of 0x3
@@ -650,37 +597,6 @@
 	   the driver will always do *something* instead of complain that
 	   adapter_cnf is 0. */
 
-#ifdef CONFIG_SH_HICOSH4
-	if (1) {
-		/* For the HiCO.SH4 board, things are different: we don't
-		   have EEPROM, but there is some data in flash, so we go
-		   get it there directly (MAC). */
-		__u16 *confd;
-		short cnt;
-		if (((* (volatile __u32 *) 0xa0013ff0) & 0x00ffffff)
-			== 0x006c3000) {
-			confd = (__u16*) 0xa0013fc0;
-		} else {
-			confd = (__u16*) 0xa001ffc0;
-		}
-		cnt = (*confd++ & 0x00ff) >> 1;
-		while (--cnt > 0) {
-			__u16 j = *confd++;
-
-			switch (j & 0x0fff) {
-			case PP_IA:
-				for (i = 0; i < ETH_ALEN/2; i++) {
-					dev->dev_addr[i*2] = confd[i] & 0xFF;
-					dev->dev_addr[i*2+1] = confd[i] >> 8;
-				}
-				break;
-			}
-			j = (j >> 12) + 1;
-			confd += j;
-			cnt -= j;
-		}
-	} else
-#endif
 
         if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) ==
 	      (EEPROM_OK|EEPROM_PRESENT)) {
@@ -735,11 +651,7 @@
         printk("\n");
 
 	/* First check to see if an EEPROM is attached. */
-#ifdef CONFIG_SH_HICOSH4 /* no EEPROM on HiCO, don't hazzle with it here */
-	if (1) {
-		printk(KERN_NOTICE "cs89x0: No EEPROM on HiCO.SH4\n");
-	} else
-#endif
+
 	if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0)
 		printk(KERN_WARNING "cs89x0: No EEPROM, relying on command line....\n");
 	else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
@@ -983,7 +895,7 @@
 			dev->name, (unsigned long)bp, status, length);
 	}
 	if ((status & RX_OK) == 0) {
-		count_rx_errors(status, lp);
+		count_rx_errors(status, dev);
 		goto skip_this_frame;
 	}
 
@@ -992,7 +904,7 @@
 	if (skb == NULL) {
 		if (net_debug)	/* I don't think we want to do this to a stressed system */
 			printk("%s: Memory squeeze, dropping packet.\n", dev->name);
-		lp->stats.rx_dropped++;
+		dev->stats.rx_dropped++;
 
 		/* AKPM: advance bp to the next frame */
 skip_this_frame:
@@ -1022,8 +934,8 @@
 	}
         skb->protocol=eth_type_trans(skb,dev);
 	netif_rx(skb);
-	lp->stats.rx_packets++;
-	lp->stats.rx_bytes += length;
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += length;
 }
 
 #endif	/* ALLOW_DMA */
@@ -1276,7 +1188,6 @@
 	int i;
 	int ret;
 
-#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX010X) /* uses irq#1, so this won't work */
 	if (dev->irq < 2) {
 		/* Allow interrupts to be generated by the chip */
 /* Cirrus' release had this: */
@@ -1305,7 +1216,6 @@
 		}
 	}
 	else
-#endif
 	{
 #ifndef CONFIG_CS89x0_NONISA_IRQ
 		if (((1 << dev->irq) & lp->irq_map) == 0) {
@@ -1391,9 +1301,6 @@
 	case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;
         default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);
         }
-#ifdef CONFIG_ARCH_PNX010X
-	result = A_CNF_10B_T;
-#endif
         if (!result) {
                 printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);
 release_dma:
@@ -1552,7 +1459,7 @@
 	/* Write the contents of the packet */
 	writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
 	spin_unlock_irqrestore(&lp->lock, flags);
-	lp->stats.tx_bytes += skb->len;
+	dev->stats.tx_bytes += skb->len;
 	dev_kfree_skb (skb);
 
 	/*
@@ -1598,18 +1505,23 @@
 			net_rx(dev);
 			break;
 		case ISQ_TRANSMITTER_EVENT:
-			lp->stats.tx_packets++;
+			dev->stats.tx_packets++;
 			netif_wake_queue(dev);	/* Inform upper layers. */
 			if ((status & (	TX_OK |
 					TX_LOST_CRS |
 					TX_SQE_ERROR |
 					TX_LATE_COL |
 					TX_16_COL)) != TX_OK) {
-				if ((status & TX_OK) == 0) lp->stats.tx_errors++;
-				if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
-				if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
-				if (status & TX_LATE_COL) lp->stats.tx_window_errors++;
-				if (status & TX_16_COL) lp->stats.tx_aborted_errors++;
+				if ((status & TX_OK) == 0)
+					dev->stats.tx_errors++;
+				if (status & TX_LOST_CRS)
+					dev->stats.tx_carrier_errors++;
+				if (status & TX_SQE_ERROR)
+					dev->stats.tx_heartbeat_errors++;
+				if (status & TX_LATE_COL)
+					dev->stats.tx_window_errors++;
+				if (status & TX_16_COL)
+					dev->stats.tx_aborted_errors++;
 			}
 			break;
 		case ISQ_BUFFER_EVENT:
@@ -1651,10 +1563,10 @@
 #endif
 			break;
 		case ISQ_RX_MISS_EVENT:
-			lp->stats.rx_missed_errors += (status >>6);
+			dev->stats.rx_missed_errors += (status >> 6);
 			break;
 		case ISQ_TX_COL_EVENT:
-			lp->stats.collisions += (status >>6);
+			dev->stats.collisions += (status >> 6);
 			break;
 		}
 	}
@@ -1662,22 +1574,24 @@
 }
 
 static void
-count_rx_errors(int status, struct net_local *lp)
+count_rx_errors(int status, struct net_device *dev)
 {
-	lp->stats.rx_errors++;
-	if (status & RX_RUNT) lp->stats.rx_length_errors++;
-	if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++;
-	if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT)))
+	dev->stats.rx_errors++;
+	if (status & RX_RUNT)
+		dev->stats.rx_length_errors++;
+	if (status & RX_EXTRA_DATA)
+		dev->stats.rx_length_errors++;
+	if ((status & RX_CRC_ERROR) && !(status & (RX_EXTRA_DATA|RX_RUNT)))
 		/* per str 172 */
-		lp->stats.rx_crc_errors++;
-	if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++;
+		dev->stats.rx_crc_errors++;
+	if (status & RX_DRIBBLE)
+		dev->stats.rx_frame_errors++;
 }
 
 /* We have a good packet(s), get it/them out of the buffers. */
 static void
 net_rx(struct net_device *dev)
 {
-	struct net_local *lp = netdev_priv(dev);
 	struct sk_buff *skb;
 	int status, length;
 
@@ -1686,7 +1600,7 @@
 	length = readword(ioaddr, RX_FRAME_PORT);
 
 	if ((status & RX_OK) == 0) {
-		count_rx_errors(status, lp);
+		count_rx_errors(status, dev);
 		return;
 	}
 
@@ -1696,7 +1610,7 @@
 #if 0		/* Again, this seems a cruel thing to do */
 		printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
 #endif
-		lp->stats.rx_dropped++;
+		dev->stats.rx_dropped++;
 		return;
 	}
 	skb_reserve(skb, 2);	/* longword align L3 header */
@@ -1713,8 +1627,8 @@
 
         skb->protocol=eth_type_trans(skb,dev);
 	netif_rx(skb);
-	lp->stats.rx_packets++;
-	lp->stats.rx_bytes += length;
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += length;
 }
 
 #if ALLOW_DMA
@@ -1765,11 +1679,11 @@
 
 	spin_lock_irqsave(&lp->lock, flags);
 	/* Update the statistics from the device registers. */
-	lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
-	lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
+	dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
+	dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
 	spin_unlock_irqrestore(&lp->lock, flags);
 
-	return &lp->stats;
+	return &dev->stats;
 }
 
 static void set_multicast_list(struct net_device *dev)
diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h
index 204ed37..91423b7 100644
--- a/drivers/net/cs89x0.h
+++ b/drivers/net/cs89x0.h
@@ -437,11 +437,7 @@
 #define IRQ_MAP_EEPROM_DATA 0x0046 /*  Offset into eeprom for the IRQ map */
 #define IRQ_MAP_LEN 0x0004 /*  No of bytes to read for the IRQ map */
 #define PNP_IRQ_FRMT 0x0022 /*  PNP small item IRQ format */
-#ifdef CONFIG_SH_HICOSH4
-#define CS8900_IRQ_MAP 0x0002 /* HiCO-SH4 board has its IRQ on #1 */
-#else
 #define CS8900_IRQ_MAP 0x1c20 /*  This IRQ map is fixed */
-#endif
 
 #define CS8920_NO_INTS 0x0F   /*  Max CS8920 interrupt select # */
 
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index e3f1b85..066fd5b 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -2311,15 +2311,9 @@
 		if (copy_from_user(&t, useraddr, sizeof(t)))
 			return -EFAULT;
 		/* Check t.len sanity ? */
-		fw_data = kmalloc(t.len, GFP_KERNEL);
-		if (!fw_data)
-			return -ENOMEM;
-
-		if (copy_from_user
-			(fw_data, useraddr + sizeof(t), t.len)) {
-			kfree(fw_data);
-			return -EFAULT;
-		}
+		fw_data = memdup_user(useraddr + sizeof(t), t.len);
+		if (IS_ERR(fw_data))
+			return PTR_ERR(fw_data);
 
 		ret = t3_load_fw(adapter, fw_data, t.len);
 		kfree(fw_data);
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 5962b91..8ff96c6 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -203,15 +203,11 @@
  */
 static inline int need_skb_unmap(void)
 {
-	/*
-	 * This structure is used to tell if the platform needs buffer
-	 * unmapping by checking if DECLARE_PCI_UNMAP_ADDR defines anything.
-	 */
-	struct dummy {
-		DEFINE_DMA_UNMAP_ADDR(addr);
-	};
-
-	return sizeof(struct dummy) != 0;
+#ifdef CONFIG_NEED_DMA_MAP_STATE
+	return 1;
+#else
+	return 0;
+#endif
 }
 
 /**
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 95a8ba0..427c451 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -679,14 +679,6 @@
 	return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
 }
 
-/*
- * Convert a character holding a hex digit to a number.
- */
-static unsigned int hex2int(unsigned char c)
-{
-	return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
-}
-
 /**
  *	get_vpd_params - read VPD parameters from VPD EEPROM
  *	@adapter: adapter to read
@@ -727,15 +719,15 @@
 		p->port_type[0] = uses_xaui(adapter) ? 1 : 2;
 		p->port_type[1] = uses_xaui(adapter) ? 6 : 2;
 	} else {
-		p->port_type[0] = hex2int(vpd.port0_data[0]);
-		p->port_type[1] = hex2int(vpd.port1_data[0]);
+		p->port_type[0] = hex_to_bin(vpd.port0_data[0]);
+		p->port_type[1] = hex_to_bin(vpd.port1_data[0]);
 		p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16);
 		p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16);
 	}
 
 	for (i = 0; i < 6; i++)
-		p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 +
-				 hex2int(vpd.na_data[2 * i + 1]);
+		p->eth_base[i] = hex_to_bin(vpd.na_data[2 * i]) * 16 +
+				 hex_to_bin(vpd.na_data[2 * i + 1]);
 	return 0;
 }
 
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index 9d0bd9d..8bda06e 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -35,10 +35,10 @@
 #define DRV_DESC "Chelsio T3 Network Driver"
 #define DRV_NAME "cxgb3"
 /* Driver version */
-#define DRV_VERSION "1.1.3-ko"
+#define DRV_VERSION "1.1.4-ko"
 
 /* Firmware version */
 #define FW_VERSION_MAJOR 7
-#define FW_VERSION_MINOR 4
+#define FW_VERSION_MINOR 10
 #define FW_VERSION_MICRO 0
 #endif				/* __CHELSIO_VERSION_H */
diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h
index dd1770e..6e562c0 100644
--- a/drivers/net/cxgb4/cxgb4.h
+++ b/drivers/net/cxgb4/cxgb4.h
@@ -219,6 +219,10 @@
 	struct vpd_params vpd;
 	struct pci_params pci;
 
+	unsigned int sf_size;             /* serial flash size in bytes */
+	unsigned int sf_nsec;             /* # of flash sectors */
+	unsigned int sf_fw_start;         /* start of FW image in flash */
+
 	unsigned int fw_vers;
 	unsigned int tp_vers;
 	u8 api_vers[7];
@@ -290,7 +294,9 @@
 	u8     rx_offload;            /* CSO, etc */
 	u8     nqsets;                /* # of qsets */
 	u8     first_qset;            /* index of first qset */
+	u8     rss_mode;
 	struct link_config link_cfg;
+	u16   *rss;
 };
 
 /* port_info.rx_offload flags */
@@ -305,7 +311,6 @@
 	FULL_INIT_DONE     = (1 << 0),
 	USING_MSI          = (1 << 1),
 	USING_MSIX         = (1 << 2),
-	QUEUES_BOUND       = (1 << 3),
 	FW_OK              = (1 << 4),
 };
 
@@ -477,7 +482,8 @@
 	struct pci_dev *pdev;
 	struct device *pdev_dev;
 	unsigned long registered_device_map;
-	unsigned long flags;
+	unsigned int fn;
+	unsigned int flags;
 
 	const char *name;
 	int msg_enable;
@@ -646,6 +652,7 @@
 void t4_intr_clear(struct adapter *adapter);
 int t4_slow_intr_handler(struct adapter *adapter);
 
+int t4_wait_dev_ready(struct adapter *adap);
 int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
 		  struct link_config *lc);
 int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port);
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index 58045b0..c327527 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -67,7 +67,7 @@
 #include "t4fw_api.h"
 #include "l2t.h"
 
-#define DRV_VERSION "1.0.0-ko"
+#define DRV_VERSION "1.3.0-ko"
 #define DRV_DESC "Chelsio T4 Network Driver"
 
 /*
@@ -77,6 +77,76 @@
  */
 #define MAX_SGE_TIMERVAL 200U
 
+#ifdef CONFIG_PCI_IOV
+/*
+ * Virtual Function provisioning constants.  We need two extra Ingress Queues
+ * with Interrupt capability to serve as the VF's Firmware Event Queue and
+ * Forwarded Interrupt Queue (when using MSI mode) -- neither will have Free
+ * Lists associated with them).  For each Ethernet/Control Egress Queue and
+ * for each Free List, we need an Egress Context.
+ */
+enum {
+	VFRES_NPORTS = 1,		/* # of "ports" per VF */
+	VFRES_NQSETS = 2,		/* # of "Queue Sets" per VF */
+
+	VFRES_NVI = VFRES_NPORTS,	/* # of Virtual Interfaces */
+	VFRES_NETHCTRL = VFRES_NQSETS,	/* # of EQs used for ETH or CTRL Qs */
+	VFRES_NIQFLINT = VFRES_NQSETS+2,/* # of ingress Qs/w Free List(s)/intr */
+	VFRES_NIQ = 0,			/* # of non-fl/int ingress queues */
+	VFRES_NEQ = VFRES_NQSETS*2,	/* # of egress queues */
+	VFRES_TC = 0,			/* PCI-E traffic class */
+	VFRES_NEXACTF = 16,		/* # of exact MPS filters */
+
+	VFRES_R_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF|FW_CMD_CAP_PORT,
+	VFRES_WX_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF,
+};
+
+/*
+ * Provide a Port Access Rights Mask for the specified PF/VF.  This is very
+ * static and likely not to be useful in the long run.  We really need to
+ * implement some form of persistent configuration which the firmware
+ * controls.
+ */
+static unsigned int pfvfres_pmask(struct adapter *adapter,
+				  unsigned int pf, unsigned int vf)
+{
+	unsigned int portn, portvec;
+
+	/*
+	 * Give PF's access to all of the ports.
+	 */
+	if (vf == 0)
+		return FW_PFVF_CMD_PMASK_MASK;
+
+	/*
+	 * For VFs, we'll assign them access to the ports based purely on the
+	 * PF.  We assign active ports in order, wrapping around if there are
+	 * fewer active ports than PFs: e.g. active port[pf % nports].
+	 * Unfortunately the adapter's port_info structs haven't been
+	 * initialized yet so we have to compute this.
+	 */
+	if (adapter->params.nports == 0)
+		return 0;
+
+	portn = pf % adapter->params.nports;
+	portvec = adapter->params.portvec;
+	for (;;) {
+		/*
+		 * Isolate the lowest set bit in the port vector.  If we're at
+		 * the port number that we want, return that as the pmask.
+		 * otherwise mask that bit out of the port vector and
+		 * decrement our port number ...
+		 */
+		unsigned int pmask = portvec ^ (portvec & (portvec-1));
+		if (portn == 0)
+			return pmask;
+		portn--;
+		portvec &= ~pmask;
+	}
+	/*NOTREACHED*/
+}
+#endif
+
 enum {
 	MEMWIN0_APERTURE = 65536,
 	MEMWIN0_BASE     = 0x30000,
@@ -101,10 +171,20 @@
 			 NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
 			 NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
 
-#define CH_DEVICE(devid) { PCI_VDEVICE(CHELSIO, devid), 0 }
+#define CH_DEVICE(devid, data) { PCI_VDEVICE(CHELSIO, devid), (data) }
 
 static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = {
-	CH_DEVICE(0xa000),  /* PE10K */
+	CH_DEVICE(0xa000, 0),  /* PE10K */
+	CH_DEVICE(0x4001, 0),
+	CH_DEVICE(0x4002, 0),
+	CH_DEVICE(0x4003, 0),
+	CH_DEVICE(0x4004, 0),
+	CH_DEVICE(0x4005, 0),
+	CH_DEVICE(0x4006, 0),
+	CH_DEVICE(0x4007, 0),
+	CH_DEVICE(0x4008, 0),
+	CH_DEVICE(0x4009, 0),
+	CH_DEVICE(0x400a, 0),
 	{ 0, }
 };
 
@@ -216,7 +296,7 @@
 void t4_os_portmod_changed(const struct adapter *adap, int port_id)
 {
 	static const char *mod_str[] = {
-		NULL, "LR", "SR", "ER", "passive DA", "active DA"
+		NULL, "LR", "SR", "ER", "passive DA", "active DA", "LRM"
 	};
 
 	const struct net_device *dev = adap->port[port_id];
@@ -224,7 +304,7 @@
 
 	if (pi->mod_type == FW_PORT_MOD_TYPE_NONE)
 		netdev_info(dev, "port module unplugged\n");
-	else
+	else if (pi->mod_type < ARRAY_SIZE(mod_str))
 		netdev_info(dev, "%s module inserted\n", mod_str[pi->mod_type]);
 }
 
@@ -244,12 +324,13 @@
 	int uc_cnt = netdev_uc_count(dev);
 	int mc_cnt = netdev_mc_count(dev);
 	const struct port_info *pi = netdev_priv(dev);
+	unsigned int mb = pi->adapter->fn;
 
 	/* first do the secondary unicast addresses */
 	netdev_for_each_uc_addr(ha, dev) {
 		addr[naddr++] = ha->addr;
 		if (--uc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) {
-			ret = t4_alloc_mac_filt(pi->adapter, 0, pi->viid, free,
+			ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free,
 					naddr, addr, filt_idx, &uhash, sleep);
 			if (ret < 0)
 				return ret;
@@ -263,7 +344,7 @@
 	netdev_for_each_mc_addr(ha, dev) {
 		addr[naddr++] = ha->addr;
 		if (--mc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) {
-			ret = t4_alloc_mac_filt(pi->adapter, 0, pi->viid, free,
+			ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free,
 					naddr, addr, filt_idx, &mhash, sleep);
 			if (ret < 0)
 				return ret;
@@ -273,7 +354,7 @@
 		}
 	}
 
-	return t4_set_addr_hash(pi->adapter, 0, pi->viid, uhash != 0,
+	return t4_set_addr_hash(pi->adapter, mb, pi->viid, uhash != 0,
 				uhash | mhash, sleep);
 }
 
@@ -288,7 +369,7 @@
 
 	ret = set_addr_filters(dev, sleep_ok);
 	if (ret == 0)
-		ret = t4_set_rxmode(pi->adapter, 0, pi->viid, mtu,
+		ret = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, mtu,
 				    (dev->flags & IFF_PROMISC) ? 1 : 0,
 				    (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1,
 				    sleep_ok);
@@ -305,15 +386,16 @@
 {
 	int ret;
 	struct port_info *pi = netdev_priv(dev);
+	unsigned int mb = pi->adapter->fn;
 
 	/*
 	 * We do not set address filters and promiscuity here, the stack does
 	 * that step explicitly.
 	 */
-	ret = t4_set_rxmode(pi->adapter, 0, pi->viid, dev->mtu, -1, -1, -1,
+	ret = t4_set_rxmode(pi->adapter, mb, pi->viid, dev->mtu, -1, -1, -1,
 			    pi->vlan_grp != NULL, true);
 	if (ret == 0) {
-		ret = t4_change_mac(pi->adapter, 0, pi->viid,
+		ret = t4_change_mac(pi->adapter, mb, pi->viid,
 				    pi->xact_addr_filt, dev->dev_addr, true,
 				    true);
 		if (ret >= 0) {
@@ -322,9 +404,10 @@
 		}
 	}
 	if (ret == 0)
-		ret = t4_link_start(pi->adapter, 0, pi->tx_chan, &pi->link_cfg);
+		ret = t4_link_start(pi->adapter, mb, pi->tx_chan,
+				    &pi->link_cfg);
 	if (ret == 0)
-		ret = t4_enable_vi(pi->adapter, 0, pi->viid, true, true);
+		ret = t4_enable_vi(pi->adapter, mb, pi->viid, true, true);
 	return ret;
 }
 
@@ -527,30 +610,47 @@
 }
 
 /**
+ *	write_rss - write the RSS table for a given port
+ *	@pi: the port
+ *	@queues: array of queue indices for RSS
+ *
+ *	Sets up the portion of the HW RSS table for the port's VI to distribute
+ *	packets to the Rx queues in @queues.
+ */
+static int write_rss(const struct port_info *pi, const u16 *queues)
+{
+	u16 *rss;
+	int i, err;
+	const struct sge_eth_rxq *q = &pi->adapter->sge.ethrxq[pi->first_qset];
+
+	rss = kmalloc(pi->rss_size * sizeof(u16), GFP_KERNEL);
+	if (!rss)
+		return -ENOMEM;
+
+	/* map the queue indices to queue ids */
+	for (i = 0; i < pi->rss_size; i++, queues++)
+		rss[i] = q[*queues].rspq.abs_id;
+
+	err = t4_config_rss_range(pi->adapter, pi->adapter->fn, pi->viid, 0,
+				  pi->rss_size, rss, pi->rss_size);
+	kfree(rss);
+	return err;
+}
+
+/**
  *	setup_rss - configure RSS
  *	@adap: the adapter
  *
- *	Sets up RSS to distribute packets to multiple receive queues.  We
- *	configure the RSS CPU lookup table to distribute to the number of HW
- *	receive queues, and the response queue lookup table to narrow that
- *	down to the response queues actually configured for each port.
- *	We always configure the RSS mapping for all ports since the mapping
- *	table has plenty of entries.
+ *	Sets up RSS for each port.
  */
 static int setup_rss(struct adapter *adap)
 {
-	int i, j, err;
-	u16 rss[MAX_ETH_QSETS];
+	int i, err;
 
 	for_each_port(adap, i) {
 		const struct port_info *pi = adap2pinfo(adap, i);
-		const struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset];
 
-		for (j = 0; j < pi->nqsets; j++)
-			rss[j] = q[j].rspq.abs_id;
-
-		err = t4_config_rss_range(adap, 0, pi->viid, 0, pi->rss_size,
-					  rss, pi->nqsets);
+		err = write_rss(pi, pi->rss);
 		if (err)
 			return err;
 	}
@@ -963,10 +1063,11 @@
  * Return a version number to identify the type of adapter.  The scheme is:
  * - bits 0..9: chip version
  * - bits 10..15: chip revision
+ * - bits 16..23: register dump version
  */
 static inline unsigned int mk_adap_vers(const struct adapter *ap)
 {
-	return 4 | (ap->params.rev << 10);
+	return 4 | (ap->params.rev << 10) | (1 << 16);
 }
 
 static void reg_block_dump(struct adapter *ap, void *buf, unsigned int start,
@@ -1041,7 +1142,9 @@
 		0xdfc0, 0xdfe0,
 		0xe000, 0xea7c,
 		0xf000, 0x11190,
-		0x19040, 0x19124,
+		0x19040, 0x1906c,
+		0x19078, 0x19080,
+		0x1908c, 0x19124,
 		0x19150, 0x191b0,
 		0x191d0, 0x191e8,
 		0x19238, 0x1924c,
@@ -1054,49 +1157,49 @@
 		0x1a190, 0x1a1c4,
 		0x1a1fc, 0x1a1fc,
 		0x1e040, 0x1e04c,
-		0x1e240, 0x1e28c,
+		0x1e284, 0x1e28c,
 		0x1e2c0, 0x1e2c0,
 		0x1e2e0, 0x1e2e0,
 		0x1e300, 0x1e384,
 		0x1e3c0, 0x1e3c8,
 		0x1e440, 0x1e44c,
-		0x1e640, 0x1e68c,
+		0x1e684, 0x1e68c,
 		0x1e6c0, 0x1e6c0,
 		0x1e6e0, 0x1e6e0,
 		0x1e700, 0x1e784,
 		0x1e7c0, 0x1e7c8,
 		0x1e840, 0x1e84c,
-		0x1ea40, 0x1ea8c,
+		0x1ea84, 0x1ea8c,
 		0x1eac0, 0x1eac0,
 		0x1eae0, 0x1eae0,
 		0x1eb00, 0x1eb84,
 		0x1ebc0, 0x1ebc8,
 		0x1ec40, 0x1ec4c,
-		0x1ee40, 0x1ee8c,
+		0x1ee84, 0x1ee8c,
 		0x1eec0, 0x1eec0,
 		0x1eee0, 0x1eee0,
 		0x1ef00, 0x1ef84,
 		0x1efc0, 0x1efc8,
 		0x1f040, 0x1f04c,
-		0x1f240, 0x1f28c,
+		0x1f284, 0x1f28c,
 		0x1f2c0, 0x1f2c0,
 		0x1f2e0, 0x1f2e0,
 		0x1f300, 0x1f384,
 		0x1f3c0, 0x1f3c8,
 		0x1f440, 0x1f44c,
-		0x1f640, 0x1f68c,
+		0x1f684, 0x1f68c,
 		0x1f6c0, 0x1f6c0,
 		0x1f6e0, 0x1f6e0,
 		0x1f700, 0x1f784,
 		0x1f7c0, 0x1f7c8,
 		0x1f840, 0x1f84c,
-		0x1fa40, 0x1fa8c,
+		0x1fa84, 0x1fa8c,
 		0x1fac0, 0x1fac0,
 		0x1fae0, 0x1fae0,
 		0x1fb00, 0x1fb84,
 		0x1fbc0, 0x1fbc8,
 		0x1fc40, 0x1fc4c,
-		0x1fe40, 0x1fe8c,
+		0x1fe84, 0x1fe8c,
 		0x1fec0, 0x1fec0,
 		0x1fee0, 0x1fee0,
 		0x1ff00, 0x1ff84,
@@ -1217,16 +1320,18 @@
 		return -EAGAIN;
 	if (p->link_cfg.autoneg != AUTONEG_ENABLE)
 		return -EINVAL;
-	t4_restart_aneg(p->adapter, 0, p->tx_chan);
+	t4_restart_aneg(p->adapter, p->adapter->fn, p->tx_chan);
 	return 0;
 }
 
 static int identify_port(struct net_device *dev, u32 data)
 {
+	struct adapter *adap = netdev2adap(dev);
+
 	if (data == 0)
 		data = 2;     /* default to 2 seconds */
 
-	return t4_identify_port(netdev2adap(dev), 0, netdev2pinfo(dev)->viid,
+	return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid,
 				data * 5);
 }
 
@@ -1234,7 +1339,8 @@
 {
 	unsigned int v = 0;
 
-	if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XAUI) {
+	if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XFI ||
+	    type == FW_PORT_TYPE_BT_XAUI) {
 		v |= SUPPORTED_TP;
 		if (caps & FW_PORT_CAP_SPEED_100M)
 			v |= SUPPORTED_100baseT_Full;
@@ -1250,7 +1356,10 @@
 			v |= SUPPORTED_10000baseKX4_Full;
 	} else if (type == FW_PORT_TYPE_KR)
 		v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full;
-	else if (type == FW_PORT_TYPE_FIBER)
+	else if (type == FW_PORT_TYPE_BP_AP)
+		v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC;
+	else if (type == FW_PORT_TYPE_FIBER_XFI ||
+		 type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP)
 		v |= SUPPORTED_FIBRE;
 
 	if (caps & FW_PORT_CAP_ANEG)
@@ -1276,13 +1385,19 @@
 	const struct port_info *p = netdev_priv(dev);
 
 	if (p->port_type == FW_PORT_TYPE_BT_SGMII ||
+	    p->port_type == FW_PORT_TYPE_BT_XFI ||
 	    p->port_type == FW_PORT_TYPE_BT_XAUI)
 		cmd->port = PORT_TP;
-	else if (p->port_type == FW_PORT_TYPE_FIBER)
+	else if (p->port_type == FW_PORT_TYPE_FIBER_XFI ||
+		 p->port_type == FW_PORT_TYPE_FIBER_XAUI)
 		cmd->port = PORT_FIBRE;
-	else if (p->port_type == FW_PORT_TYPE_TWINAX)
-		cmd->port = PORT_DA;
-	else
+	else if (p->port_type == FW_PORT_TYPE_SFP) {
+		if (p->mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE ||
+		    p->mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE)
+			cmd->port = PORT_DA;
+		else
+			cmd->port = PORT_FIBRE;
+	} else
 		cmd->port = PORT_OTHER;
 
 	if (p->mdio_addr >= 0) {
@@ -1356,7 +1471,8 @@
 	lc->autoneg = cmd->autoneg;
 
 	if (netif_running(dev))
-		return t4_link_start(p->adapter, 0, p->tx_chan, lc);
+		return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan,
+				     lc);
 	return 0;
 }
 
@@ -1388,7 +1504,8 @@
 	if (epause->tx_pause)
 		lc->requested_fc |= PAUSE_TX;
 	if (netif_running(dev))
-		return t4_link_start(p->adapter, 0, p->tx_chan, lc);
+		return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan,
+				     lc);
 	return 0;
 }
 
@@ -1520,7 +1637,8 @@
 			v = FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) |
 			    FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH) |
 			    FW_PARAMS_PARAM_YZ(q->cntxt_id);
-			err = t4_set_params(adap, 0, 0, 0, 1, &v, &new_idx);
+			err = t4_set_params(adap, adap->fn, adap->fn, 0, 1, &v,
+					    &new_idx);
 			if (err)
 				return err;
 		}
@@ -1708,27 +1826,114 @@
 	return err;
 }
 
+#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
+
 static int set_tso(struct net_device *dev, u32 value)
 {
 	if (value)
-		dev->features |= NETIF_F_TSO | NETIF_F_TSO6;
+		dev->features |= TSO_FLAGS;
 	else
-		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+		dev->features &= ~TSO_FLAGS;
 	return 0;
 }
 
 static int set_flags(struct net_device *dev, u32 flags)
 {
-	if (flags & ~ETH_FLAG_RXHASH)
-		return -EOPNOTSUPP;
+	return ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH);
+}
 
-	if (flags & ETH_FLAG_RXHASH)
-		dev->features |= NETIF_F_RXHASH;
-	else
-		dev->features &= ~NETIF_F_RXHASH;
+static int get_rss_table(struct net_device *dev, struct ethtool_rxfh_indir *p)
+{
+	const struct port_info *pi = netdev_priv(dev);
+	unsigned int n = min_t(unsigned int, p->size, pi->rss_size);
+
+	p->size = pi->rss_size;
+	while (n--)
+		p->ring_index[n] = pi->rss[n];
 	return 0;
 }
 
+static int set_rss_table(struct net_device *dev,
+			 const struct ethtool_rxfh_indir *p)
+{
+	unsigned int i;
+	struct port_info *pi = netdev_priv(dev);
+
+	if (p->size != pi->rss_size)
+		return -EINVAL;
+	for (i = 0; i < p->size; i++)
+		if (p->ring_index[i] >= pi->nqsets)
+			return -EINVAL;
+	for (i = 0; i < p->size; i++)
+		pi->rss[i] = p->ring_index[i];
+	if (pi->adapter->flags & FULL_INIT_DONE)
+		return write_rss(pi, pi->rss);
+	return 0;
+}
+
+static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
+		     void *rules)
+{
+	const struct port_info *pi = netdev_priv(dev);
+
+	switch (info->cmd) {
+	case ETHTOOL_GRXFH: {
+		unsigned int v = pi->rss_mode;
+
+		info->data = 0;
+		switch (info->flow_type) {
+		case TCP_V4_FLOW:
+			if (v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN)
+				info->data = RXH_IP_SRC | RXH_IP_DST |
+					     RXH_L4_B_0_1 | RXH_L4_B_2_3;
+			else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN)
+				info->data = RXH_IP_SRC | RXH_IP_DST;
+			break;
+		case UDP_V4_FLOW:
+			if ((v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN) &&
+			    (v & FW_RSS_VI_CONFIG_CMD_UDPEN))
+				info->data = RXH_IP_SRC | RXH_IP_DST |
+					     RXH_L4_B_0_1 | RXH_L4_B_2_3;
+			else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN)
+				info->data = RXH_IP_SRC | RXH_IP_DST;
+			break;
+		case SCTP_V4_FLOW:
+		case AH_ESP_V4_FLOW:
+		case IPV4_FLOW:
+			if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN)
+				info->data = RXH_IP_SRC | RXH_IP_DST;
+			break;
+		case TCP_V6_FLOW:
+			if (v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN)
+				info->data = RXH_IP_SRC | RXH_IP_DST |
+					     RXH_L4_B_0_1 | RXH_L4_B_2_3;
+			else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN)
+				info->data = RXH_IP_SRC | RXH_IP_DST;
+			break;
+		case UDP_V6_FLOW:
+			if ((v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN) &&
+			    (v & FW_RSS_VI_CONFIG_CMD_UDPEN))
+				info->data = RXH_IP_SRC | RXH_IP_DST |
+					     RXH_L4_B_0_1 | RXH_L4_B_2_3;
+			else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN)
+				info->data = RXH_IP_SRC | RXH_IP_DST;
+			break;
+		case SCTP_V6_FLOW:
+		case AH_ESP_V6_FLOW:
+		case IPV6_FLOW:
+			if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN)
+				info->data = RXH_IP_SRC | RXH_IP_DST;
+			break;
+		}
+		return 0;
+	}
+	case ETHTOOL_GRXRINGS:
+		info->data = pi->nqsets;
+		return 0;
+	}
+	return -EOPNOTSUPP;
+}
+
 static struct ethtool_ops cxgb_ethtool_ops = {
 	.get_settings      = get_settings,
 	.set_settings      = set_settings,
@@ -1760,6 +1965,9 @@
 	.set_wol           = set_wol,
 	.set_tso           = set_tso,
 	.set_flags         = set_flags,
+	.get_rxnfc         = get_rxnfc,
+	.get_rxfh_indir    = get_rss_table,
+	.set_rxfh_indir    = set_rss_table,
 	.flash_device      = set_flash,
 };
 
@@ -2306,9 +2514,11 @@
 	lli.adapter_type = adap->params.rev;
 	lli.iscsi_iolen = MAXRXDATA_GET(t4_read_reg(adap, TP_PARA_REG2));
 	lli.udb_density = 1 << QUEUESPERPAGEPF0_GET(
-			t4_read_reg(adap, SGE_EGRESS_QUEUES_PER_PAGE_PF));
+			t4_read_reg(adap, SGE_EGRESS_QUEUES_PER_PAGE_PF) >>
+			(adap->fn * 4));
 	lli.ucq_density = 1 << QUEUESPERPAGEPF0_GET(
-			t4_read_reg(adap, SGE_INGRESS_QUEUES_PER_PAGE_PF));
+			t4_read_reg(adap, SGE_INGRESS_QUEUES_PER_PAGE_PF) >>
+			(adap->fn * 4));
 	lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS);
 	lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL);
 	lli.fw_vers = adap->params.fw_vers;
@@ -2483,6 +2693,7 @@
 	t4_intr_disable(adapter);
 	cancel_work_sync(&adapter->tid_release_task);
 	adapter->tid_release_task_busy = false;
+	adapter->tid_release_head = NULL;
 
 	if (adapter->flags & USING_MSIX) {
 		free_msix_queue_irqs(adapter);
@@ -2511,9 +2722,10 @@
 	}
 
 	dev->real_num_tx_queues = pi->nqsets;
-	link_start(dev);
-	netif_tx_start_all_queues(dev);
-	return 0;
+	err = link_start(dev);
+	if (!err)
+		netif_tx_start_all_queues(dev);
+	return err;
 }
 
 static int cxgb_close(struct net_device *dev)
@@ -2523,15 +2735,15 @@
 
 	netif_tx_stop_all_queues(dev);
 	netif_carrier_off(dev);
-	return t4_enable_vi(adapter, 0, pi->viid, false, false);
+	return t4_enable_vi(adapter, adapter->fn, pi->viid, false, false);
 }
 
-static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *cxgb_get_stats(struct net_device *dev,
+						struct rtnl_link_stats64 *ns)
 {
 	struct port_stats stats;
 	struct port_info *p = netdev_priv(dev);
 	struct adapter *adapter = p->adapter;
-	struct net_device_stats *ns = &dev->stats;
 
 	spin_lock(&adapter->stats_lock);
 	t4_get_port_stats(adapter, p->tx_chan, &stats);
@@ -2570,6 +2782,7 @@
 
 static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
 {
+	unsigned int mbox;
 	int ret = 0, prtad, devad;
 	struct port_info *pi = netdev_priv(dev);
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&req->ifr_data;
@@ -2592,11 +2805,12 @@
 		} else
 			return -EINVAL;
 
+		mbox = pi->adapter->fn;
 		if (cmd == SIOCGMIIREG)
-			ret = t4_mdio_rd(pi->adapter, 0, prtad, devad,
+			ret = t4_mdio_rd(pi->adapter, mbox, prtad, devad,
 					 data->reg_num, &data->val_out);
 		else
-			ret = t4_mdio_wr(pi->adapter, 0, prtad, devad,
+			ret = t4_mdio_wr(pi->adapter, mbox, prtad, devad,
 					 data->reg_num, data->val_in);
 		break;
 	default:
@@ -2618,8 +2832,8 @@
 
 	if (new_mtu < 81 || new_mtu > MAX_MTU)         /* accommodate SACK */
 		return -EINVAL;
-	ret = t4_set_rxmode(pi->adapter, 0, pi->viid, new_mtu, -1, -1, -1, -1,
-			    true);
+	ret = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, new_mtu, -1,
+			    -1, -1, -1, true);
 	if (!ret)
 		dev->mtu = new_mtu;
 	return ret;
@@ -2634,8 +2848,8 @@
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EINVAL;
 
-	ret = t4_change_mac(pi->adapter, 0, pi->viid, pi->xact_addr_filt,
-			    addr->sa_data, true, true);
+	ret = t4_change_mac(pi->adapter, pi->adapter->fn, pi->viid,
+			    pi->xact_addr_filt, addr->sa_data, true, true);
 	if (ret < 0)
 		return ret;
 
@@ -2649,8 +2863,8 @@
 	struct port_info *pi = netdev_priv(dev);
 
 	pi->vlan_grp = grp;
-	t4_set_rxmode(pi->adapter, 0, pi->viid, -1, -1, -1, -1, grp != NULL,
-		      true);
+	t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1, -1, -1, -1,
+		      grp != NULL, true);
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2674,7 +2888,7 @@
 	.ndo_open             = cxgb_open,
 	.ndo_stop             = cxgb_close,
 	.ndo_start_xmit       = t4_eth_xmit,
-	.ndo_get_stats        = cxgb_get_stats,
+	.ndo_get_stats64      = cxgb_get_stats,
 	.ndo_set_rx_mode      = cxgb_set_rxmode,
 	.ndo_set_mac_address  = cxgb_set_mac_addr,
 	.ndo_validate_addr    = eth_validate_addr,
@@ -2707,6 +2921,76 @@
 	t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2),
 		     (bar0 + MEMWIN2_BASE) | BIR(0) |
 		     WINDOW(ilog2(MEMWIN2_APERTURE) - 10));
+	if (adap->vres.ocq.size) {
+		unsigned int start, sz_kb;
+
+		start = pci_resource_start(adap->pdev, 2) +
+			OCQ_WIN_OFFSET(adap->pdev, &adap->vres);
+		sz_kb = roundup_pow_of_two(adap->vres.ocq.size) >> 10;
+		t4_write_reg(adap,
+			     PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 3),
+			     start | BIR(1) | WINDOW(ilog2(sz_kb)));
+		t4_write_reg(adap,
+			     PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3),
+			     adap->vres.ocq.start);
+		t4_read_reg(adap,
+			    PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3));
+	}
+}
+
+static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
+{
+	u32 v;
+	int ret;
+
+	/* get device capabilities */
+	memset(c, 0, sizeof(*c));
+	c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
+			       FW_CMD_REQUEST | FW_CMD_READ);
+	c->retval_len16 = htonl(FW_LEN16(*c));
+	ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), c);
+	if (ret < 0)
+		return ret;
+
+	/* select capabilities we'll be using */
+	if (c->niccaps & htons(FW_CAPS_CONFIG_NIC_VM)) {
+		if (!vf_acls)
+			c->niccaps ^= htons(FW_CAPS_CONFIG_NIC_VM);
+		else
+			c->niccaps = htons(FW_CAPS_CONFIG_NIC_VM);
+	} else if (vf_acls) {
+		dev_err(adap->pdev_dev, "virtualization ACLs not supported");
+		return ret;
+	}
+	c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
+			       FW_CMD_REQUEST | FW_CMD_WRITE);
+	ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), NULL);
+	if (ret < 0)
+		return ret;
+
+	ret = t4_config_glbl_rss(adap, adap->fn,
+				 FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL,
+				 FW_RSS_GLB_CONFIG_CMD_TNLMAPEN |
+				 FW_RSS_GLB_CONFIG_CMD_TNLALLLKP);
+	if (ret < 0)
+		return ret;
+
+	ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, MAX_EGRQ, 64, MAX_INGQ,
+			  0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, FW_CMD_CAP_PF);
+	if (ret < 0)
+		return ret;
+
+	t4_sge_init(adap);
+
+	/* tweak some settings */
+	t4_write_reg(adap, TP_SHIFT_CNT, 0x64f8849);
+	t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(PAGE_SHIFT - 12));
+	t4_write_reg(adap, TP_PIO_ADDR, TP_INGRESS_CONFIG);
+	v = t4_read_reg(adap, TP_PIO_DATA);
+	t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR);
+
+	/* get basic stuff going */
+	return t4_early_init(adap, adap->fn);
 }
 
 /*
@@ -2734,7 +3018,7 @@
 		return ret;
 
 	/* contact FW, request master */
-	ret = t4_fw_hello(adap, 0, 0, MASTER_MUST, &state);
+	ret = t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, &state);
 	if (ret < 0) {
 		dev_err(adap->pdev_dev, "could not connect to FW, error %d\n",
 			ret);
@@ -2742,44 +3026,7 @@
 	}
 
 	/* reset device */
-	ret = t4_fw_reset(adap, 0, PIORSTMODE | PIORST);
-	if (ret < 0)
-		goto bye;
-
-	/* get device capabilities */
-	memset(&c, 0, sizeof(c));
-	c.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
-			      FW_CMD_REQUEST | FW_CMD_READ);
-	c.retval_len16 = htonl(FW_LEN16(c));
-	ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c);
-	if (ret < 0)
-		goto bye;
-
-	/* select capabilities we'll be using */
-	if (c.niccaps & htons(FW_CAPS_CONFIG_NIC_VM)) {
-		if (!vf_acls)
-			c.niccaps ^= htons(FW_CAPS_CONFIG_NIC_VM);
-		else
-			c.niccaps = htons(FW_CAPS_CONFIG_NIC_VM);
-	} else if (vf_acls) {
-		dev_err(adap->pdev_dev, "virtualization ACLs not supported");
-		goto bye;
-	}
-	c.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
-			      FW_CMD_REQUEST | FW_CMD_WRITE);
-	ret = t4_wr_mbox(adap, 0, &c, sizeof(c), NULL);
-	if (ret < 0)
-		goto bye;
-
-	ret = t4_config_glbl_rss(adap, 0,
-				 FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL,
-				 FW_RSS_GLB_CONFIG_CMD_TNLMAPEN |
-				 FW_RSS_GLB_CONFIG_CMD_TNLALLLKP);
-	if (ret < 0)
-		goto bye;
-
-	ret = t4_cfg_pfvf(adap, 0, 0, 0, 64, 64, 64, 0, 0, 4, 0xf, 0xf, 16,
-			  FW_CMD_CAP_PF, FW_CMD_CAP_PF);
+	ret = t4_fw_reset(adap, adap->fn, PIORSTMODE | PIORST);
 	if (ret < 0)
 		goto bye;
 
@@ -2790,27 +3037,31 @@
 	for (v = 1; v < SGE_NCOUNTERS; v++)
 		adap->sge.counter_val[v] = min(intr_cnt[v - 1],
 					       THRESHOLD_3_MASK);
-	t4_sge_init(adap);
-
-	/* get basic stuff going */
-	ret = t4_early_init(adap, 0);
-	if (ret < 0)
-		goto bye;
-
 #define FW_PARAM_DEV(param) \
 	(FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
 	 FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
 
+	params[0] = FW_PARAM_DEV(CCLK);
+	ret = t4_query_params(adap, adap->fn, adap->fn, 0, 1, params, val);
+	if (ret < 0)
+		goto bye;
+	adap->params.vpd.cclk = val[0];
+
+	ret = adap_init1(adap, &c);
+	if (ret < 0)
+		goto bye;
+
 #define FW_PARAM_PFVF(param) \
 	(FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
-	 FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param))
+	 FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param) | \
+	 FW_PARAMS_PARAM_Y(adap->fn))
 
 	params[0] = FW_PARAM_DEV(PORTVEC);
 	params[1] = FW_PARAM_PFVF(L2T_START);
 	params[2] = FW_PARAM_PFVF(L2T_END);
 	params[3] = FW_PARAM_PFVF(FILTER_START);
 	params[4] = FW_PARAM_PFVF(FILTER_END);
-	ret = t4_query_params(adap, 0, 0, 0, 5, params, val);
+	ret = t4_query_params(adap, adap->fn, adap->fn, 0, 5, params, val);
 	if (ret < 0)
 		goto bye;
 	port_vec = val[0];
@@ -2825,7 +3076,8 @@
 		params[3] = FW_PARAM_PFVF(TDDP_START);
 		params[4] = FW_PARAM_PFVF(TDDP_END);
 		params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
-		ret = t4_query_params(adap, 0, 0, 0, 6, params, val);
+		ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params,
+				      val);
 		if (ret < 0)
 			goto bye;
 		adap->tids.ntids = val[0];
@@ -2844,7 +3096,8 @@
 		params[3] = FW_PARAM_PFVF(RQ_END);
 		params[4] = FW_PARAM_PFVF(PBL_START);
 		params[5] = FW_PARAM_PFVF(PBL_END);
-		ret = t4_query_params(adap, 0, 0, 0, 6, params, val);
+		ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params,
+				      val);
 		if (ret < 0)
 			goto bye;
 		adap->vres.stag.start = val[0];
@@ -2853,11 +3106,29 @@
 		adap->vres.rq.size = val[3] - val[2] + 1;
 		adap->vres.pbl.start = val[4];
 		adap->vres.pbl.size = val[5] - val[4] + 1;
+
+		params[0] = FW_PARAM_PFVF(SQRQ_START);
+		params[1] = FW_PARAM_PFVF(SQRQ_END);
+		params[2] = FW_PARAM_PFVF(CQ_START);
+		params[3] = FW_PARAM_PFVF(CQ_END);
+		params[4] = FW_PARAM_PFVF(OCQ_START);
+		params[5] = FW_PARAM_PFVF(OCQ_END);
+		ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params,
+				      val);
+		if (ret < 0)
+			goto bye;
+		adap->vres.qp.start = val[0];
+		adap->vres.qp.size = val[1] - val[0] + 1;
+		adap->vres.cq.start = val[2];
+		adap->vres.cq.size = val[3] - val[2] + 1;
+		adap->vres.ocq.start = val[4];
+		adap->vres.ocq.size = val[5] - val[4] + 1;
 	}
 	if (c.iscsicaps) {
 		params[0] = FW_PARAM_PFVF(ISCSI_START);
 		params[1] = FW_PARAM_PFVF(ISCSI_END);
-		ret = t4_query_params(adap, 0, 0, 0, 2, params, val);
+		ret = t4_query_params(adap, adap->fn, adap->fn, 0, 2, params,
+				      val);
 		if (ret < 0)
 			goto bye;
 		adap->vres.iscsi.start = val[0];
@@ -2877,12 +3148,41 @@
 	t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd,
 		     adap->params.b_wnd);
 
-	/* tweak some settings */
-	t4_write_reg(adap, TP_SHIFT_CNT, 0x64f8849);
-	t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(PAGE_SHIFT - 12));
-	t4_write_reg(adap, TP_PIO_ADDR, TP_INGRESS_CONFIG);
-	v = t4_read_reg(adap, TP_PIO_DATA);
-	t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR);
+#ifdef CONFIG_PCI_IOV
+	/*
+	 * Provision resource limits for Virtual Functions.  We currently
+	 * grant them all the same static resource limits except for the Port
+	 * Access Rights Mask which we're assigning based on the PF.  All of
+	 * the static provisioning stuff for both the PF and VF really needs
+	 * to be managed in a persistent manner for each device which the
+	 * firmware controls.
+	 */
+	{
+		int pf, vf;
+
+		for (pf = 0; pf < ARRAY_SIZE(num_vf); pf++) {
+			if (num_vf[pf] <= 0)
+				continue;
+
+			/* VF numbering starts at 1! */
+			for (vf = 1; vf <= num_vf[pf]; vf++) {
+				ret = t4_cfg_pfvf(adap, adap->fn, pf, vf,
+						  VFRES_NEQ, VFRES_NETHCTRL,
+						  VFRES_NIQFLINT, VFRES_NIQ,
+						  VFRES_TC, VFRES_NVI,
+						  FW_PFVF_CMD_CMASK_MASK,
+						  pfvfres_pmask(adap, pf, vf),
+						  VFRES_NEXACTF,
+						  VFRES_R_CAPS, VFRES_WX_CAPS);
+				if (ret < 0)
+					dev_warn(adap->pdev_dev, "failed to "
+						 "provision pf/vf=%d/%d; "
+						 "err=%d\n", pf, vf, ret);
+			}
+		}
+	}
+#endif
+
 	setup_memwin(adap);
 	return 0;
 
@@ -2892,10 +3192,114 @@
 	 * commands.
 	 */
 bye:	if (ret != -ETIMEDOUT && ret != -EIO)
-		t4_fw_bye(adap, 0);
+		t4_fw_bye(adap, adap->fn);
 	return ret;
 }
 
+/* EEH callbacks */
+
+static pci_ers_result_t eeh_err_detected(struct pci_dev *pdev,
+					 pci_channel_state_t state)
+{
+	int i;
+	struct adapter *adap = pci_get_drvdata(pdev);
+
+	if (!adap)
+		goto out;
+
+	rtnl_lock();
+	adap->flags &= ~FW_OK;
+	notify_ulds(adap, CXGB4_STATE_START_RECOVERY);
+	for_each_port(adap, i) {
+		struct net_device *dev = adap->port[i];
+
+		netif_device_detach(dev);
+		netif_carrier_off(dev);
+	}
+	if (adap->flags & FULL_INIT_DONE)
+		cxgb_down(adap);
+	rtnl_unlock();
+	pci_disable_device(pdev);
+out:	return state == pci_channel_io_perm_failure ?
+		PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev)
+{
+	int i, ret;
+	struct fw_caps_config_cmd c;
+	struct adapter *adap = pci_get_drvdata(pdev);
+
+	if (!adap) {
+		pci_restore_state(pdev);
+		pci_save_state(pdev);
+		return PCI_ERS_RESULT_RECOVERED;
+	}
+
+	if (pci_enable_device(pdev)) {
+		dev_err(&pdev->dev, "cannot reenable PCI device after reset\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+
+	pci_set_master(pdev);
+	pci_restore_state(pdev);
+	pci_save_state(pdev);
+	pci_cleanup_aer_uncorrect_error_status(pdev);
+
+	if (t4_wait_dev_ready(adap) < 0)
+		return PCI_ERS_RESULT_DISCONNECT;
+	if (t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, NULL))
+		return PCI_ERS_RESULT_DISCONNECT;
+	adap->flags |= FW_OK;
+	if (adap_init1(adap, &c))
+		return PCI_ERS_RESULT_DISCONNECT;
+
+	for_each_port(adap, i) {
+		struct port_info *p = adap2pinfo(adap, i);
+
+		ret = t4_alloc_vi(adap, adap->fn, p->tx_chan, adap->fn, 0, 1,
+				  NULL, NULL);
+		if (ret < 0)
+			return PCI_ERS_RESULT_DISCONNECT;
+		p->viid = ret;
+		p->xact_addr_filt = -1;
+	}
+
+	t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd,
+		     adap->params.b_wnd);
+	setup_memwin(adap);
+	if (cxgb_up(adap))
+		return PCI_ERS_RESULT_DISCONNECT;
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void eeh_resume(struct pci_dev *pdev)
+{
+	int i;
+	struct adapter *adap = pci_get_drvdata(pdev);
+
+	if (!adap)
+		return;
+
+	rtnl_lock();
+	for_each_port(adap, i) {
+		struct net_device *dev = adap->port[i];
+
+		if (netif_running(dev)) {
+			link_start(dev);
+			cxgb_set_rxmode(dev);
+		}
+		netif_device_attach(dev);
+	}
+	rtnl_unlock();
+}
+
+static struct pci_error_handlers cxgb4_eeh = {
+	.error_detected = eeh_err_detected,
+	.slot_reset     = eeh_slot_reset,
+	.resume         = eeh_resume,
+};
+
 static inline bool is_10g_port(const struct link_config *lc)
 {
 	return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0;
@@ -3076,10 +3480,27 @@
 
 #undef EXTRA_VECS
 
+static int __devinit init_rss(struct adapter *adap)
+{
+	unsigned int i, j;
+
+	for_each_port(adap, i) {
+		struct port_info *pi = adap2pinfo(adap, i);
+
+		pi->rss = kcalloc(pi->rss_size, sizeof(u16), GFP_KERNEL);
+		if (!pi->rss)
+			return -ENOMEM;
+		for (j = 0; j < pi->rss_size; j++)
+			pi->rss[j] = j % pi->nqsets;
+	}
+	return 0;
+}
+
 static void __devinit print_port_info(struct adapter *adap)
 {
 	static const char *base[] = {
-		"R", "KX4", "T", "KX", "T", "KR", "CX4"
+		"R XFI", "R XAUI", "T SGMII", "T XFI", "T XAUI", "KX4", "CX4",
+		"KX", "KR", "KR SFP+", "KR FEC"
 	};
 
 	int i;
@@ -3121,7 +3542,31 @@
 	}
 }
 
-#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |\
+/*
+ * Free the following resources:
+ * - memory used for tables
+ * - MSI/MSI-X
+ * - net devices
+ * - resources FW is holding for us
+ */
+static void free_some_resources(struct adapter *adapter)
+{
+	unsigned int i;
+
+	t4_free_mem(adapter->l2t);
+	t4_free_mem(adapter->tids.tid_tab);
+	disable_msi(adapter);
+
+	for_each_port(adapter, i)
+		if (adapter->port[i]) {
+			kfree(adap2pinfo(adapter, i)->rss);
+			free_netdev(adapter->port[i]);
+		}
+	if (adapter->flags & FW_OK)
+		t4_fw_bye(adapter, adapter->fn);
+}
+
+#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \
 		   NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA)
 
 static int __devinit init_one(struct pci_dev *pdev,
@@ -3141,10 +3586,12 @@
 		return err;
 	}
 
-	/* We control everything through PF 0 */
+	/* We control everything through one PF */
 	func = PCI_FUNC(pdev->devfn);
-	if (func > 0)
+	if (func != ent->driver_data) {
+		pci_save_state(pdev);        /* to restore SR-IOV later */
 		goto sriov;
+	}
 
 	err = pci_enable_device(pdev);
 	if (err) {
@@ -3187,6 +3634,7 @@
 
 	adapter->pdev = pdev;
 	adapter->pdev_dev = &pdev->dev;
+	adapter->fn = func;
 	adapter->name = pci_name(pdev);
 	adapter->msg_enable = dflt_msg_enable;
 	memset(adapter->chan_map, 0xff, sizeof(adapter->chan_map));
@@ -3225,7 +3673,7 @@
 		netif_tx_stop_all_queues(netdev);
 		netdev->irq = pdev->irq;
 
-		netdev->features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6;
+		netdev->features |= NETIF_F_SG | TSO_FLAGS;
 		netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
 		netdev->features |= NETIF_F_GRO | NETIF_F_RXHASH | highdma;
 		netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
@@ -3238,7 +3686,7 @@
 	pci_set_drvdata(pdev, adapter);
 
 	if (adapter->flags & FW_OK) {
-		err = t4_port_init(adapter, 0, 0, 0);
+		err = t4_port_init(adapter, func, func, 0);
 		if (err)
 			goto out_free_dev;
 	}
@@ -3262,6 +3710,16 @@
 		adapter->params.offload = 0;
 	}
 
+	/* See what interrupts we'll be using */
+	if (msi > 1 && enable_msix(adapter) == 0)
+		adapter->flags |= USING_MSIX;
+	else if (msi > 0 && pci_enable_msi(pdev) == 0)
+		adapter->flags |= USING_MSI;
+
+	err = init_rss(adapter);
+	if (err)
+		goto out_free_dev;
+
 	/*
 	 * The card is now ready to go.  If any errors occur during device
 	 * registration we do not fail the whole card but rather proceed only
@@ -3297,12 +3755,6 @@
 		setup_debugfs(adapter);
 	}
 
-	/* See what interrupts we'll be using */
-	if (msi > 1 && enable_msix(adapter) == 0)
-		adapter->flags |= USING_MSIX;
-	else if (msi > 0 && pci_enable_msi(pdev) == 0)
-		adapter->flags |= USING_MSI;
-
 	if (is_offload(adapter))
 		attach_ulds(adapter);
 
@@ -3319,13 +3771,7 @@
 	return 0;
 
  out_free_dev:
-	t4_free_mem(adapter->tids.tid_tab);
-	t4_free_mem(adapter->l2t);
-	for_each_port(adapter, i)
-		if (adapter->port[i])
-			free_netdev(adapter->port[i]);
-	if (adapter->flags & FW_OK)
-		t4_fw_bye(adapter, 0);
+	free_some_resources(adapter);
  out_unmap_bar:
 	iounmap(adapter->regs);
  out_free_adapter:
@@ -3360,16 +3806,8 @@
 
 		if (adapter->flags & FULL_INIT_DONE)
 			cxgb_down(adapter);
-		t4_free_mem(adapter->l2t);
-		t4_free_mem(adapter->tids.tid_tab);
-		disable_msi(adapter);
 
-		for_each_port(adapter, i)
-			if (adapter->port[i])
-				free_netdev(adapter->port[i]);
-
-		if (adapter->flags & FW_OK)
-			t4_fw_bye(adapter, 0);
+		free_some_resources(adapter);
 		iounmap(adapter->regs);
 		kfree(adapter);
 		pci_disable_pcie_error_reporting(pdev);
@@ -3385,6 +3823,7 @@
 	.id_table = cxgb4_pci_tbl,
 	.probe    = init_one,
 	.remove   = __devexit_p(remove_one),
+	.err_handler = &cxgb4_eeh,
 };
 
 static int __init cxgb4_init_module(void)
diff --git a/drivers/net/cxgb4/cxgb4_uld.h b/drivers/net/cxgb4/cxgb4_uld.h
index 5b98546..85d74e7 100644
--- a/drivers/net/cxgb4/cxgb4_uld.h
+++ b/drivers/net/cxgb4/cxgb4_uld.h
@@ -185,8 +185,14 @@
 	struct cxgb4_range stag;
 	struct cxgb4_range rq;
 	struct cxgb4_range pbl;
+	struct cxgb4_range qp;
+	struct cxgb4_range cq;
+	struct cxgb4_range ocq;
 };
 
+#define OCQ_WIN_OFFSET(pdev, vres) \
+	(pci_resource_len((pdev), 2) - roundup_pow_of_two((vres)->ocq.size))
+
 /*
  * Block of information the LLD provides to ULDs attaching to a device.
  */
diff --git a/drivers/net/cxgb4/l2t.c b/drivers/net/cxgb4/l2t.c
index 9f96724..e8f0f55 100644
--- a/drivers/net/cxgb4/l2t.c
+++ b/drivers/net/cxgb4/l2t.c
@@ -310,6 +310,13 @@
 			neigh_release(e->neigh);
 			e->neigh = NULL;
 		}
+		while (e->arpq_head) {
+			struct sk_buff *skb = e->arpq_head;
+
+			e->arpq_head = skb->next;
+			kfree_skb(skb);
+		}
+		e->arpq_tail = NULL;
 	}
 	spin_unlock_bh(&e->lock);
 
diff --git a/drivers/net/cxgb4/sge.c b/drivers/net/cxgb4/sge.c
index d1f8f22..bf38cfc 100644
--- a/drivers/net/cxgb4/sge.c
+++ b/drivers/net/cxgb4/sge.c
@@ -938,16 +938,16 @@
 
 		wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) |
 				       FW_WR_IMMDLEN(sizeof(*lso)));
-		lso->lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) |
-				      LSO_FIRST_SLICE | LSO_LAST_SLICE |
-				      LSO_IPV6(v6) |
-				      LSO_ETHHDR_LEN(eth_xtra_len / 4) |
-				      LSO_IPHDR_LEN(l3hdr_len / 4) |
-				      LSO_TCPHDR_LEN(tcp_hdr(skb)->doff));
-		lso->ipid_ofst = htons(0);
-		lso->mss = htons(ssi->gso_size);
-		lso->seqno_offset = htonl(0);
-		lso->len = htonl(skb->len);
+		lso->c.lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) |
+					LSO_FIRST_SLICE | LSO_LAST_SLICE |
+					LSO_IPV6(v6) |
+					LSO_ETHHDR_LEN(eth_xtra_len / 4) |
+					LSO_IPHDR_LEN(l3hdr_len / 4) |
+					LSO_TCPHDR_LEN(tcp_hdr(skb)->doff));
+		lso->c.ipid_ofst = htons(0);
+		lso->c.mss = htons(ssi->gso_size);
+		lso->c.seqno_offset = htonl(0);
+		lso->c.len = htonl(skb->len);
 		cpl = (void *)(lso + 1);
 		cntrl = TXPKT_CSUM_TYPE(v6 ? TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) |
 			TXPKT_IPHDR_LEN(l3hdr_len) |
@@ -1593,14 +1593,15 @@
 
 	if (csum_ok && (pi->rx_offload & RX_CSO) &&
 	    (pkt->l2info & htonl(RXF_UDP | RXF_TCP))) {
-		if (!pkt->ip_frag)
+		if (!pkt->ip_frag) {
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
-		else {
+			rxq->stats.rx_cso++;
+		} else if (pkt->l2info & htonl(RXF_IP)) {
 			__sum16 c = (__force __sum16)pkt->csum;
 			skb->csum = csum_unfold(c);
 			skb->ip_summed = CHECKSUM_COMPLETE;
+			rxq->stats.rx_cso++;
 		}
-		rxq->stats.rx_cso++;
 	} else
 		skb->ip_summed = CHECKSUM_NONE;
 
@@ -1718,7 +1719,7 @@
 					free_rx_bufs(q->adap, &rxq->fl, 1);
 					q->offset = 0;
 				}
-				len &= RSPD_LEN;
+				len = RSPD_LEN(len);
 			}
 			si.tot_len = len;
 
@@ -1998,7 +1999,7 @@
 	memset(&c, 0, sizeof(c));
 	c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST |
 			    FW_CMD_WRITE | FW_CMD_EXEC |
-			    FW_IQ_CMD_PFN(0) | FW_IQ_CMD_VFN(0));
+			    FW_IQ_CMD_PFN(adap->fn) | FW_IQ_CMD_VFN(0));
 	c.alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC | FW_IQ_CMD_IQSTART(1) |
 				 FW_LEN16(c));
 	c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(FW_IQ_TYPE_FL_INT_CAP) |
@@ -2030,7 +2031,7 @@
 		c.fl0addr = cpu_to_be64(fl->addr);
 	}
 
-	ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c);
+	ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c);
 	if (ret)
 		goto err;
 
@@ -2109,7 +2110,7 @@
 	memset(&c, 0, sizeof(c));
 	c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_ETH_CMD) | FW_CMD_REQUEST |
 			    FW_CMD_WRITE | FW_CMD_EXEC |
-			    FW_EQ_ETH_CMD_PFN(0) | FW_EQ_ETH_CMD_VFN(0));
+			    FW_EQ_ETH_CMD_PFN(adap->fn) | FW_EQ_ETH_CMD_VFN(0));
 	c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_ALLOC |
 				 FW_EQ_ETH_CMD_EQSTART | FW_LEN16(c));
 	c.viid_pkd = htonl(FW_EQ_ETH_CMD_VIID(pi->viid));
@@ -2122,7 +2123,7 @@
 				  FW_EQ_ETH_CMD_EQSIZE(nentries));
 	c.eqaddr = cpu_to_be64(txq->q.phys_addr);
 
-	ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c);
+	ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c);
 	if (ret) {
 		kfree(txq->q.sdesc);
 		txq->q.sdesc = NULL;
@@ -2159,7 +2160,8 @@
 
 	c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST |
 			    FW_CMD_WRITE | FW_CMD_EXEC |
-			    FW_EQ_CTRL_CMD_PFN(0) | FW_EQ_CTRL_CMD_VFN(0));
+			    FW_EQ_CTRL_CMD_PFN(adap->fn) |
+			    FW_EQ_CTRL_CMD_VFN(0));
 	c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_ALLOC |
 				 FW_EQ_CTRL_CMD_EQSTART | FW_LEN16(c));
 	c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_CMPLIQID(cmplqid));
@@ -2173,7 +2175,7 @@
 				  FW_EQ_CTRL_CMD_EQSIZE(nentries));
 	c.eqaddr = cpu_to_be64(txq->q.phys_addr);
 
-	ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c);
+	ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c);
 	if (ret) {
 		dma_free_coherent(adap->pdev_dev,
 				  nentries * sizeof(struct tx_desc),
@@ -2209,7 +2211,8 @@
 	memset(&c, 0, sizeof(c));
 	c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST |
 			    FW_CMD_WRITE | FW_CMD_EXEC |
-			    FW_EQ_OFLD_CMD_PFN(0) | FW_EQ_OFLD_CMD_VFN(0));
+			    FW_EQ_OFLD_CMD_PFN(adap->fn) |
+			    FW_EQ_OFLD_CMD_VFN(0));
 	c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC |
 				 FW_EQ_OFLD_CMD_EQSTART | FW_LEN16(c));
 	c.fetchszm_to_iqid = htonl(FW_EQ_OFLD_CMD_HOSTFCMODE(2) |
@@ -2221,7 +2224,7 @@
 				  FW_EQ_OFLD_CMD_EQSIZE(nentries));
 	c.eqaddr = cpu_to_be64(txq->q.phys_addr);
 
-	ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c);
+	ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c);
 	if (ret) {
 		kfree(txq->q.sdesc);
 		txq->q.sdesc = NULL;
@@ -2257,8 +2260,8 @@
 	unsigned int fl_id = fl ? fl->cntxt_id : 0xffff;
 
 	adap->sge.ingr_map[rq->cntxt_id] = NULL;
-	t4_iq_free(adap, 0, 0, 0, FW_IQ_TYPE_FL_INT_CAP, rq->cntxt_id, fl_id,
-		   0xffff);
+	t4_iq_free(adap, adap->fn, adap->fn, 0, FW_IQ_TYPE_FL_INT_CAP,
+		   rq->cntxt_id, fl_id, 0xffff);
 	dma_free_coherent(adap->pdev_dev, (rq->size + 1) * rq->iqe_len,
 			  rq->desc, rq->phys_addr);
 	netif_napi_del(&rq->napi);
@@ -2295,7 +2298,8 @@
 		if (eq->rspq.desc)
 			free_rspq_fl(adap, &eq->rspq, &eq->fl);
 		if (etq->q.desc) {
-			t4_eth_eq_free(adap, 0, 0, 0, etq->q.cntxt_id);
+			t4_eth_eq_free(adap, adap->fn, adap->fn, 0,
+				       etq->q.cntxt_id);
 			free_tx_desc(adap, &etq->q, etq->q.in_use, true);
 			kfree(etq->q.sdesc);
 			free_txq(adap, &etq->q);
@@ -2318,7 +2322,8 @@
 
 		if (q->q.desc) {
 			tasklet_kill(&q->qresume_tsk);
-			t4_ofld_eq_free(adap, 0, 0, 0, q->q.cntxt_id);
+			t4_ofld_eq_free(adap, adap->fn, adap->fn, 0,
+					q->q.cntxt_id);
 			free_tx_desc(adap, &q->q, q->q.in_use, false);
 			kfree(q->q.sdesc);
 			__skb_queue_purge(&q->sendq);
@@ -2332,7 +2337,8 @@
 
 		if (cq->q.desc) {
 			tasklet_kill(&cq->qresume_tsk);
-			t4_ctrl_eq_free(adap, 0, 0, 0, cq->q.cntxt_id);
+			t4_ctrl_eq_free(adap, adap->fn, adap->fn, 0,
+					cq->q.cntxt_id);
 			__skb_queue_purge(&cq->sendq);
 			free_txq(adap, &cq->q);
 		}
@@ -2400,6 +2406,7 @@
  */
 void t4_sge_init(struct adapter *adap)
 {
+	unsigned int i, v;
 	struct sge *s = &adap->sge;
 	unsigned int fl_align_log = ilog2(FL_ALIGN);
 
@@ -2408,8 +2415,10 @@
 			 INGPADBOUNDARY(fl_align_log - 5) | PKTSHIFT(2) |
 			 RXPKTCPLMODE |
 			 (STAT_LEN == 128 ? EGRSTATUSPAGESIZE : 0));
-	t4_set_reg_field(adap, SGE_HOST_PAGE_SIZE, HOSTPAGESIZEPF0_MASK,
-			 HOSTPAGESIZEPF0(PAGE_SHIFT - 10));
+
+	for (i = v = 0; i < 32; i += 4)
+		v |= (PAGE_SHIFT - 10) << i;
+	t4_write_reg(adap, SGE_HOST_PAGE_SIZE, v);
 	t4_write_reg(adap, SGE_FL_BUFFER_SIZE0, PAGE_SIZE);
 #if FL_PG_ORDER > 0
 	t4_write_reg(adap, SGE_FL_BUFFER_SIZE1, PAGE_SIZE << FL_PG_ORDER);
diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c
index da272a9..9e1a4b4 100644
--- a/drivers/net/cxgb4/t4_hw.c
+++ b/drivers/net/cxgb4/t4_hw.c
@@ -221,6 +221,13 @@
 	if ((size & 15) || size > MBOX_LEN)
 		return -EINVAL;
 
+	/*
+	 * If the device is off-line, as in EEH, commands will time out.
+	 * Fail them early so we don't waste time waiting.
+	 */
+	if (adap->pdev->error_state != pci_channel_io_normal)
+		return -EIO;
+
 	v = MBOWNER_GET(t4_read_reg(adap, ctl_reg));
 	for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
 		v = MBOWNER_GET(t4_read_reg(adap, ctl_reg));
@@ -449,12 +456,10 @@
 	SF_RD_STATUS    = 5,          /* read status register */
 	SF_WR_ENABLE    = 6,          /* enable writes */
 	SF_RD_DATA_FAST = 0xb,        /* read flash */
+	SF_RD_ID        = 0x9f,       /* read ID */
 	SF_ERASE_SECTOR = 0xd8,       /* erase sector */
 
-	FW_START_SEC = 8,             /* first flash sector for FW */
-	FW_END_SEC = 15,              /* last flash sector for FW */
-	FW_IMG_START = FW_START_SEC * SF_SEC_SIZE,
-	FW_MAX_SIZE = (FW_END_SEC - FW_START_SEC + 1) * SF_SEC_SIZE,
+	FW_MAX_SIZE = 512 * 1024,
 };
 
 /**
@@ -558,7 +563,7 @@
 {
 	int ret;
 
-	if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3))
+	if (addr + nwords * sizeof(u32) > adapter->params.sf_size || (addr & 3))
 		return -EINVAL;
 
 	addr = swab32(addr) | SF_RD_DATA_FAST;
@@ -596,7 +601,7 @@
 	u32 buf[64];
 	unsigned int i, c, left, val, offset = addr & 0xff;
 
-	if (addr >= SF_SIZE || offset + n > SF_PAGE_SIZE)
+	if (addr >= adapter->params.sf_size || offset + n > SF_PAGE_SIZE)
 		return -EINVAL;
 
 	val = swab32(addr) | SF_PROG_PAGE;
@@ -614,7 +619,7 @@
 		if (ret)
 			goto unlock;
 	}
-	ret = flash_wait_op(adapter, 5, 1);
+	ret = flash_wait_op(adapter, 8, 1);
 	if (ret)
 		goto unlock;
 
@@ -647,9 +652,8 @@
  */
 static int get_fw_version(struct adapter *adapter, u32 *vers)
 {
-	return t4_read_flash(adapter,
-			     FW_IMG_START + offsetof(struct fw_hdr, fw_ver), 1,
-			     vers, 0);
+	return t4_read_flash(adapter, adapter->params.sf_fw_start +
+			     offsetof(struct fw_hdr, fw_ver), 1, vers, 0);
 }
 
 /**
@@ -661,8 +665,8 @@
  */
 static int get_tp_version(struct adapter *adapter, u32 *vers)
 {
-	return t4_read_flash(adapter, FW_IMG_START + offsetof(struct fw_hdr,
-							      tp_microcode_ver),
+	return t4_read_flash(adapter, adapter->params.sf_fw_start +
+			     offsetof(struct fw_hdr, tp_microcode_ver),
 			     1, vers, 0);
 }
 
@@ -684,9 +688,9 @@
 	if (!ret)
 		ret = get_tp_version(adapter, &adapter->params.tp_vers);
 	if (!ret)
-		ret = t4_read_flash(adapter,
-			FW_IMG_START + offsetof(struct fw_hdr, intfver_nic),
-			2, api_vers, 1);
+		ret = t4_read_flash(adapter, adapter->params.sf_fw_start +
+				    offsetof(struct fw_hdr, intfver_nic),
+				    2, api_vers, 1);
 	if (ret)
 		return ret;
 
@@ -726,7 +730,7 @@
 		if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 ||
 		    (ret = sf1_write(adapter, 4, 0, 1,
 				     SF_ERASE_SECTOR | (start << 8))) != 0 ||
-		    (ret = flash_wait_op(adapter, 5, 500)) != 0) {
+		    (ret = flash_wait_op(adapter, 14, 500)) != 0) {
 			dev_err(adapter->pdev_dev,
 				"erase of flash sector %d failed, error %d\n",
 				start, ret);
@@ -754,6 +758,9 @@
 	u8 first_page[SF_PAGE_SIZE];
 	const u32 *p = (const u32 *)fw_data;
 	const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data;
+	unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
+	unsigned int fw_img_start = adap->params.sf_fw_start;
+	unsigned int fw_start_sec = fw_img_start / sf_sec_size;
 
 	if (!size) {
 		dev_err(adap->pdev_dev, "FW image has no data\n");
@@ -784,8 +791,8 @@
 		return -EINVAL;
 	}
 
-	i = DIV_ROUND_UP(size, SF_SEC_SIZE);        /* # of sectors spanned */
-	ret = t4_flash_erase_sectors(adap, FW_START_SEC, FW_START_SEC + i - 1);
+	i = DIV_ROUND_UP(size, sf_sec_size);        /* # of sectors spanned */
+	ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1);
 	if (ret)
 		goto out;
 
@@ -796,11 +803,11 @@
 	 */
 	memcpy(first_page, fw_data, SF_PAGE_SIZE);
 	((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff);
-	ret = t4_write_flash(adap, FW_IMG_START, SF_PAGE_SIZE, first_page);
+	ret = t4_write_flash(adap, fw_img_start, SF_PAGE_SIZE, first_page);
 	if (ret)
 		goto out;
 
-	addr = FW_IMG_START;
+	addr = fw_img_start;
 	for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
 		addr += SF_PAGE_SIZE;
 		fw_data += SF_PAGE_SIZE;
@@ -810,7 +817,7 @@
 	}
 
 	ret = t4_write_flash(adap,
-			     FW_IMG_START + offsetof(struct fw_hdr, fw_ver),
+			     fw_img_start + offsetof(struct fw_hdr, fw_ver),
 			     sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver);
 out:
 	if (ret)
@@ -1128,6 +1135,7 @@
 static void ulprx_intr_handler(struct adapter *adapter)
 {
 	static struct intr_info ulprx_intr_info[] = {
+		{ 0x1800000, "ULPRX context error", -1, 1 },
 		{ 0x7fffff, "ULPRX parity error", -1, 1 },
 		{ 0 }
 	};
@@ -1436,7 +1444,7 @@
 		t4_fatal_err(adap);
 }
 
-#define PF_INTR_MASK (PFSW | PFCIM)
+#define PF_INTR_MASK (PFSW)
 #define GLBL_INTR_MASK (CIM | MPS | PL | PCIE | MC | EDC0 | \
 		EDC1 | LE | TP | MA | PM_TX | PM_RX | ULP_RX | \
 		CPL_SWITCH | SGE | ULP_TX)
@@ -2510,7 +2518,7 @@
 	c.retval_len16 = htonl(FW_LEN16(c));
 	c.niqflint_niq = htonl(FW_PFVF_CMD_NIQFLINT(rxqi) |
 			       FW_PFVF_CMD_NIQ(rxq));
-	c.cmask_to_neq = htonl(FW_PFVF_CMD_CMASK(cmask) |
+	c.type_to_neq = htonl(FW_PFVF_CMD_CMASK(cmask) |
 			       FW_PFVF_CMD_PMASK(pmask) |
 			       FW_PFVF_CMD_NEQ(txq));
 	c.tc_to_nexactf = htonl(FW_PFVF_CMD_TC(tc) | FW_PFVF_CMD_NVI(vi) |
@@ -2572,7 +2580,7 @@
 	}
 	if (rss_size)
 		*rss_size = FW_VI_CMD_RSSSIZE_GET(ntohs(c.rsssize_pkd));
-	return ntohs(c.viid_pkd);
+	return FW_VI_CMD_VIID_GET(ntohs(c.type_viid));
 }
 
 /**
@@ -2595,7 +2603,7 @@
 			    FW_CMD_EXEC | FW_VI_CMD_PFN(pf) |
 			    FW_VI_CMD_VFN(vf));
 	c.alloc_to_len16 = htonl(FW_VI_CMD_FREE | FW_LEN16(c));
-	c.viid_pkd = htons(FW_VI_CMD_VIID(viid));
+	c.type_viid = htons(FW_VI_CMD_VIID(viid));
 	return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
 }
 
@@ -3045,7 +3053,7 @@
 	}
 }
 
-static int __devinit wait_dev_ready(struct adapter *adap)
+int t4_wait_dev_ready(struct adapter *adap)
 {
 	if (t4_read_reg(adap, PL_WHOAMI) != 0xffffffff)
 		return 0;
@@ -3053,6 +3061,33 @@
 	return t4_read_reg(adap, PL_WHOAMI) != 0xffffffff ? 0 : -EIO;
 }
 
+static int __devinit get_flash_params(struct adapter *adap)
+{
+	int ret;
+	u32 info;
+
+	ret = sf1_write(adap, 1, 1, 0, SF_RD_ID);
+	if (!ret)
+		ret = sf1_read(adap, 3, 0, 1, &info);
+	t4_write_reg(adap, SF_OP, 0);                    /* unlock SF */
+	if (ret)
+		return ret;
+
+	if ((info & 0xff) != 0x20)             /* not a Numonix flash */
+		return -EINVAL;
+	info >>= 16;                           /* log2 of size */
+	if (info >= 0x14 && info < 0x18)
+		adap->params.sf_nsec = 1 << (info - 16);
+	else if (info == 0x18)
+		adap->params.sf_nsec = 64;
+	else
+		return -EINVAL;
+	adap->params.sf_size = 1 << info;
+	adap->params.sf_fw_start =
+		t4_read_reg(adap, CIM_BOOT_CFG) & BOOTADDR_MASK;
+	return 0;
+}
+
 /**
  *	t4_prep_adapter - prepare SW and HW for operation
  *	@adapter: the adapter
@@ -3066,13 +3101,19 @@
 {
 	int ret;
 
-	ret = wait_dev_ready(adapter);
+	ret = t4_wait_dev_ready(adapter);
 	if (ret < 0)
 		return ret;
 
 	get_pci_mode(adapter, &adapter->params.pci);
 	adapter->params.rev = t4_read_reg(adapter, PL_REV);
 
+	ret = get_flash_params(adapter);
+	if (ret < 0) {
+		dev_err(adapter->pdev_dev, "error %d identifying flash\n", ret);
+		return ret;
+	}
+
 	ret = get_vpd_params(adapter, &adapter->params.vpd);
 	if (ret < 0)
 		return ret;
@@ -3092,8 +3133,10 @@
 	u8 addr[6];
 	int ret, i, j = 0;
 	struct fw_port_cmd c;
+	struct fw_rss_vi_config_cmd rvc;
 
 	memset(&c, 0, sizeof(c));
+	memset(&rvc, 0, sizeof(rvc));
 
 	for_each_port(adap, i) {
 		unsigned int rss_size;
@@ -3122,12 +3165,22 @@
 		p->rss_size = rss_size;
 		memcpy(adap->port[i]->dev_addr, addr, ETH_ALEN);
 		memcpy(adap->port[i]->perm_addr, addr, ETH_ALEN);
+		adap->port[i]->dev_id = j;
 
 		ret = ntohl(c.u.info.lstatus_to_modtype);
 		p->mdio_addr = (ret & FW_PORT_CMD_MDIOCAP) ?
 			FW_PORT_CMD_MDIOADDR_GET(ret) : -1;
 		p->port_type = FW_PORT_CMD_PTYPE_GET(ret);
-		p->mod_type = FW_PORT_CMD_MODTYPE_GET(ret);
+		p->mod_type = FW_PORT_MOD_TYPE_NA;
+
+		rvc.op_to_viid = htonl(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
+				       FW_CMD_REQUEST | FW_CMD_READ |
+				       FW_RSS_VI_CONFIG_CMD_VIID(p->viid));
+		rvc.retval_len16 = htonl(FW_LEN16(rvc));
+		ret = t4_wr_mbox(adap, mbox, &rvc, sizeof(rvc), &rvc);
+		if (ret)
+			return ret;
+		p->rss_mode = ntohl(rvc.u.basicvirtual.defaultq_to_udpen);
 
 		init_link_config(&p->link_cfg, ntohs(c.u.info.pcap));
 		j++;
diff --git a/drivers/net/cxgb4/t4_hw.h b/drivers/net/cxgb4/t4_hw.h
index 0256232..10a0555 100644
--- a/drivers/net/cxgb4/t4_hw.h
+++ b/drivers/net/cxgb4/t4_hw.h
@@ -57,8 +57,6 @@
 
 enum {
 	SF_PAGE_SIZE = 256,           /* serial flash page size */
-	SF_SEC_SIZE = 64 * 1024,      /* serial flash sector size */
-	SF_SIZE = SF_SEC_SIZE * 16,   /* serial flash size */
 };
 
 enum { RSP_TYPE_FLBUF, RSP_TYPE_CPL, RSP_TYPE_INTR }; /* response entry types */
@@ -69,6 +67,45 @@
 	SGE_MAX_WR_LEN = 512,     /* max WR size in bytes */
 	SGE_NTIMERS = 6,          /* # of interrupt holdoff timer values */
 	SGE_NCOUNTERS = 4,        /* # of interrupt packet counter values */
+
+	SGE_TIMER_RSTRT_CNTR = 6, /* restart RX packet threshold counter */
+	SGE_TIMER_UPD_CIDX = 7,   /* update cidx only */
+
+	SGE_EQ_IDXSIZE = 64,      /* egress queue pidx/cidx unit size */
+
+	SGE_INTRDST_PCI = 0,      /* interrupt destination is PCI-E */
+	SGE_INTRDST_IQ = 1,       /*   destination is an ingress queue */
+
+	SGE_UPDATEDEL_NONE = 0,   /* ingress queue pidx update delivery */
+	SGE_UPDATEDEL_INTR = 1,   /*   interrupt */
+	SGE_UPDATEDEL_STPG = 2,   /*   status page */
+	SGE_UPDATEDEL_BOTH = 3,   /*   interrupt and status page */
+
+	SGE_HOSTFCMODE_NONE = 0,  /* egress queue cidx updates */
+	SGE_HOSTFCMODE_IQ = 1,    /*   sent to ingress queue */
+	SGE_HOSTFCMODE_STPG = 2,  /*   sent to status page */
+	SGE_HOSTFCMODE_BOTH = 3,  /*   ingress queue and status page */
+
+	SGE_FETCHBURSTMIN_16B = 0,/* egress queue descriptor fetch minimum */
+	SGE_FETCHBURSTMIN_32B = 1,
+	SGE_FETCHBURSTMIN_64B = 2,
+	SGE_FETCHBURSTMIN_128B = 3,
+
+	SGE_FETCHBURSTMAX_64B = 0,/* egress queue descriptor fetch maximum */
+	SGE_FETCHBURSTMAX_128B = 1,
+	SGE_FETCHBURSTMAX_256B = 2,
+	SGE_FETCHBURSTMAX_512B = 3,
+
+	SGE_CIDXFLUSHTHRESH_1 = 0,/* egress queue cidx flush threshold */
+	SGE_CIDXFLUSHTHRESH_2 = 1,
+	SGE_CIDXFLUSHTHRESH_4 = 2,
+	SGE_CIDXFLUSHTHRESH_8 = 3,
+	SGE_CIDXFLUSHTHRESH_16 = 4,
+	SGE_CIDXFLUSHTHRESH_32 = 5,
+	SGE_CIDXFLUSHTHRESH_64 = 6,
+	SGE_CIDXFLUSHTHRESH_128 = 7,
+
+	SGE_INGPADBOUNDARY_SHIFT = 5,/* ingress queue pad boundary */
 };
 
 struct sge_qstat {                /* data written to SGE queue status entries */
@@ -90,11 +127,13 @@
 };
 
 #define RSPD_NEWBUF 0x80000000U
-#define RSPD_LEN    0x7fffffffU
+#define RSPD_LEN(x) (((x) >> 0) & 0x7fffffffU)
+#define RSPD_QID(x) RSPD_LEN(x)
 
 #define RSPD_GEN(x)  ((x) >> 7)
 #define RSPD_TYPE(x) (((x) >> 4) & 3)
 
 #define QINTR_CNT_EN       0x1
 #define QINTR_TIMER_IDX(x) ((x) << 1)
+#define QINTR_TIMER_IDX_GET(x) (((x) >> 1) & 0x7)
 #endif /* __T4_HW_H */
diff --git a/drivers/net/cxgb4/t4_msg.h b/drivers/net/cxgb4/t4_msg.h
index 7a981b8..a550d0c 100644
--- a/drivers/net/cxgb4/t4_msg.h
+++ b/drivers/net/cxgb4/t4_msg.h
@@ -443,8 +443,7 @@
 
 #define cpl_tx_pkt_xt cpl_tx_pkt
 
-struct cpl_tx_pkt_lso {
-	WR_HDR;
+struct cpl_tx_pkt_lso_core {
 	__be32 lso_ctrl;
 #define LSO_TCPHDR_LEN(x) ((x) << 0)
 #define LSO_IPHDR_LEN(x)  ((x) << 4)
@@ -460,6 +459,12 @@
 	/* encapsulated CPL (TX_PKT, TX_PKT_XT or TX_DATA) follows here */
 };
 
+struct cpl_tx_pkt_lso {
+	WR_HDR;
+	struct cpl_tx_pkt_lso_core c;
+	/* encapsulated CPL (TX_PKT, TX_PKT_XT or TX_DATA) follows here */
+};
+
 struct cpl_iscsi_hdr {
 	union opcode_tid ot;
 	__be16 pdu_len_ddp;
@@ -524,6 +529,8 @@
 	__be32 l2info;
 #define RXF_UDP (1 << 22)
 #define RXF_TCP (1 << 23)
+#define RXF_IP  (1 << 24)
+#define RXF_IP6 (1 << 25)
 	__be16 hdr_len;
 	__be16 err_vec;
 };
@@ -623,6 +630,11 @@
 	__be64 data[4];
 };
 
+/* cpl_fw6_msg.type values */
+enum {
+	FW6_TYPE_CMD_RPL = 0,
+};
+
 enum {
 	ULP_TX_MEM_READ = 2,
 	ULP_TX_MEM_WRITE = 3,
diff --git a/drivers/net/cxgb4/t4_regs.h b/drivers/net/cxgb4/t4_regs.h
index 5ed5648..0adc5bc 100644
--- a/drivers/net/cxgb4/t4_regs.h
+++ b/drivers/net/cxgb4/t4_regs.h
@@ -93,12 +93,15 @@
 #define  PKTSHIFT_MASK          0x00001c00U
 #define  PKTSHIFT_SHIFT         10
 #define  PKTSHIFT(x)            ((x) << PKTSHIFT_SHIFT)
+#define  PKTSHIFT_GET(x)	(((x) & PKTSHIFT_MASK) >> PKTSHIFT_SHIFT)
 #define  INGPCIEBOUNDARY_MASK   0x00000380U
 #define  INGPCIEBOUNDARY_SHIFT  7
 #define  INGPCIEBOUNDARY(x)     ((x) << INGPCIEBOUNDARY_SHIFT)
 #define  INGPADBOUNDARY_MASK    0x00000070U
 #define  INGPADBOUNDARY_SHIFT   4
 #define  INGPADBOUNDARY(x)      ((x) << INGPADBOUNDARY_SHIFT)
+#define  INGPADBOUNDARY_GET(x)	(((x) & INGPADBOUNDARY_MASK) \
+				 >> INGPADBOUNDARY_SHIFT)
 #define  EGRPCIEBOUNDARY_MASK   0x0000000eU
 #define  EGRPCIEBOUNDARY_SHIFT  1
 #define  EGRPCIEBOUNDARY(x)     ((x) << EGRPCIEBOUNDARY_SHIFT)
@@ -229,6 +232,7 @@
 #define  WINDOW_MASK     0x000000ffU
 #define  WINDOW_SHIFT    0
 #define  WINDOW(x)       ((x) << WINDOW_SHIFT)
+#define PCIE_MEM_ACCESS_OFFSET 0x306c
 
 #define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS 0x5908
 #define  RNPP 0x80000000U
@@ -326,6 +330,9 @@
 
 #define EDC_1_BASE_ADDR 0x7980
 
+#define CIM_BOOT_CFG 0x7b00
+#define  BOOTADDR_MASK 0xffffff00U
+
 #define CIM_PF_MAILBOX_DATA 0x240
 #define CIM_PF_MAILBOX_CTRL 0x280
 #define  MBMSGVALID     0x00000008U
diff --git a/drivers/net/cxgb4/t4fw_api.h b/drivers/net/cxgb4/t4fw_api.h
index 63991d6..0969f2f 100644
--- a/drivers/net/cxgb4/t4fw_api.h
+++ b/drivers/net/cxgb4/t4fw_api.h
@@ -71,6 +71,7 @@
 #define FW_WR_ATOMIC(x)	 ((x) << 23)
 #define FW_WR_FLUSH(x)   ((x) << 22)
 #define FW_WR_COMPL(x)   ((x) << 21)
+#define FW_WR_IMMDLEN_MASK 0xff
 #define FW_WR_IMMDLEN(x) ((x) << 0)
 
 #define FW_WR_EQUIQ	(1U << 31)
@@ -447,7 +448,9 @@
 	FW_PARAMS_PARAM_DEV_INTVER_RI	= 0x07,
 	FW_PARAMS_PARAM_DEV_INTVER_ISCSIPDU = 0x08,
 	FW_PARAMS_PARAM_DEV_INTVER_ISCSI = 0x09,
-	FW_PARAMS_PARAM_DEV_INTVER_FCOE = 0x0A
+	FW_PARAMS_PARAM_DEV_INTVER_FCOE = 0x0A,
+	FW_PARAMS_PARAM_DEV_FWREV = 0x0B,
+	FW_PARAMS_PARAM_DEV_TPREV = 0x0C,
 };
 
 /*
@@ -475,7 +478,15 @@
 	FW_PARAMS_PARAM_PFVF_PBL_END	= 0x12,
 	FW_PARAMS_PARAM_PFVF_L2T_START = 0x13,
 	FW_PARAMS_PARAM_PFVF_L2T_END = 0x14,
+	FW_PARAMS_PARAM_PFVF_SQRQ_START = 0x15,
+	FW_PARAMS_PARAM_PFVF_SQRQ_END	= 0x16,
+	FW_PARAMS_PARAM_PFVF_CQ_START	= 0x17,
+	FW_PARAMS_PARAM_PFVF_CQ_END	= 0x18,
 	FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH = 0x20,
+	FW_PARAMS_PARAM_PFVF_VIID       = 0x24,
+	FW_PARAMS_PARAM_PFVF_CPMASK     = 0x25,
+	FW_PARAMS_PARAM_PFVF_OCQ_START  = 0x26,
+	FW_PARAMS_PARAM_PFVF_OCQ_END    = 0x27,
 };
 
 /*
@@ -512,7 +523,7 @@
 	__be32 op_to_vfn;
 	__be32 retval_len16;
 	__be32 niqflint_niq;
-	__be32 cmask_to_neq;
+	__be32 type_to_neq;
 	__be32 tc_to_nexactf;
 	__be32 r_caps_to_nethctrl;
 	__be16 nricq;
@@ -529,11 +540,16 @@
 #define FW_PFVF_CMD_NIQ(x) ((x) << 0)
 #define FW_PFVF_CMD_NIQ_GET(x) (((x) >> 0) & 0xfffff)
 
+#define FW_PFVF_CMD_TYPE (1 << 31)
+#define FW_PFVF_CMD_TYPE_GET(x) (((x) >> 31) & 0x1)
+
 #define FW_PFVF_CMD_CMASK(x) ((x) << 24)
-#define FW_PFVF_CMD_CMASK_GET(x) (((x) >> 24) & 0xf)
+#define FW_PFVF_CMD_CMASK_MASK 0xf
+#define FW_PFVF_CMD_CMASK_GET(x) (((x) >> 24) & FW_PFVF_CMD_CMASK_MASK)
 
 #define FW_PFVF_CMD_PMASK(x) ((x) << 20)
-#define FW_PFVF_CMD_PMASK_GET(x) (((x) >> 20) & 0xf)
+#define FW_PFVF_CMD_PMASK_MASK 0xf
+#define FW_PFVF_CMD_PMASK_GET(x) (((x) >> 20) & FW_PFVF_CMD_PMASK_MASK)
 
 #define FW_PFVF_CMD_NEQ(x) ((x) << 0)
 #define FW_PFVF_CMD_NEQ_GET(x) (((x) >> 0) & 0xfffff)
@@ -686,6 +702,7 @@
 #define FW_EQ_ETH_CMD_EQID(x) ((x) << 0)
 #define FW_EQ_ETH_CMD_EQID_GET(x) (((x) >> 0) & 0xfffff)
 #define FW_EQ_ETH_CMD_PHYSEQID(x) ((x) << 0)
+#define FW_EQ_ETH_CMD_PHYSEQID_GET(x) (((x) >> 0) & 0xfffff)
 
 #define FW_EQ_ETH_CMD_FETCHSZM(x) ((x) << 26)
 #define FW_EQ_ETH_CMD_STATUSPGNS(x) ((x) << 25)
@@ -804,16 +821,16 @@
 struct fw_vi_cmd {
 	__be32 op_to_vfn;
 	__be32 alloc_to_len16;
-	__be16 viid_pkd;
+	__be16 type_viid;
 	u8 mac[6];
 	u8 portid_pkd;
 	u8 nmac;
 	u8 nmac0[6];
 	__be16 rsssize_pkd;
 	u8 nmac1[6];
-	__be16 r7;
+	__be16 idsiiq_pkd;
 	u8 nmac2[6];
-	__be16 r8;
+	__be16 idseiq_pkd;
 	u8 nmac3[6];
 	__be64 r9;
 	__be64 r10;
@@ -824,13 +841,16 @@
 #define FW_VI_CMD_ALLOC (1U << 31)
 #define FW_VI_CMD_FREE (1U << 30)
 #define FW_VI_CMD_VIID(x) ((x) << 0)
+#define FW_VI_CMD_VIID_GET(x) ((x) & 0xfff)
 #define FW_VI_CMD_PORTID(x) ((x) << 4)
+#define FW_VI_CMD_PORTID_GET(x) (((x) >> 4) & 0xf)
 #define FW_VI_CMD_RSSSIZE_GET(x) (((x) >> 0) & 0x7ff)
 
 /* Special VI_MAC command index ids */
 #define FW_VI_MAC_ADD_MAC		0x3FF
 #define FW_VI_MAC_ADD_PERSIST_MAC	0x3FE
 #define FW_VI_MAC_MAC_BASED_FREE	0x3FD
+#define FW_CLS_TCAM_NUM_ENTRIES		336
 
 enum fw_vi_mac_smac {
 	FW_VI_MAC_MPS_TCAM_ENTRY,
@@ -881,6 +901,7 @@
 };
 
 #define FW_VI_RXMODE_CMD_VIID(x) ((x) << 0)
+#define FW_VI_RXMODE_CMD_MTU_MASK 0xffff
 #define FW_VI_RXMODE_CMD_MTU(x) ((x) << 16)
 #define FW_VI_RXMODE_CMD_PROMISCEN_MASK 0x3
 #define FW_VI_RXMODE_CMD_PROMISCEN(x) ((x) << 14)
@@ -1136,6 +1157,11 @@
 			__be32 lstatus_to_modtype;
 			__be16 pcap;
 			__be16 acap;
+			__be16 mtu;
+			__u8   cbllen;
+			__u8   r9;
+			__be32 r10;
+			__be64 r11;
 		} info;
 		struct fw_port_ppp {
 			__be32 pppen_to_ncsich;
@@ -1161,6 +1187,7 @@
 #define FW_PORT_CMD_PORTID_GET(x) (((x) >> 0) & 0xf)
 
 #define FW_PORT_CMD_ACTION(x) ((x) << 16)
+#define FW_PORT_CMD_ACTION_GET(x) (((x) >> 16) & 0xffff)
 
 #define FW_PORT_CMD_CTLBF(x) ((x) << 10)
 #define FW_PORT_CMD_OVLAN3(x) ((x) << 7)
@@ -1196,14 +1223,17 @@
 #define FW_PORT_CMD_NCSICH(x) ((x) << 4)
 
 enum fw_port_type {
-	FW_PORT_TYPE_FIBER,
-	FW_PORT_TYPE_KX4,
+	FW_PORT_TYPE_FIBER_XFI,
+	FW_PORT_TYPE_FIBER_XAUI,
 	FW_PORT_TYPE_BT_SGMII,
-	FW_PORT_TYPE_KX,
+	FW_PORT_TYPE_BT_XFI,
 	FW_PORT_TYPE_BT_XAUI,
-	FW_PORT_TYPE_KR,
+	FW_PORT_TYPE_KX4,
 	FW_PORT_TYPE_CX4,
-	FW_PORT_TYPE_TWINAX,
+	FW_PORT_TYPE_KX,
+	FW_PORT_TYPE_KR,
+	FW_PORT_TYPE_SFP,
+	FW_PORT_TYPE_BP_AP,
 
 	FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_MASK
 };
@@ -1213,6 +1243,9 @@
 	FW_PORT_MOD_TYPE_LR,
 	FW_PORT_MOD_TYPE_SR,
 	FW_PORT_MOD_TYPE_ER,
+	FW_PORT_MOD_TYPE_TWINAX_PASSIVE,
+	FW_PORT_MOD_TYPE_TWINAX_ACTIVE,
+	FW_PORT_MOD_TYPE_LRM,
 
 	FW_PORT_MOD_TYPE_NONE = FW_PORT_CMD_MODTYPE_MASK
 };
@@ -1469,6 +1502,7 @@
 };
 
 #define FW_RSS_GLB_CONFIG_CMD_MODE(x)	((x) << 28)
+#define FW_RSS_GLB_CONFIG_CMD_MODE_GET(x) (((x) >> 28) & 0xf)
 
 #define FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL	0
 #define FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL	1
@@ -1485,13 +1519,14 @@
 		} manual;
 		struct fw_rss_vi_config_basicvirtual {
 			__be32 r6;
-			__be32 defaultq_to_ip4udpen;
+			__be32 defaultq_to_udpen;
 #define FW_RSS_VI_CONFIG_CMD_DEFAULTQ(x)  ((x) << 16)
+#define FW_RSS_VI_CONFIG_CMD_DEFAULTQ_GET(x) (((x) >> 16) & 0x3ff)
 #define FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN (1U << 4)
 #define FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN  (1U << 3)
 #define FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN (1U << 2)
 #define FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN  (1U << 1)
-#define FW_RSS_VI_CONFIG_CMD_IP4UDPEN     (1U << 0)
+#define FW_RSS_VI_CONFIG_CMD_UDPEN        (1U << 0)
 			__be64 r9;
 			__be64 r10;
 		} basicvirtual;
diff --git a/drivers/net/cxgb4vf/Makefile b/drivers/net/cxgb4vf/Makefile
new file mode 100644
index 0000000..d72ee26
--- /dev/null
+++ b/drivers/net/cxgb4vf/Makefile
@@ -0,0 +1,7 @@
+#
+# Chelsio T4 SR-IOV Virtual Function Driver
+#
+
+obj-$(CONFIG_CHELSIO_T4VF) += cxgb4vf.o
+
+cxgb4vf-objs := cxgb4vf_main.o t4vf_hw.o sge.o
diff --git a/drivers/net/cxgb4vf/adapter.h b/drivers/net/cxgb4vf/adapter.h
new file mode 100644
index 0000000..8ea0196
--- /dev/null
+++ b/drivers/net/cxgb4vf/adapter.h
@@ -0,0 +1,540 @@
+/*
+ * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet
+ * driver for Linux.
+ *
+ * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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.
+ */
+
+/*
+ * This file should not be included directly.  Include t4vf_common.h instead.
+ */
+
+#ifndef __CXGB4VF_ADAPTER_H__
+#define __CXGB4VF_ADAPTER_H__
+
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+
+#include "../cxgb4/t4_hw.h"
+
+/*
+ * Constants of the implementation.
+ */
+enum {
+	MAX_NPORTS	= 1,		/* max # of "ports" */
+	MAX_PORT_QSETS	= 8,		/* max # of Queue Sets / "port" */
+	MAX_ETH_QSETS	= MAX_NPORTS*MAX_PORT_QSETS,
+
+	/*
+	 * MSI-X interrupt index usage.
+	 */
+	MSIX_FW		= 0,		/* MSI-X index for firmware Q */
+	MSIX_NIQFLINT	= 1,		/* MSI-X index base for Ingress Qs */
+	MSIX_EXTRAS	= 1,
+	MSIX_ENTRIES	= MAX_ETH_QSETS + MSIX_EXTRAS,
+
+	/*
+	 * The maximum number of Ingress and Egress Queues is determined by
+	 * the maximum number of "Queue Sets" which we support plus any
+	 * ancillary queues.  Each "Queue Set" requires one Ingress Queue
+	 * for RX Packet Ingress Event notifications and two Egress Queues for
+	 * a Free List and an Ethernet TX list.
+	 */
+	INGQ_EXTRAS	= 2,		/* firmware event queue and */
+					/*   forwarded interrupts */
+	MAX_INGQ	= MAX_ETH_QSETS+INGQ_EXTRAS,
+	MAX_EGRQ	= MAX_ETH_QSETS*2,
+};
+
+/*
+ * Forward structure definition references.
+ */
+struct adapter;
+struct sge_eth_rxq;
+struct sge_rspq;
+
+/*
+ * Per-"port" information.  This is really per-Virtual Interface information
+ * but the use of the "port" nomanclature makes it easier to go back and forth
+ * between the PF and VF drivers ...
+ */
+struct port_info {
+	struct adapter *adapter;	/* our adapter */
+	struct vlan_group *vlan_grp;	/* out VLAN group */
+	u16 viid;			/* virtual interface ID */
+	s16 xact_addr_filt;		/* index of our MAC address filter */
+	u16 rss_size;			/* size of VI's RSS table slice */
+	u8 pidx;			/* index into adapter port[] */
+	u8 port_id;			/* physical port ID */
+	u8 rx_offload;			/* CSO, etc. */
+	u8 nqsets;			/* # of "Queue Sets" */
+	u8 first_qset;			/* index of first "Queue Set" */
+	struct link_config link_cfg;	/* physical port configuration */
+};
+
+/* port_info.rx_offload flags */
+enum {
+	RX_CSO = 1 << 0,
+};
+
+/*
+ * Scatter Gather Engine resources for the "adapter".  Our ingress and egress
+ * queues are organized into "Queue Sets" with one ingress and one egress
+ * queue per Queue Set.  These Queue Sets are aportionable between the "ports"
+ * (Virtual Interfaces).  One extra ingress queue is used to receive
+ * asynchronous messages from the firmware.  Note that the "Queue IDs" that we
+ * use here are really "Relative Queue IDs" which are returned as part of the
+ * firmware command to allocate queues.  These queue IDs are relative to the
+ * absolute Queue ID base of the section of the Queue ID space allocated to
+ * the PF/VF.
+ */
+
+/*
+ * SGE free-list queue state.
+ */
+struct rx_sw_desc;
+struct sge_fl {
+	unsigned int avail;		/* # of available RX buffers */
+	unsigned int pend_cred;		/* new buffers since last FL DB ring */
+	unsigned int cidx;		/* consumer index */
+	unsigned int pidx;		/* producer index */
+	unsigned long alloc_failed;	/* # of buffer allocation failures */
+	unsigned long large_alloc_failed;
+	unsigned long starving;		/* # of times FL was found starving */
+
+	/*
+	 * Write-once/infrequently fields.
+	 * -------------------------------
+	 */
+
+	unsigned int cntxt_id;		/* SGE relative QID for the free list */
+	unsigned int abs_id;		/* SGE absolute QID for the free list */
+	unsigned int size;		/* capacity of free list */
+	struct rx_sw_desc *sdesc;	/* address of SW RX descriptor ring */
+	__be64 *desc;			/* address of HW RX descriptor ring */
+	dma_addr_t addr;		/* PCI bus address of hardware ring */
+};
+
+/*
+ * An ingress packet gather list.
+ */
+struct pkt_gl {
+	skb_frag_t frags[MAX_SKB_FRAGS];
+	void *va;			/* virtual address of first byte */
+	unsigned int nfrags;		/* # of fragments */
+	unsigned int tot_len;		/* total length of fragments */
+};
+
+typedef int (*rspq_handler_t)(struct sge_rspq *, const __be64 *,
+			      const struct pkt_gl *);
+
+/*
+ * State for an SGE Response Queue.
+ */
+struct sge_rspq {
+	struct napi_struct napi;	/* NAPI scheduling control */
+	const __be64 *cur_desc;		/* current descriptor in queue */
+	unsigned int cidx;		/* consumer index */
+	u8 gen;				/* current generation bit */
+	u8 next_intr_params;		/* holdoff params for next interrupt */
+	int offset;			/* offset into current FL buffer */
+
+	unsigned int unhandled_irqs;	/* bogus interrupts */
+
+	/*
+	 * Write-once/infrequently fields.
+	 * -------------------------------
+	 */
+
+	u8 intr_params;			/* interrupt holdoff parameters */
+	u8 pktcnt_idx;			/* interrupt packet threshold */
+	u8 idx;				/* queue index within its group */
+	u16 cntxt_id;			/* SGE rel QID for the response Q */
+	u16 abs_id;			/* SGE abs QID for the response Q */
+	__be64 *desc;			/* address of hardware response ring */
+	dma_addr_t phys_addr;		/* PCI bus address of ring */
+	unsigned int iqe_len;		/* entry size */
+	unsigned int size;		/* capcity of response Q */
+	struct adapter *adapter;	/* our adapter */
+	struct net_device *netdev;	/* associated net device */
+	rspq_handler_t handler;		/* the handler for this response Q */
+};
+
+/*
+ * Ethernet queue statistics
+ */
+struct sge_eth_stats {
+	unsigned long pkts;		/* # of ethernet packets */
+	unsigned long lro_pkts;		/* # of LRO super packets */
+	unsigned long lro_merged;	/* # of wire packets merged by LRO */
+	unsigned long rx_cso;		/* # of Rx checksum offloads */
+	unsigned long vlan_ex;		/* # of Rx VLAN extractions */
+	unsigned long rx_drops;		/* # of packets dropped due to no mem */
+};
+
+/*
+ * State for an Ethernet Receive Queue.
+ */
+struct sge_eth_rxq {
+	struct sge_rspq rspq;		/* Response Queue */
+	struct sge_fl fl;		/* Free List */
+	struct sge_eth_stats stats;	/* receive statistics */
+};
+
+/*
+ * SGE Transmit Queue state.  This contains all of the resources associated
+ * with the hardware status of a TX Queue which is a circular ring of hardware
+ * TX Descriptors.  For convenience, it also contains a pointer to a parallel
+ * "Software Descriptor" array but we don't know anything about it here other
+ * than its type name.
+ */
+struct tx_desc {
+	/*
+	 * Egress Queues are measured in units of SGE_EQ_IDXSIZE by the
+	 * hardware: Sizes, Producer and Consumer indices, etc.
+	 */
+	__be64 flit[SGE_EQ_IDXSIZE/sizeof(__be64)];
+};
+struct tx_sw_desc;
+struct sge_txq {
+	unsigned int in_use;		/* # of in-use TX descriptors */
+	unsigned int size;		/* # of descriptors */
+	unsigned int cidx;		/* SW consumer index */
+	unsigned int pidx;		/* producer index */
+	unsigned long stops;		/* # of times queue has been stopped */
+	unsigned long restarts;		/* # of queue restarts */
+
+	/*
+	 * Write-once/infrequently fields.
+	 * -------------------------------
+	 */
+
+	unsigned int cntxt_id;		/* SGE relative QID for the TX Q */
+	unsigned int abs_id;		/* SGE absolute QID for the TX Q */
+	struct tx_desc *desc;		/* address of HW TX descriptor ring */
+	struct tx_sw_desc *sdesc;	/* address of SW TX descriptor ring */
+	struct sge_qstat *stat;		/* queue status entry */
+	dma_addr_t phys_addr;		/* PCI bus address of hardware ring */
+};
+
+/*
+ * State for an Ethernet Transmit Queue.
+ */
+struct sge_eth_txq {
+	struct sge_txq q;		/* SGE TX Queue */
+	struct netdev_queue *txq;	/* associated netdev TX queue */
+	unsigned long tso;		/* # of TSO requests */
+	unsigned long tx_cso;		/* # of TX checksum offloads */
+	unsigned long vlan_ins;		/* # of TX VLAN insertions */
+	unsigned long mapping_err;	/* # of I/O MMU packet mapping errors */
+};
+
+/*
+ * The complete set of Scatter/Gather Engine resources.
+ */
+struct sge {
+	/*
+	 * Our "Queue Sets" ...
+	 */
+	struct sge_eth_txq ethtxq[MAX_ETH_QSETS];
+	struct sge_eth_rxq ethrxq[MAX_ETH_QSETS];
+
+	/*
+	 * Extra ingress queues for asynchronous firmware events and
+	 * forwarded interrupts (when in MSI mode).
+	 */
+	struct sge_rspq fw_evtq ____cacheline_aligned_in_smp;
+
+	struct sge_rspq intrq ____cacheline_aligned_in_smp;
+	spinlock_t intrq_lock;
+
+	/*
+	 * State for managing "starving Free Lists" -- Free Lists which have
+	 * fallen below a certain threshold of buffers available to the
+	 * hardware and attempts to refill them up to that threshold have
+	 * failed.  We have a regular "slow tick" timer process which will
+	 * make periodic attempts to refill these starving Free Lists ...
+	 */
+	DECLARE_BITMAP(starving_fl, MAX_EGRQ);
+	struct timer_list rx_timer;
+
+	/*
+	 * State for cleaning up completed TX descriptors.
+	 */
+	struct timer_list tx_timer;
+
+	/*
+	 * Write-once/infrequently fields.
+	 * -------------------------------
+	 */
+
+	u16 max_ethqsets;		/* # of available Ethernet queue sets */
+	u16 ethqsets;			/* # of active Ethernet queue sets */
+	u16 ethtxq_rover;		/* Tx queue to clean up next */
+	u16 timer_val[SGE_NTIMERS];	/* interrupt holdoff timer array */
+	u8 counter_val[SGE_NCOUNTERS];	/* interrupt RX threshold array */
+
+	/*
+	 * Reverse maps from Absolute Queue IDs to associated queue pointers.
+	 * The absolute Queue IDs are in a compact range which start at a
+	 * [potentially large] Base Queue ID.  We perform the reverse map by
+	 * first converting the Absolute Queue ID into a Relative Queue ID by
+	 * subtracting off the Base Queue ID and then use a Relative Queue ID
+	 * indexed table to get the pointer to the corresponding software
+	 * queue structure.
+	 */
+	unsigned int egr_base;
+	unsigned int ingr_base;
+	void *egr_map[MAX_EGRQ];
+	struct sge_rspq *ingr_map[MAX_INGQ];
+};
+
+/*
+ * Utility macros to convert Absolute- to Relative-Queue indices and Egress-
+ * and Ingress-Queues.  The EQ_MAP() and IQ_MAP() macros which provide
+ * pointers to Ingress- and Egress-Queues can be used as both L- and R-values
+ */
+#define EQ_IDX(s, abs_id) ((unsigned int)((abs_id) - (s)->egr_base))
+#define IQ_IDX(s, abs_id) ((unsigned int)((abs_id) - (s)->ingr_base))
+
+#define EQ_MAP(s, abs_id) ((s)->egr_map[EQ_IDX(s, abs_id)])
+#define IQ_MAP(s, abs_id) ((s)->ingr_map[IQ_IDX(s, abs_id)])
+
+/*
+ * Macro to iterate across Queue Sets ("rxq" is a historic misnomer).
+ */
+#define for_each_ethrxq(sge, iter) \
+	for (iter = 0; iter < (sge)->ethqsets; iter++)
+
+/*
+ * Per-"adapter" (Virtual Function) information.
+ */
+struct adapter {
+	/* PCI resources */
+	void __iomem *regs;
+	struct pci_dev *pdev;
+	struct device *pdev_dev;
+
+	/* "adapter" resources */
+	unsigned long registered_device_map;
+	unsigned long open_device_map;
+	unsigned long flags;
+	struct adapter_params params;
+
+	/* queue and interrupt resources */
+	struct {
+		unsigned short vec;
+		char desc[22];
+	} msix_info[MSIX_ENTRIES];
+	struct sge sge;
+
+	/* Linux network device resources */
+	struct net_device *port[MAX_NPORTS];
+	const char *name;
+	unsigned int msg_enable;
+
+	/* debugfs resources */
+	struct dentry *debugfs_root;
+
+	/* various locks */
+	spinlock_t stats_lock;
+};
+
+enum { /* adapter flags */
+	FULL_INIT_DONE     = (1UL << 0),
+	USING_MSI          = (1UL << 1),
+	USING_MSIX         = (1UL << 2),
+	QUEUES_BOUND       = (1UL << 3),
+};
+
+/*
+ * The following register read/write routine definitions are required by
+ * the common code.
+ */
+
+/**
+ * t4_read_reg - read a HW register
+ * @adapter: the adapter
+ * @reg_addr: the register address
+ *
+ * Returns the 32-bit value of the given HW register.
+ */
+static inline u32 t4_read_reg(struct adapter *adapter, u32 reg_addr)
+{
+	return readl(adapter->regs + reg_addr);
+}
+
+/**
+ * t4_write_reg - write a HW register
+ * @adapter: the adapter
+ * @reg_addr: the register address
+ * @val: the value to write
+ *
+ * Write a 32-bit value into the given HW register.
+ */
+static inline void t4_write_reg(struct adapter *adapter, u32 reg_addr, u32 val)
+{
+	writel(val, adapter->regs + reg_addr);
+}
+
+#ifndef readq
+static inline u64 readq(const volatile void __iomem *addr)
+{
+	return readl(addr) + ((u64)readl(addr + 4) << 32);
+}
+
+static inline void writeq(u64 val, volatile void __iomem *addr)
+{
+	writel(val, addr);
+	writel(val >> 32, addr + 4);
+}
+#endif
+
+/**
+ * t4_read_reg64 - read a 64-bit HW register
+ * @adapter: the adapter
+ * @reg_addr: the register address
+ *
+ * Returns the 64-bit value of the given HW register.
+ */
+static inline u64 t4_read_reg64(struct adapter *adapter, u32 reg_addr)
+{
+	return readq(adapter->regs + reg_addr);
+}
+
+/**
+ * t4_write_reg64 - write a 64-bit HW register
+ * @adapter: the adapter
+ * @reg_addr: the register address
+ * @val: the value to write
+ *
+ * Write a 64-bit value into the given HW register.
+ */
+static inline void t4_write_reg64(struct adapter *adapter, u32 reg_addr,
+				  u64 val)
+{
+	writeq(val, adapter->regs + reg_addr);
+}
+
+/**
+ * port_name - return the string name of a port
+ * @adapter: the adapter
+ * @pidx: the port index
+ *
+ * Return the string name of the selected port.
+ */
+static inline const char *port_name(struct adapter *adapter, int pidx)
+{
+	return adapter->port[pidx]->name;
+}
+
+/**
+ * t4_os_set_hw_addr - store a port's MAC address in SW
+ * @adapter: the adapter
+ * @pidx: the port index
+ * @hw_addr: the Ethernet address
+ *
+ * Store the Ethernet address of the given port in SW.  Called by the common
+ * code when it retrieves a port's Ethernet address from EEPROM.
+ */
+static inline void t4_os_set_hw_addr(struct adapter *adapter, int pidx,
+				     u8 hw_addr[])
+{
+	memcpy(adapter->port[pidx]->dev_addr, hw_addr, ETH_ALEN);
+	memcpy(adapter->port[pidx]->perm_addr, hw_addr, ETH_ALEN);
+}
+
+/**
+ * netdev2pinfo - return the port_info structure associated with a net_device
+ * @dev: the netdev
+ *
+ * Return the struct port_info associated with a net_device
+ */
+static inline struct port_info *netdev2pinfo(const struct net_device *dev)
+{
+	return netdev_priv(dev);
+}
+
+/**
+ * adap2pinfo - return the port_info of a port
+ * @adap: the adapter
+ * @pidx: the port index
+ *
+ * Return the port_info structure for the adapter.
+ */
+static inline struct port_info *adap2pinfo(struct adapter *adapter, int pidx)
+{
+	return netdev_priv(adapter->port[pidx]);
+}
+
+/**
+ * netdev2adap - return the adapter structure associated with a net_device
+ * @dev: the netdev
+ *
+ * Return the struct adapter associated with a net_device
+ */
+static inline struct adapter *netdev2adap(const struct net_device *dev)
+{
+	return netdev2pinfo(dev)->adapter;
+}
+
+/*
+ * OS "Callback" function declarations.  These are functions that the OS code
+ * is "contracted" to provide for the common code.
+ */
+void t4vf_os_link_changed(struct adapter *, int, int);
+
+/*
+ * SGE function prototype declarations.
+ */
+int t4vf_sge_alloc_rxq(struct adapter *, struct sge_rspq *, bool,
+		       struct net_device *, int,
+		       struct sge_fl *, rspq_handler_t);
+int t4vf_sge_alloc_eth_txq(struct adapter *, struct sge_eth_txq *,
+			   struct net_device *, struct netdev_queue *,
+			   unsigned int);
+void t4vf_free_sge_resources(struct adapter *);
+
+int t4vf_eth_xmit(struct sk_buff *, struct net_device *);
+int t4vf_ethrx_handler(struct sge_rspq *, const __be64 *,
+		       const struct pkt_gl *);
+
+irq_handler_t t4vf_intr_handler(struct adapter *);
+irqreturn_t t4vf_sge_intr_msix(int, void *);
+
+int t4vf_sge_init(struct adapter *);
+void t4vf_sge_start(struct adapter *);
+void t4vf_sge_stop(struct adapter *);
+
+#endif /* __CXGB4VF_ADAPTER_H__ */
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
new file mode 100644
index 0000000..a165632
--- /dev/null
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -0,0 +1,2888 @@
+/*
+ * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet
+ * driver for Linux.
+ *
+ * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/debugfs.h>
+#include <linux/ethtool.h>
+
+#include "t4vf_common.h"
+#include "t4vf_defs.h"
+
+#include "../cxgb4/t4_regs.h"
+#include "../cxgb4/t4_msg.h"
+
+/*
+ * Generic information about the driver.
+ */
+#define DRV_VERSION "1.0.0"
+#define DRV_DESC "Chelsio T4 Virtual Function (VF) Network Driver"
+
+/*
+ * Module Parameters.
+ * ==================
+ */
+
+/*
+ * Default ethtool "message level" for adapters.
+ */
+#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
+			 NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
+			 NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
+
+static int dflt_msg_enable = DFLT_MSG_ENABLE;
+
+module_param(dflt_msg_enable, int, 0644);
+MODULE_PARM_DESC(dflt_msg_enable,
+		 "default adapter ethtool message level bitmap");
+
+/*
+ * The driver uses the best interrupt scheme available on a platform in the
+ * order MSI-X then MSI.  This parameter determines which of these schemes the
+ * driver may consider as follows:
+ *
+ *     msi = 2: choose from among MSI-X and MSI
+ *     msi = 1: only consider MSI interrupts
+ *
+ * Note that unlike the Physical Function driver, this Virtual Function driver
+ * does _not_ support legacy INTx interrupts (this limitation is mandated by
+ * the PCI-E SR-IOV standard).
+ */
+#define MSI_MSIX	2
+#define MSI_MSI		1
+#define MSI_DEFAULT	MSI_MSIX
+
+static int msi = MSI_DEFAULT;
+
+module_param(msi, int, 0644);
+MODULE_PARM_DESC(msi, "whether to use MSI-X or MSI");
+
+/*
+ * Fundamental constants.
+ * ======================
+ */
+
+enum {
+	MAX_TXQ_ENTRIES		= 16384,
+	MAX_RSPQ_ENTRIES	= 16384,
+	MAX_RX_BUFFERS		= 16384,
+
+	MIN_TXQ_ENTRIES		= 32,
+	MIN_RSPQ_ENTRIES	= 128,
+	MIN_FL_ENTRIES		= 16,
+
+	/*
+	 * For purposes of manipulating the Free List size we need to
+	 * recognize that Free Lists are actually Egress Queues (the host
+	 * produces free buffers which the hardware consumes), Egress Queues
+	 * indices are all in units of Egress Context Units bytes, and free
+	 * list entries are 64-bit PCI DMA addresses.  And since the state of
+	 * the Producer Index == the Consumer Index implies an EMPTY list, we
+	 * always have at least one Egress Unit's worth of Free List entries
+	 * unused.  See sge.c for more details ...
+	 */
+	EQ_UNIT = SGE_EQ_IDXSIZE,
+	FL_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64),
+	MIN_FL_RESID = FL_PER_EQ_UNIT,
+};
+
+/*
+ * Global driver state.
+ * ====================
+ */
+
+static struct dentry *cxgb4vf_debugfs_root;
+
+/*
+ * OS "Callback" functions.
+ * ========================
+ */
+
+/*
+ * The link status has changed on the indicated "port" (Virtual Interface).
+ */
+void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok)
+{
+	struct net_device *dev = adapter->port[pidx];
+
+	/*
+	 * If the port is disabled or the current recorded "link up"
+	 * status matches the new status, just return.
+	 */
+	if (!netif_running(dev) || link_ok == netif_carrier_ok(dev))
+		return;
+
+	/*
+	 * Tell the OS that the link status has changed and print a short
+	 * informative message on the console about the event.
+	 */
+	if (link_ok) {
+		const char *s;
+		const char *fc;
+		const struct port_info *pi = netdev_priv(dev);
+
+		netif_carrier_on(dev);
+
+		switch (pi->link_cfg.speed) {
+		case SPEED_10000:
+			s = "10Gbps";
+			break;
+
+		case SPEED_1000:
+			s = "1000Mbps";
+			break;
+
+		case SPEED_100:
+			s = "100Mbps";
+			break;
+
+		default:
+			s = "unknown";
+			break;
+		}
+
+		switch (pi->link_cfg.fc) {
+		case PAUSE_RX:
+			fc = "RX";
+			break;
+
+		case PAUSE_TX:
+			fc = "TX";
+			break;
+
+		case PAUSE_RX|PAUSE_TX:
+			fc = "RX/TX";
+			break;
+
+		default:
+			fc = "no";
+			break;
+		}
+
+		printk(KERN_INFO "%s: link up, %s, full-duplex, %s PAUSE\n",
+		       dev->name, s, fc);
+	} else {
+		netif_carrier_off(dev);
+		printk(KERN_INFO "%s: link down\n", dev->name);
+	}
+}
+
+/*
+ * Net device operations.
+ * ======================
+ */
+
+/*
+ * Record our new VLAN Group and enable/disable hardware VLAN Tag extraction
+ * based on whether the specified VLAN Group pointer is NULL or not.
+ */
+static void cxgb4vf_vlan_rx_register(struct net_device *dev,
+				     struct vlan_group *grp)
+{
+	struct port_info *pi = netdev_priv(dev);
+
+	pi->vlan_grp = grp;
+	t4vf_set_rxmode(pi->adapter, pi->viid, -1, -1, -1, -1, grp != NULL, 0);
+}
+
+/*
+ * Perform the MAC and PHY actions needed to enable a "port" (Virtual
+ * Interface).
+ */
+static int link_start(struct net_device *dev)
+{
+	int ret;
+	struct port_info *pi = netdev_priv(dev);
+
+	/*
+	 * We do not set address filters and promiscuity here, the stack does
+	 * that step explicitly.
+	 */
+	ret = t4vf_set_rxmode(pi->adapter, pi->viid, dev->mtu, -1, -1, -1, -1,
+			      true);
+	if (ret == 0) {
+		ret = t4vf_change_mac(pi->adapter, pi->viid,
+				      pi->xact_addr_filt, dev->dev_addr, true);
+		if (ret >= 0) {
+			pi->xact_addr_filt = ret;
+			ret = 0;
+		}
+	}
+
+	/*
+	 * We don't need to actually "start the link" itself since the
+	 * firmware will do that for us when the first Virtual Interface
+	 * is enabled on a port.
+	 */
+	if (ret == 0)
+		ret = t4vf_enable_vi(pi->adapter, pi->viid, true, true);
+	return ret;
+}
+
+/*
+ * Name the MSI-X interrupts.
+ */
+static void name_msix_vecs(struct adapter *adapter)
+{
+	int namelen = sizeof(adapter->msix_info[0].desc) - 1;
+	int pidx;
+
+	/*
+	 * Firmware events.
+	 */
+	snprintf(adapter->msix_info[MSIX_FW].desc, namelen,
+		 "%s-FWeventq", adapter->name);
+	adapter->msix_info[MSIX_FW].desc[namelen] = 0;
+
+	/*
+	 * Ethernet queues.
+	 */
+	for_each_port(adapter, pidx) {
+		struct net_device *dev = adapter->port[pidx];
+		const struct port_info *pi = netdev_priv(dev);
+		int qs, msi;
+
+		for (qs = 0, msi = MSIX_NIQFLINT;
+		     qs < pi->nqsets;
+		     qs++, msi++) {
+			snprintf(adapter->msix_info[msi].desc, namelen,
+				 "%s-%d", dev->name, qs);
+			adapter->msix_info[msi].desc[namelen] = 0;
+		}
+	}
+}
+
+/*
+ * Request all of our MSI-X resources.
+ */
+static int request_msix_queue_irqs(struct adapter *adapter)
+{
+	struct sge *s = &adapter->sge;
+	int rxq, msi, err;
+
+	/*
+	 * Firmware events.
+	 */
+	err = request_irq(adapter->msix_info[MSIX_FW].vec, t4vf_sge_intr_msix,
+			  0, adapter->msix_info[MSIX_FW].desc, &s->fw_evtq);
+	if (err)
+		return err;
+
+	/*
+	 * Ethernet queues.
+	 */
+	msi = MSIX_NIQFLINT;
+	for_each_ethrxq(s, rxq) {
+		err = request_irq(adapter->msix_info[msi].vec,
+				  t4vf_sge_intr_msix, 0,
+				  adapter->msix_info[msi].desc,
+				  &s->ethrxq[rxq].rspq);
+		if (err)
+			goto err_free_irqs;
+		msi++;
+	}
+	return 0;
+
+err_free_irqs:
+	while (--rxq >= 0)
+		free_irq(adapter->msix_info[--msi].vec, &s->ethrxq[rxq].rspq);
+	free_irq(adapter->msix_info[MSIX_FW].vec, &s->fw_evtq);
+	return err;
+}
+
+/*
+ * Free our MSI-X resources.
+ */
+static void free_msix_queue_irqs(struct adapter *adapter)
+{
+	struct sge *s = &adapter->sge;
+	int rxq, msi;
+
+	free_irq(adapter->msix_info[MSIX_FW].vec, &s->fw_evtq);
+	msi = MSIX_NIQFLINT;
+	for_each_ethrxq(s, rxq)
+		free_irq(adapter->msix_info[msi++].vec,
+			 &s->ethrxq[rxq].rspq);
+}
+
+/*
+ * Turn on NAPI and start up interrupts on a response queue.
+ */
+static void qenable(struct sge_rspq *rspq)
+{
+	napi_enable(&rspq->napi);
+
+	/*
+	 * 0-increment the Going To Sleep register to start the timer and
+	 * enable interrupts.
+	 */
+	t4_write_reg(rspq->adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
+		     CIDXINC(0) |
+		     SEINTARM(rspq->intr_params) |
+		     INGRESSQID(rspq->cntxt_id));
+}
+
+/*
+ * Enable NAPI scheduling and interrupt generation for all Receive Queues.
+ */
+static void enable_rx(struct adapter *adapter)
+{
+	int rxq;
+	struct sge *s = &adapter->sge;
+
+	for_each_ethrxq(s, rxq)
+		qenable(&s->ethrxq[rxq].rspq);
+	qenable(&s->fw_evtq);
+
+	/*
+	 * The interrupt queue doesn't use NAPI so we do the 0-increment of
+	 * its Going To Sleep register here to get it started.
+	 */
+	if (adapter->flags & USING_MSI)
+		t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
+			     CIDXINC(0) |
+			     SEINTARM(s->intrq.intr_params) |
+			     INGRESSQID(s->intrq.cntxt_id));
+
+}
+
+/*
+ * Wait until all NAPI handlers are descheduled.
+ */
+static void quiesce_rx(struct adapter *adapter)
+{
+	struct sge *s = &adapter->sge;
+	int rxq;
+
+	for_each_ethrxq(s, rxq)
+		napi_disable(&s->ethrxq[rxq].rspq.napi);
+	napi_disable(&s->fw_evtq.napi);
+}
+
+/*
+ * Response queue handler for the firmware event queue.
+ */
+static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp,
+			  const struct pkt_gl *gl)
+{
+	/*
+	 * Extract response opcode and get pointer to CPL message body.
+	 */
+	struct adapter *adapter = rspq->adapter;
+	u8 opcode = ((const struct rss_header *)rsp)->opcode;
+	void *cpl = (void *)(rsp + 1);
+
+	switch (opcode) {
+	case CPL_FW6_MSG: {
+		/*
+		 * We've received an asynchronous message from the firmware.
+		 */
+		const struct cpl_fw6_msg *fw_msg = cpl;
+		if (fw_msg->type == FW6_TYPE_CMD_RPL)
+			t4vf_handle_fw_rpl(adapter, fw_msg->data);
+		break;
+	}
+
+	case CPL_SGE_EGR_UPDATE: {
+		/*
+		 * We've received an Egress Queue Status Update message.  We
+		 * get these, if the SGE is configured to send these when the
+		 * firmware passes certain points in processing our TX
+		 * Ethernet Queue or if we make an explicit request for one.
+		 * We use these updates to determine when we may need to
+		 * restart a TX Ethernet Queue which was stopped for lack of
+		 * free TX Queue Descriptors ...
+		 */
+		const struct cpl_sge_egr_update *p = (void *)cpl;
+		unsigned int qid = EGR_QID(be32_to_cpu(p->opcode_qid));
+		struct sge *s = &adapter->sge;
+		struct sge_txq *tq;
+		struct sge_eth_txq *txq;
+		unsigned int eq_idx;
+
+		/*
+		 * Perform sanity checking on the Queue ID to make sure it
+		 * really refers to one of our TX Ethernet Egress Queues which
+		 * is active and matches the queue's ID.  None of these error
+		 * conditions should ever happen so we may want to either make
+		 * them fatal and/or conditionalized under DEBUG.
+		 */
+		eq_idx = EQ_IDX(s, qid);
+		if (unlikely(eq_idx >= MAX_EGRQ)) {
+			dev_err(adapter->pdev_dev,
+				"Egress Update QID %d out of range\n", qid);
+			break;
+		}
+		tq = s->egr_map[eq_idx];
+		if (unlikely(tq == NULL)) {
+			dev_err(adapter->pdev_dev,
+				"Egress Update QID %d TXQ=NULL\n", qid);
+			break;
+		}
+		txq = container_of(tq, struct sge_eth_txq, q);
+		if (unlikely(tq->abs_id != qid)) {
+			dev_err(adapter->pdev_dev,
+				"Egress Update QID %d refers to TXQ %d\n",
+				qid, tq->abs_id);
+			break;
+		}
+
+		/*
+		 * Restart a stopped TX Queue which has less than half of its
+		 * TX ring in use ...
+		 */
+		txq->q.restarts++;
+		netif_tx_wake_queue(txq->txq);
+		break;
+	}
+
+	default:
+		dev_err(adapter->pdev_dev,
+			"unexpected CPL %#x on FW event queue\n", opcode);
+	}
+
+	return 0;
+}
+
+/*
+ * Allocate SGE TX/RX response queues.  Determine how many sets of SGE queues
+ * to use and initializes them.  We support multiple "Queue Sets" per port if
+ * we have MSI-X, otherwise just one queue set per port.
+ */
+static int setup_sge_queues(struct adapter *adapter)
+{
+	struct sge *s = &adapter->sge;
+	int err, pidx, msix;
+
+	/*
+	 * Clear "Queue Set" Free List Starving and TX Queue Mapping Error
+	 * state.
+	 */
+	bitmap_zero(s->starving_fl, MAX_EGRQ);
+
+	/*
+	 * If we're using MSI interrupt mode we need to set up a "forwarded
+	 * interrupt" queue which we'll set up with our MSI vector.  The rest
+	 * of the ingress queues will be set up to forward their interrupts to
+	 * this queue ...  This must be first since t4vf_sge_alloc_rxq() uses
+	 * the intrq's queue ID as the interrupt forwarding queue for the
+	 * subsequent calls ...
+	 */
+	if (adapter->flags & USING_MSI) {
+		err = t4vf_sge_alloc_rxq(adapter, &s->intrq, false,
+					 adapter->port[0], 0, NULL, NULL);
+		if (err)
+			goto err_free_queues;
+	}
+
+	/*
+	 * Allocate our ingress queue for asynchronous firmware messages.
+	 */
+	err = t4vf_sge_alloc_rxq(adapter, &s->fw_evtq, true, adapter->port[0],
+				 MSIX_FW, NULL, fwevtq_handler);
+	if (err)
+		goto err_free_queues;
+
+	/*
+	 * Allocate each "port"'s initial Queue Sets.  These can be changed
+	 * later on ... up to the point where any interface on the adapter is
+	 * brought up at which point lots of things get nailed down
+	 * permanently ...
+	 */
+	msix = MSIX_NIQFLINT;
+	for_each_port(adapter, pidx) {
+		struct net_device *dev = adapter->port[pidx];
+		struct port_info *pi = netdev_priv(dev);
+		struct sge_eth_rxq *rxq = &s->ethrxq[pi->first_qset];
+		struct sge_eth_txq *txq = &s->ethtxq[pi->first_qset];
+		int qs;
+
+		for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) {
+			err = t4vf_sge_alloc_rxq(adapter, &rxq->rspq, false,
+						 dev, msix++,
+						 &rxq->fl, t4vf_ethrx_handler);
+			if (err)
+				goto err_free_queues;
+
+			err = t4vf_sge_alloc_eth_txq(adapter, txq, dev,
+					     netdev_get_tx_queue(dev, qs),
+					     s->fw_evtq.cntxt_id);
+			if (err)
+				goto err_free_queues;
+
+			rxq->rspq.idx = qs;
+			memset(&rxq->stats, 0, sizeof(rxq->stats));
+		}
+	}
+
+	/*
+	 * Create the reverse mappings for the queues.
+	 */
+	s->egr_base = s->ethtxq[0].q.abs_id - s->ethtxq[0].q.cntxt_id;
+	s->ingr_base = s->ethrxq[0].rspq.abs_id - s->ethrxq[0].rspq.cntxt_id;
+	IQ_MAP(s, s->fw_evtq.abs_id) = &s->fw_evtq;
+	for_each_port(adapter, pidx) {
+		struct net_device *dev = adapter->port[pidx];
+		struct port_info *pi = netdev_priv(dev);
+		struct sge_eth_rxq *rxq = &s->ethrxq[pi->first_qset];
+		struct sge_eth_txq *txq = &s->ethtxq[pi->first_qset];
+		int qs;
+
+		for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) {
+			IQ_MAP(s, rxq->rspq.abs_id) = &rxq->rspq;
+			EQ_MAP(s, txq->q.abs_id) = &txq->q;
+
+			/*
+			 * The FW_IQ_CMD doesn't return the Absolute Queue IDs
+			 * for Free Lists but since all of the Egress Queues
+			 * (including Free Lists) have Relative Queue IDs
+			 * which are computed as Absolute - Base Queue ID, we
+			 * can synthesize the Absolute Queue IDs for the Free
+			 * Lists.  This is useful for debugging purposes when
+			 * we want to dump Queue Contexts via the PF Driver.
+			 */
+			rxq->fl.abs_id = rxq->fl.cntxt_id + s->egr_base;
+			EQ_MAP(s, rxq->fl.abs_id) = &rxq->fl;
+		}
+	}
+	return 0;
+
+err_free_queues:
+	t4vf_free_sge_resources(adapter);
+	return err;
+}
+
+/*
+ * Set up Receive Side Scaling (RSS) to distribute packets to multiple receive
+ * queues.  We configure the RSS CPU lookup table to distribute to the number
+ * of HW receive queues, and the response queue lookup table to narrow that
+ * down to the response queues actually configured for each "port" (Virtual
+ * Interface).  We always configure the RSS mapping for all ports since the
+ * mapping table has plenty of entries.
+ */
+static int setup_rss(struct adapter *adapter)
+{
+	int pidx;
+
+	for_each_port(adapter, pidx) {
+		struct port_info *pi = adap2pinfo(adapter, pidx);
+		struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[pi->first_qset];
+		u16 rss[MAX_PORT_QSETS];
+		int qs, err;
+
+		for (qs = 0; qs < pi->nqsets; qs++)
+			rss[qs] = rxq[qs].rspq.abs_id;
+
+		err = t4vf_config_rss_range(adapter, pi->viid,
+					    0, pi->rss_size, rss, pi->nqsets);
+		if (err)
+			return err;
+
+		/*
+		 * Perform Global RSS Mode-specific initialization.
+		 */
+		switch (adapter->params.rss.mode) {
+		case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL:
+			/*
+			 * If Tunnel All Lookup isn't specified in the global
+			 * RSS Configuration, then we need to specify a
+			 * default Ingress Queue for any ingress packets which
+			 * aren't hashed.  We'll use our first ingress queue
+			 * ...
+			 */
+			if (!adapter->params.rss.u.basicvirtual.tnlalllookup) {
+				union rss_vi_config config;
+				err = t4vf_read_rss_vi_config(adapter,
+							      pi->viid,
+							      &config);
+				if (err)
+					return err;
+				config.basicvirtual.defaultq =
+					rxq[0].rspq.abs_id;
+				err = t4vf_write_rss_vi_config(adapter,
+							       pi->viid,
+							       &config);
+				if (err)
+					return err;
+			}
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Bring the adapter up.  Called whenever we go from no "ports" open to having
+ * one open.  This function performs the actions necessary to make an adapter
+ * operational, such as completing the initialization of HW modules, and
+ * enabling interrupts.  Must be called with the rtnl lock held.  (Note that
+ * this is called "cxgb_up" in the PF Driver.)
+ */
+static int adapter_up(struct adapter *adapter)
+{
+	int err;
+
+	/*
+	 * If this is the first time we've been called, perform basic
+	 * adapter setup.  Once we've done this, many of our adapter
+	 * parameters can no longer be changed ...
+	 */
+	if ((adapter->flags & FULL_INIT_DONE) == 0) {
+		err = setup_sge_queues(adapter);
+		if (err)
+			return err;
+		err = setup_rss(adapter);
+		if (err) {
+			t4vf_free_sge_resources(adapter);
+			return err;
+		}
+
+		if (adapter->flags & USING_MSIX)
+			name_msix_vecs(adapter);
+		adapter->flags |= FULL_INIT_DONE;
+	}
+
+	/*
+	 * Acquire our interrupt resources.  We only support MSI-X and MSI.
+	 */
+	BUG_ON((adapter->flags & (USING_MSIX|USING_MSI)) == 0);
+	if (adapter->flags & USING_MSIX)
+		err = request_msix_queue_irqs(adapter);
+	else
+		err = request_irq(adapter->pdev->irq,
+				  t4vf_intr_handler(adapter), 0,
+				  adapter->name, adapter);
+	if (err) {
+		dev_err(adapter->pdev_dev, "request_irq failed, err %d\n",
+			err);
+		return err;
+	}
+
+	/*
+	 * Enable NAPI ingress processing and return success.
+	 */
+	enable_rx(adapter);
+	t4vf_sge_start(adapter);
+	return 0;
+}
+
+/*
+ * Bring the adapter down.  Called whenever the last "port" (Virtual
+ * Interface) closed.  (Note that this routine is called "cxgb_down" in the PF
+ * Driver.)
+ */
+static void adapter_down(struct adapter *adapter)
+{
+	/*
+	 * Free interrupt resources.
+	 */
+	if (adapter->flags & USING_MSIX)
+		free_msix_queue_irqs(adapter);
+	else
+		free_irq(adapter->pdev->irq, adapter);
+
+	/*
+	 * Wait for NAPI handlers to finish.
+	 */
+	quiesce_rx(adapter);
+}
+
+/*
+ * Start up a net device.
+ */
+static int cxgb4vf_open(struct net_device *dev)
+{
+	int err;
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
+
+	/*
+	 * If this is the first interface that we're opening on the "adapter",
+	 * bring the "adapter" up now.
+	 */
+	if (adapter->open_device_map == 0) {
+		err = adapter_up(adapter);
+		if (err)
+			return err;
+	}
+
+	/*
+	 * Note that this interface is up and start everything up ...
+	 */
+	dev->real_num_tx_queues = pi->nqsets;
+	set_bit(pi->port_id, &adapter->open_device_map);
+	link_start(dev);
+	netif_tx_start_all_queues(dev);
+	return 0;
+}
+
+/*
+ * Shut down a net device.  This routine is called "cxgb_close" in the PF
+ * Driver ...
+ */
+static int cxgb4vf_stop(struct net_device *dev)
+{
+	int ret;
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
+
+	netif_tx_stop_all_queues(dev);
+	netif_carrier_off(dev);
+	ret = t4vf_enable_vi(adapter, pi->viid, false, false);
+	pi->link_cfg.link_ok = 0;
+
+	clear_bit(pi->port_id, &adapter->open_device_map);
+	if (adapter->open_device_map == 0)
+		adapter_down(adapter);
+	return 0;
+}
+
+/*
+ * Translate our basic statistics into the standard "ifconfig" statistics.
+ */
+static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev)
+{
+	struct t4vf_port_stats stats;
+	struct port_info *pi = netdev2pinfo(dev);
+	struct adapter *adapter = pi->adapter;
+	struct net_device_stats *ns = &dev->stats;
+	int err;
+
+	spin_lock(&adapter->stats_lock);
+	err = t4vf_get_port_stats(adapter, pi->pidx, &stats);
+	spin_unlock(&adapter->stats_lock);
+
+	memset(ns, 0, sizeof(*ns));
+	if (err)
+		return ns;
+
+	ns->tx_bytes = (stats.tx_bcast_bytes + stats.tx_mcast_bytes +
+			stats.tx_ucast_bytes + stats.tx_offload_bytes);
+	ns->tx_packets = (stats.tx_bcast_frames + stats.tx_mcast_frames +
+			  stats.tx_ucast_frames + stats.tx_offload_frames);
+	ns->rx_bytes = (stats.rx_bcast_bytes + stats.rx_mcast_bytes +
+			stats.rx_ucast_bytes);
+	ns->rx_packets = (stats.rx_bcast_frames + stats.rx_mcast_frames +
+			  stats.rx_ucast_frames);
+	ns->multicast = stats.rx_mcast_frames;
+	ns->tx_errors = stats.tx_drop_frames;
+	ns->rx_errors = stats.rx_err_frames;
+
+	return ns;
+}
+
+/*
+ * Collect up to maxaddrs worth of a netdevice's unicast addresses into an
+ * array of addrss pointers and return the number collected.
+ */
+static inline int collect_netdev_uc_list_addrs(const struct net_device *dev,
+					       const u8 **addr,
+					       unsigned int maxaddrs)
+{
+	unsigned int naddr = 0;
+	const struct netdev_hw_addr *ha;
+
+	for_each_dev_addr(dev, ha) {
+		addr[naddr++] = ha->addr;
+		if (naddr >= maxaddrs)
+			break;
+	}
+	return naddr;
+}
+
+/*
+ * Collect up to maxaddrs worth of a netdevice's multicast addresses into an
+ * array of addrss pointers and return the number collected.
+ */
+static inline int collect_netdev_mc_list_addrs(const struct net_device *dev,
+					       const u8 **addr,
+					       unsigned int maxaddrs)
+{
+	unsigned int naddr = 0;
+	const struct netdev_hw_addr *ha;
+
+	netdev_for_each_mc_addr(ha, dev) {
+		addr[naddr++] = ha->addr;
+		if (naddr >= maxaddrs)
+			break;
+	}
+	return naddr;
+}
+
+/*
+ * Configure the exact and hash address filters to handle a port's multicast
+ * and secondary unicast MAC addresses.
+ */
+static int set_addr_filters(const struct net_device *dev, bool sleep)
+{
+	u64 mhash = 0;
+	u64 uhash = 0;
+	bool free = true;
+	u16 filt_idx[7];
+	const u8 *addr[7];
+	int ret, naddr = 0;
+	const struct port_info *pi = netdev_priv(dev);
+
+	/* first do the secondary unicast addresses */
+	naddr = collect_netdev_uc_list_addrs(dev, addr, ARRAY_SIZE(addr));
+	if (naddr > 0) {
+		ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
+					  naddr, addr, filt_idx, &uhash, sleep);
+		if (ret < 0)
+			return ret;
+
+		free = false;
+	}
+
+	/* next set up the multicast addresses */
+	naddr = collect_netdev_mc_list_addrs(dev, addr, ARRAY_SIZE(addr));
+	if (naddr > 0) {
+		ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
+					  naddr, addr, filt_idx, &mhash, sleep);
+		if (ret < 0)
+			return ret;
+	}
+
+	return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0,
+				  uhash | mhash, sleep);
+}
+
+/*
+ * Set RX properties of a port, such as promiscruity, address filters, and MTU.
+ * If @mtu is -1 it is left unchanged.
+ */
+static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
+{
+	int ret;
+	struct port_info *pi = netdev_priv(dev);
+
+	ret = set_addr_filters(dev, sleep_ok);
+	if (ret == 0)
+		ret = t4vf_set_rxmode(pi->adapter, pi->viid, -1,
+				      (dev->flags & IFF_PROMISC) != 0,
+				      (dev->flags & IFF_ALLMULTI) != 0,
+				      1, -1, sleep_ok);
+	return ret;
+}
+
+/*
+ * Set the current receive modes on the device.
+ */
+static void cxgb4vf_set_rxmode(struct net_device *dev)
+{
+	/* unfortunately we can't return errors to the stack */
+	set_rxmode(dev, -1, false);
+}
+
+/*
+ * Find the entry in the interrupt holdoff timer value array which comes
+ * closest to the specified interrupt holdoff value.
+ */
+static int closest_timer(const struct sge *s, int us)
+{
+	int i, timer_idx = 0, min_delta = INT_MAX;
+
+	for (i = 0; i < ARRAY_SIZE(s->timer_val); i++) {
+		int delta = us - s->timer_val[i];
+		if (delta < 0)
+			delta = -delta;
+		if (delta < min_delta) {
+			min_delta = delta;
+			timer_idx = i;
+		}
+	}
+	return timer_idx;
+}
+
+static int closest_thres(const struct sge *s, int thres)
+{
+	int i, delta, pktcnt_idx = 0, min_delta = INT_MAX;
+
+	for (i = 0; i < ARRAY_SIZE(s->counter_val); i++) {
+		delta = thres - s->counter_val[i];
+		if (delta < 0)
+			delta = -delta;
+		if (delta < min_delta) {
+			min_delta = delta;
+			pktcnt_idx = i;
+		}
+	}
+	return pktcnt_idx;
+}
+
+/*
+ * Return a queue's interrupt hold-off time in us.  0 means no timer.
+ */
+static unsigned int qtimer_val(const struct adapter *adapter,
+			       const struct sge_rspq *rspq)
+{
+	unsigned int timer_idx = QINTR_TIMER_IDX_GET(rspq->intr_params);
+
+	return timer_idx < SGE_NTIMERS
+		? adapter->sge.timer_val[timer_idx]
+		: 0;
+}
+
+/**
+ *	set_rxq_intr_params - set a queue's interrupt holdoff parameters
+ *	@adapter: the adapter
+ *	@rspq: the RX response queue
+ *	@us: the hold-off time in us, or 0 to disable timer
+ *	@cnt: the hold-off packet count, or 0 to disable counter
+ *
+ *	Sets an RX response queue's interrupt hold-off time and packet count.
+ *	At least one of the two needs to be enabled for the queue to generate
+ *	interrupts.
+ */
+static int set_rxq_intr_params(struct adapter *adapter, struct sge_rspq *rspq,
+			       unsigned int us, unsigned int cnt)
+{
+	unsigned int timer_idx;
+
+	/*
+	 * If both the interrupt holdoff timer and count are specified as
+	 * zero, default to a holdoff count of 1 ...
+	 */
+	if ((us | cnt) == 0)
+		cnt = 1;
+
+	/*
+	 * If an interrupt holdoff count has been specified, then find the
+	 * closest configured holdoff count and use that.  If the response
+	 * queue has already been created, then update its queue context
+	 * parameters ...
+	 */
+	if (cnt) {
+		int err;
+		u32 v, pktcnt_idx;
+
+		pktcnt_idx = closest_thres(&adapter->sge, cnt);
+		if (rspq->desc && rspq->pktcnt_idx != pktcnt_idx) {
+			v = FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) |
+			    FW_PARAMS_PARAM_X(
+					FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH) |
+			    FW_PARAMS_PARAM_YZ(rspq->cntxt_id);
+			err = t4vf_set_params(adapter, 1, &v, &pktcnt_idx);
+			if (err)
+				return err;
+		}
+		rspq->pktcnt_idx = pktcnt_idx;
+	}
+
+	/*
+	 * Compute the closest holdoff timer index from the supplied holdoff
+	 * timer value.
+	 */
+	timer_idx = (us == 0
+		     ? SGE_TIMER_RSTRT_CNTR
+		     : closest_timer(&adapter->sge, us));
+
+	/*
+	 * Update the response queue's interrupt coalescing parameters and
+	 * return success.
+	 */
+	rspq->intr_params = (QINTR_TIMER_IDX(timer_idx) |
+			     (cnt > 0 ? QINTR_CNT_EN : 0));
+	return 0;
+}
+
+/*
+ * Return a version number to identify the type of adapter.  The scheme is:
+ * - bits 0..9: chip version
+ * - bits 10..15: chip revision
+ */
+static inline unsigned int mk_adap_vers(const struct adapter *adapter)
+{
+	/*
+	 * Chip version 4, revision 0x3f (cxgb4vf).
+	 */
+	return 4 | (0x3f << 10);
+}
+
+/*
+ * Execute the specified ioctl command.
+ */
+static int cxgb4vf_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	int ret = 0;
+
+	switch (cmd) {
+	    /*
+	     * The VF Driver doesn't have access to any of the other
+	     * common Ethernet device ioctl()'s (like reading/writing
+	     * PHY registers, etc.
+	     */
+
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+	return ret;
+}
+
+/*
+ * Change the device's MTU.
+ */
+static int cxgb4vf_change_mtu(struct net_device *dev, int new_mtu)
+{
+	int ret;
+	struct port_info *pi = netdev_priv(dev);
+
+	/* accommodate SACK */
+	if (new_mtu < 81)
+		return -EINVAL;
+
+	ret = t4vf_set_rxmode(pi->adapter, pi->viid, new_mtu,
+			      -1, -1, -1, -1, true);
+	if (!ret)
+		dev->mtu = new_mtu;
+	return ret;
+}
+
+/*
+ * Change the devices MAC address.
+ */
+static int cxgb4vf_set_mac_addr(struct net_device *dev, void *_addr)
+{
+	int ret;
+	struct sockaddr *addr = _addr;
+	struct port_info *pi = netdev_priv(dev);
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EINVAL;
+
+	ret = t4vf_change_mac(pi->adapter, pi->viid, pi->xact_addr_filt,
+			      addr->sa_data, true);
+	if (ret < 0)
+		return ret;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	pi->xact_addr_filt = ret;
+	return 0;
+}
+
+/*
+ * Return a TX Queue on which to send the specified skb.
+ */
+static u16 cxgb4vf_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+	/*
+	 * XXX For now just use the default hash but we probably want to
+	 * XXX look at other possibilities ...
+	 */
+	return skb_tx_hash(dev, skb);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Poll all of our receive queues.  This is called outside of normal interrupt
+ * context.
+ */
+static void cxgb4vf_poll_controller(struct net_device *dev)
+{
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
+
+	if (adapter->flags & USING_MSIX) {
+		struct sge_eth_rxq *rxq;
+		int nqsets;
+
+		rxq = &adapter->sge.ethrxq[pi->first_qset];
+		for (nqsets = pi->nqsets; nqsets; nqsets--) {
+			t4vf_sge_intr_msix(0, &rxq->rspq);
+			rxq++;
+		}
+	} else
+		t4vf_intr_handler(adapter)(0, adapter);
+}
+#endif
+
+/*
+ * Ethtool operations.
+ * ===================
+ *
+ * Note that we don't support any ethtool operations which change the physical
+ * state of the port to which we're linked.
+ */
+
+/*
+ * Return current port link settings.
+ */
+static int cxgb4vf_get_settings(struct net_device *dev,
+				struct ethtool_cmd *cmd)
+{
+	const struct port_info *pi = netdev_priv(dev);
+
+	cmd->supported = pi->link_cfg.supported;
+	cmd->advertising = pi->link_cfg.advertising;
+	cmd->speed = netif_carrier_ok(dev) ? pi->link_cfg.speed : -1;
+	cmd->duplex = DUPLEX_FULL;
+
+	cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+	cmd->phy_address = pi->port_id;
+	cmd->transceiver = XCVR_EXTERNAL;
+	cmd->autoneg = pi->link_cfg.autoneg;
+	cmd->maxtxpkt = 0;
+	cmd->maxrxpkt = 0;
+	return 0;
+}
+
+/*
+ * Return our driver information.
+ */
+static void cxgb4vf_get_drvinfo(struct net_device *dev,
+				struct ethtool_drvinfo *drvinfo)
+{
+	struct adapter *adapter = netdev2adap(dev);
+
+	strcpy(drvinfo->driver, KBUILD_MODNAME);
+	strcpy(drvinfo->version, DRV_VERSION);
+	strcpy(drvinfo->bus_info, pci_name(to_pci_dev(dev->dev.parent)));
+	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+		 "%u.%u.%u.%u, TP %u.%u.%u.%u",
+		 FW_HDR_FW_VER_MAJOR_GET(adapter->params.dev.fwrev),
+		 FW_HDR_FW_VER_MINOR_GET(adapter->params.dev.fwrev),
+		 FW_HDR_FW_VER_MICRO_GET(adapter->params.dev.fwrev),
+		 FW_HDR_FW_VER_BUILD_GET(adapter->params.dev.fwrev),
+		 FW_HDR_FW_VER_MAJOR_GET(adapter->params.dev.tprev),
+		 FW_HDR_FW_VER_MINOR_GET(adapter->params.dev.tprev),
+		 FW_HDR_FW_VER_MICRO_GET(adapter->params.dev.tprev),
+		 FW_HDR_FW_VER_BUILD_GET(adapter->params.dev.tprev));
+}
+
+/*
+ * Return current adapter message level.
+ */
+static u32 cxgb4vf_get_msglevel(struct net_device *dev)
+{
+	return netdev2adap(dev)->msg_enable;
+}
+
+/*
+ * Set current adapter message level.
+ */
+static void cxgb4vf_set_msglevel(struct net_device *dev, u32 msglevel)
+{
+	netdev2adap(dev)->msg_enable = msglevel;
+}
+
+/*
+ * Return the device's current Queue Set ring size parameters along with the
+ * allowed maximum values.  Since ethtool doesn't understand the concept of
+ * multi-queue devices, we just return the current values associated with the
+ * first Queue Set.
+ */
+static void cxgb4vf_get_ringparam(struct net_device *dev,
+				  struct ethtool_ringparam *rp)
+{
+	const struct port_info *pi = netdev_priv(dev);
+	const struct sge *s = &pi->adapter->sge;
+
+	rp->rx_max_pending = MAX_RX_BUFFERS;
+	rp->rx_mini_max_pending = MAX_RSPQ_ENTRIES;
+	rp->rx_jumbo_max_pending = 0;
+	rp->tx_max_pending = MAX_TXQ_ENTRIES;
+
+	rp->rx_pending = s->ethrxq[pi->first_qset].fl.size - MIN_FL_RESID;
+	rp->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size;
+	rp->rx_jumbo_pending = 0;
+	rp->tx_pending = s->ethtxq[pi->first_qset].q.size;
+}
+
+/*
+ * Set the Queue Set ring size parameters for the device.  Again, since
+ * ethtool doesn't allow for the concept of multiple queues per device, we'll
+ * apply these new values across all of the Queue Sets associated with the
+ * device -- after vetting them of course!
+ */
+static int cxgb4vf_set_ringparam(struct net_device *dev,
+				 struct ethtool_ringparam *rp)
+{
+	const struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
+	struct sge *s = &adapter->sge;
+	int qs;
+
+	if (rp->rx_pending > MAX_RX_BUFFERS ||
+	    rp->rx_jumbo_pending ||
+	    rp->tx_pending > MAX_TXQ_ENTRIES ||
+	    rp->rx_mini_pending > MAX_RSPQ_ENTRIES ||
+	    rp->rx_mini_pending < MIN_RSPQ_ENTRIES ||
+	    rp->rx_pending < MIN_FL_ENTRIES ||
+	    rp->tx_pending < MIN_TXQ_ENTRIES)
+		return -EINVAL;
+
+	if (adapter->flags & FULL_INIT_DONE)
+		return -EBUSY;
+
+	for (qs = pi->first_qset; qs < pi->first_qset + pi->nqsets; qs++) {
+		s->ethrxq[qs].fl.size = rp->rx_pending + MIN_FL_RESID;
+		s->ethrxq[qs].rspq.size = rp->rx_mini_pending;
+		s->ethtxq[qs].q.size = rp->tx_pending;
+	}
+	return 0;
+}
+
+/*
+ * Return the interrupt holdoff timer and count for the first Queue Set on the
+ * device.  Our extension ioctl() (the cxgbtool interface) allows the
+ * interrupt holdoff timer to be read on all of the device's Queue Sets.
+ */
+static int cxgb4vf_get_coalesce(struct net_device *dev,
+				struct ethtool_coalesce *coalesce)
+{
+	const struct port_info *pi = netdev_priv(dev);
+	const struct adapter *adapter = pi->adapter;
+	const struct sge_rspq *rspq = &adapter->sge.ethrxq[pi->first_qset].rspq;
+
+	coalesce->rx_coalesce_usecs = qtimer_val(adapter, rspq);
+	coalesce->rx_max_coalesced_frames =
+		((rspq->intr_params & QINTR_CNT_EN)
+		 ? adapter->sge.counter_val[rspq->pktcnt_idx]
+		 : 0);
+	return 0;
+}
+
+/*
+ * Set the RX interrupt holdoff timer and count for the first Queue Set on the
+ * interface.  Our extension ioctl() (the cxgbtool interface) allows us to set
+ * the interrupt holdoff timer on any of the device's Queue Sets.
+ */
+static int cxgb4vf_set_coalesce(struct net_device *dev,
+				struct ethtool_coalesce *coalesce)
+{
+	const struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
+
+	return set_rxq_intr_params(adapter,
+				   &adapter->sge.ethrxq[pi->first_qset].rspq,
+				   coalesce->rx_coalesce_usecs,
+				   coalesce->rx_max_coalesced_frames);
+}
+
+/*
+ * Report current port link pause parameter settings.
+ */
+static void cxgb4vf_get_pauseparam(struct net_device *dev,
+				   struct ethtool_pauseparam *pauseparam)
+{
+	struct port_info *pi = netdev_priv(dev);
+
+	pauseparam->autoneg = (pi->link_cfg.requested_fc & PAUSE_AUTONEG) != 0;
+	pauseparam->rx_pause = (pi->link_cfg.fc & PAUSE_RX) != 0;
+	pauseparam->tx_pause = (pi->link_cfg.fc & PAUSE_TX) != 0;
+}
+
+/*
+ * Return whether RX Checksum Offloading is currently enabled for the device.
+ */
+static u32 cxgb4vf_get_rx_csum(struct net_device *dev)
+{
+	struct port_info *pi = netdev_priv(dev);
+
+	return (pi->rx_offload & RX_CSO) != 0;
+}
+
+/*
+ * Turn RX Checksum Offloading on or off for the device.
+ */
+static int cxgb4vf_set_rx_csum(struct net_device *dev, u32 csum)
+{
+	struct port_info *pi = netdev_priv(dev);
+
+	if (csum)
+		pi->rx_offload |= RX_CSO;
+	else
+		pi->rx_offload &= ~RX_CSO;
+	return 0;
+}
+
+/*
+ * Identify the port by blinking the port's LED.
+ */
+static int cxgb4vf_phys_id(struct net_device *dev, u32 id)
+{
+	struct port_info *pi = netdev_priv(dev);
+
+	return t4vf_identify_port(pi->adapter, pi->viid, 5);
+}
+
+/*
+ * Port stats maintained per queue of the port.
+ */
+struct queue_port_stats {
+	u64 tso;
+	u64 tx_csum;
+	u64 rx_csum;
+	u64 vlan_ex;
+	u64 vlan_ins;
+};
+
+/*
+ * Strings for the ETH_SS_STATS statistics set ("ethtool -S").  Note that
+ * these need to match the order of statistics returned by
+ * t4vf_get_port_stats().
+ */
+static const char stats_strings[][ETH_GSTRING_LEN] = {
+	/*
+	 * These must match the layout of the t4vf_port_stats structure.
+	 */
+	"TxBroadcastBytes  ",
+	"TxBroadcastFrames ",
+	"TxMulticastBytes  ",
+	"TxMulticastFrames ",
+	"TxUnicastBytes    ",
+	"TxUnicastFrames   ",
+	"TxDroppedFrames   ",
+	"TxOffloadBytes    ",
+	"TxOffloadFrames   ",
+	"RxBroadcastBytes  ",
+	"RxBroadcastFrames ",
+	"RxMulticastBytes  ",
+	"RxMulticastFrames ",
+	"RxUnicastBytes    ",
+	"RxUnicastFrames   ",
+	"RxErrorFrames     ",
+
+	/*
+	 * These are accumulated per-queue statistics and must match the
+	 * order of the fields in the queue_port_stats structure.
+	 */
+	"TSO               ",
+	"TxCsumOffload     ",
+	"RxCsumGood        ",
+	"VLANextractions   ",
+	"VLANinsertions    ",
+};
+
+/*
+ * Return the number of statistics in the specified statistics set.
+ */
+static int cxgb4vf_get_sset_count(struct net_device *dev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(stats_strings);
+	default:
+		return -EOPNOTSUPP;
+	}
+	/*NOTREACHED*/
+}
+
+/*
+ * Return the strings for the specified statistics set.
+ */
+static void cxgb4vf_get_strings(struct net_device *dev,
+				u32 sset,
+				u8 *data)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		memcpy(data, stats_strings, sizeof(stats_strings));
+		break;
+	}
+}
+
+/*
+ * Small utility routine to accumulate queue statistics across the queues of
+ * a "port".
+ */
+static void collect_sge_port_stats(const struct adapter *adapter,
+				   const struct port_info *pi,
+				   struct queue_port_stats *stats)
+{
+	const struct sge_eth_txq *txq = &adapter->sge.ethtxq[pi->first_qset];
+	const struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[pi->first_qset];
+	int qs;
+
+	memset(stats, 0, sizeof(*stats));
+	for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) {
+		stats->tso += txq->tso;
+		stats->tx_csum += txq->tx_cso;
+		stats->rx_csum += rxq->stats.rx_cso;
+		stats->vlan_ex += rxq->stats.vlan_ex;
+		stats->vlan_ins += txq->vlan_ins;
+	}
+}
+
+/*
+ * Return the ETH_SS_STATS statistics set.
+ */
+static void cxgb4vf_get_ethtool_stats(struct net_device *dev,
+				      struct ethtool_stats *stats,
+				      u64 *data)
+{
+	struct port_info *pi = netdev2pinfo(dev);
+	struct adapter *adapter = pi->adapter;
+	int err = t4vf_get_port_stats(adapter, pi->pidx,
+				      (struct t4vf_port_stats *)data);
+	if (err)
+		memset(data, 0, sizeof(struct t4vf_port_stats));
+
+	data += sizeof(struct t4vf_port_stats) / sizeof(u64);
+	collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data);
+}
+
+/*
+ * Return the size of our register map.
+ */
+static int cxgb4vf_get_regs_len(struct net_device *dev)
+{
+	return T4VF_REGMAP_SIZE;
+}
+
+/*
+ * Dump a block of registers, start to end inclusive, into a buffer.
+ */
+static void reg_block_dump(struct adapter *adapter, void *regbuf,
+			   unsigned int start, unsigned int end)
+{
+	u32 *bp = regbuf + start - T4VF_REGMAP_START;
+
+	for ( ; start <= end; start += sizeof(u32)) {
+		/*
+		 * Avoid reading the Mailbox Control register since that
+		 * can trigger a Mailbox Ownership Arbitration cycle and
+		 * interfere with communication with the firmware.
+		 */
+		if (start == T4VF_CIM_BASE_ADDR + CIM_VF_EXT_MAILBOX_CTRL)
+			*bp++ = 0xffff;
+		else
+			*bp++ = t4_read_reg(adapter, start);
+	}
+}
+
+/*
+ * Copy our entire register map into the provided buffer.
+ */
+static void cxgb4vf_get_regs(struct net_device *dev,
+			     struct ethtool_regs *regs,
+			     void *regbuf)
+{
+	struct adapter *adapter = netdev2adap(dev);
+
+	regs->version = mk_adap_vers(adapter);
+
+	/*
+	 * Fill in register buffer with our register map.
+	 */
+	memset(regbuf, 0, T4VF_REGMAP_SIZE);
+
+	reg_block_dump(adapter, regbuf,
+		       T4VF_SGE_BASE_ADDR + T4VF_MOD_MAP_SGE_FIRST,
+		       T4VF_SGE_BASE_ADDR + T4VF_MOD_MAP_SGE_LAST);
+	reg_block_dump(adapter, regbuf,
+		       T4VF_MPS_BASE_ADDR + T4VF_MOD_MAP_MPS_FIRST,
+		       T4VF_MPS_BASE_ADDR + T4VF_MOD_MAP_MPS_LAST);
+	reg_block_dump(adapter, regbuf,
+		       T4VF_PL_BASE_ADDR + T4VF_MOD_MAP_PL_FIRST,
+		       T4VF_PL_BASE_ADDR + T4VF_MOD_MAP_PL_LAST);
+	reg_block_dump(adapter, regbuf,
+		       T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_FIRST,
+		       T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_LAST);
+
+	reg_block_dump(adapter, regbuf,
+		       T4VF_MBDATA_BASE_ADDR + T4VF_MBDATA_FIRST,
+		       T4VF_MBDATA_BASE_ADDR + T4VF_MBDATA_LAST);
+}
+
+/*
+ * Report current Wake On LAN settings.
+ */
+static void cxgb4vf_get_wol(struct net_device *dev,
+			    struct ethtool_wolinfo *wol)
+{
+	wol->supported = 0;
+	wol->wolopts = 0;
+	memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+/*
+ * Set TCP Segmentation Offloading feature capabilities.
+ */
+static int cxgb4vf_set_tso(struct net_device *dev, u32 tso)
+{
+	if (tso)
+		dev->features |= NETIF_F_TSO | NETIF_F_TSO6;
+	else
+		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+	return 0;
+}
+
+static struct ethtool_ops cxgb4vf_ethtool_ops = {
+	.get_settings		= cxgb4vf_get_settings,
+	.get_drvinfo		= cxgb4vf_get_drvinfo,
+	.get_msglevel		= cxgb4vf_get_msglevel,
+	.set_msglevel		= cxgb4vf_set_msglevel,
+	.get_ringparam		= cxgb4vf_get_ringparam,
+	.set_ringparam		= cxgb4vf_set_ringparam,
+	.get_coalesce		= cxgb4vf_get_coalesce,
+	.set_coalesce		= cxgb4vf_set_coalesce,
+	.get_pauseparam		= cxgb4vf_get_pauseparam,
+	.get_rx_csum		= cxgb4vf_get_rx_csum,
+	.set_rx_csum		= cxgb4vf_set_rx_csum,
+	.set_tx_csum		= ethtool_op_set_tx_ipv6_csum,
+	.set_sg			= ethtool_op_set_sg,
+	.get_link		= ethtool_op_get_link,
+	.get_strings		= cxgb4vf_get_strings,
+	.phys_id		= cxgb4vf_phys_id,
+	.get_sset_count		= cxgb4vf_get_sset_count,
+	.get_ethtool_stats	= cxgb4vf_get_ethtool_stats,
+	.get_regs_len		= cxgb4vf_get_regs_len,
+	.get_regs		= cxgb4vf_get_regs,
+	.get_wol		= cxgb4vf_get_wol,
+	.set_tso		= cxgb4vf_set_tso,
+};
+
+/*
+ * /sys/kernel/debug/cxgb4vf support code and data.
+ * ================================================
+ */
+
+/*
+ * Show SGE Queue Set information.  We display QPL Queues Sets per line.
+ */
+#define QPL	4
+
+static int sge_qinfo_show(struct seq_file *seq, void *v)
+{
+	struct adapter *adapter = seq->private;
+	int eth_entries = DIV_ROUND_UP(adapter->sge.ethqsets, QPL);
+	int qs, r = (uintptr_t)v - 1;
+
+	if (r)
+		seq_putc(seq, '\n');
+
+	#define S3(fmt_spec, s, v) \
+		do {\
+			seq_printf(seq, "%-12s", s); \
+			for (qs = 0; qs < n; ++qs) \
+				seq_printf(seq, " %16" fmt_spec, v); \
+			seq_putc(seq, '\n'); \
+		} while (0)
+	#define S(s, v)		S3("s", s, v)
+	#define T(s, v)		S3("u", s, txq[qs].v)
+	#define R(s, v)		S3("u", s, rxq[qs].v)
+
+	if (r < eth_entries) {
+		const struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[r * QPL];
+		const struct sge_eth_txq *txq = &adapter->sge.ethtxq[r * QPL];
+		int n = min(QPL, adapter->sge.ethqsets - QPL * r);
+
+		S("QType:", "Ethernet");
+		S("Interface:",
+		  (rxq[qs].rspq.netdev
+		   ? rxq[qs].rspq.netdev->name
+		   : "N/A"));
+		S3("d", "Port:",
+		   (rxq[qs].rspq.netdev
+		    ? ((struct port_info *)
+		       netdev_priv(rxq[qs].rspq.netdev))->port_id
+		    : -1));
+		T("TxQ ID:", q.abs_id);
+		T("TxQ size:", q.size);
+		T("TxQ inuse:", q.in_use);
+		T("TxQ PIdx:", q.pidx);
+		T("TxQ CIdx:", q.cidx);
+		R("RspQ ID:", rspq.abs_id);
+		R("RspQ size:", rspq.size);
+		R("RspQE size:", rspq.iqe_len);
+		S3("u", "Intr delay:", qtimer_val(adapter, &rxq[qs].rspq));
+		S3("u", "Intr pktcnt:",
+		   adapter->sge.counter_val[rxq[qs].rspq.pktcnt_idx]);
+		R("RspQ CIdx:", rspq.cidx);
+		R("RspQ Gen:", rspq.gen);
+		R("FL ID:", fl.abs_id);
+		R("FL size:", fl.size - MIN_FL_RESID);
+		R("FL avail:", fl.avail);
+		R("FL PIdx:", fl.pidx);
+		R("FL CIdx:", fl.cidx);
+		return 0;
+	}
+
+	r -= eth_entries;
+	if (r == 0) {
+		const struct sge_rspq *evtq = &adapter->sge.fw_evtq;
+
+		seq_printf(seq, "%-12s %16s\n", "QType:", "FW event queue");
+		seq_printf(seq, "%-12s %16u\n", "RspQ ID:", evtq->abs_id);
+		seq_printf(seq, "%-12s %16u\n", "Intr delay:",
+			   qtimer_val(adapter, evtq));
+		seq_printf(seq, "%-12s %16u\n", "Intr pktcnt:",
+			   adapter->sge.counter_val[evtq->pktcnt_idx]);
+		seq_printf(seq, "%-12s %16u\n", "RspQ Cidx:", evtq->cidx);
+		seq_printf(seq, "%-12s %16u\n", "RspQ Gen:", evtq->gen);
+	} else if (r == 1) {
+		const struct sge_rspq *intrq = &adapter->sge.intrq;
+
+		seq_printf(seq, "%-12s %16s\n", "QType:", "Interrupt Queue");
+		seq_printf(seq, "%-12s %16u\n", "RspQ ID:", intrq->abs_id);
+		seq_printf(seq, "%-12s %16u\n", "Intr delay:",
+			   qtimer_val(adapter, intrq));
+		seq_printf(seq, "%-12s %16u\n", "Intr pktcnt:",
+			   adapter->sge.counter_val[intrq->pktcnt_idx]);
+		seq_printf(seq, "%-12s %16u\n", "RspQ Cidx:", intrq->cidx);
+		seq_printf(seq, "%-12s %16u\n", "RspQ Gen:", intrq->gen);
+	}
+
+	#undef R
+	#undef T
+	#undef S
+	#undef S3
+
+	return 0;
+}
+
+/*
+ * Return the number of "entries" in our "file".  We group the multi-Queue
+ * sections with QPL Queue Sets per "entry".  The sections of the output are:
+ *
+ *     Ethernet RX/TX Queue Sets
+ *     Firmware Event Queue
+ *     Forwarded Interrupt Queue (if in MSI mode)
+ */
+static int sge_queue_entries(const struct adapter *adapter)
+{
+	return DIV_ROUND_UP(adapter->sge.ethqsets, QPL) + 1 +
+		((adapter->flags & USING_MSI) != 0);
+}
+
+static void *sge_queue_start(struct seq_file *seq, loff_t *pos)
+{
+	int entries = sge_queue_entries(seq->private);
+
+	return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL;
+}
+
+static void sge_queue_stop(struct seq_file *seq, void *v)
+{
+}
+
+static void *sge_queue_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	int entries = sge_queue_entries(seq->private);
+
+	++*pos;
+	return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL;
+}
+
+static const struct seq_operations sge_qinfo_seq_ops = {
+	.start = sge_queue_start,
+	.next  = sge_queue_next,
+	.stop  = sge_queue_stop,
+	.show  = sge_qinfo_show
+};
+
+static int sge_qinfo_open(struct inode *inode, struct file *file)
+{
+	int res = seq_open(file, &sge_qinfo_seq_ops);
+
+	if (!res) {
+		struct seq_file *seq = file->private_data;
+		seq->private = inode->i_private;
+	}
+	return res;
+}
+
+static const struct file_operations sge_qinfo_debugfs_fops = {
+	.owner   = THIS_MODULE,
+	.open    = sge_qinfo_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release,
+};
+
+/*
+ * Show SGE Queue Set statistics.  We display QPL Queues Sets per line.
+ */
+#define QPL	4
+
+static int sge_qstats_show(struct seq_file *seq, void *v)
+{
+	struct adapter *adapter = seq->private;
+	int eth_entries = DIV_ROUND_UP(adapter->sge.ethqsets, QPL);
+	int qs, r = (uintptr_t)v - 1;
+
+	if (r)
+		seq_putc(seq, '\n');
+
+	#define S3(fmt, s, v) \
+		do { \
+			seq_printf(seq, "%-16s", s); \
+			for (qs = 0; qs < n; ++qs) \
+				seq_printf(seq, " %8" fmt, v); \
+			seq_putc(seq, '\n'); \
+		} while (0)
+	#define S(s, v)		S3("s", s, v)
+
+	#define T3(fmt, s, v)	S3(fmt, s, txq[qs].v)
+	#define T(s, v)		T3("lu", s, v)
+
+	#define R3(fmt, s, v)	S3(fmt, s, rxq[qs].v)
+	#define R(s, v)		R3("lu", s, v)
+
+	if (r < eth_entries) {
+		const struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[r * QPL];
+		const struct sge_eth_txq *txq = &adapter->sge.ethtxq[r * QPL];
+		int n = min(QPL, adapter->sge.ethqsets - QPL * r);
+
+		S("QType:", "Ethernet");
+		S("Interface:",
+		  (rxq[qs].rspq.netdev
+		   ? rxq[qs].rspq.netdev->name
+		   : "N/A"));
+		R3("u", "RspQNullInts:", rspq.unhandled_irqs);
+		R("RxPackets:", stats.pkts);
+		R("RxCSO:", stats.rx_cso);
+		R("VLANxtract:", stats.vlan_ex);
+		R("LROmerged:", stats.lro_merged);
+		R("LROpackets:", stats.lro_pkts);
+		R("RxDrops:", stats.rx_drops);
+		T("TSO:", tso);
+		T("TxCSO:", tx_cso);
+		T("VLANins:", vlan_ins);
+		T("TxQFull:", q.stops);
+		T("TxQRestarts:", q.restarts);
+		T("TxMapErr:", mapping_err);
+		R("FLAllocErr:", fl.alloc_failed);
+		R("FLLrgAlcErr:", fl.large_alloc_failed);
+		R("FLStarving:", fl.starving);
+		return 0;
+	}
+
+	r -= eth_entries;
+	if (r == 0) {
+		const struct sge_rspq *evtq = &adapter->sge.fw_evtq;
+
+		seq_printf(seq, "%-8s %16s\n", "QType:", "FW event queue");
+		seq_printf(seq, "%-16s %8u\n", "RspQNullInts:",
+			   evtq->unhandled_irqs);
+		seq_printf(seq, "%-16s %8u\n", "RspQ CIdx:", evtq->cidx);
+		seq_printf(seq, "%-16s %8u\n", "RspQ Gen:", evtq->gen);
+	} else if (r == 1) {
+		const struct sge_rspq *intrq = &adapter->sge.intrq;
+
+		seq_printf(seq, "%-8s %16s\n", "QType:", "Interrupt Queue");
+		seq_printf(seq, "%-16s %8u\n", "RspQNullInts:",
+			   intrq->unhandled_irqs);
+		seq_printf(seq, "%-16s %8u\n", "RspQ CIdx:", intrq->cidx);
+		seq_printf(seq, "%-16s %8u\n", "RspQ Gen:", intrq->gen);
+	}
+
+	#undef R
+	#undef T
+	#undef S
+	#undef R3
+	#undef T3
+	#undef S3
+
+	return 0;
+}
+
+/*
+ * Return the number of "entries" in our "file".  We group the multi-Queue
+ * sections with QPL Queue Sets per "entry".  The sections of the output are:
+ *
+ *     Ethernet RX/TX Queue Sets
+ *     Firmware Event Queue
+ *     Forwarded Interrupt Queue (if in MSI mode)
+ */
+static int sge_qstats_entries(const struct adapter *adapter)
+{
+	return DIV_ROUND_UP(adapter->sge.ethqsets, QPL) + 1 +
+		((adapter->flags & USING_MSI) != 0);
+}
+
+static void *sge_qstats_start(struct seq_file *seq, loff_t *pos)
+{
+	int entries = sge_qstats_entries(seq->private);
+
+	return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL;
+}
+
+static void sge_qstats_stop(struct seq_file *seq, void *v)
+{
+}
+
+static void *sge_qstats_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	int entries = sge_qstats_entries(seq->private);
+
+	(*pos)++;
+	return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL;
+}
+
+static const struct seq_operations sge_qstats_seq_ops = {
+	.start = sge_qstats_start,
+	.next  = sge_qstats_next,
+	.stop  = sge_qstats_stop,
+	.show  = sge_qstats_show
+};
+
+static int sge_qstats_open(struct inode *inode, struct file *file)
+{
+	int res = seq_open(file, &sge_qstats_seq_ops);
+
+	if (res == 0) {
+		struct seq_file *seq = file->private_data;
+		seq->private = inode->i_private;
+	}
+	return res;
+}
+
+static const struct file_operations sge_qstats_proc_fops = {
+	.owner   = THIS_MODULE,
+	.open    = sge_qstats_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release,
+};
+
+/*
+ * Show PCI-E SR-IOV Virtual Function Resource Limits.
+ */
+static int resources_show(struct seq_file *seq, void *v)
+{
+	struct adapter *adapter = seq->private;
+	struct vf_resources *vfres = &adapter->params.vfres;
+
+	#define S(desc, fmt, var) \
+		seq_printf(seq, "%-60s " fmt "\n", \
+			   desc " (" #var "):", vfres->var)
+
+	S("Virtual Interfaces", "%d", nvi);
+	S("Egress Queues", "%d", neq);
+	S("Ethernet Control", "%d", nethctrl);
+	S("Ingress Queues/w Free Lists/Interrupts", "%d", niqflint);
+	S("Ingress Queues", "%d", niq);
+	S("Traffic Class", "%d", tc);
+	S("Port Access Rights Mask", "%#x", pmask);
+	S("MAC Address Filters", "%d", nexactf);
+	S("Firmware Command Read Capabilities", "%#x", r_caps);
+	S("Firmware Command Write/Execute Capabilities", "%#x", wx_caps);
+
+	#undef S
+
+	return 0;
+}
+
+static int resources_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, resources_show, inode->i_private);
+}
+
+static const struct file_operations resources_proc_fops = {
+	.owner   = THIS_MODULE,
+	.open    = resources_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = single_release,
+};
+
+/*
+ * Show Virtual Interfaces.
+ */
+static int interfaces_show(struct seq_file *seq, void *v)
+{
+	if (v == SEQ_START_TOKEN) {
+		seq_puts(seq, "Interface  Port   VIID\n");
+	} else {
+		struct adapter *adapter = seq->private;
+		int pidx = (uintptr_t)v - 2;
+		struct net_device *dev = adapter->port[pidx];
+		struct port_info *pi = netdev_priv(dev);
+
+		seq_printf(seq, "%9s  %4d  %#5x\n",
+			   dev->name, pi->port_id, pi->viid);
+	}
+	return 0;
+}
+
+static inline void *interfaces_get_idx(struct adapter *adapter, loff_t pos)
+{
+	return pos <= adapter->params.nports
+		? (void *)(uintptr_t)(pos + 1)
+		: NULL;
+}
+
+static void *interfaces_start(struct seq_file *seq, loff_t *pos)
+{
+	return *pos
+		? interfaces_get_idx(seq->private, *pos)
+		: SEQ_START_TOKEN;
+}
+
+static void *interfaces_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	(*pos)++;
+	return interfaces_get_idx(seq->private, *pos);
+}
+
+static void interfaces_stop(struct seq_file *seq, void *v)
+{
+}
+
+static const struct seq_operations interfaces_seq_ops = {
+	.start = interfaces_start,
+	.next  = interfaces_next,
+	.stop  = interfaces_stop,
+	.show  = interfaces_show
+};
+
+static int interfaces_open(struct inode *inode, struct file *file)
+{
+	int res = seq_open(file, &interfaces_seq_ops);
+
+	if (res == 0) {
+		struct seq_file *seq = file->private_data;
+		seq->private = inode->i_private;
+	}
+	return res;
+}
+
+static const struct file_operations interfaces_proc_fops = {
+	.owner   = THIS_MODULE,
+	.open    = interfaces_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release,
+};
+
+/*
+ * /sys/kernel/debugfs/cxgb4vf/ files list.
+ */
+struct cxgb4vf_debugfs_entry {
+	const char *name;		/* name of debugfs node */
+	mode_t mode;			/* file system mode */
+	const struct file_operations *fops;
+};
+
+static struct cxgb4vf_debugfs_entry debugfs_files[] = {
+	{ "sge_qinfo",  S_IRUGO, &sge_qinfo_debugfs_fops },
+	{ "sge_qstats", S_IRUGO, &sge_qstats_proc_fops },
+	{ "resources",  S_IRUGO, &resources_proc_fops },
+	{ "interfaces", S_IRUGO, &interfaces_proc_fops },
+};
+
+/*
+ * Module and device initialization and cleanup code.
+ * ==================================================
+ */
+
+/*
+ * Set up out /sys/kernel/debug/cxgb4vf sub-nodes.  We assume that the
+ * directory (debugfs_root) has already been set up.
+ */
+static int __devinit setup_debugfs(struct adapter *adapter)
+{
+	int i;
+
+	BUG_ON(adapter->debugfs_root == NULL);
+
+	/*
+	 * Debugfs support is best effort.
+	 */
+	for (i = 0; i < ARRAY_SIZE(debugfs_files); i++)
+		(void)debugfs_create_file(debugfs_files[i].name,
+				  debugfs_files[i].mode,
+				  adapter->debugfs_root,
+				  (void *)adapter,
+				  debugfs_files[i].fops);
+
+	return 0;
+}
+
+/*
+ * Tear down the /sys/kernel/debug/cxgb4vf sub-nodes created above.  We leave
+ * it to our caller to tear down the directory (debugfs_root).
+ */
+static void __devexit cleanup_debugfs(struct adapter *adapter)
+{
+	BUG_ON(adapter->debugfs_root == NULL);
+
+	/*
+	 * Unlike our sister routine cleanup_proc(), we don't need to remove
+	 * individual entries because a call will be made to
+	 * debugfs_remove_recursive().  We just need to clean up any ancillary
+	 * persistent state.
+	 */
+	/* nothing to do */
+}
+
+/*
+ * Perform early "adapter" initialization.  This is where we discover what
+ * adapter parameters we're going to be using and initialize basic adapter
+ * hardware support.
+ */
+static int adap_init0(struct adapter *adapter)
+{
+	struct vf_resources *vfres = &adapter->params.vfres;
+	struct sge_params *sge_params = &adapter->params.sge;
+	struct sge *s = &adapter->sge;
+	unsigned int ethqsets;
+	int err;
+
+	/*
+	 * Wait for the device to become ready before proceeding ...
+	 */
+	err = t4vf_wait_dev_ready(adapter);
+	if (err) {
+		dev_err(adapter->pdev_dev, "device didn't become ready:"
+			" err=%d\n", err);
+		return err;
+	}
+
+	/*
+	 * Grab basic operational parameters.  These will predominantly have
+	 * been set up by the Physical Function Driver or will be hard coded
+	 * into the adapter.  We just have to live with them ...  Note that
+	 * we _must_ get our VPD parameters before our SGE parameters because
+	 * we need to know the adapter's core clock from the VPD in order to
+	 * properly decode the SGE Timer Values.
+	 */
+	err = t4vf_get_dev_params(adapter);
+	if (err) {
+		dev_err(adapter->pdev_dev, "unable to retrieve adapter"
+			" device parameters: err=%d\n", err);
+		return err;
+	}
+	err = t4vf_get_vpd_params(adapter);
+	if (err) {
+		dev_err(adapter->pdev_dev, "unable to retrieve adapter"
+			" VPD parameters: err=%d\n", err);
+		return err;
+	}
+	err = t4vf_get_sge_params(adapter);
+	if (err) {
+		dev_err(adapter->pdev_dev, "unable to retrieve adapter"
+			" SGE parameters: err=%d\n", err);
+		return err;
+	}
+	err = t4vf_get_rss_glb_config(adapter);
+	if (err) {
+		dev_err(adapter->pdev_dev, "unable to retrieve adapter"
+			" RSS parameters: err=%d\n", err);
+		return err;
+	}
+	if (adapter->params.rss.mode !=
+	    FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) {
+		dev_err(adapter->pdev_dev, "unable to operate with global RSS"
+			" mode %d\n", adapter->params.rss.mode);
+		return -EINVAL;
+	}
+	err = t4vf_sge_init(adapter);
+	if (err) {
+		dev_err(adapter->pdev_dev, "unable to use adapter parameters:"
+			" err=%d\n", err);
+		return err;
+	}
+
+	/*
+	 * Retrieve our RX interrupt holdoff timer values and counter
+	 * threshold values from the SGE parameters.
+	 */
+	s->timer_val[0] = core_ticks_to_us(adapter,
+		TIMERVALUE0_GET(sge_params->sge_timer_value_0_and_1));
+	s->timer_val[1] = core_ticks_to_us(adapter,
+		TIMERVALUE1_GET(sge_params->sge_timer_value_0_and_1));
+	s->timer_val[2] = core_ticks_to_us(adapter,
+		TIMERVALUE0_GET(sge_params->sge_timer_value_2_and_3));
+	s->timer_val[3] = core_ticks_to_us(adapter,
+		TIMERVALUE1_GET(sge_params->sge_timer_value_2_and_3));
+	s->timer_val[4] = core_ticks_to_us(adapter,
+		TIMERVALUE0_GET(sge_params->sge_timer_value_4_and_5));
+	s->timer_val[5] = core_ticks_to_us(adapter,
+		TIMERVALUE1_GET(sge_params->sge_timer_value_4_and_5));
+
+	s->counter_val[0] =
+		THRESHOLD_0_GET(sge_params->sge_ingress_rx_threshold);
+	s->counter_val[1] =
+		THRESHOLD_1_GET(sge_params->sge_ingress_rx_threshold);
+	s->counter_val[2] =
+		THRESHOLD_2_GET(sge_params->sge_ingress_rx_threshold);
+	s->counter_val[3] =
+		THRESHOLD_3_GET(sge_params->sge_ingress_rx_threshold);
+
+	/*
+	 * Grab our Virtual Interface resource allocation, extract the
+	 * features that we're interested in and do a bit of sanity testing on
+	 * what we discover.
+	 */
+	err = t4vf_get_vfres(adapter);
+	if (err) {
+		dev_err(adapter->pdev_dev, "unable to get virtual interface"
+			" resources: err=%d\n", err);
+		return err;
+	}
+
+	/*
+	 * The number of "ports" which we support is equal to the number of
+	 * Virtual Interfaces with which we've been provisioned.
+	 */
+	adapter->params.nports = vfres->nvi;
+	if (adapter->params.nports > MAX_NPORTS) {
+		dev_warn(adapter->pdev_dev, "only using %d of %d allowed"
+			 " virtual interfaces\n", MAX_NPORTS,
+			 adapter->params.nports);
+		adapter->params.nports = MAX_NPORTS;
+	}
+
+	/*
+	 * We need to reserve a number of the ingress queues with Free List
+	 * and Interrupt capabilities for special interrupt purposes (like
+	 * asynchronous firmware messages, or forwarded interrupts if we're
+	 * using MSI).  The rest of the FL/Intr-capable ingress queues will be
+	 * matched up one-for-one with Ethernet/Control egress queues in order
+	 * to form "Queue Sets" which will be aportioned between the "ports".
+	 * For each Queue Set, we'll need the ability to allocate two Egress
+	 * Contexts -- one for the Ingress Queue Free List and one for the TX
+	 * Ethernet Queue.
+	 */
+	ethqsets = vfres->niqflint - INGQ_EXTRAS;
+	if (vfres->nethctrl != ethqsets) {
+		dev_warn(adapter->pdev_dev, "unequal number of [available]"
+			 " ingress/egress queues (%d/%d); using minimum for"
+			 " number of Queue Sets\n", ethqsets, vfres->nethctrl);
+		ethqsets = min(vfres->nethctrl, ethqsets);
+	}
+	if (vfres->neq < ethqsets*2) {
+		dev_warn(adapter->pdev_dev, "Not enough Egress Contexts (%d)"
+			 " to support Queue Sets (%d); reducing allowed Queue"
+			 " Sets\n", vfres->neq, ethqsets);
+		ethqsets = vfres->neq/2;
+	}
+	if (ethqsets > MAX_ETH_QSETS) {
+		dev_warn(adapter->pdev_dev, "only using %d of %d allowed Queue"
+			 " Sets\n", MAX_ETH_QSETS, adapter->sge.max_ethqsets);
+		ethqsets = MAX_ETH_QSETS;
+	}
+	if (vfres->niq != 0 || vfres->neq > ethqsets*2) {
+		dev_warn(adapter->pdev_dev, "unused resources niq/neq (%d/%d)"
+			 " ignored\n", vfres->niq, vfres->neq - ethqsets*2);
+	}
+	adapter->sge.max_ethqsets = ethqsets;
+
+	/*
+	 * Check for various parameter sanity issues.  Most checks simply
+	 * result in us using fewer resources than our provissioning but we
+	 * do need at least  one "port" with which to work ...
+	 */
+	if (adapter->sge.max_ethqsets < adapter->params.nports) {
+		dev_warn(adapter->pdev_dev, "only using %d of %d available"
+			 " virtual interfaces (too few Queue Sets)\n",
+			 adapter->sge.max_ethqsets, adapter->params.nports);
+		adapter->params.nports = adapter->sge.max_ethqsets;
+	}
+	if (adapter->params.nports == 0) {
+		dev_err(adapter->pdev_dev, "no virtual interfaces configured/"
+			"usable!\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static inline void init_rspq(struct sge_rspq *rspq, u8 timer_idx,
+			     u8 pkt_cnt_idx, unsigned int size,
+			     unsigned int iqe_size)
+{
+	rspq->intr_params = (QINTR_TIMER_IDX(timer_idx) |
+			     (pkt_cnt_idx < SGE_NCOUNTERS ? QINTR_CNT_EN : 0));
+	rspq->pktcnt_idx = (pkt_cnt_idx < SGE_NCOUNTERS
+			    ? pkt_cnt_idx
+			    : 0);
+	rspq->iqe_len = iqe_size;
+	rspq->size = size;
+}
+
+/*
+ * Perform default configuration of DMA queues depending on the number and
+ * type of ports we found and the number of available CPUs.  Most settings can
+ * be modified by the admin via ethtool and cxgbtool prior to the adapter
+ * being brought up for the first time.
+ */
+static void __devinit cfg_queues(struct adapter *adapter)
+{
+	struct sge *s = &adapter->sge;
+	int q10g, n10g, qidx, pidx, qs;
+
+	/*
+	 * We should not be called till we know how many Queue Sets we can
+	 * support.  In particular, this means that we need to know what kind
+	 * of interrupts we'll be using ...
+	 */
+	BUG_ON((adapter->flags & (USING_MSIX|USING_MSI)) == 0);
+
+	/*
+	 * Count the number of 10GbE Virtual Interfaces that we have.
+	 */
+	n10g = 0;
+	for_each_port(adapter, pidx)
+		n10g += is_10g_port(&adap2pinfo(adapter, pidx)->link_cfg);
+
+	/*
+	 * We default to 1 queue per non-10G port and up to # of cores queues
+	 * per 10G port.
+	 */
+	if (n10g == 0)
+		q10g = 0;
+	else {
+		int n1g = (adapter->params.nports - n10g);
+		q10g = (adapter->sge.max_ethqsets - n1g) / n10g;
+		if (q10g > num_online_cpus())
+			q10g = num_online_cpus();
+	}
+
+	/*
+	 * Allocate the "Queue Sets" to the various Virtual Interfaces.
+	 * The layout will be established in setup_sge_queues() when the
+	 * adapter is brough up for the first time.
+	 */
+	qidx = 0;
+	for_each_port(adapter, pidx) {
+		struct port_info *pi = adap2pinfo(adapter, pidx);
+
+		pi->first_qset = qidx;
+		pi->nqsets = is_10g_port(&pi->link_cfg) ? q10g : 1;
+		qidx += pi->nqsets;
+	}
+	s->ethqsets = qidx;
+
+	/*
+	 * Set up default Queue Set parameters ...  Start off with the
+	 * shortest interrupt holdoff timer.
+	 */
+	for (qs = 0; qs < s->max_ethqsets; qs++) {
+		struct sge_eth_rxq *rxq = &s->ethrxq[qs];
+		struct sge_eth_txq *txq = &s->ethtxq[qs];
+
+		init_rspq(&rxq->rspq, 0, 0, 1024, L1_CACHE_BYTES);
+		rxq->fl.size = 72;
+		txq->q.size = 1024;
+	}
+
+	/*
+	 * The firmware event queue is used for link state changes and
+	 * notifications of TX DMA completions.
+	 */
+	init_rspq(&s->fw_evtq, SGE_TIMER_RSTRT_CNTR, 0, 512,
+		  L1_CACHE_BYTES);
+
+	/*
+	 * The forwarded interrupt queue is used when we're in MSI interrupt
+	 * mode.  In this mode all interrupts associated with RX queues will
+	 * be forwarded to a single queue which we'll associate with our MSI
+	 * interrupt vector.  The messages dropped in the forwarded interrupt
+	 * queue will indicate which ingress queue needs servicing ...  This
+	 * queue needs to be large enough to accommodate all of the ingress
+	 * queues which are forwarding their interrupt (+1 to prevent the PIDX
+	 * from equalling the CIDX if every ingress queue has an outstanding
+	 * interrupt).  The queue doesn't need to be any larger because no
+	 * ingress queue will ever have more than one outstanding interrupt at
+	 * any time ...
+	 */
+	init_rspq(&s->intrq, SGE_TIMER_RSTRT_CNTR, 0, MSIX_ENTRIES + 1,
+		  L1_CACHE_BYTES);
+}
+
+/*
+ * Reduce the number of Ethernet queues across all ports to at most n.
+ * n provides at least one queue per port.
+ */
+static void __devinit reduce_ethqs(struct adapter *adapter, int n)
+{
+	int i;
+	struct port_info *pi;
+
+	/*
+	 * While we have too many active Ether Queue Sets, interate across the
+	 * "ports" and reduce their individual Queue Set allocations.
+	 */
+	BUG_ON(n < adapter->params.nports);
+	while (n < adapter->sge.ethqsets)
+		for_each_port(adapter, i) {
+			pi = adap2pinfo(adapter, i);
+			if (pi->nqsets > 1) {
+				pi->nqsets--;
+				adapter->sge.ethqsets--;
+				if (adapter->sge.ethqsets <= n)
+					break;
+			}
+		}
+
+	/*
+	 * Reassign the starting Queue Sets for each of the "ports" ...
+	 */
+	n = 0;
+	for_each_port(adapter, i) {
+		pi = adap2pinfo(adapter, i);
+		pi->first_qset = n;
+		n += pi->nqsets;
+	}
+}
+
+/*
+ * We need to grab enough MSI-X vectors to cover our interrupt needs.  Ideally
+ * we get a separate MSI-X vector for every "Queue Set" plus any extras we
+ * need.  Minimally we need one for every Virtual Interface plus those needed
+ * for our "extras".  Note that this process may lower the maximum number of
+ * allowed Queue Sets ...
+ */
+static int __devinit enable_msix(struct adapter *adapter)
+{
+	int i, err, want, need;
+	struct msix_entry entries[MSIX_ENTRIES];
+	struct sge *s = &adapter->sge;
+
+	for (i = 0; i < MSIX_ENTRIES; ++i)
+		entries[i].entry = i;
+
+	/*
+	 * We _want_ enough MSI-X interrupts to cover all of our "Queue Sets"
+	 * plus those needed for our "extras" (for example, the firmware
+	 * message queue).  We _need_ at least one "Queue Set" per Virtual
+	 * Interface plus those needed for our "extras".  So now we get to see
+	 * if the song is right ...
+	 */
+	want = s->max_ethqsets + MSIX_EXTRAS;
+	need = adapter->params.nports + MSIX_EXTRAS;
+	while ((err = pci_enable_msix(adapter->pdev, entries, want)) >= need)
+		want = err;
+
+	if (err == 0) {
+		int nqsets = want - MSIX_EXTRAS;
+		if (nqsets < s->max_ethqsets) {
+			dev_warn(adapter->pdev_dev, "only enough MSI-X vectors"
+				 " for %d Queue Sets\n", nqsets);
+			s->max_ethqsets = nqsets;
+			if (nqsets < s->ethqsets)
+				reduce_ethqs(adapter, nqsets);
+		}
+		for (i = 0; i < want; ++i)
+			adapter->msix_info[i].vec = entries[i].vector;
+	} else if (err > 0) {
+		pci_disable_msix(adapter->pdev);
+		dev_info(adapter->pdev_dev, "only %d MSI-X vectors left,"
+			 " not using MSI-X\n", err);
+	}
+	return err;
+}
+
+#ifdef HAVE_NET_DEVICE_OPS
+static const struct net_device_ops cxgb4vf_netdev_ops	= {
+	.ndo_open		= cxgb4vf_open,
+	.ndo_stop		= cxgb4vf_stop,
+	.ndo_start_xmit		= t4vf_eth_xmit,
+	.ndo_get_stats		= cxgb4vf_get_stats,
+	.ndo_set_rx_mode	= cxgb4vf_set_rxmode,
+	.ndo_set_mac_address	= cxgb4vf_set_mac_addr,
+	.ndo_select_queue	= cxgb4vf_select_queue,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= cxgb4vf_do_ioctl,
+	.ndo_change_mtu		= cxgb4vf_change_mtu,
+	.ndo_vlan_rx_register	= cxgb4vf_vlan_rx_register,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= cxgb4vf_poll_controller,
+#endif
+};
+#endif
+
+/*
+ * "Probe" a device: initialize a device and construct all kernel and driver
+ * state needed to manage the device.  This routine is called "init_one" in
+ * the PF Driver ...
+ */
+static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
+				       const struct pci_device_id *ent)
+{
+	static int version_printed;
+
+	int pci_using_dac;
+	int err, pidx;
+	unsigned int pmask;
+	struct adapter *adapter;
+	struct port_info *pi;
+	struct net_device *netdev;
+
+	/*
+	 * Vet our module parameters.
+	 */
+	if (msi != MSI_MSIX && msi != MSI_MSI) {
+		dev_err(&pdev->dev, "bad module parameter msi=%d; must be %d"
+			" (MSI-X or MSI) or %d (MSI)\n", msi, MSI_MSIX,
+			MSI_MSI);
+		err = -EINVAL;
+		goto err_out;
+	}
+
+	/*
+	 * Print our driver banner the first time we're called to initialize a
+	 * device.
+	 */
+	if (version_printed == 0) {
+		printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
+		version_printed = 1;
+	}
+
+	/*
+	 * Reserve PCI resources for the device.  If we can't get them some
+	 * other driver may have already claimed the device ...
+	 */
+	err = pci_request_regions(pdev, KBUILD_MODNAME);
+	if (err) {
+		dev_err(&pdev->dev, "cannot obtain PCI resources\n");
+		return err;
+	}
+
+	/*
+	 * Initialize generic PCI device state.
+	 */
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "cannot enable PCI device\n");
+		goto err_release_regions;
+	}
+
+	/*
+	 * Set up our DMA mask: try for 64-bit address masking first and
+	 * fall back to 32-bit if we can't get 64 bits ...
+	 */
+	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+	if (err == 0) {
+		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+		if (err) {
+			dev_err(&pdev->dev, "unable to obtain 64-bit DMA for"
+				" coherent allocations\n");
+			goto err_disable_device;
+		}
+		pci_using_dac = 1;
+	} else {
+		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (err != 0) {
+			dev_err(&pdev->dev, "no usable DMA configuration\n");
+			goto err_disable_device;
+		}
+		pci_using_dac = 0;
+	}
+
+	/*
+	 * Enable bus mastering for the device ...
+	 */
+	pci_set_master(pdev);
+
+	/*
+	 * Allocate our adapter data structure and attach it to the device.
+	 */
+	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+	if (!adapter) {
+		err = -ENOMEM;
+		goto err_disable_device;
+	}
+	pci_set_drvdata(pdev, adapter);
+	adapter->pdev = pdev;
+	adapter->pdev_dev = &pdev->dev;
+
+	/*
+	 * Initialize SMP data synchronization resources.
+	 */
+	spin_lock_init(&adapter->stats_lock);
+
+	/*
+	 * Map our I/O registers in BAR0.
+	 */
+	adapter->regs = pci_ioremap_bar(pdev, 0);
+	if (!adapter->regs) {
+		dev_err(&pdev->dev, "cannot map device registers\n");
+		err = -ENOMEM;
+		goto err_free_adapter;
+	}
+
+	/*
+	 * Initialize adapter level features.
+	 */
+	adapter->name = pci_name(pdev);
+	adapter->msg_enable = dflt_msg_enable;
+	err = adap_init0(adapter);
+	if (err)
+		goto err_unmap_bar;
+
+	/*
+	 * Allocate our "adapter ports" and stitch everything together.
+	 */
+	pmask = adapter->params.vfres.pmask;
+	for_each_port(adapter, pidx) {
+		int port_id, viid;
+
+		/*
+		 * We simplistically allocate our virtual interfaces
+		 * sequentially across the port numbers to which we have
+		 * access rights.  This should be configurable in some manner
+		 * ...
+		 */
+		if (pmask == 0)
+			break;
+		port_id = ffs(pmask) - 1;
+		pmask &= ~(1 << port_id);
+		viid = t4vf_alloc_vi(adapter, port_id);
+		if (viid < 0) {
+			dev_err(&pdev->dev, "cannot allocate VI for port %d:"
+				" err=%d\n", port_id, viid);
+			err = viid;
+			goto err_free_dev;
+		}
+
+		/*
+		 * Allocate our network device and stitch things together.
+		 */
+		netdev = alloc_etherdev_mq(sizeof(struct port_info),
+					   MAX_PORT_QSETS);
+		if (netdev == NULL) {
+			dev_err(&pdev->dev, "cannot allocate netdev for"
+				" port %d\n", port_id);
+			t4vf_free_vi(adapter, viid);
+			err = -ENOMEM;
+			goto err_free_dev;
+		}
+		adapter->port[pidx] = netdev;
+		SET_NETDEV_DEV(netdev, &pdev->dev);
+		pi = netdev_priv(netdev);
+		pi->adapter = adapter;
+		pi->pidx = pidx;
+		pi->port_id = port_id;
+		pi->viid = viid;
+
+		/*
+		 * Initialize the starting state of our "port" and register
+		 * it.
+		 */
+		pi->xact_addr_filt = -1;
+		pi->rx_offload = RX_CSO;
+		netif_carrier_off(netdev);
+		netif_tx_stop_all_queues(netdev);
+		netdev->irq = pdev->irq;
+
+		netdev->features = (NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
+				    NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+				    NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+				    NETIF_F_GRO);
+		if (pci_using_dac)
+			netdev->features |= NETIF_F_HIGHDMA;
+		netdev->vlan_features =
+			(netdev->features &
+			 ~(NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX));
+
+#ifdef HAVE_NET_DEVICE_OPS
+		netdev->netdev_ops = &cxgb4vf_netdev_ops;
+#else
+		netdev->vlan_rx_register = cxgb4vf_vlan_rx_register;
+		netdev->open = cxgb4vf_open;
+		netdev->stop = cxgb4vf_stop;
+		netdev->hard_start_xmit = t4vf_eth_xmit;
+		netdev->get_stats = cxgb4vf_get_stats;
+		netdev->set_rx_mode = cxgb4vf_set_rxmode;
+		netdev->do_ioctl = cxgb4vf_do_ioctl;
+		netdev->change_mtu = cxgb4vf_change_mtu;
+		netdev->set_mac_address = cxgb4vf_set_mac_addr;
+		netdev->select_queue = cxgb4vf_select_queue;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+		netdev->poll_controller = cxgb4vf_poll_controller;
+#endif
+#endif
+		SET_ETHTOOL_OPS(netdev, &cxgb4vf_ethtool_ops);
+
+		/*
+		 * Initialize the hardware/software state for the port.
+		 */
+		err = t4vf_port_init(adapter, pidx);
+		if (err) {
+			dev_err(&pdev->dev, "cannot initialize port %d\n",
+				pidx);
+			goto err_free_dev;
+		}
+	}
+
+	/*
+	 * The "card" is now ready to go.  If any errors occur during device
+	 * registration we do not fail the whole "card" but rather proceed
+	 * only with the ports we manage to register successfully.  However we
+	 * must register at least one net device.
+	 */
+	for_each_port(adapter, pidx) {
+		netdev = adapter->port[pidx];
+		if (netdev == NULL)
+			continue;
+
+		err = register_netdev(netdev);
+		if (err) {
+			dev_warn(&pdev->dev, "cannot register net device %s,"
+				 " skipping\n", netdev->name);
+			continue;
+		}
+
+		set_bit(pidx, &adapter->registered_device_map);
+	}
+	if (adapter->registered_device_map == 0) {
+		dev_err(&pdev->dev, "could not register any net devices\n");
+		goto err_free_dev;
+	}
+
+	/*
+	 * Set up our debugfs entries.
+	 */
+	if (cxgb4vf_debugfs_root) {
+		adapter->debugfs_root =
+			debugfs_create_dir(pci_name(pdev),
+					   cxgb4vf_debugfs_root);
+		if (adapter->debugfs_root == NULL)
+			dev_warn(&pdev->dev, "could not create debugfs"
+				 " directory");
+		else
+			setup_debugfs(adapter);
+	}
+
+	/*
+	 * See what interrupts we'll be using.  If we've been configured to
+	 * use MSI-X interrupts, try to enable them but fall back to using
+	 * MSI interrupts if we can't enable MSI-X interrupts.  If we can't
+	 * get MSI interrupts we bail with the error.
+	 */
+	if (msi == MSI_MSIX && enable_msix(adapter) == 0)
+		adapter->flags |= USING_MSIX;
+	else {
+		err = pci_enable_msi(pdev);
+		if (err) {
+			dev_err(&pdev->dev, "Unable to allocate %s interrupts;"
+				" err=%d\n",
+				msi == MSI_MSIX ? "MSI-X or MSI" : "MSI", err);
+			goto err_free_debugfs;
+		}
+		adapter->flags |= USING_MSI;
+	}
+
+	/*
+	 * Now that we know how many "ports" we have and what their types are,
+	 * and how many Queue Sets we can support, we can configure our queue
+	 * resources.
+	 */
+	cfg_queues(adapter);
+
+	/*
+	 * Print a short notice on the existance and configuration of the new
+	 * VF network device ...
+	 */
+	for_each_port(adapter, pidx) {
+		dev_info(adapter->pdev_dev, "%s: Chelsio VF NIC PCIe %s\n",
+			 adapter->port[pidx]->name,
+			 (adapter->flags & USING_MSIX) ? "MSI-X" :
+			 (adapter->flags & USING_MSI)  ? "MSI" : "");
+	}
+
+	/*
+	 * Return success!
+	 */
+	return 0;
+
+	/*
+	 * Error recovery and exit code.  Unwind state that's been created
+	 * so far and return the error.
+	 */
+
+err_free_debugfs:
+	if (adapter->debugfs_root) {
+		cleanup_debugfs(adapter);
+		debugfs_remove_recursive(adapter->debugfs_root);
+	}
+
+err_free_dev:
+	for_each_port(adapter, pidx) {
+		netdev = adapter->port[pidx];
+		if (netdev == NULL)
+			continue;
+		pi = netdev_priv(netdev);
+		t4vf_free_vi(adapter, pi->viid);
+		if (test_bit(pidx, &adapter->registered_device_map))
+			unregister_netdev(netdev);
+		free_netdev(netdev);
+	}
+
+err_unmap_bar:
+	iounmap(adapter->regs);
+
+err_free_adapter:
+	kfree(adapter);
+	pci_set_drvdata(pdev, NULL);
+
+err_disable_device:
+	pci_disable_device(pdev);
+	pci_clear_master(pdev);
+
+err_release_regions:
+	pci_release_regions(pdev);
+	pci_set_drvdata(pdev, NULL);
+
+err_out:
+	return err;
+}
+
+/*
+ * "Remove" a device: tear down all kernel and driver state created in the
+ * "probe" routine and quiesce the device (disable interrupts, etc.).  (Note
+ * that this is called "remove_one" in the PF Driver.)
+ */
+static void __devexit cxgb4vf_pci_remove(struct pci_dev *pdev)
+{
+	struct adapter *adapter = pci_get_drvdata(pdev);
+
+	/*
+	 * Tear down driver state associated with device.
+	 */
+	if (adapter) {
+		int pidx;
+
+		/*
+		 * Stop all of our activity.  Unregister network port,
+		 * disable interrupts, etc.
+		 */
+		for_each_port(adapter, pidx)
+			if (test_bit(pidx, &adapter->registered_device_map))
+				unregister_netdev(adapter->port[pidx]);
+		t4vf_sge_stop(adapter);
+		if (adapter->flags & USING_MSIX) {
+			pci_disable_msix(adapter->pdev);
+			adapter->flags &= ~USING_MSIX;
+		} else if (adapter->flags & USING_MSI) {
+			pci_disable_msi(adapter->pdev);
+			adapter->flags &= ~USING_MSI;
+		}
+
+		/*
+		 * Tear down our debugfs entries.
+		 */
+		if (adapter->debugfs_root) {
+			cleanup_debugfs(adapter);
+			debugfs_remove_recursive(adapter->debugfs_root);
+		}
+
+		/*
+		 * Free all of the various resources which we've acquired ...
+		 */
+		t4vf_free_sge_resources(adapter);
+		for_each_port(adapter, pidx) {
+			struct net_device *netdev = adapter->port[pidx];
+			struct port_info *pi;
+
+			if (netdev == NULL)
+				continue;
+
+			pi = netdev_priv(netdev);
+			t4vf_free_vi(adapter, pi->viid);
+			free_netdev(netdev);
+		}
+		iounmap(adapter->regs);
+		kfree(adapter);
+		pci_set_drvdata(pdev, NULL);
+	}
+
+	/*
+	 * Disable the device and release its PCI resources.
+	 */
+	pci_disable_device(pdev);
+	pci_clear_master(pdev);
+	pci_release_regions(pdev);
+}
+
+/*
+ * PCI Device registration data structures.
+ */
+#define CH_DEVICE(devid, idx) \
+	{ PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx }
+
+static struct pci_device_id cxgb4vf_pci_tbl[] = {
+	CH_DEVICE(0xb000, 0),	/* PE10K FPGA */
+	CH_DEVICE(0x4800, 0),	/* T440-dbg */
+	CH_DEVICE(0x4801, 0),	/* T420-cr */
+	CH_DEVICE(0x4802, 0),	/* T422-cr */
+	{ 0, }
+};
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_AUTHOR("Chelsio Communications");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, cxgb4vf_pci_tbl);
+
+static struct pci_driver cxgb4vf_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= cxgb4vf_pci_tbl,
+	.probe		= cxgb4vf_pci_probe,
+	.remove		= __devexit_p(cxgb4vf_pci_remove),
+};
+
+/*
+ * Initialize global driver state.
+ */
+static int __init cxgb4vf_module_init(void)
+{
+	int ret;
+
+	/* Debugfs support is optional, just warn if this fails */
+	cxgb4vf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+	if (!cxgb4vf_debugfs_root)
+		printk(KERN_WARNING KBUILD_MODNAME ": could not create"
+		       " debugfs entry, continuing\n");
+
+	ret = pci_register_driver(&cxgb4vf_driver);
+	if (ret < 0)
+		debugfs_remove(cxgb4vf_debugfs_root);
+	return ret;
+}
+
+/*
+ * Tear down global driver state.
+ */
+static void __exit cxgb4vf_module_exit(void)
+{
+	pci_unregister_driver(&cxgb4vf_driver);
+	debugfs_remove(cxgb4vf_debugfs_root);
+}
+
+module_init(cxgb4vf_module_init);
+module_exit(cxgb4vf_module_exit);
diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c
new file mode 100644
index 0000000..eb5a1c9
--- /dev/null
+++ b/drivers/net/cxgb4vf/sge.c
@@ -0,0 +1,2454 @@
+/*
+ * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet
+ * driver for Linux.
+ *
+ * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <net/ipv6.h>
+#include <net/tcp.h>
+#include <linux/dma-mapping.h>
+
+#include "t4vf_common.h"
+#include "t4vf_defs.h"
+
+#include "../cxgb4/t4_regs.h"
+#include "../cxgb4/t4fw_api.h"
+#include "../cxgb4/t4_msg.h"
+
+/*
+ * Decoded Adapter Parameters.
+ */
+static u32 FL_PG_ORDER;		/* large page allocation size */
+static u32 STAT_LEN;		/* length of status page at ring end */
+static u32 PKTSHIFT;		/* padding between CPL and packet data */
+static u32 FL_ALIGN;		/* response queue message alignment */
+
+/*
+ * Constants ...
+ */
+enum {
+	/*
+	 * Egress Queue sizes, producer and consumer indices are all in units
+	 * of Egress Context Units bytes.  Note that as far as the hardware is
+	 * concerned, the free list is an Egress Queue (the host produces free
+	 * buffers which the hardware consumes) and free list entries are
+	 * 64-bit PCI DMA addresses.
+	 */
+	EQ_UNIT = SGE_EQ_IDXSIZE,
+	FL_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64),
+	TXD_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64),
+
+	/*
+	 * Max number of TX descriptors we clean up at a time.  Should be
+	 * modest as freeing skbs isn't cheap and it happens while holding
+	 * locks.  We just need to free packets faster than they arrive, we
+	 * eventually catch up and keep the amortized cost reasonable.
+	 */
+	MAX_TX_RECLAIM = 16,
+
+	/*
+	 * Max number of Rx buffers we replenish at a time.  Again keep this
+	 * modest, allocating buffers isn't cheap either.
+	 */
+	MAX_RX_REFILL = 16,
+
+	/*
+	 * Period of the Rx queue check timer.  This timer is infrequent as it
+	 * has something to do only when the system experiences severe memory
+	 * shortage.
+	 */
+	RX_QCHECK_PERIOD = (HZ / 2),
+
+	/*
+	 * Period of the TX queue check timer and the maximum number of TX
+	 * descriptors to be reclaimed by the TX timer.
+	 */
+	TX_QCHECK_PERIOD = (HZ / 2),
+	MAX_TIMER_TX_RECLAIM = 100,
+
+	/*
+	 * An FL with <= FL_STARVE_THRES buffers is starving and a periodic
+	 * timer will attempt to refill it.
+	 */
+	FL_STARVE_THRES = 4,
+
+	/*
+	 * Suspend an Ethernet TX queue with fewer available descriptors than
+	 * this.  We always want to have room for a maximum sized packet:
+	 * inline immediate data + MAX_SKB_FRAGS. This is the same as
+	 * calc_tx_flits() for a TSO packet with nr_frags == MAX_SKB_FRAGS
+	 * (see that function and its helpers for a description of the
+	 * calculation).
+	 */
+	ETHTXQ_MAX_FRAGS = MAX_SKB_FRAGS + 1,
+	ETHTXQ_MAX_SGL_LEN = ((3 * (ETHTXQ_MAX_FRAGS-1))/2 +
+				   ((ETHTXQ_MAX_FRAGS-1) & 1) +
+				   2),
+	ETHTXQ_MAX_HDR = (sizeof(struct fw_eth_tx_pkt_vm_wr) +
+			  sizeof(struct cpl_tx_pkt_lso_core) +
+			  sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64),
+	ETHTXQ_MAX_FLITS = ETHTXQ_MAX_SGL_LEN + ETHTXQ_MAX_HDR,
+
+	ETHTXQ_STOP_THRES = 1 + DIV_ROUND_UP(ETHTXQ_MAX_FLITS, TXD_PER_EQ_UNIT),
+
+	/*
+	 * Max TX descriptor space we allow for an Ethernet packet to be
+	 * inlined into a WR.  This is limited by the maximum value which
+	 * we can specify for immediate data in the firmware Ethernet TX
+	 * Work Request.
+	 */
+	MAX_IMM_TX_PKT_LEN = FW_WR_IMMDLEN_MASK,
+
+	/*
+	 * Max size of a WR sent through a control TX queue.
+	 */
+	MAX_CTRL_WR_LEN = 256,
+
+	/*
+	 * Maximum amount of data which we'll ever need to inline into a
+	 * TX ring: max(MAX_IMM_TX_PKT_LEN, MAX_CTRL_WR_LEN).
+	 */
+	MAX_IMM_TX_LEN = (MAX_IMM_TX_PKT_LEN > MAX_CTRL_WR_LEN
+			  ? MAX_IMM_TX_PKT_LEN
+			  : MAX_CTRL_WR_LEN),
+
+	/*
+	 * For incoming packets less than RX_COPY_THRES, we copy the data into
+	 * an skb rather than referencing the data.  We allocate enough
+	 * in-line room in skb's to accommodate pulling in RX_PULL_LEN bytes
+	 * of the data (header).
+	 */
+	RX_COPY_THRES = 256,
+	RX_PULL_LEN = 128,
+};
+
+/*
+ * Can't define this in the above enum because PKTSHIFT isn't a constant in
+ * the VF Driver ...
+ */
+#define RX_PKT_PULL_LEN (RX_PULL_LEN + PKTSHIFT)
+
+/*
+ * Software state per TX descriptor.
+ */
+struct tx_sw_desc {
+	struct sk_buff *skb;		/* socket buffer of TX data source */
+	struct ulptx_sgl *sgl;		/* scatter/gather list in TX Queue */
+};
+
+/*
+ * Software state per RX Free List descriptor.  We keep track of the allocated
+ * FL page, its size, and its PCI DMA address (if the page is mapped).  The FL
+ * page size and its PCI DMA mapped state are stored in the low bits of the
+ * PCI DMA address as per below.
+ */
+struct rx_sw_desc {
+	struct page *page;		/* Free List page buffer */
+	dma_addr_t dma_addr;		/* PCI DMA address (if mapped) */
+					/*   and flags (see below) */
+};
+
+/*
+ * The low bits of rx_sw_desc.dma_addr have special meaning.  Note that the
+ * SGE also uses the low 4 bits to determine the size of the buffer.  It uses
+ * those bits to index into the SGE_FL_BUFFER_SIZE[index] register array.
+ * Since we only use SGE_FL_BUFFER_SIZE0 and SGE_FL_BUFFER_SIZE1, these low 4
+ * bits can only contain a 0 or a 1 to indicate which size buffer we're giving
+ * to the SGE.  Thus, our software state of "is the buffer mapped for DMA" is
+ * maintained in an inverse sense so the hardware never sees that bit high.
+ */
+enum {
+	RX_LARGE_BUF    = 1 << 0,	/* buffer is SGE_FL_BUFFER_SIZE[1] */
+	RX_UNMAPPED_BUF = 1 << 1,	/* buffer is not mapped */
+};
+
+/**
+ *	get_buf_addr - return DMA buffer address of software descriptor
+ *	@sdesc: pointer to the software buffer descriptor
+ *
+ *	Return the DMA buffer address of a software descriptor (stripping out
+ *	our low-order flag bits).
+ */
+static inline dma_addr_t get_buf_addr(const struct rx_sw_desc *sdesc)
+{
+	return sdesc->dma_addr & ~(dma_addr_t)(RX_LARGE_BUF | RX_UNMAPPED_BUF);
+}
+
+/**
+ *	is_buf_mapped - is buffer mapped for DMA?
+ *	@sdesc: pointer to the software buffer descriptor
+ *
+ *	Determine whether the buffer associated with a software descriptor in
+ *	mapped for DMA or not.
+ */
+static inline bool is_buf_mapped(const struct rx_sw_desc *sdesc)
+{
+	return !(sdesc->dma_addr & RX_UNMAPPED_BUF);
+}
+
+/**
+ *	need_skb_unmap - does the platform need unmapping of sk_buffs?
+ *
+ *	Returns true if the platfrom needs sk_buff unmapping.  The compiler
+ *	optimizes away unecessary code if this returns true.
+ */
+static inline int need_skb_unmap(void)
+{
+#ifdef CONFIG_NEED_DMA_MAP_STATE
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+/**
+ *	txq_avail - return the number of available slots in a TX queue
+ *	@tq: the TX queue
+ *
+ *	Returns the number of available descriptors in a TX queue.
+ */
+static inline unsigned int txq_avail(const struct sge_txq *tq)
+{
+	return tq->size - 1 - tq->in_use;
+}
+
+/**
+ *	fl_cap - return the capacity of a Free List
+ *	@fl: the Free List
+ *
+ *	Returns the capacity of a Free List.  The capacity is less than the
+ *	size because an Egress Queue Index Unit worth of descriptors needs to
+ *	be left unpopulated, otherwise the Producer and Consumer indices PIDX
+ *	and CIDX will match and the hardware will think the FL is empty.
+ */
+static inline unsigned int fl_cap(const struct sge_fl *fl)
+{
+	return fl->size - FL_PER_EQ_UNIT;
+}
+
+/**
+ *	fl_starving - return whether a Free List is starving.
+ *	@fl: the Free List
+ *
+ *	Tests specified Free List to see whether the number of buffers
+ *	available to the hardware has falled below our "starvation"
+ *	threshhold.
+ */
+static inline bool fl_starving(const struct sge_fl *fl)
+{
+	return fl->avail - fl->pend_cred <= FL_STARVE_THRES;
+}
+
+/**
+ *	map_skb -  map an skb for DMA to the device
+ *	@dev: the egress net device
+ *	@skb: the packet to map
+ *	@addr: a pointer to the base of the DMA mapping array
+ *
+ *	Map an skb for DMA to the device and return an array of DMA addresses.
+ */
+static int map_skb(struct device *dev, const struct sk_buff *skb,
+		   dma_addr_t *addr)
+{
+	const skb_frag_t *fp, *end;
+	const struct skb_shared_info *si;
+
+	*addr = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
+	if (dma_mapping_error(dev, *addr))
+		goto out_err;
+
+	si = skb_shinfo(skb);
+	end = &si->frags[si->nr_frags];
+	for (fp = si->frags; fp < end; fp++) {
+		*++addr = dma_map_page(dev, fp->page, fp->page_offset, fp->size,
+				       DMA_TO_DEVICE);
+		if (dma_mapping_error(dev, *addr))
+			goto unwind;
+	}
+	return 0;
+
+unwind:
+	while (fp-- > si->frags)
+		dma_unmap_page(dev, *--addr, fp->size, DMA_TO_DEVICE);
+	dma_unmap_single(dev, addr[-1], skb_headlen(skb), DMA_TO_DEVICE);
+
+out_err:
+	return -ENOMEM;
+}
+
+static void unmap_sgl(struct device *dev, const struct sk_buff *skb,
+		      const struct ulptx_sgl *sgl, const struct sge_txq *tq)
+{
+	const struct ulptx_sge_pair *p;
+	unsigned int nfrags = skb_shinfo(skb)->nr_frags;
+
+	if (likely(skb_headlen(skb)))
+		dma_unmap_single(dev, be64_to_cpu(sgl->addr0),
+				 be32_to_cpu(sgl->len0), DMA_TO_DEVICE);
+	else {
+		dma_unmap_page(dev, be64_to_cpu(sgl->addr0),
+			       be32_to_cpu(sgl->len0), DMA_TO_DEVICE);
+		nfrags--;
+	}
+
+	/*
+	 * the complexity below is because of the possibility of a wrap-around
+	 * in the middle of an SGL
+	 */
+	for (p = sgl->sge; nfrags >= 2; nfrags -= 2) {
+		if (likely((u8 *)(p + 1) <= (u8 *)tq->stat)) {
+unmap:
+			dma_unmap_page(dev, be64_to_cpu(p->addr[0]),
+				       be32_to_cpu(p->len[0]), DMA_TO_DEVICE);
+			dma_unmap_page(dev, be64_to_cpu(p->addr[1]),
+				       be32_to_cpu(p->len[1]), DMA_TO_DEVICE);
+			p++;
+		} else if ((u8 *)p == (u8 *)tq->stat) {
+			p = (const struct ulptx_sge_pair *)tq->desc;
+			goto unmap;
+		} else if ((u8 *)p + 8 == (u8 *)tq->stat) {
+			const __be64 *addr = (const __be64 *)tq->desc;
+
+			dma_unmap_page(dev, be64_to_cpu(addr[0]),
+				       be32_to_cpu(p->len[0]), DMA_TO_DEVICE);
+			dma_unmap_page(dev, be64_to_cpu(addr[1]),
+				       be32_to_cpu(p->len[1]), DMA_TO_DEVICE);
+			p = (const struct ulptx_sge_pair *)&addr[2];
+		} else {
+			const __be64 *addr = (const __be64 *)tq->desc;
+
+			dma_unmap_page(dev, be64_to_cpu(p->addr[0]),
+				       be32_to_cpu(p->len[0]), DMA_TO_DEVICE);
+			dma_unmap_page(dev, be64_to_cpu(addr[0]),
+				       be32_to_cpu(p->len[1]), DMA_TO_DEVICE);
+			p = (const struct ulptx_sge_pair *)&addr[1];
+		}
+	}
+	if (nfrags) {
+		__be64 addr;
+
+		if ((u8 *)p == (u8 *)tq->stat)
+			p = (const struct ulptx_sge_pair *)tq->desc;
+		addr = ((u8 *)p + 16 <= (u8 *)tq->stat
+			? p->addr[0]
+			: *(const __be64 *)tq->desc);
+		dma_unmap_page(dev, be64_to_cpu(addr), be32_to_cpu(p->len[0]),
+			       DMA_TO_DEVICE);
+	}
+}
+
+/**
+ *	free_tx_desc - reclaims TX descriptors and their buffers
+ *	@adapter: the adapter
+ *	@tq: the TX queue to reclaim descriptors from
+ *	@n: the number of descriptors to reclaim
+ *	@unmap: whether the buffers should be unmapped for DMA
+ *
+ *	Reclaims TX descriptors from an SGE TX queue and frees the associated
+ *	TX buffers.  Called with the TX queue lock held.
+ */
+static void free_tx_desc(struct adapter *adapter, struct sge_txq *tq,
+			 unsigned int n, bool unmap)
+{
+	struct tx_sw_desc *sdesc;
+	unsigned int cidx = tq->cidx;
+	struct device *dev = adapter->pdev_dev;
+
+	const int need_unmap = need_skb_unmap() && unmap;
+
+	sdesc = &tq->sdesc[cidx];
+	while (n--) {
+		/*
+		 * If we kept a reference to the original TX skb, we need to
+		 * unmap it from PCI DMA space (if required) and free it.
+		 */
+		if (sdesc->skb) {
+			if (need_unmap)
+				unmap_sgl(dev, sdesc->skb, sdesc->sgl, tq);
+			kfree_skb(sdesc->skb);
+			sdesc->skb = NULL;
+		}
+
+		sdesc++;
+		if (++cidx == tq->size) {
+			cidx = 0;
+			sdesc = tq->sdesc;
+		}
+	}
+	tq->cidx = cidx;
+}
+
+/*
+ * Return the number of reclaimable descriptors in a TX queue.
+ */
+static inline int reclaimable(const struct sge_txq *tq)
+{
+	int hw_cidx = be16_to_cpu(tq->stat->cidx);
+	int reclaimable = hw_cidx - tq->cidx;
+	if (reclaimable < 0)
+		reclaimable += tq->size;
+	return reclaimable;
+}
+
+/**
+ *	reclaim_completed_tx - reclaims completed TX descriptors
+ *	@adapter: the adapter
+ *	@tq: the TX queue to reclaim completed descriptors from
+ *	@unmap: whether the buffers should be unmapped for DMA
+ *
+ *	Reclaims TX descriptors that the SGE has indicated it has processed,
+ *	and frees the associated buffers if possible.  Called with the TX
+ *	queue locked.
+ */
+static inline void reclaim_completed_tx(struct adapter *adapter,
+					struct sge_txq *tq,
+					bool unmap)
+{
+	int avail = reclaimable(tq);
+
+	if (avail) {
+		/*
+		 * Limit the amount of clean up work we do at a time to keep
+		 * the TX lock hold time O(1).
+		 */
+		if (avail > MAX_TX_RECLAIM)
+			avail = MAX_TX_RECLAIM;
+
+		free_tx_desc(adapter, tq, avail, unmap);
+		tq->in_use -= avail;
+	}
+}
+
+/**
+ *	get_buf_size - return the size of an RX Free List buffer.
+ *	@sdesc: pointer to the software buffer descriptor
+ */
+static inline int get_buf_size(const struct rx_sw_desc *sdesc)
+{
+	return FL_PG_ORDER > 0 && (sdesc->dma_addr & RX_LARGE_BUF)
+		? (PAGE_SIZE << FL_PG_ORDER)
+		: PAGE_SIZE;
+}
+
+/**
+ *	free_rx_bufs - free RX buffers on an SGE Free List
+ *	@adapter: the adapter
+ *	@fl: the SGE Free List to free buffers from
+ *	@n: how many buffers to free
+ *
+ *	Release the next @n buffers on an SGE Free List RX queue.   The
+ *	buffers must be made inaccessible to hardware before calling this
+ *	function.
+ */
+static void free_rx_bufs(struct adapter *adapter, struct sge_fl *fl, int n)
+{
+	while (n--) {
+		struct rx_sw_desc *sdesc = &fl->sdesc[fl->cidx];
+
+		if (is_buf_mapped(sdesc))
+			dma_unmap_page(adapter->pdev_dev, get_buf_addr(sdesc),
+				       get_buf_size(sdesc), PCI_DMA_FROMDEVICE);
+		put_page(sdesc->page);
+		sdesc->page = NULL;
+		if (++fl->cidx == fl->size)
+			fl->cidx = 0;
+		fl->avail--;
+	}
+}
+
+/**
+ *	unmap_rx_buf - unmap the current RX buffer on an SGE Free List
+ *	@adapter: the adapter
+ *	@fl: the SGE Free List
+ *
+ *	Unmap the current buffer on an SGE Free List RX queue.   The
+ *	buffer must be made inaccessible to HW before calling this function.
+ *
+ *	This is similar to @free_rx_bufs above but does not free the buffer.
+ *	Do note that the FL still loses any further access to the buffer.
+ *	This is used predominantly to "transfer ownership" of an FL buffer
+ *	to another entity (typically an skb's fragment list).
+ */
+static void unmap_rx_buf(struct adapter *adapter, struct sge_fl *fl)
+{
+	struct rx_sw_desc *sdesc = &fl->sdesc[fl->cidx];
+
+	if (is_buf_mapped(sdesc))
+		dma_unmap_page(adapter->pdev_dev, get_buf_addr(sdesc),
+			       get_buf_size(sdesc), PCI_DMA_FROMDEVICE);
+	sdesc->page = NULL;
+	if (++fl->cidx == fl->size)
+		fl->cidx = 0;
+	fl->avail--;
+}
+
+/**
+ *	ring_fl_db - righ doorbell on free list
+ *	@adapter: the adapter
+ *	@fl: the Free List whose doorbell should be rung ...
+ *
+ *	Tell the Scatter Gather Engine that there are new free list entries
+ *	available.
+ */
+static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl)
+{
+	/*
+	 * The SGE keeps track of its Producer and Consumer Indices in terms
+	 * of Egress Queue Units so we can only tell it about integral numbers
+	 * of multiples of Free List Entries per Egress Queue Units ...
+	 */
+	if (fl->pend_cred >= FL_PER_EQ_UNIT) {
+		wmb();
+		t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL,
+			     DBPRIO |
+			     QID(fl->cntxt_id) |
+			     PIDX(fl->pend_cred / FL_PER_EQ_UNIT));
+		fl->pend_cred %= FL_PER_EQ_UNIT;
+	}
+}
+
+/**
+ *	set_rx_sw_desc - initialize software RX buffer descriptor
+ *	@sdesc: pointer to the softwore RX buffer descriptor
+ *	@page: pointer to the page data structure backing the RX buffer
+ *	@dma_addr: PCI DMA address (possibly with low-bit flags)
+ */
+static inline void set_rx_sw_desc(struct rx_sw_desc *sdesc, struct page *page,
+				  dma_addr_t dma_addr)
+{
+	sdesc->page = page;
+	sdesc->dma_addr = dma_addr;
+}
+
+/*
+ * Support for poisoning RX buffers ...
+ */
+#define POISON_BUF_VAL -1
+
+static inline void poison_buf(struct page *page, size_t sz)
+{
+#if POISON_BUF_VAL >= 0
+	memset(page_address(page), POISON_BUF_VAL, sz);
+#endif
+}
+
+/**
+ *	refill_fl - refill an SGE RX buffer ring
+ *	@adapter: the adapter
+ *	@fl: the Free List ring to refill
+ *	@n: the number of new buffers to allocate
+ *	@gfp: the gfp flags for the allocations
+ *
+ *	(Re)populate an SGE free-buffer queue with up to @n new packet buffers,
+ *	allocated with the supplied gfp flags.  The caller must assure that
+ *	@n does not exceed the queue's capacity -- i.e. (cidx == pidx) _IN
+ *	EGRESS QUEUE UNITS_ indicates an empty Free List!  Returns the number
+ *	of buffers allocated.  If afterwards the queue is found critically low,
+ *	mark it as starving in the bitmap of starving FLs.
+ */
+static unsigned int refill_fl(struct adapter *adapter, struct sge_fl *fl,
+			      int n, gfp_t gfp)
+{
+	struct page *page;
+	dma_addr_t dma_addr;
+	unsigned int cred = fl->avail;
+	__be64 *d = &fl->desc[fl->pidx];
+	struct rx_sw_desc *sdesc = &fl->sdesc[fl->pidx];
+
+	/*
+	 * Sanity: ensure that the result of adding n Free List buffers
+	 * won't result in wrapping the SGE's Producer Index around to
+	 * it's Consumer Index thereby indicating an empty Free List ...
+	 */
+	BUG_ON(fl->avail + n > fl->size - FL_PER_EQ_UNIT);
+
+	/*
+	 * If we support large pages, prefer large buffers and fail over to
+	 * small pages if we can't allocate large pages to satisfy the refill.
+	 * If we don't support large pages, drop directly into the small page
+	 * allocation code.
+	 */
+	if (FL_PG_ORDER == 0)
+		goto alloc_small_pages;
+
+	while (n) {
+		page = alloc_pages(gfp | __GFP_COMP | __GFP_NOWARN,
+				   FL_PG_ORDER);
+		if (unlikely(!page)) {
+			/*
+			 * We've failed inour attempt to allocate a "large
+			 * page".  Fail over to the "small page" allocation
+			 * below.
+			 */
+			fl->large_alloc_failed++;
+			break;
+		}
+		poison_buf(page, PAGE_SIZE << FL_PG_ORDER);
+
+		dma_addr = dma_map_page(adapter->pdev_dev, page, 0,
+					PAGE_SIZE << FL_PG_ORDER,
+					PCI_DMA_FROMDEVICE);
+		if (unlikely(dma_mapping_error(adapter->pdev_dev, dma_addr))) {
+			/*
+			 * We've run out of DMA mapping space.  Free up the
+			 * buffer and return with what we've managed to put
+			 * into the free list.  We don't want to fail over to
+			 * the small page allocation below in this case
+			 * because DMA mapping resources are typically
+			 * critical resources once they become scarse.
+			 */
+			__free_pages(page, FL_PG_ORDER);
+			goto out;
+		}
+		dma_addr |= RX_LARGE_BUF;
+		*d++ = cpu_to_be64(dma_addr);
+
+		set_rx_sw_desc(sdesc, page, dma_addr);
+		sdesc++;
+
+		fl->avail++;
+		if (++fl->pidx == fl->size) {
+			fl->pidx = 0;
+			sdesc = fl->sdesc;
+			d = fl->desc;
+		}
+		n--;
+	}
+
+alloc_small_pages:
+	while (n--) {
+		page = __netdev_alloc_page(adapter->port[0],
+					   gfp | __GFP_NOWARN);
+		if (unlikely(!page)) {
+			fl->alloc_failed++;
+			break;
+		}
+		poison_buf(page, PAGE_SIZE);
+
+		dma_addr = dma_map_page(adapter->pdev_dev, page, 0, PAGE_SIZE,
+				       PCI_DMA_FROMDEVICE);
+		if (unlikely(dma_mapping_error(adapter->pdev_dev, dma_addr))) {
+			netdev_free_page(adapter->port[0], page);
+			break;
+		}
+		*d++ = cpu_to_be64(dma_addr);
+
+		set_rx_sw_desc(sdesc, page, dma_addr);
+		sdesc++;
+
+		fl->avail++;
+		if (++fl->pidx == fl->size) {
+			fl->pidx = 0;
+			sdesc = fl->sdesc;
+			d = fl->desc;
+		}
+	}
+
+out:
+	/*
+	 * Update our accounting state to incorporate the new Free List
+	 * buffers, tell the hardware about them and return the number of
+	 * bufers which we were able to allocate.
+	 */
+	cred = fl->avail - cred;
+	fl->pend_cred += cred;
+	ring_fl_db(adapter, fl);
+
+	if (unlikely(fl_starving(fl))) {
+		smp_wmb();
+		set_bit(fl->cntxt_id, adapter->sge.starving_fl);
+	}
+
+	return cred;
+}
+
+/*
+ * Refill a Free List to its capacity or the Maximum Refill Increment,
+ * whichever is smaller ...
+ */
+static inline void __refill_fl(struct adapter *adapter, struct sge_fl *fl)
+{
+	refill_fl(adapter, fl,
+		  min((unsigned int)MAX_RX_REFILL, fl_cap(fl) - fl->avail),
+		  GFP_ATOMIC);
+}
+
+/**
+ *	alloc_ring - allocate resources for an SGE descriptor ring
+ *	@dev: the PCI device's core device
+ *	@nelem: the number of descriptors
+ *	@hwsize: the size of each hardware descriptor
+ *	@swsize: the size of each software descriptor
+ *	@busaddrp: the physical PCI bus address of the allocated ring
+ *	@swringp: return address pointer for software ring
+ *	@stat_size: extra space in hardware ring for status information
+ *
+ *	Allocates resources for an SGE descriptor ring, such as TX queues,
+ *	free buffer lists, response queues, etc.  Each SGE ring requires
+ *	space for its hardware descriptors plus, optionally, space for software
+ *	state associated with each hardware entry (the metadata).  The function
+ *	returns three values: the virtual address for the hardware ring (the
+ *	return value of the function), the PCI bus address of the hardware
+ *	ring (in *busaddrp), and the address of the software ring (in swringp).
+ *	Both the hardware and software rings are returned zeroed out.
+ */
+static void *alloc_ring(struct device *dev, size_t nelem, size_t hwsize,
+			size_t swsize, dma_addr_t *busaddrp, void *swringp,
+			size_t stat_size)
+{
+	/*
+	 * Allocate the hardware ring and PCI DMA bus address space for said.
+	 */
+	size_t hwlen = nelem * hwsize + stat_size;
+	void *hwring = dma_alloc_coherent(dev, hwlen, busaddrp, GFP_KERNEL);
+
+	if (!hwring)
+		return NULL;
+
+	/*
+	 * If the caller wants a software ring, allocate it and return a
+	 * pointer to it in *swringp.
+	 */
+	BUG_ON((swsize != 0) != (swringp != NULL));
+	if (swsize) {
+		void *swring = kcalloc(nelem, swsize, GFP_KERNEL);
+
+		if (!swring) {
+			dma_free_coherent(dev, hwlen, hwring, *busaddrp);
+			return NULL;
+		}
+		*(void **)swringp = swring;
+	}
+
+	/*
+	 * Zero out the hardware ring and return its address as our function
+	 * value.
+	 */
+	memset(hwring, 0, hwlen);
+	return hwring;
+}
+
+/**
+ *	sgl_len - calculates the size of an SGL of the given capacity
+ *	@n: the number of SGL entries
+ *
+ *	Calculates the number of flits (8-byte units) needed for a Direct
+ *	Scatter/Gather List that can hold the given number of entries.
+ */
+static inline unsigned int sgl_len(unsigned int n)
+{
+	/*
+	 * A Direct Scatter Gather List uses 32-bit lengths and 64-bit PCI DMA
+	 * addresses.  The DSGL Work Request starts off with a 32-bit DSGL
+	 * ULPTX header, then Length0, then Address0, then, for 1 <= i <= N,
+	 * repeated sequences of { Length[i], Length[i+1], Address[i],
+	 * Address[i+1] } (this ensures that all addresses are on 64-bit
+	 * boundaries).  If N is even, then Length[N+1] should be set to 0 and
+	 * Address[N+1] is omitted.
+	 *
+	 * The following calculation incorporates all of the above.  It's
+	 * somewhat hard to follow but, briefly: the "+2" accounts for the
+	 * first two flits which include the DSGL header, Length0 and
+	 * Address0; the "(3*(n-1))/2" covers the main body of list entries (3
+	 * flits for every pair of the remaining N) +1 if (n-1) is odd; and
+	 * finally the "+((n-1)&1)" adds the one remaining flit needed if
+	 * (n-1) is odd ...
+	 */
+	n--;
+	return (3 * n) / 2 + (n & 1) + 2;
+}
+
+/**
+ *	flits_to_desc - returns the num of TX descriptors for the given flits
+ *	@flits: the number of flits
+ *
+ *	Returns the number of TX descriptors needed for the supplied number
+ *	of flits.
+ */
+static inline unsigned int flits_to_desc(unsigned int flits)
+{
+	BUG_ON(flits > SGE_MAX_WR_LEN / sizeof(__be64));
+	return DIV_ROUND_UP(flits, TXD_PER_EQ_UNIT);
+}
+
+/**
+ *	is_eth_imm - can an Ethernet packet be sent as immediate data?
+ *	@skb: the packet
+ *
+ *	Returns whether an Ethernet packet is small enough to fit completely as
+ *	immediate data.
+ */
+static inline int is_eth_imm(const struct sk_buff *skb)
+{
+	/*
+	 * The VF Driver uses the FW_ETH_TX_PKT_VM_WR firmware Work Request
+	 * which does not accommodate immediate data.  We could dike out all
+	 * of the support code for immediate data but that would tie our hands
+	 * too much if we ever want to enhace the firmware.  It would also
+	 * create more differences between the PF and VF Drivers.
+	 */
+	return false;
+}
+
+/**
+ *	calc_tx_flits - calculate the number of flits for a packet TX WR
+ *	@skb: the packet
+ *
+ *	Returns the number of flits needed for a TX Work Request for the
+ *	given Ethernet packet, including the needed WR and CPL headers.
+ */
+static inline unsigned int calc_tx_flits(const struct sk_buff *skb)
+{
+	unsigned int flits;
+
+	/*
+	 * If the skb is small enough, we can pump it out as a work request
+	 * with only immediate data.  In that case we just have to have the
+	 * TX Packet header plus the skb data in the Work Request.
+	 */
+	if (is_eth_imm(skb))
+		return DIV_ROUND_UP(skb->len + sizeof(struct cpl_tx_pkt),
+				    sizeof(__be64));
+
+	/*
+	 * Otherwise, we're going to have to construct a Scatter gather list
+	 * of the skb body and fragments.  We also include the flits necessary
+	 * for the TX Packet Work Request and CPL.  We always have a firmware
+	 * Write Header (incorporated as part of the cpl_tx_pkt_lso and
+	 * cpl_tx_pkt structures), followed by either a TX Packet Write CPL
+	 * message or, if we're doing a Large Send Offload, an LSO CPL message
+	 * with an embeded TX Packet Write CPL message.
+	 */
+	flits = sgl_len(skb_shinfo(skb)->nr_frags + 1);
+	if (skb_shinfo(skb)->gso_size)
+		flits += (sizeof(struct fw_eth_tx_pkt_vm_wr) +
+			  sizeof(struct cpl_tx_pkt_lso_core) +
+			  sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64);
+	else
+		flits += (sizeof(struct fw_eth_tx_pkt_vm_wr) +
+			  sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64);
+	return flits;
+}
+
+/**
+ *	write_sgl - populate a Scatter/Gather List for a packet
+ *	@skb: the packet
+ *	@tq: the TX queue we are writing into
+ *	@sgl: starting location for writing the SGL
+ *	@end: points right after the end of the SGL
+ *	@start: start offset into skb main-body data to include in the SGL
+ *	@addr: the list of DMA bus addresses for the SGL elements
+ *
+ *	Generates a Scatter/Gather List for the buffers that make up a packet.
+ *	The caller must provide adequate space for the SGL that will be written.
+ *	The SGL includes all of the packet's page fragments and the data in its
+ *	main body except for the first @start bytes.  @pos must be 16-byte
+ *	aligned and within a TX descriptor with available space.  @end points
+ *	write after the end of the SGL but does not account for any potential
+ *	wrap around, i.e., @end > @tq->stat.
+ */
+static void write_sgl(const struct sk_buff *skb, struct sge_txq *tq,
+		      struct ulptx_sgl *sgl, u64 *end, unsigned int start,
+		      const dma_addr_t *addr)
+{
+	unsigned int i, len;
+	struct ulptx_sge_pair *to;
+	const struct skb_shared_info *si = skb_shinfo(skb);
+	unsigned int nfrags = si->nr_frags;
+	struct ulptx_sge_pair buf[MAX_SKB_FRAGS / 2 + 1];
+
+	len = skb_headlen(skb) - start;
+	if (likely(len)) {
+		sgl->len0 = htonl(len);
+		sgl->addr0 = cpu_to_be64(addr[0] + start);
+		nfrags++;
+	} else {
+		sgl->len0 = htonl(si->frags[0].size);
+		sgl->addr0 = cpu_to_be64(addr[1]);
+	}
+
+	sgl->cmd_nsge = htonl(ULPTX_CMD(ULP_TX_SC_DSGL) |
+			      ULPTX_NSGE(nfrags));
+	if (likely(--nfrags == 0))
+		return;
+	/*
+	 * Most of the complexity below deals with the possibility we hit the
+	 * end of the queue in the middle of writing the SGL.  For this case
+	 * only we create the SGL in a temporary buffer and then copy it.
+	 */
+	to = (u8 *)end > (u8 *)tq->stat ? buf : sgl->sge;
+
+	for (i = (nfrags != si->nr_frags); nfrags >= 2; nfrags -= 2, to++) {
+		to->len[0] = cpu_to_be32(si->frags[i].size);
+		to->len[1] = cpu_to_be32(si->frags[++i].size);
+		to->addr[0] = cpu_to_be64(addr[i]);
+		to->addr[1] = cpu_to_be64(addr[++i]);
+	}
+	if (nfrags) {
+		to->len[0] = cpu_to_be32(si->frags[i].size);
+		to->len[1] = cpu_to_be32(0);
+		to->addr[0] = cpu_to_be64(addr[i + 1]);
+	}
+	if (unlikely((u8 *)end > (u8 *)tq->stat)) {
+		unsigned int part0 = (u8 *)tq->stat - (u8 *)sgl->sge, part1;
+
+		if (likely(part0))
+			memcpy(sgl->sge, buf, part0);
+		part1 = (u8 *)end - (u8 *)tq->stat;
+		memcpy(tq->desc, (u8 *)buf + part0, part1);
+		end = (void *)tq->desc + part1;
+	}
+	if ((uintptr_t)end & 8)           /* 0-pad to multiple of 16 */
+		*(u64 *)end = 0;
+}
+
+/**
+ *	check_ring_tx_db - check and potentially ring a TX queue's doorbell
+ *	@adapter: the adapter
+ *	@tq: the TX queue
+ *	@n: number of new descriptors to give to HW
+ *
+ *	Ring the doorbel for a TX queue.
+ */
+static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq,
+			      int n)
+{
+	/*
+	 * Warn if we write doorbells with the wrong priority and write
+	 * descriptors before telling HW.
+	 */
+	WARN_ON((QID(tq->cntxt_id) | PIDX(n)) & DBPRIO);
+	wmb();
+	t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL,
+		     QID(tq->cntxt_id) | PIDX(n));
+}
+
+/**
+ *	inline_tx_skb - inline a packet's data into TX descriptors
+ *	@skb: the packet
+ *	@tq: the TX queue where the packet will be inlined
+ *	@pos: starting position in the TX queue to inline the packet
+ *
+ *	Inline a packet's contents directly into TX descriptors, starting at
+ *	the given position within the TX DMA ring.
+ *	Most of the complexity of this operation is dealing with wrap arounds
+ *	in the middle of the packet we want to inline.
+ */
+static void inline_tx_skb(const struct sk_buff *skb, const struct sge_txq *tq,
+			  void *pos)
+{
+	u64 *p;
+	int left = (void *)tq->stat - pos;
+
+	if (likely(skb->len <= left)) {
+		if (likely(!skb->data_len))
+			skb_copy_from_linear_data(skb, pos, skb->len);
+		else
+			skb_copy_bits(skb, 0, pos, skb->len);
+		pos += skb->len;
+	} else {
+		skb_copy_bits(skb, 0, pos, left);
+		skb_copy_bits(skb, left, tq->desc, skb->len - left);
+		pos = (void *)tq->desc + (skb->len - left);
+	}
+
+	/* 0-pad to multiple of 16 */
+	p = PTR_ALIGN(pos, 8);
+	if ((uintptr_t)p & 8)
+		*p = 0;
+}
+
+/*
+ * Figure out what HW csum a packet wants and return the appropriate control
+ * bits.
+ */
+static u64 hwcsum(const struct sk_buff *skb)
+{
+	int csum_type;
+	const struct iphdr *iph = ip_hdr(skb);
+
+	if (iph->version == 4) {
+		if (iph->protocol == IPPROTO_TCP)
+			csum_type = TX_CSUM_TCPIP;
+		else if (iph->protocol == IPPROTO_UDP)
+			csum_type = TX_CSUM_UDPIP;
+		else {
+nocsum:
+			/*
+			 * unknown protocol, disable HW csum
+			 * and hope a bad packet is detected
+			 */
+			return TXPKT_L4CSUM_DIS;
+		}
+	} else {
+		/*
+		 * this doesn't work with extension headers
+		 */
+		const struct ipv6hdr *ip6h = (const struct ipv6hdr *)iph;
+
+		if (ip6h->nexthdr == IPPROTO_TCP)
+			csum_type = TX_CSUM_TCPIP6;
+		else if (ip6h->nexthdr == IPPROTO_UDP)
+			csum_type = TX_CSUM_UDPIP6;
+		else
+			goto nocsum;
+	}
+
+	if (likely(csum_type >= TX_CSUM_TCPIP))
+		return TXPKT_CSUM_TYPE(csum_type) |
+			TXPKT_IPHDR_LEN(skb_network_header_len(skb)) |
+			TXPKT_ETHHDR_LEN(skb_network_offset(skb) - ETH_HLEN);
+	else {
+		int start = skb_transport_offset(skb);
+
+		return TXPKT_CSUM_TYPE(csum_type) |
+			TXPKT_CSUM_START(start) |
+			TXPKT_CSUM_LOC(start + skb->csum_offset);
+	}
+}
+
+/*
+ * Stop an Ethernet TX queue and record that state change.
+ */
+static void txq_stop(struct sge_eth_txq *txq)
+{
+	netif_tx_stop_queue(txq->txq);
+	txq->q.stops++;
+}
+
+/*
+ * Advance our software state for a TX queue by adding n in use descriptors.
+ */
+static inline void txq_advance(struct sge_txq *tq, unsigned int n)
+{
+	tq->in_use += n;
+	tq->pidx += n;
+	if (tq->pidx >= tq->size)
+		tq->pidx -= tq->size;
+}
+
+/**
+ *	t4vf_eth_xmit - add a packet to an Ethernet TX queue
+ *	@skb: the packet
+ *	@dev: the egress net device
+ *
+ *	Add a packet to an SGE Ethernet TX queue.  Runs with softirqs disabled.
+ */
+int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	u32 wr_mid;
+	u64 cntrl, *end;
+	int qidx, credits;
+	unsigned int flits, ndesc;
+	struct adapter *adapter;
+	struct sge_eth_txq *txq;
+	const struct port_info *pi;
+	struct fw_eth_tx_pkt_vm_wr *wr;
+	struct cpl_tx_pkt_core *cpl;
+	const struct skb_shared_info *ssi;
+	dma_addr_t addr[MAX_SKB_FRAGS + 1];
+	const size_t fw_hdr_copy_len = (sizeof(wr->ethmacdst) +
+					sizeof(wr->ethmacsrc) +
+					sizeof(wr->ethtype) +
+					sizeof(wr->vlantci));
+
+	/*
+	 * The chip minimum packet length is 10 octets but the firmware
+	 * command that we are using requires that we copy the Ethernet header
+	 * (including the VLAN tag) into the header so we reject anything
+	 * smaller than that ...
+	 */
+	if (unlikely(skb->len < fw_hdr_copy_len))
+		goto out_free;
+
+	/*
+	 * Figure out which TX Queue we're going to use.
+	 */
+	pi = netdev_priv(dev);
+	adapter = pi->adapter;
+	qidx = skb_get_queue_mapping(skb);
+	BUG_ON(qidx >= pi->nqsets);
+	txq = &adapter->sge.ethtxq[pi->first_qset + qidx];
+
+	/*
+	 * Take this opportunity to reclaim any TX Descriptors whose DMA
+	 * transfers have completed.
+	 */
+	reclaim_completed_tx(adapter, &txq->q, true);
+
+	/*
+	 * Calculate the number of flits and TX Descriptors we're going to
+	 * need along with how many TX Descriptors will be left over after
+	 * we inject our Work Request.
+	 */
+	flits = calc_tx_flits(skb);
+	ndesc = flits_to_desc(flits);
+	credits = txq_avail(&txq->q) - ndesc;
+
+	if (unlikely(credits < 0)) {
+		/*
+		 * Not enough room for this packet's Work Request.  Stop the
+		 * TX Queue and return a "busy" condition.  The queue will get
+		 * started later on when the firmware informs us that space
+		 * has opened up.
+		 */
+		txq_stop(txq);
+		dev_err(adapter->pdev_dev,
+			"%s: TX ring %u full while queue awake!\n",
+			dev->name, qidx);
+		return NETDEV_TX_BUSY;
+	}
+
+	if (!is_eth_imm(skb) &&
+	    unlikely(map_skb(adapter->pdev_dev, skb, addr) < 0)) {
+		/*
+		 * We need to map the skb into PCI DMA space (because it can't
+		 * be in-lined directly into the Work Request) and the mapping
+		 * operation failed.  Record the error and drop the packet.
+		 */
+		txq->mapping_err++;
+		goto out_free;
+	}
+
+	wr_mid = FW_WR_LEN16(DIV_ROUND_UP(flits, 2));
+	if (unlikely(credits < ETHTXQ_STOP_THRES)) {
+		/*
+		 * After we're done injecting the Work Request for this
+		 * packet, we'll be below our "stop threshhold" so stop the TX
+		 * Queue now and schedule a request for an SGE Egress Queue
+		 * Update message.  The queue will get started later on when
+		 * the firmware processes this Work Request and sends us an
+		 * Egress Queue Status Update message indicating that space
+		 * has opened up.
+		 */
+		txq_stop(txq);
+		wr_mid |= FW_WR_EQUEQ | FW_WR_EQUIQ;
+	}
+
+	/*
+	 * Start filling in our Work Request.  Note that we do _not_ handle
+	 * the WR Header wrapping around the TX Descriptor Ring.  If our
+	 * maximum header size ever exceeds one TX Descriptor, we'll need to
+	 * do something else here.
+	 */
+	BUG_ON(DIV_ROUND_UP(ETHTXQ_MAX_HDR, TXD_PER_EQ_UNIT) > 1);
+	wr = (void *)&txq->q.desc[txq->q.pidx];
+	wr->equiq_to_len16 = cpu_to_be32(wr_mid);
+	wr->r3[0] = cpu_to_be64(0);
+	wr->r3[1] = cpu_to_be64(0);
+	skb_copy_from_linear_data(skb, (void *)wr->ethmacdst, fw_hdr_copy_len);
+	end = (u64 *)wr + flits;
+
+	/*
+	 * If this is a Large Send Offload packet we'll put in an LSO CPL
+	 * message with an encapsulated TX Packet CPL message.  Otherwise we
+	 * just use a TX Packet CPL message.
+	 */
+	ssi = skb_shinfo(skb);
+	if (ssi->gso_size) {
+		struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1);
+		bool v6 = (ssi->gso_type & SKB_GSO_TCPV6) != 0;
+		int l3hdr_len = skb_network_header_len(skb);
+		int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN;
+
+		wr->op_immdlen =
+			cpu_to_be32(FW_WR_OP(FW_ETH_TX_PKT_VM_WR) |
+				    FW_WR_IMMDLEN(sizeof(*lso) +
+						  sizeof(*cpl)));
+		/*
+		 * Fill in the LSO CPL message.
+		 */
+		lso->lso_ctrl =
+			cpu_to_be32(LSO_OPCODE(CPL_TX_PKT_LSO) |
+				    LSO_FIRST_SLICE |
+				    LSO_LAST_SLICE |
+				    LSO_IPV6(v6) |
+				    LSO_ETHHDR_LEN(eth_xtra_len/4) |
+				    LSO_IPHDR_LEN(l3hdr_len/4) |
+				    LSO_TCPHDR_LEN(tcp_hdr(skb)->doff));
+		lso->ipid_ofst = cpu_to_be16(0);
+		lso->mss = cpu_to_be16(ssi->gso_size);
+		lso->seqno_offset = cpu_to_be32(0);
+		lso->len = cpu_to_be32(skb->len);
+
+		/*
+		 * Set up TX Packet CPL pointer, control word and perform
+		 * accounting.
+		 */
+		cpl = (void *)(lso + 1);
+		cntrl = (TXPKT_CSUM_TYPE(v6 ? TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) |
+			 TXPKT_IPHDR_LEN(l3hdr_len) |
+			 TXPKT_ETHHDR_LEN(eth_xtra_len));
+		txq->tso++;
+		txq->tx_cso += ssi->gso_segs;
+	} else {
+		int len;
+
+		len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl);
+		wr->op_immdlen =
+			cpu_to_be32(FW_WR_OP(FW_ETH_TX_PKT_VM_WR) |
+				    FW_WR_IMMDLEN(len));
+
+		/*
+		 * Set up TX Packet CPL pointer, control word and perform
+		 * accounting.
+		 */
+		cpl = (void *)(wr + 1);
+		if (skb->ip_summed == CHECKSUM_PARTIAL) {
+			cntrl = hwcsum(skb) | TXPKT_IPCSUM_DIS;
+			txq->tx_cso++;
+		} else
+			cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS;
+	}
+
+	/*
+	 * If there's a VLAN tag present, add that to the list of things to
+	 * do in this Work Request.
+	 */
+	if (vlan_tx_tag_present(skb)) {
+		txq->vlan_ins++;
+		cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(vlan_tx_tag_get(skb));
+	}
+
+	/*
+	 * Fill in the TX Packet CPL message header.
+	 */
+	cpl->ctrl0 = cpu_to_be32(TXPKT_OPCODE(CPL_TX_PKT_XT) |
+				 TXPKT_INTF(pi->port_id) |
+				 TXPKT_PF(0));
+	cpl->pack = cpu_to_be16(0);
+	cpl->len = cpu_to_be16(skb->len);
+	cpl->ctrl1 = cpu_to_be64(cntrl);
+
+#ifdef T4_TRACE
+	T4_TRACE5(adapter->tb[txq->q.cntxt_id & 7],
+		  "eth_xmit: ndesc %u, credits %u, pidx %u, len %u, frags %u",
+		  ndesc, credits, txq->q.pidx, skb->len, ssi->nr_frags);
+#endif
+
+	/*
+	 * Fill in the body of the TX Packet CPL message with either in-lined
+	 * data or a Scatter/Gather List.
+	 */
+	if (is_eth_imm(skb)) {
+		/*
+		 * In-line the packet's data and free the skb since we don't
+		 * need it any longer.
+		 */
+		inline_tx_skb(skb, &txq->q, cpl + 1);
+		dev_kfree_skb(skb);
+	} else {
+		/*
+		 * Write the skb's Scatter/Gather list into the TX Packet CPL
+		 * message and retain a pointer to the skb so we can free it
+		 * later when its DMA completes.  (We store the skb pointer
+		 * in the Software Descriptor corresponding to the last TX
+		 * Descriptor used by the Work Request.)
+		 *
+		 * The retained skb will be freed when the corresponding TX
+		 * Descriptors are reclaimed after their DMAs complete.
+		 * However, this could take quite a while since, in general,
+		 * the hardware is set up to be lazy about sending DMA
+		 * completion notifications to us and we mostly perform TX
+		 * reclaims in the transmit routine.
+		 *
+		 * This is good for performamce but means that we rely on new
+		 * TX packets arriving to run the destructors of completed
+		 * packets, which open up space in their sockets' send queues.
+		 * Sometimes we do not get such new packets causing TX to
+		 * stall.  A single UDP transmitter is a good example of this
+		 * situation.  We have a clean up timer that periodically
+		 * reclaims completed packets but it doesn't run often enough
+		 * (nor do we want it to) to prevent lengthy stalls.  A
+		 * solution to this problem is to run the destructor early,
+		 * after the packet is queued but before it's DMAd.  A con is
+		 * that we lie to socket memory accounting, but the amount of
+		 * extra memory is reasonable (limited by the number of TX
+		 * descriptors), the packets do actually get freed quickly by
+		 * new packets almost always, and for protocols like TCP that
+		 * wait for acks to really free up the data the extra memory
+		 * is even less.  On the positive side we run the destructors
+		 * on the sending CPU rather than on a potentially different
+		 * completing CPU, usually a good thing.
+		 *
+		 * Run the destructor before telling the DMA engine about the
+		 * packet to make sure it doesn't complete and get freed
+		 * prematurely.
+		 */
+		struct ulptx_sgl *sgl = (struct ulptx_sgl *)(cpl + 1);
+		struct sge_txq *tq = &txq->q;
+		int last_desc;
+
+		/*
+		 * If the Work Request header was an exact multiple of our TX
+		 * Descriptor length, then it's possible that the starting SGL
+		 * pointer lines up exactly with the end of our TX Descriptor
+		 * ring.  If that's the case, wrap around to the beginning
+		 * here ...
+		 */
+		if (unlikely((void *)sgl == (void *)tq->stat)) {
+			sgl = (void *)tq->desc;
+			end = (void *)((void *)tq->desc +
+				       ((void *)end - (void *)tq->stat));
+		}
+
+		write_sgl(skb, tq, sgl, end, 0, addr);
+		skb_orphan(skb);
+
+		last_desc = tq->pidx + ndesc - 1;
+		if (last_desc >= tq->size)
+			last_desc -= tq->size;
+		tq->sdesc[last_desc].skb = skb;
+		tq->sdesc[last_desc].sgl = sgl;
+	}
+
+	/*
+	 * Advance our internal TX Queue state, tell the hardware about
+	 * the new TX descriptors and return success.
+	 */
+	txq_advance(&txq->q, ndesc);
+	dev->trans_start = jiffies;
+	ring_tx_db(adapter, &txq->q, ndesc);
+	return NETDEV_TX_OK;
+
+out_free:
+	/*
+	 * An error of some sort happened.  Free the TX skb and tell the
+	 * OS that we've "dealt" with the packet ...
+	 */
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+/**
+ *	t4vf_pktgl_free - free a packet gather list
+ *	@gl: the gather list
+ *
+ *	Releases the pages of a packet gather list.  We do not own the last
+ *	page on the list and do not free it.
+ */
+void t4vf_pktgl_free(const struct pkt_gl *gl)
+{
+	int frag;
+
+	frag = gl->nfrags - 1;
+	while (frag--)
+		put_page(gl->frags[frag].page);
+}
+
+/**
+ *	copy_frags - copy fragments from gather list into skb_shared_info
+ *	@si: destination skb shared info structure
+ *	@gl: source internal packet gather list
+ *	@offset: packet start offset in first page
+ *
+ *	Copy an internal packet gather list into a Linux skb_shared_info
+ *	structure.
+ */
+static inline void copy_frags(struct skb_shared_info *si,
+			      const struct pkt_gl *gl,
+			      unsigned int offset)
+{
+	unsigned int n;
+
+	/* usually there's just one frag */
+	si->frags[0].page = gl->frags[0].page;
+	si->frags[0].page_offset = gl->frags[0].page_offset + offset;
+	si->frags[0].size = gl->frags[0].size - offset;
+	si->nr_frags = gl->nfrags;
+
+	n = gl->nfrags - 1;
+	if (n)
+		memcpy(&si->frags[1], &gl->frags[1], n * sizeof(skb_frag_t));
+
+	/* get a reference to the last page, we don't own it */
+	get_page(gl->frags[n].page);
+}
+
+/**
+ *	do_gro - perform Generic Receive Offload ingress packet processing
+ *	@rxq: ingress RX Ethernet Queue
+ *	@gl: gather list for ingress packet
+ *	@pkt: CPL header for last packet fragment
+ *
+ *	Perform Generic Receive Offload (GRO) ingress packet processing.
+ *	We use the standard Linux GRO interfaces for this.
+ */
+static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
+		   const struct cpl_rx_pkt *pkt)
+{
+	int ret;
+	struct sk_buff *skb;
+
+	skb = napi_get_frags(&rxq->rspq.napi);
+	if (unlikely(!skb)) {
+		t4vf_pktgl_free(gl);
+		rxq->stats.rx_drops++;
+		return;
+	}
+
+	copy_frags(skb_shinfo(skb), gl, PKTSHIFT);
+	skb->len = gl->tot_len - PKTSHIFT;
+	skb->data_len = skb->len;
+	skb->truesize += skb->data_len;
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	skb_record_rx_queue(skb, rxq->rspq.idx);
+
+	if (unlikely(pkt->vlan_ex)) {
+		struct port_info *pi = netdev_priv(rxq->rspq.netdev);
+		struct vlan_group *grp = pi->vlan_grp;
+
+		rxq->stats.vlan_ex++;
+		if (likely(grp)) {
+			ret = vlan_gro_frags(&rxq->rspq.napi, grp,
+					     be16_to_cpu(pkt->vlan));
+			goto stats;
+		}
+	}
+	ret = napi_gro_frags(&rxq->rspq.napi);
+
+stats:
+	if (ret == GRO_HELD)
+		rxq->stats.lro_pkts++;
+	else if (ret == GRO_MERGED || ret == GRO_MERGED_FREE)
+		rxq->stats.lro_merged++;
+	rxq->stats.pkts++;
+	rxq->stats.rx_cso++;
+}
+
+/**
+ *	t4vf_ethrx_handler - process an ingress ethernet packet
+ *	@rspq: the response queue that received the packet
+ *	@rsp: the response queue descriptor holding the RX_PKT message
+ *	@gl: the gather list of packet fragments
+ *
+ *	Process an ingress ethernet packet and deliver it to the stack.
+ */
+int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
+		       const struct pkt_gl *gl)
+{
+	struct sk_buff *skb;
+	struct port_info *pi;
+	struct skb_shared_info *ssi;
+	const struct cpl_rx_pkt *pkt = (void *)&rsp[1];
+	bool csum_ok = pkt->csum_calc && !pkt->err_vec;
+	unsigned int len = be16_to_cpu(pkt->len);
+	struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq);
+
+	/*
+	 * If this is a good TCP packet and we have Generic Receive Offload
+	 * enabled, handle the packet in the GRO path.
+	 */
+	if ((pkt->l2info & cpu_to_be32(RXF_TCP)) &&
+	    (rspq->netdev->features & NETIF_F_GRO) && csum_ok &&
+	    !pkt->ip_frag) {
+		do_gro(rxq, gl, pkt);
+		return 0;
+	}
+
+	/*
+	 * If the ingress packet is small enough, allocate an skb large enough
+	 * for all of the data and copy it inline.  Otherwise, allocate an skb
+	 * with enough room to pull in the header and reference the rest of
+	 * the data via the skb fragment list.
+	 */
+	if (len <= RX_COPY_THRES) {
+		/* small packets have only one fragment */
+		skb = alloc_skb(gl->frags[0].size, GFP_ATOMIC);
+		if (!skb)
+			goto nomem;
+		__skb_put(skb, gl->frags[0].size);
+		skb_copy_to_linear_data(skb, gl->va, gl->frags[0].size);
+	} else {
+		skb = alloc_skb(RX_PKT_PULL_LEN, GFP_ATOMIC);
+		if (!skb)
+			goto nomem;
+		__skb_put(skb, RX_PKT_PULL_LEN);
+		skb_copy_to_linear_data(skb, gl->va, RX_PKT_PULL_LEN);
+
+		ssi = skb_shinfo(skb);
+		ssi->frags[0].page = gl->frags[0].page;
+		ssi->frags[0].page_offset = (gl->frags[0].page_offset +
+					     RX_PKT_PULL_LEN);
+		ssi->frags[0].size = gl->frags[0].size - RX_PKT_PULL_LEN;
+		if (gl->nfrags > 1)
+			memcpy(&ssi->frags[1], &gl->frags[1],
+			       (gl->nfrags-1) * sizeof(skb_frag_t));
+		ssi->nr_frags = gl->nfrags;
+		skb->len = len + PKTSHIFT;
+		skb->data_len = skb->len - RX_PKT_PULL_LEN;
+		skb->truesize += skb->data_len;
+
+		/* Get a reference for the last page, we don't own it */
+		get_page(gl->frags[gl->nfrags - 1].page);
+	}
+
+	__skb_pull(skb, PKTSHIFT);
+	skb->protocol = eth_type_trans(skb, rspq->netdev);
+	skb_record_rx_queue(skb, rspq->idx);
+	skb->dev->last_rx = jiffies;                  /* XXX removed 2.6.29 */
+	pi = netdev_priv(skb->dev);
+	rxq->stats.pkts++;
+
+	if (csum_ok && (pi->rx_offload & RX_CSO) && !pkt->err_vec &&
+	    (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) {
+		if (!pkt->ip_frag)
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		else {
+			__sum16 c = (__force __sum16)pkt->csum;
+			skb->csum = csum_unfold(c);
+			skb->ip_summed = CHECKSUM_COMPLETE;
+		}
+		rxq->stats.rx_cso++;
+	} else
+		skb->ip_summed = CHECKSUM_NONE;
+
+	if (unlikely(pkt->vlan_ex)) {
+		struct vlan_group *grp = pi->vlan_grp;
+
+		rxq->stats.vlan_ex++;
+		if (likely(grp))
+			vlan_hwaccel_receive_skb(skb, grp,
+						 be16_to_cpu(pkt->vlan));
+		else
+			dev_kfree_skb_any(skb);
+	} else
+		netif_receive_skb(skb);
+
+	return 0;
+
+nomem:
+	t4vf_pktgl_free(gl);
+	rxq->stats.rx_drops++;
+	return 0;
+}
+
+/**
+ *	is_new_response - check if a response is newly written
+ *	@rc: the response control descriptor
+ *	@rspq: the response queue
+ *
+ *	Returns true if a response descriptor contains a yet unprocessed
+ *	response.
+ */
+static inline bool is_new_response(const struct rsp_ctrl *rc,
+				   const struct sge_rspq *rspq)
+{
+	return RSPD_GEN(rc->type_gen) == rspq->gen;
+}
+
+/**
+ *	restore_rx_bufs - put back a packet's RX buffers
+ *	@gl: the packet gather list
+ *	@fl: the SGE Free List
+ *	@nfrags: how many fragments in @si
+ *
+ *	Called when we find out that the current packet, @si, can't be
+ *	processed right away for some reason.  This is a very rare event and
+ *	there's no effort to make this suspension/resumption process
+ *	particularly efficient.
+ *
+ *	We implement the suspension by putting all of the RX buffers associated
+ *	with the current packet back on the original Free List.  The buffers
+ *	have already been unmapped and are left unmapped, we mark them as
+ *	unmapped in order to prevent further unmapping attempts.  (Effectively
+ *	this function undoes the series of @unmap_rx_buf calls which were done
+ *	to create the current packet's gather list.)  This leaves us ready to
+ *	restart processing of the packet the next time we start processing the
+ *	RX Queue ...
+ */
+static void restore_rx_bufs(const struct pkt_gl *gl, struct sge_fl *fl,
+			    int frags)
+{
+	struct rx_sw_desc *sdesc;
+
+	while (frags--) {
+		if (fl->cidx == 0)
+			fl->cidx = fl->size - 1;
+		else
+			fl->cidx--;
+		sdesc = &fl->sdesc[fl->cidx];
+		sdesc->page = gl->frags[frags].page;
+		sdesc->dma_addr |= RX_UNMAPPED_BUF;
+		fl->avail++;
+	}
+}
+
+/**
+ *	rspq_next - advance to the next entry in a response queue
+ *	@rspq: the queue
+ *
+ *	Updates the state of a response queue to advance it to the next entry.
+ */
+static inline void rspq_next(struct sge_rspq *rspq)
+{
+	rspq->cur_desc = (void *)rspq->cur_desc + rspq->iqe_len;
+	if (unlikely(++rspq->cidx == rspq->size)) {
+		rspq->cidx = 0;
+		rspq->gen ^= 1;
+		rspq->cur_desc = rspq->desc;
+	}
+}
+
+/**
+ *	process_responses - process responses from an SGE response queue
+ *	@rspq: the ingress response queue to process
+ *	@budget: how many responses can be processed in this round
+ *
+ *	Process responses from a Scatter Gather Engine response queue up to
+ *	the supplied budget.  Responses include received packets as well as
+ *	control messages from firmware or hardware.
+ *
+ *	Additionally choose the interrupt holdoff time for the next interrupt
+ *	on this queue.  If the system is under memory shortage use a fairly
+ *	long delay to help recovery.
+ */
+int process_responses(struct sge_rspq *rspq, int budget)
+{
+	struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq);
+	int budget_left = budget;
+
+	while (likely(budget_left)) {
+		int ret, rsp_type;
+		const struct rsp_ctrl *rc;
+
+		rc = (void *)rspq->cur_desc + (rspq->iqe_len - sizeof(*rc));
+		if (!is_new_response(rc, rspq))
+			break;
+
+		/*
+		 * Figure out what kind of response we've received from the
+		 * SGE.
+		 */
+		rmb();
+		rsp_type = RSPD_TYPE(rc->type_gen);
+		if (likely(rsp_type == RSP_TYPE_FLBUF)) {
+			skb_frag_t *fp;
+			struct pkt_gl gl;
+			const struct rx_sw_desc *sdesc;
+			u32 bufsz, frag;
+			u32 len = be32_to_cpu(rc->pldbuflen_qid);
+
+			/*
+			 * If we get a "new buffer" message from the SGE we
+			 * need to move on to the next Free List buffer.
+			 */
+			if (len & RSPD_NEWBUF) {
+				/*
+				 * We get one "new buffer" message when we
+				 * first start up a queue so we need to ignore
+				 * it when our offset into the buffer is 0.
+				 */
+				if (likely(rspq->offset > 0)) {
+					free_rx_bufs(rspq->adapter, &rxq->fl,
+						     1);
+					rspq->offset = 0;
+				}
+				len = RSPD_LEN(len);
+			}
+
+			/*
+			 * Gather packet fragments.
+			 */
+			for (frag = 0, fp = gl.frags; /**/; frag++, fp++) {
+				BUG_ON(frag >= MAX_SKB_FRAGS);
+				BUG_ON(rxq->fl.avail == 0);
+				sdesc = &rxq->fl.sdesc[rxq->fl.cidx];
+				bufsz = get_buf_size(sdesc);
+				fp->page = sdesc->page;
+				fp->page_offset = rspq->offset;
+				fp->size = min(bufsz, len);
+				len -= fp->size;
+				if (!len)
+					break;
+				unmap_rx_buf(rspq->adapter, &rxq->fl);
+			}
+			gl.nfrags = frag+1;
+
+			/*
+			 * Last buffer remains mapped so explicitly make it
+			 * coherent for CPU access and start preloading first
+			 * cache line ...
+			 */
+			dma_sync_single_for_cpu(rspq->adapter->pdev_dev,
+						get_buf_addr(sdesc),
+						fp->size, DMA_FROM_DEVICE);
+			gl.va = (page_address(gl.frags[0].page) +
+				 gl.frags[0].page_offset);
+			prefetch(gl.va);
+
+			/*
+			 * Hand the new ingress packet to the handler for
+			 * this Response Queue.
+			 */
+			ret = rspq->handler(rspq, rspq->cur_desc, &gl);
+			if (likely(ret == 0))
+				rspq->offset += ALIGN(fp->size, FL_ALIGN);
+			else
+				restore_rx_bufs(&gl, &rxq->fl, frag);
+		} else if (likely(rsp_type == RSP_TYPE_CPL)) {
+			ret = rspq->handler(rspq, rspq->cur_desc, NULL);
+		} else {
+			WARN_ON(rsp_type > RSP_TYPE_CPL);
+			ret = 0;
+		}
+
+		if (unlikely(ret)) {
+			/*
+			 * Couldn't process descriptor, back off for recovery.
+			 * We use the SGE's last timer which has the longest
+			 * interrupt coalescing value ...
+			 */
+			const int NOMEM_TIMER_IDX = SGE_NTIMERS-1;
+			rspq->next_intr_params =
+				QINTR_TIMER_IDX(NOMEM_TIMER_IDX);
+			break;
+		}
+
+		rspq_next(rspq);
+		budget_left--;
+	}
+
+	/*
+	 * If this is a Response Queue with an associated Free List and
+	 * at least two Egress Queue units available in the Free List
+	 * for new buffer pointers, refill the Free List.
+	 */
+	if (rspq->offset >= 0 &&
+	    rxq->fl.size - rxq->fl.avail >= 2*FL_PER_EQ_UNIT)
+		__refill_fl(rspq->adapter, &rxq->fl);
+	return budget - budget_left;
+}
+
+/**
+ *	napi_rx_handler - the NAPI handler for RX processing
+ *	@napi: the napi instance
+ *	@budget: how many packets we can process in this round
+ *
+ *	Handler for new data events when using NAPI.  This does not need any
+ *	locking or protection from interrupts as data interrupts are off at
+ *	this point and other adapter interrupts do not interfere (the latter
+ *	in not a concern at all with MSI-X as non-data interrupts then have
+ *	a separate handler).
+ */
+static int napi_rx_handler(struct napi_struct *napi, int budget)
+{
+	unsigned int intr_params;
+	struct sge_rspq *rspq = container_of(napi, struct sge_rspq, napi);
+	int work_done = process_responses(rspq, budget);
+
+	if (likely(work_done < budget)) {
+		napi_complete(napi);
+		intr_params = rspq->next_intr_params;
+		rspq->next_intr_params = rspq->intr_params;
+	} else
+		intr_params = QINTR_TIMER_IDX(SGE_TIMER_UPD_CIDX);
+
+	if (unlikely(work_done == 0))
+		rspq->unhandled_irqs++;
+
+	t4_write_reg(rspq->adapter,
+		     T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
+		     CIDXINC(work_done) |
+		     INGRESSQID((u32)rspq->cntxt_id) |
+		     SEINTARM(intr_params));
+	return work_done;
+}
+
+/*
+ * The MSI-X interrupt handler for an SGE response queue for the NAPI case
+ * (i.e., response queue serviced by NAPI polling).
+ */
+irqreturn_t t4vf_sge_intr_msix(int irq, void *cookie)
+{
+	struct sge_rspq *rspq = cookie;
+
+	napi_schedule(&rspq->napi);
+	return IRQ_HANDLED;
+}
+
+/*
+ * Process the indirect interrupt entries in the interrupt queue and kick off
+ * NAPI for each queue that has generated an entry.
+ */
+static unsigned int process_intrq(struct adapter *adapter)
+{
+	struct sge *s = &adapter->sge;
+	struct sge_rspq *intrq = &s->intrq;
+	unsigned int work_done;
+
+	spin_lock(&adapter->sge.intrq_lock);
+	for (work_done = 0; ; work_done++) {
+		const struct rsp_ctrl *rc;
+		unsigned int qid, iq_idx;
+		struct sge_rspq *rspq;
+
+		/*
+		 * Grab the next response from the interrupt queue and bail
+		 * out if it's not a new response.
+		 */
+		rc = (void *)intrq->cur_desc + (intrq->iqe_len - sizeof(*rc));
+		if (!is_new_response(rc, intrq))
+			break;
+
+		/*
+		 * If the response isn't a forwarded interrupt message issue a
+		 * error and go on to the next response message.  This should
+		 * never happen ...
+		 */
+		rmb();
+		if (unlikely(RSPD_TYPE(rc->type_gen) != RSP_TYPE_INTR)) {
+			dev_err(adapter->pdev_dev,
+				"Unexpected INTRQ response type %d\n",
+				RSPD_TYPE(rc->type_gen));
+			continue;
+		}
+
+		/*
+		 * Extract the Queue ID from the interrupt message and perform
+		 * sanity checking to make sure it really refers to one of our
+		 * Ingress Queues which is active and matches the queue's ID.
+		 * None of these error conditions should ever happen so we may
+		 * want to either make them fatal and/or conditionalized under
+		 * DEBUG.
+		 */
+		qid = RSPD_QID(be32_to_cpu(rc->pldbuflen_qid));
+		iq_idx = IQ_IDX(s, qid);
+		if (unlikely(iq_idx >= MAX_INGQ)) {
+			dev_err(adapter->pdev_dev,
+				"Ingress QID %d out of range\n", qid);
+			continue;
+		}
+		rspq = s->ingr_map[iq_idx];
+		if (unlikely(rspq == NULL)) {
+			dev_err(adapter->pdev_dev,
+				"Ingress QID %d RSPQ=NULL\n", qid);
+			continue;
+		}
+		if (unlikely(rspq->abs_id != qid)) {
+			dev_err(adapter->pdev_dev,
+				"Ingress QID %d refers to RSPQ %d\n",
+				qid, rspq->abs_id);
+			continue;
+		}
+
+		/*
+		 * Schedule NAPI processing on the indicated Response Queue
+		 * and move on to the next entry in the Forwarded Interrupt
+		 * Queue.
+		 */
+		napi_schedule(&rspq->napi);
+		rspq_next(intrq);
+	}
+
+	t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
+		     CIDXINC(work_done) |
+		     INGRESSQID(intrq->cntxt_id) |
+		     SEINTARM(intrq->intr_params));
+
+	spin_unlock(&adapter->sge.intrq_lock);
+
+	return work_done;
+}
+
+/*
+ * The MSI interrupt handler handles data events from SGE response queues as
+ * well as error and other async events as they all use the same MSI vector.
+ */
+irqreturn_t t4vf_intr_msi(int irq, void *cookie)
+{
+	struct adapter *adapter = cookie;
+
+	process_intrq(adapter);
+	return IRQ_HANDLED;
+}
+
+/**
+ *	t4vf_intr_handler - select the top-level interrupt handler
+ *	@adapter: the adapter
+ *
+ *	Selects the top-level interrupt handler based on the type of interrupts
+ *	(MSI-X or MSI).
+ */
+irq_handler_t t4vf_intr_handler(struct adapter *adapter)
+{
+	BUG_ON((adapter->flags & (USING_MSIX|USING_MSI)) == 0);
+	if (adapter->flags & USING_MSIX)
+		return t4vf_sge_intr_msix;
+	else
+		return t4vf_intr_msi;
+}
+
+/**
+ *	sge_rx_timer_cb - perform periodic maintenance of SGE RX queues
+ *	@data: the adapter
+ *
+ *	Runs periodically from a timer to perform maintenance of SGE RX queues.
+ *
+ *	a) Replenishes RX queues that have run out due to memory shortage.
+ *	Normally new RX buffers are added when existing ones are consumed but
+ *	when out of memory a queue can become empty.  We schedule NAPI to do
+ *	the actual refill.
+ */
+static void sge_rx_timer_cb(unsigned long data)
+{
+	struct adapter *adapter = (struct adapter *)data;
+	struct sge *s = &adapter->sge;
+	unsigned int i;
+
+	/*
+	 * Scan the "Starving Free Lists" flag array looking for any Free
+	 * Lists in need of more free buffers.  If we find one and it's not
+	 * being actively polled, then bump its "starving" counter and attempt
+	 * to refill it.  If we're successful in adding enough buffers to push
+	 * the Free List over the starving threshold, then we can clear its
+	 * "starving" status.
+	 */
+	for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++) {
+		unsigned long m;
+
+		for (m = s->starving_fl[i]; m; m &= m - 1) {
+			unsigned int id = __ffs(m) + i * BITS_PER_LONG;
+			struct sge_fl *fl = s->egr_map[id];
+
+			clear_bit(id, s->starving_fl);
+			smp_mb__after_clear_bit();
+
+			/*
+			 * Since we are accessing fl without a lock there's a
+			 * small probability of a false positive where we
+			 * schedule napi but the FL is no longer starving.
+			 * No biggie.
+			 */
+			if (fl_starving(fl)) {
+				struct sge_eth_rxq *rxq;
+
+				rxq = container_of(fl, struct sge_eth_rxq, fl);
+				if (napi_reschedule(&rxq->rspq.napi))
+					fl->starving++;
+				else
+					set_bit(id, s->starving_fl);
+			}
+		}
+	}
+
+	/*
+	 * Reschedule the next scan for starving Free Lists ...
+	 */
+	mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD);
+}
+
+/**
+ *	sge_tx_timer_cb - perform periodic maintenance of SGE Tx queues
+ *	@data: the adapter
+ *
+ *	Runs periodically from a timer to perform maintenance of SGE TX queues.
+ *
+ *	b) Reclaims completed Tx packets for the Ethernet queues.  Normally
+ *	packets are cleaned up by new Tx packets, this timer cleans up packets
+ *	when no new packets are being submitted.  This is essential for pktgen,
+ *	at least.
+ */
+static void sge_tx_timer_cb(unsigned long data)
+{
+	struct adapter *adapter = (struct adapter *)data;
+	struct sge *s = &adapter->sge;
+	unsigned int i, budget;
+
+	budget = MAX_TIMER_TX_RECLAIM;
+	i = s->ethtxq_rover;
+	do {
+		struct sge_eth_txq *txq = &s->ethtxq[i];
+
+		if (reclaimable(&txq->q) && __netif_tx_trylock(txq->txq)) {
+			int avail = reclaimable(&txq->q);
+
+			if (avail > budget)
+				avail = budget;
+
+			free_tx_desc(adapter, &txq->q, avail, true);
+			txq->q.in_use -= avail;
+			__netif_tx_unlock(txq->txq);
+
+			budget -= avail;
+			if (!budget)
+				break;
+		}
+
+		i++;
+		if (i >= s->ethqsets)
+			i = 0;
+	} while (i != s->ethtxq_rover);
+	s->ethtxq_rover = i;
+
+	/*
+	 * If we found too many reclaimable packets schedule a timer in the
+	 * near future to continue where we left off.  Otherwise the next timer
+	 * will be at its normal interval.
+	 */
+	mod_timer(&s->tx_timer, jiffies + (budget ? TX_QCHECK_PERIOD : 2));
+}
+
+/**
+ *	t4vf_sge_alloc_rxq - allocate an SGE RX Queue
+ *	@adapter: the adapter
+ *	@rspq: pointer to to the new rxq's Response Queue to be filled in
+ *	@iqasynch: if 0, a normal rspq; if 1, an asynchronous event queue
+ *	@dev: the network device associated with the new rspq
+ *	@intr_dest: MSI-X vector index (overriden in MSI mode)
+ *	@fl: pointer to the new rxq's Free List to be filled in
+ *	@hnd: the interrupt handler to invoke for the rspq
+ */
+int t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq,
+		       bool iqasynch, struct net_device *dev,
+		       int intr_dest,
+		       struct sge_fl *fl, rspq_handler_t hnd)
+{
+	struct port_info *pi = netdev_priv(dev);
+	struct fw_iq_cmd cmd, rpl;
+	int ret, iqandst, flsz = 0;
+
+	/*
+	 * If we're using MSI interrupts and we're not initializing the
+	 * Forwarded Interrupt Queue itself, then set up this queue for
+	 * indirect interrupts to the Forwarded Interrupt Queue.  Obviously
+	 * the Forwarded Interrupt Queue must be set up before any other
+	 * ingress queue ...
+	 */
+	if ((adapter->flags & USING_MSI) && rspq != &adapter->sge.intrq) {
+		iqandst = SGE_INTRDST_IQ;
+		intr_dest = adapter->sge.intrq.abs_id;
+	} else
+		iqandst = SGE_INTRDST_PCI;
+
+	/*
+	 * Allocate the hardware ring for the Response Queue.  The size needs
+	 * to be a multiple of 16 which includes the mandatory status entry
+	 * (regardless of whether the Status Page capabilities are enabled or
+	 * not).
+	 */
+	rspq->size = roundup(rspq->size, 16);
+	rspq->desc = alloc_ring(adapter->pdev_dev, rspq->size, rspq->iqe_len,
+				0, &rspq->phys_addr, NULL, 0);
+	if (!rspq->desc)
+		return -ENOMEM;
+
+	/*
+	 * Fill in the Ingress Queue Command.  Note: Ideally this code would
+	 * be in t4vf_hw.c but there are so many parameters and dependencies
+	 * on our Linux SGE state that we would end up having to pass tons of
+	 * parameters.  We'll have to think about how this might be migrated
+	 * into OS-independent common code ...
+	 */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_IQ_CMD) |
+				    FW_CMD_REQUEST |
+				    FW_CMD_WRITE |
+				    FW_CMD_EXEC);
+	cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_ALLOC |
+					 FW_IQ_CMD_IQSTART(1) |
+					 FW_LEN16(cmd));
+	cmd.type_to_iqandstindex =
+		cpu_to_be32(FW_IQ_CMD_TYPE(FW_IQ_TYPE_FL_INT_CAP) |
+			    FW_IQ_CMD_IQASYNCH(iqasynch) |
+			    FW_IQ_CMD_VIID(pi->viid) |
+			    FW_IQ_CMD_IQANDST(iqandst) |
+			    FW_IQ_CMD_IQANUS(1) |
+			    FW_IQ_CMD_IQANUD(SGE_UPDATEDEL_INTR) |
+			    FW_IQ_CMD_IQANDSTINDEX(intr_dest));
+	cmd.iqdroprss_to_iqesize =
+		cpu_to_be16(FW_IQ_CMD_IQPCIECH(pi->port_id) |
+			    FW_IQ_CMD_IQGTSMODE |
+			    FW_IQ_CMD_IQINTCNTTHRESH(rspq->pktcnt_idx) |
+			    FW_IQ_CMD_IQESIZE(ilog2(rspq->iqe_len) - 4));
+	cmd.iqsize = cpu_to_be16(rspq->size);
+	cmd.iqaddr = cpu_to_be64(rspq->phys_addr);
+
+	if (fl) {
+		/*
+		 * Allocate the ring for the hardware free list (with space
+		 * for its status page) along with the associated software
+		 * descriptor ring.  The free list size needs to be a multiple
+		 * of the Egress Queue Unit.
+		 */
+		fl->size = roundup(fl->size, FL_PER_EQ_UNIT);
+		fl->desc = alloc_ring(adapter->pdev_dev, fl->size,
+				      sizeof(__be64), sizeof(struct rx_sw_desc),
+				      &fl->addr, &fl->sdesc, STAT_LEN);
+		if (!fl->desc) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		/*
+		 * Calculate the size of the hardware free list ring plus
+		 * status page (which the SGE will place at the end of the
+		 * free list ring) in Egress Queue Units.
+		 */
+		flsz = (fl->size / FL_PER_EQ_UNIT +
+			STAT_LEN / EQ_UNIT);
+
+		/*
+		 * Fill in all the relevant firmware Ingress Queue Command
+		 * fields for the free list.
+		 */
+		cmd.iqns_to_fl0congen =
+			cpu_to_be32(
+				FW_IQ_CMD_FL0HOSTFCMODE(SGE_HOSTFCMODE_NONE) |
+				FW_IQ_CMD_FL0PACKEN |
+				FW_IQ_CMD_FL0PADEN);
+		cmd.fl0dcaen_to_fl0cidxfthresh =
+			cpu_to_be16(
+				FW_IQ_CMD_FL0FBMIN(SGE_FETCHBURSTMIN_64B) |
+				FW_IQ_CMD_FL0FBMAX(SGE_FETCHBURSTMAX_512B));
+		cmd.fl0size = cpu_to_be16(flsz);
+		cmd.fl0addr = cpu_to_be64(fl->addr);
+	}
+
+	/*
+	 * Issue the firmware Ingress Queue Command and extract the results if
+	 * it completes successfully.
+	 */
+	ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+	if (ret)
+		goto err;
+
+	netif_napi_add(dev, &rspq->napi, napi_rx_handler, 64);
+	rspq->cur_desc = rspq->desc;
+	rspq->cidx = 0;
+	rspq->gen = 1;
+	rspq->next_intr_params = rspq->intr_params;
+	rspq->cntxt_id = be16_to_cpu(rpl.iqid);
+	rspq->abs_id = be16_to_cpu(rpl.physiqid);
+	rspq->size--;			/* subtract status entry */
+	rspq->adapter = adapter;
+	rspq->netdev = dev;
+	rspq->handler = hnd;
+
+	/* set offset to -1 to distinguish ingress queues without FL */
+	rspq->offset = fl ? 0 : -1;
+
+	if (fl) {
+		fl->cntxt_id = be16_to_cpu(rpl.fl0id);
+		fl->avail = 0;
+		fl->pend_cred = 0;
+		fl->pidx = 0;
+		fl->cidx = 0;
+		fl->alloc_failed = 0;
+		fl->large_alloc_failed = 0;
+		fl->starving = 0;
+		refill_fl(adapter, fl, fl_cap(fl), GFP_KERNEL);
+	}
+
+	return 0;
+
+err:
+	/*
+	 * An error occurred.  Clean up our partial allocation state and
+	 * return the error.
+	 */
+	if (rspq->desc) {
+		dma_free_coherent(adapter->pdev_dev, rspq->size * rspq->iqe_len,
+				  rspq->desc, rspq->phys_addr);
+		rspq->desc = NULL;
+	}
+	if (fl && fl->desc) {
+		kfree(fl->sdesc);
+		fl->sdesc = NULL;
+		dma_free_coherent(adapter->pdev_dev, flsz * EQ_UNIT,
+				  fl->desc, fl->addr);
+		fl->desc = NULL;
+	}
+	return ret;
+}
+
+/**
+ *	t4vf_sge_alloc_eth_txq - allocate an SGE Ethernet TX Queue
+ *	@adapter: the adapter
+ *	@txq: pointer to the new txq to be filled in
+ *	@devq: the network TX queue associated with the new txq
+ *	@iqid: the relative ingress queue ID to which events relating to
+ *		the new txq should be directed
+ */
+int t4vf_sge_alloc_eth_txq(struct adapter *adapter, struct sge_eth_txq *txq,
+			   struct net_device *dev, struct netdev_queue *devq,
+			   unsigned int iqid)
+{
+	int ret, nentries;
+	struct fw_eq_eth_cmd cmd, rpl;
+	struct port_info *pi = netdev_priv(dev);
+
+	/*
+	 * Calculate the size of the hardware TX Queue (including the
+	 * status age on the end) in units of TX Descriptors.
+	 */
+	nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc);
+
+	/*
+	 * Allocate the hardware ring for the TX ring (with space for its
+	 * status page) along with the associated software descriptor ring.
+	 */
+	txq->q.desc = alloc_ring(adapter->pdev_dev, txq->q.size,
+				 sizeof(struct tx_desc),
+				 sizeof(struct tx_sw_desc),
+				 &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN);
+	if (!txq->q.desc)
+		return -ENOMEM;
+
+	/*
+	 * Fill in the Egress Queue Command.  Note: As with the direct use of
+	 * the firmware Ingress Queue COmmand above in our RXQ allocation
+	 * routine, ideally, this code would be in t4vf_hw.c.  Again, we'll
+	 * have to see if there's some reasonable way to parameterize it
+	 * into the common code ...
+	 */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_EQ_ETH_CMD) |
+				    FW_CMD_REQUEST |
+				    FW_CMD_WRITE |
+				    FW_CMD_EXEC);
+	cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_ALLOC |
+					 FW_EQ_ETH_CMD_EQSTART |
+					 FW_LEN16(cmd));
+	cmd.viid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_VIID(pi->viid));
+	cmd.fetchszm_to_iqid =
+		cpu_to_be32(FW_EQ_ETH_CMD_HOSTFCMODE(SGE_HOSTFCMODE_STPG) |
+			    FW_EQ_ETH_CMD_PCIECHN(pi->port_id) |
+			    FW_EQ_ETH_CMD_IQID(iqid));
+	cmd.dcaen_to_eqsize =
+		cpu_to_be32(FW_EQ_ETH_CMD_FBMIN(SGE_FETCHBURSTMIN_64B) |
+			    FW_EQ_ETH_CMD_FBMAX(SGE_FETCHBURSTMAX_512B) |
+			    FW_EQ_ETH_CMD_CIDXFTHRESH(SGE_CIDXFLUSHTHRESH_32) |
+			    FW_EQ_ETH_CMD_EQSIZE(nentries));
+	cmd.eqaddr = cpu_to_be64(txq->q.phys_addr);
+
+	/*
+	 * Issue the firmware Egress Queue Command and extract the results if
+	 * it completes successfully.
+	 */
+	ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+	if (ret) {
+		/*
+		 * The girmware Ingress Queue Command failed for some reason.
+		 * Free up our partial allocation state and return the error.
+		 */
+		kfree(txq->q.sdesc);
+		txq->q.sdesc = NULL;
+		dma_free_coherent(adapter->pdev_dev,
+				  nentries * sizeof(struct tx_desc),
+				  txq->q.desc, txq->q.phys_addr);
+		txq->q.desc = NULL;
+		return ret;
+	}
+
+	txq->q.in_use = 0;
+	txq->q.cidx = 0;
+	txq->q.pidx = 0;
+	txq->q.stat = (void *)&txq->q.desc[txq->q.size];
+	txq->q.cntxt_id = FW_EQ_ETH_CMD_EQID_GET(be32_to_cpu(rpl.eqid_pkd));
+	txq->q.abs_id =
+		FW_EQ_ETH_CMD_PHYSEQID_GET(be32_to_cpu(rpl.physeqid_pkd));
+	txq->txq = devq;
+	txq->tso = 0;
+	txq->tx_cso = 0;
+	txq->vlan_ins = 0;
+	txq->q.stops = 0;
+	txq->q.restarts = 0;
+	txq->mapping_err = 0;
+	return 0;
+}
+
+/*
+ * Free the DMA map resources associated with a TX queue.
+ */
+static void free_txq(struct adapter *adapter, struct sge_txq *tq)
+{
+	dma_free_coherent(adapter->pdev_dev,
+			  tq->size * sizeof(*tq->desc) + STAT_LEN,
+			  tq->desc, tq->phys_addr);
+	tq->cntxt_id = 0;
+	tq->sdesc = NULL;
+	tq->desc = NULL;
+}
+
+/*
+ * Free the resources associated with a response queue (possibly including a
+ * free list).
+ */
+static void free_rspq_fl(struct adapter *adapter, struct sge_rspq *rspq,
+			 struct sge_fl *fl)
+{
+	unsigned int flid = fl ? fl->cntxt_id : 0xffff;
+
+	t4vf_iq_free(adapter, FW_IQ_TYPE_FL_INT_CAP,
+		     rspq->cntxt_id, flid, 0xffff);
+	dma_free_coherent(adapter->pdev_dev, (rspq->size + 1) * rspq->iqe_len,
+			  rspq->desc, rspq->phys_addr);
+	netif_napi_del(&rspq->napi);
+	rspq->netdev = NULL;
+	rspq->cntxt_id = 0;
+	rspq->abs_id = 0;
+	rspq->desc = NULL;
+
+	if (fl) {
+		free_rx_bufs(adapter, fl, fl->avail);
+		dma_free_coherent(adapter->pdev_dev,
+				  fl->size * sizeof(*fl->desc) + STAT_LEN,
+				  fl->desc, fl->addr);
+		kfree(fl->sdesc);
+		fl->sdesc = NULL;
+		fl->cntxt_id = 0;
+		fl->desc = NULL;
+	}
+}
+
+/**
+ *	t4vf_free_sge_resources - free SGE resources
+ *	@adapter: the adapter
+ *
+ *	Frees resources used by the SGE queue sets.
+ */
+void t4vf_free_sge_resources(struct adapter *adapter)
+{
+	struct sge *s = &adapter->sge;
+	struct sge_eth_rxq *rxq = s->ethrxq;
+	struct sge_eth_txq *txq = s->ethtxq;
+	struct sge_rspq *evtq = &s->fw_evtq;
+	struct sge_rspq *intrq = &s->intrq;
+	int qs;
+
+	for (qs = 0; qs < adapter->sge.ethqsets; qs++, rxq++, txq++) {
+		if (rxq->rspq.desc)
+			free_rspq_fl(adapter, &rxq->rspq, &rxq->fl);
+		if (txq->q.desc) {
+			t4vf_eth_eq_free(adapter, txq->q.cntxt_id);
+			free_tx_desc(adapter, &txq->q, txq->q.in_use, true);
+			kfree(txq->q.sdesc);
+			free_txq(adapter, &txq->q);
+		}
+	}
+	if (evtq->desc)
+		free_rspq_fl(adapter, evtq, NULL);
+	if (intrq->desc)
+		free_rspq_fl(adapter, intrq, NULL);
+}
+
+/**
+ *	t4vf_sge_start - enable SGE operation
+ *	@adapter: the adapter
+ *
+ *	Start tasklets and timers associated with the DMA engine.
+ */
+void t4vf_sge_start(struct adapter *adapter)
+{
+	adapter->sge.ethtxq_rover = 0;
+	mod_timer(&adapter->sge.rx_timer, jiffies + RX_QCHECK_PERIOD);
+	mod_timer(&adapter->sge.tx_timer, jiffies + TX_QCHECK_PERIOD);
+}
+
+/**
+ *	t4vf_sge_stop - disable SGE operation
+ *	@adapter: the adapter
+ *
+ *	Stop tasklets and timers associated with the DMA engine.  Note that
+ *	this is effective only if measures have been taken to disable any HW
+ *	events that may restart them.
+ */
+void t4vf_sge_stop(struct adapter *adapter)
+{
+	struct sge *s = &adapter->sge;
+
+	if (s->rx_timer.function)
+		del_timer_sync(&s->rx_timer);
+	if (s->tx_timer.function)
+		del_timer_sync(&s->tx_timer);
+}
+
+/**
+ *	t4vf_sge_init - initialize SGE
+ *	@adapter: the adapter
+ *
+ *	Performs SGE initialization needed every time after a chip reset.
+ *	We do not initialize any of the queue sets here, instead the driver
+ *	top-level must request those individually.  We also do not enable DMA
+ *	here, that should be done after the queues have been set up.
+ */
+int t4vf_sge_init(struct adapter *adapter)
+{
+	struct sge_params *sge_params = &adapter->params.sge;
+	u32 fl0 = sge_params->sge_fl_buffer_size[0];
+	u32 fl1 = sge_params->sge_fl_buffer_size[1];
+	struct sge *s = &adapter->sge;
+
+	/*
+	 * Start by vetting the basic SGE parameters which have been set up by
+	 * the Physical Function Driver.  Ideally we should be able to deal
+	 * with _any_ configuration.  Practice is different ...
+	 */
+	if (fl0 != PAGE_SIZE || (fl1 != 0 && fl1 <= fl0)) {
+		dev_err(adapter->pdev_dev, "bad SGE FL buffer sizes [%d, %d]\n",
+			fl0, fl1);
+		return -EINVAL;
+	}
+	if ((sge_params->sge_control & RXPKTCPLMODE) == 0) {
+		dev_err(adapter->pdev_dev, "bad SGE CPL MODE\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Now translate the adapter parameters into our internal forms.
+	 */
+	if (fl1)
+		FL_PG_ORDER = ilog2(fl1) - PAGE_SHIFT;
+	STAT_LEN = ((sge_params->sge_control & EGRSTATUSPAGESIZE) ? 128 : 64);
+	PKTSHIFT = PKTSHIFT_GET(sge_params->sge_control);
+	FL_ALIGN = 1 << (INGPADBOUNDARY_GET(sge_params->sge_control) +
+			 SGE_INGPADBOUNDARY_SHIFT);
+
+	/*
+	 * Set up tasklet timers.
+	 */
+	setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adapter);
+	setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adapter);
+
+	/*
+	 * Initialize Forwarded Interrupt Queue lock.
+	 */
+	spin_lock_init(&s->intrq_lock);
+
+	return 0;
+}
diff --git a/drivers/net/cxgb4vf/t4vf_common.h b/drivers/net/cxgb4vf/t4vf_common.h
new file mode 100644
index 0000000..5c7bde7
--- /dev/null
+++ b/drivers/net/cxgb4vf/t4vf_common.h
@@ -0,0 +1,273 @@
+/*
+ * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet
+ * driver for Linux.
+ *
+ * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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 __T4VF_COMMON_H__
+#define __T4VF_COMMON_H__
+
+#include "../cxgb4/t4fw_api.h"
+
+/*
+ * The "len16" field of a Firmware Command Structure ...
+ */
+#define FW_LEN16(fw_struct) FW_CMD_LEN16(sizeof(fw_struct) / 16)
+
+/*
+ * Per-VF statistics.
+ */
+struct t4vf_port_stats {
+	/*
+	 * TX statistics.
+	 */
+	u64 tx_bcast_bytes;		/* broadcast */
+	u64 tx_bcast_frames;
+	u64 tx_mcast_bytes;		/* multicast */
+	u64 tx_mcast_frames;
+	u64 tx_ucast_bytes;		/* unicast */
+	u64 tx_ucast_frames;
+	u64 tx_drop_frames;		/* TX dropped frames */
+	u64 tx_offload_bytes;		/* offload */
+	u64 tx_offload_frames;
+
+	/*
+	 * RX statistics.
+	 */
+	u64 rx_bcast_bytes;		/* broadcast */
+	u64 rx_bcast_frames;
+	u64 rx_mcast_bytes;		/* multicast */
+	u64 rx_mcast_frames;
+	u64 rx_ucast_bytes;
+	u64 rx_ucast_frames;		/* unicast */
+
+	u64 rx_err_frames;		/* RX error frames */
+};
+
+/*
+ * Per-"port" (Virtual Interface) link configuration ...
+ */
+struct link_config {
+	unsigned int   supported;        /* link capabilities */
+	unsigned int   advertising;      /* advertised capabilities */
+	unsigned short requested_speed;  /* speed user has requested */
+	unsigned short speed;            /* actual link speed */
+	unsigned char  requested_fc;     /* flow control user has requested */
+	unsigned char  fc;               /* actual link flow control */
+	unsigned char  autoneg;          /* autonegotiating? */
+	unsigned char  link_ok;          /* link up? */
+};
+
+enum {
+	PAUSE_RX      = 1 << 0,
+	PAUSE_TX      = 1 << 1,
+	PAUSE_AUTONEG = 1 << 2
+};
+
+/*
+ * General device parameters ...
+ */
+struct dev_params {
+	u32 fwrev;			/* firmware version */
+	u32 tprev;			/* TP Microcode Version */
+};
+
+/*
+ * Scatter Gather Engine parameters.  These are almost all determined by the
+ * Physical Function Driver.  We just need to grab them to see within which
+ * environment we're playing ...
+ */
+struct sge_params {
+	u32 sge_control;		/* padding, boundaries, lengths, etc. */
+	u32 sge_host_page_size;		/* RDMA page sizes */
+	u32 sge_queues_per_page;	/* RDMA queues/page */
+	u32 sge_user_mode_limits;	/* limits for BAR2 user mode accesses */
+	u32 sge_fl_buffer_size[16];	/* free list buffer sizes */
+	u32 sge_ingress_rx_threshold;	/* RX counter interrupt threshold[4] */
+	u32 sge_timer_value_0_and_1;	/* interrupt coalescing timer values */
+	u32 sge_timer_value_2_and_3;
+	u32 sge_timer_value_4_and_5;
+};
+
+/*
+ * Vital Product Data parameters.
+ */
+struct vpd_params {
+	u32 cclk;			/* Core Clock (KHz) */
+};
+
+/*
+ * Global Receive Side Scaling (RSS) parameters in host-native format.
+ */
+struct rss_params {
+	unsigned int mode;		/* RSS mode */
+	union {
+	    struct {
+		int synmapen:1;		/* SYN Map Enable */
+		int syn4tupenipv6:1;	/* enable hashing 4-tuple IPv6 SYNs */
+		int syn2tupenipv6:1;	/* enable hashing 2-tuple IPv6 SYNs */
+		int syn4tupenipv4:1;	/* enable hashing 4-tuple IPv4 SYNs */
+		int syn2tupenipv4:1;	/* enable hashing 2-tuple IPv4 SYNs */
+		int ofdmapen:1;		/* Offload Map Enable */
+		int tnlmapen:1;		/* Tunnel Map Enable */
+		int tnlalllookup:1;	/* Tunnel All Lookup */
+		int hashtoeplitz:1;	/* use Toeplitz hash */
+	    } basicvirtual;
+	} u;
+};
+
+/*
+ * Virtual Interface RSS Configuration in host-native format.
+ */
+union rss_vi_config {
+    struct {
+	u16 defaultq;			/* Ingress Queue ID for !tnlalllookup */
+	int ip6fourtupen:1;		/* hash 4-tuple IPv6 ingress packets */
+	int ip6twotupen:1;		/* hash 2-tuple IPv6 ingress packets */
+	int ip4fourtupen:1;		/* hash 4-tuple IPv4 ingress packets */
+	int ip4twotupen:1;		/* hash 2-tuple IPv4 ingress packets */
+	int udpen;			/* hash 4-tuple UDP ingress packets */
+    } basicvirtual;
+};
+
+/*
+ * Maximum resources provisioned for a PCI VF.
+ */
+struct vf_resources {
+	unsigned int nvi;		/* N virtual interfaces */
+	unsigned int neq;		/* N egress Qs */
+	unsigned int nethctrl;		/* N egress ETH or CTRL Qs */
+	unsigned int niqflint;		/* N ingress Qs/w free list(s) & intr */
+	unsigned int niq;		/* N ingress Qs */
+	unsigned int tc;		/* PCI-E traffic class */
+	unsigned int pmask;		/* port access rights mask */
+	unsigned int nexactf;		/* N exact MPS filters */
+	unsigned int r_caps;		/* read capabilities */
+	unsigned int wx_caps;		/* write/execute capabilities */
+};
+
+/*
+ * Per-"adapter" (Virtual Function) parameters.
+ */
+struct adapter_params {
+	struct dev_params dev;		/* general device parameters */
+	struct sge_params sge;		/* Scatter Gather Engine */
+	struct vpd_params vpd;		/* Vital Product Data */
+	struct rss_params rss;		/* Receive Side Scaling */
+	struct vf_resources vfres;	/* Virtual Function Resource limits */
+	u8 nports;			/* # of Ethernet "ports" */
+};
+
+#include "adapter.h"
+
+#ifndef PCI_VENDOR_ID_CHELSIO
+# define PCI_VENDOR_ID_CHELSIO 0x1425
+#endif
+
+#define for_each_port(adapter, iter) \
+	for (iter = 0; iter < (adapter)->params.nports; iter++)
+
+static inline bool is_10g_port(const struct link_config *lc)
+{
+	return (lc->supported & SUPPORTED_10000baseT_Full) != 0;
+}
+
+static inline unsigned int core_ticks_per_usec(const struct adapter *adapter)
+{
+	return adapter->params.vpd.cclk / 1000;
+}
+
+static inline unsigned int us_to_core_ticks(const struct adapter *adapter,
+					    unsigned int us)
+{
+	return (us * adapter->params.vpd.cclk) / 1000;
+}
+
+static inline unsigned int core_ticks_to_us(const struct adapter *adapter,
+					    unsigned int ticks)
+{
+	return (ticks * 1000) / adapter->params.vpd.cclk;
+}
+
+int t4vf_wr_mbox_core(struct adapter *, const void *, int, void *, bool);
+
+static inline int t4vf_wr_mbox(struct adapter *adapter, const void *cmd,
+			       int size, void *rpl)
+{
+	return t4vf_wr_mbox_core(adapter, cmd, size, rpl, true);
+}
+
+static inline int t4vf_wr_mbox_ns(struct adapter *adapter, const void *cmd,
+				  int size, void *rpl)
+{
+	return t4vf_wr_mbox_core(adapter, cmd, size, rpl, false);
+}
+
+int __devinit t4vf_wait_dev_ready(struct adapter *);
+int __devinit t4vf_port_init(struct adapter *, int);
+
+int t4vf_query_params(struct adapter *, unsigned int, const u32 *, u32 *);
+int t4vf_set_params(struct adapter *, unsigned int, const u32 *, const u32 *);
+
+int t4vf_get_sge_params(struct adapter *);
+int t4vf_get_vpd_params(struct adapter *);
+int t4vf_get_dev_params(struct adapter *);
+int t4vf_get_rss_glb_config(struct adapter *);
+int t4vf_get_vfres(struct adapter *);
+
+int t4vf_read_rss_vi_config(struct adapter *, unsigned int,
+			    union rss_vi_config *);
+int t4vf_write_rss_vi_config(struct adapter *, unsigned int,
+			     union rss_vi_config *);
+int t4vf_config_rss_range(struct adapter *, unsigned int, int, int,
+			  const u16 *, int);
+
+int t4vf_alloc_vi(struct adapter *, int);
+int t4vf_free_vi(struct adapter *, int);
+int t4vf_enable_vi(struct adapter *, unsigned int, bool, bool);
+int t4vf_identify_port(struct adapter *, unsigned int, unsigned int);
+
+int t4vf_set_rxmode(struct adapter *, unsigned int, int, int, int, int, int,
+		    bool);
+int t4vf_alloc_mac_filt(struct adapter *, unsigned int, bool, unsigned int,
+			const u8 **, u16 *, u64 *, bool);
+int t4vf_change_mac(struct adapter *, unsigned int, int, const u8 *, bool);
+int t4vf_set_addr_hash(struct adapter *, unsigned int, bool, u64, bool);
+int t4vf_get_port_stats(struct adapter *, int, struct t4vf_port_stats *);
+
+int t4vf_iq_free(struct adapter *, unsigned int, unsigned int, unsigned int,
+		 unsigned int);
+int t4vf_eth_eq_free(struct adapter *, unsigned int);
+
+int t4vf_handle_fw_rpl(struct adapter *, const __be64 *);
+
+#endif /* __T4VF_COMMON_H__ */
diff --git a/drivers/net/cxgb4vf/t4vf_defs.h b/drivers/net/cxgb4vf/t4vf_defs.h
new file mode 100644
index 0000000..c7b127d
--- /dev/null
+++ b/drivers/net/cxgb4vf/t4vf_defs.h
@@ -0,0 +1,121 @@
+/*
+ * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet
+ * driver for Linux.
+ *
+ * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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 __T4VF_DEFS_H__
+#define __T4VF_DEFS_H__
+
+#include "../cxgb4/t4_regs.h"
+
+/*
+ * The VF Register Map.
+ *
+ * The Scatter Gather Engine (SGE), Multiport Support module (MPS), PIO Local
+ * bus module (PL) and CPU Interface Module (CIM) components are mapped via
+ * the Slice to Module Map Table (see below) in the Physical Function Register
+ * Map.  The Mail Box Data (MBDATA) range is mapped via the PCI-E Mailbox Base
+ * and Offset registers in the PF Register Map.  The MBDATA base address is
+ * quite constrained as it determines the Mailbox Data addresses for both PFs
+ * and VFs, and therefore must fit in both the VF and PF Register Maps without
+ * overlapping other registers.
+ */
+#define T4VF_SGE_BASE_ADDR	0x0000
+#define T4VF_MPS_BASE_ADDR	0x0100
+#define T4VF_PL_BASE_ADDR	0x0200
+#define T4VF_MBDATA_BASE_ADDR	0x0240
+#define T4VF_CIM_BASE_ADDR	0x0300
+
+#define T4VF_REGMAP_START	0x0000
+#define T4VF_REGMAP_SIZE	0x0400
+
+/*
+ * There's no hardware limitation which requires that the addresses of the
+ * Mailbox Data in the fixed CIM PF map and the programmable VF map must
+ * match.  However, it's a useful convention ...
+ */
+#if T4VF_MBDATA_BASE_ADDR != CIM_PF_MAILBOX_DATA
+#error T4VF_MBDATA_BASE_ADDR must match CIM_PF_MAILBOX_DATA!
+#endif
+
+/*
+ * Virtual Function "Slice to Module Map Table" definitions.
+ *
+ * This table allows us to map subsets of the various module register sets
+ * into the T4VF Register Map.  Each table entry identifies the index of the
+ * module whose registers are being mapped, the offset within the module's
+ * register set that the mapping should start at, the limit of the mapping,
+ * and the offset within the T4VF Register Map to which the module's registers
+ * are being mapped.  All addresses and qualtities are in terms of 32-bit
+ * words.  The "limit" value is also in terms of 32-bit words and is equal to
+ * the last address mapped in the T4VF Register Map 1 (i.e. it's a "<="
+ * relation rather than a "<").
+ */
+#define T4VF_MOD_MAP(module, index, first, last) \
+	T4VF_MOD_MAP_##module##_INDEX  = (index), \
+	T4VF_MOD_MAP_##module##_FIRST  = (first), \
+	T4VF_MOD_MAP_##module##_LAST   = (last), \
+	T4VF_MOD_MAP_##module##_OFFSET = ((first)/4), \
+	T4VF_MOD_MAP_##module##_BASE = \
+		(T4VF_##module##_BASE_ADDR/4 + (first)/4), \
+	T4VF_MOD_MAP_##module##_LIMIT = \
+		(T4VF_##module##_BASE_ADDR/4 + (last)/4),
+
+#define SGE_VF_KDOORBELL 0x0
+#define SGE_VF_GTS 0x4
+#define MPS_VF_CTL 0x0
+#define MPS_VF_STAT_RX_VF_ERR_FRAMES_H 0xfc
+#define PL_VF_WHOAMI 0x0
+#define CIM_VF_EXT_MAILBOX_CTRL 0x0
+#define CIM_VF_EXT_MAILBOX_STATUS 0x4
+
+enum {
+    T4VF_MOD_MAP(SGE, 2, SGE_VF_KDOORBELL, SGE_VF_GTS)
+    T4VF_MOD_MAP(MPS, 0, MPS_VF_CTL, MPS_VF_STAT_RX_VF_ERR_FRAMES_H)
+    T4VF_MOD_MAP(PL,  3, PL_VF_WHOAMI, PL_VF_WHOAMI)
+    T4VF_MOD_MAP(CIM, 1, CIM_VF_EXT_MAILBOX_CTRL, CIM_VF_EXT_MAILBOX_STATUS)
+};
+
+/*
+ * There isn't a Slice to Module Map Table entry for the Mailbox Data
+ * registers, but it's convenient to use similar names as above.  There are 8
+ * little-endian 64-bit Mailbox Data registers.  Note that the "instances"
+ * value below is in terms of 32-bit words which matches the "word" addressing
+ * space we use above for the Slice to Module Map Space.
+ */
+#define NUM_CIM_VF_MAILBOX_DATA_INSTANCES 16
+
+#define T4VF_MBDATA_FIRST	0
+#define T4VF_MBDATA_LAST	((NUM_CIM_VF_MAILBOX_DATA_INSTANCES-1)*4)
+
+#endif /* __T4T4VF_DEFS_H__ */
diff --git a/drivers/net/cxgb4vf/t4vf_hw.c b/drivers/net/cxgb4vf/t4vf_hw.c
new file mode 100644
index 0000000..ea1c123
--- /dev/null
+++ b/drivers/net/cxgb4vf/t4vf_hw.c
@@ -0,0 +1,1333 @@
+/*
+ * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet
+ * driver for Linux.
+ *
+ * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/version.h>
+#include <linux/pci.h>
+
+#include "t4vf_common.h"
+#include "t4vf_defs.h"
+
+#include "../cxgb4/t4_regs.h"
+#include "../cxgb4/t4fw_api.h"
+
+/*
+ * Wait for the device to become ready (signified by our "who am I" register
+ * returning a value other than all 1's).  Return an error if it doesn't
+ * become ready ...
+ */
+int __devinit t4vf_wait_dev_ready(struct adapter *adapter)
+{
+	const u32 whoami = T4VF_PL_BASE_ADDR + PL_VF_WHOAMI;
+	const u32 notready1 = 0xffffffff;
+	const u32 notready2 = 0xeeeeeeee;
+	u32 val;
+
+	val = t4_read_reg(adapter, whoami);
+	if (val != notready1 && val != notready2)
+		return 0;
+	msleep(500);
+	val = t4_read_reg(adapter, whoami);
+	if (val != notready1 && val != notready2)
+		return 0;
+	else
+		return -EIO;
+}
+
+/*
+ * Get the reply to a mailbox command and store it in @rpl in big-endian order
+ * (since the firmware data structures are specified in a big-endian layout).
+ */
+static void get_mbox_rpl(struct adapter *adapter, __be64 *rpl, int size,
+			 u32 mbox_data)
+{
+	for ( ; size; size -= 8, mbox_data += 8)
+		*rpl++ = cpu_to_be64(t4_read_reg64(adapter, mbox_data));
+}
+
+/*
+ * Dump contents of mailbox with a leading tag.
+ */
+static void dump_mbox(struct adapter *adapter, const char *tag, u32 mbox_data)
+{
+	dev_err(adapter->pdev_dev,
+		"mbox %s: %llx %llx %llx %llx %llx %llx %llx %llx\n", tag,
+		(unsigned long long)t4_read_reg64(adapter, mbox_data +  0),
+		(unsigned long long)t4_read_reg64(adapter, mbox_data +  8),
+		(unsigned long long)t4_read_reg64(adapter, mbox_data + 16),
+		(unsigned long long)t4_read_reg64(adapter, mbox_data + 24),
+		(unsigned long long)t4_read_reg64(adapter, mbox_data + 32),
+		(unsigned long long)t4_read_reg64(adapter, mbox_data + 40),
+		(unsigned long long)t4_read_reg64(adapter, mbox_data + 48),
+		(unsigned long long)t4_read_reg64(adapter, mbox_data + 56));
+}
+
+/**
+ *	t4vf_wr_mbox_core - send a command to FW through the mailbox
+ *	@adapter: the adapter
+ *	@cmd: the command to write
+ *	@size: command length in bytes
+ *	@rpl: where to optionally store the reply
+ *	@sleep_ok: if true we may sleep while awaiting command completion
+ *
+ *	Sends the given command to FW through the mailbox and waits for the
+ *	FW to execute the command.  If @rpl is not %NULL it is used to store
+ *	the FW's reply to the command.  The command and its optional reply
+ *	are of the same length.  FW can take up to 500 ms to respond.
+ *	@sleep_ok determines whether we may sleep while awaiting the response.
+ *	If sleeping is allowed we use progressive backoff otherwise we spin.
+ *
+ *	The return value is 0 on success or a negative errno on failure.  A
+ *	failure can happen either because we are not able to execute the
+ *	command or FW executes it but signals an error.  In the latter case
+ *	the return value is the error code indicated by FW (negated).
+ */
+int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
+		      void *rpl, bool sleep_ok)
+{
+	static int delay[] = {
+		1, 1, 3, 5, 10, 10, 20, 50, 100
+	};
+
+	u32 v;
+	int i, ms, delay_idx;
+	const __be64 *p;
+	u32 mbox_data = T4VF_MBDATA_BASE_ADDR;
+	u32 mbox_ctl = T4VF_CIM_BASE_ADDR + CIM_VF_EXT_MAILBOX_CTRL;
+
+	/*
+	 * Commands must be multiples of 16 bytes in length and may not be
+	 * larger than the size of the Mailbox Data register array.
+	 */
+	if ((size % 16) != 0 ||
+	    size > NUM_CIM_VF_MAILBOX_DATA_INSTANCES * 4)
+		return -EINVAL;
+
+	/*
+	 * Loop trying to get ownership of the mailbox.  Return an error
+	 * if we can't gain ownership.
+	 */
+	v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl));
+	for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
+		v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl));
+	if (v != MBOX_OWNER_DRV)
+		return v == MBOX_OWNER_FW ? -EBUSY : -ETIMEDOUT;
+
+	/*
+	 * Write the command array into the Mailbox Data register array and
+	 * transfer ownership of the mailbox to the firmware.
+	 */
+	for (i = 0, p = cmd; i < size; i += 8)
+		t4_write_reg64(adapter, mbox_data + i, be64_to_cpu(*p++));
+	t4_write_reg(adapter, mbox_ctl,
+		     MBMSGVALID | MBOWNER(MBOX_OWNER_FW));
+	t4_read_reg(adapter, mbox_ctl);          /* flush write */
+
+	/*
+	 * Spin waiting for firmware to acknowledge processing our command.
+	 */
+	delay_idx = 0;
+	ms = delay[0];
+
+	for (i = 0; i < 500; i += ms) {
+		if (sleep_ok) {
+			ms = delay[delay_idx];
+			if (delay_idx < ARRAY_SIZE(delay) - 1)
+				delay_idx++;
+			msleep(ms);
+		} else
+			mdelay(ms);
+
+		/*
+		 * If we're the owner, see if this is the reply we wanted.
+		 */
+		v = t4_read_reg(adapter, mbox_ctl);
+		if (MBOWNER_GET(v) == MBOX_OWNER_DRV) {
+			/*
+			 * If the Message Valid bit isn't on, revoke ownership
+			 * of the mailbox and continue waiting for our reply.
+			 */
+			if ((v & MBMSGVALID) == 0) {
+				t4_write_reg(adapter, mbox_ctl,
+					     MBOWNER(MBOX_OWNER_NONE));
+				continue;
+			}
+
+			/*
+			 * We now have our reply.  Extract the command return
+			 * value, copy the reply back to our caller's buffer
+			 * (if specified) and revoke ownership of the mailbox.
+			 * We return the (negated) firmware command return
+			 * code (this depends on FW_SUCCESS == 0).
+			 */
+
+			/* return value in low-order little-endian word */
+			v = t4_read_reg(adapter, mbox_data);
+			if (FW_CMD_RETVAL_GET(v))
+				dump_mbox(adapter, "FW Error", mbox_data);
+
+			if (rpl) {
+				/* request bit in high-order BE word */
+				WARN_ON((be32_to_cpu(*(const u32 *)cmd)
+					 & FW_CMD_REQUEST) == 0);
+				get_mbox_rpl(adapter, rpl, size, mbox_data);
+				WARN_ON((be32_to_cpu(*(u32 *)rpl)
+					 & FW_CMD_REQUEST) != 0);
+			}
+			t4_write_reg(adapter, mbox_ctl,
+				     MBOWNER(MBOX_OWNER_NONE));
+			return -FW_CMD_RETVAL_GET(v);
+		}
+	}
+
+	/*
+	 * We timed out.  Return the error ...
+	 */
+	dump_mbox(adapter, "FW Timeout", mbox_data);
+	return -ETIMEDOUT;
+}
+
+/**
+ *	hash_mac_addr - return the hash value of a MAC address
+ *	@addr: the 48-bit Ethernet MAC address
+ *
+ *	Hashes a MAC address according to the hash function used by hardware
+ *	inexact (hash) address matching.
+ */
+static int hash_mac_addr(const u8 *addr)
+{
+	u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
+	u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
+	a ^= b;
+	a ^= (a >> 12);
+	a ^= (a >> 6);
+	return a & 0x3f;
+}
+
+/**
+ *	init_link_config - initialize a link's SW state
+ *	@lc: structure holding the link state
+ *	@caps: link capabilities
+ *
+ *	Initializes the SW state maintained for each link, including the link's
+ *	capabilities and default speed/flow-control/autonegotiation settings.
+ */
+static void __devinit init_link_config(struct link_config *lc,
+				       unsigned int caps)
+{
+	lc->supported = caps;
+	lc->requested_speed = 0;
+	lc->speed = 0;
+	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
+	if (lc->supported & SUPPORTED_Autoneg) {
+		lc->advertising = lc->supported;
+		lc->autoneg = AUTONEG_ENABLE;
+		lc->requested_fc |= PAUSE_AUTONEG;
+	} else {
+		lc->advertising = 0;
+		lc->autoneg = AUTONEG_DISABLE;
+	}
+}
+
+/**
+ *	t4vf_port_init - initialize port hardware/software state
+ *	@adapter: the adapter
+ *	@pidx: the adapter port index
+ */
+int __devinit t4vf_port_init(struct adapter *adapter, int pidx)
+{
+	struct port_info *pi = adap2pinfo(adapter, pidx);
+	struct fw_vi_cmd vi_cmd, vi_rpl;
+	struct fw_port_cmd port_cmd, port_rpl;
+	int v;
+	u32 word;
+
+	/*
+	 * Execute a VI Read command to get our Virtual Interface information
+	 * like MAC address, etc.
+	 */
+	memset(&vi_cmd, 0, sizeof(vi_cmd));
+	vi_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) |
+				       FW_CMD_REQUEST |
+				       FW_CMD_READ);
+	vi_cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(vi_cmd));
+	vi_cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID(pi->viid));
+	v = t4vf_wr_mbox(adapter, &vi_cmd, sizeof(vi_cmd), &vi_rpl);
+	if (v)
+		return v;
+
+	BUG_ON(pi->port_id != FW_VI_CMD_PORTID_GET(vi_rpl.portid_pkd));
+	pi->rss_size = FW_VI_CMD_RSSSIZE_GET(be16_to_cpu(vi_rpl.rsssize_pkd));
+	t4_os_set_hw_addr(adapter, pidx, vi_rpl.mac);
+
+	/*
+	 * If we don't have read access to our port information, we're done
+	 * now.  Otherwise, execute a PORT Read command to get it ...
+	 */
+	if (!(adapter->params.vfres.r_caps & FW_CMD_CAP_PORT))
+		return 0;
+
+	memset(&port_cmd, 0, sizeof(port_cmd));
+	port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP(FW_PORT_CMD) |
+					    FW_CMD_REQUEST |
+					    FW_CMD_READ |
+					    FW_PORT_CMD_PORTID(pi->port_id));
+	port_cmd.action_to_len16 =
+		cpu_to_be32(FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
+			    FW_LEN16(port_cmd));
+	v = t4vf_wr_mbox(adapter, &port_cmd, sizeof(port_cmd), &port_rpl);
+	if (v)
+		return v;
+
+	v = 0;
+	word = be16_to_cpu(port_rpl.u.info.pcap);
+	if (word & FW_PORT_CAP_SPEED_100M)
+		v |= SUPPORTED_100baseT_Full;
+	if (word & FW_PORT_CAP_SPEED_1G)
+		v |= SUPPORTED_1000baseT_Full;
+	if (word & FW_PORT_CAP_SPEED_10G)
+		v |= SUPPORTED_10000baseT_Full;
+	if (word & FW_PORT_CAP_ANEG)
+		v |= SUPPORTED_Autoneg;
+	init_link_config(&pi->link_cfg, v);
+
+	return 0;
+}
+
+/**
+ *	t4vf_query_params - query FW or device parameters
+ *	@adapter: the adapter
+ *	@nparams: the number of parameters
+ *	@params: the parameter names
+ *	@vals: the parameter values
+ *
+ *	Reads the values of firmware or device parameters.  Up to 7 parameters
+ *	can be queried at once.
+ */
+int t4vf_query_params(struct adapter *adapter, unsigned int nparams,
+		      const u32 *params, u32 *vals)
+{
+	int i, ret;
+	struct fw_params_cmd cmd, rpl;
+	struct fw_params_param *p;
+	size_t len16;
+
+	if (nparams > 7)
+		return -EINVAL;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) |
+				    FW_CMD_REQUEST |
+				    FW_CMD_READ);
+	len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd,
+				      param[nparams].mnem), 16);
+	cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+	for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++)
+		p->mnem = htonl(*params++);
+
+	ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+	if (ret == 0)
+		for (i = 0, p = &rpl.param[0]; i < nparams; i++, p++)
+			*vals++ = be32_to_cpu(p->val);
+	return ret;
+}
+
+/**
+ *	t4vf_set_params - sets FW or device parameters
+ *	@adapter: the adapter
+ *	@nparams: the number of parameters
+ *	@params: the parameter names
+ *	@vals: the parameter values
+ *
+ *	Sets the values of firmware or device parameters.  Up to 7 parameters
+ *	can be specified at once.
+ */
+int t4vf_set_params(struct adapter *adapter, unsigned int nparams,
+		    const u32 *params, const u32 *vals)
+{
+	int i;
+	struct fw_params_cmd cmd;
+	struct fw_params_param *p;
+	size_t len16;
+
+	if (nparams > 7)
+		return -EINVAL;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) |
+				    FW_CMD_REQUEST |
+				    FW_CMD_WRITE);
+	len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd,
+				      param[nparams]), 16);
+	cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+	for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++) {
+		p->mnem = cpu_to_be32(*params++);
+		p->val = cpu_to_be32(*vals++);
+	}
+
+	return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
+ *	t4vf_get_sge_params - retrieve adapter Scatter gather Engine parameters
+ *	@adapter: the adapter
+ *
+ *	Retrieves various core SGE parameters in the form of hardware SGE
+ *	register values.  The caller is responsible for decoding these as
+ *	needed.  The SGE parameters are stored in @adapter->params.sge.
+ */
+int t4vf_get_sge_params(struct adapter *adapter)
+{
+	struct sge_params *sge_params = &adapter->params.sge;
+	u32 params[7], vals[7];
+	int v;
+
+	params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+		     FW_PARAMS_PARAM_XYZ(SGE_CONTROL));
+	params[1] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+		     FW_PARAMS_PARAM_XYZ(SGE_HOST_PAGE_SIZE));
+	params[2] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+		     FW_PARAMS_PARAM_XYZ(SGE_FL_BUFFER_SIZE0));
+	params[3] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+		     FW_PARAMS_PARAM_XYZ(SGE_FL_BUFFER_SIZE1));
+	params[4] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+		     FW_PARAMS_PARAM_XYZ(SGE_TIMER_VALUE_0_AND_1));
+	params[5] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+		     FW_PARAMS_PARAM_XYZ(SGE_TIMER_VALUE_2_AND_3));
+	params[6] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+		     FW_PARAMS_PARAM_XYZ(SGE_TIMER_VALUE_4_AND_5));
+	v = t4vf_query_params(adapter, 7, params, vals);
+	if (v)
+		return v;
+	sge_params->sge_control = vals[0];
+	sge_params->sge_host_page_size = vals[1];
+	sge_params->sge_fl_buffer_size[0] = vals[2];
+	sge_params->sge_fl_buffer_size[1] = vals[3];
+	sge_params->sge_timer_value_0_and_1 = vals[4];
+	sge_params->sge_timer_value_2_and_3 = vals[5];
+	sge_params->sge_timer_value_4_and_5 = vals[6];
+
+	params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+		     FW_PARAMS_PARAM_XYZ(SGE_INGRESS_RX_THRESHOLD));
+	v = t4vf_query_params(adapter, 1, params, vals);
+	if (v)
+		return v;
+	sge_params->sge_ingress_rx_threshold = vals[0];
+
+	return 0;
+}
+
+/**
+ *	t4vf_get_vpd_params - retrieve device VPD paremeters
+ *	@adapter: the adapter
+ *
+ *	Retrives various device Vital Product Data parameters.  The parameters
+ *	are stored in @adapter->params.vpd.
+ */
+int t4vf_get_vpd_params(struct adapter *adapter)
+{
+	struct vpd_params *vpd_params = &adapter->params.vpd;
+	u32 params[7], vals[7];
+	int v;
+
+	params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
+		     FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CCLK));
+	v = t4vf_query_params(adapter, 1, params, vals);
+	if (v)
+		return v;
+	vpd_params->cclk = vals[0];
+
+	return 0;
+}
+
+/**
+ *	t4vf_get_dev_params - retrieve device paremeters
+ *	@adapter: the adapter
+ *
+ *	Retrives various device parameters.  The parameters are stored in
+ *	@adapter->params.dev.
+ */
+int t4vf_get_dev_params(struct adapter *adapter)
+{
+	struct dev_params *dev_params = &adapter->params.dev;
+	u32 params[7], vals[7];
+	int v;
+
+	params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
+		     FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_FWREV));
+	params[1] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
+		     FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_TPREV));
+	v = t4vf_query_params(adapter, 2, params, vals);
+	if (v)
+		return v;
+	dev_params->fwrev = vals[0];
+	dev_params->tprev = vals[1];
+
+	return 0;
+}
+
+/**
+ *	t4vf_get_rss_glb_config - retrieve adapter RSS Global Configuration
+ *	@adapter: the adapter
+ *
+ *	Retrieves global RSS mode and parameters with which we have to live
+ *	and stores them in the @adapter's RSS parameters.
+ */
+int t4vf_get_rss_glb_config(struct adapter *adapter)
+{
+	struct rss_params *rss = &adapter->params.rss;
+	struct fw_rss_glb_config_cmd cmd, rpl;
+	int v;
+
+	/*
+	 * Execute an RSS Global Configuration read command to retrieve
+	 * our RSS configuration.
+	 */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) |
+				      FW_CMD_REQUEST |
+				      FW_CMD_READ);
+	cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+	v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+	if (v)
+		return v;
+
+	/*
+	 * Transate the big-endian RSS Global Configuration into our
+	 * cpu-endian format based on the RSS mode.  We also do first level
+	 * filtering at this point to weed out modes which don't support
+	 * VF Drivers ...
+	 */
+	rss->mode = FW_RSS_GLB_CONFIG_CMD_MODE_GET(
+			be32_to_cpu(rpl.u.manual.mode_pkd));
+	switch (rss->mode) {
+	case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: {
+		u32 word = be32_to_cpu(
+				rpl.u.basicvirtual.synmapen_to_hashtoeplitz);
+
+		rss->u.basicvirtual.synmapen =
+			((word & FW_RSS_GLB_CONFIG_CMD_SYNMAPEN) != 0);
+		rss->u.basicvirtual.syn4tupenipv6 =
+			((word & FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV6) != 0);
+		rss->u.basicvirtual.syn2tupenipv6 =
+			((word & FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV6) != 0);
+		rss->u.basicvirtual.syn4tupenipv4 =
+			((word & FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV4) != 0);
+		rss->u.basicvirtual.syn2tupenipv4 =
+			((word & FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV4) != 0);
+
+		rss->u.basicvirtual.ofdmapen =
+			((word & FW_RSS_GLB_CONFIG_CMD_OFDMAPEN) != 0);
+
+		rss->u.basicvirtual.tnlmapen =
+			((word & FW_RSS_GLB_CONFIG_CMD_TNLMAPEN) != 0);
+		rss->u.basicvirtual.tnlalllookup =
+			((word  & FW_RSS_GLB_CONFIG_CMD_TNLALLLKP) != 0);
+
+		rss->u.basicvirtual.hashtoeplitz =
+			((word & FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ) != 0);
+
+		/* we need at least Tunnel Map Enable to be set */
+		if (!rss->u.basicvirtual.tnlmapen)
+			return -EINVAL;
+		break;
+	}
+
+	default:
+		/* all unknown/unsupported RSS modes result in an error */
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ *	t4vf_get_vfres - retrieve VF resource limits
+ *	@adapter: the adapter
+ *
+ *	Retrieves configured resource limits and capabilities for a virtual
+ *	function.  The results are stored in @adapter->vfres.
+ */
+int t4vf_get_vfres(struct adapter *adapter)
+{
+	struct vf_resources *vfres = &adapter->params.vfres;
+	struct fw_pfvf_cmd cmd, rpl;
+	int v;
+	u32 word;
+
+	/*
+	 * Execute PFVF Read command to get VF resource limits; bail out early
+	 * with error on command failure.
+	 */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PFVF_CMD) |
+				    FW_CMD_REQUEST |
+				    FW_CMD_READ);
+	cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+	v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+	if (v)
+		return v;
+
+	/*
+	 * Extract VF resource limits and return success.
+	 */
+	word = be32_to_cpu(rpl.niqflint_niq);
+	vfres->niqflint = FW_PFVF_CMD_NIQFLINT_GET(word);
+	vfres->niq = FW_PFVF_CMD_NIQ_GET(word);
+
+	word = be32_to_cpu(rpl.type_to_neq);
+	vfres->neq = FW_PFVF_CMD_NEQ_GET(word);
+	vfres->pmask = FW_PFVF_CMD_PMASK_GET(word);
+
+	word = be32_to_cpu(rpl.tc_to_nexactf);
+	vfres->tc = FW_PFVF_CMD_TC_GET(word);
+	vfres->nvi = FW_PFVF_CMD_NVI_GET(word);
+	vfres->nexactf = FW_PFVF_CMD_NEXACTF_GET(word);
+
+	word = be32_to_cpu(rpl.r_caps_to_nethctrl);
+	vfres->r_caps = FW_PFVF_CMD_R_CAPS_GET(word);
+	vfres->wx_caps = FW_PFVF_CMD_WX_CAPS_GET(word);
+	vfres->nethctrl = FW_PFVF_CMD_NETHCTRL_GET(word);
+
+	return 0;
+}
+
+/**
+ *	t4vf_read_rss_vi_config - read a VI's RSS configuration
+ *	@adapter: the adapter
+ *	@viid: Virtual Interface ID
+ *	@config: pointer to host-native VI RSS Configuration buffer
+ *
+ *	Reads the Virtual Interface's RSS configuration information and
+ *	translates it into CPU-native format.
+ */
+int t4vf_read_rss_vi_config(struct adapter *adapter, unsigned int viid,
+			    union rss_vi_config *config)
+{
+	struct fw_rss_vi_config_cmd cmd, rpl;
+	int v;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
+				     FW_CMD_REQUEST |
+				     FW_CMD_READ |
+				     FW_RSS_VI_CONFIG_CMD_VIID(viid));
+	cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+	v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+	if (v)
+		return v;
+
+	switch (adapter->params.rss.mode) {
+	case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: {
+		u32 word = be32_to_cpu(rpl.u.basicvirtual.defaultq_to_udpen);
+
+		config->basicvirtual.ip6fourtupen =
+			((word & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN) != 0);
+		config->basicvirtual.ip6twotupen =
+			((word & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN) != 0);
+		config->basicvirtual.ip4fourtupen =
+			((word & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN) != 0);
+		config->basicvirtual.ip4twotupen =
+			((word & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN) != 0);
+		config->basicvirtual.udpen =
+			((word & FW_RSS_VI_CONFIG_CMD_UDPEN) != 0);
+		config->basicvirtual.defaultq =
+			FW_RSS_VI_CONFIG_CMD_DEFAULTQ_GET(word);
+		break;
+	}
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ *	t4vf_write_rss_vi_config - write a VI's RSS configuration
+ *	@adapter: the adapter
+ *	@viid: Virtual Interface ID
+ *	@config: pointer to host-native VI RSS Configuration buffer
+ *
+ *	Write the Virtual Interface's RSS configuration information
+ *	(translating it into firmware-native format before writing).
+ */
+int t4vf_write_rss_vi_config(struct adapter *adapter, unsigned int viid,
+			     union rss_vi_config *config)
+{
+	struct fw_rss_vi_config_cmd cmd, rpl;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
+				     FW_CMD_REQUEST |
+				     FW_CMD_WRITE |
+				     FW_RSS_VI_CONFIG_CMD_VIID(viid));
+	cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+	switch (adapter->params.rss.mode) {
+	case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: {
+		u32 word = 0;
+
+		if (config->basicvirtual.ip6fourtupen)
+			word |= FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN;
+		if (config->basicvirtual.ip6twotupen)
+			word |= FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN;
+		if (config->basicvirtual.ip4fourtupen)
+			word |= FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN;
+		if (config->basicvirtual.ip4twotupen)
+			word |= FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN;
+		if (config->basicvirtual.udpen)
+			word |= FW_RSS_VI_CONFIG_CMD_UDPEN;
+		word |= FW_RSS_VI_CONFIG_CMD_DEFAULTQ(
+				config->basicvirtual.defaultq);
+		cmd.u.basicvirtual.defaultq_to_udpen = cpu_to_be32(word);
+		break;
+	}
+
+	default:
+		return -EINVAL;
+	}
+
+	return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+}
+
+/**
+ *	t4vf_config_rss_range - configure a portion of the RSS mapping table
+ *	@adapter: the adapter
+ *	@viid: Virtual Interface of RSS Table Slice
+ *	@start: starting entry in the table to write
+ *	@n: how many table entries to write
+ *	@rspq: values for the "Response Queue" (Ingress Queue) lookup table
+ *	@nrspq: number of values in @rspq
+ *
+ *	Programs the selected part of the VI's RSS mapping table with the
+ *	provided values.  If @nrspq < @n the supplied values are used repeatedly
+ *	until the full table range is populated.
+ *
+ *	The caller must ensure the values in @rspq are in the range 0..1023.
+ */
+int t4vf_config_rss_range(struct adapter *adapter, unsigned int viid,
+			  int start, int n, const u16 *rspq, int nrspq)
+{
+	const u16 *rsp = rspq;
+	const u16 *rsp_end = rspq+nrspq;
+	struct fw_rss_ind_tbl_cmd cmd;
+
+	/*
+	 * Initialize firmware command template to write the RSS table.
+	 */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_IND_TBL_CMD) |
+				     FW_CMD_REQUEST |
+				     FW_CMD_WRITE |
+				     FW_RSS_IND_TBL_CMD_VIID(viid));
+	cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+
+	/*
+	 * Each firmware RSS command can accommodate up to 32 RSS Ingress
+	 * Queue Identifiers.  These Ingress Queue IDs are packed three to
+	 * a 32-bit word as 10-bit values with the upper remaining 2 bits
+	 * reserved.
+	 */
+	while (n > 0) {
+		__be32 *qp = &cmd.iq0_to_iq2;
+		int nq = min(n, 32);
+		int ret;
+
+		/*
+		 * Set up the firmware RSS command header to send the next
+		 * "nq" Ingress Queue IDs to the firmware.
+		 */
+		cmd.niqid = cpu_to_be16(nq);
+		cmd.startidx = cpu_to_be16(start);
+
+		/*
+		 * "nq" more done for the start of the next loop.
+		 */
+		start += nq;
+		n -= nq;
+
+		/*
+		 * While there are still Ingress Queue IDs to stuff into the
+		 * current firmware RSS command, retrieve them from the
+		 * Ingress Queue ID array and insert them into the command.
+		 */
+		while (nq > 0) {
+			/*
+			 * Grab up to the next 3 Ingress Queue IDs (wrapping
+			 * around the Ingress Queue ID array if necessary) and
+			 * insert them into the firmware RSS command at the
+			 * current 3-tuple position within the commad.
+			 */
+			u16 qbuf[3];
+			u16 *qbp = qbuf;
+			int nqbuf = min(3, nq);
+
+			nq -= nqbuf;
+			qbuf[0] = qbuf[1] = qbuf[2] = 0;
+			while (nqbuf) {
+				nqbuf--;
+				*qbp++ = *rsp++;
+				if (rsp >= rsp_end)
+					rsp = rspq;
+			}
+			*qp++ = cpu_to_be32(FW_RSS_IND_TBL_CMD_IQ0(qbuf[0]) |
+					    FW_RSS_IND_TBL_CMD_IQ1(qbuf[1]) |
+					    FW_RSS_IND_TBL_CMD_IQ2(qbuf[2]));
+		}
+
+		/*
+		 * Send this portion of the RRS table update to the firmware;
+		 * bail out on any errors.
+		 */
+		ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+/**
+ *	t4vf_alloc_vi - allocate a virtual interface on a port
+ *	@adapter: the adapter
+ *	@port_id: physical port associated with the VI
+ *
+ *	Allocate a new Virtual Interface and bind it to the indicated
+ *	physical port.  Return the new Virtual Interface Identifier on
+ *	success, or a [negative] error number on failure.
+ */
+int t4vf_alloc_vi(struct adapter *adapter, int port_id)
+{
+	struct fw_vi_cmd cmd, rpl;
+	int v;
+
+	/*
+	 * Execute a VI command to allocate Virtual Interface and return its
+	 * VIID.
+	 */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) |
+				    FW_CMD_REQUEST |
+				    FW_CMD_WRITE |
+				    FW_CMD_EXEC);
+	cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) |
+					 FW_VI_CMD_ALLOC);
+	cmd.portid_pkd = FW_VI_CMD_PORTID(port_id);
+	v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+	if (v)
+		return v;
+
+	return FW_VI_CMD_VIID_GET(be16_to_cpu(rpl.type_viid));
+}
+
+/**
+ *	t4vf_free_vi -- free a virtual interface
+ *	@adapter: the adapter
+ *	@viid: the virtual interface identifier
+ *
+ *	Free a previously allocated Virtual Interface.  Return an error on
+ *	failure.
+ */
+int t4vf_free_vi(struct adapter *adapter, int viid)
+{
+	struct fw_vi_cmd cmd;
+
+	/*
+	 * Execute a VI command to free the Virtual Interface.
+	 */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) |
+				    FW_CMD_REQUEST |
+				    FW_CMD_EXEC);
+	cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) |
+					 FW_VI_CMD_FREE);
+	cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID(viid));
+	return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
+ *	t4vf_enable_vi - enable/disable a virtual interface
+ *	@adapter: the adapter
+ *	@viid: the Virtual Interface ID
+ *	@rx_en: 1=enable Rx, 0=disable Rx
+ *	@tx_en: 1=enable Tx, 0=disable Tx
+ *
+ *	Enables/disables a virtual interface.
+ */
+int t4vf_enable_vi(struct adapter *adapter, unsigned int viid,
+		   bool rx_en, bool tx_en)
+{
+	struct fw_vi_enable_cmd cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_ENABLE_CMD) |
+				     FW_CMD_REQUEST |
+				     FW_CMD_EXEC |
+				     FW_VI_ENABLE_CMD_VIID(viid));
+	cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_IEN(rx_en) |
+				       FW_VI_ENABLE_CMD_EEN(tx_en) |
+				       FW_LEN16(cmd));
+	return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
+ *	t4vf_identify_port - identify a VI's port by blinking its LED
+ *	@adapter: the adapter
+ *	@viid: the Virtual Interface ID
+ *	@nblinks: how many times to blink LED at 2.5 Hz
+ *
+ *	Identifies a VI's port by blinking its LED.
+ */
+int t4vf_identify_port(struct adapter *adapter, unsigned int viid,
+		       unsigned int nblinks)
+{
+	struct fw_vi_enable_cmd cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_ENABLE_CMD) |
+				     FW_CMD_REQUEST |
+				     FW_CMD_EXEC |
+				     FW_VI_ENABLE_CMD_VIID(viid));
+	cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_LED |
+				       FW_LEN16(cmd));
+	cmd.blinkdur = cpu_to_be16(nblinks);
+	return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
+ *	t4vf_set_rxmode - set Rx properties of a virtual interface
+ *	@adapter: the adapter
+ *	@viid: the VI id
+ *	@mtu: the new MTU or -1 for no change
+ *	@promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change
+ *	@all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change
+ *	@bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change
+ *	@vlanex: 1 to enable hardware VLAN Tag extraction, 0 to disable it,
+ *		-1 no change
+ *
+ *	Sets Rx properties of a virtual interface.
+ */
+int t4vf_set_rxmode(struct adapter *adapter, unsigned int viid,
+		    int mtu, int promisc, int all_multi, int bcast, int vlanex,
+		    bool sleep_ok)
+{
+	struct fw_vi_rxmode_cmd cmd;
+
+	/* convert to FW values */
+	if (mtu < 0)
+		mtu = FW_VI_RXMODE_CMD_MTU_MASK;
+	if (promisc < 0)
+		promisc = FW_VI_RXMODE_CMD_PROMISCEN_MASK;
+	if (all_multi < 0)
+		all_multi = FW_VI_RXMODE_CMD_ALLMULTIEN_MASK;
+	if (bcast < 0)
+		bcast = FW_VI_RXMODE_CMD_BROADCASTEN_MASK;
+	if (vlanex < 0)
+		vlanex = FW_VI_RXMODE_CMD_VLANEXEN_MASK;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_RXMODE_CMD) |
+				     FW_CMD_REQUEST |
+				     FW_CMD_WRITE |
+				     FW_VI_RXMODE_CMD_VIID(viid));
+	cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+	cmd.mtu_to_vlanexen =
+		cpu_to_be32(FW_VI_RXMODE_CMD_MTU(mtu) |
+			    FW_VI_RXMODE_CMD_PROMISCEN(promisc) |
+			    FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) |
+			    FW_VI_RXMODE_CMD_BROADCASTEN(bcast) |
+			    FW_VI_RXMODE_CMD_VLANEXEN(vlanex));
+	return t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), NULL, sleep_ok);
+}
+
+/**
+ *	t4vf_alloc_mac_filt - allocates exact-match filters for MAC addresses
+ *	@adapter: the adapter
+ *	@viid: the Virtual Interface Identifier
+ *	@free: if true any existing filters for this VI id are first removed
+ *	@naddr: the number of MAC addresses to allocate filters for (up to 7)
+ *	@addr: the MAC address(es)
+ *	@idx: where to store the index of each allocated filter
+ *	@hash: pointer to hash address filter bitmap
+ *	@sleep_ok: call is allowed to sleep
+ *
+ *	Allocates an exact-match filter for each of the supplied addresses and
+ *	sets it to the corresponding address.  If @idx is not %NULL it should
+ *	have at least @naddr entries, each of which will be set to the index of
+ *	the filter allocated for the corresponding MAC address.  If a filter
+ *	could not be allocated for an address its index is set to 0xffff.
+ *	If @hash is not %NULL addresses that fail to allocate an exact filter
+ *	are hashed and update the hash filter bitmap pointed at by @hash.
+ *
+ *	Returns a negative error number or the number of filters allocated.
+ */
+int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free,
+			unsigned int naddr, const u8 **addr, u16 *idx,
+			u64 *hash, bool sleep_ok)
+{
+	int i, ret;
+	struct fw_vi_mac_cmd cmd, rpl;
+	struct fw_vi_mac_exact *p;
+	size_t len16;
+
+	if (naddr > ARRAY_SIZE(cmd.u.exact))
+		return -EINVAL;
+	len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
+				      u.exact[naddr]), 16);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
+				     FW_CMD_REQUEST |
+				     FW_CMD_WRITE |
+				     (free ? FW_CMD_EXEC : 0) |
+				     FW_VI_MAC_CMD_VIID(viid));
+	cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) |
+					    FW_CMD_LEN16(len16));
+
+	for (i = 0, p = cmd.u.exact; i < naddr; i++, p++) {
+		p->valid_to_idx =
+			cpu_to_be16(FW_VI_MAC_CMD_VALID |
+				    FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC));
+		memcpy(p->macaddr, addr[i], sizeof(p->macaddr));
+	}
+
+	ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, sleep_ok);
+	if (ret)
+		return ret;
+
+	for (i = 0, p = rpl.u.exact; i < naddr; i++, p++) {
+		u16 index = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx));
+
+		if (idx)
+			idx[i] = (index >= FW_CLS_TCAM_NUM_ENTRIES
+				  ? 0xffff
+				  : index);
+		if (index < FW_CLS_TCAM_NUM_ENTRIES)
+			ret++;
+		else if (hash)
+			*hash |= (1 << hash_mac_addr(addr[i]));
+	}
+	return ret;
+}
+
+/**
+ *	t4vf_change_mac - modifies the exact-match filter for a MAC address
+ *	@adapter: the adapter
+ *	@viid: the Virtual Interface ID
+ *	@idx: index of existing filter for old value of MAC address, or -1
+ *	@addr: the new MAC address value
+ *	@persist: if idx < 0, the new MAC allocation should be persistent
+ *
+ *	Modifies an exact-match filter and sets it to the new MAC address.
+ *	Note that in general it is not possible to modify the value of a given
+ *	filter so the generic way to modify an address filter is to free the
+ *	one being used by the old address value and allocate a new filter for
+ *	the new address value.  @idx can be -1 if the address is a new
+ *	addition.
+ *
+ *	Returns a negative error number or the index of the filter with the new
+ *	MAC value.
+ */
+int t4vf_change_mac(struct adapter *adapter, unsigned int viid,
+		    int idx, const u8 *addr, bool persist)
+{
+	int ret;
+	struct fw_vi_mac_cmd cmd, rpl;
+	struct fw_vi_mac_exact *p = &cmd.u.exact[0];
+	size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
+					     u.exact[1]), 16);
+
+	/*
+	 * If this is a new allocation, determine whether it should be
+	 * persistent (across a "freemacs" operation) or not.
+	 */
+	if (idx < 0)
+		idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
+				     FW_CMD_REQUEST |
+				     FW_CMD_WRITE |
+				     FW_VI_MAC_CMD_VIID(viid));
+	cmd.freemacs_to_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+	p->valid_to_idx = cpu_to_be16(FW_VI_MAC_CMD_VALID |
+				      FW_VI_MAC_CMD_IDX(idx));
+	memcpy(p->macaddr, addr, sizeof(p->macaddr));
+
+	ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+	if (ret == 0) {
+		p = &rpl.u.exact[0];
+		ret = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx));
+		if (ret >= FW_CLS_TCAM_NUM_ENTRIES)
+			ret = -ENOMEM;
+	}
+	return ret;
+}
+
+/**
+ *	t4vf_set_addr_hash - program the MAC inexact-match hash filter
+ *	@adapter: the adapter
+ *	@viid: the Virtual Interface Identifier
+ *	@ucast: whether the hash filter should also match unicast addresses
+ *	@vec: the value to be written to the hash filter
+ *	@sleep_ok: call is allowed to sleep
+ *
+ *	Sets the 64-bit inexact-match hash filter for a virtual interface.
+ */
+int t4vf_set_addr_hash(struct adapter *adapter, unsigned int viid,
+		       bool ucast, u64 vec, bool sleep_ok)
+{
+	struct fw_vi_mac_cmd cmd;
+	size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
+					     u.exact[0]), 16);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
+				     FW_CMD_REQUEST |
+				     FW_CMD_WRITE |
+				     FW_VI_ENABLE_CMD_VIID(viid));
+	cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_HASHVECEN |
+					    FW_VI_MAC_CMD_HASHUNIEN(ucast) |
+					    FW_CMD_LEN16(len16));
+	cmd.u.hash.hashvec = cpu_to_be64(vec);
+	return t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), NULL, sleep_ok);
+}
+
+/**
+ *	t4vf_get_port_stats - collect "port" statistics
+ *	@adapter: the adapter
+ *	@pidx: the port index
+ *	@s: the stats structure to fill
+ *
+ *	Collect statistics for the "port"'s Virtual Interface.
+ */
+int t4vf_get_port_stats(struct adapter *adapter, int pidx,
+			struct t4vf_port_stats *s)
+{
+	struct port_info *pi = adap2pinfo(adapter, pidx);
+	struct fw_vi_stats_vf fwstats;
+	unsigned int rem = VI_VF_NUM_STATS;
+	__be64 *fwsp = (__be64 *)&fwstats;
+
+	/*
+	 * Grab the Virtual Interface statistics a chunk at a time via mailbox
+	 * commands.  We could use a Work Request and get all of them at once
+	 * but that's an asynchronous interface which is awkward to use.
+	 */
+	while (rem) {
+		unsigned int ix = VI_VF_NUM_STATS - rem;
+		unsigned int nstats = min(6U, rem);
+		struct fw_vi_stats_cmd cmd, rpl;
+		size_t len = (offsetof(struct fw_vi_stats_cmd, u) +
+			      sizeof(struct fw_vi_stats_ctl));
+		size_t len16 = DIV_ROUND_UP(len, 16);
+		int ret;
+
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_STATS_CMD) |
+					     FW_VI_STATS_CMD_VIID(pi->viid) |
+					     FW_CMD_REQUEST |
+					     FW_CMD_READ);
+		cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+		cmd.u.ctl.nstats_ix =
+			cpu_to_be16(FW_VI_STATS_CMD_IX(ix) |
+				    FW_VI_STATS_CMD_NSTATS(nstats));
+		ret = t4vf_wr_mbox_ns(adapter, &cmd, len, &rpl);
+		if (ret)
+			return ret;
+
+		memcpy(fwsp, &rpl.u.ctl.stat0, sizeof(__be64) * nstats);
+
+		rem -= nstats;
+		fwsp += nstats;
+	}
+
+	/*
+	 * Translate firmware statistics into host native statistics.
+	 */
+	s->tx_bcast_bytes = be64_to_cpu(fwstats.tx_bcast_bytes);
+	s->tx_bcast_frames = be64_to_cpu(fwstats.tx_bcast_frames);
+	s->tx_mcast_bytes = be64_to_cpu(fwstats.tx_mcast_bytes);
+	s->tx_mcast_frames = be64_to_cpu(fwstats.tx_mcast_frames);
+	s->tx_ucast_bytes = be64_to_cpu(fwstats.tx_ucast_bytes);
+	s->tx_ucast_frames = be64_to_cpu(fwstats.tx_ucast_frames);
+	s->tx_drop_frames = be64_to_cpu(fwstats.tx_drop_frames);
+	s->tx_offload_bytes = be64_to_cpu(fwstats.tx_offload_bytes);
+	s->tx_offload_frames = be64_to_cpu(fwstats.tx_offload_frames);
+
+	s->rx_bcast_bytes = be64_to_cpu(fwstats.rx_bcast_bytes);
+	s->rx_bcast_frames = be64_to_cpu(fwstats.rx_bcast_frames);
+	s->rx_mcast_bytes = be64_to_cpu(fwstats.rx_mcast_bytes);
+	s->rx_mcast_frames = be64_to_cpu(fwstats.rx_mcast_frames);
+	s->rx_ucast_bytes = be64_to_cpu(fwstats.rx_ucast_bytes);
+	s->rx_ucast_frames = be64_to_cpu(fwstats.rx_ucast_frames);
+
+	s->rx_err_frames = be64_to_cpu(fwstats.rx_err_frames);
+
+	return 0;
+}
+
+/**
+ *	t4vf_iq_free - free an ingress queue and its free lists
+ *	@adapter: the adapter
+ *	@iqtype: the ingress queue type (FW_IQ_TYPE_FL_INT_CAP, etc.)
+ *	@iqid: ingress queue ID
+ *	@fl0id: FL0 queue ID or 0xffff if no attached FL0
+ *	@fl1id: FL1 queue ID or 0xffff if no attached FL1
+ *
+ *	Frees an ingress queue and its associated free lists, if any.
+ */
+int t4vf_iq_free(struct adapter *adapter, unsigned int iqtype,
+		 unsigned int iqid, unsigned int fl0id, unsigned int fl1id)
+{
+	struct fw_iq_cmd cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_IQ_CMD) |
+				    FW_CMD_REQUEST |
+				    FW_CMD_EXEC);
+	cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_FREE |
+					 FW_LEN16(cmd));
+	cmd.type_to_iqandstindex =
+		cpu_to_be32(FW_IQ_CMD_TYPE(iqtype));
+
+	cmd.iqid = cpu_to_be16(iqid);
+	cmd.fl0id = cpu_to_be16(fl0id);
+	cmd.fl1id = cpu_to_be16(fl1id);
+	return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
+ *	t4vf_eth_eq_free - free an Ethernet egress queue
+ *	@adapter: the adapter
+ *	@eqid: egress queue ID
+ *
+ *	Frees an Ethernet egress queue.
+ */
+int t4vf_eth_eq_free(struct adapter *adapter, unsigned int eqid)
+{
+	struct fw_eq_eth_cmd cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_EQ_ETH_CMD) |
+				    FW_CMD_REQUEST |
+				    FW_CMD_EXEC);
+	cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_FREE |
+					 FW_LEN16(cmd));
+	cmd.eqid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_EQID(eqid));
+	return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
+ *	t4vf_handle_fw_rpl - process a firmware reply message
+ *	@adapter: the adapter
+ *	@rpl: start of the firmware message
+ *
+ *	Processes a firmware message, such as link state change messages.
+ */
+int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
+{
+	struct fw_cmd_hdr *cmd_hdr = (struct fw_cmd_hdr *)rpl;
+	u8 opcode = FW_CMD_OP_GET(be32_to_cpu(cmd_hdr->hi));
+
+	switch (opcode) {
+	case FW_PORT_CMD: {
+		/*
+		 * Link/module state change message.
+		 */
+		const struct fw_port_cmd *port_cmd = (void *)rpl;
+		u32 word;
+		int action, port_id, link_ok, speed, fc, pidx;
+
+		/*
+		 * Extract various fields from port status change message.
+		 */
+		action = FW_PORT_CMD_ACTION_GET(
+			be32_to_cpu(port_cmd->action_to_len16));
+		if (action != FW_PORT_ACTION_GET_PORT_INFO) {
+			dev_err(adapter->pdev_dev,
+				"Unknown firmware PORT reply action %x\n",
+				action);
+			break;
+		}
+
+		port_id = FW_PORT_CMD_PORTID_GET(
+			be32_to_cpu(port_cmd->op_to_portid));
+
+		word = be32_to_cpu(port_cmd->u.info.lstatus_to_modtype);
+		link_ok = (word & FW_PORT_CMD_LSTATUS) != 0;
+		speed = 0;
+		fc = 0;
+		if (word & FW_PORT_CMD_RXPAUSE)
+			fc |= PAUSE_RX;
+		if (word & FW_PORT_CMD_TXPAUSE)
+			fc |= PAUSE_TX;
+		if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M))
+			speed = SPEED_100;
+		else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G))
+			speed = SPEED_1000;
+		else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G))
+			speed = SPEED_10000;
+
+		/*
+		 * Scan all of our "ports" (Virtual Interfaces) looking for
+		 * those bound to the physical port which has changed.  If
+		 * our recorded state doesn't match the current state,
+		 * signal that change to the OS code.
+		 */
+		for_each_port(adapter, pidx) {
+			struct port_info *pi = adap2pinfo(adapter, pidx);
+			struct link_config *lc;
+
+			if (pi->port_id != port_id)
+				continue;
+
+			lc = &pi->link_cfg;
+			if (link_ok != lc->link_ok || speed != lc->speed ||
+			    fc != lc->fc) {
+				/* something changed */
+				lc->link_ok = link_ok;
+				lc->speed = speed;
+				lc->fc = fc;
+				t4vf_os_link_changed(adapter, pidx, link_ok);
+			}
+		}
+		break;
+	}
+
+	default:
+		dev_err(adapter->pdev_dev, "Unknown firmware reply %X\n",
+			opcode);
+	}
+	return 0;
+}
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index 08e82b1..d0824e3 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -298,6 +298,11 @@
 #define EMAC_CTRL_EWCTL		(0x4)
 #define EMAC_CTRL_EWINTTCNT	(0x8)
 
+/* EMAC DM644x control module masks */
+#define EMAC_DM644X_EWINTCNT_MASK	0x1FFFF
+#define EMAC_DM644X_INTMIN_INTVL	0x1
+#define EMAC_DM644X_INTMAX_INTVL	(EMAC_DM644X_EWINTCNT_MASK)
+
 /* EMAC MDIO related */
 /* Mask & Control defines */
 #define MDIO_CONTROL_CLKDIV	(0xFF)
@@ -318,8 +323,20 @@
 #define MDIO_CONTROL		(0x04)
 
 /* EMAC DM646X control module registers */
-#define EMAC_DM646X_CMRXINTEN	(0x14)
-#define EMAC_DM646X_CMTXINTEN	(0x18)
+#define EMAC_DM646X_CMINTCTRL	0x0C
+#define EMAC_DM646X_CMRXINTEN	0x14
+#define EMAC_DM646X_CMTXINTEN	0x18
+#define EMAC_DM646X_CMRXINTMAX	0x70
+#define EMAC_DM646X_CMTXINTMAX	0x74
+
+/* EMAC DM646X control module masks */
+#define EMAC_DM646X_INTPACEEN		(0x3 << 16)
+#define EMAC_DM646X_INTPRESCALE_MASK	(0x7FF << 0)
+#define EMAC_DM646X_CMINTMAX_CNT	63
+#define EMAC_DM646X_CMINTMIN_CNT	2
+#define EMAC_DM646X_CMINTMAX_INTVL	(1000 / EMAC_DM646X_CMINTMIN_CNT)
+#define EMAC_DM646X_CMINTMIN_INTVL	((1000 / EMAC_DM646X_CMINTMAX_CNT) + 1)
+
 
 /* EMAC EOI codes for C0 */
 #define EMAC_DM646X_MAC_EOI_C0_RXEN	(0x01)
@@ -468,9 +485,10 @@
 	u32 duplex; /* Link duplex: 0=Half, 1=Full */
 	u32 rx_buf_size;
 	u32 isr_count;
+	u32 coal_intvl;
+	u32 bus_freq_mhz;
 	u8 rmii_en;
 	u8 version;
-	struct net_device_stats net_dev_stats;
 	u32 mac_hash1;
 	u32 mac_hash2;
 	u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS];
@@ -546,9 +564,11 @@
 
 	/* Print important registers in EMAC */
 	dev_info(emac_dev, "EMAC Basic registers\n");
-	dev_info(emac_dev, "EMAC: EWCTL: %08X, EWINTTCNT: %08X\n",
-		emac_ctrl_read(EMAC_CTRL_EWCTL),
-		emac_ctrl_read(EMAC_CTRL_EWINTTCNT));
+	if (priv->version == EMAC_VERSION_1) {
+		dev_info(emac_dev, "EMAC: EWCTL: %08X, EWINTTCNT: %08X\n",
+			emac_ctrl_read(EMAC_CTRL_EWCTL),
+			emac_ctrl_read(EMAC_CTRL_EWINTTCNT));
+	}
 	dev_info(emac_dev, "EMAC: TXID: %08X %s, RXID: %08X %s\n",
 		emac_read(EMAC_TXIDVER),
 		((emac_read(EMAC_TXCONTROL)) ? "enabled" : "disabled"),
@@ -692,6 +712,103 @@
 }
 
 /**
+ * emac_get_coalesce : Get interrupt coalesce settings for this device
+ * @ndev : The DaVinci EMAC network adapter
+ * @coal : ethtool coalesce settings structure
+ *
+ * Fetch the current interrupt coalesce settings
+ *
+ */
+static int emac_get_coalesce(struct net_device *ndev,
+				struct ethtool_coalesce *coal)
+{
+	struct emac_priv *priv = netdev_priv(ndev);
+
+	coal->rx_coalesce_usecs = priv->coal_intvl;
+	return 0;
+
+}
+
+/**
+ * emac_set_coalesce : Set interrupt coalesce settings for this device
+ * @ndev : The DaVinci EMAC network adapter
+ * @coal : ethtool coalesce settings structure
+ *
+ * Set interrupt coalesce parameters
+ *
+ */
+static int emac_set_coalesce(struct net_device *ndev,
+				struct ethtool_coalesce *coal)
+{
+	struct emac_priv *priv = netdev_priv(ndev);
+	u32 int_ctrl, num_interrupts = 0;
+	u32 prescale = 0, addnl_dvdr = 1, coal_intvl = 0;
+
+	if (!coal->rx_coalesce_usecs)
+		return -EINVAL;
+
+	coal_intvl = coal->rx_coalesce_usecs;
+
+	switch (priv->version) {
+	case EMAC_VERSION_2:
+		int_ctrl =  emac_ctrl_read(EMAC_DM646X_CMINTCTRL);
+		prescale = priv->bus_freq_mhz * 4;
+
+		if (coal_intvl < EMAC_DM646X_CMINTMIN_INTVL)
+			coal_intvl = EMAC_DM646X_CMINTMIN_INTVL;
+
+		if (coal_intvl > EMAC_DM646X_CMINTMAX_INTVL) {
+			/*
+			 * Interrupt pacer works with 4us Pulse, we can
+			 * throttle further by dilating the 4us pulse.
+			 */
+			addnl_dvdr = EMAC_DM646X_INTPRESCALE_MASK / prescale;
+
+			if (addnl_dvdr > 1) {
+				prescale *= addnl_dvdr;
+				if (coal_intvl > (EMAC_DM646X_CMINTMAX_INTVL
+							* addnl_dvdr))
+					coal_intvl = (EMAC_DM646X_CMINTMAX_INTVL
+							* addnl_dvdr);
+			} else {
+				addnl_dvdr = 1;
+				coal_intvl = EMAC_DM646X_CMINTMAX_INTVL;
+			}
+		}
+
+		num_interrupts = (1000 * addnl_dvdr) / coal_intvl;
+
+		int_ctrl |= EMAC_DM646X_INTPACEEN;
+		int_ctrl &= (~EMAC_DM646X_INTPRESCALE_MASK);
+		int_ctrl |= (prescale & EMAC_DM646X_INTPRESCALE_MASK);
+		emac_ctrl_write(EMAC_DM646X_CMINTCTRL, int_ctrl);
+
+		emac_ctrl_write(EMAC_DM646X_CMRXINTMAX, num_interrupts);
+		emac_ctrl_write(EMAC_DM646X_CMTXINTMAX, num_interrupts);
+
+		break;
+	default:
+		int_ctrl = emac_ctrl_read(EMAC_CTRL_EWINTTCNT);
+		int_ctrl &= (~EMAC_DM644X_EWINTCNT_MASK);
+		prescale = coal_intvl * priv->bus_freq_mhz;
+		if (prescale > EMAC_DM644X_EWINTCNT_MASK) {
+			prescale = EMAC_DM644X_EWINTCNT_MASK;
+			coal_intvl = prescale / priv->bus_freq_mhz;
+		}
+		emac_ctrl_write(EMAC_CTRL_EWINTTCNT, (int_ctrl | prescale));
+
+		break;
+	}
+
+	printk(KERN_INFO"Set coalesce to %d usecs.\n", coal_intvl);
+	priv->coal_intvl = coal_intvl;
+
+	return 0;
+
+}
+
+
+/**
  * ethtool_ops: DaVinci EMAC Ethtool structure
  *
  * Ethtool support for EMAC adapter
@@ -702,6 +819,8 @@
 	.get_settings = emac_get_settings,
 	.set_settings = emac_set_settings,
 	.get_link = ethtool_op_get_link,
+	.get_coalesce = emac_get_coalesce,
+	.set_coalesce =  emac_set_coalesce,
 };
 
 /**
@@ -1180,16 +1299,17 @@
 				void **net_data_tokens,
 				int num_tokens, u32 ch)
 {
+	struct net_device *ndev = priv->ndev;
 	u32 cnt;
 
-	if (unlikely(num_tokens && netif_queue_stopped(priv->ndev)))
-		netif_start_queue(priv->ndev);
+	if (unlikely(num_tokens && netif_queue_stopped(ndev)))
+		netif_start_queue(ndev);
 	for (cnt = 0; cnt < num_tokens; cnt++) {
 		struct sk_buff *skb = (struct sk_buff *)net_data_tokens[cnt];
 		if (skb == NULL)
 			continue;
-		priv->net_dev_stats.tx_packets++;
-		priv->net_dev_stats.tx_bytes += skb->len;
+		ndev->stats.tx_packets++;
+		ndev->stats.tx_bytes += skb->len;
 		dev_kfree_skb_any(skb);
 	}
 	return 0;
@@ -1476,7 +1596,7 @@
 					" err. Out of TX BD's");
 			netif_stop_queue(priv->ndev);
 		}
-		priv->net_dev_stats.tx_dropped++;
+		ndev->stats.tx_dropped++;
 		return NETDEV_TX_BUSY;
 	}
 
@@ -1501,7 +1621,7 @@
 	if (netif_msg_tx_err(priv))
 		dev_err(emac_dev, "DaVinci EMAC: xmit timeout, restarting TX");
 
-	priv->net_dev_stats.tx_errors++;
+	ndev->stats.tx_errors++;
 	emac_int_disable(priv);
 	emac_stop_txch(priv, EMAC_DEF_TX_CH);
 	emac_cleanup_txch(priv, EMAC_DEF_TX_CH);
@@ -1926,14 +2046,14 @@
 static int emac_net_rx_cb(struct emac_priv *priv,
 			  struct emac_netpktobj *net_pkt_list)
 {
-	struct sk_buff *p_skb;
-	p_skb = (struct sk_buff *)net_pkt_list->pkt_token;
+	struct net_device *ndev = priv->ndev;
+	struct sk_buff *p_skb = net_pkt_list->pkt_token;
 	/* set length of packet */
 	skb_put(p_skb, net_pkt_list->pkt_length);
 	p_skb->protocol = eth_type_trans(p_skb, priv->ndev);
 	netif_receive_skb(p_skb);
-	priv->net_dev_stats.rx_bytes += net_pkt_list->pkt_length;
-	priv->net_dev_stats.rx_packets++;
+	ndev->stats.rx_bytes += net_pkt_list->pkt_length;
+	ndev->stats.rx_packets++;
 	return 0;
 }
 
@@ -2148,7 +2268,7 @@
 	struct net_device *ndev = priv->ndev;
 	struct device *emac_dev = &ndev->dev;
 	u32 status = 0;
-	u32 num_pkts = 0;
+	u32 num_tx_pkts = 0, num_rx_pkts = 0;
 
 	/* Check interrupt vectors and call packet processing */
 	status = emac_read(EMAC_MACINVECTOR);
@@ -2159,27 +2279,19 @@
 		mask = EMAC_DM646X_MAC_IN_VECTOR_TX_INT_VEC;
 
 	if (status & mask) {
-		num_pkts = emac_tx_bdproc(priv, EMAC_DEF_TX_CH,
+		num_tx_pkts = emac_tx_bdproc(priv, EMAC_DEF_TX_CH,
 					  EMAC_DEF_TX_MAX_SERVICE);
 	} /* TX processing */
 
-	if (num_pkts)
-		return budget;
-
 	mask = EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC;
 
 	if (priv->version == EMAC_VERSION_2)
 		mask = EMAC_DM646X_MAC_IN_VECTOR_RX_INT_VEC;
 
 	if (status & mask) {
-		num_pkts = emac_rx_bdproc(priv, EMAC_DEF_RX_CH, budget);
+		num_rx_pkts = emac_rx_bdproc(priv, EMAC_DEF_RX_CH, budget);
 	} /* RX processing */
 
-	if (num_pkts < budget) {
-		napi_complete(napi);
-		emac_int_enable(priv);
-	}
-
 	mask = EMAC_DM644X_MAC_IN_VECTOR_HOST_INT;
 	if (priv->version == EMAC_VERSION_2)
 		mask = EMAC_DM646X_MAC_IN_VECTOR_HOST_INT;
@@ -2210,9 +2322,12 @@
 				dev_err(emac_dev, "RX Host error %s on ch=%d\n",
 					&emac_rxhost_errcodes[cause][0], ch);
 		}
-	} /* Host error processing */
+	} else if (num_rx_pkts < budget) {
+		napi_complete(napi);
+		emac_int_enable(priv);
+	}
 
-	return num_pkts;
+	return num_rx_pkts;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2437,6 +2552,14 @@
 	/* Start/Enable EMAC hardware */
 	emac_hw_enable(priv);
 
+	/* Enable Interrupt pacing if configured */
+	if (priv->coal_intvl != 0) {
+		struct ethtool_coalesce coal;
+
+		coal.rx_coalesce_usecs = (priv->coal_intvl << 4);
+		emac_set_coalesce(ndev, &coal);
+	}
+
 	/* find the first phy */
 	priv->phydev = NULL;
 	if (priv->phy_mask) {
@@ -2570,39 +2693,39 @@
 	else
 		stats_clear_mask = 0;
 
-	priv->net_dev_stats.multicast += emac_read(EMAC_RXMCASTFRAMES);
+	ndev->stats.multicast += emac_read(EMAC_RXMCASTFRAMES);
 	emac_write(EMAC_RXMCASTFRAMES, stats_clear_mask);
 
-	priv->net_dev_stats.collisions += (emac_read(EMAC_TXCOLLISION) +
+	ndev->stats.collisions += (emac_read(EMAC_TXCOLLISION) +
 					   emac_read(EMAC_TXSINGLECOLL) +
 					   emac_read(EMAC_TXMULTICOLL));
 	emac_write(EMAC_TXCOLLISION, stats_clear_mask);
 	emac_write(EMAC_TXSINGLECOLL, stats_clear_mask);
 	emac_write(EMAC_TXMULTICOLL, stats_clear_mask);
 
-	priv->net_dev_stats.rx_length_errors += (emac_read(EMAC_RXOVERSIZED) +
+	ndev->stats.rx_length_errors += (emac_read(EMAC_RXOVERSIZED) +
 						emac_read(EMAC_RXJABBER) +
 						emac_read(EMAC_RXUNDERSIZED));
 	emac_write(EMAC_RXOVERSIZED, stats_clear_mask);
 	emac_write(EMAC_RXJABBER, stats_clear_mask);
 	emac_write(EMAC_RXUNDERSIZED, stats_clear_mask);
 
-	priv->net_dev_stats.rx_over_errors += (emac_read(EMAC_RXSOFOVERRUNS) +
+	ndev->stats.rx_over_errors += (emac_read(EMAC_RXSOFOVERRUNS) +
 					       emac_read(EMAC_RXMOFOVERRUNS));
 	emac_write(EMAC_RXSOFOVERRUNS, stats_clear_mask);
 	emac_write(EMAC_RXMOFOVERRUNS, stats_clear_mask);
 
-	priv->net_dev_stats.rx_fifo_errors += emac_read(EMAC_RXDMAOVERRUNS);
+	ndev->stats.rx_fifo_errors += emac_read(EMAC_RXDMAOVERRUNS);
 	emac_write(EMAC_RXDMAOVERRUNS, stats_clear_mask);
 
-	priv->net_dev_stats.tx_carrier_errors +=
+	ndev->stats.tx_carrier_errors +=
 		emac_read(EMAC_TXCARRIERSENSE);
 	emac_write(EMAC_TXCARRIERSENSE, stats_clear_mask);
 
-	priv->net_dev_stats.tx_fifo_errors = emac_read(EMAC_TXUNDERRUN);
+	ndev->stats.tx_fifo_errors = emac_read(EMAC_TXUNDERRUN);
 	emac_write(EMAC_TXUNDERRUN, stats_clear_mask);
 
-	return &priv->net_dev_stats;
+	return &ndev->stats;
 }
 
 static const struct net_device_ops emac_netdev_ops = {
@@ -2677,6 +2800,9 @@
 	priv->int_enable = pdata->interrupt_enable;
 	priv->int_disable = pdata->interrupt_disable;
 
+	priv->coal_intvl = 0;
+	priv->bus_freq_mhz = (u32)(emac_bus_frequency / 1000000);
+
 	emac_dev = &ndev->dev;
 	/* Get EMAC platform data */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index bf66e9b..44c0694 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -2061,18 +2061,35 @@
 
 static int __init depca_module_init (void)
 {
-        int err = 0;
+	int err = 0;
 
 #ifdef CONFIG_MCA
-        err = mca_register_driver (&depca_mca_driver);
+	err = mca_register_driver(&depca_mca_driver);
+	if (err)
+		goto err;
 #endif
 #ifdef CONFIG_EISA
-        err |= eisa_driver_register (&depca_eisa_driver);
+	err = eisa_driver_register(&depca_eisa_driver);
+	if (err)
+		goto err_mca;
 #endif
-	err |= platform_driver_register (&depca_isa_driver);
-	depca_platform_probe ();
+	err = platform_driver_register(&depca_isa_driver);
+	if (err)
+		goto err_eisa;
 
-        return err;
+	depca_platform_probe();
+	return 0;
+
+err_eisa:
+#ifdef CONFIG_EISA
+	eisa_driver_unregister(&depca_eisa_driver);
+err_mca:
+#endif
+#ifdef CONFIG_MCA
+	mca_unregister_driver(&depca_mca_driver);
+err:
+#endif
+	return err;
 }
 
 static void __exit depca_module_exit (void)
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index abcc838..4fd6b2b 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -961,7 +961,7 @@
 	u8	RxPktReady;
 	u8	RxStatus;
 	__le16	RxLen;
-} __attribute__((__packed__));
+} __packed;
 
 /*
  *  Received a packet and pass to upper layer
diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c
index 8b0f50b..7c07575 100644
--- a/drivers/net/dnet.c
+++ b/drivers/net/dnet.c
@@ -797,7 +797,7 @@
 	if (!phydev)
 		return -ENODEV;
 
-	return phy_mii_ioctl(phydev, if_mii(rq), cmd);
+	return phy_mii_ioctl(phydev, rq, cmd);
 }
 
 static void dnet_get_drvinfo(struct net_device *dev,
@@ -854,7 +854,7 @@
 	dev = alloc_etherdev(sizeof(*bp));
 	if (!dev) {
 		dev_err(&pdev->dev, "etherdev alloc failed, aborting.\n");
-		goto err_out;
+		goto err_out_release_mem;
 	}
 
 	/* TODO: Actually, we have some interesting features... */
@@ -911,7 +911,8 @@
 	if (err)
 		dev_warn(&pdev->dev, "Cannot register PHY board fixup.\n");
 
-	if (dnet_mii_init(bp) != 0)
+	err = dnet_mii_init(bp);
+	if (err)
 		goto err_out_unregister_netdev;
 
 	dev_info(&pdev->dev, "Dave DNET at 0x%p (0x%08x) irq %d %pM\n",
@@ -936,6 +937,8 @@
 	iounmap(bp->regs);
 err_out_free_dev:
 	free_netdev(dev);
+err_out_release_mem:
+	release_mem_region(mem_base, mem_size);
 err_out:
 	return err;
 }
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 40b62b4..99288b9 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -86,12 +86,12 @@
 /* TX/RX descriptor defines */
 #define E1000_DEFAULT_TXD                  256
 #define E1000_MAX_TXD                      256
-#define E1000_MIN_TXD                       80
+#define E1000_MIN_TXD                       48
 #define E1000_MAX_82544_TXD               4096
 
 #define E1000_DEFAULT_RXD                  256
 #define E1000_MAX_RXD                      256
-#define E1000_MIN_RXD                       80
+#define E1000_MIN_RXD                       48
 #define E1000_MAX_82544_RXD               4096
 
 #define E1000_MIN_ITR_USECS		10 /* 100000 irq/sec */
@@ -324,18 +324,20 @@
 extern struct net_device *e1000_get_hw_dev(struct e1000_hw *hw);
 #define e_dbg(format, arg...) \
 	netdev_dbg(e1000_get_hw_dev(hw), format, ## arg)
-#define e_err(format, arg...) \
-	netdev_err(adapter->netdev, format, ## arg)
-#define e_info(format, arg...) \
-	netdev_info(adapter->netdev, format, ## arg)
-#define e_warn(format, arg...) \
-	netdev_warn(adapter->netdev, format, ## arg)
-#define e_notice(format, arg...) \
-	netdev_notice(adapter->netdev, format, ## arg)
+#define e_err(msglvl, format, arg...) \
+	netif_err(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_info(msglvl, format, arg...) \
+	netif_info(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_warn(msglvl, format, arg...) \
+	netif_warn(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_notice(msglvl, format, arg...) \
+	netif_notice(adapter, msglvl, adapter->netdev, format, ## arg)
 #define e_dev_info(format, arg...) \
 	dev_info(&adapter->pdev->dev, format, ## arg)
 #define e_dev_warn(format, arg...) \
 	dev_warn(&adapter->pdev->dev, format, ## arg)
+#define e_dev_err(format, arg...) \
+	dev_err(&adapter->pdev->dev, format, ## arg)
 
 extern char e1000_driver_name[];
 extern const char e1000_driver_version[];
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index d5ff029..f4d0922 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -346,7 +346,7 @@
 
 	netdev->features &= ~NETIF_F_TSO6;
 
-	e_info("TSO is %s\n", data ? "Enabled" : "Disabled");
+	e_info(probe, "TSO is %s\n", data ? "Enabled" : "Disabled");
 	adapter->tso_force = true;
 	return 0;
 }
@@ -714,9 +714,9 @@
 		writel(write & test[i], address);
 		read = readl(address);
 		if (read != (write & test[i] & mask)) {
-			e_info("pattern test reg %04X failed: "
-			       "got 0x%08X expected 0x%08X\n",
-			       reg, read, (write & test[i] & mask));
+			e_err(drv, "pattern test reg %04X failed: "
+			      "got 0x%08X expected 0x%08X\n",
+			      reg, read, (write & test[i] & mask));
 			*data = reg;
 			return true;
 		}
@@ -734,7 +734,7 @@
 	writel(write & mask, address);
 	read = readl(address);
 	if ((read & mask) != (write & mask)) {
-		e_err("set/check reg %04X test failed: "
+		e_err(drv, "set/check reg %04X test failed: "
 		      "got 0x%08X expected 0x%08X\n",
 		      reg, (read & mask), (write & mask));
 		*data = reg;
@@ -779,7 +779,7 @@
 	ew32(STATUS, toggle);
 	after = er32(STATUS) & toggle;
 	if (value != after) {
-		e_err("failed STATUS register test got: "
+		e_err(drv, "failed STATUS register test got: "
 		      "0x%08X expected: 0x%08X\n", after, value);
 		*data = 1;
 		return 1;
@@ -894,7 +894,8 @@
 		*data = 1;
 		return -1;
 	}
-	e_info("testing %s interrupt\n", (shared_int ? "shared" : "unshared"));
+	e_info(hw, "testing %s interrupt\n", (shared_int ?
+	       "shared" : "unshared"));
 
 	/* Disable all the interrupts */
 	ew32(IMC, 0xFFFFFFFF);
@@ -1561,7 +1562,7 @@
 		u8 forced_speed_duplex = hw->forced_speed_duplex;
 		u8 autoneg = hw->autoneg;
 
-		e_info("offline testing starting\n");
+		e_info(hw, "offline testing starting\n");
 
 		/* Link test performed before hardware reset so autoneg doesn't
 		 * interfere with test result */
@@ -1601,7 +1602,7 @@
 		if (if_running)
 			dev_open(netdev);
 	} else {
-		e_info("online testing starting\n");
+		e_info(hw, "online testing starting\n");
 		/* Online tests */
 		if (e1000_link_test(adapter, &data[4]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1694,8 +1695,8 @@
 		wol->supported &= ~WAKE_UCAST;
 
 		if (adapter->wol & E1000_WUFC_EX)
-			e_err("Interface does not support "
-		        "directed (unicast) frame wake-up packets\n");
+			e_err(drv, "Interface does not support directed "
+			      "(unicast) frame wake-up packets\n");
 		break;
 	default:
 		break;
@@ -1726,8 +1727,8 @@
 	switch (hw->device_id) {
 	case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
 		if (wol->wolopts & WAKE_UCAST) {
-			e_err("Interface does not support "
-			      "directed (unicast) frame wake-up packets\n");
+			e_err(drv, "Interface does not support directed "
+			      "(unicast) frame wake-up packets\n");
 			return -EOPNOTSUPP;
 		}
 		break;
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 68a8089..02833af 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -275,7 +275,7 @@
 	err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,
 	                  netdev);
 	if (err) {
-		e_err("Unable to allocate interrupt Error: %d\n", err);
+		e_err(probe, "Unable to allocate interrupt Error: %d\n", err);
 	}
 
 	return err;
@@ -657,7 +657,7 @@
 		ew32(WUC, 0);
 
 	if (e1000_init_hw(hw))
-		e_err("Hardware Error\n");
+		e_dev_err("Hardware Error\n");
 	e1000_update_mng_vlan(adapter);
 
 	/* if (adapter->hwflags & HWFLAGS_PHY_PWR_BIT) { */
@@ -925,7 +925,7 @@
 
 	/* initialize eeprom parameters */
 	if (e1000_init_eeprom_params(hw)) {
-		e_err("EEPROM initialization failed\n");
+		e_err(probe, "EEPROM initialization failed\n");
 		goto err_eeprom;
 	}
 
@@ -936,7 +936,7 @@
 
 	/* make sure the EEPROM is good */
 	if (e1000_validate_eeprom_checksum(hw) < 0) {
-		e_err("The EEPROM Checksum Is Not Valid\n");
+		e_err(probe, "The EEPROM Checksum Is Not Valid\n");
 		e1000_dump_eeprom(adapter);
 		/*
 		 * set MAC address to all zeroes to invalidate and temporary
@@ -950,14 +950,14 @@
 	} else {
 		/* copy the MAC address out of the EEPROM */
 		if (e1000_read_mac_addr(hw))
-			e_err("EEPROM Read Error\n");
+			e_err(probe, "EEPROM Read Error\n");
 	}
 	/* don't block initalization here due to bad MAC address */
 	memcpy(netdev->dev_addr, hw->mac_addr, netdev->addr_len);
 	memcpy(netdev->perm_addr, hw->mac_addr, netdev->addr_len);
 
 	if (!is_valid_ether_addr(netdev->perm_addr))
-		e_err("Invalid MAC Address\n");
+		e_err(probe, "Invalid MAC Address\n");
 
 	e1000_get_bus_info(hw);
 
@@ -1047,7 +1047,7 @@
 		goto err_register;
 
 	/* print bus type/speed/width info */
-	e_info("(PCI%s:%dMHz:%d-bit) %pM\n",
+	e_info(probe, "(PCI%s:%dMHz:%d-bit) %pM\n",
 	       ((hw->bus_type == e1000_bus_type_pcix) ? "-X" : ""),
 	       ((hw->bus_speed == e1000_bus_speed_133) ? 133 :
 		(hw->bus_speed == e1000_bus_speed_120) ? 120 :
@@ -1059,7 +1059,7 @@
 	/* carrier off reporting is important to ethtool even BEFORE open */
 	netif_carrier_off(netdev);
 
-	e_info("Intel(R) PRO/1000 Network Connection\n");
+	e_info(probe, "Intel(R) PRO/1000 Network Connection\n");
 
 	cards_found++;
 	return 0;
@@ -1159,7 +1159,7 @@
 	/* identify the MAC */
 
 	if (e1000_set_mac_type(hw)) {
-		e_err("Unknown MAC Type\n");
+		e_err(probe, "Unknown MAC Type\n");
 		return -EIO;
 	}
 
@@ -1192,7 +1192,7 @@
 	adapter->num_rx_queues = 1;
 
 	if (e1000_alloc_queues(adapter)) {
-		e_err("Unable to allocate memory for queues\n");
+		e_err(probe, "Unable to allocate memory for queues\n");
 		return -ENOMEM;
 	}
 
@@ -1386,7 +1386,8 @@
 	size = sizeof(struct e1000_buffer) * txdr->count;
 	txdr->buffer_info = vmalloc(size);
 	if (!txdr->buffer_info) {
-		e_err("Unable to allocate memory for the Tx descriptor ring\n");
+		e_err(probe, "Unable to allocate memory for the Tx descriptor "
+		      "ring\n");
 		return -ENOMEM;
 	}
 	memset(txdr->buffer_info, 0, size);
@@ -1401,7 +1402,8 @@
 	if (!txdr->desc) {
 setup_tx_desc_die:
 		vfree(txdr->buffer_info);
-		e_err("Unable to allocate memory for the Tx descriptor ring\n");
+		e_err(probe, "Unable to allocate memory for the Tx descriptor "
+		      "ring\n");
 		return -ENOMEM;
 	}
 
@@ -1409,7 +1411,7 @@
 	if (!e1000_check_64k_bound(adapter, txdr->desc, txdr->size)) {
 		void *olddesc = txdr->desc;
 		dma_addr_t olddma = txdr->dma;
-		e_err("txdr align check failed: %u bytes at %p\n",
+		e_err(tx_err, "txdr align check failed: %u bytes at %p\n",
 		      txdr->size, txdr->desc);
 		/* Try again, without freeing the previous */
 		txdr->desc = dma_alloc_coherent(&pdev->dev, txdr->size,
@@ -1427,7 +1429,7 @@
 					  txdr->dma);
 			dma_free_coherent(&pdev->dev, txdr->size, olddesc,
 					  olddma);
-			e_err("Unable to allocate aligned memory "
+			e_err(probe, "Unable to allocate aligned memory "
 			      "for the transmit descriptor ring\n");
 			vfree(txdr->buffer_info);
 			return -ENOMEM;
@@ -1460,7 +1462,7 @@
 	for (i = 0; i < adapter->num_tx_queues; i++) {
 		err = e1000_setup_tx_resources(adapter, &adapter->tx_ring[i]);
 		if (err) {
-			e_err("Allocation for Tx Queue %u failed\n", i);
+			e_err(probe, "Allocation for Tx Queue %u failed\n", i);
 			for (i-- ; i >= 0; i--)
 				e1000_free_tx_resources(adapter,
 							&adapter->tx_ring[i]);
@@ -1580,7 +1582,8 @@
 	size = sizeof(struct e1000_buffer) * rxdr->count;
 	rxdr->buffer_info = vmalloc(size);
 	if (!rxdr->buffer_info) {
-		e_err("Unable to allocate memory for the Rx descriptor ring\n");
+		e_err(probe, "Unable to allocate memory for the Rx descriptor "
+		      "ring\n");
 		return -ENOMEM;
 	}
 	memset(rxdr->buffer_info, 0, size);
@@ -1596,7 +1599,8 @@
 					GFP_KERNEL);
 
 	if (!rxdr->desc) {
-		e_err("Unable to allocate memory for the Rx descriptor ring\n");
+		e_err(probe, "Unable to allocate memory for the Rx descriptor "
+		      "ring\n");
 setup_rx_desc_die:
 		vfree(rxdr->buffer_info);
 		return -ENOMEM;
@@ -1606,7 +1610,7 @@
 	if (!e1000_check_64k_bound(adapter, rxdr->desc, rxdr->size)) {
 		void *olddesc = rxdr->desc;
 		dma_addr_t olddma = rxdr->dma;
-		e_err("rxdr align check failed: %u bytes at %p\n",
+		e_err(rx_err, "rxdr align check failed: %u bytes at %p\n",
 		      rxdr->size, rxdr->desc);
 		/* Try again, without freeing the previous */
 		rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size,
@@ -1615,8 +1619,8 @@
 		if (!rxdr->desc) {
 			dma_free_coherent(&pdev->dev, rxdr->size, olddesc,
 					  olddma);
-			e_err("Unable to allocate memory for the Rx descriptor "
-			      "ring\n");
+			e_err(probe, "Unable to allocate memory for the Rx "
+			      "descriptor ring\n");
 			goto setup_rx_desc_die;
 		}
 
@@ -1626,8 +1630,8 @@
 					  rxdr->dma);
 			dma_free_coherent(&pdev->dev, rxdr->size, olddesc,
 					  olddma);
-			e_err("Unable to allocate aligned memory for the Rx "
-			      "descriptor ring\n");
+			e_err(probe, "Unable to allocate aligned memory for "
+			      "the Rx descriptor ring\n");
 			goto setup_rx_desc_die;
 		} else {
 			/* Free old allocation, new allocation was successful */
@@ -1659,7 +1663,7 @@
 	for (i = 0; i < adapter->num_rx_queues; i++) {
 		err = e1000_setup_rx_resources(adapter, &adapter->rx_ring[i]);
 		if (err) {
-			e_err("Allocation for Rx Queue %u failed\n", i);
+			e_err(probe, "Allocation for Rx Queue %u failed\n", i);
 			for (i-- ; i >= 0; i--)
 				e1000_free_rx_resources(adapter,
 							&adapter->rx_ring[i]);
@@ -2110,7 +2114,7 @@
 	u32 *mcarray = kcalloc(mta_reg_count, sizeof(u32), GFP_ATOMIC);
 
 	if (!mcarray) {
-		e_err("memory allocation failed\n");
+		e_err(probe, "memory allocation failed\n");
 		return;
 	}
 
@@ -2648,7 +2652,8 @@
 		break;
 	default:
 		if (unlikely(net_ratelimit()))
-			e_warn("checksum_partial proto=%x!\n", skb->protocol);
+			e_warn(drv, "checksum_partial proto=%x!\n",
+			       skb->protocol);
 		break;
 	}
 
@@ -2992,7 +2997,8 @@
 				/* fall through */
 				pull_size = min((unsigned int)4, skb->data_len);
 				if (!__pskb_pull_tail(skb, pull_size)) {
-					e_err("__pskb_pull_tail failed.\n");
+					e_err(drv, "__pskb_pull_tail "
+					      "failed.\n");
 					dev_kfree_skb_any(skb);
 					return NETDEV_TX_OK;
 				}
@@ -3140,7 +3146,7 @@
 
 	if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
 	    (max_frame > MAX_JUMBO_FRAME_SIZE)) {
-		e_err("Invalid MTU setting\n");
+		e_err(probe, "Invalid MTU setting\n");
 		return -EINVAL;
 	}
 
@@ -3148,7 +3154,7 @@
 	switch (hw->mac_type) {
 	case e1000_undefined ... e1000_82542_rev2_1:
 		if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
-			e_err("Jumbo Frames not supported.\n");
+			e_err(probe, "Jumbo Frames not supported.\n");
 			return -EINVAL;
 		}
 		break;
@@ -3500,7 +3506,7 @@
 		    !(er32(STATUS) & E1000_STATUS_TXOFF)) {
 
 			/* detected Tx unit hang */
-			e_err("Detected Tx Unit Hang\n"
+			e_err(drv, "Detected Tx Unit Hang\n"
 			      "  Tx Queue             <%lu>\n"
 			      "  TDH                  <%x>\n"
 			      "  TDT                  <%x>\n"
@@ -3749,7 +3755,7 @@
 
 		/* eth type trans needs skb->data to point to something */
 		if (!pskb_may_pull(skb, ETH_HLEN)) {
-			e_err("pskb_may_pull failed.\n");
+			e_err(drv, "pskb_may_pull failed.\n");
 			dev_kfree_skb(skb);
 			goto next_desc;
 		}
@@ -3874,7 +3880,7 @@
 
 		if (adapter->discarding) {
 			/* All receives must fit into a single buffer */
-			e_info("Receive packet consumed multiple buffers\n");
+			e_dbg("Receive packet consumed multiple buffers\n");
 			/* recycle */
 			buffer_info->skb = skb;
 			if (status & E1000_RXD_STAT_EOP)
@@ -3986,8 +3992,8 @@
 		/* Fix for errata 23, can't cross 64kB boundary */
 		if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
 			struct sk_buff *oldskb = skb;
-			e_err("skb align check failed: %u bytes at %p\n",
-			      bufsz, skb->data);
+			e_err(rx_err, "skb align check failed: %u bytes at "
+			      "%p\n", bufsz, skb->data);
 			/* Try again, without freeing the previous */
 			skb = netdev_alloc_skb_ip_align(netdev, bufsz);
 			/* Failed allocation, critical failure */
@@ -4095,8 +4101,8 @@
 		/* Fix for errata 23, can't cross 64kB boundary */
 		if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
 			struct sk_buff *oldskb = skb;
-			e_err("skb align check failed: %u bytes at %p\n",
-			      bufsz, skb->data);
+			e_err(rx_err, "skb align check failed: %u bytes at "
+			      "%p\n", bufsz, skb->data);
 			/* Try again, without freeing the previous */
 			skb = netdev_alloc_skb_ip_align(netdev, bufsz);
 			/* Failed allocation, critical failure */
@@ -4141,8 +4147,8 @@
 		if (!e1000_check_64k_bound(adapter,
 					(void *)(unsigned long)buffer_info->dma,
 					adapter->rx_buffer_len)) {
-			e_err("dma align check failed: %u bytes at %p\n",
-			      adapter->rx_buffer_len,
+			e_err(rx_err, "dma align check failed: %u bytes at "
+			      "%p\n", adapter->rx_buffer_len,
 			      (void *)(unsigned long)buffer_info->dma);
 			dev_kfree_skb(skb);
 			buffer_info->skb = NULL;
@@ -4355,7 +4361,7 @@
 	int ret_val = pci_set_mwi(adapter->pdev);
 
 	if (ret_val)
-		e_err("Error in setting MWI\n");
+		e_err(probe, "Error in setting MWI\n");
 }
 
 void e1000_pci_clear_mwi(struct e1000_hw *hw)
@@ -4486,7 +4492,7 @@
 	/* Fiber NICs only allow 1000 gbps Full duplex */
 	if ((hw->media_type == e1000_media_type_fiber) &&
 		spddplx != (SPEED_1000 + DUPLEX_FULL)) {
-		e_err("Unsupported Speed/Duplex configuration\n");
+		e_err(probe, "Unsupported Speed/Duplex configuration\n");
 		return -EINVAL;
 	}
 
@@ -4509,7 +4515,7 @@
 		break;
 	case SPEED_1000 + DUPLEX_HALF: /* not supported */
 	default:
-		e_err("Unsupported Speed/Duplex configuration\n");
+		e_err(probe, "Unsupported Speed/Duplex configuration\n");
 		return -EINVAL;
 	}
 	return 0;
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index f654db9..a4a0d2b 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
+  Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index 4dc02c7..307a72f4 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
+  Copyright(c) 1999 - 2010 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,
@@ -359,6 +359,7 @@
 #define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE       0x00000001
 #define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE       0x00000008
 #define E1000_EXTCNF_CTRL_SWFLAG                 0x00000020
+#define E1000_EXTCNF_CTRL_GATE_PHY_CFG           0x00000080
 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK   0x00FF0000
 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT          16
 #define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK   0x0FFF0000
@@ -714,6 +715,7 @@
 #define BME1000_E_PHY_ID_R2  0x01410CB1
 #define I82577_E_PHY_ID      0x01540050
 #define I82578_E_PHY_ID      0x004DD040
+#define I82579_E_PHY_ID      0x01540090
 
 /* M88E1000 Specific Registers */
 #define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index c0b3db4..f9a31c8 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
+  Copyright(c) 1999 - 2010 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,
@@ -164,6 +164,7 @@
 	board_ich9lan,
 	board_ich10lan,
 	board_pchlan,
+	board_pch2lan,
 };
 
 struct e1000_queue_stats {
@@ -347,6 +348,7 @@
 	u32 test_icr;
 
 	u32 msg_enable;
+	unsigned int num_vectors;
 	struct msix_entry *msix_entries;
 	int int_mode;
 	u32 eiac_mask;
@@ -421,6 +423,8 @@
 #define FLAG2_HAS_PHY_WAKEUP              (1 << 1)
 #define FLAG2_IS_DISCARDING               (1 << 2)
 #define FLAG2_DISABLE_ASPM_L1             (1 << 3)
+#define FLAG2_HAS_PHY_STATS               (1 << 4)
+#define FLAG2_HAS_EEE                     (1 << 5)
 
 #define E1000_RX_DESC_PS(R, i)	    \
 	(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
@@ -458,7 +462,6 @@
 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 e1000e_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);
 extern void e1000e_disable_aspm(struct pci_dev *pdev, u16 state);
@@ -476,6 +479,7 @@
 extern struct e1000_info e1000_ich9_info;
 extern struct e1000_info e1000_ich10_info;
 extern struct e1000_info e1000_pch_info;
+extern struct e1000_info e1000_pch2_info;
 extern struct e1000_info e1000_es2_info;
 
 extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num);
@@ -494,6 +498,8 @@
 extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
 extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw);
 extern s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
+extern s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
+extern void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
 
 extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
 extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
index 38d79a6..45aebb4 100644
--- a/drivers/net/e1000e/es2lan.c
+++ b/drivers/net/e1000e/es2lan.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
+  Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 2c52121..6355a1b 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
+  Copyright(c) 1999 - 2010 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,
@@ -118,7 +118,6 @@
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
-	u32 status;
 
 	if (hw->phy.media_type == e1000_media_type_copper) {
 
@@ -156,22 +155,29 @@
 		ecmd->transceiver = XCVR_EXTERNAL;
 	}
 
-	status = er32(STATUS);
-	if (status & E1000_STATUS_LU) {
-		if (status & E1000_STATUS_SPEED_1000)
-			ecmd->speed = 1000;
-		else if (status & E1000_STATUS_SPEED_100)
-			ecmd->speed = 100;
-		else
-			ecmd->speed = 10;
+	ecmd->speed = -1;
+	ecmd->duplex = -1;
 
-		if (status & E1000_STATUS_FD)
-			ecmd->duplex = DUPLEX_FULL;
-		else
-			ecmd->duplex = DUPLEX_HALF;
+	if (netif_running(netdev)) {
+		if (netif_carrier_ok(netdev)) {
+			ecmd->speed = adapter->link_speed;
+			ecmd->duplex = adapter->link_duplex - 1;
+		}
 	} else {
-		ecmd->speed = -1;
-		ecmd->duplex = -1;
+		u32 status = er32(STATUS);
+		if (status & E1000_STATUS_LU) {
+			if (status & E1000_STATUS_SPEED_1000)
+				ecmd->speed = 1000;
+			else if (status & E1000_STATUS_SPEED_100)
+				ecmd->speed = 100;
+			else
+				ecmd->speed = 10;
+
+			if (status & E1000_STATUS_FD)
+				ecmd->duplex = DUPLEX_FULL;
+			else
+				ecmd->duplex = DUPLEX_HALF;
+		}
 	}
 
 	ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||
@@ -179,7 +185,7 @@
 
 	/* MDI-X => 2; MDI =>1; Invalid =>0 */
 	if ((hw->phy.media_type == e1000_media_type_copper) &&
-	    !hw->mac.get_link_status)
+	    netif_carrier_ok(netdev))
 		ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X :
 		                                      ETH_TP_MDI;
 	else
@@ -191,19 +197,15 @@
 static u32 e1000_get_link(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
-	struct e1000_mac_info *mac = &adapter->hw.mac;
+	struct e1000_hw *hw = &adapter->hw;
 
 	/*
-	 * If the link is not reported up to netdev, interrupts are disabled,
-	 * and so the physical link state may have changed since we last
-	 * looked. Set get_link_status to make sure that the true link
-	 * state is interrogated, rather than pulling a cached and possibly
-	 * stale link state from the driver.
+	 * Avoid touching hardware registers when possible, otherwise
+	 * link negotiation can get messed up when user-level scripts
+	 * are rapidly polling the driver to see if link is up.
 	 */
-	if (!netif_carrier_ok(netdev))
-		mac->get_link_status = 1;
-
-	return e1000e_has_link(adapter);
+	return netif_running(netdev) ? netif_carrier_ok(netdev) :
+	    !!(er32(STATUS) & E1000_STATUS_LU);
 }
 
 static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
@@ -880,6 +882,7 @@
 	switch (mac->type) {
 	case e1000_ich10lan:
 	case e1000_pchlan:
+	case e1000_pch2lan:
 		mask |= (1 << 18);
 		break;
 	default:
@@ -1263,33 +1266,36 @@
 
 	hw->mac.autoneg = 0;
 
-	/* Workaround: K1 must be disabled for stable 1Gbps operation */
-	if (hw->mac.type == e1000_pchlan)
-		e1000_configure_k1_ich8lan(hw, false);
+	if (hw->phy.type == e1000_phy_ife) {
+		/* force 100, set loopback */
+		e1e_wphy(hw, PHY_CONTROL, 0x6100);
 
-	if (hw->phy.type == e1000_phy_m88) {
+		/* Now set up the MAC to the same speed/duplex as the PHY. */
+		ctrl_reg = er32(CTRL);
+		ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+		ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+			     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+			     E1000_CTRL_SPD_100 |/* Force Speed to 100 */
+			     E1000_CTRL_FD);	 /* Force Duplex to FULL */
+
+		ew32(CTRL, ctrl_reg);
+		udelay(500);
+
+		return 0;
+	}
+
+	/* Specific PHY configuration for loopback */
+	switch (hw->phy.type) {
+	case e1000_phy_m88:
 		/* Auto-MDI/MDIX Off */
 		e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
 		/* reset to update Auto-MDI/MDIX */
 		e1e_wphy(hw, PHY_CONTROL, 0x9140);
 		/* autoneg off */
 		e1e_wphy(hw, PHY_CONTROL, 0x8140);
-	} else if (hw->phy.type == e1000_phy_gg82563)
+		break;
+	case e1000_phy_gg82563:
 		e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC);
-
-	ctrl_reg = er32(CTRL);
-
-	switch (hw->phy.type) {
-	case e1000_phy_ife:
-		/* force 100, set loopback */
-		e1e_wphy(hw, PHY_CONTROL, 0x6100);
-
-		/* Now set up the MAC to the same speed/duplex as the PHY. */
-		ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
-		ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
-			     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
-			     E1000_CTRL_SPD_100 |/* Force Speed to 100 */
-			     E1000_CTRL_FD);	 /* Force Duplex to FULL */
 		break;
 	case e1000_phy_bm:
 		/* Set Default MAC Interface speed to 1GB */
@@ -1312,24 +1318,42 @@
 		/* Set Early Link Enable */
 		e1e_rphy(hw, PHY_REG(769, 20), &phy_reg);
 		e1e_wphy(hw, PHY_REG(769, 20), phy_reg | 0x0400);
-		/* fall through */
+		break;
+	case e1000_phy_82577:
+	case e1000_phy_82578:
+		/* Workaround: K1 must be disabled for stable 1Gbps operation */
+		e1000_configure_k1_ich8lan(hw, false);
+		break;
+	case e1000_phy_82579:
+		/* Disable PHY energy detect power down */
+		e1e_rphy(hw, PHY_REG(0, 21), &phy_reg);
+		e1e_wphy(hw, PHY_REG(0, 21), phy_reg & ~(1 << 3));
+		/* Disable full chip energy detect */
+		e1e_rphy(hw, PHY_REG(776, 18), &phy_reg);
+		e1e_wphy(hw, PHY_REG(776, 18), phy_reg | 1);
+		/* Enable loopback on the PHY */
+#define I82577_PHY_LBK_CTRL          19
+		e1e_wphy(hw, I82577_PHY_LBK_CTRL, 0x8001);
+		break;
 	default:
-		/* force 1000, set loopback */
-		e1e_wphy(hw, PHY_CONTROL, 0x4140);
-		mdelay(250);
-
-		/* Now set up the MAC to the same speed/duplex as the PHY. */
-		ctrl_reg = er32(CTRL);
-		ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
-		ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
-			     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
-			     E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
-			     E1000_CTRL_FD);	 /* Force Duplex to FULL */
-
-		if (adapter->flags & FLAG_IS_ICH)
-			ctrl_reg |= E1000_CTRL_SLU;	/* Set Link Up */
+		break;
 	}
 
+	/* force 1000, set loopback */
+	e1e_wphy(hw, PHY_CONTROL, 0x4140);
+	mdelay(250);
+
+	/* Now set up the MAC to the same speed/duplex as the PHY. */
+	ctrl_reg = er32(CTRL);
+	ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+	ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+		     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+		     E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
+		     E1000_CTRL_FD);	 /* Force Duplex to FULL */
+
+	if (adapter->flags & FLAG_IS_ICH)
+		ctrl_reg |= E1000_CTRL_SLU;	/* Set Link Up */
+
 	if (hw->phy.media_type == e1000_media_type_copper &&
 	    hw->phy.type == e1000_phy_m88) {
 		ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
@@ -1868,6 +1892,7 @@
 
 	if ((hw->phy.type == e1000_phy_ife) ||
 	    (hw->mac.type == e1000_pchlan) ||
+	    (hw->mac.type == e1000_pch2lan) ||
 	    (hw->mac.type == e1000_82583) ||
 	    (hw->mac.type == e1000_82574)) {
 		INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task);
@@ -2026,7 +2051,6 @@
 	.get_coalesce		= e1000_get_coalesce,
 	.set_coalesce		= e1000_set_coalesce,
 	.get_flags		= ethtool_op_get_flags,
-	.set_flags		= ethtool_op_set_flags,
 };
 
 void e1000e_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index 5d1220d..66ed08f 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
+  Copyright(c) 1999 - 2010 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,
@@ -217,7 +217,10 @@
 	E1000_SWSM      = 0x05B50, /* SW Semaphore */
 	E1000_FWSM      = 0x05B54, /* FW Semaphore */
 	E1000_SWSM2     = 0x05B58, /* Driver-only SW semaphore */
-	E1000_CRC_OFFSET = 0x05F50, /* CRC Offset register */
+	E1000_FFLT_DBG  = 0x05F04, /* Debug Register */
+	E1000_PCH_RAICC_BASE = 0x05F50, /* Receive Address Initial CRC */
+#define E1000_PCH_RAICC(_n)	(E1000_PCH_RAICC_BASE + ((_n) * 4))
+#define E1000_CRC_OFFSET	E1000_PCH_RAICC_BASE
 	E1000_HICR      = 0x08F00, /* Host Interface Control */
 };
 
@@ -303,13 +306,14 @@
 #define E1000_KMRNCTRLSTA_OFFSET	0x001F0000
 #define E1000_KMRNCTRLSTA_OFFSET_SHIFT	16
 #define E1000_KMRNCTRLSTA_REN		0x00200000
+#define E1000_KMRNCTRLSTA_CTRL_OFFSET	0x1    /* Kumeran Control */
 #define E1000_KMRNCTRLSTA_DIAG_OFFSET	0x3    /* Kumeran Diagnostic */
 #define E1000_KMRNCTRLSTA_TIMEOUTS	0x4    /* Kumeran Timeouts */
 #define E1000_KMRNCTRLSTA_INBAND_PARAM	0x9    /* Kumeran InBand Parameters */
 #define E1000_KMRNCTRLSTA_DIAG_NELPBK	0x1000 /* Nearend Loopback mode */
 #define E1000_KMRNCTRLSTA_K1_CONFIG	0x7
-#define E1000_KMRNCTRLSTA_K1_ENABLE	0x140E
-#define E1000_KMRNCTRLSTA_K1_DISABLE	0x1400
+#define E1000_KMRNCTRLSTA_K1_ENABLE	0x0002
+#define E1000_KMRNCTRLSTA_HD_CTRL	0x10   /* Kumeran HD Control */
 
 #define IFE_PHY_EXTENDED_STATUS_CONTROL	0x10
 #define IFE_PHY_SPECIAL_CONTROL		0x11 /* 100BaseTx PHY Special Control */
@@ -387,6 +391,8 @@
 #define E1000_DEV_ID_PCH_M_HV_LC		0x10EB
 #define E1000_DEV_ID_PCH_D_HV_DM		0x10EF
 #define E1000_DEV_ID_PCH_D_HV_DC		0x10F0
+#define E1000_DEV_ID_PCH2_LV_LM			0x1502
+#define E1000_DEV_ID_PCH2_LV_V			0x1503
 
 #define E1000_REVISION_4 4
 
@@ -406,6 +412,7 @@
 	e1000_ich9lan,
 	e1000_ich10lan,
 	e1000_pchlan,
+	e1000_pch2lan,
 };
 
 enum e1000_media_type {
@@ -442,6 +449,7 @@
 	e1000_phy_bm,
 	e1000_phy_82578,
 	e1000_phy_82577,
+	e1000_phy_82579,
 };
 
 enum e1000_bus_width {
@@ -929,6 +937,7 @@
 	bool kmrn_lock_loss_workaround_enabled;
 	struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
 	bool nvm_k1_enabled;
+	bool eee_disable;
 };
 
 struct e1000_hw {
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index b2507d9..63930d1 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
+  Copyright(c) 1999 - 2010 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,
@@ -52,6 +52,8 @@
  * 82577LC Gigabit Network Connection
  * 82578DM Gigabit Network Connection
  * 82578DC Gigabit Network Connection
+ * 82579LM Gigabit Network Connection
+ * 82579V Gigabit Network Connection
  */
 
 #include "e1000.h"
@@ -126,6 +128,13 @@
 #define HV_SMB_ADDR_PEC_EN     0x0200
 #define HV_SMB_ADDR_VALID      0x0080
 
+/* PHY Power Management Control */
+#define HV_PM_CTRL		PHY_REG(770, 17)
+
+/* PHY Low Power Idle Control */
+#define I82579_LPI_CTRL			PHY_REG(772, 20)
+#define I82579_LPI_CTRL_ENABLE_MASK	0x6000
+
 /* Strapping Option Register - RO */
 #define E1000_STRAP                     0x0000C
 #define E1000_STRAP_SMBUS_ADDRESS_MASK  0x00FE0000
@@ -226,6 +235,8 @@
 static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw);
 static s32  e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
 static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
+static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
+static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
 
 static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
 {
@@ -277,13 +288,13 @@
 	phy->ops.power_down           = e1000_power_down_phy_copper_ich8lan;
 	phy->autoneg_mask             = AUTONEG_ADVERTISE_SPEED_DEFAULT;
 
+	/*
+	 * The MAC-PHY interconnect may still be in SMBus mode
+	 * after Sx->S0.  If the manageability engine (ME) is
+	 * disabled, then toggle the LANPHYPC Value bit to force
+	 * the interconnect to PCIe mode.
+	 */
 	if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
-		/*
-		 * The MAC-PHY interconnect may still be in SMBus mode
-		 * after Sx->S0.  Toggle the LANPHYPC Value bit to force
-		 * the interconnect to PCIe mode, but only if there is no
-		 * firmware present otherwise firmware will have done it.
-		 */
 		ctrl = er32(CTRL);
 		ctrl |=  E1000_CTRL_LANPHYPC_OVERRIDE;
 		ctrl &= ~E1000_CTRL_LANPHYPC_VALUE;
@@ -324,6 +335,7 @@
 
 	switch (phy->type) {
 	case e1000_phy_82577:
+	case e1000_phy_82579:
 		phy->ops.check_polarity = e1000_check_polarity_82577;
 		phy->ops.force_speed_duplex =
 			e1000_phy_force_speed_duplex_82577;
@@ -515,6 +527,8 @@
 	case e1000_ich8lan:
 	case e1000_ich9lan:
 	case e1000_ich10lan:
+		/* check management mode */
+		mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
 		/* ID LED init */
 		mac->ops.id_led_init = e1000e_id_led_init;
 		/* setup LED */
@@ -526,6 +540,9 @@
 		mac->ops.led_off = e1000_led_off_ich8lan;
 		break;
 	case e1000_pchlan:
+	case e1000_pch2lan:
+		/* check management mode */
+		mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
 		/* ID LED init */
 		mac->ops.id_led_init = e1000_id_led_init_pchlan;
 		/* setup LED */
@@ -544,10 +561,47 @@
 	if (mac->type == e1000_ich8lan)
 		e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
 
+	/* Disable PHY configuration by hardware, config by software */
+	if (mac->type == e1000_pch2lan) {
+		u32 extcnf_ctrl = er32(EXTCNF_CTRL);
+
+		extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+		ew32(EXTCNF_CTRL, extcnf_ctrl);
+	}
+
 	return 0;
 }
 
 /**
+ *  e1000_set_eee_pchlan - Enable/disable EEE support
+ *  @hw: pointer to the HW structure
+ *
+ *  Enable/disable EEE based on setting in dev_spec structure.  The bits in
+ *  the LPI Control register will remain set only if/when link is up.
+ **/
+static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+	u16 phy_reg;
+
+	if (hw->phy.type != e1000_phy_82579)
+		goto out;
+
+	ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg);
+	if (ret_val)
+		goto out;
+
+	if (hw->dev_spec.ich8lan.eee_disable)
+		phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK;
+	else
+		phy_reg |= I82579_LPI_CTRL_ENABLE_MASK;
+
+	ret_val = e1e_wphy(hw, I82579_LPI_CTRL, phy_reg);
+out:
+	return ret_val;
+}
+
+/**
  *  e1000_check_for_copper_link_ich8lan - Check for link (Copper)
  *  @hw: pointer to the HW structure
  *
@@ -604,6 +658,11 @@
 	 */
 	e1000e_check_downshift(hw);
 
+	/* Enable/Disable EEE after link up */
+	ret_val = e1000_set_eee_pchlan(hw);
+	if (ret_val)
+		goto out;
+
 	/*
 	 * If we are forcing speed/duplex, then we simply return since
 	 * we have already determined whether we have link or not.
@@ -647,10 +706,19 @@
 	if (rc)
 		return rc;
 
-	if (hw->mac.type == e1000_pchlan)
-		rc = e1000_init_phy_params_pchlan(hw);
-	else
+	switch (hw->mac.type) {
+	case e1000_ich8lan:
+	case e1000_ich9lan:
+	case e1000_ich10lan:
 		rc = e1000_init_phy_params_ich8lan(hw);
+		break;
+	case e1000_pchlan:
+	case e1000_pch2lan:
+		rc = e1000_init_phy_params_pchlan(hw);
+		break;
+	default:
+		break;
+	}
 	if (rc)
 		return rc;
 
@@ -663,6 +731,10 @@
 	    (adapter->hw.phy.type == e1000_phy_igp_3))
 		adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
 
+	/* Disable EEE by default until IEEE802.3az spec is finalized */
+	if (adapter->flags2 & FLAG2_HAS_EEE)
+		adapter->hw.dev_spec.ich8lan.eee_disable = true;
+
 	return 0;
 }
 
@@ -774,7 +846,7 @@
  *  e1000_check_mng_mode_ich8lan - Checks management mode
  *  @hw: pointer to the HW structure
  *
- *  This checks if the adapter has manageability enabled.
+ *  This checks if the adapter has any manageability enabled.
  *  This is a function pointer entry point only called by read/write
  *  routines for the PHY and NVM parts.
  **/
@@ -783,9 +855,26 @@
 	u32 fwsm;
 
 	fwsm = er32(FWSM);
+	return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
+	       ((fwsm & E1000_FWSM_MODE_MASK) ==
+		(E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
+}
 
-	return (fwsm & E1000_FWSM_MODE_MASK) ==
-		(E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
+/**
+ *  e1000_check_mng_mode_pchlan - Checks management mode
+ *  @hw: pointer to the HW structure
+ *
+ *  This checks if the adapter has iAMT enabled.
+ *  This is a function pointer entry point only called by read/write
+ *  routines for the PHY and NVM parts.
+ **/
+static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw)
+{
+	u32 fwsm;
+
+	fwsm = er32(FWSM);
+	return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
+	       (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
 }
 
 /**
@@ -820,14 +909,6 @@
 	s32 ret_val = 0;
 	u16 word_addr, reg_data, reg_addr, phy_page = 0;
 
-	if (!(hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) &&
-		!(hw->mac.type == e1000_pchlan))
-		return ret_val;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		return ret_val;
-
 	/*
 	 * Initialize the PHY from the NVM on ICH platforms.  This
 	 * is needed due to an issue where the NVM configuration is
@@ -835,12 +916,27 @@
 	 * Therefore, after each PHY reset, we will load the
 	 * configuration data out of the NVM manually.
 	 */
-	if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
-	    (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M) ||
-	    (hw->mac.type == e1000_pchlan))
+	switch (hw->mac.type) {
+	case e1000_ich8lan:
+		if (phy->type != e1000_phy_igp_3)
+			return ret_val;
+
+		if (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_AMT) {
+			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+			break;
+		}
+		/* Fall-thru */
+	case e1000_pchlan:
+	case e1000_pch2lan:
 		sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
-	else
-		sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+		break;
+	default:
+		return ret_val;
+	}
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		return ret_val;
 
 	data = er32(FEXTNVM);
 	if (!(data & sw_cfg_mask))
@@ -851,8 +947,10 @@
 	 * extended configuration before SW configuration
 	 */
 	data = er32(EXTCNF_CTRL);
-	if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
-		goto out;
+	if (!(hw->mac.type == e1000_pch2lan)) {
+		if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+			goto out;
+	}
 
 	cnf_size = er32(EXTCNF_SIZE);
 	cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
@@ -864,7 +962,8 @@
 	cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
 
 	if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
-	    (hw->mac.type == e1000_pchlan)) {
+	    ((hw->mac.type == e1000_pchlan) ||
+	     (hw->mac.type == e1000_pch2lan))) {
 		/*
 		 * HW configures the SMBus address and LEDs when the
 		 * OEM and LCD Write Enable bits are set in the NVM.
@@ -1071,16 +1170,18 @@
 	u32 mac_reg;
 	u16 oem_reg;
 
-	if (hw->mac.type != e1000_pchlan)
+	if ((hw->mac.type != e1000_pch2lan) && (hw->mac.type != e1000_pchlan))
 		return ret_val;
 
 	ret_val = hw->phy.ops.acquire(hw);
 	if (ret_val)
 		return ret_val;
 
-	mac_reg = er32(EXTCNF_CTRL);
-	if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
-		goto out;
+	if (!(hw->mac.type == e1000_pch2lan)) {
+		mac_reg = er32(EXTCNF_CTRL);
+		if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
+			goto out;
+	}
 
 	mac_reg = er32(FEXTNVM);
 	if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
@@ -1221,6 +1322,243 @@
 }
 
 /**
+ *  e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY
+ *  @hw:   pointer to the HW structure
+ **/
+void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
+{
+	u32 mac_reg;
+	u16 i;
+
+	/* Copy both RAL/H (rar_entry_count) and SHRAL/H (+4) to PHY */
+	for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+		mac_reg = er32(RAL(i));
+		e1e_wphy(hw, BM_RAR_L(i), (u16)(mac_reg & 0xFFFF));
+		e1e_wphy(hw, BM_RAR_M(i), (u16)((mac_reg >> 16) & 0xFFFF));
+		mac_reg = er32(RAH(i));
+		e1e_wphy(hw, BM_RAR_H(i), (u16)(mac_reg & 0xFFFF));
+		e1e_wphy(hw, BM_RAR_CTRL(i), (u16)((mac_reg >> 16) & 0x8000));
+	}
+}
+
+static u32 e1000_calc_rx_da_crc(u8 mac[])
+{
+	u32 poly = 0xEDB88320;	/* Polynomial for 802.3 CRC calculation */
+	u32 i, j, mask, crc;
+
+	crc = 0xffffffff;
+	for (i = 0; i < 6; i++) {
+		crc = crc ^ mac[i];
+		for (j = 8; j > 0; j--) {
+			mask = (crc & 1) * (-1);
+			crc = (crc >> 1) ^ (poly & mask);
+		}
+	}
+	return ~crc;
+}
+
+/**
+ *  e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation
+ *  with 82579 PHY
+ *  @hw: pointer to the HW structure
+ *  @enable: flag to enable/disable workaround when enabling/disabling jumbos
+ **/
+s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
+{
+	s32 ret_val = 0;
+	u16 phy_reg, data;
+	u32 mac_reg;
+	u16 i;
+
+	if (hw->mac.type != e1000_pch2lan)
+		goto out;
+
+	/* disable Rx path while enabling/disabling workaround */
+	e1e_rphy(hw, PHY_REG(769, 20), &phy_reg);
+	ret_val = e1e_wphy(hw, PHY_REG(769, 20), phy_reg | (1 << 14));
+	if (ret_val)
+		goto out;
+
+	if (enable) {
+		/*
+		 * Write Rx addresses (rar_entry_count for RAL/H, +4 for
+		 * SHRAL/H) and initial CRC values to the MAC
+		 */
+		for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+			u8 mac_addr[ETH_ALEN] = {0};
+			u32 addr_high, addr_low;
+
+			addr_high = er32(RAH(i));
+			if (!(addr_high & E1000_RAH_AV))
+				continue;
+			addr_low = er32(RAL(i));
+			mac_addr[0] = (addr_low & 0xFF);
+			mac_addr[1] = ((addr_low >> 8) & 0xFF);
+			mac_addr[2] = ((addr_low >> 16) & 0xFF);
+			mac_addr[3] = ((addr_low >> 24) & 0xFF);
+			mac_addr[4] = (addr_high & 0xFF);
+			mac_addr[5] = ((addr_high >> 8) & 0xFF);
+
+			ew32(PCH_RAICC(i),
+					e1000_calc_rx_da_crc(mac_addr));
+		}
+
+		/* Write Rx addresses to the PHY */
+		e1000_copy_rx_addrs_to_phy_ich8lan(hw);
+
+		/* Enable jumbo frame workaround in the MAC */
+		mac_reg = er32(FFLT_DBG);
+		mac_reg &= ~(1 << 14);
+		mac_reg |= (7 << 15);
+		ew32(FFLT_DBG, mac_reg);
+
+		mac_reg = er32(RCTL);
+		mac_reg |= E1000_RCTL_SECRC;
+		ew32(RCTL, mac_reg);
+
+		ret_val = e1000e_read_kmrn_reg(hw,
+						E1000_KMRNCTRLSTA_CTRL_OFFSET,
+						&data);
+		if (ret_val)
+			goto out;
+		ret_val = e1000e_write_kmrn_reg(hw,
+						E1000_KMRNCTRLSTA_CTRL_OFFSET,
+						data | (1 << 0));
+		if (ret_val)
+			goto out;
+		ret_val = e1000e_read_kmrn_reg(hw,
+						E1000_KMRNCTRLSTA_HD_CTRL,
+						&data);
+		if (ret_val)
+			goto out;
+		data &= ~(0xF << 8);
+		data |= (0xB << 8);
+		ret_val = e1000e_write_kmrn_reg(hw,
+						E1000_KMRNCTRLSTA_HD_CTRL,
+						data);
+		if (ret_val)
+			goto out;
+
+		/* Enable jumbo frame workaround in the PHY */
+		e1e_rphy(hw, PHY_REG(769, 20), &data);
+		ret_val = e1e_wphy(hw, PHY_REG(769, 20), data & ~(1 << 14));
+		if (ret_val)
+			goto out;
+		e1e_rphy(hw, PHY_REG(769, 23), &data);
+		data &= ~(0x7F << 5);
+		data |= (0x37 << 5);
+		ret_val = e1e_wphy(hw, PHY_REG(769, 23), data);
+		if (ret_val)
+			goto out;
+		e1e_rphy(hw, PHY_REG(769, 16), &data);
+		data &= ~(1 << 13);
+		data |= (1 << 12);
+		ret_val = e1e_wphy(hw, PHY_REG(769, 16), data);
+		if (ret_val)
+			goto out;
+		e1e_rphy(hw, PHY_REG(776, 20), &data);
+		data &= ~(0x3FF << 2);
+		data |= (0x1A << 2);
+		ret_val = e1e_wphy(hw, PHY_REG(776, 20), data);
+		if (ret_val)
+			goto out;
+		ret_val = e1e_wphy(hw, PHY_REG(776, 23), 0xFE00);
+		if (ret_val)
+			goto out;
+		e1e_rphy(hw, HV_PM_CTRL, &data);
+		ret_val = e1e_wphy(hw, HV_PM_CTRL, data | (1 << 10));
+		if (ret_val)
+			goto out;
+	} else {
+		/* Write MAC register values back to h/w defaults */
+		mac_reg = er32(FFLT_DBG);
+		mac_reg &= ~(0xF << 14);
+		ew32(FFLT_DBG, mac_reg);
+
+		mac_reg = er32(RCTL);
+		mac_reg &= ~E1000_RCTL_SECRC;
+		ew32(FFLT_DBG, mac_reg);
+
+		ret_val = e1000e_read_kmrn_reg(hw,
+						E1000_KMRNCTRLSTA_CTRL_OFFSET,
+						&data);
+		if (ret_val)
+			goto out;
+		ret_val = e1000e_write_kmrn_reg(hw,
+						E1000_KMRNCTRLSTA_CTRL_OFFSET,
+						data & ~(1 << 0));
+		if (ret_val)
+			goto out;
+		ret_val = e1000e_read_kmrn_reg(hw,
+						E1000_KMRNCTRLSTA_HD_CTRL,
+						&data);
+		if (ret_val)
+			goto out;
+		data &= ~(0xF << 8);
+		data |= (0xB << 8);
+		ret_val = e1000e_write_kmrn_reg(hw,
+						E1000_KMRNCTRLSTA_HD_CTRL,
+						data);
+		if (ret_val)
+			goto out;
+
+		/* Write PHY register values back to h/w defaults */
+		e1e_rphy(hw, PHY_REG(769, 20), &data);
+		ret_val = e1e_wphy(hw, PHY_REG(769, 20), data & ~(1 << 14));
+		if (ret_val)
+			goto out;
+		e1e_rphy(hw, PHY_REG(769, 23), &data);
+		data &= ~(0x7F << 5);
+		ret_val = e1e_wphy(hw, PHY_REG(769, 23), data);
+		if (ret_val)
+			goto out;
+		e1e_rphy(hw, PHY_REG(769, 16), &data);
+		data &= ~(1 << 12);
+		data |= (1 << 13);
+		ret_val = e1e_wphy(hw, PHY_REG(769, 16), data);
+		if (ret_val)
+			goto out;
+		e1e_rphy(hw, PHY_REG(776, 20), &data);
+		data &= ~(0x3FF << 2);
+		data |= (0x8 << 2);
+		ret_val = e1e_wphy(hw, PHY_REG(776, 20), data);
+		if (ret_val)
+			goto out;
+		ret_val = e1e_wphy(hw, PHY_REG(776, 23), 0x7E00);
+		if (ret_val)
+			goto out;
+		e1e_rphy(hw, HV_PM_CTRL, &data);
+		ret_val = e1e_wphy(hw, HV_PM_CTRL, data & ~(1 << 10));
+		if (ret_val)
+			goto out;
+	}
+
+	/* re-enable Rx path after enabling/disabling workaround */
+	ret_val = e1e_wphy(hw, PHY_REG(769, 20), phy_reg & ~(1 << 14));
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ *  done after every PHY reset.
+ **/
+static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+
+	if (hw->mac.type != e1000_pch2lan)
+		goto out;
+
+	/* Set MDIO slow mode before any other MDIO access */
+	ret_val = e1000_set_mdio_slow_mode_hv(hw);
+
+out:
+	return ret_val;
+}
+
+/**
  *  e1000_lan_init_done_ich8lan - Check for PHY config completion
  *  @hw: pointer to the HW structure
  *
@@ -1271,12 +1609,17 @@
 		if (ret_val)
 			goto out;
 		break;
+	case e1000_pch2lan:
+		ret_val = e1000_lv_phy_workarounds_ich8lan(hw);
+		if (ret_val)
+			goto out;
+		break;
 	default:
 		break;
 	}
 
 	/* Dummy read to clear the phy wakeup bit after lcd reset */
-	if (hw->mac.type == e1000_pchlan)
+	if (hw->mac.type >= e1000_pchlan)
 		e1e_rphy(hw, BM_WUC, &reg);
 
 	/* Configure the LCD with the extended configuration region in NVM */
@@ -2800,6 +3143,7 @@
 
 	ew32(FCTTV, hw->fc.pause_time);
 	if ((hw->phy.type == e1000_phy_82578) ||
+	    (hw->phy.type == e1000_phy_82579) ||
 	    (hw->phy.type == e1000_phy_82577)) {
 		ew32(FCRTV_PCH, hw->fc.refresh_time);
 
@@ -2863,6 +3207,7 @@
 			return ret_val;
 		break;
 	case e1000_phy_82577:
+	case e1000_phy_82579:
 		ret_val = e1000_copper_link_setup_82577(hw);
 		if (ret_val)
 			return ret_val;
@@ -3116,21 +3461,12 @@
 {
 	u32 phy_ctrl;
 
-	switch (hw->mac.type) {
-	case e1000_ich8lan:
-	case e1000_ich9lan:
-	case e1000_ich10lan:
-	case e1000_pchlan:
-		phy_ctrl = er32(PHY_CTRL);
-		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
-		            E1000_PHY_CTRL_GBE_DISABLE;
-		ew32(PHY_CTRL, phy_ctrl);
+	phy_ctrl = er32(PHY_CTRL);
+	phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE;
+	ew32(PHY_CTRL, phy_ctrl);
 
-		if (hw->mac.type == e1000_pchlan)
-			e1000_phy_hw_reset_ich8lan(hw);
-	default:
-		break;
-	}
+	if (hw->mac.type >= e1000_pchlan)
+		e1000_phy_hw_reset_ich8lan(hw);
 }
 
 /**
@@ -3370,6 +3706,7 @@
 
 	/* Clear PHY statistics registers */
 	if ((hw->phy.type == e1000_phy_82578) ||
+	    (hw->phy.type == e1000_phy_82579) ||
 	    (hw->phy.type == e1000_phy_82577)) {
 		hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data);
 		hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data);
@@ -3390,7 +3727,7 @@
 
 static struct e1000_mac_operations ich8_mac_ops = {
 	.id_led_init		= e1000e_id_led_init,
-	.check_mng_mode		= e1000_check_mng_mode_ich8lan,
+	/* check_mng_mode dependent on mac type */
 	.check_for_link		= e1000_check_for_copper_link_ich8lan,
 	/* cleanup_led dependent on mac type */
 	.clear_hw_cntrs		= e1000_clear_hw_cntrs_ich8lan,
@@ -3497,6 +3834,7 @@
 				  | FLAG_HAS_JUMBO_FRAMES
 				  | FLAG_DISABLE_FC_PAUSE_TIME /* errata */
 				  | FLAG_APME_IN_WUC,
+	.flags2			= FLAG2_HAS_PHY_STATS,
 	.pba			= 26,
 	.max_hw_frame_size	= 4096,
 	.get_variants		= e1000_get_variants_ich8lan,
@@ -3504,3 +3842,23 @@
 	.phy_ops		= &ich8_phy_ops,
 	.nvm_ops		= &ich8_nvm_ops,
 };
+
+struct e1000_info e1000_pch2_info = {
+	.mac			= e1000_pch2lan,
+	.flags			= FLAG_IS_ICH
+				  | FLAG_HAS_WOL
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_FLASH
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_APME_IN_WUC,
+	.flags2			= FLAG2_HAS_PHY_STATS
+				  | FLAG2_HAS_EEE,
+	.pba			= 18,
+	.max_hw_frame_size	= DEFAULT_JUMBO,
+	.get_variants		= e1000_get_variants_ich8lan,
+	.mac_ops		= &ich8_mac_ops,
+	.phy_ops		= &ich8_phy_ops,
+	.nvm_ops		= &ich8_nvm_ops,
+};
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
index a968e3a..df4a279 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/e1000e/lib.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
+  Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 57a7e41..36d31a4 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
+  Copyright(c) 1999 - 2010 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,
@@ -52,7 +52,9 @@
 
 #include "e1000.h"
 
-#define DRV_VERSION "1.0.2-k4"
+#define DRV_EXTRAVERSION "-k2"
+
+#define DRV_VERSION "1.2.7" DRV_EXTRAVERSION
 char e1000e_driver_name[] = "e1000e";
 const char e1000e_driver_version[] = DRV_VERSION;
 
@@ -67,6 +69,7 @@
 	[board_ich9lan]		= &e1000_ich9_info,
 	[board_ich10lan]	= &e1000_ich10_info,
 	[board_pchlan]		= &e1000_pch_info,
+	[board_pch2lan]		= &e1000_pch2_info,
 };
 
 struct e1000_reg_info {
@@ -221,10 +224,10 @@
 	buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
 	printk(KERN_INFO " %5d %5X %5X %016llX %04X %3X %016llX\n",
 		0, tx_ring->next_to_use, tx_ring->next_to_clean,
-		(u64)buffer_info->dma,
+		(unsigned long long)buffer_info->dma,
 		buffer_info->length,
 		buffer_info->next_to_watch,
-		(u64)buffer_info->time_stamp);
+		(unsigned long long)buffer_info->time_stamp);
 
 	/* Print TX Rings */
 	if (!netif_msg_tx_done(adapter))
@@ -276,9 +279,11 @@
 			"%04X  %3X %016llX %p",
 		       (!(le64_to_cpu(u0->b) & (1<<29)) ? 'l' :
 			((le64_to_cpu(u0->b) & (1<<20)) ? 'd' : 'c')), i,
-		       le64_to_cpu(u0->a), le64_to_cpu(u0->b),
-		       (u64)buffer_info->dma, buffer_info->length,
-		       buffer_info->next_to_watch, (u64)buffer_info->time_stamp,
+		       (unsigned long long)le64_to_cpu(u0->a),
+		       (unsigned long long)le64_to_cpu(u0->b),
+		       (unsigned long long)buffer_info->dma,
+		       buffer_info->length, buffer_info->next_to_watch,
+		       (unsigned long long)buffer_info->time_stamp,
 		       buffer_info->skb);
 		if (i == tx_ring->next_to_use && i == tx_ring->next_to_clean)
 			printk(KERN_CONT " NTC/U\n");
@@ -353,19 +358,19 @@
 				printk(KERN_INFO "RWB[0x%03X]     %016llX "
 					"%016llX %016llX %016llX "
 					"---------------- %p", i,
-					le64_to_cpu(u1->a),
-					le64_to_cpu(u1->b),
-					le64_to_cpu(u1->c),
-					le64_to_cpu(u1->d),
+					(unsigned long long)le64_to_cpu(u1->a),
+					(unsigned long long)le64_to_cpu(u1->b),
+					(unsigned long long)le64_to_cpu(u1->c),
+					(unsigned long long)le64_to_cpu(u1->d),
 					buffer_info->skb);
 			} else {
 				printk(KERN_INFO "R  [0x%03X]     %016llX "
 					"%016llX %016llX %016llX %016llX %p", i,
-					le64_to_cpu(u1->a),
-					le64_to_cpu(u1->b),
-					le64_to_cpu(u1->c),
-					le64_to_cpu(u1->d),
-					(u64)buffer_info->dma,
+					(unsigned long long)le64_to_cpu(u1->a),
+					(unsigned long long)le64_to_cpu(u1->b),
+					(unsigned long long)le64_to_cpu(u1->c),
+					(unsigned long long)le64_to_cpu(u1->d),
+					(unsigned long long)buffer_info->dma,
 					buffer_info->skb);
 
 				if (netif_msg_pktdata(adapter))
@@ -402,9 +407,11 @@
 			buffer_info = &rx_ring->buffer_info[i];
 			u0 = (struct my_u0 *)rx_desc;
 			printk(KERN_INFO "Rl[0x%03X]    %016llX %016llX "
-				"%016llX %p",
-				i, le64_to_cpu(u0->a), le64_to_cpu(u0->b),
-				(u64)buffer_info->dma, buffer_info->skb);
+				"%016llX %p", i,
+				(unsigned long long)le64_to_cpu(u0->a),
+				(unsigned long long)le64_to_cpu(u0->b),
+				(unsigned long long)buffer_info->dma,
+				buffer_info->skb);
 			if (i == rx_ring->next_to_use)
 				printk(KERN_CONT " NTU\n");
 			else if (i == rx_ring->next_to_clean)
@@ -1778,25 +1785,25 @@
 void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
 {
 	int err;
-	int numvecs, i;
-
+	int i;
 
 	switch (adapter->int_mode) {
 	case E1000E_INT_MODE_MSIX:
 		if (adapter->flags & FLAG_HAS_MSIX) {
-			numvecs = 3; /* RxQ0, TxQ0 and other */
-			adapter->msix_entries = kcalloc(numvecs,
+			adapter->num_vectors = 3; /* RxQ0, TxQ0 and other */
+			adapter->msix_entries = kcalloc(adapter->num_vectors,
 						      sizeof(struct msix_entry),
 						      GFP_KERNEL);
 			if (adapter->msix_entries) {
-				for (i = 0; i < numvecs; i++)
+				for (i = 0; i < adapter->num_vectors; i++)
 					adapter->msix_entries[i].entry = i;
 
 				err = pci_enable_msix(adapter->pdev,
 						      adapter->msix_entries,
-						      numvecs);
-				if (err == 0)
+						      adapter->num_vectors);
+				if (err == 0) {
 					return;
+				}
 			}
 			/* MSI-X failed, so fall through and try MSI */
 			e_err("Failed to initialize MSI-X interrupts.  "
@@ -1818,6 +1825,9 @@
 		/* Don't do anything; this is the system default */
 		break;
 	}
+
+	/* store the number of vectors being used */
+	adapter->num_vectors = 1;
 }
 
 /**
@@ -1939,7 +1949,14 @@
 	if (adapter->msix_entries)
 		ew32(EIAC_82574, 0);
 	e1e_flush();
-	synchronize_irq(adapter->pdev->irq);
+
+	if (adapter->msix_entries) {
+		int i;
+		for (i = 0; i < adapter->num_vectors; i++)
+			synchronize_irq(adapter->msix_entries[i].vector);
+	} else {
+		synchronize_irq(adapter->pdev->irq);
+	}
 }
 
 /**
@@ -2723,6 +2740,16 @@
 		e1e_wphy(hw, 22, phy_data);
 	}
 
+	/* Workaround Si errata on 82579 - configure jumbo frame flow */
+	if (hw->mac.type == e1000_pch2lan) {
+		s32 ret_val;
+
+		if (rctl & E1000_RCTL_LPE)
+			ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, true);
+		else
+			ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, false);
+	}
+
 	/* Setup buffer sizes */
 	rctl &= ~E1000_RCTL_SZ_4096;
 	rctl |= E1000_RCTL_BSEX;
@@ -2759,7 +2786,7 @@
 	 * per packet.
 	 */
 	pages = PAGE_USE_COUNT(adapter->netdev->mtu);
-	if (!(adapter->flags & FLAG_IS_ICH) && (pages <= 3) &&
+	if (!(adapter->flags & FLAG_HAS_ERT) && (pages <= 3) &&
 	    (PAGE_SIZE <= 16384) && (rctl & E1000_RCTL_LPE))
 		adapter->rx_ps_pages = pages;
 	else
@@ -2901,10 +2928,10 @@
 			 * dropped transactions.
 			 */
 			pm_qos_update_request(
-				adapter->netdev->pm_qos_req, 55);
+				&adapter->netdev->pm_qos_req, 55);
 		} else {
 			pm_qos_update_request(
-				adapter->netdev->pm_qos_req,
+				&adapter->netdev->pm_qos_req,
 				PM_QOS_DEFAULT_VALUE);
 		}
 	}
@@ -3118,7 +3145,27 @@
 	 *   with ERT support assuming ERT set to E1000_ERT_2048), or
 	 * - the full Rx FIFO size minus one full frame
 	 */
-	if (hw->mac.type == e1000_pchlan) {
+	if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME)
+		fc->pause_time = 0xFFFF;
+	else
+		fc->pause_time = E1000_FC_PAUSE_TIME;
+	fc->send_xon = 1;
+	fc->current_mode = fc->requested_mode;
+
+	switch (hw->mac.type) {
+	default:
+		if ((adapter->flags & FLAG_HAS_ERT) &&
+		    (adapter->netdev->mtu > ETH_DATA_LEN))
+			hwm = min(((pba << 10) * 9 / 10),
+				  ((pba << 10) - (E1000_ERT_2048 << 3)));
+		else
+			hwm = min(((pba << 10) * 9 / 10),
+				  ((pba << 10) - adapter->max_frame_size));
+
+		fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */
+		fc->low_water = fc->high_water - 8;
+		break;
+	case e1000_pchlan:
 		/*
 		 * Workaround PCH LOM adapter hangs with certain network
 		 * loads.  If hangs persist, try disabling Tx flow control.
@@ -3131,26 +3178,15 @@
 			fc->low_water  = 0x3000;
 		}
 		fc->refresh_time = 0x1000;
-	} else {
-		if ((adapter->flags & FLAG_HAS_ERT) &&
-		    (adapter->netdev->mtu > ETH_DATA_LEN))
-			hwm = min(((pba << 10) * 9 / 10),
-				  ((pba << 10) - (E1000_ERT_2048 << 3)));
-		else
-			hwm = min(((pba << 10) * 9 / 10),
-				  ((pba << 10) - adapter->max_frame_size));
-
-		fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */
-		fc->low_water = fc->high_water - 8;
+		break;
+	case e1000_pch2lan:
+		fc->high_water = 0x05C20;
+		fc->low_water = 0x05048;
+		fc->pause_time = 0x0650;
+		fc->refresh_time = 0x0400;
+		break;
 	}
 
-	if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME)
-		fc->pause_time = 0xFFFF;
-	else
-		fc->pause_time = E1000_FC_PAUSE_TIME;
-	fc->send_xon = 1;
-	fc->current_mode = fc->requested_mode;
-
 	/* Allow time for pending master requests to run */
 	mac->ops.reset_hw(hw);
 
@@ -3162,8 +3198,6 @@
 		e1000_get_hw_control(adapter);
 
 	ew32(WUC, 0);
-	if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP)
-		e1e_wphy(&adapter->hw, BM_WUC, 0);
 
 	if (mac->ops.init_hw(hw))
 		e_err("Hardware Error\n");
@@ -3194,12 +3228,6 @@
 {
 	struct e1000_hw *hw = &adapter->hw;
 
-	/* DMA latency requirement to workaround early-receive/jumbo issue */
-	if (adapter->flags & FLAG_HAS_ERT)
-		adapter->netdev->pm_qos_req =
-			pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,
-				       PM_QOS_DEFAULT_VALUE);
-
 	/* hardware has been reset, we need to reload some things */
 	e1000_configure(adapter);
 
@@ -3263,12 +3291,6 @@
 	e1000_clean_tx_ring(adapter);
 	e1000_clean_rx_ring(adapter);
 
-	if (adapter->flags & FLAG_HAS_ERT) {
-		pm_qos_remove_request(
-			      adapter->netdev->pm_qos_req);
-		adapter->netdev->pm_qos_req = NULL;
-	}
-
 	/*
 	 * TODO: for power management, we could drop the link and
 	 * pci_disable_device here.
@@ -3419,13 +3441,18 @@
 
 	/* disable SERR in case the MSI write causes a master abort */
 	pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd);
-	pci_write_config_word(adapter->pdev, PCI_COMMAND,
-			      pci_cmd & ~PCI_COMMAND_SERR);
+	if (pci_cmd & PCI_COMMAND_SERR)
+		pci_write_config_word(adapter->pdev, PCI_COMMAND,
+				      pci_cmd & ~PCI_COMMAND_SERR);
 
 	err = e1000_test_msi_interrupt(adapter);
 
-	/* restore previous setting of command word */
-	pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd);
+	/* re-enable SERR */
+	if (pci_cmd & PCI_COMMAND_SERR) {
+		pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd);
+		pci_cmd |= PCI_COMMAND_SERR;
+		pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd);
+	}
 
 	/* success ! */
 	if (!err)
@@ -3498,6 +3525,12 @@
 	     E1000_MNG_DHCP_COOKIE_STATUS_VLAN))
 		e1000_update_mng_vlan(adapter);
 
+	/* DMA latency requirement to workaround early-receive/jumbo issue */
+	if (adapter->flags & FLAG_HAS_ERT)
+		pm_qos_add_request(&adapter->netdev->pm_qos_req,
+				   PM_QOS_CPU_DMA_LATENCY,
+				   PM_QOS_DEFAULT_VALUE);
+
 	/*
 	 * before we allocate an interrupt, we must be ready to handle it.
 	 * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
@@ -3602,6 +3635,9 @@
 	if (adapter->flags & FLAG_HAS_AMT)
 		e1000_release_hw_control(adapter);
 
+	if (adapter->flags & FLAG_HAS_ERT)
+		pm_qos_remove_request(&adapter->netdev->pm_qos_req);
+
 	pm_runtime_put_sync(&pdev->dev);
 
 	return 0;
@@ -3672,6 +3708,110 @@
 }
 
 /**
+ * e1000e_update_phy_stats - Update the PHY statistics counters
+ * @adapter: board private structure
+ **/
+static void e1000e_update_phy_stats(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	s32 ret_val;
+	u16 phy_data;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		return;
+
+	hw->phy.addr = 1;
+
+#define HV_PHY_STATS_PAGE	778
+	/*
+	 * A page set is expensive so check if already on desired page.
+	 * If not, set to the page with the PHY status registers.
+	 */
+	ret_val = e1000e_read_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+					   &phy_data);
+	if (ret_val)
+		goto release;
+	if (phy_data != (HV_PHY_STATS_PAGE << IGP_PAGE_SHIFT)) {
+		ret_val = e1000e_write_phy_reg_mdic(hw,
+						    IGP01E1000_PHY_PAGE_SELECT,
+						    (HV_PHY_STATS_PAGE <<
+						     IGP_PAGE_SHIFT));
+		if (ret_val)
+			goto release;
+	}
+
+	/* Read/clear the upper 16-bit registers and read/accumulate lower */
+
+	/* Single Collision Count */
+	e1000e_read_phy_reg_mdic(hw, HV_SCC_UPPER & MAX_PHY_REG_ADDRESS,
+				 &phy_data);
+	ret_val = e1000e_read_phy_reg_mdic(hw,
+					   HV_SCC_LOWER & MAX_PHY_REG_ADDRESS,
+					   &phy_data);
+	if (!ret_val)
+		adapter->stats.scc += phy_data;
+
+	/* Excessive Collision Count */
+	e1000e_read_phy_reg_mdic(hw, HV_ECOL_UPPER & MAX_PHY_REG_ADDRESS,
+				 &phy_data);
+	ret_val = e1000e_read_phy_reg_mdic(hw,
+					   HV_ECOL_LOWER & MAX_PHY_REG_ADDRESS,
+					   &phy_data);
+	if (!ret_val)
+		adapter->stats.ecol += phy_data;
+
+	/* Multiple Collision Count */
+	e1000e_read_phy_reg_mdic(hw, HV_MCC_UPPER & MAX_PHY_REG_ADDRESS,
+				 &phy_data);
+	ret_val = e1000e_read_phy_reg_mdic(hw,
+					   HV_MCC_LOWER & MAX_PHY_REG_ADDRESS,
+					   &phy_data);
+	if (!ret_val)
+		adapter->stats.mcc += phy_data;
+
+	/* Late Collision Count */
+	e1000e_read_phy_reg_mdic(hw, HV_LATECOL_UPPER & MAX_PHY_REG_ADDRESS,
+				 &phy_data);
+	ret_val = e1000e_read_phy_reg_mdic(hw,
+					   HV_LATECOL_LOWER &
+					   MAX_PHY_REG_ADDRESS,
+					   &phy_data);
+	if (!ret_val)
+		adapter->stats.latecol += phy_data;
+
+	/* Collision Count - also used for adaptive IFS */
+	e1000e_read_phy_reg_mdic(hw, HV_COLC_UPPER & MAX_PHY_REG_ADDRESS,
+				 &phy_data);
+	ret_val = e1000e_read_phy_reg_mdic(hw,
+					   HV_COLC_LOWER & MAX_PHY_REG_ADDRESS,
+					   &phy_data);
+	if (!ret_val)
+		hw->mac.collision_delta = phy_data;
+
+	/* Defer Count */
+	e1000e_read_phy_reg_mdic(hw, HV_DC_UPPER & MAX_PHY_REG_ADDRESS,
+				 &phy_data);
+	ret_val = e1000e_read_phy_reg_mdic(hw,
+					   HV_DC_LOWER & MAX_PHY_REG_ADDRESS,
+					   &phy_data);
+	if (!ret_val)
+		adapter->stats.dc += phy_data;
+
+	/* Transmit with no CRS */
+	e1000e_read_phy_reg_mdic(hw, HV_TNCRS_UPPER & MAX_PHY_REG_ADDRESS,
+				 &phy_data);
+	ret_val = e1000e_read_phy_reg_mdic(hw,
+					   HV_TNCRS_LOWER & MAX_PHY_REG_ADDRESS,
+					   &phy_data);
+	if (!ret_val)
+		adapter->stats.tncrs += phy_data;
+
+release:
+	hw->phy.ops.release(hw);
+}
+
+/**
  * e1000e_update_stats - Update the board statistics counters
  * @adapter: board private structure
  **/
@@ -3680,7 +3820,6 @@
 	struct net_device *netdev = adapter->netdev;
 	struct e1000_hw *hw = &adapter->hw;
 	struct pci_dev *pdev = adapter->pdev;
-	u16 phy_data;
 
 	/*
 	 * Prevent stats update while adapter is being reset, or if the pci
@@ -3700,34 +3839,27 @@
 	adapter->stats.roc += er32(ROC);
 
 	adapter->stats.mpc += er32(MPC);
-	if ((hw->phy.type == e1000_phy_82578) ||
-	    (hw->phy.type == e1000_phy_82577)) {
-		e1e_rphy(hw, HV_SCC_UPPER, &phy_data);
-		if (!e1e_rphy(hw, HV_SCC_LOWER, &phy_data))
-			adapter->stats.scc += phy_data;
 
-		e1e_rphy(hw, HV_ECOL_UPPER, &phy_data);
-		if (!e1e_rphy(hw, HV_ECOL_LOWER, &phy_data))
-			adapter->stats.ecol += phy_data;
+	/* Half-duplex statistics */
+	if (adapter->link_duplex == HALF_DUPLEX) {
+		if (adapter->flags2 & FLAG2_HAS_PHY_STATS) {
+			e1000e_update_phy_stats(adapter);
+		} else {
+			adapter->stats.scc += er32(SCC);
+			adapter->stats.ecol += er32(ECOL);
+			adapter->stats.mcc += er32(MCC);
+			adapter->stats.latecol += er32(LATECOL);
+			adapter->stats.dc += er32(DC);
 
-		e1e_rphy(hw, HV_MCC_UPPER, &phy_data);
-		if (!e1e_rphy(hw, HV_MCC_LOWER, &phy_data))
-			adapter->stats.mcc += phy_data;
+			hw->mac.collision_delta = er32(COLC);
 
-		e1e_rphy(hw, HV_LATECOL_UPPER, &phy_data);
-		if (!e1e_rphy(hw, HV_LATECOL_LOWER, &phy_data))
-			adapter->stats.latecol += phy_data;
-
-		e1e_rphy(hw, HV_DC_UPPER, &phy_data);
-		if (!e1e_rphy(hw, HV_DC_LOWER, &phy_data))
-			adapter->stats.dc += phy_data;
-	} else {
-		adapter->stats.scc += er32(SCC);
-		adapter->stats.ecol += er32(ECOL);
-		adapter->stats.mcc += er32(MCC);
-		adapter->stats.latecol += er32(LATECOL);
-		adapter->stats.dc += er32(DC);
+			if ((hw->mac.type != e1000_82574) &&
+			    (hw->mac.type != e1000_82583))
+				adapter->stats.tncrs += er32(TNCRS);
+		}
+		adapter->stats.colc += hw->mac.collision_delta;
 	}
+
 	adapter->stats.xonrxc += er32(XONRXC);
 	adapter->stats.xontxc += er32(XONTXC);
 	adapter->stats.xoffrxc += er32(XOFFRXC);
@@ -3745,28 +3877,9 @@
 
 	hw->mac.tx_packet_delta = er32(TPT);
 	adapter->stats.tpt += hw->mac.tx_packet_delta;
-	if ((hw->phy.type == e1000_phy_82578) ||
-	    (hw->phy.type == e1000_phy_82577)) {
-		e1e_rphy(hw, HV_COLC_UPPER, &phy_data);
-		if (!e1e_rphy(hw, HV_COLC_LOWER, &phy_data))
-			hw->mac.collision_delta = phy_data;
-	} else {
-		hw->mac.collision_delta = er32(COLC);
-	}
-	adapter->stats.colc += hw->mac.collision_delta;
 
 	adapter->stats.algnerrc += er32(ALGNERRC);
 	adapter->stats.rxerrc += er32(RXERRC);
-	if ((hw->phy.type == e1000_phy_82578) ||
-	    (hw->phy.type == e1000_phy_82577)) {
-		e1e_rphy(hw, HV_TNCRS_UPPER, &phy_data);
-		if (!e1e_rphy(hw, HV_TNCRS_LOWER, &phy_data))
-			adapter->stats.tncrs += phy_data;
-	} else {
-		if ((hw->mac.type != e1000_82574) &&
-		    (hw->mac.type != e1000_82583))
-			adapter->stats.tncrs += er32(TNCRS);
-	}
 	adapter->stats.cexterr += er32(CEXTERR);
 	adapter->stats.tsctc += er32(TSCTC);
 	adapter->stats.tsctfc += er32(TSCTFC);
@@ -3865,7 +3978,7 @@
 	       ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" )));
 }
 
-bool e1000e_has_link(struct e1000_adapter *adapter)
+static bool e1000e_has_link(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
 	bool link_active = 0;
@@ -4841,14 +4954,7 @@
 	int retval = 0;
 
 	/* copy MAC RARs to PHY RARs */
-	for (i = 0; i < adapter->hw.mac.rar_entry_count; i++) {
-		mac_reg = er32(RAL(i));
-		e1e_wphy(hw, BM_RAR_L(i), (u16)(mac_reg & 0xFFFF));
-		e1e_wphy(hw, BM_RAR_M(i), (u16)((mac_reg >> 16) & 0xFFFF));
-		mac_reg = er32(RAH(i));
-		e1e_wphy(hw, BM_RAR_H(i), (u16)(mac_reg & 0xFFFF));
-		e1e_wphy(hw, BM_RAR_CTRL(i), (u16)((mac_reg >> 16) & 0xFFFF));
-	}
+	e1000_copy_rx_addrs_to_phy_ich8lan(hw);
 
 	/* copy MAC MTA to PHY MTA */
 	for (i = 0; i < adapter->hw.mac.mta_reg_count; i++) {
@@ -5551,8 +5657,6 @@
 	if (err)
 		goto err_sw_init;
 
-	err = -EIO;
-
 	memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops));
 	memcpy(&hw->nvm.ops, ei->nvm_ops, sizeof(hw->nvm.ops));
 	memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops));
@@ -5899,6 +6003,9 @@
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DM), board_pchlan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DC), board_pchlan },
 
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_LM), board_pch2lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_V), board_pch2lan },
+
 	{ }	/* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
@@ -5935,7 +6042,7 @@
 	int ret;
 	pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
 		e1000e_driver_version);
-	pr_info("Copyright (c) 1999 - 2009 Intel Corporation.\n");
+	pr_info("Copyright (c) 1999 - 2010 Intel Corporation.\n");
 	ret = pci_register_driver(&e1000_driver);
 
 	return ret;
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c
index a150e48..34aeec1 100644
--- a/drivers/net/e1000e/param.c
+++ b/drivers/net/e1000e/param.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
+  Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index b4ac82d..3d3dc0c 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
+  Copyright(c) 1999 - 2010 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,
@@ -2319,6 +2319,9 @@
 	case I82577_E_PHY_ID:
 		phy_type = e1000_phy_82577;
 		break;
+	case I82579_E_PHY_ID:
+		phy_type = e1000_phy_82579;
+		break;
 	default:
 		phy_type = e1000_phy_unknown;
 		break;
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 8b92acb..3beba70 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -335,7 +335,7 @@
 
 	memset(stats, 0, sizeof(*stats));
 
-	cb2 = (void *)get_zeroed_page(GFP_ATOMIC);
+	cb2 = (void *)get_zeroed_page(GFP_KERNEL);
 	if (!cb2) {
 		ehea_error("no mem for cb2");
 		goto out;
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index 882c50c..f608a6c 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -126,7 +126,7 @@
 			u8 immediate_data[SWQE2_MAX_IMM];
 			/* 0xd0 */
 			struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES-1];
-		} immdata_desc __attribute__ ((packed));
+		} immdata_desc __packed;
 
 		/*  Send WQE Format 3 */
 		struct {
diff --git a/drivers/net/enic/cq_desc.h b/drivers/net/enic/cq_desc.h
index 1eb289f..d6dd1b4 100644
--- a/drivers/net/enic/cq_desc.h
+++ b/drivers/net/enic/cq_desc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
diff --git a/drivers/net/enic/cq_enet_desc.h b/drivers/net/enic/cq_enet_desc.h
index 337d194..c2c0680 100644
--- a/drivers/net/enic/cq_enet_desc.h
+++ b/drivers/net/enic/cq_enet_desc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -73,7 +73,16 @@
 #define CQ_ENET_RQ_DESC_FLAGS_TRUNCATED             (0x1 << 14)
 #define CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED         (0x1 << 15)
 
-#define CQ_ENET_RQ_DESC_FCOE_SOF_BITS               4
+#define CQ_ENET_RQ_DESC_VLAN_TCI_VLAN_BITS          12
+#define CQ_ENET_RQ_DESC_VLAN_TCI_VLAN_MASK \
+	((1 << CQ_ENET_RQ_DESC_VLAN_TCI_VLAN_BITS) - 1)
+#define CQ_ENET_RQ_DESC_VLAN_TCI_CFI_MASK           (0x1 << 12)
+#define CQ_ENET_RQ_DESC_VLAN_TCI_USER_PRIO_BITS     3
+#define CQ_ENET_RQ_DESC_VLAN_TCI_USER_PRIO_MASK \
+	((1 << CQ_ENET_RQ_DESC_VLAN_TCI_USER_PRIO_BITS) - 1)
+#define CQ_ENET_RQ_DESC_VLAN_TCI_USER_PRIO_SHIFT    13
+
+#define CQ_ENET_RQ_DESC_FCOE_SOF_BITS               8
 #define CQ_ENET_RQ_DESC_FCOE_SOF_MASK \
 	((1 << CQ_ENET_RQ_DESC_FCOE_SOF_BITS) - 1)
 #define CQ_ENET_RQ_DESC_FCOE_EOF_BITS               8
@@ -96,7 +105,7 @@
 	u8 *type, u8 *color, u16 *q_number, u16 *completed_index,
 	u8 *ingress_port, u8 *fcoe, u8 *eop, u8 *sop, u8 *rss_type,
 	u8 *csum_not_calc, u32 *rss_hash, u16 *bytes_written, u8 *packet_error,
-	u8 *vlan_stripped, u16 *vlan, u16 *checksum, u8 *fcoe_sof,
+	u8 *vlan_stripped, u16 *vlan_tci, u16 *checksum, u8 *fcoe_sof,
 	u8 *fcoe_fc_crc_ok, u8 *fcoe_enc_error, u8 *fcoe_eof,
 	u8 *tcp_udp_csum_ok, u8 *udp, u8 *tcp, u8 *ipv4_csum_ok,
 	u8 *ipv6, u8 *ipv4, u8 *ipv4_fragment, u8 *fcs_ok)
@@ -136,7 +145,10 @@
 	*vlan_stripped = (bytes_written_flags &
 		CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED) ? 1 : 0;
 
-	*vlan = le16_to_cpu(desc->vlan);
+	/*
+	 * Tag Control Information(16) = user_priority(3) + cfi(1) + vlan(12)
+	 */
+	*vlan_tci = le16_to_cpu(desc->vlan);
 
 	if (*fcoe) {
 		*fcoe_sof = (u8)(le16_to_cpu(desc->checksum_fcoe) &
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index 45e86d1..f239aa8 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -20,8 +20,6 @@
 #ifndef _ENIC_H_
 #define _ENIC_H_
 
-#include <linux/inet_lro.h>
-
 #include "vnic_enet.h"
 #include "vnic_dev.h"
 #include "vnic_wq.h"
@@ -34,12 +32,8 @@
 
 #define DRV_NAME		"enic"
 #define DRV_DESCRIPTION		"Cisco VIC Ethernet NIC Driver"
-#define DRV_VERSION		"1.3.1.1-pp"
-#define DRV_COPYRIGHT		"Copyright 2008-2009 Cisco Systems, Inc"
-#define PFX			DRV_NAME ": "
-
-#define ENIC_LRO_MAX_DESC	8
-#define ENIC_LRO_MAX_AGGR	64
+#define DRV_VERSION		"1.4.1.1"
+#define DRV_COPYRIGHT		"Copyright 2008-2010 Cisco Systems, Inc"
 
 #define ENIC_BARS_MAX		6
 
@@ -116,6 +110,8 @@
 	spinlock_t wq_lock[ENIC_WQ_MAX];
 	unsigned int wq_count;
 	struct vlan_group *vlan_group;
+	u16 loop_enable;
+	u16 loop_tag;
 
 	/* receive queue cache line section */
 	____cacheline_aligned struct vnic_rq rq[ENIC_RQ_MAX];
@@ -124,8 +120,6 @@
 	u64 rq_truncated_pkts;
 	u64 rq_bad_fcs;
 	struct napi_struct napi;
-	struct net_lro_mgr lro_mgr;
-	struct net_lro_desc lro_desc[ENIC_LRO_MAX_DESC];
 
 	/* interrupt resource cache line section */
 	____cacheline_aligned struct vnic_intr intr[ENIC_INTR_MAX];
@@ -137,4 +131,9 @@
 	unsigned int cq_count;
 };
 
+static inline struct device *enic_get_dev(struct enic *enic)
+{
+	return &(enic->pdev->dev);
+}
+
 #endif /* _ENIC_H_ */
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index bc7d6b9..77a7f87 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -29,12 +29,12 @@
 #include <linux/etherdevice.h>
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
-#include <linux/if_link.h>
 #include <linux/ethtool.h>
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/tcp.h>
+#include <linux/rtnetlink.h>
 #include <net/ip6_checksum.h>
 
 #include "cq_enet_desc.h"
@@ -145,15 +145,25 @@
 	return 0;
 }
 
+static int enic_dev_fw_info(struct enic *enic,
+	struct vnic_devcmd_fw_info **fw_info)
+{
+	int err;
+
+	spin_lock(&enic->devcmd_lock);
+	err = vnic_dev_fw_info(enic->vdev, fw_info);
+	spin_unlock(&enic->devcmd_lock);
+
+	return err;
+}
+
 static void enic_get_drvinfo(struct net_device *netdev,
 	struct ethtool_drvinfo *drvinfo)
 {
 	struct enic *enic = netdev_priv(netdev);
 	struct vnic_devcmd_fw_info *fw_info;
 
-	spin_lock(&enic->devcmd_lock);
-	vnic_dev_fw_info(enic->vdev, &fw_info);
-	spin_unlock(&enic->devcmd_lock);
+	enic_dev_fw_info(enic, &fw_info);
 
 	strncpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
 	strncpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
@@ -191,6 +201,17 @@
 	}
 }
 
+static int enic_dev_stats_dump(struct enic *enic, struct vnic_stats **vstats)
+{
+	int err;
+
+	spin_lock(&enic->devcmd_lock);
+	err = vnic_dev_stats_dump(enic->vdev, vstats);
+	spin_unlock(&enic->devcmd_lock);
+
+	return err;
+}
+
 static void enic_get_ethtool_stats(struct net_device *netdev,
 	struct ethtool_stats *stats, u64 *data)
 {
@@ -198,9 +219,7 @@
 	struct vnic_stats *vstats;
 	unsigned int i;
 
-	spin_lock(&enic->devcmd_lock);
-	vnic_dev_stats_dump(enic->vdev, &vstats);
-	spin_unlock(&enic->devcmd_lock);
+	enic_dev_stats_dump(enic, &vstats);
 
 	for (i = 0; i < enic_n_tx_stats; i++)
 		*(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].offset];
@@ -346,7 +365,6 @@
 	.get_coalesce = enic_get_coalesce,
 	.set_coalesce = enic_set_coalesce,
 	.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)
@@ -399,15 +417,41 @@
 	for (i = 0; i < enic->wq_count; i++) {
 		error_status = vnic_wq_error_status(&enic->wq[i]);
 		if (error_status)
-			printk(KERN_ERR PFX "%s: WQ[%d] error_status %d\n",
-				enic->netdev->name, i, error_status);
+			netdev_err(enic->netdev, "WQ[%d] error_status %d\n",
+				i, error_status);
 	}
 
 	for (i = 0; i < enic->rq_count; i++) {
 		error_status = vnic_rq_error_status(&enic->rq[i]);
 		if (error_status)
-			printk(KERN_ERR PFX "%s: RQ[%d] error_status %d\n",
-				enic->netdev->name, i, error_status);
+			netdev_err(enic->netdev, "RQ[%d] error_status %d\n",
+				i, error_status);
+	}
+}
+
+static void enic_msglvl_check(struct enic *enic)
+{
+	u32 msg_enable = vnic_dev_msg_lvl(enic->vdev);
+
+	if (msg_enable != enic->msg_enable) {
+		netdev_info(enic->netdev, "msg lvl changed from 0x%x to 0x%x\n",
+			enic->msg_enable, msg_enable);
+		enic->msg_enable = msg_enable;
+	}
+}
+
+static void enic_mtu_check(struct enic *enic)
+{
+	u32 mtu = vnic_dev_mtu(enic->vdev);
+	struct net_device *netdev = enic->netdev;
+
+	if (mtu && mtu != enic->port_mtu) {
+		enic->port_mtu = mtu;
+		if (mtu < netdev->mtu)
+			netdev_warn(netdev,
+				"interface MTU (%d) set higher "
+				"than switch port MTU (%d)\n",
+				netdev->mtu, mtu);
 	}
 }
 
@@ -417,39 +461,14 @@
 	int carrier_ok = netif_carrier_ok(enic->netdev);
 
 	if (link_status && !carrier_ok) {
-		printk(KERN_INFO PFX "%s: Link UP\n", enic->netdev->name);
+		netdev_info(enic->netdev, "Link UP\n");
 		netif_carrier_on(enic->netdev);
 	} else if (!link_status && carrier_ok) {
-		printk(KERN_INFO PFX "%s: Link DOWN\n", enic->netdev->name);
+		netdev_info(enic->netdev, "Link DOWN\n");
 		netif_carrier_off(enic->netdev);
 	}
 }
 
-static void enic_mtu_check(struct enic *enic)
-{
-	u32 mtu = vnic_dev_mtu(enic->vdev);
-
-	if (mtu && mtu != enic->port_mtu) {
-		enic->port_mtu = mtu;
-		if (mtu < enic->netdev->mtu)
-			printk(KERN_WARNING PFX
-				"%s: interface MTU (%d) set higher "
-				"than switch port MTU (%d)\n",
-				enic->netdev->name, enic->netdev->mtu, mtu);
-	}
-}
-
-static void enic_msglvl_check(struct enic *enic)
-{
-	u32 msg_enable = vnic_dev_msg_lvl(enic->vdev);
-
-	if (msg_enable != enic->msg_enable) {
-		printk(KERN_INFO PFX "%s: msg lvl changed from 0x%x to 0x%x\n",
-			enic->netdev->name, enic->msg_enable, msg_enable);
-		enic->msg_enable = msg_enable;
-	}
-}
-
 static void enic_notify_check(struct enic *enic)
 {
 	enic_msglvl_check(enic);
@@ -574,7 +593,7 @@
 
 static inline void enic_queue_wq_skb_cont(struct enic *enic,
 	struct vnic_wq *wq, struct sk_buff *skb,
-	unsigned int len_left)
+	unsigned int len_left, int loopback)
 {
 	skb_frag_t *frag;
 
@@ -586,13 +605,14 @@
 				frag->page_offset, frag->size,
 				PCI_DMA_TODEVICE),
 			frag->size,
-			(len_left == 0));	/* EOP? */
+			(len_left == 0),	/* EOP? */
+			loopback);
 	}
 }
 
 static inline void enic_queue_wq_skb_vlan(struct enic *enic,
 	struct vnic_wq *wq, struct sk_buff *skb,
-	int vlan_tag_insert, unsigned int vlan_tag)
+	int vlan_tag_insert, unsigned int vlan_tag, int loopback)
 {
 	unsigned int head_len = skb_headlen(skb);
 	unsigned int len_left = skb->len - head_len;
@@ -608,15 +628,15 @@
 			head_len, PCI_DMA_TODEVICE),
 		head_len,
 		vlan_tag_insert, vlan_tag,
-		eop);
+		eop, loopback);
 
 	if (!eop)
-		enic_queue_wq_skb_cont(enic, wq, skb, len_left);
+		enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
 }
 
 static inline void enic_queue_wq_skb_csum_l4(struct enic *enic,
 	struct vnic_wq *wq, struct sk_buff *skb,
-	int vlan_tag_insert, unsigned int vlan_tag)
+	int vlan_tag_insert, unsigned int vlan_tag, int loopback)
 {
 	unsigned int head_len = skb_headlen(skb);
 	unsigned int len_left = skb->len - head_len;
@@ -636,15 +656,15 @@
 		csum_offset,
 		hdr_len,
 		vlan_tag_insert, vlan_tag,
-		eop);
+		eop, loopback);
 
 	if (!eop)
-		enic_queue_wq_skb_cont(enic, wq, skb, len_left);
+		enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
 }
 
 static inline void enic_queue_wq_skb_tso(struct enic *enic,
 	struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss,
-	int vlan_tag_insert, unsigned int vlan_tag)
+	int vlan_tag_insert, unsigned int vlan_tag, int loopback)
 {
 	unsigned int frag_len_left = skb_headlen(skb);
 	unsigned int len_left = skb->len - frag_len_left;
@@ -681,7 +701,7 @@
 			len,
 			mss, hdr_len,
 			vlan_tag_insert, vlan_tag,
-			eop && (len == frag_len_left));
+			eop && (len == frag_len_left), loopback);
 		frag_len_left -= len;
 		offset += len;
 	}
@@ -707,7 +727,8 @@
 				dma_addr,
 				len,
 				(len_left == 0) &&
-				(len == frag_len_left));	/* EOP? */
+				(len == frag_len_left),		/* EOP? */
+				loopback);
 			frag_len_left -= len;
 			offset += len;
 		}
@@ -720,22 +741,26 @@
 	unsigned int mss = skb_shinfo(skb)->gso_size;
 	unsigned int vlan_tag = 0;
 	int vlan_tag_insert = 0;
+	int loopback = 0;
 
 	if (enic->vlan_group && vlan_tx_tag_present(skb)) {
 		/* VLAN tag from trunking driver */
 		vlan_tag_insert = 1;
 		vlan_tag = vlan_tx_tag_get(skb);
+	} else if (enic->loop_enable) {
+		vlan_tag = enic->loop_tag;
+		loopback = 1;
 	}
 
 	if (mss)
 		enic_queue_wq_skb_tso(enic, wq, skb, mss,
-			vlan_tag_insert, vlan_tag);
+			vlan_tag_insert, vlan_tag, loopback);
 	else if	(skb->ip_summed == CHECKSUM_PARTIAL)
 		enic_queue_wq_skb_csum_l4(enic, wq, skb,
-			vlan_tag_insert, vlan_tag);
+			vlan_tag_insert, vlan_tag, loopback);
 	else
 		enic_queue_wq_skb_vlan(enic, wq, skb,
-			vlan_tag_insert, vlan_tag);
+			vlan_tag_insert, vlan_tag, loopback);
 }
 
 /* netif_tx_lock held, process context with BHs disabled, or BH */
@@ -769,8 +794,7 @@
 	    skb_shinfo(skb)->nr_frags + ENIC_DESC_MAX_SPLITS) {
 		netif_stop_queue(netdev);
 		/* This is a hard error, log it */
-		printk(KERN_ERR PFX "%s: BUG! Tx ring full when "
-			"queue awake!\n", netdev->name);
+		netdev_err(netdev, "BUG! Tx ring full when queue awake!\n");
 		spin_unlock_irqrestore(&enic->wq_lock[0], flags);
 		return NETDEV_TX_BUSY;
 	}
@@ -792,9 +816,7 @@
 	struct net_device_stats *net_stats = &netdev->stats;
 	struct vnic_stats *stats;
 
-	spin_lock(&enic->devcmd_lock);
-	vnic_dev_stats_dump(enic->vdev, &stats);
-	spin_unlock(&enic->devcmd_lock);
+	enic_dev_stats_dump(enic, &stats);
 
 	net_stats->tx_packets = stats->tx.tx_frames_ok;
 	net_stats->tx_bytes = stats->tx.tx_bytes_ok;
@@ -812,9 +834,10 @@
 	return net_stats;
 }
 
-static void enic_reset_mcaddrs(struct enic *enic)
+static void enic_reset_multicast_list(struct enic *enic)
 {
 	enic->mc_count = 0;
+	enic->flags = 0;
 }
 
 static int enic_set_mac_addr(struct net_device *netdev, char *addr)
@@ -891,6 +914,41 @@
 	return -EOPNOTSUPP;
 }
 
+static int enic_dev_packet_filter(struct enic *enic, int directed,
+	int multicast, int broadcast, int promisc, int allmulti)
+{
+	int err;
+
+	spin_lock(&enic->devcmd_lock);
+	err = vnic_dev_packet_filter(enic->vdev, directed,
+		multicast, broadcast, promisc, allmulti);
+	spin_unlock(&enic->devcmd_lock);
+
+	return err;
+}
+
+static int enic_dev_add_multicast_addr(struct enic *enic, u8 *addr)
+{
+	int err;
+
+	spin_lock(&enic->devcmd_lock);
+	err = vnic_dev_add_addr(enic->vdev, addr);
+	spin_unlock(&enic->devcmd_lock);
+
+	return err;
+}
+
+static int enic_dev_del_multicast_addr(struct enic *enic, u8 *addr)
+{
+	int err;
+
+	spin_lock(&enic->devcmd_lock);
+	err = vnic_dev_del_addr(enic->vdev, addr);
+	spin_unlock(&enic->devcmd_lock);
+
+	return err;
+}
+
 /* netif_tx_lock held, BHs disabled */
 static void enic_set_multicast_list(struct net_device *netdev)
 {
@@ -910,11 +968,9 @@
 	if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS)
 		mc_count = ENIC_MULTICAST_PERFECT_FILTERS;
 
-	spin_lock(&enic->devcmd_lock);
-
 	if (enic->flags != flags) {
 		enic->flags = flags;
-		vnic_dev_packet_filter(enic->vdev, directed,
+		enic_dev_packet_filter(enic, directed,
 			multicast, broadcast, promisc, allmulti);
 	}
 
@@ -937,7 +993,7 @@
 				mc_addr[j]) == 0)
 				break;
 		if (j == mc_count)
-			enic_del_multicast_addr(enic, enic->mc_addr[i]);
+			enic_dev_del_multicast_addr(enic, enic->mc_addr[i]);
 	}
 
 	for (i = 0; i < mc_count; i++) {
@@ -946,7 +1002,7 @@
 				enic->mc_addr[j]) == 0)
 				break;
 		if (j == enic->mc_count)
-			enic_add_multicast_addr(enic, mc_addr[i]);
+			enic_dev_add_multicast_addr(enic, mc_addr[i]);
 	}
 
 	/* Save the list to compare against next time
@@ -956,8 +1012,6 @@
 		memcpy(enic->mc_addr[i], mc_addr[i], ETH_ALEN);
 
 	enic->mc_count = mc_count;
-
-	spin_unlock(&enic->devcmd_lock);
 }
 
 /* rtnl lock is held */
@@ -1226,7 +1280,7 @@
 	struct enic *enic = vnic_dev_priv(rq->vdev);
 	struct net_device *netdev = enic->netdev;
 	struct sk_buff *skb;
-	unsigned int len = netdev->mtu + ETH_HLEN;
+	unsigned int len = netdev->mtu + VLAN_ETH_HLEN;
 	unsigned int os_buf_index = 0;
 	dma_addr_t dma_addr;
 
@@ -1263,12 +1317,24 @@
 	return 0;
 }
 
+static int enic_dev_hw_version(struct enic *enic,
+	enum vnic_dev_hw_version *hw_ver)
+{
+	int err;
+
+	spin_lock(&enic->devcmd_lock);
+	err = vnic_dev_hw_version(enic->vdev, hw_ver);
+	spin_unlock(&enic->devcmd_lock);
+
+	return err;
+}
+
 static int enic_set_rq_alloc_buf(struct enic *enic)
 {
 	enum vnic_dev_hw_version hw_ver;
 	int err;
 
-	err = vnic_dev_hw_version(enic->vdev, &hw_ver);
+	err = enic_dev_hw_version(enic, &hw_ver);
 	if (err)
 		return err;
 
@@ -1287,51 +1353,6 @@
 	return 0;
 }
 
-static int enic_get_skb_header(struct sk_buff *skb, void **iphdr,
-	void **tcph, u64 *hdr_flags, void *priv)
-{
-	struct cq_enet_rq_desc *cq_desc = priv;
-	unsigned int ip_len;
-	struct iphdr *iph;
-
-	u8 type, color, eop, sop, ingress_port, vlan_stripped;
-	u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof;
-	u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok;
-	u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc;
-	u8 packet_error;
-	u16 q_number, completed_index, bytes_written, vlan, checksum;
-	u32 rss_hash;
-
-	cq_enet_rq_desc_dec(cq_desc,
-		&type, &color, &q_number, &completed_index,
-		&ingress_port, &fcoe, &eop, &sop, &rss_type,
-		&csum_not_calc, &rss_hash, &bytes_written,
-		&packet_error, &vlan_stripped, &vlan, &checksum,
-		&fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error,
-		&fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp,
-		&ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment,
-		&fcs_ok);
-
-	if (!(ipv4 && tcp && !ipv4_fragment))
-		return -1;
-
-	skb_reset_network_header(skb);
-	iph = ip_hdr(skb);
-
-	ip_len = ip_hdrlen(skb);
-	skb_set_transport_header(skb, ip_len);
-
-	/* check if ip header and tcp header are complete */
-	if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
-		return -1;
-
-	*hdr_flags = LRO_IPV4 | LRO_TCP;
-	*tcph = tcp_hdr(skb);
-	*iphdr = iph;
-
-	return 0;
-}
-
 static void enic_rq_indicate_buf(struct vnic_rq *rq,
 	struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
 	int skipped, void *opaque)
@@ -1345,7 +1366,7 @@
 	u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok;
 	u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc;
 	u8 packet_error;
-	u16 q_number, completed_index, bytes_written, vlan, checksum;
+	u16 q_number, completed_index, bytes_written, vlan_tci, checksum;
 	u32 rss_hash;
 
 	if (skipped)
@@ -1360,7 +1381,7 @@
 		&type, &color, &q_number, &completed_index,
 		&ingress_port, &fcoe, &eop, &sop, &rss_type,
 		&csum_not_calc, &rss_hash, &bytes_written,
-		&packet_error, &vlan_stripped, &vlan, &checksum,
+		&packet_error, &vlan_stripped, &vlan_tci, &checksum,
 		&fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error,
 		&fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp,
 		&ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment,
@@ -1395,20 +1416,20 @@
 
 		skb->dev = netdev;
 
-		if (enic->vlan_group && vlan_stripped) {
+		if (enic->vlan_group && vlan_stripped &&
+			(vlan_tci & CQ_ENET_RQ_DESC_VLAN_TCI_VLAN_MASK)) {
 
-			if ((netdev->features & NETIF_F_LRO) && ipv4)
-				lro_vlan_hwaccel_receive_skb(&enic->lro_mgr,
-					skb, enic->vlan_group,
-					vlan, cq_desc);
+			if (netdev->features & NETIF_F_GRO)
+				vlan_gro_receive(&enic->napi, enic->vlan_group,
+					vlan_tci, skb);
 			else
 				vlan_hwaccel_receive_skb(skb,
-					enic->vlan_group, vlan);
+					enic->vlan_group, vlan_tci);
 
 		} else {
 
-			if ((netdev->features & NETIF_F_LRO) && ipv4)
-				lro_receive_skb(&enic->lro_mgr, skb, cq_desc);
+			if (netdev->features & NETIF_F_GRO)
+				napi_gro_receive(&enic->napi, skb);
 			else
 				netif_receive_skb(skb);
 
@@ -1438,7 +1459,6 @@
 static int enic_poll(struct napi_struct *napi, int budget)
 {
 	struct enic *enic = container_of(napi, struct enic, napi);
-	struct net_device *netdev = enic->netdev;
 	unsigned int rq_work_to_do = budget;
 	unsigned int wq_work_to_do = -1; /* no limit */
 	unsigned int  work_done, rq_work_done, wq_work_done;
@@ -1478,12 +1498,9 @@
 	if (rq_work_done < rq_work_to_do) {
 
 		/* Some work done, but not enough to stay in polling,
-		 * flush all LROs and exit polling
+		 * exit polling
 		 */
 
-		if (netdev->features & NETIF_F_LRO)
-			lro_flush_all(&enic->lro_mgr);
-
 		napi_complete(napi);
 		vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]);
 	}
@@ -1494,7 +1511,6 @@
 static int enic_poll_msix(struct napi_struct *napi, int budget)
 {
 	struct enic *enic = container_of(napi, struct enic, napi);
-	struct net_device *netdev = enic->netdev;
 	unsigned int work_to_do = budget;
 	unsigned int work_done;
 	int err;
@@ -1528,12 +1544,9 @@
 	if (work_done < work_to_do) {
 
 		/* Some work done, but not enough to stay in polling,
-		 * flush all LROs and exit polling
+		 * exit polling
 		 */
 
-		if (netdev->features & NETIF_F_LRO)
-			lro_flush_all(&enic->lro_mgr);
-
 		napi_complete(napi);
 		vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]);
 	}
@@ -1655,7 +1668,7 @@
 	}
 }
 
-static int enic_notify_set(struct enic *enic)
+static int enic_dev_notify_set(struct enic *enic)
 {
 	int err;
 
@@ -1676,6 +1689,39 @@
 	return err;
 }
 
+static int enic_dev_notify_unset(struct enic *enic)
+{
+	int err;
+
+	spin_lock(&enic->devcmd_lock);
+	err = vnic_dev_notify_unset(enic->vdev);
+	spin_unlock(&enic->devcmd_lock);
+
+	return err;
+}
+
+static int enic_dev_enable(struct enic *enic)
+{
+	int err;
+
+	spin_lock(&enic->devcmd_lock);
+	err = vnic_dev_enable(enic->vdev);
+	spin_unlock(&enic->devcmd_lock);
+
+	return err;
+}
+
+static int enic_dev_disable(struct enic *enic)
+{
+	int err;
+
+	spin_lock(&enic->devcmd_lock);
+	err = vnic_dev_disable(enic->vdev);
+	spin_unlock(&enic->devcmd_lock);
+
+	return err;
+}
+
 static void enic_notify_timer_start(struct enic *enic)
 {
 	switch (vnic_dev_get_intr_mode(enic->vdev)) {
@@ -1697,16 +1743,14 @@
 
 	err = enic_request_intr(enic);
 	if (err) {
-		printk(KERN_ERR PFX "%s: Unable to request irq.\n",
-			netdev->name);
+		netdev_err(netdev, "Unable to request irq.\n");
 		return err;
 	}
 
-	err = enic_notify_set(enic);
+	err = enic_dev_notify_set(enic);
 	if (err) {
-		printk(KERN_ERR PFX
-			"%s: Failed to alloc notify buffer, aborting.\n",
-			netdev->name);
+		netdev_err(netdev,
+			"Failed to alloc notify buffer, aborting.\n");
 		goto err_out_free_intr;
 	}
 
@@ -1714,9 +1758,7 @@
 		vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf);
 		/* Need at least one buffer on ring to get going */
 		if (vnic_rq_desc_used(&enic->rq[i]) == 0) {
-			printk(KERN_ERR PFX
-				"%s: Unable to alloc receive buffers.\n",
-				netdev->name);
+			netdev_err(netdev, "Unable to alloc receive buffers\n");
 			err = -ENOMEM;
 			goto err_out_notify_unset;
 		}
@@ -1732,9 +1774,7 @@
 
 	netif_wake_queue(netdev);
 	napi_enable(&enic->napi);
-	spin_lock(&enic->devcmd_lock);
-	vnic_dev_enable(enic->vdev);
-	spin_unlock(&enic->devcmd_lock);
+	enic_dev_enable(enic);
 
 	for (i = 0; i < enic->intr_count; i++)
 		vnic_intr_unmask(&enic->intr[i]);
@@ -1744,9 +1784,7 @@
 	return 0;
 
 err_out_notify_unset:
-	spin_lock(&enic->devcmd_lock);
-	vnic_dev_notify_unset(enic->vdev);
-	spin_unlock(&enic->devcmd_lock);
+	enic_dev_notify_unset(enic);
 err_out_free_intr:
 	enic_free_intr(enic);
 
@@ -1760,20 +1798,19 @@
 	unsigned int i;
 	int err;
 
-	for (i = 0; i < enic->intr_count; i++)
+	for (i = 0; i < enic->intr_count; i++) {
 		vnic_intr_mask(&enic->intr[i]);
+		(void)vnic_intr_masked(&enic->intr[i]); /* flush write */
+	}
 
 	enic_synchronize_irqs(enic);
 
 	del_timer_sync(&enic->notify_timer);
 
-	spin_lock(&enic->devcmd_lock);
-	vnic_dev_disable(enic->vdev);
-	spin_unlock(&enic->devcmd_lock);
+	enic_dev_disable(enic);
 	napi_disable(&enic->napi);
 	netif_carrier_off(netdev);
 	netif_tx_disable(netdev);
-
 	enic_dev_del_station_addr(enic);
 
 	for (i = 0; i < enic->wq_count; i++) {
@@ -1787,9 +1824,7 @@
 			return err;
 	}
 
-	spin_lock(&enic->devcmd_lock);
-	vnic_dev_notify_unset(enic->vdev);
-	spin_unlock(&enic->devcmd_lock);
+	enic_dev_notify_unset(enic);
 	enic_free_intr(enic);
 
 	for (i = 0; i < enic->wq_count; i++)
@@ -1818,10 +1853,9 @@
 	netdev->mtu = new_mtu;
 
 	if (netdev->mtu > enic->port_mtu)
-		printk(KERN_WARNING PFX
-			"%s: interface MTU (%d) set higher "
-			"than port MTU (%d)\n",
-			netdev->name, netdev->mtu, enic->port_mtu);
+		netdev_warn(netdev,
+			"interface MTU (%d) set higher than port MTU (%d)\n",
+			netdev->mtu, enic->port_mtu);
 
 	if (running)
 		enic_open(netdev);
@@ -1894,21 +1928,21 @@
 	err = enic_dev_wait(enic->vdev, vnic_dev_open,
 		vnic_dev_open_done, 0);
 	if (err)
-		printk(KERN_ERR PFX
-			"vNIC device open failed, err %d.\n", err);
+		dev_err(enic_get_dev(enic), "vNIC device open failed, err %d\n",
+			err);
 
 	return err;
 }
 
-static int enic_dev_soft_reset(struct enic *enic)
+static int enic_dev_hang_reset(struct enic *enic)
 {
 	int err;
 
-	err = enic_dev_wait(enic->vdev, vnic_dev_soft_reset,
-		vnic_dev_soft_reset_done, 0);
+	err = enic_dev_wait(enic->vdev, vnic_dev_hang_reset,
+		vnic_dev_hang_reset_done, 0);
 	if (err)
-		printk(KERN_ERR PFX
-			"vNIC soft reset failed, err %d.\n", err);
+		netdev_err(enic->netdev, "vNIC hang reset failed, err %d\n",
+			err);
 
 	return err;
 }
@@ -1922,15 +1956,43 @@
 	const u8 rss_enable = 0;
 	const u8 tso_ipid_split_en = 0;
 	const u8 ig_vlan_strip_en = 1;
+	int err;
 
 	/* Enable VLAN tag stripping.  RSS not enabled (yet).
 	 */
 
-	return enic_set_nic_cfg(enic,
+	spin_lock(&enic->devcmd_lock);
+	err = enic_set_nic_cfg(enic,
 		rss_default_cpu, rss_hash_type,
 		rss_hash_bits, rss_base_cpu,
 		rss_enable, tso_ipid_split_en,
 		ig_vlan_strip_en);
+	spin_unlock(&enic->devcmd_lock);
+
+	return err;
+}
+
+static int enic_dev_hang_notify(struct enic *enic)
+{
+	int err;
+
+	spin_lock(&enic->devcmd_lock);
+	err = vnic_dev_hang_notify(enic->vdev);
+	spin_unlock(&enic->devcmd_lock);
+
+	return err;
+}
+
+int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic)
+{
+	int err;
+
+	spin_lock(&enic->devcmd_lock);
+	err = vnic_dev_set_ig_vlan_rewrite_mode(enic->vdev,
+		IG_VLAN_REWRITE_MODE_PRIORITY_TAG_DEFAULT_VLAN);
+	spin_unlock(&enic->devcmd_lock);
+
+	return err;
 }
 
 static void enic_reset(struct work_struct *work)
@@ -1942,16 +2004,13 @@
 
 	rtnl_lock();
 
-	spin_lock(&enic->devcmd_lock);
-	vnic_dev_hang_notify(enic->vdev);
-	spin_unlock(&enic->devcmd_lock);
-
+	enic_dev_hang_notify(enic);
 	enic_stop(enic->netdev);
-	enic_dev_soft_reset(enic);
-	vnic_dev_init(enic->vdev, 0);
-	enic_reset_mcaddrs(enic);
+	enic_dev_hang_reset(enic);
+	enic_reset_multicast_list(enic);
 	enic_init_vnic_resources(enic);
 	enic_set_niccfg(enic);
+	enic_dev_set_ig_vlan_rewrite_mode(enic);
 	enic_open(enic->netdev);
 
 	rtnl_unlock();
@@ -2087,8 +2146,8 @@
 	.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_set_mac_address	= enic_set_mac_address,
+	.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,
@@ -2106,8 +2165,20 @@
 	enic_clear_intr_mode(enic);
 }
 
+static int enic_dev_stats_clear(struct enic *enic)
+{
+	int err;
+
+	spin_lock(&enic->devcmd_lock);
+	err = vnic_dev_stats_clear(enic->vdev);
+	spin_unlock(&enic->devcmd_lock);
+
+	return err;
+}
+
 int enic_dev_init(struct enic *enic)
 {
+	struct device *dev = enic_get_dev(enic);
 	struct net_device *netdev = enic->netdev;
 	int err;
 
@@ -2116,8 +2187,7 @@
 
 	err = enic_get_vnic_config(enic);
 	if (err) {
-		printk(KERN_ERR PFX
-			"Get vNIC configuration failed, aborting.\n");
+		dev_err(dev, "Get vNIC configuration failed, aborting\n");
 		return err;
 	}
 
@@ -2132,9 +2202,8 @@
 
 	err = enic_set_intr_mode(enic);
 	if (err) {
-		printk(KERN_ERR PFX
-			"Failed to set intr mode based on resource "
-			"counts and system capabilities, aborting.\n");
+		dev_err(dev, "Failed to set intr mode based on resource "
+			"counts and system capabilities, aborting\n");
 		return err;
 	}
 
@@ -2143,24 +2212,32 @@
 
 	err = enic_alloc_vnic_resources(enic);
 	if (err) {
-		printk(KERN_ERR PFX
-			"Failed to alloc vNIC resources, aborting.\n");
+		dev_err(dev, "Failed to alloc vNIC resources, aborting\n");
 		goto err_out_free_vnic_resources;
 	}
 
 	enic_init_vnic_resources(enic);
 
+	/* Clear LIF stats
+	 */
+	enic_dev_stats_clear(enic);
+
 	err = enic_set_rq_alloc_buf(enic);
 	if (err) {
-		printk(KERN_ERR PFX
-			"Failed to set RQ buffer allocator, aborting.\n");
+		dev_err(dev, "Failed to set RQ buffer allocator, aborting\n");
 		goto err_out_free_vnic_resources;
 	}
 
 	err = enic_set_niccfg(enic);
 	if (err) {
-		printk(KERN_ERR PFX
-			"Failed to config nic, aborting.\n");
+		dev_err(dev, "Failed to config nic, aborting\n");
+		goto err_out_free_vnic_resources;
+	}
+
+	err = enic_dev_set_ig_vlan_rewrite_mode(enic);
+	if (err) {
+		netdev_err(netdev,
+			"Failed to set ingress vlan rewrite mode, aborting.\n");
 		goto err_out_free_vnic_resources;
 	}
 
@@ -2194,6 +2271,7 @@
 static int __devinit enic_probe(struct pci_dev *pdev,
 	const struct pci_device_id *ent)
 {
+	struct device *dev = &pdev->dev;
 	struct net_device *netdev;
 	struct enic *enic;
 	int using_dac = 0;
@@ -2206,7 +2284,7 @@
 
 	netdev = alloc_etherdev(sizeof(struct enic));
 	if (!netdev) {
-		printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+		pr_err("Etherdev alloc failed, aborting\n");
 		return -ENOMEM;
 	}
 
@@ -2221,17 +2299,15 @@
 	/* Setup PCI resources
 	 */
 
-	err = pci_enable_device(pdev);
+	err = pci_enable_device_mem(pdev);
 	if (err) {
-		printk(KERN_ERR PFX
-			"Cannot enable PCI device, aborting.\n");
+		dev_err(dev, "Cannot enable PCI device, aborting\n");
 		goto err_out_free_netdev;
 	}
 
 	err = pci_request_regions(pdev, DRV_NAME);
 	if (err) {
-		printk(KERN_ERR PFX
-			"Cannot request PCI regions, aborting.\n");
+		dev_err(dev, "Cannot request PCI regions, aborting\n");
 		goto err_out_disable_device;
 	}
 
@@ -2246,23 +2322,20 @@
 	if (err) {
 		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
 		if (err) {
-			printk(KERN_ERR PFX
-				"No usable DMA configuration, aborting.\n");
+			dev_err(dev, "No usable DMA configuration, aborting\n");
 			goto err_out_release_regions;
 		}
 		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
 		if (err) {
-			printk(KERN_ERR PFX
-				"Unable to obtain 32-bit DMA "
-				"for consistent allocations, aborting.\n");
+			dev_err(dev, "Unable to obtain %u-bit DMA "
+				"for consistent allocations, aborting\n", 32);
 			goto err_out_release_regions;
 		}
 	} else {
 		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(40));
 		if (err) {
-			printk(KERN_ERR PFX
-				"Unable to obtain 40-bit DMA "
-				"for consistent allocations, aborting.\n");
+			dev_err(dev, "Unable to obtain %u-bit DMA "
+				"for consistent allocations, aborting\n", 40);
 			goto err_out_release_regions;
 		}
 		using_dac = 1;
@@ -2277,8 +2350,7 @@
 		enic->bar[i].len = pci_resource_len(pdev, i);
 		enic->bar[i].vaddr = pci_iomap(pdev, i, enic->bar[i].len);
 		if (!enic->bar[i].vaddr) {
-			printk(KERN_ERR PFX
-				"Cannot memory-map BAR %d, aborting.\n", i);
+			dev_err(dev, "Cannot memory-map BAR %d, aborting\n", i);
 			err = -ENODEV;
 			goto err_out_iounmap;
 		}
@@ -2291,8 +2363,7 @@
 	enic->vdev = vnic_dev_register(NULL, enic, pdev, enic->bar,
 		ARRAY_SIZE(enic->bar));
 	if (!enic->vdev) {
-		printk(KERN_ERR PFX
-			"vNIC registration failed, aborting.\n");
+		dev_err(dev, "vNIC registration failed, aborting\n");
 		err = -ENODEV;
 		goto err_out_iounmap;
 	}
@@ -2302,8 +2373,7 @@
 
 	err = enic_dev_open(enic);
 	if (err) {
-		printk(KERN_ERR PFX
-			"vNIC dev open failed, aborting.\n");
+		dev_err(dev, "vNIC dev open failed, aborting\n");
 		goto err_out_vnic_unregister;
 	}
 
@@ -2317,23 +2387,31 @@
 
 	netif_carrier_off(netdev);
 
+	/* Do not call dev_init for a dynamic vnic.
+	 * For a dynamic vnic, init_prov_info will be
+	 * called later by an upper layer.
+	 */
+
 	if (!enic_is_dynamic(enic)) {
 		err = vnic_dev_init(enic->vdev, 0);
 		if (err) {
-			printk(KERN_ERR PFX
-				"vNIC dev init failed, aborting.\n");
+			dev_err(dev, "vNIC dev init failed, aborting\n");
 			goto err_out_dev_close;
 		}
 	}
 
+	/* Setup devcmd lock
+	 */
+
+	spin_lock_init(&enic->devcmd_lock);
+
 	err = enic_dev_init(enic);
 	if (err) {
-		printk(KERN_ERR PFX
-			"Device initialization failed, aborting.\n");
+		dev_err(dev, "Device initialization failed, aborting\n");
 		goto err_out_dev_close;
 	}
 
-	/* Setup notification timer, HW reset task, and locks
+	/* Setup notification timer, HW reset task, and wq locks
 	 */
 
 	init_timer(&enic->notify_timer);
@@ -2345,8 +2423,6 @@
 	for (i = 0; i < enic->wq_count; i++)
 		spin_lock_init(&enic->wq_lock[i]);
 
-	spin_lock_init(&enic->devcmd_lock);
-
 	/* Register net device
 	 */
 
@@ -2355,8 +2431,7 @@
 
 	err = enic_set_mac_addr(netdev, enic->mac_addr);
 	if (err) {
-		printk(KERN_ERR PFX
-			"Invalid MAC address, aborting.\n");
+		dev_err(dev, "Invalid MAC address, aborting\n");
 		goto err_out_dev_deinit;
 	}
 
@@ -2372,31 +2447,27 @@
 	netdev->ethtool_ops = &enic_ethtool_ops;
 
 	netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+	if (ENIC_SETTING(enic, LOOP)) {
+		netdev->features &= ~NETIF_F_HW_VLAN_TX;
+		enic->loop_enable = 1;
+		enic->loop_tag = enic->config.loop_tag;
+		dev_info(dev, "loopback tag=0x%04x\n", enic->loop_tag);
+	}
 	if (ENIC_SETTING(enic, TXCSUM))
 		netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
 	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;
+		netdev->features |= NETIF_F_GRO;
 	if (using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
 
 	enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM);
 
-	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) {
-		printk(KERN_ERR PFX
-			"Cannot register net device, aborting.\n");
+		dev_err(dev, "Cannot register net device, aborting\n");
 		goto err_out_dev_deinit;
 	}
 
@@ -2450,7 +2521,7 @@
 
 static int __init enic_init_module(void)
 {
-	printk(KERN_INFO PFX "%s, ver %s\n", DRV_DESCRIPTION, DRV_VERSION);
+	pr_info("%s, ver %s\n", DRV_DESCRIPTION, DRV_VERSION);
 
 	return pci_register_driver(&enic_driver);
 }
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index 9b18840..29ede8a 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -46,7 +46,8 @@
 
 	err = vnic_dev_mac_addr(enic->vdev, enic->mac_addr);
 	if (err) {
-		printk(KERN_ERR PFX "Error getting MAC addr, %d\n", err);
+		dev_err(enic_get_dev(enic),
+			"Error getting MAC addr, %d\n", err);
 		return err;
 	}
 
@@ -56,7 +57,7 @@
 			offsetof(struct vnic_enet_config, m), \
 			sizeof(c->m), &c->m); \
 		if (err) { \
-			printk(KERN_ERR PFX \
+			dev_err(enic_get_dev(enic), \
 				"Error getting %s, %d\n", #m, err); \
 			return err; \
 		} \
@@ -69,6 +70,7 @@
 	GET_CONFIG(intr_timer_type);
 	GET_CONFIG(intr_mode);
 	GET_CONFIG(intr_timer_usec);
+	GET_CONFIG(loop_tag);
 
 	c->wq_desc_count =
 		min_t(u32, ENIC_MAX_WQ_DESCS,
@@ -92,10 +94,10 @@
 		INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
 		c->intr_timer_usec);
 
-	printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n",
+	dev_info(enic_get_dev(enic), "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 usec\n",
+	dev_info(enic_get_dev(enic), "vNIC mtu %d csum tx/rx %d/%d "
+		"tso/lro %d/%d intr timer %d usec\n",
 		c->mtu, ENIC_SETTING(enic, TXCSUM),
 		ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO),
 		ENIC_SETTING(enic, LRO), c->intr_timer_usec);
@@ -103,17 +105,7 @@
 	return 0;
 }
 
-void enic_add_multicast_addr(struct enic *enic, u8 *addr)
-{
-	vnic_dev_add_addr(enic->vdev, addr);
-}
-
-void enic_del_multicast_addr(struct enic *enic, u8 *addr)
-{
-	vnic_dev_del_addr(enic->vdev, addr);
-}
-
-void enic_add_vlan(struct enic *enic, u16 vlanid)
+int enic_add_vlan(struct enic *enic, u16 vlanid)
 {
 	u64 a0 = vlanid, a1 = 0;
 	int wait = 1000;
@@ -121,10 +113,12 @@
 
 	err = vnic_dev_cmd(enic->vdev, CMD_VLAN_ADD, &a0, &a1, wait);
 	if (err)
-		printk(KERN_ERR PFX "Can't add vlan id, %d\n", err);
+		dev_err(enic_get_dev(enic), "Can't add vlan id, %d\n", err);
+
+	return err;
 }
 
-void enic_del_vlan(struct enic *enic, u16 vlanid)
+int enic_del_vlan(struct enic *enic, u16 vlanid)
 {
 	u64 a0 = vlanid, a1 = 0;
 	int wait = 1000;
@@ -132,7 +126,9 @@
 
 	err = vnic_dev_cmd(enic->vdev, CMD_VLAN_DEL, &a0, &a1, wait);
 	if (err)
-		printk(KERN_ERR PFX "Can't delete vlan id, %d\n", err);
+		dev_err(enic_get_dev(enic), "Can't delete vlan id, %d\n", err);
+
+	return err;
 }
 
 int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
@@ -198,8 +194,8 @@
 		vnic_dev_get_res_count(enic->vdev, RES_TYPE_INTR_CTRL),
 		ENIC_INTR_MAX);
 
-	printk(KERN_INFO PFX "vNIC resources avail: "
-		"wq %d rq %d cq %d intr %d\n",
+	dev_info(enic_get_dev(enic),
+		"vNIC resources avail: wq %d rq %d cq %d intr %d\n",
 		enic->wq_count, enic->rq_count,
 		enic->cq_count, enic->intr_count);
 }
@@ -304,11 +300,6 @@
 			enic->config.intr_timer_type,
 			mask_on_assertion);
 	}
-
-	/* Clear LIF stats
-	 */
-
-	vnic_dev_stats_clear(enic->vdev);
 }
 
 int enic_alloc_vnic_resources(struct enic *enic)
@@ -319,15 +310,14 @@
 
 	intr_mode = vnic_dev_get_intr_mode(enic->vdev);
 
-	printk(KERN_INFO PFX "vNIC resources used:  "
+	dev_info(enic_get_dev(enic), "vNIC resources used:  "
 		"wq %d rq %d cq %d intr %d intr mode %s\n",
 		enic->wq_count, enic->rq_count,
 		enic->cq_count, enic->intr_count,
 		intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
 		intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
 		intr_mode == VNIC_DEV_INTR_MODE_MSIX ? "MSI-X" :
-		"unknown"
-		);
+		"unknown");
 
 	/* Allocate queue resources
 	 */
@@ -373,7 +363,8 @@
 	enic->legacy_pba = vnic_dev_get_res(enic->vdev,
 		RES_TYPE_INTR_PBA_LEGACY, 0);
 	if (!enic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
-		printk(KERN_ERR PFX "Failed to hook legacy pba resource\n");
+		dev_err(enic_get_dev(enic),
+			"Failed to hook legacy pba resource\n");
 		err = -ENODEV;
 		goto err_out_cleanup;
 	}
diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h
index 494664f..83bd172 100644
--- a/drivers/net/enic/enic_res.h
+++ b/drivers/net/enic/enic_res.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -43,7 +43,7 @@
 	void *os_buf, dma_addr_t dma_addr, unsigned int len,
 	unsigned int mss_or_csum_offset, unsigned int hdr_len,
 	int vlan_tag_insert, unsigned int vlan_tag,
-	int offload_mode, int cq_entry, int sop, int eop)
+	int offload_mode, int cq_entry, int sop, int eop, int loopback)
 {
 	struct wq_enet_desc *desc = vnic_wq_next_desc(wq);
 
@@ -56,61 +56,62 @@
 		0, /* fcoe_encap */
 		(u8)vlan_tag_insert,
 		(u16)vlan_tag,
-		0 /* loopback */);
+		(u8)loopback);
 
 	vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop);
 }
 
 static inline void enic_queue_wq_desc_cont(struct vnic_wq *wq,
-	void *os_buf, dma_addr_t dma_addr, unsigned int len, int eop)
+	void *os_buf, dma_addr_t dma_addr, unsigned int len,
+	int eop, int loopback)
 {
 	enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
 		0, 0, 0, 0, 0,
-		eop, 0 /* !SOP */, eop);
+		eop, 0 /* !SOP */, eop, loopback);
 }
 
 static inline void enic_queue_wq_desc(struct vnic_wq *wq, void *os_buf,
 	dma_addr_t dma_addr, unsigned int len, int vlan_tag_insert,
-	unsigned int vlan_tag, int eop)
+	unsigned int vlan_tag, int eop, int loopback)
 {
 	enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
 		0, 0, vlan_tag_insert, vlan_tag,
 		WQ_ENET_OFFLOAD_MODE_CSUM,
-		eop, 1 /* SOP */, eop);
+		eop, 1 /* SOP */, eop, loopback);
 }
 
 static inline void enic_queue_wq_desc_csum(struct vnic_wq *wq,
 	void *os_buf, dma_addr_t dma_addr, unsigned int len,
 	int ip_csum, int tcpudp_csum, int vlan_tag_insert,
-	unsigned int vlan_tag, int eop)
+	unsigned int vlan_tag, int eop, int loopback)
 {
 	enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
 		(ip_csum ? 1 : 0) + (tcpudp_csum ? 2 : 0),
 		0, vlan_tag_insert, vlan_tag,
 		WQ_ENET_OFFLOAD_MODE_CSUM,
-		eop, 1 /* SOP */, eop);
+		eop, 1 /* SOP */, eop, loopback);
 }
 
 static inline void enic_queue_wq_desc_csum_l4(struct vnic_wq *wq,
 	void *os_buf, dma_addr_t dma_addr, unsigned int len,
 	unsigned int csum_offset, unsigned int hdr_len,
-	int vlan_tag_insert, unsigned int vlan_tag, int eop)
+	int vlan_tag_insert, unsigned int vlan_tag, int eop, int loopback)
 {
 	enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
 		csum_offset, hdr_len, vlan_tag_insert, vlan_tag,
 		WQ_ENET_OFFLOAD_MODE_CSUM_L4,
-		eop, 1 /* SOP */, eop);
+		eop, 1 /* SOP */, eop, loopback);
 }
 
 static inline void enic_queue_wq_desc_tso(struct vnic_wq *wq,
 	void *os_buf, dma_addr_t dma_addr, unsigned int len,
 	unsigned int mss, unsigned int hdr_len, int vlan_tag_insert,
-	unsigned int vlan_tag, int eop)
+	unsigned int vlan_tag, int eop, int loopback)
 {
 	enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
 		mss, hdr_len, vlan_tag_insert, vlan_tag,
 		WQ_ENET_OFFLOAD_MODE_TSO,
-		eop, 1 /* SOP */, eop);
+		eop, 1 /* SOP */, eop, loopback);
 }
 
 static inline void enic_queue_rq_desc(struct vnic_rq *rq,
@@ -131,10 +132,8 @@
 struct enic;
 
 int enic_get_vnic_config(struct enic *);
-void enic_add_multicast_addr(struct enic *enic, u8 *addr);
-void enic_del_multicast_addr(struct enic *enic, u8 *addr);
-void enic_add_vlan(struct enic *enic, u16 vlanid);
-void enic_del_vlan(struct enic *enic, u16 vlanid);
+int enic_add_vlan(struct enic *enic, u16 vlanid);
+int enic_del_vlan(struct enic *enic, u16 vlanid);
 int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
 	u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
 	u8 ig_vlan_strip_en);
diff --git a/drivers/net/enic/rq_enet_desc.h b/drivers/net/enic/rq_enet_desc.h
index a06e649..e6dd309 100644
--- a/drivers/net/enic/rq_enet_desc.h
+++ b/drivers/net/enic/rq_enet_desc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
diff --git a/drivers/net/enic/vnic_cq.c b/drivers/net/enic/vnic_cq.c
index 020ae6c..b86d6ef 100644
--- a/drivers/net/enic/vnic_cq.c
+++ b/drivers/net/enic/vnic_cq.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -42,7 +42,7 @@
 
 	cq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_CQ, index);
 	if (!cq->ctrl) {
-		printk(KERN_ERR "Failed to hook CQ[%d] resource\n", index);
+		pr_err("Failed to hook CQ[%d] resource\n", index);
 		return -EINVAL;
 	}
 
diff --git a/drivers/net/enic/vnic_cq.h b/drivers/net/enic/vnic_cq.h
index 114763c..552d3da 100644
--- a/drivers/net/enic/vnic_cq.h
+++ b/drivers/net/enic/vnic_cq.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c
index e0d3328..6a5b578 100644
--- a/drivers/net/enic/vnic_dev.c
+++ b/drivers/net/enic/vnic_dev.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -23,21 +23,23 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/if_ether.h>
-#include <linux/slab.h>
 
 #include "vnic_resource.h"
 #include "vnic_devcmd.h"
 #include "vnic_dev.h"
 #include "vnic_stats.h"
 
+enum vnic_proxy_type {
+	PROXY_NONE,
+	PROXY_BY_BDF,
+};
+
 struct vnic_res {
 	void __iomem *vaddr;
 	dma_addr_t bus_addr;
 	unsigned int count;
 };
 
-#define VNIC_DEV_CAP_INIT	0x0001
-
 struct vnic_dev {
 	void *priv;
 	struct pci_dev *pdev;
@@ -48,13 +50,14 @@
 	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;
 	dma_addr_t stats_pa;
 	struct vnic_devcmd_fw_info *fw_info;
 	dma_addr_t fw_info_pa;
-	u32 cap_flags;
+	enum vnic_proxy_type proxy;
+	u32 proxy_index;
+	u64 args[VNIC_DEVCMD_NARGS];
 };
 
 #define VNIC_MAX_RES_HDR_SIZE \
@@ -78,19 +81,19 @@
 		return -EINVAL;
 
 	if (bar->len < VNIC_MAX_RES_HDR_SIZE) {
-		printk(KERN_ERR "vNIC BAR0 res hdr length error\n");
+		pr_err("vNIC BAR0 res hdr length error\n");
 		return -EINVAL;
 	}
 
 	rh = bar->vaddr;
 	if (!rh) {
-		printk(KERN_ERR "vNIC BAR0 res hdr not mem-mapped\n");
+		pr_err("vNIC BAR0 res hdr not mem-mapped\n");
 		return -EINVAL;
 	}
 
 	if (ioread32(&rh->magic) != VNIC_RES_MAGIC ||
 	    ioread32(&rh->version) != VNIC_RES_VERSION) {
-		printk(KERN_ERR "vNIC BAR0 res magic/version error "
+		pr_err("vNIC BAR0 res magic/version error "
 			"exp (%lx/%lx) curr (%x/%x)\n",
 			VNIC_RES_MAGIC, VNIC_RES_VERSION,
 			ioread32(&rh->magic), ioread32(&rh->version));
@@ -122,7 +125,7 @@
 			/* each count is stride bytes long */
 			len = count * VNIC_RES_STRIDE;
 			if (len + bar_offset > bar[bar_num].len) {
-				printk(KERN_ERR "vNIC BAR0 resource %d "
+				pr_err("vNIC BAR0 resource %d "
 					"out-of-bounds, offset 0x%x + "
 					"size 0x%x > bar len 0x%lx\n",
 					type, bar_offset,
@@ -229,8 +232,7 @@
 		&ring->base_addr_unaligned);
 
 	if (!ring->descs_unaligned) {
-		printk(KERN_ERR
-		  "Failed to allocate ring (size=%d), aborting\n",
+		pr_err("Failed to allocate ring (size=%d), aborting\n",
 			(int)ring->size);
 		return -ENOMEM;
 	}
@@ -258,23 +260,28 @@
 	}
 }
 
-int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
-	u64 *a0, u64 *a1, int wait)
+static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
+	int wait)
 {
 	struct vnic_devcmd __iomem *devcmd = vdev->devcmd;
+	unsigned int i;
 	int delay;
 	u32 status;
 	int err;
 
 	status = ioread32(&devcmd->status);
+	if (status == 0xFFFFFFFF) {
+		/* PCI-e target device is gone */
+		return -ENODEV;
+	}
 	if (status & STAT_BUSY) {
-		printk(KERN_ERR "Busy devcmd %d\n", _CMD_N(cmd));
+		pr_err("Busy devcmd %d\n", _CMD_N(cmd));
 		return -EBUSY;
 	}
 
 	if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) {
-		writeq(*a0, &devcmd->args[0]);
-		writeq(*a1, &devcmd->args[1]);
+		for (i = 0; i < VNIC_DEVCMD_NARGS; i++)
+			writeq(vdev->args[i], &devcmd->args[i]);
 		wmb();
 	}
 
@@ -288,31 +295,110 @@
 		udelay(100);
 
 		status = ioread32(&devcmd->status);
+		if (status == 0xFFFFFFFF) {
+			/* PCI-e target device is gone */
+			return -ENODEV;
+		}
+
 		if (!(status & STAT_BUSY)) {
 
 			if (status & STAT_ERROR) {
 				err = (int)readq(&devcmd->args[0]);
 				if (err != ERR_ECMDUNKNOWN ||
 				    cmd != CMD_CAPABILITY)
-					printk(KERN_ERR "Error %d devcmd %d\n",
+					pr_err("Error %d devcmd %d\n",
 						err, _CMD_N(cmd));
 				return err;
 			}
 
 			if (_CMD_DIR(cmd) & _CMD_DIR_READ) {
 				rmb();
-				*a0 = readq(&devcmd->args[0]);
-				*a1 = readq(&devcmd->args[1]);
+				for (i = 0; i < VNIC_DEVCMD_NARGS; i++)
+					vdev->args[i] = readq(&devcmd->args[i]);
 			}
 
 			return 0;
 		}
 	}
 
-	printk(KERN_ERR "Timedout devcmd %d\n", _CMD_N(cmd));
+	pr_err("Timedout devcmd %d\n", _CMD_N(cmd));
 	return -ETIMEDOUT;
 }
 
+static int vnic_dev_cmd_proxy_by_bdf(struct vnic_dev *vdev,
+	enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait)
+{
+	u32 status;
+	int err;
+
+	memset(vdev->args, 0, sizeof(vdev->args));
+
+	vdev->args[0] = vdev->proxy_index; /* bdf */
+	vdev->args[1] = cmd;
+	vdev->args[2] = *a0;
+	vdev->args[3] = *a1;
+
+	err = _vnic_dev_cmd(vdev, CMD_PROXY_BY_BDF, wait);
+	if (err)
+		return err;
+
+	status = (u32)vdev->args[0];
+	if (status & STAT_ERROR) {
+		err = (int)vdev->args[1];
+		if (err != ERR_ECMDUNKNOWN ||
+		    cmd != CMD_CAPABILITY)
+			pr_err("Error %d proxy devcmd %d\n", err, _CMD_N(cmd));
+		return err;
+	}
+
+	*a0 = vdev->args[1];
+	*a1 = vdev->args[2];
+
+	return 0;
+}
+
+static int vnic_dev_cmd_no_proxy(struct vnic_dev *vdev,
+	enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait)
+{
+	int err;
+
+	vdev->args[0] = *a0;
+	vdev->args[1] = *a1;
+
+	err = _vnic_dev_cmd(vdev, cmd, wait);
+
+	*a0 = vdev->args[0];
+	*a1 = vdev->args[1];
+
+	return err;
+}
+
+void vnic_dev_cmd_proxy_by_bdf_start(struct vnic_dev *vdev, u16 bdf)
+{
+	vdev->proxy = PROXY_BY_BDF;
+	vdev->proxy_index = bdf;
+}
+
+void vnic_dev_cmd_proxy_end(struct vnic_dev *vdev)
+{
+	vdev->proxy = PROXY_NONE;
+	vdev->proxy_index = 0;
+}
+
+int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
+	u64 *a0, u64 *a1, int wait)
+{
+	memset(vdev->args, 0, sizeof(vdev->args));
+
+	switch (vdev->proxy) {
+	case PROXY_BY_BDF:
+		return vnic_dev_cmd_proxy_by_bdf(vdev, cmd, a0, a1, wait);
+	case PROXY_NONE:
+	default:
+		return vnic_dev_cmd_no_proxy(vdev, cmd, a0, a1, wait);
+	}
+}
+
 static int vnic_dev_capable(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd)
 {
 	u64 a0 = (u32)cmd, a1 = 0;
@@ -431,6 +517,19 @@
 	return vnic_dev_cmd(vdev, CMD_ENABLE, &a0, &a1, wait);
 }
 
+int vnic_dev_enable_wait(struct vnic_dev *vdev)
+{
+	u64 a0 = 0, a1 = 0;
+	int wait = 1000;
+	int err;
+
+	err = vnic_dev_cmd(vdev, CMD_ENABLE_WAIT, &a0, &a1, wait);
+	if (err == ERR_ECMDUNKNOWN)
+		return vnic_dev_cmd(vdev, CMD_ENABLE, &a0, &a1, wait);
+
+	return err;
+}
+
 int vnic_dev_disable(struct vnic_dev *vdev)
 {
 	u64 a0 = 0, a1 = 0;
@@ -486,6 +585,44 @@
 	return 0;
 }
 
+int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg)
+{
+	u64 a0 = (u32)arg, a1 = 0;
+	int wait = 1000;
+	int err;
+
+	err = vnic_dev_cmd(vdev, CMD_HANG_RESET, &a0, &a1, wait);
+	if (err == ERR_ECMDUNKNOWN) {
+		err = vnic_dev_soft_reset(vdev, arg);
+		if (err)
+			return err;
+
+		return vnic_dev_init(vdev, 0);
+	}
+
+	return err;
+}
+
+int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done)
+{
+	u64 a0 = 0, a1 = 0;
+	int wait = 1000;
+	int err;
+
+	*done = 0;
+
+	err = vnic_dev_cmd(vdev, CMD_HANG_RESET_STATUS, &a0, &a1, wait);
+	if (err) {
+		if (err == ERR_ECMDUNKNOWN)
+			return vnic_dev_soft_reset_done(vdev, done);
+		return err;
+	}
+
+	*done = (a0 == 0);
+
+	return 0;
+}
+
 int vnic_dev_hang_notify(struct vnic_dev *vdev)
 {
 	u64 a0, a1;
@@ -512,7 +649,7 @@
 	return 0;
 }
 
-void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
+int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
 	int broadcast, int promisc, int allmulti)
 {
 	u64 a0, a1 = 0;
@@ -527,7 +664,29 @@
 
 	err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait);
 	if (err)
-		printk(KERN_ERR "Can't set packet filter\n");
+		pr_err("Can't set packet filter\n");
+
+	return err;
+}
+
+int vnic_dev_packet_filter_all(struct vnic_dev *vdev, int directed,
+	int multicast, int broadcast, int promisc, int allmulti)
+{
+	u64 a0, a1 = 0;
+	int wait = 1000;
+	int err;
+
+	a0 = (directed ? CMD_PFILTER_DIRECTED : 0) |
+	     (multicast ? CMD_PFILTER_MULTICAST : 0) |
+	     (broadcast ? CMD_PFILTER_BROADCAST : 0) |
+	     (promisc ? CMD_PFILTER_PROMISCUOUS : 0) |
+	     (allmulti ? CMD_PFILTER_ALL_MULTICAST : 0);
+
+	err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER_ALL, &a0, &a1, wait);
+	if (err)
+		pr_err("Can't set packet filter\n");
+
+	return err;
 }
 
 int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
@@ -542,7 +701,7 @@
 
 	err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
 	if (err)
-		printk(KERN_ERR "Can't add addr [%pM], %d\n", addr, err);
+		pr_err("Can't add addr [%pM], %d\n", addr, err);
 
 	return err;
 }
@@ -559,7 +718,21 @@
 
 	err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait);
 	if (err)
-		printk(KERN_ERR "Can't del addr [%pM], %d\n", addr, err);
+		pr_err("Can't del addr [%pM], %d\n", addr, err);
+
+	return err;
+}
+
+int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev,
+	u8 ig_vlan_rewrite_mode)
+{
+	u64 a0 = ig_vlan_rewrite_mode, a1 = 0;
+	int wait = 1000;
+	int err;
+
+	err = vnic_dev_cmd(vdev, CMD_IG_VLAN_REWRITE_MODE, &a0, &a1, wait);
+	if (err == ERR_ECMDUNKNOWN)
+		return 0;
 
 	return err;
 }
@@ -572,8 +745,7 @@
 
 	err = vnic_dev_cmd(vdev, CMD_IAR, &a0, &a1, wait);
 	if (err)
-		printk(KERN_ERR "Failed to raise INTR[%d], err %d\n",
-			intr, err);
+		pr_err("Failed to raise INTR[%d], err %d\n", intr, err);
 
 	return err;
 }
@@ -604,8 +776,7 @@
 	dma_addr_t notify_pa;
 
 	if (vdev->notify || vdev->notify_pa) {
-		printk(KERN_ERR "notify block %p still allocated",
-			vdev->notify);
+		pr_err("notify block %p still allocated", vdev->notify);
 		return -EINVAL;
 	}
 
@@ -618,22 +789,25 @@
 	return vnic_dev_notify_setcmd(vdev, notify_addr, notify_pa, intr);
 }
 
-void vnic_dev_notify_unsetcmd(struct vnic_dev *vdev)
+int vnic_dev_notify_unsetcmd(struct vnic_dev *vdev)
 {
 	u64 a0, a1;
 	int wait = 1000;
+	int err;
 
 	a0 = 0;  /* paddr = 0 to unset notify buffer */
 	a1 = 0x0000ffff00000000ULL; /* intr num = -1 to unreg for intr */
 	a1 += sizeof(struct vnic_devcmd_notify);
 
-	vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
+	err = vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
 	vdev->notify = NULL;
 	vdev->notify_pa = 0;
 	vdev->notify_sz = 0;
+
+	return err;
 }
 
-void vnic_dev_notify_unset(struct vnic_dev *vdev)
+int vnic_dev_notify_unset(struct vnic_dev *vdev)
 {
 	if (vdev->notify) {
 		pci_free_consistent(vdev->pdev,
@@ -642,7 +816,7 @@
 			vdev->notify_pa);
 	}
 
-	vnic_dev_notify_unsetcmd(vdev);
+	return vnic_dev_notify_unsetcmd(vdev);
 }
 
 static int vnic_dev_notify_ready(struct vnic_dev *vdev)
@@ -672,13 +846,14 @@
 	int wait = 1000;
 	int r = 0;
 
-	if (vdev->cap_flags & VNIC_DEV_CAP_INIT)
+	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_*.
+			/* 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);
 		}
@@ -700,7 +875,7 @@
 
 	*done = (a0 == 0);
 
-	*err = (a0 == 0) ? a1 : 0;
+	*err = (a0 == 0) ? (int)a1:0;
 
 	return 0;
 }
@@ -738,9 +913,6 @@
 
 int vnic_dev_link_status(struct vnic_dev *vdev)
 {
-	if (vdev->linkstatus)
-		return *vdev->linkstatus;
-
 	if (!vnic_dev_notify_ready(vdev))
 		return 0;
 
@@ -787,6 +959,14 @@
 	return vdev->notify_copy.status;
 }
 
+u32 vnic_dev_uif(struct vnic_dev *vdev)
+{
+	if (!vnic_dev_notify_ready(vdev))
+		return 0;
+
+	return vdev->notify_copy.uif;
+}
+
 void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
 	enum vnic_dev_intr_mode intr_mode)
 {
@@ -807,14 +987,9 @@
 				sizeof(struct vnic_devcmd_notify),
 				vdev->notify,
 				vdev->notify_pa);
-		if (vdev->linkstatus)
-			pci_free_consistent(vdev->pdev,
-				sizeof(u32),
-				vdev->linkstatus,
-				vdev->linkstatus_pa);
 		if (vdev->stats)
 			pci_free_consistent(vdev->pdev,
-				sizeof(struct vnic_dev),
+				sizeof(struct vnic_stats),
 				vdev->stats, vdev->stats_pa);
 		if (vdev->fw_info)
 			pci_free_consistent(vdev->pdev,
@@ -844,11 +1019,6 @@
 	if (!vdev->devcmd)
 		goto err_out;
 
-	vdev->cap_flags = 0;
-
-	if (vnic_dev_capable(vdev, CMD_INIT))
-		vdev->cap_flags |= VNIC_DEV_CAP_INIT;
-
 	return vdev;
 
 err_out:
diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h
index caccce3..3a61873 100644
--- a/drivers/net/enic/vnic_dev.h
+++ b/drivers/net/enic/vnic_dev.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -41,6 +41,9 @@
 }
 #endif
 
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 enum vnic_dev_hw_version {
 	VNIC_DEV_HW_VER_UNKNOWN,
 	VNIC_DEV_HW_VER_A1,
@@ -92,6 +95,8 @@
 	struct vnic_dev_ring *ring);
 int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
 	u64 *a0, u64 *a1, int wait);
+void vnic_dev_cmd_proxy_by_bdf_start(struct vnic_dev *vdev, u16 bdf);
+void vnic_dev_cmd_proxy_end(struct vnic_dev *vdev);
 int vnic_dev_fw_info(struct vnic_dev *vdev,
 	struct vnic_devcmd_fw_info **fw_info);
 int vnic_dev_hw_version(struct vnic_dev *vdev,
@@ -101,8 +106,10 @@
 int vnic_dev_stats_clear(struct vnic_dev *vdev);
 int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats);
 int vnic_dev_hang_notify(struct vnic_dev *vdev);
-void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
+int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
 	int broadcast, int promisc, int allmulti);
+int vnic_dev_packet_filter_all(struct vnic_dev *vdev, int directed,
+	int multicast, int broadcast, int promisc, int allmulti);
 int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr);
 int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr);
 int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
@@ -110,16 +117,18 @@
 int vnic_dev_notify_setcmd(struct vnic_dev *vdev,
 	void *notify_addr, dma_addr_t notify_pa, u16 intr);
 int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr);
-void vnic_dev_notify_unsetcmd(struct vnic_dev *vdev);
-void vnic_dev_notify_unset(struct vnic_dev *vdev);
+int vnic_dev_notify_unsetcmd(struct vnic_dev *vdev);
+int vnic_dev_notify_unset(struct vnic_dev *vdev);
 int vnic_dev_link_status(struct vnic_dev *vdev);
 u32 vnic_dev_port_speed(struct vnic_dev *vdev);
 u32 vnic_dev_msg_lvl(struct vnic_dev *vdev);
 u32 vnic_dev_mtu(struct vnic_dev *vdev);
 u32 vnic_dev_link_down_cnt(struct vnic_dev *vdev);
 u32 vnic_dev_notify_status(struct vnic_dev *vdev);
+u32 vnic_dev_uif(struct vnic_dev *vdev);
 int vnic_dev_close(struct vnic_dev *vdev);
 int vnic_dev_enable(struct vnic_dev *vdev);
+int vnic_dev_enable_wait(struct vnic_dev *vdev);
 int vnic_dev_disable(struct vnic_dev *vdev);
 int vnic_dev_open(struct vnic_dev *vdev, int arg);
 int vnic_dev_open_done(struct vnic_dev *vdev, int *done);
@@ -129,10 +138,14 @@
 int vnic_dev_deinit(struct vnic_dev *vdev);
 int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg);
 int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done);
+int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg);
+int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done);
 void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
 	enum vnic_dev_intr_mode intr_mode);
 enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev);
 void vnic_dev_unregister(struct vnic_dev *vdev);
+int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev,
+	u8 ig_vlan_rewrite_mode);
 struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
 	void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar,
 	unsigned int num_bars);
diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h
index d78bbcc..2066175 100644
--- a/drivers/net/enic/vnic_devcmd.h
+++ b/drivers/net/enic/vnic_devcmd.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -98,6 +98,9 @@
 	/* set Rx packet filter: (u32)a0=filters (see CMD_PFILTER_*) */
 	CMD_PACKET_FILTER	= _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 7),
 
+	/* set Rx packet filter for all: (u32)a0=filters (see CMD_PFILTER_*) */
+	CMD_PACKET_FILTER_ALL   = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 7),
+
 	/* hang detection notification */
 	CMD_HANG_NOTIFY         = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 8),
 
@@ -171,6 +174,9 @@
 	/* enable virtual link */
 	CMD_ENABLE		= _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 28),
 
+	/* enable virtual link, waiting variant. */
+	CMD_ENABLE_WAIT		= _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 28),
+
 	/* disable virtual link */
 	CMD_DISABLE		= _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 29),
 
@@ -211,6 +217,27 @@
 	 * in: (u16)a0=interrupt number to assert
 	 */
 	CMD_IAR			= _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 38),
+
+	/* initiate hangreset, like softreset after hang detected */
+	CMD_HANG_RESET		= _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 39),
+
+	/* hangreset status:
+	 *    out: a0=0 reset complete, a0=1 reset in progress */
+	CMD_HANG_RESET_STATUS   = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 40),
+
+	/*
+	 * Set hw ingress packet vlan rewrite mode:
+	 * in:  (u32)a0=new vlan rewrite mode
+	 * out: (u32)a0=old vlan rewrite mode */
+	CMD_IG_VLAN_REWRITE_MODE = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ENET, 41),
+
+	/*
+	 * in:  (u16)a0=bdf of target vnic
+	 *      (u32)a1=cmd to proxy
+	 *      a2-a15=args to cmd in a1
+	 * out: (u32)a0=status of proxied cmd
+	 *      a1-a15=out args of proxied cmd */
+	CMD_PROXY_BY_BDF =	_CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 42),
 };
 
 /* flags for CMD_OPEN */
@@ -226,6 +253,12 @@
 #define CMD_PFILTER_PROMISCUOUS		0x08
 #define CMD_PFILTER_ALL_MULTICAST	0x10
 
+/* rewrite modes for CMD_IG_VLAN_REWRITE_MODE */
+#define IG_VLAN_REWRITE_MODE_DEFAULT_TRUNK              0
+#define IG_VLAN_REWRITE_MODE_UNTAG_DEFAULT_VLAN         1
+#define IG_VLAN_REWRITE_MODE_PRIORITY_TAG_DEFAULT_VLAN  2
+#define IG_VLAN_REWRITE_MODE_PASS_THRU                  3
+
 enum vnic_devcmd_status {
 	STAT_NONE = 0,
 	STAT_BUSY = 1 << 0,	/* cmd in progress */
diff --git a/drivers/net/enic/vnic_enet.h b/drivers/net/enic/vnic_enet.h
index 8eeb675..3b32912 100644
--- a/drivers/net/enic/vnic_enet.h
+++ b/drivers/net/enic/vnic_enet.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -35,6 +35,7 @@
 	u8 intr_mode;
 	char devname[16];
 	u32 intr_timer_usec;
+	u16 loop_tag;
 };
 
 #define VENETF_TSO		0x1	/* TSO enabled */
@@ -48,5 +49,6 @@
 #define VENETF_RSSHASH_TCPIPV6	0x100	/* Hash on TCP + IPv6 fields */
 #define VENETF_RSSHASH_IPV6_EX	0x200	/* Hash on IPv6 extended fields */
 #define VENETF_RSSHASH_TCPIPV6_EX 0x400	/* Hash on TCP + IPv6 ext. fields */
+#define VENETF_LOOP		0x800	/* Loopback enabled */
 
 #endif /* _VNIC_ENIC_H_ */
diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/enic/vnic_intr.c
index 3934309..52ab61a 100644
--- a/drivers/net/enic/vnic_intr.c
+++ b/drivers/net/enic/vnic_intr.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -39,8 +39,7 @@
 
 	intr->ctrl = vnic_dev_get_res(vdev, RES_TYPE_INTR_CTRL, index);
 	if (!intr->ctrl) {
-		printk(KERN_ERR "Failed to hook INTR[%d].ctrl resource\n",
-			index);
+		pr_err("Failed to hook INTR[%d].ctrl resource\n", index);
 		return -EINVAL;
 	}
 
diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h
index 2fe6c63..09dc0b7 100644
--- a/drivers/net/enic/vnic_intr.h
+++ b/drivers/net/enic/vnic_intr.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -61,7 +61,11 @@
 static inline void vnic_intr_mask(struct vnic_intr *intr)
 {
 	iowrite32(1, &intr->ctrl->mask);
-	(void)ioread32(&intr->ctrl->mask);
+}
+
+static inline int vnic_intr_masked(struct vnic_intr *intr)
+{
+	return ioread32(&intr->ctrl->mask);
 }
 
 static inline void vnic_intr_return_credits(struct vnic_intr *intr,
diff --git a/drivers/net/enic/vnic_nic.h b/drivers/net/enic/vnic_nic.h
index cf80ab4..995a50d 100644
--- a/drivers/net/enic/vnic_nic.h
+++ b/drivers/net/enic/vnic_nic.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
diff --git a/drivers/net/enic/vnic_resource.h b/drivers/net/enic/vnic_resource.h
index b61c22a..810287b 100644
--- a/drivers/net/enic/vnic_resource.h
+++ b/drivers/net/enic/vnic_resource.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
diff --git a/drivers/net/enic/vnic_rq.c b/drivers/net/enic/vnic_rq.c
index cc580cf..dbb2aca 100644
--- a/drivers/net/enic/vnic_rq.c
+++ b/drivers/net/enic/vnic_rq.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -37,23 +37,23 @@
 	vdev = rq->vdev;
 
 	for (i = 0; i < blks; i++) {
-		rq->bufs[i] = kzalloc(VNIC_RQ_BUF_BLK_SZ, GFP_ATOMIC);
+		rq->bufs[i] = kzalloc(VNIC_RQ_BUF_BLK_SZ(count), GFP_ATOMIC);
 		if (!rq->bufs[i]) {
-			printk(KERN_ERR "Failed to alloc rq_bufs\n");
+			pr_err("Failed to alloc rq_bufs\n");
 			return -ENOMEM;
 		}
 	}
 
 	for (i = 0; i < blks; i++) {
 		buf = rq->bufs[i];
-		for (j = 0; j < VNIC_RQ_BUF_BLK_ENTRIES; j++) {
-			buf->index = i * VNIC_RQ_BUF_BLK_ENTRIES + j;
+		for (j = 0; j < VNIC_RQ_BUF_BLK_ENTRIES(count); j++) {
+			buf->index = i * VNIC_RQ_BUF_BLK_ENTRIES(count) + j;
 			buf->desc = (u8 *)rq->ring.descs +
 				rq->ring.desc_size * buf->index;
 			if (buf->index + 1 == count) {
 				buf->next = rq->bufs[0];
 				break;
-			} else if (j + 1 == VNIC_RQ_BUF_BLK_ENTRIES) {
+			} else if (j + 1 == VNIC_RQ_BUF_BLK_ENTRIES(count)) {
 				buf->next = rq->bufs[i + 1];
 			} else {
 				buf->next = buf + 1;
@@ -94,7 +94,7 @@
 
 	rq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_RQ, index);
 	if (!rq->ctrl) {
-		printk(KERN_ERR "Failed to hook RQ[%d] resource\n", index);
+		pr_err("Failed to hook RQ[%d] resource\n", index);
 		return -EINVAL;
 	}
 
@@ -119,10 +119,11 @@
 	unsigned int error_interrupt_offset)
 {
 	u64 paddr;
+	unsigned int count = rq->ring.desc_count;
 
 	paddr = (u64)rq->ring.base_addr | VNIC_PADDR_TARGET;
 	writeq(paddr, &rq->ctrl->ring_base);
-	iowrite32(rq->ring.desc_count, &rq->ctrl->ring_size);
+	iowrite32(count, &rq->ctrl->ring_size);
 	iowrite32(cq_index, &rq->ctrl->cq_index);
 	iowrite32(error_interrupt_enable, &rq->ctrl->error_interrupt_enable);
 	iowrite32(error_interrupt_offset, &rq->ctrl->error_interrupt_offset);
@@ -132,8 +133,8 @@
 	iowrite32(posted_index, &rq->ctrl->posted_index);
 
 	rq->to_use = rq->to_clean =
-		&rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES]
-			[fetch_index % VNIC_RQ_BUF_BLK_ENTRIES];
+		&rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES(count)]
+			[fetch_index % VNIC_RQ_BUF_BLK_ENTRIES(count)];
 }
 
 void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index,
@@ -145,6 +146,11 @@
 	/* Use current fetch_index as the ring starting point */
 	fetch_index = ioread32(&rq->ctrl->fetch_index);
 
+	if (fetch_index == 0xFFFFFFFF) { /* check for hardware gone  */
+		/* Hardware surprise removal: reset fetch_index */
+		fetch_index = 0;
+	}
+
 	vnic_rq_init_start(rq, cq_index,
 		fetch_index, fetch_index,
 		error_interrupt_enable,
@@ -174,7 +180,7 @@
 		udelay(10);
 	}
 
-	printk(KERN_ERR "Failed to disable RQ[%d]\n", rq->index);
+	pr_err("Failed to disable RQ[%d]\n", rq->index);
 
 	return -ETIMEDOUT;
 }
@@ -184,8 +190,7 @@
 {
 	struct vnic_rq_buf *buf;
 	u32 fetch_index;
-
-	BUG_ON(ioread32(&rq->ctrl->enable));
+	unsigned int count = rq->ring.desc_count;
 
 	buf = rq->to_clean;
 
@@ -199,9 +204,14 @@
 
 	/* Use current fetch_index as the ring starting point */
 	fetch_index = ioread32(&rq->ctrl->fetch_index);
+
+	if (fetch_index == 0xFFFFFFFF) { /* check for hardware gone  */
+		/* Hardware surprise removal: reset fetch_index */
+		fetch_index = 0;
+	}
 	rq->to_use = rq->to_clean =
-		&rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES]
-			[fetch_index % VNIC_RQ_BUF_BLK_ENTRIES];
+		&rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES(count)]
+			[fetch_index % VNIC_RQ_BUF_BLK_ENTRIES(count)];
 	iowrite32(fetch_index, &rq->ctrl->posted_index);
 
 	vnic_dev_clear_desc_ring(&rq->ring);
diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h
index 35e736c..2dc48f9 100644
--- a/drivers/net/enic/vnic_rq.h
+++ b/drivers/net/enic/vnic_rq.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008, 2009 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -52,12 +52,16 @@
 	u32 pad10;
 };
 
-/* Break the vnic_rq_buf allocations into blocks of 64 entries */
-#define VNIC_RQ_BUF_BLK_ENTRIES 64
-#define VNIC_RQ_BUF_BLK_SZ \
-	(VNIC_RQ_BUF_BLK_ENTRIES * sizeof(struct vnic_rq_buf))
+/* Break the vnic_rq_buf allocations into blocks of 32/64 entries */
+#define VNIC_RQ_BUF_MIN_BLK_ENTRIES 32
+#define VNIC_RQ_BUF_DFLT_BLK_ENTRIES 64
+#define VNIC_RQ_BUF_BLK_ENTRIES(entries) \
+	((unsigned int)((entries < VNIC_RQ_BUF_DFLT_BLK_ENTRIES) ? \
+	VNIC_RQ_BUF_MIN_BLK_ENTRIES : VNIC_RQ_BUF_DFLT_BLK_ENTRIES))
+#define VNIC_RQ_BUF_BLK_SZ(entries) \
+	(VNIC_RQ_BUF_BLK_ENTRIES(entries) * sizeof(struct vnic_rq_buf))
 #define VNIC_RQ_BUF_BLKS_NEEDED(entries) \
-	DIV_ROUND_UP(entries, VNIC_RQ_BUF_BLK_ENTRIES)
+	DIV_ROUND_UP(entries, VNIC_RQ_BUF_BLK_ENTRIES(entries))
 #define VNIC_RQ_BUF_BLKS_MAX VNIC_RQ_BUF_BLKS_NEEDED(4096)
 
 struct vnic_rq_buf {
diff --git a/drivers/net/enic/vnic_rss.h b/drivers/net/enic/vnic_rss.h
index 5fbb3c9..f62d187 100644
--- a/drivers/net/enic/vnic_rss.h
+++ b/drivers/net/enic/vnic_rss.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
diff --git a/drivers/net/enic/vnic_stats.h b/drivers/net/enic/vnic_stats.h
index 9ff9614..77750ec 100644
--- a/drivers/net/enic/vnic_stats.h
+++ b/drivers/net/enic/vnic_stats.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
diff --git a/drivers/net/enic/vnic_vic.c b/drivers/net/enic/vnic_vic.c
index d769772..197c9d2 100644
--- a/drivers/net/enic/vnic_vic.c
+++ b/drivers/net/enic/vnic_vic.c
@@ -25,9 +25,13 @@
 
 struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type)
 {
-	struct vic_provinfo *vp = kzalloc(VIC_PROVINFO_MAX_DATA, flags);
+	struct vic_provinfo *vp;
 
-	if (!vp || !oui)
+	if (!oui)
+		return NULL;
+
+	vp = kzalloc(VIC_PROVINFO_MAX_DATA, flags);
+	if (!vp)
 		return NULL;
 
 	memcpy(vp->oui, oui, sizeof(vp->oui));
diff --git a/drivers/net/enic/vnic_vic.h b/drivers/net/enic/vnic_vic.h
index 085c2a2..7e46e5e 100644
--- a/drivers/net/enic/vnic_vic.h
+++ b/drivers/net/enic/vnic_vic.h
@@ -44,7 +44,7 @@
 		u16 length;
 		u8 value[0];
 	} tlv[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define VIC_PROVINFO_MAX_DATA		1385
 #define VIC_PROVINFO_MAX_TLV_DATA (VIC_PROVINFO_MAX_DATA - \
diff --git a/drivers/net/enic/vnic_wq.c b/drivers/net/enic/vnic_wq.c
index 1378afb..122e33b 100644
--- a/drivers/net/enic/vnic_wq.c
+++ b/drivers/net/enic/vnic_wq.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -37,23 +37,23 @@
 	vdev = wq->vdev;
 
 	for (i = 0; i < blks; i++) {
-		wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ, GFP_ATOMIC);
+		wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ(count), GFP_ATOMIC);
 		if (!wq->bufs[i]) {
-			printk(KERN_ERR "Failed to alloc wq_bufs\n");
+			pr_err("Failed to alloc wq_bufs\n");
 			return -ENOMEM;
 		}
 	}
 
 	for (i = 0; i < blks; i++) {
 		buf = wq->bufs[i];
-		for (j = 0; j < VNIC_WQ_BUF_BLK_ENTRIES; j++) {
-			buf->index = i * VNIC_WQ_BUF_BLK_ENTRIES + j;
+		for (j = 0; j < VNIC_WQ_BUF_BLK_ENTRIES(count); j++) {
+			buf->index = i * VNIC_WQ_BUF_BLK_ENTRIES(count) + j;
 			buf->desc = (u8 *)wq->ring.descs +
 				wq->ring.desc_size * buf->index;
 			if (buf->index + 1 == count) {
 				buf->next = wq->bufs[0];
 				break;
-			} else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES) {
+			} else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES(count)) {
 				buf->next = wq->bufs[i + 1];
 			} else {
 				buf->next = buf + 1;
@@ -94,7 +94,7 @@
 
 	wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index);
 	if (!wq->ctrl) {
-		printk(KERN_ERR "Failed to hook WQ[%d] resource\n", index);
+		pr_err("Failed to hook WQ[%d] resource\n", index);
 		return -EINVAL;
 	}
 
@@ -119,10 +119,11 @@
 	unsigned int error_interrupt_offset)
 {
 	u64 paddr;
+	unsigned int count = wq->ring.desc_count;
 
 	paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET;
 	writeq(paddr, &wq->ctrl->ring_base);
-	iowrite32(wq->ring.desc_count, &wq->ctrl->ring_size);
+	iowrite32(count, &wq->ctrl->ring_size);
 	iowrite32(fetch_index, &wq->ctrl->fetch_index);
 	iowrite32(posted_index, &wq->ctrl->posted_index);
 	iowrite32(cq_index, &wq->ctrl->cq_index);
@@ -131,8 +132,8 @@
 	iowrite32(0, &wq->ctrl->error_status);
 
 	wq->to_use = wq->to_clean =
-		&wq->bufs[fetch_index / VNIC_WQ_BUF_BLK_ENTRIES]
-			[fetch_index % VNIC_WQ_BUF_BLK_ENTRIES];
+		&wq->bufs[fetch_index / VNIC_WQ_BUF_BLK_ENTRIES(count)]
+			[fetch_index % VNIC_WQ_BUF_BLK_ENTRIES(count)];
 }
 
 void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
@@ -167,7 +168,7 @@
 		udelay(10);
 	}
 
-	printk(KERN_ERR "Failed to disable WQ[%d]\n", wq->index);
+	pr_err("Failed to disable WQ[%d]\n", wq->index);
 
 	return -ETIMEDOUT;
 }
@@ -177,8 +178,6 @@
 {
 	struct vnic_wq_buf *buf;
 
-	BUG_ON(ioread32(&wq->ctrl->enable));
-
 	buf = wq->to_clean;
 
 	while (vnic_wq_desc_used(wq) > 0) {
diff --git a/drivers/net/enic/vnic_wq.h b/drivers/net/enic/vnic_wq.h
index 9c34d41..94ac462 100644
--- a/drivers/net/enic/vnic_wq.h
+++ b/drivers/net/enic/vnic_wq.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
@@ -60,12 +60,16 @@
 	void *desc;
 };
 
-/* Break the vnic_wq_buf allocations into blocks of 64 entries */
-#define VNIC_WQ_BUF_BLK_ENTRIES 64
-#define VNIC_WQ_BUF_BLK_SZ \
-	(VNIC_WQ_BUF_BLK_ENTRIES * sizeof(struct vnic_wq_buf))
+/* Break the vnic_wq_buf allocations into blocks of 32/64 entries */
+#define VNIC_WQ_BUF_MIN_BLK_ENTRIES 32
+#define VNIC_WQ_BUF_DFLT_BLK_ENTRIES 64
+#define VNIC_WQ_BUF_BLK_ENTRIES(entries) \
+	((unsigned int)((entries < VNIC_WQ_BUF_DFLT_BLK_ENTRIES) ? \
+	VNIC_WQ_BUF_MIN_BLK_ENTRIES : VNIC_WQ_BUF_DFLT_BLK_ENTRIES))
+#define VNIC_WQ_BUF_BLK_SZ(entries) \
+	(VNIC_WQ_BUF_BLK_ENTRIES(entries) * sizeof(struct vnic_wq_buf))
 #define VNIC_WQ_BUF_BLKS_NEEDED(entries) \
-	DIV_ROUND_UP(entries, VNIC_WQ_BUF_BLK_ENTRIES)
+	DIV_ROUND_UP(entries, VNIC_WQ_BUF_BLK_ENTRIES(entries))
 #define VNIC_WQ_BUF_BLKS_MAX VNIC_WQ_BUF_BLKS_NEEDED(4096)
 
 struct vnic_wq {
diff --git a/drivers/net/enic/wq_enet_desc.h b/drivers/net/enic/wq_enet_desc.h
index 483596c..c7021e3 100644
--- a/drivers/net/enic/wq_enet_desc.h
+++ b/drivers/net/enic/wq_enet_desc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ * Copyright 2008-2010 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
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 4c27465..57c8ac0 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -278,7 +278,6 @@
 	struct pci_dev *pci_dev;			/* PCI bus location. */
 	int chip_id, chip_flags;
 
-	struct net_device_stats stats;
 	struct timer_list timer;			/* Media selection timer. */
 	int tx_threshold;
 	unsigned char mc_filter[8];
@@ -770,7 +769,6 @@
 static void epic_pause(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct epic_private *ep = netdev_priv(dev);
 
 	netif_stop_queue (dev);
 
@@ -781,9 +779,9 @@
 
 	/* Update the error counts. */
 	if (inw(ioaddr + COMMAND) != 0xffff) {
-		ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
-		ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
-		ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+		dev->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+		dev->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+		dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
 	}
 
 	/* Remove the packets on the Rx queue. */
@@ -900,7 +898,7 @@
 		}
 	}
 	if (inw(ioaddr + TxSTAT) & 0x10) {		/* Tx FIFO underflow. */
-		ep->stats.tx_fifo_errors++;
+		dev->stats.tx_fifo_errors++;
 		outl(RestartTx, ioaddr + COMMAND);
 	} else {
 		epic_restart(dev);
@@ -908,7 +906,7 @@
 	}
 
 	dev->trans_start = jiffies; /* prevent tx timeout */
-	ep->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	if (!ep->tx_full)
 		netif_wake_queue(dev);
 }
@@ -1016,7 +1014,7 @@
 static void epic_tx_error(struct net_device *dev, struct epic_private *ep,
 			  int status)
 {
-	struct net_device_stats *stats = &ep->stats;
+	struct net_device_stats *stats = &dev->stats;
 
 #ifndef final_version
 	/* There was an major error, log it. */
@@ -1053,9 +1051,9 @@
 			break;	/* It still hasn't been Txed */
 
 		if (likely(txstatus & 0x0001)) {
-			ep->stats.collisions += (txstatus >> 8) & 15;
-			ep->stats.tx_packets++;
-			ep->stats.tx_bytes += ep->tx_skbuff[entry]->len;
+			dev->stats.collisions += (txstatus >> 8) & 15;
+			dev->stats.tx_packets++;
+			dev->stats.tx_bytes += ep->tx_skbuff[entry]->len;
 		} else
 			epic_tx_error(dev, ep, txstatus);
 
@@ -1125,12 +1123,12 @@
 			goto out;
 
 		/* Always update the error counts to avoid overhead later. */
-		ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
-		ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
-		ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+		dev->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+		dev->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+		dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
 
 		if (status & TxUnderrun) { /* Tx FIFO underflow. */
-			ep->stats.tx_fifo_errors++;
+			dev->stats.tx_fifo_errors++;
 			outl(ep->tx_threshold += 128, ioaddr + TxThresh);
 			/* Restart the transmit process. */
 			outl(RestartTx, ioaddr + COMMAND);
@@ -1183,10 +1181,10 @@
 			if (status & 0x2000) {
 				printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
 					   "multiple buffers, status %4.4x!\n", dev->name, status);
-				ep->stats.rx_length_errors++;
+				dev->stats.rx_length_errors++;
 			} else if (status & 0x0006)
 				/* Rx Frame errors are counted in hardware. */
-				ep->stats.rx_errors++;
+				dev->stats.rx_errors++;
 		} else {
 			/* Malloc up new buffer, compatible with net-2e. */
 			/* Omit the four octet CRC from the length. */
@@ -1223,8 +1221,8 @@
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_receive_skb(skb);
-			ep->stats.rx_packets++;
-			ep->stats.rx_bytes += pkt_len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += pkt_len;
 		}
 		work_done++;
 		entry = (++ep->cur_rx) % RX_RING_SIZE;
@@ -1259,7 +1257,7 @@
 	if (status == EpicRemoved)
 		return;
 	if (status & RxOverflow) 	/* Missed a Rx frame. */
-		ep->stats.rx_errors++;
+		dev->stats.rx_errors++;
 	if (status & (RxOverflow | RxFull))
 		outw(RxQueued, ioaddr + COMMAND);
 }
@@ -1357,17 +1355,16 @@
 
 static struct net_device_stats *epic_get_stats(struct net_device *dev)
 {
-	struct epic_private *ep = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	if (netif_running(dev)) {
 		/* Update the error counts. */
-		ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
-		ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
-		ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+		dev->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+		dev->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+		dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
 	}
 
-	return &ep->stats;
+	return &dev->stats;
 }
 
 /* Set or clear the multicast filter for this adaptor.
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 874973f..10e39f2 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -1442,8 +1442,10 @@
 		dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]);
 
 		if(io[this_dev] == 0) {
-			if(this_dev != 0) /* Only autoprobe 1st one */
+			if (this_dev != 0) { /* Only autoprobe 1st one */
+				free_netdev(dev);
 				break;
+			}
 
 			printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n");
 		}
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index 6ed2df1..6d653c4 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -180,9 +180,9 @@
  * @dty_tx:	last buffer actually sent
  * @num_rx:	number of receive buffers
  * @cur_rx:	current receive buffer
+ * @vma:        pointer to array of virtual memory addresses for buffers
  * @netdev:	pointer to network device structure
  * @napi:	NAPI structure
- * @stats:	network device statistics
  * @msg_enable:	device state flags
  * @rx_lock:	receive lock
  * @lock:	device lock
@@ -203,9 +203,10 @@
 	unsigned int num_rx;
 	unsigned int cur_rx;
 
+	void** vma;
+
 	struct net_device *netdev;
 	struct napi_struct napi;
-	struct net_device_stats stats;
 	u32 msg_enable;
 
 	spinlock_t rx_lock;
@@ -285,18 +286,22 @@
 	ethoc_write(dev, MODER, mode);
 }
 
-static int ethoc_init_ring(struct ethoc *dev)
+static int ethoc_init_ring(struct ethoc *dev, unsigned long mem_start)
 {
 	struct ethoc_bd bd;
 	int i;
+	void* vma;
 
 	dev->cur_tx = 0;
 	dev->dty_tx = 0;
 	dev->cur_rx = 0;
 
+	ethoc_write(dev, TX_BD_NUM, dev->num_tx);
+
 	/* setup transmission buffers */
-	bd.addr = virt_to_phys(dev->membase);
+	bd.addr = mem_start;
 	bd.stat = TX_BD_IRQ | TX_BD_CRC;
+	vma = dev->membase;
 
 	for (i = 0; i < dev->num_tx; i++) {
 		if (i == dev->num_tx - 1)
@@ -304,6 +309,9 @@
 
 		ethoc_write_bd(dev, i, &bd);
 		bd.addr += ETHOC_BUFSIZ;
+
+		dev->vma[i] = vma;
+		vma += ETHOC_BUFSIZ;
 	}
 
 	bd.stat = RX_BD_EMPTY | RX_BD_IRQ;
@@ -314,6 +322,9 @@
 
 		ethoc_write_bd(dev, dev->num_tx + i, &bd);
 		bd.addr += ETHOC_BUFSIZ;
+
+		dev->vma[dev->num_tx + i] = vma;
+		vma += ETHOC_BUFSIZ;
 	}
 
 	return 0;
@@ -354,39 +365,39 @@
 
 	if (bd->stat & RX_BD_TL) {
 		dev_err(&netdev->dev, "RX: frame too long\n");
-		dev->stats.rx_length_errors++;
+		netdev->stats.rx_length_errors++;
 		ret++;
 	}
 
 	if (bd->stat & RX_BD_SF) {
 		dev_err(&netdev->dev, "RX: frame too short\n");
-		dev->stats.rx_length_errors++;
+		netdev->stats.rx_length_errors++;
 		ret++;
 	}
 
 	if (bd->stat & RX_BD_DN) {
 		dev_err(&netdev->dev, "RX: dribble nibble\n");
-		dev->stats.rx_frame_errors++;
+		netdev->stats.rx_frame_errors++;
 	}
 
 	if (bd->stat & RX_BD_CRC) {
 		dev_err(&netdev->dev, "RX: wrong CRC\n");
-		dev->stats.rx_crc_errors++;
+		netdev->stats.rx_crc_errors++;
 		ret++;
 	}
 
 	if (bd->stat & RX_BD_OR) {
 		dev_err(&netdev->dev, "RX: overrun\n");
-		dev->stats.rx_over_errors++;
+		netdev->stats.rx_over_errors++;
 		ret++;
 	}
 
 	if (bd->stat & RX_BD_MISS)
-		dev->stats.rx_missed_errors++;
+		netdev->stats.rx_missed_errors++;
 
 	if (bd->stat & RX_BD_LC) {
 		dev_err(&netdev->dev, "RX: late collision\n");
-		dev->stats.collisions++;
+		netdev->stats.collisions++;
 		ret++;
 	}
 
@@ -415,18 +426,18 @@
 			skb = netdev_alloc_skb_ip_align(dev, size);
 
 			if (likely(skb)) {
-				void *src = phys_to_virt(bd.addr);
+				void *src = priv->vma[entry];
 				memcpy_fromio(skb_put(skb, size), src, size);
 				skb->protocol = eth_type_trans(skb, dev);
-				priv->stats.rx_packets++;
-				priv->stats.rx_bytes += size;
+				dev->stats.rx_packets++;
+				dev->stats.rx_bytes += size;
 				netif_receive_skb(skb);
 			} else {
 				if (net_ratelimit())
 					dev_warn(&dev->dev, "low on memory - "
 							"packet dropped\n");
 
-				priv->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				break;
 			}
 		}
@@ -447,30 +458,30 @@
 
 	if (bd->stat & TX_BD_LC) {
 		dev_err(&netdev->dev, "TX: late collision\n");
-		dev->stats.tx_window_errors++;
+		netdev->stats.tx_window_errors++;
 	}
 
 	if (bd->stat & TX_BD_RL) {
 		dev_err(&netdev->dev, "TX: retransmit limit\n");
-		dev->stats.tx_aborted_errors++;
+		netdev->stats.tx_aborted_errors++;
 	}
 
 	if (bd->stat & TX_BD_UR) {
 		dev_err(&netdev->dev, "TX: underrun\n");
-		dev->stats.tx_fifo_errors++;
+		netdev->stats.tx_fifo_errors++;
 	}
 
 	if (bd->stat & TX_BD_CS) {
 		dev_err(&netdev->dev, "TX: carrier sense lost\n");
-		dev->stats.tx_carrier_errors++;
+		netdev->stats.tx_carrier_errors++;
 	}
 
 	if (bd->stat & TX_BD_STATS)
-		dev->stats.tx_errors++;
+		netdev->stats.tx_errors++;
 
-	dev->stats.collisions += (bd->stat >> 4) & 0xf;
-	dev->stats.tx_bytes += bd->stat >> 16;
-	dev->stats.tx_packets++;
+	netdev->stats.collisions += (bd->stat >> 4) & 0xf;
+	netdev->stats.tx_bytes += bd->stat >> 16;
+	netdev->stats.tx_packets++;
 	return 0;
 }
 
@@ -501,7 +512,7 @@
 
 static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
 {
-	struct net_device *dev = (struct net_device *)dev_id;
+	struct net_device *dev = dev_id;
 	struct ethoc *priv = netdev_priv(dev);
 	u32 pending;
 
@@ -516,7 +527,7 @@
 
 	if (pending & INT_MASK_BUSY) {
 		dev_err(&dev->dev, "packet dropped\n");
-		priv->stats.rx_dropped++;
+		dev->stats.rx_dropped++;
 	}
 
 	if (pending & INT_MASK_RX) {
@@ -600,8 +611,11 @@
 
 	while (time_before(jiffies, timeout)) {
 		u32 stat = ethoc_read(priv, MIISTATUS);
-		if (!(stat & MIISTATUS_BUSY))
+		if (!(stat & MIISTATUS_BUSY)) {
+			/* reset MII command register */
+			ethoc_write(priv, MIICOMMAND, 0);
 			return 0;
+		}
 
 		schedule();
 	}
@@ -618,25 +632,16 @@
 {
 }
 
-static int ethoc_mdio_probe(struct net_device *dev)
+static int __devinit ethoc_mdio_probe(struct net_device *dev)
 {
 	struct ethoc *priv = netdev_priv(dev);
 	struct phy_device *phy;
-	int i;
+	int err;
 
-	for (i = 0; i < PHY_MAX_ADDR; i++) {
-		phy = priv->mdio->phy_map[i];
-		if (phy) {
-			if (priv->phy_id != -1) {
-				/* attach to specified PHY */
-				if (priv->phy_id == phy->addr)
-					break;
-			} else {
-				/* autoselect PHY if none was specified */
-				if (phy->addr != 0)
-					break;
-			}
-		}
+	if (priv->phy_id != -1) {
+		phy = priv->mdio->phy_map[priv->phy_id];
+	} else {
+		phy = phy_find_first(priv->mdio);
 	}
 
 	if (!phy) {
@@ -644,11 +649,11 @@
 		return -ENXIO;
 	}
 
-	phy = phy_connect(dev, dev_name(&phy->dev), ethoc_mdio_poll, 0,
+	err = phy_connect_direct(dev, phy, ethoc_mdio_poll, 0,
 			PHY_INTERFACE_MODE_GMII);
-	if (IS_ERR(phy)) {
+	if (err) {
 		dev_err(&dev->dev, "could not attach to PHY\n");
-		return PTR_ERR(phy);
+		return err;
 	}
 
 	priv->phy = phy;
@@ -658,8 +663,6 @@
 static int ethoc_open(struct net_device *dev)
 {
 	struct ethoc *priv = netdev_priv(dev);
-	unsigned int min_tx = 2;
-	unsigned int num_bd;
 	int ret;
 
 	ret = request_irq(dev->irq, ethoc_interrupt, IRQF_SHARED,
@@ -667,14 +670,7 @@
 	if (ret)
 		return ret;
 
-	/* calculate the number of TX/RX buffers, maximum 128 supported */
-	num_bd = min_t(unsigned int,
-		128, (dev->mem_end - dev->mem_start + 1) / ETHOC_BUFSIZ);
-	priv->num_tx = max(min_tx, num_bd / 4);
-	priv->num_rx = num_bd - priv->num_tx;
-	ethoc_write(priv, TX_BD_NUM, priv->num_tx);
-
-	ethoc_init_ring(priv);
+	ethoc_init_ring(priv, dev->mem_start);
 	ethoc_reset(priv);
 
 	if (netif_queue_stopped(dev)) {
@@ -734,7 +730,7 @@
 		phy = priv->phy;
 	}
 
-	return phy_mii_ioctl(phy, mdio, cmd);
+	return phy_mii_ioctl(phy, ifr, cmd);
 }
 
 static int ethoc_config(struct net_device *dev, struct ifmap *map)
@@ -812,8 +808,7 @@
 
 static struct net_device_stats *ethoc_stats(struct net_device *dev)
 {
-	struct ethoc *priv = netdev_priv(dev);
-	return &priv->stats;
+	return &dev->stats;
 }
 
 static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -824,7 +819,7 @@
 	void *dest;
 
 	if (unlikely(skb->len > ETHOC_BUFSIZ)) {
-		priv->stats.tx_errors++;
+		dev->stats.tx_errors++;
 		goto out;
 	}
 
@@ -838,7 +833,7 @@
 	else
 		bd.stat &= ~TX_BD_PAD;
 
-	dest = phys_to_virt(bd.addr);
+	dest = priv->vma[entry];
 	memcpy_toio(dest, skb->data, skb->len);
 
 	bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK);
@@ -876,7 +871,7 @@
  * ethoc_probe() - initialize OpenCores ethernet MAC
  * pdev:	platform device
  */
-static int ethoc_probe(struct platform_device *pdev)
+static int __devinit ethoc_probe(struct platform_device *pdev)
 {
 	struct net_device *netdev = NULL;
 	struct resource *res = NULL;
@@ -884,6 +879,7 @@
 	struct resource *mem = NULL;
 	struct ethoc *priv = NULL;
 	unsigned int phy;
+	int num_bd;
 	int ret = 0;
 
 	/* allocate networking device */
@@ -965,7 +961,7 @@
 		}
 	} else {
 		/* Allocate buffer memory */
-		priv->membase = dma_alloc_coherent(NULL,
+		priv->membase = dmam_alloc_coherent(&pdev->dev,
 			buffer_size, (void *)&netdev->mem_start,
 			GFP_KERNEL);
 		if (!priv->membase) {
@@ -978,6 +974,18 @@
 		priv->dma_alloc = buffer_size;
 	}
 
+	/* calculate the number of TX/RX buffers, maximum 128 supported */
+	num_bd = min_t(unsigned int,
+		128, (netdev->mem_end - netdev->mem_start + 1) / ETHOC_BUFSIZ);
+	priv->num_tx = max(2, num_bd / 4);
+	priv->num_rx = num_bd - priv->num_tx;
+
+	priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void*), GFP_KERNEL);
+	if (!priv->vma) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
 	/* Allow the platform setup code to pass in a MAC address. */
 	if (pdev->dev.platform_data) {
 		struct ethoc_platform_data *pdata =
@@ -1063,21 +1071,6 @@
 	kfree(priv->mdio->irq);
 	mdiobus_free(priv->mdio);
 free:
-	if (priv) {
-		if (priv->dma_alloc)
-			dma_free_coherent(NULL, priv->dma_alloc, priv->membase,
-					  netdev->mem_start);
-		else if (priv->membase)
-			devm_iounmap(&pdev->dev, priv->membase);
-		if (priv->iobase)
-			devm_iounmap(&pdev->dev, priv->iobase);
-	}
-	if (mem)
-		devm_release_mem_region(&pdev->dev, mem->start,
-					mem->end - mem->start + 1);
-	if (mmio)
-		devm_release_mem_region(&pdev->dev, mmio->start,
-					mmio->end - mmio->start + 1);
 	free_netdev(netdev);
 out:
 	return ret;
@@ -1087,7 +1080,7 @@
  * ethoc_remove() - shutdown OpenCores ethernet MAC
  * @pdev:	platform device
  */
-static int ethoc_remove(struct platform_device *pdev)
+static int __devexit ethoc_remove(struct platform_device *pdev)
 {
 	struct net_device *netdev = platform_get_drvdata(pdev);
 	struct ethoc *priv = netdev_priv(netdev);
@@ -1104,17 +1097,6 @@
 			kfree(priv->mdio->irq);
 			mdiobus_free(priv->mdio);
 		}
-		if (priv->dma_alloc)
-			dma_free_coherent(NULL, priv->dma_alloc, priv->membase,
-				netdev->mem_start);
-		else {
-			devm_iounmap(&pdev->dev, priv->membase);
-			devm_release_mem_region(&pdev->dev, netdev->mem_start,
-				netdev->mem_end - netdev->mem_start + 1);
-		}
-		devm_iounmap(&pdev->dev, priv->iobase);
-		devm_release_mem_region(&pdev->dev, netdev->base_addr,
-			priv->io_region_size);
 		unregister_netdev(netdev);
 		free_netdev(netdev);
 	}
@@ -1139,7 +1121,7 @@
 
 static struct platform_driver ethoc_driver = {
 	.probe   = ethoc_probe,
-	.remove  = ethoc_remove,
+	.remove  = __devexit_p(ethoc_remove),
 	.suspend = ethoc_suspend,
 	.resume  = ethoc_resume,
 	.driver  = {
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index 15f4f8d..d7e8f6b 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -382,8 +382,6 @@
 
 	spinlock_t lock;
 
-	struct net_device_stats stats;
-
 	/* Media monitoring timer. */
 	struct timer_list timer;
 
@@ -1234,7 +1232,7 @@
 	spin_unlock_irqrestore(&np->lock, flags);
 
 	dev->trans_start = jiffies; /* prevent tx timeout */
-	np->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	netif_wake_queue(dev); /* or .._start_.. ?? */
 }
 
@@ -1479,10 +1477,11 @@
 
 		if (intr_status & CNTOVF) {
 			/* missed pkts */
-			np->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff;
+			dev->stats.rx_missed_errors +=
+				ioread32(ioaddr + TALLY) & 0x7fff;
 
 			/* crc error */
-			np->stats.rx_crc_errors +=
+			dev->stats.rx_crc_errors +=
 			    (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16;
 		}
 
@@ -1513,30 +1512,30 @@
 
 			if (!(np->crvalue & CR_W_ENH)) {
 				if (tx_status & (CSL | LC | EC | UDF | HF)) {
-					np->stats.tx_errors++;
+					dev->stats.tx_errors++;
 					if (tx_status & EC)
-						np->stats.tx_aborted_errors++;
+						dev->stats.tx_aborted_errors++;
 					if (tx_status & CSL)
-						np->stats.tx_carrier_errors++;
+						dev->stats.tx_carrier_errors++;
 					if (tx_status & LC)
-						np->stats.tx_window_errors++;
+						dev->stats.tx_window_errors++;
 					if (tx_status & UDF)
-						np->stats.tx_fifo_errors++;
+						dev->stats.tx_fifo_errors++;
 					if ((tx_status & HF) && np->mii.full_duplex == 0)
-						np->stats.tx_heartbeat_errors++;
+						dev->stats.tx_heartbeat_errors++;
 
 				} else {
-					np->stats.tx_bytes +=
+					dev->stats.tx_bytes +=
 					    ((tx_control & PKTSMask) >> PKTSShift);
 
-					np->stats.collisions +=
+					dev->stats.collisions +=
 					    ((tx_status & NCRMask) >> NCRShift);
-					np->stats.tx_packets++;
+					dev->stats.tx_packets++;
 				}
 			} else {
-				np->stats.tx_bytes +=
+				dev->stats.tx_bytes +=
 				    ((tx_control & PKTSMask) >> PKTSShift);
-				np->stats.tx_packets++;
+				dev->stats.tx_packets++;
 			}
 
 			/* Free the original skb. */
@@ -1564,10 +1563,12 @@
 			long data;
 
 			data = ioread32(ioaddr + TSR);
-			np->stats.tx_errors += (data & 0xff000000) >> 24;
-			np->stats.tx_aborted_errors += (data & 0xff000000) >> 24;
-			np->stats.tx_window_errors += (data & 0x00ff0000) >> 16;
-			np->stats.collisions += (data & 0x0000ffff);
+			dev->stats.tx_errors += (data & 0xff000000) >> 24;
+			dev->stats.tx_aborted_errors +=
+				(data & 0xff000000) >> 24;
+			dev->stats.tx_window_errors +=
+				(data & 0x00ff0000) >> 16;
+			dev->stats.collisions += (data & 0x0000ffff);
 		}
 
 		if (--boguscnt < 0) {
@@ -1593,10 +1594,11 @@
 
 	/* read the tally counters */
 	/* missed pkts */
-	np->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff;
+	dev->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff;
 
 	/* crc error */
-	np->stats.rx_crc_errors += (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16;
+	dev->stats.rx_crc_errors +=
+		(ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16;
 
 	if (debug)
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
@@ -1635,13 +1637,13 @@
 					       "%s: Receive error, Rx status %8.8x.\n",
 					       dev->name, rx_status);
 
-				np->stats.rx_errors++;	/* end of a packet. */
+				dev->stats.rx_errors++;	/* end of a packet. */
 				if (rx_status & (LONG | RUNT))
-					np->stats.rx_length_errors++;
+					dev->stats.rx_length_errors++;
 				if (rx_status & RXER)
-					np->stats.rx_frame_errors++;
+					dev->stats.rx_frame_errors++;
 				if (rx_status & CRC)
-					np->stats.rx_crc_errors++;
+					dev->stats.rx_crc_errors++;
 			} else {
 				int need_to_reset = 0;
 				int desno = 0;
@@ -1667,7 +1669,7 @@
 				if (need_to_reset == 0) {
 					int i;
 
-					np->stats.rx_length_errors++;
+					dev->stats.rx_length_errors++;
 
 					/* free all rx descriptors related this long pkt */
 					for (i = 0; i < desno; ++i) {
@@ -1733,8 +1735,8 @@
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
-			np->stats.rx_packets++;
-			np->stats.rx_bytes += pkt_len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += pkt_len;
 		}
 
 		np->cur_rx = np->cur_rx->next_desc_logical;
@@ -1754,11 +1756,13 @@
 
 	/* The chip only need report frame silently dropped. */
 	if (netif_running(dev)) {
-		np->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff;
-		np->stats.rx_crc_errors += (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16;
+		dev->stats.rx_missed_errors +=
+			ioread32(ioaddr + TALLY) & 0x7fff;
+		dev->stats.rx_crc_errors +=
+			(ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16;
 	}
 
-	return &np->stats;
+	return &dev->stats;
 }
 
 
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index edfff92..768b840 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -118,6 +118,8 @@
 #define FEC_ENET_MII	((uint)0x00800000)	/* MII interrupt */
 #define FEC_ENET_EBERR	((uint)0x00400000)	/* SDMA bus error */
 
+#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
+
 /* The FEC stores dest/src/type, data, and checksum for receive packets.
  */
 #define PKT_MAXBUF_SIZE		1518
@@ -187,6 +189,7 @@
 	int	index;
 	int	link;
 	int	full_duplex;
+	struct	completion mdio_done;
 };
 
 static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
@@ -205,12 +208,12 @@
 #define FEC_MMFR_TA		(2 << 16)
 #define FEC_MMFR_DATA(v)	(v & 0xffff)
 
-#define FEC_MII_TIMEOUT		10000
+#define FEC_MII_TIMEOUT		1000 /* us */
 
 /* Transmitter timeout */
 #define TX_TIMEOUT (2 * HZ)
 
-static int
+static netdev_tx_t
 fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct fec_enet_private *fep = netdev_priv(dev);
@@ -334,6 +337,11 @@
 			ret = IRQ_HANDLED;
 			fec_enet_tx(dev);
 		}
+
+		if (int_events & FEC_ENET_MII) {
+			ret = IRQ_HANDLED;
+			complete(&fep->mdio_done);
+		}
 	} while (int_events);
 
 	return ret;
@@ -608,18 +616,13 @@
 		phy_print_status(phy_dev);
 }
 
-/*
- * NOTE: a MII transaction is during around 25 us, so polling it...
- */
 static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 {
 	struct fec_enet_private *fep = bus->priv;
-	int timeout = FEC_MII_TIMEOUT;
+	unsigned long time_left;
 
 	fep->mii_timeout = 0;
-
-	/* clear MII end of transfer bit*/
-	writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
+	init_completion(&fep->mdio_done);
 
 	/* start a read op */
 	writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
@@ -627,13 +630,12 @@
 		FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
 
 	/* wait for end of transfer */
-	while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) {
-		cpu_relax();
-		if (timeout-- < 0) {
-			fep->mii_timeout = 1;
-			printk(KERN_ERR "FEC: MDIO read timeout\n");
-			return -ETIMEDOUT;
-		}
+	time_left = wait_for_completion_timeout(&fep->mdio_done,
+			usecs_to_jiffies(FEC_MII_TIMEOUT));
+	if (time_left == 0) {
+		fep->mii_timeout = 1;
+		printk(KERN_ERR "FEC: MDIO read timeout\n");
+		return -ETIMEDOUT;
 	}
 
 	/* return value */
@@ -644,12 +646,10 @@
 			   u16 value)
 {
 	struct fec_enet_private *fep = bus->priv;
-	int timeout = FEC_MII_TIMEOUT;
+	unsigned long time_left;
 
 	fep->mii_timeout = 0;
-
-	/* clear MII end of transfer bit*/
-	writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
+	init_completion(&fep->mdio_done);
 
 	/* start a read op */
 	writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
@@ -658,13 +658,12 @@
 		fep->hwp + FEC_MII_DATA);
 
 	/* wait for end of transfer */
-	while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) {
-		cpu_relax();
-		if (timeout-- < 0) {
-			fep->mii_timeout = 1;
-			printk(KERN_ERR "FEC: MDIO write timeout\n");
-			return -ETIMEDOUT;
-		}
+	time_left = wait_for_completion_timeout(&fep->mdio_done,
+			usecs_to_jiffies(FEC_MII_TIMEOUT));
+	if (time_left == 0) {
+		fep->mii_timeout = 1;
+		printk(KERN_ERR "FEC: MDIO write timeout\n");
+		return -ETIMEDOUT;
 	}
 
 	return 0;
@@ -679,30 +678,24 @@
 {
 	struct fec_enet_private *fep = netdev_priv(dev);
 	struct phy_device *phy_dev = NULL;
-	int phy_addr;
+	int ret;
 
 	fep->phy_dev = NULL;
 
 	/* find the first phy */
-	for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
-		if (fep->mii_bus->phy_map[phy_addr]) {
-			phy_dev = fep->mii_bus->phy_map[phy_addr];
-			break;
-		}
-	}
-
+	phy_dev = phy_find_first(fep->mii_bus);
 	if (!phy_dev) {
 		printk(KERN_ERR "%s: no PHY found\n", dev->name);
 		return -ENODEV;
 	}
 
 	/* attach the mac to the phy */
-	phy_dev = phy_connect(dev, dev_name(&phy_dev->dev),
+	ret = phy_connect_direct(dev, phy_dev,
 			     &fec_enet_adjust_link, 0,
 			     PHY_INTERFACE_MODE_MII);
-	if (IS_ERR(phy_dev)) {
+	if (ret) {
 		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
-		return PTR_ERR(phy_dev);
+		return ret;
 	}
 
 	/* mask with MAC supported features */
@@ -834,7 +827,7 @@
 	if (!phydev)
 		return -ENODEV;
 
-	return phy_mii_ioctl(phydev, if_mii(rq), cmd);
+	return phy_mii_ioctl(phydev, rq, cmd);
 }
 
 static void fec_enet_free_buffers(struct net_device *dev)
@@ -1222,7 +1215,7 @@
 	writel(0, fep->hwp + FEC_R_DES_ACTIVE);
 
 	/* Enable interrupts we wish to service */
-	writel(FEC_ENET_TXF | FEC_ENET_RXF, fep->hwp + FEC_IMASK);
+	writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 }
 
 static void
@@ -1241,11 +1234,8 @@
 	/* Whack a reset.  We should wait for this. */
 	writel(1, fep->hwp + FEC_ECNTRL);
 	udelay(10);
-
-	/* Clear outstanding MII command interrupts. */
-	writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
-
 	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
+	writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 }
 
 static int __devinit
@@ -1365,10 +1355,11 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
 static int
-fec_suspend(struct platform_device *dev, pm_message_t state)
+fec_suspend(struct device *dev)
 {
-	struct net_device *ndev = platform_get_drvdata(dev);
+	struct net_device *ndev = dev_get_drvdata(dev);
 	struct fec_enet_private *fep;
 
 	if (ndev) {
@@ -1381,9 +1372,9 @@
 }
 
 static int
-fec_resume(struct platform_device *dev)
+fec_resume(struct device *dev)
 {
-	struct net_device *ndev = platform_get_drvdata(dev);
+	struct net_device *ndev = dev_get_drvdata(dev);
 	struct fec_enet_private *fep;
 
 	if (ndev) {
@@ -1395,15 +1386,26 @@
 	return 0;
 }
 
+static const struct dev_pm_ops fec_pm_ops = {
+	.suspend	= fec_suspend,
+	.resume		= fec_resume,
+	.freeze		= fec_suspend,
+	.thaw		= fec_resume,
+	.poweroff	= fec_suspend,
+	.restore	= fec_resume,
+};
+#endif
+
 static struct platform_driver fec_driver = {
 	.driver	= {
-		.name    = "fec",
-		.owner	 = THIS_MODULE,
+		.name	= "fec",
+		.owner	= THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &fec_pm_ops,
+#endif
 	},
-	.probe   = fec_probe,
-	.remove  = __devexit_p(fec_drv_remove),
-	.suspend = fec_suspend,
-	.resume  = fec_resume,
+	.probe	= fec_probe,
+	.remove	= __devexit_p(fec_drv_remove),
 };
 
 static int __init
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index 25e6cc6..d1a5b17 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -826,7 +826,7 @@
 	if (!priv->phydev)
 		return -ENOTSUPP;
 
-	return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
+	return phy_mii_ioctl(priv->phydev, rq, cmd);
 }
 
 static const struct net_device_ops mpc52xx_fec_netdev_ops = {
@@ -875,17 +875,21 @@
 	if (rv) {
 		printk(KERN_ERR DRIVER_NAME ": "
 				"Error while parsing device node resource\n" );
-		return rv;
+		goto err_netdev;
 	}
 	if ((mem.end - mem.start + 1) < sizeof(struct mpc52xx_fec)) {
 		printk(KERN_ERR DRIVER_NAME
 			" - invalid resource size (%lx < %x), check mpc52xx_devices.c\n",
 			(unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec));
-		return -EINVAL;
+		rv = -EINVAL;
+		goto err_netdev;
 	}
 
-	if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec), DRIVER_NAME))
-		return -EBUSY;
+	if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec),
+				DRIVER_NAME)) {
+		rv = -EBUSY;
+		goto err_netdev;
+	}
 
 	/* Init ether ndev with what we have */
 	ndev->netdev_ops	= &mpc52xx_fec_netdev_ops;
@@ -901,7 +905,7 @@
 
 	if (!priv->fec) {
 		rv = -ENOMEM;
-		goto probe_error;
+		goto err_mem_region;
 	}
 
 	/* Bestcomm init */
@@ -914,7 +918,7 @@
 	if (!priv->rx_dmatsk || !priv->tx_dmatsk) {
 		printk(KERN_ERR DRIVER_NAME ": Can not init SDMA tasks\n" );
 		rv = -ENOMEM;
-		goto probe_error;
+		goto err_rx_tx_dmatsk;
 	}
 
 	/* Get the IRQ we need one by one */
@@ -966,33 +970,25 @@
 
 	rv = register_netdev(ndev);
 	if (rv < 0)
-		goto probe_error;
+		goto err_node;
 
 	/* We're done ! */
 	dev_set_drvdata(&op->dev, ndev);
 
 	return 0;
 
-
-	/* Error handling - free everything that might be allocated */
-probe_error:
-
-	if (priv->phy_node)
-		of_node_put(priv->phy_node);
-	priv->phy_node = NULL;
-
+err_node:
+	of_node_put(priv->phy_node);
 	irq_dispose_mapping(ndev->irq);
-
+err_rx_tx_dmatsk:
 	if (priv->rx_dmatsk)
 		bcom_fec_rx_release(priv->rx_dmatsk);
 	if (priv->tx_dmatsk)
 		bcom_fec_tx_release(priv->tx_dmatsk);
-
-	if (priv->fec)
-		iounmap(priv->fec);
-
+	iounmap(priv->fec);
+err_mem_region:
 	release_mem_region(mem.start, sizeof(struct mpc52xx_fec));
-
+err_netdev:
 	free_netdev(ndev);
 
 	return rv;
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c
index 006f64d..dbaf72c 100644
--- a/drivers/net/fec_mpc52xx_phy.c
+++ b/drivers/net/fec_mpc52xx_phy.c
@@ -29,15 +29,14 @@
 		int reg, u32 value)
 {
 	struct mpc52xx_fec_mdio_priv *priv = bus->priv;
-	struct mpc52xx_fec __iomem *fec;
+	struct mpc52xx_fec __iomem *fec = priv->regs;
 	int tries = 3;
 
 	value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
 	value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
 
-	fec = priv->regs;
 	out_be32(&fec->ievent, FEC_IEVENT_MII);
-	out_be32(&priv->regs->mii_data, value);
+	out_be32(&fec->mii_data, value);
 
 	/* wait for it to finish, this takes about 23 us on lite5200b */
 	while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
@@ -47,7 +46,7 @@
 		return -ETIMEDOUT;
 
 	return value & FEC_MII_DATA_OP_RD ?
-		in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK : 0;
+		in_be32(&fec->mii_data) & FEC_MII_DATA_DATAMSK : 0;
 }
 
 static int mpc52xx_fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
@@ -69,9 +68,8 @@
 	struct device_node *np = of->dev.of_node;
 	struct mii_bus *bus;
 	struct mpc52xx_fec_mdio_priv *priv;
-	struct resource res = {};
+	struct resource res;
 	int err;
-	int i;
 
 	bus = mdiobus_alloc();
 	if (bus == NULL)
@@ -93,7 +91,7 @@
 	err = of_address_to_resource(np, 0, &res);
 	if (err)
 		goto out_free;
-	priv->regs = ioremap(res.start, res.end - res.start + 1);
+	priv->regs = ioremap(res.start, resource_size(&res));
 	if (priv->regs == NULL) {
 		err = -ENOMEM;
 		goto out_free;
@@ -118,10 +116,6 @@
  out_unmap:
 	iounmap(priv->regs);
  out_free:
-	for (i=0; i<PHY_MAX_ADDR; i++)
-		if (bus->irq[i] != PHY_POLL)
-			irq_dispose_mapping(bus->irq[i]);
-	kfree(bus->irq);
 	kfree(priv);
 	mdiobus_free(bus);
 
@@ -133,23 +127,16 @@
 	struct device *dev = &of->dev;
 	struct mii_bus *bus = dev_get_drvdata(dev);
 	struct mpc52xx_fec_mdio_priv *priv = bus->priv;
-	int i;
 
 	mdiobus_unregister(bus);
 	dev_set_drvdata(dev, NULL);
-
 	iounmap(priv->regs);
-	for (i=0; i<PHY_MAX_ADDR; i++)
-		if (bus->irq[i] != PHY_POLL)
-			irq_dispose_mapping(bus->irq[i]);
 	kfree(priv);
-	kfree(bus->irq);
 	mdiobus_free(bus);
 
 	return 0;
 }
 
-
 static struct of_device_id mpc52xx_fec_mdio_match[] = {
 	{ .compatible = "fsl,mpc5200b-mdio", },
 	{ .compatible = "fsl,mpc5200-mdio", },
@@ -171,5 +158,4 @@
 /* let fec driver call it, since this has to be registered before it */
 EXPORT_SYMBOL_GPL(mpc52xx_fec_mdio_driver);
 
-
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 268ea4d..4da05b1 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -89,8 +89,10 @@
 #define DEV_HAS_MSI_X              0x0000080  /* device supports MSI-X */
 #define DEV_HAS_POWER_CNTRL        0x0000100  /* device supports power savings */
 #define DEV_HAS_STATISTICS_V1      0x0000200  /* device supports hw statistics version 1 */
-#define DEV_HAS_STATISTICS_V2      0x0000600  /* device supports hw statistics version 2 */
-#define DEV_HAS_STATISTICS_V3      0x0000e00  /* device supports hw statistics version 3 */
+#define DEV_HAS_STATISTICS_V2      0x0000400  /* device supports hw statistics version 2 */
+#define DEV_HAS_STATISTICS_V3      0x0000800  /* device supports hw statistics version 3 */
+#define DEV_HAS_STATISTICS_V12     0x0000600  /* device supports hw statistics version 1 and 2 */
+#define DEV_HAS_STATISTICS_V123    0x0000e00  /* device supports hw statistics version 1, 2, and 3 */
 #define DEV_HAS_TEST_EXTENDED      0x0001000  /* device supports extended diagnostic test */
 #define DEV_HAS_MGMT_UNIT          0x0002000  /* device supports management unit */
 #define DEV_HAS_CORRECT_MACADDR    0x0004000  /* device supports correct mac address order */
@@ -2468,7 +2470,7 @@
 	struct ring_desc_ex* orig_get_tx = np->get_tx.ex;
 
 	while ((np->get_tx.ex != np->put_tx.ex) &&
-	       !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) &&
+	       !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX2_VALID) &&
 	       (tx_work < limit)) {
 
 		dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n",
@@ -6067,111 +6069,111 @@
 	},
 	{	/* MCP55 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0372),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP55 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0373),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP61 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x03E5),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP61 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x03E6),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP61 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x03EE),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP61 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x03EF),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP65 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0450),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP65 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0451),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP65 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0452),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP65 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0453),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP67 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x054C),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP67 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x054D),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP67 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x054E),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP67 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x054F),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP73 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x07DC),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP73 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x07DD),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP73 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x07DE),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP73 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x07DF),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP77 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0760),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP77 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0761),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP77 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0762),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP77 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0763),
-		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP79 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0AB0),
-		.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_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+		.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_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP79 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0AB1),
-		.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_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+		.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_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP79 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0AB2),
-		.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_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+		.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_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP79 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0AB3),
-		.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_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+		.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_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
 	},
 	{	/* MCP89 Ethernet Controller */
 		PCI_DEVICE(0x10DE, 0x0D7D),
-		.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_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX,
+		.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_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX,
 	},
 	{0,},
 };
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 309a0ea..f08cff9 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -963,12 +963,11 @@
 static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data;
 
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	return phy_mii_ioctl(fep->phydev, mii, cmd);
+	return phy_mii_ioctl(fep->phydev, rq, cmd);
 }
 
 extern int fs_mii_connect(struct net_device *dev);
diff --git a/drivers/net/fsl_pq_mdio.h b/drivers/net/fsl_pq_mdio.h
index 1f7d865..bd17a2a 100644
--- a/drivers/net/fsl_pq_mdio.h
+++ b/drivers/net/fsl_pq_mdio.h
@@ -39,7 +39,7 @@
 	u8 reserved[28];	/* Space holder */
 	u32 utbipar;		/* TBI phy address reg (only on UCC) */
 	u8 res4[2728];
-} __attribute__ ((packed));
+} __packed;
 
 int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
 int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index efd4c70..a1b6301 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -85,6 +85,7 @@
 #include <linux/net_tstamp.h>
 
 #include <asm/io.h>
+#include <asm/reg.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <linux/module.h>
@@ -685,8 +686,8 @@
 		priv->rx_queue[i] = NULL;
 
 	for (i = 0; i < priv->num_tx_queues; i++) {
-		priv->tx_queue[i] =  (struct gfar_priv_tx_q *)kzalloc(
-				sizeof (struct gfar_priv_tx_q), GFP_KERNEL);
+		priv->tx_queue[i] = kzalloc(sizeof(struct gfar_priv_tx_q),
+					    GFP_KERNEL);
 		if (!priv->tx_queue[i]) {
 			err = -ENOMEM;
 			goto tx_alloc_failed;
@@ -698,8 +699,8 @@
 	}
 
 	for (i = 0; i < priv->num_rx_queues; i++) {
-		priv->rx_queue[i] = (struct gfar_priv_rx_q *)kzalloc(
-					sizeof (struct gfar_priv_rx_q), GFP_KERNEL);
+		priv->rx_queue[i] = kzalloc(sizeof(struct gfar_priv_rx_q),
+					    GFP_KERNEL);
 		if (!priv->rx_queue[i]) {
 			err = -ENOMEM;
 			goto rx_alloc_failed;
@@ -846,7 +847,7 @@
 	if (!priv->phydev)
 		return -ENODEV;
 
-	return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
+	return phy_mii_ioctl(priv->phydev, rq, cmd);
 }
 
 static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs)
@@ -928,6 +929,34 @@
 	}
 }
 
+static void gfar_detect_errata(struct gfar_private *priv)
+{
+	struct device *dev = &priv->ofdev->dev;
+	unsigned int pvr = mfspr(SPRN_PVR);
+	unsigned int svr = mfspr(SPRN_SVR);
+	unsigned int mod = (svr >> 16) & 0xfff6; /* w/o E suffix */
+	unsigned int rev = svr & 0xffff;
+
+	/* MPC8313 Rev 2.0 and higher; All MPC837x */
+	if ((pvr == 0x80850010 && mod == 0x80b0 && rev >= 0x0020) ||
+			(pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
+		priv->errata |= GFAR_ERRATA_74;
+
+	/* MPC8313 and MPC837x all rev */
+	if ((pvr == 0x80850010 && mod == 0x80b0) ||
+			(pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
+		priv->errata |= GFAR_ERRATA_76;
+
+	/* MPC8313 and MPC837x all rev */
+	if ((pvr == 0x80850010 && mod == 0x80b0) ||
+			(pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
+		priv->errata |= GFAR_ERRATA_A002;
+
+	if (priv->errata)
+		dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
+			 priv->errata);
+}
+
 /* Set up the ethernet device structure, private data,
  * and anything else we need before we start */
 static int gfar_probe(struct of_device *ofdev,
@@ -960,6 +989,8 @@
 	dev_set_drvdata(&ofdev->dev, priv);
 	regs = priv->gfargrp[0].regs;
 
+	gfar_detect_errata(priv);
+
 	/* Stop the DMA engine now, in case it was running before */
 	/* (The firmware could have used it, and left it running). */
 	gfar_halt(dev);
@@ -974,7 +1005,10 @@
 	gfar_write(&regs->maccfg1, tempval);
 
 	/* Initialize MACCFG2. */
-	gfar_write(&regs->maccfg2, MACCFG2_INIT_SETTINGS);
+	tempval = MACCFG2_INIT_SETTINGS;
+	if (gfar_has_errata(priv, GFAR_ERRATA_74))
+		tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK;
+	gfar_write(&regs->maccfg2, tempval);
 
 	/* Initialize ECNTRL */
 	gfar_write(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
@@ -1541,6 +1575,29 @@
 	gfar_write(&regs->minflr, MINFLR_INIT_SETTINGS);
 }
 
+static int __gfar_is_rx_idle(struct gfar_private *priv)
+{
+	u32 res;
+
+	/*
+	 * Normaly TSEC should not hang on GRS commands, so we should
+	 * actually wait for IEVENT_GRSC flag.
+	 */
+	if (likely(!gfar_has_errata(priv, GFAR_ERRATA_A002)))
+		return 0;
+
+	/*
+	 * Read the eTSEC register at offset 0xD1C. If bits 7-14 are
+	 * the same as bits 23-30, the eTSEC Rx is assumed to be idle
+	 * and the Rx can be safely reset.
+	 */
+	res = gfar_read((void __iomem *)priv->gfargrp[0].regs + 0xd1c);
+	res &= 0x7f807f80;
+	if ((res & 0xffff) == (res >> 16))
+		return 1;
+
+	return 0;
+}
 
 /* Halt the receive and transmit queues */
 static void gfar_halt_nodisable(struct net_device *dev)
@@ -1564,12 +1621,18 @@
 	tempval = gfar_read(&regs->dmactrl);
 	if ((tempval & (DMACTRL_GRS | DMACTRL_GTS))
 	    != (DMACTRL_GRS | DMACTRL_GTS)) {
+		int ret;
+
 		tempval |= (DMACTRL_GRS | DMACTRL_GTS);
 		gfar_write(&regs->dmactrl, tempval);
 
-		spin_event_timeout(((gfar_read(&regs->ievent) &
-			 (IEVENT_GRSC | IEVENT_GTSC)) ==
-			 (IEVENT_GRSC | IEVENT_GTSC)), -1, 0);
+		do {
+			ret = spin_event_timeout(((gfar_read(&regs->ievent) &
+				 (IEVENT_GRSC | IEVENT_GTSC)) ==
+				 (IEVENT_GRSC | IEVENT_GTSC)), 1000000, 0);
+			if (!ret && !(gfar_read(&regs->ievent) & IEVENT_GRSC))
+				ret = __gfar_is_rx_idle(priv);
+		} while (!ret);
 	}
 }
 
@@ -1987,6 +2050,20 @@
 	unsigned int nr_frags, nr_txbds, length;
 	union skb_shared_tx *shtx;
 
+	/*
+	 * TOE=1 frames larger than 2500 bytes may see excess delays
+	 * before start of transmission.
+	 */
+	if (unlikely(gfar_has_errata(priv, GFAR_ERRATA_76) &&
+			skb->ip_summed == CHECKSUM_PARTIAL &&
+			skb->len > 2500)) {
+		int ret;
+
+		ret = skb_checksum_help(skb);
+		if (ret)
+			return ret;
+	}
+
 	rq = skb->queue_mapping;
 	tx_queue = priv->tx_queue[rq];
 	txq = netdev_get_tx_queue(dev, rq);
@@ -2300,7 +2377,8 @@
 	 * to allow huge frames, and to check the length */
 	tempval = gfar_read(&regs->maccfg2);
 
-	if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE)
+	if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE ||
+			gfar_has_errata(priv, GFAR_ERRATA_74))
 		tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
 	else
 		tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
@@ -2342,6 +2420,15 @@
 	schedule_work(&priv->reset_task);
 }
 
+static void gfar_align_skb(struct sk_buff *skb)
+{
+	/* We need the data buffer to be aligned properly.  We will reserve
+	 * as many bytes as needed to align the data properly
+	 */
+	skb_reserve(skb, RXBUF_ALIGNMENT -
+		(((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1)));
+}
+
 /* Interrupt Handler for Transmit complete */
 static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 {
@@ -2426,9 +2513,10 @@
 		 */
 		if (skb_queue_len(&priv->rx_recycle) < rx_queue->rx_ring_size &&
 				skb_recycle_check(skb, priv->rx_buffer_size +
-					RXBUF_ALIGNMENT))
+					RXBUF_ALIGNMENT)) {
+			gfar_align_skb(skb);
 			__skb_queue_head(&priv->rx_recycle, skb);
-		else
+		} else
 			dev_kfree_skb_any(skb);
 
 		tx_queue->tx_skbuff[skb_dirtytx] = NULL;
@@ -2491,29 +2579,28 @@
 	gfar_init_rxbdp(rx_queue, bdp, buf);
 }
 
+static struct sk_buff * gfar_alloc_skb(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	struct sk_buff *skb = NULL;
+
+	skb = netdev_alloc_skb(dev, priv->rx_buffer_size + RXBUF_ALIGNMENT);
+	if (!skb)
+		return NULL;
+
+	gfar_align_skb(skb);
+
+	return skb;
+}
 
 struct sk_buff * gfar_new_skb(struct net_device *dev)
 {
-	unsigned int alignamount;
 	struct gfar_private *priv = netdev_priv(dev);
 	struct sk_buff *skb = NULL;
 
 	skb = __skb_dequeue(&priv->rx_recycle);
 	if (!skb)
-		skb = netdev_alloc_skb(dev,
-				priv->rx_buffer_size + RXBUF_ALIGNMENT);
-
-	if (!skb)
-		return NULL;
-
-	alignamount = RXBUF_ALIGNMENT -
-		(((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1));
-
-	/* We need the data buffer to be aligned properly.  We will reserve
-	 * as many bytes as needed to align the data properly
-	 */
-	skb_reserve(skb, alignamount);
-	GFAR_CB(skb)->alignamount = alignamount;
+		skb = gfar_alloc_skb(dev);
 
 	return skb;
 }
@@ -2666,17 +2753,8 @@
 
 			if (unlikely(!newskb))
 				newskb = skb;
-			else if (skb) {
-				/*
-				 * We need to un-reserve() the skb to what it
-				 * was before gfar_new_skb() re-aligned
-				 * it to an RXBUF_ALIGNMENT boundary
-				 * before we put the skb back on the
-				 * recycle list.
-				 */
-				skb_reserve(skb, -GFAR_CB(skb)->alignamount);
+			else if (skb)
 				__skb_queue_head(&priv->rx_recycle, skb);
-			}
 		} else {
 			/* Increment the number of packets */
 			rx_queue->stats.rx_packets++;
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index ac4a92e..710810e 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -1025,6 +1025,12 @@
 	char int_name_er[GFAR_INT_NAME_MAX];
 };
 
+enum gfar_errata {
+	GFAR_ERRATA_74		= 0x01,
+	GFAR_ERRATA_76		= 0x02,
+	GFAR_ERRATA_A002	= 0x04,
+};
+
 /* 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
@@ -1049,6 +1055,7 @@
 	struct device_node *node;
 	struct net_device *ndev;
 	struct of_device *ofdev;
+	enum gfar_errata errata;
 
 	struct gfar_priv_grp gfargrp[MAXGROUPS];
 	struct gfar_priv_tx_q *tx_queue[MAX_TX_QS];
@@ -1111,6 +1118,12 @@
 extern unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
 extern unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
 
+static inline int gfar_has_errata(struct gfar_private *priv,
+				  enum gfar_errata err)
+{
+	return priv->errata & err;
+}
+
 static inline u32 gfar_read(volatile unsigned __iomem *addr)
 {
 	u32 val;
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
index 3a029d0..4d09eab 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/greth.c
@@ -1555,7 +1555,6 @@
 	}
 
 	/* setup NAPI */
-	memset(&greth->napi, 0, sizeof(greth->napi));
 	netif_napi_add(dev, &greth->napi, greth_poll, 64);
 
 	return 0;
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 61f2b1c..49aac70 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -492,7 +492,6 @@
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
 	dma_addr_t tx_ring_dma;
 	dma_addr_t rx_ring_dma;
-	struct net_device_stats stats;
 	struct timer_list timer;		/* Media selection timer. */
 	/* Frequently used and paired value: keep adjacent for cache effect. */
 	spinlock_t lock;
@@ -1036,7 +1035,7 @@
 		if (entry >= TX_RING_SIZE-1)
 			hmp->tx_ring[TX_RING_SIZE-1].status_n_length |=
 				cpu_to_le32(DescEndRing);
-		hmp->stats.tx_packets++;
+		dev->stats.tx_packets++;
 	}
 
 	return 0;
@@ -1167,7 +1166,7 @@
 
 	/* Trigger an immediate transmit demand. */
 	dev->trans_start = jiffies; /* prevent tx timeout */
-	hmp->stats.tx_errors++;
+	dev->stats.tx_errors++;
 
 	/* Restart the chip's Tx/Rx processes . */
 	writew(0x0002, ioaddr + TxCmd); /* STOP Tx */
@@ -1434,7 +1433,7 @@
 					if (entry >= TX_RING_SIZE-1)
 						hmp->tx_ring[TX_RING_SIZE-1].status_n_length |=
 							cpu_to_le32(DescEndRing);
-					hmp->stats.tx_packets++;
+					dev->stats.tx_packets++;
 				}
 				if (hmp->cur_tx - hmp->dirty_tx < TX_RING_SIZE - 4){
 					/* The ring is no longer full */
@@ -1525,18 +1524,22 @@
 				   le32_to_cpu(hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length) & 0xffff0000,
 				   le32_to_cpu(hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length) & 0x0000ffff,
 				   le32_to_cpu(hmp->rx_ring[(hmp->cur_rx-1) % RX_RING_SIZE].status_n_length));
-			hmp->stats.rx_length_errors++;
+			dev->stats.rx_length_errors++;
 		} /* else  Omit for prototype errata??? */
 		if (frame_status & 0x00380000) {
 			/* There was an error. */
 			if (hamachi_debug > 2)
 				printk(KERN_DEBUG "  hamachi_rx() Rx error was %8.8x.\n",
 					   frame_status);
-			hmp->stats.rx_errors++;
-			if (frame_status & 0x00600000) hmp->stats.rx_length_errors++;
-			if (frame_status & 0x00080000) hmp->stats.rx_frame_errors++;
-			if (frame_status & 0x00100000) hmp->stats.rx_crc_errors++;
-			if (frame_status < 0) hmp->stats.rx_dropped++;
+			dev->stats.rx_errors++;
+			if (frame_status & 0x00600000)
+				dev->stats.rx_length_errors++;
+			if (frame_status & 0x00080000)
+				dev->stats.rx_frame_errors++;
+			if (frame_status & 0x00100000)
+				dev->stats.rx_crc_errors++;
+			if (frame_status < 0)
+				dev->stats.rx_dropped++;
 		} else {
 			struct sk_buff *skb;
 			/* Omit CRC */
@@ -1654,7 +1657,7 @@
 #endif  /* RX_CHECKSUM */
 
 			netif_rx(skb);
-			hmp->stats.rx_packets++;
+			dev->stats.rx_packets++;
 		}
 		entry = (++hmp->cur_rx) % RX_RING_SIZE;
 	}
@@ -1724,9 +1727,9 @@
 		       dev->name, intr_status);
 	/* Hmmmmm, it's not clear how to recover from PCI faults. */
 	if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))
-		hmp->stats.tx_fifo_errors++;
+		dev->stats.tx_fifo_errors++;
 	if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))
-		hmp->stats.rx_fifo_errors++;
+		dev->stats.rx_fifo_errors++;
 }
 
 static int hamachi_close(struct net_device *dev)
@@ -1828,19 +1831,27 @@
            so I think I'll comment it out here and see if better things
            happen.
         */
-	/* hmp->stats.tx_packets	= readl(ioaddr + 0x000); */
+	/* dev->stats.tx_packets	= readl(ioaddr + 0x000); */
 
-	hmp->stats.rx_bytes = readl(ioaddr + 0x330); /* Total Uni+Brd+Multi */
-	hmp->stats.tx_bytes = readl(ioaddr + 0x3B0); /* Total Uni+Brd+Multi */
-	hmp->stats.multicast		= readl(ioaddr + 0x320); /* Multicast Rx */
+	/* Total Uni+Brd+Multi */
+	dev->stats.rx_bytes = readl(ioaddr + 0x330);
+	/* Total Uni+Brd+Multi */
+	dev->stats.tx_bytes = readl(ioaddr + 0x3B0);
+	/* Multicast Rx */
+	dev->stats.multicast = readl(ioaddr + 0x320);
 
-	hmp->stats.rx_length_errors	= readl(ioaddr + 0x368); /* Over+Undersized */
-	hmp->stats.rx_over_errors	= readl(ioaddr + 0x35C); /* Jabber */
-	hmp->stats.rx_crc_errors	= readl(ioaddr + 0x360); /* Jabber */
-	hmp->stats.rx_frame_errors	= readl(ioaddr + 0x364); /* Symbol Errs */
-	hmp->stats.rx_missed_errors	= readl(ioaddr + 0x36C); /* Dropped */
+	/* Over+Undersized */
+	dev->stats.rx_length_errors = readl(ioaddr + 0x368);
+	/* Jabber */
+	dev->stats.rx_over_errors = readl(ioaddr + 0x35C);
+	/* Jabber */
+	dev->stats.rx_crc_errors = readl(ioaddr + 0x360);
+	/* Symbol Errs */
+	dev->stats.rx_frame_errors = readl(ioaddr + 0x364);
+	/* Dropped */
+	dev->stats.rx_missed_errors = readl(ioaddr + 0x36C);
 
-	return &hmp->stats;
+	return &dev->stats;
 }
 
 static void set_rx_mode(struct net_device *dev)
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index dfc787f..095b17e 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -168,7 +168,6 @@
 	u_char mac1_mode;
 	u_char mac2_mode;
 	u_char hash_bytes[8];
-	struct net_device_stats stats;
 
 	/* Rings for busmaster mode: */
 	hp100_ring_t *rxrhead;	/* Head (oldest) index into rxring */
@@ -721,9 +720,10 @@
 		/* Conversion to new PCI API :
 		 * Pages are always aligned and zeroed, no need to it ourself.
 		 * Doc says should be OK for EISA bus as well - Jean II */
-		if ((lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr)) == NULL) {
+		lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr);
+		if (!lp->page_vaddr_algn) {
 			err = -ENOMEM;
-			goto out2;
+			goto out_mem_ptr;
 		}
 		lp->whatever_offset = ((u_long) page_baddr) - ((u_long) lp->page_vaddr_algn);
 
@@ -799,6 +799,7 @@
 		pci_free_consistent(lp->pci_dev, MAX_RINGSIZE + 0x0f,
 				    lp->page_vaddr_algn,
 				    virt_to_whatever(dev, lp->page_vaddr_algn));
+out_mem_ptr:
 	if (mem_ptr_virt)
 		iounmap(mem_ptr_virt);
 out2:
@@ -1582,8 +1583,8 @@
 	spin_unlock_irqrestore(&lp->lock, flags);
 
 	/* Update statistics */
-	lp->stats.tx_packets++;
-	lp->stats.tx_bytes += skb->len;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
 
 	return NETDEV_TX_OK;
 
@@ -1740,8 +1741,8 @@
 
 	hp100_outb(HP100_TX_CMD | HP100_SET_LB, OPTION_MSW);	/* send packet */
 
-	lp->stats.tx_packets++;
-	lp->stats.tx_bytes += skb->len;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
 	hp100_ints_on();
 	spin_unlock_irqrestore(&lp->lock, flags);
 
@@ -1822,7 +1823,7 @@
 			printk("hp100: %s: rx: couldn't allocate a sk_buff of size %d\n",
 					     dev->name, pkt_len);
 #endif
-			lp->stats.rx_dropped++;
+			dev->stats.rx_dropped++;
 		} else {	/* skb successfully allocated */
 
 			u_char *ptr;
@@ -1848,8 +1849,8 @@
 					ptr[9], ptr[10], ptr[11]);
 #endif
 			netif_rx(skb);
-			lp->stats.rx_packets++;
-			lp->stats.rx_bytes += pkt_len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += pkt_len;
 		}
 
 		/* Indicate the card that we have got the packet */
@@ -1858,7 +1859,7 @@
 		switch (header & 0x00070000) {
 		case (HP100_MULTI_ADDR_HASH << 16):
 		case (HP100_MULTI_ADDR_NO_HASH << 16):
-			lp->stats.multicast++;
+			dev->stats.multicast++;
 			break;
 		}
 	}			/* end of while(there are packets) loop */
@@ -1930,7 +1931,7 @@
 			if (ptr->skb == NULL) {
 				printk("hp100: %s: rx_bm: skb null\n", dev->name);
 				/* can happen if we only allocated room for the pdh due to memory shortage. */
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 			} else {
 				skb_trim(ptr->skb, pkt_len);	/* Shorten it */
 				ptr->skb->protocol =
@@ -1938,14 +1939,14 @@
 
 				netif_rx(ptr->skb);	/* Up and away... */
 
-				lp->stats.rx_packets++;
-				lp->stats.rx_bytes += pkt_len;
+				dev->stats.rx_packets++;
+				dev->stats.rx_bytes += pkt_len;
 			}
 
 			switch (header & 0x00070000) {
 			case (HP100_MULTI_ADDR_HASH << 16):
 			case (HP100_MULTI_ADDR_NO_HASH << 16):
-				lp->stats.multicast++;
+				dev->stats.multicast++;
 				break;
 			}
 		} else {
@@ -1954,7 +1955,7 @@
 #endif
 			if (ptr->skb != NULL)
 				dev_kfree_skb_any(ptr->skb);
-			lp->stats.rx_errors++;
+			dev->stats.rx_errors++;
 		}
 
 		lp->rxrhead = lp->rxrhead->next;
@@ -1992,14 +1993,13 @@
 	hp100_update_stats(dev);
 	hp100_ints_on();
 	spin_unlock_irqrestore(&lp->lock, flags);
-	return &(lp->stats);
+	return &(dev->stats);
 }
 
 static void hp100_update_stats(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
 	u_short val;
-	struct hp100_private *lp = netdev_priv(dev);
 
 #ifdef HP100_DEBUG_B
 	hp100_outw(0x4216, TRACE);
@@ -2009,14 +2009,14 @@
 	/* Note: Statistics counters clear when read. */
 	hp100_page(MAC_CTRL);
 	val = hp100_inw(DROPPED) & 0x0fff;
-	lp->stats.rx_errors += val;
-	lp->stats.rx_over_errors += val;
+	dev->stats.rx_errors += val;
+	dev->stats.rx_over_errors += val;
 	val = hp100_inb(CRC);
-	lp->stats.rx_errors += val;
-	lp->stats.rx_crc_errors += val;
+	dev->stats.rx_errors += val;
+	dev->stats.rx_crc_errors += val;
 	val = hp100_inb(ABORT);
-	lp->stats.tx_errors += val;
-	lp->stats.tx_aborted_errors += val;
+	dev->stats.tx_errors += val;
+	dev->stats.tx_aborted_errors += val;
 	hp100_page(PERFORMANCE);
 }
 
@@ -2025,7 +2025,6 @@
 #ifdef HP100_DEBUG_B
 	int ioaddr = dev->base_addr;
 #endif
-	struct hp100_private *lp = netdev_priv(dev);
 
 #ifdef HP100_DEBUG_B
 	int ioaddr = dev->base_addr;
@@ -2034,8 +2033,8 @@
 #endif
 
 	/* Note: Statistics counters clear when read. */
-	lp->stats.rx_errors++;
-	lp->stats.tx_errors++;
+	dev->stats.rx_errors++;
+	dev->stats.tx_errors++;
 }
 
 static void hp100_clear_stats(struct hp100_private *lp, int ioaddr)
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index 86438b5..187622f 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -63,6 +63,7 @@
 static s32  igb_reset_init_script_82575(struct e1000_hw *);
 static s32  igb_read_mac_addr_82575(struct e1000_hw *);
 static s32  igb_set_pcie_completion_timeout(struct e1000_hw *hw);
+static s32  igb_reset_mdicnfg_82580(struct e1000_hw *hw);
 
 static const u16 e1000_82580_rxpbs_table[] =
 	{ 36, 72, 144, 1, 2, 4, 8, 16,
@@ -70,6 +71,35 @@
 #define E1000_82580_RXPBS_TABLE_SIZE \
 	(sizeof(e1000_82580_rxpbs_table)/sizeof(u16))
 
+/**
+ *  igb_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO
+ *  @hw: pointer to the HW structure
+ *
+ *  Called to determine if the I2C pins are being used for I2C or as an
+ *  external MDIO interface since the two options are mutually exclusive.
+ **/
+static bool igb_sgmii_uses_mdio_82575(struct e1000_hw *hw)
+{
+	u32 reg = 0;
+	bool ext_mdio = false;
+
+	switch (hw->mac.type) {
+	case e1000_82575:
+	case e1000_82576:
+		reg = rd32(E1000_MDIC);
+		ext_mdio = !!(reg & E1000_MDIC_DEST);
+		break;
+	case e1000_82580:
+	case e1000_i350:
+		reg = rd32(E1000_MDICNFG);
+		ext_mdio = !!(reg & E1000_MDICNFG_EXT_MDIO);
+		break;
+	default:
+		break;
+	}
+	return ext_mdio;
+}
+
 static s32 igb_get_invariants_82575(struct e1000_hw *hw)
 {
 	struct e1000_phy_info *phy = &hw->phy;
@@ -130,27 +160,15 @@
 	switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
 	case E1000_CTRL_EXT_LINK_MODE_SGMII:
 		dev_spec->sgmii_active = true;
-		ctrl_ext |= E1000_CTRL_I2C_ENA;
 		break;
 	case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
 	case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
 		hw->phy.media_type = e1000_media_type_internal_serdes;
-		ctrl_ext |= E1000_CTRL_I2C_ENA;
 		break;
 	default:
-		ctrl_ext &= ~E1000_CTRL_I2C_ENA;
 		break;
 	}
 
-	wr32(E1000_CTRL_EXT, ctrl_ext);
-
-	/*
-	 * if using i2c make certain the MDICNFG register is cleared to prevent
-	 * communications from being misrouted to the mdic registers
-	 */
-	if ((ctrl_ext & E1000_CTRL_I2C_ENA) && (hw->mac.type == e1000_82580))
-		wr32(E1000_MDICNFG, 0);
-
 	/* Set mta register count */
 	mac->mta_reg_count = 128;
 	/* Set rar entry count */
@@ -228,19 +246,29 @@
 	phy->autoneg_mask        = AUTONEG_ADVERTISE_SPEED_DEFAULT;
 	phy->reset_delay_us      = 100;
 
+	ctrl_ext = rd32(E1000_CTRL_EXT);
+
 	/* PHY function pointers */
 	if (igb_sgmii_active_82575(hw)) {
-		phy->ops.reset              = igb_phy_hw_reset_sgmii_82575;
-		phy->ops.read_reg           = igb_read_phy_reg_sgmii_82575;
-		phy->ops.write_reg          = igb_write_phy_reg_sgmii_82575;
-	} else if (hw->mac.type >= e1000_82580) {
-		phy->ops.reset              = igb_phy_hw_reset;
-		phy->ops.read_reg           = igb_read_phy_reg_82580;
-		phy->ops.write_reg          = igb_write_phy_reg_82580;
+		phy->ops.reset      = igb_phy_hw_reset_sgmii_82575;
+		ctrl_ext |= E1000_CTRL_I2C_ENA;
 	} else {
-		phy->ops.reset              = igb_phy_hw_reset;
-		phy->ops.read_reg           = igb_read_phy_reg_igp;
-		phy->ops.write_reg          = igb_write_phy_reg_igp;
+		phy->ops.reset      = igb_phy_hw_reset;
+		ctrl_ext &= ~E1000_CTRL_I2C_ENA;
+	}
+
+	wr32(E1000_CTRL_EXT, ctrl_ext);
+	igb_reset_mdicnfg_82580(hw);
+
+	if (igb_sgmii_active_82575(hw) && !igb_sgmii_uses_mdio_82575(hw)) {
+		phy->ops.read_reg   = igb_read_phy_reg_sgmii_82575;
+		phy->ops.write_reg  = igb_write_phy_reg_sgmii_82575;
+	} else if (hw->mac.type >= e1000_82580) {
+		phy->ops.read_reg   = igb_read_phy_reg_82580;
+		phy->ops.write_reg  = igb_write_phy_reg_82580;
+	} else {
+		phy->ops.read_reg   = igb_read_phy_reg_igp;
+		phy->ops.write_reg  = igb_write_phy_reg_igp;
 	}
 
 	/* set lan id */
@@ -295,6 +323,10 @@
 
 	if (hw->bus.func == E1000_FUNC_1)
 		mask = E1000_SWFW_PHY1_SM;
+	else if (hw->bus.func == E1000_FUNC_2)
+		mask = E1000_SWFW_PHY2_SM;
+	else if (hw->bus.func == E1000_FUNC_3)
+		mask = E1000_SWFW_PHY3_SM;
 
 	return igb_acquire_swfw_sync_82575(hw, mask);
 }
@@ -312,6 +344,10 @@
 
 	if (hw->bus.func == E1000_FUNC_1)
 		mask = E1000_SWFW_PHY1_SM;
+	else if (hw->bus.func == E1000_FUNC_2)
+		mask = E1000_SWFW_PHY2_SM;
+	else if (hw->bus.func == E1000_FUNC_3)
+		mask = E1000_SWFW_PHY3_SM;
 
 	igb_release_swfw_sync_82575(hw, mask);
 }
@@ -392,6 +428,7 @@
 	s32  ret_val = 0;
 	u16 phy_id;
 	u32 ctrl_ext;
+	u32 mdic;
 
 	/*
 	 * For SGMII PHYs, we try the list of possible addresses until
@@ -406,6 +443,29 @@
 		goto out;
 	}
 
+	if (igb_sgmii_uses_mdio_82575(hw)) {
+		switch (hw->mac.type) {
+		case e1000_82575:
+		case e1000_82576:
+			mdic = rd32(E1000_MDIC);
+			mdic &= E1000_MDIC_PHY_MASK;
+			phy->addr = mdic >> E1000_MDIC_PHY_SHIFT;
+			break;
+		case e1000_82580:
+		case e1000_i350:
+			mdic = rd32(E1000_MDICNFG);
+			mdic &= E1000_MDICNFG_PHY_MASK;
+			phy->addr = mdic >> E1000_MDICNFG_PHY_SHIFT;
+			break;
+		default:
+			ret_val = -E1000_ERR_PHY;
+			goto out;
+			break;
+		}
+		ret_val = igb_get_phy_id(hw);
+		goto out;
+	}
+
 	/* Power on sgmii phy if it is disabled */
 	ctrl_ext = rd32(E1000_CTRL_EXT);
 	wr32(E1000_CTRL_EXT, ctrl_ext & ~E1000_CTRL_EXT_SDP3_DATA);
@@ -1493,6 +1553,43 @@
 }
 
 /**
+ *  igb_reset_mdicnfg_82580 - Reset MDICNFG destination and com_mdio bits
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the the MDICNFG.Destination and MDICNFG.Com_MDIO bits based on
+ *  the values found in the EEPROM.  This addresses an issue in which these
+ *  bits are not restored from EEPROM after reset.
+ **/
+static s32 igb_reset_mdicnfg_82580(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+	u32 mdicnfg;
+	u16 nvm_data;
+
+	if (hw->mac.type != e1000_82580)
+		goto out;
+	if (!igb_sgmii_active_82575(hw))
+		goto out;
+
+	ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A +
+				   NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1,
+				   &nvm_data);
+	if (ret_val) {
+		hw_dbg("NVM Read Error\n");
+		goto out;
+	}
+
+	mdicnfg = rd32(E1000_MDICNFG);
+	if (nvm_data & NVM_WORD24_EXT_MDIO)
+		mdicnfg |= E1000_MDICNFG_EXT_MDIO;
+	if (nvm_data & NVM_WORD24_COM_MDIO)
+		mdicnfg |= E1000_MDICNFG_COM_MDIO;
+	wr32(E1000_MDICNFG, mdicnfg);
+out:
+	return ret_val;
+}
+
+/**
  *  igb_reset_hw_82580 - Reset hardware
  *  @hw: pointer to the HW structure
  *
@@ -1567,6 +1664,10 @@
 	wr32(E1000_IMC, 0xffffffff);
 	icr = rd32(E1000_ICR);
 
+	ret_val = igb_reset_mdicnfg_82580(hw);
+	if (ret_val)
+		hw_dbg("Could not reset MDICNFG based on EEPROM\n");
+
 	/* Install any alternate MAC address into RAR0 */
 	ret_val = igb_check_alt_mac_addr(hw);
 
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
index 24d9be6..bbd2ec3 100644
--- a/drivers/net/igb/e1000_defines.h
+++ b/drivers/net/igb/e1000_defines.h
@@ -164,6 +164,8 @@
 #define E1000_SWFW_EEP_SM   0x1
 #define E1000_SWFW_PHY0_SM  0x2
 #define E1000_SWFW_PHY1_SM  0x4
+#define E1000_SWFW_PHY2_SM  0x20
+#define E1000_SWFW_PHY3_SM  0x40
 
 /* FACTPS Definitions */
 /* Device Control */
@@ -466,6 +468,11 @@
 
 #define E1000_TIMINCA_16NS_SHIFT 24
 
+#define E1000_MDICNFG_EXT_MDIO    0x80000000      /* MDI ext/int destination */
+#define E1000_MDICNFG_COM_MDIO    0x40000000      /* MDI shared w/ lan 0 */
+#define E1000_MDICNFG_PHY_MASK    0x03E00000
+#define E1000_MDICNFG_PHY_SHIFT   21
+
 /* PCI Express Control */
 #define E1000_GCR_CMPL_TMOUT_MASK       0x0000F000
 #define E1000_GCR_CMPL_TMOUT_10ms       0x00001000
@@ -563,6 +570,10 @@
 
 #define NVM_82580_LAN_FUNC_OFFSET(a) (a ? (0x40 + (0x40 * a)) : 0)
 
+/* Mask bits for fields in Word 0x24 of the NVM */
+#define NVM_WORD24_COM_MDIO         0x0008 /* MDIO interface shared */
+#define NVM_WORD24_EXT_MDIO         0x0004 /* MDIO accesses routed external */
+
 /* Mask bits for fields in Word 0x0f of the NVM */
 #define NVM_WORD0F_PAUSE_MASK       0x3000
 #define NVM_WORD0F_ASM_DIR          0x2000
@@ -696,12 +707,17 @@
 #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
 
 /* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
 #define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
 #define E1000_MDIC_PHY_SHIFT 21
 #define E1000_MDIC_OP_WRITE  0x04000000
 #define E1000_MDIC_OP_READ   0x08000000
 #define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
 #define E1000_MDIC_ERROR     0x40000000
+#define E1000_MDIC_DEST      0x80000000
 
 /* SerDes Control */
 #define E1000_GEN_CTL_READY             0x80000000
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index f2ebf927..26bf6a1 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -1823,12 +1823,10 @@
 		dev_info(&adapter->pdev->dev, "online testing starting\n");
 
 		/* PHY is powered down when interface is down */
-		if (!netif_carrier_ok(netdev)) {
+		if (if_running && igb_link_test(adapter, &data[4]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+		else
 			data[4] = 0;
-		} else {
-			if (igb_link_test(adapter, &data[4]))
-				eth_test->flags |= ETH_TEST_FL_FAILED;
-		}
 
 		/* Online tests aren't run; pass by default */
 		data[0] = 0;
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index cea37e0..df5dcd2 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -630,9 +630,6 @@
 			for (; i < adapter->rss_queues; i++)
 				adapter->rx_ring[i]->reg_idx = rbase_offset +
 				                               Q_IDX_82576(i);
-			for (; j < adapter->rss_queues; j++)
-				adapter->tx_ring[j]->reg_idx = rbase_offset +
-				                               Q_IDX_82576(j);
 		}
 	case e1000_82575:
 	case e1000_82580:
@@ -996,7 +993,10 @@
 
 	/* Number of supported queues. */
 	adapter->num_rx_queues = adapter->rss_queues;
-	adapter->num_tx_queues = adapter->rss_queues;
+	if (adapter->vfs_allocated_count)
+		adapter->num_tx_queues = 1;
+	else
+		adapter->num_tx_queues = adapter->rss_queues;
 
 	/* start with one vector for every rx queue */
 	numvecs = adapter->num_rx_queues;
@@ -1290,7 +1290,13 @@
 	wr32(E1000_IAM, 0);
 	wr32(E1000_IMC, ~0);
 	wrfl();
-	synchronize_irq(adapter->pdev->irq);
+	if (adapter->msix_entries) {
+		int i;
+		for (i = 0; i < adapter->num_q_vectors; i++)
+			synchronize_irq(adapter->msix_entries[i].vector);
+	} else {
+		synchronize_irq(adapter->pdev->irq);
+	}
 }
 
 /**
@@ -2100,9 +2106,6 @@
 #ifdef CONFIG_PCI_IOV
 	struct pci_dev *pdev = adapter->pdev;
 
-	if (adapter->vfs_allocated_count > 7)
-		adapter->vfs_allocated_count = 7;
-
 	if (adapter->vfs_allocated_count) {
 		adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
 		                           sizeof(struct vf_data_storage),
@@ -2267,7 +2270,7 @@
 
 #ifdef CONFIG_PCI_IOV
 	if (hw->mac.type == e1000_82576)
-		adapter->vfs_allocated_count = max_vfs;
+		adapter->vfs_allocated_count = (max_vfs > 7) ? 7 : max_vfs;
 
 #endif /* CONFIG_PCI_IOV */
 	adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus());
@@ -2729,14 +2732,16 @@
 	}
 	igb_vmm_control(adapter);
 
-	mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 |
-		 E1000_MRQC_RSS_FIELD_IPV4_TCP);
-	mrqc |= (E1000_MRQC_RSS_FIELD_IPV6 |
-		 E1000_MRQC_RSS_FIELD_IPV6_TCP);
-	mrqc |= (E1000_MRQC_RSS_FIELD_IPV4_UDP |
-		 E1000_MRQC_RSS_FIELD_IPV6_UDP);
-	mrqc |= (E1000_MRQC_RSS_FIELD_IPV6_UDP_EX |
-		 E1000_MRQC_RSS_FIELD_IPV6_TCP_EX);
+	/*
+	 * Generate RSS hash based on TCP port numbers and/or
+	 * IPv4/v6 src and dst addresses since UDP cannot be
+	 * hashed reliably due to IP fragmentation
+	 */
+	mrqc |= E1000_MRQC_RSS_FIELD_IPV4 |
+		E1000_MRQC_RSS_FIELD_IPV4_TCP |
+		E1000_MRQC_RSS_FIELD_IPV6 |
+		E1000_MRQC_RSS_FIELD_IPV6_TCP |
+		E1000_MRQC_RSS_FIELD_IPV6_TCP_EX;
 
 	wr32(E1000_MRQC, mrqc);
 }
@@ -4986,6 +4991,10 @@
 
 static int igb_set_vf_mac_addr(struct igb_adapter *adapter, u32 *msg, int vf)
 {
+	/*
+	 * The VF MAC Address is stored in a packed array of bytes
+	 * starting at the second 32 bit word of the msg array
+	 */
 	unsigned char *addr = (char *)&msg[1];
 	int err = -1;
 
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
index 5e2b2a8..ec808fa 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/igbvf/netdev.c
@@ -48,7 +48,7 @@
 #define DRV_VERSION "1.0.0-k0"
 char igbvf_driver_name[] = "igbvf";
 const char igbvf_driver_version[] = DRV_VERSION;
-struct pm_qos_request_list *igbvf_driver_pm_qos_req;
+static struct pm_qos_request_list igbvf_driver_pm_qos_req;
 static const char igbvf_driver_string[] =
 				"Intel(R) Virtual Function Network Driver";
 static const char igbvf_copyright[] = "Copyright (c) 2009 Intel Corporation.";
@@ -2751,7 +2751,7 @@
 		dev_info(&pdev->dev,
 			 "PF still in reset state, assigning new address."
 			 " Is the PF interface up?\n");
-		random_ether_addr(hw->mac.addr);
+		dev_hw_addr_random(adapter->netdev, hw->mac.addr);
 	} else {
 		err = hw->mac.ops.read_mac_addr(hw);
 		if (err) {
@@ -2902,8 +2902,8 @@
 	printk(KERN_INFO "%s\n", igbvf_copyright);
 
 	ret = pci_register_driver(&igbvf_driver);
-	igbvf_driver_pm_qos_req = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,
-	                       PM_QOS_DEFAULT_VALUE);
+	pm_qos_add_request(&igbvf_driver_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+			   PM_QOS_DEFAULT_VALUE);
 
 	return ret;
 }
@@ -2918,8 +2918,7 @@
 static void __exit igbvf_exit_module(void)
 {
 	pci_unregister_driver(&igbvf_driver);
-	pm_qos_remove_request(igbvf_driver_pm_qos_req);
-	igbvf_driver_pm_qos_req = NULL;
+	pm_qos_remove_request(&igbvf_driver_pm_qos_req);
 }
 module_exit(igbvf_exit_module);
 
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index e3b5e94..0b3f6df 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -82,7 +82,6 @@
 	struct ioc3_etxd *txr;
 	struct sk_buff *rx_skbs[512];
 	struct sk_buff *tx_skbs[128];
-	struct net_device_stats stats;
 	int rx_ci;			/* RX consumer index */
 	int rx_pi;			/* RX producer index */
 	int tx_ci;			/* TX consumer index */
@@ -504,8 +503,8 @@
 	struct ioc3_private *ip = netdev_priv(dev);
 	struct ioc3 *ioc3 = ip->regs;
 
-	ip->stats.collisions += (ioc3_r_etcdc() & ETCDC_COLLCNT_MASK);
-	return &ip->stats;
+	dev->stats.collisions += (ioc3_r_etcdc() & ETCDC_COLLCNT_MASK);
+	return &dev->stats;
 }
 
 static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len)
@@ -576,8 +575,9 @@
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 }
 
-static inline void ioc3_rx(struct ioc3_private *ip)
+static inline void ioc3_rx(struct net_device *dev)
 {
+	struct ioc3_private *ip = netdev_priv(dev);
 	struct sk_buff *skb, *new_skb;
 	struct ioc3 *ioc3 = ip->regs;
 	int rx_entry, n_entry, len;
@@ -598,13 +598,13 @@
 		if (err & ERXBUF_GOODPKT) {
 			len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4;
 			skb_trim(skb, len);
-			skb->protocol = eth_type_trans(skb, priv_netdev(ip));
+			skb->protocol = eth_type_trans(skb, dev);
 
 			new_skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
 			if (!new_skb) {
 				/* Ouch, drop packet and just recycle packet
 				   to keep the ring filled.  */
-				ip->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				new_skb = skb;
 				goto next;
 			}
@@ -622,19 +622,19 @@
 			rxb = (struct ioc3_erxbuf *) new_skb->data;
 			skb_reserve(new_skb, RX_OFFSET);
 
-			ip->stats.rx_packets++;		/* Statistics */
-			ip->stats.rx_bytes += len;
+			dev->stats.rx_packets++;		/* Statistics */
+			dev->stats.rx_bytes += len;
 		} else {
- 			/* The frame is invalid and the skb never
-                           reached the network layer so we can just
-                           recycle it.  */
- 			new_skb = skb;
- 			ip->stats.rx_errors++;
+			/* The frame is invalid and the skb never
+			   reached the network layer so we can just
+			   recycle it.  */
+			new_skb = skb;
+			dev->stats.rx_errors++;
 		}
 		if (err & ERXBUF_CRCERR)	/* Statistics */
-			ip->stats.rx_crc_errors++;
+			dev->stats.rx_crc_errors++;
 		if (err & ERXBUF_FRAMERR)
-			ip->stats.rx_frame_errors++;
+			dev->stats.rx_frame_errors++;
 next:
 		ip->rx_skbs[n_entry] = new_skb;
 		rxr[n_entry] = cpu_to_be64(ioc3_map(rxb, 1));
@@ -652,8 +652,9 @@
 	ip->rx_ci = rx_entry;
 }
 
-static inline void ioc3_tx(struct ioc3_private *ip)
+static inline void ioc3_tx(struct net_device *dev)
 {
+	struct ioc3_private *ip = netdev_priv(dev);
 	unsigned long packets, bytes;
 	struct ioc3 *ioc3 = ip->regs;
 	int tx_entry, o_entry;
@@ -681,12 +682,12 @@
 		tx_entry = (etcir >> 7) & 127;
 	}
 
-	ip->stats.tx_packets += packets;
-	ip->stats.tx_bytes += bytes;
+	dev->stats.tx_packets += packets;
+	dev->stats.tx_bytes += bytes;
 	ip->txqlen -= packets;
 
 	if (ip->txqlen < 128)
-		netif_wake_queue(priv_netdev(ip));
+		netif_wake_queue(dev);
 
 	ip->tx_ci = o_entry;
 	spin_unlock(&ip->ioc3_lock);
@@ -699,9 +700,9 @@
  * with such error interrupts if something really goes wrong, so we might
  * also consider to take the interface down.
  */
-static void ioc3_error(struct ioc3_private *ip, u32 eisr)
+static void ioc3_error(struct net_device *dev, u32 eisr)
 {
-	struct net_device *dev = priv_netdev(ip);
+	struct ioc3_private *ip = netdev_priv(dev);
 	unsigned char *iface = dev->name;
 
 	spin_lock(&ip->ioc3_lock);
@@ -747,11 +748,11 @@
 
 	if (eisr & (EISR_RXOFLO | EISR_RXBUFOFLO | EISR_RXMEMERR |
 	            EISR_RXPARERR | EISR_TXBUFUFLO | EISR_TXMEMERR))
-		ioc3_error(ip, eisr);
+		ioc3_error(dev, eisr);
 	if (eisr & EISR_RXTIMERINT)
-		ioc3_rx(ip);
+		ioc3_rx(dev);
 	if (eisr & EISR_TXEXPLICIT)
-		ioc3_tx(ip);
+		ioc3_tx(dev);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h
index 0dbd193..36c3060 100644
--- a/drivers/net/irda/donauboe.h
+++ b/drivers/net/irda/donauboe.h
@@ -273,7 +273,7 @@
   __u8 control;                 /*Slot control/status see below */
   __u32 address;                /*Slot buffer address */
 }
-__attribute__ ((packed));
+__packed;
 
 #define OBOE_NTASKS OBOE_TXRING_OFFSET_IN_SLOTS
 
diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h
index ac0443d..58ddb52 100644
--- a/drivers/net/irda/irda-usb.h
+++ b/drivers/net/irda/irda-usb.h
@@ -125,7 +125,7 @@
 	__u8  bmAdditionalBOFs;
 	__u8  bIrdaRateSniff;
 	__u8  bMaxUnicastList;
-} __attribute__ ((packed));
+} __packed;
 
 /* class specific interface request to get the IrDA-USB class descriptor
  * (6.2.5, USB-IrDA class spec 1.0) */
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
index b54d3b4..1046014 100644
--- a/drivers/net/irda/ks959-sir.c
+++ b/drivers/net/irda/ks959-sir.c
@@ -154,7 +154,7 @@
 	__le32 baudrate;	/* baud rate, little endian */
 	__u8 flags;
 	__u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
 
 #define KS_DATA_5_BITS 0x00
 #define KS_DATA_6_BITS 0x01
diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c
index 8d713eb..9cc142f 100644
--- a/drivers/net/irda/ksdazzle-sir.c
+++ b/drivers/net/irda/ksdazzle-sir.c
@@ -117,7 +117,7 @@
 	__le32 baudrate;	/* baud rate, little endian */
 	__u8 flags;
 	__u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
 
 #define KS_DATA_5_BITS 0x00
 #define KS_DATA_6_BITS 0x01
diff --git a/drivers/net/irda/sh_irda.c b/drivers/net/irda/sh_irda.c
index 9a828b0..edd5666 100644
--- a/drivers/net/irda/sh_irda.c
+++ b/drivers/net/irda/sh_irda.c
@@ -749,7 +749,7 @@
 	struct sh_irda_self *self;
 	struct resource *res;
 	char clk_name[8];
-	unsigned int irq;
+	int irq;
 	int err = -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c
index 5c5f99d..00b38bc 100644
--- a/drivers/net/irda/sh_sir.c
+++ b/drivers/net/irda/sh_sir.c
@@ -709,7 +709,7 @@
 	struct sh_sir_self *self;
 	struct resource *res;
 	char clk_name[8];
-	unsigned int irq;
+	int irq;
 	int err = -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index d67e484..850ca1c 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -2848,9 +2848,7 @@
 	unsigned short ss_device = 0x0000;
 	int ret = 0;
 
-	dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
-
-	while (dev != NULL) {
+	for_each_pci_dev(dev) {
 		struct smsc_ircc_subsystem_configuration *conf;
 
 		/*
@@ -2899,7 +2897,6 @@
 					ret = -ENODEV;
 			}
 		}
-		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
 	}
 
 	return ret;
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
index 3050d1a..3f24a1f3 100644
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -544,9 +544,9 @@
 		struct {
 			u8		addr_res[3];
 			volatile u8	status;		/* descriptor status */
-		} __attribute__((packed)) rd_s;
-	} __attribute((packed)) rd_u;
-} __attribute__ ((packed));
+		} __packed rd_s;
+	} __packed rd_u;
+} __packed;
 
 #define rd_addr		rd_u.addr
 #define rd_status	rd_u.rd_s.status
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index ffae480..9e15eb9 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -44,11 +44,9 @@
 #include <linux/dca.h>
 #endif
 
-#define PFX "ixgbe: "
-#define DPRINTK(nlevel, klevel, fmt, args...) \
-	((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \
-	printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \
-		__func__ , ## args)))
+/* common prefix used by pr_<> macros */
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 /* TX/RX descriptor defines */
 #define IXGBE_DEFAULT_TXD		    512
@@ -112,7 +110,6 @@
 	u16 vlans_enabled;
 	bool clear_to_send;
 	bool pf_set_mac;
-	int rar;
 	u16 pf_vlan; /* When set, guest VLAN config not allowed. */
 	u16 pf_qos;
 };
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
index a4e2901..3e06a61 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ixgbe/ixgbe_82599.c
@@ -206,6 +206,14 @@
 	s32 status = 0;
 	u32 autoc = 0;
 
+	/* Determine 1G link capabilities off of SFP+ type */
+	if (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
+	    hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1) {
+		*speed = IXGBE_LINK_SPEED_1GB_FULL;
+		*negotiation = true;
+		goto out;
+	}
+
 	/*
 	 * Determine link capabilities based on the stored value of AUTOC,
 	 * which represents EEPROM defaults.  If AUTOC value has not been
@@ -707,9 +715,8 @@
 
 out:
 	if (link_up && (link_speed == IXGBE_LINK_SPEED_1GB_FULL))
-		netif_info(adapter, hw, adapter->netdev, "Smartspeed has"
-			" downgraded the link speed from the maximum"
-			" advertised\n");
+		e_info(hw, "Smartspeed has downgraded the link speed from "
+		       "the maximum advertised\n");
 	return status;
 }
 
@@ -2088,6 +2095,7 @@
 	u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK;
 	u16 ext_ability = 0;
 	u8 comp_codes_10g = 0;
+	u8 comp_codes_1g = 0;
 
 	hw->phy.ops.identify(hw);
 
@@ -2168,11 +2176,15 @@
 	case ixgbe_phy_sfp_intel:
 	case ixgbe_phy_sfp_unknown:
 		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);
 		if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
 			physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR;
 		else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
 			physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR;
+		else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE)
+			physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_T;
 		break;
 	default:
 		break;
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
index 3080afb..5cf15aa 100644
--- a/drivers/net/ixgbe/ixgbe_common.h
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -105,12 +105,23 @@
 
 #define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS)
 
-#ifdef DEBUG
-extern char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw);
+extern struct net_device *ixgbe_get_hw_dev(struct ixgbe_hw *hw);
 #define hw_dbg(hw, format, arg...) \
-	printk(KERN_DEBUG "%s: " format, ixgbe_get_hw_dev_name(hw), ##arg)
-#else
-#define hw_dbg(hw, format, arg...) do {} while (0)
-#endif
-
+	netdev_dbg(ixgbe_get_hw_dev(hw), format, ##arg)
+#define e_dev_info(format, arg...) \
+	dev_info(&adapter->pdev->dev, format, ## arg)
+#define e_dev_warn(format, arg...) \
+	dev_warn(&adapter->pdev->dev, format, ## arg)
+#define e_dev_err(format, arg...) \
+	dev_err(&adapter->pdev->dev, format, ## arg)
+#define e_dev_notice(format, arg...) \
+	dev_notice(&adapter->pdev->dev, format, ## arg)
+#define e_info(msglvl, format, arg...) \
+	netif_info(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_err(msglvl, format, arg...) \
+	netif_err(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_warn(msglvl, format, arg...) \
+	netif_warn(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_crit(msglvl, format, arg...) \
+	netif_crit(adapter, msglvl, adapter->netdev, format, ## arg)
 #endif /* IXGBE_COMMON */
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c
index 4f7a26a..25b02fb 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82599.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c
@@ -346,7 +346,7 @@
 	 */
 	reg = IXGBE_READ_REG(hw, IXGBE_MFLCN);
 	reg &= ~IXGBE_MFLCN_RFCE;
-	reg |= IXGBE_MFLCN_RPFCE;
+	reg |= IXGBE_MFLCN_RPFCE | IXGBE_MFLCN_DPF;
 	IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg);
 out:
 	return 0;
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index 71da325..b53b465 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -121,7 +121,7 @@
 			goto out;
 
 		if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
-			DPRINTK(DRV, ERR, "Enable failed, needs MSI-X\n");
+			e_err(drv, "Enable failed, needs MSI-X\n");
 			err = 1;
 			goto out;
 		}
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 3a93a81..dcebc82 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -54,14 +54,14 @@
 				sizeof(((struct ixgbe_adapter *)0)->m), \
 				offsetof(struct ixgbe_adapter, m)
 #define IXGBE_NETDEV_STAT(m)	NETDEV_STATS, \
-				sizeof(((struct net_device *)0)->m), \
-				offsetof(struct net_device, m)
+				sizeof(((struct rtnl_link_stats64 *)0)->m), \
+				offsetof(struct rtnl_link_stats64, m)
 
 static struct ixgbe_stats ixgbe_gstrings_stats[] = {
-	{"rx_packets", IXGBE_NETDEV_STAT(stats.rx_packets)},
-	{"tx_packets", IXGBE_NETDEV_STAT(stats.tx_packets)},
-	{"rx_bytes", IXGBE_NETDEV_STAT(stats.rx_bytes)},
-	{"tx_bytes", IXGBE_NETDEV_STAT(stats.tx_bytes)},
+	{"rx_packets", IXGBE_NETDEV_STAT(rx_packets)},
+	{"tx_packets", IXGBE_NETDEV_STAT(tx_packets)},
+	{"rx_bytes", IXGBE_NETDEV_STAT(rx_bytes)},
+	{"tx_bytes", IXGBE_NETDEV_STAT(tx_bytes)},
 	{"rx_pkts_nic", IXGBE_STAT(stats.gprc)},
 	{"tx_pkts_nic", IXGBE_STAT(stats.gptc)},
 	{"rx_bytes_nic", IXGBE_STAT(stats.gorc)},
@@ -69,27 +69,27 @@
 	{"lsc_int", IXGBE_STAT(lsc_int)},
 	{"tx_busy", IXGBE_STAT(tx_busy)},
 	{"non_eop_descs", IXGBE_STAT(non_eop_descs)},
-	{"rx_errors", IXGBE_NETDEV_STAT(stats.rx_errors)},
-	{"tx_errors", IXGBE_NETDEV_STAT(stats.tx_errors)},
-	{"rx_dropped", IXGBE_NETDEV_STAT(stats.rx_dropped)},
-	{"tx_dropped", IXGBE_NETDEV_STAT(stats.tx_dropped)},
-	{"multicast", IXGBE_NETDEV_STAT(stats.multicast)},
+	{"rx_errors", IXGBE_NETDEV_STAT(rx_errors)},
+	{"tx_errors", IXGBE_NETDEV_STAT(tx_errors)},
+	{"rx_dropped", IXGBE_NETDEV_STAT(rx_dropped)},
+	{"tx_dropped", IXGBE_NETDEV_STAT(tx_dropped)},
+	{"multicast", IXGBE_NETDEV_STAT(multicast)},
 	{"broadcast", IXGBE_STAT(stats.bprc)},
 	{"rx_no_buffer_count", IXGBE_STAT(stats.rnbc[0]) },
-	{"collisions", IXGBE_NETDEV_STAT(stats.collisions)},
-	{"rx_over_errors", IXGBE_NETDEV_STAT(stats.rx_over_errors)},
-	{"rx_crc_errors", IXGBE_NETDEV_STAT(stats.rx_crc_errors)},
-	{"rx_frame_errors", IXGBE_NETDEV_STAT(stats.rx_frame_errors)},
+	{"collisions", IXGBE_NETDEV_STAT(collisions)},
+	{"rx_over_errors", IXGBE_NETDEV_STAT(rx_over_errors)},
+	{"rx_crc_errors", IXGBE_NETDEV_STAT(rx_crc_errors)},
+	{"rx_frame_errors", IXGBE_NETDEV_STAT(rx_frame_errors)},
 	{"hw_rsc_aggregated", IXGBE_STAT(rsc_total_count)},
 	{"hw_rsc_flushed", IXGBE_STAT(rsc_total_flush)},
 	{"fdir_match", IXGBE_STAT(stats.fdirmatch)},
 	{"fdir_miss", IXGBE_STAT(stats.fdirmiss)},
-	{"rx_fifo_errors", IXGBE_NETDEV_STAT(stats.rx_fifo_errors)},
-	{"rx_missed_errors", IXGBE_NETDEV_STAT(stats.rx_missed_errors)},
-	{"tx_aborted_errors", IXGBE_NETDEV_STAT(stats.tx_aborted_errors)},
-	{"tx_carrier_errors", IXGBE_NETDEV_STAT(stats.tx_carrier_errors)},
-	{"tx_fifo_errors", IXGBE_NETDEV_STAT(stats.tx_fifo_errors)},
-	{"tx_heartbeat_errors", IXGBE_NETDEV_STAT(stats.tx_heartbeat_errors)},
+	{"rx_fifo_errors", IXGBE_NETDEV_STAT(rx_fifo_errors)},
+	{"rx_missed_errors", IXGBE_NETDEV_STAT(rx_missed_errors)},
+	{"tx_aborted_errors", IXGBE_NETDEV_STAT(tx_aborted_errors)},
+	{"tx_carrier_errors", IXGBE_NETDEV_STAT(tx_carrier_errors)},
+	{"tx_fifo_errors", IXGBE_NETDEV_STAT(tx_fifo_errors)},
+	{"tx_heartbeat_errors", IXGBE_NETDEV_STAT(tx_heartbeat_errors)},
 	{"tx_timeout_count", IXGBE_STAT(tx_timeout_count)},
 	{"tx_restart_queue", IXGBE_STAT(restart_queue)},
 	{"rx_long_length_errors", IXGBE_STAT(stats.roc)},
@@ -234,6 +234,13 @@
 		case ixgbe_sfp_type_not_present:
 			ecmd->port = PORT_NONE;
 			break;
+		case ixgbe_sfp_type_1g_cu_core0:
+		case ixgbe_sfp_type_1g_cu_core1:
+			ecmd->port = PORT_TP;
+			ecmd->supported = SUPPORTED_TP;
+			ecmd->advertising = (ADVERTISED_1000baseT_Full |
+			                     ADVERTISED_TP);
+			break;
 		case ixgbe_sfp_type_unknown:
 		default:
 			ecmd->port = PORT_OTHER;
@@ -294,8 +301,7 @@
 		hw->mac.autotry_restart = true;
 		err = hw->mac.ops.setup_link(hw, advertised, true, true);
 		if (err) {
-			DPRINTK(PROBE, INFO,
-			        "setup link failed with code %d\n", err);
+			e_info(probe, "setup link failed with code %d\n", err);
 			hw->mac.ops.setup_link(hw, old, true, true);
 		}
 	} else {
@@ -992,16 +998,18 @@
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	u64 *queue_stat;
 	int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64);
+	struct rtnl_link_stats64 temp;
+	const struct rtnl_link_stats64 *net_stats;
 	int j, k;
 	int i;
 	char *p = NULL;
 
 	ixgbe_update_stats(adapter);
-	dev_get_stats(netdev);
+	net_stats = dev_get_stats(netdev, &temp);
 	for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
 		switch (ixgbe_gstrings_stats[i].type) {
 		case NETDEV_STATS:
-			p = (char *) netdev +
+			p = (char *) net_stats +
 					ixgbe_gstrings_stats[i].stat_offset;
 			break;
 		case IXGBE_STATS:
@@ -1188,9 +1196,9 @@
 		writel((_test[pat] & W), (adapter->hw.hw_addr + R));          \
 		val = readl(adapter->hw.hw_addr + R);                         \
 		if (val != (_test[pat] & W & M)) {                            \
-			DPRINTK(DRV, ERR, "pattern test reg %04X failed: got "\
-					  "0x%08X expected 0x%08X\n",         \
-				R, val, (_test[pat] & W & M));                \
+			e_err(drv, "pattern test reg %04X failed: got "   \
+			      "0x%08X expected 0x%08X\n",		      \
+			      R, val, (_test[pat] & W & M));                \
 			*data = R;                                            \
 			writel(before, adapter->hw.hw_addr + R);              \
 			return 1;                                             \
@@ -1206,8 +1214,8 @@
 	writel((W & M), (adapter->hw.hw_addr + R));                           \
 	val = readl(adapter->hw.hw_addr + R);                                 \
 	if ((W & M) != (val & M)) {                                           \
-		DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\
-				 "expected 0x%08X\n", R, (val & M), (W & M)); \
+		e_err(drv, "set/check reg %04X test failed: got 0x%08X "  \
+		      "expected 0x%08X\n", R, (val & M), (W & M));        \
 		*data = R;                                                    \
 		writel(before, (adapter->hw.hw_addr + R));                    \
 		return 1;                                                     \
@@ -1240,8 +1248,8 @@
 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, toggle);
 	after = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle;
 	if (value != after) {
-		DPRINTK(DRV, ERR, "failed STATUS register test got: "
-		        "0x%08X expected: 0x%08X\n", after, value);
+		e_err(drv, "failed STATUS register test got: 0x%08X "
+		      "expected: 0x%08X\n", after, value);
 		*data = 1;
 		return 1;
 	}
@@ -1341,8 +1349,8 @@
 		*data = 1;
 		return -1;
 	}
-	DPRINTK(HW, INFO, "testing %s interrupt\n",
-		(shared_int ? "shared" : "unshared"));
+	e_info(hw, "testing %s interrupt\n", shared_int ?
+	       "shared" : "unshared");
 
 	/* Disable all the interrupts */
 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF);
@@ -1847,7 +1855,7 @@
 	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
 		/* Offline tests */
 
-		DPRINTK(HW, INFO, "offline testing starting\n");
+		e_info(hw, "offline testing starting\n");
 
 		/* Link test performed before hardware reset so autoneg doesn't
 		 * interfere with test result */
@@ -1880,17 +1888,17 @@
 		else
 			ixgbe_reset(adapter);
 
-		DPRINTK(HW, INFO, "register testing starting\n");
+		e_info(hw, "register testing starting\n");
 		if (ixgbe_reg_test(adapter, &data[0]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
 		ixgbe_reset(adapter);
-		DPRINTK(HW, INFO, "eeprom testing starting\n");
+		e_info(hw, "eeprom testing starting\n");
 		if (ixgbe_eeprom_test(adapter, &data[1]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
 		ixgbe_reset(adapter);
-		DPRINTK(HW, INFO, "interrupt testing starting\n");
+		e_info(hw, "interrupt testing starting\n");
 		if (ixgbe_intr_test(adapter, &data[2]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
@@ -1898,14 +1906,14 @@
 		 * loopback diagnostic. */
 		if (adapter->flags & (IXGBE_FLAG_SRIOV_ENABLED |
 				      IXGBE_FLAG_VMDQ_ENABLED)) {
-			DPRINTK(HW, INFO, "Skip MAC loopback diagnostic in VT "
-				"mode\n");
+			e_info(hw, "Skip MAC loopback diagnostic in VT "
+			       "mode\n");
 			data[3] = 0;
 			goto skip_loopback;
 		}
 
 		ixgbe_reset(adapter);
-		DPRINTK(HW, INFO, "loopback testing starting\n");
+		e_info(hw, "loopback testing starting\n");
 		if (ixgbe_loopback_test(adapter, &data[3]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
@@ -1916,7 +1924,7 @@
 		if (if_running)
 			dev_open(netdev);
 	} else {
-		DPRINTK(HW, INFO, "online testing starting\n");
+		e_info(hw, "online testing starting\n");
 		/* Online tests */
 		if (ixgbe_link_test(adapter, &data[4]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -2134,8 +2142,8 @@
 			adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED;
 			if (netdev->features & NETIF_F_LRO) {
 				netdev->features &= ~NETIF_F_LRO;
-				DPRINTK(PROBE, INFO, "rx-usecs set to 0, "
-					"disabling LRO/RSC\n");
+				e_info(probe, "rx-usecs set to 0, "
+				       "disabling RSC\n");
 			}
 			need_reset = true;
 		}
@@ -2208,8 +2216,11 @@
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	bool need_reset = false;
+	int rc;
 
-	ethtool_op_set_flags(netdev, data);
+	rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_LRO | ETH_FLAG_NTUPLE);
+	if (rc)
+		return rc;
 
 	/* if state changes we need to update adapter->flags and reset */
 	if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) {
@@ -2230,10 +2241,10 @@
 				break;
 			}
 		} else if (!adapter->rx_itr_setting) {
-			netdev->features &= ~ETH_FLAG_LRO;
+			netdev->features &= ~NETIF_F_LRO;
 			if (data & ETH_FLAG_LRO)
-				DPRINTK(PROBE, INFO, "rx-usecs set to 0, "
-					"LRO/RSC cannot be enabled.\n");
+				e_info(probe, "rx-usecs set to 0, "
+				       "LRO/RSC cannot be enabled.\n");
 		}
 	}
 
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c
index 45182ab..072327c 100644
--- a/drivers/net/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ixgbe/ixgbe_fcoe.c
@@ -25,7 +25,6 @@
 
 *******************************************************************************/
 
-
 #include "ixgbe.h"
 #ifdef CONFIG_IXGBE_DCB
 #include "ixgbe_dcb_82599.h"
@@ -165,20 +164,20 @@
 
 	adapter = netdev_priv(netdev);
 	if (xid >= IXGBE_FCOE_DDP_MAX) {
-		DPRINTK(DRV, WARNING, "xid=0x%x out-of-range\n", xid);
+		e_warn(drv, "xid=0x%x out-of-range\n", xid);
 		return 0;
 	}
 
 	fcoe = &adapter->fcoe;
 	if (!fcoe->pool) {
-		DPRINTK(DRV, WARNING, "xid=0x%x no ddp pool for fcoe\n", xid);
+		e_warn(drv, "xid=0x%x no ddp pool for fcoe\n", xid);
 		return 0;
 	}
 
 	ddp = &fcoe->ddp[xid];
 	if (ddp->sgl) {
-		DPRINTK(DRV, ERR, "xid 0x%x w/ non-null sgl=%p nents=%d\n",
-			xid, ddp->sgl, ddp->sgc);
+		e_err(drv, "xid 0x%x w/ non-null sgl=%p nents=%d\n",
+		      xid, ddp->sgl, ddp->sgc);
 		return 0;
 	}
 	ixgbe_fcoe_clear_ddp(ddp);
@@ -186,14 +185,14 @@
 	/* setup dma from scsi command sgl */
 	dmacount = pci_map_sg(adapter->pdev, sgl, sgc, DMA_FROM_DEVICE);
 	if (dmacount == 0) {
-		DPRINTK(DRV, ERR, "xid 0x%x DMA map error\n", xid);
+		e_err(drv, "xid 0x%x DMA map error\n", xid);
 		return 0;
 	}
 
 	/* alloc the udl from our ddp pool */
-	ddp->udl = pci_pool_alloc(fcoe->pool, GFP_KERNEL, &ddp->udp);
+	ddp->udl = pci_pool_alloc(fcoe->pool, GFP_ATOMIC, &ddp->udp);
 	if (!ddp->udl) {
-		DPRINTK(DRV, ERR, "failed allocated ddp context\n");
+		e_err(drv, "failed allocated ddp context\n");
 		goto out_noddp_unmap;
 	}
 	ddp->sgl = sgl;
@@ -206,10 +205,9 @@
 		while (len) {
 			/* max number of buffers allowed in one DDP context */
 			if (j >= IXGBE_BUFFCNT_MAX) {
-				netif_err(adapter, drv, adapter->netdev,
-					  "xid=%x:%d,%d,%d:addr=%llx "
-					  "not enough descriptors\n",
-					  xid, i, j, dmacount, (u64)addr);
+				e_err(drv, "xid=%x:%d,%d,%d:addr=%llx "
+				      "not enough descriptors\n",
+				      xid, i, j, dmacount, (u64)addr);
 				goto out_noddp_free;
 			}
 
@@ -387,8 +385,8 @@
 	struct fc_frame_header *fh;
 
 	if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_type != SKB_GSO_FCOE)) {
-		DPRINTK(DRV, ERR, "Wrong gso type %d:expecting SKB_GSO_FCOE\n",
-			skb_shinfo(skb)->gso_type);
+		e_err(drv, "Wrong gso type %d:expecting SKB_GSO_FCOE\n",
+		      skb_shinfo(skb)->gso_type);
 		return -EINVAL;
 	}
 
@@ -414,7 +412,7 @@
 		fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_SOF;
 		break;
 	default:
-		DPRINTK(DRV, WARNING, "unknown sof = 0x%x\n", sof);
+		e_warn(drv, "unknown sof = 0x%x\n", sof);
 		return -EINVAL;
 	}
 
@@ -441,7 +439,7 @@
 		fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_A;
 		break;
 	default:
-		DPRINTK(DRV, WARNING, "unknown eof = 0x%x\n", eof);
+		e_warn(drv, "unknown eof = 0x%x\n", eof);
 		return -EINVAL;
 	}
 
@@ -517,8 +515,7 @@
 					     adapter->pdev, IXGBE_FCPTR_MAX,
 					     IXGBE_FCPTR_ALIGN, PAGE_SIZE);
 		if (!fcoe->pool)
-			DPRINTK(DRV, ERR,
-				"failed to allocated FCoE DDP pool\n");
+			e_err(drv, "failed to allocated FCoE DDP pool\n");
 
 		spin_lock_init(&fcoe->lock);
 	}
@@ -614,7 +611,7 @@
 	if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
 		goto out_enable;
 
-	DPRINTK(DRV, INFO, "Enabling FCoE offload features.\n");
+	e_info(drv, "Enabling FCoE offload features.\n");
 	if (netif_running(netdev))
 		netdev->netdev_ops->ndo_stop(netdev);
 
@@ -625,9 +622,6 @@
 	netdev->features |= NETIF_F_FCOE_CRC;
 	netdev->features |= NETIF_F_FSO;
 	netdev->features |= NETIF_F_FCOE_MTU;
-	netdev->vlan_features |= NETIF_F_FCOE_CRC;
-	netdev->vlan_features |= NETIF_F_FSO;
-	netdev->vlan_features |= NETIF_F_FCOE_MTU;
 	netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1;
 
 	ixgbe_init_interrupt_scheme(adapter);
@@ -660,25 +654,21 @@
 	if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))
 		goto out_disable;
 
-	DPRINTK(DRV, INFO, "Disabling FCoE offload features.\n");
+	e_info(drv, "Disabling FCoE offload features.\n");
+	netdev->features &= ~NETIF_F_FCOE_CRC;
+	netdev->features &= ~NETIF_F_FSO;
+	netdev->features &= ~NETIF_F_FCOE_MTU;
+	netdev->fcoe_ddp_xid = 0;
+	netdev_features_change(netdev);
+
 	if (netif_running(netdev))
 		netdev->netdev_ops->ndo_stop(netdev);
 
 	ixgbe_clear_interrupt_scheme(adapter);
-
 	adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
 	adapter->ring_feature[RING_F_FCOE].indices = 0;
-	netdev->features &= ~NETIF_F_FCOE_CRC;
-	netdev->features &= ~NETIF_F_FSO;
-	netdev->features &= ~NETIF_F_FCOE_MTU;
-	netdev->vlan_features &= ~NETIF_F_FCOE_CRC;
-	netdev->vlan_features &= ~NETIF_F_FSO;
-	netdev->vlan_features &= ~NETIF_F_FCOE_MTU;
-	netdev->fcoe_ddp_xid = 0;
-
 	ixgbe_cleanup_fcoe(adapter);
 	ixgbe_init_interrupt_scheme(adapter);
-	netdev_features_change(netdev);
 
 	if (netif_running(netdev))
 		netdev->netdev_ops->ndo_open(netdev);
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 74d9b6d..7d6a415 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -52,7 +52,7 @@
 static const char ixgbe_driver_string[] =
                               "Intel(R) 10 Gigabit PCI Express Network Driver";
 
-#define DRV_VERSION "2.0.62-k2"
+#define DRV_VERSION "2.0.84-k2"
 const char ixgbe_driver_version[] = DRV_VERSION;
 static char ixgbe_copyright[] = "Copyright (c) 1999-2010 Intel Corporation.";
 
@@ -696,19 +696,19 @@
 		/* detected Tx unit hang */
 		union ixgbe_adv_tx_desc *tx_desc;
 		tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
-		DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
-			"  Tx Queue             <%d>\n"
-			"  TDH, TDT             <%x>, <%x>\n"
-			"  next_to_use          <%x>\n"
-			"  next_to_clean        <%x>\n"
-			"tx_buffer_info[next_to_clean]\n"
-			"  time_stamp           <%lx>\n"
-			"  jiffies              <%lx>\n",
-			tx_ring->queue_index,
-			IXGBE_READ_REG(hw, tx_ring->head),
-			IXGBE_READ_REG(hw, tx_ring->tail),
-			tx_ring->next_to_use, eop,
-			tx_ring->tx_buffer_info[eop].time_stamp, jiffies);
+		e_err(drv, "Detected Tx Unit Hang\n"
+		      "  Tx Queue             <%d>\n"
+		      "  TDH, TDT             <%x>, <%x>\n"
+		      "  next_to_use          <%x>\n"
+		      "  next_to_clean        <%x>\n"
+		      "tx_buffer_info[next_to_clean]\n"
+		      "  time_stamp           <%lx>\n"
+		      "  jiffies              <%lx>\n",
+		      tx_ring->queue_index,
+		      IXGBE_READ_REG(hw, tx_ring->head),
+		      IXGBE_READ_REG(hw, tx_ring->tail),
+		      tx_ring->next_to_use, eop,
+		      tx_ring->tx_buffer_info[eop].time_stamp, jiffies);
 		return true;
 	}
 
@@ -812,9 +812,8 @@
 	if (adapter->detect_tx_hung) {
 		if (ixgbe_check_tx_hang(adapter, tx_ring, i)) {
 			/* schedule immediate reset if we believe we hung */
-			DPRINTK(PROBE, INFO,
-			        "tx hang %d detected, resetting adapter\n",
-			        adapter->tx_timeout_count + 1);
+			e_info(probe, "tx hang %d detected, resetting "
+			       "adapter\n", adapter->tx_timeout_count + 1);
 			ixgbe_tx_timeout(adapter->netdev);
 		}
 	}
@@ -1653,10 +1652,10 @@
 				return;
 			break;
 		}
-		DPRINTK(DRV, ERR, "Network adapter has been stopped because it "
-		        "has over heated. Restart the computer. If the problem "
-		        "persists, power off the system and replace the "
-		        "adapter\n");
+		e_crit(drv, "Network adapter has been stopped because it has "
+		       "over heated. Restart the computer. If the problem "
+		       "persists, power off the system and replace the "
+		       "adapter\n");
 		/* write to clear the interrupt */
 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0);
 	}
@@ -1668,7 +1667,7 @@
 
 	if ((adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) &&
 	    (eicr & IXGBE_EICR_GPI_SDP1)) {
-		DPRINTK(PROBE, CRIT, "Fan has stopped, replace the adapter\n");
+		e_crit(probe, "Fan has stopped, replace the adapter\n");
 		/* write to clear the interrupt */
 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
 	}
@@ -2154,9 +2153,8 @@
 		                  handler, 0, adapter->name[vector],
 		                  adapter->q_vector[vector]);
 		if (err) {
-			DPRINTK(PROBE, ERR,
-			        "request_irq failed for MSIX interrupt "
-			        "Error: %d\n", err);
+			e_err(probe, "request_irq failed for MSIX interrupt "
+			      "Error: %d\n", err);
 			goto free_queue_irqs;
 		}
 	}
@@ -2165,8 +2163,7 @@
 	err = request_irq(adapter->msix_entries[vector].vector,
 	                  ixgbe_msix_lsc, 0, adapter->name[vector], netdev);
 	if (err) {
-		DPRINTK(PROBE, ERR,
-			"request_irq for msix_lsc failed: %d\n", err);
+		e_err(probe, "request_irq for msix_lsc failed: %d\n", err);
 		goto free_queue_irqs;
 	}
 
@@ -2352,7 +2349,7 @@
 	}
 
 	if (err)
-		DPRINTK(PROBE, ERR, "request_irq failed, Error %d\n", err);
+		e_err(probe, "request_irq failed, Error %d\n", err);
 
 	return err;
 }
@@ -2423,7 +2420,7 @@
 	map_vector_to_rxq(adapter, 0, 0);
 	map_vector_to_txq(adapter, 0, 0);
 
-	DPRINTK(HW, INFO, "Legacy interrupt IVAR setup done\n");
+	e_info(hw, "Legacy interrupt IVAR setup done\n");
 }
 
 /**
@@ -2803,10 +2800,8 @@
 		    /* Perform hash on these packet types */
 		mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4
 		      | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
-		      | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
 		      | IXGBE_MRQC_RSS_FIELD_IPV6
-		      | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
-		      | IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
+		      | IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
 	}
 	IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
 
@@ -2995,6 +2990,48 @@
 }
 
 /**
+ * ixgbe_write_uc_addr_list - write unicast addresses to RAR table
+ * @netdev: network interface device structure
+ *
+ * Writes unicast address list to the RAR table.
+ * Returns: -ENOMEM on failure/insufficient address space
+ *                0 on no addresses written
+ *                X on writing X addresses to the RAR table
+ **/
+static int ixgbe_write_uc_addr_list(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_hw *hw = &adapter->hw;
+	unsigned int vfn = adapter->num_vfs;
+	unsigned int rar_entries = hw->mac.num_rar_entries - (vfn + 1);
+	int count = 0;
+
+	/* return ENOMEM indicating insufficient memory for addresses */
+	if (netdev_uc_count(netdev) > rar_entries)
+		return -ENOMEM;
+
+	if (!netdev_uc_empty(netdev) && rar_entries) {
+		struct netdev_hw_addr *ha;
+		/* return error if we do not support writing to RAR table */
+		if (!hw->mac.ops.set_rar)
+			return -ENOMEM;
+
+		netdev_for_each_uc_addr(ha, netdev) {
+			if (!rar_entries)
+				break;
+			hw->mac.ops.set_rar(hw, rar_entries--, ha->addr,
+					    vfn, IXGBE_RAH_AV);
+			count++;
+		}
+	}
+	/* write the addresses in reverse order to avoid write combining */
+	for (; rar_entries > 0 ; rar_entries--)
+		hw->mac.ops.clear_rar(hw, rar_entries);
+
+	return count;
+}
+
+/**
  * ixgbe_set_rx_mode - Unicast, Multicast and Promiscuous mode set
  * @netdev: network interface device structure
  *
@@ -3007,38 +3044,58 @@
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
-	u32 fctrl;
+	u32 fctrl, vmolr = IXGBE_VMOLR_BAM | IXGBE_VMOLR_AUPE;
+	int count;
 
 	/* Check for Promiscuous and All Multicast modes */
 
 	fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
 
+	/* clear the bits we are changing the status of */
+	fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+
 	if (netdev->flags & IFF_PROMISC) {
 		hw->addr_ctrl.user_set_promisc = true;
 		fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+		vmolr |= (IXGBE_VMOLR_ROPE | IXGBE_VMOLR_MPE);
 		/* don't hardware filter vlans in promisc mode */
 		ixgbe_vlan_filter_disable(adapter);
 	} else {
 		if (netdev->flags & IFF_ALLMULTI) {
 			fctrl |= IXGBE_FCTRL_MPE;
-			fctrl &= ~IXGBE_FCTRL_UPE;
-		} else if (!hw->addr_ctrl.uc_set_promisc) {
-			fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+			vmolr |= IXGBE_VMOLR_MPE;
+		} else {
+			/*
+			 * Write addresses to the MTA, if the attempt fails
+			 * then we should just turn on promiscous mode so
+			 * that we can at least receive multicast traffic
+			 */
+			hw->mac.ops.update_mc_addr_list(hw, netdev);
+			vmolr |= IXGBE_VMOLR_ROMPE;
 		}
 		ixgbe_vlan_filter_enable(adapter);
 		hw->addr_ctrl.user_set_promisc = false;
+		/*
+		 * Write addresses to available RAR registers, if there is not
+		 * sufficient space to store all the addresses then enable
+		 * unicast promiscous mode
+		 */
+		count = ixgbe_write_uc_addr_list(netdev);
+		if (count < 0) {
+			fctrl |= IXGBE_FCTRL_UPE;
+			vmolr |= IXGBE_VMOLR_ROPE;
+		}
+	}
+
+	if (adapter->num_vfs) {
+		ixgbe_restore_vf_multicasts(adapter);
+		vmolr |= IXGBE_READ_REG(hw, IXGBE_VMOLR(adapter->num_vfs)) &
+			 ~(IXGBE_VMOLR_MPE | IXGBE_VMOLR_ROMPE |
+			   IXGBE_VMOLR_ROPE);
+		IXGBE_WRITE_REG(hw, IXGBE_VMOLR(adapter->num_vfs), vmolr);
 	}
 
 	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
-
-	/* reprogram secondary unicast list */
-	hw->mac.ops.update_uc_addr_list(hw, netdev);
-
-	/* reprogram multicast list */
-	hw->mac.ops.update_mc_addr_list(hw, netdev);
-
-	if (adapter->num_vfs)
-		ixgbe_restore_vf_multicasts(adapter);
 }
 
 static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter)
@@ -3257,8 +3314,8 @@
 			msleep(1);
 	}
 	if (k >= IXGBE_MAX_RX_DESC_POLL) {
-		DPRINTK(DRV, ERR, "RXDCTL.ENABLE on Rx queue %d "
-		        "not set within the polling period\n", rxr);
+		e_err(drv, "RXDCTL.ENABLE on Rx queue %d not set within "
+		      "the polling period\n", rxr);
 	}
 	ixgbe_release_rx_desc(&adapter->hw, adapter->rx_ring[rxr],
 	                      (adapter->rx_ring[rxr]->count - 1));
@@ -3387,8 +3444,7 @@
 			} while (--wait_loop &&
 			         !(txdctl & IXGBE_TXDCTL_ENABLE));
 			if (!wait_loop)
-				DPRINTK(DRV, ERR, "Could not enable "
-				        "Tx Queue %d\n", j);
+				e_err(drv, "Could not enable Tx Queue %d\n", j);
 		}
 	}
 
@@ -3436,8 +3492,7 @@
 	if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) {
 		u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
 		if (esdp & IXGBE_ESDP_SDP1)
-			DPRINTK(DRV, CRIT,
-				"Fan has stopped, replace the adapter\n");
+			e_crit(drv, "Fan has stopped, replace the adapter\n");
 	}
 
 	/*
@@ -3466,7 +3521,7 @@
 	} else {
 		err = ixgbe_non_sfp_link_config(hw);
 		if (err)
-			DPRINTK(PROBE, ERR, "link_config FAILED %d\n", err);
+			e_err(probe, "link_config FAILED %d\n", err);
 	}
 
 	for (i = 0; i < adapter->num_tx_queues; i++)
@@ -3527,19 +3582,19 @@
 	case IXGBE_ERR_SFP_NOT_PRESENT:
 		break;
 	case IXGBE_ERR_MASTER_REQUESTS_PENDING:
-		dev_err(&adapter->pdev->dev, "master disable timed out\n");
+		e_dev_err("master disable timed out\n");
 		break;
 	case IXGBE_ERR_EEPROM_VERSION:
 		/* We are running on a pre-production device, log a warning */
-		dev_warn(&adapter->pdev->dev, "This device is a pre-production "
-		         "adapter/LOM.  Please be aware there may be issues "
-		         "associated with your hardware.  If you are "
-		         "experiencing problems please contact your Intel or "
-		         "hardware representative who provided you with this "
-		         "hardware.\n");
+		e_dev_warn("This device is a pre-production adapter/LOM. "
+			   "Please be aware there may be issuesassociated with "
+			   "your hardware.  If you are experiencing problems "
+			   "please contact your Intel or hardware "
+			   "representative who provided you with this "
+			   "hardware.\n");
 		break;
 	default:
-		dev_err(&adapter->pdev->dev, "Hardware Error: %d\n", err);
+		e_dev_err("Hardware Error: %d\n", err);
 	}
 
 	/* reprogram the RAR[0] in case user changed it. */
@@ -3920,12 +3975,12 @@
 		adapter->num_tx_queues = 1;
 #ifdef CONFIG_IXGBE_DCB
 		if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
-			DPRINTK(PROBE, INFO, "FCoE enabled with DCB\n");
+			e_info(probe, "FCoE enabled with DCB\n");
 			ixgbe_set_dcb_queues(adapter);
 		}
 #endif
 		if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
-			DPRINTK(PROBE, INFO, "FCoE enabled with RSS\n");
+			e_info(probe, "FCoE enabled with RSS\n");
 			if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) ||
 			    (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
 				ixgbe_set_fdir_queues(adapter);
@@ -4038,7 +4093,8 @@
 		 * This just means we'll go with either a single MSI
 		 * vector or fall back to legacy interrupts.
 		 */
-		DPRINTK(HW, DEBUG, "Unable to allocate MSI-X interrupts\n");
+		netif_printk(adapter, hw, KERN_DEBUG, adapter->netdev,
+			     "Unable to allocate MSI-X interrupts\n");
 		adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
 		kfree(adapter->msix_entries);
 		adapter->msix_entries = NULL;
@@ -4435,8 +4491,9 @@
 	if (!err) {
 		adapter->flags |= IXGBE_FLAG_MSI_ENABLED;
 	} else {
-		DPRINTK(HW, DEBUG, "Unable to allocate MSI interrupt, "
-		        "falling back to legacy.  Error: %d\n", err);
+		netif_printk(adapter, hw, KERN_DEBUG, adapter->netdev,
+			     "Unable to allocate MSI interrupt, "
+			     "falling back to legacy.  Error: %d\n", err);
 		/* reset err */
 		err = 0;
 	}
@@ -4557,27 +4614,25 @@
 
 	err = ixgbe_set_interrupt_capability(adapter);
 	if (err) {
-		DPRINTK(PROBE, ERR, "Unable to setup interrupt capabilities\n");
+		e_dev_err("Unable to setup interrupt capabilities\n");
 		goto err_set_interrupt;
 	}
 
 	err = ixgbe_alloc_q_vectors(adapter);
 	if (err) {
-		DPRINTK(PROBE, ERR, "Unable to allocate memory for queue "
-		        "vectors\n");
+		e_dev_err("Unable to allocate memory for queue vectors\n");
 		goto err_alloc_q_vectors;
 	}
 
 	err = ixgbe_alloc_queues(adapter);
 	if (err) {
-		DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n");
+		e_dev_err("Unable to allocate memory for queues\n");
 		goto err_alloc_queues;
 	}
 
-	DPRINTK(DRV, INFO, "Multiqueue %s: Rx Queue count = %u, "
-	        "Tx Queue count = %u\n",
-	        (adapter->num_rx_queues > 1) ? "Enabled" :
-	        "Disabled", adapter->num_rx_queues, adapter->num_tx_queues);
+	e_dev_info("Multiqueue %s: Rx Queue count = %u, Tx Queue count = %u\n",
+		   (adapter->num_rx_queues > 1) ? "Enabled" : "Disabled",
+		   adapter->num_rx_queues, adapter->num_tx_queues);
 
 	set_bit(__IXGBE_DOWN, &adapter->state);
 
@@ -4648,15 +4703,13 @@
 			goto reschedule;
 		ret = hw->phy.ops.reset(hw);
 		if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
-			dev_err(&adapter->pdev->dev, "failed to initialize "
-				"because an unsupported SFP+ module type "
-				"was detected.\n"
-				"Reload the driver after installing a "
-				"supported module.\n");
+			e_dev_err("failed to initialize because an unsupported "
+				  "SFP+ module type was detected.\n");
+			e_dev_err("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);
+			e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type);
 		}
 		/* don't need this routine any more */
 		clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
@@ -4730,6 +4783,7 @@
 #ifdef CONFIG_IXGBE_DCB
 		/* Default traffic class to use for FCoE */
 		adapter->fcoe.tc = IXGBE_FCOE_DEFTC;
+		adapter->fcoe.up = IXGBE_FCOE_DEFTC;
 #endif
 #endif /* IXGBE_FCOE */
 	}
@@ -4783,7 +4837,7 @@
 
 	/* initialize eeprom parameters */
 	if (ixgbe_init_eeprom_params_generic(hw)) {
-		dev_err(&pdev->dev, "EEPROM initialization failed\n");
+		e_dev_err("EEPROM initialization failed\n");
 		return -EIO;
 	}
 
@@ -4836,8 +4890,7 @@
 err:
 	vfree(tx_ring->tx_buffer_info);
 	tx_ring->tx_buffer_info = NULL;
-	DPRINTK(PROBE, ERR, "Unable to allocate memory for the transmit "
-	                    "descriptor ring\n");
+	e_err(probe, "Unable to allocate memory for the Tx descriptor ring\n");
 	return -ENOMEM;
 }
 
@@ -4859,7 +4912,7 @@
 		err = ixgbe_setup_tx_resources(adapter, adapter->tx_ring[i]);
 		if (!err)
 			continue;
-		DPRINTK(PROBE, ERR, "Allocation for Tx Queue %u failed\n", i);
+		e_err(probe, "Allocation for Tx Queue %u failed\n", i);
 		break;
 	}
 
@@ -4884,8 +4937,8 @@
 	if (!rx_ring->rx_buffer_info)
 		rx_ring->rx_buffer_info = vmalloc(size);
 	if (!rx_ring->rx_buffer_info) {
-		DPRINTK(PROBE, ERR,
-		        "vmalloc allocation failed for the rx desc ring\n");
+		e_err(probe, "vmalloc allocation failed for the Rx "
+		      "descriptor ring\n");
 		goto alloc_failed;
 	}
 	memset(rx_ring->rx_buffer_info, 0, size);
@@ -4898,8 +4951,8 @@
 					   &rx_ring->dma, GFP_KERNEL);
 
 	if (!rx_ring->desc) {
-		DPRINTK(PROBE, ERR,
-		        "Memory allocation failed for the rx desc ring\n");
+		e_err(probe, "Memory allocation failed for the Rx "
+		      "descriptor ring\n");
 		vfree(rx_ring->rx_buffer_info);
 		goto alloc_failed;
 	}
@@ -4932,7 +4985,7 @@
 		err = ixgbe_setup_rx_resources(adapter, adapter->rx_ring[i]);
 		if (!err)
 			continue;
-		DPRINTK(PROBE, ERR, "Allocation for Rx Queue %u failed\n", i);
+		e_err(probe, "Allocation for Rx Queue %u failed\n", i);
 		break;
 	}
 
@@ -5031,8 +5084,7 @@
 	if ((new_mtu < 68) || (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE))
 		return -EINVAL;
 
-	DPRINTK(PROBE, INFO, "changing MTU from %d to %d\n",
-	        netdev->mtu, new_mtu);
+	e_info(probe, "changing MTU from %d to %d\n", netdev->mtu, new_mtu);
 	/* must set new MTU before calling down or up */
 	netdev->mtu = new_mtu;
 
@@ -5145,8 +5197,7 @@
 
 	err = pci_enable_device_mem(pdev);
 	if (err) {
-		printk(KERN_ERR "ixgbe: Cannot enable PCI device from "
-				"suspend\n");
+		e_dev_err("Cannot enable PCI device from suspend\n");
 		return err;
 	}
 	pci_set_master(pdev);
@@ -5155,8 +5206,7 @@
 
 	err = ixgbe_init_interrupt_scheme(adapter);
 	if (err) {
-		printk(KERN_ERR "ixgbe: Cannot initialize interrupts for "
-		                "device\n");
+		e_dev_err("Cannot initialize interrupts for device\n");
 		return err;
 	}
 
@@ -5517,10 +5567,10 @@
 	err = hw->phy.ops.identify_sfp(hw);
 
 	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
-		dev_err(&adapter->pdev->dev, "failed to initialize because "
-			"an unsupported SFP+ module type was detected.\n"
-			"Reload the driver after installing a supported "
-			"module.\n");
+		e_dev_err("failed to initialize because an unsupported SFP+ "
+			  "module type was detected.\n");
+		e_dev_err("Reload the driver after installing a supported "
+			  "module.\n");
 		unregister_netdev(adapter->netdev);
 		return;
 	}
@@ -5549,8 +5599,8 @@
 			set_bit(__IXGBE_FDIR_INIT_DONE,
 			        &(adapter->tx_ring[i]->reinit_state));
 	} else {
-		DPRINTK(PROBE, ERR, "failed to finish FDIR re-initialization, "
-			"ignored adding FDIR ATR filters\n");
+		e_err(probe, "failed to finish FDIR re-initialization, "
+		      "ignored adding FDIR ATR filters\n");
 	}
 	/* Done FDIR Re-initialization, enable transmits */
 	netif_tx_start_all_queues(adapter->netdev);
@@ -5621,16 +5671,14 @@
 				flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
 			}
 
-			printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, "
-			       "Flow Control: %s\n",
-			       netdev->name,
+			e_info(drv, "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")),
+			       "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"))));
+			       (flow_rx ? "RX" :
+			       (flow_tx ? "TX" : "None"))));
 
 			netif_carrier_on(netdev);
 		} else {
@@ -5641,8 +5689,7 @@
 		adapter->link_up = false;
 		adapter->link_speed = 0;
 		if (netif_carrier_ok(netdev)) {
-			printk(KERN_INFO "ixgbe: %s NIC Link is Down\n",
-			       netdev->name);
+			e_info(drv, "NIC Link is Down\n");
 			netif_carrier_off(netdev);
 		}
 	}
@@ -5818,9 +5865,9 @@
 				break;
 			default:
 				if (unlikely(net_ratelimit())) {
-					DPRINTK(PROBE, WARNING,
-					 "partial checksum but proto=%x!\n",
-					 skb->protocol);
+					e_warn(probe, "partial checksum "
+					       "but proto=%x!\n",
+					       skb->protocol);
 				}
 				break;
 			}
@@ -5931,7 +5978,7 @@
 	return count;
 
 dma_error:
-	dev_err(&pdev->dev, "TX DMA map failed\n");
+	e_dev_err("TX DMA map failed\n");
 
 	/* clear timestamp and dma mappings for failed tx_buffer_info map */
 	tx_buffer_info->dma = 0;
@@ -6101,21 +6148,26 @@
 	struct ixgbe_adapter *adapter = netdev_priv(dev);
 	int txq = smp_processor_id();
 
+#ifdef IXGBE_FCOE
+	if ((skb->protocol == htons(ETH_P_FCOE)) ||
+	    (skb->protocol == htons(ETH_P_FIP))) {
+		if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
+			txq &= (adapter->ring_feature[RING_F_FCOE].indices - 1);
+			txq += adapter->ring_feature[RING_F_FCOE].mask;
+			return txq;
+		} else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+			txq = adapter->fcoe.up;
+			return txq;
+		}
+	}
+#endif
+
 	if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
 		while (unlikely(txq >= dev->real_num_tx_queues))
 			txq -= dev->real_num_tx_queues;
 		return txq;
 	}
 
-#ifdef IXGBE_FCOE
-	if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) &&
-	    ((skb->protocol == htons(ETH_P_FCOE)) ||
-	     (skb->protocol == htons(ETH_P_FIP)))) {
-		txq &= (adapter->ring_feature[RING_F_FCOE].indices - 1);
-		txq += adapter->ring_feature[RING_F_FCOE].mask;
-		return txq;
-	}
-#endif
 	if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
 		if (skb->priority == TC_PRIO_CONTROL)
 			txq = adapter->ring_feature[RING_F_DCB].indices-1;
@@ -6159,18 +6211,15 @@
 	tx_ring = adapter->tx_ring[skb->queue_mapping];
 
 #ifdef IXGBE_FCOE
-	if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
-#ifdef CONFIG_IXGBE_DCB
-		/* for FCoE with DCB, we force the priority to what
-		 * was specified by the switch */
-		if ((skb->protocol == htons(ETH_P_FCOE)) ||
-		    (skb->protocol == htons(ETH_P_FIP))) {
-			tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK
-				      << IXGBE_TX_FLAGS_VLAN_SHIFT);
-			tx_flags |= ((adapter->fcoe.up << 13)
-				     << IXGBE_TX_FLAGS_VLAN_SHIFT);
-		}
-#endif
+	/* for FCoE with DCB, we force the priority to what
+	 * was specified by the switch */
+	if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED &&
+	    (skb->protocol == htons(ETH_P_FCOE) ||
+	     skb->protocol == htons(ETH_P_FIP))) {
+		tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK
+			      << IXGBE_TX_FLAGS_VLAN_SHIFT);
+		tx_flags |= ((adapter->fcoe.up << 13)
+			      << IXGBE_TX_FLAGS_VLAN_SHIFT);
 		/* flag for FCoE offloads */
 		if (skb->protocol == htons(ETH_P_FCOE))
 			tx_flags |= IXGBE_TX_FLAGS_FCOE;
@@ -6430,8 +6479,7 @@
 	adapter->flags |= IXGBE_FLAG_SRIOV_ENABLED;
 	err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
 	if (err) {
-		DPRINTK(PROBE, ERR,
-			"Failed to enable PCI sriov: %d\n", err);
+		e_err(probe, "Failed to enable PCI sriov: %d\n", err);
 		goto err_novfs;
 	}
 	/* If call to enable VFs succeeded then allocate memory
@@ -6455,9 +6503,8 @@
 	}
 
 	/* Oh oh */
-	DPRINTK(PROBE, ERR,
-		"Unable to allocate memory for VF "
-		"Data Storage - SRIOV disabled\n");
+	e_err(probe, "Unable to allocate memory for VF Data Storage - "
+	      "SRIOV disabled\n");
 	pci_disable_sriov(adapter->pdev);
 
 err_novfs:
@@ -6514,8 +6561,8 @@
 			err = dma_set_coherent_mask(&pdev->dev,
 						    DMA_BIT_MASK(32));
 			if (err) {
-				dev_err(&pdev->dev, "No usable DMA "
-				        "configuration, aborting\n");
+				dev_err(&pdev->dev,
+					"No usable DMA configuration, aborting\n");
 				goto err_dma;
 			}
 		}
@@ -6526,7 +6573,7 @@
 	                                   IORESOURCE_MEM), ixgbe_driver_name);
 	if (err) {
 		dev_err(&pdev->dev,
-		        "pci_request_selected_regions failed 0x%x\n", err);
+			"pci_request_selected_regions failed 0x%x\n", err);
 		goto err_pci_reg;
 	}
 
@@ -6637,8 +6684,7 @@
 	if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) {
 		u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
 		if (esdp & IXGBE_ESDP_SDP1)
-			DPRINTK(PROBE, CRIT,
-				"Fan has stopped, replace the adapter\n");
+			e_crit(probe, "Fan has stopped, replace the adapter\n");
 	}
 
 	/* reset_hw fills in the perm_addr as well */
@@ -6657,13 +6703,13 @@
 			  round_jiffies(jiffies + (2 * HZ)));
 		err = 0;
 	} else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
-		dev_err(&adapter->pdev->dev, "failed to initialize because "
-			"an unsupported SFP+ module type was detected.\n"
-			"Reload the driver after installing a supported "
-			"module.\n");
+		e_dev_err("failed to initialize because an unsupported SFP+ "
+			  "module type was detected.\n");
+		e_dev_err("Reload the driver after installing a supported "
+			  "module.\n");
 		goto err_sw_init;
 	} else if (err) {
-		dev_err(&adapter->pdev->dev, "HW Init failed: %d\n", err);
+		e_dev_err("HW Init failed: %d\n", err);
 		goto err_sw_init;
 	}
 
@@ -6707,6 +6753,11 @@
 				adapter->flags &= ~IXGBE_FLAG_FCOE_CAPABLE;
 		}
 	}
+	if (adapter->flags & IXGBE_FLAG_FCOE_CAPABLE) {
+		netdev->vlan_features |= NETIF_F_FCOE_CRC;
+		netdev->vlan_features |= NETIF_F_FSO;
+		netdev->vlan_features |= NETIF_F_FCOE_MTU;
+	}
 #endif /* IXGBE_FCOE */
 	if (pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
@@ -6716,7 +6767,7 @@
 
 	/* make sure the EEPROM is good */
 	if (hw->eeprom.ops.validate_checksum(hw, NULL) < 0) {
-		dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n");
+		e_dev_err("The EEPROM Checksum Is Not Valid\n");
 		err = -EIO;
 		goto err_eeprom;
 	}
@@ -6725,7 +6776,7 @@
 	memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len);
 
 	if (ixgbe_validate_mac_addr(netdev->perm_addr)) {
-		dev_err(&pdev->dev, "invalid MAC address\n");
+		e_dev_err("invalid MAC address\n");
 		err = -EIO;
 		goto err_eeprom;
 	}
@@ -6760,7 +6811,7 @@
 	hw->mac.ops.get_bus_info(hw);
 
 	/* print bus type/speed/width info */
-	dev_info(&pdev->dev, "(PCI Express:%s:%s) %pM\n",
+	e_dev_info("(PCI Express:%s:%s) %pM\n",
 	        ((hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0Gb/s":
 	         (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5Gb/s":"Unknown"),
 	        ((hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" :
@@ -6770,20 +6821,20 @@
 	        netdev->dev_addr);
 	ixgbe_read_pba_num_generic(hw, &part_num);
 	if (ixgbe_is_sfp(hw) && hw->phy.sfp_type != ixgbe_sfp_type_not_present)
-		dev_info(&pdev->dev, "MAC: %d, PHY: %d, SFP+: %d, PBA No: %06x-%03x\n",
-		         hw->mac.type, hw->phy.type, hw->phy.sfp_type,
-		         (part_num >> 8), (part_num & 0xff));
+		e_dev_info("MAC: %d, PHY: %d, SFP+: %d, "
+			   "PBA No: %06x-%03x\n",
+			   hw->mac.type, hw->phy.type, hw->phy.sfp_type,
+			   (part_num >> 8), (part_num & 0xff));
 	else
-		dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
-		         hw->mac.type, hw->phy.type,
-		         (part_num >> 8), (part_num & 0xff));
+		e_dev_info("MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
+			   hw->mac.type, hw->phy.type,
+			   (part_num >> 8), (part_num & 0xff));
 
 	if (hw->bus.width <= ixgbe_bus_width_pcie_x4) {
-		dev_warn(&pdev->dev, "PCI-Express bandwidth available for "
-		         "this card is not sufficient for optimal "
-		         "performance.\n");
-		dev_warn(&pdev->dev, "For optimal performance a x8 "
-		         "PCI-Express slot is required.\n");
+		e_dev_warn("PCI-Express bandwidth available for this card is "
+			   "not sufficient for optimal performance.\n");
+		e_dev_warn("For optimal performance a x8 PCI-Express slot "
+			   "is required.\n");
 	}
 
 	/* save off EEPROM version number */
@@ -6794,12 +6845,12 @@
 
 	if (err == IXGBE_ERR_EEPROM_VERSION) {
 		/* We are running on a pre-production device, log a warning */
-		dev_warn(&pdev->dev, "This device is a pre-production "
-		         "adapter/LOM.  Please be aware there may be issues "
-		         "associated with your hardware.  If you are "
-		         "experiencing problems please contact your Intel or "
-		         "hardware representative who provided you with this "
-		         "hardware.\n");
+		e_dev_warn("This device is a pre-production adapter/LOM. "
+			   "Please be aware there may be issues associated "
+			   "with your hardware.  If you are experiencing "
+			   "problems please contact your Intel or hardware "
+			   "representative who provided you with this "
+			   "hardware.\n");
 	}
 	strcpy(netdev->name, "eth%d");
 	err = register_netdev(netdev);
@@ -6822,8 +6873,7 @@
 	}
 #endif
 	if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
-		DPRINTK(PROBE, INFO, "IOV is enabled with %d VFs\n",
-			adapter->num_vfs);
+		e_info(probe, "IOV is enabled with %d VFs\n", adapter->num_vfs);
 		for (i = 0; i < adapter->num_vfs; i++)
 			ixgbe_vf_configuration(pdev, (i | 0x10000000));
 	}
@@ -6831,7 +6881,7 @@
 	/* add san mac addr to netdev */
 	ixgbe_add_sanmac_netdev(netdev);
 
-	dev_info(&pdev->dev, "Intel(R) 10 Gigabit Network Connection\n");
+	e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
 	cards_found++;
 	return 0;
 
@@ -6921,7 +6971,7 @@
 	pci_release_selected_regions(pdev, pci_select_bars(pdev,
 	                             IORESOURCE_MEM));
 
-	DPRINTK(PROBE, INFO, "complete\n");
+	e_dev_info("complete\n");
 
 	free_netdev(netdev);
 
@@ -6971,8 +7021,7 @@
 	int err;
 
 	if (pci_enable_device_mem(pdev)) {
-		DPRINTK(PROBE, ERR,
-		        "Cannot re-enable PCI device after reset.\n");
+		e_err(probe, "Cannot re-enable PCI device after reset.\n");
 		result = PCI_ERS_RESULT_DISCONNECT;
 	} else {
 		pci_set_master(pdev);
@@ -6988,8 +7037,8 @@
 
 	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);
+		e_dev_err("pci_cleanup_aer_uncorrect_error_status "
+			  "failed 0x%0x\n", err);
 		/* non-fatal, continue */
 	}
 
@@ -7010,7 +7059,7 @@
 
 	if (netif_running(netdev)) {
 		if (ixgbe_up(adapter)) {
-			DPRINTK(PROBE, INFO, "ixgbe_up failed after reset\n");
+			e_info(probe, "ixgbe_up failed after reset\n");
 			return;
 		}
 	}
@@ -7046,10 +7095,9 @@
 static int __init ixgbe_init_module(void)
 {
 	int ret;
-	printk(KERN_INFO "%s: %s - version %s\n", ixgbe_driver_name,
-	       ixgbe_driver_string, ixgbe_driver_version);
-
-	printk(KERN_INFO "%s: %s\n", ixgbe_driver_name, ixgbe_copyright);
+	pr_info("%s - version %s\n", ixgbe_driver_string,
+		   ixgbe_driver_version);
+	pr_info("%s\n", ixgbe_copyright);
 
 #ifdef CONFIG_IXGBE_DCA
 	dca_register_notify(&dca_notifier);
@@ -7088,18 +7136,17 @@
 }
 
 #endif /* CONFIG_IXGBE_DCA */
-#ifdef DEBUG
+
 /**
- * ixgbe_get_hw_dev_name - return device name string
+ * ixgbe_get_hw_dev return device
  * used by hardware layer to print debugging information
  **/
-char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw)
+struct net_device *ixgbe_get_hw_dev(struct ixgbe_hw *hw)
 {
 	struct ixgbe_adapter *adapter = hw->back;
-	return adapter->netdev->name;
+	return adapter->netdev;
 }
 
-#endif
 module_exit(ixgbe_exit_module);
 
 /* ixgbe_main.c */
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c
index 48325a5..6c0d42e 100644
--- a/drivers/net/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ixgbe/ixgbe_phy.c
@@ -577,6 +577,8 @@
 		 * 6    SFP_SR/LR_CORE1 - 82599-specific
 		 * 7    SFP_act_lmt_DA_CORE0 - 82599-specific
 		 * 8    SFP_act_lmt_DA_CORE1 - 82599-specific
+		 * 9    SFP_1g_cu_CORE0 - 82599-specific
+		 * 10   SFP_1g_cu_CORE1 - 82599-specific
 		 */
 		if (hw->mac.type == ixgbe_mac_82598EB) {
 			if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
@@ -625,6 +627,13 @@
 				else
 					hw->phy.sfp_type =
 					              ixgbe_sfp_type_srlr_core1;
+			else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE)
+				if (hw->bus.lan_id == 0)
+					hw->phy.sfp_type =
+						ixgbe_sfp_type_1g_cu_core0;
+				else
+					hw->phy.sfp_type =
+						ixgbe_sfp_type_1g_cu_core1;
 			else
 				hw->phy.sfp_type = ixgbe_sfp_type_unknown;
 		}
@@ -696,8 +705,10 @@
 			goto out;
 		}
 
-		/* 1G SFP modules are not supported */
-		if (comp_codes_10g == 0) {
+		/* Verify supported 1G SFP modules */
+		if (comp_codes_10g == 0 &&
+		    !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
+		      hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0)) {
 			hw->phy.type = ixgbe_phy_sfp_unsupported;
 			status = IXGBE_ERR_SFP_NOT_SUPPORTED;
 			goto out;
@@ -711,7 +722,9 @@
 
 		/* This is guaranteed to be 82599, no need to check for NULL */
 		hw->mac.ops.get_device_caps(hw, &enforce_sfp);
-		if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) {
+		if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) &&
+		    !((hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0) ||
+		      (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1))) {
 			/* Make sure we're a supported PHY type */
 			if (hw->phy.type == ixgbe_phy_sfp_intel) {
 				status = 0;
@@ -742,6 +755,7 @@
                                         u16 *data_offset)
 {
 	u16 sfp_id;
+	u16 sfp_type = hw->phy.sfp_type;
 
 	if (hw->phy.sfp_type == ixgbe_sfp_type_unknown)
 		return IXGBE_ERR_SFP_NOT_SUPPORTED;
@@ -753,6 +767,17 @@
 	    (hw->phy.sfp_type == ixgbe_sfp_type_da_cu))
 		return IXGBE_ERR_SFP_NOT_SUPPORTED;
 
+	/*
+	 * Limiting active cables and 1G Phys must be initialized as
+	 * SR modules
+	 */
+	if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 ||
+	    sfp_type == ixgbe_sfp_type_1g_cu_core0)
+		sfp_type = ixgbe_sfp_type_srlr_core0;
+	else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 ||
+	         sfp_type == ixgbe_sfp_type_1g_cu_core1)
+		sfp_type = ixgbe_sfp_type_srlr_core1;
+
 	/* Read offset to PHY init contents */
 	hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset);
 
@@ -769,7 +794,7 @@
 	hw->eeprom.ops.read(hw, *list_offset, &sfp_id);
 
 	while (sfp_id != IXGBE_PHY_INIT_END_NL) {
-		if (sfp_id == hw->phy.sfp_type) {
+		if (sfp_id == sfp_type) {
 			(*list_offset)++;
 			hw->eeprom.ops.read(hw, *list_offset, data_offset);
 			if ((!*data_offset) || (*data_offset == 0xFFFF)) {
diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h
index ef4ba83..fb3898f 100644
--- a/drivers/net/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ixgbe/ixgbe_phy.h
@@ -48,6 +48,7 @@
 #define IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING    0x4
 #define IXGBE_SFF_1GBASESX_CAPABLE           0x1
 #define IXGBE_SFF_1GBASELX_CAPABLE           0x2
+#define IXGBE_SFF_1GBASET_CAPABLE            0x8
 #define IXGBE_SFF_10GBASESR_CAPABLE          0x10
 #define IXGBE_SFF_10GBASELR_CAPABLE          0x20
 #define IXGBE_I2C_EEPROM_READ_MASK           0x100
diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c
index f6cee94..49661a1 100644
--- a/drivers/net/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ixgbe/ixgbe_sriov.c
@@ -25,7 +25,6 @@
 
 *******************************************************************************/
 
-
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -138,6 +137,7 @@
 inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
+	int rar_entry = hw->mac.num_rar_entries - (vf + 1);
 
 	/* reset offloads to defaults */
 	if (adapter->vfinfo[vf].pf_vlan) {
@@ -159,26 +159,17 @@
 	/* Flush and reset the mta with the new values */
 	ixgbe_set_rx_mode(adapter->netdev);
 
-	if (adapter->vfinfo[vf].rar > 0) {
-		adapter->hw.mac.ops.clear_rar(&adapter->hw,
-		                              adapter->vfinfo[vf].rar);
-		adapter->vfinfo[vf].rar = -1;
-	}
+	hw->mac.ops.clear_rar(hw, rar_entry);
 }
 
 int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
                           int vf, unsigned char *mac_addr)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
-
-	adapter->vfinfo[vf].rar = hw->mac.ops.set_rar(hw, vf + 1, mac_addr,
-	                                              vf, IXGBE_RAH_AV);
-	if (adapter->vfinfo[vf].rar < 0) {
-		DPRINTK(DRV, ERR, "Could not set MAC Filter for VF %d\n", vf);
-		return -1;
-	}
+	int rar_entry = hw->mac.num_rar_entries - (vf + 1);
 
 	memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, 6);
+	hw->mac.ops.set_rar(hw, rar_entry, mac_addr, vf, IXGBE_RAH_AV);
 
 	return 0;
 }
@@ -194,11 +185,8 @@
 
 	if (enable) {
 		random_ether_addr(vf_mac_addr);
-		DPRINTK(PROBE, INFO, "IOV: VF %d is enabled "
-		       "mac %02X:%02X:%02X:%02X:%02X:%02X\n",
-		       vfn,
-		       vf_mac_addr[0], vf_mac_addr[1], vf_mac_addr[2],
-		       vf_mac_addr[3], vf_mac_addr[4], vf_mac_addr[5]);
+		e_info(probe, "IOV: VF %d is enabled MAC %pM\n",
+		       vfn, vf_mac_addr);
 		/*
 		 * Store away the VF "permananet" MAC address, it will ask
 		 * for it later.
@@ -243,7 +231,7 @@
 	retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf);
 
 	if (retval)
-		printk(KERN_ERR "Error receiving message from VF\n");
+		pr_err("Error receiving message from VF\n");
 
 	/* this is a message we already processed, do nothing */
 	if (msgbuf[0] & (IXGBE_VT_MSGTYPE_ACK | IXGBE_VT_MSGTYPE_NACK))
@@ -257,7 +245,7 @@
 	if (msgbuf[0] == IXGBE_VF_RESET) {
 		unsigned char *vf_mac = adapter->vfinfo[vf].vf_mac_addresses;
 		u8 *addr = (u8 *)(&msgbuf[1]);
-		DPRINTK(PROBE, INFO, "VF Reset msg received from vf %d\n", vf);
+		e_info(probe, "VF Reset msg received from vf %d\n", vf);
 		adapter->vfinfo[vf].clear_to_send = false;
 		ixgbe_vf_reset_msg(adapter, vf);
 		adapter->vfinfo[vf].clear_to_send = true;
@@ -310,7 +298,7 @@
 		retval = ixgbe_set_vf_vlan(adapter, add, vid, vf);
 		break;
 	default:
-		DPRINTK(DRV, ERR, "Unhandled Msg %8.8x\n", msgbuf[0]);
+		e_err(drv, "Unhandled Msg %8.8x\n", msgbuf[0]);
 		retval = IXGBE_ERR_MBX;
 		break;
 	}
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index cdd1998..9587d97 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -2214,6 +2214,8 @@
 	ixgbe_sfp_type_srlr_core1 = 6,
 	ixgbe_sfp_type_da_act_lmt_core0 = 7,
 	ixgbe_sfp_type_da_act_lmt_core1 = 8,
+	ixgbe_sfp_type_1g_cu_core0 = 9,
+	ixgbe_sfp_type_1g_cu_core1 = 10,
 	ixgbe_sfp_type_not_present = 0xFFFE,
 	ixgbe_sfp_type_unknown = 0xFFFF
 };
diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c
index a16cff7..3e291cc 100644
--- a/drivers/net/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ixgbevf/ixgbevf_main.c
@@ -1463,18 +1463,10 @@
 {
 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
-	struct net_device *v_netdev;
 
 	/* add VID to filter table */
 	if (hw->mac.ops.set_vfta)
 		hw->mac.ops.set_vfta(hw, vid, 0, true);
-	/*
-	 * Copy feature flags from netdev to the vlan netdev for this vid.
-	 * This allows things like TSO to bubble down to our vlan device.
-	 */
-	v_netdev = vlan_group_get_device(adapter->vlgrp, vid);
-	v_netdev->features |= adapter->netdev->features;
-	vlan_group_set_device(adapter->vlgrp, vid, v_netdev);
 }
 
 static void ixgbevf_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
@@ -2229,7 +2221,7 @@
 	if (err) {
 		dev_info(&pdev->dev,
 		         "PF still in reset state, assigning new address\n");
-		random_ether_addr(hw->mac.addr);
+		dev_hw_addr_random(adapter->netdev, hw->mac.addr);
 	} else {
 		err = hw->mac.ops.init_hw(hw);
 		if (err) {
@@ -2935,7 +2927,8 @@
 	struct ixgbevf_tx_buffer *tx_buffer_info;
 	unsigned int len;
 	unsigned int total = skb->len;
-	unsigned int offset = 0, size, count = 0;
+	unsigned int offset = 0, size;
+	int count = 0;
 	unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
 	unsigned int f;
 	int i;
@@ -3401,7 +3394,6 @@
 	/* setup the private structure */
 	err = ixgbevf_sw_init(adapter);
 
-#ifdef MAX_SKB_FRAGS
 	netdev->features = NETIF_F_SG |
 			   NETIF_F_IP_CSUM |
 			   NETIF_F_HW_VLAN_TX |
@@ -3411,16 +3403,16 @@
 	netdev->features |= NETIF_F_IPV6_CSUM;
 	netdev->features |= NETIF_F_TSO;
 	netdev->features |= NETIF_F_TSO6;
+	netdev->features |= NETIF_F_GRO;
 	netdev->vlan_features |= NETIF_F_TSO;
 	netdev->vlan_features |= NETIF_F_TSO6;
 	netdev->vlan_features |= NETIF_F_IP_CSUM;
+	netdev->vlan_features |= NETIF_F_IPV6_CSUM;
 	netdev->vlan_features |= NETIF_F_SG;
 
 	if (pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
 
-#endif /* MAX_SKB_FRAGS */
-
 	/* The HW MAC address was set and/or determined in sw_init */
 	memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
 	memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index 3e6aaf9..949c1f9 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -82,11 +82,20 @@
 
 static int jazzsonic_open(struct net_device* dev)
 {
-	if (request_irq(dev->irq, sonic_interrupt, IRQF_DISABLED, "sonic", dev)) {
-		printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
-		return -EAGAIN;
+	int retval;
+
+	retval = request_irq(dev->irq, sonic_interrupt, IRQF_DISABLED,
+				"sonic", dev);
+	if (retval) {
+		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+				dev->name, dev->irq);
+		return retval;
 	}
-	return sonic_open(dev);
+
+	retval = sonic_open(dev);
+	if (retval)
+		free_irq(dev->irq, dev);
+	return retval;
 }
 
 static int jazzsonic_close(struct net_device* dev)
diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c
index f852ab3..928b2b8 100644
--- a/drivers/net/ks8842.c
+++ b/drivers/net/ks8842.c
@@ -18,6 +18,7 @@
 
 /* Supports:
  * The Micrel KS8842 behind the timberdale FPGA
+ * The genuine Micrel KS8841/42 device with ISA 16/32bit bus interface
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -29,11 +30,19 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/ks8842.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
 
 #define DRV_NAME "ks8842"
 
 /* Timberdale specific Registers */
-#define REG_TIMB_RST	0x1c
+#define REG_TIMB_RST		0x1c
+#define REG_TIMB_FIFO		0x20
+#define REG_TIMB_ISR		0x24
+#define REG_TIMB_IER		0x28
+#define REG_TIMB_IAR		0x2C
+#define REQ_TIMB_DMA_RESUME	0x30
 
 /* KS8842 registers */
 
@@ -76,6 +85,15 @@
 #define IRQ_RX_ERROR	0x0080
 #define ENABLED_IRQS	(IRQ_LINK_CHANGE | IRQ_TX | IRQ_RX | IRQ_RX_STOPPED | \
 		IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR)
+/* When running via timberdale in DMA mode, the RX interrupt should be
+   enabled in the KS8842, but not in the FPGA IP, since the IP handles
+   RX DMA internally.
+   TX interrupts are not needed it is handled by the FPGA the driver is
+   notified via DMA callbacks.
+*/
+#define ENABLED_IRQS_DMA_IP	(IRQ_LINK_CHANGE | IRQ_RX_STOPPED | \
+	IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR)
+#define ENABLED_IRQS_DMA	(ENABLED_IRQS_DMA_IP | IRQ_RX)
 #define REG_ISR		0x02
 #define REG_RXSR	0x04
 #define RXSR_VALID	0x8000
@@ -114,14 +132,53 @@
 #define REG_P1CR4		0x02
 #define REG_P1SR		0x04
 
+/* flags passed by platform_device for configuration */
+#define	MICREL_KS884X		0x01	/* 0=Timeberdale(FPGA), 1=Micrel */
+#define	KS884X_16BIT		0x02	/*  1=16bit, 0=32bit */
+
+#define DMA_BUFFER_SIZE		2048
+
+struct ks8842_tx_dma_ctl {
+	struct dma_chan *chan;
+	struct dma_async_tx_descriptor *adesc;
+	void *buf;
+	struct scatterlist sg;
+	int channel;
+};
+
+struct ks8842_rx_dma_ctl {
+	struct dma_chan *chan;
+	struct dma_async_tx_descriptor *adesc;
+	struct sk_buff  *skb;
+	struct scatterlist sg;
+	struct tasklet_struct tasklet;
+	int channel;
+};
+
+#define KS8842_USE_DMA(adapter) (((adapter)->dma_tx.channel != -1) && \
+	 ((adapter)->dma_rx.channel != -1))
+
 struct ks8842_adapter {
 	void __iomem	*hw_addr;
 	int		irq;
+	unsigned long	conf_flags;	/* copy of platform_device config */
 	struct tasklet_struct	tasklet;
 	spinlock_t	lock; /* spinlock to be interrupt safe */
-	struct platform_device *pdev;
+	struct work_struct timeout_work;
+	struct net_device *netdev;
+	struct device *dev;
+	struct ks8842_tx_dma_ctl	dma_tx;
+	struct ks8842_rx_dma_ctl	dma_rx;
 };
 
+static void ks8842_dma_rx_cb(void *data);
+static void ks8842_dma_tx_cb(void *data);
+
+static inline void ks8842_resume_dma(struct ks8842_adapter *adapter)
+{
+	iowrite32(1, adapter->hw_addr + REQ_TIMB_DMA_RESUME);
+}
+
 static inline void ks8842_select_bank(struct ks8842_adapter *adapter, u16 bank)
 {
 	iowrite16(bank, adapter->hw_addr + REG_SELECT_BANK);
@@ -191,16 +248,21 @@
 
 static void ks8842_reset(struct ks8842_adapter *adapter)
 {
-	/* The KS8842 goes haywire when doing softare reset
-	 * a work around in the timberdale IP is implemented to
-	 * do a hardware reset instead
-	ks8842_write16(adapter, 3, 1, REG_GRR);
-	msleep(10);
-	iowrite16(0, adapter->hw_addr + REG_GRR);
-	*/
-	iowrite16(32, adapter->hw_addr + REG_SELECT_BANK);
-	iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST);
-	msleep(20);
+	if (adapter->conf_flags & MICREL_KS884X) {
+		ks8842_write16(adapter, 3, 1, REG_GRR);
+		msleep(10);
+		iowrite16(0, adapter->hw_addr + REG_GRR);
+	} else {
+		/* The KS8842 goes haywire when doing softare reset
+		* a work around in the timberdale IP is implemented to
+		* do a hardware reset instead
+		ks8842_write16(adapter, 3, 1, REG_GRR);
+		msleep(10);
+		iowrite16(0, adapter->hw_addr + REG_GRR);
+		*/
+		iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST);
+		msleep(20);
+	}
 }
 
 static void ks8842_update_link_status(struct net_device *netdev,
@@ -269,8 +331,6 @@
 
 	/* restart port auto-negotiation */
 	ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4);
-	/* only advertise 10Mbps */
-	ks8842_clear_bits(adapter, 49, 3 << 2, REG_P1CR4);
 
 	/* Enable the transmitter */
 	ks8842_enable_tx(adapter);
@@ -282,8 +342,19 @@
 	ks8842_write16(adapter, 18, 0xffff, REG_ISR);
 
 	/* enable interrupts */
-	ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
-
+	if (KS8842_USE_DMA(adapter)) {
+		/* When running in DMA Mode the RX interrupt is not enabled in
+		   timberdale because RX data is received by DMA callbacks
+		   it must still be enabled in the KS8842 because it indicates
+		   to timberdale when there is RX data for it's DMA FIFOs */
+		iowrite16(ENABLED_IRQS_DMA_IP, adapter->hw_addr + REG_TIMB_IER);
+		ks8842_write16(adapter, 18, ENABLED_IRQS_DMA, REG_IER);
+	} else {
+		if (!(adapter->conf_flags & MICREL_KS884X))
+			iowrite16(ENABLED_IRQS,
+				adapter->hw_addr + REG_TIMB_IER);
+		ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
+	}
 	/* enable the switch */
 	ks8842_write16(adapter, 32, 0x1, REG_SW_ID_AND_ENABLE);
 }
@@ -296,13 +367,28 @@
 	for (i = 0; i < ETH_ALEN; i++)
 		dest[ETH_ALEN - i - 1] = ks8842_read8(adapter, 2, REG_MARL + i);
 
-	/* make sure the switch port uses the same MAC as the QMU */
-	mac = ks8842_read16(adapter, 2, REG_MARL);
-	ks8842_write16(adapter, 39, mac, REG_MACAR1);
-	mac = ks8842_read16(adapter, 2, REG_MARM);
-	ks8842_write16(adapter, 39, mac, REG_MACAR2);
-	mac = ks8842_read16(adapter, 2, REG_MARH);
-	ks8842_write16(adapter, 39, mac, REG_MACAR3);
+	if (adapter->conf_flags & MICREL_KS884X) {
+		/*
+		the sequence of saving mac addr between MAC and Switch is
+		different.
+		*/
+
+		mac = ks8842_read16(adapter, 2, REG_MARL);
+		ks8842_write16(adapter, 39, mac, REG_MACAR3);
+		mac = ks8842_read16(adapter, 2, REG_MARM);
+		ks8842_write16(adapter, 39, mac, REG_MACAR2);
+		mac = ks8842_read16(adapter, 2, REG_MARH);
+		ks8842_write16(adapter, 39, mac, REG_MACAR1);
+	} else {
+
+		/* make sure the switch port uses the same MAC as the QMU */
+		mac = ks8842_read16(adapter, 2, REG_MARL);
+		ks8842_write16(adapter, 39, mac, REG_MACAR1);
+		mac = ks8842_read16(adapter, 2, REG_MARM);
+		ks8842_write16(adapter, 39, mac, REG_MACAR2);
+		mac = ks8842_read16(adapter, 2, REG_MARH);
+		ks8842_write16(adapter, 39, mac, REG_MACAR3);
+	}
 }
 
 static void ks8842_write_mac_addr(struct ks8842_adapter *adapter, u8 *mac)
@@ -313,8 +399,25 @@
 	spin_lock_irqsave(&adapter->lock, flags);
 	for (i = 0; i < ETH_ALEN; i++) {
 		ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i);
-		ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1],
-			REG_MACAR1 + i);
+		if (!(adapter->conf_flags & MICREL_KS884X))
+			ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1],
+				REG_MACAR1 + i);
+	}
+
+	if (adapter->conf_flags & MICREL_KS884X) {
+		/*
+		the sequence of saving mac addr between MAC and Switch is
+		different.
+		*/
+
+		u16 mac;
+
+		mac = ks8842_read16(adapter, 2, REG_MARL);
+		ks8842_write16(adapter, 39, mac, REG_MACAR3);
+		mac = ks8842_read16(adapter, 2, REG_MARM);
+		ks8842_write16(adapter, 39, mac, REG_MACAR2);
+		mac = ks8842_read16(adapter, 2, REG_MARH);
+		ks8842_write16(adapter, 39, mac, REG_MACAR1);
 	}
 	spin_unlock_irqrestore(&adapter->lock, flags);
 }
@@ -324,15 +427,59 @@
 	return ks8842_read16(adapter, 16, REG_TXMIR) & 0x1fff;
 }
 
+static int ks8842_tx_frame_dma(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct ks8842_adapter *adapter = netdev_priv(netdev);
+	struct ks8842_tx_dma_ctl *ctl = &adapter->dma_tx;
+	u8 *buf = ctl->buf;
+
+	if (ctl->adesc) {
+		netdev_dbg(netdev, "%s: TX ongoing\n", __func__);
+		/* transfer ongoing */
+		return NETDEV_TX_BUSY;
+	}
+
+	sg_dma_len(&ctl->sg) = skb->len + sizeof(u32);
+
+	/* copy data to the TX buffer */
+	/* the control word, enable IRQ, port 1 and the length */
+	*buf++ = 0x00;
+	*buf++ = 0x01; /* Port 1 */
+	*buf++ = skb->len & 0xff;
+	*buf++ = (skb->len >> 8) & 0xff;
+	skb_copy_from_linear_data(skb, buf, skb->len);
+
+	dma_sync_single_range_for_device(adapter->dev,
+		sg_dma_address(&ctl->sg), 0, sg_dma_len(&ctl->sg),
+		DMA_TO_DEVICE);
+
+	/* make sure the length is a multiple of 4 */
+	if (sg_dma_len(&ctl->sg) % 4)
+		sg_dma_len(&ctl->sg) += 4 - sg_dma_len(&ctl->sg) % 4;
+
+	ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan,
+		&ctl->sg, 1, DMA_TO_DEVICE,
+		DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
+	if (!ctl->adesc)
+		return NETDEV_TX_BUSY;
+
+	ctl->adesc->callback_param = netdev;
+	ctl->adesc->callback = ks8842_dma_tx_cb;
+	ctl->adesc->tx_submit(ctl->adesc);
+
+	netdev->stats.tx_bytes += skb->len;
+
+	dev_kfree_skb(skb);
+
+	return NETDEV_TX_OK;
+}
+
 static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct ks8842_adapter *adapter = netdev_priv(netdev);
 	int len = skb->len;
-	u32 *ptr = (u32 *)skb->data;
-	u32 ctrl;
 
-	dev_dbg(&adapter->pdev->dev,
-		"%s: len %u head %p data %p tail %p end %p\n",
+	netdev_dbg(netdev, "%s: len %u head %p data %p tail %p end %p\n",
 		__func__, skb->len, skb->head, skb->data,
 		skb_tail_pointer(skb), skb_end_pointer(skb));
 
@@ -340,17 +487,34 @@
 	if (ks8842_tx_fifo_space(adapter) < len + 8)
 		return NETDEV_TX_BUSY;
 
-	/* the control word, enable IRQ, port 1 and the length */
-	ctrl = 0x8000 | 0x100 | (len << 16);
-	ks8842_write32(adapter, 17, ctrl, REG_QMU_DATA_LO);
+	if (adapter->conf_flags & KS884X_16BIT) {
+		u16 *ptr16 = (u16 *)skb->data;
+		ks8842_write16(adapter, 17, 0x8000 | 0x100, REG_QMU_DATA_LO);
+		ks8842_write16(adapter, 17, (u16)len, REG_QMU_DATA_HI);
+		netdev->stats.tx_bytes += len;
 
-	netdev->stats.tx_bytes += len;
+		/* copy buffer */
+		while (len > 0) {
+			iowrite16(*ptr16++, adapter->hw_addr + REG_QMU_DATA_LO);
+			iowrite16(*ptr16++, adapter->hw_addr + REG_QMU_DATA_HI);
+			len -= sizeof(u32);
+		}
+	} else {
 
-	/* copy buffer */
-	while (len > 0) {
-		iowrite32(*ptr, adapter->hw_addr + REG_QMU_DATA_LO);
-		len -= sizeof(u32);
-		ptr++;
+		u32 *ptr = (u32 *)skb->data;
+		u32 ctrl;
+		/* the control word, enable IRQ, port 1 and the length */
+		ctrl = 0x8000 | 0x100 | (len << 16);
+		ks8842_write32(adapter, 17, ctrl, REG_QMU_DATA_LO);
+
+		netdev->stats.tx_bytes += len;
+
+		/* copy buffer */
+		while (len > 0) {
+			iowrite32(*ptr, adapter->hw_addr + REG_QMU_DATA_LO);
+			len -= sizeof(u32);
+			ptr++;
+		}
 	}
 
 	/* enqueue packet */
@@ -361,54 +525,174 @@
 	return NETDEV_TX_OK;
 }
 
+static void ks8842_update_rx_err_counters(struct net_device *netdev, u32 status)
+{
+	netdev_dbg(netdev, "RX error, status: %x\n", status);
+
+	netdev->stats.rx_errors++;
+	if (status & RXSR_TOO_LONG)
+		netdev->stats.rx_length_errors++;
+	if (status & RXSR_CRC_ERROR)
+		netdev->stats.rx_crc_errors++;
+	if (status & RXSR_RUNT)
+		netdev->stats.rx_frame_errors++;
+}
+
+static void ks8842_update_rx_counters(struct net_device *netdev, u32 status,
+	int len)
+{
+	netdev_dbg(netdev, "RX packet, len: %d\n", len);
+
+	netdev->stats.rx_packets++;
+	netdev->stats.rx_bytes += len;
+	if (status & RXSR_MULTICAST)
+		netdev->stats.multicast++;
+}
+
+static int __ks8842_start_new_rx_dma(struct net_device *netdev)
+{
+	struct ks8842_adapter *adapter = netdev_priv(netdev);
+	struct ks8842_rx_dma_ctl *ctl = &adapter->dma_rx;
+	struct scatterlist *sg = &ctl->sg;
+	int err;
+
+	ctl->skb = netdev_alloc_skb(netdev, DMA_BUFFER_SIZE);
+	if (ctl->skb) {
+		sg_init_table(sg, 1);
+		sg_dma_address(sg) = dma_map_single(adapter->dev,
+			ctl->skb->data, DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+		err = dma_mapping_error(adapter->dev, sg_dma_address(sg));
+		if (unlikely(err)) {
+			sg_dma_address(sg) = 0;
+			goto out;
+		}
+
+		sg_dma_len(sg) = DMA_BUFFER_SIZE;
+
+		ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan,
+			sg, 1, DMA_FROM_DEVICE,
+			DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
+
+		if (!ctl->adesc)
+			goto out;
+
+		ctl->adesc->callback_param = netdev;
+		ctl->adesc->callback = ks8842_dma_rx_cb;
+		ctl->adesc->tx_submit(ctl->adesc);
+	} else {
+		err = -ENOMEM;
+		sg_dma_address(sg) = 0;
+		goto out;
+	}
+
+	return err;
+out:
+	if (sg_dma_address(sg))
+		dma_unmap_single(adapter->dev, sg_dma_address(sg),
+			DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+	sg_dma_address(sg) = 0;
+	if (ctl->skb)
+		dev_kfree_skb(ctl->skb);
+
+	ctl->skb = NULL;
+
+	printk(KERN_ERR DRV_NAME": Failed to start RX DMA: %d\n", err);
+	return err;
+}
+
+static void ks8842_rx_frame_dma_tasklet(unsigned long arg)
+{
+	struct net_device *netdev = (struct net_device *)arg;
+	struct ks8842_adapter *adapter = netdev_priv(netdev);
+	struct ks8842_rx_dma_ctl *ctl = &adapter->dma_rx;
+	struct sk_buff *skb = ctl->skb;
+	dma_addr_t addr = sg_dma_address(&ctl->sg);
+	u32 status;
+
+	ctl->adesc = NULL;
+
+	/* kick next transfer going */
+	__ks8842_start_new_rx_dma(netdev);
+
+	/* now handle the data we got */
+	dma_unmap_single(adapter->dev, addr, DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+	status = *((u32 *)skb->data);
+
+	netdev_dbg(netdev, "%s - rx_data: status: %x\n",
+		__func__, status & 0xffff);
+
+	/* check the status */
+	if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
+		int len = (status >> 16) & 0x7ff;
+
+		ks8842_update_rx_counters(netdev, status, len);
+
+		/* reserve 4 bytes which is the status word */
+		skb_reserve(skb, 4);
+		skb_put(skb, len);
+
+		skb->protocol = eth_type_trans(skb, netdev);
+		netif_rx(skb);
+	} else {
+		ks8842_update_rx_err_counters(netdev, status);
+		dev_kfree_skb(skb);
+	}
+}
+
 static void ks8842_rx_frame(struct net_device *netdev,
 	struct ks8842_adapter *adapter)
 {
-	u32 status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO);
-	int len = (status >> 16) & 0x7ff;
+	u32 status;
+	int len;
 
-	status &= 0xffff;
-
-	dev_dbg(&adapter->pdev->dev, "%s - rx_data: status: %x\n",
-		__func__, status);
+	if (adapter->conf_flags & KS884X_16BIT) {
+		status = ks8842_read16(adapter, 17, REG_QMU_DATA_LO);
+		len = ks8842_read16(adapter, 17, REG_QMU_DATA_HI);
+		netdev_dbg(netdev, "%s - rx_data: status: %x\n",
+			   __func__, status);
+	} else {
+		status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO);
+		len = (status >> 16) & 0x7ff;
+		status &= 0xffff;
+		netdev_dbg(netdev, "%s - rx_data: status: %x\n",
+			   __func__, status);
+	}
 
 	/* check the status */
 	if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
 		struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len);
 
-		dev_dbg(&adapter->pdev->dev, "%s, got package, len: %d\n",
-			__func__, len);
 		if (skb) {
-			u32 *data;
 
-			netdev->stats.rx_packets++;
-			netdev->stats.rx_bytes += len;
-			if (status & RXSR_MULTICAST)
-				netdev->stats.multicast++;
+			ks8842_update_rx_counters(netdev, status, len);
 
-			data = (u32 *)skb_put(skb, len);
+			if (adapter->conf_flags & KS884X_16BIT) {
+				u16 *data16 = (u16 *)skb_put(skb, len);
+				ks8842_select_bank(adapter, 17);
+				while (len > 0) {
+					*data16++ = ioread16(adapter->hw_addr +
+						REG_QMU_DATA_LO);
+					*data16++ = ioread16(adapter->hw_addr +
+						REG_QMU_DATA_HI);
+					len -= sizeof(u32);
+				}
+			} else {
+				u32 *data = (u32 *)skb_put(skb, len);
 
-			ks8842_select_bank(adapter, 17);
-			while (len > 0) {
-				*data++ = ioread32(adapter->hw_addr +
-					REG_QMU_DATA_LO);
-				len -= sizeof(u32);
+				ks8842_select_bank(adapter, 17);
+				while (len > 0) {
+					*data++ = ioread32(adapter->hw_addr +
+						REG_QMU_DATA_LO);
+					len -= sizeof(u32);
+				}
 			}
-
 			skb->protocol = eth_type_trans(skb, netdev);
 			netif_rx(skb);
 		} else
 			netdev->stats.rx_dropped++;
-	} else {
-		dev_dbg(&adapter->pdev->dev, "RX error, status: %x\n", status);
-		netdev->stats.rx_errors++;
-		if (status & RXSR_TOO_LONG)
-			netdev->stats.rx_length_errors++;
-		if (status & RXSR_CRC_ERROR)
-			netdev->stats.rx_crc_errors++;
-		if (status & RXSR_RUNT)
-			netdev->stats.rx_frame_errors++;
-	}
+	} else
+		ks8842_update_rx_err_counters(netdev, status);
 
 	/* set high watermark to 3K */
 	ks8842_clear_bits(adapter, 0, 1 << 12, REG_QRFCR);
@@ -423,8 +707,7 @@
 void ks8842_handle_rx(struct net_device *netdev, struct ks8842_adapter *adapter)
 {
 	u16 rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff;
-	dev_dbg(&adapter->pdev->dev, "%s Entry - rx_data: %d\n",
-		__func__, rx_data);
+	netdev_dbg(netdev, "%s Entry - rx_data: %d\n", __func__, rx_data);
 	while (rx_data) {
 		ks8842_rx_frame(netdev, adapter);
 		rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff;
@@ -434,7 +717,7 @@
 void ks8842_handle_tx(struct net_device *netdev, struct ks8842_adapter *adapter)
 {
 	u16 sr = ks8842_read16(adapter, 16, REG_TXSR);
-	dev_dbg(&adapter->pdev->dev, "%s - entry, sr: %x\n", __func__, sr);
+	netdev_dbg(netdev, "%s - entry, sr: %x\n", __func__, sr);
 	netdev->stats.tx_packets++;
 	if (netif_queue_stopped(netdev))
 		netif_wake_queue(netdev);
@@ -443,7 +726,7 @@
 void ks8842_handle_rx_overrun(struct net_device *netdev,
 	struct ks8842_adapter *adapter)
 {
-	dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__);
+	netdev_dbg(netdev, "%s: entry\n", __func__);
 	netdev->stats.rx_errors++;
 	netdev->stats.rx_fifo_errors++;
 }
@@ -462,20 +745,32 @@
 	spin_unlock_irqrestore(&adapter->lock, flags);
 
 	isr = ks8842_read16(adapter, 18, REG_ISR);
-	dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr);
+	netdev_dbg(netdev, "%s - ISR: 0x%x\n", __func__, isr);
+
+	/* when running in DMA mode, do not ack RX interrupts, it is handled
+	   internally by timberdale, otherwise it's DMA FIFO:s would stop
+	*/
+	if (KS8842_USE_DMA(adapter))
+		isr &= ~IRQ_RX;
 
 	/* Ack */
 	ks8842_write16(adapter, 18, isr, REG_ISR);
 
+	if (!(adapter->conf_flags & MICREL_KS884X))
+		/* Ack in the timberdale IP as well */
+		iowrite32(0x1, adapter->hw_addr + REG_TIMB_IAR);
+
 	if (!netif_running(netdev))
 		return;
 
 	if (isr & IRQ_LINK_CHANGE)
 		ks8842_update_link_status(netdev, adapter);
 
-	if (isr & (IRQ_RX | IRQ_RX_ERROR))
+	/* should not get IRQ_RX when running DMA mode */
+	if (isr & (IRQ_RX | IRQ_RX_ERROR) && !KS8842_USE_DMA(adapter))
 		ks8842_handle_rx(netdev, adapter);
 
+	/* should only happen when in PIO mode */
 	if (isr & IRQ_TX)
 		ks8842_handle_tx(netdev, adapter);
 
@@ -494,24 +789,38 @@
 
 	/* re-enable interrupts, put back the bank selection register */
 	spin_lock_irqsave(&adapter->lock, flags);
-	ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
+	if (KS8842_USE_DMA(adapter))
+		ks8842_write16(adapter, 18, ENABLED_IRQS_DMA, REG_IER);
+	else
+		ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
 	iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK);
+
+	/* Make sure timberdale continues DMA operations, they are stopped while
+	   we are handling the ks8842 because we might change bank */
+	if (KS8842_USE_DMA(adapter))
+		ks8842_resume_dma(adapter);
+
 	spin_unlock_irqrestore(&adapter->lock, flags);
 }
 
 static irqreturn_t ks8842_irq(int irq, void *devid)
 {
-	struct ks8842_adapter *adapter = devid;
+	struct net_device *netdev = devid;
+	struct ks8842_adapter *adapter = netdev_priv(netdev);
 	u16 isr;
 	u16 entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK);
 	irqreturn_t ret = IRQ_NONE;
 
 	isr = ks8842_read16(adapter, 18, REG_ISR);
-	dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr);
+	netdev_dbg(netdev, "%s - ISR: 0x%x\n", __func__, isr);
 
 	if (isr) {
-		/* disable IRQ */
-		ks8842_write16(adapter, 18, 0x00, REG_IER);
+		if (KS8842_USE_DMA(adapter))
+			/* disable all but RX IRQ, since the FPGA relies on it*/
+			ks8842_write16(adapter, 18, IRQ_RX, REG_IER);
+		else
+			/* disable IRQ */
+			ks8842_write16(adapter, 18, 0x00, REG_IER);
 
 		/* schedule tasklet */
 		tasklet_schedule(&adapter->tasklet);
@@ -521,9 +830,151 @@
 
 	iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK);
 
+	/* After an interrupt, tell timberdale to continue DMA operations.
+	   DMA is disabled while we are handling the ks8842 because we might
+	   change bank */
+	ks8842_resume_dma(adapter);
+
 	return ret;
 }
 
+static void ks8842_dma_rx_cb(void *data)
+{
+	struct net_device	*netdev = data;
+	struct ks8842_adapter	*adapter = netdev_priv(netdev);
+
+	netdev_dbg(netdev, "RX DMA finished\n");
+	/* schedule tasklet */
+	if (adapter->dma_rx.adesc)
+		tasklet_schedule(&adapter->dma_rx.tasklet);
+}
+
+static void ks8842_dma_tx_cb(void *data)
+{
+	struct net_device		*netdev = data;
+	struct ks8842_adapter		*adapter = netdev_priv(netdev);
+	struct ks8842_tx_dma_ctl	*ctl = &adapter->dma_tx;
+
+	netdev_dbg(netdev, "TX DMA finished\n");
+
+	if (!ctl->adesc)
+		return;
+
+	netdev->stats.tx_packets++;
+	ctl->adesc = NULL;
+
+	if (netif_queue_stopped(netdev))
+		netif_wake_queue(netdev);
+}
+
+static void ks8842_stop_dma(struct ks8842_adapter *adapter)
+{
+	struct ks8842_tx_dma_ctl *tx_ctl = &adapter->dma_tx;
+	struct ks8842_rx_dma_ctl *rx_ctl = &adapter->dma_rx;
+
+	tx_ctl->adesc = NULL;
+	if (tx_ctl->chan)
+		tx_ctl->chan->device->device_control(tx_ctl->chan,
+			DMA_TERMINATE_ALL, 0);
+
+	rx_ctl->adesc = NULL;
+	if (rx_ctl->chan)
+		rx_ctl->chan->device->device_control(rx_ctl->chan,
+			DMA_TERMINATE_ALL, 0);
+
+	if (sg_dma_address(&rx_ctl->sg))
+		dma_unmap_single(adapter->dev, sg_dma_address(&rx_ctl->sg),
+			DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+	sg_dma_address(&rx_ctl->sg) = 0;
+
+	dev_kfree_skb(rx_ctl->skb);
+	rx_ctl->skb = NULL;
+}
+
+static void ks8842_dealloc_dma_bufs(struct ks8842_adapter *adapter)
+{
+	struct ks8842_tx_dma_ctl *tx_ctl = &adapter->dma_tx;
+	struct ks8842_rx_dma_ctl *rx_ctl = &adapter->dma_rx;
+
+	ks8842_stop_dma(adapter);
+
+	if (tx_ctl->chan)
+		dma_release_channel(tx_ctl->chan);
+	tx_ctl->chan = NULL;
+
+	if (rx_ctl->chan)
+		dma_release_channel(rx_ctl->chan);
+	rx_ctl->chan = NULL;
+
+	tasklet_kill(&rx_ctl->tasklet);
+
+	if (sg_dma_address(&tx_ctl->sg))
+		dma_unmap_single(adapter->dev, sg_dma_address(&tx_ctl->sg),
+			DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+	sg_dma_address(&tx_ctl->sg) = 0;
+
+	kfree(tx_ctl->buf);
+	tx_ctl->buf = NULL;
+}
+
+static bool ks8842_dma_filter_fn(struct dma_chan *chan, void *filter_param)
+{
+	return chan->chan_id == (long)filter_param;
+}
+
+static int ks8842_alloc_dma_bufs(struct net_device *netdev)
+{
+	struct ks8842_adapter *adapter = netdev_priv(netdev);
+	struct ks8842_tx_dma_ctl *tx_ctl = &adapter->dma_tx;
+	struct ks8842_rx_dma_ctl *rx_ctl = &adapter->dma_rx;
+	int err;
+
+	dma_cap_mask_t mask;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	dma_cap_set(DMA_PRIVATE, mask);
+
+	sg_init_table(&tx_ctl->sg, 1);
+
+	tx_ctl->chan = dma_request_channel(mask, ks8842_dma_filter_fn,
+					   (void *)(long)tx_ctl->channel);
+	if (!tx_ctl->chan) {
+		err = -ENODEV;
+		goto err;
+	}
+
+	/* allocate DMA buffer */
+	tx_ctl->buf = kmalloc(DMA_BUFFER_SIZE, GFP_KERNEL);
+	if (!tx_ctl->buf) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	sg_dma_address(&tx_ctl->sg) = dma_map_single(adapter->dev,
+		tx_ctl->buf, DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+	err = dma_mapping_error(adapter->dev,
+		sg_dma_address(&tx_ctl->sg));
+	if (err) {
+		sg_dma_address(&tx_ctl->sg) = 0;
+		goto err;
+	}
+
+	rx_ctl->chan = dma_request_channel(mask, ks8842_dma_filter_fn,
+					   (void *)(long)rx_ctl->channel);
+	if (!rx_ctl->chan) {
+		err = -ENODEV;
+		goto err;
+	}
+
+	tasklet_init(&rx_ctl->tasklet, ks8842_rx_frame_dma_tasklet,
+		(unsigned long)netdev);
+
+	return 0;
+err:
+	ks8842_dealloc_dma_bufs(adapter);
+	return err;
+}
 
 /* Netdevice operations */
 
@@ -532,7 +983,26 @@
 	struct ks8842_adapter *adapter = netdev_priv(netdev);
 	int err;
 
-	dev_dbg(&adapter->pdev->dev, "%s - entry\n", __func__);
+	netdev_dbg(netdev, "%s - entry\n", __func__);
+
+	if (KS8842_USE_DMA(adapter)) {
+		err = ks8842_alloc_dma_bufs(netdev);
+
+		if (!err) {
+			/* start RX dma */
+			err = __ks8842_start_new_rx_dma(netdev);
+			if (err)
+				ks8842_dealloc_dma_bufs(adapter);
+		}
+
+		if (err) {
+			printk(KERN_WARNING DRV_NAME
+				": Failed to initiate DMA, running PIO\n");
+			ks8842_dealloc_dma_bufs(adapter);
+			adapter->dma_rx.channel = -1;
+			adapter->dma_tx.channel = -1;
+		}
+	}
 
 	/* reset the HW */
 	ks8842_reset_hw(adapter);
@@ -542,7 +1012,7 @@
 	ks8842_update_link_status(netdev, adapter);
 
 	err = request_irq(adapter->irq, ks8842_irq, IRQF_SHARED, DRV_NAME,
-		adapter);
+		netdev);
 	if (err) {
 		pr_err("Failed to request IRQ: %d: %d\n", adapter->irq, err);
 		return err;
@@ -555,10 +1025,15 @@
 {
 	struct ks8842_adapter *adapter = netdev_priv(netdev);
 
-	dev_dbg(&adapter->pdev->dev, "%s - entry\n", __func__);
+	netdev_dbg(netdev, "%s - entry\n", __func__);
+
+	cancel_work_sync(&adapter->timeout_work);
+
+	if (KS8842_USE_DMA(adapter))
+		ks8842_dealloc_dma_bufs(adapter);
 
 	/* free the irq */
-	free_irq(adapter->irq, adapter);
+	free_irq(adapter->irq, netdev);
 
 	/* disable the switch */
 	ks8842_write16(adapter, 32, 0x0, REG_SW_ID_AND_ENABLE);
@@ -572,7 +1047,18 @@
 	int ret;
 	struct ks8842_adapter *adapter = netdev_priv(netdev);
 
-	dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__);
+	netdev_dbg(netdev, "%s: entry\n", __func__);
+
+	if (KS8842_USE_DMA(adapter)) {
+		unsigned long flags;
+		ret = ks8842_tx_frame_dma(skb, netdev);
+		/* for now only allow one transfer at the time */
+		spin_lock_irqsave(&adapter->lock, flags);
+		if (adapter->dma_tx.adesc)
+			netif_stop_queue(netdev);
+		spin_unlock_irqrestore(&adapter->lock, flags);
+		return ret;
+	}
 
 	ret = ks8842_tx_frame(skb, netdev);
 
@@ -588,7 +1074,7 @@
 	struct sockaddr *addr = p;
 	char *mac = (u8 *)addr->sa_data;
 
-	dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__);
+	netdev_dbg(netdev, "%s: entry\n", __func__);
 
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
@@ -599,17 +1085,26 @@
 	return 0;
 }
 
-static void ks8842_tx_timeout(struct net_device *netdev)
+static void ks8842_tx_timeout_work(struct work_struct *work)
 {
-	struct ks8842_adapter *adapter = netdev_priv(netdev);
+	struct ks8842_adapter *adapter =
+		container_of(work, struct ks8842_adapter, timeout_work);
+	struct net_device *netdev = adapter->netdev;
 	unsigned long flags;
 
-	dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__);
+	netdev_dbg(netdev, "%s: entry\n", __func__);
 
 	spin_lock_irqsave(&adapter->lock, flags);
+
+	if (KS8842_USE_DMA(adapter))
+		ks8842_stop_dma(adapter);
+
 	/* disable interrupts */
 	ks8842_write16(adapter, 18, 0, REG_IER);
 	ks8842_write16(adapter, 18, 0xFFFF, REG_ISR);
+
+	netif_stop_queue(netdev);
+
 	spin_unlock_irqrestore(&adapter->lock, flags);
 
 	ks8842_reset_hw(adapter);
@@ -617,6 +1112,18 @@
 	ks8842_write_mac_addr(adapter, netdev->dev_addr);
 
 	ks8842_update_link_status(netdev, adapter);
+
+	if (KS8842_USE_DMA(adapter))
+		__ks8842_start_new_rx_dma(netdev);
+}
+
+static void ks8842_tx_timeout(struct net_device *netdev)
+{
+	struct ks8842_adapter *adapter = netdev_priv(netdev);
+
+	netdev_dbg(netdev, "%s: entry\n", __func__);
+
+	schedule_work(&adapter->timeout_work);
 }
 
 static const struct net_device_ops ks8842_netdev_ops = {
@@ -653,7 +1160,11 @@
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
 	adapter = netdev_priv(netdev);
+	adapter->netdev = netdev;
+	INIT_WORK(&adapter->timeout_work, ks8842_tx_timeout_work);
 	adapter->hw_addr = ioremap(iomem->start, resource_size(iomem));
+	adapter->conf_flags = iomem->flags;
+
 	if (!adapter->hw_addr)
 		goto err_ioremap;
 
@@ -663,7 +1174,18 @@
 		goto err_get_irq;
 	}
 
-	adapter->pdev = pdev;
+	adapter->dev = (pdev->dev.parent) ? pdev->dev.parent : &pdev->dev;
+
+	/* DMA is only supported when accessed via timberdale */
+	if (!(adapter->conf_flags & MICREL_KS884X) && pdata &&
+		(pdata->tx_dma_channel != -1) &&
+		(pdata->rx_dma_channel != -1)) {
+		adapter->dma_rx.channel = pdata->rx_dma_channel;
+		adapter->dma_tx.channel = pdata->tx_dma_channel;
+	} else {
+		adapter->dma_rx.channel = -1;
+		adapter->dma_tx.channel = -1;
+	}
 
 	tasklet_init(&adapter->tasklet, ks8842_tasklet, (unsigned long)netdev);
 	spin_lock_init(&adapter->lock);
diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c
index aa50ee1..37504a3 100644
--- a/drivers/net/ksz884x.c
+++ b/drivers/net/ksz884x.c
@@ -1457,7 +1457,6 @@
  * @adapter:		Adapter device information.
  * @port:		Port information.
  * @monitor_time_info:	Timer to monitor ports.
- * @stats:		Network statistics.
  * @proc_sem:		Semaphore for proc accessing.
  * @id:			Device ID.
  * @mii_if:		MII interface information.
@@ -1471,7 +1470,6 @@
 	struct dev_info *adapter;
 	struct ksz_port port;
 	struct ksz_timer_info monitor_timer_info;
-	struct net_device_stats stats;
 
 	struct semaphore proc_sem;
 	int id;
@@ -4751,8 +4749,8 @@
 	hw_send_pkt(hw);
 
 	/* Update transmit statistics. */
-	priv->stats.tx_packets++;
-	priv->stats.tx_bytes += len;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += len;
 }
 
 /**
@@ -5030,7 +5028,7 @@
 		/* skb->data != skb->head */
 		skb = dev_alloc_skb(packet_len + 2);
 		if (!skb) {
-			priv->stats.rx_dropped++;
+			dev->stats.rx_dropped++;
 			return -ENOMEM;
 		}
 
@@ -5050,8 +5048,8 @@
 		csum_verified(skb);
 
 	/* Update receive statistics. */
-	priv->stats.rx_packets++;
-	priv->stats.rx_bytes += packet_len;
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += packet_len;
 
 	/* Notify upper layer for received packet. */
 	rx_status = netif_rx(skb);
@@ -5291,7 +5289,7 @@
 		}
 
 		if (unlikely(int_enable & KS884X_INT_RX_OVERRUN)) {
-			priv->stats.rx_fifo_errors++;
+			dev->stats.rx_fifo_errors++;
 			hw_resume_rx(hw);
 		}
 
@@ -5522,7 +5520,7 @@
 	priv->promiscuous = 0;
 
 	/* Reset device statistics. */
-	memset(&priv->stats, 0, sizeof(struct net_device_stats));
+	memset(&dev->stats, 0, sizeof(struct net_device_stats));
 	memset((void *) port->counter, 0,
 		(sizeof(u64) * OID_COUNTER_LAST));
 
@@ -5622,42 +5620,42 @@
 	int i;
 	int p;
 
-	priv->stats.rx_errors = port->counter[OID_COUNTER_RCV_ERROR];
-	priv->stats.tx_errors = port->counter[OID_COUNTER_XMIT_ERROR];
+	dev->stats.rx_errors = port->counter[OID_COUNTER_RCV_ERROR];
+	dev->stats.tx_errors = port->counter[OID_COUNTER_XMIT_ERROR];
 
 	/* Reset to zero to add count later. */
-	priv->stats.multicast = 0;
-	priv->stats.collisions = 0;
-	priv->stats.rx_length_errors = 0;
-	priv->stats.rx_crc_errors = 0;
-	priv->stats.rx_frame_errors = 0;
-	priv->stats.tx_window_errors = 0;
+	dev->stats.multicast = 0;
+	dev->stats.collisions = 0;
+	dev->stats.rx_length_errors = 0;
+	dev->stats.rx_crc_errors = 0;
+	dev->stats.rx_frame_errors = 0;
+	dev->stats.tx_window_errors = 0;
 
 	for (i = 0, p = port->first_port; i < port->mib_port_cnt; i++, p++) {
 		mib = &hw->port_mib[p];
 
-		priv->stats.multicast += (unsigned long)
+		dev->stats.multicast += (unsigned long)
 			mib->counter[MIB_COUNTER_RX_MULTICAST];
 
-		priv->stats.collisions += (unsigned long)
+		dev->stats.collisions += (unsigned long)
 			mib->counter[MIB_COUNTER_TX_TOTAL_COLLISION];
 
-		priv->stats.rx_length_errors += (unsigned long)(
+		dev->stats.rx_length_errors += (unsigned long)(
 			mib->counter[MIB_COUNTER_RX_UNDERSIZE] +
 			mib->counter[MIB_COUNTER_RX_FRAGMENT] +
 			mib->counter[MIB_COUNTER_RX_OVERSIZE] +
 			mib->counter[MIB_COUNTER_RX_JABBER]);
-		priv->stats.rx_crc_errors += (unsigned long)
+		dev->stats.rx_crc_errors += (unsigned long)
 			mib->counter[MIB_COUNTER_RX_CRC_ERR];
-		priv->stats.rx_frame_errors += (unsigned long)(
+		dev->stats.rx_frame_errors += (unsigned long)(
 			mib->counter[MIB_COUNTER_RX_ALIGNMENT_ERR] +
 			mib->counter[MIB_COUNTER_RX_SYMBOL_ERR]);
 
-		priv->stats.tx_window_errors += (unsigned long)
+		dev->stats.tx_window_errors += (unsigned long)
 			mib->counter[MIB_COUNTER_TX_LATE_COLLISION];
 	}
 
-	return &priv->stats;
+	return &dev->stats;
 }
 
 /**
@@ -5718,7 +5716,7 @@
 		 * from the bridge.
 		 */
 		if ((hw->features & STP_SUPPORT) && !promiscuous &&
-				dev->br_port) {
+		    (dev->priv_flags & IFF_BRIDGE_PORT)) {
 			struct ksz_switch *sw = hw->ksz_switch;
 			int port = priv->port.first_port;
 
@@ -6896,13 +6894,12 @@
 	i = j = num = got_num = 0;
 	while (j < MAC_ADDR_LEN) {
 		if (macaddr[i]) {
+			int digit;
+
 			got_num = 1;
-			if ('0' <= macaddr[i] && macaddr[i] <= '9')
-				num = num * 16 + macaddr[i] - '0';
-			else if ('A' <= macaddr[i] && macaddr[i] <= 'F')
-				num = num * 16 + 10 + macaddr[i] - 'A';
-			else if ('a' <= macaddr[i] && macaddr[i] <= 'f')
-				num = num * 16 + 10 + macaddr[i] - 'a';
+			digit = hex_to_bin(macaddr[i]);
+			if (digit >= 0)
+				num = num * 16 + digit;
 			else if (':' == macaddr[i])
 				got_num = 2;
 			else
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 21f8ada..f06296b 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -248,7 +248,6 @@
 	int cur_rx, cur_tx;			/* The next free ring entry */
 	int dirty_rx, dirty_tx;		/* The ring entries to be free()ed. */
 	int dma;
-	struct net_device_stats stats;
 	unsigned char chip_version;	/* See lance_chip_type. */
 	spinlock_t devlock;
 };
@@ -925,7 +924,7 @@
 	printk ("%s: transmit timed out, status %4.4x, resetting.\n",
 		dev->name, inw (ioaddr + LANCE_DATA));
 	outw (0x0004, ioaddr + LANCE_DATA);
-	lp->stats.tx_errors++;
+	dev->stats.tx_errors++;
 #ifndef final_version
 	if (lance_debug > 3) {
 		int i;
@@ -989,7 +988,7 @@
 
 	lp->tx_ring[entry].misc = 0x0000;
 
-	lp->stats.tx_bytes += skb->len;
+	dev->stats.tx_bytes += skb->len;
 
 	/* If any part of this buffer is >16M we must copy it to a low-memory
 	   buffer. */
@@ -1062,13 +1061,16 @@
 				if (status & 0x40000000) {
 					/* There was an major error, log it. */
 					int err_status = lp->tx_ring[entry].misc;
-					lp->stats.tx_errors++;
-					if (err_status & 0x0400) lp->stats.tx_aborted_errors++;
-					if (err_status & 0x0800) lp->stats.tx_carrier_errors++;
-					if (err_status & 0x1000) lp->stats.tx_window_errors++;
+					dev->stats.tx_errors++;
+					if (err_status & 0x0400)
+						dev->stats.tx_aborted_errors++;
+					if (err_status & 0x0800)
+						dev->stats.tx_carrier_errors++;
+					if (err_status & 0x1000)
+						dev->stats.tx_window_errors++;
 					if (err_status & 0x4000) {
 						/* Ackk!  On FIFO errors the Tx unit is turned off! */
-						lp->stats.tx_fifo_errors++;
+						dev->stats.tx_fifo_errors++;
 						/* Remove this verbosity later! */
 						printk("%s: Tx FIFO error! Status %4.4x.\n",
 							   dev->name, csr0);
@@ -1077,8 +1079,8 @@
 					}
 				} else {
 					if (status & 0x18000000)
-						lp->stats.collisions++;
-					lp->stats.tx_packets++;
+						dev->stats.collisions++;
+					dev->stats.tx_packets++;
 				}
 
 				/* We must free the original skb if it's not a data-only copy
@@ -1108,8 +1110,10 @@
 		}
 
 		/* Log misc errors. */
-		if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */
-		if (csr0 & 0x1000) lp->stats.rx_errors++; /* Missed a Rx frame. */
+		if (csr0 & 0x4000)
+			dev->stats.tx_errors++; /* Tx babble. */
+		if (csr0 & 0x1000)
+			dev->stats.rx_errors++; /* Missed a Rx frame. */
 		if (csr0 & 0x0800) {
 			printk("%s: Bus master arbitration failure, status %4.4x.\n",
 				   dev->name, csr0);
@@ -1155,11 +1159,15 @@
 			   buffers it's possible for a jabber packet to use two
 			   buffers, with only the last correctly noting the error. */
 			if (status & 0x01)	/* Only count a general error at the */
-				lp->stats.rx_errors++; /* end of a packet.*/
-			if (status & 0x20) lp->stats.rx_frame_errors++;
-			if (status & 0x10) lp->stats.rx_over_errors++;
-			if (status & 0x08) lp->stats.rx_crc_errors++;
-			if (status & 0x04) lp->stats.rx_fifo_errors++;
+				dev->stats.rx_errors++; /* end of a packet.*/
+			if (status & 0x20)
+				dev->stats.rx_frame_errors++;
+			if (status & 0x10)
+				dev->stats.rx_over_errors++;
+			if (status & 0x08)
+				dev->stats.rx_crc_errors++;
+			if (status & 0x04)
+				dev->stats.rx_fifo_errors++;
 			lp->rx_ring[entry].base &= 0x03ffffff;
 		}
 		else
@@ -1171,7 +1179,7 @@
 			if(pkt_len<60)
 			{
 				printk("%s: Runt packet!\n",dev->name);
-				lp->stats.rx_errors++;
+				dev->stats.rx_errors++;
 			}
 			else
 			{
@@ -1185,7 +1193,7 @@
 
 					if (i > RX_RING_SIZE -2)
 					{
-						lp->stats.rx_dropped++;
+						dev->stats.rx_dropped++;
 						lp->rx_ring[entry].base |= 0x80000000;
 						lp->cur_rx++;
 					}
@@ -1198,8 +1206,8 @@
 					pkt_len);
 				skb->protocol=eth_type_trans(skb,dev);
 				netif_rx(skb);
-				lp->stats.rx_packets++;
-				lp->stats.rx_bytes+=pkt_len;
+				dev->stats.rx_packets++;
+				dev->stats.rx_bytes += pkt_len;
 			}
 		}
 		/* The docs say that the buffer length isn't touched, but Andrew Boyd
@@ -1225,7 +1233,7 @@
 
 	if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) {
 		outw(112, ioaddr+LANCE_ADDR);
-		lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
+		dev->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
 	}
 	outw(0, ioaddr+LANCE_ADDR);
 
@@ -1262,12 +1270,12 @@
 		spin_lock_irqsave(&lp->devlock, flags);
 		saved_addr = inw(ioaddr+LANCE_ADDR);
 		outw(112, ioaddr+LANCE_ADDR);
-		lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
+		dev->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
 		outw(saved_addr, ioaddr+LANCE_ADDR);
 		spin_unlock_irqrestore(&lp->devlock, flags);
 	}
 
-	return &lp->stats;
+	return &dev->stats;
 }
 
 /* Set or clear the multicast filter for this adaptor.
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c
index dc6bf04..4eea3f7 100644
--- a/drivers/net/ll_temac_main.c
+++ b/drivers/net/ll_temac_main.c
@@ -193,6 +193,35 @@
 #endif
 
 /**
+ *  * temac_dma_bd_release - Release buffer descriptor rings
+ */
+static void temac_dma_bd_release(struct net_device *ndev)
+{
+	struct temac_local *lp = netdev_priv(ndev);
+	int i;
+
+	for (i = 0; i < RX_BD_NUM; i++) {
+		if (!lp->rx_skb[i])
+			break;
+		else {
+			dma_unmap_single(ndev->dev.parent, lp->rx_bd_v[i].phys,
+					XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE);
+			dev_kfree_skb(lp->rx_skb[i]);
+		}
+	}
+	if (lp->rx_bd_v)
+		dma_free_coherent(ndev->dev.parent,
+				sizeof(*lp->rx_bd_v) * RX_BD_NUM,
+				lp->rx_bd_v, lp->rx_bd_p);
+	if (lp->tx_bd_v)
+		dma_free_coherent(ndev->dev.parent,
+				sizeof(*lp->tx_bd_v) * TX_BD_NUM,
+				lp->tx_bd_v, lp->tx_bd_p);
+	if (lp->rx_skb)
+		kfree(lp->rx_skb);
+}
+
+/**
  * temac_dma_bd_init - Setup buffer descriptor rings
  */
 static int temac_dma_bd_init(struct net_device *ndev)
@@ -202,14 +231,29 @@
 	int i;
 
 	lp->rx_skb = kzalloc(sizeof(*lp->rx_skb) * RX_BD_NUM, GFP_KERNEL);
+	if (!lp->rx_skb) {
+		dev_err(&ndev->dev,
+				"can't allocate memory for DMA RX buffer\n");
+		goto out;
+	}
 	/* allocate the tx and rx ring buffer descriptors. */
 	/* returns a virtual addres and a physical address. */
 	lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent,
 					 sizeof(*lp->tx_bd_v) * TX_BD_NUM,
 					 &lp->tx_bd_p, GFP_KERNEL);
+	if (!lp->tx_bd_v) {
+		dev_err(&ndev->dev,
+				"unable to allocate DMA TX buffer descriptors");
+		goto out;
+	}
 	lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent,
 					 sizeof(*lp->rx_bd_v) * RX_BD_NUM,
 					 &lp->rx_bd_p, GFP_KERNEL);
+	if (!lp->rx_bd_v) {
+		dev_err(&ndev->dev,
+				"unable to allocate DMA RX buffer descriptors");
+		goto out;
+	}
 
 	memset(lp->tx_bd_v, 0, sizeof(*lp->tx_bd_v) * TX_BD_NUM);
 	for (i = 0; i < TX_BD_NUM; i++) {
@@ -227,7 +271,7 @@
 
 		if (skb == 0) {
 			dev_err(&ndev->dev, "alloc_skb error %d\n", i);
-			return -1;
+			goto out;
 		}
 		lp->rx_skb[i] = skb;
 		/* returns physical address of skb->data */
@@ -258,6 +302,10 @@
 	lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
 
 	return 0;
+
+out:
+	temac_dma_bd_release(ndev);
+	return -ENOMEM;
 }
 
 /* ---------------------------------------------------------------------
@@ -505,7 +553,10 @@
 	}
 	lp->dma_out(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);
 
-	temac_dma_bd_init(ndev);
+	if (temac_dma_bd_init(ndev)) {
+		dev_err(&ndev->dev,
+				"temac_device_reset descriptor allocation failed\n");
+	}
 
 	temac_indirect_out32(lp, XTE_RXC0_OFFSET, 0);
 	temac_indirect_out32(lp, XTE_RXC1_OFFSET, 0);
@@ -837,6 +888,8 @@
 		phy_disconnect(lp->phy_dev);
 	lp->phy_dev = NULL;
 
+	temac_dma_bd_release(ndev);
+
 	return 0;
 }
 
@@ -862,6 +915,7 @@
 	.ndo_stop = temac_stop,
 	.ndo_start_xmit = temac_start_xmit,
 	.ndo_set_mac_address = netdev_set_mac_address,
+	.ndo_validate_addr = eth_validate_addr,
 	//.ndo_set_multicast_list = temac_set_multicast_list,
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller = temac_poll_controller,
@@ -978,19 +1032,22 @@
 			dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs);
 		} else {
 			dev_err(&op->dev, "unable to map DMA registers\n");
+			of_node_put(np);
 			goto err_iounmap;
 		}
 	}
 
 	lp->rx_irq = irq_of_parse_and_map(np, 0);
 	lp->tx_irq = irq_of_parse_and_map(np, 1);
+
+	of_node_put(np); /* Finished with the DMA node; drop the reference */
+
 	if ((lp->rx_irq == NO_IRQ) || (lp->tx_irq == NO_IRQ)) {
 		dev_err(&op->dev, "could not determine irqs\n");
 		rc = -ENOMEM;
 		goto err_iounmap_2;
 	}
 
-	of_node_put(np); /* Finished with the DMA node; drop the reference */
 
 	/* Retrieve the MAC address */
 	addr = of_get_property(op->dev.of_node, "local-mac-address", &size);
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 72b7949..9a09967 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -58,11 +58,13 @@
 #include <linux/tcp.h>
 #include <linux/percpu.h>
 #include <net/net_namespace.h>
+#include <linux/u64_stats_sync.h>
 
 struct pcpu_lstats {
-	unsigned long packets;
-	unsigned long bytes;
-	unsigned long drops;
+	u64			packets;
+	u64			bytes;
+	struct u64_stats_sync	syncp;
+	unsigned long		drops;
 };
 
 /*
@@ -86,31 +88,40 @@
 
 	len = skb->len;
 	if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
+		u64_stats_update_begin(&lb_stats->syncp);
 		lb_stats->bytes += len;
 		lb_stats->packets++;
+		u64_stats_update_end(&lb_stats->syncp);
 	} else
 		lb_stats->drops++;
 
 	return NETDEV_TX_OK;
 }
 
-static struct net_device_stats *loopback_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev,
+						      struct rtnl_link_stats64 *stats)
 {
 	const struct pcpu_lstats __percpu *pcpu_lstats;
-	struct net_device_stats *stats = &dev->stats;
-	unsigned long bytes = 0;
-	unsigned long packets = 0;
-	unsigned long drops = 0;
+	u64 bytes = 0;
+	u64 packets = 0;
+	u64 drops = 0;
 	int i;
 
 	pcpu_lstats = (void __percpu __force *)dev->ml_priv;
 	for_each_possible_cpu(i) {
 		const struct pcpu_lstats *lb_stats;
+		u64 tbytes, tpackets;
+		unsigned int start;
 
 		lb_stats = per_cpu_ptr(pcpu_lstats, i);
-		bytes   += lb_stats->bytes;
-		packets += lb_stats->packets;
+		do {
+			start = u64_stats_fetch_begin(&lb_stats->syncp);
+			tbytes = lb_stats->bytes;
+			tpackets = lb_stats->packets;
+		} while (u64_stats_fetch_retry(&lb_stats->syncp, start));
 		drops   += lb_stats->drops;
+		bytes   += tbytes;
+		packets += tpackets;
 	}
 	stats->rx_packets = packets;
 	stats->tx_packets = packets;
@@ -158,7 +169,7 @@
 static const struct net_device_ops loopback_ops = {
 	.ndo_init      = loopback_dev_init,
 	.ndo_start_xmit= loopback_xmit,
-	.ndo_get_stats = loopback_get_stats,
+	.ndo_get_stats64 = loopback_get_stats64,
 };
 
 /*
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index 1136c9a..3832fa4 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -157,6 +157,8 @@
 #define memcpy_fromio(a, b, c)	memcpy((a), (void *)(b), (c))
 #define memcpy_toio(a, b, c)	memcpy((void *)(a), (b), (c))
 
+#define memcmp_withio(a, b, c)	memcmp((a), (void *)(b), (c))
+
 /* Slow Sane (16-bit chunk memory read/write) Cabletron uses this */
 static void slow_sane_get_8390_hdr(struct net_device *dev,
 				   struct e8390_pkt_hdr *hdr, int ring_page);
@@ -164,8 +166,8 @@
 				  struct sk_buff *skb, int ring_offset);
 static void slow_sane_block_output(struct net_device *dev, int count,
 				   const unsigned char *buf, int start_page);
-static void word_memcpy_tocard(void *tp, const void *fp, int count);
-static void word_memcpy_fromcard(void *tp, const void *fp, int count);
+static void word_memcpy_tocard(unsigned long tp, const void *fp, int count);
+static void word_memcpy_fromcard(void *tp, unsigned long fp, int count);
 
 static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev)
 {
@@ -245,9 +247,9 @@
 	unsigned long outdata = 0xA5A0B5B0;
 	unsigned long indata =  0x00000000;
 	/* Try writing 32 bits */
-	memcpy(membase, &outdata, 4);
+	memcpy_toio(membase, &outdata, 4);
 	/* Now compare them */
-	if (memcmp((char *)&outdata, (char *)membase, 4) == 0)
+	if (memcmp_withio(&outdata, membase, 4) == 0)
 		return ACCESS_32;
 	/* Write 16 bit output */
 	word_memcpy_tocard(membase, &outdata, 4);
@@ -554,7 +556,7 @@
 	case MAC8390_APPLE:
 		switch (mac8390_testio(dev->mem_start)) {
 		case ACCESS_UNKNOWN:
-			pr_info("Don't know how to access card memory!\n");
+			pr_err("Don't know how to access card memory!\n");
 			return -ENODEV;
 			break;
 
@@ -641,12 +643,13 @@
 
 static int mac8390_open(struct net_device *dev)
 {
+	int err;
+
 	__ei_open(dev);
-	if (request_irq(dev->irq, __ei_interrupt, 0, "8390 Ethernet", dev)) {
-		pr_info("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
-		return -EAGAIN;
-	}
-	return 0;
+	err = request_irq(dev->irq, __ei_interrupt, 0, "8390 Ethernet", dev);
+	if (err)
+		pr_err("%s: unable to get IRQ %d\n", dev->name, dev->irq);
+	return err;
 }
 
 static int mac8390_close(struct net_device *dev)
@@ -731,7 +734,7 @@
 			      struct e8390_pkt_hdr *hdr, int ring_page)
 {
 	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
-	memcpy_fromio((void *)hdr, (char *)dev->mem_start + hdr_start, 4);
+	memcpy_fromio(hdr, dev->mem_start + hdr_start, 4);
 	/* Fix endianness */
 	hdr->count = swab16(hdr->count);
 }
@@ -745,14 +748,13 @@
 	if (xfer_start + count > ei_status.rmem_end) {
 		/* We must wrap the input move. */
 		int semi_count = ei_status.rmem_end - xfer_start;
-		memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base,
+		memcpy_fromio(skb->data, dev->mem_start + xfer_base,
 			      semi_count);
 		count -= semi_count;
-		memcpy_toio(skb->data + semi_count,
-			    (char *)ei_status.rmem_start, count);
-	} else {
-		memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base,
+		memcpy_fromio(skb->data + semi_count, ei_status.rmem_start,
 			      count);
+	} else {
+		memcpy_fromio(skb->data, dev->mem_start + xfer_base, count);
 	}
 }
 
@@ -761,7 +763,7 @@
 {
 	long shmem = (start_page - WD_START_PG)<<8;
 
-	memcpy_toio((char *)dev->mem_start + shmem, buf, count);
+	memcpy_toio(dev->mem_start + shmem, buf, count);
 }
 
 /* dayna block input/output */
@@ -812,7 +814,7 @@
 				   int ring_page)
 {
 	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
-	word_memcpy_fromcard(hdr, (char *)dev->mem_start + hdr_start, 4);
+	word_memcpy_fromcard(hdr, dev->mem_start + hdr_start, 4);
 	/* Register endianism - fix here rather than 8390.c */
 	hdr->count = (hdr->count&0xFF)<<8|(hdr->count>>8);
 }
@@ -826,15 +828,14 @@
 	if (xfer_start + count > ei_status.rmem_end) {
 		/* We must wrap the input move. */
 		int semi_count = ei_status.rmem_end - xfer_start;
-		word_memcpy_fromcard(skb->data,
-				     (char *)dev->mem_start + xfer_base,
+		word_memcpy_fromcard(skb->data, dev->mem_start + xfer_base,
 				     semi_count);
 		count -= semi_count;
 		word_memcpy_fromcard(skb->data + semi_count,
-				     (char *)ei_status.rmem_start, count);
+				     ei_status.rmem_start, count);
 	} else {
-		word_memcpy_fromcard(skb->data,
-				     (char *)dev->mem_start + xfer_base, count);
+		word_memcpy_fromcard(skb->data, dev->mem_start + xfer_base,
+				     count);
 	}
 }
 
@@ -843,12 +844,12 @@
 {
 	long shmem = (start_page - WD_START_PG)<<8;
 
-	word_memcpy_tocard((char *)dev->mem_start + shmem, buf, count);
+	word_memcpy_tocard(dev->mem_start + shmem, buf, count);
 }
 
-static void word_memcpy_tocard(void *tp, const void *fp, int count)
+static void word_memcpy_tocard(unsigned long tp, const void *fp, int count)
 {
-	volatile unsigned short *to = tp;
+	volatile unsigned short *to = (void *)tp;
 	const unsigned short *from = fp;
 
 	count++;
@@ -858,10 +859,10 @@
 		*to++ = *from++;
 }
 
-static void word_memcpy_fromcard(void *tp, const void *fp, int count)
+static void word_memcpy_fromcard(void *tp, unsigned long fp, int count)
 {
 	unsigned short *to = tp;
-	const volatile unsigned short *from = fp;
+	const volatile unsigned short *from = (const void *)fp;
 
 	count++;
 	count /= 2;
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index 69fa4ef6..669b317 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -110,7 +110,6 @@
 
 /* Information that need to be kept for each board. */
 struct net_local {
-	struct net_device_stats stats;
 	int chip_type;		/* one of: CS8900, CS8920, CS8920M */
 	char chip_revision;	/* revision letter of the chip ('A'...) */
 	int send_cmd;		/* the propercommand used to send a packet. */
@@ -444,13 +443,18 @@
 			net_rx(dev);
 			break;
 		case ISQ_TRANSMITTER_EVENT:
-			lp->stats.tx_packets++;
+			dev->stats.tx_packets++;
 			netif_wake_queue(dev);
-			if ((status & TX_OK) == 0) lp->stats.tx_errors++;
-			if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
-			if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
-			if (status & TX_LATE_COL) lp->stats.tx_window_errors++;
-			if (status & TX_16_COL) lp->stats.tx_aborted_errors++;
+			if ((status & TX_OK) == 0)
+				dev->stats.tx_errors++;
+			if (status & TX_LOST_CRS)
+				dev->stats.tx_carrier_errors++;
+			if (status & TX_SQE_ERROR)
+				dev->stats.tx_heartbeat_errors++;
+			if (status & TX_LATE_COL)
+				dev->stats.tx_window_errors++;
+			if (status & TX_16_COL)
+				dev->stats.tx_aborted_errors++;
 			break;
 		case ISQ_BUFFER_EVENT:
 			if (status & READY_FOR_TX) {
@@ -469,10 +473,10 @@
                         }
 			break;
 		case ISQ_RX_MISS_EVENT:
-			lp->stats.rx_missed_errors += (status >>6);
+			dev->stats.rx_missed_errors += (status >> 6);
 			break;
 		case ISQ_TX_COL_EVENT:
-			lp->stats.collisions += (status >>6);
+			dev->stats.collisions += (status >> 6);
 			break;
 		}
 	}
@@ -483,19 +487,22 @@
 static void
 net_rx(struct net_device *dev)
 {
-	struct net_local *lp = netdev_priv(dev);
 	struct sk_buff *skb;
 	int status, length;
 
 	status = readreg(dev, PP_RxStatus);
 	if ((status & RX_OK) == 0) {
-		lp->stats.rx_errors++;
-		if (status & RX_RUNT) lp->stats.rx_length_errors++;
-		if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++;
-		if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT)))
+		dev->stats.rx_errors++;
+		if (status & RX_RUNT)
+				dev->stats.rx_length_errors++;
+		if (status & RX_EXTRA_DATA)
+				dev->stats.rx_length_errors++;
+		if ((status & RX_CRC_ERROR) &&
+		    !(status & (RX_EXTRA_DATA|RX_RUNT)))
 			/* per str 172 */
-			lp->stats.rx_crc_errors++;
-		if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++;
+			dev->stats.rx_crc_errors++;
+		if (status & RX_DRIBBLE)
+				dev->stats.rx_frame_errors++;
 		return;
 	}
 
@@ -504,7 +511,7 @@
 	skb = alloc_skb(length, GFP_ATOMIC);
 	if (skb == NULL) {
 		printk("%s: Memory squeeze, dropping packet.\n", dev->name);
-		lp->stats.rx_dropped++;
+		dev->stats.rx_dropped++;
 		return;
 	}
 	skb_put(skb, length);
@@ -519,8 +526,8 @@
 
         skb->protocol=eth_type_trans(skb,dev);
 	netif_rx(skb);
-	lp->stats.rx_packets++;
-	lp->stats.rx_bytes += length;
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += length;
 }
 
 /* The inverse routine to net_open(). */
@@ -548,16 +555,15 @@
 static struct net_device_stats *
 net_get_stats(struct net_device *dev)
 {
-	struct net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	local_irq_save(flags);
 	/* Update the statistics from the device registers. */
-	lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
-	lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
+	dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
+	dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
 	local_irq_restore(flags);
 
-	return &lp->stats;
+	return &dev->stats;
 }
 
 static void set_multicast_list(struct net_device *dev)
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 40797fb..ff2f158 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -1082,7 +1082,7 @@
 	if (!phydev)
 		return -ENODEV;
 
-	return phy_mii_ioctl(phydev, if_mii(rq), cmd);
+	return phy_mii_ioctl(phydev, rq, cmd);
 }
 
 static const struct net_device_ops macb_netdev_ops = {
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index adb54fe..c93679e 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -140,21 +140,40 @@
 
 static int macsonic_open(struct net_device* dev)
 {
-	if (request_irq(dev->irq, sonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) {
-		printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
-		return -EAGAIN;
+	int retval;
+
+	retval = request_irq(dev->irq, sonic_interrupt, IRQ_FLG_FAST,
+				"sonic", dev);
+	if (retval) {
+		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+				dev->name, dev->irq);
+		goto err;
 	}
 	/* Under the A/UX interrupt scheme, the onboard SONIC interrupt comes
 	 * in at priority level 3. However, we sometimes get the level 2 inter-
 	 * rupt as well, which must prevent re-entrance of the sonic handler.
 	 */
-	if (dev->irq == IRQ_AUTO_3)
-		if (request_irq(IRQ_NUBUS_9, macsonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) {
-			printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, IRQ_NUBUS_9);
-			free_irq(dev->irq, dev);
-			return -EAGAIN;
+	if (dev->irq == IRQ_AUTO_3) {
+		retval = request_irq(IRQ_NUBUS_9, macsonic_interrupt,
+					IRQ_FLG_FAST, "sonic", dev);
+		if (retval) {
+			printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+					dev->name, IRQ_NUBUS_9);
+			goto err_irq;
 		}
-	return sonic_open(dev);
+	}
+	retval = sonic_open(dev);
+	if (retval)
+		goto err_irq_nubus;
+	return 0;
+
+err_irq_nubus:
+	if (dev->irq == IRQ_AUTO_3)
+		free_irq(IRQ_NUBUS_9, dev);
+err_irq:
+	free_irq(dev->irq, dev);
+err:
+	return retval;
 }
 
 static int macsonic_close(struct net_device* dev)
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index f15fe2c..0ef0eb0 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -37,8 +37,14 @@
 	struct net_device	*dev;
 	struct hlist_head	vlan_hash[MACVLAN_HASH_SIZE];
 	struct list_head	vlans;
+	struct rcu_head		rcu;
 };
 
+#define macvlan_port_get_rcu(dev) \
+	((struct macvlan_port *) rcu_dereference(dev->rx_handler_data))
+#define macvlan_port_get(dev) ((struct macvlan_port *) dev->rx_handler_data)
+#define macvlan_port_exists(dev) (dev->priv_flags & IFF_MACVLAN_PORT)
+
 static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
 					       const unsigned char *addr)
 {
@@ -145,15 +151,17 @@
 }
 
 /* called under rcu_read_lock() from netif_receive_skb */
-static struct sk_buff *macvlan_handle_frame(struct macvlan_port *port,
-					    struct sk_buff *skb)
+static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
 {
+	struct macvlan_port *port;
 	const struct ethhdr *eth = eth_hdr(skb);
 	const struct macvlan_dev *vlan;
 	const struct macvlan_dev *src;
 	struct net_device *dev;
-	unsigned int len;
+	unsigned int len = 0;
+	int ret = NET_RX_DROP;
 
+	port = macvlan_port_get_rcu(skb->dev);
 	if (is_multicast_ether_addr(eth->h_dest)) {
 		src = macvlan_hash_lookup(port, eth->h_source);
 		if (!src)
@@ -188,14 +196,16 @@
 	}
 	len = skb->len + ETH_HLEN;
 	skb = skb_share_check(skb, GFP_ATOMIC);
-	macvlan_count_rx(vlan, len, skb != NULL, 0);
 	if (!skb)
-		return NULL;
+		goto out;
 
 	skb->dev = dev;
 	skb->pkt_type = PACKET_HOST;
 
-	vlan->receive(skb);
+	ret = vlan->receive(skb);
+
+out:
+	macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0);
 	return NULL;
 }
 
@@ -424,29 +434,38 @@
 	free_percpu(vlan->rx_stats);
 }
 
-static struct net_device_stats *macvlan_dev_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
+							 struct rtnl_link_stats64 *stats)
 {
-	struct net_device_stats *stats = &dev->stats;
 	struct macvlan_dev *vlan = netdev_priv(dev);
 
 	dev_txq_stats_fold(dev, stats);
 
 	if (vlan->rx_stats) {
-		struct macvlan_rx_stats *p, rx = {0};
+		struct macvlan_rx_stats *p, accum = {0};
+		u64 rx_packets, rx_bytes, rx_multicast;
+		unsigned int start;
 		int i;
 
 		for_each_possible_cpu(i) {
 			p = per_cpu_ptr(vlan->rx_stats, i);
-			rx.rx_packets += p->rx_packets;
-			rx.rx_bytes   += p->rx_bytes;
-			rx.rx_errors  += p->rx_errors;
-			rx.multicast  += p->multicast;
+			do {
+				start = u64_stats_fetch_begin_bh(&p->syncp);
+				rx_packets	= p->rx_packets;
+				rx_bytes	= p->rx_bytes;
+				rx_multicast	= p->rx_multicast;
+			} while (u64_stats_fetch_retry_bh(&p->syncp, start));
+			accum.rx_packets	+= rx_packets;
+			accum.rx_bytes		+= rx_bytes;
+			accum.rx_multicast	+= rx_multicast;
+			/* rx_errors is an ulong, updated without syncp protection */
+			accum.rx_errors		+= p->rx_errors;
 		}
-		stats->rx_packets = rx.rx_packets;
-		stats->rx_bytes   = rx.rx_bytes;
-		stats->rx_errors  = rx.rx_errors;
-		stats->rx_dropped = rx.rx_errors;
-		stats->multicast  = rx.multicast;
+		stats->rx_packets = accum.rx_packets;
+		stats->rx_bytes   = accum.rx_bytes;
+		stats->rx_errors  = accum.rx_errors;
+		stats->rx_dropped = accum.rx_errors;
+		stats->multicast  = accum.rx_multicast;
 	}
 	return stats;
 }
@@ -495,7 +514,7 @@
 	.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_get_stats		= macvlan_dev_get_stats,
+	.ndo_get_stats64	= macvlan_dev_get_stats64,
 	.ndo_validate_addr	= eth_validate_addr,
 };
 
@@ -521,6 +540,7 @@
 {
 	struct macvlan_port *port;
 	unsigned int i;
+	int err;
 
 	if (dev->type != ARPHRD_ETHER || dev->flags & IFF_LOOPBACK)
 		return -EINVAL;
@@ -533,17 +553,30 @@
 	INIT_LIST_HEAD(&port->vlans);
 	for (i = 0; i < MACVLAN_HASH_SIZE; i++)
 		INIT_HLIST_HEAD(&port->vlan_hash[i]);
-	rcu_assign_pointer(dev->macvlan_port, port);
-	return 0;
+
+	err = netdev_rx_handler_register(dev, macvlan_handle_frame, port);
+	if (err)
+		kfree(port);
+
+	dev->priv_flags |= IFF_MACVLAN_PORT;
+	return err;
+}
+
+static void macvlan_port_rcu_free(struct rcu_head *head)
+{
+	struct macvlan_port *port;
+
+	port = container_of(head, struct macvlan_port, rcu);
+	kfree(port);
 }
 
 static void macvlan_port_destroy(struct net_device *dev)
 {
-	struct macvlan_port *port = dev->macvlan_port;
+	struct macvlan_port *port = macvlan_port_get(dev);
 
-	rcu_assign_pointer(dev->macvlan_port, NULL);
-	synchronize_rcu();
-	kfree(port);
+	dev->priv_flags &= ~IFF_MACVLAN_PORT;
+	netdev_rx_handler_unregister(dev);
+	call_rcu(&port->rcu, macvlan_port_rcu_free);
 }
 
 static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
@@ -621,12 +654,12 @@
 	if (!tb[IFLA_ADDRESS])
 		random_ether_addr(dev->dev_addr);
 
-	if (lowerdev->macvlan_port == NULL) {
+	if (!macvlan_port_exists(lowerdev)) {
 		err = macvlan_port_create(lowerdev);
 		if (err < 0)
 			return err;
 	}
-	port = lowerdev->macvlan_port;
+	port = macvlan_port_get(lowerdev);
 
 	vlan->lowerdev = lowerdev;
 	vlan->dev      = dev;
@@ -736,10 +769,11 @@
 	struct macvlan_dev *vlan, *next;
 	struct macvlan_port *port;
 
-	port = dev->macvlan_port;
-	if (port == NULL)
+	if (!macvlan_port_exists(dev))
 		return NOTIFY_DONE;
 
+	port = macvlan_port_get(dev);
+
 	switch (event) {
 	case NETDEV_CHANGE:
 		list_for_each_entry(vlan, &port->vlans, list)
@@ -773,14 +807,12 @@
 	int err;
 
 	register_netdevice_notifier(&macvlan_notifier_block);
-	macvlan_handle_frame_hook = macvlan_handle_frame;
 
 	err = macvlan_link_register(&macvlan_link_ops);
 	if (err < 0)
 		goto err1;
 	return 0;
 err1:
-	macvlan_handle_frame_hook = NULL;
 	unregister_netdevice_notifier(&macvlan_notifier_block);
 	return err;
 }
@@ -788,7 +820,6 @@
 static void __exit macvlan_cleanup_module(void)
 {
 	rtnl_link_unregister(&macvlan_link_ops);
-	macvlan_handle_frame_hook = NULL;
 	unregister_netdevice_notifier(&macvlan_notifier_block);
 }
 
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index ff02b83..3b1c54a 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -58,7 +58,7 @@
  * only has one tap, the interface numbers assure that the
  * device nodes are unique.
  */
-static unsigned int macvtap_major;
+static dev_t macvtap_major;
 #define MACVTAP_NUM_DEVS 65536
 static struct class *macvtap_class;
 static struct cdev macvtap_cdev;
diff --git a/drivers/net/mlx4/catas.c b/drivers/net/mlx4/catas.c
index f599294..68aaa42 100644
--- a/drivers/net/mlx4/catas.c
+++ b/drivers/net/mlx4/catas.c
@@ -101,8 +101,8 @@
 		ret = mlx4_restart_one(priv->dev.pdev);
 		/* 'priv' now is not valid */
 		if (ret)
-			printk(KERN_ERR "mlx4 %s: Reset failed (%d)\n",
-				pci_name(pdev), ret);
+			pr_err("mlx4 %s: Reset failed (%d)\n",
+			       pci_name(pdev), ret);
 		else {
 			dev  = pci_get_drvdata(pdev);
 			mlx4_dbg(dev, "Reset succeeded\n");
diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c
index d5afd03..b275238 100644
--- a/drivers/net/mlx4/en_ethtool.c
+++ b/drivers/net/mlx4/en_ethtool.c
@@ -387,6 +387,42 @@
 	param->tx_pending = mdev->profile.prof[priv->port].tx_ring_size;
 }
 
+static int mlx4_ethtool_op_set_flags(struct net_device *dev, u32 data)
+{
+	struct mlx4_en_priv *priv = netdev_priv(dev);
+	struct mlx4_en_dev *mdev = priv->mdev;
+	int rc = 0;
+	int changed = 0;
+
+	if (data & ~ETH_FLAG_LRO)
+		return -EOPNOTSUPP;
+
+	if (data & ETH_FLAG_LRO) {
+		if (mdev->profile.num_lro == 0)
+			return -EOPNOTSUPP;
+		if (!(dev->features & NETIF_F_LRO))
+			changed = 1;
+	} else if (dev->features & NETIF_F_LRO) {
+		changed = 1;
+	}
+
+	if (changed) {
+		if (netif_running(dev)) {
+			mutex_lock(&mdev->state_lock);
+			mlx4_en_stop_port(dev);
+		}
+		dev->features ^= NETIF_F_LRO;
+		if (netif_running(dev)) {
+			rc = mlx4_en_start_port(dev);
+			if (rc)
+				en_err(priv, "Failed to restart port\n");
+			mutex_unlock(&mdev->state_lock);
+		}
+	}
+
+	return rc;
+}
+
 const struct ethtool_ops mlx4_en_ethtool_ops = {
 	.get_drvinfo = mlx4_en_get_drvinfo,
 	.get_settings = mlx4_en_get_settings,
@@ -415,7 +451,7 @@
 	.get_ringparam = mlx4_en_get_ringparam,
 	.set_ringparam = mlx4_en_set_ringparam,
 	.get_flags = ethtool_op_get_flags,
-	.set_flags = ethtool_op_set_flags,
+	.set_flags = mlx4_ethtool_op_set_flags,
 };
 
 
diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c
index cbabf14..97934f1 100644
--- a/drivers/net/mlx4/en_main.c
+++ b/drivers/net/mlx4/en_main.c
@@ -79,6 +79,29 @@
 MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]."
 			   " Per priority bit mask");
 
+int en_print(const char *level, const struct mlx4_en_priv *priv,
+	     const char *format, ...)
+{
+	va_list args;
+	struct va_format vaf;
+	int i;
+
+	va_start(args, format);
+
+	vaf.fmt = format;
+	vaf.va = &args;
+	if (priv->registered)
+		i = printk("%s%s: %s: %pV",
+			   level, DRV_NAME, priv->dev->name, &vaf);
+	else
+		i = printk("%s%s: %s: Port %d: %pV",
+			   level, DRV_NAME, dev_name(&priv->mdev->pdev->dev),
+			   priv->port, &vaf);
+	va_end(args);
+
+	return i;
+}
+
 static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
 {
 	struct mlx4_en_profile *params = &mdev->profile;
@@ -152,15 +175,11 @@
 
 static void *mlx4_en_add(struct mlx4_dev *dev)
 {
-	static int mlx4_en_version_printed;
 	struct mlx4_en_dev *mdev;
 	int i;
 	int err;
 
-	if (!mlx4_en_version_printed) {
-		printk(KERN_INFO "%s", mlx4_en_version);
-		mlx4_en_version_printed++;
-	}
+	printk_once(KERN_INFO "%s", mlx4_en_version);
 
 	mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
 	if (!mdev) {
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 96180c0..a0d8a26 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -961,6 +961,7 @@
 	}
 
 	SET_NETDEV_DEV(dev, &mdev->dev->pdev->dev);
+	dev->dev_id =  port - 1;
 
 	/*
 	 * Initialize driver private data
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 4230534..6d7b2bf 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -110,7 +110,7 @@
 		u32		raw[6];
 		struct {
 			__be32	cqn;
-		} __attribute__((packed)) comp;
+		} __packed comp;
 		struct {
 			u16	reserved1;
 			__be16	token;
@@ -118,27 +118,27 @@
 			u8	reserved3[3];
 			u8	status;
 			__be64	out_param;
-		} __attribute__((packed)) cmd;
+		} __packed cmd;
 		struct {
 			__be32	qpn;
-		} __attribute__((packed)) qp;
+		} __packed qp;
 		struct {
 			__be32	srqn;
-		} __attribute__((packed)) srq;
+		} __packed srq;
 		struct {
 			__be32	cqn;
 			u32	reserved1;
 			u8	reserved2[3];
 			u8	syndrome;
-		} __attribute__((packed)) cq_err;
+		} __packed cq_err;
 		struct {
 			u32	reserved1[2];
 			__be32	port;
-		} __attribute__((packed)) port_change;
+		} __packed port_change;
 	}			event;
 	u8			reserved3[3];
 	u8			owner;
-} __attribute__((packed));
+} __packed;
 
 static void eq_set_ci(struct mlx4_eq *eq, int req_not)
 {
@@ -475,10 +475,10 @@
 		mlx4_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn);
 		for (i = 0; i < sizeof (struct mlx4_eq_context) / 4; ++i) {
 			if (i % 4 == 0)
-				printk("[%02x] ", i * 4);
-			printk(" %08x", be32_to_cpup(mailbox->buf + i * 4));
+				pr_cont("[%02x] ", i * 4);
+			pr_cont(" %08x", be32_to_cpup(mailbox->buf + i * 4));
 			if ((i + 1) % 4 == 0)
-				printk("\n");
+				pr_cont("\n");
 		}
 	}
 
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index e3e0d54..5102ab1 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -1050,8 +1050,7 @@
 	int err;
 	int port;
 
-	printk(KERN_INFO PFX "Initializing %s\n",
-	       pci_name(pdev));
+	pr_info(DRV_NAME ": Initializing %s\n", pci_name(pdev));
 
 	err = pci_enable_device(pdev);
 	if (err) {
@@ -1216,12 +1215,7 @@
 static int __devinit mlx4_init_one(struct pci_dev *pdev,
 				   const struct pci_device_id *id)
 {
-	static int mlx4_version_printed;
-
-	if (!mlx4_version_printed) {
-		printk(KERN_INFO "%s", mlx4_version);
-		++mlx4_version_printed;
-	}
+	printk_once(KERN_INFO "%s", mlx4_version);
 
 	return __mlx4_init_one(pdev, id);
 }
@@ -1301,17 +1295,17 @@
 static int __init mlx4_verify_params(void)
 {
 	if ((log_num_mac < 0) || (log_num_mac > 7)) {
-		printk(KERN_WARNING "mlx4_core: bad num_mac: %d\n", log_num_mac);
+		pr_warning("mlx4_core: bad num_mac: %d\n", log_num_mac);
 		return -1;
 	}
 
 	if ((log_num_vlan < 0) || (log_num_vlan > 7)) {
-		printk(KERN_WARNING "mlx4_core: bad num_vlan: %d\n", log_num_vlan);
+		pr_warning("mlx4_core: bad num_vlan: %d\n", log_num_vlan);
 		return -1;
 	}
 
 	if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 5)) {
-		printk(KERN_WARNING "mlx4_core: bad log_mtts_per_seg: %d\n", log_mtts_per_seg);
+		pr_warning("mlx4_core: bad log_mtts_per_seg: %d\n", log_mtts_per_seg);
 		return -1;
 	}
 
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 13343e8..0da5bb72 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -48,7 +48,6 @@
 #include <linux/mlx4/doorbell.h>
 
 #define DRV_NAME	"mlx4_core"
-#define PFX		DRV_NAME ": "
 #define DRV_VERSION	"0.01"
 #define DRV_RELDATE	"May 1, 2007"
 
@@ -88,17 +87,17 @@
 #endif /* CONFIG_MLX4_DEBUG */
 
 #define mlx4_dbg(mdev, format, arg...)					\
-	do {								\
-		if (mlx4_debug_level)					\
-			dev_printk(KERN_DEBUG, &mdev->pdev->dev, format, ## arg); \
-	} while (0)
+do {									\
+	if (mlx4_debug_level)						\
+		dev_printk(KERN_DEBUG, &mdev->pdev->dev, format, ##arg); \
+} while (0)
 
 #define mlx4_err(mdev, format, arg...) \
-	dev_err(&mdev->pdev->dev, format, ## arg)
+	dev_err(&mdev->pdev->dev, format, ##arg)
 #define mlx4_info(mdev, format, arg...) \
-	dev_info(&mdev->pdev->dev, format, ## arg)
+	dev_info(&mdev->pdev->dev, format, ##arg)
 #define mlx4_warn(mdev, format, arg...) \
-	dev_warn(&mdev->pdev->dev, format, ## arg)
+	dev_warn(&mdev->pdev->dev, format, ##arg)
 
 struct mlx4_bitmap {
 	u32			last;
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h
index b55e46c..4492109 100644
--- a/drivers/net/mlx4/mlx4_en.h
+++ b/drivers/net/mlx4/mlx4_en.h
@@ -52,40 +52,8 @@
 #define DRV_VERSION	"1.4.1.1"
 #define DRV_RELDATE	"June 2009"
 
-
 #define MLX4_EN_MSG_LEVEL	(NETIF_MSG_LINK | NETIF_MSG_IFDOWN)
 
-#define en_print(level, priv, format, arg...)			\
-	{							\
-	if ((priv)->registered)					\
-		printk(level "%s: %s: " format, DRV_NAME,	\
-			(priv->dev)->name, ## arg);		\
-	else							\
-		printk(level "%s: %s: Port %d: " format,	\
-			DRV_NAME, dev_name(&priv->mdev->pdev->dev), \
-			(priv)->port, ## arg);			\
-	}
-
-#define en_dbg(mlevel, priv, format, arg...)			\
-	{							\
-	if (NETIF_MSG_##mlevel & priv->msg_enable)		\
-		en_print(KERN_DEBUG, priv, format, ## arg)	\
-	}
-#define en_warn(priv, format, arg...)				\
-	en_print(KERN_WARNING, priv, format, ## arg)
-#define en_err(priv, format, arg...)				\
-	en_print(KERN_ERR, priv, format, ## arg)
-
-#define mlx4_err(mdev, format, arg...) \
-	printk(KERN_ERR "%s %s: " format , DRV_NAME ,\
-		dev_name(&mdev->pdev->dev) , ## arg)
-#define mlx4_info(mdev, format, arg...) \
-	printk(KERN_INFO "%s %s: " format , DRV_NAME ,\
-		dev_name(&mdev->pdev->dev) , ## arg)
-#define mlx4_warn(mdev, format, arg...) \
-	printk(KERN_WARNING "%s %s: " format , DRV_NAME ,\
-		dev_name(&mdev->pdev->dev) , ## arg)
-
 /*
  * Device constants
  */
@@ -568,4 +536,34 @@
  * Globals
  */
 extern const struct ethtool_ops mlx4_en_ethtool_ops;
+
+
+
+/*
+ * printk / logging functions
+ */
+
+int en_print(const char *level, const struct mlx4_en_priv *priv,
+	     const char *format, ...) __attribute__ ((format (printf, 3, 4)));
+
+#define en_dbg(mlevel, priv, format, arg...)			\
+do {								\
+	if (NETIF_MSG_##mlevel & priv->msg_enable)		\
+		en_print(KERN_DEBUG, priv, format, ##arg);	\
+} while (0)
+#define en_warn(priv, format, arg...)			\
+	en_print(KERN_WARNING, priv, format, ##arg)
+#define en_err(priv, format, arg...)			\
+	en_print(KERN_ERR, priv, format, ##arg)
+
+#define mlx4_err(mdev, format, arg...)			\
+	pr_err("%s %s: " format, DRV_NAME,		\
+	       dev_name(&mdev->pdev->dev), ##arg)
+#define mlx4_info(mdev, format, arg...)			\
+	pr_info("%s %s: " format, DRV_NAME,		\
+		dev_name(&mdev->pdev->dev), ##arg)
+#define mlx4_warn(mdev, format, arg...)			\
+	pr_warning("%s %s: " format, DRV_NAME,		\
+		   dev_name(&mdev->pdev->dev), ##arg)
+
 #endif
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index 3dc69be..9c188bd 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -58,7 +58,7 @@
 	__be32 mtt_sz;
 	__be32 entity_size;
 	__be32 first_byte_offset;
-} __attribute__((packed));
+} __packed;
 
 #define MLX4_MPT_FLAG_SW_OWNS	    (0xfUL << 28)
 #define MLX4_MPT_FLAG_FREE	    (0x3UL << 28)
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 73bb8ea..2d488ab 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1640,6 +1640,11 @@
 	}
 }
 
+static int mv643xx_eth_set_flags(struct net_device *dev, u32 data)
+{
+	return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO);
+}
+
 static int mv643xx_eth_get_sset_count(struct net_device *dev, int sset)
 {
 	if (sset == ETH_SS_STATS)
@@ -1665,7 +1670,7 @@
 	.get_strings		= mv643xx_eth_get_strings,
 	.get_ethtool_stats	= mv643xx_eth_get_ethtool_stats,
 	.get_flags		= ethtool_op_get_flags,
-	.set_flags		= ethtool_op_set_flags,
+	.set_flags		= mv643xx_eth_set_flags,
 	.get_sset_count		= mv643xx_eth_get_sset_count,
 };
 
@@ -2456,7 +2461,7 @@
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
 
 	if (mp->phy != NULL)
-		return phy_mii_ioctl(mp->phy, if_mii(ifr), cmd);
+		return phy_mii_ioctl(mp->phy, ifr, cmd);
 
 	return -EOPNOTSUPP;
 }
@@ -2670,7 +2675,8 @@
 	 * Detect hardware parameters.
 	 */
 	msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000;
-	msp->tx_csum_limit = pd->tx_csum_limit ? pd->tx_csum_limit : 9 * 1024;
+	msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ?
+					pd->tx_csum_limit : 9 * 1024;
 	infer_hw_params(msp);
 
 	platform_set_drvdata(pdev, msp);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index e0b47cc..d771d16 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1730,8 +1730,7 @@
 	if (csum_enabled)
 		mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
 	else {
-		u32 flags = ethtool_op_get_flags(netdev);
-		err = ethtool_op_set_flags(netdev, (flags & ~ETH_FLAG_LRO));
+		netdev->features &= ~NETIF_F_LRO;
 		mgp->csum_flag = 0;
 
 	}
@@ -1900,6 +1899,11 @@
 	return mgp->msg_enable;
 }
 
+static int myri10ge_set_flags(struct net_device *netdev, u32 value)
+{
+	return ethtool_op_set_flags(netdev, value, ETH_FLAG_LRO);
+}
+
 static const struct ethtool_ops myri10ge_ethtool_ops = {
 	.get_settings = myri10ge_get_settings,
 	.get_drvinfo = myri10ge_get_drvinfo,
@@ -1920,7 +1924,7 @@
 	.set_msglevel = myri10ge_set_msglevel,
 	.get_msglevel = myri10ge_get_msglevel,
 	.get_flags = ethtool_op_get_flags,
-	.set_flags = ethtool_op_set_flags
+	.set_flags = myri10ge_set_flags
 };
 
 static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss)
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 2a17b50..a6033d4 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -548,7 +548,6 @@
 	dma_addr_t tx_dma[TX_RING_SIZE];
 	struct net_device *dev;
 	struct napi_struct napi;
-	struct net_device_stats stats;
 	/* Media monitoring timer */
 	struct timer_list timer;
 	/* Frequently used values: keep some adjacent for cache effect */
@@ -1906,7 +1905,7 @@
 	enable_irq(dev->irq);
 
 	dev->trans_start = jiffies; /* prevent tx timeout */
-	np->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	netif_wake_queue(dev);
 }
 
@@ -2009,7 +2008,7 @@
 				np->tx_dma[i], np->tx_skbuff[i]->len,
 				PCI_DMA_TODEVICE);
 			dev_kfree_skb(np->tx_skbuff[i]);
-			np->stats.tx_dropped++;
+			dev->stats.tx_dropped++;
 		}
 		np->tx_skbuff[i] = NULL;
 	}
@@ -2115,7 +2114,7 @@
 		writel(TxOn, ioaddr + ChipCmd);
 	} else {
 		dev_kfree_skb_irq(skb);
-		np->stats.tx_dropped++;
+		dev->stats.tx_dropped++;
 	}
 	spin_unlock_irqrestore(&np->lock, flags);
 
@@ -2140,20 +2139,20 @@
 					dev->name, np->dirty_tx,
 					le32_to_cpu(np->tx_ring[entry].cmd_status));
 		if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescPktOK)) {
-			np->stats.tx_packets++;
-			np->stats.tx_bytes += np->tx_skbuff[entry]->len;
+			dev->stats.tx_packets++;
+			dev->stats.tx_bytes += np->tx_skbuff[entry]->len;
 		} else { /* Various Tx errors */
 			int tx_status =
 				le32_to_cpu(np->tx_ring[entry].cmd_status);
 			if (tx_status & (DescTxAbort|DescTxExcColl))
-				np->stats.tx_aborted_errors++;
+				dev->stats.tx_aborted_errors++;
 			if (tx_status & DescTxFIFO)
-				np->stats.tx_fifo_errors++;
+				dev->stats.tx_fifo_errors++;
 			if (tx_status & DescTxCarrier)
-				np->stats.tx_carrier_errors++;
+				dev->stats.tx_carrier_errors++;
 			if (tx_status & DescTxOOWCol)
-				np->stats.tx_window_errors++;
-			np->stats.tx_errors++;
+				dev->stats.tx_window_errors++;
+			dev->stats.tx_errors++;
 		}
 		pci_unmap_single(np->pci_dev,np->tx_dma[entry],
 					np->tx_skbuff[entry]->len,
@@ -2301,7 +2300,7 @@
 						"buffers, entry %#08x "
 						"status %#08x.\n", dev->name,
 						np->cur_rx, desc_status);
-				np->stats.rx_length_errors++;
+				dev->stats.rx_length_errors++;
 
 				/* The RX state machine has probably
 				 * locked up beneath us.  Follow the
@@ -2321,15 +2320,15 @@
 
 			} else {
 				/* There was an error. */
-				np->stats.rx_errors++;
+				dev->stats.rx_errors++;
 				if (desc_status & (DescRxAbort|DescRxOver))
-					np->stats.rx_over_errors++;
+					dev->stats.rx_over_errors++;
 				if (desc_status & (DescRxLong|DescRxRunt))
-					np->stats.rx_length_errors++;
+					dev->stats.rx_length_errors++;
 				if (desc_status & (DescRxInvalid|DescRxAlign))
-					np->stats.rx_frame_errors++;
+					dev->stats.rx_frame_errors++;
 				if (desc_status & DescRxCRC)
-					np->stats.rx_crc_errors++;
+					dev->stats.rx_crc_errors++;
 			}
 		} else if (pkt_len > np->rx_buf_sz) {
 			/* if this is the tail of a double buffer
@@ -2364,8 +2363,8 @@
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_receive_skb(skb);
-			np->stats.rx_packets++;
-			np->stats.rx_bytes += pkt_len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += pkt_len;
 		}
 		entry = (++np->cur_rx) % RX_RING_SIZE;
 		np->rx_head_desc = &np->rx_ring[entry];
@@ -2428,17 +2427,17 @@
 			printk(KERN_NOTICE "%s: Rx status FIFO overrun\n",
 				dev->name);
 		}
-		np->stats.rx_fifo_errors++;
-		np->stats.rx_errors++;
+		dev->stats.rx_fifo_errors++;
+		dev->stats.rx_errors++;
 	}
 	/* Hmmmmm, it's not clear how to recover from PCI faults. */
 	if (intr_status & IntrPCIErr) {
 		printk(KERN_NOTICE "%s: PCI error %#08x\n", dev->name,
 			intr_status & IntrPCIErr);
-		np->stats.tx_fifo_errors++;
-		np->stats.tx_errors++;
-		np->stats.rx_fifo_errors++;
-		np->stats.rx_errors++;
+		dev->stats.tx_fifo_errors++;
+		dev->stats.tx_errors++;
+		dev->stats.rx_fifo_errors++;
+		dev->stats.rx_errors++;
 	}
 	spin_unlock(&np->lock);
 }
@@ -2446,11 +2445,10 @@
 static void __get_stats(struct net_device *dev)
 {
 	void __iomem * ioaddr = ns_ioaddr(dev);
-	struct netdev_private *np = netdev_priv(dev);
 
 	/* The chip only need report frame silently dropped. */
-	np->stats.rx_crc_errors	+= readl(ioaddr + RxCRCErrs);
-	np->stats.rx_missed_errors += readl(ioaddr + RxMissed);
+	dev->stats.rx_crc_errors += readl(ioaddr + RxCRCErrs);
+	dev->stats.rx_missed_errors += readl(ioaddr + RxMissed);
 }
 
 static struct net_device_stats *get_stats(struct net_device *dev)
@@ -2463,7 +2461,7 @@
 		__get_stats(dev);
 	spin_unlock_irq(&np->lock);
 
-	return &np->stats;
+	return &dev->stats;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c
index 3a41b6a..1261212 100644
--- a/drivers/net/netxen/netxen_nic_ctx.c
+++ b/drivers/net/netxen/netxen_nic_ctx.c
@@ -255,6 +255,19 @@
 }
 
 static void
+nx_fw_cmd_reset_ctx(struct netxen_adapter *adapter)
+{
+
+	netxen_issue_cmd(adapter, adapter->ahw.pci_func, NXHAL_VERSION,
+			adapter->ahw.pci_func, NX_DESTROY_CTX_RESET, 0,
+			NX_CDRP_CMD_DESTROY_RX_CTX);
+
+	netxen_issue_cmd(adapter, adapter->ahw.pci_func, NXHAL_VERSION,
+			adapter->ahw.pci_func, NX_DESTROY_CTX_RESET, 0,
+			NX_CDRP_CMD_DESTROY_TX_CTX);
+}
+
+static void
 nx_fw_cmd_destroy_rx_ctx(struct netxen_adapter *adapter)
 {
 	struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
@@ -685,7 +698,8 @@
 	if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
 		if (test_and_set_bit(__NX_FW_ATTACHED, &adapter->state))
 			goto done;
-
+		if (reset_devices)
+			nx_fw_cmd_reset_ctx(adapter);
 		err = nx_fw_cmd_create_rx_ctx(adapter);
 		if (err)
 			goto err_out_free;
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index 20f7c58..b30de24 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -887,12 +887,19 @@
 	struct netxen_adapter *adapter = netdev_priv(netdev);
 	int hw_lro;
 
+	if (data & ~ETH_FLAG_LRO)
+		return -EINVAL;
+
 	if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO))
 		return -EINVAL;
 
-	ethtool_op_set_flags(netdev, data);
-
-	hw_lro = (data & ETH_FLAG_LRO) ? NETXEN_NIC_LRO_ENABLED : 0;
+	if (data & ETH_FLAG_LRO) {
+		hw_lro = NETXEN_NIC_LRO_ENABLED;
+		netdev->features |= NETIF_F_LRO;
+	} else {
+		hw_lro = 0;
+		netdev->features &= ~NETIF_F_LRO;
+	}
 
 	if (netxen_config_hw_lro(adapter, hw_lro))
 		return -EIO;
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 9bddb5f..33618edc 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -185,7 +185,6 @@
 static void    ni52_rnr_int(struct net_device *dev);
 
 struct priv {
-	struct net_device_stats stats;
 	char __iomem *base;
 	char __iomem *mapped;
 	char __iomem *memtop;
@@ -972,10 +971,10 @@
 					memcpy_fromio(skb->data, p->base + readl(&rbd->buffer), totlen);
 					skb->protocol = eth_type_trans(skb, dev);
 					netif_rx(skb);
-					p->stats.rx_packets++;
-					p->stats.rx_bytes += totlen;
+					dev->stats.rx_packets++;
+					dev->stats.rx_bytes += totlen;
 				} else
-					p->stats.rx_dropped++;
+					dev->stats.rx_dropped++;
 			} else {
 				int rstat;
 				 /* free all RBD's until RBD_LAST is set */
@@ -993,12 +992,12 @@
 				writew(0, &rbd->status);
 				printk(KERN_ERR "%s: received oversized frame! length: %d\n",
 					dev->name, totlen);
-				p->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 			 }
 		} else {/* frame !(ok), only with 'save-bad-frames' */
 			printk(KERN_ERR "%s: oops! rfd-error-status: %04x\n",
 				dev->name, status);
-			p->stats.rx_errors++;
+			dev->stats.rx_errors++;
 		}
 		writeb(0, &p->rfd_top->stat_high);
 		writeb(RFD_SUSP, &p->rfd_top->last); /* maybe exchange by RFD_LAST */
@@ -1043,7 +1042,7 @@
 {
 	struct priv *p = netdev_priv(dev);
 
-	p->stats.rx_errors++;
+	dev->stats.rx_errors++;
 
 	wait_for_scb_cmd(dev);		/* wait for the last cmd, WAIT_4_FULLSTAT?? */
 	writeb(RUC_ABORT, &p->scb->cmd_ruc); /* usually the RU is in the 'no resource'-state .. abort it now. */
@@ -1076,29 +1075,29 @@
 		printk(KERN_ERR "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
 
 	if (status & STAT_OK) {
-		p->stats.tx_packets++;
-		p->stats.collisions += (status & TCMD_MAXCOLLMASK);
+		dev->stats.tx_packets++;
+		dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
 	} else {
-		p->stats.tx_errors++;
+		dev->stats.tx_errors++;
 		if (status & TCMD_LATECOLL) {
 			printk(KERN_ERR "%s: late collision detected.\n",
 				dev->name);
-			p->stats.collisions++;
+			dev->stats.collisions++;
 		} else if (status & TCMD_NOCARRIER) {
-			p->stats.tx_carrier_errors++;
+			dev->stats.tx_carrier_errors++;
 			printk(KERN_ERR "%s: no carrier detected.\n",
 				dev->name);
 		} else if (status & TCMD_LOSTCTS)
 			printk(KERN_ERR "%s: loss of CTS detected.\n",
 				dev->name);
 		else if (status & TCMD_UNDERRUN) {
-			p->stats.tx_fifo_errors++;
+			dev->stats.tx_fifo_errors++;
 			printk(KERN_ERR "%s: DMA underrun detected.\n",
 				dev->name);
 		} else if (status & TCMD_MAXCOLL) {
 			printk(KERN_ERR "%s: Max. collisions exceeded.\n",
 				dev->name);
-			p->stats.collisions += 16;
+			dev->stats.collisions += 16;
 		}
 	}
 #if (NUM_XMIT_BUFFS > 1)
@@ -1286,12 +1285,12 @@
 	ovrn = readw(&p->scb->ovrn_errs);
 	writew(0, &p->scb->ovrn_errs);
 
-	p->stats.rx_crc_errors += crc;
-	p->stats.rx_fifo_errors += ovrn;
-	p->stats.rx_frame_errors += aln;
-	p->stats.rx_dropped += rsc;
+	dev->stats.rx_crc_errors += crc;
+	dev->stats.rx_fifo_errors += ovrn;
+	dev->stats.rx_frame_errors += aln;
+	dev->stats.rx_dropped += rsc;
 
-	return &p->stats;
+	return &dev->stats;
 }
 
 /********************************************************
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 63e8e38..b9b9508 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -3330,10 +3330,12 @@
 	for (; (p = *pp) != NULL; pp = (struct page **) &p->mapping) {
 		if (p->index == addr) {
 			*link = pp;
-			break;
+			goto found;
 		}
 	}
+	BUG();
 
+found:
 	return p;
 }
 
@@ -7920,14 +7922,7 @@
 
 static int niu_set_flags(struct net_device *dev, u32 data)
 {
-	if (data & (ETH_FLAG_LRO | ETH_FLAG_NTUPLE))
-		return -EOPNOTSUPP;
-
-	if (data & ETH_FLAG_RXHASH)
-		dev->features |= NETIF_F_RXHASH;
-	else
-		dev->features &= ~NETIF_F_RXHASH;
-	return 0;
+	return ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH);
 }
 
 static const struct ethtool_ops niu_ethtool_ops = {
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index e88e97c..5a3488f 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -424,7 +424,6 @@
 
 
 struct ns83820 {
-	struct net_device_stats	stats;
 	u8			__iomem *base;
 
 	struct pci_dev		*pci_dev;
@@ -918,9 +917,9 @@
 			if (unlikely(!skb))
 				goto netdev_mangle_me_harder_failed;
 			if (cmdsts & CMDSTS_DEST_MULTI)
-				dev->stats.multicast ++;
-			dev->stats.rx_packets ++;
-			dev->stats.rx_bytes += len;
+				ndev->stats.multicast++;
+			ndev->stats.rx_packets++;
+			ndev->stats.rx_bytes += len;
 			if ((extsts & 0x002a0000) && !(extsts & 0x00540000)) {
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
 			} else {
@@ -940,7 +939,7 @@
 #endif
 			if (NET_RX_DROP == rx_rc) {
 netdev_mangle_me_harder_failed:
-				dev->stats.rx_dropped ++;
+				ndev->stats.rx_dropped++;
 			}
 		} else {
 			kfree_skb(skb);
@@ -1008,11 +1007,11 @@
 		dma_addr_t addr;
 
 		if (cmdsts & CMDSTS_ERR)
-			dev->stats.tx_errors ++;
+			ndev->stats.tx_errors++;
 		if (cmdsts & CMDSTS_OK)
-			dev->stats.tx_packets ++;
+			ndev->stats.tx_packets++;
 		if (cmdsts & CMDSTS_OK)
-			dev->stats.tx_bytes += cmdsts & 0xffff;
+			ndev->stats.tx_bytes += cmdsts & 0xffff;
 
 		dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
 			tx_done_idx, dev->tx_free_idx, cmdsts);
@@ -1212,20 +1211,21 @@
 
 static void ns83820_update_stats(struct ns83820 *dev)
 {
+	struct net_device *ndev = dev->ndev;
 	u8 __iomem *base = dev->base;
 
 	/* the DP83820 will freeze counters, so we need to read all of them */
-	dev->stats.rx_errors		+= readl(base + 0x60) & 0xffff;
-	dev->stats.rx_crc_errors	+= readl(base + 0x64) & 0xffff;
-	dev->stats.rx_missed_errors	+= readl(base + 0x68) & 0xffff;
-	dev->stats.rx_frame_errors	+= readl(base + 0x6c) & 0xffff;
-	/*dev->stats.rx_symbol_errors +=*/ readl(base + 0x70);
-	dev->stats.rx_length_errors	+= readl(base + 0x74) & 0xffff;
-	dev->stats.rx_length_errors	+= readl(base + 0x78) & 0xffff;
-	/*dev->stats.rx_badopcode_errors += */ readl(base + 0x7c);
-	/*dev->stats.rx_pause_count += */  readl(base + 0x80);
-	/*dev->stats.tx_pause_count += */  readl(base + 0x84);
-	dev->stats.tx_carrier_errors	+= readl(base + 0x88) & 0xff;
+	ndev->stats.rx_errors		+= readl(base + 0x60) & 0xffff;
+	ndev->stats.rx_crc_errors	+= readl(base + 0x64) & 0xffff;
+	ndev->stats.rx_missed_errors	+= readl(base + 0x68) & 0xffff;
+	ndev->stats.rx_frame_errors	+= readl(base + 0x6c) & 0xffff;
+	/*ndev->stats.rx_symbol_errors +=*/ readl(base + 0x70);
+	ndev->stats.rx_length_errors	+= readl(base + 0x74) & 0xffff;
+	ndev->stats.rx_length_errors	+= readl(base + 0x78) & 0xffff;
+	/*ndev->stats.rx_badopcode_errors += */ readl(base + 0x7c);
+	/*ndev->stats.rx_pause_count += */  readl(base + 0x80);
+	/*ndev->stats.tx_pause_count += */  readl(base + 0x84);
+	ndev->stats.tx_carrier_errors	+= readl(base + 0x88) & 0xff;
 }
 
 static struct net_device_stats *ns83820_get_stats(struct net_device *ndev)
@@ -1237,7 +1237,7 @@
 	ns83820_update_stats(dev);
 	spin_unlock_irq(&dev->misc_lock);
 
-	return &dev->stats;
+	return &ndev->stats;
 }
 
 /* Let ethtool retrieve info */
@@ -1464,12 +1464,12 @@
 
 	if (unlikely(ISR_RXSOVR & isr)) {
 		//printk("overrun: rxsovr\n");
-		dev->stats.rx_fifo_errors ++;
+		ndev->stats.rx_fifo_errors++;
 	}
 
 	if (unlikely(ISR_RXORN & isr)) {
 		//printk("overrun: rxorn\n");
-		dev->stats.rx_fifo_errors ++;
+		ndev->stats.rx_fifo_errors++;
 	}
 
 	if ((ISR_RXRCMP & isr) && dev->rx_info.up)
diff --git a/drivers/net/octeon/octeon_mgmt.c b/drivers/net/octeon/octeon_mgmt.c
index 000e792..b264f0f 100644
--- a/drivers/net/octeon/octeon_mgmt.c
+++ b/drivers/net/octeon/octeon_mgmt.c
@@ -620,7 +620,7 @@
 	if (!p->phydev)
 		return -EINVAL;
 
-	return phy_mii_ioctl(p->phydev, if_mii(rq), cmd);
+	return phy_mii_ioctl(p->phydev, rq, cmd);
 }
 
 static void octeon_mgmt_adjust_link(struct net_device *netdev)
@@ -1067,7 +1067,7 @@
 #endif
 };
 
-static int __init octeon_mgmt_probe(struct platform_device *pdev)
+static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
 {
 	struct resource *res_irq;
 	struct net_device *netdev;
@@ -1124,7 +1124,7 @@
 	return -ENOENT;
 }
 
-static int __exit octeon_mgmt_remove(struct platform_device *pdev)
+static int __devexit octeon_mgmt_remove(struct platform_device *pdev)
 {
 	struct net_device *netdev = dev_get_drvdata(&pdev->dev);
 
@@ -1139,7 +1139,7 @@
 		.owner		= THIS_MODULE,
 	},
 	.probe		= octeon_mgmt_probe,
-	.remove		= __exit_p(octeon_mgmt_remove),
+	.remove		= __devexit_p(octeon_mgmt_remove),
 };
 
 extern void octeon_mdiobus_force_mod_depencency(void);
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index cecdbbd..4accd83 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -685,7 +685,7 @@
 }
 
 static struct phy_driver bcm5411_driver = {
-	.phy_id		= 0x00206070,
+	.phy_id		= PHY_ID_BCM5411,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM5411",
 	.features	= PHY_GBIT_FEATURES |
@@ -700,7 +700,7 @@
 };
 
 static struct phy_driver bcm5421_driver = {
-	.phy_id		= 0x002060e0,
+	.phy_id		= PHY_ID_BCM5421,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM5421",
 	.features	= PHY_GBIT_FEATURES |
@@ -715,7 +715,7 @@
 };
 
 static struct phy_driver bcm5461_driver = {
-	.phy_id		= 0x002060c0,
+	.phy_id		= PHY_ID_BCM5461,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM5461",
 	.features	= PHY_GBIT_FEATURES |
@@ -730,7 +730,7 @@
 };
 
 static struct phy_driver bcm5464_driver = {
-	.phy_id		= 0x002060b0,
+	.phy_id		= PHY_ID_BCM5464,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM5464",
 	.features	= PHY_GBIT_FEATURES |
@@ -745,7 +745,7 @@
 };
 
 static struct phy_driver bcm5481_driver = {
-	.phy_id		= 0x0143bca0,
+	.phy_id		= PHY_ID_BCM5481,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM5481",
 	.features	= PHY_GBIT_FEATURES |
@@ -760,7 +760,7 @@
 };
 
 static struct phy_driver bcm5482_driver = {
-	.phy_id		= 0x0143bcb0,
+	.phy_id		= PHY_ID_BCM5482,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM5482",
 	.features	= PHY_GBIT_FEATURES |
@@ -834,6 +834,21 @@
 	.driver		= { .owner = THIS_MODULE },
 };
 
+static struct phy_driver bcm5241_driver = {
+	.phy_id		= PHY_ID_BCM5241,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCM5241",
+	.features	= PHY_BASIC_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= brcm_fet_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= brcm_fet_ack_interrupt,
+	.config_intr	= brcm_fet_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
 static int __init broadcom_init(void)
 {
 	int ret;
@@ -868,8 +883,13 @@
 	ret = phy_driver_register(&bcmac131_driver);
 	if (ret)
 		goto out_ac131;
+	ret = phy_driver_register(&bcm5241_driver);
+	if (ret)
+		goto out_5241;
 	return ret;
 
+out_5241:
+	phy_driver_unregister(&bcmac131_driver);
 out_ac131:
 	phy_driver_unregister(&bcm57780_driver);
 out_57780:
@@ -894,6 +914,7 @@
 
 static void __exit broadcom_exit(void)
 {
+	phy_driver_unregister(&bcm5241_driver);
 	phy_driver_unregister(&bcmac131_driver);
 	phy_driver_unregister(&bcm57780_driver);
 	phy_driver_unregister(&bcm50610m_driver);
@@ -910,16 +931,17 @@
 module_exit(broadcom_exit);
 
 static struct mdio_device_id broadcom_tbl[] = {
-	{ 0x00206070, 0xfffffff0 },
-	{ 0x002060e0, 0xfffffff0 },
-	{ 0x002060c0, 0xfffffff0 },
-	{ 0x002060b0, 0xfffffff0 },
-	{ 0x0143bca0, 0xfffffff0 },
-	{ 0x0143bcb0, 0xfffffff0 },
+	{ PHY_ID_BCM5411, 0xfffffff0 },
+	{ PHY_ID_BCM5421, 0xfffffff0 },
+	{ PHY_ID_BCM5461, 0xfffffff0 },
+	{ PHY_ID_BCM5464, 0xfffffff0 },
+	{ PHY_ID_BCM5482, 0xfffffff0 },
+	{ PHY_ID_BCM5482, 0xfffffff0 },
 	{ PHY_ID_BCM50610, 0xfffffff0 },
 	{ PHY_ID_BCM50610M, 0xfffffff0 },
 	{ PHY_ID_BCM57780, 0xfffffff0 },
 	{ PHY_ID_BCMAC131, 0xfffffff0 },
+	{ PHY_ID_BCM5241, 0xfffffff0 },
 	{ }
 };
 
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
index 439adaf..3f2583f 100644
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -116,6 +116,8 @@
 	.config_init	= &ip175c_config_init,
 	.config_aneg	= &ip175c_config_aneg,
 	.read_status	= &ip175c_read_status,
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
 	.driver		= { .owner = THIS_MODULE,},
 };
 
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 5a1bd5d..0101f2b 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -68,6 +68,15 @@
 #define MII_M1111_COPPER		0
 #define MII_M1111_FIBER			1
 
+#define MII_88E1121_PHY_MSCR_PAGE	2
+#define MII_88E1121_PHY_MSCR_REG	21
+#define MII_88E1121_PHY_MSCR_RX_DELAY	BIT(5)
+#define MII_88E1121_PHY_MSCR_TX_DELAY	BIT(4)
+#define MII_88E1121_PHY_MSCR_DELAY_MASK	(~(0x3 << 4))
+
+#define MII_88EC048_PHY_MSCR1_REG	16
+#define MII_88EC048_PHY_MSCR1_PAD_ODD	BIT(6)
+
 #define MII_88E1121_PHY_LED_CTRL	16
 #define MII_88E1121_PHY_LED_PAGE	3
 #define MII_88E1121_PHY_LED_DEF		0x0030
@@ -179,7 +188,30 @@
 
 static int m88e1121_config_aneg(struct phy_device *phydev)
 {
-	int err, temp;
+	int err, oldpage, mscr;
+
+	oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+
+	err = phy_write(phydev, MII_88E1121_PHY_PAGE,
+			MII_88E1121_PHY_MSCR_PAGE);
+	if (err < 0)
+		return err;
+	mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
+		MII_88E1121_PHY_MSCR_DELAY_MASK;
+
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+		mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
+			 MII_88E1121_PHY_MSCR_TX_DELAY);
+	else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+		mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
+	else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+		mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
+
+	err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
+	if (err < 0)
+		return err;
+
+	phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
 
 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
 	if (err < 0)
@@ -190,17 +222,42 @@
 	if (err < 0)
 		return err;
 
-	temp = phy_read(phydev, MII_88E1121_PHY_PAGE);
+	oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
 
 	phy_write(phydev, MII_88E1121_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
 	phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF);
-	phy_write(phydev, MII_88E1121_PHY_PAGE, temp);
+	phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
 
 	err = genphy_config_aneg(phydev);
 
 	return err;
 }
 
+static int m88ec048_config_aneg(struct phy_device *phydev)
+{
+	int err, oldpage, mscr;
+
+	oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+
+	err = phy_write(phydev, MII_88E1121_PHY_PAGE,
+			MII_88E1121_PHY_MSCR_PAGE);
+	if (err < 0)
+		return err;
+
+	mscr = phy_read(phydev, MII_88EC048_PHY_MSCR1_REG);
+	mscr |= MII_88EC048_PHY_MSCR1_PAD_ODD;
+
+	err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+	if (err < 0)
+		return err;
+
+	return m88e1121_config_aneg(phydev);
+}
+
 static int m88e1111_config_init(struct phy_device *phydev)
 {
 	int err;
@@ -595,6 +652,19 @@
 		.driver = { .owner = THIS_MODULE },
 	},
 	{
+		.phy_id = MARVELL_PHY_ID_88EC048,
+		.phy_id_mask = MARVELL_PHY_ID_MASK,
+		.name = "Marvell 88EC048",
+		.features = PHY_GBIT_FEATURES,
+		.flags = PHY_HAS_INTERRUPT,
+		.config_aneg = &m88ec048_config_aneg,
+		.read_status = &marvell_read_status,
+		.ack_interrupt = &marvell_ack_interrupt,
+		.config_intr = &marvell_config_intr,
+		.did_interrupt = &m88e1121_did_interrupt,
+		.driver = { .owner = THIS_MODULE },
+	},
+	{
 		.phy_id = MARVELL_PHY_ID_88E1145,
 		.phy_id_mask = MARVELL_PHY_ID_MASK,
 		.name = "Marvell 88E1145",
@@ -659,6 +729,7 @@
 	{ 0x01410cb0, 0xfffffff0 },
 	{ 0x01410cd0, 0xfffffff0 },
 	{ 0x01410e30, 0xfffffff0 },
+	{ 0x01410e90, 0xfffffff0 },
 	{ }
 };
 
diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c
index f443d43..bd12ba9 100644
--- a/drivers/net/phy/mdio-octeon.c
+++ b/drivers/net/phy/mdio-octeon.c
@@ -85,7 +85,7 @@
 	return 0;
 }
 
-static int __init octeon_mdiobus_probe(struct platform_device *pdev)
+static int __devinit octeon_mdiobus_probe(struct platform_device *pdev)
 {
 	struct octeon_mdiobus *bus;
 	union cvmx_smix_en smi_en;
@@ -143,7 +143,7 @@
 	return err;
 }
 
-static int __exit octeon_mdiobus_remove(struct platform_device *pdev)
+static int __devexit octeon_mdiobus_remove(struct platform_device *pdev)
 {
 	struct octeon_mdiobus *bus;
 	union cvmx_smix_en smi_en;
@@ -163,7 +163,7 @@
 		.owner		= THIS_MODULE,
 	},
 	.probe		= octeon_mdiobus_probe,
-	.remove		= __exit_p(octeon_mdiobus_remove),
+	.remove		= __devexit_p(octeon_mdiobus_remove),
 };
 
 void octeon_mdiobus_force_mod_depencency(void)
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 0692f75..8bb7db6 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -12,7 +12,8 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  *
- * Support : ksz9021 , vsc8201, ks8001
+ * Support : ksz9021 1000/100/10 phy from Micrel
+ *		ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy
  */
 
 #include <linux/kernel.h>
@@ -20,37 +21,146 @@
 #include <linux/phy.h>
 
 #define	PHY_ID_KSZ9021			0x00221611
-#define	PHY_ID_VSC8201			0x000FC413
+#define	PHY_ID_KS8737			0x00221720
+#define	PHY_ID_KS8041			0x00221510
+#define	PHY_ID_KS8051			0x00221550
+/* both for ks8001 Rev. A/B, and for ks8721 Rev 3. */
 #define	PHY_ID_KS8001			0x0022161A
 
+/* general Interrupt control/status reg in vendor specific block. */
+#define MII_KSZPHY_INTCS			0x1B
+#define	KSZPHY_INTCS_JABBER			(1 << 15)
+#define	KSZPHY_INTCS_RECEIVE_ERR		(1 << 14)
+#define	KSZPHY_INTCS_PAGE_RECEIVE		(1 << 13)
+#define	KSZPHY_INTCS_PARELLEL			(1 << 12)
+#define	KSZPHY_INTCS_LINK_PARTNER_ACK		(1 << 11)
+#define	KSZPHY_INTCS_LINK_DOWN			(1 << 10)
+#define	KSZPHY_INTCS_REMOTE_FAULT		(1 << 9)
+#define	KSZPHY_INTCS_LINK_UP			(1 << 8)
+#define	KSZPHY_INTCS_ALL			(KSZPHY_INTCS_LINK_UP |\
+						KSZPHY_INTCS_LINK_DOWN)
+
+/* general PHY control reg in vendor specific block. */
+#define	MII_KSZPHY_CTRL			0x1F
+/* bitmap of PHY register to set interrupt mode */
+#define KSZPHY_CTRL_INT_ACTIVE_HIGH		(1 << 9)
+#define KSZ9021_CTRL_INT_ACTIVE_HIGH		(1 << 14)
+#define KS8737_CTRL_INT_ACTIVE_HIGH		(1 << 14)
+
+static int kszphy_ack_interrupt(struct phy_device *phydev)
+{
+	/* bit[7..0] int status, which is a read and clear register. */
+	int rc;
+
+	rc = phy_read(phydev, MII_KSZPHY_INTCS);
+
+	return (rc < 0) ? rc : 0;
+}
+
+static int kszphy_set_interrupt(struct phy_device *phydev)
+{
+	int temp;
+	temp = (PHY_INTERRUPT_ENABLED == phydev->interrupts) ?
+		KSZPHY_INTCS_ALL : 0;
+	return phy_write(phydev, MII_KSZPHY_INTCS, temp);
+}
+
+static int kszphy_config_intr(struct phy_device *phydev)
+{
+	int temp, rc;
+
+	/* set the interrupt pin active low */
+	temp = phy_read(phydev, MII_KSZPHY_CTRL);
+	temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH;
+	phy_write(phydev, MII_KSZPHY_CTRL, temp);
+	rc = kszphy_set_interrupt(phydev);
+	return rc < 0 ? rc : 0;
+}
+
+static int ksz9021_config_intr(struct phy_device *phydev)
+{
+	int temp, rc;
+
+	/* set the interrupt pin active low */
+	temp = phy_read(phydev, MII_KSZPHY_CTRL);
+	temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH;
+	phy_write(phydev, MII_KSZPHY_CTRL, temp);
+	rc = kszphy_set_interrupt(phydev);
+	return rc < 0 ? rc : 0;
+}
+
+static int ks8737_config_intr(struct phy_device *phydev)
+{
+	int temp, rc;
+
+	/* set the interrupt pin active low */
+	temp = phy_read(phydev, MII_KSZPHY_CTRL);
+	temp &= ~KS8737_CTRL_INT_ACTIVE_HIGH;
+	phy_write(phydev, MII_KSZPHY_CTRL, temp);
+	rc = kszphy_set_interrupt(phydev);
+	return rc < 0 ? rc : 0;
+}
 
 static int kszphy_config_init(struct phy_device *phydev)
 {
 	return 0;
 }
 
-
-static struct phy_driver ks8001_driver = {
-	.phy_id		= PHY_ID_KS8001,
-	.name		= "Micrel KS8001",
+static struct phy_driver ks8737_driver = {
+	.phy_id		= PHY_ID_KS8737,
 	.phy_id_mask	= 0x00fffff0,
-	.features	= PHY_BASIC_FEATURES,
-	.flags		= PHY_POLL,
+	.name		= "Micrel KS8737",
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 	.config_init	= kszphy_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= ks8737_config_intr,
 	.driver		= { .owner = THIS_MODULE,},
 };
 
-static struct phy_driver vsc8201_driver = {
-	.phy_id		= PHY_ID_VSC8201,
-	.name		= "Micrel VSC8201",
+static struct phy_driver ks8041_driver = {
+	.phy_id		= PHY_ID_KS8041,
 	.phy_id_mask	= 0x00fffff0,
-	.features	= PHY_BASIC_FEATURES,
-	.flags		= PHY_POLL,
+	.name		= "Micrel KS8041",
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
+				| SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 	.config_init	= kszphy_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= kszphy_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver ks8051_driver = {
+	.phy_id		= PHY_ID_KS8051,
+	.phy_id_mask	= 0x00fffff0,
+	.name		= "Micrel KS8051",
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
+				| SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= kszphy_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= kszphy_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver ks8001_driver = {
+	.phy_id		= PHY_ID_KS8001,
+	.name		= "Micrel KS8001 or KS8721",
+	.phy_id_mask	= 0x00fffff0,
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= kszphy_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= kszphy_config_intr,
 	.driver		= { .owner = THIS_MODULE,},
 };
 
@@ -58,11 +168,14 @@
 	.phy_id		= PHY_ID_KSZ9021,
 	.phy_id_mask	= 0x000fff10,
 	.name		= "Micrel KSZ9021 Gigabit PHY",
-	.features	= PHY_GBIT_FEATURES | SUPPORTED_Pause,
-	.flags		= PHY_POLL,
+	.features	= (PHY_GBIT_FEATURES | SUPPORTED_Pause
+				| SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 	.config_init	= kszphy_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= ksz9021_config_intr,
 	.driver		= { .owner = THIS_MODULE, },
 };
 
@@ -73,17 +186,29 @@
 	ret = phy_driver_register(&ks8001_driver);
 	if (ret)
 		goto err1;
-	ret = phy_driver_register(&vsc8201_driver);
-	if (ret)
-		goto err2;
 
 	ret = phy_driver_register(&ksz9021_driver);
 	if (ret)
+		goto err2;
+
+	ret = phy_driver_register(&ks8737_driver);
+	if (ret)
 		goto err3;
+	ret = phy_driver_register(&ks8041_driver);
+	if (ret)
+		goto err4;
+	ret = phy_driver_register(&ks8051_driver);
+	if (ret)
+		goto err5;
+
 	return 0;
 
+err5:
+	phy_driver_unregister(&ks8041_driver);
+err4:
+	phy_driver_unregister(&ks8737_driver);
 err3:
-	phy_driver_unregister(&vsc8201_driver);
+	phy_driver_unregister(&ksz9021_driver);
 err2:
 	phy_driver_unregister(&ks8001_driver);
 err1:
@@ -93,8 +218,10 @@
 static void __exit ksphy_exit(void)
 {
 	phy_driver_unregister(&ks8001_driver);
-	phy_driver_unregister(&vsc8201_driver);
+	phy_driver_unregister(&ks8737_driver);
 	phy_driver_unregister(&ksz9021_driver);
+	phy_driver_unregister(&ks8041_driver);
+	phy_driver_unregister(&ks8051_driver);
 }
 
 module_init(ksphy_init);
@@ -106,8 +233,10 @@
 
 static struct mdio_device_id micrel_tbl[] = {
 	{ PHY_ID_KSZ9021, 0x000fff10 },
-	{ PHY_ID_VSC8201, 0x00fffff0 },
 	{ PHY_ID_KS8001, 0x00fffff0 },
+	{ PHY_ID_KS8737, 0x00fffff0 },
+	{ PHY_ID_KS8041, 0x00fffff0 },
+	{ PHY_ID_KS8051, 0x00fffff0 },
 	{ }
 };
 
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 64be466..5130db8 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -309,8 +309,9 @@
  * current state.  Use at own risk.
  */
 int phy_mii_ioctl(struct phy_device *phydev,
-		struct mii_ioctl_data *mii_data, int cmd)
+		struct ifreq *ifr, int cmd)
 {
+	struct mii_ioctl_data *mii_data = if_mii(ifr);
 	u16 val = mii_data->val_in;
 
 	switch (cmd) {
@@ -360,6 +361,11 @@
 		}
 		break;
 
+	case SIOCSHWTSTAMP:
+		if (phydev->drv->hwtstamp)
+			return phydev->drv->hwtstamp(phydev, ifr);
+		/* fall through */
+
 	default:
 		return -EOPNOTSUPP;
 	}
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 1a99bb2..c076119 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -460,6 +460,7 @@
 	}
 
 	phydev->attached_dev = dev;
+	dev->phydev = phydev;
 
 	phydev->dev_flags = flags;
 
@@ -513,6 +514,7 @@
  */
 void phy_detach(struct phy_device *phydev)
 {
+	phydev->attached_dev->phydev = NULL;
 	phydev->attached_dev = NULL;
 
 	/* If the device had no specific driver before (i.e. - it
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 1b2c291..6695a51 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -40,7 +40,6 @@
 #include <linux/if_arp.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/rwsem.h>
 #include <linux/stddef.h>
@@ -69,7 +68,6 @@
 
 #define MPHDRLEN	6	/* multilink protocol header length */
 #define MPHDRLEN_SSN	4	/* ditto with short sequence numbers */
-#define MIN_FRAG_SIZE	64
 
 /*
  * An instance of /dev/ppp can be associated with either a ppp
@@ -181,6 +179,7 @@
  * channel.downl.
  */
 
+static DEFINE_MUTEX(ppp_mutex);
 static atomic_t ppp_unit_count = ATOMIC_INIT(0);
 static atomic_t channel_count = ATOMIC_INIT(0);
 
@@ -363,7 +362,6 @@
  */
 static int ppp_open(struct inode *inode, struct file *file)
 {
-	cycle_kernel_lock();
 	/*
 	 * This could (should?) be enforced by the permissions on /dev/ppp.
 	 */
@@ -539,14 +537,9 @@
 	}
 
 	len = uprog.len * sizeof(struct sock_filter);
-	code = kmalloc(len, GFP_KERNEL);
-	if (code == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(code, uprog.filter, len)) {
-		kfree(code);
-		return -EFAULT;
-	}
+	code = memdup_user(uprog.filter, len);
+	if (IS_ERR(code))
+		return PTR_ERR(code);
 
 	err = sk_chk_filter(code, uprog.len);
 	if (err) {
@@ -588,7 +581,7 @@
 		 * this fd and reopening /dev/ppp.
 		 */
 		err = -EINVAL;
-		lock_kernel();
+		mutex_lock(&ppp_mutex);
 		if (pf->kind == INTERFACE) {
 			ppp = PF_TO_PPP(pf);
 			if (file == ppp->owner)
@@ -600,7 +593,7 @@
 		} else
 			printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%ld\n",
 			       atomic_long_read(&file->f_count));
-		unlock_kernel();
+		mutex_unlock(&ppp_mutex);
 		return err;
 	}
 
@@ -608,7 +601,7 @@
 		struct channel *pch;
 		struct ppp_channel *chan;
 
-		lock_kernel();
+		mutex_lock(&ppp_mutex);
 		pch = PF_TO_CHANNEL(pf);
 
 		switch (cmd) {
@@ -630,7 +623,7 @@
 				err = chan->ops->ioctl(chan, cmd, arg);
 			up_read(&pch->chan_sem);
 		}
-		unlock_kernel();
+		mutex_unlock(&ppp_mutex);
 		return err;
 	}
 
@@ -640,7 +633,7 @@
 		return -EINVAL;
 	}
 
-	lock_kernel();
+	mutex_lock(&ppp_mutex);
 	ppp = PF_TO_PPP(pf);
 	switch (cmd) {
 	case PPPIOCSMRU:
@@ -788,7 +781,7 @@
 	default:
 		err = -ENOTTY;
 	}
-	unlock_kernel();
+	mutex_unlock(&ppp_mutex);
 	return err;
 }
 
@@ -801,7 +794,7 @@
 	struct ppp_net *pn;
 	int __user *p = (int __user *)arg;
 
-	lock_kernel();
+	mutex_lock(&ppp_mutex);
 	switch (cmd) {
 	case PPPIOCNEWUNIT:
 		/* Create a new ppp unit */
@@ -852,7 +845,7 @@
 	default:
 		err = -ENOTTY;
 	}
-	unlock_kernel();
+	mutex_unlock(&ppp_mutex);
 	return err;
 }
 
@@ -1933,9 +1926,9 @@
 	/* If the queue is getting long, don't wait any longer for packets
 	   before the start of the queue. */
 	if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN) {
-		struct sk_buff *skb = skb_peek(&ppp->mrq);
-		if (seq_before(ppp->minseq, skb->sequence))
-			ppp->minseq = skb->sequence;
+		struct sk_buff *mskb = skb_peek(&ppp->mrq);
+		if (seq_before(ppp->minseq, mskb->sequence))
+			ppp->minseq = mskb->sequence;
 	}
 
 	/* Pull completed packets off the queue and receive them. */
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 805b64d..344ef33 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -89,7 +89,6 @@
 #define PPPOE_HASH_SIZE (1 << PPPOE_HASH_BITS)
 #define PPPOE_HASH_MASK	(PPPOE_HASH_SIZE - 1)
 
-static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb);
 static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb);
 
 static const struct proto_ops pppoe_ops;
@@ -949,7 +948,7 @@
 
 abort:
 	kfree_skb(skb);
-	return 1;
+	return 0;
 }
 
 /************************************************************************
diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h
index 0a88b53..f7e51b7 100644
--- a/drivers/net/ps3_gelic_wireless.h
+++ b/drivers/net/ps3_gelic_wireless.h
@@ -74,7 +74,7 @@
 	u16 bss_type;    /* infra or adhoc */
 	u16 auth_method; /* shared key or open */
 	u16 op_mode; /* B/G */
-} __attribute__((packed));
+} __packed;
 
 
 /* for GELIC_EURUS_CMD_WEP_CFG */
@@ -88,7 +88,7 @@
 	/* all fields are big endian */
 	u16 security;
 	u8 key[4][16];
-} __attribute__((packed));
+} __packed;
 
 /* for GELIC_EURUS_CMD_WPA_CFG */
 enum gelic_eurus_wpa_security {
@@ -120,7 +120,7 @@
 	u16 security;
 	u16 psk_type; /* psk key encoding type */
 	u8 psk[GELIC_WL_EURUS_PSK_MAX_LEN]; /* psk key; hex or passphrase */
-} __attribute__((packed));
+} __packed;
 
 /* for GELIC_EURUS_CMD_{START,GET}_SCAN */
 enum gelic_eurus_scan_capability {
@@ -171,7 +171,7 @@
 	__be32 reserved3;
 	__be32 reserved4;
 	u8 elements[0]; /* ie */
-} __attribute__ ((packed));
+} __packed;
 
 /* the hypervisor returns bbs up to 16 */
 #define GELIC_EURUS_MAX_SCAN  (16)
@@ -193,7 +193,7 @@
 struct gelic_eurus_rssi_info {
 	/* big endian */
 	__be16 rssi;
-} __attribute__ ((packed));
+} __packed;
 
 
 /* for 'stat' member of gelic_wl_info */
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 54ebb65..6168a13 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -5,6 +5,8 @@
  * See LICENSE.qla3xxx for copyright and licensing details.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -36,14 +38,16 @@
 
 #include "qla3xxx.h"
 
-#define DRV_NAME  	"qla3xxx"
-#define DRV_STRING 	"QLogic ISP3XXX Network Driver"
+#define DRV_NAME	"qla3xxx"
+#define DRV_STRING	"QLogic ISP3XXX Network Driver"
 #define DRV_VERSION	"v2.03.00-k5"
-#define PFX		DRV_NAME " "
 
 static const char ql3xxx_driver_name[] = DRV_NAME;
 static const char ql3xxx_driver_version[] = DRV_VERSION;
 
+#define TIMED_OUT_MSG							\
+"Timed out waiting for management port to get free before issuing command\n"
+
 MODULE_AUTHOR("QLogic Corporation");
 MODULE_DESCRIPTION("QLogic ISP3XXX Network Driver " DRV_VERSION " ");
 MODULE_LICENSE("GPL");
@@ -73,24 +77,24 @@
 /*
  *  These are the known PHY's which are used
  */
-typedef enum {
+enum PHY_DEVICE_TYPE {
    PHY_TYPE_UNKNOWN   = 0,
    PHY_VITESSE_VSC8211,
    PHY_AGERE_ET1011C,
    MAX_PHY_DEV_TYPES
-} PHY_DEVICE_et;
+};
 
-typedef struct {
-	PHY_DEVICE_et phyDevice;
-	u32		phyIdOUI;
-	u16		phyIdModel;
-	char 		*name;
-} PHY_DEVICE_INFO_t;
+struct PHY_DEVICE_INFO {
+	const enum PHY_DEVICE_TYPE	phyDevice;
+	const u32		phyIdOUI;
+	const u16		phyIdModel;
+	const char		*name;
+};
 
-static const PHY_DEVICE_INFO_t PHY_DEVICES[] =
-	{{PHY_TYPE_UNKNOWN,    0x000000, 0x0, "PHY_TYPE_UNKNOWN"},
-	 {PHY_VITESSE_VSC8211, 0x0003f1, 0xb, "PHY_VITESSE_VSC8211"},
-	 {PHY_AGERE_ET1011C,   0x00a0bc, 0x1, "PHY_AGERE_ET1011C"},
+static const struct PHY_DEVICE_INFO PHY_DEVICES[] = {
+	{PHY_TYPE_UNKNOWN,    0x000000, 0x0, "PHY_TYPE_UNKNOWN"},
+	{PHY_VITESSE_VSC8211, 0x0003f1, 0xb, "PHY_VITESSE_VSC8211"},
+	{PHY_AGERE_ET1011C,   0x00a0bc, 0x1, "PHY_AGERE_ET1011C"},
 };
 
 
@@ -100,7 +104,8 @@
 static int ql_sem_spinlock(struct ql3_adapter *qdev,
 			    u32 sem_mask, u32 sem_bits)
 {
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 	u32 value;
 	unsigned int seconds = 3;
 
@@ -111,20 +116,22 @@
 		if ((value & (sem_mask >> 16)) == sem_bits)
 			return 0;
 		ssleep(1);
-	} while(--seconds);
+	} while (--seconds);
 	return -1;
 }
 
 static void ql_sem_unlock(struct ql3_adapter *qdev, u32 sem_mask)
 {
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 	writel(sem_mask, &port_regs->CommonRegs.semaphoreReg);
 	readl(&port_regs->CommonRegs.semaphoreReg);
 }
 
 static int ql_sem_lock(struct ql3_adapter *qdev, u32 sem_mask, u32 sem_bits)
 {
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 	u32 value;
 
 	writel((sem_mask | sem_bits), &port_regs->CommonRegs.semaphoreReg);
@@ -139,32 +146,28 @@
 {
 	int i = 0;
 
-	while (1) {
-		if (!ql_sem_lock(qdev,
-				 QL_DRVR_SEM_MASK,
-				 (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
-				  * 2) << 1)) {
-			if (i < 10) {
-				ssleep(1);
-				i++;
-			} else {
-				printk(KERN_ERR PFX "%s: Timed out waiting for "
-				       "driver lock...\n",
-				       qdev->ndev->name);
-				return 0;
-			}
-		} else {
-			printk(KERN_DEBUG PFX
-			       "%s: driver lock acquired.\n",
-			       qdev->ndev->name);
+	while (i < 10) {
+		if (i)
+			ssleep(1);
+
+		if (ql_sem_lock(qdev,
+				QL_DRVR_SEM_MASK,
+				(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
+				 * 2) << 1)) {
+			netdev_printk(KERN_DEBUG, qdev->ndev,
+				      "driver lock acquired\n");
 			return 1;
 		}
 	}
+
+	netdev_err(qdev->ndev, "Timed out waiting for driver lock...\n");
+	return 0;
 }
 
 static void ql_set_register_page(struct ql3_adapter *qdev, u32 page)
 {
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 
 	writel(((ISP_CONTROL_NP_MASK << 16) | page),
 			&port_regs->CommonRegs.ispControlStatus);
@@ -172,8 +175,7 @@
 	qdev->current_page = page;
 }
 
-static u32 ql_read_common_reg_l(struct ql3_adapter *qdev,
-			      u32 __iomem * reg)
+static u32 ql_read_common_reg_l(struct ql3_adapter *qdev, u32 __iomem *reg)
 {
 	u32 value;
 	unsigned long hw_flags;
@@ -185,8 +187,7 @@
 	return value;
 }
 
-static u32 ql_read_common_reg(struct ql3_adapter *qdev,
-			      u32 __iomem * reg)
+static u32 ql_read_common_reg(struct ql3_adapter *qdev, u32 __iomem *reg)
 {
 	return readl(reg);
 }
@@ -199,7 +200,7 @@
 	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
 
 	if (qdev->current_page != 0)
-		ql_set_register_page(qdev,0);
+		ql_set_register_page(qdev, 0);
 	value = readl(reg);
 
 	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
@@ -209,7 +210,7 @@
 static u32 ql_read_page0_reg(struct ql3_adapter *qdev, u32 __iomem *reg)
 {
 	if (qdev->current_page != 0)
-		ql_set_register_page(qdev,0);
+		ql_set_register_page(qdev, 0);
 	return readl(reg);
 }
 
@@ -243,7 +244,7 @@
 			       u32 __iomem *reg, u32 value)
 {
 	if (qdev->current_page != 0)
-		ql_set_register_page(qdev,0);
+		ql_set_register_page(qdev, 0);
 	writel(value, reg);
 	readl(reg);
 }
@@ -255,7 +256,7 @@
 			       u32 __iomem *reg, u32 value)
 {
 	if (qdev->current_page != 1)
-		ql_set_register_page(qdev,1);
+		ql_set_register_page(qdev, 1);
 	writel(value, reg);
 	readl(reg);
 }
@@ -267,14 +268,15 @@
 			       u32 __iomem *reg, u32 value)
 {
 	if (qdev->current_page != 2)
-		ql_set_register_page(qdev,2);
+		ql_set_register_page(qdev, 2);
 	writel(value, reg);
 	readl(reg);
 }
 
 static void ql_disable_interrupts(struct ql3_adapter *qdev)
 {
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 
 	ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg,
 			    (ISP_IMR_ENABLE_INT << 16));
@@ -283,7 +285,8 @@
 
 static void ql_enable_interrupts(struct ql3_adapter *qdev)
 {
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 
 	ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg,
 			    ((0xff << 16) | ISP_IMR_ENABLE_INT));
@@ -308,8 +311,7 @@
 		lrg_buf_cb->skb = netdev_alloc_skb(qdev->ndev,
 						   qdev->lrg_buffer_len);
 		if (unlikely(!lrg_buf_cb->skb)) {
-			printk(KERN_ERR PFX "%s: failed netdev_alloc_skb().\n",
-			       qdev->ndev->name);
+			netdev_err(qdev->ndev, "failed netdev_alloc_skb()\n");
 			qdev->lrg_buf_skb_check++;
 		} else {
 			/*
@@ -323,9 +325,10 @@
 					     QL_HEADER_SPACE,
 					     PCI_DMA_FROMDEVICE);
 			err = pci_dma_mapping_error(qdev->pdev, map);
-			if(err) {
-				printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
-				       qdev->ndev->name, err);
+			if (err) {
+				netdev_err(qdev->ndev,
+					   "PCI mapping failed with error: %d\n",
+					   err);
 				dev_kfree_skb(lrg_buf_cb->skb);
 				lrg_buf_cb->skb = NULL;
 
@@ -350,10 +353,11 @@
 static struct ql_rcv_buf_cb *ql_get_from_lrg_buf_free_list(struct ql3_adapter
 							   *qdev)
 {
-	struct ql_rcv_buf_cb *lrg_buf_cb;
+	struct ql_rcv_buf_cb *lrg_buf_cb = qdev->lrg_buf_free_head;
 
-	if ((lrg_buf_cb = qdev->lrg_buf_free_head) != NULL) {
-		if ((qdev->lrg_buf_free_head = lrg_buf_cb->next) == NULL)
+	if (lrg_buf_cb != NULL) {
+		qdev->lrg_buf_free_head = lrg_buf_cb->next;
+		if (qdev->lrg_buf_free_head == NULL)
 			qdev->lrg_buf_free_tail = NULL;
 		qdev->lrg_buf_free_count--;
 	}
@@ -374,13 +378,13 @@
 static void fm93c56a_select(struct ql3_adapter *qdev)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
+	u32 *spir = &port_regs->CommonRegs.serialPortInterfaceReg;
 
 	qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_1;
-	ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
-			    ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
-	ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
-			    ((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data));
+	ql_write_nvram_reg(qdev, spir, ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
+	ql_write_nvram_reg(qdev, spir,
+			   ((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data));
 }
 
 /*
@@ -393,51 +397,40 @@
 	u32 dataBit;
 	u32 previousBit;
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
+	u32 *spir = &port_regs->CommonRegs.serialPortInterfaceReg;
 
 	/* Clock in a zero, then do the start bit */
-	ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
-			    ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
-			    AUBURN_EEPROM_DO_1);
-	ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
-			    ISP_NVRAM_MASK | qdev->
-			    eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
-			    AUBURN_EEPROM_CLK_RISE);
-	ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
-			    ISP_NVRAM_MASK | qdev->
-			    eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
-			    AUBURN_EEPROM_CLK_FALL);
+	ql_write_nvram_reg(qdev, spir,
+			   (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+			    AUBURN_EEPROM_DO_1));
+	ql_write_nvram_reg(qdev, spir,
+			   (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+			    AUBURN_EEPROM_DO_1 | AUBURN_EEPROM_CLK_RISE));
+	ql_write_nvram_reg(qdev, spir,
+			   (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+			    AUBURN_EEPROM_DO_1 | AUBURN_EEPROM_CLK_FALL));
 
 	mask = 1 << (FM93C56A_CMD_BITS - 1);
 	/* Force the previous data bit to be different */
 	previousBit = 0xffff;
 	for (i = 0; i < FM93C56A_CMD_BITS; i++) {
-		dataBit =
-		    (cmd & mask) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0;
+		dataBit = (cmd & mask)
+			? AUBURN_EEPROM_DO_1
+			: AUBURN_EEPROM_DO_0;
 		if (previousBit != dataBit) {
-			/*
-			 * If the bit changed, then change the DO state to
-			 * match
-			 */
-			ql_write_nvram_reg(qdev,
-					    &port_regs->CommonRegs.
-					    serialPortInterfaceReg,
-					    ISP_NVRAM_MASK | qdev->
-					    eeprom_cmd_data | dataBit);
+			/* If the bit changed, change the DO state to match */
+			ql_write_nvram_reg(qdev, spir,
+					   (ISP_NVRAM_MASK |
+					    qdev->eeprom_cmd_data | dataBit));
 			previousBit = dataBit;
 		}
-		ql_write_nvram_reg(qdev,
-				    &port_regs->CommonRegs.
-				    serialPortInterfaceReg,
-				    ISP_NVRAM_MASK | qdev->
-				    eeprom_cmd_data | dataBit |
-				    AUBURN_EEPROM_CLK_RISE);
-		ql_write_nvram_reg(qdev,
-				    &port_regs->CommonRegs.
-				    serialPortInterfaceReg,
-				    ISP_NVRAM_MASK | qdev->
-				    eeprom_cmd_data | dataBit |
-				    AUBURN_EEPROM_CLK_FALL);
+		ql_write_nvram_reg(qdev, spir,
+				   (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+				    dataBit | AUBURN_EEPROM_CLK_RISE));
+		ql_write_nvram_reg(qdev, spir,
+				   (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+				    dataBit | AUBURN_EEPROM_CLK_FALL));
 		cmd = cmd << 1;
 	}
 
@@ -445,33 +438,24 @@
 	/* Force the previous data bit to be different */
 	previousBit = 0xffff;
 	for (i = 0; i < addrBits; i++) {
-		dataBit =
-		    (eepromAddr & mask) ? AUBURN_EEPROM_DO_1 :
-		    AUBURN_EEPROM_DO_0;
+		dataBit = (eepromAddr & mask) ? AUBURN_EEPROM_DO_1
+			: AUBURN_EEPROM_DO_0;
 		if (previousBit != dataBit) {
 			/*
 			 * If the bit changed, then change the DO state to
 			 * match
 			 */
-			ql_write_nvram_reg(qdev,
-					    &port_regs->CommonRegs.
-					    serialPortInterfaceReg,
-					    ISP_NVRAM_MASK | qdev->
-					    eeprom_cmd_data | dataBit);
+			ql_write_nvram_reg(qdev, spir,
+					   (ISP_NVRAM_MASK |
+					    qdev->eeprom_cmd_data | dataBit));
 			previousBit = dataBit;
 		}
-		ql_write_nvram_reg(qdev,
-				    &port_regs->CommonRegs.
-				    serialPortInterfaceReg,
-				    ISP_NVRAM_MASK | qdev->
-				    eeprom_cmd_data | dataBit |
-				    AUBURN_EEPROM_CLK_RISE);
-		ql_write_nvram_reg(qdev,
-				    &port_regs->CommonRegs.
-				    serialPortInterfaceReg,
-				    ISP_NVRAM_MASK | qdev->
-				    eeprom_cmd_data | dataBit |
-				    AUBURN_EEPROM_CLK_FALL);
+		ql_write_nvram_reg(qdev, spir,
+				   (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+				    dataBit | AUBURN_EEPROM_CLK_RISE));
+		ql_write_nvram_reg(qdev, spir,
+				   (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+				    dataBit | AUBURN_EEPROM_CLK_FALL));
 		eepromAddr = eepromAddr << 1;
 	}
 }
@@ -482,10 +466,11 @@
 static void fm93c56a_deselect(struct ql3_adapter *qdev)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
+	u32 *spir = &port_regs->CommonRegs.serialPortInterfaceReg;
+
 	qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_0;
-	ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
-			    ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
+	ql_write_nvram_reg(qdev, spir, ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
 }
 
 /*
@@ -497,29 +482,23 @@
 	u32 data = 0;
 	u32 dataBit;
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
+	u32 *spir = &port_regs->CommonRegs.serialPortInterfaceReg;
 
 	/* Read the data bits */
 	/* The first bit is a dummy.  Clock right over it. */
 	for (i = 0; i < dataBits; i++) {
-		ql_write_nvram_reg(qdev,
-				    &port_regs->CommonRegs.
-				    serialPortInterfaceReg,
-				    ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
-				    AUBURN_EEPROM_CLK_RISE);
-		ql_write_nvram_reg(qdev,
-				    &port_regs->CommonRegs.
-				    serialPortInterfaceReg,
-				    ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
-				    AUBURN_EEPROM_CLK_FALL);
-		dataBit =
-		    (ql_read_common_reg
-		     (qdev,
-		      &port_regs->CommonRegs.
-		      serialPortInterfaceReg) & AUBURN_EEPROM_DI_1) ? 1 : 0;
+		ql_write_nvram_reg(qdev, spir,
+				   ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+				   AUBURN_EEPROM_CLK_RISE);
+		ql_write_nvram_reg(qdev, spir,
+				   ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+				   AUBURN_EEPROM_CLK_FALL);
+		dataBit = (ql_read_common_reg(qdev, spir) &
+			   AUBURN_EEPROM_DI_1) ? 1 : 0;
 		data = (data << 1) | dataBit;
 	}
-	*value = (u16) data;
+	*value = (u16)data;
 }
 
 /*
@@ -551,13 +530,12 @@
 
 	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
 
-	pEEPROMData = (u16 *) & qdev->nvram_data;
+	pEEPROMData = (u16 *)&qdev->nvram_data;
 	qdev->eeprom_cmd_data = 0;
-	if(ql_sem_spinlock(qdev, QL_NVRAM_SEM_MASK,
+	if (ql_sem_spinlock(qdev, QL_NVRAM_SEM_MASK,
 			(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
 			 2) << 10)) {
-		printk(KERN_ERR PFX"%s: Failed ql_sem_spinlock().\n",
-			__func__);
+		pr_err("%s: Failed ql_sem_spinlock()\n", __func__);
 		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 		return -1;
 	}
@@ -570,8 +548,8 @@
 	ql_sem_unlock(qdev, QL_NVRAM_SEM_MASK);
 
 	if (checksum != 0) {
-		printk(KERN_ERR PFX "%s: checksum should be zero, is %x!!\n",
-		       qdev->ndev->name, checksum);
+		netdev_err(qdev->ndev, "checksum should be zero, is %x!!\n",
+			   checksum);
 		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 		return -1;
 	}
@@ -587,7 +565,7 @@
 static int ql_wait_for_mii_ready(struct ql3_adapter *qdev)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u32 temp;
 	int count = 1000;
 
@@ -604,7 +582,7 @@
 static void ql_mii_enable_scan_mode(struct ql3_adapter *qdev)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u32 scanControl;
 
 	if (qdev->numPorts > 1) {
@@ -632,7 +610,7 @@
 {
 	u8 ret;
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    				qdev->mem_map_registers;
+					qdev->mem_map_registers;
 
 	/* See if scan mode is enabled before we turn it off */
 	if (ql_read_page0_reg(qdev, &port_regs->macMIIMgmtControlReg) &
@@ -662,17 +640,13 @@
 			       u16 regAddr, u16 value, u32 phyAddr)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u8 scanWasEnabled;
 
 	scanWasEnabled = ql_mii_disable_scan_mode(qdev);
 
 	if (ql_wait_for_mii_ready(qdev)) {
-		if (netif_msg_link(qdev))
-			printk(KERN_WARNING PFX
-			       "%s Timed out waiting for management port to "
-			       "get free before issuing command.\n",
-			       qdev->ndev->name);
+		netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
 		return -1;
 	}
 
@@ -683,11 +657,7 @@
 
 	/* Wait for write to complete 9/10/04 SJP */
 	if (ql_wait_for_mii_ready(qdev)) {
-		if (netif_msg_link(qdev))
-			printk(KERN_WARNING PFX
-			       "%s: Timed out waiting for management port to "
-			       "get free before issuing command.\n",
-			       qdev->ndev->name);
+		netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
 		return -1;
 	}
 
@@ -698,21 +668,17 @@
 }
 
 static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
-			      u16 * value, u32 phyAddr)
+			      u16 *value, u32 phyAddr)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u8 scanWasEnabled;
 	u32 temp;
 
 	scanWasEnabled = ql_mii_disable_scan_mode(qdev);
 
 	if (ql_wait_for_mii_ready(qdev)) {
-		if (netif_msg_link(qdev))
-			printk(KERN_WARNING PFX
-			       "%s: Timed out waiting for management port to "
-			       "get free before issuing command.\n",
-			       qdev->ndev->name);
+		netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
 		return -1;
 	}
 
@@ -727,11 +693,7 @@
 
 	/* Wait for the read to complete */
 	if (ql_wait_for_mii_ready(qdev)) {
-		if (netif_msg_link(qdev))
-			printk(KERN_WARNING PFX
-			       "%s: Timed out waiting for management port to "
-			       "get free after issuing command.\n",
-			       qdev->ndev->name);
+		netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
 		return -1;
 	}
 
@@ -747,16 +709,12 @@
 static int ql_mii_write_reg(struct ql3_adapter *qdev, u16 regAddr, u16 value)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 
 	ql_mii_disable_scan_mode(qdev);
 
 	if (ql_wait_for_mii_ready(qdev)) {
-		if (netif_msg_link(qdev))
-			printk(KERN_WARNING PFX
-			       "%s: Timed out waiting for management port to "
-			       "get free before issuing command.\n",
-			       qdev->ndev->name);
+		netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
 		return -1;
 	}
 
@@ -767,11 +725,7 @@
 
 	/* Wait for write to complete. */
 	if (ql_wait_for_mii_ready(qdev)) {
-		if (netif_msg_link(qdev))
-			printk(KERN_WARNING PFX
-			       "%s: Timed out waiting for management port to "
-			       "get free before issuing command.\n",
-			       qdev->ndev->name);
+		netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
 		return -1;
 	}
 
@@ -784,16 +738,12 @@
 {
 	u32 temp;
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 
 	ql_mii_disable_scan_mode(qdev);
 
 	if (ql_wait_for_mii_ready(qdev)) {
-		if (netif_msg_link(qdev))
-			printk(KERN_WARNING PFX
-			       "%s: Timed out waiting for management port to "
-			       "get free before issuing command.\n",
-			       qdev->ndev->name);
+		netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
 		return -1;
 	}
 
@@ -808,11 +758,7 @@
 
 	/* Wait for the read to complete */
 	if (ql_wait_for_mii_ready(qdev)) {
-		if (netif_msg_link(qdev))
-			printk(KERN_WARNING PFX
-			       "%s: Timed out waiting for management port to "
-			       "get free before issuing command.\n",
-			       qdev->ndev->name);
+		netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
 		return -1;
 	}
 
@@ -898,7 +844,7 @@
 
 static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr)
 {
-	printk(KERN_INFO "%s: enabling Agere specific PHY\n", qdev->ndev->name);
+	netdev_info(qdev->ndev, "enabling Agere specific PHY\n");
 	/* power down device bit 11 = 1 */
 	ql_mii_write_reg_ex(qdev, 0x00, 0x1940, miiAddr);
 	/* enable diagnostic mode bit 2 = 1 */
@@ -918,7 +864,8 @@
 	/* point to hidden reg 0x2806 */
 	ql_mii_write_reg_ex(qdev, 0x10, 0x2806, miiAddr);
 	/* Write new PHYAD w/bit 5 set */
-	ql_mii_write_reg_ex(qdev, 0x11, 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr);
+	ql_mii_write_reg_ex(qdev, 0x11,
+			    0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr);
 	/*
 	 * Disable diagnostic mode bit 2 = 0
 	 * Power up device bit 11 = 0
@@ -929,21 +876,19 @@
 	ql_mii_write_reg(qdev, 0x1c, 0xfaf0);
 }
 
-static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev,
-				 u16 phyIdReg0, u16 phyIdReg1)
+static enum PHY_DEVICE_TYPE getPhyType(struct ql3_adapter *qdev,
+				       u16 phyIdReg0, u16 phyIdReg1)
 {
-	PHY_DEVICE_et result = PHY_TYPE_UNKNOWN;
+	enum PHY_DEVICE_TYPE result = PHY_TYPE_UNKNOWN;
 	u32   oui;
 	u16   model;
 	int i;
 
-	if (phyIdReg0 == 0xffff) {
+	if (phyIdReg0 == 0xffff)
 		return result;
-	}
 
-	if (phyIdReg1 == 0xffff) {
+	if (phyIdReg1 == 0xffff)
 		return result;
-	}
 
 	/* oui is split between two registers */
 	oui = (phyIdReg0 << 6) | ((phyIdReg1 & PHY_OUI_1_MASK) >> 10);
@@ -951,15 +896,13 @@
 	model = (phyIdReg1 & PHY_MODEL_MASK) >> 4;
 
 	/* Scan table for this PHY */
-	for(i = 0; i < MAX_PHY_DEV_TYPES; i++) {
-		if ((oui == PHY_DEVICES[i].phyIdOUI) && (model == PHY_DEVICES[i].phyIdModel))
-		{
+	for (i = 0; i < MAX_PHY_DEV_TYPES; i++) {
+		if ((oui == PHY_DEVICES[i].phyIdOUI) &&
+		    (model == PHY_DEVICES[i].phyIdModel)) {
+			netdev_info(qdev->ndev, "Phy: %s\n",
+				    PHY_DEVICES[i].name);
 			result = PHY_DEVICES[i].phyDevice;
-
-			printk(KERN_INFO "%s: Phy: %s\n",
-				qdev->ndev->name, PHY_DEVICES[i].name);
-
-		        break;
+			break;
 		}
 	}
 
@@ -970,9 +913,8 @@
 {
 	u16 reg;
 
-	switch(qdev->phyType) {
-	case PHY_AGERE_ET1011C:
-	{
+	switch (qdev->phyType) {
+	case PHY_AGERE_ET1011C: {
 		if (ql_mii_read_reg(qdev, 0x1A, &reg) < 0)
 			return 0;
 
@@ -980,20 +922,20 @@
 		break;
 	}
 	default:
-	if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
-		return 0;
+		if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
+			return 0;
 
-	reg = (((reg & 0x18) >> 3) & 3);
+		reg = (((reg & 0x18) >> 3) & 3);
 	}
 
-	switch(reg) {
-		case 2:
+	switch (reg) {
+	case 2:
 		return SPEED_1000;
-		case 1:
+	case 1:
 		return SPEED_100;
-		case 0:
+	case 0:
 		return SPEED_10;
-		default:
+	default:
 		return -1;
 	}
 }
@@ -1002,17 +944,15 @@
 {
 	u16 reg;
 
-	switch(qdev->phyType) {
-	case PHY_AGERE_ET1011C:
-	{
+	switch (qdev->phyType) {
+	case PHY_AGERE_ET1011C: {
 		if (ql_mii_read_reg(qdev, 0x1A, &reg))
 			return 0;
 
 		return ((reg & 0x0080) && (reg & 0x1000)) != 0;
 	}
 	case PHY_VITESSE_VSC8211:
-	default:
-	{
+	default: {
 		if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
 			return 0;
 		return (reg & PHY_AUX_DUPLEX_STAT) != 0;
@@ -1040,17 +980,15 @@
 
 	/*  Determine the PHY we are using by reading the ID's */
 	err = ql_mii_read_reg(qdev, PHY_ID_0_REG, &reg1);
-	if(err != 0) {
-		printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n",
-		       qdev->ndev->name);
-                return err;
+	if (err != 0) {
+		netdev_err(qdev->ndev, "Could not read from reg PHY_ID_0_REG\n");
+		return err;
 	}
 
 	err = ql_mii_read_reg(qdev, PHY_ID_1_REG, &reg2);
-	if(err != 0) {
-		printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n",
-		       qdev->ndev->name);
-                return err;
+	if (err != 0) {
+		netdev_err(qdev->ndev, "Could not read from reg PHY_ID_1_REG\n");
+		return err;
 	}
 
 	/*  Check if we have a Agere PHY */
@@ -1058,24 +996,22 @@
 
 		/* Determine which MII address we should be using
 		   determined by the index of the card */
-		if (qdev->mac_index == 0) {
+		if (qdev->mac_index == 0)
 			miiAddr = MII_AGERE_ADDR_1;
-		} else {
+		else
 			miiAddr = MII_AGERE_ADDR_2;
-		}
 
-		err =ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, &reg1, miiAddr);
-		if(err != 0) {
-			printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
-		       	       qdev->ndev->name);
+		err = ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, &reg1, miiAddr);
+		if (err != 0) {
+			netdev_err(qdev->ndev,
+				   "Could not read from reg PHY_ID_0_REG after Agere detected\n");
 			return err;
 		}
 
 		err = ql_mii_read_reg_ex(qdev, PHY_ID_1_REG, &reg2, miiAddr);
-		if(err != 0) {
-			printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
-			       qdev->ndev->name);
-        	        return err;
+		if (err != 0) {
+			netdev_err(qdev->ndev, "Could not read from reg PHY_ID_1_REG after Agere detected\n");
+			return err;
 		}
 
 		/*  We need to remember to initialize the Agere PHY */
@@ -1090,7 +1026,7 @@
 		/* need this here so address gets changed */
 		phyAgereSpecificInit(qdev, miiAddr);
 	} else if (qdev->phyType == PHY_TYPE_UNKNOWN) {
-		printk(KERN_ERR "%s: PHY is unknown\n", qdev->ndev->name);
+		netdev_err(qdev->ndev, "PHY is unknown\n");
 		return -EIO;
 	}
 
@@ -1103,7 +1039,7 @@
 static void ql_mac_enable(struct ql3_adapter *qdev, u32 enable)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u32 value;
 
 	if (enable)
@@ -1123,7 +1059,7 @@
 static void ql_mac_cfg_soft_reset(struct ql3_adapter *qdev, u32 enable)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u32 value;
 
 	if (enable)
@@ -1143,7 +1079,7 @@
 static void ql_mac_cfg_gig(struct ql3_adapter *qdev, u32 enable)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u32 value;
 
 	if (enable)
@@ -1163,7 +1099,7 @@
 static void ql_mac_cfg_full_dup(struct ql3_adapter *qdev, u32 enable)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u32 value;
 
 	if (enable)
@@ -1183,7 +1119,7 @@
 static void ql_mac_cfg_pause(struct ql3_adapter *qdev, u32 enable)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u32 value;
 
 	if (enable)
@@ -1205,7 +1141,7 @@
 static int ql_is_fiber(struct ql3_adapter *qdev)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u32 bitToCheck = 0;
 	u32 temp;
 
@@ -1235,7 +1171,7 @@
 static int ql_is_auto_neg_complete(struct ql3_adapter *qdev)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u32 bitToCheck = 0;
 	u32 temp;
 
@@ -1250,18 +1186,11 @@
 
 	temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
 	if (temp & bitToCheck) {
-		if (netif_msg_link(qdev))
-			printk(KERN_INFO PFX
-			       "%s: Auto-Negotiate complete.\n",
-			       qdev->ndev->name);
+		netif_info(qdev, link, qdev->ndev, "Auto-Negotiate complete\n");
 		return 1;
-	} else {
-		if (netif_msg_link(qdev))
-			printk(KERN_WARNING PFX
-			       "%s: Auto-Negotiate incomplete.\n",
-			       qdev->ndev->name);
-		return 0;
 	}
+	netif_info(qdev, link, qdev->ndev, "Auto-Negotiate incomplete\n");
+	return 0;
 }
 
 /*
@@ -1278,7 +1207,7 @@
 static int ql_auto_neg_error(struct ql3_adapter *qdev)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u32 bitToCheck = 0;
 	u32 temp;
 
@@ -1316,7 +1245,7 @@
 static int ql_link_down_detect(struct ql3_adapter *qdev)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u32 bitToCheck = 0;
 	u32 temp;
 
@@ -1340,7 +1269,7 @@
 static int ql_link_down_detect_clear(struct ql3_adapter *qdev)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 
 	switch (qdev->mac_index) {
 	case 0:
@@ -1370,7 +1299,7 @@
 static int ql_this_adapter_controls_port(struct ql3_adapter *qdev)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u32 bitToCheck = 0;
 	u32 temp;
 
@@ -1387,16 +1316,13 @@
 
 	temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
 	if (temp & bitToCheck) {
-		if (netif_msg_link(qdev))
-			printk(KERN_DEBUG PFX
-			       "%s: is not link master.\n", qdev->ndev->name);
+		netif_printk(qdev, link, KERN_DEBUG, qdev->ndev,
+			     "not link master\n");
 		return 0;
-	} else {
-		if (netif_msg_link(qdev))
-			printk(KERN_DEBUG PFX
-			       "%s: is link master.\n", qdev->ndev->name);
-		return 1;
 	}
+
+	netif_printk(qdev, link, KERN_DEBUG, qdev->ndev, "link master\n");
+	return 1;
 }
 
 static void ql_phy_reset_ex(struct ql3_adapter *qdev)
@@ -1410,19 +1336,20 @@
 	u16 reg;
 	u16 portConfiguration;
 
-	if(qdev->phyType == PHY_AGERE_ET1011C) {
-		/* turn off external loopback */
+	if (qdev->phyType == PHY_AGERE_ET1011C)
 		ql_mii_write_reg(qdev, 0x13, 0x0000);
-	}
+					/* turn off external loopback */
 
-	if(qdev->mac_index == 0)
-		portConfiguration = qdev->nvram_data.macCfg_port0.portConfiguration;
+	if (qdev->mac_index == 0)
+		portConfiguration =
+			qdev->nvram_data.macCfg_port0.portConfiguration;
 	else
-		portConfiguration = qdev->nvram_data.macCfg_port1.portConfiguration;
+		portConfiguration =
+			qdev->nvram_data.macCfg_port1.portConfiguration;
 
 	/*  Some HBA's in the field are set to 0 and they need to
 	    be reinterpreted with a default value */
-	if(portConfiguration == 0)
+	if (portConfiguration == 0)
 		portConfiguration = PORT_CONFIG_DEFAULT;
 
 	/* Set the 1000 advertisements */
@@ -1430,8 +1357,8 @@
 			   PHYAddr[qdev->mac_index]);
 	reg &= ~PHY_GIG_ALL_PARAMS;
 
-	if(portConfiguration & PORT_CONFIG_1000MB_SPEED) {
-		if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED)
+	if (portConfiguration & PORT_CONFIG_1000MB_SPEED) {
+		if (portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED)
 			reg |= PHY_GIG_ADV_1000F;
 		else
 			reg |= PHY_GIG_ADV_1000H;
@@ -1445,29 +1372,27 @@
 			   PHYAddr[qdev->mac_index]);
 	reg &= ~PHY_NEG_ALL_PARAMS;
 
-	if(portConfiguration & PORT_CONFIG_SYM_PAUSE_ENABLED)
+	if (portConfiguration & PORT_CONFIG_SYM_PAUSE_ENABLED)
 		reg |= PHY_NEG_ASY_PAUSE | PHY_NEG_SYM_PAUSE;
 
-	if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) {
-		if(portConfiguration & PORT_CONFIG_100MB_SPEED)
+	if (portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) {
+		if (portConfiguration & PORT_CONFIG_100MB_SPEED)
 			reg |= PHY_NEG_ADV_100F;
 
-		if(portConfiguration & PORT_CONFIG_10MB_SPEED)
+		if (portConfiguration & PORT_CONFIG_10MB_SPEED)
 			reg |= PHY_NEG_ADV_10F;
 	}
 
-	if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) {
-		if(portConfiguration & PORT_CONFIG_100MB_SPEED)
+	if (portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) {
+		if (portConfiguration & PORT_CONFIG_100MB_SPEED)
 			reg |= PHY_NEG_ADV_100H;
 
-		if(portConfiguration & PORT_CONFIG_10MB_SPEED)
+		if (portConfiguration & PORT_CONFIG_10MB_SPEED)
 			reg |= PHY_NEG_ADV_10H;
 	}
 
-	if(portConfiguration &
-	   PORT_CONFIG_1000MB_SPEED) {
+	if (portConfiguration & PORT_CONFIG_1000MB_SPEED)
 		reg |= 1;
-	}
 
 	ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg,
 			    PHYAddr[qdev->mac_index]);
@@ -1492,7 +1417,7 @@
 static u32 ql_get_link_state(struct ql3_adapter *qdev)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	u32 bitToCheck = 0;
 	u32 temp, linkState;
 
@@ -1504,22 +1429,22 @@
 		bitToCheck = PORT_STATUS_UP1;
 		break;
 	}
+
 	temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
-	if (temp & bitToCheck) {
+	if (temp & bitToCheck)
 		linkState = LS_UP;
-	} else {
+	else
 		linkState = LS_DOWN;
-	}
+
 	return linkState;
 }
 
 static int ql_port_start(struct ql3_adapter *qdev)
 {
-	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+	if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
 		(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
 			 2) << 7)) {
-		printk(KERN_ERR "%s: Could not get hw lock for GIO\n",
-		       qdev->ndev->name);
+		netdev_err(qdev->ndev, "Could not get hw lock for GIO\n");
 		return -1;
 	}
 
@@ -1537,19 +1462,16 @@
 static int ql_finish_auto_neg(struct ql3_adapter *qdev)
 {
 
-	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+	if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
 		(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
 			 2) << 7))
 		return -1;
 
 	if (!ql_auto_neg_error(qdev)) {
-		if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
+		if (test_bit(QL_LINK_MASTER, &qdev->flags)) {
 			/* configure the MAC */
-			if (netif_msg_link(qdev))
-				printk(KERN_DEBUG PFX
-				       "%s: Configuring link.\n",
-				       qdev->ndev->
-				       name);
+			netif_printk(qdev, link, KERN_DEBUG, qdev->ndev,
+				     "Configuring link\n");
 			ql_mac_cfg_soft_reset(qdev, 1);
 			ql_mac_cfg_gig(qdev,
 				       (ql_get_link_speed
@@ -1564,43 +1486,32 @@
 			ql_mac_cfg_soft_reset(qdev, 0);
 
 			/* enable the MAC */
-			if (netif_msg_link(qdev))
-				printk(KERN_DEBUG PFX
-				       "%s: Enabling mac.\n",
-				       qdev->ndev->
-					       name);
+			netif_printk(qdev, link, KERN_DEBUG, qdev->ndev,
+				     "Enabling mac\n");
 			ql_mac_enable(qdev, 1);
 		}
 
 		qdev->port_link_state = LS_UP;
 		netif_start_queue(qdev->ndev);
 		netif_carrier_on(qdev->ndev);
-		if (netif_msg_link(qdev))
-			printk(KERN_INFO PFX
-			       "%s: Link is up at %d Mbps, %s duplex.\n",
-			       qdev->ndev->name,
-			       ql_get_link_speed(qdev),
-			       ql_is_link_full_dup(qdev)
-			       ? "full" : "half");
+		netif_info(qdev, link, qdev->ndev,
+			   "Link is up at %d Mbps, %s duplex\n",
+			   ql_get_link_speed(qdev),
+			   ql_is_link_full_dup(qdev) ? "full" : "half");
 
 	} else {	/* Remote error detected */
 
-		if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
-			if (netif_msg_link(qdev))
-				printk(KERN_DEBUG PFX
-				       "%s: Remote error detected. "
-				       "Calling ql_port_start().\n",
-				       qdev->ndev->
-				       name);
+		if (test_bit(QL_LINK_MASTER, &qdev->flags)) {
+			netif_printk(qdev, link, KERN_DEBUG, qdev->ndev,
+				     "Remote error detected. Calling ql_port_start()\n");
 			/*
 			 * ql_port_start() is shared code and needs
 			 * to lock the PHY on it's own.
 			 */
 			ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
-			if(ql_port_start(qdev))	{/* Restart port */
+			if (ql_port_start(qdev))	/* Restart port */
 				return -1;
-			} else
-				return 0;
+			return 0;
 		}
 	}
 	ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
@@ -1619,33 +1530,28 @@
 
 	curr_link_state = ql_get_link_state(qdev);
 
-	if (test_bit(QL_RESET_ACTIVE,&qdev->flags)) {
-		if (netif_msg_link(qdev))
-			printk(KERN_INFO PFX
-			       "%s: Reset in progress, skip processing link "
-			       "state.\n", qdev->ndev->name);
+	if (test_bit(QL_RESET_ACTIVE, &qdev->flags)) {
+		netif_info(qdev, link, qdev->ndev,
+			   "Reset in progress, skip processing link state\n");
 
 		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 
 		/* Restart timer on 2 second interval. */
-		mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);\
+		mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
 
 		return;
 	}
 
 	switch (qdev->port_link_state) {
 	default:
-		if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
+		if (test_bit(QL_LINK_MASTER, &qdev->flags))
 			ql_port_start(qdev);
-		}
 		qdev->port_link_state = LS_DOWN;
 		/* Fall Through */
 
 	case LS_DOWN:
 		if (curr_link_state == LS_UP) {
-			if (netif_msg_link(qdev))
-				printk(KERN_INFO PFX "%s: Link is up.\n",
-				       qdev->ndev->name);
+			netif_info(qdev, link, qdev->ndev, "Link is up\n");
 			if (ql_is_auto_neg_complete(qdev))
 				ql_finish_auto_neg(qdev);
 
@@ -1662,9 +1568,7 @@
 		 * back up
 		 */
 		if (curr_link_state == LS_DOWN) {
-			if (netif_msg_link(qdev))
-				printk(KERN_INFO PFX "%s: Link is down.\n",
-				       qdev->ndev->name);
+			netif_info(qdev, link, qdev->ndev, "Link is down\n");
 			qdev->port_link_state = LS_DOWN;
 		}
 		if (ql_link_down_detect(qdev))
@@ -1683,9 +1587,9 @@
 static void ql_get_phy_owner(struct ql3_adapter *qdev)
 {
 	if (ql_this_adapter_controls_port(qdev))
-		set_bit(QL_LINK_MASTER,&qdev->flags);
+		set_bit(QL_LINK_MASTER, &qdev->flags);
 	else
-		clear_bit(QL_LINK_MASTER,&qdev->flags);
+		clear_bit(QL_LINK_MASTER, &qdev->flags);
 }
 
 /*
@@ -1695,7 +1599,7 @@
 {
 	ql_mii_enable_scan_mode(qdev);
 
-	if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
+	if (test_bit(QL_LINK_OPTICAL, &qdev->flags)) {
 		if (ql_this_adapter_controls_port(qdev))
 			ql_petbi_init_ex(qdev);
 	} else {
@@ -1705,18 +1609,18 @@
 }
 
 /*
- * MII_Setup needs to be called before taking the PHY out of reset so that the
- * management interface clock speed can be set properly.  It would be better if
- * we had a way to disable MDC until after the PHY is out of reset, but we
- * don't have that capability.
+ * MII_Setup needs to be called before taking the PHY out of reset
+ * so that the management interface clock speed can be set properly.
+ * It would be better if we had a way to disable MDC until after the
+ * PHY is out of reset, but we don't have that capability.
  */
 static int ql_mii_setup(struct ql3_adapter *qdev)
 {
 	u32 reg;
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 
-	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+	if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
 			(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
 			 2) << 7))
 		return -1;
@@ -1735,24 +1639,24 @@
 	return 0;
 }
 
+#define SUPPORTED_OPTICAL_MODES	(SUPPORTED_1000baseT_Full |	\
+				 SUPPORTED_FIBRE |		\
+				 SUPPORTED_Autoneg)
+#define SUPPORTED_TP_MODES	(SUPPORTED_10baseT_Half |	\
+				 SUPPORTED_10baseT_Full |	\
+				 SUPPORTED_100baseT_Half |	\
+				 SUPPORTED_100baseT_Full |	\
+				 SUPPORTED_1000baseT_Half |	\
+				 SUPPORTED_1000baseT_Full |	\
+				 SUPPORTED_Autoneg |		\
+				 SUPPORTED_TP);			\
+
 static u32 ql_supported_modes(struct ql3_adapter *qdev)
 {
-	u32 supported;
+	if (test_bit(QL_LINK_OPTICAL, &qdev->flags))
+		return SUPPORTED_OPTICAL_MODES;
 
-	if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
-		supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
-		    | SUPPORTED_Autoneg;
-	} else {
-		supported = SUPPORTED_10baseT_Half
-		    | SUPPORTED_10baseT_Full
-		    | SUPPORTED_100baseT_Half
-		    | SUPPORTED_100baseT_Full
-		    | SUPPORTED_1000baseT_Half
-		    | SUPPORTED_1000baseT_Full
-		    | SUPPORTED_Autoneg | SUPPORTED_TP;
-	}
-
-	return supported;
+	return SUPPORTED_TP_MODES;
 }
 
 static int ql_get_auto_cfg_status(struct ql3_adapter *qdev)
@@ -1760,9 +1664,9 @@
 	int status;
 	unsigned long hw_flags;
 	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
-	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
-		(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
-			 2) << 7)) {
+	if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+			    (QL_RESOURCE_BITS_BASE_CODE |
+			     (qdev->mac_index) * 2) << 7)) {
 		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 		return 0;
 	}
@@ -1777,9 +1681,9 @@
 	u32 status;
 	unsigned long hw_flags;
 	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
-	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
-		(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
-			 2) << 7)) {
+	if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+			    (QL_RESOURCE_BITS_BASE_CODE |
+			     (qdev->mac_index) * 2) << 7)) {
 		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 		return 0;
 	}
@@ -1794,9 +1698,9 @@
 	int status;
 	unsigned long hw_flags;
 	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
-	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
-		(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
-			 2) << 7)) {
+	if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+			    (QL_RESOURCE_BITS_BASE_CODE |
+			     (qdev->mac_index) * 2) << 7)) {
 		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 		return 0;
 	}
@@ -1806,7 +1710,6 @@
 	return status;
 }
 
-
 static int ql_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
 {
 	struct ql3_adapter *qdev = netdev_priv(ndev);
@@ -1814,7 +1717,7 @@
 	ecmd->transceiver = XCVR_INTERNAL;
 	ecmd->supported = ql_supported_modes(qdev);
 
-	if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
+	if (test_bit(QL_LINK_OPTICAL, &qdev->flags)) {
 		ecmd->port = PORT_FIBRE;
 	} else {
 		ecmd->port = PORT_TP;
@@ -1855,10 +1758,11 @@
 			      struct ethtool_pauseparam *pause)
 {
 	struct ql3_adapter *qdev = netdev_priv(ndev);
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 
 	u32 reg;
-	if(qdev->mac_index == 0)
+	if (qdev->mac_index == 0)
 		reg = ql_read_page0_reg(qdev, &port_regs->mac0ConfigReg);
 	else
 		reg = ql_read_page0_reg(qdev, &port_regs->mac1ConfigReg);
@@ -1885,12 +1789,12 @@
 
 	while (lrg_buf_cb) {
 		if (!lrg_buf_cb->skb) {
-			lrg_buf_cb->skb = netdev_alloc_skb(qdev->ndev,
-							   qdev->lrg_buffer_len);
+			lrg_buf_cb->skb =
+				netdev_alloc_skb(qdev->ndev,
+						 qdev->lrg_buffer_len);
 			if (unlikely(!lrg_buf_cb->skb)) {
-				printk(KERN_DEBUG PFX
-				       "%s: Failed netdev_alloc_skb().\n",
-				       qdev->ndev->name);
+				netdev_printk(KERN_DEBUG, qdev->ndev,
+					      "Failed netdev_alloc_skb()\n");
 				break;
 			} else {
 				/*
@@ -1905,9 +1809,10 @@
 						     PCI_DMA_FROMDEVICE);
 
 				err = pci_dma_mapping_error(qdev->pdev, map);
-				if(err) {
-					printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
-					       qdev->ndev->name, err);
+				if (err) {
+					netdev_err(qdev->ndev,
+						   "PCI mapping failed with error: %d\n",
+						   err);
 					dev_kfree_skb(lrg_buf_cb->skb);
 					lrg_buf_cb->skb = NULL;
 					break;
@@ -1915,9 +1820,9 @@
 
 
 				lrg_buf_cb->buf_phy_addr_low =
-				    cpu_to_le32(LS_64BITS(map));
+					cpu_to_le32(LS_64BITS(map));
 				lrg_buf_cb->buf_phy_addr_high =
-				    cpu_to_le32(MS_64BITS(map));
+					cpu_to_le32(MS_64BITS(map));
 				dma_unmap_addr_set(lrg_buf_cb, mapaddr, map);
 				dma_unmap_len_set(lrg_buf_cb, maplen,
 						  qdev->lrg_buffer_len -
@@ -1937,7 +1842,9 @@
  */
 static void ql_update_small_bufq_prod_index(struct ql3_adapter *qdev)
 {
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
+
 	if (qdev->small_buf_release_cnt >= 16) {
 		while (qdev->small_buf_release_cnt >= 16) {
 			qdev->small_buf_q_producer_index++;
@@ -1961,7 +1868,8 @@
 	struct bufq_addr_element *lrg_buf_q_ele;
 	int i;
 	struct ql_rcv_buf_cb *lrg_buf_cb;
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 
 	if ((qdev->lrg_buf_free_count >= 8) &&
 	    (qdev->lrg_buf_release_cnt >= 16)) {
@@ -1989,7 +1897,8 @@
 
 			qdev->lrg_buf_q_producer_index++;
 
-			if (qdev->lrg_buf_q_producer_index == qdev->num_lbufq_entries)
+			if (qdev->lrg_buf_q_producer_index ==
+			    qdev->num_lbufq_entries)
 				qdev->lrg_buf_q_producer_index = 0;
 
 			if (qdev->lrg_buf_q_producer_index ==
@@ -2011,23 +1920,26 @@
 	int i;
 	int retval = 0;
 
-	if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
-		printk(KERN_WARNING "Frame short but, frame was padded and sent.\n");
+	if (mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
+		netdev_warn(qdev->ndev,
+			    "Frame too short but it was padded and sent\n");
 	}
 
 	tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
 
 	/*  Check the transmit response flags for any errors */
-	if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
-		printk(KERN_ERR "Frame too short to be legal, frame not sent.\n");
+	if (mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
+		netdev_err(qdev->ndev,
+			   "Frame too short to be legal, frame not sent\n");
 
 		qdev->ndev->stats.tx_errors++;
 		retval = -EIO;
 		goto frame_not_sent;
 	}
 
-	if(tx_cb->seg_count == 0) {
-		printk(KERN_ERR "tx_cb->seg_count == 0: %d\n", mac_rsp->transaction_id);
+	if (tx_cb->seg_count == 0) {
+		netdev_err(qdev->ndev, "tx_cb->seg_count == 0: %d\n",
+			   mac_rsp->transaction_id);
 
 		qdev->ndev->stats.tx_errors++;
 		retval = -EIO;
@@ -2073,7 +1985,7 @@
 	qdev->lrg_buf_release_cnt++;
 	if (++qdev->lrg_buf_index == qdev->num_large_buffers)
 		qdev->lrg_buf_index = 0;
-	return(lrg_buf_cb);
+	return lrg_buf_cb;
 }
 
 /*
@@ -2177,12 +2089,11 @@
 		if (checksum &
 			(IB_IP_IOCB_RSP_3032_ICE |
 			 IB_IP_IOCB_RSP_3032_CE)) {
-			printk(KERN_ERR
-			       "%s: Bad checksum for this %s packet, checksum = %x.\n",
-			       __func__,
-			       ((checksum &
-				IB_IP_IOCB_RSP_3032_TCP) ? "TCP" :
-				"UDP"),checksum);
+			netdev_err(ndev,
+				   "%s: Bad checksum for this %s packet, checksum = %x\n",
+				   __func__,
+				   ((checksum & IB_IP_IOCB_RSP_3032_TCP) ?
+				    "TCP" : "UDP"), checksum);
 		} else if ((checksum & IB_IP_IOCB_RSP_3032_TCP) ||
 				(checksum & IB_IP_IOCB_RSP_3032_UDP &&
 				!(checksum & IB_IP_IOCB_RSP_3032_NUC))) {
@@ -2215,8 +2126,8 @@
 		net_rsp = qdev->rsp_current;
 		rmb();
 		/*
-		 * Fix 4032 chipe undocumented "feature" where bit-8 is set if the
-		 * inbound completion is for a VLAN.
+		 * Fix 4032 chip's undocumented "feature" where bit-8 is set
+		 * if the inbound completion is for a VLAN.
 		 */
 		if (qdev->device_id == QL3032_DEVICE_ID)
 			net_rsp->opcode &= 0x7f;
@@ -2242,22 +2153,18 @@
 						 net_rsp);
 			(*rx_cleaned)++;
 			break;
-		default:
-			{
-				u32 *tmp = (u32 *) net_rsp;
-				printk(KERN_ERR PFX
-				       "%s: Hit default case, not "
-				       "handled!\n"
-				       "	dropping the packet, opcode = "
-				       "%x.\n",
-				       ndev->name, net_rsp->opcode);
-				printk(KERN_ERR PFX
-				       "0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
-				       (unsigned long int)tmp[0],
-				       (unsigned long int)tmp[1],
-				       (unsigned long int)tmp[2],
-				       (unsigned long int)tmp[3]);
-			}
+		default: {
+			u32 *tmp = (u32 *)net_rsp;
+			netdev_err(ndev,
+				   "Hit default case, not handled!\n"
+				   "	dropping the packet, opcode = %x\n"
+				   "0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
+				   net_rsp->opcode,
+				   (unsigned long int)tmp[0],
+				   (unsigned long int)tmp[1],
+				   (unsigned long int)tmp[2],
+				   (unsigned long int)tmp[3]);
+		}
 		}
 
 		qdev->rsp_consumer_index++;
@@ -2280,7 +2187,8 @@
 	struct ql3_adapter *qdev = container_of(napi, struct ql3_adapter, napi);
 	int rx_cleaned = 0, tx_cleaned = 0;
 	unsigned long hw_flags;
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 
 	ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, budget);
 
@@ -2303,15 +2211,14 @@
 
 	struct net_device *ndev = dev_id;
 	struct ql3_adapter *qdev = netdev_priv(ndev);
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 	u32 value;
 	int handled = 1;
 	u32 var;
 
-	port_regs = qdev->mem_map_registers;
-
-	value =
-	    ql_read_common_reg_l(qdev, &port_regs->CommonRegs.ispControlStatus);
+	value = ql_read_common_reg_l(qdev,
+				     &port_regs->CommonRegs.ispControlStatus);
 
 	if (value & (ISP_CONTROL_FE | ISP_CONTROL_RI)) {
 		spin_lock(&qdev->adapter_lock);
@@ -2319,7 +2226,7 @@
 		netif_carrier_off(qdev->ndev);
 		ql_disable_interrupts(qdev);
 		qdev->port_link_state = LS_DOWN;
-		set_bit(QL_RESET_ACTIVE,&qdev->flags) ;
+		set_bit(QL_RESET_ACTIVE, &qdev->flags) ;
 
 		if (value & ISP_CONTROL_FE) {
 			/*
@@ -2328,69 +2235,53 @@
 			var =
 			    ql_read_page0_reg_l(qdev,
 					      &port_regs->PortFatalErrStatus);
-			printk(KERN_WARNING PFX
-			       "%s: Resetting chip. PortFatalErrStatus "
-			       "register = 0x%x\n", ndev->name, var);
-			set_bit(QL_RESET_START,&qdev->flags) ;
+			netdev_warn(ndev,
+				    "Resetting chip. PortFatalErrStatus register = 0x%x\n",
+				    var);
+			set_bit(QL_RESET_START, &qdev->flags) ;
 		} else {
 			/*
 			 * Soft Reset Requested.
 			 */
-			set_bit(QL_RESET_PER_SCSI,&qdev->flags) ;
-			printk(KERN_ERR PFX
-			       "%s: Another function issued a reset to the "
-			       "chip. ISR value = %x.\n", ndev->name, value);
+			set_bit(QL_RESET_PER_SCSI, &qdev->flags) ;
+			netdev_err(ndev,
+				   "Another function issued a reset to the chip. ISR value = %x\n",
+				   value);
 		}
 		queue_delayed_work(qdev->workqueue, &qdev->reset_work, 0);
 		spin_unlock(&qdev->adapter_lock);
 	} else if (value & ISP_IMR_DISABLE_CMPL_INT) {
 		ql_disable_interrupts(qdev);
-		if (likely(napi_schedule_prep(&qdev->napi))) {
+		if (likely(napi_schedule_prep(&qdev->napi)))
 			__napi_schedule(&qdev->napi);
-		}
-	} else {
+	} else
 		return IRQ_NONE;
-	}
 
 	return IRQ_RETVAL(handled);
 }
 
 /*
- * Get the total number of segments needed for the
- * given number of fragments.  This is necessary because
- * outbound address lists (OAL) will be used when more than
- * two frags are given.  Each address list has 5 addr/len
- * pairs.  The 5th pair in each AOL is used to  point to
- * the next AOL if more frags are coming.
- * That is why the frags:segment count  ratio is not linear.
+ * Get the total number of segments needed for the given number of fragments.
+ * This is necessary because outbound address lists (OAL) will be used when
+ * more than two frags are given.  Each address list has 5 addr/len pairs.
+ * The 5th pair in each OAL is used to  point to the next OAL if more frags
+ * are coming.  That is why the frags:segment count ratio is not linear.
  */
-static int ql_get_seg_count(struct ql3_adapter *qdev,
-			    unsigned short frags)
+static int ql_get_seg_count(struct ql3_adapter *qdev, unsigned short frags)
 {
 	if (qdev->device_id == QL3022_DEVICE_ID)
 		return 1;
 
-	switch(frags) {
-	case 0:	return 1;	/* just the skb->data seg */
-	case 1:	return 2;	/* skb->data + 1 frag */
-	case 2:	return 3;	/* skb->data + 2 frags */
-	case 3:	return 5;	/* skb->data + 1 frag + 1 AOL containting 2 frags */
-	case 4:	return 6;
-	case 5:	return 7;
-	case 6:	return 8;
-	case 7:	return 10;
-	case 8:	return 11;
-	case 9:	return 12;
-	case 10: return 13;
-	case 11: return 15;
-	case 12: return 16;
-	case 13: return 17;
-	case 14: return 18;
-	case 15: return 20;
-	case 16: return 21;
-	case 17: return 22;
-	case 18: return 23;
-	}
+	if (frags <= 2)
+		return frags + 1;
+	else if (frags <= 6)
+		return frags + 2;
+	else if (frags <= 10)
+		return frags + 3;
+	else if (frags <= 14)
+		return frags + 4;
+	else if (frags <= 18)
+		return frags + 5;
 	return -1;
 }
 
@@ -2413,8 +2304,8 @@
 }
 
 /*
- * Map the buffers for this transmit.  This will return
- * NETDEV_TX_BUSY or NETDEV_TX_OK based on success.
+ * Map the buffers for this transmit.
+ * This will return NETDEV_TX_BUSY or NETDEV_TX_OK based on success.
  */
 static int ql_send_map(struct ql3_adapter *qdev,
 				struct ob_mac_iocb_req *mac_iocb_ptr,
@@ -2437,9 +2328,9 @@
 	map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE);
 
 	err = pci_dma_mapping_error(qdev->pdev, map);
-	if(err) {
-		printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
-		       qdev->ndev->name, err);
+	if (err) {
+		netdev_err(qdev->ndev, "PCI mapping failed with error: %d\n",
+			   err);
 
 		return NETDEV_TX_BUSY;
 	}
@@ -2455,65 +2346,67 @@
 	if (seg_cnt == 1) {
 		/* Terminate the last segment. */
 		oal_entry->len |= cpu_to_le32(OAL_LAST_ENTRY);
-	} else {
-		oal = tx_cb->oal;
-		for (completed_segs=0; completed_segs<frag_cnt; completed_segs++,seg++) {
-			skb_frag_t *frag = &skb_shinfo(skb)->frags[completed_segs];
-			oal_entry++;
-			if ((seg == 2 && seg_cnt > 3) ||	/* Check for continuation */
-			    (seg == 7 && seg_cnt > 8) ||	/* requirements. It's strange */
-			    (seg == 12 && seg_cnt > 13) ||	/* but necessary. */
-			    (seg == 17 && seg_cnt > 18)) {
-				/* Continuation entry points to outbound address list. */
-				map = pci_map_single(qdev->pdev, oal,
-						     sizeof(struct oal),
-						     PCI_DMA_TODEVICE);
-
-				err = pci_dma_mapping_error(qdev->pdev, map);
-				if(err) {
-
-					printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n",
-					       qdev->ndev->name, err);
-					goto map_error;
-				}
-
-				oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
-				oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
-				oal_entry->len =
-				    cpu_to_le32(sizeof(struct oal) |
-						OAL_CONT_ENTRY);
-				dma_unmap_addr_set(&tx_cb->map[seg], mapaddr,
-						   map);
-				dma_unmap_len_set(&tx_cb->map[seg], maplen,
-						  sizeof(struct oal));
-				oal_entry = (struct oal_entry *)oal;
-				oal++;
-				seg++;
-			}
-
-			map =
-			    pci_map_page(qdev->pdev, frag->page,
-					 frag->page_offset, frag->size,
-					 PCI_DMA_TODEVICE);
+		return NETDEV_TX_OK;
+	}
+	oal = tx_cb->oal;
+	for (completed_segs = 0;
+	     completed_segs < frag_cnt;
+	     completed_segs++, seg++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[completed_segs];
+		oal_entry++;
+		/*
+		 * Check for continuation requirements.
+		 * It's strange but necessary.
+		 * Continuation entry points to outbound address list.
+		 */
+		if ((seg == 2 && seg_cnt > 3) ||
+		    (seg == 7 && seg_cnt > 8) ||
+		    (seg == 12 && seg_cnt > 13) ||
+		    (seg == 17 && seg_cnt > 18)) {
+			map = pci_map_single(qdev->pdev, oal,
+					     sizeof(struct oal),
+					     PCI_DMA_TODEVICE);
 
 			err = pci_dma_mapping_error(qdev->pdev, map);
-			if(err) {
-				printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n",
-				       qdev->ndev->name, err);
+			if (err) {
+				netdev_err(qdev->ndev,
+					   "PCI mapping outbound address list with error: %d\n",
+					   err);
 				goto map_error;
 			}
 
 			oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
 			oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
-			oal_entry->len = cpu_to_le32(frag->size);
+			oal_entry->len = cpu_to_le32(sizeof(struct oal) |
+						     OAL_CONT_ENTRY);
 			dma_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
 			dma_unmap_len_set(&tx_cb->map[seg], maplen,
-					  frag->size);
+					  sizeof(struct oal));
+			oal_entry = (struct oal_entry *)oal;
+			oal++;
+			seg++;
 		}
-		/* Terminate the last segment. */
-		oal_entry->len |= cpu_to_le32(OAL_LAST_ENTRY);
-	}
 
+		map = pci_map_page(qdev->pdev, frag->page,
+				   frag->page_offset, frag->size,
+				   PCI_DMA_TODEVICE);
+
+		err = pci_dma_mapping_error(qdev->pdev, map);
+		if (err) {
+			netdev_err(qdev->ndev,
+				   "PCI mapping frags failed with error: %d\n",
+				   err);
+			goto map_error;
+		}
+
+		oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+		oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+		oal_entry->len = cpu_to_le32(frag->size);
+		dma_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+		dma_unmap_len_set(&tx_cb->map[seg], maplen, frag->size);
+		}
+	/* Terminate the last segment. */
+	oal_entry->len |= cpu_to_le32(OAL_LAST_ENTRY);
 	return NETDEV_TX_OK;
 
 map_error:
@@ -2525,13 +2418,18 @@
 	seg = 1;
 	oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
 	oal = tx_cb->oal;
-	for (i=0; i<completed_segs; i++,seg++) {
+	for (i = 0; i < completed_segs; i++, seg++) {
 		oal_entry++;
 
-		if((seg == 2 && seg_cnt > 3) ||        /* Check for continuation */
-		   (seg == 7 && seg_cnt > 8) ||        /* requirements. It's strange */
-		   (seg == 12 && seg_cnt > 13) ||      /* but necessary. */
-		   (seg == 17 && seg_cnt > 18)) {
+		/*
+		 * Check for continuation requirements.
+		 * It's strange but necessary.
+		 */
+
+		if ((seg == 2 && seg_cnt > 3) ||
+		    (seg == 7 && seg_cnt > 8) ||
+		    (seg == 12 && seg_cnt > 13) ||
+		    (seg == 17 && seg_cnt > 18)) {
 			pci_unmap_single(qdev->pdev,
 				dma_unmap_addr(&tx_cb->map[seg], mapaddr),
 				dma_unmap_len(&tx_cb->map[seg], maplen),
@@ -2570,19 +2468,20 @@
 			       struct net_device *ndev)
 {
 	struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+			qdev->mem_map_registers;
 	struct ql_tx_buf_cb *tx_cb;
 	u32 tot_len = skb->len;
 	struct ob_mac_iocb_req *mac_iocb_ptr;
 
-	if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
+	if (unlikely(atomic_read(&qdev->tx_count) < 2))
 		return NETDEV_TX_BUSY;
-	}
 
-	tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
-	if((tx_cb->seg_count = ql_get_seg_count(qdev,
-						(skb_shinfo(skb)->nr_frags))) == -1) {
-		printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__);
+	tx_cb = &qdev->tx_buf[qdev->req_producer_index];
+	tx_cb->seg_count = ql_get_seg_count(qdev,
+					     skb_shinfo(skb)->nr_frags);
+	if (tx_cb->seg_count == -1) {
+		netdev_err(ndev, "%s: invalid segment count!\n", __func__);
 		return NETDEV_TX_OK;
 	}
 
@@ -2598,8 +2497,8 @@
 	    skb->ip_summed == CHECKSUM_PARTIAL)
 		ql_hw_csum_setup(skb, mac_iocb_ptr);
 
-	if(ql_send_map(qdev,mac_iocb_ptr,tx_cb,skb) != NETDEV_TX_OK) {
-		printk(KERN_ERR PFX"%s: Could not map the segments!\n",__func__);
+	if (ql_send_map(qdev, mac_iocb_ptr, tx_cb, skb) != NETDEV_TX_OK) {
+		netdev_err(ndev, "%s: Could not map the segments!\n", __func__);
 		return NETDEV_TX_BUSY;
 	}
 
@@ -2612,9 +2511,9 @@
 			    &port_regs->CommonRegs.reqQProducerIndex,
 			    qdev->req_producer_index);
 
-	if (netif_msg_tx_queued(qdev))
-		printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n",
-		       ndev->name, qdev->req_producer_index, skb->len);
+	netif_printk(qdev, tx_queued, KERN_DEBUG, ndev,
+		     "tx queued, slot %d, len %d\n",
+		     qdev->req_producer_index, skb->len);
 
 	atomic_dec(&qdev->tx_count);
 	return NETDEV_TX_OK;
@@ -2632,8 +2531,7 @@
 
 	if ((qdev->req_q_virt_addr == NULL) ||
 	    LS_64BITS(qdev->req_q_phy_addr) & (qdev->req_q_size - 1)) {
-		printk(KERN_ERR PFX "%s: reqQ failed.\n",
-		       qdev->ndev->name);
+		netdev_err(qdev->ndev, "reqQ failed\n");
 		return -ENOMEM;
 	}
 
@@ -2646,25 +2544,22 @@
 
 	if ((qdev->rsp_q_virt_addr == NULL) ||
 	    LS_64BITS(qdev->rsp_q_phy_addr) & (qdev->rsp_q_size - 1)) {
-		printk(KERN_ERR PFX
-		       "%s: rspQ allocation failed\n",
-		       qdev->ndev->name);
+		netdev_err(qdev->ndev, "rspQ allocation failed\n");
 		pci_free_consistent(qdev->pdev, (size_t) qdev->req_q_size,
 				    qdev->req_q_virt_addr,
 				    qdev->req_q_phy_addr);
 		return -ENOMEM;
 	}
 
-	set_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags);
+	set_bit(QL_ALLOC_REQ_RSP_Q_DONE, &qdev->flags);
 
 	return 0;
 }
 
 static void ql_free_net_req_rsp_queues(struct ql3_adapter *qdev)
 {
-	if (!test_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags)) {
-		printk(KERN_INFO PFX
-		       "%s: Already done.\n", qdev->ndev->name);
+	if (!test_bit(QL_ALLOC_REQ_RSP_Q_DONE, &qdev->flags)) {
+		netdev_info(qdev->ndev, "Already done\n");
 		return;
 	}
 
@@ -2680,34 +2575,34 @@
 
 	qdev->rsp_q_virt_addr = NULL;
 
-	clear_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags);
+	clear_bit(QL_ALLOC_REQ_RSP_Q_DONE, &qdev->flags);
 }
 
 static int ql_alloc_buffer_queues(struct ql3_adapter *qdev)
 {
 	/* Create Large Buffer Queue */
 	qdev->lrg_buf_q_size =
-	    qdev->num_lbufq_entries * sizeof(struct lrg_buf_q_entry);
+		qdev->num_lbufq_entries * sizeof(struct lrg_buf_q_entry);
 	if (qdev->lrg_buf_q_size < PAGE_SIZE)
 		qdev->lrg_buf_q_alloc_size = PAGE_SIZE;
 	else
 		qdev->lrg_buf_q_alloc_size = qdev->lrg_buf_q_size * 2;
 
-	qdev->lrg_buf = kmalloc(qdev->num_large_buffers * sizeof(struct ql_rcv_buf_cb),GFP_KERNEL);
+	qdev->lrg_buf =
+		kmalloc(qdev->num_large_buffers * sizeof(struct ql_rcv_buf_cb),
+			GFP_KERNEL);
 	if (qdev->lrg_buf == NULL) {
-		printk(KERN_ERR PFX
-		       "%s: qdev->lrg_buf alloc failed.\n", qdev->ndev->name);
+		netdev_err(qdev->ndev, "qdev->lrg_buf alloc failed\n");
 		return -ENOMEM;
 	}
 
 	qdev->lrg_buf_q_alloc_virt_addr =
-	    pci_alloc_consistent(qdev->pdev,
-				 qdev->lrg_buf_q_alloc_size,
-				 &qdev->lrg_buf_q_alloc_phy_addr);
+		pci_alloc_consistent(qdev->pdev,
+				     qdev->lrg_buf_q_alloc_size,
+				     &qdev->lrg_buf_q_alloc_phy_addr);
 
 	if (qdev->lrg_buf_q_alloc_virt_addr == NULL) {
-		printk(KERN_ERR PFX
-		       "%s: lBufQ failed\n", qdev->ndev->name);
+		netdev_err(qdev->ndev, "lBufQ failed\n");
 		return -ENOMEM;
 	}
 	qdev->lrg_buf_q_virt_addr = qdev->lrg_buf_q_alloc_virt_addr;
@@ -2715,21 +2610,19 @@
 
 	/* Create Small Buffer Queue */
 	qdev->small_buf_q_size =
-	    NUM_SBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry);
+		NUM_SBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry);
 	if (qdev->small_buf_q_size < PAGE_SIZE)
 		qdev->small_buf_q_alloc_size = PAGE_SIZE;
 	else
 		qdev->small_buf_q_alloc_size = qdev->small_buf_q_size * 2;
 
 	qdev->small_buf_q_alloc_virt_addr =
-	    pci_alloc_consistent(qdev->pdev,
-				 qdev->small_buf_q_alloc_size,
-				 &qdev->small_buf_q_alloc_phy_addr);
+		pci_alloc_consistent(qdev->pdev,
+				     qdev->small_buf_q_alloc_size,
+				     &qdev->small_buf_q_alloc_phy_addr);
 
 	if (qdev->small_buf_q_alloc_virt_addr == NULL) {
-		printk(KERN_ERR PFX
-		       "%s: Small Buffer Queue allocation failed.\n",
-		       qdev->ndev->name);
+		netdev_err(qdev->ndev, "Small Buffer Queue allocation failed\n");
 		pci_free_consistent(qdev->pdev, qdev->lrg_buf_q_alloc_size,
 				    qdev->lrg_buf_q_alloc_virt_addr,
 				    qdev->lrg_buf_q_alloc_phy_addr);
@@ -2738,18 +2631,17 @@
 
 	qdev->small_buf_q_virt_addr = qdev->small_buf_q_alloc_virt_addr;
 	qdev->small_buf_q_phy_addr = qdev->small_buf_q_alloc_phy_addr;
-	set_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags);
+	set_bit(QL_ALLOC_BUFQS_DONE, &qdev->flags);
 	return 0;
 }
 
 static void ql_free_buffer_queues(struct ql3_adapter *qdev)
 {
-	if (!test_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags)) {
-		printk(KERN_INFO PFX
-		       "%s: Already done.\n", qdev->ndev->name);
+	if (!test_bit(QL_ALLOC_BUFQS_DONE, &qdev->flags)) {
+		netdev_info(qdev->ndev, "Already done\n");
 		return;
 	}
-	if(qdev->lrg_buf) kfree(qdev->lrg_buf);
+	kfree(qdev->lrg_buf);
 	pci_free_consistent(qdev->pdev,
 			    qdev->lrg_buf_q_alloc_size,
 			    qdev->lrg_buf_q_alloc_virt_addr,
@@ -2764,7 +2656,7 @@
 
 	qdev->small_buf_q_virt_addr = NULL;
 
-	clear_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags);
+	clear_bit(QL_ALLOC_BUFQS_DONE, &qdev->flags);
 }
 
 static int ql_alloc_small_buffers(struct ql3_adapter *qdev)
@@ -2774,18 +2666,16 @@
 
 	/* Currently we allocate on one of memory and use it for smallbuffers */
 	qdev->small_buf_total_size =
-	    (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES *
-	     QL_SMALL_BUFFER_SIZE);
+		(QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES *
+		 QL_SMALL_BUFFER_SIZE);
 
 	qdev->small_buf_virt_addr =
-	    pci_alloc_consistent(qdev->pdev,
-				 qdev->small_buf_total_size,
-				 &qdev->small_buf_phy_addr);
+		pci_alloc_consistent(qdev->pdev,
+				     qdev->small_buf_total_size,
+				     &qdev->small_buf_phy_addr);
 
 	if (qdev->small_buf_virt_addr == NULL) {
-		printk(KERN_ERR PFX
-		       "%s: Failed to get small buffer memory.\n",
-		       qdev->ndev->name);
+		netdev_err(qdev->ndev, "Failed to get small buffer memory\n");
 		return -ENOMEM;
 	}
 
@@ -2804,15 +2694,14 @@
 		small_buf_q_entry++;
 	}
 	qdev->small_buf_index = 0;
-	set_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags);
+	set_bit(QL_ALLOC_SMALL_BUF_DONE, &qdev->flags);
 	return 0;
 }
 
 static void ql_free_small_buffers(struct ql3_adapter *qdev)
 {
-	if (!test_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags)) {
-		printk(KERN_INFO PFX
-		       "%s: Already done.\n", qdev->ndev->name);
+	if (!test_bit(QL_ALLOC_SMALL_BUF_DONE, &qdev->flags)) {
+		netdev_info(qdev->ndev, "Already done\n");
 		return;
 	}
 	if (qdev->small_buf_virt_addr != NULL) {
@@ -2874,11 +2763,9 @@
 				       qdev->lrg_buffer_len);
 		if (unlikely(!skb)) {
 			/* Better luck next round */
-			printk(KERN_ERR PFX
-			       "%s: large buff alloc failed, "
-			       "for %d bytes at index %d.\n",
-			       qdev->ndev->name,
-			       qdev->lrg_buffer_len * 2, i);
+			netdev_err(qdev->ndev,
+				   "large buff alloc failed for %d bytes at index %d\n",
+				   qdev->lrg_buffer_len * 2, i);
 			ql_free_large_buffers(qdev);
 			return -ENOMEM;
 		} else {
@@ -2899,9 +2786,10 @@
 					     PCI_DMA_FROMDEVICE);
 
 			err = pci_dma_mapping_error(qdev->pdev, map);
-			if(err) {
-				printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
-				       qdev->ndev->name, err);
+			if (err) {
+				netdev_err(qdev->ndev,
+					   "PCI mapping failed with error: %d\n",
+					   err);
 				ql_free_large_buffers(qdev);
 				return -ENOMEM;
 			}
@@ -2926,10 +2814,8 @@
 
 	tx_cb = &qdev->tx_buf[0];
 	for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
-		if (tx_cb->oal) {
-			kfree(tx_cb->oal);
-			tx_cb->oal = NULL;
-		}
+		kfree(tx_cb->oal);
+		tx_cb->oal = NULL;
 		tx_cb++;
 	}
 }
@@ -2938,8 +2824,7 @@
 {
 	struct ql_tx_buf_cb *tx_cb;
 	int i;
-	struct ob_mac_iocb_req *req_q_curr =
-					qdev->req_q_virt_addr;
+	struct ob_mac_iocb_req *req_q_curr = qdev->req_q_virt_addr;
 
 	/* Create free list of transmit buffers */
 	for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
@@ -2960,23 +2845,22 @@
 	if (qdev->ndev->mtu == NORMAL_MTU_SIZE) {
 		qdev->num_lbufq_entries = NUM_LBUFQ_ENTRIES;
 		qdev->lrg_buffer_len = NORMAL_MTU_SIZE;
-	}
-	else if (qdev->ndev->mtu == JUMBO_MTU_SIZE) {
+	} else if (qdev->ndev->mtu == JUMBO_MTU_SIZE) {
 		/*
 		 * Bigger buffers, so less of them.
 		 */
 		qdev->num_lbufq_entries = JUMBO_NUM_LBUFQ_ENTRIES;
 		qdev->lrg_buffer_len = JUMBO_MTU_SIZE;
 	} else {
-		printk(KERN_ERR PFX
-		       "%s: Invalid mtu size.  Only 1500 and 9000 are accepted.\n",
-		       qdev->ndev->name);
+		netdev_err(qdev->ndev, "Invalid mtu size: %d.  Only %d and %d are accepted.\n",
+			   qdev->ndev->mtu, NORMAL_MTU_SIZE, JUMBO_MTU_SIZE);
 		return -ENOMEM;
 	}
-	qdev->num_large_buffers = qdev->num_lbufq_entries * QL_ADDR_ELE_PER_BUFQ_ENTRY;
+	qdev->num_large_buffers =
+		qdev->num_lbufq_entries * QL_ADDR_ELE_PER_BUFQ_ENTRY;
 	qdev->lrg_buffer_len += VLAN_ETH_HLEN + VLAN_ID_LEN + QL_HEADER_SPACE;
 	qdev->max_frame_size =
-	    (qdev->lrg_buffer_len - QL_HEADER_SPACE) + ETHERNET_CRC_SIZE;
+		(qdev->lrg_buffer_len - QL_HEADER_SPACE) + ETHERNET_CRC_SIZE;
 
 	/*
 	 * First allocate a page of shared memory and use it for shadow
@@ -2984,51 +2868,44 @@
 	 * Network Completion Queue Producer Index Register
 	 */
 	qdev->shadow_reg_virt_addr =
-	    pci_alloc_consistent(qdev->pdev,
-				 PAGE_SIZE, &qdev->shadow_reg_phy_addr);
+		pci_alloc_consistent(qdev->pdev,
+				     PAGE_SIZE, &qdev->shadow_reg_phy_addr);
 
 	if (qdev->shadow_reg_virt_addr != NULL) {
 		qdev->preq_consumer_index = (u16 *) qdev->shadow_reg_virt_addr;
 		qdev->req_consumer_index_phy_addr_high =
-		    MS_64BITS(qdev->shadow_reg_phy_addr);
+			MS_64BITS(qdev->shadow_reg_phy_addr);
 		qdev->req_consumer_index_phy_addr_low =
-		    LS_64BITS(qdev->shadow_reg_phy_addr);
+			LS_64BITS(qdev->shadow_reg_phy_addr);
 
 		qdev->prsp_producer_index =
-		    (__le32 *) (((u8 *) qdev->preq_consumer_index) + 8);
+			(__le32 *) (((u8 *) qdev->preq_consumer_index) + 8);
 		qdev->rsp_producer_index_phy_addr_high =
-		    qdev->req_consumer_index_phy_addr_high;
+			qdev->req_consumer_index_phy_addr_high;
 		qdev->rsp_producer_index_phy_addr_low =
-		    qdev->req_consumer_index_phy_addr_low + 8;
+			qdev->req_consumer_index_phy_addr_low + 8;
 	} else {
-		printk(KERN_ERR PFX
-		       "%s: shadowReg Alloc failed.\n", qdev->ndev->name);
+		netdev_err(qdev->ndev, "shadowReg Alloc failed\n");
 		return -ENOMEM;
 	}
 
 	if (ql_alloc_net_req_rsp_queues(qdev) != 0) {
-		printk(KERN_ERR PFX
-		       "%s: ql_alloc_net_req_rsp_queues failed.\n",
-		       qdev->ndev->name);
+		netdev_err(qdev->ndev, "ql_alloc_net_req_rsp_queues failed\n");
 		goto err_req_rsp;
 	}
 
 	if (ql_alloc_buffer_queues(qdev) != 0) {
-		printk(KERN_ERR PFX
-		       "%s: ql_alloc_buffer_queues failed.\n",
-		       qdev->ndev->name);
+		netdev_err(qdev->ndev, "ql_alloc_buffer_queues failed\n");
 		goto err_buffer_queues;
 	}
 
 	if (ql_alloc_small_buffers(qdev) != 0) {
-		printk(KERN_ERR PFX
-		       "%s: ql_alloc_small_buffers failed\n", qdev->ndev->name);
+		netdev_err(qdev->ndev, "ql_alloc_small_buffers failed\n");
 		goto err_small_buffers;
 	}
 
 	if (ql_alloc_large_buffers(qdev) != 0) {
-		printk(KERN_ERR PFX
-		       "%s: ql_alloc_large_buffers failed\n", qdev->ndev->name);
+		netdev_err(qdev->ndev, "ql_alloc_large_buffers failed\n");
 		goto err_small_buffers;
 	}
 
@@ -3076,7 +2953,7 @@
 	struct ql3xxx_local_ram_registers __iomem *local_ram =
 	    (void __iomem *)qdev->mem_map_registers;
 
-	if(ql_sem_spinlock(qdev, QL_DDR_RAM_SEM_MASK,
+	if (ql_sem_spinlock(qdev, QL_DDR_RAM_SEM_MASK,
 			(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
 			 2) << 4))
 		return -1;
@@ -3132,18 +3009,20 @@
 static int ql_adapter_initialize(struct ql3_adapter *qdev)
 {
 	u32 value;
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
+	u32 *spir = &port_regs->CommonRegs.serialPortInterfaceReg;
 	struct ql3xxx_host_memory_registers __iomem *hmem_regs =
-						(void __iomem *)port_regs;
+		(void __iomem *)port_regs;
 	u32 delay = 10;
 	int status = 0;
 	unsigned long hw_flags = 0;
 
-	if(ql_mii_setup(qdev))
+	if (ql_mii_setup(qdev))
 		return -1;
 
 	/* Bring out PHY out of reset */
-	ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+	ql_write_common_reg(qdev, spir,
 			    (ISP_SERIAL_PORT_IF_WE |
 			     (ISP_SERIAL_PORT_IF_WE << 16)));
 	/* Give the PHY time to come out of reset. */
@@ -3152,13 +3031,13 @@
 	netif_carrier_off(qdev->ndev);
 
 	/* V2 chip fix for ARS-39168. */
-	ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+	ql_write_common_reg(qdev, spir,
 			    (ISP_SERIAL_PORT_IF_SDE |
 			     (ISP_SERIAL_PORT_IF_SDE << 16)));
 
 	/* Request Queue Registers */
-	*((u32 *) (qdev->preq_consumer_index)) = 0;
-	atomic_set(&qdev->tx_count,NUM_REQ_Q_ENTRIES);
+	*((u32 *)(qdev->preq_consumer_index)) = 0;
+	atomic_set(&qdev->tx_count, NUM_REQ_Q_ENTRIES);
 	qdev->req_producer_index = 0;
 
 	ql_write_page1_reg(qdev,
@@ -3208,7 +3087,9 @@
 			   &hmem_regs->rxLargeQBaseAddrLow,
 			   LS_64BITS(qdev->lrg_buf_q_phy_addr));
 
-	ql_write_page1_reg(qdev, &hmem_regs->rxLargeQLength, qdev->num_lbufq_entries);
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->rxLargeQLength,
+			   qdev->num_lbufq_entries);
 
 	ql_write_page1_reg(qdev,
 			   &hmem_regs->rxLargeBufferLength,
@@ -3258,7 +3139,7 @@
 	if ((value & PORT_STATUS_IC) == 0) {
 
 		/* Chip has not been configured yet, so let it rip. */
-		if(ql_init_misc_registers(qdev)) {
+		if (ql_init_misc_registers(qdev)) {
 			status = -1;
 			goto out;
 		}
@@ -3268,7 +3149,7 @@
 
 		value = (0xFFFF << 16) | qdev->nvram_data.extHwConfig;
 
-		if(ql_sem_spinlock(qdev, QL_FLASH_SEM_MASK,
+		if (ql_sem_spinlock(qdev, QL_FLASH_SEM_MASK,
 				(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
 				 * 2) << 13)) {
 			status = -1;
@@ -3291,7 +3172,7 @@
 					   &port_regs->mac0MaxFrameLengthReg,
 					   qdev->max_frame_size);
 
-	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+	if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
 			(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
 			 2) << 7)) {
 		status = -1;
@@ -3353,8 +3234,7 @@
 	} while (--delay);
 
 	if (delay == 0) {
-		printk(KERN_ERR PFX
-		       "%s: Hw Initialization timeout.\n", qdev->ndev->name);
+		netdev_err(qdev->ndev, "Hw Initialization timeout\n");
 		status = -1;
 		goto out;
 	}
@@ -3385,7 +3265,8 @@
  */
 static int ql_adapter_reset(struct ql3_adapter *qdev)
 {
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 	int status = 0;
 	u16 value;
 	int max_wait_time;
@@ -3396,17 +3277,14 @@
 	/*
 	 * Issue soft reset to chip.
 	 */
-	printk(KERN_DEBUG PFX
-	       "%s: Issue soft reset to chip.\n",
-	       qdev->ndev->name);
+	netdev_printk(KERN_DEBUG, qdev->ndev, "Issue soft reset to chip\n");
 	ql_write_common_reg(qdev,
 			    &port_regs->CommonRegs.ispControlStatus,
 			    ((ISP_CONTROL_SR << 16) | ISP_CONTROL_SR));
 
 	/* Wait 3 seconds for reset to complete. */
-	printk(KERN_DEBUG PFX
-	       "%s: Wait 10 milliseconds for reset to complete.\n",
-	       qdev->ndev->name);
+	netdev_printk(KERN_DEBUG, qdev->ndev,
+		      "Wait 10 milliseconds for reset to complete\n");
 
 	/* Wait until the firmware tells us the Soft Reset is done */
 	max_wait_time = 5;
@@ -3427,8 +3305,8 @@
 	value =
 	    ql_read_common_reg(qdev, &port_regs->CommonRegs.ispControlStatus);
 	if (value & ISP_CONTROL_RI) {
-		printk(KERN_DEBUG PFX
-		       "ql_adapter_reset: clearing RI after reset.\n");
+		netdev_printk(KERN_DEBUG, qdev->ndev,
+			      "clearing RI after reset\n");
 		ql_write_common_reg(qdev,
 				    &port_regs->CommonRegs.
 				    ispControlStatus,
@@ -3448,13 +3326,11 @@
 		 */
 		max_wait_time = 5;
 		do {
-			value =
-			    ql_read_common_reg(qdev,
-					       &port_regs->CommonRegs.
-					       ispControlStatus);
-			if ((value & ISP_CONTROL_FSR) == 0) {
+			value = ql_read_common_reg(qdev,
+						   &port_regs->CommonRegs.
+						   ispControlStatus);
+			if ((value & ISP_CONTROL_FSR) == 0)
 				break;
-			}
 			ssleep(1);
 		} while ((--max_wait_time));
 	}
@@ -3468,7 +3344,8 @@
 
 static void ql_set_mac_info(struct ql3_adapter *qdev)
 {
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 	u32 value, port_status;
 	u8 func_number;
 
@@ -3484,9 +3361,9 @@
 		qdev->mb_bit_mask = FN0_MA_BITS_MASK;
 		qdev->PHYAddr = PORT0_PHY_ADDRESS;
 		if (port_status & PORT_STATUS_SM0)
-			set_bit(QL_LINK_OPTICAL,&qdev->flags);
+			set_bit(QL_LINK_OPTICAL, &qdev->flags);
 		else
-			clear_bit(QL_LINK_OPTICAL,&qdev->flags);
+			clear_bit(QL_LINK_OPTICAL, &qdev->flags);
 		break;
 
 	case ISP_CONTROL_FN1_NET:
@@ -3495,17 +3372,17 @@
 		qdev->mb_bit_mask = FN1_MA_BITS_MASK;
 		qdev->PHYAddr = PORT1_PHY_ADDRESS;
 		if (port_status & PORT_STATUS_SM1)
-			set_bit(QL_LINK_OPTICAL,&qdev->flags);
+			set_bit(QL_LINK_OPTICAL, &qdev->flags);
 		else
-			clear_bit(QL_LINK_OPTICAL,&qdev->flags);
+			clear_bit(QL_LINK_OPTICAL, &qdev->flags);
 		break;
 
 	case ISP_CONTROL_FN0_SCSI:
 	case ISP_CONTROL_FN1_SCSI:
 	default:
-		printk(KERN_DEBUG PFX
-		       "%s: Invalid function number, ispControlStatus = 0x%x\n",
-		       qdev->ndev->name,value);
+		netdev_printk(KERN_DEBUG, qdev->ndev,
+			      "Invalid function number, ispControlStatus = 0x%x\n",
+			      value);
 		break;
 	}
 	qdev->numPorts = qdev->nvram_data.version_and_numPorts >> 8;
@@ -3516,32 +3393,26 @@
 	struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
 	struct pci_dev *pdev = qdev->pdev;
 
-	printk(KERN_INFO PFX
-	       "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n",
-	       DRV_NAME, qdev->index, qdev->chip_rev_id,
-	       (qdev->device_id == QL3032_DEVICE_ID) ? "QLA3032" : "QLA3022",
-	       qdev->pci_slot);
-	printk(KERN_INFO PFX
-	       "%s Interface.\n",
-	       test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER");
+	netdev_info(ndev,
+		    "%s Adapter %d RevisionID %d found %s on PCI slot %d\n",
+		    DRV_NAME, qdev->index, qdev->chip_rev_id,
+		    qdev->device_id == QL3032_DEVICE_ID ? "QLA3032" : "QLA3022",
+		    qdev->pci_slot);
+	netdev_info(ndev, "%s Interface\n",
+		test_bit(QL_LINK_OPTICAL, &qdev->flags) ? "OPTICAL" : "COPPER");
 
 	/*
 	 * Print PCI bus width/type.
 	 */
-	printk(KERN_INFO PFX
-	       "Bus interface is %s %s.\n",
-	       ((qdev->pci_width == 64) ? "64-bit" : "32-bit"),
-	       ((qdev->pci_x) ? "PCI-X" : "PCI"));
+	netdev_info(ndev, "Bus interface is %s %s\n",
+		    ((qdev->pci_width == 64) ? "64-bit" : "32-bit"),
+		    ((qdev->pci_x) ? "PCI-X" : "PCI"));
 
-	printk(KERN_INFO PFX
-	       "mem  IO base address adjusted = 0x%p\n",
-	       qdev->mem_map_registers);
-	printk(KERN_INFO PFX "Interrupt number = %d\n", pdev->irq);
+	netdev_info(ndev, "mem  IO base address adjusted = 0x%p\n",
+		    qdev->mem_map_registers);
+	netdev_info(ndev, "Interrupt number = %d\n", pdev->irq);
 
-	if (netif_msg_probe(qdev))
-		printk(KERN_INFO PFX
-		       "%s: MAC address %pM\n",
-		       ndev->name, ndev->dev_addr);
+	netif_info(qdev, probe, ndev, "MAC address %pM\n", ndev->dev_addr);
 }
 
 static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
@@ -3552,17 +3423,16 @@
 	netif_stop_queue(ndev);
 	netif_carrier_off(ndev);
 
-	clear_bit(QL_ADAPTER_UP,&qdev->flags);
-	clear_bit(QL_LINK_MASTER,&qdev->flags);
+	clear_bit(QL_ADAPTER_UP, &qdev->flags);
+	clear_bit(QL_LINK_MASTER, &qdev->flags);
 
 	ql_disable_interrupts(qdev);
 
 	free_irq(qdev->pdev->irq, ndev);
 
-	if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) {
-		printk(KERN_INFO PFX
-		       "%s: calling pci_disable_msi().\n", qdev->ndev->name);
-		clear_bit(QL_MSI_ENABLED,&qdev->flags);
+	if (qdev->msi && test_bit(QL_MSI_ENABLED, &qdev->flags)) {
+		netdev_info(qdev->ndev, "calling pci_disable_msi()\n");
+		clear_bit(QL_MSI_ENABLED, &qdev->flags);
 		pci_disable_msi(qdev->pdev);
 	}
 
@@ -3576,17 +3446,16 @@
 
 		spin_lock_irqsave(&qdev->hw_lock, hw_flags);
 		if (ql_wait_for_drvr_lock(qdev)) {
-			if ((soft_reset = ql_adapter_reset(qdev))) {
-				printk(KERN_ERR PFX
-				       "%s: ql_adapter_reset(%d) FAILED!\n",
-				       ndev->name, qdev->index);
+			soft_reset = ql_adapter_reset(qdev);
+			if (soft_reset) {
+				netdev_err(ndev, "ql_adapter_reset(%d) FAILED!\n",
+					   qdev->index);
 			}
-			printk(KERN_ERR PFX
-				"%s: Releaseing driver lock via chip reset.\n",ndev->name);
+			netdev_err(ndev,
+				   "Releasing driver lock via chip reset\n");
 		} else {
-			printk(KERN_ERR PFX
-			       "%s: Could not acquire driver lock to do "
-			       "reset!\n", ndev->name);
+			netdev_err(ndev,
+				   "Could not acquire driver lock to do reset!\n");
 			retval = -1;
 		}
 		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
@@ -3603,56 +3472,50 @@
 	unsigned long hw_flags;
 
 	if (ql_alloc_mem_resources(qdev)) {
-		printk(KERN_ERR PFX
-		       "%s Unable to  allocate buffers.\n", ndev->name);
+		netdev_err(ndev, "Unable to  allocate buffers\n");
 		return -ENOMEM;
 	}
 
 	if (qdev->msi) {
 		if (pci_enable_msi(qdev->pdev)) {
-			printk(KERN_ERR PFX
-			       "%s: User requested MSI, but MSI failed to "
-			       "initialize.  Continuing without MSI.\n",
-			       qdev->ndev->name);
+			netdev_err(ndev,
+				   "User requested MSI, but MSI failed to initialize.  Continuing without MSI.\n");
 			qdev->msi = 0;
 		} else {
-			printk(KERN_INFO PFX "%s: MSI Enabled...\n", qdev->ndev->name);
-			set_bit(QL_MSI_ENABLED,&qdev->flags);
+			netdev_info(ndev, "MSI Enabled...\n");
+			set_bit(QL_MSI_ENABLED, &qdev->flags);
 			irq_flags &= ~IRQF_SHARED;
 		}
 	}
 
-	if ((err = request_irq(qdev->pdev->irq,
-			       ql3xxx_isr,
-			       irq_flags, ndev->name, ndev))) {
-		printk(KERN_ERR PFX
-		       "%s: Failed to reserve interrupt %d already in use.\n",
-		       ndev->name, qdev->pdev->irq);
+	err = request_irq(qdev->pdev->irq, ql3xxx_isr,
+			  irq_flags, ndev->name, ndev);
+	if (err) {
+		netdev_err(ndev,
+			   "Failed to reserve interrupt %d - already in use\n",
+			   qdev->pdev->irq);
 		goto err_irq;
 	}
 
 	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
 
-	if ((err = ql_wait_for_drvr_lock(qdev))) {
-		if ((err = ql_adapter_initialize(qdev))) {
-			printk(KERN_ERR PFX
-			       "%s: Unable to initialize adapter.\n",
-			       ndev->name);
+	err = ql_wait_for_drvr_lock(qdev);
+	if (err) {
+		err = ql_adapter_initialize(qdev);
+		if (err) {
+			netdev_err(ndev, "Unable to initialize adapter\n");
 			goto err_init;
 		}
-		printk(KERN_ERR PFX
-				"%s: Releaseing driver lock.\n",ndev->name);
+		netdev_err(ndev, "Releasing driver lock\n");
 		ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
 	} else {
-		printk(KERN_ERR PFX
-		       "%s: Could not acquire driver lock.\n",
-		       ndev->name);
+		netdev_err(ndev, "Could not acquire driver lock\n");
 		goto err_lock;
 	}
 
 	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 
-	set_bit(QL_ADAPTER_UP,&qdev->flags);
+	set_bit(QL_ADAPTER_UP, &qdev->flags);
 
 	mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
 
@@ -3666,11 +3529,9 @@
 	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 	free_irq(qdev->pdev->irq, ndev);
 err_irq:
-	if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) {
-		printk(KERN_INFO PFX
-		       "%s: calling pci_disable_msi().\n",
-		       qdev->ndev->name);
-		clear_bit(QL_MSI_ENABLED,&qdev->flags);
+	if (qdev->msi && test_bit(QL_MSI_ENABLED, &qdev->flags)) {
+		netdev_info(ndev, "calling pci_disable_msi()\n");
+		clear_bit(QL_MSI_ENABLED, &qdev->flags);
 		pci_disable_msi(qdev->pdev);
 	}
 	return err;
@@ -3678,10 +3539,9 @@
 
 static int ql_cycle_adapter(struct ql3_adapter *qdev, int reset)
 {
-	if( ql_adapter_down(qdev,reset) || ql_adapter_up(qdev)) {
-		printk(KERN_ERR PFX
-				"%s: Driver up/down cycle failed, "
-				"closing device\n",qdev->ndev->name);
+	if (ql_adapter_down(qdev, reset) || ql_adapter_up(qdev)) {
+		netdev_err(qdev->ndev,
+			   "Driver up/down cycle failed, closing device\n");
 		rtnl_lock();
 		dev_close(qdev->ndev);
 		rtnl_unlock();
@@ -3698,24 +3558,24 @@
 	 * Wait for device to recover from a reset.
 	 * (Rarely happens, but possible.)
 	 */
-	while (!test_bit(QL_ADAPTER_UP,&qdev->flags))
+	while (!test_bit(QL_ADAPTER_UP, &qdev->flags))
 		msleep(50);
 
-	ql_adapter_down(qdev,QL_DO_RESET);
+	ql_adapter_down(qdev, QL_DO_RESET);
 	return 0;
 }
 
 static int ql3xxx_open(struct net_device *ndev)
 {
 	struct ql3_adapter *qdev = netdev_priv(ndev);
-	return (ql_adapter_up(qdev));
+	return ql_adapter_up(qdev);
 }
 
 static int ql3xxx_set_mac_address(struct net_device *ndev, void *p)
 {
 	struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
 	struct ql3xxx_port_registers __iomem *port_regs =
-	    		qdev->mem_map_registers;
+			qdev->mem_map_registers;
 	struct sockaddr *addr = p;
 	unsigned long hw_flags;
 
@@ -3750,7 +3610,7 @@
 {
 	struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
 
-	printk(KERN_ERR PFX "%s: Resetting...\n", ndev->name);
+	netdev_err(ndev, "Resetting...\n");
 	/*
 	 * Stop the queues, we've got a problem.
 	 */
@@ -3770,11 +3630,12 @@
 	u32 value;
 	struct ql_tx_buf_cb *tx_cb;
 	int max_wait_time, i;
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 	unsigned long hw_flags;
 
-	if (test_bit((QL_RESET_PER_SCSI | QL_RESET_START),&qdev->flags)) {
-		clear_bit(QL_LINK_MASTER,&qdev->flags);
+	if (test_bit((QL_RESET_PER_SCSI | QL_RESET_START), &qdev->flags)) {
+		clear_bit(QL_LINK_MASTER, &qdev->flags);
 
 		/*
 		 * Loop through the active list and return the skb.
@@ -3783,17 +3644,19 @@
 			int j;
 			tx_cb = &qdev->tx_buf[i];
 			if (tx_cb->skb) {
-				printk(KERN_DEBUG PFX
-				       "%s: Freeing lost SKB.\n",
-				       qdev->ndev->name);
+				netdev_printk(KERN_DEBUG, ndev,
+					      "Freeing lost SKB\n");
 				pci_unmap_single(qdev->pdev,
-					 dma_unmap_addr(&tx_cb->map[0], mapaddr),
+					 dma_unmap_addr(&tx_cb->map[0],
+							mapaddr),
 					 dma_unmap_len(&tx_cb->map[0], maplen),
 					 PCI_DMA_TODEVICE);
-				for(j=1;j<tx_cb->seg_count;j++) {
+				for (j = 1; j < tx_cb->seg_count; j++) {
 					pci_unmap_page(qdev->pdev,
-					       dma_unmap_addr(&tx_cb->map[j],mapaddr),
-					       dma_unmap_len(&tx_cb->map[j],maplen),
+					       dma_unmap_addr(&tx_cb->map[j],
+							      mapaddr),
+					       dma_unmap_len(&tx_cb->map[j],
+							     maplen),
 					       PCI_DMA_TODEVICE);
 				}
 				dev_kfree_skb(tx_cb->skb);
@@ -3801,8 +3664,7 @@
 			}
 		}
 
-		printk(KERN_ERR PFX
-		       "%s: Clearing NRI after reset.\n", qdev->ndev->name);
+		netdev_err(ndev, "Clearing NRI after reset\n");
 		spin_lock_irqsave(&qdev->hw_lock, hw_flags);
 		ql_write_common_reg(qdev,
 				    &port_regs->CommonRegs.
@@ -3818,16 +3680,14 @@
 
 						   ispControlStatus);
 			if ((value & ISP_CONTROL_SR) == 0) {
-				printk(KERN_DEBUG PFX
-				       "%s: reset completed.\n",
-				       qdev->ndev->name);
+				netdev_printk(KERN_DEBUG, ndev,
+					      "reset completed\n");
 				break;
 			}
 
 			if (value & ISP_CONTROL_RI) {
-				printk(KERN_DEBUG PFX
-				       "%s: clearing NRI after reset.\n",
-				       qdev->ndev->name);
+				netdev_printk(KERN_DEBUG, ndev,
+					      "clearing NRI after reset\n");
 				ql_write_common_reg(qdev,
 						    &port_regs->
 						    CommonRegs.
@@ -3848,21 +3708,19 @@
 			 * Set the reset flags and clear the board again.
 			 * Nothing else to do...
 			 */
-			printk(KERN_ERR PFX
-			       "%s: Timed out waiting for reset to "
-			       "complete.\n", ndev->name);
-			printk(KERN_ERR PFX
-			       "%s: Do a reset.\n", ndev->name);
-			clear_bit(QL_RESET_PER_SCSI,&qdev->flags);
-			clear_bit(QL_RESET_START,&qdev->flags);
-			ql_cycle_adapter(qdev,QL_DO_RESET);
+			netdev_err(ndev,
+				   "Timed out waiting for reset to complete\n");
+			netdev_err(ndev, "Do a reset\n");
+			clear_bit(QL_RESET_PER_SCSI, &qdev->flags);
+			clear_bit(QL_RESET_START, &qdev->flags);
+			ql_cycle_adapter(qdev, QL_DO_RESET);
 			return;
 		}
 
-		clear_bit(QL_RESET_ACTIVE,&qdev->flags);
-		clear_bit(QL_RESET_PER_SCSI,&qdev->flags);
-		clear_bit(QL_RESET_START,&qdev->flags);
-		ql_cycle_adapter(qdev,QL_NO_RESET);
+		clear_bit(QL_RESET_ACTIVE, &qdev->flags);
+		clear_bit(QL_RESET_PER_SCSI, &qdev->flags);
+		clear_bit(QL_RESET_START, &qdev->flags);
+		ql_cycle_adapter(qdev, QL_NO_RESET);
 	}
 }
 
@@ -3876,7 +3734,8 @@
 
 static void ql_get_board_info(struct ql3_adapter *qdev)
 {
-	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_port_registers __iomem *port_regs =
+		qdev->mem_map_registers;
 	u32 value;
 
 	value = ql_read_page0_reg_l(qdev, &port_regs->portStatus);
@@ -3915,20 +3774,18 @@
 {
 	struct net_device *ndev = NULL;
 	struct ql3_adapter *qdev = NULL;
-	static int cards_found = 0;
+	static int cards_found;
 	int uninitialized_var(pci_using_dac), err;
 
 	err = pci_enable_device(pdev);
 	if (err) {
-		printk(KERN_ERR PFX "%s cannot enable PCI device\n",
-		       pci_name(pdev));
+		pr_err("%s cannot enable PCI device\n", pci_name(pdev));
 		goto err_out;
 	}
 
 	err = pci_request_regions(pdev, DRV_NAME);
 	if (err) {
-		printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
-		       pci_name(pdev));
+		pr_err("%s cannot obtain PCI resources\n", pci_name(pdev));
 		goto err_out_disable_pdev;
 	}
 
@@ -3943,15 +3800,13 @@
 	}
 
 	if (err) {
-		printk(KERN_ERR PFX "%s no usable DMA configuration\n",
-		       pci_name(pdev));
+		pr_err("%s no usable DMA configuration\n", pci_name(pdev));
 		goto err_out_free_regions;
 	}
 
 	ndev = alloc_etherdev(sizeof(struct ql3_adapter));
 	if (!ndev) {
-		printk(KERN_ERR PFX "%s could not alloc etherdev\n",
-		       pci_name(pdev));
+		pr_err("%s could not alloc etherdev\n", pci_name(pdev));
 		err = -ENOMEM;
 		goto err_out_free_regions;
 	}
@@ -3978,8 +3833,7 @@
 
 	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));
+		pr_err("%s: cannot map device registers\n", pci_name(pdev));
 		err = -EIO;
 		goto err_out_free_ndev;
 	}
@@ -3998,9 +3852,8 @@
 
 	/* make sure the EEPROM is good */
 	if (ql_get_nvram_params(qdev)) {
-		printk(KERN_ALERT PFX
-		       "ql3xxx_probe: Adapter #%d, Invalid NVRAM parameters.\n",
-		       qdev->index);
+		pr_alert("%s: Adapter #%d, Invalid NVRAM parameters\n",
+			 __func__, qdev->index);
 		err = -EIO;
 		goto err_out_iounmap;
 	}
@@ -4026,14 +3879,12 @@
 	 * Set the Maximum Memory Read Byte Count value. We do this to handle
 	 * jumbo frames.
 	 */
-	if (qdev->pci_x) {
+	if (qdev->pci_x)
 		pci_write_config_word(pdev, (int)0x4e, (u16) 0x0036);
-	}
 
 	err = register_netdev(ndev);
 	if (err) {
-		printk(KERN_ERR PFX "%s: cannot register net device\n",
-		       pci_name(pdev));
+		pr_err("%s: cannot register net device\n", pci_name(pdev));
 		goto err_out_iounmap;
 	}
 
@@ -4052,10 +3903,10 @@
 	qdev->adapter_timer.expires = jiffies + HZ * 2;	/* two second delay */
 	qdev->adapter_timer.data = (unsigned long)qdev;
 
-	if(!cards_found) {
-		printk(KERN_ALERT PFX "%s\n", DRV_STRING);
-		printk(KERN_ALERT PFX "Driver name: %s, Version: %s.\n",
-	    	   DRV_NAME, DRV_VERSION);
+	if (!cards_found) {
+		pr_alert("%s\n", DRV_STRING);
+		pr_alert("Driver name: %s, Version: %s\n",
+			 DRV_NAME, DRV_VERSION);
 	}
 	ql_display_dev_info(ndev);
 
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 896d40d..9703893 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -51,8 +51,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 2
-#define QLCNIC_LINUX_VERSIONID  "5.0.2"
+#define _QLCNIC_LINUX_SUBVERSION 7
+#define QLCNIC_LINUX_VERSIONID  "5.0.7"
 #define QLCNIC_DRV_IDC_VER  0x01
 
 #define QLCNIC_VERSION_CODE(a, b, c)	(((a) << 24) + ((b) << 16) + (c))
@@ -68,6 +68,7 @@
 #define QLCNIC_DECODE_VERSION(v) \
 	QLCNIC_VERSION_CODE(((v) & 0xff), (((v) >> 8) & 0xff), ((v) >> 16))
 
+#define QLCNIC_MIN_FW_VERSION     QLCNIC_VERSION_CODE(4, 4, 2)
 #define QLCNIC_NUM_FLASH_SECTORS (64)
 #define QLCNIC_FLASH_SECTOR_SIZE (64 * 1024)
 #define QLCNIC_FLASH_TOTAL_SIZE  (QLCNIC_NUM_FLASH_SECTORS \
@@ -112,8 +113,10 @@
 #define TX_UDPV6_PKT	0x0c
 
 /* Tx defines */
-#define MAX_BUFFERS_PER_CMD	32
-#define TX_STOP_THRESH		((MAX_SKB_FRAGS >> 2) + 4)
+#define MAX_TSO_HEADER_DESC	2
+#define MGMT_CMD_DESC_RESV	4
+#define TX_STOP_THRESH		((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \
+							+ MGMT_CMD_DESC_RESV)
 #define QLCNIC_MAX_TX_TIMEOUTS	2
 
 /*
@@ -197,8 +200,7 @@
 
 	__le64 addr_buffer4;
 
-	__le32 reserved2;
-	__le16 reserved;
+	u8 eth_addr[ETH_ALEN];
 	__le16 vlan_TCI;
 
 } __attribute__ ((aligned(64)));
@@ -315,6 +317,8 @@
 #define QLCNIC_BRDTYPE_P3_10G_XFP	0x0032
 #define QLCNIC_BRDTYPE_P3_10G_TP	0x0080
 
+#define QLCNIC_MSIX_TABLE_OFFSET	0x44
+
 /* Flash memory map */
 #define QLCNIC_BRDCFG_START	0x4000		/* board config */
 #define QLCNIC_BOOTLD_START	0x10000		/* bootld */
@@ -367,7 +371,7 @@
  */
 struct qlcnic_cmd_buffer {
 	struct sk_buff *skb;
-	struct qlcnic_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1];
+	struct qlcnic_skb_frag frag_array[MAX_SKB_FRAGS + 1];
 	u32 frag_count;
 };
 
@@ -377,7 +381,6 @@
 	struct sk_buff *skb;
 	u64 dma;
 	u16 ref_handle;
-	u16 state;
 };
 
 /* Board types */
@@ -419,7 +422,6 @@
 	u64  xmit_on;
 	u64  xmit_off;
 	u64  skb_alloc_failure;
-	u64  null_skb;
 	u64  null_rxbuf;
 	u64  rx_dma_map_error;
 	u64  tx_dma_map_error;
@@ -542,7 +544,17 @@
 #define QLCNIC_CDRP_CMD_READ_PEXQ_PARAMETERS	0x0000001c
 #define QLCNIC_CDRP_CMD_GET_LIC_CAPABILITIES	0x0000001d
 #define QLCNIC_CDRP_CMD_READ_MAX_LRO_PER_BOARD	0x0000001e
-#define QLCNIC_CDRP_CMD_MAX			0x0000001f
+#define QLCNIC_CDRP_CMD_MAC_ADDRESS		0x0000001f
+
+#define QLCNIC_CDRP_CMD_GET_PCI_INFO		0x00000020
+#define QLCNIC_CDRP_CMD_GET_NIC_INFO		0x00000021
+#define QLCNIC_CDRP_CMD_SET_NIC_INFO		0x00000022
+#define QLCNIC_CDRP_CMD_RESET_NPAR		0x00000023
+#define QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY	0x00000024
+#define QLCNIC_CDRP_CMD_TOGGLE_ESWITCH		0x00000025
+#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS	0x00000026
+#define QLCNIC_CDRP_CMD_SET_PORTMIRRORING	0x00000027
+#define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH	0x00000028
 
 #define QLCNIC_RCODE_SUCCESS		0
 #define QLCNIC_RCODE_TIMEOUT		17
@@ -556,12 +568,12 @@
 #define QLCNIC_CAP0_LSO 		(1 << 6)
 #define QLCNIC_CAP0_JUMBO_CONTIGUOUS	(1 << 7)
 #define QLCNIC_CAP0_LRO_CONTIGUOUS	(1 << 8)
+#define QLCNIC_CAP0_VALIDOFF		(1 << 11)
 
 /*
  * Context state
  */
-#define QLCHAL_VERSION	1
-
+#define QLCNIC_HOST_CTX_STATE_FREED	0
 #define QLCNIC_HOST_CTX_STATE_ACTIVE	2
 
 /*
@@ -592,9 +604,10 @@
 	__le32 sds_ring_offset;	/* Offset to SDS config */
 	__le16 num_rds_rings;	/* Count of RDS rings */
 	__le16 num_sds_rings;	/* Count of SDS rings */
-	__le16 rsvd1;		/* Padding */
-	__le16 rsvd2;		/* Padding */
-	u8  reserved[128]; 	/* reserve space for future expansion*/
+	__le16 valid_field_offset;
+	u8  txrx_sds_binding;
+	u8  msix_handler;
+	u8  reserved[128];      /* reserve space for future expansion*/
 	/* MUST BE 64-bit aligned.
 	   The following is packed:
 	   - N hostrq_rds_rings
@@ -808,9 +821,10 @@
 #define QLCNIC_LRO_REQUEST_CLEANUP	4
 
 /* Capabilites received */
-#define QLCNIC_FW_CAPABILITY_BDG		(1 << 8)
-#define QLCNIC_FW_CAPABILITY_FVLANTX		(1 << 9)
-#define QLCNIC_FW_CAPABILITY_HW_LRO		(1 << 10)
+#define QLCNIC_FW_CAPABILITY_TSO		BIT_1
+#define QLCNIC_FW_CAPABILITY_BDG		BIT_8
+#define QLCNIC_FW_CAPABILITY_FVLANTX		BIT_9
+#define QLCNIC_FW_CAPABILITY_HW_LRO		BIT_10
 
 /* module types */
 #define LINKEVENT_MODULE_NOT_PRESENT			1
@@ -881,12 +895,14 @@
 #define QLCNIC_LRO_ENABLED		0x08
 #define QLCNIC_BRIDGE_ENABLED       	0X10
 #define QLCNIC_DIAG_ENABLED		0x20
+#define QLCNIC_ESWITCH_ENABLED		0x40
 #define QLCNIC_IS_MSI_FAMILY(adapter) \
 	((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
 
 #define MSIX_ENTRIES_PER_ADAPTER	NUM_STS_DESC_RINGS
 #define QLCNIC_MSIX_TBL_SPACE		8192
 #define QLCNIC_PCI_REG_MSIX_TBL 	0x44
+#define QLCNIC_MSIX_TBL_PGSIZE		4096
 
 #define QLCNIC_NETDEV_WEIGHT	128
 #define QLCNIC_ADAPTER_UP_MAGIC 777
@@ -895,6 +911,7 @@
 #define __QLCNIC_DEV_UP 		1
 #define __QLCNIC_RESETTING		2
 #define __QLCNIC_START_FW 		4
+#define __QLCNIC_AER			5
 
 #define QLCNIC_INTERRUPT_TEST		1
 #define QLCNIC_LOOPBACK_TEST		2
@@ -919,11 +936,11 @@
 	u8 rx_csum;
 	u8 portnum;
 	u8 physical_port;
+	u8 reset_context;
 
 	u8 mc_enabled;
 	u8 max_mc_count;
 	u8 rss_supported;
-	u8 rsrvd1;
 	u8 fw_wait_cnt;
 	u8 fw_fail_cnt;
 	u8 tx_timeo_cnt;
@@ -932,7 +949,6 @@
 	u8 has_link_events;
 	u8 fw_type;
 	u16 tx_context_id;
-	u16 mtu;
 	u16 is_up;
 
 	u16 link_speed;
@@ -940,6 +956,13 @@
 	u16 link_autoneg;
 	u16 module_type;
 
+	u16 op_mode;
+	u16 switch_mode;
+	u16 max_tx_ques;
+	u16 max_rx_ques;
+	u16 max_mtu;
+
+	u32 fw_hal_version;
 	u32 capabilities;
 	u32 flags;
 	u32 irq;
@@ -948,18 +971,22 @@
 	u32 int_vec_bit;
 	u32 heartbit;
 
+	u8 max_mac_filters;
 	u8 dev_state;
 	u8 diag_test;
 	u8 diag_cnt;
 	u8 reset_ack_timeo;
 	u8 dev_init_timeo;
-	u8 rsrd1;
 	u16 msg_enable;
 
 	u8 mac_addr[ETH_ALEN];
 
 	u64 dev_rst_time;
 
+	struct qlcnic_npar_info *npars;
+	struct qlcnic_eswitch *eswitch;
+	struct qlcnic_nic_template *nic_ops;
+
 	struct qlcnic_adapter_stats stats;
 
 	struct qlcnic_recv_context recv_ctx;
@@ -974,8 +1001,6 @@
 
 	struct delayed_work fw_work;
 
-	struct work_struct  tx_timeout_task;
-
 	struct qlcnic_nic_intr_coalesce coal;
 
 	unsigned long state;
@@ -984,6 +1009,123 @@
 	const struct firmware *fw;
 };
 
+struct qlcnic_info {
+	__le16	pci_func;
+	__le16	op_mode; /* 1 = Priv, 2 = NP, 3 = NP passthru */
+	__le16	phys_port;
+	__le16	switch_mode; /* 0 = disabled, 1 = int, 2 = ext */
+
+	__le32	capabilities;
+	u8	max_mac_filters;
+	u8	reserved1;
+	__le16	max_mtu;
+
+	__le16	max_tx_ques;
+	__le16	max_rx_ques;
+	__le16	min_tx_bw;
+	__le16	max_tx_bw;
+	u8	reserved2[104];
+};
+
+struct qlcnic_pci_info {
+	__le16	id; /* pci function id */
+	__le16	active; /* 1 = Enabled */
+	__le16	type; /* 1 = NIC, 2 = FCoE, 3 = iSCSI */
+	__le16	default_port; /* default port number */
+
+	__le16	tx_min_bw; /* Multiple of 100mbpc */
+	__le16	tx_max_bw;
+	__le16	reserved1[2];
+
+	u8	mac[ETH_ALEN];
+	u8	reserved2[106];
+};
+
+struct qlcnic_npar_info {
+	u16	vlan_id;
+	u16	min_bw;
+	u16	max_bw;
+	u8	phy_port;
+	u8	type;
+	u8	active;
+	u8	enable_pm;
+	u8	dest_npar;
+	u8	host_vlan_tag;
+	u8	promisc_mode;
+	u8	discard_tagged;
+	u8	mac_learning;
+};
+struct qlcnic_eswitch {
+	u8	port;
+	u8	active_vports;
+	u8	active_vlans;
+	u8	active_ucast_filters;
+	u8	max_ucast_filters;
+	u8	max_active_vlans;
+
+	u32	flags;
+#define QLCNIC_SWITCH_ENABLE		BIT_1
+#define QLCNIC_SWITCH_VLAN_FILTERING	BIT_2
+#define QLCNIC_SWITCH_PROMISC_MODE	BIT_3
+#define QLCNIC_SWITCH_PORT_MIRRORING	BIT_4
+};
+
+
+/* Return codes for Error handling */
+#define QL_STATUS_INVALID_PARAM	-1
+
+#define MAX_BW			100
+#define MIN_BW			1
+#define MAX_VLAN_ID		4095
+#define MIN_VLAN_ID		2
+#define MAX_TX_QUEUES		1
+#define MAX_RX_QUEUES		4
+#define DEFAULT_MAC_LEARN	1
+
+#define IS_VALID_VLAN(vlan)	(vlan >= MIN_VLAN_ID && vlan <= MAX_VLAN_ID)
+#define IS_VALID_BW(bw)		(bw >= MIN_BW && bw <= MAX_BW)
+#define IS_VALID_TX_QUEUES(que)	(que > 0 && que <= MAX_TX_QUEUES)
+#define IS_VALID_RX_QUEUES(que)	(que > 0 && que <= MAX_RX_QUEUES)
+#define IS_VALID_MODE(mode)	(mode == 0 || mode == 1)
+
+struct qlcnic_pci_func_cfg {
+	u16	func_type;
+	u16	min_bw;
+	u16	max_bw;
+	u16	port_num;
+	u8	pci_func;
+	u8	func_state;
+	u8	def_mac_addr[6];
+};
+
+struct qlcnic_npar_func_cfg {
+	u32	fw_capab;
+	u16	port_num;
+	u16	min_bw;
+	u16	max_bw;
+	u16	max_tx_queues;
+	u16	max_rx_queues;
+	u8	pci_func;
+	u8	op_mode;
+};
+
+struct qlcnic_pm_func_cfg {
+	u8	pci_func;
+	u8	action;
+	u8	dest_npar;
+	u8	reserved[5];
+};
+
+struct qlcnic_esw_func_cfg {
+	u16	vlan_id;
+	u8	pci_func;
+	u8	host_vlan_tag;
+	u8	promisc_mode;
+	u8	discard_tagged;
+	u8	mac_learning;
+	u8	reserved;
+};
+
 int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val);
 int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val);
 
@@ -1031,13 +1173,13 @@
 int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate);
 
 /* Functions from qlcnic_init.c */
-int qlcnic_phantom_init(struct qlcnic_adapter *adapter);
 int qlcnic_load_firmware(struct qlcnic_adapter *adapter);
 int qlcnic_need_fw_reset(struct qlcnic_adapter *adapter);
 void qlcnic_request_firmware(struct qlcnic_adapter *adapter);
 void qlcnic_release_firmware(struct qlcnic_adapter *adapter);
 int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter);
 int qlcnic_setup_idc_param(struct qlcnic_adapter *adapter);
+int qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter);
 
 int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp);
 int qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr,
@@ -1050,6 +1192,10 @@
 int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter);
 void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter);
 
+int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter);
+void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter);
+
+void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter);
 void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter);
 void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter);
 
@@ -1070,13 +1216,14 @@
 int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
 int qlcnic_change_mtu(struct net_device *netdev, int new_mtu);
 int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable);
-int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable);
+int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable);
 int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
 void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
 		struct qlcnic_host_tx_ring *tx_ring);
-int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac);
+int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac);
 void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter);
 int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
+void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *);
 
 /* Functions from qlcnic_main.c */
 int qlcnic_reset_context(struct qlcnic_adapter *);
@@ -1088,6 +1235,25 @@
 netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
 void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
 
+/* Management functions */
+int qlcnic_set_mac_address(struct qlcnic_adapter *, u8*);
+int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
+int qlcnic_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
+int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
+int qlcnic_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
+int qlcnic_reset_partition(struct qlcnic_adapter *, u8);
+
+/*  eSwitch management functions */
+int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *, u8,
+				struct qlcnic_eswitch *);
+int qlcnic_get_eswitch_status(struct qlcnic_adapter *, u8,
+				struct qlcnic_eswitch *);
+int qlcnic_toggle_eswitch(struct qlcnic_adapter *, u8, u8);
+int qlcnic_config_switch_port(struct qlcnic_adapter *, u8, int, u8, u8,
+			u8, u8, u16);
+int qlcnic_config_port_mirroring(struct qlcnic_adapter *, u8, u8, u8);
+extern int qlcnic_config_tso;
+
 /*
  * QLOGIC Board information
  */
@@ -1131,6 +1297,13 @@
 
 extern const struct ethtool_ops qlcnic_ethtool_ops;
 
+struct qlcnic_nic_template {
+	int (*get_mac_addr) (struct qlcnic_adapter *, u8*);
+	int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
+	int (*config_led) (struct qlcnic_adapter *, u32, u32);
+	int (*start_firmware) (struct qlcnic_adapter *);
+};
+
 #define QLCDB(adapter, lvl, _fmt, _args...) do {	\
 	if (NETIF_MSG_##lvl & adapter->msg_enable)	\
 		printk(KERN_INFO "%s: %s: " _fmt,	\
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index c2c1f5c..cc5d861 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -88,12 +88,12 @@
 
 	if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) {
 		if (qlcnic_issue_cmd(adapter,
-				adapter->ahw.pci_func,
-				QLCHAL_VERSION,
-				recv_ctx->context_id,
-				mtu,
-				0,
-				QLCNIC_CDRP_CMD_SET_MTU)) {
+			adapter->ahw.pci_func,
+			adapter->fw_hal_version,
+			recv_ctx->context_id,
+			mtu,
+			0,
+			QLCNIC_CDRP_CMD_SET_MTU)) {
 
 			dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
 			return -EIO;
@@ -121,7 +121,7 @@
 
 	int i, nrds_rings, nsds_rings;
 	size_t rq_size, rsp_size;
-	u32 cap, reg, val;
+	u32 cap, reg, val, reg2;
 	int err;
 
 	struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
@@ -152,9 +152,14 @@
 
 	prq->host_rsp_dma_addr = cpu_to_le64(cardrsp_phys_addr);
 
-	cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN);
+	cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN
+						| QLCNIC_CAP0_VALIDOFF);
 	cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);
 
+	prq->valid_field_offset = offsetof(struct qlcnic_hostrq_rx_ctx,
+							 msix_handler);
+	prq->txrx_sds_binding = nsds_rings - 1;
+
 	prq->capabilities[0] = cpu_to_le32(cap);
 	prq->host_int_crb_mode =
 		cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
@@ -175,6 +180,7 @@
 	for (i = 0; i < nrds_rings; i++) {
 
 		rds_ring = &recv_ctx->rds_rings[i];
+		rds_ring->producer = 0;
 
 		prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr);
 		prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc);
@@ -188,6 +194,8 @@
 	for (i = 0; i < nsds_rings; i++) {
 
 		sds_ring = &recv_ctx->sds_rings[i];
+		sds_ring->consumer = 0;
+		memset(sds_ring->desc_head, 0, STATUS_DESC_RINGSIZE(sds_ring));
 
 		prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr);
 		prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc);
@@ -197,7 +205,7 @@
 	phys_addr = hostrq_phys_addr;
 	err = qlcnic_issue_cmd(adapter,
 			adapter->ahw.pci_func,
-			QLCHAL_VERSION,
+			adapter->fw_hal_version,
 			(u32)(phys_addr >> 32),
 			(u32)(phys_addr & 0xffffffff),
 			rq_size,
@@ -216,8 +224,7 @@
 		rds_ring = &recv_ctx->rds_rings[i];
 
 		reg = le32_to_cpu(prsp_rds[i].host_producer_crb);
-		rds_ring->crb_rcv_producer = qlcnic_get_ioaddr(adapter,
-				QLCNIC_REG(reg - 0x200));
+		rds_ring->crb_rcv_producer = adapter->ahw.pci_base0 + reg;
 	}
 
 	prsp_sds = ((struct qlcnic_cardrsp_sds_ring *)
@@ -227,12 +234,10 @@
 		sds_ring = &recv_ctx->sds_rings[i];
 
 		reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
-		sds_ring->crb_sts_consumer = qlcnic_get_ioaddr(adapter,
-				QLCNIC_REG(reg - 0x200));
+		reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb);
 
-		reg = le32_to_cpu(prsp_sds[i].interrupt_crb);
-		sds_ring->crb_intr_mask = qlcnic_get_ioaddr(adapter,
-				QLCNIC_REG(reg - 0x200));
+		sds_ring->crb_sts_consumer = adapter->ahw.pci_base0 + reg;
+		sds_ring->crb_intr_mask = adapter->ahw.pci_base0 + reg2;
 	}
 
 	recv_ctx->state = le32_to_cpu(prsp->host_ctx_state);
@@ -253,7 +258,7 @@
 
 	if (qlcnic_issue_cmd(adapter,
 			adapter->ahw.pci_func,
-			QLCHAL_VERSION,
+			adapter->fw_hal_version,
 			recv_ctx->context_id,
 			QLCNIC_DESTROY_CTX_RESET,
 			0,
@@ -262,6 +267,8 @@
 		dev_err(&adapter->pdev->dev,
 			"Failed to destroy rx ctx in firmware\n");
 	}
+
+	recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED;
 }
 
 static int
@@ -278,6 +285,11 @@
 	dma_addr_t	rq_phys_addr, rsp_phys_addr;
 	struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
 
+	/* reset host resources */
+	tx_ring->producer = 0;
+	tx_ring->sw_consumer = 0;
+	*(tx_ring->hw_consumer) = 0;
+
 	rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx);
 	rq_addr = pci_alloc_consistent(adapter->pdev,
 		rq_size, &rq_phys_addr);
@@ -319,7 +331,7 @@
 	phys_addr = rq_phys_addr;
 	err = qlcnic_issue_cmd(adapter,
 			adapter->ahw.pci_func,
-			QLCHAL_VERSION,
+			adapter->fw_hal_version,
 			(u32)(phys_addr >> 32),
 			((u32)phys_addr & 0xffffffff),
 			rq_size,
@@ -327,8 +339,7 @@
 
 	if (err == QLCNIC_RCODE_SUCCESS) {
 		temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
-		tx_ring->crb_cmd_producer = qlcnic_get_ioaddr(adapter,
-				QLCNIC_REG(temp - 0x200));
+		tx_ring->crb_cmd_producer = adapter->ahw.pci_base0 + temp;
 
 		adapter->tx_context_id =
 			le16_to_cpu(prsp->context_id);
@@ -351,7 +362,7 @@
 {
 	if (qlcnic_issue_cmd(adapter,
 			adapter->ahw.pci_func,
-			QLCHAL_VERSION,
+			adapter->fw_hal_version,
 			adapter->tx_context_id,
 			QLCNIC_DESTROY_CTX_RESET,
 			0,
@@ -368,7 +379,7 @@
 
 	if (qlcnic_issue_cmd(adapter,
 			adapter->ahw.pci_func,
-			QLCHAL_VERSION,
+			adapter->fw_hal_version,
 			reg,
 			0,
 			0,
@@ -385,7 +396,7 @@
 {
 	return qlcnic_issue_cmd(adapter,
 			adapter->ahw.pci_func,
-			QLCHAL_VERSION,
+			adapter->fw_hal_version,
 			reg,
 			val,
 			0,
@@ -457,15 +468,6 @@
 		sds_ring->desc_head = (struct status_desc *)addr;
 	}
 
-
-	err = qlcnic_fw_cmd_create_rx_ctx(adapter);
-	if (err)
-		goto err_out_free;
-	err = qlcnic_fw_cmd_create_tx_ctx(adapter);
-	if (err)
-		goto err_out_free;
-
-	set_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
 	return 0;
 
 err_out_free:
@@ -473,6 +475,36 @@
 	return err;
 }
 
+
+int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter)
+{
+	int err;
+
+	err = qlcnic_fw_cmd_create_rx_ctx(adapter);
+	if (err)
+		return err;
+
+	err = qlcnic_fw_cmd_create_tx_ctx(adapter);
+	if (err) {
+		qlcnic_fw_cmd_destroy_rx_ctx(adapter);
+		return err;
+	}
+
+	set_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
+	return 0;
+}
+
+void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
+{
+	if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) {
+		qlcnic_fw_cmd_destroy_rx_ctx(adapter);
+		qlcnic_fw_cmd_destroy_tx_ctx(adapter);
+
+		/* Allow dma queues to drain after context reset */
+		msleep(20);
+	}
+}
+
 void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
 {
 	struct qlcnic_recv_context *recv_ctx;
@@ -481,15 +513,6 @@
 	struct qlcnic_host_tx_ring *tx_ring;
 	int ring;
 
-
-	if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) {
-		qlcnic_fw_cmd_destroy_rx_ctx(adapter);
-		qlcnic_fw_cmd_destroy_tx_ctx(adapter);
-
-		/* Allow dma queues to drain after context reset */
-		msleep(20);
-	}
-
 	recv_ctx = &adapter->recv_ctx;
 
 	tx_ring = adapter->tx_ring;
@@ -533,3 +556,430 @@
 	}
 }
 
+/* Set MAC address of a NIC partition */
+int qlcnic_set_mac_address(struct qlcnic_adapter *adapter, u8* mac)
+{
+	int err = 0;
+	u32 arg1, arg2, arg3;
+
+	arg1 = adapter->ahw.pci_func | BIT_9;
+	arg2 = mac[0] | (mac[1] << 8) | (mac[2] << 16) | (mac[3] << 24);
+	arg3 = mac[4] | (mac[5] << 16);
+
+	err = qlcnic_issue_cmd(adapter,
+			adapter->ahw.pci_func,
+			adapter->fw_hal_version,
+			arg1,
+			arg2,
+			arg3,
+			QLCNIC_CDRP_CMD_MAC_ADDRESS);
+
+	if (err != QLCNIC_RCODE_SUCCESS) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to set mac address%d\n", err);
+		err = -EIO;
+	}
+
+	return err;
+}
+
+/* Get MAC address of a NIC partition */
+int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
+{
+	int err;
+	u32 arg1;
+
+	arg1 = adapter->ahw.pci_func | BIT_8;
+	err = qlcnic_issue_cmd(adapter,
+			adapter->ahw.pci_func,
+			adapter->fw_hal_version,
+			arg1,
+			0,
+			0,
+			QLCNIC_CDRP_CMD_MAC_ADDRESS);
+
+	if (err == QLCNIC_RCODE_SUCCESS)
+		qlcnic_fetch_mac(adapter, QLCNIC_ARG1_CRB_OFFSET,
+				QLCNIC_ARG2_CRB_OFFSET, 0, mac);
+	else {
+		dev_err(&adapter->pdev->dev,
+			"Failed to get mac address%d\n", err);
+		err = -EIO;
+	}
+
+	return err;
+}
+
+/* Get info of a NIC partition */
+int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
+				struct qlcnic_info *npar_info, u8 func_id)
+{
+	int	err;
+	dma_addr_t nic_dma_t;
+	struct qlcnic_info *nic_info;
+	void *nic_info_addr;
+	size_t	nic_size = sizeof(struct qlcnic_info);
+
+	nic_info_addr = pci_alloc_consistent(adapter->pdev,
+		nic_size, &nic_dma_t);
+	if (!nic_info_addr)
+		return -ENOMEM;
+	memset(nic_info_addr, 0, nic_size);
+
+	nic_info = (struct qlcnic_info *) nic_info_addr;
+	err = qlcnic_issue_cmd(adapter,
+			adapter->ahw.pci_func,
+			adapter->fw_hal_version,
+			MSD(nic_dma_t),
+			LSD(nic_dma_t),
+			(func_id << 16 | nic_size),
+			QLCNIC_CDRP_CMD_GET_NIC_INFO);
+
+	if (err == QLCNIC_RCODE_SUCCESS) {
+		npar_info->pci_func = le16_to_cpu(nic_info->pci_func);
+		npar_info->op_mode = le16_to_cpu(nic_info->op_mode);
+		npar_info->phys_port = le16_to_cpu(nic_info->phys_port);
+		npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode);
+		npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
+		npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
+		npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
+		npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
+		npar_info->capabilities = le32_to_cpu(nic_info->capabilities);
+		npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu);
+
+		dev_info(&adapter->pdev->dev,
+			"phy port: %d switch_mode: %d,\n"
+			"\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n"
+			"\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n",
+			npar_info->phys_port, npar_info->switch_mode,
+			npar_info->max_tx_ques, npar_info->max_rx_ques,
+			npar_info->min_tx_bw, npar_info->max_tx_bw,
+			npar_info->max_mtu, npar_info->capabilities);
+	} else {
+		dev_err(&adapter->pdev->dev,
+			"Failed to get nic info%d\n", err);
+		err = -EIO;
+	}
+
+	pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t);
+	return err;
+}
+
+/* Configure a NIC partition */
+int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
+{
+	int err = -EIO;
+	dma_addr_t nic_dma_t;
+	void *nic_info_addr;
+	struct qlcnic_info *nic_info;
+	size_t nic_size = sizeof(struct qlcnic_info);
+
+	if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+		return err;
+
+	nic_info_addr = pci_alloc_consistent(adapter->pdev, nic_size,
+			&nic_dma_t);
+	if (!nic_info_addr)
+		return -ENOMEM;
+
+	memset(nic_info_addr, 0, nic_size);
+	nic_info = (struct qlcnic_info *)nic_info_addr;
+
+	nic_info->pci_func = cpu_to_le16(nic->pci_func);
+	nic_info->op_mode = cpu_to_le16(nic->op_mode);
+	nic_info->phys_port = cpu_to_le16(nic->phys_port);
+	nic_info->switch_mode = cpu_to_le16(nic->switch_mode);
+	nic_info->capabilities = cpu_to_le32(nic->capabilities);
+	nic_info->max_mac_filters = nic->max_mac_filters;
+	nic_info->max_tx_ques = cpu_to_le16(nic->max_tx_ques);
+	nic_info->max_rx_ques = cpu_to_le16(nic->max_rx_ques);
+	nic_info->min_tx_bw = cpu_to_le16(nic->min_tx_bw);
+	nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw);
+
+	err = qlcnic_issue_cmd(adapter,
+			adapter->ahw.pci_func,
+			adapter->fw_hal_version,
+			MSD(nic_dma_t),
+			LSD(nic_dma_t),
+			((nic->pci_func << 16) | nic_size),
+			QLCNIC_CDRP_CMD_SET_NIC_INFO);
+
+	if (err != QLCNIC_RCODE_SUCCESS) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to set nic info%d\n", err);
+		err = -EIO;
+	}
+
+	pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t);
+	return err;
+}
+
+/* Get PCI Info of a partition */
+int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
+				struct qlcnic_pci_info *pci_info)
+{
+	int err = 0, i;
+	dma_addr_t pci_info_dma_t;
+	struct qlcnic_pci_info *npar;
+	void *pci_info_addr;
+	size_t npar_size = sizeof(struct qlcnic_pci_info);
+	size_t pci_size = npar_size * QLCNIC_MAX_PCI_FUNC;
+
+	pci_info_addr = pci_alloc_consistent(adapter->pdev, pci_size,
+			&pci_info_dma_t);
+	if (!pci_info_addr)
+		return -ENOMEM;
+	memset(pci_info_addr, 0, pci_size);
+
+	npar = (struct qlcnic_pci_info *) pci_info_addr;
+	err = qlcnic_issue_cmd(adapter,
+			adapter->ahw.pci_func,
+			adapter->fw_hal_version,
+			MSD(pci_info_dma_t),
+			LSD(pci_info_dma_t),
+			pci_size,
+			QLCNIC_CDRP_CMD_GET_PCI_INFO);
+
+	if (err == QLCNIC_RCODE_SUCCESS) {
+		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++, pci_info++) {
+			pci_info->id = le32_to_cpu(npar->id);
+			pci_info->active = le32_to_cpu(npar->active);
+			pci_info->type = le32_to_cpu(npar->type);
+			pci_info->default_port =
+				le32_to_cpu(npar->default_port);
+			pci_info->tx_min_bw =
+				le32_to_cpu(npar->tx_min_bw);
+			pci_info->tx_max_bw =
+				le32_to_cpu(npar->tx_max_bw);
+			memcpy(pci_info->mac, npar->mac, ETH_ALEN);
+		}
+	} else {
+		dev_err(&adapter->pdev->dev,
+			"Failed to get PCI Info%d\n", err);
+		err = -EIO;
+	}
+
+	pci_free_consistent(adapter->pdev, pci_size, pci_info_addr,
+		pci_info_dma_t);
+	return err;
+}
+
+/* Reset a NIC partition */
+
+int qlcnic_reset_partition(struct qlcnic_adapter *adapter, u8 func_no)
+{
+	int err = -EIO;
+
+	if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+		return err;
+
+	err = qlcnic_issue_cmd(adapter,
+			adapter->ahw.pci_func,
+			adapter->fw_hal_version,
+			func_no,
+			0,
+			0,
+			QLCNIC_CDRP_CMD_RESET_NPAR);
+
+	if (err != QLCNIC_RCODE_SUCCESS) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to issue reset partition%d\n", err);
+		err = -EIO;
+	}
+
+	return err;
+}
+
+/* Get eSwitch Capabilities */
+int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *adapter, u8 port,
+					struct qlcnic_eswitch *eswitch)
+{
+	int err = -EIO;
+	u32 arg1, arg2;
+
+	if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
+		return err;
+
+	err = qlcnic_issue_cmd(adapter,
+			adapter->ahw.pci_func,
+			adapter->fw_hal_version,
+			port,
+			0,
+			0,
+			QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY);
+
+	if (err == QLCNIC_RCODE_SUCCESS) {
+		arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+		arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
+
+		eswitch->port = arg1 & 0xf;
+		eswitch->active_vports = LSB(arg2);
+		eswitch->max_ucast_filters = MSB(arg2);
+		eswitch->max_active_vlans = LSB(MSW(arg2));
+		if (arg1 & BIT_6)
+			eswitch->flags |= QLCNIC_SWITCH_VLAN_FILTERING;
+		if (arg1 & BIT_7)
+			eswitch->flags |= QLCNIC_SWITCH_PROMISC_MODE;
+		if (arg1 & BIT_8)
+			eswitch->flags |= QLCNIC_SWITCH_PORT_MIRRORING;
+	} else {
+		dev_err(&adapter->pdev->dev,
+			"Failed to get eswitch capabilities%d\n", err);
+	}
+
+	return err;
+}
+
+/* Get current status of eswitch */
+int qlcnic_get_eswitch_status(struct qlcnic_adapter *adapter, u8 port,
+				struct qlcnic_eswitch *eswitch)
+{
+	int err = -EIO;
+	u32 arg1, arg2;
+
+	if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+		return err;
+
+	err = qlcnic_issue_cmd(adapter,
+			adapter->ahw.pci_func,
+			adapter->fw_hal_version,
+			port,
+			0,
+			0,
+			QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS);
+
+	if (err == QLCNIC_RCODE_SUCCESS) {
+		arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+		arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
+
+		eswitch->port = arg1 & 0xf;
+		eswitch->active_vports = LSB(arg2);
+		eswitch->active_ucast_filters = MSB(arg2);
+		eswitch->active_vlans = LSB(MSW(arg2));
+		if (arg1 & BIT_6)
+			eswitch->flags |= QLCNIC_SWITCH_VLAN_FILTERING;
+		if (arg1 & BIT_8)
+			eswitch->flags |= QLCNIC_SWITCH_PORT_MIRRORING;
+
+	} else {
+		dev_err(&adapter->pdev->dev,
+			"Failed to get eswitch status%d\n", err);
+	}
+
+	return err;
+}
+
+/* Enable/Disable eSwitch */
+int qlcnic_toggle_eswitch(struct qlcnic_adapter *adapter, u8 id, u8 enable)
+{
+	int err = -EIO;
+	u32 arg1, arg2;
+	struct qlcnic_eswitch *eswitch;
+
+	if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+		return err;
+
+	eswitch = &adapter->eswitch[id];
+	if (!eswitch)
+		return err;
+
+	arg1 = eswitch->port | (enable ? BIT_4 : 0);
+	arg2 = eswitch->active_vports | (eswitch->max_ucast_filters << 8) |
+		(eswitch->max_active_vlans << 16);
+	err = qlcnic_issue_cmd(adapter,
+			adapter->ahw.pci_func,
+			adapter->fw_hal_version,
+			arg1,
+			arg2,
+			0,
+			QLCNIC_CDRP_CMD_TOGGLE_ESWITCH);
+
+	if (err != QLCNIC_RCODE_SUCCESS) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to enable eswitch%d\n", eswitch->port);
+		eswitch->flags &= ~QLCNIC_SWITCH_ENABLE;
+		err = -EIO;
+	} else {
+		eswitch->flags |= QLCNIC_SWITCH_ENABLE;
+		dev_info(&adapter->pdev->dev,
+			"Enabled eSwitch for port %d\n", eswitch->port);
+	}
+
+	return err;
+}
+
+/* Configure eSwitch for port mirroring */
+int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
+				u8 enable_mirroring, u8 pci_func)
+{
+	int err = -EIO;
+	u32 arg1;
+
+	if (adapter->op_mode != QLCNIC_MGMT_FUNC ||
+		!(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE))
+		return err;
+
+	arg1 = id | (enable_mirroring ? BIT_4 : 0);
+	arg1 |= pci_func << 8;
+
+	err = qlcnic_issue_cmd(adapter,
+			adapter->ahw.pci_func,
+			adapter->fw_hal_version,
+			arg1,
+			0,
+			0,
+			QLCNIC_CDRP_CMD_SET_PORTMIRRORING);
+
+	if (err != QLCNIC_RCODE_SUCCESS) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to configure port mirroring%d on eswitch:%d\n",
+			pci_func, id);
+	} else {
+		dev_info(&adapter->pdev->dev,
+			"Configured eSwitch %d for port mirroring:%d\n",
+			id, pci_func);
+	}
+
+	return err;
+}
+
+/* Configure eSwitch port */
+int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, u8 id,
+		int vlan_tagging, u8 discard_tagged, u8 promsc_mode,
+		u8 mac_learn, u8 pci_func, u16 vlan_id)
+{
+	int err = -EIO;
+	u32 arg1;
+	struct qlcnic_eswitch *eswitch;
+
+	if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+		return err;
+
+	eswitch = &adapter->eswitch[id];
+	if (!(eswitch->flags & QLCNIC_SWITCH_ENABLE))
+		return err;
+
+	arg1 = eswitch->port | (discard_tagged ? BIT_4 : 0);
+	arg1 |= (promsc_mode ? BIT_6 : 0) | (mac_learn ? BIT_7 : 0);
+	arg1 |= pci_func << 8;
+	if (vlan_tagging)
+		arg1 |= BIT_5 | (vlan_id << 16);
+
+	err = qlcnic_issue_cmd(adapter,
+			adapter->ahw.pci_func,
+			adapter->fw_hal_version,
+			arg1,
+			0,
+			0,
+			QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH);
+
+	if (err != QLCNIC_RCODE_SUCCESS) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to configure eswitch port%d\n", eswitch->port);
+	} else {
+		dev_info(&adapter->pdev->dev,
+			"Configured eSwitch for port %d\n", eswitch->port);
+	}
+
+	return err;
+}
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 3bd514e..9328d59 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -69,8 +69,6 @@
 		QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
 	{"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
 		QLC_OFF(stats.skb_alloc_failure)},
-	{"null skb",
-		QLC_SIZEOF(stats.null_skb), QLC_OFF(stats.null_skb)},
 	{"null rxbuf",
 		QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
 	{"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
@@ -350,7 +348,7 @@
 	for (i = 0; diag_registers[i] != -1; i++)
 		regs_buff[i] = QLCRD32(adapter, diag_registers[i]);
 
-	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
 		return;
 
 	regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
@@ -580,8 +578,12 @@
 		}
 		QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
 	} else if (adapter->ahw.port_type == QLCNIC_XGBE) {
+		if (!pause->rx_pause || pause->autoneg)
+			return -EOPNOTSUPP;
+
 		if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
 			return -EIO;
+
 		val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
 		if (port == 0) {
 			if (pause->tx_pause)
@@ -676,6 +678,12 @@
 	int max_sds_rings = adapter->max_sds_rings;
 	int ret;
 
+	if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+		dev_warn(&adapter->pdev->dev, "Loopback test not supported"
+				"for non privilege function\n");
+		return 0;
+	}
+
 	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
 		return -EIO;
 
@@ -715,7 +723,8 @@
 
 	adapter->diag_cnt = 0;
 	ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func,
-			QLCHAL_VERSION, adapter->portnum, 0, 0, 0x00000011);
+			adapter->fw_hal_version, adapter->portnum,
+			0, 0, 0x00000011);
 	if (ret)
 		goto done;
 
@@ -821,6 +830,9 @@
 
 static int qlcnic_set_tso(struct net_device *dev, u32 data)
 {
+	struct qlcnic_adapter *adapter = netdev_priv(dev);
+	if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO))
+		return -EOPNOTSUPP;
 	if (data)
 		dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
 	else
@@ -834,7 +846,10 @@
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	int ret;
 
-	ret = qlcnic_config_led(adapter, 1, 0xf);
+	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
+		return -EIO;
+
+	ret = adapter->nic_ops->config_led(adapter, 1, 0xf);
 	if (ret) {
 		dev_err(&adapter->pdev->dev,
 			"Failed to set LED blink state.\n");
@@ -843,7 +858,7 @@
 
 	msleep_interruptible(val * 1000);
 
-	ret = qlcnic_config_led(adapter, 0, 0xf);
+	ret = adapter->nic_ops->config_led(adapter, 0, 0xf);
 	if (ret) {
 		dev_err(&adapter->pdev->dev,
 			"Failed to reset LED blink state.\n");
@@ -905,7 +920,7 @@
 {
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 
-	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
 		return -EINVAL;
 
 	/*
@@ -981,12 +996,19 @@
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 	int hw_lro;
 
+	if (data & ~ETH_FLAG_LRO)
+		return -EINVAL;
+
 	if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO))
 		return -EINVAL;
 
-	ethtool_op_set_flags(netdev, data);
-
-	hw_lro = (data & ETH_FLAG_LRO) ? QLCNIC_LRO_ENABLED : 0;
+	if (data & ETH_FLAG_LRO) {
+		hw_lro = QLCNIC_LRO_ENABLED;
+		netdev->features |= NETIF_F_LRO;
+	} else {
+		hw_lro = 0;
+		netdev->features &= ~NETIF_F_LRO;
+	}
 
 	if (qlcnic_config_hw_lro(adapter, hw_lro))
 		return -EIO;
diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h
index ad9d167..15fc320 100644
--- a/drivers/net/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/qlcnic/qlcnic_hdr.h
@@ -208,6 +208,39 @@
 	QLCNIC_HW_PX_MAP_CRB_PGR0
 };
 
+#define	BIT_0	0x1
+#define	BIT_1	0x2
+#define	BIT_2	0x4
+#define	BIT_3	0x8
+#define	BIT_4	0x10
+#define	BIT_5	0x20
+#define	BIT_6	0x40
+#define	BIT_7	0x80
+#define	BIT_8	0x100
+#define	BIT_9	0x200
+#define	BIT_10	0x400
+#define	BIT_11	0x800
+#define	BIT_12	0x1000
+#define	BIT_13	0x2000
+#define	BIT_14	0x4000
+#define	BIT_15	0x8000
+#define	BIT_16	0x10000
+#define	BIT_17	0x20000
+#define	BIT_18	0x40000
+#define	BIT_19	0x80000
+#define	BIT_20	0x100000
+#define	BIT_21	0x200000
+#define	BIT_22	0x400000
+#define	BIT_23	0x800000
+#define	BIT_24	0x1000000
+#define	BIT_25	0x2000000
+#define	BIT_26	0x4000000
+#define	BIT_27	0x8000000
+#define	BIT_28	0x10000000
+#define	BIT_29	0x20000000
+#define	BIT_30	0x40000000
+#define	BIT_31	0x80000000
+
 /*  This field defines CRB adr [31:20] of the agents */
 
 #define QLCNIC_HW_CRB_HUB_AGT_ADR_MN	\
@@ -668,10 +701,11 @@
 #define QLCNIC_CRB_DEV_REF_COUNT	(QLCNIC_CAM_RAM(0x138))
 #define QLCNIC_CRB_DEV_STATE		(QLCNIC_CAM_RAM(0x140))
 
-#define QLCNIC_CRB_DRV_STATE               (QLCNIC_CAM_RAM(0x144))
-#define QLCNIC_CRB_DRV_SCRATCH             (QLCNIC_CAM_RAM(0x148))
-#define QLCNIC_CRB_DEV_PARTITION_INFO      (QLCNIC_CAM_RAM(0x14c))
+#define QLCNIC_CRB_DRV_STATE		(QLCNIC_CAM_RAM(0x144))
+#define QLCNIC_CRB_DRV_SCRATCH		(QLCNIC_CAM_RAM(0x148))
+#define QLCNIC_CRB_DEV_PARTITION_INFO	(QLCNIC_CAM_RAM(0x14c))
 #define QLCNIC_CRB_DRV_IDC_VER		(QLCNIC_CAM_RAM(0x174))
+#define QLCNIC_CRB_DEV_NPAR_STATE	(QLCNIC_CAM_RAM(0x19c))
 #define QLCNIC_ROM_DEV_INIT_TIMEOUT	(0x3e885c)
 #define QLCNIC_ROM_DRV_RESET_TIMEOUT	(0x3e8860)
 
@@ -684,15 +718,26 @@
 #define QLCNIC_DEV_FAILED		0x6
 #define QLCNIC_DEV_QUISCENT		0x7
 
+#define QLCNIC_DEV_NPAR_NOT_RDY	0
+#define QLCNIC_DEV_NPAR_RDY		1
+
+#define QLC_DEV_CHECK_ACTIVE(VAL, FN)		((VAL) &= (1 << (FN * 4)))
 #define QLC_DEV_SET_REF_CNT(VAL, FN)		((VAL) |= (1 << (FN * 4)))
 #define QLC_DEV_CLR_REF_CNT(VAL, FN)		((VAL) &= ~(1 << (FN * 4)))
 #define QLC_DEV_SET_RST_RDY(VAL, FN)		((VAL) |= (1 << (FN * 4)))
 #define QLC_DEV_SET_QSCNT_RDY(VAL, FN)		((VAL) |= (2 << (FN * 4)))
 #define QLC_DEV_CLR_RST_QSCNT(VAL, FN)		((VAL) &= ~(3 << (FN * 4)))
 
+#define QLC_DEV_GET_DRV(VAL, FN)		(0xf & ((VAL) >> (FN * 4)))
+#define QLC_DEV_SET_DRV(VAL, FN)		((VAL) << (FN * 4))
+
+#define QLCNIC_TYPE_NIC		1
+#define QLCNIC_TYPE_FCOE		2
+#define QLCNIC_TYPE_ISCSI		3
+
 #define QLCNIC_RCODE_DRIVER_INFO		0x20000000
-#define QLCNIC_RCODE_DRIVER_CAN_RELOAD		0x40000000
-#define QLCNIC_RCODE_FATAL_ERROR		0x80000000
+#define QLCNIC_RCODE_DRIVER_CAN_RELOAD		BIT_30
+#define QLCNIC_RCODE_FATAL_ERROR		BIT_31
 #define QLCNIC_FWERROR_PEGNUM(code)		((code) & 0xff)
 #define QLCNIC_FWERROR_CODE(code)		((code >> 8) & 0xfffff)
 
@@ -721,6 +766,29 @@
 	u32	pci_int_reg;
 };
 
+#define QLCNIC_FW_API		0x1b216c
+#define QLCNIC_DRV_OP_MODE	0x1b2170
+#define QLCNIC_MSIX_BASE	0x132110
+#define QLCNIC_MAX_PCI_FUNC	8
+
+/* PCI function operational mode */
+enum {
+	QLCNIC_MGMT_FUNC	= 0,
+	QLCNIC_PRIV_FUNC	= 1,
+	QLCNIC_NON_PRIV_FUNC	= 2
+};
+
+#define QLC_DEV_DRV_DEFAULT 0x11111111
+
+#define LSB(x)	((uint8_t)(x))
+#define MSB(x)	((uint8_t)((uint16_t)(x) >> 8))
+
+#define LSW(x)  ((uint16_t)((uint32_t)(x)))
+#define MSW(x)  ((uint16_t)((uint32_t)(x) >> 16))
+
+#define LSD(x)  ((uint32_t)((uint64_t)(x)))
+#define MSD(x)  ((uint32_t)((((uint64_t)(x)) >> 16) >> 16))
+
 #define	QLCNIC_LEGACY_INTR_CONFIG					\
 {									\
 	{								\
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
index 0c2e1f0..e08c8b0 100644
--- a/drivers/net/qlcnic/qlcnic_hw.c
+++ b/drivers/net/qlcnic/qlcnic_hw.c
@@ -327,7 +327,7 @@
 
 	i = 0;
 
-	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
 		return -EIO;
 
 	tx_ring = adapter->tx_ring;
@@ -338,9 +338,15 @@
 
 	if (nr_desc >= qlcnic_tx_avail(tx_ring)) {
 		netif_tx_stop_queue(tx_ring->txq);
-		__netif_tx_unlock_bh(tx_ring->txq);
-		adapter->stats.xmit_off++;
-		return -EBUSY;
+		smp_mb();
+		if (qlcnic_tx_avail(tx_ring) > nr_desc) {
+			if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
+				netif_tx_wake_queue(tx_ring->txq);
+		} else {
+			adapter->stats.xmit_off++;
+			__netif_tx_unlock_bh(tx_ring->txq);
+			return -EBUSY;
+		}
 	}
 
 	do {
@@ -407,10 +413,15 @@
 		return -ENOMEM;
 	}
 	memcpy(cur->mac_addr, addr, ETH_ALEN);
-	list_add_tail(&cur->list, &adapter->mac_list);
 
-	return qlcnic_sre_macaddr_change(adapter,
-				cur->mac_addr, QLCNIC_MAC_ADD);
+	if (qlcnic_sre_macaddr_change(adapter,
+				cur->mac_addr, QLCNIC_MAC_ADD)) {
+		kfree(cur);
+		return -EIO;
+	}
+
+	list_add_tail(&cur->list, &adapter->mac_list);
+	return 0;
 }
 
 void qlcnic_set_multi(struct net_device *netdev)
@@ -420,7 +431,7 @@
 	u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 	u32 mode = VPORT_MISS_MODE_DROP;
 
-	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
 		return;
 
 	qlcnic_nic_add_mac(adapter, adapter->mac_addr);
@@ -538,7 +549,7 @@
 	return rv;
 }
 
-int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable)
+int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
 {
 	struct qlcnic_nic_req req;
 	u64 word;
@@ -704,21 +715,15 @@
 	return rc;
 }
 
-int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac)
+int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac)
 {
-	u32 crbaddr, mac_hi, mac_lo;
+	u32 crbaddr;
 	int pci_func = adapter->ahw.pci_func;
 
 	crbaddr = CRB_MAC_BLOCK_START +
 		(4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1));
 
-	mac_lo = QLCRD32(adapter, crbaddr);
-	mac_hi = QLCRD32(adapter, crbaddr+4);
-
-	if (pci_func & 1)
-		*mac = le64_to_cpu((mac_lo >> 16) | ((u64)mac_hi << 16));
-	else
-		*mac = le64_to_cpu((u64)mac_lo | ((u64)mac_hi << 32));
+	qlcnic_fetch_mac(adapter, crbaddr, crbaddr+4, pci_func & 1, mac);
 
 	return 0;
 }
@@ -766,7 +771,7 @@
  * Out: 'off' is 2M pci map addr
  * side effect: lock crb window
  */
-static void
+static int
 qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off)
 {
 	u32 window;
@@ -775,6 +780,10 @@
 	off -= QLCNIC_PCI_CRBSPACE;
 
 	window = CRB_HI(off);
+	if (window == 0) {
+		dev_err(&adapter->pdev->dev, "Invalid offset 0x%lx\n", off);
+		return -EIO;
+	}
 
 	writel(window, addr);
 	if (readl(addr) != window) {
@@ -782,7 +791,9 @@
 			dev_warn(&adapter->pdev->dev,
 				"failed to set CRB window to %d off 0x%lx\n",
 				window, off);
+		return -EIO;
 	}
+	return 0;
 }
 
 int
@@ -803,11 +814,12 @@
 		/* indirect access */
 		write_lock_irqsave(&adapter->ahw.crb_lock, flags);
 		crb_win_lock(adapter);
-		qlcnic_pci_set_crbwindow_2M(adapter, off);
-		writel(data, addr);
+		rv = qlcnic_pci_set_crbwindow_2M(adapter, off);
+		if (!rv)
+			writel(data, addr);
 		crb_win_unlock(adapter);
 		write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
-		return 0;
+		return rv;
 	}
 
 	dev_err(&adapter->pdev->dev,
@@ -821,7 +833,7 @@
 {
 	unsigned long flags;
 	int rv;
-	u32 data;
+	u32 data = -1;
 	void __iomem *addr = NULL;
 
 	rv = qlcnic_pci_get_crb_addr_2M(adapter, off, &addr);
@@ -833,8 +845,8 @@
 		/* indirect access */
 		write_lock_irqsave(&adapter->ahw.crb_lock, flags);
 		crb_win_lock(adapter);
-		qlcnic_pci_set_crbwindow_2M(adapter, off);
-		data = readl(addr);
+		if (!qlcnic_pci_set_crbwindow_2M(adapter, off))
+			data = readl(addr);
 		crb_win_unlock(adapter);
 		write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
 		return data;
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
index 71a4e66..75ba744 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -112,18 +112,45 @@
 		rds_ring = &recv_ctx->rds_rings[ring];
 		for (i = 0; i < rds_ring->num_desc; ++i) {
 			rx_buf = &(rds_ring->rx_buf_arr[i]);
-			if (rx_buf->state == QLCNIC_BUFFER_FREE)
+			if (rx_buf->skb == NULL)
 				continue;
+
 			pci_unmap_single(adapter->pdev,
 					rx_buf->dma,
 					rds_ring->dma_size,
 					PCI_DMA_FROMDEVICE);
-			if (rx_buf->skb != NULL)
-				dev_kfree_skb_any(rx_buf->skb);
+
+			dev_kfree_skb_any(rx_buf->skb);
 		}
 	}
 }
 
+void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_recv_context *recv_ctx;
+	struct qlcnic_host_rds_ring *rds_ring;
+	struct qlcnic_rx_buffer *rx_buf;
+	int i, ring;
+
+	recv_ctx = &adapter->recv_ctx;
+	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+		rds_ring = &recv_ctx->rds_rings[ring];
+
+		spin_lock(&rds_ring->lock);
+
+		INIT_LIST_HEAD(&rds_ring->free_list);
+
+		rx_buf = rds_ring->rx_buf_arr;
+		for (i = 0; i < rds_ring->num_desc; i++) {
+			list_add_tail(&rx_buf->list,
+					&rds_ring->free_list);
+			rx_buf++;
+		}
+
+		spin_unlock(&rds_ring->lock);
+	}
+}
+
 void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter)
 {
 	struct qlcnic_cmd_buffer *cmd_buf;
@@ -181,7 +208,9 @@
 
 	tx_ring = adapter->tx_ring;
 	vfree(tx_ring->cmd_buf_arr);
+	tx_ring->cmd_buf_arr = NULL;
 	kfree(adapter->tx_ring);
+	adapter->tx_ring = NULL;
 }
 
 int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
@@ -264,7 +293,6 @@
 			list_add_tail(&rx_buf->list,
 					&rds_ring->free_list);
 			rx_buf->ref_handle = i;
-			rx_buf->state = QLCNIC_BUFFER_FREE;
 			rx_buf++;
 		}
 		spin_lock_init(&rds_ring->lock);
@@ -413,7 +441,7 @@
 
 	/* resetall */
 	qlcnic_rom_lock(adapter);
-	QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xffffffff);
+	QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xfeffffff);
 	qlcnic_rom_unlock(adapter);
 
 	if (qlcnic_rom_fast_read(adapter, 0, &n) != 0 || (n != 0xcafecafe) ||
@@ -521,16 +549,13 @@
 	u32 val;
 
 	val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
-	val = (val >> (adapter->portnum * 4)) & 0xf;
-
-	if ((val & 0x3) != 1) {
-		dev_err(&adapter->pdev->dev, "Not an Ethernet NIC func=%u\n",
-									val);
+	val = QLC_DEV_GET_DRV(val, adapter->portnum);
+	if ((val & 0x3) != QLCNIC_TYPE_NIC) {
+		dev_err(&adapter->pdev->dev,
+			"Not an Ethernet NIC func=%u\n", val);
 		return -EIO;
 	}
-
 	adapter->physical_port = (val >> 2);
-
 	if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DEV_INIT_TIMEOUT, &timeo))
 		timeo = 30;
 
@@ -544,16 +569,34 @@
 	return 0;
 }
 
+int
+qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter)
+{
+	u32 ver = -1, min_ver;
+
+	qlcnic_rom_fast_read(adapter, QLCNIC_FW_VERSION_OFFSET, (int *)&ver);
+
+	ver = QLCNIC_DECODE_VERSION(ver);
+	min_ver = QLCNIC_MIN_FW_VERSION;
+
+	if (ver < min_ver) {
+		dev_err(&adapter->pdev->dev,
+			"firmware version %d.%d.%d unsupported."
+			"Min supported version %d.%d.%d\n",
+			_major(ver), _minor(ver), _build(ver),
+			_major(min_ver), _minor(min_ver), _build(min_ver));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int
 qlcnic_has_mn(struct qlcnic_adapter *adapter)
 {
-	u32 capability, flashed_ver;
+	u32 capability;
 	capability = 0;
 
-	qlcnic_rom_fast_read(adapter,
-			QLCNIC_FW_VERSION_OFFSET, (int *)&flashed_ver);
-	flashed_ver = QLCNIC_DECODE_VERSION(flashed_ver);
-
 	capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY);
 	if (capability & QLCNIC_PEG_TUNE_MN_PRESENT)
 		return 1;
@@ -1007,7 +1050,7 @@
 qlcnic_validate_firmware(struct qlcnic_adapter *adapter)
 {
 	__le32 val;
-	u32 ver, min_ver, bios, min_size;
+	u32 ver, bios, min_size;
 	struct pci_dev *pdev = adapter->pdev;
 	const struct firmware *fw = adapter->fw;
 	u8 fw_type = adapter->fw_type;
@@ -1029,12 +1072,9 @@
 		return -EINVAL;
 
 	val = qlcnic_get_fw_version(adapter);
-
-	min_ver = QLCNIC_VERSION_CODE(4, 0, 216);
-
 	ver = QLCNIC_DECODE_VERSION(val);
 
-	if ((_major(ver) > _QLCNIC_LINUX_MAJOR) || (ver < min_ver)) {
+	if (ver < QLCNIC_MIN_FW_VERSION) {
 		dev_err(&pdev->dev,
 				"%s: firmware version %d.%d.%d unsupported\n",
 		fw_name[fw_type], _major(ver), _minor(ver), _build(ver));
@@ -1122,7 +1162,7 @@
 	adapter->fw = NULL;
 }
 
-int qlcnic_phantom_init(struct qlcnic_adapter *adapter)
+static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter)
 {
 	u32 val;
 	int retries = 60;
@@ -1147,7 +1187,8 @@
 	QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
 
 out_err:
-	dev_err(&adapter->pdev->dev, "firmware init failed\n");
+	dev_err(&adapter->pdev->dev, "Command Peg initialization not "
+		      "complete, state: 0x%x.\n", val);
 	return -EIO;
 }
 
@@ -1180,6 +1221,10 @@
 {
 	int err;
 
+	err = qlcnic_cmd_peg_ready(adapter);
+	if (err)
+		return err;
+
 	err = qlcnic_receive_peg_ready(adapter);
 	if (err)
 		return err;
@@ -1265,14 +1310,12 @@
 	dma_addr_t dma;
 	struct pci_dev *pdev = adapter->pdev;
 
-	buffer->skb = dev_alloc_skb(rds_ring->skb_size);
-	if (!buffer->skb) {
+	skb = dev_alloc_skb(rds_ring->skb_size);
+	if (!skb) {
 		adapter->stats.skb_alloc_failure++;
 		return -ENOMEM;
 	}
 
-	skb = buffer->skb;
-
 	skb_reserve(skb, 2);
 
 	dma = pci_map_single(pdev, skb->data,
@@ -1281,13 +1324,11 @@
 	if (pci_dma_mapping_error(pdev, dma)) {
 		adapter->stats.rx_dma_map_error++;
 		dev_kfree_skb_any(skb);
-		buffer->skb = NULL;
 		return -ENOMEM;
 	}
 
 	buffer->skb = skb;
 	buffer->dma = dma;
-	buffer->state = QLCNIC_BUFFER_BUSY;
 
 	return 0;
 }
@@ -1300,14 +1341,15 @@
 
 	buffer = &rds_ring->rx_buf_arr[index];
 
+	if (unlikely(buffer->skb == NULL)) {
+		WARN_ON(1);
+		return NULL;
+	}
+
 	pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
 			PCI_DMA_FROMDEVICE);
 
 	skb = buffer->skb;
-	if (!skb) {
-		adapter->stats.null_skb++;
-		goto no_skb;
-	}
 
 	if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) {
 		adapter->stats.csummed++;
@@ -1319,8 +1361,7 @@
 	skb->dev = adapter->netdev;
 
 	buffer->skb = NULL;
-no_skb:
-	buffer->state = QLCNIC_BUFFER_FREE;
+
 	return skb;
 }
 
@@ -1495,7 +1536,7 @@
 
 		WARN_ON(desc_cnt > 1);
 
-		if (rxbuf)
+		if (likely(rxbuf))
 			list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
 		else
 			adapter->stats.null_rxbuf++;
@@ -1701,3 +1742,24 @@
 	sds_ring->consumer = consumer;
 	writel(consumer, sds_ring->crb_sts_consumer);
 }
+
+void
+qlcnic_fetch_mac(struct qlcnic_adapter *adapter, u32 off1, u32 off2,
+			u8 alt_mac, u8 *mac)
+{
+	u32 mac_low, mac_high;
+	int i;
+
+	mac_low = QLCRD32(adapter, off1);
+	mac_high = QLCRD32(adapter, off2);
+
+	if (alt_mac) {
+		mac_low |= (mac_low >> 16) | (mac_high << 16);
+		mac_high >>= 16;
+	}
+
+	for (i = 0; i < 2; i++)
+		mac[i] = (u8)(mac_high >> ((1 - i) * 8));
+	for (i = 2; i < 6; i++)
+		mac[i] = (u8)(mac_low >> ((5 - i) * 8));
+}
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 23ea9ca..b9615bd 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -34,15 +34,16 @@
 #include <linux/ipv6.h>
 #include <linux/inetdevice.h>
 #include <linux/sysfs.h>
+#include <linux/aer.h>
 
-MODULE_DESCRIPTION("QLogic 10 GbE Converged Ethernet Driver");
+MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(QLCNIC_LINUX_VERSIONID);
 MODULE_FIRMWARE(QLCNIC_UNIFIED_ROMIMAGE_NAME);
 
 char qlcnic_driver_name[] = "qlcnic";
-static const char qlcnic_driver_string[] = "QLogic Converged Ethernet Driver v"
-    QLCNIC_LINUX_VERSIONID;
+static const char qlcnic_driver_string[] = "QLogic 1/10 GbE "
+	"Converged/Intelligent Ethernet Driver v" QLCNIC_LINUX_VERSIONID;
 
 static int port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
 
@@ -65,13 +66,16 @@
 module_param(load_fw_file, int, 0644);
 MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");
 
+static int qlcnic_config_npars;
+module_param(qlcnic_config_npars, int, 0644);
+MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled");
+
 static int __devinit qlcnic_probe(struct pci_dev *pdev,
 		const struct pci_device_id *ent);
 static void __devexit qlcnic_remove(struct pci_dev *pdev);
 static int qlcnic_open(struct net_device *netdev);
 static int qlcnic_close(struct net_device *netdev);
 static void qlcnic_tx_timeout(struct net_device *netdev);
-static void qlcnic_tx_timeout_task(struct work_struct *work);
 static void qlcnic_attach_work(struct work_struct *work);
 static void qlcnic_fwinit_work(struct work_struct *work);
 static void qlcnic_fw_poll_work(struct work_struct *work);
@@ -79,6 +83,7 @@
 		work_func_t func, int delay);
 static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter);
 static int qlcnic_poll(struct napi_struct *napi, int budget);
+static int qlcnic_rx_poll(struct napi_struct *napi, int budget);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void qlcnic_poll_controller(struct net_device *netdev);
 #endif
@@ -99,7 +104,12 @@
 
 static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
 static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
+static int qlcnic_start_firmware(struct qlcnic_adapter *);
 
+static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
+static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
+static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
+static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
 /*  PCI Device ID Table  */
 #define ENTRY(device) \
 	{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
@@ -120,12 +130,6 @@
 		struct qlcnic_host_tx_ring *tx_ring)
 {
 	writel(tx_ring->producer, tx_ring->crb_cmd_producer);
-
-	if (qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH) {
-		netif_stop_queue(adapter->netdev);
-		smp_mb();
-		adapter->stats.xmit_off++;
-	}
 }
 
 static const u32 msi_tgt_status[8] = {
@@ -184,8 +188,13 @@
 
 	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
 		sds_ring = &recv_ctx->sds_rings[ring];
-		netif_napi_add(netdev, &sds_ring->napi,
-				qlcnic_poll, QLCNIC_NETDEV_WEIGHT);
+
+		if (ring == adapter->max_sds_rings - 1)
+			netif_napi_add(netdev, &sds_ring->napi, qlcnic_poll,
+				QLCNIC_NETDEV_WEIGHT/adapter->max_sds_rings);
+		else
+			netif_napi_add(netdev, &sds_ring->napi,
+				qlcnic_rx_poll, QLCNIC_NETDEV_WEIGHT*2);
 	}
 
 	return 0;
@@ -307,19 +316,14 @@
 static int
 qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
 {
-	int i;
-	unsigned char *p;
-	u64 mac_addr;
+	u8 mac_addr[ETH_ALEN];
 	struct net_device *netdev = adapter->netdev;
 	struct pci_dev *pdev = adapter->pdev;
 
-	if (qlcnic_get_mac_addr(adapter, &mac_addr) != 0)
+	if (adapter->nic_ops->get_mac_addr(adapter, mac_addr) != 0)
 		return -EIO;
 
-	p = (unsigned char *)&mac_addr;
-	for (i = 0; i < 6; i++)
-		netdev->dev_addr[i] = *(p + 5 - i);
-
+	memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
 	memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
 	memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
 
@@ -340,7 +344,7 @@
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EINVAL;
 
-	if (netif_running(netdev)) {
+	if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
 		netif_device_detach(netdev);
 		qlcnic_napi_disable(adapter);
 	}
@@ -349,7 +353,7 @@
 	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 	qlcnic_set_multi(adapter->netdev);
 
-	if (netif_running(netdev)) {
+	if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
 		netif_device_attach(netdev);
 		qlcnic_napi_enable(adapter);
 	}
@@ -371,6 +375,20 @@
 #endif
 };
 
+static struct qlcnic_nic_template qlcnic_ops = {
+	.get_mac_addr = qlcnic_get_mac_address,
+	.config_bridged_mode = qlcnic_config_bridged_mode,
+	.config_led = qlcnic_config_led,
+	.start_firmware = qlcnic_start_firmware
+};
+
+static struct qlcnic_nic_template qlcnic_vf_ops = {
+	.get_mac_addr = qlcnic_get_mac_address,
+	.config_bridged_mode = qlcnicvf_config_bridged_mode,
+	.config_led = qlcnicvf_config_led,
+	.start_firmware = qlcnicvf_start_firmware
+};
+
 static void
 qlcnic_setup_intr(struct qlcnic_adapter *adapter)
 {
@@ -453,6 +471,169 @@
 }
 
 static int
+qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_pci_info pci_info[QLCNIC_MAX_PCI_FUNC];
+	int i, ret = 0, err;
+	u8 pfn;
+
+	if (!adapter->npars)
+		adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
+				QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
+	if (!adapter->npars)
+		return -ENOMEM;
+
+	if (!adapter->eswitch)
+		adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
+				QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
+	if (!adapter->eswitch) {
+		err = -ENOMEM;
+		goto err_eswitch;
+	}
+
+	ret = qlcnic_get_pci_info(adapter, pci_info);
+	if (!ret) {
+		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+			pfn = pci_info[i].id;
+			if (pfn > QLCNIC_MAX_PCI_FUNC)
+				return QL_STATUS_INVALID_PARAM;
+			adapter->npars[pfn].active = pci_info[i].active;
+			adapter->npars[pfn].type = pci_info[i].type;
+			adapter->npars[pfn].phy_port = pci_info[i].default_port;
+			adapter->npars[pfn].mac_learning = DEFAULT_MAC_LEARN;
+			adapter->npars[pfn].min_bw = pci_info[i].tx_min_bw;
+			adapter->npars[pfn].max_bw = pci_info[i].tx_max_bw;
+		}
+
+		for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
+			adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
+
+		return ret;
+	}
+
+	kfree(adapter->eswitch);
+	adapter->eswitch = NULL;
+err_eswitch:
+	kfree(adapter->npars);
+
+	return ret;
+}
+
+static int
+qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
+{
+	u8 id;
+	u32 ref_count;
+	int i, ret = 1;
+	u32 data = QLCNIC_MGMT_FUNC;
+	void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+
+	/* If other drivers are not in use set their privilege level */
+	ref_count = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+	ret = qlcnic_api_lock(adapter);
+	if (ret)
+		goto err_lock;
+	if (QLC_DEV_CLR_REF_CNT(ref_count, adapter->ahw.pci_func))
+		goto err_npar;
+
+	if (qlcnic_config_npars) {
+		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+			id = i;
+			if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
+				id == adapter->ahw.pci_func)
+				continue;
+			data |= (qlcnic_config_npars &
+					QLC_DEV_SET_DRV(0xf, id));
+		}
+	} else {
+		data = readl(priv_op);
+		data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw.pci_func)) |
+			(QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
+			adapter->ahw.pci_func));
+	}
+	writel(data, priv_op);
+err_npar:
+	qlcnic_api_unlock(adapter);
+err_lock:
+	return ret;
+}
+
+static u32
+qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
+{
+	void __iomem *msix_base_addr;
+	void __iomem *priv_op;
+	struct qlcnic_info nic_info;
+	u32 func;
+	u32 msix_base;
+	u32 op_mode, priv_level;
+
+	/* Determine FW API version */
+	adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API);
+
+	/* Find PCI function number */
+	pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
+	msix_base_addr = adapter->ahw.pci_base0 + QLCNIC_MSIX_BASE;
+	msix_base = readl(msix_base_addr);
+	func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
+	adapter->ahw.pci_func = func;
+
+	if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
+		adapter->capabilities = nic_info.capabilities;
+
+		if (adapter->capabilities & BIT_6)
+			adapter->flags |= QLCNIC_ESWITCH_ENABLED;
+		else
+			adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+	}
+
+	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))	{
+		adapter->nic_ops = &qlcnic_ops;
+		return adapter->fw_hal_version;
+	}
+
+	/* Determine function privilege level */
+	priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+	op_mode = readl(priv_op);
+	if (op_mode == QLC_DEV_DRV_DEFAULT)
+		priv_level = QLCNIC_MGMT_FUNC;
+	else
+		priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
+
+	switch (priv_level) {
+	case QLCNIC_MGMT_FUNC:
+		adapter->op_mode = QLCNIC_MGMT_FUNC;
+		adapter->nic_ops = &qlcnic_ops;
+		qlcnic_init_pci_info(adapter);
+		/* Set privilege level for other functions */
+		qlcnic_set_function_modes(adapter);
+		dev_info(&adapter->pdev->dev,
+			"HAL Version: %d, Management function\n",
+			adapter->fw_hal_version);
+		break;
+	case QLCNIC_PRIV_FUNC:
+		adapter->op_mode = QLCNIC_PRIV_FUNC;
+		dev_info(&adapter->pdev->dev,
+			"HAL Version: %d, Privileged function\n",
+			adapter->fw_hal_version);
+		adapter->nic_ops = &qlcnic_ops;
+		break;
+	case QLCNIC_NON_PRIV_FUNC:
+		adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
+		dev_info(&adapter->pdev->dev,
+			"HAL Version: %d Non Privileged function\n",
+			adapter->fw_hal_version);
+		adapter->nic_ops = &qlcnic_vf_ops;
+		break;
+	default:
+		dev_info(&adapter->pdev->dev, "Unknown function mode: %d\n",
+			priv_level);
+		return 0;
+	}
+	return adapter->fw_hal_version;
+}
+
+static int
 qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
 {
 	void __iomem *mem_ptr0 = NULL;
@@ -460,7 +641,6 @@
 	unsigned long mem_len, pci_len0 = 0;
 
 	struct pci_dev *pdev = adapter->pdev;
-	int pci_func = adapter->ahw.pci_func;
 
 	/* remap phys address */
 	mem_base = pci_resource_start(pdev, 0);	/* 0 is for BAR 0 */
@@ -483,8 +663,13 @@
 	adapter->ahw.pci_base0 = mem_ptr0;
 	adapter->ahw.pci_len0 = pci_len0;
 
+	if (!qlcnic_get_driver_mode(adapter)) {
+		iounmap(adapter->ahw.pci_base0);
+		return -EIO;
+	}
+
 	adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
-		QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func)));
+		QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func)));
 
 	return 0;
 }
@@ -509,7 +694,7 @@
 	}
 
 	if (!found)
-		name = "Unknown";
+		sprintf(name, "%pM Gigabit Ethernet", adapter->mac_addr);
 }
 
 static void
@@ -521,7 +706,7 @@
 	int i, offset, val;
 	int *ptr32;
 	struct pci_dev *pdev = adapter->pdev;
-
+	struct qlcnic_info nic_info;
 	adapter->driver_mismatch = 0;
 
 	ptr32 = (int *)&serial_num;
@@ -553,8 +738,6 @@
 	dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
 			fw_major, fw_minor, fw_build);
 
-	adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);
-
 	adapter->flags &= ~QLCNIC_LRO_ENABLED;
 
 	if (adapter->ahw.port_type == QLCNIC_XGBE) {
@@ -565,6 +748,16 @@
 		adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
 	}
 
+	if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
+		adapter->physical_port = nic_info.phys_port;
+		adapter->switch_mode = nic_info.switch_mode;
+		adapter->max_tx_ques = nic_info.max_tx_ques;
+		adapter->max_rx_ques = nic_info.max_rx_ques;
+		adapter->capabilities = nic_info.capabilities;
+		adapter->max_mac_filters = nic_info.max_mac_filters;
+		adapter->max_mtu = nic_info.max_mtu;
+	}
+
 	adapter->msix_supported = !!use_msi_x;
 	adapter->rss_supported = !!use_msi_x;
 
@@ -574,6 +767,50 @@
 }
 
 static int
+qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
+{
+	int i, err = 0;
+	struct qlcnic_npar_info *npar;
+	struct qlcnic_info nic_info;
+
+	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+	    !adapter->need_fw_reset)
+		return 0;
+
+	if (adapter->op_mode == QLCNIC_MGMT_FUNC) {
+		/* Set the NPAR config data after FW reset */
+		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+			npar = &adapter->npars[i];
+			if (npar->type != QLCNIC_TYPE_NIC)
+				continue;
+			err = qlcnic_get_nic_info(adapter, &nic_info, i);
+			if (err)
+				goto err_out;
+			nic_info.min_tx_bw = npar->min_bw;
+			nic_info.max_tx_bw = npar->max_bw;
+			err = qlcnic_set_nic_info(adapter, &nic_info);
+			if (err)
+				goto err_out;
+
+			if (npar->enable_pm) {
+				err = qlcnic_config_port_mirroring(adapter,
+						npar->dest_npar, 1, i);
+				if (err)
+					goto err_out;
+
+			}
+			npar->mac_learning = DEFAULT_MAC_LEARN;
+			npar->host_vlan_tag = 0;
+			npar->promisc_mode = 0;
+			npar->discard_tagged = 0;
+			npar->vlan_id = 0;
+		}
+	}
+err_out:
+	return err;
+}
+
+static int
 qlcnic_start_firmware(struct qlcnic_adapter *adapter)
 {
 	int val, err, first_boot;
@@ -591,8 +828,12 @@
 
 	if (load_fw_file)
 		qlcnic_request_firmware(adapter);
-	else
+	else {
+		if (qlcnic_check_flash_fw_ver(adapter))
+			goto err_out;
+
 		adapter->fw_type = QLCNIC_FLASH_ROMIMAGE;
+	}
 
 	err = qlcnic_need_fw_reset(adapter);
 	if (err < 0)
@@ -602,6 +843,7 @@
 
 	if (first_boot != 0x55555555) {
 		QLCWR32(adapter, CRB_CMDPEG_STATE, 0);
+		QLCWR32(adapter, CRB_RCVPEG_STATE, 0);
 		qlcnic_pinit_from_rom(adapter);
 		msleep(1);
 	}
@@ -624,7 +866,7 @@
 
 wait_init:
 	/* Handshake with the card before we register the devices. */
-	err = qlcnic_phantom_init(adapter);
+	err = qlcnic_init_firmware(adapter);
 	if (err)
 		goto err_out;
 
@@ -632,6 +874,9 @@
 	qlcnic_idc_debug_info(adapter, 1);
 
 	qlcnic_check_options(adapter);
+	if (qlcnic_reset_npar_config(adapter))
+		goto err_out;
+	qlcnic_dev_set_npar_ready(adapter);
 
 	adapter->need_fw_reset = 0;
 
@@ -716,9 +961,23 @@
 static int
 __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
+	int ring;
+	struct qlcnic_host_rds_ring *rds_ring;
+
 	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
 		return -EIO;
 
+	if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+		return 0;
+
+	if (qlcnic_fw_create_ctx(adapter))
+		return -EIO;
+
+	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+		rds_ring = &adapter->recv_ctx.rds_rings[ring];
+		qlcnic_post_rx_buffers(adapter, ring, rds_ring);
+	}
+
 	qlcnic_set_multi(netdev);
 	qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu);
 
@@ -736,6 +995,7 @@
 
 	qlcnic_linkevent_request(adapter, 1);
 
+	adapter->reset_context = 0;
 	set_bit(__QLCNIC_DEV_UP, &adapter->state);
 	return 0;
 }
@@ -775,6 +1035,9 @@
 
 	qlcnic_napi_disable(adapter);
 
+	qlcnic_fw_destroy_ctx(adapter);
+
+	qlcnic_reset_rx_buffers_list(adapter);
 	qlcnic_release_tx_buffers(adapter);
 	spin_unlock(&adapter->tx_clean_lock);
 }
@@ -796,16 +1059,11 @@
 {
 	struct net_device *netdev = adapter->netdev;
 	struct pci_dev *pdev = adapter->pdev;
-	int err, ring;
-	struct qlcnic_host_rds_ring *rds_ring;
+	int err;
 
 	if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC)
 		return 0;
 
-	err = qlcnic_init_firmware(adapter);
-	if (err)
-		return err;
-
 	err = qlcnic_napi_add(adapter, netdev);
 	if (err)
 		return err;
@@ -813,7 +1071,7 @@
 	err = qlcnic_alloc_sw_resources(adapter);
 	if (err) {
 		dev_err(&pdev->dev, "Error in setting sw resources\n");
-		return err;
+		goto err_out_napi_del;
 	}
 
 	err = qlcnic_alloc_hw_resources(adapter);
@@ -822,16 +1080,10 @@
 		goto err_out_free_sw;
 	}
 
-
-	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
-		rds_ring = &adapter->recv_ctx.rds_rings[ring];
-		qlcnic_post_rx_buffers(adapter, ring, rds_ring);
-	}
-
 	err = qlcnic_request_irq(adapter);
 	if (err) {
 		dev_err(&pdev->dev, "failed to setup interrupt\n");
-		goto err_out_free_rxbuf;
+		goto err_out_free_hw;
 	}
 
 	qlcnic_init_coalesce_defaults(adapter);
@@ -841,11 +1093,12 @@
 	adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC;
 	return 0;
 
-err_out_free_rxbuf:
-	qlcnic_release_rx_buffers(adapter);
+err_out_free_hw:
 	qlcnic_free_hw_resources(adapter);
 err_out_free_sw:
 	qlcnic_free_sw_resources(adapter);
+err_out_napi_del:
+	qlcnic_napi_del(adapter);
 	return err;
 }
 
@@ -880,6 +1133,8 @@
 		}
 	}
 
+	qlcnic_fw_destroy_ctx(adapter);
+
 	qlcnic_detach(adapter);
 
 	adapter->diag_test = 0;
@@ -898,6 +1153,7 @@
 {
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_host_rds_ring *rds_ring;
 	int ring;
 	int ret;
 
@@ -917,6 +1173,18 @@
 		return ret;
 	}
 
+	ret = qlcnic_fw_create_ctx(adapter);
+	if (ret) {
+		qlcnic_detach(adapter);
+		netif_device_attach(netdev);
+		return ret;
+	}
+
+	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+		rds_ring = &adapter->recv_ctx.rds_rings[ring];
+		qlcnic_post_rx_buffers(adapter, ring, rds_ring);
+	}
+
 	if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
 		for (ring = 0; ring < adapter->max_sds_rings; ring++) {
 			sds_ring = &adapter->recv_ctx.sds_rings[ring];
@@ -928,6 +1196,27 @@
 	return 0;
 }
 
+/* Reset context in hardware only */
+static int
+qlcnic_reset_hw_context(struct qlcnic_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+		return -EBUSY;
+
+	netif_device_detach(netdev);
+
+	qlcnic_down(adapter, netdev);
+
+	qlcnic_up(adapter, netdev);
+
+	netif_device_attach(netdev);
+
+	clear_bit(__QLCNIC_RESETTING, &adapter->state);
+	return 0;
+}
+
 int
 qlcnic_reset_context(struct qlcnic_adapter *adapter)
 {
@@ -971,18 +1260,21 @@
 	adapter->max_mc_count = 38;
 
 	netdev->netdev_ops	   = &qlcnic_netdev_ops;
-	netdev->watchdog_timeo     = 2*HZ;
+	netdev->watchdog_timeo     = 5*HZ;
 
 	qlcnic_change_mtu(netdev, netdev->mtu);
 
 	SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
 
-	netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
-	netdev->features |= (NETIF_F_GRO);
-	netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+	netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
+		NETIF_F_IPV6_CSUM | NETIF_F_GRO);
+	netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
+		NETIF_F_IPV6_CSUM);
 
-	netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
-	netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+	if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
+		netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
+		netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
+	}
 
 	if (pci_using_dac) {
 		netdev->features |= NETIF_F_HIGHDMA;
@@ -997,8 +1289,6 @@
 
 	netdev->irq = adapter->msix_entries[0].vector;
 
-	INIT_WORK(&adapter->tx_timeout_task, qlcnic_tx_timeout_task);
-
 	if (qlcnic_read_mac_addr(adapter))
 		dev_warn(&pdev->dev, "failed to read mac addr\n");
 
@@ -1036,7 +1326,6 @@
 	struct net_device *netdev = NULL;
 	struct qlcnic_adapter *adapter = NULL;
 	int err;
-	int pci_func_id = PCI_FUNC(pdev->devfn);
 	uint8_t revision_id;
 	uint8_t pci_using_dac;
 
@@ -1058,6 +1347,7 @@
 		goto err_out_disable_pdev;
 
 	pci_set_master(pdev);
+	pci_enable_pcie_error_reporting(pdev);
 
 	netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
 	if (!netdev) {
@@ -1072,7 +1362,6 @@
 	adapter->netdev  = netdev;
 	adapter->pdev    = pdev;
 	adapter->dev_rst_time = jiffies;
-	adapter->ahw.pci_func  = pci_func_id;
 
 	revision_id = pdev->revision;
 	adapter->ahw.revision_id = revision_id;
@@ -1088,7 +1377,7 @@
 		goto err_out_free_netdev;
 
 	/* This will be reset for mezz cards  */
-	adapter->portnum = pci_func_id;
+	adapter->portnum = adapter->ahw.pci_func;
 
 	err = qlcnic_get_board_info(adapter);
 	if (err) {
@@ -1102,7 +1391,7 @@
 	if (qlcnic_setup_idc_param(adapter))
 		goto err_out_iounmap;
 
-	err = qlcnic_start_firmware(adapter);
+	err = adapter->nic_ops->start_firmware(adapter);
 	if (err) {
 		dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
 		goto err_out_decr_ref;
@@ -1171,10 +1460,13 @@
 
 	unregister_netdev(netdev);
 
-	cancel_work_sync(&adapter->tx_timeout_task);
-
 	qlcnic_detach(adapter);
 
+	if (adapter->npars != NULL)
+		kfree(adapter->npars);
+	if (adapter->eswitch != NULL)
+		kfree(adapter->eswitch);
+
 	qlcnic_clr_all_drv_state(adapter);
 
 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
@@ -1187,6 +1479,7 @@
 
 	qlcnic_release_firmware(adapter);
 
+	pci_disable_pcie_error_reporting(pdev);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
@@ -1206,10 +1499,6 @@
 	if (netif_running(netdev))
 		qlcnic_down(adapter, netdev);
 
-	cancel_work_sync(&adapter->tx_timeout_task);
-
-	qlcnic_detach(adapter);
-
 	qlcnic_clr_all_drv_state(adapter);
 
 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
@@ -1263,35 +1552,23 @@
 	pci_set_master(pdev);
 	pci_restore_state(pdev);
 
-	err = qlcnic_start_firmware(adapter);
+	err = adapter->nic_ops->start_firmware(adapter);
 	if (err) {
 		dev_err(&pdev->dev, "failed to start firmware\n");
 		return err;
 	}
 
 	if (netif_running(netdev)) {
-		err = qlcnic_attach(adapter);
-		if (err)
-			goto err_out;
-
 		err = qlcnic_up(adapter, netdev);
 		if (err)
-			goto err_out_detach;
-
+			goto done;
 
 		qlcnic_config_indev_addr(netdev, NETDEV_UP);
 	}
-
+done:
 	netif_device_attach(netdev);
 	qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
 	return 0;
-
-err_out_detach:
-	qlcnic_detach(adapter);
-err_out:
-	qlcnic_clr_all_drv_state(adapter);
-	netif_device_attach(netdev);
-	return err;
 }
 #endif
 
@@ -1340,11 +1617,11 @@
 	u8 opcode = TX_ETHER_PKT;
 	__be16 protocol = skb->protocol;
 	u16 flags = 0, vid = 0;
-	u32 producer;
 	int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
 	struct cmd_desc_type0 *hwdesc;
 	struct vlan_ethhdr *vh;
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
+	u32 producer = tx_ring->producer;
 
 	if (protocol == cpu_to_be16(ETH_P_8021Q)) {
 
@@ -1360,6 +1637,11 @@
 		vlan_oob = 1;
 	}
 
+	if (*(skb->data) & BIT_0) {
+		flags |= BIT_0;
+		memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
+	}
+
 	if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
 			skb_shinfo(skb)->gso_size > 0) {
 
@@ -1409,7 +1691,6 @@
 	/* For LSO, we need to copy the MAC/IP/TCP headers into
 	 * the descriptor ring
 	 */
-	producer = tx_ring->producer;
 	copied = 0;
 	offset = 2;
 
@@ -1537,10 +1818,15 @@
 	/* 4 fragments per cmd des */
 	no_of_desc = (frag_count + 3) >> 2;
 
-	if (unlikely(no_of_desc + 2 > qlcnic_tx_avail(tx_ring))) {
+	if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
 		netif_stop_queue(netdev);
-		adapter->stats.xmit_off++;
-		return NETDEV_TX_BUSY;
+		smp_mb();
+		if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
+			netif_start_queue(netdev);
+		else {
+			adapter->stats.xmit_off++;
+			return NETDEV_TX_BUSY;
+		}
 	}
 
 	producer = tx_ring->producer;
@@ -1675,35 +1961,11 @@
 		return;
 
 	dev_err(&netdev->dev, "transmit timeout, resetting.\n");
-	schedule_work(&adapter->tx_timeout_task);
-}
-
-static void qlcnic_tx_timeout_task(struct work_struct *work)
-{
-	struct qlcnic_adapter *adapter =
-		container_of(work, struct qlcnic_adapter, tx_timeout_task);
-
-	if (!netif_running(adapter->netdev))
-		return;
-
-	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
-		return;
 
 	if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS)
-		goto request_reset;
-
-	clear_bit(__QLCNIC_RESETTING, &adapter->state);
-	if (!qlcnic_reset_context(adapter)) {
-		adapter->netdev->trans_start = jiffies;
-		return;
-
-		/* context reset failed, fall through for fw reset */
-	}
-
-request_reset:
-	adapter->need_fw_reset = 1;
-	clear_bit(__QLCNIC_RESETTING, &adapter->state);
-	QLCDB(adapter, DRV, "Resetting adapter\n");
+		adapter->need_fw_reset = 1;
+	else
+		adapter->reset_context = 1;
 }
 
 static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
@@ -1846,14 +2108,12 @@
 		smp_mb();
 
 		if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
-			__netif_tx_lock(tx_ring->txq, smp_processor_id());
 			if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
 				netif_wake_queue(netdev);
-				adapter->tx_timeo_cnt = 0;
 				adapter->stats.xmit_on++;
 			}
-			__netif_tx_unlock(tx_ring->txq);
 		}
+		adapter->tx_timeo_cnt = 0;
 	}
 	/*
 	 * If everything is freed up to consumer then check if the ring is full
@@ -1898,6 +2158,25 @@
 	return work_done;
 }
 
+static int qlcnic_rx_poll(struct napi_struct *napi, int budget)
+{
+	struct qlcnic_host_sds_ring *sds_ring =
+		container_of(napi, struct qlcnic_host_sds_ring, napi);
+
+	struct qlcnic_adapter *adapter = sds_ring->adapter;
+	int work_done;
+
+	work_done = qlcnic_process_rcv_ring(sds_ring, budget);
+
+	if (work_done < budget) {
+		napi_complete(&sds_ring->napi);
+		if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+			qlcnic_enable_int(sds_ring);
+	}
+
+	return work_done;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void qlcnic_poll_controller(struct net_device *netdev)
 {
@@ -2109,7 +2388,7 @@
 {
 	struct qlcnic_adapter *adapter = container_of(work,
 			struct qlcnic_adapter, fw_work.work);
-	u32 dev_state = 0xf;
+	u32 dev_state = 0xf, npar_state;
 
 	if (qlcnic_api_lock(adapter))
 		goto err_ret;
@@ -2122,6 +2401,19 @@
 		return;
 	}
 
+	if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+		npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+		if (npar_state == QLCNIC_DEV_NPAR_RDY) {
+			qlcnic_api_unlock(adapter);
+			goto wait_npar;
+		} else {
+			qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
+				FW_POLL_DELAY);
+			qlcnic_api_unlock(adapter);
+			return;
+		}
+	}
+
 	if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
 		dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
 					adapter->reset_ack_timeo);
@@ -2154,7 +2446,7 @@
 
 		qlcnic_api_unlock(adapter);
 
-		if (!qlcnic_start_firmware(adapter)) {
+		if (!adapter->nic_ops->start_firmware(adapter)) {
 			qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
 			return;
 		}
@@ -2163,6 +2455,7 @@
 
 	qlcnic_api_unlock(adapter);
 
+wait_npar:
 	dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
 	QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
 
@@ -2177,7 +2470,7 @@
 		break;
 
 	default:
-		if (!qlcnic_start_firmware(adapter)) {
+		if (!adapter->nic_ops->start_firmware(adapter)) {
 			qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
 			return;
 		}
@@ -2202,10 +2495,6 @@
 
 	qlcnic_down(adapter, netdev);
 
-	rtnl_lock();
-	qlcnic_detach(adapter);
-	rtnl_unlock();
-
 	status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
 
 	if (status & QLCNIC_RCODE_FATAL_ERROR)
@@ -2237,6 +2526,7 @@
 {
 	u32 state;
 
+	adapter->need_fw_reset = 1;
 	if (qlcnic_api_lock(adapter))
 		return;
 
@@ -2251,10 +2541,36 @@
 	qlcnic_api_unlock(adapter);
 }
 
+/* Transit to NPAR READY state from NPAR NOT READY state */
+static void
+qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
+{
+	u32 state;
+
+	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+		adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
+		return;
+	if (qlcnic_api_lock(adapter))
+		return;
+
+	state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+
+	if (state != QLCNIC_DEV_NPAR_RDY) {
+		QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+			QLCNIC_DEV_NPAR_RDY);
+		QLCDB(adapter, DRV, "NPAR READY state set\n");
+	}
+
+	qlcnic_api_unlock(adapter);
+}
+
 static void
 qlcnic_schedule_work(struct qlcnic_adapter *adapter,
 		work_func_t func, int delay)
 {
+	if (test_bit(__QLCNIC_AER, &adapter->state))
+		return;
+
 	INIT_DELAYED_WORK(&adapter->fw_work, func);
 	schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay));
 }
@@ -2274,19 +2590,11 @@
 	struct qlcnic_adapter *adapter = container_of(work,
 				struct qlcnic_adapter, fw_work.work);
 	struct net_device *netdev = adapter->netdev;
-	int err;
 
 	if (netif_running(netdev)) {
-		err = qlcnic_attach(adapter);
-		if (err)
+		if (qlcnic_up(adapter, netdev))
 			goto done;
 
-		err = qlcnic_up(adapter, netdev);
-		if (err) {
-			qlcnic_detach(adapter);
-			goto done;
-		}
-
 		qlcnic_config_indev_addr(netdev, NETDEV_UP);
 	}
 
@@ -2322,6 +2630,13 @@
 		adapter->fw_fail_cnt = 0;
 		if (adapter->need_fw_reset)
 			goto detach;
+
+		if (adapter->reset_context &&
+		    auto_fw_reset == AUTO_FW_RESET_ENABLED) {
+			qlcnic_reset_hw_context(adapter);
+			adapter->netdev->trans_start = jiffies;
+		}
+
 		return 0;
 	}
 
@@ -2330,7 +2645,8 @@
 
 	qlcnic_dev_request_reset(adapter);
 
-	clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
+	if ((auto_fw_reset == AUTO_FW_RESET_ENABLED))
+		clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
 
 	dev_info(&netdev->dev, "firmware hang detected\n");
 
@@ -2365,6 +2681,161 @@
 	qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
 }
 
+static int qlcnic_is_first_func(struct pci_dev *pdev)
+{
+	struct pci_dev *oth_pdev;
+	int val = pdev->devfn;
+
+	while (val-- > 0) {
+		oth_pdev = pci_get_domain_bus_and_slot(pci_domain_nr
+			(pdev->bus), pdev->bus->number,
+			PCI_DEVFN(PCI_SLOT(pdev->devfn), val));
+		if (!oth_pdev)
+			continue;
+
+		if (oth_pdev->current_state != PCI_D3cold) {
+			pci_dev_put(oth_pdev);
+			return 0;
+		}
+		pci_dev_put(oth_pdev);
+	}
+	return 1;
+}
+
+static int qlcnic_attach_func(struct pci_dev *pdev)
+{
+	int err, first_func;
+	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+	struct net_device *netdev = adapter->netdev;
+
+	pdev->error_state = pci_channel_io_normal;
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_set_master(pdev);
+	pci_restore_state(pdev);
+
+	first_func = qlcnic_is_first_func(pdev);
+
+	if (qlcnic_api_lock(adapter))
+		return -EINVAL;
+
+	if (first_func) {
+		adapter->need_fw_reset = 1;
+		set_bit(__QLCNIC_START_FW, &adapter->state);
+		QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
+		QLCDB(adapter, DRV, "Restarting fw\n");
+	}
+	qlcnic_api_unlock(adapter);
+
+	err = adapter->nic_ops->start_firmware(adapter);
+	if (err)
+		return err;
+
+	qlcnic_clr_drv_state(adapter);
+	qlcnic_setup_intr(adapter);
+
+	if (netif_running(netdev)) {
+		err = qlcnic_attach(adapter);
+		if (err) {
+			qlcnic_clr_all_drv_state(adapter);
+			clear_bit(__QLCNIC_AER, &adapter->state);
+			netif_device_attach(netdev);
+			return err;
+		}
+
+		err = qlcnic_up(adapter, netdev);
+		if (err)
+			goto done;
+
+		qlcnic_config_indev_addr(netdev, NETDEV_UP);
+	}
+ done:
+	netif_device_attach(netdev);
+	return err;
+}
+
+static pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev,
+						pci_channel_state_t state)
+{
+	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+	struct net_device *netdev = adapter->netdev;
+
+	if (state == pci_channel_io_perm_failure)
+		return PCI_ERS_RESULT_DISCONNECT;
+
+	if (state == pci_channel_io_normal)
+		return PCI_ERS_RESULT_RECOVERED;
+
+	set_bit(__QLCNIC_AER, &adapter->state);
+	netif_device_detach(netdev);
+
+	cancel_delayed_work_sync(&adapter->fw_work);
+
+	if (netif_running(netdev))
+		qlcnic_down(adapter, netdev);
+
+	qlcnic_detach(adapter);
+	qlcnic_teardown_intr(adapter);
+
+	clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t qlcnic_io_slot_reset(struct pci_dev *pdev)
+{
+	return qlcnic_attach_func(pdev) ? PCI_ERS_RESULT_DISCONNECT :
+				PCI_ERS_RESULT_RECOVERED;
+}
+
+static void qlcnic_io_resume(struct pci_dev *pdev)
+{
+	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+
+	pci_cleanup_aer_uncorrect_error_status(pdev);
+
+	if (QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY &&
+	    test_and_clear_bit(__QLCNIC_AER, &adapter->state))
+		qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
+						FW_POLL_DELAY);
+}
+
+
+static int
+qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
+{
+	int err;
+
+	err = qlcnic_can_start_firmware(adapter);
+	if (err)
+		return err;
+
+	qlcnic_check_options(adapter);
+
+	adapter->need_fw_reset = 0;
+
+	return err;
+}
+
+static int
+qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
+{
+	return -EOPNOTSUPP;
+}
+
+static int
+qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
+{
+	return -EOPNOTSUPP;
+}
+
 static ssize_t
 qlcnic_store_bridged_mode(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t len)
@@ -2376,13 +2847,13 @@
 	if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG))
 		goto err_out;
 
-	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
 		goto err_out;
 
 	if (strict_strtoul(buf, 2, &new))
 		goto err_out;
 
-	if (!qlcnic_config_bridged_mode(adapter, !!new))
+	if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
 		ret = len;
 
 err_out:
@@ -2585,6 +3056,361 @@
 	.write = qlcnic_sysfs_write_mem,
 };
 
+static int
+validate_pm_config(struct qlcnic_adapter *adapter,
+			struct qlcnic_pm_func_cfg *pm_cfg, int count)
+{
+
+	u8 src_pci_func, s_esw_id, d_esw_id;
+	u8 dest_pci_func;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		src_pci_func = pm_cfg[i].pci_func;
+		dest_pci_func = pm_cfg[i].dest_npar;
+		if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
+				|| dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (!IS_VALID_MODE(pm_cfg[i].action))
+			return QL_STATUS_INVALID_PARAM;
+
+		s_esw_id = adapter->npars[src_pci_func].phy_port;
+		d_esw_id = adapter->npars[dest_pci_func].phy_port;
+
+		if (s_esw_id != d_esw_id)
+			return QL_STATUS_INVALID_PARAM;
+
+	}
+	return 0;
+
+}
+
+static ssize_t
+qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_pm_func_cfg *pm_cfg;
+	u32 id, action, pci_func;
+	int count, rem, i, ret;
+
+	count	= size / sizeof(struct qlcnic_pm_func_cfg);
+	rem	= size % sizeof(struct qlcnic_pm_func_cfg);
+	if (rem)
+		return QL_STATUS_INVALID_PARAM;
+
+	pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
+
+	ret = validate_pm_config(adapter, pm_cfg, count);
+	if (ret)
+		return ret;
+	for (i = 0; i < count; i++) {
+		pci_func = pm_cfg[i].pci_func;
+		action = pm_cfg[i].action;
+		id = adapter->npars[pci_func].phy_port;
+		ret = qlcnic_config_port_mirroring(adapter, id,
+						action, pci_func);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < count; i++) {
+		pci_func = pm_cfg[i].pci_func;
+		id = adapter->npars[pci_func].phy_port;
+		adapter->npars[pci_func].enable_pm = pm_cfg[i].action;
+		adapter->npars[pci_func].dest_npar = id;
+	}
+	return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
+	int i;
+
+	if (size != sizeof(pm_cfg))
+		return QL_STATUS_INVALID_PARAM;
+
+	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+			continue;
+		pm_cfg[i].action = adapter->npars[i].enable_pm;
+		pm_cfg[i].dest_npar = 0;
+		pm_cfg[i].pci_func = i;
+	}
+	memcpy(buf, &pm_cfg, size);
+
+	return size;
+}
+
+static int
+validate_esw_config(struct qlcnic_adapter *adapter,
+			struct qlcnic_esw_func_cfg *esw_cfg, int count)
+{
+	u8 pci_func;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		pci_func = esw_cfg[i].pci_func;
+		if (pci_func >= QLCNIC_MAX_PCI_FUNC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (esw_cfg->host_vlan_tag == 1)
+			if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
+				return QL_STATUS_INVALID_PARAM;
+
+		if (!IS_VALID_MODE(esw_cfg[i].promisc_mode)
+				|| !IS_VALID_MODE(esw_cfg[i].host_vlan_tag)
+				|| !IS_VALID_MODE(esw_cfg[i].mac_learning)
+				|| !IS_VALID_MODE(esw_cfg[i].discard_tagged))
+			return QL_STATUS_INVALID_PARAM;
+	}
+
+	return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_esw_func_cfg *esw_cfg;
+	int count, rem, i, ret;
+	u8 id, pci_func;
+
+	count	= size / sizeof(struct qlcnic_esw_func_cfg);
+	rem	= size % sizeof(struct qlcnic_esw_func_cfg);
+	if (rem)
+		return QL_STATUS_INVALID_PARAM;
+
+	esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
+	ret = validate_esw_config(adapter, esw_cfg, count);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < count; i++) {
+		pci_func = esw_cfg[i].pci_func;
+		id = adapter->npars[pci_func].phy_port;
+		ret = qlcnic_config_switch_port(adapter, id,
+						esw_cfg[i].host_vlan_tag,
+						esw_cfg[i].discard_tagged,
+						esw_cfg[i].promisc_mode,
+						esw_cfg[i].mac_learning,
+						esw_cfg[i].pci_func,
+						esw_cfg[i].vlan_id);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < count; i++) {
+		pci_func = esw_cfg[i].pci_func;
+		adapter->npars[pci_func].promisc_mode = esw_cfg[i].promisc_mode;
+		adapter->npars[pci_func].mac_learning =	esw_cfg[i].mac_learning;
+		adapter->npars[pci_func].vlan_id = esw_cfg[i].vlan_id;
+		adapter->npars[pci_func].discard_tagged	=
+						esw_cfg[i].discard_tagged;
+		adapter->npars[pci_func].host_vlan_tag =
+						esw_cfg[i].host_vlan_tag;
+	}
+
+	return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
+	int i;
+
+	if (size != sizeof(esw_cfg))
+		return QL_STATUS_INVALID_PARAM;
+
+	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+			continue;
+
+		esw_cfg[i].host_vlan_tag = adapter->npars[i].host_vlan_tag;
+		esw_cfg[i].promisc_mode = adapter->npars[i].promisc_mode;
+		esw_cfg[i].discard_tagged = adapter->npars[i].discard_tagged;
+		esw_cfg[i].vlan_id = adapter->npars[i].vlan_id;
+		esw_cfg[i].mac_learning = adapter->npars[i].mac_learning;
+	}
+	memcpy(buf, &esw_cfg, size);
+
+	return size;
+}
+
+static int
+validate_npar_config(struct qlcnic_adapter *adapter,
+				struct qlcnic_npar_func_cfg *np_cfg, int count)
+{
+	u8 pci_func, i;
+
+	for (i = 0; i < count; i++) {
+		pci_func = np_cfg[i].pci_func;
+		if (pci_func >= QLCNIC_MAX_PCI_FUNC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (!IS_VALID_BW(np_cfg[i].min_bw)
+				|| !IS_VALID_BW(np_cfg[i].max_bw)
+				|| !IS_VALID_RX_QUEUES(np_cfg[i].max_rx_queues)
+				|| !IS_VALID_TX_QUEUES(np_cfg[i].max_tx_queues))
+			return QL_STATUS_INVALID_PARAM;
+	}
+	return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_info nic_info;
+	struct qlcnic_npar_func_cfg *np_cfg;
+	int i, count, rem, ret;
+	u8 pci_func;
+
+	count	= size / sizeof(struct qlcnic_npar_func_cfg);
+	rem	= size % sizeof(struct qlcnic_npar_func_cfg);
+	if (rem)
+		return QL_STATUS_INVALID_PARAM;
+
+	np_cfg = (struct qlcnic_npar_func_cfg *) buf;
+	ret = validate_npar_config(adapter, np_cfg, count);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < count ; i++) {
+		pci_func = np_cfg[i].pci_func;
+		ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
+		if (ret)
+			return ret;
+		nic_info.pci_func = pci_func;
+		nic_info.min_tx_bw = np_cfg[i].min_bw;
+		nic_info.max_tx_bw = np_cfg[i].max_bw;
+		ret = qlcnic_set_nic_info(adapter, &nic_info);
+		if (ret)
+			return ret;
+		adapter->npars[i].min_bw = nic_info.min_tx_bw;
+		adapter->npars[i].max_bw = nic_info.max_tx_bw;
+	}
+
+	return size;
+
+}
+static ssize_t
+qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_info nic_info;
+	struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
+	int i, ret;
+
+	if (size != sizeof(np_cfg))
+		return QL_STATUS_INVALID_PARAM;
+
+	for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+			continue;
+		ret = qlcnic_get_nic_info(adapter, &nic_info, i);
+		if (ret)
+			return ret;
+
+		np_cfg[i].pci_func = i;
+		np_cfg[i].op_mode = nic_info.op_mode;
+		np_cfg[i].port_num = nic_info.phys_port;
+		np_cfg[i].fw_capab = nic_info.capabilities;
+		np_cfg[i].min_bw = nic_info.min_tx_bw ;
+		np_cfg[i].max_bw = nic_info.max_tx_bw;
+		np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
+		np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
+	}
+	memcpy(buf, &np_cfg, size);
+	return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
+	struct qlcnic_pci_info	pci_info[QLCNIC_MAX_PCI_FUNC];
+	int i, ret;
+
+	if (size != sizeof(pci_cfg))
+		return QL_STATUS_INVALID_PARAM;
+
+	ret = qlcnic_get_pci_info(adapter, pci_info);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+		pci_cfg[i].pci_func = pci_info[i].id;
+		pci_cfg[i].func_type = pci_info[i].type;
+		pci_cfg[i].port_num = pci_info[i].default_port;
+		pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
+		pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
+		memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
+	}
+	memcpy(buf, &pci_cfg, size);
+	return size;
+
+}
+static struct bin_attribute bin_attr_npar_config = {
+	.attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
+	.size = 0,
+	.read = qlcnic_sysfs_read_npar_config,
+	.write = qlcnic_sysfs_write_npar_config,
+};
+
+static struct bin_attribute bin_attr_pci_config = {
+	.attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
+	.size = 0,
+	.read = qlcnic_sysfs_read_pci_config,
+	.write = NULL,
+};
+
+static struct bin_attribute bin_attr_esw_config = {
+	.attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
+	.size = 0,
+	.read = qlcnic_sysfs_read_esw_config,
+	.write = qlcnic_sysfs_write_esw_config,
+};
+
+static struct bin_attribute bin_attr_pm_config = {
+	.attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
+	.size = 0,
+	.read = qlcnic_sysfs_read_pm_config,
+	.write = qlcnic_sysfs_write_pm_config,
+};
+
 static void
 qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
 {
@@ -2610,23 +3436,45 @@
 {
 	struct device *dev = &adapter->pdev->dev;
 
+	if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
+		return;
 	if (device_create_file(dev, &dev_attr_diag_mode))
 		dev_info(dev, "failed to create diag_mode sysfs entry\n");
 	if (device_create_bin_file(dev, &bin_attr_crb))
 		dev_info(dev, "failed to create crb sysfs entry\n");
 	if (device_create_bin_file(dev, &bin_attr_mem))
 		dev_info(dev, "failed to create mem sysfs entry\n");
-}
+	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+			adapter->op_mode != QLCNIC_MGMT_FUNC)
+		return;
+	if (device_create_bin_file(dev, &bin_attr_pci_config))
+		dev_info(dev, "failed to create pci config sysfs entry");
+	if (device_create_bin_file(dev, &bin_attr_npar_config))
+		dev_info(dev, "failed to create npar config sysfs entry");
+	if (device_create_bin_file(dev, &bin_attr_esw_config))
+		dev_info(dev, "failed to create esw config sysfs entry");
+	if (device_create_bin_file(dev, &bin_attr_pm_config))
+		dev_info(dev, "failed to create pm config sysfs entry");
 
+}
 
 static void
 qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
 {
 	struct device *dev = &adapter->pdev->dev;
 
+	if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
+		return;
 	device_remove_file(dev, &dev_attr_diag_mode);
 	device_remove_bin_file(dev, &bin_attr_crb);
 	device_remove_bin_file(dev, &bin_attr_mem);
+	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+			adapter->op_mode != QLCNIC_MGMT_FUNC)
+		return;
+	device_remove_bin_file(dev, &bin_attr_pci_config);
+	device_remove_bin_file(dev, &bin_attr_npar_config);
+	device_remove_bin_file(dev, &bin_attr_esw_config);
+	device_remove_bin_file(dev, &bin_attr_pm_config);
 }
 
 #ifdef CONFIG_INET
@@ -2684,7 +3532,7 @@
 	if (!adapter)
 		goto done;
 
-	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
 		goto done;
 
 	qlcnic_config_indev_addr(dev, event);
@@ -2720,7 +3568,7 @@
 	if (!adapter)
 		goto done;
 
-	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
 		goto done;
 
 	switch (event) {
@@ -2750,6 +3598,11 @@
 qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
 { }
 #endif
+static struct pci_error_handlers qlcnic_err_handler = {
+	.error_detected = qlcnic_io_error_detected,
+	.slot_reset = qlcnic_io_slot_reset,
+	.resume = qlcnic_io_resume,
+};
 
 static struct pci_driver qlcnic_driver = {
 	.name = qlcnic_driver_name,
@@ -2760,11 +3613,14 @@
 	.suspend = qlcnic_suspend,
 	.resume = qlcnic_resume,
 #endif
-	.shutdown = qlcnic_shutdown
+	.shutdown = qlcnic_shutdown,
+	.err_handler = &qlcnic_err_handler
+
 };
 
 static int __init qlcnic_init_module(void)
 {
+	int ret;
 
 	printk(KERN_INFO "%s\n", qlcnic_driver_string);
 
@@ -2773,8 +3629,15 @@
 	register_inetaddr_notifier(&qlcnic_inetaddr_cb);
 #endif
 
+	ret = pci_register_driver(&qlcnic_driver);
+	if (ret) {
+#ifdef CONFIG_INET
+		unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
+		unregister_netdevice_notifier(&qlcnic_netdev_cb);
+#endif
+	}
 
-	return pci_register_driver(&qlcnic_driver);
+	return ret;
 }
 
 module_init(qlcnic_init_module);
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 20624ba..a478786 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -16,9 +16,7 @@
  */
 #define DRV_NAME  	"qlge"
 #define DRV_STRING 	"QLogic 10 Gigabit PCI-E Ethernet Driver "
-#define DRV_VERSION	"v1.00.00.23.00.00-01"
-
-#define PFX "qlge: "
+#define DRV_VERSION	"v1.00.00.25.00.00-01"
 
 #define WQ_ADDR_ALIGN	0x3	/* 4 byte alignment */
 
@@ -1062,7 +1060,7 @@
 #define TX_DESC_LEN_MASK	0x000fffff
 #define TX_DESC_C	0x40000000
 #define TX_DESC_E	0x80000000
-} __attribute((packed));
+} __packed;
 
 /*
  * IOCB Definitions...
@@ -1095,7 +1093,7 @@
 	__le16 vlan_tci;
 	__le16 reserved4;
 	struct tx_buf_desc tbd[TX_DESC_PER_IOCB];
-} __attribute((packed));
+} __packed;
 
 struct ob_mac_iocb_rsp {
 	u8 opcode;		/* */
@@ -1112,7 +1110,7 @@
 	u32 tid;
 	u32 txq_idx;
 	__le32 reserved[13];
-} __attribute((packed));
+} __packed;
 
 struct ob_mac_tso_iocb_req {
 	u8 opcode;
@@ -1140,7 +1138,7 @@
 	__le16 vlan_tci;
 	__le16 mss;
 	struct tx_buf_desc tbd[TX_DESC_PER_IOCB];
-} __attribute((packed));
+} __packed;
 
 struct ob_mac_tso_iocb_rsp {
 	u8 opcode;
@@ -1157,7 +1155,7 @@
 	u32 tid;
 	u32 txq_idx;
 	__le32 reserved2[13];
-} __attribute((packed));
+} __packed;
 
 struct ib_mac_iocb_rsp {
 	u8 opcode;		/* 0x20 */
@@ -1216,7 +1214,7 @@
 #define IB_MAC_IOCB_RSP_HL	0x80
 	__le32 hdr_len;		/* */
 	__le64 hdr_addr;	/* */
-} __attribute((packed));
+} __packed;
 
 struct ib_ae_iocb_rsp {
 	u8 opcode;
@@ -1237,7 +1235,7 @@
 #define PCI_ERR_ANON_BUF_RD        0x40
 	u8 q_id;
 	__le32 reserved[15];
-} __attribute((packed));
+} __packed;
 
 /*
  * These three structures are for generic
@@ -1249,7 +1247,7 @@
 	__le16 length;
 	__le32 tid;
 	__le32 reserved[14];
-} __attribute((packed));
+} __packed;
 
 struct net_req_iocb {
 	u8 opcode;
@@ -1257,7 +1255,7 @@
 	__le16 flags1;
 	__le32 tid;
 	__le32 reserved1[30];
-} __attribute((packed));
+} __packed;
 
 /*
  * tx ring initialization control block for chip.
@@ -1283,7 +1281,7 @@
 	__le16 rid;
 	__le64 addr;
 	__le64 cnsmr_idx_addr;
-} __attribute((packed));
+} __packed;
 
 /*
  * rx ring initialization control block for chip.
@@ -1317,7 +1315,7 @@
 	__le64 sbq_addr;
 	__le16 sbq_buf_size;
 	__le16 sbq_len;		/* entry count */
-} __attribute((packed));
+} __packed;
 
 struct ricb {
 	u8 base_cq;
@@ -1335,7 +1333,7 @@
 	u8 hash_cq_id[1024];
 	__le32 ipv6_hash_key[10];
 	__le32 ipv4_hash_key[4];
-} __attribute((packed));
+} __packed;
 
 /* SOFTWARE/DRIVER DATA STRUCTURES. */
 
@@ -2227,7 +2225,6 @@
 		u32 ram_addr, int word_count);
 int ql_core_dump(struct ql_adapter *qdev,
 		struct ql_mpi_coredump *mpi_coredump);
-int ql_mb_sys_err(struct ql_adapter *qdev);
 int ql_mb_about_fw(struct ql_adapter *qdev);
 int ql_wol(struct ql_adapter *qdev);
 int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol);
@@ -2246,6 +2243,7 @@
 void ql_check_lb_frame(struct ql_adapter *, struct sk_buff *);
 int ql_own_firmware(struct ql_adapter *qdev);
 int ql_clean_lb_rx_ring(struct rx_ring *rx_ring, int budget);
+void qlge_set_multicast_list(struct net_device *ndev);
 
 #if 1
 #define QL_ALL_DUMP
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index 68a1c9b..4747492 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/slab.h>
 
 #include "qlge.h"
@@ -446,7 +448,7 @@
 					MAC_ADDR_TYPE_CAM_MAC, i, value);
 		if (status) {
 			netif_err(qdev, drv, qdev->ndev,
-				  "Failed read of mac index register.\n");
+				  "Failed read of mac index register\n");
 			goto err;
 		}
 		*buf++ = value[0];	/* lower MAC address */
@@ -458,7 +460,7 @@
 					MAC_ADDR_TYPE_MULTI_MAC, i, value);
 		if (status) {
 			netif_err(qdev, drv, qdev->ndev,
-				  "Failed read of mac index register.\n");
+				  "Failed read of mac index register\n");
 			goto err;
 		}
 		*buf++ = value[0];	/* lower Mcast address */
@@ -482,7 +484,7 @@
 		status = ql_get_routing_reg(qdev, i, &value);
 		if (status) {
 			netif_err(qdev, drv, qdev->ndev,
-				  "Failed read of routing index register.\n");
+				  "Failed read of routing index register\n");
 			goto err;
 		} else {
 			*buf++ = value;
@@ -668,7 +670,7 @@
 			max_offset = MAC_ADDR_MAX_MGMT_TU_DP_WCOUNT;
 			break;
 		default:
-			printk(KERN_ERR"Bad type!!! 0x%08x\n", type);
+			pr_err("Bad type!!! 0x%08x\n", type);
 			max_index = 0;
 			max_offset = 0;
 			break;
@@ -738,7 +740,7 @@
 	int i;
 
 	if (!mpi_coredump) {
-		netif_err(qdev, drv, qdev->ndev, "No memory available.\n");
+		netif_err(qdev, drv, qdev->ndev, "No memory available\n");
 		return -ENOMEM;
 	}
 
@@ -1234,15 +1236,10 @@
 
 	if (!netif_running(qdev->ndev)) {
 		netif_err(qdev, ifup, qdev->ndev,
-			  "Force Coredump can only be done from interface that is up.\n");
+			  "Force Coredump can only be done from interface that is up\n");
 		return;
 	}
-
-	if (ql_mb_sys_err(qdev)) {
-		netif_err(qdev, ifup, qdev->ndev,
-			  "Fail force coredump with ql_mb_sys_err().\n");
-		return;
-	}
+	ql_queue_fw_error(qdev);
 }
 
 void ql_gen_reg_dump(struct ql_adapter *qdev,
@@ -1339,7 +1336,7 @@
 		     "Core is dumping to log file!\n");
 
 	for (i = 0; i < count; i += 8) {
-		printk(KERN_ERR "%.08x: %.08x %.08x %.08x %.08x %.08x "
+		pr_err("%.08x: %.08x %.08x %.08x %.08x %.08x "
 			"%.08x %.08x %.08x\n", i,
 			tmp[i + 0],
 			tmp[i + 1],
@@ -1361,71 +1358,43 @@
 	for (i = 0; i < qdev->intr_count; i++) {
 		ql_write32(qdev, INTR_EN, qdev->intr_context[i].intr_read_mask);
 		value = ql_read32(qdev, INTR_EN);
-		printk(KERN_ERR PFX
-		       "%s: Interrupt %d is %s.\n",
+		pr_err("%s: Interrupt %d is %s\n",
 		       qdev->ndev->name, i,
 		       (value & INTR_EN_EN ? "enabled" : "disabled"));
 	}
 }
 
+#define DUMP_XGMAC(qdev, reg)					\
+do {								\
+	u32 data;						\
+	ql_read_xgmac_reg(qdev, reg, &data);			\
+	pr_err("%s: %s = 0x%.08x\n", qdev->ndev->name, #reg, data); \
+} while (0)
+
 void ql_dump_xgmac_control_regs(struct ql_adapter *qdev)
 {
-	u32 data;
 	if (ql_sem_spinlock(qdev, qdev->xg_sem_mask)) {
-		printk(KERN_ERR "%s: Couldn't get xgmac sem.\n", __func__);
+		pr_err("%s: Couldn't get xgmac sem\n", __func__);
 		return;
 	}
-	ql_read_xgmac_reg(qdev, PAUSE_SRC_LO, &data);
-	printk(KERN_ERR PFX "%s: PAUSE_SRC_LO = 0x%.08x.\n", qdev->ndev->name,
-	       data);
-	ql_read_xgmac_reg(qdev, PAUSE_SRC_HI, &data);
-	printk(KERN_ERR PFX "%s: PAUSE_SRC_HI = 0x%.08x.\n", qdev->ndev->name,
-	       data);
-	ql_read_xgmac_reg(qdev, GLOBAL_CFG, &data);
-	printk(KERN_ERR PFX "%s: GLOBAL_CFG = 0x%.08x.\n", qdev->ndev->name,
-	       data);
-	ql_read_xgmac_reg(qdev, TX_CFG, &data);
-	printk(KERN_ERR PFX "%s: TX_CFG = 0x%.08x.\n", qdev->ndev->name, data);
-	ql_read_xgmac_reg(qdev, RX_CFG, &data);
-	printk(KERN_ERR PFX "%s: RX_CFG = 0x%.08x.\n", qdev->ndev->name, data);
-	ql_read_xgmac_reg(qdev, FLOW_CTL, &data);
-	printk(KERN_ERR PFX "%s: FLOW_CTL = 0x%.08x.\n", qdev->ndev->name,
-	       data);
-	ql_read_xgmac_reg(qdev, PAUSE_OPCODE, &data);
-	printk(KERN_ERR PFX "%s: PAUSE_OPCODE = 0x%.08x.\n", qdev->ndev->name,
-	       data);
-	ql_read_xgmac_reg(qdev, PAUSE_TIMER, &data);
-	printk(KERN_ERR PFX "%s: PAUSE_TIMER = 0x%.08x.\n", qdev->ndev->name,
-	       data);
-	ql_read_xgmac_reg(qdev, PAUSE_FRM_DEST_LO, &data);
-	printk(KERN_ERR PFX "%s: PAUSE_FRM_DEST_LO = 0x%.08x.\n",
-	       qdev->ndev->name, data);
-	ql_read_xgmac_reg(qdev, PAUSE_FRM_DEST_HI, &data);
-	printk(KERN_ERR PFX "%s: PAUSE_FRM_DEST_HI = 0x%.08x.\n",
-	       qdev->ndev->name, data);
-	ql_read_xgmac_reg(qdev, MAC_TX_PARAMS, &data);
-	printk(KERN_ERR PFX "%s: MAC_TX_PARAMS = 0x%.08x.\n", qdev->ndev->name,
-	       data);
-	ql_read_xgmac_reg(qdev, MAC_RX_PARAMS, &data);
-	printk(KERN_ERR PFX "%s: MAC_RX_PARAMS = 0x%.08x.\n", qdev->ndev->name,
-	       data);
-	ql_read_xgmac_reg(qdev, MAC_SYS_INT, &data);
-	printk(KERN_ERR PFX "%s: MAC_SYS_INT = 0x%.08x.\n", qdev->ndev->name,
-	       data);
-	ql_read_xgmac_reg(qdev, MAC_SYS_INT_MASK, &data);
-	printk(KERN_ERR PFX "%s: MAC_SYS_INT_MASK = 0x%.08x.\n",
-	       qdev->ndev->name, data);
-	ql_read_xgmac_reg(qdev, MAC_MGMT_INT, &data);
-	printk(KERN_ERR PFX "%s: MAC_MGMT_INT = 0x%.08x.\n", qdev->ndev->name,
-	       data);
-	ql_read_xgmac_reg(qdev, MAC_MGMT_IN_MASK, &data);
-	printk(KERN_ERR PFX "%s: MAC_MGMT_IN_MASK = 0x%.08x.\n",
-	       qdev->ndev->name, data);
-	ql_read_xgmac_reg(qdev, EXT_ARB_MODE, &data);
-	printk(KERN_ERR PFX "%s: EXT_ARB_MODE = 0x%.08x.\n", qdev->ndev->name,
-	       data);
+	DUMP_XGMAC(qdev, PAUSE_SRC_LO);
+	DUMP_XGMAC(qdev, PAUSE_SRC_HI);
+	DUMP_XGMAC(qdev, GLOBAL_CFG);
+	DUMP_XGMAC(qdev, TX_CFG);
+	DUMP_XGMAC(qdev, RX_CFG);
+	DUMP_XGMAC(qdev, FLOW_CTL);
+	DUMP_XGMAC(qdev, PAUSE_OPCODE);
+	DUMP_XGMAC(qdev, PAUSE_TIMER);
+	DUMP_XGMAC(qdev, PAUSE_FRM_DEST_LO);
+	DUMP_XGMAC(qdev, PAUSE_FRM_DEST_HI);
+	DUMP_XGMAC(qdev, MAC_TX_PARAMS);
+	DUMP_XGMAC(qdev, MAC_RX_PARAMS);
+	DUMP_XGMAC(qdev, MAC_SYS_INT);
+	DUMP_XGMAC(qdev, MAC_SYS_INT_MASK);
+	DUMP_XGMAC(qdev, MAC_MGMT_INT);
+	DUMP_XGMAC(qdev, MAC_MGMT_IN_MASK);
+	DUMP_XGMAC(qdev, EXT_ARB_MODE);
 	ql_sem_unlock(qdev, qdev->xg_sem_mask);
-
 }
 
 static void ql_dump_ets_regs(struct ql_adapter *qdev)
@@ -1442,14 +1411,12 @@
 		return;
 	for (i = 0; i < 4; i++) {
 		if (ql_get_mac_addr_reg(qdev, MAC_ADDR_TYPE_CAM_MAC, i, value)) {
-			printk(KERN_ERR PFX
-			       "%s: Failed read of mac index register.\n",
+			pr_err("%s: Failed read of mac index register\n",
 			       __func__);
 			return;
 		} else {
 			if (value[0])
-				printk(KERN_ERR PFX
-				       "%s: CAM index %d CAM Lookup Lower = 0x%.08x:%.08x, Output = 0x%.08x.\n",
+				pr_err("%s: CAM index %d CAM Lookup Lower = 0x%.08x:%.08x, Output = 0x%.08x\n",
 				       qdev->ndev->name, i, value[1], value[0],
 				       value[2]);
 		}
@@ -1457,14 +1424,12 @@
 	for (i = 0; i < 32; i++) {
 		if (ql_get_mac_addr_reg
 		    (qdev, MAC_ADDR_TYPE_MULTI_MAC, i, value)) {
-			printk(KERN_ERR PFX
-			       "%s: Failed read of mac index register.\n",
+			pr_err("%s: Failed read of mac index register\n",
 			       __func__);
 			return;
 		} else {
 			if (value[0])
-				printk(KERN_ERR PFX
-				       "%s: MCAST index %d CAM Lookup Lower = 0x%.08x:%.08x.\n",
+				pr_err("%s: MCAST index %d CAM Lookup Lower = 0x%.08x:%.08x\n",
 				       qdev->ndev->name, i, value[1], value[0]);
 		}
 	}
@@ -1481,129 +1446,77 @@
 	for (i = 0; i < 16; i++) {
 		value = 0;
 		if (ql_get_routing_reg(qdev, i, &value)) {
-			printk(KERN_ERR PFX
-			       "%s: Failed read of routing index register.\n",
+			pr_err("%s: Failed read of routing index register\n",
 			       __func__);
 			return;
 		} else {
 			if (value)
-				printk(KERN_ERR PFX
-				       "%s: Routing Mask %d = 0x%.08x.\n",
+				pr_err("%s: Routing Mask %d = 0x%.08x\n",
 				       qdev->ndev->name, i, value);
 		}
 	}
 	ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
 }
 
+#define DUMP_REG(qdev, reg)			\
+	pr_err("%-32s= 0x%x\n", #reg, ql_read32(qdev, reg))
+
 void ql_dump_regs(struct ql_adapter *qdev)
 {
-	printk(KERN_ERR PFX "reg dump for function #%d.\n", qdev->func);
-	printk(KERN_ERR PFX "SYS	 			= 0x%x.\n",
-	       ql_read32(qdev, SYS));
-	printk(KERN_ERR PFX "RST_FO 			= 0x%x.\n",
-	       ql_read32(qdev, RST_FO));
-	printk(KERN_ERR PFX "FSC 				= 0x%x.\n",
-	       ql_read32(qdev, FSC));
-	printk(KERN_ERR PFX "CSR 				= 0x%x.\n",
-	       ql_read32(qdev, CSR));
-	printk(KERN_ERR PFX "ICB_RID 			= 0x%x.\n",
-	       ql_read32(qdev, ICB_RID));
-	printk(KERN_ERR PFX "ICB_L 				= 0x%x.\n",
-	       ql_read32(qdev, ICB_L));
-	printk(KERN_ERR PFX "ICB_H 				= 0x%x.\n",
-	       ql_read32(qdev, ICB_H));
-	printk(KERN_ERR PFX "CFG 				= 0x%x.\n",
-	       ql_read32(qdev, CFG));
-	printk(KERN_ERR PFX "BIOS_ADDR 			= 0x%x.\n",
-	       ql_read32(qdev, BIOS_ADDR));
-	printk(KERN_ERR PFX "STS 				= 0x%x.\n",
-	       ql_read32(qdev, STS));
-	printk(KERN_ERR PFX "INTR_EN			= 0x%x.\n",
-	       ql_read32(qdev, INTR_EN));
-	printk(KERN_ERR PFX "INTR_MASK 			= 0x%x.\n",
-	       ql_read32(qdev, INTR_MASK));
-	printk(KERN_ERR PFX "ISR1 				= 0x%x.\n",
-	       ql_read32(qdev, ISR1));
-	printk(KERN_ERR PFX "ISR2 				= 0x%x.\n",
-	       ql_read32(qdev, ISR2));
-	printk(KERN_ERR PFX "ISR3 				= 0x%x.\n",
-	       ql_read32(qdev, ISR3));
-	printk(KERN_ERR PFX "ISR4 				= 0x%x.\n",
-	       ql_read32(qdev, ISR4));
-	printk(KERN_ERR PFX "REV_ID 			= 0x%x.\n",
-	       ql_read32(qdev, REV_ID));
-	printk(KERN_ERR PFX "FRC_ECC_ERR 			= 0x%x.\n",
-	       ql_read32(qdev, FRC_ECC_ERR));
-	printk(KERN_ERR PFX "ERR_STS 			= 0x%x.\n",
-	       ql_read32(qdev, ERR_STS));
-	printk(KERN_ERR PFX "RAM_DBG_ADDR 			= 0x%x.\n",
-	       ql_read32(qdev, RAM_DBG_ADDR));
-	printk(KERN_ERR PFX "RAM_DBG_DATA 			= 0x%x.\n",
-	       ql_read32(qdev, RAM_DBG_DATA));
-	printk(KERN_ERR PFX "ECC_ERR_CNT 			= 0x%x.\n",
-	       ql_read32(qdev, ECC_ERR_CNT));
-	printk(KERN_ERR PFX "SEM 				= 0x%x.\n",
-	       ql_read32(qdev, SEM));
-	printk(KERN_ERR PFX "GPIO_1 			= 0x%x.\n",
-	       ql_read32(qdev, GPIO_1));
-	printk(KERN_ERR PFX "GPIO_2 			= 0x%x.\n",
-	       ql_read32(qdev, GPIO_2));
-	printk(KERN_ERR PFX "GPIO_3 			= 0x%x.\n",
-	       ql_read32(qdev, GPIO_3));
-	printk(KERN_ERR PFX "XGMAC_ADDR 			= 0x%x.\n",
-	       ql_read32(qdev, XGMAC_ADDR));
-	printk(KERN_ERR PFX "XGMAC_DATA 			= 0x%x.\n",
-	       ql_read32(qdev, XGMAC_DATA));
-	printk(KERN_ERR PFX "NIC_ETS 			= 0x%x.\n",
-	       ql_read32(qdev, NIC_ETS));
-	printk(KERN_ERR PFX "CNA_ETS 			= 0x%x.\n",
-	       ql_read32(qdev, CNA_ETS));
-	printk(KERN_ERR PFX "FLASH_ADDR 			= 0x%x.\n",
-	       ql_read32(qdev, FLASH_ADDR));
-	printk(KERN_ERR PFX "FLASH_DATA 			= 0x%x.\n",
-	       ql_read32(qdev, FLASH_DATA));
-	printk(KERN_ERR PFX "CQ_STOP 			= 0x%x.\n",
-	       ql_read32(qdev, CQ_STOP));
-	printk(KERN_ERR PFX "PAGE_TBL_RID 			= 0x%x.\n",
-	       ql_read32(qdev, PAGE_TBL_RID));
-	printk(KERN_ERR PFX "WQ_PAGE_TBL_LO 		= 0x%x.\n",
-	       ql_read32(qdev, WQ_PAGE_TBL_LO));
-	printk(KERN_ERR PFX "WQ_PAGE_TBL_HI 		= 0x%x.\n",
-	       ql_read32(qdev, WQ_PAGE_TBL_HI));
-	printk(KERN_ERR PFX "CQ_PAGE_TBL_LO 		= 0x%x.\n",
-	       ql_read32(qdev, CQ_PAGE_TBL_LO));
-	printk(KERN_ERR PFX "CQ_PAGE_TBL_HI 		= 0x%x.\n",
-	       ql_read32(qdev, CQ_PAGE_TBL_HI));
-	printk(KERN_ERR PFX "COS_DFLT_CQ1 			= 0x%x.\n",
-	       ql_read32(qdev, COS_DFLT_CQ1));
-	printk(KERN_ERR PFX "COS_DFLT_CQ2 			= 0x%x.\n",
-	       ql_read32(qdev, COS_DFLT_CQ2));
-	printk(KERN_ERR PFX "SPLT_HDR 			= 0x%x.\n",
-	       ql_read32(qdev, SPLT_HDR));
-	printk(KERN_ERR PFX "FC_PAUSE_THRES 		= 0x%x.\n",
-	       ql_read32(qdev, FC_PAUSE_THRES));
-	printk(KERN_ERR PFX "NIC_PAUSE_THRES 		= 0x%x.\n",
-	       ql_read32(qdev, NIC_PAUSE_THRES));
-	printk(KERN_ERR PFX "FC_ETHERTYPE 			= 0x%x.\n",
-	       ql_read32(qdev, FC_ETHERTYPE));
-	printk(KERN_ERR PFX "FC_RCV_CFG 			= 0x%x.\n",
-	       ql_read32(qdev, FC_RCV_CFG));
-	printk(KERN_ERR PFX "NIC_RCV_CFG 			= 0x%x.\n",
-	       ql_read32(qdev, NIC_RCV_CFG));
-	printk(KERN_ERR PFX "FC_COS_TAGS 			= 0x%x.\n",
-	       ql_read32(qdev, FC_COS_TAGS));
-	printk(KERN_ERR PFX "NIC_COS_TAGS 			= 0x%x.\n",
-	       ql_read32(qdev, NIC_COS_TAGS));
-	printk(KERN_ERR PFX "MGMT_RCV_CFG 			= 0x%x.\n",
-	       ql_read32(qdev, MGMT_RCV_CFG));
-	printk(KERN_ERR PFX "XG_SERDES_ADDR 		= 0x%x.\n",
-	       ql_read32(qdev, XG_SERDES_ADDR));
-	printk(KERN_ERR PFX "XG_SERDES_DATA 		= 0x%x.\n",
-	       ql_read32(qdev, XG_SERDES_DATA));
-	printk(KERN_ERR PFX "PRB_MX_ADDR 			= 0x%x.\n",
-	       ql_read32(qdev, PRB_MX_ADDR));
-	printk(KERN_ERR PFX "PRB_MX_DATA 			= 0x%x.\n",
-	       ql_read32(qdev, PRB_MX_DATA));
+	pr_err("reg dump for function #%d\n", qdev->func);
+	DUMP_REG(qdev, SYS);
+	DUMP_REG(qdev, RST_FO);
+	DUMP_REG(qdev, FSC);
+	DUMP_REG(qdev, CSR);
+	DUMP_REG(qdev, ICB_RID);
+	DUMP_REG(qdev, ICB_L);
+	DUMP_REG(qdev, ICB_H);
+	DUMP_REG(qdev, CFG);
+	DUMP_REG(qdev, BIOS_ADDR);
+	DUMP_REG(qdev, STS);
+	DUMP_REG(qdev, INTR_EN);
+	DUMP_REG(qdev, INTR_MASK);
+	DUMP_REG(qdev, ISR1);
+	DUMP_REG(qdev, ISR2);
+	DUMP_REG(qdev, ISR3);
+	DUMP_REG(qdev, ISR4);
+	DUMP_REG(qdev, REV_ID);
+	DUMP_REG(qdev, FRC_ECC_ERR);
+	DUMP_REG(qdev, ERR_STS);
+	DUMP_REG(qdev, RAM_DBG_ADDR);
+	DUMP_REG(qdev, RAM_DBG_DATA);
+	DUMP_REG(qdev, ECC_ERR_CNT);
+	DUMP_REG(qdev, SEM);
+	DUMP_REG(qdev, GPIO_1);
+	DUMP_REG(qdev, GPIO_2);
+	DUMP_REG(qdev, GPIO_3);
+	DUMP_REG(qdev, XGMAC_ADDR);
+	DUMP_REG(qdev, XGMAC_DATA);
+	DUMP_REG(qdev, NIC_ETS);
+	DUMP_REG(qdev, CNA_ETS);
+	DUMP_REG(qdev, FLASH_ADDR);
+	DUMP_REG(qdev, FLASH_DATA);
+	DUMP_REG(qdev, CQ_STOP);
+	DUMP_REG(qdev, PAGE_TBL_RID);
+	DUMP_REG(qdev, WQ_PAGE_TBL_LO);
+	DUMP_REG(qdev, WQ_PAGE_TBL_HI);
+	DUMP_REG(qdev, CQ_PAGE_TBL_LO);
+	DUMP_REG(qdev, CQ_PAGE_TBL_HI);
+	DUMP_REG(qdev, COS_DFLT_CQ1);
+	DUMP_REG(qdev, COS_DFLT_CQ2);
+	DUMP_REG(qdev, SPLT_HDR);
+	DUMP_REG(qdev, FC_PAUSE_THRES);
+	DUMP_REG(qdev, NIC_PAUSE_THRES);
+	DUMP_REG(qdev, FC_ETHERTYPE);
+	DUMP_REG(qdev, FC_RCV_CFG);
+	DUMP_REG(qdev, NIC_RCV_CFG);
+	DUMP_REG(qdev, FC_COS_TAGS);
+	DUMP_REG(qdev, NIC_COS_TAGS);
+	DUMP_REG(qdev, MGMT_RCV_CFG);
+	DUMP_REG(qdev, XG_SERDES_ADDR);
+	DUMP_REG(qdev, XG_SERDES_DATA);
+	DUMP_REG(qdev, PRB_MX_ADDR);
+	DUMP_REG(qdev, PRB_MX_DATA);
 	ql_dump_intr_states(qdev);
 	ql_dump_xgmac_control_regs(qdev);
 	ql_dump_ets_regs(qdev);
@@ -1613,191 +1526,124 @@
 #endif
 
 #ifdef QL_STAT_DUMP
+
+#define DUMP_STAT(qdev, stat)	\
+	pr_err("%s = %ld\n", #stat, (unsigned long)qdev->nic_stats.stat)
+
 void ql_dump_stat(struct ql_adapter *qdev)
 {
-	printk(KERN_ERR "%s: Enter.\n", __func__);
-	printk(KERN_ERR "tx_pkts = %ld\n",
-	       (unsigned long)qdev->nic_stats.tx_pkts);
-	printk(KERN_ERR "tx_bytes = %ld\n",
-	       (unsigned long)qdev->nic_stats.tx_bytes);
-	printk(KERN_ERR "tx_mcast_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_mcast_pkts);
-	printk(KERN_ERR "tx_bcast_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_bcast_pkts);
-	printk(KERN_ERR "tx_ucast_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_ucast_pkts);
-	printk(KERN_ERR "tx_ctl_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_ctl_pkts);
-	printk(KERN_ERR "tx_pause_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_pause_pkts);
-	printk(KERN_ERR "tx_64_pkt = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_64_pkt);
-	printk(KERN_ERR "tx_65_to_127_pkt = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_65_to_127_pkt);
-	printk(KERN_ERR "tx_128_to_255_pkt = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_128_to_255_pkt);
-	printk(KERN_ERR "tx_256_511_pkt = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_256_511_pkt);
-	printk(KERN_ERR "tx_512_to_1023_pkt = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_512_to_1023_pkt);
-	printk(KERN_ERR "tx_1024_to_1518_pkt = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_1024_to_1518_pkt);
-	printk(KERN_ERR "tx_1519_to_max_pkt = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_1519_to_max_pkt);
-	printk(KERN_ERR "tx_undersize_pkt = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_undersize_pkt);
-	printk(KERN_ERR "tx_oversize_pkt = %ld.\n",
-	       (unsigned long)qdev->nic_stats.tx_oversize_pkt);
-	printk(KERN_ERR "rx_bytes = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_bytes);
-	printk(KERN_ERR "rx_bytes_ok = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_bytes_ok);
-	printk(KERN_ERR "rx_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_pkts);
-	printk(KERN_ERR "rx_pkts_ok = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_pkts_ok);
-	printk(KERN_ERR "rx_bcast_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_bcast_pkts);
-	printk(KERN_ERR "rx_mcast_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_mcast_pkts);
-	printk(KERN_ERR "rx_ucast_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_ucast_pkts);
-	printk(KERN_ERR "rx_undersize_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_undersize_pkts);
-	printk(KERN_ERR "rx_oversize_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_oversize_pkts);
-	printk(KERN_ERR "rx_jabber_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_jabber_pkts);
-	printk(KERN_ERR "rx_undersize_fcerr_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_undersize_fcerr_pkts);
-	printk(KERN_ERR "rx_drop_events = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_drop_events);
-	printk(KERN_ERR "rx_fcerr_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_fcerr_pkts);
-	printk(KERN_ERR "rx_align_err = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_align_err);
-	printk(KERN_ERR "rx_symbol_err = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_symbol_err);
-	printk(KERN_ERR "rx_mac_err = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_mac_err);
-	printk(KERN_ERR "rx_ctl_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_ctl_pkts);
-	printk(KERN_ERR "rx_pause_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_pause_pkts);
-	printk(KERN_ERR "rx_64_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_64_pkts);
-	printk(KERN_ERR "rx_65_to_127_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_65_to_127_pkts);
-	printk(KERN_ERR "rx_128_255_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_128_255_pkts);
-	printk(KERN_ERR "rx_256_511_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_256_511_pkts);
-	printk(KERN_ERR "rx_512_to_1023_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_512_to_1023_pkts);
-	printk(KERN_ERR "rx_1024_to_1518_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_1024_to_1518_pkts);
-	printk(KERN_ERR "rx_1519_to_max_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_1519_to_max_pkts);
-	printk(KERN_ERR "rx_len_err_pkts = %ld.\n",
-	       (unsigned long)qdev->nic_stats.rx_len_err_pkts);
+	pr_err("%s: Enter\n", __func__);
+	DUMP_STAT(qdev, tx_pkts);
+	DUMP_STAT(qdev, tx_bytes);
+	DUMP_STAT(qdev, tx_mcast_pkts);
+	DUMP_STAT(qdev, tx_bcast_pkts);
+	DUMP_STAT(qdev, tx_ucast_pkts);
+	DUMP_STAT(qdev, tx_ctl_pkts);
+	DUMP_STAT(qdev, tx_pause_pkts);
+	DUMP_STAT(qdev, tx_64_pkt);
+	DUMP_STAT(qdev, tx_65_to_127_pkt);
+	DUMP_STAT(qdev, tx_128_to_255_pkt);
+	DUMP_STAT(qdev, tx_256_511_pkt);
+	DUMP_STAT(qdev, tx_512_to_1023_pkt);
+	DUMP_STAT(qdev, tx_1024_to_1518_pkt);
+	DUMP_STAT(qdev, tx_1519_to_max_pkt);
+	DUMP_STAT(qdev, tx_undersize_pkt);
+	DUMP_STAT(qdev, tx_oversize_pkt);
+	DUMP_STAT(qdev, rx_bytes);
+	DUMP_STAT(qdev, rx_bytes_ok);
+	DUMP_STAT(qdev, rx_pkts);
+	DUMP_STAT(qdev, rx_pkts_ok);
+	DUMP_STAT(qdev, rx_bcast_pkts);
+	DUMP_STAT(qdev, rx_mcast_pkts);
+	DUMP_STAT(qdev, rx_ucast_pkts);
+	DUMP_STAT(qdev, rx_undersize_pkts);
+	DUMP_STAT(qdev, rx_oversize_pkts);
+	DUMP_STAT(qdev, rx_jabber_pkts);
+	DUMP_STAT(qdev, rx_undersize_fcerr_pkts);
+	DUMP_STAT(qdev, rx_drop_events);
+	DUMP_STAT(qdev, rx_fcerr_pkts);
+	DUMP_STAT(qdev, rx_align_err);
+	DUMP_STAT(qdev, rx_symbol_err);
+	DUMP_STAT(qdev, rx_mac_err);
+	DUMP_STAT(qdev, rx_ctl_pkts);
+	DUMP_STAT(qdev, rx_pause_pkts);
+	DUMP_STAT(qdev, rx_64_pkts);
+	DUMP_STAT(qdev, rx_65_to_127_pkts);
+	DUMP_STAT(qdev, rx_128_255_pkts);
+	DUMP_STAT(qdev, rx_256_511_pkts);
+	DUMP_STAT(qdev, rx_512_to_1023_pkts);
+	DUMP_STAT(qdev, rx_1024_to_1518_pkts);
+	DUMP_STAT(qdev, rx_1519_to_max_pkts);
+	DUMP_STAT(qdev, rx_len_err_pkts);
 };
 #endif
 
 #ifdef QL_DEV_DUMP
+
+#define DUMP_QDEV_FIELD(qdev, type, field)		\
+	pr_err("qdev->%-24s = " type "\n", #field, qdev->field)
+#define DUMP_QDEV_DMA_FIELD(qdev, field)		\
+	pr_err("qdev->%-24s = %llx\n", #field, (unsigned long long)qdev->field)
+#define DUMP_QDEV_ARRAY(qdev, type, array, index, field) \
+	pr_err("%s[%d].%s = " type "\n",		 \
+	       #array, index, #field, qdev->array[index].field);
 void ql_dump_qdev(struct ql_adapter *qdev)
 {
 	int i;
-	printk(KERN_ERR PFX "qdev->flags 			= %lx.\n",
-	       qdev->flags);
-	printk(KERN_ERR PFX "qdev->vlgrp 			= %p.\n",
-	       qdev->vlgrp);
-	printk(KERN_ERR PFX "qdev->pdev 			= %p.\n",
-	       qdev->pdev);
-	printk(KERN_ERR PFX "qdev->ndev 			= %p.\n",
-	       qdev->ndev);
-	printk(KERN_ERR PFX "qdev->chip_rev_id 		= %d.\n",
-	       qdev->chip_rev_id);
-	printk(KERN_ERR PFX "qdev->reg_base 		= %p.\n",
-	       qdev->reg_base);
-	printk(KERN_ERR PFX "qdev->doorbell_area 	= %p.\n",
-	       qdev->doorbell_area);
-	printk(KERN_ERR PFX "qdev->doorbell_area_size 	= %d.\n",
-	       qdev->doorbell_area_size);
-	printk(KERN_ERR PFX "msg_enable 		= %x.\n",
-	       qdev->msg_enable);
-	printk(KERN_ERR PFX "qdev->rx_ring_shadow_reg_area	= %p.\n",
-	       qdev->rx_ring_shadow_reg_area);
-	printk(KERN_ERR PFX "qdev->rx_ring_shadow_reg_dma 	= %llx.\n",
-	       (unsigned long long) qdev->rx_ring_shadow_reg_dma);
-	printk(KERN_ERR PFX "qdev->tx_ring_shadow_reg_area	= %p.\n",
-	       qdev->tx_ring_shadow_reg_area);
-	printk(KERN_ERR PFX "qdev->tx_ring_shadow_reg_dma	= %llx.\n",
-	       (unsigned long long) qdev->tx_ring_shadow_reg_dma);
-	printk(KERN_ERR PFX "qdev->intr_count 		= %d.\n",
-	       qdev->intr_count);
+	DUMP_QDEV_FIELD(qdev, "%lx", flags);
+	DUMP_QDEV_FIELD(qdev, "%p", vlgrp);
+	DUMP_QDEV_FIELD(qdev, "%p", pdev);
+	DUMP_QDEV_FIELD(qdev, "%p", ndev);
+	DUMP_QDEV_FIELD(qdev, "%d", chip_rev_id);
+	DUMP_QDEV_FIELD(qdev, "%p", reg_base);
+	DUMP_QDEV_FIELD(qdev, "%p", doorbell_area);
+	DUMP_QDEV_FIELD(qdev, "%d", doorbell_area_size);
+	DUMP_QDEV_FIELD(qdev, "%x", msg_enable);
+	DUMP_QDEV_FIELD(qdev, "%p", rx_ring_shadow_reg_area);
+	DUMP_QDEV_DMA_FIELD(qdev, rx_ring_shadow_reg_dma);
+	DUMP_QDEV_FIELD(qdev, "%p", tx_ring_shadow_reg_area);
+	DUMP_QDEV_DMA_FIELD(qdev, tx_ring_shadow_reg_dma);
+	DUMP_QDEV_FIELD(qdev, "%d", intr_count);
 	if (qdev->msi_x_entry)
 		for (i = 0; i < qdev->intr_count; i++) {
-			printk(KERN_ERR PFX
-			       "msi_x_entry.[%d]vector	= %d.\n", i,
-			       qdev->msi_x_entry[i].vector);
-			printk(KERN_ERR PFX
-			       "msi_x_entry.[%d]entry	= %d.\n", i,
-			       qdev->msi_x_entry[i].entry);
+			DUMP_QDEV_ARRAY(qdev, "%d", msi_x_entry, i, vector);
+			DUMP_QDEV_ARRAY(qdev, "%d", msi_x_entry, i, entry);
 		}
 	for (i = 0; i < qdev->intr_count; i++) {
-		printk(KERN_ERR PFX
-		       "intr_context[%d].qdev		= %p.\n", i,
-		       qdev->intr_context[i].qdev);
-		printk(KERN_ERR PFX
-		       "intr_context[%d].intr		= %d.\n", i,
-		       qdev->intr_context[i].intr);
-		printk(KERN_ERR PFX
-		       "intr_context[%d].hooked		= %d.\n", i,
-		       qdev->intr_context[i].hooked);
-		printk(KERN_ERR PFX
-		       "intr_context[%d].intr_en_mask	= 0x%08x.\n", i,
-		       qdev->intr_context[i].intr_en_mask);
-		printk(KERN_ERR PFX
-		       "intr_context[%d].intr_dis_mask	= 0x%08x.\n", i,
-		       qdev->intr_context[i].intr_dis_mask);
-		printk(KERN_ERR PFX
-		       "intr_context[%d].intr_read_mask	= 0x%08x.\n", i,
-		       qdev->intr_context[i].intr_read_mask);
+		DUMP_QDEV_ARRAY(qdev, "%p", intr_context, i, qdev);
+		DUMP_QDEV_ARRAY(qdev, "%d", intr_context, i, intr);
+		DUMP_QDEV_ARRAY(qdev, "%d", intr_context, i, hooked);
+		DUMP_QDEV_ARRAY(qdev, "0x%08x", intr_context, i, intr_en_mask);
+		DUMP_QDEV_ARRAY(qdev, "0x%08x", intr_context, i, intr_dis_mask);
+		DUMP_QDEV_ARRAY(qdev, "0x%08x", intr_context, i, intr_read_mask);
 	}
-	printk(KERN_ERR PFX "qdev->tx_ring_count = %d.\n", qdev->tx_ring_count);
-	printk(KERN_ERR PFX "qdev->rx_ring_count = %d.\n", qdev->rx_ring_count);
-	printk(KERN_ERR PFX "qdev->ring_mem_size = %d.\n", qdev->ring_mem_size);
-	printk(KERN_ERR PFX "qdev->ring_mem 	= %p.\n", qdev->ring_mem);
-	printk(KERN_ERR PFX "qdev->intr_count 	= %d.\n", qdev->intr_count);
-	printk(KERN_ERR PFX "qdev->tx_ring		= %p.\n",
-	       qdev->tx_ring);
-	printk(KERN_ERR PFX "qdev->rss_ring_count 	= %d.\n",
-	       qdev->rss_ring_count);
-	printk(KERN_ERR PFX "qdev->rx_ring	= %p.\n", qdev->rx_ring);
-	printk(KERN_ERR PFX "qdev->default_rx_queue	= %d.\n",
-	       qdev->default_rx_queue);
-	printk(KERN_ERR PFX "qdev->xg_sem_mask		= 0x%08x.\n",
-	       qdev->xg_sem_mask);
-	printk(KERN_ERR PFX "qdev->port_link_up		= 0x%08x.\n",
-	       qdev->port_link_up);
-	printk(KERN_ERR PFX "qdev->port_init		= 0x%08x.\n",
-	       qdev->port_init);
-
+	DUMP_QDEV_FIELD(qdev, "%d", tx_ring_count);
+	DUMP_QDEV_FIELD(qdev, "%d", rx_ring_count);
+	DUMP_QDEV_FIELD(qdev, "%d", ring_mem_size);
+	DUMP_QDEV_FIELD(qdev, "%p", ring_mem);
+	DUMP_QDEV_FIELD(qdev, "%d", intr_count);
+	DUMP_QDEV_FIELD(qdev, "%p", tx_ring);
+	DUMP_QDEV_FIELD(qdev, "%d", rss_ring_count);
+	DUMP_QDEV_FIELD(qdev, "%p", rx_ring);
+	DUMP_QDEV_FIELD(qdev, "%d", default_rx_queue);
+	DUMP_QDEV_FIELD(qdev, "0x%08x", xg_sem_mask);
+	DUMP_QDEV_FIELD(qdev, "0x%08x", port_link_up);
+	DUMP_QDEV_FIELD(qdev, "0x%08x", port_init);
 }
 #endif
 
 #ifdef QL_CB_DUMP
 void ql_dump_wqicb(struct wqicb *wqicb)
 {
-	printk(KERN_ERR PFX "Dumping wqicb stuff...\n");
-	printk(KERN_ERR PFX "wqicb->len = 0x%x.\n", le16_to_cpu(wqicb->len));
-	printk(KERN_ERR PFX "wqicb->flags = %x.\n", le16_to_cpu(wqicb->flags));
-	printk(KERN_ERR PFX "wqicb->cq_id_rss = %d.\n",
+	pr_err("Dumping wqicb stuff...\n");
+	pr_err("wqicb->len = 0x%x\n", le16_to_cpu(wqicb->len));
+	pr_err("wqicb->flags = %x\n", le16_to_cpu(wqicb->flags));
+	pr_err("wqicb->cq_id_rss = %d\n",
 	       le16_to_cpu(wqicb->cq_id_rss));
-	printk(KERN_ERR PFX "wqicb->rid = 0x%x.\n", le16_to_cpu(wqicb->rid));
-	printk(KERN_ERR PFX "wqicb->wq_addr = 0x%llx.\n",
+	pr_err("wqicb->rid = 0x%x\n", le16_to_cpu(wqicb->rid));
+	pr_err("wqicb->wq_addr = 0x%llx\n",
 	       (unsigned long long) le64_to_cpu(wqicb->addr));
-	printk(KERN_ERR PFX "wqicb->wq_cnsmr_idx_addr = 0x%llx.\n",
+	pr_err("wqicb->wq_cnsmr_idx_addr = 0x%llx\n",
 	       (unsigned long long) le64_to_cpu(wqicb->cnsmr_idx_addr));
 }
 
@@ -1805,40 +1651,34 @@
 {
 	if (tx_ring == NULL)
 		return;
-	printk(KERN_ERR PFX
-	       "===================== Dumping tx_ring %d ===============.\n",
+	pr_err("===================== Dumping tx_ring %d ===============\n",
 	       tx_ring->wq_id);
-	printk(KERN_ERR PFX "tx_ring->base = %p.\n", tx_ring->wq_base);
-	printk(KERN_ERR PFX "tx_ring->base_dma = 0x%llx.\n",
+	pr_err("tx_ring->base = %p\n", tx_ring->wq_base);
+	pr_err("tx_ring->base_dma = 0x%llx\n",
 	       (unsigned long long) tx_ring->wq_base_dma);
-	printk(KERN_ERR PFX
-	       "tx_ring->cnsmr_idx_sh_reg, addr = 0x%p, value = %d.\n",
+	pr_err("tx_ring->cnsmr_idx_sh_reg, addr = 0x%p, value = %d\n",
 	       tx_ring->cnsmr_idx_sh_reg,
 	       tx_ring->cnsmr_idx_sh_reg
 			? ql_read_sh_reg(tx_ring->cnsmr_idx_sh_reg) : 0);
-	printk(KERN_ERR PFX "tx_ring->size = %d.\n", tx_ring->wq_size);
-	printk(KERN_ERR PFX "tx_ring->len = %d.\n", tx_ring->wq_len);
-	printk(KERN_ERR PFX "tx_ring->prod_idx_db_reg = %p.\n",
-	       tx_ring->prod_idx_db_reg);
-	printk(KERN_ERR PFX "tx_ring->valid_db_reg = %p.\n",
-	       tx_ring->valid_db_reg);
-	printk(KERN_ERR PFX "tx_ring->prod_idx = %d.\n", tx_ring->prod_idx);
-	printk(KERN_ERR PFX "tx_ring->cq_id = %d.\n", tx_ring->cq_id);
-	printk(KERN_ERR PFX "tx_ring->wq_id = %d.\n", tx_ring->wq_id);
-	printk(KERN_ERR PFX "tx_ring->q = %p.\n", tx_ring->q);
-	printk(KERN_ERR PFX "tx_ring->tx_count = %d.\n",
-	       atomic_read(&tx_ring->tx_count));
+	pr_err("tx_ring->size = %d\n", tx_ring->wq_size);
+	pr_err("tx_ring->len = %d\n", tx_ring->wq_len);
+	pr_err("tx_ring->prod_idx_db_reg = %p\n", tx_ring->prod_idx_db_reg);
+	pr_err("tx_ring->valid_db_reg = %p\n", tx_ring->valid_db_reg);
+	pr_err("tx_ring->prod_idx = %d\n", tx_ring->prod_idx);
+	pr_err("tx_ring->cq_id = %d\n", tx_ring->cq_id);
+	pr_err("tx_ring->wq_id = %d\n", tx_ring->wq_id);
+	pr_err("tx_ring->q = %p\n", tx_ring->q);
+	pr_err("tx_ring->tx_count = %d\n", atomic_read(&tx_ring->tx_count));
 }
 
 void ql_dump_ricb(struct ricb *ricb)
 {
 	int i;
-	printk(KERN_ERR PFX
-	       "===================== Dumping ricb ===============.\n");
-	printk(KERN_ERR PFX "Dumping ricb stuff...\n");
+	pr_err("===================== Dumping ricb ===============\n");
+	pr_err("Dumping ricb stuff...\n");
 
-	printk(KERN_ERR PFX "ricb->base_cq = %d.\n", ricb->base_cq & 0x1f);
-	printk(KERN_ERR PFX "ricb->flags = %s%s%s%s%s%s%s%s%s.\n",
+	pr_err("ricb->base_cq = %d\n", ricb->base_cq & 0x1f);
+	pr_err("ricb->flags = %s%s%s%s%s%s%s%s%s\n",
 	       ricb->base_cq & RSS_L4K ? "RSS_L4K " : "",
 	       ricb->flags & RSS_L6K ? "RSS_L6K " : "",
 	       ricb->flags & RSS_LI ? "RSS_LI " : "",
@@ -1848,44 +1688,44 @@
 	       ricb->flags & RSS_RT4 ? "RSS_RT4 " : "",
 	       ricb->flags & RSS_RI6 ? "RSS_RI6 " : "",
 	       ricb->flags & RSS_RT6 ? "RSS_RT6 " : "");
-	printk(KERN_ERR PFX "ricb->mask = 0x%.04x.\n", le16_to_cpu(ricb->mask));
+	pr_err("ricb->mask = 0x%.04x\n", le16_to_cpu(ricb->mask));
 	for (i = 0; i < 16; i++)
-		printk(KERN_ERR PFX "ricb->hash_cq_id[%d] = 0x%.08x.\n", i,
+		pr_err("ricb->hash_cq_id[%d] = 0x%.08x\n", i,
 		       le32_to_cpu(ricb->hash_cq_id[i]));
 	for (i = 0; i < 10; i++)
-		printk(KERN_ERR PFX "ricb->ipv6_hash_key[%d] = 0x%.08x.\n", i,
+		pr_err("ricb->ipv6_hash_key[%d] = 0x%.08x\n", i,
 		       le32_to_cpu(ricb->ipv6_hash_key[i]));
 	for (i = 0; i < 4; i++)
-		printk(KERN_ERR PFX "ricb->ipv4_hash_key[%d] = 0x%.08x.\n", i,
+		pr_err("ricb->ipv4_hash_key[%d] = 0x%.08x\n", i,
 		       le32_to_cpu(ricb->ipv4_hash_key[i]));
 }
 
 void ql_dump_cqicb(struct cqicb *cqicb)
 {
-	printk(KERN_ERR PFX "Dumping cqicb stuff...\n");
+	pr_err("Dumping cqicb stuff...\n");
 
-	printk(KERN_ERR PFX "cqicb->msix_vect = %d.\n", cqicb->msix_vect);
-	printk(KERN_ERR PFX "cqicb->flags = %x.\n", cqicb->flags);
-	printk(KERN_ERR PFX "cqicb->len = %d.\n", le16_to_cpu(cqicb->len));
-	printk(KERN_ERR PFX "cqicb->addr = 0x%llx.\n",
+	pr_err("cqicb->msix_vect = %d\n", cqicb->msix_vect);
+	pr_err("cqicb->flags = %x\n", cqicb->flags);
+	pr_err("cqicb->len = %d\n", le16_to_cpu(cqicb->len));
+	pr_err("cqicb->addr = 0x%llx\n",
 	       (unsigned long long) le64_to_cpu(cqicb->addr));
-	printk(KERN_ERR PFX "cqicb->prod_idx_addr = 0x%llx.\n",
+	pr_err("cqicb->prod_idx_addr = 0x%llx\n",
 	       (unsigned long long) le64_to_cpu(cqicb->prod_idx_addr));
-	printk(KERN_ERR PFX "cqicb->pkt_delay = 0x%.04x.\n",
+	pr_err("cqicb->pkt_delay = 0x%.04x\n",
 	       le16_to_cpu(cqicb->pkt_delay));
-	printk(KERN_ERR PFX "cqicb->irq_delay = 0x%.04x.\n",
+	pr_err("cqicb->irq_delay = 0x%.04x\n",
 	       le16_to_cpu(cqicb->irq_delay));
-	printk(KERN_ERR PFX "cqicb->lbq_addr = 0x%llx.\n",
+	pr_err("cqicb->lbq_addr = 0x%llx\n",
 	       (unsigned long long) le64_to_cpu(cqicb->lbq_addr));
-	printk(KERN_ERR PFX "cqicb->lbq_buf_size = 0x%.04x.\n",
+	pr_err("cqicb->lbq_buf_size = 0x%.04x\n",
 	       le16_to_cpu(cqicb->lbq_buf_size));
-	printk(KERN_ERR PFX "cqicb->lbq_len = 0x%.04x.\n",
+	pr_err("cqicb->lbq_len = 0x%.04x\n",
 	       le16_to_cpu(cqicb->lbq_len));
-	printk(KERN_ERR PFX "cqicb->sbq_addr = 0x%llx.\n",
+	pr_err("cqicb->sbq_addr = 0x%llx\n",
 	       (unsigned long long) le64_to_cpu(cqicb->sbq_addr));
-	printk(KERN_ERR PFX "cqicb->sbq_buf_size = 0x%.04x.\n",
+	pr_err("cqicb->sbq_buf_size = 0x%.04x\n",
 	       le16_to_cpu(cqicb->sbq_buf_size));
-	printk(KERN_ERR PFX "cqicb->sbq_len = 0x%.04x.\n",
+	pr_err("cqicb->sbq_len = 0x%.04x\n",
 	       le16_to_cpu(cqicb->sbq_len));
 }
 
@@ -1893,100 +1733,85 @@
 {
 	if (rx_ring == NULL)
 		return;
-	printk(KERN_ERR PFX
-	       "===================== Dumping rx_ring %d ===============.\n",
+	pr_err("===================== Dumping rx_ring %d ===============\n",
 	       rx_ring->cq_id);
-	printk(KERN_ERR PFX "Dumping rx_ring %d, type = %s%s%s.\n",
+	pr_err("Dumping rx_ring %d, type = %s%s%s\n",
 	       rx_ring->cq_id, rx_ring->type == DEFAULT_Q ? "DEFAULT" : "",
 	       rx_ring->type == TX_Q ? "OUTBOUND COMPLETIONS" : "",
 	       rx_ring->type == RX_Q ? "INBOUND_COMPLETIONS" : "");
-	printk(KERN_ERR PFX "rx_ring->cqicb = %p.\n", &rx_ring->cqicb);
-	printk(KERN_ERR PFX "rx_ring->cq_base = %p.\n", rx_ring->cq_base);
-	printk(KERN_ERR PFX "rx_ring->cq_base_dma = %llx.\n",
+	pr_err("rx_ring->cqicb = %p\n", &rx_ring->cqicb);
+	pr_err("rx_ring->cq_base = %p\n", rx_ring->cq_base);
+	pr_err("rx_ring->cq_base_dma = %llx\n",
 	       (unsigned long long) rx_ring->cq_base_dma);
-	printk(KERN_ERR PFX "rx_ring->cq_size = %d.\n", rx_ring->cq_size);
-	printk(KERN_ERR PFX "rx_ring->cq_len = %d.\n", rx_ring->cq_len);
-	printk(KERN_ERR PFX
-	       "rx_ring->prod_idx_sh_reg, addr = 0x%p, value = %d.\n",
+	pr_err("rx_ring->cq_size = %d\n", rx_ring->cq_size);
+	pr_err("rx_ring->cq_len = %d\n", rx_ring->cq_len);
+	pr_err("rx_ring->prod_idx_sh_reg, addr = 0x%p, value = %d\n",
 	       rx_ring->prod_idx_sh_reg,
 	       rx_ring->prod_idx_sh_reg
 			? ql_read_sh_reg(rx_ring->prod_idx_sh_reg) : 0);
-	printk(KERN_ERR PFX "rx_ring->prod_idx_sh_reg_dma = %llx.\n",
+	pr_err("rx_ring->prod_idx_sh_reg_dma = %llx\n",
 	       (unsigned long long) rx_ring->prod_idx_sh_reg_dma);
-	printk(KERN_ERR PFX "rx_ring->cnsmr_idx_db_reg = %p.\n",
+	pr_err("rx_ring->cnsmr_idx_db_reg = %p\n",
 	       rx_ring->cnsmr_idx_db_reg);
-	printk(KERN_ERR PFX "rx_ring->cnsmr_idx = %d.\n", rx_ring->cnsmr_idx);
-	printk(KERN_ERR PFX "rx_ring->curr_entry = %p.\n", rx_ring->curr_entry);
-	printk(KERN_ERR PFX "rx_ring->valid_db_reg = %p.\n",
-	       rx_ring->valid_db_reg);
+	pr_err("rx_ring->cnsmr_idx = %d\n", rx_ring->cnsmr_idx);
+	pr_err("rx_ring->curr_entry = %p\n", rx_ring->curr_entry);
+	pr_err("rx_ring->valid_db_reg = %p\n", rx_ring->valid_db_reg);
 
-	printk(KERN_ERR PFX "rx_ring->lbq_base = %p.\n", rx_ring->lbq_base);
-	printk(KERN_ERR PFX "rx_ring->lbq_base_dma = %llx.\n",
+	pr_err("rx_ring->lbq_base = %p\n", rx_ring->lbq_base);
+	pr_err("rx_ring->lbq_base_dma = %llx\n",
 	       (unsigned long long) rx_ring->lbq_base_dma);
-	printk(KERN_ERR PFX "rx_ring->lbq_base_indirect = %p.\n",
+	pr_err("rx_ring->lbq_base_indirect = %p\n",
 	       rx_ring->lbq_base_indirect);
-	printk(KERN_ERR PFX "rx_ring->lbq_base_indirect_dma = %llx.\n",
+	pr_err("rx_ring->lbq_base_indirect_dma = %llx\n",
 	       (unsigned long long) rx_ring->lbq_base_indirect_dma);
-	printk(KERN_ERR PFX "rx_ring->lbq = %p.\n", rx_ring->lbq);
-	printk(KERN_ERR PFX "rx_ring->lbq_len = %d.\n", rx_ring->lbq_len);
-	printk(KERN_ERR PFX "rx_ring->lbq_size = %d.\n", rx_ring->lbq_size);
-	printk(KERN_ERR PFX "rx_ring->lbq_prod_idx_db_reg = %p.\n",
+	pr_err("rx_ring->lbq = %p\n", rx_ring->lbq);
+	pr_err("rx_ring->lbq_len = %d\n", rx_ring->lbq_len);
+	pr_err("rx_ring->lbq_size = %d\n", rx_ring->lbq_size);
+	pr_err("rx_ring->lbq_prod_idx_db_reg = %p\n",
 	       rx_ring->lbq_prod_idx_db_reg);
-	printk(KERN_ERR PFX "rx_ring->lbq_prod_idx = %d.\n",
-	       rx_ring->lbq_prod_idx);
-	printk(KERN_ERR PFX "rx_ring->lbq_curr_idx = %d.\n",
-	       rx_ring->lbq_curr_idx);
-	printk(KERN_ERR PFX "rx_ring->lbq_clean_idx = %d.\n",
-	       rx_ring->lbq_clean_idx);
-	printk(KERN_ERR PFX "rx_ring->lbq_free_cnt = %d.\n",
-	       rx_ring->lbq_free_cnt);
-	printk(KERN_ERR PFX "rx_ring->lbq_buf_size = %d.\n",
-	       rx_ring->lbq_buf_size);
+	pr_err("rx_ring->lbq_prod_idx = %d\n", rx_ring->lbq_prod_idx);
+	pr_err("rx_ring->lbq_curr_idx = %d\n", rx_ring->lbq_curr_idx);
+	pr_err("rx_ring->lbq_clean_idx = %d\n", rx_ring->lbq_clean_idx);
+	pr_err("rx_ring->lbq_free_cnt = %d\n", rx_ring->lbq_free_cnt);
+	pr_err("rx_ring->lbq_buf_size = %d\n", rx_ring->lbq_buf_size);
 
-	printk(KERN_ERR PFX "rx_ring->sbq_base = %p.\n", rx_ring->sbq_base);
-	printk(KERN_ERR PFX "rx_ring->sbq_base_dma = %llx.\n",
+	pr_err("rx_ring->sbq_base = %p\n", rx_ring->sbq_base);
+	pr_err("rx_ring->sbq_base_dma = %llx\n",
 	       (unsigned long long) rx_ring->sbq_base_dma);
-	printk(KERN_ERR PFX "rx_ring->sbq_base_indirect = %p.\n",
+	pr_err("rx_ring->sbq_base_indirect = %p\n",
 	       rx_ring->sbq_base_indirect);
-	printk(KERN_ERR PFX "rx_ring->sbq_base_indirect_dma = %llx.\n",
+	pr_err("rx_ring->sbq_base_indirect_dma = %llx\n",
 	       (unsigned long long) rx_ring->sbq_base_indirect_dma);
-	printk(KERN_ERR PFX "rx_ring->sbq = %p.\n", rx_ring->sbq);
-	printk(KERN_ERR PFX "rx_ring->sbq_len = %d.\n", rx_ring->sbq_len);
-	printk(KERN_ERR PFX "rx_ring->sbq_size = %d.\n", rx_ring->sbq_size);
-	printk(KERN_ERR PFX "rx_ring->sbq_prod_idx_db_reg addr = %p.\n",
+	pr_err("rx_ring->sbq = %p\n", rx_ring->sbq);
+	pr_err("rx_ring->sbq_len = %d\n", rx_ring->sbq_len);
+	pr_err("rx_ring->sbq_size = %d\n", rx_ring->sbq_size);
+	pr_err("rx_ring->sbq_prod_idx_db_reg addr = %p\n",
 	       rx_ring->sbq_prod_idx_db_reg);
-	printk(KERN_ERR PFX "rx_ring->sbq_prod_idx = %d.\n",
-	       rx_ring->sbq_prod_idx);
-	printk(KERN_ERR PFX "rx_ring->sbq_curr_idx = %d.\n",
-	       rx_ring->sbq_curr_idx);
-	printk(KERN_ERR PFX "rx_ring->sbq_clean_idx = %d.\n",
-	       rx_ring->sbq_clean_idx);
-	printk(KERN_ERR PFX "rx_ring->sbq_free_cnt = %d.\n",
-	       rx_ring->sbq_free_cnt);
-	printk(KERN_ERR PFX "rx_ring->sbq_buf_size = %d.\n",
-	       rx_ring->sbq_buf_size);
-	printk(KERN_ERR PFX "rx_ring->cq_id = %d.\n", rx_ring->cq_id);
-	printk(KERN_ERR PFX "rx_ring->irq = %d.\n", rx_ring->irq);
-	printk(KERN_ERR PFX "rx_ring->cpu = %d.\n", rx_ring->cpu);
-	printk(KERN_ERR PFX "rx_ring->qdev = %p.\n", rx_ring->qdev);
+	pr_err("rx_ring->sbq_prod_idx = %d\n", rx_ring->sbq_prod_idx);
+	pr_err("rx_ring->sbq_curr_idx = %d\n", rx_ring->sbq_curr_idx);
+	pr_err("rx_ring->sbq_clean_idx = %d\n", rx_ring->sbq_clean_idx);
+	pr_err("rx_ring->sbq_free_cnt = %d\n", rx_ring->sbq_free_cnt);
+	pr_err("rx_ring->sbq_buf_size = %d\n", rx_ring->sbq_buf_size);
+	pr_err("rx_ring->cq_id = %d\n", rx_ring->cq_id);
+	pr_err("rx_ring->irq = %d\n", rx_ring->irq);
+	pr_err("rx_ring->cpu = %d\n", rx_ring->cpu);
+	pr_err("rx_ring->qdev = %p\n", rx_ring->qdev);
 }
 
 void ql_dump_hw_cb(struct ql_adapter *qdev, int size, u32 bit, u16 q_id)
 {
 	void *ptr;
 
-	printk(KERN_ERR PFX "%s: Enter.\n", __func__);
+	pr_err("%s: Enter\n", __func__);
 
 	ptr = kmalloc(size, GFP_ATOMIC);
 	if (ptr == NULL) {
-		printk(KERN_ERR PFX "%s: Couldn't allocate a buffer.\n",
-		       __func__);
+		pr_err("%s: Couldn't allocate a buffer\n", __func__);
 		return;
 	}
 
 	if (ql_write_cfg(qdev, ptr, size, bit, q_id)) {
-		printk(KERN_ERR "%s: Failed to upload control block!\n",
-		       __func__);
+		pr_err("%s: Failed to upload control block!\n", __func__);
 		goto fail_it;
 	}
 	switch (bit) {
@@ -2000,8 +1825,7 @@
 		ql_dump_ricb((struct ricb *)ptr);
 		break;
 	default:
-		printk(KERN_ERR PFX "%s: Invalid bit value = %x.\n",
-		       __func__, bit);
+		pr_err("%s: Invalid bit value = %x\n", __func__, bit);
 		break;
 	}
 fail_it:
@@ -2012,27 +1836,27 @@
 #ifdef QL_OB_DUMP
 void ql_dump_tx_desc(struct tx_buf_desc *tbd)
 {
-	printk(KERN_ERR PFX "tbd->addr  = 0x%llx\n",
+	pr_err("tbd->addr  = 0x%llx\n",
 	       le64_to_cpu((u64) tbd->addr));
-	printk(KERN_ERR PFX "tbd->len   = %d\n",
+	pr_err("tbd->len   = %d\n",
 	       le32_to_cpu(tbd->len & TX_DESC_LEN_MASK));
-	printk(KERN_ERR PFX "tbd->flags = %s %s\n",
+	pr_err("tbd->flags = %s %s\n",
 	       tbd->len & TX_DESC_C ? "C" : ".",
 	       tbd->len & TX_DESC_E ? "E" : ".");
 	tbd++;
-	printk(KERN_ERR PFX "tbd->addr  = 0x%llx\n",
+	pr_err("tbd->addr  = 0x%llx\n",
 	       le64_to_cpu((u64) tbd->addr));
-	printk(KERN_ERR PFX "tbd->len   = %d\n",
+	pr_err("tbd->len   = %d\n",
 	       le32_to_cpu(tbd->len & TX_DESC_LEN_MASK));
-	printk(KERN_ERR PFX "tbd->flags = %s %s\n",
+	pr_err("tbd->flags = %s %s\n",
 	       tbd->len & TX_DESC_C ? "C" : ".",
 	       tbd->len & TX_DESC_E ? "E" : ".");
 	tbd++;
-	printk(KERN_ERR PFX "tbd->addr  = 0x%llx\n",
+	pr_err("tbd->addr  = 0x%llx\n",
 	       le64_to_cpu((u64) tbd->addr));
-	printk(KERN_ERR PFX "tbd->len   = %d\n",
+	pr_err("tbd->len   = %d\n",
 	       le32_to_cpu(tbd->len & TX_DESC_LEN_MASK));
-	printk(KERN_ERR PFX "tbd->flags = %s %s\n",
+	pr_err("tbd->flags = %s %s\n",
 	       tbd->len & TX_DESC_C ? "C" : ".",
 	       tbd->len & TX_DESC_E ? "E" : ".");
 
@@ -2045,38 +1869,38 @@
 	struct tx_buf_desc *tbd;
 	u16 frame_len;
 
-	printk(KERN_ERR PFX "%s\n", __func__);
-	printk(KERN_ERR PFX "opcode         = %s\n",
+	pr_err("%s\n", __func__);
+	pr_err("opcode         = %s\n",
 	       (ob_mac_iocb->opcode == OPCODE_OB_MAC_IOCB) ? "MAC" : "TSO");
-	printk(KERN_ERR PFX "flags1          = %s %s %s %s %s\n",
+	pr_err("flags1          = %s %s %s %s %s\n",
 	       ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_OI ? "OI" : "",
 	       ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_I ? "I" : "",
 	       ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_D ? "D" : "",
 	       ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_IP4 ? "IP4" : "",
 	       ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_IP6 ? "IP6" : "");
-	printk(KERN_ERR PFX "flags2          = %s %s %s\n",
+	pr_err("flags2          = %s %s %s\n",
 	       ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_LSO ? "LSO" : "",
 	       ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_UC ? "UC" : "",
 	       ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_TC ? "TC" : "");
-	printk(KERN_ERR PFX "flags3          = %s %s %s\n",
+	pr_err("flags3          = %s %s %s\n",
 	       ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_IC ? "IC" : "",
 	       ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_DFP ? "DFP" : "",
 	       ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_V ? "V" : "");
-	printk(KERN_ERR PFX "tid = %x\n", ob_mac_iocb->tid);
-	printk(KERN_ERR PFX "txq_idx = %d\n", ob_mac_iocb->txq_idx);
-	printk(KERN_ERR PFX "vlan_tci      = %x\n", ob_mac_tso_iocb->vlan_tci);
+	pr_err("tid = %x\n", ob_mac_iocb->tid);
+	pr_err("txq_idx = %d\n", ob_mac_iocb->txq_idx);
+	pr_err("vlan_tci      = %x\n", ob_mac_tso_iocb->vlan_tci);
 	if (ob_mac_iocb->opcode == OPCODE_OB_MAC_TSO_IOCB) {
-		printk(KERN_ERR PFX "frame_len      = %d\n",
+		pr_err("frame_len      = %d\n",
 		       le32_to_cpu(ob_mac_tso_iocb->frame_len));
-		printk(KERN_ERR PFX "mss      = %d\n",
+		pr_err("mss      = %d\n",
 		       le16_to_cpu(ob_mac_tso_iocb->mss));
-		printk(KERN_ERR PFX "prot_hdr_len   = %d\n",
+		pr_err("prot_hdr_len   = %d\n",
 		       le16_to_cpu(ob_mac_tso_iocb->total_hdrs_len));
-		printk(KERN_ERR PFX "hdr_offset     = 0x%.04x\n",
+		pr_err("hdr_offset     = 0x%.04x\n",
 		       le16_to_cpu(ob_mac_tso_iocb->net_trans_offset));
 		frame_len = le32_to_cpu(ob_mac_tso_iocb->frame_len);
 	} else {
-		printk(KERN_ERR PFX "frame_len      = %d\n",
+		pr_err("frame_len      = %d\n",
 		       le16_to_cpu(ob_mac_iocb->frame_len));
 		frame_len = le16_to_cpu(ob_mac_iocb->frame_len);
 	}
@@ -2086,9 +1910,9 @@
 
 void ql_dump_ob_mac_rsp(struct ob_mac_iocb_rsp *ob_mac_rsp)
 {
-	printk(KERN_ERR PFX "%s\n", __func__);
-	printk(KERN_ERR PFX "opcode         = %d\n", ob_mac_rsp->opcode);
-	printk(KERN_ERR PFX "flags          = %s %s %s %s %s %s %s\n",
+	pr_err("%s\n", __func__);
+	pr_err("opcode         = %d\n", ob_mac_rsp->opcode);
+	pr_err("flags          = %s %s %s %s %s %s %s\n",
 	       ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_OI ? "OI" : ".",
 	       ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_I ? "I" : ".",
 	       ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_E ? "E" : ".",
@@ -2096,16 +1920,16 @@
 	       ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_L ? "L" : ".",
 	       ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_P ? "P" : ".",
 	       ob_mac_rsp->flags2 & OB_MAC_IOCB_RSP_B ? "B" : ".");
-	printk(KERN_ERR PFX "tid = %x\n", ob_mac_rsp->tid);
+	pr_err("tid = %x\n", ob_mac_rsp->tid);
 }
 #endif
 
 #ifdef QL_IB_DUMP
 void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp)
 {
-	printk(KERN_ERR PFX "%s\n", __func__);
-	printk(KERN_ERR PFX "opcode         = 0x%x\n", ib_mac_rsp->opcode);
-	printk(KERN_ERR PFX "flags1 = %s%s%s%s%s%s\n",
+	pr_err("%s\n", __func__);
+	pr_err("opcode         = 0x%x\n", ib_mac_rsp->opcode);
+	pr_err("flags1 = %s%s%s%s%s%s\n",
 	       ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_OI ? "OI " : "",
 	       ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_I ? "I " : "",
 	       ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_TE ? "TE " : "",
@@ -2114,7 +1938,7 @@
 	       ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_B ? "B " : "");
 
 	if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK)
-		printk(KERN_ERR PFX "%s%s%s Multicast.\n",
+		pr_err("%s%s%s Multicast\n",
 		       (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
 		       IB_MAC_IOCB_RSP_M_HASH ? "Hash" : "",
 		       (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
@@ -2122,7 +1946,7 @@
 		       (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
 		       IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : "");
 
-	printk(KERN_ERR PFX "flags2 = %s%s%s%s%s\n",
+	pr_err("flags2 = %s%s%s%s%s\n",
 	       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P) ? "P " : "",
 	       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ? "V " : "",
 	       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) ? "U " : "",
@@ -2130,7 +1954,7 @@
 	       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_FO) ? "FO " : "");
 
 	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK)
-		printk(KERN_ERR PFX "%s%s%s%s%s error.\n",
+		pr_err("%s%s%s%s%s error\n",
 		       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) ==
 		       IB_MAC_IOCB_RSP_ERR_OVERSIZE ? "oversize" : "",
 		       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) ==
@@ -2142,12 +1966,12 @@
 		       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) ==
 		       IB_MAC_IOCB_RSP_ERR_CRC ? "CRC" : "");
 
-	printk(KERN_ERR PFX "flags3 = %s%s.\n",
+	pr_err("flags3 = %s%s\n",
 	       ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DS ? "DS " : "",
 	       ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL ? "DL " : "");
 
 	if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK)
-		printk(KERN_ERR PFX "RSS flags = %s%s%s%s.\n",
+		pr_err("RSS flags = %s%s%s%s\n",
 		       ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) ==
 			IB_MAC_IOCB_RSP_M_IPV4) ? "IPv4 RSS" : "",
 		       ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) ==
@@ -2157,26 +1981,26 @@
 		       ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) ==
 			IB_MAC_IOCB_RSP_M_TCP_V6) ? "TCP/IPv6 RSS" : "");
 
-	printk(KERN_ERR PFX "data_len	= %d\n",
+	pr_err("data_len	= %d\n",
 	       le32_to_cpu(ib_mac_rsp->data_len));
-	printk(KERN_ERR PFX "data_addr    = 0x%llx\n",
+	pr_err("data_addr    = 0x%llx\n",
 	       (unsigned long long) le64_to_cpu(ib_mac_rsp->data_addr));
 	if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK)
-		printk(KERN_ERR PFX "rss    = %x\n",
+		pr_err("rss    = %x\n",
 		       le32_to_cpu(ib_mac_rsp->rss));
 	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V)
-		printk(KERN_ERR PFX "vlan_id    = %x\n",
+		pr_err("vlan_id    = %x\n",
 		       le16_to_cpu(ib_mac_rsp->vlan_id));
 
-	printk(KERN_ERR PFX "flags4 = %s%s%s.\n",
+	pr_err("flags4 = %s%s%s\n",
 		ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV ? "HV " : "",
 		ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS ? "HS " : "",
 		ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HL ? "HL " : "");
 
 	if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV) {
-		printk(KERN_ERR PFX "hdr length	= %d.\n",
+		pr_err("hdr length	= %d\n",
 		       le32_to_cpu(ib_mac_rsp->hdr_len));
-		printk(KERN_ERR PFX "hdr addr    = 0x%llx.\n",
+		pr_err("hdr addr    = 0x%llx\n",
 		       (unsigned long long) le64_to_cpu(ib_mac_rsp->hdr_addr));
 	}
 }
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index d10bcef..8d63f69 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -574,6 +574,22 @@
 			    (RT_IDX_ALL_ERR_SLOT << RT_IDX_IDX_SHIFT);/* index */
 			break;
 		}
+	case RT_IDX_IP_CSUM_ERR: /* Pass up IP CSUM error frames. */
+		{
+			value = RT_IDX_DST_DFLT_Q | /* dest */
+				RT_IDX_TYPE_NICQ | /* type */
+				(RT_IDX_IP_CSUM_ERR_SLOT <<
+				RT_IDX_IDX_SHIFT); /* index */
+			break;
+		}
+	case RT_IDX_TU_CSUM_ERR: /* Pass up TCP/UDP CSUM error frames. */
+		{
+			value = RT_IDX_DST_DFLT_Q | /* dest */
+				RT_IDX_TYPE_NICQ | /* type */
+				(RT_IDX_TCP_UDP_CSUM_ERR_SLOT <<
+				RT_IDX_IDX_SHIFT); /* index */
+			break;
+		}
 	case RT_IDX_BCAST:	/* Pass up Broadcast frames to default Q. */
 		{
 			value = RT_IDX_DST_DFLT_Q |	/* dest */
@@ -1521,7 +1537,7 @@
 
 	/* Frame error, so drop the packet. */
 	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
-		netif_err(qdev, drv, qdev->ndev,
+		netif_info(qdev, drv, qdev->ndev,
 			  "Receive error, flags2 = 0x%x\n", ib_mac_rsp->flags2);
 		rx_ring->rx_errors++;
 		goto err_out;
@@ -1618,7 +1634,7 @@
 
 	/* Frame error, so drop the packet. */
 	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
-		netif_err(qdev, drv, qdev->ndev,
+		netif_info(qdev, drv, qdev->ndev,
 			  "Receive error, flags2 = 0x%x\n", ib_mac_rsp->flags2);
 		dev_kfree_skb_any(skb);
 		rx_ring->rx_errors++;
@@ -1677,7 +1693,7 @@
 			/* Unfragmented ipv4 UDP frame. */
 			struct iphdr *iph = (struct iphdr *) skb->data;
 			if (!(iph->frag_off &
-				cpu_to_be16(IP_MF|IP_OFFSET))) {
+				ntohs(IP_MF|IP_OFFSET))) {
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
 				netif_printk(qdev, rx_status, KERN_DEBUG,
 					     qdev->ndev,
@@ -1939,7 +1955,7 @@
 
 	/* Frame error, so drop the packet. */
 	if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
-		netif_err(qdev, drv, qdev->ndev,
+		netif_info(qdev, drv, qdev->ndev,
 			  "Receive error, flags2 = 0x%x\n", ib_mac_rsp->flags2);
 		dev_kfree_skb_any(skb);
 		rx_ring->rx_errors++;
@@ -1997,7 +2013,7 @@
 		/* Unfragmented ipv4 UDP frame. */
 			struct iphdr *iph = (struct iphdr *) skb->data;
 			if (!(iph->frag_off &
-				cpu_to_be16(IP_MF|IP_OFFSET))) {
+				ntohs(IP_MF|IP_OFFSET))) {
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
 				netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
 					     "TCP checksum done!\n");
@@ -3587,10 +3603,20 @@
 	if (status)
 		return status;
 
-	status = ql_set_routing_reg(qdev, RT_IDX_ALL_ERR_SLOT, RT_IDX_ERR, 1);
+	status = ql_set_routing_reg(qdev, RT_IDX_IP_CSUM_ERR_SLOT,
+						RT_IDX_IP_CSUM_ERR, 1);
 	if (status) {
 		netif_err(qdev, ifup, qdev->ndev,
-			  "Failed to init routing register for error packets.\n");
+			"Failed to init routing register "
+			"for IP CSUM error packets.\n");
+		goto exit;
+	}
+	status = ql_set_routing_reg(qdev, RT_IDX_TCP_UDP_CSUM_ERR_SLOT,
+						RT_IDX_TU_CSUM_ERR, 1);
+	if (status) {
+		netif_err(qdev, ifup, qdev->ndev,
+			"Failed to init routing register "
+			"for TCP/UDP CSUM error packets.\n");
 		goto exit;
 	}
 	status = ql_set_routing_reg(qdev, RT_IDX_BCAST_SLOT, RT_IDX_BCAST, 1);
@@ -3919,6 +3945,11 @@
 	if ((ql_read32(qdev, STS) & qdev->port_init) &&
 			(ql_read32(qdev, STS) & qdev->port_link_up))
 		ql_link_on(qdev);
+	/* Restore rx mode. */
+	clear_bit(QL_ALLMULTI, &qdev->flags);
+	clear_bit(QL_PROMISCUOUS, &qdev->flags);
+	qlge_set_multicast_list(qdev->ndev);
+
 	ql_enable_interrupts(qdev);
 	ql_enable_all_completion_interrupts(qdev);
 	netif_tx_start_all_queues(qdev->ndev);
@@ -4204,7 +4235,7 @@
 	return &ndev->stats;
 }
 
-static void qlge_set_multicast_list(struct net_device *ndev)
+void qlge_set_multicast_list(struct net_device *ndev)
 {
 	struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
 	struct netdev_hw_addr *ha;
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 3c00462..f84e857 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -606,23 +606,6 @@
 	return status;
 }
 
-int ql_mb_sys_err(struct ql_adapter *qdev)
-{
-	struct mbox_params mbc;
-	struct mbox_params *mbcp = &mbc;
-	int status;
-
-	memset(mbcp, 0, sizeof(struct mbox_params));
-
-	mbcp->in_count = 1;
-	mbcp->out_count = 0;
-
-	mbcp->mbox_in[0] = MB_CMD_MAKE_SYS_ERR;
-
-	status = ql_mailbox_command(qdev, mbcp);
-	return status;
-}
-
 /* Get MPI firmware version. This will be used for
  * driver banner and for ethtool info.
  * Returns zero on success.
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 9a251ac..142c381 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -44,12 +44,13 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/uaccess.h>
+#include <linux/phy.h>
 
 #include <asm/processor.h>
 
 #define DRV_NAME	"r6040"
-#define DRV_VERSION	"0.25"
-#define DRV_RELDATE	"20Aug2009"
+#define DRV_VERSION	"0.26"
+#define DRV_RELDATE	"30May2010"
 
 /* PHY CHIP Address */
 #define PHY1_ADDR	1	/* For MAC1 */
@@ -179,7 +180,6 @@
 
 struct r6040_private {
 	spinlock_t lock;		/* driver lock */
-	struct timer_list timer;
 	struct pci_dev *pdev;
 	struct r6040_descriptor *rx_insert_ptr;
 	struct r6040_descriptor *rx_remove_ptr;
@@ -189,13 +189,15 @@
 	struct r6040_descriptor *tx_ring;
 	dma_addr_t rx_ring_dma;
 	dma_addr_t tx_ring_dma;
-	u16	tx_free_desc, phy_addr, phy_mode;
+	u16	tx_free_desc, phy_addr;
 	u16	mcr0, mcr1;
-	u16	switch_sig;
 	struct net_device *dev;
-	struct mii_if_info mii_if;
+	struct mii_bus *mii_bus;
 	struct napi_struct napi;
 	void __iomem *base;
+	struct phy_device *phydev;
+	int old_link;
+	int old_duplex;
 };
 
 static char version[] __devinitdata = KERN_INFO DRV_NAME
@@ -238,20 +240,30 @@
 	}
 }
 
-static int r6040_mdio_read(struct net_device *dev, int mii_id, int reg)
+static int r6040_mdiobus_read(struct mii_bus *bus, int phy_addr, int reg)
 {
+	struct net_device *dev = bus->priv;
 	struct r6040_private *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->base;
 
-	return (r6040_phy_read(ioaddr, lp->phy_addr, reg));
+	return r6040_phy_read(ioaddr, phy_addr, reg);
 }
 
-static void r6040_mdio_write(struct net_device *dev, int mii_id, int reg, int val)
+static int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr,
+						int reg, u16 value)
 {
+	struct net_device *dev = bus->priv;
 	struct r6040_private *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->base;
 
-	r6040_phy_write(ioaddr, lp->phy_addr, reg, val);
+	r6040_phy_write(ioaddr, phy_addr, reg, value);
+
+	return 0;
+}
+
+static int r6040_mdiobus_reset(struct mii_bus *bus)
+{
+	return 0;
 }
 
 static void r6040_free_txbufs(struct net_device *dev)
@@ -408,10 +420,9 @@
 	void __iomem *ioaddr = priv->base;
 
 	netdev_warn(dev, "transmit timed out, int enable %4.4x "
-		"status %4.4x, PHY status %4.4x\n",
+		"status %4.4x\n",
 		ioread16(ioaddr + MIER),
-		ioread16(ioaddr + MISR),
-		r6040_mdio_read(dev, priv->mii_if.phy_id, MII_BMSR));
+		ioread16(ioaddr + MISR));
 
 	dev->stats.tx_errors++;
 
@@ -463,9 +474,6 @@
 	struct r6040_private *lp = netdev_priv(dev);
 	struct pci_dev *pdev = lp->pdev;
 
-	/* deleted timer */
-	del_timer_sync(&lp->timer);
-
 	spin_lock_irq(&lp->lock);
 	napi_disable(&lp->napi);
 	netif_stop_queue(dev);
@@ -495,64 +503,14 @@
 	return 0;
 }
 
-/* Status of PHY CHIP */
-static int r6040_phy_mode_chk(struct net_device *dev)
-{
-	struct r6040_private *lp = netdev_priv(dev);
-	void __iomem *ioaddr = lp->base;
-	int phy_dat;
-
-	/* PHY Link Status Check */
-	phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 1);
-	if (!(phy_dat & 0x4))
-		phy_dat = 0x8000;	/* Link Failed, full duplex */
-
-	/* PHY Chip Auto-Negotiation Status */
-	phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 1);
-	if (phy_dat & 0x0020) {
-		/* Auto Negotiation Mode */
-		phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 5);
-		phy_dat &= r6040_phy_read(ioaddr, lp->phy_addr, 4);
-		if (phy_dat & 0x140)
-			/* Force full duplex */
-			phy_dat = 0x8000;
-		else
-			phy_dat = 0;
-	} else {
-		/* Force Mode */
-		phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 0);
-		if (phy_dat & 0x100)
-			phy_dat = 0x8000;
-		else
-			phy_dat = 0x0000;
-	}
-
-	return phy_dat;
-};
-
-static void r6040_set_carrier(struct mii_if_info *mii)
-{
-	if (r6040_phy_mode_chk(mii->dev)) {
-		/* autoneg is off: Link is always assumed to be up */
-		if (!netif_carrier_ok(mii->dev))
-			netif_carrier_on(mii->dev);
-	} else
-		r6040_phy_mode_chk(mii->dev);
-}
-
 static int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct r6040_private *lp = netdev_priv(dev);
-	struct mii_ioctl_data *data = if_mii(rq);
-	int rc;
 
-	if (!netif_running(dev))
+	if (!lp->phydev)
 		return -EINVAL;
-	spin_lock_irq(&lp->lock);
-	rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL);
-	spin_unlock_irq(&lp->lock);
-	r6040_set_carrier(&lp->mii_if);
-	return rc;
+
+	return phy_mii_ioctl(lp->phydev, rq, cmd);
 }
 
 static int r6040_rx(struct net_device *dev, int limit)
@@ -751,26 +709,6 @@
 	if (ret)
 		return ret;
 
-	/* Read the PHY ID */
-	lp->switch_sig = r6040_phy_read(ioaddr, 0, 2);
-
-	if (lp->switch_sig  == ICPLUS_PHY_ID) {
-		r6040_phy_write(ioaddr, 29, 31, 0x175C); /* Enable registers */
-		lp->phy_mode = 0x8000;
-	} else {
-		/* PHY Mode Check */
-		r6040_phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP);
-		r6040_phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);
-
-		if (PHY_MODE == 0x3100)
-			lp->phy_mode = r6040_phy_mode_chk(dev);
-		else
-			lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
-	}
-
-	/* Set duplex mode */
-	lp->mcr0 |= lp->phy_mode;
-
 	/* improve performance (by RDC guys) */
 	r6040_phy_write(ioaddr, 30, 17, (r6040_phy_read(ioaddr, 30, 17) | 0x4000));
 	r6040_phy_write(ioaddr, 30, 17, ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
@@ -783,35 +721,6 @@
 	return 0;
 }
 
-/*
-  A periodic timer routine
-	Polling PHY Chip Link Status
-*/
-static void r6040_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct r6040_private *lp = netdev_priv(dev);
-	void __iomem *ioaddr = lp->base;
-	u16 phy_mode;
-
-	/* Polling PHY Chip Status */
-	if (PHY_MODE == 0x3100)
-		phy_mode = r6040_phy_mode_chk(dev);
-	else
-		phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
-
-	if (phy_mode != lp->phy_mode) {
-		lp->phy_mode = phy_mode;
-		lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode;
-		iowrite16(lp->mcr0, ioaddr);
-	}
-
-	/* Timer active again */
-	mod_timer(&lp->timer, round_jiffies(jiffies + HZ));
-
-	/* Check media */
-	mii_check_media(&lp->mii_if, 1, 1);
-}
 
 /* Read/set MAC address routines */
 static void r6040_mac_address(struct net_device *dev)
@@ -873,10 +782,6 @@
 	napi_enable(&lp->napi);
 	netif_start_queue(dev);
 
-	/* set and active a timer process */
-	setup_timer(&lp->timer, r6040_timer, (unsigned long) dev);
-	if (lp->switch_sig != ICPLUS_PHY_ID)
-		mod_timer(&lp->timer, jiffies + HZ);
 	return 0;
 }
 
@@ -1015,40 +920,22 @@
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct r6040_private *rp = netdev_priv(dev);
-	int rc;
 
-	spin_lock_irq(&rp->lock);
-	rc = mii_ethtool_gset(&rp->mii_if, cmd);
-	spin_unlock_irq(&rp->lock);
-
-	return rc;
+	return  phy_ethtool_gset(rp->phydev, cmd);
 }
 
 static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct r6040_private *rp = netdev_priv(dev);
-	int rc;
 
-	spin_lock_irq(&rp->lock);
-	rc = mii_ethtool_sset(&rp->mii_if, cmd);
-	spin_unlock_irq(&rp->lock);
-	r6040_set_carrier(&rp->mii_if);
-
-	return rc;
-}
-
-static u32 netdev_get_link(struct net_device *dev)
-{
-	struct r6040_private *rp = netdev_priv(dev);
-
-	return mii_link_ok(&rp->mii_if);
+	return phy_ethtool_sset(rp->phydev, cmd);
 }
 
 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,
+	.get_link		= ethtool_op_get_link,
 };
 
 static const struct net_device_ops r6040_netdev_ops = {
@@ -1067,6 +954,79 @@
 #endif
 };
 
+static void r6040_adjust_link(struct net_device *dev)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	struct phy_device *phydev = lp->phydev;
+	int status_changed = 0;
+	void __iomem *ioaddr = lp->base;
+
+	BUG_ON(!phydev);
+
+	if (lp->old_link != phydev->link) {
+		status_changed = 1;
+		lp->old_link = phydev->link;
+	}
+
+	/* reflect duplex change */
+	if (phydev->link && (lp->old_duplex != phydev->duplex)) {
+		lp->mcr0 |= (phydev->duplex == DUPLEX_FULL ? 0x8000 : 0);
+		iowrite16(lp->mcr0, ioaddr);
+
+		status_changed = 1;
+		lp->old_duplex = phydev->duplex;
+	}
+
+	if (status_changed) {
+		pr_info("%s: link %s", dev->name, phydev->link ?
+			"UP" : "DOWN");
+		if (phydev->link)
+			pr_cont(" - %d/%s", phydev->speed,
+			DUPLEX_FULL == phydev->duplex ? "full" : "half");
+		pr_cont("\n");
+	}
+}
+
+static int r6040_mii_probe(struct net_device *dev)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	struct phy_device *phydev = NULL;
+
+	phydev = phy_find_first(lp->mii_bus);
+	if (!phydev) {
+		dev_err(&lp->pdev->dev, "no PHY found\n");
+		return -ENODEV;
+	}
+
+	phydev = phy_connect(dev, dev_name(&phydev->dev), &r6040_adjust_link,
+				0, PHY_INTERFACE_MODE_MII);
+
+	if (IS_ERR(phydev)) {
+		dev_err(&lp->pdev->dev, "could not attach to PHY\n");
+		return PTR_ERR(phydev);
+	}
+
+	/* mask with MAC supported features */
+	phydev->supported &= (SUPPORTED_10baseT_Half
+				| SUPPORTED_10baseT_Full
+				| SUPPORTED_100baseT_Half
+				| SUPPORTED_100baseT_Full
+				| SUPPORTED_Autoneg
+				| SUPPORTED_MII
+				| SUPPORTED_TP);
+
+	phydev->advertising = phydev->supported;
+	lp->phydev = phydev;
+	lp->old_link = 0;
+	lp->old_duplex = -1;
+
+	dev_info(&lp->pdev->dev, "attached PHY driver [%s] "
+		"(mii_bus:phy_addr=%s)\n",
+		phydev->drv->name, dev_name(&phydev->dev));
+
+	return 0;
+}
+
 static int __devinit r6040_init_one(struct pci_dev *pdev,
 					 const struct pci_device_id *ent)
 {
@@ -1077,6 +1037,7 @@
 	static int card_idx = -1;
 	int bar = 0;
 	u16 *adrp;
+	int i;
 
 	printk("%s\n", version);
 
@@ -1163,7 +1124,6 @@
 	/* Init RDC private data */
 	lp->mcr0 = 0x1002;
 	lp->phy_addr = phy_table[card_idx];
-	lp->switch_sig = 0;
 
 	/* The RDC-specific entries in the device structure. */
 	dev->netdev_ops = &r6040_netdev_ops;
@@ -1171,28 +1131,54 @@
 	dev->watchdog_timeo = TX_TIMEOUT;
 
 	netif_napi_add(dev, &lp->napi, r6040_poll, 64);
-	lp->mii_if.dev = dev;
-	lp->mii_if.mdio_read = r6040_mdio_read;
-	lp->mii_if.mdio_write = r6040_mdio_write;
-	lp->mii_if.phy_id = lp->phy_addr;
-	lp->mii_if.phy_id_mask = 0x1f;
-	lp->mii_if.reg_num_mask = 0x1f;
 
-	/* Check the vendor ID on the PHY, if 0xffff assume none attached */
-	if (r6040_phy_read(ioaddr, lp->phy_addr, 2) == 0xffff) {
-		dev_err(&pdev->dev, "Failed to detect an attached PHY\n");
-		err = -ENODEV;
+	lp->mii_bus = mdiobus_alloc();
+	if (!lp->mii_bus) {
+		dev_err(&pdev->dev, "mdiobus_alloc() failed\n");
 		goto err_out_unmap;
 	}
 
+	lp->mii_bus->priv = dev;
+	lp->mii_bus->read = r6040_mdiobus_read;
+	lp->mii_bus->write = r6040_mdiobus_write;
+	lp->mii_bus->reset = r6040_mdiobus_reset;
+	lp->mii_bus->name = "r6040_eth_mii";
+	snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x", card_idx);
+	lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+	if (!lp->mii_bus->irq) {
+		dev_err(&pdev->dev, "mii_bus irq allocation failed\n");
+		goto err_out_mdio;
+	}
+
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		lp->mii_bus->irq[i] = PHY_POLL;
+
+	err = mdiobus_register(lp->mii_bus);
+	if (err) {
+		dev_err(&pdev->dev, "failed to register MII bus\n");
+		goto err_out_mdio_irq;
+	}
+
+	err = r6040_mii_probe(dev);
+	if (err) {
+		dev_err(&pdev->dev, "failed to probe MII bus\n");
+		goto err_out_mdio_unregister;
+	}
+
 	/* Register net device. After this dev->name assign */
 	err = register_netdev(dev);
 	if (err) {
 		dev_err(&pdev->dev, "Failed to register net device\n");
-		goto err_out_unmap;
+		goto err_out_mdio_unregister;
 	}
 	return 0;
 
+err_out_mdio_unregister:
+	mdiobus_unregister(lp->mii_bus);
+err_out_mdio_irq:
+	kfree(lp->mii_bus->irq);
+err_out_mdio:
+	mdiobus_free(lp->mii_bus);
 err_out_unmap:
 	pci_iounmap(pdev, ioaddr);
 err_out_free_res:
@@ -1206,8 +1192,12 @@
 static void __devexit r6040_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
+	struct r6040_private *lp = netdev_priv(dev);
 
 	unregister_netdev(dev);
+	mdiobus_unregister(lp->mii_bus);
+	kfree(lp->mii_bus->irq);
+	mdiobus_free(lp->mii_bus);
 	pci_release_regions(pdev);
 	free_netdev(dev);
 	pci_disable_device(pdev);
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index cdc6a5c..3554041 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -88,7 +88,7 @@
 #define RTL_W32(reg, val32)	writel ((val32), ioaddr + (reg))
 #define RTL_R8(reg)		readb (ioaddr + (reg))
 #define RTL_R16(reg)		readw (ioaddr + (reg))
-#define RTL_R32(reg)		((unsigned long) readl (ioaddr + (reg)))
+#define RTL_R32(reg)		readl (ioaddr + (reg))
 
 enum mac_version {
 	RTL_GIGA_MAC_NONE   = 0x00,
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index 416669f..3688325 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -1,6 +1,6 @@
 /************************************************************************
  * regs.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2007 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
 
  * This software may be used and distributed according to the terms of
  * the GNU General Public License (GPL), incorporated herein by reference.
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 1d37f0c..18bc5b7 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -1,6 +1,6 @@
 /************************************************************************
  * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2007 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
  *
  * This software may be used and distributed according to the terms of
  * the GNU General Public License (GPL), incorporated herein by reference.
@@ -38,7 +38,7 @@
  * Tx descriptors that can be associated with each corresponding FIFO.
  * intr_type: This defines the type of interrupt. The values can be 0(INTA),
  *     2(MSI_X). Default value is '2(MSI_X)'
- * lro_enable: Specifies whether to enable Large Receive Offload (LRO) or not.
+ * lro: Specifies whether to enable Large Receive Offload (LRO) or not.
  *     Possible values '1' for enable '0' for disable. Default is '0'
  * lro_max_pkts: This parameter defines maximum number of packets can be
  *     aggregated as a single large packet
@@ -90,7 +90,7 @@
 #include "s2io.h"
 #include "s2io-regs.h"
 
-#define DRV_VERSION "2.0.26.25"
+#define DRV_VERSION "2.0.26.26"
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
@@ -496,7 +496,7 @@
 /* Interrupt type. Values can be 0(INTA), 2(MSI_X) */
 S2IO_PARM_INT(intr_type, 2);
 /* Large receive offload feature */
-static unsigned int lro_enable;
+static unsigned int lro_enable = 1;
 module_param_named(lro, lro_enable, uint, 0);
 
 /* Max pkts to be aggregated by LRO at one time. If not specified,
@@ -795,7 +795,6 @@
 		ring->rx_curr_put_info.ring_len = rx_cfg->num_rxd - 1;
 		ring->nic = nic;
 		ring->ring_no = i;
-		ring->lro = lro_enable;
 
 		blk_cnt = rx_cfg->num_rxd / (rxd_count[nic->rxd_mode] + 1);
 		/*  Allocating all the Rx blocks */
@@ -5797,7 +5796,7 @@
 {
 	u8 *vpd_data;
 	u8 data;
-	int i = 0, cnt, fail = 0;
+	int i = 0, cnt, len, fail = 0;
 	int vpd_addr = 0x80;
 	struct swStat *swstats = &nic->mac_control.stats_info->sw_stat;
 
@@ -5838,20 +5837,28 @@
 
 	if (!fail) {
 		/* read serial number of adapter */
-		for (cnt = 0; cnt < 256; cnt++) {
+		for (cnt = 0; cnt < 252; cnt++) {
 			if ((vpd_data[cnt] == 'S') &&
-			    (vpd_data[cnt+1] == 'N') &&
-			    (vpd_data[cnt+2] < VPD_STRING_LEN)) {
-				memset(nic->serial_num, 0, VPD_STRING_LEN);
-				memcpy(nic->serial_num, &vpd_data[cnt + 3],
-				       vpd_data[cnt+2]);
-				break;
+			    (vpd_data[cnt+1] == 'N')) {
+				len = vpd_data[cnt+2];
+				if (len < min(VPD_STRING_LEN, 256-cnt-2)) {
+					memcpy(nic->serial_num,
+					       &vpd_data[cnt + 3],
+					       len);
+					memset(nic->serial_num+len,
+					       0,
+					       VPD_STRING_LEN-len);
+					break;
+				}
 			}
 		}
 	}
 
-	if ((!fail) && (vpd_data[1] < VPD_STRING_LEN))
-		memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
+	if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) {
+		len = vpd_data[1];
+		memcpy(nic->product_name, &vpd_data[3], len);
+		nic->product_name[len] = 0;
+	}
 	kfree(vpd_data);
 	swstats->mem_freed += 256;
 }
@@ -6707,6 +6714,7 @@
 {
 	return (dev->features & NETIF_F_TSO) != 0;
 }
+
 static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data)
 {
 	if (data)
@@ -6717,6 +6725,42 @@
 	return 0;
 }
 
+static int s2io_ethtool_set_flags(struct net_device *dev, u32 data)
+{
+	struct s2io_nic *sp = netdev_priv(dev);
+	int rc = 0;
+	int changed = 0;
+
+	if (data & ~ETH_FLAG_LRO)
+		return -EINVAL;
+
+	if (data & ETH_FLAG_LRO) {
+		if (lro_enable) {
+			if (!(dev->features & NETIF_F_LRO)) {
+				dev->features |= NETIF_F_LRO;
+				changed = 1;
+			}
+		} else
+			rc = -EINVAL;
+	} else if (dev->features & NETIF_F_LRO) {
+		dev->features &= ~NETIF_F_LRO;
+		changed = 1;
+	}
+
+	if (changed && netif_running(dev)) {
+		s2io_stop_all_tx_queue(sp);
+		s2io_card_down(sp);
+		sp->lro = !!(dev->features & NETIF_F_LRO);
+		rc = s2io_card_up(sp);
+		if (rc)
+			s2io_reset(sp);
+		else
+			s2io_start_all_tx_queue(sp);
+	}
+
+	return rc;
+}
+
 static const struct ethtool_ops netdev_ethtool_ops = {
 	.get_settings = s2io_ethtool_gset,
 	.set_settings = s2io_ethtool_sset,
@@ -6733,6 +6777,8 @@
 	.get_rx_csum = s2io_ethtool_get_rx_csum,
 	.set_rx_csum = s2io_ethtool_set_rx_csum,
 	.set_tx_csum = s2io_ethtool_op_set_tx_csum,
+	.set_flags = s2io_ethtool_set_flags,
+	.get_flags = ethtool_op_get_flags,
 	.set_sg = ethtool_op_set_sg,
 	.get_tso = s2io_ethtool_op_get_tso,
 	.set_tso = s2io_ethtool_op_set_tso,
@@ -7261,6 +7307,7 @@
 		struct ring_info *ring = &mac_control->rings[i];
 
 		ring->mtu = dev->mtu;
+		ring->lro = sp->lro;
 		ret = fill_rx_buffers(sp, ring, 1);
 		if (ret) {
 			DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
@@ -7847,7 +7894,6 @@
 
 	/*  Private member variable initialized to s2io NIC structure */
 	sp = netdev_priv(dev);
-	memset(sp, 0, sizeof(struct s2io_nic));
 	sp->dev = dev;
 	sp->pdev = pdev;
 	sp->high_dma_flag = dma_flag;
@@ -8001,7 +8047,8 @@
 	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;
-
+	if (lro_enable)
+		dev->features |= NETIF_F_LRO;
 	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
 	if (sp->high_dma_flag == true)
 		dev->features |= NETIF_F_HIGHDMA;
@@ -8159,7 +8206,7 @@
 		goto register_failed;
 	}
 	s2io_vpd_read(sp);
-	DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n");
+	DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2010 Exar Corp.\n");
 	DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n", dev->name,
 		  sp->product_name, pdev->revision);
 	DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 7f3a53d..0af0335 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -1,6 +1,6 @@
 /************************************************************************
  * s2io.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2007 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
 
  * This software may be used and distributed according to the terms of
  * the GNU General Public License (GPL), incorporated herein by reference.
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index 79eee30..8e6bd45 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -2532,7 +2532,7 @@
 	if (!netif_running(dev) || !sc->phy_dev)
 		return -EINVAL;
 
-	return phy_mii_ioctl(sc->phy_dev, if_mii(rq), cmd);
+	return phy_mii_ioctl(sc->phy_dev, rq, cmd);
 }
 
 static int sbmac_close(struct net_device *dev)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 1564605..ba674c5 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -27,6 +27,7 @@
 #include "nic.h"
 
 #include "mcdi.h"
+#include "workarounds.h"
 
 /**************************************************************************
  *
@@ -92,13 +93,6 @@
 
 #define EFX_MAX_MTU (9 * 1024)
 
-/* RX slow fill workqueue. If memory allocation fails in the fast path,
- * a work item is pushed onto this work queue to retry the allocation later,
- * to avoid the NIC being starved of RX buffers. Since this is a per cpu
- * workqueue, there is nothing to be gained in making it per NIC
- */
-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.
@@ -195,6 +189,13 @@
 MODULE_PARM_DESC(irq_adapt_high_thresh,
 		 "Threshold score for increasing IRQ moderation");
 
+static unsigned debug = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
+			 NETIF_MSG_LINK | NETIF_MSG_IFDOWN |
+			 NETIF_MSG_IFUP | NETIF_MSG_RX_ERR |
+			 NETIF_MSG_TX_ERR | NETIF_MSG_HW);
+module_param(debug, uint, 0);
+MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value");
+
 /**************************************************************************
  *
  * Utility functions and prototypes
@@ -278,16 +279,16 @@
 {
 	struct efx_channel *channel =
 		container_of(napi, struct efx_channel, napi_str);
+	struct efx_nic *efx = channel->efx;
 	int spent;
 
-	EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n",
-		  channel->channel, raw_smp_processor_id());
+	netif_vdbg(efx, intr, efx->net_dev,
+		   "channel %d NAPI poll executing on CPU %d\n",
+		   channel->channel, raw_smp_processor_id());
 
 	spent = efx_process_channel(channel, budget);
 
 	if (spent < budget) {
-		struct efx_nic *efx = channel->efx;
-
 		if (channel->channel < efx->n_rx_channels &&
 		    efx->irq_rx_adaptive &&
 		    unlikely(++channel->irq_count == 1000)) {
@@ -363,7 +364,8 @@
  */
 static int efx_probe_eventq(struct efx_channel *channel)
 {
-	EFX_LOG(channel->efx, "chan %d create event queue\n", channel->channel);
+	netif_dbg(channel->efx, probe, channel->efx->net_dev,
+		  "chan %d create event queue\n", channel->channel);
 
 	return efx_nic_probe_eventq(channel);
 }
@@ -371,7 +373,8 @@
 /* Prepare channel's event queue */
 static void efx_init_eventq(struct efx_channel *channel)
 {
-	EFX_LOG(channel->efx, "chan %d init event queue\n", channel->channel);
+	netif_dbg(channel->efx, drv, channel->efx->net_dev,
+		  "chan %d init event queue\n", channel->channel);
 
 	channel->eventq_read_ptr = 0;
 
@@ -380,14 +383,16 @@
 
 static void efx_fini_eventq(struct efx_channel *channel)
 {
-	EFX_LOG(channel->efx, "chan %d fini event queue\n", channel->channel);
+	netif_dbg(channel->efx, drv, channel->efx->net_dev,
+		  "chan %d fini event queue\n", channel->channel);
 
 	efx_nic_fini_eventq(channel);
 }
 
 static void efx_remove_eventq(struct efx_channel *channel)
 {
-	EFX_LOG(channel->efx, "chan %d remove event queue\n", channel->channel);
+	netif_dbg(channel->efx, drv, channel->efx->net_dev,
+		  "chan %d remove event queue\n", channel->channel);
 
 	efx_nic_remove_eventq(channel);
 }
@@ -404,7 +409,8 @@
 	struct efx_rx_queue *rx_queue;
 	int rc;
 
-	EFX_LOG(channel->efx, "creating channel %d\n", channel->channel);
+	netif_dbg(channel->efx, probe, channel->efx->net_dev,
+		  "creating channel %d\n", channel->channel);
 
 	rc = efx_probe_eventq(channel);
 	if (rc)
@@ -474,12 +480,15 @@
 	 */
 	efx->rx_buffer_len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) +
 			      EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
+			      efx->type->rx_buffer_hash_size +
 			      efx->type->rx_buffer_padding);
-	efx->rx_buffer_order = get_order(efx->rx_buffer_len);
+	efx->rx_buffer_order = get_order(efx->rx_buffer_len +
+					 sizeof(struct efx_rx_page_state));
 
 	/* Initialise the channels */
 	efx_for_each_channel(channel, efx) {
-		EFX_LOG(channel->efx, "init chan %d\n", channel->channel);
+		netif_dbg(channel->efx, drv, channel->efx->net_dev,
+			  "init chan %d\n", channel->channel);
 
 		efx_init_eventq(channel);
 
@@ -506,7 +515,8 @@
 {
 	struct efx_rx_queue *rx_queue;
 
-	EFX_LOG(channel->efx, "starting chan %d\n", channel->channel);
+	netif_dbg(channel->efx, ifup, channel->efx->net_dev,
+		  "starting chan %d\n", channel->channel);
 
 	/* The interrupt handler for this channel may set work_pending
 	 * as soon as we enable it.  Make sure it's cleared before
@@ -515,11 +525,11 @@
 	channel->enabled = true;
 	smp_wmb();
 
-	napi_enable(&channel->napi_str);
-
-	/* Load up RX descriptors */
+	/* Fill the queues before enabling NAPI */
 	efx_for_each_channel_rx_queue(rx_queue, channel)
 		efx_fast_push_rx_descriptors(rx_queue);
+
+	napi_enable(&channel->napi_str);
 }
 
 /* This disables event queue processing and packet transmission.
@@ -528,21 +538,14 @@
  */
 static void efx_stop_channel(struct efx_channel *channel)
 {
-	struct efx_rx_queue *rx_queue;
-
 	if (!channel->enabled)
 		return;
 
-	EFX_LOG(channel->efx, "stop chan %d\n", channel->channel);
+	netif_dbg(channel->efx, ifdown, channel->efx->net_dev,
+		  "stop chan %d\n", channel->channel);
 
 	channel->enabled = false;
 	napi_disable(&channel->napi_str);
-
-	/* Ensure that any worker threads have exited or will be no-ops */
-	efx_for_each_channel_rx_queue(rx_queue, channel) {
-		spin_lock_bh(&rx_queue->add_lock);
-		spin_unlock_bh(&rx_queue->add_lock);
-	}
 }
 
 static void efx_fini_channels(struct efx_nic *efx)
@@ -556,13 +559,24 @@
 	BUG_ON(efx->port_enabled);
 
 	rc = efx_nic_flush_queues(efx);
-	if (rc)
-		EFX_ERR(efx, "failed to flush queues\n");
-	else
-		EFX_LOG(efx, "successfully flushed all queues\n");
+	if (rc && EFX_WORKAROUND_7803(efx)) {
+		/* Schedule a reset to recover from the flush failure. The
+		 * descriptor caches reference memory we're about to free,
+		 * but falcon_reconfigure_mac_wrapper() won't reconnect
+		 * the MACs because of the pending reset. */
+		netif_err(efx, drv, efx->net_dev,
+			  "Resetting to recover from flush failure\n");
+		efx_schedule_reset(efx, RESET_TYPE_ALL);
+	} else if (rc) {
+		netif_err(efx, drv, efx->net_dev, "failed to flush queues\n");
+	} else {
+		netif_dbg(efx, drv, efx->net_dev,
+			  "successfully flushed all queues\n");
+	}
 
 	efx_for_each_channel(channel, efx) {
-		EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel);
+		netif_dbg(channel->efx, drv, channel->efx->net_dev,
+			  "shut down chan %d\n", channel->channel);
 
 		efx_for_each_channel_rx_queue(rx_queue, channel)
 			efx_fini_rx_queue(rx_queue);
@@ -577,7 +591,8 @@
 	struct efx_tx_queue *tx_queue;
 	struct efx_rx_queue *rx_queue;
 
-	EFX_LOG(channel->efx, "destroy chan %d\n", channel->channel);
+	netif_dbg(channel->efx, drv, channel->efx->net_dev,
+		  "destroy chan %d\n", channel->channel);
 
 	efx_for_each_channel_rx_queue(rx_queue, channel)
 		efx_remove_rx_queue(rx_queue);
@@ -586,9 +601,9 @@
 	efx_remove_eventq(channel);
 }
 
-void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay)
+void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue)
 {
-	queue_delayed_work(refill_workqueue, &rx_queue->work, delay);
+	mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100));
 }
 
 /**************************************************************************
@@ -628,12 +643,13 @@
 
 	/* Status message for kernel log */
 	if (link_state->up) {
-		EFX_INFO(efx, "link up at %uMbps %s-duplex (MTU %d)%s\n",
-			 link_state->speed, link_state->fd ? "full" : "half",
-			 efx->net_dev->mtu,
-			 (efx->promiscuous ? " [PROMISC]" : ""));
+		netif_info(efx, link, efx->net_dev,
+			   "link up at %uMbps %s-duplex (MTU %d)%s\n",
+			   link_state->speed, link_state->fd ? "full" : "half",
+			   efx->net_dev->mtu,
+			   (efx->promiscuous ? " [PROMISC]" : ""));
 	} else {
-		EFX_INFO(efx, "link down\n");
+		netif_info(efx, link, efx->net_dev, "link down\n");
 	}
 
 }
@@ -737,7 +753,7 @@
 {
 	int rc;
 
-	EFX_LOG(efx, "create port\n");
+	netif_dbg(efx, probe, efx->net_dev, "create port\n");
 
 	if (phy_flash_cfg)
 		efx->phy_mode = PHY_MODE_SPECIAL;
@@ -751,15 +767,16 @@
 	if (is_valid_ether_addr(efx->mac_address)) {
 		memcpy(efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN);
 	} else {
-		EFX_ERR(efx, "invalid MAC address %pM\n",
-			efx->mac_address);
+		netif_err(efx, probe, efx->net_dev, "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 %pM\n",
-			 efx->net_dev->dev_addr);
+		netif_info(efx, probe, efx->net_dev,
+			   "using locally-generated MAC %pM\n",
+			   efx->net_dev->dev_addr);
 	}
 
 	return 0;
@@ -773,7 +790,7 @@
 {
 	int rc;
 
-	EFX_LOG(efx, "init port\n");
+	netif_dbg(efx, drv, efx->net_dev, "init port\n");
 
 	mutex_lock(&efx->mac_lock);
 
@@ -804,7 +821,7 @@
 
 static void efx_start_port(struct efx_nic *efx)
 {
-	EFX_LOG(efx, "start port\n");
+	netif_dbg(efx, ifup, efx->net_dev, "start port\n");
 	BUG_ON(efx->port_enabled);
 
 	mutex_lock(&efx->mac_lock);
@@ -821,7 +838,7 @@
 /* Prevent efx_mac_work() and efx_monitor() from working */
 static void efx_stop_port(struct efx_nic *efx)
 {
-	EFX_LOG(efx, "stop port\n");
+	netif_dbg(efx, ifdown, efx->net_dev, "stop port\n");
 
 	mutex_lock(&efx->mac_lock);
 	efx->port_enabled = false;
@@ -836,7 +853,7 @@
 
 static void efx_fini_port(struct efx_nic *efx)
 {
-	EFX_LOG(efx, "shut down port\n");
+	netif_dbg(efx, drv, efx->net_dev, "shut down port\n");
 
 	if (!efx->port_initialized)
 		return;
@@ -850,7 +867,7 @@
 
 static void efx_remove_port(struct efx_nic *efx)
 {
-	EFX_LOG(efx, "destroying port\n");
+	netif_dbg(efx, drv, efx->net_dev, "destroying port\n");
 
 	efx->type->remove_port(efx);
 }
@@ -868,11 +885,12 @@
 	dma_addr_t dma_mask = efx->type->max_dma_mask;
 	int rc;
 
-	EFX_LOG(efx, "initialising I/O\n");
+	netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n");
 
 	rc = pci_enable_device(pci_dev);
 	if (rc) {
-		EFX_ERR(efx, "failed to enable PCI device\n");
+		netif_err(efx, probe, efx->net_dev,
+			  "failed to enable PCI device\n");
 		goto fail1;
 	}
 
@@ -890,39 +908,45 @@
 		dma_mask >>= 1;
 	}
 	if (rc) {
-		EFX_ERR(efx, "could not find a suitable DMA mask\n");
+		netif_err(efx, probe, efx->net_dev,
+			  "could not find a suitable DMA mask\n");
 		goto fail2;
 	}
-	EFX_LOG(efx, "using DMA mask %llx\n", (unsigned long long) dma_mask);
+	netif_dbg(efx, probe, efx->net_dev,
+		  "using DMA mask %llx\n", (unsigned long long) dma_mask);
 	rc = pci_set_consistent_dma_mask(pci_dev, dma_mask);
 	if (rc) {
 		/* pci_set_consistent_dma_mask() is not *allowed* to
 		 * fail with a mask that pci_set_dma_mask() accepted,
 		 * but just in case...
 		 */
-		EFX_ERR(efx, "failed to set consistent DMA mask\n");
+		netif_err(efx, probe, efx->net_dev,
+			  "failed to set consistent DMA mask\n");
 		goto fail2;
 	}
 
 	efx->membase_phys = pci_resource_start(efx->pci_dev, EFX_MEM_BAR);
 	rc = pci_request_region(pci_dev, EFX_MEM_BAR, "sfc");
 	if (rc) {
-		EFX_ERR(efx, "request for memory BAR failed\n");
+		netif_err(efx, probe, efx->net_dev,
+			  "request for memory BAR failed\n");
 		rc = -EIO;
 		goto fail3;
 	}
 	efx->membase = ioremap_nocache(efx->membase_phys,
 				       efx->type->mem_map_size);
 	if (!efx->membase) {
-		EFX_ERR(efx, "could not map memory BAR at %llx+%x\n",
-			(unsigned long long)efx->membase_phys,
-			efx->type->mem_map_size);
+		netif_err(efx, probe, efx->net_dev,
+			  "could not map memory BAR at %llx+%x\n",
+			  (unsigned long long)efx->membase_phys,
+			  efx->type->mem_map_size);
 		rc = -ENOMEM;
 		goto fail4;
 	}
-	EFX_LOG(efx, "memory BAR at %llx+%x (virtual %p)\n",
-		(unsigned long long)efx->membase_phys,
-		efx->type->mem_map_size, efx->membase);
+	netif_dbg(efx, probe, efx->net_dev,
+		  "memory BAR at %llx+%x (virtual %p)\n",
+		  (unsigned long long)efx->membase_phys,
+		  efx->type->mem_map_size, efx->membase);
 
 	return 0;
 
@@ -938,7 +962,7 @@
 
 static void efx_fini_io(struct efx_nic *efx)
 {
-	EFX_LOG(efx, "shutting down I/O\n");
+	netif_dbg(efx, drv, efx->net_dev, "shutting down I/O\n");
 
 	if (efx->membase) {
 		iounmap(efx->membase);
@@ -1002,9 +1026,11 @@
 			xentries[i].entry = i;
 		rc = pci_enable_msix(efx->pci_dev, xentries, n_channels);
 		if (rc > 0) {
-			EFX_ERR(efx, "WARNING: Insufficient MSI-X vectors"
-				" available (%d < %d).\n", rc, n_channels);
-			EFX_ERR(efx, "WARNING: Performance may be reduced.\n");
+			netif_err(efx, drv, efx->net_dev,
+				  "WARNING: Insufficient MSI-X vectors"
+				  " available (%d < %d).\n", rc, n_channels);
+			netif_err(efx, drv, efx->net_dev,
+				  "WARNING: Performance may be reduced.\n");
 			EFX_BUG_ON_PARANOID(rc >= n_channels);
 			n_channels = rc;
 			rc = pci_enable_msix(efx->pci_dev, xentries,
@@ -1028,7 +1054,8 @@
 		} else {
 			/* Fall back to single channel MSI */
 			efx->interrupt_mode = EFX_INT_MODE_MSI;
-			EFX_ERR(efx, "could not enable MSI-X\n");
+			netif_err(efx, drv, efx->net_dev,
+				  "could not enable MSI-X\n");
 		}
 	}
 
@@ -1041,7 +1068,8 @@
 		if (rc == 0) {
 			efx->channel[0].irq = efx->pci_dev->irq;
 		} else {
-			EFX_ERR(efx, "could not enable MSI\n");
+			netif_err(efx, drv, efx->net_dev,
+				  "could not enable MSI\n");
 			efx->interrupt_mode = EFX_INT_MODE_LEGACY;
 		}
 	}
@@ -1093,9 +1121,10 @@
 
 static int efx_probe_nic(struct efx_nic *efx)
 {
+	size_t i;
 	int rc;
 
-	EFX_LOG(efx, "creating NIC\n");
+	netif_dbg(efx, probe, efx->net_dev, "creating NIC\n");
 
 	/* Carry out hardware-type specific initialisation */
 	rc = efx->type->probe(efx);
@@ -1106,6 +1135,11 @@
 	 * in MSI-X interrupts. */
 	efx_probe_interrupts(efx);
 
+	if (efx->n_channels > 1)
+		get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key));
+	for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
+		efx->rx_indir_table[i] = i % efx->n_rx_channels;
+
 	efx_set_channels(efx);
 	efx->net_dev->real_num_tx_queues = efx->n_tx_channels;
 
@@ -1117,7 +1151,7 @@
 
 static void efx_remove_nic(struct efx_nic *efx)
 {
-	EFX_LOG(efx, "destroying NIC\n");
+	netif_dbg(efx, drv, efx->net_dev, "destroying NIC\n");
 
 	efx_remove_interrupts(efx);
 	efx->type->remove(efx);
@@ -1137,14 +1171,14 @@
 	/* Create NIC */
 	rc = efx_probe_nic(efx);
 	if (rc) {
-		EFX_ERR(efx, "failed to create NIC\n");
+		netif_err(efx, probe, efx->net_dev, "failed to create NIC\n");
 		goto fail1;
 	}
 
 	/* Create port */
 	rc = efx_probe_port(efx);
 	if (rc) {
-		EFX_ERR(efx, "failed to create port\n");
+		netif_err(efx, probe, efx->net_dev, "failed to create port\n");
 		goto fail2;
 	}
 
@@ -1152,8 +1186,9 @@
 	efx_for_each_channel(channel, efx) {
 		rc = efx_probe_channel(channel);
 		if (rc) {
-			EFX_ERR(efx, "failed to create channel %d\n",
-				channel->channel);
+			netif_err(efx, probe, efx->net_dev,
+				  "failed to create channel %d\n",
+				  channel->channel);
 			goto fail3;
 		}
 	}
@@ -1233,15 +1268,8 @@
  * since we're holding the rtnl_lock at this point. */
 static void efx_flush_all(struct efx_nic *efx)
 {
-	struct efx_rx_queue *rx_queue;
-
 	/* Make sure the hardware monitor is stopped */
 	cancel_delayed_work_sync(&efx->monitor_work);
-
-	/* Ensure that all RX slow refills are complete. */
-	efx_for_each_rx_queue(rx_queue, efx)
-		cancel_delayed_work_sync(&rx_queue->work);
-
 	/* Stop scheduled port reconfigurations */
 	cancel_work_sync(&efx->mac_work);
 }
@@ -1356,8 +1384,9 @@
 	struct efx_nic *efx = container_of(data, struct efx_nic,
 					   monitor_work.work);
 
-	EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
-		  raw_smp_processor_id());
+	netif_vdbg(efx, timer, efx->net_dev,
+		   "hardware monitor executing on CPU %d\n",
+		   raw_smp_processor_id());
 	BUG_ON(efx->type->monitor == NULL);
 
 	/* If the mac_lock is already held then it is likely a port
@@ -1464,8 +1493,8 @@
 	struct efx_nic *efx = netdev_priv(net_dev);
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
-	EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name,
-		raw_smp_processor_id());
+	netif_dbg(efx, ifup, efx->net_dev, "opening device on CPU %d\n",
+		  raw_smp_processor_id());
 
 	if (efx->state == STATE_DISABLED)
 		return -EIO;
@@ -1490,8 +1519,8 @@
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
 
-	EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name,
-		raw_smp_processor_id());
+	netif_dbg(efx, ifdown, efx->net_dev, "closing on CPU %d\n",
+		  raw_smp_processor_id());
 
 	if (efx->state != STATE_DISABLED) {
 		/* Stop the device and flush all the channels */
@@ -1504,11 +1533,10 @@
 }
 
 /* Context: process, dev_base_lock or RTNL held, non-blocking. */
-static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
+static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev, struct rtnl_link_stats64 *stats)
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
 	struct efx_mac_stats *mac_stats = &efx->mac_stats;
-	struct net_device_stats *stats = &net_dev->stats;
 
 	spin_lock_bh(&efx->stats_lock);
 	efx->type->update_stats(efx);
@@ -1530,11 +1558,8 @@
 	stats->tx_window_errors = mac_stats->tx_late_collision;
 
 	stats->rx_errors = (stats->rx_length_errors +
-			    stats->rx_over_errors +
 			    stats->rx_crc_errors +
 			    stats->rx_frame_errors +
-			    stats->rx_fifo_errors +
-			    stats->rx_missed_errors +
 			    mac_stats->rx_symbol_error);
 	stats->tx_errors = (stats->tx_window_errors +
 			    mac_stats->tx_bad);
@@ -1547,8 +1572,9 @@
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
 
-	EFX_ERR(efx, "TX stuck with port_enabled=%d: resetting channels\n",
-		efx->port_enabled);
+	netif_err(efx, tx_err, efx->net_dev,
+		  "TX stuck with port_enabled=%d: resetting channels\n",
+		  efx->port_enabled);
 
 	efx_schedule_reset(efx, RESET_TYPE_TX_WATCHDOG);
 }
@@ -1567,7 +1593,7 @@
 
 	efx_stop_all(efx);
 
-	EFX_LOG(efx, "changing MTU to %d\n", new_mtu);
+	netif_dbg(efx, drv, efx->net_dev, "changing MTU to %d\n", new_mtu);
 
 	efx_fini_channels(efx);
 
@@ -1593,8 +1619,9 @@
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
 	if (!is_valid_ether_addr(new_addr)) {
-		EFX_ERR(efx, "invalid ethernet MAC address requested: %pM\n",
-			new_addr);
+		netif_err(efx, drv, efx->net_dev,
+			  "invalid ethernet MAC address requested: %pM\n",
+			  new_addr);
 		return -EINVAL;
 	}
 
@@ -1645,7 +1672,7 @@
 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_get_stats64	= efx_net_stats,
 	.ndo_tx_timeout		= efx_watchdog,
 	.ndo_start_xmit		= efx_hard_start_xmit,
 	.ndo_validate_addr	= eth_validate_addr,
@@ -1697,7 +1724,6 @@
 	net_dev->watchdog_timeo = 5 * HZ;
 	net_dev->irq = efx->pci_dev->irq;
 	net_dev->netdev_ops = &efx_netdev_ops;
-	SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev);
 	SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
 
 	/* Clear MAC statistics */
@@ -1722,7 +1748,8 @@
 
 	rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type);
 	if (rc) {
-		EFX_ERR(efx, "failed to init net dev attributes\n");
+		netif_err(efx, drv, efx->net_dev,
+			  "failed to init net dev attributes\n");
 		goto fail_registered;
 	}
 
@@ -1730,7 +1757,7 @@
 
 fail_locked:
 	rtnl_unlock();
-	EFX_ERR(efx, "could not register net dev\n");
+	netif_err(efx, drv, efx->net_dev, "could not register net dev\n");
 	return rc;
 
 fail_registered:
@@ -1795,7 +1822,7 @@
 
 	rc = efx->type->init(efx);
 	if (rc) {
-		EFX_ERR(efx, "failed to initialise NIC\n");
+		netif_err(efx, drv, efx->net_dev, "failed to initialise NIC\n");
 		goto fail;
 	}
 
@@ -1807,7 +1834,8 @@
 		if (rc)
 			goto fail;
 		if (efx->phy_op->reconfigure(efx))
-			EFX_ERR(efx, "could not restore PHY settings\n");
+			netif_err(efx, drv, efx->net_dev,
+				  "could not restore PHY settings\n");
 	}
 
 	efx->mac_op->reconfigure(efx);
@@ -1840,13 +1868,14 @@
 	int rc, rc2;
 	bool disabled;
 
-	EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method));
+	netif_info(efx, drv, efx->net_dev, "resetting (%s)\n",
+		   RESET_TYPE(method));
 
 	efx_reset_down(efx, method);
 
 	rc = efx->type->reset(efx, method);
 	if (rc) {
-		EFX_ERR(efx, "failed to reset hardware\n");
+		netif_err(efx, drv, efx->net_dev, "failed to reset hardware\n");
 		goto out;
 	}
 
@@ -1871,10 +1900,10 @@
 
 	if (disabled) {
 		dev_close(efx->net_dev);
-		EFX_ERR(efx, "has been disabled\n");
+		netif_err(efx, drv, efx->net_dev, "has been disabled\n");
 		efx->state = STATE_DISABLED;
 	} else {
-		EFX_LOG(efx, "reset complete\n");
+		netif_dbg(efx, drv, efx->net_dev, "reset complete\n");
 	}
 	return rc;
 }
@@ -1886,10 +1915,14 @@
 {
 	struct efx_nic *efx = container_of(data, struct efx_nic, reset_work);
 
+	if (efx->reset_pending == RESET_TYPE_NONE)
+		return;
+
 	/* If we're not RUNNING then don't reset. Leave the reset_pending
 	 * 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");
+		netif_info(efx, drv, efx->net_dev,
+			   "scheduled reset quenched. NIC not RUNNING\n");
 		return;
 	}
 
@@ -1903,7 +1936,8 @@
 	enum reset_type method;
 
 	if (efx->reset_pending != RESET_TYPE_NONE) {
-		EFX_INFO(efx, "quenching already scheduled reset\n");
+		netif_info(efx, drv, efx->net_dev,
+			   "quenching already scheduled reset\n");
 		return;
 	}
 
@@ -1927,10 +1961,12 @@
 	}
 
 	if (method != type)
-		EFX_LOG(efx, "scheduling %s reset for %s\n",
-			RESET_TYPE(method), RESET_TYPE(type));
+		netif_dbg(efx, drv, efx->net_dev,
+			  "scheduling %s reset for %s\n",
+			  RESET_TYPE(method), RESET_TYPE(type));
 	else
-		EFX_LOG(efx, "scheduling %s reset\n", RESET_TYPE(method));
+		netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n",
+			  RESET_TYPE(method));
 
 	efx->reset_pending = method;
 
@@ -2017,6 +2053,7 @@
 	INIT_WORK(&efx->reset_work, efx_reset_work);
 	INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor);
 	efx->pci_dev = pci_dev;
+	efx->msg_enable = debug;
 	efx->state = STATE_INIT;
 	efx->reset_pending = RESET_TYPE_NONE;
 	strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name));
@@ -2052,8 +2089,8 @@
 		rx_queue->queue = i;
 		rx_queue->channel = &efx->channel[0]; /* for safety */
 		rx_queue->buffer = NULL;
-		spin_lock_init(&rx_queue->add_lock);
-		INIT_DELAYED_WORK(&rx_queue->work, efx_rx_work);
+		setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill,
+			    (unsigned long)rx_queue);
 	}
 
 	efx->type = type;
@@ -2136,7 +2173,7 @@
 	efx_pci_remove_main(efx);
 
 	efx_fini_io(efx);
-	EFX_LOG(efx, "shutdown successful\n");
+	netif_dbg(efx, drv, efx->net_dev, "shutdown successful\n");
 
 	pci_set_drvdata(pci_dev, NULL);
 	efx_fini_struct(efx);
@@ -2161,13 +2198,15 @@
 
 	rc = efx->type->init(efx);
 	if (rc) {
-		EFX_ERR(efx, "failed to initialise NIC\n");
+		netif_err(efx, probe, efx->net_dev,
+			  "failed to initialise NIC\n");
 		goto fail3;
 	}
 
 	rc = efx_init_port(efx);
 	if (rc) {
-		EFX_ERR(efx, "failed to initialise port\n");
+		netif_err(efx, probe, efx->net_dev,
+			  "failed to initialise port\n");
 		goto fail4;
 	}
 
@@ -2223,11 +2262,13 @@
 				   NETIF_F_HIGHDMA | NETIF_F_TSO);
 	efx = netdev_priv(net_dev);
 	pci_set_drvdata(pci_dev, efx);
+	SET_NETDEV_DEV(net_dev, &pci_dev->dev);
 	rc = efx_init_struct(efx, type, pci_dev, net_dev);
 	if (rc)
 		goto fail1;
 
-	EFX_INFO(efx, "Solarflare Communications NIC detected\n");
+	netif_info(efx, probe, efx->net_dev,
+		   "Solarflare Communications NIC detected\n");
 
 	/* Set up basic I/O (BAR mappings etc) */
 	rc = efx_init_io(efx);
@@ -2265,7 +2306,7 @@
 	}
 
 	if (rc) {
-		EFX_ERR(efx, "Could not reset NIC\n");
+		netif_err(efx, probe, efx->net_dev, "Could not reset NIC\n");
 		goto fail4;
 	}
 
@@ -2277,7 +2318,7 @@
 	if (rc)
 		goto fail5;
 
-	EFX_LOG(efx, "initialisation successful\n");
+	netif_dbg(efx, probe, efx->net_dev, "initialisation successful\n");
 
 	rtnl_lock();
 	efx_mtd_probe(efx); /* allowed to fail */
@@ -2293,7 +2334,7 @@
 	efx_fini_struct(efx);
  fail1:
 	WARN_ON(rc > 0);
-	EFX_LOG(efx, "initialisation failed. rc=%d\n", rc);
+	netif_dbg(efx, drv, efx->net_dev, "initialisation failed. rc=%d\n", rc);
 	free_netdev(net_dev);
 	return rc;
 }
@@ -2332,6 +2373,9 @@
 
 	efx->type->resume_wol(efx);
 
+	/* Reschedule any quenched resets scheduled during efx_pm_freeze() */
+	queue_work(reset_workqueue, &efx->reset_work);
+
 	return 0;
 }
 
@@ -2394,7 +2438,7 @@
 };
 
 static struct pci_driver efx_pci_driver = {
-	.name		= EFX_DRIVER_NAME,
+	.name		= KBUILD_MODNAME,
 	.id_table	= efx_pci_table,
 	.probe		= efx_pci_probe,
 	.remove		= efx_pci_remove,
@@ -2421,11 +2465,6 @@
 	if (rc)
 		goto err_notifier;
 
-	refill_workqueue = create_workqueue("sfc_refill");
-	if (!refill_workqueue) {
-		rc = -ENOMEM;
-		goto err_refill;
-	}
 	reset_workqueue = create_singlethread_workqueue("sfc_reset");
 	if (!reset_workqueue) {
 		rc = -ENOMEM;
@@ -2441,8 +2480,6 @@
  err_pci:
 	destroy_workqueue(reset_workqueue);
  err_reset:
-	destroy_workqueue(refill_workqueue);
- err_refill:
 	unregister_netdevice_notifier(&efx_netdev_notifier);
  err_notifier:
 	return rc;
@@ -2454,7 +2491,6 @@
 
 	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 ffd708c..060dc95 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -47,12 +47,12 @@
 extern void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
 extern void efx_rx_strategy(struct efx_channel *channel);
 extern void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
-extern void efx_rx_work(struct work_struct *data);
+extern void efx_rx_slow_fill(unsigned long context);
 extern void __efx_rx_packet(struct efx_channel *channel,
 			    struct efx_rx_buffer *rx_buf, bool checksummed);
 extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
 			  unsigned int len, bool checksummed, bool discard);
-extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay);
+extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
 #define EFX_RXQ_SIZE 1024
 #define EFX_RXQ_MASK (EFX_RXQ_SIZE - 1)
 
@@ -106,8 +106,9 @@
 
 static inline void efx_schedule_channel(struct efx_channel *channel)
 {
-	EFX_TRACE(channel->efx, "channel %d scheduling NAPI poll on CPU%d\n",
-		  channel->channel, raw_smp_processor_id());
+	netif_vdbg(channel->efx, intr, channel->efx->net_dev,
+		   "channel %d scheduling NAPI poll on CPU%d\n",
+		   channel->channel, raw_smp_processor_id());
 	channel->work_pending = true;
 
 	napi_schedule(&channel->napi_str);
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 22026bf..fd19d6a 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -218,8 +218,8 @@
 
 	/* GMAC does not support 1000Mbps HD */
 	if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) {
-		EFX_LOG(efx, "rejecting unsupported 1000Mbps HD"
-			" setting\n");
+		netif_dbg(efx, drv, efx->net_dev,
+			  "rejecting unsupported 1000Mbps HD setting\n");
 		return -EINVAL;
 	}
 
@@ -234,7 +234,7 @@
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
 
-	strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver));
+	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
 	strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
 	if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
 		siena_print_fwver(efx, info->fw_version,
@@ -242,6 +242,32 @@
 	strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));
 }
 
+static int efx_ethtool_get_regs_len(struct net_device *net_dev)
+{
+	return efx_nic_get_regs_len(netdev_priv(net_dev));
+}
+
+static void efx_ethtool_get_regs(struct net_device *net_dev,
+				 struct ethtool_regs *regs, void *buf)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+
+	regs->version = efx->type->revision;
+	efx_nic_get_regs(efx, buf);
+}
+
+static u32 efx_ethtool_get_msglevel(struct net_device *net_dev)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+	return efx->msg_enable;
+}
+
+static void efx_ethtool_set_msglevel(struct net_device *net_dev, u32 msg_enable)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+	efx->msg_enable = msg_enable;
+}
+
 /**
  * efx_fill_test - fill in an individual self-test entry
  * @test_index:		Index of the test
@@ -443,12 +469,13 @@
 	struct efx_mac_stats *mac_stats = &efx->mac_stats;
 	struct efx_ethtool_stat *stat;
 	struct efx_channel *channel;
+	struct rtnl_link_stats64 temp;
 	int i;
 
 	EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
 
 	/* Update MAC and NIC statistics */
-	dev_get_stats(net_dev);
+	dev_get_stats(net_dev, &temp);
 
 	/* Fill detailed statistics buffer */
 	for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {
@@ -520,6 +547,14 @@
 	return efx->rx_checksum_enabled;
 }
 
+static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+	u32 supported = efx->type->offload_features & ETH_FLAG_RXHASH;
+
+	return ethtool_op_set_flags(net_dev, data, supported);
+}
+
 static void efx_ethtool_self_test(struct net_device *net_dev,
 				  struct ethtool_test *test, u64 *data)
 {
@@ -539,7 +574,8 @@
 	if (!already_up) {
 		rc = dev_open(efx->net_dev);
 		if (rc) {
-			EFX_ERR(efx, "failed opening device.\n");
+			netif_err(efx, drv, efx->net_dev,
+				  "failed opening device.\n");
 			goto fail2;
 		}
 	}
@@ -551,9 +587,9 @@
 	if (!already_up)
 		dev_close(efx->net_dev);
 
-	EFX_LOG(efx, "%s %sline self-tests\n",
-		rc == 0 ? "passed" : "failed",
-		(test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
+	netif_dbg(efx, drv, efx->net_dev, "%s %sline self-tests\n",
+		  rc == 0 ? "passed" : "failed",
+		  (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
 
  fail2:
  fail1:
@@ -679,8 +715,8 @@
 		return -EOPNOTSUPP;
 
 	if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) {
-		EFX_ERR(efx, "invalid coalescing setting. "
-			"Only rx/tx_coalesce_usecs_irq are supported\n");
+		netif_err(efx, drv, efx->net_dev, "invalid coalescing setting. "
+			  "Only rx/tx_coalesce_usecs_irq are supported\n");
 		return -EOPNOTSUPP;
 	}
 
@@ -692,8 +728,8 @@
 	efx_for_each_tx_queue(tx_queue, efx) {
 		if ((tx_queue->channel->channel < efx->n_rx_channels) &&
 		    tx_usecs) {
-			EFX_ERR(efx, "Channel is shared. "
-				"Only RX coalescing may be set\n");
+			netif_err(efx, drv, efx->net_dev, "Channel is shared. "
+				  "Only RX coalescing may be set\n");
 			return -EOPNOTSUPP;
 		}
 	}
@@ -721,13 +757,15 @@
 		     (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");
+		netif_dbg(efx, drv, efx->net_dev,
+			  "Flow control unsupported: tx ON rx OFF\n");
 		rc = -EINVAL;
 		goto out;
 	}
 
 	if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising) {
-		EFX_LOG(efx, "Autonegotiation is disabled\n");
+		netif_dbg(efx, drv, efx->net_dev,
+			  "Autonegotiation is disabled\n");
 		rc = -EINVAL;
 		goto out;
 	}
@@ -758,8 +796,9 @@
 	    (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) {
 		rc = efx->phy_op->reconfigure(efx);
 		if (rc) {
-			EFX_ERR(efx, "Unable to advertise requested flow "
-				"control setting\n");
+			netif_err(efx, drv, efx->net_dev,
+				  "Unable to advertise requested flow "
+				  "control setting\n");
 			goto out;
 		}
 	}
@@ -830,10 +869,101 @@
 	return efx_reset(efx, method);
 }
 
+static int
+efx_ethtool_get_rxnfc(struct net_device *net_dev,
+		      struct ethtool_rxnfc *info, void *rules __always_unused)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+
+	switch (info->cmd) {
+	case ETHTOOL_GRXRINGS:
+		info->data = efx->n_rx_channels;
+		return 0;
+
+	case ETHTOOL_GRXFH: {
+		unsigned min_revision = 0;
+
+		info->data = 0;
+		switch (info->flow_type) {
+		case TCP_V4_FLOW:
+			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+			/* fall through */
+		case UDP_V4_FLOW:
+		case SCTP_V4_FLOW:
+		case AH_ESP_V4_FLOW:
+		case IPV4_FLOW:
+			info->data |= RXH_IP_SRC | RXH_IP_DST;
+			min_revision = EFX_REV_FALCON_B0;
+			break;
+		case TCP_V6_FLOW:
+			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+			/* fall through */
+		case UDP_V6_FLOW:
+		case SCTP_V6_FLOW:
+		case AH_ESP_V6_FLOW:
+		case IPV6_FLOW:
+			info->data |= RXH_IP_SRC | RXH_IP_DST;
+			min_revision = EFX_REV_SIENA_A0;
+			break;
+		default:
+			break;
+		}
+		if (efx_nic_rev(efx) < min_revision)
+			info->data = 0;
+		return 0;
+	}
+
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev,
+				      struct ethtool_rxfh_indir *indir)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+	size_t copy_size =
+		min_t(size_t, indir->size, ARRAY_SIZE(efx->rx_indir_table));
+
+	if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
+		return -EOPNOTSUPP;
+
+	indir->size = ARRAY_SIZE(efx->rx_indir_table);
+	memcpy(indir->ring_index, efx->rx_indir_table,
+	       copy_size * sizeof(indir->ring_index[0]));
+	return 0;
+}
+
+static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev,
+				      const struct ethtool_rxfh_indir *indir)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+	size_t i;
+
+	if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
+		return -EOPNOTSUPP;
+
+	/* Validate size and indices */
+	if (indir->size != ARRAY_SIZE(efx->rx_indir_table))
+		return -EINVAL;
+	for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
+		if (indir->ring_index[i] >= efx->n_rx_channels)
+			return -EINVAL;
+
+	memcpy(efx->rx_indir_table, indir->ring_index,
+	       sizeof(efx->rx_indir_table));
+	efx_nic_push_rx_indir_table(efx);
+	return 0;
+}
+
 const struct ethtool_ops efx_ethtool_ops = {
 	.get_settings		= efx_ethtool_get_settings,
 	.set_settings		= efx_ethtool_set_settings,
 	.get_drvinfo		= efx_ethtool_get_drvinfo,
+	.get_regs_len		= efx_ethtool_get_regs_len,
+	.get_regs		= efx_ethtool_get_regs,
+	.get_msglevel		= efx_ethtool_get_msglevel,
+	.set_msglevel		= efx_ethtool_set_msglevel,
 	.nway_reset		= efx_ethtool_nway_reset,
 	.get_link		= efx_ethtool_get_link,
 	.get_eeprom_len		= efx_ethtool_get_eeprom_len,
@@ -854,7 +984,7 @@
 	/* Need to enable/disable TSO-IPv6 too */
 	.set_tso		= efx_ethtool_set_tso,
 	.get_flags		= ethtool_op_get_flags,
-	.set_flags		= ethtool_op_set_flags,
+	.set_flags		= efx_ethtool_set_flags,
 	.get_sset_count		= efx_ethtool_get_sset_count,
 	.self_test		= efx_ethtool_self_test,
 	.get_strings		= efx_ethtool_get_strings,
@@ -863,4 +993,7 @@
 	.get_wol                = efx_ethtool_get_wol,
 	.set_wol                = efx_ethtool_set_wol,
 	.reset			= efx_ethtool_reset,
+	.get_rxnfc		= efx_ethtool_get_rxnfc,
+	.get_rxfh_indir		= efx_ethtool_get_rxfh_indir,
+	.set_rxfh_indir		= efx_ethtool_set_rxfh_indir,
 };
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 655b697..4f9d33f 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -167,13 +167,15 @@
 	 * exit without having touched the hardware.
 	 */
 	if (unlikely(EFX_OWORD_IS_ZERO(*int_ker))) {
-		EFX_TRACE(efx, "IRQ %d on CPU %d not for me\n", irq,
-			  raw_smp_processor_id());
+		netif_vdbg(efx, intr, efx->net_dev,
+			   "IRQ %d on CPU %d not for me\n", irq,
+			   raw_smp_processor_id());
 		return IRQ_NONE;
 	}
 	efx->last_irq_cpu = raw_smp_processor_id();
-	EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
-		  irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
+	netif_vdbg(efx, intr, efx->net_dev,
+		   "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
+		   irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
 
 	/* Determine interrupting queues, clear interrupt status
 	 * register and acknowledge the device interrupt.
@@ -239,7 +241,8 @@
 		if (!falcon_spi_poll(efx))
 			return 0;
 		if (time_after_eq(jiffies, timeout)) {
-			EFX_ERR(efx, "timed out waiting for SPI\n");
+			netif_err(efx, hw, efx->net_dev,
+				  "timed out waiting for SPI\n");
 			return -ETIMEDOUT;
 		}
 		schedule_timeout_uninterruptible(1);
@@ -333,9 +336,10 @@
 		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);
+			netif_err(efx, hw, efx->net_dev,
+				  "SPI write timeout on device %d"
+				  " last status=0x%02x\n",
+				  spi->device_id, status);
 			return -ETIMEDOUT;
 		}
 		schedule_timeout_uninterruptible(1);
@@ -469,7 +473,8 @@
 				udelay(10);
 			}
 
-			EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
+			netif_err(efx, hw, efx->net_dev,
+				  "timed out waiting for XMAC core reset\n");
 		}
 	}
 
@@ -492,12 +497,13 @@
 		if (!EFX_OWORD_FIELD(reg, FRF_AB_RST_XGTX) &&
 		    !EFX_OWORD_FIELD(reg, FRF_AB_RST_XGRX) &&
 		    !EFX_OWORD_FIELD(reg, FRF_AB_RST_EM)) {
-			EFX_LOG(efx, "Completed MAC reset after %d loops\n",
-				count);
+			netif_dbg(efx, hw, efx->net_dev,
+				  "Completed MAC reset after %d loops\n",
+				  count);
 			break;
 		}
 		if (count > 20) {
-			EFX_ERR(efx, "MAC reset failed\n");
+			netif_err(efx, hw, efx->net_dev, "MAC reset failed\n");
 			break;
 		}
 		count++;
@@ -548,7 +554,9 @@
 {
 	struct efx_link_state *link_state = &efx->link_state;
 	efx_oword_t reg;
-	int link_speed;
+	int link_speed, isolate;
+
+	isolate = (efx->reset_pending != RESET_TYPE_NONE);
 
 	switch (link_state->speed) {
 	case 10000: link_speed = 3; break;
@@ -570,7 +578,7 @@
 	 * discarded. */
 	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
 		EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN,
-				    !link_state->up);
+				    !link_state->up || isolate);
 	}
 
 	efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
@@ -584,7 +592,7 @@
 	EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
 	/* Unisolate the MAC -> RX */
 	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
-		EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
+		EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, !isolate);
 	efx_writeo(efx, &reg, FR_AZ_RX_CFG);
 }
 
@@ -625,7 +633,8 @@
 		rmb(); /* read the done flag before the stats */
 		efx->mac_op->update_stats(efx);
 	} else {
-		EFX_ERR(efx, "timed out waiting for statistics\n");
+		netif_err(efx, hw, efx->net_dev,
+			  "timed out waiting for statistics\n");
 	}
 }
 
@@ -715,16 +724,17 @@
 		if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) {
 			if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_LNFL) != 0 ||
 			    EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSERR) != 0) {
-				EFX_ERR(efx, "error from GMII access "
-					EFX_OWORD_FMT"\n",
-					EFX_OWORD_VAL(md_stat));
+				netif_err(efx, hw, efx->net_dev,
+					  "error from GMII access "
+					  EFX_OWORD_FMT"\n",
+					  EFX_OWORD_VAL(md_stat));
 				return -EIO;
 			}
 			return 0;
 		}
 		udelay(10);
 	}
-	EFX_ERR(efx, "timed out waiting for GMII\n");
+	netif_err(efx, hw, efx->net_dev, "timed out waiting for GMII\n");
 	return -ETIMEDOUT;
 }
 
@@ -736,7 +746,8 @@
 	efx_oword_t reg;
 	int rc;
 
-	EFX_REGDUMP(efx, "writing MDIO %d register %d.%d with 0x%04x\n",
+	netif_vdbg(efx, hw, efx->net_dev,
+		   "writing MDIO %d register %d.%d with 0x%04x\n",
 		    prtad, devad, addr, value);
 
 	mutex_lock(&efx->mdio_lock);
@@ -810,8 +821,9 @@
 	if (rc == 0) {
 		efx_reado(efx, &reg, FR_AB_MD_RXD);
 		rc = EFX_OWORD_FIELD(reg, FRF_AB_MD_RXD);
-		EFX_REGDUMP(efx, "read from MDIO %d register %d.%d, got %04x\n",
-			    prtad, devad, addr, rc);
+		netif_vdbg(efx, hw, efx->net_dev,
+			   "read from MDIO %d register %d.%d, got %04x\n",
+			   prtad, devad, addr, rc);
 	} else {
 		/* Abort the read operation */
 		EFX_POPULATE_OWORD_2(reg,
@@ -819,8 +831,9 @@
 				     FRF_AB_MD_GC, 1);
 		efx_writeo(efx, &reg, FR_AB_MD_CS);
 
-		EFX_LOG(efx, "read from MDIO %d register %d.%d, got error %d\n",
-			prtad, devad, addr, rc);
+		netif_dbg(efx, hw, efx->net_dev,
+			  "read from MDIO %d register %d.%d, got error %d\n",
+			  prtad, devad, addr, rc);
 	}
 
 out:
@@ -871,7 +884,8 @@
 
 	falcon_clock_mac(efx);
 
-	EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G');
+	netif_dbg(efx, hw, efx->net_dev, "selected %cMAC\n",
+		  EFX_IS10G(efx) ? 'X' : 'G');
 	/* Not all macs support a mac-level link state */
 	efx->xmac_poll_required = false;
 	falcon_reset_macs(efx);
@@ -895,8 +909,8 @@
 		efx->phy_op = &falcon_qt202x_phy_ops;
 		break;
 	default:
-		EFX_ERR(efx, "Unknown PHY type %d\n",
-			efx->phy_type);
+		netif_err(efx, probe, efx->net_dev, "Unknown PHY type %d\n",
+			  efx->phy_type);
 		return -ENODEV;
 	}
 
@@ -924,10 +938,11 @@
 				  FALCON_MAC_STATS_SIZE);
 	if (rc)
 		return rc;
-	EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n",
-		(u64)efx->stats_buffer.dma_addr,
-		efx->stats_buffer.addr,
-		(u64)virt_to_phys(efx->stats_buffer.addr));
+	netif_dbg(efx, probe, efx->net_dev,
+		  "stats buffer at %llx (virt %p phys %llx)\n",
+		  (u64)efx->stats_buffer.dma_addr,
+		  efx->stats_buffer.addr,
+		  (u64)virt_to_phys(efx->stats_buffer.addr));
 
 	return 0;
 }
@@ -967,8 +982,8 @@
 	rc = falcon_spi_read(efx, 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");
+		netif_err(efx, hw, efx->net_dev, "Failed to read %s\n",
+			  efx->spi_flash ? "flash" : "EEPROM");
 		rc = -EIO;
 		goto out;
 	}
@@ -978,11 +993,13 @@
 
 	rc = -EINVAL;
 	if (magic_num != FALCON_NVCONFIG_BOARD_MAGIC_NUM) {
-		EFX_ERR(efx, "NVRAM bad magic 0x%x\n", magic_num);
+		netif_err(efx, hw, efx->net_dev,
+			  "NVRAM bad magic 0x%x\n", magic_num);
 		goto out;
 	}
 	if (struct_ver < 2) {
-		EFX_ERR(efx, "NVRAM has ancient version 0x%x\n", struct_ver);
+		netif_err(efx, hw, efx->net_dev,
+			  "NVRAM has ancient version 0x%x\n", struct_ver);
 		goto out;
 	} else if (struct_ver < 4) {
 		word = &nvconfig->board_magic_num;
@@ -995,7 +1012,8 @@
 		csum += le16_to_cpu(*word);
 
 	if (~csum & 0xffff) {
-		EFX_ERR(efx, "NVRAM has incorrect checksum\n");
+		netif_err(efx, hw, efx->net_dev,
+			  "NVRAM has incorrect checksum\n");
 		goto out;
 	}
 
@@ -1073,22 +1091,25 @@
 	efx_oword_t glb_ctl_reg_ker;
 	int rc;
 
-	EFX_LOG(efx, "performing %s hardware reset\n", RESET_TYPE(method));
+	netif_dbg(efx, hw, efx->net_dev, "performing %s hardware reset\n",
+		  RESET_TYPE(method));
 
 	/* Initiate device reset */
 	if (method == RESET_TYPE_WORLD) {
 		rc = pci_save_state(efx->pci_dev);
 		if (rc) {
-			EFX_ERR(efx, "failed to backup PCI state of primary "
-				"function prior to hardware reset\n");
+			netif_err(efx, drv, efx->net_dev,
+				  "failed to backup PCI state of primary "
+				  "function prior to hardware reset\n");
 			goto fail1;
 		}
 		if (efx_nic_is_dual_func(efx)) {
 			rc = pci_save_state(nic_data->pci_dev2);
 			if (rc) {
-				EFX_ERR(efx, "failed to backup PCI state of "
-					"secondary function prior to "
-					"hardware reset\n");
+				netif_err(efx, drv, efx->net_dev,
+					  "failed to backup PCI state of "
+					  "secondary function prior to "
+					  "hardware reset\n");
 				goto fail2;
 			}
 		}
@@ -1113,7 +1134,7 @@
 	}
 	efx_writeo(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL);
 
-	EFX_LOG(efx, "waiting for hardware reset\n");
+	netif_dbg(efx, hw, efx->net_dev, "waiting for hardware reset\n");
 	schedule_timeout_uninterruptible(HZ / 20);
 
 	/* Restore PCI configuration if needed */
@@ -1121,28 +1142,32 @@
 		if (efx_nic_is_dual_func(efx)) {
 			rc = pci_restore_state(nic_data->pci_dev2);
 			if (rc) {
-				EFX_ERR(efx, "failed to restore PCI config for "
-					"the secondary function\n");
+				netif_err(efx, drv, efx->net_dev,
+					  "failed to restore PCI config for "
+					  "the secondary function\n");
 				goto fail3;
 			}
 		}
 		rc = pci_restore_state(efx->pci_dev);
 		if (rc) {
-			EFX_ERR(efx, "failed to restore PCI config for the "
-				"primary function\n");
+			netif_err(efx, drv, efx->net_dev,
+				  "failed to restore PCI config for the "
+				  "primary function\n");
 			goto fail4;
 		}
-		EFX_LOG(efx, "successfully restored PCI config\n");
+		netif_dbg(efx, drv, efx->net_dev,
+			  "successfully restored PCI config\n");
 	}
 
 	/* Assert that reset complete */
 	efx_reado(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL);
 	if (EFX_OWORD_FIELD(glb_ctl_reg_ker, FRF_AB_SWRST) != 0) {
 		rc = -ETIMEDOUT;
-		EFX_ERR(efx, "timed out waiting for hardware reset\n");
+		netif_err(efx, hw, efx->net_dev,
+			  "timed out waiting for hardware reset\n");
 		goto fail5;
 	}
-	EFX_LOG(efx, "hardware reset complete\n");
+	netif_dbg(efx, hw, efx->net_dev, "hardware reset complete\n");
 
 	return 0;
 
@@ -1165,8 +1190,9 @@
 
 	rc = falcon_board(efx)->type->monitor(efx);
 	if (rc) {
-		EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
-			(rc == -ERANGE) ? "reported fault" : "failed");
+		netif_err(efx, hw, efx->net_dev,
+			  "Board sensor %s; shutting down PHY\n",
+			  (rc == -ERANGE) ? "reported fault" : "failed");
 		efx->phy_mode |= PHY_MODE_LOW_POWER;
 		rc = __efx_reconfigure_port(efx);
 		WARN_ON(rc);
@@ -1217,7 +1243,8 @@
 	/* Wait for SRAM reset to complete */
 	count = 0;
 	do {
-		EFX_LOG(efx, "waiting for SRAM reset (attempt %d)...\n", count);
+		netif_dbg(efx, hw, efx->net_dev,
+			  "waiting for SRAM reset (attempt %d)...\n", count);
 
 		/* SRAM reset is slow; expect around 16ms */
 		schedule_timeout_uninterruptible(HZ / 50);
@@ -1225,13 +1252,14 @@
 		/* Check for reset complete */
 		efx_reado(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG);
 		if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, FRF_AZ_SRM_INIT_EN)) {
-			EFX_LOG(efx, "SRAM reset complete\n");
+			netif_dbg(efx, hw, efx->net_dev,
+				  "SRAM reset complete\n");
 
 			return 0;
 		}
 	} while (++count < 20);	/* wait upto 0.4 sec */
 
-	EFX_ERR(efx, "timed out waiting for SRAM reset\n");
+	netif_err(efx, hw, efx->net_dev, "timed out waiting for SRAM reset\n");
 	return -ETIMEDOUT;
 }
 
@@ -1290,7 +1318,8 @@
 
 	rc = falcon_read_nvram(efx, nvconfig);
 	if (rc == -EINVAL) {
-		EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n");
+		netif_err(efx, probe, efx->net_dev,
+			  "NVRAM is invalid therefore using defaults\n");
 		efx->phy_type = PHY_TYPE_NONE;
 		efx->mdio.prtad = MDIO_PRTAD_NONE;
 		board_rev = 0;
@@ -1324,7 +1353,8 @@
 	/* Read the MAC addresses */
 	memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN);
 
-	EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mdio.prtad);
+	netif_dbg(efx, probe, efx->net_dev, "PHY is %d phy_id %d\n",
+		  efx->phy_type, efx->mdio.prtad);
 
 	rc = falcon_probe_board(efx, board_rev);
 	if (rc)
@@ -1353,14 +1383,16 @@
 	if (EFX_OWORD_FIELD(gpio_ctl, FRF_AB_GPIO3_PWRUP_VALUE)) {
 		boot_dev = (EFX_OWORD_FIELD(nic_stat, FRF_AB_SF_PRST) ?
 			    FFE_AB_SPI_DEVICE_FLASH : FFE_AB_SPI_DEVICE_EEPROM);
-		EFX_LOG(efx, "Booted from %s\n",
-			boot_dev == FFE_AB_SPI_DEVICE_FLASH ? "flash" : "EEPROM");
+		netif_dbg(efx, probe, efx->net_dev, "Booted from %s\n",
+			  boot_dev == FFE_AB_SPI_DEVICE_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");
+		netif_dbg(efx, probe, efx->net_dev,
+			  "Booted from internal ASIC settings;"
+			  " setting SPI config\n");
 		EFX_POPULATE_OWORD_3(ee_vpd_cfg, FRF_AB_EE_VPD_EN, 0,
 				     /* 125 MHz / 7 ~= 20 MHz */
 				     FRF_AB_EE_SF_CLOCK_DIV, 7,
@@ -1394,7 +1426,8 @@
 	rc = -ENODEV;
 
 	if (efx_nic_fpga_ver(efx) != 0) {
-		EFX_ERR(efx, "Falcon FPGA not supported\n");
+		netif_err(efx, probe, efx->net_dev,
+			  "Falcon FPGA not supported\n");
 		goto fail1;
 	}
 
@@ -1404,16 +1437,19 @@
 		u8 pci_rev = efx->pci_dev->revision;
 
 		if ((pci_rev == 0xff) || (pci_rev == 0)) {
-			EFX_ERR(efx, "Falcon rev A0 not supported\n");
+			netif_err(efx, probe, efx->net_dev,
+				  "Falcon rev A0 not supported\n");
 			goto fail1;
 		}
 		efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
 		if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) {
-			EFX_ERR(efx, "Falcon rev A1 1G not supported\n");
+			netif_err(efx, probe, efx->net_dev,
+				  "Falcon rev A1 1G not supported\n");
 			goto fail1;
 		}
 		if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) {
-			EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
+			netif_err(efx, probe, efx->net_dev,
+				  "Falcon rev A1 PCI-X not supported\n");
 			goto fail1;
 		}
 
@@ -1427,7 +1463,8 @@
 			}
 		}
 		if (!nic_data->pci_dev2) {
-			EFX_ERR(efx, "failed to find secondary function\n");
+			netif_err(efx, probe, efx->net_dev,
+				  "failed to find secondary function\n");
 			rc = -ENODEV;
 			goto fail2;
 		}
@@ -1436,7 +1473,7 @@
 	/* Now we can reset the NIC */
 	rc = falcon_reset_hw(efx, RESET_TYPE_ALL);
 	if (rc) {
-		EFX_ERR(efx, "failed to reset NIC\n");
+		netif_err(efx, probe, efx->net_dev, "failed to reset NIC\n");
 		goto fail3;
 	}
 
@@ -1446,9 +1483,11 @@
 		goto fail4;
 	BUG_ON(efx->irq_status.dma_addr & 0x0f);
 
-	EFX_LOG(efx, "INT_KER at %llx (virt %p phys %llx)\n",
-		(u64)efx->irq_status.dma_addr,
-		efx->irq_status.addr, (u64)virt_to_phys(efx->irq_status.addr));
+	netif_dbg(efx, probe, efx->net_dev,
+		  "INT_KER at %llx (virt %p phys %llx)\n",
+		  (u64)efx->irq_status.dma_addr,
+		  efx->irq_status.addr,
+		  (u64)virt_to_phys(efx->irq_status.addr));
 
 	falcon_probe_spi_devices(efx);
 
@@ -1472,7 +1511,8 @@
 
 	rc = falcon_board(efx)->type->init(efx);
 	if (rc) {
-		EFX_ERR(efx, "failed to initialise board\n");
+		netif_err(efx, probe, efx->net_dev,
+			  "failed to initialise board\n");
 		goto fail6;
 	}
 
@@ -1542,6 +1582,13 @@
 		EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_TX_TH, ctrl_xon_thr);
 		EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr);
 		EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
+
+		/* Enable hash insertion. This is broken for the
+		 * 'Falcon' hash so also select Toeplitz TCP/IPv4 and
+		 * IPv4 hashes. */
+		EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_HASH_INSRT_HDR, 1);
+		EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_HASH_ALG, 1);
+		EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_IP_HASH, 1);
 	}
 	/* Always enable XOFF signal from RX FIFO.  We enable
 	 * or disable transmission of pause frames at the MAC. */
@@ -1615,8 +1662,12 @@
 
 	falcon_init_rx_cfg(efx);
 
-	/* Set destination of both TX and RX Flush events */
 	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
+		/* Set hash key for IPv4 */
+		memcpy(&temp, efx->rx_hash_key, sizeof(temp));
+		efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY);
+
+		/* Set destination of both TX and RX Flush events */
 		EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0);
 		efx_writeo(efx, &temp, FR_BZ_DP_CTRL);
 	}
@@ -1821,6 +1872,7 @@
 	.evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL,
 	.evq_rptr_tbl_base = FR_BZ_EVQ_RPTR,
 	.max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
+	.rx_buffer_hash_size = 0x10,
 	.rx_buffer_padding = 0,
 	.max_interrupt_mode = EFX_INT_MODE_MSIX,
 	.phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
@@ -1828,7 +1880,7 @@
 				   * channels */
 	.tx_dc_base = 0x130000,
 	.rx_dc_base = 0x100000,
-	.offload_features = NETIF_F_IP_CSUM,
+	.offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH,
 	.reset_world_flags = ETH_RESET_IRQ,
 };
 
diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c
index c7a933a..3d950c2 100644
--- a/drivers/net/sfc/falcon_boards.c
+++ b/drivers/net/sfc/falcon_boards.c
@@ -106,12 +106,17 @@
 	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" : "");
+		netif_err(efx, hw, efx->net_dev,
+			  "LM87 detected a hardware failure (status %02x:%02x)"
+			  "%s%s%s\n",
+			  alarms1, alarms2,
+			  (alarms1 & LM87_ALARM_TEMP_INT) ?
+			  "; board is overheating" : "",
+			  (alarms1 & LM87_ALARM_TEMP_EXT1) ?
+			  "; controller is overheating" : "",
+			  (alarms1 & ~(LM87_ALARM_TEMP_INT | LM87_ALARM_TEMP_EXT1)
+			   || alarms2) ?
+			  "; electrical fault" : "");
 		return -ERANGE;
 	}
 
@@ -243,7 +248,7 @@
 		       (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
 		       (0 << P0_EN_1V0X_LBN));
 	if (rc != out) {
-		EFX_INFO(efx, "power-cycling PHY\n");
+		netif_info(efx, hw, efx->net_dev, "power-cycling PHY\n");
 		rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
 		if (rc)
 			goto fail_on;
@@ -269,7 +274,8 @@
 		if (rc)
 			goto fail_on;
 
-		EFX_INFO(efx, "waiting for DSP boot (attempt %d)...\n", i);
+		netif_info(efx, hw, efx->net_dev,
+			   "waiting for DSP boot (attempt %d)...\n", i);
 
 		/* In flash config mode, DSP does not turn on AFE, so
 		 * just wait 1 second.
@@ -291,7 +297,7 @@
 		}
 	}
 
-	EFX_INFO(efx, "timed out waiting for DSP boot\n");
+	netif_info(efx, hw, efx->net_dev, "timed out waiting for DSP boot\n");
 	rc = -ETIMEDOUT;
 fail_on:
 	sfe4001_poweroff(efx);
@@ -377,7 +383,7 @@
 {
 	struct falcon_board *board = falcon_board(efx);
 
-	EFX_INFO(efx, "%s\n", __func__);
+	netif_info(efx, drv, efx->net_dev, "%s\n", __func__);
 
 	device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
 	sfe4001_poweroff(efx);
@@ -461,7 +467,7 @@
 	if (rc)
 		goto fail_on;
 
-	EFX_INFO(efx, "PHY is powered on\n");
+	netif_info(efx, hw, efx->net_dev, "PHY is powered on\n");
 	return 0;
 
 fail_on:
@@ -493,7 +499,7 @@
 
 static void sfn4111t_fini(struct efx_nic *efx)
 {
-	EFX_INFO(efx, "%s\n", __func__);
+	netif_info(efx, drv, efx->net_dev, "%s\n", __func__);
 
 	device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
 	i2c_unregister_device(falcon_board(efx)->hwmon_client);
@@ -742,13 +748,14 @@
 			board->type = &board_types[i];
 
 	if (board->type) {
-		EFX_INFO(efx, "board is %s rev %c%d\n",
+		netif_info(efx, probe, efx->net_dev, "board is %s rev %c%d\n",
 			 (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
 			 ? board->type->ref_model : board->type->gen_type,
 			 'A' + board->major, board->minor);
 		return 0;
 	} else {
-		EFX_ERR(efx, "unknown board type %d\n", type_id);
+		netif_err(efx, probe, efx->net_dev, "unknown board type %d\n",
+			  type_id);
 		return -ENODEV;
 	}
 }
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index c84a2ce..bae656d 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -81,7 +81,8 @@
 		}
 		udelay(10);
 	}
-	EFX_ERR(efx, "timed out waiting for XAUI/XGXS reset\n");
+	netif_err(efx, hw, efx->net_dev,
+		  "timed out waiting for XAUI/XGXS reset\n");
 	return -ETIMEDOUT;
 }
 
@@ -256,7 +257,7 @@
 	falcon_stop_nic_stats(efx);
 
 	while (!mac_up && tries) {
-		EFX_LOG(efx, "bashing xaui\n");
+		netif_dbg(efx, hw, efx->net_dev, "bashing xaui\n");
 		falcon_reset_xaui(efx);
 		udelay(200);
 
diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h
index b89177c..85a99fe 100644
--- a/drivers/net/sfc/io.h
+++ b/drivers/net/sfc/io.h
@@ -78,8 +78,9 @@
 {
 	unsigned long flags __attribute__ ((unused));
 
-	EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg,
-		    EFX_OWORD_VAL(*value));
+	netif_vdbg(efx, hw, efx->net_dev,
+		   "writing register %x with " EFX_OWORD_FMT "\n", reg,
+		   EFX_OWORD_VAL(*value));
 
 	spin_lock_irqsave(&efx->biu_lock, flags);
 #ifdef EFX_USE_QWORD_IO
@@ -105,8 +106,9 @@
 	unsigned int addr = index * sizeof(*value);
 	unsigned long flags __attribute__ ((unused));
 
-	EFX_REGDUMP(efx, "writing SRAM address %x with " EFX_QWORD_FMT "\n",
-		    addr, EFX_QWORD_VAL(*value));
+	netif_vdbg(efx, hw, efx->net_dev,
+		   "writing SRAM address %x with " EFX_QWORD_FMT "\n",
+		   addr, EFX_QWORD_VAL(*value));
 
 	spin_lock_irqsave(&efx->biu_lock, flags);
 #ifdef EFX_USE_QWORD_IO
@@ -129,8 +131,9 @@
 static inline void efx_writed(struct efx_nic *efx, efx_dword_t *value,
 			      unsigned int reg)
 {
-	EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n",
-		    reg, EFX_DWORD_VAL(*value));
+	netif_vdbg(efx, hw, efx->net_dev,
+		   "writing partial register %x with "EFX_DWORD_FMT"\n",
+		   reg, EFX_DWORD_VAL(*value));
 
 	/* No lock required */
 	_efx_writed(efx, value->u32[0], reg);
@@ -155,8 +158,9 @@
 	value->u32[3] = _efx_readd(efx, reg + 12);
 	spin_unlock_irqrestore(&efx->biu_lock, flags);
 
-	EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg,
-		    EFX_OWORD_VAL(*value));
+	netif_vdbg(efx, hw, efx->net_dev,
+		   "read from register %x, got " EFX_OWORD_FMT "\n", reg,
+		   EFX_OWORD_VAL(*value));
 }
 
 /* Read an 8-byte SRAM entry through supplied mapping,
@@ -177,8 +181,9 @@
 #endif
 	spin_unlock_irqrestore(&efx->biu_lock, flags);
 
-	EFX_REGDUMP(efx, "read from SRAM address %x, got "EFX_QWORD_FMT"\n",
-		    addr, EFX_QWORD_VAL(*value));
+	netif_vdbg(efx, hw, efx->net_dev,
+		   "read from SRAM address %x, got "EFX_QWORD_FMT"\n",
+		   addr, EFX_QWORD_VAL(*value));
 }
 
 /* Read dword from register that allows partial writes (sic) */
@@ -186,8 +191,9 @@
 				unsigned int reg)
 {
 	value->u32[0] = _efx_readd(efx, reg);
-	EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n",
-		    reg, EFX_DWORD_VAL(*value));
+	netif_vdbg(efx, hw, efx->net_dev,
+		   "read from register %x, got "EFX_DWORD_FMT"\n",
+		   reg, EFX_DWORD_VAL(*value));
 }
 
 /* Write to a register forming part of a table */
@@ -211,6 +217,13 @@
 	efx_writed(efx, value, reg + index * sizeof(efx_oword_t));
 }
 
+/* Read from a dword register forming part of a table */
+static inline void efx_readd_table(struct efx_nic *efx, efx_dword_t *value,
+				   unsigned int reg, unsigned int index)
+{
+	efx_readd(efx, value, reg + index * sizeof(efx_dword_t));
+}
+
 /* Page-mapped register block size */
 #define EFX_PAGE_BLOCK_SIZE 0x2000
 
diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c
index 93cc3c1..3912b8f 100644
--- a/drivers/net/sfc/mcdi.c
+++ b/drivers/net/sfc/mcdi.c
@@ -168,11 +168,12 @@
 	error = EFX_DWORD_FIELD(reg, MCDI_HEADER_ERROR);
 
 	if (error && mcdi->resplen == 0) {
-		EFX_ERR(efx, "MC rebooted\n");
+		netif_err(efx, hw, efx->net_dev, "MC rebooted\n");
 		rc = EIO;
 	} else if ((respseq ^ mcdi->seqno) & SEQ_MASK) {
-		EFX_ERR(efx, "MC response mismatch tx seq 0x%x rx seq 0x%x\n",
-			respseq, mcdi->seqno);
+		netif_err(efx, hw, efx->net_dev,
+			  "MC response mismatch tx seq 0x%x rx seq 0x%x\n",
+			  respseq, mcdi->seqno);
 		rc = EIO;
 	} else if (error) {
 		efx_readd(efx, &reg, pdu + 4);
@@ -303,8 +304,9 @@
 			/* The request has been cancelled */
 			--mcdi->credits;
 		else
-			EFX_ERR(efx, "MC response mismatch tx seq 0x%x rx "
-				"seq 0x%x\n", seqno, mcdi->seqno);
+			netif_err(efx, hw, efx->net_dev,
+				  "MC response mismatch tx seq 0x%x rx "
+				  "seq 0x%x\n", seqno, mcdi->seqno);
 	} else {
 		mcdi->resprc = errno;
 		mcdi->resplen = datalen;
@@ -352,8 +354,9 @@
 		++mcdi->credits;
 		spin_unlock_bh(&mcdi->iface_lock);
 
-		EFX_ERR(efx, "MC command 0x%x inlen %d mode %d timed out\n",
-			cmd, (int)inlen, mcdi->mode);
+		netif_err(efx, hw, efx->net_dev,
+			  "MC command 0x%x inlen %d mode %d timed out\n",
+			  cmd, (int)inlen, mcdi->mode);
 	} else {
 		size_t resplen;
 
@@ -374,11 +377,13 @@
 		} else if (cmd == MC_CMD_REBOOT && rc == -EIO)
 			; /* Don't reset if MC_CMD_REBOOT returns EIO */
 		else if (rc == -EIO || rc == -EINTR) {
-			EFX_ERR(efx, "MC fatal error %d\n", -rc);
+			netif_err(efx, hw, efx->net_dev, "MC fatal error %d\n",
+				  -rc);
 			efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
 		} else
-			EFX_ERR(efx, "MC command 0x%x inlen %d failed rc=%d\n",
-				cmd, (int)inlen, -rc);
+			netif_err(efx, hw, efx->net_dev,
+				  "MC command 0x%x inlen %d failed rc=%d\n",
+				  cmd, (int)inlen, -rc);
 	}
 
 	efx_mcdi_release(mcdi);
@@ -534,8 +539,9 @@
 	EFX_BUG_ON_PARANOID(state >= ARRAY_SIZE(sensor_status_names));
 	state_txt = sensor_status_names[state];
 
-	EFX_ERR(efx, "Sensor %d (%s) reports condition '%s' for raw value %d\n",
-		monitor, name, state_txt, value);
+	netif_err(efx, hw, efx->net_dev,
+		  "Sensor %d (%s) reports condition '%s' for raw value %d\n",
+		  monitor, name, state_txt, value);
 }
 
 /* Called from  falcon_process_eventq for MCDI events */
@@ -548,12 +554,13 @@
 
 	switch (code) {
 	case MCDI_EVENT_CODE_BADSSERT:
-		EFX_ERR(efx, "MC watchdog or assertion failure at 0x%x\n", data);
+		netif_err(efx, hw, efx->net_dev,
+			  "MC watchdog or assertion failure at 0x%x\n", data);
 		efx_mcdi_ev_death(efx, EINTR);
 		break;
 
 	case MCDI_EVENT_CODE_PMNOTICE:
-		EFX_INFO(efx, "MCDI PM event.\n");
+		netif_info(efx, wol, efx->net_dev, "MCDI PM event.\n");
 		break;
 
 	case MCDI_EVENT_CODE_CMDDONE:
@@ -570,10 +577,11 @@
 		efx_mcdi_sensor_event(efx, event);
 		break;
 	case MCDI_EVENT_CODE_SCHEDERR:
-		EFX_INFO(efx, "MC Scheduler error address=0x%x\n", data);
+		netif_info(efx, hw, efx->net_dev,
+			   "MC Scheduler error address=0x%x\n", data);
 		break;
 	case MCDI_EVENT_CODE_REBOOT:
-		EFX_INFO(efx, "MC Reboot\n");
+		netif_info(efx, hw, efx->net_dev, "MC Reboot\n");
 		efx_mcdi_ev_death(efx, EIO);
 		break;
 	case MCDI_EVENT_CODE_MAC_STATS_DMA:
@@ -581,7 +589,8 @@
 		break;
 
 	default:
-		EFX_ERR(efx, "Unknown MCDI event 0x%x\n", code);
+		netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n",
+			  code);
 	}
 }
 
@@ -627,7 +636,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -657,7 +666,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -695,7 +704,8 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d len=%d\n", __func__, rc, (int)outlen);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d len=%d\n",
+		  __func__, rc, (int)outlen);
 
 	return rc;
 }
@@ -724,7 +734,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -749,8 +759,8 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n",
-		__func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
+		  __func__, rc);
 	return rc;
 }
 
@@ -781,7 +791,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -802,7 +812,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -827,7 +837,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -853,7 +863,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -877,7 +887,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -898,7 +908,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -948,9 +958,10 @@
 	return 0;
 
 fail2:
-	EFX_ERR(efx, "%s: failed type=%u\n", __func__, type);
+	netif_err(efx, hw, efx->net_dev, "%s: failed type=%u\n",
+		  __func__, type);
 fail1:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -994,14 +1005,15 @@
 		: (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
 		? "watchdog reset"
 		: "unknown assertion";
-	EFX_ERR(efx, "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason,
-		MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS),
-		MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS));
+	netif_err(efx, hw, efx->net_dev,
+		  "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason,
+		  MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS),
+		  MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS));
 
 	/* Print out the registers */
 	ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
 	for (index = 1; index < 32; index++) {
-		EFX_ERR(efx, "R%.2d (?): 0x%.8x\n", index,
+		netif_err(efx, hw, efx->net_dev, "R%.2d (?): 0x%.8x\n", index,
 			MCDI_DWORD2(outbuf, ofst));
 		ofst += sizeof(efx_dword_t);
 	}
@@ -1050,14 +1062,16 @@
 	rc = efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, sizeof(inbuf),
 			  NULL, 0, NULL);
 	if (rc)
-		EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+		netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
+			  __func__, rc);
 }
 
 int efx_mcdi_reset_port(struct efx_nic *efx)
 {
 	int rc = efx_mcdi_rpc(efx, MC_CMD_PORT_RESET, NULL, 0, NULL, 0, NULL);
 	if (rc)
-		EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+		netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
+			  __func__, rc);
 	return rc;
 }
 
@@ -1075,7 +1089,7 @@
 		return 0;
 	if (rc == 0)
 		rc = -EIO;
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -1108,7 +1122,7 @@
 
 fail:
 	*id_out = -1;
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 
 }
@@ -1143,7 +1157,7 @@
 
 fail:
 	*id_out = -1;
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -1163,7 +1177,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -1179,7 +1193,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c
index 3918263..f88f4bf 100644
--- a/drivers/net/sfc/mcdi_mac.c
+++ b/drivers/net/sfc/mcdi_mac.c
@@ -69,8 +69,8 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n",
-		__func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
+		  __func__, rc);
 	return rc;
 }
 
@@ -110,8 +110,8 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: %s failed rc=%d\n",
-		__func__, enable ? "enable" : "disable", rc);
+	netif_err(efx, hw, efx->net_dev, "%s: %s failed rc=%d\n",
+		  __func__, enable ? "enable" : "disable", rc);
 	return rc;
 }
 
diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c
index 6032c0e..0121e71 100644
--- a/drivers/net/sfc/mcdi_phy.c
+++ b/drivers/net/sfc/mcdi_phy.c
@@ -20,7 +20,7 @@
 #include "nic.h"
 #include "selftest.h"
 
-struct efx_mcdi_phy_cfg {
+struct efx_mcdi_phy_data {
 	u32 flags;
 	u32 type;
 	u32 supported_cap;
@@ -35,7 +35,7 @@
 };
 
 static int
-efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_cfg *cfg)
+efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_data *cfg)
 {
 	u8 outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN];
 	size_t outlen;
@@ -71,7 +71,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -97,7 +97,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -122,7 +122,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -150,7 +150,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -178,7 +178,7 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+	netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
 	return rc;
 }
 
@@ -259,7 +259,7 @@
 
 static u32 efx_get_mcdi_phy_flags(struct efx_nic *efx)
 {
-	struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+	struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
 	enum efx_phy_mode mode, supported;
 	u32 flags;
 
@@ -307,7 +307,7 @@
 
 static int efx_mcdi_phy_probe(struct efx_nic *efx)
 {
-	struct efx_mcdi_phy_cfg *phy_data;
+	struct efx_mcdi_phy_data *phy_data;
 	u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
 	u32 caps;
 	int rc;
@@ -395,6 +395,7 @@
 	efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
 	if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
 		efx->wanted_fc |= EFX_FC_AUTO;
+	efx_link_set_wanted_fc(efx, efx->wanted_fc);
 
 	return 0;
 
@@ -405,7 +406,7 @@
 
 int efx_mcdi_phy_reconfigure(struct efx_nic *efx)
 {
-	struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+	struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
 	u32 caps = (efx->link_advertising ?
 		    ethtool_to_mcdi_cap(efx->link_advertising) :
 		    phy_cfg->forced_cap);
@@ -446,7 +447,7 @@
  */
 void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa)
 {
-	struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+	struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
 	u32 rmtadv;
 
 	/* The link partner capabilities are only relevent if the
@@ -465,8 +466,8 @@
 		rmtadv |=  ADVERTISED_Asym_Pause;
 
 	if ((efx->wanted_fc & EFX_FC_TX) && rmtadv == ADVERTISED_Asym_Pause)
-		EFX_ERR(efx, "warning: link partner doesn't support "
-			"pause frames");
+		netif_err(efx, link, efx->net_dev,
+			  "warning: link partner doesn't support pause frames");
 }
 
 static bool efx_mcdi_phy_poll(struct efx_nic *efx)
@@ -482,7 +483,8 @@
 	rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
 			  outbuf, sizeof(outbuf), NULL);
 	if (rc) {
-		EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+		netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
+			  __func__, rc);
 		efx->link_state.up = false;
 	} else {
 		efx_mcdi_phy_decode_link(
@@ -505,7 +507,7 @@
 
 static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 {
-	struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+	struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
 	u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
 	int rc;
 
@@ -525,7 +527,8 @@
 	rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
 			  outbuf, sizeof(outbuf), NULL);
 	if (rc) {
-		EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+		netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
+			  __func__, rc);
 		return;
 	}
 	ecmd->lp_advertising =
@@ -535,7 +538,7 @@
 
 static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 {
-	struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+	struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
 	u32 caps;
 	int rc;
 
@@ -674,7 +677,7 @@
 static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results,
 				  unsigned flags)
 {
-	struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+	struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
 	u32 mode;
 	int rc;
 
@@ -712,7 +715,7 @@
 
 const char *efx_mcdi_phy_test_name(struct efx_nic *efx, unsigned int index)
 {
-	struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+	struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
 
 	if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) {
 		if (index == 0)
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 0548fcb..eeaf0bd 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -63,7 +63,8 @@
 		/* Read MMD STATUS2 to check it is responding. */
 		status = efx_mdio_read(efx, mmd, MDIO_STAT2);
 		if ((status & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL) {
-			EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd);
+			netif_err(efx, hw, efx->net_dev,
+				  "PHY MMD %d not responding.\n", mmd);
 			return -EIO;
 		}
 	}
@@ -72,12 +73,14 @@
 	status = efx_mdio_read(efx, mmd, MDIO_STAT1);
 	if (status & MDIO_STAT1_FAULT) {
 		if (fault_fatal) {
-			EFX_ERR(efx, "PHY MMD %d reporting fatal"
-				" fault: status %x\n", mmd, status);
+			netif_err(efx, hw, efx->net_dev,
+				  "PHY MMD %d reporting fatal"
+				  " fault: status %x\n", mmd, status);
 			return -EIO;
 		} else {
-			EFX_LOG(efx, "PHY MMD %d reporting status"
-				" %x (expected)\n", mmd, status);
+			netif_dbg(efx, hw, efx->net_dev,
+				  "PHY MMD %d reporting status"
+				  " %x (expected)\n", mmd, status);
 		}
 	}
 	return 0;
@@ -103,8 +106,9 @@
 			if (mask & 1) {
 				stat = efx_mdio_read(efx, mmd, MDIO_CTRL1);
 				if (stat < 0) {
-					EFX_ERR(efx, "failed to read status of"
-						" MMD %d\n", mmd);
+					netif_err(efx, hw, efx->net_dev,
+						  "failed to read status of"
+						  " MMD %d\n", mmd);
 					return -EIO;
 				}
 				if (stat & MDIO_CTRL1_RESET)
@@ -119,8 +123,9 @@
 		msleep(spintime);
 	}
 	if (in_reset != 0) {
-		EFX_ERR(efx, "not all MMDs came out of reset in time."
-			" MMDs still in reset: %x\n", in_reset);
+		netif_err(efx, hw, efx->net_dev,
+			  "not all MMDs came out of reset in time."
+			  " MMDs still in reset: %x\n", in_reset);
 		rc = -ETIMEDOUT;
 	}
 	return rc;
@@ -142,16 +147,18 @@
 	devs1 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS1);
 	devs2 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS2);
 	if (devs1 < 0 || devs2 < 0) {
-		EFX_ERR(efx, "failed to read devices present\n");
+		netif_err(efx, hw, efx->net_dev,
+			  "failed to read devices present\n");
 		return -EIO;
 	}
 	devices = devs1 | (devs2 << 16);
 	if ((devices & mmd_mask) != mmd_mask) {
-		EFX_ERR(efx, "required MMDs not present: got %x, "
-			"wanted %x\n", devices, mmd_mask);
+		netif_err(efx, hw, efx->net_dev,
+			  "required MMDs not present: got %x, wanted %x\n",
+			  devices, mmd_mask);
 		return -ENODEV;
 	}
-	EFX_TRACE(efx, "Devices present: %x\n", devices);
+	netif_vdbg(efx, hw, efx->net_dev, "Devices present: %x\n", devices);
 
 	/* Check all required MMDs are responding and happy. */
 	while (mmd_mask) {
@@ -219,7 +226,7 @@
 {
 	int stat = efx_mdio_read(efx, mmd, MDIO_STAT1);
 
-	EFX_TRACE(efx, "Setting low power mode for MMD %d to %d\n",
+	netif_vdbg(efx, drv, efx->net_dev, "Setting low power mode for MMD %d to %d\n",
 		  mmd, lpower);
 
 	if (stat & MDIO_STAT1_LPOWERABLE) {
@@ -349,8 +356,8 @@
 
 	if ((physid1 == 0x0000) || (physid1 == 0xffff) ||
 	    (physid2 == 0x0000) || (physid2 == 0xffff)) {
-		EFX_ERR(efx, "no MDIO PHY present with ID %d\n",
-			efx->mdio.prtad);
+		netif_err(efx, hw, efx->net_dev,
+			  "no MDIO PHY present with ID %d\n", efx->mdio.prtad);
 		rc = -EINVAL;
 	} else {
 		rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0);
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
index f89e719..75791d3 100644
--- a/drivers/net/sfc/mdio_10g.h
+++ b/drivers/net/sfc/mdio_10g.h
@@ -51,7 +51,8 @@
 
 	sync = !!(lane_status & MDIO_PHYXS_LNSTAT_ALIGN);
 	if (!sync)
-		EFX_LOG(efx, "XGXS lane status: %x\n", lane_status);
+		netif_dbg(efx, hw, efx->net_dev, "XGXS lane status: %x\n",
+			  lane_status);
 	return sync;
 }
 
diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c
index f3ac7f3..02e54b4 100644
--- a/drivers/net/sfc/mtd.c
+++ b/drivers/net/sfc/mtd.c
@@ -15,7 +15,6 @@
 #include <linux/slab.h>
 #include <linux/rtnetlink.h>
 
-#define EFX_DRIVER_NAME "sfc_mtd"
 #include "net_driver.h"
 #include "spi.h"
 #include "efx.h"
@@ -71,8 +70,10 @@
 
 /* SPI utilities */
 
-static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible)
+static int
+efx_spi_slow_wait(struct efx_mtd_partition *part, bool uninterruptible)
 {
+	struct efx_mtd *efx_mtd = part->mtd.priv;
 	const struct efx_spi_device *spi = efx_mtd->spi;
 	struct efx_nic *efx = efx_mtd->efx;
 	u8 status;
@@ -92,7 +93,7 @@
 		if (signal_pending(current))
 			return -EINTR;
 	}
-	EFX_ERR(efx, "timed out waiting for %s\n", efx_mtd->name);
+	pr_err("%s: timed out waiting for %s\n", part->name, efx_mtd->name);
 	return -ETIMEDOUT;
 }
 
@@ -131,8 +132,10 @@
 	return 0;
 }
 
-static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len)
+static int
+efx_spi_erase(struct efx_mtd_partition *part, loff_t start, size_t len)
 {
+	struct efx_mtd *efx_mtd = part->mtd.priv;
 	const struct efx_spi_device *spi = efx_mtd->spi;
 	struct efx_nic *efx = efx_mtd->efx;
 	unsigned pos, block_len;
@@ -156,7 +159,7 @@
 			    NULL, 0);
 	if (rc)
 		return rc;
-	rc = efx_spi_slow_wait(efx_mtd, false);
+	rc = efx_spi_slow_wait(part, false);
 
 	/* Verify the entire region has been wiped */
 	memset(empty, 0xff, sizeof(empty));
@@ -198,13 +201,14 @@
 
 static void efx_mtd_sync(struct mtd_info *mtd)
 {
+	struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
 	struct efx_mtd *efx_mtd = mtd->priv;
-	struct efx_nic *efx = efx_mtd->efx;
 	int rc;
 
 	rc = efx_mtd->ops->sync(mtd);
 	if (rc)
-		EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc);
+		pr_err("%s: %s sync failed (%d)\n",
+		       part->name, efx_mtd->name, rc);
 }
 
 static void efx_mtd_remove_partition(struct efx_mtd_partition *part)
@@ -338,7 +342,7 @@
 	rc = mutex_lock_interruptible(&efx->spi_lock);
 	if (rc)
 		return rc;
-	rc = efx_spi_erase(efx_mtd, part->offset + start, len);
+	rc = efx_spi_erase(part, part->offset + start, len);
 	mutex_unlock(&efx->spi_lock);
 	return rc;
 }
@@ -363,12 +367,13 @@
 
 static int falcon_mtd_sync(struct mtd_info *mtd)
 {
+	struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
 	struct efx_mtd *efx_mtd = mtd->priv;
 	struct efx_nic *efx = efx_mtd->efx;
 	int rc;
 
 	mutex_lock(&efx->spi_lock);
-	rc = efx_spi_slow_wait(efx_mtd, true);
+	rc = efx_spi_slow_wait(part, true);
 	mutex_unlock(&efx->spi_lock);
 	return rc;
 }
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 4762c91..64e7caa 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -13,11 +13,16 @@
 #ifndef EFX_NET_DRIVER_H
 #define EFX_NET_DRIVER_H
 
+#if defined(EFX_ENABLE_DEBUG) && !defined(DEBUG)
+#define DEBUG
+#endif
+
 #include <linux/version.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
+#include <linux/timer.h>
 #include <linux/mdio.h>
 #include <linux/list.h>
 #include <linux/pci.h>
@@ -34,9 +39,7 @@
  * Build definitions
  *
  **************************************************************************/
-#ifndef EFX_DRIVER_NAME
-#define EFX_DRIVER_NAME	"sfc"
-#endif
+
 #define EFX_DRIVER_VERSION	"3.0"
 
 #ifdef EFX_ENABLE_DEBUG
@@ -47,35 +50,6 @@
 #define EFX_WARN_ON_PARANOID(x) do {} while (0)
 #endif
 
-/* Un-rate-limited logging */
-#define EFX_ERR(efx, fmt, args...) \
-dev_err(&((efx)->pci_dev->dev), "ERR: %s " fmt, efx_dev_name(efx), ##args)
-
-#define EFX_INFO(efx, fmt, args...) \
-dev_info(&((efx)->pci_dev->dev), "INFO: %s " fmt, efx_dev_name(efx), ##args)
-
-#ifdef EFX_ENABLE_DEBUG
-#define EFX_LOG(efx, fmt, args...) \
-dev_info(&((efx)->pci_dev->dev), "DBG: %s " fmt, efx_dev_name(efx), ##args)
-#else
-#define EFX_LOG(efx, fmt, args...) \
-dev_dbg(&((efx)->pci_dev->dev), "DBG: %s " fmt, efx_dev_name(efx), ##args)
-#endif
-
-#define EFX_TRACE(efx, fmt, args...) do {} while (0)
-
-#define EFX_REGDUMP(efx, fmt, args...) do {} while (0)
-
-/* Rate-limited logging */
-#define EFX_ERR_RL(efx, fmt, args...) \
-do {if (net_ratelimit()) EFX_ERR(efx, fmt, ##args); } while (0)
-
-#define EFX_INFO_RL(efx, fmt, args...) \
-do {if (net_ratelimit()) EFX_INFO(efx, fmt, ##args); } while (0)
-
-#define EFX_LOG_RL(efx, fmt, args...) \
-do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
-
 /**************************************************************************
  *
  * Efx data structures
@@ -221,7 +195,6 @@
  *	If both this and skb are %NULL, the buffer slot is currently free.
  * @data: Pointer to ethernet header
  * @len: Buffer length, in bytes.
- * @unmap_addr: DMA address to unmap
  */
 struct efx_rx_buffer {
 	dma_addr_t dma_addr;
@@ -229,7 +202,24 @@
 	struct page *page;
 	char *data;
 	unsigned int len;
-	dma_addr_t unmap_addr;
+};
+
+/**
+ * struct efx_rx_page_state - Page-based rx buffer state
+ *
+ * Inserted at the start of every page allocated for receive buffers.
+ * Used to facilitate sharing dma mappings between recycled rx buffers
+ * and those passed up to the kernel.
+ *
+ * @refcnt: Number of struct efx_rx_buffer's referencing this page.
+ *	When refcnt falls to zero, the page is unmapped for dma
+ * @dma_addr: The dma address of this page.
+ */
+struct efx_rx_page_state {
+	unsigned refcnt;
+	dma_addr_t dma_addr;
+
+	unsigned int __pad[0] ____cacheline_aligned;
 };
 
 /**
@@ -242,10 +232,6 @@
  * @added_count: Number of buffers added to the receive queue.
  * @notified_count: Number of buffers given to NIC (<= @added_count).
  * @removed_count: Number of buffers removed from the receive queue.
- * @add_lock: Receive queue descriptor add spin lock.
- *	This lock must be held in order to add buffers to the RX
- *	descriptor ring (rxd and buffer) and to update added_count (but
- *	not removed_count).
  * @max_fill: RX descriptor maximum fill level (<= ring size)
  * @fast_fill_trigger: RX descriptor fill level that will trigger a fast fill
  *	(<= @max_fill)
@@ -259,12 +245,7 @@
  *	overflow was observed.  It should never be set.
  * @alloc_page_count: RX allocation strategy counter.
  * @alloc_skb_count: RX allocation strategy counter.
- * @work: Descriptor push work thread
- * @buf_page: Page for next RX buffer.
- *	We can use a single page for multiple RX buffers. This tracks
- *	the remaining space in the allocation.
- * @buf_dma_addr: Page's DMA address.
- * @buf_data: Page's host address.
+ * @slow_fill: Timer used to defer efx_nic_generate_fill_event().
  * @flushed: Use when handling queue flushing
  */
 struct efx_rx_queue {
@@ -277,7 +258,6 @@
 	int added_count;
 	int notified_count;
 	int removed_count;
-	spinlock_t add_lock;
 	unsigned int max_fill;
 	unsigned int fast_fill_trigger;
 	unsigned int fast_fill_limit;
@@ -285,12 +265,9 @@
 	unsigned int min_overfill;
 	unsigned int alloc_page_count;
 	unsigned int alloc_skb_count;
-	struct delayed_work work;
+	struct timer_list slow_fill;
 	unsigned int slow_fill_count;
 
-	struct page *buf_page;
-	dma_addr_t buf_dma_addr;
-	char *buf_data;
 	enum efx_flush_state flushed;
 };
 
@@ -336,7 +313,7 @@
  * @eventq: Event queue buffer
  * @eventq_read_ptr: Event queue read pointer
  * @last_eventq_read_ptr: Last event queue read pointer value.
- * @eventq_magic: Event queue magic value for driver-generated test events
+ * @magic_count: Event queue test event count
  * @irq_count: Number of IRQs since last adaptive moderation decision
  * @irq_mod_score: IRQ moderation score
  * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
@@ -367,7 +344,7 @@
 	struct efx_special_buffer eventq;
 	unsigned int eventq_read_ptr;
 	unsigned int last_eventq_read_ptr;
-	unsigned int eventq_magic;
+	unsigned int magic_count;
 
 	unsigned int irq_count;
 	unsigned int irq_mod_score;
@@ -658,6 +635,7 @@
  * @interrupt_mode: Interrupt mode
  * @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues
  * @irq_rx_moderation: IRQ moderation time for RX event queues
+ * @msg_enable: Log message enable flags
  * @state: Device state flag. Serialised by the rtnl_lock.
  * @reset_pending: Pending reset method (normally RESET_TYPE_NONE)
  * @tx_queue: TX DMA queues
@@ -669,6 +647,7 @@
  * @n_tx_channels: Number of channels used for TX
  * @rx_buffer_len: RX buffer length
  * @rx_buffer_order: Order (log2) of number of pages for each RX buffer
+ * @rx_indir_table: Indirection table for RSS
  * @int_error_count: Number of internal errors seen recently
  * @int_error_expire: Time at which error count will be expired
  * @irq_status: Interrupt status buffer
@@ -740,6 +719,7 @@
 	enum efx_int_mode interrupt_mode;
 	bool irq_rx_adaptive;
 	unsigned int irq_rx_moderation;
+	u32 msg_enable;
 
 	enum nic_state state;
 	enum reset_type reset_pending;
@@ -754,6 +734,8 @@
 	unsigned n_tx_channels;
 	unsigned int rx_buffer_len;
 	unsigned int rx_buffer_order;
+	u8 rx_hash_key[40];
+	u32 rx_indir_table[128];
 
 	unsigned int_error_count;
 	unsigned long int_error_expire;
@@ -866,7 +848,8 @@
  * @evq_ptr_tbl_base: Event queue pointer table base address
  * @evq_rptr_tbl_base: Event queue read-pointer table base address
  * @max_dma_mask: Maximum possible DMA mask
- * @rx_buffer_padding: Padding added to each RX buffer
+ * @rx_buffer_hash_size: Size of hash at start of RX buffer
+ * @rx_buffer_padding: Size of padding at end of RX buffer
  * @max_interrupt_mode: Highest capability interrupt mode supported
  *	from &enum efx_init_mode.
  * @phys_addr_channels: Number of channels with physically addressed
@@ -910,6 +893,7 @@
 	unsigned int evq_ptr_tbl_base;
 	unsigned int evq_rptr_tbl_base;
 	u64 max_dma_mask;
+	unsigned int rx_buffer_hash_size;
 	unsigned int rx_buffer_padding;
 	unsigned int max_interrupt_mode;
 	unsigned int phys_addr_channels;
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index 5d3aaec..f595d92 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -79,6 +79,14 @@
 /* Depth of RX flush request fifo */
 #define EFX_RX_FLUSH_COUNT 4
 
+/* Generated event code for efx_generate_test_event() */
+#define EFX_CHANNEL_MAGIC_TEST(_channel)	\
+	(0x00010100 + (_channel)->channel)
+
+/* Generated event code for efx_generate_fill_event() */
+#define EFX_CHANNEL_MAGIC_FILL(_channel)	\
+	(0x00010200 + (_channel)->channel)
+
 /**************************************************************************
  *
  * Solarstorm hardware access
@@ -171,9 +179,10 @@
 	return 0;
 
 fail:
-	EFX_ERR(efx, "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT
-		" at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg),
-		EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask));
+	netif_err(efx, hw, efx->net_dev,
+		  "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT
+		  " at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg),
+		  EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask));
 	return -EIO;
 }
 
@@ -206,8 +215,9 @@
 	for (i = 0; i < buffer->entries; i++) {
 		index = buffer->index + i;
 		dma_addr = buffer->dma_addr + (i * 4096);
-		EFX_LOG(efx, "mapping special buffer %d at %llx\n",
-			index, (unsigned long long)dma_addr);
+		netif_dbg(efx, probe, efx->net_dev,
+			  "mapping special buffer %d at %llx\n",
+			  index, (unsigned long long)dma_addr);
 		EFX_POPULATE_QWORD_3(buf_desc,
 				     FRF_AZ_BUF_ADR_REGION, 0,
 				     FRF_AZ_BUF_ADR_FBUF, dma_addr >> 12,
@@ -227,8 +237,8 @@
 	if (!buffer->entries)
 		return;
 
-	EFX_LOG(efx, "unmapping special buffers %d-%d\n",
-		buffer->index, buffer->index + buffer->entries - 1);
+	netif_dbg(efx, hw, efx->net_dev, "unmapping special buffers %d-%d\n",
+		  buffer->index, buffer->index + buffer->entries - 1);
 
 	EFX_POPULATE_OWORD_4(buf_tbl_upd,
 			     FRF_AZ_BUF_UPD_CMD, 0,
@@ -268,11 +278,12 @@
 	buffer->index = efx->next_buffer_table;
 	efx->next_buffer_table += buffer->entries;
 
-	EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x "
-		"(virt %p phys %llx)\n", buffer->index,
-		buffer->index + buffer->entries - 1,
-		(u64)buffer->dma_addr, len,
-		buffer->addr, (u64)virt_to_phys(buffer->addr));
+	netif_dbg(efx, probe, efx->net_dev,
+		  "allocating special buffers %d-%d at %llx+%x "
+		  "(virt %p phys %llx)\n", buffer->index,
+		  buffer->index + buffer->entries - 1,
+		  (u64)buffer->dma_addr, len,
+		  buffer->addr, (u64)virt_to_phys(buffer->addr));
 
 	return 0;
 }
@@ -283,11 +294,12 @@
 	if (!buffer->addr)
 		return;
 
-	EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x "
-		"(virt %p phys %llx)\n", buffer->index,
-		buffer->index + buffer->entries - 1,
-		(u64)buffer->dma_addr, buffer->len,
-		buffer->addr, (u64)virt_to_phys(buffer->addr));
+	netif_dbg(efx, hw, efx->net_dev,
+		  "deallocating special buffers %d-%d at %llx+%x "
+		  "(virt %p phys %llx)\n", buffer->index,
+		  buffer->index + buffer->entries - 1,
+		  (u64)buffer->dma_addr, buffer->len,
+		  buffer->addr, (u64)virt_to_phys(buffer->addr));
 
 	pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr,
 			    buffer->dma_addr);
@@ -547,9 +559,10 @@
 	bool is_b0 = efx_nic_rev(efx) >= EFX_REV_FALCON_B0;
 	bool iscsi_digest_en = is_b0;
 
-	EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n",
-		rx_queue->queue, rx_queue->rxd.index,
-		rx_queue->rxd.index + rx_queue->rxd.entries - 1);
+	netif_dbg(efx, hw, efx->net_dev,
+		  "RX queue %d ring in special buffers %d-%d\n",
+		  rx_queue->queue, rx_queue->rxd.index,
+		  rx_queue->rxd.index + rx_queue->rxd.entries - 1);
 
 	rx_queue->flushed = FLUSH_NONE;
 
@@ -686,9 +699,10 @@
 		   EFX_WORKAROUND_10727(efx)) {
 		efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
 	} else {
-		EFX_ERR(efx, "channel %d unexpected TX event "
-			EFX_QWORD_FMT"\n", channel->channel,
-			EFX_QWORD_VAL(*event));
+		netif_err(efx, tx_err, efx->net_dev,
+			  "channel %d unexpected TX event "
+			  EFX_QWORD_FMT"\n", channel->channel,
+			  EFX_QWORD_VAL(*event));
 	}
 
 	return tx_packets;
@@ -751,20 +765,21 @@
 	 * to a FIFO overflow.
 	 */
 #ifdef EFX_ENABLE_DEBUG
-	if (rx_ev_other_err) {
-		EFX_INFO_RL(efx, " RX queue %d unexpected RX event "
-			    EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n",
-			    rx_queue->queue, EFX_QWORD_VAL(*event),
-			    rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "",
-			    rx_ev_ip_hdr_chksum_err ?
-			    " [IP_HDR_CHKSUM_ERR]" : "",
-			    rx_ev_tcp_udp_chksum_err ?
-			    " [TCP_UDP_CHKSUM_ERR]" : "",
-			    rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "",
-			    rx_ev_frm_trunc ? " [FRM_TRUNC]" : "",
-			    rx_ev_drib_nib ? " [DRIB_NIB]" : "",
-			    rx_ev_tobe_disc ? " [TOBE_DISC]" : "",
-			    rx_ev_pause_frm ? " [PAUSE]" : "");
+	if (rx_ev_other_err && net_ratelimit()) {
+		netif_dbg(efx, rx_err, efx->net_dev,
+			  " RX queue %d unexpected RX event "
+			  EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n",
+			  rx_queue->queue, EFX_QWORD_VAL(*event),
+			  rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "",
+			  rx_ev_ip_hdr_chksum_err ?
+			  " [IP_HDR_CHKSUM_ERR]" : "",
+			  rx_ev_tcp_udp_chksum_err ?
+			  " [TCP_UDP_CHKSUM_ERR]" : "",
+			  rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "",
+			  rx_ev_frm_trunc ? " [FRM_TRUNC]" : "",
+			  rx_ev_drib_nib ? " [DRIB_NIB]" : "",
+			  rx_ev_tobe_disc ? " [TOBE_DISC]" : "",
+			  rx_ev_pause_frm ? " [PAUSE]" : "");
 	}
 #endif
 }
@@ -778,8 +793,9 @@
 
 	expected = rx_queue->removed_count & EFX_RXQ_MASK;
 	dropped = (index - expected) & EFX_RXQ_MASK;
-	EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n",
-		dropped, index, expected);
+	netif_info(efx, rx_err, efx->net_dev,
+		   "dropped %d events (index=%d expected=%d)\n",
+		   dropped, index, expected);
 
 	efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ?
 			   RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
@@ -850,6 +866,26 @@
 		      checksummed, discard);
 }
 
+static void
+efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event)
+{
+	struct efx_nic *efx = channel->efx;
+	unsigned code;
+
+	code = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC);
+	if (code == EFX_CHANNEL_MAGIC_TEST(channel))
+		++channel->magic_count;
+	else if (code == EFX_CHANNEL_MAGIC_FILL(channel))
+		/* The queue must be empty, so we won't receive any rx
+		 * events, so efx_process_channel() won't refill the
+		 * queue. Refill it here */
+		efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]);
+	else
+		netif_dbg(efx, hw, efx->net_dev, "channel %d received "
+			  "generated event "EFX_QWORD_FMT"\n",
+			  channel->channel, EFX_QWORD_VAL(*event));
+}
+
 /* Global events are basically PHY events */
 static void
 efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event)
@@ -873,8 +909,9 @@
 	if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ?
 	    EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) :
 	    EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) {
-		EFX_ERR(efx, "channel %d seen global RX_RESET "
-			"event. Resetting.\n", channel->channel);
+		netif_err(efx, rx_err, efx->net_dev,
+			  "channel %d seen global RX_RESET event. Resetting.\n",
+			  channel->channel);
 
 		atomic_inc(&efx->rx_reset);
 		efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ?
@@ -883,9 +920,10 @@
 	}
 
 	if (!handled)
-		EFX_ERR(efx, "channel %d unknown global event "
-			EFX_QWORD_FMT "\n", channel->channel,
-			EFX_QWORD_VAL(*event));
+		netif_err(efx, hw, efx->net_dev,
+			  "channel %d unknown global event "
+			  EFX_QWORD_FMT "\n", channel->channel,
+			  EFX_QWORD_VAL(*event));
 }
 
 static void
@@ -900,31 +938,35 @@
 
 	switch (ev_sub_code) {
 	case FSE_AZ_TX_DESCQ_FLS_DONE_EV:
-		EFX_TRACE(efx, "channel %d TXQ %d flushed\n",
-			  channel->channel, ev_sub_data);
+		netif_vdbg(efx, hw, efx->net_dev, "channel %d TXQ %d flushed\n",
+			   channel->channel, ev_sub_data);
 		break;
 	case FSE_AZ_RX_DESCQ_FLS_DONE_EV:
-		EFX_TRACE(efx, "channel %d RXQ %d flushed\n",
-			  channel->channel, ev_sub_data);
+		netif_vdbg(efx, hw, efx->net_dev, "channel %d RXQ %d flushed\n",
+			   channel->channel, ev_sub_data);
 		break;
 	case FSE_AZ_EVQ_INIT_DONE_EV:
-		EFX_LOG(efx, "channel %d EVQ %d initialised\n",
-			channel->channel, ev_sub_data);
+		netif_dbg(efx, hw, efx->net_dev,
+			  "channel %d EVQ %d initialised\n",
+			  channel->channel, ev_sub_data);
 		break;
 	case FSE_AZ_SRM_UPD_DONE_EV:
-		EFX_TRACE(efx, "channel %d SRAM update done\n",
-			  channel->channel);
+		netif_vdbg(efx, hw, efx->net_dev,
+			   "channel %d SRAM update done\n", channel->channel);
 		break;
 	case FSE_AZ_WAKE_UP_EV:
-		EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n",
-			  channel->channel, ev_sub_data);
+		netif_vdbg(efx, hw, efx->net_dev,
+			   "channel %d RXQ %d wakeup event\n",
+			   channel->channel, ev_sub_data);
 		break;
 	case FSE_AZ_TIMER_EV:
-		EFX_TRACE(efx, "channel %d RX queue %d timer expired\n",
-			  channel->channel, ev_sub_data);
+		netif_vdbg(efx, hw, efx->net_dev,
+			   "channel %d RX queue %d timer expired\n",
+			   channel->channel, ev_sub_data);
 		break;
 	case FSE_AA_RX_RECOVER_EV:
-		EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. "
+		netif_err(efx, rx_err, efx->net_dev,
+			  "channel %d seen DRIVER RX_RESET event. "
 			"Resetting.\n", channel->channel);
 		atomic_inc(&efx->rx_reset);
 		efx_schedule_reset(efx,
@@ -933,19 +975,22 @@
 				   RESET_TYPE_DISABLE);
 		break;
 	case FSE_BZ_RX_DSC_ERROR_EV:
-		EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error."
-			" RX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
+		netif_err(efx, rx_err, efx->net_dev,
+			  "RX DMA Q %d reports descriptor fetch error."
+			  " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
 		efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH);
 		break;
 	case FSE_BZ_TX_DSC_ERROR_EV:
-		EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error."
-			" TX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
+		netif_err(efx, tx_err, efx->net_dev,
+			  "TX DMA Q %d reports descriptor fetch error."
+			  " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
 		efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
 		break;
 	default:
-		EFX_TRACE(efx, "channel %d unknown driver event code %d "
-			  "data %04x\n", channel->channel, ev_sub_code,
-			  ev_sub_data);
+		netif_vdbg(efx, hw, efx->net_dev,
+			   "channel %d unknown driver event code %d "
+			   "data %04x\n", channel->channel, ev_sub_code,
+			   ev_sub_data);
 		break;
 	}
 }
@@ -968,8 +1013,9 @@
 			/* End of events */
 			break;
 
-		EFX_TRACE(channel->efx, "channel %d event is "EFX_QWORD_FMT"\n",
-			  channel->channel, EFX_QWORD_VAL(event));
+		netif_vdbg(channel->efx, intr, channel->efx->net_dev,
+			   "channel %d event is "EFX_QWORD_FMT"\n",
+			   channel->channel, EFX_QWORD_VAL(event));
 
 		/* Clear this event by marking it all ones */
 		EFX_SET_QWORD(*p_event);
@@ -993,11 +1039,7 @@
 			}
 			break;
 		case FSE_AZ_EV_CODE_DRV_GEN_EV:
-			channel->eventq_magic = EFX_QWORD_FIELD(
-				event, FSF_AZ_DRV_GEN_EV_MAGIC);
-			EFX_LOG(channel->efx, "channel %d received generated "
-				"event "EFX_QWORD_FMT"\n", channel->channel,
-				EFX_QWORD_VAL(event));
+			efx_handle_generated_event(channel, &event);
 			break;
 		case FSE_AZ_EV_CODE_GLOBAL_EV:
 			efx_handle_global_event(channel, &event);
@@ -1009,9 +1051,10 @@
 			efx_mcdi_process_event(channel, &event);
 			break;
 		default:
-			EFX_ERR(channel->efx, "channel %d unknown event type %d"
-				" (data " EFX_QWORD_FMT ")\n", channel->channel,
-				ev_code, EFX_QWORD_VAL(event));
+			netif_err(channel->efx, hw, channel->efx->net_dev,
+				  "channel %d unknown event type %d (data "
+				  EFX_QWORD_FMT ")\n", channel->channel,
+				  ev_code, EFX_QWORD_VAL(event));
 		}
 	}
 
@@ -1036,9 +1079,10 @@
 	efx_oword_t reg;
 	struct efx_nic *efx = channel->efx;
 
-	EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n",
-		channel->channel, channel->eventq.index,
-		channel->eventq.index + channel->eventq.entries - 1);
+	netif_dbg(efx, hw, efx->net_dev,
+		  "channel %d event queue in special buffers %d-%d\n",
+		  channel->channel, channel->eventq.index,
+		  channel->eventq.index + channel->eventq.entries - 1);
 
 	if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) {
 		EFX_POPULATE_OWORD_3(reg,
@@ -1088,12 +1132,20 @@
 }
 
 
-/* Generates a test event on the event queue.  A subsequent call to
- * process_eventq() should pick up the event and place the value of
- * "magic" into channel->eventq_magic;
- */
-void efx_nic_generate_test_event(struct efx_channel *channel, unsigned int magic)
+void efx_nic_generate_test_event(struct efx_channel *channel)
 {
+	unsigned int magic = EFX_CHANNEL_MAGIC_TEST(channel);
+	efx_qword_t test_event;
+
+	EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
+			     FSE_AZ_EV_CODE_DRV_GEN_EV,
+			     FSF_AZ_DRV_GEN_EV_MAGIC, magic);
+	efx_generate_event(channel, &test_event);
+}
+
+void efx_nic_generate_fill_event(struct efx_channel *channel)
+{
+	unsigned int magic = EFX_CHANNEL_MAGIC_FILL(channel);
 	efx_qword_t test_event;
 
 	EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
@@ -1208,20 +1260,19 @@
 	 * leading to a reset, or fake up success anyway */
 	efx_for_each_tx_queue(tx_queue, efx) {
 		if (tx_queue->flushed != FLUSH_DONE)
-			EFX_ERR(efx, "tx queue %d flush command timed out\n",
-				tx_queue->queue);
+			netif_err(efx, hw, efx->net_dev,
+				  "tx queue %d flush command timed out\n",
+				  tx_queue->queue);
 		tx_queue->flushed = FLUSH_DONE;
 	}
 	efx_for_each_rx_queue(rx_queue, efx) {
 		if (rx_queue->flushed != FLUSH_DONE)
-			EFX_ERR(efx, "rx queue %d flush command timed out\n",
-				rx_queue->queue);
+			netif_err(efx, hw, efx->net_dev,
+				  "rx queue %d flush command timed out\n",
+				  rx_queue->queue);
 		rx_queue->flushed = FLUSH_DONE;
 	}
 
-	if (EFX_WORKAROUND_7803(efx))
-		return 0;
-
 	return -ETIMEDOUT;
 }
 
@@ -1290,10 +1341,10 @@
 	efx_reado(efx, &fatal_intr, FR_AZ_FATAL_INTR_KER);
 	error = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_FATAL_INTR);
 
-	EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status "
-		EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker),
-		EFX_OWORD_VAL(fatal_intr),
-		error ? "disabling bus mastering" : "no recognised error");
+	netif_err(efx, hw, efx->net_dev, "SYSTEM ERROR "EFX_OWORD_FMT" status "
+		  EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker),
+		  EFX_OWORD_VAL(fatal_intr),
+		  error ? "disabling bus mastering" : "no recognised error");
 
 	/* If this is a memory parity error dump which blocks are offending */
 	mem_perr = (EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER) ||
@@ -1301,8 +1352,9 @@
 	if (mem_perr) {
 		efx_oword_t reg;
 		efx_reado(efx, &reg, FR_AZ_MEM_STAT);
-		EFX_ERR(efx, "SYSTEM ERROR: memory parity error "
-			EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg));
+		netif_err(efx, hw, efx->net_dev,
+			  "SYSTEM ERROR: memory parity error "EFX_OWORD_FMT"\n",
+			  EFX_OWORD_VAL(reg));
 	}
 
 	/* Disable both devices */
@@ -1319,11 +1371,13 @@
 			jiffies + EFX_INT_ERROR_EXPIRE * HZ;
 	}
 	if (++efx->int_error_count < EFX_MAX_INT_ERRORS) {
-		EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n");
+		netif_err(efx, hw, efx->net_dev,
+			  "SYSTEM ERROR - reset scheduled\n");
 		efx_schedule_reset(efx, RESET_TYPE_INT_ERROR);
 	} else {
-		EFX_ERR(efx, "SYSTEM ERROR - max number of errors seen."
-			"NIC will be disabled\n");
+		netif_err(efx, hw, efx->net_dev,
+			  "SYSTEM ERROR - max number of errors seen."
+			  "NIC will be disabled\n");
 		efx_schedule_reset(efx, RESET_TYPE_DISABLE);
 	}
 
@@ -1386,8 +1440,9 @@
 
 	if (result == IRQ_HANDLED) {
 		efx->last_irq_cpu = raw_smp_processor_id();
-		EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
-			  irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
+		netif_vdbg(efx, intr, efx->net_dev,
+			   "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
+			   irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
 	}
 
 	return result;
@@ -1408,8 +1463,9 @@
 	int syserr;
 
 	efx->last_irq_cpu = raw_smp_processor_id();
-	EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
-		  irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
+	netif_vdbg(efx, intr, efx->net_dev,
+		   "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
+		   irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
 
 	/* Check to see if we have a serious error condition */
 	if (channel->channel == efx->fatal_irq_level) {
@@ -1428,22 +1484,21 @@
 /* Setup RSS indirection table.
  * This maps from the hash value of the packet to RXQ
  */
-static void efx_setup_rss_indir_table(struct efx_nic *efx)
+void efx_nic_push_rx_indir_table(struct efx_nic *efx)
 {
-	int i = 0;
-	unsigned long offset;
+	size_t i = 0;
 	efx_dword_t dword;
 
 	if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
 		return;
 
-	for (offset = FR_BZ_RX_INDIRECTION_TBL;
-	     offset < FR_BZ_RX_INDIRECTION_TBL + 0x800;
-	     offset += 0x10) {
+	BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) !=
+		     FR_BZ_RX_INDIRECTION_TBL_ROWS);
+
+	for (i = 0; i < FR_BZ_RX_INDIRECTION_TBL_ROWS; i++) {
 		EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE,
-				     i % efx->n_rx_channels);
-		efx_writed(efx, &dword, offset);
-		i++;
+				     efx->rx_indir_table[i]);
+		efx_writed_table(efx, &dword, FR_BZ_RX_INDIRECTION_TBL, i);
 	}
 }
 
@@ -1465,8 +1520,9 @@
 		rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED,
 				 efx->name, efx);
 		if (rc) {
-			EFX_ERR(efx, "failed to hook legacy IRQ %d\n",
-				efx->pci_dev->irq);
+			netif_err(efx, drv, efx->net_dev,
+				  "failed to hook legacy IRQ %d\n",
+				  efx->pci_dev->irq);
 			goto fail1;
 		}
 		return 0;
@@ -1478,7 +1534,8 @@
 				 IRQF_PROBE_SHARED, /* Not shared */
 				 channel->name, channel);
 		if (rc) {
-			EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq);
+			netif_err(efx, drv, efx->net_dev,
+				  "failed to hook IRQ %d\n", channel->irq);
 			goto fail2;
 		}
 	}
@@ -1576,7 +1633,7 @@
 	EFX_INVERT_OWORD(temp);
 	efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER);
 
-	efx_setup_rss_indir_table(efx);
+	efx_nic_push_rx_indir_table(efx);
 
 	/* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be
 	 * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q.
@@ -1598,3 +1655,269 @@
 		EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
 	efx_writeo(efx, &temp, FR_AZ_TX_RESERVED);
 }
+
+/* Register dump */
+
+#define REGISTER_REVISION_A	1
+#define REGISTER_REVISION_B	2
+#define REGISTER_REVISION_C	3
+#define REGISTER_REVISION_Z	3	/* latest revision */
+
+struct efx_nic_reg {
+	u32 offset:24;
+	u32 min_revision:2, max_revision:2;
+};
+
+#define REGISTER(name, min_rev, max_rev) {				\
+	FR_ ## min_rev ## max_rev ## _ ## name,				\
+	REGISTER_REVISION_ ## min_rev, REGISTER_REVISION_ ## max_rev	\
+}
+#define REGISTER_AA(name) REGISTER(name, A, A)
+#define REGISTER_AB(name) REGISTER(name, A, B)
+#define REGISTER_AZ(name) REGISTER(name, A, Z)
+#define REGISTER_BB(name) REGISTER(name, B, B)
+#define REGISTER_BZ(name) REGISTER(name, B, Z)
+#define REGISTER_CZ(name) REGISTER(name, C, Z)
+
+static const struct efx_nic_reg efx_nic_regs[] = {
+	REGISTER_AZ(ADR_REGION),
+	REGISTER_AZ(INT_EN_KER),
+	REGISTER_BZ(INT_EN_CHAR),
+	REGISTER_AZ(INT_ADR_KER),
+	REGISTER_BZ(INT_ADR_CHAR),
+	/* INT_ACK_KER is WO */
+	/* INT_ISR0 is RC */
+	REGISTER_AZ(HW_INIT),
+	REGISTER_CZ(USR_EV_CFG),
+	REGISTER_AB(EE_SPI_HCMD),
+	REGISTER_AB(EE_SPI_HADR),
+	REGISTER_AB(EE_SPI_HDATA),
+	REGISTER_AB(EE_BASE_PAGE),
+	REGISTER_AB(EE_VPD_CFG0),
+	/* EE_VPD_SW_CNTL and EE_VPD_SW_DATA are not used */
+	/* PMBX_DBG_IADDR and PBMX_DBG_IDATA are indirect */
+	/* PCIE_CORE_INDIRECT is indirect */
+	REGISTER_AB(NIC_STAT),
+	REGISTER_AB(GPIO_CTL),
+	REGISTER_AB(GLB_CTL),
+	/* FATAL_INTR_KER and FATAL_INTR_CHAR are partly RC */
+	REGISTER_BZ(DP_CTRL),
+	REGISTER_AZ(MEM_STAT),
+	REGISTER_AZ(CS_DEBUG),
+	REGISTER_AZ(ALTERA_BUILD),
+	REGISTER_AZ(CSR_SPARE),
+	REGISTER_AB(PCIE_SD_CTL0123),
+	REGISTER_AB(PCIE_SD_CTL45),
+	REGISTER_AB(PCIE_PCS_CTL_STAT),
+	/* DEBUG_DATA_OUT is not used */
+	/* DRV_EV is WO */
+	REGISTER_AZ(EVQ_CTL),
+	REGISTER_AZ(EVQ_CNT1),
+	REGISTER_AZ(EVQ_CNT2),
+	REGISTER_AZ(BUF_TBL_CFG),
+	REGISTER_AZ(SRM_RX_DC_CFG),
+	REGISTER_AZ(SRM_TX_DC_CFG),
+	REGISTER_AZ(SRM_CFG),
+	/* BUF_TBL_UPD is WO */
+	REGISTER_AZ(SRM_UPD_EVQ),
+	REGISTER_AZ(SRAM_PARITY),
+	REGISTER_AZ(RX_CFG),
+	REGISTER_BZ(RX_FILTER_CTL),
+	/* RX_FLUSH_DESCQ is WO */
+	REGISTER_AZ(RX_DC_CFG),
+	REGISTER_AZ(RX_DC_PF_WM),
+	REGISTER_BZ(RX_RSS_TKEY),
+	/* RX_NODESC_DROP is RC */
+	REGISTER_AA(RX_SELF_RST),
+	/* RX_DEBUG, RX_PUSH_DROP are not used */
+	REGISTER_CZ(RX_RSS_IPV6_REG1),
+	REGISTER_CZ(RX_RSS_IPV6_REG2),
+	REGISTER_CZ(RX_RSS_IPV6_REG3),
+	/* TX_FLUSH_DESCQ is WO */
+	REGISTER_AZ(TX_DC_CFG),
+	REGISTER_AA(TX_CHKSM_CFG),
+	REGISTER_AZ(TX_CFG),
+	/* TX_PUSH_DROP is not used */
+	REGISTER_AZ(TX_RESERVED),
+	REGISTER_BZ(TX_PACE),
+	/* TX_PACE_DROP_QID is RC */
+	REGISTER_BB(TX_VLAN),
+	REGISTER_BZ(TX_IPFIL_PORTEN),
+	REGISTER_AB(MD_TXD),
+	REGISTER_AB(MD_RXD),
+	REGISTER_AB(MD_CS),
+	REGISTER_AB(MD_PHY_ADR),
+	REGISTER_AB(MD_ID),
+	/* MD_STAT is RC */
+	REGISTER_AB(MAC_STAT_DMA),
+	REGISTER_AB(MAC_CTRL),
+	REGISTER_BB(GEN_MODE),
+	REGISTER_AB(MAC_MC_HASH_REG0),
+	REGISTER_AB(MAC_MC_HASH_REG1),
+	REGISTER_AB(GM_CFG1),
+	REGISTER_AB(GM_CFG2),
+	/* GM_IPG and GM_HD are not used */
+	REGISTER_AB(GM_MAX_FLEN),
+	/* GM_TEST is not used */
+	REGISTER_AB(GM_ADR1),
+	REGISTER_AB(GM_ADR2),
+	REGISTER_AB(GMF_CFG0),
+	REGISTER_AB(GMF_CFG1),
+	REGISTER_AB(GMF_CFG2),
+	REGISTER_AB(GMF_CFG3),
+	REGISTER_AB(GMF_CFG4),
+	REGISTER_AB(GMF_CFG5),
+	REGISTER_BB(TX_SRC_MAC_CTL),
+	REGISTER_AB(XM_ADR_LO),
+	REGISTER_AB(XM_ADR_HI),
+	REGISTER_AB(XM_GLB_CFG),
+	REGISTER_AB(XM_TX_CFG),
+	REGISTER_AB(XM_RX_CFG),
+	REGISTER_AB(XM_MGT_INT_MASK),
+	REGISTER_AB(XM_FC),
+	REGISTER_AB(XM_PAUSE_TIME),
+	REGISTER_AB(XM_TX_PARAM),
+	REGISTER_AB(XM_RX_PARAM),
+	/* XM_MGT_INT_MSK (note no 'A') is RC */
+	REGISTER_AB(XX_PWR_RST),
+	REGISTER_AB(XX_SD_CTL),
+	REGISTER_AB(XX_TXDRV_CTL),
+	/* XX_PRBS_CTL, XX_PRBS_CHK and XX_PRBS_ERR are not used */
+	/* XX_CORE_STAT is partly RC */
+};
+
+struct efx_nic_reg_table {
+	u32 offset:24;
+	u32 min_revision:2, max_revision:2;
+	u32 step:6, rows:21;
+};
+
+#define REGISTER_TABLE_DIMENSIONS(_, offset, min_rev, max_rev, step, rows) { \
+	offset,								\
+	REGISTER_REVISION_ ## min_rev, REGISTER_REVISION_ ## max_rev,	\
+	step, rows							\
+}
+#define REGISTER_TABLE(name, min_rev, max_rev) 				\
+	REGISTER_TABLE_DIMENSIONS(					\
+		name, FR_ ## min_rev ## max_rev ## _ ## name,		\
+		min_rev, max_rev,					\
+		FR_ ## min_rev ## max_rev ## _ ## name ## _STEP,	\
+		FR_ ## min_rev ## max_rev ## _ ## name ## _ROWS)
+#define REGISTER_TABLE_AA(name) REGISTER_TABLE(name, A, A)
+#define REGISTER_TABLE_AZ(name) REGISTER_TABLE(name, A, Z)
+#define REGISTER_TABLE_BB(name) REGISTER_TABLE(name, B, B)
+#define REGISTER_TABLE_BZ(name) REGISTER_TABLE(name, B, Z)
+#define REGISTER_TABLE_BB_CZ(name)					\
+	REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, B, B,		\
+				  FR_BZ_ ## name ## _STEP,		\
+				  FR_BB_ ## name ## _ROWS),		\
+	REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, C, Z,		\
+				  FR_BZ_ ## name ## _STEP,		\
+				  FR_CZ_ ## name ## _ROWS)
+#define REGISTER_TABLE_CZ(name) REGISTER_TABLE(name, C, Z)
+
+static const struct efx_nic_reg_table efx_nic_reg_tables[] = {
+	/* DRIVER is not used */
+	/* EVQ_RPTR, TIMER_COMMAND, USR_EV and {RX,TX}_DESC_UPD are WO */
+	REGISTER_TABLE_BB(TX_IPFIL_TBL),
+	REGISTER_TABLE_BB(TX_SRC_MAC_TBL),
+	REGISTER_TABLE_AA(RX_DESC_PTR_TBL_KER),
+	REGISTER_TABLE_BB_CZ(RX_DESC_PTR_TBL),
+	REGISTER_TABLE_AA(TX_DESC_PTR_TBL_KER),
+	REGISTER_TABLE_BB_CZ(TX_DESC_PTR_TBL),
+	REGISTER_TABLE_AA(EVQ_PTR_TBL_KER),
+	REGISTER_TABLE_BB_CZ(EVQ_PTR_TBL),
+	/* The register buffer is allocated with slab, so we can't
+	 * reasonably read all of the buffer table (up to 8MB!).
+	 * However this driver will only use a few entries.  Reading
+	 * 1K entries allows for some expansion of queue count and
+	 * size before we need to change the version. */
+	REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL_KER, FR_AA_BUF_FULL_TBL_KER,
+				  A, A, 8, 1024),
+	REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL, FR_BZ_BUF_FULL_TBL,
+				  B, Z, 8, 1024),
+	/* RX_FILTER_TBL{0,1} is huge and not used by this driver */
+	REGISTER_TABLE_CZ(RX_MAC_FILTER_TBL0),
+	REGISTER_TABLE_BB_CZ(TIMER_TBL),
+	REGISTER_TABLE_BB_CZ(TX_PACE_TBL),
+	REGISTER_TABLE_BZ(RX_INDIRECTION_TBL),
+	/* TX_FILTER_TBL0 is huge and not used by this driver */
+	REGISTER_TABLE_CZ(TX_MAC_FILTER_TBL0),
+	REGISTER_TABLE_CZ(MC_TREG_SMEM),
+	/* MSIX_PBA_TABLE is not mapped */
+	/* SRM_DBG is not mapped (and is redundant with BUF_FLL_TBL) */
+};
+
+size_t efx_nic_get_regs_len(struct efx_nic *efx)
+{
+	const struct efx_nic_reg *reg;
+	const struct efx_nic_reg_table *table;
+	size_t len = 0;
+
+	for (reg = efx_nic_regs;
+	     reg < efx_nic_regs + ARRAY_SIZE(efx_nic_regs);
+	     reg++)
+		if (efx->type->revision >= reg->min_revision &&
+		    efx->type->revision <= reg->max_revision)
+			len += sizeof(efx_oword_t);
+
+	for (table = efx_nic_reg_tables;
+	     table < efx_nic_reg_tables + ARRAY_SIZE(efx_nic_reg_tables);
+	     table++)
+		if (efx->type->revision >= table->min_revision &&
+		    efx->type->revision <= table->max_revision)
+			len += table->rows * min_t(size_t, table->step, 16);
+
+	return len;
+}
+
+void efx_nic_get_regs(struct efx_nic *efx, void *buf)
+{
+	const struct efx_nic_reg *reg;
+	const struct efx_nic_reg_table *table;
+
+	for (reg = efx_nic_regs;
+	     reg < efx_nic_regs + ARRAY_SIZE(efx_nic_regs);
+	     reg++) {
+		if (efx->type->revision >= reg->min_revision &&
+		    efx->type->revision <= reg->max_revision) {
+			efx_reado(efx, (efx_oword_t *)buf, reg->offset);
+			buf += sizeof(efx_oword_t);
+		}
+	}
+
+	for (table = efx_nic_reg_tables;
+	     table < efx_nic_reg_tables + ARRAY_SIZE(efx_nic_reg_tables);
+	     table++) {
+		size_t size, i;
+
+		if (!(efx->type->revision >= table->min_revision &&
+		      efx->type->revision <= table->max_revision))
+			continue;
+
+		size = min_t(size_t, table->step, 16);
+
+		for (i = 0; i < table->rows; i++) {
+			switch (table->step) {
+			case 4: /* 32-bit register or SRAM */
+				efx_readd_table(efx, buf, table->offset, i);
+				break;
+			case 8: /* 64-bit SRAM */
+				efx_sram_readq(efx,
+					       efx->membase + table->offset,
+					       buf, i);
+				break;
+			case 16: /* 128-bit register */
+				efx_reado_table(efx, buf, table->offset, i);
+				break;
+			case 32: /* 128-bit register, interleaved */
+				efx_reado_table(efx, buf, table->offset, 2 * i);
+				break;
+			default:
+				WARN_ON(1);
+				return;
+			}
+			buf += size;
+		}
+	}
+}
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
index bbc2c0c..0438dc9 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/sfc/nic.h
@@ -142,7 +142,6 @@
 	u32 fw_build;
 	struct efx_mcdi_iface mcdi;
 	int wol_filter_id;
-	u8 ipv6_rss_key[40];
 };
 
 extern void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len);
@@ -190,8 +189,8 @@
 /* Interrupts and test events */
 extern int efx_nic_init_interrupt(struct efx_nic *efx);
 extern void efx_nic_enable_interrupts(struct efx_nic *efx);
-extern void efx_nic_generate_test_event(struct efx_channel *channel,
-					unsigned int magic);
+extern void efx_nic_generate_test_event(struct efx_channel *channel);
+extern void efx_nic_generate_fill_event(struct efx_channel *channel);
 extern void efx_nic_generate_interrupt(struct efx_nic *efx);
 extern void efx_nic_disable_interrupts(struct efx_nic *efx);
 extern void efx_nic_fini_interrupt(struct efx_nic *efx);
@@ -208,6 +207,7 @@
 extern void falcon_setup_xaui(struct efx_nic *efx);
 extern int falcon_reset_xaui(struct efx_nic *efx);
 extern void efx_nic_init_common(struct efx_nic *efx);
+extern void efx_nic_push_rx_indir_table(struct efx_nic *efx);
 
 int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer,
 			 unsigned int len);
@@ -222,6 +222,9 @@
 				  const struct efx_nic_register_test *regs,
 				  size_t n_regs);
 
+extern size_t efx_nic_get_regs_len(struct efx_nic *efx);
+extern void efx_nic_get_regs(struct efx_nic *efx, void *buf);
+
 /**************************************************************************
  *
  * Falcon MAC stats
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
index e077bef..68813d1 100644
--- a/drivers/net/sfc/qt202x_phy.c
+++ b/drivers/net/sfc/qt202x_phy.c
@@ -91,9 +91,10 @@
 		if (time_after(jiffies, timeout)) {
 			/* Some cables have EEPROMs that conflict with the
 			 * PHY's on-board EEPROM so it cannot load firmware */
-			EFX_ERR(efx, "If an SFP+ direct attach cable is"
-				" connected, please check that it complies"
-				" with the SFP+ specification\n");
+			netif_err(efx, hw, efx->net_dev,
+				  "If an SFP+ direct attach cable is"
+				  " connected, please check that it complies"
+				  " with the SFP+ specification\n");
 			return -ETIMEDOUT;
 		}
 		msleep(QT2025C_HEARTB_WAIT);
@@ -145,7 +146,8 @@
 		/* Bug 17689: occasionally heartbeat starts but firmware status
 		 * code never progresses beyond 0x00.  Try again, once, after
 		 * restarting execution of the firmware image. */
-		EFX_LOG(efx, "bashing QT2025C microcontroller\n");
+		netif_dbg(efx, hw, efx->net_dev,
+			  "bashing QT2025C microcontroller\n");
 		qt2025c_restart_firmware(efx);
 		rc = qt2025c_wait_heartbeat(efx);
 		if (rc != 0)
@@ -165,11 +167,12 @@
 	for (i = 0; i < sizeof(firmware_id); i++)
 		firmware_id[i] = efx_mdio_read(efx, MDIO_MMD_PCS,
 					       PCS_FW_PRODUCT_CODE_1 + i);
-	EFX_INFO(efx, "QT2025C firmware %xr%d v%d.%d.%d.%d [20%02d-%02d-%02d]\n",
-		 (firmware_id[0] << 8) | firmware_id[1], firmware_id[2],
-		 firmware_id[3] >> 4, firmware_id[3] & 0xf,
-		 firmware_id[4], firmware_id[5],
-		 firmware_id[6], firmware_id[7], firmware_id[8]);
+	netif_info(efx, probe, efx->net_dev,
+		   "QT2025C firmware %xr%d v%d.%d.%d.%d [20%02d-%02d-%02d]\n",
+		   (firmware_id[0] << 8) | firmware_id[1], firmware_id[2],
+		   firmware_id[3] >> 4, firmware_id[3] & 0xf,
+		   firmware_id[4], firmware_id[5],
+		   firmware_id[6], firmware_id[7], firmware_id[8]);
 	phy_data->firmware_ver = ((firmware_id[3] & 0xf0) << 20) |
 				 ((firmware_id[3] & 0x0f) << 16) |
 				 (firmware_id[4] << 8) | firmware_id[5];
@@ -198,7 +201,7 @@
 	}
 
 	if (time_after_eq(jiffies, phy_data->bug17190_timer)) {
-		EFX_LOG(efx, "bashing QT2025C PMA/PMD\n");
+		netif_dbg(efx, hw, efx->net_dev, "bashing QT2025C PMA/PMD\n");
 		efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1,
 				  MDIO_PMA_CTRL1_LOOPBACK, true);
 		msleep(100);
@@ -231,7 +234,8 @@
 	reg = efx_mdio_read(efx, 1, 0xc319);
 	if ((reg & 0x0038) == phy_op_mode)
 		return 0;
-	EFX_LOG(efx, "Switching PHY to mode 0x%04x\n", phy_op_mode);
+	netif_dbg(efx, hw, efx->net_dev, "Switching PHY to mode 0x%04x\n",
+		  phy_op_mode);
 
 	/* This sequence replicates the register writes configured in the boot
 	 * EEPROM (including the differences between board revisions), except
@@ -287,8 +291,9 @@
 	/* Wait for the microcontroller to be ready again */
 	rc = qt2025c_wait_reset(efx);
 	if (rc < 0) {
-		EFX_ERR(efx, "PHY microcontroller reset during mode switch "
-				"timed out\n");
+		netif_err(efx, hw, efx->net_dev,
+			  "PHY microcontroller reset during mode switch "
+			  "timed out\n");
 		return rc;
 	}
 
@@ -324,7 +329,7 @@
 	return 0;
 
  fail:
-	EFX_ERR(efx, "PHY reset timed out\n");
+	netif_err(efx, hw, efx->net_dev, "PHY reset timed out\n");
 	return rc;
 }
 
@@ -353,14 +358,15 @@
 
 	rc = qt202x_reset_phy(efx);
 	if (rc) {
-		EFX_ERR(efx, "PHY init failed\n");
+		netif_err(efx, probe, efx->net_dev, "PHY init failed\n");
 		return rc;
 	}
 
 	devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS);
-	EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n",
-		 devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid),
-		 efx_mdio_id_rev(devid));
+	netif_info(efx, probe, efx->net_dev,
+		   "PHY ID reg %x (OUI %06x model %02x revision %x)\n",
+		   devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid),
+		   efx_mdio_id_rev(devid));
 
 	if (efx->phy_type == PHY_TYPE_QT2025C)
 		qt2025c_firmware_id(efx);
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index e308818..799c461 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -25,6 +25,9 @@
 /* Number of RX descriptors pushed at once. */
 #define EFX_RX_BATCH  8
 
+/* Maximum size of a buffer sharing a page */
+#define EFX_RX_HALF_PAGE ((PAGE_SIZE >> 1) - sizeof(struct efx_rx_page_state))
+
 /* Size of buffer allocated for skb header area. */
 #define EFX_SKB_HEADERS  64u
 
@@ -98,155 +101,151 @@
 	return PAGE_SIZE << efx->rx_buffer_order;
 }
 
+static inline u32 efx_rx_buf_hash(struct efx_rx_buffer *buf)
+{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) || NET_IP_ALIGN % 4 == 0
+	return __le32_to_cpup((const __le32 *)(buf->data - 4));
+#else
+	const u8 *data = (const u8 *)(buf->data - 4);
+	return ((u32)data[0]       |
+		(u32)data[1] << 8  |
+		(u32)data[2] << 16 |
+		(u32)data[3] << 24);
+#endif
+}
 
 /**
- * efx_init_rx_buffer_skb - create new RX buffer using skb-based allocation
+ * efx_init_rx_buffers_skb - create EFX_RX_BATCH skb-based RX buffers
  *
  * @rx_queue:		Efx RX queue
- * @rx_buf:		RX buffer structure to populate
  *
- * This allocates memory for a new receive buffer, maps it for DMA,
- * and populates a struct efx_rx_buffer with the relevant
- * information.  Return a negative error code or 0 on success.
+ * This allocates EFX_RX_BATCH skbs, maps them for DMA, and populates a
+ * struct efx_rx_buffer for each one. Return a negative error code or 0
+ * on success. May fail having only inserted fewer than EFX_RX_BATCH
+ * buffers.
  */
-static int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
-				  struct efx_rx_buffer *rx_buf)
+static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue)
 {
 	struct efx_nic *efx = rx_queue->efx;
 	struct net_device *net_dev = efx->net_dev;
+	struct efx_rx_buffer *rx_buf;
 	int skb_len = efx->rx_buffer_len;
+	unsigned index, count;
 
-	rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
-	if (unlikely(!rx_buf->skb))
-		return -ENOMEM;
+	for (count = 0; count < EFX_RX_BATCH; ++count) {
+		index = rx_queue->added_count & EFX_RXQ_MASK;
+		rx_buf = efx_rx_buffer(rx_queue, index);
 
-	/* Adjust the SKB for padding and checksum */
-	skb_reserve(rx_buf->skb, NET_IP_ALIGN);
-	rx_buf->len = skb_len - NET_IP_ALIGN;
-	rx_buf->data = (char *)rx_buf->skb->data;
-	rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY;
+		rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
+		if (unlikely(!rx_buf->skb))
+			return -ENOMEM;
+		rx_buf->page = NULL;
 
-	rx_buf->dma_addr = pci_map_single(efx->pci_dev,
-					  rx_buf->data, rx_buf->len,
-					  PCI_DMA_FROMDEVICE);
+		/* Adjust the SKB for padding and checksum */
+		skb_reserve(rx_buf->skb, NET_IP_ALIGN);
+		rx_buf->len = skb_len - NET_IP_ALIGN;
+		rx_buf->data = (char *)rx_buf->skb->data;
+		rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY;
 
-	if (unlikely(pci_dma_mapping_error(efx->pci_dev, rx_buf->dma_addr))) {
-		dev_kfree_skb_any(rx_buf->skb);
-		rx_buf->skb = NULL;
-		return -EIO;
+		rx_buf->dma_addr = pci_map_single(efx->pci_dev,
+						  rx_buf->data, rx_buf->len,
+						  PCI_DMA_FROMDEVICE);
+		if (unlikely(pci_dma_mapping_error(efx->pci_dev,
+						   rx_buf->dma_addr))) {
+			dev_kfree_skb_any(rx_buf->skb);
+			rx_buf->skb = NULL;
+			return -EIO;
+		}
+
+		++rx_queue->added_count;
+		++rx_queue->alloc_skb_count;
 	}
 
 	return 0;
 }
 
 /**
- * efx_init_rx_buffer_page - create new RX buffer using page-based allocation
+ * efx_init_rx_buffers_page - create EFX_RX_BATCH page-based RX buffers
  *
  * @rx_queue:		Efx RX queue
- * @rx_buf:		RX buffer structure to populate
  *
- * This allocates memory for a new receive buffer, maps it for DMA,
- * and populates a struct efx_rx_buffer with the relevant
- * information.  Return a negative error code or 0 on success.
+ * This allocates memory for EFX_RX_BATCH receive buffers, maps them for DMA,
+ * and populates struct efx_rx_buffers for each one. Return a negative error
+ * code or 0 on success. If a single page can be split between two buffers,
+ * then the page will either be inserted fully, or not at at all.
  */
-static int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
-				   struct efx_rx_buffer *rx_buf)
+static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
 {
 	struct efx_nic *efx = rx_queue->efx;
-	int bytes, space, offset;
+	struct efx_rx_buffer *rx_buf;
+	struct page *page;
+	void *page_addr;
+	struct efx_rx_page_state *state;
+	dma_addr_t dma_addr;
+	unsigned index, count;
 
-	bytes = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
+	/* We can split a page between two buffers */
+	BUILD_BUG_ON(EFX_RX_BATCH & 1);
 
-	/* If there is space left in the previously allocated page,
-	 * then use it. Otherwise allocate a new one */
-	rx_buf->page = rx_queue->buf_page;
-	if (rx_buf->page == NULL) {
-		dma_addr_t dma_addr;
-
-		rx_buf->page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
-					   efx->rx_buffer_order);
-		if (unlikely(rx_buf->page == NULL))
+	for (count = 0; count < EFX_RX_BATCH; ++count) {
+		page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
+				   efx->rx_buffer_order);
+		if (unlikely(page == NULL))
 			return -ENOMEM;
-
-		dma_addr = pci_map_page(efx->pci_dev, rx_buf->page,
-					0, efx_rx_buf_size(efx),
+		dma_addr = pci_map_page(efx->pci_dev, page, 0,
+					efx_rx_buf_size(efx),
 					PCI_DMA_FROMDEVICE);
-
 		if (unlikely(pci_dma_mapping_error(efx->pci_dev, dma_addr))) {
-			__free_pages(rx_buf->page, efx->rx_buffer_order);
-			rx_buf->page = NULL;
+			__free_pages(page, efx->rx_buffer_order);
 			return -EIO;
 		}
+		page_addr = page_address(page);
+		state = page_addr;
+		state->refcnt = 0;
+		state->dma_addr = dma_addr;
 
-		rx_queue->buf_page = rx_buf->page;
-		rx_queue->buf_dma_addr = dma_addr;
-		rx_queue->buf_data = (page_address(rx_buf->page) +
-				      EFX_PAGE_IP_ALIGN);
-	}
+		page_addr += sizeof(struct efx_rx_page_state);
+		dma_addr += sizeof(struct efx_rx_page_state);
 
-	rx_buf->len = bytes;
-	rx_buf->data = rx_queue->buf_data;
-	offset = efx_rx_buf_offset(rx_buf);
-	rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
+	split:
+		index = rx_queue->added_count & EFX_RXQ_MASK;
+		rx_buf = efx_rx_buffer(rx_queue, index);
+		rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN;
+		rx_buf->skb = NULL;
+		rx_buf->page = page;
+		rx_buf->data = page_addr + EFX_PAGE_IP_ALIGN;
+		rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
+		++rx_queue->added_count;
+		++rx_queue->alloc_page_count;
+		++state->refcnt;
 
-	/* Try to pack multiple buffers per page */
-	if (efx->rx_buffer_order == 0) {
-		/* The next buffer starts on the next 512 byte boundary */
-		rx_queue->buf_data += ((bytes + 0x1ff) & ~0x1ff);
-		offset += ((bytes + 0x1ff) & ~0x1ff);
-
-		space = efx_rx_buf_size(efx) - offset;
-		if (space >= bytes) {
-			/* Refs dropped on kernel releasing each skb */
-			get_page(rx_queue->buf_page);
-			goto out;
+		if ((~count & 1) && (efx->rx_buffer_len <= EFX_RX_HALF_PAGE)) {
+			/* Use the second half of the page */
+			get_page(page);
+			dma_addr += (PAGE_SIZE >> 1);
+			page_addr += (PAGE_SIZE >> 1);
+			++count;
+			goto split;
 		}
 	}
 
-	/* This is the final RX buffer for this page, so mark it for
-	 * unmapping */
-	rx_queue->buf_page = NULL;
-	rx_buf->unmap_addr = rx_queue->buf_dma_addr;
-
- out:
 	return 0;
 }
 
-/* This allocates memory for a new receive buffer, maps it for DMA,
- * and populates a struct efx_rx_buffer with the relevant
- * information.
- */
-static int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
-			      struct efx_rx_buffer *new_rx_buf)
-{
-	int rc = 0;
-
-	if (rx_queue->channel->rx_alloc_push_pages) {
-		new_rx_buf->skb = NULL;
-		rc = efx_init_rx_buffer_page(rx_queue, new_rx_buf);
-		rx_queue->alloc_page_count++;
-	} else {
-		new_rx_buf->page = NULL;
-		rc = efx_init_rx_buffer_skb(rx_queue, new_rx_buf);
-		rx_queue->alloc_skb_count++;
-	}
-
-	if (unlikely(rc < 0))
-		EFX_LOG_RL(rx_queue->efx, "%s RXQ[%d] =%d\n", __func__,
-			   rx_queue->queue, rc);
-	return rc;
-}
-
 static void efx_unmap_rx_buffer(struct efx_nic *efx,
 				struct efx_rx_buffer *rx_buf)
 {
 	if (rx_buf->page) {
+		struct efx_rx_page_state *state;
+
 		EFX_BUG_ON_PARANOID(rx_buf->skb);
-		if (rx_buf->unmap_addr) {
-			pci_unmap_page(efx->pci_dev, rx_buf->unmap_addr,
+
+		state = page_address(rx_buf->page);
+		if (--state->refcnt == 0) {
+			pci_unmap_page(efx->pci_dev,
+				       state->dma_addr,
 				       efx_rx_buf_size(efx),
 				       PCI_DMA_FROMDEVICE);
-			rx_buf->unmap_addr = 0;
 		}
 	} else if (likely(rx_buf->skb)) {
 		pci_unmap_single(efx->pci_dev, rx_buf->dma_addr,
@@ -273,31 +272,84 @@
 	efx_free_rx_buffer(rx_queue->efx, rx_buf);
 }
 
+/* Attempt to resurrect the other receive buffer that used to share this page,
+ * which had previously been passed up to the kernel and freed. */
+static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue,
+				    struct efx_rx_buffer *rx_buf)
+{
+	struct efx_rx_page_state *state = page_address(rx_buf->page);
+	struct efx_rx_buffer *new_buf;
+	unsigned fill_level, index;
+
+	/* +1 because efx_rx_packet() incremented removed_count. +1 because
+	 * we'd like to insert an additional descriptor whilst leaving
+	 * EFX_RXD_HEAD_ROOM for the non-recycle path */
+	fill_level = (rx_queue->added_count - rx_queue->removed_count + 2);
+	if (unlikely(fill_level >= EFX_RXQ_SIZE - EFX_RXD_HEAD_ROOM)) {
+		/* We could place "state" on a list, and drain the list in
+		 * efx_fast_push_rx_descriptors(). For now, this will do. */
+		return;
+	}
+
+	++state->refcnt;
+	get_page(rx_buf->page);
+
+	index = rx_queue->added_count & EFX_RXQ_MASK;
+	new_buf = efx_rx_buffer(rx_queue, index);
+	new_buf->dma_addr = rx_buf->dma_addr ^ (PAGE_SIZE >> 1);
+	new_buf->skb = NULL;
+	new_buf->page = rx_buf->page;
+	new_buf->data = (void *)
+		((__force unsigned long)rx_buf->data ^ (PAGE_SIZE >> 1));
+	new_buf->len = rx_buf->len;
+	++rx_queue->added_count;
+}
+
+/* Recycle the given rx buffer directly back into the rx_queue. There is
+ * always room to add this buffer, because we've just popped a buffer. */
+static void efx_recycle_rx_buffer(struct efx_channel *channel,
+				  struct efx_rx_buffer *rx_buf)
+{
+	struct efx_nic *efx = channel->efx;
+	struct efx_rx_queue *rx_queue = &efx->rx_queue[channel->channel];
+	struct efx_rx_buffer *new_buf;
+	unsigned index;
+
+	if (rx_buf->page != NULL && efx->rx_buffer_len <= EFX_RX_HALF_PAGE &&
+	    page_count(rx_buf->page) == 1)
+		efx_resurrect_rx_buffer(rx_queue, rx_buf);
+
+	index = rx_queue->added_count & EFX_RXQ_MASK;
+	new_buf = efx_rx_buffer(rx_queue, index);
+
+	memcpy(new_buf, rx_buf, sizeof(*new_buf));
+	rx_buf->page = NULL;
+	rx_buf->skb = NULL;
+	++rx_queue->added_count;
+}
+
 /**
  * efx_fast_push_rx_descriptors - push new RX descriptors quickly
  * @rx_queue:		RX descriptor queue
- * @retry:              Recheck the fill level
  * This will aim to fill the RX descriptor queue up to
  * @rx_queue->@fast_fill_limit. If there is insufficient atomic
- * memory to do so, the caller should retry.
+ * memory to do so, a slow fill will be scheduled.
+ *
+ * The caller must provide serialisation (none is used here). In practise,
+ * this means this function must run from the NAPI handler, or be called
+ * when NAPI is disabled.
  */
-static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
-					  int retry)
+void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
 {
-	struct efx_rx_buffer *rx_buf;
-	unsigned fill_level, index;
-	int i, space, rc = 0;
+	struct efx_channel *channel = rx_queue->channel;
+	unsigned fill_level;
+	int space, rc = 0;
 
-	/* Calculate current fill level.  Do this outside the lock,
-	 * because most of the time we'll end up not wanting to do the
-	 * fill anyway.
-	 */
+	/* Calculate current fill level, and exit if we don't need to fill */
 	fill_level = (rx_queue->added_count - rx_queue->removed_count);
 	EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
-
-	/* Don't fill if we don't need to */
 	if (fill_level >= rx_queue->fast_fill_trigger)
-		return 0;
+		goto out;
 
 	/* Record minimum fill level */
 	if (unlikely(fill_level < rx_queue->min_fill)) {
@@ -305,99 +357,47 @@
 			rx_queue->min_fill = fill_level;
 	}
 
-	/* Acquire RX add lock.  If this lock is contended, then a fast
-	 * fill must already be in progress (e.g. in the refill
-	 * tasklet), so we don't need to do anything
-	 */
-	if (!spin_trylock_bh(&rx_queue->add_lock))
-		return -1;
-
- retry:
-	/* Recalculate current fill level now that we have the lock */
-	fill_level = (rx_queue->added_count - rx_queue->removed_count);
-	EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
 	space = rx_queue->fast_fill_limit - fill_level;
 	if (space < EFX_RX_BATCH)
-		goto out_unlock;
+		goto out;
 
-	EFX_TRACE(rx_queue->efx, "RX queue %d fast-filling descriptor ring from"
-		  " level %d to level %d using %s allocation\n",
-		  rx_queue->queue, fill_level, rx_queue->fast_fill_limit,
-		  rx_queue->channel->rx_alloc_push_pages ? "page" : "skb");
+	netif_vdbg(rx_queue->efx, rx_status, rx_queue->efx->net_dev,
+		   "RX queue %d fast-filling descriptor ring from"
+		   " level %d to level %d using %s allocation\n",
+		   rx_queue->queue, fill_level, rx_queue->fast_fill_limit,
+		   channel->rx_alloc_push_pages ? "page" : "skb");
 
 	do {
-		for (i = 0; i < EFX_RX_BATCH; ++i) {
-			index = rx_queue->added_count & EFX_RXQ_MASK;
-			rx_buf = efx_rx_buffer(rx_queue, index);
-			rc = efx_init_rx_buffer(rx_queue, rx_buf);
-			if (unlikely(rc))
-				goto out;
-			++rx_queue->added_count;
+		if (channel->rx_alloc_push_pages)
+			rc = efx_init_rx_buffers_page(rx_queue);
+		else
+			rc = efx_init_rx_buffers_skb(rx_queue);
+		if (unlikely(rc)) {
+			/* Ensure that we don't leave the rx queue empty */
+			if (rx_queue->added_count == rx_queue->removed_count)
+				efx_schedule_slow_fill(rx_queue);
+			goto out;
 		}
 	} while ((space -= EFX_RX_BATCH) >= EFX_RX_BATCH);
 
-	EFX_TRACE(rx_queue->efx, "RX queue %d fast-filled descriptor ring "
-		  "to level %d\n", rx_queue->queue,
-		  rx_queue->added_count - rx_queue->removed_count);
+	netif_vdbg(rx_queue->efx, rx_status, rx_queue->efx->net_dev,
+		   "RX queue %d fast-filled descriptor ring "
+		   "to level %d\n", rx_queue->queue,
+		   rx_queue->added_count - rx_queue->removed_count);
 
  out:
-	/* Send write pointer to card. */
-	efx_nic_notify_rx_desc(rx_queue);
-
-	/* If the fast fill is running inside from the refill tasklet, then
-	 * for SMP systems it may be running on a different CPU to
-	 * RX event processing, which means that the fill level may now be
-	 * out of date. */
-	if (unlikely(retry && (rc == 0)))
-		goto retry;
-
- out_unlock:
-	spin_unlock_bh(&rx_queue->add_lock);
-
-	return rc;
+	if (rx_queue->notified_count != rx_queue->added_count)
+		efx_nic_notify_rx_desc(rx_queue);
 }
 
-/**
- * efx_fast_push_rx_descriptors - push new RX descriptors quickly
- * @rx_queue:		RX descriptor queue
- *
- * This will aim to fill the RX descriptor queue up to
- * @rx_queue->@fast_fill_limit.  If there is insufficient memory to do so,
- * it will schedule a work item to immediately continue the fast fill
- */
-void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
+void efx_rx_slow_fill(unsigned long context)
 {
-	int rc;
+	struct efx_rx_queue *rx_queue = (struct efx_rx_queue *)context;
+	struct efx_channel *channel = rx_queue->channel;
 
-	rc = __efx_fast_push_rx_descriptors(rx_queue, 0);
-	if (unlikely(rc)) {
-		/* Schedule the work item to run immediately. The hope is
-		 * that work is immediately pending to free some memory
-		 * (e.g. an RX event or TX completion)
-		 */
-		efx_schedule_slow_fill(rx_queue, 0);
-	}
-}
-
-void efx_rx_work(struct work_struct *data)
-{
-	struct efx_rx_queue *rx_queue;
-	int rc;
-
-	rx_queue = container_of(data, struct efx_rx_queue, work.work);
-
-	if (unlikely(!rx_queue->channel->enabled))
-		return;
-
-	EFX_TRACE(rx_queue->efx, "RX queue %d worker thread executing on CPU "
-		  "%d\n", rx_queue->queue, raw_smp_processor_id());
-
+	/* Post an event to cause NAPI to run and refill the queue */
+	efx_nic_generate_fill_event(channel);
 	++rx_queue->slow_fill_count;
-	/* Push new RX descriptors, allowing at least 1 jiffy for
-	 * the kernel to free some more memory. */
-	rc = __efx_fast_push_rx_descriptors(rx_queue, 1);
-	if (rc)
-		efx_schedule_slow_fill(rx_queue, 1);
 }
 
 static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
@@ -417,10 +417,12 @@
 	*discard = true;
 
 	if ((len > rx_buf->len) && EFX_WORKAROUND_8071(efx)) {
-		EFX_ERR_RL(efx, " RX queue %d seriously overlength "
-			   "RX event (0x%x > 0x%x+0x%x). Leaking\n",
-			   rx_queue->queue, len, max_len,
-			   efx->type->rx_buffer_padding);
+		if (net_ratelimit())
+			netif_err(efx, rx_err, efx->net_dev,
+				  " RX queue %d seriously overlength "
+				  "RX event (0x%x > 0x%x+0x%x). Leaking\n",
+				  rx_queue->queue, len, max_len,
+				  efx->type->rx_buffer_padding);
 		/* If this buffer was skb-allocated, then the meta
 		 * data at the end of the skb will be trashed. So
 		 * we have no choice but to leak the fragment.
@@ -428,8 +430,11 @@
 		*leak_packet = (rx_buf->skb != NULL);
 		efx_schedule_reset(efx, RESET_TYPE_RX_RECOVERY);
 	} else {
-		EFX_ERR_RL(efx, " RX queue %d overlength RX event "
-			   "(0x%x > 0x%x)\n", rx_queue->queue, len, max_len);
+		if (net_ratelimit())
+			netif_err(efx, rx_err, efx->net_dev,
+				  " RX queue %d overlength RX event "
+				  "(0x%x > 0x%x)\n",
+				  rx_queue->queue, len, max_len);
 	}
 
 	rx_queue->channel->n_rx_overlength++;
@@ -449,6 +454,7 @@
 
 	/* Pass the skb/page into the LRO engine */
 	if (rx_buf->page) {
+		struct efx_nic *efx = channel->efx;
 		struct page *page = rx_buf->page;
 		struct sk_buff *skb;
 
@@ -461,6 +467,9 @@
 			return;
 		}
 
+		if (efx->net_dev->features & NETIF_F_RXHASH)
+			skb->rxhash = efx_rx_buf_hash(rx_buf);
+
 		skb_shinfo(skb)->frags[0].page = page;
 		skb_shinfo(skb)->frags[0].page_offset =
 			efx_rx_buf_offset(rx_buf);
@@ -498,6 +507,7 @@
 		   unsigned int len, bool checksummed, bool discard)
 {
 	struct efx_nic *efx = rx_queue->efx;
+	struct efx_channel *channel = rx_queue->channel;
 	struct efx_rx_buffer *rx_buf;
 	bool leak_packet = false;
 
@@ -516,21 +526,23 @@
 	efx_rx_packet__check_len(rx_queue, rx_buf, len,
 				 &discard, &leak_packet);
 
-	EFX_TRACE(efx, "RX queue %d received id %x at %llx+%x %s%s\n",
-		  rx_queue->queue, index,
-		  (unsigned long long)rx_buf->dma_addr, len,
-		  (checksummed ? " [SUMMED]" : ""),
-		  (discard ? " [DISCARD]" : ""));
+	netif_vdbg(efx, rx_status, efx->net_dev,
+		   "RX queue %d received id %x at %llx+%x %s%s\n",
+		   rx_queue->queue, index,
+		   (unsigned long long)rx_buf->dma_addr, len,
+		   (checksummed ? " [SUMMED]" : ""),
+		   (discard ? " [DISCARD]" : ""));
 
 	/* Discard packet, if instructed to do so */
 	if (unlikely(discard)) {
 		if (unlikely(leak_packet))
-			rx_queue->channel->n_skbuff_leaks++;
+			channel->n_skbuff_leaks++;
 		else
-			/* We haven't called efx_unmap_rx_buffer yet,
-			 * so fini the entire rx_buffer here */
-			efx_fini_rx_buffer(rx_queue, rx_buf);
-		return;
+			efx_recycle_rx_buffer(channel, rx_buf);
+
+		/* Don't hold off the previous receive */
+		rx_buf = NULL;
+		goto out;
 	}
 
 	/* Release card resources - assumes all RX buffers consumed in-order
@@ -547,6 +559,7 @@
 	 * prefetched into cache.
 	 */
 	rx_buf->len = len;
+out:
 	if (rx_queue->channel->rx_pkt)
 		__efx_rx_packet(rx_queue->channel,
 				rx_queue->channel->rx_pkt,
@@ -562,6 +575,9 @@
 	struct efx_nic *efx = channel->efx;
 	struct sk_buff *skb;
 
+	rx_buf->data += efx->type->rx_buffer_hash_size;
+	rx_buf->len -= efx->type->rx_buffer_hash_size;
+
 	/* If we're in loopback test, then pass the packet directly to the
 	 * loopback layer, and free the rx_buf here
 	 */
@@ -574,8 +590,12 @@
 	if (rx_buf->skb) {
 		prefetch(skb_shinfo(rx_buf->skb));
 
+		skb_reserve(rx_buf->skb, efx->type->rx_buffer_hash_size);
 		skb_put(rx_buf->skb, rx_buf->len);
 
+		if (efx->net_dev->features & NETIF_F_RXHASH)
+			rx_buf->skb->rxhash = efx_rx_buf_hash(rx_buf);
+
 		/* Move past the ethernet header. rx_buf->data still points
 		 * at the ethernet header */
 		rx_buf->skb->protocol = eth_type_trans(rx_buf->skb,
@@ -633,7 +653,8 @@
 	unsigned int rxq_size;
 	int rc;
 
-	EFX_LOG(efx, "creating RX queue %d\n", rx_queue->queue);
+	netif_dbg(efx, probe, efx->net_dev,
+		  "creating RX queue %d\n", rx_queue->queue);
 
 	/* Allocate RX buffers */
 	rxq_size = EFX_RXQ_SIZE * sizeof(*rx_queue->buffer);
@@ -653,7 +674,8 @@
 {
 	unsigned int max_fill, trigger, limit;
 
-	EFX_LOG(rx_queue->efx, "initialising RX queue %d\n", rx_queue->queue);
+	netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev,
+		  "initialising RX queue %d\n", rx_queue->queue);
 
 	/* Initialise ptr fields */
 	rx_queue->added_count = 0;
@@ -680,8 +702,10 @@
 	int i;
 	struct efx_rx_buffer *rx_buf;
 
-	EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue);
+	netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev,
+		  "shutting down RX queue %d\n", rx_queue->queue);
 
+	del_timer_sync(&rx_queue->slow_fill);
 	efx_nic_fini_rx(rx_queue);
 
 	/* Release RX buffers NB start at index 0 not current HW ptr */
@@ -691,21 +715,12 @@
 			efx_fini_rx_buffer(rx_queue, rx_buf);
 		}
 	}
-
-	/* For a page that is part-way through splitting into RX buffers */
-	if (rx_queue->buf_page != NULL) {
-		pci_unmap_page(rx_queue->efx->pci_dev, rx_queue->buf_dma_addr,
-			       efx_rx_buf_size(rx_queue->efx),
-			       PCI_DMA_FROMDEVICE);
-		__free_pages(rx_queue->buf_page,
-			     rx_queue->efx->rx_buffer_order);
-		rx_queue->buf_page = NULL;
-	}
 }
 
 void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
 {
-	EFX_LOG(rx_queue->efx, "destroying RX queue %d\n", rx_queue->queue);
+	netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev,
+		  "destroying RX queue %d\n", rx_queue->queue);
 
 	efx_nic_remove_rx(rx_queue);
 
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 371e86c..85f015f 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -38,7 +38,7 @@
 	struct udphdr udp;
 	__be16 iteration;
 	const char msg[64];
-} __attribute__ ((packed));
+} __packed;
 
 /* Loopback test source MAC address */
 static const unsigned char payload_source[ETH_ALEN] = {
@@ -123,7 +123,7 @@
 {
 	struct efx_channel *channel;
 
-	EFX_LOG(efx, "testing interrupts\n");
+	netif_dbg(efx, drv, efx->net_dev, "testing interrupts\n");
 	tests->interrupt = -1;
 
 	/* Reset interrupt flag */
@@ -142,16 +142,17 @@
 	efx_nic_generate_interrupt(efx);
 
 	/* Wait for arrival of test interrupt. */
-	EFX_LOG(efx, "waiting for test interrupt\n");
+	netif_dbg(efx, drv, efx->net_dev, "waiting for test interrupt\n");
 	schedule_timeout_uninterruptible(HZ / 10);
 	if (efx->last_irq_cpu >= 0)
 		goto success;
 
-	EFX_ERR(efx, "timed out waiting for interrupt\n");
+	netif_err(efx, drv, efx->net_dev, "timed out waiting for interrupt\n");
 	return -ETIMEDOUT;
 
  success:
-	EFX_LOG(efx, "%s test interrupt seen on CPU%d\n", INT_MODE(efx),
+	netif_dbg(efx, drv, efx->net_dev, "%s test interrupt seen on CPU%d\n",
+		  INT_MODE(efx),
 		efx->last_irq_cpu);
 	tests->interrupt = 1;
 	return 0;
@@ -161,23 +162,18 @@
 static int efx_test_eventq_irq(struct efx_channel *channel,
 			       struct efx_self_tests *tests)
 {
-	unsigned int magic, count;
-
-	/* Channel specific code, limited to 20 bits */
-	magic = (0x00010150 + channel->channel);
-	EFX_LOG(channel->efx, "channel %d testing event queue with code %x\n",
-		channel->channel, magic);
+	struct efx_nic *efx = channel->efx;
+	unsigned int magic_count, count;
 
 	tests->eventq_dma[channel->channel] = -1;
 	tests->eventq_int[channel->channel] = -1;
 	tests->eventq_poll[channel->channel] = -1;
 
-	/* Reset flag and zero magic word */
+	magic_count = channel->magic_count;
 	channel->efx->last_irq_cpu = -1;
-	channel->eventq_magic = 0;
 	smp_wmb();
 
-	efx_nic_generate_test_event(channel, magic);
+	efx_nic_generate_test_event(channel);
 
 	/* Wait for arrival of interrupt */
 	count = 0;
@@ -187,33 +183,36 @@
 		if (channel->work_pending)
 			efx_process_channel_now(channel);
 
-		if (channel->eventq_magic == magic)
+		if (channel->magic_count != magic_count)
 			goto eventq_ok;
 	} while (++count < 2);
 
-	EFX_ERR(channel->efx, "channel %d timed out waiting for event queue\n",
-		channel->channel);
+	netif_err(efx, drv, efx->net_dev,
+		  "channel %d timed out waiting for event queue\n",
+		  channel->channel);
 
 	/* See if interrupt arrived */
 	if (channel->efx->last_irq_cpu >= 0) {
-		EFX_ERR(channel->efx, "channel %d saw interrupt on CPU%d "
-			"during event queue test\n", channel->channel,
-			raw_smp_processor_id());
+		netif_err(efx, drv, efx->net_dev,
+			  "channel %d saw interrupt on CPU%d "
+			  "during event queue test\n", channel->channel,
+			  raw_smp_processor_id());
 		tests->eventq_int[channel->channel] = 1;
 	}
 
 	/* Check to see if event was received even if interrupt wasn't */
 	efx_process_channel_now(channel);
-	if (channel->eventq_magic == magic) {
-		EFX_ERR(channel->efx, "channel %d event was generated, but "
-			"failed to trigger an interrupt\n", channel->channel);
+	if (channel->magic_count != magic_count) {
+		netif_err(efx, drv, efx->net_dev,
+			  "channel %d event was generated, but "
+			  "failed to trigger an interrupt\n", channel->channel);
 		tests->eventq_dma[channel->channel] = 1;
 	}
 
 	return -ETIMEDOUT;
  eventq_ok:
-	EFX_LOG(channel->efx, "channel %d event queue passed\n",
-		channel->channel);
+	netif_dbg(efx, drv, efx->net_dev, "channel %d event queue passed\n",
+		  channel->channel);
 	tests->eventq_dma[channel->channel] = 1;
 	tests->eventq_int[channel->channel] = 1;
 	tests->eventq_poll[channel->channel] = 1;
@@ -266,51 +265,57 @@
 
 	/* Check that header exists */
 	if (pkt_len < sizeof(received->header)) {
-		EFX_ERR(efx, "saw runt RX packet (length %d) in %s loopback "
-			"test\n", pkt_len, LOOPBACK_MODE(efx));
+		netif_err(efx, drv, efx->net_dev,
+			  "saw runt RX packet (length %d) in %s loopback "
+			  "test\n", pkt_len, LOOPBACK_MODE(efx));
 		goto err;
 	}
 
 	/* Check that the ethernet header exists */
 	if (memcmp(&received->header, &payload->header, ETH_HLEN) != 0) {
-		EFX_ERR(efx, "saw non-loopback RX packet in %s loopback test\n",
-			LOOPBACK_MODE(efx));
+		netif_err(efx, drv, efx->net_dev,
+			  "saw non-loopback RX packet in %s loopback test\n",
+			  LOOPBACK_MODE(efx));
 		goto err;
 	}
 
 	/* Check packet length */
 	if (pkt_len != sizeof(*payload)) {
-		EFX_ERR(efx, "saw incorrect RX packet length %d (wanted %d) in "
-			"%s loopback test\n", pkt_len, (int)sizeof(*payload),
-			LOOPBACK_MODE(efx));
+		netif_err(efx, drv, efx->net_dev,
+			  "saw incorrect RX packet length %d (wanted %d) in "
+			  "%s loopback test\n", pkt_len, (int)sizeof(*payload),
+			  LOOPBACK_MODE(efx));
 		goto err;
 	}
 
 	/* Check that IP header matches */
 	if (memcmp(&received->ip, &payload->ip, sizeof(payload->ip)) != 0) {
-		EFX_ERR(efx, "saw corrupted IP header in %s loopback test\n",
-			LOOPBACK_MODE(efx));
+		netif_err(efx, drv, efx->net_dev,
+			  "saw corrupted IP header in %s loopback test\n",
+			  LOOPBACK_MODE(efx));
 		goto err;
 	}
 
 	/* Check that msg and padding matches */
 	if (memcmp(&received->msg, &payload->msg, sizeof(received->msg)) != 0) {
-		EFX_ERR(efx, "saw corrupted RX packet in %s loopback test\n",
-			LOOPBACK_MODE(efx));
+		netif_err(efx, drv, efx->net_dev,
+			  "saw corrupted RX packet in %s loopback test\n",
+			  LOOPBACK_MODE(efx));
 		goto err;
 	}
 
 	/* Check that iteration matches */
 	if (received->iteration != payload->iteration) {
-		EFX_ERR(efx, "saw RX packet from iteration %d (wanted %d) in "
-			"%s loopback test\n", ntohs(received->iteration),
-			ntohs(payload->iteration), LOOPBACK_MODE(efx));
+		netif_err(efx, drv, efx->net_dev,
+			  "saw RX packet from iteration %d (wanted %d) in "
+			  "%s loopback test\n", ntohs(received->iteration),
+			  ntohs(payload->iteration), LOOPBACK_MODE(efx));
 		goto err;
 	}
 
 	/* Increase correct RX count */
-	EFX_TRACE(efx, "got loopback RX in %s loopback test\n",
-		  LOOPBACK_MODE(efx));
+	netif_vdbg(efx, drv, efx->net_dev,
+		   "got loopback RX in %s loopback test\n", LOOPBACK_MODE(efx));
 
 	atomic_inc(&state->rx_good);
 	return;
@@ -318,10 +323,10 @@
  err:
 #ifdef EFX_ENABLE_DEBUG
 	if (atomic_read(&state->rx_bad) == 0) {
-		EFX_ERR(efx, "received packet:\n");
+		netif_err(efx, drv, efx->net_dev, "received packet:\n");
 		print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1,
 			       buf_ptr, pkt_len, 0);
-		EFX_ERR(efx, "expected packet:\n");
+		netif_err(efx, drv, efx->net_dev, "expected packet:\n");
 		print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1,
 			       &state->payload, sizeof(state->payload), 0);
 	}
@@ -402,9 +407,11 @@
 			netif_tx_unlock_bh(efx->net_dev);
 
 		if (rc != NETDEV_TX_OK) {
-			EFX_ERR(efx, "TX queue %d could not transmit packet %d "
-				"of %d in %s loopback test\n", tx_queue->queue,
-				i + 1, state->packet_count, LOOPBACK_MODE(efx));
+			netif_err(efx, drv, efx->net_dev,
+				  "TX queue %d could not transmit packet %d of "
+				  "%d in %s loopback test\n", tx_queue->queue,
+				  i + 1, state->packet_count,
+				  LOOPBACK_MODE(efx));
 
 			/* Defer cleaning up the other skbs for the caller */
 			kfree_skb(skb);
@@ -460,20 +467,22 @@
 		/* Don't free the skbs; they will be picked up on TX
 		 * overflow or channel teardown.
 		 */
-		EFX_ERR(efx, "TX queue %d saw only %d out of an expected %d "
-			"TX completion events in %s loopback test\n",
-			tx_queue->queue, tx_done, state->packet_count,
-			LOOPBACK_MODE(efx));
+		netif_err(efx, drv, efx->net_dev,
+			  "TX queue %d saw only %d out of an expected %d "
+			  "TX completion events in %s loopback test\n",
+			  tx_queue->queue, tx_done, state->packet_count,
+			  LOOPBACK_MODE(efx));
 		rc = -ETIMEDOUT;
 		/* Allow to fall through so we see the RX errors as well */
 	}
 
 	/* We may always be up to a flush away from our desired packet total */
 	if (rx_good != state->packet_count) {
-		EFX_LOG(efx, "TX queue %d saw only %d out of an expected %d "
-			"received packets in %s loopback test\n",
-			tx_queue->queue, rx_good, state->packet_count,
-			LOOPBACK_MODE(efx));
+		netif_dbg(efx, drv, efx->net_dev,
+			  "TX queue %d saw only %d out of an expected %d "
+			  "received packets in %s loopback test\n",
+			  tx_queue->queue, rx_good, state->packet_count,
+			  LOOPBACK_MODE(efx));
 		rc = -ETIMEDOUT;
 		/* Fall through */
 	}
@@ -505,9 +514,10 @@
 			return -ENOMEM;
 		state->flush = false;
 
-		EFX_LOG(efx, "TX queue %d testing %s loopback with %d "
-			"packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
-			state->packet_count);
+		netif_dbg(efx, drv, efx->net_dev,
+			  "TX queue %d testing %s loopback with %d packets\n",
+			  tx_queue->queue, LOOPBACK_MODE(efx),
+			  state->packet_count);
 
 		efx_iterate_state(efx);
 		begin_rc = efx_begin_loopback(tx_queue);
@@ -531,9 +541,10 @@
 		}
 	}
 
-	EFX_LOG(efx, "TX queue %d passed %s loopback test with a burst length "
-		"of %d packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
-		state->packet_count);
+	netif_dbg(efx, drv, efx->net_dev,
+		  "TX queue %d passed %s loopback test with a burst length "
+		  "of %d packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
+		  state->packet_count);
 
 	return 0;
 }
@@ -545,7 +556,7 @@
 static int efx_wait_for_link(struct efx_nic *efx)
 {
 	struct efx_link_state *link_state = &efx->link_state;
-	int count;
+	int count, link_up_count = 0;
 	bool link_up;
 
 	for (count = 0; count < 40; count++) {
@@ -567,8 +578,12 @@
 			link_up = !efx->mac_op->check_fault(efx);
 		mutex_unlock(&efx->mac_lock);
 
-		if (link_up)
-			return 0;
+		if (link_up) {
+			if (++link_up_count == 2)
+				return 0;
+		} else {
+			link_up_count = 0;
+		}
 	}
 
 	return -ETIMEDOUT;
@@ -604,15 +619,17 @@
 		rc = __efx_reconfigure_port(efx);
 		mutex_unlock(&efx->mac_lock);
 		if (rc) {
-			EFX_ERR(efx, "unable to move into %s loopback\n",
-				LOOPBACK_MODE(efx));
+			netif_err(efx, drv, efx->net_dev,
+				  "unable to move into %s loopback\n",
+				  LOOPBACK_MODE(efx));
 			goto out;
 		}
 
 		rc = efx_wait_for_link(efx);
 		if (rc) {
-			EFX_ERR(efx, "loopback %s never came up\n",
-				LOOPBACK_MODE(efx));
+			netif_err(efx, drv, efx->net_dev,
+				  "loopback %s never came up\n",
+				  LOOPBACK_MODE(efx));
 			goto out;
 		}
 
@@ -720,7 +737,8 @@
 		rc_reset = rc;
 
 	if (rc_reset) {
-		EFX_ERR(efx, "Unable to recover from chip test\n");
+		netif_err(efx, drv, efx->net_dev,
+			  "Unable to recover from chip test\n");
 		efx_schedule_reset(efx, RESET_TYPE_DISABLE);
 		return rc_reset;
 	}
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index f2b1e61..3fab030 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -118,10 +118,11 @@
 				  MC_CMD_MAC_NSTATS * sizeof(u64));
 	if (rc)
 		return rc;
-	EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n",
-		(u64)efx->stats_buffer.dma_addr,
-		efx->stats_buffer.addr,
-		(u64)virt_to_phys(efx->stats_buffer.addr));
+	netif_dbg(efx, probe, efx->net_dev,
+		  "stats buffer at %llx (virt %p phys %llx)\n",
+		  (u64)efx->stats_buffer.dma_addr,
+		  efx->stats_buffer.addr,
+		  (u64)virt_to_phys(efx->stats_buffer.addr));
 
 	efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 1);
 
@@ -216,7 +217,8 @@
 	efx->nic_data = nic_data;
 
 	if (efx_nic_fpga_ver(efx) != 0) {
-		EFX_ERR(efx, "Siena FPGA not supported\n");
+		netif_err(efx, probe, efx->net_dev,
+			  "Siena FPGA not supported\n");
 		rc = -ENODEV;
 		goto fail1;
 	}
@@ -233,8 +235,8 @@
 
 	rc = efx_mcdi_fwver(efx, &nic_data->fw_version, &nic_data->fw_build);
 	if (rc) {
-		EFX_ERR(efx, "Failed to read MCPU firmware version - "
-			"rc %d\n", rc);
+		netif_err(efx, probe, efx->net_dev,
+			  "Failed to read MCPU firmware version - rc %d\n", rc);
 		goto fail1; /* MCPU absent? */
 	}
 
@@ -242,17 +244,19 @@
 	 * filter settings. We must do this before we reset the NIC */
 	rc = efx_mcdi_drv_attach(efx, true, &already_attached);
 	if (rc) {
-		EFX_ERR(efx, "Unable to register driver with MCPU\n");
+		netif_err(efx, probe, efx->net_dev,
+			  "Unable to register driver with MCPU\n");
 		goto fail2;
 	}
 	if (already_attached)
 		/* Not a fatal error */
-		EFX_ERR(efx, "Host already registered with MCPU\n");
+		netif_err(efx, probe, efx->net_dev,
+			  "Host already registered with MCPU\n");
 
 	/* Now we can reset the NIC */
 	rc = siena_reset_hw(efx, RESET_TYPE_ALL);
 	if (rc) {
-		EFX_ERR(efx, "failed to reset NIC\n");
+		netif_err(efx, probe, efx->net_dev, "failed to reset NIC\n");
 		goto fail3;
 	}
 
@@ -264,24 +268,23 @@
 		goto fail4;
 	BUG_ON(efx->irq_status.dma_addr & 0x0f);
 
-	EFX_LOG(efx, "INT_KER at %llx (virt %p phys %llx)\n",
-		(unsigned long long)efx->irq_status.dma_addr,
-		efx->irq_status.addr,
-		(unsigned long long)virt_to_phys(efx->irq_status.addr));
+	netif_dbg(efx, probe, efx->net_dev,
+		  "INT_KER at %llx (virt %p phys %llx)\n",
+		  (unsigned long long)efx->irq_status.dma_addr,
+		  efx->irq_status.addr,
+		  (unsigned long long)virt_to_phys(efx->irq_status.addr));
 
 	/* Read in the non-volatile configuration */
 	rc = siena_probe_nvconfig(efx);
 	if (rc == -EINVAL) {
-		EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n");
+		netif_err(efx, probe, efx->net_dev,
+			  "NVRAM is invalid therefore using defaults\n");
 		efx->phy_type = PHY_TYPE_NONE;
 		efx->mdio.prtad = MDIO_PRTAD_NONE;
 	} else if (rc) {
 		goto fail5;
 	}
 
-	get_random_bytes(&nic_data->ipv6_rss_key,
-			 sizeof(nic_data->ipv6_rss_key));
-
 	return 0;
 
 fail5:
@@ -301,7 +304,6 @@
  */
 static int siena_init_nic(struct efx_nic *efx)
 {
-	struct siena_nic_data *nic_data = efx->nic_data;
 	efx_oword_t temp;
 	int rc;
 
@@ -326,25 +328,36 @@
 	efx_reado(efx, &temp, FR_AZ_RX_CFG);
 	EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_DESC_PUSH_EN, 0);
 	EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_INGR_EN, 1);
+	/* Enable hash insertion. This is broken for the 'Falcon' hash
+	 * if IPv6 hashing is also enabled, so also select Toeplitz
+	 * TCP/IPv4 and IPv4 hashes. */
+	EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_HASH_INSRT_HDR, 1);
+	EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_HASH_ALG, 1);
+	EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_IP_HASH, 1);
 	efx_writeo(efx, &temp, FR_AZ_RX_CFG);
 
+	/* Set hash key for IPv4 */
+	memcpy(&temp, efx->rx_hash_key, sizeof(temp));
+	efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY);
+
 	/* Enable IPv6 RSS */
-	BUILD_BUG_ON(sizeof(nic_data->ipv6_rss_key) !=
+	BUILD_BUG_ON(sizeof(efx->rx_hash_key) <
 		     2 * sizeof(temp) + FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8 ||
 		     FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN != 0);
-	memcpy(&temp, nic_data->ipv6_rss_key, sizeof(temp));
+	memcpy(&temp, efx->rx_hash_key, sizeof(temp));
 	efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG1);
-	memcpy(&temp, nic_data->ipv6_rss_key + sizeof(temp), sizeof(temp));
+	memcpy(&temp, efx->rx_hash_key + sizeof(temp), sizeof(temp));
 	efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG2);
 	EFX_POPULATE_OWORD_2(temp, FRF_CZ_RX_RSS_IPV6_THASH_ENABLE, 1,
 			     FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE, 1);
-	memcpy(&temp, nic_data->ipv6_rss_key + 2 * sizeof(temp),
+	memcpy(&temp, efx->rx_hash_key + 2 * sizeof(temp),
 	       FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8);
 	efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3);
 
 	if (efx_nic_rx_xoff_thresh >= 0 || efx_nic_rx_xon_thresh >= 0)
 		/* No MCDI operation has been defined to set thresholds */
-		EFX_ERR(efx, "ignoring RX flow control thresholds\n");
+		netif_err(efx, hw, efx->net_dev,
+			  "ignoring RX flow control thresholds\n");
 
 	/* Enable event logging */
 	rc = efx_mcdi_log_ctrl(efx, true, false, 0);
@@ -565,7 +578,8 @@
 
 	return 0;
  fail:
-	EFX_ERR(efx, "%s failed: type=%d rc=%d\n", __func__, type, rc);
+	netif_err(efx, hw, efx->net_dev, "%s failed: type=%d rc=%d\n",
+		  __func__, type, rc);
 	return rc;
 }
 
@@ -628,6 +642,7 @@
 	.evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL,
 	.evq_rptr_tbl_base = FR_BZ_EVQ_RPTR,
 	.max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
+	.rx_buffer_hash_size = 0x10,
 	.rx_buffer_padding = 0,
 	.max_interrupt_mode = EFX_INT_MODE_MSIX,
 	.phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
@@ -635,6 +650,7 @@
 				   * channels */
 	.tx_dc_base = 0x88000,
 	.rx_dc_base = 0x68000,
-	.offload_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM,
+	.offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+			     NETIF_F_RXHASH),
 	.reset_world_flags = ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT,
 };
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index f21efe7..6791be9 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -228,7 +228,8 @@
 		boot_stat = efx_mdio_read(efx, MDIO_MMD_PCS,
 					  PCS_BOOT_STATUS_REG);
 		if (boot_stat >= 0) {
-			EFX_LOG(efx, "PHY boot status = %#x\n", boot_stat);
+			netif_dbg(efx, hw, efx->net_dev,
+				  "PHY boot status = %#x\n", boot_stat);
 			switch (boot_stat &
 				((1 << PCS_BOOT_FATAL_ERROR_LBN) |
 				 (3 << PCS_BOOT_PROGRESS_LBN) |
@@ -463,10 +464,11 @@
 			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");
+			netif_err(efx, link, efx->net_dev,
+				  "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");
 		}
 		efx_mdio_write(efx, MDIO_MMD_PMAPMD,
 			       PMA_PMD_LED_OVERR_REG, reg);
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
index 6bb12a8..c6942da 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/sfc/tx.c
@@ -42,7 +42,7 @@
 		return;
 
 	spin_lock_bh(&channel->tx_stop_lock);
-	EFX_TRACE(efx, "stop TX queue\n");
+	netif_vdbg(efx, tx_queued, efx->net_dev, "stop TX queue\n");
 
 	atomic_inc(&channel->tx_stop_count);
 	netif_tx_stop_queue(
@@ -64,7 +64,7 @@
 	local_bh_disable();
 	if (atomic_dec_and_lock(&channel->tx_stop_count,
 				&channel->tx_stop_lock)) {
-		EFX_TRACE(efx, "waking TX queue\n");
+		netif_vdbg(efx, tx_queued, efx->net_dev, "waking TX queue\n");
 		netif_tx_wake_queue(
 			netdev_get_tx_queue(
 				efx->net_dev,
@@ -94,8 +94,9 @@
 	if (buffer->skb) {
 		dev_kfree_skb_any((struct sk_buff *) buffer->skb);
 		buffer->skb = NULL;
-		EFX_TRACE(tx_queue->efx, "TX queue %d transmission id %x "
-			  "complete\n", tx_queue->queue, read_ptr);
+		netif_vdbg(tx_queue->efx, tx_done, tx_queue->efx->net_dev,
+			   "TX queue %d transmission id %x complete\n",
+			   tx_queue->queue, tx_queue->read_count);
 	}
 }
 
@@ -300,9 +301,10 @@
 	return NETDEV_TX_OK;
 
  pci_err:
-	EFX_ERR_RL(efx, " TX queue %d could not map skb with %d bytes %d "
-		   "fragments for DMA\n", tx_queue->queue, skb->len,
-		   skb_shinfo(skb)->nr_frags + 1);
+	netif_err(efx, tx_err, efx->net_dev,
+		  " TX queue %d could not map skb with %d bytes %d "
+		  "fragments for DMA\n", tx_queue->queue, skb->len,
+		  skb_shinfo(skb)->nr_frags + 1);
 
 	/* Mark the packet as transmitted, and free the SKB ourselves */
 	dev_kfree_skb_any(skb);
@@ -354,9 +356,9 @@
 	while (read_ptr != stop_index) {
 		struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr];
 		if (unlikely(buffer->len == 0)) {
-			EFX_ERR(tx_queue->efx, "TX queue %d spurious TX "
-				"completion id %x\n", tx_queue->queue,
-				read_ptr);
+			netif_err(efx, tx_err, efx->net_dev,
+				  "TX queue %d spurious TX completion id %x\n",
+				  tx_queue->queue, read_ptr);
 			efx_schedule_reset(efx, RESET_TYPE_TX_SKIP);
 			return;
 		}
@@ -431,7 +433,8 @@
 	unsigned int txq_size;
 	int i, rc;
 
-	EFX_LOG(efx, "creating TX queue %d\n", tx_queue->queue);
+	netif_dbg(efx, probe, efx->net_dev, "creating TX queue %d\n",
+		  tx_queue->queue);
 
 	/* Allocate software ring */
 	txq_size = EFX_TXQ_SIZE * sizeof(*tx_queue->buffer);
@@ -456,7 +459,8 @@
 
 void efx_init_tx_queue(struct efx_tx_queue *tx_queue)
 {
-	EFX_LOG(tx_queue->efx, "initialising TX queue %d\n", tx_queue->queue);
+	netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev,
+		  "initialising TX queue %d\n", tx_queue->queue);
 
 	tx_queue->insert_count = 0;
 	tx_queue->write_count = 0;
@@ -488,7 +492,8 @@
 
 void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
 {
-	EFX_LOG(tx_queue->efx, "shutting down TX queue %d\n", tx_queue->queue);
+	netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev,
+		  "shutting down TX queue %d\n", tx_queue->queue);
 
 	/* Flush TX queue, remove descriptor ring */
 	efx_nic_fini_tx(tx_queue);
@@ -507,7 +512,8 @@
 
 void efx_remove_tx_queue(struct efx_tx_queue *tx_queue)
 {
-	EFX_LOG(tx_queue->efx, "destroying TX queue %d\n", tx_queue->queue);
+	netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev,
+		  "destroying TX queue %d\n", tx_queue->queue);
 	efx_nic_remove_tx(tx_queue);
 
 	kfree(tx_queue->buffer);
@@ -639,8 +645,8 @@
 
 	base_kva = pci_alloc_consistent(pci_dev, PAGE_SIZE, &dma_addr);
 	if (base_kva == NULL) {
-		EFX_ERR(tx_queue->efx, "Unable to allocate page for TSO"
-			" headers\n");
+		netif_err(tx_queue->efx, tx_err, tx_queue->efx->net_dev,
+			  "Unable to allocate page for TSO headers\n");
 		return -ENOMEM;
 	}
 
@@ -1124,7 +1130,8 @@
 	return NETDEV_TX_OK;
 
  mem_err:
-	EFX_ERR(efx, "Out of memory for TSO headers, or PCI mapping error\n");
+	netif_err(efx, tx_err, efx->net_dev,
+		  "Out of memory for TSO headers, or PCI mapping error\n");
 	dev_kfree_skb_any(skb);
 	goto unwind;
 
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index 518f7fc..782e45a 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -54,7 +54,7 @@
 /* Increase filter depth to avoid RX_RESET */
 #define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A
 /* Flushes may never complete */
-#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_A
+#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_AB
 /* Leak overlength packets rather than free */
 #define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
 
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 70a9bc5..f5a9eb1 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -88,6 +88,55 @@
 	.rpadir		= 1,
 	.rpadir_value	= 0x00020000, /* NET_IP_ALIGN assumed to be 2 */
 };
+#elif defined(CONFIG_CPU_SUBTYPE_SH7757)
+#define SH_ETH_RESET_DEFAULT	1
+static void sh_eth_set_duplex(struct net_device *ndev)
+{
+	struct sh_eth_private *mdp = netdev_priv(ndev);
+	u32 ioaddr = ndev->base_addr;
+
+	if (mdp->duplex) /* Full */
+		ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR);
+	else		/* Half */
+		ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR);
+}
+
+static void sh_eth_set_rate(struct net_device *ndev)
+{
+	struct sh_eth_private *mdp = netdev_priv(ndev);
+	u32 ioaddr = ndev->base_addr;
+
+	switch (mdp->speed) {
+	case 10: /* 10BASE */
+		ctrl_outl(0, ioaddr + RTRATE);
+		break;
+	case 100:/* 100BASE */
+		ctrl_outl(1, ioaddr + RTRATE);
+		break;
+	default:
+		break;
+	}
+}
+
+/* SH7757 */
+static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
+	.set_duplex		= sh_eth_set_duplex,
+	.set_rate		= sh_eth_set_rate,
+
+	.eesipr_value	= DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+	.rmcr_value	= 0x00000001,
+
+	.tx_check	= EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO,
+	.eesr_err_check	= EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE |
+			  EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI,
+	.tx_error_check	= EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE,
+
+	.apr		= 1,
+	.mpr		= 1,
+	.tpauser	= 1,
+	.hw_swap	= 1,
+	.no_ade		= 1,
+};
 
 #elif defined(CONFIG_CPU_SUBTYPE_SH7763)
 #define SH_ETH_HAS_TSU	1
@@ -1023,7 +1072,9 @@
 	pm_runtime_get_sync(&mdp->pdev->dev);
 
 	ret = request_irq(ndev->irq, sh_eth_interrupt,
-#if defined(CONFIG_CPU_SUBTYPE_SH7763) || defined(CONFIG_CPU_SUBTYPE_SH7764)
+#if defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7764) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7757)
 				IRQF_SHARED,
 #else
 				0,
@@ -1233,7 +1284,7 @@
 	if (!phydev)
 		return -ENODEV;
 
-	return phy_mii_ioctl(phydev, if_mii(rq), cmd);
+	return phy_mii_ioctl(phydev, rq, cmd);
 }
 
 #if defined(SH_ETH_HAS_TSU)
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 7985165..194e5cf 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -79,7 +79,7 @@
 
 #define SKY2_EEPROM_MAGIC	0x9955aabb
 
-#define RING_NEXT(x,s)	(((x)+1) & ((s)-1))
+#define RING_NEXT(x, s)	(((x)+1) & ((s)-1))
 
 static const u32 default_msg =
     NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
@@ -172,7 +172,7 @@
 		udelay(10);
 	}
 
-	dev_warn(&hw->pdev->dev,"%s: phy write timeout\n", hw->dev[port]->name);
+	dev_warn(&hw->pdev->dev, "%s: phy write timeout\n", hw->dev[port]->name);
 	return -ETIMEDOUT;
 
 io_error:
@@ -1067,7 +1067,7 @@
 	return le;
 }
 
-static unsigned sky2_get_rx_threshold(struct sky2_port* sky2)
+static unsigned sky2_get_rx_threshold(struct sky2_port *sky2)
 {
 	unsigned size;
 
@@ -1078,7 +1078,7 @@
 	return (size - 8) / sizeof(u32);
 }
 
-static unsigned sky2_get_rx_data_size(struct sky2_port* sky2)
+static unsigned sky2_get_rx_data_size(struct sky2_port *sky2)
 {
 	struct rx_ring_info *re;
 	unsigned size;
@@ -1102,7 +1102,7 @@
 }
 
 /* Build description to hardware for one receive segment */
-static void sky2_rx_add(struct sky2_port *sky2,  u8 op,
+static void sky2_rx_add(struct sky2_port *sky2, u8 op,
 			dma_addr_t map, unsigned len)
 {
 	struct sky2_rx_le *le;
@@ -3014,7 +3014,7 @@
 	hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
 	hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
 
-	switch(hw->chip_id) {
+	switch (hw->chip_id) {
 	case CHIP_ID_YUKON_XL:
 		hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY;
 		if (hw->chip_rev < CHIP_REV_YU_XL_A2)
@@ -3685,7 +3685,7 @@
 	return 0;
 }
 
-static void inline sky2_add_filter(u8 filter[8], const u8 *addr)
+static inline void sky2_add_filter(u8 filter[8], const u8 *addr)
 {
 	u32 bit;
 
@@ -3911,7 +3911,7 @@
 		return -EINVAL;
 	if (ecmd->rx_max_coalesced_frames > RX_MAX_PENDING)
 		return -EINVAL;
-	if (ecmd->rx_max_coalesced_frames_irq >RX_MAX_PENDING)
+	if (ecmd->rx_max_coalesced_frames_irq > RX_MAX_PENDING)
 		return -EINVAL;
 
 	if (ecmd->tx_coalesce_usecs == 0)
@@ -4188,17 +4188,13 @@
 static int sky2_set_flags(struct net_device *dev, u32 data)
 {
 	struct sky2_port *sky2 = netdev_priv(dev);
+	u32 supported =
+		(sky2->hw->flags & SKY2_HW_RSS_BROKEN) ? 0 : ETH_FLAG_RXHASH;
+	int rc;
 
-	if (data & ~ETH_FLAG_RXHASH)
-		return -EOPNOTSUPP;
-
-	if (data & ETH_FLAG_RXHASH) {
-		if (sky2->hw->flags & SKY2_HW_RSS_BROKEN)
-			return -EINVAL;
-
-		dev->features |= NETIF_F_RXHASH;
-	} else
-		dev->features &= ~NETIF_F_RXHASH;
+	rc = ethtool_op_set_flags(dev, data, supported);
+	if (rc)
+		return rc;
 
 	rx_set_rss(dev);
 
@@ -4376,7 +4372,7 @@
 			seq_printf(seq, "%u:", idx);
 		sop = 0;
 
-		switch(le->opcode & ~HW_OWNER) {
+		switch (le->opcode & ~HW_OWNER) {
 		case OP_ADDR64:
 			seq_printf(seq, " %#x:", a);
 			break;
@@ -4445,7 +4441,7 @@
 	if (dev->netdev_ops->ndo_open != sky2_up || !sky2_debug)
 		return NOTIFY_DONE;
 
-	switch(event) {
+	switch (event) {
 	case NETDEV_CHANGENAME:
 		if (sky2->debugfs) {
 			sky2->debugfs = debugfs_rename(sky2_debug, sky2->debugfs,
@@ -4640,7 +4636,7 @@
 	struct pci_dev *pdev = hw->pdev;
 	int err;
 
-	init_waitqueue_head (&hw->msi_wait);
+	init_waitqueue_head(&hw->msi_wait);
 
 	sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW);
 
@@ -4757,7 +4753,7 @@
 	 * this driver uses software swapping.
 	 */
 	reg &= ~PCI_REV_DESC;
-	err = pci_write_config_dword(pdev,PCI_DEV_REG2, reg);
+	err = pci_write_config_dword(pdev, PCI_DEV_REG2, reg);
 	if (err) {
 		dev_err(&pdev->dev, "PCI write config failed\n");
 		goto err_out_free_regions;
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 084eff2..61891a6 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -2161,21 +2161,21 @@
 	__le16	length;	/* also vlan tag or checksum start */
 	u8	ctrl;
 	u8	opcode;
-} __attribute((packed));
+} __packed;
 
 struct sky2_rx_le {
 	__le32	addr;
 	__le16	length;
 	u8	ctrl;
 	u8	opcode;
-} __attribute((packed));
+} __packed;
 
 struct sky2_status_le {
 	__le32	status;	/* also checksum */
 	__le16	length;	/* also vlan tag */
 	u8	css;
 	u8	opcode;
-} __attribute((packed));
+} __packed;
 
 struct tx_ring_info {
 	struct sk_buff	*skb;
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index cc55974..0909ae9 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -84,8 +84,7 @@
 	 */
 	spinlock_t mac_lock;
 
-	/* spinlock to ensure 16-bit accesses are serialised.
-	 * unused with a 32-bit bus */
+	/* spinlock to ensure register accesses are serialised */
 	spinlock_t dev_lock;
 
 	struct phy_device *phy_dev;
@@ -118,37 +117,33 @@
 	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)
+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) |
+	if (pdata->config.flags & SMSC911X_USE_16BIT)
+		return ((readw(pdata->ioaddr + reg) & 0xFFFF) |
 			((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16));
-		spin_unlock_irqrestore(&pdata->dev_lock, flags);
-
-		return data;
-	}
 
 	BUG();
 	return 0;
 }
 
-static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
-				      u32 val)
+static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
+{
+	u32 data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pdata->dev_lock, flags);
+	data = __smsc911x_reg_read(pdata, reg);
+	spin_unlock_irqrestore(&pdata->dev_lock, flags);
+
+	return data;
+}
+
+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);
@@ -156,44 +151,54 @@
 	}
 
 	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();
 }
 
+static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
+				      u32 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&pdata->dev_lock, flags);
+	__smsc911x_reg_write(pdata, reg, val);
+	spin_unlock_irqrestore(&pdata->dev_lock, flags);
+}
+
 /* Writes a packet to the TX_DATA_FIFO */
 static inline void
 smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf,
 		      unsigned int wordcount)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&pdata->dev_lock, flags);
+
 	if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
 		while (wordcount--)
-			smsc911x_reg_write(pdata, TX_DATA_FIFO, swab32(*buf++));
-		return;
+			__smsc911x_reg_write(pdata, TX_DATA_FIFO,
+					     swab32(*buf++));
+		goto out;
 	}
 
 	if (pdata->config.flags & SMSC911X_USE_32BIT) {
 		writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount);
-		return;
+		goto out;
 	}
 
 	if (pdata->config.flags & SMSC911X_USE_16BIT) {
 		while (wordcount--)
-			smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++);
-		return;
+			__smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++);
+		goto out;
 	}
 
 	BUG();
+out:
+	spin_unlock_irqrestore(&pdata->dev_lock, flags);
 }
 
 /* Reads a packet out of the RX_DATA_FIFO */
@@ -201,24 +206,31 @@
 smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf,
 		     unsigned int wordcount)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&pdata->dev_lock, flags);
+
 	if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
 		while (wordcount--)
-			*buf++ = swab32(smsc911x_reg_read(pdata, RX_DATA_FIFO));
-		return;
+			*buf++ = swab32(__smsc911x_reg_read(pdata,
+							    RX_DATA_FIFO));
+		goto out;
 	}
 
 	if (pdata->config.flags & SMSC911X_USE_32BIT) {
 		readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount);
-		return;
+		goto out;
 	}
 
 	if (pdata->config.flags & SMSC911X_USE_16BIT) {
 		while (wordcount--)
-			*buf++ = smsc911x_reg_read(pdata, RX_DATA_FIFO);
-		return;
+			*buf++ = __smsc911x_reg_read(pdata, RX_DATA_FIFO);
+		goto out;
 	}
 
 	BUG();
+out:
+	spin_unlock_irqrestore(&pdata->dev_lock, flags);
 }
 
 /* waits for MAC not busy, with timeout.  Only called by smsc911x_mac_read
@@ -1538,7 +1550,7 @@
 	if (!netif_running(dev) || !pdata->phy_dev)
 		return -EINVAL;
 
-	return phy_mii_ioctl(pdata->phy_dev, if_mii(ifr), cmd);
+	return phy_mii_ioctl(pdata->phy_dev, ifr, cmd);
 }
 
 static int
diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c
index 6cdee6a..b09ee1c 100644
--- a/drivers/net/smsc9420.c
+++ b/drivers/net/smsc9420.c
@@ -245,7 +245,7 @@
 	if (!netif_running(dev) || !pd->phy_dev)
 		return -EINVAL;
 
-	return phy_mii_ioctl(pd->phy_dev, if_mii(ifr), cmd);
+	return phy_mii_ioctl(pd->phy_dev, ifr, cmd);
 }
 
 static int smsc9420_ethtool_get_settings(struct net_device *dev,
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 74b7ae7..a42b687 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -562,7 +562,6 @@
 	unsigned int tx_done;
 	struct napi_struct napi;
 	struct net_device *dev;
-	struct net_device_stats stats;
 	struct pci_dev *pci_dev;
 #ifdef VLAN_SUPPORT
 	struct vlan_group *vlgrp;
@@ -1174,7 +1173,7 @@
 	/* Trigger an immediate transmit demand. */
 
 	dev->trans_start = jiffies; /* prevent tx timeout */
-	np->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	netif_wake_queue(dev);
 }
 
@@ -1265,7 +1264,7 @@
 			}
 			if (skb->ip_summed == CHECKSUM_PARTIAL) {
 				status |= TxCalTCP;
-				np->stats.tx_compressed++;
+				dev->stats.tx_compressed++;
 			}
 			status |= skb_first_frag_len(skb) | (skb_num_frags(skb) << 16);
 
@@ -1374,7 +1373,7 @@
 				printk(KERN_DEBUG "%s: Tx completion #%d entry %d is %#8.8x.\n",
 				       dev->name, np->dirty_tx, np->tx_done, tx_status);
 			if ((tx_status & 0xe0000000) == 0xa0000000) {
-				np->stats.tx_packets++;
+				dev->stats.tx_packets++;
 			} else if ((tx_status & 0xe0000000) == 0x80000000) {
 				u16 entry = (tx_status & 0x7fff) / sizeof(starfire_tx_desc);
 				struct sk_buff *skb = np->tx_info[entry].skb;
@@ -1462,9 +1461,9 @@
 			/* There was an error. */
 			if (debug > 2)
 				printk(KERN_DEBUG "  netdev_rx() Rx error was %#8.8x.\n", desc_status);
-			np->stats.rx_errors++;
+			dev->stats.rx_errors++;
 			if (desc_status & RxFIFOErr)
-				np->stats.rx_fifo_errors++;
+				dev->stats.rx_fifo_errors++;
 			goto next_rx;
 		}
 
@@ -1515,7 +1514,7 @@
 #endif
 		if (le16_to_cpu(desc->status2) & 0x0100) {
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
-			np->stats.rx_compressed++;
+			dev->stats.rx_compressed++;
 		}
 		/*
 		 * This feature doesn't seem to be working, at least
@@ -1547,7 +1546,7 @@
 		} else
 #endif /* VLAN_SUPPORT */
 			netif_receive_skb(skb);
-		np->stats.rx_packets++;
+		dev->stats.rx_packets++;
 
 	next_rx:
 		np->cur_rx++;
@@ -1717,12 +1716,12 @@
 			printk(KERN_WARNING "%s: PCI Tx underflow -- adapter is probably malfunctioning\n", dev->name);
 	}
 	if (intr_status & IntrRxGFPDead) {
-		np->stats.rx_fifo_errors++;
-		np->stats.rx_errors++;
+		dev->stats.rx_fifo_errors++;
+		dev->stats.rx_errors++;
 	}
 	if (intr_status & (IntrNoTxCsum | IntrDMAErr)) {
-		np->stats.tx_fifo_errors++;
-		np->stats.tx_errors++;
+		dev->stats.tx_fifo_errors++;
+		dev->stats.tx_errors++;
 	}
 	if ((intr_status & ~(IntrNormalMask | IntrAbnormalSummary | IntrLinkChange | IntrStatsMax | IntrTxDataLow | IntrRxGFPDead | IntrNoTxCsum | IntrPCIPad)) && debug)
 		printk(KERN_ERR "%s: Something Wicked happened! %#8.8x.\n",
@@ -1736,24 +1735,24 @@
 	void __iomem *ioaddr = np->base;
 
 	/* This adapter architecture needs no SMP locks. */
-	np->stats.tx_bytes = readl(ioaddr + 0x57010);
-	np->stats.rx_bytes = readl(ioaddr + 0x57044);
-	np->stats.tx_packets = readl(ioaddr + 0x57000);
-	np->stats.tx_aborted_errors =
+	dev->stats.tx_bytes = readl(ioaddr + 0x57010);
+	dev->stats.rx_bytes = readl(ioaddr + 0x57044);
+	dev->stats.tx_packets = readl(ioaddr + 0x57000);
+	dev->stats.tx_aborted_errors =
 		readl(ioaddr + 0x57024) + readl(ioaddr + 0x57028);
-	np->stats.tx_window_errors = readl(ioaddr + 0x57018);
-	np->stats.collisions =
+	dev->stats.tx_window_errors = readl(ioaddr + 0x57018);
+	dev->stats.collisions =
 		readl(ioaddr + 0x57004) + readl(ioaddr + 0x57008);
 
 	/* The chip only need report frame silently dropped. */
-	np->stats.rx_dropped += readw(ioaddr + RxDMAStatus);
+	dev->stats.rx_dropped += readw(ioaddr + RxDMAStatus);
 	writew(0, ioaddr + RxDMAStatus);
-	np->stats.rx_crc_errors = readl(ioaddr + 0x5703C);
-	np->stats.rx_frame_errors = readl(ioaddr + 0x57040);
-	np->stats.rx_length_errors = readl(ioaddr + 0x57058);
-	np->stats.rx_missed_errors = readl(ioaddr + 0x5707C);
+	dev->stats.rx_crc_errors = readl(ioaddr + 0x5703C);
+	dev->stats.rx_frame_errors = readl(ioaddr + 0x57040);
+	dev->stats.rx_length_errors = readl(ioaddr + 0x57058);
+	dev->stats.rx_missed_errors = readl(ioaddr + 0x5707C);
 
-	return &np->stats;
+	return &dev->stats;
 }
 
 
diff --git a/drivers/net/stmmac/common.h b/drivers/net/stmmac/common.h
index 144f76f..66b9da0 100644
--- a/drivers/net/stmmac/common.h
+++ b/drivers/net/stmmac/common.h
@@ -108,6 +108,7 @@
 	good_frame = 0,
 	discard_frame = 1,
 	csum_none = 2,
+	llc_snap = 4,
 };
 
 enum tx_dma_irq_status {
diff --git a/drivers/net/stmmac/dwmac1000.h b/drivers/net/stmmac/dwmac1000.h
index d8d0f35..8b20b19 100644
--- a/drivers/net/stmmac/dwmac1000.h
+++ b/drivers/net/stmmac/dwmac1000.h
@@ -93,7 +93,7 @@
 #define GMAC_CONTROL_IPC	0x00000400 /* Checksum Offload */
 #define GMAC_CONTROL_DR		0x00000200 /* Disable Retry */
 #define GMAC_CONTROL_LUD	0x00000100 /* Link up/down */
-#define GMAC_CONTROL_ACS	0x00000080 /* Automatic Pad Stripping */
+#define GMAC_CONTROL_ACS	0x00000080 /* Automatic Pad/FCS Stripping */
 #define GMAC_CONTROL_DC		0x00000010 /* Deferral Check */
 #define GMAC_CONTROL_TE		0x00000008 /* Transmitter Enable */
 #define GMAC_CONTROL_RE		0x00000004 /* Receiver Enable */
diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c
index 917b4e1..2b2f5c8 100644
--- a/drivers/net/stmmac/dwmac1000_core.c
+++ b/drivers/net/stmmac/dwmac1000_core.c
@@ -220,6 +220,8 @@
 		((uid & 0x0000ff00) >> 8), (uid & 0x000000ff));
 
 	mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
+	if (!mac)
+		return NULL;
 
 	mac->mac = &dwmac1000_ops;
 	mac->dma = &dwmac1000_dma_ops;
diff --git a/drivers/net/stmmac/dwmac100_core.c b/drivers/net/stmmac/dwmac100_core.c
index 6f270a0..2fb165f 100644
--- a/drivers/net/stmmac/dwmac100_core.c
+++ b/drivers/net/stmmac/dwmac100_core.c
@@ -179,6 +179,8 @@
 	struct mac_device_info *mac;
 
 	mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
+	if (!mac)
+		return NULL;
 
 	pr_info("\tDWMAC100\n");
 
diff --git a/drivers/net/stmmac/enh_desc.c b/drivers/net/stmmac/enh_desc.c
index 3c18ebe..f612f98 100644
--- a/drivers/net/stmmac/enh_desc.c
+++ b/drivers/net/stmmac/enh_desc.c
@@ -123,7 +123,7 @@
 	 */
 	if (status == 0x0) {
 		CHIP_DBG(KERN_INFO "RX Des0 status: IEEE 802.3 Type frame.\n");
-		ret = good_frame;
+		ret = llc_snap;
 	} else if (status == 0x4) {
 		CHIP_DBG(KERN_INFO "RX Des0 status: IPv4/6 No CSUM errorS.\n");
 		ret = good_frame;
diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c
index a31d580..bbb7951 100644
--- a/drivers/net/stmmac/stmmac_main.c
+++ b/drivers/net/stmmac/stmmac_main.c
@@ -829,7 +829,6 @@
 	 * In case of failure continue without timer. */
 	if (unlikely((stmmac_open_ext_timer(dev, priv->tm)) < 0)) {
 		pr_warning("stmmaceth: cannot attach the external timer.\n");
-		tmrate = 0;
 		priv->tm->freq = 0;
 		priv->tm->timer_start = stmmac_no_timer_started;
 		priv->tm->timer_stop = stmmac_no_timer_stopped;
@@ -1217,9 +1216,13 @@
 			priv->dev->stats.rx_errors++;
 		else {
 			struct sk_buff *skb;
-			/* Length should omit the CRC */
-			int frame_len = priv->hw->desc->get_rx_frame_len(p) - 4;
+			int frame_len;
 
+			frame_len = priv->hw->desc->get_rx_frame_len(p);
+			/* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
+			 * Type frames (LLC/LLC-SNAP) */
+			if (unlikely(status != llc_snap))
+				frame_len -= ETH_FCS_LEN;
 #ifdef STMMAC_RX_DEBUG
 			if (frame_len > ETH_FRAME_LEN)
 				pr_debug("\tRX frame size %d, COE status: %d\n",
@@ -1437,24 +1440,18 @@
 static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct stmmac_priv *priv = netdev_priv(dev);
-	int ret = -EOPNOTSUPP;
+	int ret;
 
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	switch (cmd) {
-	case SIOCGMIIPHY:
-	case SIOCGMIIREG:
-	case SIOCSMIIREG:
-		if (!priv->phydev)
-			return -EINVAL;
+	if (!priv->phydev)
+		return -EINVAL;
 
-		spin_lock(&priv->lock);
-		ret = phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
-		spin_unlock(&priv->lock);
-	default:
-		break;
-	}
+	spin_lock(&priv->lock);
+	ret = phy_mii_ioctl(priv->phydev, rq, cmd);
+	spin_unlock(&priv->lock);
+
 	return ret;
 }
 
@@ -1564,15 +1561,15 @@
 	else
 		device = dwmac100_setup(ioaddr);
 
+	if (!device)
+		return -ENOMEM;
+
 	if (priv->enh_desc) {
 		device->desc = &enh_desc_ops;
 		pr_info("\tEnhanced descriptor structure\n");
 	} else
 		device->desc = &ndesc_ops;
 
-	if (!device)
-		return -ENOMEM;
-
 	priv->hw = device;
 
 	priv->wolenabled = priv->hw->pmt;	/* PMT supported */
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index 1513123..b6ae53b 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -142,7 +142,6 @@
 
 struct priv
 {
-	struct net_device_stats stats;
 	unsigned long base;
 	char *memtop;
 	long int lock;
@@ -788,10 +787,10 @@
 						skb_copy_to_linear_data(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen);
 						skb->protocol=eth_type_trans(skb,dev);
 						netif_rx(skb);
-						p->stats.rx_packets++;
+						dev->stats.rx_packets++;
 					}
 					else
-						p->stats.rx_dropped++;
+						dev->stats.rx_dropped++;
 				}
 				else
 				{
@@ -812,13 +811,13 @@
 					totlen += rstat & RBD_MASK;
 					rbd->status = 0;
 					printk("%s: received oversized frame! length: %d\n",dev->name,totlen);
-					p->stats.rx_dropped++;
+					dev->stats.rx_dropped++;
 			 }
 		}
 		else /* frame !(ok), only with 'save-bad-frames' */
 		{
 			printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
-			p->stats.rx_errors++;
+			dev->stats.rx_errors++;
 		}
 		p->rfd_top->stat_high = 0;
 		p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */
@@ -885,7 +884,7 @@
 {
 	struct priv *p = netdev_priv(dev);
 
-	p->stats.rx_errors++;
+	dev->stats.rx_errors++;
 
 	WAIT_4_SCB_CMD();		/* wait for the last cmd, WAIT_4_FULLSTAT?? */
 	p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
@@ -918,29 +917,29 @@
 
 	if(status & STAT_OK)
 	{
-		p->stats.tx_packets++;
-		p->stats.collisions += (status & TCMD_MAXCOLLMASK);
+		dev->stats.tx_packets++;
+		dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
 	}
 	else
 	{
-		p->stats.tx_errors++;
+		dev->stats.tx_errors++;
 		if(status & TCMD_LATECOLL) {
 			printk("%s: late collision detected.\n",dev->name);
-			p->stats.collisions++;
+			dev->stats.collisions++;
 		}
 		else if(status & TCMD_NOCARRIER) {
-			p->stats.tx_carrier_errors++;
+			dev->stats.tx_carrier_errors++;
 			printk("%s: no carrier detected.\n",dev->name);
 		}
 		else if(status & TCMD_LOSTCTS)
 			printk("%s: loss of CTS detected.\n",dev->name);
 		else if(status & TCMD_UNDERRUN) {
-			p->stats.tx_fifo_errors++;
+			dev->stats.tx_fifo_errors++;
 			printk("%s: DMA underrun detected.\n",dev->name);
 		}
 		else if(status & TCMD_MAXCOLL) {
 			printk("%s: Max. collisions exceeded.\n",dev->name);
-			p->stats.collisions += 16;
+			dev->stats.collisions += 16;
 		}
 	}
 
@@ -1129,12 +1128,12 @@
 	ovrn = swab16(p->scb->ovrn_errs);
 	p->scb->ovrn_errs = 0;
 
-	p->stats.rx_crc_errors += crc;
-	p->stats.rx_fifo_errors += ovrn;
-	p->stats.rx_frame_errors += aln;
-	p->stats.rx_dropped += rsc;
+	dev->stats.rx_crc_errors += crc;
+	dev->stats.rx_fifo_errors += ovrn;
+	dev->stats.rx_frame_errors += aln;
+	dev->stats.rx_dropped += rsc;
 
-	return &p->stats;
+	return &dev->stats;
 }
 
 /********************************************************
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index be08b75..99e423a 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -2066,7 +2066,7 @@
 		return -EINVAL;
 	if (!lp->phy_dev)
 		return -ENODEV;
-	return phy_mii_ioctl(lp->phy_dev, if_mii(rq), cmd);
+	return phy_mii_ioctl(lp->phy_dev, rq, cmd);
 }
 
 static void tc35815_chip_reset(struct net_device *dev)
diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h
index cff98d0..67e3b71 100644
--- a/drivers/net/tehuti.h
+++ b/drivers/net/tehuti.h
@@ -334,7 +334,7 @@
 	u32 va_lo;
 	u32 va_hi;
 	struct pbl pbl[0];	/* Fragments */
-} __attribute__ ((packed));
+} __packed;
 
 /* Register region size */
 #define BDX_REGS_SIZE	  0x1000
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 573054a..bc3af78 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -18,6 +18,7 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/stringify.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/compiler.h>
@@ -67,8 +68,11 @@
 #include "tg3.h"
 
 #define DRV_MODULE_NAME		"tg3"
-#define DRV_MODULE_VERSION	"3.110"
-#define DRV_MODULE_RELDATE	"April 9, 2010"
+#define TG3_MAJ_NUM			3
+#define TG3_MIN_NUM			113
+#define DRV_MODULE_VERSION	\
+	__stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
+#define DRV_MODULE_RELDATE	"August 2, 2010"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -145,8 +149,6 @@
 #define TG3_RX_JMB_BUFF_RING_SIZE \
 	(sizeof(struct ring_info) * TG3_RX_JUMBO_RING_SIZE)
 
-#define TG3_RSS_MIN_NUM_MSIX_VECS	2
-
 /* Due to a hardware bug, the 5701 can only DMA to memory addresses
  * that are at least dword aligned when used in PCIX mode.  The driver
  * works around this bug by double copying the packet.  This workaround
@@ -219,12 +221,9 @@
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S_2)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F)},
-	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5720)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5722)},
-	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751)},
-	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750M)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752)},
@@ -272,6 +271,7 @@
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57765)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5719)},
 	{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)},
@@ -585,18 +585,23 @@
 static void tg3_ape_lock_init(struct tg3 *tp)
 {
 	int i;
+	u32 regbase;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+		regbase = TG3_APE_LOCK_GRANT;
+	else
+		regbase = TG3_APE_PER_LOCK_GRANT;
 
 	/* Make sure the driver hasn't any stale locks. */
 	for (i = 0; i < 8; i++)
-		tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + 4 * i,
-				APE_LOCK_GRANT_DRIVER);
+		tg3_ape_write32(tp, regbase + 4 * i, APE_LOCK_GRANT_DRIVER);
 }
 
 static int tg3_ape_lock(struct tg3 *tp, int locknum)
 {
 	int i, off;
 	int ret = 0;
-	u32 status;
+	u32 status, req, gnt;
 
 	if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
 		return 0;
@@ -609,13 +614,21 @@
 		return -EINVAL;
 	}
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+		req = TG3_APE_LOCK_REQ;
+		gnt = TG3_APE_LOCK_GRANT;
+	} else {
+		req = TG3_APE_PER_LOCK_REQ;
+		gnt = TG3_APE_PER_LOCK_GRANT;
+	}
+
 	off = 4 * locknum;
 
-	tg3_ape_write32(tp, TG3_APE_LOCK_REQ + off, APE_LOCK_REQ_DRIVER);
+	tg3_ape_write32(tp, req + off, APE_LOCK_REQ_DRIVER);
 
 	/* Wait for up to 1 millisecond to acquire lock. */
 	for (i = 0; i < 100; i++) {
-		status = tg3_ape_read32(tp, TG3_APE_LOCK_GRANT + off);
+		status = tg3_ape_read32(tp, gnt + off);
 		if (status == APE_LOCK_GRANT_DRIVER)
 			break;
 		udelay(10);
@@ -623,7 +636,7 @@
 
 	if (status != APE_LOCK_GRANT_DRIVER) {
 		/* Revoke the lock request. */
-		tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off,
+		tg3_ape_write32(tp, gnt + off,
 				APE_LOCK_GRANT_DRIVER);
 
 		ret = -EBUSY;
@@ -634,7 +647,7 @@
 
 static void tg3_ape_unlock(struct tg3 *tp, int locknum)
 {
-	int off;
+	u32 gnt;
 
 	if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
 		return;
@@ -647,8 +660,12 @@
 		return;
 	}
 
-	off = 4 * locknum;
-	tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off, APE_LOCK_GRANT_DRIVER);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+		gnt = TG3_APE_LOCK_GRANT;
+	else
+		gnt = TG3_APE_PER_LOCK_GRANT;
+
+	tg3_ape_write32(tp, gnt + 4 * locknum, APE_LOCK_GRANT_DRIVER);
 }
 
 static void tg3_disable_ints(struct tg3 *tp)
@@ -862,7 +879,7 @@
 	unsigned int loops;
 	int ret;
 
-	if ((tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) &&
+	if ((tp->phy_flags & TG3_PHYFLG_IS_FET) &&
 	    (reg == MII_TG3_CTRL || reg == MII_TG3_AUX_CTRL))
 		return 0;
 
@@ -1069,14 +1086,11 @@
 	u32 reg;
 	struct phy_device *phydev;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
-		u32 funcnum, is_serdes;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+		u32 is_serdes;
 
-		funcnum = tr32(TG3_CPMU_STATUS) & TG3_CPMU_STATUS_PCIE_FUNC;
-		if (funcnum)
-			tp->phy_addr = 2;
-		else
-			tp->phy_addr = 1;
+		tp->phy_addr = PCI_FUNC(tp->pdev->devfn) + 1;
 
 		if (tp->pci_chip_rev_id != CHIPREV_ID_5717_A0)
 			is_serdes = tr32(SG_DIG_STATUS) & SG_DIG_IS_SERDES;
@@ -1161,7 +1175,7 @@
 	case PHY_ID_BCMAC131:
 		phydev->interface = PHY_INTERFACE_MODE_MII;
 		phydev->dev_flags |= PHY_BRCM_AUTO_PWRDWN_ENABLE;
-		tp->tg3_flags3 |= TG3_FLG3_PHY_IS_FET;
+		tp->phy_flags |= TG3_PHYFLG_IS_FET;
 		break;
 	}
 
@@ -1254,7 +1268,7 @@
 	tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val);
 
 	val = 0;
-	if (!(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) {
+	if (!(tp->phy_flags & TG3_PHYFLG_MII_SERDES)) {
 		if (!tg3_readphy(tp, MII_CTRL1000, &reg))
 			val = reg << 16;
 		if (!tg3_readphy(tp, MII_STAT1000, &reg))
@@ -1362,7 +1376,7 @@
 
 	if (autoneg == AUTONEG_ENABLE &&
 	    (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
-		if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
+		if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
 			flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv);
 		else
 			flowctrl = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
@@ -1476,7 +1490,7 @@
 {
 	struct phy_device *phydev;
 
-	if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)
+	if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED)
 		return 0;
 
 	/* Bring the PHY back to a known state. */
@@ -1496,7 +1510,7 @@
 	switch (phydev->interface) {
 	case PHY_INTERFACE_MODE_GMII:
 	case PHY_INTERFACE_MODE_RGMII:
-		if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) {
+		if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
 			phydev->supported &= (PHY_GBIT_FEATURES |
 					      SUPPORTED_Pause |
 					      SUPPORTED_Asym_Pause);
@@ -1513,7 +1527,7 @@
 		return -EINVAL;
 	}
 
-	tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED;
+	tp->phy_flags |= TG3_PHYFLG_IS_CONNECTED;
 
 	phydev->advertising = phydev->supported;
 
@@ -1524,13 +1538,13 @@
 {
 	struct phy_device *phydev;
 
-	if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+	if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
 		return;
 
 	phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
 
-	if (tp->link_config.phy_is_low_power) {
-		tp->link_config.phy_is_low_power = 0;
+	if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
+		tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER;
 		phydev->speed = tp->link_config.orig_speed;
 		phydev->duplex = tp->link_config.orig_duplex;
 		phydev->autoneg = tp->link_config.orig_autoneg;
@@ -1544,7 +1558,7 @@
 
 static void tg3_phy_stop(struct tg3 *tp)
 {
-	if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+	if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
 		return;
 
 	phy_stop(tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]);
@@ -1552,16 +1566,21 @@
 
 static void tg3_phy_fini(struct tg3 *tp)
 {
-	if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
+	if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) {
 		phy_disconnect(tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]);
-		tp->tg3_flags3 &= ~TG3_FLG3_PHY_CONNECTED;
+		tp->phy_flags &= ~TG3_PHYFLG_IS_CONNECTED;
 	}
 }
 
-static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val)
+static int tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val)
 {
-	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg);
-	tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);
+	int err;
+
+	err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg);
+	if (!err)
+		err = tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);
+
+	return err;
 }
 
 static void tg3_phy_fet_toggle_apd(struct tg3 *tp, bool enable)
@@ -1589,11 +1608,12 @@
 	u32 reg;
 
 	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
-		(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
-	     (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
+	    ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+	      GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) &&
+	     (tp->phy_flags & TG3_PHYFLG_MII_SERDES)))
 		return;
 
-	if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
+	if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
 		tg3_phy_fet_toggle_apd(tp, enable);
 		return;
 	}
@@ -1624,10 +1644,10 @@
 	u32 phy;
 
 	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
-	    (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
+	    (tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
 		return;
 
-	if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
+	if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
 		u32 ephy;
 
 		if (!tg3_readphy(tp, MII_TG3_FET_TEST, &ephy)) {
@@ -1663,7 +1683,7 @@
 {
 	u32 val;
 
-	if (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED)
+	if (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED)
 		return;
 
 	if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007) &&
@@ -1722,7 +1742,7 @@
 	while (limit--) {
 		u32 tmp32;
 
-		if (!tg3_readphy(tp, 0x16, &tmp32)) {
+		if (!tg3_readphy(tp, MII_TG3_DSP_CONTROL, &tmp32)) {
 			if ((tmp32 & 0x1000) == 0)
 				break;
 		}
@@ -1748,13 +1768,13 @@
 
 		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
 			     (chan * 0x2000) | 0x0200);
-		tg3_writephy(tp, 0x16, 0x0002);
+		tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0002);
 
 		for (i = 0; i < 6; i++)
 			tg3_writephy(tp, MII_TG3_DSP_RW_PORT,
 				     test_pat[chan][i]);
 
-		tg3_writephy(tp, 0x16, 0x0202);
+		tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0202);
 		if (tg3_wait_macro_done(tp)) {
 			*resetp = 1;
 			return -EBUSY;
@@ -1762,13 +1782,13 @@
 
 		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
 			     (chan * 0x2000) | 0x0200);
-		tg3_writephy(tp, 0x16, 0x0082);
+		tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0082);
 		if (tg3_wait_macro_done(tp)) {
 			*resetp = 1;
 			return -EBUSY;
 		}
 
-		tg3_writephy(tp, 0x16, 0x0802);
+		tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0802);
 		if (tg3_wait_macro_done(tp)) {
 			*resetp = 1;
 			return -EBUSY;
@@ -1808,10 +1828,10 @@
 
 		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
 			     (chan * 0x2000) | 0x0200);
-		tg3_writephy(tp, 0x16, 0x0002);
+		tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0002);
 		for (i = 0; i < 6; i++)
 			tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x000);
-		tg3_writephy(tp, 0x16, 0x0202);
+		tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0202);
 		if (tg3_wait_macro_done(tp))
 			return -EBUSY;
 	}
@@ -1857,8 +1877,7 @@
 		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
 
 		/* Block the PHY control access.  */
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
-		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0800);
+		tg3_phydsp_write(tp, 0x8005, 0x0800);
 
 		err = tg3_phy_write_and_check_testpat(tp, &do_phy_reset);
 		if (!err)
@@ -1869,11 +1888,10 @@
 	if (err)
 		return err;
 
-	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
-	tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0000);
+	tg3_phydsp_write(tp, 0x8005, 0x0000);
 
 	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200);
-	tg3_writephy(tp, 0x16, 0x0000);
+	tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0000);
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
@@ -1964,43 +1982,39 @@
 		}
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
-	    (tp->tg3_flags2 & TG3_FLG2_MII_SERDES))
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) &&
+	    (tp->phy_flags & TG3_PHYFLG_MII_SERDES))
 		return 0;
 
 	tg3_phy_apply_otp(tp);
 
-	if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD)
+	if (tp->phy_flags & TG3_PHYFLG_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) {
+	if (tp->phy_flags & TG3_PHYFLG_ADC_BUG) {
 		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
-		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
-		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0323);
+		tg3_phydsp_write(tp, 0x201f, 0x2aaa);
+		tg3_phydsp_write(tp, 0x000a, 0x0323);
 		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
 	}
-	if (tp->tg3_flags2 & TG3_FLG2_PHY_5704_A0_BUG) {
-		tg3_writephy(tp, 0x1c, 0x8d68);
-		tg3_writephy(tp, 0x1c, 0x8d68);
+	if (tp->phy_flags & TG3_PHYFLG_5704_A0_BUG) {
+		tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68);
+		tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68);
 	}
-	if (tp->tg3_flags2 & TG3_FLG2_PHY_BER_BUG) {
+	if (tp->phy_flags & TG3_PHYFLG_BER_BUG) {
 		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
-		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x310b);
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
-		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x9506);
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x401f);
-		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x14e2);
+		tg3_phydsp_write(tp, 0x000a, 0x310b);
+		tg3_phydsp_write(tp, 0x201f, 0x9506);
+		tg3_phydsp_write(tp, 0x401f, 0x14e2);
 		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
-	} else if (tp->tg3_flags2 & TG3_FLG2_PHY_JITTER_BUG) {
+	} else if (tp->phy_flags & TG3_PHYFLG_JITTER_BUG) {
 		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
 		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
-		if (tp->tg3_flags2 & TG3_FLG2_PHY_ADJUST_TRIM) {
+		if (tp->phy_flags & TG3_PHYFLG_ADJUST_TRIM) {
 			tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b);
 			tg3_writephy(tp, MII_TG3_TEST1,
 				     MII_TG3_TEST1_TRIM_EN | 0x4);
@@ -2049,6 +2063,7 @@
 
 	/* The GPIOs do something completely different on 57765. */
 	if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
 		return;
 
@@ -2184,7 +2199,7 @@
 {
 	u32 val;
 
-	if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
 			u32 sg_dig_ctrl = tr32(SG_DIG_CTRL);
 			u32 serdes_cfg = tr32(MAC_SERDES_CFG);
@@ -2203,7 +2218,7 @@
 		tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ);
 		udelay(40);
 		return;
-	} else if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
+	} else if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
 		u32 phytest;
 		if (!tg3_readphy(tp, MII_TG3_FET_TEST, &phytest)) {
 			u32 phy;
@@ -2240,7 +2255,7 @@
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
 	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 &&
-	     (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
+	     (tp->phy_flags & TG3_PHYFLG_MII_SERDES)))
 		return;
 
 	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX ||
@@ -2543,14 +2558,14 @@
 
 	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) {
+		if ((tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) &&
+		    !(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
 			struct phy_device *phydev;
 			u32 phyid, advertising;
 
 			phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
 
-			tp->link_config.phy_is_low_power = 1;
+			tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER;
 
 			tp->link_config.orig_speed = phydev->speed;
 			tp->link_config.orig_duplex = phydev->duplex;
@@ -2589,14 +2604,14 @@
 	} else {
 		do_low_power = true;
 
-		if (tp->link_config.phy_is_low_power == 0) {
-			tp->link_config.phy_is_low_power = 1;
+		if (!(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
+			tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER;
 			tp->link_config.orig_speed = tp->link_config.speed;
 			tp->link_config.orig_duplex = tp->link_config.duplex;
 			tp->link_config.orig_autoneg = tp->link_config.autoneg;
 		}
 
-		if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) {
+		if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) {
 			tp->link_config.speed = SPEED_10;
 			tp->link_config.duplex = DUPLEX_HALF;
 			tp->link_config.autoneg = AUTONEG_ENABLE;
@@ -2629,13 +2644,13 @@
 	if (device_should_wake) {
 		u32 mac_mode;
 
-		if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+		if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
 			if (do_low_power) {
 				tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
 				udelay(40);
 			}
 
-			if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+			if (tp->phy_flags & TG3_PHYFLG_MII_SERDES)
 				mac_mode = MAC_MODE_PORT_MODE_GMII;
 			else
 				mac_mode = MAC_MODE_PORT_MODE_MII;
@@ -2803,7 +2818,7 @@
 		break;
 
 	default:
-		if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
+		if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
 			*speed = (val & MII_TG3_AUX_STAT_100) ? SPEED_100 :
 				 SPEED_10;
 			*duplex = (val & MII_TG3_AUX_STAT_FULL) ? DUPLEX_FULL :
@@ -2821,7 +2836,7 @@
 	u32 new_adv;
 	int i;
 
-	if (tp->link_config.phy_is_low_power) {
+	if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
 		/* Entering low power mode.  Disable gigabit and
 		 * 100baseT advertisements.
 		 */
@@ -2834,7 +2849,7 @@
 
 		tg3_writephy(tp, MII_ADVERTISE, new_adv);
 	} else if (tp->link_config.speed == SPEED_INVALID) {
-		if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+		if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
 			tp->link_config.advertising &=
 				~(ADVERTISED_1000baseT_Half |
 				  ADVERTISED_1000baseT_Full);
@@ -2860,7 +2875,7 @@
 				new_adv |= MII_TG3_CTRL_ADV_1000_HALF;
 			if (tp->link_config.advertising & ADVERTISED_1000baseT_Full)
 				new_adv |= MII_TG3_CTRL_ADV_1000_FULL;
-			if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
+			if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY) &&
 			    (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
 			     tp->pci_chip_rev_id == CHIPREV_ID_5701_B0))
 				new_adv |= (MII_TG3_CTRL_AS_MASTER |
@@ -2962,20 +2977,11 @@
 	/* Set Extended packet length bit */
 	err  = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20);
 
-	err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x0012);
-	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x1804);
-
-	err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x0013);
-	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x1204);
-
-	err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8006);
-	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0132);
-
-	err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8006);
-	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0232);
-
-	err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
-	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0a20);
+	err |= tg3_phydsp_write(tp, 0x0012, 0x1804);
+	err |= tg3_phydsp_write(tp, 0x0013, 0x1204);
+	err |= tg3_phydsp_write(tp, 0x8006, 0x0132);
+	err |= tg3_phydsp_write(tp, 0x8006, 0x0232);
+	err |= tg3_phydsp_write(tp, 0x201f, 0x0a20);
 
 	udelay(40);
 
@@ -3000,7 +3006,7 @@
 
 	if ((adv_reg & all_mask) != all_mask)
 		return 0;
-	if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) {
+	if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
 		u32 tg3_ctrl;
 
 		all_mask = 0;
@@ -3128,18 +3134,18 @@
 		   tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
 		/* 5701 {A0,B0} CRC bug workaround */
 		tg3_writephy(tp, 0x15, 0x0a75);
-		tg3_writephy(tp, 0x1c, 0x8c68);
-		tg3_writephy(tp, 0x1c, 0x8d68);
-		tg3_writephy(tp, 0x1c, 0x8c68);
+		tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8c68);
+		tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68);
+		tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8c68);
 	}
 
 	/* Clear pending interrupts... */
 	tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
 	tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
 
-	if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT)
+	if (tp->phy_flags & TG3_PHYFLG_USE_MI_INTERRUPT)
 		tg3_writephy(tp, MII_TG3_IMASK, ~MII_TG3_INT_LINKCHG);
-	else if (!(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET))
+	else if (!(tp->phy_flags & TG3_PHYFLG_IS_FET))
 		tg3_writephy(tp, MII_TG3_IMASK, ~0);
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
@@ -3155,7 +3161,7 @@
 	current_speed = SPEED_INVALID;
 	current_duplex = DUPLEX_INVALID;
 
-	if (tp->tg3_flags2 & TG3_FLG2_CAPACITIVE_COUPLING) {
+	if (tp->phy_flags & TG3_PHYFLG_CAPACITIVE_COUPLING) {
 		u32 val;
 
 		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4007);
@@ -3231,7 +3237,7 @@
 	}
 
 relink:
-	if (current_link_up == 0 || tp->link_config.phy_is_low_power) {
+	if (current_link_up == 0 || (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
 		u32 tmp;
 
 		tg3_phy_copper_begin(tp);
@@ -3249,7 +3255,7 @@
 			tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
 		else
 			tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
-	} else if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET)
+	} else if (tp->phy_flags & TG3_PHYFLG_IS_FET)
 		tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
 	else
 		tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
@@ -3800,7 +3806,7 @@
 		expected_sg_dig_ctrl |= SG_DIG_ASYM_PAUSE;
 
 	if (sg_dig_ctrl != expected_sg_dig_ctrl) {
-		if ((tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
+		if ((tp->phy_flags & TG3_PHYFLG_PARALLEL_DETECT) &&
 		    tp->serdes_counter &&
 		    ((mac_status & (MAC_STATUS_PCS_SYNCED |
 				    MAC_STATUS_RCVD_CFG)) ==
@@ -3817,7 +3823,7 @@
 		tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
 
 		tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
-		tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+		tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
 	} else if (mac_status & (MAC_STATUS_PCS_SYNCED |
 				 MAC_STATUS_SIGNAL_DET)) {
 		sg_dig_status = tr32(SG_DIG_STATUS);
@@ -3840,7 +3846,7 @@
 			tg3_setup_flow_control(tp, local_adv, remote_adv);
 			current_link_up = 1;
 			tp->serdes_counter = 0;
-			tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+			tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
 		} else if (!(sg_dig_status & SG_DIG_AUTONEG_COMPLETE)) {
 			if (tp->serdes_counter)
 				tp->serdes_counter--;
@@ -3867,8 +3873,8 @@
 				    !(mac_status & MAC_STATUS_RCVD_CFG)) {
 					tg3_setup_flow_control(tp, 0, 0);
 					current_link_up = 1;
-					tp->tg3_flags2 |=
-						TG3_FLG2_PARALLEL_DETECT;
+					tp->phy_flags |=
+						TG3_PHYFLG_PARALLEL_DETECT;
 					tp->serdes_counter =
 						SERDES_PARALLEL_DET_TIMEOUT;
 				} else
@@ -3877,7 +3883,7 @@
 		}
 	} else {
 		tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
-		tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+		tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
 	}
 
 out:
@@ -4094,7 +4100,7 @@
 	err |= tg3_readphy(tp, MII_BMCR, &bmcr);
 
 	if ((tp->link_config.autoneg == AUTONEG_ENABLE) && !force_reset &&
-	    (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) {
+	    (tp->phy_flags & TG3_PHYFLG_PARALLEL_DETECT)) {
 		/* do nothing, just check for link up at the end */
 	} else if (tp->link_config.autoneg == AUTONEG_ENABLE) {
 		u32 adv, new_adv;
@@ -4119,7 +4125,7 @@
 
 			tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
 			tp->serdes_counter = SERDES_AN_TIMEOUT_5714S;
-			tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+			tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
 
 			return err;
 		}
@@ -4164,7 +4170,7 @@
 				else
 					bmsr &= ~BMSR_LSTATUS;
 			}
-			tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+			tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
 		}
 	}
 
@@ -4191,6 +4197,8 @@
 					current_duplex = DUPLEX_FULL;
 				else
 					current_duplex = DUPLEX_HALF;
+			} else if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+				/* Link is up via parallel detect */
 			} else {
 				current_link_up = 0;
 			}
@@ -4217,7 +4225,7 @@
 			netif_carrier_on(tp->dev);
 		else {
 			netif_carrier_off(tp->dev);
-			tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+			tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
 		}
 		tg3_link_report(tp);
 	}
@@ -4241,13 +4249,14 @@
 			u32 phy1, phy2;
 
 			/* Select shadow register 0x1f */
-			tg3_writephy(tp, 0x1c, 0x7c00);
-			tg3_readphy(tp, 0x1c, &phy1);
+			tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x7c00);
+			tg3_readphy(tp, MII_TG3_MISC_SHDW, &phy1);
 
 			/* Select expansion interrupt status register */
-			tg3_writephy(tp, 0x17, 0x0f01);
-			tg3_readphy(tp, 0x15, &phy2);
-			tg3_readphy(tp, 0x15, &phy2);
+			tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
+					 MII_TG3_DSP_EXP1_INT_STAT);
+			tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &phy2);
+			tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &phy2);
 
 			if ((phy1 & 0x10) && !(phy2 & 0x20)) {
 				/* We have signal detect and not receiving
@@ -4258,17 +4267,18 @@
 				bmcr &= ~BMCR_ANENABLE;
 				bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
 				tg3_writephy(tp, MII_BMCR, bmcr);
-				tp->tg3_flags2 |= TG3_FLG2_PARALLEL_DETECT;
+				tp->phy_flags |= TG3_PHYFLG_PARALLEL_DETECT;
 			}
 		}
 	} else if (netif_carrier_ok(tp->dev) &&
 		   (tp->link_config.autoneg == AUTONEG_ENABLE) &&
-		   (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) {
+		   (tp->phy_flags & TG3_PHYFLG_PARALLEL_DETECT)) {
 		u32 phy2;
 
 		/* Select expansion interrupt status register */
-		tg3_writephy(tp, 0x17, 0x0f01);
-		tg3_readphy(tp, 0x15, &phy2);
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
+				 MII_TG3_DSP_EXP1_INT_STAT);
+		tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &phy2);
 		if (phy2 & 0x20) {
 			u32 bmcr;
 
@@ -4276,7 +4286,7 @@
 			tg3_readphy(tp, MII_BMCR, &bmcr);
 			tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANENABLE);
 
-			tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+			tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
 
 		}
 	}
@@ -4286,9 +4296,9 @@
 {
 	int err;
 
-	if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
 		err = tg3_setup_fiber_phy(tp, force_reset);
-	else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+	else if (tp->phy_flags & TG3_PHYFLG_MII_SERDES)
 		err = tg3_setup_fiber_mii_phy(tp, force_reset);
 	else
 		err = tg3_setup_copper_phy(tp, force_reset);
@@ -4367,7 +4377,8 @@
 
 static inline u32 tg3_tx_avail(struct tg3_napi *tnapi)
 {
-	smp_mb();
+	/* Tell compiler to fetch tx indices from memory. */
+	barrier();
 	return tnapi->tx_pending -
 	       ((tnapi->tx_prod - tnapi->tx_cons) & (TG3_TX_RING_SIZE - 1));
 }
@@ -5552,8 +5563,8 @@
 
 	entry = tnapi->tx_prod;
 	base_flags = 0;
-	mss = 0;
-	if ((mss = skb_shinfo(skb)->gso_size) != 0) {
+	mss = skb_shinfo(skb)->gso_size;
+	if (mss) {
 		int tcp_opt_len, ip_tcp_len;
 		u32 hdrlen;
 
@@ -5651,6 +5662,13 @@
 	tnapi->tx_prod = entry;
 	if (unlikely(tg3_tx_avail(tnapi) <= (MAX_SKB_FRAGS + 1))) {
 		netif_tx_stop_queue(txq);
+
+		/* netif_tx_stop_queue() must be done before checking
+		 * checking tx index in tg3_tx_avail() below, because in
+		 * tg3_tx(), we update tx index before checking for
+		 * netif_tx_queue_stopped().
+		 */
+		smp_mb();
 		if (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi))
 			netif_tx_wake_queue(txq);
 	}
@@ -5696,6 +5714,13 @@
 	/* Estimate the number of fragments in the worst case */
 	if (unlikely(tg3_tx_avail(&tp->napi[0]) <= frag_cnt_est)) {
 		netif_stop_queue(tp->dev);
+
+		/* netif_tx_stop_queue() must be done before checking
+		 * checking tx index in tg3_tx_avail() below, because in
+		 * tg3_tx(), we update tx index before checking for
+		 * netif_tx_queue_stopped().
+		 */
+		smp_mb();
 		if (tg3_tx_avail(&tp->napi[0]) <= frag_cnt_est)
 			return NETDEV_TX_BUSY;
 
@@ -5759,9 +5784,10 @@
 	if (skb->ip_summed == CHECKSUM_PARTIAL)
 		base_flags |= TXD_FLAG_TCPUDP_CSUM;
 
-	if ((mss = skb_shinfo(skb)->gso_size) != 0) {
+	mss = skb_shinfo(skb)->gso_size;
+	if (mss) {
 		struct iphdr *iph;
-		u32 tcp_opt_len, ip_tcp_len, hdr_len;
+		u32 tcp_opt_len, hdr_len;
 
 		if (skb_header_cloned(skb) &&
 		    pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
@@ -5769,10 +5795,21 @@
 			goto out_unlock;
 		}
 
+		iph = ip_hdr(skb);
 		tcp_opt_len = tcp_optlen(skb);
-		ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
 
-		hdr_len = ip_tcp_len + tcp_opt_len;
+		if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
+			hdr_len = skb_headlen(skb) - ETH_HLEN;
+		} else {
+			u32 ip_tcp_len;
+
+			ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
+			hdr_len = ip_tcp_len + tcp_opt_len;
+
+			iph->check = 0;
+			iph->tot_len = htons(mss + hdr_len);
+		}
+
 		if (unlikely((ETH_HLEN + hdr_len) > 80) &&
 			     (tp->tg3_flags2 & TG3_FLG2_TSO_BUG))
 			return tg3_tso_bug(tp, skb);
@@ -5780,9 +5817,6 @@
 		base_flags |= (TXD_FLAG_CPU_PRE_DMA |
 			       TXD_FLAG_CPU_POST_DMA);
 
-		iph = ip_hdr(skb);
-		iph->check = 0;
-		iph->tot_len = htons(mss + hdr_len);
 		if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
 			tcp_hdr(skb)->check = 0;
 			base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
@@ -5922,6 +5956,13 @@
 	tnapi->tx_prod = entry;
 	if (unlikely(tg3_tx_avail(tnapi) <= (MAX_SKB_FRAGS + 1))) {
 		netif_tx_stop_queue(txq);
+
+		/* netif_tx_stop_queue() must be done before checking
+		 * checking tx index in tg3_tx_avail() below, because in
+		 * tg3_tx(), we update tx index before checking for
+		 * netif_tx_queue_stopped().
+		 */
+		smp_mb();
 		if (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi))
 			netif_tx_wake_queue(txq);
 	}
@@ -6212,6 +6253,8 @@
 	for (j = 0; j < tp->irq_cnt; j++) {
 		struct tg3_napi *tnapi = &tp->napi[j];
 
+		tg3_rx_prodring_free(tp, &tp->prodring[j]);
+
 		if (!tnapi->tx_buffers)
 			continue;
 
@@ -6247,8 +6290,6 @@
 
 			dev_kfree_skb_any(skb);
 		}
-
-		tg3_rx_prodring_free(tp, &tp->prodring[j]);
 	}
 }
 
@@ -6603,7 +6644,7 @@
 		apedata = tg3_ape_read32(tp, TG3_APE_HOST_INIT_COUNT);
 		tg3_ape_write32(tp, TG3_APE_HOST_INIT_COUNT, ++apedata);
 		tg3_ape_write32(tp, TG3_APE_HOST_DRIVER_ID,
-				APE_HOST_DRIVER_ID_MAGIC);
+			APE_HOST_DRIVER_ID_MAGIC(TG3_MAJ_NUM, TG3_MIN_NUM));
 		tg3_ape_write32(tp, TG3_APE_HOST_BEHAVIOR,
 				APE_HOST_BEHAV_NO_PHYLOCK);
 
@@ -6782,7 +6823,8 @@
 	/* Allow reads and writes to the APE register and memory space. */
 	if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
 		val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
-		       PCISTATE_ALLOW_APE_SHMEM_WR;
+		       PCISTATE_ALLOW_APE_SHMEM_WR |
+		       PCISTATE_ALLOW_APE_PSPACE_WR;
 	pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
 
 	pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd);
@@ -6897,9 +6939,13 @@
 	val = GRC_MISC_CFG_CORECLK_RESET;
 
 	if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
-		if (tr32(0x7e2c) == 0x60) {
-			tw32(0x7e2c, 0x20);
-		}
+		/* Force PCIe 1.0a mode */
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+		    !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS) &&
+		    tr32(TG3_PCIE_PHY_TSTCTL) ==
+		    (TG3_PCIE_PHY_TSTCTL_PCIE10 | TG3_PCIE_PHY_TSTCTL_PSCRAM))
+			tw32(TG3_PCIE_PHY_TSTCTL, TG3_PCIE_PHY_TSTCTL_PSCRAM);
+
 		if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
 			tw32(GRC_MISC_CFG, (1 << 29));
 			val |= (1 << 29);
@@ -6912,8 +6958,11 @@
 		     tr32(GRC_VCPU_EXT_CTRL) & ~GRC_VCPU_EXT_CTRL_HALT_CPU);
 	}
 
-	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+	/* Manage gphy power for all CPMU absent PCIe devices. */
+	if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
+	    !(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT))
 		val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
+
 	tw32(GRC_MISC_CFG, val);
 
 	/* restore 5701 hardware bug workaround write method */
@@ -6970,8 +7019,7 @@
 		 * Older PCIe devices only support the 128 byte
 		 * MPS setting.  Enforce the restriction.
 		 */
-		if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) ||
-		    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784))
+		if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT))
 			val16 &= ~PCI_EXP_DEVCTL_PAYLOAD;
 		pci_write_config_word(tp->pdev,
 				      tp->pcie_cap + PCI_EXP_DEVCTL,
@@ -7018,10 +7066,10 @@
 		tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
 	}
 
-	if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
 		tp->mac_mode = MAC_MODE_PORT_MODE_TBI;
 		tw32_f(MAC_MODE, tp->mac_mode);
-	} else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
+	} else if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
 		tp->mac_mode = MAC_MODE_PORT_MODE_GMII;
 		tw32_f(MAC_MODE, tp->mac_mode);
 	} else if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
@@ -7041,35 +7089,10 @@
 
 	tg3_mdio_start(tp);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
-		u8 phy_addr;
-
-		phy_addr = tp->phy_addr;
-		tp->phy_addr = TG3_PHY_PCIE_ADDR;
-
-		tg3_writephy(tp, TG3_PCIEPHY_BLOCK_ADDR,
-			     TG3_PCIEPHY_TXB_BLK << TG3_PCIEPHY_BLOCK_SHIFT);
-		val = TG3_PCIEPHY_TX0CTRL1_TXOCM | TG3_PCIEPHY_TX0CTRL1_RDCTL |
-		      TG3_PCIEPHY_TX0CTRL1_TXCMV | TG3_PCIEPHY_TX0CTRL1_TKSEL |
-		      TG3_PCIEPHY_TX0CTRL1_NB_EN;
-		tg3_writephy(tp, TG3_PCIEPHY_TX0CTRL1, val);
-		udelay(10);
-
-		tg3_writephy(tp, TG3_PCIEPHY_BLOCK_ADDR,
-			     TG3_PCIEPHY_XGXS_BLK1 << TG3_PCIEPHY_BLOCK_SHIFT);
-		val = TG3_PCIEPHY_PWRMGMT4_LOWPWR_EN |
-		      TG3_PCIEPHY_PWRMGMT4_L1PLLPD_EN;
-		tg3_writephy(tp, TG3_PCIEPHY_PWRMGMT4, val);
-		udelay(10);
-
-		tp->phy_addr = phy_addr;
-	}
-
 	if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
 	    tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 &&
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765) {
+	    !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) {
 		val = tr32(0x7c00);
 
 		tw32(0x7c00, val | (1 << 25));
@@ -7427,7 +7450,7 @@
 		tw32(HOSTCC_TXCOAL_MAXF_INT, 0);
 	}
 
-	if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) {
+	if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) {
 		tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs);
 		tw32(HOSTCC_RXMAX_FRAMES, ec->rx_max_coalesced_frames);
 		tw32(HOSTCC_RXCOAL_MAXF_INT, ec->rx_max_coalesced_frames_irq);
@@ -7504,7 +7527,8 @@
 
 
 	/* Disable all receive return rings but the first. */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
 		limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17;
 	else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
 		limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16;
@@ -7720,7 +7744,8 @@
 		 */
 		val = tr32(TG3PCI_PCISTATE);
 		val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
-		       PCISTATE_ALLOW_APE_SHMEM_WR;
+		       PCISTATE_ALLOW_APE_SHMEM_WR |
+		       PCISTATE_ALLOW_APE_PSPACE_WR;
 		tw32(TG3PCI_PCISTATE, val);
 	}
 
@@ -7740,8 +7765,7 @@
 	if (err)
 		return err;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+	if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
 		val = tr32(TG3PCI_DMA_RW_CTRL) &
 		      ~DMA_RWCTRL_DIS_CACHE_ALIGNMENT;
 		if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0)
@@ -7869,7 +7893,8 @@
 	     ((u64) tpr->rx_std_mapping >> 32));
 	tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
 	     ((u64) tpr->rx_std_mapping & 0xffffffff));
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719)
 		tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR,
 		     NIC_SRAM_RX_BUFFER_DESC);
 
@@ -7894,7 +7919,8 @@
 			tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
 			     (RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT) |
 			     BDINFO_FLAGS_USE_EXT_RECV);
-			if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+			if (!(tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) ||
+			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
 				tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR,
 				     NIC_SRAM_RX_JUMBO_BUFFER_DESC);
 		} else {
@@ -7902,8 +7928,7 @@
 			     BDINFO_FLAGS_DISABLED);
 		}
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+		if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)
 			val = (RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT) |
 			      (TG3_RX_STD_DMA_SZ << 2);
 		else
@@ -7920,8 +7945,7 @@
 			  tp->rx_jumbo_pending : 0;
 	tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG, tpr->rx_jmb_prod_idx);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+	if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
 		tw32(STD_REPLENISH_LWM, 32);
 		tw32(JMB_REPLENISH_LWM, 16);
 	}
@@ -7956,7 +7980,8 @@
 		      RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
 		      RDMAC_MODE_LNGREAD_ENAB);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
 		rdmac_mode |= RDMAC_MODE_MULT_DMA_RD_DIS;
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
@@ -8048,8 +8073,8 @@
 	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
 		tw32(RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE);
 
-	if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
-		tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+	if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
+		tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
 		/* reset to prevent losing 1st rx packet intermittently */
 		tw32_f(MAC_RX_MODE, RX_MODE_RESET);
 		udelay(10);
@@ -8062,7 +8087,7 @@
 	tp->mac_mode |= MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
 		MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
 	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
-	    !(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+	    !(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)
 		tp->mac_mode |= MAC_MODE_LINK_POLARITY;
 	tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
@@ -8195,6 +8220,9 @@
 	}
 
 	tp->tx_mode = TX_MODE_ENABLE;
+	if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+		tp->tx_mode |= TX_MODE_MBUF_LOCKUP_FIX;
 	tw32_f(MAC_TX_MODE, tp->tx_mode);
 	udelay(100);
 
@@ -8244,16 +8272,16 @@
 	tw32(MAC_LED_CTRL, tp->led_ctrl);
 
 	tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
-	if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
 		tw32_f(MAC_RX_MODE, RX_MODE_RESET);
 		udelay(10);
 	}
 	tw32_f(MAC_RX_MODE, tp->rx_mode);
 	udelay(10);
 
-	if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
 		if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
-			!(tp->tg3_flags2 & TG3_FLG2_SERDES_PREEMPHASIS)) {
+			!(tp->phy_flags & TG3_PHYFLG_SERDES_PREEMPHASIS)) {
 			/* Set drive transmission level to 1.2V  */
 			/* only if the signal pre-emphasis bit is not set  */
 			val = tr32(MAC_SERDES_CFG);
@@ -8275,12 +8303,12 @@
 	tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, val);
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
-	    (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+	    (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
 		/* Use hardware link auto-negotiation */
 		tp->tg3_flags2 |= TG3_FLG2_HW_AUTONEG;
 	}
 
-	if ((tp->tg3_flags2 & TG3_FLG2_MII_SERDES) &&
+	if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) &&
 	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) {
 		u32 tmp;
 
@@ -8292,8 +8320,8 @@
 	}
 
 	if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
-		if (tp->link_config.phy_is_low_power) {
-			tp->link_config.phy_is_low_power = 0;
+		if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
+			tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER;
 			tp->link_config.speed = tp->link_config.orig_speed;
 			tp->link_config.duplex = tp->link_config.orig_duplex;
 			tp->link_config.autoneg = tp->link_config.orig_autoneg;
@@ -8303,15 +8331,15 @@
 		if (err)
 			return err;
 
-		if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
-		    !(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET)) {
+		if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
+		    !(tp->phy_flags & TG3_PHYFLG_IS_FET)) {
 			u32 tmp;
 
 			/* Clear CRC stats. */
 			if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) {
 				tg3_writephy(tp, MII_TG3_TEST1,
 					     tmp | MII_TG3_TEST1_CRC_EN);
-				tg3_readphy(tp, 0x14, &tmp);
+				tg3_readphy(tp, MII_TG3_RXR_COUNTERS, &tmp);
 			}
 		}
 	}
@@ -8479,7 +8507,7 @@
 			mac_stat = tr32(MAC_STATUS);
 
 			phy_event = 0;
-			if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) {
+			if (tp->phy_flags & TG3_PHYFLG_USE_MI_INTERRUPT) {
 				if (mac_stat & MAC_STATUS_MI_INTERRUPT)
 					phy_event = 1;
 			} else if (mac_stat & MAC_STATUS_LNKSTATE_CHANGED)
@@ -8495,7 +8523,7 @@
 			    (mac_stat & MAC_STATUS_LNKSTATE_CHANGED)) {
 				need_setup = 1;
 			}
-			if (! netif_carrier_ok(tp->dev) &&
+			if (!netif_carrier_ok(tp->dev) &&
 			    (mac_stat & (MAC_STATUS_PCS_SYNCED |
 					 MAC_STATUS_SIGNAL_DET))) {
 				need_setup = 1;
@@ -8511,8 +8539,10 @@
 				}
 				tg3_setup_phy(tp, 0);
 			}
-		} else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+		} else if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) &&
+			   (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
 			tg3_serdes_parallel_detect(tp);
+		}
 
 		tp->timer_counter = tp->timer_multiplier;
 	}
@@ -8605,8 +8635,7 @@
 	 * Turn off MSI one shot mode.  Otherwise this test has no
 	 * observable way to know whether the interrupt was delivered.
 	 */
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) &&
+	if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) &&
 	    (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) {
 		val = tr32(MSGINT_MODE) | MSGINT_MODE_ONE_SHOT_DISABLE;
 		tw32(MSGINT_MODE, val);
@@ -8649,8 +8678,7 @@
 
 	if (intr_ok) {
 		/* Reenable MSI one shot mode. */
-		if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-		     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) &&
+		if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) &&
 		    (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) {
 			val = tr32(MSGINT_MODE) & ~MSGINT_MODE_ONE_SHOT_DISABLE;
 			tw32(MSGINT_MODE, val);
@@ -8775,9 +8803,9 @@
 	}
 
 	rc = pci_enable_msix(tp->pdev, msix_ent, tp->irq_cnt);
-	if (rc != 0) {
-		if (rc < TG3_RSS_MIN_NUM_MSIX_VECS)
-			return false;
+	if (rc < 0) {
+		return false;
+	} else if (rc != 0) {
 		if (pci_enable_msix(tp->pdev, msix_ent, rc))
 			return false;
 		netdev_notice(tp->dev, "Requested %d MSI-X vectors, received %d\n",
@@ -8785,16 +8813,19 @@
 		tp->irq_cnt = rc;
 	}
 
-	tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS;
-
 	for (i = 0; i < tp->irq_max; i++)
 		tp->napi[i].irq_vec = msix_ent[i].vector;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
-		tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS;
-		tp->dev->real_num_tx_queues = tp->irq_cnt - 1;
-	} else
-		tp->dev->real_num_tx_queues = 1;
+	tp->dev->real_num_tx_queues = 1;
+	if (tp->irq_cnt > 1) {
+		tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS;
+
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+			tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS;
+			tp->dev->real_num_tx_queues = tp->irq_cnt - 1;
+		}
+	}
 
 	return true;
 }
@@ -8838,7 +8869,7 @@
 	else if (tp->tg3_flags2 & TG3_FLG2_USING_MSI)
 		pci_disable_msi(tp->pdev);
 	tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI_OR_MSIX;
-	tp->tg3_flags3 &= ~TG3_FLG3_ENABLE_RSS;
+	tp->tg3_flags3 &= ~(TG3_FLG3_ENABLE_RSS | TG3_FLG3_ENABLE_TSS);
 }
 
 static int tg3_open(struct net_device *dev)
@@ -8942,10 +8973,8 @@
 			goto err_out2;
 		}
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
-		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765 &&
-		    (tp->tg3_flags2 & TG3_FLG2_USING_MSI) &&
-		    (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)) {
+		if (!(tp->tg3_flags3 & TG3_FLG3_5717_PLUS) &&
+		    (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) {
 			u32 val = tr32(PCIE_TRANSACTION_CFG);
 
 			tw32(PCIE_TRANSACTION_CFG,
@@ -8982,7 +9011,8 @@
 	return err;
 }
 
-static struct net_device_stats *tg3_get_stats(struct net_device *);
+static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *,
+						 struct rtnl_link_stats64 *);
 static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *);
 
 static int tg3_close(struct net_device *dev)
@@ -9016,8 +9046,8 @@
 
 	tg3_ints_fini(tp);
 
-	memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev),
-	       sizeof(tp->net_stats_prev));
+	tg3_get_stats64(tp->dev, &tp->net_stats_prev);
+
 	memcpy(&tp->estats_prev, tg3_get_estats(tp),
 	       sizeof(tp->estats_prev));
 
@@ -9030,28 +9060,16 @@
 	return 0;
 }
 
-static inline unsigned long get_stat64(tg3_stat64_t *val)
-{
-	unsigned long ret;
-
-#if (BITS_PER_LONG == 32)
-	ret = val->low;
-#else
-	ret = ((u64)val->high << 32) | ((u64)val->low);
-#endif
-	return ret;
-}
-
-static inline u64 get_estat64(tg3_stat64_t *val)
+static inline u64 get_stat64(tg3_stat64_t *val)
 {
        return ((u64)val->high << 32) | ((u64)val->low);
 }
 
-static unsigned long calc_crc_errors(struct tg3 *tp)
+static u64 calc_crc_errors(struct tg3 *tp)
 {
 	struct tg3_hw_stats *hw_stats = tp->hw_stats;
 
-	if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+	if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
 	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
 	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
 		u32 val;
@@ -9060,7 +9078,7 @@
 		if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) {
 			tg3_writephy(tp, MII_TG3_TEST1,
 				     val | MII_TG3_TEST1_CRC_EN);
-			tg3_readphy(tp, 0x14, &val);
+			tg3_readphy(tp, MII_TG3_RXR_COUNTERS, &val);
 		} else
 			val = 0;
 		spin_unlock_bh(&tp->lock);
@@ -9075,7 +9093,7 @@
 
 #define ESTAT_ADD(member) \
 	estats->member =	old_estats->member + \
-				get_estat64(&hw_stats->member)
+				get_stat64(&hw_stats->member)
 
 static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp)
 {
@@ -9165,11 +9183,11 @@
 	return estats;
 }
 
-static struct net_device_stats *tg3_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
+						 struct rtnl_link_stats64 *stats)
 {
 	struct tg3 *tp = netdev_priv(dev);
-	struct net_device_stats *stats = &tp->net_stats;
-	struct net_device_stats *old_stats = &tp->net_stats_prev;
+	struct rtnl_link_stats64 *old_stats = &tp->net_stats_prev;
 	struct tg3_hw_stats *hw_stats = tp->hw_stats;
 
 	if (!hw_stats)
@@ -9350,13 +9368,13 @@
 
 	memset(p, 0, TG3_REGDUMP_LEN);
 
-	if (tp->link_config.phy_is_low_power)
+	if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
 		return;
 
 	tg3_full_lock(tp, 0);
 
 #define __GET_REG32(reg)	(*(p)++ = tr32(reg))
-#define GET_REG32_LOOP(base,len)		\
+#define GET_REG32_LOOP(base, len)		\
 do {	p = (u32 *)(orig_p + (base));		\
 	for (i = 0; i < len; i += 4)		\
 		__GET_REG32((base) + i);	\
@@ -9429,7 +9447,7 @@
 	if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM)
 		return -EINVAL;
 
-	if (tp->link_config.phy_is_low_power)
+	if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
 		return -EAGAIN;
 
 	offset = eeprom->offset;
@@ -9449,7 +9467,7 @@
 		ret = tg3_nvram_read_be32(tp, offset-b_offset, &val);
 		if (ret)
 			return ret;
-		memcpy(data, ((char*)&val) + b_offset, b_count);
+		memcpy(data, ((char *)&val) + b_offset, b_count);
 		len -= b_count;
 		offset += b_count;
 		eeprom->len += b_count;
@@ -9491,7 +9509,7 @@
 	u8 *buf;
 	__be32 start, end;
 
-	if (tp->link_config.phy_is_low_power)
+	if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
 		return -EAGAIN;
 
 	if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) ||
@@ -9548,7 +9566,7 @@
 
 	if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
 		struct phy_device *phydev;
-		if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+		if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
 			return -EAGAIN;
 		phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
 		return phy_ethtool_gset(phydev, cmd);
@@ -9556,11 +9574,11 @@
 
 	cmd->supported = (SUPPORTED_Autoneg);
 
-	if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+	if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
 		cmd->supported |= (SUPPORTED_1000baseT_Half |
 				   SUPPORTED_1000baseT_Full);
 
-	if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) {
+	if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) {
 		cmd->supported |= (SUPPORTED_100baseT_Half |
 				  SUPPORTED_100baseT_Full |
 				  SUPPORTED_10baseT_Half |
@@ -9591,7 +9609,7 @@
 
 	if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
 		struct phy_device *phydev;
-		if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+		if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
 			return -EAGAIN;
 		phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
 		return phy_ethtool_sset(phydev, cmd);
@@ -9611,11 +9629,11 @@
 			   ADVERTISED_Pause |
 			   ADVERTISED_Asym_Pause;
 
-		if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+		if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
 			mask |= ADVERTISED_1000baseT_Half |
 				ADVERTISED_1000baseT_Full;
 
-		if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
+		if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
 			mask |= ADVERTISED_100baseT_Half |
 				ADVERTISED_100baseT_Full |
 				ADVERTISED_10baseT_Half |
@@ -9636,7 +9654,7 @@
 
 		cmd->advertising &= mask;
 	} else {
-		if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
+		if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES) {
 			if (cmd->speed != SPEED_1000)
 				return -EINVAL;
 
@@ -9772,11 +9790,11 @@
 	if (!netif_running(dev))
 		return -EAGAIN;
 
-	if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
 		return -EINVAL;
 
 	if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
-		if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+		if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
 			return -EAGAIN;
 		r = phy_start_aneg(tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]);
 	} else {
@@ -9787,7 +9805,7 @@
 		tg3_readphy(tp, MII_BMCR, &bmcr);
 		if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
 		    ((bmcr & BMCR_ANENABLE) ||
-		     (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) {
+		     (tp->phy_flags & TG3_PHYFLG_PARALLEL_DETECT))) {
 			tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART |
 						   BMCR_ANENABLE);
 			r = 0;
@@ -9922,7 +9940,7 @@
 		else
 			tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
 
-		if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
+		if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) {
 			u32 oldadv = phydev->advertising &
 				     (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
 			if (oldadv != newadv) {
@@ -10251,7 +10269,7 @@
 	if (!netif_running(tp->dev))
 		return -ENODEV;
 
-	if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
+	if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
 		max = TG3_SERDES_TIMEOUT_SEC;
 	else
 		max = TG3_COPPER_TIMEOUT_SEC;
@@ -10554,7 +10572,8 @@
 	int err = 0;
 	int i;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
 		mem_tbl = mem_tbl_5717;
 	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
 		mem_tbl = mem_tbl_57765;
@@ -10568,8 +10587,8 @@
 		mem_tbl = mem_tbl_570x;
 
 	for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
-		if ((err = tg3_do_mem_test(tp, mem_tbl[i].offset,
-		    mem_tbl[i].len)) != 0)
+		err = tg3_do_mem_test(tp, mem_tbl[i].offset, mem_tbl[i].len);
+		if (err)
 			break;
 	}
 
@@ -10612,7 +10631,7 @@
 			   MAC_MODE_PORT_INT_LPBACK;
 		if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
 			mac_mode |= MAC_MODE_LINK_POLARITY;
-		if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+		if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
 			mac_mode |= MAC_MODE_PORT_MODE_MII;
 		else
 			mac_mode |= MAC_MODE_PORT_MODE_GMII;
@@ -10620,7 +10639,7 @@
 	} else if (loopback_mode == TG3_PHY_LOOPBACK) {
 		u32 val;
 
-		if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
+		if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
 			tg3_phy_fet_toggle_apd(tp, false);
 			val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100;
 		} else
@@ -10632,7 +10651,7 @@
 		udelay(40);
 
 		mac_mode = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
-		if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
+		if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
 			tg3_writephy(tp, MII_TG3_FET_PTEST,
 				     MII_TG3_FET_PTEST_FRC_TX_LINK |
 				     MII_TG3_FET_PTEST_FRC_TX_LOCK);
@@ -10644,7 +10663,7 @@
 			mac_mode |= MAC_MODE_PORT_MODE_GMII;
 
 		/* reset to prevent losing 1st rx packet intermittently */
-		if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
+		if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
 			tw32_f(MAC_RX_MODE, RX_MODE_RESET);
 			udelay(10);
 			tw32_f(MAC_RX_MODE, tp->rx_mode);
@@ -10775,7 +10794,7 @@
 		return TG3_LOOPBACK_FAILED;
 
 	/* Turn off gphy autopowerdown. */
-	if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD)
+	if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD)
 		tg3_phy_toggle_apd(tp, false);
 
 	if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) {
@@ -10812,14 +10831,14 @@
 		tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER);
 	}
 
-	if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+	if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
 	    !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
 		if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK))
 			err |= TG3_PHY_LOOPBACK_FAILED;
 	}
 
 	/* Re-enable gphy autopowerdown. */
-	if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD)
+	if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD)
 		tg3_phy_toggle_apd(tp, true);
 
 	return err;
@@ -10830,7 +10849,7 @@
 {
 	struct tg3 *tp = netdev_priv(dev);
 
-	if (tp->link_config.phy_is_low_power)
+	if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
 		tg3_set_power_state(tp, PCI_D0);
 
 	memset(data, 0, sizeof(u64) * TG3_NUM_TEST);
@@ -10862,7 +10881,7 @@
 		if (!err)
 			tg3_nvram_unlock(tp);
 
-		if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+		if (tp->phy_flags & TG3_PHYFLG_MII_SERDES)
 			tg3_phy_reset(tp);
 
 		if (tg3_test_registers(tp) != 0) {
@@ -10898,7 +10917,7 @@
 		if (irq_sync && !err2)
 			tg3_phy_start(tp);
 	}
-	if (tp->link_config.phy_is_low_power)
+	if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
 		tg3_set_power_state(tp, PCI_D3hot);
 
 }
@@ -10911,10 +10930,10 @@
 
 	if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
 		struct phy_device *phydev;
-		if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+		if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
 			return -EAGAIN;
 		phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
-		return phy_mii_ioctl(phydev, data, cmd);
+		return phy_mii_ioctl(phydev, ifr, cmd);
 	}
 
 	switch (cmd) {
@@ -10925,10 +10944,10 @@
 	case SIOCGMIIREG: {
 		u32 mii_regval;
 
-		if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+		if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
 			break;			/* We have no PHY */
 
-		if (tp->link_config.phy_is_low_power)
+		if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
 			return -EAGAIN;
 
 		spin_lock_bh(&tp->lock);
@@ -10941,10 +10960,10 @@
 	}
 
 	case SIOCSMIIREG:
-		if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+		if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
 			break;			/* We have no PHY */
 
-		if (tp->link_config.phy_is_low_power)
+		if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
 			return -EAGAIN;
 
 		spin_lock_bh(&tp->lock);
@@ -11634,7 +11653,8 @@
 		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
 			 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
 			tg3_get_57780_nvram_info(tp);
-		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+			 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
 			tg3_get_5717_nvram_info(tp);
 		else
 			tg3_get_nvram_info(tp);
@@ -12070,11 +12090,10 @@
 
 		tp->phy_id = eeprom_phy_id;
 		if (eeprom_phy_serdes) {
-			if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
-			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
-				tp->tg3_flags2 |= TG3_FLG2_MII_SERDES;
+			if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+				tp->phy_flags |= TG3_PHYFLG_PHY_SERDES;
 			else
-				tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
+				tp->phy_flags |= TG3_PHYFLG_MII_SERDES;
 		}
 
 		if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
@@ -12158,7 +12177,7 @@
 			(tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
 			tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE;
 
-		if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
+		if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES &&
 		    !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL))
 			tp->tg3_flags &= ~TG3_FLAG_WOL_CAP;
 
@@ -12167,19 +12186,21 @@
 			tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
 
 		if (cfg2 & (1 << 17))
-			tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING;
+			tp->phy_flags |= TG3_PHYFLG_CAPACITIVE_COUPLING;
 
 		/* serdes signal pre-emphasis in register 0x590 set by */
 		/* bootcode if bit 18 is set */
 		if (cfg2 & (1 << 18))
-			tp->tg3_flags2 |= TG3_FLG2_SERDES_PREEMPHASIS;
+			tp->phy_flags |= TG3_PHYFLG_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;
+			tp->phy_flags |= TG3_PHYFLG_ENABLE_APD;
 
-		if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+		if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
+		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+		    !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) {
 			u32 cfg3;
 
 			tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &cfg3);
@@ -12284,9 +12305,9 @@
 	if (!err && TG3_KNOWN_PHY_ID(hw_phy_id_masked)) {
 		tp->phy_id = hw_phy_id;
 		if (hw_phy_id_masked == TG3_PHY_ID_BCM8002)
-			tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
+			tp->phy_flags |= TG3_PHYFLG_PHY_SERDES;
 		else
-			tp->tg3_flags2 &= ~TG3_FLG2_PHY_SERDES;
+			tp->phy_flags &= ~TG3_PHYFLG_PHY_SERDES;
 	} else {
 		if (tp->phy_id != TG3_PHY_ID_INVALID) {
 			/* Do nothing, phy ID already set up in
@@ -12305,11 +12326,11 @@
 			tp->phy_id = p->phy_id;
 			if (!tp->phy_id ||
 			    tp->phy_id == TG3_PHY_ID_BCM8002)
-				tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
+				tp->phy_flags |= TG3_PHYFLG_PHY_SERDES;
 		}
 	}
 
-	if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) &&
+	if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
 	    !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) &&
 	    !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
 		u32 bmsr, adv_reg, tg3_ctrl, mask;
@@ -12327,7 +12348,7 @@
 			   ADVERTISE_100HALF | ADVERTISE_100FULL |
 			   ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
 		tg3_ctrl = 0;
-		if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) {
+		if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
 			tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF |
 				    MII_TG3_CTRL_ADV_1000_FULL);
 			if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
@@ -12342,7 +12363,7 @@
 		if (!tg3_copper_is_advertising_all(tp, mask)) {
 			tg3_writephy(tp, MII_ADVERTISE, adv_reg);
 
-			if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+			if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
 				tg3_writephy(tp, MII_TG3_CTRL, tg3_ctrl);
 
 			tg3_writephy(tp, MII_BMCR,
@@ -12351,7 +12372,7 @@
 		tg3_phy_set_wirespeed(tp);
 
 		tg3_writephy(tp, MII_ADVERTISE, adv_reg);
-		if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+		if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
 			tg3_writephy(tp, MII_TG3_CTRL, tg3_ctrl);
 	}
 
@@ -12364,13 +12385,13 @@
 		err = tg3_init_5401phy_dsp(tp);
 	}
 
-	if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
+	if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
 		tp->link_config.advertising =
 			(ADVERTISED_1000baseT_Half |
 			 ADVERTISED_1000baseT_Full |
 			 ADVERTISED_Autoneg |
 			 ADVERTISED_FIBRE);
-	if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+	if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
 		tp->link_config.advertising &=
 			~(ADVERTISED_1000baseT_Half |
 			  ADVERTISED_1000baseT_Full);
@@ -12699,6 +12720,7 @@
 {
 	int vlen;
 	u32 apedata;
+	char *fwtype;
 
 	if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) ||
 	    !(tp->tg3_flags  & TG3_FLAG_ENABLE_ASF))
@@ -12714,9 +12736,15 @@
 
 	apedata = tg3_ape_read32(tp, TG3_APE_FW_VERSION);
 
+	if (tg3_ape_read32(tp, TG3_APE_FW_FEATURES) & TG3_APE_FW_FEATURE_NCSI)
+		fwtype = "NCSI";
+	else
+		fwtype = "DASH";
+
 	vlen = strlen(tp->fw_ver);
 
-	snprintf(&tp->fw_ver[vlen], TG3_VER_SIZE - vlen, " DASH v%d.%d.%d.%d",
+	snprintf(&tp->fw_ver[vlen], TG3_VER_SIZE - vlen, " %s v%d.%d.%d.%d",
+		 fwtype,
 		 (apedata & APE_FW_VERSION_MAJMSK) >> APE_FW_VERSION_MAJSFT,
 		 (apedata & APE_FW_VERSION_MINMSK) >> APE_FW_VERSION_MINSFT,
 		 (apedata & APE_FW_VERSION_REVMSK) >> APE_FW_VERSION_REVSFT,
@@ -12760,6 +12788,13 @@
 
 static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
 
+static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
+{
+#if TG3_VLAN_TAG_USED
+	dev->vlan_features |= flags;
+#endif
+}
+
 static int __devinit tg3_get_invariants(struct tg3 *tp)
 {
 	static struct pci_device_id write_reorder_chipsets[] = {
@@ -12804,7 +12839,8 @@
 
 		if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 ||
 		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
-		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5724)
+		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5724 ||
+		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719)
 			pci_read_config_dword(tp->pdev,
 					      TG3PCI_GEN2_PRODID_ASICREV,
 					      &prod_id_asic_rev);
@@ -12962,6 +12998,11 @@
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
 		tp->pdev_peer = tg3_find_peer(tp);
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+		tp->tg3_flags3 |= TG3_FLG3_5717_PLUS;
+
 	/* 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 ||
@@ -12969,8 +13010,7 @@
 	    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 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+	    (tp->tg3_flags3 & TG3_FLG3_5717_PLUS))
 		tp->tg3_flags3 |= TG3_FLG3_5755_PLUS;
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
@@ -12990,16 +13030,17 @@
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0)
 		tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS;
 	else {
+		unsigned long features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO;
+
 		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;
-		tp->dev->features |= NETIF_F_GRO;
+			features |= NETIF_F_IPV6_CSUM;
+		tp->dev->features |= features;
+		vlan_features_add(tp->dev, features);
 	}
 
 	/* Determine TSO capabilities */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+	if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)
 		tp->tg3_flags2 |= TG3_FLG2_HW_TSO_3;
 	else if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
 		 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
@@ -13035,14 +13076,14 @@
 			tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
 		}
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+		if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
 			tp->tg3_flags |= TG3_FLAG_SUPPORT_MSIX;
 			tp->irq_max = TG3_IRQ_MAX_VECS;
 		}
 	}
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
 		tp->tg3_flags3 |= TG3_FLG3_SHORT_DMA_BUG;
 	else if (!(tp->tg3_flags3 & TG3_FLG3_5755_PLUS)) {
@@ -13050,8 +13091,7 @@
 		tp->tg3_flags3 |= TG3_FLG3_40BIT_DMA_LIMIT_BUG;
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+	if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)
 		tp->tg3_flags3 |= TG3_FLG3_USE_JUMBO_BDFLAG;
 
 	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
@@ -13242,7 +13282,8 @@
 		 * APE register and memory space.
 		 */
 		pci_state_reg |= PCISTATE_ALLOW_APE_CTLSPC_WR |
-				 PCISTATE_ALLOW_APE_SHMEM_WR;
+				 PCISTATE_ALLOW_APE_SHMEM_WR |
+				 PCISTATE_ALLOW_APE_PSPACE_WR;
 		pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE,
 				       pci_state_reg);
 	}
@@ -13251,8 +13292,7 @@
 	    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 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+	    (tp->tg3_flags3 & TG3_FLG3_5717_PLUS))
 		tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;
 
 	/* Set up tp->grc_local_ctrl before calling tg3_set_power_state().
@@ -13310,40 +13350,39 @@
 	}
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
-		tp->tg3_flags3 |= TG3_FLG3_PHY_IS_FET;
+		tp->phy_flags |= TG3_PHYFLG_IS_FET;
 
 	/* A few boards don't want Ethernet@WireSpeed phy feature */
 	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) ||
 	    ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
 	     (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
 	     (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) ||
-	    (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) ||
-	    (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
-		tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED;
+	    (tp->phy_flags & TG3_PHYFLG_IS_FET) ||
+	    (tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
+		tp->phy_flags |= TG3_PHYFLG_NO_ETH_WIRE_SPEED;
 
 	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5703_AX ||
 	    GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_AX)
-		tp->tg3_flags2 |= TG3_FLG2_PHY_ADC_BUG;
+		tp->phy_flags |= TG3_PHYFLG_ADC_BUG;
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
-		tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG;
+		tp->phy_flags |= TG3_PHYFLG_5704_A0_BUG;
 
 	if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
-	    !(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) &&
+	    !(tp->phy_flags & TG3_PHYFLG_IS_FET) &&
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765) {
+	    !(tp->tg3_flags3 & TG3_FLG3_5717_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) {
 			if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 &&
 			    tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722)
-				tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
+				tp->phy_flags |= TG3_PHYFLG_JITTER_BUG;
 			if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M)
-				tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM;
+				tp->phy_flags |= TG3_PHYFLG_ADJUST_TRIM;
 		} else
-			tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
+			tp->phy_flags |= TG3_PHYFLG_BER_BUG;
 	}
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
@@ -13372,8 +13411,7 @@
 		return err;
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
-	    (tp->pci_chip_rev_id != CHIPREV_ID_5717_A0 ||
-		 (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
+	    tp->pci_chip_rev_id != CHIPREV_ID_5717_A0)
 		return -ENOTSUPP;
 
 	/* Initialize data/descriptor byte/word swapping. */
@@ -13457,8 +13495,8 @@
 	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790 ||
 	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791 ||
 	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795 ||
-	    (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET))
-		tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
+	    (tp->phy_flags & TG3_PHYFLG_IS_FET))
+		tp->phy_flags |= TG3_PHYFLG_10_100_ONLY;
 
 	err = tg3_phy_probe(tp);
 	if (err) {
@@ -13470,13 +13508,13 @@
 	tg3_read_vpd(tp);
 	tg3_read_fw_ver(tp);
 
-	if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
-		tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT;
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
+		tp->phy_flags &= ~TG3_PHYFLG_USE_MI_INTERRUPT;
 	} else {
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
-			tp->tg3_flags |= TG3_FLAG_USE_MI_INTERRUPT;
+			tp->phy_flags |= TG3_PHYFLG_USE_MI_INTERRUPT;
 		else
-			tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT;
+			tp->phy_flags &= ~TG3_PHYFLG_USE_MI_INTERRUPT;
 	}
 
 	/* 5700 {AX,BX} chips have a broken status block link
@@ -13494,13 +13532,13 @@
 	 */
 	if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
-	    !(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
-		tp->tg3_flags |= (TG3_FLAG_USE_MI_INTERRUPT |
-				  TG3_FLAG_USE_LINKCHG_REG);
+	    !(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
+		tp->phy_flags |= TG3_PHYFLG_USE_MI_INTERRUPT;
+		tp->tg3_flags |= TG3_FLAG_USE_LINKCHG_REG;
 	}
 
 	/* For all SERDES we poll the MAC status register. */
-	if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
 		tp->tg3_flags |= TG3_FLAG_POLL_SERDES;
 	else
 		tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
@@ -13580,9 +13618,12 @@
 			tw32_f(NVRAM_CMD, NVRAM_CMD_RESET);
 		else
 			tg3_nvram_unlock(tp);
-	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
-		if (tr32(TG3_CPMU_STATUS) & TG3_CPMU_STATUS_PCIE_FUNC)
+	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+		   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+		if (PCI_FUNC(tp->pdev->devfn) & 1)
 			mac_offset = 0xcc;
+		if (PCI_FUNC(tp->pdev->devfn) > 1)
+			mac_offset += 0x18c;
 	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
 		mac_offset = 0x10;
 
@@ -13667,8 +13708,7 @@
 #endif
 #endif
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+	if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
 		val = goal ? 0 : DMA_RWCTRL_DIS_CACHE_ALIGNMENT;
 		goto out;
 	}
@@ -13879,8 +13919,7 @@
 
 	tp->dma_rwctrl = tg3_calc_dma_bndry(tp, tp->dma_rwctrl);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+	if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)
 		goto out;
 
 	if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
@@ -14070,7 +14109,6 @@
 	tp->link_config.autoneg = AUTONEG_ENABLE;
 	tp->link_config.active_speed = SPEED_INVALID;
 	tp->link_config.active_duplex = DUPLEX_INVALID;
-	tp->link_config.phy_is_low_power = 0;
 	tp->link_config.orig_speed = SPEED_INVALID;
 	tp->link_config.orig_duplex = DUPLEX_INVALID;
 	tp->link_config.orig_autoneg = AUTONEG_INVALID;
@@ -14078,8 +14116,7 @@
 
 static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
 {
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+	if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
 		tp->bufmgr_config.mbuf_read_dma_low_water =
 			DEFAULT_MB_RDMA_LOW_WATER_5705;
 		tp->bufmgr_config.mbuf_mac_rx_low_water =
@@ -14156,6 +14193,7 @@
 	case TG3_PHY_ID_BCM5718C:	return "5718C";
 	case TG3_PHY_ID_BCM5718S:	return "5718S";
 	case TG3_PHY_ID_BCM57765:	return "57765";
+	case TG3_PHY_ID_BCM5719C:	return "5719C";
 	case TG3_PHY_ID_BCM8002:	return "8002/serdes";
 	case 0:			return "serdes";
 	default:		return "unknown";
@@ -14261,7 +14299,7 @@
 	.ndo_open		= tg3_open,
 	.ndo_stop		= tg3_close,
 	.ndo_start_xmit		= tg3_start_xmit,
-	.ndo_get_stats		= tg3_get_stats,
+	.ndo_get_stats64	= tg3_get_stats64,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_set_multicast_list	= tg3_set_rx_mode,
 	.ndo_set_mac_address	= tg3_set_mac_addr,
@@ -14280,7 +14318,7 @@
 	.ndo_open		= tg3_open,
 	.ndo_stop		= tg3_close,
 	.ndo_start_xmit		= tg3_start_xmit_dma_bug,
-	.ndo_get_stats		= tg3_get_stats,
+	.ndo_get_stats64	= tg3_get_stats64,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_set_multicast_list	= tg3_set_rx_mode,
 	.ndo_set_mac_address	= tg3_set_mac_addr,
@@ -14404,7 +14442,8 @@
 	}
 
 	if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) &&
-	    tp->pci_chip_rev_id != CHIPREV_ID_5717_A0)
+	    tp->pci_chip_rev_id != CHIPREV_ID_5717_A0 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719)
 		dev->netdev_ops = &tg3_netdev_ops;
 	else
 		dev->netdev_ops = &tg3_netdev_ops_dma_bug;
@@ -14468,20 +14507,25 @@
 	 * is off by default, but can be enabled using ethtool.
 	 */
 	if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) &&
-	    (dev->features & NETIF_F_IP_CSUM))
+	    (dev->features & NETIF_F_IP_CSUM)) {
 		dev->features |= NETIF_F_TSO;
-
+		vlan_features_add(dev, NETIF_F_TSO);
+	}
 	if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) ||
 	    (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3)) {
-		if (dev->features & NETIF_F_IPV6_CSUM)
+		if (dev->features & NETIF_F_IPV6_CSUM) {
 			dev->features |= NETIF_F_TSO6;
+			vlan_features_add(dev, NETIF_F_TSO6);
+		}
 		if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) ||
 		    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_57780)
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
 			dev->features |= NETIF_F_TSO_ECN;
+			vlan_features_add(dev, NETIF_F_TSO_ECN);
+		}
 	}
 
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 &&
@@ -14597,24 +14641,31 @@
 		    tg3_bus_string(tp, str),
 		    dev->dev_addr);
 
-	if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
+	if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) {
 		struct phy_device *phydev;
 		phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
 		netdev_info(dev,
 			    "attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
 			    phydev->drv->name, dev_name(&phydev->dev));
-	} else
+	} else {
+		char *ethtype;
+
+		if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
+			ethtype = "10/100Base-TX";
+		else if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
+			ethtype = "1000Base-SX";
+		else
+			ethtype = "10/100/1000Base-T";
+
 		netdev_info(dev, "attached PHY is %s (%s Ethernet) "
-			    "(WireSpeed[%d])\n", 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);
+			    "(WireSpeed[%d])\n", tg3_phy_string(tp), ethtype,
+			  (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED) == 0);
+	}
 
 	netdev_info(dev, "RXcsums[%d] LinkChgREG[%d] MIirq[%d] ASF[%d] TSOcap[%d]\n",
 		    (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->phy_flags & TG3_PHYFLG_USE_MI_INTERRUPT) != 0,
 		    (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0,
 		    (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0);
 	netdev_info(dev, "dma_rwctrl[%08x] dma_mask[%d-bit]\n",
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index ce9c491..4937bd1 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -53,6 +53,7 @@
 #define  TG3PCI_DEVICE_TIGON3_57765	 0x16b4
 #define  TG3PCI_DEVICE_TIGON3_57791	 0x16b2
 #define  TG3PCI_DEVICE_TIGON3_57795	 0x16b6
+#define  TG3PCI_DEVICE_TIGON3_5719	 0x1657
 /* 0x04 --> 0x2c unused */
 #define TG3PCI_SUBVENDOR_ID_BROADCOM		PCI_VENDOR_ID_BROADCOM
 #define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6	0x1644
@@ -160,6 +161,7 @@
 #define   ASIC_REV_57780		 0x57780
 #define   ASIC_REV_5717			 0x5717
 #define   ASIC_REV_57765		 0x57785
+#define   ASIC_REV_5719			 0x5719
 #define  GET_CHIP_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 8)
 #define   CHIPREV_5700_AX		 0x70
 #define   CHIPREV_5700_BX		 0x71
@@ -231,6 +233,7 @@
 #define  PCISTATE_RETRY_SAME_DMA	 0x00002000
 #define  PCISTATE_ALLOW_APE_CTLSPC_WR	 0x00010000
 #define  PCISTATE_ALLOW_APE_SHMEM_WR	 0x00020000
+#define  PCISTATE_ALLOW_APE_PSPACE_WR	 0x00040000
 #define TG3PCI_CLOCK_CTRL		0x00000074
 #define  CLOCK_CTRL_CORECLK_DISABLE	 0x00000200
 #define  CLOCK_CTRL_RXCLK_DISABLE	 0x00000400
@@ -468,6 +471,7 @@
 #define  TX_MODE_FLOW_CTRL_ENABLE	 0x00000010
 #define  TX_MODE_BIG_BCKOFF_ENABLE	 0x00000020
 #define  TX_MODE_LONG_PAUSE_ENABLE	 0x00000040
+#define  TX_MODE_MBUF_LOCKUP_FIX	 0x00000100
 #define MAC_TX_STATUS			0x00000460
 #define  TX_STATUS_XOFFED		 0x00000001
 #define  TX_STATUS_SENT_XOFF		 0x00000002
@@ -1071,10 +1075,8 @@
 #define TG3_CPMU_HST_ACC		0x0000361c
 #define  CPMU_HST_ACC_MACCLK_MASK	 0x001f0000
 #define  CPMU_HST_ACC_MACCLK_6_25	 0x00130000
-/* 0x3620 --> 0x362c unused */
+/* 0x3620 --> 0x3630 unused */
 
-#define TG3_CPMU_STATUS			0x0000362c
-#define  TG3_CPMU_STATUS_PCIE_FUNC	 0x20000000
 #define TG3_CPMU_CLCK_STAT		0x00003630
 #define  CPMU_CLCK_STAT_MAC_CLCK_MASK	 0x001f0000
 #define  CPMU_CLCK_STAT_MAC_CLCK_62_5	 0x00000000
@@ -1842,6 +1844,10 @@
 #define  TG3_PCIE_LNKCTL_L1_PLL_PD_DIS	 0x00000080
 /* 0x7d58 --> 0x7e70 unused */
 
+#define TG3_PCIE_PHY_TSTCTL		0x00007e2c
+#define  TG3_PCIE_PHY_TSTCTL_PCIE10	 0x00000040
+#define  TG3_PCIE_PHY_TSTCTL_PSCRAM	 0x00000020
+
 #define TG3_PCIE_EIDLE_DELAY		0x00007e70
 #define  TG3_PCIE_EIDLE_DELAY_MASK	 0x0000001f
 #define  TG3_PCIE_EIDLE_DELAY_13_CLKS	 0x0000000c
@@ -2030,31 +2036,9 @@
 
 
 /* Currently this is fixed. */
-#define TG3_PHY_PCIE_ADDR		0x00
 #define TG3_PHY_MII_ADDR		0x01
 
 
-/*** Tigon3 specific PHY PCIE registers. ***/
-
-#define TG3_PCIEPHY_BLOCK_ADDR		0x1f
-#define  TG3_PCIEPHY_XGXS_BLK1		0x0801
-#define  TG3_PCIEPHY_TXB_BLK		0x0861
-#define  TG3_PCIEPHY_BLOCK_SHIFT	4
-
-/* TG3_PCIEPHY_TXB_BLK */
-#define TG3_PCIEPHY_TX0CTRL1		0x15
-#define  TG3_PCIEPHY_TX0CTRL1_TXOCM	0x0003
-#define  TG3_PCIEPHY_TX0CTRL1_RDCTL	0x0008
-#define  TG3_PCIEPHY_TX0CTRL1_TXCMV	0x0030
-#define  TG3_PCIEPHY_TX0CTRL1_TKSEL	0x0040
-#define  TG3_PCIEPHY_TX0CTRL1_NB_EN	0x0400
-
-/* TG3_PCIEPHY_XGXS_BLK1 */
-#define TG3_PCIEPHY_PWRMGMT4		0x1a
-#define TG3_PCIEPHY_PWRMGMT4_L1PLLPD_EN	0x0038
-#define TG3_PCIEPHY_PWRMGMT4_LOWPWR_EN	0x4000
-
-
 /*** Tigon3 specific PHY MII registers. ***/
 #define  TG3_BMCR_SPEED1000		0x0040
 
@@ -2073,8 +2057,9 @@
 #define MII_TG3_EXT_STAT		0x11 /* Extended status register */
 #define  MII_TG3_EXT_STAT_LPASS		0x0100
 
+#define MII_TG3_RXR_COUNTERS		0x14 /* Local/Remote Receiver Counts */
 #define MII_TG3_DSP_RW_PORT		0x15 /* DSP coefficient read/write port */
-
+#define MII_TG3_DSP_CONTROL		0x16 /* DSP control register */
 #define MII_TG3_DSP_ADDRESS		0x17 /* DSP address register */
 
 #define MII_TG3_DSP_TAP1		0x0001
@@ -2082,6 +2067,7 @@
 #define MII_TG3_DSP_AADJ1CH0		0x001f
 #define MII_TG3_DSP_AADJ1CH3		0x601f
 #define  MII_TG3_DSP_AADJ1CH3_ADCCKADJ	0x0002
+#define MII_TG3_DSP_EXP1_INT_STAT	0x0f01
 #define MII_TG3_DSP_EXP8		0x0f08
 #define  MII_TG3_DSP_EXP8_REJ2MHz	0x0001
 #define  MII_TG3_DSP_EXP8_AEDW		0x0200
@@ -2177,6 +2163,8 @@
 /* APE shared memory.  Accessible through BAR1 */
 #define TG3_APE_FW_STATUS		0x400c
 #define  APE_FW_STATUS_READY		 0x00000100
+#define TG3_APE_FW_FEATURES		0x4010
+#define  TG3_APE_FW_FEATURE_NCSI	 0x00000002
 #define TG3_APE_FW_VERSION		0x4018
 #define  APE_FW_VERSION_MAJMSK		 0xff000000
 #define  APE_FW_VERSION_MAJSFT		 24
@@ -2191,7 +2179,9 @@
 #define  APE_HOST_SEG_LEN_MAGIC		 0x0000001c
 #define TG3_APE_HOST_INIT_COUNT		0x4208
 #define TG3_APE_HOST_DRIVER_ID		0x420c
-#define  APE_HOST_DRIVER_ID_MAGIC	 0xf0035100
+#define  APE_HOST_DRIVER_ID_LINUX	 0xf0000000
+#define  APE_HOST_DRIVER_ID_MAGIC(maj, min)	\
+	(APE_HOST_DRIVER_ID_LINUX | (maj & 0xff) << 16 | (min & 0xff) << 8)
 #define TG3_APE_HOST_BEHAVIOR		0x4210
 #define  APE_HOST_BEHAV_NO_PHYLOCK	 0x00000001
 #define TG3_APE_HOST_HEARTBEAT_INT_MS	0x4214
@@ -2209,6 +2199,11 @@
 #define  APE_EVENT_STATUS_STATE_SUSPEND	 0x00040000
 #define  APE_EVENT_STATUS_EVENT_PENDING	 0x80000000
 
+#define TG3_APE_PER_LOCK_REQ		0x8400
+#define  APE_LOCK_PER_REQ_DRIVER	 0x00001000
+#define TG3_APE_PER_LOCK_GRANT		0x8420
+#define  APE_PER_LOCK_GRANT_DRIVER	 0x00001000
+
 /* APE convenience enumerations. */
 #define TG3_APE_LOCK_GRC                1
 #define TG3_APE_LOCK_MEM                4
@@ -2539,7 +2534,6 @@
 	/* When we go in and out of low power mode we need
 	 * to swap with this state.
 	 */
-	int				phy_is_low_power;
 	u16				orig_speed;
 	u8				orig_duplex;
 	u8				orig_autoneg;
@@ -2765,8 +2759,8 @@
 
 
 	/* begin "everything else" cacheline(s) section */
-	struct net_device_stats		net_stats;
-	struct net_device_stats		net_stats_prev;
+	struct rtnl_link_stats64	net_stats;
+	struct rtnl_link_stats64	net_stats_prev;
 	struct tg3_ethtool_stats	estats;
 	struct tg3_ethtool_stats	estats_prev;
 
@@ -2780,7 +2774,6 @@
 #define TG3_FLAG_TXD_MBOX_HWBUG		0x00000002
 #define TG3_FLAG_RX_CHECKSUMS		0x00000004
 #define TG3_FLAG_USE_LINKCHG_REG	0x00000008
-#define TG3_FLAG_USE_MI_INTERRUPT	0x00000010
 #define TG3_FLAG_ENABLE_ASF		0x00000020
 #define TG3_FLAG_ASPM_WORKAROUND	0x00000040
 #define TG3_FLAG_POLL_SERDES		0x00000080
@@ -2802,7 +2795,6 @@
 #define TG3_FLAG_TX_RECOVERY_PENDING	0x00200000
 #define TG3_FLAG_WOL_CAP		0x00400000
 #define TG3_FLAG_JUMBO_RING_ENABLE	0x00800000
-#define TG3_FLAG_10_100_ONLY		0x01000000
 #define TG3_FLAG_PAUSE_AUTONEG		0x02000000
 #define TG3_FLAG_CPMU_PRESENT		0x04000000
 #define TG3_FLAG_40BIT_DMA_BUG		0x08000000
@@ -2813,22 +2805,15 @@
 	u32				tg3_flags2;
 #define TG3_FLG2_RESTART_TIMER		0x00000001
 #define TG3_FLG2_TSO_BUG		0x00000002
-#define TG3_FLG2_NO_ETH_WIRE_SPEED	0x00000004
 #define TG3_FLG2_IS_5788		0x00000008
 #define TG3_FLG2_MAX_RXPEND_64		0x00000010
 #define TG3_FLG2_TSO_CAPABLE		0x00000020
-#define TG3_FLG2_PHY_ADC_BUG		0x00000040
-#define TG3_FLG2_PHY_5704_A0_BUG	0x00000080
-#define TG3_FLG2_PHY_BER_BUG		0x00000100
 #define TG3_FLG2_PCI_EXPRESS		0x00000200
 #define TG3_FLG2_ASF_NEW_HANDSHAKE	0x00000400
 #define TG3_FLG2_HW_AUTONEG		0x00000800
 #define TG3_FLG2_IS_NIC			0x00001000
-#define TG3_FLG2_PHY_SERDES		0x00002000
-#define TG3_FLG2_CAPACITIVE_COUPLING	0x00004000
 #define TG3_FLG2_FLASH			0x00008000
 #define TG3_FLG2_HW_TSO_1		0x00010000
-#define TG3_FLG2_SERDES_PREEMPHASIS	0x00020000
 #define TG3_FLG2_5705_PLUS		0x00040000
 #define TG3_FLG2_5750_PLUS		0x00080000
 #define TG3_FLG2_HW_TSO_3		0x00100000
@@ -2836,10 +2821,6 @@
 #define TG3_FLG2_USING_MSIX		0x00400000
 #define TG3_FLG2_USING_MSI_OR_MSIX	(TG3_FLG2_USING_MSI | \
 					TG3_FLG2_USING_MSIX)
-#define TG3_FLG2_MII_SERDES		0x00800000
-#define TG3_FLG2_ANY_SERDES		(TG3_FLG2_PHY_SERDES |	\
-					TG3_FLG2_MII_SERDES)
-#define TG3_FLG2_PARALLEL_DETECT	0x01000000
 #define TG3_FLG2_ICH_WORKAROUND		0x02000000
 #define TG3_FLG2_5780_CLASS		0x04000000
 #define TG3_FLG2_HW_TSO_2		0x08000000
@@ -2847,9 +2828,7 @@
 					 TG3_FLG2_HW_TSO_2 | \
 					 TG3_FLG2_HW_TSO_3)
 #define TG3_FLG2_1SHOT_MSI		0x10000000
-#define TG3_FLG2_PHY_JITTER_BUG		0x20000000
 #define TG3_FLG2_NO_FWARE_REPORTED	0x40000000
-#define TG3_FLG2_PHY_ADJUST_TRIM	0x80000000
 	u32				tg3_flags3;
 #define TG3_FLG3_NO_NVRAM_ADDR_TRANS	0x00000001
 #define TG3_FLG3_ENABLE_APE		0x00000002
@@ -2857,15 +2836,12 @@
 #define TG3_FLG3_5701_DMA_BUG		0x00000008
 #define TG3_FLG3_USE_PHYLIB		0x00000010
 #define TG3_FLG3_MDIOBUS_INITED		0x00000020
-#define TG3_FLG3_PHY_CONNECTED		0x00000080
 #define TG3_FLG3_RGMII_INBAND_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
 #define TG3_FLG3_NO_NVRAM		0x00004000
-#define TG3_FLG3_PHY_IS_FET		0x00010000
 #define TG3_FLG3_ENABLE_RSS		0x00020000
 #define TG3_FLG3_ENABLE_TSS		0x00040000
 #define TG3_FLG3_4G_DMA_BNDRY_BUG	0x00080000
@@ -2873,6 +2849,7 @@
 #define TG3_FLG3_SHORT_DMA_BUG		0x00200000
 #define TG3_FLG3_USE_JUMBO_BDFLAG	0x00400000
 #define TG3_FLG3_L1PLLPD_EN		0x00800000
+#define TG3_FLG3_5717_PLUS		0x01000000
 
 	struct timer_list		timer;
 	u16				timer_counter;
@@ -2942,6 +2919,7 @@
 #define TG3_PHY_ID_BCM5718C		0x5c0d8a00
 #define TG3_PHY_ID_BCM5718S		0xbc050ff0
 #define TG3_PHY_ID_BCM57765		0x5c0d8a40
+#define TG3_PHY_ID_BCM5719C		0x5c0d8a20
 #define TG3_PHY_ID_BCM5906		0xdc00ac40
 #define TG3_PHY_ID_BCM8002		0x60010140
 #define TG3_PHY_ID_INVALID		0xffffffff
@@ -2965,7 +2943,29 @@
 	 (X) == TG3_PHY_ID_BCM5755 || (X) == TG3_PHY_ID_BCM5756 || \
 	 (X) == TG3_PHY_ID_BCM5906 || (X) == TG3_PHY_ID_BCM5761 || \
 	 (X) == TG3_PHY_ID_BCM5718C || (X) == TG3_PHY_ID_BCM5718S || \
-	 (X) == TG3_PHY_ID_BCM57765 || (X) == TG3_PHY_ID_BCM8002)
+	 (X) == TG3_PHY_ID_BCM57765 || (X) == TG3_PHY_ID_BCM5719C || \
+	 (X) == TG3_PHY_ID_BCM8002)
+
+	u32				phy_flags;
+#define TG3_PHYFLG_IS_LOW_POWER		0x00000001
+#define TG3_PHYFLG_IS_CONNECTED		0x00000002
+#define TG3_PHYFLG_USE_MI_INTERRUPT	0x00000004
+#define TG3_PHYFLG_PHY_SERDES		0x00000010
+#define TG3_PHYFLG_MII_SERDES		0x00000020
+#define TG3_PHYFLG_ANY_SERDES		(TG3_PHYFLG_PHY_SERDES |	\
+					TG3_PHYFLG_MII_SERDES)
+#define TG3_PHYFLG_IS_FET		0x00000040
+#define TG3_PHYFLG_10_100_ONLY		0x00000080
+#define TG3_PHYFLG_ENABLE_APD		0x00000100
+#define TG3_PHYFLG_CAPACITIVE_COUPLING	0x00000200
+#define TG3_PHYFLG_NO_ETH_WIRE_SPEED	0x00000400
+#define TG3_PHYFLG_JITTER_BUG		0x00000800
+#define TG3_PHYFLG_ADJUST_TRIM		0x00001000
+#define TG3_PHYFLG_ADC_BUG		0x00002000
+#define TG3_PHYFLG_5704_A0_BUG		0x00004000
+#define TG3_PHYFLG_BER_BUG		0x00008000
+#define TG3_PHYFLG_SERDES_PREEMPHASIS	0x00010000
+#define TG3_PHYFLG_PARALLEL_DETECT	0x00020000
 
 	u32				led_ctrl;
 	u32				phy_otp;
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index 06b552f..5efa577 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -262,13 +262,13 @@
 	u16			csr13;
 	u16			csr14;
 	u16			csr15;
-} __attribute__((packed));
+} __packed;
 
 struct de_srom_info_leaf {
 	u16			default_media;
 	u8			n_blocks;
 	u8			unused;
-} __attribute__((packed));
+} __packed;
 
 struct de_desc {
 	__le32			opts1;
diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
index 6002e65..3031ed9 100644
--- a/drivers/net/tulip/eeprom.c
+++ b/drivers/net/tulip/eeprom.c
@@ -120,8 +120,8 @@
 			  0x00, 0x06  /* ttm bit map */
 			};
 
-		tp->mtable = (struct mediatable *)
-			kmalloc(sizeof(struct mediatable) + sizeof(struct medialeaf), GFP_KERNEL);
+		tp->mtable = kmalloc(sizeof(struct mediatable) +
+				     sizeof(struct medialeaf), GFP_KERNEL);
 
 		if (tp->mtable == NULL)
 			return; /* Horrible, impossible failure. */
@@ -227,9 +227,9 @@
 		        return;
 		}
 
-		mtable = (struct mediatable *)
-			kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf),
-					GFP_KERNEL);
+		mtable = kmalloc(sizeof(struct mediatable) +
+				 count * sizeof(struct medialeaf),
+				 GFP_KERNEL);
 		if (mtable == NULL)
 			return;				/* Horrible, impossible failure. */
 		last_mediatable = tp->mtable = mtable;
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 0afa2d4..e525875 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -20,6 +20,7 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <linux/netdevice.h>
+#include <linux/ethtool.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
@@ -51,22 +52,23 @@
 
 
 enum tbl_flag {
-	HAS_MII			= 0x0001,
-	HAS_MEDIA_TABLE		= 0x0002,
-	CSR12_IN_SROM		= 0x0004,
-	ALWAYS_CHECK_MII	= 0x0008,
-	HAS_ACPI		= 0x0010,
-	MC_HASH_ONLY		= 0x0020, /* Hash-only multicast filter. */
-	HAS_PNICNWAY		= 0x0080,
-	HAS_NWAY		= 0x0040, /* Uses internal NWay xcvr. */
-	HAS_INTR_MITIGATION	= 0x0100,
-	IS_ASIX			= 0x0200,
-	HAS_8023X		= 0x0400,
-	COMET_MAC_ADDR		= 0x0800,
-	HAS_PCI_MWI		= 0x1000,
-	HAS_PHY_IRQ		= 0x2000,
-	HAS_SWAPPED_SEEPROM	= 0x4000,
-	NEEDS_FAKE_MEDIA_TABLE	= 0x8000,
+	HAS_MII			= 0x00001,
+	HAS_MEDIA_TABLE		= 0x00002,
+	CSR12_IN_SROM		= 0x00004,
+	ALWAYS_CHECK_MII	= 0x00008,
+	HAS_ACPI		= 0x00010,
+	MC_HASH_ONLY		= 0x00020, /* Hash-only multicast filter. */
+	HAS_PNICNWAY		= 0x00080,
+	HAS_NWAY		= 0x00040, /* Uses internal NWay xcvr. */
+	HAS_INTR_MITIGATION	= 0x00100,
+	IS_ASIX			= 0x00200,
+	HAS_8023X		= 0x00400,
+	COMET_MAC_ADDR		= 0x00800,
+	HAS_PCI_MWI		= 0x01000,
+	HAS_PHY_IRQ		= 0x02000,
+	HAS_SWAPPED_SEEPROM	= 0x04000,
+	NEEDS_FAKE_MEDIA_TABLE	= 0x08000,
+	COMET_PM		= 0x10000,
 };
 
 
@@ -120,6 +122,11 @@
 	CSR13 = 0x68,
 	CSR14 = 0x70,
 	CSR15 = 0x78,
+	CSR18 = 0x88,
+	CSR19 = 0x8c,
+	CSR20 = 0x90,
+	CSR27 = 0xAC,
+	CSR28 = 0xB0,
 };
 
 /* register offset and bits for CFDD PCI config reg */
@@ -289,6 +296,30 @@
 	csr6_mask_100bt = (csr6_scr | csr6_pcs | csr6_hbd),
 };
 
+enum tulip_comet_csr13_bits {
+/* The LINKOFFE and LINKONE work in conjunction with LSCE, i.e. they
+ * determine which link status transition wakes up if LSCE is
+ * enabled */
+        comet_csr13_linkoffe = (1 << 17),
+        comet_csr13_linkone = (1 << 16),
+        comet_csr13_wfre = (1 << 10),
+        comet_csr13_mpre = (1 << 9),
+        comet_csr13_lsce = (1 << 8),
+        comet_csr13_wfr = (1 << 2),
+        comet_csr13_mpr = (1 << 1),
+        comet_csr13_lsc = (1 << 0),
+};
+
+enum tulip_comet_csr18_bits {
+        comet_csr18_pmes_sticky = (1 << 24),
+        comet_csr18_pm_mode = (1 << 19),
+        comet_csr18_apm_mode = (1 << 18),
+        comet_csr18_d3a = (1 << 7)
+};
+
+enum tulip_comet_csr20_bits {
+        comet_csr20_pmes = (1 << 15),
+};
 
 /* Keep the ring sizes a power of two for efficiency.
    Making the Tx ring too large decreases the effectiveness of channel
@@ -411,6 +442,7 @@
 	unsigned int csr6;	/* Current CSR6 control settings. */
 	unsigned char eeprom[EEPROM_SIZE];	/* Serial EEPROM contents. */
 	void (*link_change) (struct net_device * dev, int csr5);
+        struct ethtool_wolinfo wolinfo;        /* WOL settings */
 	u16 sym_advertise, mii_advertise; /* NWay capabilities advertised.  */
 	u16 lpar;		/* 21143 Link partner ability. */
 	u16 advertising[4];
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 254643e..3a8d7ef 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -30,7 +30,6 @@
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
 #include <linux/mii.h>
-#include <linux/ethtool.h>
 #include <linux/crc32.h>
 #include <asm/unaligned.h>
 #include <asm/uaccess.h>
@@ -272,6 +271,7 @@
 static struct net_device_stats *tulip_get_stats(struct net_device *dev);
 static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void set_rx_mode(struct net_device *dev);
+static void tulip_set_wolopts(struct pci_dev *pdev, u32 wolopts);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void poll_tulip(struct net_device *dev);
 #endif
@@ -309,6 +309,11 @@
 	/* Wake the chip from sleep/snooze mode. */
 	tulip_set_power_state (tp, 0, 0);
 
+	/* Disable all WOL events */
+	pci_enable_wake(tp->pdev, PCI_D3hot, 0);
+	pci_enable_wake(tp->pdev, PCI_D3cold, 0);
+	tulip_set_wolopts(tp->pdev, 0);
+
 	/* On some chip revs we must set the MII/SYM port before the reset!? */
 	if (tp->mii_cnt  ||  (tp->mtable  &&  tp->mtable->has_mii))
 		iowrite32(0x00040000, ioaddr + CSR6);
@@ -345,8 +350,8 @@
 		} else if (tp->flags & COMET_MAC_ADDR) {
 			iowrite32(addr_low,  ioaddr + 0xA4);
 			iowrite32(addr_high, ioaddr + 0xA8);
-			iowrite32(0, ioaddr + 0xAC);
-			iowrite32(0, ioaddr + 0xB0);
+			iowrite32(0, ioaddr + CSR27);
+			iowrite32(0, ioaddr + CSR28);
 		}
 	} else {
 		/* This is set_rx_mode(), but without starting the transmitter. */
@@ -591,10 +596,10 @@
 					pr_cont(" %02x", buf[j]);
 			pr_cont(" j=%d\n", j);
 		}
-		printk(KERN_DEBUG "  Rx ring %08x: ", (int)tp->rx_ring);
+		printk(KERN_DEBUG "  Rx ring %p: ", tp->rx_ring);
 		for (i = 0; i < RX_RING_SIZE; i++)
 			pr_cont(" %08x", (unsigned int)tp->rx_ring[i].status);
-		printk(KERN_DEBUG "  Tx ring %08x: ", (int)tp->tx_ring);
+		printk(KERN_DEBUG "  Tx ring %p: ", tp->tx_ring);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			pr_cont(" %08x", (unsigned int)tp->tx_ring[i].status);
 		pr_cont("\n");
@@ -876,8 +881,35 @@
 	strcpy(info->bus_info, pci_name(np->pdev));
 }
 
+
+static int tulip_ethtool_set_wol(struct net_device *dev,
+				 struct ethtool_wolinfo *wolinfo)
+{
+	struct tulip_private *tp = netdev_priv(dev);
+
+	if (wolinfo->wolopts & (~tp->wolinfo.supported))
+		   return -EOPNOTSUPP;
+
+	tp->wolinfo.wolopts = wolinfo->wolopts;
+	device_set_wakeup_enable(&tp->pdev->dev, tp->wolinfo.wolopts);
+	return 0;
+}
+
+static void tulip_ethtool_get_wol(struct net_device *dev,
+				  struct ethtool_wolinfo *wolinfo)
+{
+	struct tulip_private *tp = netdev_priv(dev);
+
+	wolinfo->supported = tp->wolinfo.supported;
+	wolinfo->wolopts = tp->wolinfo.wolopts;
+	return;
+}
+
+
 static const struct ethtool_ops ops = {
-	.get_drvinfo = tulip_get_drvinfo
+	.get_drvinfo = tulip_get_drvinfo,
+	.set_wol     = tulip_ethtool_set_wol,
+	.get_wol     = tulip_ethtool_get_wol,
 };
 
 /* Provide ioctl() calls to examine the MII xcvr state. */
@@ -1093,8 +1125,8 @@
 				iowrite32(3, ioaddr + CSR13);
 				iowrite32(mc_filter[1], ioaddr + CSR14);
 			} else if (tp->flags & COMET_MAC_ADDR) {
-				iowrite32(mc_filter[0], ioaddr + 0xAC);
-				iowrite32(mc_filter[1], ioaddr + 0xB0);
+				iowrite32(mc_filter[0], ioaddr + CSR27);
+				iowrite32(mc_filter[1], ioaddr + CSR28);
 			}
 			tp->mc_filter[0] = mc_filter[0];
 			tp->mc_filter[1] = mc_filter[1];
@@ -1309,6 +1341,12 @@
         if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) {
 		pr_err(PFX "skipping LMC card\n");
 		return -ENODEV;
+	} else if (pdev->subsystem_vendor == PCI_VENDOR_ID_SBE &&
+		   (pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_T3E3 ||
+		    pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_2T3E3_P0 ||
+		    pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_2T3E3_P1)) {
+		pr_err(PFX "skipping SBE T3E3 port\n");
+		return -ENODEV;
 	}
 
 	/*
@@ -1381,6 +1419,13 @@
 		return i;
 	}
 
+	/* The chip will fail to enter a low-power state later unless
+	 * first explicitly commanded into D0 */
+	if (pci_set_power_state(pdev, PCI_D0)) {
+		printk (KERN_NOTICE PFX
+			"Failed to set power state to D0\n");
+	}
+
 	irq = pdev->irq;
 
 	/* alloc_etherdev ensures aligned and zeroed private structures */
@@ -1427,6 +1472,19 @@
 
 	tp->chip_id = chip_idx;
 	tp->flags = tulip_tbl[chip_idx].flags;
+
+	tp->wolinfo.supported = 0;
+	tp->wolinfo.wolopts = 0;
+	/* COMET: Enable power management only for AN983B */
+	if (chip_idx == COMET ) {
+		u32 sig;
+		pci_read_config_dword (pdev, 0x80, &sig);
+		if (sig == 0x09811317) {
+			tp->flags |= COMET_PM;
+			tp->wolinfo.supported = WAKE_PHY | WAKE_MAGIC;
+			printk(KERN_INFO "tulip_init_one: Enabled WOL support for AN983B\n");
+		}
+	}
 	tp->pdev = pdev;
 	tp->base_addr = ioaddr;
 	tp->revision = pdev->revision;
@@ -1759,11 +1817,43 @@
 }
 
 
+/* set the registers according to the given wolopts */
+static void tulip_set_wolopts (struct pci_dev *pdev, u32 wolopts)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct tulip_private *tp = netdev_priv(dev);
+	void __iomem *ioaddr = tp->base_addr;
+
+	if (tp->flags & COMET_PM) {
+	  
+		unsigned int tmp;
+			
+		tmp = ioread32(ioaddr + CSR18);
+		tmp &= ~(comet_csr18_pmes_sticky | comet_csr18_apm_mode | comet_csr18_d3a);
+		tmp |= comet_csr18_pm_mode;
+		iowrite32(tmp, ioaddr + CSR18);
+			
+		/* Set the Wake-up Control/Status Register to the given WOL options*/
+		tmp = ioread32(ioaddr + CSR13);
+		tmp &= ~(comet_csr13_linkoffe | comet_csr13_linkone | comet_csr13_wfre | comet_csr13_lsce | comet_csr13_mpre);
+		if (wolopts & WAKE_MAGIC)
+			tmp |= comet_csr13_mpre;
+		if (wolopts & WAKE_PHY)
+			tmp |= comet_csr13_linkoffe | comet_csr13_linkone | comet_csr13_lsce;
+		/* Clear the event flags */
+		tmp |= comet_csr13_wfr | comet_csr13_mpr | comet_csr13_lsc;
+		iowrite32(tmp, ioaddr + CSR13);
+	}
+}
+
 #ifdef CONFIG_PM
 
+
 static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
 {
+	pci_power_t pstate;
 	struct net_device *dev = pci_get_drvdata(pdev);
+	struct tulip_private *tp = netdev_priv(dev);
 
 	if (!dev)
 		return -EINVAL;
@@ -1779,7 +1869,16 @@
 save_state:
 	pci_save_state(pdev);
 	pci_disable_device(pdev);
-	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+	pstate = pci_choose_state(pdev, state);
+	if (state.event == PM_EVENT_SUSPEND && pstate != PCI_D0) {
+		int rc;
+
+		tulip_set_wolopts(pdev, tp->wolinfo.wolopts);
+		rc = pci_enable_wake(pdev, pstate, tp->wolinfo.wolopts);
+		if (rc)
+			printk("tulip: pci_enable_wake failed (%d)\n", rc);
+	}
+	pci_set_power_state(pdev, pstate);
 
 	return 0;
 }
@@ -1788,7 +1887,10 @@
 static int tulip_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
+	struct tulip_private *tp = netdev_priv(dev);
+	void __iomem *ioaddr = tp->base_addr;
 	int retval;
+	unsigned int tmp;
 
 	if (!dev)
 		return -EINVAL;
@@ -1809,6 +1911,18 @@
 		return retval;
 	}
 
+	if (tp->flags & COMET_PM) {
+		pci_enable_wake(pdev, PCI_D3hot, 0);
+		pci_enable_wake(pdev, PCI_D3cold, 0);
+
+		/* Clear the PMES flag */
+		tmp = ioread32(ioaddr + CSR20);
+		tmp |= comet_csr20_pmes;
+		iowrite32(tmp, ioaddr + CSR20);
+
+		/* Disable all wake-up events */
+		tulip_set_wolopts(pdev, 0);
+	}
 	netif_device_attach(dev);
 
 	if (netif_running(dev))
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 608b279..66d41cf 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -1514,12 +1514,12 @@
 	if (debug > 2) {
 		int i;
 
-		printk(KERN_DEBUG"  Tx ring at %08x:\n", (int)np->tx_ring);
+		printk(KERN_DEBUG"  Tx ring at %p:\n", np->tx_ring);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			printk(KERN_DEBUG " #%d desc. %04x %04x %08x\n",
 			       i, np->tx_ring[i].length,
 			       np->tx_ring[i].status, np->tx_ring[i].buffer1);
-		printk(KERN_DEBUG "  Rx ring %08x:\n", (int)np->rx_ring);
+		printk(KERN_DEBUG "  Rx ring %p:\n", np->rx_ring);
 		for (i = 0; i < RX_RING_SIZE; i++) {
 			printk(KERN_DEBUG " #%d desc. %04x %04x %08x\n",
 			       i, np->rx_ring[i].length,
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 6304259..55f3a3e 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -149,6 +149,7 @@
 	tfile->tun = tun;
 	tun->tfile = tfile;
 	tun->socket.file = file;
+	netif_carrier_on(tun->dev);
 	dev_hold(tun->dev);
 	sock_hold(tun->socket.sk);
 	atomic_inc(&tfile->count);
@@ -162,6 +163,7 @@
 {
 	/* Detach from net device */
 	netif_tx_lock_bh(tun->dev);
+	netif_carrier_off(tun->dev);
 	tun->tfile = NULL;
 	tun->socket.file = NULL;
 	netif_tx_unlock_bh(tun->dev);
@@ -1574,12 +1576,6 @@
 #endif
 }
 
-static u32 tun_get_link(struct net_device *dev)
-{
-	struct tun_struct *tun = netdev_priv(dev);
-	return !!tun->tfile;
-}
-
 static u32 tun_get_rx_csum(struct net_device *dev)
 {
 	struct tun_struct *tun = netdev_priv(dev);
@@ -1601,7 +1597,7 @@
 	.get_drvinfo	= tun_get_drvinfo,
 	.get_msglevel	= tun_get_msglevel,
 	.set_msglevel	= tun_set_msglevel,
-	.get_link	= tun_get_link,
+	.get_link	= ethtool_op_get_link,
 	.get_rx_csum	= tun_get_rx_csum,
 	.set_rx_csum	= tun_set_rx_csum
 };
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 22bde49..2e50077 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -255,7 +255,7 @@
 	struct rx_free			rxBuff[RXFREE_ENTRIES]	__3xp_aligned;
 	u32				zeroWord;
 	struct tx_desc			txHi[TXHI_ENTRIES];
-} __attribute__ ((packed));
+} __packed;
 
 struct rxbuff_ent {
 	struct sk_buff *skb;
diff --git a/drivers/net/typhoon.h b/drivers/net/typhoon.h
index 673fd51..88187fc 100644
--- a/drivers/net/typhoon.h
+++ b/drivers/net/typhoon.h
@@ -77,7 +77,7 @@
 	volatile __le32 cmdCleared;
 	volatile __le32 respReady;
 	volatile __le32 rxHiReady;
-} __attribute__ ((packed));
+} __packed;
 
 /* The host<->Typhoon interface
  * Our means of communicating where things are
@@ -125,7 +125,7 @@
 	__le32 rxHiAddr;
 	__le32 rxHiAddrHi;
 	__le32 rxHiSize;
-} __attribute__ ((packed));
+} __packed;
 
 /* The Typhoon transmit/fragment descriptor
  *
@@ -187,7 +187,7 @@
 #define TYPHOON_TX_PF_VLAN_MASK		cpu_to_le32(0x0ffff000)
 #define TYPHOON_TX_PF_INTERNAL		cpu_to_le32(0xf0000000)
 #define TYPHOON_TX_PF_VLAN_TAG_SHIFT	12
-} __attribute__ ((packed));
+} __packed;
 
 /* The TCP Segmentation offload option descriptor
  *
@@ -208,7 +208,7 @@
 	__le32 respAddrLo;
 	__le32 bytesTx;
 	__le32 status;
-} __attribute__ ((packed));
+} __packed;
 
 /* The IPSEC Offload descriptor
  *
@@ -227,7 +227,7 @@
 	__le32 sa1;
 	__le32 sa2;
 	__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 /* The Typhoon receive descriptor (Updated by NIC)
  *
@@ -284,7 +284,7 @@
 #define TYPHOON_RX_UNKNOWN_SA		cpu_to_le16(0x0100)
 #define TYPHOON_RX_ESP_FORMAT_ERR	cpu_to_le16(0x0200)
 	__be32 vlanTag;
-} __attribute__ ((packed));
+} __packed;
 
 /* The Typhoon free buffer descriptor, used to give a buffer to the NIC
  *
@@ -301,7 +301,7 @@
 	__le32 physAddrHi;
 	u32 virtAddr;
 	u32 virtAddrHi;
-} __attribute__ ((packed));
+} __packed;
 
 /* The Typhoon command descriptor, used for commands and responses
  *
@@ -347,7 +347,7 @@
 	__le16 parm1;
 	__le32 parm2;
 	__le32 parm3;
-} __attribute__ ((packed));
+} __packed;
 
 /* The Typhoon response descriptor, see command descriptor for details
  */
@@ -359,7 +359,7 @@
 	__le16 parm1;
 	__le32 parm2;
 	__le32 parm3;
-} __attribute__ ((packed));
+} __packed;
 
 #define INIT_COMMAND_NO_RESPONSE(x, command)				\
 	do { struct cmd_desc *_ptr = (x);				\
@@ -427,7 +427,7 @@
 #define TYPHOON_LINK_HALF_DUPLEX	cpu_to_le32(0x00000000)
 	__le32 unused2;
 	__le32 unused3;
-} __attribute__ ((packed));
+} __packed;
 
 /* TYPHOON_CMD_XCVR_SELECT xcvr values (resp.parm1)
  */
@@ -488,7 +488,7 @@
 	u32 index;
 	u32 unused;
 	u32 unused2;
-} __attribute__ ((packed));
+} __packed;
 
 /* TYPHOON_CMD_SET_OFFLOAD_TASKS bits (cmd.parm2 (Tx) & cmd.parm3 (Rx))
  * This is all for IPv4.
@@ -518,14 +518,14 @@
 	__le32 numSections;
 	__le32 startAddr;
 	__le32 hmacDigest[5];
-} __attribute__ ((packed));
+} __packed;
 
 struct typhoon_section_header {
 	__le32 len;
 	u16 checksum;
 	u16 reserved;
 	__le32 startAddr;
-} __attribute__ ((packed));
+} __packed;
 
 /* The Typhoon Register offsets
  */
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 807470e..8d532f9 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -594,7 +594,7 @@
 {
 	int i;
 
-	ugeth_info("UCC%d Geth registers:", ugeth->ug_info->uf_info.ucc_num);
+	ugeth_info("UCC%d Geth registers:", ugeth->ug_info->uf_info.ucc_num + 1);
 	ugeth_info("Base address: 0x%08x", (u32) ugeth->ug_regs);
 
 	ugeth_info("maccfg1    : addr - 0x%08x, val - 0x%08x",
@@ -3704,6 +3704,19 @@
 	return PHY_INTERFACE_MODE_MII;
 }
 
+static int ucc_geth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(dev);
+
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	if (!ugeth->phydev)
+		return -ENODEV;
+
+	return phy_mii_ioctl(ugeth->phydev, rq, cmd);
+}
+
 static const struct net_device_ops ucc_geth_netdev_ops = {
 	.ndo_open		= ucc_geth_open,
 	.ndo_stop		= ucc_geth_close,
@@ -3713,6 +3726,7 @@
 	.ndo_change_mtu		= eth_change_mtu,
 	.ndo_set_multicast_list	= ucc_geth_set_multi,
 	.ndo_tx_timeout		= ucc_geth_timeout,
+	.ndo_do_ioctl		= ucc_geth_ioctl,
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= ucc_netpoll,
 #endif
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index ef1fbeb..05a9558 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -106,7 +106,7 @@
 	u32 scar;		/* Statistics carry register */
 	u32 scam;		/* Statistics caryy mask register */
 	u8 res5[0x200 - 0x1c4];
-} __attribute__ ((packed));
+} __packed;
 
 /* UCC GETH TEMODR Register */
 #define TEMODER_TX_RMON_STATISTICS_ENABLE       0x0100	/* enable Tx statistics
@@ -420,11 +420,11 @@
 
 struct ucc_geth_thread_data_tx {
 	u8 res0[104];
-} __attribute__ ((packed));
+} __packed;
 
 struct ucc_geth_thread_data_rx {
 	u8 res0[40];
-} __attribute__ ((packed));
+} __packed;
 
 /* Send Queue Queue-Descriptor */
 struct ucc_geth_send_queue_qd {
@@ -432,19 +432,19 @@
 	u8 res0[0x8];
 	u32 last_bd_completed_address;/* initialize to last entry in BD ring */
 	u8 res1[0x30];
-} __attribute__ ((packed));
+} __packed;
 
 struct ucc_geth_send_queue_mem_region {
 	struct ucc_geth_send_queue_qd sqqd[NUM_TX_QUEUES];
-} __attribute__ ((packed));
+} __packed;
 
 struct ucc_geth_thread_tx_pram {
 	u8 res0[64];
-} __attribute__ ((packed));
+} __packed;
 
 struct ucc_geth_thread_rx_pram {
 	u8 res0[128];
-} __attribute__ ((packed));
+} __packed;
 
 #define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING        64
 #define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8      64
@@ -484,7 +484,7 @@
 				      /**< weight factor for queues   */
 	u32 minw;		/* temporary variable handled by QE */
 	u8 res1[0x70 - 0x64];
-} __attribute__ ((packed));
+} __packed;
 
 struct ucc_geth_tx_firmware_statistics_pram {
 	u32 sicoltx;		/* single collision */
@@ -506,7 +506,7 @@
 				   and 1518 octets */
 	u32 txpktsjumbo;	/* total packets (including bad) between 1024
 				   and MAXLength octets */
-} __attribute__ ((packed));
+} __packed;
 
 struct ucc_geth_rx_firmware_statistics_pram {
 	u32 frrxfcser;		/* frames with crc error */
@@ -540,7 +540,7 @@
 				   replaced */
 	u32 insertvlan;		/* total frames that had their VLAN tag
 				   inserted */
-} __attribute__ ((packed));
+} __packed;
 
 struct ucc_geth_rx_interrupt_coalescing_entry {
 	u32 interruptcoalescingmaxvalue;	/* interrupt coalescing max
@@ -548,23 +548,23 @@
 	u32 interruptcoalescingcounter;	/* interrupt coalescing counter,
 					   initialize to
 					   interruptcoalescingmaxvalue */
-} __attribute__ ((packed));
+} __packed;
 
 struct ucc_geth_rx_interrupt_coalescing_table {
 	struct ucc_geth_rx_interrupt_coalescing_entry coalescingentry[NUM_RX_QUEUES];
 				       /**< interrupt coalescing entry */
-} __attribute__ ((packed));
+} __packed;
 
 struct ucc_geth_rx_prefetched_bds {
 	struct qe_bd bd[NUM_BDS_IN_PREFETCHED_BDS];	/* prefetched bd */
-} __attribute__ ((packed));
+} __packed;
 
 struct ucc_geth_rx_bd_queues_entry {
 	u32 bdbaseptr;		/* BD base pointer */
 	u32 bdptr;		/* BD pointer */
 	u32 externalbdbaseptr;	/* external BD base pointer */
 	u32 externalbdptr;	/* external BD pointer */
-} __attribute__ ((packed));
+} __packed;
 
 struct ucc_geth_tx_global_pram {
 	u16 temoder;
@@ -580,13 +580,13 @@
 	u32 tqptr;		/* a base pointer to the Tx Queues Memory
 				   Region */
 	u8 res2[0x80 - 0x74];
-} __attribute__ ((packed));
+} __packed;
 
 /* structure representing Extended Filtering Global Parameters in PRAM */
 struct ucc_geth_exf_global_pram {
 	u32 l2pcdptr;		/* individual address filter, high */
 	u8 res0[0x10 - 0x04];
-} __attribute__ ((packed));
+} __packed;
 
 struct ucc_geth_rx_global_pram {
 	u32 remoder;		/* ethernet mode reg. */
@@ -620,7 +620,7 @@
 	u32 exfGlobalParam;	/* base address for extended filtering global
 				   parameters */
 	u8 res6[0x100 - 0xC4];	/* Initialize to zero */
-} __attribute__ ((packed));
+} __packed;
 
 #define GRACEFUL_STOP_ACKNOWLEDGE_RX            0x01
 
@@ -639,7 +639,7 @@
 	u32 txglobal;		/* tx global */
 	u32 txthread[ENET_INIT_PARAM_MAX_ENTRIES_TX];	/* tx threads */
 	u8 res3[0x1];
-} __attribute__ ((packed));
+} __packed;
 
 #define ENET_INIT_PARAM_RGF_SHIFT               (32 - 4)
 #define ENET_INIT_PARAM_TGF_SHIFT               (32 - 8)
@@ -661,7 +661,7 @@
 	u16 h;			/* address (MSB) */
 	u16 m;			/* address */
 	u16 l;			/* address (LSB) */
-} __attribute__ ((packed));
+} __packed;
 
 /* structure representing 82xx Address Filtering PRAM */
 struct ucc_geth_82xx_address_filtering_pram {
@@ -672,7 +672,7 @@
 	struct ucc_geth_82xx_enet_address __iomem taddr;
 	struct ucc_geth_82xx_enet_address __iomem paddr[NUM_OF_PADDRS];
 	u8 res0[0x40 - 0x38];
-} __attribute__ ((packed));
+} __packed;
 
 /* GETH Tx firmware statistics structure, used when calling
    UCC_GETH_GetStatistics. */
@@ -696,7 +696,7 @@
 				   and 1518 octets */
 	u32 txpktsjumbo;	/* total packets (including bad) between 1024
 				   and MAXLength octets */
-} __attribute__ ((packed));
+} __packed;
 
 /* GETH Rx firmware statistics structure, used when calling
    UCC_GETH_GetStatistics. */
@@ -732,7 +732,7 @@
 				   replaced */
 	u32 insertvlan;		/* total frames that had their VLAN tag
 				   inserted */
-} __attribute__ ((packed));
+} __packed;
 
 /* GETH hardware statistics structure, used when calling
    UCC_GETH_GetStatistics. */
@@ -781,7 +781,7 @@
 	u32 rbca;		/* Total number of frames received successfully
 				   that had destination address equal to the
 				   broadcast address */
-} __attribute__ ((packed));
+} __packed;
 
 /* UCC GETH Tx errors returned via TxConf callback */
 #define TX_ERRORS_DEF      0x0200
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 9516f38..aea4645 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -179,7 +179,7 @@
 	__le16 res2;
 	u8 status;
 	__le16 res3;
-} __attribute__ ((packed));
+} __packed;
 
 static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
 			    u16 size, void *data)
diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c
index dc94445..109751b 100644
--- a/drivers/net/usb/cdc-phonet.c
+++ b/drivers/net/usb/cdc-phonet.c
@@ -97,8 +97,9 @@
 	struct sk_buff *skb = req->context;
 	struct net_device *dev = skb->dev;
 	struct usbpn_dev *pnd = netdev_priv(dev);
+	int status = req->status;
 
-	switch (req->status) {
+	switch (status) {
 	case 0:
 		dev->stats.tx_bytes += skb->len;
 		break;
@@ -109,7 +110,7 @@
 		dev->stats.tx_aborted_errors++;
 	default:
 		dev->stats.tx_errors++;
-		dev_dbg(&dev->dev, "TX error (%d)\n", req->status);
+		dev_dbg(&dev->dev, "TX error (%d)\n", status);
 	}
 	dev->stats.tx_packets++;
 
@@ -150,8 +151,9 @@
 	struct page *page = virt_to_page(req->transfer_buffer);
 	struct sk_buff *skb;
 	unsigned long flags;
+	int status = req->status;
 
-	switch (req->status) {
+	switch (status) {
 	case 0:
 		spin_lock_irqsave(&pnd->rx_lock, flags);
 		skb = pnd->rx_skb;
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 4dd2351..6efca66 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -73,7 +73,6 @@
 #include <linux/serial.h>
 
 
-#define DRIVER_VERSION			"1.2"
 #define MOD_AUTHOR			"Option Wireless"
 #define MOD_DESCRIPTION			"USB High Speed Option driver"
 #define MOD_LICENSE			"GPL"
@@ -211,7 +210,7 @@
 	u16 wIndex;
 	u16 wLength;
 	u16 UART_state_bitmap;
-} __attribute__((packed));
+} __packed;
 
 struct hso_tiocmget {
 	struct mutex mutex;
@@ -401,7 +400,7 @@
 /* driver info */
 static const char driver_name[] = "hso";
 static const char tty_filename[] = "ttyHS";
-static const char *version = __FILE__ ": " DRIVER_VERSION " " MOD_AUTHOR;
+static const char *version = __FILE__ ": " MOD_AUTHOR;
 /* the usb driver itself (registered in hso_init) */
 static struct usb_driver hso_driver;
 /* serial structures */
@@ -478,6 +477,7 @@
 	{USB_DEVICE(0x0af0, 0x8600)},
 	{USB_DEVICE(0x0af0, 0x8800)},
 	{USB_DEVICE(0x0af0, 0x8900)},
+	{USB_DEVICE(0x0af0, 0x9000)},
 	{USB_DEVICE(0x0af0, 0xd035)},
 	{USB_DEVICE(0x0af0, 0xd055)},
 	{USB_DEVICE(0x0af0, 0xd155)},
@@ -848,7 +848,6 @@
 	struct hso_net *odev = netdev_priv(net);
 
 	strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
-	strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
 	usb_make_path(odev->parent->usb, info->bus_info, sizeof info->bus_info);
 }
 
@@ -3388,7 +3387,6 @@
 MODULE_AUTHOR(MOD_AUTHOR);
 MODULE_DESCRIPTION(MOD_DESCRIPTION);
 MODULE_LICENSE(MOD_LICENSE);
-MODULE_INFO(Version, DRIVER_VERSION);
 
 /* change the debug level (eg: insmod hso.ko debug=0x04) */
 MODULE_PARM_DESC(debug, "Level of debug [0x01 | 0x02 | 0x04 | 0x08 | 0x10]");
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
index 197c352..08e7b6a 100644
--- a/drivers/net/usb/ipheth.c
+++ b/drivers/net/usb/ipheth.c
@@ -193,7 +193,7 @@
 	case 0:
 		break;
 	default:
-		err("%s: urb status: %d", __func__, urb->status);
+		err("%s: urb status: %d", __func__, status);
 		return;
 	}
 
@@ -222,16 +222,17 @@
 static void ipheth_sndbulk_callback(struct urb *urb)
 {
 	struct ipheth_device *dev;
+	int status = urb->status;
 
 	dev = urb->context;
 	if (dev == NULL)
 		return;
 
-	if (urb->status != 0 &&
-	    urb->status != -ENOENT &&
-	    urb->status != -ECONNRESET &&
-	    urb->status != -ESHUTDOWN)
-		err("%s: urb status: %d", __func__, urb->status);
+	if (status != 0 &&
+	    status != -ENOENT &&
+	    status != -ECONNRESET &&
+	    status != -ESHUTDOWN)
+		err("%s: urb status: %d", __func__, status);
 
 	dev_kfree_skb_irq(dev->tx_skb);
 	netif_wake_queue(dev->net);
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index d6078b8..2b7b39c 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -207,7 +207,7 @@
 	__le16 segment_size;
 	__u16 max_multicast_filters;
 	__u8 reserved3;
-} __attribute__ ((packed));
+} __packed;
 
 /****************************************************************
  *     kaweth_device
diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c
index 961a8ed..ba72a72 100644
--- a/drivers/net/usb/net1080.c
+++ b/drivers/net/usb/net1080.c
@@ -64,13 +64,13 @@
 	// all else is optional, and must start with:
 	// __le16	vendorId;	// from usb-if
 	// __le16	productId;
-} __attribute__((__packed__));
+} __packed;
 
 #define	PAD_BYTE	((unsigned char)0xAC)
 
 struct nc_trailer {
 	__le16	packet_id;
-} __attribute__((__packed__));
+} __packed;
 
 // packets may use FLAG_FRAMING_NC and optional pad
 #define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 974d17f..6710f09 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -21,11 +21,11 @@
  *			behaves. Pegasus II support added since this version.
  *			TODO: suppressing HCD warnings spewage on disconnect.
  *		v0.4.13	Ethernet address is now set at probe(), not at open()
- *			time as this seems to break dhcpd. 
+ *			time as this seems to break dhcpd.
  *		v0.5.0	branch to 2.5.x kernels
  *		v0.5.1	ethtool support added
  *		v0.5.5	rx socket buffers are in a pool and the their allocation
- * 			is out of the interrupt routine.
+ *			is out of the interrupt routine.
  */
 
 #include <linux/sched.h>
@@ -55,9 +55,9 @@
 #define	BMSR_MEDIA	(BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
 			BMSR_100FULL | BMSR_ANEGCAPABLE)
 
-static int loopback = 0;
-static int mii_mode = 0;
-static char *devid=NULL;
+static int loopback;
+static int mii_mode;
+static char *devid;
 
 static struct usb_eth_dev usb_dev_id[] = {
 #define	PEGASUS_DEV(pn, vid, pid, flags)	\
@@ -102,8 +102,8 @@
 
 /* use ethtool to change the level for any given device */
 static int msg_level = -1;
-module_param (msg_level, int, 0);
-MODULE_PARM_DESC (msg_level, "Override default message level");
+module_param(msg_level, int, 0);
+MODULE_PARM_DESC(msg_level, "Override default message level");
 
 MODULE_DEVICE_TABLE(usb, pegasus_ids);
 static const struct net_device_ops pegasus_netdev_ops;
@@ -141,7 +141,7 @@
 	wake_up(&pegasus->ctrl_wait);
 }
 
-static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
+static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size,
 			 void *data)
 {
 	int ret;
@@ -196,7 +196,7 @@
 	return ret;
 }
 
-static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
+static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size,
 			 void *data)
 {
 	int ret;
@@ -248,7 +248,7 @@
 	return ret;
 }
 
-static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
+static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data)
 {
 	int ret;
 	char *tmp;
@@ -299,7 +299,7 @@
 	return ret;
 }
 
-static int update_eth_regs_async(pegasus_t * pegasus)
+static int update_eth_regs_async(pegasus_t *pegasus)
 {
 	int ret;
 
@@ -326,7 +326,7 @@
 }
 
 /* Returns 0 on success, error on failure */
-static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
+static int read_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd)
 {
 	int i;
 	__u8 data[4] = { phy, 0, 0, indx };
@@ -334,7 +334,7 @@
 	int ret;
 
 	set_register(pegasus, PhyCtrl, 0);
-	set_registers(pegasus, PhyAddr, sizeof (data), data);
+	set_registers(pegasus, PhyAddr, sizeof(data), data);
 	set_register(pegasus, PhyCtrl, (indx | PHY_READ));
 	for (i = 0; i < REG_TIMEOUT; i++) {
 		ret = get_registers(pegasus, PhyCtrl, 1, data);
@@ -366,7 +366,7 @@
 	return (int)res;
 }
 
-static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
+static int write_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd)
 {
 	int i;
 	__u8 data[4] = { phy, 0, 0, indx };
@@ -402,7 +402,7 @@
 	write_mii_word(pegasus, phy_id, loc, val);
 }
 
-static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata)
+static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata)
 {
 	int i;
 	__u8 tmp;
@@ -433,7 +433,7 @@
 }
 
 #ifdef	PEGASUS_WRITE_EEPROM
-static inline void enable_eprom_write(pegasus_t * pegasus)
+static inline void enable_eprom_write(pegasus_t *pegasus)
 {
 	__u8 tmp;
 	int ret;
@@ -442,7 +442,7 @@
 	set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE);
 }
 
-static inline void disable_eprom_write(pegasus_t * pegasus)
+static inline void disable_eprom_write(pegasus_t *pegasus)
 {
 	__u8 tmp;
 	int ret;
@@ -452,7 +452,7 @@
 	set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE);
 }
 
-static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data)
+static int write_eprom_word(pegasus_t *pegasus, __u8 index, __u16 data)
 {
 	int i;
 	__u8 tmp, d[4] = { 0x3f, 0, 0, EPROM_WRITE };
@@ -484,7 +484,7 @@
 }
 #endif				/* PEGASUS_WRITE_EEPROM */
 
-static inline void get_node_id(pegasus_t * pegasus, __u8 * id)
+static inline void get_node_id(pegasus_t *pegasus, __u8 *id)
 {
 	int i;
 	__u16 w16;
@@ -495,7 +495,7 @@
 	}
 }
 
-static void set_ethernet_addr(pegasus_t * pegasus)
+static void set_ethernet_addr(pegasus_t *pegasus)
 {
 	__u8 node_id[6];
 
@@ -503,12 +503,12 @@
 		get_registers(pegasus, 0x10, sizeof(node_id), node_id);
 	} else {
 		get_node_id(pegasus, node_id);
-		set_registers(pegasus, EthID, sizeof (node_id), node_id);
+		set_registers(pegasus, EthID, sizeof(node_id), node_id);
 	}
-	memcpy(pegasus->net->dev_addr, node_id, sizeof (node_id));
+	memcpy(pegasus->net->dev_addr, node_id, sizeof(node_id));
 }
 
-static inline int reset_mac(pegasus_t * pegasus)
+static inline int reset_mac(pegasus_t *pegasus)
 {
 	__u8 data = 0x8;
 	int i;
@@ -563,7 +563,7 @@
 		data[1] = 0;
 	data[2] = (loopback & 1) ? 0x09 : 0x01;
 
-	memcpy(pegasus->eth_regs, data, sizeof (data));
+	memcpy(pegasus->eth_regs, data, sizeof(data));
 	ret = set_registers(pegasus, EthCtrl0, 3, data);
 
 	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
@@ -577,7 +577,7 @@
 	return ret;
 }
 
-static void fill_skb_pool(pegasus_t * pegasus)
+static void fill_skb_pool(pegasus_t *pegasus)
 {
 	int i;
 
@@ -595,7 +595,7 @@
 	}
 }
 
-static void free_skb_pool(pegasus_t * pegasus)
+static void free_skb_pool(pegasus_t *pegasus)
 {
 	int i;
 
@@ -667,11 +667,11 @@
 		netif_dbg(pegasus, rx_err, net,
 			  "RX packet error %x\n", rx_status);
 		pegasus->stats.rx_errors++;
-		if (rx_status & 0x06)	// long or runt
+		if (rx_status & 0x06)	/* long or runt	*/
 			pegasus->stats.rx_length_errors++;
 		if (rx_status & 0x08)
 			pegasus->stats.rx_crc_errors++;
-		if (rx_status & 0x10)	// extra bits
+		if (rx_status & 0x10)	/* extra bits	*/
 			pegasus->stats.rx_frame_errors++;
 		goto goon;
 	}
@@ -748,9 +748,8 @@
 	if (pegasus->flags & PEGASUS_RX_URB_FAIL)
 		if (pegasus->rx_skb)
 			goto try_again;
-	if (pegasus->rx_skb == NULL) {
+	if (pegasus->rx_skb == NULL)
 		pegasus->rx_skb = pull_skb(pegasus);
-	}
 	if (pegasus->rx_skb == NULL) {
 		netif_warn(pegasus, rx_err, pegasus->net, "low on memory\n");
 		tasklet_schedule(&pegasus->rx_tl);
@@ -835,7 +834,7 @@
 	}
 
 	if (urb->actual_length >= 6) {
-		u8	* d = urb->transfer_buffer;
+		u8 *d = urb->transfer_buffer;
 
 		/* byte 0 == tx_status1, reg 2B */
 		if (d[0] & (TX_UNDERRUN|EXCESSIVE_COL
@@ -918,14 +917,14 @@
 	return &((pegasus_t *) netdev_priv(dev))->stats;
 }
 
-static inline void disable_net_traffic(pegasus_t * pegasus)
+static inline void disable_net_traffic(pegasus_t *pegasus)
 {
 	__le16 tmp = cpu_to_le16(0);
 
 	set_registers(pegasus, EthCtrl0, sizeof(tmp), &tmp);
 }
 
-static inline void get_interrupt_interval(pegasus_t * pegasus)
+static inline void get_interrupt_interval(pegasus_t *pegasus)
 {
 	u16 data;
 	u8 interval;
@@ -961,7 +960,7 @@
 		netif_carrier_off(net);
 }
 
-static void free_all_urbs(pegasus_t * pegasus)
+static void free_all_urbs(pegasus_t *pegasus)
 {
 	usb_free_urb(pegasus->intr_urb);
 	usb_free_urb(pegasus->tx_urb);
@@ -969,7 +968,7 @@
 	usb_free_urb(pegasus->ctrl_urb);
 }
 
-static void unlink_all_urbs(pegasus_t * pegasus)
+static void unlink_all_urbs(pegasus_t *pegasus)
 {
 	usb_kill_urb(pegasus->intr_urb);
 	usb_kill_urb(pegasus->tx_urb);
@@ -977,12 +976,11 @@
 	usb_kill_urb(pegasus->ctrl_urb);
 }
 
-static int alloc_urbs(pegasus_t * pegasus)
+static int alloc_urbs(pegasus_t *pegasus)
 {
 	pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!pegasus->ctrl_urb) {
+	if (!pegasus->ctrl_urb)
 		return 0;
-	}
 	pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!pegasus->rx_urb) {
 		usb_free_urb(pegasus->ctrl_urb);
@@ -1019,7 +1017,7 @@
 		return -ENOMEM;
 
 	res = set_registers(pegasus, EthID, 6, net->dev_addr);
-	
+
 	usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
 			  usb_rcvbulkpipe(pegasus->usb, 1),
 			  pegasus->rx_skb->data, PEGASUS_MTU + 8,
@@ -1033,7 +1031,7 @@
 
 	usb_fill_int_urb(pegasus->intr_urb, pegasus->usb,
 			 usb_rcvintpipe(pegasus->usb, 3),
-			 pegasus->intr_buff, sizeof (pegasus->intr_buff),
+			 pegasus->intr_buff, sizeof(pegasus->intr_buff),
 			 intr_callback, pegasus, pegasus->intr_interval);
 	if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) {
 		if (res == -ENODEV)
@@ -1076,9 +1074,9 @@
 				struct ethtool_drvinfo *info)
 {
 	pegasus_t *pegasus = netdev_priv(dev);
-	strncpy(info->driver, driver_name, sizeof (info->driver) - 1);
-	strncpy(info->version, DRIVER_VERSION, sizeof (info->version) - 1);
-	usb_make_path(pegasus->usb, info->bus_info, sizeof (info->bus_info));
+	strncpy(info->driver, driver_name, sizeof(info->driver) - 1);
+	strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
+	usb_make_path(pegasus->usb, info->bus_info, sizeof(info->bus_info));
 }
 
 /* also handles three patterns of some kind in hardware */
@@ -1098,7 +1096,7 @@
 {
 	pegasus_t	*pegasus = netdev_priv(dev);
 	u8		reg78 = 0x04;
-	
+
 	if (wol->wolopts & ~WOL_SUPPORTED)
 		return -EINVAL;
 
@@ -1118,7 +1116,7 @@
 static inline void pegasus_reset_wol(struct net_device *dev)
 {
 	struct ethtool_wolinfo wol;
-	
+
 	memset(&wol, 0, sizeof wol);
 	(void) pegasus_set_wol(dev, &wol);
 }
@@ -1178,7 +1176,7 @@
 
 static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
 {
-	__u16 *data = (__u16 *) & rq->ifr_ifru;
+	__u16 *data = (__u16 *) &rq->ifr_ifru;
 	pegasus_t *pegasus = netdev_priv(net);
 	int res;
 
@@ -1223,7 +1221,7 @@
 	ctrl_callback(pegasus->ctrl_urb);
 }
 
-static __u8 mii_phy_probe(pegasus_t * pegasus)
+static __u8 mii_phy_probe(pegasus_t *pegasus)
 {
 	int i;
 	__u16 tmp;
@@ -1239,10 +1237,10 @@
 	return 0xff;
 }
 
-static inline void setup_pegasus_II(pegasus_t * pegasus)
+static inline void setup_pegasus_II(pegasus_t *pegasus)
 {
 	__u8 data = 0xa5;
-	
+
 	set_register(pegasus, Reg1d, 0);
 	set_register(pegasus, Reg7b, 1);
 	mdelay(100);
@@ -1254,16 +1252,15 @@
 	set_register(pegasus, 0x83, data);
 	get_registers(pegasus, 0x83, 1, &data);
 
-	if (data == 0xa5) {
+	if (data == 0xa5)
 		pegasus->chip = 0x8513;
-	} else {
+	else
 		pegasus->chip = 0;
-	}
 
 	set_register(pegasus, 0x80, 0xc0);
 	set_register(pegasus, 0x83, 0xff);
 	set_register(pegasus, 0x84, 0x01);
-	
+
 	if (pegasus->features & HAS_HOME_PNA && mii_mode)
 		set_register(pegasus, Reg81, 6);
 	else
@@ -1272,7 +1269,7 @@
 
 
 static int pegasus_count;
-static struct workqueue_struct *pegasus_workqueue = NULL;
+static struct workqueue_struct *pegasus_workqueue;
 #define CARRIER_CHECK_DELAY (2 * HZ)
 
 static void check_carrier(struct work_struct *work)
@@ -1367,7 +1364,7 @@
 	pegasus->mii.phy_id_mask = 0x1f;
 	pegasus->mii.reg_num_mask = 0x1f;
 	spin_lock_init(&pegasus->rx_pool_lock);
-	pegasus->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
+	pegasus->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV
 				| NETIF_MSG_PROBE | NETIF_MSG_LINK);
 
 	pegasus->features = usb_dev_id[dev_index].private;
@@ -1442,11 +1439,11 @@
 	pegasus_dec_workqueue();
 }
 
-static int pegasus_suspend (struct usb_interface *intf, pm_message_t message)
+static int pegasus_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct pegasus *pegasus = usb_get_intfdata(intf);
-	
-	netif_device_detach (pegasus->net);
+
+	netif_device_detach(pegasus->net);
 	cancel_delayed_work(&pegasus->carrier_check);
 	if (netif_running(pegasus->net)) {
 		usb_kill_urb(pegasus->rx_urb);
@@ -1455,11 +1452,11 @@
 	return 0;
 }
 
-static int pegasus_resume (struct usb_interface *intf)
+static int pegasus_resume(struct usb_interface *intf)
 {
 	struct pegasus *pegasus = usb_get_intfdata(intf);
 
-	netif_device_attach (pegasus->net);
+	netif_device_attach(pegasus->net);
 	if (netif_running(pegasus->net)) {
 		pegasus->rx_urb->status = 0;
 		pegasus->rx_urb->actual_length = 0;
@@ -1498,8 +1495,8 @@
 
 static void __init parse_id(char *id)
 {
-	unsigned int vendor_id=0, device_id=0, flags=0, i=0;
-	char *token, *name=NULL;
+	unsigned int vendor_id = 0, device_id = 0, flags = 0, i = 0;
+	char *token, *name = NULL;
 
 	if ((token = strsep(&id, ":")) != NULL)
 		name = token;
@@ -1510,14 +1507,14 @@
 		device_id = simple_strtoul(token, NULL, 16);
 	flags = simple_strtoul(id, NULL, 16);
 	pr_info("%s: new device %s, vendor ID 0x%04x, device ID 0x%04x, flags: 0x%x\n",
-	        driver_name, name, vendor_id, device_id, flags);
+		driver_name, name, vendor_id, device_id, flags);
 
 	if (vendor_id > 0x10000 || vendor_id == 0)
 		return;
 	if (device_id > 0x10000 || device_id == 0)
 		return;
 
-	for (i=0; usb_dev_id[i].name; i++);
+	for (i = 0; usb_dev_id[i].name; i++);
 	usb_dev_id[i].name = name;
 	usb_dev_id[i].vendor = vendor_id;
 	usb_dev_id[i].device = device_id;
diff --git a/drivers/net/usb/pegasus.h b/drivers/net/usb/pegasus.h
index 29f5211..65b78b3 100644
--- a/drivers/net/usb/pegasus.h
+++ b/drivers/net/usb/pegasus.h
@@ -68,7 +68,7 @@
 	EpromData = 0x21,	/* 0x21 low, 0x22 high byte */
 	EpromCtrl = 0x23,
 	PhyAddr = 0x25,
-	PhyData = 0x26, 	/* 0x26 low, 0x27 high byte */
+	PhyData = 0x26,		/* 0x26 low, 0x27 high byte */
 	PhyCtrl = 0x28,
 	UsbStst = 0x2a,
 	EthTxStat0 = 0x2b,
@@ -154,162 +154,162 @@
 
 #else	/* PEGASUS_DEV */
 
-PEGASUS_DEV( "3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "ATEN USB Ethernet UC-110T", VENDOR_ATEN, 0x2007,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c,
-		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
-PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104,
-		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4004,
-		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4007,
-		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4102,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4002,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400b,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Philips USB 10/100 Ethernet", VENDOR_ACCTON, 0xb004,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
+PEGASUS_DEV("3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("ATEN USB Ethernet UC-110T", VENDOR_ATEN, 0x2007,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c,
+		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA)
+PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104,
+		DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4004,
+		DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4007,
+		DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4102,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4002,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400b,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Philips USB 10/100 Ethernet", VENDOR_ACCTON, 0xb004,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
 		VENDOR_ADMTEK, 0x8511,
-		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
-PEGASUS_DEV( "ADMtek ADM8513 \"Pegasus II\" USB Ethernet",
+		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA)
+PEGASUS_DEV("ADMtek ADM8513 \"Pegasus II\" USB Ethernet",
 		VENDOR_ADMTEK, 0x8513,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "ADMtek ADM8515 \"Pegasus II\" USB-2.0 Ethernet",
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("ADMtek ADM8515 \"Pegasus II\" USB-2.0 Ethernet",
 		VENDOR_ADMTEK, 0x8515,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)",
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)",
 		VENDOR_ADMTEK, 0x0986,
-		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "AN986A USB MAC", VENDOR_ADMTEK, 1986,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "AEI USB Fast Ethernet Adapter", VENDOR_AEILAB, 0x1701,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
+		DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("AN986A USB MAC", VENDOR_ADMTEK, 1986,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("AEI USB Fast Ethernet Adapter", VENDOR_AEILAB, 0x1701,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
 /*
  * Distinguish between this Belkin adaptor and the Belkin bluetooth adaptors
  * with the same product IDs by checking the device class too.
  */
-PEGASUS_DEV_CLASS( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, 0x00,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Belkin F5U122 10/100 USB Ethernet", VENDOR_BELKIN, 0x0122,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987,
-		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "iPAQ Networking 10/100 USB", VENDOR_COMPAQ, 0x8511,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Corega FEther USB-TX", VENDOR_COREGA, 0x0004,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Corega FEther USB-TXS", VENDOR_COREGA, 0x000d,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4002,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4102,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x400b,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x200c,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003,
-		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002,
-		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
-PEGASUS_DEV( "ELECOM USB Ethernet LD-USB20", VENDOR_ELECOM,  0x4010,
-		DEFAULT_GPIO_RESET  | PEGASUS_II )
-PEGASUS_DEV( "EasiDock Ethernet", VENDOR_MOBILITY, 0x0304,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "HP hn210c Ethernet USB", VENDOR_HP, 0x811c,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "IO DATA USB ETX-US2", VENDOR_IODATA, 0x093a,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a,
+PEGASUS_DEV_CLASS("Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, 0x00,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Belkin F5U122 10/100 USB Ethernet", VENDOR_BELKIN, 0x0122,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
 		DEFAULT_GPIO_RESET)
-PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005,
+PEGASUS_DEV("Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987,
+		DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("iPAQ Networking 10/100 USB", VENDOR_COMPAQ, 0x8511,
 		DEFAULT_GPIO_RESET | PEGASUS_II)
-PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2204,
-		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "Linksys USB10T Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
+PEGASUS_DEV("Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
 		DEFAULT_GPIO_RESET | PEGASUS_II)
-PEGASUS_DEV( "Linksys USBVPN1", VENDOR_LINKSYS2, 0x08b4,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Linksys USB USB100TX", VENDOR_LINKSYS, 0x400b,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x200c,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Microsoft MN-110", VENDOR_MICROSOFT, 0x007a,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "OCT USB TO Ethernet", VENDOR_OCT, 0x0901,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201,
+PEGASUS_DEV("Corega FEther USB-TX", VENDOR_COREGA, 0x0004,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Corega FEther USB-TXS", VENDOR_COREGA, 0x000d,
 		DEFAULT_GPIO_RESET | PEGASUS_II)
-PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x4002,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x4102,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x400b,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x200c,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003,
+		DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("D-Link DSB-650", VENDOR_DLINK, 0xabc1,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002,
+		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA)
+PEGASUS_DEV("ELECOM USB Ethernet LD-USB20", VENDOR_ELECOM,  0x4010,
+		DEFAULT_GPIO_RESET  | PEGASUS_II)
+PEGASUS_DEV("EasiDock Ethernet", VENDOR_MOBILITY, 0x0304,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("HP hn210c Ethernet USB", VENDOR_HP, 0x811c,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("IO DATA USB ETX-US2", VENDOR_IODATA, 0x093a,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Linksys USB100TX", VENDOR_LINKSYS, 0x2204,
+		DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("Linksys USB10T Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Linksys USBVPN1", VENDOR_LINKSYS2, 0x08b4,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Linksys USB USB100TX", VENDOR_LINKSYS, 0x400b,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Linksys USB10TX", VENDOR_LINKSYS, 0x200c,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Microsoft MN-110", VENDOR_MICROSOFT, 0x007a,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("NETGEAR FA101", VENDOR_NETGEAR, 0x1020,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("OCT Inc.", VENDOR_OCT, 0x0109,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("OCT USB TO Ethernet", VENDOR_OCT, 0x0901,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
+		DEFAULT_GPIO_RESET)
+PEGASUS_DEV("SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
 
 
 #endif	/* PEGASUS_DEV */
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index f1942d6..ee85c8b 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -165,7 +165,7 @@
 	u8 gw_addr_len; /* NW-supplied GW address len */
 	u8 gw_addr[16]; /* NW-supplied GW address (bigendian) */
 	u8 reserved[8];
-} __attribute__ ((packed));
+} __packed;
 
 #define SIERRA_NET_LSI_COMMON_LEN      4
 #define SIERRA_NET_LSI_UMTS_LEN        (sizeof(struct lsi_umts))
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 81c76ad..3b03794 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -44,6 +44,7 @@
 #include <linux/usb.h>
 #include <linux/usb/usbnet.h>
 #include <linux/slab.h>
+#include <linux/kernel.h>
 
 #define DRIVER_VERSION		"22-Aug-2005"
 
@@ -158,16 +159,6 @@
 }
 EXPORT_SYMBOL_GPL(usbnet_get_endpoints);
 
-static u8 nibble(unsigned char c)
-{
-	if (likely(isdigit(c)))
-		return c - '0';
-	c = toupper(c);
-	if (likely(isxdigit(c)))
-		return 10 + c - 'A';
-	return 0;
-}
-
 int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress)
 {
 	int 		tmp, i;
@@ -183,7 +174,7 @@
 	}
 	for (i = tmp = 0; i < 6; i++, tmp += 2)
 		dev->net->dev_addr [i] =
-			(nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]);
+			(hex_to_bin(buf[tmp]) << 4) + hex_to_bin(buf[tmp + 1]);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr);
@@ -624,7 +615,7 @@
 	while (!skb_queue_empty(&dev->rxq)
 		&& !skb_queue_empty(&dev->txq)
 		&& !skb_queue_empty(&dev->done)) {
-			schedule_timeout(UNLINK_TIMEOUT_MS);
+			schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS));
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			netif_dbg(dev, ifdown, dev->net,
 				  "waited for %d urb completions\n", temp);
@@ -643,7 +634,7 @@
 	netif_stop_queue (net);
 
 	netif_info(dev, ifdown, dev->net,
-		   "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
+		   "stop stats: rx/tx %lu/%lu, errs %lu/%lu\n",
 		   net->stats.rx_packets, net->stats.tx_packets,
 		   net->stats.rx_errors, net->stats.tx_errors);
 
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index c381911..f7b33ae 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -193,7 +193,7 @@
 	__le32 pa_low;		/* Low 32 bit PCI address */
 	__le16 pa_high;		/* Next 16 bit PCI address (48 total) */
 	__le16 size;		/* bits 0--14 - frame size, bit 15 - enable int. */
-} __attribute__ ((__packed__));
+} __packed;
 
 /*
  *	Transmit descriptor
@@ -208,7 +208,7 @@
 	__le16 vlan;
 	u8 TCR;
 	u8 cmd;			/* bits 0--1 - TCPLS, bits 4--7 - CMDZ */
-} __attribute__ ((__packed__));
+} __packed;
 
 enum {
 	TD_QUEUE = cpu_to_le16(0x8000)
@@ -218,7 +218,7 @@
 	__le32 pa_low;
 	__le16 pa_high;
 	__le16 size;		/* bits 0--13 - size, bit 15 - queue */
-} __attribute__ ((__packed__));
+} __packed;
 
 struct tx_desc {
 	struct tdesc0 tdesc0;
@@ -1096,7 +1096,7 @@
 
 	volatile __le16 PatternCRC[8];	/* 0xB0 */
 	volatile __le32 ByteMask[4][4];	/* 0xC0 */
-} __attribute__ ((__packed__));
+} __packed;
 
 
 enum hw_mib {
@@ -1216,7 +1216,7 @@
 	u8 ar_sip[4];
 	u8 ar_tha[ETH_ALEN];
 	u8 ar_tip[4];
-} __attribute__ ((__packed__));
+} __packed;
 
 struct _magic_packet {
 	u8 dest_mac[6];
@@ -1224,7 +1224,7 @@
 	__be16 type;
 	u8 MAC[16][6];
 	u8 password[6];
-} __attribute__ ((__packed__));
+} __packed;
 
 /*
  *	Store for chip context when saving and restoring status. Not
diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h
index b4889e6..ca7727b 100644
--- a/drivers/net/vmxnet3/vmxnet3_defs.h
+++ b/drivers/net/vmxnet3/vmxnet3_defs.h
@@ -464,6 +464,9 @@
 /* addition 1 for events */
 #define VMXNET3_MAX_INTRS      25
 
+/* value of intrCtrl */
+#define VMXNET3_IC_DISABLE_ALL  0x1   /* bit 0 */
+
 
 struct Vmxnet3_IntrConf {
 	bool		autoMask;
@@ -471,7 +474,8 @@
 	u8		eventIntrIdx;
 	u8		modLevels[VMXNET3_MAX_INTRS];	/* moderation level for
 							 * each intr */
-	__le32		reserved[3];
+	__le32		intrCtrl;
+	__le32		reserved[2];
 };
 
 /* one bit per VLAN ID, the size is in the units of u32	*/
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 989b742..abe0ff5 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -72,6 +72,8 @@
 
 	for (i = 0; i < adapter->intr.num_intrs; i++)
 		vmxnet3_enable_intr(adapter, i);
+	adapter->shared->devRead.intrConf.intrCtrl &=
+					cpu_to_le32(~VMXNET3_IC_DISABLE_ALL);
 }
 
 
@@ -80,6 +82,8 @@
 {
 	int i;
 
+	adapter->shared->devRead.intrConf.intrCtrl |=
+					cpu_to_le32(VMXNET3_IC_DISABLE_ALL);
 	for (i = 0; i < adapter->intr.num_intrs; i++)
 		vmxnet3_disable_intr(adapter, i);
 }
@@ -128,7 +132,7 @@
  * Check the link state. This may start or stop the tx queue.
  */
 static void
-vmxnet3_check_link(struct vmxnet3_adapter *adapter)
+vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
 {
 	u32 ret;
 
@@ -141,14 +145,16 @@
 		if (!netif_carrier_ok(adapter->netdev))
 			netif_carrier_on(adapter->netdev);
 
-		vmxnet3_tq_start(&adapter->tx_queue, adapter);
+		if (affectTxQueue)
+			vmxnet3_tq_start(&adapter->tx_queue, adapter);
 	} else {
 		printk(KERN_INFO "%s: NIC Link is Down\n",
 		       adapter->netdev->name);
 		if (netif_carrier_ok(adapter->netdev))
 			netif_carrier_off(adapter->netdev);
 
-		vmxnet3_tq_stop(&adapter->tx_queue, adapter);
+		if (affectTxQueue)
+			vmxnet3_tq_stop(&adapter->tx_queue, adapter);
 	}
 }
 
@@ -163,7 +169,7 @@
 
 	/* Check if link state has changed */
 	if (events & VMXNET3_ECR_LINK)
-		vmxnet3_check_link(adapter);
+		vmxnet3_check_link(adapter, true);
 
 	/* Check if there is an error on xmit/recv queues */
 	if (events & (VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR)) {
@@ -658,8 +664,13 @@
 	while (len) {
 		u32 buf_size;
 
-		buf_size = len > VMXNET3_MAX_TX_BUF_SIZE ?
-			   VMXNET3_MAX_TX_BUF_SIZE : len;
+		if (len < VMXNET3_MAX_TX_BUF_SIZE) {
+			buf_size = len;
+			dw2 |= len;
+		} else {
+			buf_size = VMXNET3_MAX_TX_BUF_SIZE;
+			/* spec says that for TxDesc.len, 0 == 2^14 */
+		}
 
 		tbi = tq->buf_info + tq->tx_ring.next2fill;
 		tbi->map_type = VMXNET3_MAP_SINGLE;
@@ -667,13 +678,13 @@
 				skb->data + buf_offset, buf_size,
 				PCI_DMA_TODEVICE);
 
-		tbi->len = buf_size; /* this automatically convert 2^14 to 0 */
+		tbi->len = buf_size;
 
 		gdesc = tq->tx_ring.base + tq->tx_ring.next2fill;
 		BUG_ON(gdesc->txd.gen == tq->tx_ring.gen);
 
 		gdesc->txd.addr = cpu_to_le64(tbi->dma_addr);
-		gdesc->dword[2] = cpu_to_le32(dw2 | buf_size);
+		gdesc->dword[2] = cpu_to_le32(dw2);
 		gdesc->dword[3] = 0;
 
 		dev_dbg(&adapter->netdev->dev,
@@ -1825,6 +1836,7 @@
 		devRead->intrConf.modLevels[i] = adapter->intr.mod_levels[i];
 
 	devRead->intrConf.eventIntrIdx = adapter->intr.event_intr_idx;
+	devRead->intrConf.intrCtrl |= cpu_to_le32(VMXNET3_IC_DISABLE_ALL);
 
 	/* rx filter settings */
 	devRead->rxFilterConf.rxMode = 0;
@@ -1889,7 +1901,7 @@
 	 * Check link state when first activating device. It will start the
 	 * tx queue if the link is up.
 	 */
-	vmxnet3_check_link(adapter);
+	vmxnet3_check_link(adapter, true);
 
 	napi_enable(&adapter->napi);
 	vmxnet3_enable_all_intrs(adapter);
@@ -2295,9 +2307,13 @@
 	adapter->intr.mask_mode = (cfg >> 2) & 0x3;
 
 	if (adapter->intr.type == VMXNET3_IT_AUTO) {
-		int err;
+		adapter->intr.type = VMXNET3_IT_MSIX;
+	}
 
 #ifdef CONFIG_PCI_MSI
+	if (adapter->intr.type == VMXNET3_IT_MSIX) {
+		int err;
+
 		adapter->intr.msix_entries[0].entry = 0;
 		err = pci_enable_msix(adapter->pdev, adapter->intr.msix_entries,
 				      VMXNET3_LINUX_MAX_MSIX_VECT);
@@ -2306,15 +2322,18 @@
 			adapter->intr.type = VMXNET3_IT_MSIX;
 			return;
 		}
-#endif
+		adapter->intr.type = VMXNET3_IT_MSI;
+	}
 
+	if (adapter->intr.type == VMXNET3_IT_MSI) {
+		int err;
 		err = pci_enable_msi(adapter->pdev);
 		if (!err) {
 			adapter->intr.num_intrs = 1;
-			adapter->intr.type = VMXNET3_IT_MSI;
 			return;
 		}
 	}
+#endif /* CONFIG_PCI_MSI */
 
 	adapter->intr.type = VMXNET3_IT_INTX;
 
@@ -2358,6 +2377,7 @@
 		return;
 
 	/* if the device is closed, we must leave it alone */
+	rtnl_lock();
 	if (netif_running(adapter->netdev)) {
 		printk(KERN_INFO "%s: resetting\n", adapter->netdev->name);
 		vmxnet3_quiesce_dev(adapter);
@@ -2366,6 +2386,7 @@
 	} else {
 		printk(KERN_INFO "%s: already closed\n", adapter->netdev->name);
 	}
+	rtnl_unlock();
 
 	clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
 }
@@ -2491,6 +2512,7 @@
 	}
 
 	set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
+	vmxnet3_check_link(adapter, false);
 	atomic_inc(&devices_found);
 	return 0;
 
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 3935c44..7e4b5a8 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -275,27 +275,27 @@
 	}
 }
 
-static u32
-vmxnet3_get_flags(struct net_device *netdev) {
-	return netdev->features;
-}
-
 static int
-vmxnet3_set_flags(struct net_device *netdev, u32 data) {
+vmxnet3_set_flags(struct net_device *netdev, u32 data)
+{
 	struct vmxnet3_adapter *adapter = netdev_priv(netdev);
 	u8 lro_requested = (data & ETH_FLAG_LRO) == 0 ? 0 : 1;
 	u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1;
 
+	if (data & ~ETH_FLAG_LRO)
+		return -EOPNOTSUPP;
+
 	if (lro_requested ^ lro_present) {
 		/* toggle the LRO feature*/
 		netdev->features ^= NETIF_F_LRO;
 
 		/* update harware LRO capability accordingly */
 		if (lro_requested)
-			adapter->shared->devRead.misc.uptFeatures &= UPT1_F_LRO;
+			adapter->shared->devRead.misc.uptFeatures |=
+						cpu_to_le64(UPT1_F_LRO);
 		else
 			adapter->shared->devRead.misc.uptFeatures &=
-								~UPT1_F_LRO;
+						cpu_to_le64(~UPT1_F_LRO);
 		VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
 				       VMXNET3_CMD_UPDATE_FEATURE);
 	}
@@ -554,7 +554,7 @@
 	.get_tso           = ethtool_op_get_tso,
 	.set_tso           = ethtool_op_set_tso,
 	.get_strings       = vmxnet3_get_strings,
-	.get_flags	   = vmxnet3_get_flags,
+	.get_flags	   = ethtool_op_get_flags,
 	.set_flags	   = vmxnet3_set_flags,
 	.get_sset_count	   = vmxnet3_get_sset_count,
 	.get_ethtool_stats = vmxnet3_get_ethtool_stats,
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 34f392f4..2121c73 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -68,10 +68,10 @@
 /*
  * Version numbers
  */
-#define VMXNET3_DRIVER_VERSION_STRING   "1.0.5.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING   "1.0.14.0-k"
 
 /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM      0x01000500
+#define VMXNET3_DRIVER_VERSION_NUM      0x01000E00
 
 
 /*
diff --git a/drivers/net/vxge/Makefile b/drivers/net/vxge/Makefile
index 8992ca2..b625e2c 100644
--- a/drivers/net/vxge/Makefile
+++ b/drivers/net/vxge/Makefile
@@ -1,5 +1,5 @@
 #
-# Makefile for Neterion Inc's X3100 Series 10 GbE PCIe # I/O
+# Makefile for Exar Corp's X3100 Series 10 GbE PCIe I/O
 # Virtualized Server Adapter linux driver
 
 obj-$(CONFIG_VXGE) += vxge.o
diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c
index 297f0d2..0e6db59 100644
--- a/drivers/net/vxge/vxge-config.c
+++ b/drivers/net/vxge/vxge-config.c
@@ -7,9 +7,9 @@
  * system is licensed under the GPL.
  * See the file COPYING in this distribution for more information.
  *
- * vxge-config.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-config.c: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
  *                Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
  ******************************************************************************/
 #include <linux/vmalloc.h>
 #include <linux/etherdevice.h>
diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h
index 4ae2625..1a94343 100644
--- a/drivers/net/vxge/vxge-config.h
+++ b/drivers/net/vxge/vxge-config.h
@@ -7,9 +7,9 @@
  * system is licensed under the GPL.
  * See the file COPYING in this distribution for more information.
  *
- * vxge-config.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-config.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
  *                Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
  ******************************************************************************/
 #ifndef VXGE_CONFIG_H
 #define VXGE_CONFIG_H
diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c
index cadef85..05679e3 100644
--- a/drivers/net/vxge/vxge-ethtool.c
+++ b/drivers/net/vxge/vxge-ethtool.c
@@ -7,9 +7,9 @@
  * system is licensed under the GPL.
  * See the file COPYING in this distribution for more information.
  *
- * vxge-ethtool.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-ethtool.c: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
  *                 Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
  ******************************************************************************/
 #include<linux/ethtool.h>
 #include <linux/slab.h>
diff --git a/drivers/net/vxge/vxge-ethtool.h b/drivers/net/vxge/vxge-ethtool.h
index 1c3df0a..6cf3044 100644
--- a/drivers/net/vxge/vxge-ethtool.h
+++ b/drivers/net/vxge/vxge-ethtool.h
@@ -7,9 +7,9 @@
  * system is licensed under the GPL.
  * See the file COPYING in this distribution for more information.
  *
- * vxge-ethtool.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-ethtool.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
  *                 Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
  ******************************************************************************/
 #ifndef _VXGE_ETHTOOL_H
 #define _VXGE_ETHTOOL_H
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
index fc8b2d7..c7c5605 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -7,9 +7,9 @@
 * system is licensed under the GPL.
 * See the file COPYING in this distribution for more information.
 *
-* vxge-main.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+* vxge-main.c: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
 *              Virtualized Server Adapter.
-* Copyright(c) 2002-2009 Neterion Inc.
+* Copyright(c) 2002-2010 Exar Corp.
 *
 * The module loadable parameters that are supported by the driver and a brief
 * explanation of all the variables:
@@ -41,6 +41,8 @@
 *
 ******************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/if_vlan.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
@@ -87,7 +89,6 @@
 
 static inline void VXGE_COMPLETE_VPATH_TX(struct vxge_fifo *fifo)
 {
-	unsigned long flags = 0;
 	struct sk_buff **skb_ptr = NULL;
 	struct sk_buff **temp;
 #define NR_SKB_COMPLETED 128
@@ -98,15 +99,16 @@
 		more = 0;
 		skb_ptr = completed;
 
-		if (spin_trylock_irqsave(&fifo->tx_lock, flags)) {
+		if (__netif_tx_trylock(fifo->txq)) {
 			vxge_hw_vpath_poll_tx(fifo->handle, &skb_ptr,
 						NR_SKB_COMPLETED, &more);
-			spin_unlock_irqrestore(&fifo->tx_lock, flags);
+			__netif_tx_unlock(fifo->txq);
 		}
+
 		/* free SKBs */
 		for (temp = completed; temp != skb_ptr; temp++)
 			dev_kfree_skb_irq(*temp);
-	} while (more) ;
+	} while (more);
 }
 
 static inline void VXGE_COMPLETE_ALL_TX(struct vxgedev *vdev)
@@ -131,80 +133,6 @@
 }
 
 /*
- * MultiQ manipulation helper functions
- */
-void vxge_stop_all_tx_queue(struct vxgedev *vdev)
-{
-	int i;
-	struct net_device *dev = vdev->ndev;
-
-	if (vdev->config.tx_steering_type != TX_MULTIQ_STEERING) {
-		for (i = 0; i < vdev->no_of_vpath; i++)
-			vdev->vpaths[i].fifo.queue_state = VPATH_QUEUE_STOP;
-	}
-	netif_tx_stop_all_queues(dev);
-}
-
-void vxge_stop_tx_queue(struct vxge_fifo *fifo)
-{
-	struct net_device *dev = fifo->ndev;
-
-	struct netdev_queue *txq = NULL;
-	if (fifo->tx_steering_type == TX_MULTIQ_STEERING)
-		txq = netdev_get_tx_queue(dev, fifo->driver_id);
-	else {
-		txq = netdev_get_tx_queue(dev, 0);
-		fifo->queue_state = VPATH_QUEUE_STOP;
-	}
-
-	netif_tx_stop_queue(txq);
-}
-
-void vxge_start_all_tx_queue(struct vxgedev *vdev)
-{
-	int i;
-	struct net_device *dev = vdev->ndev;
-
-	if (vdev->config.tx_steering_type != TX_MULTIQ_STEERING) {
-		for (i = 0; i < vdev->no_of_vpath; i++)
-			vdev->vpaths[i].fifo.queue_state = VPATH_QUEUE_START;
-	}
-	netif_tx_start_all_queues(dev);
-}
-
-static void vxge_wake_all_tx_queue(struct vxgedev *vdev)
-{
-	int i;
-	struct net_device *dev = vdev->ndev;
-
-	if (vdev->config.tx_steering_type != TX_MULTIQ_STEERING) {
-		for (i = 0; i < vdev->no_of_vpath; i++)
-			vdev->vpaths[i].fifo.queue_state = VPATH_QUEUE_START;
-	}
-	netif_tx_wake_all_queues(dev);
-}
-
-void vxge_wake_tx_queue(struct vxge_fifo *fifo, struct sk_buff *skb)
-{
-	struct net_device *dev = fifo->ndev;
-
-	int vpath_no = fifo->driver_id;
-	struct netdev_queue *txq = NULL;
-	if (fifo->tx_steering_type == TX_MULTIQ_STEERING) {
-		txq = netdev_get_tx_queue(dev, vpath_no);
-		if (netif_tx_queue_stopped(txq))
-			netif_tx_wake_queue(txq);
-	} else {
-		txq = netdev_get_tx_queue(dev, 0);
-		if (fifo->queue_state == VPATH_QUEUE_STOP)
-			if (netif_tx_queue_stopped(txq)) {
-				fifo->queue_state = VPATH_QUEUE_START;
-				netif_tx_wake_queue(txq);
-			}
-	}
-}
-
-/*
  * vxge_callback_link_up
  *
  * This function is called during interrupt context to notify link up state
@@ -218,11 +146,11 @@
 
 	vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
 		vdev->ndev->name, __func__, __LINE__);
-	printk(KERN_NOTICE "%s: Link Up\n", vdev->ndev->name);
+	netdev_notice(vdev->ndev, "Link Up\n");
 	vdev->stats.link_up++;
 
 	netif_carrier_on(vdev->ndev);
-	vxge_wake_all_tx_queue(vdev);
+	netif_tx_wake_all_queues(vdev->ndev);
 
 	vxge_debug_entryexit(VXGE_TRACE,
 		"%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__);
@@ -242,11 +170,11 @@
 
 	vxge_debug_entryexit(VXGE_TRACE,
 		"%s: %s:%d", vdev->ndev->name, __func__, __LINE__);
-	printk(KERN_NOTICE "%s: Link Down\n", vdev->ndev->name);
+	netdev_notice(vdev->ndev, "Link Down\n");
 
 	vdev->stats.link_down++;
 	netif_carrier_off(vdev->ndev);
-	vxge_stop_all_tx_queue(vdev);
+	netif_tx_stop_all_queues(vdev->ndev);
 
 	vxge_debug_entryexit(VXGE_TRACE,
 		"%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__);
@@ -677,7 +605,8 @@
 				&dtr, &t_code) == VXGE_HW_OK);
 
 	*skb_ptr = done_skb;
-	vxge_wake_tx_queue(fifo, skb);
+	if (netif_tx_queue_stopped(fifo->txq))
+		netif_tx_wake_queue(fifo->txq);
 
 	vxge_debug_entryexit(VXGE_TRACE,
 				"%s: %s:%d  Exiting...",
@@ -686,8 +615,7 @@
 }
 
 /* select a vpath to transmit the packet */
-static u32 vxge_get_vpath_no(struct vxgedev *vdev, struct sk_buff *skb,
-	int *do_lock)
+static u32 vxge_get_vpath_no(struct vxgedev *vdev, struct sk_buff *skb)
 {
 	u16 queue_len, counter = 0;
 	if (skb->protocol == htons(ETH_P_IP)) {
@@ -706,12 +634,6 @@
 				vdev->vpath_selector[queue_len - 1];
 			if (counter >= queue_len)
 				counter = queue_len - 1;
-
-			if (ip->protocol == IPPROTO_UDP) {
-#ifdef NETIF_F_LLTX
-				*do_lock = 0;
-#endif
-			}
 		}
 	}
 	return counter;
@@ -808,8 +730,6 @@
  *
  * This function is the Tx entry point of the driver. Neterion NIC supports
  * certain protocol assist features on Tx side, namely  CSO, S/G, LSO.
- * NOTE: when device cant queue the pkt, just the trans_start variable will
- * not be upadted.
 */
 static netdev_tx_t
 vxge_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -826,9 +746,7 @@
 	struct vxge_tx_priv *txdl_priv = NULL;
 	struct __vxge_hw_fifo *fifo_hw;
 	int offload_type;
-	unsigned long flags = 0;
 	int vpath_no = 0;
-	int do_spin_tx_lock = 1;
 
 	vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
 			dev->name, __func__, __LINE__);
@@ -864,7 +782,7 @@
 	if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING)
 		vpath_no = skb_get_queue_mapping(skb);
 	else if (vdev->config.tx_steering_type == TX_PORT_STEERING)
-		vpath_no = vxge_get_vpath_no(vdev, skb, &do_spin_tx_lock);
+		vpath_no = vxge_get_vpath_no(vdev, skb);
 
 	vxge_debug_tx(VXGE_TRACE, "%s: vpath_no= %d", dev->name, vpath_no);
 
@@ -874,46 +792,29 @@
 	fifo = &vdev->vpaths[vpath_no].fifo;
 	fifo_hw = fifo->handle;
 
-	if (do_spin_tx_lock)
-		spin_lock_irqsave(&fifo->tx_lock, flags);
-	else {
-		if (unlikely(!spin_trylock_irqsave(&fifo->tx_lock, flags)))
-			return NETDEV_TX_LOCKED;
-	}
+	if (netif_tx_queue_stopped(fifo->txq))
+		return NETDEV_TX_BUSY;
 
-	if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING) {
-		if (netif_subqueue_stopped(dev, skb)) {
-			spin_unlock_irqrestore(&fifo->tx_lock, flags);
-			return NETDEV_TX_BUSY;
-		}
-	} else if (unlikely(fifo->queue_state == VPATH_QUEUE_STOP)) {
-		if (netif_queue_stopped(dev)) {
-			spin_unlock_irqrestore(&fifo->tx_lock, flags);
-			return NETDEV_TX_BUSY;
-		}
-	}
 	avail = vxge_hw_fifo_free_txdl_count_get(fifo_hw);
 	if (avail == 0) {
 		vxge_debug_tx(VXGE_ERR,
 			"%s: No free TXDs available", dev->name);
 		fifo->stats.txd_not_free++;
-		vxge_stop_tx_queue(fifo);
-		goto _exit2;
+		goto _exit0;
 	}
 
 	/* Last TXD?  Stop tx queue to avoid dropping packets.  TX
 	 * completion will resume the queue.
 	 */
 	if (avail == 1)
-		vxge_stop_tx_queue(fifo);
+		netif_tx_stop_queue(fifo->txq);
 
 	status = vxge_hw_fifo_txdl_reserve(fifo_hw, &dtr, &dtr_priv);
 	if (unlikely(status != VXGE_HW_OK)) {
 		vxge_debug_tx(VXGE_ERR,
 		   "%s: Out of descriptors .", dev->name);
 		fifo->stats.txd_out_of_desc++;
-		vxge_stop_tx_queue(fifo);
-		goto _exit2;
+		goto _exit0;
 	}
 
 	vxge_debug_tx(VXGE_TRACE,
@@ -933,9 +834,8 @@
 
 	if (unlikely(pci_dma_mapping_error(fifo->pdev, dma_pointer))) {
 		vxge_hw_fifo_txdl_free(fifo_hw, dtr);
-		vxge_stop_tx_queue(fifo);
 		fifo->stats.pci_map_fail++;
-		goto _exit2;
+		goto _exit0;
 	}
 
 	txdl_priv = vxge_hw_fifo_txdl_private_get(dtr);
@@ -958,13 +858,12 @@
 		if (!frag->size)
 			continue;
 
-		dma_pointer =
-			(u64)pci_map_page(fifo->pdev, frag->page,
+		dma_pointer = (u64) pci_map_page(fifo->pdev, frag->page,
 				frag->page_offset, frag->size,
 				PCI_DMA_TODEVICE);
 
 		if (unlikely(pci_dma_mapping_error(fifo->pdev, dma_pointer)))
-			goto _exit0;
+			goto _exit2;
 		vxge_debug_tx(VXGE_TRACE,
 			"%s: %s:%d frag = %d dma_pointer = 0x%llx",
 				dev->name, __func__, __LINE__, i,
@@ -979,11 +878,9 @@
 	offload_type = vxge_offload_type(skb);
 
 	if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
-
 		int mss = vxge_tcp_mss(skb);
 		if (mss) {
-			vxge_debug_tx(VXGE_TRACE,
-				"%s: %s:%d mss = %d",
+			vxge_debug_tx(VXGE_TRACE, "%s: %s:%d mss = %d",
 				dev->name, __func__, __LINE__, mss);
 			vxge_hw_fifo_txdl_mss_set(dtr, mss);
 		} else {
@@ -1001,19 +898,13 @@
 					VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN);
 
 	vxge_hw_fifo_txdl_post(fifo_hw, dtr);
-#ifdef NETIF_F_LLTX
-	dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
-#endif
-	spin_unlock_irqrestore(&fifo->tx_lock, flags);
 
-	VXGE_COMPLETE_VPATH_TX(fifo);
 	vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d  Exiting...",
 		dev->name, __func__, __LINE__);
 	return NETDEV_TX_OK;
 
-_exit0:
+_exit2:
 	vxge_debug_tx(VXGE_TRACE, "%s: pci_map_page failed", dev->name);
-
 _exit1:
 	j = 0;
 	frag = &skb_shinfo(skb)->frags[0];
@@ -1028,10 +919,9 @@
 	}
 
 	vxge_hw_fifo_txdl_free(fifo_hw, dtr);
-_exit2:
+_exit0:
+	netif_tx_stop_queue(fifo->txq);
 	dev_kfree_skb(skb);
-	spin_unlock_irqrestore(&fifo->tx_lock, flags);
-	VXGE_COMPLETE_VPATH_TX(fifo);
 
 	return NETDEV_TX_OK;
 }
@@ -1121,7 +1011,8 @@
 	struct netdev_hw_addr *ha;
 	struct vxgedev *vdev;
 	int i, mcast_cnt = 0;
-	struct __vxge_hw_device  *hldev;
+	struct __vxge_hw_device *hldev;
+	struct vxge_vpath *vpath;
 	enum vxge_hw_status status = VXGE_HW_OK;
 	struct macInfo mac_info;
 	int vpath_idx = 0;
@@ -1141,46 +1032,48 @@
 
 	if ((dev->flags & IFF_ALLMULTI) && (!vdev->all_multi_flg)) {
 		for (i = 0; i < vdev->no_of_vpath; i++) {
-			vxge_assert(vdev->vpaths[i].is_open);
-			status = vxge_hw_vpath_mcast_enable(
-						vdev->vpaths[i].handle);
+			vpath = &vdev->vpaths[i];
+			vxge_assert(vpath->is_open);
+			status = vxge_hw_vpath_mcast_enable(vpath->handle);
+			if (status != VXGE_HW_OK)
+				vxge_debug_init(VXGE_ERR, "failed to enable "
+						"multicast, status %d", status);
 			vdev->all_multi_flg = 1;
 		}
-	} else if ((dev->flags & IFF_ALLMULTI) && (vdev->all_multi_flg)) {
+	} else if (!(dev->flags & IFF_ALLMULTI) && (vdev->all_multi_flg)) {
 		for (i = 0; i < vdev->no_of_vpath; i++) {
-			vxge_assert(vdev->vpaths[i].is_open);
-			status = vxge_hw_vpath_mcast_disable(
-						vdev->vpaths[i].handle);
-			vdev->all_multi_flg = 1;
+			vpath = &vdev->vpaths[i];
+			vxge_assert(vpath->is_open);
+			status = vxge_hw_vpath_mcast_disable(vpath->handle);
+			if (status != VXGE_HW_OK)
+				vxge_debug_init(VXGE_ERR, "failed to disable "
+						"multicast, status %d", status);
+			vdev->all_multi_flg = 0;
 		}
 	}
 
-	if (status != VXGE_HW_OK)
-		vxge_debug_init(VXGE_ERR,
-			"failed to %s multicast, status %d",
-			dev->flags & IFF_ALLMULTI ?
-			"enable" : "disable", status);
 
 	if (!vdev->config.addr_learn_en) {
-		if (dev->flags & IFF_PROMISC) {
-			for (i = 0; i < vdev->no_of_vpath; i++) {
-				vxge_assert(vdev->vpaths[i].is_open);
+		for (i = 0; i < vdev->no_of_vpath; i++) {
+			vpath = &vdev->vpaths[i];
+			vxge_assert(vpath->is_open);
+
+			if (dev->flags & IFF_PROMISC)
 				status = vxge_hw_vpath_promisc_enable(
-						vdev->vpaths[i].handle);
-			}
-		} else {
-			for (i = 0; i < vdev->no_of_vpath; i++) {
-				vxge_assert(vdev->vpaths[i].is_open);
+					vpath->handle);
+			else
 				status = vxge_hw_vpath_promisc_disable(
-						vdev->vpaths[i].handle);
-			}
+					vpath->handle);
+			if (status != VXGE_HW_OK)
+				vxge_debug_init(VXGE_ERR, "failed to %s promisc"
+					", status %d", dev->flags&IFF_PROMISC ?
+					"enable" : "disable", status);
 		}
 	}
 
 	memset(&mac_info, 0, sizeof(struct macInfo));
 	/* Update individual M_CAST address list */
 	if ((!vdev->all_multi_flg) && netdev_mc_count(dev)) {
-
 		mcast_cnt = vdev->vpaths[0].mcast_addr_cnt;
 		list_head = &vdev->vpaths[0].mac_addr_list;
 		if ((netdev_mc_count(dev) +
@@ -1190,14 +1083,7 @@
 
 		/* Delete previous MC's */
 		for (i = 0; i < mcast_cnt; i++) {
-			if (!list_empty(list_head))
-				mac_entry = (struct vxge_mac_addrs *)
-					list_first_entry(list_head,
-						struct vxge_mac_addrs,
-						item);
-
 			list_for_each_safe(entry, next, list_head) {
-
 				mac_entry = (struct vxge_mac_addrs *) entry;
 				/* Copy the mac address to delete */
 				mac_address = (u8 *)&mac_entry->macaddr;
@@ -1240,9 +1126,7 @@
 		mcast_cnt = vdev->vpaths[0].mcast_addr_cnt;
 		/* Delete previous MC's */
 		for (i = 0; i < mcast_cnt; i++) {
-
 			list_for_each_safe(entry, next, list_head) {
-
 				mac_entry = (struct vxge_mac_addrs *) entry;
 				/* Copy the mac address to delete */
 				mac_address = (u8 *)&mac_entry->macaddr;
@@ -1262,9 +1146,10 @@
 
 		/* Enable all multicast */
 		for (i = 0; i < vdev->no_of_vpath; i++) {
-			vxge_assert(vdev->vpaths[i].is_open);
-			status = vxge_hw_vpath_mcast_enable(
-						vdev->vpaths[i].handle);
+			vpath = &vdev->vpaths[i];
+			vxge_assert(vpath->is_open);
+
+			status = vxge_hw_vpath_mcast_enable(vpath->handle);
 			if (status != VXGE_HW_OK) {
 				vxge_debug_init(VXGE_ERR,
 					"%s:%d Enabling all multicasts failed",
@@ -1425,6 +1310,7 @@
 static int vxge_reset_vpath(struct vxgedev *vdev, int vp_id)
 {
 	enum vxge_hw_status status = VXGE_HW_OK;
+	struct vxge_vpath *vpath = &vdev->vpaths[vp_id];
 	int ret = 0;
 
 	/* check if device is down already */
@@ -1435,12 +1321,10 @@
 	if (test_bit(__VXGE_STATE_RESET_CARD, &vdev->state))
 		return 0;
 
-	if (vdev->vpaths[vp_id].handle) {
-		if (vxge_hw_vpath_reset(vdev->vpaths[vp_id].handle)
-				== VXGE_HW_OK) {
+	if (vpath->handle) {
+		if (vxge_hw_vpath_reset(vpath->handle) == VXGE_HW_OK) {
 			if (is_vxge_card_up(vdev) &&
-				vxge_hw_vpath_recover_from_reset(
-					vdev->vpaths[vp_id].handle)
+				vxge_hw_vpath_recover_from_reset(vpath->handle)
 					!= VXGE_HW_OK) {
 				vxge_debug_init(VXGE_ERR,
 					"vxge_hw_vpath_recover_from_reset"
@@ -1456,11 +1340,20 @@
 	} else
 		return VXGE_HW_FAIL;
 
-	vxge_restore_vpath_mac_addr(&vdev->vpaths[vp_id]);
-	vxge_restore_vpath_vid_table(&vdev->vpaths[vp_id]);
+	vxge_restore_vpath_mac_addr(vpath);
+	vxge_restore_vpath_vid_table(vpath);
 
 	/* Enable all broadcast */
-	vxge_hw_vpath_bcast_enable(vdev->vpaths[vp_id].handle);
+	vxge_hw_vpath_bcast_enable(vpath->handle);
+
+	/* Enable all multicast */
+	if (vdev->all_multi_flg) {
+		status = vxge_hw_vpath_mcast_enable(vpath->handle);
+		if (status != VXGE_HW_OK)
+			vxge_debug_init(VXGE_ERR,
+				"%s:%d Enabling multicast failed",
+				__func__, __LINE__);
+	}
 
 	/* Enable the interrupts */
 	vxge_vpath_intr_enable(vdev, vp_id);
@@ -1468,17 +1361,18 @@
 	smp_wmb();
 
 	/* Enable the flow of traffic through the vpath */
-	vxge_hw_vpath_enable(vdev->vpaths[vp_id].handle);
+	vxge_hw_vpath_enable(vpath->handle);
 
 	smp_wmb();
-	vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[vp_id].handle);
-	vdev->vpaths[vp_id].ring.last_status = VXGE_HW_OK;
+	vxge_hw_vpath_rx_doorbell_init(vpath->handle);
+	vpath->ring.last_status = VXGE_HW_OK;
 
 	/* Vpath reset done */
 	clear_bit(vp_id, &vdev->vp_reset);
 
 	/* Start the vpath queue */
-	vxge_wake_tx_queue(&vdev->vpaths[vp_id].fifo, NULL);
+	if (netif_tx_queue_stopped(vpath->fifo.txq))
+		netif_tx_wake_queue(vpath->fifo.txq);
 
 	return ret;
 }
@@ -1512,9 +1406,9 @@
 			vxge_debug_init(VXGE_ERR,
 				"%s: execution mode is debug, returning..",
 				vdev->ndev->name);
-		clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
-		vxge_stop_all_tx_queue(vdev);
-		return 0;
+			clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
+			netif_tx_stop_all_queues(vdev->ndev);
+			return 0;
 		}
 	}
 
@@ -1523,7 +1417,7 @@
 
 		switch (vdev->cric_err_event) {
 		case VXGE_HW_EVENT_UNKNOWN:
-			vxge_stop_all_tx_queue(vdev);
+			netif_tx_stop_all_queues(vdev->ndev);
 			vxge_debug_init(VXGE_ERR,
 				"fatal: %s: Disabling device due to"
 				"unknown error",
@@ -1544,7 +1438,7 @@
 		case VXGE_HW_EVENT_VPATH_ERR:
 			break;
 		case VXGE_HW_EVENT_CRITICAL_ERR:
-			vxge_stop_all_tx_queue(vdev);
+			netif_tx_stop_all_queues(vdev->ndev);
 			vxge_debug_init(VXGE_ERR,
 				"fatal: %s: Disabling device due to"
 				"serious error",
@@ -1554,7 +1448,7 @@
 			ret = -EPERM;
 			goto out;
 		case VXGE_HW_EVENT_SERR:
-			vxge_stop_all_tx_queue(vdev);
+			netif_tx_stop_all_queues(vdev->ndev);
 			vxge_debug_init(VXGE_ERR,
 				"fatal: %s: Disabling device due to"
 				"serious error",
@@ -1566,7 +1460,7 @@
 			ret = -EPERM;
 			goto out;
 		case VXGE_HW_EVENT_SLOT_FREEZE:
-			vxge_stop_all_tx_queue(vdev);
+			netif_tx_stop_all_queues(vdev->ndev);
 			vxge_debug_init(VXGE_ERR,
 				"fatal: %s: Disabling device due to"
 				"slot freeze",
@@ -1580,7 +1474,7 @@
 	}
 
 	if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_START_RESET))
-		vxge_stop_all_tx_queue(vdev);
+		netif_tx_stop_all_queues(vdev->ndev);
 
 	if (event == VXGE_LL_FULL_RESET) {
 		status = vxge_reset_all_vpaths(vdev);
@@ -1640,7 +1534,7 @@
 			vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[i].handle);
 		}
 
-		vxge_wake_all_tx_queue(vdev);
+		netif_tx_wake_all_queues(vdev->ndev);
 	}
 
 out:
@@ -1661,8 +1555,7 @@
  */
 int vxge_reset(struct vxgedev *vdev)
 {
-	do_vxge_reset(vdev, VXGE_LL_FULL_RESET);
-	return 0;
+	return do_vxge_reset(vdev, VXGE_LL_FULL_RESET);
 }
 
 /**
@@ -2025,17 +1918,17 @@
 /* reset vpaths */
 enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev)
 {
-	int i;
 	enum vxge_hw_status status = VXGE_HW_OK;
+	struct vxge_vpath *vpath;
+	int i;
 
-	for (i = 0; i < vdev->no_of_vpath; i++)
-		if (vdev->vpaths[i].handle) {
-			if (vxge_hw_vpath_reset(vdev->vpaths[i].handle)
-					== VXGE_HW_OK) {
+	for (i = 0; i < vdev->no_of_vpath; i++) {
+		vpath = &vdev->vpaths[i];
+		if (vpath->handle) {
+			if (vxge_hw_vpath_reset(vpath->handle) == VXGE_HW_OK) {
 				if (is_vxge_card_up(vdev) &&
 					vxge_hw_vpath_recover_from_reset(
-						vdev->vpaths[i].handle)
-						!= VXGE_HW_OK) {
+						vpath->handle) != VXGE_HW_OK) {
 					vxge_debug_init(VXGE_ERR,
 						"vxge_hw_vpath_recover_"
 						"from_reset failed for vpath: "
@@ -2049,83 +1942,93 @@
 					return status;
 			}
 		}
+	}
+
 	return status;
 }
 
 /* close vpaths */
 void vxge_close_vpaths(struct vxgedev *vdev, int index)
 {
+	struct vxge_vpath *vpath;
 	int i;
+
 	for (i = index; i < vdev->no_of_vpath; i++) {
-		if (vdev->vpaths[i].handle && vdev->vpaths[i].is_open) {
-			vxge_hw_vpath_close(vdev->vpaths[i].handle);
+		vpath = &vdev->vpaths[i];
+
+		if (vpath->handle && vpath->is_open) {
+			vxge_hw_vpath_close(vpath->handle);
 			vdev->stats.vpaths_open--;
 		}
-		vdev->vpaths[i].is_open = 0;
-		vdev->vpaths[i].handle  = NULL;
+		vpath->is_open = 0;
+		vpath->handle = NULL;
 	}
 }
 
 /* open vpaths */
 int vxge_open_vpaths(struct vxgedev *vdev)
 {
-	enum vxge_hw_status status;
-	int i;
-	u32 vp_id = 0;
 	struct vxge_hw_vpath_attr attr;
+	enum vxge_hw_status status;
+	struct vxge_vpath *vpath;
+	u32 vp_id = 0;
+	int i;
 
 	for (i = 0; i < vdev->no_of_vpath; i++) {
-		vxge_assert(vdev->vpaths[i].is_configured);
-		attr.vp_id = vdev->vpaths[i].device_id;
+		vpath = &vdev->vpaths[i];
+
+		vxge_assert(vpath->is_configured);
+		attr.vp_id = vpath->device_id;
 		attr.fifo_attr.callback = vxge_xmit_compl;
 		attr.fifo_attr.txdl_term = vxge_tx_term;
 		attr.fifo_attr.per_txdl_space = sizeof(struct vxge_tx_priv);
-		attr.fifo_attr.userdata = (void *)&vdev->vpaths[i].fifo;
+		attr.fifo_attr.userdata = &vpath->fifo;
 
 		attr.ring_attr.callback = vxge_rx_1b_compl;
 		attr.ring_attr.rxd_init = vxge_rx_initial_replenish;
 		attr.ring_attr.rxd_term = vxge_rx_term;
 		attr.ring_attr.per_rxd_space = sizeof(struct vxge_rx_priv);
-		attr.ring_attr.userdata = (void *)&vdev->vpaths[i].ring;
+		attr.ring_attr.userdata = &vpath->ring;
 
-		vdev->vpaths[i].ring.ndev = vdev->ndev;
-		vdev->vpaths[i].ring.pdev = vdev->pdev;
-		status = vxge_hw_vpath_open(vdev->devh, &attr,
-				&(vdev->vpaths[i].handle));
+		vpath->ring.ndev = vdev->ndev;
+		vpath->ring.pdev = vdev->pdev;
+		status = vxge_hw_vpath_open(vdev->devh, &attr, &vpath->handle);
 		if (status == VXGE_HW_OK) {
-			vdev->vpaths[i].fifo.handle =
+			vpath->fifo.handle =
 			    (struct __vxge_hw_fifo *)attr.fifo_attr.userdata;
-			vdev->vpaths[i].ring.handle =
+			vpath->ring.handle =
 			    (struct __vxge_hw_ring *)attr.ring_attr.userdata;
-			vdev->vpaths[i].fifo.tx_steering_type =
+			vpath->fifo.tx_steering_type =
 				vdev->config.tx_steering_type;
-			vdev->vpaths[i].fifo.ndev = vdev->ndev;
-			vdev->vpaths[i].fifo.pdev = vdev->pdev;
-			vdev->vpaths[i].fifo.indicate_max_pkts =
+			vpath->fifo.ndev = vdev->ndev;
+			vpath->fifo.pdev = vdev->pdev;
+			if (vdev->config.tx_steering_type)
+				vpath->fifo.txq =
+					netdev_get_tx_queue(vdev->ndev, i);
+			else
+				vpath->fifo.txq =
+					netdev_get_tx_queue(vdev->ndev, 0);
+			vpath->fifo.indicate_max_pkts =
 				vdev->config.fifo_indicate_max_pkts;
-			vdev->vpaths[i].ring.rx_vector_no = 0;
-			vdev->vpaths[i].ring.rx_csum = vdev->rx_csum;
-			vdev->vpaths[i].is_open = 1;
-			vdev->vp_handles[i] = vdev->vpaths[i].handle;
-			vdev->vpaths[i].ring.gro_enable =
-						vdev->config.gro_enable;
-			vdev->vpaths[i].ring.vlan_tag_strip =
-						vdev->vlan_tag_strip;
+			vpath->ring.rx_vector_no = 0;
+			vpath->ring.rx_csum = vdev->rx_csum;
+			vpath->is_open = 1;
+			vdev->vp_handles[i] = vpath->handle;
+			vpath->ring.gro_enable = vdev->config.gro_enable;
+			vpath->ring.vlan_tag_strip = vdev->vlan_tag_strip;
 			vdev->stats.vpaths_open++;
 		} else {
 			vdev->stats.vpath_open_fail++;
 			vxge_debug_init(VXGE_ERR,
 				"%s: vpath: %d failed to open "
 				"with status: %d",
-			    vdev->ndev->name, vdev->vpaths[i].device_id,
+			    vdev->ndev->name, vpath->device_id,
 				status);
 			vxge_close_vpaths(vdev, 0);
 			return -EPERM;
 		}
 
-		vp_id =
-		  ((struct __vxge_hw_vpath_handle *)vdev->vpaths[i].handle)->
-		  vpath->vp_id;
+		vp_id = vpath->handle->vpath->vp_id;
 		vdev->vpaths_deployed |= vxge_mBIT(vp_id);
 	}
 	return VXGE_HW_OK;
@@ -2299,7 +2202,6 @@
 	vdev->vxge_entries[j].in_use = 0;
 
 	ret = pci_enable_msix(vdev->pdev, vdev->entries, vdev->intr_cnt);
-
 	if (ret > 0) {
 		vxge_debug_init(VXGE_ERR,
 			"%s: MSI-X enable failed for %d vectors, ret: %d",
@@ -2345,17 +2247,16 @@
 	ret = vxge_alloc_msix(vdev);
 	if (!ret) {
 		for (i = 0; i < vdev->no_of_vpath; i++) {
+			struct vxge_vpath *vpath = &vdev->vpaths[i];
 
-			/* If fifo or ring are not enabled
-			   the MSIX vector for that should be set to 0
-			   Hence initializeing this array to all 0s.
-			*/
-			vdev->vpaths[i].ring.rx_vector_no =
-				(vdev->vpaths[i].device_id *
-					VXGE_HW_VPATH_MSIX_ACTIVE) + 1;
+			/* If fifo or ring are not enabled, the MSIX vector for
+			 * it should be set to 0.
+			 */
+			vpath->ring.rx_vector_no = (vpath->device_id *
+						VXGE_HW_VPATH_MSIX_ACTIVE) + 1;
 
-			vxge_hw_vpath_msix_set(vdev->vpaths[i].handle,
-					tim_msix_id, VXGE_ALARM_MSIX_ID);
+			vxge_hw_vpath_msix_set(vpath->handle, tim_msix_id,
+					       VXGE_ALARM_MSIX_ID);
 		}
 	}
 
@@ -2570,9 +2471,10 @@
 static void vxge_poll_vp_lockup(unsigned long data)
 {
 	struct vxgedev *vdev = (struct vxgedev *)data;
-	int i;
-	struct vxge_ring *ring;
 	enum vxge_hw_status status = VXGE_HW_OK;
+	struct vxge_vpath *vpath;
+	struct vxge_ring *ring;
+	int i;
 
 	for (i = 0; i < vdev->no_of_vpath; i++) {
 		ring = &vdev->vpaths[i].ring;
@@ -2586,13 +2488,13 @@
 
 				/* schedule vpath reset */
 				if (!test_and_set_bit(i, &vdev->vp_reset)) {
+					vpath = &vdev->vpaths[i];
 
 					/* disable interrupts for this vpath */
 					vxge_vpath_intr_disable(vdev, i);
 
 					/* stop the queue for this vpath */
-					vxge_stop_tx_queue(&vdev->vpaths[i].
-								fifo);
+					netif_tx_stop_queue(vpath->fifo.txq);
 					continue;
 				}
 			}
@@ -2621,6 +2523,7 @@
 	enum vxge_hw_status status;
 	struct vxgedev *vdev;
 	struct __vxge_hw_device *hldev;
+	struct vxge_vpath *vpath;
 	int ret = 0;
 	int i;
 	u64 val64, function_mode;
@@ -2654,20 +2557,21 @@
 		goto out1;
 	}
 
-
 	if (vdev->config.intr_type != MSI_X) {
 		netif_napi_add(dev, &vdev->napi, vxge_poll_inta,
 			vdev->config.napi_weight);
 		napi_enable(&vdev->napi);
-		for (i = 0; i < vdev->no_of_vpath; i++)
-			vdev->vpaths[i].ring.napi_p = &vdev->napi;
+		for (i = 0; i < vdev->no_of_vpath; i++) {
+			vpath = &vdev->vpaths[i];
+			vpath->ring.napi_p = &vdev->napi;
+		}
 	} else {
 		for (i = 0; i < vdev->no_of_vpath; i++) {
-			netif_napi_add(dev, &vdev->vpaths[i].ring.napi,
+			vpath = &vdev->vpaths[i];
+			netif_napi_add(dev, &vpath->ring.napi,
 			    vxge_poll_msix, vdev->config.napi_weight);
-			napi_enable(&vdev->vpaths[i].ring.napi);
-			vdev->vpaths[i].ring.napi_p =
-				&vdev->vpaths[i].ring.napi;
+			napi_enable(&vpath->ring.napi);
+			vpath->ring.napi_p = &vpath->ring.napi;
 		}
 	}
 
@@ -2684,9 +2588,10 @@
 	}
 
 	for (i = 0; i < vdev->no_of_vpath; i++) {
+		vpath = &vdev->vpaths[i];
+
 		/* set initial mtu before enabling the device */
-		status = vxge_hw_vpath_mtu_set(vdev->vpaths[i].handle,
-						vdev->mtu);
+		status = vxge_hw_vpath_mtu_set(vpath->handle, vdev->mtu);
 		if (status != VXGE_HW_OK) {
 			vxge_debug_init(VXGE_ERR,
 				"%s: fatal: can not set new MTU", dev->name);
@@ -2700,10 +2605,21 @@
 		"%s: MTU is %d", vdev->ndev->name, vdev->mtu);
 	VXGE_DEVICE_DEBUG_LEVEL_SET(VXGE_ERR, VXGE_COMPONENT_LL, vdev);
 
-	/* Reprogram the DA table with populated mac addresses */
-	for (i = 0; i < vdev->no_of_vpath; i++) {
-		vxge_restore_vpath_mac_addr(&vdev->vpaths[i]);
-		vxge_restore_vpath_vid_table(&vdev->vpaths[i]);
+	/* Restore the DA, VID table and also multicast and promiscuous mode
+	 * states
+	 */
+	if (vdev->all_multi_flg) {
+		for (i = 0; i < vdev->no_of_vpath; i++) {
+			vpath = &vdev->vpaths[i];
+			vxge_restore_vpath_mac_addr(vpath);
+			vxge_restore_vpath_vid_table(vpath);
+
+			status = vxge_hw_vpath_mcast_enable(vpath->handle);
+			if (status != VXGE_HW_OK)
+				vxge_debug_init(VXGE_ERR,
+					"%s:%d Enabling multicast failed",
+					__func__, __LINE__);
+		}
 	}
 
 	/* Enable vpath to sniff all unicast/multicast traffic that not
@@ -2732,14 +2648,14 @@
 
 	/* Enabling Bcast and mcast for all vpath */
 	for (i = 0; i < vdev->no_of_vpath; i++) {
-		status = vxge_hw_vpath_bcast_enable(vdev->vpaths[i].handle);
+		vpath = &vdev->vpaths[i];
+		status = vxge_hw_vpath_bcast_enable(vpath->handle);
 		if (status != VXGE_HW_OK)
 			vxge_debug_init(VXGE_ERR,
 				"%s : Can not enable bcast for vpath "
 				"id %d", dev->name, i);
 		if (vdev->config.addr_learn_en) {
-			status =
-			    vxge_hw_vpath_mcast_enable(vdev->vpaths[i].handle);
+			status = vxge_hw_vpath_mcast_enable(vpath->handle);
 			if (status != VXGE_HW_OK)
 				vxge_debug_init(VXGE_ERR,
 					"%s : Can not enable mcast for vpath "
@@ -2765,7 +2681,7 @@
 
 	if (vxge_hw_device_link_state_get(vdev->devh) == VXGE_HW_LINK_UP) {
 		netif_carrier_on(vdev->ndev);
-		printk(KERN_NOTICE "%s: Link Up\n", vdev->ndev->name);
+		netdev_notice(vdev->ndev, "Link Up\n");
 		vdev->stats.link_up++;
 	}
 
@@ -2774,12 +2690,14 @@
 	smp_wmb();
 
 	for (i = 0; i < vdev->no_of_vpath; i++) {
-		vxge_hw_vpath_enable(vdev->vpaths[i].handle);
+		vpath = &vdev->vpaths[i];
+
+		vxge_hw_vpath_enable(vpath->handle);
 		smp_wmb();
-		vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[i].handle);
+		vxge_hw_vpath_rx_doorbell_init(vpath->handle);
 	}
 
-	vxge_start_all_tx_queue(vdev);
+	netif_tx_start_all_queues(vdev->ndev);
 	goto out0;
 
 out2:
@@ -2901,8 +2819,8 @@
 	}
 
 	netif_carrier_off(vdev->ndev);
-	printk(KERN_NOTICE "%s: Link Down\n", vdev->ndev->name);
-	vxge_stop_all_tx_queue(vdev);
+	netdev_notice(vdev->ndev, "Link Down\n");
+	netif_tx_stop_all_queues(vdev->ndev);
 
 	/* Note that at this point xmit() is stopped by upper layer */
 	if (do_io)
@@ -3211,11 +3129,11 @@
 	struct net_device *ndev;
 	enum vxge_hw_status status = VXGE_HW_OK;
 	struct vxgedev *vdev;
-	int i, ret = 0, no_of_queue = 1;
+	int ret = 0, no_of_queue = 1;
 	u64 stat;
 
 	*vdev_out = NULL;
-	if (config->tx_steering_type == TX_MULTIQ_STEERING)
+	if (config->tx_steering_type)
 		no_of_queue = no_of_vpath;
 
 	ndev = alloc_etherdev_mq(sizeof(struct vxgedev),
@@ -3284,16 +3202,6 @@
 	if (vdev->config.gro_enable)
 		ndev->features |= NETIF_F_GRO;
 
-	if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING)
-		ndev->real_num_tx_queues = no_of_vpath;
-
-#ifdef NETIF_F_LLTX
-	ndev->features |= NETIF_F_LLTX;
-#endif
-
-	for (i = 0; i < no_of_vpath; i++)
-		spin_lock_init(&vdev->vpaths[i].fifo.tx_lock);
-
 	if (register_netdev(ndev)) {
 		vxge_debug_init(vxge_hw_device_trace_level_get(hldev),
 			"%s: %s : device registration failed!",
@@ -3393,6 +3301,7 @@
 {
 	struct net_device *dev = hldev->ndev;
 	struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+	struct vxge_vpath *vpath = NULL;
 	int vpath_idx;
 
 	vxge_debug_entryexit(vdev->level_trace,
@@ -3403,9 +3312,11 @@
 	 */
 	vdev->cric_err_event = type;
 
-	for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++)
-		if (vdev->vpaths[vpath_idx].device_id == vp_id)
+	for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) {
+		vpath = &vdev->vpaths[vpath_idx];
+		if (vpath->device_id == vp_id)
 			break;
+	}
 
 	if (!test_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) {
 		if (type == VXGE_HW_EVENT_SLOT_FREEZE) {
@@ -3442,8 +3353,7 @@
 				vxge_vpath_intr_disable(vdev, vpath_idx);
 
 				/* stop the queue for this vpath */
-				vxge_stop_tx_queue(&vdev->vpaths[vpath_idx].
-							fifo);
+				netif_tx_stop_queue(vpath->fifo.txq);
 			}
 		}
 	}
@@ -3936,9 +3846,7 @@
 	struct vxgedev *vdev = netdev_priv(netdev);
 
 	if (pci_enable_device(pdev)) {
-		printk(KERN_ERR "%s: "
-			"Cannot re-enable device after reset\n",
-			VXGE_DRIVER_NAME);
+		netdev_err(netdev, "Cannot re-enable device after reset\n");
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
 
@@ -3963,9 +3871,8 @@
 
 	if (netif_running(netdev)) {
 		if (vxge_open(netdev)) {
-			printk(KERN_ERR "%s: "
-				"Can't bring device back up after reset\n",
-				VXGE_DRIVER_NAME);
+			netdev_err(netdev,
+				   "Can't bring device back up after reset\n");
 			return;
 		}
 	}
@@ -4023,7 +3930,7 @@
 	int high_dma = 0;
 	u64 vpath_mask = 0;
 	struct vxgedev *vdev;
-	struct vxge_config ll_config;
+	struct vxge_config *ll_config = NULL;
 	struct vxge_hw_device_config *device_config = NULL;
 	struct vxge_hw_device_attr attr;
 	int i, j, no_of_vpath = 0, max_vpath_supported = 0;
@@ -4082,17 +3989,24 @@
 		goto _exit0;
 	}
 
-	memset(&ll_config, 0, sizeof(struct vxge_config));
-	ll_config.tx_steering_type = TX_MULTIQ_STEERING;
-	ll_config.intr_type = MSI_X;
-	ll_config.napi_weight = NEW_NAPI_WEIGHT;
-	ll_config.rth_steering = RTH_STEERING;
+	ll_config = kzalloc(sizeof(*ll_config), GFP_KERNEL);
+	if (!ll_config) {
+		ret = -ENOMEM;
+		vxge_debug_init(VXGE_ERR,
+			"ll_config : malloc failed %s %d",
+			__FILE__, __LINE__);
+		goto _exit0;
+	}
+	ll_config->tx_steering_type = TX_MULTIQ_STEERING;
+	ll_config->intr_type = MSI_X;
+	ll_config->napi_weight = NEW_NAPI_WEIGHT;
+	ll_config->rth_steering = RTH_STEERING;
 
 	/* get the default configuration parameters */
 	vxge_hw_device_config_default_get(device_config);
 
 	/* initialize configuration parameters */
-	vxge_device_config_init(device_config, &ll_config.intr_type);
+	vxge_device_config_init(device_config, &ll_config->intr_type);
 
 	ret = pci_enable_device(pdev);
 	if (ret) {
@@ -4145,7 +4059,7 @@
 		(unsigned long long)pci_resource_start(pdev, 0));
 
 	status = vxge_hw_device_hw_info_get(attr.bar0,
-			&ll_config.device_hw_info);
+			&ll_config->device_hw_info);
 	if (status != VXGE_HW_OK) {
 		vxge_debug_init(VXGE_ERR,
 			"%s: Reading of hardware info failed."
@@ -4154,7 +4068,7 @@
 		goto _exit3;
 	}
 
-	if (ll_config.device_hw_info.fw_version.major !=
+	if (ll_config->device_hw_info.fw_version.major !=
 		VXGE_DRIVER_FW_VERSION_MAJOR) {
 		vxge_debug_init(VXGE_ERR,
 			"%s: Incorrect firmware version."
@@ -4164,7 +4078,7 @@
 		goto _exit3;
 	}
 
-	vpath_mask = ll_config.device_hw_info.vpath_mask;
+	vpath_mask = ll_config->device_hw_info.vpath_mask;
 	if (vpath_mask == 0) {
 		vxge_debug_ll_config(VXGE_TRACE,
 			"%s: No vpaths available in device", VXGE_DRIVER_NAME);
@@ -4176,10 +4090,10 @@
 		"%s:%d  Vpath mask = %llx", __func__, __LINE__,
 		(unsigned long long)vpath_mask);
 
-	function_mode = ll_config.device_hw_info.function_mode;
-	host_type = ll_config.device_hw_info.host_type;
+	function_mode = ll_config->device_hw_info.function_mode;
+	host_type = ll_config->device_hw_info.host_type;
 	is_privileged = __vxge_hw_device_is_privilaged(host_type,
-		ll_config.device_hw_info.func_id);
+		ll_config->device_hw_info.func_id);
 
 	/* Check how many vpaths are available */
 	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
@@ -4193,7 +4107,7 @@
 
 	/* Enable SRIOV mode, if firmware has SRIOV support and if it is a PF */
 	if (is_sriov(function_mode) && (max_config_dev > 1) &&
-		(ll_config.intr_type != INTA) &&
+		(ll_config->intr_type != INTA) &&
 		(is_privileged == VXGE_HW_OK)) {
 		ret = pci_enable_sriov(pdev, ((max_config_dev - 1) < num_vfs)
 			? (max_config_dev - 1) : num_vfs);
@@ -4206,7 +4120,7 @@
 	 * Configure vpaths and get driver configured number of vpaths
 	 * which is less than or equal to the maximum vpaths per function.
 	 */
-	no_of_vpath = vxge_config_vpaths(device_config, vpath_mask, &ll_config);
+	no_of_vpath = vxge_config_vpaths(device_config, vpath_mask, ll_config);
 	if (!no_of_vpath) {
 		vxge_debug_ll_config(VXGE_ERR,
 			"%s: No more vpaths to configure", VXGE_DRIVER_NAME);
@@ -4241,21 +4155,21 @@
 	/* set private device info */
 	pci_set_drvdata(pdev, hldev);
 
-	ll_config.gro_enable = VXGE_GRO_ALWAYS_AGGREGATE;
-	ll_config.fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS;
-	ll_config.addr_learn_en = addr_learn_en;
-	ll_config.rth_algorithm = RTH_ALG_JENKINS;
-	ll_config.rth_hash_type_tcpipv4 = VXGE_HW_RING_HASH_TYPE_TCP_IPV4;
-	ll_config.rth_hash_type_ipv4 = VXGE_HW_RING_HASH_TYPE_NONE;
-	ll_config.rth_hash_type_tcpipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
-	ll_config.rth_hash_type_ipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
-	ll_config.rth_hash_type_tcpipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
-	ll_config.rth_hash_type_ipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
-	ll_config.rth_bkt_sz = RTH_BUCKET_SIZE;
-	ll_config.tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
-	ll_config.rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
+	ll_config->gro_enable = VXGE_GRO_ALWAYS_AGGREGATE;
+	ll_config->fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS;
+	ll_config->addr_learn_en = addr_learn_en;
+	ll_config->rth_algorithm = RTH_ALG_JENKINS;
+	ll_config->rth_hash_type_tcpipv4 = VXGE_HW_RING_HASH_TYPE_TCP_IPV4;
+	ll_config->rth_hash_type_ipv4 = VXGE_HW_RING_HASH_TYPE_NONE;
+	ll_config->rth_hash_type_tcpipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
+	ll_config->rth_hash_type_ipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
+	ll_config->rth_hash_type_tcpipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
+	ll_config->rth_hash_type_ipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
+	ll_config->rth_bkt_sz = RTH_BUCKET_SIZE;
+	ll_config->tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
+	ll_config->rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
 
-	if (vxge_device_register(hldev, &ll_config, high_dma, no_of_vpath,
+	if (vxge_device_register(hldev, ll_config, high_dma, no_of_vpath,
 		&vdev)) {
 		ret = -EINVAL;
 		goto _exit4;
@@ -4281,12 +4195,11 @@
 
 		vdev->vpaths[j].is_configured = 1;
 		vdev->vpaths[j].device_id = i;
-		vdev->vpaths[j].fifo.driver_id = j;
 		vdev->vpaths[j].ring.driver_id = j;
 		vdev->vpaths[j].vdev = vdev;
 		vdev->vpaths[j].max_mac_addr_cnt = max_mac_vpath;
 		memcpy((u8 *)vdev->vpaths[j].macaddr,
-				(u8 *)ll_config.device_hw_info.mac_addrs[i],
+				ll_config->device_hw_info.mac_addrs[i],
 				ETH_ALEN);
 
 		/* Initialize the mac address list header */
@@ -4307,18 +4220,18 @@
 
 	macaddr = (u8 *)vdev->vpaths[0].macaddr;
 
-	ll_config.device_hw_info.serial_number[VXGE_HW_INFO_LEN - 1] = '\0';
-	ll_config.device_hw_info.product_desc[VXGE_HW_INFO_LEN - 1] = '\0';
-	ll_config.device_hw_info.part_number[VXGE_HW_INFO_LEN - 1] = '\0';
+	ll_config->device_hw_info.serial_number[VXGE_HW_INFO_LEN - 1] = '\0';
+	ll_config->device_hw_info.product_desc[VXGE_HW_INFO_LEN - 1] = '\0';
+	ll_config->device_hw_info.part_number[VXGE_HW_INFO_LEN - 1] = '\0';
 
 	vxge_debug_init(VXGE_TRACE, "%s: SERIAL NUMBER: %s",
-		vdev->ndev->name, ll_config.device_hw_info.serial_number);
+		vdev->ndev->name, ll_config->device_hw_info.serial_number);
 
 	vxge_debug_init(VXGE_TRACE, "%s: PART NUMBER: %s",
-		vdev->ndev->name, ll_config.device_hw_info.part_number);
+		vdev->ndev->name, ll_config->device_hw_info.part_number);
 
 	vxge_debug_init(VXGE_TRACE, "%s: Neterion %s Server Adapter",
-		vdev->ndev->name, ll_config.device_hw_info.product_desc);
+		vdev->ndev->name, ll_config->device_hw_info.product_desc);
 
 	vxge_debug_init(VXGE_TRACE, "%s: MAC ADDR: %pM",
 		vdev->ndev->name, macaddr);
@@ -4328,11 +4241,11 @@
 
 	vxge_debug_init(VXGE_TRACE,
 		"%s: Firmware version : %s Date : %s", vdev->ndev->name,
-		ll_config.device_hw_info.fw_version.version,
-		ll_config.device_hw_info.fw_date.date);
+		ll_config->device_hw_info.fw_version.version,
+		ll_config->device_hw_info.fw_date.date);
 
 	if (new_device) {
-		switch (ll_config.device_hw_info.function_mode) {
+		switch (ll_config->device_hw_info.function_mode) {
 		case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION:
 			vxge_debug_init(VXGE_TRACE,
 			"%s: Single Function Mode Enabled", vdev->ndev->name);
@@ -4355,7 +4268,7 @@
 	vxge_print_parm(vdev, vpath_mask);
 
 	/* Store the fw version for ethttool option */
-	strcpy(vdev->fw_version, ll_config.device_hw_info.fw_version.version);
+	strcpy(vdev->fw_version, ll_config->device_hw_info.fw_version.version);
 	memcpy(vdev->ndev->dev_addr, (u8 *)vdev->vpaths[0].macaddr, ETH_ALEN);
 	memcpy(vdev->ndev->perm_addr, vdev->ndev->dev_addr, ETH_ALEN);
 
@@ -4394,7 +4307,7 @@
 	 * present to prevent such a failure.
 	 */
 
-	if (ll_config.device_hw_info.function_mode ==
+	if (ll_config->device_hw_info.function_mode ==
 		VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION)
 		if (vdev->config.intr_type == INTA)
 			vxge_hw_device_unmask_all(hldev);
@@ -4406,6 +4319,7 @@
 	VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev),
 		vxge_hw_device_trace_level_get(hldev));
 
+	kfree(ll_config);
 	return 0;
 
 _exit5:
@@ -4423,6 +4337,7 @@
 _exit1:
 	pci_disable_device(pdev);
 _exit0:
+	kfree(ll_config);
 	kfree(device_config);
 	driver_config->config_dev_cnt--;
 	pci_set_drvdata(pdev, NULL);
@@ -4514,13 +4429,9 @@
 vxge_starter(void)
 {
 	int ret = 0;
-	char version[32];
-	snprintf(version, 32, "%s", DRV_VERSION);
 
-	printk(KERN_INFO "%s: Copyright(c) 2002-2009 Neterion Inc\n",
-		VXGE_DRIVER_NAME);
-	printk(KERN_INFO "%s: Driver version: %s\n",
-			VXGE_DRIVER_NAME, version);
+	pr_info("Copyright(c) 2002-2010 Exar Corp.\n");
+	pr_info("Driver version: %s\n", DRV_VERSION);
 
 	verify_bandwidth();
 
diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h
index 60276b2..2e3b064 100644
--- a/drivers/net/vxge/vxge-main.h
+++ b/drivers/net/vxge/vxge-main.h
@@ -7,9 +7,9 @@
  * system is licensed under the GPL.
  * See the file COPYING in this distribution for more information.
  *
- * vxge-main.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-main.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
  *              Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
  ******************************************************************************/
 #ifndef VXGE_MAIN_H
 #define VXGE_MAIN_H
@@ -217,21 +217,13 @@
 };
 
 struct vxge_fifo {
-	struct net_device	*ndev;
-	struct pci_dev		*pdev;
+	struct net_device *ndev;
+	struct pci_dev *pdev;
 	struct __vxge_hw_fifo *handle;
+	struct netdev_queue *txq;
 
-	/* The vpath id maintained in the driver -
-	 * 0 to 'maximum_vpaths_in_function - 1'
-	 */
-	int driver_id;
 	int tx_steering_type;
 	int indicate_max_pkts;
-	spinlock_t tx_lock;
-	/* flag used to maintain queue state when MULTIQ is not enabled */
-#define VPATH_QUEUE_START       0
-#define VPATH_QUEUE_STOP        1
-	int queue_state;
 
 	/* Tx stats */
 	struct vxge_fifo_stats stats;
@@ -279,7 +271,6 @@
 } ____cacheline_aligned;
 
 struct vxge_vpath {
-
 	struct vxge_fifo fifo;
 	struct vxge_ring ring;
 
@@ -447,14 +438,6 @@
 
 enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev);
 
-void vxge_stop_all_tx_queue(struct vxgedev *vdev);
-
-void vxge_stop_tx_queue(struct vxge_fifo *fifo);
-
-void vxge_start_all_tx_queue(struct vxgedev *vdev);
-
-void vxge_wake_tx_queue(struct vxge_fifo *fifo, struct sk_buff *skb);
-
 enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev,
 	struct macInfo *mac);
 
diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h
index 9a0cf8e..3dd5c96 100644
--- a/drivers/net/vxge/vxge-reg.h
+++ b/drivers/net/vxge/vxge-reg.h
@@ -7,9 +7,9 @@
  * system is licensed under the GPL.
  * See the file COPYING in this distribution for more information.
  *
- * vxge-reg.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O Virtualized
+ * vxge-reg.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O Virtualized
  *             Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
  ******************************************************************************/
 #ifndef VXGE_REG_H
 #define VXGE_REG_H
diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c
index 6cc1dd7..cedf08f 100644
--- a/drivers/net/vxge/vxge-traffic.c
+++ b/drivers/net/vxge/vxge-traffic.c
@@ -7,9 +7,9 @@
  * system is licensed under the GPL.
  * See the file COPYING in this distribution for more information.
  *
- * vxge-traffic.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-traffic.c: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
  *                 Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
  ******************************************************************************/
 #include <linux/etherdevice.h>
 
@@ -2466,14 +2466,12 @@
  * the same.
  * @fifo: Handle to the fifo object used for non offload send
  *
- * The function	polls the Tx for the completed	descriptors and	calls
+ * The function polls the Tx for the completed descriptors and calls
  * the driver via supplied completion callback.
  *
  * Returns: VXGE_HW_OK, if the polling is completed successful.
  * VXGE_HW_COMPLETIONS_REMAIN: There are still more completed
  * descriptors available which are yet to be processed.
- *
- * See also: vxge_hw_vpath_poll_tx().
  */
 enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo,
 					struct sk_buff ***skb_ptr, int nr_skb,
diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h
index c252f3d..6fa07d1 100644
--- a/drivers/net/vxge/vxge-traffic.h
+++ b/drivers/net/vxge/vxge-traffic.h
@@ -7,9 +7,9 @@
  * system is licensed under the GPL.
  * See the file COPYING in this distribution for more information.
  *
- * vxge-traffic.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-traffic.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
  *                 Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
  ******************************************************************************/
 #ifndef VXGE_TRAFFIC_H
 #define VXGE_TRAFFIC_H
diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h
index 5da7ab1..53fefe1 100644
--- a/drivers/net/vxge/vxge-version.h
+++ b/drivers/net/vxge/vxge-version.h
@@ -7,17 +7,16 @@
  * system is licensed under the GPL.
  * See the file COPYING in this distribution for more information.
  *
- * vxge-version.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-version.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
  *                 Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
  ******************************************************************************/
 #ifndef VXGE_VERSION_H
-
 #define VXGE_VERSION_H
 
 #define VXGE_VERSION_MAJOR	"2"
 #define VXGE_VERSION_MINOR	"0"
-#define VXGE_VERSION_FIX	"8"
-#define VXGE_VERSION_BUILD	"20182"
+#define VXGE_VERSION_FIX	"9"
+#define VXGE_VERSION_BUILD	"20840"
 #define VXGE_VERSION_FOR	"k"
 #endif
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index f0bd70f..04c6cd4 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -89,7 +89,6 @@
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
 #include <linux/device.h>
-#include <linux/smp_lock.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
@@ -174,6 +173,7 @@
  * Character device major number. 117 was allocated for us.
  * The value of 0 means to allocate a first free one.
  */
+static DEFINE_MUTEX(cosa_chardev_mutex);
 static int cosa_major = 117;
 
 /*
@@ -944,7 +944,7 @@
 	int n;
 	int ret = 0;
 
-	lock_kernel();
+	mutex_lock(&cosa_chardev_mutex);
 	if ((n=iminor(file->f_path.dentry->d_inode)>>CARD_MINOR_BITS)
 		>= nr_cards) {
 		ret = -ENODEV;
@@ -976,7 +976,7 @@
 	chan->rx_done = chrdev_rx_done;
 	spin_unlock_irqrestore(&cosa->lock, flags);
 out:
-	unlock_kernel();
+	mutex_unlock(&cosa_chardev_mutex);
 	return ret;
 }
 
@@ -1212,10 +1212,10 @@
 	struct cosa_data *cosa;
 	long ret;
 
-	lock_kernel();
+	mutex_lock(&cosa_chardev_mutex);
 	cosa = channel->cosa;
 	ret = cosa_ioctl_common(cosa, channel, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&cosa_chardev_mutex);
 	return ret;
 }
 
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index e087b9a..ad7719f 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -15,6 +15,8 @@
  *      Maintainer:  Kevin Curtis  <kevin.curtis@farsite.co.uk>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/version.h>
@@ -511,21 +513,19 @@
  * support variable numbers of macro parameters. The inverted if prevents us
  * eating someone else's else clause.
  */
-#define dbg(F,fmt,A...) if ( ! ( fst_debug_mask & (F))) \
-                                ; \
-                        else \
-                                printk ( KERN_DEBUG FST_NAME ": " fmt, ## A )
-
+#define dbg(F, fmt, args...)					\
+do {								\
+	if (fst_debug_mask & (F))				\
+		printk(KERN_DEBUG pr_fmt(fmt), ##args);		\
+} while (0)
 #else
-#define dbg(X...)		/* NOP */
+#define dbg(F, fmt, args...)					\
+do {								\
+	if (0)							\
+		printk(KERN_DEBUG pr_fmt(fmt), ##args);		\
+} while (0)
 #endif
 
-/*      Printing short cuts
- */
-#define printk_err(fmt,A...)    printk ( KERN_ERR     FST_NAME ": " fmt, ## A )
-#define printk_warn(fmt,A...)   printk ( KERN_WARNING FST_NAME ": " fmt, ## A )
-#define printk_info(fmt,A...)   printk ( KERN_INFO    FST_NAME ": " fmt, ## A )
-
 /*
  *      PCI ID lookup table
  */
@@ -961,7 +961,7 @@
 		spin_lock_irqsave(&card->card_lock, flags);
 
 		if (++safety > 2000) {
-			printk_err("Mailbox safety timeout\n");
+			pr_err("Mailbox safety timeout\n");
 			break;
 		}
 
@@ -1241,8 +1241,8 @@
 		 * This seems to happen on the TE1 interface sometimes
 		 * so throw the frame away and log the event.
 		 */
-		printk_err("Frame received with 0 length. Card %d Port %d\n",
-			   card->card_no, port->index);
+		pr_err("Frame received with 0 length. Card %d Port %d\n",
+		       card->card_no, port->index);
 		/* Return descriptor to card */
 		FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);
 
@@ -1486,9 +1486,8 @@
 	 */
 	dbg(DBG_INTR, "intr: %d %p\n", card->irq, card);
 	if (card->state != FST_RUNNING) {
-		printk_err
-		    ("Interrupt received for card %d in a non running state (%d)\n",
-		     card->card_no, card->state);
+		pr_err("Interrupt received for card %d in a non running state (%d)\n",
+		       card->card_no, card->state);
 
 		/* 
 		 * It is possible to really be running, i.e. we have re-loaded
@@ -1614,8 +1613,7 @@
 			break;
 
 		default:
-			printk_err("intr: unknown card event %d. ignored\n",
-				   event);
+			pr_err("intr: unknown card event %d. ignored\n", event);
 			break;
 		}
 
@@ -1637,13 +1635,13 @@
 
 	/* Check structure version and end marker */
 	if (FST_RDW(card, smcVersion) != SMC_VERSION) {
-		printk_err("Bad shared memory version %d expected %d\n",
-			   FST_RDW(card, smcVersion), SMC_VERSION);
+		pr_err("Bad shared memory version %d expected %d\n",
+		       FST_RDW(card, smcVersion), SMC_VERSION);
 		card->state = FST_BADVERSION;
 		return;
 	}
 	if (FST_RDL(card, endOfSmcSignature) != END_SIG) {
-		printk_err("Missing shared memory signature\n");
+		pr_err("Missing shared memory signature\n");
 		card->state = FST_BADVERSION;
 		return;
 	}
@@ -1651,11 +1649,11 @@
 	if ((i = FST_RDB(card, taskStatus)) == 0x01) {
 		card->state = FST_RUNNING;
 	} else if (i == 0xFF) {
-		printk_err("Firmware initialisation failed. Card halted\n");
+		pr_err("Firmware initialisation failed. Card halted\n");
 		card->state = FST_HALTED;
 		return;
 	} else if (i != 0x00) {
-		printk_err("Unknown firmware status 0x%x\n", i);
+		pr_err("Unknown firmware status 0x%x\n", i);
 		card->state = FST_HALTED;
 		return;
 	}
@@ -1665,9 +1663,10 @@
 	 * existing firmware etc so we just report it for the moment.
 	 */
 	if (FST_RDL(card, numberOfPorts) != card->nports) {
-		printk_warn("Port count mismatch on card %d."
-			    " Firmware thinks %d we say %d\n", card->card_no,
-			    FST_RDL(card, numberOfPorts), card->nports);
+		pr_warning("Port count mismatch on card %d. "
+			   "Firmware thinks %d we say %d\n",
+			   card->card_no,
+			   FST_RDL(card, numberOfPorts), card->nports);
 	}
 }
 
@@ -2038,16 +2037,10 @@
 
 		/* Now copy the data to the card. */
 
-		buf = kmalloc(wrthdr.size, GFP_KERNEL);
-		if (!buf)
-			return -ENOMEM;
-
-		if (copy_from_user(buf,
-				   ifr->ifr_data + sizeof (struct fstioc_write),
-				   wrthdr.size)) {
-			kfree(buf);
-			return -EFAULT;
-		}
+		buf = memdup_user(ifr->ifr_data + sizeof(struct fstioc_write),
+				  wrthdr.size);
+		if (IS_ERR(buf))
+			return PTR_ERR(buf);
 
 		memcpy_toio(card->mem + wrthdr.offset, buf, wrthdr.size);
 		kfree(buf);
@@ -2096,9 +2089,8 @@
 		 */
 
 		if (card->state != FST_RUNNING) {
-			printk_err
-			    ("Attempt to configure card %d in non-running state (%d)\n",
-			     card->card_no, card->state);
+			pr_err("Attempt to configure card %d in non-running state (%d)\n",
+			       card->card_no, card->state);
 			return -EIO;
 		}
 		if (copy_from_user(&info, ifr->ifr_data, sizeof (info))) {
@@ -2390,8 +2382,8 @@
                 err = register_hdlc_device(card->ports[i].dev);
                 if (err < 0) {
 			int j;
-                        printk_err ("Cannot register HDLC device for port %d"
-                                    " (errno %d)\n", i, -err );
+			pr_err("Cannot register HDLC device for port %d (errno %d)\n",
+			       i, -err);
 			for (j = i; j < card->nports; j++) {
 				free_netdev(card->ports[j].dev);
 				card->ports[j].dev = NULL;
@@ -2401,10 +2393,10 @@
                 }
 	}
 
-	printk_info("%s-%s: %s IRQ%d, %d ports\n",
-	       port_to_dev(&card->ports[0])->name,
-	       port_to_dev(&card->ports[card->nports - 1])->name,
-	       type_strings[card->type], card->irq, card->nports);
+	pr_info("%s-%s: %s IRQ%d, %d ports\n",
+		port_to_dev(&card->ports[0])->name,
+		port_to_dev(&card->ports[card->nports - 1])->name,
+		type_strings[card->type], card->irq, card->nports);
 }
 
 static const struct net_device_ops fst_ops = {
@@ -2423,19 +2415,17 @@
 static int __devinit
 fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	static int firsttime_done = 0;
 	static int no_of_cards_added = 0;
 	struct fst_card_info *card;
 	int err = 0;
 	int i;
 
-	if (!firsttime_done) {
-		printk_info("FarSync WAN driver " FST_USER_VERSION
-		       " (c) 2001-2004 FarSite Communications Ltd.\n");
-		firsttime_done = 1;
-		dbg(DBG_ASS, "The value of debug mask is %x\n", fst_debug_mask);
-	}
-
+	printk_once(KERN_INFO
+		    pr_fmt("FarSync WAN driver " FST_USER_VERSION
+			   " (c) 2001-2004 FarSite Communications Ltd.\n"));
+#if FST_DEBUG
+	dbg(DBG_ASS, "The value of debug mask is %x\n", fst_debug_mask);
+#endif
 	/*
 	 * We are going to be clever and allow certain cards not to be
 	 * configured.  An exclude list can be provided in /etc/modules.conf
@@ -2447,8 +2437,8 @@
 		 */
 		for (i = 0; i < fst_excluded_cards; i++) {
 			if ((pdev->devfn) >> 3 == fst_excluded_list[i]) {
-				printk_info("FarSync PCI device %d not assigned\n",
-				       (pdev->devfn) >> 3);
+				pr_info("FarSync PCI device %d not assigned\n",
+					(pdev->devfn) >> 3);
 				return -EBUSY;
 			}
 		}
@@ -2457,20 +2447,19 @@
 	/* Allocate driver private data */
 	card = kzalloc(sizeof (struct fst_card_info), GFP_KERNEL);
 	if (card == NULL) {
-		printk_err("FarSync card found but insufficient memory for"
-			   " driver storage\n");
+		pr_err("FarSync card found but insufficient memory for driver storage\n");
 		return -ENOMEM;
 	}
 
 	/* Try to enable the device */
 	if ((err = pci_enable_device(pdev)) != 0) {
-		printk_err("Failed to enable card. Err %d\n", -err);
+		pr_err("Failed to enable card. Err %d\n", -err);
 		kfree(card);
 		return err;
 	}
 
 	if ((err = pci_request_regions(pdev, "FarSync")) !=0) {
-	        printk_err("Failed to allocate regions. Err %d\n", -err);
+		pr_err("Failed to allocate regions. Err %d\n", -err);
 		pci_disable_device(pdev);
 		kfree(card);
 	        return err;
@@ -2481,14 +2470,14 @@
 	card->phys_mem = pci_resource_start(pdev, 2);
 	card->phys_ctlmem = pci_resource_start(pdev, 3);
 	if ((card->mem = ioremap(card->phys_mem, FST_MEMSIZE)) == NULL) {
-		printk_err("Physical memory remap failed\n");
+		pr_err("Physical memory remap failed\n");
 		pci_release_regions(pdev);
 		pci_disable_device(pdev);
 		kfree(card);
 		return -ENODEV;
 	}
 	if ((card->ctlmem = ioremap(card->phys_ctlmem, 0x10)) == NULL) {
-		printk_err("Control memory remap failed\n");
+		pr_err("Control memory remap failed\n");
 		pci_release_regions(pdev);
 		pci_disable_device(pdev);
 		kfree(card);
@@ -2498,7 +2487,7 @@
 
 	/* Register the interrupt handler */
 	if (request_irq(pdev->irq, fst_intr, IRQF_SHARED, FST_DEV_NAME, card)) {
-		printk_err("Unable to register interrupt %d\n", card->irq);
+		pr_err("Unable to register interrupt %d\n", card->irq);
 		pci_release_regions(pdev);
 		pci_disable_device(pdev);
 		iounmap(card->ctlmem);
@@ -2529,7 +2518,7 @@
 		if (!dev) {
 			while (i--)
 				free_netdev(card->ports[i].dev);
-			printk_err ("FarSync: out of memory\n");
+			pr_err("FarSync: out of memory\n");
                         free_irq(card->irq, card);
                         pci_release_regions(pdev);
                         pci_disable_device(pdev);
@@ -2593,7 +2582,7 @@
 		    pci_alloc_consistent(card->device, FST_MAX_MTU,
 					 &card->rx_dma_handle_card);
 		if (card->rx_dma_handle_host == NULL) {
-			printk_err("Could not allocate rx dma buffer\n");
+			pr_err("Could not allocate rx dma buffer\n");
 			fst_disable_intr(card);
 			pci_release_regions(pdev);
 			pci_disable_device(pdev);
@@ -2606,7 +2595,7 @@
 		    pci_alloc_consistent(card->device, FST_MAX_MTU,
 					 &card->tx_dma_handle_card);
 		if (card->tx_dma_handle_host == NULL) {
-			printk_err("Could not allocate tx dma buffer\n");
+			pr_err("Could not allocate tx dma buffer\n");
 			fst_disable_intr(card);
 			pci_release_regions(pdev);
 			pci_disable_device(pdev);
@@ -2678,7 +2667,7 @@
 static void __exit
 fst_cleanup_module(void)
 {
-	printk_info("FarSync WAN driver unloading\n");
+	pr_info("FarSync WAN driver unloading\n");
 	pci_unregister_driver(&fst_driver);
 }
 
diff --git a/drivers/net/wan/hd64570.h b/drivers/net/wan/hd64570.h
index 3839662..e4f539a 100644
--- a/drivers/net/wan/hd64570.h
+++ b/drivers/net/wan/hd64570.h
@@ -153,7 +153,7 @@
 	u16 len;		/* Data Length */
 	u8 stat;		/* Status */
 	u8 unused;		/* pads to 2-byte boundary */
-}__attribute__ ((packed)) pkt_desc;
+}__packed pkt_desc;
 
 
 /* Packet Descriptor Status bits */
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index ee7083f..b38ffa1 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -36,7 +36,7 @@
 	u8 address;
 	u8 control;
 	__be16 protocol;
-}__attribute__ ((packed));
+}__packed;
 
 
 struct cisco_packet {
@@ -45,7 +45,7 @@
 	__be32 par2;
 	__be16 rel;		/* reliability */
 	__be32 time;
-}__attribute__ ((packed));
+}__packed;
 #define	CISCO_PACKET_LEN	18
 #define	CISCO_BIG_PACKET_LEN	20
 
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 0e52993..0edb535 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -112,7 +112,7 @@
 	unsigned de:	1;
 	unsigned ea2:	1;
 #endif
-}__attribute__ ((packed)) fr_hdr;
+}__packed fr_hdr;
 
 
 typedef struct pvc_device_struct {
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 43ae6f4..f4125da 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -330,7 +330,7 @@
 {
 	short dlci;
 	char  flags;
-} __attribute__((packed));
+} __packed;
 
 struct _frad_stat 
 {
@@ -1211,14 +1211,9 @@
 	}
 	else
 	{
-		temp = kmalloc(mem.len, GFP_KERNEL);
-		if (!temp)
-			return(-ENOMEM);
-		if(copy_from_user(temp, mem.data, mem.len))
-		{
-			kfree(temp);
-			return -EFAULT;
-		}
+		temp = memdup_user(mem.data, mem.len);
+		if (IS_ERR(temp))
+			return PTR_ERR(temp);
 		sdla_write(dev, mem.addr, temp, mem.len);
 		kfree(temp);
 	}
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index 746a5ee..eb72c67 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -358,8 +358,10 @@
 #endif
 
 	err = register_netdev(dev);
-	if (err)
+	if (err) {
 		free_irq(dev->irq, dev);
+		iounmap(ei_status.mem);
+	}
 	return err;
 }
 
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index 7f48e04..9fb0308 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -848,7 +848,7 @@
 	struct i2400m_l3l4_hdr hdr;
 	struct i2400m_tlv_hdr tlv;
 	__le32 val;
-} __attribute__((packed));
+} __packed;
 
 
 /*
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 1149135..8b55a5b 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -651,7 +651,7 @@
 	struct {
 		struct i2400m_bootrom_header cmd;
 		u8 cmd_payload[chunk_len];
-	} __attribute__((packed)) *buf;
+	} __packed *buf;
 	struct i2400m_bootrom_header ack;
 
 	d_fnstart(5, dev, "(i2400m %p chunk %p __chunk_len %zu addr 0x%08lx "
@@ -794,7 +794,7 @@
 	struct {
 		struct i2400m_bootrom_header cmd;
 		u8 cmd_pl[0];
-	} __attribute__((packed)) *cmd_buf;
+	} __packed *cmd_buf;
 	size_t signature_block_offset, signature_block_size;
 
 	d_fnstart(3, dev, "offset %zu\n", offset);
@@ -1029,7 +1029,7 @@
 	struct {
 		struct i2400m_bootrom_header ack;
 		u8 ack_pl[16];
-	} __attribute__((packed)) ack_buf;
+	} __packed ack_buf;
 
 	d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
 	cmd = i2400m->bm_cmd_buf;
@@ -1115,7 +1115,7 @@
 	struct {
 		struct i2400m_bootrom_header cmd;
 		struct i2400m_bcf_hdr cmd_pl;
-	} __attribute__((packed)) *cmd_buf;
+	} __packed *cmd_buf;
 	struct i2400m_bootrom_header ack;
 
 	d_fnstart(5, dev, "(i2400m %p bcf_hdr %p)\n", i2400m, bcf_hdr);
diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c
index 035e4cf..9e02b90 100644
--- a/drivers/net/wimax/i2400m/op-rfkill.c
+++ b/drivers/net/wimax/i2400m/op-rfkill.c
@@ -91,7 +91,7 @@
 	struct {
 		struct i2400m_l3l4_hdr hdr;
 		struct i2400m_tlv_rf_operation sw_rf;
-	} __attribute__((packed)) *cmd;
+	} __packed *cmd;
 	char strerr[32];
 
 	d_fnstart(4, dev, "(wimax_dev %p state %d)\n", wimax_dev, state);
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 880ad9d..a105087 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -373,8 +373,8 @@
 		pktlen = status & RDES0_STATUS_FL;
 		if (pktlen > RX_PKT_SIZE) {
 			if (net_ratelimit())
-				printk(KERN_DEBUG "%s: frame too long (%d)\n",
-				       wiphy_name(dev->wiphy), pktlen);
+				wiphy_debug(dev->wiphy, "frame too long (%d)\n",
+					    pktlen);
 			pktlen = RX_PKT_SIZE;
 		}
 
@@ -454,10 +454,10 @@
 
 static irqreturn_t adm8211_interrupt(int irq, void *dev_id)
 {
-#define ADM8211_INT(x)							   \
-do {									   \
-	if (unlikely(stsr & ADM8211_STSR_ ## x))			   \
-		printk(KERN_DEBUG "%s: " #x "\n", wiphy_name(dev->wiphy)); \
+#define ADM8211_INT(x)						\
+do {								\
+	if (unlikely(stsr & ADM8211_STSR_ ## x))		\
+		wiphy_debug(dev->wiphy, "%s\n", #x);		\
 } while (0)
 
 	struct ieee80211_hw *dev = dev_id;
@@ -570,9 +570,9 @@
 	}
 
 	if (timeout == 0) {
-		printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed"
-		       " prewrite (reg=0x%08x)\n",
-		       wiphy_name(dev->wiphy), addr, data, reg);
+		wiphy_debug(dev->wiphy,
+			    "adm8211_write_bbp(%d,%d) failed prewrite (reg=0x%08x)\n",
+			    addr, data, reg);
 		return -ETIMEDOUT;
 	}
 
@@ -605,9 +605,9 @@
 	if (timeout == 0) {
 		ADM8211_CSR_WRITE(BBPCTL, ADM8211_CSR_READ(BBPCTL) &
 				  ~ADM8211_BBPCTL_WR);
-		printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed"
-		       " postwrite (reg=0x%08x)\n",
-		       wiphy_name(dev->wiphy), addr, data, reg);
+		wiphy_debug(dev->wiphy,
+			    "adm8211_write_bbp(%d,%d) failed postwrite (reg=0x%08x)\n",
+			    addr, data, reg);
 		return -ETIMEDOUT;
 	}
 
@@ -675,8 +675,8 @@
 		break;
 
 	default:
-		printk(KERN_DEBUG "%s: unsupported transceiver type %d\n",
-		       wiphy_name(dev->wiphy), priv->transceiver_type);
+		wiphy_debug(dev->wiphy, "unsupported transceiver type %d\n",
+			    priv->transceiver_type);
 		break;
 	}
 
@@ -732,8 +732,8 @@
 
 	/* Nothing to do for ADMtek BBP */
 	} else if (priv->bbp_type != ADM8211_TYPE_ADMTEK)
-		printk(KERN_DEBUG "%s: unsupported BBP type %d\n",
-		       wiphy_name(dev->wiphy), priv->bbp_type);
+		wiphy_debug(dev->wiphy, "unsupported bbp type %d\n",
+			    priv->bbp_type);
 
 	ADM8211_RESTORE();
 
@@ -1027,13 +1027,12 @@
 			break;
 
 		default:
-			printk(KERN_DEBUG "%s: unsupported transceiver %d\n",
-			       wiphy_name(dev->wiphy), priv->transceiver_type);
+			wiphy_debug(dev->wiphy, "unsupported transceiver %d\n",
+				    priv->transceiver_type);
 			break;
 		}
 	} else
-		printk(KERN_DEBUG "%s: unsupported BBP %d\n",
-		       wiphy_name(dev->wiphy), priv->bbp_type);
+		wiphy_debug(dev->wiphy, "unsupported bbp %d\n", priv->bbp_type);
 
 	ADM8211_CSR_WRITE(SYNRF, 0);
 
@@ -1509,15 +1508,13 @@
 	/* Power up MAC and RF chips */
 	retval = adm8211_hw_reset(dev);
 	if (retval) {
-		printk(KERN_ERR "%s: hardware reset failed\n",
-		       wiphy_name(dev->wiphy));
+		wiphy_err(dev->wiphy, "hardware reset failed\n");
 		goto fail;
 	}
 
 	retval = adm8211_init_rings(dev);
 	if (retval) {
-		printk(KERN_ERR "%s: failed to initialize rings\n",
-		       wiphy_name(dev->wiphy));
+		wiphy_err(dev->wiphy, "failed to initialize rings\n");
 		goto fail;
 	}
 
@@ -1528,8 +1525,7 @@
 	retval = request_irq(priv->pdev->irq, adm8211_interrupt,
 			     IRQF_SHARED, "adm8211", dev);
 	if (retval) {
-		printk(KERN_ERR "%s: failed to register IRQ handler\n",
-		       wiphy_name(dev->wiphy));
+		wiphy_err(dev->wiphy, "failed to register irq handler\n");
 		goto fail;
 	}
 
@@ -1903,15 +1899,17 @@
 	if (err) {
 		printk(KERN_ERR "%s (adm8211): Cannot register device\n",
 		       pci_name(pdev));
-		goto err_free_desc;
+		goto err_free_eeprom;
 	}
 
-	printk(KERN_INFO "%s: hwaddr %pM, Rev 0x%02x\n",
-	       wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
-	       pdev->revision);
+	wiphy_info(dev->wiphy, "hwaddr %pm, rev 0x%02x\n",
+		   dev->wiphy->perm_addr, pdev->revision);
 
 	return 0;
 
+ err_free_eeprom:
+	kfree(priv->eeprom);
+
  err_free_desc:
 	pci_free_consistent(pdev,
 			    sizeof(struct adm8211_desc) * priv->rx_ring_size +
diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h
index b07e4d3..bbc10b1 100644
--- a/drivers/net/wireless/adm8211.h
+++ b/drivers/net/wireless/adm8211.h
@@ -80,7 +80,7 @@
 	__le32 FEMR;		/* 0x104 */
 	__le32 FPSR;		/* 0x108 */
 	__le32 FFER;		/* 0x10C */
-} __attribute__ ((packed));
+} __packed;
 
 /* CSR0 - PAR (PCI Address Register) */
 #define ADM8211_PAR_MWIE	(1 << 24)
@@ -484,7 +484,7 @@
 	u8 entry_control;	// huh??
 	u16 reserved_1;
 	u32 reserved_2;
-} __attribute__ ((packed));
+} __packed;
 
 
 #define RX_COPY_BREAK 128
@@ -531,7 +531,7 @@
 	u8	lnags_threshold[14];	/* 0x70 */
 	__le16	checksum;		/* 0x7E */
 	u8	cis_data[0];		/* 0x80, 384 bytes */
-} __attribute__ ((packed));
+} __packed;
 
 struct adm8211_priv {
 	struct pci_dev *pdev;
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 3b7ab20..1d05445 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -506,20 +506,20 @@
 	u8 mac[ETH_ALEN];
 	__le16 klen;
 	u8 key[16];
-} __attribute__ ((packed));
+} __packed;
 
 /* These structures are from the Aironet's PC4500 Developers Manual */
 typedef struct Ssid Ssid;
 struct Ssid {
 	__le16 len;
 	u8 ssid[32];
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct SsidRid SsidRid;
 struct SsidRid {
 	__le16 len;
 	Ssid ssids[3];
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct ModulationRid ModulationRid;
 struct ModulationRid {
@@ -528,7 +528,7 @@
 #define MOD_DEFAULT cpu_to_le16(0)
 #define MOD_CCK cpu_to_le16(1)
 #define MOD_MOK cpu_to_le16(2)
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct ConfigRid ConfigRid;
 struct ConfigRid {
@@ -652,7 +652,7 @@
 #define MAGIC_STAY_IN_CAM (1<<10)
 	u8 magicControl;
 	__le16 autoWake;
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct StatusRid StatusRid;
 struct StatusRid {
@@ -711,20 +711,20 @@
 #define STAT_LEAPFAILED 91
 #define STAT_LEAPTIMEDOUT 92
 #define STAT_LEAPCOMPLETE 93
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct StatsRid StatsRid;
 struct StatsRid {
 	__le16 len;
 	__le16 spacer;
 	__le32 vals[100];
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct APListRid APListRid;
 struct APListRid {
 	__le16 len;
 	u8 ap[4][ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct CapabilityRid CapabilityRid;
 struct CapabilityRid {
@@ -754,7 +754,7 @@
 	__le16 bootBlockVer;
 	__le16 requiredHard;
 	__le16 extSoftCap;
-} __attribute__ ((packed));
+} __packed;
 
 /* Only present on firmware >= 5.30.17 */
 typedef struct BSSListRidExtra BSSListRidExtra;
@@ -762,7 +762,7 @@
   __le16 unknown[4];
   u8 fixed[12]; /* WLAN management frame */
   u8 iep[624];
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct BSSListRid BSSListRid;
 struct BSSListRid {
@@ -796,7 +796,7 @@
 
   /* Only present on firmware >= 5.30.17 */
   BSSListRidExtra extra;
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct {
   BSSListRid bss;
@@ -807,13 +807,13 @@
 struct tdsRssiEntry {
   u8 rssipct;
   u8 rssidBm;
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct tdsRssiRid tdsRssiRid;
 struct tdsRssiRid {
   u16 len;
   tdsRssiEntry x[256];
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct MICRid MICRid;
 struct MICRid {
@@ -823,7 +823,7 @@
 	u8  multicast[16];
 	__le16 unicastValid;
 	u8  unicast[16];
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct MICBuffer MICBuffer;
 struct MICBuffer {
@@ -841,7 +841,7 @@
 	} u;
 	__be32 mic;
 	__be32 seq;
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct {
 	u8 da[ETH_ALEN];
@@ -996,7 +996,7 @@
 	u8 rate;
 	u8 freq;
 	__le16 tmp[4];
-} __attribute__ ((packed));
+} __packed;
 
 typedef struct {
 	unsigned int  ctl: 15;
@@ -2931,8 +2931,8 @@
 	        release_region( dev->base_addr, 64 );
 err_out_nets:
 	airo_networks_free(ai);
-	del_airo_dev(ai);
 err_out_free:
+	del_airo_dev(ai);
 	free_netdev(dev);
 	return NULL;
 }
@@ -4657,7 +4657,7 @@
 			   loff_t *offset )
 {
 	loff_t pos = *offset;
-	struct proc_data *priv = (struct proc_data*)file->private_data;
+	struct proc_data *priv = file->private_data;
 
 	if (!priv->wbuffer)
 		return -EINVAL;
@@ -4689,7 +4689,7 @@
 
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	data = (struct proc_data *)file->private_data;
+	data = file->private_data;
 	if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
 		return -ENOMEM;
@@ -4772,7 +4772,7 @@
 
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	data = (struct proc_data *)file->private_data;
+	data = file->private_data;
 	if ((data->rbuffer = kmalloc( 4096, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
 		return -ENOMEM;
@@ -5045,7 +5045,7 @@
 
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	data = (struct proc_data *)file->private_data;
+	data = file->private_data;
 	if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
 		return -ENOMEM;
@@ -5127,7 +5127,7 @@
 
 static void proc_SSID_on_close(struct inode *inode, struct file *file)
 {
-	struct proc_data *data = (struct proc_data *)file->private_data;
+	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->ml_priv;
@@ -5163,7 +5163,7 @@
 }
 
 static void proc_APList_on_close( struct inode *inode, struct file *file ) {
-	struct proc_data *data = (struct proc_data *)file->private_data;
+	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->ml_priv;
@@ -5309,7 +5309,7 @@
 
 	memset(key, 0, sizeof(key));
 
-	data = (struct proc_data *)file->private_data;
+	data = file->private_data;
 	if ( !data->writelen ) return;
 
 	if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' &&
@@ -5363,7 +5363,7 @@
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(&wkr, 0, sizeof(wkr));
-	data = (struct proc_data *)file->private_data;
+	data = file->private_data;
 	if ((data->rbuffer = kzalloc( 180, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
 		return -ENOMEM;
@@ -5409,7 +5409,7 @@
 
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	data = (struct proc_data *)file->private_data;
+	data = file->private_data;
 	if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
 		return -ENOMEM;
@@ -5453,7 +5453,7 @@
 
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	data = (struct proc_data *)file->private_data;
+	data = file->private_data;
 	if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
 		return -ENOMEM;
@@ -5495,7 +5495,7 @@
 
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	data = (struct proc_data *)file->private_data;
+	data = file->private_data;
 	if ((data->rbuffer = kmalloc( 1024, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
 		return -ENOMEM;
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 8a2d4af..d5140a8 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -7,6 +7,7 @@
  * Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com>
  * Copyright (c) 2007 Guido Guenther <agx@sigxcpu.org>
  * Copyright (c) 2007 Kalle Valo <kalle.valo@iki.fi>
+ * Copyright (c) 2010 Sebastian Smolorz <sesmo@gmx.net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -88,22 +89,19 @@
 #define DBG_DEFAULTS		0
 
 /* Use our own dbg macro */
-#define at76_dbg(bits, format, arg...) \
-	do { \
-		if (at76_debug & (bits))				 \
-			printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , \
-			       ## arg);					 \
-	} while (0)
+#define at76_dbg(bits, format, arg...)					\
+do {									\
+	if (at76_debug & (bits))					\
+		printk(KERN_DEBUG DRIVER_NAME ": " format "\n", ##arg);	\
+} while (0)
 
-#define at76_dbg_dump(bits, buf, len, format, arg...)	\
-	do { \
-		if (at76_debug & (bits)) { \
-			printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , \
-			       ## arg);					 \
-			print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,     \
-					     buf, len);			 \
-		}							 \
-	} while (0)
+#define at76_dbg_dump(bits, buf, len, format, arg...)			\
+do {									\
+	if (at76_debug & (bits)) {					\
+		printk(KERN_DEBUG DRIVER_NAME ": " format "\n", ##arg);	\
+		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len);	\
+	}								\
+} while (0)
 
 static uint at76_debug = DBG_DEFAULTS;
 
@@ -305,7 +303,7 @@
 	unsigned char poll_timeout[3];
 	unsigned char state;
 	unsigned char string;
-} __attribute__((packed));
+} __packed;
 
 static inline int at76_is_intersil(enum board_type board)
 {
@@ -657,8 +655,8 @@
 exit:
 	kfree(hwcfg);
 	if (ret < 0)
-		printk(KERN_ERR "%s: cannot get HW Config (error %d)\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy, "cannot get hw config (error %d)\n",
+			  ret);
 
 	return ret;
 }
@@ -793,8 +791,9 @@
 	do {
 		status = at76_get_cmd_status(priv->udev, cmd);
 		if (status < 0) {
-			printk(KERN_ERR "%s: at76_get_cmd_status failed: %d\n",
-			       wiphy_name(priv->hw->wiphy), status);
+			wiphy_err(priv->hw->wiphy,
+				  "at76_get_cmd_status failed: %d\n",
+				  status);
 			break;
 		}
 
@@ -809,9 +808,8 @@
 
 		schedule_timeout_interruptible(HZ / 10);	/* 100 ms */
 		if (time_after(jiffies, timeout)) {
-			printk(KERN_ERR
-			       "%s: completion timeout for command %d\n",
-			       wiphy_name(priv->hw->wiphy), cmd);
+			wiphy_err(priv->hw->wiphy,
+				  "completion timeout for command %d\n", cmd);
 			status = -ETIMEDOUT;
 			break;
 		}
@@ -832,9 +830,9 @@
 
 	ret = at76_wait_completion(priv, CMD_SET_MIB);
 	if (ret != CMD_STATUS_COMPLETE) {
-		printk(KERN_INFO
-		       "%s: set_mib: at76_wait_completion failed "
-		       "with %d\n", wiphy_name(priv->hw->wiphy), ret);
+		wiphy_info(priv->hw->wiphy,
+			   "set_mib: at76_wait_completion failed with %d\n",
+			   ret);
 		ret = -EIO;
 	}
 
@@ -854,8 +852,8 @@
 
 	ret = at76_set_card_command(priv->udev, cmd, NULL, 0);
 	if (ret < 0)
-		printk(KERN_ERR "%s: at76_set_card_command(%d) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), cmd, ret);
+		wiphy_err(priv->hw->wiphy,
+			  "at76_set_card_command(%d) failed: %d\n", cmd, ret);
 	else
 		ret = 1;
 
@@ -875,8 +873,8 @@
 
 	ret = at76_set_mib(priv, &priv->mib_buf);
 	if (ret < 0)
-		printk(KERN_ERR "%s: set_mib (pm_mode) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy, "set_mib (pm_mode) failed: %d\n",
+			  ret);
 
 	return ret;
 }
@@ -892,8 +890,8 @@
 
 	ret = at76_set_mib(priv, &priv->mib_buf);
 	if (ret < 0)
-		printk(KERN_ERR "%s: set_mib (preamble) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy, "set_mib (preamble) failed: %d\n",
+			  ret);
 
 	return ret;
 }
@@ -909,8 +907,8 @@
 
 	ret = at76_set_mib(priv, &priv->mib_buf);
 	if (ret < 0)
-		printk(KERN_ERR "%s: set_mib (frag threshold) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy,
+			  "set_mib (frag threshold) failed: %d\n", ret);
 
 	return ret;
 }
@@ -926,8 +924,7 @@
 
 	ret = at76_set_mib(priv, &priv->mib_buf);
 	if (ret < 0)
-		printk(KERN_ERR "%s: set_mib (rts) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy, "set_mib (rts) failed: %d\n", ret);
 
 	return ret;
 }
@@ -943,8 +940,8 @@
 
 	ret = at76_set_mib(priv, &priv->mib_buf);
 	if (ret < 0)
-		printk(KERN_ERR "%s: set_mib (autorate fallback) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy,
+			  "set_mib (autorate fallback) failed: %d\n", ret);
 
 	return ret;
 }
@@ -962,8 +959,8 @@
 	ret = at76_get_mib(priv->udev, MIB_MAC_ADDR, m,
 			   sizeof(struct mib_mac_addr));
 	if (ret < 0) {
-		printk(KERN_ERR "%s: at76_get_mib (MAC_ADDR) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy,
+			  "at76_get_mib (mac_addr) failed: %d\n", ret);
 		goto exit;
 	}
 
@@ -991,8 +988,8 @@
 	ret = at76_get_mib(priv->udev, MIB_MAC_WEP, m,
 			   sizeof(struct mib_mac_wep));
 	if (ret < 0) {
-		printk(KERN_ERR "%s: at76_get_mib (MAC_WEP) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy,
+			  "at76_get_mib (mac_wep) failed: %d\n", ret);
 		goto exit;
 	}
 
@@ -1028,8 +1025,8 @@
 	ret = at76_get_mib(priv->udev, MIB_MAC_MGMT, m,
 			   sizeof(struct mib_mac_mgmt));
 	if (ret < 0) {
-		printk(KERN_ERR "%s: at76_get_mib (MAC_MGMT) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy,
+			  "at76_get_mib (mac_mgmt) failed: %d\n", ret);
 		goto exit;
 	}
 
@@ -1064,8 +1061,8 @@
 
 	ret = at76_get_mib(priv->udev, MIB_MAC, m, sizeof(struct mib_mac));
 	if (ret < 0) {
-		printk(KERN_ERR "%s: at76_get_mib (MAC) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy,
+			  "at76_get_mib (mac) failed: %d\n", ret);
 		goto exit;
 	}
 
@@ -1101,8 +1098,8 @@
 
 	ret = at76_get_mib(priv->udev, MIB_PHY, m, sizeof(struct mib_phy));
 	if (ret < 0) {
-		printk(KERN_ERR "%s: at76_get_mib (PHY) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy,
+			  "at76_get_mib (phy) failed: %d\n", ret);
 		goto exit;
 	}
 
@@ -1134,8 +1131,8 @@
 
 	ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(struct mib_local));
 	if (ret < 0) {
-		printk(KERN_ERR "%s: at76_get_mib (LOCAL) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy,
+			  "at76_get_mib (local) failed: %d\n", ret);
 		goto exit;
 	}
 
@@ -1160,8 +1157,8 @@
 	ret = at76_get_mib(priv->udev, MIB_MDOMAIN, m,
 			   sizeof(struct mib_mdomain));
 	if (ret < 0) {
-		printk(KERN_ERR "%s: at76_get_mib (MDOMAIN) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy,
+			  "at76_get_mib (mdomain) failed: %d\n", ret);
 		goto exit;
 	}
 
@@ -1232,16 +1229,16 @@
 	struct sk_buff *skb = priv->rx_skb;
 
 	if (!priv->rx_urb) {
-		printk(KERN_ERR "%s: %s: priv->rx_urb is NULL\n",
-		       wiphy_name(priv->hw->wiphy), __func__);
+		wiphy_err(priv->hw->wiphy, "%s: priv->rx_urb is null\n",
+			  __func__);
 		return -EFAULT;
 	}
 
 	if (!skb) {
 		skb = dev_alloc_skb(sizeof(struct at76_rx_buffer));
 		if (!skb) {
-			printk(KERN_ERR "%s: cannot allocate rx skbuff\n",
-			       wiphy_name(priv->hw->wiphy));
+			wiphy_err(priv->hw->wiphy,
+				  "cannot allocate rx skbuff\n");
 			ret = -ENOMEM;
 			goto exit;
 		}
@@ -1260,15 +1257,14 @@
 			at76_dbg(DBG_DEVSTART,
 				 "usb_submit_urb returned -ENODEV");
 		else
-			printk(KERN_ERR "%s: rx, usb_submit_urb failed: %d\n",
-			       wiphy_name(priv->hw->wiphy), ret);
+			wiphy_err(priv->hw->wiphy,
+				  "rx, usb_submit_urb failed: %d\n", ret);
 	}
 
 exit:
 	if (ret < 0 && ret != -ENODEV)
-		printk(KERN_ERR "%s: cannot submit rx urb - please unload the "
-		       "driver and/or power cycle the device\n",
-		       wiphy_name(priv->hw->wiphy));
+		wiphy_err(priv->hw->wiphy,
+			  "cannot submit rx urb - please unload the driver and/or power cycle the device\n");
 
 	return ret;
 }
@@ -1437,8 +1433,8 @@
 	ret = at76_set_card_command(priv->udev, CMD_STARTUP, &priv->card_config,
 				    sizeof(struct at76_card_config));
 	if (ret < 0) {
-		printk(KERN_ERR "%s: at76_set_card_command failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy, "at76_set_card_command failed: %d\n",
+			  ret);
 		return ret;
 	}
 
@@ -1503,8 +1499,8 @@
 
 	ret = at76_set_mib(priv, &priv->mib_buf);
 	if (ret < 0)
-		printk(KERN_ERR "%s: set_mib (promiscuous_mode) failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy,
+			  "set_mib (promiscuous_mode) failed: %d\n", ret);
 
 	mutex_unlock(&priv->mtx);
 }
@@ -1649,6 +1645,58 @@
 		return NULL;
 }
 
+static int at76_join(struct at76_priv *priv)
+{
+	struct at76_req_join join;
+	int ret;
+
+	memset(&join, 0, sizeof(struct at76_req_join));
+	memcpy(join.essid, priv->essid, priv->essid_size);
+	join.essid_size = priv->essid_size;
+	memcpy(join.bssid, priv->bssid, ETH_ALEN);
+	join.bss_type = INFRASTRUCTURE_MODE;
+	join.channel = priv->channel;
+	join.timeout = cpu_to_le16(2000);
+
+	at76_dbg(DBG_MAC80211, "%s: sending CMD_JOIN", __func__);
+	ret = at76_set_card_command(priv->udev, CMD_JOIN, &join,
+				    sizeof(struct at76_req_join));
+
+	if (ret < 0) {
+		wiphy_err(priv->hw->wiphy, "at76_set_card_command failed: %d\n",
+			  ret);
+		return 0;
+	}
+
+	ret = at76_wait_completion(priv, CMD_JOIN);
+	at76_dbg(DBG_MAC80211, "%s: CMD_JOIN returned: 0x%02x", __func__, ret);
+	if (ret != CMD_STATUS_COMPLETE) {
+		wiphy_err(priv->hw->wiphy, "at76_wait_completion failed: %d\n",
+			  ret);
+		return 0;
+	}
+
+	at76_set_pm_mode(priv);
+
+	return 0;
+}
+
+static void at76_work_join_bssid(struct work_struct *work)
+{
+	struct at76_priv *priv = container_of(work, struct at76_priv,
+					      work_join_bssid);
+
+	if (priv->device_unplugged)
+		return;
+
+	mutex_lock(&priv->mtx);
+
+	if (is_valid_ether_addr(priv->bssid))
+		at76_join(priv);
+
+	mutex_unlock(&priv->mtx);
+}
+
 static void at76_mac80211_tx_callback(struct urb *urb)
 {
 	struct at76_priv *priv = urb->context;
@@ -1686,16 +1734,32 @@
 	struct at76_priv *priv = hw->priv;
 	struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
 	int padding, submit_len, ret;
 
 	at76_dbg(DBG_MAC80211, "%s()", __func__);
 
 	if (priv->tx_urb->status == -EINPROGRESS) {
-		printk(KERN_ERR "%s: %s called while tx urb is pending\n",
-		       wiphy_name(priv->hw->wiphy), __func__);
+		wiphy_err(priv->hw->wiphy,
+			  "%s called while tx urb is pending\n", __func__);
 		return NETDEV_TX_BUSY;
 	}
 
+	/* The following code lines are important when the device is going to
+	 * authenticate with a new bssid. The driver must send CMD_JOIN before
+	 * an authentication frame is transmitted. For this to succeed, the
+	 * correct bssid of the AP must be known. As mac80211 does not inform
+	 * drivers about the bssid prior to the authentication process the
+	 * following workaround is necessary. If the TX frame is an
+	 * authentication frame extract the bssid and send the CMD_JOIN. */
+	if (mgmt->frame_control & cpu_to_le16(IEEE80211_STYPE_AUTH)) {
+		if (compare_ether_addr(priv->bssid, mgmt->bssid)) {
+			memcpy(priv->bssid, mgmt->bssid, ETH_ALEN);
+			ieee80211_queue_work(hw, &priv->work_join_bssid);
+			return NETDEV_TX_BUSY;
+		}
+	}
+
 	ieee80211_stop_queues(hw);
 
 	at76_ledtrig_tx_activity();	/* tell ledtrigger we send a packet */
@@ -1725,13 +1789,12 @@
 			  submit_len, at76_mac80211_tx_callback, priv);
 	ret = usb_submit_urb(priv->tx_urb, GFP_ATOMIC);
 	if (ret) {
-		printk(KERN_ERR "%s: error in tx submit urb: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy, "error in tx submit urb: %d\n", ret);
 		if (ret == -EINVAL)
-			printk(KERN_ERR
-			       "%s: -EINVAL: tx urb %p hcpriv %p complete %p\n",
-			       wiphy_name(priv->hw->wiphy), priv->tx_urb,
-			       priv->tx_urb->hcpriv, priv->tx_urb->complete);
+			wiphy_err(priv->hw->wiphy,
+				  "-einval: tx urb %p hcpriv %p complete %p\n",
+				  priv->tx_urb,
+				  priv->tx_urb->hcpriv, priv->tx_urb->complete);
 	}
 
 	return 0;
@@ -1748,8 +1811,8 @@
 
 	ret = at76_submit_rx_urb(priv);
 	if (ret < 0) {
-		printk(KERN_ERR "%s: open: submit_rx_urb failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
+		wiphy_err(priv->hw->wiphy, "open: submit_rx_urb failed: %d\n",
+			  ret);
 		goto error;
 	}
 
@@ -1770,6 +1833,7 @@
 	at76_dbg(DBG_MAC80211, "%s()", __func__);
 
 	cancel_delayed_work(&priv->dwork_hw_scan);
+	cancel_work_sync(&priv->work_join_bssid);
 	cancel_work_sync(&priv->work_set_promisc);
 
 	mutex_lock(&priv->mtx);
@@ -1818,42 +1882,6 @@
 	at76_dbg(DBG_MAC80211, "%s()", __func__);
 }
 
-static int at76_join(struct at76_priv *priv)
-{
-	struct at76_req_join join;
-	int ret;
-
-	memset(&join, 0, sizeof(struct at76_req_join));
-	memcpy(join.essid, priv->essid, priv->essid_size);
-	join.essid_size = priv->essid_size;
-	memcpy(join.bssid, priv->bssid, ETH_ALEN);
-	join.bss_type = INFRASTRUCTURE_MODE;
-	join.channel = priv->channel;
-	join.timeout = cpu_to_le16(2000);
-
-	at76_dbg(DBG_MAC80211, "%s: sending CMD_JOIN", __func__);
-	ret = at76_set_card_command(priv->udev, CMD_JOIN, &join,
-				    sizeof(struct at76_req_join));
-
-	if (ret < 0) {
-		printk(KERN_ERR "%s: at76_set_card_command failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
-		return 0;
-	}
-
-	ret = at76_wait_completion(priv, CMD_JOIN);
-	at76_dbg(DBG_MAC80211, "%s: CMD_JOIN returned: 0x%02x", __func__, ret);
-	if (ret != CMD_STATUS_COMPLETE) {
-		printk(KERN_ERR "%s: at76_wait_completion failed: %d\n",
-		       wiphy_name(priv->hw->wiphy), ret);
-		return 0;
-	}
-
-	at76_set_pm_mode(priv);
-
-	return 0;
-}
-
 static void at76_dwork_hw_scan(struct work_struct *work)
 {
 	struct at76_priv *priv = container_of(work, struct at76_priv,
@@ -2107,6 +2135,7 @@
 	mutex_init(&priv->mtx);
 	INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc);
 	INIT_WORK(&priv->work_submit_rx, at76_work_submit_rx);
+	INIT_WORK(&priv->work_join_bssid, at76_work_join_bssid);
 	INIT_DELAYED_WORK(&priv->dwork_hw_scan, at76_dwork_hw_scan);
 
 	tasklet_init(&priv->rx_tasklet, at76_rx_tasklet, 0);
@@ -2281,14 +2310,12 @@
 
 	priv->mac80211_registered = 1;
 
-	printk(KERN_INFO "%s: USB %s, MAC %pM, firmware %d.%d.%d-%d\n",
-	       wiphy_name(priv->hw->wiphy),
-	       dev_name(&interface->dev), priv->mac_addr,
-	       priv->fw_version.major, priv->fw_version.minor,
-	       priv->fw_version.patch, priv->fw_version.build);
-	printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n",
-	       wiphy_name(priv->hw->wiphy),
-	       priv->regulatory_domain, priv->domain->name);
+	wiphy_info(priv->hw->wiphy, "usb %s, mac %pm, firmware %d.%d.%d-%d\n",
+		   dev_name(&interface->dev), priv->mac_addr,
+		   priv->fw_version.major, priv->fw_version.minor,
+		   priv->fw_version.patch, priv->fw_version.build);
+	wiphy_info(priv->hw->wiphy, "regulatory domain 0x%02x: %s\n",
+		   priv->regulatory_domain, priv->domain->name);
 
 exit:
 	return ret;
@@ -2450,7 +2477,7 @@
 	if (!priv)
 		return;
 
-	printk(KERN_INFO "%s: disconnecting\n", wiphy_name(priv->hw->wiphy));
+	wiphy_info(priv->hw->wiphy, "disconnecting\n");
 	at76_delete_device(priv);
 	dev_printk(KERN_INFO, &interface->dev, "disconnected\n");
 }
@@ -2508,5 +2535,6 @@
 MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
 MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
 MODULE_AUTHOR("Kalle Valo <kalle.valo@iki.fi>");
+MODULE_AUTHOR("Sebastian Smolorz <sesmo@gmx.net>");
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/at76c50x-usb.h b/drivers/net/wireless/at76c50x-usb.h
index 1ec5ccf..4a37447 100644
--- a/drivers/net/wireless/at76c50x-usb.h
+++ b/drivers/net/wireless/at76c50x-usb.h
@@ -99,7 +99,7 @@
 	u8 reserved2[14];
 	u8 cr15_values[14];
 	u8 reserved3[3];
-} __attribute__((packed));
+} __packed;
 
 struct hwcfg_rfmd {
 	u8 cr20_values[14];
@@ -111,7 +111,7 @@
 	u8 low_power_values[14];
 	u8 normal_power_values[14];
 	u8 reserved1[3];
-} __attribute__((packed));
+} __packed;
 
 struct hwcfg_intersil {
 	u8 mac_addr[ETH_ALEN];
@@ -120,7 +120,7 @@
 	u8 pidvid[4];
 	u8 regulatory_domain;
 	u8 reserved[1];
-} __attribute__((packed));
+} __packed;
 
 union at76_hwcfg {
 	struct hwcfg_intersil i;
@@ -149,14 +149,14 @@
 	u8 ssid_len;
 	u8 short_preamble;
 	__le16 beacon_period;
-} __attribute__((packed));
+} __packed;
 
 struct at76_command {
 	u8 cmd;
 	u8 reserved;
 	__le16 size;
 	u8 data[0];
-} __attribute__((packed));
+} __packed;
 
 /* Length of Atmel-specific Rx header before 802.11 frame */
 #define AT76_RX_HDRLEN offsetof(struct at76_rx_buffer, packet)
@@ -171,7 +171,7 @@
 	u8 noise_level;
 	__le32 rx_time;
 	u8 packet[IEEE80211_MAX_FRAG_THRESHOLD];
-} __attribute__((packed));
+} __packed;
 
 /* Length of Atmel-specific Tx header before 802.11 frame */
 #define AT76_TX_HDRLEN offsetof(struct at76_tx_buffer, packet)
@@ -182,7 +182,7 @@
 	u8 padding;
 	u8 reserved[4];
 	u8 packet[IEEE80211_MAX_FRAG_THRESHOLD];
-} __attribute__((packed));
+} __packed;
 
 /* defines for scan_type below */
 #define SCAN_TYPE_ACTIVE	0
@@ -198,7 +198,7 @@
 	__le16 max_channel_time;
 	u8 essid_size;
 	u8 international_scan;
-} __attribute__((packed));
+} __packed;
 
 struct at76_req_ibss {
 	u8 bssid[ETH_ALEN];
@@ -207,7 +207,7 @@
 	u8 channel;
 	u8 essid_size;
 	u8 reserved[3];
-} __attribute__((packed));
+} __packed;
 
 struct at76_req_join {
 	u8 bssid[ETH_ALEN];
@@ -217,7 +217,7 @@
 	__le16 timeout;
 	u8 essid_size;
 	u8 reserved;
-} __attribute__((packed));
+} __packed;
 
 struct set_mib_buffer {
 	u8 type;
@@ -229,7 +229,7 @@
 		__le16 word;
 		u8 addr[ETH_ALEN];
 	} data;
-} __attribute__((packed));
+} __packed;
 
 struct mib_local {
 	u16 reserved0;
@@ -241,14 +241,14 @@
 	u16 reserved2;
 	u8 preamble_type;
 	u16 reserved3;
-} __attribute__((packed));
+} __packed;
 
 struct mib_mac_addr {
 	u8 mac_addr[ETH_ALEN];
 	u8 res[2];		/* ??? */
 	u8 group_addr[4][ETH_ALEN];
 	u8 group_addr_status[4];
-} __attribute__((packed));
+} __packed;
 
 struct mib_mac {
 	__le32 max_tx_msdu_lifetime;
@@ -269,7 +269,7 @@
 	u8 desired_bssid[ETH_ALEN];
 	u8 desired_bsstype;	/* ad-hoc or infrastructure */
 	u8 reserved2;
-} __attribute__((packed));
+} __packed;
 
 struct mib_mac_mgmt {
 	__le16 beacon_period;
@@ -292,7 +292,7 @@
 	u8 multi_domain_capability_enabled;
 	u8 country_string[3];
 	u8 reserved[3];
-} __attribute__((packed));
+} __packed;
 
 struct mib_mac_wep {
 	u8 privacy_invoked;	/* 0 disable encr., 1 enable encr */
@@ -303,7 +303,7 @@
 	__le32 wep_excluded_count;
 	u8 wep_default_keyvalue[WEP_KEYS][WEP_LARGE_KEY_LEN];
 	u8 encryption_level;	/* 1 for 40bit, 2 for 104bit encryption */
-} __attribute__((packed));
+} __packed;
 
 struct mib_phy {
 	__le32 ed_threshold;
@@ -320,19 +320,19 @@
 	u8 current_cca_mode;
 	u8 phy_type;
 	u8 current_reg_domain;
-} __attribute__((packed));
+} __packed;
 
 struct mib_fw_version {
 	u8 major;
 	u8 minor;
 	u8 patch;
 	u8 build;
-} __attribute__((packed));
+} __packed;
 
 struct mib_mdomain {
 	u8 tx_powerlevel[14];
 	u8 channel_list[14];	/* 0 for invalid channels */
-} __attribute__((packed));
+} __packed;
 
 struct at76_fw_header {
 	__le32 crc;		/* CRC32 of the whole image */
@@ -346,7 +346,7 @@
 	__le32 int_fw_len;	/* internal firmware image length */
 	__le32 ext_fw_offset;	/* external firmware image offset */
 	__le32 ext_fw_len;	/* external firmware image length */
-} __attribute__((packed));
+} __packed;
 
 /* a description of a regulatory domain and the allowed channels */
 struct reg_domain {
@@ -387,6 +387,7 @@
 	/* work queues */
 	struct work_struct work_set_promisc;
 	struct work_struct work_submit_rx;
+	struct work_struct work_join_bssid;
 	struct delayed_work dwork_hw_scan;
 
 	struct tasklet_struct rx_tasklet;
diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c
index cf6f5c4..4604de0 100644
--- a/drivers/net/wireless/ath/ar9170/cmd.c
+++ b/drivers/net/wireless/ath/ar9170/cmd.c
@@ -48,8 +48,7 @@
 
 	err = ar->exec_cmd(ar, AR9170_CMD_WMEM, len, (u8 *) data, 0, NULL);
 	if (err)
-		printk(KERN_DEBUG "%s: writing memory failed\n",
-		       wiphy_name(ar->hw->wiphy));
+		wiphy_debug(ar->hw->wiphy, "writing memory failed\n");
 	return err;
 }
 
@@ -67,8 +66,8 @@
 	err = ar->exec_cmd(ar, AR9170_CMD_WREG, sizeof(buf),
 			   (u8 *) buf, 0, NULL);
 	if (err)
-		printk(KERN_DEBUG "%s: writing reg %#x (val %#x) failed\n",
-		       wiphy_name(ar->hw->wiphy), reg, val);
+		wiphy_debug(ar->hw->wiphy, "writing reg %#x (val %#x) failed\n",
+			    reg, val);
 	return err;
 }
 
diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c
index 86c4e79..832d900 100644
--- a/drivers/net/wireless/ath/ar9170/led.c
+++ b/drivers/net/wireless/ath/ar9170/led.c
@@ -133,8 +133,8 @@
 	err = led_classdev_register(wiphy_dev(ar->hw->wiphy),
 				    &ar->leds[i].l);
 	if (err)
-		printk(KERN_ERR "%s: failed to register %s LED (%d).\n",
-		       wiphy_name(ar->hw->wiphy), ar->leds[i].name, err);
+		wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n",
+			  ar->leds[i].name, err);
 	else
 		ar->leds[i].registered = true;
 
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 2abc875..c67b05f 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -198,12 +198,13 @@
 	struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
 	struct ieee80211_hdr *hdr = (void *) txc->frame_data;
 
-	printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] s:%d "
-			  "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
-	       wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
-	       ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr),
-	       le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
-	       jiffies_to_msecs(arinfo->timeout - jiffies));
+	wiphy_debug(ar->hw->wiphy,
+		    "=> FRAME [skb:%p, q:%d, DA:[%pM] s:%d "
+		    "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
+		    skb, skb_get_queue_mapping(skb),
+		    ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr),
+		    le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
+		    jiffies_to_msecs(arinfo->timeout - jiffies));
 }
 
 static void __ar9170_dump_txqueue(struct ar9170 *ar,
@@ -213,8 +214,8 @@
 	int i = 0;
 
 	printk(KERN_DEBUG "---[ cut here ]---\n");
-	printk(KERN_DEBUG "%s: %d entries in queue.\n",
-	       wiphy_name(ar->hw->wiphy), skb_queue_len(queue));
+	wiphy_debug(ar->hw->wiphy, "%d entries in queue.\n",
+		    skb_queue_len(queue));
 
 	skb_queue_walk(queue, skb) {
 		printk(KERN_DEBUG "index:%d =>\n", i++);
@@ -244,15 +245,14 @@
 {
 	int i;
 
-	printk(KERN_DEBUG "%s: QoS queue stats\n",
-	       wiphy_name(ar->hw->wiphy));
+	wiphy_debug(ar->hw->wiphy, "qos queue stats\n");
 
 	for (i = 0; i < __AR9170_NUM_TXQ; i++)
-		printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d "
-		       " stopped:%d\n", wiphy_name(ar->hw->wiphy), i,
-		       ar->tx_stats[i].limit, ar->tx_stats[i].len,
-		       skb_queue_len(&ar->tx_status[i]),
-		       ieee80211_queue_stopped(ar->hw, i));
+		wiphy_debug(ar->hw->wiphy,
+			    "queue:%d limit:%d len:%d waitack:%d stopped:%d\n",
+			    i, ar->tx_stats[i].limit, ar->tx_stats[i].len,
+			    skb_queue_len(&ar->tx_status[i]),
+			    ieee80211_queue_stopped(ar->hw, i));
 }
 #endif /* AR9170_QUEUE_STOP_DEBUG */
 
@@ -274,9 +274,9 @@
 
 		if (time_is_before_jiffies(arinfo->timeout)) {
 #ifdef AR9170_QUEUE_DEBUG
-			printk(KERN_DEBUG "%s: [%ld > %ld] frame expired => "
-			       "recycle\n", wiphy_name(ar->hw->wiphy),
-			       jiffies, arinfo->timeout);
+			wiphy_debug(ar->hw->wiphy,
+				    "[%ld > %ld] frame expired => recycle\n",
+				    jiffies, arinfo->timeout);
 			ar9170_print_txheader(ar, skb);
 #endif /* AR9170_QUEUE_DEBUG */
 			__skb_unlink(skb, queue);
@@ -317,8 +317,8 @@
 		break;
 
 	default:
-		printk(KERN_ERR "%s: invalid tx_status response (%x).\n",
-		       wiphy_name(ar->hw->wiphy), tx_status);
+		wiphy_err(ar->hw->wiphy,
+			  "invalid tx_status response (%x)\n", tx_status);
 		break;
 	}
 
@@ -339,8 +339,7 @@
 
 	if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) {
 #ifdef AR9170_QUEUE_STOP_DEBUG
-		printk(KERN_DEBUG "%s: wake queue %d\n",
-		       wiphy_name(ar->hw->wiphy), queue);
+		wiphy_debug(ar->hw->wiphy, "wake queue %d\n", queue);
 		__ar9170_dump_txstats(ar);
 #endif /* AR9170_QUEUE_STOP_DEBUG */
 		ieee80211_wake_queue(ar->hw, queue);
@@ -387,9 +386,9 @@
 
 		if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) {
 #ifdef AR9170_QUEUE_DEBUG
-			printk(KERN_DEBUG "%s: skip frame => DA %pM != %pM\n",
-			       wiphy_name(ar->hw->wiphy), mac,
-			       ieee80211_get_DA(hdr));
+			wiphy_debug(ar->hw->wiphy,
+				    "skip frame => da %pm != %pm\n",
+				    mac, ieee80211_get_DA(hdr));
 			ar9170_print_txheader(ar, skb);
 #endif /* AR9170_QUEUE_DEBUG */
 			continue;
@@ -400,8 +399,8 @@
 
 		if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) {
 #ifdef AR9170_QUEUE_DEBUG
-			printk(KERN_DEBUG "%s: skip frame => rate %d != %d\n",
-			       wiphy_name(ar->hw->wiphy), rate, r);
+			wiphy_debug(ar->hw->wiphy,
+				    "skip frame => rate %d != %d\n", rate, r);
 			ar9170_print_txheader(ar, skb);
 #endif /* AR9170_QUEUE_DEBUG */
 			continue;
@@ -413,9 +412,9 @@
 	}
 
 #ifdef AR9170_QUEUE_DEBUG
-	printk(KERN_ERR "%s: ESS:[%pM] does not have any "
-			"outstanding frames in queue.\n",
-			wiphy_name(ar->hw->wiphy), mac);
+	wiphy_err(ar->hw->wiphy,
+		  "ESS:[%pM] does not have any outstanding frames in queue.\n",
+		  mac);
 	__ar9170_dump_txqueue(ar, queue);
 #endif /* AR9170_QUEUE_DEBUG */
 	spin_unlock_irqrestore(&queue->lock, flags);
@@ -444,8 +443,8 @@
 
 	for (i = 0; i < __AR9170_NUM_TXQ; i++) {
 #ifdef AR9170_QUEUE_DEBUG
-		printk(KERN_DEBUG "%s: garbage collector scans queue:%d\n",
-		       wiphy_name(ar->hw->wiphy), i);
+		wiphy_debug(ar->hw->wiphy, "garbage collector scans queue:%d\n",
+			    i);
 		ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
 		ar9170_dump_txqueue(ar, &ar->tx_status[i]);
 #endif /* AR9170_QUEUE_DEBUG */
@@ -495,8 +494,9 @@
 		u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >>
 			AR9170_TX_PHY_QOS_SHIFT;
 #ifdef AR9170_QUEUE_DEBUG
-		printk(KERN_DEBUG "%s: recv tx_status for %pM, p:%08x, q:%d\n",
-		       wiphy_name(ar->hw->wiphy), cmd->tx_status.dst, phy, q);
+		wiphy_debug(ar->hw->wiphy,
+			    "recv tx_status for %pm, p:%08x, q:%d\n",
+			    cmd->tx_status.dst, phy, q);
 #endif /* AR9170_QUEUE_DEBUG */
 
 		skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst,
@@ -582,7 +582,7 @@
 		break;
 
 	default:
-		printk(KERN_INFO "received unhandled event %x\n", cmd->type);
+		pr_info("received unhandled event %x\n", cmd->type);
 		print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len);
 		break;
 	}
@@ -675,9 +675,9 @@
 		/* TODO: update netdevice's RX dropped/errors statistics */
 
 		if (ar9170_nag_limiter(ar))
-			printk(KERN_DEBUG "%s: received frame with "
-			       "suspicious error code (%#x).\n",
-			       wiphy_name(ar->hw->wiphy), error);
+			wiphy_debug(ar->hw->wiphy,
+				    "received frame with suspicious error code (%#x).\n",
+				    error);
 
 		return -EINVAL;
 	}
@@ -704,9 +704,9 @@
 			break;
 		default:
 			if (ar9170_nag_limiter(ar))
-				printk(KERN_ERR "%s: invalid plcp cck rate "
-				       "(%x).\n", wiphy_name(ar->hw->wiphy),
-				       head->plcp[0]);
+				wiphy_err(ar->hw->wiphy,
+					  "invalid plcp cck rate (%x).\n",
+					  head->plcp[0]);
 			return -EINVAL;
 		}
 		break;
@@ -740,9 +740,9 @@
 			break;
 		default:
 			if (ar9170_nag_limiter(ar))
-				printk(KERN_ERR "%s: invalid plcp ofdm rate "
-				       "(%x).\n", wiphy_name(ar->hw->wiphy),
-				       head->plcp[0]);
+				wiphy_err(ar->hw->wiphy,
+					  "invalid plcp ofdm rate (%x).\n",
+					  head->plcp[0]);
 			return -EINVAL;
 		}
 		if (status->band == IEEE80211_BAND_2GHZ)
@@ -761,8 +761,7 @@
 
 	default:
 		if (ar9170_nag_limiter(ar))
-			printk(KERN_ERR "%s: invalid modulation\n",
-			       wiphy_name(ar->hw->wiphy));
+			wiphy_err(ar->hw->wiphy, "invalid modulation\n");
 		return -EINVAL;
 	}
 
@@ -863,8 +862,8 @@
 			ar->rx_mpdu.has_plcp = true;
 		} else {
 			if (ar9170_nag_limiter(ar))
-				printk(KERN_ERR "%s: plcp info is clipped.\n",
-				       wiphy_name(ar->hw->wiphy));
+				wiphy_err(ar->hw->wiphy,
+					  "plcp info is clipped.\n");
 			return ;
 		}
 		break;
@@ -877,8 +876,8 @@
 			phy = (void *)(buf + mpdu_len);
 		} else {
 			if (ar9170_nag_limiter(ar))
-				printk(KERN_ERR "%s: frame tail is clipped.\n",
-				       wiphy_name(ar->hw->wiphy));
+				wiphy_err(ar->hw->wiphy,
+					  "frame tail is clipped.\n");
 			return ;
 		}
 
@@ -888,9 +887,8 @@
 			if (!ar9170_nag_limiter(ar))
 				return ;
 
-			printk(KERN_ERR "%s: rx stream did not start "
-					"with a first_mpdu frame tag.\n",
-			       wiphy_name(ar->hw->wiphy));
+			wiphy_err(ar->hw->wiphy,
+				  "rx stream did not start with a first_mpdu frame tag.\n");
 
 			return ;
 		}
@@ -954,8 +952,8 @@
 			if (!ar->rx_failover_missing) {
 				/* this is no "short read". */
 				if (ar9170_nag_limiter(ar)) {
-					printk(KERN_ERR "%s: missing tag!\n",
-					       wiphy_name(ar->hw->wiphy));
+					wiphy_err(ar->hw->wiphy,
+						  "missing tag!\n");
 					goto err_telluser;
 				} else
 					goto err_silent;
@@ -963,9 +961,8 @@
 
 			if (ar->rx_failover_missing > tlen) {
 				if (ar9170_nag_limiter(ar)) {
-					printk(KERN_ERR "%s: possible multi "
-					       "stream corruption!\n",
-					       wiphy_name(ar->hw->wiphy));
+					wiphy_err(ar->hw->wiphy,
+						  "possible multi stream corruption!\n");
 					goto err_telluser;
 				} else
 					goto err_silent;
@@ -997,9 +994,8 @@
 			if (ar->rx_failover_missing) {
 				/* TODO: handle double stream corruption. */
 				if (ar9170_nag_limiter(ar)) {
-					printk(KERN_ERR "%s: double rx stream "
-					       "corruption!\n",
-						wiphy_name(ar->hw->wiphy));
+					wiphy_err(ar->hw->wiphy,
+						  "double rx stream corruption!\n");
 					goto err_telluser;
 				} else
 					goto err_silent;
@@ -1042,9 +1038,9 @@
 
 	if (tlen) {
 		if (net_ratelimit())
-			printk(KERN_ERR "%s: %d bytes of unprocessed "
-					"data left in rx stream!\n",
-			       wiphy_name(ar->hw->wiphy), tlen);
+			wiphy_err(ar->hw->wiphy,
+				  "%d bytes of unprocessed data left in rx stream!\n",
+				  tlen);
 
 		goto err_telluser;
 	}
@@ -1052,10 +1048,9 @@
 	return ;
 
 err_telluser:
-	printk(KERN_ERR "%s: damaged RX stream data [want:%d, "
-			"data:%d, rx:%d, pending:%d ]\n",
-	       wiphy_name(ar->hw->wiphy), clen, wlen, tlen,
-	       ar->rx_failover_missing);
+	wiphy_err(ar->hw->wiphy,
+		  "damaged RX stream data [want:%d, data:%d, rx:%d, pending:%d ]\n",
+		  clen, wlen, tlen, ar->rx_failover_missing);
 
 	if (ar->rx_failover_missing)
 		print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET,
@@ -1065,9 +1060,8 @@
 	print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET,
 			     skb->data, skb->len);
 
-	printk(KERN_ERR "%s: please check your hardware and cables, if "
-			"you see this message frequently.\n",
-	       wiphy_name(ar->hw->wiphy));
+	wiphy_err(ar->hw->wiphy,
+		  "If you see this message frequently, please check your hardware and cables.\n");
 
 err_silent:
 	if (ar->rx_failover_missing) {
@@ -1384,10 +1378,10 @@
 
 		if (remaining_space < frames) {
 #ifdef AR9170_QUEUE_DEBUG
-			printk(KERN_DEBUG "%s: tx quota reached queue:%d, "
-			       "remaining slots:%d, needed:%d\n",
-			       wiphy_name(ar->hw->wiphy), i, remaining_space,
-			       frames);
+			wiphy_debug(ar->hw->wiphy,
+				    "tx quota reached queue:%d, "
+				    "remaining slots:%d, needed:%d\n",
+				    i, remaining_space, frames);
 #endif /* AR9170_QUEUE_DEBUG */
 			frames = remaining_space;
 		}
@@ -1396,18 +1390,14 @@
 		ar->tx_stats[i].count += frames;
 		if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) {
 #ifdef AR9170_QUEUE_DEBUG
-			printk(KERN_DEBUG "%s: queue %d full\n",
-			       wiphy_name(ar->hw->wiphy), i);
-
-			printk(KERN_DEBUG "%s: stuck frames: ===>\n",
-			       wiphy_name(ar->hw->wiphy));
+			wiphy_debug(ar->hw->wiphy, "queue %d full\n", i);
+			wiphy_debug(ar->hw->wiphy, "stuck frames: ===>\n");
 			ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
 			ar9170_dump_txqueue(ar, &ar->tx_status[i]);
 #endif /* AR9170_QUEUE_DEBUG */
 
 #ifdef AR9170_QUEUE_STOP_DEBUG
-			printk(KERN_DEBUG "%s: stop queue %d\n",
-			       wiphy_name(ar->hw->wiphy), i);
+			wiphy_debug(ar->hw->wiphy, "stop queue %d\n", i);
 			__ar9170_dump_txstats(ar);
 #endif /* AR9170_QUEUE_STOP_DEBUG */
 			ieee80211_stop_queue(ar->hw, i);
@@ -1435,8 +1425,7 @@
 					  msecs_to_jiffies(AR9170_TX_TIMEOUT);
 
 #ifdef AR9170_QUEUE_DEBUG
-			printk(KERN_DEBUG "%s: send frame q:%d =>\n",
-			       wiphy_name(ar->hw->wiphy), i);
+			wiphy_debug(ar->hw->wiphy, "send frame q:%d =>\n", i);
 			ar9170_print_txheader(ar, skb);
 #endif /* AR9170_QUEUE_DEBUG */
 
@@ -1453,26 +1442,25 @@
 		}
 
 #ifdef AR9170_QUEUE_DEBUG
-		printk(KERN_DEBUG "%s: ar9170_tx report for queue %d\n",
-		       wiphy_name(ar->hw->wiphy), i);
+		wiphy_debug(ar->hw->wiphy,
+			    "ar9170_tx report for queue %d\n", i);
 
-		printk(KERN_DEBUG "%s: unprocessed pending frames left:\n",
-		       wiphy_name(ar->hw->wiphy));
+		wiphy_debug(ar->hw->wiphy,
+			    "unprocessed pending frames left:\n");
 		ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
 #endif /* AR9170_QUEUE_DEBUG */
 
 		if (unlikely(frames_failed)) {
 #ifdef AR9170_QUEUE_DEBUG
-			printk(KERN_DEBUG "%s: frames failed %d =>\n",
-			       wiphy_name(ar->hw->wiphy), frames_failed);
+			wiphy_debug(ar->hw->wiphy,
+				    "frames failed %d =>\n", frames_failed);
 #endif /* AR9170_QUEUE_DEBUG */
 
 			spin_lock_irqsave(&ar->tx_stats_lock, flags);
 			ar->tx_stats[i].len -= frames_failed;
 			ar->tx_stats[i].count -= frames_failed;
 #ifdef AR9170_QUEUE_STOP_DEBUG
-			printk(KERN_DEBUG "%s: wake queue %d\n",
-			       wiphy_name(ar->hw->wiphy), i);
+			wiphy_debug(ar->hw->wiphy, "wake queue %d\n", i);
 			__ar9170_dump_txstats(ar);
 #endif /* AR9170_QUEUE_STOP_DEBUG */
 			ieee80211_wake_queue(ar->hw, i);
@@ -1917,6 +1905,24 @@
 	return 0;
 }
 
+static int ar9170_get_survey(struct ieee80211_hw *hw, int idx,
+				struct survey_info *survey)
+{
+	struct ar9170 *ar = hw->priv;
+	struct ieee80211_conf *conf = &hw->conf;
+
+	if (idx != 0)
+		return -ENOENT;
+
+	/* TODO: update noise value, e.g. call ar9170_set_channel */
+
+	survey->channel = conf->channel;
+	survey->filled = SURVEY_INFO_NOISE_DBM;
+	survey->noise = ar->noise[0];
+
+	return 0;
+}
+
 static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
 			  const struct ieee80211_tx_queue_params *param)
 {
@@ -1969,6 +1975,7 @@
 	.get_tsf		= ar9170_op_get_tsf,
 	.set_key		= ar9170_set_key,
 	.get_stats		= ar9170_get_stats,
+	.get_survey		= ar9170_get_survey,
 	.ampdu_action		= ar9170_ampdu_action,
 };
 
diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c
index 45a415e..0dbfcf7 100644
--- a/drivers/net/wireless/ath/ar9170/phy.c
+++ b/drivers/net/wireless/ath/ar9170/phy.c
@@ -670,8 +670,7 @@
 	ar9170_regwrite_finish();
 	err = ar9170_regwrite_result();
 	if (err)
-		printk(KERN_ERR "%s: rf init failed\n",
-		       wiphy_name(ar->hw->wiphy));
+		wiphy_err(ar->hw->wiphy, "rf init failed\n");
 	return err;
 }
 
@@ -1702,9 +1701,8 @@
 				       0x200 | ar->phy_heavy_clip);
 		if (err) {
 			if (ar9170_nag_limiter(ar))
-				printk(KERN_ERR "%s: failed to set "
-				       "heavy clip\n",
-				       wiphy_name(ar->hw->wiphy));
+				wiphy_err(ar->hw->wiphy,
+					  "failed to set heavy clip\n");
 		}
 	}
 
diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile
index cc09595..2242a14 100644
--- a/drivers/net/wireless/ath/ath5k/Makefile
+++ b/drivers/net/wireless/ath/ath5k/Makefile
@@ -13,5 +13,6 @@
 ath5k-y				+= led.o
 ath5k-y				+= rfkill.o
 ath5k-y				+= ani.o
+ath5k-y				+= sysfs.o
 ath5k-$(CONFIG_ATH5K_DEBUG)	+= debug.o
 obj-$(CONFIG_ATH5K)		+= ath5k.o
diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c
index f2311ab..26dbe65 100644
--- a/drivers/net/wireless/ath/ath5k/ani.c
+++ b/drivers/net/wireless/ath/ath5k/ani.c
@@ -74,8 +74,8 @@
 	const s8 fr[] = { -78, -80 };
 #endif
 	if (level < 0 || level >= ARRAY_SIZE(sz)) {
-		ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
-			"level out of range %d", level);
+		ATH5K_ERR(ah->ah_sc, "noise immuniy level %d out of range",
+			  level);
 		return;
 	}
 
@@ -106,8 +106,8 @@
 
 	if (level < 0 || level >= ARRAY_SIZE(val) ||
 	    level > ah->ah_sc->ani_state.max_spur_level) {
-		ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
-			"level out of range %d", level);
+		ATH5K_ERR(ah->ah_sc, "spur immunity level %d out of range",
+			  level);
 		return;
 	}
 
@@ -130,8 +130,7 @@
 	const int val[] = { 0, 4, 8 };
 
 	if (level < 0 || level >= ARRAY_SIZE(val)) {
-		ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
-			"level out of range %d", level);
+		ATH5K_ERR(ah->ah_sc, "firstep level %d out of range", level);
 		return;
 	}
 
@@ -481,14 +480,15 @@
 	struct ath5k_ani_state *as = &ah->ah_sc->ani_state;
 	int listen, ofdm_high, ofdm_low, cck_high, cck_low;
 
-	if (as->ani_mode != ATH5K_ANI_MODE_AUTO)
-		return;
-
 	/* get listen time since last call and add it to the counter because we
-	 * might not have restarted the "ani period" last time */
+	 * might not have restarted the "ani period" last time.
+	 * always do this to calculate the busy time also in manual mode */
 	listen = ath5k_hw_ani_get_listen_time(ah, as);
 	as->listen_time += listen;
 
+	if (as->ani_mode != ATH5K_ANI_MODE_AUTO)
+		return;
+
 	ath5k_ani_save_and_clear_phy_errors(ah, as);
 
 	ofdm_high = as->listen_time * ATH5K_ANI_OFDM_TRIG_HIGH / 1000;
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 2785946..ea6362a 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -204,6 +204,7 @@
 #define AR5K_TUNE_TPC_TXPOWER			false
 #define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL    10000   /* 10 sec */
 #define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI	1000	/* 1 sec */
+#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF	60000	/* 60 sec */
 
 #define AR5K_INIT_CARR_SENSE_EN			1
 
@@ -565,7 +566,7 @@
 )
 
 /*
- * DMA size definitions (2^n+2)
+ * DMA size definitions (2^(n+2))
  */
 enum ath5k_dmasize {
 	AR5K_DMASIZE_4B	= 0,
@@ -1118,6 +1119,7 @@
 	/* Calibration timestamp */
 	unsigned long		ah_cal_next_full;
 	unsigned long		ah_cal_next_ani;
+	unsigned long		ah_cal_next_nf;
 
 	/* Calibration mask */
 	u8			ah_cal_mask;
@@ -1125,15 +1127,10 @@
 	/*
 	 * Function pointers
 	 */
-	int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc,
-				u32 size, unsigned int flags);
 	int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
 		unsigned int, unsigned int, int, enum ath5k_pkt_type,
 		unsigned int, unsigned int, unsigned int, unsigned int,
 		unsigned int, unsigned int, unsigned int, unsigned int);
-	int (*ah_setup_mrr_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
-		unsigned int, unsigned int, unsigned int, unsigned int,
-		unsigned int, unsigned int);
 	int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
 		struct ath5k_tx_status *);
 	int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *,
@@ -1148,6 +1145,9 @@
 int ath5k_hw_attach(struct ath5k_softc *sc);
 void ath5k_hw_detach(struct ath5k_hw *ah);
 
+int ath5k_sysfs_register(struct ath5k_softc *sc);
+void ath5k_sysfs_unregister(struct ath5k_softc *sc);
+
 /* LED functions */
 int ath5k_init_leds(struct ath5k_softc *sc);
 void ath5k_led_enable(struct ath5k_softc *sc);
@@ -1231,6 +1231,11 @@
 
 /* Hardware Descriptor Functions */
 int ath5k_hw_init_desc_functions(struct ath5k_hw *ah);
+int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+			   u32 size, unsigned int flags);
+int ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+	unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
+	u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3);
 
 /* GPIO Functions */
 void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state);
@@ -1270,6 +1275,7 @@
 void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
 int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
 			   struct ieee80211_channel *channel);
+void ath5k_hw_update_noise_floor(struct ath5k_hw *ah);
 /* Spur mitigation */
 bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
 				  struct ieee80211_channel *channel);
@@ -1280,6 +1286,7 @@
 int ath5k_hw_phy_disable(struct ath5k_hw *ah);
 /* Antenna control */
 void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode);
+void ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode);
 /* TX power setup */
 int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
 		     u8 ee_mode, u8 txpower);
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index 31c0080..b32e28c 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -352,8 +352,6 @@
  */
 void ath5k_hw_detach(struct ath5k_hw *ah)
 {
-	ATH5K_TRACE(ah->ah_sc);
-
 	__set_bit(ATH_STAT_INVALID, ah->ah_sc->status);
 
 	if (ah->ah_rf_banks != NULL)
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 648972d..0d5de25 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -311,7 +311,8 @@
 static int 	ath5k_txbuf_setup(struct ath5k_softc *sc,
 				struct ath5k_buf *bf,
 				struct ath5k_txq *txq, int padsize);
-static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
+
+static inline void ath5k_txbuf_free_skb(struct ath5k_softc *sc,
 				struct ath5k_buf *bf)
 {
 	BUG_ON(!bf);
@@ -321,9 +322,11 @@
 			PCI_DMA_TODEVICE);
 	dev_kfree_skb_any(bf->skb);
 	bf->skb = NULL;
+	bf->skbaddr = 0;
+	bf->desc->ds_data = 0;
 }
 
-static inline void ath5k_rxbuf_free(struct ath5k_softc *sc,
+static inline void ath5k_rxbuf_free_skb(struct ath5k_softc *sc,
 				struct ath5k_buf *bf)
 {
 	struct ath5k_hw *ah = sc->ah;
@@ -336,6 +339,8 @@
 			PCI_DMA_FROMDEVICE);
 	dev_kfree_skb_any(bf->skb);
 	bf->skb = NULL;
+	bf->skbaddr = 0;
+	bf->desc->ds_data = 0;
 }
 
 
@@ -352,7 +357,6 @@
 static int 	ath5k_rx_start(struct ath5k_softc *sc);
 static void 	ath5k_rx_stop(struct ath5k_softc *sc);
 static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc,
-					struct ath5k_desc *ds,
 					struct sk_buff *skb,
 					struct ath5k_rx_status *rs);
 static void 	ath5k_tasklet_rx(unsigned long data);
@@ -384,7 +388,7 @@
 static int 	ath5k_stop_locked(struct ath5k_softc *sc);
 static int 	ath5k_stop_hw(struct ath5k_softc *sc);
 static irqreturn_t ath5k_intr(int irq, void *dev_id);
-static void 	ath5k_tasklet_reset(unsigned long data);
+static void ath5k_reset_work(struct work_struct *work);
 
 static void 	ath5k_tasklet_calibrate(unsigned long data);
 
@@ -578,7 +582,7 @@
 	spin_lock_init(&sc->block);
 
 	/* Set private data */
-	pci_set_drvdata(pdev, hw);
+	pci_set_drvdata(pdev, sc);
 
 	/* Setup interrupt handler */
 	ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
@@ -694,25 +698,23 @@
 static void __devexit
 ath5k_pci_remove(struct pci_dev *pdev)
 {
-	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
-	struct ath5k_softc *sc = hw->priv;
+	struct ath5k_softc *sc = pci_get_drvdata(pdev);
 
 	ath5k_debug_finish_device(sc);
-	ath5k_detach(pdev, hw);
+	ath5k_detach(pdev, sc->hw);
 	ath5k_hw_detach(sc->ah);
 	kfree(sc->ah);
 	free_irq(pdev->irq, sc);
 	pci_iounmap(pdev, sc->iobase);
 	pci_release_region(pdev, 0);
 	pci_disable_device(pdev);
-	ieee80211_free_hw(hw);
+	ieee80211_free_hw(sc->hw);
 }
 
 #ifdef CONFIG_PM_SLEEP
 static int ath5k_pci_suspend(struct device *dev)
 {
-	struct ieee80211_hw *hw = pci_get_drvdata(to_pci_dev(dev));
-	struct ath5k_softc *sc = hw->priv;
+	struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev));
 
 	ath5k_led_off(sc);
 	return 0;
@@ -721,8 +723,7 @@
 static int ath5k_pci_resume(struct device *dev)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
-	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
-	struct ath5k_softc *sc = hw->priv;
+	struct ath5k_softc *sc = pci_get_drvdata(pdev);
 
 	/*
 	 * Suspend/Resume resets the PCI configuration space, so we have to
@@ -768,7 +769,8 @@
 	 * return false w/o doing anything.  MAC's that do
 	 * support it will return true w/o doing anything.
 	 */
-	ret = ah->ah_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
+	ret = ath5k_hw_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
+
 	if (ret < 0)
 		goto err;
 	if (ret > 0)
@@ -829,11 +831,12 @@
 
 	tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
 	tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
-	tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
 	tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc);
 	tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc);
 	tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc);
 
+	INIT_WORK(&sc->reset_work, ath5k_reset_work);
+
 	ret = ath5k_eeprom_read_mac(ah, mac);
 	if (ret) {
 		ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
@@ -864,6 +867,8 @@
 
 	ath5k_init_leds(sc);
 
+	ath5k_sysfs_register(sc);
+
 	return 0;
 err_queues:
 	ath5k_txq_release(sc);
@@ -899,6 +904,7 @@
 	ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
 	ath5k_unregister_leds(sc);
 
+	ath5k_sysfs_unregister(sc);
 	/*
 	 * NB: can't reclaim these until after ieee80211_ifdetach
 	 * returns because we'll get called back to reclaim node
@@ -1111,8 +1117,9 @@
 static int
 ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
 {
-	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n",
-		sc->curchan->center_freq, chan->center_freq);
+	ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+		  "channel set, resetting (%u -> %u MHz)\n",
+		  sc->curchan->center_freq, chan->center_freq);
 
 	/*
 	 * To switch channels clear any pending DMA operations;
@@ -1228,21 +1235,23 @@
 	 * not get overrun under high load (as can happen with a
 	 * 5212 when ANI processing enables PHY error frames).
 	 *
-	 * To insure the last descriptor is self-linked we create
+	 * To ensure the last descriptor is self-linked we create
 	 * each descriptor as self-linked and add it to the end.  As
 	 * each additional descriptor is added the previous self-linked
-	 * entry is ``fixed'' naturally.  This should be safe even
+	 * entry is "fixed" naturally.  This should be safe even
 	 * if DMA is happening.  When processing RX interrupts we
 	 * never remove/process the last, self-linked, entry on the
-	 * descriptor list.  This insures the hardware always has
+	 * descriptor list.  This ensures the hardware always has
 	 * someplace to write a new frame.
 	 */
 	ds = bf->desc;
 	ds->ds_link = bf->daddr;	/* link to self */
 	ds->ds_data = bf->skbaddr;
-	ret = ah->ah_setup_rx_desc(ah, ds, ah->common.rx_bufsize, 0);
-	if (ret)
+	ret = ath5k_hw_setup_rx_desc(ah, ds, ah->common.rx_bufsize, 0);
+	if (ret) {
+		ATH5K_ERR(sc, "%s: could not setup RX desc\n", __func__);
 		return ret;
+	}
 
 	if (sc->rxlink != NULL)
 		*sc->rxlink = bf->daddr;
@@ -1347,7 +1356,7 @@
 		mrr_tries[i] = info->control.rates[i + 1].count;
 	}
 
-	ah->ah_setup_mrr_tx_desc(ah, ds,
+	ath5k_hw_setup_mrr_tx_desc(ah, ds,
 		mrr_rate[0], mrr_tries[0],
 		mrr_rate[1], mrr_tries[1],
 		mrr_rate[2], mrr_tries[2]);
@@ -1443,17 +1452,20 @@
 {
 	struct ath5k_buf *bf;
 
-	ath5k_txbuf_free(sc, sc->bbuf);
+	ath5k_txbuf_free_skb(sc, sc->bbuf);
 	list_for_each_entry(bf, &sc->txbuf, list)
-		ath5k_txbuf_free(sc, bf);
+		ath5k_txbuf_free_skb(sc, bf);
 	list_for_each_entry(bf, &sc->rxbuf, list)
-		ath5k_rxbuf_free(sc, bf);
+		ath5k_rxbuf_free_skb(sc, bf);
 
 	/* Free memory associated with all descriptors */
 	pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
+	sc->desc = NULL;
+	sc->desc_daddr = 0;
 
 	kfree(sc->bufptr);
 	sc->bufptr = NULL;
+	sc->bbuf = NULL;
 }
 
 
@@ -1602,7 +1614,7 @@
 	list_for_each_entry_safe(bf, bf0, &txq->q, list) {
 		ath5k_debug_printtxbuf(sc, bf);
 
-		ath5k_txbuf_free(sc, bf);
+		ath5k_txbuf_free_skb(sc, bf);
 
 		spin_lock_bh(&sc->txbuflock);
 		list_move_tail(&bf->list, &sc->txbuf);
@@ -1716,13 +1728,11 @@
 	ath5k_hw_stop_rx_dma(ah);	/* disable DMA engine */
 
 	ath5k_debug_printrxbuffs(sc, ah);
-
-	sc->rxlink = NULL;		/* just in case */
 }
 
 static unsigned int
-ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
-		struct sk_buff *skb, struct ath5k_rx_status *rs)
+ath5k_rx_decrypted(struct ath5k_softc *sc, struct sk_buff *skb,
+		   struct ath5k_rx_status *rs)
 {
 	struct ath5k_hw *ah = sc->ah;
 	struct ath_common *common = ath5k_hw_common(ah);
@@ -1889,9 +1899,138 @@
 }
 
 static void
-ath5k_tasklet_rx(unsigned long data)
+ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb,
+		    struct ath5k_rx_status *rs)
 {
 	struct ieee80211_rx_status *rxs;
+
+	/* 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. */
+	ath5k_remove_padding(skb);
+
+	rxs = IEEE80211_SKB_RXCB(skb);
+
+	rxs->flag = 0;
+	if (unlikely(rs->rs_status & AR5K_RXERR_MIC))
+		rxs->flag |= RX_FLAG_MMIC_ERROR;
+
+	/*
+	 * always extend the mac timestamp, since this information is
+	 * also needed for proper IBSS merging.
+	 *
+	 * XXX: it might be too late to do it here, since rs_tstamp is
+	 * 15bit only. that means TSF extension has to be done within
+	 * 32768usec (about 32ms). it might be necessary to move this to
+	 * the interrupt handler, like it is done in madwifi.
+	 *
+	 * Unfortunately we don't know when the hardware takes the rx
+	 * timestamp (beginning of phy frame, data frame, end of rx?).
+	 * The only thing we know is that it is hardware specific...
+	 * On AR5213 it seems the rx timestamp is at the end of the
+	 * frame, but i'm not sure.
+	 *
+	 * NOTE: mac80211 defines mactime at the beginning of the first
+	 * data symbol. Since we don't have any time references it's
+	 * impossible to comply to that. This affects IBSS merge only
+	 * right now, so it's not too bad...
+	 */
+	rxs->mactime = ath5k_extend_tsf(sc->ah, rs->rs_tstamp);
+	rxs->flag |= RX_FLAG_TSFT;
+
+	rxs->freq = sc->curchan->center_freq;
+	rxs->band = sc->curband->band;
+
+	rxs->signal = sc->ah->ah_noise_floor + rs->rs_rssi;
+
+	rxs->antenna = rs->rs_antenna;
+
+	if (rs->rs_antenna > 0 && rs->rs_antenna < 5)
+		sc->stats.antenna_rx[rs->rs_antenna]++;
+	else
+		sc->stats.antenna_rx[0]++; /* invalid */
+
+	rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs->rs_rate);
+	rxs->flag |= ath5k_rx_decrypted(sc, skb, rs);
+
+	if (rxs->rate_idx >= 0 && rs->rs_rate ==
+	    sc->curband->bitrates[rxs->rate_idx].hw_value_short)
+		rxs->flag |= RX_FLAG_SHORTPRE;
+
+	ath5k_debug_dump_skb(sc, skb, "RX  ", 0);
+
+	ath5k_update_beacon_rssi(sc, skb, rs->rs_rssi);
+
+	/* check beacons in IBSS mode */
+	if (sc->opmode == NL80211_IFTYPE_ADHOC)
+		ath5k_check_ibss_tsf(sc, skb, rxs);
+
+	ieee80211_rx(sc->hw, skb);
+}
+
+/** ath5k_frame_receive_ok() - Do we want to receive this frame or not?
+ *
+ * Check if we want to further process this frame or not. Also update
+ * statistics. Return true if we want this frame, false if not.
+ */
+static bool
+ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)
+{
+	sc->stats.rx_all_count++;
+
+	if (unlikely(rs->rs_status)) {
+		if (rs->rs_status & AR5K_RXERR_CRC)
+			sc->stats.rxerr_crc++;
+		if (rs->rs_status & AR5K_RXERR_FIFO)
+			sc->stats.rxerr_fifo++;
+		if (rs->rs_status & AR5K_RXERR_PHY) {
+			sc->stats.rxerr_phy++;
+			if (rs->rs_phyerr > 0 && rs->rs_phyerr < 32)
+				sc->stats.rxerr_phy_code[rs->rs_phyerr]++;
+			return false;
+		}
+		if (rs->rs_status & AR5K_RXERR_DECRYPT) {
+			/*
+			 * Decrypt error.  If the error occurred
+			 * because there was no hardware key, then
+			 * let the frame through so the upper layers
+			 * can process it.  This is necessary for 5210
+			 * parts which have no way to setup a ``clear''
+			 * key cache entry.
+			 *
+			 * XXX do key cache faulting
+			 */
+			sc->stats.rxerr_decrypt++;
+			if (rs->rs_keyix == AR5K_RXKEYIX_INVALID &&
+			    !(rs->rs_status & AR5K_RXERR_CRC))
+				return true;
+		}
+		if (rs->rs_status & AR5K_RXERR_MIC) {
+			sc->stats.rxerr_mic++;
+			return true;
+		}
+
+		/* let crypto-error packets fall through in MNTR */
+		if ((rs->rs_status & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
+		    sc->opmode != NL80211_IFTYPE_MONITOR)
+			return false;
+	}
+
+	if (unlikely(rs->rs_more)) {
+		sc->stats.rxerr_jumbo++;
+		return false;
+	}
+	return true;
+}
+
+static void
+ath5k_tasklet_rx(unsigned long data)
+{
 	struct ath5k_rx_status rs = {};
 	struct sk_buff *skb, *next_skb;
 	dma_addr_t next_skb_addr;
@@ -1901,7 +2040,6 @@
 	struct ath5k_buf *bf;
 	struct ath5k_desc *ds;
 	int ret;
-	int rx_flag;
 
 	spin_lock(&sc->rxbuflock);
 	if (list_empty(&sc->rxbuf)) {
@@ -1909,8 +2047,6 @@
 		goto unlock;
 	}
 	do {
-		rx_flag = 0;
-
 		bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
 		BUG_ON(bf->skb == NULL);
 		skb = bf->skb;
@@ -1926,137 +2062,30 @@
 		else if (unlikely(ret)) {
 			ATH5K_ERR(sc, "error in processing rx descriptor\n");
 			sc->stats.rxerr_proc++;
-			spin_unlock(&sc->rxbuflock);
-			return;
+			break;
 		}
 
-		sc->stats.rx_all_count++;
+		if (ath5k_receive_frame_ok(sc, &rs)) {
+			next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr);
 
-		if (unlikely(rs.rs_status)) {
-			if (rs.rs_status & AR5K_RXERR_CRC)
-				sc->stats.rxerr_crc++;
-			if (rs.rs_status & AR5K_RXERR_FIFO)
-				sc->stats.rxerr_fifo++;
-			if (rs.rs_status & AR5K_RXERR_PHY) {
-				sc->stats.rxerr_phy++;
-				if (rs.rs_phyerr > 0 && rs.rs_phyerr < 32)
-					sc->stats.rxerr_phy_code[rs.rs_phyerr]++;
+			/*
+			 * If we can't replace bf->skb with a new skb under
+			 * memory pressure, just skip this packet
+			 */
+			if (!next_skb)
 				goto next;
-			}
-			if (rs.rs_status & AR5K_RXERR_DECRYPT) {
-				/*
-				 * Decrypt error.  If the error occurred
-				 * because there was no hardware key, then
-				 * let the frame through so the upper layers
-				 * can process it.  This is necessary for 5210
-				 * parts which have no way to setup a ``clear''
-				 * key cache entry.
-				 *
-				 * XXX do key cache faulting
-				 */
-				sc->stats.rxerr_decrypt++;
-				if (rs.rs_keyix == AR5K_RXKEYIX_INVALID &&
-				    !(rs.rs_status & AR5K_RXERR_CRC))
-					goto accept;
-			}
-			if (rs.rs_status & AR5K_RXERR_MIC) {
-				rx_flag |= RX_FLAG_MMIC_ERROR;
-				sc->stats.rxerr_mic++;
-				goto accept;
-			}
 
-			/* let crypto-error packets fall through in MNTR */
-			if ((rs.rs_status &
-				~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
-					sc->opmode != NL80211_IFTYPE_MONITOR)
-				goto next;
+			pci_unmap_single(sc->pdev, bf->skbaddr,
+					 common->rx_bufsize,
+					 PCI_DMA_FROMDEVICE);
+
+			skb_put(skb, rs.rs_datalen);
+
+			ath5k_receive_frame(sc, skb, &rs);
+
+			bf->skb = next_skb;
+			bf->skbaddr = next_skb_addr;
 		}
-
-		if (unlikely(rs.rs_more)) {
-			sc->stats.rxerr_jumbo++;
-			goto next;
-
-		}
-accept:
-		next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr);
-
-		/*
-		 * If we can't replace bf->skb with a new skb under memory
-		 * pressure, just skip this packet
-		 */
-		if (!next_skb)
-			goto next;
-
-		pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize,
-				PCI_DMA_FROMDEVICE);
-		skb_put(skb, rs.rs_datalen);
-
-		/* 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. */
-		ath5k_remove_padding(skb);
-
-		rxs = IEEE80211_SKB_RXCB(skb);
-
-		/*
-		 * always extend the mac timestamp, since this information is
-		 * also needed for proper IBSS merging.
-		 *
-		 * XXX: it might be too late to do it here, since rs_tstamp is
-		 * 15bit only. that means TSF extension has to be done within
-		 * 32768usec (about 32ms). it might be necessary to move this to
-		 * the interrupt handler, like it is done in madwifi.
-		 *
-		 * Unfortunately we don't know when the hardware takes the rx
-		 * timestamp (beginning of phy frame, data frame, end of rx?).
-		 * The only thing we know is that it is hardware specific...
-		 * On AR5213 it seems the rx timestamp is at the end of the
-		 * frame, but i'm not sure.
-		 *
-		 * NOTE: mac80211 defines mactime at the beginning of the first
-		 * data symbol. Since we don't have any time references it's
-		 * impossible to comply to that. This affects IBSS merge only
-		 * right now, so it's not too bad...
-		 */
-		rxs->mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp);
-		rxs->flag = rx_flag | RX_FLAG_TSFT;
-
-		rxs->freq = sc->curchan->center_freq;
-		rxs->band = sc->curband->band;
-
-		rxs->signal = sc->ah->ah_noise_floor + rs.rs_rssi;
-
-		rxs->antenna = rs.rs_antenna;
-
-		if (rs.rs_antenna > 0 && rs.rs_antenna < 5)
-			sc->stats.antenna_rx[rs.rs_antenna]++;
-		else
-			sc->stats.antenna_rx[0]++; /* invalid */
-
-		rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
-		rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
-
-		if (rxs->rate_idx >= 0 && rs.rs_rate ==
-		    sc->curband->bitrates[rxs->rate_idx].hw_value_short)
-			rxs->flag |= RX_FLAG_SHORTPRE;
-
-		ath5k_debug_dump_skb(sc, skb, "RX  ", 0);
-
-		ath5k_update_beacon_rssi(sc, skb, rs.rs_rssi);
-
-		/* check beacons in IBSS mode */
-		if (sc->opmode == NL80211_IFTYPE_ADHOC)
-			ath5k_check_ibss_tsf(sc, skb, rxs);
-
-		ieee80211_rx(sc->hw, skb);
-
-		bf->skb = next_skb;
-		bf->skbaddr = next_skb_addr;
 next:
 		list_move_tail(&bf->list, &sc->rxbuf);
 	} while (ath5k_rxbuf_setup(sc, bf) == 0);
@@ -2065,8 +2094,6 @@
 }
 
 
-
-
 /*************\
 * TX Handling *
 \*************/
@@ -2266,8 +2293,8 @@
  * frame contents are done as needed and the slot time is
  * also adjusted based on current state.
  *
- * This is called from software irq context (beacontq or restq
- * tasklets) or user context from ath5k_beacon_config.
+ * This is called from software irq context (beacontq tasklets)
+ * or user context from ath5k_beacon_config.
  */
 static void
 ath5k_beacon_send(struct ath5k_softc *sc)
@@ -2298,7 +2325,9 @@
 			ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
 				"stuck beacon time (%u missed)\n",
 				sc->bmisscount);
-			tasklet_schedule(&sc->restq);
+			ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+				  "stuck beacon, resetting\n");
+			ieee80211_queue_work(sc->hw, &sc->reset_work);
 		}
 		return;
 	}
@@ -2602,12 +2631,20 @@
 	if (!test_bit(ATH_STAT_INVALID, sc->status)) {
 		ath5k_rx_stop(sc);
 		ath5k_hw_phy_disable(ah);
-	} else
-		sc->rxlink = NULL;
+	}
 
 	return 0;
 }
 
+static void stop_tasklets(struct ath5k_softc *sc)
+{
+	tasklet_kill(&sc->rxtq);
+	tasklet_kill(&sc->txtq);
+	tasklet_kill(&sc->calib);
+	tasklet_kill(&sc->beacontq);
+	tasklet_kill(&sc->ani_tasklet);
+}
+
 /*
  * Stop the device, grabbing the top-level lock to protect
  * against concurrent entry through ath5k_init (which can happen
@@ -2647,17 +2684,12 @@
 		ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
 				"putting device to sleep\n");
 	}
-	ath5k_txbuf_free(sc, sc->bbuf);
+	ath5k_txbuf_free_skb(sc, sc->bbuf);
 
 	mmiowb();
 	mutex_unlock(&sc->lock);
 
-	tasklet_kill(&sc->rxtq);
-	tasklet_kill(&sc->txtq);
-	tasklet_kill(&sc->restq);
-	tasklet_kill(&sc->calib);
-	tasklet_kill(&sc->beacontq);
-	tasklet_kill(&sc->ani_tasklet);
+	stop_tasklets(sc);
 
 	ath5k_rfkill_hw_stop(sc->ah);
 
@@ -2705,7 +2737,9 @@
 			 * Fatal errors are unrecoverable.
 			 * Typically these are caused by DMA errors.
 			 */
-			tasklet_schedule(&sc->restq);
+			ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+				  "fatal int, resetting\n");
+			ieee80211_queue_work(sc->hw, &sc->reset_work);
 		} else if (unlikely(status & AR5K_INT_RXORN)) {
 			/*
 			 * Receive buffers are full. Either the bus is busy or
@@ -2717,8 +2751,11 @@
 			 * this guess is copied from the HAL.
 			 */
 			sc->stats.rxorn_intr++;
-			if (ah->ah_mac_srev < AR5K_SREV_AR5212)
-				tasklet_schedule(&sc->restq);
+			if (ah->ah_mac_srev < AR5K_SREV_AR5212) {
+				ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+					  "rx overrun, resetting\n");
+				ieee80211_queue_work(sc->hw, &sc->reset_work);
+			}
 			else
 				tasklet_schedule(&sc->rxtq);
 		} else {
@@ -2731,7 +2768,7 @@
 				*     RXE bit is written, but it doesn't work at
 				*     least on older hardware revs.
 				*/
-				sc->rxlink = NULL;
+				sc->stats.rxeol_intr++;
 			}
 			if (status & AR5K_INT_TXURN) {
 				/* bump tx trigger level */
@@ -2764,14 +2801,6 @@
 	return IRQ_HANDLED;
 }
 
-static void
-ath5k_tasklet_reset(unsigned long data)
-{
-	struct ath5k_softc *sc = (void *)data;
-
-	ath5k_reset(sc, sc->curchan);
-}
-
 /*
  * Periodically recalibrate the PHY to account
  * for temperature/environment changes.
@@ -2785,10 +2814,6 @@
 	/* Only full calibration for now */
 	ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
 
-	/* Stop queues so that calibration
-	 * doesn't interfere with tx */
-	ieee80211_stop_queues(sc->hw);
-
 	ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
 		ieee80211_frequency_to_channel(sc->curchan->center_freq),
 		sc->curchan->hw_value);
@@ -2799,15 +2824,23 @@
 		 * to load new gain values.
 		 */
 		ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n");
-		ath5k_reset(sc, sc->curchan);
+		ieee80211_queue_work(sc->hw, &sc->reset_work);
 	}
 	if (ath5k_hw_phy_calibrate(ah, sc->curchan))
 		ATH5K_ERR(sc, "calibration of channel %u failed\n",
 			ieee80211_frequency_to_channel(
 				sc->curchan->center_freq));
 
-	/* Wake queues */
-	ieee80211_wake_queues(sc->hw);
+	/* Noise floor calibration interrupts rx/tx path while I/Q calibration
+	 * doesn't. We stop the queues so that calibration doesn't interfere
+	 * with TX and don't run it as often */
+	if (time_is_before_eq_jiffies(ah->ah_cal_next_nf)) {
+		ah->ah_cal_next_nf = jiffies +
+			msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_NF);
+		ieee80211_stop_queues(sc->hw);
+		ath5k_hw_update_noise_floor(ah);
+		ieee80211_wake_queues(sc->hw);
+	}
 
 	ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
 }
@@ -2895,6 +2928,8 @@
 /*
  * Reset the hardware.  If chan is not NULL, then also pause rx/tx
  * and change to the given channel.
+ *
+ * This should be called with sc->lock.
  */
 static int
 ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
@@ -2904,8 +2939,11 @@
 
 	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
 
+	ath5k_hw_set_imr(ah, 0);
+	synchronize_irq(sc->pdev->irq);
+	stop_tasklets(sc);
+
 	if (chan) {
-		ath5k_hw_set_imr(ah, 0);
 		ath5k_txq_cleanup(sc);
 		ath5k_rx_stop(sc);
 
@@ -2926,6 +2964,10 @@
 
 	ath5k_ani_init(ah, ah->ah_sc->ani_state.ani_mode);
 
+	ah->ah_cal_next_full = jiffies;
+	ah->ah_cal_next_ani = jiffies;
+	ah->ah_cal_next_nf = jiffies;
+
 	/*
 	 * Change channels and update the h/w rate map if we're switching;
 	 * e.g. 11a to 11b/g.
@@ -2947,6 +2989,16 @@
 	return ret;
 }
 
+static void ath5k_reset_work(struct work_struct *work)
+{
+	struct ath5k_softc *sc = container_of(work, struct ath5k_softc,
+		reset_work);
+
+	mutex_lock(&sc->lock);
+	ath5k_reset(sc, sc->curchan);
+	mutex_unlock(&sc->lock);
+}
+
 static int ath5k_start(struct ieee80211_hw *hw)
 {
 	return ath5k_init(hw->priv);
@@ -3360,7 +3412,7 @@
 
 	ath5k_debug_dump_skb(sc, skb, "BC  ", 1);
 
-	ath5k_txbuf_free(sc, sc->bbuf);
+	ath5k_txbuf_free_skb(sc, sc->bbuf);
 	sc->bbuf->skb = skb;
 	ret = ath5k_beacon_setup(sc, sc->bbuf);
 	if (ret)
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 56221bc..dc1241f 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -47,6 +47,7 @@
 #include <linux/if_ether.h>
 #include <linux/leds.h>
 #include <linux/rfkill.h>
+#include <linux/workqueue.h>
 
 #include "ath5k.h"
 #include "debug.h"
@@ -136,6 +137,7 @@
 
 	unsigned int mib_intr;
 	unsigned int rxorn_intr;
+	unsigned int rxeol_intr;
 };
 
 #if CHAN_DEBUG
@@ -189,7 +191,7 @@
 	unsigned int		led_pin,	/* GPIO pin for driving LED */
 				led_on;		/* pin setting for LED on */
 
-	struct tasklet_struct	restq;		/* reset tasklet */
+	struct work_struct	reset_work;	/* deferred chip reset */
 
 	unsigned int		rxbufsize;	/* rx size based on mtu */
 	struct list_head	rxbuf;		/* receive buffer */
diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c
index 74f0071..beae519 100644
--- a/drivers/net/wireless/ath/ath5k/caps.c
+++ b/drivers/net/wireless/ath/ath5k/caps.c
@@ -34,7 +34,6 @@
 {
 	u16 ee_header;
 
-	ATH5K_TRACE(ah->ah_sc);
 	/* Capabilities stored in the EEPROM */
 	ee_header = ah->ah_capabilities.cap_eeprom.ee_header;
 
@@ -123,8 +122,6 @@
 		enum ath5k_capability_type cap_type,
 		u32 capability, u32 *result)
 {
-	ATH5K_TRACE(ah->ah_sc);
-
 	switch (cap_type) {
 	case AR5K_CAP_NUM_TXQUEUES:
 		if (result) {
@@ -173,8 +170,6 @@
 int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid,
 		u16 assoc_id)
 {
-	ATH5K_TRACE(ah->ah_sc);
-
 	if (ah->ah_version == AR5K_AR5210) {
 		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
 			AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
@@ -186,8 +181,6 @@
 
 int ath5k_hw_disable_pspoll(struct ath5k_hw *ah)
 {
-	ATH5K_TRACE(ah->ah_sc);
-
 	if (ah->ah_version == AR5K_AR5210) {
 		AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
 			AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 6fb5c5f..4cccc29 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -239,6 +239,9 @@
 		"TSF\t\t0x%016llx\tTU: %08x\n",
 		(unsigned long long)tsf, TSF_TO_TU(tsf));
 
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -278,7 +281,8 @@
 				 size_t count, loff_t *ppos)
 {
 	struct ath5k_softc *sc = file->private_data;
-	tasklet_schedule(&sc->restq);
+	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "debug file triggered reset\n");
+	ieee80211_queue_work(sc->hw, &sc->reset_work);
 	return count;
 }
 
@@ -307,7 +311,6 @@
 	{ ATH5K_DEBUG_DUMP_RX,	"dumprx",	"print received skb content" },
 	{ ATH5K_DEBUG_DUMP_TX,	"dumptx",	"print transmit skb content" },
 	{ ATH5K_DEBUG_DUMPBANDS, "dumpbands",	"dump bands" },
-	{ ATH5K_DEBUG_TRACE,	"trace",	"trace function calls" },
 	{ ATH5K_DEBUG_ANI,	"ani",		"adaptive noise immunity" },
 	{ ATH5K_DEBUG_ANY,	"all",		"show all debug levels" },
 };
@@ -334,6 +337,9 @@
 		sc->debug.level == dbg_info[i].level ? '+' : ' ',
 		dbg_info[i].level, dbg_info[i].desc);
 
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -426,6 +432,16 @@
 		"AR5K_PHY_FAST_ANT_DIV_EN\t%d\n",
 		(v & AR5K_PHY_FAST_ANT_DIV_EN) != 0);
 
+	v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_ANT_SWITCH_TABLE_0);
+	len += snprintf(buf+len, sizeof(buf)-len,
+			"\nAR5K_PHY_ANT_SWITCH_TABLE_0\t0x%08x\n", v);
+	v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_ANT_SWITCH_TABLE_1);
+	len += snprintf(buf+len, sizeof(buf)-len,
+			"AR5K_PHY_ANT_SWITCH_TABLE_1\t0x%08x\n", v);
+
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -535,6 +551,9 @@
 	len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%d]\n",
 			st->tx_all_count);
 
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -674,6 +693,9 @@
 			ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
 			ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2)));
 
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -729,6 +751,69 @@
 };
 
 
+/* debugfs: queues etc */
+
+static ssize_t read_file_queue(struct file *file, char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+	struct ath5k_softc *sc = file->private_data;
+	char buf[700];
+	unsigned int len = 0;
+
+	struct ath5k_txq *txq;
+	struct ath5k_buf *bf, *bf0;
+	int i, n = 0;
+
+	len += snprintf(buf+len, sizeof(buf)-len,
+			"available txbuffers: %d\n", sc->txbuf_len);
+
+	for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) {
+		txq = &sc->txqs[i];
+
+		len += snprintf(buf+len, sizeof(buf)-len,
+			"%02d: %ssetup\n", i, txq->setup ? "" : "not ");
+
+		if (!txq->setup)
+			continue;
+
+		list_for_each_entry_safe(bf, bf0, &txq->q, list)
+			n++;
+		len += snprintf(buf+len, sizeof(buf)-len, "  len: %d\n", n);
+	}
+
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_queue(struct file *file,
+				 const char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	struct ath5k_softc *sc = file->private_data;
+	char buf[20];
+
+	if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
+		return -EFAULT;
+
+	if (strncmp(buf, "start", 5) == 0)
+		ieee80211_wake_queues(sc->hw);
+	else if (strncmp(buf, "stop", 4) == 0)
+		ieee80211_stop_queues(sc->hw);
+
+	return count;
+}
+
+
+static const struct file_operations fops_queue = {
+	.read = read_file_queue,
+	.write = write_file_queue,
+	.open = ath5k_debugfs_open,
+	.owner = THIS_MODULE,
+};
+
+
 /* init */
 
 void
@@ -772,6 +857,11 @@
 				S_IWUSR | S_IRUSR,
 				sc->debug.debugfs_phydir, sc,
 				&fops_ani);
+
+	sc->debug.debugfs_queue = debugfs_create_file("queue",
+				S_IWUSR | S_IRUSR,
+				sc->debug.debugfs_phydir, sc,
+				&fops_queue);
 }
 
 void
@@ -790,6 +880,7 @@
 	debugfs_remove(sc->debug.debugfs_antenna);
 	debugfs_remove(sc->debug.debugfs_frameerrors);
 	debugfs_remove(sc->debug.debugfs_ani);
+	debugfs_remove(sc->debug.debugfs_queue);
 	debugfs_remove(sc->debug.debugfs_phydir);
 }
 
@@ -852,7 +943,7 @@
 		ds, (unsigned long long)bf->daddr,
 		ds->ds_link, ds->ds_data,
 		rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1,
-		rd->u.rx_stat.rx_status_0, rd->u.rx_stat.rx_status_0,
+		rd->rx_stat.rx_status_0, rd->rx_stat.rx_status_1,
 		!done ? ' ' : (rs->rs_status == 0) ? '*' : '!');
 }
 
@@ -867,7 +958,7 @@
 	if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
 		return;
 
-	printk(KERN_DEBUG "rx queue %x, link %p\n",
+	printk(KERN_DEBUG "rxdp %x, rxlink %p\n",
 		ath5k_hw_get_rxdp(ah), sc->rxlink);
 
 	spin_lock_bh(&sc->rxbuflock);
diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h
index ddd5b3a..606ae94 100644
--- a/drivers/net/wireless/ath/ath5k/debug.h
+++ b/drivers/net/wireless/ath/ath5k/debug.h
@@ -77,6 +77,7 @@
 	struct dentry		*debugfs_antenna;
 	struct dentry		*debugfs_frameerrors;
 	struct dentry		*debugfs_ani;
+	struct dentry		*debugfs_queue;
 };
 
 /**
@@ -115,18 +116,12 @@
 	ATH5K_DEBUG_DUMP_RX	= 0x00000100,
 	ATH5K_DEBUG_DUMP_TX	= 0x00000200,
 	ATH5K_DEBUG_DUMPBANDS	= 0x00000400,
-	ATH5K_DEBUG_TRACE	= 0x00001000,
 	ATH5K_DEBUG_ANI		= 0x00002000,
 	ATH5K_DEBUG_ANY		= 0xffffffff
 };
 
 #ifdef CONFIG_ATH5K_DEBUG
 
-#define ATH5K_TRACE(_sc) do { \
-	if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \
-		printk(KERN_DEBUG "ath5k trace %s:%d\n", __func__, __LINE__); \
-	} while (0)
-
 #define ATH5K_DBG(_sc, _m, _fmt, ...) do { \
 	if (unlikely((_sc)->debug.level & (_m) && net_ratelimit())) \
 		ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \
@@ -168,8 +163,6 @@
 
 #include <linux/compiler.h>
 
-#define ATH5K_TRACE(_sc) typecheck(struct ath5k_softc *, (_sc))
-
 static inline void __attribute__ ((format (printf, 3, 4)))
 ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {}
 
diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c
index 7d7b646..4324438 100644
--- a/drivers/net/wireless/ath/ath5k/desc.c
+++ b/drivers/net/wireless/ath/ath5k/desc.c
@@ -91,14 +91,13 @@
 	tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
 
 	/*
-	 * Verify and set header length
-	 * XXX: I only found that on 5210 code, does it work on 5211 ?
+	 * Verify and set header length (only 5210)
 	 */
 	if (ah->ah_version == AR5K_AR5210) {
-		if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN)
+		if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210)
 			return -EINVAL;
 		tx_ctl->tx_control_0 |=
-			AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
+			AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210);
 	}
 
 	/*Differences between 5210-5211*/
@@ -110,11 +109,11 @@
 		case AR5K_PKT_TYPE_PIFS:
 			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
 		default:
-			frame_type = type /*<< 2 ?*/;
+			frame_type = type;
 		}
 
 		tx_ctl->tx_control_0 |=
-		AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) |
+		AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210) |
 		AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
 
 	} else {
@@ -123,21 +122,30 @@
 			AR5K_REG_SM(antenna_mode,
 				AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
 		tx_ctl->tx_control_1 |=
-			AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE);
+			AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211);
 	}
+
 #define _TX_FLAGS(_c, _flag)					\
 	if (flags & AR5K_TXDESC_##_flag) {			\
 		tx_ctl->tx_control_##_c |=			\
 			AR5K_2W_TX_DESC_CTL##_c##_##_flag;	\
 	}
-
+#define _TX_FLAGS_5211(_c, _flag)					\
+	if (flags & AR5K_TXDESC_##_flag) {				\
+		tx_ctl->tx_control_##_c |=				\
+			AR5K_2W_TX_DESC_CTL##_c##_##_flag##_5211;	\
+	}
 	_TX_FLAGS(0, CLRDMASK);
-	_TX_FLAGS(0, VEOL);
 	_TX_FLAGS(0, INTREQ);
 	_TX_FLAGS(0, RTSENA);
-	_TX_FLAGS(1, NOACK);
+
+	if (ah->ah_version == AR5K_AR5211) {
+		_TX_FLAGS_5211(0, VEOL);
+		_TX_FLAGS_5211(1, NOACK);
+	}
 
 #undef _TX_FLAGS
+#undef _TX_FLAGS_5211
 
 	/*
 	 * WEP crap
@@ -147,7 +155,7 @@
 			AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
 		tx_ctl->tx_control_1 |=
 			AR5K_REG_SM(key_index,
-			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
+			AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX);
 	}
 
 	/*
@@ -156,7 +164,7 @@
 	if ((ah->ah_version == AR5K_AR5210) &&
 			(flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
 		tx_ctl->tx_control_1 |= rtscts_duration &
-				AR5K_2W_TX_DESC_CTL1_RTS_DURATION;
+				AR5K_2W_TX_DESC_CTL1_RTS_DURATION_5210;
 
 	return 0;
 }
@@ -176,7 +184,6 @@
 	struct ath5k_hw_4w_tx_ctl *tx_ctl;
 	unsigned int frame_len;
 
-	ATH5K_TRACE(ah->ah_sc);
 	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
 
 	/*
@@ -256,7 +263,7 @@
 	if (key_index != AR5K_TXKEYIX_INVALID) {
 		tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
 		tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index,
-				AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
+				AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX);
 	}
 
 	/*
@@ -278,13 +285,17 @@
 /*
  * Initialize a 4-word multi rate retry tx control descriptor on 5212
  */
-static int
+int
 ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
 	unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
 	u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3)
 {
 	struct ath5k_hw_4w_tx_ctl *tx_ctl;
 
+	/* no mrr support for cards older than 5212 */
+	if (ah->ah_version < AR5K_AR5212)
+		return 0;
+
 	/*
 	 * Rates can be 0 as long as the retry count is 0 too.
 	 * A zero rate and nonzero retry count will put the HW into a mode where
@@ -324,15 +335,6 @@
 	return 0;
 }
 
-/* no mrr support for cards older than 5212 */
-static int
-ath5k_hw_setup_no_mrr(struct ath5k_hw *ah, struct ath5k_desc *desc,
-	unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
-	u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3)
-{
-	return 0;
-}
-
 /*
  * Proccess the tx status descriptor on 5210/5211
  */
@@ -342,8 +344,6 @@
 	struct ath5k_hw_2w_tx_ctl *tx_ctl;
 	struct ath5k_hw_tx_status *tx_status;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
 	tx_status = &desc->ud.ds_tx5210.tx_stat;
 
@@ -396,8 +396,6 @@
 	struct ath5k_hw_4w_tx_ctl *tx_ctl;
 	struct ath5k_hw_tx_status *tx_status;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
 	tx_status = &desc->ud.ds_tx5212.tx_stat;
 
@@ -419,11 +417,11 @@
 	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
 		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
 	ts->ts_antenna = (tx_status->tx_status_1 &
-		AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
+		AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1;
 	ts->ts_status = 0;
 
 	ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1,
-			AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX);
+			AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212);
 
 	/* The longretry counter has the number of un-acked retries
 	 * for the final rate. To get the total number of retries
@@ -485,12 +483,11 @@
 /*
  * Initialize an rx control descriptor
  */
-static int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
-			u32 size, unsigned int flags)
+int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+			   u32 size, unsigned int flags)
 {
 	struct ath5k_hw_rx_ctl *rx_ctl;
 
-	ATH5K_TRACE(ah->ah_sc);
 	rx_ctl = &desc->ud.ds_rx.rx_ctl;
 
 	/*
@@ -502,10 +499,11 @@
 	*/
 	memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc));
 
+	if (unlikely(size & ~AR5K_DESC_RX_CTL1_BUF_LEN))
+		return -EINVAL;
+
 	/* Setup descriptor */
 	rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
-	if (unlikely(rx_ctl->rx_control_1 != size))
-		return -EINVAL;
 
 	if (flags & AR5K_RXDESC_INTREQ)
 		rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
@@ -521,13 +519,15 @@
 {
 	struct ath5k_hw_rx_status *rx_status;
 
-	rx_status = &desc->ud.ds_rx.u.rx_stat;
+	rx_status = &desc->ud.ds_rx.rx_stat;
 
 	/* No frame received / not ready */
 	if (unlikely(!(rx_status->rx_status_1 &
-	AR5K_5210_RX_DESC_STATUS1_DONE)))
+			AR5K_5210_RX_DESC_STATUS1_DONE)))
 		return -EINPROGRESS;
 
+	memset(rs, 0, sizeof(struct ath5k_rx_status));
+
 	/*
 	 * Frame receive status
 	 */
@@ -537,15 +537,23 @@
 		AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL);
 	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
 		AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE);
-	rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
-		AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA);
 	rs->rs_more = !!(rx_status->rx_status_0 &
 		AR5K_5210_RX_DESC_STATUS0_MORE);
-	/* TODO: this timestamp is 13 bit, later on we assume 15 bit */
+	/* TODO: this timestamp is 13 bit, later on we assume 15 bit!
+	 * also the HAL code for 5210 says the timestamp is bits [10..22] of the
+	 * TSF, and extends the timestamp here to 15 bit.
+	 * we need to check on 5210...
+	 */
 	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
 		AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
-	rs->rs_status = 0;
-	rs->rs_phyerr = 0;
+
+	if (ah->ah_version == AR5K_AR5211)
+		rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
+				AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5211);
+	else
+		rs->rs_antenna = (rx_status->rx_status_0 &
+				AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5210)
+				? 2 : 1;
 
 	/*
 	 * Key table status
@@ -560,19 +568,21 @@
 	 * Receive/descriptor errors
 	 */
 	if (!(rx_status->rx_status_1 &
-	AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+			AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
 		if (rx_status->rx_status_1 &
 				AR5K_5210_RX_DESC_STATUS1_CRC_ERROR)
 			rs->rs_status |= AR5K_RXERR_CRC;
 
-		if (rx_status->rx_status_1 &
-				AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN)
+		/* only on 5210 */
+		if ((ah->ah_version == AR5K_AR5210) &&
+		    (rx_status->rx_status_1 &
+				AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN_5210))
 			rs->rs_status |= AR5K_RXERR_FIFO;
 
 		if (rx_status->rx_status_1 &
 				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
 			rs->rs_status |= AR5K_RXERR_PHY;
-			rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1,
+			rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1,
 				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR);
 		}
 
@@ -588,22 +598,20 @@
  * Proccess the rx status descriptor on 5212
  */
 static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
-		struct ath5k_desc *desc, struct ath5k_rx_status *rs)
+					struct ath5k_desc *desc,
+					struct ath5k_rx_status *rs)
 {
 	struct ath5k_hw_rx_status *rx_status;
-	struct ath5k_hw_rx_error *rx_err;
 
-	ATH5K_TRACE(ah->ah_sc);
-	rx_status = &desc->ud.ds_rx.u.rx_stat;
-
-	/* Overlay on error */
-	rx_err = &desc->ud.ds_rx.u.rx_err;
+	rx_status = &desc->ud.ds_rx.rx_stat;
 
 	/* No frame received / not ready */
 	if (unlikely(!(rx_status->rx_status_1 &
-	AR5K_5212_RX_DESC_STATUS1_DONE)))
+				AR5K_5212_RX_DESC_STATUS1_DONE)))
 		return -EINPROGRESS;
 
+	memset(rs, 0, sizeof(struct ath5k_rx_status));
+
 	/*
 	 * Frame receive status
 	 */
@@ -619,15 +627,13 @@
 		AR5K_5212_RX_DESC_STATUS0_MORE);
 	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
 		AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
-	rs->rs_status = 0;
-	rs->rs_phyerr = 0;
 
 	/*
 	 * Key table status
 	 */
 	if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
 		rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
-				AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
+					   AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
 	else
 		rs->rs_keyix = AR5K_RXKEYIX_INVALID;
 
@@ -635,7 +641,7 @@
 	 * Receive/descriptor errors
 	 */
 	if (!(rx_status->rx_status_1 &
-	AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+	    AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
 		if (rx_status->rx_status_1 &
 				AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
 			rs->rs_status |= AR5K_RXERR_CRC;
@@ -643,9 +649,10 @@
 		if (rx_status->rx_status_1 &
 				AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
 			rs->rs_status |= AR5K_RXERR_PHY;
-			rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1,
-					   AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
-			ath5k_ani_phy_error_report(ah, rs->rs_phyerr);
+			rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1,
+				AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE);
+			if (!ah->ah_capabilities.cap_has_phyerr_counters)
+				ath5k_ani_phy_error_report(ah, rs->rs_phyerr);
 		}
 
 		if (rx_status->rx_status_1 &
@@ -656,7 +663,6 @@
 				AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
 			rs->rs_status |= AR5K_RXERR_MIC;
 	}
-
 	return 0;
 }
 
@@ -665,29 +671,15 @@
  */
 int ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
 {
-
-	if (ah->ah_version != AR5K_AR5210 &&
-		ah->ah_version != AR5K_AR5211 &&
-		ah->ah_version != AR5K_AR5212)
-			return -ENOTSUPP;
-
 	if (ah->ah_version == AR5K_AR5212) {
-		ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
 		ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
-		ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc;
 		ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status;
-	} else {
-		ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
-		ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
-		ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_no_mrr;
-		ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
-	}
-
-	if (ah->ah_version == AR5K_AR5212)
 		ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status;
-	else if (ah->ah_version <= AR5K_AR5211)
+	} else if (ah->ah_version <= AR5K_AR5211) {
+		ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
+		ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
 		ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status;
-
+	} else
+		return -ENOTSUPP;
 	return 0;
 }
-
diff --git a/drivers/net/wireless/ath/ath5k/desc.h b/drivers/net/wireless/ath/ath5k/desc.h
index 64538fb..b2adb2a 100644
--- a/drivers/net/wireless/ath/ath5k/desc.h
+++ b/drivers/net/wireless/ath/ath5k/desc.h
@@ -17,28 +17,24 @@
  */
 
 /*
- * Internal RX/TX descriptor structures
- * (rX: reserved fields possibily used by future versions of the ar5k chipset)
+ * RX/TX descriptor structures
  */
 
 /*
- * common hardware RX control descriptor
+ * Common hardware RX control descriptor
  */
 struct ath5k_hw_rx_ctl {
 	u32	rx_control_0; /* RX control word 0 */
 	u32	rx_control_1; /* RX control word 1 */
 } __packed;
 
-/* RX control word 0 field/sflags */
-#define AR5K_DESC_RX_CTL0			0x00000000
-
 /* RX control word 1 fields/flags */
-#define AR5K_DESC_RX_CTL1_BUF_LEN		0x00000fff
-#define AR5K_DESC_RX_CTL1_INTREQ		0x00002000
+#define AR5K_DESC_RX_CTL1_BUF_LEN		0x00000fff /* data buffer length */
+#define AR5K_DESC_RX_CTL1_INTREQ		0x00002000 /* RX interrupt request */
 
 /*
- * common hardware RX status descriptor
- * 5210/11 and 5212 differ only in the flags defined below
+ * Common hardware RX status descriptor
+ * 5210, 5211 and 5212 differ only in the fields and flags defined below
  */
 struct ath5k_hw_rx_status {
 	u32	rx_status_0; /* RX status word 0 */
@@ -47,81 +43,69 @@
 
 /* 5210/5211 */
 /* RX status word 0 fields/flags */
-#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN		0x00000fff
-#define AR5K_5210_RX_DESC_STATUS0_MORE			0x00001000
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE		0x00078000
+#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN		0x00000fff /* RX data length */
+#define AR5K_5210_RX_DESC_STATUS0_MORE			0x00001000 /* more desc for this frame */
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5210	0x00004000 /* [5210] receive on ant 1 */
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE		0x00078000 /* reception rate */
 #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S	15
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x07f80000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x07f80000 /* rssi */
 #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	19
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA	0x38000000
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	27
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5211	0x38000000 /* [5211] receive antenna */
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5211_S	27
 
 /* RX status word 1 fields/flags */
-#define AR5K_5210_RX_DESC_STATUS1_DONE			0x00000001
-#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
-#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR		0x00000004
-#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN		0x00000008
-#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000010
-#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR		0x000000e0
+#define AR5K_5210_RX_DESC_STATUS1_DONE			0x00000001 /* descriptor complete */
+#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002 /* reception success */
+#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR		0x00000004 /* CRC error */
+#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN_5210	0x00000008 /* [5210] FIFO overrun */
+#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000010 /* decyption CRC failure */
+#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR		0x000000e0 /* PHY error */
 #define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S		5
-#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
-#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX		0x00007e00
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100 /* key index valid */
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX		0x00007e00 /* decyption key index */
 #define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S		9
-#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x0fff8000
+#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x0fff8000 /* 13 bit of TSF */
 #define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	15
-#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS	0x10000000
+#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS	0x10000000 /* key cache miss */
 
 /* 5212 */
 /* RX status word 0 fields/flags */
-#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN		0x00000fff
-#define AR5K_5212_RX_DESC_STATUS0_MORE			0x00001000
-#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR	0x00002000
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE		0x000f8000
+#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN		0x00000fff /* RX data length */
+#define AR5K_5212_RX_DESC_STATUS0_MORE			0x00001000 /* more desc for this frame */
+#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR	0x00002000 /* decompression CRC error */
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE		0x000f8000 /* reception rate */
 #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S	15
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x0ff00000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x0ff00000 /* rssi */
 #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	20
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA	0xf0000000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA	0xf0000000 /* receive antenna */
 #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	28
 
 /* RX status word 1 fields/flags */
-#define AR5K_5212_RX_DESC_STATUS1_DONE			0x00000001
-#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
-#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR		0x00000004
-#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000008
-#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR		0x00000010
-#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR		0x00000020
-#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
-#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX		0x0000fe00
+#define AR5K_5212_RX_DESC_STATUS1_DONE			0x00000001 /* descriptor complete */
+#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002 /* frame reception success */
+#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR		0x00000004 /* CRC error */
+#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000008 /* decryption CRC failure */
+#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR		0x00000010 /* PHY error */
+#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR		0x00000020 /* MIC decrypt error */
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100 /* key index valid */
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX		0x0000fe00 /* decryption key index */
 #define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S		9
-#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x7fff0000
+#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x7fff0000 /* first 15bit of the TSF */
 #define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	16
-#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS	0x80000000
-
-/*
- * common hardware RX error descriptor
- */
-struct ath5k_hw_rx_error {
-	u32	rx_error_0; /* RX status word 0 */
-	u32	rx_error_1; /* RX status word 1 */
-} __packed;
-
-/* RX error word 0 fields/flags */
-#define AR5K_RX_DESC_ERROR0			0x00000000
-
-/* RX error word 1 fields/flags */
-#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE	0x0000ff00
-#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S	8
+#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS	0x80000000 /* key cache miss */
+#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE	0x0000ff00 /* phy error code overlays key index and valid fields */
+#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE_S	8
 
 /**
  * enum ath5k_phy_error_code - PHY Error codes
  */
 enum ath5k_phy_error_code {
-	AR5K_RX_PHY_ERROR_UNDERRUN		= 0,	/* Transmit underrun */
+	AR5K_RX_PHY_ERROR_UNDERRUN		= 0,	/* Transmit underrun, [5210] No error */
 	AR5K_RX_PHY_ERROR_TIMING		= 1,	/* Timing error */
 	AR5K_RX_PHY_ERROR_PARITY		= 2,	/* Illegal parity */
 	AR5K_RX_PHY_ERROR_RATE			= 3,	/* Illegal rate */
 	AR5K_RX_PHY_ERROR_LENGTH		= 4,	/* Illegal length */
-	AR5K_RX_PHY_ERROR_RADAR			= 5,	/* Radar detect */
+	AR5K_RX_PHY_ERROR_RADAR			= 5,	/* Radar detect, [5210] 64 QAM rate */
 	AR5K_RX_PHY_ERROR_SERVICE		= 6,	/* Illegal service */
 	AR5K_RX_PHY_ERROR_TOR			= 7,	/* Transmit override receive */
 	/* these are specific to the 5212 */
@@ -148,112 +132,111 @@
 } __packed;
 
 /* TX control word 0 fields/flags */
-#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
-#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN		0x0003f000 /*[5210 ?]*/
-#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S	12
-#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE		0x003c0000
+#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN		0x00000fff /* frame length */
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210	0x0003f000 /* [5210] header length */
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210_S	12
+#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE		0x003c0000 /* tx rate */
 #define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S	18
-#define AR5K_2W_TX_DESC_CTL0_RTSENA		0x00400000
-#define AR5K_2W_TX_DESC_CTL0_CLRDMASK		0x01000000
-#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET	0x00800000 /*[5210]*/
-#define AR5K_2W_TX_DESC_CTL0_VEOL		0x00800000 /*[5211]*/
-#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE		0x1c000000 /*[5210]*/
-#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S	26
-#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210	0x02000000
-#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211	0x1e000000
-
+#define AR5K_2W_TX_DESC_CTL0_RTSENA		0x00400000 /* RTS/CTS enable */
+#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET_5210	0x00800000 /* [5210] long packet */
+#define AR5K_2W_TX_DESC_CTL0_VEOL_5211		0x00800000 /* [5211] virtual end-of-list */
+#define AR5K_2W_TX_DESC_CTL0_CLRDMASK		0x01000000 /* clear destination mask */
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210	0x02000000 /* [5210] antenna selection */
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211	0x1e000000 /* [5211] antenna selection */
 #define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT			\
 		(ah->ah_version == AR5K_AR5210 ?		\
 		AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 :	\
 		AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211)
-
 #define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
-#define AR5K_2W_TX_DESC_CTL0_INTREQ		0x20000000
-#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210	0x1c000000 /* [5210] frame type */
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210_S	26
+#define AR5K_2W_TX_DESC_CTL0_INTREQ		0x20000000 /* TX interrupt request */
+#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000 /* key is valid */
 
 /* TX control word 1 fields/flags */
-#define AR5K_2W_TX_DESC_CTL1_BUF_LEN		0x00000fff
-#define AR5K_2W_TX_DESC_CTL1_MORE		0x00001000
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210	0x0007e000
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211	0x000fe000
-
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX				\
+#define AR5K_2W_TX_DESC_CTL1_BUF_LEN		0x00000fff /* data buffer length */
+#define AR5K_2W_TX_DESC_CTL1_MORE		0x00001000 /* more desc for this frame */
+#define AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_5210	0x0007e000 /* [5210] key table index */
+#define AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_5211	0x000fe000 /* [5211] key table index */
+#define AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX				\
 			(ah->ah_version == AR5K_AR5210 ?		\
-			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 :	\
-			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211)
-
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
-#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE		0x00700000 /*[5211]*/
-#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S	20
-#define AR5K_2W_TX_DESC_CTL1_NOACK		0x00800000 /*[5211]*/
-#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION	0xfff80000 /*[5210 ?]*/
+			AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_5210 :		\
+			AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_5211)
+#define AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_S	13
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211	0x00700000 /* [5211] frame type */
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211_S	20
+#define AR5K_2W_TX_DESC_CTL1_NOACK_5211		0x00800000 /* [5211] no ACK */
+#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION_5210	0xfff80000 /* [5210] lower 13 bit of duration */
 
 /* Frame types */
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL   0x00
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM     0x04
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL   0x08
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS     0x10
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL	0
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM	1
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL	2
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY	3
+#define AR5K_AR5211_TX_DESC_FRAME_TYPE_BEACON	3
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS	4
+#define AR5K_AR5211_TX_DESC_FRAME_TYPE_PRESP	4
 
 /*
  * 5212 hardware 4-word TX control descriptor
  */
 struct ath5k_hw_4w_tx_ctl {
 	u32	tx_control_0; /* TX control word 0 */
-
-#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
-#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER		0x003f0000
-#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S	16
-#define AR5K_4W_TX_DESC_CTL0_RTSENA		0x00400000
-#define AR5K_4W_TX_DESC_CTL0_VEOL		0x00800000
-#define AR5K_4W_TX_DESC_CTL0_CLRDMASK		0x01000000
-#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT	0x1e000000
-#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
-#define AR5K_4W_TX_DESC_CTL0_INTREQ		0x20000000
-#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
-#define AR5K_4W_TX_DESC_CTL0_CTSENA		0x80000000
-
 	u32	tx_control_1; /* TX control word 1 */
+	u32	tx_control_2; /* TX control word 2 */
+	u32	tx_control_3; /* TX control word 3 */
+} __packed;
 
-#define AR5K_4W_TX_DESC_CTL1_BUF_LEN		0x00000fff
-#define AR5K_4W_TX_DESC_CTL1_MORE		0x00001000
-#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX	0x000fe000
-#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
-#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE		0x00f00000
+/* TX control word 0 fields/flags */
+#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN		0x00000fff /* frame length */
+#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER		0x003f0000 /* transmit power */
+#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S	16
+#define AR5K_4W_TX_DESC_CTL0_RTSENA		0x00400000 /* RTS/CTS enable */
+#define AR5K_4W_TX_DESC_CTL0_VEOL		0x00800000 /* virtual end-of-list */
+#define AR5K_4W_TX_DESC_CTL0_CLRDMASK		0x01000000 /* clear destination mask */
+#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT	0x1e000000 /* TX antenna selection */
+#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
+#define AR5K_4W_TX_DESC_CTL0_INTREQ		0x20000000 /* TX interrupt request */
+#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000 /* destination index valid */
+#define AR5K_4W_TX_DESC_CTL0_CTSENA		0x80000000 /* precede frame with CTS */
+
+/* TX control word 1 fields/flags */
+#define AR5K_4W_TX_DESC_CTL1_BUF_LEN		0x00000fff /* data buffer length */
+#define AR5K_4W_TX_DESC_CTL1_MORE		0x00001000 /* more desc for this frame */
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX	0x000fe000 /* destination table index */
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX_S	13
+#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE		0x00f00000 /* frame type */
 #define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S	20
-#define AR5K_4W_TX_DESC_CTL1_NOACK		0x01000000
-#define AR5K_4W_TX_DESC_CTL1_COMP_PROC		0x06000000
+#define AR5K_4W_TX_DESC_CTL1_NOACK		0x01000000 /* no ACK */
+#define AR5K_4W_TX_DESC_CTL1_COMP_PROC		0x06000000 /* compression processing */
 #define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S	25
-#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN	0x18000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN	0x18000000 /* length of frame IV */
 #define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S	27
-#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN	0x60000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN	0x60000000 /* length of frame ICV */
 #define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S	29
 
-	u32	tx_control_2; /* TX control word 2 */
+/* TX control word 2 fields/flags */
+#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION	0x00007fff /* RTS/CTS duration */
+#define AR5K_4W_TX_DESC_CTL2_DURATION_UPD_EN	0x00008000 /* frame duration update */
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0	0x000f0000 /* series 0 max attempts */
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S	16
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1	0x00f00000 /* series 1 max attempts */
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S	20
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2	0x0f000000 /* series 2 max attempts */
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S	24
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3	0xf0000000 /* series 3 max attempts */
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S	28
 
-#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION		0x00007fff
-#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE	0x00008000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0		0x000f0000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S		16
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1		0x00f00000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S		20
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2		0x0f000000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S		24
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3		0xf0000000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S		28
-
-	u32	tx_control_3; /* TX control word 3 */
-
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0		0x0000001f
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1		0x000003e0
+/* TX control word 3 fields/flags */
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0		0x0000001f /* series 0 tx rate */
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1		0x000003e0 /* series 1 tx rate */
 #define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S	5
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2		0x00007c00
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2		0x00007c00 /* series 2 tx rate */
 #define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S	10
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3		0x000f8000
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3		0x000f8000 /* series 3 tx rate */
 #define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S	15
-#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE	0x01f00000
+#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE	0x01f00000 /* RTS or CTS rate */
 #define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S	20
-} __packed;
 
 /*
  * Common TX status descriptor
@@ -264,37 +247,34 @@
 } __packed;
 
 /* TX status word 0 fields/flags */
-#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK	0x00000001
-#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES	0x00000002
-#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN	0x00000004
-#define AR5K_DESC_TX_STATUS0_FILTERED		0x00000008
-/*???
-#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT	0x000000f0
-#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S	4
-*/
-#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT	0x000000f0
+#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK	0x00000001 /* TX success */
+#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES	0x00000002 /* excessive retries */
+#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN	0x00000004 /* FIFO underrun */
+#define AR5K_DESC_TX_STATUS0_FILTERED		0x00000008 /* TX filter indication */
+/* according to the HAL sources the spec has short/long retry counts reversed.
+ * we have it reversed to the HAL sources as well, for 5210 and 5211.
+ * For 5212 these fields are defined as RTS_FAIL_COUNT and DATA_FAIL_COUNT,
+ * but used respectively as SHORT and LONG retry count in the code later. This
+ * is consistent with the definitions here... TODO: check */
+#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT	0x000000f0 /* short retry count */
 #define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S	4
-/*???
-#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT	0x00000f00
-#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S	8
-*/
-#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT	0x00000f00
+#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT	0x00000f00 /* long retry count */
 #define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S	8
-#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT	0x0000f000
-#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S	12
-#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP	0xffff0000
+#define AR5K_DESC_TX_STATUS0_VIRTCOLL_CT_5211	0x0000f000 /* [5211+] virtual collision count */
+#define AR5K_DESC_TX_STATUS0_VIRTCOLL_CT_5212_S	12
+#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP	0xffff0000 /* TX timestamp */
 #define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S	16
 
 /* TX status word 1 fields/flags */
-#define AR5K_DESC_TX_STATUS1_DONE		0x00000001
-#define AR5K_DESC_TX_STATUS1_SEQ_NUM		0x00001ffe
+#define AR5K_DESC_TX_STATUS1_DONE		0x00000001 /* descriptor complete */
+#define AR5K_DESC_TX_STATUS1_SEQ_NUM		0x00001ffe /* TX sequence number */
 #define AR5K_DESC_TX_STATUS1_SEQ_NUM_S		1
-#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH	0x001fe000
+#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH	0x001fe000 /* signal strength of ACK */
 #define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S	13
-#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX	0x00600000
-#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S	21
-#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS	0x00800000
-#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA	0x01000000
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212	0x00600000 /* [5212] final TX attempt series ix */
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212_S	21
+#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS_5212	0x00800000 /* [5212] compression status */
+#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212	0x01000000 /* [5212] transmit antenna */
 
 /*
  * 5210/5211 hardware TX descriptor
@@ -313,18 +293,15 @@
 } __packed;
 
 /*
- * common hardware RX descriptor
+ * Common hardware RX descriptor
  */
 struct ath5k_hw_all_rx_desc {
-	struct ath5k_hw_rx_ctl			rx_ctl;
-	union {
-		struct ath5k_hw_rx_status	rx_stat;
-		struct ath5k_hw_rx_error	rx_err;
-	} u;
+	struct ath5k_hw_rx_ctl		rx_ctl;
+	struct ath5k_hw_rx_status	rx_stat;
 } __packed;
 
 /*
- * Atheros hardware descriptor
+ * Atheros hardware DMA descriptor
  * This is read and written to by the hardware
  */
 struct ath5k_desc {
@@ -346,4 +323,3 @@
 #define AR5K_TXDESC_CTSENA	0x0008
 #define AR5K_TXDESC_INTREQ	0x0010
 #define AR5K_TXDESC_VEOL	0x0020	/*[5211+]*/
-
diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c
index 941b511..484f318 100644
--- a/drivers/net/wireless/ath/ath5k/dma.c
+++ b/drivers/net/wireless/ath/ath5k/dma.c
@@ -48,7 +48,6 @@
  */
 void ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
 {
-	ATH5K_TRACE(ah->ah_sc);
 	ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
 	ath5k_hw_reg_read(ah, AR5K_CR);
 }
@@ -62,7 +61,6 @@
 {
 	unsigned int i;
 
-	ATH5K_TRACE(ah->ah_sc);
 	ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
 
 	/*
@@ -96,8 +94,6 @@
  */
 void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
 {
-	ATH5K_TRACE(ah->ah_sc);
-
 	ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
 }
 
@@ -125,7 +121,6 @@
 {
 	u32 tx_queue;
 
-	ATH5K_TRACE(ah->ah_sc);
 	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
 
 	/* Return if queue is declared inactive */
@@ -186,7 +181,6 @@
 	unsigned int i = 40;
 	u32 tx_queue, pending;
 
-	ATH5K_TRACE(ah->ah_sc);
 	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
 
 	/* Return if queue is declared inactive */
@@ -297,7 +291,6 @@
 {
 	u16 tx_reg;
 
-	ATH5K_TRACE(ah->ah_sc);
 	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
 
 	/*
@@ -340,7 +333,6 @@
 {
 	u16 tx_reg;
 
-	ATH5K_TRACE(ah->ah_sc);
 	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
 
 	/*
@@ -400,8 +392,6 @@
 	u32 trigger_level, imr;
 	int ret = -EIO;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	/*
 	 * Disable interrupts by setting the mask
 	 */
@@ -451,7 +441,6 @@
  */
 bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
 {
-	ATH5K_TRACE(ah->ah_sc);
 	return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0;
 }
 
@@ -475,8 +464,6 @@
 {
 	u32 data;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	/*
 	 * Read interrupt status from the Interrupt Status register
 	 * on 5210
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index ed02636..ae316fe 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -35,7 +35,6 @@
 {
 	u32 status, timeout;
 
-	ATH5K_TRACE(ah->ah_sc);
 	/*
 	 * Initialize EEPROM access
 	 */
@@ -715,7 +714,7 @@
 
 		/* Only one curve for RF5111
 		 * find out which one and place
-		 * in in pd_curves.
+		 * in pd_curves.
 		 * Note: ee_x_gain is reversed here */
 		for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) {
 
diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c
index 64a27e7..bc90503 100644
--- a/drivers/net/wireless/ath/ath5k/gpio.c
+++ b/drivers/net/wireless/ath/ath5k/gpio.c
@@ -34,8 +34,6 @@
 	/*5210 has different led mode handling*/
 	u32 led_5210;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	/*Reset led status*/
 	if (ah->ah_version != AR5K_AR5210)
 		AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
@@ -82,7 +80,6 @@
  */
 int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
 {
-	ATH5K_TRACE(ah->ah_sc);
 	if (gpio >= AR5K_NUM_GPIO)
 		return -EINVAL;
 
@@ -98,7 +95,6 @@
  */
 int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
 {
-	ATH5K_TRACE(ah->ah_sc);
 	if (gpio >= AR5K_NUM_GPIO)
 		return -EINVAL;
 
@@ -114,7 +110,6 @@
  */
 u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
 {
-	ATH5K_TRACE(ah->ah_sc);
 	if (gpio >= AR5K_NUM_GPIO)
 		return 0xffffffff;
 
@@ -129,7 +124,6 @@
 int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
 {
 	u32 data;
-	ATH5K_TRACE(ah->ah_sc);
 
 	if (gpio >= AR5K_NUM_GPIO)
 		return -EINVAL;
@@ -153,7 +147,6 @@
 {
 	u32 data;
 
-	ATH5K_TRACE(ah->ah_sc);
 	if (gpio >= AR5K_NUM_GPIO)
 		return;
 
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index 5212e27..86fdb6d 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -59,8 +59,6 @@
 
 	beacon_reg = 0;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	switch (op_mode) {
 	case NL80211_IFTYPE_ADHOC:
 		pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
@@ -173,7 +171,6 @@
  */
 static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
 {
-	ATH5K_TRACE(ah->ah_sc);
 	if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK))
 			<= timeout)
 		return -EINVAL;
@@ -192,7 +189,6 @@
  */
 static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
 {
-	ATH5K_TRACE(ah->ah_sc);
 	if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS))
 			<= timeout)
 		return -EINVAL;
@@ -297,7 +293,6 @@
 	u32 low_id, high_id;
 	u32 pcu_reg;
 
-	ATH5K_TRACE(ah->ah_sc);
 	/* Set new station ID */
 	memcpy(common->macaddr, mac, ETH_ALEN);
 
@@ -357,7 +352,6 @@
 void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
 {
 	struct ath_common *common = ath5k_hw_common(ah);
-	ATH5K_TRACE(ah->ah_sc);
 
 	/* Cache bssid mask so that we can restore it
 	 * on reset */
@@ -382,7 +376,6 @@
  */
 void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
 {
-	ATH5K_TRACE(ah->ah_sc);
 	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
 }
 
@@ -397,7 +390,6 @@
  */
 void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
 {
-	ATH5K_TRACE(ah->ah_sc);
 	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
 }
 
@@ -406,8 +398,6 @@
  */
 void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
 {
-	ATH5K_TRACE(ah->ah_sc);
-	/* Set the multicat filter */
 	ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
 	ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
 }
@@ -427,7 +417,6 @@
 {
 	u32 data, filter = 0;
 
-	ATH5K_TRACE(ah->ah_sc);
 	filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
 
 	/*Radar detection for 5212*/
@@ -457,8 +446,6 @@
 {
 	u32 data = 0;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	/* Set PHY error filter register on 5212*/
 	if (ah->ah_version == AR5K_AR5212) {
 		if (filter & AR5K_RX_FILTER_RADARERR)
@@ -533,8 +520,6 @@
 
 	WARN_ON( i == ATH5K_MAX_TSF_READ );
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	return (((u64)tsf_upper1 << 32) | tsf_lower);
 }
 
@@ -548,8 +533,6 @@
  */
 void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64)
 {
-	ATH5K_TRACE(ah->ah_sc);
-
 	ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32);
 	ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32);
 }
@@ -565,8 +548,6 @@
 {
 	u32 val;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF;
 
 	/*
@@ -586,7 +567,6 @@
 {
 	u32 timer1, timer2, timer3;
 
-	ATH5K_TRACE(ah->ah_sc);
 	/*
 	 * Set the additional timers by mode
 	 */
@@ -674,7 +654,6 @@
 	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));
@@ -749,8 +728,6 @@
 	bool is_tkip;
 	const u8 *key_ptr;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	is_tkip = (key->alg == ALG_TKIP);
 
 	/*
@@ -836,7 +813,6 @@
 {
 	u32 low_id, high_id;
 
-	ATH5K_TRACE(ah->ah_sc);
 	 /* Invalid entry (key table overflow) */
 	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
 
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 492cbb1..6284c38 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -378,8 +378,6 @@
 	u32 data, type;
 	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	if (ah->ah_rf_banks == NULL ||
 	ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE)
 		return AR5K_RFGAIN_INACTIVE;
@@ -1167,7 +1165,7 @@
  * The median of the values in the history is then loaded into the
  * hardware for its own use for RSSI and CCA measurements.
  */
-static void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
+void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
 {
 	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
 	u32 val;
@@ -1248,7 +1246,6 @@
 /*
  * Perform a PHY calibration on RF5110
  * -Fix BPSK/QAM Constellation (I/Q correction)
- * -Calculate Noise Floor
  */
 static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
 		struct ieee80211_channel *channel)
@@ -1335,8 +1332,6 @@
 		return ret;
 	}
 
-	ath5k_hw_update_noise_floor(ah);
-
 	/*
 	 * Re-enable RX/TX and beacons
 	 */
@@ -1348,22 +1343,20 @@
 }
 
 /*
- * Perform a PHY calibration on RF5111/5112 and newer chips
+ * Perform I/Q calibration on RF5111/5112 and newer chips
  */
-static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
-		struct ieee80211_channel *channel)
+static int
+ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah)
 {
 	u32 i_pwr, q_pwr;
 	s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
 	int i;
-	ATH5K_TRACE(ah->ah_sc);
 
 	if (!ah->ah_calibration ||
 		ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
-		goto done;
+		return 0;
 
 	/* Calibration has finished, get the results and re-run */
-
 	/* work around empty results which can apparently happen on 5212 */
 	for (i = 0; i <= 10; i++) {
 		iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
@@ -1384,7 +1377,7 @@
 
 	/* protect against divide by 0 and loss of sign bits */
 	if (i_coffd == 0 || q_coffd < 2)
-		goto done;
+		return -1;
 
 	i_coff = (-iq_corr) / i_coffd;
 	i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */
@@ -1410,17 +1403,6 @@
 			AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
 	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN);
 
-done:
-
-	/* TODO: Separate noise floor calibration from I/Q calibration
-	 * since noise floor calibration interrupts rx path while I/Q
-	 * calibration doesn't. We don't need to run noise floor calibration
-	 * as often as I/Q calibration.*/
-	ath5k_hw_update_noise_floor(ah);
-
-	/* Initiate a gain_F calibration */
-	ath5k_hw_request_rfgain_probe(ah);
-
 	return 0;
 }
 
@@ -1434,8 +1416,10 @@
 
 	if (ah->ah_radio == AR5K_RF5110)
 		ret = ath5k_hw_rf5110_calibrate(ah, channel);
-	else
-		ret = ath5k_hw_rf511x_calibrate(ah, channel);
+	else {
+		ret = ath5k_hw_rf511x_iq_calibrate(ah);
+		ath5k_hw_request_rfgain_probe(ah);
+	}
 
 	return ret;
 }
@@ -1693,7 +1677,6 @@
 
 int ath5k_hw_phy_disable(struct ath5k_hw *ah)
 {
-	ATH5K_TRACE(ah->ah_sc);
 	/*Just a try M.F.*/
 	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
 
@@ -1709,8 +1692,6 @@
 	u32 srev;
 	u16 ret;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	/*
 	 * Set the radio chip access register
 	 */
@@ -1755,8 +1736,6 @@
 static void /*TODO:Boundary check*/
 ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant)
 {
-	ATH5K_TRACE(ah->ah_sc);
-
 	if (ah->ah_version != AR5K_AR5210)
 		ath5k_hw_reg_write(ah, ant & 0x7, AR5K_DEFAULT_ANTENNA);
 }
@@ -1789,19 +1768,50 @@
 
 	if (enable) {
 		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART,
-				AR5K_PHY_RESTART_DIV_GC, 0xc);
+				AR5K_PHY_RESTART_DIV_GC, 4);
 
 		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV,
 					AR5K_PHY_FAST_ANT_DIV_EN);
 	} else {
 		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART,
-				AR5K_PHY_RESTART_DIV_GC, 0x8);
+				AR5K_PHY_RESTART_DIV_GC, 0);
 
 		AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV,
 					AR5K_PHY_FAST_ANT_DIV_EN);
 	}
 }
 
+void
+ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode)
+{
+	u8 ant0, ant1;
+
+	/*
+	 * In case a fixed antenna was set as default
+	 * use the same switch table twice.
+	 */
+	if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_A)
+		ant0 = ant1 = AR5K_ANT_SWTABLE_A;
+	else if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_B)
+		ant0 = ant1 = AR5K_ANT_SWTABLE_B;
+	else {
+		ant0 = AR5K_ANT_SWTABLE_A;
+		ant1 = AR5K_ANT_SWTABLE_B;
+	}
+
+	/* Set antenna idle switch table */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL,
+			AR5K_PHY_ANT_CTL_SWTABLE_IDLE,
+			(ah->ah_ant_ctl[ee_mode][AR5K_ANT_CTL] |
+			AR5K_PHY_ANT_CTL_TXRX_EN));
+
+	/* Set antenna switch tables */
+	ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant0],
+		AR5K_PHY_ANT_SWITCH_TABLE_0);
+	ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant1],
+		AR5K_PHY_ANT_SWITCH_TABLE_1);
+}
+
 /*
  * Set antenna operating mode
  */
@@ -1823,8 +1833,6 @@
 
 	def_ant = ah->ah_def_ant;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	switch (channel->hw_value & CHANNEL_MODES) {
 	case CHANNEL_A:
 	case CHANNEL_T:
@@ -1923,6 +1931,7 @@
 	if (sta_id1)
 		AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, sta_id1);
 
+	ath5k_hw_set_antenna_switch(ah, ee_mode);
 	/* Note: set diversity before default antenna
 	 * because it won't work correctly */
 	ath5k_hw_set_fast_div(ah, ee_mode, fast_div);
@@ -2988,7 +2997,6 @@
 	u8 type;
 	int ret;
 
-	ATH5K_TRACE(ah->ah_sc);
 	if (txpower > AR5K_TUNE_MAX_TXPOWER) {
 		ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower);
 		return -EINVAL;
@@ -3084,8 +3092,6 @@
 	struct ieee80211_channel *channel = ah->ah_current_channel;
 	u8 ee_mode;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	switch (channel->hw_value & CHANNEL_MODES) {
 	case CHANNEL_A:
 	case CHANNEL_T:
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index f5831da..4186ff4 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -31,7 +31,6 @@
 int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
 		struct ath5k_txq_info *queue_info)
 {
-	ATH5K_TRACE(ah->ah_sc);
 	memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
 	return 0;
 }
@@ -42,7 +41,6 @@
 int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
 				const struct ath5k_txq_info *queue_info)
 {
-	ATH5K_TRACE(ah->ah_sc);
 	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
 
 	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
@@ -69,8 +67,6 @@
 	unsigned int queue;
 	int ret;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	/*
 	 * Get queue by type
 	 */
@@ -149,7 +145,6 @@
 u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
 {
 	u32 pending;
-	ATH5K_TRACE(ah->ah_sc);
 	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
 
 	/* Return if queue is declared inactive */
@@ -177,7 +172,6 @@
  */
 void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
 {
-	ATH5K_TRACE(ah->ah_sc);
 	if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
 		return;
 
@@ -195,7 +189,6 @@
 	u32 cw_min, cw_max, retry_lg, retry_sh;
 	struct ath5k_txq_info *tq = &ah->ah_txq[queue];
 
-	ATH5K_TRACE(ah->ah_sc);
 	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
 
 	tq = &ah->ah_txq[queue];
@@ -523,8 +516,6 @@
 {
 	u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
 		return -EINVAL;
 
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 307f80e..498aa28 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -201,8 +201,6 @@
 	int ret;
 	u32 mask = val ? val : ~0U;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	/* Read-and-clear RX Descriptor Pointer*/
 	ath5k_hw_reg_read(ah, AR5K_RXDP);
 
@@ -246,7 +244,6 @@
 	unsigned int i;
 	u32 staid, data;
 
-	ATH5K_TRACE(ah->ah_sc);
 	staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
 
 	switch (mode) {
@@ -393,8 +390,6 @@
 	mode = 0;
 	clock = 0;
 
-	ATH5K_TRACE(ah->ah_sc);
-
 	/* Wakeup the device */
 	ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
 	if (ret) {
@@ -734,7 +729,7 @@
 }
 
 static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
-		struct ieee80211_channel *channel, u8 *ant, u8 ee_mode)
+		struct ieee80211_channel *channel, u8 ee_mode)
 {
 	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
 	s16 cck_ofdm_pwr_delta;
@@ -768,17 +763,9 @@
 						ee->ee_cck_ofdm_gain_delta;
 	}
 
-	/* Set antenna idle switch table */
-	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL,
-			AR5K_PHY_ANT_CTL_SWTABLE_IDLE,
-			(ah->ah_ant_ctl[ee_mode][0] |
-			AR5K_PHY_ANT_CTL_TXRX_EN));
-
-	/* Set antenna switch tables */
-	ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant[0]],
-		AR5K_PHY_ANT_SWITCH_TABLE_0);
-	ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant[1]],
-		AR5K_PHY_ANT_SWITCH_TABLE_1);
+	/* XXX: necessary here? is called from ath5k_hw_set_antenna_mode()
+	 * too */
+	ath5k_hw_set_antenna_switch(ah, ee_mode);
 
 	/* Noise floor threshold */
 	ath5k_hw_reg_write(ah,
@@ -855,7 +842,6 @@
 			AR5K_PHY_NF_THRESH62,
 			ee->ee_thr_62[ee_mode]);
 
-
 	/* False detect backoff for channels
 	 * that have spur noise. Write the new
 	 * cyclic power RSSI threshold. */
@@ -891,14 +877,11 @@
 	struct ieee80211_channel *channel, bool change_channel)
 {
 	struct ath_common *common = ath5k_hw_common(ah);
-	u32 s_seq[10], s_ant, s_led[3], staid1_flags, tsf_up, tsf_lo;
+	u32 s_seq[10], s_led[3], staid1_flags, tsf_up, tsf_lo;
 	u32 phy_tst1;
-	u8 mode, freq, ee_mode, ant[2];
+	u8 mode, freq, ee_mode;
 	int i, ret;
 
-	ATH5K_TRACE(ah->ah_sc);
-
-	s_ant = 0;
 	ee_mode = 0;
 	staid1_flags = 0;
 	tsf_up = 0;
@@ -995,9 +978,6 @@
 			}
 		}
 
-		/* Save default antenna */
-		s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
-
 		if (ah->ah_version == AR5K_AR5212) {
 			/* Restore normal 32/40MHz clock operation
 			 * to avoid register access delay on certain
@@ -1094,22 +1074,17 @@
 		/* Write OFDM timings on 5212*/
 		if (ah->ah_version == AR5K_AR5212 &&
 			channel->hw_value & CHANNEL_OFDM) {
-			struct ath5k_eeprom_info *ee =
-					&ah->ah_capabilities.cap_eeprom;
 
 			ret = ath5k_hw_write_ofdm_timings(ah, channel);
 			if (ret)
 				return ret;
 
-			/* Note: According to docs we can have a newer
-			 * EEPROM on old hardware, so we need to verify
-			 * that our hardware is new enough to have spur
-			 * mitigation registers (delta phase etc) */
-			if (ah->ah_mac_srev >= AR5K_SREV_AR5424 ||
-			(ah->ah_mac_srev >= AR5K_SREV_AR5424 &&
-			ee->ee_version >= AR5K_EEPROM_VERSION_5_3))
+			/* Spur info is available only from EEPROM versions
+			 * bigger than 5.3 but but the EEPOM routines will use
+			 * static values for older versions */
+			if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
 				ath5k_hw_set_spur_mitigation_filter(ah,
-								channel);
+								    channel);
 		}
 
 		/*Enable/disable 802.11b mode on 5111
@@ -1123,21 +1098,8 @@
 				    AR5K_TXCFG_B_MODE);
 		}
 
-		/*
-		 * In case a fixed antenna was set as default
-		 * use the same switch table twice.
-		 */
-		if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_A)
-				ant[0] = ant[1] = AR5K_ANT_SWTABLE_A;
-		else if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_B)
-				ant[0] = ant[1] = AR5K_ANT_SWTABLE_B;
-		else {
-			ant[0] = AR5K_ANT_SWTABLE_A;
-			ant[1] = AR5K_ANT_SWTABLE_B;
-		}
-
 		/* Commit values from EEPROM */
-		ath5k_hw_commit_eeprom_settings(ah, channel, ant, ee_mode);
+		ath5k_hw_commit_eeprom_settings(ah, channel, ee_mode);
 
 	} else {
 		/*
@@ -1175,8 +1137,6 @@
 				ath5k_hw_reg_write(ah, tsf_lo, AR5K_TSF_L32);
 			}
 		}
-
-		ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA);
 	}
 
 	/* Ledstate */
diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c
new file mode 100644
index 0000000..90757de
--- /dev/null
+++ b/drivers/net/wireless/ath/ath5k/sysfs.c
@@ -0,0 +1,116 @@
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include "base.h"
+#include "ath5k.h"
+#include "reg.h"
+
+#define SIMPLE_SHOW_STORE(name, get, set)				\
+static ssize_t ath5k_attr_show_##name(struct device *dev,		\
+			struct device_attribute *attr,			\
+			char *buf)					\
+{									\
+	struct ath5k_softc *sc = dev_get_drvdata(dev);			\
+	return snprintf(buf, PAGE_SIZE, "%d\n", get); 			\
+}									\
+									\
+static ssize_t ath5k_attr_store_##name(struct device *dev,		\
+			struct device_attribute *attr,			\
+			const char *buf, size_t count)			\
+{									\
+	struct ath5k_softc *sc = dev_get_drvdata(dev);			\
+	int val;							\
+									\
+	val = (int)simple_strtoul(buf, NULL, 10);			\
+	set(sc->ah, val);						\
+	return count;							\
+}									\
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR,				\
+		   ath5k_attr_show_##name, ath5k_attr_store_##name)
+
+#define SIMPLE_SHOW(name, get)						\
+static ssize_t ath5k_attr_show_##name(struct device *dev,		\
+			struct device_attribute *attr,			\
+			char *buf)					\
+{									\
+	struct ath5k_softc *sc = dev_get_drvdata(dev);			\
+	return snprintf(buf, PAGE_SIZE, "%d\n", get); 			\
+}									\
+static DEVICE_ATTR(name, S_IRUGO, ath5k_attr_show_##name, NULL)
+
+/*** ANI ***/
+
+SIMPLE_SHOW_STORE(ani_mode, sc->ani_state.ani_mode, ath5k_ani_init);
+SIMPLE_SHOW_STORE(noise_immunity_level, sc->ani_state.noise_imm_level,
+			ath5k_ani_set_noise_immunity_level);
+SIMPLE_SHOW_STORE(spur_level, sc->ani_state.spur_level,
+			ath5k_ani_set_spur_immunity_level);
+SIMPLE_SHOW_STORE(firstep_level, sc->ani_state.firstep_level,
+			ath5k_ani_set_firstep_level);
+SIMPLE_SHOW_STORE(ofdm_weak_signal_detection, sc->ani_state.ofdm_weak_sig,
+			ath5k_ani_set_ofdm_weak_signal_detection);
+SIMPLE_SHOW_STORE(cck_weak_signal_detection, sc->ani_state.cck_weak_sig,
+			ath5k_ani_set_cck_weak_signal_detection);
+SIMPLE_SHOW(spur_level_max, sc->ani_state.max_spur_level);
+
+static ssize_t ath5k_attr_show_noise_immunity_level_max(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", ATH5K_ANI_MAX_NOISE_IMM_LVL);
+}
+static DEVICE_ATTR(noise_immunity_level_max, S_IRUGO,
+		   ath5k_attr_show_noise_immunity_level_max, NULL);
+
+static ssize_t ath5k_attr_show_firstep_level_max(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", ATH5K_ANI_MAX_FIRSTEP_LVL);
+}
+static DEVICE_ATTR(firstep_level_max, S_IRUGO,
+		   ath5k_attr_show_firstep_level_max, NULL);
+
+static struct attribute *ath5k_sysfs_entries_ani[] = {
+	&dev_attr_ani_mode.attr,
+	&dev_attr_noise_immunity_level.attr,
+	&dev_attr_spur_level.attr,
+	&dev_attr_firstep_level.attr,
+	&dev_attr_ofdm_weak_signal_detection.attr,
+	&dev_attr_cck_weak_signal_detection.attr,
+	&dev_attr_noise_immunity_level_max.attr,
+	&dev_attr_spur_level_max.attr,
+	&dev_attr_firstep_level_max.attr,
+	NULL
+};
+
+static struct attribute_group ath5k_attribute_group_ani = {
+	.name = "ani",
+	.attrs = ath5k_sysfs_entries_ani,
+};
+
+
+/*** register / unregister ***/
+
+int
+ath5k_sysfs_register(struct ath5k_softc *sc)
+{
+	struct device *dev = &sc->pdev->dev;
+	int err;
+
+	err = sysfs_create_group(&dev->kobj, &ath5k_attribute_group_ani);
+	if (err) {
+		ATH5K_ERR(sc, "failed to create sysfs group\n");
+		return err;
+	}
+
+	return 0;
+}
+
+void
+ath5k_sysfs_unregister(struct ath5k_softc *sc)
+{
+	struct device *dev = &sc->pdev->dev;
+
+	sysfs_remove_group(&dev->kobj, &ath5k_attribute_group_ani);
+}
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index dd112be..973ae4f 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -32,7 +32,8 @@
 		mac.o \
 		ar9002_mac.o \
 		ar9003_mac.o \
-		ar9003_eeprom.o
+		ar9003_eeprom.o \
+		ar9003_paprd.o
 
 obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
 
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 85fdd26..1a984b0 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -131,11 +131,8 @@
 
 	ah = sc->sc_ah;
 	ath9k_hw_name(ah, hw_name, sizeof(hw_name));
-	printk(KERN_INFO
-	       "%s: %s mem=0x%lx, irq=%d\n",
-	       wiphy_name(hw->wiphy),
-	       hw_name,
-	       (unsigned long)mem, irq);
+	wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
+		   hw_name, (unsigned long)mem, irq);
 
 	return 0;
 
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index ba8b20f..cc648b6 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2010 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
@@ -17,8 +17,99 @@
 #include "hw.h"
 #include "hw-ops.h"
 
-static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
-					struct ath9k_channel *chan)
+struct ani_ofdm_level_entry {
+	int spur_immunity_level;
+	int fir_step_level;
+	int ofdm_weak_signal_on;
+};
+
+/* values here are relative to the INI */
+
+/*
+ * Legend:
+ *
+ * SI: Spur immunity
+ * FS: FIR Step
+ * WS: OFDM / CCK Weak Signal detection
+ * MRC-CCK: Maximal Ratio Combining for CCK
+ */
+
+static const struct ani_ofdm_level_entry ofdm_level_table[] = {
+	/* SI  FS  WS */
+	{  0,  0,  1  }, /* lvl 0 */
+	{  1,  1,  1  }, /* lvl 1 */
+	{  2,  2,  1  }, /* lvl 2 */
+	{  3,  2,  1  }, /* lvl 3  (default) */
+	{  4,  3,  1  }, /* lvl 4 */
+	{  5,  4,  1  }, /* lvl 5 */
+	{  6,  5,  1  }, /* lvl 6 */
+	{  7,  6,  1  }, /* lvl 7 */
+	{  7,  7,  1  }, /* lvl 8 */
+	{  7,  8,  0  }  /* lvl 9 */
+};
+#define ATH9K_ANI_OFDM_NUM_LEVEL \
+	(sizeof(ofdm_level_table)/sizeof(ofdm_level_table[0]))
+#define ATH9K_ANI_OFDM_MAX_LEVEL \
+	(ATH9K_ANI_OFDM_NUM_LEVEL-1)
+#define ATH9K_ANI_OFDM_DEF_LEVEL \
+	3 /* default level - matches the INI settings */
+
+/*
+ * MRC (Maximal Ratio Combining) has always been used with multi-antenna ofdm.
+ * With OFDM for single stream you just add up all antenna inputs, you're
+ * only interested in what you get after FFT. Signal aligment is also not
+ * required for OFDM because any phase difference adds up in the frequency
+ * domain.
+ *
+ * MRC requires extra work for use with CCK. You need to align the antenna
+ * signals from the different antenna before you can add the signals together.
+ * You need aligment of signals as CCK is in time domain, so addition can cancel
+ * your signal completely if phase is 180 degrees (think of adding sine waves).
+ * You also need to remove noise before the addition and this is where ANI
+ * MRC CCK comes into play. One of the antenna inputs may be stronger but
+ * lower SNR, so just adding after alignment can be dangerous.
+ *
+ * Regardless of alignment in time, the antenna signals add constructively after
+ * FFT and improve your reception. For more information:
+ *
+ * http://en.wikipedia.org/wiki/Maximal-ratio_combining
+ */
+
+struct ani_cck_level_entry {
+	int fir_step_level;
+	int mrc_cck_on;
+};
+
+static const struct ani_cck_level_entry cck_level_table[] = {
+	/* FS  MRC-CCK  */
+	{  0,  1  }, /* lvl 0 */
+	{  1,  1  }, /* lvl 1 */
+	{  2,  1  }, /* lvl 2  (default) */
+	{  3,  1  }, /* lvl 3 */
+	{  4,  0  }, /* lvl 4 */
+	{  5,  0  }, /* lvl 5 */
+	{  6,  0  }, /* lvl 6 */
+	{  7,  0  }, /* lvl 7 (only for high rssi) */
+	{  8,  0  }  /* lvl 8 (only for high rssi) */
+};
+
+#define ATH9K_ANI_CCK_NUM_LEVEL \
+	(sizeof(cck_level_table)/sizeof(cck_level_table[0]))
+#define ATH9K_ANI_CCK_MAX_LEVEL \
+	(ATH9K_ANI_CCK_NUM_LEVEL-1)
+#define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \
+	(ATH9K_ANI_CCK_NUM_LEVEL-3)
+#define ATH9K_ANI_CCK_DEF_LEVEL \
+	2 /* default level - matches the INI settings */
+
+/* Private to ani.c */
+static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
+{
+	ath9k_hw_private_ops(ah)->ani_lower_immunity(ah);
+}
+
+int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
+				 struct ath9k_channel *chan)
 {
 	int i;
 
@@ -48,7 +139,7 @@
 	stats->beacons += REG_READ(ah, AR_BEACON_CNT);
 }
 
-static void ath9k_ani_restart(struct ath_hw *ah)
+static void ath9k_ani_restart_old(struct ath_hw *ah)
 {
 	struct ar5416AniState *aniState;
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -96,7 +187,42 @@
 	aniState->cckPhyErrCount = 0;
 }
 
-static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
+static void ath9k_ani_restart_new(struct ath_hw *ah)
+{
+	struct ar5416AniState *aniState;
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (!DO_ANI(ah))
+		return;
+
+	aniState = ah->curani;
+	aniState->listenTime = 0;
+
+	aniState->ofdmPhyErrBase = 0;
+	aniState->cckPhyErrBase = 0;
+
+	ath_print(common, ATH_DBG_ANI,
+		  "Writing ofdmbase=%08x   cckbase=%08x\n",
+		  aniState->ofdmPhyErrBase,
+		  aniState->cckPhyErrBase);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	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);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+
+	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
+
+	aniState->ofdmPhyErrCount = 0;
+	aniState->cckPhyErrCount = 0;
+}
+
+static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
 {
 	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
 	struct ar5416AniState *aniState;
@@ -168,7 +294,7 @@
 	}
 }
 
-static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
+static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
 {
 	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
 	struct ar5416AniState *aniState;
@@ -206,7 +332,125 @@
 	}
 }
 
-static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
+/* Adjust the OFDM Noise Immunity Level */
+static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
+{
+	struct ar5416AniState *aniState = ah->curani;
+	struct ath_common *common = ath9k_hw_common(ah);
+	const struct ani_ofdm_level_entry *entry_ofdm;
+	const struct ani_cck_level_entry *entry_cck;
+
+	aniState->noiseFloor = BEACON_RSSI(ah);
+
+	ath_print(common, ATH_DBG_ANI,
+		  "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
+		  aniState->ofdmNoiseImmunityLevel,
+		  immunityLevel, aniState->noiseFloor,
+		  aniState->rssiThrLow, aniState->rssiThrHigh);
+
+	aniState->ofdmNoiseImmunityLevel = immunityLevel;
+
+	entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
+	entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
+
+	if (aniState->spurImmunityLevel != entry_ofdm->spur_immunity_level)
+		ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+				     entry_ofdm->spur_immunity_level);
+
+	if (aniState->firstepLevel != entry_ofdm->fir_step_level &&
+	    entry_ofdm->fir_step_level >= entry_cck->fir_step_level)
+		ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_FIRSTEP_LEVEL,
+				     entry_ofdm->fir_step_level);
+
+	if ((ah->opmode != NL80211_IFTYPE_STATION &&
+	     ah->opmode != NL80211_IFTYPE_ADHOC) ||
+	    aniState->noiseFloor <= aniState->rssiThrHigh) {
+		if (aniState->ofdmWeakSigDetectOff)
+			/* force on ofdm weak sig detect */
+			ath9k_hw_ani_control(ah,
+				ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+					     true);
+		else if (aniState->ofdmWeakSigDetectOff ==
+			 entry_ofdm->ofdm_weak_signal_on)
+			ath9k_hw_ani_control(ah,
+				ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+				entry_ofdm->ofdm_weak_signal_on);
+	}
+}
+
+static void ath9k_hw_ani_ofdm_err_trigger_new(struct ath_hw *ah)
+{
+	struct ar5416AniState *aniState;
+
+	if (!DO_ANI(ah))
+		return;
+
+	aniState = ah->curani;
+
+	if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
+		ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1);
+}
+
+/*
+ * Set the ANI settings to match an CCK level.
+ */
+static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
+{
+	struct ar5416AniState *aniState = ah->curani;
+	struct ath_common *common = ath9k_hw_common(ah);
+	const struct ani_ofdm_level_entry *entry_ofdm;
+	const struct ani_cck_level_entry *entry_cck;
+
+	aniState->noiseFloor = BEACON_RSSI(ah);
+	ath_print(common, ATH_DBG_ANI,
+		  "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
+		  aniState->cckNoiseImmunityLevel, immunityLevel,
+		  aniState->noiseFloor, aniState->rssiThrLow,
+		  aniState->rssiThrHigh);
+
+	if ((ah->opmode == NL80211_IFTYPE_STATION ||
+	     ah->opmode == NL80211_IFTYPE_ADHOC) &&
+	    aniState->noiseFloor <= aniState->rssiThrLow &&
+	    immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
+		immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
+
+	aniState->cckNoiseImmunityLevel = immunityLevel;
+
+	entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
+	entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
+
+	if (aniState->firstepLevel != entry_cck->fir_step_level &&
+	    entry_cck->fir_step_level >= entry_ofdm->fir_step_level)
+		ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_FIRSTEP_LEVEL,
+				     entry_cck->fir_step_level);
+
+	/* Skip MRC CCK for pre AR9003 families */
+	if (!AR_SREV_9300_20_OR_LATER(ah))
+		return;
+
+	if (aniState->mrcCCKOff == entry_cck->mrc_cck_on)
+		ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_MRC_CCK,
+				     entry_cck->mrc_cck_on);
+}
+
+static void ath9k_hw_ani_cck_err_trigger_new(struct ath_hw *ah)
+{
+	struct ar5416AniState *aniState;
+
+	if (!DO_ANI(ah))
+		return;
+
+	aniState = ah->curani;
+
+	if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
+		ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1);
+}
+
+static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
 {
 	struct ar5416AniState *aniState;
 	int32_t rssi;
@@ -259,9 +503,53 @@
 	}
 }
 
+/*
+ * only lower either OFDM or CCK errors per turn
+ * we lower the other one next time
+ */
+static void ath9k_hw_ani_lower_immunity_new(struct ath_hw *ah)
+{
+	struct ar5416AniState *aniState;
+
+	aniState = ah->curani;
+
+	/* lower OFDM noise immunity */
+	if (aniState->ofdmNoiseImmunityLevel > 0 &&
+	    (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) {
+		ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1);
+		return;
+	}
+
+	/* lower CCK noise immunity */
+	if (aniState->cckNoiseImmunityLevel > 0)
+		ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1);
+}
+
+static u8 ath9k_hw_chan_2_clockrate_mhz(struct ath_hw *ah)
+{
+	struct ath9k_channel *chan = ah->curchan;
+	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
+	u8 clockrate; /* in MHz */
+
+	if (!ah->curchan) /* should really check for CCK instead */
+		clockrate = ATH9K_CLOCK_RATE_CCK;
+	else if (conf->channel->band == IEEE80211_BAND_2GHZ)
+		clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM;
+	else if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+		clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM;
+	else
+		clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM;
+
+	if (conf_is_ht40(conf))
+		return clockrate * 2;
+
+	return clockrate * 2;
+}
+
 static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
 {
 	struct ar5416AniState *aniState;
+	struct ath_common *common = ath9k_hw_common(ah);
 	u32 txFrameCount, rxFrameCount, cycleCount;
 	int32_t listenTime;
 
@@ -271,15 +559,31 @@
 
 	aniState = ah->curani;
 	if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
-
 		listenTime = 0;
 		ah->stats.ast_ani_lzero++;
+		ath_print(common, ATH_DBG_ANI,
+			  "1st call: aniState->cycleCount=%d\n",
+			  aniState->cycleCount);
 	} else {
 		int32_t ccdelta = cycleCount - aniState->cycleCount;
 		int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
 		int32_t tfdelta = txFrameCount - aniState->txFrameCount;
-		listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
+		int32_t clock_rate;
+
+		/*
+		 * convert HW counter values to ms using mode
+		 * specifix clock rate
+		 */
+		clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;;
+
+		listenTime = (ccdelta - rfdelta - tfdelta) / clock_rate;
+
+		ath_print(common, ATH_DBG_ANI,
+			  "cyclecount=%d, rfcount=%d, "
+			  "tfcount=%d, listenTime=%d CLOCK_RATE=%d\n",
+			  ccdelta, rfdelta, tfdelta, listenTime, clock_rate);
 	}
+
 	aniState->cycleCount = cycleCount;
 	aniState->txFrameCount = txFrameCount;
 	aniState->rxFrameCount = rxFrameCount;
@@ -287,7 +591,7 @@
 	return listenTime;
 }
 
-void ath9k_ani_reset(struct ath_hw *ah)
+static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
 {
 	struct ar5416AniState *aniState;
 	struct ath9k_channel *chan = ah->curchan;
@@ -340,7 +644,7 @@
 			ah->curani->cckTrigLow =
 				ah->config.cck_trig_low;
 		}
-		ath9k_ani_restart(ah);
+		ath9k_ani_restart_old(ah);
 		return;
 	}
 
@@ -362,7 +666,7 @@
 
 	ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
 			     ~ATH9K_RX_FILTER_PHYERR);
-	ath9k_ani_restart(ah);
+	ath9k_ani_restart_old(ah);
 
 	ENABLE_REGWRITE_BUFFER(ah);
 
@@ -373,8 +677,102 @@
 	DISABLE_REGWRITE_BUFFER(ah);
 }
 
-void ath9k_hw_ani_monitor(struct ath_hw *ah,
-			  struct ath9k_channel *chan)
+/*
+ * Restore the ANI parameters in the HAL and reset the statistics.
+ * This routine should be called for every hardware reset and for
+ * every channel change.
+ */
+static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning)
+{
+	struct ar5416AniState *aniState = ah->curani;
+	struct ath9k_channel *chan = ah->curchan;
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (!DO_ANI(ah))
+		return;
+
+	BUG_ON(aniState == NULL);
+	ah->stats.ast_ani_reset++;
+
+	/* only allow a subset of functions in AP mode */
+	if (ah->opmode == NL80211_IFTYPE_AP) {
+		if (IS_CHAN_2GHZ(chan)) {
+			ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
+					    ATH9K_ANI_FIRSTEP_LEVEL);
+			if (AR_SREV_9300_20_OR_LATER(ah))
+				ah->ani_function |= ATH9K_ANI_MRC_CCK;
+		} else
+			ah->ani_function = 0;
+	}
+
+	/* always allow mode (on/off) to be controlled */
+	ah->ani_function |= ATH9K_ANI_MODE;
+
+	if (is_scanning ||
+	    (ah->opmode != NL80211_IFTYPE_STATION &&
+	     ah->opmode != NL80211_IFTYPE_ADHOC)) {
+		/*
+		 * If we're scanning or in AP mode, the defaults (ini)
+		 * should be in place. For an AP we assume the historical
+		 * levels for this channel are probably outdated so start
+		 * from defaults instead.
+		 */
+		if (aniState->ofdmNoiseImmunityLevel !=
+		    ATH9K_ANI_OFDM_DEF_LEVEL ||
+		    aniState->cckNoiseImmunityLevel !=
+		    ATH9K_ANI_CCK_DEF_LEVEL) {
+			ath_print(common, ATH_DBG_ANI,
+				  "Restore defaults: opmode %u "
+				  "chan %d Mhz/0x%x is_scanning=%d "
+				  "ofdm:%d cck:%d\n",
+				  ah->opmode,
+				  chan->channel,
+				  chan->channelFlags,
+				  is_scanning,
+				  aniState->ofdmNoiseImmunityLevel,
+				  aniState->cckNoiseImmunityLevel);
+
+			ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL);
+			ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL);
+		}
+	} else {
+		/*
+		 * restore historical levels for this channel
+		 */
+		ath_print(common, ATH_DBG_ANI,
+			  "Restore history: opmode %u "
+			  "chan %d Mhz/0x%x is_scanning=%d "
+			  "ofdm:%d cck:%d\n",
+			  ah->opmode,
+			  chan->channel,
+			  chan->channelFlags,
+			  is_scanning,
+			  aniState->ofdmNoiseImmunityLevel,
+			  aniState->cckNoiseImmunityLevel);
+
+			ath9k_hw_set_ofdm_nil(ah,
+					      aniState->ofdmNoiseImmunityLevel);
+			ath9k_hw_set_cck_nil(ah,
+					     aniState->cckNoiseImmunityLevel);
+	}
+
+	/*
+	 * enable phy counters if hw supports or if not, enable phy
+	 * interrupts (so we can count each one)
+	 */
+	ath9k_ani_restart_new(ah);
+
+	ENABLE_REGWRITE_BUFFER(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);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+}
+
+static void ath9k_hw_ani_monitor_old(struct ath_hw *ah,
+				     struct ath9k_channel *chan)
 {
 	struct ar5416AniState *aniState;
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -390,7 +788,7 @@
 	listenTime = ath9k_hw_ani_get_listen_time(ah);
 	if (listenTime < 0) {
 		ah->stats.ast_ani_lneg++;
-		ath9k_ani_restart(ah);
+		ath9k_ani_restart_old(ah);
 		return;
 	}
 
@@ -444,21 +842,166 @@
 		    aniState->cckPhyErrCount <= aniState->listenTime *
 		    aniState->cckTrigLow / 1000)
 			ath9k_hw_ani_lower_immunity(ah);
-		ath9k_ani_restart(ah);
+		ath9k_ani_restart_old(ah);
 	} else if (aniState->listenTime > ah->aniperiod) {
 		if (aniState->ofdmPhyErrCount > aniState->listenTime *
 		    aniState->ofdmTrigHigh / 1000) {
-			ath9k_hw_ani_ofdm_err_trigger(ah);
-			ath9k_ani_restart(ah);
+			ath9k_hw_ani_ofdm_err_trigger_old(ah);
+			ath9k_ani_restart_old(ah);
 		} else if (aniState->cckPhyErrCount >
 			   aniState->listenTime * aniState->cckTrigHigh /
 			   1000) {
-			ath9k_hw_ani_cck_err_trigger(ah);
-			ath9k_ani_restart(ah);
+			ath9k_hw_ani_cck_err_trigger_old(ah);
+			ath9k_ani_restart_old(ah);
 		}
 	}
 }
-EXPORT_SYMBOL(ath9k_hw_ani_monitor);
+
+static void ath9k_hw_ani_monitor_new(struct ath_hw *ah,
+				     struct ath9k_channel *chan)
+{
+	struct ar5416AniState *aniState;
+	struct ath_common *common = ath9k_hw_common(ah);
+	int32_t listenTime;
+	u32 phyCnt1, phyCnt2;
+	u32 ofdmPhyErrCnt, cckPhyErrCnt;
+	u32 ofdmPhyErrRate, cckPhyErrRate;
+
+	if (!DO_ANI(ah))
+		return;
+
+	aniState = ah->curani;
+	if (WARN_ON(!aniState))
+		return;
+
+	listenTime = ath9k_hw_ani_get_listen_time(ah);
+	if (listenTime <= 0) {
+		ah->stats.ast_ani_lneg++;
+		/* restart ANI period if listenTime is invalid */
+		ath_print(common, ATH_DBG_ANI,
+			  "listenTime=%d - on new ani monitor\n",
+			  listenTime);
+		ath9k_ani_restart_new(ah);
+		return;
+	}
+
+	aniState->listenTime += listenTime;
+
+	ath9k_hw_update_mibstats(ah, &ah->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) {
+			ath_print(common, 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) {
+			ath_print(common, 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;
+	ah->stats.ast_ani_ofdmerrs +=
+		ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+	aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+
+	cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+	ah->stats.ast_ani_cckerrs +=
+		cckPhyErrCnt - aniState->cckPhyErrCount;
+	aniState->cckPhyErrCount = cckPhyErrCnt;
+
+	ath_print(common, ATH_DBG_ANI,
+		  "Errors: OFDM=0x%08x-0x%08x=%d   "
+		  "CCK=0x%08x-0x%08x=%d\n",
+		  phyCnt1,
+		  aniState->ofdmPhyErrBase,
+		  ofdmPhyErrCnt,
+		  phyCnt2,
+		  aniState->cckPhyErrBase,
+		  cckPhyErrCnt);
+
+	ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 /
+			 aniState->listenTime;
+	cckPhyErrRate =  aniState->cckPhyErrCount * 1000 /
+			 aniState->listenTime;
+
+	ath_print(common, ATH_DBG_ANI,
+		  "listenTime=%d OFDM:%d errs=%d/s CCK:%d "
+		  "errs=%d/s ofdm_turn=%d\n",
+		  listenTime, aniState->ofdmNoiseImmunityLevel,
+		  ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
+		  cckPhyErrRate, aniState->ofdmsTurn);
+
+	if (aniState->listenTime > 5 * ah->aniperiod) {
+		if (ofdmPhyErrRate <= aniState->ofdmTrigLow &&
+		    cckPhyErrRate <= aniState->cckTrigLow) {
+			ath_print(common, ATH_DBG_ANI,
+				  "1. listenTime=%d OFDM:%d errs=%d/s(<%d)  "
+				  "CCK:%d errs=%d/s(<%d) -> "
+				  "ath9k_hw_ani_lower_immunity()\n",
+				  aniState->listenTime,
+				  aniState->ofdmNoiseImmunityLevel,
+				  ofdmPhyErrRate,
+				  aniState->ofdmTrigLow,
+				  aniState->cckNoiseImmunityLevel,
+				  cckPhyErrRate,
+				  aniState->cckTrigLow);
+			ath9k_hw_ani_lower_immunity(ah);
+			aniState->ofdmsTurn = !aniState->ofdmsTurn;
+		}
+		ath_print(common, ATH_DBG_ANI,
+			  "1 listenTime=%d ofdm=%d/s cck=%d/s - "
+			  "calling ath9k_ani_restart_new()\n",
+			  aniState->listenTime, ofdmPhyErrRate, cckPhyErrRate);
+		ath9k_ani_restart_new(ah);
+	} else if (aniState->listenTime > ah->aniperiod) {
+		/* check to see if need to raise immunity */
+		if (ofdmPhyErrRate > aniState->ofdmTrigHigh &&
+		    (cckPhyErrRate <= aniState->cckTrigHigh ||
+		     aniState->ofdmsTurn)) {
+			ath_print(common, ATH_DBG_ANI,
+				  "2 listenTime=%d OFDM:%d errs=%d/s(>%d) -> "
+				  "ath9k_hw_ani_ofdm_err_trigger_new()\n",
+				  aniState->listenTime,
+				  aniState->ofdmNoiseImmunityLevel,
+				  ofdmPhyErrRate,
+				  aniState->ofdmTrigHigh);
+			ath9k_hw_ani_ofdm_err_trigger_new(ah);
+			ath9k_ani_restart_new(ah);
+			aniState->ofdmsTurn = false;
+		} else if (cckPhyErrRate > aniState->cckTrigHigh) {
+			ath_print(common, ATH_DBG_ANI,
+				 "3 listenTime=%d CCK:%d errs=%d/s(>%d) -> "
+				 "ath9k_hw_ani_cck_err_trigger_new()\n",
+				 aniState->listenTime,
+				 aniState->cckNoiseImmunityLevel,
+				 cckPhyErrRate,
+				 aniState->cckTrigHigh);
+			ath9k_hw_ani_cck_err_trigger_new(ah);
+			ath9k_ani_restart_new(ah);
+			aniState->ofdmsTurn = true;
+		}
+	}
+}
 
 void ath9k_enable_mib_counters(struct ath_hw *ah)
 {
@@ -495,6 +1038,7 @@
 	REG_WRITE(ah, AR_FILT_OFDM, 0);
 	REG_WRITE(ah, AR_FILT_CCK, 0);
 }
+EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
 
 u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
 				  u32 *rxc_pcnt,
@@ -542,7 +1086,7 @@
  * 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_hw *ah)
+static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah)
 {
 	u32 phyCnt1, phyCnt2;
 
@@ -555,8 +1099,15 @@
 	/* Clear the mib counters and save them in the stats */
 	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 
-	if (!DO_ANI(ah))
+	if (!DO_ANI(ah)) {
+		/*
+		 * We must always clear the interrupt cause by
+		 * resetting the phy error regs.
+		 */
+		REG_WRITE(ah, AR_PHY_ERR_1, 0);
+		REG_WRITE(ah, AR_PHY_ERR_2, 0);
 		return;
+	}
 
 	/* NB: these are not reset-on-read */
 	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
@@ -584,14 +1135,51 @@
 		 * check will never be true.
 		 */
 		if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
-			ath9k_hw_ani_ofdm_err_trigger(ah);
+			ath9k_hw_ani_ofdm_err_trigger_new(ah);
 		if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
-			ath9k_hw_ani_cck_err_trigger(ah);
+			ath9k_hw_ani_cck_err_trigger_old(ah);
 		/* NB: always restart to insure the h/w counters are reset */
-		ath9k_ani_restart(ah);
+		ath9k_ani_restart_old(ah);
 	}
 }
-EXPORT_SYMBOL(ath9k_hw_procmibevent);
+
+/*
+ * 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.
+ */
+static void ath9k_hw_proc_mib_event_new(struct ath_hw *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, &ah->ah_mibStats);
+
+	if (!DO_ANI(ah)) {
+		/*
+		 * We must always clear the interrupt cause by
+		 * resetting the phy error regs.
+		 */
+		REG_WRITE(ah, AR_PHY_ERR_1, 0);
+		REG_WRITE(ah, AR_PHY_ERR_2, 0);
+		return;
+	}
+
+	/* NB: these are not reset-on-read */
+	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+
+	/* NB: always restart to insure the h/w counters are reset */
+	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
+	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK))
+		ath9k_ani_restart_new(ah);
+}
 
 void ath9k_hw_ani_setup(struct ath_hw *ah)
 {
@@ -619,22 +1207,70 @@
 
 	memset(ah->ani, 0, sizeof(ah->ani));
 	for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
-		ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
-		ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
-		ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
-		ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
+		if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) {
+			ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
+			ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
+
+			ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
+			ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_NEW;
+
+			ah->ani[i].spurImmunityLevel =
+				ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+
+			ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
+
+			ah->ani[i].ofdmPhyErrBase = 0;
+			ah->ani[i].cckPhyErrBase = 0;
+
+			if (AR_SREV_9300_20_OR_LATER(ah))
+				ah->ani[i].mrcCCKOff =
+					!ATH9K_ANI_ENABLE_MRC_CCK;
+			else
+				ah->ani[i].mrcCCKOff = true;
+
+			ah->ani[i].ofdmsTurn = true;
+		} else {
+			ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
+			ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
+
+			ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
+			ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_OLD;
+
+			ah->ani[i].spurImmunityLevel =
+				ATH9K_ANI_SPUR_IMMUNE_LVL_OLD;
+			ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
+
+			ah->ani[i].ofdmPhyErrBase =
+				AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
+			ah->ani[i].cckPhyErrBase =
+				AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH_OLD;
+			ah->ani[i].cckWeakSigThreshold =
+				ATH9K_ANI_CCK_WEAK_SIG_THR;
+		}
+
 		ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
 		ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
 		ah->ani[i].ofdmWeakSigDetectOff =
 			!ATH9K_ANI_USE_OFDM_WEAK_SIG;
-		ah->ani[i].cckWeakSigThreshold =
-			ATH9K_ANI_CCK_WEAK_SIG_THR;
-		ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
-		ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
-		ah->ani[i].ofdmPhyErrBase =
-			AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
-		ah->ani[i].cckPhyErrBase =
-			AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
+		ah->ani[i].cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
+	}
+
+	/*
+	 * since we expect some ongoing maintenance on the tables, let's sanity
+	 * check here default level should not modify INI setting.
+	 */
+	if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) {
+		const struct ani_ofdm_level_entry *entry_ofdm;
+		const struct ani_cck_level_entry *entry_cck;
+
+		entry_ofdm = &ofdm_level_table[ATH9K_ANI_OFDM_DEF_LEVEL];
+		entry_cck = &cck_level_table[ATH9K_ANI_CCK_DEF_LEVEL];
+
+		ah->aniperiod = ATH9K_ANI_PERIOD_NEW;
+		ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW;
+	} else {
+		ah->aniperiod = ATH9K_ANI_PERIOD_OLD;
+		ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD;
 	}
 
 	ath_print(common, ATH_DBG_ANI,
@@ -653,7 +1289,34 @@
 
 	ath9k_enable_mib_counters(ah);
 
-	ah->aniperiod = ATH9K_ANI_PERIOD;
 	if (ah->config.enable_ani)
 		ah->proc_phyerr |= HAL_PROCESS_ANI;
 }
+
+void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah)
+{
+	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+	priv_ops->ani_reset = ath9k_ani_reset_old;
+	priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_old;
+
+	ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_old;
+	ops->ani_monitor = ath9k_hw_ani_monitor_old;
+
+	ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v1\n");
+}
+
+void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah)
+{
+	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+	priv_ops->ani_reset = ath9k_ani_reset_new;
+	priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_new;
+
+	ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_new;
+	ops->ani_monitor = ath9k_hw_ani_monitor_new;
+
+	ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v2\n");
+}
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h
index 3356762..f4d0a4d 100644
--- a/drivers/net/wireless/ath/ath9k/ani.h
+++ b/drivers/net/wireless/ath/ath9k/ani.h
@@ -23,23 +23,55 @@
 
 #define BEACON_RSSI(ahp) (ahp->stats.avgbrssi)
 
-#define ATH9K_ANI_OFDM_TRIG_HIGH          500
-#define ATH9K_ANI_OFDM_TRIG_LOW           200
-#define ATH9K_ANI_CCK_TRIG_HIGH           200
-#define ATH9K_ANI_CCK_TRIG_LOW            100
+/* units are errors per second */
+#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD      500
+#define ATH9K_ANI_OFDM_TRIG_HIGH_NEW      1000
+
+/* units are errors per second */
+#define ATH9K_ANI_OFDM_TRIG_LOW_OLD       200
+#define ATH9K_ANI_OFDM_TRIG_LOW_NEW       400
+
+/* units are errors per second */
+#define ATH9K_ANI_CCK_TRIG_HIGH_OLD       200
+#define ATH9K_ANI_CCK_TRIG_HIGH_NEW       600
+
+/* units are errors per second */
+#define ATH9K_ANI_CCK_TRIG_LOW_OLD        100
+#define ATH9K_ANI_CCK_TRIG_LOW_NEW        300
+
 #define ATH9K_ANI_NOISE_IMMUNE_LVL        4
 #define ATH9K_ANI_USE_OFDM_WEAK_SIG       true
 #define ATH9K_ANI_CCK_WEAK_SIG_THR        false
-#define ATH9K_ANI_SPUR_IMMUNE_LVL         7
-#define ATH9K_ANI_FIRSTEP_LVL             0
+
+#define ATH9K_ANI_SPUR_IMMUNE_LVL_OLD     7
+#define ATH9K_ANI_SPUR_IMMUNE_LVL_NEW     3
+
+#define ATH9K_ANI_FIRSTEP_LVL_OLD         0
+#define ATH9K_ANI_FIRSTEP_LVL_NEW         2
+
 #define ATH9K_ANI_RSSI_THR_HIGH           40
 #define ATH9K_ANI_RSSI_THR_LOW            7
-#define ATH9K_ANI_PERIOD                  100
+
+#define ATH9K_ANI_PERIOD_OLD              100
+#define ATH9K_ANI_PERIOD_NEW              1000
+
+/* in ms */
+#define ATH9K_ANI_POLLINTERVAL_OLD        100
+#define ATH9K_ANI_POLLINTERVAL_NEW        1000
 
 #define HAL_NOISE_IMMUNE_MAX              4
 #define HAL_SPUR_IMMUNE_MAX               7
 #define HAL_FIRST_STEP_MAX                2
 
+#define ATH9K_SIG_FIRSTEP_SETTING_MIN     0
+#define ATH9K_SIG_FIRSTEP_SETTING_MAX     20
+#define ATH9K_SIG_SPUR_IMM_SETTING_MIN    0
+#define ATH9K_SIG_SPUR_IMM_SETTING_MAX    22
+
+#define ATH9K_ANI_ENABLE_MRC_CCK          true
+
+/* values here are relative to the INI */
+
 enum ath9k_ani_cmd {
 	ATH9K_ANI_PRESENT = 0x1,
 	ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2,
@@ -49,7 +81,8 @@
 	ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20,
 	ATH9K_ANI_MODE = 0x40,
 	ATH9K_ANI_PHYERR_RESET = 0x80,
-	ATH9K_ANI_ALL = 0xff
+	ATH9K_ANI_MRC_CCK = 0x100,
+	ATH9K_ANI_ALL = 0xfff
 };
 
 struct ath9k_mib_stats {
@@ -60,9 +93,31 @@
 	u32 beacons;
 };
 
+/* INI default values for ANI registers */
+struct ath9k_ani_default {
+	u16 m1ThreshLow;
+	u16 m2ThreshLow;
+	u16 m1Thresh;
+	u16 m2Thresh;
+	u16 m2CountThr;
+	u16 m2CountThrLow;
+	u16 m1ThreshLowExt;
+	u16 m2ThreshLowExt;
+	u16 m1ThreshExt;
+	u16 m2ThreshExt;
+	u16 firstep;
+	u16 firstepLow;
+	u16 cycpwrThr1;
+	u16 cycpwrThr1Ext;
+};
+
 struct ar5416AniState {
 	struct ath9k_channel *c;
 	u8 noiseImmunityLevel;
+	u8 ofdmNoiseImmunityLevel;
+	u8 cckNoiseImmunityLevel;
+	bool ofdmsTurn;
+	u8 mrcCCKOff;
 	u8 spurImmunityLevel;
 	u8 firstepLevel;
 	u8 ofdmWeakSigDetectOff;
@@ -85,6 +140,7 @@
 	int16_t pktRssi[2];
 	int16_t ofdmErrRssi[2];
 	int16_t cckErrRssi[2];
+	struct ath9k_ani_default iniDef;
 };
 
 struct ar5416Stats {
@@ -108,15 +164,13 @@
 };
 #define ah_mibStats stats.ast_mibstats
 
-void ath9k_ani_reset(struct ath_hw *ah);
-void ath9k_hw_ani_monitor(struct ath_hw *ah,
-			  struct ath9k_channel *chan);
 void ath9k_enable_mib_counters(struct ath_hw *ah);
 void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
 u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt,
 				  u32 *rxf_pcnt, u32 *txf_pcnt);
-void ath9k_hw_procmibevent(struct ath_hw *ah);
 void ath9k_hw_ani_setup(struct ath_hw *ah);
 void ath9k_hw_ani_init(struct ath_hw *ah);
+int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
+				 struct ath9k_channel *chan);
 
 #endif /* ANI_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
index 025c31ac..36f7d06 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2010 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
@@ -14,729 +14,660 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#ifndef INITVALS_AR5008_H
-#define INITVALS_AR5008_H
-
 static const u32 ar5416Modes[][6] = {
-    { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
-    { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
-    { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
-    { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
-    { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
-    { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
-    { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
-    { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a },
-    { 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 },
-    { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 },
-    { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de },
-    { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
-    { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e },
-    { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 },
-    { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
-    { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 },
-    { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
-    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
-    { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 },
-    { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b },
-    { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
-    { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
-    { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
-    { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
-    { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 },
-    { 0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 },
-    { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
-    { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
-    { 0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c },
-    { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
-    { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
-    { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
-    { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
-    { 0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
-    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
-    { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
-    { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
-    { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
-    { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
-    { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
-    { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
-    { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
-    { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
-    { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
-    { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
-    { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+	{0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008},
+	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+	{0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
+	{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},
+	{0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0},
+	{0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de},
+	{0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
+	{0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+	{0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18},
+	{0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+	{0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190},
+	{0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
+	{0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+	{0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134},
+	{0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b},
+	{0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020},
+	{0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80},
+	{0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80},
+	{0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80},
+	{0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120},
+	{0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00},
+	{0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
+	{0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+	{0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c},
+	{0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+	{0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+	{0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
+	{0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788},
+	{0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa},
+	{0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
+	{0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402},
+	{0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06},
+	{0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b},
+	{0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b},
+	{0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a},
+	{0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf},
+	{0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f},
+	{0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f},
+	{0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f},
+	{0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 };
 
 static const u32 ar5416Common[][2] = {
-    { 0x0000000c, 0x00000000 },
-    { 0x00000030, 0x00020015 },
-    { 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 },
-    { 0x00007010, 0x00000000 },
-    { 0x00007038, 0x000004c2 },
-    { 0x00008004, 0x00000000 },
-    { 0x00008008, 0x00000000 },
-    { 0x0000800c, 0x00000000 },
-    { 0x00008018, 0x00000700 },
-    { 0x00008020, 0x00000000 },
-    { 0x00008038, 0x00000000 },
-    { 0x0000803c, 0x00000000 },
-    { 0x00008048, 0x40000000 },
-    { 0x00008054, 0x00000000 },
-    { 0x00008058, 0x00000000 },
-    { 0x0000805c, 0x000fc78f },
-    { 0x00008060, 0x0000000f },
-    { 0x00008064, 0x00000000 },
-    { 0x000080c0, 0x2a82301a },
-    { 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 },
-    { 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 },
-    { 0x000081c4, 0x00000000 },
-    { 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, 0x88000010 },
-    { 0x00008270, 0x00000000 },
-    { 0x00008274, 0x40000000 },
-    { 0x00008278, 0x003e4180 },
-    { 0x0000827c, 0x00000000 },
-    { 0x00008284, 0x0000002c },
-    { 0x00008288, 0x0000002c },
-    { 0x0000828c, 0x00000000 },
-    { 0x00008294, 0x00000000 },
-    { 0x00008298, 0x00000000 },
-    { 0x00008300, 0x00000000 },
-    { 0x00008304, 0x00000000 },
-    { 0x00008308, 0x00000000 },
-    { 0x0000830c, 0x00000000 },
-    { 0x00008310, 0x00000000 },
-    { 0x00008314, 0x00000000 },
-    { 0x00008318, 0x00000000 },
-    { 0x00008328, 0x00000000 },
-    { 0x0000832c, 0x00000007 },
-    { 0x00008330, 0x00000302 },
-    { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00070000 },
-    { 0x0000833c, 0x00000000 },
-    { 0x00008340, 0x000107ff },
-    { 0x00009808, 0x00000000 },
-    { 0x0000980c, 0xad848e19 },
-    { 0x00009810, 0x7d14e000 },
-    { 0x00009814, 0x9c0a9f6b },
-    { 0x0000981c, 0x00000000 },
-    { 0x0000982c, 0x0000a000 },
-    { 0x00009830, 0x00000000 },
-    { 0x0000983c, 0x00200400 },
-    { 0x00009840, 0x206a002e },
-    { 0x0000984c, 0x1284233c },
-    { 0x00009854, 0x00000859 },
-    { 0x00009900, 0x00000000 },
-    { 0x00009904, 0x00000000 },
-    { 0x00009908, 0x00000000 },
-    { 0x0000990c, 0x00000000 },
-    { 0x0000991c, 0x10000fff },
-    { 0x00009920, 0x05100000 },
-    { 0x0000a920, 0x05100000 },
-    { 0x0000b920, 0x05100000 },
-    { 0x00009928, 0x00000001 },
-    { 0x0000992c, 0x00000004 },
-    { 0x00009934, 0x1e1f2022 },
-    { 0x00009938, 0x0a0b0c0d },
-    { 0x0000993c, 0x00000000 },
-    { 0x00009948, 0x9280b212 },
-    { 0x0000994c, 0x00020028 },
-    { 0x00009954, 0x5d50e188 },
-    { 0x00009958, 0x00081fff },
-    { 0x0000c95c, 0x004b6a8e },
-    { 0x0000c968, 0x000003ce },
-    { 0x00009970, 0x190fb515 },
-    { 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, 0x001fff00 },
-    { 0x000099ac, 0x00000000 },
-    { 0x000099b0, 0x03051000 },
-    { 0x000099dc, 0x00000000 },
-    { 0x000099e0, 0x00000200 },
-    { 0x000099e4, 0xaaaaaaaa },
-    { 0x000099e8, 0x3c466478 },
-    { 0x000099ec, 0x000000aa },
-    { 0x000099fc, 0x00001042 },
-    { 0x00009b00, 0x00000000 },
-    { 0x00009b04, 0x00000001 },
-    { 0x00009b08, 0x00000002 },
-    { 0x00009b0c, 0x00000003 },
-    { 0x00009b10, 0x00000004 },
-    { 0x00009b14, 0x00000005 },
-    { 0x00009b18, 0x00000008 },
-    { 0x00009b1c, 0x00000009 },
-    { 0x00009b20, 0x0000000a },
-    { 0x00009b24, 0x0000000b },
-    { 0x00009b28, 0x0000000c },
-    { 0x00009b2c, 0x0000000d },
-    { 0x00009b30, 0x00000010 },
-    { 0x00009b34, 0x00000011 },
-    { 0x00009b38, 0x00000012 },
-    { 0x00009b3c, 0x00000013 },
-    { 0x00009b40, 0x00000014 },
-    { 0x00009b44, 0x00000015 },
-    { 0x00009b48, 0x00000018 },
-    { 0x00009b4c, 0x00000019 },
-    { 0x00009b50, 0x0000001a },
-    { 0x00009b54, 0x0000001b },
-    { 0x00009b58, 0x0000001c },
-    { 0x00009b5c, 0x0000001d },
-    { 0x00009b60, 0x00000020 },
-    { 0x00009b64, 0x00000021 },
-    { 0x00009b68, 0x00000022 },
-    { 0x00009b6c, 0x00000023 },
-    { 0x00009b70, 0x00000024 },
-    { 0x00009b74, 0x00000025 },
-    { 0x00009b78, 0x00000028 },
-    { 0x00009b7c, 0x00000029 },
-    { 0x00009b80, 0x0000002a },
-    { 0x00009b84, 0x0000002b },
-    { 0x00009b88, 0x0000002c },
-    { 0x00009b8c, 0x0000002d },
-    { 0x00009b90, 0x00000030 },
-    { 0x00009b94, 0x00000031 },
-    { 0x00009b98, 0x00000032 },
-    { 0x00009b9c, 0x00000033 },
-    { 0x00009ba0, 0x00000034 },
-    { 0x00009ba4, 0x00000035 },
-    { 0x00009ba8, 0x00000035 },
-    { 0x00009bac, 0x00000035 },
-    { 0x00009bb0, 0x00000035 },
-    { 0x00009bb4, 0x00000035 },
-    { 0x00009bb8, 0x00000035 },
-    { 0x00009bbc, 0x00000035 },
-    { 0x00009bc0, 0x00000035 },
-    { 0x00009bc4, 0x00000035 },
-    { 0x00009bc8, 0x00000035 },
-    { 0x00009bcc, 0x00000035 },
-    { 0x00009bd0, 0x00000035 },
-    { 0x00009bd4, 0x00000035 },
-    { 0x00009bd8, 0x00000035 },
-    { 0x00009bdc, 0x00000035 },
-    { 0x00009be0, 0x00000035 },
-    { 0x00009be4, 0x00000035 },
-    { 0x00009be8, 0x00000035 },
-    { 0x00009bec, 0x00000035 },
-    { 0x00009bf0, 0x00000035 },
-    { 0x00009bf4, 0x00000035 },
-    { 0x00009bf8, 0x00000010 },
-    { 0x00009bfc, 0x0000001a },
-    { 0x0000a210, 0x40806333 },
-    { 0x0000a214, 0x00106c10 },
-    { 0x0000a218, 0x009c4060 },
-    { 0x0000a220, 0x018830c6 },
-    { 0x0000a224, 0x00000400 },
-    { 0x0000a228, 0x00000bb5 },
-    { 0x0000a22c, 0x00000011 },
-    { 0x0000a234, 0x20202020 },
-    { 0x0000a238, 0x20202020 },
-    { 0x0000a23c, 0x13c889af },
-    { 0x0000a240, 0x38490a20 },
-    { 0x0000a244, 0x00007bb6 },
-    { 0x0000a248, 0x0fff3ffc },
-    { 0x0000a24c, 0x00000001 },
-    { 0x0000a250, 0x0000a000 },
-    { 0x0000a254, 0x00000000 },
-    { 0x0000a258, 0x0cc75380 },
-    { 0x0000a25c, 0x0f0f0f01 },
-    { 0x0000a260, 0xdfa91f01 },
-    { 0x0000a268, 0x00000000 },
-    { 0x0000a26c, 0x0e79e5c6 },
-    { 0x0000b26c, 0x0e79e5c6 },
-    { 0x0000c26c, 0x0e79e5c6 },
-    { 0x0000d270, 0x00820820 },
-    { 0x0000a278, 0x1ce739ce },
-    { 0x0000a27c, 0x051701ce },
-    { 0x0000a338, 0x00000000 },
-    { 0x0000a33c, 0x00000000 },
-    { 0x0000a340, 0x00000000 },
-    { 0x0000a344, 0x00000000 },
-    { 0x0000a348, 0x3fffffff },
-    { 0x0000a34c, 0x3fffffff },
-    { 0x0000a350, 0x3fffffff },
-    { 0x0000a354, 0x0003ffff },
-    { 0x0000a358, 0x79a8aa1f },
-    { 0x0000d35c, 0x07ffffef },
-    { 0x0000d360, 0x0fffffe7 },
-    { 0x0000d364, 0x17ffffe5 },
-    { 0x0000d368, 0x1fffffe4 },
-    { 0x0000d36c, 0x37ffffe3 },
-    { 0x0000d370, 0x3fffffe3 },
-    { 0x0000d374, 0x57ffffe3 },
-    { 0x0000d378, 0x5fffffe2 },
-    { 0x0000d37c, 0x7fffffe2 },
-    { 0x0000d380, 0x7f3c7bba },
-    { 0x0000d384, 0xf3307ff0 },
-    { 0x0000a388, 0x08000000 },
-    { 0x0000a38c, 0x20202020 },
-    { 0x0000a390, 0x20202020 },
-    { 0x0000a394, 0x1ce739ce },
-    { 0x0000a398, 0x000001ce },
-    { 0x0000a39c, 0x00000001 },
-    { 0x0000a3a0, 0x00000000 },
-    { 0x0000a3a4, 0x00000000 },
-    { 0x0000a3a8, 0x00000000 },
-    { 0x0000a3ac, 0x00000000 },
-    { 0x0000a3b0, 0x00000000 },
-    { 0x0000a3b4, 0x00000000 },
-    { 0x0000a3b8, 0x00000000 },
-    { 0x0000a3bc, 0x00000000 },
-    { 0x0000a3c0, 0x00000000 },
-    { 0x0000a3c4, 0x00000000 },
-    { 0x0000a3c8, 0x00000246 },
-    { 0x0000a3cc, 0x20202020 },
-    { 0x0000a3d0, 0x20202020 },
-    { 0x0000a3d4, 0x20202020 },
-    { 0x0000a3dc, 0x1ce739ce },
-    { 0x0000a3e0, 0x000001ce },
+	/* Addr      allmodes  */
+	{0x0000000c, 0x00000000},
+	{0x00000030, 0x00020015},
+	{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},
+	{0x00007010, 0x00000000},
+	{0x00007038, 0x000004c2},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000700},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008048, 0x40000000},
+	{0x00008054, 0x00000000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x000080c0, 0x2a82301a},
+	{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},
+	{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},
+	{0x000081c4, 0x00000000},
+	{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, 0x88000010},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000000},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x00000000},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x00008300, 0x00000000},
+	{0x00008304, 0x00000000},
+	{0x00008308, 0x00000000},
+	{0x0000830c, 0x00000000},
+	{0x00008310, 0x00000000},
+	{0x00008314, 0x00000000},
+	{0x00008318, 0x00000000},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000e00},
+	{0x00008338, 0x00070000},
+	{0x0000833c, 0x00000000},
+	{0x00008340, 0x000107ff},
+	{0x00009808, 0x00000000},
+	{0x0000980c, 0xad848e19},
+	{0x00009810, 0x7d14e000},
+	{0x00009814, 0x9c0a9f6b},
+	{0x0000981c, 0x00000000},
+	{0x0000982c, 0x0000a000},
+	{0x00009830, 0x00000000},
+	{0x0000983c, 0x00200400},
+	{0x00009840, 0x206a002e},
+	{0x0000984c, 0x1284233c},
+	{0x00009854, 0x00000859},
+	{0x00009900, 0x00000000},
+	{0x00009904, 0x00000000},
+	{0x00009908, 0x00000000},
+	{0x0000990c, 0x00000000},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x05100000},
+	{0x0000a920, 0x05100000},
+	{0x0000b920, 0x05100000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009948, 0x9280b212},
+	{0x0000994c, 0x00020028},
+	{0x00009954, 0x5d50e188},
+	{0x00009958, 0x00081fff},
+	{0x0000c95c, 0x004b6a8e},
+	{0x0000c968, 0x000003ce},
+	{0x00009970, 0x190fb515},
+	{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, 0x001fff00},
+	{0x000099ac, 0x00000000},
+	{0x000099b0, 0x03051000},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000200},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x000000aa},
+	{0x000099fc, 0x00001042},
+	{0x00009b00, 0x00000000},
+	{0x00009b04, 0x00000001},
+	{0x00009b08, 0x00000002},
+	{0x00009b0c, 0x00000003},
+	{0x00009b10, 0x00000004},
+	{0x00009b14, 0x00000005},
+	{0x00009b18, 0x00000008},
+	{0x00009b1c, 0x00000009},
+	{0x00009b20, 0x0000000a},
+	{0x00009b24, 0x0000000b},
+	{0x00009b28, 0x0000000c},
+	{0x00009b2c, 0x0000000d},
+	{0x00009b30, 0x00000010},
+	{0x00009b34, 0x00000011},
+	{0x00009b38, 0x00000012},
+	{0x00009b3c, 0x00000013},
+	{0x00009b40, 0x00000014},
+	{0x00009b44, 0x00000015},
+	{0x00009b48, 0x00000018},
+	{0x00009b4c, 0x00000019},
+	{0x00009b50, 0x0000001a},
+	{0x00009b54, 0x0000001b},
+	{0x00009b58, 0x0000001c},
+	{0x00009b5c, 0x0000001d},
+	{0x00009b60, 0x00000020},
+	{0x00009b64, 0x00000021},
+	{0x00009b68, 0x00000022},
+	{0x00009b6c, 0x00000023},
+	{0x00009b70, 0x00000024},
+	{0x00009b74, 0x00000025},
+	{0x00009b78, 0x00000028},
+	{0x00009b7c, 0x00000029},
+	{0x00009b80, 0x0000002a},
+	{0x00009b84, 0x0000002b},
+	{0x00009b88, 0x0000002c},
+	{0x00009b8c, 0x0000002d},
+	{0x00009b90, 0x00000030},
+	{0x00009b94, 0x00000031},
+	{0x00009b98, 0x00000032},
+	{0x00009b9c, 0x00000033},
+	{0x00009ba0, 0x00000034},
+	{0x00009ba4, 0x00000035},
+	{0x00009ba8, 0x00000035},
+	{0x00009bac, 0x00000035},
+	{0x00009bb0, 0x00000035},
+	{0x00009bb4, 0x00000035},
+	{0x00009bb8, 0x00000035},
+	{0x00009bbc, 0x00000035},
+	{0x00009bc0, 0x00000035},
+	{0x00009bc4, 0x00000035},
+	{0x00009bc8, 0x00000035},
+	{0x00009bcc, 0x00000035},
+	{0x00009bd0, 0x00000035},
+	{0x00009bd4, 0x00000035},
+	{0x00009bd8, 0x00000035},
+	{0x00009bdc, 0x00000035},
+	{0x00009be0, 0x00000035},
+	{0x00009be4, 0x00000035},
+	{0x00009be8, 0x00000035},
+	{0x00009bec, 0x00000035},
+	{0x00009bf0, 0x00000035},
+	{0x00009bf4, 0x00000035},
+	{0x00009bf8, 0x00000010},
+	{0x00009bfc, 0x0000001a},
+	{0x0000a210, 0x40806333},
+	{0x0000a214, 0x00106c10},
+	{0x0000a218, 0x009c4060},
+	{0x0000a220, 0x018830c6},
+	{0x0000a224, 0x00000400},
+	{0x0000a228, 0x00000bb5},
+	{0x0000a22c, 0x00000011},
+	{0x0000a234, 0x20202020},
+	{0x0000a238, 0x20202020},
+	{0x0000a23c, 0x13c889af},
+	{0x0000a240, 0x38490a20},
+	{0x0000a244, 0x00007bb6},
+	{0x0000a248, 0x0fff3ffc},
+	{0x0000a24c, 0x00000001},
+	{0x0000a250, 0x0000a000},
+	{0x0000a254, 0x00000000},
+	{0x0000a258, 0x0cc75380},
+	{0x0000a25c, 0x0f0f0f01},
+	{0x0000a260, 0xdfa91f01},
+	{0x0000a268, 0x00000000},
+	{0x0000a26c, 0x0e79e5c6},
+	{0x0000b26c, 0x0e79e5c6},
+	{0x0000c26c, 0x0e79e5c6},
+	{0x0000d270, 0x00820820},
+	{0x0000a278, 0x1ce739ce},
+	{0x0000a27c, 0x051701ce},
+	{0x0000a338, 0x00000000},
+	{0x0000a33c, 0x00000000},
+	{0x0000a340, 0x00000000},
+	{0x0000a344, 0x00000000},
+	{0x0000a348, 0x3fffffff},
+	{0x0000a34c, 0x3fffffff},
+	{0x0000a350, 0x3fffffff},
+	{0x0000a354, 0x0003ffff},
+	{0x0000a358, 0x79a8aa1f},
+	{0x0000d35c, 0x07ffffef},
+	{0x0000d360, 0x0fffffe7},
+	{0x0000d364, 0x17ffffe5},
+	{0x0000d368, 0x1fffffe4},
+	{0x0000d36c, 0x37ffffe3},
+	{0x0000d370, 0x3fffffe3},
+	{0x0000d374, 0x57ffffe3},
+	{0x0000d378, 0x5fffffe2},
+	{0x0000d37c, 0x7fffffe2},
+	{0x0000d380, 0x7f3c7bba},
+	{0x0000d384, 0xf3307ff0},
+	{0x0000a388, 0x08000000},
+	{0x0000a38c, 0x20202020},
+	{0x0000a390, 0x20202020},
+	{0x0000a394, 0x1ce739ce},
+	{0x0000a398, 0x000001ce},
+	{0x0000a39c, 0x00000001},
+	{0x0000a3a0, 0x00000000},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0x00000000},
+	{0x0000a3ac, 0x00000000},
+	{0x0000a3b0, 0x00000000},
+	{0x0000a3b4, 0x00000000},
+	{0x0000a3b8, 0x00000000},
+	{0x0000a3bc, 0x00000000},
+	{0x0000a3c0, 0x00000000},
+	{0x0000a3c4, 0x00000000},
+	{0x0000a3c8, 0x00000246},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3dc, 0x1ce739ce},
+	{0x0000a3e0, 0x000001ce},
 };
 
 static const u32 ar5416Bank0[][2] = {
-    { 0x000098b0, 0x1e5795e5 },
-    { 0x000098e0, 0x02008020 },
+	/* Addr      allmodes  */
+	{0x000098b0, 0x1e5795e5},
+	{0x000098e0, 0x02008020},
 };
 
 static const u32 ar5416BB_RfGain[][3] = {
-    { 0x00009a00, 0x00000000, 0x00000000 },
-    { 0x00009a04, 0x00000040, 0x00000040 },
-    { 0x00009a08, 0x00000080, 0x00000080 },
-    { 0x00009a0c, 0x000001a1, 0x00000141 },
-    { 0x00009a10, 0x000001e1, 0x00000181 },
-    { 0x00009a14, 0x00000021, 0x000001c1 },
-    { 0x00009a18, 0x00000061, 0x00000001 },
-    { 0x00009a1c, 0x00000168, 0x00000041 },
-    { 0x00009a20, 0x000001a8, 0x000001a8 },
-    { 0x00009a24, 0x000001e8, 0x000001e8 },
-    { 0x00009a28, 0x00000028, 0x00000028 },
-    { 0x00009a2c, 0x00000068, 0x00000068 },
-    { 0x00009a30, 0x00000189, 0x000000a8 },
-    { 0x00009a34, 0x000001c9, 0x00000169 },
-    { 0x00009a38, 0x00000009, 0x000001a9 },
-    { 0x00009a3c, 0x00000049, 0x000001e9 },
-    { 0x00009a40, 0x00000089, 0x00000029 },
-    { 0x00009a44, 0x00000170, 0x00000069 },
-    { 0x00009a48, 0x000001b0, 0x00000190 },
-    { 0x00009a4c, 0x000001f0, 0x000001d0 },
-    { 0x00009a50, 0x00000030, 0x00000010 },
-    { 0x00009a54, 0x00000070, 0x00000050 },
-    { 0x00009a58, 0x00000191, 0x00000090 },
-    { 0x00009a5c, 0x000001d1, 0x00000151 },
-    { 0x00009a60, 0x00000011, 0x00000191 },
-    { 0x00009a64, 0x00000051, 0x000001d1 },
-    { 0x00009a68, 0x00000091, 0x00000011 },
-    { 0x00009a6c, 0x000001b8, 0x00000051 },
-    { 0x00009a70, 0x000001f8, 0x00000198 },
-    { 0x00009a74, 0x00000038, 0x000001d8 },
-    { 0x00009a78, 0x00000078, 0x00000018 },
-    { 0x00009a7c, 0x00000199, 0x00000058 },
-    { 0x00009a80, 0x000001d9, 0x00000098 },
-    { 0x00009a84, 0x00000019, 0x00000159 },
-    { 0x00009a88, 0x00000059, 0x00000199 },
-    { 0x00009a8c, 0x00000099, 0x000001d9 },
-    { 0x00009a90, 0x000000d9, 0x00000019 },
-    { 0x00009a94, 0x000000f9, 0x00000059 },
-    { 0x00009a98, 0x000000f9, 0x00000099 },
-    { 0x00009a9c, 0x000000f9, 0x000000d9 },
-    { 0x00009aa0, 0x000000f9, 0x000000f9 },
-    { 0x00009aa4, 0x000000f9, 0x000000f9 },
-    { 0x00009aa8, 0x000000f9, 0x000000f9 },
-    { 0x00009aac, 0x000000f9, 0x000000f9 },
-    { 0x00009ab0, 0x000000f9, 0x000000f9 },
-    { 0x00009ab4, 0x000000f9, 0x000000f9 },
-    { 0x00009ab8, 0x000000f9, 0x000000f9 },
-    { 0x00009abc, 0x000000f9, 0x000000f9 },
-    { 0x00009ac0, 0x000000f9, 0x000000f9 },
-    { 0x00009ac4, 0x000000f9, 0x000000f9 },
-    { 0x00009ac8, 0x000000f9, 0x000000f9 },
-    { 0x00009acc, 0x000000f9, 0x000000f9 },
-    { 0x00009ad0, 0x000000f9, 0x000000f9 },
-    { 0x00009ad4, 0x000000f9, 0x000000f9 },
-    { 0x00009ad8, 0x000000f9, 0x000000f9 },
-    { 0x00009adc, 0x000000f9, 0x000000f9 },
-    { 0x00009ae0, 0x000000f9, 0x000000f9 },
-    { 0x00009ae4, 0x000000f9, 0x000000f9 },
-    { 0x00009ae8, 0x000000f9, 0x000000f9 },
-    { 0x00009aec, 0x000000f9, 0x000000f9 },
-    { 0x00009af0, 0x000000f9, 0x000000f9 },
-    { 0x00009af4, 0x000000f9, 0x000000f9 },
-    { 0x00009af8, 0x000000f9, 0x000000f9 },
-    { 0x00009afc, 0x000000f9, 0x000000f9 },
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x00009a00, 0x00000000, 0x00000000},
+	{0x00009a04, 0x00000040, 0x00000040},
+	{0x00009a08, 0x00000080, 0x00000080},
+	{0x00009a0c, 0x000001a1, 0x00000141},
+	{0x00009a10, 0x000001e1, 0x00000181},
+	{0x00009a14, 0x00000021, 0x000001c1},
+	{0x00009a18, 0x00000061, 0x00000001},
+	{0x00009a1c, 0x00000168, 0x00000041},
+	{0x00009a20, 0x000001a8, 0x000001a8},
+	{0x00009a24, 0x000001e8, 0x000001e8},
+	{0x00009a28, 0x00000028, 0x00000028},
+	{0x00009a2c, 0x00000068, 0x00000068},
+	{0x00009a30, 0x00000189, 0x000000a8},
+	{0x00009a34, 0x000001c9, 0x00000169},
+	{0x00009a38, 0x00000009, 0x000001a9},
+	{0x00009a3c, 0x00000049, 0x000001e9},
+	{0x00009a40, 0x00000089, 0x00000029},
+	{0x00009a44, 0x00000170, 0x00000069},
+	{0x00009a48, 0x000001b0, 0x00000190},
+	{0x00009a4c, 0x000001f0, 0x000001d0},
+	{0x00009a50, 0x00000030, 0x00000010},
+	{0x00009a54, 0x00000070, 0x00000050},
+	{0x00009a58, 0x00000191, 0x00000090},
+	{0x00009a5c, 0x000001d1, 0x00000151},
+	{0x00009a60, 0x00000011, 0x00000191},
+	{0x00009a64, 0x00000051, 0x000001d1},
+	{0x00009a68, 0x00000091, 0x00000011},
+	{0x00009a6c, 0x000001b8, 0x00000051},
+	{0x00009a70, 0x000001f8, 0x00000198},
+	{0x00009a74, 0x00000038, 0x000001d8},
+	{0x00009a78, 0x00000078, 0x00000018},
+	{0x00009a7c, 0x00000199, 0x00000058},
+	{0x00009a80, 0x000001d9, 0x00000098},
+	{0x00009a84, 0x00000019, 0x00000159},
+	{0x00009a88, 0x00000059, 0x00000199},
+	{0x00009a8c, 0x00000099, 0x000001d9},
+	{0x00009a90, 0x000000d9, 0x00000019},
+	{0x00009a94, 0x000000f9, 0x00000059},
+	{0x00009a98, 0x000000f9, 0x00000099},
+	{0x00009a9c, 0x000000f9, 0x000000d9},
+	{0x00009aa0, 0x000000f9, 0x000000f9},
+	{0x00009aa4, 0x000000f9, 0x000000f9},
+	{0x00009aa8, 0x000000f9, 0x000000f9},
+	{0x00009aac, 0x000000f9, 0x000000f9},
+	{0x00009ab0, 0x000000f9, 0x000000f9},
+	{0x00009ab4, 0x000000f9, 0x000000f9},
+	{0x00009ab8, 0x000000f9, 0x000000f9},
+	{0x00009abc, 0x000000f9, 0x000000f9},
+	{0x00009ac0, 0x000000f9, 0x000000f9},
+	{0x00009ac4, 0x000000f9, 0x000000f9},
+	{0x00009ac8, 0x000000f9, 0x000000f9},
+	{0x00009acc, 0x000000f9, 0x000000f9},
+	{0x00009ad0, 0x000000f9, 0x000000f9},
+	{0x00009ad4, 0x000000f9, 0x000000f9},
+	{0x00009ad8, 0x000000f9, 0x000000f9},
+	{0x00009adc, 0x000000f9, 0x000000f9},
+	{0x00009ae0, 0x000000f9, 0x000000f9},
+	{0x00009ae4, 0x000000f9, 0x000000f9},
+	{0x00009ae8, 0x000000f9, 0x000000f9},
+	{0x00009aec, 0x000000f9, 0x000000f9},
+	{0x00009af0, 0x000000f9, 0x000000f9},
+	{0x00009af4, 0x000000f9, 0x000000f9},
+	{0x00009af8, 0x000000f9, 0x000000f9},
+	{0x00009afc, 0x000000f9, 0x000000f9},
 };
 
 static const u32 ar5416Bank1[][2] = {
-    { 0x000098b0, 0x02108421 },
-    { 0x000098ec, 0x00000008 },
+	/* Addr      allmodes  */
+	{0x000098b0, 0x02108421},
+	{0x000098ec, 0x00000008},
 };
 
 static const u32 ar5416Bank2[][2] = {
-    { 0x000098b0, 0x0e73ff17 },
-    { 0x000098e0, 0x00000420 },
+	/* Addr      allmodes  */
+	{0x000098b0, 0x0e73ff17},
+	{0x000098e0, 0x00000420},
 };
 
 static const u32 ar5416Bank3[][3] = {
-    { 0x000098f0, 0x01400018, 0x01c00018 },
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x000098f0, 0x01400018, 0x01c00018},
 };
 
 static const u32 ar5416Bank6[][3] = {
-
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00e00000, 0x00e00000 },
-    { 0x0000989c, 0x005e0000, 0x005e0000 },
-    { 0x0000989c, 0x00120000, 0x00120000 },
-    { 0x0000989c, 0x00620000, 0x00620000 },
-    { 0x0000989c, 0x00020000, 0x00020000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
-    { 0x0000989c, 0x005f0000, 0x005f0000 },
-    { 0x0000989c, 0x00870000, 0x00870000 },
-    { 0x0000989c, 0x00f90000, 0x00f90000 },
-    { 0x0000989c, 0x007b0000, 0x007b0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00f50000, 0x00f50000 },
-    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
-    { 0x0000989c, 0x00110000, 0x00110000 },
-    { 0x0000989c, 0x006100a8, 0x006100a8 },
-    { 0x0000989c, 0x004210a2, 0x004210a2 },
-    { 0x0000989c, 0x0014008f, 0x0014008f },
-    { 0x0000989c, 0x00c40003, 0x00c40003 },
-    { 0x0000989c, 0x003000f2, 0x003000f2 },
-    { 0x0000989c, 0x00440016, 0x00440016 },
-    { 0x0000989c, 0x00410040, 0x00410040 },
-    { 0x0000989c, 0x0001805e, 0x0001805e },
-    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
-    { 0x0000989c, 0x000000f1, 0x000000f1 },
-    { 0x0000989c, 0x00002081, 0x00002081 },
-    { 0x0000989c, 0x000000d4, 0x000000d4 },
-    { 0x000098d0, 0x0000000f, 0x0010000f },
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00e00000, 0x00e00000},
+	{0x0000989c, 0x005e0000, 0x005e0000},
+	{0x0000989c, 0x00120000, 0x00120000},
+	{0x0000989c, 0x00620000, 0x00620000},
+	{0x0000989c, 0x00020000, 0x00020000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x40ff0000, 0x40ff0000},
+	{0x0000989c, 0x005f0000, 0x005f0000},
+	{0x0000989c, 0x00870000, 0x00870000},
+	{0x0000989c, 0x00f90000, 0x00f90000},
+	{0x0000989c, 0x007b0000, 0x007b0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00f50000, 0x00f50000},
+	{0x0000989c, 0x00dc0000, 0x00dc0000},
+	{0x0000989c, 0x00110000, 0x00110000},
+	{0x0000989c, 0x006100a8, 0x006100a8},
+	{0x0000989c, 0x004210a2, 0x004210a2},
+	{0x0000989c, 0x0014008f, 0x0014008f},
+	{0x0000989c, 0x00c40003, 0x00c40003},
+	{0x0000989c, 0x003000f2, 0x003000f2},
+	{0x0000989c, 0x00440016, 0x00440016},
+	{0x0000989c, 0x00410040, 0x00410040},
+	{0x0000989c, 0x0001805e, 0x0001805e},
+	{0x0000989c, 0x0000c0ab, 0x0000c0ab},
+	{0x0000989c, 0x000000f1, 0x000000f1},
+	{0x0000989c, 0x00002081, 0x00002081},
+	{0x0000989c, 0x000000d4, 0x000000d4},
+	{0x000098d0, 0x0000000f, 0x0010000f},
 };
 
 static const u32 ar5416Bank6TPC[][3] = {
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00e00000, 0x00e00000 },
-    { 0x0000989c, 0x005e0000, 0x005e0000 },
-    { 0x0000989c, 0x00120000, 0x00120000 },
-    { 0x0000989c, 0x00620000, 0x00620000 },
-    { 0x0000989c, 0x00020000, 0x00020000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
-    { 0x0000989c, 0x005f0000, 0x005f0000 },
-    { 0x0000989c, 0x00870000, 0x00870000 },
-    { 0x0000989c, 0x00f90000, 0x00f90000 },
-    { 0x0000989c, 0x007b0000, 0x007b0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00f50000, 0x00f50000 },
-    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
-    { 0x0000989c, 0x00110000, 0x00110000 },
-    { 0x0000989c, 0x006100a8, 0x006100a8 },
-    { 0x0000989c, 0x00423022, 0x00423022 },
-    { 0x0000989c, 0x201400df, 0x201400df },
-    { 0x0000989c, 0x00c40002, 0x00c40002 },
-    { 0x0000989c, 0x003000f2, 0x003000f2 },
-    { 0x0000989c, 0x00440016, 0x00440016 },
-    { 0x0000989c, 0x00410040, 0x00410040 },
-    { 0x0000989c, 0x0001805e, 0x0001805e },
-    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
-    { 0x0000989c, 0x000000e1, 0x000000e1 },
-    { 0x0000989c, 0x00007081, 0x00007081 },
-    { 0x0000989c, 0x000000d4, 0x000000d4 },
-    { 0x000098d0, 0x0000000f, 0x0010000f },
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00e00000, 0x00e00000},
+	{0x0000989c, 0x005e0000, 0x005e0000},
+	{0x0000989c, 0x00120000, 0x00120000},
+	{0x0000989c, 0x00620000, 0x00620000},
+	{0x0000989c, 0x00020000, 0x00020000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x40ff0000, 0x40ff0000},
+	{0x0000989c, 0x005f0000, 0x005f0000},
+	{0x0000989c, 0x00870000, 0x00870000},
+	{0x0000989c, 0x00f90000, 0x00f90000},
+	{0x0000989c, 0x007b0000, 0x007b0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00f50000, 0x00f50000},
+	{0x0000989c, 0x00dc0000, 0x00dc0000},
+	{0x0000989c, 0x00110000, 0x00110000},
+	{0x0000989c, 0x006100a8, 0x006100a8},
+	{0x0000989c, 0x00423022, 0x00423022},
+	{0x0000989c, 0x201400df, 0x201400df},
+	{0x0000989c, 0x00c40002, 0x00c40002},
+	{0x0000989c, 0x003000f2, 0x003000f2},
+	{0x0000989c, 0x00440016, 0x00440016},
+	{0x0000989c, 0x00410040, 0x00410040},
+	{0x0000989c, 0x0001805e, 0x0001805e},
+	{0x0000989c, 0x0000c0ab, 0x0000c0ab},
+	{0x0000989c, 0x000000e1, 0x000000e1},
+	{0x0000989c, 0x00007081, 0x00007081},
+	{0x0000989c, 0x000000d4, 0x000000d4},
+	{0x000098d0, 0x0000000f, 0x0010000f},
 };
 
 static const u32 ar5416Bank7[][2] = {
-    { 0x0000989c, 0x00000500 },
-    { 0x0000989c, 0x00000800 },
-    { 0x000098cc, 0x0000000e },
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000500},
+	{0x0000989c, 0x00000800},
+	{0x000098cc, 0x0000000e},
 };
 
 static const u32 ar5416Addac[][2] = {
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000003 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x0000000c },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000030 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000060 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000058 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x000098cc,  0x00000000 },
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000003},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x0000000c},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000030},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000060},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000058},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x000098cc, 0x00000000},
 };
 
-static const u32 ar5416Modes_9100[][6] = {
-    { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
-    { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
-    { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
-    { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
-    { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
-    { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
-    { 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 },
-    { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
-    { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 },
-    { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec86d2e, 0x7ec84d2e, 0x7ec82d2e },
-    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
-    { 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 },
-    { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
-    { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a11, 0xd00a8a0d, 0xd00a8a0d },
-    { 0x00009940, 0x00754604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204 },
-    { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
-    { 0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e },
-    { 0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff },
-#ifdef TB243
-    { 0x00009960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
-    { 0x0000a960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
-    { 0x0000b960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
-    { 0x00009964, 0x00000000, 0x00000000, 0x00002210, 0x00002210, 0x00001120 },
-#else
-    { 0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
-    { 0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
-    { 0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
-    { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
-#endif
-    { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00 },
-    { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
-    { 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 },
-    { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
-    { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
-    { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
-    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
-    { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
-    { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
-    { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
-    { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
-    { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
-    { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
-    { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
-    { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
-    { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
-    { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
-    { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-};
-
-#endif /* INITVALS_AR5008_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index b2c17c9..3d2c867 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -19,7 +19,30 @@
 #include "../regd.h"
 #include "ar9002_phy.h"
 
-/* All code below is for non single-chip solutions */
+/* All code below is for AR5008, AR9001, AR9002 */
+
+static const int firstep_table[] =
+/* level:  0   1   2   3   4   5   6   7   8  */
+	{ -4, -2,  0,  2,  4,  6,  8, 10, 12 }; /* lvl 0-8, default 2 */
+
+static const int cycpwrThr1_table[] =
+/* level:  0   1   2   3   4   5   6   7   8  */
+	{ -6, -4, -2,  0,  2,  4,  6,  8 };     /* lvl 0-7, default 3 */
+
+/*
+ * register values to turn OFDM weak signal detection OFF
+ */
+static const int m1ThreshLow_off = 127;
+static const int m2ThreshLow_off = 127;
+static const int m1Thresh_off = 127;
+static const int m2Thresh_off = 127;
+static const int m2CountThr_off =  31;
+static const int m2CountThrLow_off =  63;
+static const int m1ThreshLowExt_off = 127;
+static const int m2ThreshLowExt_off = 127;
+static const int m1ThreshExt_off = 127;
+static const int m2ThreshExt_off = 127;
+
 
 /**
  * ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters
@@ -742,17 +765,6 @@
 		return -EINVAL;
 	}
 
-	if (AR_SREV_9287_12_OR_LATER(ah)) {
-		/* Enable ASYNC FIFO */
-		REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
-				AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
-		REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
-		REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
-				AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
-		REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
-				AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
-	}
-
 	/*
 	 * Set correct baseband to analog shift setting to
 	 * access analog chips.
@@ -1037,8 +1049,9 @@
 	return pll;
 }
 
-static bool ar5008_hw_ani_control(struct ath_hw *ah,
-				  enum ath9k_ani_cmd cmd, int param)
+static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
+				      enum ath9k_ani_cmd cmd,
+				      int param)
 {
 	struct ar5416AniState *aniState = ah->curani;
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -1220,60 +1233,369 @@
 	return true;
 }
 
+static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
+				      enum ath9k_ani_cmd cmd,
+				      int param)
+{
+	struct ar5416AniState *aniState = ah->curani;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_channel *chan = ah->curchan;
+	s32 value, value2;
+
+	switch (cmd & ah->ani_function) {
+	case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+		/*
+		 * on == 1 means ofdm weak signal detection is ON
+		 * on == 1 is the default, for less noise immunity
+		 *
+		 * on == 0 means ofdm weak signal detection is OFF
+		 * on == 0 means more noise imm
+		 */
+		u32 on = param ? 1 : 0;
+		/*
+		 * make register setting for default
+		 * (weak sig detect ON) come from INI file
+		 */
+		int m1ThreshLow = on ?
+			aniState->iniDef.m1ThreshLow : m1ThreshLow_off;
+		int m2ThreshLow = on ?
+			aniState->iniDef.m2ThreshLow : m2ThreshLow_off;
+		int m1Thresh = on ?
+			aniState->iniDef.m1Thresh : m1Thresh_off;
+		int m2Thresh = on ?
+			aniState->iniDef.m2Thresh : m2Thresh_off;
+		int m2CountThr = on ?
+			aniState->iniDef.m2CountThr : m2CountThr_off;
+		int m2CountThrLow = on ?
+			aniState->iniDef.m2CountThrLow : m2CountThrLow_off;
+		int m1ThreshLowExt = on ?
+			aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off;
+		int m2ThreshLowExt = on ?
+			aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off;
+		int m1ThreshExt = on ?
+			aniState->iniDef.m1ThreshExt : m1ThreshExt_off;
+		int m2ThreshExt = on ?
+			aniState->iniDef.m2ThreshExt : m2ThreshExt_off;
+
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+			      m1ThreshLow);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+			      m2ThreshLow);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M1_THRESH, m1Thresh);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M2_THRESH, m2Thresh);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M2COUNT_THR, m2CountThr);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+			      m2CountThrLow);
+
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLowExt);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLowExt);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M1_THRESH, m1ThreshExt);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M2_THRESH, m2ThreshExt);
+
+		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) {
+			ath_print(common, ATH_DBG_ANI,
+				  "** ch %d: ofdm weak signal: %s=>%s\n",
+				  chan->channel,
+				  !aniState->ofdmWeakSigDetectOff ?
+					"on" : "off",
+				  on ? "on" : "off");
+			if (on)
+				ah->stats.ast_ani_ofdmon++;
+			else
+				ah->stats.ast_ani_ofdmoff++;
+			aniState->ofdmWeakSigDetectOff = !on;
+		}
+		break;
+	}
+	case ATH9K_ANI_FIRSTEP_LEVEL:{
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(firstep_table)) {
+			ath_print(common, ATH_DBG_ANI,
+				  "ATH9K_ANI_FIRSTEP_LEVEL: level "
+				  "out of range (%u > %u)\n",
+				  level,
+				  (unsigned) ARRAY_SIZE(firstep_table));
+			return false;
+		}
+
+		/*
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value = firstep_table[level] -
+			firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+			aniState->iniDef.firstep;
+		if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+			value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+		if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+			value = ATH9K_SIG_FIRSTEP_SETTING_MAX;
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+			      AR_PHY_FIND_SIG_FIRSTEP,
+			      value);
+		/*
+		 * we need to set first step low register too
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value2 = firstep_table[level] -
+			 firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+			 aniState->iniDef.firstepLow;
+		if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+			value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+		if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+			value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX;
+
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
+			      AR_PHY_FIND_SIG_FIRSTEP_LOW, value2);
+
+		if (level != aniState->firstepLevel) {
+			ath_print(common, ATH_DBG_ANI,
+				  "** ch %d: level %d=>%d[def:%d] "
+				  "firstep[level]=%d ini=%d\n",
+				  chan->channel,
+				  aniState->firstepLevel,
+				  level,
+				  ATH9K_ANI_FIRSTEP_LVL_NEW,
+				  value,
+				  aniState->iniDef.firstep);
+			ath_print(common, ATH_DBG_ANI,
+				  "** ch %d: level %d=>%d[def:%d] "
+				  "firstep_low[level]=%d ini=%d\n",
+				  chan->channel,
+				  aniState->firstepLevel,
+				  level,
+				  ATH9K_ANI_FIRSTEP_LVL_NEW,
+				  value2,
+				  aniState->iniDef.firstepLow);
+			if (level > aniState->firstepLevel)
+				ah->stats.ast_ani_stepup++;
+			else if (level < aniState->firstepLevel)
+				ah->stats.ast_ani_stepdown++;
+			aniState->firstepLevel = level;
+		}
+		break;
+	}
+	case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(cycpwrThr1_table)) {
+			ath_print(common, ATH_DBG_ANI,
+				  "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level "
+				  "out of range (%u > %u)\n",
+				  level,
+				  (unsigned) ARRAY_SIZE(cycpwrThr1_table));
+			return false;
+		}
+		/*
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value = cycpwrThr1_table[level] -
+			cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+			aniState->iniDef.cycpwrThr1;
+		if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+			value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+		if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+			value = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
+		REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+			      AR_PHY_TIMING5_CYCPWR_THR1,
+			      value);
+
+		/*
+		 * set AR_PHY_EXT_CCA for extension channel
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value2 = cycpwrThr1_table[level] -
+			 cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+			 aniState->iniDef.cycpwrThr1Ext;
+		if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+			value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+		if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+			value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
+		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+			      AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2);
+
+		if (level != aniState->spurImmunityLevel) {
+			ath_print(common, ATH_DBG_ANI,
+				  "** ch %d: level %d=>%d[def:%d] "
+				  "cycpwrThr1[level]=%d ini=%d\n",
+				  chan->channel,
+				  aniState->spurImmunityLevel,
+				  level,
+				  ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+				  value,
+				  aniState->iniDef.cycpwrThr1);
+			ath_print(common, ATH_DBG_ANI,
+				  "** ch %d: level %d=>%d[def:%d] "
+				  "cycpwrThr1Ext[level]=%d ini=%d\n",
+				  chan->channel,
+				  aniState->spurImmunityLevel,
+				  level,
+				  ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+				  value2,
+				  aniState->iniDef.cycpwrThr1Ext);
+			if (level > aniState->spurImmunityLevel)
+				ah->stats.ast_ani_spurup++;
+			else if (level < aniState->spurImmunityLevel)
+				ah->stats.ast_ani_spurdown++;
+			aniState->spurImmunityLevel = level;
+		}
+		break;
+	}
+	case ATH9K_ANI_MRC_CCK:
+		/*
+		 * You should not see this as AR5008, AR9001, AR9002
+		 * does not have hardware support for MRC CCK.
+		 */
+		WARN_ON(1);
+		break;
+	case ATH9K_ANI_PRESENT:
+		break;
+	default:
+		ath_print(common, ATH_DBG_ANI,
+			  "invalid cmd %u\n", cmd);
+		return false;
+	}
+
+	ath_print(common, ATH_DBG_ANI,
+		  "ANI parameters: SI=%d, ofdmWS=%s FS=%d "
+		  "MRCcck=%s listenTime=%d CC=%d listen=%d "
+		  "ofdmErrs=%d cckErrs=%d\n",
+		  aniState->spurImmunityLevel,
+		  !aniState->ofdmWeakSigDetectOff ? "on" : "off",
+		  aniState->firstepLevel,
+		  !aniState->mrcCCKOff ? "on" : "off",
+		  aniState->listenTime,
+		  aniState->cycleCount,
+		  aniState->listenTime,
+		  aniState->ofdmPhyErrCount,
+		  aniState->cckPhyErrCount);
+	return true;
+}
+
 static void ar5008_hw_do_getnf(struct ath_hw *ah,
 			      int16_t nfarray[NUM_NF_READINGS])
 {
-	struct ath_common *common = ath9k_hw_common(ah);
 	int16_t nf;
 
 	nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ctl] [chain 0] is %d\n", nf);
-	nfarray[0] = nf;
+	nfarray[0] = sign_extend(nf, 9);
 
 	nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR);
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ctl] [chain 1] is %d\n", nf);
-	nfarray[1] = nf;
+	nfarray[1] = sign_extend(nf, 9);
 
 	nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR);
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ctl] [chain 2] is %d\n", nf);
-	nfarray[2] = nf;
+	nfarray[2] = sign_extend(nf, 9);
+
+	if (!IS_CHAN_HT40(ah->curchan))
+		return;
 
 	nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ext] [chain 0] is %d\n", nf);
-	nfarray[3] = nf;
+	nfarray[3] = sign_extend(nf, 9);
 
 	nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR);
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ext] [chain 1] is %d\n", nf);
-	nfarray[4] = nf;
+	nfarray[4] = sign_extend(nf, 9);
 
 	nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR);
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ext] [chain 2] is %d\n", nf);
-	nfarray[5] = nf;
+	nfarray[5] = sign_extend(nf, 9);
 }
 
-static void ar5008_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
+/*
+ * Initialize the ANI register values with default (ini) values.
+ * This routine is called during a (full) hardware reset after
+ * all the registers are initialised from the INI.
+ */
+static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
 {
-	struct ath9k_nfcal_hist *h;
-	int i, j;
-	int32_t val;
+	struct ar5416AniState *aniState;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_channel *chan = ah->curchan;
+	struct ath9k_ani_default *iniDef;
+	int index;
+	u32 val;
+
+	index = ath9k_hw_get_ani_channel_idx(ah, chan);
+	aniState = &ah->ani[index];
+	ah->curani = aniState;
+	iniDef = &aniState->iniDef;
+
+	ath_print(common, ATH_DBG_ANI,
+		  "ver %d.%d opmode %u chan %d Mhz/0x%x\n",
+		  ah->hw_version.macVersion,
+		  ah->hw_version.macRev,
+		  ah->opmode,
+		  chan->channel,
+		  chan->channelFlags);
+
+	val = REG_READ(ah, AR_PHY_SFCORR);
+	iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH);
+	iniDef->m2Thresh = MS(val, AR_PHY_SFCORR_M2_THRESH);
+	iniDef->m2CountThr = MS(val, AR_PHY_SFCORR_M2COUNT_THR);
+
+	val = REG_READ(ah, AR_PHY_SFCORR_LOW);
+	iniDef->m1ThreshLow = MS(val, AR_PHY_SFCORR_LOW_M1_THRESH_LOW);
+	iniDef->m2ThreshLow = MS(val, AR_PHY_SFCORR_LOW_M2_THRESH_LOW);
+	iniDef->m2CountThrLow = MS(val, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW);
+
+	val = REG_READ(ah, AR_PHY_SFCORR_EXT);
+	iniDef->m1ThreshExt = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH);
+	iniDef->m2ThreshExt = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH);
+	iniDef->m1ThreshLowExt = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH_LOW);
+	iniDef->m2ThreshLowExt = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH_LOW);
+	iniDef->firstep = REG_READ_FIELD(ah,
+					 AR_PHY_FIND_SIG,
+					 AR_PHY_FIND_SIG_FIRSTEP);
+	iniDef->firstepLow = REG_READ_FIELD(ah,
+					    AR_PHY_FIND_SIG_LOW,
+					    AR_PHY_FIND_SIG_FIRSTEP_LOW);
+	iniDef->cycpwrThr1 = REG_READ_FIELD(ah,
+					    AR_PHY_TIMING5,
+					    AR_PHY_TIMING5_CYCPWR_THR1);
+	iniDef->cycpwrThr1Ext = REG_READ_FIELD(ah,
+					       AR_PHY_EXT_CCA,
+					       AR_PHY_EXT_TIMING5_CYCPWR_THR1);
+
+	/* these levels just got reset to defaults by the INI */
+	aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+	aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
+	aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
+	aniState->mrcCCKOff = true; /* not available on pre AR9003 */
+
+	aniState->cycleCount = 0;
+}
+
+static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
+{
+	ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_2GHZ;
+	ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_2GHZ;
+	ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_5416_2GHZ;
+	ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_5GHZ;
+	ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_5GHZ;
+	ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_5416_5GHZ;
+}
+
+void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
+{
+	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
 	const u32 ar5416_cca_regs[6] = {
 		AR_PHY_CCA,
 		AR_PHY_CH1_CCA,
@@ -1282,67 +1604,6 @@
 		AR_PHY_CH1_EXT_CCA,
 		AR_PHY_CH2_EXT_CCA
 	};
-	u8 chainmask, rx_chain_status;
-
-	rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK);
-	if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
-		chainmask = 0x9;
-	else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
-		if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4))
-			chainmask = 0x1B;
-		else
-			chainmask = 0x09;
-	} else {
-		if (rx_chain_status & 0x4)
-			chainmask = 0x3F;
-		else if (rx_chain_status & 0x2)
-			chainmask = 0x1B;
-		else
-			chainmask = 0x09;
-	}
-
-	h = ah->nfCalHist;
-
-	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 < 5; j++) {
-		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
-		     AR_PHY_AGC_CONTROL_NF) == 0)
-			break;
-		udelay(50);
-	}
-
-	ENABLE_REGWRITE_BUFFER(ah);
-
-	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);
-		}
-	}
-
-	REGWRITE_BUFFER_FLUSH(ah);
-	DISABLE_REGWRITE_BUFFER(ah);
-}
-
-void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
-{
-	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
 
 	priv_ops->rf_set_freq = ar5008_hw_set_channel;
 	priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate;
@@ -1361,9 +1622,13 @@
 	priv_ops->enable_rfkill = ar5008_hw_enable_rfkill;
 	priv_ops->restore_chainmask = ar5008_restore_chainmask;
 	priv_ops->set_diversity = ar5008_set_diversity;
-	priv_ops->ani_control = ar5008_hw_ani_control;
 	priv_ops->do_getnf = ar5008_hw_do_getnf;
-	priv_ops->loadnf = ar5008_hw_loadnf;
+
+	if (modparam_force_new_ani) {
+		priv_ops->ani_control = ar5008_hw_ani_control_new;
+		priv_ops->ani_cache_ini_regs = ar5008_hw_ani_cache_ini_regs;
+	} else
+		priv_ops->ani_control = ar5008_hw_ani_control_old;
 
 	if (AR_SREV_9100(ah))
 		priv_ops->compute_pll_control = ar9100_hw_compute_pll_control;
@@ -1371,4 +1636,7 @@
 		priv_ops->compute_pll_control = ar9160_hw_compute_pll_control;
 	else
 		priv_ops->compute_pll_control = ar5008_hw_compute_pll_control;
+
+	ar5008_hw_set_nf_limits(ah);
+	memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs));
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
index 0b94bd3..69a94c7 100644
--- a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
@@ -1,1254 +1,1357 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+static const u32 ar5416Modes_9100[][6] = {
+	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+	{0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008},
+	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+	{0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
+	{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},
+	{0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0},
+	{0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2, 0x6c48b0e2},
+	{0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
+	{0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 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, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+	{0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
+	{0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
+	{0x00009940, 0x00750604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204},
+	{0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020},
+	{0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e},
+	{0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff},
+	{0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
+	{0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
+	{0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
+	{0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120},
+	{0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00},
+	{0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
+	{0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+	{0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329},
+	{0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+	{0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+	{0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
+	{0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788},
+	{0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa},
+	{0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
+	{0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402},
+	{0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06},
+	{0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b},
+	{0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b},
+	{0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a},
+	{0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf},
+	{0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f},
+	{0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f},
+	{0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f},
+	{0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+};
 
 static const u32 ar5416Common_9100[][2] = {
-    { 0x0000000c, 0x00000000 },
-    { 0x00000030, 0x00020015 },
-    { 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 },
-    { 0x00020010, 0x00000003 },
-    { 0x00020038, 0x000004c2 },
-    { 0x00008004, 0x00000000 },
-    { 0x00008008, 0x00000000 },
-    { 0x0000800c, 0x00000000 },
-    { 0x00008018, 0x00000700 },
-    { 0x00008020, 0x00000000 },
-    { 0x00008038, 0x00000000 },
-    { 0x0000803c, 0x00000000 },
-    { 0x00008048, 0x40000000 },
-    { 0x00008054, 0x00004000 },
-    { 0x00008058, 0x00000000 },
-    { 0x0000805c, 0x000fc78f },
-    { 0x00008060, 0x0000000f },
-    { 0x00008064, 0x00000000 },
-    { 0x000080c0, 0x2a82301a },
-    { 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 },
-    { 0x000081c4, 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 },
-    { 0x00008270, 0x00000000 },
-    { 0x00008274, 0x40000000 },
-    { 0x00008278, 0x003e4180 },
-    { 0x0000827c, 0x00000000 },
-    { 0x00008284, 0x0000002c },
-    { 0x00008288, 0x0000002c },
-    { 0x0000828c, 0x00000000 },
-    { 0x00008294, 0x00000000 },
-    { 0x00008298, 0x00000000 },
-    { 0x00008300, 0x00000000 },
-    { 0x00008304, 0x00000000 },
-    { 0x00008308, 0x00000000 },
-    { 0x0000830c, 0x00000000 },
-    { 0x00008310, 0x00000000 },
-    { 0x00008314, 0x00000000 },
-    { 0x00008318, 0x00000000 },
-    { 0x00008328, 0x00000000 },
-    { 0x0000832c, 0x00000007 },
-    { 0x00008330, 0x00000302 },
-    { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00000000 },
-    { 0x0000833c, 0x00000000 },
-    { 0x00008340, 0x000107ff },
-    { 0x00009808, 0x00000000 },
-    { 0x0000980c, 0xad848e19 },
-    { 0x00009810, 0x7d14e000 },
-    { 0x00009814, 0x9c0a9f6b },
-    { 0x0000981c, 0x00000000 },
-    { 0x0000982c, 0x0000a000 },
-    { 0x00009830, 0x00000000 },
-    { 0x0000983c, 0x00200400 },
-    { 0x00009840, 0x206a01ae },
-    { 0x0000984c, 0x1284233c },
-    { 0x00009854, 0x00000859 },
-    { 0x00009900, 0x00000000 },
-    { 0x00009904, 0x00000000 },
-    { 0x00009908, 0x00000000 },
-    { 0x0000990c, 0x00000000 },
-    { 0x0000991c, 0x10000fff },
-    { 0x00009920, 0x05100000 },
-    { 0x0000a920, 0x05100000 },
-    { 0x0000b920, 0x05100000 },
-    { 0x00009928, 0x00000001 },
-    { 0x0000992c, 0x00000004 },
-    { 0x00009934, 0x1e1f2022 },
-    { 0x00009938, 0x0a0b0c0d },
-    { 0x0000993c, 0x00000000 },
-    { 0x00009948, 0x9280b212 },
-    { 0x0000994c, 0x00020028 },
-    { 0x0000c95c, 0x004b6a8e },
-    { 0x0000c968, 0x000003ce },
-    { 0x00009970, 0x190fb515 },
-    { 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, 0x006f0000 },
-    { 0x000099b0, 0x03051000 },
-    { 0x000099dc, 0x00000000 },
-    { 0x000099e0, 0x00000200 },
-    { 0x000099e4, 0xaaaaaaaa },
-    { 0x000099e8, 0x3c466478 },
-    { 0x000099ec, 0x0cc80caa },
-    { 0x000099fc, 0x00001042 },
-    { 0x00009b00, 0x00000000 },
-    { 0x00009b04, 0x00000001 },
-    { 0x00009b08, 0x00000002 },
-    { 0x00009b0c, 0x00000003 },
-    { 0x00009b10, 0x00000004 },
-    { 0x00009b14, 0x00000005 },
-    { 0x00009b18, 0x00000008 },
-    { 0x00009b1c, 0x00000009 },
-    { 0x00009b20, 0x0000000a },
-    { 0x00009b24, 0x0000000b },
-    { 0x00009b28, 0x0000000c },
-    { 0x00009b2c, 0x0000000d },
-    { 0x00009b30, 0x00000010 },
-    { 0x00009b34, 0x00000011 },
-    { 0x00009b38, 0x00000012 },
-    { 0x00009b3c, 0x00000013 },
-    { 0x00009b40, 0x00000014 },
-    { 0x00009b44, 0x00000015 },
-    { 0x00009b48, 0x00000018 },
-    { 0x00009b4c, 0x00000019 },
-    { 0x00009b50, 0x0000001a },
-    { 0x00009b54, 0x0000001b },
-    { 0x00009b58, 0x0000001c },
-    { 0x00009b5c, 0x0000001d },
-    { 0x00009b60, 0x00000020 },
-    { 0x00009b64, 0x00000021 },
-    { 0x00009b68, 0x00000022 },
-    { 0x00009b6c, 0x00000023 },
-    { 0x00009b70, 0x00000024 },
-    { 0x00009b74, 0x00000025 },
-    { 0x00009b78, 0x00000028 },
-    { 0x00009b7c, 0x00000029 },
-    { 0x00009b80, 0x0000002a },
-    { 0x00009b84, 0x0000002b },
-    { 0x00009b88, 0x0000002c },
-    { 0x00009b8c, 0x0000002d },
-    { 0x00009b90, 0x00000030 },
-    { 0x00009b94, 0x00000031 },
-    { 0x00009b98, 0x00000032 },
-    { 0x00009b9c, 0x00000033 },
-    { 0x00009ba0, 0x00000034 },
-    { 0x00009ba4, 0x00000035 },
-    { 0x00009ba8, 0x00000035 },
-    { 0x00009bac, 0x00000035 },
-    { 0x00009bb0, 0x00000035 },
-    { 0x00009bb4, 0x00000035 },
-    { 0x00009bb8, 0x00000035 },
-    { 0x00009bbc, 0x00000035 },
-    { 0x00009bc0, 0x00000035 },
-    { 0x00009bc4, 0x00000035 },
-    { 0x00009bc8, 0x00000035 },
-    { 0x00009bcc, 0x00000035 },
-    { 0x00009bd0, 0x00000035 },
-    { 0x00009bd4, 0x00000035 },
-    { 0x00009bd8, 0x00000035 },
-    { 0x00009bdc, 0x00000035 },
-    { 0x00009be0, 0x00000035 },
-    { 0x00009be4, 0x00000035 },
-    { 0x00009be8, 0x00000035 },
-    { 0x00009bec, 0x00000035 },
-    { 0x00009bf0, 0x00000035 },
-    { 0x00009bf4, 0x00000035 },
-    { 0x00009bf8, 0x00000010 },
-    { 0x00009bfc, 0x0000001a },
-    { 0x0000a210, 0x40806333 },
-    { 0x0000a214, 0x00106c10 },
-    { 0x0000a218, 0x009c4060 },
-    { 0x0000a220, 0x018830c6 },
-    { 0x0000a224, 0x00000400 },
-    { 0x0000a228, 0x001a0bb5 },
-    { 0x0000a22c, 0x00000000 },
-    { 0x0000a234, 0x20202020 },
-    { 0x0000a238, 0x20202020 },
-    { 0x0000a23c, 0x13c889ae },
-    { 0x0000a240, 0x38490a20 },
-    { 0x0000a244, 0x00007bb6 },
-    { 0x0000a248, 0x0fff3ffc },
-    { 0x0000a24c, 0x00000001 },
-    { 0x0000a250, 0x0000a000 },
-    { 0x0000a254, 0x00000000 },
-    { 0x0000a258, 0x0cc75380 },
-    { 0x0000a25c, 0x0f0f0f01 },
-    { 0x0000a260, 0xdfa91f01 },
-    { 0x0000a268, 0x00000001 },
-    { 0x0000a26c, 0x0ebae9c6 },
-    { 0x0000b26c, 0x0ebae9c6 },
-    { 0x0000c26c, 0x0ebae9c6 },
-    { 0x0000d270, 0x00820820 },
-    { 0x0000a278, 0x1ce739ce },
-    { 0x0000a27c, 0x050701ce },
-    { 0x0000a338, 0x00000000 },
-    { 0x0000a33c, 0x00000000 },
-    { 0x0000a340, 0x00000000 },
-    { 0x0000a344, 0x00000000 },
-    { 0x0000a348, 0x3fffffff },
-    { 0x0000a34c, 0x3fffffff },
-    { 0x0000a350, 0x3fffffff },
-    { 0x0000a354, 0x0003ffff },
-    { 0x0000a358, 0x79a8aa33 },
-    { 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, 0x1ce739ce },
-    { 0x0000a398, 0x000001ce },
-    { 0x0000a39c, 0x00000001 },
-    { 0x0000a3a0, 0x00000000 },
-    { 0x0000a3a4, 0x00000000 },
-    { 0x0000a3a8, 0x00000000 },
-    { 0x0000a3ac, 0x00000000 },
-    { 0x0000a3b0, 0x00000000 },
-    { 0x0000a3b4, 0x00000000 },
-    { 0x0000a3b8, 0x00000000 },
-    { 0x0000a3bc, 0x00000000 },
-    { 0x0000a3c0, 0x00000000 },
-    { 0x0000a3c4, 0x00000000 },
-    { 0x0000a3c8, 0x00000246 },
-    { 0x0000a3cc, 0x20202020 },
-    { 0x0000a3d0, 0x20202020 },
-    { 0x0000a3d4, 0x20202020 },
-    { 0x0000a3dc, 0x1ce739ce },
-    { 0x0000a3e0, 0x000001ce },
+	/* Addr      allmodes  */
+	{0x0000000c, 0x00000000},
+	{0x00000030, 0x00020015},
+	{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},
+	{0x00020010, 0x00000003},
+	{0x00020038, 0x000004c2},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000700},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008048, 0x40000000},
+	{0x00008054, 0x00004000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x000080c0, 0x2a82301a},
+	{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},
+	{0x000081c4, 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},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000000},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x00000000},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x00008300, 0x00000000},
+	{0x00008304, 0x00000000},
+	{0x00008308, 0x00000000},
+	{0x0000830c, 0x00000000},
+	{0x00008310, 0x00000000},
+	{0x00008314, 0x00000000},
+	{0x00008318, 0x00000000},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000e00},
+	{0x00008338, 0x00000000},
+	{0x0000833c, 0x00000000},
+	{0x00008340, 0x000107ff},
+	{0x00009808, 0x00000000},
+	{0x0000980c, 0xad848e19},
+	{0x00009810, 0x7d14e000},
+	{0x00009814, 0x9c0a9f6b},
+	{0x0000981c, 0x00000000},
+	{0x0000982c, 0x0000a000},
+	{0x00009830, 0x00000000},
+	{0x0000983c, 0x00200400},
+	{0x00009840, 0x206a01ae},
+	{0x0000984c, 0x1284233c},
+	{0x00009854, 0x00000859},
+	{0x00009900, 0x00000000},
+	{0x00009904, 0x00000000},
+	{0x00009908, 0x00000000},
+	{0x0000990c, 0x00000000},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x05100000},
+	{0x0000a920, 0x05100000},
+	{0x0000b920, 0x05100000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009948, 0x9280b212},
+	{0x0000994c, 0x00020028},
+	{0x0000c95c, 0x004b6a8e},
+	{0x0000c968, 0x000003ce},
+	{0x00009970, 0x190fb515},
+	{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, 0x006f0000},
+	{0x000099b0, 0x03051000},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000200},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x0cc80caa},
+	{0x000099fc, 0x00001042},
+	{0x00009b00, 0x00000000},
+	{0x00009b04, 0x00000001},
+	{0x00009b08, 0x00000002},
+	{0x00009b0c, 0x00000003},
+	{0x00009b10, 0x00000004},
+	{0x00009b14, 0x00000005},
+	{0x00009b18, 0x00000008},
+	{0x00009b1c, 0x00000009},
+	{0x00009b20, 0x0000000a},
+	{0x00009b24, 0x0000000b},
+	{0x00009b28, 0x0000000c},
+	{0x00009b2c, 0x0000000d},
+	{0x00009b30, 0x00000010},
+	{0x00009b34, 0x00000011},
+	{0x00009b38, 0x00000012},
+	{0x00009b3c, 0x00000013},
+	{0x00009b40, 0x00000014},
+	{0x00009b44, 0x00000015},
+	{0x00009b48, 0x00000018},
+	{0x00009b4c, 0x00000019},
+	{0x00009b50, 0x0000001a},
+	{0x00009b54, 0x0000001b},
+	{0x00009b58, 0x0000001c},
+	{0x00009b5c, 0x0000001d},
+	{0x00009b60, 0x00000020},
+	{0x00009b64, 0x00000021},
+	{0x00009b68, 0x00000022},
+	{0x00009b6c, 0x00000023},
+	{0x00009b70, 0x00000024},
+	{0x00009b74, 0x00000025},
+	{0x00009b78, 0x00000028},
+	{0x00009b7c, 0x00000029},
+	{0x00009b80, 0x0000002a},
+	{0x00009b84, 0x0000002b},
+	{0x00009b88, 0x0000002c},
+	{0x00009b8c, 0x0000002d},
+	{0x00009b90, 0x00000030},
+	{0x00009b94, 0x00000031},
+	{0x00009b98, 0x00000032},
+	{0x00009b9c, 0x00000033},
+	{0x00009ba0, 0x00000034},
+	{0x00009ba4, 0x00000035},
+	{0x00009ba8, 0x00000035},
+	{0x00009bac, 0x00000035},
+	{0x00009bb0, 0x00000035},
+	{0x00009bb4, 0x00000035},
+	{0x00009bb8, 0x00000035},
+	{0x00009bbc, 0x00000035},
+	{0x00009bc0, 0x00000035},
+	{0x00009bc4, 0x00000035},
+	{0x00009bc8, 0x00000035},
+	{0x00009bcc, 0x00000035},
+	{0x00009bd0, 0x00000035},
+	{0x00009bd4, 0x00000035},
+	{0x00009bd8, 0x00000035},
+	{0x00009bdc, 0x00000035},
+	{0x00009be0, 0x00000035},
+	{0x00009be4, 0x00000035},
+	{0x00009be8, 0x00000035},
+	{0x00009bec, 0x00000035},
+	{0x00009bf0, 0x00000035},
+	{0x00009bf4, 0x00000035},
+	{0x00009bf8, 0x00000010},
+	{0x00009bfc, 0x0000001a},
+	{0x0000a210, 0x40806333},
+	{0x0000a214, 0x00106c10},
+	{0x0000a218, 0x009c4060},
+	{0x0000a220, 0x018830c6},
+	{0x0000a224, 0x00000400},
+	{0x0000a228, 0x001a0bb5},
+	{0x0000a22c, 0x00000000},
+	{0x0000a234, 0x20202020},
+	{0x0000a238, 0x20202020},
+	{0x0000a23c, 0x13c889af},
+	{0x0000a240, 0x38490a20},
+	{0x0000a244, 0x00007bb6},
+	{0x0000a248, 0x0fff3ffc},
+	{0x0000a24c, 0x00000001},
+	{0x0000a250, 0x0000e000},
+	{0x0000a254, 0x00000000},
+	{0x0000a258, 0x0cc75380},
+	{0x0000a25c, 0x0f0f0f01},
+	{0x0000a260, 0xdfa91f01},
+	{0x0000a268, 0x00000001},
+	{0x0000a26c, 0x0ebae9c6},
+	{0x0000b26c, 0x0ebae9c6},
+	{0x0000c26c, 0x0ebae9c6},
+	{0x0000d270, 0x00820820},
+	{0x0000a278, 0x1ce739ce},
+	{0x0000a27c, 0x050701ce},
+	{0x0000a338, 0x00000000},
+	{0x0000a33c, 0x00000000},
+	{0x0000a340, 0x00000000},
+	{0x0000a344, 0x00000000},
+	{0x0000a348, 0x3fffffff},
+	{0x0000a34c, 0x3fffffff},
+	{0x0000a350, 0x3fffffff},
+	{0x0000a354, 0x0003ffff},
+	{0x0000a358, 0x79a8aa33},
+	{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, 0x1ce739ce},
+	{0x0000a398, 0x000001ce},
+	{0x0000a39c, 0x00000001},
+	{0x0000a3a0, 0x00000000},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0x00000000},
+	{0x0000a3ac, 0x00000000},
+	{0x0000a3b0, 0x00000000},
+	{0x0000a3b4, 0x00000000},
+	{0x0000a3b8, 0x00000000},
+	{0x0000a3bc, 0x00000000},
+	{0x0000a3c0, 0x00000000},
+	{0x0000a3c4, 0x00000000},
+	{0x0000a3c8, 0x00000246},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3dc, 0x1ce739ce},
+	{0x0000a3e0, 0x000001ce},
 };
 
 static const u32 ar5416Bank0_9100[][2] = {
-    { 0x000098b0, 0x1e5795e5 },
-    { 0x000098e0, 0x02008020 },
+	/* Addr      allmodes  */
+	{0x000098b0, 0x1e5795e5},
+	{0x000098e0, 0x02008020},
 };
 
 static const u32 ar5416BB_RfGain_9100[][3] = {
-    { 0x00009a00, 0x00000000, 0x00000000 },
-    { 0x00009a04, 0x00000040, 0x00000040 },
-    { 0x00009a08, 0x00000080, 0x00000080 },
-    { 0x00009a0c, 0x000001a1, 0x00000141 },
-    { 0x00009a10, 0x000001e1, 0x00000181 },
-    { 0x00009a14, 0x00000021, 0x000001c1 },
-    { 0x00009a18, 0x00000061, 0x00000001 },
-    { 0x00009a1c, 0x00000168, 0x00000041 },
-    { 0x00009a20, 0x000001a8, 0x000001a8 },
-    { 0x00009a24, 0x000001e8, 0x000001e8 },
-    { 0x00009a28, 0x00000028, 0x00000028 },
-    { 0x00009a2c, 0x00000068, 0x00000068 },
-    { 0x00009a30, 0x00000189, 0x000000a8 },
-    { 0x00009a34, 0x000001c9, 0x00000169 },
-    { 0x00009a38, 0x00000009, 0x000001a9 },
-    { 0x00009a3c, 0x00000049, 0x000001e9 },
-    { 0x00009a40, 0x00000089, 0x00000029 },
-    { 0x00009a44, 0x00000170, 0x00000069 },
-    { 0x00009a48, 0x000001b0, 0x00000190 },
-    { 0x00009a4c, 0x000001f0, 0x000001d0 },
-    { 0x00009a50, 0x00000030, 0x00000010 },
-    { 0x00009a54, 0x00000070, 0x00000050 },
-    { 0x00009a58, 0x00000191, 0x00000090 },
-    { 0x00009a5c, 0x000001d1, 0x00000151 },
-    { 0x00009a60, 0x00000011, 0x00000191 },
-    { 0x00009a64, 0x00000051, 0x000001d1 },
-    { 0x00009a68, 0x00000091, 0x00000011 },
-    { 0x00009a6c, 0x000001b8, 0x00000051 },
-    { 0x00009a70, 0x000001f8, 0x00000198 },
-    { 0x00009a74, 0x00000038, 0x000001d8 },
-    { 0x00009a78, 0x00000078, 0x00000018 },
-    { 0x00009a7c, 0x00000199, 0x00000058 },
-    { 0x00009a80, 0x000001d9, 0x00000098 },
-    { 0x00009a84, 0x00000019, 0x00000159 },
-    { 0x00009a88, 0x00000059, 0x00000199 },
-    { 0x00009a8c, 0x00000099, 0x000001d9 },
-    { 0x00009a90, 0x000000d9, 0x00000019 },
-    { 0x00009a94, 0x000000f9, 0x00000059 },
-    { 0x00009a98, 0x000000f9, 0x00000099 },
-    { 0x00009a9c, 0x000000f9, 0x000000d9 },
-    { 0x00009aa0, 0x000000f9, 0x000000f9 },
-    { 0x00009aa4, 0x000000f9, 0x000000f9 },
-    { 0x00009aa8, 0x000000f9, 0x000000f9 },
-    { 0x00009aac, 0x000000f9, 0x000000f9 },
-    { 0x00009ab0, 0x000000f9, 0x000000f9 },
-    { 0x00009ab4, 0x000000f9, 0x000000f9 },
-    { 0x00009ab8, 0x000000f9, 0x000000f9 },
-    { 0x00009abc, 0x000000f9, 0x000000f9 },
-    { 0x00009ac0, 0x000000f9, 0x000000f9 },
-    { 0x00009ac4, 0x000000f9, 0x000000f9 },
-    { 0x00009ac8, 0x000000f9, 0x000000f9 },
-    { 0x00009acc, 0x000000f9, 0x000000f9 },
-    { 0x00009ad0, 0x000000f9, 0x000000f9 },
-    { 0x00009ad4, 0x000000f9, 0x000000f9 },
-    { 0x00009ad8, 0x000000f9, 0x000000f9 },
-    { 0x00009adc, 0x000000f9, 0x000000f9 },
-    { 0x00009ae0, 0x000000f9, 0x000000f9 },
-    { 0x00009ae4, 0x000000f9, 0x000000f9 },
-    { 0x00009ae8, 0x000000f9, 0x000000f9 },
-    { 0x00009aec, 0x000000f9, 0x000000f9 },
-    { 0x00009af0, 0x000000f9, 0x000000f9 },
-    { 0x00009af4, 0x000000f9, 0x000000f9 },
-    { 0x00009af8, 0x000000f9, 0x000000f9 },
-    { 0x00009afc, 0x000000f9, 0x000000f9 },
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x00009a00, 0x00000000, 0x00000000},
+	{0x00009a04, 0x00000040, 0x00000040},
+	{0x00009a08, 0x00000080, 0x00000080},
+	{0x00009a0c, 0x000001a1, 0x00000141},
+	{0x00009a10, 0x000001e1, 0x00000181},
+	{0x00009a14, 0x00000021, 0x000001c1},
+	{0x00009a18, 0x00000061, 0x00000001},
+	{0x00009a1c, 0x00000168, 0x00000041},
+	{0x00009a20, 0x000001a8, 0x000001a8},
+	{0x00009a24, 0x000001e8, 0x000001e8},
+	{0x00009a28, 0x00000028, 0x00000028},
+	{0x00009a2c, 0x00000068, 0x00000068},
+	{0x00009a30, 0x00000189, 0x000000a8},
+	{0x00009a34, 0x000001c9, 0x00000169},
+	{0x00009a38, 0x00000009, 0x000001a9},
+	{0x00009a3c, 0x00000049, 0x000001e9},
+	{0x00009a40, 0x00000089, 0x00000029},
+	{0x00009a44, 0x00000170, 0x00000069},
+	{0x00009a48, 0x000001b0, 0x00000190},
+	{0x00009a4c, 0x000001f0, 0x000001d0},
+	{0x00009a50, 0x00000030, 0x00000010},
+	{0x00009a54, 0x00000070, 0x00000050},
+	{0x00009a58, 0x00000191, 0x00000090},
+	{0x00009a5c, 0x000001d1, 0x00000151},
+	{0x00009a60, 0x00000011, 0x00000191},
+	{0x00009a64, 0x00000051, 0x000001d1},
+	{0x00009a68, 0x00000091, 0x00000011},
+	{0x00009a6c, 0x000001b8, 0x00000051},
+	{0x00009a70, 0x000001f8, 0x00000198},
+	{0x00009a74, 0x00000038, 0x000001d8},
+	{0x00009a78, 0x00000078, 0x00000018},
+	{0x00009a7c, 0x00000199, 0x00000058},
+	{0x00009a80, 0x000001d9, 0x00000098},
+	{0x00009a84, 0x00000019, 0x00000159},
+	{0x00009a88, 0x00000059, 0x00000199},
+	{0x00009a8c, 0x00000099, 0x000001d9},
+	{0x00009a90, 0x000000d9, 0x00000019},
+	{0x00009a94, 0x000000f9, 0x00000059},
+	{0x00009a98, 0x000000f9, 0x00000099},
+	{0x00009a9c, 0x000000f9, 0x000000d9},
+	{0x00009aa0, 0x000000f9, 0x000000f9},
+	{0x00009aa4, 0x000000f9, 0x000000f9},
+	{0x00009aa8, 0x000000f9, 0x000000f9},
+	{0x00009aac, 0x000000f9, 0x000000f9},
+	{0x00009ab0, 0x000000f9, 0x000000f9},
+	{0x00009ab4, 0x000000f9, 0x000000f9},
+	{0x00009ab8, 0x000000f9, 0x000000f9},
+	{0x00009abc, 0x000000f9, 0x000000f9},
+	{0x00009ac0, 0x000000f9, 0x000000f9},
+	{0x00009ac4, 0x000000f9, 0x000000f9},
+	{0x00009ac8, 0x000000f9, 0x000000f9},
+	{0x00009acc, 0x000000f9, 0x000000f9},
+	{0x00009ad0, 0x000000f9, 0x000000f9},
+	{0x00009ad4, 0x000000f9, 0x000000f9},
+	{0x00009ad8, 0x000000f9, 0x000000f9},
+	{0x00009adc, 0x000000f9, 0x000000f9},
+	{0x00009ae0, 0x000000f9, 0x000000f9},
+	{0x00009ae4, 0x000000f9, 0x000000f9},
+	{0x00009ae8, 0x000000f9, 0x000000f9},
+	{0x00009aec, 0x000000f9, 0x000000f9},
+	{0x00009af0, 0x000000f9, 0x000000f9},
+	{0x00009af4, 0x000000f9, 0x000000f9},
+	{0x00009af8, 0x000000f9, 0x000000f9},
+	{0x00009afc, 0x000000f9, 0x000000f9},
 };
 
 static const u32 ar5416Bank1_9100[][2] = {
-    { 0x000098b0, 0x02108421},
-    { 0x000098ec, 0x00000008},
+	/* Addr      allmodes  */
+	{0x000098b0, 0x02108421},
+	{0x000098ec, 0x00000008},
 };
 
 static const u32 ar5416Bank2_9100[][2] = {
-    { 0x000098b0, 0x0e73ff17},
-    { 0x000098e0, 0x00000420},
+	/* Addr      allmodes  */
+	{0x000098b0, 0x0e73ff17},
+	{0x000098e0, 0x00000420},
 };
 
 static const u32 ar5416Bank3_9100[][3] = {
-    { 0x000098f0, 0x01400018, 0x01c00018 },
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x000098f0, 0x01400018, 0x01c00018},
 };
 
 static const u32 ar5416Bank6_9100[][3] = {
-
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00e00000, 0x00e00000 },
-    { 0x0000989c, 0x005e0000, 0x005e0000 },
-    { 0x0000989c, 0x00120000, 0x00120000 },
-    { 0x0000989c, 0x00620000, 0x00620000 },
-    { 0x0000989c, 0x00020000, 0x00020000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x005f0000, 0x005f0000 },
-    { 0x0000989c, 0x00870000, 0x00870000 },
-    { 0x0000989c, 0x00f90000, 0x00f90000 },
-    { 0x0000989c, 0x007b0000, 0x007b0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00f50000, 0x00f50000 },
-    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
-    { 0x0000989c, 0x00110000, 0x00110000 },
-    { 0x0000989c, 0x006100a8, 0x006100a8 },
-    { 0x0000989c, 0x004210a2, 0x004210a2 },
-    { 0x0000989c, 0x0014000f, 0x0014000f },
-    { 0x0000989c, 0x00c40002, 0x00c40002 },
-    { 0x0000989c, 0x003000f2, 0x003000f2 },
-    { 0x0000989c, 0x00440016, 0x00440016 },
-    { 0x0000989c, 0x00410040, 0x00410040 },
-    { 0x0000989c, 0x000180d6, 0x000180d6 },
-    { 0x0000989c, 0x0000c0aa, 0x0000c0aa },
-    { 0x0000989c, 0x000000b1, 0x000000b1 },
-    { 0x0000989c, 0x00002000, 0x00002000 },
-    { 0x0000989c, 0x000000d4, 0x000000d4 },
-    { 0x000098d0, 0x0000000f, 0x0010000f },
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00e00000, 0x00e00000},
+	{0x0000989c, 0x005e0000, 0x005e0000},
+	{0x0000989c, 0x00120000, 0x00120000},
+	{0x0000989c, 0x00620000, 0x00620000},
+	{0x0000989c, 0x00020000, 0x00020000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x005f0000, 0x005f0000},
+	{0x0000989c, 0x00870000, 0x00870000},
+	{0x0000989c, 0x00f90000, 0x00f90000},
+	{0x0000989c, 0x007b0000, 0x007b0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00f50000, 0x00f50000},
+	{0x0000989c, 0x00dc0000, 0x00dc0000},
+	{0x0000989c, 0x00110000, 0x00110000},
+	{0x0000989c, 0x006100a8, 0x006100a8},
+	{0x0000989c, 0x004210a2, 0x004210a2},
+	{0x0000989c, 0x0014000f, 0x0014000f},
+	{0x0000989c, 0x00c40002, 0x00c40002},
+	{0x0000989c, 0x003000f2, 0x003000f2},
+	{0x0000989c, 0x00440016, 0x00440016},
+	{0x0000989c, 0x00410040, 0x00410040},
+	{0x0000989c, 0x000180d6, 0x000180d6},
+	{0x0000989c, 0x0000c0aa, 0x0000c0aa},
+	{0x0000989c, 0x000000b1, 0x000000b1},
+	{0x0000989c, 0x00002000, 0x00002000},
+	{0x0000989c, 0x000000d4, 0x000000d4},
+	{0x000098d0, 0x0000000f, 0x0010000f},
 };
 
-
 static const u32 ar5416Bank6TPC_9100[][3] = {
-
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00e00000, 0x00e00000 },
-    { 0x0000989c, 0x005e0000, 0x005e0000 },
-    { 0x0000989c, 0x00120000, 0x00120000 },
-    { 0x0000989c, 0x00620000, 0x00620000 },
-    { 0x0000989c, 0x00020000, 0x00020000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
-    { 0x0000989c, 0x005f0000, 0x005f0000 },
-    { 0x0000989c, 0x00870000, 0x00870000 },
-    { 0x0000989c, 0x00f90000, 0x00f90000 },
-    { 0x0000989c, 0x007b0000, 0x007b0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00f50000, 0x00f50000 },
-    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
-    { 0x0000989c, 0x00110000, 0x00110000 },
-    { 0x0000989c, 0x006100a8, 0x006100a8 },
-    { 0x0000989c, 0x00423022, 0x00423022 },
-    { 0x0000989c, 0x2014008f, 0x2014008f },
-    { 0x0000989c, 0x00c40002, 0x00c40002 },
-    { 0x0000989c, 0x003000f2, 0x003000f2 },
-    { 0x0000989c, 0x00440016, 0x00440016 },
-    { 0x0000989c, 0x00410040, 0x00410040 },
-    { 0x0000989c, 0x0001805e, 0x0001805e },
-    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
-    { 0x0000989c, 0x000000e1, 0x000000e1 },
-    { 0x0000989c, 0x00007080, 0x00007080 },
-    { 0x0000989c, 0x000000d4, 0x000000d4 },
-    { 0x000098d0, 0x0000000f, 0x0010000f },
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00e00000, 0x00e00000},
+	{0x0000989c, 0x005e0000, 0x005e0000},
+	{0x0000989c, 0x00120000, 0x00120000},
+	{0x0000989c, 0x00620000, 0x00620000},
+	{0x0000989c, 0x00020000, 0x00020000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x40ff0000, 0x40ff0000},
+	{0x0000989c, 0x005f0000, 0x005f0000},
+	{0x0000989c, 0x00870000, 0x00870000},
+	{0x0000989c, 0x00f90000, 0x00f90000},
+	{0x0000989c, 0x007b0000, 0x007b0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00f50000, 0x00f50000},
+	{0x0000989c, 0x00dc0000, 0x00dc0000},
+	{0x0000989c, 0x00110000, 0x00110000},
+	{0x0000989c, 0x006100a8, 0x006100a8},
+	{0x0000989c, 0x00423022, 0x00423022},
+	{0x0000989c, 0x2014008f, 0x2014008f},
+	{0x0000989c, 0x00c40002, 0x00c40002},
+	{0x0000989c, 0x003000f2, 0x003000f2},
+	{0x0000989c, 0x00440016, 0x00440016},
+	{0x0000989c, 0x00410040, 0x00410040},
+	{0x0000989c, 0x0001805e, 0x0001805e},
+	{0x0000989c, 0x0000c0ab, 0x0000c0ab},
+	{0x0000989c, 0x000000e1, 0x000000e1},
+	{0x0000989c, 0x00007080, 0x00007080},
+	{0x0000989c, 0x000000d4, 0x000000d4},
+	{0x000098d0, 0x0000000f, 0x0010000f},
 };
 
 static const u32 ar5416Bank7_9100[][2] = {
-    { 0x0000989c, 0x00000500 },
-    { 0x0000989c, 0x00000800 },
-    { 0x000098cc, 0x0000000e },
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000500},
+	{0x0000989c, 0x00000800},
+	{0x000098cc, 0x0000000e},
 };
 
 static const u32 ar5416Addac_9100[][2] = {
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000010 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x000000c0 },
-    {0x0000989c, 0x00000015 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x000098cc, 0x00000000 },
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000010},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x000000c0},
+	{0x0000989c, 0x00000015},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x000098cc, 0x00000000},
 };
 
 static const u32 ar5416Modes_9160[][6] = {
-    { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
-    { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
-    { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
-    { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
-    { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
-    { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
-    { 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 },
-    { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
-    { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 },
-    { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
-    { 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, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
-    { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
-    { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
-    { 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 },
-    { 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 },
-    { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
-    { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
-    { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
-    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
-    { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
-    { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
-    { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
-    { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
-    { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
-    { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
-    { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
-    { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
-    { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
-    { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
-    { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+	{0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008},
+	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+	{0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
+	{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},
+	{0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0},
+	{0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2, 0x6c48b0e2},
+	{0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
+	{0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+	{0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18},
+	{0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+	{0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0},
+	{0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
+	{0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+	{0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
+	{0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
+	{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},
+	{0x000099bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00},
+	{0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
+	{0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+	{0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329},
+	{0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+	{0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+	{0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
+	{0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788},
+	{0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa},
+	{0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
+	{0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402},
+	{0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06},
+	{0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b},
+	{0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b},
+	{0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a},
+	{0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf},
+	{0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f},
+	{0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f},
+	{0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f},
+	{0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 };
 
 static const u32 ar5416Common_9160[][2] = {
-    { 0x0000000c, 0x00000000 },
-    { 0x00000030, 0x00020015 },
-    { 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 },
-    { 0x00007010, 0x00000020 },
-    { 0x00007038, 0x000004c2 },
-    { 0x00008004, 0x00000000 },
-    { 0x00008008, 0x00000000 },
-    { 0x0000800c, 0x00000000 },
-    { 0x00008018, 0x00000700 },
-    { 0x00008020, 0x00000000 },
-    { 0x00008038, 0x00000000 },
-    { 0x0000803c, 0x00000000 },
-    { 0x00008048, 0x40000000 },
-    { 0x00008054, 0x00000000 },
-    { 0x00008058, 0x00000000 },
-    { 0x0000805c, 0x000fc78f },
-    { 0x00008060, 0x0000000f },
-    { 0x00008064, 0x00000000 },
-    { 0x000080c0, 0x2a82301a },
-    { 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 },
-    { 0x000081c4, 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 },
-    { 0x00008270, 0x00000000 },
-    { 0x00008274, 0x40000000 },
-    { 0x00008278, 0x003e4180 },
-    { 0x0000827c, 0x00000000 },
-    { 0x00008284, 0x0000002c },
-    { 0x00008288, 0x0000002c },
-    { 0x0000828c, 0x00000000 },
-    { 0x00008294, 0x00000000 },
-    { 0x00008298, 0x00000000 },
-    { 0x00008300, 0x00000000 },
-    { 0x00008304, 0x00000000 },
-    { 0x00008308, 0x00000000 },
-    { 0x0000830c, 0x00000000 },
-    { 0x00008310, 0x00000000 },
-    { 0x00008314, 0x00000000 },
-    { 0x00008318, 0x00000000 },
-    { 0x00008328, 0x00000000 },
-    { 0x0000832c, 0x00000007 },
-    { 0x00008330, 0x00000302 },
-    { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00ff0000 },
-    { 0x0000833c, 0x00000000 },
-    { 0x00008340, 0x000107ff },
-    { 0x00009808, 0x00000000 },
-    { 0x0000980c, 0xad848e19 },
-    { 0x00009810, 0x7d14e000 },
-    { 0x00009814, 0x9c0a9f6b },
-    { 0x0000981c, 0x00000000 },
-    { 0x0000982c, 0x0000a000 },
-    { 0x00009830, 0x00000000 },
-    { 0x0000983c, 0x00200400 },
-    { 0x00009840, 0x206a01ae },
-    { 0x0000984c, 0x1284233c },
-    { 0x00009854, 0x00000859 },
-    { 0x00009900, 0x00000000 },
-    { 0x00009904, 0x00000000 },
-    { 0x00009908, 0x00000000 },
-    { 0x0000990c, 0x00000000 },
-    { 0x0000991c, 0x10000fff },
-    { 0x00009920, 0x05100000 },
-    { 0x0000a920, 0x05100000 },
-    { 0x0000b920, 0x05100000 },
-    { 0x00009928, 0x00000001 },
-    { 0x0000992c, 0x00000004 },
-    { 0x00009934, 0x1e1f2022 },
-    { 0x00009938, 0x0a0b0c0d },
-    { 0x0000993c, 0x00000000 },
-    { 0x00009948, 0x9280b212 },
-    { 0x0000994c, 0x00020028 },
-    { 0x00009954, 0x5f3ca3de },
-    { 0x00009958, 0x2108ecff },
-    { 0x00009940, 0x00750604 },
-    { 0x0000c95c, 0x004b6a8e },
-    { 0x00009970, 0x190fb515 },
-    { 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, 0x006f0000 },
-    { 0x000099b0, 0x03051000 },
-    { 0x000099dc, 0x00000000 },
-    { 0x000099e0, 0x00000200 },
-    { 0x000099e4, 0xaaaaaaaa },
-    { 0x000099e8, 0x3c466478 },
-    { 0x000099ec, 0x0cc80caa },
-    { 0x000099fc, 0x00001042 },
-    { 0x00009b00, 0x00000000 },
-    { 0x00009b04, 0x00000001 },
-    { 0x00009b08, 0x00000002 },
-    { 0x00009b0c, 0x00000003 },
-    { 0x00009b10, 0x00000004 },
-    { 0x00009b14, 0x00000005 },
-    { 0x00009b18, 0x00000008 },
-    { 0x00009b1c, 0x00000009 },
-    { 0x00009b20, 0x0000000a },
-    { 0x00009b24, 0x0000000b },
-    { 0x00009b28, 0x0000000c },
-    { 0x00009b2c, 0x0000000d },
-    { 0x00009b30, 0x00000010 },
-    { 0x00009b34, 0x00000011 },
-    { 0x00009b38, 0x00000012 },
-    { 0x00009b3c, 0x00000013 },
-    { 0x00009b40, 0x00000014 },
-    { 0x00009b44, 0x00000015 },
-    { 0x00009b48, 0x00000018 },
-    { 0x00009b4c, 0x00000019 },
-    { 0x00009b50, 0x0000001a },
-    { 0x00009b54, 0x0000001b },
-    { 0x00009b58, 0x0000001c },
-    { 0x00009b5c, 0x0000001d },
-    { 0x00009b60, 0x00000020 },
-    { 0x00009b64, 0x00000021 },
-    { 0x00009b68, 0x00000022 },
-    { 0x00009b6c, 0x00000023 },
-    { 0x00009b70, 0x00000024 },
-    { 0x00009b74, 0x00000025 },
-    { 0x00009b78, 0x00000028 },
-    { 0x00009b7c, 0x00000029 },
-    { 0x00009b80, 0x0000002a },
-    { 0x00009b84, 0x0000002b },
-    { 0x00009b88, 0x0000002c },
-    { 0x00009b8c, 0x0000002d },
-    { 0x00009b90, 0x00000030 },
-    { 0x00009b94, 0x00000031 },
-    { 0x00009b98, 0x00000032 },
-    { 0x00009b9c, 0x00000033 },
-    { 0x00009ba0, 0x00000034 },
-    { 0x00009ba4, 0x00000035 },
-    { 0x00009ba8, 0x00000035 },
-    { 0x00009bac, 0x00000035 },
-    { 0x00009bb0, 0x00000035 },
-    { 0x00009bb4, 0x00000035 },
-    { 0x00009bb8, 0x00000035 },
-    { 0x00009bbc, 0x00000035 },
-    { 0x00009bc0, 0x00000035 },
-    { 0x00009bc4, 0x00000035 },
-    { 0x00009bc8, 0x00000035 },
-    { 0x00009bcc, 0x00000035 },
-    { 0x00009bd0, 0x00000035 },
-    { 0x00009bd4, 0x00000035 },
-    { 0x00009bd8, 0x00000035 },
-    { 0x00009bdc, 0x00000035 },
-    { 0x00009be0, 0x00000035 },
-    { 0x00009be4, 0x00000035 },
-    { 0x00009be8, 0x00000035 },
-    { 0x00009bec, 0x00000035 },
-    { 0x00009bf0, 0x00000035 },
-    { 0x00009bf4, 0x00000035 },
-    { 0x00009bf8, 0x00000010 },
-    { 0x00009bfc, 0x0000001a },
-    { 0x0000a210, 0x40806333 },
-    { 0x0000a214, 0x00106c10 },
-    { 0x0000a218, 0x009c4060 },
-    { 0x0000a220, 0x018830c6 },
-    { 0x0000a224, 0x00000400 },
-    { 0x0000a228, 0x001a0bb5 },
-    { 0x0000a22c, 0x00000000 },
-    { 0x0000a234, 0x20202020 },
-    { 0x0000a238, 0x20202020 },
-    { 0x0000a23c, 0x13c889af },
-    { 0x0000a240, 0x38490a20 },
-    { 0x0000a244, 0x00007bb6 },
-    { 0x0000a248, 0x0fff3ffc },
-    { 0x0000a24c, 0x00000001 },
-    { 0x0000a250, 0x0000e000 },
-    { 0x0000a254, 0x00000000 },
-    { 0x0000a258, 0x0cc75380 },
-    { 0x0000a25c, 0x0f0f0f01 },
-    { 0x0000a260, 0xdfa91f01 },
-    { 0x0000a268, 0x00000001 },
-    { 0x0000a26c, 0x0ebae9c6 },
-    { 0x0000b26c, 0x0ebae9c6 },
-    { 0x0000c26c, 0x0ebae9c6 },
-    { 0x0000d270, 0x00820820 },
-    { 0x0000a278, 0x1ce739ce },
-    { 0x0000a27c, 0x050701ce },
-    { 0x0000a338, 0x00000000 },
-    { 0x0000a33c, 0x00000000 },
-    { 0x0000a340, 0x00000000 },
-    { 0x0000a344, 0x00000000 },
-    { 0x0000a348, 0x3fffffff },
-    { 0x0000a34c, 0x3fffffff },
-    { 0x0000a350, 0x3fffffff },
-    { 0x0000a354, 0x0003ffff },
-    { 0x0000a358, 0x79bfaa03 },
-    { 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, 0x1ce739ce },
-    { 0x0000a398, 0x000001ce },
-    { 0x0000a39c, 0x00000001 },
-    { 0x0000a3a0, 0x00000000 },
-    { 0x0000a3a4, 0x00000000 },
-    { 0x0000a3a8, 0x00000000 },
-    { 0x0000a3ac, 0x00000000 },
-    { 0x0000a3b0, 0x00000000 },
-    { 0x0000a3b4, 0x00000000 },
-    { 0x0000a3b8, 0x00000000 },
-    { 0x0000a3bc, 0x00000000 },
-    { 0x0000a3c0, 0x00000000 },
-    { 0x0000a3c4, 0x00000000 },
-    { 0x0000a3c8, 0x00000246 },
-    { 0x0000a3cc, 0x20202020 },
-    { 0x0000a3d0, 0x20202020 },
-    { 0x0000a3d4, 0x20202020 },
-    { 0x0000a3dc, 0x1ce739ce },
-    { 0x0000a3e0, 0x000001ce },
+	/* Addr      allmodes  */
+	{0x0000000c, 0x00000000},
+	{0x00000030, 0x00020015},
+	{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},
+	{0x00007010, 0x00000020},
+	{0x00007038, 0x000004c2},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000700},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008048, 0x40000000},
+	{0x00008054, 0x00000000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x000080c0, 0x2a82301a},
+	{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},
+	{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},
+	{0x000081c4, 0x00000000},
+	{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, 0x88a00010},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000000},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x00000000},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x00008300, 0x00000000},
+	{0x00008304, 0x00000000},
+	{0x00008308, 0x00000000},
+	{0x0000830c, 0x00000000},
+	{0x00008310, 0x00000000},
+	{0x00008314, 0x00000000},
+	{0x00008318, 0x00000000},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000e00},
+	{0x00008338, 0x00ff0000},
+	{0x0000833c, 0x00000000},
+	{0x00008340, 0x000107ff},
+	{0x00009808, 0x00000000},
+	{0x0000980c, 0xad848e19},
+	{0x00009810, 0x7d14e000},
+	{0x00009814, 0x9c0a9f6b},
+	{0x0000981c, 0x00000000},
+	{0x0000982c, 0x0000a000},
+	{0x00009830, 0x00000000},
+	{0x0000983c, 0x00200400},
+	{0x00009840, 0x206a01ae},
+	{0x0000984c, 0x1284233c},
+	{0x00009854, 0x00000859},
+	{0x00009900, 0x00000000},
+	{0x00009904, 0x00000000},
+	{0x00009908, 0x00000000},
+	{0x0000990c, 0x00000000},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x05100000},
+	{0x0000a920, 0x05100000},
+	{0x0000b920, 0x05100000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009948, 0x9280b212},
+	{0x0000994c, 0x00020028},
+	{0x00009954, 0x5f3ca3de},
+	{0x00009958, 0x2108ecff},
+	{0x00009940, 0x00750604},
+	{0x0000c95c, 0x004b6a8e},
+	{0x00009970, 0x190fb515},
+	{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, 0x006f0000},
+	{0x000099b0, 0x03051000},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000200},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x0cc80caa},
+	{0x000099fc, 0x00001042},
+	{0x00009b00, 0x00000000},
+	{0x00009b04, 0x00000001},
+	{0x00009b08, 0x00000002},
+	{0x00009b0c, 0x00000003},
+	{0x00009b10, 0x00000004},
+	{0x00009b14, 0x00000005},
+	{0x00009b18, 0x00000008},
+	{0x00009b1c, 0x00000009},
+	{0x00009b20, 0x0000000a},
+	{0x00009b24, 0x0000000b},
+	{0x00009b28, 0x0000000c},
+	{0x00009b2c, 0x0000000d},
+	{0x00009b30, 0x00000010},
+	{0x00009b34, 0x00000011},
+	{0x00009b38, 0x00000012},
+	{0x00009b3c, 0x00000013},
+	{0x00009b40, 0x00000014},
+	{0x00009b44, 0x00000015},
+	{0x00009b48, 0x00000018},
+	{0x00009b4c, 0x00000019},
+	{0x00009b50, 0x0000001a},
+	{0x00009b54, 0x0000001b},
+	{0x00009b58, 0x0000001c},
+	{0x00009b5c, 0x0000001d},
+	{0x00009b60, 0x00000020},
+	{0x00009b64, 0x00000021},
+	{0x00009b68, 0x00000022},
+	{0x00009b6c, 0x00000023},
+	{0x00009b70, 0x00000024},
+	{0x00009b74, 0x00000025},
+	{0x00009b78, 0x00000028},
+	{0x00009b7c, 0x00000029},
+	{0x00009b80, 0x0000002a},
+	{0x00009b84, 0x0000002b},
+	{0x00009b88, 0x0000002c},
+	{0x00009b8c, 0x0000002d},
+	{0x00009b90, 0x00000030},
+	{0x00009b94, 0x00000031},
+	{0x00009b98, 0x00000032},
+	{0x00009b9c, 0x00000033},
+	{0x00009ba0, 0x00000034},
+	{0x00009ba4, 0x00000035},
+	{0x00009ba8, 0x00000035},
+	{0x00009bac, 0x00000035},
+	{0x00009bb0, 0x00000035},
+	{0x00009bb4, 0x00000035},
+	{0x00009bb8, 0x00000035},
+	{0x00009bbc, 0x00000035},
+	{0x00009bc0, 0x00000035},
+	{0x00009bc4, 0x00000035},
+	{0x00009bc8, 0x00000035},
+	{0x00009bcc, 0x00000035},
+	{0x00009bd0, 0x00000035},
+	{0x00009bd4, 0x00000035},
+	{0x00009bd8, 0x00000035},
+	{0x00009bdc, 0x00000035},
+	{0x00009be0, 0x00000035},
+	{0x00009be4, 0x00000035},
+	{0x00009be8, 0x00000035},
+	{0x00009bec, 0x00000035},
+	{0x00009bf0, 0x00000035},
+	{0x00009bf4, 0x00000035},
+	{0x00009bf8, 0x00000010},
+	{0x00009bfc, 0x0000001a},
+	{0x0000a210, 0x40806333},
+	{0x0000a214, 0x00106c10},
+	{0x0000a218, 0x009c4060},
+	{0x0000a220, 0x018830c6},
+	{0x0000a224, 0x00000400},
+	{0x0000a228, 0x001a0bb5},
+	{0x0000a22c, 0x00000000},
+	{0x0000a234, 0x20202020},
+	{0x0000a238, 0x20202020},
+	{0x0000a23c, 0x13c889af},
+	{0x0000a240, 0x38490a20},
+	{0x0000a244, 0x00007bb6},
+	{0x0000a248, 0x0fff3ffc},
+	{0x0000a24c, 0x00000001},
+	{0x0000a250, 0x0000e000},
+	{0x0000a254, 0x00000000},
+	{0x0000a258, 0x0cc75380},
+	{0x0000a25c, 0x0f0f0f01},
+	{0x0000a260, 0xdfa91f01},
+	{0x0000a268, 0x00000001},
+	{0x0000a26c, 0x0e79e5c6},
+	{0x0000b26c, 0x0e79e5c6},
+	{0x0000c26c, 0x0e79e5c6},
+	{0x0000d270, 0x00820820},
+	{0x0000a278, 0x1ce739ce},
+	{0x0000a27c, 0x050701ce},
+	{0x0000a338, 0x00000000},
+	{0x0000a33c, 0x00000000},
+	{0x0000a340, 0x00000000},
+	{0x0000a344, 0x00000000},
+	{0x0000a348, 0x3fffffff},
+	{0x0000a34c, 0x3fffffff},
+	{0x0000a350, 0x3fffffff},
+	{0x0000a354, 0x0003ffff},
+	{0x0000a358, 0x79bfaa03},
+	{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, 0x1ce739ce},
+	{0x0000a398, 0x000001ce},
+	{0x0000a39c, 0x00000001},
+	{0x0000a3a0, 0x00000000},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0x00000000},
+	{0x0000a3ac, 0x00000000},
+	{0x0000a3b0, 0x00000000},
+	{0x0000a3b4, 0x00000000},
+	{0x0000a3b8, 0x00000000},
+	{0x0000a3bc, 0x00000000},
+	{0x0000a3c0, 0x00000000},
+	{0x0000a3c4, 0x00000000},
+	{0x0000a3c8, 0x00000246},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3dc, 0x1ce739ce},
+	{0x0000a3e0, 0x000001ce},
 };
 
 static const u32 ar5416Bank0_9160[][2] = {
-    { 0x000098b0, 0x1e5795e5 },
-    { 0x000098e0, 0x02008020 },
+	/* Addr      allmodes  */
+	{0x000098b0, 0x1e5795e5},
+	{0x000098e0, 0x02008020},
 };
 
 static const u32 ar5416BB_RfGain_9160[][3] = {
-    { 0x00009a00, 0x00000000, 0x00000000 },
-    { 0x00009a04, 0x00000040, 0x00000040 },
-    { 0x00009a08, 0x00000080, 0x00000080 },
-    { 0x00009a0c, 0x000001a1, 0x00000141 },
-    { 0x00009a10, 0x000001e1, 0x00000181 },
-    { 0x00009a14, 0x00000021, 0x000001c1 },
-    { 0x00009a18, 0x00000061, 0x00000001 },
-    { 0x00009a1c, 0x00000168, 0x00000041 },
-    { 0x00009a20, 0x000001a8, 0x000001a8 },
-    { 0x00009a24, 0x000001e8, 0x000001e8 },
-    { 0x00009a28, 0x00000028, 0x00000028 },
-    { 0x00009a2c, 0x00000068, 0x00000068 },
-    { 0x00009a30, 0x00000189, 0x000000a8 },
-    { 0x00009a34, 0x000001c9, 0x00000169 },
-    { 0x00009a38, 0x00000009, 0x000001a9 },
-    { 0x00009a3c, 0x00000049, 0x000001e9 },
-    { 0x00009a40, 0x00000089, 0x00000029 },
-    { 0x00009a44, 0x00000170, 0x00000069 },
-    { 0x00009a48, 0x000001b0, 0x00000190 },
-    { 0x00009a4c, 0x000001f0, 0x000001d0 },
-    { 0x00009a50, 0x00000030, 0x00000010 },
-    { 0x00009a54, 0x00000070, 0x00000050 },
-    { 0x00009a58, 0x00000191, 0x00000090 },
-    { 0x00009a5c, 0x000001d1, 0x00000151 },
-    { 0x00009a60, 0x00000011, 0x00000191 },
-    { 0x00009a64, 0x00000051, 0x000001d1 },
-    { 0x00009a68, 0x00000091, 0x00000011 },
-    { 0x00009a6c, 0x000001b8, 0x00000051 },
-    { 0x00009a70, 0x000001f8, 0x00000198 },
-    { 0x00009a74, 0x00000038, 0x000001d8 },
-    { 0x00009a78, 0x00000078, 0x00000018 },
-    { 0x00009a7c, 0x00000199, 0x00000058 },
-    { 0x00009a80, 0x000001d9, 0x00000098 },
-    { 0x00009a84, 0x00000019, 0x00000159 },
-    { 0x00009a88, 0x00000059, 0x00000199 },
-    { 0x00009a8c, 0x00000099, 0x000001d9 },
-    { 0x00009a90, 0x000000d9, 0x00000019 },
-    { 0x00009a94, 0x000000f9, 0x00000059 },
-    { 0x00009a98, 0x000000f9, 0x00000099 },
-    { 0x00009a9c, 0x000000f9, 0x000000d9 },
-    { 0x00009aa0, 0x000000f9, 0x000000f9 },
-    { 0x00009aa4, 0x000000f9, 0x000000f9 },
-    { 0x00009aa8, 0x000000f9, 0x000000f9 },
-    { 0x00009aac, 0x000000f9, 0x000000f9 },
-    { 0x00009ab0, 0x000000f9, 0x000000f9 },
-    { 0x00009ab4, 0x000000f9, 0x000000f9 },
-    { 0x00009ab8, 0x000000f9, 0x000000f9 },
-    { 0x00009abc, 0x000000f9, 0x000000f9 },
-    { 0x00009ac0, 0x000000f9, 0x000000f9 },
-    { 0x00009ac4, 0x000000f9, 0x000000f9 },
-    { 0x00009ac8, 0x000000f9, 0x000000f9 },
-    { 0x00009acc, 0x000000f9, 0x000000f9 },
-    { 0x00009ad0, 0x000000f9, 0x000000f9 },
-    { 0x00009ad4, 0x000000f9, 0x000000f9 },
-    { 0x00009ad8, 0x000000f9, 0x000000f9 },
-    { 0x00009adc, 0x000000f9, 0x000000f9 },
-    { 0x00009ae0, 0x000000f9, 0x000000f9 },
-    { 0x00009ae4, 0x000000f9, 0x000000f9 },
-    { 0x00009ae8, 0x000000f9, 0x000000f9 },
-    { 0x00009aec, 0x000000f9, 0x000000f9 },
-    { 0x00009af0, 0x000000f9, 0x000000f9 },
-    { 0x00009af4, 0x000000f9, 0x000000f9 },
-    { 0x00009af8, 0x000000f9, 0x000000f9 },
-    { 0x00009afc, 0x000000f9, 0x000000f9 },
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x00009a00, 0x00000000, 0x00000000},
+	{0x00009a04, 0x00000040, 0x00000040},
+	{0x00009a08, 0x00000080, 0x00000080},
+	{0x00009a0c, 0x000001a1, 0x00000141},
+	{0x00009a10, 0x000001e1, 0x00000181},
+	{0x00009a14, 0x00000021, 0x000001c1},
+	{0x00009a18, 0x00000061, 0x00000001},
+	{0x00009a1c, 0x00000168, 0x00000041},
+	{0x00009a20, 0x000001a8, 0x000001a8},
+	{0x00009a24, 0x000001e8, 0x000001e8},
+	{0x00009a28, 0x00000028, 0x00000028},
+	{0x00009a2c, 0x00000068, 0x00000068},
+	{0x00009a30, 0x00000189, 0x000000a8},
+	{0x00009a34, 0x000001c9, 0x00000169},
+	{0x00009a38, 0x00000009, 0x000001a9},
+	{0x00009a3c, 0x00000049, 0x000001e9},
+	{0x00009a40, 0x00000089, 0x00000029},
+	{0x00009a44, 0x00000170, 0x00000069},
+	{0x00009a48, 0x000001b0, 0x00000190},
+	{0x00009a4c, 0x000001f0, 0x000001d0},
+	{0x00009a50, 0x00000030, 0x00000010},
+	{0x00009a54, 0x00000070, 0x00000050},
+	{0x00009a58, 0x00000191, 0x00000090},
+	{0x00009a5c, 0x000001d1, 0x00000151},
+	{0x00009a60, 0x00000011, 0x00000191},
+	{0x00009a64, 0x00000051, 0x000001d1},
+	{0x00009a68, 0x00000091, 0x00000011},
+	{0x00009a6c, 0x000001b8, 0x00000051},
+	{0x00009a70, 0x000001f8, 0x00000198},
+	{0x00009a74, 0x00000038, 0x000001d8},
+	{0x00009a78, 0x00000078, 0x00000018},
+	{0x00009a7c, 0x00000199, 0x00000058},
+	{0x00009a80, 0x000001d9, 0x00000098},
+	{0x00009a84, 0x00000019, 0x00000159},
+	{0x00009a88, 0x00000059, 0x00000199},
+	{0x00009a8c, 0x00000099, 0x000001d9},
+	{0x00009a90, 0x000000d9, 0x00000019},
+	{0x00009a94, 0x000000f9, 0x00000059},
+	{0x00009a98, 0x000000f9, 0x00000099},
+	{0x00009a9c, 0x000000f9, 0x000000d9},
+	{0x00009aa0, 0x000000f9, 0x000000f9},
+	{0x00009aa4, 0x000000f9, 0x000000f9},
+	{0x00009aa8, 0x000000f9, 0x000000f9},
+	{0x00009aac, 0x000000f9, 0x000000f9},
+	{0x00009ab0, 0x000000f9, 0x000000f9},
+	{0x00009ab4, 0x000000f9, 0x000000f9},
+	{0x00009ab8, 0x000000f9, 0x000000f9},
+	{0x00009abc, 0x000000f9, 0x000000f9},
+	{0x00009ac0, 0x000000f9, 0x000000f9},
+	{0x00009ac4, 0x000000f9, 0x000000f9},
+	{0x00009ac8, 0x000000f9, 0x000000f9},
+	{0x00009acc, 0x000000f9, 0x000000f9},
+	{0x00009ad0, 0x000000f9, 0x000000f9},
+	{0x00009ad4, 0x000000f9, 0x000000f9},
+	{0x00009ad8, 0x000000f9, 0x000000f9},
+	{0x00009adc, 0x000000f9, 0x000000f9},
+	{0x00009ae0, 0x000000f9, 0x000000f9},
+	{0x00009ae4, 0x000000f9, 0x000000f9},
+	{0x00009ae8, 0x000000f9, 0x000000f9},
+	{0x00009aec, 0x000000f9, 0x000000f9},
+	{0x00009af0, 0x000000f9, 0x000000f9},
+	{0x00009af4, 0x000000f9, 0x000000f9},
+	{0x00009af8, 0x000000f9, 0x000000f9},
+	{0x00009afc, 0x000000f9, 0x000000f9},
 };
 
 static const u32 ar5416Bank1_9160[][2] = {
-    { 0x000098b0, 0x02108421 },
-    { 0x000098ec, 0x00000008 },
+	/* Addr      allmodes  */
+	{0x000098b0, 0x02108421},
+	{0x000098ec, 0x00000008},
 };
 
 static const u32 ar5416Bank2_9160[][2] = {
-    { 0x000098b0, 0x0e73ff17 },
-    { 0x000098e0, 0x00000420 },
+	/* Addr      allmodes  */
+	{0x000098b0, 0x0e73ff17},
+	{0x000098e0, 0x00000420},
 };
 
 static const u32 ar5416Bank3_9160[][3] = {
-    { 0x000098f0, 0x01400018, 0x01c00018 },
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x000098f0, 0x01400018, 0x01c00018},
 };
 
 static const u32 ar5416Bank6_9160[][3] = {
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00e00000, 0x00e00000 },
-    { 0x0000989c, 0x005e0000, 0x005e0000 },
-    { 0x0000989c, 0x00120000, 0x00120000 },
-    { 0x0000989c, 0x00620000, 0x00620000 },
-    { 0x0000989c, 0x00020000, 0x00020000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
-    { 0x0000989c, 0x005f0000, 0x005f0000 },
-    { 0x0000989c, 0x00870000, 0x00870000 },
-    { 0x0000989c, 0x00f90000, 0x00f90000 },
-    { 0x0000989c, 0x007b0000, 0x007b0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00f50000, 0x00f50000 },
-    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
-    { 0x0000989c, 0x00110000, 0x00110000 },
-    { 0x0000989c, 0x006100a8, 0x006100a8 },
-    { 0x0000989c, 0x004210a2, 0x004210a2 },
-    { 0x0000989c, 0x0014008f, 0x0014008f },
-    { 0x0000989c, 0x00c40003, 0x00c40003 },
-    { 0x0000989c, 0x003000f2, 0x003000f2 },
-    { 0x0000989c, 0x00440016, 0x00440016 },
-    { 0x0000989c, 0x00410040, 0x00410040 },
-    { 0x0000989c, 0x0001805e, 0x0001805e },
-    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
-    { 0x0000989c, 0x000000f1, 0x000000f1 },
-    { 0x0000989c, 0x00002081, 0x00002081 },
-    { 0x0000989c, 0x000000d4, 0x000000d4 },
-    { 0x000098d0, 0x0000000f, 0x0010000f },
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00e00000, 0x00e00000},
+	{0x0000989c, 0x005e0000, 0x005e0000},
+	{0x0000989c, 0x00120000, 0x00120000},
+	{0x0000989c, 0x00620000, 0x00620000},
+	{0x0000989c, 0x00020000, 0x00020000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x40ff0000, 0x40ff0000},
+	{0x0000989c, 0x005f0000, 0x005f0000},
+	{0x0000989c, 0x00870000, 0x00870000},
+	{0x0000989c, 0x00f90000, 0x00f90000},
+	{0x0000989c, 0x007b0000, 0x007b0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00f50000, 0x00f50000},
+	{0x0000989c, 0x00dc0000, 0x00dc0000},
+	{0x0000989c, 0x00110000, 0x00110000},
+	{0x0000989c, 0x006100a8, 0x006100a8},
+	{0x0000989c, 0x004210a2, 0x004210a2},
+	{0x0000989c, 0x0014008f, 0x0014008f},
+	{0x0000989c, 0x00c40003, 0x00c40003},
+	{0x0000989c, 0x003000f2, 0x003000f2},
+	{0x0000989c, 0x00440016, 0x00440016},
+	{0x0000989c, 0x00410040, 0x00410040},
+	{0x0000989c, 0x0001805e, 0x0001805e},
+	{0x0000989c, 0x0000c0ab, 0x0000c0ab},
+	{0x0000989c, 0x000000f1, 0x000000f1},
+	{0x0000989c, 0x00002081, 0x00002081},
+	{0x0000989c, 0x000000d4, 0x000000d4},
+	{0x000098d0, 0x0000000f, 0x0010000f},
 };
 
 static const u32 ar5416Bank6TPC_9160[][3] = {
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00e00000, 0x00e00000 },
-    { 0x0000989c, 0x005e0000, 0x005e0000 },
-    { 0x0000989c, 0x00120000, 0x00120000 },
-    { 0x0000989c, 0x00620000, 0x00620000 },
-    { 0x0000989c, 0x00020000, 0x00020000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
-    { 0x0000989c, 0x005f0000, 0x005f0000 },
-    { 0x0000989c, 0x00870000, 0x00870000 },
-    { 0x0000989c, 0x00f90000, 0x00f90000 },
-    { 0x0000989c, 0x007b0000, 0x007b0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00f50000, 0x00f50000 },
-    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
-    { 0x0000989c, 0x00110000, 0x00110000 },
-    { 0x0000989c, 0x006100a8, 0x006100a8 },
-    { 0x0000989c, 0x00423022, 0x00423022 },
-    { 0x0000989c, 0x2014008f, 0x2014008f },
-    { 0x0000989c, 0x00c40002, 0x00c40002 },
-    { 0x0000989c, 0x003000f2, 0x003000f2 },
-    { 0x0000989c, 0x00440016, 0x00440016 },
-    { 0x0000989c, 0x00410040, 0x00410040 },
-    { 0x0000989c, 0x0001805e, 0x0001805e },
-    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
-    { 0x0000989c, 0x000000e1, 0x000000e1 },
-    { 0x0000989c, 0x00007080, 0x00007080 },
-    { 0x0000989c, 0x000000d4, 0x000000d4 },
-    { 0x000098d0, 0x0000000f, 0x0010000f },
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00e00000, 0x00e00000},
+	{0x0000989c, 0x005e0000, 0x005e0000},
+	{0x0000989c, 0x00120000, 0x00120000},
+	{0x0000989c, 0x00620000, 0x00620000},
+	{0x0000989c, 0x00020000, 0x00020000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x40ff0000, 0x40ff0000},
+	{0x0000989c, 0x005f0000, 0x005f0000},
+	{0x0000989c, 0x00870000, 0x00870000},
+	{0x0000989c, 0x00f90000, 0x00f90000},
+	{0x0000989c, 0x007b0000, 0x007b0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00f50000, 0x00f50000},
+	{0x0000989c, 0x00dc0000, 0x00dc0000},
+	{0x0000989c, 0x00110000, 0x00110000},
+	{0x0000989c, 0x006100a8, 0x006100a8},
+	{0x0000989c, 0x00423022, 0x00423022},
+	{0x0000989c, 0x2014008f, 0x2014008f},
+	{0x0000989c, 0x00c40002, 0x00c40002},
+	{0x0000989c, 0x003000f2, 0x003000f2},
+	{0x0000989c, 0x00440016, 0x00440016},
+	{0x0000989c, 0x00410040, 0x00410040},
+	{0x0000989c, 0x0001805e, 0x0001805e},
+	{0x0000989c, 0x0000c0ab, 0x0000c0ab},
+	{0x0000989c, 0x000000e1, 0x000000e1},
+	{0x0000989c, 0x00007080, 0x00007080},
+	{0x0000989c, 0x000000d4, 0x000000d4},
+	{0x000098d0, 0x0000000f, 0x0010000f},
 };
 
 static const u32 ar5416Bank7_9160[][2] = {
-    { 0x0000989c, 0x00000500 },
-    { 0x0000989c, 0x00000800 },
-    { 0x000098cc, 0x0000000e },
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000500},
+	{0x0000989c, 0x00000800},
+	{0x000098cc, 0x0000000e},
 };
 
 static const u32 ar5416Addac_9160[][2] = {
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x000000c0 },
-    {0x0000989c,  0x00000018 },
-    {0x0000989c,  0x00000004 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x000000c0 },
-    {0x0000989c,  0x00000019 },
-    {0x0000989c,  0x00000004 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000004 },
-    {0x0000989c,  0x00000003 },
-    {0x0000989c,  0x00000008 },
-    {0x0000989c,  0x00000000 },
-    {0x000098cc,  0x00000000 },
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x000000c0},
+	{0x0000989c, 0x00000018},
+	{0x0000989c, 0x00000004},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x000000c0},
+	{0x0000989c, 0x00000019},
+	{0x0000989c, 0x00000004},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000004},
+	{0x0000989c, 0x00000003},
+	{0x0000989c, 0x00000008},
+	{0x0000989c, 0x00000000},
+	{0x000098cc, 0x00000000},
 };
 
-static const u32 ar5416Addac_91601_1[][2] = {
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x000000c0 },
-    {0x0000989c,  0x00000018 },
-    {0x0000989c,  0x00000004 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x000000c0 },
-    {0x0000989c,  0x00000019 },
-    {0x0000989c,  0x00000004 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x000098cc,  0x00000000 },
+static const u32 ar5416Addac_9160_1_1[][2] = {
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x000000c0},
+	{0x0000989c, 0x00000018},
+	{0x0000989c, 0x00000004},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x000000c0},
+	{0x0000989c, 0x00000019},
+	{0x0000989c, 0x00000004},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x000098cc, 0x00000000},
 };
 
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index 5fdbb53..dabafb8 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -239,7 +239,7 @@
 			if (qCoff > 15)
 				qCoff = 15;
 			else if (qCoff <= -16)
-				qCoff = 16;
+				qCoff = -16;
 
 			ath_print(common, ATH_DBG_CALIBRATE,
 				  "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index a8a8cdc..303c63d 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -18,6 +18,11 @@
 #include "ar5008_initvals.h"
 #include "ar9001_initvals.h"
 #include "ar9002_initvals.h"
+#include "ar9002_phy.h"
+
+int modparam_force_new_ani;
+module_param_named(force_new_ani, modparam_force_new_ani, int, 0444);
+MODULE_PARM_DESC(nohwcrypt, "Force new ANI for AR5008, AR9001, AR9002");
 
 /* General hardware code for the A5008/AR9001/AR9002 hadware families */
 
@@ -80,21 +85,6 @@
 			ar9287PciePhy_clkreq_always_on_L1_9287_1_1,
 			ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1),
 					2);
-	} else if (AR_SREV_9287_10_OR_LATER(ah)) {
-		INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_0,
-				ARRAY_SIZE(ar9287Modes_9287_1_0), 6);
-		INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_0,
-				ARRAY_SIZE(ar9287Common_9287_1_0), 2);
-
-		if (ah->config.pcie_clock_req)
-			INIT_INI_ARRAY(&ah->iniPcieSerdes,
-			ar9287PciePhy_clkreq_off_L1_9287_1_0,
-			ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_0), 2);
-		else
-			INIT_INI_ARRAY(&ah->iniPcieSerdes,
-			ar9287PciePhy_clkreq_always_on_L1_9287_1_0,
-			ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_0),
-				  2);
 	} else if (AR_SREV_9285_12_OR_LATER(ah)) {
 
 
@@ -113,21 +103,6 @@
 			ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
 				  2);
 		}
-	} else if (AR_SREV_9285_10_OR_LATER(ah)) {
-		INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285,
-			       ARRAY_SIZE(ar9285Modes_9285), 6);
-		INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285,
-			       ARRAY_SIZE(ar9285Common_9285), 2);
-
-		if (ah->config.pcie_clock_req) {
-			INIT_INI_ARRAY(&ah->iniPcieSerdes,
-			ar9285PciePhy_clkreq_off_L1_9285,
-			ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2);
-		} else {
-			INIT_INI_ARRAY(&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(&ah->iniModes, ar9280Modes_9280_2,
 			       ARRAY_SIZE(ar9280Modes_9280_2), 6);
@@ -146,11 +121,6 @@
 		INIT_INI_ARRAY(&ah->iniModesAdditional,
 			       ar9280Modes_fast_clock_9280_2,
 			       ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
-	} else if (AR_SREV_9280_10_OR_LATER(ah)) {
-		INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280,
-			       ARRAY_SIZE(ar9280Modes_9280), 6);
-		INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280,
-			       ARRAY_SIZE(ar9280Common_9280), 2);
 	} else if (AR_SREV_9160_10_OR_LATER(ah)) {
 		INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160,
 			       ARRAY_SIZE(ar5416Modes_9160), 6);
@@ -174,8 +144,8 @@
 			       ARRAY_SIZE(ar5416Bank7_9160), 2);
 		if (AR_SREV_9160_11(ah)) {
 			INIT_INI_ARRAY(&ah->iniAddac,
-				       ar5416Addac_91601_1,
-				       ARRAY_SIZE(ar5416Addac_91601_1), 2);
+				       ar5416Addac_9160_1_1,
+				       ARRAY_SIZE(ar5416Addac_9160_1_1), 2);
 		} else {
 			INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160,
 				       ARRAY_SIZE(ar5416Addac_9160), 2);
@@ -234,12 +204,12 @@
 {
 	if (AR_SREV_9287_11_OR_LATER(ah)) {
 		INIT_INI_ARRAY(&ah->iniCckfirNormal,
-		       ar9287Common_normal_cck_fir_coeff_92871_1,
-		       ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_92871_1),
+		       ar9287Common_normal_cck_fir_coeff_9287_1_1,
+		       ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_9287_1_1),
 		       2);
 		INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
-		       ar9287Common_japan_2484_cck_fir_coeff_92871_1,
-		       ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_92871_1),
+		       ar9287Common_japan_2484_cck_fir_coeff_9287_1_1,
+		       ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_9287_1_1),
 		       2);
 	}
 }
@@ -300,10 +270,6 @@
 		INIT_INI_ARRAY(&ah->iniModesRxGain,
 		ar9287Modes_rx_gain_9287_1_1,
 		ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6);
-	else if (AR_SREV_9287_10(ah))
-		INIT_INI_ARRAY(&ah->iniModesRxGain,
-		ar9287Modes_rx_gain_9287_1_0,
-		ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_0), 6);
 	else if (AR_SREV_9280_20(ah))
 		ar9280_20_hw_init_rxgain_ini(ah);
 
@@ -311,10 +277,6 @@
 		INIT_INI_ARRAY(&ah->iniModesTxGain,
 		ar9287Modes_tx_gain_9287_1_1,
 		ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6);
-	} else if (AR_SREV_9287_10(ah)) {
-		INIT_INI_ARRAY(&ah->iniModesTxGain,
-		ar9287Modes_tx_gain_9287_1_0,
-		ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_0), 6);
 	} else if (AR_SREV_9280_20(ah)) {
 		ar9280_20_hw_init_txgain_ini(ah);
 	} else if (AR_SREV_9285_12_OR_LATER(ah)) {
@@ -384,29 +346,6 @@
 				REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
 					  INI_RA(&ah->iniPcieSerdes, i, 1));
 			}
-		} else if (AR_SREV_9280(ah) &&
-			   (ah->hw_version.macRev == AR_SREV_REVISION_9280_10)) {
-			REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
-			REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
-
-			/* RX shut off when elecidle is asserted */
-			REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
-			REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
-			REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
-
-			/* Shut off CLKREQ active in L1 */
-			if (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);
-
-			/* Load the new settings */
-			REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-
 		} else {
 			ENABLE_REGWRITE_BUFFER(ah);
 
@@ -436,55 +375,84 @@
 		}
 
 		udelay(1000);
+	}
 
-		/* set bit 19 to allow forcing of pcie core into L1 state */
-		REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+	if (power_off) {
+		/* clear bit 19 to disable L1 */
+		REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
 
-		/* Several PCIe massages to ensure proper behaviour */
+		val = REG_READ(ah, AR_WA);
+
+		/*
+		 * Set PCIe workaround bits
+		 * In AR9280 and AR9285, bit 14 in WA register (disable L1)
+		 * should only  be set when device enters D3 and be
+		 * cleared when device comes back to D0.
+		 */
+		if (ah->config.pcie_waen) {
+			if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
+				val |= AR_WA_D3_L1_DISABLE;
+		} else {
+			if (((AR_SREV_9285(ah) ||
+			      AR_SREV_9271(ah) ||
+			      AR_SREV_9287(ah)) &&
+			     (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) ||
+			    (AR_SREV_9280(ah) &&
+			     (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) {
+				val |= AR_WA_D3_L1_DISABLE;
+			}
+		}
+
+		if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
+			/*
+			 * Disable bit 6 and 7 before entering D3 to
+			 * prevent system hang.
+			 */
+			val &= ~(AR_WA_BIT6 | AR_WA_BIT7);
+		}
+
+		if (AR_SREV_9285E_20(ah))
+			val |= AR_WA_BIT23;
+
+		REG_WRITE(ah, AR_WA, val);
+	} else {
 		if (ah->config.pcie_waen) {
 			val = ah->config.pcie_waen;
 			if (!power_off)
 				val &= (~AR_WA_D3_L1_DISABLE);
 		} else {
-			if (AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
+			if (AR_SREV_9285(ah) ||
+			    AR_SREV_9271(ah) ||
 			    AR_SREV_9287(ah)) {
 				val = AR9285_WA_DEFAULT;
 				if (!power_off)
 					val &= (~AR_WA_D3_L1_DISABLE);
-			} else if (AR_SREV_9280(ah)) {
+			}
+			else if (AR_SREV_9280(ah)) {
 				/*
-				 * On AR9280 chips bit 22 of 0x4004 needs to be
-				 * set otherwise card may disappear.
+				 * For AR9280 chips, bit 22 of 0x4004
+				 * needs to be set.
 				 */
 				val = AR9280_WA_DEFAULT;
 				if (!power_off)
 					val &= (~AR_WA_D3_L1_DISABLE);
-			} else
+			} else {
 				val = AR_WA_DEFAULT;
-		}
-
-		REG_WRITE(ah, AR_WA, val);
-	}
-
-	if (power_off) {
-		/*
-		 * Set PCIe workaround bits
-		 * bit 14 in WA register (disable L1) should only
-		 * be set when device enters D3 and be cleared
-		 * when device comes back to D0.
-		 */
-		if (ah->config.pcie_waen) {
-			if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
-				REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
-		} else {
-			if (((AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
-			      AR_SREV_9287(ah)) &&
-			     (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) ||
-			    (AR_SREV_9280(ah) &&
-			     (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) {
-				REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
 			}
 		}
+
+		/* WAR for ASPM system hang */
+		if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
+			val |= (AR_WA_BIT6 | AR_WA_BIT7);
+		}
+
+		if (AR_SREV_9285E_20(ah))
+			val |= AR_WA_BIT23;
+
+		REG_WRITE(ah, AR_WA, val);
+
+		/* set bit 19 to allow forcing of pcie core into L1 state */
+		REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
 	}
 }
 
@@ -536,18 +504,29 @@
 	return 0;
 }
 
+void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
+{
+	if (AR_SREV_9287_13_OR_LATER(ah)) {
+		REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+				AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
+		REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
+		REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+				AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+		REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+				AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+	}
+}
+
 /*
- * Enable ASYNC FIFO
- *
  * If Async FIFO is enabled, the following counters change as MAC now runs
  * at 117 Mhz instead of 88/44MHz when async FIFO is disabled.
  *
  * The values below tested for ht40 2 chain.
  * Overwrite the delay/timeouts initialized in process ini.
  */
-void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
+void ar9002_hw_update_async_fifo(struct ath_hw *ah)
 {
-	if (AR_SREV_9287_12_OR_LATER(ah)) {
+	if (AR_SREV_9287_13_OR_LATER(ah)) {
 		REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
 			  AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
 		REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
@@ -571,9 +550,9 @@
  */
 void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah)
 {
-	if (AR_SREV_9287_12_OR_LATER(ah)) {
+	if (AR_SREV_9287_13_OR_LATER(ah)) {
 		REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
-				AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
+			    AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
 	}
 }
 
@@ -595,4 +574,9 @@
 
 	ar9002_hw_attach_calib_ops(ah);
 	ar9002_hw_attach_mac_ops(ah);
+
+	if (modparam_force_new_ani)
+		ath9k_hw_attach_ani_ops_new(ah);
+	else
+		ath9k_hw_attach_ani_ops_old(ah);
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
index dae7f33..6203eed 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
@@ -14,5217 +14,3252 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#ifndef INITVALS_9002_10_H
-#define INITVALS_9002_10_H
-
-static const u32 ar9280Modes_9280[][6] = {
-    { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
-    { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
-    { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
-    { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
-    { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801080, 0x08400840, 0x06e006e0 },
-    { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f },
-    { 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 },
-    { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 },
-    { 0x00009848, 0x00028566, 0x00028566, 0x00028563, 0x00028563, 0x00028563 },
-    { 0x0000a848, 0x00028566, 0x00028566, 0x00028563, 0x00028563, 0x00028563 },
-    { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
-    { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
-    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
-    { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d20, 0x00049d20, 0x00049d18 },
-    { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
-    { 0x00009868, 0x5ac64190, 0x5ac64190, 0x5ac64190, 0x5ac64190, 0x5ac64190 },
-    { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
-    { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
-    { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
-    { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
-    { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 },
-    { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
-    { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
-    { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 },
-    { 0x0000c9b8, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a },
-    { 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
-    { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
-    { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
-    { 0x000099c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c },
-    { 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, 0x00008184, 0x00008184, 0x00000214, 0x00000214, 0x00000214 },
-    { 0x00009a04, 0x00008188, 0x00008188, 0x00000218, 0x00000218, 0x00000218 },
-    { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000224, 0x00000224, 0x00000224 },
-    { 0x00009a0c, 0x00008190, 0x00008190, 0x00000228, 0x00000228, 0x00000228 },
-    { 0x00009a10, 0x00008194, 0x00008194, 0x0000022c, 0x0000022c, 0x0000022c },
-    { 0x00009a14, 0x00008200, 0x00008200, 0x00000230, 0x00000230, 0x00000230 },
-    { 0x00009a18, 0x00008204, 0x00008204, 0x000002a4, 0x000002a4, 0x000002a4 },
-    { 0x00009a1c, 0x00008208, 0x00008208, 0x000002a8, 0x000002a8, 0x000002a8 },
-    { 0x00009a20, 0x0000820c, 0x0000820c, 0x000002ac, 0x000002ac, 0x000002ac },
-    { 0x00009a24, 0x00008210, 0x00008210, 0x000002b0, 0x000002b0, 0x000002b0 },
-    { 0x00009a28, 0x00008214, 0x00008214, 0x000002b4, 0x000002b4, 0x000002b4 },
-    { 0x00009a2c, 0x00008280, 0x00008280, 0x000002b8, 0x000002b8, 0x000002b8 },
-    { 0x00009a30, 0x00008284, 0x00008284, 0x00000390, 0x00000390, 0x00000390 },
-    { 0x00009a34, 0x00008288, 0x00008288, 0x00000394, 0x00000394, 0x00000394 },
-    { 0x00009a38, 0x0000828c, 0x0000828c, 0x00000398, 0x00000398, 0x00000398 },
-    { 0x00009a3c, 0x00008290, 0x00008290, 0x00000334, 0x00000334, 0x00000334 },
-    { 0x00009a40, 0x00008300, 0x00008300, 0x00000338, 0x00000338, 0x00000338 },
-    { 0x00009a44, 0x00008304, 0x00008304, 0x000003ac, 0x000003ac, 0x000003ac },
-    { 0x00009a48, 0x00008308, 0x00008308, 0x000003b0, 0x000003b0, 0x000003b0 },
-    { 0x00009a4c, 0x0000830c, 0x0000830c, 0x000003b4, 0x000003b4, 0x000003b4 },
-    { 0x00009a50, 0x00008310, 0x00008310, 0x000003b8, 0x000003b8, 0x000003b8 },
-    { 0x00009a54, 0x00008314, 0x00008314, 0x000003a5, 0x000003a5, 0x000003a5 },
-    { 0x00009a58, 0x00008380, 0x00008380, 0x000003a9, 0x000003a9, 0x000003a9 },
-    { 0x00009a5c, 0x00008384, 0x00008384, 0x000003ad, 0x000003ad, 0x000003ad },
-    { 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, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019 },
-    { 0x0000b20c, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019 },
-    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
-    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 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 },
-    { 0x0000784c, 0x0e4f048c, 0x0e4f048c, 0x0e4d048c, 0x0e4d048c, 0x0e4d048c },
-    { 0x00007854, 0x12031828, 0x12031828, 0x12035828, 0x12035828, 0x12035828 },
-    { 0x00007870, 0x807ec400, 0x807ec400, 0x807ec000, 0x807ec000, 0x807ec000 },
-    { 0x0000788c, 0x00010000, 0x00010000, 0x00110000, 0x00110000, 0x00110000 },
-};
-
-static const u32 ar9280Common_9280[][2] = {
-    { 0x0000000c, 0x00000000 },
-    { 0x00000030, 0x00020015 },
-    { 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 },
-    { 0x00007010, 0x00000033 },
-    { 0x00007038, 0x000004c2 },
-    { 0x00008004, 0x00000000 },
-    { 0x00008008, 0x00000000 },
-    { 0x0000800c, 0x00000000 },
-    { 0x00008018, 0x00000700 },
-    { 0x00008020, 0x00000000 },
-    { 0x00008038, 0x00000000 },
-    { 0x0000803c, 0x00000000 },
-    { 0x00008048, 0x40000000 },
-    { 0x00008054, 0x00000000 },
-    { 0x00008058, 0x00000000 },
-    { 0x0000805c, 0x000fc78f },
-    { 0x00008060, 0x0000000f },
-    { 0x00008064, 0x00000000 },
-    { 0x00008070, 0x00000000 },
-    { 0x000080c0, 0x2a82301a },
-    { 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 },
-    { 0x000081c4, 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 },
-    { 0x00008270, 0x00000000 },
-    { 0x00008274, 0x40000000 },
-    { 0x00008278, 0x003e4180 },
-    { 0x0000827c, 0x00000000 },
-    { 0x00008284, 0x0000002c },
-    { 0x00008288, 0x0000002c },
-    { 0x0000828c, 0x00000000 },
-    { 0x00008294, 0x00000000 },
-    { 0x00008298, 0x00000000 },
-    { 0x00008300, 0x00000000 },
-    { 0x00008304, 0x00000000 },
-    { 0x00008308, 0x00000000 },
-    { 0x0000830c, 0x00000000 },
-    { 0x00008310, 0x00000000 },
-    { 0x00008314, 0x00000000 },
-    { 0x00008318, 0x00000000 },
-    { 0x00008328, 0x00000000 },
-    { 0x0000832c, 0x00000007 },
-    { 0x00008330, 0x00000302 },
-    { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00000000 },
-    { 0x0000833c, 0x00000000 },
-    { 0x00008340, 0x000107ff },
-    { 0x00008344, 0x00000000 },
-    { 0x00009808, 0x00000000 },
-    { 0x0000980c, 0xaf268e30 },
-    { 0x00009810, 0xfd14e000 },
-    { 0x00009814, 0x9c0a9f6b },
-    { 0x0000981c, 0x00000000 },
-    { 0x0000982c, 0x0000a000 },
-    { 0x00009830, 0x00000000 },
-    { 0x0000983c, 0x00200400 },
-    { 0x00009840, 0x206a01ae },
-    { 0x0000984c, 0x0040233c },
-    { 0x0000a84c, 0x0040233c },
-    { 0x00009854, 0x00000044 },
-    { 0x00009900, 0x00000000 },
-    { 0x00009904, 0x00000000 },
-    { 0x00009908, 0x00000000 },
-    { 0x0000990c, 0x00000000 },
-    { 0x0000991c, 0x10000fff },
-    { 0x00009920, 0x04900000 },
-    { 0x0000a920, 0x04900000 },
-    { 0x00009928, 0x00000001 },
-    { 0x0000992c, 0x00000004 },
-    { 0x00009934, 0x1e1f2022 },
-    { 0x00009938, 0x0a0b0c0d },
-    { 0x0000993c, 0x00000000 },
-    { 0x00009948, 0x9280c00a },
-    { 0x0000994c, 0x00020028 },
-    { 0x00009954, 0xe250a51e },
-    { 0x00009958, 0x3388ffff },
-    { 0x00009940, 0x00781204 },
-    { 0x0000c95c, 0x004b6a8e },
-    { 0x0000c968, 0x000003ce },
-    { 0x00009970, 0x190fb514 },
-    { 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, 0x006f00c4 },
-    { 0x000099b0, 0x03051000 },
-    { 0x000099b4, 0x00000820 },
-    { 0x000099dc, 0x00000000 },
-    { 0x000099e0, 0x00000000 },
-    { 0x000099e4, 0xaaaaaaaa },
-    { 0x000099e8, 0x3c466478 },
-    { 0x000099ec, 0x0cc80caa },
-    { 0x000099fc, 0x00001042 },
-    { 0x0000a210, 0x4080a333 },
-    { 0x0000a214, 0x40206c10 },
-    { 0x0000a218, 0x009c4060 },
-    { 0x0000a220, 0x01834061 },
-    { 0x0000a224, 0x00000400 },
-    { 0x0000a228, 0x000003b5 },
-    { 0x0000a22c, 0x23277200 },
-    { 0x0000a234, 0x20202020 },
-    { 0x0000a238, 0x20202020 },
-    { 0x0000a23c, 0x13c889af },
-    { 0x0000a240, 0x38490a20 },
-    { 0x0000a244, 0x00007bb6 },
-    { 0x0000a248, 0x0fff3ffc },
-    { 0x0000a24c, 0x00000001 },
-    { 0x0000a250, 0x001da000 },
-    { 0x0000a254, 0x00000000 },
-    { 0x0000a258, 0x0cdbd380 },
-    { 0x0000a25c, 0x0f0f0f01 },
-    { 0x0000a260, 0xdfa91f01 },
-    { 0x0000a268, 0x00000000 },
-    { 0x0000a26c, 0x0ebae9c6 },
-    { 0x0000b26c, 0x0ebae9c6 },
-    { 0x0000d270, 0x00820820 },
-    { 0x0000a278, 0x1ce739ce },
-    { 0x0000a27c, 0x050701ce },
-    { 0x0000a358, 0x7999aa0f },
-    { 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, 0x1ce739ce },
-    { 0x0000a398, 0x000001ce },
-    { 0x0000a39c, 0x00000001 },
-    { 0x0000a3a0, 0x00000000 },
-    { 0x0000a3a4, 0x00000000 },
-    { 0x0000a3a8, 0x00000000 },
-    { 0x0000a3ac, 0x00000000 },
-    { 0x0000a3b0, 0x00000000 },
-    { 0x0000a3b4, 0x00000000 },
-    { 0x0000a3b8, 0x00000000 },
-    { 0x0000a3bc, 0x00000000 },
-    { 0x0000a3c0, 0x00000000 },
-    { 0x0000a3c4, 0x00000000 },
-    { 0x0000a3c8, 0x00000246 },
-    { 0x0000a3cc, 0x20202020 },
-    { 0x0000a3d0, 0x20202020 },
-    { 0x0000a3d4, 0x20202020 },
-    { 0x0000a3dc, 0x1ce739ce },
-    { 0x0000a3e0, 0x000001ce },
-    { 0x0000a3e4, 0x00000000 },
-    { 0x0000a3e8, 0x18c43433 },
-    { 0x0000a3ec, 0x00f38081 },
-    { 0x00007800, 0x00040000 },
-    { 0x00007804, 0xdb005012 },
-    { 0x00007808, 0x04924914 },
-    { 0x0000780c, 0x21084210 },
-    { 0x00007810, 0x6d801300 },
-    { 0x00007814, 0x0019beff },
-    { 0x00007818, 0x07e40000 },
-    { 0x0000781c, 0x00492000 },
-    { 0x00007820, 0x92492480 },
-    { 0x00007824, 0x00040000 },
-    { 0x00007828, 0xdb005012 },
-    { 0x0000782c, 0x04924914 },
-    { 0x00007830, 0x21084210 },
-    { 0x00007834, 0x6d801300 },
-    { 0x00007838, 0x0019beff },
-    { 0x0000783c, 0x07e40000 },
-    { 0x00007840, 0x00492000 },
-    { 0x00007844, 0x92492480 },
-    { 0x00007848, 0x00120000 },
-    { 0x00007850, 0x54214514 },
-    { 0x00007858, 0x92592692 },
-    { 0x00007860, 0x52802000 },
-    { 0x00007864, 0x0a8e370e },
-    { 0x00007868, 0xc0102850 },
-    { 0x0000786c, 0x812d4000 },
-    { 0x00007874, 0x001b6db0 },
-    { 0x00007878, 0x00376b63 },
-    { 0x0000787c, 0x06db6db6 },
-    { 0x00007880, 0x006d8000 },
-    { 0x00007884, 0xffeffffe },
-    { 0x00007888, 0xffeffffe },
-    { 0x00007890, 0x00060aeb },
-    { 0x00007894, 0x5a108000 },
-    { 0x00007898, 0x2a850160 },
-};
-
-/* XXX 9280 2 */
 static const u32 ar9280Modes_9280_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 },
-    { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
-    { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a },
-    { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
-    { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
-    { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
-    { 0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e },
-    { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
-    { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
-    { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
-    { 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e },
-    { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
-    { 0x00009850, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
-    { 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
-    { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e },
-    { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
-    { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
-    { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
-    { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
-    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
-    { 0x00009918, 0x0000000a, 0x00000014, 0x00000268, 0x0000000b, 0x00000016 },
-    { 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 },
-    { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce },
-    { 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 },
-    { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
-    { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
-    { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 },
-    { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
-    { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
-    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
-    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 0x0000a23c, 0x13c88000, 0x13c88000, 0x13c88001, 0x13c88000, 0x13c88000 },
-    { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 },
-    { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
-    { 0x0000a388, 0x0c000000, 0x0c000000, 0x08000000, 0x0c000000, 0x0c000000 },
-    { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 },
+	{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},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
+	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880},
+	{0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
+	{0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+	{0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+	{0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+	{0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+	{0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e},
+	{0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0},
+	{0x00009850, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2},
+	{0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+	{0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+	{0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18},
+	{0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+	{0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881},
+	{0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+	{0x00009918, 0x0000000a, 0x00000014, 0x00000268, 0x0000000b, 0x00000016},
+	{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},
+	{0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce},
+	{0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c},
+	{0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00},
+	{0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+	{0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444},
+	{0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019},
+	{0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019},
+	{0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a23c, 0x13c88000, 0x13c88000, 0x13c88001, 0x13c88000, 0x13c88000},
+	{0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000},
+	{0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
+	{0x0000a388, 0x0c000000, 0x0c000000, 0x08000000, 0x0c000000, 0x0c000000},
+	{0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000},
 };
 
 static const u32 ar9280Common_9280_2[][2] = {
-    { 0x0000000c, 0x00000000 },
-    { 0x00000030, 0x00020015 },
-    { 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, 0x00000033 },
-    { 0x00007034, 0x00000002 },
-    { 0x00007038, 0x000004c2 },
-    { 0x00008004, 0x00000000 },
-    { 0x00008008, 0x00000000 },
-    { 0x0000800c, 0x00000000 },
-    { 0x00008018, 0x00000700 },
-    { 0x00008020, 0x00000000 },
-    { 0x00008038, 0x00000000 },
-    { 0x0000803c, 0x00000000 },
-    { 0x00008048, 0x40000000 },
-    { 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 },
-    { 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 },
-    { 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, 0x88a00010 },
-    { 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, 0x00000007 },
-    { 0x00008330, 0x00000302 },
-    { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00ff0000 },
-    { 0x0000833c, 0x00000000 },
-    { 0x00008340, 0x000107ff },
-    { 0x00008344, 0x00481043 },
-    { 0x00009808, 0x00000000 },
-    { 0x0000980c, 0xafa68e30 },
-    { 0x00009810, 0xfd14e000 },
-    { 0x00009814, 0x9c0a9f6b },
-    { 0x0000981c, 0x00000000 },
-    { 0x0000982c, 0x0000a000 },
-    { 0x00009830, 0x00000000 },
-    { 0x0000983c, 0x00200400 },
-    { 0x0000984c, 0x0040233c },
-    { 0x0000a84c, 0x0040233c },
-    { 0x00009854, 0x00000044 },
-    { 0x00009900, 0x00000000 },
-    { 0x00009904, 0x00000000 },
-    { 0x00009908, 0x00000000 },
-    { 0x0000990c, 0x00000000 },
-    { 0x00009910, 0x01002310 },
-    { 0x0000991c, 0x10000fff },
-    { 0x00009920, 0x04900000 },
-    { 0x0000a920, 0x04900000 },
-    { 0x00009928, 0x00000001 },
-    { 0x0000992c, 0x00000004 },
-    { 0x00009934, 0x1e1f2022 },
-    { 0x00009938, 0x0a0b0c0d },
-    { 0x0000993c, 0x00000000 },
-    { 0x00009948, 0x9280c00a },
-    { 0x0000994c, 0x00020028 },
-    { 0x00009954, 0x5f3ca3de },
-    { 0x00009958, 0x2108ecff },
-    { 0x00009940, 0x14750604 },
-    { 0x0000c95c, 0x004b6a8e },
-    { 0x00009970, 0x190fb515 },
-    { 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, 0x006f0000 },
-    { 0x000099b0, 0x03051000 },
-    { 0x000099b4, 0x00000820 },
-    { 0x000099dc, 0x00000000 },
-    { 0x000099e0, 0x00000000 },
-    { 0x000099e4, 0xaaaaaaaa },
-    { 0x000099e8, 0x3c466478 },
-    { 0x000099ec, 0x0cc80caa },
-    { 0x000099f0, 0x00000000 },
-    { 0x000099fc, 0x00001042 },
-    { 0x0000a208, 0x803e4788 },
-    { 0x0000a210, 0x4080a333 },
-    { 0x0000a214, 0x40206c10 },
-    { 0x0000a218, 0x009c4060 },
-    { 0x0000a220, 0x01834061 },
-    { 0x0000a224, 0x00000400 },
-    { 0x0000a228, 0x000003b5 },
-    { 0x0000a22c, 0x233f7180 },
-    { 0x0000a234, 0x20202020 },
-    { 0x0000a238, 0x20202020 },
-    { 0x0000a240, 0x38490a20 },
-    { 0x0000a244, 0x00007bb6 },
-    { 0x0000a248, 0x0fff3ffc },
-    { 0x0000a24c, 0x00000000 },
-    { 0x0000a254, 0x00000000 },
-    { 0x0000a258, 0x0cdbd380 },
-    { 0x0000a25c, 0x0f0f0f01 },
-    { 0x0000a260, 0xdfa91f01 },
-    { 0x0000a268, 0x00000000 },
-    { 0x0000a26c, 0x0e79e5c6 },
-    { 0x0000b26c, 0x0e79e5c6 },
-    { 0x0000d270, 0x00820820 },
-    { 0x0000a278, 0x1ce739ce },
-    { 0x0000d35c, 0x07ffffef },
-    { 0x0000d360, 0x0fffffe7 },
-    { 0x0000d364, 0x17ffffe5 },
-    { 0x0000d368, 0x1fffffe4 },
-    { 0x0000d36c, 0x37ffffe3 },
-    { 0x0000d370, 0x3fffffe3 },
-    { 0x0000d374, 0x57ffffe3 },
-    { 0x0000d378, 0x5fffffe2 },
-    { 0x0000d37c, 0x7fffffe2 },
-    { 0x0000d380, 0x7f3c7bba },
-    { 0x0000d384, 0xf3307ff0 },
-    { 0x0000a38c, 0x20202020 },
-    { 0x0000a390, 0x20202020 },
-    { 0x0000a394, 0x1ce739ce },
-    { 0x0000a398, 0x000001ce },
-    { 0x0000a39c, 0x00000001 },
-    { 0x0000a3a0, 0x00000000 },
-    { 0x0000a3a4, 0x00000000 },
-    { 0x0000a3a8, 0x00000000 },
-    { 0x0000a3ac, 0x00000000 },
-    { 0x0000a3b0, 0x00000000 },
-    { 0x0000a3b4, 0x00000000 },
-    { 0x0000a3b8, 0x00000000 },
-    { 0x0000a3bc, 0x00000000 },
-    { 0x0000a3c0, 0x00000000 },
-    { 0x0000a3c4, 0x00000000 },
-    { 0x0000a3c8, 0x00000246 },
-    { 0x0000a3cc, 0x20202020 },
-    { 0x0000a3d0, 0x20202020 },
-    { 0x0000a3d4, 0x20202020 },
-    { 0x0000a3dc, 0x1ce739ce },
-    { 0x0000a3e0, 0x000001ce },
-    { 0x0000a3e4, 0x00000000 },
-    { 0x0000a3e8, 0x18c43433 },
-    { 0x0000a3ec, 0x00f70081 },
-    { 0x00007800, 0x00040000 },
-    { 0x00007804, 0xdb005012 },
-    { 0x00007808, 0x04924914 },
-    { 0x0000780c, 0x21084210 },
-    { 0x00007810, 0x6d801300 },
-    { 0x00007818, 0x07e41000 },
-    { 0x00007824, 0x00040000 },
-    { 0x00007828, 0xdb005012 },
-    { 0x0000782c, 0x04924914 },
-    { 0x00007830, 0x21084210 },
-    { 0x00007834, 0x6d801300 },
-    { 0x0000783c, 0x07e40000 },
-    { 0x00007848, 0x00100000 },
-    { 0x0000784c, 0x773f0567 },
-    { 0x00007850, 0x54214514 },
-    { 0x00007854, 0x12035828 },
-    { 0x00007858, 0x9259269a },
-    { 0x00007860, 0x52802000 },
-    { 0x00007864, 0x0a8e370e },
-    { 0x00007868, 0xc0102850 },
-    { 0x0000786c, 0x812d4000 },
-    { 0x00007870, 0x807ec400 },
-    { 0x00007874, 0x001b6db0 },
-    { 0x00007878, 0x00376b63 },
-    { 0x0000787c, 0x06db6db6 },
-    { 0x00007880, 0x006d8000 },
-    { 0x00007884, 0xffeffffe },
-    { 0x00007888, 0xffeffffe },
-    { 0x0000788c, 0x00010000 },
-    { 0x00007890, 0x02060aeb },
-    { 0x00007898, 0x2a850160 },
+	/* Addr      allmodes  */
+	{0x0000000c, 0x00000000},
+	{0x00000030, 0x00020015},
+	{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, 0x00000033},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000700},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008048, 0x40000000},
+	{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},
+	{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},
+	{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, 0x88a00010},
+	{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, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000e00},
+	{0x00008338, 0x00ff0000},
+	{0x0000833c, 0x00000000},
+	{0x00008340, 0x000107ff},
+	{0x00008344, 0x00481043},
+	{0x00009808, 0x00000000},
+	{0x0000980c, 0xafa68e30},
+	{0x00009810, 0xfd14e000},
+	{0x00009814, 0x9c0a9f6b},
+	{0x0000981c, 0x00000000},
+	{0x0000982c, 0x0000a000},
+	{0x00009830, 0x00000000},
+	{0x0000983c, 0x00200400},
+	{0x0000984c, 0x0040233c},
+	{0x0000a84c, 0x0040233c},
+	{0x00009854, 0x00000044},
+	{0x00009900, 0x00000000},
+	{0x00009904, 0x00000000},
+	{0x00009908, 0x00000000},
+	{0x0000990c, 0x00000000},
+	{0x00009910, 0x01002310},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x04900000},
+	{0x0000a920, 0x04900000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009948, 0x9280c00a},
+	{0x0000994c, 0x00020028},
+	{0x00009954, 0x5f3ca3de},
+	{0x00009958, 0x2108ecff},
+	{0x00009940, 0x14750604},
+	{0x0000c95c, 0x004b6a8e},
+	{0x00009970, 0x190fb514},
+	{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, 0x006f0000},
+	{0x000099b0, 0x03051000},
+	{0x000099b4, 0x00000820},
+	{0x000099c4, 0x06336f77},
+	{0x000099c8, 0x6af6532f},
+	{0x000099cc, 0x08f186c8},
+	{0x000099d0, 0x00046384},
+	{0x000099d4, 0x00000000},
+	{0x000099d8, 0x00000000},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000000},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x0cc80caa},
+	{0x000099f0, 0x00000000},
+	{0x000099fc, 0x00001042},
+	{0x0000a208, 0x803e4788},
+	{0x0000a210, 0x4080a333},
+	{0x0000a214, 0x40206c10},
+	{0x0000a218, 0x009c4060},
+	{0x0000a220, 0x01834061},
+	{0x0000a224, 0x00000400},
+	{0x0000a228, 0x000003b5},
+	{0x0000a22c, 0x233f7180},
+	{0x0000a234, 0x20202020},
+	{0x0000a238, 0x20202020},
+	{0x0000a240, 0x38490a20},
+	{0x0000a244, 0x00007bb6},
+	{0x0000a248, 0x0fff3ffc},
+	{0x0000a24c, 0x00000000},
+	{0x0000a254, 0x00000000},
+	{0x0000a258, 0x0cdbd380},
+	{0x0000a25c, 0x0f0f0f01},
+	{0x0000a260, 0xdfa91f01},
+	{0x0000a268, 0x00000000},
+	{0x0000a26c, 0x0e79e5c6},
+	{0x0000b26c, 0x0e79e5c6},
+	{0x0000d270, 0x00820820},
+	{0x0000a278, 0x1ce739ce},
+	{0x0000d35c, 0x07ffffef},
+	{0x0000d360, 0x0fffffe7},
+	{0x0000d364, 0x17ffffe5},
+	{0x0000d368, 0x1fffffe4},
+	{0x0000d36c, 0x37ffffe3},
+	{0x0000d370, 0x3fffffe3},
+	{0x0000d374, 0x57ffffe3},
+	{0x0000d378, 0x5fffffe2},
+	{0x0000d37c, 0x7fffffe2},
+	{0x0000d380, 0x7f3c7bba},
+	{0x0000d384, 0xf3307ff0},
+	{0x0000a38c, 0x20202020},
+	{0x0000a390, 0x20202020},
+	{0x0000a394, 0x1ce739ce},
+	{0x0000a398, 0x000001ce},
+	{0x0000a39c, 0x00000001},
+	{0x0000a3a0, 0x00000000},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0x00000000},
+	{0x0000a3ac, 0x00000000},
+	{0x0000a3b0, 0x00000000},
+	{0x0000a3b4, 0x00000000},
+	{0x0000a3b8, 0x00000000},
+	{0x0000a3bc, 0x00000000},
+	{0x0000a3c0, 0x00000000},
+	{0x0000a3c4, 0x00000000},
+	{0x0000a3c8, 0x00000246},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3dc, 0x1ce739ce},
+	{0x0000a3e0, 0x000001ce},
+	{0x0000a3e4, 0x00000000},
+	{0x0000a3e8, 0x18c43433},
+	{0x00007800, 0x00040000},
+	{0x00007804, 0xdb005012},
+	{0x00007808, 0x04924914},
+	{0x0000780c, 0x21084210},
+	{0x00007810, 0x6d801300},
+	{0x00007818, 0x07e41000},
+	{0x00007824, 0x00040000},
+	{0x00007828, 0xdb005012},
+	{0x0000782c, 0x04924914},
+	{0x00007830, 0x21084210},
+	{0x00007834, 0x6d801300},
+	{0x0000783c, 0x07e40000},
+	{0x00007848, 0x00100000},
+	{0x0000784c, 0x773f0567},
+	{0x00007850, 0x54214514},
+	{0x00007854, 0x12035828},
+	{0x00007858, 0x9259269a},
+	{0x00007860, 0x52802000},
+	{0x00007864, 0x0a8e370e},
+	{0x00007868, 0xc0102850},
+	{0x0000786c, 0x812d4000},
+	{0x00007870, 0x807ec400},
+	{0x00007874, 0x001b6db0},
+	{0x00007878, 0x00376b63},
+	{0x0000787c, 0x06db6db6},
+	{0x00007880, 0x006d8000},
+	{0x00007884, 0xffeffffe},
+	{0x00007888, 0xffeffffe},
+	{0x0000788c, 0x00010000},
+	{0x00007890, 0x02060aeb},
+	{0x00007898, 0x2a850160},
 };
 
 static const u32 ar9280Modes_fast_clock_9280_2[][3] = {
-    { 0x00001030, 0x00000268, 0x000004d0 },
-    { 0x00001070, 0x0000018c, 0x00000318 },
-    { 0x000010b0, 0x00000fd0, 0x00001fa0 },
-    { 0x00008014, 0x044c044c, 0x08980898 },
-    { 0x0000801c, 0x148ec02b, 0x148ec057 },
-    { 0x00008318, 0x000044c0, 0x00008980 },
-    { 0x00009820, 0x02020200, 0x02020200 },
-    { 0x00009824, 0x01000f0f, 0x01000f0f },
-    { 0x00009828, 0x0b020001, 0x0b020001 },
-    { 0x00009834, 0x00000f0f, 0x00000f0f },
-    { 0x00009844, 0x03721821, 0x03721821 },
-    { 0x00009914, 0x00000898, 0x00001130 },
-    { 0x00009918, 0x0000000b, 0x00000016 },
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x00001030, 0x00000268, 0x000004d0},
+	{0x00001070, 0x0000018c, 0x00000318},
+	{0x000010b0, 0x00000fd0, 0x00001fa0},
+	{0x00008014, 0x044c044c, 0x08980898},
+	{0x0000801c, 0x148ec02b, 0x148ec057},
+	{0x00008318, 0x000044c0, 0x00008980},
+	{0x00009820, 0x02020200, 0x02020200},
+	{0x00009824, 0x01000f0f, 0x01000f0f},
+	{0x00009828, 0x0b020001, 0x0b020001},
+	{0x00009834, 0x00000f0f, 0x00000f0f},
+	{0x00009844, 0x03721821, 0x03721821},
+	{0x00009914, 0x00000898, 0x00001130},
+	{0x00009918, 0x0000000b, 0x00000016},
 };
 
 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 },
+	{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, 0x00008b80, 0x00008b80, 0x00008b80},
+	{0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b84, 0x00008b84, 0x00008b84},
+	{0x00009acc, 0x0000b380, 0x0000b380, 0x00008b88, 0x00008b88, 0x00008b88},
+	{0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b8c, 0x00008b8c, 0x00008b8c},
+	{0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b90, 0x00008b90, 0x00008b90},
+	{0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b94, 0x00008b94, 0x00008b94},
+	{0x00009adc, 0x0000b390, 0x0000b390, 0x00008b98, 0x00008b98, 0x00008b98},
+	{0x00009ae0, 0x0000b394, 0x0000b394, 0x00008ba4, 0x00008ba4, 0x00008ba4},
+	{0x00009ae4, 0x0000b398, 0x0000b398, 0x00008ba8, 0x00008ba8, 0x00008ba8},
+	{0x00009ae8, 0x0000b780, 0x0000b780, 0x00008bac, 0x00008bac, 0x00008bac},
+	{0x00009aec, 0x0000b784, 0x0000b784, 0x00008bb0, 0x00008bb0, 0x00008bb0},
+	{0x00009af0, 0x0000b788, 0x0000b788, 0x00008bb4, 0x00008bb4, 0x00008bb4},
+	{0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008ba1, 0x00008ba1, 0x00008ba1},
+	{0x00009af8, 0x0000b790, 0x0000b790, 0x00008ba5, 0x00008ba5, 0x00008ba5},
+	{0x00009afc, 0x0000b794, 0x0000b794, 0x00008ba9, 0x00008ba9, 0x00008ba9},
+	{0x00009b00, 0x0000b798, 0x0000b798, 0x00008bad, 0x00008bad, 0x00008bad},
+	{0x00009b04, 0x0000d784, 0x0000d784, 0x00008bb1, 0x00008bb1, 0x00008bb1},
+	{0x00009b08, 0x0000d788, 0x0000d788, 0x00008bb5, 0x00008bb5, 0x00008bb5},
+	{0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008ba2, 0x00008ba2, 0x00008ba2},
+	{0x00009b10, 0x0000d790, 0x0000d790, 0x00008ba6, 0x00008ba6, 0x00008ba6},
+	{0x00009b14, 0x0000f780, 0x0000f780, 0x00008baa, 0x00008baa, 0x00008baa},
+	{0x00009b18, 0x0000f784, 0x0000f784, 0x00008bae, 0x00008bae, 0x00008bae},
+	{0x00009b1c, 0x0000f788, 0x0000f788, 0x00008bb2, 0x00008bb2, 0x00008bb2},
+	{0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008bb6, 0x00008bb6, 0x00008bb6},
+	{0x00009b24, 0x0000f790, 0x0000f790, 0x00008ba3, 0x00008ba3, 0x00008ba3},
+	{0x00009b28, 0x0000f794, 0x0000f794, 0x00008ba7, 0x00008ba7, 0x00008ba7},
+	{0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008bab, 0x00008bab, 0x00008bab},
+	{0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008baf, 0x00008baf, 0x00008baf},
+	{0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008bb3, 0x00008bb3, 0x00008bb3},
+	{0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008bb7, 0x00008bb7, 0x00008bb7},
+	{0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008bc3, 0x00008bc3, 0x00008bc3},
+	{0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008bc7, 0x00008bc7, 0x00008bc7},
+	{0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008bcb, 0x00008bcb, 0x00008bcb},
+	{0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008bcf, 0x00008bcf, 0x00008bcf},
+	{0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008bd3, 0x00008bd3, 0x00008bd3},
+	{0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008bd7, 0x00008bd7, 0x00008bd7},
+	{0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009848, 0x00001066, 0x00001066, 0x00001055, 0x00001055, 0x00001055},
+	{0x0000a848, 0x00001066, 0x00001066, 0x00001055, 0x00001055, 0x00001055},
 };
 
 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 },
+	{0x00009a00, 0x00008184, 0x00008184, 0x00008000, 0x00008000, 0x00008000},
+	{0x00009a04, 0x00008188, 0x00008188, 0x00008000, 0x00008000, 0x00008000},
+	{0x00009a08, 0x0000818c, 0x0000818c, 0x00008000, 0x00008000, 0x00008000},
+	{0x00009a0c, 0x00008190, 0x00008190, 0x00008000, 0x00008000, 0x00008000},
+	{0x00009a10, 0x00008194, 0x00008194, 0x00008000, 0x00008000, 0x00008000},
+	{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 },
+	{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] = {
-    { 0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
-    { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce },
-    { 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, 0x00021092, 0x00021092, 0x00022411, 0x00022411, 0x00022411 },
-    { 0x0000a328, 0x0002510a, 0x0002510a, 0x00025413, 0x00025413, 0x00025413 },
-    { 0x0000a32c, 0x0002910c, 0x0002910c, 0x00029811, 0x00029811, 0x00029811 },
-    { 0x0000a330, 0x0002c18b, 0x0002c18b, 0x0002c813, 0x0002c813, 0x0002c813 },
-    { 0x0000a334, 0x0002f1cc, 0x0002f1cc, 0x00030a14, 0x00030a14, 0x00030a14 },
-    { 0x0000a338, 0x000321eb, 0x000321eb, 0x00035a50, 0x00035a50, 0x00035a50 },
-    { 0x0000a33c, 0x000341ec, 0x000341ec, 0x00039c4c, 0x00039c4c, 0x00039c4c },
-    { 0x0000a340, 0x000341ec, 0x000341ec, 0x0003de8a, 0x0003de8a, 0x0003de8a },
-    { 0x0000a344, 0x000341ec, 0x000341ec, 0x00042e92, 0x00042e92, 0x00042e92 },
-    { 0x0000a348, 0x000341ec, 0x000341ec, 0x00046ed2, 0x00046ed2, 0x00046ed2 },
-    { 0x0000a34c, 0x000341ec, 0x000341ec, 0x0004bed5, 0x0004bed5, 0x0004bed5 },
-    { 0x0000a350, 0x000341ec, 0x000341ec, 0x0004ff54, 0x0004ff54, 0x0004ff54 },
-    { 0x0000a354, 0x000341ec, 0x000341ec, 0x00055fd5, 0x00055fd5, 0x00055fd5 },
-    { 0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff },
-    { 0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff },
-    { 0x0000781c, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000 },
-    { 0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000 },
-    { 0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 },
-    { 0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 },
+	{0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652},
+	{0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce},
+	{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, 0x00021092, 0x00021092, 0x00022411, 0x00022411, 0x00022411},
+	{0x0000a328, 0x0002510a, 0x0002510a, 0x00025413, 0x00025413, 0x00025413},
+	{0x0000a32c, 0x0002910c, 0x0002910c, 0x00029811, 0x00029811, 0x00029811},
+	{0x0000a330, 0x0002c18b, 0x0002c18b, 0x0002c813, 0x0002c813, 0x0002c813},
+	{0x0000a334, 0x0002f1cc, 0x0002f1cc, 0x00030a14, 0x00030a14, 0x00030a14},
+	{0x0000a338, 0x000321eb, 0x000321eb, 0x00035a50, 0x00035a50, 0x00035a50},
+	{0x0000a33c, 0x000341ec, 0x000341ec, 0x00039c4c, 0x00039c4c, 0x00039c4c},
+	{0x0000a340, 0x000341ec, 0x000341ec, 0x0003de8a, 0x0003de8a, 0x0003de8a},
+	{0x0000a344, 0x000341ec, 0x000341ec, 0x00042e92, 0x00042e92, 0x00042e92},
+	{0x0000a348, 0x000341ec, 0x000341ec, 0x00046ed2, 0x00046ed2, 0x00046ed2},
+	{0x0000a34c, 0x000341ec, 0x000341ec, 0x0004bed5, 0x0004bed5, 0x0004bed5},
+	{0x0000a350, 0x000341ec, 0x000341ec, 0x0004ff54, 0x0004ff54, 0x0004ff54},
+	{0x0000a354, 0x000341ec, 0x000341ec, 0x00055fd5, 0x00055fd5, 0x00055fd5},
+	{0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081},
+	{0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff},
+	{0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff},
+	{0x0000781c, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000},
+	{0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000},
+	{0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480},
+	{0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480},
 };
 
 static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = {
-    { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
-    { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
-    { 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 },
-    { 0x0000781c, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000 },
-    { 0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000 },
-    { 0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 },
-    { 0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 },
+	{0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652},
+	{0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce},
+	{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},
+	{0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081},
+	{0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff},
+	{0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff},
+	{0x0000781c, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000},
+	{0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000},
+	{0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480},
+	{0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480},
 };
 
 static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
-    {0x00004040,  0x9248fd00 },
-    {0x00004040,  0x24924924 },
-    {0x00004040,  0xa8000019 },
-    {0x00004040,  0x13160820 },
-    {0x00004040,  0xe5980560 },
-    {0x00004040,  0xc01dcffc },
-    {0x00004040,  0x1aaabe41 },
-    {0x00004040,  0xbe105554 },
-    {0x00004040,  0x00043007 },
-    {0x00004044,  0x00000000 },
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{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,  0xc01dcffd },
-    {0x00004040,  0x1aaabe41 },
-    {0x00004040,  0xbe105554 },
-    {0x00004040,  0x00043007 },
-    {0x00004044,  0x00000000 },
-};
-
-/* AR9285 Revsion 10*/
-static const u32 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 u32 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, 0x88a00010 },
-    { 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, 0x00481043 },
-    { 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 },
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffd},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
 };
 
 static const u32 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 },
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffd},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
 };
 
 static const u32 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 },
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffc},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
 };
 
-/* AR9285 v1_2 PCI Register Writes.  Created: 04/13/09 */
 static const u32 ar9285Modes_9285_1_2[][6] = {
-    /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
-    { 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, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e },
-    { 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, 0x03721620, 0x03721620, 0x037216a0 },
-    { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
-    { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
-    { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
-    { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
-    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 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, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f },
-    { 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, 0x00058084, 0x00058084, 0x00000000 },
-    { 0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 },
-    { 0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 },
-    { 0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 },
-    { 0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 },
-    { 0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 },
-    { 0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 },
-    { 0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 },
-    { 0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 },
-    { 0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 },
-    { 0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 },
-    { 0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 },
-    { 0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 },
-    { 0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 },
-    { 0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 },
-    { 0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 },
-    { 0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 },
-    { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
-    { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
-    { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
-    { 0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
-    { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
-    { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
-    { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
-    { 0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 },
-    { 0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 },
-    { 0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 },
-    { 0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 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, 0x00078b00, 0x00078b00, 0x00000000 },
-    { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
-    { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
-    { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
-    { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
-    { 0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 },
-    { 0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 },
-    { 0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 },
-    { 0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 },
-    { 0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 },
-    { 0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 },
-    { 0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 },
-    { 0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 },
-    { 0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 },
-    { 0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 },
-    { 0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 },
-    { 0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 },
-    { 0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 },
-    { 0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 },
-    { 0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 },
-    { 0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 },
-    { 0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 },
-    { 0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 },
-    { 0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 },
-    { 0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 },
-    { 0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 },
-    { 0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 },
-    { 0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 },
-    { 0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 },
-    { 0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 },
-    { 0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 },
-    { 0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 },
-    { 0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 },
-    { 0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 },
-    { 0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 },
-    { 0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 },
-    { 0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 },
-    { 0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 },
-    { 0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 },
-    { 0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 },
-    { 0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 },
-    { 0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 },
-    { 0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 },
-    { 0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 },
-    { 0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 },
-    { 0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 },
-    { 0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 },
-    { 0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 },
-    { 0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 },
-    { 0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 },
-    { 0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 },
-    { 0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 },
-    { 0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 },
-    { 0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 },
-    { 0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 },
-    { 0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 },
-    { 0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 },
-    { 0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 },
-    { 0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 },
-    { 0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 },
-    { 0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 },
-    { 0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 },
-    { 0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 },
-    { 0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 },
-    { 0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 },
-    { 0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 },
-    { 0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 },
-    { 0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 },
-    { 0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 },
-    { 0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 },
-    { 0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 },
-    { 0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 },
-    { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
-    { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
-    { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
-    { 0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
-    { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
-    { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
-    { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
-    { 0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 },
-    { 0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 },
-    { 0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 },
-    { 0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 },
-    { 0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
-    { 0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
-    { 0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
-    { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
-    { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
-    { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
-    { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 },
-    { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
-    { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
-    { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
-    { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
-    { 0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 },
-    { 0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 },
-    { 0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 },
-    { 0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 },
-    { 0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 },
-    { 0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 },
-    { 0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 },
-    { 0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 },
-    { 0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 },
-    { 0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 },
-    { 0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 },
-    { 0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 },
-    { 0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 },
-    { 0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 },
-    { 0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 },
-    { 0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 },
-    { 0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 },
-    { 0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 },
-    { 0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 },
-    { 0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 },
-    { 0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 },
-    { 0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 },
-    { 0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 },
-    { 0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 },
-    { 0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 },
-    { 0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 },
-    { 0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 },
-    { 0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 },
-    { 0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 },
-    { 0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 },
-    { 0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 },
-    { 0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 },
-    { 0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 },
-    { 0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 },
-    { 0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 },
-    { 0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 },
-    { 0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 },
-    { 0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 },
-    { 0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 },
-    { 0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 },
-    { 0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 },
-    { 0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 },
-    { 0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 },
-    { 0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 },
-    { 0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 },
-    { 0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 },
-    { 0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 },
-    { 0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 },
-    { 0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 },
-    { 0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 },
-    { 0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
-    { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
-    { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
-    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
-    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
-    { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+	{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, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+	{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, 0x03721620, 0x03721620, 0x037216a0},
+	{0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
+	{0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
+	{0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
+	{0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+	{0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 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, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f},
+	{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, 0x00058084, 0x00058084, 0x00000000},
+	{0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
+	{0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
+	{0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
+	{0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
+	{0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
+	{0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
+	{0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
+	{0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
+	{0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
+	{0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
+	{0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
+	{0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
+	{0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
+	{0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
+	{0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
+	{0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
+	{0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
+	{0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
+	{0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
+	{0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
+	{0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
+	{0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
+	{0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
+	{0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
+	{0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
+	{0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
+	{0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 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, 0x00078b00, 0x00078b00, 0x00000000},
+	{0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
+	{0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
+	{0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
+	{0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
+	{0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
+	{0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
+	{0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
+	{0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
+	{0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
+	{0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
+	{0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
+	{0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
+	{0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
+	{0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
+	{0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
+	{0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
+	{0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
+	{0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
+	{0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
+	{0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
+	{0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
+	{0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
+	{0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
+	{0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
+	{0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
+	{0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
+	{0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
+	{0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
+	{0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
+	{0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
+	{0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
+	{0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
+	{0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
+	{0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
+	{0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
+	{0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
+	{0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
+	{0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
+	{0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
+	{0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
+	{0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
+	{0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
+	{0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
+	{0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
+	{0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
+	{0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
+	{0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
+	{0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
+	{0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
+	{0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
+	{0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
+	{0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
+	{0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
+	{0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
+	{0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
+	{0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
+	{0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
+	{0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
+	{0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
+	{0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
+	{0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
+	{0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
+	{0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
+	{0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
+	{0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
+	{0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
+	{0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
+	{0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
+	{0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
+	{0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
+	{0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
+	{0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
+	{0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
+	{0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
+	{0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
+	{0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
+	{0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
+	{0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
+	{0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
+	{0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
+	{0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
+	{0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
+	{0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
+	{0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
+	{0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
+	{0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
+	{0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
+	{0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
+	{0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
+	{0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
+	{0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
+	{0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
+	{0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
+	{0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
+	{0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
+	{0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
+	{0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
+	{0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
+	{0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
+	{0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
+	{0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
+	{0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
+	{0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
+	{0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
+	{0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
+	{0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
+	{0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
+	{0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
+	{0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
+	{0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
+	{0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
+	{0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
+	{0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
+	{0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
+	{0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
+	{0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
+	{0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
+	{0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
+	{0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
+	{0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
+	{0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
+	{0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
+	{0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
+	{0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
+	{0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
+	{0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
+	{0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
+	{0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
+	{0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
+	{0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
+	{0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
+	{0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
+	{0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
+	{0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
+	{0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
+	{0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
+	{0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
+	{0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
+	{0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
+	{0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
+	{0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
+	{0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
+	{0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
+	{0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004},
+	{0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
+	{0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
+	{0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000},
+	{0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
 };
 
 static const u32 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, 0x08f04810 },
-    { 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, 0x0000320a },
-    { 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, 0x88a00010 },
-    { 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, 0x00481043 },
-    { 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, 0x192bb514 },
-    { 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, 0x2def0400 },
-    { 0x000099b0, 0x03051000 },
-    { 0x000099b4, 0x00000820 },
-    { 0x000099dc, 0x00000000 },
-    { 0x000099e0, 0x00000000 },
-    { 0x000099e4, 0xaaaaaaaa },
-    { 0x000099e8, 0x3c466478 },
-    { 0x000099ec, 0x0cc80caa },
-    { 0x000099f0, 0x00000000 },
-    { 0x0000a208, 0x803e68c8 },
-    { 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 },
-    { 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 },
-    { 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 },
-    { 0x0000a3e4, 0x00000000 },
-    { 0x0000a3e8, 0x18c43433 },
-    { 0x0000a3ec, 0x00f70081 },
-    { 0x00007800, 0x00140000 },
-    { 0x00007804, 0x0e4548d8 },
-    { 0x00007808, 0x54214514 },
-    { 0x0000780c, 0x02025830 },
-    { 0x00007810, 0x71c0d388 },
-    { 0x0000781c, 0x00000000 },
-    { 0x00007824, 0x00d86fff },
-    { 0x0000782c, 0x6e36d97b },
-    { 0x00007834, 0x71400087 },
-    { 0x00007844, 0x000c0db6 },
-    { 0x00007848, 0x6db6246f },
-    { 0x0000784c, 0x6d9b66db },
-    { 0x00007850, 0x6d8c6dba },
-    { 0x00007854, 0x00040000 },
-    { 0x00007858, 0xdb003012 },
-    { 0x0000785c, 0x04924914 },
-    { 0x00007860, 0x21084210 },
-    { 0x00007864, 0xf7d7ffde },
-    { 0x00007868, 0xc2034080 },
-    { 0x00007870, 0x10142c00 },
+	/* Addr      allmodes  */
+	{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, 0x08f04810},
+	{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, 0x0000320a},
+	{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, 0x88a00010},
+	{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, 0x00481043},
+	{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, 0x192bb514},
+	{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, 0x2def0400},
+	{0x000099b0, 0x03051000},
+	{0x000099b4, 0x00000820},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000000},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x0cc80caa},
+	{0x000099f0, 0x00000000},
+	{0x0000a208, 0x803e68c8},
+	{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},
+	{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},
+	{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},
+	{0x0000a3e4, 0x00000000},
+	{0x0000a3e8, 0x18c43433},
+	{0x0000a3ec, 0x00f70081},
+	{0x00007800, 0x00140000},
+	{0x00007804, 0x0e4548d8},
+	{0x00007808, 0x54214514},
+	{0x0000780c, 0x02025830},
+	{0x00007810, 0x71c0d388},
+	{0x0000781c, 0x00000000},
+	{0x00007824, 0x00d86fff},
+	{0x0000782c, 0x6e36d97b},
+	{0x00007834, 0x71400087},
+	{0x00007844, 0x000c0db6},
+	{0x00007848, 0x6db6246f},
+	{0x0000784c, 0x6d9b66db},
+	{0x00007850, 0x6d8c6dba},
+	{0x00007854, 0x00040000},
+	{0x00007858, 0xdb003012},
+	{0x0000785c, 0x04924914},
+	{0x00007860, 0x21084210},
+	{0x00007864, 0xf7d7ffde},
+	{0x00007868, 0xc2034080},
+	{0x00007870, 0x10142c00},
 };
 
 static const u32 ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
-    /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
-    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 },
-    { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 },
-    { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 },
-    { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 },
-    { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 },
-    { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 },
-    { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 },
-    { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 },
-    { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 },
-    { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 },
-    { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 },
-    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
-    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
-    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8 },
-    { 0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b },
-    { 0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e },
-    { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 },
-    { 0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe },
-    { 0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20 },
-    { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
-    { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
-    { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
-    { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
-    { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 },
-    { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
-    { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
-    { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
-    { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000},
+	{0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000},
+	{0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000},
+	{0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000},
+	{0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000},
+	{0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000},
+	{0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+	{0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+	{0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8},
+	{0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b},
+	{0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e},
+	{0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803},
+	{0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe},
+	{0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20},
+	{0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe},
+	{0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
+	{0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652},
+	{0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7},
+	{0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
+	{0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
 };
 
 static const u32 ar9285Modes_original_tx_gain_9285_1_2[][6] = {
-    /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
-    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
-    { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 },
-    { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 },
-    { 0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000 },
-    { 0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000 },
-    { 0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000 },
-    { 0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000 },
-    { 0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000 },
-    { 0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000 },
-    { 0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000 },
-    { 0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000 },
-    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
-    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
-    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8 },
-    { 0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b },
-    { 0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e },
-    { 0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801 },
-    { 0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe },
-    { 0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20 },
-    { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 },
-    { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 },
-    { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
-    { 0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
-    { 0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c },
-    { 0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
-    { 0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
-    { 0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
-    { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000},
+	{0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000},
+	{0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000},
+	{0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000},
+	{0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000},
+	{0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000},
+	{0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+	{0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+	{0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8},
+	{0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b},
+	{0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e},
+	{0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801},
+	{0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe},
+	{0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20},
+	{0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
+	{0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
+	{0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652},
+	{0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+	{0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c},
+	{0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+	{0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
+	{0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+	{0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
 };
 
 static const u32 ar9285Modes_XE2_0_normal_power[][6] = {
-    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
-    { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 },
-    { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 },
-    { 0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000 },
-    { 0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000 },
-    { 0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000 },
-    { 0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000 },
-    { 0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000 },
-    { 0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000 },
-    { 0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000 },
-    { 0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000 },
-    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
-    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
-    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8 },
-    { 0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b },
-    { 0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6dbae },
-    { 0x00007838, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441 },
-    { 0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe },
-    { 0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c },
-    { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 },
-    { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 },
-    { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
-    { 0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
-    { 0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c },
-    { 0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
-    { 0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
-    { 0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
-    { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000},
+	{0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000},
+	{0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000},
+	{0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000},
+	{0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000},
+	{0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000},
+	{0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+	{0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+	{0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8},
+	{0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b},
+	{0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6dbae},
+	{0x00007838, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441},
+	{0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe},
+	{0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c},
+	{0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
+	{0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
+	{0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652},
+	{0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+	{0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c},
+	{0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+	{0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
+	{0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+	{0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
 };
 
 static const u32 ar9285Modes_XE2_0_high_power[][6] = {
-    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 },
-    { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 },
-    { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 },
-    { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 },
-    { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 },
-    { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 },
-    { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 },
-    { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 },
-    { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 },
-    { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 },
-    { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 },
-    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
-    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
-    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8 },
-    { 0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b },
-    { 0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e },
-    { 0x00007838, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443 },
-    { 0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe },
-    { 0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c },
-    { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
-    { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
-    { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
-    { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
-    { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 },
-    { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
-    { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
-    { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
-    { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000},
+	{0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000},
+	{0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000},
+	{0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000},
+	{0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000},
+	{0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000},
+	{0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+	{0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+	{0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8},
+	{0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b},
+	{0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e},
+	{0x00007838, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443},
+	{0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe},
+	{0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c},
+	{0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe},
+	{0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
+	{0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652},
+	{0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7},
+	{0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
+	{0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
 };
 
 static const u32 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 },
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffd},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
 };
 
 static const u32 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 },
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffc},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
 };
 
-/* AR9287 Revision 10 */
-static const u32 ar9287Modes_9287_1_0[][6] = {
-    /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
-    { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 },
-    { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 },
-    { 0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180 },
-    { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
-    { 0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0 },
-    { 0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f },
-    { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
-    { 0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a },
-    { 0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880 },
-    { 0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303 },
-    { 0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200 },
-    { 0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e },
-    { 0x00009828, 0x00000000, 0x00000000, 0x0a020001, 0x0a020001, 0x0a020001 },
-    { 0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e },
-    { 0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007 },
-    { 0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e },
-    { 0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0 },
-    { 0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
-    { 0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
-    { 0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e },
-    { 0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18 },
-    { 0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
-    { 0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
-    { 0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881 },
-    { 0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0 },
-    { 0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016 },
-    { 0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
-    { 0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010 },
-    { 0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
-    { 0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
-    { 0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210 },
-    { 0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce },
-    { 0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c },
-    { 0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00 },
-    { 0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
-    { 0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444 },
-    { 0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a },
-    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000 },
-    { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
-    { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-};
-
-static const u32 ar9287Common_9287_1_0[][2] = {
-    { 0x0000000c, 0x00000000 },
-    { 0x00000030, 0x00020015 },
-    { 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, 0x00000033 },
-    { 0x00007020, 0x00000000 },
-    { 0x00007034, 0x00000002 },
-    { 0x00007038, 0x000004c2 },
-    { 0x00008004, 0x00000000 },
-    { 0x00008008, 0x00000000 },
-    { 0x0000800c, 0x00000000 },
-    { 0x00008018, 0x00000700 },
-    { 0x00008020, 0x00000000 },
-    { 0x00008038, 0x00000000 },
-    { 0x0000803c, 0x00000000 },
-    { 0x00008048, 0x40000000 },
-    { 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 },
-    { 0x00008124, 0x00000000 },
-    { 0x00008128, 0x00000000 },
-    { 0x0000812c, 0x00000000 },
-    { 0x00008130, 0x00000000 },
-    { 0x00008134, 0x00000000 },
-    { 0x00008138, 0x00000000 },
-    { 0x0000813c, 0x00000000 },
-    { 0x00008144, 0xffffffff },
-    { 0x00008168, 0x00000000 },
-    { 0x0000816c, 0x00000000 },
-    { 0x00008170, 0x18487320 },
-    { 0x00008174, 0xfaa4fa50 },
-    { 0x00008178, 0x00000100 },
-    { 0x0000817c, 0x00000000 },
-    { 0x000081c0, 0x00000000 },
-    { 0x000081c4, 0x00000000 },
-    { 0x000081d4, 0x00000000 },
-    { 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, 0x88a00010 },
-    { 0x00008270, 0x00000000 },
-    { 0x00008274, 0x40000000 },
-    { 0x00008278, 0x003e4180 },
-    { 0x0000827c, 0x00000000 },
-    { 0x00008284, 0x0000002c },
-    { 0x00008288, 0x0000002c },
-    { 0x0000828c, 0x000000ff },
-    { 0x00008294, 0x00000000 },
-    { 0x00008298, 0x00000000 },
-    { 0x0000829c, 0x00000000 },
-    { 0x00008300, 0x00000040 },
-    { 0x00008314, 0x00000000 },
-    { 0x00008328, 0x00000000 },
-    { 0x0000832c, 0x00000007 },
-    { 0x00008330, 0x00000302 },
-    { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00ff0000 },
-    { 0x0000833c, 0x00000000 },
-    { 0x00008340, 0x000107ff },
-    { 0x00008344, 0x01c81043 },
-    { 0x00008360, 0xffffffff },
-    { 0x00008364, 0xffffffff },
-    { 0x00008368, 0x00000000 },
-    { 0x00008370, 0x00000000 },
-    { 0x00008374, 0x000000ff },
-    { 0x00008378, 0x00000000 },
-    { 0x0000837c, 0x00000000 },
-    { 0x00008380, 0xffffffff },
-    { 0x00008384, 0xffffffff },
-    { 0x00008390, 0x0fffffff },
-    { 0x00008394, 0x0fffffff },
-    { 0x00008398, 0x00000000 },
-    { 0x0000839c, 0x00000000 },
-    { 0x000083a0, 0x00000000 },
-    { 0x00009808, 0x00000000 },
-    { 0x0000980c, 0xafe68e30 },
-    { 0x00009810, 0xfd14e000 },
-    { 0x00009814, 0x9c0a9f6b },
-    { 0x0000981c, 0x00000000 },
-    { 0x0000982c, 0x0000a000 },
-    { 0x00009830, 0x00000000 },
-    { 0x0000983c, 0x00200400 },
-    { 0x0000984c, 0x0040233c },
-    { 0x0000a84c, 0x0040233c },
-    { 0x00009854, 0x00000044 },
-    { 0x00009900, 0x00000000 },
-    { 0x00009904, 0x00000000 },
-    { 0x00009908, 0x00000000 },
-    { 0x0000990c, 0x00000000 },
-    { 0x00009910, 0x10002310 },
-    { 0x0000991c, 0x10000fff },
-    { 0x00009920, 0x04900000 },
-    { 0x0000a920, 0x04900000 },
-    { 0x00009928, 0x00000001 },
-    { 0x0000992c, 0x00000004 },
-    { 0x00009930, 0x00000000 },
-    { 0x0000a930, 0x00000000 },
-    { 0x00009934, 0x1e1f2022 },
-    { 0x00009938, 0x0a0b0c0d },
-    { 0x0000993c, 0x00000000 },
-    { 0x00009948, 0x9280c00a },
-    { 0x0000994c, 0x00020028 },
-    { 0x00009954, 0x5f3ca3de },
-    { 0x00009958, 0x0108ecff },
-    { 0x00009940, 0x14750604 },
-    { 0x0000c95c, 0x004b6a8e },
-    { 0x00009970, 0x990bb515 },
-    { 0x00009974, 0x00000000 },
-    { 0x00009978, 0x00000001 },
-    { 0x0000997c, 0x00000000 },
-    { 0x000099a0, 0x00000000 },
-    { 0x000099a4, 0x00000001 },
-    { 0x000099a8, 0x201fff00 },
-    { 0x000099ac, 0x0c6f0000 },
-    { 0x000099b0, 0x03051000 },
-    { 0x000099b4, 0x00000820 },
-    { 0x000099c4, 0x06336f77 },
-    { 0x000099c8, 0x6af65329 },
-    { 0x000099cc, 0x08f186c8 },
-    { 0x000099d0, 0x00046384 },
-    { 0x000099dc, 0x00000000 },
-    { 0x000099e0, 0x00000000 },
-    { 0x000099e4, 0xaaaaaaaa },
-    { 0x000099e8, 0x3c466478 },
-    { 0x000099ec, 0x0cc80caa },
-    { 0x000099f0, 0x00000000 },
-    { 0x000099fc, 0x00001042 },
-    { 0x0000a1f4, 0x00fffeff },
-    { 0x0000a1f8, 0x00f5f9ff },
-    { 0x0000a1fc, 0xb79f6427 },
-    { 0x0000a208, 0x803e4788 },
-    { 0x0000a210, 0x4080a333 },
-    { 0x0000a214, 0x40206c10 },
-    { 0x0000a218, 0x009c4060 },
-    { 0x0000a220, 0x01834061 },
-    { 0x0000a224, 0x00000400 },
-    { 0x0000a228, 0x000003b5 },
-    { 0x0000a22c, 0x233f7180 },
-    { 0x0000a234, 0x20202020 },
-    { 0x0000a238, 0x20202020 },
-    { 0x0000a23c, 0x13c889af },
-    { 0x0000a240, 0x38490a20 },
-    { 0x0000a244, 0x00000000 },
-    { 0x0000a248, 0xfffffffc },
-    { 0x0000a24c, 0x00000000 },
-    { 0x0000a254, 0x00000000 },
-    { 0x0000a258, 0x0cdbd380 },
-    { 0x0000a25c, 0x0f0f0f01 },
-    { 0x0000a260, 0xdfa91f01 },
-    { 0x0000a264, 0x00418a11 },
-    { 0x0000b264, 0x00418a11 },
-    { 0x0000a268, 0x00000000 },
-    { 0x0000a26c, 0x0e79e5c6 },
-    { 0x0000b26c, 0x0e79e5c6 },
-    { 0x0000d270, 0x00820820 },
-    { 0x0000a278, 0x1ce739ce },
-    { 0x0000a27c, 0x050701ce },
-    { 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, 0x1ce739ce },
-    { 0x0000a398, 0x000001ce },
-    { 0x0000b398, 0x000001ce },
-    { 0x0000a39c, 0x00000001 },
-    { 0x0000a3c8, 0x00000246 },
-    { 0x0000a3cc, 0x20202020 },
-    { 0x0000a3d0, 0x20202020 },
-    { 0x0000a3d4, 0x20202020 },
-    { 0x0000a3dc, 0x1ce739ce },
-    { 0x0000a3e0, 0x000001ce },
-    { 0x0000a3e4, 0x00000000 },
-    { 0x0000a3e8, 0x18c43433 },
-    { 0x0000a3ec, 0x00f70081 },
-    { 0x0000a3f0, 0x01036a1e },
-    { 0x0000a3f4, 0x00000000 },
-    { 0x0000b3f4, 0x00000000 },
-    { 0x0000a7d8, 0x00000001 },
-    { 0x00007800, 0x00000800 },
-    { 0x00007804, 0x6c35ffb0 },
-    { 0x00007808, 0x6db6c000 },
-    { 0x0000780c, 0x6db6cb30 },
-    { 0x00007810, 0x6db6cb6c },
-    { 0x00007814, 0x0501e200 },
-    { 0x00007818, 0x0094128d },
-    { 0x0000781c, 0x976ee392 },
-    { 0x00007820, 0xf75ff6fc },
-    { 0x00007824, 0x00040000 },
-    { 0x00007828, 0xdb003012 },
-    { 0x0000782c, 0x04924914 },
-    { 0x00007830, 0x21084210 },
-    { 0x00007834, 0x00140000 },
-    { 0x00007838, 0x0e4548d8 },
-    { 0x0000783c, 0x54214514 },
-    { 0x00007840, 0x02025820 },
-    { 0x00007844, 0x71c0d388 },
-    { 0x00007848, 0x934934a8 },
-    { 0x00007850, 0x00000000 },
-    { 0x00007854, 0x00000800 },
-    { 0x00007858, 0x6c35ffb0 },
-    { 0x0000785c, 0x6db6c000 },
-    { 0x00007860, 0x6db6cb2c },
-    { 0x00007864, 0x6db6cb6c },
-    { 0x00007868, 0x0501e200 },
-    { 0x0000786c, 0x0094128d },
-    { 0x00007870, 0x976ee392 },
-    { 0x00007874, 0xf75ff6fc },
-    { 0x00007878, 0x00040000 },
-    { 0x0000787c, 0xdb003012 },
-    { 0x00007880, 0x04924914 },
-    { 0x00007884, 0x21084210 },
-    { 0x00007888, 0x001b6db0 },
-    { 0x0000788c, 0x00376b63 },
-    { 0x00007890, 0x06db6db6 },
-    { 0x00007894, 0x006d8000 },
-    { 0x00007898, 0x48100000 },
-    { 0x0000789c, 0x00000000 },
-    { 0x000078a0, 0x08000000 },
-    { 0x000078a4, 0x0007ffd8 },
-    { 0x000078a8, 0x0007ffd8 },
-    { 0x000078ac, 0x001c0020 },
-    { 0x000078b0, 0x000611eb },
-    { 0x000078b4, 0x40008080 },
-    { 0x000078b8, 0x2a850160 },
-};
-
-static const u32 ar9287Modes_tx_gain_9287_1_0[][6] = {
-    /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
-    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 },
-    { 0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004 },
-    { 0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a },
-    { 0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c },
-    { 0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b },
-    { 0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a },
-    { 0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a },
-    { 0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a },
-    { 0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a },
-    { 0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a },
-    { 0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a },
-    { 0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c },
-    { 0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc },
-    { 0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4 },
-    { 0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc },
-    { 0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede },
-    { 0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e },
-    { 0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e },
-    { 0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e },
-    { 0x0000a780, 0x00000000, 0x00000000, 0x00000060, 0x00000060, 0x00000060 },
-    { 0x0000a784, 0x00000000, 0x00000000, 0x00004062, 0x00004062, 0x00004062 },
-    { 0x0000a788, 0x00000000, 0x00000000, 0x00008064, 0x00008064, 0x00008064 },
-    { 0x0000a78c, 0x00000000, 0x00000000, 0x0000c0a4, 0x0000c0a4, 0x0000c0a4 },
-    { 0x0000a790, 0x00000000, 0x00000000, 0x000100b0, 0x000100b0, 0x000100b0 },
-    { 0x0000a794, 0x00000000, 0x00000000, 0x000140b2, 0x000140b2, 0x000140b2 },
-    { 0x0000a798, 0x00000000, 0x00000000, 0x000180b4, 0x000180b4, 0x000180b4 },
-    { 0x0000a79c, 0x00000000, 0x00000000, 0x0001c0f4, 0x0001c0f4, 0x0001c0f4 },
-    { 0x0000a7a0, 0x00000000, 0x00000000, 0x00020134, 0x00020134, 0x00020134 },
-    { 0x0000a7a4, 0x00000000, 0x00000000, 0x000240fe, 0x000240fe, 0x000240fe },
-    { 0x0000a7a8, 0x00000000, 0x00000000, 0x0002813e, 0x0002813e, 0x0002813e },
-    { 0x0000a7ac, 0x00000000, 0x00000000, 0x0002c17e, 0x0002c17e, 0x0002c17e },
-    { 0x0000a7b0, 0x00000000, 0x00000000, 0x000301be, 0x000301be, 0x000301be },
-    { 0x0000a7b4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
-    { 0x0000a7b8, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
-    { 0x0000a7bc, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
-    { 0x0000a7c0, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
-    { 0x0000a7c4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
-    { 0x0000a7c8, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
-    { 0x0000a7cc, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
-    { 0x0000a7d0, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
-    { 0x0000a7d4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
-    { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 },
-};
-
-
-static const u32 ar9287Modes_rx_gain_9287_1_0[][6] = {
-    /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
-    { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
-    { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
-    { 0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
-    { 0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
-    { 0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
-    { 0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
-    { 0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
-    { 0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
-    { 0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
-    { 0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
-    { 0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
-    { 0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
-    { 0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
-    { 0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
-    { 0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
-    { 0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
-    { 0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
-    { 0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
-    { 0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
-    { 0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
-    { 0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
-    { 0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
-    { 0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
-    { 0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
-    { 0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
-    { 0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
-    { 0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
-    { 0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
-    { 0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
-    { 0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
-    { 0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
-    { 0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
-    { 0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
-    { 0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
-    { 0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
-    { 0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
-    { 0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
-    { 0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
-    { 0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
-    { 0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
-    { 0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
-    { 0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
-    { 0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
-    { 0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
-    { 0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
-    { 0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
-    { 0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
-    { 0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
-    { 0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
-    { 0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
-    { 0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
-    { 0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
-    { 0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
-    { 0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
-    { 0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
-    { 0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
-    { 0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
-    { 0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
-    { 0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
-    { 0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
-    { 0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
-    { 0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
-    { 0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
-    { 0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
-    { 0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
-    { 0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
-    { 0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
-    { 0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
-    { 0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
-    { 0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
-    { 0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
-    { 0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
-    { 0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
-    { 0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
-    { 0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
-    { 0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
-    { 0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
-    { 0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
-    { 0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
-    { 0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
-    { 0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
-    { 0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
-    { 0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
-    { 0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
-    { 0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
-    { 0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
-    { 0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
-    { 0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
-    { 0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
-    { 0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
-    { 0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
-    { 0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
-    { 0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
-    { 0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
-    { 0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
-    { 0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
-    { 0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
-    { 0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
-    { 0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
-    { 0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
-    { 0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
-    { 0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
-    { 0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
-    { 0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
-    { 0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
-    { 0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
-    { 0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
-    { 0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
-    { 0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
-    { 0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
-    { 0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
-    { 0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
-    { 0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
-    { 0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
-    { 0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
-    { 0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
-    { 0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
-    { 0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
-    { 0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
-    { 0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
-    { 0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
-    { 0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
-    { 0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
-    { 0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
-    { 0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
-    { 0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
-    { 0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
-    { 0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
-    { 0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
-    { 0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
-    { 0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
-    { 0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
-    { 0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
-    { 0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
-    { 0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
-    { 0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
-    { 0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
-    { 0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
-    { 0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
-    { 0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
-    { 0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
-    { 0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
-    { 0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
-    { 0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
-    { 0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
-    { 0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
-    { 0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
-    { 0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
-    { 0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
-    { 0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
-    { 0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
-    { 0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
-    { 0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
-    { 0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
-    { 0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
-    { 0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
-    { 0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
-    { 0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
-    { 0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
-    { 0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
-    { 0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
-    { 0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
-    { 0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
-    { 0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
-    { 0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
-    { 0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
-    { 0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
-    { 0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
-    { 0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
-    { 0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
-    { 0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
-    { 0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
-    { 0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
-    { 0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
-    { 0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
-    { 0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
-    { 0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
-    { 0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
-    { 0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
-    { 0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
-    { 0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
-    { 0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
-    { 0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
-    { 0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
-    { 0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
-    { 0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
-    { 0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
-    { 0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
-    { 0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
-    { 0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
-    { 0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
-    { 0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
-    { 0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
-    { 0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
-    { 0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
-    { 0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
-    { 0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
-    { 0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
-    { 0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
-    { 0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
-    { 0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
-    { 0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
-    { 0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
-    { 0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
-    { 0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
-    { 0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
-    { 0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
-    { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
-};
-
-static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_0[][2] = {
-    {0x00004040,  0x9248fd00 },
-    {0x00004040,  0x24924924 },
-    {0x00004040,  0xa8000019 },
-    {0x00004040,  0x13160820 },
-    {0x00004040,  0xe5980560 },
-    {0x00004040,  0xc01dcffd },
-    {0x00004040,  0x1aaabe41 },
-    {0x00004040,  0xbe105554 },
-    {0x00004040,  0x00043007 },
-    {0x00004044,  0x00000000 },
-};
-
-static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_0[][2] = {
-    {0x00004040,  0x9248fd00 },
-    {0x00004040,  0x24924924 },
-    {0x00004040,  0xa8000019 },
-    {0x00004040,  0x13160820 },
-    {0x00004040,  0xe5980560 },
-    {0x00004040,  0xc01dcffc },
-    {0x00004040,  0x1aaabe41 },
-    {0x00004040,  0xbe105554 },
-    {0x00004040,  0x00043007 },
-    {0x00004044,  0x00000000 },
-};
-
-/* AR9287 Revision 11 */
-
 static const u32 ar9287Modes_9287_1_1[][6] = {
-    /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
-    { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 },
-    { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 },
-    { 0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180 },
-    { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
-    { 0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0 },
-    { 0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f },
-    { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
-    { 0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a },
-    { 0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880 },
-    { 0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303 },
-    { 0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200 },
-    { 0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e },
-    { 0x00009828, 0x00000000, 0x00000000, 0x3a020001, 0x3a020001, 0x3a020001 },
-    { 0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e },
-    { 0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007 },
-    { 0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e },
-    { 0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0 },
-    { 0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
-    { 0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
-    { 0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e },
-    { 0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18 },
-    { 0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
-    { 0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
-    { 0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881 },
-    { 0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0 },
-    { 0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016 },
-    { 0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
-    { 0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010 },
-    { 0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
-    { 0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
-    { 0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210 },
-    { 0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce },
-    { 0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c },
-    { 0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00 },
-    { 0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
-    { 0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444 },
-    { 0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a },
-    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000 },
-    { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
-    { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+	{0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0},
+	{0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0},
+	{0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180},
+	{0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008},
+	{0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0},
+	{0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a},
+	{0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880},
+	{0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303},
+	{0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200},
+	{0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+	{0x00009828, 0x00000000, 0x00000000, 0x3a020001, 0x3a020001, 0x3a020001},
+	{0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007},
+	{0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e},
+	{0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0},
+	{0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2},
+	{0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+	{0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+	{0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18},
+	{0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+	{0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881},
+	{0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0},
+	{0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016},
+	{0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
+	{0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010},
+	{0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010},
+	{0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010},
+	{0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210},
+	{0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce},
+	{0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c},
+	{0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00},
+	{0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+	{0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444},
+	{0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000},
+	{0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
+	{0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 };
 
 static const u32 ar9287Common_9287_1_1[][2] = {
-    { 0x0000000c, 0x00000000 },
-    { 0x00000030, 0x00020015 },
-    { 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, 0x00000033 },
-    { 0x00007020, 0x00000000 },
-    { 0x00007034, 0x00000002 },
-    { 0x00007038, 0x000004c2 },
-    { 0x00008004, 0x00000000 },
-    { 0x00008008, 0x00000000 },
-    { 0x0000800c, 0x00000000 },
-    { 0x00008018, 0x00000700 },
-    { 0x00008020, 0x00000000 },
-    { 0x00008038, 0x00000000 },
-    { 0x0000803c, 0x00000000 },
-    { 0x00008048, 0x40000000 },
-    { 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 },
-    { 0x00008124, 0x00000000 },
-    { 0x00008128, 0x00000000 },
-    { 0x0000812c, 0x00000000 },
-    { 0x00008130, 0x00000000 },
-    { 0x00008134, 0x00000000 },
-    { 0x00008138, 0x00000000 },
-    { 0x0000813c, 0x00000000 },
-    { 0x00008144, 0xffffffff },
-    { 0x00008168, 0x00000000 },
-    { 0x0000816c, 0x00000000 },
-    { 0x00008170, 0x18487320 },
-    { 0x00008174, 0xfaa4fa50 },
-    { 0x00008178, 0x00000100 },
-    { 0x0000817c, 0x00000000 },
-    { 0x000081c0, 0x00000000 },
-    { 0x000081c4, 0x00000000 },
-    { 0x000081d4, 0x00000000 },
-    { 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, 0x88a00010 },
-    { 0x00008270, 0x00000000 },
-    { 0x00008274, 0x40000000 },
-    { 0x00008278, 0x003e4180 },
-    { 0x0000827c, 0x00000000 },
-    { 0x00008284, 0x0000002c },
-    { 0x00008288, 0x0000002c },
-    { 0x0000828c, 0x000000ff },
-    { 0x00008294, 0x00000000 },
-    { 0x00008298, 0x00000000 },
-    { 0x0000829c, 0x00000000 },
-    { 0x00008300, 0x00000040 },
-    { 0x00008314, 0x00000000 },
-    { 0x00008328, 0x00000000 },
-    { 0x0000832c, 0x00000007 },
-    { 0x00008330, 0x00000302 },
-    { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00ff0000 },
-    { 0x0000833c, 0x00000000 },
-    { 0x00008340, 0x000107ff },
-    { 0x00008344, 0x01c81043 },
-    { 0x00008360, 0xffffffff },
-    { 0x00008364, 0xffffffff },
-    { 0x00008368, 0x00000000 },
-    { 0x00008370, 0x00000000 },
-    { 0x00008374, 0x000000ff },
-    { 0x00008378, 0x00000000 },
-    { 0x0000837c, 0x00000000 },
-    { 0x00008380, 0xffffffff },
-    { 0x00008384, 0xffffffff },
-    { 0x00008390, 0x0fffffff },
-    { 0x00008394, 0x0fffffff },
-    { 0x00008398, 0x00000000 },
-    { 0x0000839c, 0x00000000 },
-    { 0x000083a0, 0x00000000 },
-    { 0x00009808, 0x00000000 },
-    { 0x0000980c, 0xafe68e30 },
-    { 0x00009810, 0xfd14e000 },
-    { 0x00009814, 0x9c0a9f6b },
-    { 0x0000981c, 0x00000000 },
-    { 0x0000982c, 0x0000a000 },
-    { 0x00009830, 0x00000000 },
-    { 0x0000983c, 0x00200400 },
-    { 0x0000984c, 0x0040233c },
-    { 0x0000a84c, 0x0040233c },
-    { 0x00009854, 0x00000044 },
-    { 0x00009900, 0x00000000 },
-    { 0x00009904, 0x00000000 },
-    { 0x00009908, 0x00000000 },
-    { 0x0000990c, 0x00000000 },
-    { 0x00009910, 0x10002310 },
-    { 0x0000991c, 0x10000fff },
-    { 0x00009920, 0x04900000 },
-    { 0x0000a920, 0x04900000 },
-    { 0x00009928, 0x00000001 },
-    { 0x0000992c, 0x00000004 },
-    { 0x00009930, 0x00000000 },
-    { 0x0000a930, 0x00000000 },
-    { 0x00009934, 0x1e1f2022 },
-    { 0x00009938, 0x0a0b0c0d },
-    { 0x0000993c, 0x00000000 },
-    { 0x00009948, 0x9280c00a },
-    { 0x0000994c, 0x00020028 },
-    { 0x00009954, 0x5f3ca3de },
-    { 0x00009958, 0x0108ecff },
-    { 0x00009940, 0x14750604 },
-    { 0x0000c95c, 0x004b6a8e },
-    { 0x00009970, 0x990bb514 },
-    { 0x00009974, 0x00000000 },
-    { 0x00009978, 0x00000001 },
-    { 0x0000997c, 0x00000000 },
-    { 0x000099a0, 0x00000000 },
-    { 0x000099a4, 0x00000001 },
-    { 0x000099a8, 0x201fff00 },
-    { 0x000099ac, 0x0c6f0000 },
-    { 0x000099b0, 0x03051000 },
-    { 0x000099b4, 0x00000820 },
-    { 0x000099c4, 0x06336f77 },
-    { 0x000099c8, 0x6af6532f },
-    { 0x000099cc, 0x08f186c8 },
-    { 0x000099d0, 0x00046384 },
-    { 0x000099dc, 0x00000000 },
-    { 0x000099e0, 0x00000000 },
-    { 0x000099e4, 0xaaaaaaaa },
-    { 0x000099e8, 0x3c466478 },
-    { 0x000099ec, 0x0cc80caa },
-    { 0x000099f0, 0x00000000 },
-    { 0x000099fc, 0x00001042 },
-    { 0x0000a208, 0x803e4788 },
-    { 0x0000a210, 0x4080a333 },
-    { 0x0000a214, 0x40206c10 },
-    { 0x0000a218, 0x009c4060 },
-    { 0x0000a220, 0x01834061 },
-    { 0x0000a224, 0x00000400 },
-    { 0x0000a228, 0x000003b5 },
-    { 0x0000a22c, 0x233f7180 },
-    { 0x0000a234, 0x20202020 },
-    { 0x0000a238, 0x20202020 },
-    { 0x0000a23c, 0x13c889af },
-    { 0x0000a240, 0x38490a20 },
-    { 0x0000a244, 0x00000000 },
-    { 0x0000a248, 0xfffffffc },
-    { 0x0000a24c, 0x00000000 },
-    { 0x0000a254, 0x00000000 },
-    { 0x0000a258, 0x0cdbd380 },
-    { 0x0000a25c, 0x0f0f0f01 },
-    { 0x0000a260, 0xdfa91f01 },
-    { 0x0000a264, 0x00418a11 },
-    { 0x0000b264, 0x00418a11 },
-    { 0x0000a268, 0x00000000 },
-    { 0x0000a26c, 0x0e79e5c6 },
-    { 0x0000b26c, 0x0e79e5c6 },
-    { 0x0000d270, 0x00820820 },
-    { 0x0000a278, 0x1ce739ce },
-    { 0x0000a27c, 0x050701ce },
-    { 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, 0x1ce739ce },
-    { 0x0000a398, 0x000001ce },
-    { 0x0000b398, 0x000001ce },
-    { 0x0000a39c, 0x00000001 },
-    { 0x0000a3c8, 0x00000246 },
-    { 0x0000a3cc, 0x20202020 },
-    { 0x0000a3d0, 0x20202020 },
-    { 0x0000a3d4, 0x20202020 },
-    { 0x0000a3dc, 0x1ce739ce },
-    { 0x0000a3e0, 0x000001ce },
-    { 0x0000a3e4, 0x00000000 },
-    { 0x0000a3e8, 0x18c43433 },
-    { 0x0000a3ec, 0x00f70081 },
-    { 0x0000a3f0, 0x01036a1e },
-    { 0x0000a3f4, 0x00000000 },
-    { 0x0000b3f4, 0x00000000 },
-    { 0x0000a7d8, 0x000003f1 },
-    { 0x00007800, 0x00000800 },
-    { 0x00007804, 0x6c35ffd2 },
-    { 0x00007808, 0x6db6c000 },
-    { 0x0000780c, 0x6db6cb30 },
-    { 0x00007810, 0x6db6cb6c },
-    { 0x00007814, 0x0501e200 },
-    { 0x00007818, 0x0094128d },
-    { 0x0000781c, 0x976ee392 },
-    { 0x00007820, 0xf75ff6fc },
-    { 0x00007824, 0x00040000 },
-    { 0x00007828, 0xdb003012 },
-    { 0x0000782c, 0x04924914 },
-    { 0x00007830, 0x21084210 },
-    { 0x00007834, 0x00140000 },
-    { 0x00007838, 0x0e4548d8 },
-    { 0x0000783c, 0x54214514 },
-    { 0x00007840, 0x02025830 },
-    { 0x00007844, 0x71c0d388 },
-    { 0x00007848, 0x934934a8 },
-    { 0x00007850, 0x00000000 },
-    { 0x00007854, 0x00000800 },
-    { 0x00007858, 0x6c35ffd2 },
-    { 0x0000785c, 0x6db6c000 },
-    { 0x00007860, 0x6db6cb30 },
-    { 0x00007864, 0x6db6cb6c },
-    { 0x00007868, 0x0501e200 },
-    { 0x0000786c, 0x0094128d },
-    { 0x00007870, 0x976ee392 },
-    { 0x00007874, 0xf75ff6fc },
-    { 0x00007878, 0x00040000 },
-    { 0x0000787c, 0xdb003012 },
-    { 0x00007880, 0x04924914 },
-    { 0x00007884, 0x21084210 },
-    { 0x00007888, 0x001b6db0 },
-    { 0x0000788c, 0x00376b63 },
-    { 0x00007890, 0x06db6db6 },
-    { 0x00007894, 0x006d8000 },
-    { 0x00007898, 0x48100000 },
-    { 0x0000789c, 0x00000000 },
-    { 0x000078a0, 0x08000000 },
-    { 0x000078a4, 0x0007ffd8 },
-    { 0x000078a8, 0x0007ffd8 },
-    { 0x000078ac, 0x001c0020 },
-    { 0x000078b0, 0x00060aeb },
-    { 0x000078b4, 0x40008080 },
-    { 0x000078b8, 0x2a850160 },
+	/* Addr      allmodes  */
+	{0x0000000c, 0x00000000},
+	{0x00000030, 0x00020015},
+	{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, 0x00000033},
+	{0x00007020, 0x00000000},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000700},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008048, 0x40000000},
+	{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},
+	{0x00008124, 0x00000000},
+	{0x00008128, 0x00000000},
+	{0x0000812c, 0x00000000},
+	{0x00008130, 0x00000000},
+	{0x00008134, 0x00000000},
+	{0x00008138, 0x00000000},
+	{0x0000813c, 0x00000000},
+	{0x00008144, 0xffffffff},
+	{0x00008168, 0x00000000},
+	{0x0000816c, 0x00000000},
+	{0x00008170, 0x18487320},
+	{0x00008174, 0xfaa4fa50},
+	{0x00008178, 0x00000100},
+	{0x0000817c, 0x00000000},
+	{0x000081c0, 0x00000000},
+	{0x000081c4, 0x00000000},
+	{0x000081d4, 0x00000000},
+	{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, 0x88a00010},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000000},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x000000ff},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x0000829c, 0x00000000},
+	{0x00008300, 0x00000040},
+	{0x00008314, 0x00000000},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000e00},
+	{0x00008338, 0x00ff0000},
+	{0x0000833c, 0x00000000},
+	{0x00008340, 0x000107ff},
+	{0x00008344, 0x01c81043},
+	{0x00008360, 0xffffffff},
+	{0x00008364, 0xffffffff},
+	{0x00008368, 0x00000000},
+	{0x00008370, 0x00000000},
+	{0x00008374, 0x000000ff},
+	{0x00008378, 0x00000000},
+	{0x0000837c, 0x00000000},
+	{0x00008380, 0xffffffff},
+	{0x00008384, 0xffffffff},
+	{0x00008390, 0x0fffffff},
+	{0x00008394, 0x0fffffff},
+	{0x00008398, 0x00000000},
+	{0x0000839c, 0x00000000},
+	{0x000083a0, 0x00000000},
+	{0x00009808, 0x00000000},
+	{0x0000980c, 0xafe68e30},
+	{0x00009810, 0xfd14e000},
+	{0x00009814, 0x9c0a9f6b},
+	{0x0000981c, 0x00000000},
+	{0x0000982c, 0x0000a000},
+	{0x00009830, 0x00000000},
+	{0x0000983c, 0x00200400},
+	{0x0000984c, 0x0040233c},
+	{0x0000a84c, 0x0040233c},
+	{0x00009854, 0x00000044},
+	{0x00009900, 0x00000000},
+	{0x00009904, 0x00000000},
+	{0x00009908, 0x00000000},
+	{0x0000990c, 0x00000000},
+	{0x00009910, 0x10002310},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x04900000},
+	{0x0000a920, 0x04900000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009930, 0x00000000},
+	{0x0000a930, 0x00000000},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009948, 0x9280c00a},
+	{0x0000994c, 0x00020028},
+	{0x00009954, 0x5f3ca3de},
+	{0x00009958, 0x0108ecff},
+	{0x00009940, 0x14750604},
+	{0x0000c95c, 0x004b6a8e},
+	{0x00009970, 0x990bb514},
+	{0x00009974, 0x00000000},
+	{0x00009978, 0x00000001},
+	{0x0000997c, 0x00000000},
+	{0x000099a0, 0x00000000},
+	{0x000099a4, 0x00000001},
+	{0x000099a8, 0x201fff00},
+	{0x000099ac, 0x0c6f0000},
+	{0x000099b0, 0x03051000},
+	{0x000099b4, 0x00000820},
+	{0x000099c4, 0x06336f77},
+	{0x000099c8, 0x6af6532f},
+	{0x000099cc, 0x08f186c8},
+	{0x000099d0, 0x00046384},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000000},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x0cc80caa},
+	{0x000099f0, 0x00000000},
+	{0x000099fc, 0x00001042},
+	{0x0000a208, 0x803e4788},
+	{0x0000a210, 0x4080a333},
+	{0x0000a214, 0x40206c10},
+	{0x0000a218, 0x009c4060},
+	{0x0000a220, 0x01834061},
+	{0x0000a224, 0x00000400},
+	{0x0000a228, 0x000003b5},
+	{0x0000a22c, 0x233f7180},
+	{0x0000a234, 0x20202020},
+	{0x0000a238, 0x20202020},
+	{0x0000a23c, 0x13c889af},
+	{0x0000a240, 0x38490a20},
+	{0x0000a244, 0x00000000},
+	{0x0000a248, 0xfffffffc},
+	{0x0000a24c, 0x00000000},
+	{0x0000a254, 0x00000000},
+	{0x0000a258, 0x0cdbd380},
+	{0x0000a25c, 0x0f0f0f01},
+	{0x0000a260, 0xdfa91f01},
+	{0x0000a264, 0x00418a11},
+	{0x0000b264, 0x00418a11},
+	{0x0000a268, 0x00000000},
+	{0x0000a26c, 0x0e79e5c6},
+	{0x0000b26c, 0x0e79e5c6},
+	{0x0000d270, 0x00820820},
+	{0x0000a278, 0x1ce739ce},
+	{0x0000a27c, 0x050701ce},
+	{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, 0x1ce739ce},
+	{0x0000a398, 0x000001ce},
+	{0x0000b398, 0x000001ce},
+	{0x0000a39c, 0x00000001},
+	{0x0000a3c8, 0x00000246},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3dc, 0x1ce739ce},
+	{0x0000a3e0, 0x000001ce},
+	{0x0000a3e4, 0x00000000},
+	{0x0000a3e8, 0x18c43433},
+	{0x0000a3ec, 0x00f70081},
+	{0x0000a3f0, 0x01036a1e},
+	{0x0000a3f4, 0x00000000},
+	{0x0000b3f4, 0x00000000},
+	{0x0000a7d8, 0x000003f1},
+	{0x00007800, 0x00000800},
+	{0x00007804, 0x6c35ffd2},
+	{0x00007808, 0x6db6c000},
+	{0x0000780c, 0x6db6cb30},
+	{0x00007810, 0x6db6cb6c},
+	{0x00007814, 0x0501e200},
+	{0x00007818, 0x0094128d},
+	{0x0000781c, 0x976ee392},
+	{0x00007820, 0xf75ff6fc},
+	{0x00007824, 0x00040000},
+	{0x00007828, 0xdb003012},
+	{0x0000782c, 0x04924914},
+	{0x00007830, 0x21084210},
+	{0x00007834, 0x00140000},
+	{0x00007838, 0x0e4548d8},
+	{0x0000783c, 0x54214514},
+	{0x00007840, 0x02025830},
+	{0x00007844, 0x71c0d388},
+	{0x00007848, 0x934934a8},
+	{0x00007850, 0x00000000},
+	{0x00007854, 0x00000800},
+	{0x00007858, 0x6c35ffd2},
+	{0x0000785c, 0x6db6c000},
+	{0x00007860, 0x6db6cb30},
+	{0x00007864, 0x6db6cb6c},
+	{0x00007868, 0x0501e200},
+	{0x0000786c, 0x0094128d},
+	{0x00007870, 0x976ee392},
+	{0x00007874, 0xf75ff6fc},
+	{0x00007878, 0x00040000},
+	{0x0000787c, 0xdb003012},
+	{0x00007880, 0x04924914},
+	{0x00007884, 0x21084210},
+	{0x00007888, 0x001b6db0},
+	{0x0000788c, 0x00376b63},
+	{0x00007890, 0x06db6db6},
+	{0x00007894, 0x006d8000},
+	{0x00007898, 0x48100000},
+	{0x0000789c, 0x00000000},
+	{0x000078a0, 0x08000000},
+	{0x000078a4, 0x0007ffd8},
+	{0x000078a8, 0x0007ffd8},
+	{0x000078ac, 0x001c0020},
+	{0x000078b0, 0x00060aeb},
+	{0x000078b4, 0x40008080},
+	{0x000078b8, 0x2a850160},
 };
 
-/*
- * For Japanese regulatory requirements, 2484 MHz requires the following three
- * registers be programmed differently from the channel between 2412 and
- * 2472 MHz.
- */
-static const u32 ar9287Common_normal_cck_fir_coeff_92871_1[][2] = {
-    { 0x0000a1f4, 0x00fffeff },
-    { 0x0000a1f8, 0x00f5f9ff },
-    { 0x0000a1fc, 0xb79f6427 },
+static const u32 ar9287Common_normal_cck_fir_coeff_9287_1_1[][2] = {
+	/* Addr      allmodes  */
+	{0x0000a1f4, 0x00fffeff},
+	{0x0000a1f8, 0x00f5f9ff},
+	{0x0000a1fc, 0xb79f6427},
 };
 
-static const u32 ar9287Common_japan_2484_cck_fir_coeff_92871_1[][2] = {
-    { 0x0000a1f4, 0x00000000 },
-    { 0x0000a1f8, 0xefff0301 },
-    { 0x0000a1fc, 0xca9228ee },
+static const u32 ar9287Common_japan_2484_cck_fir_coeff_9287_1_1[][2] = {
+	/* Addr      allmodes  */
+	{0x0000a1f4, 0x00000000},
+	{0x0000a1f8, 0xefff0301},
+	{0x0000a1fc, 0xca9228ee},
 };
 
 static const u32 ar9287Modes_tx_gain_9287_1_1[][6] = {
-    /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
-    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 },
-    { 0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004 },
-    { 0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a },
-    { 0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c },
-    { 0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b },
-    { 0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a },
-    { 0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a },
-    { 0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a },
-    { 0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a },
-    { 0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a },
-    { 0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a },
-    { 0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c },
-    { 0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc },
-    { 0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4 },
-    { 0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc },
-    { 0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede },
-    { 0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e },
-    { 0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e },
-    { 0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e },
-    { 0x0000a780, 0x00000000, 0x00000000, 0x00000062, 0x00000062, 0x00000062 },
-    { 0x0000a784, 0x00000000, 0x00000000, 0x00004064, 0x00004064, 0x00004064 },
-    { 0x0000a788, 0x00000000, 0x00000000, 0x000080a4, 0x000080a4, 0x000080a4 },
-    { 0x0000a78c, 0x00000000, 0x00000000, 0x0000c0aa, 0x0000c0aa, 0x0000c0aa },
-    { 0x0000a790, 0x00000000, 0x00000000, 0x000100ac, 0x000100ac, 0x000100ac },
-    { 0x0000a794, 0x00000000, 0x00000000, 0x000140b4, 0x000140b4, 0x000140b4 },
-    { 0x0000a798, 0x00000000, 0x00000000, 0x000180f4, 0x000180f4, 0x000180f4 },
-    { 0x0000a79c, 0x00000000, 0x00000000, 0x0001c134, 0x0001c134, 0x0001c134 },
-    { 0x0000a7a0, 0x00000000, 0x00000000, 0x00020174, 0x00020174, 0x00020174 },
-    { 0x0000a7a4, 0x00000000, 0x00000000, 0x0002417c, 0x0002417c, 0x0002417c },
-    { 0x0000a7a8, 0x00000000, 0x00000000, 0x0002817e, 0x0002817e, 0x0002817e },
-    { 0x0000a7ac, 0x00000000, 0x00000000, 0x0002c1be, 0x0002c1be, 0x0002c1be },
-    { 0x0000a7b0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
-    { 0x0000a7b4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
-    { 0x0000a7b8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
-    { 0x0000a7bc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
-    { 0x0000a7c0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
-    { 0x0000a7c4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
-    { 0x0000a7c8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
-    { 0x0000a7cc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
-    { 0x0000a7d0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
-    { 0x0000a7d4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
-    { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 },
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a},
+	{0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b},
+	{0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a},
+	{0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a},
+	{0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a},
+	{0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a},
+	{0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a},
+	{0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a},
+	{0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c},
+	{0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc},
+	{0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4},
+	{0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc},
+	{0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede},
+	{0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e},
+	{0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e},
+	{0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e},
+	{0x0000a780, 0x00000000, 0x00000000, 0x00000062, 0x00000062, 0x00000062},
+	{0x0000a784, 0x00000000, 0x00000000, 0x00004064, 0x00004064, 0x00004064},
+	{0x0000a788, 0x00000000, 0x00000000, 0x000080a4, 0x000080a4, 0x000080a4},
+	{0x0000a78c, 0x00000000, 0x00000000, 0x0000c0aa, 0x0000c0aa, 0x0000c0aa},
+	{0x0000a790, 0x00000000, 0x00000000, 0x000100ac, 0x000100ac, 0x000100ac},
+	{0x0000a794, 0x00000000, 0x00000000, 0x000140b4, 0x000140b4, 0x000140b4},
+	{0x0000a798, 0x00000000, 0x00000000, 0x000180f4, 0x000180f4, 0x000180f4},
+	{0x0000a79c, 0x00000000, 0x00000000, 0x0001c134, 0x0001c134, 0x0001c134},
+	{0x0000a7a0, 0x00000000, 0x00000000, 0x00020174, 0x00020174, 0x00020174},
+	{0x0000a7a4, 0x00000000, 0x00000000, 0x0002417c, 0x0002417c, 0x0002417c},
+	{0x0000a7a8, 0x00000000, 0x00000000, 0x0002817e, 0x0002817e, 0x0002817e},
+	{0x0000a7ac, 0x00000000, 0x00000000, 0x0002c1be, 0x0002c1be, 0x0002c1be},
+	{0x0000a7b0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7b4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7b8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7bc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7c0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7c4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7c8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7cc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7d0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7d4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000},
 };
 
 static const u32 ar9287Modes_rx_gain_9287_1_1[][6] = {
-    /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
-    { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
-    { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
-    { 0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
-    { 0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
-    { 0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
-    { 0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
-    { 0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
-    { 0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
-    { 0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
-    { 0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
-    { 0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
-    { 0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
-    { 0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
-    { 0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
-    { 0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
-    { 0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
-    { 0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
-    { 0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
-    { 0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
-    { 0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
-    { 0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
-    { 0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
-    { 0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
-    { 0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
-    { 0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
-    { 0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
-    { 0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
-    { 0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
-    { 0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
-    { 0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
-    { 0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
-    { 0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
-    { 0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
-    { 0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
-    { 0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
-    { 0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
-    { 0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
-    { 0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
-    { 0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
-    { 0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
-    { 0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
-    { 0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
-    { 0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
-    { 0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
-    { 0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
-    { 0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
-    { 0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
-    { 0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
-    { 0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
-    { 0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
-    { 0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
-    { 0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
-    { 0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
-    { 0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
-    { 0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
-    { 0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
-    { 0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
-    { 0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
-    { 0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
-    { 0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
-    { 0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
-    { 0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
-    { 0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
-    { 0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
-    { 0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
-    { 0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
-    { 0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
-    { 0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
-    { 0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
-    { 0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
-    { 0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
-    { 0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
-    { 0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
-    { 0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
-    { 0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
-    { 0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
-    { 0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
-    { 0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
-    { 0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
-    { 0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
-    { 0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
-    { 0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
-    { 0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
-    { 0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
-    { 0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
-    { 0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
-    { 0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
-    { 0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
-    { 0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
-    { 0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
-    { 0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
-    { 0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
-    { 0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
-    { 0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
-    { 0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
-    { 0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
-    { 0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
-    { 0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
-    { 0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
-    { 0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
-    { 0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
-    { 0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
-    { 0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
-    { 0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
-    { 0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
-    { 0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
-    { 0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
-    { 0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
-    { 0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
-    { 0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
-    { 0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
-    { 0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
-    { 0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
-    { 0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
-    { 0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
-    { 0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
-    { 0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
-    { 0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
-    { 0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
-    { 0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
-    { 0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
-    { 0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
-    { 0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
-    { 0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
-    { 0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
-    { 0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
-    { 0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
-    { 0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
-    { 0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
-    { 0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
-    { 0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
-    { 0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
-    { 0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
-    { 0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
-    { 0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
-    { 0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
-    { 0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
-    { 0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
-    { 0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
-    { 0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
-    { 0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
-    { 0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
-    { 0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
-    { 0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
-    { 0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
-    { 0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
-    { 0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
-    { 0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
-    { 0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
-    { 0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
-    { 0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
-    { 0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
-    { 0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
-    { 0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
-    { 0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
-    { 0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
-    { 0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
-    { 0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
-    { 0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
-    { 0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
-    { 0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
-    { 0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
-    { 0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
-    { 0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
-    { 0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
-    { 0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
-    { 0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
-    { 0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
-    { 0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
-    { 0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
-    { 0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
-    { 0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
-    { 0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
-    { 0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
-    { 0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
-    { 0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
-    { 0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
-    { 0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
-    { 0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
-    { 0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
-    { 0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
-    { 0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
-    { 0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
-    { 0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
-    { 0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
-    { 0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
-    { 0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
-    { 0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
-    { 0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
-    { 0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
-    { 0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
-    { 0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
-    { 0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
-    { 0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
-    { 0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
-    { 0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
-    { 0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
-    { 0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
-    { 0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
-    { 0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
-    { 0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
-    { 0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
-    { 0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
-    { 0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
-    { 0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
-    { 0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
-    { 0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
-    { 0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
-    { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
+	{0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120},
+	{0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124},
+	{0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128},
+	{0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c},
+	{0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130},
+	{0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194},
+	{0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198},
+	{0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c},
+	{0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210},
+	{0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284},
+	{0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288},
+	{0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c},
+	{0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290},
+	{0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294},
+	{0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0},
+	{0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4},
+	{0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8},
+	{0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac},
+	{0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0},
+	{0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4},
+	{0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8},
+	{0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4},
+	{0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708},
+	{0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c},
+	{0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710},
+	{0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04},
+	{0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08},
+	{0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c},
+	{0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10},
+	{0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14},
+	{0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18},
+	{0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c},
+	{0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90},
+	{0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94},
+	{0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98},
+	{0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4},
+	{0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8},
+	{0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04},
+	{0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08},
+	{0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c},
+	{0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10},
+	{0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14},
+	{0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18},
+	{0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c},
+	{0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90},
+	{0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18},
+	{0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24},
+	{0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28},
+	{0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314},
+	{0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318},
+	{0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c},
+	{0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390},
+	{0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394},
+	{0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398},
+	{0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4},
+	{0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8},
+	{0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac},
+	{0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0},
+	{0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380},
+	{0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384},
+	{0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388},
+	{0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710},
+	{0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714},
+	{0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718},
+	{0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10},
+	{0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14},
+	{0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18},
+	{0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c},
+	{0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90},
+	{0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94},
+	{0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c},
+	{0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90},
+	{0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94},
+	{0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0},
+	{0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4},
+	{0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8},
+	{0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac},
+	{0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0},
+	{0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4},
+	{0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1},
+	{0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5},
+	{0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9},
+	{0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad},
+	{0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1},
+	{0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5},
+	{0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9},
+	{0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5},
+	{0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9},
+	{0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd},
+	{0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1},
+	{0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5},
+	{0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2},
+	{0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6},
+	{0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca},
+	{0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce},
+	{0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2},
+	{0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6},
+	{0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda},
+	{0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7},
+	{0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb},
+	{0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf},
+	{0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3},
+	{0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7},
+	{0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120},
+	{0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124},
+	{0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128},
+	{0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c},
+	{0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130},
+	{0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194},
+	{0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198},
+	{0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c},
+	{0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210},
+	{0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284},
+	{0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288},
+	{0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c},
+	{0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290},
+	{0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294},
+	{0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0},
+	{0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4},
+	{0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8},
+	{0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac},
+	{0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0},
+	{0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4},
+	{0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8},
+	{0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4},
+	{0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708},
+	{0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c},
+	{0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710},
+	{0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04},
+	{0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08},
+	{0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c},
+	{0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10},
+	{0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14},
+	{0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18},
+	{0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c},
+	{0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90},
+	{0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94},
+	{0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98},
+	{0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4},
+	{0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8},
+	{0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04},
+	{0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08},
+	{0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c},
+	{0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10},
+	{0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14},
+	{0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18},
+	{0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c},
+	{0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90},
+	{0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18},
+	{0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24},
+	{0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28},
+	{0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314},
+	{0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318},
+	{0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c},
+	{0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390},
+	{0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394},
+	{0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398},
+	{0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4},
+	{0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8},
+	{0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac},
+	{0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0},
+	{0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380},
+	{0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384},
+	{0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388},
+	{0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710},
+	{0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714},
+	{0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718},
+	{0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10},
+	{0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14},
+	{0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18},
+	{0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c},
+	{0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90},
+	{0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94},
+	{0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c},
+	{0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90},
+	{0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94},
+	{0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0},
+	{0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4},
+	{0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8},
+	{0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac},
+	{0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0},
+	{0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4},
+	{0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1},
+	{0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5},
+	{0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9},
+	{0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad},
+	{0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1},
+	{0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5},
+	{0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9},
+	{0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5},
+	{0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9},
+	{0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd},
+	{0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1},
+	{0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5},
+	{0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2},
+	{0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6},
+	{0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca},
+	{0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce},
+	{0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2},
+	{0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6},
+	{0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda},
+	{0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7},
+	{0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb},
+	{0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf},
+	{0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3},
+	{0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7},
+	{0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067},
+	{0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067},
 };
 
 static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = {
-    {0x00004040,  0x9248fd00 },
-    {0x00004040,  0x24924924 },
-    {0x00004040,  0xa8000019 },
-    {0x00004040,  0x13160820 },
-    {0x00004040,  0xe5980560 },
-    {0x00004040,  0xc01dcffd },
-    {0x00004040,  0x1aaabe41 },
-    {0x00004040,  0xbe105554 },
-    {0x00004040,  0x00043007 },
-    {0x00004044,  0x00000000 },
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffd},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
 };
 
 static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = {
-    {0x00004040,  0x9248fd00 },
-    {0x00004040,  0x24924924 },
-    {0x00004040,  0xa8000019 },
-    {0x00004040,  0x13160820 },
-    {0x00004040,  0xe5980560 },
-    {0x00004040,  0xc01dcffc },
-    {0x00004040,  0x1aaabe41 },
-    {0x00004040,  0xbe105554 },
-    {0x00004040,  0x00043007 },
-    {0x00004044,  0x00000000 },
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffc},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
 };
 
-
-/* AR9271 initialization values automaticaly created: 06/04/09 */
 static const u32 ar9271Modes_9271[][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, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e },
-    { 0x00009828, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001 },
-    { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
-    { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
-    { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
-    { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 },
-    { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
-    { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
-    { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
-    { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
-    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
-    { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18 },
-    { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
-    { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
-    { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
-    { 0x00009910, 0x30002310, 0x30002310, 0x30002310, 0x30002310, 0x30002310 },
-    { 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, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f },
-    { 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, 0x00058084, 0x00058084, 0x00000000 },
-    { 0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 },
-    { 0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 },
-    { 0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 },
-    { 0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 },
-    { 0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 },
-    { 0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 },
-    { 0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 },
-    { 0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 },
-    { 0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 },
-    { 0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 },
-    { 0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 },
-    { 0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 },
-    { 0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 },
-    { 0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 },
-    { 0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 },
-    { 0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 },
-    { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
-    { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
-    { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
-    { 0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
-    { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
-    { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
-    { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
-    { 0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 },
-    { 0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 },
-    { 0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 },
-    { 0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 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, 0x00078b00, 0x00078b00, 0x00000000 },
-    { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
-    { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
-    { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
-    { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
-    { 0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 },
-    { 0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 },
-    { 0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 },
-    { 0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 },
-    { 0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 },
-    { 0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 },
-    { 0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 },
-    { 0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 },
-    { 0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 },
-    { 0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 },
-    { 0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 },
-    { 0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 },
-    { 0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 },
-    { 0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 },
-    { 0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 },
-    { 0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 },
-    { 0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 },
-    { 0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 },
-    { 0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 },
-    { 0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 },
-    { 0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 },
-    { 0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 },
-    { 0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 },
-    { 0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 },
-    { 0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 },
-    { 0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 },
-    { 0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 },
-    { 0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 },
-    { 0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 },
-    { 0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 },
-    { 0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 },
-    { 0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 },
-    { 0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 },
-    { 0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 },
-    { 0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 },
-    { 0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 },
-    { 0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 },
-    { 0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 },
-    { 0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 },
-    { 0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 },
-    { 0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 },
-    { 0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 },
-    { 0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 },
-    { 0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 },
-    { 0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 },
-    { 0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 },
-    { 0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 },
-    { 0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 },
-    { 0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 },
-    { 0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 },
-    { 0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 },
-    { 0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 },
-    { 0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 },
-    { 0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 },
-    { 0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 },
-    { 0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 },
-    { 0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 },
-    { 0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 },
-    { 0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 },
-    { 0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 },
-    { 0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 },
-    { 0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 },
-    { 0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 },
-    { 0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 },
-    { 0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 },
-    { 0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 },
-    { 0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 },
-    { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
-    { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
-    { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
-    { 0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
-    { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
-    { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
-    { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
-    { 0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 },
-    { 0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 },
-    { 0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 },
-    { 0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 },
-    { 0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
-    { 0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
-    { 0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
-    { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
-    { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
-    { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
-    { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 },
-    { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
-    { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
-    { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
-    { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
-    { 0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 },
-    { 0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 },
-    { 0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 },
-    { 0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 },
-    { 0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 },
-    { 0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 },
-    { 0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 },
-    { 0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 },
-    { 0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 },
-    { 0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 },
-    { 0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 },
-    { 0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 },
-    { 0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 },
-    { 0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 },
-    { 0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 },
-    { 0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 },
-    { 0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 },
-    { 0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 },
-    { 0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 },
-    { 0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 },
-    { 0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 },
-    { 0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 },
-    { 0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 },
-    { 0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 },
-    { 0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 },
-    { 0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 },
-    { 0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 },
-    { 0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 },
-    { 0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 },
-    { 0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 },
-    { 0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 },
-    { 0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 },
-    { 0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 },
-    { 0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 },
-    { 0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 },
-    { 0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 },
-    { 0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 },
-    { 0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 },
-    { 0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 },
-    { 0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 },
-    { 0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 },
-    { 0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 },
-    { 0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 },
-    { 0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 },
-    { 0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 },
-    { 0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 },
-    { 0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 },
-    { 0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 },
-    { 0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 },
-    { 0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 },
-    { 0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
-    { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
-    { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
-    { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
-    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
-    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
-    { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+	{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, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+	{0x00009828, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001},
+	{0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+	{0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e},
+	{0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0},
+	{0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
+	{0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
+	{0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
+	{0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+	{0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e},
+	{0x00009860, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
+	{0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+	{0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881},
+	{0x00009910, 0x30002310, 0x30002310, 0x30002310, 0x30002310, 0x30002310},
+	{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, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f},
+	{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, 0x00058084, 0x00058084, 0x00000000},
+	{0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
+	{0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
+	{0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
+	{0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
+	{0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
+	{0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
+	{0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
+	{0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
+	{0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
+	{0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
+	{0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
+	{0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
+	{0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
+	{0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
+	{0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
+	{0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
+	{0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
+	{0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
+	{0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
+	{0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
+	{0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
+	{0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
+	{0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
+	{0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
+	{0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
+	{0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
+	{0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 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, 0x00078b00, 0x00078b00, 0x00000000},
+	{0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
+	{0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
+	{0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
+	{0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
+	{0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
+	{0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
+	{0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
+	{0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
+	{0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
+	{0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
+	{0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
+	{0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
+	{0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
+	{0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
+	{0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
+	{0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
+	{0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
+	{0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
+	{0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
+	{0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
+	{0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
+	{0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
+	{0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
+	{0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
+	{0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
+	{0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
+	{0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
+	{0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
+	{0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
+	{0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
+	{0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
+	{0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
+	{0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
+	{0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
+	{0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
+	{0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
+	{0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
+	{0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
+	{0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
+	{0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
+	{0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
+	{0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
+	{0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
+	{0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
+	{0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
+	{0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
+	{0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
+	{0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
+	{0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
+	{0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
+	{0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
+	{0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
+	{0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
+	{0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
+	{0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
+	{0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
+	{0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
+	{0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
+	{0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
+	{0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
+	{0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
+	{0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
+	{0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
+	{0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
+	{0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
+	{0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
+	{0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
+	{0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
+	{0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
+	{0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
+	{0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
+	{0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
+	{0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
+	{0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
+	{0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
+	{0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
+	{0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
+	{0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
+	{0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
+	{0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
+	{0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
+	{0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
+	{0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
+	{0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
+	{0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
+	{0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
+	{0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
+	{0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
+	{0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
+	{0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
+	{0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
+	{0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
+	{0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
+	{0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
+	{0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
+	{0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
+	{0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
+	{0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
+	{0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
+	{0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
+	{0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
+	{0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
+	{0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
+	{0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
+	{0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
+	{0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
+	{0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
+	{0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
+	{0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
+	{0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
+	{0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
+	{0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
+	{0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
+	{0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
+	{0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
+	{0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
+	{0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
+	{0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
+	{0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
+	{0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
+	{0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
+	{0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
+	{0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
+	{0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
+	{0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
+	{0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
+	{0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
+	{0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
+	{0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
+	{0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
+	{0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
+	{0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
+	{0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
+	{0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
+	{0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
+	{0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
+	{0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
+	{0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
+	{0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
+	{0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
+	{0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
+	{0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
+	{0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
+	{0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004},
+	{0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
+	{0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
+	{0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000},
+	{0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
 };
 
 static const u32 ar9271Common_9271[][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 },
-    { 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 },
-    { 0x000080b0, 0x00000000 },
-    { 0x000080b4, 0x00000000 },
-    { 0x000080b8, 0x00000000 },
-    { 0x000080bc, 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, 0x08f04810 },
-    { 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, 0x0000320a },
-    { 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, 0x88a00010 },
-    { 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 },
-    { 0x00007010, 0x00000030 },
-    { 0x00007034, 0x00000002 },
-    { 0x00007038, 0x000004c2 },
-    { 0x00007800, 0x00140000 },
-    { 0x00007804, 0x0e4548d8 },
-    { 0x00007808, 0x54214514 },
-    { 0x0000780c, 0x02025820 },
-    { 0x00007810, 0x71c0d388 },
-    { 0x00007814, 0x924934a8 },
-    { 0x0000781c, 0x00000000 },
-    { 0x00007828, 0x66964300 },
-    { 0x0000782c, 0x8db6d961 },
-    { 0x00007830, 0x8db6d96c },
-    { 0x00007834, 0x6140008b },
-    { 0x0000783c, 0x72ee0a72 },
-    { 0x00007840, 0xbbfffffc },
-    { 0x00007844, 0x000c0db6 },
-    { 0x00007848, 0x6db61b6f },
-    { 0x0000784c, 0x6d9b66db },
-    { 0x00007850, 0x6d8c6dba },
-    { 0x00007854, 0x00040000 },
-    { 0x00007858, 0xdb003012 },
-    { 0x0000785c, 0x04924914 },
-    { 0x00007860, 0x21084210 },
-    { 0x00007864, 0xf7d7ffde },
-    { 0x00007868, 0xc2034080 },
-    { 0x00007870, 0x10142c00 },
-    { 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 },
-    { 0x0000991c, 0x10000fff },
-    { 0x00009920, 0x04900000 },
-    { 0x00009928, 0x00000001 },
-    { 0x0000992c, 0x00000004 },
-    { 0x00009934, 0x1e1f2022 },
-    { 0x00009938, 0x0a0b0c0d },
-    { 0x0000993c, 0x00000000 },
-    { 0x00009940, 0x14750604 },
-    { 0x00009948, 0x9280c00a },
-    { 0x0000994c, 0x00020028 },
-    { 0x00009954, 0x5f3ca3de },
-    { 0x00009958, 0x0108ecff },
-    { 0x00009968, 0x000003ce },
-    { 0x00009970, 0x192bb514 },
-    { 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, 0x2def0400 },
-    { 0x000099b0, 0x03051000 },
-    { 0x000099b4, 0x00000820 },
-    { 0x000099dc, 0x00000000 },
-    { 0x000099e0, 0x00000000 },
-    { 0x000099e4, 0xaaaaaaaa },
-    { 0x000099e8, 0x3c466478 },
-    { 0x000099ec, 0x0cc80caa },
-    { 0x000099f0, 0x00000000 },
-    { 0x0000a208, 0x803e68c8 },
-    { 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 },
-    { 0x0000a388, 0x0c000000 },
-    { 0x0000a38c, 0x20202020 },
-    { 0x0000a390, 0x20202020 },
-    { 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 },
-    { 0x0000a3e4, 0x00000000 },
-    { 0x0000a3e8, 0x18c43433 },
-    { 0x0000a3ec, 0x00f70081 },
-    { 0x0000a3f0, 0x01036a2f },
-    { 0x0000a3f4, 0x00000000 },
-    { 0x0000d270, 0x0d820820 },
-    { 0x0000d35c, 0x07ffffef },
-    { 0x0000d360, 0x0fffffe7 },
-    { 0x0000d364, 0x17ffffe5 },
-    { 0x0000d368, 0x1fffffe4 },
-    { 0x0000d36c, 0x37ffffe3 },
-    { 0x0000d370, 0x3fffffe3 },
-    { 0x0000d374, 0x57ffffe3 },
-    { 0x0000d378, 0x5fffffe2 },
-    { 0x0000d37c, 0x7fffffe2 },
-    { 0x0000d380, 0x7f3c7bba },
-    { 0x0000d384, 0xf3307ff0 },
+	/* Addr      allmodes  */
+	{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},
+	{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},
+	{0x000080b0, 0x00000000},
+	{0x000080b4, 0x00000000},
+	{0x000080b8, 0x00000000},
+	{0x000080bc, 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, 0x08f04810},
+	{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, 0x0000320a},
+	{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, 0x88a00010},
+	{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},
+	{0x00007010, 0x00000030},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+	{0x00007800, 0x00140000},
+	{0x00007804, 0x0e4548d8},
+	{0x00007808, 0x54214514},
+	{0x0000780c, 0x02025820},
+	{0x00007810, 0x71c0d388},
+	{0x00007814, 0x924934a8},
+	{0x0000781c, 0x00000000},
+	{0x00007828, 0x66964300},
+	{0x0000782c, 0x8db6d961},
+	{0x00007830, 0x8db6d96c},
+	{0x00007834, 0x6140008b},
+	{0x0000783c, 0x72ee0a72},
+	{0x00007840, 0xbbfffffc},
+	{0x00007844, 0x000c0db6},
+	{0x00007848, 0x6db6246f},
+	{0x0000784c, 0x6d9b66db},
+	{0x00007850, 0x6d8c6dba},
+	{0x00007854, 0x00040000},
+	{0x00007858, 0xdb003012},
+	{0x0000785c, 0x04924914},
+	{0x00007860, 0x21084210},
+	{0x00007864, 0xf7d7ffde},
+	{0x00007868, 0xc2034080},
+	{0x00007870, 0x10142c00},
+	{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},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x04900000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009940, 0x14750604},
+	{0x00009948, 0x9280c00a},
+	{0x0000994c, 0x00020028},
+	{0x00009954, 0x5f3ca3de},
+	{0x00009958, 0x0108ecff},
+	{0x00009968, 0x000003ce},
+	{0x00009970, 0x192bb514},
+	{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, 0x2def0400},
+	{0x000099b0, 0x03051000},
+	{0x000099b4, 0x00000820},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000000},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x0cc80caa},
+	{0x000099f0, 0x00000000},
+	{0x0000a208, 0x803e68c8},
+	{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},
+	{0x0000a388, 0x0c000000},
+	{0x0000a38c, 0x20202020},
+	{0x0000a390, 0x20202020},
+	{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},
+	{0x0000a3e4, 0x00000000},
+	{0x0000a3e8, 0x18c43433},
+	{0x0000a3ec, 0x00f70081},
+	{0x0000a3f0, 0x01036a2f},
+	{0x0000a3f4, 0x00000000},
+	{0x0000d270, 0x0d820820},
+	{0x0000d35c, 0x07ffffef},
+	{0x0000d360, 0x0fffffe7},
+	{0x0000d364, 0x17ffffe5},
+	{0x0000d368, 0x1fffffe4},
+	{0x0000d36c, 0x37ffffe3},
+	{0x0000d370, 0x3fffffe3},
+	{0x0000d374, 0x57ffffe3},
+	{0x0000d378, 0x5fffffe2},
+	{0x0000d37c, 0x7fffffe2},
+	{0x0000d380, 0x7f3c7bba},
+	{0x0000d384, 0xf3307ff0},
 };
 
 static const u32 ar9271Common_normal_cck_fir_coeff_9271[][2] = {
-    { 0x0000a1f4, 0x00fffeff },
-    { 0x0000a1f8, 0x00f5f9ff },
-    { 0x0000a1fc, 0xb79f6427 },
+	/* Addr      allmodes  */
+	{0x0000a1f4, 0x00fffeff},
+	{0x0000a1f8, 0x00f5f9ff},
+	{0x0000a1fc, 0xb79f6427},
 };
 
 static const u32 ar9271Common_japan_2484_cck_fir_coeff_9271[][2] = {
-    { 0x0000a1f4, 0x00000000 },
-    { 0x0000a1f8, 0xefff0301 },
-    { 0x0000a1fc, 0xca9228ee },
+	/* Addr      allmodes  */
+	{0x0000a1f4, 0x00000000},
+	{0x0000a1f8, 0xefff0301},
+	{0x0000a1fc, 0xca9228ee},
 };
 
 static const u32 ar9271Modes_9271_1_0_only[][6] = {
-    { 0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311, 0x30002311 },
-    { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
+	{0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311, 0x30002311},
+	{0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
 };
 
 static const u32 ar9271Modes_9271_ANI_reg[][6] = {
-    { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
-    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
-    { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
-    { 0x0000986c, 0x06903881, 0x06903881, 0x06903881, 0x06903881, 0x06903881 },
-    { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
-    { 0x0000a208, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8 },
-    { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d },
-    { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+	{0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
+	{0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e},
+	{0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+	{0x0000986c, 0x06903881, 0x06903881, 0x06903881, 0x06903881, 0x06903881},
+	{0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x0000a208, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8},
+	{0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d},
+	{0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
 };
 
 static const u32 ar9271Modes_normal_power_tx_gain_9271[][6] = {
-    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
-    { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 },
-    { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 },
-    { 0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000 },
-    { 0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000 },
-    { 0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000 },
-    { 0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000 },
-    { 0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000 },
-    { 0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000 },
-    { 0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000 },
-    { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 },
-    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
-    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
-    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x00007838, 0x00000029, 0x00000029, 0x00000029, 0x00000029, 0x00000029 },
-    { 0x00007824, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff },
-    { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 },
-    { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 },
-    { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652 },
-    { 0x0000a278, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd },
-    { 0x0000a27c, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd },
-    { 0x0000a394, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd },
-    { 0x0000a398, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd },
-    { 0x0000a3dc, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd },
-    { 0x0000a3e0, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd },
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000},
+	{0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000},
+	{0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000},
+	{0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000},
+	{0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000},
+	{0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000},
+	{0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000},
+	{0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+	{0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+	{0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x00007838, 0x00000029, 0x00000029, 0x00000029, 0x00000029, 0x00000029},
+	{0x00007824, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff},
+	{0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
+	{0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
+	{0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652},
+	{0x0000a278, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
+	{0x0000a27c, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd},
+	{0x0000a394, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
+	{0x0000a398, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd},
+	{0x0000a3dc, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
+	{0x0000a3e0, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd},
 };
 
 static const u32 ar9271Modes_high_power_tx_gain_9271[][6] = {
-    { 0x0000a300, 0x00000000, 0x00000000, 0x00010000, 0x00010000, 0x00000000 },
-    { 0x0000a304, 0x00000000, 0x00000000, 0x00016200, 0x00016200, 0x00000000 },
-    { 0x0000a308, 0x00000000, 0x00000000, 0x00018201, 0x00018201, 0x00000000 },
-    { 0x0000a30c, 0x00000000, 0x00000000, 0x0001b240, 0x0001b240, 0x00000000 },
-    { 0x0000a310, 0x00000000, 0x00000000, 0x0001d241, 0x0001d241, 0x00000000 },
-    { 0x0000a314, 0x00000000, 0x00000000, 0x0001f600, 0x0001f600, 0x00000000 },
-    { 0x0000a318, 0x00000000, 0x00000000, 0x00022800, 0x00022800, 0x00000000 },
-    { 0x0000a31c, 0x00000000, 0x00000000, 0x00026802, 0x00026802, 0x00000000 },
-    { 0x0000a320, 0x00000000, 0x00000000, 0x0002b805, 0x0002b805, 0x00000000 },
-    { 0x0000a324, 0x00000000, 0x00000000, 0x0002ea41, 0x0002ea41, 0x00000000 },
-    { 0x0000a328, 0x00000000, 0x00000000, 0x00038b00, 0x00038b00, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x0003ab40, 0x0003ab40, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x0003cd80, 0x0003cd80, 0x00000000 },
-    { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 },
-    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
-    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
-    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x00007838, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b },
-    { 0x00007824, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff },
-    { 0x0000786c, 0x08609eb6, 0x08609eb6, 0x08609eba, 0x08609eba, 0x08609eb6 },
-    { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
-    { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a212652, 0x0a212652, 0x0a22a652 },
-    { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
-    { 0x0000a27c, 0x05018063, 0x05038063, 0x05018063, 0x05018063, 0x05018063 },
-    { 0x0000a394, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63 },
-    { 0x0000a398, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063 },
-    { 0x0000a3dc, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63 },
-    { 0x0000a3e0, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063 },
+	{0x0000a300, 0x00000000, 0x00000000, 0x00010000, 0x00010000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00016200, 0x00016200, 0x00000000},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00018201, 0x00018201, 0x00000000},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x0001b240, 0x0001b240, 0x00000000},
+	{0x0000a310, 0x00000000, 0x00000000, 0x0001d241, 0x0001d241, 0x00000000},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0001f600, 0x0001f600, 0x00000000},
+	{0x0000a318, 0x00000000, 0x00000000, 0x00022800, 0x00022800, 0x00000000},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x00026802, 0x00026802, 0x00000000},
+	{0x0000a320, 0x00000000, 0x00000000, 0x0002b805, 0x0002b805, 0x00000000},
+	{0x0000a324, 0x00000000, 0x00000000, 0x0002ea41, 0x0002ea41, 0x00000000},
+	{0x0000a328, 0x00000000, 0x00000000, 0x00038b00, 0x00038b00, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0003ab40, 0x0003ab40, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x0003cd80, 0x0003cd80, 0x00000000},
+	{0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000},
+	{0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+	{0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+	{0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x00007838, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b},
+	{0x00007824, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff},
+	{0x0000786c, 0x08609eb6, 0x08609eb6, 0x08609eba, 0x08609eba, 0x08609eb6},
+	{0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
+	{0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a214652, 0x0a214652, 0x0a22a652},
+	{0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a27c, 0x05018063, 0x05038063, 0x05018063, 0x05018063, 0x05018063},
+	{0x0000a394, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63},
+	{0x0000a398, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063},
+	{0x0000a3dc, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63},
+	{0x0000a3e0, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063},
 };
 
-#endif /* INITVALS_9002_10_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
index 2be20d2..50dda39 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
@@ -287,6 +287,7 @@
 	ts->ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
 	ts->ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
 	ts->ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
+	ts->tid = MS(ads->ds_txstatus9, AR_TxTid);
 	ts->ts_antenna = 0;
 
 	return 0;
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index ed314e8..adbf031 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -471,52 +471,47 @@
 static void ar9002_hw_do_getnf(struct ath_hw *ah,
 			      int16_t nfarray[NUM_NF_READINGS])
 {
-	struct ath_common *common = ath9k_hw_common(ah);
 	int16_t nf;
 
 	nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
-
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ctl] [chain 0] is %d\n", nf);
-
-	if (AR_SREV_9271(ah) && (nf >= -114))
-		nf = -116;
-
-	nfarray[0] = nf;
-
-	if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) {
-		nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
-				AR9280_PHY_CH1_MINCCA_PWR);
-
-		if (nf & 0x100)
-			nf = 0 - ((nf ^ 0x1ff) + 1);
-		ath_print(common, ATH_DBG_CALIBRATE,
-			  "NF calibrated [ctl] [chain 1] is %d\n", nf);
-		nfarray[1] = nf;
-	}
+	nfarray[0] = sign_extend(nf, 9);
 
 	nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR9280_PHY_EXT_MINCCA_PWR);
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ext] [chain 0] is %d\n", nf);
+	if (IS_CHAN_HT40(ah->curchan))
+		nfarray[3] = sign_extend(nf, 9);
 
-	if (AR_SREV_9271(ah) && (nf >= -114))
-		nf = -116;
+	if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+		return;
 
-	nfarray[3] = nf;
+	nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR9280_PHY_CH1_MINCCA_PWR);
+	nfarray[1] = sign_extend(nf, 9);
 
-	if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) {
-		nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
-				AR9280_PHY_CH1_EXT_MINCCA_PWR);
+	nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR9280_PHY_CH1_EXT_MINCCA_PWR);
+	if (IS_CHAN_HT40(ah->curchan))
+		nfarray[4] = sign_extend(nf, 9);
+}
 
-		if (nf & 0x100)
-			nf = 0 - ((nf ^ 0x1ff) + 1);
-		ath_print(common, ATH_DBG_CALIBRATE,
-			  "NF calibrated [ext] [chain 1] is %d\n", nf);
-		nfarray[4] = nf;
+static void ar9002_hw_set_nf_limits(struct ath_hw *ah)
+{
+	if (AR_SREV_9285(ah)) {
+		ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ;
+		ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ;
+		ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9285_2GHZ;
+	} else if (AR_SREV_9287(ah)) {
+		ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ;
+		ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ;
+		ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9287_2GHZ;
+	} else if (AR_SREV_9271(ah)) {
+		ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ;
+		ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ;
+		ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9271_2GHZ;
+	} else {
+		ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_2GHZ;
+		ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_2GHZ;
+		ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9280_2GHZ;
+		ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_5GHZ;
+		ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_5GHZ;
+		ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9280_5GHZ;
 	}
 }
 
@@ -532,4 +527,6 @@
 	priv_ops->olc_init = ar9002_olc_init;
 	priv_ops->compute_pll_control = ar9002_hw_compute_pll_control;
 	priv_ops->do_getnf = ar9002_hw_do_getnf;
+
+	ar9002_hw_set_nf_limits(ah);
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
index 81bf6e5..c5151a4 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
@@ -114,6 +114,10 @@
 #define AR_PHY_FIND_SIG_FIRPWR    0x03FC0000
 #define AR_PHY_FIND_SIG_FIRPWR_S  18
 
+#define AR_PHY_FIND_SIG_LOW           0x9840
+#define AR_PHY_FIND_SIG_FIRSTEP_LOW   0x00000FC0L
+#define AR_PHY_FIND_SIG_FIRSTEP_LOW_S 6
+
 #define AR_PHY_AGC_CTL1                  0x985C
 #define AR_PHY_AGC_CTL1_COARSE_LOW       0x00007F80
 #define AR_PHY_AGC_CTL1_COARSE_LOW_S     7
@@ -325,6 +329,9 @@
 #define AR_PHY_EXT_CCA_CYCPWR_THR1_S    9
 #define AR_PHY_EXT_CCA_THRESH62         0x007F0000
 #define AR_PHY_EXT_CCA_THRESH62_S       16
+#define AR_PHY_EXT_TIMING5_CYCPWR_THR1   0x0000FE00L
+#define AR_PHY_EXT_TIMING5_CYCPWR_THR1_S 9
+
 #define AR_PHY_EXT_MINCCA_PWR           0xFF800000
 #define AR_PHY_EXT_MINCCA_PWR_S         23
 #define AR9280_PHY_EXT_MINCCA_PWR       0x01FF0000
@@ -569,4 +576,30 @@
 #define AR_PHY_CH2_EXT_MINCCA_PWR   0xFF800000
 #define AR_PHY_CH2_EXT_MINCCA_PWR_S 23
 
+#define AR_PHY_CCA_NOM_VAL_5416_2GHZ            -90
+#define AR_PHY_CCA_NOM_VAL_5416_5GHZ            -100
+#define AR_PHY_CCA_MIN_GOOD_VAL_5416_2GHZ     -100
+#define AR_PHY_CCA_MIN_GOOD_VAL_5416_5GHZ     -110
+#define AR_PHY_CCA_MAX_GOOD_VAL_5416_2GHZ     -80
+#define AR_PHY_CCA_MAX_GOOD_VAL_5416_5GHZ     -90
+
+#define AR_PHY_CCA_NOM_VAL_9280_2GHZ         -112
+#define AR_PHY_CCA_NOM_VAL_9280_5GHZ         -112
+#define AR_PHY_CCA_MIN_GOOD_VAL_9280_2GHZ  -127
+#define AR_PHY_CCA_MIN_GOOD_VAL_9280_5GHZ  -122
+#define AR_PHY_CCA_MAX_GOOD_VAL_9280_2GHZ  -97
+#define AR_PHY_CCA_MAX_GOOD_VAL_9280_5GHZ  -102
+
+#define AR_PHY_CCA_NOM_VAL_9285_2GHZ           -118
+#define AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ    -127
+#define AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ    -108
+
+#define AR_PHY_CCA_NOM_VAL_9271_2GHZ             -118
+#define AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ      -127
+#define AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ      -116
+
+#define AR_PHY_CCA_NOM_VAL_9287_2GHZ           -120
+#define AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ    -127
+#define AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ    -110
+
 #endif
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h
similarity index 87%
rename from drivers/net/wireless/ath/ath9k/ar9003_initvals.h
rename to drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h
index db019dd..d3375fc 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h
@@ -14,8 +14,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#ifndef INITVALS_9003_H
-#define INITVALS_9003_H
+#ifndef INITVALS_9003_2P0_H
+#define INITVALS_9003_2P0_H
 
 /* AR9003 2.0 */
 
@@ -835,71 +835,71 @@
 
 static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
 	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-	{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
-	{0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
-	{0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
-	{0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
-	{0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
-	{0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
-	{0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
-	{0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
-	{0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
-	{0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
-	{0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
-	{0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
-	{0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
-	{0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
-	{0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
-	{0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
-	{0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
-	{0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
+	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+	{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+	{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+	{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+	{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+	{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+	{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+	{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+	{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+	{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+	{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+	{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+	{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
 	{0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
-	{0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
-	{0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
-	{0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
-	{0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
-	{0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
-	{0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+	{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
 	{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
-	{0x0000a584, 0x06802223, 0x06802223, 0x04800002, 0x04800002},
-	{0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004},
-	{0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200},
-	{0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202},
-	{0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400},
-	{0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402},
-	{0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404},
-	{0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603},
-	{0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
-	{0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
-	{0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
-	{0x0000a5b0, 0x34825643, 0x34825643, 0x2a800e20, 0x2a800e20},
-	{0x0000a5b4, 0x38825a44, 0x38825a44, 0x2e800e22, 0x2e800e22},
-	{0x0000a5b8, 0x3b825e45, 0x3b825e45, 0x31800e24, 0x31800e24},
-	{0x0000a5bc, 0x41825e4a, 0x41825e4a, 0x34801640, 0x34801640},
-	{0x0000a5c0, 0x48825e6c, 0x48825e6c, 0x38801660, 0x38801660},
-	{0x0000a5c4, 0x4e825e8e, 0x4e825e8e, 0x3b801861, 0x3b801861},
-	{0x0000a5c8, 0x53825eb2, 0x53825eb2, 0x3e801a81, 0x3e801a81},
-	{0x0000a5cc, 0x59825eb5, 0x59825eb5, 0x42801a83, 0x42801a83},
-	{0x0000a5d0, 0x5f825ef6, 0x5f825ef6, 0x44801c84, 0x44801c84},
-	{0x0000a5d4, 0x62825f56, 0x62825f56, 0x48801ce3, 0x48801ce3},
-	{0x0000a5d8, 0x66827f56, 0x66827f56, 0x4c801ce5, 0x4c801ce5},
-	{0x0000a5dc, 0x6a829f56, 0x6a829f56, 0x50801ce9, 0x50801ce9},
-	{0x0000a5e0, 0x70849f56, 0x70849f56, 0x54801ceb, 0x54801ceb},
-	{0x0000a5e4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5e8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5ec, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5f0, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5f4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+	{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+	{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+	{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+	{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+	{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+	{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+	{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+	{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+	{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+	{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+	{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+	{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+	{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+	{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
 	{0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
 	{0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
 	{0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
@@ -913,71 +913,71 @@
 
 static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p0[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
 	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-	{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
-	{0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
-	{0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
-	{0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
-	{0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
-	{0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
-	{0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
-	{0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
-	{0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
-	{0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
-	{0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
-	{0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
-	{0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
-	{0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
-	{0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
-	{0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
-	{0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
-	{0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
+	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+	{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+	{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+	{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+	{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+	{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+	{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+	{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+	{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+	{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+	{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+	{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+	{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
 	{0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
-	{0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
-	{0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
-	{0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
-	{0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
-	{0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
-	{0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+	{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
 	{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
-	{0x0000a584, 0x06802223, 0x06802223, 0x04800002, 0x04800002},
-	{0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004},
-	{0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200},
-	{0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202},
-	{0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400},
-	{0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402},
-	{0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404},
-	{0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603},
-	{0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
-	{0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
-	{0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
-	{0x0000a5b0, 0x34825643, 0x34825643, 0x2a800e20, 0x2a800e20},
-	{0x0000a5b4, 0x38825a44, 0x38825a44, 0x2e800e22, 0x2e800e22},
-	{0x0000a5b8, 0x3b825e45, 0x3b825e45, 0x31800e24, 0x31800e24},
-	{0x0000a5bc, 0x41825e4a, 0x41825e4a, 0x34801640, 0x34801640},
-	{0x0000a5c0, 0x48825e6c, 0x48825e6c, 0x38801660, 0x38801660},
-	{0x0000a5c4, 0x4e825e8e, 0x4e825e8e, 0x3b801861, 0x3b801861},
-	{0x0000a5c8, 0x53825eb2, 0x53825eb2, 0x3e801a81, 0x3e801a81},
-	{0x0000a5cc, 0x59825eb5, 0x59825eb5, 0x42801a83, 0x42801a83},
-	{0x0000a5d0, 0x5f825ef6, 0x5f825ef6, 0x44801c84, 0x44801c84},
-	{0x0000a5d4, 0x62825f56, 0x62825f56, 0x48801ce3, 0x48801ce3},
-	{0x0000a5d8, 0x66827f56, 0x66827f56, 0x4c801ce5, 0x4c801ce5},
-	{0x0000a5dc, 0x6a829f56, 0x6a829f56, 0x50801ce9, 0x50801ce9},
-	{0x0000a5e0, 0x70849f56, 0x70849f56, 0x54801ceb, 0x54801ceb},
-	{0x0000a5e4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5e8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5ec, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5f0, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5f4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+	{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+	{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+	{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+	{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+	{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+	{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+	{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+	{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+	{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+	{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+	{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+	{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+	{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+	{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
 	{0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
 	{0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
 	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -1781,4 +1781,4 @@
 	{0x00004044, 0x00000000},
 };
 
-#endif /* INITVALS_9003_H */
+#endif /* INITVALS_9003_2P0_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
similarity index 78%
copy from drivers/net/wireless/ath/ath9k/ar9003_initvals.h
copy to drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index db019dd..ec98ab5 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -14,12 +14,12 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#ifndef INITVALS_9003_H
-#define INITVALS_9003_H
+#ifndef INITVALS_9003_2P2_H
+#define INITVALS_9003_2P2_H
 
-/* AR9003 2.0 */
+/* AR9003 2.2 */
 
-static const u32 ar9300_2p0_radio_postamble[][5] = {
+static const u32 ar9300_2p2_radio_postamble[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
 	{0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31},
 	{0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800},
@@ -32,7 +32,7 @@
 	{0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
 };
 
-static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p0[][5] = {
+static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
 	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
 	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@@ -41,8 +41,8 @@
 	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
 	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
 	{0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
-	{0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
-	{0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404},
+	{0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
 	{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
 	{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
 	{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
@@ -54,27 +54,27 @@
 	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
 	{0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
 	{0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
-	{0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
-	{0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
-	{0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
-	{0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
-	{0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
-	{0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
-	{0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
 	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
 	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
 	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
 	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
 	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
 	{0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
-	{0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402},
-	{0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404},
+	{0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+	{0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
 	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
 	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
 	{0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
@@ -86,19 +86,19 @@
 	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
 	{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
 	{0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
-	{0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83},
-	{0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84},
-	{0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3},
-	{0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5},
-	{0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9},
-	{0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb},
-	{0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
+	{0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
+	{0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
+	{0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
+	{0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
+	{0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
+	{0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
 	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
 	{0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
 	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -110,7 +110,7 @@
 	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
-static const u32 ar9300Modes_fast_clock_2p0[][3] = {
+static const u32 ar9300Modes_fast_clock_2p2[][3] = {
 	/* Addr      5G_HT20     5G_HT40   */
 	{0x00001030, 0x00000268, 0x000004d0},
 	{0x00001070, 0x0000018c, 0x00000318},
@@ -123,7 +123,7 @@
 	{0x0000a254, 0x00000898, 0x00001130},
 };
 
-static const u32 ar9300_2p0_radio_core[][2] = {
+static const u32 ar9300_2p2_radio_core[][2] = {
 	/* Addr      allmodes  */
 	{0x00016000, 0x36db6db6},
 	{0x00016004, 0x6db6db40},
@@ -161,7 +161,7 @@
 	{0x00016284, 0x3d840208},
 	{0x00016288, 0x05a20408},
 	{0x0001628c, 0x00038c07},
-	{0x00016290, 0x40000004},
+	{0x00016290, 0x00000004},
 	{0x00016294, 0x458aa14f},
 	{0x00016380, 0x00000000},
 	{0x00016384, 0x00000000},
@@ -267,7 +267,7 @@
 	{0x00016bd4, 0x00000000},
 };
 
-static const u32 ar9300Common_rx_gain_table_merlin_2p0[][2] = {
+static const u32 ar9300Common_rx_gain_table_merlin_2p2[][2] = {
 	/* Addr      allmodes  */
 	{0x0000a000, 0x02000101},
 	{0x0000a004, 0x02000102},
@@ -527,7 +527,7 @@
 	{0x0000b1fc, 0x00000776},
 };
 
-static const u32 ar9300_2p0_mac_postamble[][5] = {
+static const u32 ar9300_2p2_mac_postamble[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
 	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
 	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
@@ -539,12 +539,12 @@
 	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
 };
 
-static const u32 ar9300_2p0_soc_postamble[][5] = {
+static const u32 ar9300_2p2_soc_postamble[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
 	{0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
 };
 
-static const u32 ar9200_merlin_2p0_radio_core[][2] = {
+static const u32 ar9200_merlin_2p2_radio_core[][2] = {
 	/* Addr      allmodes  */
 	{0x00007800, 0x00040000},
 	{0x00007804, 0xdb005012},
@@ -586,7 +586,7 @@
 	{0x00007894, 0x5a108000},
 };
 
-static const u32 ar9300_2p0_baseband_postamble[][5] = {
+static const u32 ar9300_2p2_baseband_postamble[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
 	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
 	{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
@@ -594,7 +594,7 @@
 	{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
 	{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
 	{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
-	{0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044},
+	{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
 	{0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
 	{0x00009e04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
 	{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
@@ -610,6 +610,7 @@
 	{0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0},
 	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
 	{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+	{0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
 	{0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
 	{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
 	{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
@@ -639,7 +640,7 @@
 	{0x0000c284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
 };
 
-static const u32 ar9300_2p0_baseband_core[][2] = {
+static const u32 ar9300_2p2_baseband_core[][2] = {
 	/* Addr      allmodes  */
 	{0x00009800, 0xafe68e30},
 	{0x00009804, 0xfd14e000},
@@ -694,7 +695,6 @@
 	{0x0000a224, 0x00000000},
 	{0x0000a228, 0x10002310},
 	{0x0000a22c, 0x01036a1e},
-	{0x0000a234, 0x10000fff},
 	{0x0000a23c, 0x00000000},
 	{0x0000a244, 0x0c000000},
 	{0x0000a2a0, 0x00000001},
@@ -756,7 +756,7 @@
 	{0x0000a43c, 0x00000000},
 	{0x0000a440, 0x00000000},
 	{0x0000a444, 0x00000000},
-	{0x0000a448, 0x04000080},
+	{0x0000a448, 0x06000080},
 	{0x0000a44c, 0x00000001},
 	{0x0000a450, 0x00010000},
 	{0x0000a458, 0x00000000},
@@ -833,73 +833,73 @@
 	{0x0000c420, 0x00000000},
 };
 
-static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = {
+static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
 	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-	{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
-	{0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
-	{0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
-	{0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
-	{0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
-	{0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
-	{0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
-	{0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
-	{0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
-	{0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
-	{0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
-	{0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
-	{0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
-	{0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
-	{0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
-	{0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
-	{0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
-	{0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
+	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+	{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+	{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+	{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+	{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+	{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+	{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+	{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+	{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+	{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+	{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+	{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+	{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
 	{0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
-	{0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
-	{0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
-	{0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
-	{0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
-	{0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
-	{0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+	{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
 	{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
-	{0x0000a584, 0x06802223, 0x06802223, 0x04800002, 0x04800002},
-	{0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004},
-	{0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200},
-	{0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202},
-	{0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400},
-	{0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402},
-	{0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404},
-	{0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603},
-	{0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
-	{0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
-	{0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
-	{0x0000a5b0, 0x34825643, 0x34825643, 0x2a800e20, 0x2a800e20},
-	{0x0000a5b4, 0x38825a44, 0x38825a44, 0x2e800e22, 0x2e800e22},
-	{0x0000a5b8, 0x3b825e45, 0x3b825e45, 0x31800e24, 0x31800e24},
-	{0x0000a5bc, 0x41825e4a, 0x41825e4a, 0x34801640, 0x34801640},
-	{0x0000a5c0, 0x48825e6c, 0x48825e6c, 0x38801660, 0x38801660},
-	{0x0000a5c4, 0x4e825e8e, 0x4e825e8e, 0x3b801861, 0x3b801861},
-	{0x0000a5c8, 0x53825eb2, 0x53825eb2, 0x3e801a81, 0x3e801a81},
-	{0x0000a5cc, 0x59825eb5, 0x59825eb5, 0x42801a83, 0x42801a83},
-	{0x0000a5d0, 0x5f825ef6, 0x5f825ef6, 0x44801c84, 0x44801c84},
-	{0x0000a5d4, 0x62825f56, 0x62825f56, 0x48801ce3, 0x48801ce3},
-	{0x0000a5d8, 0x66827f56, 0x66827f56, 0x4c801ce5, 0x4c801ce5},
-	{0x0000a5dc, 0x6a829f56, 0x6a829f56, 0x50801ce9, 0x50801ce9},
-	{0x0000a5e0, 0x70849f56, 0x70849f56, 0x54801ceb, 0x54801ceb},
-	{0x0000a5e4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5e8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5ec, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5f0, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5f4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+	{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+	{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+	{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+	{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+	{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+	{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+	{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+	{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+	{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+	{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+	{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+	{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+	{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+	{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
 	{0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
 	{0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
 	{0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
@@ -911,73 +911,73 @@
 	{0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
 };
 
-static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p0[][5] = {
+static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
 	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-	{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
-	{0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
-	{0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
-	{0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
-	{0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
-	{0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
-	{0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
-	{0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
-	{0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
-	{0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
-	{0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
-	{0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
-	{0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
-	{0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
-	{0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
-	{0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
-	{0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
-	{0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
+	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+	{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+	{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+	{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+	{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+	{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+	{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+	{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+	{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+	{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+	{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+	{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+	{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
 	{0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
-	{0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
-	{0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
-	{0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
-	{0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
-	{0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
-	{0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
-	{0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+	{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
 	{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
-	{0x0000a584, 0x06802223, 0x06802223, 0x04800002, 0x04800002},
-	{0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004},
-	{0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200},
-	{0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202},
-	{0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400},
-	{0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402},
-	{0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404},
-	{0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603},
-	{0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
-	{0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
-	{0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
-	{0x0000a5b0, 0x34825643, 0x34825643, 0x2a800e20, 0x2a800e20},
-	{0x0000a5b4, 0x38825a44, 0x38825a44, 0x2e800e22, 0x2e800e22},
-	{0x0000a5b8, 0x3b825e45, 0x3b825e45, 0x31800e24, 0x31800e24},
-	{0x0000a5bc, 0x41825e4a, 0x41825e4a, 0x34801640, 0x34801640},
-	{0x0000a5c0, 0x48825e6c, 0x48825e6c, 0x38801660, 0x38801660},
-	{0x0000a5c4, 0x4e825e8e, 0x4e825e8e, 0x3b801861, 0x3b801861},
-	{0x0000a5c8, 0x53825eb2, 0x53825eb2, 0x3e801a81, 0x3e801a81},
-	{0x0000a5cc, 0x59825eb5, 0x59825eb5, 0x42801a83, 0x42801a83},
-	{0x0000a5d0, 0x5f825ef6, 0x5f825ef6, 0x44801c84, 0x44801c84},
-	{0x0000a5d4, 0x62825f56, 0x62825f56, 0x48801ce3, 0x48801ce3},
-	{0x0000a5d8, 0x66827f56, 0x66827f56, 0x4c801ce5, 0x4c801ce5},
-	{0x0000a5dc, 0x6a829f56, 0x6a829f56, 0x50801ce9, 0x50801ce9},
-	{0x0000a5e0, 0x70849f56, 0x70849f56, 0x54801ceb, 0x54801ceb},
-	{0x0000a5e4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5e8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5ec, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5f0, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5f4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
-	{0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+	{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+	{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+	{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+	{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+	{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+	{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+	{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+	{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+	{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+	{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+	{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+	{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+	{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+	{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
 	{0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
 	{0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
 	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -989,7 +989,7 @@
 	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
-static const u32 ar9300Common_rx_gain_table_2p0[][2] = {
+static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
 	/* Addr      allmodes  */
 	{0x0000a000, 0x00010000},
 	{0x0000a004, 0x00030002},
@@ -1249,7 +1249,7 @@
 	{0x0000b1fc, 0x00000196},
 };
 
-static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p0[][5] = {
+static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
 	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
 	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@@ -1258,8 +1258,8 @@
 	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
 	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
 	{0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
-	{0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
-	{0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404},
+	{0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
 	{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
 	{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
 	{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
@@ -1271,27 +1271,27 @@
 	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
 	{0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
 	{0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
-	{0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
-	{0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
-	{0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
-	{0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
-	{0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
-	{0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
-	{0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-	{0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
 	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
 	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
 	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
 	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
 	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
 	{0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
-	{0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402},
-	{0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404},
+	{0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+	{0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
 	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
 	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
 	{0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
@@ -1303,31 +1303,31 @@
 	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
 	{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
 	{0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
-	{0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83},
-	{0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84},
-	{0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3},
-	{0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5},
-	{0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9},
-	{0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb},
-	{0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
-	{0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
+	{0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
+	{0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
+	{0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
+	{0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
+	{0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
+	{0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
 	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-	{0x00016048, 0x64000001, 0x64000001, 0x64000001, 0x64000001},
+	{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
 	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 	{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-	{0x00016448, 0x64000001, 0x64000001, 0x64000001, 0x64000001},
+	{0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
 	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 	{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-	{0x00016848, 0x64000001, 0x64000001, 0x64000001, 0x64000001},
+	{0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
 	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
-static const u32 ar9300_2p0_mac_core[][2] = {
+static const u32 ar9300_2p2_mac_core[][2] = {
 	/* Addr      allmodes  */
 	{0x00000008, 0x00000000},
 	{0x00000030, 0x00020085},
@@ -1437,7 +1437,7 @@
 	{0x00008258, 0x00000000},
 	{0x0000825c, 0x40000000},
 	{0x00008260, 0x00080922},
-	{0x00008264, 0x98a00010},
+	{0x00008264, 0x9bc00010},
 	{0x00008268, 0xffffffff},
 	{0x0000826c, 0x0000ffff},
 	{0x00008270, 0x00000000},
@@ -1491,7 +1491,7 @@
 	{0x000083d0, 0x000301ff},
 };
 
-static const u32 ar9300Common_wo_xlna_rx_gain_table_2p0[][2] = {
+static const u32 ar9300Common_wo_xlna_rx_gain_table_2p2[][2] = {
 	/* Addr      allmodes  */
 	{0x0000a000, 0x00010000},
 	{0x0000a004, 0x00030002},
@@ -1751,34 +1751,35 @@
 	{0x0000b1fc, 0x00000196},
 };
 
-static const u32 ar9300_2p0_soc_preamble[][2] = {
+static const u32 ar9300_2p2_soc_preamble[][2] = {
 	/* Addr      allmodes  */
 	{0x000040a4, 0x00a0c1c9},
 	{0x00007008, 0x00000000},
 	{0x00007020, 0x00000000},
 	{0x00007034, 0x00000002},
 	{0x00007038, 0x000004c2},
+	{0x00007048, 0x00000008},
 };
 
-static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p0[][2] = {
+static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2[][2] = {
 	/* Addr      allmodes  */
 	{0x00004040, 0x08212e5e},
 	{0x00004040, 0x0008003b},
 	{0x00004044, 0x00000000},
 };
 
-static const u32 ar9300PciePhy_clkreq_enable_L1_2p0[][2] = {
+static const u32 ar9300PciePhy_clkreq_enable_L1_2p2[][2] = {
 	/* Addr      allmodes  */
 	{0x00004040, 0x08253e5e},
 	{0x00004040, 0x0008003b},
 	{0x00004044, 0x00000000},
 };
 
-static const u32 ar9300PciePhy_clkreq_disable_L1_2p0[][2] = {
+static const u32 ar9300PciePhy_clkreq_disable_L1_2p2[][2] = {
 	/* Addr      allmodes  */
 	{0x00004040, 0x08213e5e},
 	{0x00004040, 0x0008003b},
 	{0x00004044, 0x00000000},
 };
 
-#endif /* INITVALS_9003_H */
+#endif /* INITVALS_9003_2P2_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 56a9e5f..5a06503 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -739,6 +739,12 @@
 	 */
 	ar9003_hw_set_chain_masks(ah, 0x7, 0x7);
 
+	/* Do Tx IQ Calibration */
+	ar9003_hw_tx_iq_cal(ah);
+	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+	udelay(5);
+	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
 	/* Calibrate the AGC */
 	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
 		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
@@ -753,10 +759,6 @@
 		return false;
 	}
 
-	/* Do Tx IQ Calibration */
-	if (ah->config.tx_iq_calibration)
-		ar9003_hw_tx_iq_cal(ah);
-
 	/* Revert chainmasks to their original values before NF cal */
 	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
 
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 23eb60e..ace8d26 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -67,6 +67,7 @@
 		  * bit2 - enable fastClock - enabled
 		  * bit3 - enable doubling - enabled
 		  * bit4 - enable internal regulator - disabled
+		  * bit5 - enable pa predistortion - disabled
 		  */
 		.miscConfiguration = 0, /* bit0 - turn down drivestrength */
 		.eepromWriteEnableGpio = 3,
@@ -129,9 +130,11 @@
 		.txEndToRxOn = 0x2,
 		.txFrameToXpaOn = 0xe,
 		.thresh62 = 28,
-		.futureModal = { /* [32] */
+		.papdRateMaskHt20 = LE32(0x80c080),
+		.papdRateMaskHt40 = LE32(0x80c080),
+		.futureModal = {
 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+			0, 0, 0, 0, 0, 0, 0, 0
 		},
 	 },
 	.calFreqPier2G = {
@@ -326,9 +329,11 @@
 		.txEndToRxOn = 0x2,
 		.txFrameToXpaOn = 0xe,
 		.thresh62 = 28,
+		.papdRateMaskHt20 = LE32(0xf0e0e0),
+		.papdRateMaskHt40 = LE32(0xf0e0e0),
 		.futureModal = {
 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+			0, 0, 0, 0, 0, 0, 0, 0
 		},
 	 },
 	.calFreqPier5G = {
@@ -644,6 +649,8 @@
 		return (pBase->featureEnable & 0x10) >> 4;
 	case EEP_SWREG:
 		return le32_to_cpu(pBase->swreg);
+	case EEP_PAPRD:
+		return !!(pBase->featureEnable & BIT(5));
 	default:
 		return 0;
 	}
@@ -944,7 +951,7 @@
 	return 1;
 }
 
-static u16 ath9k_hw_ar9300_get_eeprom_antenna_cfg(struct ath_hw *ah,
+static u32 ath9k_hw_ar9300_get_eeprom_antenna_cfg(struct ath_hw *ah,
 						  struct ath9k_channel *chan)
 {
 	return -EINVAL;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
index 23fb353..3c533bb 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
@@ -234,7 +234,9 @@
 	u8 txEndToRxOn;
 	u8 txFrameToXpaOn;
 	u8 thresh62;
-	u8 futureModal[32];
+	__le32 papdRateMaskHt20;
+	__le32 papdRateMaskHt40;
+	u8 futureModal[24];
 } __packed;
 
 struct ar9300_cal_data_per_freq_op_loop {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index b15309c..0641689 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -16,7 +16,8 @@
 
 #include "hw.h"
 #include "ar9003_mac.h"
-#include "ar9003_initvals.h"
+#include "ar9003_2p0_initvals.h"
+#include "ar9003_2p2_initvals.h"
 
 /* General hardware code for the AR9003 hadware family */
 
@@ -31,12 +32,8 @@
 	return false;
 }
 
-/* AR9003 2.0 - new INI format (pre, core, post arrays per subsystem) */
-/*
- * XXX: move TX/RX gain INI to its own init_mode_gain_regs after
- * ensuring it does not affect hardware bring up
- */
-static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
+/* AR9003 2.0 */
+static void ar9003_2p0_hw_init_mode_regs(struct ath_hw *ah)
 {
 	/* mac */
 	INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
@@ -106,27 +103,128 @@
 		       3);
 }
 
+/* AR9003 2.2 */
+static void ar9003_2p2_hw_init_mode_regs(struct ath_hw *ah)
+{
+	/* mac */
+	INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
+	INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+		       ar9300_2p2_mac_core,
+		       ARRAY_SIZE(ar9300_2p2_mac_core), 2);
+	INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+		       ar9300_2p2_mac_postamble,
+		       ARRAY_SIZE(ar9300_2p2_mac_postamble), 5);
+
+	/* bb */
+	INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
+	INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+		       ar9300_2p2_baseband_core,
+		       ARRAY_SIZE(ar9300_2p2_baseband_core), 2);
+	INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+		       ar9300_2p2_baseband_postamble,
+		       ARRAY_SIZE(ar9300_2p2_baseband_postamble), 5);
+
+	/* radio */
+	INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
+	INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+		       ar9300_2p2_radio_core,
+		       ARRAY_SIZE(ar9300_2p2_radio_core), 2);
+	INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+		       ar9300_2p2_radio_postamble,
+		       ARRAY_SIZE(ar9300_2p2_radio_postamble), 5);
+
+	/* soc */
+	INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+		       ar9300_2p2_soc_preamble,
+		       ARRAY_SIZE(ar9300_2p2_soc_preamble), 2);
+	INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
+	INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+		       ar9300_2p2_soc_postamble,
+		       ARRAY_SIZE(ar9300_2p2_soc_postamble), 5);
+
+	/* rx/tx gain */
+	INIT_INI_ARRAY(&ah->iniModesRxGain,
+		       ar9300Common_rx_gain_table_2p2,
+		       ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), 2);
+	INIT_INI_ARRAY(&ah->iniModesTxGain,
+		       ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
+		       ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
+		       5);
+
+	/* Load PCIE SERDES settings from INI */
+
+	/* Awake Setting */
+
+	INIT_INI_ARRAY(&ah->iniPcieSerdes,
+		       ar9300PciePhy_pll_on_clkreq_disable_L1_2p2,
+		       ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2),
+		       2);
+
+	/* Sleep Setting */
+
+	INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
+		       ar9300PciePhy_clkreq_enable_L1_2p2,
+		       ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p2),
+		       2);
+
+	/* Fast clock modal settings */
+	INIT_INI_ARRAY(&ah->iniModesAdditional,
+		       ar9300Modes_fast_clock_2p2,
+		       ARRAY_SIZE(ar9300Modes_fast_clock_2p2),
+		       3);
+}
+
+/*
+ * The AR9003 family uses a new INI format (pre, core, post
+ * arrays per subsystem).
+ */
+static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
+{
+	if (AR_SREV_9300_20(ah))
+		ar9003_2p0_hw_init_mode_regs(ah);
+	else
+		ar9003_2p2_hw_init_mode_regs(ah);
+}
+
 static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
 {
 	switch (ar9003_hw_get_tx_gain_idx(ah)) {
 	case 0:
 	default:
-		INIT_INI_ARRAY(&ah->iniModesTxGain,
-			       ar9300Modes_lowest_ob_db_tx_gain_table_2p0,
-			       ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0),
-			       5);
+		if (AR_SREV_9300_20(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9300Modes_lowest_ob_db_tx_gain_table_2p0,
+				       ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0),
+				       5);
+		else
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
+				       ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
+				       5);
 		break;
 	case 1:
-		INIT_INI_ARRAY(&ah->iniModesTxGain,
-			       ar9300Modes_high_ob_db_tx_gain_table_2p0,
-			       ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p0),
-			       5);
+		if (AR_SREV_9300_20(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9300Modes_high_ob_db_tx_gain_table_2p0,
+				       ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p0),
+				       5);
+		else
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9300Modes_high_ob_db_tx_gain_table_2p2,
+				       ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2),
+				       5);
 		break;
 	case 2:
-		INIT_INI_ARRAY(&ah->iniModesTxGain,
-			       ar9300Modes_low_ob_db_tx_gain_table_2p0,
-			       ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p0),
-			       5);
+		if (AR_SREV_9300_20(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9300Modes_low_ob_db_tx_gain_table_2p0,
+				       ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p0),
+				       5);
+		else
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9300Modes_low_ob_db_tx_gain_table_2p2,
+				       ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2),
+				       5);
 		break;
 	}
 }
@@ -136,15 +234,28 @@
 	switch (ar9003_hw_get_rx_gain_idx(ah)) {
 	case 0:
 	default:
-		INIT_INI_ARRAY(&ah->iniModesRxGain, ar9300Common_rx_gain_table_2p0,
-			       ARRAY_SIZE(ar9300Common_rx_gain_table_2p0),
-			       2);
+		if (AR_SREV_9300_20(ah))
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				       ar9300Common_rx_gain_table_2p0,
+				       ARRAY_SIZE(ar9300Common_rx_gain_table_2p0),
+				       2);
+		else
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				       ar9300Common_rx_gain_table_2p2,
+				       ARRAY_SIZE(ar9300Common_rx_gain_table_2p2),
+				       2);
 		break;
 	case 1:
-		INIT_INI_ARRAY(&ah->iniModesRxGain,
-			       ar9300Common_wo_xlna_rx_gain_table_2p0,
-			       ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p0),
-			       2);
+		if (AR_SREV_9300_20(ah))
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				       ar9300Common_wo_xlna_rx_gain_table_2p0,
+				       ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p0),
+				       2);
+		else
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				       ar9300Common_wo_xlna_rx_gain_table_2p2,
+				       ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2),
+				       2);
 		break;
 	}
 }
@@ -184,6 +295,26 @@
 		/* Several PCIe massages to ensure proper behaviour */
 		if (ah->config.pcie_waen)
 			REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
+		else
+			REG_WRITE(ah, AR_WA, ah->WARegVal);
+	}
+
+	/*
+	 * Configire PCIE after Ini init. SERDES values now come from ini file
+	 * This enables PCIe low power mode.
+	 */
+	if (ah->config.pcieSerDesWrite) {
+		unsigned int i;
+		struct ar5416IniArray *array;
+
+		array = power_off ? &ah->iniPcieSerdes :
+				    &ah->iniPcieSerdesLowPower;
+
+		for (i = 0; i < array->ia_rows; i++) {
+			REG_WRITE(ah,
+				  INI_RA(array, i, 0),
+				  INI_RA(array, i, 1));
+		}
 	}
 }
 
@@ -202,4 +333,6 @@
 	ar9003_hw_attach_phy_ops(ah);
 	ar9003_hw_attach_calib_ops(ah);
 	ar9003_hw_attach_mac_ops(ah);
+
+	ath9k_hw_attach_ani_ops_new(ah);
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 37ba374..5b995be 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -90,6 +90,8 @@
 				  MAP_ISR_S2_CST);
 			mask2 |= ((isr2 & AR_ISR_S2_TSFOOR) >>
 				  MAP_ISR_S2_TSFOOR);
+			mask2 |= ((isr2 & AR_ISR_S2_BB_WATCHDOG) >>
+				  MAP_ISR_S2_BB_WATCHDOG);
 
 			if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
 				REG_WRITE(ah, AR_ISR_S2, isr2);
@@ -167,6 +169,9 @@
 
 			(void) REG_READ(ah, AR_ISR);
 		}
+
+		if (*masked & ATH9K_INT_BB_WATCHDOG)
+			ar9003_hw_bb_watchdog_read(ah);
 	}
 
 	if (sync_cause) {
@@ -465,6 +470,14 @@
 		ads->ctl11 &= ~AR_VirtMoreFrag;
 }
 
+void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains)
+{
+	struct ar9003_txc *ads = ds;
+
+	ads->ctl12 |= SM(chains, AR_PAPRDChainMask);
+}
+EXPORT_SYMBOL(ar9003_hw_set_paprd_txdesc);
+
 void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
 {
 	struct ath_hw_ops *ops = ath9k_hw_ops(hw);
@@ -566,12 +579,39 @@
 		rxs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
 
 	if ((rxsp->status11 & AR_RxFrameOK) == 0) {
+		/*
+		 * AR_CRCErr will bet set to true if we're on the last
+		 * subframe and the AR_PostDelimCRCErr is caught.
+		 * In a way this also gives us a guarantee that when
+		 * (!(AR_CRCErr) && (AR_PostDelimCRCErr)) we cannot
+		 * possibly be reviewing the last subframe. AR_CRCErr
+		 * is the CRC of the actual data.
+		 */
 		if (rxsp->status11 & AR_CRCErr) {
 			rxs->rs_status |= ATH9K_RXERR_CRC;
 		} else if (rxsp->status11 & AR_PHYErr) {
-			rxs->rs_status |= ATH9K_RXERR_PHY;
 			phyerr = MS(rxsp->status11, AR_PHYErrCode);
-			rxs->rs_phyerr = phyerr;
+			/*
+			 * If we reach a point here where AR_PostDelimCRCErr is
+			 * true it implies we're *not* on the last subframe. In
+			 * in that case that we know already that the CRC of
+			 * the frame was OK, and MAC would send an ACK for that
+			 * subframe, even if we did get a phy error of type
+			 * ATH9K_PHYERR_OFDM_RESTART. This is only applicable
+			 * to frame that are prior to the last subframe.
+			 * The AR_PostDelimCRCErr is the CRC for the MPDU
+			 * delimiter, which contains the 4 reserved bits,
+			 * the MPDU length (12 bits), and follows the MPDU
+			 * delimiter for an A-MPDU subframe (0x4E = 'N' ASCII).
+			 */
+			if ((phyerr == ATH9K_PHYERR_OFDM_RESTART) &&
+			    (rxsp->status11 & AR_PostDelimCRCErr)) {
+				rxs->rs_phyerr = 0;
+			} else {
+				rxs->rs_status |= ATH9K_RXERR_PHY;
+				rxs->rs_phyerr = phyerr;
+			}
+
 		} else if (rxsp->status11 & AR_DecryptCRCErr) {
 			rxs->rs_status |= ATH9K_RXERR_DECRYPT;
 		} else if (rxsp->status11 & AR_MichaelErr) {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.h b/drivers/net/wireless/ath/ath9k/ar9003_mac.h
index f17558b..9f2cea7 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.h
@@ -33,13 +33,14 @@
 #define AR_TxDescId_S	16
 #define AR_TxPtrChkSum	0x0000ffff
 
-#define AR_TxTid	0xf0000000
-#define AR_TxTid_S	28
-
 #define AR_LowRxChain	0x00004000
 
 #define AR_Not_Sounding	0x20000000
 
+/* ctl 12 */
+#define AR_PAPRDChainMask	0x00000e00
+#define AR_PAPRDChainMask_S	9
+
 #define MAP_ISR_S2_CST          6
 #define MAP_ISR_S2_GTT          6
 #define MAP_ISR_S2_TIM          3
@@ -47,6 +48,7 @@
 #define MAP_ISR_S2_DTIMSYNC     7
 #define MAP_ISR_S2_DTIM         7
 #define MAP_ISR_S2_TSFOOR       4
+#define MAP_ISR_S2_BB_WATCHDOG  6
 
 #define AR9003TXC_CONST(_ds) ((const struct ar9003_txc *) _ds)
 
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
new file mode 100644
index 0000000..49e0c86
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
@@ -0,0 +1,714 @@
+/*
+ * Copyright (c) 2010 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 "hw.h"
+#include "ar9003_phy.h"
+
+void ar9003_paprd_enable(struct ath_hw *ah, bool val)
+{
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0,
+		      AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B1,
+		      AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B2,
+		      AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
+}
+EXPORT_SYMBOL(ar9003_paprd_enable);
+
+static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
+{
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	struct ar9300_modal_eep_header *hdr;
+	const u32 ctrl0[3] = {
+		AR_PHY_PAPRD_CTRL0_B0,
+		AR_PHY_PAPRD_CTRL0_B1,
+		AR_PHY_PAPRD_CTRL0_B2
+	};
+	const u32 ctrl1[3] = {
+		AR_PHY_PAPRD_CTRL1_B0,
+		AR_PHY_PAPRD_CTRL1_B1,
+		AR_PHY_PAPRD_CTRL1_B2
+	};
+	u32 am_mask, ht40_mask;
+	int i;
+
+	if (ah->curchan && IS_CHAN_5GHZ(ah->curchan))
+		hdr = &eep->modalHeader5G;
+	else
+		hdr = &eep->modalHeader2G;
+
+	am_mask = le32_to_cpu(hdr->papdRateMaskHt20);
+	ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40);
+
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, am_mask);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, ht40_mask);
+
+	for (i = 0; i < 3; i++) {
+		REG_RMW_FIELD(ah, ctrl0[i],
+			      AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1);
+		REG_RMW_FIELD(ah, ctrl1[i],
+			      AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE, 1);
+		REG_RMW_FIELD(ah, ctrl1[i],
+			      AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE, 1);
+		REG_RMW_FIELD(ah, ctrl1[i],
+			      AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0);
+		REG_RMW_FIELD(ah, ctrl1[i],
+			      AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK, 181);
+		REG_RMW_FIELD(ah, ctrl1[i],
+			      AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT, 361);
+		REG_RMW_FIELD(ah, ctrl1[i],
+			      AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0);
+		REG_RMW_FIELD(ah, ctrl0[i],
+			      AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH, 3);
+	}
+
+	ar9003_paprd_enable(ah, false);
+
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+		      AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP, 0x30);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+		      AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE, 1);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+		      AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE, 1);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+		      AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE, 0);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+		      AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE, 0);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+		      AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+		      AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2,
+		      AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, 147);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+		      AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+		      AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN, 4);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+		      AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+		      AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+		      AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+		      AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE,
+		      -15);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+		      AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
+		      AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA, 0);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
+		      AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR, 400);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
+		      AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES,
+		      100);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_0_B0,
+		      AR_PHY_PAPRD_PRE_POST_SCALING, 261376);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_1_B0,
+		      AR_PHY_PAPRD_PRE_POST_SCALING, 248079);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_2_B0,
+		      AR_PHY_PAPRD_PRE_POST_SCALING, 233759);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_3_B0,
+		      AR_PHY_PAPRD_PRE_POST_SCALING, 220464);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_4_B0,
+		      AR_PHY_PAPRD_PRE_POST_SCALING, 208194);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_5_B0,
+		      AR_PHY_PAPRD_PRE_POST_SCALING, 196949);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_6_B0,
+		      AR_PHY_PAPRD_PRE_POST_SCALING, 185706);
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0,
+		      AR_PHY_PAPRD_PRE_POST_SCALING, 175487);
+}
+
+static void ar9003_paprd_get_gain_table(struct ath_hw *ah)
+{
+	u32 *entry = ah->paprd_gain_table_entries;
+	u8 *index = ah->paprd_gain_table_index;
+	u32 reg = AR_PHY_TXGAIN_TABLE;
+	int i;
+
+	memset(entry, 0, sizeof(ah->paprd_gain_table_entries));
+	memset(index, 0, sizeof(ah->paprd_gain_table_index));
+
+	for (i = 0; i < 32; i++) {
+		entry[i] = REG_READ(ah, reg);
+		index[i] = (entry[i] >> 24) & 0xff;
+		reg += 4;
+	}
+}
+
+static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain,
+					    int target_power)
+{
+	int olpc_gain_delta = 0;
+	int alpha_therm, alpha_volt;
+	int therm_cal_value, volt_cal_value;
+	int therm_value, volt_value;
+	int thermal_gain_corr, voltage_gain_corr;
+	int desired_scale, desired_gain = 0;
+	u32 reg;
+
+	REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+		    AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
+	desired_scale = REG_READ_FIELD(ah, AR_PHY_TPC_12,
+				       AR_PHY_TPC_12_DESIRED_SCALE_HT40_5);
+	alpha_therm = REG_READ_FIELD(ah, AR_PHY_TPC_19,
+				     AR_PHY_TPC_19_ALPHA_THERM);
+	alpha_volt = REG_READ_FIELD(ah, AR_PHY_TPC_19,
+				    AR_PHY_TPC_19_ALPHA_VOLT);
+	therm_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18,
+					 AR_PHY_TPC_18_THERM_CAL_VALUE);
+	volt_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18,
+					AR_PHY_TPC_18_VOLT_CAL_VALUE);
+	therm_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4,
+				     AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE);
+	volt_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4,
+				    AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE);
+
+	if (chain == 0)
+		reg = AR_PHY_TPC_11_B0;
+	else if (chain == 1)
+		reg = AR_PHY_TPC_11_B1;
+	else
+		reg = AR_PHY_TPC_11_B2;
+
+	olpc_gain_delta = REG_READ_FIELD(ah, reg,
+					 AR_PHY_TPC_11_OLPC_GAIN_DELTA);
+
+	if (olpc_gain_delta >= 128)
+		olpc_gain_delta = olpc_gain_delta - 256;
+
+	thermal_gain_corr = (alpha_therm * (therm_value - therm_cal_value) +
+			     (256 / 2)) / 256;
+	voltage_gain_corr = (alpha_volt * (volt_value - volt_cal_value) +
+			     (128 / 2)) / 128;
+	desired_gain = target_power - olpc_gain_delta - thermal_gain_corr -
+	    voltage_gain_corr + desired_scale;
+
+	return desired_gain;
+}
+
+static void ar9003_tx_force_gain(struct ath_hw *ah, unsigned int gain_index)
+{
+	int selected_gain_entry, txbb1dbgain, txbb6dbgain, txmxrgain;
+	int padrvgnA, padrvgnB, padrvgnC, padrvgnD;
+	u32 *gain_table_entries = ah->paprd_gain_table_entries;
+
+	selected_gain_entry = gain_table_entries[gain_index];
+	txbb1dbgain = selected_gain_entry & 0x7;
+	txbb6dbgain = (selected_gain_entry >> 3) & 0x3;
+	txmxrgain = (selected_gain_entry >> 5) & 0xf;
+	padrvgnA = (selected_gain_entry >> 9) & 0xf;
+	padrvgnB = (selected_gain_entry >> 13) & 0xf;
+	padrvgnC = (selected_gain_entry >> 17) & 0xf;
+	padrvgnD = (selected_gain_entry >> 21) & 0x3;
+
+	REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+		      AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN, txbb1dbgain);
+	REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+		      AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN, txbb6dbgain);
+	REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+		      AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN, txmxrgain);
+	REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+		      AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA, padrvgnA);
+	REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+		      AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB, padrvgnB);
+	REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+		      AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC, padrvgnC);
+	REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+		      AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND, padrvgnD);
+	REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+		      AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL, 0);
+	REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+		      AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN, 0);
+	REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCED_DAC_GAIN, 0);
+	REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCE_DAC_GAIN, 0);
+}
+
+static inline int find_expn(int num)
+{
+	return fls(num) - 1;
+}
+
+static inline int find_proper_scale(int expn, int N)
+{
+	return (expn > N) ? expn - 10 : 0;
+}
+
+#define NUM_BIN 23
+
+static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
+{
+	unsigned int thresh_accum_cnt;
+	int x_est[NUM_BIN + 1], Y[NUM_BIN + 1], theta[NUM_BIN + 1];
+	int PA_in[NUM_BIN + 1];
+	int B1_tmp[NUM_BIN + 1], B2_tmp[NUM_BIN + 1];
+	unsigned int B1_abs_max, B2_abs_max;
+	int max_index, scale_factor;
+	int y_est[NUM_BIN + 1];
+	int x_est_fxp1_nonlin, x_tilde[NUM_BIN + 1];
+	unsigned int x_tilde_abs;
+	int G_fxp, Y_intercept, order_x_by_y, M, I, L, sum_y_sqr, sum_y_quad;
+	int Q_x, Q_B1, Q_B2, beta_raw, alpha_raw, scale_B;
+	int Q_scale_B, Q_beta, Q_alpha, alpha, beta, order_1, order_2;
+	int order1_5x, order2_3x, order1_5x_rem, order2_3x_rem;
+	int y5, y3, tmp;
+	int theta_low_bin = 0;
+	int i;
+
+	/* disregard any bin that contains <= 16 samples */
+	thresh_accum_cnt = 16;
+	scale_factor = 5;
+	max_index = 0;
+	memset(theta, 0, sizeof(theta));
+	memset(x_est, 0, sizeof(x_est));
+	memset(Y, 0, sizeof(Y));
+	memset(y_est, 0, sizeof(y_est));
+	memset(x_tilde, 0, sizeof(x_tilde));
+
+	for (i = 0; i < NUM_BIN; i++) {
+		s32 accum_cnt, accum_tx, accum_rx, accum_ang;
+
+		/* number of samples */
+		accum_cnt = data_L[i] & 0xffff;
+
+		if (accum_cnt <= thresh_accum_cnt)
+			continue;
+
+		/* sum(tx amplitude) */
+		accum_tx = ((data_L[i] >> 16) & 0xffff) |
+		    ((data_U[i] & 0x7ff) << 16);
+
+		/* sum(rx amplitude distance to lower bin edge) */
+		accum_rx = ((data_U[i] >> 11) & 0x1f) |
+		    ((data_L[i + 23] & 0xffff) << 5);
+
+		/* sum(angles) */
+		accum_ang = ((data_L[i + 23] >> 16) & 0xffff) |
+		    ((data_U[i + 23] & 0x7ff) << 16);
+
+		accum_tx <<= scale_factor;
+		accum_rx <<= scale_factor;
+		x_est[i + 1] = (((accum_tx + accum_cnt) / accum_cnt) + 32) >>
+		    scale_factor;
+
+		Y[i + 1] = ((((accum_rx + accum_cnt) / accum_cnt) + 32) >>
+			    scale_factor) +
+			    (1 << scale_factor) * max_index + 16;
+
+		if (accum_ang >= (1 << 26))
+			accum_ang -= 1 << 27;
+
+		theta[i + 1] = ((accum_ang * (1 << scale_factor)) + accum_cnt) /
+		    accum_cnt;
+
+		max_index++;
+	}
+
+	/*
+	 * Find average theta of first 5 bin and all of those to same value.
+	 * Curve is linear at that range.
+	 */
+	for (i = 1; i < 6; i++)
+		theta_low_bin += theta[i];
+
+	theta_low_bin = theta_low_bin / 5;
+	for (i = 1; i < 6; i++)
+		theta[i] = theta_low_bin;
+
+	/* Set values at origin */
+	theta[0] = theta_low_bin;
+	for (i = 0; i <= max_index; i++)
+		theta[i] -= theta_low_bin;
+
+	x_est[0] = 0;
+	Y[0] = 0;
+	scale_factor = 8;
+
+	/* low signal gain */
+	if (x_est[6] == x_est[3])
+		return false;
+
+	G_fxp =
+	    (((Y[6] - Y[3]) * 1 << scale_factor) +
+	     (x_est[6] - x_est[3])) / (x_est[6] - x_est[3]);
+
+	Y_intercept =
+	    (G_fxp * (x_est[0] - x_est[3]) +
+	     (1 << scale_factor)) / (1 << scale_factor) + Y[3];
+
+	for (i = 0; i <= max_index; i++)
+		y_est[i] = Y[i] - Y_intercept;
+
+	for (i = 0; i <= 3; i++) {
+		y_est[i] = i * 32;
+
+		/* prevent division by zero */
+		if (G_fxp == 0)
+			return false;
+
+		x_est[i] = ((y_est[i] * 1 << scale_factor) + G_fxp) / G_fxp;
+	}
+
+	x_est_fxp1_nonlin =
+	    x_est[max_index] - ((1 << scale_factor) * y_est[max_index] +
+				G_fxp) / G_fxp;
+
+	order_x_by_y =
+	    (x_est_fxp1_nonlin + y_est[max_index]) / y_est[max_index];
+
+	if (order_x_by_y == 0)
+		M = 10;
+	else if (order_x_by_y == 1)
+		M = 9;
+	else
+		M = 8;
+
+	I = (max_index > 15) ? 7 : max_index >> 1;
+	L = max_index - I;
+	scale_factor = 8;
+	sum_y_sqr = 0;
+	sum_y_quad = 0;
+	x_tilde_abs = 0;
+
+	for (i = 0; i <= L; i++) {
+		unsigned int y_sqr;
+		unsigned int y_quad;
+		unsigned int tmp_abs;
+
+		/* prevent division by zero */
+		if (y_est[i + I] == 0)
+			return false;
+
+		x_est_fxp1_nonlin =
+		    x_est[i + I] - ((1 << scale_factor) * y_est[i + I] +
+				    G_fxp) / G_fxp;
+
+		x_tilde[i] =
+		    (x_est_fxp1_nonlin * (1 << M) + y_est[i + I]) / y_est[i +
+									  I];
+		x_tilde[i] =
+		    (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I];
+		x_tilde[i] =
+		    (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I];
+		y_sqr =
+		    (y_est[i + I] * y_est[i + I] +
+		     (scale_factor * scale_factor)) / (scale_factor *
+						       scale_factor);
+		tmp_abs = abs(x_tilde[i]);
+		if (tmp_abs > x_tilde_abs)
+			x_tilde_abs = tmp_abs;
+
+		y_quad = y_sqr * y_sqr;
+		sum_y_sqr = sum_y_sqr + y_sqr;
+		sum_y_quad = sum_y_quad + y_quad;
+		B1_tmp[i] = y_sqr * (L + 1);
+		B2_tmp[i] = y_sqr;
+	}
+
+	B1_abs_max = 0;
+	B2_abs_max = 0;
+	for (i = 0; i <= L; i++) {
+		int abs_val;
+
+		B1_tmp[i] -= sum_y_sqr;
+		B2_tmp[i] = sum_y_quad - sum_y_sqr * B2_tmp[i];
+
+		abs_val = abs(B1_tmp[i]);
+		if (abs_val > B1_abs_max)
+			B1_abs_max = abs_val;
+
+		abs_val = abs(B2_tmp[i]);
+		if (abs_val > B2_abs_max)
+			B2_abs_max = abs_val;
+	}
+
+	Q_x = find_proper_scale(find_expn(x_tilde_abs), 10);
+	Q_B1 = find_proper_scale(find_expn(B1_abs_max), 10);
+	Q_B2 = find_proper_scale(find_expn(B2_abs_max), 10);
+
+	beta_raw = 0;
+	alpha_raw = 0;
+	for (i = 0; i <= L; i++) {
+		x_tilde[i] = x_tilde[i] / (1 << Q_x);
+		B1_tmp[i] = B1_tmp[i] / (1 << Q_B1);
+		B2_tmp[i] = B2_tmp[i] / (1 << Q_B2);
+		beta_raw = beta_raw + B1_tmp[i] * x_tilde[i];
+		alpha_raw = alpha_raw + B2_tmp[i] * x_tilde[i];
+	}
+
+	scale_B =
+	    ((sum_y_quad / scale_factor) * (L + 1) -
+	     (sum_y_sqr / scale_factor) * sum_y_sqr) * scale_factor;
+
+	Q_scale_B = find_proper_scale(find_expn(abs(scale_B)), 10);
+	scale_B = scale_B / (1 << Q_scale_B);
+	Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10);
+	Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10);
+	beta_raw = beta_raw / (1 << Q_beta);
+	alpha_raw = alpha_raw / (1 << Q_alpha);
+	alpha = (alpha_raw << 10) / scale_B;
+	beta = (beta_raw << 10) / scale_B;
+	order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B;
+	order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B;
+	order1_5x = order_1 / 5;
+	order2_3x = order_2 / 3;
+	order1_5x_rem = order_1 - 5 * order1_5x;
+	order2_3x_rem = order_2 - 3 * order2_3x;
+
+	for (i = 0; i < PAPRD_TABLE_SZ; i++) {
+		tmp = i * 32;
+		y5 = ((beta * tmp) >> 6) >> order1_5x;
+		y5 = (y5 * tmp) >> order1_5x;
+		y5 = (y5 * tmp) >> order1_5x;
+		y5 = (y5 * tmp) >> order1_5x;
+		y5 = (y5 * tmp) >> order1_5x;
+		y5 = y5 >> order1_5x_rem;
+		y3 = (alpha * tmp) >> order2_3x;
+		y3 = (y3 * tmp) >> order2_3x;
+		y3 = (y3 * tmp) >> order2_3x;
+		y3 = y3 >> order2_3x_rem;
+		PA_in[i] = y5 + y3 + (256 * tmp) / G_fxp;
+
+		if (i >= 2) {
+			tmp = PA_in[i] - PA_in[i - 1];
+			if (tmp < 0)
+				PA_in[i] =
+				    PA_in[i - 1] + (PA_in[i - 1] -
+						    PA_in[i - 2]);
+		}
+
+		PA_in[i] = (PA_in[i] < 1400) ? PA_in[i] : 1400;
+	}
+
+	beta_raw = 0;
+	alpha_raw = 0;
+
+	for (i = 0; i <= L; i++) {
+		int theta_tilde =
+		    ((theta[i + I] << M) + y_est[i + I]) / y_est[i + I];
+		theta_tilde =
+		    ((theta_tilde << M) + y_est[i + I]) / y_est[i + I];
+		theta_tilde =
+		    ((theta_tilde << M) + y_est[i + I]) / y_est[i + I];
+		beta_raw = beta_raw + B1_tmp[i] * theta_tilde;
+		alpha_raw = alpha_raw + B2_tmp[i] * theta_tilde;
+	}
+
+	Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10);
+	Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10);
+	beta_raw = beta_raw / (1 << Q_beta);
+	alpha_raw = alpha_raw / (1 << Q_alpha);
+
+	alpha = (alpha_raw << 10) / scale_B;
+	beta = (beta_raw << 10) / scale_B;
+	order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B + 5;
+	order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B + 5;
+	order1_5x = order_1 / 5;
+	order2_3x = order_2 / 3;
+	order1_5x_rem = order_1 - 5 * order1_5x;
+	order2_3x_rem = order_2 - 3 * order2_3x;
+
+	for (i = 0; i < PAPRD_TABLE_SZ; i++) {
+		int PA_angle;
+
+		/* pa_table[4] is calculated from PA_angle for i=5 */
+		if (i == 4)
+			continue;
+
+		tmp = i * 32;
+		if (beta > 0)
+			y5 = (((beta * tmp - 64) >> 6) -
+			      (1 << order1_5x)) / (1 << order1_5x);
+		else
+			y5 = ((((beta * tmp - 64) >> 6) +
+			       (1 << order1_5x)) / (1 << order1_5x));
+
+		y5 = (y5 * tmp) / (1 << order1_5x);
+		y5 = (y5 * tmp) / (1 << order1_5x);
+		y5 = (y5 * tmp) / (1 << order1_5x);
+		y5 = (y5 * tmp) / (1 << order1_5x);
+		y5 = y5 / (1 << order1_5x_rem);
+
+		if (beta > 0)
+			y3 = (alpha * tmp -
+			      (1 << order2_3x)) / (1 << order2_3x);
+		else
+			y3 = (alpha * tmp +
+			      (1 << order2_3x)) / (1 << order2_3x);
+		y3 = (y3 * tmp) / (1 << order2_3x);
+		y3 = (y3 * tmp) / (1 << order2_3x);
+		y3 = y3 / (1 << order2_3x_rem);
+
+		if (i < 4) {
+			PA_angle = 0;
+		} else {
+			PA_angle = y5 + y3;
+			if (PA_angle < -150)
+				PA_angle = -150;
+			else if (PA_angle > 150)
+				PA_angle = 150;
+		}
+
+		pa_table[i] = ((PA_in[i] & 0x7ff) << 11) + (PA_angle & 0x7ff);
+		if (i == 5) {
+			PA_angle = (PA_angle + 2) >> 1;
+			pa_table[i - 1] = ((PA_in[i - 1] & 0x7ff) << 11) +
+			    (PA_angle & 0x7ff);
+		}
+	}
+
+	*gain = G_fxp;
+	return true;
+}
+
+void ar9003_paprd_populate_single_table(struct ath_hw *ah,
+					struct ath9k_channel *chan, int chain)
+{
+	u32 *paprd_table_val = chan->pa_table[chain];
+	u32 small_signal_gain = chan->small_signal_gain[chain];
+	u32 training_power;
+	u32 reg = 0;
+	int i;
+
+	training_power =
+	    REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
+			   AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
+	training_power -= 4;
+
+	if (chain == 0)
+		reg = AR_PHY_PAPRD_MEM_TAB_B0;
+	else if (chain == 1)
+		reg = AR_PHY_PAPRD_MEM_TAB_B1;
+	else if (chain == 2)
+		reg = AR_PHY_PAPRD_MEM_TAB_B2;
+
+	for (i = 0; i < PAPRD_TABLE_SZ; i++) {
+		REG_WRITE(ah, reg, paprd_table_val[i]);
+		reg = reg + 4;
+	}
+
+	if (chain == 0)
+		reg = AR_PHY_PA_GAIN123_B0;
+	else if (chain == 1)
+		reg = AR_PHY_PA_GAIN123_B1;
+	else
+		reg = AR_PHY_PA_GAIN123_B2;
+
+	REG_RMW_FIELD(ah, reg, AR_PHY_PA_GAIN123_PA_GAIN1, small_signal_gain);
+
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B0,
+		      AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
+		      training_power);
+
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1,
+		      AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
+		      training_power);
+
+	REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2,
+		      AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
+		      training_power);
+}
+EXPORT_SYMBOL(ar9003_paprd_populate_single_table);
+
+int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
+{
+
+	unsigned int i, desired_gain, gain_index;
+	unsigned int train_power;
+
+	train_power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
+				     AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
+
+	train_power = train_power - 4;
+
+	desired_gain = ar9003_get_desired_gain(ah, chain, train_power);
+
+	gain_index = 0;
+	for (i = 0; i < 32; i++) {
+		if (ah->paprd_gain_table_index[i] >= desired_gain)
+			break;
+		gain_index++;
+	}
+
+	ar9003_tx_force_gain(ah, gain_index);
+
+	REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+			AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
+
+	return 0;
+}
+EXPORT_SYMBOL(ar9003_paprd_setup_gain_table);
+
+int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_channel *chan,
+			      int chain)
+{
+	u16 *small_signal_gain = &chan->small_signal_gain[chain];
+	u32 *pa_table = chan->pa_table[chain];
+	u32 *data_L, *data_U;
+	int i, status = 0;
+	u32 *buf;
+	u32 reg;
+
+	memset(chan->pa_table[chain], 0, sizeof(chan->pa_table[chain]));
+
+	buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC);
+	if (!buf)
+		return -ENOMEM;
+
+	data_L = &buf[0];
+	data_U = &buf[48];
+
+	REG_CLR_BIT(ah, AR_PHY_CHAN_INFO_MEMORY,
+		    AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ);
+
+	reg = AR_PHY_CHAN_INFO_TAB_0;
+	for (i = 0; i < 48; i++)
+		data_L[i] = REG_READ(ah, reg + (i << 2));
+
+	REG_SET_BIT(ah, AR_PHY_CHAN_INFO_MEMORY,
+		    AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ);
+
+	for (i = 0; i < 48; i++)
+		data_U[i] = REG_READ(ah, reg + (i << 2));
+
+	if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain))
+		status = -2;
+
+	REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+		    AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
+
+	kfree(buf);
+
+	return status;
+}
+EXPORT_SYMBOL(ar9003_paprd_create_curve);
+
+int ar9003_paprd_init_table(struct ath_hw *ah)
+{
+	ar9003_paprd_setup_single_table(ah);
+	ar9003_paprd_get_gain_table(ah);
+	return 0;
+}
+EXPORT_SYMBOL(ar9003_paprd_init_table);
+
+bool ar9003_paprd_is_done(struct ath_hw *ah)
+{
+	return !!REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+				AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
+}
+EXPORT_SYMBOL(ar9003_paprd_is_done);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 80431a2..a753a43 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -17,6 +17,28 @@
 #include "hw.h"
 #include "ar9003_phy.h"
 
+static const int firstep_table[] =
+/* level:  0   1   2   3   4   5   6   7   8  */
+	{ -4, -2,  0,  2,  4,  6,  8, 10, 12 }; /* lvl 0-8, default 2 */
+
+static const int cycpwrThr1_table[] =
+/* level:  0   1   2   3   4   5   6   7   8  */
+	{ -6, -4, -2,  0,  2,  4,  6,  8 };     /* lvl 0-7, default 3 */
+
+/*
+ * register values to turn OFDM weak signal detection OFF
+ */
+static const int m1ThreshLow_off = 127;
+static const int m2ThreshLow_off = 127;
+static const int m1Thresh_off = 127;
+static const int m2Thresh_off = 127;
+static const int m2CountThr_off =  31;
+static const int m2CountThrLow_off =  63;
+static const int m1ThreshLowExt_off = 127;
+static const int m2ThreshLowExt_off = 127;
+static const int m1ThreshExt_off = 127;
+static const int m2ThreshExt_off = 127;
+
 /**
  * ar9003_hw_set_channel - set channel on single-chip device
  * @ah: atheros hardware structure
@@ -94,7 +116,7 @@
 }
 
 /**
- * ar9003_hw_spur_mitigate - convert baseband spur frequency
+ * ar9003_hw_spur_mitigate_mrc_cck - convert baseband spur frequency
  * @ah: atheros hardware structure
  * @chan:
  *
@@ -521,15 +543,6 @@
 		u32 val = INI_RA(iniArr, i, column);
 
 		REG_WRITE(ah, reg, val);
-
-		/*
-		 * Determine if this is a shift register value, and insert the
-		 * configured delay if so.
-		 */
-		if (reg >= 0x16000 && reg < 0x17000
-		    && ah->config.analog_shiftreg)
-			udelay(100);
-
 		DO_DELAY(regWrites);
 	}
 }
@@ -732,71 +745,68 @@
 {
 	struct ar5416AniState *aniState = ah->curani;
 	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_channel *chan = ah->curchan;
+	s32 value, value2;
 
 	switch (cmd & ah->ani_function) {
-	case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
-		u32 level = param;
-
-		if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
-			ath_print(common, ATH_DBG_ANI,
-				  "level out of range (%u > %u)\n",
-				  level,
-				  (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
-			return false;
-		}
-
-		REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
-			      AR_PHY_DESIRED_SZ_TOT_DES,
-			      ah->totalSizeDesired[level]);
-		REG_RMW_FIELD(ah, AR_PHY_AGC,
-			      AR_PHY_AGC_COARSE_LOW,
-			      ah->coarse_low[level]);
-		REG_RMW_FIELD(ah, AR_PHY_AGC,
-			      AR_PHY_AGC_COARSE_HIGH,
-			      ah->coarse_high[level]);
-		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
-			      AR_PHY_FIND_SIG_FIRPWR, ah->firpwr[level]);
-
-		if (level > aniState->noiseImmunityLevel)
-			ah->stats.ast_ani_niup++;
-		else if (level < aniState->noiseImmunityLevel)
-			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 };
+		/*
+		 * on == 1 means ofdm weak signal detection is ON
+		 * on == 1 is the default, for less noise immunity
+		 *
+		 * on == 0 means ofdm weak signal detection is OFF
+		 * on == 0 means more noise imm
+		 */
 		u32 on = param ? 1 : 0;
+		/*
+		 * make register setting for default
+		 * (weak sig detect ON) come from INI file
+		 */
+		int m1ThreshLow = on ?
+			aniState->iniDef.m1ThreshLow : m1ThreshLow_off;
+		int m2ThreshLow = on ?
+			aniState->iniDef.m2ThreshLow : m2ThreshLow_off;
+		int m1Thresh = on ?
+			aniState->iniDef.m1Thresh : m1Thresh_off;
+		int m2Thresh = on ?
+			aniState->iniDef.m2Thresh : m2Thresh_off;
+		int m2CountThr = on ?
+			aniState->iniDef.m2CountThr : m2CountThr_off;
+		int m2CountThrLow = on ?
+			aniState->iniDef.m2CountThrLow : m2CountThrLow_off;
+		int m1ThreshLowExt = on ?
+			aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off;
+		int m2ThreshLowExt = on ?
+			aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off;
+		int m1ThreshExt = on ?
+			aniState->iniDef.m1ThreshExt : m1ThreshExt_off;
+		int m2ThreshExt = on ?
+			aniState->iniDef.m2ThreshExt : m2ThreshExt_off;
 
 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
 			      AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
-			      m1ThreshLow[on]);
+			      m1ThreshLow);
 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
 			      AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
-			      m2ThreshLow[on]);
+			      m2ThreshLow);
 		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-			      AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]);
+			      AR_PHY_SFCORR_M1_THRESH, m1Thresh);
 		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-			      AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]);
+			      AR_PHY_SFCORR_M2_THRESH, m2Thresh);
 		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-			      AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]);
+			      AR_PHY_SFCORR_M2COUNT_THR, m2CountThr);
 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
 			      AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
-			      m2CountThrLow[on]);
+			      m2CountThrLow);
 
 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-			      AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]);
+			      AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLowExt);
 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-			      AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]);
+			      AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLowExt);
 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-			      AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]);
+			      AR_PHY_SFCORR_EXT_M1_THRESH, m1ThreshExt);
 		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-			      AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]);
+			      AR_PHY_SFCORR_EXT_M2_THRESH, m2ThreshExt);
 
 		if (on)
 			REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
@@ -806,6 +816,12 @@
 				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
 
 		if (!on != aniState->ofdmWeakSigDetectOff) {
+			ath_print(common, ATH_DBG_ANI,
+				  "** ch %d: ofdm weak signal: %s=>%s\n",
+				  chan->channel,
+				  !aniState->ofdmWeakSigDetectOff ?
+					"on" : "off",
+				  on ? "on" : "off");
 			if (on)
 				ah->stats.ast_ani_ofdmon++;
 			else
@@ -814,64 +830,167 @@
 		}
 		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)
-				ah->stats.ast_ani_cckhigh++;
-			else
-				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)) {
+		if (level >= ARRAY_SIZE(firstep_table)) {
 			ath_print(common, ATH_DBG_ANI,
-				  "level out of range (%u > %u)\n",
+				  "ATH9K_ANI_FIRSTEP_LEVEL: level "
+				  "out of range (%u > %u)\n",
 				  level,
-				  (unsigned) ARRAY_SIZE(firstep));
+				  (unsigned) ARRAY_SIZE(firstep_table));
 			return false;
 		}
+
+		/*
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value = firstep_table[level] -
+			firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+			aniState->iniDef.firstep;
+		if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+			value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+		if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+			value = ATH9K_SIG_FIRSTEP_SETTING_MAX;
 		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
 			      AR_PHY_FIND_SIG_FIRSTEP,
-			      firstep[level]);
-		if (level > aniState->firstepLevel)
-			ah->stats.ast_ani_stepup++;
-		else if (level < aniState->firstepLevel)
-			ah->stats.ast_ani_stepdown++;
-		aniState->firstepLevel = level;
+			      value);
+		/*
+		 * we need to set first step low register too
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value2 = firstep_table[level] -
+			 firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+			 aniState->iniDef.firstepLow;
+		if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+			value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+		if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+			value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX;
+
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
+			      AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2);
+
+		if (level != aniState->firstepLevel) {
+			ath_print(common, ATH_DBG_ANI,
+				  "** ch %d: level %d=>%d[def:%d] "
+				  "firstep[level]=%d ini=%d\n",
+				  chan->channel,
+				  aniState->firstepLevel,
+				  level,
+				  ATH9K_ANI_FIRSTEP_LVL_NEW,
+				  value,
+				  aniState->iniDef.firstep);
+			ath_print(common, ATH_DBG_ANI,
+				  "** ch %d: level %d=>%d[def:%d] "
+				  "firstep_low[level]=%d ini=%d\n",
+				  chan->channel,
+				  aniState->firstepLevel,
+				  level,
+				  ATH9K_ANI_FIRSTEP_LVL_NEW,
+				  value2,
+				  aniState->iniDef.firstepLow);
+			if (level > aniState->firstepLevel)
+				ah->stats.ast_ani_stepup++;
+			else if (level < aniState->firstepLevel)
+				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)) {
+		if (level >= ARRAY_SIZE(cycpwrThr1_table)) {
 			ath_print(common, ATH_DBG_ANI,
-				  "level out of range (%u > %u)\n",
+				  "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level "
+				  "out of range (%u > %u)\n",
 				  level,
-				  (unsigned) ARRAY_SIZE(cycpwrThr1));
+				  (unsigned) ARRAY_SIZE(cycpwrThr1_table));
 			return false;
 		}
+		/*
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value = cycpwrThr1_table[level] -
+			cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+			aniState->iniDef.cycpwrThr1;
+		if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+			value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+		if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+			value = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
 		REG_RMW_FIELD(ah, AR_PHY_TIMING5,
 			      AR_PHY_TIMING5_CYCPWR_THR1,
-			      cycpwrThr1[level]);
-		if (level > aniState->spurImmunityLevel)
-			ah->stats.ast_ani_spurup++;
-		else if (level < aniState->spurImmunityLevel)
-			ah->stats.ast_ani_spurdown++;
-		aniState->spurImmunityLevel = level;
+			      value);
+
+		/*
+		 * set AR_PHY_EXT_CCA for extension channel
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value2 = cycpwrThr1_table[level] -
+			 cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+			 aniState->iniDef.cycpwrThr1Ext;
+		if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+			value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+		if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+			value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
+		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+			      AR_PHY_EXT_CYCPWR_THR1, value2);
+
+		if (level != aniState->spurImmunityLevel) {
+			ath_print(common, ATH_DBG_ANI,
+				  "** ch %d: level %d=>%d[def:%d] "
+				  "cycpwrThr1[level]=%d ini=%d\n",
+				  chan->channel,
+				  aniState->spurImmunityLevel,
+				  level,
+				  ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+				  value,
+				  aniState->iniDef.cycpwrThr1);
+			ath_print(common, ATH_DBG_ANI,
+				  "** ch %d: level %d=>%d[def:%d] "
+				  "cycpwrThr1Ext[level]=%d ini=%d\n",
+				  chan->channel,
+				  aniState->spurImmunityLevel,
+				  level,
+				  ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+				  value2,
+				  aniState->iniDef.cycpwrThr1Ext);
+			if (level > aniState->spurImmunityLevel)
+				ah->stats.ast_ani_spurup++;
+			else if (level < aniState->spurImmunityLevel)
+				ah->stats.ast_ani_spurdown++;
+			aniState->spurImmunityLevel = level;
+		}
 		break;
 	}
+	case ATH9K_ANI_MRC_CCK:{
+		/*
+		 * is_on == 1 means MRC CCK ON (default, less noise imm)
+		 * is_on == 0 means MRC CCK is OFF (more noise imm)
+		 */
+		bool is_on = param ? 1 : 0;
+		REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
+			      AR_PHY_MRC_CCK_ENABLE, is_on);
+		REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
+			      AR_PHY_MRC_CCK_MUX_REG, is_on);
+		if (!is_on != aniState->mrcCCKOff) {
+			ath_print(common, ATH_DBG_ANI,
+				  "** ch %d: MRC CCK: %s=>%s\n",
+				  chan->channel,
+				  !aniState->mrcCCKOff ? "on" : "off",
+				  is_on ? "on" : "off");
+		if (is_on)
+			ah->stats.ast_ani_ccklow++;
+		else
+			ah->stats.ast_ani_cckhigh++;
+		aniState->mrcCCKOff = !is_on;
+		}
+	break;
+	}
 	case ATH9K_ANI_PRESENT:
 		break;
 	default:
@@ -880,158 +999,126 @@
 		return false;
 	}
 
-	ath_print(common, ATH_DBG_ANI, "ANI parameters:\n");
 	ath_print(common, ATH_DBG_ANI,
-		  "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
-		  "ofdmWeakSigDetectOff=%d\n",
-		  aniState->noiseImmunityLevel,
+		  "ANI parameters: SI=%d, ofdmWS=%s FS=%d "
+		  "MRCcck=%s listenTime=%d CC=%d listen=%d "
+		  "ofdmErrs=%d cckErrs=%d\n",
 		  aniState->spurImmunityLevel,
-		  !aniState->ofdmWeakSigDetectOff);
-	ath_print(common, ATH_DBG_ANI,
-		  "cckWeakSigThreshold=%d, "
-		  "firstepLevel=%d, listenTime=%d\n",
-		  aniState->cckWeakSigThreshold,
+		  !aniState->ofdmWeakSigDetectOff ? "on" : "off",
 		  aniState->firstepLevel,
-		  aniState->listenTime);
-	ath_print(common, ATH_DBG_ANI,
-		"cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
-		aniState->cycleCount,
-		aniState->ofdmPhyErrCount,
-		aniState->cckPhyErrCount);
-
+		  !aniState->mrcCCKOff ? "on" : "off",
+		  aniState->listenTime,
+		  aniState->cycleCount,
+		  aniState->listenTime,
+		  aniState->ofdmPhyErrCount,
+		  aniState->cckPhyErrCount);
 	return true;
 }
 
-static void ar9003_hw_nf_sanitize_2g(struct ath_hw *ah, s16 *nf)
-{
-	struct ath_common *common = ath9k_hw_common(ah);
-
-	if (*nf > ah->nf_2g_max) {
-		ath_print(common, ATH_DBG_CALIBRATE,
-			  "2 GHz NF (%d) > MAX (%d), "
-			  "correcting to MAX",
-			  *nf, ah->nf_2g_max);
-		*nf = ah->nf_2g_max;
-	} else if (*nf < ah->nf_2g_min) {
-		ath_print(common, ATH_DBG_CALIBRATE,
-			  "2 GHz NF (%d) < MIN (%d), "
-			  "correcting to MIN",
-			  *nf, ah->nf_2g_min);
-		*nf = ah->nf_2g_min;
-	}
-}
-
-static void ar9003_hw_nf_sanitize_5g(struct ath_hw *ah, s16 *nf)
-{
-	struct ath_common *common = ath9k_hw_common(ah);
-
-	if (*nf > ah->nf_5g_max) {
-		ath_print(common, ATH_DBG_CALIBRATE,
-			  "5 GHz NF (%d) > MAX (%d), "
-			  "correcting to MAX",
-			  *nf, ah->nf_5g_max);
-		*nf = ah->nf_5g_max;
-	} else if (*nf < ah->nf_5g_min) {
-		ath_print(common, ATH_DBG_CALIBRATE,
-			  "5 GHz NF (%d) < MIN (%d), "
-			  "correcting to MIN",
-			  *nf, ah->nf_5g_min);
-		*nf = ah->nf_5g_min;
-	}
-}
-
-static void ar9003_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
-{
-	if (IS_CHAN_2GHZ(ah->curchan))
-		ar9003_hw_nf_sanitize_2g(ah, nf);
-	else
-		ar9003_hw_nf_sanitize_5g(ah, nf);
-}
-
 static void ar9003_hw_do_getnf(struct ath_hw *ah,
 			      int16_t nfarray[NUM_NF_READINGS])
 {
-	struct ath_common *common = ath9k_hw_common(ah);
 	int16_t nf;
 
 	nf = MS(REG_READ(ah, AR_PHY_CCA_0), AR_PHY_MINCCA_PWR);
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ar9003_hw_nf_sanitize(ah, &nf);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ctl] [chain 0] is %d\n", nf);
-	nfarray[0] = nf;
+	nfarray[0] = sign_extend(nf, 9);
 
 	nf = MS(REG_READ(ah, AR_PHY_CCA_1), AR_PHY_CH1_MINCCA_PWR);
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ar9003_hw_nf_sanitize(ah, &nf);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ctl] [chain 1] is %d\n", nf);
-	nfarray[1] = nf;
+	nfarray[1] = sign_extend(nf, 9);
 
 	nf = MS(REG_READ(ah, AR_PHY_CCA_2), AR_PHY_CH2_MINCCA_PWR);
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ar9003_hw_nf_sanitize(ah, &nf);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ctl] [chain 2] is %d\n", nf);
-	nfarray[2] = nf;
+	nfarray[2] = sign_extend(nf, 9);
+
+	if (!IS_CHAN_HT40(ah->curchan))
+		return;
 
 	nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ar9003_hw_nf_sanitize(ah, &nf);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ext] [chain 0] is %d\n", nf);
-	nfarray[3] = nf;
+	nfarray[3] = sign_extend(nf, 9);
 
 	nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_1), AR_PHY_CH1_EXT_MINCCA_PWR);
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ar9003_hw_nf_sanitize(ah, &nf);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ext] [chain 1] is %d\n", nf);
-	nfarray[4] = nf;
+	nfarray[4] = sign_extend(nf, 9);
 
 	nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_2), AR_PHY_CH2_EXT_MINCCA_PWR);
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	ar9003_hw_nf_sanitize(ah, &nf);
-	ath_print(common, ATH_DBG_CALIBRATE,
-		  "NF calibrated [ext] [chain 2] is %d\n", nf);
-	nfarray[5] = nf;
+	nfarray[5] = sign_extend(nf, 9);
 }
 
-void ar9003_hw_set_nf_limits(struct ath_hw *ah)
+static void ar9003_hw_set_nf_limits(struct ath_hw *ah)
 {
-	ah->nf_2g_max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ;
-	ah->nf_2g_min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ;
-	ah->nf_5g_max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ;
-	ah->nf_5g_min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ;
+	ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ;
+	ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ;
+	ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9300_2GHZ;
+	ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ;
+	ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ;
+	ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9300_5GHZ;
 }
 
 /*
- * Find out which of the RX chains are enabled
+ * Initialize the ANI register values with default (ini) values.
+ * This routine is called during a (full) hardware reset after
+ * all the registers are initialised from the INI.
  */
-static u32 ar9003_hw_get_rx_chainmask(struct ath_hw *ah)
+static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
 {
-	u32 chain = REG_READ(ah, AR_PHY_RX_CHAINMASK);
-	/*
-	 * The bits [2:0] indicate the rx chain mask and are to be
-	 * interpreted as follows:
-	 * 00x => Only chain 0 is enabled
-	 * 01x => Chain 1 and 0 enabled
-	 * 1xx => Chain 2,1 and 0 enabled
-	 */
-	return chain & 0x7;
+	struct ar5416AniState *aniState;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_channel *chan = ah->curchan;
+	struct ath9k_ani_default *iniDef;
+	int index;
+	u32 val;
+
+	index = ath9k_hw_get_ani_channel_idx(ah, chan);
+	aniState = &ah->ani[index];
+	ah->curani = aniState;
+	iniDef = &aniState->iniDef;
+
+	ath_print(common, ATH_DBG_ANI,
+		  "ver %d.%d opmode %u chan %d Mhz/0x%x\n",
+		  ah->hw_version.macVersion,
+		  ah->hw_version.macRev,
+		  ah->opmode,
+		  chan->channel,
+		  chan->channelFlags);
+
+	val = REG_READ(ah, AR_PHY_SFCORR);
+	iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH);
+	iniDef->m2Thresh = MS(val, AR_PHY_SFCORR_M2_THRESH);
+	iniDef->m2CountThr = MS(val, AR_PHY_SFCORR_M2COUNT_THR);
+
+	val = REG_READ(ah, AR_PHY_SFCORR_LOW);
+	iniDef->m1ThreshLow = MS(val, AR_PHY_SFCORR_LOW_M1_THRESH_LOW);
+	iniDef->m2ThreshLow = MS(val, AR_PHY_SFCORR_LOW_M2_THRESH_LOW);
+	iniDef->m2CountThrLow = MS(val, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW);
+
+	val = REG_READ(ah, AR_PHY_SFCORR_EXT);
+	iniDef->m1ThreshExt = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH);
+	iniDef->m2ThreshExt = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH);
+	iniDef->m1ThreshLowExt = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH_LOW);
+	iniDef->m2ThreshLowExt = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH_LOW);
+	iniDef->firstep = REG_READ_FIELD(ah,
+					 AR_PHY_FIND_SIG,
+					 AR_PHY_FIND_SIG_FIRSTEP);
+	iniDef->firstepLow = REG_READ_FIELD(ah,
+					    AR_PHY_FIND_SIG_LOW,
+					    AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW);
+	iniDef->cycpwrThr1 = REG_READ_FIELD(ah,
+					    AR_PHY_TIMING5,
+					    AR_PHY_TIMING5_CYCPWR_THR1);
+	iniDef->cycpwrThr1Ext = REG_READ_FIELD(ah,
+					       AR_PHY_EXT_CCA,
+					       AR_PHY_EXT_CYCPWR_THR1);
+
+	/* these levels just got reset to defaults by the INI */
+	aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+	aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
+	aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
+	aniState->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK;
+
+	aniState->cycleCount = 0;
 }
 
-static void ar9003_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
+void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
 {
-	struct ath9k_nfcal_hist *h;
-	unsigned i, j;
-	int32_t val;
+	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
 	const u32 ar9300_cca_regs[6] = {
 		AR_PHY_CCA_0,
 		AR_PHY_CCA_1,
@@ -1040,80 +1127,6 @@
 		AR_PHY_EXT_CCA_1,
 		AR_PHY_EXT_CCA_2,
 	};
-	u8 chainmask, rx_chain_status;
-	struct ath_common *common = ath9k_hw_common(ah);
-
-	rx_chain_status = ar9003_hw_get_rx_chainmask(ah);
-
-	chainmask = 0x3F;
-	h = ah->nfCalHist;
-
-	for (i = 0; i < NUM_NF_READINGS; i++) {
-		if (chainmask & (1 << i)) {
-			val = REG_READ(ah, ar9300_cca_regs[i]);
-			val &= 0xFFFFFE00;
-			val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
-			REG_WRITE(ah, ar9300_cca_regs[i], val);
-		}
-	}
-
-	/*
-	 * Load software filtered NF value into baseband internal minCCApwr
-	 * variable.
-	 */
-	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);
-
-	/*
-	 * Wait for load to complete, should be fast, a few 10s of us.
-	 * The max delay was changed from an original 250us to 10000us
-	 * since 250us often results in NF load timeout and causes deaf
-	 * condition during stress testing 12/12/2009
-	 */
-	for (j = 0; j < 1000; j++) {
-		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
-		     AR_PHY_AGC_CONTROL_NF) == 0)
-			break;
-		udelay(10);
-	}
-
-	/*
-	 * We timed out waiting for the noisefloor to load, probably due to an
-	 * in-progress rx. Simply return here and allow the load plenty of time
-	 * to complete before the next calibration interval.  We need to avoid
-	 * trying to load -50 (which happens below) while the previous load is
-	 * still in progress as this can cause rx deafness. Instead by returning
-	 * here, the baseband nf cal will just be capped by our present
-	 * noisefloor until the next calibration timer.
-	 */
-	if (j == 1000) {
-		ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf "
-			  "to load: AR_PHY_AGC_CONTROL=0x%x\n",
-			  REG_READ(ah, AR_PHY_AGC_CONTROL));
-		return;
-	}
-
-	/*
-	 * Restore maxCCAPower register parameter again so that we're not capped
-	 * by the median we just loaded.  This will be initial (and max) value
-	 * of next noise floor calibration the baseband does.
-	 */
-	for (i = 0; i < NUM_NF_READINGS; i++) {
-		if (chainmask & (1 << i)) {
-			val = REG_READ(ah, ar9300_cca_regs[i]);
-			val &= 0xFFFFFE00;
-			val |= (((u32) (-50) << 1) & 0x1ff);
-			REG_WRITE(ah, ar9300_cca_regs[i], val);
-		}
-	}
-}
-
-void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
-{
-	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
 
 	priv_ops->rf_set_freq = ar9003_hw_set_channel;
 	priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate;
@@ -1130,5 +1143,127 @@
 	priv_ops->set_diversity = ar9003_hw_set_diversity;
 	priv_ops->ani_control = ar9003_hw_ani_control;
 	priv_ops->do_getnf = ar9003_hw_do_getnf;
-	priv_ops->loadnf = ar9003_hw_loadnf;
+	priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
+
+	ar9003_hw_set_nf_limits(ah);
+	memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
 }
+
+void ar9003_hw_bb_watchdog_config(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	u32 idle_tmo_ms = ah->bb_watchdog_timeout_ms;
+	u32 val, idle_count;
+
+	if (!idle_tmo_ms) {
+		/* disable IRQ, disable chip-reset for BB panic */
+		REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_2,
+			  REG_READ(ah, AR_PHY_WATCHDOG_CTL_2) &
+			  ~(AR_PHY_WATCHDOG_RST_ENABLE |
+			    AR_PHY_WATCHDOG_IRQ_ENABLE));
+
+		/* disable watchdog in non-IDLE mode, disable in IDLE mode */
+		REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_1,
+			  REG_READ(ah, AR_PHY_WATCHDOG_CTL_1) &
+			  ~(AR_PHY_WATCHDOG_NON_IDLE_ENABLE |
+			    AR_PHY_WATCHDOG_IDLE_ENABLE));
+
+		ath_print(common, ATH_DBG_RESET, "Disabled BB Watchdog\n");
+		return;
+	}
+
+	/* enable IRQ, disable chip-reset for BB watchdog */
+	val = REG_READ(ah, AR_PHY_WATCHDOG_CTL_2) & AR_PHY_WATCHDOG_CNTL2_MASK;
+	REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_2,
+		  (val | AR_PHY_WATCHDOG_IRQ_ENABLE) &
+		  ~AR_PHY_WATCHDOG_RST_ENABLE);
+
+	/* bound limit to 10 secs */
+	if (idle_tmo_ms > 10000)
+		idle_tmo_ms = 10000;
+
+	/*
+	 * The time unit for watchdog event is 2^15 44/88MHz cycles.
+	 *
+	 * For HT20 we have a time unit of 2^15/44 MHz = .74 ms per tick
+	 * For HT40 we have a time unit of 2^15/88 MHz = .37 ms per tick
+	 *
+	 * Given we use fast clock now in 5 GHz, these time units should
+	 * be common for both 2 GHz and 5 GHz.
+	 */
+	idle_count = (100 * idle_tmo_ms) / 74;
+	if (ah->curchan && IS_CHAN_HT40(ah->curchan))
+		idle_count = (100 * idle_tmo_ms) / 37;
+
+	/*
+	 * enable watchdog in non-IDLE mode, disable in IDLE mode,
+	 * set idle time-out.
+	 */
+	REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_1,
+		  AR_PHY_WATCHDOG_NON_IDLE_ENABLE |
+		  AR_PHY_WATCHDOG_IDLE_MASK |
+		  (AR_PHY_WATCHDOG_NON_IDLE_MASK & (idle_count << 2)));
+
+	ath_print(common, ATH_DBG_RESET,
+		  "Enabled BB Watchdog timeout (%u ms)\n",
+		  idle_tmo_ms);
+}
+
+void ar9003_hw_bb_watchdog_read(struct ath_hw *ah)
+{
+	/*
+	 * we want to avoid printing in ISR context so we save the
+	 * watchdog status to be printed later in bottom half context.
+	 */
+	ah->bb_watchdog_last_status = REG_READ(ah, AR_PHY_WATCHDOG_STATUS);
+
+	/*
+	 * the watchdog timer should reset on status read but to be sure
+	 * sure we write 0 to the watchdog status bit.
+	 */
+	REG_WRITE(ah, AR_PHY_WATCHDOG_STATUS,
+		  ah->bb_watchdog_last_status & ~AR_PHY_WATCHDOG_STATUS_CLR);
+}
+
+void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	u32 rxc_pcnt = 0, rxf_pcnt = 0, txf_pcnt = 0, status;
+
+	if (likely(!(common->debug_mask & ATH_DBG_RESET)))
+		return;
+
+	status = ah->bb_watchdog_last_status;
+	ath_print(common, ATH_DBG_RESET,
+		  "\n==== BB update: BB status=0x%08x ====\n", status);
+	ath_print(common, ATH_DBG_RESET,
+		  "** BB state: wd=%u det=%u rdar=%u rOFDM=%d "
+		  "rCCK=%u tOFDM=%u tCCK=%u agc=%u src=%u **\n",
+		  MS(status, AR_PHY_WATCHDOG_INFO),
+		  MS(status, AR_PHY_WATCHDOG_DET_HANG),
+		  MS(status, AR_PHY_WATCHDOG_RADAR_SM),
+		  MS(status, AR_PHY_WATCHDOG_RX_OFDM_SM),
+		  MS(status, AR_PHY_WATCHDOG_RX_CCK_SM),
+		  MS(status, AR_PHY_WATCHDOG_TX_OFDM_SM),
+		  MS(status, AR_PHY_WATCHDOG_TX_CCK_SM),
+		  MS(status, AR_PHY_WATCHDOG_AGC_SM),
+		  MS(status,AR_PHY_WATCHDOG_SRCH_SM));
+
+	ath_print(common, ATH_DBG_RESET,
+		  "** BB WD cntl: cntl1=0x%08x cntl2=0x%08x **\n",
+		  REG_READ(ah, AR_PHY_WATCHDOG_CTL_1),
+		  REG_READ(ah, AR_PHY_WATCHDOG_CTL_2));
+	ath_print(common, ATH_DBG_RESET,
+		  "** BB mode: BB_gen_controls=0x%08x **\n",
+		  REG_READ(ah, AR_PHY_GEN_CTRL));
+
+	if (ath9k_hw_GetMibCycleCountsPct(ah, &rxc_pcnt, &rxf_pcnt, &txf_pcnt))
+		ath_print(common, ATH_DBG_RESET,
+			  "** BB busy times: rx_clear=%d%%, "
+			  "rx_frame=%d%%, tx_frame=%d%% **\n",
+			  rxc_pcnt, rxf_pcnt, txf_pcnt);
+
+	ath_print(common, ATH_DBG_RESET,
+		  "==== BB update: done ====\n\n");
+}
+EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index f08cc8b..3394dfe 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -149,6 +149,8 @@
 #define AR_PHY_EXT_CCA_THRESH62_S       16
 #define AR_PHY_EXT_MINCCA_PWR   0x01FF0000
 #define AR_PHY_EXT_MINCCA_PWR_S 16
+#define AR_PHY_EXT_CYCPWR_THR1 0x0000FE00L
+#define AR_PHY_EXT_CYCPWR_THR1_S 9
 #define AR_PHY_TIMING5_CYCPWR_THR1  0x000000FE
 #define AR_PHY_TIMING5_CYCPWR_THR1_S    1
 #define AR_PHY_TIMING5_CYCPWR_THR1_ENABLE  0x00000001
@@ -283,6 +285,12 @@
 #define AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ                           0x1ffffe00
 #define AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ_S                                  9
 
+#define AR_PHY_MRC_CCK_CTRL         (AR_AGC_BASE + 0x1d0)
+#define AR_PHY_MRC_CCK_ENABLE       0x00000001
+#define AR_PHY_MRC_CCK_ENABLE_S              0
+#define AR_PHY_MRC_CCK_MUX_REG      0x00000002
+#define AR_PHY_MRC_CCK_MUX_REG_S             1
+
 #define AR_PHY_RX_OCGAIN        (AR_AGC_BASE + 0x200)
 
 #define AR_PHY_CCA_NOM_VAL_9300_2GHZ          -110
@@ -451,7 +459,11 @@
 #define AR_PHY_TSTDAC            (AR_SM_BASE + 0x168)
 
 #define AR_PHY_CHAN_STATUS       (AR_SM_BASE + 0x16c)
-#define AR_PHY_CHAN_INFO_MEMORY  (AR_SM_BASE + 0x170)
+
+#define AR_PHY_CHAN_INFO_MEMORY				(AR_SM_BASE + 0x170)
+#define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ	0x00000008
+#define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ_S	3
+
 #define AR_PHY_CHNINFO_NOISEPWR  (AR_SM_BASE + 0x174)
 #define AR_PHY_CHNINFO_GAINDIFF  (AR_SM_BASE + 0x178)
 #define AR_PHY_CHNINFO_FINETIM   (AR_SM_BASE + 0x17c)
@@ -467,30 +479,86 @@
 #define AR_PHY_PWRTX_MAX         (AR_SM_BASE + 0x1f0)
 #define AR_PHY_POWER_TX_SUB      (AR_SM_BASE + 0x1f4)
 
-#define AR_PHY_TPC_4_B0          (AR_SM_BASE + 0x204)
-#define AR_PHY_TPC_5_B0          (AR_SM_BASE + 0x208)
-#define AR_PHY_TPC_6_B0          (AR_SM_BASE + 0x20c)
-#define AR_PHY_TPC_11_B0         (AR_SM_BASE + 0x220)
-#define AR_PHY_TPC_18            (AR_SM_BASE + 0x23c)
-#define AR_PHY_TPC_19            (AR_SM_BASE + 0x240)
+#define AR_PHY_TPC_1				(AR_SM_BASE + 0x1f8)
+#define AR_PHY_TPC_1_FORCED_DAC_GAIN		0x0000003e
+#define AR_PHY_TPC_1_FORCED_DAC_GAIN_S		1
+#define AR_PHY_TPC_1_FORCE_DAC_GAIN		0x00000001
+#define AR_PHY_TPC_1_FORCE_DAC_GAIN_S		0
 
-#define AR_PHY_TX_FORCED_GAIN    (AR_SM_BASE + 0x258)
+#define AR_PHY_TPC_4_B0				(AR_SM_BASE + 0x204)
+#define AR_PHY_TPC_5_B0				(AR_SM_BASE + 0x208)
+#define AR_PHY_TPC_6_B0				(AR_SM_BASE + 0x20c)
+
+#define AR_PHY_TPC_11_B0			(AR_SM_BASE + 0x220)
+#define AR_PHY_TPC_11_B1			(AR_SM1_BASE + 0x220)
+#define AR_PHY_TPC_11_B2			(AR_SM2_BASE + 0x220)
+#define AR_PHY_TPC_11_OLPC_GAIN_DELTA		0x00ff0000
+#define AR_PHY_TPC_11_OLPC_GAIN_DELTA_S		16
+
+#define AR_PHY_TPC_12				(AR_SM_BASE + 0x224)
+#define AR_PHY_TPC_12_DESIRED_SCALE_HT40_5	0x3e000000
+#define AR_PHY_TPC_12_DESIRED_SCALE_HT40_5_S	25
+
+#define AR_PHY_TPC_18				(AR_SM_BASE + 0x23c)
+#define AR_PHY_TPC_18_THERM_CAL_VALUE           0x000000ff
+#define AR_PHY_TPC_18_THERM_CAL_VALUE_S         0
+#define AR_PHY_TPC_18_VOLT_CAL_VALUE		0x0000ff00
+#define AR_PHY_TPC_18_VOLT_CAL_VALUE_S		8
+
+#define AR_PHY_TPC_19				(AR_SM_BASE + 0x240)
+#define AR_PHY_TPC_19_ALPHA_VOLT		0x001f0000
+#define AR_PHY_TPC_19_ALPHA_VOLT_S		16
+#define AR_PHY_TPC_19_ALPHA_THERM		0xff
+#define AR_PHY_TPC_19_ALPHA_THERM_S		0
+
+#define AR_PHY_TX_FORCED_GAIN				(AR_SM_BASE + 0x258)
+#define AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN		0x00000001
+#define AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN_S		0
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN	0x0000000e
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN_S	1
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN	0x00000030
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN_S	4
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN		0x000003c0
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN_S	6
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA		0x00003c00
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA_S		10
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB		0x0003c000
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB_S		14
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC		0x003c0000
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC_S		18
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND		0x00c00000
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND_S		22
+#define AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL		0x01000000
+#define AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL_S	24
+
 
 #define AR_PHY_PDADC_TAB_0       (AR_SM_BASE + 0x280)
 
+#define AR_PHY_TXGAIN_TABLE      (AR_SM_BASE + 0x300)
+
 #define AR_PHY_TX_IQCAL_CONTROL_1   (AR_SM_BASE + 0x448)
 #define AR_PHY_TX_IQCAL_START       (AR_SM_BASE + 0x440)
 #define AR_PHY_TX_IQCAL_STATUS_B0   (AR_SM_BASE + 0x48c)
 #define AR_PHY_TX_IQCAL_CORR_COEFF_01_B0    (AR_SM_BASE + 0x450)
 
-#define AR_PHY_PANIC_WD_STATUS      (AR_SM_BASE + 0x5c0)
-#define AR_PHY_PANIC_WD_CTL_1       (AR_SM_BASE + 0x5c4)
-#define AR_PHY_PANIC_WD_CTL_2       (AR_SM_BASE + 0x5c8)
-#define AR_PHY_BT_CTL               (AR_SM_BASE + 0x5cc)
+#define AR_PHY_WATCHDOG_STATUS      (AR_SM_BASE + 0x5c0)
+#define AR_PHY_WATCHDOG_CTL_1       (AR_SM_BASE + 0x5c4)
+#define AR_PHY_WATCHDOG_CTL_2       (AR_SM_BASE + 0x5c8)
+#define AR_PHY_WATCHDOG_CTL         (AR_SM_BASE + 0x5cc)
 #define AR_PHY_ONLY_WARMRESET       (AR_SM_BASE + 0x5d0)
 #define AR_PHY_ONLY_CTL             (AR_SM_BASE + 0x5d4)
 #define AR_PHY_ECO_CTRL             (AR_SM_BASE + 0x5dc)
-#define AR_PHY_BB_THERM_ADC_1       (AR_SM_BASE + 0x248)
+
+#define AR_PHY_BB_THERM_ADC_1				(AR_SM_BASE + 0x248)
+#define AR_PHY_BB_THERM_ADC_1_INIT_THERM		0x000000ff
+#define AR_PHY_BB_THERM_ADC_1_INIT_THERM_S		0
+
+#define AR_PHY_BB_THERM_ADC_4				(AR_SM_BASE + 0x254)
+#define AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE	0x000000ff
+#define AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE_S	0
+#define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE		0x0000ff00
+#define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE_S	8
+
 
 #define AR_PHY_65NM_CH0_SYNTH4      0x1608c
 #define AR_PHY_SYNTH4_LONG_SHIFT_SELECT   0x00000002
@@ -660,17 +728,9 @@
 #define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE      0x00003fff
 #define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE_S    0
 
-#define AR_PHY_TPC_18_THERM_CAL_VALUE           0xff
-#define AR_PHY_TPC_18_THERM_CAL_VALUE_S         0
-#define AR_PHY_TPC_19_ALPHA_THERM               0xff
-#define AR_PHY_TPC_19_ALPHA_THERM_S             0
-
 #define AR_PHY_65NM_CH0_RXTX4_THERM_ON          0x10000000
 #define AR_PHY_65NM_CH0_RXTX4_THERM_ON_S        28
 
-#define AR_PHY_BB_THERM_ADC_1_INIT_THERM        0x000000ff
-#define AR_PHY_BB_THERM_ADC_1_INIT_THERM_S      0
-
 /*
  * Channel 1 Register Map
  */
@@ -812,35 +872,173 @@
 #define AR_PHY_CAL_MEAS_2_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_2_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
 #define AR_PHY_CAL_MEAS_3_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_3_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
 
-#define AR_PHY_BB_PANIC_NON_IDLE_ENABLE 0x00000001
-#define AR_PHY_BB_PANIC_IDLE_ENABLE     0x00000002
-#define AR_PHY_BB_PANIC_IDLE_MASK       0xFFFF0000
-#define AR_PHY_BB_PANIC_NON_IDLE_MASK   0x0000FFFC
+#define AR_PHY_WATCHDOG_NON_IDLE_ENABLE    0x00000001
+#define AR_PHY_WATCHDOG_IDLE_ENABLE        0x00000002
+#define AR_PHY_WATCHDOG_IDLE_MASK          0xFFFF0000
+#define AR_PHY_WATCHDOG_NON_IDLE_MASK      0x0000FFFC
 
-#define AR_PHY_BB_PANIC_RST_ENABLE      0x00000002
-#define AR_PHY_BB_PANIC_IRQ_ENABLE      0x00000004
-#define AR_PHY_BB_PANIC_CNTL2_MASK      0xFFFFFFF9
+#define AR_PHY_WATCHDOG_RST_ENABLE         0x00000002
+#define AR_PHY_WATCHDOG_IRQ_ENABLE         0x00000004
+#define AR_PHY_WATCHDOG_CNTL2_MASK         0xFFFFFFF9
 
-#define AR_PHY_BB_WD_STATUS             0x00000007
-#define AR_PHY_BB_WD_STATUS_S           0
-#define AR_PHY_BB_WD_DET_HANG           0x00000008
-#define AR_PHY_BB_WD_DET_HANG_S         3
-#define AR_PHY_BB_WD_RADAR_SM           0x000000F0
-#define AR_PHY_BB_WD_RADAR_SM_S         4
-#define AR_PHY_BB_WD_RX_OFDM_SM         0x00000F00
-#define AR_PHY_BB_WD_RX_OFDM_SM_S       8
-#define AR_PHY_BB_WD_RX_CCK_SM          0x0000F000
-#define AR_PHY_BB_WD_RX_CCK_SM_S        12
-#define AR_PHY_BB_WD_TX_OFDM_SM         0x000F0000
-#define AR_PHY_BB_WD_TX_OFDM_SM_S       16
-#define AR_PHY_BB_WD_TX_CCK_SM          0x00F00000
-#define AR_PHY_BB_WD_TX_CCK_SM_S        20
-#define AR_PHY_BB_WD_AGC_SM             0x0F000000
-#define AR_PHY_BB_WD_AGC_SM_S           24
-#define AR_PHY_BB_WD_SRCH_SM            0xF0000000
-#define AR_PHY_BB_WD_SRCH_SM_S          28
+#define AR_PHY_WATCHDOG_INFO               0x00000007
+#define AR_PHY_WATCHDOG_INFO_S             0
+#define AR_PHY_WATCHDOG_DET_HANG           0x00000008
+#define AR_PHY_WATCHDOG_DET_HANG_S         3
+#define AR_PHY_WATCHDOG_RADAR_SM           0x000000F0
+#define AR_PHY_WATCHDOG_RADAR_SM_S         4
+#define AR_PHY_WATCHDOG_RX_OFDM_SM         0x00000F00
+#define AR_PHY_WATCHDOG_RX_OFDM_SM_S       8
+#define AR_PHY_WATCHDOG_RX_CCK_SM          0x0000F000
+#define AR_PHY_WATCHDOG_RX_CCK_SM_S        12
+#define AR_PHY_WATCHDOG_TX_OFDM_SM         0x000F0000
+#define AR_PHY_WATCHDOG_TX_OFDM_SM_S       16
+#define AR_PHY_WATCHDOG_TX_CCK_SM          0x00F00000
+#define AR_PHY_WATCHDOG_TX_CCK_SM_S        20
+#define AR_PHY_WATCHDOG_AGC_SM             0x0F000000
+#define AR_PHY_WATCHDOG_AGC_SM_S           24
+#define AR_PHY_WATCHDOG_SRCH_SM            0xF0000000
+#define AR_PHY_WATCHDOG_SRCH_SM_S          28
 
-#define AR_PHY_BB_WD_STATUS_CLR         0x00000008
+#define AR_PHY_WATCHDOG_STATUS_CLR         0x00000008
+
+/*
+ * PAPRD registers
+ */
+#define AR_PHY_XPA_TIMING_CTL		(AR_SM_BASE + 0x64)
+
+#define AR_PHY_PAPRD_AM2AM		(AR_CHAN_BASE + 0xe4)
+#define AR_PHY_PAPRD_AM2AM_MASK		0x01ffffff
+#define AR_PHY_PAPRD_AM2AM_MASK_S	0
+
+#define AR_PHY_PAPRD_AM2PM		(AR_CHAN_BASE + 0xe8)
+#define AR_PHY_PAPRD_AM2PM_MASK		0x01ffffff
+#define AR_PHY_PAPRD_AM2PM_MASK_S	0
+
+#define AR_PHY_PAPRD_HT40		(AR_CHAN_BASE + 0xec)
+#define AR_PHY_PAPRD_HT40_MASK		0x01ffffff
+#define AR_PHY_PAPRD_HT40_MASK_S	0
+
+#define AR_PHY_PAPRD_CTRL0_B0				(AR_CHAN_BASE + 0xf0)
+#define AR_PHY_PAPRD_CTRL0_B1				(AR_CHAN1_BASE + 0xf0)
+#define AR_PHY_PAPRD_CTRL0_B2				(AR_CHAN2_BASE + 0xf0)
+#define AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE			0x00000001
+#define AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE_S		0
+#define AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK	0x00000002
+#define AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK_S	1
+#define AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH		0xf8000000
+#define AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH_S		27
+
+#define AR_PHY_PAPRD_CTRL1_B0				(AR_CHAN_BASE + 0xf4)
+#define AR_PHY_PAPRD_CTRL1_B1				(AR_CHAN1_BASE + 0xf4)
+#define AR_PHY_PAPRD_CTRL1_B2				(AR_CHAN2_BASE + 0xf4)
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA		0x00000001
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA_S	0
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE	0x00000002
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE_S	1
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE	0x00000004
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE_S	2
+#define AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL	0x000001f8
+#define AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL_S	3
+#define AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK	0x0001fe00
+#define AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK_S	9
+#define AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT		0x0ffe0000
+#define AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT_S	17
+
+#define AR_PHY_PAPRD_TRAINER_CNTL1				(AR_SM_BASE + 0x490)
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE	0x00000001
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE_S	0
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING	0x0000007e
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING_S	1
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE	0x00000100
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE_S	8
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE	0x00000200
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE_S	9
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE	0x00000400
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE_S	10
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE		0x00000800
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE_S		11
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP		0x0003f000
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP_S		12
+
+#define AR_PHY_PAPRD_TRAINER_CNTL2				(AR_SM_BASE + 0x494)
+#define AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN	0xFFFFFFFF
+#define AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN_S	0
+
+#define AR_PHY_PAPRD_TRAINER_CNTL3				(AR_SM_BASE + 0x498)
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE	0x0000003f
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE_S	0
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP		0x00000fc0
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP_S	6
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL	0x0001f000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL_S	12
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES	0x000e0000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES_S	17
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN	0x00f00000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN_S	20
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN	0x0f000000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN_S	24
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE	0x20000000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE_S	29
+
+#define AR_PHY_PAPRD_TRAINER_CNTL4				(AR_SM_BASE + 0x49c)
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES	0x03ff0000
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES_S	16
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA	0x0000f000
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA_S	12
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR		0x00000fff
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR_S		0
+
+#define AR_PHY_PAPRD_PRE_POST_SCALE_0_B0			(AR_CHAN_BASE + 0x100)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_1_B0			(AR_CHAN_BASE + 0x104)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_2_B0			(AR_CHAN_BASE + 0x108)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_3_B0			(AR_CHAN_BASE + 0x10c)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_4_B0			(AR_CHAN_BASE + 0x110)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_5_B0			(AR_CHAN_BASE + 0x114)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_6_B0			(AR_CHAN_BASE + 0x118)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_7_B0			(AR_CHAN_BASE + 0x11c)
+#define AR_PHY_PAPRD_PRE_POST_SCALING				0x3FFFF
+#define AR_PHY_PAPRD_PRE_POST_SCALING_S				0
+
+#define AR_PHY_PAPRD_TRAINER_STAT1				(AR_SM_BASE + 0x4a0)
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE		0x00000001
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE_S		0
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_INCOMPLETE	0x00000002
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_INCOMPLETE_S	1
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_CORR_ERR		0x00000004
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_CORR_ERR_S		2
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_ACTIVE		0x00000008
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_ACTIVE_S		3
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_RX_GAIN_IDX		0x000001f0
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_RX_GAIN_IDX_S		4
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR		0x0001fe00
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR_S		9
+
+#define AR_PHY_PAPRD_TRAINER_STAT2				(AR_SM_BASE + 0x4a4)
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_VAL		0x0000ffff
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_VAL_S		0
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_COARSE_IDX		0x001f0000
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_COARSE_IDX_S		16
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_IDX		0x00600000
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_IDX_S		21
+
+#define AR_PHY_PAPRD_TRAINER_STAT3				(AR_SM_BASE + 0x4a8)
+#define AR_PHY_PAPRD_TRAINER_STAT3_PAPRD_TRAIN_SAMPLES_CNT	0x000fffff
+#define AR_PHY_PAPRD_TRAINER_STAT3_PAPRD_TRAIN_SAMPLES_CNT_S	0
+
+#define AR_PHY_PAPRD_MEM_TAB_B0			(AR_CHAN_BASE + 0x120)
+#define AR_PHY_PAPRD_MEM_TAB_B1			(AR_CHAN1_BASE + 0x120)
+#define AR_PHY_PAPRD_MEM_TAB_B2			(AR_CHAN2_BASE + 0x120)
+
+#define AR_PHY_PA_GAIN123_B0			(AR_CHAN_BASE + 0xf8)
+#define AR_PHY_PA_GAIN123_B1			(AR_CHAN1_BASE + 0xf8)
+#define AR_PHY_PA_GAIN123_B2			(AR_CHAN2_BASE + 0xf8)
+#define AR_PHY_PA_GAIN123_PA_GAIN1		0x3FF
+#define AR_PHY_PA_GAIN123_PA_GAIN1_S		0
+
+#define AR_PHY_POWERTX_RATE5			(AR_SM_BASE + 0x1d0)
+#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0	0x3F
+#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0_S	0
 
 void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
 
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5ea8773..998ae2c 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -20,6 +20,7 @@
 #include <linux/etherdevice.h>
 #include <linux/device.h>
 #include <linux/leds.h>
+#include <linux/completion.h>
 
 #include "debug.h"
 #include "common.h"
@@ -136,6 +137,8 @@
 #define ATH_MAX_ANTENNA         3
 #define ATH_RXBUF               512
 #define ATH_TXBUF               512
+#define ATH_TXBUF_RESERVE       5
+#define ATH_MAX_QDEPTH          (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
 #define ATH_TXMAXTRY            13
 #define ATH_MGT_TXMAXTRY        4
 
@@ -192,6 +195,7 @@
 
 #define ATH_TXFIFO_DEPTH 8
 struct ath_txq {
+	int axq_class;
 	u32 axq_qnum;
 	u32 *axq_link;
 	struct list_head axq_q;
@@ -206,6 +210,71 @@
 	u8 txq_tailidx;
 };
 
+struct ath_atx_ac {
+	int sched;
+	int qnum;
+	struct list_head list;
+	struct list_head tid_q;
+};
+
+struct ath_buf_state {
+	int bfs_nframes;
+	u16 bfs_al;
+	u16 bfs_frmlen;
+	int bfs_seqno;
+	int bfs_tidno;
+	int bfs_retries;
+	u8 bf_type;
+	u8 bfs_paprd;
+	unsigned long bfs_paprd_timestamp;
+	u32 bfs_keyix;
+	enum ath9k_key_type bfs_keytype;
+};
+
+struct ath_buf {
+	struct list_head list;
+	struct ath_buf *bf_lastbf;	/* last buf of this unit (a frame or
+					   an aggregate) */
+	struct ath_buf *bf_next;	/* next subframe in the aggregate */
+	struct sk_buff *bf_mpdu;	/* enclosing frame structure */
+	void *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 */
+	bool bf_stale;
+	bool bf_isnullfunc;
+	bool bf_tx_aborted;
+	u16 bf_flags;
+	struct ath_buf_state bf_state;
+	dma_addr_t bf_dmacontext;
+	struct ath_wiphy *aphy;
+};
+
+struct ath_atx_tid {
+	struct list_head list;
+	struct list_head buf_q;
+	struct ath_node *an;
+	struct ath_atx_ac *ac;
+	struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
+	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;
+};
+
+struct ath_node {
+	struct ath_common *common;
+	struct ath_atx_tid tid[WME_NUM_TID];
+	struct ath_atx_ac ac[WME_NUM_AC];
+	u16 maxampdu;
+	u8 mpdudensity;
+	int last_rssi;
+};
+
 #define AGGR_CLEANUP         BIT(1)
 #define AGGR_ADDBA_COMPLETE  BIT(2)
 #define AGGR_ADDBA_PROGRESS  BIT(3)
@@ -214,6 +283,7 @@
 	struct ath_txq *txq;
 	int if_id;
 	enum ath9k_internal_frame_type frame_type;
+	u8 paprd;
 };
 
 #define ATH_TX_ERROR        0x01
@@ -223,11 +293,12 @@
 struct ath_tx {
 	u16 seq_no;
 	u32 txqsetup;
-	int hwq_map[ATH9K_WME_AC_VO+1];
+	int hwq_map[WME_NUM_AC];
 	spinlock_t txbuflock;
 	struct list_head txbuf;
 	struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
 	struct ath_descdma txdma;
+	int pending_frames[WME_NUM_AC];
 };
 
 struct ath_rx_edma {
@@ -267,7 +338,6 @@
 void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
 int ath_tx_init(struct ath_softc *sc, int nbufs);
 void ath_tx_cleanup(struct ath_softc *sc);
-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 ieee80211_hw *hw, struct sk_buff *skb,
@@ -351,10 +421,15 @@
 
 #define ATH_STA_SHORT_CALINTERVAL 1000    /* 1 second */
 #define ATH_AP_SHORT_CALINTERVAL  100     /* 100 ms */
-#define ATH_ANI_POLLINTERVAL      100     /* 100 ms */
+#define ATH_ANI_POLLINTERVAL_OLD  100     /* 100 ms */
+#define ATH_ANI_POLLINTERVAL_NEW  1000    /* 1000 ms */
 #define ATH_LONG_CALINTERVAL      30000   /* 30 seconds */
 #define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */
 
+#define ATH_PAPRD_TIMEOUT	100 /* msecs */
+
+void ath_hw_check(struct work_struct *work);
+void ath_paprd_calibrate(struct work_struct *work);
 void ath_ani_calibrate(unsigned long data);
 
 /**********/
@@ -487,6 +562,9 @@
 	spinlock_t sc_serial_rw;
 	spinlock_t sc_pm_lock;
 	struct mutex mutex;
+	struct work_struct paprd_work;
+	struct work_struct hw_check_work;
+	struct completion paprd_complete;
 
 	u32 intrstatus;
 	u32 sc_flags; /* SC_OP_* */
@@ -545,7 +623,6 @@
 
 void ath9k_tasklet(unsigned long data);
 int ath_reset(struct ath_softc *sc, bool retry_tx);
-int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
 int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
 int ath_cabq_update(struct ath_softc *);
 
@@ -556,13 +633,12 @@
 
 extern struct ieee80211_ops ath9k_ops;
 extern int modparam_nohwcrypt;
+extern int led_blink;
 
 irqreturn_t ath_isr(int irq, void *dev);
 int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
 		    const struct ath_bus_ops *bus_ops);
 void ath9k_deinit_device(struct ath_softc *sc);
-const char *ath_mac_bb_name(u32 mac_bb_version);
-const char *ath_rf_name(u16 rf_version);
 void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
 void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
 			   struct ath9k_channel *ichan);
@@ -611,9 +687,7 @@
 void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle);
 
 void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue);
-void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
-
-int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
+bool ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
 
 void ath_start_rfkill_poll(struct ath_softc *sc);
 extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index f43d85a..4d4b22d 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -38,8 +38,7 @@
 		qi.tqi_cwmax = 0;
 	} else {
 		/* Adhoc mode; important thing is to use 2x cwmin. */
-		qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA,
-				       ATH9K_WME_AC_BE);
+		qnum = sc->tx.hwq_map[WME_AC_BE];
 		ath9k_hw_get_txq_props(ah, qnum, &qi_be);
 		qi.tqi_aifs = qi_be.tqi_aifs;
 		qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 07b8fa6..139289e 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -74,13 +74,8 @@
 			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];
-			}
+			h[i].invalidNFcount--;
+			h[i].privNF = nfarray[i];
 		} else {
 			h[i].privNF =
 				ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
@@ -172,6 +167,116 @@
 	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
 }
 
+void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	struct ath9k_nfcal_hist *h;
+	unsigned i, j;
+	int32_t val;
+	u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	h = ah->nfCalHist;
+
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		if (chainmask & (1 << i)) {
+			val = REG_READ(ah, ah->nf_regs[i]);
+			val &= 0xFFFFFE00;
+			val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
+			REG_WRITE(ah, ah->nf_regs[i], val);
+		}
+	}
+
+	/*
+	 * Load software filtered NF value into baseband internal minCCApwr
+	 * variable.
+	 */
+	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);
+
+	/*
+	 * Wait for load to complete, should be fast, a few 10s of us.
+	 * The max delay was changed from an original 250us to 10000us
+	 * since 250us often results in NF load timeout and causes deaf
+	 * condition during stress testing 12/12/2009
+	 */
+	for (j = 0; j < 1000; j++) {
+		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
+		     AR_PHY_AGC_CONTROL_NF) == 0)
+			break;
+		udelay(10);
+	}
+
+	/*
+	 * We timed out waiting for the noisefloor to load, probably due to an
+	 * in-progress rx. Simply return here and allow the load plenty of time
+	 * to complete before the next calibration interval.  We need to avoid
+	 * trying to load -50 (which happens below) while the previous load is
+	 * still in progress as this can cause rx deafness. Instead by returning
+	 * here, the baseband nf cal will just be capped by our present
+	 * noisefloor until the next calibration timer.
+	 */
+	if (j == 1000) {
+		ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf "
+			  "to load: AR_PHY_AGC_CONTROL=0x%x\n",
+			  REG_READ(ah, AR_PHY_AGC_CONTROL));
+		return;
+	}
+
+	/*
+	 * Restore maxCCAPower register parameter again so that we're not capped
+	 * by the median we just loaded.  This will be initial (and max) value
+	 * of next noise floor calibration the baseband does.
+	 */
+	ENABLE_REGWRITE_BUFFER(ah);
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		if (chainmask & (1 << i)) {
+			val = REG_READ(ah, ah->nf_regs[i]);
+			val &= 0xFFFFFE00;
+			val |= (((u32) (-50) << 1) & 0x1ff);
+			REG_WRITE(ah, ah->nf_regs[i], val);
+		}
+	}
+	REGWRITE_BUFFER_FLUSH(ah);
+	DISABLE_REGWRITE_BUFFER(ah);
+}
+
+
+static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath_nf_limits *limit;
+	int i;
+
+	if (IS_CHAN_2GHZ(ah->curchan))
+		limit = &ah->nf_2g;
+	else
+		limit = &ah->nf_5g;
+
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		if (!nf[i])
+			continue;
+
+		ath_print(common, ATH_DBG_CALIBRATE,
+			  "NF calibrated [%s] [chain %d] is %d\n",
+			  (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]);
+
+		if (nf[i] > limit->max) {
+			ath_print(common, ATH_DBG_CALIBRATE,
+				  "NF[%d] (%d) > MAX (%d), correcting to MAX",
+				  i, nf[i], limit->max);
+			nf[i] = limit->max;
+		} else if (nf[i] < limit->min) {
+			ath_print(common, ATH_DBG_CALIBRATE,
+				  "NF[%d] (%d) < MIN (%d), correcting to NOM",
+				  i, nf[i], limit->min);
+			nf[i] = limit->nominal;
+		}
+	}
+}
+
 int16_t ath9k_hw_getnf(struct ath_hw *ah,
 		       struct ath9k_channel *chan)
 {
@@ -190,6 +295,7 @@
 		return chan->rawNoiseFloor;
 	} else {
 		ath9k_hw_do_getnf(ah, nfarray);
+		ath9k_hw_nf_sanitize(ah, nfarray);
 		nf = nfarray[0];
 		if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
 		    && nf > nfThresh) {
@@ -211,25 +317,21 @@
 
 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
 {
+	struct ath_nf_limits *limit;
 	int i, j;
-	s16 noise_floor;
 
-	if (AR_SREV_9280(ah))
-		noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
-	else if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
-		noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
-	else if (AR_SREV_9287(ah))
-		noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE;
+	if (!ah->curchan || IS_CHAN_2GHZ(ah->curchan))
+		limit = &ah->nf_2g;
 	else
-		noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
+		limit = &ah->nf_5g;
 
 	for (i = 0; i < NUM_NF_READINGS; i++) {
 		ah->nfCalHist[i].currIndex = 0;
-		ah->nfCalHist[i].privNF = noise_floor;
+		ah->nfCalHist[i].privNF = limit->nominal;
 		ah->nfCalHist[i].invalidNFcount =
 			AR_PHY_CCA_FILTERWINDOW_LENGTH;
 		for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
-			ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
+			ah->nfCalHist[i].nfCalBuffer[j] = limit->nominal;
 		}
 	}
 }
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index 24538bd..cd60d09 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -19,12 +19,6 @@
 
 #include "hw.h"
 
-#define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE	-85
-#define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE	-112
-#define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE	-118
-#define AR_PHY_CCA_MAX_AR9287_GOOD_VALUE	-118
-#define AR_PHY_CCA_MAX_HIGH_VALUE      		-62
-#define AR_PHY_CCA_MIN_BAD_VALUE       		-140
 #define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT     3
 #define AR_PHY_CCA_FILTERWINDOW_LENGTH          5
 
@@ -115,6 +109,7 @@
 
 bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
 void ath9k_hw_start_nfcal(struct ath_hw *ah);
+void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
 int16_t ath9k_hw_getnf(struct ath_hw *ah,
 		       struct ath9k_channel *chan);
 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index 7707341..c86f7d3 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -27,270 +27,6 @@
 MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards.");
 MODULE_LICENSE("Dual BSD/GPL");
 
-/* Common RX processing */
-
-/* Assumes you've already done the endian to CPU conversion */
-static bool ath9k_rx_accept(struct ath_common *common,
-			    struct sk_buff *skb,
-			    struct ieee80211_rx_status *rxs,
-			    struct ath_rx_status *rx_stats,
-			    bool *decrypt_error)
-{
-	struct ath_hw *ah = common->ah;
-	struct ieee80211_hdr *hdr;
-	__le16 fc;
-
-	hdr = (struct ieee80211_hdr *) skb->data;
-	fc = hdr->frame_control;
-
-	if (!rx_stats->rs_datalen)
-		return false;
-        /*
-         * rs_status follows rs_datalen so if rs_datalen is too large
-         * we can take a hint that hardware corrupted it, so ignore
-         * those frames.
-         */
-	if (rx_stats->rs_datalen > common->rx_bufsize)
-		return false;
-
-	/*
-	 * rs_more indicates chained descriptors which can be used
-	 * to link buffers together for a sort of scatter-gather
-	 * operation.
-	 * reject the frame, we don't support scatter-gather yet and
-	 * the frame is probably corrupt anyway
-	 */
-	if (rx_stats->rs_more)
-		return false;
-
-	/*
-	 * The rx_stats->rs_status will not be set until the end of the
-	 * chained descriptors so it can be ignored if rs_more is set. The
-	 * rs_more will be false at the last element of the chained
-	 * descriptors.
-	 */
-	if (rx_stats->rs_status != 0) {
-		if (rx_stats->rs_status & ATH9K_RXERR_CRC)
-			rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
-		if (rx_stats->rs_status & ATH9K_RXERR_PHY)
-			return false;
-
-		if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
-			*decrypt_error = true;
-		} else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
-			if (ieee80211_is_ctl(fc))
-				/*
-				 * Sometimes, we get invalid
-				 * MIC failures on valid control frames.
-				 * Remove these mic errors.
-				 */
-				rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
-			else
-				rxs->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 (ah->opmode == NL80211_IFTYPE_MONITOR) {
-			if (rx_stats->rs_status &
-			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
-			      ATH9K_RXERR_CRC))
-				return false;
-		} else {
-			if (rx_stats->rs_status &
-			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
-				return false;
-			}
-		}
-	}
-	return true;
-}
-
-static int ath9k_process_rate(struct ath_common *common,
-			      struct ieee80211_hw *hw,
-			      struct ath_rx_status *rx_stats,
-			      struct ieee80211_rx_status *rxs,
-			      struct sk_buff *skb)
-{
-	struct ieee80211_supported_band *sband;
-	enum ieee80211_band band;
-	unsigned int i = 0;
-
-	band = hw->conf.channel->band;
-	sband = hw->wiphy->bands[band];
-
-	if (rx_stats->rs_rate & 0x80) {
-		/* HT rate */
-		rxs->flag |= RX_FLAG_HT;
-		if (rx_stats->rs_flags & ATH9K_RX_2040)
-			rxs->flag |= RX_FLAG_40MHZ;
-		if (rx_stats->rs_flags & ATH9K_RX_GI)
-			rxs->flag |= RX_FLAG_SHORT_GI;
-		rxs->rate_idx = rx_stats->rs_rate & 0x7f;
-		return 0;
-	}
-
-	for (i = 0; i < sband->n_bitrates; i++) {
-		if (sband->bitrates[i].hw_value == rx_stats->rs_rate) {
-			rxs->rate_idx = i;
-			return 0;
-		}
-		if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
-			rxs->flag |= RX_FLAG_SHORTPRE;
-			rxs->rate_idx = i;
-			return 0;
-		}
-	}
-
-	/*
-	 * No valid hardware bitrate found -- we should not get here
-	 * because hardware has already validated this frame as OK.
-	 */
-	ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected "
-		  "0x%02x using 1 Mbit\n", rx_stats->rs_rate);
-	if ((common->debug_mask & ATH_DBG_XMIT))
-		print_hex_dump_bytes("", DUMP_PREFIX_NONE, skb->data, skb->len);
-
-	return -EINVAL;
-}
-
-static void ath9k_process_rssi(struct ath_common *common,
-			       struct ieee80211_hw *hw,
-			       struct sk_buff *skb,
-			       struct ath_rx_status *rx_stats)
-{
-	struct ath_hw *ah = common->ah;
-	struct ieee80211_sta *sta;
-	struct ieee80211_hdr *hdr;
-	struct ath_node *an;
-	int last_rssi = ATH_RSSI_DUMMY_MARKER;
-	__le16 fc;
-
-	hdr = (struct ieee80211_hdr *)skb->data;
-	fc = hdr->frame_control;
-
-	rcu_read_lock();
-	/*
-	 * XXX: use ieee80211_find_sta! This requires quite a bit of work
-	 * under the current ath9k virtual wiphy implementation as we have
-	 * no way of tying a vif to wiphy. Typically vifs are attached to
-	 * at least one sdata of a wiphy on mac80211 but with ath9k virtual
-	 * wiphy you'd have to iterate over every wiphy and each sdata.
-	 */
-	sta = ieee80211_find_sta_by_hw(hw, hdr->addr2);
-	if (sta) {
-		an = (struct ath_node *) sta->drv_priv;
-		if (rx_stats->rs_rssi != ATH9K_RSSI_BAD &&
-		   !rx_stats->rs_moreaggr)
-			ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi);
-		last_rssi = an->last_rssi;
-	}
-	rcu_read_unlock();
-
-	if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
-		rx_stats->rs_rssi = ATH_EP_RND(last_rssi,
-					      ATH_RSSI_EP_MULTIPLIER);
-	if (rx_stats->rs_rssi < 0)
-		rx_stats->rs_rssi = 0;
-
-	/* Update Beacon RSSI, this is used by ANI. */
-	if (ieee80211_is_beacon(fc))
-		ah->stats.avgbrssi = rx_stats->rs_rssi;
-}
-
-/*
- * 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.
- */
-int ath9k_cmn_rx_skb_preprocess(struct ath_common *common,
-				struct ieee80211_hw *hw,
-				struct sk_buff *skb,
-				struct ath_rx_status *rx_stats,
-				struct ieee80211_rx_status *rx_status,
-				bool *decrypt_error)
-{
-	struct ath_hw *ah = common->ah;
-
-	memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
-
-	/*
-	 * everything but the rate is checked here, the rate check is done
-	 * separately to avoid doing two lookups for a rate for each frame.
-	 */
-	if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error))
-		return -EINVAL;
-
-	ath9k_process_rssi(common, hw, skb, rx_stats);
-
-	if (ath9k_process_rate(common, hw, rx_stats, rx_status, skb))
-		return -EINVAL;
-
-	rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp);
-	rx_status->band = hw->conf.channel->band;
-	rx_status->freq = hw->conf.channel->center_freq;
-	rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
-	rx_status->antenna = rx_stats->rs_antenna;
-	rx_status->flag |= RX_FLAG_TSFT;
-
-	return 0;
-}
-EXPORT_SYMBOL(ath9k_cmn_rx_skb_preprocess);
-
-void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
-				  struct sk_buff *skb,
-				  struct ath_rx_status *rx_stats,
-				  struct ieee80211_rx_status *rxs,
-				  bool decrypt_error)
-{
-	struct ath_hw *ah = common->ah;
-	struct ieee80211_hdr *hdr;
-	int hdrlen, padpos, padsize;
-	u8 keyix;
-	__le16 fc;
-
-	/* 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);
-	fc = hdr->frame_control;
-	padpos = ath9k_cmn_padpos(hdr->frame_control);
-
-	/* 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 - padpos % 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 = padpos & 3;
-	if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
-		memmove(skb->data + padsize, skb->data, padpos);
-		skb_pull(skb, padsize);
-	}
-
-	keyix = rx_stats->rs_keyix;
-
-	if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
-	    ieee80211_has_protected(fc)) {
-		rxs->flag |= RX_FLAG_DECRYPTED;
-	} else if (ieee80211_has_protected(fc)
-		   && !decrypt_error && skb->len >= hdrlen + 4) {
-		keyix = skb->data[hdrlen + 3] >> 6;
-
-		if (test_bit(keyix, common->keymap))
-			rxs->flag |= RX_FLAG_DECRYPTED;
-	}
-	if (ah->sw_mgmt_crypto &&
-	    (rxs->flag & RX_FLAG_DECRYPTED) &&
-	    ieee80211_is_mgmt(fc))
-		/* Use software decrypt for management frames. */
-		rxs->flag &= ~RX_FLAG_DECRYPTED;
-}
-EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess);
-
 int ath9k_cmn_padpos(__le16 frame_control)
 {
 	int padpos = 24;
@@ -475,10 +211,14 @@
 	return -1;
 }
 
-static int ath_reserve_key_cache_slot(struct ath_common *common)
+static int ath_reserve_key_cache_slot(struct ath_common *common,
+				      enum ieee80211_key_alg alg)
 {
 	int i;
 
+	if (alg == ALG_TKIP)
+		return ath_reserve_key_cache_slot_tkip(common);
+
 	/* First, try to find slots that would not be available for TKIP. */
 	if (common->splitmic) {
 		for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
@@ -547,6 +287,7 @@
 	struct ath_hw *ah = common->ah;
 	struct ath9k_keyval hk;
 	const u8 *mac = NULL;
+	u8 gmac[ETH_ALEN];
 	int ret = 0;
 	int idx;
 
@@ -570,9 +311,27 @@
 	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;
+		switch (vif->type) {
+		case NL80211_IFTYPE_AP:
+			memcpy(gmac, vif->addr, ETH_ALEN);
+			gmac[0] |= 0x01;
+			mac = gmac;
+			idx = ath_reserve_key_cache_slot(common, key->alg);
+			break;
+		case NL80211_IFTYPE_ADHOC:
+			if (!sta) {
+				idx = key->keyidx;
+				break;
+			}
+			memcpy(gmac, sta->addr, ETH_ALEN);
+			gmac[0] |= 0x01;
+			mac = gmac;
+			idx = ath_reserve_key_cache_slot(common, key->alg);
+			break;
+		default:
+			idx = key->keyidx;
+			break;
+		}
 	} else if (key->keyidx) {
 		if (WARN_ON(!sta))
 			return -EOPNOTSUPP;
@@ -589,14 +348,12 @@
 			return -EOPNOTSUPP;
 		mac = sta->addr;
 
-		if (key->alg == ALG_TKIP)
-			idx = ath_reserve_key_cache_slot_tkip(common);
-		else
-			idx = ath_reserve_key_cache_slot(common);
-		if (idx < 0)
-			return -ENOSPC; /* no free key cache entries */
+		idx = ath_reserve_key_cache_slot(common, key->alg);
 	}
 
+	if (idx < 0)
+		return -ENOSPC; /* no free key cache entries */
+
 	if (key->alg == ALG_TKIP)
 		ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
 				      vif->type == NL80211_IFTYPE_AP);
@@ -644,6 +401,19 @@
 }
 EXPORT_SYMBOL(ath9k_cmn_key_delete);
 
+int ath9k_cmn_count_streams(unsigned int chainmask, int max)
+{
+	int streams = 0;
+
+	do {
+		if (++streams == max)
+			break;
+	} while ((chainmask = chainmask & (chainmask - 1)));
+
+	return streams;
+}
+EXPORT_SYMBOL(ath9k_cmn_count_streams);
+
 static int __init ath9k_cmn_init(void)
 {
 	return 0;
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index e08f7e5..97809d3 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -52,82 +52,6 @@
 #define ATH_EP_RND(x, mul) 						\
 	((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
 
-struct ath_atx_ac {
-	int sched;
-	int qnum;
-	struct list_head list;
-	struct list_head tid_q;
-};
-
-struct ath_buf_state {
-	int bfs_nframes;
-	u16 bfs_al;
-	u16 bfs_frmlen;
-	int bfs_seqno;
-	int bfs_tidno;
-	int bfs_retries;
-	u8 bf_type;
-	u32 bfs_keyix;
-	enum ath9k_key_type bfs_keytype;
-};
-
-struct ath_buf {
-	struct list_head list;
-	struct ath_buf *bf_lastbf;	/* last buf of this unit (a frame or
-					   an aggregate) */
-	struct ath_buf *bf_next;	/* next subframe in the aggregate */
-	struct sk_buff *bf_mpdu;	/* enclosing frame structure */
-	void *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 */
-	bool bf_stale;
-	bool bf_isnullfunc;
-	bool bf_tx_aborted;
-	u16 bf_flags;
-	struct ath_buf_state bf_state;
-	dma_addr_t bf_dmacontext;
-	struct ath_wiphy *aphy;
-};
-
-struct ath_atx_tid {
-	struct list_head list;
-	struct list_head buf_q;
-	struct ath_node *an;
-	struct ath_atx_ac *ac;
-	struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
-	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;
-};
-
-struct ath_node {
-	struct ath_common *common;
-	struct ath_atx_tid tid[WME_NUM_TID];
-	struct ath_atx_ac ac[WME_NUM_AC];
-	u16 maxampdu;
-	u8 mpdudensity;
-	int last_rssi;
-};
-
-int ath9k_cmn_rx_skb_preprocess(struct ath_common *common,
-				struct ieee80211_hw *hw,
-				struct sk_buff *skb,
-				struct ath_rx_status *rx_stats,
-				struct ieee80211_rx_status *rx_status,
-				bool *decrypt_error);
-
-void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
-				  struct sk_buff *skb,
-				  struct ath_rx_status *rx_stats,
-				  struct ieee80211_rx_status *rxs,
-				  bool decrypt_error);
-
 int ath9k_cmn_padpos(__le16 frame_control);
 int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
 void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
@@ -140,3 +64,4 @@
 			 struct ieee80211_key_conf *key);
 void ath9k_cmn_key_delete(struct ath_common *common,
 			  struct ieee80211_key_conf *key);
+int ath9k_cmn_count_streams(unsigned int chainmask, int max);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 29898f8..54aae93 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -42,7 +42,7 @@
 	char buf[32];
 	unsigned int len;
 
-	len = snprintf(buf, sizeof(buf), "0x%08x\n", common->debug_mask);
+	len = sprintf(buf, "0x%08x\n", common->debug_mask);
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -57,7 +57,7 @@
 
 	len = min(count, sizeof(buf) - 1);
 	if (copy_from_user(buf, user_buf, len))
-		return -EINVAL;
+		return -EFAULT;
 
 	buf[len] = '\0';
 	if (strict_strtoul(buf, 0, &mask))
@@ -86,7 +86,7 @@
 	char buf[32];
 	unsigned int len;
 
-	len = snprintf(buf, sizeof(buf), "0x%08x\n", common->tx_chainmask);
+	len = sprintf(buf, "0x%08x\n", common->tx_chainmask);
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -101,7 +101,7 @@
 
 	len = min(count, sizeof(buf) - 1);
 	if (copy_from_user(buf, user_buf, len))
-		return -EINVAL;
+		return -EFAULT;
 
 	buf[len] = '\0';
 	if (strict_strtoul(buf, 0, &mask))
@@ -128,7 +128,7 @@
 	char buf[32];
 	unsigned int len;
 
-	len = snprintf(buf, sizeof(buf), "0x%08x\n", common->rx_chainmask);
+	len = sprintf(buf, "0x%08x\n", common->rx_chainmask);
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -143,7 +143,7 @@
 
 	len = min(count, sizeof(buf) - 1);
 	if (copy_from_user(buf, user_buf, len))
-		return -EINVAL;
+		return -EFAULT;
 
 	buf[len] = '\0';
 	if (strict_strtoul(buf, 0, &mask))
@@ -176,7 +176,7 @@
 
 	buf = kmalloc(DMA_BUF_LEN, GFP_KERNEL);
 	if (!buf)
-		return 0;
+		return -ENOMEM;
 
 	ath9k_ps_wakeup(sc);
 
@@ -248,6 +248,9 @@
 
 	ath9k_ps_restore(sc);
 
+	if (len > DMA_BUF_LEN)
+		len = DMA_BUF_LEN;
+
 	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 	kfree(buf);
 	return retval;
@@ -269,6 +272,8 @@
 			sc->debug.stats.istats.rxlp++;
 		if (status & ATH9K_INT_RXHP)
 			sc->debug.stats.istats.rxhp++;
+		if (status & ATH9K_INT_BB_WATCHDOG)
+			sc->debug.stats.istats.bb_watchdog++;
 	} else {
 		if (status & ATH9K_INT_RX)
 			sc->debug.stats.istats.rxok++;
@@ -319,6 +324,9 @@
 			"%8s: %10u\n", "RXLP", sc->debug.stats.istats.rxlp);
 		len += snprintf(buf + len, sizeof(buf) - len,
 			"%8s: %10u\n", "RXHP", sc->debug.stats.istats.rxhp);
+		len += snprintf(buf + len, sizeof(buf) - len,
+			"%8s: %10u\n", "WATCHDOG",
+			sc->debug.stats.istats.bb_watchdog);
 	} else {
 		len += snprintf(buf + len, sizeof(buf) - len,
 			"%8s: %10u\n", "RX", sc->debug.stats.istats.rxok);
@@ -358,6 +366,9 @@
 	len += snprintf(buf + len, sizeof(buf) - len,
 		"%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total);
 
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -397,11 +408,10 @@
 	if (sc->cur_rate_table == NULL)
 		return 0;
 
-	max = 80 + sc->cur_rate_table->rate_cnt * 1024;
-	buf = kmalloc(max + 1, GFP_KERNEL);
+	max = 80 + sc->cur_rate_table->rate_cnt * 1024 + 1;
+	buf = kmalloc(max, GFP_KERNEL);
 	if (buf == NULL)
-		return 0;
-	buf[max] = 0;
+		return -ENOMEM;
 
 	len += sprintf(buf, "%6s %6s %6s "
 		       "%10s %10s %10s %10s\n",
@@ -443,6 +453,9 @@
 			stats->per);
 	}
 
+	if (len > max)
+		len = max;
+
 	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 	kfree(buf);
 	return retval;
@@ -505,6 +518,9 @@
 	len += snprintf(buf + len, sizeof(buf) - len,
 			"addrmask: %pM\n", addr);
 
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -614,10 +630,10 @@
 	do {								\
 		len += snprintf(buf + len, size - len,			\
 				"%s%13u%11u%10u%10u\n", str,		\
-		sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BE]].elem, \
-		sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BK]].elem, \
-		sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VI]].elem, \
-		sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VO]].elem); \
+		sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_BE]].elem, \
+		sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_BK]].elem, \
+		sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_VI]].elem, \
+		sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_VO]].elem); \
 } while(0)
 
 static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
@@ -630,7 +646,7 @@
 
 	buf = kzalloc(size, GFP_KERNEL);
 	if (buf == NULL)
-		return 0;
+		return -ENOMEM;
 
 	len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO");
 
@@ -648,6 +664,9 @@
 	PR("DATA Underrun:   ", data_underrun);
 	PR("DELIM Underrun:  ", delim_underrun);
 
+	if (len > size)
+		len = size;
+
 	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 	kfree(buf);
 
@@ -700,7 +719,7 @@
 
 	buf = kzalloc(size, GFP_KERNEL);
 	if (buf == NULL)
-		return 0;
+		return -ENOMEM;
 
 	len += snprintf(buf + len, size - len,
 			"%18s : %10u\n", "CRC ERR",
@@ -751,6 +770,9 @@
 	PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
 	PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
 
+	if (len > size)
+		len = size;
+
 	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 	kfree(buf);
 
@@ -802,7 +824,7 @@
 	char buf[32];
 	unsigned int len;
 
-	len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.regidx);
+	len = sprintf(buf, "0x%08x\n", sc->debug.regidx);
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -816,7 +838,7 @@
 
 	len = min(count, sizeof(buf) - 1);
 	if (copy_from_user(buf, user_buf, len))
-		return -EINVAL;
+		return -EFAULT;
 
 	buf[len] = '\0';
 	if (strict_strtoul(buf, 0, &regidx))
@@ -843,7 +865,7 @@
 	u32 regval;
 
 	regval = REG_READ_D(ah, sc->debug.regidx);
-	len = snprintf(buf, sizeof(buf), "0x%08x\n", regval);
+	len = sprintf(buf, "0x%08x\n", regval);
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -858,7 +880,7 @@
 
 	len = min(count, sizeof(buf) - 1);
 	if (copy_from_user(buf, user_buf, len))
-		return -EINVAL;
+		return -EFAULT;
 
 	buf[len] = '\0';
 	if (strict_strtoul(buf, 0, &regval))
@@ -934,6 +956,10 @@
 			sc->debug.debugfs_phy, sc, &fops_regval))
 		goto err;
 
+	if (!debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR,
+			sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca))
+		goto err;
+
 	sc->debug.regidx = 0;
 	return 0;
 err:
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 5147b87..5d21704 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -53,6 +53,7 @@
  * @cabend: RX End of CAB traffic
  * @dtimsync: DTIM sync lossage
  * @dtim: RX Beacon with DTIM
+ * @bb_watchdog: Baseband watchdog
  */
 struct ath_interrupt_stats {
 	u32 total;
@@ -76,6 +77,7 @@
 	u32 cabend;
 	u32 dtimsync;
 	u32 dtim;
+	u32 bb_watchdog;
 };
 
 struct ath_rc_stats {
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index ca8704a..1266333 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -24,6 +24,14 @@
 	return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
 }
 
+void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
+{
+        REG_WRITE(ah, reg, val);
+
+        if (ah->config.analog_shiftreg)
+		udelay(100);
+}
+
 void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
 			       u32 shift, u32 val)
 {
@@ -250,6 +258,27 @@
 	return twiceMaxEdgePower;
 }
 
+void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+
+	switch (ar5416_get_ntxchains(ah->txchainmask)) {
+	case 1:
+		break;
+	case 2:
+		regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
+		break;
+	case 3:
+		regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
+		break;
+	default:
+		ath_print(common, ATH_DBG_EEPROM,
+			  "Invalid chainmask configuration\n");
+		break;
+	}
+}
+
 int ath9k_hw_eeprom_init(struct ath_hw *ah)
 {
 	int status;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 21354c1..8750c55 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -263,7 +263,8 @@
 	EEP_PWR_TABLE_OFFSET,
 	EEP_DRIVE_STRENGTH,
 	EEP_INTERNAL_REGULATOR,
-	EEP_SWREG
+	EEP_SWREG,
+	EEP_PAPRD,
 };
 
 enum ar5416_rates {
@@ -669,7 +670,7 @@
 	int (*get_eeprom_ver)(struct ath_hw *hw);
 	int (*get_eeprom_rev)(struct ath_hw *hw);
 	u8 (*get_num_ant_config)(struct ath_hw *hw, enum ieee80211_band band);
-	u16 (*get_eeprom_antenna_cfg)(struct ath_hw *hw,
+	u32 (*get_eeprom_antenna_cfg)(struct ath_hw *hw,
 				      struct ath9k_channel *chan);
 	void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
 	void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan);
@@ -679,6 +680,7 @@
 	u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
 };
 
+void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val);
 void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
 			       u32 shift, u32 val);
 int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
@@ -704,6 +706,7 @@
 				u16 numRates, bool isHt40Target);
 u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
 				bool is2GHz, int num_band_edges);
+void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah);
 int ath9k_hw_eeprom_init(struct ath_hw *ah);
 
 #define ar5416_get_ntxchains(_txchainmask)			\
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 41a77d1..9cccd12 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -222,7 +222,7 @@
 				struct ath9k_channel *chan,
 				struct cal_data_per_freq_4k *pRawDataSet,
 				u8 *bChans, u16 availPiers,
-				u16 tPdGainOverlap, int16_t *pMinCalPower,
+				u16 tPdGainOverlap,
 				u16 *pPdGainBoundaries, u8 *pPDADCValues,
 				u16 numXpdGains)
 {
@@ -249,6 +249,7 @@
 	struct chan_centers centers;
 #define PD_GAIN_BOUNDARY_DEFAULT 58;
 
+	memset(&minPwrT4, 0, AR9287_NUM_PD_GAINS);
 	ath9k_hw_get_channel_centers(ah, chan, &centers);
 
 	for (numPiers = 0; numPiers < availPiers; numPiers++) {
@@ -307,8 +308,6 @@
 		}
 	}
 
-	*pMinCalPower = (int16_t)(minPwrT4[0] / 2);
-
 	k = 0;
 
 	for (i = 0; i < numXpdGains; i++) {
@@ -398,7 +397,6 @@
 	static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
 	u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK];
 	u16 numPiers, i, j;
-	int16_t tMinCalPower;
 	u16 numXpdGain, xpdMask;
 	u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 };
 	u32 reg32, regOffset, regChainOffset;
@@ -451,7 +449,7 @@
 			ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan,
 					    pRawDataset, pCalBChans,
 					    numPiers, pdGainOverlap_t2,
-					    &tMinCalPower, gainBoundaries,
+					    gainBoundaries,
 					    pdadcValues, numXpdGain);
 
 			ENABLE_REGWRITE_BUFFER(ah);
@@ -1149,13 +1147,13 @@
 	}
 }
 
-static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah,
+static u32 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah,
 					      struct ath9k_channel *chan)
 {
 	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
 	struct modal_eep_4k_header *pModal = &eep->modalHeader;
 
-	return pModal->antCtrlCommon & 0xFFFF;
+	return pModal->antCtrlCommon;
 }
 
 static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index b471db5..4a52cf0 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -17,17 +17,19 @@
 #include "hw.h"
 #include "ar9002_phy.h"
 
-static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah)
+#define NUM_EEP_WORDS (sizeof(struct ar9287_eeprom) / sizeof(u16))
+
+static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah)
 {
 	return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF;
 }
 
-static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah)
+static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah)
 {
 	return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF;
 }
 
-static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
+static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
 {
 	struct ar9287_eeprom *eep = &ah->eeprom.map9287;
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -40,20 +42,20 @@
 			  "Reading from EEPROM, not flash\n");
 	}
 
-	for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16);
-			addr++)	{
-		if (!ath9k_hw_nvram_read(common,
-					 addr + eep_start_loc, eep_data)) {
+	for (addr = 0; addr < NUM_EEP_WORDS; addr++) {
+		if (!ath9k_hw_nvram_read(common, addr + eep_start_loc,
+					 eep_data)) {
 			ath_print(common, ATH_DBG_EEPROM,
 				  "Unable to read eeprom region\n");
 			return false;
 		}
 		eep_data++;
 	}
+
 	return true;
 }
 
-static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
+static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
 {
 	u32 sum = 0, el, integer;
 	u16 temp, word, magic, magic2, *eepdata;
@@ -63,8 +65,8 @@
 	struct ath_common *common = ath9k_hw_common(ah);
 
 	if (!ath9k_hw_use_flash(ah)) {
-		if (!ath9k_hw_nvram_read(common,
-					 AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
+		if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
+					 &magic)) {
 			ath_print(common, ATH_DBG_FATAL,
 				  "Reading Magic # failed\n");
 			return false;
@@ -72,6 +74,7 @@
 
 		ath_print(common, ATH_DBG_EEPROM,
 			  "Read Magic = 0x%04X\n", magic);
+
 		if (magic != AR5416_EEPROM_MAGIC) {
 			magic2 = swab16(magic);
 
@@ -79,9 +82,7 @@
 				need_swap = true;
 				eepdata = (u16 *)(&ah->eeprom);
 
-				for (addr = 0;
-				     addr < sizeof(struct ar9287_eeprom) / sizeof(u16);
-				     addr++) {
+				for (addr = 0; addr < NUM_EEP_WORDS; addr++) {
 					temp = swab16(*eepdata);
 					*eepdata = temp;
 					eepdata++;
@@ -89,13 +90,14 @@
 			} else {
 				ath_print(common, ATH_DBG_FATAL,
 					  "Invalid EEPROM Magic. "
-					  "endianness mismatch.\n");
+					  "Endianness mismatch.\n");
 				return -EINVAL;
 			}
 		}
 	}
-	ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ?
-		  "True" : "False");
+
+	ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
+		  need_swap ? "True" : "False");
 
 	if (need_swap)
 		el = swab16(ah->eeprom.map9287.baseEepHeader.length);
@@ -108,6 +110,7 @@
 		el = el / sizeof(u16);
 
 	eepdata = (u16 *)(&ah->eeprom);
+
 	for (i = 0; i < el; i++)
 		sum ^= *eepdata++;
 
@@ -161,7 +164,7 @@
 	return 0;
 }
 
-static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah,
+static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
 				      enum eeprom_param param)
 {
 	struct ar9287_eeprom *eep = &ah->eeprom.map9287;
@@ -170,6 +173,7 @@
 	u16 ver_minor;
 
 	ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK;
+
 	switch (param) {
 	case EEP_NFTHRESH_2:
 		return pModal->noiseFloorThreshCh[0];
@@ -214,29 +218,29 @@
 	}
 }
 
-
-static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
-				   struct ath9k_channel *chan,
-				   struct cal_data_per_freq_ar9287 *pRawDataSet,
-				   u8 *bChans,  u16 availPiers,
-				   u16 tPdGainOverlap, int16_t *pMinCalPower,
-				   u16 *pPdGainBoundaries, u8 *pPDADCValues,
-				   u16 numXpdGains)
+static void ath9k_hw_get_ar9287_gain_boundaries_pdadcs(struct ath_hw *ah,
+			       struct ath9k_channel *chan,
+			       struct cal_data_per_freq_ar9287 *pRawDataSet,
+			       u8 *bChans, u16 availPiers,
+			       u16 tPdGainOverlap,
+			       u16 *pPdGainBoundaries,
+			       u8 *pPDADCValues,
+			       u16 numXpdGains)
 {
-#define TMP_VAL_VPD_TABLE \
+#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;
-	u8   *pVpdL, *pVpdR, *pPwrL, *pPwrR;
-	u8   minPwrT4[AR9287_NUM_PD_GAINS];
-	u8   maxPwrT4[AR9287_NUM_PD_GAINS];
-	int16_t   vpdStep;
-	int16_t   tmpVal;
-	u16  sizeCurrVpdTable, maxIndex, tgtIndex;
-	bool    match;
-	int16_t  minDelta = 0;
+	int i, j, k;
+	int16_t ss;
+	u16 idxL = 0, idxR = 0, numPiers;
+	u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+	u8 minPwrT4[AR9287_NUM_PD_GAINS];
+	u8 maxPwrT4[AR9287_NUM_PD_GAINS];
+	int16_t vpdStep;
+	int16_t tmpVal;
+	u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+	bool match;
+	int16_t minDelta = 0;
 	struct chan_centers centers;
 	static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS]
 		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
@@ -245,6 +249,7 @@
 	static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS]
 		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
 
+	memset(&minPwrT4, 0, AR9287_NUM_PD_GAINS);
 	ath9k_hw_get_channel_centers(ah, chan, &centers);
 
 	for (numPiers = 0; numPiers < availPiers; numPiers++) {
@@ -253,18 +258,18 @@
 	}
 
 	match = ath9k_hw_get_lower_upper_index(
-				   (u8)FREQ2FBIN(centers.synth_center,
-				    IS_CHAN_2GHZ(chan)), bChans, numPiers,
-				    &idxL, &idxR);
+		(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],
-					AR9287_PD_GAIN_ICEPTS, vpdTableI[i]);
+						pRawDataSet[idxL].pwrPdg[i],
+						pRawDataSet[idxL].vpdPdg[i],
+						AR9287_PD_GAIN_ICEPTS,
+						vpdTableI[i]);
 		}
 	} else {
 		for (i = 0; i < numXpdGains; i++) {
@@ -275,61 +280,58 @@
 
 			minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
 
-			maxPwrT4[i] =
-				min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1],
-				    pPwrR[AR9287_PD_GAIN_ICEPTS - 1]);
+			maxPwrT4[i] = min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1],
+					  pPwrR[AR9287_PD_GAIN_ICEPTS - 1]);
 
 			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
-					pPwrL, pVpdL,
-					AR9287_PD_GAIN_ICEPTS,
-					vpdTableL[i]);
+						pPwrL, pVpdL,
+						AR9287_PD_GAIN_ICEPTS,
+						vpdTableL[i]);
 			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
-					pPwrR, pVpdR,
-					AR9287_PD_GAIN_ICEPTS,
-					vpdTableR[i]);
+						pPwrR, pVpdR,
+						AR9287_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]));
+				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);
+			pPdGainBoundaries[i] =
+				(u16)(maxPwrT4[i] / 2);
 		else
-			pPdGainBoundaries[i] = (u16)((maxPwrT4[i] +
-						      minPwrT4[i+1]) / 4);
+			pPdGainBoundaries[i] =
+				(u16)((maxPwrT4[i] + minPwrT4[i+1]) / 4);
 
 		pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER,
-					    pPdGainBoundaries[i]);
+					   pPdGainBoundaries[i]);
 
 
-		if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
-			minDelta = pPdGainBoundaries[0] - 23;
-			pPdGainBoundaries[0] = 23;
-		} else
-			minDelta = 0;
+		minDelta = 0;
 
 		if (i == 0) {
 			if (AR_SREV_9280_10_OR_LATER(ah))
 				ss = (int16_t)(0 - (minPwrT4[i] / 2));
 			else
 				ss = 0;
-		} else
+		} else {
 			ss = (int16_t)((pPdGainBoundaries[i-1] -
-				       (minPwrT4[i] / 2)) -
+					(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 < (AR9287_NUM_PDADC_VALUES - 1)))	{
 			tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
 			pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
@@ -348,12 +350,13 @@
 		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 < (AR9287_NUM_PDADC_VALUES - 1))) {
 				tmpVal = (int16_t) TMP_VAL_VPD_TABLE;
-				pPDADCValues[k++] = (u8)((tmpVal > 255) ?
-							  255 : tmpVal);
+				pPDADCValues[k++] =
+					(u8)((tmpVal > 255) ? 255 : tmpVal);
 				ss++;
 			}
 		}
@@ -375,10 +378,9 @@
 static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
 			    struct ath9k_channel *chan,
 			    struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
-			    u8 *pCalChans,  u16 availPiers,
-			    int8_t *pPwr)
+			    u8 *pCalChans,  u16 availPiers, int8_t *pPwr)
 {
-	u16  idxL = 0, idxR = 0, numPiers;
+	u16 idxL = 0, idxR = 0, numPiers;
 	bool match;
 	struct chan_centers centers;
 
@@ -390,15 +392,14 @@
 	}
 
 	match = ath9k_hw_get_lower_upper_index(
-			(u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
-			pCalChans, numPiers,
-			&idxL, &idxR);
+		(u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
+		pCalChans, numPiers, &idxL, &idxR);
 
 	if (match) {
 		*pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0];
 	} else {
 		*pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
-			    (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
+			 (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
 	}
 
 }
@@ -409,16 +410,22 @@
 	u32 tmpVal;
 	u32 a;
 
+	/* Enable OLPC for chain 0 */
+
 	tmpVal = REG_READ(ah, 0xa270);
 	tmpVal = tmpVal & 0xFCFFFFFF;
 	tmpVal = tmpVal | (0x3 << 24);
 	REG_WRITE(ah, 0xa270, tmpVal);
 
+	/* Enable OLPC for chain 1 */
+
 	tmpVal = REG_READ(ah, 0xb270);
 	tmpVal = tmpVal & 0xFCFFFFFF;
 	tmpVal = tmpVal | (0x3 << 24);
 	REG_WRITE(ah, 0xb270, tmpVal);
 
+	/* Write the OLPC ref power for chain 0 */
+
 	if (chain == 0) {
 		tmpVal = REG_READ(ah, 0xa398);
 		tmpVal = tmpVal & 0xff00ffff;
@@ -427,6 +434,8 @@
 		REG_WRITE(ah, 0xa398, tmpVal);
 	}
 
+	/* Write the OLPC ref power for chain 1 */
+
 	if (chain == 1) {
 		tmpVal = REG_READ(ah, 0xb398);
 		tmpVal = tmpVal & 0xff00ffff;
@@ -436,28 +445,28 @@
 	}
 }
 
-static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
+static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
 						struct ath9k_channel *chan,
 						int16_t *pTxPowerIndexOffset)
 {
-	struct ath_common *common = ath9k_hw_common(ah);
 	struct cal_data_per_freq_ar9287 *pRawDataset;
 	struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
-	u8  *pCalBChans = NULL;
+	u8 *pCalBChans = NULL;
 	u16 pdGainOverlap_t2;
-	u8  pdadcValues[AR9287_NUM_PDADC_VALUES];
+	u8 pdadcValues[AR9287_NUM_PDADC_VALUES];
 	u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK];
 	u16 numPiers = 0, i, j;
-	int16_t  tMinCalPower;
 	u16 numXpdGain, xpdMask;
 	u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0};
-	u32 reg32, regOffset, regChainOffset;
-	int16_t   modalIdx, diff = 0;
+	u32 reg32, regOffset, regChainOffset, regval;
+	int16_t modalIdx, diff = 0;
 	struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
+
 	modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
 	xpdMask = pEepData->modalHeader.xpdGain;
+
 	if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
-			AR9287_EEP_MINOR_VER_2)
+	    AR9287_EEP_MINOR_VER_2)
 		pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
 	else
 		pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
@@ -466,15 +475,16 @@
 	if (IS_CHAN_2GHZ(chan)) {
 		pCalBChans = pEepData->calFreqPier2G;
 		numPiers = AR9287_NUM_2G_CAL_PIERS;
-		if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+		if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
 			pRawDatasetOpenLoop =
-				(struct cal_data_op_loop_ar9287 *)
-				pEepData->calPierData2G[0];
+			(struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0];
 			ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0];
 		}
 	}
 
 	numXpdGain = 0;
+
+	/* Calculate the value of xpdgains from the xpdGain Mask */
 	for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) {
 		if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) {
 			if (numXpdGain >= AR9287_NUM_PD_GAINS)
@@ -496,99 +506,79 @@
 
 	for (i = 0; i < AR9287_MAX_CHAINS; i++)	{
 		regChainOffset = i * 0x1000;
+
 		if (pEepData->baseEepHeader.txMask & (1 << i)) {
-			pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *)
-					       pEepData->calPierData2G[i];
-			if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+			pRawDatasetOpenLoop =
+			(struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i];
+
+			if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
 				int8_t txPower;
 				ar9287_eeprom_get_tx_gain_index(ah, chan,
-							  pRawDatasetOpenLoop,
-							  pCalBChans, numPiers,
-							  &txPower);
+							pRawDatasetOpenLoop,
+							pCalBChans, numPiers,
+							&txPower);
 				ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i);
 			} else {
 				pRawDataset =
 					(struct cal_data_per_freq_ar9287 *)
 					pEepData->calPierData2G[i];
-				ath9k_hw_get_AR9287_gain_boundaries_pdadcs(
-						  ah, chan, pRawDataset,
-						  pCalBChans, numPiers,
-						  pdGainOverlap_t2,
-						  &tMinCalPower, gainBoundaries,
-						  pdadcValues, numXpdGain);
+
+				ath9k_hw_get_ar9287_gain_boundaries_pdadcs(ah, chan,
+							   pRawDataset,
+							   pCalBChans, numPiers,
+							   pdGainOverlap_t2,
+							   gainBoundaries,
+							   pdadcValues,
+							   numXpdGain);
 			}
 
 			if (i == 0) {
-				if (!ath9k_hw_AR9287_get_eeprom(
-					    ah, EEP_OL_PWRCTRL)) {
-					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));
+				if (!ath9k_hw_ar9287_get_eeprom(ah,
+							EEP_OL_PWRCTRL)) {
+
+					regval = 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);
+
+					REG_WRITE(ah,
+						  AR_PHY_TPCRG5 + regChainOffset,
+						  regval);
 				}
 			}
 
 			if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB !=
-				     pEepData->baseEepHeader.pwrTableOffset) {
-				diff = (u16)
-				       (pEepData->baseEepHeader.pwrTableOffset
-					- (int32_t)AR9287_PWR_TABLE_OFFSET_DB);
+			    pEepData->baseEepHeader.pwrTableOffset) {
+				diff = (u16)(pEepData->baseEepHeader.pwrTableOffset -
+					     (int32_t)AR9287_PWR_TABLE_OFFSET_DB);
 				diff *= 2;
 
-				for (j = 0;
-				     j < ((u16)AR9287_NUM_PDADC_VALUES-diff);
-				     j++)
+				for (j = 0; j < ((u16)AR9287_NUM_PDADC_VALUES-diff); j++)
 					pdadcValues[j] = pdadcValues[j+diff];
 
 				for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff);
 				     j < AR9287_NUM_PDADC_VALUES; j++)
 					pdadcValues[j] =
-					  pdadcValues[
-					  AR9287_NUM_PDADC_VALUES-diff];
+					  pdadcValues[AR9287_NUM_PDADC_VALUES-diff];
 			}
 
-			if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
-				regOffset = AR_PHY_BASE + (672 << 2) +
-							   regChainOffset;
+			if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+				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) ;
+					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);
-
-					ath_print(common, ATH_DBG_EEPROM,
-						  "PDADC (%d,%4x): %4.4x "
-						  "%8.8x\n",
-						  i, regChainOffset, regOffset,
-						  reg32);
-
-					ath_print(common, ATH_DBG_EEPROM,
-						  "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;
 				}
 			}
@@ -598,30 +588,45 @@
 	*pTxPowerIndexOffset = 0;
 }
 
-static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
-		struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl,
-		u16 AntennaReduction, u16 twiceMaxRegulatoryPower,
-		u16 powerLimit)
+static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
+						     struct ath9k_channel *chan,
+						     int16_t *ratesArray,
+						     u16 cfgCtl,
+						     u16 AntennaReduction,
+						     u16 twiceMaxRegulatoryPower,
+						     u16 powerLimit)
 {
+#define CMP_CTL \
+	(((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
+	 pEepData->ctlIndex[i])
+
+#define CMP_NO_CTL \
+	(((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
+	 ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
+
 #define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6
 #define REDUCE_SCALED_POWER_BY_THREE_CHAIN   10
+
 	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
 	static const u16 tpScaleReductionTable[5] =
 		{ 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
 	int i;
-	int16_t  twiceLargestAntenna;
+	int16_t twiceLargestAntenna;
 	struct cal_ctl_data_ar9287 *rep;
 	struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
 				    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,
+	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 ctlModesFor11g[] = {CTL_11B,
+				CTL_11G,
+				CTL_2GHT20,
+				CTL_11B_EXT,
+				CTL_11G_EXT,
+				CTL_2GHT40};
 	u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq;
 	struct chan_centers centers;
 	int tx_chainmask;
@@ -631,19 +636,28 @@
 
 	ath9k_hw_get_channel_centers(ah, chan, &centers);
 
+	/* Compute TxPower reduction due to Antenna Gain */
 	twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0],
 				  pEepData->modalHeader.antennaGainCh[1]);
+	twiceLargestAntenna = (int16_t)min((AntennaReduction) -
+					   twiceLargestAntenna, 0);
 
-	twiceLargestAntenna =  (int16_t)min((AntennaReduction) -
-					    twiceLargestAntenna, 0);
-
+	/*
+	 * scaledPower is the minimum of the user input power level
+	 * and the regulatory allowed power level.
+	 */
 	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
 	if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX)
 		maxRegAllowedPower -=
 			(tpScaleReductionTable[(regulatory->tp_scale)] * 2);
 
 	scaledPower = min(powerLimit, maxRegAllowedPower);
 
+	/*
+	 * Reduce scaled Power by number of chains active
+	 * to get the per chain tx power level.
+	 */
 	switch (ar5416_get_ntxchains(tx_chainmask)) {
 	case 1:
 		break;
@@ -656,9 +670,14 @@
 	}
 	scaledPower = max((u16)0, scaledPower);
 
+	/*
+	 * Get TX power from EEPROM.
+	 */
 	if (IS_CHAN_2GHZ(chan))	{
+		/* CTL_11B, CTL_11G, CTL_2GHT20 */
 		numCtlModes =
 			ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
+
 		pCtlMode = ctlModesFor11g;
 
 		ath9k_hw_get_legacy_target_powers(ah, chan,
@@ -675,6 +694,7 @@
 					   &targetPowerHt20, 8, false);
 
 		if (IS_CHAN_HT40(chan))	{
+			/* All 2G CTLs */
 			numCtlModes = ARRAY_SIZE(ctlModesFor11g);
 			ath9k_hw_get_target_powers(ah, chan,
 						   pEepData->calTargetPower2GHT40,
@@ -692,8 +712,9 @@
 	}
 
 	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
-		bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
-				     (pCtlMode[ctlMode] == CTL_2GHT40);
+		bool isHt40CtlMode =
+			(pCtlMode[ctlMode] == CTL_2GHT40) ? true : false;
+
 		if (isHt40CtlMode)
 			freq = centers.synth_center;
 		else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
@@ -701,31 +722,28 @@
 		else
 			freq = centers.ctl_center;
 
-		if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
-		    ah->eep_ops->get_eeprom_rev(ah) <= 2)
-			twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-
+		/* Walk through the CTL indices stored in EEPROM */
 		for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
-			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))) {
+			struct cal_ctl_edges *pRdEdgesPower;
 
+			/*
+			 * Compare test group from regulatory channel list
+			 * with test mode from pCtlMode list
+			 */
+			if (CMP_CTL || CMP_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);
+				pRdEdgesPower =
+				rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1];
 
-				if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
-					twiceMaxEdgePower = min(
-							    twiceMaxEdgePower,
-							    twiceMinEdgePower);
-				else {
+				twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
+								pRdEdgesPower,
+								IS_CHAN_2GHZ(chan),
+								AR5416_NUM_BAND_EDGES);
+
+				if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+					twiceMaxEdgePower = min(twiceMaxEdgePower,
+								twiceMinEdgePower);
+				} else {
 					twiceMaxEdgePower = twiceMinEdgePower;
 					break;
 				}
@@ -734,55 +752,48 @@
 
 		minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
 
+		/* Apply ctl mode to correct target power set */
 		switch (pCtlMode[ctlMode]) {
 		case CTL_11B:
-			for (i = 0;
-			     i < ARRAY_SIZE(targetPowerCck.tPow2x);
-			     i++) {
-				targetPowerCck.tPow2x[i] = (u8)min(
-					(u16)targetPowerCck.tPow2x[i],
-					minCtlPower);
+			for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
+				targetPowerCck.tPow2x[i] =
+					(u8)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] = (u8)min(
-					(u16)targetPowerOfdm.tPow2x[i],
-					minCtlPower);
+			for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
+				targetPowerOfdm.tPow2x[i] =
+					(u8)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] = (u8)min(
-					(u16)targetPowerHt20.tPow2x[i],
-					minCtlPower);
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
+				targetPowerHt20.tPow2x[i] =
+					(u8)min((u16)targetPowerHt20.tPow2x[i],
+						minCtlPower);
 			}
 			break;
 		case CTL_11B_EXT:
-			targetPowerCckExt.tPow2x[0] = (u8)min(
-				    (u16)targetPowerCckExt.tPow2x[0],
-				    minCtlPower);
+			targetPowerCckExt.tPow2x[0] =
+				(u8)min((u16)targetPowerCckExt.tPow2x[0],
+					minCtlPower);
 			break;
 		case CTL_11A_EXT:
 		case CTL_11G_EXT:
-			targetPowerOfdmExt.tPow2x[0] = (u8)min(
-				    (u16)targetPowerOfdmExt.tPow2x[0],
-				    minCtlPower);
+			targetPowerOfdmExt.tPow2x[0] =
+				(u8)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] = (u8)min(
-					(u16)targetPowerHt40.tPow2x[i],
-					minCtlPower);
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+				targetPowerHt40.tPow2x[i] =
+					(u8)min((u16)targetPowerHt40.tPow2x[i],
+						minCtlPower);
 			}
 			break;
 		default:
@@ -790,12 +801,13 @@
 		}
 	}
 
+	/* Now set the rates array */
+
 	ratesArray[rate6mb] =
 	ratesArray[rate9mb] =
 	ratesArray[rate12mb] =
 	ratesArray[rate18mb] =
-	ratesArray[rate24mb] =
-	targetPowerOfdm.tPow2x[0];
+	ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0];
 
 	ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
 	ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
@@ -807,12 +819,12 @@
 
 	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];
+		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++)
@@ -821,28 +833,28 @@
 		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];
 	}
 
+#undef CMP_CTL
+#undef CMP_NO_CTL
 #undef REDUCE_SCALED_POWER_BY_TWO_CHAIN
 #undef REDUCE_SCALED_POWER_BY_THREE_CHAIN
 }
 
-static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
+static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
 					struct ath9k_channel *chan, u16 cfgCtl,
 					u8 twiceAntennaReduction,
 					u8 twiceMaxRegulatoryPower,
 					u8 powerLimit)
 {
-#define INCREASE_MAXPOW_BY_TWO_CHAIN     6
-#define INCREASE_MAXPOW_BY_THREE_CHAIN   10
-	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
 	struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
 	int16_t ratesArray[Ar5416RateSize];
-	int16_t  txPowerIndexOffset = 0;
+	int16_t txPowerIndexOffset = 0;
 	u8 ht40PowerIncForPdadc = 2;
 	int i;
 
@@ -852,13 +864,13 @@
 	    AR9287_EEP_MINOR_VER_2)
 		ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
 
-	ath9k_hw_set_AR9287_power_per_rate_table(ah, chan,
+	ath9k_hw_set_ar9287_power_per_rate_table(ah, chan,
 						 &ratesArray[0], cfgCtl,
 						 twiceAntennaReduction,
 						 twiceMaxRegulatoryPower,
 						 powerLimit);
 
-	ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset);
+	ath9k_hw_set_ar9287_power_cal_table(ah, chan, &txPowerIndexOffset);
 
 	for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
 		ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
@@ -871,6 +883,7 @@
 			ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
 	}
 
+	/* OFDM power per rate */
 	REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
 		  ATH9K_POW_SM(ratesArray[rate18mb], 24)
 		  | ATH9K_POW_SM(ratesArray[rate12mb], 16)
@@ -883,6 +896,7 @@
 		  | ATH9K_POW_SM(ratesArray[rate36mb], 8)
 		  | ATH9K_POW_SM(ratesArray[rate24mb], 0));
 
+	/* CCK power per rate */
 	if (IS_CHAN_2GHZ(chan))	{
 		REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
 			  ATH9K_POW_SM(ratesArray[rate2s], 24)
@@ -896,6 +910,7 @@
 			  | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
 	}
 
+	/* HT20 power per rate */
 	REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
 		  ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
 		  | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
@@ -908,8 +923,9 @@
 		  | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
 		  | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
 
+	/* HT40 power per rate */
 	if (IS_CHAN_HT40(chan))	{
-		if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+		if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
 			REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
 				  ATH9K_POW_SM(ratesArray[rateHt40_3], 24)
 				  | ATH9K_POW_SM(ratesArray[rateHt40_2], 16)
@@ -943,6 +959,7 @@
 						 ht40PowerIncForPdadc, 0));
 		}
 
+		/* Dup/Ext power per rate */
 		REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
 			  ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
 			  | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
@@ -960,37 +977,20 @@
 			ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2;
 	else
 		regulatory->max_power_level = ratesArray[i];
-
-	switch (ar5416_get_ntxchains(ah->txchainmask)) {
-	case 1:
-		break;
-	case 2:
-		regulatory->max_power_level +=
-			INCREASE_MAXPOW_BY_TWO_CHAIN;
-		break;
-	case 3:
-		regulatory->max_power_level +=
-			INCREASE_MAXPOW_BY_THREE_CHAIN;
-		break;
-	default:
-		ath_print(common, ATH_DBG_EEPROM,
-			  "Invalid chainmask configuration\n");
-		break;
-	}
 }
 
-static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah,
+static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah,
 				      struct ath9k_channel *chan)
 {
 }
 
-static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah,
+static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
 					     struct ath9k_channel *chan)
 {
 	struct ar9287_eeprom *eep = &ah->eeprom.map9287;
 	struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
 	u16 antWrites[AR9287_ANT_16S];
-	u32 regChainOffset;
+	u32 regChainOffset, regval;
 	u8 txRxAttenLocal;
 	int i, j, offset_num;
 
@@ -1077,42 +1077,37 @@
 	REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
 		      AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62);
 
-	ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1,
-				  AR9287_AN_RF2G3_DB1_S, pModal->db1);
-	ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2,
-				  AR9287_AN_RF2G3_DB2_S, pModal->db2);
-	ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
-				  AR9287_AN_RF2G3_OB_CCK,
-				  AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck);
-	ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
-				  AR9287_AN_RF2G3_OB_PSK,
-				  AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk);
-	ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
-				  AR9287_AN_RF2G3_OB_QAM,
-				  AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam);
-	ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
-				  AR9287_AN_RF2G3_OB_PAL_OFF,
-				  AR9287_AN_RF2G3_OB_PAL_OFF_S,
-				  pModal->ob_pal_off);
+	regval = REG_READ(ah, AR9287_AN_RF2G3_CH0);
+	regval &= ~(AR9287_AN_RF2G3_DB1 |
+		    AR9287_AN_RF2G3_DB2 |
+		    AR9287_AN_RF2G3_OB_CCK |
+		    AR9287_AN_RF2G3_OB_PSK |
+		    AR9287_AN_RF2G3_OB_QAM |
+		    AR9287_AN_RF2G3_OB_PAL_OFF);
+	regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
+		   SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
+		   SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
+		   SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
+		   SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
+		   SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
 
-	ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
-				  AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S,
-				  pModal->db1);
-	ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2,
-				  AR9287_AN_RF2G3_DB2_S, pModal->db2);
-	ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
-				  AR9287_AN_RF2G3_OB_CCK,
-				  AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck);
-	ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
-				  AR9287_AN_RF2G3_OB_PSK,
-				  AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk);
-	ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
-				  AR9287_AN_RF2G3_OB_QAM,
-				  AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam);
-	ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
-				  AR9287_AN_RF2G3_OB_PAL_OFF,
-				  AR9287_AN_RF2G3_OB_PAL_OFF_S,
-				  pModal->ob_pal_off);
+	ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH0, regval);
+
+	regval = REG_READ(ah, AR9287_AN_RF2G3_CH1);
+	regval &= ~(AR9287_AN_RF2G3_DB1 |
+		    AR9287_AN_RF2G3_DB2 |
+		    AR9287_AN_RF2G3_OB_CCK |
+		    AR9287_AN_RF2G3_OB_PSK |
+		    AR9287_AN_RF2G3_OB_QAM |
+		    AR9287_AN_RF2G3_OB_PAL_OFF);
+	regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
+		   SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
+		   SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
+		   SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
+		   SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
+		   SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
+
+	ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH1, regval);
 
 	REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
 		      AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart);
@@ -1125,26 +1120,27 @@
 				  pModal->xpaBiasLvl);
 }
 
-static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah,
+static u8 ath9k_hw_ar9287_get_num_ant_config(struct ath_hw *ah,
 					     enum ieee80211_band freq_band)
 {
 	return 1;
 }
 
-static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
+static u32 ath9k_hw_ar9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
 						  struct ath9k_channel *chan)
 {
 	struct ar9287_eeprom *eep = &ah->eeprom.map9287;
 	struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
 
-	return pModal->antCtrlCommon & 0xFFFF;
+	return pModal->antCtrlCommon;
 }
 
-static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah,
+static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
 					    u16 i, bool is2GHz)
 {
 #define EEP_MAP9287_SPURCHAN \
 	(ah->eeprom.map9287.modalHeader.spurChans[i].spurChan)
+
 	struct ath_common *common = ath9k_hw_common(ah);
 	u16 spur_val = AR_NO_SPUR;
 
@@ -1171,15 +1167,15 @@
 }
 
 const struct eeprom_ops eep_ar9287_ops = {
-	.check_eeprom		= ath9k_hw_AR9287_check_eeprom,
-	.get_eeprom		= ath9k_hw_AR9287_get_eeprom,
-	.fill_eeprom		= ath9k_hw_AR9287_fill_eeprom,
-	.get_eeprom_ver		= ath9k_hw_AR9287_get_eeprom_ver,
-	.get_eeprom_rev		= ath9k_hw_AR9287_get_eeprom_rev,
-	.get_num_ant_config	= ath9k_hw_AR9287_get_num_ant_config,
-	.get_eeprom_antenna_cfg	= ath9k_hw_AR9287_get_eeprom_antenna_cfg,
-	.set_board_values	= ath9k_hw_AR9287_set_board_values,
-	.set_addac		= ath9k_hw_AR9287_set_addac,
-	.set_txpower		= ath9k_hw_AR9287_set_txpower,
-	.get_spur_channel	= ath9k_hw_AR9287_get_spur_channel
+	.check_eeprom		= ath9k_hw_ar9287_check_eeprom,
+	.get_eeprom		= ath9k_hw_ar9287_get_eeprom,
+	.fill_eeprom		= ath9k_hw_ar9287_fill_eeprom,
+	.get_eeprom_ver		= ath9k_hw_ar9287_get_eeprom_ver,
+	.get_eeprom_rev		= ath9k_hw_ar9287_get_eeprom_rev,
+	.get_num_ant_config	= ath9k_hw_ar9287_get_num_ant_config,
+	.get_eeprom_antenna_cfg	= ath9k_hw_ar9287_get_eeprom_antenna_cfg,
+	.set_board_values	= ath9k_hw_ar9287_set_board_values,
+	.set_addac		= ath9k_hw_ar9287_set_addac,
+	.set_txpower		= ath9k_hw_ar9287_set_txpower,
+	.get_spur_channel	= ath9k_hw_ar9287_get_spur_channel
 };
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 7e1ed78..afa2b73 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -593,7 +593,7 @@
 				struct ath9k_channel *chan,
 				struct cal_data_per_freq *pRawDataSet,
 				u8 *bChans, u16 availPiers,
-				u16 tPdGainOverlap, int16_t *pMinCalPower,
+				u16 tPdGainOverlap,
 				u16 *pPdGainBoundaries, u8 *pPDADCValues,
 				u16 numXpdGains)
 {
@@ -617,6 +617,7 @@
 	int16_t minDelta = 0;
 	struct chan_centers centers;
 
+	memset(&minPwrT4, 0, AR9287_NUM_PD_GAINS);
 	ath9k_hw_get_channel_centers(ah, chan, &centers);
 
 	for (numPiers = 0; numPiers < availPiers; numPiers++) {
@@ -674,8 +675,6 @@
 		}
 	}
 
-	*pMinCalPower = (int16_t)(minPwrT4[0] / 2);
-
 	k = 0;
 
 	for (i = 0; i < numXpdGains; i++) {
@@ -729,7 +728,7 @@
 				    vpdTableI[i][sizeCurrVpdTable - 2]);
 		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
 
-		if (tgtIndex > maxIndex) {
+		if (tgtIndex >= maxIndex) {
 			while ((ss <= tgtIndex) &&
 			       (k < (AR5416_NUM_PDADC_VALUES - 1))) {
 				tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
@@ -837,7 +836,7 @@
 	static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
 	u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
 	u16 numPiers, i, j;
-	int16_t tMinCalPower, diff = 0;
+	int16_t diff = 0;
 	u16 numXpdGain, xpdMask;
 	u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
 	u32 reg32, regOffset, regChainOffset;
@@ -922,7 +921,6 @@
 							chan, pRawDataset,
 							pCalBChans, numPiers,
 							pdGainOverlap_t2,
-							&tMinCalPower,
 							gainBoundaries,
 							pdadcValues,
 							numXpdGain);
@@ -1437,14 +1435,14 @@
 	return num_ant_config;
 }
 
-static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah,
+static u32 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah,
 					       struct ath9k_channel *chan)
 {
 	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
 	struct modal_eep_header *pModal =
 		&(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
 
-	return pModal->antCtrlCommon & 0xFFFF;
+	return pModal->antCtrlCommon;
 }
 
 static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index 0ee75e7..3a8ee99 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -76,7 +76,8 @@
 	case LED_FULL:
 		if (led->led_type == ATH_LED_ASSOC) {
 			sc->sc_flags |= SC_OP_LED_ASSOCIATED;
-			ieee80211_queue_delayed_work(sc->hw,
+			if (led_blink)
+				ieee80211_queue_delayed_work(sc->hw,
 						     &sc->ath_led_blink_work, 0);
 		} else if (led->led_type == ATH_LED_RADIO) {
 			ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
@@ -143,7 +144,8 @@
 	/* LED off, active low */
 	ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
 
-	INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
+	if (led_blink)
+		INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
 
 	trigger = ieee80211_get_radio_led_name(sc->hw);
 	snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
@@ -180,7 +182,8 @@
 	return;
 
 fail:
-	cancel_delayed_work_sync(&sc->ath_led_blink_work);
+	if (led_blink)
+		cancel_delayed_work_sync(&sc->ath_led_blink_work);
 	ath_deinit_leds(sc);
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 23c15aa..61c1bee 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -16,12 +16,27 @@
 
 #include "htc.h"
 
-#define ATH9K_FW_USB_DEV(devid, fw)					\
-	{ USB_DEVICE(0x0cf3, devid), .driver_info = (unsigned long) fw }
+/* identify firmware images */
+#define FIRMWARE_AR7010		"ar7010.fw"
+#define FIRMWARE_AR7010_1_1	"ar7010_1_1.fw"
+#define FIRMWARE_AR9271		"ar9271.fw"
+
+MODULE_FIRMWARE(FIRMWARE_AR7010);
+MODULE_FIRMWARE(FIRMWARE_AR7010_1_1);
+MODULE_FIRMWARE(FIRMWARE_AR9271);
 
 static struct usb_device_id ath9k_hif_usb_ids[] = {
-	ATH9K_FW_USB_DEV(0x9271, "ar9271.fw"),
-	ATH9K_FW_USB_DEV(0x1006, "ar9271.fw"),
+	{ USB_DEVICE(0x0cf3, 0x9271) }, /* Atheros */
+	{ USB_DEVICE(0x0cf3, 0x1006) }, /* Atheros */
+	{ USB_DEVICE(0x0cf3, 0x7010) }, /* Atheros */
+	{ USB_DEVICE(0x0cf3, 0x7015) }, /* Atheros */
+	{ USB_DEVICE(0x0846, 0x9030) }, /* Netgear N150 */
+	{ USB_DEVICE(0x0846, 0x9018) }, /* Netgear WNDA3200 */
+	{ USB_DEVICE(0x07D1, 0x3A10) }, /* Dlink Wireless 150 */
+	{ USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */
+	{ USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */
+	{ USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */
+	{ USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */
 	{ },
 };
 
@@ -760,6 +775,7 @@
 	size_t len = hif_dev->firmware->size;
 	u32 addr = AR9271_FIRMWARE;
 	u8 *buf = kzalloc(4096, GFP_KERNEL);
+	u32 firm_offset;
 
 	if (!buf)
 		return -ENOMEM;
@@ -783,32 +799,37 @@
 	}
 	kfree(buf);
 
+	if (hif_dev->device_id == 0x7010)
+		firm_offset = AR7010_FIRMWARE_TEXT;
+	else
+		firm_offset = AR9271_FIRMWARE_TEXT;
+
 	/*
 	 * Issue FW download complete command to firmware.
 	 */
 	err = usb_control_msg(hif_dev->udev, usb_sndctrlpipe(hif_dev->udev, 0),
 			      FIRMWARE_DOWNLOAD_COMP,
 			      0x40 | USB_DIR_OUT,
-			      AR9271_FIRMWARE_TEXT >> 8, 0, NULL, 0, HZ);
+			      firm_offset >> 8, 0, NULL, 0, HZ);
 	if (err)
 		return -EIO;
 
 	dev_info(&hif_dev->udev->dev, "ath9k_htc: Transferred FW: %s, size: %ld\n",
-		 "ar9271.fw", (unsigned long) hif_dev->firmware->size);
+		 hif_dev->fw_name, (unsigned long) hif_dev->firmware->size);
 
 	return 0;
 }
 
-static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev,
-				  const char *fw_name)
+static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
 {
 	int ret;
 
 	/* Request firmware */
-	ret = request_firmware(&hif_dev->firmware, fw_name, &hif_dev->udev->dev);
+	ret = request_firmware(&hif_dev->firmware, hif_dev->fw_name,
+			       &hif_dev->udev->dev);
 	if (ret) {
 		dev_err(&hif_dev->udev->dev,
-			"ath9k_htc: Firmware - %s not found\n", fw_name);
+			"ath9k_htc: Firmware - %s not found\n", hif_dev->fw_name);
 		goto err_fw_req;
 	}
 
@@ -824,7 +845,8 @@
 	ret = ath9k_hif_usb_download_fw(hif_dev);
 	if (ret) {
 		dev_err(&hif_dev->udev->dev,
-			"ath9k_htc: Firmware - %s download failed\n", fw_name);
+			"ath9k_htc: Firmware - %s download failed\n",
+			hif_dev->fw_name);
 		goto err_fw_download;
 	}
 
@@ -851,7 +873,6 @@
 {
 	struct usb_device *udev = interface_to_usbdev(interface);
 	struct hif_device_usb *hif_dev;
-	const char *fw_name = (const char *) id->driver_info;
 	int ret = 0;
 
 	hif_dev = kzalloc(sizeof(struct hif_device_usb), GFP_KERNEL);
@@ -876,7 +897,27 @@
 		goto err_htc_hw_alloc;
 	}
 
-	ret = ath9k_hif_usb_dev_init(hif_dev, fw_name);
+	/* Find out which firmware to load */
+
+	switch(hif_dev->device_id) {
+	case 0x7010:
+	case 0x9018:
+		if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202)
+			hif_dev->fw_name = FIRMWARE_AR7010_1_1;
+		else
+			hif_dev->fw_name = FIRMWARE_AR7010;
+		break;
+	default:
+		hif_dev->fw_name = FIRMWARE_AR9271;
+		break;
+	}
+
+	if (!hif_dev->fw_name) {
+		dev_err(&udev->dev, "Can't determine firmware !\n");
+		goto err_htc_hw_alloc;
+	}
+
+	ret = ath9k_hif_usb_dev_init(hif_dev);
 	if (ret) {
 		ret = -EINVAL;
 		goto err_hif_init_usb;
@@ -911,12 +952,10 @@
 	void *buf;
 	int ret;
 
-	buf = kmalloc(4, GFP_KERNEL);
+	buf = kmemdup(&reboot_cmd, 4, GFP_KERNEL);
 	if (!buf)
 		return;
 
-	memcpy(buf, &reboot_cmd, 4);
-
 	ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, USB_REG_OUT_PIPE),
 			   buf, 4, NULL, HZ);
 	if (ret)
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index 0aca49b6..2daf97b 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -19,6 +19,7 @@
 
 #define AR9271_FIRMWARE       0x501000
 #define AR9271_FIRMWARE_TEXT  0x903000
+#define AR7010_FIRMWARE_TEXT  0x906000
 
 #define FIRMWARE_DOWNLOAD       0x30
 #define FIRMWARE_DOWNLOAD_COMP  0x31
@@ -90,6 +91,7 @@
 	struct usb_anchor regout_submitted;
 	struct usb_anchor rx_submitted;
 	struct sk_buff *remain_skb;
+	const char *fw_name;
 	int rx_remain_len;
 	int rx_pkt_len;
 	int rx_transfer_len;
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index c251603..3756400 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -223,15 +223,6 @@
 	enum tid_aggr_state tid_state[ATH9K_HTC_MAX_TID];
 };
 
-struct ath9k_htc_aggr_work {
-	u16 tid;
-	u8 sta_addr[ETH_ALEN];
-	struct ieee80211_hw *hw;
-	struct ieee80211_vif *vif;
-	enum ieee80211_ampdu_mlme_action action;
-	struct mutex mutex;
-};
-
 #define ATH9K_HTC_RXBUF 256
 #define HTC_RX_FRAME_HEADER_SIZE 40
 
@@ -257,12 +248,15 @@
 #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++)
 #define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++)
 
+#define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++)
+
 struct ath_tx_stats {
 	u32 buf_queued;
 	u32 buf_completed;
 	u32 skb_queued;
 	u32 skb_completed;
 	u32 skb_dropped;
+	u32 queue_stats[WME_NUM_AC];
 };
 
 struct ath_rx_stats {
@@ -286,11 +280,14 @@
 #define TX_STAT_INC(c) do { } while (0)
 #define RX_STAT_INC(c) do { } while (0)
 
+#define TX_QSTAT_INC(c) do { } while (0)
+
 #endif /* CONFIG_ATH9K_HTC_DEBUGFS */
 
 #define ATH_LED_PIN_DEF             1
 #define ATH_LED_PIN_9287            8
 #define ATH_LED_PIN_9271            15
+#define ATH_LED_PIN_7010            12
 #define ATH_LED_ON_DURATION_IDLE    350	/* in msecs */
 #define ATH_LED_OFF_DURATION_IDLE   250	/* in msecs */
 
@@ -326,11 +323,10 @@
 #define OP_LED_ON         BIT(4)
 #define OP_PREAMBLE_SHORT BIT(5)
 #define OP_PROTECT_ENABLE BIT(6)
-#define OP_TXAGGR         BIT(7)
-#define OP_ASSOCIATED     BIT(8)
-#define OP_ENABLE_BEACON  BIT(9)
-#define OP_LED_DEINIT     BIT(10)
-#define OP_UNPLUGGED      BIT(11)
+#define OP_ASSOCIATED     BIT(7)
+#define OP_ENABLE_BEACON  BIT(8)
+#define OP_LED_DEINIT     BIT(9)
+#define OP_UNPLUGGED      BIT(10)
 
 struct ath9k_htc_priv {
 	struct device *dev;
@@ -371,8 +367,6 @@
 	struct ath9k_htc_rx rx;
 	struct tasklet_struct tx_tasklet;
 	struct sk_buff_head tx_queue;
-	struct ath9k_htc_aggr_work aggr_work;
-	struct delayed_work ath9k_aggr_work;
 	struct delayed_work ath9k_ani_work;
 	struct work_struct ps_work;
 
@@ -390,13 +384,14 @@
 	int led_off_duration;
 	int led_on_cnt;
 	int led_off_cnt;
-	int hwq_map[ATH9K_WME_AC_VO+1];
+
+	int beaconq;
+	int cabq;
+	int hwq_map[WME_NUM_AC];
 
 #ifdef CONFIG_ATH9K_HTC_DEBUGFS
 	struct ath9k_debug debug;
 #endif
-	struct ath9k_htc_target_rate tgt_rate;
-
 	struct mutex mutex;
 };
 
@@ -405,6 +400,7 @@
 	common->bus_ops->read_cachesize(common, csz);
 }
 
+void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv);
 void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
 			     struct ieee80211_vif *vif);
 void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending);
@@ -424,8 +420,8 @@
 void ath9k_tx_tasklet(unsigned long data);
 int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb);
 void ath9k_tx_cleanup(struct ath9k_htc_priv *priv);
-bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv,
-			 enum ath9k_tx_queue_subtype qtype);
+bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype);
+int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv);
 int get_hw_qnum(u16 queue, int *hwq_map);
 int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
 		       struct ath9k_tx_queue_info *qinfo);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index c10c7d0..bd1506e 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -222,6 +222,29 @@
 	spin_unlock_bh(&priv->beacon_lock);
 }
 
+/* Currently, only for IBSS */
+void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
+{
+	struct ath_hw *ah = priv->ah;
+	struct ath9k_tx_queue_info qi, qi_be;
+	int qnum = priv->hwq_map[WME_AC_BE];
+
+	memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
+	memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info));
+
+	ath9k_hw_get_txq_props(ah, qnum, &qi_be);
+
+	qi.tqi_aifs = qi_be.tqi_aifs;
+	qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
+	qi.tqi_cwmax = qi_be.tqi_cwmax;
+
+	if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) {
+		ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+			  "Unable to update beacon queue %u!\n", qnum);
+	} else {
+		ath9k_hw_resettxqueue(ah, priv->beaconq);
+	}
+}
 
 void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
 			     struct ieee80211_vif *vif)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index dc01507..148b433 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -34,6 +34,13 @@
 	.max_power = 20, \
 }
 
+#define CHAN5G(_freq, _idx) { \
+	.band = IEEE80211_BAND_5GHZ, \
+	.center_freq = (_freq), \
+	.hw_value = (_idx), \
+	.max_power = 20, \
+}
+
 static struct ieee80211_channel ath9k_2ghz_channels[] = {
 	CHAN2G(2412, 0), /* Channel 1 */
 	CHAN2G(2417, 1), /* Channel 2 */
@@ -51,6 +58,37 @@
 	CHAN2G(2484, 13), /* Channel 14 */
 };
 
+static struct ieee80211_channel ath9k_5ghz_channels[] = {
+	/* _We_ call this UNII 1 */
+	CHAN5G(5180, 14), /* Channel 36 */
+	CHAN5G(5200, 15), /* Channel 40 */
+	CHAN5G(5220, 16), /* Channel 44 */
+	CHAN5G(5240, 17), /* Channel 48 */
+	/* _We_ call this UNII 2 */
+	CHAN5G(5260, 18), /* Channel 52 */
+	CHAN5G(5280, 19), /* Channel 56 */
+	CHAN5G(5300, 20), /* Channel 60 */
+	CHAN5G(5320, 21), /* Channel 64 */
+	/* _We_ call this "Middle band" */
+	CHAN5G(5500, 22), /* Channel 100 */
+	CHAN5G(5520, 23), /* Channel 104 */
+	CHAN5G(5540, 24), /* Channel 108 */
+	CHAN5G(5560, 25), /* Channel 112 */
+	CHAN5G(5580, 26), /* Channel 116 */
+	CHAN5G(5600, 27), /* Channel 120 */
+	CHAN5G(5620, 28), /* Channel 124 */
+	CHAN5G(5640, 29), /* Channel 128 */
+	CHAN5G(5660, 30), /* Channel 132 */
+	CHAN5G(5680, 31), /* Channel 136 */
+	CHAN5G(5700, 32), /* Channel 140 */
+	/* _We_ call this UNII 3 */
+	CHAN5G(5745, 33), /* Channel 149 */
+	CHAN5G(5765, 34), /* Channel 153 */
+	CHAN5G(5785, 35), /* Channel 157 */
+	CHAN5G(5805, 36), /* Channel 161 */
+	CHAN5G(5825, 37), /* Channel 165 */
+};
+
 /* Atheros hardware rate code addition for short premble */
 #define SHPCHECK(__hw_rate, __flags) \
 	((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0)
@@ -141,7 +179,7 @@
 	return htc_connect_service(priv->htc, &req, ep_id);
 }
 
-static int ath9k_init_htc_services(struct ath9k_htc_priv *priv)
+static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid)
 {
 	int ret;
 
@@ -199,10 +237,28 @@
 	if (ret)
 		goto err;
 
+	/*
+	 * Setup required credits before initializing HTC.
+	 * This is a bit hacky, but, since queuing is done in
+	 * the HIF layer, shouldn't matter much.
+	 */
+
+	switch(devid) {
+	case 0x7010:
+	case 0x9018:
+		priv->htc->credits = 45;
+		break;
+	default:
+		priv->htc->credits = 33;
+	}
+
 	ret = htc_init(priv->htc);
 	if (ret)
 		goto err;
 
+	dev_info(priv->dev, "ath9k_htc: HTC initialized with %d credits\n",
+		 priv->htc->credits);
+
 	return 0;
 
 err:
@@ -398,17 +454,43 @@
 static void setup_ht_cap(struct ath9k_htc_priv *priv,
 			 struct ieee80211_sta_ht_cap *ht_info)
 {
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	u8 tx_streams, rx_streams;
+	int i;
+
 	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;
 
+	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+		ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+
+	ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+
 	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
 	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
 
 	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
-	ht_info->mcs.rx_mask[0] = 0xff;
+
+	/* ath9k_htc supports only 1 or 2 stream devices */
+	tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, 2);
+	rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, 2);
+
+	ath_print(common, ATH_DBG_CONFIG,
+		  "TX streams %d, RX streams: %d\n",
+		  tx_streams, rx_streams);
+
+	if (tx_streams != rx_streams) {
+		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+		ht_info->mcs.tx_params |= ((tx_streams - 1) <<
+					   IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
+	}
+
+	for (i = 0; i < rx_streams; i++)
+		ht_info->mcs.rx_mask[i] = 0xff;
+
 	ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
 }
 
@@ -420,23 +502,37 @@
 	for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++)
 		priv->hwq_map[i] = -1;
 
-	if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_BE)) {
+	priv->beaconq = ath9k_hw_beaconq_setup(priv->ah);
+	if (priv->beaconq == -1) {
+		ath_print(common, ATH_DBG_FATAL,
+			  "Unable to setup BEACON xmit queue\n");
+		goto err;
+	}
+
+	priv->cabq = ath9k_htc_cabq_setup(priv);
+	if (priv->cabq == -1) {
+		ath_print(common, ATH_DBG_FATAL,
+			  "Unable to setup CAB xmit queue\n");
+		goto err;
+	}
+
+	if (!ath9k_htc_txq_setup(priv, WME_AC_BE)) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to setup xmit queue for BE traffic\n");
 		goto err;
 	}
 
-	if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_BK)) {
+	if (!ath9k_htc_txq_setup(priv, WME_AC_BK)) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to setup xmit queue for BK traffic\n");
 		goto err;
 	}
-	if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_VI)) {
+	if (!ath9k_htc_txq_setup(priv, WME_AC_VI)) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to setup xmit queue for VI traffic\n");
 		goto err;
 	}
-	if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_VO)) {
+	if (!ath9k_htc_txq_setup(priv, WME_AC_VO)) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to setup xmit queue for VO traffic\n");
 		goto err;
@@ -468,36 +564,6 @@
 	 */
 	for (i = 0; i < common->keymax; i++)
 		ath9k_hw_keyreset(priv->ah, (u16) i);
-
-	if (ath9k_hw_getcapability(priv->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(priv->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(priv->ah, ATH9K_CAP_CIPHER,
-				   ATH9K_CIPHER_TKIP, NULL)
-	    && ath9k_hw_getcapability(priv->ah, ATH9K_CAP_CIPHER,
-				      ATH9K_CIPHER_MIC, NULL)
-	    && ath9k_hw_getcapability(priv->ah, ATH9K_CAP_TKIP_SPLIT,
-				      0, NULL))
-		common->splitmic = 1;
-
-	/* turn on mcast key search if possible */
-	if (!ath9k_hw_getcapability(priv->ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
-		(void)ath9k_hw_setcapability(priv->ah, ATH9K_CAP_MCAST_KEYSRCH,
-					     1, 1, NULL);
 }
 
 static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
@@ -512,6 +578,17 @@
 		priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
 			ARRAY_SIZE(ath9k_legacy_rates);
 	}
+
+	if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes)) {
+		priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels;
+		priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
+		priv->sbands[IEEE80211_BAND_5GHZ].n_channels =
+			ARRAY_SIZE(ath9k_5ghz_channels);
+		priv->sbands[IEEE80211_BAND_5GHZ].bitrates =
+			ath9k_legacy_rates + 4;
+		priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
+			ARRAY_SIZE(ath9k_legacy_rates) - 4;
+	}
 }
 
 static void ath9k_init_misc(struct ath9k_htc_priv *priv)
@@ -524,7 +601,6 @@
 	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
 		memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
 
-	priv->op_flags |= OP_TXAGGR;
 	priv->ah->opmode = NL80211_IFTYPE_STATION;
 }
 
@@ -556,14 +632,12 @@
 	spin_lock_init(&priv->beacon_lock);
 	spin_lock_init(&priv->tx_lock);
 	mutex_init(&priv->mutex);
-	mutex_init(&priv->aggr_work.mutex);
 	mutex_init(&priv->htc_pm_lock);
 	tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet,
 		     (unsigned long)priv);
 	tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
 		     (unsigned long)priv);
 	tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv);
-	INIT_DELAYED_WORK(&priv->ath9k_aggr_work, ath9k_htc_aggr_work);
 	INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work);
 	INIT_WORK(&priv->ps_work, ath9k_ps_work);
 
@@ -643,11 +717,17 @@
 	if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes))
 		hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
 			&priv->sbands[IEEE80211_BAND_2GHZ];
+	if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes))
+		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+			&priv->sbands[IEEE80211_BAND_5GHZ];
 
 	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
 		if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes))
 			setup_ht_cap(priv,
 				     &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+		if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes))
+			setup_ht_cap(priv,
+				     &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap);
 	}
 
 	SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
@@ -747,7 +827,7 @@
 		goto err_free;
 	}
 
-	ret = ath9k_init_htc_services(priv);
+	ret = ath9k_init_htc_services(priv, devid);
 	if (ret)
 		goto err_init;
 
@@ -790,7 +870,8 @@
 	if (ret)
 		return ret;
 
-	ret = ath9k_init_htc_services(htc_handle->drv_priv);
+	ret = ath9k_init_htc_services(htc_handle->drv_priv,
+			      htc_handle->drv_priv->ah->hw_version.devid);
 	return ret;
 }
 #endif
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 9d371c1..cf9bcc6 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -27,13 +27,11 @@
 static void ath_update_txpow(struct ath9k_htc_priv *priv)
 {
 	struct ath_hw *ah = priv->ah;
-	u32 txpow;
 
 	if (priv->curtxpow != priv->txpowlimit) {
 		ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit);
 		/* read back in case value is clamped */
-		ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
-		priv->curtxpow = txpow;
+		priv->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
 	}
 }
 
@@ -325,142 +323,129 @@
 	tcap.flags_ext = 0x80601000;
 	tcap.ampdu_limit = 0xffff0000;
 	tcap.ampdu_subframes = 20;
-	tcap.tx_chainmask_legacy = 1;
+	tcap.tx_chainmask_legacy = priv->ah->caps.tx_chainmask;
 	tcap.protmode = 1;
-	tcap.tx_chainmask = 1;
+	tcap.tx_chainmask = priv->ah->caps.tx_chainmask;
 
 	WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap);
 
 	return ret;
 }
 
-static int ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
-				 struct ieee80211_vif *vif,
-				 struct ieee80211_sta *sta)
+static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv,
+				 struct ieee80211_sta *sta,
+				 struct ath9k_htc_target_rate *trate)
 {
-	struct ath_common *common = ath9k_hw_common(priv->ah);
 	struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
 	struct ieee80211_supported_band *sband;
-	struct ath9k_htc_target_rate trate;
 	u32 caps = 0;
-	u8 cmd_rsp;
-	int i, j, ret;
+	int i, j;
 
-	memset(&trate, 0, sizeof(trate));
-
-	/* Only 2GHz is supported */
-	sband = priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
+	sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band];
 
 	for (i = 0, j = 0; i < sband->n_bitrates; i++) {
 		if (sta->supp_rates[sband->band] & BIT(i)) {
-			priv->tgt_rate.rates.legacy_rates.rs_rates[j]
+			trate->rates.legacy_rates.rs_rates[j]
 				= (sband->bitrates[i].bitrate * 2) / 10;
 			j++;
 		}
 	}
-	priv->tgt_rate.rates.legacy_rates.rs_nrates = j;
+	trate->rates.legacy_rates.rs_nrates = j;
 
 	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)))
-				priv->tgt_rate.rates.ht_rates.rs_rates[j++] = i;
+				trate->rates.ht_rates.rs_rates[j++] = i;
 			if (j == ATH_HTC_RATE_MAX)
 				break;
 		}
-		priv->tgt_rate.rates.ht_rates.rs_nrates = j;
+		trate->rates.ht_rates.rs_nrates = j;
 
 		caps = WLAN_RC_HT_FLAG;
+		if (sta->ht_cap.mcs.rx_mask[1])
+			caps |= WLAN_RC_DS_FLAG;
 		if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
 			caps |= WLAN_RC_40_FLAG;
-		if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
+		if (conf_is_ht40(&priv->hw->conf) &&
+		    (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40))
 			caps |= WLAN_RC_SGI_FLAG;
-
+		else if (conf_is_ht20(&priv->hw->conf) &&
+			 (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20))
+			caps |= WLAN_RC_SGI_FLAG;
 	}
 
-	priv->tgt_rate.sta_index = ista->index;
-	priv->tgt_rate.isnew = 1;
-	trate = priv->tgt_rate;
-	priv->tgt_rate.capflags = cpu_to_be32(caps);
-	trate.capflags = cpu_to_be32(caps);
+	trate->sta_index = ista->index;
+	trate->isnew = 1;
+	trate->capflags = cpu_to_be32(caps);
+}
 
-	WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
+static int ath9k_htc_send_rate_cmd(struct ath9k_htc_priv *priv,
+				    struct ath9k_htc_target_rate *trate)
+{
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	int ret;
+	u8 cmd_rsp;
+
+	WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, trate);
 	if (ret) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to initialize Rate information on target\n");
-		return ret;
 	}
 
-	ath_print(common, ATH_DBG_CONFIG,
-		  "Updated target STA: %pM (caps: 0x%x)\n", sta->addr, caps);
-	return 0;
+	return ret;
 }
 
-static bool check_rc_update(struct ieee80211_hw *hw, bool *cw40)
+static void ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
+				struct ieee80211_sta *sta)
 {
-	struct ath9k_htc_priv *priv = hw->priv;
-	struct ieee80211_conf *conf = &hw->conf;
-
-	if (!conf_is_ht(conf))
-		return false;
-
-	if (!(priv->op_flags & OP_ASSOCIATED) ||
-	    (priv->op_flags & OP_SCANNING))
-		return false;
-
-	if (conf_is_ht40(conf)) {
-		if (priv->ah->curchan->chanmode &
-			(CHANNEL_HT40PLUS | CHANNEL_HT40MINUS)) {
-			return false;
-		} else {
-			*cw40 = true;
-			return true;
-		}
-	} else {  /* ht20 */
-		if (priv->ah->curchan->chanmode & CHANNEL_HT20)
-			return false;
-		else
-			return true;
-	}
-}
-
-static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40)
-{
-	struct ath9k_htc_target_rate trate;
 	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct ath9k_htc_target_rate trate;
 	int ret;
-	u32 caps = be32_to_cpu(priv->tgt_rate.capflags);
-	u8 cmd_rsp;
 
-	memset(&trate, 0, sizeof(trate));
+	memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
+	ath9k_htc_setup_rate(priv, sta, &trate);
+	ret = ath9k_htc_send_rate_cmd(priv, &trate);
+	if (!ret)
+		ath_print(common, ATH_DBG_CONFIG,
+			  "Updated target sta: %pM, rate caps: 0x%X\n",
+			  sta->addr, be32_to_cpu(trate.capflags));
+}
 
-	trate = priv->tgt_rate;
+static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv,
+				  struct ieee80211_vif *vif,
+				  struct ieee80211_bss_conf *bss_conf)
+{
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct ath9k_htc_target_rate trate;
+	struct ieee80211_sta *sta;
+	int ret;
 
-	if (is_cw40)
-		caps |= WLAN_RC_40_FLAG;
-	else
-		caps &= ~WLAN_RC_40_FLAG;
+	memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
 
-	priv->tgt_rate.capflags = cpu_to_be32(caps);
-	trate.capflags = cpu_to_be32(caps);
-
-	WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
-	if (ret) {
-		ath_print(common, ATH_DBG_FATAL,
-			  "Unable to update Rate information on target\n");
+	rcu_read_lock();
+	sta = ieee80211_find_sta(vif, bss_conf->bssid);
+	if (!sta) {
+		rcu_read_unlock();
 		return;
 	}
+	ath9k_htc_setup_rate(priv, sta, &trate);
+	rcu_read_unlock();
 
-	ath_print(common, ATH_DBG_CONFIG, "Rate control updated with "
-		  "caps:0x%x on target\n", priv->tgt_rate.capflags);
+	ret = ath9k_htc_send_rate_cmd(priv, &trate);
+	if (!ret)
+		ath_print(common, ATH_DBG_CONFIG,
+			  "Updated target sta: %pM, rate caps: 0x%X\n",
+			  bss_conf->bssid, be32_to_cpu(trate.capflags));
 }
 
-static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
-			       struct ieee80211_vif *vif,
-			       u8 *sta_addr, u8 tid, bool oper)
+static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv,
+				  struct ieee80211_vif *vif,
+				  struct ieee80211_sta *sta,
+				  enum ieee80211_ampdu_mlme_action action,
+				  u16 tid)
 {
 	struct ath_common *common = ath9k_hw_common(priv->ah);
 	struct ath9k_htc_target_aggr aggr;
-	struct ieee80211_sta *sta = NULL;
 	struct ath9k_htc_sta *ista;
 	int ret = 0;
 	u8 cmd_rsp;
@@ -469,74 +454,30 @@
 		return -EINVAL;
 
 	memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
-
-	rcu_read_lock();
-
-	/* Check if we are able to retrieve the station */
-	sta = ieee80211_find_sta(vif, sta_addr);
-	if (!sta) {
-		rcu_read_unlock();
-		return -EINVAL;
-	}
-
 	ista = (struct ath9k_htc_sta *) sta->drv_priv;
 
-	if (oper)
-		ista->tid_state[tid] = AGGR_START;
-	else
-		ista->tid_state[tid] = AGGR_STOP;
-
 	aggr.sta_index = ista->index;
-
-	rcu_read_unlock();
-
-	aggr.tidno = tid;
-	aggr.aggr_enable = oper;
+	aggr.tidno = tid & 0xf;
+	aggr.aggr_enable = (action == IEEE80211_AMPDU_TX_START) ? true : false;
 
 	WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
 	if (ret)
 		ath_print(common, ATH_DBG_CONFIG,
 			  "Unable to %s TX aggregation for (%pM, %d)\n",
-			  (oper) ? "start" : "stop", sta->addr, tid);
+			  (aggr.aggr_enable) ? "start" : "stop", sta->addr, tid);
 	else
 		ath_print(common, ATH_DBG_CONFIG,
-			  "%s aggregation for (%pM, %d)\n",
-			  (oper) ? "Starting" : "Stopping", sta->addr, tid);
+			  "%s TX aggregation for (%pM, %d)\n",
+			  (aggr.aggr_enable) ? "Starting" : "Stopping",
+			  sta->addr, tid);
+
+	spin_lock_bh(&priv->tx_lock);
+	ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
+	spin_unlock_bh(&priv->tx_lock);
 
 	return ret;
 }
 
-void ath9k_htc_aggr_work(struct work_struct *work)
-{
-	int ret = 0;
-	struct ath9k_htc_priv *priv =
-		container_of(work, struct ath9k_htc_priv,
-			     ath9k_aggr_work.work);
-	struct ath9k_htc_aggr_work *wk = &priv->aggr_work;
-
-	mutex_lock(&wk->mutex);
-
-	switch (wk->action) {
-	case IEEE80211_AMPDU_TX_START:
-		ret = ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
-					  wk->tid, true);
-		if (!ret)
-			ieee80211_start_tx_ba_cb(wk->vif, wk->sta_addr,
-						 wk->tid);
-		break;
-	case IEEE80211_AMPDU_TX_STOP:
-		ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
-				    wk->tid, false);
-		ieee80211_stop_tx_ba_cb(wk->vif, wk->sta_addr, wk->tid);
-		break;
-	default:
-		ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
-			  "Unknown AMPDU action\n");
-	}
-
-	mutex_unlock(&wk->mutex);
-}
-
 /*********/
 /* DEBUG */
 /*********/
@@ -552,8 +493,7 @@
 static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
 				   size_t count, loff_t *ppos)
 {
-	struct ath9k_htc_priv *priv =
-		(struct ath9k_htc_priv *) file->private_data;
+	struct ath9k_htc_priv *priv = file->private_data;
 	struct ath9k_htc_target_stats cmd_rsp;
 	char buf[512];
 	unsigned int len = 0;
@@ -584,6 +524,9 @@
 	len += snprintf(buf + len, sizeof(buf) - len,
 			"%19s : %10u\n", "TX Rate", priv->debug.txrate);
 
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -596,8 +539,7 @@
 static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
 			      size_t count, loff_t *ppos)
 {
-	struct ath9k_htc_priv *priv =
-		(struct ath9k_htc_priv *) file->private_data;
+	struct ath9k_htc_priv *priv = file->private_data;
 	char buf[512];
 	unsigned int len = 0;
 
@@ -617,6 +559,22 @@
 			"%20s : %10u\n", "SKBs dropped",
 			priv->debug.tx_stats.skb_dropped);
 
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "BE queued",
+			priv->debug.tx_stats.queue_stats[WME_AC_BE]);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "BK queued",
+			priv->debug.tx_stats.queue_stats[WME_AC_BK]);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "VI queued",
+			priv->debug.tx_stats.queue_stats[WME_AC_VI]);
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"%20s : %10u\n", "VO queued",
+			priv->debug.tx_stats.queue_stats[WME_AC_VO]);
+
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -629,8 +587,7 @@
 static ssize_t read_file_recv(struct file *file, char __user *user_buf,
 			      size_t count, loff_t *ppos)
 {
-	struct ath9k_htc_priv *priv =
-		(struct ath9k_htc_priv *) file->private_data;
+	struct ath9k_htc_priv *priv = file->private_data;
 	char buf[512];
 	unsigned int len = 0;
 
@@ -644,6 +601,9 @@
 			"%20s : %10u\n", "SKBs Dropped",
 			priv->debug.rx_stats.skb_dropped);
 
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -978,6 +938,8 @@
 		priv->ah->led_pin = ATH_LED_PIN_9287;
 	else if (AR_SREV_9271(priv->ah))
 		priv->ah->led_pin = ATH_LED_PIN_9271;
+	else if (AR_DEVID_7010(priv->ah))
+		priv->ah->led_pin = ATH_LED_PIN_7010;
 	else
 		priv->ah->led_pin = ATH_LED_PIN_DEF;
 
@@ -1054,6 +1016,95 @@
 		wiphy_rfkill_start_polling(priv->hw->wiphy);
 }
 
+static void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
+{
+	struct ath9k_htc_priv *priv = hw->priv;
+	struct ath_hw *ah = priv->ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	int ret;
+	u8 cmd_rsp;
+
+	if (!ah->curchan)
+		ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
+
+	/* Reset the HW */
+	ret = ath9k_hw_reset(ah, ah->curchan, false);
+	if (ret) {
+		ath_print(common, ATH_DBG_FATAL,
+			  "Unable to reset hardware; reset status %d "
+			  "(freq %u MHz)\n", ret, ah->curchan->channel);
+	}
+
+	ath_update_txpow(priv);
+
+	/* Start RX */
+	WMI_CMD(WMI_START_RECV_CMDID);
+	ath9k_host_rx_init(priv);
+
+	/* Start TX */
+	htc_start(priv->htc);
+	spin_lock_bh(&priv->tx_lock);
+	priv->tx_queues_stop = false;
+	spin_unlock_bh(&priv->tx_lock);
+	ieee80211_wake_queues(hw);
+
+	WMI_CMD(WMI_ENABLE_INTR_CMDID);
+
+	/* Enable LED */
+	ath9k_hw_cfg_output(ah, ah->led_pin,
+			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+	ath9k_hw_set_gpio(ah, ah->led_pin, 0);
+}
+
+static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
+{
+	struct ath9k_htc_priv *priv = hw->priv;
+	struct ath_hw *ah = priv->ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	int ret;
+	u8 cmd_rsp;
+
+	ath9k_htc_ps_wakeup(priv);
+
+	/* Disable LED */
+	ath9k_hw_set_gpio(ah, ah->led_pin, 1);
+	ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
+
+	WMI_CMD(WMI_DISABLE_INTR_CMDID);
+
+	/* Stop TX */
+	ieee80211_stop_queues(hw);
+	htc_stop(priv->htc);
+	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
+	skb_queue_purge(&priv->tx_queue);
+
+	/* Stop RX */
+	WMI_CMD(WMI_STOP_RECV_CMDID);
+
+	/*
+	 * The MIB counters have to be disabled here,
+	 * since the target doesn't do it.
+	 */
+	ath9k_hw_disable_mib_counters(ah);
+
+	if (!ah->curchan)
+		ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
+
+	/* Reset the HW */
+	ret = ath9k_hw_reset(ah, ah->curchan, false);
+	if (ret) {
+		ath_print(common, ATH_DBG_FATAL,
+			  "Unable to reset hardware; reset status %d "
+			  "(freq %u MHz)\n", ret, ah->curchan->channel);
+	}
+
+	/* Disable the PHY */
+	ath9k_hw_phy_disable(ah);
+
+	ath9k_htc_ps_restore(priv);
+	ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
+}
+
 /**********************/
 /* mac80211 Callbacks */
 /**********************/
@@ -1099,7 +1150,7 @@
 	return 0;
 }
 
-static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led)
+static int ath9k_htc_start(struct ieee80211_hw *hw)
 {
 	struct ath9k_htc_priv *priv = hw->priv;
 	struct ath_hw *ah = priv->ah;
@@ -1111,10 +1162,16 @@
 	__be16 htc_mode;
 	u8 cmd_rsp;
 
+	mutex_lock(&priv->mutex);
+
 	ath_print(common, ATH_DBG_CONFIG,
 		  "Starting driver with initial channel: %d MHz\n",
 		  curchan->center_freq);
 
+	/* Ensure that HW is awake before flushing RX */
+	ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
+	WMI_CMD(WMI_FLUSH_RECV_CMDID);
+
 	/* setup initial channel */
 	init_channel = ath9k_cmn_get_curchannel(hw, ah);
 
@@ -1127,6 +1184,7 @@
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset hardware; reset status %d "
 			  "(freq %u MHz)\n", ret, curchan->center_freq);
+		mutex_unlock(&priv->mutex);
 		return ret;
 	}
 
@@ -1147,31 +1205,14 @@
 	priv->tx_queues_stop = false;
 	spin_unlock_bh(&priv->tx_lock);
 
-	if (led) {
-		/* Enable LED */
-		ath9k_hw_cfg_output(ah, ah->led_pin,
-				    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-		ath9k_hw_set_gpio(ah, ah->led_pin, 0);
-	}
-
 	ieee80211_wake_queues(hw);
 
-	return ret;
-}
-
-static int ath9k_htc_start(struct ieee80211_hw *hw)
-{
-	struct ath9k_htc_priv *priv = hw->priv;
-	int ret = 0;
-
-	mutex_lock(&priv->mutex);
-	ret = ath9k_htc_radio_enable(hw, false);
 	mutex_unlock(&priv->mutex);
 
 	return ret;
 }
 
-static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led)
+static void ath9k_htc_stop(struct ieee80211_hw *hw)
 {
 	struct ath9k_htc_priv *priv = hw->priv;
 	struct ath_hw *ah = priv->ah;
@@ -1179,21 +1220,17 @@
 	int ret = 0;
 	u8 cmd_rsp;
 
+	mutex_lock(&priv->mutex);
+
 	if (priv->op_flags & OP_INVALID) {
 		ath_print(common, ATH_DBG_ANY, "Device not present\n");
+		mutex_unlock(&priv->mutex);
 		return;
 	}
 
-	if (led) {
-		/* Disable LED */
-		ath9k_hw_set_gpio(ah, ah->led_pin, 1);
-		ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
-	}
-
 	/* Cancel all the running timers/work .. */
 	cancel_work_sync(&priv->ps_work);
 	cancel_delayed_work_sync(&priv->ath9k_ani_work);
-	cancel_delayed_work_sync(&priv->ath9k_aggr_work);
 	cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
 	ath9k_led_stop_brightness(priv);
 
@@ -1202,12 +1239,6 @@
 	WMI_CMD(WMI_DISABLE_INTR_CMDID);
 	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
 	WMI_CMD(WMI_STOP_RECV_CMDID);
-	ath9k_hw_phy_disable(ah);
-	ath9k_hw_disable(ah);
-	ath9k_hw_configpcipowersave(ah, 1, 1);
-	ath9k_htc_ps_restore(priv);
-	ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
-
 	skb_queue_purge(&priv->tx_queue);
 
 	/* Remove monitor interface here */
@@ -1220,21 +1251,18 @@
 				  "Monitor interface removed\n");
 	}
 
+	ath9k_hw_phy_disable(ah);
+	ath9k_hw_disable(ah);
+	ath9k_hw_configpcipowersave(ah, 1, 1);
+	ath9k_htc_ps_restore(priv);
+	ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
+
 	priv->op_flags |= OP_INVALID;
 
 	ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
-}
-
-static void ath9k_htc_stop(struct ieee80211_hw *hw)
-{
-	struct ath9k_htc_priv *priv = hw->priv;
-
-	mutex_lock(&priv->mutex);
-	ath9k_htc_radio_disable(hw, false);
 	mutex_unlock(&priv->mutex);
 }
 
-
 static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
 				   struct ieee80211_vif *vif)
 {
@@ -1302,6 +1330,7 @@
 out:
 	ath9k_htc_ps_restore(priv);
 	mutex_unlock(&priv->mutex);
+
 	return ret;
 }
 
@@ -1318,6 +1347,7 @@
 	ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
 
 	mutex_lock(&priv->mutex);
+	ath9k_htc_ps_wakeup(priv);
 
 	memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
 	memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
@@ -1328,6 +1358,7 @@
 	ath9k_htc_remove_station(priv, vif, NULL);
 	priv->vif = NULL;
 
+	ath9k_htc_ps_restore(priv);
 	mutex_unlock(&priv->mutex);
 }
 
@@ -1343,30 +1374,27 @@
 		bool enable_radio = false;
 		bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
 
+		mutex_lock(&priv->htc_pm_lock);
 		if (!idle && priv->ps_idle)
 			enable_radio = true;
-
 		priv->ps_idle = idle;
+		mutex_unlock(&priv->htc_pm_lock);
 
 		if (enable_radio) {
-			ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
-			ath9k_htc_radio_enable(hw, true);
 			ath_print(common, ATH_DBG_CONFIG,
 				  "not-idle: enabling radio\n");
+			ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
+			ath9k_htc_radio_enable(hw);
 		}
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
 		struct ieee80211_channel *curchan = hw->conf.channel;
 		int pos = curchan->hw_value;
-		bool is_cw40 = false;
 
 		ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
 			  curchan->center_freq);
 
-		if (check_rc_update(hw, &is_cw40))
-			ath9k_htc_rc_update(priv, is_cw40);
-
 		ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
 
 		if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
@@ -1399,14 +1427,21 @@
 		}
 	}
 
-	if (priv->ps_idle) {
+	if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+		mutex_lock(&priv->htc_pm_lock);
+		if (!priv->ps_idle) {
+			mutex_unlock(&priv->htc_pm_lock);
+			goto out;
+		}
+		mutex_unlock(&priv->htc_pm_lock);
+
 		ath_print(common, ATH_DBG_CONFIG,
 			  "idle: disabling radio\n");
-		ath9k_htc_radio_disable(hw, true);
+		ath9k_htc_radio_disable(hw);
 	}
 
+out:
 	mutex_unlock(&priv->mutex);
-
 	return 0;
 }
 
@@ -1428,8 +1463,8 @@
 	u32 rfilt;
 
 	mutex_lock(&priv->mutex);
-
 	ath9k_htc_ps_wakeup(priv);
+
 	changed_flags &= SUPPORTED_FILTERS;
 	*total_flags &= SUPPORTED_FILTERS;
 
@@ -1444,30 +1479,38 @@
 	mutex_unlock(&priv->mutex);
 }
 
-static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
-				 struct ieee80211_vif *vif,
-				 enum sta_notify_cmd cmd,
-				 struct ieee80211_sta *sta)
+static int ath9k_htc_sta_add(struct ieee80211_hw *hw,
+			     struct ieee80211_vif *vif,
+			     struct ieee80211_sta *sta)
 {
 	struct ath9k_htc_priv *priv = hw->priv;
 	int ret;
 
 	mutex_lock(&priv->mutex);
-
-	switch (cmd) {
-	case STA_NOTIFY_ADD:
-		ret = ath9k_htc_add_station(priv, vif, sta);
-		if (!ret)
-			ath9k_htc_init_rate(priv, vif, sta);
-		break;
-	case STA_NOTIFY_REMOVE:
-		ath9k_htc_remove_station(priv, vif, sta);
-		break;
-	default:
-		break;
-	}
-
+	ath9k_htc_ps_wakeup(priv);
+	ret = ath9k_htc_add_station(priv, vif, sta);
+	if (!ret)
+		ath9k_htc_init_rate(priv, sta);
+	ath9k_htc_ps_restore(priv);
 	mutex_unlock(&priv->mutex);
+
+	return ret;
+}
+
+static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
+				struct ieee80211_vif *vif,
+				struct ieee80211_sta *sta)
+{
+	struct ath9k_htc_priv *priv = hw->priv;
+	int ret;
+
+	mutex_lock(&priv->mutex);
+	ath9k_htc_ps_wakeup(priv);
+	ret = ath9k_htc_remove_station(priv, vif, sta);
+	ath9k_htc_ps_restore(priv);
+	mutex_unlock(&priv->mutex);
+
+	return ret;
 }
 
 static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
@@ -1482,6 +1525,7 @@
 		return 0;
 
 	mutex_lock(&priv->mutex);
+	ath9k_htc_ps_wakeup(priv);
 
 	memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
 
@@ -1499,9 +1543,16 @@
 		  params->cw_max, params->txop);
 
 	ret = ath_htc_txq_update(priv, qnum, &qi);
-	if (ret)
+	if (ret) {
 		ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
+		goto out;
+	}
 
+	if ((priv->ah->opmode == NL80211_IFTYPE_ADHOC) &&
+	    (qnum == priv->hwq_map[WME_AC_BE]))
+		    ath9k_htc_beaconq_config(priv);
+out:
+	ath9k_htc_ps_restore(priv);
 	mutex_unlock(&priv->mutex);
 
 	return ret;
@@ -1574,7 +1625,6 @@
 			ath_start_ani(priv);
 		} else {
 			priv->op_flags &= ~OP_ASSOCIATED;
-			cancel_work_sync(&priv->ps_work);
 			cancel_delayed_work_sync(&priv->ath9k_ani_work);
 		}
 	}
@@ -1631,6 +1681,9 @@
 		ath9k_hw_init_global_settings(ah);
 	}
 
+	if (changed & BSS_CHANGED_HT)
+		ath9k_htc_update_rate(priv, vif, bss_conf);
+
 	ath9k_htc_ps_restore(priv);
 	mutex_unlock(&priv->mutex);
 }
@@ -1641,7 +1694,9 @@
 	u64 tsf;
 
 	mutex_lock(&priv->mutex);
+	ath9k_htc_ps_wakeup(priv);
 	tsf = ath9k_hw_gettsf64(priv->ah);
+	ath9k_htc_ps_restore(priv);
 	mutex_unlock(&priv->mutex);
 
 	return tsf;
@@ -1652,7 +1707,9 @@
 	struct ath9k_htc_priv *priv = hw->priv;
 
 	mutex_lock(&priv->mutex);
+	ath9k_htc_ps_wakeup(priv);
 	ath9k_hw_settsf64(priv->ah, tsf);
+	ath9k_htc_ps_restore(priv);
 	mutex_unlock(&priv->mutex);
 }
 
@@ -1660,11 +1717,11 @@
 {
 	struct ath9k_htc_priv *priv = hw->priv;
 
-	ath9k_htc_ps_wakeup(priv);
 	mutex_lock(&priv->mutex);
+	ath9k_htc_ps_wakeup(priv);
 	ath9k_hw_reset_tsf(priv->ah);
-	mutex_unlock(&priv->mutex);
 	ath9k_htc_ps_restore(priv);
+	mutex_unlock(&priv->mutex);
 }
 
 static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
@@ -1674,8 +1731,8 @@
 				  u16 tid, u16 *ssn)
 {
 	struct ath9k_htc_priv *priv = hw->priv;
-	struct ath9k_htc_aggr_work *work = &priv->aggr_work;
 	struct ath9k_htc_sta *ista;
+	int ret = 0;
 
 	switch (action) {
 	case IEEE80211_AMPDU_RX_START:
@@ -1683,26 +1740,26 @@
 	case IEEE80211_AMPDU_RX_STOP:
 		break;
 	case IEEE80211_AMPDU_TX_START:
+		ret = ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
+		if (!ret)
+			ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		break;
 	case IEEE80211_AMPDU_TX_STOP:
-		if (!(priv->op_flags & OP_TXAGGR))
-			return -ENOTSUPP;
-		memcpy(work->sta_addr, sta->addr, ETH_ALEN);
-		work->hw = hw;
-		work->vif = vif;
-		work->action = action;
-		work->tid = tid;
-		ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0);
+		ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
+		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
 		ista = (struct ath9k_htc_sta *) sta->drv_priv;
+		spin_lock_bh(&priv->tx_lock);
 		ista->tid_state[tid] = AGGR_OPERATIONAL;
+		spin_unlock_bh(&priv->tx_lock);
 		break;
 	default:
 		ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
 			  "Unknown AMPDU action\n");
 	}
 
-	return 0;
+	return ret;
 }
 
 static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
@@ -1722,8 +1779,8 @@
 {
 	struct ath9k_htc_priv *priv = hw->priv;
 
-	ath9k_htc_ps_wakeup(priv);
 	mutex_lock(&priv->mutex);
+	ath9k_htc_ps_wakeup(priv);
 	spin_lock_bh(&priv->beacon_lock);
 	priv->op_flags &= ~OP_SCANNING;
 	spin_unlock_bh(&priv->beacon_lock);
@@ -1731,8 +1788,8 @@
 	if (priv->op_flags & OP_ASSOCIATED)
 		ath9k_htc_beacon_config(priv, priv->vif);
 	ath_start_ani(priv);
-	mutex_unlock(&priv->mutex);
 	ath9k_htc_ps_restore(priv);
+	mutex_unlock(&priv->mutex);
 }
 
 static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
@@ -1746,8 +1803,10 @@
 	struct ath9k_htc_priv *priv = hw->priv;
 
 	mutex_lock(&priv->mutex);
+	ath9k_htc_ps_wakeup(priv);
 	priv->ah->coverage_class = coverage_class;
 	ath9k_hw_init_global_settings(priv->ah);
+	ath9k_htc_ps_restore(priv);
 	mutex_unlock(&priv->mutex);
 }
 
@@ -1759,7 +1818,8 @@
 	.remove_interface   = ath9k_htc_remove_interface,
 	.config             = ath9k_htc_config,
 	.configure_filter   = ath9k_htc_configure_filter,
-	.sta_notify         = ath9k_htc_sta_notify,
+	.sta_add            = ath9k_htc_sta_add,
+	.sta_remove         = ath9k_htc_sta_remove,
 	.conf_tx            = ath9k_htc_conf_tx,
 	.bss_info_changed   = ath9k_htc_bss_info_changed,
 	.set_key            = ath9k_htc_set_key,
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 2571b44..bd0b4ac 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -20,19 +20,29 @@
 /* TX */
 /******/
 
+#define ATH9K_HTC_INIT_TXQ(subtype) do {			\
+		qi.tqi_subtype = subtype;			\
+		qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;		\
+		qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;		\
+		qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;		\
+		qi.tqi_physCompBuf = 0;				\
+		qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |	\
+			TXQ_FLAG_TXDESCINT_ENABLE;		\
+	} while (0)
+
 int get_hw_qnum(u16 queue, int *hwq_map)
 {
 	switch (queue) {
 	case 0:
-		return hwq_map[ATH9K_WME_AC_VO];
+		return hwq_map[WME_AC_VO];
 	case 1:
-		return hwq_map[ATH9K_WME_AC_VI];
+		return hwq_map[WME_AC_VI];
 	case 2:
-		return hwq_map[ATH9K_WME_AC_BE];
+		return hwq_map[WME_AC_BE];
 	case 3:
-		return hwq_map[ATH9K_WME_AC_BK];
+		return hwq_map[WME_AC_BK];
 	default:
-		return hwq_map[ATH9K_WME_AC_BE];
+		return hwq_map[WME_AC_BE];
 	}
 }
 
@@ -71,7 +81,7 @@
 	struct ath9k_htc_vif *avp;
 	struct ath9k_htc_tx_ctl tx_ctl;
 	enum htc_endpoint_id epid;
-	u16 qnum, hw_qnum;
+	u16 qnum;
 	__le16 fc;
 	u8 *tx_fhdr;
 	u8 sta_idx;
@@ -131,20 +141,23 @@
 		memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
 
 		qnum = skb_get_queue_mapping(skb);
-		hw_qnum = get_hw_qnum(qnum, priv->hwq_map);
 
-		switch (hw_qnum) {
+		switch (qnum) {
 		case 0:
-			epid = priv->data_be_ep;
-			break;
-		case 2:
-			epid = priv->data_vi_ep;
-			break;
-		case 3:
+			TX_QSTAT_INC(WME_AC_VO);
 			epid = priv->data_vo_ep;
 			break;
 		case 1:
+			TX_QSTAT_INC(WME_AC_VI);
+			epid = priv->data_vi_ep;
+			break;
+		case 2:
+			TX_QSTAT_INC(WME_AC_BE);
+			epid = priv->data_be_ep;
+			break;
+		case 3:
 		default:
+			TX_QSTAT_INC(WME_AC_BK);
 			epid = priv->data_bk_ep;
 			break;
 		}
@@ -174,6 +187,19 @@
 	return htc_send(priv->htc, skb, epid, &tx_ctl);
 }
 
+static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
+				    struct ath9k_htc_sta *ista, u8 tid)
+{
+	bool ret = false;
+
+	spin_lock_bh(&priv->tx_lock);
+	if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP))
+		ret = true;
+	spin_unlock_bh(&priv->tx_lock);
+
+	return ret;
+}
+
 void ath9k_tx_tasklet(unsigned long data)
 {
 	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
@@ -203,8 +229,7 @@
 		/* Check if we need to start aggregation */
 
 		if (sta && conf_is_ht(&priv->hw->conf) &&
-		    (priv->op_flags & OP_TXAGGR)
-		    && !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
+		    !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
 			if (ieee80211_is_data_qos(fc)) {
 				u8 *qc, tid;
 				struct ath9k_htc_sta *ista;
@@ -213,10 +238,11 @@
 				tid = qc[0] & 0xf;
 				ista = (struct ath9k_htc_sta *)sta->drv_priv;
 
-				if ((tid < ATH9K_HTC_MAX_TID) &&
-				    ista->tid_state[tid] == AGGR_STOP) {
+				if (ath9k_htc_check_tx_aggr(priv, ista, tid)) {
 					ieee80211_start_tx_ba_session(sta, tid);
+					spin_lock_bh(&priv->tx_lock);
 					ista->tid_state[tid] = AGGR_PROGRESS;
+					spin_unlock_bh(&priv->tx_lock);
 				}
 			}
 		}
@@ -284,8 +310,7 @@
 
 }
 
-bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv,
-			 enum ath9k_tx_queue_subtype subtype)
+bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype)
 {
 	struct ath_hw *ah = priv->ah;
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -293,13 +318,7 @@
 	int qnum;
 
 	memset(&qi, 0, sizeof(qi));
-
-	qi.tqi_subtype = subtype;
-	qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
-	qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
-	qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
-	qi.tqi_physCompBuf = 0;
-	qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE;
+	ATH9K_HTC_INIT_TXQ(subtype);
 
 	qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi);
 	if (qnum == -1)
@@ -317,6 +336,16 @@
 	return true;
 }
 
+int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv)
+{
+	struct ath9k_tx_queue_info qi;
+
+	memset(&qi, 0, sizeof(qi));
+	ATH9K_HTC_INIT_TXQ(0);
+
+	return ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_CAB, &qi);
+}
+
 /******/
 /* RX */
 /******/
@@ -387,9 +416,6 @@
 	/* configure operational mode */
 	ath9k_hw_setopmode(ah);
 
-	/* Handle any link-level address change. */
-	ath9k_hw_setmac(ah, common->macaddr);
-
 	/* calculate and install multicast filter */
 	mfilt[0] = mfilt[1] = ~0;
 	ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
@@ -399,7 +425,7 @@
 {
 	ath9k_hw_rxena(priv->ah);
 	ath9k_htc_opmode_init(priv);
-	ath9k_hw_startpcureceive(priv->ah);
+	ath9k_hw_startpcureceive(priv->ah, (priv->op_flags & OP_SCANNING));
 	priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER;
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 064397f..705c0f3 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -89,7 +89,6 @@
 	struct htc_endpoint *endpoint;
 	struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf;
 
-	target->credits = be16_to_cpu(htc_ready_msg->credits);
 	target->credit_size = be16_to_cpu(htc_ready_msg->credit_size);
 
 	endpoint = &target->endpoint[ENDPOINT0];
@@ -159,7 +158,7 @@
 
 	cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID);
 	cp_msg->pipe_id = USB_WLAN_TX_PIPE;
-	cp_msg->credits = 28;
+	cp_msg->credits = target->credits;
 
 	target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
 
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index 624422a..ffecbad 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -128,6 +128,17 @@
 	ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf);
 }
 
+static inline void ath9k_hw_procmibevent(struct ath_hw *ah)
+{
+	ath9k_hw_ops(ah)->ani_proc_mib_event(ah);
+}
+
+static inline void ath9k_hw_ani_monitor(struct ath_hw *ah,
+					struct ath9k_channel *chan)
+{
+	ath9k_hw_ops(ah)->ani_monitor(ah, chan);
+}
+
 /* Private hardware call ops */
 
 /* PHY ops */
@@ -253,12 +264,6 @@
 	ath9k_hw_private_ops(ah)->do_getnf(ah, nfarray);
 }
 
-static inline void ath9k_hw_loadnf(struct ath_hw *ah,
-				   struct ath9k_channel *chan)
-{
-	ath9k_hw_private_ops(ah)->loadnf(ah, chan);
-}
-
 static inline bool ath9k_hw_init_cal(struct ath_hw *ah,
 				     struct ath9k_channel *chan)
 {
@@ -277,4 +282,9 @@
 	return ath9k_hw_private_ops(ah)->iscal_supported(ah, calType);
 }
 
+static inline void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
+{
+	ath9k_hw_private_ops(ah)->ani_reset(ah, is_scanning);
+}
+
 #endif /* ATH9K_HW_OPS_H */
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index c33f17d..8d291cc 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -23,11 +23,6 @@
 #include "rc.h"
 #include "ar9003_mac.h"
 
-#define ATH9K_CLOCK_RATE_CCK		22
-#define ATH9K_CLOCK_RATE_5GHZ_OFDM	40
-#define ATH9K_CLOCK_RATE_2GHZ_OFDM	44
-#define ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM 44
-
 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
 
 MODULE_AUTHOR("Atheros Communications");
@@ -80,6 +75,15 @@
 	ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah);
 }
 
+static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah)
+{
+	/* You will not have this callback if using the old ANI */
+	if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs)
+		return;
+
+	ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah);
+}
+
 /********************/
 /* Helper Functions */
 /********************/
@@ -371,13 +375,7 @@
 	ah->config.ofdm_trig_high = 500;
 	ah->config.cck_trig_high = 200;
 	ah->config.cck_trig_low = 100;
-
-	/*
-	 * For now ANI is disabled for AR9003, it is still
-	 * being tested.
-	 */
-	if (!AR_SREV_9300_20_OR_LATER(ah))
-		ah->config.enable_ani = 1;
+	ah->config.enable_ani = true;
 
 	for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
 		ah->config.spurchans[i][0] = AR_NO_SPUR;
@@ -390,12 +388,7 @@
 		ah->config.ht_enable = 0;
 
 	ah->config.rx_intr_mitigation = true;
-
-	/*
-	 * Tx IQ Calibration (ah->config.tx_iq_calibration) is only
-	 * used by AR9003, but it is showing reliability issues.
-	 * It will take a while to fix so this is currently disabled.
-	 */
+	ah->config.pcieSerDesWrite = true;
 
 	/*
 	 * We need this for PCI devices only (Cardbus, PCI, miniPCI)
@@ -433,7 +426,9 @@
 		ah->ah_flags = AH_USE_EEPROM;
 
 	ah->atim_window = 0;
-	ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
+	ah->sta_id1_defaults =
+		AR_STA_ID1_CRPT_MIC_ENABLE |
+		AR_STA_ID1_MCAST_KSRCH;
 	ah->beacon_interval = 100;
 	ah->enable_32kHz_clock = DONT_USE_32KHZ;
 	ah->slottime = (u32) -1;
@@ -537,7 +532,8 @@
 
 	if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
 		if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
-		    (AR_SREV_9280(ah) && !ah->is_pciexpress)) {
+		    ((AR_SREV_9160(ah) || AR_SREV_9280(ah)) &&
+		     !ah->is_pciexpress)) {
 			ah->config.serialize_regmode =
 				SER_REG_MODE_ON;
 		} else {
@@ -571,28 +567,19 @@
 	ah->ani_function = ATH9K_ANI_ALL;
 	if (AR_SREV_9280_10_OR_LATER(ah) && !AR_SREV_9300_20_OR_LATER(ah))
 		ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+	if (!AR_SREV_9300_20_OR_LATER(ah))
+		ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
 
 	ath9k_hw_init_mode_regs(ah);
 
 	/*
-	 * Configire PCIE after Ini init. SERDES values now come from ini file
-	 * This enables PCIe low power mode.
+	 * Read back AR_WA into a permanent copy and set bits 14 and 17.
+	 * We need to do this to avoid RMW of this register. We cannot
+	 * read the reg when chip is asleep.
 	 */
-	if (AR_SREV_9300_20_OR_LATER(ah)) {
-		u32 regval;
-		unsigned int i;
-
-		/* Set Bits 16 and 17 in the AR_WA register. */
-		regval = REG_READ(ah, AR_WA);
-		regval |= 0x00030000;
-		REG_WRITE(ah, AR_WA, regval);
-
-		for (i = 0; i < ah->iniPcieSerdesLowPower.ia_rows; i++) {
-			REG_WRITE(ah,
-				  INI_RA(&ah->iniPcieSerdesLowPower, i, 0),
-				  INI_RA(&ah->iniPcieSerdesLowPower, i, 1));
-		}
-	}
+	ah->WARegVal = REG_READ(ah, AR_WA);
+	ah->WARegVal |= (AR_WA_D3_L1_DISABLE |
+			 AR_WA_ASPM_TIMER_BASED_DISABLE);
 
 	if (ah->is_pciexpress)
 		ath9k_hw_configpcipowersave(ah, 0, 0);
@@ -623,10 +610,8 @@
 	else
 		ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
 
-	if (AR_SREV_9300_20_OR_LATER(ah))
-		ar9003_hw_set_nf_limits(ah);
-
 	ath9k_init_nfcal_hist_buffer(ah);
+	ah->bb_watchdog_timeout_ms = 25;
 
 	common->state = ATH_HW_INITIALIZED;
 
@@ -1012,6 +997,11 @@
 
 	ENABLE_REGWRITE_BUFFER(ah);
 
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		REG_WRITE(ah, AR_WA, ah->WARegVal);
+		udelay(10);
+	}
+
 	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
 		  AR_RTC_FORCE_WAKE_ON_INT);
 
@@ -1066,6 +1056,11 @@
 {
 	ENABLE_REGWRITE_BUFFER(ah);
 
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		REG_WRITE(ah, AR_WA, ah->WARegVal);
+		udelay(10);
+	}
+
 	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
 		  AR_RTC_FORCE_WAKE_ON_INT);
 
@@ -1073,6 +1068,7 @@
 		REG_WRITE(ah, AR_RC, AR_RC_AHB);
 
 	REG_WRITE(ah, AR_RTC_RESET, 0);
+	udelay(2);
 
 	REGWRITE_BUFFER_FLUSH(ah);
 	DISABLE_REGWRITE_BUFFER(ah);
@@ -1102,6 +1098,11 @@
 
 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
 {
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		REG_WRITE(ah, AR_WA, ah->WARegVal);
+		udelay(10);
+	}
+
 	REG_WRITE(ah, AR_RTC_FORCE_WAKE,
 		  AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
 
@@ -1232,9 +1233,11 @@
 
 	if (!ah->chip_fullsleep) {
 		ath9k_hw_abortpcurecv(ah);
-		if (!ath9k_hw_stopdmarecv(ah))
+		if (!ath9k_hw_stopdmarecv(ah)) {
 			ath_print(common, ATH_DBG_XMIT,
 				"Failed to stop receive dma\n");
+			bChannelChange = false;
+		}
 	}
 
 	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
@@ -1265,7 +1268,8 @@
 	macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
 
 	/* For chips on which RTC reset is done, save TSF before it gets cleared */
-	if (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+	if (AR_SREV_9100(ah) ||
+	    (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)))
 		tsf = ath9k_hw_gettsf64(ah);
 
 	saveLedState = REG_READ(ah, AR_CFG_LED) &
@@ -1297,16 +1301,30 @@
 	}
 
 	/* Restore TSF */
-	if (tsf && AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+	if (tsf)
 		ath9k_hw_settsf64(ah, tsf);
 
 	if (AR_SREV_9280_10_OR_LATER(ah))
 		REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
 
+	if (!AR_SREV_9300_20_OR_LATER(ah))
+		ar9002_hw_enable_async_fifo(ah);
+
 	r = ath9k_hw_process_ini(ah, chan);
 	if (r)
 		return r;
 
+	/*
+	 * Some AR91xx SoC devices frequently fail to accept TSF writes
+	 * right after the chip reset. When that happens, write a new
+	 * value after the initvals have been applied, with an offset
+	 * based on measured time difference
+	 */
+	if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) {
+		tsf += 1500;
+		ath9k_hw_settsf64(ah, tsf);
+	}
+
 	/* Setup MFP options for CCMP */
 	if (AR_SREV_9280_20_OR_LATER(ah)) {
 		/* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt
@@ -1367,6 +1385,7 @@
 		ath9k_hw_resettxqueue(ah, i);
 
 	ath9k_hw_init_interrupt_masks(ah, ah->opmode);
+	ath9k_hw_ani_cache_ini_regs(ah);
 	ath9k_hw_init_qos(ah);
 
 	if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
@@ -1375,7 +1394,7 @@
 	ath9k_hw_init_global_settings(ah);
 
 	if (!AR_SREV_9300_20_OR_LATER(ah)) {
-		ar9002_hw_enable_async_fifo(ah);
+		ar9002_hw_update_async_fifo(ah);
 		ar9002_hw_enable_wep_aggregation(ah);
 	}
 
@@ -1426,9 +1445,13 @@
 				"Setting CFG 0x%x\n", REG_READ(ah, AR_CFG));
 		}
 	} else {
-		/* Configure AR9271 target WLAN */
-                if (AR_SREV_9271(ah))
-			REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
+		if (common->bus_ops->ath_bus_type == ATH_USB) {
+			/* Configure AR9271 target WLAN */
+			if (AR_SREV_9271(ah))
+				REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
+			else
+				REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+		}
 #ifdef __BIG_ENDIAN
                 else
 			REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
@@ -1441,6 +1464,7 @@
 	if (AR_SREV_9300_20_OR_LATER(ah)) {
 		ath9k_hw_loadnf(ah, curchan);
 		ath9k_hw_start_nfcal(ah);
+		ar9003_hw_bb_watchdog_config(ah);
 	}
 
 	return 0;
@@ -1486,9 +1510,10 @@
 }
 EXPORT_SYMBOL(ath9k_hw_keyreset);
 
-bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
+static bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
 {
 	u32 macHi, macLo;
+	u32 unicast_flag = AR_KEYTABLE_VALID;
 
 	if (entry >= ah->caps.keycache_size) {
 		ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
@@ -1497,6 +1522,16 @@
 	}
 
 	if (mac != NULL) {
+		/*
+		 * AR_KEYTABLE_VALID indicates that the address is a unicast
+		 * address, which must match the transmitter address for
+		 * decrypting frames.
+		 * Not setting this bit allows the hardware to use the key
+		 * for multicast frame decryption.
+		 */
+		if (mac[0] & 0x01)
+			unicast_flag = 0;
+
 		macHi = (mac[5] << 8) | mac[4];
 		macLo = (mac[3] << 24) |
 			(mac[2] << 16) |
@@ -1509,11 +1544,10 @@
 		macLo = macHi = 0;
 	}
 	REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
-	REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID);
+	REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);
 
 	return true;
 }
-EXPORT_SYMBOL(ath9k_hw_keysetmac);
 
 bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
 				 const struct ath9k_keyval *k,
@@ -1714,17 +1748,6 @@
 }
 EXPORT_SYMBOL(ath9k_hw_set_keycache_entry);
 
-bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry)
-{
-	if (entry < ah->caps.keycache_size) {
-		u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry));
-		if (val & AR_KEYTABLE_VALID)
-			return true;
-	}
-	return false;
-}
-EXPORT_SYMBOL(ath9k_hw_keyisvalid);
-
 /******************************/
 /* Power Management (Chipset) */
 /******************************/
@@ -1751,6 +1774,11 @@
 			REG_CLR_BIT(ah, (AR_RTC_RESET),
 				    AR_RTC_RESET_EN);
 	}
+
+	/* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */
+	if (AR_SREV_9300_20_OR_LATER(ah))
+		REG_WRITE(ah, AR_WA,
+			  ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
 }
 
 /*
@@ -1777,6 +1805,10 @@
 				    AR_RTC_FORCE_WAKE_EN);
 		}
 	}
+
+	/* Clear Bit 14 of AR_WA after putting chip into Net Sleep mode. */
+	if (AR_SREV_9300_20_OR_LATER(ah))
+		REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
 }
 
 static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
@@ -1784,6 +1816,12 @@
 	u32 val;
 	int i;
 
+	/* Set Bits 14 and 17 of AR_WA before powering on the chip. */
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		REG_WRITE(ah, AR_WA, ah->WARegVal);
+		udelay(10);
+	}
+
 	if (setChip) {
 		if ((REG_READ(ah, AR_RTC_STATUS) &
 		     AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
@@ -2138,6 +2176,8 @@
 
 	if (AR_SREV_9271(ah))
 		pCap->num_gpio_pins = AR9271_NUM_GPIO;
+	else if (AR_DEVID_7010(ah))
+		pCap->num_gpio_pins = AR7010_NUM_GPIO;
 	else if (AR_SREV_9285_10_OR_LATER(ah))
 		pCap->num_gpio_pins = AR9285_NUM_GPIO;
 	else if (AR_SREV_9280_10_OR_LATER(ah))
@@ -2165,7 +2205,7 @@
 		pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
 	}
 #endif
-	if (AR_SREV_9271(ah))
+	if (AR_SREV_9271(ah) || AR_SREV_9300_20_OR_LATER(ah))
 		pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
 	else
 		pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
@@ -2220,6 +2260,8 @@
 		pCap->rx_status_len = sizeof(struct ar9003_rxs);
 		pCap->tx_desc_len = sizeof(struct ar9003_txc);
 		pCap->txs_len = sizeof(struct ar9003_txs);
+		if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
+			pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
 	} else {
 		pCap->tx_desc_len = sizeof(struct ath_desc);
 		if (AR_SREV_9280_20(ah) &&
@@ -2232,101 +2274,12 @@
 	if (AR_SREV_9300_20_OR_LATER(ah))
 		pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED;
 
+	if (AR_SREV_9287_10_OR_LATER(ah) || AR_SREV_9271(ah))
+		pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;
+
 	return 0;
 }
 
-bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
-			    u32 capability, u32 *result)
-{
-	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
-	switch (type) {
-	case ATH9K_CAP_CIPHER:
-		switch (capability) {
-		case ATH9K_CIPHER_AES_CCM:
-		case ATH9K_CIPHER_AES_OCB:
-		case ATH9K_CIPHER_TKIP:
-		case ATH9K_CIPHER_WEP:
-		case ATH9K_CIPHER_MIC:
-		case ATH9K_CIPHER_CLR:
-			return true;
-		default:
-			return false;
-		}
-	case ATH9K_CAP_TKIP_MIC:
-		switch (capability) {
-		case 0:
-			return true;
-		case 1:
-			return (ah->sta_id1_defaults &
-				AR_STA_ID1_CRPT_MIC_ENABLE) ? true :
-			false;
-		}
-	case ATH9K_CAP_TKIP_SPLIT:
-		return (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) ?
-			false : true;
-	case ATH9K_CAP_MCAST_KEYSRCH:
-		switch (capability) {
-		case 0:
-			return true;
-		case 1:
-			if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) {
-				return false;
-			} else {
-				return (ah->sta_id1_defaults &
-					AR_STA_ID1_MCAST_KSRCH) ? true :
-					false;
-			}
-		}
-		return false;
-	case ATH9K_CAP_TXPOW:
-		switch (capability) {
-		case 0:
-			return 0;
-		case 1:
-			*result = regulatory->power_limit;
-			return 0;
-		case 2:
-			*result = regulatory->max_power_level;
-			return 0;
-		case 3:
-			*result = regulatory->tp_scale;
-			return 0;
-		}
-		return false;
-	case ATH9K_CAP_DS:
-		return (AR_SREV_9280_20_OR_LATER(ah) &&
-			(ah->eep_ops->get_eeprom(ah, EEP_RC_CHAIN_MASK) == 1))
-			? false : true;
-	default:
-		return false;
-	}
-}
-EXPORT_SYMBOL(ath9k_hw_getcapability);
-
-bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
-			    u32 capability, u32 setting, int *status)
-{
-	switch (type) {
-	case ATH9K_CAP_TKIP_MIC:
-		if (setting)
-			ah->sta_id1_defaults |=
-				AR_STA_ID1_CRPT_MIC_ENABLE;
-		else
-			ah->sta_id1_defaults &=
-				~AR_STA_ID1_CRPT_MIC_ENABLE;
-		return true;
-	case ATH9K_CAP_MCAST_KEYSRCH:
-		if (setting)
-			ah->sta_id1_defaults |= AR_STA_ID1_MCAST_KSRCH;
-		else
-			ah->sta_id1_defaults &= ~AR_STA_ID1_MCAST_KSRCH;
-		return true;
-	default:
-		return false;
-	}
-}
-EXPORT_SYMBOL(ath9k_hw_setcapability);
-
 /****************************/
 /* GPIO / RFKILL / Antennae */
 /****************************/
@@ -2365,8 +2318,15 @@
 
 	BUG_ON(gpio >= ah->caps.num_gpio_pins);
 
-	gpio_shift = gpio << 1;
+	if (AR_DEVID_7010(ah)) {
+		gpio_shift = gpio;
+		REG_RMW(ah, AR7010_GPIO_OE,
+			(AR7010_GPIO_OE_AS_INPUT << gpio_shift),
+			(AR7010_GPIO_OE_MASK << gpio_shift));
+		return;
+	}
 
+	gpio_shift = gpio << 1;
 	REG_RMW(ah,
 		AR_GPIO_OE_OUT,
 		(AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
@@ -2382,7 +2342,11 @@
 	if (gpio >= ah->caps.num_gpio_pins)
 		return 0xffffffff;
 
-	if (AR_SREV_9300_20_OR_LATER(ah))
+	if (AR_DEVID_7010(ah)) {
+		u32 val;
+		val = REG_READ(ah, AR7010_GPIO_IN);
+		return (MS(val, AR7010_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) == 0;
+	} else if (AR_SREV_9300_20_OR_LATER(ah))
 		return MS_REG_READ(AR9300, gpio) != 0;
 	else if (AR_SREV_9271(ah))
 		return MS_REG_READ(AR9271, gpio) != 0;
@@ -2402,10 +2366,16 @@
 {
 	u32 gpio_shift;
 
+	if (AR_DEVID_7010(ah)) {
+		gpio_shift = gpio;
+		REG_RMW(ah, AR7010_GPIO_OE,
+			(AR7010_GPIO_OE_AS_OUTPUT << gpio_shift),
+			(AR7010_GPIO_OE_MASK << gpio_shift));
+		return;
+	}
+
 	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),
@@ -2415,6 +2385,13 @@
 
 void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
 {
+	if (AR_DEVID_7010(ah)) {
+		val = val ? 0 : 1;
+		REG_RMW(ah, AR7010_GPIO_OUT, ((val&1) << gpio),
+			AR_GPIO_BIT(gpio));
+		return;
+	}
+
 	if (AR_SREV_9271(ah))
 		val = ~val;
 
@@ -2520,12 +2497,6 @@
 }
 EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit);
 
-void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac)
-{
-	memcpy(ath9k_hw_common(ah)->macaddr, mac, ETH_ALEN);
-}
-EXPORT_SYMBOL(ath9k_hw_setmac);
-
 void ath9k_hw_setopmode(struct ath_hw *ah)
 {
 	ath9k_hw_set_operating_mode(ah, ah->opmode);
@@ -2598,21 +2569,6 @@
 }
 EXPORT_SYMBOL(ath9k_hw_set_tsfadjust);
 
-/*
- *  Extend 15-bit time stamp from rx descriptor to
- *  a full 64-bit TSF using the current h/w TSF.
-*/
-u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp)
-{
-	u64 tsf;
-
-	tsf = ath9k_hw_gettsf64(ah);
-	if ((tsf & 0x7fff) < rstamp)
-		tsf -= 0x8000;
-	return (tsf & ~0x7fff) | rstamp;
-}
-EXPORT_SYMBOL(ath9k_hw_extend_tsf);
-
 void ath9k_hw_set11nmac2040(struct ath_hw *ah)
 {
 	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 77245df..2d30efc 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -158,6 +158,9 @@
 #define ATH9K_HW_RX_HP_QDEPTH	16
 #define ATH9K_HW_RX_LP_QDEPTH	128
 
+#define PAPRD_GAIN_TABLE_ENTRIES    32
+#define PAPRD_TABLE_SZ              24
+
 enum ath_ini_subsys {
 	ATH_INI_PRE = 0,
 	ATH_INI_CORE,
@@ -199,15 +202,8 @@
 	ATH9K_HW_CAP_RAC_SUPPORTED		= BIT(18),
 	ATH9K_HW_CAP_LDPC			= BIT(19),
 	ATH9K_HW_CAP_FASTCLOCK			= BIT(20),
-};
-
-enum ath9k_capability_type {
-	ATH9K_CAP_CIPHER = 0,
-	ATH9K_CAP_TKIP_MIC,
-	ATH9K_CAP_TKIP_SPLIT,
-	ATH9K_CAP_TXPOW,
-	ATH9K_CAP_MCAST_KEYSRCH,
-	ATH9K_CAP_DS
+	ATH9K_HW_CAP_SGI_20			= BIT(21),
+	ATH9K_HW_CAP_PAPRD			= BIT(22),
 };
 
 struct ath9k_hw_capabilities {
@@ -237,8 +233,9 @@
 	int sw_beacon_response_time;
 	int additional_swba_backoff;
 	int ack_6mb;
-	int cwm_ignore_extcca;
+	u32 cwm_ignore_extcca;
 	u8 pcie_powersave_enable;
+	bool pcieSerDesWrite;
 	u8 pcie_clock_req;
 	u32 pcie_waen;
 	u8 analog_shiftreg;
@@ -262,10 +259,10 @@
 #define AR_BASE_FREQ_5GHZ   	4900
 #define AR_SPUR_FEEQ_BOUND_HT40 19
 #define AR_SPUR_FEEQ_BOUND_HT20 10
-	bool tx_iq_calibration; /* Only available for >= AR9003 */
 	int spurmode;
 	u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
 	u8 max_txtrig_level;
+	u16 ani_poll_interval; /* ANI poll interval in ms */
 };
 
 enum ath9k_int {
@@ -279,6 +276,7 @@
 	ATH9K_INT_TX = 0x00000040,
 	ATH9K_INT_TXDESC = 0x00000080,
 	ATH9K_INT_TIM_TIMER = 0x00000100,
+	ATH9K_INT_BB_WATCHDOG = 0x00000400,
 	ATH9K_INT_TXURN = 0x00000800,
 	ATH9K_INT_MIB = 0x00001000,
 	ATH9K_INT_RXPHY = 0x00004000,
@@ -358,6 +356,9 @@
 	int8_t iCoff;
 	int8_t qCoff;
 	int16_t rawNoiseFloor;
+	bool paprd_done;
+	u16 small_signal_gain[AR9300_MAX_CHAINS];
+	u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
 };
 
 #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
@@ -459,7 +460,7 @@
 #define AR_GENTMR_BIT(_index)	(1 << (_index))
 
 /*
- * Using de Bruijin sequence to to look up 1's index in a 32 bit number
+ * Using de Bruijin sequence to look up 1's index in a 32 bit number
  * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001
  */
 #define debruijn32 0x077CB531U
@@ -509,7 +510,17 @@
  *	AR_RTC_PLL_CONTROL for a given channel
  * @setup_calibration: set up calibration
  * @iscal_supported: used to query if a type of calibration is supported
- * @loadnf: load noise floor read from each chain on the CCA registers
+ *
+ * @ani_reset: reset ANI parameters to default values
+ * @ani_lower_immunity: lower the noise immunity level. The level controls
+ *	the power-based packet detection on hardware. If a power jump is
+ *	detected the adapter takes it as an indication that a packet has
+ *	arrived. The level ranges from 0-5. Each level corresponds to a
+ *	few dB more of noise immunity. If you have a strong time-varying
+ *	interference that is causing false detections (OFDM timing errors or
+ *	CCK timing errors) the level can be increased.
+ * @ani_cache_ini_regs: cache the values for ANI from the initial
+ *	register settings through the register initialization.
  */
 struct ath_hw_private_ops {
 	/* Calibration ops */
@@ -552,7 +563,11 @@
 	bool (*ani_control)(struct ath_hw *ah, enum ath9k_ani_cmd cmd,
 			    int param);
 	void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]);
-	void (*loadnf)(struct ath_hw *ah, struct ath9k_channel *chan);
+
+	/* ANI */
+	void (*ani_reset)(struct ath_hw *ah, bool is_scanning);
+	void (*ani_lower_immunity)(struct ath_hw *ah);
+	void (*ani_cache_ini_regs)(struct ath_hw *ah);
 };
 
 /**
@@ -563,6 +578,11 @@
  *
  * @config_pci_powersave:
  * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
+ *
+ * @ani_proc_mib_event: process MIB events, this would happen upon specific ANI
+ *	thresholds being reached or having overflowed.
+ * @ani_monitor: called periodically by the core driver to collect
+ *	MIB stats and adjust ANI if specific thresholds have been reached.
  */
 struct ath_hw_ops {
 	void (*config_pci_powersave)(struct ath_hw *ah,
@@ -603,6 +623,15 @@
 				     u32 burstDuration);
 	void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds,
 				       u32 vmf);
+
+	void (*ani_proc_mib_event)(struct ath_hw *ah);
+	void (*ani_monitor)(struct ath_hw *ah, struct ath9k_channel *chan);
+};
+
+struct ath_nf_limits {
+	s16 max;
+	s16 min;
+	s16 nominal;
 };
 
 struct ath_hw {
@@ -626,10 +655,10 @@
 	bool is_pciexpress;
 	bool need_an_top2_fixup;
 	u16 tx_trig_level;
-	s16 nf_2g_max;
-	s16 nf_2g_min;
-	s16 nf_5g_max;
-	s16 nf_5g_min;
+
+	u32 nf_regs[6];
+	struct ath_nf_limits nf_2g;
+	struct ath_nf_limits nf_5g;
 	u16 rfsilent;
 	u32 rfkill_gpio;
 	u32 rfkill_polarity;
@@ -789,6 +818,18 @@
 	u32 ts_paddr_end;
 	u16 ts_tail;
 	u8 ts_size;
+
+	u32 bb_watchdog_last_status;
+	u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */
+
+	u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES];
+	u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES];
+	/*
+	 * Store the permanent value of Reg 0x4004in WARegVal
+	 * so we dont have to R/M/W. We should not be reading
+	 * this register when in sleep states.
+	 */
+	u32 WARegVal;
 };
 
 static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
@@ -811,6 +852,12 @@
 	return &ah->ops;
 }
 
+static inline int sign_extend(int val, const int nbits)
+{
+	int order = BIT(nbits-1);
+	return (val ^ order) - order;
+}
+
 /* Initialization, Detach, Reset */
 const char *ath9k_hw_probe(u16 vendorid, u16 devid);
 void ath9k_hw_deinit(struct ath_hw *ah);
@@ -818,19 +865,13 @@
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 		   bool bChannelChange);
 int ath9k_hw_fill_cap_info(struct ath_hw *ah);
-bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
-			    u32 capability, u32 *result);
-bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
-			    u32 capability, u32 setting, int *status);
 u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan);
 
 /* Key Cache Management */
 bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry);
-bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac);
 bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
 				 const struct ath9k_keyval *k,
 				 const u8 *mac);
-bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry);
 
 /* GPIO / RFKILL / Antennae */
 void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio);
@@ -856,7 +897,6 @@
 bool ath9k_hw_phy_disable(struct ath_hw *ah);
 bool ath9k_hw_disable(struct ath_hw *ah);
 void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit);
-void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac);
 void ath9k_hw_setopmode(struct ath_hw *ah);
 void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
 void ath9k_hw_setbssidmask(struct ath_hw *ah);
@@ -865,7 +905,6 @@
 void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
 void ath9k_hw_reset_tsf(struct ath_hw *ah);
 void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
-u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp);
 void ath9k_hw_init_global_settings(struct ath_hw *ah);
 void ath9k_hw_set11nmac2040(struct ath_hw *ah);
 void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
@@ -907,13 +946,25 @@
 void ar9002_hw_cck_chan14_spread(struct ath_hw *ah);
 int ar9002_hw_rf_claim(struct ath_hw *ah);
 void ar9002_hw_enable_async_fifo(struct ath_hw *ah);
+void ar9002_hw_update_async_fifo(struct ath_hw *ah);
 void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah);
 
 /*
- * Code specifric to AR9003, we stuff these here to avoid callbacks
+ * Code specific to AR9003, we stuff these here to avoid callbacks
  * for older families
  */
-void ar9003_hw_set_nf_limits(struct ath_hw *ah);
+void ar9003_hw_bb_watchdog_config(struct ath_hw *ah);
+void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
+void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);
+void ar9003_paprd_enable(struct ath_hw *ah, bool val);
+void ar9003_paprd_populate_single_table(struct ath_hw *ah,
+					struct ath9k_channel *chan, int chain);
+int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_channel *chan,
+			      int chain);
+int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain);
+int ar9003_paprd_init_table(struct ath_hw *ah);
+bool ar9003_paprd_is_done(struct ath_hw *ah);
+void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains);
 
 /* Hardware family op attach helpers */
 void ar5008_hw_attach_phy_ops(struct ath_hw *ah);
@@ -926,8 +977,24 @@
 void ar9002_hw_attach_ops(struct ath_hw *ah);
 void ar9003_hw_attach_ops(struct ath_hw *ah);
 
+/*
+ * ANI work can be shared between all families but a next
+ * generation implementation of ANI will be used only for AR9003 only
+ * for now as the other families still need to be tested with the same
+ * next generation ANI. Feel free to start testing it though for the
+ * older families (AR5008, AR9001, AR9002) by using modparam_force_new_ani.
+ */
+extern int modparam_force_new_ani;
+void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah);
+void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah);
+
 #define ATH_PCIE_CAP_LINK_CTRL	0x70
 #define ATH_PCIE_CAP_LINK_L0S	1
 #define ATH_PCIE_CAP_LINK_L1	2
 
+#define ATH9K_CLOCK_RATE_CCK		22
+#define ATH9K_CLOCK_RATE_5GHZ_OFDM	40
+#define ATH9K_CLOCK_RATE_2GHZ_OFDM	44
+#define ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM 44
+
 #endif
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index d457cb3..243c177 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -33,6 +33,10 @@
 module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
 
+int led_blink = 1;
+module_param_named(blink, led_blink, int, 0444);
+MODULE_PARM_DESC(blink, "Enable LED blink on activity");
+
 /* We use the hw_value as an index into our private channel structure */
 
 #define CHAN2G(_freq, _idx)  { \
@@ -175,18 +179,6 @@
 	.write = ath9k_iowrite32,
 };
 
-static int count_streams(unsigned int chainmask, int max)
-{
-	int streams = 0;
-
-	do {
-		if (++streams == max)
-			break;
-	} while ((chainmask = chainmask & (chainmask - 1)));
-
-	return streams;
-}
-
 /**************************/
 /*     Initialization     */
 /**************************/
@@ -208,6 +200,9 @@
 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC)
 		ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
 
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+		ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+
 	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
 	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
 
@@ -224,8 +219,8 @@
 
 	/* set up supported mcs set */
 	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
-	tx_streams = count_streams(common->tx_chainmask, max_streams);
-	rx_streams = count_streams(common->rx_chainmask, max_streams);
+	tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, max_streams);
+	rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, max_streams);
 
 	ath_print(common, ATH_DBG_CONFIG,
 		  "TX streams %d, RX streams: %d\n",
@@ -388,36 +383,14 @@
 	for (i = 0; i < common->keymax; i++)
 		ath9k_hw_keyreset(sc->sc_ah, (u16) i);
 
-	if (ath9k_hw_getcapability(sc->sc_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(sc->sc_ah, ATH9K_CAP_CIPHER,
-				   ATH9K_CIPHER_TKIP, NULL)
-	    && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER,
-				      ATH9K_CIPHER_MIC, NULL)
-	    && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_TKIP_SPLIT,
-				      0, NULL))
+	if (!(sc->sc_ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA))
 		common->splitmic = 1;
-
-	/* turn on mcast key search if possible */
-	if (!ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
-		(void)ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH,
-					     1, 1, NULL);
-
 }
 
 static int ath9k_init_btcoex(struct ath_softc *sc)
@@ -435,7 +408,7 @@
 		r = ath_init_btcoex_timer(sc);
 		if (r)
 			return -1;
-		qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
+		qnum = sc->tx.hwq_map[WME_AC_BE];
 		ath9k_hw_init_btcoex_hw(sc->sc_ah, qnum);
 		sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
 		break;
@@ -472,23 +445,23 @@
 	sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
 	ath_cabq_update(sc);
 
-	if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
+	if (!ath_tx_setup(sc, WME_AC_BK)) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to setup xmit queue for BK traffic\n");
 		goto err;
 	}
 
-	if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
+	if (!ath_tx_setup(sc, WME_AC_BE)) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to setup xmit queue for BE traffic\n");
 		goto err;
 	}
-	if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
+	if (!ath_tx_setup(sc, WME_AC_VI)) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to setup xmit queue for VI traffic\n");
 		goto err;
 	}
-	if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
+	if (!ath_tx_setup(sc, WME_AC_VO)) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to setup xmit queue for VO traffic\n");
 		goto err;
@@ -745,6 +718,8 @@
 			goto error_world;
 	}
 
+	INIT_WORK(&sc->hw_check_work, ath_hw_check);
+	INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
 	INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
 	INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
 	sc->wiphy_scheduler_int = msecs_to_jiffies(500);
@@ -812,12 +787,12 @@
 		ieee80211_unregister_hw(aphy->hw);
 		ieee80211_free_hw(aphy->hw);
 	}
-	kfree(sc->sec_wiphy);
 
 	ieee80211_unregister_hw(hw);
 	ath_rx_cleanup(sc);
 	ath_tx_cleanup(sc);
 	ath9k_deinit_softc(sc);
+	kfree(sc->sec_wiphy);
 }
 
 void ath_descdma_cleanup(struct ath_softc *sc,
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 0e425cb..e955bb9 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -15,6 +15,7 @@
  */
 
 #include "hw.h"
+#include "hw-ops.h"
 
 static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
 					struct ath9k_tx_queue_info *qi)
@@ -554,8 +555,13 @@
 		REGWRITE_BUFFER_FLUSH(ah);
 		DISABLE_REGWRITE_BUFFER(ah);
 
-		/* cwmin and cwmax should be 0 for beacon queue */
-		if (AR_SREV_9300_20_OR_LATER(ah)) {
+		/*
+		 * cwmin and cwmax should be 0 for beacon queue
+		 * but not for IBSS as we would create an imbalance
+		 * on beaconing fairness for participating nodes.
+		 */
+		if (AR_SREV_9300_20_OR_LATER(ah) &&
+		    ah->opmode != NL80211_IFTYPE_ADHOC) {
 			REG_WRITE(ah, AR_DLCL_IFS(q), SM(0, AR_D_LCL_IFS_CWMIN)
 				  | SM(0, AR_D_LCL_IFS_CWMAX)
 				  | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
@@ -756,11 +762,11 @@
 }
 EXPORT_SYMBOL(ath9k_hw_putrxbuf);
 
-void ath9k_hw_startpcureceive(struct ath_hw *ah)
+void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning)
 {
 	ath9k_enable_mib_counters(ah);
 
-	ath9k_ani_reset(ah);
+	ath9k_ani_reset(ah, is_scanning);
 
 	REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
 }
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 00f3e0c..2633896 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -485,6 +485,9 @@
 #define AR_TxRSSICombined   0xff000000
 #define AR_TxRSSICombined_S 24
 
+#define AR_TxTid	0xf0000000
+#define AR_TxTid_S	28
+
 #define AR_TxEVM0           ds_txstatus5
 #define AR_TxEVM1           ds_txstatus6
 #define AR_TxEVM2           ds_txstatus7
@@ -577,13 +580,8 @@
 
 #define	ATH9K_NUM_TX_QUEUES 10
 
-enum ath9k_tx_queue_subtype {
-	ATH9K_WME_AC_BK = 0,
-	ATH9K_WME_AC_BE,
-	ATH9K_WME_AC_VI,
-	ATH9K_WME_AC_VO,
-	ATH9K_WME_UPSD
-};
+/* Used as a queue subtype instead of a WMM AC */
+#define ATH9K_WME_UPSD	4
 
 enum ath9k_tx_queue_flags {
 	TXQ_FLAG_TXOKINT_ENABLE = 0x0001,
@@ -617,7 +615,7 @@
 struct ath9k_tx_queue_info {
 	u32 tqi_ver;
 	enum ath9k_tx_queue tqi_type;
-	enum ath9k_tx_queue_subtype tqi_subtype;
+	int tqi_subtype;
 	enum ath9k_tx_queue_flags tqi_qflags;
 	u32 tqi_priority;
 	u32 tqi_aifs;
@@ -715,7 +713,7 @@
 			  u32 size, u32 flags);
 bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
 void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp);
-void ath9k_hw_startpcureceive(struct ath_hw *ah);
+void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning);
 void ath9k_hw_stoppcurecv(struct ath_hw *ah);
 void ath9k_hw_abortpcurecv(struct ath_hw *ah);
 bool ath9k_hw_stopdmarecv(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 1e2a68e..0429dda 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -51,13 +51,11 @@
 static void ath_update_txpow(struct ath_softc *sc)
 {
 	struct ath_hw *ah = sc->sc_ah;
-	u32 txpow;
 
 	if (sc->curtxpow != sc->config.txpowlimit) {
 		ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit);
 		/* read back in case value is clamped */
-		ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
-		sc->curtxpow = txpow;
+		sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
 	}
 }
 
@@ -232,6 +230,114 @@
 	return r;
 }
 
+static void ath_paprd_activate(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	int chain;
+
+	if (!ah->curchan->paprd_done)
+		return;
+
+	ath9k_ps_wakeup(sc);
+	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+		if (!(ah->caps.tx_chainmask & BIT(chain)))
+			continue;
+
+		ar9003_paprd_populate_single_table(ah, ah->curchan, chain);
+	}
+
+	ar9003_paprd_enable(ah, true);
+	ath9k_ps_restore(sc);
+}
+
+void ath_paprd_calibrate(struct work_struct *work)
+{
+	struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
+	struct ieee80211_hw *hw = sc->hw;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ieee80211_hdr *hdr;
+	struct sk_buff *skb = NULL;
+	struct ieee80211_tx_info *tx_info;
+	int band = hw->conf.channel->band;
+	struct ieee80211_supported_band *sband = &sc->sbands[band];
+	struct ath_tx_control txctl;
+	int qnum, ftype;
+	int chain_ok = 0;
+	int chain;
+	int len = 1800;
+	int time_left;
+	int i;
+
+	skb = alloc_skb(len, GFP_KERNEL);
+	if (!skb)
+		return;
+
+	tx_info = IEEE80211_SKB_CB(skb);
+
+	skb_put(skb, len);
+	memset(skb->data, 0, len);
+	hdr = (struct ieee80211_hdr *)skb->data;
+	ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC;
+	hdr->frame_control = cpu_to_le16(ftype);
+	hdr->duration_id = cpu_to_le16(10);
+	memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
+	memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
+	memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
+
+	memset(&txctl, 0, sizeof(txctl));
+	qnum = sc->tx.hwq_map[WME_AC_BE];
+	txctl.txq = &sc->tx.txq[qnum];
+
+	ath9k_ps_wakeup(sc);
+	ar9003_paprd_init_table(ah);
+	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+		if (!(ah->caps.tx_chainmask & BIT(chain)))
+			continue;
+
+		chain_ok = 0;
+		memset(tx_info, 0, sizeof(*tx_info));
+		tx_info->band = band;
+
+		for (i = 0; i < 4; i++) {
+			tx_info->control.rates[i].idx = sband->n_bitrates - 1;
+			tx_info->control.rates[i].count = 6;
+		}
+
+		init_completion(&sc->paprd_complete);
+		ar9003_paprd_setup_gain_table(ah, chain);
+		txctl.paprd = BIT(chain);
+		if (ath_tx_start(hw, skb, &txctl) != 0)
+			break;
+
+		time_left = wait_for_completion_timeout(&sc->paprd_complete,
+				msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
+		if (!time_left) {
+			ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+				  "Timeout waiting for paprd training on "
+				  "TX chain %d\n",
+				  chain);
+			goto fail_paprd;
+		}
+
+		if (!ar9003_paprd_is_done(ah))
+			break;
+
+		if (ar9003_paprd_create_curve(ah, ah->curchan, chain) != 0)
+			break;
+
+		chain_ok = 1;
+	}
+	kfree_skb(skb);
+
+	if (chain_ok) {
+		ah->curchan->paprd_done = true;
+		ath_paprd_activate(sc);
+	}
+
+fail_paprd:
+	ath9k_ps_restore(sc);
+}
+
 /*
  *  This routine performs the periodic noise floor calibration function
  *  that is used to adjust and optimize the chip performance.  This
@@ -285,7 +391,8 @@
 	}
 
 	/* Verify whether we must check ANI */
-	if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
+	if ((timestamp - common->ani.checkani_timer) >=
+	     ah->config.ani_poll_interval) {
 		aniflag = true;
 		common->ani.checkani_timer = timestamp;
 	}
@@ -326,15 +433,24 @@
 	*/
 	cal_interval = ATH_LONG_CALINTERVAL;
 	if (sc->sc_ah->config.enable_ani)
-		cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
+		cal_interval = min(cal_interval,
+				   (u32)ah->config.ani_poll_interval);
 	if (!common->ani.caldone)
 		cal_interval = min(cal_interval, (u32)short_cal_interval);
 
 	mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
+	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) &&
+	    !(sc->sc_flags & SC_OP_SCANNING)) {
+		if (!sc->sc_ah->curchan->paprd_done)
+			ieee80211_queue_work(sc->hw, &sc->paprd_work);
+		else
+			ath_paprd_activate(sc);
+	}
 }
 
 static void ath_start_ani(struct ath_common *common)
 {
+	struct ath_hw *ah = common->ah;
 	unsigned long timestamp = jiffies_to_msecs(jiffies);
 	struct ath_softc *sc = (struct ath_softc *) common->priv;
 
@@ -346,7 +462,8 @@
 	common->ani.checkani_timer = timestamp;
 
 	mod_timer(&common->ani.timer,
-		  jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
+		  jiffies +
+			msecs_to_jiffies((u32)ah->config.ani_poll_interval));
 }
 
 /*
@@ -398,6 +515,25 @@
 		ath_tx_node_cleanup(sc, an);
 }
 
+void ath_hw_check(struct work_struct *work)
+{
+	struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
+	int i;
+
+	ath9k_ps_wakeup(sc);
+
+	for (i = 0; i < 3; i++) {
+		if (ath9k_hw_check_alive(sc->sc_ah))
+			goto out;
+
+		msleep(1);
+	}
+	ath_reset(sc, false);
+
+out:
+	ath9k_ps_restore(sc);
+}
+
 void ath9k_tasklet(unsigned long data)
 {
 	struct ath_softc *sc = (struct ath_softc *)data;
@@ -409,13 +545,15 @@
 
 	ath9k_ps_wakeup(sc);
 
-	if ((status & ATH9K_INT_FATAL) ||
-	    !ath9k_hw_check_alive(ah)) {
+	if (status & ATH9K_INT_FATAL) {
 		ath_reset(sc, false);
 		ath9k_ps_restore(sc);
 		return;
 	}
 
+	if (!ath9k_hw_check_alive(ah))
+		ieee80211_queue_work(sc->hw, &sc->hw_check_work);
+
 	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
 		rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
 			  ATH9K_INT_RXORN);
@@ -524,6 +662,12 @@
 	    !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)))
 		goto chip_reset;
 
+	if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
+	    (status & ATH9K_INT_BB_WATCHDOG)) {
+		ar9003_hw_bb_watchdog_dbg_info(ah);
+		goto chip_reset;
+	}
+
 	if (status & ATH9K_INT_SWBA)
 		tasklet_schedule(&sc->bcon_tasklet);
 
@@ -619,234 +763,6 @@
 	return chanmode;
 }
 
-static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,
-			   struct ath9k_keyval *hk, const u8 *addr,
-			   bool authenticator)
-{
-	struct ath_hw *ah = common->ah;
-	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 - only two key cache entries are used
-		 * regardless of splitmic capability since group key is only
-		 * used either for TX or RX.
-		 */
-		if (authenticator) {
-			memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
-			memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));
-		} else {
-			memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
-			memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
-		}
-		return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
-	}
-	if (!common->splitmic) {
-		/* TX and RX keys share the same key cache entry. */
-		memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
-		memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
-		return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
-	}
-
-	/* Separate key cache entries for TX and RX */
-
-	/* TX key goes at first index, RX key at +32. */
-	memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
-	if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) {
-		/* TX MIC entry failed. No need to proceed further */
-		ath_print(common, ATH_DBG_FATAL,
-			  "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 ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr);
-}
-
-static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
-{
-	int i;
-
-	for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
-		if (test_bit(i, common->keymap) ||
-		    test_bit(i + 64, common->keymap))
-			continue; /* At least one part of TKIP key allocated */
-		if (common->splitmic &&
-		    (test_bit(i + 32, common->keymap) ||
-		     test_bit(i + 64 + 32, common->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_common *common)
-{
-	int i;
-
-	/* First, try to find slots that would not be available for TKIP. */
-	if (common->splitmic) {
-		for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
-			if (!test_bit(i, common->keymap) &&
-			    (test_bit(i + 32, common->keymap) ||
-			     test_bit(i + 64, common->keymap) ||
-			     test_bit(i + 64 + 32, common->keymap)))
-				return i;
-			if (!test_bit(i + 32, common->keymap) &&
-			    (test_bit(i, common->keymap) ||
-			     test_bit(i + 64, common->keymap) ||
-			     test_bit(i + 64 + 32, common->keymap)))
-				return i + 32;
-			if (!test_bit(i + 64, common->keymap) &&
-			    (test_bit(i , common->keymap) ||
-			     test_bit(i + 32, common->keymap) ||
-			     test_bit(i + 64 + 32, common->keymap)))
-				return i + 64;
-			if (!test_bit(i + 64 + 32, common->keymap) &&
-			    (test_bit(i, common->keymap) ||
-			     test_bit(i + 32, common->keymap) ||
-			     test_bit(i + 64, common->keymap)))
-				return i + 64 + 32;
-		}
-	} else {
-		for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
-			if (!test_bit(i, common->keymap) &&
-			    test_bit(i + 64, common->keymap))
-				return i;
-			if (test_bit(i, common->keymap) &&
-			    !test_bit(i + 64, common->keymap))
-				return i + 64;
-		}
-	}
-
-	/* No partially used TKIP slots, pick any available slot */
-	for (i = IEEE80211_WEP_NKID; i < common->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 (common->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, common->keymap))
-			return i; /* Found a free slot for a key */
-	}
-
-	/* No free slot found */
-	return -1;
-}
-
-static int ath_key_config(struct ath_common *common,
-			  struct ieee80211_vif *vif,
-			  struct ieee80211_sta *sta,
-			  struct ieee80211_key_conf *key)
-{
-	struct ath_hw *ah = common->ah;
-	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 -EOPNOTSUPP;
-	}
-
-	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) {
-		if (WARN_ON(!sta))
-			return -EOPNOTSUPP;
-		mac = sta->addr;
-
-		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 {
-		if (WARN_ON(!sta))
-			return -EOPNOTSUPP;
-		mac = sta->addr;
-
-		if (key->alg == ALG_TKIP)
-			idx = ath_reserve_key_cache_slot_tkip(common);
-		else
-			idx = ath_reserve_key_cache_slot(common);
-		if (idx < 0)
-			return -ENOSPC; /* no free key cache entries */
-	}
-
-	if (key->alg == ALG_TKIP)
-		ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
-				      vif->type == NL80211_IFTYPE_AP);
-	else
-		ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac);
-
-	if (!ret)
-		return -EIO;
-
-	set_bit(idx, common->keymap);
-	if (key->alg == ALG_TKIP) {
-		set_bit(idx + 64, common->keymap);
-		if (common->splitmic) {
-			set_bit(idx + 32, common->keymap);
-			set_bit(idx + 64 + 32, common->keymap);
-		}
-	}
-
-	return idx;
-}
-
-static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key)
-{
-	struct ath_hw *ah = common->ah;
-
-	ath9k_hw_keyreset(ah, key->hw_key_idx);
-	if (key->hw_key_idx < IEEE80211_WEP_NKID)
-		return;
-
-	clear_bit(key->hw_key_idx, common->keymap);
-	if (key->alg != ALG_TKIP)
-		return;
-
-	clear_bit(key->hw_key_idx + 64, common->keymap);
-	if (common->splitmic) {
-		ath9k_hw_keyreset(ah, key->hw_key_idx + 32);
-		clear_bit(key->hw_key_idx + 32, common->keymap);
-		clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
-	}
-}
-
 static void ath9k_bss_assoc_info(struct ath_softc *sc,
 				 struct ieee80211_vif *vif,
 				 struct ieee80211_bss_conf *bss_conf)
@@ -941,9 +857,14 @@
 	ath9k_ps_wakeup(sc);
 	ieee80211_stop_queues(hw);
 
-	/* Disable LED */
-	ath9k_hw_set_gpio(ah, ah->led_pin, 1);
-	ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
+	/*
+	 * Keep the LED on when the radio is disabled
+	 * during idle unassociated state.
+	 */
+	if (!sc->ps_idle) {
+		ath9k_hw_set_gpio(ah, ah->led_pin, 1);
+		ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
+	}
 
 	/* Disable interrupts */
 	ath9k_hw_set_interrupts(ah, 0);
@@ -1032,25 +953,25 @@
 	return r;
 }
 
-int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
+static 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];
+		qnum = sc->tx.hwq_map[WME_AC_VO];
 		break;
 	case 1:
-		qnum = sc->tx.hwq_map[ATH9K_WME_AC_VI];
+		qnum = sc->tx.hwq_map[WME_AC_VI];
 		break;
 	case 2:
-		qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE];
+		qnum = sc->tx.hwq_map[WME_AC_BE];
 		break;
 	case 3:
-		qnum = sc->tx.hwq_map[ATH9K_WME_AC_BK];
+		qnum = sc->tx.hwq_map[WME_AC_BK];
 		break;
 	default:
-		qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE];
+		qnum = sc->tx.hwq_map[WME_AC_BE];
 		break;
 	}
 
@@ -1062,16 +983,16 @@
 	int qnum;
 
 	switch (queue) {
-	case ATH9K_WME_AC_VO:
+	case WME_AC_VO:
 		qnum = 0;
 		break;
-	case ATH9K_WME_AC_VI:
+	case WME_AC_VI:
 		qnum = 1;
 		break;
-	case ATH9K_WME_AC_BE:
+	case WME_AC_BE:
 		qnum = 2;
 		break;
-	case ATH9K_WME_AC_BK:
+	case WME_AC_BK:
 		qnum = 3;
 		break;
 	default:
@@ -1201,7 +1122,9 @@
 		    ATH9K_INT_GLOBAL;
 
 	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
-		ah->imask |= ATH9K_INT_RXHP | ATH9K_INT_RXLP;
+		ah->imask |= ATH9K_INT_RXHP |
+			     ATH9K_INT_RXLP |
+			     ATH9K_INT_BB_WATCHDOG;
 	else
 		ah->imask |= ATH9K_INT_RX;
 
@@ -1251,6 +1174,7 @@
 	struct ath_tx_control txctl;
 	int padpos, padsize;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	int qnum;
 
 	if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
 		ath_print(common, ATH_DBG_XMIT,
@@ -1280,7 +1204,8 @@
 		 * completed and if needed, also for RX of buffered frames.
 		 */
 		ath9k_ps_wakeup(sc);
-		ath9k_hw_setrxabort(sc->sc_ah, 0);
+		if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+			ath9k_hw_setrxabort(sc->sc_ah, 0);
 		if (ieee80211_is_pspoll(hdr->frame_control)) {
 			ath_print(common, ATH_DBG_PS,
 				  "Sending PS-Poll to pick a buffered frame\n");
@@ -1322,11 +1247,8 @@
 		memmove(skb->data, skb->data + padsize, padpos);
 	}
 
-	/* Check if a tx queue is available */
-
-	txctl.txq = ath_test_get_txq(sc, skb);
-	if (!txctl.txq)
-		goto exit;
+	qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
+	txctl.txq = &sc->tx.txq[qnum];
 
 	ath_print(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
 
@@ -1347,15 +1269,25 @@
 	struct ath_softc *sc = aphy->sc;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
+	int i;
 
 	mutex_lock(&sc->mutex);
 
 	aphy->state = ATH_WIPHY_INACTIVE;
 
-	cancel_delayed_work_sync(&sc->ath_led_blink_work);
-	cancel_delayed_work_sync(&sc->tx_complete_work);
+	if (led_blink)
+		cancel_delayed_work_sync(&sc->ath_led_blink_work);
 
-	if (!sc->num_sec_wiphy) {
+	cancel_delayed_work_sync(&sc->tx_complete_work);
+	cancel_work_sync(&sc->paprd_work);
+	cancel_work_sync(&sc->hw_check_work);
+
+	for (i = 0; i < sc->num_sec_wiphy; i++) {
+		if (sc->sec_wiphy[i])
+			break;
+	}
+
+	if (i == sc->num_sec_wiphy) {
 		cancel_delayed_work_sync(&sc->wiphy_work);
 		cancel_work_sync(&sc->chan_work);
 	}
@@ -1547,8 +1479,8 @@
 			ah->imask |= ATH9K_INT_TIM_TIMER;
 			ath9k_hw_set_interrupts(ah, ah->imask);
 		}
+		ath9k_hw_setrxabort(ah, 1);
 	}
-	ath9k_hw_setrxabort(ah, 1);
 }
 
 static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
@@ -1785,7 +1717,7 @@
 		ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
 
 	if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)
-		if ((qnum == sc->tx.hwq_map[ATH9K_WME_AC_BE]) && !ret)
+		if ((qnum == sc->tx.hwq_map[WME_AC_BE]) && !ret)
 			ath_beaconq_config(sc);
 
 	mutex_unlock(&sc->mutex);
@@ -1813,7 +1745,7 @@
 
 	switch (cmd) {
 	case SET_KEY:
-		ret = ath_key_config(common, vif, sta, key);
+		ret = ath9k_cmn_key_config(common, vif, sta, key);
 		if (ret >= 0) {
 			key->hw_key_idx = ret;
 			/* push IV and Michael MIC generation to stack */
@@ -1826,7 +1758,7 @@
 		}
 		break;
 	case DISABLE_KEY:
-		ath_key_delete(common, key);
+		ath9k_cmn_key_delete(common, key);
 		break;
 	default:
 		ret = -EINVAL;
@@ -1999,6 +1931,8 @@
 	struct ath_softc *sc = aphy->sc;
 	int ret = 0;
 
+	local_bh_disable();
+
 	switch (action) {
 	case IEEE80211_AMPDU_RX_START:
 		if (!(sc->sc_flags & SC_OP_RXAGGR))
@@ -2028,6 +1962,8 @@
 			  "Unknown AMPDU action\n");
 	}
 
+	local_bh_enable();
+
 	return ret;
 }
 
@@ -2058,11 +1994,12 @@
 
 	mutex_lock(&sc->mutex);
 	if (ath9k_wiphy_scanning(sc)) {
-		printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the "
-		       "same time\n");
 		/*
-		 * Do not allow the concurrent scanning state for now. This
-		 * could be improved with scanning control moved into ath9k.
+		 * There is a race here in mac80211 but fixing it requires
+		 * we revisit how we handle the scan complete callback.
+		 * After mac80211 fixes we will not have configured hardware
+		 * to the home channel nor would we have configured the RX
+		 * filter yet.
 		 */
 		mutex_unlock(&sc->mutex);
 		return;
@@ -2072,10 +2009,16 @@
 	ath9k_wiphy_pause_all_forced(sc, aphy);
 	sc->sc_flags |= SC_OP_SCANNING;
 	del_timer_sync(&common->ani.timer);
+	cancel_work_sync(&sc->paprd_work);
+	cancel_work_sync(&sc->hw_check_work);
 	cancel_delayed_work_sync(&sc->tx_complete_work);
 	mutex_unlock(&sc->mutex);
 }
 
+/*
+ * XXX: this requires a revisit after the driver
+ * scan_complete gets moved to another place/removed in mac80211.
+ */
 static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
 {
 	struct ath_wiphy *aphy = hw->priv;
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 1ec836c..b5b6514 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -28,6 +28,7 @@
 	{ PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
 	{ PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI   */
 	{ PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
+	{ PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E  AR9300 */
 	{ 0 }
 };
 
@@ -208,11 +209,8 @@
 	}
 
 	ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name));
-	printk(KERN_INFO
-	       "%s: %s mem=0x%lx, irq=%d\n",
-	       wiphy_name(hw->wiphy),
-	       hw_name,
-	       (unsigned long)mem, pdev->irq);
+	wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
+		   hw_name, (unsigned long)mem, pdev->irq);
 
 	return 0;
 
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 8519452..e49be73 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -20,93 +20,145 @@
 #include "ath9k.h"
 
 static const struct ath_rate_table ar5416_11na_ratetable = {
-	42,
+	68,
 	8, /* MCS start */
 	{
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
-			5400, 0, 12, 0, 0, 0, 0, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
-			7800,  1, 18, 0, 1, 1, 1, 1 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
-			10000, 2, 24, 2, 2, 2, 2, 2 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
-			13900, 3, 36, 2, 3, 3, 3, 3 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
-			17300, 4, 48, 4, 4, 4, 4, 4 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
-			23000, 5, 72, 4, 5, 5, 5, 5 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
-			27400, 6, 96, 4, 6, 6, 6, 6 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
-			29300, 7, 108, 4, 7, 7, 7, 7 },
-		{ VALID_2040, VALID_2040, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
-			6400, 0, 0, 0, 8, 24, 8, 24 },
-		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
-			12700, 1, 1, 2, 9, 25, 9, 25 },
-		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
-			18800, 2, 2, 2, 10, 26, 10, 26 },
-		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
-			25000, 3, 3, 4, 11, 27, 11, 27 },
-		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
-			36700, 4, 4, 4, 12, 28, 12, 28 },
-		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
-			48100, 5, 5, 4, 13, 29, 13, 29 },
-		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
-			53500, 6, 6, 4, 14, 30, 14, 30 },
-		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
-			59000, 7, 7, 4, 15, 31, 15, 32 },
-		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
-			12700, 8, 8, 3, 16, 33, 16, 33 },
-		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
-			24800, 9, 9, 2, 17, 34, 17, 34 },
-		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
-			36600, 10, 10, 2, 18, 35, 18, 35 },
-		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
-			48100, 11, 11, 4, 19, 36, 19, 36 },
-		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
-			69500, 12, 12, 4, 20, 37, 20, 37 },
-		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
-			89500, 13, 13, 4, 21, 38, 21, 38 },
-		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
-			98900, 14, 14, 4, 22, 39, 22, 39 },
-		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
-			108300, 15, 15, 4, 23, 40, 23, 41 },
-		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
-			13200, 0, 0, 0, 8, 24, 24, 24 },
-		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
-			25900, 1, 1, 2, 9, 25, 25, 25 },
-		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
-			38600, 2, 2, 2, 10, 26, 26, 26 },
-		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
-			49800, 3, 3, 4, 11, 27, 27, 27 },
-		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
-			72200, 4, 4, 4, 12, 28, 28, 28 },
-		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
-			92900, 5, 5, 4, 13, 29, 29, 29 },
-		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
-			102700, 6, 6, 4, 14, 30, 30, 30 },
-		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
-			112000, 7, 7, 4, 15, 31, 32, 32 },
-		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
-			122000, 7, 7, 4, 15, 31, 32, 32 },
-		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
-			25800, 8, 8, 0, 16, 33, 33, 33 },
-		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
-			49800, 9, 9, 2, 17, 34, 34, 34 },
-		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
-			71900, 10, 10, 2, 18, 35, 35, 35 },
-		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
-			92500, 11, 11, 4, 19, 36, 36, 36 },
-		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
-			130300, 12, 12, 4, 20, 37, 37, 37 },
-		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
-			162800, 13, 13, 4, 21, 38, 38, 38 },
-		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
-			178200, 14, 14, 4, 22, 39, 39, 39 },
-		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
-			192100, 15, 15, 4, 23, 40, 41, 41 },
-		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
-			207000, 15, 15, 4, 23, 40, 41, 41 },
+		[0] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000,
+			5400, 0, 12, 0, 0, 0, 0 }, /* 6 Mb */
+		[1] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000,
+			7800,  1, 18, 0, 1, 1, 1 }, /* 9 Mb */
+		[2] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000,
+			10000, 2, 24, 2, 2, 2, 2 }, /* 12 Mb */
+		[3] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000,
+			13900, 3, 36, 2, 3, 3, 3 }, /* 18 Mb */
+		[4] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000,
+			17300, 4, 48, 4, 4, 4, 4 }, /* 24 Mb */
+		[5] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000,
+			23000, 5, 72, 4, 5, 5, 5 }, /* 36 Mb */
+		[6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000,
+			27400, 6, 96, 4, 6, 6, 6 }, /* 48 Mb */
+		[7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000,
+			29300, 7, 108, 4, 7, 7, 7 }, /* 54 Mb */
+		[8] = { RC_HT_SDT_2040, WLAN_RC_PHY_HT_20_SS, 6500,
+			6400, 0, 0, 0, 38, 8, 38 }, /* 6.5 Mb */
+		[9] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000,
+			12700, 1, 1, 2, 39, 9, 39 }, /* 13 Mb */
+		[10] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500,
+			18800, 2, 2, 2, 40, 10, 40 }, /* 19.5 Mb */
+		[11] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000,
+			25000, 3, 3, 4, 41, 11, 41 }, /* 26 Mb */
+		[12] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000,
+			36700, 4, 4, 4, 42, 12, 42 }, /* 39 Mb */
+		[13] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000,
+			48100, 5, 5, 4, 43, 13, 43 }, /* 52 Mb */
+		[14] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500,
+			53500, 6, 6, 4, 44, 14, 44 }, /* 58.5 Mb */
+		[15] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000,
+			59000, 7, 7, 4, 45, 16, 46 }, /* 65 Mb */
+		[16] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200,
+			65400, 7, 7, 4, 45, 16, 46 }, /* 75 Mb */
+		[17] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000,
+			12700, 8, 8, 0, 47, 17, 47 }, /* 13 Mb */
+		[18] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000,
+			24800, 9, 9, 2, 48, 18, 48 }, /* 26 Mb */
+		[19] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000,
+			36600, 10, 10, 2, 49, 19, 49 }, /* 39 Mb */
+		[20] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000,
+			48100, 11, 11, 4, 50, 20, 50 }, /* 52 Mb */
+		[21] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000,
+			69500, 12, 12, 4, 51, 21, 51 }, /* 78 Mb */
+		[22] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000,
+			89500, 13, 13, 4, 52, 22, 52 }, /* 104 Mb */
+		[23] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000,
+			98900, 14, 14, 4, 53, 23, 53 }, /* 117 Mb */
+		[24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000,
+			108300, 15, 15, 4, 54, 25, 55 }, /* 130 Mb */
+		[25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400,
+			120000, 15, 15, 4, 54, 25, 55 }, /* 144.4 Mb */
+		[26] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500,
+			17400, 16, 16, 0, 56, 26, 56 }, /* 19.5 Mb */
+		[27] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000,
+			35100, 17, 17, 2, 57, 27, 57 }, /* 39 Mb */
+		[28] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500,
+			52600, 18, 18, 2, 58, 28, 58 }, /* 58.5 Mb */
+		[29] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000,
+			70400, 19, 19, 4, 59, 29, 59 }, /* 78 Mb */
+		[30] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000,
+			104900, 20, 20, 4, 60, 31, 61 }, /* 117 Mb */
+		[31] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000,
+			115800, 20, 20, 4, 60, 31, 61 }, /* 130 Mb*/
+		[32] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000,
+			137200, 21, 21, 4, 62, 33, 63 }, /* 156 Mb */
+		[33] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300,
+			151100, 21, 21, 4, 62, 33, 63 }, /* 173.3 Mb */
+		[34] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500,
+			152800, 22, 22, 4, 64, 35, 65 }, /* 175.5 Mb */
+		[35] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000,
+			168400, 22, 22, 4, 64, 35, 65 }, /* 195 Mb*/
+		[36] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000,
+			168400, 23, 23, 4, 66, 37, 67 }, /* 195 Mb */
+		[37] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700,
+			185000, 23, 23, 4, 66, 37, 67 }, /* 216.7 Mb */
+		[38] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500,
+			13200, 0, 0, 0, 38, 38, 38 }, /* 13.5 Mb*/
+		[39] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500,
+			25900, 1, 1, 2, 39, 39, 39 }, /* 27.0 Mb*/
+		[40] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500,
+			38600, 2, 2, 2, 40, 40, 40 }, /* 40.5 Mb*/
+		[41] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000,
+			49800, 3, 3, 4, 41, 41, 41 }, /* 54 Mb */
+		[42] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500,
+			72200, 4, 4, 4, 42, 42, 42 }, /* 81 Mb */
+		[43] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 108000,
+			92900, 5, 5, 4, 43, 43, 43 }, /* 108 Mb */
+		[44] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500,
+			102700, 6, 6, 4, 44, 44, 44 }, /* 121.5 Mb*/
+		[45] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000,
+			112000, 7, 7, 4, 45, 46, 46 }, /* 135 Mb */
+		[46] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000,
+			122000, 7, 7, 4, 45, 46, 46 }, /* 150 Mb */
+		[47] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000,
+			25800, 8, 8, 0, 47, 47, 47 }, /* 27 Mb */
+		[48] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000,
+			49800, 9, 9, 2, 48, 48, 48 }, /* 54 Mb */
+		[49] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000,
+			71900, 10, 10, 2, 49, 49, 49 }, /* 81 Mb */
+		[50] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000,
+			92500, 11, 11, 4, 50, 50, 50 }, /* 108 Mb */
+		[51] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000,
+			130300, 12, 12, 4, 51, 51, 51 }, /* 162 Mb */
+		[52] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000,
+			162800, 13, 13, 4, 52, 52, 52 }, /* 216 Mb */
+		[53] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000,
+			178200, 14, 14, 4, 53, 53, 53 }, /* 243 Mb */
+		[54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000,
+			192100, 15, 15, 4, 54, 55, 55 }, /* 270 Mb */
+		[55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000,
+			207000, 15, 15, 4, 54, 55, 55 }, /* 300 Mb */
+		[56] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500,
+			36100, 16, 16, 0, 56, 56, 56 }, /* 40.5 Mb */
+		[57] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000,
+			72900, 17, 17, 2, 57, 57, 57 }, /* 81 Mb */
+		[58] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500,
+			108300, 18, 18, 2, 58, 58, 58 }, /* 121.5 Mb */
+		[59] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000,
+			142000, 19, 19, 4, 59, 59, 59 }, /*  162 Mb */
+		[60] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000,
+			205100, 20, 20, 4, 60, 61, 61 }, /*  243 Mb */
+		[61] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000,
+			224700, 20, 20, 4, 60, 61, 61 }, /*  270 Mb */
+		[62] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000,
+			263100, 21, 21, 4, 62, 63, 63 }, /*  324 Mb */
+		[63] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000,
+			288000, 21, 21, 4, 62, 63, 63 }, /*  360 Mb */
+		[64] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500,
+			290700, 22, 22, 4, 64, 65, 65 }, /* 364.5 Mb */
+		[65] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000,
+			317200, 22, 22, 4, 64, 65, 65 }, /* 405 Mb */
+		[66] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000,
+			317200, 23, 23, 4, 66, 67, 67 }, /* 405 Mb */
+		[67] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000,
+			346400, 23, 23, 4, 66, 67, 67 }, /* 450 Mb */
 	},
 	50,  /* probe interval */
 	WLAN_RC_HT_FLAG,  /* Phy rates allowed initially */
@@ -116,101 +168,153 @@
  * for HT are the 64K max aggregate limit */
 
 static const struct ath_rate_table ar5416_11ng_ratetable = {
-	46,
+	72,
 	12, /* MCS start */
 	{
-		{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
-			900, 0, 2, 0, 0, 0, 0, 0 },
-		{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
-			1900, 1, 4, 1, 1, 1, 1, 1 },
-		{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
-			4900, 2, 11, 2, 2, 2, 2, 2 },
-		{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
-			8100, 3, 22, 3, 3, 3, 3, 3 },
-		{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
-			5400, 4, 12, 4, 4, 4, 4, 4 },
-		{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
-			7800, 5, 18, 4, 5, 5, 5, 5 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
-			10100, 6, 24, 6, 6, 6, 6, 6 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
-			14100, 7, 36, 6, 7, 7, 7, 7 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
-			17700, 8, 48, 8, 8, 8, 8, 8 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
-			23700, 9, 72, 8, 9, 9, 9, 9 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
-			27400, 10, 96, 8, 10, 10, 10, 10 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
-			30900, 11, 108, 8, 11, 11, 11, 11 },
-		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
-			6400, 0, 0, 4, 12, 28, 12, 28 },
-		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
-			12700, 1, 1, 6, 13, 29, 13, 29 },
-		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
-			18800, 2, 2, 6, 14, 30, 14, 30 },
-		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
-			25000, 3, 3, 8, 15, 31, 15, 31 },
-		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
-			36700, 4, 4, 8, 16, 32, 16, 32 },
-		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
-			48100, 5, 5, 8, 17, 33, 17, 33 },
-		{ INVALID,  VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
-			53500, 6, 6, 8, 18, 34, 18, 34 },
-		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
-			59000, 7, 7, 8, 19, 35, 19, 36 },
-		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
-			12700, 8, 8, 4, 20, 37, 20, 37 },
-		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
-			24800, 9, 9, 6, 21, 38, 21, 38 },
-		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
-			36600, 10, 10, 6, 22, 39, 22, 39 },
-		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
-			48100, 11, 11, 8, 23, 40, 23, 40 },
-		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
-			69500, 12, 12, 8, 24, 41, 24, 41 },
-		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
-			89500, 13, 13, 8, 25, 42, 25, 42 },
-		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
-			98900, 14, 14, 8, 26, 43, 26, 44 },
-		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
-			108300, 15, 15, 8, 27, 44, 27, 45 },
-		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
-			13200, 0, 0, 8, 12, 28, 28, 28 },
-		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
-			25900, 1, 1, 8, 13, 29, 29, 29 },
-		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
-			38600, 2, 2, 8, 14, 30, 30, 30 },
-		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
-			49800, 3, 3, 8,  15, 31, 31, 31 },
-		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
-			72200, 4, 4, 8, 16, 32, 32, 32 },
-		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
-			92900, 5, 5, 8, 17, 33, 33, 33 },
-		{ INVALID,  VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
-			102700, 6, 6, 8, 18, 34, 34, 34 },
-		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
-			112000, 7, 7, 8, 19, 35, 36, 36 },
-		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
-			122000, 7, 7, 8, 19, 35, 36, 36 },
-		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
-			25800, 8, 8, 8, 20, 37, 37, 37 },
-		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
-			49800, 9, 9, 8, 21, 38, 38, 38 },
-		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
-			71900, 10, 10, 8, 22, 39, 39, 39 },
-		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
-			92500, 11, 11, 8, 23, 40, 40, 40 },
-		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
-			130300, 12, 12, 8, 24, 41, 41, 41 },
-		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
-			162800, 13, 13, 8, 25, 42, 42, 42 },
-		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
-			178200, 14, 14, 8, 26, 43, 43, 43 },
-		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
-			192100, 15, 15, 8, 27, 44, 45, 45 },
-		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
-			207000, 15, 15, 8, 27, 44, 45, 45 },
+		[0] = { RC_ALL, WLAN_RC_PHY_CCK, 1000,
+			900, 0, 2, 0, 0, 0, 0 }, /* 1 Mb */
+		[1] = { RC_ALL, WLAN_RC_PHY_CCK, 2000,
+			1900, 1, 4, 1, 1, 1, 1 }, /* 2 Mb */
+		[2] = { RC_ALL, WLAN_RC_PHY_CCK, 5500,
+			4900, 2, 11, 2, 2, 2, 2 }, /* 5.5 Mb */
+		[3] = { RC_ALL, WLAN_RC_PHY_CCK, 11000,
+			8100, 3, 22, 3, 3, 3, 3 }, /* 11 Mb */
+		[4] = { RC_INVALID, WLAN_RC_PHY_OFDM, 6000,
+			5400, 4, 12, 4, 4, 4, 4 }, /* 6 Mb */
+		[5] = { RC_INVALID, WLAN_RC_PHY_OFDM, 9000,
+			7800, 5, 18, 4, 5, 5, 5 }, /* 9 Mb */
+		[6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000,
+			10100, 6, 24, 6, 6, 6, 6 }, /* 12 Mb */
+		[7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000,
+			14100, 7, 36, 6, 7, 7, 7 }, /* 18 Mb */
+		[8] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000,
+			17700, 8, 48, 8, 8, 8, 8 }, /* 24 Mb */
+		[9] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000,
+			23700, 9, 72, 8, 9, 9, 9 }, /* 36 Mb */
+		[10] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000,
+			27400, 10, 96, 8, 10, 10, 10 }, /* 48 Mb */
+		[11] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000,
+			30900, 11, 108, 8, 11, 11, 11 }, /* 54 Mb */
+		[12] = { RC_INVALID, WLAN_RC_PHY_HT_20_SS, 6500,
+			6400, 0, 0, 4, 42, 12, 42 }, /* 6.5 Mb */
+		[13] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000,
+			12700, 1, 1, 6, 43, 13, 43 }, /* 13 Mb */
+		[14] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500,
+			18800, 2, 2, 6, 44, 14, 44 }, /* 19.5 Mb*/
+		[15] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000,
+			25000, 3, 3, 8, 45, 15, 45 }, /* 26 Mb */
+		[16] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000,
+			36700, 4, 4, 8, 46, 16, 46 }, /* 39 Mb */
+		[17] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000,
+			48100, 5, 5, 8, 47, 17, 47 }, /* 52 Mb */
+		[18] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500,
+			53500, 6, 6, 8, 48, 18, 48 }, /* 58.5 Mb */
+		[19] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000,
+			59000, 7, 7, 8, 49, 20, 50 }, /* 65 Mb */
+		[20] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200,
+			65400, 7, 7, 8, 49, 20, 50 }, /* 65 Mb*/
+		[21] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000,
+			12700, 8, 8, 4, 51, 21, 51 }, /* 13 Mb */
+		[22] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000,
+			24800, 9, 9, 6, 52, 22, 52 }, /* 26 Mb */
+		[23] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000,
+			36600, 10, 10, 6, 53, 23, 53 }, /* 39 Mb */
+		[24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000,
+			48100, 11, 11, 8, 54, 24, 54 }, /* 52 Mb */
+		[25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000,
+			69500, 12, 12, 8, 55, 25, 55 }, /* 78 Mb */
+		[26] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000,
+			89500, 13, 13, 8, 56, 26, 56 }, /* 104 Mb */
+		[27] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000,
+			98900, 14, 14, 8, 57, 27, 57 }, /* 117 Mb */
+		[28] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000,
+			108300, 15, 15, 8, 58, 29, 59 }, /* 130 Mb */
+		[29] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400,
+			120000, 15, 15, 8, 58, 29, 59 }, /* 144.4 Mb */
+		[30] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500,
+			17400, 16, 16, 4, 60, 30, 60 }, /* 19.5 Mb */
+		[31] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000,
+			35100, 17, 17, 6, 61, 31, 61 }, /* 39 Mb */
+		[32] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500,
+			52600, 18, 18, 6, 62, 32, 62 }, /* 58.5 Mb */
+		[33] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000,
+			70400, 19, 19, 8, 63, 33, 63 }, /* 78 Mb */
+		[34] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000,
+			104900, 20, 20, 8, 64, 35, 65 }, /* 117 Mb */
+		[35] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000,
+			115800, 20, 20, 8, 64, 35, 65 }, /* 130 Mb */
+		[36] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000,
+			137200, 21, 21, 8, 66, 37, 67 }, /* 156 Mb */
+		[37] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300,
+			151100, 21, 21, 8, 66, 37, 67 }, /* 173.3 Mb */
+		[38] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500,
+			152800, 22, 22, 8, 68, 39, 69 }, /* 175.5 Mb */
+		[39] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000,
+			168400, 22, 22, 8, 68, 39, 69 }, /* 195 Mb */
+		[40] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000,
+			168400, 23, 23, 8, 70, 41, 71 }, /* 195 Mb */
+		[41] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700,
+			185000, 23, 23, 8, 70, 41, 71 }, /* 216.7 Mb */
+		[42] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500,
+			13200, 0, 0, 8, 42, 42, 42 }, /* 13.5 Mb */
+		[43] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500,
+			25900, 1, 1, 8, 43, 43, 43 }, /* 27.0 Mb */
+		[44] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500,
+			38600, 2, 2, 8, 44, 44, 44 }, /* 40.5 Mb */
+		[45] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000,
+			49800, 3, 3, 8, 45, 45, 45 }, /* 54 Mb */
+		[46] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500,
+			72200, 4, 4, 8, 46, 46, 46 }, /* 81 Mb */
+		[47] = { RC_HT_S_40 , WLAN_RC_PHY_HT_40_SS, 108000,
+			92900, 5, 5, 8, 47, 47, 47 }, /* 108 Mb */
+		[48] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500,
+			102700, 6, 6, 8, 48, 48, 48 }, /* 121.5 Mb */
+		[49] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000,
+			112000, 7, 7, 8, 49, 50, 50 }, /* 135 Mb */
+		[50] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000,
+			122000, 7, 7, 8, 49, 50, 50 }, /* 150 Mb */
+		[51] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000,
+			25800, 8, 8, 8, 51, 51, 51 }, /* 27 Mb */
+		[52] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000,
+			49800, 9, 9, 8, 52, 52, 52 }, /* 54 Mb */
+		[53] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000,
+			71900, 10, 10, 8, 53, 53, 53 }, /* 81 Mb */
+		[54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000,
+			92500, 11, 11, 8, 54, 54, 54 }, /* 108 Mb */
+		[55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000,
+			130300, 12, 12, 8, 55, 55, 55 }, /* 162 Mb */
+		[56] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000,
+			162800, 13, 13, 8, 56, 56, 56 }, /* 216 Mb */
+		[57] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000,
+			178200, 14, 14, 8, 57, 57, 57 }, /* 243 Mb */
+		[58] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000,
+			192100, 15, 15, 8, 58, 59, 59 }, /* 270 Mb */
+		[59] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000,
+			207000, 15, 15, 8, 58, 59, 59 }, /* 300 Mb */
+		[60] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500,
+			36100, 16, 16, 8, 60, 60, 60 }, /* 40.5 Mb */
+		[61] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000,
+			72900, 17, 17, 8, 61, 61, 61 }, /* 81 Mb */
+		[62] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500,
+			108300, 18, 18, 8, 62, 62, 62 }, /* 121.5 Mb */
+		[63] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000,
+			142000, 19, 19, 8, 63, 63, 63 }, /* 162 Mb */
+		[64] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000,
+			205100, 20, 20, 8, 64, 65, 65 }, /* 243 Mb */
+		[65] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000,
+			224700, 20, 20, 8, 64, 65, 65 }, /* 170 Mb */
+		[66] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000,
+			263100, 21, 21, 8, 66, 67, 67 }, /* 324 Mb */
+		[67] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000,
+			288000, 21, 21, 8, 66, 67, 67 }, /* 360 Mb */
+		[68] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500,
+			290700, 22, 22, 8, 68, 69, 69 }, /* 364.5 Mb */
+		[69] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000,
+			317200, 22, 22, 8, 68, 69, 69 }, /* 405 Mb */
+		[70] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000,
+			317200, 23, 23, 8, 70, 71, 71 }, /* 405 Mb */
+		[71] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000,
+			346400, 23, 23, 8, 70, 71, 71 }, /* 450 Mb */
 	},
 	50,  /* probe interval */
 	WLAN_RC_HT_FLAG,  /* Phy rates allowed initially */
@@ -220,22 +324,22 @@
 	8,
 	0,
 	{
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
-			5400, 0, 12, 0, 0, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
-			7800,  1, 18, 0, 1, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
-			10000, 2, 24, 2, 2, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
-			13900, 3, 36, 2, 3, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
-			17300, 4, 48, 4, 4, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
-			23000, 5, 72, 4, 5, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
-			27400, 6, 96, 4, 6, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
-			29300, 7, 108, 4, 7, 0 },
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
+			5400, 0, 12, 0},
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
+			7800,  1, 18, 0},
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
+			10000, 2, 24, 2},
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
+			13900, 3, 36, 2},
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
+			17300, 4, 48, 4},
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
+			23000, 5, 72, 4},
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
+			27400, 6, 96, 4},
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
+			29300, 7, 108, 4},
 	},
 	50,  /* probe interval */
 	0,   /* Phy rates allowed initially */
@@ -245,30 +349,30 @@
 	12,
 	0,
 	{
-		{ VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
-			900, 0, 2, 0, 0, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
-			1900, 1, 4, 1, 1, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
-			4900, 2, 11, 2, 2, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
-			8100, 3, 22, 3, 3, 0 },
-		{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
-			5400, 4, 12, 4, 4, 0 },
-		{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
-			7800, 5, 18, 4, 5, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
-			10000, 6, 24, 6, 6, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
-			13900, 7, 36, 6, 7, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
-			17300, 8, 48, 8, 8, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
-			23000, 9, 72, 8, 9, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
-			27400, 10, 96, 8, 10, 0 },
-		{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
-			29300, 11, 108, 8, 11, 0 },
+		{ RC_L_SDT, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
+			900, 0, 2, 0},
+		{ RC_L_SDT, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
+			1900, 1, 4, 1},
+		{ RC_L_SDT, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
+			4900, 2, 11, 2},
+		{ RC_L_SDT, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
+			8100, 3, 22, 3},
+		{ RC_INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
+			5400, 4, 12, 4},
+		{ RC_INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
+			7800, 5, 18, 4},
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
+			10000, 6, 24, 6},
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
+			13900, 7, 36, 6},
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
+			17300, 8, 48, 8},
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
+			23000, 9, 72, 8},
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
+			27400, 10, 96, 8},
+		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
+			29300, 11, 108, 8},
 	},
 	50,  /* probe interval */
 	0,   /* Phy rates allowed initially */
@@ -338,7 +442,7 @@
 					   u8 index, int valid_tx_rate)
 {
 	BUG_ON(index > ath_rc_priv->rate_table_size);
-	ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0;
+	ath_rc_priv->valid_rate_index[index] = !!valid_tx_rate;
 }
 
 static inline
@@ -370,6 +474,8 @@
 		return 0;
 	if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG))
 		return 0;
+	if (WLAN_RC_PHY_TS(phy) && !(capflag & WLAN_RC_TS_FLAG))
+		return 0;
 	if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG))
 		return 0;
 	if (!ignore_cw && WLAN_RC_PHY_HT(phy))
@@ -400,13 +506,9 @@
 				 u32 capflag)
 {
 	u8 i, hi = 0;
-	u32 valid;
 
 	for (i = 0; i < rate_table->rate_cnt; i++) {
-		valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ?
-			 rate_table->info[i].valid_single_stream :
-			 rate_table->info[i].valid);
-		if (valid == 1) {
+		if (rate_table->info[i].rate_flags & RC_LEGACY) {
 			u32 phy = rate_table->info[i].phy;
 			u8 valid_rate_count = 0;
 
@@ -418,7 +520,7 @@
 			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);
+			hi = i;
 		}
 	}
 
@@ -436,9 +538,7 @@
 	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->ht_cap & WLAN_RC_DS_FLAG) ?
-				     rate_table->info[j].valid_single_stream :
-				     rate_table->info[j].valid);
+			u16 rate_flags = rate_table->info[i].rate_flags;
 			u8 rate = rateset->rs_rates[i];
 			u8 dot11rate = rate_table->info[j].dot11rate;
 
@@ -447,8 +547,9 @@
 			 * (VALID/VALID_20/VALID_40) flags */
 
 			if ((rate == dot11rate) &&
-			    ((valid & WLAN_RC_CAP_MODE(capflag)) ==
-			     WLAN_RC_CAP_MODE(capflag)) &&
+			    (rate_flags & WLAN_RC_CAP_MODE(capflag)) ==
+			    WLAN_RC_CAP_MODE(capflag) &&
+			    (rate_flags & WLAN_RC_CAP_STREAM(capflag)) &&
 			    !WLAN_RC_PHY_HT(phy)) {
 				u8 valid_rate_count = 0;
 
@@ -482,14 +583,13 @@
 	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->ht_cap & WLAN_RC_DS_FLAG) ?
-				     rate_table->info[j].valid_single_stream :
-				     rate_table->info[j].valid);
+			u16 rate_flags = rate_table->info[j].rate_flags;
 			u8 rate = rateset->rs_rates[i];
 			u8 dot11rate = rate_table->info[j].dot11rate;
 
 			if ((rate != dot11rate) || !WLAN_RC_PHY_HT(phy) ||
-			    !WLAN_RC_PHY_HT_VALID(valid, capflag))
+			    !(rate_flags & WLAN_RC_CAP_STREAM(capflag)) ||
+			    !WLAN_RC_PHY_HT_VALID(rate_flags, capflag))
 				continue;
 
 			if (!ath_rc_valid_phyrate(phy, capflag, 0))
@@ -585,12 +685,15 @@
 	if (rate > (ath_rc_priv->rate_table_size - 1))
 		rate = ath_rc_priv->rate_table_size - 1;
 
-	if (rate_table->info[rate].valid &&
-	    (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))
+	if (RC_TS_ONLY(rate_table->info[rate].rate_flags) &&
+	    (ath_rc_priv->ht_cap & WLAN_RC_TS_FLAG))
 		return rate;
 
-	if (rate_table->info[rate].valid_single_stream &&
-	    !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))
+	if (RC_DS_OR_LATER(rate_table->info[rate].rate_flags) &&
+	    (ath_rc_priv->ht_cap & (WLAN_RC_DS_FLAG | WLAN_RC_TS_FLAG)))
+		return rate;
+
+	if (RC_SS_OR_LEGACY(rate_table->info[rate].rate_flags))
 		return rate;
 
 	/* This should not happen */
@@ -1003,12 +1106,19 @@
 static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
 				struct ieee80211_tx_rate *rate)
 {
-	int rix;
+	int rix = 0, i = 0;
+	int mcs_rix_off[] = { 7, 15, 20, 21, 22, 23 };
 
 	if (!(rate->flags & IEEE80211_TX_RC_MCS))
 		return rate->idx;
 
-	rix = rate->idx + rate_table->mcs_start;
+	while (rate->idx > mcs_rix_off[i] &&
+	      i < sizeof(mcs_rix_off)/sizeof(int)) {
+		rix++; i++;
+	}
+
+	rix += rate->idx + rate_table->mcs_start;
+
 	if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
 	    (rate->flags & IEEE80211_TX_RC_SHORT_GI))
 		rix = rate_table->info[rix].ht_index;
@@ -1016,8 +1126,6 @@
 		rix = rate_table->info[rix].sgi_index;
 	else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
 		rix = rate_table->info[rix].cw40index;
-	else
-		rix = rate_table->info[rix].base_index;
 
 	return rix;
 }
@@ -1193,20 +1301,19 @@
 }
 
 static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta,
-			       bool is_cw40, bool is_sgi40)
+			       bool is_cw40, bool is_sgi)
 {
 	u8 caps = 0;
 
 	if (sta->ht_cap.ht_supported) {
 		caps = WLAN_RC_HT_FLAG;
-		if (sc->sc_ah->caps.tx_chainmask != 1 &&
-		    ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_DS, 0, NULL)) {
-			if (sta->ht_cap.mcs.rx_mask[1])
-				caps |= WLAN_RC_DS_FLAG;
-		}
+		if (sta->ht_cap.mcs.rx_mask[1] && sta->ht_cap.mcs.rx_mask[2])
+			caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG;
+		else if (sta->ht_cap.mcs.rx_mask[1])
+			caps |= WLAN_RC_DS_FLAG;
 		if (is_cw40)
 			caps |= WLAN_RC_40_FLAG;
-		if (is_sgi40)
+		if (is_sgi)
 			caps |= WLAN_RC_SGI_FLAG;
 	}
 
@@ -1300,7 +1407,7 @@
 	struct ath_softc *sc = priv;
 	struct ath_rate_priv *ath_rc_priv = priv_sta;
 	const struct ath_rate_table *rate_table;
-	bool is_cw40, is_sgi40;
+	bool is_cw40, is_sgi = false;
 	int i, j = 0;
 
 	for (i = 0; i < sband->n_bitrates; i++) {
@@ -1323,7 +1430,11 @@
 	}
 
 	is_cw40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-	is_sgi40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+
+	if (is_cw40)
+		is_sgi = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+	else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+		is_sgi = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
 
 	/* Choose rate table first */
 
@@ -1336,7 +1447,7 @@
 		rate_table = hw_rate_table[sc->cur_rate_mode];
 	}
 
-	ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi40);
+	ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi);
 	ath_rc_init(sc, priv_sta, sband, sta, rate_table);
 }
 
@@ -1347,10 +1458,10 @@
 	struct ath_softc *sc = priv;
 	struct ath_rate_priv *ath_rc_priv = priv_sta;
 	const struct ath_rate_table *rate_table = NULL;
-	bool oper_cw40 = false, oper_sgi40;
+	bool oper_cw40 = false, oper_sgi;
 	bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ?
 		true : false;
-	bool local_sgi40 = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ?
+	bool local_sgi = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ?
 		true : false;
 
 	/* FIXME: Handle AP mode later when we support CWM */
@@ -1363,15 +1474,21 @@
 		    oper_chan_type == NL80211_CHAN_HT40PLUS)
 			oper_cw40 = true;
 
-		oper_sgi40 = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
-			true : false;
+		if (oper_cw40)
+			oper_sgi = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+				   true : false;
+		else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+			oper_sgi = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+				   true : false;
+		else
+			oper_sgi = false;
 
-		if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) {
+		if ((local_cw40 != oper_cw40) || (local_sgi != oper_sgi)) {
 			rate_table = ath_choose_rate_table(sc, sband->band,
 						   sta->ht_cap.ht_supported,
 						   oper_cw40);
 			ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta,
-						   oper_cw40, oper_sgi40);
+						   oper_cw40, oper_sgi);
 			ath_rc_init(sc, priv_sta, sband, sta, rate_table);
 
 			ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index 3d8d40c..dc10826 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -24,32 +24,63 @@
 struct ath_softc;
 
 #define ATH_RATE_MAX     30
-#define RATE_TABLE_SIZE  64
+#define RATE_TABLE_SIZE  72
 #define MAX_TX_RATE_PHY  48
 
-/* VALID_ALL - valid for 20/40/Legacy,
- * VALID - Legacy only,
- * VALID_20 - HT 20 only,
- * VALID_40 - HT 40 only */
 
-#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 RC_INVALID	0x0000
+#define RC_LEGACY	0x0001
+#define RC_SS		0x0002
+#define RC_DS		0x0004
+#define RC_TS		0x0008
+#define RC_HT_20	0x0010
+#define RC_HT_40	0x0020
+
+#define RC_STREAM_MASK	0xe
+#define RC_DS_OR_LATER(f)	((((f) & RC_STREAM_MASK) == RC_DS) || \
+				(((f) & RC_STREAM_MASK) == (RC_DS | RC_TS)))
+#define RC_TS_ONLY(f)		(((f) & RC_STREAM_MASK) == RC_TS)
+#define RC_SS_OR_LEGACY(f)	((f) & (RC_SS | RC_LEGACY))
+
+#define RC_HT_2040		(RC_HT_20 | RC_HT_40)
+#define RC_ALL_STREAM		(RC_SS | RC_DS | RC_TS)
+#define RC_L_SD			(RC_LEGACY | RC_SS | RC_DS)
+#define RC_L_SDT		(RC_LEGACY | RC_SS | RC_DS | RC_TS)
+#define RC_HT_S_20		(RC_HT_20 | RC_SS)
+#define RC_HT_D_20		(RC_HT_20 | RC_DS)
+#define RC_HT_T_20		(RC_HT_20 | RC_TS)
+#define RC_HT_S_40		(RC_HT_40 | RC_SS)
+#define RC_HT_D_40		(RC_HT_40 | RC_DS)
+#define RC_HT_T_40		(RC_HT_40 | RC_TS)
+
+#define RC_HT_SD_20		(RC_HT_20 | RC_SS | RC_DS)
+#define RC_HT_DT_20		(RC_HT_20 | RC_DS | RC_TS)
+#define RC_HT_SD_40		(RC_HT_40 | RC_SS | RC_DS)
+#define RC_HT_DT_40		(RC_HT_40 | RC_DS | RC_TS)
+
+#define RC_HT_SD_2040		(RC_HT_2040 | RC_SS | RC_DS)
+#define RC_HT_SDT_2040		(RC_HT_2040 | RC_SS | RC_DS | RC_TS)
+
+#define RC_HT_SDT_20		(RC_HT_20 | RC_SS | RC_DS | RC_TS)
+#define RC_HT_SDT_40		(RC_HT_40 | RC_SS | RC_DS | RC_TS)
+
+#define RC_ALL			(RC_LEGACY | RC_HT_2040 | RC_ALL_STREAM)
 
 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_20_TS,
 	WLAN_RC_PHY_HT_40_SS,
 	WLAN_RC_PHY_HT_40_DS,
+	WLAN_RC_PHY_HT_40_TS,
 	WLAN_RC_PHY_HT_20_SS_HGI,
 	WLAN_RC_PHY_HT_20_DS_HGI,
+	WLAN_RC_PHY_HT_20_TS_HGI,
 	WLAN_RC_PHY_HT_40_SS_HGI,
 	WLAN_RC_PHY_HT_40_DS_HGI,
+	WLAN_RC_PHY_HT_40_TS_HGI,
 	WLAN_RC_PHY_MAX
 };
 
@@ -57,36 +88,50 @@
 				|| (_phy == WLAN_RC_PHY_HT_40_DS)	\
 				|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI)	\
 				|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+#define WLAN_RC_PHY_TS(_phy)   ((_phy == WLAN_RC_PHY_HT_20_TS)		\
+				|| (_phy == WLAN_RC_PHY_HT_40_TS)	\
+				|| (_phy == WLAN_RC_PHY_HT_20_TS_HGI)	\
+				|| (_phy == WLAN_RC_PHY_HT_40_TS_HGI))
 #define WLAN_RC_PHY_20(_phy)   ((_phy == WLAN_RC_PHY_HT_20_SS)		\
 				|| (_phy == WLAN_RC_PHY_HT_20_DS)	\
+				|| (_phy == WLAN_RC_PHY_HT_20_TS)	\
 				|| (_phy == WLAN_RC_PHY_HT_20_SS_HGI)	\
-				|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI))
+				|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI)	\
+				|| (_phy == WLAN_RC_PHY_HT_20_TS_HGI))
 #define WLAN_RC_PHY_40(_phy)   ((_phy == WLAN_RC_PHY_HT_40_SS)		\
 				|| (_phy == WLAN_RC_PHY_HT_40_DS)	\
+				|| (_phy == WLAN_RC_PHY_HT_40_TS)	\
 				|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI)	\
-				|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+				|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI)	\
+				|| (_phy == WLAN_RC_PHY_HT_40_TS_HGI))
 #define WLAN_RC_PHY_SGI(_phy)  ((_phy == WLAN_RC_PHY_HT_20_SS_HGI)      \
 				|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI)   \
+				|| (_phy == WLAN_RC_PHY_HT_20_TS_HGI)   \
 				|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI)   \
-				|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+				|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI)   \
+				|| (_phy == WLAN_RC_PHY_HT_40_TS_HGI))
 
 #define WLAN_RC_PHY_HT(_phy)    (_phy >= WLAN_RC_PHY_HT_20_SS)
 
 #define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ?	\
-		(capflag & WLAN_RC_40_FLAG) ? VALID_40 : VALID_20 : VALID))
+	((capflag & WLAN_RC_40_FLAG) ? RC_HT_40 : RC_HT_20) : RC_LEGACY))
+
+#define WLAN_RC_CAP_STREAM(capflag) (((capflag & WLAN_RC_TS_FLAG) ?	\
+	(RC_TS) : ((capflag & WLAN_RC_DS_FLAG) ? RC_DS : RC_SS)))
 
 /* 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 & VALID_20) && !(capflag & WLAN_RC_40_FLAG)) || \
-	 ((flag & VALID_40) && (capflag & WLAN_RC_40_FLAG)))
+	(((flag & RC_HT_20) && !(capflag & WLAN_RC_40_FLAG)) || \
+	 ((flag & RC_HT_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 WLAN_RC_TS_FLAG         (0x02)
+#define WLAN_RC_40_FLAG         (0x04)
+#define WLAN_RC_SGI_FLAG        (0x08)
+#define WLAN_RC_HT_FLAG         (0x10)
 
 /**
  * struct ath_rate_table - Rate Control table
@@ -110,15 +155,13 @@
 	int rate_cnt;
 	int mcs_start;
 	struct {
-		u8 valid;
-		u8 valid_single_stream;
+		u16 rate_flags;
 		u8 phy;
 		u32 ratekbps;
 		u32 user_ratekbps;
 		u8 ratecode;
 		u8 dot11rate;
 		u8 ctrl_rate;
-		u8 base_index;
 		u8 cw40index;
 		u8 sgi_index;
 		u8 ht_index;
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index e3e5291..da0cfe9 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -116,9 +116,6 @@
 	/* configure operational mode */
 	ath9k_hw_setopmode(ah);
 
-	/* Handle any link-level address change. */
-	ath9k_hw_setmac(ah, common->macaddr);
-
 	/* calculate and install multicast filter */
 	mfilt[0] = mfilt[1] = ~0;
 	ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
@@ -295,7 +292,7 @@
 
 	ath_opmode_init(sc);
 
-	ath9k_hw_startpcureceive(sc->sc_ah);
+	ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_SCANNING));
 }
 
 static void ath_edma_stop_recv(struct ath_softc *sc)
@@ -501,7 +498,7 @@
 start_recv:
 	spin_unlock_bh(&sc->rx.rxbuflock);
 	ath_opmode_init(sc);
-	ath9k_hw_startpcureceive(ah);
+	ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_SCANNING));
 
 	return 0;
 }
@@ -700,12 +697,16 @@
 	bf = SKB_CB_ATHBUF(skb);
 	BUG_ON(!bf);
 
-	dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+	dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
 				common->rx_bufsize, DMA_FROM_DEVICE);
 
 	ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data);
-	if (ret == -EINPROGRESS)
+	if (ret == -EINPROGRESS) {
+		/*let device gain the buffer again*/
+		dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+				common->rx_bufsize, DMA_FROM_DEVICE);
 		return false;
+	}
 
 	__skb_unlink(skb, &rx_edma->rx_fifo);
 	if (ret == -EINVAL) {
@@ -814,13 +815,263 @@
 	 * 1. accessing the frame
 	 * 2. requeueing the same buffer to h/w
 	 */
-	dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+	dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
 			common->rx_bufsize,
 			DMA_FROM_DEVICE);
 
 	return bf;
 }
 
+/* Assumes you've already done the endian to CPU conversion */
+static bool ath9k_rx_accept(struct ath_common *common,
+			    struct ieee80211_hdr *hdr,
+			    struct ieee80211_rx_status *rxs,
+			    struct ath_rx_status *rx_stats,
+			    bool *decrypt_error)
+{
+	struct ath_hw *ah = common->ah;
+	__le16 fc;
+	u8 rx_status_len = ah->caps.rx_status_len;
+
+	fc = hdr->frame_control;
+
+	if (!rx_stats->rs_datalen)
+		return false;
+        /*
+         * rs_status follows rs_datalen so if rs_datalen is too large
+         * we can take a hint that hardware corrupted it, so ignore
+         * those frames.
+         */
+	if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len))
+		return false;
+
+	/*
+	 * rs_more indicates chained descriptors which can be used
+	 * to link buffers together for a sort of scatter-gather
+	 * operation.
+	 * reject the frame, we don't support scatter-gather yet and
+	 * the frame is probably corrupt anyway
+	 */
+	if (rx_stats->rs_more)
+		return false;
+
+	/*
+	 * The rx_stats->rs_status will not be set until the end of the
+	 * chained descriptors so it can be ignored if rs_more is set. The
+	 * rs_more will be false at the last element of the chained
+	 * descriptors.
+	 */
+	if (rx_stats->rs_status != 0) {
+		if (rx_stats->rs_status & ATH9K_RXERR_CRC)
+			rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
+		if (rx_stats->rs_status & ATH9K_RXERR_PHY)
+			return false;
+
+		if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
+			*decrypt_error = true;
+		} else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
+			if (ieee80211_is_ctl(fc))
+				/*
+				 * Sometimes, we get invalid
+				 * MIC failures on valid control frames.
+				 * Remove these mic errors.
+				 */
+				rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
+			else
+				rxs->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 (ah->opmode == NL80211_IFTYPE_MONITOR) {
+			if (rx_stats->rs_status &
+			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+			      ATH9K_RXERR_CRC))
+				return false;
+		} else {
+			if (rx_stats->rs_status &
+			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
+				return false;
+			}
+		}
+	}
+	return true;
+}
+
+static int ath9k_process_rate(struct ath_common *common,
+			      struct ieee80211_hw *hw,
+			      struct ath_rx_status *rx_stats,
+			      struct ieee80211_rx_status *rxs)
+{
+	struct ieee80211_supported_band *sband;
+	enum ieee80211_band band;
+	unsigned int i = 0;
+
+	band = hw->conf.channel->band;
+	sband = hw->wiphy->bands[band];
+
+	if (rx_stats->rs_rate & 0x80) {
+		/* HT rate */
+		rxs->flag |= RX_FLAG_HT;
+		if (rx_stats->rs_flags & ATH9K_RX_2040)
+			rxs->flag |= RX_FLAG_40MHZ;
+		if (rx_stats->rs_flags & ATH9K_RX_GI)
+			rxs->flag |= RX_FLAG_SHORT_GI;
+		rxs->rate_idx = rx_stats->rs_rate & 0x7f;
+		return 0;
+	}
+
+	for (i = 0; i < sband->n_bitrates; i++) {
+		if (sband->bitrates[i].hw_value == rx_stats->rs_rate) {
+			rxs->rate_idx = i;
+			return 0;
+		}
+		if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
+			rxs->flag |= RX_FLAG_SHORTPRE;
+			rxs->rate_idx = i;
+			return 0;
+		}
+	}
+
+	/*
+	 * No valid hardware bitrate found -- we should not get here
+	 * because hardware has already validated this frame as OK.
+	 */
+	ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected "
+		  "0x%02x using 1 Mbit\n", rx_stats->rs_rate);
+
+	return -EINVAL;
+}
+
+static void ath9k_process_rssi(struct ath_common *common,
+			       struct ieee80211_hw *hw,
+			       struct ieee80211_hdr *hdr,
+			       struct ath_rx_status *rx_stats)
+{
+	struct ath_hw *ah = common->ah;
+	struct ieee80211_sta *sta;
+	struct ath_node *an;
+	int last_rssi = ATH_RSSI_DUMMY_MARKER;
+	__le16 fc;
+
+	fc = hdr->frame_control;
+
+	rcu_read_lock();
+	/*
+	 * XXX: use ieee80211_find_sta! This requires quite a bit of work
+	 * under the current ath9k virtual wiphy implementation as we have
+	 * no way of tying a vif to wiphy. Typically vifs are attached to
+	 * at least one sdata of a wiphy on mac80211 but with ath9k virtual
+	 * wiphy you'd have to iterate over every wiphy and each sdata.
+	 */
+	sta = ieee80211_find_sta_by_hw(hw, hdr->addr2);
+	if (sta) {
+		an = (struct ath_node *) sta->drv_priv;
+		if (rx_stats->rs_rssi != ATH9K_RSSI_BAD &&
+		   !rx_stats->rs_moreaggr)
+			ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi);
+		last_rssi = an->last_rssi;
+	}
+	rcu_read_unlock();
+
+	if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
+		rx_stats->rs_rssi = ATH_EP_RND(last_rssi,
+					      ATH_RSSI_EP_MULTIPLIER);
+	if (rx_stats->rs_rssi < 0)
+		rx_stats->rs_rssi = 0;
+
+	/* Update Beacon RSSI, this is used by ANI. */
+	if (ieee80211_is_beacon(fc))
+		ah->stats.avgbrssi = rx_stats->rs_rssi;
+}
+
+/*
+ * 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 ath9k_rx_skb_preprocess(struct ath_common *common,
+				   struct ieee80211_hw *hw,
+				   struct ieee80211_hdr *hdr,
+				   struct ath_rx_status *rx_stats,
+				   struct ieee80211_rx_status *rx_status,
+				   bool *decrypt_error)
+{
+	memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
+
+	/*
+	 * everything but the rate is checked here, the rate check is done
+	 * separately to avoid doing two lookups for a rate for each frame.
+	 */
+	if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
+		return -EINVAL;
+
+	ath9k_process_rssi(common, hw, hdr, rx_stats);
+
+	if (ath9k_process_rate(common, hw, rx_stats, rx_status))
+		return -EINVAL;
+
+	rx_status->band = hw->conf.channel->band;
+	rx_status->freq = hw->conf.channel->center_freq;
+	rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
+	rx_status->antenna = rx_stats->rs_antenna;
+	rx_status->flag |= RX_FLAG_TSFT;
+
+	return 0;
+}
+
+static void ath9k_rx_skb_postprocess(struct ath_common *common,
+				     struct sk_buff *skb,
+				     struct ath_rx_status *rx_stats,
+				     struct ieee80211_rx_status *rxs,
+				     bool decrypt_error)
+{
+	struct ath_hw *ah = common->ah;
+	struct ieee80211_hdr *hdr;
+	int hdrlen, padpos, padsize;
+	u8 keyix;
+	__le16 fc;
+
+	/* 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);
+	fc = hdr->frame_control;
+	padpos = ath9k_cmn_padpos(hdr->frame_control);
+
+	/* 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 - padpos % 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 = padpos & 3;
+	if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
+		memmove(skb->data + padsize, skb->data, padpos);
+		skb_pull(skb, padsize);
+	}
+
+	keyix = rx_stats->rs_keyix;
+
+	if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
+	    ieee80211_has_protected(fc)) {
+		rxs->flag |= RX_FLAG_DECRYPTED;
+	} else if (ieee80211_has_protected(fc)
+		   && !decrypt_error && skb->len >= hdrlen + 4) {
+		keyix = skb->data[hdrlen + 3] >> 6;
+
+		if (test_bit(keyix, common->keymap))
+			rxs->flag |= RX_FLAG_DECRYPTED;
+	}
+	if (ah->sw_mgmt_crypto &&
+	    (rxs->flag & RX_FLAG_DECRYPTED) &&
+	    ieee80211_is_mgmt(fc))
+		/* Use software decrypt for management frames. */
+		rxs->flag &= ~RX_FLAG_DECRYPTED;
+}
 
 int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 {
@@ -842,6 +1093,9 @@
 	enum ath9k_rx_qtype qtype;
 	bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
 	int dma_type;
+	u8 rx_status_len = ah->caps.rx_status_len;
+	u64 tsf = 0;
+	u32 tsf_lower = 0;
 
 	if (edma)
 		dma_type = DMA_BIDIRECTIONAL;
@@ -851,6 +1105,9 @@
 	qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP;
 	spin_lock_bh(&sc->rx.rxbuflock);
 
+	tsf = ath9k_hw_gettsf64(ah);
+	tsf_lower = tsf & 0xffffffff;
+
 	do {
 		/* If handling rx interrupt and flush is in progress => exit */
 		if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
@@ -869,7 +1126,7 @@
 		if (!skb)
 			continue;
 
-		hdr = (struct ieee80211_hdr *) skb->data;
+		hdr = (struct ieee80211_hdr *) (skb->data + rx_status_len);
 		rxs =  IEEE80211_SKB_RXCB(skb);
 
 		hw = ath_get_virt_hw(sc, hdr);
@@ -883,8 +1140,17 @@
 		if (flush)
 			goto requeue;
 
-		retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, &rs,
-						     rxs, &decrypt_error);
+		rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
+		if (rs.rs_tstamp > tsf_lower &&
+		    unlikely(rs.rs_tstamp - tsf_lower > 0x10000000))
+			rxs->mactime -= 0x100000000ULL;
+
+		if (rs.rs_tstamp < tsf_lower &&
+		    unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
+			rxs->mactime += 0x100000000ULL;
+
+		retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
+						 rxs, &decrypt_error);
 		if (retval)
 			goto requeue;
 
@@ -908,8 +1174,8 @@
 		if (ah->caps.rx_status_len)
 			skb_pull(skb, ah->caps.rx_status_len);
 
-		ath9k_cmn_rx_skb_postprocess(common, skb, &rs,
-					     rxs, decrypt_error);
+		ath9k_rx_skb_postprocess(common, skb, &rs,
+					 rxs, decrypt_error);
 
 		/* We will now give hardware our shiny new allocated skb */
 		bf->bf_mpdu = requeue_skb;
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index d4371a4..633e3d9 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -222,6 +222,7 @@
 
 #define AR_ISR_S2              0x008c
 #define AR_ISR_S2_QCU_TXURN    0x000003FF
+#define AR_ISR_S2_BB_WATCHDOG  0x00010000
 #define AR_ISR_S2_CST          0x00400000
 #define AR_ISR_S2_GTT          0x00800000
 #define AR_ISR_S2_TIM          0x01000000
@@ -699,7 +700,15 @@
 #define AR_RC_HOSTIF         0x00000100
 
 #define AR_WA                		0x4004
+#define AR_WA_BIT6			(1 << 6)
+#define AR_WA_BIT7			(1 << 7)
+#define AR_WA_BIT23			(1 << 23)
 #define AR_WA_D3_L1_DISABLE		(1 << 14)
+#define AR_WA_D3_TO_L1_DISABLE_REAL     (1 << 16)
+#define AR_WA_ASPM_TIMER_BASED_DISABLE  (1 << 17)
+#define AR_WA_RESET_EN                  (1 << 18) /* Sw Control to enable PCI-Reset to POR (bit 15) */
+#define AR_WA_ANALOG_SHIFT              (1 << 20)
+#define AR_WA_POR_SHORT                 (1 << 21) /* PCI-E Phy reset control */
 #define AR9285_WA_DEFAULT		0x004a050b
 #define AR9280_WA_DEFAULT           	0x0040073b
 #define AR_WA_DEFAULT               	0x0000073f
@@ -756,32 +765,33 @@
 #define AR_SREV_REVISION2        	      0x00000F00
 #define AR_SREV_REVISION2_S     	      8
 
-#define AR_SREV_VERSION_5416_PCI               0xD
-#define AR_SREV_VERSION_5416_PCIE              0xC
-#define AR_SREV_REVISION_5416_10               0
-#define AR_SREV_REVISION_5416_20               1
-#define AR_SREV_REVISION_5416_22               2
-#define AR_SREV_VERSION_9100                  0x14
-#define AR_SREV_VERSION_9160        	      0x40
-#define AR_SREV_REVISION_9160_10    	      0
-#define AR_SREV_REVISION_9160_11    	      1
-#define AR_SREV_VERSION_9280                0x80
-#define AR_SREV_REVISION_9280_10            0
-#define AR_SREV_REVISION_9280_20            1
-#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_VERSION_9287                  0x180
-#define AR_SREV_REVISION_9287_10              0
-#define AR_SREV_REVISION_9287_11              1
-#define AR_SREV_REVISION_9287_12              2
-#define AR_SREV_VERSION_9271			0x140
-#define AR_SREV_REVISION_9271_10		0
-#define AR_SREV_REVISION_9271_11		1
-#define AR_SREV_VERSION_9300                  0x1c0
-#define AR_SREV_REVISION_9300_20              2 /* 2.0 and 2.1 */
+#define AR_SREV_VERSION_5416_PCI	0xD
+#define AR_SREV_VERSION_5416_PCIE	0xC
+#define AR_SREV_REVISION_5416_10	0
+#define AR_SREV_REVISION_5416_20	1
+#define AR_SREV_REVISION_5416_22	2
+#define AR_SREV_VERSION_9100		0x14
+#define AR_SREV_VERSION_9160		0x40
+#define AR_SREV_REVISION_9160_10	0
+#define AR_SREV_REVISION_9160_11	1
+#define AR_SREV_VERSION_9280		0x80
+#define AR_SREV_REVISION_9280_10	0
+#define AR_SREV_REVISION_9280_20	1
+#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_VERSION_9287		0x180
+#define AR_SREV_REVISION_9287_10	0
+#define AR_SREV_REVISION_9287_11	1
+#define AR_SREV_REVISION_9287_12	2
+#define AR_SREV_REVISION_9287_13	3
+#define AR_SREV_VERSION_9271		0x140
+#define AR_SREV_REVISION_9271_10	0
+#define AR_SREV_REVISION_9271_11	1
+#define AR_SREV_VERSION_9300		0x1c0
+#define AR_SREV_REVISION_9300_20	2 /* 2.0 and 2.1 */
 
 #define AR_SREV_5416(_ah) \
 	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -859,6 +869,11 @@
 	(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
 	 (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
 	  ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_12)))
+#define AR_SREV_9287_13_OR_LATER(_ah) \
+	(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
+	 (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+	  ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_13)))
+
 #define AR_SREV_9271(_ah) \
     (((_ah))->hw_version.macVersion == AR_SREV_VERSION_9271)
 #define AR_SREV_9271_10(_ah) \
@@ -867,6 +882,7 @@
 #define AR_SREV_9271_11(_ah) \
     (AR_SREV_9271(_ah) && \
      ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11))
+
 #define AR_SREV_9300(_ah) \
 	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
 #define AR_SREV_9300_20(_ah) \
@@ -881,6 +897,10 @@
     (AR_SREV_9285_12_OR_LATER(_ah) && \
      ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
 
+#define AR_DEVID_7010(_ah) \
+	(((_ah)->hw_version.devid == 0x7010) || \
+	 ((_ah)->hw_version.devid == 0x9018))
+
 #define AR_RADIO_SREV_MAJOR                   0xf0
 #define AR_RAD5133_SREV_MAJOR                 0xc0
 #define AR_RAD2133_SREV_MAJOR                 0xd0
@@ -978,6 +998,7 @@
 #define AR9287_NUM_GPIO                          11
 #define AR9271_NUM_GPIO                          16
 #define AR9300_NUM_GPIO                          17
+#define AR7010_NUM_GPIO                          16
 
 #define AR_GPIO_IN_OUT                           0x4048
 #define AR_GPIO_IN_VAL                           0x0FFFC000
@@ -992,6 +1013,8 @@
 #define AR9271_GPIO_IN_VAL_S                     16
 #define AR9300_GPIO_IN_VAL                       0x0001FFFF
 #define AR9300_GPIO_IN_VAL_S                     0
+#define AR7010_GPIO_IN_VAL                       0x0000FFFF
+#define AR7010_GPIO_IN_VAL_S                     0
 
 #define AR_GPIO_OE_OUT                           (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)
 #define AR_GPIO_OE_OUT_DRV                       0x3
@@ -1000,6 +1023,21 @@
 #define AR_GPIO_OE_OUT_DRV_HI                    0x2
 #define AR_GPIO_OE_OUT_DRV_ALL                   0x3
 
+#define AR7010_GPIO_OE                           0x52000
+#define AR7010_GPIO_OE_MASK                      0x1
+#define AR7010_GPIO_OE_AS_OUTPUT                 0x0
+#define AR7010_GPIO_OE_AS_INPUT                  0x1
+#define AR7010_GPIO_IN                           0x52004
+#define AR7010_GPIO_OUT                          0x52008
+#define AR7010_GPIO_SET                          0x5200C
+#define AR7010_GPIO_CLEAR                        0x52010
+#define AR7010_GPIO_INT                          0x52014
+#define AR7010_GPIO_INT_TYPE                     0x52018
+#define AR7010_GPIO_INT_POLARITY                 0x5201C
+#define AR7010_GPIO_PENDING                      0x52020
+#define AR7010_GPIO_INT_MASK                     0x52024
+#define AR7010_GPIO_FUNCTION                     0x52028
+
 #define AR_GPIO_INTR_POL                         (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050)
 #define AR_GPIO_INTR_POL_VAL                     0x0001FFFF
 #define AR_GPIO_INTR_POL_VAL_S                   0
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index 105ad40..fd20241 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -219,7 +219,7 @@
 	info->control.rates[1].idx = -1;
 
 	memset(&txctl, 0, sizeof(struct ath_tx_control));
-	txctl.txq = &sc->tx.txq[sc->tx.hwq_map[ATH9K_WME_AC_VO]];
+	txctl.txq = &sc->tx.txq[sc->tx.hwq_map[WME_AC_VO]];
 	txctl.frame_type = ps ? ATH9K_IFT_PAUSE : ATH9K_IFT_UNPAUSE;
 
 	if (ath_tx_start(aphy->hw, skb, &txctl) != 0)
@@ -695,16 +695,18 @@
 		  idle ? "idle" : "not-idle");
 }
 /* Only bother starting a queue on an active virtual wiphy */
-void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue)
+bool ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue)
 {
 	struct ieee80211_hw *hw = sc->pri_wiphy->hw;
 	unsigned int i;
+	bool txq_started = false;
 
 	spin_lock_bh(&sc->wiphy_lock);
 
 	/* Start the primary wiphy */
 	if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) {
 		ieee80211_wake_queue(hw, skb_queue);
+		txq_started = true;
 		goto unlock;
 	}
 
@@ -718,11 +720,13 @@
 
 		hw = aphy->hw;
 		ieee80211_wake_queue(hw, skb_queue);
+		txq_started = true;
 		break;
 	}
 
 unlock:
 	spin_unlock_bh(&sc->wiphy_lock);
+	return txq_started;
 }
 
 /* Go ahead and propagate information to all virtual wiphys, it won't hurt */
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index e23172c..6260faa 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -279,9 +279,6 @@
 	if (wmi->drv_priv->op_flags & OP_UNPLUGGED)
 		return 0;
 
-	if (!wmi)
-		return -EINVAL;
-
 	skb = alloc_skb(headroom + cmd_len, GFP_ATOMIC);
 	if (!skb)
 		return -ENOMEM;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 859aa4a..501b728 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -328,6 +328,7 @@
 	u32 ba[WME_BA_BMP_SIZE >> 5];
 	int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
 	bool rc_update = true;
+	struct ieee80211_tx_rate rates[4];
 
 	skb = bf->bf_mpdu;
 	hdr = (struct ieee80211_hdr *)skb->data;
@@ -335,18 +336,44 @@
 	tx_info = IEEE80211_SKB_CB(skb);
 	hw = bf->aphy->hw;
 
+	memcpy(rates, tx_info->control.rates, sizeof(rates));
+
 	rcu_read_lock();
 
 	/* XXX: use ieee80211_find_sta! */
 	sta = ieee80211_find_sta_by_hw(hw, hdr->addr1);
 	if (!sta) {
 		rcu_read_unlock();
+
+		INIT_LIST_HEAD(&bf_head);
+		while (bf) {
+			bf_next = bf->bf_next;
+
+			bf->bf_state.bf_type |= BUF_XRETRY;
+			if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
+			    !bf->bf_stale || bf_next != NULL)
+				list_move_tail(&bf->list, &bf_head);
+
+			ath_tx_rc_status(bf, ts, 0, 0, false);
+			ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
+				0, 0);
+
+			bf = bf_next;
+		}
 		return;
 	}
 
 	an = (struct ath_node *)sta->drv_priv;
 	tid = ATH_AN_2_TID(an, bf->bf_tidno);
 
+	/*
+	 * The hardware occasionally sends a tx status for the wrong TID.
+	 * In this case, the BA status cannot be considered valid and all
+	 * subframes need to be retransmitted
+	 */
+	if (bf->bf_tidno != ts->tid)
+		txok = false;
+
 	isaggr = bf_isaggr(bf);
 	memset(ba, 0, WME_BA_BMP_SIZE >> 3);
 
@@ -375,6 +402,9 @@
 		txfail = txpending = 0;
 		bf_next = bf->bf_next;
 
+		skb = bf->bf_mpdu;
+		tx_info = IEEE80211_SKB_CB(skb);
+
 		if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
 			/* transmit completion, subframe is
 			 * acked by block ack */
@@ -428,6 +458,7 @@
 			spin_unlock_bh(&txq->axq_lock);
 
 			if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
+				memcpy(tx_info->control.rates, rates, sizeof(rates));
 				ath_tx_rc_status(bf, ts, nbad, txok, true);
 				rc_update = false;
 			} else {
@@ -487,6 +518,14 @@
 		bf = bf_next;
 	}
 
+	/* prepend un-acked frames to the beginning of the pending frame queue */
+	if (!list_empty(&bf_pending)) {
+		spin_lock_bh(&txq->axq_lock);
+		list_splice(&bf_pending, &tid->buf_q);
+		ath_tx_queue_tid(txq, tid);
+		spin_unlock_bh(&txq->axq_lock);
+	}
+
 	if (tid->state & AGGR_CLEANUP) {
 		if (tid->baw_head == tid->baw_tail) {
 			tid->state &= ~AGGR_ADDBA_COMPLETE;
@@ -499,14 +538,6 @@
 		return;
 	}
 
-	/* prepend un-acked frames to the beginning of the pending frame queue */
-	if (!list_empty(&bf_pending)) {
-		spin_lock_bh(&txq->axq_lock);
-		list_splice(&bf_pending, &tid->buf_q);
-		ath_tx_queue_tid(txq, tid);
-		spin_unlock_bh(&txq->axq_lock);
-	}
-
 	rcu_read_unlock();
 
 	if (needreset)
@@ -941,6 +972,7 @@
 	if (!ATH_TXQ_SETUP(sc, qnum)) {
 		struct ath_txq *txq = &sc->tx.txq[qnum];
 
+		txq->axq_class = subtype;
 		txq->axq_qnum = qnum;
 		txq->axq_link = NULL;
 		INIT_LIST_HEAD(&txq->axq_q);
@@ -958,58 +990,6 @@
 	return &sc->tx.txq[qnum];
 }
 
-int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
-{
-	int qnum;
-
-	switch (qtype) {
-	case ATH9K_TX_QUEUE_DATA:
-		if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
-			ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
-				  "HAL AC %u out of range, max %zu!\n",
-				  haltype, ARRAY_SIZE(sc->tx.hwq_map));
-			return -1;
-		}
-		qnum = sc->tx.hwq_map[haltype];
-		break;
-	case ATH9K_TX_QUEUE_BEACON:
-		qnum = sc->beacon.beaconq;
-		break;
-	case ATH9K_TX_QUEUE_CAB:
-		qnum = sc->beacon.cabq->axq_qnum;
-		break;
-	default:
-		qnum = -1;
-	}
-	return qnum;
-}
-
-struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
-{
-	struct ath_txq *txq = NULL;
-	u16 skb_queue = skb_get_queue_mapping(skb);
-	int qnum;
-
-	qnum = ath_get_hal_qnum(skb_queue, sc);
-	txq = &sc->tx.txq[qnum];
-
-	spin_lock_bh(&txq->axq_lock);
-
-	if (txq->axq_depth >= (ATH_TXBUF - 20)) {
-		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT,
-			  "TX queue: %d is full, depth: %d\n",
-			  qnum, txq->axq_depth);
-		ath_mac80211_stop_queue(sc, skb_queue);
-		txq->stopped = 1;
-		spin_unlock_bh(&txq->axq_lock);
-		return NULL;
-	}
-
-	spin_unlock_bh(&txq->axq_lock);
-
-	return txq;
-}
-
 int ath_txq_update(struct ath_softc *sc, int qnum,
 		   struct ath9k_tx_queue_info *qinfo)
 {
@@ -1688,12 +1668,15 @@
 		bf->bf_frmlen -= padsize;
 	}
 
-	if (conf_is_ht(&hw->conf)) {
+	if (!txctl->paprd && conf_is_ht(&hw->conf)) {
 		bf->bf_state.bf_type |= BUF_HT;
 		if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
 			use_ldpc = true;
 	}
 
+	bf->bf_state.bfs_paprd = txctl->paprd;
+	if (txctl->paprd)
+		bf->bf_state.bfs_paprd_timestamp = jiffies;
 	bf->bf_flags = setup_tx_flags(skb, use_ldpc);
 
 	bf->bf_keytype = get_hw_crypto_keytype(skb);
@@ -1768,6 +1751,9 @@
 			    bf->bf_buf_addr,
 			    txctl->txq->axq_qnum);
 
+	if (bf->bf_state.bfs_paprd)
+		ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
+
 	spin_lock_bh(&txctl->txq->axq_lock);
 
 	if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
@@ -1809,8 +1795,9 @@
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ath_txq *txq = txctl->txq;
 	struct ath_buf *bf;
-	int r;
+	int q, r;
 
 	bf = ath_tx_get_buffer(sc);
 	if (!bf) {
@@ -1820,8 +1807,6 @@
 
 	r = ath_tx_setup_buffer(hw, bf, skb, txctl);
 	if (unlikely(r)) {
-		struct ath_txq *txq = txctl->txq;
-
 		ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
 
 		/* upon ath_tx_processq() this TX queue will be resumed, we
@@ -1829,7 +1814,7 @@
 		 * we will at least have to run TX completionon one buffer
 		 * on the queue */
 		spin_lock_bh(&txq->axq_lock);
-		if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) {
+		if (!txq->stopped && txq->axq_depth > 1) {
 			ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
 			txq->stopped = 1;
 		}
@@ -1840,6 +1825,17 @@
 		return r;
 	}
 
+	q = skb_get_queue_mapping(skb);
+	if (q >= 4)
+		q = 0;
+
+	spin_lock_bh(&txq->axq_lock);
+	if (++sc->tx.pending_frames[q] > ATH_MAX_QDEPTH && !txq->stopped) {
+		ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
+		txq->stopped = 1;
+	}
+	spin_unlock_bh(&txq->axq_lock);
+
 	ath_tx_start_dma(sc, bf, txctl);
 
 	return 0;
@@ -1909,7 +1905,7 @@
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
-	int padpos, padsize;
+	int q, padpos, padsize;
 
 	ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
 
@@ -1948,8 +1944,16 @@
 
 	if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
 		ath9k_tx_status(hw, skb);
-	else
+	else {
+		q = skb_get_queue_mapping(skb);
+		if (q >= 4)
+			q = 0;
+
+		if (--sc->tx.pending_frames[q] < 0)
+			sc->tx.pending_frames[q] = 0;
+
 		ieee80211_tx_status(hw, skb);
+	}
 }
 
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
@@ -1971,8 +1975,18 @@
 	}
 
 	dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
-	ath_tx_complete(sc, skb, bf->aphy, tx_flags);
-	ath_debug_stat_tx(sc, txq, bf, ts);
+
+	if (bf->bf_state.bfs_paprd) {
+		if (time_after(jiffies,
+			       bf->bf_state.bfs_paprd_timestamp +
+			       msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
+			dev_kfree_skb_any(skb);
+		else
+			complete(&sc->paprd_complete);
+	} else {
+		ath_tx_complete(sc, skb, bf->aphy, tx_flags);
+		ath_debug_stat_tx(sc, txq, bf, ts);
+	}
 
 	/*
 	 * Return the list of ath_buf of this mpdu to free queue
@@ -2050,21 +2064,21 @@
 		tx_info->status.rates[i].idx = -1;
 	}
 
-	tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1;
+	tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
 }
 
 static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
 {
 	int qnum;
 
+	qnum = ath_get_mac80211_qnum(txq->axq_class, sc);
+	if (qnum == -1)
+		return;
+
 	spin_lock_bh(&txq->axq_lock);
-	if (txq->stopped &&
-	    sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) {
-		qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc);
-		if (qnum != -1) {
-			ath_mac80211_start_queue(sc, qnum);
+	if (txq->stopped && sc->tx.pending_frames[qnum] < ATH_MAX_QDEPTH) {
+		if (ath_mac80211_start_queue(sc, qnum))
 			txq->stopped = 0;
-		}
 	}
 	spin_unlock_bh(&txq->axq_lock);
 }
@@ -2161,7 +2175,6 @@
 			 * This frame is sent out as a single frame.
 			 * Use hardware retry status for this frame.
 			 */
-			bf->bf_retries = ts.ts_longretry;
 			if (ts.ts_status & ATH9K_TXERR_XRETRY)
 				bf->bf_state.bf_type |= BUF_XRETRY;
 			ath_tx_rc_status(bf, &ts, 0, txok, true);
@@ -2279,8 +2292,18 @@
 
 		txok = !(txs.ts_status & ATH9K_TXERR_MASK);
 
+		/*
+		 * Make sure null func frame is acked before configuring
+		 * hw into ps mode.
+		 */
+		if (bf->bf_isnullfunc && txok) {
+			if ((sc->ps_flags & PS_ENABLED))
+				ath9k_enable_ps(sc);
+			else
+				sc->ps_flags |= PS_NULLFUNC_COMPLETED;
+		}
+
 		if (!bf_isampdu(bf)) {
-			bf->bf_retries = txs.ts_longretry;
 			if (txs.ts_status & ATH9K_TXERR_XRETRY)
 				bf->bf_state.bf_type |= BUF_XRETRY;
 			ath_tx_rc_status(bf, &txs, 0, txok, true);
@@ -2424,62 +2447,44 @@
 	for (acno = 0, ac = &an->ac[acno];
 	     acno < WME_NUM_AC; acno++, ac++) {
 		ac->sched    = false;
+		ac->qnum = sc->tx.hwq_map[acno];
 		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;
-		}
 	}
 }
 
 void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
 {
-	int i;
-	struct ath_atx_ac *ac, *ac_tmp;
-	struct ath_atx_tid *tid, *tid_tmp;
+	struct ath_atx_ac *ac;
+	struct ath_atx_tid *tid;
 	struct ath_txq *txq;
+	int i, tidno;
 
-	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-		if (ATH_TXQ_SETUP(sc, i)) {
-			txq = &sc->tx.txq[i];
+	for (tidno = 0, tid = &an->tid[tidno];
+	     tidno < WME_NUM_TID; tidno++, tid++) {
+		i = tid->ac->qnum;
 
-			spin_lock_bh(&txq->axq_lock);
+		if (!ATH_TXQ_SETUP(sc, i))
+			continue;
 
-			list_for_each_entry_safe(ac,
-					ac_tmp, &txq->axq_acq, list) {
-				tid = list_first_entry(&ac->tid_q,
-						struct ath_atx_tid, list);
-				if (tid && tid->an != an)
-					continue;
-				list_del(&ac->list);
-				ac->sched = false;
+		txq = &sc->tx.txq[i];
+		ac = tid->ac;
 
-				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);
-					tid->state &= ~AGGR_ADDBA_COMPLETE;
-					tid->state &= ~AGGR_CLEANUP;
-				}
-			}
+		spin_lock_bh(&txq->axq_lock);
 
-			spin_unlock_bh(&txq->axq_lock);
+		if (tid->sched) {
+			list_del(&tid->list);
+			tid->sched = false;
 		}
+
+		if (ac->sched) {
+			list_del(&ac->list);
+			tid->ac->sched = false;
+		}
+
+		ath_tid_drain(sc, txq, tid);
+		tid->state &= ~AGGR_ADDBA_COMPLETE;
+		tid->state &= ~AGGR_CLEANUP;
+
+		spin_unlock_bh(&txq->axq_lock);
 	}
 }
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 3a003e6..8674a9935 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -530,7 +530,7 @@
 	/* Size of the data. For ucode and PCM this is in bytes.
 	 * For IV this is number-of-ivs. */
 	__be32 size;
-} __attribute__((__packed__));
+} __packed;
 
 /* Initial Value file format */
 #define B43_IV_OFFSET_MASK	0x7FFF
@@ -540,8 +540,8 @@
 	union {
 		__be16 d16;
 		__be32 d32;
-	} data __attribute__((__packed__));
-} __attribute__((__packed__));
+	} data __packed;
+} __packed;
 
 
 /* Data structures for DMA transmission, per 80211 core. */
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index fa40fdf..10d0aaf 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -333,11 +333,11 @@
 	dma_addr_t dmaaddr;
 
 	if (tx) {
-		dmaaddr = ssb_dma_map_single(ring->dev->dev,
-					     buf, len, DMA_TO_DEVICE);
+		dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
+					 buf, len, DMA_TO_DEVICE);
 	} else {
-		dmaaddr = ssb_dma_map_single(ring->dev->dev,
-					     buf, len, DMA_FROM_DEVICE);
+		dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
+					 buf, len, DMA_FROM_DEVICE);
 	}
 
 	return dmaaddr;
@@ -348,11 +348,11 @@
 			  dma_addr_t addr, size_t len, int tx)
 {
 	if (tx) {
-		ssb_dma_unmap_single(ring->dev->dev,
-				     addr, len, DMA_TO_DEVICE);
+		dma_unmap_single(ring->dev->dev->dma_dev,
+				 addr, len, DMA_TO_DEVICE);
 	} else {
-		ssb_dma_unmap_single(ring->dev->dev,
-				     addr, len, DMA_FROM_DEVICE);
+		dma_unmap_single(ring->dev->dev->dma_dev,
+				 addr, len, DMA_FROM_DEVICE);
 	}
 }
 
@@ -361,7 +361,7 @@
 				 dma_addr_t addr, size_t len)
 {
 	B43_WARN_ON(ring->tx);
-	ssb_dma_sync_single_for_cpu(ring->dev->dev,
+	dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
 				    addr, len, DMA_FROM_DEVICE);
 }
 
@@ -370,8 +370,8 @@
 				    dma_addr_t addr, size_t len)
 {
 	B43_WARN_ON(ring->tx);
-	ssb_dma_sync_single_for_device(ring->dev->dev,
-				       addr, len, DMA_FROM_DEVICE);
+	dma_sync_single_for_device(ring->dev->dev->dma_dev,
+				   addr, len, DMA_FROM_DEVICE);
 }
 
 static inline
@@ -401,9 +401,9 @@
 	 */
 	if (ring->type == B43_DMA_64BIT)
 		flags |= GFP_DMA;
-	ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
-						  B43_DMA_RINGMEMSIZE,
-						  &(ring->dmabase), flags);
+	ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
+					    B43_DMA_RINGMEMSIZE,
+					    &(ring->dmabase), flags);
 	if (!ring->descbase) {
 		b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
 		return -ENOMEM;
@@ -420,8 +420,8 @@
 	if (ring->type == B43_DMA_64BIT)
 		flags |= GFP_DMA;
 
-	ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE,
-				ring->descbase, ring->dmabase, flags);
+	dma_free_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE,
+			  ring->descbase, ring->dmabase);
 }
 
 /* Reset the RX DMA channel */
@@ -528,7 +528,7 @@
 				  dma_addr_t addr,
 				  size_t buffersize, bool dma_to_device)
 {
-	if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
+	if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr)))
 		return 1;
 
 	switch (ring->type) {
@@ -874,10 +874,10 @@
 			goto err_kfree_meta;
 
 		/* test for ability to dma to txhdr_cache */
-		dma_test = ssb_dma_map_single(dev->dev,
-					      ring->txhdr_cache,
-					      b43_txhdr_size(dev),
-					      DMA_TO_DEVICE);
+		dma_test = dma_map_single(dev->dev->dma_dev,
+					  ring->txhdr_cache,
+					  b43_txhdr_size(dev),
+					  DMA_TO_DEVICE);
 
 		if (b43_dma_mapping_error(ring, dma_test,
 					  b43_txhdr_size(dev), 1)) {
@@ -889,10 +889,10 @@
 			if (!ring->txhdr_cache)
 				goto err_kfree_meta;
 
-			dma_test = ssb_dma_map_single(dev->dev,
-						      ring->txhdr_cache,
-						      b43_txhdr_size(dev),
-						      DMA_TO_DEVICE);
+			dma_test = dma_map_single(dev->dev->dma_dev,
+						  ring->txhdr_cache,
+						  b43_txhdr_size(dev),
+						  DMA_TO_DEVICE);
 
 			if (b43_dma_mapping_error(ring, dma_test,
 						  b43_txhdr_size(dev), 1)) {
@@ -903,9 +903,9 @@
 			}
 		}
 
-		ssb_dma_unmap_single(dev->dev,
-				     dma_test, b43_txhdr_size(dev),
-				     DMA_TO_DEVICE);
+		dma_unmap_single(dev->dev->dma_dev,
+				 dma_test, b43_txhdr_size(dev),
+				 DMA_TO_DEVICE);
 	}
 
 	err = alloc_ringmemory(ring);
@@ -1018,9 +1018,12 @@
 	/* Try to set the DMA mask. If it fails, try falling back to a
 	 * lower mask, as we can always also support a lower one. */
 	while (1) {
-		err = ssb_dma_set_mask(dev->dev, mask);
-		if (!err)
-			break;
+		err = dma_set_mask(dev->dev->dma_dev, mask);
+		if (!err) {
+			err = dma_set_coherent_mask(dev->dev->dma_dev, mask);
+			if (!err)
+				break;
+		}
 		if (mask == DMA_BIT_MASK(64)) {
 			mask = DMA_BIT_MASK(32);
 			fallback = 1;
@@ -1221,14 +1224,14 @@
 	meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
 	/* create a bounce buffer in zone_dma on mapping failure. */
 	if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
-		priv_info->bouncebuffer = kmalloc(skb->len, GFP_ATOMIC | GFP_DMA);
+		priv_info->bouncebuffer = kmemdup(skb->data, skb->len,
+						  GFP_ATOMIC | GFP_DMA);
 		if (!priv_info->bouncebuffer) {
 			ring->current_slot = old_top_slot;
 			ring->used_slots = old_used_slots;
 			err = -ENOMEM;
 			goto out_unmap_hdr;
 		}
-		memcpy(priv_info->bouncebuffer, skb->data, skb->len);
 
 		meta->dmaaddr = map_descbuffer(ring, priv_info->bouncebuffer, skb->len, 1);
 		if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index dc91944..a01c210 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -67,7 +67,7 @@
 struct b43_dmadesc32 {
 	__le32 control;
 	__le32 address;
-} __attribute__ ((__packed__));
+} __packed;
 #define B43_DMA32_DCTL_BYTECNT		0x00001FFF
 #define B43_DMA32_DCTL_ADDREXT_MASK		0x00030000
 #define B43_DMA32_DCTL_ADDREXT_SHIFT	16
@@ -140,7 +140,7 @@
 	__le32 control1;
 	__le32 address_low;
 	__le32 address_high;
-} __attribute__ ((__packed__));
+} __packed;
 #define B43_DMA64_DCTL0_DTABLEEND		0x10000000
 #define B43_DMA64_DCTL0_IRQ			0x20000000
 #define B43_DMA64_DCTL0_FRAMEEND		0x40000000
@@ -153,8 +153,8 @@
 	union {
 		struct b43_dmadesc32 dma32;
 		struct b43_dmadesc64 dma64;
-	} __attribute__ ((__packed__));
-} __attribute__ ((__packed__));
+	} __packed;
+} __packed;
 
 /* Misc DMA constants */
 #define B43_DMA_RINGMEMSIZE		PAGE_SIZE
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 7965b70..20631ae 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -108,7 +108,7 @@
 module_param_named(verbose, b43_modparam_verbose, int, 0644);
 MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
 
-int b43_modparam_pio = B43_PIO_DEFAULT;
+static int b43_modparam_pio = B43_PIO_DEFAULT;
 module_param_named(pio, b43_modparam_pio, int, 0644);
 MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO");
 
@@ -1804,7 +1804,7 @@
 			       dma_reason[2], dma_reason[3],
 			       dma_reason[4], dma_reason[5]);
 			b43err(dev->wl, "This device does not support DMA "
-			       "on your system. Please use PIO instead.\n");
+			       "on your system. It will now be switched to PIO.\n");
 			/* Fall back to PIO transfers if we get fatal DMA errors! */
 			dev->use_pio = 1;
 			b43_controller_restart(dev, "DMA error");
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c
index 29bf34c..0dc33b6 100644
--- a/drivers/net/wireless/b43/phy_g.c
+++ b/drivers/net/wireless/b43/phy_g.c
@@ -972,7 +972,7 @@
 		b43_phy_maskset(dev, 0x04A2, 0xFFF0, 0x000B);
 
 		if (phy->rev >= 3) {
-			b43_phy_mask(dev, 0x048A, (u16)~0x8000);
+			b43_phy_mask(dev, 0x048A, 0x7FFF);
 			b43_phy_maskset(dev, 0x0415, 0x8000, 0x36D8);
 			b43_phy_maskset(dev, 0x0416, 0x8000, 0x36D8);
 			b43_phy_maskset(dev, 0x0417, 0xFE00, 0x016D);
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index c6afe9d..fd50eb1 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -1145,7 +1145,7 @@
 		B43_WARN_ON(1);
 	}
 	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
-			(u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE, ctl);
+			~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF, ctl);
 }
 
 static void lpphy_set_tx_power_control(struct b43_wldev *dev,
@@ -1522,11 +1522,11 @@
 	b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xFF);
 	b43_phy_write(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xA);
 	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
-			(u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE,
+			~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF,
 			B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF);
 	b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xF8FF);
 	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
-			(u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE,
+			~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF,
 			B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW);
 
 	if (dev->phy.rev < 2) {
@@ -2698,7 +2698,7 @@
 	return B43_TXPWR_RES_DONE;
 }
 
-void b43_lpphy_op_switch_analog(struct b43_wldev *dev, bool on)
+static void b43_lpphy_op_switch_analog(struct b43_wldev *dev, bool on)
 {
        if (on) {
                b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xfff8);
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 3d6b337..5a72570 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -509,7 +509,8 @@
 	b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001);
 	b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001);
 
-	b43_phy_maskset(dev, B43_NPHY_RFSEQCA, (u16)~B43_NPHY_RFSEQCA_RXDIS,
+	b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
+			~B43_NPHY_RFSEQCA_RXDIS & 0xFFFF,
 			((1 - core) << B43_NPHY_RFSEQCA_RXDIS_SHIFT));
 	b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN,
 			((1 - core) << B43_NPHY_RFSEQCA_TXEN_SHIFT));
@@ -762,7 +763,7 @@
 	if (tmp & 0x1)
 		b43_phy_set(dev, B43_NPHY_SAMP_CMD, B43_NPHY_SAMP_CMD_STOP);
 	else if (tmp & 0x2)
-		b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, (u16)~0x8000);
+		b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
 
 	b43_phy_mask(dev, B43_NPHY_SAMP_CMD, ~0x0004);
 
@@ -1009,7 +1010,7 @@
 			b43_nphy_set_rf_sequence(dev, 5,
 					rfseq_events, rfseq_delays, 3);
 			b43_phy_maskset(dev, B43_NPHY_OVER_DGAIN1,
-				(u16)~B43_NPHY_OVER_DGAIN_CCKDGECV,
+				~B43_NPHY_OVER_DGAIN_CCKDGECV & 0xFFFF,
 				0x5A << B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT);
 
 			if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
@@ -1116,7 +1117,7 @@
 		b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
 
 		b43_phy_mask(dev, B43_NPHY_PIL_DW1,
-				(u16)~B43_NPHY_PIL_DW_64QAM);
+				~B43_NPHY_PIL_DW_64QAM & 0xFFFF);
 		b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
 		b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
 		b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
@@ -2455,7 +2456,8 @@
 		b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp | 0x0600);
 
 		regs[4] = b43_phy_read(dev, B43_NPHY_BBCFG);
-		b43_phy_mask(dev, B43_NPHY_BBCFG, (u16)~B43_NPHY_BBCFG_RSTRX);
+		b43_phy_mask(dev, B43_NPHY_BBCFG,
+			     ~B43_NPHY_BBCFG_RSTRX & 0xFFFF);
 
 		tmp = b43_ntab_read(dev, B43_NTAB16(8, 3));
 		regs[5] = tmp;
@@ -2930,7 +2932,7 @@
 		tmp[5] = b43_phy_read(dev, rfctl[1]);
 
 		b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
-				(u16)~B43_NPHY_RFSEQCA_RXDIS,
+				~B43_NPHY_RFSEQCA_RXDIS & 0xFFFF,
 				((1 - i) << B43_NPHY_RFSEQCA_RXDIS_SHIFT));
 		b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN,
 				(1 - i));
@@ -3291,7 +3293,7 @@
 		b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
 		tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR);
 		b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4);
-		b43_phy_mask(dev, B43_PHY_B_BBCFG, (u16)~0xC000);
+		b43_phy_mask(dev, B43_PHY_B_BBCFG, 0x3FFF);
 		b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32);
 	}
 
diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c
index 4e56b7b..45933cf 100644
--- a/drivers/net/wireless/b43/sdio.c
+++ b/drivers/net/wireless/b43/sdio.c
@@ -182,6 +182,7 @@
 
 static const struct sdio_device_id b43_sdio_ids[] = {
 	{ SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */
+	{ SDIO_DEVICE(0x0092, 0x0004) }, /* C-guys, Inc. EW-CG1102GC */
 	{ },
 };
 
diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c
index 97c7916..9a335da 100644
--- a/drivers/net/wireless/b43/wa.c
+++ b/drivers/net/wireless/b43/wa.c
@@ -382,7 +382,7 @@
 		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 3, 25);
 	}
 
-	b43_phy_maskset(dev, B43_PHY_CCKSHIFTBITS_WA, (u16)~0xFF00, 0x5700);
+	b43_phy_maskset(dev, B43_PHY_CCKSHIFTBITS_WA, 0x00FF, 0x5700);
 	b43_phy_maskset(dev, B43_PHY_OFDM(0x1A), ~0x007F, 0x000F);
 	b43_phy_maskset(dev, B43_PHY_OFDM(0x1A), ~0x3F80, 0x2B80);
 	b43_phy_maskset(dev, B43_PHY_ANTWRSETT, 0xF0FF, 0x0300);
@@ -400,9 +400,9 @@
 	b43_phy_maskset(dev, B43_PHY_OFDM(0x89), ~0x00FF, 0x0020);
 	b43_phy_maskset(dev, B43_PHY_OFDM(0x89), ~0x3F00, 0x0200);
 	b43_phy_maskset(dev, B43_PHY_OFDM(0x82), ~0x00FF, 0x002E);
-	b43_phy_maskset(dev, B43_PHY_OFDM(0x96), (u16)~0xFF00, 0x1A00);
+	b43_phy_maskset(dev, B43_PHY_OFDM(0x96), 0x00FF, 0x1A00);
 	b43_phy_maskset(dev, B43_PHY_OFDM(0x81), ~0x00FF, 0x0028);
-	b43_phy_maskset(dev, B43_PHY_OFDM(0x81), (u16)~0xFF00, 0x2C00);
+	b43_phy_maskset(dev, B43_PHY_OFDM(0x81), 0x00FF, 0x2C00);
 	if (phy->rev == 1) {
 		b43_phy_write(dev, B43_PHY_PEAK_COUNT, 0x092B);
 		b43_phy_maskset(dev, B43_PHY_OFDM(0x1B), ~0x001E, 0x0002);
@@ -412,7 +412,7 @@
 		b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, ~0x000F, 0x0004);
 		if (phy->rev >= 6) {
 			b43_phy_write(dev, B43_PHY_OFDM(0x22), 0x287A);
-			b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, (u16)~0xF000, 0x3000);
+			b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, 0x0FFF, 0x3000);
 		}
 	}
 	b43_phy_maskset(dev, B43_PHY_DIVSRCHIDX, 0x8080, 0x7874);
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index d23ff9f..d4cf9b3 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -10,8 +10,8 @@
 		union {				\
 			__le32 data;		\
 			__u8 raw[size];		\
-		} __attribute__((__packed__));	\
-	} __attribute__((__packed__))
+		} __packed;	\
+	} __packed
 
 /* struct b43_plcp_hdr4 */
 _b43_declare_plcp_hdr(4);
@@ -57,7 +57,7 @@
 			__u8 rts_frame[16];		/* The RTS frame (if used) */
 			PAD_BYTES(2);
 			struct b43_plcp_hdr6 plcp;	/* Main PLCP header */
-		} new_format __attribute__ ((__packed__));
+		} new_format __packed;
 
 		/* The old r351 format. */
 		struct {
@@ -68,10 +68,10 @@
 			__u8 rts_frame[16];		/* The RTS frame (if used) */
 			PAD_BYTES(2);
 			struct b43_plcp_hdr6 plcp;	/* Main PLCP header */
-		} old_format __attribute__ ((__packed__));
+		} old_format __packed;
 
-	} __attribute__ ((__packed__));
-} __attribute__ ((__packed__));
+	} __packed;
+} __packed;
 
 /* MAC TX control */
 #define B43_TXH_MAC_USEFBR		0x10000000 /* Use fallback rate for this AMPDU */
@@ -218,20 +218,20 @@
 		struct {
 			__u8 jssi;	/* PHY RX Status 1: JSSI */
 			__u8 sig_qual;	/* PHY RX Status 1: Signal Quality */
-		} __attribute__ ((__packed__));
+		} __packed;
 
 		/* RSSI for N-PHYs */
 		struct {
 			__s8 power0;	/* PHY RX Status 1: Power 0 */
 			__s8 power1;	/* PHY RX Status 1: Power 1 */
-		} __attribute__ ((__packed__));
-	} __attribute__ ((__packed__));
+		} __packed;
+	} __packed;
 	__le16 phy_status2;	/* PHY RX Status 2 */
 	__le16 phy_status3;	/* PHY RX Status 3 */
 	__le32 mac_status;	/* MAC RX status */
 	__le16 mac_time;
 	__le16 channel;
-} __attribute__ ((__packed__));
+} __packed;
 
 /* PHY RX Status 0 */
 #define B43_RX_PHYST0_GAINCTL		0x4000 /* Gain Control */
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index 89fe2f9..c81b2f5 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -372,7 +372,7 @@
 	/* Size of the data. For ucode and PCM this is in bytes.
 	 * For IV this is number-of-ivs. */
 	__be32 size;
-} __attribute__((__packed__));
+} __packed;
 
 /* Initial Value file format */
 #define B43legacy_IV_OFFSET_MASK	0x7FFF
@@ -382,8 +382,8 @@
 	union {
 		__be16 d16;
 		__be32 d32;
-	} data __attribute__((__packed__));
-} __attribute__((__packed__));
+	} data __packed;
+} __packed;
 
 #define B43legacy_PHYMODE(phytype)	(1 << (phytype))
 #define B43legacy_PHYMODE_B		B43legacy_PHYMODE	\
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index e91520d..e03e01d 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -394,11 +394,11 @@
 	dma_addr_t dmaaddr;
 
 	if (tx)
-		dmaaddr = ssb_dma_map_single(ring->dev->dev,
+		dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
 					     buf, len,
 					     DMA_TO_DEVICE);
 	else
-		dmaaddr = ssb_dma_map_single(ring->dev->dev,
+		dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
 					     buf, len,
 					     DMA_FROM_DEVICE);
 
@@ -412,11 +412,11 @@
 		      int tx)
 {
 	if (tx)
-		ssb_dma_unmap_single(ring->dev->dev,
+		dma_unmap_single(ring->dev->dev->dma_dev,
 				     addr, len,
 				     DMA_TO_DEVICE);
 	else
-		ssb_dma_unmap_single(ring->dev->dev,
+		dma_unmap_single(ring->dev->dev->dma_dev,
 				     addr, len,
 				     DMA_FROM_DEVICE);
 }
@@ -428,8 +428,8 @@
 {
 	B43legacy_WARN_ON(ring->tx);
 
-	ssb_dma_sync_single_for_cpu(ring->dev->dev,
-				    addr, len, DMA_FROM_DEVICE);
+	dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
+				addr, len, DMA_FROM_DEVICE);
 }
 
 static inline
@@ -439,8 +439,8 @@
 {
 	B43legacy_WARN_ON(ring->tx);
 
-	ssb_dma_sync_single_for_device(ring->dev->dev,
-				       addr, len, DMA_FROM_DEVICE);
+	dma_sync_single_for_device(ring->dev->dev->dma_dev,
+				   addr, len, DMA_FROM_DEVICE);
 }
 
 static inline
@@ -460,10 +460,10 @@
 static int alloc_ringmemory(struct b43legacy_dmaring *ring)
 {
 	/* GFP flags must match the flags in free_ringmemory()! */
-	ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
-						  B43legacy_DMA_RINGMEMSIZE,
-						  &(ring->dmabase),
-						  GFP_KERNEL);
+	ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
+					    B43legacy_DMA_RINGMEMSIZE,
+					    &(ring->dmabase),
+					    GFP_KERNEL);
 	if (!ring->descbase) {
 		b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
 			     " failed\n");
@@ -476,8 +476,8 @@
 
 static void free_ringmemory(struct b43legacy_dmaring *ring)
 {
-	ssb_dma_free_consistent(ring->dev->dev, B43legacy_DMA_RINGMEMSIZE,
-				ring->descbase, ring->dmabase, GFP_KERNEL);
+	dma_free_coherent(ring->dev->dev->dma_dev, B43legacy_DMA_RINGMEMSIZE,
+			  ring->descbase, ring->dmabase);
 }
 
 /* Reset the RX DMA channel */
@@ -589,7 +589,7 @@
 					 size_t buffersize,
 					 bool dma_to_device)
 {
-	if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
+	if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr)))
 		return 1;
 
 	switch (ring->type) {
@@ -906,7 +906,7 @@
 			goto err_kfree_meta;
 
 		/* test for ability to dma to txhdr_cache */
-		dma_test = ssb_dma_map_single(dev->dev, ring->txhdr_cache,
+		dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache,
 					      sizeof(struct b43legacy_txhdr_fw3),
 					      DMA_TO_DEVICE);
 
@@ -920,7 +920,7 @@
 			if (!ring->txhdr_cache)
 				goto err_kfree_meta;
 
-			dma_test = ssb_dma_map_single(dev->dev,
+			dma_test = dma_map_single(dev->dev->dma_dev,
 					ring->txhdr_cache,
 					sizeof(struct b43legacy_txhdr_fw3),
 					DMA_TO_DEVICE);
@@ -930,9 +930,9 @@
 				goto err_kfree_txhdr_cache;
 		}
 
-		ssb_dma_unmap_single(dev->dev, dma_test,
-				     sizeof(struct b43legacy_txhdr_fw3),
-				     DMA_TO_DEVICE);
+		dma_unmap_single(dev->dev->dma_dev, dma_test,
+				 sizeof(struct b43legacy_txhdr_fw3),
+				 DMA_TO_DEVICE);
 	}
 
 	ring->nr_slots = nr_slots;
@@ -1040,9 +1040,12 @@
 	/* Try to set the DMA mask. If it fails, try falling back to a
 	 * lower mask, as we can always also support a lower one. */
 	while (1) {
-		err = ssb_dma_set_mask(dev->dev, mask);
-		if (!err)
-			break;
+		err = dma_set_mask(dev->dev->dma_dev, mask);
+		if (!err) {
+			err = dma_set_coherent_mask(dev->dev->dma_dev, mask);
+			if (!err)
+				break;
+		}
 		if (mask == DMA_BIT_MASK(64)) {
 			mask = DMA_BIT_MASK(32);
 			fallback = 1;
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h
index f968104..f89c342 100644
--- a/drivers/net/wireless/b43legacy/dma.h
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -72,7 +72,7 @@
 struct b43legacy_dmadesc32 {
 	__le32 control;
 	__le32 address;
-} __attribute__((__packed__));
+} __packed;
 #define B43legacy_DMA32_DCTL_BYTECNT		0x00001FFF
 #define B43legacy_DMA32_DCTL_ADDREXT_MASK	0x00030000
 #define B43legacy_DMA32_DCTL_ADDREXT_SHIFT	16
@@ -147,7 +147,7 @@
 	__le32 control1;
 	__le32 address_low;
 	__le32 address_high;
-} __attribute__((__packed__));
+} __packed;
 #define B43legacy_DMA64_DCTL0_DTABLEEND		0x10000000
 #define B43legacy_DMA64_DCTL0_IRQ		0x20000000
 #define B43legacy_DMA64_DCTL0_FRAMEEND		0x40000000
@@ -162,8 +162,8 @@
 	union {
 		struct b43legacy_dmadesc32 dma32;
 		struct b43legacy_dmadesc64 dma64;
-	} __attribute__((__packed__));
-} __attribute__((__packed__));
+	} __packed;
+} __packed;
 
 
 /* Misc DMA constants */
diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h
index 9163308..289db00 100644
--- a/drivers/net/wireless/b43legacy/xmit.h
+++ b/drivers/net/wireless/b43legacy/xmit.h
@@ -9,8 +9,8 @@
 		union {				\
 			__le32 data;		\
 			__u8 raw[size];		\
-		} __attribute__((__packed__));	\
-	} __attribute__((__packed__))
+		} __packed;	\
+	} __packed
 
 /* struct b43legacy_plcp_hdr4 */
 _b43legacy_declare_plcp_hdr(4);
@@ -39,7 +39,7 @@
 	struct b43legacy_plcp_hdr6 rts_plcp;	/* RTS PLCP */
 	__u8 rts_frame[18];			/* The RTS frame (if used) */
 	struct b43legacy_plcp_hdr6 plcp;
-} __attribute__((__packed__));
+} __packed;
 
 /* MAC TX control */
 #define B43legacy_TX4_MAC_KEYIDX	0x0FF00000 /* Security key index */
@@ -123,7 +123,7 @@
 	__le16 seq;
 	u8 phy_stat;
 	PAD_BYTES(1);
-} __attribute__((__packed__));
+} __packed;
 
 
 /* Receive header for v3 firmware. */
@@ -138,7 +138,7 @@
 	__le16 mac_status;	/* MAC RX status */
 	__le16 mac_time;
 	__le16 channel;
-} __attribute__((__packed__));
+} __packed;
 
 
 /* PHY RX Status 0 */
diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h
index 7f9d8d9..ed98ce7 100644
--- a/drivers/net/wireless/hostap/hostap_80211.h
+++ b/drivers/net/wireless/hostap/hostap_80211.h
@@ -19,35 +19,35 @@
 			__le16 status_code;
 			/* possibly followed by Challenge text */
 			u8 variable[0];
-		} __attribute__ ((packed)) auth;
+		} __packed auth;
 		struct {
 			__le16 reason_code;
-		} __attribute__ ((packed)) deauth;
+		} __packed deauth;
 		struct {
 			__le16 capab_info;
 			__le16 listen_interval;
 			/* followed by SSID and Supported rates */
 			u8 variable[0];
-		} __attribute__ ((packed)) assoc_req;
+		} __packed assoc_req;
 		struct {
 			__le16 capab_info;
 			__le16 status_code;
 			__le16 aid;
 			/* followed by Supported rates */
 			u8 variable[0];
-		} __attribute__ ((packed)) assoc_resp, reassoc_resp;
+		} __packed assoc_resp, reassoc_resp;
 		struct {
 			__le16 capab_info;
 			__le16 listen_interval;
 			u8 current_ap[6];
 			/* followed by SSID and Supported rates */
 			u8 variable[0];
-		} __attribute__ ((packed)) reassoc_req;
+		} __packed reassoc_req;
 		struct {
 			__le16 reason_code;
-		} __attribute__ ((packed)) disassoc;
+		} __packed disassoc;
 		struct {
-		} __attribute__ ((packed)) probe_req;
+		} __packed probe_req;
 		struct {
 			u8 timestamp[8];
 			__le16 beacon_int;
@@ -55,9 +55,9 @@
 			/* followed by some of SSID, Supported rates,
 			 * FH Params, DS Params, CF Params, IBSS Params, TIM */
 			u8 variable[0];
-		} __attribute__ ((packed)) beacon, probe_resp;
+		} __packed beacon, probe_resp;
 	} u;
-} __attribute__ ((packed));
+} __packed;
 
 
 #define IEEE80211_MGMT_HDR_LEN 24
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index cb3c25f..dbb9869 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -688,7 +688,7 @@
 	struct ap_data *ap = data;
 	struct net_device *dev = ap->local->dev;
 	struct ieee80211_hdr *hdr;
-	u16 fc, status;
+	u16 status;
 	__le16 *pos;
 	struct sta_info *sta = NULL;
 	char *txt = NULL;
@@ -699,7 +699,6 @@
 	}
 
 	hdr = (struct ieee80211_hdr *) skb->data;
-	fc = le16_to_cpu(hdr->frame_control);
 	if ((!ieee80211_is_assoc_resp(hdr->frame_control) &&
 	     !ieee80211_is_reassoc_resp(hdr->frame_control)) ||
 	    skb->len < IEEE80211_MGMT_HDR_LEN + 4) {
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
index 90b64b09..4230102 100644
--- a/drivers/net/wireless/hostap/hostap_common.h
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -179,7 +179,7 @@
 	__le16 variant;
 	__le16 major;
 	__le16 minor;
-} __attribute__ ((packed));
+} __packed;
 
 #define HFA384X_COMP_ID_PRI 0x15
 #define HFA384X_COMP_ID_STA 0x1f
@@ -192,14 +192,14 @@
 	__le16 variant;
 	__le16 bottom;
 	__le16 top;
-} __attribute__ ((packed));
+} __packed;
 
 
 struct hfa384x_build_id
 {
 	__le16 pri_seq;
 	__le16 sec_seq;
-} __attribute__ ((packed));
+} __packed;
 
 /* FD01 - Download Buffer */
 struct hfa384x_rid_download_buffer
@@ -207,14 +207,14 @@
 	__le16 page;
 	__le16 offset;
 	__le16 length;
-} __attribute__ ((packed));
+} __packed;
 
 /* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */
 struct hfa384x_comms_quality {
 	__le16 comm_qual; /* 0 .. 92 */
 	__le16 signal_level; /* 27 .. 154 */
 	__le16 noise_level; /* 27 .. 154 */
-} __attribute__ ((packed));
+} __packed;
 
 
 /* netdevice private ioctls (used, e.g., with iwpriv from user space) */
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index eb57d1e..25a2722 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -186,7 +186,7 @@
 		return -ENOBUFS;
 
 	/* verify that there is room for wds# postfix in the interface name */
-	if (strlen(local->dev->name) > IFNAMSIZ - 5) {
+	if (strlen(local->dev->name) >= IFNAMSIZ - 5) {
 		printk(KERN_DEBUG "'%s' too long base device name\n",
 		       local->dev->name);
 		return -EINVAL;
@@ -741,9 +741,7 @@
 	local_info_t *local =
 		container_of(work, local_info_t, set_multicast_list_queue);
 	struct net_device *dev = local->dev;
-	struct hostap_interface *iface;
 
-	iface = netdev_priv(dev);
 	if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE,
 			    local->is_promisc)) {
 		printk(KERN_INFO "%s: %sabling promiscuous mode failed\n",
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
index 1ba33be..1c66b3c 100644
--- a/drivers/net/wireless/hostap/hostap_wlan.h
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -31,14 +31,14 @@
 	u32 did;
 	u16 status, len;
 	u32 data;
-} __attribute__ ((packed));
+} __packed;
 
 struct linux_wlan_ng_prism_hdr {
 	u32 msgcode, msglen;
 	char devname[16];
 	struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal,
 		noise, rate, istx, frmlen;
-} __attribute__ ((packed));
+} __packed;
 
 struct linux_wlan_ng_cap_hdr {
 	__be32 version;
@@ -55,7 +55,7 @@
 	__be32 ssi_noise;
 	__be32 preamble;
 	__be32 encoding;
-} __attribute__ ((packed));
+} __packed;
 
 struct hostap_radiotap_rx {
 	struct ieee80211_radiotap_header hdr;
@@ -66,7 +66,7 @@
 	__le16 chan_flags;
 	s8 dbm_antsignal;
 	s8 dbm_antnoise;
-} __attribute__ ((packed));
+} __packed;
 
 #define LWNG_CAP_DID_BASE   (4 | (1 << 6)) /* section 4, group 1 */
 #define LWNG_CAPHDR_VERSION 0x80211001
@@ -97,7 +97,7 @@
 	__be16 len;
 
 	/* followed by frame data; max 2304 bytes */
-} __attribute__ ((packed));
+} __packed;
 
 
 struct hfa384x_tx_frame {
@@ -126,14 +126,14 @@
 	__be16 len;
 
 	/* followed by frame data; max 2304 bytes */
-} __attribute__ ((packed));
+} __packed;
 
 
 struct hfa384x_rid_hdr
 {
 	__le16 len;
 	__le16 rid;
-} __attribute__ ((packed));
+} __packed;
 
 
 /* Macro for converting signal levels (range 27 .. 154) to wireless ext
@@ -145,24 +145,24 @@
 struct hfa384x_scan_request {
 	__le16 channel_list;
 	__le16 txrate; /* HFA384X_RATES_* */
-} __attribute__ ((packed));
+} __packed;
 
 struct hfa384x_hostscan_request {
 	__le16 channel_list;
 	__le16 txrate;
 	__le16 target_ssid_len;
 	u8 target_ssid[32];
-} __attribute__ ((packed));
+} __packed;
 
 struct hfa384x_join_request {
 	u8 bssid[6];
 	__le16 channel;
-} __attribute__ ((packed));
+} __packed;
 
 struct hfa384x_info_frame {
 	__le16 len;
 	__le16 type;
-} __attribute__ ((packed));
+} __packed;
 
 struct hfa384x_comm_tallies {
 	__le16 tx_unicast_frames;
@@ -186,7 +186,7 @@
 	__le16 rx_discards_wep_undecryptable;
 	__le16 rx_message_in_msg_fragments;
 	__le16 rx_message_in_bad_msg_fragments;
-} __attribute__ ((packed));
+} __packed;
 
 struct hfa384x_comm_tallies32 {
 	__le32 tx_unicast_frames;
@@ -210,7 +210,7 @@
 	__le32 rx_discards_wep_undecryptable;
 	__le32 rx_message_in_msg_fragments;
 	__le32 rx_message_in_bad_msg_fragments;
-} __attribute__ ((packed));
+} __packed;
 
 struct hfa384x_scan_result_hdr {
 	__le16 reserved;
@@ -219,7 +219,7 @@
 #define HFA384X_SCAN_HOST_INITIATED 1
 #define HFA384X_SCAN_FIRMWARE_INITIATED 2
 #define HFA384X_SCAN_INQUIRY_FROM_HOST 3
-} __attribute__ ((packed));
+} __packed;
 
 #define HFA384X_SCAN_MAX_RESULTS 32
 
@@ -234,7 +234,7 @@
 	u8 ssid[32];
 	u8 sup_rates[10];
 	__le16 rate;
-} __attribute__ ((packed));
+} __packed;
 
 struct hfa384x_hostscan_result {
 	__le16 chid;
@@ -248,7 +248,7 @@
 	u8 sup_rates[10];
 	__le16 rate;
 	__le16 atim;
-} __attribute__ ((packed));
+} __packed;
 
 struct comm_tallies_sums {
 	unsigned int tx_unicast_frames;
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 0bd4dfa..c24c5ef 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -174,7 +174,7 @@
 #define DRV_DESCRIPTION	"Intel(R) PRO/Wireless 2100 Network Driver"
 #define DRV_COPYRIGHT	"Copyright(c) 2003-2006 Intel Corporation"
 
-struct pm_qos_request_list *ipw2100_pm_qos_req;
+static struct pm_qos_request_list ipw2100_pm_qos_req;
 
 /* Debugging stuff */
 #ifdef CONFIG_IPW2100_DEBUG
@@ -1741,7 +1741,7 @@
 	/* the ipw2100 hardware really doesn't want power management delays
 	 * longer than 175usec
 	 */
-	pm_qos_update_request(ipw2100_pm_qos_req, 175);
+	pm_qos_update_request(&ipw2100_pm_qos_req, 175);
 
 	/* If the interrupt is enabled, turn it off... */
 	spin_lock_irqsave(&priv->low_lock, flags);
@@ -1889,7 +1889,7 @@
 	ipw2100_disable_interrupts(priv);
 	spin_unlock_irqrestore(&priv->low_lock, flags);
 
-	pm_qos_update_request(ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
+	pm_qos_update_request(&ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
 
 	/* We have to signal any supplicant if we are disassociating */
 	if (associated)
@@ -3467,10 +3467,8 @@
 	dma_addr_t p;
 
 	priv->msg_buffers =
-	    (struct ipw2100_tx_packet *)kmalloc(IPW_COMMAND_POOL_SIZE *
-						sizeof(struct
-						       ipw2100_tx_packet),
-						GFP_KERNEL);
+	    kmalloc(IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet),
+		    GFP_KERNEL);
 	if (!priv->msg_buffers) {
 		printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg "
 		       "buffers.\n", priv->net_dev->name);
@@ -4499,10 +4497,8 @@
 	}
 
 	priv->tx_buffers =
-	    (struct ipw2100_tx_packet *)kmalloc(TX_PENDED_QUEUE_LENGTH *
-						sizeof(struct
-						       ipw2100_tx_packet),
-						GFP_ATOMIC);
+	    kmalloc(TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet),
+		    GFP_ATOMIC);
 	if (!priv->tx_buffers) {
 		printk(KERN_ERR DRV_NAME
 		       ": %s: alloc failed form tx buffers.\n",
@@ -4651,9 +4647,9 @@
 	/*
 	 * allocate packets
 	 */
-	priv->rx_buffers = (struct ipw2100_rx_packet *)
-	    kmalloc(RX_QUEUE_LENGTH * sizeof(struct ipw2100_rx_packet),
-		    GFP_KERNEL);
+	priv->rx_buffers = kmalloc(RX_QUEUE_LENGTH *
+				   sizeof(struct ipw2100_rx_packet),
+				   GFP_KERNEL);
 	if (!priv->rx_buffers) {
 		IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
 
@@ -5233,7 +5229,7 @@
 	u8 auth_mode;
 	u8 replay_counters_number;
 	u8 unicast_using_group;
-} __attribute__ ((packed));
+} __packed;
 
 static int ipw2100_set_security_information(struct ipw2100_priv *priv,
 					    int auth_mode,
@@ -6669,8 +6665,8 @@
 	if (ret)
 		goto out;
 
-	ipw2100_pm_qos_req = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,
-			PM_QOS_DEFAULT_VALUE);
+	pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+			   PM_QOS_DEFAULT_VALUE);
 #ifdef CONFIG_IPW2100_DEBUG
 	ipw2100_debug_level = debug;
 	ret = driver_create_file(&ipw2100_pci_driver.driver,
@@ -6692,7 +6688,7 @@
 			   &driver_attr_debug_level);
 #endif
 	pci_unregister_driver(&ipw2100_pci_driver);
-	pm_qos_remove_request(ipw2100_pm_qos_req);
+	pm_qos_remove_request(&ipw2100_pm_qos_req);
 }
 
 module_init(ipw2100_init);
@@ -8475,7 +8471,7 @@
 	short mode;
 	unsigned int fw_size;
 	unsigned int uc_size;
-} __attribute__ ((packed));
+} __packed;
 
 static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
 {
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h
index 1eab0d6..838002b 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.h
+++ b/drivers/net/wireless/ipw2x00/ipw2100.h
@@ -164,7 +164,7 @@
 		} fields;
 		u8 field;
 	} info;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw2100_bd {
 	u32 host_addr;
@@ -174,7 +174,7 @@
 	 * 1st TBD) */
 	u8 num_fragments;
 	u8 reserved[6];
-} __attribute__ ((packed));
+} __packed;
 
 #define IPW_BD_QUEUE_LENGTH(n) (1<<n)
 #define IPW_BD_ALIGNMENT(L)    (L*sizeof(struct ipw2100_bd))
@@ -232,7 +232,7 @@
 #define IPW_STATUS_FLAG_WEP_ENCRYPTED	(1<<1)
 #define IPW_STATUS_FLAG_CRC_ERROR       (1<<2)
 	u8 rssi;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw2100_status_queue {
 	/* driver (virtual) pointer to queue */
@@ -293,7 +293,7 @@
 	u32 reserved1[3];
 	u32 *ordinal1_ptr;
 	u32 *ordinal2_ptr;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw2100_data_header {
 	u32 host_command_reg;
@@ -307,7 +307,7 @@
 	u8 src_addr[ETH_ALEN];
 	u8 dst_addr[ETH_ALEN];
 	u16 fragment_size;
-} __attribute__ ((packed));
+} __packed;
 
 /* Host command data structure */
 struct host_command {
@@ -316,7 +316,7 @@
 	u32 host_command_sequence;	// UNIQUE COMMAND NUMBER (ID)
 	u32 host_command_length;	// LENGTH
 	u32 host_command_parameters[HOST_COMMAND_PARAMS_REG_LEN];	// COMMAND PARAMETERS
-} __attribute__ ((packed));
+} __packed;
 
 typedef enum {
 	POWER_ON_RESET,
@@ -382,7 +382,7 @@
 	u32 hnhdr_size;		/* size in bytes of data
 				   or number of entries, if table.
 				   Does NOT include header */
-} __attribute__ ((packed));
+} __packed;
 
 #define MAX_KEY_SIZE	16
 #define	MAX_KEYS	8
@@ -814,7 +814,7 @@
 		struct ipw2100_notification notification;
 		struct ipw2100_cmd_header command;
 	} rx_data;
-} __attribute__ ((packed));
+} __packed;
 
 /* Bit 0-7 are for 802.11b tx rates - .  Bit 5-7 are reserved */
 #define TX_RATE_1_MBIT              0x0001
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 3aa3bb1..cb2552a 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -96,7 +96,7 @@
 static u32 ipw_debug_level;
 static int associate;
 static int auto_create = 1;
-static int led_support = 0;
+static int led_support = 1;
 static int disable = 0;
 static int bt_coexist = 0;
 static int hwcrypto = 0;
@@ -6624,13 +6624,12 @@
 		return -EINVAL;
 
 	if (wrqu->data.length) {
-		buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+		buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
 		if (buf == NULL) {
 			err = -ENOMEM;
 			goto out;
 		}
 
-		memcpy(buf, extra, wrqu->data.length);
 		kfree(ieee->wpa_ie);
 		ieee->wpa_ie = buf;
 		ieee->wpa_ie_len = wrqu->data.length;
@@ -12083,7 +12082,7 @@
 MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
 
 module_param_named(led, led_support, int, 0444);
-MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)");
+MODULE_PARM_DESC(led, "enable led control on some systems (default 1 on)");
 
 module_param(debug, int, 0444);
 MODULE_PARM_DESC(debug, "debug output mask");
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h
index bf0eeb2..d7d049c 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.h
+++ b/drivers/net/wireless/ipw2x00/ipw2200.h
@@ -388,7 +388,7 @@
 	dma_addr_t dma_addr;		/**< physical addr for BD's */
 	int low_mark;		       /**< low watermark, resume queue if free space more than this */
 	int high_mark;		       /**< high watermark, stop queue if free space less than this */
-} __attribute__ ((packed)); /* XXX */
+} __packed; /* XXX */
 
 struct machdr32 {
 	__le16 frame_ctl;
@@ -399,7 +399,7 @@
 	__le16 seq_ctrl;		// more endians!
 	u8 addr4[MACADRR_BYTE_LEN];
 	__le16 qos_ctrl;
-} __attribute__ ((packed));
+} __packed;
 
 struct machdr30 {
 	__le16 frame_ctl;
@@ -409,7 +409,7 @@
 	u8 addr3[MACADRR_BYTE_LEN];
 	__le16 seq_ctrl;		// more endians!
 	u8 addr4[MACADRR_BYTE_LEN];
-} __attribute__ ((packed));
+} __packed;
 
 struct machdr26 {
 	__le16 frame_ctl;
@@ -419,7 +419,7 @@
 	u8 addr3[MACADRR_BYTE_LEN];
 	__le16 seq_ctrl;		// more endians!
 	__le16 qos_ctrl;
-} __attribute__ ((packed));
+} __packed;
 
 struct machdr24 {
 	__le16 frame_ctl;
@@ -428,20 +428,20 @@
 	u8 addr2[MACADRR_BYTE_LEN];
 	u8 addr3[MACADRR_BYTE_LEN];
 	__le16 seq_ctrl;		// more endians!
-} __attribute__ ((packed));
+} __packed;
 
 // TX TFD with 32 byte MAC Header
 struct tx_tfd_32 {
 	struct machdr32 mchdr;	// 32
 	__le32 uivplaceholder[2];	// 8
-} __attribute__ ((packed));
+} __packed;
 
 // TX TFD with 30 byte MAC Header
 struct tx_tfd_30 {
 	struct machdr30 mchdr;	// 30
 	u8 reserved[2];		// 2
 	__le32 uivplaceholder[2];	// 8
-} __attribute__ ((packed));
+} __packed;
 
 // tx tfd with 26 byte mac header
 struct tx_tfd_26 {
@@ -449,14 +449,14 @@
 	u8 reserved1[2];	// 2
 	__le32 uivplaceholder[2];	// 8
 	u8 reserved2[4];	// 4
-} __attribute__ ((packed));
+} __packed;
 
 // tx tfd with 24 byte mac header
 struct tx_tfd_24 {
 	struct machdr24 mchdr;	// 24
 	__le32 uivplaceholder[2];	// 8
 	u8 reserved[8];		// 8
-} __attribute__ ((packed));
+} __packed;
 
 #define DCT_WEP_KEY_FIELD_LENGTH 16
 
@@ -465,7 +465,7 @@
 	u8 length;
 	__le16 reserved;
 	u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct tfd_data {
 	/* Header */
@@ -504,14 +504,14 @@
 	__le32 num_chunks;
 	__le32 chunk_ptr[NUM_TFD_CHUNKS];
 	__le16 chunk_len[NUM_TFD_CHUNKS];
-} __attribute__ ((packed));
+} __packed;
 
 struct txrx_control_flags {
 	u8 message_type;
 	u8 rx_seq_num;
 	u8 control_bits;
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 #define  TFD_SIZE                           128
 #define  TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH   (TFD_SIZE - sizeof(struct txrx_control_flags))
@@ -523,7 +523,7 @@
 		struct tfd_command cmd;
 		u8 raw[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH];
 	} u;
-} __attribute__ ((packed));
+} __packed;
 
 typedef void destructor_func(const void *);
 
@@ -559,7 +559,7 @@
 		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
 		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
 	} failed;
-} __attribute__ ((packed));
+} __packed;
 
 /* statistics command response */
 struct ipw_cmd_stats {
@@ -586,13 +586,13 @@
 	__le16 rx_autodetec_no_ofdm;
 	__le16 rx_autodetec_no_barker;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct notif_channel_result {
 	u8 channel_num;
 	struct ipw_cmd_stats stats;
 	u8 uReserved;
-} __attribute__ ((packed));
+} __packed;
 
 #define SCAN_COMPLETED_STATUS_COMPLETE  1
 #define SCAN_COMPLETED_STATUS_ABORTED   2
@@ -602,24 +602,24 @@
 	u8 num_channels;
 	u8 status;
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct notif_frag_length {
 	__le16 frag_length;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct notif_beacon_state {
 	__le32 state;
 	__le32 number;
-} __attribute__ ((packed));
+} __packed;
 
 struct notif_tgi_tx_key {
 	u8 key_state;
 	u8 security_type;
 	u8 station_index;
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 #define SILENCE_OVER_THRESH (1)
 #define SILENCE_UNDER_THRESH (2)
@@ -631,25 +631,25 @@
 	struct rate_histogram histogram;
 	u8 silence_notification_type;	/* SILENCE_OVER/UNDER_THRESH */
 	__le16 silence_count;
-} __attribute__ ((packed));
+} __packed;
 
 struct notif_association {
 	u8 state;
-} __attribute__ ((packed));
+} __packed;
 
 struct notif_authenticate {
 	u8 state;
 	struct machdr24 addr;
 	__le16 status;
-} __attribute__ ((packed));
+} __packed;
 
 struct notif_calibration {
 	u8 data[104];
-} __attribute__ ((packed));
+} __packed;
 
 struct notif_noise {
 	__le32 value;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_rx_notification {
 	u8 reserved[8];
@@ -669,7 +669,7 @@
 		struct notif_noise noise;
 		u8 raw[0];
 	} u;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_rx_frame {
 	__le32 reserved1;
@@ -692,14 +692,14 @@
 	u8 rtscts_seen;		// 0x1 RTS seen ; 0x2 CTS seen
 	__le16 length;
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_rx_header {
 	u8 message_type;
 	u8 rx_seq_num;
 	u8 control_bits;
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_rx_packet {
 	struct ipw_rx_header header;
@@ -707,7 +707,7 @@
 		struct ipw_rx_frame frame;
 		struct ipw_rx_notification notification;
 	} u;
-} __attribute__ ((packed));
+} __packed;
 
 #define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12
 #define IPW_RX_FRAME_SIZE        (unsigned int)(sizeof(struct ipw_rx_header) + \
@@ -717,7 +717,7 @@
 	dma_addr_t dma_addr;
 	struct sk_buff *skb;
 	struct list_head list;
-};				/* Not transferred over network, so not  __attribute__ ((packed)) */
+};				/* Not transferred over network, so not  __packed */
 
 struct ipw_rx_queue {
 	struct ipw_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
@@ -730,7 +730,7 @@
 	struct list_head rx_free;	/* Own an SKBs */
 	struct list_head rx_used;	/* No SKB allocated */
 	spinlock_t lock;
-};				/* Not transferred over network, so not  __attribute__ ((packed)) */
+};				/* Not transferred over network, so not  __packed */
 
 struct alive_command_responce {
 	u8 alive_command;
@@ -745,21 +745,21 @@
 	__le16 reserved4;
 	u8 time_stamp[5];	/* month, day, year, hours, minutes */
 	u8 ucode_valid;
-} __attribute__ ((packed));
+} __packed;
 
 #define IPW_MAX_RATES 12
 
 struct ipw_rates {
 	u8 num_rates;
 	u8 rates[IPW_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
 
 struct command_block {
 	unsigned int control;
 	u32 source_addr;
 	u32 dest_addr;
 	unsigned int status;
-} __attribute__ ((packed));
+} __packed;
 
 #define CB_NUMBER_OF_ELEMENTS_SMALL 64
 struct fw_image_desc {
@@ -792,7 +792,7 @@
 	u8 accept_all_mgmt_frames;
 	u8 pass_noise_stats_to_host;
 	u8 reserved3;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_multicast_addr {
 	u8 num_of_multicast_addresses;
@@ -801,7 +801,7 @@
 	u8 mac2[6];
 	u8 mac3[6];
 	u8 mac4[6];
-} __attribute__ ((packed));
+} __packed;
 
 #define DCW_WEP_KEY_INDEX_MASK		0x03	/* bits [0:1] */
 #define DCW_WEP_KEY_SEC_TYPE_MASK	0x30	/* bits [4:5] */
@@ -822,7 +822,7 @@
 	u8 key_index;
 	u8 key_size;
 	u8 key[16];
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_tgi_tx_key {
 	u8 key_id;
@@ -831,7 +831,7 @@
 	u8 flags;
 	u8 key[16];
 	__le32 tx_counter[2];
-} __attribute__ ((packed));
+} __packed;
 
 #define IPW_SCAN_CHANNELS 54
 
@@ -840,7 +840,7 @@
 	__le16 dwell_time;
 	u8 channels_list[IPW_SCAN_CHANNELS];
 	u8 channels_reserved[3];
-} __attribute__ ((packed));
+} __packed;
 
 enum {
 	IPW_SCAN_PASSIVE_TILL_FIRST_BEACON_SCAN = 0,
@@ -857,7 +857,7 @@
 	u8 scan_type[IPW_SCAN_CHANNELS / 2];
 	u8 reserved;
 	__le16 dwell_time[IPW_SCAN_TYPES];
-} __attribute__ ((packed));
+} __packed;
 
 static inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index)
 {
@@ -902,7 +902,7 @@
 	u8 smr;
 	u8 reserved1;
 	__le16 reserved2;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_supported_rates {
 	u8 ieee_mode;
@@ -910,36 +910,36 @@
 	u8 purpose;
 	u8 reserved;
 	u8 supported_rates[IPW_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_rts_threshold {
 	__le16 rts_threshold;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_frag_threshold {
 	__le16 frag_threshold;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_retry_limit {
 	u8 short_retry_limit;
 	u8 long_retry_limit;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_dino_config {
 	__le32 dino_config_addr;
 	__le16 dino_config_size;
 	u8 dino_response;
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_aironet_info {
 	u8 id;
 	u8 length;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_rx_key {
 	u8 station_index;
@@ -950,25 +950,25 @@
 	u8 station_address[6];
 	u8 key_index;
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_country_channel_info {
 	u8 first_channel;
 	u8 no_channels;
 	s8 max_tx_power;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_country_info {
 	u8 id;
 	u8 length;
 	u8 country_str[3];
 	struct ipw_country_channel_info groups[7];
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_channel_tx_power {
 	u8 channel_number;
 	s8 tx_power;
-} __attribute__ ((packed));
+} __packed;
 
 #define SCAN_ASSOCIATED_INTERVAL (HZ)
 #define SCAN_INTERVAL (HZ / 10)
@@ -979,18 +979,18 @@
 	u8 num_channels;
 	u8 ieee_mode;
 	struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS];
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_rsn_capabilities {
 	u8 id;
 	u8 length;
 	__le16 version;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_sensitivity_calib {
 	__le16 beacon_rssi_raw;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * Host command structure.
@@ -1019,7 +1019,7 @@
    * nParams=(len+3)/4+status_len
    */
 	u32 param[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define STATUS_HCMD_ACTIVE      (1<<0)	/**< host command in progress */
 
@@ -1114,7 +1114,7 @@
 	u32 event;
 	u32 time;
 	u32 data;
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_fw_error {	 /* XXX */
 	unsigned long jiffies;
@@ -1125,7 +1125,7 @@
 	struct ipw_error_elem *elem;
 	struct ipw_event *log;
 	u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
 
 #ifdef CONFIG_IPW2200_PROMISCUOUS
 
@@ -1170,7 +1170,7 @@
 	s8 rt_dbmnoise;
 	u8 rt_antenna;	/* antenna number */
 	u8 payload[0];  /* payload... */
-} __attribute__ ((packed));
+} __packed;
 #endif
 
 struct ipw_priv {
@@ -1957,7 +1957,7 @@
 struct ipw_fixed_rate {
 	__le16 tx_rates;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 #define IPW_INDIRECT_ADDR_MASK (~0x3ul)
 
@@ -1966,14 +1966,14 @@
 	u8 len;
 	u16 reserved;
 	u32 *param;
-} __attribute__ ((packed));	/* XXX */
+} __packed;	/* XXX */
 
 struct cmdlog_host_cmd {
 	u8 cmd;
 	u8 len;
 	__le16 reserved;
 	char param[124];
-} __attribute__ ((packed));
+} __packed;
 
 struct ipw_cmd_log {
 	unsigned long jiffies;
diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h
index 284b0e4..70f5586 100644
--- a/drivers/net/wireless/ipw2x00/libipw.h
+++ b/drivers/net/wireless/ipw2x00/libipw.h
@@ -154,7 +154,7 @@
 	u8 ctrl;		/* always 0x03 */
 	u8 oui[P80211_OUI_LEN];	/* organizational universal id */
 
-} __attribute__ ((packed));
+} __packed;
 
 #define SNAP_SIZE sizeof(struct libipw_snap_hdr)
 
@@ -323,7 +323,7 @@
 	u8 keys[WEP_KEYS][SCM_KEY_LEN];
 	u8 level;
 	u16 flags;
-} __attribute__ ((packed));
+} __packed;
 
 /*
 
@@ -347,7 +347,7 @@
 	__le16 duration_id;
 	u8 addr1[ETH_ALEN];
 	u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_hdr_2addr {
 	__le16 frame_ctl;
@@ -355,7 +355,7 @@
 	u8 addr1[ETH_ALEN];
 	u8 addr2[ETH_ALEN];
 	u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_hdr_3addr {
 	__le16 frame_ctl;
@@ -365,7 +365,7 @@
 	u8 addr3[ETH_ALEN];
 	__le16 seq_ctl;
 	u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_hdr_4addr {
 	__le16 frame_ctl;
@@ -376,7 +376,7 @@
 	__le16 seq_ctl;
 	u8 addr4[ETH_ALEN];
 	u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_hdr_3addrqos {
 	__le16 frame_ctl;
@@ -387,13 +387,13 @@
 	__le16 seq_ctl;
 	u8 payload[0];
 	__le16 qos_ctl;
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_info_element {
 	u8 id;
 	u8 len;
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * These are the data types that can make up management packets
@@ -406,7 +406,7 @@
 	u16 listen_interval;
 	struct {
 		u16 association_id:14, reserved:2;
-	} __attribute__ ((packed));
+	} __packed;
 	u32 time_stamp[2];
 	u16 reason;
 	u16 status;
@@ -419,7 +419,7 @@
 	__le16 status;
 	/* challenge */
 	struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_channel_switch {
 	u8 id;
@@ -427,7 +427,7 @@
 	u8 mode;
 	u8 channel;
 	u8 count;
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_action {
 	struct libipw_hdr_3addr header;
@@ -441,12 +441,12 @@
 		struct libipw_channel_switch channel_switch;
 
 	} format;
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_disassoc {
 	struct libipw_hdr_3addr header;
 	__le16 reason;
-} __attribute__ ((packed));
+} __packed;
 
 /* Alias deauth for disassoc */
 #define libipw_deauth libipw_disassoc
@@ -455,7 +455,7 @@
 	struct libipw_hdr_3addr header;
 	/* SSID, supported rates */
 	struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_probe_response {
 	struct libipw_hdr_3addr header;
@@ -465,7 +465,7 @@
 	/* SSID, supported rates, FH params, DS params,
 	 * CF params, IBSS params, TIM (if beacon), RSN */
 	struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Alias beacon for probe_response */
 #define libipw_beacon libipw_probe_response
@@ -476,7 +476,7 @@
 	__le16 listen_interval;
 	/* SSID, supported rates, RSN */
 	struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_reassoc_request {
 	struct libipw_hdr_3addr header;
@@ -484,7 +484,7 @@
 	__le16 listen_interval;
 	u8 current_ap[ETH_ALEN];
 	struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_assoc_response {
 	struct libipw_hdr_3addr header;
@@ -493,7 +493,7 @@
 	__le16 aid;
 	/* supported rates */
 	struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_txb {
 	u8 nr_frags;
@@ -555,19 +555,19 @@
 	u8 qui_subtype;
 	u8 version;
 	u8 ac_info;
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_qos_ac_parameter {
 	u8 aci_aifsn;
 	u8 ecw_min_max;
 	__le16 tx_op_limit;
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_qos_parameter_info {
 	struct libipw_qos_information_element info_element;
 	u8 reserved;
 	struct libipw_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM];
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_qos_parameters {
 	__le16 cw_min[QOS_QUEUE_NUM];
@@ -575,7 +575,7 @@
 	u8 aifs[QOS_QUEUE_NUM];
 	u8 flag[QOS_QUEUE_NUM];
 	__le16 tx_op_limit[QOS_QUEUE_NUM];
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_qos_data {
 	struct libipw_qos_parameters parameters;
@@ -588,7 +588,7 @@
 struct libipw_tim_parameters {
 	u8 tim_count;
 	u8 tim_period;
-} __attribute__ ((packed));
+} __packed;
 
 /*******************************************************/
 
@@ -606,7 +606,7 @@
 	__le64 start_time;
 	__le16 duration;
 	u8 map;
-} __attribute__ ((packed));
+} __packed;
 
 enum {				/* libipw_measurement_request.mode */
 	/* Bit 0 is reserved */
@@ -627,7 +627,7 @@
 	u8 channel;
 	__le64 start_time;
 	__le16 duration;
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_measurement_request {
 	struct libipw_info_element ie;
@@ -635,7 +635,7 @@
 	u8 mode;
 	u8 type;
 	struct libipw_measurement_params params[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_measurement_report {
 	struct libipw_info_element ie;
@@ -645,17 +645,17 @@
 	union {
 		struct libipw_basic_report basic[0];
 	} u;
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_tpc_report {
 	u8 transmit_power;
 	u8 link_margin;
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_channel_map {
 	u8 channel;
 	u8 map;
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_ibss_dfs {
 	struct libipw_info_element ie;
@@ -668,14 +668,14 @@
 	u8 mode;
 	u8 channel;
 	u8 count;
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_quiet {
 	u8 count;
 	u8 period;
 	u8 duration;
 	u8 offset;
-} __attribute__ ((packed));
+} __packed;
 
 struct libipw_network {
 	/* These entries are used to identify a unique network */
@@ -828,7 +828,6 @@
 	int host_strip_iv_icv;
 
 	int host_open_frag;
-	int host_build_iv;
 	int ieee802_1x;		/* is IEEE 802.1X used */
 
 	/* WPA data */
diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c
index 5596540..32dee2c 100644
--- a/drivers/net/wireless/ipw2x00/libipw_module.c
+++ b/drivers/net/wireless/ipw2x00/libipw_module.c
@@ -62,8 +62,8 @@
 MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 
-struct cfg80211_ops libipw_config_ops = { };
-void *libipw_wiphy_privid = &libipw_wiphy_privid;
+static struct cfg80211_ops libipw_config_ops = { };
+static void *libipw_wiphy_privid = &libipw_wiphy_privid;
 
 static int libipw_networks_allocate(struct libipw_device *ieee)
 {
diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c
index da8beac..01c88a7 100644
--- a/drivers/net/wireless/ipw2x00/libipw_tx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_tx.c
@@ -260,7 +260,7 @@
 	int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
 	    rts_required;
 	unsigned long flags;
-	int encrypt, host_encrypt, host_encrypt_msdu, host_build_iv;
+	int encrypt, host_encrypt, host_encrypt_msdu;
 	__be16 ether_type;
 	int bytes, fc, hdr_len;
 	struct sk_buff *skb_frag;
@@ -301,7 +301,6 @@
 
 	host_encrypt = ieee->host_encrypt && encrypt && crypt;
 	host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt && crypt;
-	host_build_iv = ieee->host_build_iv && encrypt && crypt;
 
 	if (!encrypt && ieee->ieee802_1x &&
 	    ieee->drop_unencrypted && ether_type != htons(ETH_P_PAE)) {
@@ -313,7 +312,7 @@
 	skb_copy_from_linear_data(skb, dest, ETH_ALEN);
 	skb_copy_from_linear_data_offset(skb, ETH_ALEN, src, ETH_ALEN);
 
-	if (host_encrypt || host_build_iv)
+	if (host_encrypt)
 		fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
 		    IEEE80211_FCTL_PROTECTED;
 	else
@@ -467,7 +466,7 @@
 	for (; i < nr_frags; i++) {
 		skb_frag = txb->fragments[i];
 
-		if (host_encrypt || host_build_iv)
+		if (host_encrypt)
 			skb_reserve(skb_frag,
 				    crypt->ops->extra_mpdu_prefix_len);
 
@@ -502,15 +501,6 @@
 		 * to insert the IV between the header and the payload */
 		if (host_encrypt)
 			libipw_encrypt_fragment(ieee, skb_frag, hdr_len);
-		else if (host_build_iv) {
-			atomic_inc(&crypt->refcnt);
-			if (crypt->ops->build_iv)
-				crypt->ops->build_iv(skb_frag, hdr_len,
-				      ieee->sec.keys[ieee->sec.active_key],
-				      ieee->sec.key_sizes[ieee->sec.active_key],
-				      crypt->priv);
-			atomic_dec(&crypt->refcnt);
-		}
 
 		if (ieee->config &
 		    (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c
index 3633c66..d7bd6cf0 100644
--- a/drivers/net/wireless/ipw2x00/libipw_wx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_wx.c
@@ -320,7 +320,7 @@
 	};
 	int i, key, key_provided, len;
 	struct lib80211_crypt_data **crypt;
-	int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
+	int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
 	DECLARE_SSID_BUF(ssid);
 
 	LIBIPW_DEBUG_WX("SET_ENCODE\n");
@@ -411,10 +411,6 @@
 
 	/* If a new key was provided, set it up */
 	if (erq->length > 0) {
-#ifdef CONFIG_LIBIPW_DEBUG
-		DECLARE_SSID_BUF(ssid);
-#endif
-
 		len = erq->length <= 5 ? 5 : 13;
 		memcpy(sec.keys[key], keybuf, erq->length);
 		if (len > erq->length)
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index dc8ed15..a51e4da 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -30,9 +30,11 @@
 
 config IWLWIFI_DEBUGFS
         bool "iwlagn debugfs support"
-        depends on IWLWIFI && IWLWIFI_DEBUG && MAC80211_DEBUGFS
+        depends on IWLWIFI && MAC80211_DEBUGFS
         ---help---
-	  Enable creation of debugfs files for the iwlwifi drivers.
+	  Enable creation of debugfs files for the iwlwifi drivers. This
+	  is a low-impact option that allows getting insight into the
+	  driver's state at runtime.
 
 config IWLWIFI_DEVICE_TRACING
 	bool "iwlwifi device access tracing"
@@ -85,10 +87,15 @@
 	  This option enables support for Intel Wireless WiFi Link 4965AGN
 
 config IWL5000
-	bool "Intel Wireless WiFi 5000AGN; Intel WiFi Link 1000, 6000, and 6050 Series"
+	bool "Intel Wireless-N/Advanced-N/Ultimate-N WiFi Link"
 	depends on IWLAGN
 	---help---
-	  This option enables support for Intel Wireless WiFi Link 5000AGN Family
+	  This option enables support for use with the following hardware:
+		Intel Wireless WiFi Link 6250AGN Adapter
+		Intel 6000 Series Wi-Fi Adapters (6200AGN and 6300AGN)
+		Intel WiFi Link 1000BGN
+		Intel Wireless WiFi 5150AGN
+		Intel Wireless WiFi 5100AGN, 5300AGN, and 5350AGN
 
 config IWL3945
 	tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)"
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 7c72353..728bb85 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,6 +1,6 @@
 obj-$(CONFIG_IWLWIFI)	+= iwlcore.o
 iwlcore-objs 		:= iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
-iwlcore-objs 		+= iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o
+iwlcore-objs 		+= iwl-rx.o iwl-tx.o iwl-sta.o
 iwlcore-objs 		+= iwl-scan.o iwl-led.o
 iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
 iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
@@ -11,7 +11,7 @@
 obj-$(CONFIG_IWLAGN)	+= iwlagn.o
 iwlagn-objs		:= iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o
 iwlagn-objs		+= iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o
-iwlagn-objs		+= iwl-agn-lib.o
+iwlagn-objs		+= iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o
 iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o
 
 iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 6be2992..8848333 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -129,8 +129,8 @@
 			priv->cfg->num_of_queues *
 			sizeof(struct iwlagn_scd_bc_tbl);
 	priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
-	priv->hw_params.max_stations = IWL5000_STATION_COUNT;
-	priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+	priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
+	priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
 
 	priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
 	priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@@ -157,6 +157,10 @@
 			BIT(IWL_CALIB_TX_IQ) 		|
 			BIT(IWL_CALIB_TX_IQ_PERD)	|
 			BIT(IWL_CALIB_BASE_BAND);
+	if (priv->cfg->need_dc_calib)
+		priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC);
+
+	priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
 
 	return 0;
 }
@@ -213,14 +217,18 @@
 		.set_ct_kill = iwl1000_set_ct_threshold,
 	 },
 	.manage_ibss_station = iwlagn_manage_ibss_station,
+	.update_bcast_station = iwl_update_bcast_station,
 	.debugfs_ops = {
 		.rx_stats_read = iwl_ucode_rx_stats_read,
 		.tx_stats_read = iwl_ucode_tx_stats_read,
 		.general_stats_read = iwl_ucode_general_stats_read,
+		.bt_stats_read = iwl_ucode_bt_stats_read,
 	},
 	.recover_from_tx_stall = iwl_bg_monitor_recover,
 	.check_plcp_health = iwl_good_plcp_health,
 	.check_ack_health = iwl_good_ack_health,
+	.txfifo_flush = iwlagn_txfifo_flush,
+	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
 
 static const struct iwl_ops iwl1000_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
index 6a9c64a..ef0835b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
@@ -28,6 +28,28 @@
 
 #include "iwl-3945-debugfs.h"
 
+
+static int iwl3945_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
+{
+	int p = 0;
+
+	p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n",
+		       le32_to_cpu(priv->_3945.statistics.flag));
+	if (le32_to_cpu(priv->_3945.statistics.flag) &
+			UCODE_STATISTICS_CLEAR_MSK)
+		p += scnprintf(buf + p, bufsz - p,
+			       "\tStatistics have been cleared\n");
+	p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
+		       (le32_to_cpu(priv->_3945.statistics.flag) &
+			UCODE_STATISTICS_FREQUENCY_MSK)
+			? "2.4 GHz" : "5.2 GHz");
+	p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
+		       (le32_to_cpu(priv->_3945.statistics.flag) &
+			UCODE_STATISTICS_NARROW_BAND_MSK)
+			? "enabled" : "disabled");
+	return p;
+}
+
 ssize_t iwl3945_ucode_rx_stats_read(struct file *file,
 				    char __user *user_buf,
 				    size_t count, loff_t *ppos)
@@ -70,7 +92,7 @@
 	max_cck = &priv->_3945.max_delta.rx.cck;
 	max_general = &priv->_3945.max_delta.rx.general;
 
-	pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+	pos += iwl3945_statistics_flag(priv, buf, bufsz);
 	pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
 			 "acumulative       delta         max\n",
 			 "Statistics_Rx - OFDM:");
@@ -331,7 +353,7 @@
 	accum_tx = &priv->_3945.accum_statistics.tx;
 	delta_tx = &priv->_3945.delta_statistics.tx;
 	max_tx = &priv->_3945.max_delta.tx;
-	pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+	pos += iwl3945_statistics_flag(priv, buf, bufsz);
 	pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
 			 "acumulative       delta         max\n",
 			 "Statistics_Tx:");
@@ -438,7 +460,7 @@
 	accum_div = &priv->_3945.accum_statistics.general.div;
 	delta_div = &priv->_3945.delta_statistics.general.div;
 	max_div = &priv->_3945.max_delta.general.div;
-	pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+	pos += iwl3945_statistics_flag(priv, buf, bufsz);
 	pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
 			 "acumulative       delta         max\n",
 			 "Statistics_General:");
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-fh.h b/drivers/net/wireless/iwlwifi/iwl-3945-fh.h
index 042f6bc..2c9ed2b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-fh.h
@@ -175,13 +175,13 @@
 struct iwl3945_tfd_tb {
 	__le32 addr;
 	__le32 len;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl3945_tfd {
 	__le32 control_flags;
 	struct iwl3945_tfd_tb tbs[4];
 	u8 __pad[28];
-} __attribute__ ((packed));
+} __packed;
 
 
 #endif /* __iwl_3945_fh_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 91bcb4e..7c731a7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -96,7 +96,7 @@
 	u8 gain_index;		/* index into power (gain) setup table ... */
 	s8 power;		/* ... for this pwr level for this chnl group */
 	u16 v_det;		/* PA output voltage */
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * Mappings of Tx power levels -> nominal radio/DSP gain table indexes.
@@ -117,7 +117,7 @@
 	u8 group_channel;	/* "representative" channel # in this band */
 	s16 temperature;	/* h/w temperature at factory calib this band
 				 * (signed) */
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * Temperature-based Tx-power compensation data, not band-specific.
@@ -131,7 +131,7 @@
 	u32 Tc;
 	u32 Td;
 	u32 Te;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * EEPROM map
@@ -215,7 +215,7 @@
 /* abs.ofs: 512 */
 	struct iwl3945_eeprom_temperature_corr corrections;  /* abs.ofs: 832 */
 	u8 reserved16[172];	/* fill out to full 1024 byte block */
-} __attribute__ ((packed));
+} __packed;
 
 #define IWL3945_EEPROM_IMG_SIZE 1024
 
@@ -274,7 +274,7 @@
  * and &iwl3945_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */
 struct iwl3945_shared {
 	__le32 tx_base_ptr[8];
-} __attribute__ ((packed));
+} __packed;
 
 static inline u8 iwl3945_hw_get_rate(__le16 rate_n_flags)
 {
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index c44a303..a07310f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -279,8 +279,8 @@
 		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]);
-		tx_info->skb[0] = NULL;
+		ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb);
+		tx_info->skb = NULL;
 		priv->cfg->ops->lib->txq_free_tfd(priv, txq);
 	}
 
@@ -315,7 +315,7 @@
 		return;
 	}
 
-	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
 	ieee80211_tx_info_clear_status(info);
 
 	/* Fill the MRR chain with some info about on-chip retransmissions */
@@ -352,7 +352,7 @@
  *  RX handler implementations
  *
  *****************************************************************************/
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
 /*
  *  based on the assumption of all statistics counter are in DWORD
  *  FIXME: This function is for debugging, do not deal with
@@ -406,6 +406,11 @@
 	unsigned int plcp_msec;
 	unsigned long plcp_received_jiffies;
 
+	if (priv->cfg->plcp_delta_threshold ==
+	    IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
+		IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
+		return rc;
+	}
 	memcpy(&current_stat, pkt->u.raw, sizeof(struct
 			iwl3945_notif_statistics));
 	/*
@@ -460,7 +465,7 @@
 	IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
 		     (int)sizeof(struct iwl3945_notif_statistics),
 		     le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
 	iwl3945_accumulative_statistics(priv, (__le32 *)&pkt->u.raw);
 #endif
 	iwl_recover_from_statistics(priv, pkt);
@@ -475,7 +480,7 @@
 	__le32 *flag = (__le32 *)&pkt->u.raw;
 
 	if (le32_to_cpu(*flag) & UCODE_STATISTICS_CLEAR_MSK) {
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
 		memset(&priv->_3945.accum_statistics, 0,
 			sizeof(struct iwl3945_notif_statistics));
 		memset(&priv->_3945.delta_statistics, 0,
@@ -494,158 +499,6 @@
  * Misc. internal state and helper functions
  *
  ******************************************************************************/
-#ifdef CONFIG_IWLWIFI_DEBUG
-
-/**
- * iwl3945_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.
- */
-static void _iwl3945_dbg_report_frame(struct iwl_priv *priv,
-		      struct iwl_rx_packet *pkt,
-		      struct ieee80211_hdr *header, int group100)
-{
-	u32 to_us;
-	u32 print_summary = 0;
-	u32 print_dump = 0;	/* set to 1 to dump all frames' contents */
-	u32 hundred = 0;
-	u32 dataframe = 0;
-	__le16 fc;
-	u16 seq_ctl;
-	u16 channel;
-	u16 phy_flags;
-	u16 length;
-	u16 status;
-	u16 bcn_tmr;
-	u32 tsf_low;
-	u64 tsf;
-	u8 rssi;
-	u8 agc;
-	u16 sig_avg;
-	u16 noise_diff;
-	struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
-	struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
-	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
-	u8 *data = IWL_RX_DATA(pkt);
-
-	/* MAC header */
-	fc = header->frame_control;
-	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);
-	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);
-
-	/* 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);
-
-	to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
-
-	/* if data frame is to us and all is good,
-	 *   (optionally) print summary for only 1 out of every 100 */
-	if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) ==
-	    cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
-		dataframe = 1;
-		if (!group100)
-			print_summary = 1;	/* print each frame */
-		else if (priv->framecnt_to_us < 100) {
-			priv->framecnt_to_us++;
-			print_summary = 0;
-		} else {
-			priv->framecnt_to_us = 0;
-			print_summary = 1;
-			hundred = 1;
-		}
-	} else {
-		/* print summary for all other frames */
-		print_summary = 1;
-	}
-
-	if (print_summary) {
-		char *title;
-		int rate;
-
-		if (hundred)
-			title = "100Frames";
-		else if (ieee80211_has_retry(fc))
-			title = "Retry";
-		else if (ieee80211_is_assoc_resp(fc))
-			title = "AscRsp";
-		else if (ieee80211_is_reassoc_resp(fc))
-			title = "RasRsp";
-		else if (ieee80211_is_probe_resp(fc)) {
-			title = "PrbRsp";
-			print_dump = 1;	/* dump frame contents */
-		} else if (ieee80211_is_beacon(fc)) {
-			title = "Beacon";
-			print_dump = 1;	/* dump frame contents */
-		} else if (ieee80211_is_atim(fc))
-			title = "ATIM";
-		else if (ieee80211_is_auth(fc))
-			title = "Auth";
-		else if (ieee80211_is_deauth(fc))
-			title = "DeAuth";
-		else if (ieee80211_is_disassoc(fc))
-			title = "DisAssoc";
-		else
-			title = "Frame";
-
-		rate = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate);
-		if (rate == -1)
-			rate = 0;
-		else
-			rate = iwl3945_rates[rate].ieee / 2;
-
-		/* print frame summary.
-		 * MAC addresses show just the last byte (for brevity),
-		 *    but you can hack it to show more, if you'd like to. */
-		if (dataframe)
-			IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
-				     "len=%u, rssi=%d, chnl=%d, rate=%d,\n",
-				     title, le16_to_cpu(fc), header->addr1[5],
-				     length, rssi, channel, rate);
-		else {
-			/* src/dst addresses assume managed mode */
-			IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, "
-				     "src=0x%02x, rssi=%u, tim=%lu usec, "
-				     "phy=0x%02x, chnl=%d\n",
-				     title, le16_to_cpu(fc), header->addr1[5],
-				     header->addr3[5], rssi,
-				     tsf_low - priv->scan_start_tsf,
-				     phy_flags, channel);
-		}
-	}
-	if (print_dump)
-		iwl_print_hex_dump(priv, IWL_DL_RX, data, length);
-}
-
-static void iwl3945_dbg_report_frame(struct iwl_priv *priv,
-		      struct iwl_rx_packet *pkt,
-		      struct ieee80211_hdr *header, int group100)
-{
-	if (iwl_get_debug_level(priv) & IWL_DL_RX)
-		_iwl3945_dbg_report_frame(priv, pkt, header, group100);
-}
-
-#else
-static inline void iwl3945_dbg_report_frame(struct iwl_priv *priv,
-		      struct iwl_rx_packet *pkt,
-		      struct ieee80211_hdr *header, int group100)
-{
-}
-#endif
 
 /* This is necessary only for a number of statistics, see the caller. */
 static int iwl3945_is_network_packet(struct iwl_priv *priv,
@@ -777,8 +630,6 @@
 			      rx_status.signal, rx_status.signal,
 			      rx_status.rate_idx);
 
-	/* Set "1" to report good data frames in groups of 100 */
-	iwl3945_dbg_report_frame(priv, pkt, header, 1);
 	iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header);
 
 	if (network_packet) {
@@ -850,25 +701,28 @@
 	/* Unmap tx_cmd */
 	if (counter)
 		pci_unmap_single(dev,
-				pci_unmap_addr(&txq->meta[index], mapping),
-				pci_unmap_len(&txq->meta[index], len),
+				dma_unmap_addr(&txq->meta[index], mapping),
+				dma_unmap_len(&txq->meta[index], len),
 				PCI_DMA_TODEVICE);
 
 	/* unmap chunks if any */
 
-	for (i = 1; i < counter; i++) {
+	for (i = 1; i < counter; i++)
 		pci_unmap_single(dev, le32_to_cpu(tfd->tbs[i].addr),
 			 le32_to_cpu(tfd->tbs[i].len), PCI_DMA_TODEVICE);
-		if (txq->txb[txq->q.read_ptr].skb[0]) {
-			struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[0];
-			if (txq->txb[txq->q.read_ptr].skb[0]) {
-				/* Can be called from interrupt context */
-				dev_kfree_skb_any(skb);
-				txq->txb[txq->q.read_ptr].skb[0] = NULL;
-			}
+
+	/* free SKB */
+	if (txq->txb) {
+		struct sk_buff *skb;
+
+		skb = txq->txb[txq->q.read_ptr].skb;
+
+		/* can be called from irqs-disabled context */
+		if (skb) {
+			dev_kfree_skb_any(skb);
+			txq->txb[txq->q.read_ptr].skb = NULL;
 		}
 	}
-	return ;
 }
 
 /**
@@ -947,8 +801,7 @@
 		       tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]);
 }
 
-static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
-			   u16 tx_rate, u8 flags)
+static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate)
 {
 	unsigned long flags_spin;
 	struct iwl_station_entry *station;
@@ -962,10 +815,9 @@
 	station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
 	station->sta.rate_n_flags = cpu_to_le16(tx_rate);
 	station->sta.mode = STA_CONTROL_MODIFY_MSK;
-
+	iwl_send_add_sta(priv, &station->sta, CMD_ASYNC);
 	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
 
-	iwl_send_add_sta(priv, &station->sta, flags);
 	IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n",
 			sta_id, tx_rate);
 	return sta_id;
@@ -997,7 +849,7 @@
 
 static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
 {
-	iwl_write_direct32(priv, FH39_RCSR_RBD_BASE(0), rxq->dma_addr);
+	iwl_write_direct32(priv, FH39_RCSR_RBD_BASE(0), rxq->bd_dma);
 	iwl_write_direct32(priv, FH39_RCSR_RPTR_ADDR(0), rxq->rb_stts_dma);
 	iwl_write_direct32(priv, FH39_RCSR_WPTR(0), 0);
 	iwl_write_direct32(priv, FH39_RCSR_CONFIG(0),
@@ -2473,8 +2325,7 @@
 
 		iwl3945_sync_sta(priv, vif_priv->ibss_bssid_sta_id,
 				 (priv->band == IEEE80211_BAND_5GHZ) ?
-				 IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
-				 CMD_ASYNC);
+				 IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP);
 		iwl3945_rate_scale_init(priv->hw, vif_priv->ibss_bssid_sta_id);
 
 		return 0;
@@ -2590,6 +2441,7 @@
 
 	priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR;
 	priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL;
+	priv->hw_params.beacon_time_tsf_bits = IWL3945_EXT_BEACON_TIME_POS;
 
 	return 0;
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index cd4b61a..9166794 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -787,6 +787,6 @@
 struct iwl4965_scd_bc_tbl {
 	__le16 tfd_offset[TFD_QUEUE_BC_SIZE];
 	u8 pad[1024 - (TFD_QUEUE_BC_SIZE) * sizeof(__le16)];
-} __attribute__ ((packed));
+} __packed;
 
 #endif /* !__iwl_4965_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index d3afdda..d6531ad 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -346,9 +346,19 @@
 {
 	struct iwl_chain_noise_data *data = &(priv->chain_noise_data);
 
-	if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+	if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
+	     iwl_is_associated(priv)) {
 		struct iwl_calib_diff_gain_cmd cmd;
 
+		/* clear data for chain noise calibration algorithm */
+		data->chain_noise_a = 0;
+		data->chain_noise_b = 0;
+		data->chain_noise_c = 0;
+		data->chain_signal_a = 0;
+		data->chain_signal_b = 0;
+		data->chain_signal_c = 0;
+		data->beacon_count = 0;
+
 		memset(&cmd, 0, sizeof(cmd));
 		cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD;
 		cmd.diff_gain_a = 0;
@@ -419,13 +429,6 @@
 		/* Mark so we run this algo only once! */
 		data->state = IWL_CHAIN_NOISE_CALIBRATED;
 	}
-	data->chain_noise_a = 0;
-	data->chain_noise_b = 0;
-	data->chain_noise_c = 0;
-	data->chain_signal_a = 0;
-	data->chain_signal_b = 0;
-	data->chain_signal_c = 0;
-	data->beacon_count = 0;
 }
 
 static void iwl4965_bg_txpower_work(struct work_struct *work)
@@ -669,6 +672,7 @@
 		priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
 
 	priv->hw_params.sens = &iwl4965_sensitivity;
+	priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
 
 	return 0;
 }
@@ -1441,7 +1445,8 @@
 	return ret;
 }
 
-static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
+				     struct ieee80211_channel_switch *ch_switch)
 {
 	int rc;
 	u8 band = 0;
@@ -1449,11 +1454,14 @@
 	u8 ctrl_chan_high = 0;
 	struct iwl4965_channel_switch_cmd cmd;
 	const struct iwl_channel_info *ch_info;
-
+	u32 switch_time_in_usec, ucode_switch_time;
+	u16 ch;
+	u32 tsf_low;
+	u8 switch_count;
+	u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
+	struct ieee80211_vif *vif = priv->vif;
 	band = priv->band == IEEE80211_BAND_2GHZ;
 
-	ch_info = iwl_get_channel_info(priv, priv->band, channel);
-
 	is_ht40 = is_ht40_channel(priv->staging_rxon.flags);
 
 	if (is_ht40 &&
@@ -1462,26 +1470,56 @@
 
 	cmd.band = band;
 	cmd.expect_beacon = 0;
-	cmd.channel = cpu_to_le16(channel);
+	ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+	cmd.channel = cpu_to_le16(ch);
 	cmd.rxon_flags = priv->staging_rxon.flags;
 	cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
-	cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+	switch_count = ch_switch->count;
+	tsf_low = ch_switch->timestamp & 0x0ffffffff;
+	/*
+	 * calculate the ucode channel switch time
+	 * adding TSF as one of the factor for when to switch
+	 */
+	if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
+		if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
+		    beacon_interval)) {
+			switch_count -= (priv->ucode_beacon_time -
+				tsf_low) / beacon_interval;
+		} else
+			switch_count = 0;
+	}
+	if (switch_count <= 1)
+		cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+	else {
+		switch_time_in_usec =
+			vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
+		ucode_switch_time = iwl_usecs_to_beacons(priv,
+							 switch_time_in_usec,
+							 beacon_interval);
+		cmd.switch_time = iwl_add_beacon_time(priv,
+						      priv->ucode_beacon_time,
+						      ucode_switch_time,
+						      beacon_interval);
+	}
+	IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
+		      cmd.switch_time);
+	ch_info = iwl_get_channel_info(priv, priv->band, ch);
 	if (ch_info)
 		cmd.expect_beacon = is_channel_radar(ch_info);
 	else {
 		IWL_ERR(priv, "invalid channel switch from %u to %u\n",
-			priv->active_rxon.channel, channel);
+			priv->active_rxon.channel, ch);
 		return -EFAULT;
 	}
 
-	rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40,
+	rc = iwl4965_fill_txpower_tbl(priv, band, ch, is_ht40,
 				      ctrl_chan_high, &cmd.tx_power);
 	if (rc) {
 		IWL_DEBUG_11H(priv, "error:%d  fill txpower_tbl\n", rc);
 		return rc;
 	}
 
-	priv->switch_rxon.channel = cpu_to_le16(channel);
+	priv->switch_rxon.channel = cmd.channel;
 	priv->switch_rxon.switch_in_progress = true;
 
 	return iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
@@ -1542,7 +1580,8 @@
 	u32 R4;
 
 	if (test_bit(STATUS_TEMPERATURE, &priv->status) &&
-		(priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)) {
+	    (priv->_agn.statistics.flag &
+			STATISTICS_REPLY_FLG_HT40_MODE_MSK)) {
 		IWL_DEBUG_TEMP(priv, "Running HT40 temperature calibration\n");
 		R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
 		R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
@@ -1566,8 +1605,8 @@
 	if (!test_bit(STATUS_TEMPERATURE, &priv->status))
 		vt = sign_extend(R4, 23);
 	else
-		vt = sign_extend(
-			le32_to_cpu(priv->statistics.general.temperature), 23);
+		vt = sign_extend(le32_to_cpu(priv->_agn.statistics.
+				 general.common.temperature), 23);
 
 	IWL_DEBUG_TEMP(priv, "Calib values R[1-3]: %d %d %d R4: %d\n", R1, R2, R3, vt);
 
@@ -1747,6 +1786,7 @@
 {
 	unsigned long flags;
 	u16 ra_tid;
+	int ret;
 
 	if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
 	    (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
@@ -1762,7 +1802,9 @@
 	ra_tid = BUILD_RAxTID(sta_id, tid);
 
 	/* Modify device's station table to Tx this TID */
-	iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+	ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+	if (ret)
+		return ret;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
@@ -1870,7 +1912,7 @@
 		IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
 				   agg->frame_count, agg->start_idx, idx);
 
-		info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+		info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb);
 		info->status.rates[0].count = tx_resp->failure_frame + 1;
 		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
 		info->flags |= iwl_tx_status_to_mac80211(status);
@@ -2026,6 +2068,7 @@
 	int sta_id;
 	int freed;
 	u8 *qc = NULL;
+	unsigned long flags;
 
 	if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
 		IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
@@ -2035,7 +2078,7 @@
 		return;
 	}
 
-	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
 	memset(&info->status, 0, sizeof(info->status));
 
 	hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
@@ -2050,10 +2093,10 @@
 		return;
 	}
 
+	spin_lock_irqsave(&priv->sta_lock, flags);
 	if (txq->sched_retry) {
 		const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
 		struct iwl_ht_agg *agg = NULL;
-
 		WARN_ON(!qc);
 
 		agg = &priv->stations[sta_id].tid[tid].agg;
@@ -2110,6 +2153,8 @@
 		iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
 
 	iwl_check_abort_status(priv, tx_resp->frame_count, status);
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
 
 static int iwl4965_calc_rssi(struct iwl_priv *priv,
@@ -2235,11 +2280,14 @@
 		.set_ct_kill = iwl4965_set_ct_threshold,
 	},
 	.manage_ibss_station = iwlagn_manage_ibss_station,
+	.update_bcast_station = iwl_update_bcast_station,
 	.debugfs_ops = {
 		.rx_stats_read = iwl_ucode_rx_stats_read,
 		.tx_stats_read = iwl_ucode_tx_stats_read,
 		.general_stats_read = iwl_ucode_general_stats_read,
+		.bt_stats_read = iwl_ucode_bt_stats_read,
 	},
+	.recover_from_tx_stall = iwl_bg_monitor_recover,
 	.check_plcp_health = iwl_good_plcp_health,
 };
 
@@ -2285,7 +2333,7 @@
 	 * Force use of chains B and C for scan RX on 5 GHz band
 	 * because the device has off-channel reception on chain A.
 	 */
-	.scan_antennas[IEEE80211_BAND_5GHZ] = ANT_BC,
+	.scan_rx_antennas[IEEE80211_BAND_5GHZ] = ANT_BC,
 };
 
 /* Module firmware */
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index a28af7e..8093ce2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -179,8 +179,8 @@
 			priv->cfg->num_of_queues *
 			sizeof(struct iwlagn_scd_bc_tbl);
 	priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
-	priv->hw_params.max_stations = IWL5000_STATION_COUNT;
-	priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+	priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
+	priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
 
 	priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
 	priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@@ -208,6 +208,8 @@
 		BIT(IWL_CALIB_TX_IQ_PERD)	|
 		BIT(IWL_CALIB_BASE_BAND);
 
+	priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
+
 	return 0;
 }
 
@@ -224,8 +226,8 @@
 			priv->cfg->num_of_queues *
 			sizeof(struct iwlagn_scd_bc_tbl);
 	priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
-	priv->hw_params.max_stations = IWL5000_STATION_COUNT;
-	priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+	priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
+	priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
 
 	priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
 	priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@@ -247,10 +249,13 @@
 	/* Set initial calibration set */
 	priv->hw_params.sens = &iwl5150_sensitivity;
 	priv->hw_params.calib_init_cfg =
-		BIT(IWL_CALIB_DC)		|
 		BIT(IWL_CALIB_LO)		|
 		BIT(IWL_CALIB_TX_IQ)		|
 		BIT(IWL_CALIB_BASE_BAND);
+	if (priv->cfg->need_dc_calib)
+		priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC);
+
+	priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
 
 	return 0;
 }
@@ -260,40 +265,76 @@
 	u32 vt = 0;
 	s32 offset =  iwl_temp_calib_to_offset(priv);
 
-	vt = le32_to_cpu(priv->statistics.general.temperature);
+	vt = le32_to_cpu(priv->_agn.statistics.general.common.temperature);
 	vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
 	/* now vt hold the temperature in Kelvin */
 	priv->temperature = KELVIN_TO_CELSIUS(vt);
 	iwl_tt_handler(priv);
 }
 
-static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
+				     struct ieee80211_channel_switch *ch_switch)
 {
 	struct iwl5000_channel_switch_cmd cmd;
 	const struct iwl_channel_info *ch_info;
+	u32 switch_time_in_usec, ucode_switch_time;
+	u16 ch;
+	u32 tsf_low;
+	u8 switch_count;
+	u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
+	struct ieee80211_vif *vif = priv->vif;
 	struct iwl_host_cmd hcmd = {
 		.id = REPLY_CHANNEL_SWITCH,
 		.len = sizeof(cmd),
-		.flags = CMD_SIZE_HUGE,
+		.flags = CMD_SYNC,
 		.data = &cmd,
 	};
 
-	IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
-		priv->active_rxon.channel, channel);
 	cmd.band = priv->band == IEEE80211_BAND_2GHZ;
-	cmd.channel = cpu_to_le16(channel);
+	ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+	IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
+		priv->active_rxon.channel, ch);
+	cmd.channel = cpu_to_le16(ch);
 	cmd.rxon_flags = priv->staging_rxon.flags;
 	cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
-	cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
-	ch_info = iwl_get_channel_info(priv, priv->band, channel);
+	switch_count = ch_switch->count;
+	tsf_low = ch_switch->timestamp & 0x0ffffffff;
+	/*
+	 * calculate the ucode channel switch time
+	 * adding TSF as one of the factor for when to switch
+	 */
+	if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
+		if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
+		    beacon_interval)) {
+			switch_count -= (priv->ucode_beacon_time -
+				tsf_low) / beacon_interval;
+		} else
+			switch_count = 0;
+	}
+	if (switch_count <= 1)
+		cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+	else {
+		switch_time_in_usec =
+			vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
+		ucode_switch_time = iwl_usecs_to_beacons(priv,
+							 switch_time_in_usec,
+							 beacon_interval);
+		cmd.switch_time = iwl_add_beacon_time(priv,
+						      priv->ucode_beacon_time,
+						      ucode_switch_time,
+						      beacon_interval);
+	}
+	IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
+		      cmd.switch_time);
+	ch_info = iwl_get_channel_info(priv, priv->band, ch);
 	if (ch_info)
 		cmd.expect_beacon = is_channel_radar(ch_info);
 	else {
 		IWL_ERR(priv, "invalid channel switch from %u to %u\n",
-			priv->active_rxon.channel, channel);
+			priv->active_rxon.channel, ch);
 		return -EFAULT;
 	}
-	priv->switch_rxon.channel = cpu_to_le16(channel);
+	priv->switch_rxon.channel = cmd.channel;
 	priv->switch_rxon.switch_in_progress = true;
 
 	return iwl_send_cmd_sync(priv, &hcmd);
@@ -352,14 +393,18 @@
 		.set_ct_kill = iwl5000_set_ct_threshold,
 	 },
 	.manage_ibss_station = iwlagn_manage_ibss_station,
+	.update_bcast_station = iwl_update_bcast_station,
 	.debugfs_ops = {
 		.rx_stats_read = iwl_ucode_rx_stats_read,
 		.tx_stats_read = iwl_ucode_tx_stats_read,
 		.general_stats_read = iwl_ucode_general_stats_read,
+		.bt_stats_read = iwl_ucode_bt_stats_read,
 	},
 	.recover_from_tx_stall = iwl_bg_monitor_recover,
 	.check_plcp_health = iwl_good_plcp_health,
 	.check_ack_health = iwl_good_ack_health,
+	.txfifo_flush = iwlagn_txfifo_flush,
+	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
 
 static struct iwl_lib_ops iwl5150_lib = {
@@ -414,6 +459,7 @@
 		.set_ct_kill = iwl5150_set_ct_threshold,
 	 },
 	.manage_ibss_station = iwlagn_manage_ibss_station,
+	.update_bcast_station = iwl_update_bcast_station,
 	.debugfs_ops = {
 		.rx_stats_read = iwl_ucode_rx_stats_read,
 		.tx_stats_read = iwl_ucode_tx_stats_read,
@@ -422,6 +468,8 @@
 	.recover_from_tx_stall = iwl_bg_monitor_recover,
 	.check_plcp_health = iwl_good_plcp_health,
 	.check_ack_health = iwl_good_ack_health,
+	.txfifo_flush = iwlagn_txfifo_flush,
+	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
 
 static const struct iwl_ops iwl5000_ops = {
@@ -620,6 +668,7 @@
 	.ucode_tracing = true,
 	.sensitivity_calib_by_driver = true,
 	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
 };
 
 struct iwl_cfg iwl5150_abg_cfg = {
@@ -649,6 +698,7 @@
 	.ucode_tracing = true,
 	.sensitivity_calib_by_driver = true,
 	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
 };
 
 MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 9fbf54c..5827052 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -71,6 +71,10 @@
 #define _IWL6000G2A_MODULE_FIRMWARE(api) IWL6000G2A_FW_PRE #api ".ucode"
 #define IWL6000G2A_MODULE_FIRMWARE(api) _IWL6000G2A_MODULE_FIRMWARE(api)
 
+#define IWL6000G2B_FW_PRE "iwlwifi-6000g2b-"
+#define _IWL6000G2B_MODULE_FIRMWARE(api) IWL6000G2B_FW_PRE #api ".ucode"
+#define IWL6000G2B_MODULE_FIRMWARE(api) _IWL6000G2B_MODULE_FIRMWARE(api)
+
 
 static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
 {
@@ -80,9 +84,10 @@
 }
 
 /* Indicate calibration version to uCode. */
-static void iwl6050_set_calib_version(struct iwl_priv *priv)
+static void iwl6000_set_calib_version(struct iwl_priv *priv)
 {
-	if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
+	if (priv->cfg->need_dc_calib &&
+	    (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6))
 		iwl_set_bit(priv, CSR_GP_DRIVER_REG,
 				CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
 }
@@ -155,8 +160,8 @@
 			priv->cfg->num_of_queues *
 			sizeof(struct iwlagn_scd_bc_tbl);
 	priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
-	priv->hw_params.max_stations = IWL5000_STATION_COUNT;
-	priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+	priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
+	priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
 
 	priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
 	priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
@@ -182,83 +187,77 @@
 		BIT(IWL_CALIB_LO)		|
 		BIT(IWL_CALIB_TX_IQ)		|
 		BIT(IWL_CALIB_BASE_BAND);
+	if (priv->cfg->need_dc_calib)
+		priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC);
+
+	priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
 
 	return 0;
 }
 
-static int iwl6050_hw_set_hw_params(struct iwl_priv *priv)
-{
-	if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
-	    priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
-		priv->cfg->num_of_queues =
-			priv->cfg->mod_params->num_of_queues;
-
-	priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
-	priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
-	priv->hw_params.scd_bc_tbls_size =
-			priv->cfg->num_of_queues *
-			sizeof(struct iwlagn_scd_bc_tbl);
-	priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
-	priv->hw_params.max_stations = IWL5000_STATION_COUNT;
-	priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
-
-	priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
-	priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
-
-	priv->hw_params.max_bsm_size = 0;
-	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
-					BIT(IEEE80211_BAND_5GHZ);
-	priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
-
-	priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
-	priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
-	priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
-	priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
-
-	if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
-		priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
-
-	/* Set initial sensitivity parameters */
-	/* Set initial calibration set */
-	priv->hw_params.sens = &iwl6000_sensitivity;
-	priv->hw_params.calib_init_cfg =
-		BIT(IWL_CALIB_XTAL)		|
-		BIT(IWL_CALIB_DC)		|
-		BIT(IWL_CALIB_LO)		|
-		BIT(IWL_CALIB_TX_IQ)		|
-		BIT(IWL_CALIB_BASE_BAND);
-
-	return 0;
-}
-
-static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
+				     struct ieee80211_channel_switch *ch_switch)
 {
 	struct iwl6000_channel_switch_cmd cmd;
 	const struct iwl_channel_info *ch_info;
+	u32 switch_time_in_usec, ucode_switch_time;
+	u16 ch;
+	u32 tsf_low;
+	u8 switch_count;
+	u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
+	struct ieee80211_vif *vif = priv->vif;
 	struct iwl_host_cmd hcmd = {
 		.id = REPLY_CHANNEL_SWITCH,
 		.len = sizeof(cmd),
-		.flags = CMD_SIZE_HUGE,
+		.flags = CMD_SYNC,
 		.data = &cmd,
 	};
 
-	IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
-		priv->active_rxon.channel, channel);
-
 	cmd.band = priv->band == IEEE80211_BAND_2GHZ;
-	cmd.channel = cpu_to_le16(channel);
+	ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+	IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
+		      priv->active_rxon.channel, ch);
+	cmd.channel = cpu_to_le16(ch);
 	cmd.rxon_flags = priv->staging_rxon.flags;
 	cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
-	cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
-	ch_info = iwl_get_channel_info(priv, priv->band, channel);
+	switch_count = ch_switch->count;
+	tsf_low = ch_switch->timestamp & 0x0ffffffff;
+	/*
+	 * calculate the ucode channel switch time
+	 * adding TSF as one of the factor for when to switch
+	 */
+	if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
+		if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
+		    beacon_interval)) {
+			switch_count -= (priv->ucode_beacon_time -
+				tsf_low) / beacon_interval;
+		} else
+			switch_count = 0;
+	}
+	if (switch_count <= 1)
+		cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+	else {
+		switch_time_in_usec =
+			vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
+		ucode_switch_time = iwl_usecs_to_beacons(priv,
+							 switch_time_in_usec,
+							 beacon_interval);
+		cmd.switch_time = iwl_add_beacon_time(priv,
+						      priv->ucode_beacon_time,
+						      ucode_switch_time,
+						      beacon_interval);
+	}
+	IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
+		      cmd.switch_time);
+	ch_info = iwl_get_channel_info(priv, priv->band, ch);
 	if (ch_info)
 		cmd.expect_beacon = is_channel_radar(ch_info);
 	else {
 		IWL_ERR(priv, "invalid channel switch from %u to %u\n",
-			priv->active_rxon.channel, channel);
+			priv->active_rxon.channel, ch);
 		return -EFAULT;
 	}
-	priv->switch_rxon.channel = cpu_to_le16(channel);
+	priv->switch_rxon.channel = cmd.channel;
 	priv->switch_rxon.switch_in_progress = true;
 
 	return iwl_send_cmd_sync(priv, &hcmd);
@@ -316,16 +315,21 @@
 	.temp_ops = {
 		.temperature = iwlagn_temperature,
 		.set_ct_kill = iwl6000_set_ct_threshold,
+		.set_calib_version = iwl6000_set_calib_version,
 	 },
 	.manage_ibss_station = iwlagn_manage_ibss_station,
+	.update_bcast_station = iwl_update_bcast_station,
 	.debugfs_ops = {
 		.rx_stats_read = iwl_ucode_rx_stats_read,
 		.tx_stats_read = iwl_ucode_tx_stats_read,
 		.general_stats_read = iwl_ucode_general_stats_read,
+		.bt_stats_read = iwl_ucode_bt_stats_read,
 	},
 	.recover_from_tx_stall = iwl_bg_monitor_recover,
 	.check_plcp_health = iwl_good_plcp_health,
 	.check_ack_health = iwl_good_ack_health,
+	.txfifo_flush = iwlagn_txfifo_flush,
+	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
 
 static const struct iwl_ops iwl6000_ops = {
@@ -335,79 +339,25 @@
 	.led = &iwlagn_led_ops,
 };
 
-static struct iwl_lib_ops iwl6050_lib = {
-	.set_hw_params = iwl6050_hw_set_hw_params,
-	.txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
-	.txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
-	.txq_set_sched = iwlagn_txq_set_sched,
-	.txq_agg_enable = iwlagn_txq_agg_enable,
-	.txq_agg_disable = iwlagn_txq_agg_disable,
-	.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-	.txq_free_tfd = iwl_hw_txq_free_tfd,
-	.txq_init = iwl_hw_tx_queue_init,
-	.rx_handler_setup = iwlagn_rx_handler_setup,
-	.setup_deferred_work = iwlagn_setup_deferred_work,
-	.is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-	.load_ucode = iwlagn_load_ucode,
-	.dump_nic_event_log = iwl_dump_nic_event_log,
-	.dump_nic_error_log = iwl_dump_nic_error_log,
-	.dump_csr = iwl_dump_csr,
-	.dump_fh = iwl_dump_fh,
-	.init_alive_start = iwlagn_init_alive_start,
-	.alive_notify = iwlagn_alive_notify,
-	.send_tx_power = iwlagn_send_tx_power,
-	.update_chain_flags = iwl_update_chain_flags,
-	.set_channel_switch = iwl6000_hw_channel_switch,
-	.apm_ops = {
-		.init = iwl_apm_init,
-		.stop = iwl_apm_stop,
-		.config = iwl6000_nic_config,
-		.set_pwr_src = iwl_set_pwr_src,
-	},
-	.eeprom_ops = {
-		.regulatory_bands = {
-			EEPROM_REG_BAND_1_CHANNELS,
-			EEPROM_REG_BAND_2_CHANNELS,
-			EEPROM_REG_BAND_3_CHANNELS,
-			EEPROM_REG_BAND_4_CHANNELS,
-			EEPROM_REG_BAND_5_CHANNELS,
-			EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
-			EEPROM_REG_BAND_52_HT40_CHANNELS
-		},
-		.verify_signature  = iwlcore_eeprom_verify_signature,
-		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
-		.release_semaphore = iwlcore_eeprom_release_semaphore,
-		.calib_version	= iwlagn_eeprom_calib_version,
-		.query_addr = iwlagn_eeprom_query_addr,
-		.update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
-	},
-	.post_associate = iwl_post_associate,
-	.isr = iwl_isr_ict,
-	.config_ap = iwl_config_ap,
-	.temp_ops = {
-		.temperature = iwlagn_temperature,
-		.set_ct_kill = iwl6000_set_ct_threshold,
-		.set_calib_version = iwl6050_set_calib_version,
-	 },
-	.manage_ibss_station = iwlagn_manage_ibss_station,
-	.debugfs_ops = {
-		.rx_stats_read = iwl_ucode_rx_stats_read,
-		.tx_stats_read = iwl_ucode_tx_stats_read,
-		.general_stats_read = iwl_ucode_general_stats_read,
-	},
-	.recover_from_tx_stall = iwl_bg_monitor_recover,
-	.check_plcp_health = iwl_good_plcp_health,
-	.check_ack_health = iwl_good_ack_health,
+static void do_not_send_bt_config(struct iwl_priv *priv)
+{
+}
+
+static struct iwl_hcmd_ops iwl6000g2b_hcmd = {
+	.rxon_assoc = iwlagn_send_rxon_assoc,
+	.commit_rxon = iwl_commit_rxon,
+	.set_rxon_chain = iwl_set_rxon_chain,
+	.set_tx_ant = iwlagn_send_tx_ant_config,
+	.send_bt_config = do_not_send_bt_config,
 };
 
-static const struct iwl_ops iwl6050_ops = {
-	.lib = &iwl6050_lib,
-	.hcmd = &iwlagn_hcmd,
+static const struct iwl_ops iwl6000g2b_ops = {
+	.lib = &iwl6000_lib,
+	.hcmd = &iwl6000g2b_hcmd,
 	.utils = &iwlagn_hcmd_utils,
 	.led = &iwlagn_led_ops,
 };
 
-
 struct iwl_cfg iwl6000g2a_2agn_cfg = {
 	.name = "6000 Series 2x2 AGN Gen2a",
 	.fw_name_pre = IWL6000G2A_FW_PRE,
@@ -443,6 +393,299 @@
 	.ucode_tracing = true,
 	.sensitivity_calib_by_driver = true,
 	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
+};
+
+struct iwl_cfg iwl6000g2a_2abg_cfg = {
+	.name = "6000 Series 2x2 ABG Gen2a",
+	.fw_name_pre = IWL6000G2A_FW_PRE,
+	.ucode_api_max = IWL6000G2_UCODE_API_MAX,
+	.ucode_api_min = IWL6000G2_UCODE_API_MIN,
+	.sku = IWL_SKU_A|IWL_SKU_G,
+	.ops = &iwl6000_ops,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+	.mod_params = &iwlagn_mod_params,
+	.valid_tx_ant = ANT_AB,
+	.valid_rx_ant = ANT_AB,
+	.pll_cfg_val = 0,
+	.set_l0s = true,
+	.use_bsm = false,
+	.pa_type = IWL_PA_SYSTEM,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.led_compensation = 51,
+	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+	.supports_idle = true,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.monitor_recover_period = IWL_MONITORING_PERIOD,
+	.max_event_log_size = 512,
+	.sensitivity_calib_by_driver = true,
+	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
+};
+
+struct iwl_cfg iwl6000g2a_2bg_cfg = {
+	.name = "6000 Series 2x2 BG Gen2a",
+	.fw_name_pre = IWL6000G2A_FW_PRE,
+	.ucode_api_max = IWL6000G2_UCODE_API_MAX,
+	.ucode_api_min = IWL6000G2_UCODE_API_MIN,
+	.sku = IWL_SKU_G,
+	.ops = &iwl6000_ops,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+	.mod_params = &iwlagn_mod_params,
+	.valid_tx_ant = ANT_AB,
+	.valid_rx_ant = ANT_AB,
+	.pll_cfg_val = 0,
+	.set_l0s = true,
+	.use_bsm = false,
+	.pa_type = IWL_PA_SYSTEM,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.led_compensation = 51,
+	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+	.supports_idle = true,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.monitor_recover_period = IWL_MONITORING_PERIOD,
+	.max_event_log_size = 512,
+	.sensitivity_calib_by_driver = true,
+	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
+};
+
+struct iwl_cfg iwl6000g2b_2agn_cfg = {
+	.name = "6000 Series 2x2 AGN Gen2b",
+	.fw_name_pre = IWL6000G2B_FW_PRE,
+	.ucode_api_max = IWL6000G2_UCODE_API_MAX,
+	.ucode_api_min = IWL6000G2_UCODE_API_MIN,
+	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+	.ops = &iwl6000g2b_ops,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+	.mod_params = &iwlagn_mod_params,
+	.valid_tx_ant = ANT_AB,
+	.valid_rx_ant = ANT_AB,
+	.pll_cfg_val = 0,
+	.set_l0s = true,
+	.use_bsm = false,
+	.pa_type = IWL_PA_SYSTEM,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.ht_greenfield_support = true,
+	.led_compensation = 51,
+	.use_rts_for_ht = true, /* use rts/cts protection */
+	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+	.supports_idle = true,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.monitor_recover_period = IWL_MONITORING_PERIOD,
+	.max_event_log_size = 512,
+	.sensitivity_calib_by_driver = true,
+	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
+	.bt_statistics = true,
+};
+
+struct iwl_cfg iwl6000g2b_2abg_cfg = {
+	.name = "6000 Series 2x2 ABG Gen2b",
+	.fw_name_pre = IWL6000G2B_FW_PRE,
+	.ucode_api_max = IWL6000G2_UCODE_API_MAX,
+	.ucode_api_min = IWL6000G2_UCODE_API_MIN,
+	.sku = IWL_SKU_A|IWL_SKU_G,
+	.ops = &iwl6000g2b_ops,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+	.mod_params = &iwlagn_mod_params,
+	.valid_tx_ant = ANT_AB,
+	.valid_rx_ant = ANT_AB,
+	.pll_cfg_val = 0,
+	.set_l0s = true,
+	.use_bsm = false,
+	.pa_type = IWL_PA_SYSTEM,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.led_compensation = 51,
+	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+	.supports_idle = true,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.monitor_recover_period = IWL_MONITORING_PERIOD,
+	.max_event_log_size = 512,
+	.sensitivity_calib_by_driver = true,
+	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
+	.bt_statistics = true,
+};
+
+struct iwl_cfg iwl6000g2b_2bgn_cfg = {
+	.name = "6000 Series 2x2 BGN Gen2b",
+	.fw_name_pre = IWL6000G2B_FW_PRE,
+	.ucode_api_max = IWL6000G2_UCODE_API_MAX,
+	.ucode_api_min = IWL6000G2_UCODE_API_MIN,
+	.sku = IWL_SKU_G|IWL_SKU_N,
+	.ops = &iwl6000g2b_ops,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+	.mod_params = &iwlagn_mod_params,
+	.valid_tx_ant = ANT_AB,
+	.valid_rx_ant = ANT_AB,
+	.pll_cfg_val = 0,
+	.set_l0s = true,
+	.use_bsm = false,
+	.pa_type = IWL_PA_SYSTEM,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.ht_greenfield_support = true,
+	.led_compensation = 51,
+	.use_rts_for_ht = true, /* use rts/cts protection */
+	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+	.supports_idle = true,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.monitor_recover_period = IWL_MONITORING_PERIOD,
+	.max_event_log_size = 512,
+	.sensitivity_calib_by_driver = true,
+	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
+	.bt_statistics = true,
+};
+
+struct iwl_cfg iwl6000g2b_2bg_cfg = {
+	.name = "6000 Series 2x2 BG Gen2b",
+	.fw_name_pre = IWL6000G2B_FW_PRE,
+	.ucode_api_max = IWL6000G2_UCODE_API_MAX,
+	.ucode_api_min = IWL6000G2_UCODE_API_MIN,
+	.sku = IWL_SKU_G,
+	.ops = &iwl6000g2b_ops,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+	.mod_params = &iwlagn_mod_params,
+	.valid_tx_ant = ANT_AB,
+	.valid_rx_ant = ANT_AB,
+	.pll_cfg_val = 0,
+	.set_l0s = true,
+	.use_bsm = false,
+	.pa_type = IWL_PA_SYSTEM,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.led_compensation = 51,
+	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+	.supports_idle = true,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.monitor_recover_period = IWL_MONITORING_PERIOD,
+	.max_event_log_size = 512,
+	.sensitivity_calib_by_driver = true,
+	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
+	.bt_statistics = true,
+};
+
+struct iwl_cfg iwl6000g2b_bgn_cfg = {
+	.name = "6000 Series 1x2 BGN Gen2b",
+	.fw_name_pre = IWL6000G2B_FW_PRE,
+	.ucode_api_max = IWL6000G2_UCODE_API_MAX,
+	.ucode_api_min = IWL6000G2_UCODE_API_MIN,
+	.sku = IWL_SKU_G|IWL_SKU_N,
+	.ops = &iwl6000g2b_ops,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+	.mod_params = &iwlagn_mod_params,
+	.valid_tx_ant = ANT_A,
+	.valid_rx_ant = ANT_AB,
+	.pll_cfg_val = 0,
+	.set_l0s = true,
+	.use_bsm = false,
+	.pa_type = IWL_PA_SYSTEM,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.ht_greenfield_support = true,
+	.led_compensation = 51,
+	.use_rts_for_ht = true, /* use rts/cts protection */
+	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+	.supports_idle = true,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.monitor_recover_period = IWL_MONITORING_PERIOD,
+	.max_event_log_size = 512,
+	.sensitivity_calib_by_driver = true,
+	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
+	.bt_statistics = true,
+};
+
+struct iwl_cfg iwl6000g2b_bg_cfg = {
+	.name = "6000 Series 1x2 BG Gen2b",
+	.fw_name_pre = IWL6000G2B_FW_PRE,
+	.ucode_api_max = IWL6000G2_UCODE_API_MAX,
+	.ucode_api_min = IWL6000G2_UCODE_API_MIN,
+	.sku = IWL_SKU_G,
+	.ops = &iwl6000g2b_ops,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+	.mod_params = &iwlagn_mod_params,
+	.valid_tx_ant = ANT_A,
+	.valid_rx_ant = ANT_AB,
+	.pll_cfg_val = 0,
+	.set_l0s = true,
+	.use_bsm = false,
+	.pa_type = IWL_PA_SYSTEM,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.led_compensation = 51,
+	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+	.supports_idle = true,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.monitor_recover_period = IWL_MONITORING_PERIOD,
+	.max_event_log_size = 512,
+	.sensitivity_calib_by_driver = true,
+	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
+	.bt_statistics = true,
 };
 
 /*
@@ -561,7 +804,7 @@
 	.ucode_api_max = IWL6050_UCODE_API_MAX,
 	.ucode_api_min = IWL6050_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
-	.ops = &iwl6050_ops,
+	.ops = &iwl6000_ops,
 	.eeprom_size = OTP_LOW_IMAGE_SIZE,
 	.eeprom_ver = EEPROM_6050_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
@@ -590,6 +833,45 @@
 	.ucode_tracing = true,
 	.sensitivity_calib_by_driver = true,
 	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
+};
+
+struct iwl_cfg iwl6050g2_bgn_cfg = {
+	.name = "6050 Series 1x2 BGN Gen2",
+	.fw_name_pre = IWL6050_FW_PRE,
+	.ucode_api_max = IWL6050_UCODE_API_MAX,
+	.ucode_api_min = IWL6050_UCODE_API_MIN,
+	.sku = IWL_SKU_G|IWL_SKU_N,
+	.ops = &iwl6000_ops,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.eeprom_ver = EEPROM_6050G2_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_6050G2_TX_POWER_VERSION,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+	.mod_params = &iwlagn_mod_params,
+	.valid_tx_ant = ANT_A,
+	.valid_rx_ant = ANT_AB,
+	.pll_cfg_val = 0,
+	.set_l0s = true,
+	.use_bsm = false,
+	.pa_type = IWL_PA_SYSTEM,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x50,
+	.shadow_ram_support = true,
+	.ht_greenfield_support = true,
+	.led_compensation = 51,
+	.use_rts_for_ht = true, /* use rts/cts protection */
+	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+	.supports_idle = true,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1500,
+	.monitor_recover_period = IWL_MONITORING_PERIOD,
+	.max_event_log_size = 1024,
+	.ucode_tracing = true,
+	.sensitivity_calib_by_driver = true,
+	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
 };
 
 struct iwl_cfg iwl6050_2abg_cfg = {
@@ -598,7 +880,7 @@
 	.ucode_api_max = IWL6050_UCODE_API_MAX,
 	.ucode_api_min = IWL6050_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G,
-	.ops = &iwl6050_ops,
+	.ops = &iwl6000_ops,
 	.eeprom_size = OTP_LOW_IMAGE_SIZE,
 	.eeprom_ver = EEPROM_6050_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
@@ -625,6 +907,7 @@
 	.ucode_tracing = true,
 	.sensitivity_calib_by_driver = true,
 	.chain_noise_calib_by_driver = true,
+	.need_dc_calib = true,
 };
 
 struct iwl_cfg iwl6000_3agn_cfg = {
@@ -667,3 +950,4 @@
 MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL6000G2B_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
similarity index 83%
rename from drivers/net/wireless/iwlwifi/iwl-calib.c
rename to drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index 7e8227773..c4c5691 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
@@ -96,17 +96,16 @@
 			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;
+			if (ret) {
+				IWL_ERR(priv, "Error %d iteration %d\n",
+					ret, i);
+				break;
+			}
 		}
 	}
 
-	return 0;
-err:
-	IWL_ERR(priv, "Error %d iteration %d\n", ret, i);
 	return ret;
 }
-EXPORT_SYMBOL(iwl_send_calib_results);
 
 int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len)
 {
@@ -121,7 +120,6 @@
 	memcpy(res->buf, buf, len);
 	return 0;
 }
-EXPORT_SYMBOL(iwl_calib_set);
 
 void iwl_calib_free_results(struct iwl_priv *priv)
 {
@@ -133,7 +131,6 @@
 		priv->calib_results[i].buf_len = 0;
 	}
 }
-EXPORT_SYMBOL(iwl_calib_free_results);
 
 /*****************************************************************************
  * RUNTIME calibrations framework
@@ -412,10 +409,50 @@
 	return 0;
 }
 
+static void iwl_prepare_legacy_sensitivity_tbl(struct iwl_priv *priv,
+				struct iwl_sensitivity_data *data,
+				__le16 *tbl)
+{
+	tbl[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
+				cpu_to_le16((u16)data->auto_corr_ofdm);
+	tbl[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
+				cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
+	tbl[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
+				cpu_to_le16((u16)data->auto_corr_ofdm_x1);
+	tbl[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
+				cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
+
+	tbl[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
+				cpu_to_le16((u16)data->auto_corr_cck);
+	tbl[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
+				cpu_to_le16((u16)data->auto_corr_cck_mrc);
+
+	tbl[HD_MIN_ENERGY_CCK_DET_INDEX] =
+				cpu_to_le16((u16)data->nrg_th_cck);
+	tbl[HD_MIN_ENERGY_OFDM_DET_INDEX] =
+				cpu_to_le16((u16)data->nrg_th_ofdm);
+
+	tbl[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
+				cpu_to_le16(data->barker_corr_th_min);
+	tbl[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
+				cpu_to_le16(data->barker_corr_th_min_mrc);
+	tbl[HD_OFDM_ENERGY_TH_IN_INDEX] =
+				cpu_to_le16(data->nrg_th_cca);
+
+	IWL_DEBUG_CALIB(priv, "ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
+			data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
+			data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1,
+			data->nrg_th_ofdm);
+
+	IWL_DEBUG_CALIB(priv, "cck: ac %u mrc %u thresh %u\n",
+			data->auto_corr_cck, data->auto_corr_cck_mrc,
+			data->nrg_th_cck);
+}
+
 /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
 static int iwl_sensitivity_write(struct iwl_priv *priv)
 {
-	struct iwl_sensitivity_cmd cmd ;
+	struct iwl_sensitivity_cmd cmd;
 	struct iwl_sensitivity_data *data = NULL;
 	struct iwl_host_cmd cmd_out = {
 		.id = SENSITIVITY_CMD,
@@ -428,40 +465,7 @@
 
 	memset(&cmd, 0, sizeof(cmd));
 
-	cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
-				cpu_to_le16((u16)data->auto_corr_ofdm);
-	cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
-				cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
-	cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
-				cpu_to_le16((u16)data->auto_corr_ofdm_x1);
-	cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
-				cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
-
-	cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
-				cpu_to_le16((u16)data->auto_corr_cck);
-	cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
-				cpu_to_le16((u16)data->auto_corr_cck_mrc);
-
-	cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] =
-				cpu_to_le16((u16)data->nrg_th_cck);
-	cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] =
-				cpu_to_le16((u16)data->nrg_th_ofdm);
-
-	cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
-				cpu_to_le16(data->barker_corr_th_min);
-	cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
-				cpu_to_le16(data->barker_corr_th_min_mrc);
-	cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] =
-				cpu_to_le16(data->nrg_th_cca);
-
-	IWL_DEBUG_CALIB(priv, "ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
-			data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
-			data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1,
-			data->nrg_th_ofdm);
-
-	IWL_DEBUG_CALIB(priv, "cck: ac %u mrc %u thresh %u\n",
-			data->auto_corr_cck, data->auto_corr_cck_mrc,
-			data->nrg_th_cck);
+	iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.table[0]);
 
 	/* Update uCode's "work" table, and copy it to DSP */
 	cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
@@ -480,6 +484,70 @@
 	return iwl_send_cmd(priv, &cmd_out);
 }
 
+/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
+static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
+{
+	struct iwl_enhance_sensitivity_cmd cmd;
+	struct iwl_sensitivity_data *data = NULL;
+	struct iwl_host_cmd cmd_out = {
+		.id = SENSITIVITY_CMD,
+		.len = sizeof(struct iwl_enhance_sensitivity_cmd),
+		.flags = CMD_ASYNC,
+		.data = &cmd,
+	};
+
+	data = &(priv->sensitivity_data);
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]);
+
+	cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
+		HD_INA_NON_SQUARE_DET_OFDM_DATA;
+	cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
+		HD_INA_NON_SQUARE_DET_CCK_DATA;
+	cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
+		HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA;
+	cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+		HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA;
+	cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+		HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA;
+	cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
+		HD_OFDM_NON_SQUARE_DET_SLOPE_DATA;
+	cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
+		HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA;
+	cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+		HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA;
+	cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+		HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA;
+	cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
+		HD_CCK_NON_SQUARE_DET_SLOPE_DATA;
+	cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
+		HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA;
+
+	/* Update uCode's "work" table, and copy it to DSP */
+	cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
+
+	/* Don't send command to uCode if nothing has changed */
+	if (!memcmp(&cmd.enhance_table[0], &(priv->sensitivity_tbl[0]),
+		    sizeof(u16)*HD_TABLE_SIZE) &&
+	    !memcmp(&cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX],
+		    &(priv->enhance_sensitivity_tbl[0]),
+		    sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES)) {
+		IWL_DEBUG_CALIB(priv, "No change in SENSITIVITY_CMD\n");
+		return 0;
+	}
+
+	/* Copy table for comparison next time */
+	memcpy(&(priv->sensitivity_tbl[0]), &(cmd.enhance_table[0]),
+	       sizeof(u16)*HD_TABLE_SIZE);
+	memcpy(&(priv->enhance_sensitivity_tbl[0]),
+	       &(cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX]),
+	       sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES);
+
+	return iwl_send_cmd(priv, &cmd_out);
+}
+
 void iwl_init_sensitivity(struct iwl_priv *priv)
 {
 	int ret = 0;
@@ -530,13 +598,14 @@
 	data->last_bad_plcp_cnt_cck = 0;
 	data->last_fa_cnt_cck = 0;
 
-	ret |= iwl_sensitivity_write(priv);
+	if (priv->enhance_sensitivity_table)
+		ret |= iwl_enhance_sensitivity_write(priv);
+	else
+		ret |= iwl_sensitivity_write(priv);
 	IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);
 }
-EXPORT_SYMBOL(iwl_init_sensitivity);
 
-void iwl_sensitivity_calibration(struct iwl_priv *priv,
-				    struct iwl_notif_statistics *resp)
+void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp)
 {
 	u32 rx_enable_time;
 	u32 fa_cck;
@@ -546,8 +615,8 @@
 	u32 norm_fa_ofdm;
 	u32 norm_fa_cck;
 	struct iwl_sensitivity_data *data = NULL;
-	struct statistics_rx_non_phy *rx_info = &(resp->rx.general);
-	struct statistics_rx *statistics = &(resp->rx);
+	struct statistics_rx_non_phy *rx_info;
+	struct statistics_rx_phy *ofdm, *cck;
 	unsigned long flags;
 	struct statistics_general_data statis;
 
@@ -562,6 +631,16 @@
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
+	if (priv->cfg->bt_statistics) {
+		rx_info = &(((struct iwl_bt_notif_statistics *)resp)->
+			      rx.general.common);
+		ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm);
+		cck = &(((struct iwl_bt_notif_statistics *)resp)->rx.cck);
+	} else {
+		rx_info = &(((struct iwl_notif_statistics *)resp)->rx.general);
+		ofdm = &(((struct iwl_notif_statistics *)resp)->rx.ofdm);
+		cck = &(((struct iwl_notif_statistics *)resp)->rx.cck);
+	}
 	if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
 		IWL_DEBUG_CALIB(priv, "<< invalid data.\n");
 		spin_unlock_irqrestore(&priv->lock, flags);
@@ -570,23 +649,23 @@
 
 	/* Extract Statistics: */
 	rx_enable_time = le32_to_cpu(rx_info->channel_load);
-	fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt);
-	fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt);
-	bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err);
-	bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err);
+	fa_cck = le32_to_cpu(cck->false_alarm_cnt);
+	fa_ofdm = le32_to_cpu(ofdm->false_alarm_cnt);
+	bad_plcp_cck = le32_to_cpu(cck->plcp_err);
+	bad_plcp_ofdm = le32_to_cpu(ofdm->plcp_err);
 
 	statis.beacon_silence_rssi_a =
-			le32_to_cpu(statistics->general.beacon_silence_rssi_a);
+			le32_to_cpu(rx_info->beacon_silence_rssi_a);
 	statis.beacon_silence_rssi_b =
-			le32_to_cpu(statistics->general.beacon_silence_rssi_b);
+			le32_to_cpu(rx_info->beacon_silence_rssi_b);
 	statis.beacon_silence_rssi_c =
-			le32_to_cpu(statistics->general.beacon_silence_rssi_c);
+			le32_to_cpu(rx_info->beacon_silence_rssi_c);
 	statis.beacon_energy_a =
-			le32_to_cpu(statistics->general.beacon_energy_a);
+			le32_to_cpu(rx_info->beacon_energy_a);
 	statis.beacon_energy_b =
-			le32_to_cpu(statistics->general.beacon_energy_b);
+			le32_to_cpu(rx_info->beacon_energy_b);
 	statis.beacon_energy_c =
-			le32_to_cpu(statistics->general.beacon_energy_c);
+			le32_to_cpu(rx_info->beacon_energy_c);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -637,9 +716,11 @@
 
 	iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
 	iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
-	iwl_sensitivity_write(priv);
+	if (priv->enhance_sensitivity_table)
+		iwl_enhance_sensitivity_write(priv);
+	else
+		iwl_sensitivity_write(priv);
 }
-EXPORT_SYMBOL(iwl_sensitivity_calibration);
 
 static inline u8 find_first_chain(u8 mask)
 {
@@ -656,8 +737,7 @@
  * 1)  Which antennas are connected.
  * 2)  Differential rx gain settings to balance the 3 receivers.
  */
-void iwl_chain_noise_calibration(struct iwl_priv *priv,
-				 struct iwl_notif_statistics *stat_resp)
+void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
 {
 	struct iwl_chain_noise_data *data = NULL;
 
@@ -681,7 +761,7 @@
 	u32 active_chains = 0;
 	u8 num_tx_chains;
 	unsigned long flags;
-	struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general);
+	struct statistics_rx_non_phy *rx_info;
 	u8 first_chain;
 
 	if (priv->disable_chain_noise_cal)
@@ -700,6 +780,13 @@
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
+	if (priv->cfg->bt_statistics) {
+		rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)->
+			      rx.general.common);
+	} else {
+		rx_info = &(((struct iwl_notif_statistics *)stat_resp)->
+			      rx.general);
+	}
 	if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
 		IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n");
 		spin_unlock_irqrestore(&priv->lock, flags);
@@ -708,8 +795,19 @@
 
 	rxon_band24 = !!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK);
 	rxon_chnum = le16_to_cpu(priv->staging_rxon.channel);
-	stat_band24 = !!(stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK);
-	stat_chnum = le32_to_cpu(stat_resp->flag) >> 16;
+	if (priv->cfg->bt_statistics) {
+		stat_band24 = !!(((struct iwl_bt_notif_statistics *)
+				 stat_resp)->flag &
+				 STATISTICS_REPLY_FLG_BAND_24G_MSK);
+		stat_chnum = le32_to_cpu(((struct iwl_bt_notif_statistics *)
+					 stat_resp)->flag) >> 16;
+	} else {
+		stat_band24 = !!(((struct iwl_notif_statistics *)
+				 stat_resp)->flag &
+				 STATISTICS_REPLY_FLG_BAND_24G_MSK);
+		stat_chnum = le32_to_cpu(((struct iwl_notif_statistics *)
+					 stat_resp)->flag) >> 16;
+	}
 
 	/* Make sure we accumulate data for just the associated channel
 	 *   (even if scanning). */
@@ -846,6 +944,13 @@
 		}
 	}
 
+	if (active_chains != priv->hw_params.valid_rx_ant &&
+	    active_chains != priv->chain_noise_data.active_chains)
+		IWL_DEBUG_CALIB(priv,
+				"Detected that not all antennas are connected! "
+				"Connected: %#x, valid: %#x.\n",
+				active_chains, priv->hw_params.valid_rx_ant);
+
 	/* Save for use within RXON, TX, SCAN commands, etc. */
 	priv->chain_noise_data.active_chains = active_chains;
 	IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n",
@@ -890,8 +995,6 @@
 	data->state = IWL_CHAIN_NOISE_DONE;
 	iwl_power_update_mode(priv, false);
 }
-EXPORT_SYMBOL(iwl_chain_noise_calibration);
-
 
 void iwl_reset_run_time_calib(struct iwl_priv *priv)
 {
@@ -908,5 +1011,3 @@
 	 * periodically after association */
 	iwl_send_statistics_request(priv, CMD_ASYNC, true);
 }
-EXPORT_SYMBOL(iwl_reset_run_time_calib);
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
index 48c023b..f052c6d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
@@ -28,6 +28,30 @@
 
 #include "iwl-agn-debugfs.h"
 
+static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
+{
+	int p = 0;
+	u32 flag;
+
+	if (priv->cfg->bt_statistics)
+		flag = le32_to_cpu(priv->_agn.statistics_bt.flag);
+	else
+		flag = le32_to_cpu(priv->_agn.statistics.flag);
+
+	p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag);
+	if (flag & UCODE_STATISTICS_CLEAR_MSK)
+		p += scnprintf(buf + p, bufsz - p,
+		"\tStatistics have been cleared\n");
+	p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
+		(flag & UCODE_STATISTICS_FREQUENCY_MSK)
+		? "2.4 GHz" : "5.2 GHz");
+	p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
+		(flag & UCODE_STATISTICS_NARROW_BAND_MSK)
+		 ? "enabled" : "disabled");
+
+	return p;
+}
+
 ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
 				size_t count, loff_t *ppos)
   {
@@ -58,24 +82,45 @@
 	 * the last statistics notification from uCode
 	 * might not reflect the current uCode activity
 	 */
-	ofdm = &priv->statistics.rx.ofdm;
-	cck = &priv->statistics.rx.cck;
-	general = &priv->statistics.rx.general;
-	ht = &priv->statistics.rx.ofdm_ht;
-	accum_ofdm = &priv->accum_statistics.rx.ofdm;
-	accum_cck = &priv->accum_statistics.rx.cck;
-	accum_general = &priv->accum_statistics.rx.general;
-	accum_ht = &priv->accum_statistics.rx.ofdm_ht;
-	delta_ofdm = &priv->delta_statistics.rx.ofdm;
-	delta_cck = &priv->delta_statistics.rx.cck;
-	delta_general = &priv->delta_statistics.rx.general;
-	delta_ht = &priv->delta_statistics.rx.ofdm_ht;
-	max_ofdm = &priv->max_delta.rx.ofdm;
-	max_cck = &priv->max_delta.rx.cck;
-	max_general = &priv->max_delta.rx.general;
-	max_ht = &priv->max_delta.rx.ofdm_ht;
+	if (priv->cfg->bt_statistics) {
+		ofdm = &priv->_agn.statistics_bt.rx.ofdm;
+		cck = &priv->_agn.statistics_bt.rx.cck;
+		general = &priv->_agn.statistics_bt.rx.general.common;
+		ht = &priv->_agn.statistics_bt.rx.ofdm_ht;
+		accum_ofdm = &priv->_agn.accum_statistics_bt.rx.ofdm;
+		accum_cck = &priv->_agn.accum_statistics_bt.rx.cck;
+		accum_general =
+			&priv->_agn.accum_statistics_bt.rx.general.common;
+		accum_ht = &priv->_agn.accum_statistics_bt.rx.ofdm_ht;
+		delta_ofdm = &priv->_agn.delta_statistics_bt.rx.ofdm;
+		delta_cck = &priv->_agn.delta_statistics_bt.rx.cck;
+		delta_general =
+			&priv->_agn.delta_statistics_bt.rx.general.common;
+		delta_ht = &priv->_agn.delta_statistics_bt.rx.ofdm_ht;
+		max_ofdm = &priv->_agn.max_delta_bt.rx.ofdm;
+		max_cck = &priv->_agn.max_delta_bt.rx.cck;
+		max_general = &priv->_agn.max_delta_bt.rx.general.common;
+		max_ht = &priv->_agn.max_delta_bt.rx.ofdm_ht;
+	} else {
+		ofdm = &priv->_agn.statistics.rx.ofdm;
+		cck = &priv->_agn.statistics.rx.cck;
+		general = &priv->_agn.statistics.rx.general;
+		ht = &priv->_agn.statistics.rx.ofdm_ht;
+		accum_ofdm = &priv->_agn.accum_statistics.rx.ofdm;
+		accum_cck = &priv->_agn.accum_statistics.rx.cck;
+		accum_general = &priv->_agn.accum_statistics.rx.general;
+		accum_ht = &priv->_agn.accum_statistics.rx.ofdm_ht;
+		delta_ofdm = &priv->_agn.delta_statistics.rx.ofdm;
+		delta_cck = &priv->_agn.delta_statistics.rx.cck;
+		delta_general = &priv->_agn.delta_statistics.rx.general;
+		delta_ht = &priv->_agn.delta_statistics.rx.ofdm_ht;
+		max_ofdm = &priv->_agn.max_delta.rx.ofdm;
+		max_cck = &priv->_agn.max_delta.rx.cck;
+		max_general = &priv->_agn.max_delta.rx.general;
+		max_ht = &priv->_agn.max_delta.rx.ofdm_ht;
+	}
 
-	pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+	pos += iwl_statistics_flag(priv, buf, bufsz);
 	pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
 			 "acumulative       delta         max\n",
 			 "Statistics_Rx - OFDM:");
@@ -539,11 +584,19 @@
 	  * the last statistics notification from uCode
 	  * might not reflect the current uCode activity
 	  */
-	tx = &priv->statistics.tx;
-	accum_tx = &priv->accum_statistics.tx;
-	delta_tx = &priv->delta_statistics.tx;
-	max_tx = &priv->max_delta.tx;
-	pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+	if (priv->cfg->bt_statistics) {
+		tx = &priv->_agn.statistics_bt.tx;
+		accum_tx = &priv->_agn.accum_statistics_bt.tx;
+		delta_tx = &priv->_agn.delta_statistics_bt.tx;
+		max_tx = &priv->_agn.max_delta_bt.tx;
+	} else {
+		tx = &priv->_agn.statistics.tx;
+		accum_tx = &priv->_agn.accum_statistics.tx;
+		delta_tx = &priv->_agn.delta_statistics.tx;
+		max_tx = &priv->_agn.max_delta.tx;
+	}
+
+	pos += iwl_statistics_flag(priv, buf, bufsz);
 	pos += scnprintf(buf + pos, bufsz - pos,  "%-32s     current"
 			 "acumulative       delta         max\n",
 			 "Statistics_Tx:");
@@ -738,8 +791,8 @@
 	char *buf;
 	int bufsz = sizeof(struct statistics_general) * 10 + 300;
 	ssize_t ret;
-	struct statistics_general *general, *accum_general;
-	struct statistics_general *delta_general, *max_general;
+	struct statistics_general_common *general, *accum_general;
+	struct statistics_general_common *delta_general, *max_general;
 	struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
 	struct statistics_div *div, *accum_div, *delta_div, *max_div;
 
@@ -756,19 +809,35 @@
 	  * the last statistics notification from uCode
 	  * might not reflect the current uCode activity
 	  */
-	general = &priv->statistics.general;
-	dbg = &priv->statistics.general.dbg;
-	div = &priv->statistics.general.div;
-	accum_general = &priv->accum_statistics.general;
-	delta_general = &priv->delta_statistics.general;
-	max_general = &priv->max_delta.general;
-	accum_dbg = &priv->accum_statistics.general.dbg;
-	delta_dbg = &priv->delta_statistics.general.dbg;
-	max_dbg = &priv->max_delta.general.dbg;
-	accum_div = &priv->accum_statistics.general.div;
-	delta_div = &priv->delta_statistics.general.div;
-	max_div = &priv->max_delta.general.div;
-	pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+	if (priv->cfg->bt_statistics) {
+		general = &priv->_agn.statistics_bt.general.common;
+		dbg = &priv->_agn.statistics_bt.general.common.dbg;
+		div = &priv->_agn.statistics_bt.general.common.div;
+		accum_general = &priv->_agn.accum_statistics_bt.general.common;
+		accum_dbg = &priv->_agn.accum_statistics_bt.general.common.dbg;
+		accum_div = &priv->_agn.accum_statistics_bt.general.common.div;
+		delta_general = &priv->_agn.delta_statistics_bt.general.common;
+		max_general = &priv->_agn.max_delta_bt.general.common;
+		delta_dbg = &priv->_agn.delta_statistics_bt.general.common.dbg;
+		max_dbg = &priv->_agn.max_delta_bt.general.common.dbg;
+		delta_div = &priv->_agn.delta_statistics_bt.general.common.div;
+		max_div = &priv->_agn.max_delta_bt.general.common.div;
+	} else {
+		general = &priv->_agn.statistics.general.common;
+		dbg = &priv->_agn.statistics.general.common.dbg;
+		div = &priv->_agn.statistics.general.common.div;
+		accum_general = &priv->_agn.accum_statistics.general.common;
+		accum_dbg = &priv->_agn.accum_statistics.general.common.dbg;
+		accum_div = &priv->_agn.accum_statistics.general.common.div;
+		delta_general = &priv->_agn.delta_statistics.general.common;
+		max_general = &priv->_agn.max_delta.general.common;
+		delta_dbg = &priv->_agn.delta_statistics.general.common.dbg;
+		max_dbg = &priv->_agn.max_delta.general.common.dbg;
+		delta_div = &priv->_agn.delta_statistics.general.common.div;
+		max_div = &priv->_agn.max_delta.general.common.div;
+	}
+
+	pos += iwl_statistics_flag(priv, buf, bufsz);
 	pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
 			 "acumulative       delta         max\n",
 			 "Statistics_General:");
@@ -792,6 +861,13 @@
 			 delta_dbg->burst_count, max_dbg->burst_count);
 	pos += scnprintf(buf + pos, bufsz - pos,
 			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "wait_for_silence_timeout_count:",
+			 le32_to_cpu(dbg->wait_for_silence_timeout_cnt),
+			 accum_dbg->wait_for_silence_timeout_cnt,
+			 delta_dbg->wait_for_silence_timeout_cnt,
+			 max_dbg->wait_for_silence_timeout_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
 			 "sleep_time:",
 			 le32_to_cpu(general->sleep_time),
 			 accum_general->sleep_time,
@@ -848,3 +924,90 @@
 	kfree(buf);
 	return ret;
 }
+
+ssize_t iwl_ucode_bt_stats_read(struct file *file,
+				char __user *user_buf,
+				size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+	int pos = 0;
+	char *buf;
+	int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200;
+	ssize_t ret;
+	struct statistics_bt_activity *bt, *accum_bt;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	/* make request to uCode to retrieve statistics information */
+	mutex_lock(&priv->mutex);
+	ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
+	mutex_unlock(&priv->mutex);
+
+	if (ret) {
+		IWL_ERR(priv,
+			"Error sending statistics request: %zd\n", ret);
+		return -EAGAIN;
+	}
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf) {
+		IWL_ERR(priv, "Can not allocate Buffer\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * the statistic information display here is based on
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+	bt = &priv->_agn.statistics_bt.general.activity;
+	accum_bt = &priv->_agn.accum_statistics_bt.general.activity;
+
+	pos += iwl_statistics_flag(priv, buf, bufsz);
+	pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"\t\t\tcurrent\t\t\taccumulative\n");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->hi_priority_tx_req_cnt),
+			 accum_bt->hi_priority_tx_req_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->hi_priority_tx_denied_cnt),
+			 accum_bt->hi_priority_tx_denied_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->lo_priority_tx_req_cnt),
+			 accum_bt->lo_priority_tx_req_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->lo_priority_tx_denied_cnt),
+			 accum_bt->lo_priority_tx_denied_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->hi_priority_rx_req_cnt),
+			 accum_bt->hi_priority_rx_req_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->hi_priority_rx_denied_cnt),
+			 accum_bt->hi_priority_rx_denied_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->lo_priority_rx_req_cnt),
+			 accum_bt->lo_priority_rx_req_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->lo_priority_rx_denied_cnt),
+			 accum_bt->lo_priority_rx_denied_cnt);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "(rx)num_bt_kills:\t\t%u\t\t\t%u\n",
+			 le32_to_cpu(priv->_agn.statistics_bt.rx.
+				general.num_bt_kills),
+			 priv->_agn.accum_statistics_bt.rx.
+				general.num_bt_kills);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
index 59b1f25..bbdce59 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
@@ -37,6 +37,8 @@
 				size_t count, loff_t *ppos);
 ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
 				     size_t count, loff_t *ppos);
+ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf,
+				size_t count, loff_t *ppos);
 #else
 static ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
 				       size_t count, loff_t *ppos)
@@ -53,4 +55,9 @@
 {
 	return 0;
 }
+static ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	return 0;
+}
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
index 01658cf..a7216dd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
@@ -37,7 +37,7 @@
 #include "iwl-io.h"
 #include "iwl-agn.h"
 
-static int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
+int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
 {
 	int ret = 0;
 	struct iwl5000_rxon_assoc_cmd rxon_assoc;
@@ -84,7 +84,7 @@
 	return ret;
 }
 
-static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
+int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
 {
 	struct iwl_tx_ant_config_cmd tx_ant_cmd = {
 	  .valid = cpu_to_le32(valid_tx_ant),
@@ -164,7 +164,7 @@
 
 		memset(&cmd, 0, sizeof(cmd));
 
-		cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
+		cmd.hdr.op_code = priv->_agn.phy_calib_chain_noise_gain_cmd;
 		cmd.hdr.first_group = 0;
 		cmd.hdr.groups_num = 1;
 		cmd.hdr.data_valid = 1;
@@ -176,14 +176,6 @@
 		data->radio_write = 1;
 		data->state = IWL_CHAIN_NOISE_CALIBRATED;
 	}
-
-	data->chain_noise_a = 0;
-	data->chain_noise_b = 0;
-	data->chain_noise_c = 0;
-	data->chain_signal_a = 0;
-	data->chain_signal_b = 0;
-	data->chain_signal_c = 0;
-	data->beacon_count = 0;
 }
 
 static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
@@ -191,11 +183,21 @@
 	struct iwl_chain_noise_data *data = &priv->chain_noise_data;
 	int ret;
 
-	if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+	if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
+	     iwl_is_associated(priv)) {
 		struct iwl_calib_chain_noise_reset_cmd cmd;
-		memset(&cmd, 0, sizeof(cmd));
 
-		cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
+		/* clear data for chain noise calibration algorithm */
+		data->chain_noise_a = 0;
+		data->chain_noise_b = 0;
+		data->chain_noise_c = 0;
+		data->chain_signal_a = 0;
+		data->chain_signal_b = 0;
+		data->chain_signal_c = 0;
+		data->beacon_count = 0;
+
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.hdr.op_code = priv->_agn.phy_calib_chain_noise_reset_cmd;
 		cmd.hdr.first_group = 0;
 		cmd.hdr.groups_num = 1;
 		cmd.hdr.data_valid = 1;
@@ -212,7 +214,7 @@
 static void iwlagn_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
 			__le32 *tx_flags)
 {
-	*tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
+	*tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
 }
 
 /* Calc max signal level (dBm) among 3 possible receivers */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
index f9a3fbb..a52b82c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
@@ -112,7 +112,7 @@
  */
 struct iwlagn_scd_bc_tbl {
 	__le16 tfd_offset[TFD_QUEUE_BC_SIZE];
-} __attribute__ ((packed));
+} __packed;
 
 
 #endif /* __iwl_agn_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 0f292a2..a1b6d20 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -77,7 +77,7 @@
 		IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
 				   agg->frame_count, agg->start_idx, idx);
 
-		info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+		info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb);
 		info->status.rates[0].count = tx_resp->failure_frame + 1;
 		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
 		info->flags |= iwl_tx_status_to_mac80211(status);
@@ -93,6 +93,12 @@
 	} else {
 		/* Two or more frames were attempted; expect block-ack */
 		u64 bitmap = 0;
+
+		/*
+		 * Start is the lowest frame sent. It may not be the first
+		 * frame in the batch; we figure this out dynamically during
+		 * the following loop.
+		 */
 		int start = agg->start_idx;
 
 		/* Construct bit-map of pending frames within Tx window */
@@ -131,25 +137,58 @@
 			IWL_DEBUG_TX_REPLY(priv, "AGG Frame i=%d idx %d seq=%d\n",
 					   i, idx, SEQ_TO_SN(sc));
 
+			/*
+			 * sh -> how many frames ahead of the starting frame is
+			 * the current one?
+			 *
+			 * Note that all frames sent in the batch must be in a
+			 * 64-frame window, so this number should be in [0,63].
+			 * If outside of this window, then we've found a new
+			 * "first" frame in the batch and need to change start.
+			 */
 			sh = idx - start;
-			if (sh > 64) {
-				sh = (start - idx) + 0xff;
+
+			/*
+			 * If >= 64, out of window. start must be at the front
+			 * of the circular buffer, idx must be near the end of
+			 * the buffer, and idx is the new "first" frame. Shift
+			 * the indices around.
+			 */
+			if (sh >= 64) {
+				/* Shift bitmap by start - idx, wrapped */
+				sh = 0x100 - idx + start;
 				bitmap = bitmap << sh;
+				/* Now idx is the new start so sh = 0 */
 				sh = 0;
 				start = idx;
-			} else if (sh < -64)
-				sh  = 0xff - (start - idx);
-			else if (sh < 0) {
+			/*
+			 * If <= -64 then wraps the 256-pkt circular buffer
+			 * (e.g., start = 255 and idx = 0, sh should be 1)
+			 */
+			} else if (sh <= -64) {
+				sh  = 0x100 - start + idx;
+			/*
+			 * If < 0 but > -64, out of window. idx is before start
+			 * but not wrapped. Shift the indices around.
+			 */
+			} else if (sh < 0) {
+				/* Shift by how far start is ahead of idx */
 				sh = start - idx;
-				start = idx;
 				bitmap = bitmap << sh;
+				/* Now idx is the new start so sh = 0 */
+				start = idx;
 				sh = 0;
 			}
+			/* Sequence number start + sh was sent in this batch */
 			bitmap |= 1ULL << sh;
 			IWL_DEBUG_TX_REPLY(priv, "start=%d bitmap=0x%llx\n",
 					   start, (unsigned long long)bitmap);
 		}
 
+		/*
+		 * Store the bitmap and possibly the new start, if we wrapped
+		 * the buffer above
+		 */
 		agg->bitmap = bitmap;
 		agg->start_idx = start;
 		IWL_DEBUG_TX_REPLY(priv, "Frames %d start_idx=%d bitmap=0x%llx\n",
@@ -166,7 +205,9 @@
 			    u8 frame_count, u32 status)
 {
 	if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) {
-		IWL_ERR(priv, "TODO: Implement Tx flush command!!!\n");
+		IWL_ERR(priv, "Tx flush command to flush out all frames\n");
+		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+			queue_work(priv->workqueue, &priv->tx_flush);
 	}
 }
 
@@ -184,6 +225,7 @@
 	int tid;
 	int sta_id;
 	int freed;
+	unsigned long flags;
 
 	if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
 		IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
@@ -193,15 +235,16 @@
 		return;
 	}
 
-	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
 	memset(&info->status, 0, sizeof(info->status));
 
 	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;
 
+	spin_lock_irqsave(&priv->sta_lock, flags);
 	if (txq->sched_retry) {
 		const u32 scd_ssn = iwlagn_get_scd_ssn(tx_resp);
-		struct iwl_ht_agg *agg = NULL;
+		struct iwl_ht_agg *agg;
 
 		agg = &priv->stations[sta_id].tid[tid].agg;
 
@@ -256,6 +299,7 @@
 	iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
 
 	iwl_check_abort_status(priv, tx_resp->frame_count, status);
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
 
 void iwlagn_rx_handler_setup(struct iwl_priv *priv)
@@ -319,7 +363,8 @@
 void iwlagn_temperature(struct iwl_priv *priv)
 {
 	/* store temperature from statistics (in Celsius) */
-	priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
+	priv->temperature =
+		le32_to_cpu(priv->_agn.statistics.general.common.temperature);
 	iwl_tt_handler(priv);
 }
 
@@ -444,7 +489,7 @@
 
 	/* Tell device where to find RBD circular buffer in DRAM */
 	iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
-			   (u32)(rxq->dma_addr >> 8));
+			   (u32)(rxq->bd_dma >> 8));
 
 	/* Tell device where in DRAM to update its Rx status */
 	iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
@@ -709,7 +754,7 @@
 	}
 
 	dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
-			  rxq->dma_addr);
+			  rxq->bd_dma);
 	dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
 			  rxq->rb_stts, rxq->rb_stts_dma);
 	rxq->bd = NULL;
@@ -755,132 +800,6 @@
 	return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-/**
- * iwlagn_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 data frames.
- *    All beacon and probe response frames are printed.
- */
-static void iwlagn_dbg_report_frame(struct iwl_priv *priv,
-		      struct iwl_rx_phy_res *phy_res, u16 length,
-		      struct ieee80211_hdr *header, int group100)
-{
-	u32 to_us;
-	u32 print_summary = 0;
-	u32 print_dump = 0;	/* set to 1 to dump all frames' contents */
-	u32 hundred = 0;
-	u32 dataframe = 0;
-	__le16 fc;
-	u16 seq_ctl;
-	u16 channel;
-	u16 phy_flags;
-	u32 rate_n_flags;
-	u32 tsf_low;
-	int rssi;
-
-	if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX)))
-		return;
-
-	/* MAC header */
-	fc = header->frame_control;
-	seq_ctl = le16_to_cpu(header->seq_ctrl);
-
-	/* metadata */
-	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 = iwlagn_calc_rssi(priv, phy_res);
-	tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff;
-
-	to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
-
-	/* if data frame is to us and all is good,
-	 *   (optionally) print summary for only 1 out of every 100 */
-	if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) ==
-	    cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
-		dataframe = 1;
-		if (!group100)
-			print_summary = 1;	/* print each frame */
-		else if (priv->framecnt_to_us < 100) {
-			priv->framecnt_to_us++;
-			print_summary = 0;
-		} else {
-			priv->framecnt_to_us = 0;
-			print_summary = 1;
-			hundred = 1;
-		}
-	} else {
-		/* print summary for all other frames */
-		print_summary = 1;
-	}
-
-	if (print_summary) {
-		char *title;
-		int rate_idx;
-		u32 bitrate;
-
-		if (hundred)
-			title = "100Frames";
-		else if (ieee80211_has_retry(fc))
-			title = "Retry";
-		else if (ieee80211_is_assoc_resp(fc))
-			title = "AscRsp";
-		else if (ieee80211_is_reassoc_resp(fc))
-			title = "RasRsp";
-		else if (ieee80211_is_probe_resp(fc)) {
-			title = "PrbRsp";
-			print_dump = 1;	/* dump frame contents */
-		} else if (ieee80211_is_beacon(fc)) {
-			title = "Beacon";
-			print_dump = 1;	/* dump frame contents */
-		} else if (ieee80211_is_atim(fc))
-			title = "ATIM";
-		else if (ieee80211_is_auth(fc))
-			title = "Auth";
-		else if (ieee80211_is_deauth(fc))
-			title = "DeAuth";
-		else if (ieee80211_is_disassoc(fc))
-			title = "DisAssoc";
-		else
-			title = "Frame";
-
-		rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
-		if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) {
-			bitrate = 0;
-			WARN_ON_ONCE(1);
-		} else {
-			bitrate = iwl_rates[rate_idx].ieee / 2;
-		}
-
-		/* print frame summary.
-		 * MAC addresses show just the last byte (for brevity),
-		 *    but you can hack it to show more, if you'd like to. */
-		if (dataframe)
-			IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
-				     "len=%u, rssi=%d, chnl=%d, rate=%u,\n",
-				     title, le16_to_cpu(fc), header->addr1[5],
-				     length, rssi, channel, bitrate);
-		else {
-			/* src/dst addresses assume managed mode */
-			IWL_DEBUG_RX(priv, "%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], length, rssi,
-				     tsf_low - priv->scan_start_tsf,
-				     phy_flags, channel);
-		}
-	}
-	if (print_dump)
-		iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
-}
-#endif
-
 static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
 {
 	u32 decrypt_out = 0;
@@ -988,7 +907,7 @@
 	struct iwl_rx_packet *pkt = rxb_addr(rxb);
 	struct iwl_rx_phy_res *phy_res;
 	__le32 rx_pkt_status;
-	struct iwl4965_rx_mpdu_res_start *amsdu;
+	struct iwl_rx_mpdu_res_start *amsdu;
 	u32 len;
 	u32 ampdu_status;
 	u32 rate_n_flags;
@@ -1017,7 +936,7 @@
 			return;
 		}
 		phy_res = &priv->_agn.last_phy_res;
-		amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
+		amsdu = (struct iwl_rx_mpdu_res_start *)pkt->u.raw;
 		header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu));
 		len = le16_to_cpu(amsdu->byte_count);
 		rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len);
@@ -1060,11 +979,6 @@
 	/* Find max signal strength (dBm) among 3 antenna/receiver chains */
 	rx_status.signal = iwlagn_calc_rssi(priv, phy_res);
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	/* Set "1" to report good data frames in groups of 100 */
-	if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX))
-		iwlagn_dbg_report_frame(priv, phy_res, len, header, 1);
-#endif
 	iwl_dbg_log_rx_data_frame(priv, len, header);
 	IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n",
 		rx_status.signal, (unsigned long long)rx_status.mactime);
@@ -1252,6 +1166,7 @@
 	bool is_active = false;
 	int  chan_mod;
 	u8 active_chains;
+	u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
 
 	conf = ieee80211_get_hw_conf(priv->hw);
 
@@ -1319,7 +1234,10 @@
 
 		IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
 		spin_lock_irqsave(&priv->lock, flags);
-		interval = vif ? vif->bss_conf.beacon_int : 0;
+		if (priv->is_internal_short_scan)
+			interval = 0;
+		else
+			interval = vif->bss_conf.beacon_int;
 		spin_unlock_irqrestore(&priv->lock, flags);
 
 		scan->suspend_time = 0;
@@ -1403,11 +1321,14 @@
 
 	band = priv->scan_band;
 
-	if (priv->cfg->scan_antennas[band])
-		rx_ant = priv->cfg->scan_antennas[band];
+	if (priv->cfg->scan_rx_antennas[band])
+		rx_ant = priv->cfg->scan_rx_antennas[band];
 
-	priv->scan_tx_ant[band] =
-			iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band]);
+	if (priv->cfg->scan_tx_antennas[band])
+		scan_tx_antennas = priv->cfg->scan_tx_antennas[band];
+
+	priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band],
+						    scan_tx_antennas);
 	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);
 
@@ -1433,13 +1354,15 @@
 	if (!priv->is_internal_short_scan) {
 		cmd_len = iwl_fill_probe_req(priv,
 					(struct ieee80211_mgmt *)scan->data,
+					vif->addr,
 					priv->scan_request->ie,
 					priv->scan_request->ie_len,
 					IWL_MAX_SCAN_SIZE - sizeof(*scan));
 	} else {
+		/* use bcast addr, will not be transmitted but must be valid */
 		cmd_len = iwl_fill_probe_req(priv,
 					(struct ieee80211_mgmt *)scan->data,
-					NULL, 0,
+					iwl_bcast_addr, NULL, 0,
 					IWL_MAX_SCAN_SIZE - sizeof(*scan));
 
 	}
@@ -1502,3 +1425,96 @@
 	return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
 				  vif->bss_conf.bssid);
 }
+
+void iwl_free_tfds_in_queue(struct iwl_priv *priv,
+			    int sta_id, int tid, int freed)
+{
+	WARN_ON(!spin_is_locked(&priv->sta_lock));
+
+	if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
+		priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+	else {
+		IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n",
+			priv->stations[sta_id].tid[tid].tfds_in_queue,
+			freed);
+		priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
+	}
+}
+
+#define IWL_FLUSH_WAIT_MS	2000
+
+int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv)
+{
+	struct iwl_tx_queue *txq;
+	struct iwl_queue *q;
+	int cnt;
+	unsigned long now = jiffies;
+	int ret = 0;
+
+	/* waiting for all the tx frames complete might take a while */
+	for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
+		if (cnt == IWL_CMD_QUEUE_NUM)
+			continue;
+		txq = &priv->txq[cnt];
+		q = &txq->q;
+		while (q->read_ptr != q->write_ptr && !time_after(jiffies,
+		       now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS)))
+				msleep(1);
+
+		if (q->read_ptr != q->write_ptr) {
+			IWL_ERR(priv, "fail to flush all tx fifo queues\n");
+			ret = -ETIMEDOUT;
+			break;
+		}
+	}
+	return ret;
+}
+
+#define IWL_TX_QUEUE_MSK	0xfffff
+
+/**
+ * iwlagn_txfifo_flush: send REPLY_TXFIFO_FLUSH command to uCode
+ *
+ * pre-requirements:
+ *  1. acquire mutex before calling
+ *  2. make sure rf is on and not in exit state
+ */
+int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
+{
+	struct iwl_txfifo_flush_cmd flush_cmd;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_TXFIFO_FLUSH,
+		.len = sizeof(struct iwl_txfifo_flush_cmd),
+		.flags = CMD_SYNC,
+		.data = &flush_cmd,
+	};
+
+	might_sleep();
+
+	memset(&flush_cmd, 0, sizeof(flush_cmd));
+	flush_cmd.fifo_control = IWL_TX_FIFO_VO_MSK | IWL_TX_FIFO_VI_MSK |
+				 IWL_TX_FIFO_BE_MSK | IWL_TX_FIFO_BK_MSK;
+	if (priv->cfg->sku & IWL_SKU_N)
+		flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK;
+
+	IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n",
+		       flush_cmd.fifo_control);
+	flush_cmd.flush_control = cpu_to_le16(flush_control);
+
+	return iwl_send_cmd(priv, &cmd);
+}
+
+void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
+{
+	mutex_lock(&priv->mutex);
+	ieee80211_stop_queues(priv->hw);
+	if (priv->cfg->ops->lib->txfifo_flush(priv, IWL_DROP_ALL)) {
+		IWL_ERR(priv, "flush request fail\n");
+		goto done;
+	}
+	IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n");
+	iwlagn_wait_tx_queue_empty(priv);
+done:
+	ieee80211_wake_queues(priv->hw);
+	mutex_unlock(&priv->mutex);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index cf4a95b..35c86d2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -313,8 +313,7 @@
 			 */
 			IWL_DEBUG_HT(priv, "Fail start Tx agg on tid: %d\n",
 				tid);
-			ieee80211_stop_tx_ba_session(sta, tid,
-						WLAN_BACK_INITIATOR);
+			ieee80211_stop_tx_ba_session(sta, tid);
 		}
 	} else
 		IWL_ERR(priv, "Fail finding valid aggregation tid: %d\n", tid);
@@ -325,18 +324,11 @@
 			      struct iwl_lq_sta *lq_data,
 			      struct ieee80211_sta *sta)
 {
-	if ((tid < TID_MAX_LOAD_COUNT) &&
-	    !rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta)) {
-		if (priv->cfg->use_rts_for_ht) {
-			/*
-			 * switch to RTS/CTS if it is the prefer protection
-			 * method for HT traffic
-			 */
-			IWL_DEBUG_HT(priv, "use RTS/CTS protection for HT\n");
-			priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
-			iwlcore_commit_rxon(priv);
-		}
-	}
+	if (tid < TID_MAX_LOAD_COUNT)
+		rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
+	else
+		IWL_ERR(priv, "tid exceeds max load count: %d/%d\n",
+			tid, TID_MAX_LOAD_COUNT);
 }
 
 static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
new file mode 100644
index 0000000..9490ece
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
@@ -0,0 +1,351 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-calib.h"
+#include "iwl-sta.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+#include "iwl-agn-hw.h"
+#include "iwl-agn.h"
+
+void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
+				struct iwl_rx_mem_buffer *rxb)
+
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_missed_beacon_notif *missed_beacon;
+
+	missed_beacon = &pkt->u.missed_beacon;
+	if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
+	    priv->missed_beacon_threshold) {
+		IWL_DEBUG_CALIB(priv,
+		    "missed bcn cnsq %d totl %d rcd %d expctd %d\n",
+		    le32_to_cpu(missed_beacon->consecutive_missed_beacons),
+		    le32_to_cpu(missed_beacon->total_missed_becons),
+		    le32_to_cpu(missed_beacon->num_recvd_beacons),
+		    le32_to_cpu(missed_beacon->num_expected_beacons));
+		if (!test_bit(STATUS_SCANNING, &priv->status))
+			iwl_init_sensitivity(priv);
+	}
+}
+
+/* Calculate noise level, based on measurements during network silence just
+ *   before arriving beacon.  This measurement can be done only if we know
+ *   exactly when to expect beacons, therefore only when we're associated. */
+static void iwl_rx_calc_noise(struct iwl_priv *priv)
+{
+	struct statistics_rx_non_phy *rx_info;
+	int num_active_rx = 0;
+	int total_silence = 0;
+	int bcn_silence_a, bcn_silence_b, bcn_silence_c;
+	int last_rx_noise;
+
+	if (priv->cfg->bt_statistics)
+		rx_info = &(priv->_agn.statistics_bt.rx.general.common);
+	else
+		rx_info = &(priv->_agn.statistics.rx.general);
+	bcn_silence_a =
+		le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
+	bcn_silence_b =
+		le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
+	bcn_silence_c =
+		le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
+
+	if (bcn_silence_a) {
+		total_silence += bcn_silence_a;
+		num_active_rx++;
+	}
+	if (bcn_silence_b) {
+		total_silence += bcn_silence_b;
+		num_active_rx++;
+	}
+	if (bcn_silence_c) {
+		total_silence += bcn_silence_c;
+		num_active_rx++;
+	}
+
+	/* Average among active antennas */
+	if (num_active_rx)
+		last_rx_noise = (total_silence / num_active_rx) - 107;
+	else
+		last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+	IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",
+			bcn_silence_a, bcn_silence_b, bcn_silence_c,
+			last_rx_noise);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+/*
+ *  based on the assumption of all statistics counter are in DWORD
+ *  FIXME: This function is for debugging, do not deal with
+ *  the case of counters roll-over.
+ */
+static void iwl_accumulative_statistics(struct iwl_priv *priv,
+					__le32 *stats)
+{
+	int i, size;
+	__le32 *prev_stats;
+	u32 *accum_stats;
+	u32 *delta, *max_delta;
+	struct statistics_general_common *general, *accum_general;
+	struct statistics_tx *tx, *accum_tx;
+
+	if (priv->cfg->bt_statistics) {
+		prev_stats = (__le32 *)&priv->_agn.statistics_bt;
+		accum_stats = (u32 *)&priv->_agn.accum_statistics_bt;
+		size = sizeof(struct iwl_bt_notif_statistics);
+		general = &priv->_agn.statistics_bt.general.common;
+		accum_general = &priv->_agn.accum_statistics_bt.general.common;
+		tx = &priv->_agn.statistics_bt.tx;
+		accum_tx = &priv->_agn.accum_statistics_bt.tx;
+		delta = (u32 *)&priv->_agn.delta_statistics_bt;
+		max_delta = (u32 *)&priv->_agn.max_delta_bt;
+	} else {
+		prev_stats = (__le32 *)&priv->_agn.statistics;
+		accum_stats = (u32 *)&priv->_agn.accum_statistics;
+		size = sizeof(struct iwl_notif_statistics);
+		general = &priv->_agn.statistics.general.common;
+		accum_general = &priv->_agn.accum_statistics.general.common;
+		tx = &priv->_agn.statistics.tx;
+		accum_tx = &priv->_agn.accum_statistics.tx;
+		delta = (u32 *)&priv->_agn.delta_statistics;
+		max_delta = (u32 *)&priv->_agn.max_delta;
+	}
+	for (i = sizeof(__le32); i < size;
+	     i += sizeof(__le32), stats++, prev_stats++, delta++,
+	     max_delta++, accum_stats++) {
+		if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
+			*delta = (le32_to_cpu(*stats) -
+				le32_to_cpu(*prev_stats));
+			*accum_stats += *delta;
+			if (*delta > *max_delta)
+				*max_delta = *delta;
+		}
+	}
+
+	/* reset accumulative statistics for "no-counter" type statistics */
+	accum_general->temperature = general->temperature;
+	accum_general->temperature_m = general->temperature_m;
+	accum_general->ttl_timestamp = general->ttl_timestamp;
+	accum_tx->tx_power.ant_a = tx->tx_power.ant_a;
+	accum_tx->tx_power.ant_b = tx->tx_power.ant_b;
+	accum_tx->tx_power.ant_c = tx->tx_power.ant_c;
+}
+#endif
+
+#define REG_RECALIB_PERIOD (60)
+
+/**
+ * iwl_good_plcp_health - checks for plcp error.
+ *
+ * When the plcp error is exceeding the thresholds, reset the radio
+ * to improve the throughput.
+ */
+bool iwl_good_plcp_health(struct iwl_priv *priv,
+				struct iwl_rx_packet *pkt)
+{
+	bool rc = true;
+	int combined_plcp_delta;
+	unsigned int plcp_msec;
+	unsigned long plcp_received_jiffies;
+
+	if (priv->cfg->plcp_delta_threshold ==
+	    IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
+		IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
+		return rc;
+	}
+
+	/*
+	 * check for plcp_err and trigger radio reset if it exceeds
+	 * the plcp error threshold plcp_delta.
+	 */
+	plcp_received_jiffies = jiffies;
+	plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
+					(long) priv->plcp_jiffies);
+	priv->plcp_jiffies = plcp_received_jiffies;
+	/*
+	 * check to make sure plcp_msec is not 0 to prevent division
+	 * by zero.
+	 */
+	if (plcp_msec) {
+		struct statistics_rx_phy *ofdm;
+		struct statistics_rx_ht_phy *ofdm_ht;
+
+		if (priv->cfg->bt_statistics) {
+			ofdm = &pkt->u.stats_bt.rx.ofdm;
+			ofdm_ht = &pkt->u.stats_bt.rx.ofdm_ht;
+			combined_plcp_delta =
+			   (le32_to_cpu(ofdm->plcp_err) -
+			   le32_to_cpu(priv->_agn.statistics_bt.
+				       rx.ofdm.plcp_err)) +
+			   (le32_to_cpu(ofdm_ht->plcp_err) -
+			   le32_to_cpu(priv->_agn.statistics_bt.
+				       rx.ofdm_ht.plcp_err));
+		} else {
+			ofdm = &pkt->u.stats.rx.ofdm;
+			ofdm_ht = &pkt->u.stats.rx.ofdm_ht;
+			combined_plcp_delta =
+			    (le32_to_cpu(ofdm->plcp_err) -
+			    le32_to_cpu(priv->_agn.statistics.
+					rx.ofdm.plcp_err)) +
+			    (le32_to_cpu(ofdm_ht->plcp_err) -
+			    le32_to_cpu(priv->_agn.statistics.
+					rx.ofdm_ht.plcp_err));
+		}
+
+		if ((combined_plcp_delta > 0) &&
+		    ((combined_plcp_delta * 100) / plcp_msec) >
+			priv->cfg->plcp_delta_threshold) {
+			/*
+			 * if plcp_err exceed the threshold,
+			 * the following data is printed in csv format:
+			 *    Text: plcp_err exceeded %d,
+			 *    Received ofdm.plcp_err,
+			 *    Current ofdm.plcp_err,
+			 *    Received ofdm_ht.plcp_err,
+			 *    Current ofdm_ht.plcp_err,
+			 *    combined_plcp_delta,
+			 *    plcp_msec
+			 */
+			IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
+				    "%u, %u, %u, %u, %d, %u mSecs\n",
+				    priv->cfg->plcp_delta_threshold,
+				    le32_to_cpu(ofdm->plcp_err),
+				    le32_to_cpu(ofdm->plcp_err),
+				    le32_to_cpu(ofdm_ht->plcp_err),
+				    le32_to_cpu(ofdm_ht->plcp_err),
+				    combined_plcp_delta, plcp_msec);
+
+			rc = false;
+		}
+	}
+	return rc;
+}
+
+void iwl_rx_statistics(struct iwl_priv *priv,
+			      struct iwl_rx_mem_buffer *rxb)
+{
+	int change;
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
+	if (priv->cfg->bt_statistics) {
+		IWL_DEBUG_RX(priv,
+			     "Statistics notification received (%d vs %d).\n",
+			     (int)sizeof(struct iwl_bt_notif_statistics),
+			     le32_to_cpu(pkt->len_n_flags) &
+			     FH_RSCSR_FRAME_SIZE_MSK);
+
+		change = ((priv->_agn.statistics_bt.general.common.temperature !=
+			   pkt->u.stats_bt.general.common.temperature) ||
+			   ((priv->_agn.statistics_bt.flag &
+			   STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
+			   (pkt->u.stats_bt.flag &
+			   STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+		iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt);
+#endif
+
+	} else {
+		IWL_DEBUG_RX(priv,
+			     "Statistics notification received (%d vs %d).\n",
+			     (int)sizeof(struct iwl_notif_statistics),
+			     le32_to_cpu(pkt->len_n_flags) &
+			     FH_RSCSR_FRAME_SIZE_MSK);
+
+		change = ((priv->_agn.statistics.general.common.temperature !=
+			   pkt->u.stats.general.common.temperature) ||
+			   ((priv->_agn.statistics.flag &
+			   STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
+			   (pkt->u.stats.flag &
+			   STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+		iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
+#endif
+
+	}
+
+	iwl_recover_from_statistics(priv, pkt);
+
+	if (priv->cfg->bt_statistics)
+		memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt,
+			sizeof(priv->_agn.statistics_bt));
+	else
+		memcpy(&priv->_agn.statistics, &pkt->u.stats,
+			sizeof(priv->_agn.statistics));
+
+	set_bit(STATUS_STATISTICS, &priv->status);
+
+	/* Reschedule the statistics timer to occur in
+	 * REG_RECALIB_PERIOD seconds to ensure we get a
+	 * thermal update even if the uCode doesn't give
+	 * us one */
+	mod_timer(&priv->statistics_periodic, jiffies +
+		  msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
+
+	if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
+	    (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
+		iwl_rx_calc_noise(priv);
+		queue_work(priv->workqueue, &priv->run_time_calib_work);
+	}
+	if (priv->cfg->ops->lib->temp_ops.temperature && change)
+		priv->cfg->ops->lib->temp_ops.temperature(priv);
+}
+
+void iwl_reply_statistics(struct iwl_priv *priv,
+			      struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
+	if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+		memset(&priv->_agn.accum_statistics, 0,
+			sizeof(struct iwl_notif_statistics));
+		memset(&priv->_agn.delta_statistics, 0,
+			sizeof(struct iwl_notif_statistics));
+		memset(&priv->_agn.max_delta, 0,
+			sizeof(struct iwl_notif_statistics));
+		memset(&priv->_agn.accum_statistics_bt, 0,
+			sizeof(struct iwl_bt_notif_statistics));
+		memset(&priv->_agn.delta_statistics_bt, 0,
+			sizeof(struct iwl_bt_notif_statistics));
+		memset(&priv->_agn.max_delta_bt, 0,
+			sizeof(struct iwl_bt_notif_statistics));
+#endif
+		IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
+	}
+	iwl_rx_statistics(priv, rxb);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 7d614c4..55a1b31 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -233,6 +233,7 @@
 {
 	unsigned long flags;
 	u16 ra_tid;
+	int ret;
 
 	if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
 	    (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
@@ -248,7 +249,9 @@
 	ra_tid = BUILD_RAxTID(sta_id, tid);
 
 	/* Modify device's station table to Tx this TID */
-	iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+	ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+	if (ret)
+		return ret;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
@@ -469,7 +472,8 @@
 	}
 
 	/* Set up antennas */
-	priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+	priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+					      priv->hw_params.valid_tx_ant);
 	rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
 
 	/* Set the rate in the TX cmd */
@@ -567,10 +571,7 @@
 	hdr_len = ieee80211_hdrlen(fc);
 
 	/* Find index into station table for destination station */
-	if (!info->control.sta)
-		sta_id = priv->hw_params.bcast_sta_id;
-	else
-		sta_id = iwl_sta_id(info->control.sta);
+	sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
 	if (sta_id == IWL_INVALID_STATION) {
 		IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
 			       hdr->addr1);
@@ -598,11 +599,17 @@
 	}
 
 	txq_id = get_queue_from_ac(skb_get_queue_mapping(skb));
+
+	/* irqs already disabled/saved above when locking priv->lock */
+	spin_lock(&priv->sta_lock);
+
 	if (ieee80211_is_data_qos(fc)) {
 		qc = ieee80211_get_qos_ctl(hdr);
 		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-		if (unlikely(tid >= MAX_TID_COUNT))
+		if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) {
+			spin_unlock(&priv->sta_lock);
 			goto drop_unlock;
+		}
 		seq_number = priv->stations[sta_id].tid[tid].seq_number;
 		seq_number &= IEEE80211_SCTL_SEQ;
 		hdr->seq_ctrl = hdr->seq_ctrl &
@@ -620,15 +627,22 @@
 	swq_id = txq->swq_id;
 	q = &txq->q;
 
-	if (unlikely(iwl_queue_space(q) < q->high_mark))
+	if (unlikely(iwl_queue_space(q) < q->high_mark)) {
+		spin_unlock(&priv->sta_lock);
 		goto drop_unlock;
+	}
 
-	if (ieee80211_is_data_qos(fc))
+	if (ieee80211_is_data_qos(fc)) {
 		priv->stations[sta_id].tid[tid].tfds_in_queue++;
+		if (!ieee80211_has_morefrags(fc))
+			priv->stations[sta_id].tid[tid].seq_number = seq_number;
+	}
+
+	spin_unlock(&priv->sta_lock);
 
 	/* 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;
+	txq->txb[q->write_ptr].skb = skb;
 
 	/* Set up first empty entry in queue's array of Tx/cmd buffers */
 	out_cmd = txq->cmd[q->write_ptr];
@@ -694,8 +708,8 @@
 	txcmd_phys = pci_map_single(priv->pci_dev,
 				    &out_cmd->hdr, len,
 				    PCI_DMA_BIDIRECTIONAL);
-	pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
-	pci_unmap_len_set(out_meta, len, len);
+	dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+	dma_unmap_len_set(out_meta, len, len);
 	/* Add buffer containing Tx command and MAC(!) header to TFD's
 	 * first entry */
 	priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
@@ -703,8 +717,6 @@
 
 	if (!ieee80211_has_morefrags(hdr->frame_control)) {
 		txq->need_update = 1;
-		if (qc)
-			priv->stations[sta_id].tid[tid].seq_number = seq_number;
 	} else {
 		wait_write_ptr = 1;
 		txq->need_update = 0;
@@ -938,9 +950,12 @@
 	/* Stop each Tx DMA channel, and wait for it to be idle */
 	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,
+		if (iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
 				    FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
-				    1000);
+				    1000))
+			IWL_ERR(priv, "Failing on timeout while stopping"
+			    " DMA channel %d [0x%08x]", ch,
+			    iwl_read_direct32(priv, FH_TSSR_TX_STATUS_REG));
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
@@ -1009,6 +1024,8 @@
 	if (ret)
 		return ret;
 
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	tid_data = &priv->stations[sta_id].tid[tid];
 	if (tid_data->tfds_in_queue == 0) {
 		IWL_DEBUG_HT(priv, "HW queue is empty\n");
 		tid_data->agg.state = IWL_AGG_ON;
@@ -1018,6 +1035,7 @@
 			     tid_data->tfds_in_queue);
 		tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
 	}
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
 	return ret;
 }
 
@@ -1040,11 +1058,14 @@
 		return -ENXIO;
 	}
 
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
 	if (priv->stations[sta_id].tid[tid].agg.state ==
 				IWL_EMPTYING_HW_QUEUE_ADDBA) {
 		IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+		spin_unlock_irqrestore(&priv->sta_lock, flags);
 		return 0;
 	}
 
@@ -1062,13 +1083,17 @@
 		IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n");
 		priv->stations[sta_id].tid[tid].agg.state =
 				IWL_EMPTYING_HW_QUEUE_DELBA;
+		spin_unlock_irqrestore(&priv->sta_lock, flags);
 		return 0;
 	}
 
 	IWL_DEBUG_HT(priv, "HW queue is empty\n");
 	priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
 
-	spin_lock_irqsave(&priv->lock, flags);
+	/* do not restore/save irqs */
+	spin_unlock(&priv->sta_lock);
+	spin_lock(&priv->lock);
+
 	/*
 	 * the only reason this call can fail is queue number out of range,
 	 * which can happen if uCode is reloaded and all the station
@@ -1092,6 +1117,8 @@
 	u8 *addr = priv->stations[sta_id].sta.sta.addr;
 	struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
 
+	WARN_ON(!spin_is_locked(&priv->sta_lock));
+
 	switch (priv->stations[sta_id].tid[tid].agg.state) {
 	case IWL_EMPTYING_HW_QUEUE_DELBA:
 		/* We are reclaiming the last packet of the */
@@ -1116,6 +1143,7 @@
 		}
 		break;
 	}
+
 	return 0;
 }
 
@@ -1159,12 +1187,12 @@
 	     q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
 		tx_info = &txq->txb[txq->q.read_ptr];
-		iwlagn_tx_status(priv, tx_info->skb[0]);
+		iwlagn_tx_status(priv, tx_info->skb);
 
-		hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
+		hdr = (struct ieee80211_hdr *)tx_info->skb->data;
 		if (hdr && ieee80211_is_data_qos(hdr->frame_control))
 			nfreed++;
-		tx_info->skb[0] = NULL;
+		tx_info->skb = NULL;
 
 		if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
 			priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
@@ -1188,7 +1216,7 @@
 	int i, sh, ack;
 	u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
 	u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
-	u64 bitmap;
+	u64 bitmap, sent_bitmap;
 	int successes = 0;
 	struct ieee80211_tx_info *info;
 
@@ -1216,24 +1244,26 @@
 
 	/* check for success or failure according to the
 	 * transmitted bitmap and block-ack bitmap */
-	bitmap &= agg->bitmap;
+	sent_bitmap = bitmap & agg->bitmap;
 
 	/* For each frame attempted in aggregation,
 	 * update driver's record of tx frame's status. */
-	for (i = 0; i < agg->frame_count ; i++) {
-		ack = bitmap & (1ULL << i);
-		successes += !!ack;
+	i = 0;
+	while (sent_bitmap) {
+		ack = sent_bitmap & 1ULL;
+		successes += ack;
 		IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
 			ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
 			agg->start_idx + i);
+		sent_bitmap >>= 1;
+		++i;
 	}
 
-	info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
+	info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb);
 	memset(&info->status, 0, sizeof(info->status));
 	info->flags |= IEEE80211_TX_STAT_ACK;
 	info->flags |= IEEE80211_TX_STAT_AMPDU;
 	info->status.ampdu_ack_len = successes;
-	info->status.ampdu_ack_map = bitmap;
 	info->status.ampdu_len = agg->frame_count;
 	iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
 
@@ -1281,6 +1311,7 @@
 	int index;
 	int sta_id;
 	int tid;
+	unsigned long flags;
 
 	/* "flow" corresponds to Tx queue */
 	u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
@@ -1308,7 +1339,7 @@
 	/* 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 */
+	spin_lock_irqsave(&priv->sta_lock, flags);
 
 	IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
 			   "sta_id = %d\n",
@@ -1344,4 +1375,6 @@
 
 		iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow);
 	}
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index 637286c..6f77441 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -423,3 +423,126 @@
 
 	return 0;
 }
+
+
+/**
+ * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ *   using sample data 100 bytes apart.  If these sample points are good,
+ *   it's a pretty good bet that everything between them is good, too.
+ */
+static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+{
+	u32 val;
+	int ret = 0;
+	u32 errcnt = 0;
+	u32 i;
+
+	IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
+
+	for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
+		/* read data comes through single port, auto-incr addr */
+		/* NOTE: Use the debugless read so we don't flood kernel log
+		 * if IWL_DL_IO is set */
+		iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
+			i + IWLAGN_RTC_INST_LOWER_BOUND);
+		val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+		if (val != le32_to_cpu(*image)) {
+			ret = -EIO;
+			errcnt++;
+			if (errcnt >= 3)
+				break;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host,
+ *     looking at all data.
+ */
+static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image,
+				 u32 len)
+{
+	u32 val;
+	u32 save_len = len;
+	int ret = 0;
+	u32 errcnt;
+
+	IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
+
+	iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
+			   IWLAGN_RTC_INST_LOWER_BOUND);
+
+	errcnt = 0;
+	for (; len > 0; len -= sizeof(u32), image++) {
+		/* read data comes through single port, auto-incr addr */
+		/* NOTE: Use the debugless read so we don't flood kernel log
+		 * if IWL_DL_IO is set */
+		val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+		if (val != le32_to_cpu(*image)) {
+			IWL_ERR(priv, "uCode INST section is invalid at "
+				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
+				  save_len - len, val, le32_to_cpu(*image));
+			ret = -EIO;
+			errcnt++;
+			if (errcnt >= 20)
+				break;
+		}
+	}
+
+	if (!errcnt)
+		IWL_DEBUG_INFO(priv,
+		    "ucode image in INSTRUCTION memory is good\n");
+
+	return ret;
+}
+
+/**
+ * iwl_verify_ucode - determine which instruction image is in SRAM,
+ *    and verify its contents
+ */
+int iwl_verify_ucode(struct iwl_priv *priv)
+{
+	__le32 *image;
+	u32 len;
+	int ret;
+
+	/* Try bootstrap */
+	image = (__le32 *)priv->ucode_boot.v_addr;
+	len = priv->ucode_boot.len;
+	ret = iwlcore_verify_inst_sparse(priv, image, len);
+	if (!ret) {
+		IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	/* Try initialize */
+	image = (__le32 *)priv->ucode_init.v_addr;
+	len = priv->ucode_init.len;
+	ret = iwlcore_verify_inst_sparse(priv, image, len);
+	if (!ret) {
+		IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	/* Try runtime/protocol */
+	image = (__le32 *)priv->ucode_code.v_addr;
+	len = priv->ucode_code.len;
+	ret = iwlcore_verify_inst_sparse(priv, image, len);
+	if (!ret) {
+		IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+
+	/* Since nothing seems to match, show first several data entries in
+	 * instruction SRAM, so maybe visual inspection will give a clue.
+	 * Selection of bootstrap image (vs. other images) is arbitrary. */
+	image = (__le32 *)priv->ucode_boot.v_addr;
+	len = priv->ucode_boot.len;
+	ret = iwl_verify_inst_full(priv, image, len);
+
+	return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 24aff65..35337b1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -27,6 +27,8 @@
  *
  *****************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -120,7 +122,7 @@
 	    (priv->switch_rxon.channel != priv->staging_rxon.channel)) {
 		IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
 		      le16_to_cpu(priv->switch_rxon.channel));
-		priv->switch_rxon.switch_in_progress = false;
+		iwl_chswitch_done(priv, false);
 	}
 
 	/* If we don't need to send a full RXON, we can use
@@ -292,9 +294,7 @@
 					  struct ieee80211_hdr *hdr,
 					  int left)
 {
-	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
-	    ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
-	     (priv->iw_mode != NL80211_IFTYPE_AP)))
+	if (!priv->ibss_beacon)
 		return 0;
 
 	if (priv->ibss_beacon->len > left)
@@ -367,7 +367,8 @@
 
 	/* Set up packet rate and flags */
 	rate = iwl_rate_get_lowest_plcp(priv);
-	priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+	priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+					      priv->hw_params.valid_tx_ant);
 	rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
 	if ((rate >= IWL_FIRST_CCK_RATE) && (rate <= IWL_LAST_CCK_RATE))
 		rate_flags |= RATE_MCS_CCK_MSK;
@@ -474,18 +475,25 @@
 	/* Unmap tx_cmd */
 	if (num_tbs)
 		pci_unmap_single(dev,
-				pci_unmap_addr(&txq->meta[index], mapping),
-				pci_unmap_len(&txq->meta[index], len),
+				dma_unmap_addr(&txq->meta[index], mapping),
+				dma_unmap_len(&txq->meta[index], len),
 				PCI_DMA_BIDIRECTIONAL);
 
 	/* Unmap chunks, if any. */
-	for (i = 1; i < num_tbs; i++) {
+	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);
 
-		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;
+	/* free SKB */
+	if (txq->txb) {
+		struct sk_buff *skb;
+
+		skb = txq->txb[txq->q.read_ptr].skb;
+
+		/* can be called from irqs-disabled context */
+		if (skb) {
+			dev_kfree_skb_any(skb);
+			txq->txb[txq->q.read_ptr].skb = NULL;
 		}
 	}
 }
@@ -851,6 +859,24 @@
 	return 0;
 }
 
+static void iwl_bg_tx_flush(struct work_struct *work)
+{
+	struct iwl_priv *priv =
+		container_of(work, struct iwl_priv, tx_flush);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	/* do nothing if rf-kill is on */
+	if (!iwl_is_ready_rf(priv))
+		return;
+
+	if (priv->cfg->ops->lib->txfifo_flush) {
+		IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n");
+		iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
+	}
+}
+
 /**
  * iwl_setup_rx_handlers - Initialize Rx handler callbacks
  *
@@ -933,6 +959,8 @@
 		fill_rx = 1;
 
 	while (i != r) {
+		int len;
+
 		rxb = rxq->queue[i];
 
 		/* If an RXB doesn't have a Rx queue slot associated with it,
@@ -947,8 +975,9 @@
 			       PCI_DMA_FROMDEVICE);
 		pkt = rxb_addr(rxb);
 
-		trace_iwlwifi_dev_rx(priv, pkt,
-			le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
+		len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+		len += sizeof(u32); /* account for status word */
+		trace_iwlwifi_dev_rx(priv, pkt, len);
 
 		/* Reclaim a command buffer only if this packet is a response
 		 *   to a (driver-originated) command.
@@ -1450,13 +1479,13 @@
 
 	actual_ack_cnt_delta =
 		le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) -
-		le32_to_cpu(priv->statistics.tx.actual_ack_cnt);
+		le32_to_cpu(priv->_agn.statistics.tx.actual_ack_cnt);
 	expected_ack_cnt_delta =
 		le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) -
-		le32_to_cpu(priv->statistics.tx.expected_ack_cnt);
+		le32_to_cpu(priv->_agn.statistics.tx.expected_ack_cnt);
 	ba_timeout_delta =
 		le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) -
-		le32_to_cpu(priv->statistics.tx.agg.ba_timeout);
+		le32_to_cpu(priv->_agn.statistics.tx.agg.ba_timeout);
 	if ((priv->_agn.agg_tids_count > 0) &&
 	    (expected_ack_cnt_delta > 0) &&
 	    (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta)
@@ -1466,12 +1495,17 @@
 				" expected_ack_cnt = %d\n",
 				actual_ack_cnt_delta, expected_ack_cnt_delta);
 
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+		/*
+		 * This is ifdef'ed on DEBUGFS because otherwise the
+		 * statistics aren't available. If DEBUGFS is set but
+		 * DEBUG is not, these will just compile out.
+		 */
 		IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
-				priv->delta_statistics.tx.rx_detected_cnt);
+				priv->_agn.delta_statistics.tx.rx_detected_cnt);
 		IWL_DEBUG_RADIO(priv,
 				"ack_or_ba_timeout_collision delta = %d\n",
-				priv->delta_statistics.tx.
+				priv->_agn.delta_statistics.tx.
 				ack_or_ba_timeout_collision);
 #endif
 		IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",
@@ -1658,6 +1692,7 @@
 
 struct iwlagn_ucode_capabilities {
 	u32 max_probe_length;
+	u32 standard_phy_calibration_size;
 };
 
 static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
@@ -1694,6 +1729,9 @@
 	size_t inst_size, data_size, init_size, init_data_size, boot_size;
 
 	u32 build;
+
+	u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
+	u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
 };
 
 static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
@@ -1787,12 +1825,20 @@
 	const u8 *data;
 	int wanted_alternative = iwlagn_wanted_ucode_alternative, tmp;
 	u64 alternatives;
+	u32 tlv_len;
+	enum iwl_ucode_tlv_type tlv_type;
+	const u8 *tlv_data;
 
-	if (len < sizeof(*ucode))
+	if (len < sizeof(*ucode)) {
+		IWL_ERR(priv, "uCode has invalid length: %zd\n", len);
 		return -EINVAL;
+	}
 
-	if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC))
+	if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) {
+		IWL_ERR(priv, "invalid uCode magic: 0X%x\n",
+			le32_to_cpu(ucode->magic));
 		return -EINVAL;
+	}
 
 	/*
 	 * Check which alternatives are present, and "downgrade"
@@ -1818,10 +1864,7 @@
 	len -= sizeof(*ucode);
 
 	while (len >= sizeof(*tlv)) {
-		u32 tlv_len;
-		enum iwl_ucode_tlv_type tlv_type;
 		u16 tlv_alt;
-		const u8 *tlv_data;
 
 		len -= sizeof(*tlv);
 		tlv = (void *)data;
@@ -1831,8 +1874,11 @@
 		tlv_alt = le16_to_cpu(tlv->alternative);
 		tlv_data = tlv->data;
 
-		if (len < tlv_len)
+		if (len < tlv_len) {
+			IWL_ERR(priv, "invalid TLV len: %zd/%u\n",
+				len, tlv_len);
 			return -EINVAL;
+		}
 		len -= ALIGN(tlv_len, 4);
 		data += sizeof(*tlv) + ALIGN(tlv_len, 4);
 
@@ -1866,20 +1912,77 @@
 			pieces->boot_size = tlv_len;
 			break;
 		case IWL_UCODE_TLV_PROBE_MAX_LEN:
-			if (tlv_len != 4)
-				return -EINVAL;
+			if (tlv_len != sizeof(u32))
+				goto invalid_tlv_len;
 			capa->max_probe_length =
-				le32_to_cpup((__le32 *)tlv_data);
+					le32_to_cpup((__le32 *)tlv_data);
+			break;
+		case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
+			if (tlv_len != sizeof(u32))
+				goto invalid_tlv_len;
+			pieces->init_evtlog_ptr =
+					le32_to_cpup((__le32 *)tlv_data);
+			break;
+		case IWL_UCODE_TLV_INIT_EVTLOG_SIZE:
+			if (tlv_len != sizeof(u32))
+				goto invalid_tlv_len;
+			pieces->init_evtlog_size =
+					le32_to_cpup((__le32 *)tlv_data);
+			break;
+		case IWL_UCODE_TLV_INIT_ERRLOG_PTR:
+			if (tlv_len != sizeof(u32))
+				goto invalid_tlv_len;
+			pieces->init_errlog_ptr =
+					le32_to_cpup((__le32 *)tlv_data);
+			break;
+		case IWL_UCODE_TLV_RUNT_EVTLOG_PTR:
+			if (tlv_len != sizeof(u32))
+				goto invalid_tlv_len;
+			pieces->inst_evtlog_ptr =
+					le32_to_cpup((__le32 *)tlv_data);
+			break;
+		case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE:
+			if (tlv_len != sizeof(u32))
+				goto invalid_tlv_len;
+			pieces->inst_evtlog_size =
+					le32_to_cpup((__le32 *)tlv_data);
+			break;
+		case IWL_UCODE_TLV_RUNT_ERRLOG_PTR:
+			if (tlv_len != sizeof(u32))
+				goto invalid_tlv_len;
+			pieces->inst_errlog_ptr =
+					le32_to_cpup((__le32 *)tlv_data);
+			break;
+		case IWL_UCODE_TLV_ENHANCE_SENS_TBL:
+			if (tlv_len)
+				goto invalid_tlv_len;
+			priv->enhance_sensitivity_table = true;
+			break;
+		case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE:
+			if (tlv_len != sizeof(u32))
+				goto invalid_tlv_len;
+			capa->standard_phy_calibration_size =
+					le32_to_cpup((__le32 *)tlv_data);
 			break;
 		default:
+			IWL_WARN(priv, "unknown TLV: %d\n", tlv_type);
 			break;
 		}
 	}
 
-	if (len)
+	if (len) {
+		IWL_ERR(priv, "invalid TLV after parsing: %zd\n", len);
+		iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)data, len);
 		return -EINVAL;
+	}
 
 	return 0;
+
+ invalid_tlv_len:
+	IWL_ERR(priv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len);
+	iwl_print_hex_dump(priv, IWL_DL_FW, tlv_data, tlv_len);
+
+	return -EINVAL;
 }
 
 /**
@@ -1901,6 +2004,8 @@
 	u32 build;
 	struct iwlagn_ucode_capabilities ucode_capa = {
 		.max_probe_length = 200,
+		.standard_phy_calibration_size =
+			IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE,
 	};
 
 	memset(&pieces, 0, sizeof(pieces));
@@ -2063,6 +2168,26 @@
 			goto err_pci_alloc;
 	}
 
+	/* Now that we can no longer fail, copy information */
+
+	/*
+	 * The (size - 16) / 12 formula is based on the information recorded
+	 * for each event, which is of mode 1 (including timestamp) for all
+	 * new microcodes that include this information.
+	 */
+	priv->_agn.init_evtlog_ptr = pieces.init_evtlog_ptr;
+	if (pieces.init_evtlog_size)
+		priv->_agn.init_evtlog_size = (pieces.init_evtlog_size - 16)/12;
+	else
+		priv->_agn.init_evtlog_size = priv->cfg->max_event_log_size;
+	priv->_agn.init_errlog_ptr = pieces.init_errlog_ptr;
+	priv->_agn.inst_evtlog_ptr = pieces.inst_evtlog_ptr;
+	if (pieces.inst_evtlog_size)
+		priv->_agn.inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12;
+	else
+		priv->_agn.inst_evtlog_size = priv->cfg->max_event_log_size;
+	priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr;
+
 	/* Copy images into buffers for card's bus-master reads ... */
 
 	/* Runtime instructions (first block of data in file) */
@@ -2102,6 +2227,20 @@
 			pieces.boot_size);
 	memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size);
 
+	/*
+	 * figure out the offset of chain noise reset and gain commands
+	 * base on the size of standard phy calibration commands table size
+	 */
+	if (ucode_capa.standard_phy_calibration_size >
+	    IWL_MAX_PHY_CALIBRATE_TBL_SIZE)
+		ucode_capa.standard_phy_calibration_size =
+			IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE;
+
+	priv->_agn.phy_calib_chain_noise_reset_cmd =
+		ucode_capa.standard_phy_calibration_size;
+	priv->_agn.phy_calib_chain_noise_gain_cmd =
+		ucode_capa.standard_phy_calibration_size + 1;
+
 	/**************************************************
 	 * This is still part of probe() in a sense...
 	 *
@@ -2172,17 +2311,41 @@
 	"DEBUG_1",
 	"DEBUG_2",
 	"DEBUG_3",
-	"ADVANCED SYSASSERT"
 };
 
-static const char *desc_lookup(int i)
+static struct { char *name; u8 num; } advanced_lookup[] = {
+	{ "NMI_INTERRUPT_WDG", 0x34 },
+	{ "SYSASSERT", 0x35 },
+	{ "UCODE_VERSION_MISMATCH", 0x37 },
+	{ "BAD_COMMAND", 0x38 },
+	{ "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
+	{ "FATAL_ERROR", 0x3D },
+	{ "NMI_TRM_HW_ERR", 0x46 },
+	{ "NMI_INTERRUPT_TRM", 0x4C },
+	{ "NMI_INTERRUPT_BREAK_POINT", 0x54 },
+	{ "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
+	{ "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
+	{ "NMI_INTERRUPT_HOST", 0x66 },
+	{ "NMI_INTERRUPT_ACTION_PT", 0x7C },
+	{ "NMI_INTERRUPT_UNKNOWN", 0x84 },
+	{ "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
+	{ "ADVANCED_SYSASSERT", 0 },
+};
+
+static const char *desc_lookup(u32 num)
 {
-	int max = ARRAY_SIZE(desc_lookup_text) - 1;
+	int i;
+	int max = ARRAY_SIZE(desc_lookup_text);
 
-	if (i < 0 || i > max)
-		i = max;
+	if (num < max)
+		return desc_lookup_text[num];
 
-	return desc_lookup_text[i];
+	max = ARRAY_SIZE(advanced_lookup) - 1;
+	for (i = 0; i < max; i++) {
+		if (advanced_lookup[i].num == num)
+			break;;
+	}
+	return advanced_lookup[i].name;
 }
 
 #define ERROR_START_OFFSET  (1 * sizeof(u32))
@@ -2195,10 +2358,15 @@
 	u32 blink1, blink2, ilink1, ilink2;
 	u32 pc, hcmd;
 
-	if (priv->ucode_type == UCODE_INIT)
+	if (priv->ucode_type == UCODE_INIT) {
 		base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
-	else
+		if (!base)
+			base = priv->_agn.init_errlog_ptr;
+	} else {
 		base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+		if (!base)
+			base = priv->_agn.inst_errlog_ptr;
+	}
 
 	if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
 		IWL_ERR(priv,
@@ -2230,9 +2398,9 @@
 	trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
 				      blink1, blink2, ilink1, ilink2);
 
-	IWL_ERR(priv, "Desc                               Time       "
+	IWL_ERR(priv, "Desc                                  Time       "
 		"data1      data2      line\n");
-	IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
+	IWL_ERR(priv, "%-28s (0x%04X) %010u 0x%08X 0x%08X %u\n",
 		desc_lookup(desc), desc, time, data1, data2, line);
 	IWL_ERR(priv, "pc      blink1  blink2  ilink1  ilink2  hcmd\n");
 	IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X 0x%05X 0x%05X\n",
@@ -2258,10 +2426,16 @@
 
 	if (num_events == 0)
 		return pos;
-	if (priv->ucode_type == UCODE_INIT)
+
+	if (priv->ucode_type == UCODE_INIT) {
 		base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
-	else
+		if (!base)
+			base = priv->_agn.init_evtlog_ptr;
+	} else {
 		base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+		if (!base)
+			base = priv->_agn.inst_evtlog_ptr;
+	}
 
 	if (mode == 0)
 		event_size = 2 * sizeof(u32);
@@ -2363,13 +2537,21 @@
 	u32 num_wraps;  /* # times uCode wrapped to top of log */
 	u32 next_entry; /* index of next entry to be written by uCode */
 	u32 size;       /* # entries that we'll print */
+	u32 logsize;
 	int pos = 0;
 	size_t bufsz = 0;
 
-	if (priv->ucode_type == UCODE_INIT)
+	if (priv->ucode_type == UCODE_INIT) {
 		base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
-	else
+		logsize = priv->_agn.init_evtlog_size;
+		if (!base)
+			base = priv->_agn.init_evtlog_ptr;
+	} else {
 		base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+		logsize = priv->_agn.inst_evtlog_size;
+		if (!base)
+			base = priv->_agn.inst_evtlog_ptr;
+	}
 
 	if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
 		IWL_ERR(priv,
@@ -2384,16 +2566,16 @@
 	num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
 	next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
 
-	if (capacity > priv->cfg->max_event_log_size) {
+	if (capacity > logsize) {
 		IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
-			capacity, priv->cfg->max_event_log_size);
-		capacity = priv->cfg->max_event_log_size;
+			capacity, logsize);
+		capacity = logsize;
 	}
 
-	if (next_entry > priv->cfg->max_event_log_size) {
+	if (next_entry > logsize) {
 		IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
-			next_entry, priv->cfg->max_event_log_size);
-		next_entry = priv->cfg->max_event_log_size;
+			next_entry, logsize);
+		next_entry = logsize;
 	}
 
 	size = num_wraps ? capacity : next_entry;
@@ -2518,8 +2700,6 @@
 
 		if (priv->cfg->ops->hcmd->set_rxon_chain)
 			priv->cfg->ops->hcmd->set_rxon_chain(priv);
-
-		memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 	}
 
 	/* Configure Bluetooth device coexistence support */
@@ -2843,9 +3023,17 @@
 	}
 
 	if (priv->start_calib) {
-		iwl_chain_noise_calibration(priv, &priv->statistics);
-
-		iwl_sensitivity_calibration(priv, &priv->statistics);
+		if (priv->cfg->bt_statistics) {
+			iwl_chain_noise_calibration(priv,
+					(void *)&priv->_agn.statistics_bt);
+			iwl_sensitivity_calibration(priv,
+					(void *)&priv->_agn.statistics_bt);
+		} else {
+			iwl_chain_noise_calibration(priv,
+					(void *)&priv->_agn.statistics);
+			iwl_sensitivity_calibration(priv,
+					(void *)&priv->_agn.statistics);
+		}
 	}
 
 	mutex_unlock(&priv->mutex);
@@ -2934,20 +3122,16 @@
 	IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
 			vif->bss_conf.aid, vif->bss_conf.beacon_int);
 
-	if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+	if (vif->bss_conf.use_short_preamble)
 		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
 	else
 		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
 	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
-		if (vif->bss_conf.assoc_capability &
-					WLAN_CAPABILITY_SHORT_SLOT_TIME)
+		if (vif->bss_conf.use_short_slot)
 			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
 		else
 			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
-		if (vif->type == NL80211_IFTYPE_ADHOC)
-			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 	}
 
 	iwlcore_commit_rxon(priv);
@@ -3173,8 +3357,7 @@
 
 		priv->staging_rxon.assoc_id = 0;
 
-		if (vif->bss_conf.assoc_capability &
-						WLAN_CAPABILITY_SHORT_PREAMBLE)
+		if (vif->bss_conf.use_short_preamble)
 			priv->staging_rxon.flags |=
 				RXON_FLG_SHORT_PREAMBLE_MSK;
 		else
@@ -3182,17 +3365,12 @@
 				~RXON_FLG_SHORT_PREAMBLE_MSK;
 
 		if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
-			if (vif->bss_conf.assoc_capability &
-						WLAN_CAPABILITY_SHORT_SLOT_TIME)
+			if (vif->bss_conf.use_short_slot)
 				priv->staging_rxon.flags |=
 					RXON_FLG_SHORT_SLOT_MSK;
 			else
 				priv->staging_rxon.flags &=
 					~RXON_FLG_SHORT_SLOT_MSK;
-
-			if (vif->type == NL80211_IFTYPE_ADHOC)
-				priv->staging_rxon.flags &=
-					~RXON_FLG_SHORT_SLOT_MSK;
 		}
 		/* restore RXON assoc */
 		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
@@ -3238,17 +3416,9 @@
 		return -EOPNOTSUPP;
 	}
 
-	if (sta) {
-		sta_id = iwl_sta_id(sta);
-
-		if (sta_id == IWL_INVALID_STATION) {
-			IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
-					   sta->addr);
-			return -EINVAL;
-		}
-	} else {
-		sta_id = priv->hw_params.bcast_sta_id;
-	}
+	sta_id = iwl_sta_id_or_broadcast(priv, sta);
+	if (sta_id == IWL_INVALID_STATION)
+		return -EINVAL;
 
 	mutex_lock(&priv->mutex);
 	iwl_scan_cancel_timeout(priv, 100);
@@ -3294,13 +3464,32 @@
 	return ret;
 }
 
+/*
+ * switch to RTS/CTS for TX
+ */
+static void iwl_enable_rts_cts(struct iwl_priv *priv)
+{
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
+	if (!test_bit(STATUS_SCANNING, &priv->status)) {
+		IWL_DEBUG_INFO(priv, "use RTS/CTS protection\n");
+		iwlcore_commit_rxon(priv);
+	} else {
+		/* scanning, defer the request until scan completed */
+		IWL_DEBUG_INFO(priv, "defer setting RTS/CTS protection\n");
+	}
+}
+
 static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
 				struct ieee80211_vif *vif,
 				enum ieee80211_ampdu_mlme_action action,
 				struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
 	struct iwl_priv *priv = hw->priv;
-	int ret;
+	int ret = -EINVAL;
 
 	IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
 		     sta->addr, tid);
@@ -3308,17 +3497,19 @@
 	if (!(priv->cfg->sku & IWL_SKU_N))
 		return -EACCES;
 
+	mutex_lock(&priv->mutex);
+
 	switch (action) {
 	case IEEE80211_AMPDU_RX_START:
 		IWL_DEBUG_HT(priv, "start Rx\n");
-		return iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
+		ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
+		break;
 	case IEEE80211_AMPDU_RX_STOP:
 		IWL_DEBUG_HT(priv, "stop Rx\n");
 		ret = iwl_sta_rx_agg_stop(priv, sta, tid);
 		if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-			return 0;
-		else
-			return ret;
+			ret = 0;
+		break;
 	case IEEE80211_AMPDU_TX_START:
 		IWL_DEBUG_HT(priv, "start Tx\n");
 		ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
@@ -3327,7 +3518,7 @@
 			IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
 				     priv->_agn.agg_tids_count);
 		}
-		return ret;
+		break;
 	case IEEE80211_AMPDU_TX_STOP:
 		IWL_DEBUG_HT(priv, "stop Tx\n");
 		ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
@@ -3337,18 +3528,22 @@
 				     priv->_agn.agg_tids_count);
 		}
 		if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-			return 0;
-		else
-			return ret;
+			ret = 0;
+		break;
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
-		/* do nothing */
-		return -EOPNOTSUPP;
-	default:
-		IWL_DEBUG_HT(priv, "unknown\n");
-		return -EINVAL;
+		if (priv->cfg->use_rts_for_ht) {
+			/*
+			 * switch to RTS/CTS if it is the prefer protection
+			 * method for HT traffic
+			 */
+			iwl_enable_rts_cts(priv);
+		}
+		ret = 0;
 		break;
 	}
-	return 0;
+	mutex_unlock(&priv->mutex);
+
+	return ret;
 }
 
 static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
@@ -3423,6 +3618,136 @@
 	return 0;
 }
 
+static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
+				   struct ieee80211_channel_switch *ch_switch)
+{
+	struct iwl_priv *priv = hw->priv;
+	const struct iwl_channel_info *ch_info;
+	struct ieee80211_conf *conf = &hw->conf;
+	struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+	u16 ch;
+	unsigned long flags = 0;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+
+	if (iwl_is_rfkill(priv))
+		goto out_exit;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+	    test_bit(STATUS_SCANNING, &priv->status))
+		goto out_exit;
+
+	if (!iwl_is_associated(priv))
+		goto out_exit;
+
+	/* channel switch in progress */
+	if (priv->switch_rxon.switch_in_progress == true)
+		goto out_exit;
+
+	mutex_lock(&priv->mutex);
+	if (priv->cfg->ops->lib->set_channel_switch) {
+
+		ch = ieee80211_frequency_to_channel(
+			ch_switch->channel->center_freq);
+		if (le16_to_cpu(priv->active_rxon.channel) != ch) {
+			ch_info = iwl_get_channel_info(priv,
+						       conf->channel->band,
+						       ch);
+			if (!is_channel_valid(ch_info)) {
+				IWL_DEBUG_MAC80211(priv, "invalid channel\n");
+				goto out;
+			}
+			spin_lock_irqsave(&priv->lock, flags);
+
+			priv->current_ht_config.smps = conf->smps_mode;
+
+			/* Configure HT40 channels */
+			ht_conf->is_ht = conf_is_ht(conf);
+			if (ht_conf->is_ht) {
+				if (conf_is_ht40_minus(conf)) {
+					ht_conf->extension_chan_offset =
+						IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+					ht_conf->is_40mhz = true;
+				} else if (conf_is_ht40_plus(conf)) {
+					ht_conf->extension_chan_offset =
+						IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+					ht_conf->is_40mhz = true;
+				} else {
+					ht_conf->extension_chan_offset =
+						IEEE80211_HT_PARAM_CHA_SEC_NONE;
+					ht_conf->is_40mhz = false;
+				}
+			} else
+				ht_conf->is_40mhz = false;
+
+			/* if we are switching from ht to 2.4 clear flags
+			 * from any ht related info since 2.4 does not
+			 * support ht */
+			if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
+				priv->staging_rxon.flags = 0;
+
+			iwl_set_rxon_channel(priv, conf->channel);
+			iwl_set_rxon_ht(priv, ht_conf);
+			iwl_set_flags_for_band(priv, conf->channel->band,
+					       priv->vif);
+			spin_unlock_irqrestore(&priv->lock, flags);
+
+			iwl_set_rate(priv);
+			/*
+			 * at this point, staging_rxon has the
+			 * configuration for channel switch
+			 */
+			if (priv->cfg->ops->lib->set_channel_switch(priv,
+								    ch_switch))
+				priv->switch_rxon.switch_in_progress = false;
+		}
+	}
+out:
+	mutex_unlock(&priv->mutex);
+out_exit:
+	if (!priv->switch_rxon.switch_in_progress)
+		ieee80211_chswitch_done(priv->vif, false);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static void iwl_mac_flush(struct ieee80211_hw *hw, bool drop)
+{
+	struct iwl_priv *priv = hw->priv;
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+
+	/* do not support "flush" */
+	if (!priv->cfg->ops->lib->txfifo_flush)
+		goto done;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
+		goto done;
+	}
+	if (iwl_is_rfkill(priv)) {
+		IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
+		goto done;
+	}
+
+	/*
+	 * mac80211 will not push any more frames for transmit
+	 * until the flush is completed
+	 */
+	if (drop) {
+		IWL_DEBUG_MAC80211(priv, "send flush command\n");
+		if (priv->cfg->ops->lib->txfifo_flush(priv, IWL_DROP_ALL)) {
+			IWL_ERR(priv, "flush request fail\n");
+			goto done;
+		}
+	}
+	IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
+	iwlagn_wait_tx_queue_empty(priv);
+done:
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
 /*****************************************************************************
  *
  * driver setup and teardown
@@ -3439,6 +3764,7 @@
 	INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
 	INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
 	INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
+	INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
 	INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
 	INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
 
@@ -3479,6 +3805,7 @@
 	cancel_delayed_work(&priv->scan_check);
 	cancel_work_sync(&priv->start_internal_scan);
 	cancel_delayed_work(&priv->alive_start);
+	cancel_work_sync(&priv->run_time_calib_work);
 	cancel_work_sync(&priv->beacon_update);
 	del_timer_sync(&priv->statistics_periodic);
 	del_timer_sync(&priv->ucode_trace);
@@ -3594,6 +3921,8 @@
 	.sta_notify = iwl_mac_sta_notify,
 	.sta_add = iwlagn_mac_sta_add,
 	.sta_remove = iwl_mac_sta_remove,
+	.channel_switch = iwl_mac_channel_switch,
+	.flush = iwl_mac_flush,
 };
 
 static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -3603,7 +3932,7 @@
 	struct ieee80211_hw *hw;
 	struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
 	unsigned long flags;
-	u16 pci_cmd;
+	u16 pci_cmd, num_mac;
 
 	/************************
 	 * 1. Allocating HW data
@@ -3633,9 +3962,6 @@
 	priv->pci_dev = pdev;
 	priv->inta_mask = CSR_INI_SET_MASK;
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	atomic_set(&priv->restrict_refcnt, 0);
-#endif
 	if (iwl_alloc_traffic_mem(priv))
 		IWL_ERR(priv, "Not enough memory to generate traffic log\n");
 
@@ -3724,9 +4050,17 @@
 		goto out_free_eeprom;
 
 	/* extract MAC Address */
-	iwl_eeprom_get_mac(priv, priv->mac_addr);
-	IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->mac_addr);
-	SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+	iwl_eeprom_get_mac(priv, priv->addresses[0].addr);
+	IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->addresses[0].addr);
+	priv->hw->wiphy->addresses = priv->addresses;
+	priv->hw->wiphy->n_addresses = 1;
+	num_mac = iwl_eeprom_query16(priv, EEPROM_NUM_MAC_ADDRESS);
+	if (num_mac > 1) {
+		memcpy(priv->addresses[1].addr, priv->addresses[0].addr,
+		       ETH_ALEN);
+		priv->addresses[1].addr[5]++;
+		priv->hw->wiphy->n_addresses++;
+	}
 
 	/************************
 	 * 5. Setup HW constants
@@ -3993,6 +4327,47 @@
 	{IWL_PCI_DEVICE(0x0082, 0x1201, iwl6000g2a_2agn_cfg)},
 	{IWL_PCI_DEVICE(0x0085, 0x1211, iwl6000g2a_2agn_cfg)},
 	{IWL_PCI_DEVICE(0x0082, 0x1221, iwl6000g2a_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1206, iwl6000g2a_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0085, 0x1216, iwl6000g2a_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1226, iwl6000g2a_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1207, iwl6000g2a_2bg_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1301, iwl6000g2a_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1306, iwl6000g2a_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1307, iwl6000g2a_2bg_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1321, iwl6000g2a_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0082, 0x1326, iwl6000g2a_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0085, 0x1311, iwl6000g2a_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0085, 0x1316, iwl6000g2a_2abg_cfg)},
+
+/* 6x00 Series Gen2b */
+	{IWL_PCI_DEVICE(0x008F, 0x5105, iwl6000g2b_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0090, 0x5115, iwl6000g2b_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x008F, 0x5125, iwl6000g2b_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x008F, 0x5107, iwl6000g2b_bg_cfg)},
+	{IWL_PCI_DEVICE(0x008F, 0x5201, iwl6000g2b_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x008F, 0x5221, iwl6000g2b_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x008F, 0x5206, iwl6000g2b_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x008F, 0x5226, iwl6000g2b_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x008F, 0x5207, iwl6000g2b_2bg_cfg)},
+	{IWL_PCI_DEVICE(0x008A, 0x5301, iwl6000g2b_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x008A, 0x5305, iwl6000g2b_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x008A, 0x5307, iwl6000g2b_bg_cfg)},
+	{IWL_PCI_DEVICE(0x008A, 0x5321, iwl6000g2b_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x008A, 0x5325, iwl6000g2b_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x008B, 0x5311, iwl6000g2b_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x008B, 0x5315, iwl6000g2b_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0090, 0x5215, iwl6000g2b_2bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5201, iwl6000g2b_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5205, iwl6000g2b_2bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5206, iwl6000g2b_2abg_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5207, iwl6000g2b_2bg_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5221, iwl6000g2b_2agn_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5225, iwl6000g2b_2bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0091, 0x5226, iwl6000g2b_2abg_cfg)},
 
 /* 6x50 WiFi/WiMax Series */
 	{IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
@@ -4002,6 +4377,14 @@
 	{IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
 	{IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
 
+/* 6x50 WiFi/WiMax Series Gen2 */
+	{IWL_PCI_DEVICE(0x0885, 0x1305, iwl6050g2_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0885, 0x1306, iwl6050g2_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0885, 0x1325, iwl6050g2_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0885, 0x1326, iwl6050g2_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0886, 0x1315, iwl6050g2_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0886, 0x1316, iwl6050g2_bgn_cfg)},
+
 /* 1000 Series WiFi */
 	{IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)},
 	{IWL_PCI_DEVICE(0x0083, 0x1305, iwl1000_bgn_cfg)},
@@ -4036,19 +4419,18 @@
 {
 
 	int ret;
-	printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
-	printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+	pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
+	pr_info(DRV_COPYRIGHT "\n");
 
 	ret = iwlagn_rate_control_register();
 	if (ret) {
-		printk(KERN_ERR DRV_NAME
-		       "Unable to register rate control algorithm: %d\n", ret);
+		pr_err("Unable to register rate control algorithm: %d\n", ret);
 		return ret;
 	}
 
 	ret = pci_register_driver(&iwl_driver);
 	if (ret) {
-		printk(KERN_ERR DRV_NAME "Unable to initialize PCI module\n");
+		pr_err("Unable to initialize PCI module\n");
 		goto error_register;
 	}
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 2d74805..cc6464d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -65,6 +65,34 @@
 
 #include "iwl-dev.h"
 
+/* configuration for the _agn devices */
+extern struct iwl_cfg iwl4965_agn_cfg;
+extern struct iwl_cfg iwl5300_agn_cfg;
+extern struct iwl_cfg iwl5100_agn_cfg;
+extern struct iwl_cfg iwl5350_agn_cfg;
+extern struct iwl_cfg iwl5100_bgn_cfg;
+extern struct iwl_cfg iwl5100_abg_cfg;
+extern struct iwl_cfg iwl5150_agn_cfg;
+extern struct iwl_cfg iwl5150_abg_cfg;
+extern struct iwl_cfg iwl6000g2a_2agn_cfg;
+extern struct iwl_cfg iwl6000g2a_2abg_cfg;
+extern struct iwl_cfg iwl6000g2a_2bg_cfg;
+extern struct iwl_cfg iwl6000g2b_bgn_cfg;
+extern struct iwl_cfg iwl6000g2b_bg_cfg;
+extern struct iwl_cfg iwl6000g2b_2agn_cfg;
+extern struct iwl_cfg iwl6000g2b_2abg_cfg;
+extern struct iwl_cfg iwl6000g2b_2bgn_cfg;
+extern struct iwl_cfg iwl6000g2b_2bg_cfg;
+extern struct iwl_cfg iwl6000i_2agn_cfg;
+extern struct iwl_cfg iwl6000i_2abg_cfg;
+extern struct iwl_cfg iwl6000i_2bg_cfg;
+extern struct iwl_cfg iwl6000_3agn_cfg;
+extern struct iwl_cfg iwl6050_2agn_cfg;
+extern struct iwl_cfg iwl6050_2abg_cfg;
+extern struct iwl_cfg iwl6050g2_bgn_cfg;
+extern struct iwl_cfg iwl1000_bgn_cfg;
+extern struct iwl_cfg iwl1000_bg_cfg;
+
 extern struct iwl_mod_params iwlagn_mod_params;
 extern struct iwl_hcmd_ops iwlagn_hcmd;
 extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils;
@@ -93,6 +121,8 @@
 int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
 			   u16 ssn_idx, u8 tx_fifo);
 void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask);
+void iwl_free_tfds_in_queue(struct iwl_priv *priv,
+			    int sta_id, int tid, int freed);
 
 /* uCode */
 int iwlagn_load_ucode(struct iwl_priv *priv);
@@ -102,6 +132,7 @@
 			   struct iwl_rx_mem_buffer *rxb);
 void iwlagn_init_alive_start(struct iwl_priv *priv);
 int iwlagn_alive_notify(struct iwl_priv *priv);
+int iwl_verify_ucode(struct iwl_priv *priv);
 
 /* lib */
 void iwl_check_abort_status(struct iwl_priv *priv,
@@ -117,6 +148,9 @@
 void iwlagn_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 int iwlagn_hw_nic_init(struct iwl_priv *priv);
+int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv);
+int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
+void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
 
 /* rx */
 void iwlagn_rx_queue_restock(struct iwl_priv *priv);
@@ -171,6 +205,16 @@
 	       (status == TX_STATUS_DIRECT_DONE);
 }
 
+/* rx */
+void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
+				struct iwl_rx_mem_buffer *rxb);
+bool iwl_good_plcp_health(struct iwl_priv *priv,
+			  struct iwl_rx_packet *pkt);
+void iwl_rx_statistics(struct iwl_priv *priv,
+		       struct iwl_rx_mem_buffer *rxb);
+void iwl_reply_statistics(struct iwl_priv *priv,
+			  struct iwl_rx_mem_buffer *rxb);
+
 /* scan */
 void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
 
@@ -178,4 +222,8 @@
 int iwlagn_manage_ibss_station(struct iwl_priv *priv,
 			       struct ieee80211_vif *vif, bool add);
 
+/* hcmd */
+int iwlagn_send_rxon_assoc(struct iwl_priv *priv);
+int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant);
+
 #endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h
index 2b7b1df..ba9523f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.h
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.h
@@ -66,10 +66,8 @@
 #include "iwl-core.h"
 #include "iwl-commands.h"
 
-void iwl_chain_noise_calibration(struct iwl_priv *priv,
-				struct iwl_notif_statistics *stat_resp);
-void iwl_sensitivity_calibration(struct iwl_priv *priv,
-				struct iwl_notif_statistics *resp);
+void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp);
+void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp);
 
 void iwl_init_sensitivity(struct iwl_priv *priv);
 void iwl_reset_run_time_calib(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 9aab020..60725a5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -95,8 +95,9 @@
 
 	/* Multi-Station support */
 	REPLY_ADD_STA = 0x18,
-	REPLY_REMOVE_STA = 0x19,	/* not used */
+	REPLY_REMOVE_STA = 0x19,
 	REPLY_REMOVE_ALL_STA = 0x1a,	/* not used */
+	REPLY_TXFIFO_FLUSH = 0x1e,
 
 	/* Security */
 	REPLY_WEPKEY = 0x20,
@@ -227,7 +228,7 @@
 
 	/* command or response/notification data follows immediately */
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 
 /**
@@ -247,7 +248,7 @@
 struct iwl3945_tx_power {
 	u8 tx_gain;		/* gain for analog radio */
 	u8 dsp_atten;		/* gain for DSP */
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct iwl3945_power_per_rate
@@ -258,7 +259,7 @@
 	u8 rate;		/* plcp */
 	struct iwl3945_tx_power tpc;
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * iwlagn rate_n_flags bit fields
@@ -389,7 +390,7 @@
  */
 struct tx_power_dual_stream {
 	__le32 dw;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct iwl4965_tx_power_db
@@ -398,7 +399,7 @@
  */
 struct iwl4965_tx_power_db {
 	struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * Command REPLY_TX_POWER_DBM_CMD = 0x98
@@ -412,7 +413,7 @@
 	u8 flags;
 	s8 srv_chan_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * Command TX_ANT_CONFIGURATION_CMD = 0x98
@@ -422,7 +423,7 @@
  */
 struct iwl_tx_ant_config_cmd {
 	__le32 valid;
-} __attribute__ ((packed));
+} __packed;
 
 /******************************************************************************
  * (0a)
@@ -478,7 +479,7 @@
 	__le32 therm_r4[2];	/* signed */
 	__le32 tx_atten[5][2];	/* signed MIMO gain comp, 5 freq groups,
 				 * 2 Tx chains */
-} __attribute__ ((packed));
+} __packed;
 
 
 /**
@@ -570,7 +571,7 @@
 	__le32 error_event_table_ptr;	/* SRAM address for error log */
 	__le32 timestamp;
 	__le32 is_valid;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * REPLY_ERROR = 0x2 (response only, not a command)
@@ -582,7 +583,7 @@
 	__le16 bad_cmd_seq_num;
 	__le32 error_info;
 	__le64 timestamp;
-} __attribute__ ((packed));
+} __packed;
 
 /******************************************************************************
  * (1)
@@ -718,7 +719,7 @@
 	__le32 filter_flags;
 	__le16 channel;
 	__le16 reserved5;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl4965_rxon_cmd {
 	u8 node_addr[6];
@@ -738,7 +739,7 @@
 	__le16 channel;
 	u8 ofdm_ht_single_stream_basic_rates;
 	u8 ofdm_ht_dual_stream_basic_rates;
-} __attribute__ ((packed));
+} __packed;
 
 /* 5000 HW just extend this command */
 struct iwl_rxon_cmd {
@@ -763,7 +764,7 @@
 	u8 reserved5;
 	__le16 acquisition_data;
 	__le16 reserved6;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
@@ -774,7 +775,7 @@
 	u8 ofdm_basic_rates;
 	u8 cck_basic_rates;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl4965_rxon_assoc_cmd {
 	__le32 flags;
@@ -785,7 +786,7 @@
 	u8 ofdm_ht_dual_stream_basic_rates;
 	__le16 rx_chain_select_flags;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl5000_rxon_assoc_cmd {
 	__le32 flags;
@@ -800,7 +801,7 @@
 	__le16 rx_chain_select_flags;
 	__le16 acquisition_data;
 	__le32 reserved3;
-} __attribute__ ((packed));
+} __packed;
 
 #define IWL_CONN_MAX_LISTEN_INTERVAL	10
 #define IWL_MAX_UCODE_BEACON_INTERVAL	4 /* 4096 */
@@ -816,7 +817,7 @@
 	__le32 beacon_init_val;
 	__le16 listen_interval;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
@@ -829,7 +830,7 @@
 	__le32 rxon_filter_flags;
 	__le32 switch_time;
 	struct iwl3945_power_per_rate power[IWL_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl4965_channel_switch_cmd {
 	u8 band;
@@ -839,7 +840,7 @@
 	__le32 rxon_filter_flags;
 	__le32 switch_time;
 	struct iwl4965_tx_power_db tx_power;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct iwl5000_channel_switch_cmd
@@ -860,7 +861,7 @@
 	__le32 rxon_filter_flags;
 	__le32 switch_time;
 	__le32 reserved[2][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct iwl6000_channel_switch_cmd
@@ -881,7 +882,7 @@
 	__le32 rxon_filter_flags;
 	__le32 switch_time;
 	__le32 reserved[3][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
@@ -890,7 +891,7 @@
 	__le16 band;
 	__le16 channel;
 	__le32 status;		/* 0 - OK, 1 - fail */
-} __attribute__ ((packed));
+} __packed;
 
 /******************************************************************************
  * (2)
@@ -920,7 +921,7 @@
 	u8 aifsn;
 	u8 reserved1;
 	__le16 edca_txop;
-} __attribute__ ((packed));
+} __packed;
 
 /* QoS flags defines */
 #define QOS_PARAM_FLG_UPDATE_EDCA_MSK	cpu_to_le32(0x01)
@@ -939,7 +940,7 @@
 struct iwl_qosparam_cmd {
 	__le32 qos_flags;
 	struct iwl_ac_qos ac[AC_NUM];
-} __attribute__ ((packed));
+} __packed;
 
 /******************************************************************************
  * (3)
@@ -952,20 +953,19 @@
 
 /* Special, dedicated locations within device's station table */
 #define	IWL_AP_ID		0
-#define IWL_MULTICAST_ID	1
 #define	IWL_STA_ID		2
 #define	IWL3945_BROADCAST_ID	24
 #define IWL3945_STATION_COUNT	25
 #define IWL4965_BROADCAST_ID	31
 #define	IWL4965_STATION_COUNT	32
-#define IWL5000_BROADCAST_ID	15
-#define	IWL5000_STATION_COUNT	16
+#define IWLAGN_BROADCAST_ID	15
+#define	IWLAGN_STATION_COUNT	16
 
 #define	IWL_STATION_COUNT	32 	/* MAX(3945,4965)*/
 #define	IWL_INVALID_STATION 	255
 
-#define STA_FLG_TX_RATE_MSK		cpu_to_le32(1 << 2);
-#define STA_FLG_PWR_SAVE_MSK		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)
 #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)
@@ -1015,7 +1015,7 @@
 	u8 key_offset;
 	u8 reserved2;
 	u8 key[16];		/* 16-byte unicast decryption key */
-} __attribute__ ((packed));
+} __packed;
 
 /* 5000 */
 struct iwl_keyinfo {
@@ -1029,7 +1029,7 @@
 	__le64 tx_secur_seq_cnt;
 	__le64 hw_tkip_mic_rx_key;
 	__le64 hw_tkip_mic_tx_key;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct sta_id_modify
@@ -1049,7 +1049,7 @@
 	u8 sta_id;
 	u8 modify_mask;
 	__le16 reserved2;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * REPLY_ADD_STA = 0x18 (command)
@@ -1103,7 +1103,7 @@
 	/* Starting Sequence Number for added block-ack support.
 	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
 	__le16 add_immediate_ba_ssn;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl4965_addsta_cmd {
 	u8 mode;		/* 1: modify existing, 0: add new station */
@@ -1140,7 +1140,7 @@
 	__le16 sleep_tx_count;
 
 	__le16 reserved2;
-} __attribute__ ((packed));
+} __packed;
 
 /* 5000 */
 struct iwl_addsta_cmd {
@@ -1178,7 +1178,7 @@
 	__le16 sleep_tx_count;
 
 	__le16 reserved2;
-} __attribute__ ((packed));
+} __packed;
 
 
 #define ADD_STA_SUCCESS_MSK		0x1
@@ -1190,7 +1190,7 @@
  */
 struct iwl_add_sta_resp {
 	u8 status;	/* ADD_STA_* */
-} __attribute__ ((packed));
+} __packed;
 
 #define REM_STA_SUCCESS_MSK              0x1
 /*
@@ -1198,7 +1198,7 @@
  */
 struct iwl_rem_sta_resp {
 	u8 status;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  *  REPLY_REM_STA = 0x19 (command)
@@ -1208,7 +1208,44 @@
 	u8 reserved[3];
 	u8 addr[ETH_ALEN]; /* MAC addr of the first station */
 	u8 reserved2[2];
-} __attribute__ ((packed));
+} __packed;
+
+#define IWL_TX_FIFO_BK_MSK		cpu_to_le32(BIT(0))
+#define IWL_TX_FIFO_BE_MSK		cpu_to_le32(BIT(1))
+#define IWL_TX_FIFO_VI_MSK		cpu_to_le32(BIT(2))
+#define IWL_TX_FIFO_VO_MSK		cpu_to_le32(BIT(3))
+#define IWL_AGG_TX_QUEUE_MSK		cpu_to_le32(0xffc00)
+
+#define IWL_DROP_SINGLE		0
+#define IWL_DROP_SELECTED	1
+#define IWL_DROP_ALL		2
+
+/*
+ * REPLY_TXFIFO_FLUSH = 0x1e(command and response)
+ *
+ * When using full FIFO flush this command checks the scheduler HW block WR/RD
+ * pointers to check if all the frames were transferred by DMA into the
+ * relevant TX FIFO queue. Only when the DMA is finished and the queue is
+ * empty the command can finish.
+ * This command is used to flush the TXFIFO from transmit commands, it may
+ * operate on single or multiple queues, the command queue can't be flushed by
+ * this command. The command response is returned when all the queue flush
+ * operations are done. Each TX command flushed return response with the FLUSH
+ * status set in the TX response status. When FIFO flush operation is used,
+ * the flush operation ends when both the scheduler DMA done and TXFIFO empty
+ * are set.
+ *
+ * @fifo_control: bit mask for which queues to flush
+ * @flush_control: flush controls
+ *	0: Dump single MSDU
+ *	1: Dump multiple MSDU according to PS, INVALID STA, TTL, TID disable.
+ *	2: Dump all FIFO
+ */
+struct iwl_txfifo_flush_cmd {
+	__le32 fifo_control;
+	__le16 flush_control;
+	__le16 reserved;
+} __packed;
 
 /*
  * REPLY_WEP_KEY = 0x20
@@ -1220,7 +1257,7 @@
 	u8 key_size;
 	u8 reserved2[3];
 	u8 key[16];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl_wep_cmd {
 	u8 num_keys;
@@ -1228,7 +1265,7 @@
 	u8 flags;
 	u8 reserved;
 	struct iwl_wep_key key[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define WEP_KEY_WEP_TYPE 1
 #define WEP_KEYS_MAX 4
@@ -1282,7 +1319,7 @@
 	__le16 sig_avg;
 	__le16 noise_diff;
 	u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl3945_rx_frame_hdr {
 	__le16 channel;
@@ -1291,13 +1328,13 @@
 	u8 rate;
 	__le16 len;
 	u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl3945_rx_frame_end {
 	__le32 status;
 	__le64 timestamp;
 	__le32 beacon_timestamp;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * REPLY_3945_RX = 0x1b (response only, not a command)
@@ -1311,7 +1348,7 @@
 	struct iwl3945_rx_frame_stats stats;
 	struct iwl3945_rx_frame_hdr hdr;
 	struct iwl3945_rx_frame_end end;
-} __attribute__ ((packed));
+} __packed;
 
 #define IWL39_RX_FRAME_SIZE	(4 + sizeof(struct iwl3945_rx_frame))
 
@@ -1327,7 +1364,7 @@
 	__le16 agc_info;	/* agc code 0:6, agc dB 7:13, reserved 14:15 */
 	u8 rssi_info[6];	/* we use even entries, 0/2/4 for A/B/C rssi */
 	u8 pad[0];
-} __attribute__ ((packed));
+} __packed;
 
 
 #define IWL50_RX_RES_PHY_CNT 8
@@ -1345,7 +1382,7 @@
 
 struct iwl5000_non_cfg_phy {
 	__le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT];  /* up to 8 phy entries */
-} __attribute__ ((packed));
+} __packed;
 
 
 /*
@@ -1365,12 +1402,12 @@
 	__le32 rate_n_flags;	/* RATE_MCS_* */
 	__le16 byte_count;	/* frame's byte-count */
 	__le16 reserved3;
-} __attribute__ ((packed));
+} __packed;
 
-struct iwl4965_rx_mpdu_res_start {
+struct iwl_rx_mpdu_res_start {
 	__le16 byte_count;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 
 /******************************************************************************
@@ -1400,18 +1437,27 @@
 
 /* REPLY_TX Tx flags field */
 
-/* 1: Use RTS/CTS protocol or CTS-to-self if spec allows 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 cpu_to_le32(1 << 0)
+ * RXON_FLG_SELF_CTS_EN status.
+ * unused in 3945/4965, used in 5000 series and after
+ */
+#define TX_CMD_FLG_PROT_REQUIRE_MSK cpu_to_le32(1 << 0)
 
-/* 1: Use Request-To-Send protocol before this frame.
- * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
+/*
+ * 1: Use Request-To-Send protocol before this frame.
+ * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK.
+ * used in 3945/4965, unused in 5000 series and after
+ */
 #define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1)
 
-/* 1: Transmit Clear-To-Send to self before this frame.
+/*
+ * 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. */
+ * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK.
+ * used in 3945/4965, unused in 5000 series and after
+ */
 #define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2)
 
 /* 1: Expect ACK from receiving station
@@ -1431,8 +1477,11 @@
  * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
 #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. */
+/*
+ * 1: Frame requires full Tx-Op protection.
+ * Set this if either RTS or CTS Tx Flag gets set.
+ * used in 3945/4965, unused in 5000 series and after
+ */
 #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.
@@ -1557,7 +1606,7 @@
 	 */
 	u8 payload[0];
 	struct ieee80211_hdr hdr[0];
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * REPLY_TX = 0x1c (response)
@@ -1569,7 +1618,7 @@
 	u8 rate;
 	__le32 wireless_media_time;
 	__le32 status;		/* TX status */
-} __attribute__ ((packed));
+} __packed;
 
 
 /*
@@ -1581,7 +1630,7 @@
 	u8 try_cnt;		/* Tx attempts */
 	u8 bt_kill_cnt;		/* Tx attempts blocked by Bluetooth device */
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl_tx_cmd {
 	/*
@@ -1660,7 +1709,7 @@
 	 */
 	u8 payload[0];
 	struct ieee80211_hdr hdr[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* TX command response is sent after *3945* transmission attempts.
  *
@@ -1826,7 +1875,7 @@
 struct agg_tx_status {
 	__le16 status;
 	__le16 sequence;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl4965_tx_resp {
 	u8 frame_count;		/* 1 no aggregation, >1 aggregation */
@@ -1863,7 +1912,7 @@
 		__le32 status;
 		struct agg_tx_status agg_status[0]; /* for each agg frame */
 	} u;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * definitions for initial rate index field
@@ -1927,7 +1976,7 @@
 	 */
 	struct agg_tx_status status;	/* TX status (in aggregation -
 					 * status of 1st frame) */
-} __attribute__ ((packed));
+} __packed;
 /*
  * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
  *
@@ -1945,7 +1994,7 @@
 	__le64 bitmap;
 	__le16 scd_flow;
 	__le16 scd_ssn;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
@@ -1958,14 +2007,14 @@
 	u8 reserved;
 	__le16 channel;
 	struct iwl3945_power_per_rate power[IWL_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl4965_txpowertable_cmd {
 	u8 band;		/* 0: 5 GHz, 1: 2.4 GHz */
 	u8 reserved;
 	__le16 channel;
 	struct iwl4965_tx_power_db tx_power;
-} __attribute__ ((packed));
+} __packed;
 
 
 /**
@@ -1987,13 +2036,13 @@
 	__le16 rate_n_flags;
 	u8 try_cnt;
 	u8 next_rate_index;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl3945_rate_scaling_cmd {
 	u8 table_id;
 	u8 reserved[3];
 	struct iwl3945_rate_scaling_info table[IWL_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
 
 
 /*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
@@ -2040,7 +2089,7 @@
 	 * TX FIFOs above 3 use same value (typically 0) as TX FIFO 3.
 	 */
 	u8 start_rate_index[LINK_QUAL_AC_NUM];
-} __attribute__ ((packed));
+} __packed;
 
 #define LINK_QUAL_AGG_TIME_LIMIT_DEF	(4000) /* 4 milliseconds */
 #define LINK_QUAL_AGG_TIME_LIMIT_MAX	(65535)
@@ -2081,7 +2130,7 @@
 	u8 agg_frame_cnt_limit;
 
 	__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
@@ -2287,7 +2336,7 @@
 		__le32 rate_n_flags;	/* RATE_MCS_*, IWL_RATE_* */
 	} rs_table[LINK_QUAL_MAX_RETRY_NUM];
 	__le32 reserved2;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * BT configuration enable flags:
@@ -2328,7 +2377,7 @@
 	u8 reserved;
 	__le32 kill_ack_mask;
 	__le32 kill_cts_mask;
-} __attribute__ ((packed));
+} __packed;
 
 /******************************************************************************
  * (6)
@@ -2353,7 +2402,7 @@
 	u8 channel;		/* channel to measure */
 	u8 type;		/* see enum iwl_measure_type */
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
@@ -2372,7 +2421,7 @@
 	__le16 channel_count;	/* minimum 1, maximum 10 */
 	__le16 reserved3;
 	struct iwl_measure_channel channels[10];
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
@@ -2383,7 +2432,7 @@
 	__le16 status;		/* 0 - command will be handled
 				 * 1 - cannot handle (conflicts with another
 				 *     measurement) */
-} __attribute__ ((packed));
+} __packed;
 
 enum iwl_measurement_state {
 	IWL_MEASUREMENT_START = 0,
@@ -2406,13 +2455,13 @@
 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));
+} __packed;
 
 /* clear channel availability counters */
 struct iwl_measurement_cca_counters {
 	__le32 ofdm;
 	__le32 cck;
-} __attribute__ ((packed));
+} __packed;
 
 enum iwl_measure_type {
 	IWL_MEASURE_BASIC = (1 << 0),
@@ -2448,7 +2497,7 @@
 	struct iwl_measurement_histogram histogram;
 	__le32 stop_time;	/* lower 32-bits of TSF */
 	__le32 status;		/* see iwl_measurement_status */
-} __attribute__ ((packed));
+} __packed;
 
 /******************************************************************************
  * (7)
@@ -2504,7 +2553,7 @@
 	__le32 rx_data_timeout;
 	__le32 tx_data_timeout;
 	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl_powertable_cmd {
 	__le16 flags;
@@ -2514,7 +2563,7 @@
 	__le32 tx_data_timeout;
 	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
 	__le32 keep_alive_beacons;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
@@ -2527,7 +2576,7 @@
 	__le32 sleep_time;
 	__le32 tsf_low;
 	__le32 bcon_timer;
-} __attribute__ ((packed));
+} __packed;
 
 /* Sleep states.  3945 and 4965 identical. */
 enum {
@@ -2552,14 +2601,14 @@
 #define CARD_STATE_CMD_HALT    0x02	/* Power down permanently */
 struct iwl_card_state_cmd {
 	__le32 status;		/* CARD_STATE_CMD_* request new power state */
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
  */
 struct iwl_card_state_notif {
 	__le32 flags;
-} __attribute__ ((packed));
+} __packed;
 
 #define HW_CARD_DISABLED   0x01
 #define SW_CARD_DISABLED   0x02
@@ -2570,14 +2619,14 @@
 	__le32   reserved;
 	__le32   critical_temperature_M;
 	__le32   critical_temperature_R;
-}  __attribute__ ((packed));
+}  __packed;
 
 /* 1000, and 6x00 */
 struct iwl_ct_kill_throttling_config {
 	__le32   critical_temperature_exit;
 	__le32   reserved;
 	__le32   critical_temperature_enter;
-}  __attribute__ ((packed));
+}  __packed;
 
 /******************************************************************************
  * (8)
@@ -2622,7 +2671,7 @@
 	struct iwl3945_tx_power tpc;
 	__le16 active_dwell;	/* in 1024-uSec TU (time units), typ 5-50 */
 	__le16 passive_dwell;	/* in 1024-uSec TU (time units), typ 20-500 */
-} __attribute__ ((packed));
+} __packed;
 
 /* set number of direct probes u8 type */
 #define IWL39_SCAN_PROBE_MASK(n) ((BIT(n) | (BIT(n) - BIT(1))))
@@ -2641,7 +2690,7 @@
 	u8 dsp_atten;		/* gain for DSP */
 	__le16 active_dwell;	/* in 1024-uSec TU (time units), typ 5-50 */
 	__le16 passive_dwell;	/* in 1024-uSec TU (time units), typ 20-500 */
-} __attribute__ ((packed));
+} __packed;
 
 /* set number of direct probes __le32 type */
 #define IWL_SCAN_PROBE_MASK(n) 	cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
@@ -2658,7 +2707,7 @@
 	u8 id;
 	u8 len;
 	u8 ssid[32];
-} __attribute__ ((packed));
+} __packed;
 
 #define PROBE_OPTION_MAX_3945		4
 #define PROBE_OPTION_MAX		20
@@ -2764,7 +2813,7 @@
 	 * before requesting another scan.
 	 */
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl_scan_cmd {
 	__le16 len;
@@ -2808,7 +2857,7 @@
 	 * before requesting another scan.
 	 */
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Can abort will notify by complete notification with abort status. */
 #define CAN_ABORT_STATUS	cpu_to_le32(0x1)
@@ -2820,7 +2869,7 @@
  */
 struct iwl_scanreq_notification {
 	__le32 status;		/* 1: okay, 2: cannot fulfill request */
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
@@ -2833,7 +2882,7 @@
 	u8 band;
 	u8 reserved[2];
 	__le32 status;
-} __attribute__ ((packed));
+} __packed;
 
 #define  SCAN_OWNER_STATUS 0x1;
 #define  MEASURE_OWNER_STATUS 0x2;
@@ -2849,7 +2898,7 @@
 	__le32 tsf_low;
 	__le32 tsf_high;
 	__le32 statistics[NUMBER_OF_STATISTICS];
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
@@ -2861,7 +2910,7 @@
 	u8 last_channel;
 	__le32 tsf_low;
 	__le32 tsf_high;
-} __attribute__ ((packed));
+} __packed;
 
 
 /******************************************************************************
@@ -2879,14 +2928,14 @@
 	__le32 low_tsf;
 	__le32 high_tsf;
 	__le32 ibss_mgr_status;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl4965_beacon_notif {
 	struct iwl4965_tx_resp beacon_notify_hdr;
 	__le32 low_tsf;
 	__le32 high_tsf;
 	__le32 ibss_mgr_status;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
@@ -2898,7 +2947,7 @@
 	u8 tim_size;
 	u8 reserved1;
 	struct ieee80211_hdr frame[0];	/* beacon frame */
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl_tx_beacon_cmd {
 	struct iwl_tx_cmd tx;
@@ -2906,7 +2955,7 @@
 	u8 tim_size;
 	u8 reserved1;
 	struct ieee80211_hdr frame[0];	/* beacon frame */
-} __attribute__ ((packed));
+} __packed;
 
 /******************************************************************************
  * (10)
@@ -2932,7 +2981,7 @@
 		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
 		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
 	} failed;
-} __attribute__ ((packed));
+} __packed;
 
 /* statistics command response */
 
@@ -2952,7 +3001,7 @@
 	__le32 rxe_frame_limit_overrun;
 	__le32 sent_ack_cnt;
 	__le32 sent_cts_cnt;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl39_statistics_rx_non_phy {
 	__le32 bogus_cts;	/* CTS received when not expecting CTS */
@@ -2963,13 +3012,13 @@
 				 * filtering process */
 	__le32 non_channel_beacons;	/* beacons with our bss id but not on
 					 * our serving channel */
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl39_statistics_rx {
 	struct iwl39_statistics_rx_phy ofdm;
 	struct iwl39_statistics_rx_phy cck;
 	struct iwl39_statistics_rx_non_phy general;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl39_statistics_tx {
 	__le32 preamble_cnt;
@@ -2981,20 +3030,21 @@
 	__le32 ack_timeout;
 	__le32 expected_ack_cnt;
 	__le32 actual_ack_cnt;
-} __attribute__ ((packed));
+} __packed;
 
 struct statistics_dbg {
 	__le32 burst_check;
 	__le32 burst_count;
-	__le32 reserved[4];
-} __attribute__ ((packed));
+	__le32 wait_for_silence_timeout_cnt;
+	__le32 reserved[3];
+} __packed;
 
 struct iwl39_statistics_div {
 	__le32 tx_on_a;
 	__le32 tx_on_b;
 	__le32 exec_time;
 	__le32 probe_time;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl39_statistics_general {
 	__le32 temperature;
@@ -3004,7 +3054,7 @@
 	__le32 slots_idle;
 	__le32 ttl_timestamp;
 	struct iwl39_statistics_div div;
-} __attribute__ ((packed));
+} __packed;
 
 struct statistics_rx_phy {
 	__le32 ina_cnt;
@@ -3027,7 +3077,7 @@
 	__le32 mh_format_err;
 	__le32 re_acq_main_rssi_sum;
 	__le32 reserved3;
-} __attribute__ ((packed));
+} __packed;
 
 struct statistics_rx_ht_phy {
 	__le32 plcp_err;
@@ -3040,7 +3090,7 @@
 	__le32 agg_mpdu_cnt;
 	__le32 agg_cnt;
 	__le32 unsupport_mcs;
-} __attribute__ ((packed));
+} __packed;
 
 #define INTERFERENCE_DATA_AVAILABLE      cpu_to_le32(1)
 
@@ -3075,14 +3125,28 @@
 	__le32 beacon_energy_a;
 	__le32 beacon_energy_b;
 	__le32 beacon_energy_c;
-} __attribute__ ((packed));
+} __packed;
+
+struct statistics_rx_non_phy_bt {
+	struct statistics_rx_non_phy common;
+	/* additional stats for bt */
+	__le32 num_bt_kills;
+	__le32 reserved[2];
+} __packed;
 
 struct statistics_rx {
 	struct statistics_rx_phy ofdm;
 	struct statistics_rx_phy cck;
 	struct statistics_rx_non_phy general;
 	struct statistics_rx_ht_phy ofdm_ht;
-} __attribute__ ((packed));
+} __packed;
+
+struct statistics_rx_bt {
+	struct statistics_rx_phy ofdm;
+	struct statistics_rx_phy cck;
+	struct statistics_rx_non_phy_bt general;
+	struct statistics_rx_ht_phy ofdm_ht;
+} __packed;
 
 /**
  * struct statistics_tx_power - current tx power
@@ -3096,7 +3160,7 @@
 	u8 ant_b;
 	u8 ant_c;
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct statistics_tx_non_phy_agg {
 	__le32 ba_timeout;
@@ -3109,7 +3173,7 @@
 	__le32 underrun;
 	__le32 bt_prio_kill;
 	__le32 rx_ba_rsp_cnt;
-} __attribute__ ((packed));
+} __packed;
 
 struct statistics_tx {
 	__le32 preamble_cnt;
@@ -3134,7 +3198,7 @@
 	 */
 	struct statistics_tx_power tx_power;
 	__le32 reserved1;
-} __attribute__ ((packed));
+} __packed;
 
 
 struct statistics_div {
@@ -3144,9 +3208,9 @@
 	__le32 probe_time;
 	__le32 reserved1;
 	__le32 reserved2;
-} __attribute__ ((packed));
+} __packed;
 
-struct statistics_general {
+struct statistics_general_common {
 	__le32 temperature;   /* radio temperature */
 	__le32 temperature_m; /* for 5000 and up, this is radio voltage */
 	struct statistics_dbg dbg;
@@ -3162,9 +3226,33 @@
 	 *  in order to get out of bad PHY status
 	 */
 	__le32 num_of_sos_states;
+} __packed;
+
+struct statistics_bt_activity {
+	/* Tx statistics */
+	__le32 hi_priority_tx_req_cnt;
+	__le32 hi_priority_tx_denied_cnt;
+	__le32 lo_priority_tx_req_cnt;
+	__le32 lo_priority_tx_denied_cnt;
+	/* Rx statistics */
+	__le32 hi_priority_rx_req_cnt;
+	__le32 hi_priority_rx_denied_cnt;
+	__le32 lo_priority_rx_req_cnt;
+	__le32 lo_priority_rx_denied_cnt;
+} __packed;
+
+struct statistics_general {
+	struct statistics_general_common common;
 	__le32 reserved2;
 	__le32 reserved3;
-} __attribute__ ((packed));
+} __packed;
+
+struct statistics_general_bt {
+	struct statistics_general_common common;
+	struct statistics_bt_activity activity;
+	__le32 reserved2;
+	__le32 reserved3;
+} __packed;
 
 #define UCODE_STATISTICS_CLEAR_MSK		(0x1 << 0)
 #define UCODE_STATISTICS_FREQUENCY_MSK		(0x1 << 1)
@@ -3189,7 +3277,7 @@
 #define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */
 struct iwl_statistics_cmd {
 	__le32 configuration_flags;	/* IWL_STATS_CONF_* */
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
@@ -3214,15 +3302,21 @@
 	struct iwl39_statistics_rx rx;
 	struct iwl39_statistics_tx tx;
 	struct iwl39_statistics_general general;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl_notif_statistics {
 	__le32 flag;
 	struct statistics_rx rx;
 	struct statistics_tx tx;
 	struct statistics_general general;
-} __attribute__ ((packed));
+} __packed;
 
+struct iwl_bt_notif_statistics {
+	__le32 flag;
+	struct statistics_rx_bt rx;
+	struct statistics_tx tx;
+	struct statistics_general_bt general;
+} __packed;
 
 /*
  * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
@@ -3253,7 +3347,7 @@
 	__le32 total_missed_becons;
 	__le32 num_expected_beacons;
 	__le32 num_recvd_beacons;
-} __attribute__ ((packed));
+} __packed;
 
 
 /******************************************************************************
@@ -3441,6 +3535,41 @@
 #define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX          (9)
 #define HD_OFDM_ENERGY_TH_IN_INDEX                  (10)
 
+/*
+ * Additional table entries in enhance SENSITIVITY_CMD
+ */
+#define HD_INA_NON_SQUARE_DET_OFDM_INDEX		(11)
+#define HD_INA_NON_SQUARE_DET_CCK_INDEX			(12)
+#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX		(13)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX		(14)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX	(15)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX		(16)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX		(17)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX		(18)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX	(19)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_INDEX		(20)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX		(21)
+#define HD_RESERVED					(22)
+
+/* number of entries for enhanced tbl */
+#define ENHANCE_HD_TABLE_SIZE  (23)
+
+/* number of additional entries for enhanced tbl */
+#define ENHANCE_HD_TABLE_ENTRIES  (ENHANCE_HD_TABLE_SIZE - HD_TABLE_SIZE)
+
+#define HD_INA_NON_SQUARE_DET_OFDM_DATA			cpu_to_le16(0)
+#define HD_INA_NON_SQUARE_DET_CCK_DATA			cpu_to_le16(0)
+#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA		cpu_to_le16(0)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA		cpu_to_le16(668)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA	cpu_to_le16(4)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA		cpu_to_le16(486)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA		cpu_to_le16(37)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA		cpu_to_le16(853)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA	cpu_to_le16(4)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA		cpu_to_le16(476)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA		cpu_to_le16(99)
+
+
 /* Control field in struct iwl_sensitivity_cmd */
 #define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE	cpu_to_le16(0)
 #define SENSITIVITY_CMD_CONTROL_WORK_TABLE	cpu_to_le16(1)
@@ -3455,7 +3584,15 @@
 struct iwl_sensitivity_cmd {
 	__le16 control;			/* always use "1" */
 	__le16 table[HD_TABLE_SIZE];	/* use HD_* as index */
-} __attribute__ ((packed));
+} __packed;
+
+/*
+ *
+ */
+struct iwl_enhance_sensitivity_cmd {
+	__le16 control;			/* always use "1" */
+	__le16 enhance_table[ENHANCE_HD_TABLE_SIZE];	/* use HD_* as index */
+} __packed;
 
 
 /**
@@ -3523,10 +3660,10 @@
 	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,
+	IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE	= 18,
 };
 
+#define IWL_MAX_PHY_CALIBRATE_TBL_SIZE		(253)
 
 #define IWL_CALIB_INIT_CFG_ALL	cpu_to_le32(0xffffffff)
 
@@ -3536,31 +3673,31 @@
 	__le32 send_res;
 	__le32 apply_res;
 	__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl_calib_cfg_status_s {
 	struct iwl_calib_cfg_elmnt_s once;
 	struct iwl_calib_cfg_elmnt_s perd;
 	__le32 flags;
-} __attribute__ ((packed));
+} __packed;
 
 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));
+} __packed;
 
 struct iwl_calib_hdr {
 	u8 op_code;
 	u8 first_group;
 	u8 groups_num;
 	u8 data_valid;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl_calib_cmd {
 	struct iwl_calib_hdr hdr;
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* IWL_PHY_CALIBRATE_DIFF_GAIN_CMD (7) */
 struct iwl_calib_diff_gain_cmd {
@@ -3569,14 +3706,14 @@
 	s8 diff_gain_b;
 	s8 diff_gain_c;
 	u8 reserved1;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl_calib_xtal_freq_cmd {
 	struct iwl_calib_hdr hdr;
 	u8 cap_pin1;
 	u8 cap_pin2;
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 /* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
 struct iwl_calib_chain_noise_reset_cmd {
@@ -3590,7 +3727,7 @@
 	u8 delta_gain_1;
 	u8 delta_gain_2;
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 /******************************************************************************
  * (12)
@@ -3613,7 +3750,7 @@
 	u8 on;			/* # intervals on while blinking;
 				 * "0", regardless of "off", turns LED off */
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * station priority table entries
@@ -3749,7 +3886,7 @@
 	u8 win_medium_prio;
 	u8 reserved;
 	u8 flags;
-} __attribute__ ((packed));
+} __packed;
 
 /* COEX flag masks */
 
@@ -3766,7 +3903,7 @@
 	u8 flags;
 	u8 reserved[3];
 	struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS];
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * Coexistence MEDIUM NOTIFICATION
@@ -3795,7 +3932,7 @@
 struct iwl_coex_medium_notification {
 	__le32 status;
 	__le32 events;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * Coexistence EVENT  Command
@@ -3810,11 +3947,11 @@
 	u8 flags;
 	u8 event;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwl_coex_event_resp {
 	__le32 status;
-} __attribute__ ((packed));
+} __packed;
 
 
 /******************************************************************************
@@ -3851,6 +3988,7 @@
 		struct iwl_sleep_notification sleep_notif;
 		struct iwl_spectrum_resp spectrum;
 		struct iwl_notif_statistics stats;
+		struct iwl_bt_notif_statistics stats_bt;
 		struct iwl_compressed_ba_resp compressed_ba;
 		struct iwl_missed_beacon_notif missed_beacon;
 		struct iwl_coex_medium_notification coex_medium_notif;
@@ -3858,7 +3996,7 @@
 		__le32 status;
 		u8 raw[0];
 	} u;
-} __attribute__ ((packed));
+} __packed;
 
 int iwl_agn_check_rxon_cmd(struct iwl_priv *priv);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 5bbc529..8024d44 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -141,13 +141,14 @@
 }
 EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx);
 
-u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
 {
 	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))
+		if (valid & BIT(ind))
 			return ind;
 	}
 	return ant;
@@ -169,7 +170,7 @@
 	struct ieee80211_hw *hw =
 		ieee80211_alloc_hw(sizeof(struct iwl_priv), hw_ops);
 	if (hw == NULL) {
-		printk(KERN_ERR "%s: Can not allocate network device\n",
+		pr_err("%s: Can not allocate network device\n",
 		       cfg->name);
 		goto out;
 	}
@@ -457,7 +458,7 @@
 		if (!sta_ht_inf->ht_supported)
 			return 0;
 	}
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
 	if (priv->disable_ht40)
 		return 0;
 #endif
@@ -506,11 +507,11 @@
 	}
 
 	beacon_int = iwl_adjust_beacon_interval(beacon_int,
-				priv->hw_params.max_beacon_itrvl * 1024);
+				priv->hw_params.max_beacon_itrvl * TIME_UNIT);
 	priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
 
 	tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
-	interval_tm = beacon_int * 1024;
+	interval_tm = beacon_int * TIME_UNIT;
 	rem = do_div(tsf, interval_tm);
 	priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
 
@@ -932,9 +933,9 @@
 }
 EXPORT_SYMBOL(iwl_set_rxon_channel);
 
-static void iwl_set_flags_for_band(struct iwl_priv *priv,
-				   enum ieee80211_band band,
-				   struct ieee80211_vif *vif)
+void iwl_set_flags_for_band(struct iwl_priv *priv,
+			    enum ieee80211_band band,
+			    struct ieee80211_vif *vif)
 {
 	if (band == IEEE80211_BAND_5GHZ) {
 		priv->staging_rxon.flags &=
@@ -943,19 +944,17 @@
 		priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
 	} else {
 		/* Copied from iwl_post_associate() */
-		if (vif && vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+		if (vif && vif->bss_conf.use_short_slot)
 			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
 		else
 			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
-		if (vif && vif->type == NL80211_IFTYPE_ADHOC)
-			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
 		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
 		priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
 		priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
 	}
 }
+EXPORT_SYMBOL(iwl_set_flags_for_band);
 
 /*
  * initialize rxon structure with default values from eeprom
@@ -1021,15 +1020,17 @@
 	/* clear both MIX and PURE40 mode flag */
 	priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
 					RXON_FLG_CHANNEL_MODE_PURE_40);
-	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
-	memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
+
+	if (vif)
+		memcpy(priv->staging_rxon.node_addr, vif->addr, ETH_ALEN);
+
 	priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
 	priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
 	priv->staging_rxon.ofdm_ht_triple_stream_basic_rates = 0xff;
 }
 EXPORT_SYMBOL(iwl_connection_init_rx_config);
 
-static void iwl_set_rate(struct iwl_priv *priv)
+void iwl_set_rate(struct iwl_priv *priv)
 {
 	const struct ieee80211_supported_band *hw = NULL;
 	struct ieee80211_rate *rate;
@@ -1057,6 +1058,21 @@
 	priv->staging_rxon.ofdm_basic_rates =
 	   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
 }
+EXPORT_SYMBOL(iwl_set_rate);
+
+void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
+{
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (priv->switch_rxon.switch_in_progress) {
+		ieee80211_chswitch_done(priv->vif, is_success);
+		mutex_lock(&priv->mutex);
+		priv->switch_rxon.switch_in_progress = false;
+		mutex_unlock(&priv->mutex);
+	}
+}
+EXPORT_SYMBOL(iwl_chswitch_done);
 
 void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 {
@@ -1071,11 +1087,12 @@
 			priv->staging_rxon.channel = csa->channel;
 			IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
 			      le16_to_cpu(csa->channel));
-		} else
+			iwl_chswitch_done(priv, true);
+		} else {
 			IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
 			      le16_to_cpu(csa->channel));
-
-		priv->switch_rxon.switch_in_progress = false;
+			iwl_chswitch_done(priv, false);
+		}
 	}
 }
 EXPORT_SYMBOL(iwl_rx_csa);
@@ -1507,130 +1524,6 @@
 }
 EXPORT_SYMBOL(iwl_send_statistics_request);
 
-/**
- * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
- *   using sample data 100 bytes apart.  If these sample points are good,
- *   it's a pretty good bet that everything between them is good, too.
- */
-static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
-{
-	u32 val;
-	int ret = 0;
-	u32 errcnt = 0;
-	u32 i;
-
-	IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
-
-	for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
-		/* read data comes through single port, auto-incr addr */
-		/* NOTE: Use the debugless read so we don't flood kernel log
-		 * if IWL_DL_IO is set */
-		iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
-			i + IWL49_RTC_INST_LOWER_BOUND);
-		val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
-		if (val != le32_to_cpu(*image)) {
-			ret = -EIO;
-			errcnt++;
-			if (errcnt >= 3)
-				break;
-		}
-	}
-
-	return ret;
-}
-
-/**
- * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host,
- *     looking at all data.
- */
-static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image,
-				 u32 len)
-{
-	u32 val;
-	u32 save_len = len;
-	int ret = 0;
-	u32 errcnt;
-
-	IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
-
-	iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
-			   IWL49_RTC_INST_LOWER_BOUND);
-
-	errcnt = 0;
-	for (; len > 0; len -= sizeof(u32), image++) {
-		/* read data comes through single port, auto-incr addr */
-		/* NOTE: Use the debugless read so we don't flood kernel log
-		 * if IWL_DL_IO is set */
-		val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
-		if (val != le32_to_cpu(*image)) {
-			IWL_ERR(priv, "uCode INST section is invalid at "
-				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
-				  save_len - len, val, le32_to_cpu(*image));
-			ret = -EIO;
-			errcnt++;
-			if (errcnt >= 20)
-				break;
-		}
-	}
-
-	if (!errcnt)
-		IWL_DEBUG_INFO(priv,
-		    "ucode image in INSTRUCTION memory is good\n");
-
-	return ret;
-}
-
-/**
- * iwl_verify_ucode - determine which instruction image is in SRAM,
- *    and verify its contents
- */
-int iwl_verify_ucode(struct iwl_priv *priv)
-{
-	__le32 *image;
-	u32 len;
-	int ret;
-
-	/* Try bootstrap */
-	image = (__le32 *)priv->ucode_boot.v_addr;
-	len = priv->ucode_boot.len;
-	ret = iwlcore_verify_inst_sparse(priv, image, len);
-	if (!ret) {
-		IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n");
-		return 0;
-	}
-
-	/* Try initialize */
-	image = (__le32 *)priv->ucode_init.v_addr;
-	len = priv->ucode_init.len;
-	ret = iwlcore_verify_inst_sparse(priv, image, len);
-	if (!ret) {
-		IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n");
-		return 0;
-	}
-
-	/* Try runtime/protocol */
-	image = (__le32 *)priv->ucode_code.v_addr;
-	len = priv->ucode_code.len;
-	ret = iwlcore_verify_inst_sparse(priv, image, len);
-	if (!ret) {
-		IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n");
-		return 0;
-	}
-
-	IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
-
-	/* Since nothing seems to match, show first several data entries in
-	 * instruction SRAM, so maybe visual inspection will give a clue.
-	 * Selection of bootstrap image (vs. other images) is arbitrary. */
-	image = (__le32 *)priv->ucode_boot.v_addr;
-	len = priv->ucode_boot.len;
-	ret = iwl_verify_inst_full(priv, image, len);
-
-	return ret;
-}
-EXPORT_SYMBOL(iwl_verify_ucode);
-
-
 void iwl_rf_kill_ct_config(struct iwl_priv *priv)
 {
 	struct iwl_ct_kill_config cmd;
@@ -1855,6 +1748,37 @@
 	iwlcore_commit_rxon(priv);
 }
 
+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;
+
+	IWL_DEBUG_MAC80211(priv, "enter\n");
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+		return -EIO;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	priv->ibss_beacon = skb;
+
+	timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
+	priv->timestamp = le64_to_cpu(timestamp);
+
+	IWL_DEBUG_MAC80211(priv, "leave\n");
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	priv->cfg->ops->lib->post_associate(priv, priv->vif);
+
+	return 0;
+}
+
 void iwl_bss_info_changed(struct ieee80211_hw *hw,
 			  struct ieee80211_vif *vif,
 			  struct ieee80211_bss_conf *bss_conf,
@@ -1870,6 +1794,15 @@
 
 	mutex_lock(&priv->mutex);
 
+	if (changes & BSS_CHANGED_QOS) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&priv->lock, flags);
+		priv->qos_data.qos_active = bss_conf->qos;
+		iwl_update_qos(priv);
+		spin_unlock_irqrestore(&priv->lock, flags);
+	}
+
 	if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) {
 		dev_kfree_skb(priv->ibss_beacon);
 		priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
@@ -2012,38 +1945,6 @@
 }
 EXPORT_SYMBOL(iwl_bss_info_changed);
 
-int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-	struct iwl_priv *priv = hw->priv;
-	unsigned long flags;
-	__le64 timestamp;
-
-	IWL_DEBUG_MAC80211(priv, "enter\n");
-
-	if (!iwl_is_ready_rf(priv)) {
-		IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
-		return -EIO;
-	}
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	if (priv->ibss_beacon)
-		dev_kfree_skb(priv->ibss_beacon);
-
-	priv->ibss_beacon = skb;
-
-	timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
-	priv->timestamp = le64_to_cpu(timestamp);
-
-	IWL_DEBUG_MAC80211(priv, "leave\n");
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	priv->cfg->ops->lib->post_associate(priv, priv->vif);
-
-	return 0;
-}
-EXPORT_SYMBOL(iwl_mac_beacon_update);
-
 static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
 	iwl_connection_init_rx_config(priv, vif);
@@ -2051,8 +1952,6 @@
 	if (priv->cfg->ops->hcmd->set_rxon_chain)
 		priv->cfg->ops->hcmd->set_rxon_chain(priv);
 
-	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
-
 	return iwlcore_commit_rxon(priv);
 }
 
@@ -2061,7 +1960,8 @@
 	struct iwl_priv *priv = hw->priv;
 	int err = 0;
 
-	IWL_DEBUG_MAC80211(priv, "enter: type %d\n", vif->type);
+	IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
+			   vif->type, vif->addr);
 
 	mutex_lock(&priv->mutex);
 
@@ -2079,9 +1979,6 @@
 	priv->vif = vif;
 	priv->iw_mode = vif->type;
 
-	IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr);
-	memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
-
 	err = iwl_set_mode(priv, vif);
 	if (err)
 		goto out_err;
@@ -2115,6 +2012,11 @@
 	}
 	if (priv->vif == vif) {
 		priv->vif = NULL;
+		if (priv->scan_vif == vif) {
+			ieee80211_scan_completed(priv->hw, true);
+			priv->scan_vif = NULL;
+			priv->scan_request = NULL;
+		}
 		memset(priv->bssid, 0, ETH_ALEN);
 	}
 	mutex_unlock(&priv->mutex);
@@ -2215,22 +2117,10 @@
 
 		iwl_set_flags_for_band(priv, conf->channel->band, priv->vif);
 		spin_unlock_irqrestore(&priv->lock, flags);
-		if (iwl_is_associated(priv) &&
-		    (le16_to_cpu(priv->active_rxon.channel) != ch) &&
-		    priv->cfg->ops->lib->set_channel_switch) {
-			iwl_set_rate(priv);
-			/*
-			 * at this point, staging_rxon has the
-			 * configuration for channel switch
-			 */
-			ret = priv->cfg->ops->lib->set_channel_switch(priv,
-				ch);
-			if (!ret) {
-				iwl_print_rx_config_cmd(priv);
-				goto out;
-			}
-			priv->switch_rxon.switch_in_progress = false;
-		}
+
+		if (priv->cfg->ops->lib->update_bcast_station)
+			ret = priv->cfg->ops->lib->update_bcast_station(priv);
+
  set_ch_out:
 		/* The list of supported rates and rate mask can be different
 		 * for each band; since the band may have changed, reset
@@ -2252,15 +2142,6 @@
 		iwl_set_tx_power(priv, conf->power_level, false);
 	}
 
-	if (changed & IEEE80211_CONF_CHANGE_QOS) {
-		bool qos_active = !!(conf->flags & IEEE80211_CONF_QOS);
-
-		spin_lock_irqsave(&priv->lock, flags);
-		priv->qos_data.qos_active = qos_active;
-		iwl_update_qos(priv);
-		spin_unlock_irqrestore(&priv->lock, flags);
-	}
-
 	if (!iwl_is_ready(priv)) {
 		IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
 		goto out;
@@ -2588,7 +2469,7 @@
 EXPORT_SYMBOL(iwl_update_stats);
 #endif
 
-const static char *get_csr_string(int cmd)
+static const char *get_csr_string(int cmd)
 {
 	switch (cmd) {
 		IWL_CMD(CSR_HW_IF_CONFIG_REG);
@@ -2659,7 +2540,7 @@
 }
 EXPORT_SYMBOL(iwl_dump_csr);
 
-const static char *get_fh_string(int cmd)
+static const char *get_fh_string(int cmd)
 {
 	switch (cmd) {
 		IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
@@ -2745,7 +2626,7 @@
 }
 
 
-int iwl_force_reset(struct iwl_priv *priv, int mode)
+int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
 {
 	struct iwl_force_reset *force_reset;
 
@@ -2758,12 +2639,14 @@
 	}
 	force_reset = &priv->force_reset[mode];
 	force_reset->reset_request_count++;
-	if (force_reset->last_force_reset_jiffies &&
-	    time_after(force_reset->last_force_reset_jiffies +
-	    force_reset->reset_duration, jiffies)) {
-		IWL_DEBUG_INFO(priv, "force reset rejected\n");
-		force_reset->reset_reject_count++;
-		return -EAGAIN;
+	if (!external) {
+		if (force_reset->last_force_reset_jiffies &&
+		    time_after(force_reset->last_force_reset_jiffies +
+		    force_reset->reset_duration, jiffies)) {
+			IWL_DEBUG_INFO(priv, "force reset rejected\n");
+			force_reset->reset_reject_count++;
+			return -EAGAIN;
+		}
 	}
 	force_reset->reset_success_count++;
 	force_reset->last_force_reset_jiffies = jiffies;
@@ -2773,6 +2656,19 @@
 		iwl_force_rf_reset(priv);
 		break;
 	case IWL_FW_RESET:
+		/*
+		 * if the request is from external(ex: debugfs),
+		 * then always perform the request in regardless the module
+		 * parameter setting
+		 * if the request is from internal (uCode error or driver
+		 * detect failure), then fw_restart module parameter
+		 * need to be check before performing firmware reload
+		 */
+		if (!external && !priv->cfg->mod_params->restart_fw) {
+			IWL_DEBUG_INFO(priv, "Cancel firmware reload based on "
+				       "module parameter setting\n");
+			break;
+		}
 		IWL_ERR(priv, "On demand firmware reload\n");
 		/* Set the FW error flag -- cleared on iwl_down */
 		set_bit(STATUS_FW_ERROR, &priv->status);
@@ -2831,7 +2727,7 @@
 					"queue %d stuck %d time. Fw reload.\n",
 					q->id, q->repeat_same_read_ptr);
 				q->repeat_same_read_ptr = 0;
-				iwl_force_reset(priv, IWL_FW_RESET);
+				iwl_force_reset(priv, IWL_FW_RESET, false);
 			} else {
 				q->repeat_same_read_ptr++;
 				IWL_DEBUG_RADIO(priv,
@@ -2881,6 +2777,61 @@
 }
 EXPORT_SYMBOL(iwl_bg_monitor_recover);
 
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in extended:internal format
+ * the extended part is the beacon counts
+ * the internal part is the time in usec within one beacon interval
+ */
+u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval)
+{
+	u32 quot;
+	u32 rem;
+	u32 interval = beacon_interval * TIME_UNIT;
+
+	if (!interval || !usec)
+		return 0;
+
+	quot = (usec / interval) &
+		(iwl_beacon_time_mask_high(priv,
+		priv->hw_params.beacon_time_tsf_bits) >>
+		priv->hw_params.beacon_time_tsf_bits);
+	rem = (usec % interval) & iwl_beacon_time_mask_low(priv,
+				   priv->hw_params.beacon_time_tsf_bits);
+
+	return (quot << priv->hw_params.beacon_time_tsf_bits) + rem;
+}
+EXPORT_SYMBOL(iwl_usecs_to_beacons);
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
+			   u32 addon, u32 beacon_interval)
+{
+	u32 base_low = base & iwl_beacon_time_mask_low(priv,
+					priv->hw_params.beacon_time_tsf_bits);
+	u32 addon_low = addon & iwl_beacon_time_mask_low(priv,
+					priv->hw_params.beacon_time_tsf_bits);
+	u32 interval = beacon_interval * TIME_UNIT;
+	u32 res = (base & iwl_beacon_time_mask_high(priv,
+				priv->hw_params.beacon_time_tsf_bits)) +
+				(addon & iwl_beacon_time_mask_high(priv,
+				priv->hw_params.beacon_time_tsf_bits));
+
+	if (base_low > addon_low)
+		res += base_low - addon_low;
+	else if (base_low < addon_low) {
+		res += interval + base_low - addon_low;
+		res += (1 << priv->hw_params.beacon_time_tsf_bits);
+	} else
+		res += (1 << priv->hw_params.beacon_time_tsf_bits);
+
+	return cpu_to_le32(res);
+}
+EXPORT_SYMBOL(iwl_add_beacon_time);
+
 #ifdef CONFIG_PM
 
 int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -2908,6 +2859,7 @@
 {
 	struct iwl_priv *priv = pci_get_drvdata(pdev);
 	int ret;
+	bool hw_rfkill = false;
 
 	/*
 	 * We disable the RETRY_TIMEOUT register (0x41) to keep
@@ -2922,6 +2874,17 @@
 	pci_restore_state(pdev);
 	iwl_enable_interrupts(priv);
 
+	if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+		hw_rfkill = true;
+
+	if (hw_rfkill)
+		set_bit(STATUS_RF_KILL_HW, &priv->status);
+	else
+		clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+	wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rfkill);
+
 	return 0;
 }
 EXPORT_SYMBOL(iwl_pci_resume);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 31775bd..e9d23f2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -79,6 +79,8 @@
 	.subvendor = PCI_ANY_ID, .subdevice = (subdev), \
 	.driver_data = (kernel_ulong_t)&(cfg)
 
+#define TIME_UNIT		1024
+
 #define IWL_SKU_G       0x1
 #define IWL_SKU_A       0x2
 #define IWL_SKU_N       0x8
@@ -123,6 +125,8 @@
 				 size_t count, loff_t *ppos);
 	ssize_t (*general_stats_read)(struct file *file, char __user *user_buf,
 				      size_t count, loff_t *ppos);
+	ssize_t (*bt_stats_read)(struct file *file, char __user *user_buf,
+				 size_t count, loff_t *ppos);
 };
 
 struct iwl_temp_ops {
@@ -173,7 +177,8 @@
 	void (*dump_nic_error_log)(struct iwl_priv *priv);
 	void (*dump_csr)(struct iwl_priv *priv);
 	int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display);
-	int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
+	int (*set_channel_switch)(struct iwl_priv *priv,
+				  struct ieee80211_channel_switch *ch_switch);
 	/* power management */
 	struct iwl_apm_ops apm_ops;
 
@@ -193,6 +198,7 @@
 	/* station management */
 	int (*manage_ibss_station)(struct iwl_priv *priv,
 				   struct ieee80211_vif *vif, bool add);
+	int (*update_bcast_station)(struct iwl_priv *priv);
 	/* recover from tx queue stall */
 	void (*recover_from_tx_stall)(unsigned long data);
 	/* check for plcp health */
@@ -201,6 +207,9 @@
 	/* check for ack health */
 	bool (*check_ack_health)(struct iwl_priv *priv,
 					struct iwl_rx_packet *pkt);
+	int (*txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
+	void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
+
 	struct iwl_debugfs_ops debugfs_ops;
 };
 
@@ -325,7 +334,10 @@
 	const bool ucode_tracing;
 	const bool sensitivity_calib_by_driver;
 	const bool chain_noise_calib_by_driver;
-	u8 scan_antennas[IEEE80211_NUM_BANDS];
+	u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
+	u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
+	const bool need_dc_calib;
+	const bool bt_statistics;
 };
 
 /***************************
@@ -343,6 +355,9 @@
 int iwl_full_rxon_required(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_flags_for_band(struct iwl_priv *priv,
+			    enum ieee80211_band band,
+			    struct ieee80211_vif *vif);
 u8 iwl_get_single_channel_number(struct iwl_priv *priv,
 				  enum ieee80211_band band);
 void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
@@ -350,6 +365,7 @@
 			 struct ieee80211_sta_ht_cap *sta_ht_inf);
 void iwl_connection_init_rx_config(struct iwl_priv *priv,
 				   struct ieee80211_vif *vif);
+void iwl_set_rate(struct iwl_priv *priv);
 int iwl_set_decrypted_flag(struct iwl_priv *priv,
 			   struct ieee80211_hdr *hdr,
 			   u32 decrypt_res,
@@ -364,7 +380,6 @@
 				     struct ieee80211_vif *vif,
 				     struct ieee80211_bss_conf *bss_conf,
 				     u32 changes);
-int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
 int iwl_commit_rxon(struct iwl_priv *priv);
 int iwl_mac_add_interface(struct ieee80211_hw *hw,
 			  struct ieee80211_vif *vif);
@@ -447,20 +462,11 @@
 int iwl_rx_queue_space(const struct iwl_rx_queue *q);
 void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
 /* Handlers */
-void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
-			       struct iwl_rx_mem_buffer *rxb);
 void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
 					  struct iwl_rx_mem_buffer *rxb);
-bool iwl_good_plcp_health(struct iwl_priv *priv,
-				 struct iwl_rx_packet *pkt);
-bool iwl_good_ack_health(struct iwl_priv *priv,
-				 struct iwl_rx_packet *pkt);
 void iwl_recover_from_statistics(struct iwl_priv *priv,
 				struct iwl_rx_packet *pkt);
-void iwl_rx_statistics(struct iwl_priv *priv,
-			      struct iwl_rx_mem_buffer *rxb);
-void iwl_reply_statistics(struct iwl_priv *priv,
-			  struct iwl_rx_mem_buffer *rxb);
+void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
 void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
 
 /* TX helpers */
@@ -474,8 +480,6 @@
 				 dma_addr_t addr, u16 len, u8 reset, u8 pad);
 int iwl_hw_tx_queue_init(struct iwl_priv *priv,
 			 struct iwl_tx_queue *txq);
-void iwl_free_tfds_in_queue(struct iwl_priv *priv,
-			    int sta_id, int tid, int freed);
 void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
 int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 		      int slots_num, u32 txq_id);
@@ -495,7 +499,7 @@
 
 u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv);
 
-u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx);
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
 
 static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
 {
@@ -526,9 +530,9 @@
 		    struct cfg80211_scan_request *req);
 void iwl_bg_start_internal_scan(struct work_struct *work);
 void iwl_internal_short_hw_scan(struct iwl_priv *priv);
-int iwl_force_reset(struct iwl_priv *priv, int mode);
+int iwl_force_reset(struct iwl_priv *priv, int mode, bool external);
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
-		       const u8 *ie, int ie_len, int left);
+		       const u8 *ta, const u8 *ie, int ie_len, int left);
 void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
 u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
 			      enum ieee80211_band band,
@@ -595,6 +599,9 @@
 }
 
 void iwl_bg_monitor_recover(unsigned long data);
+u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval);
+__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
+			   u32 addon, u32 beacon_interval);
 
 #ifdef CONFIG_PM
 int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state);
@@ -693,7 +700,6 @@
 extern void iwl_send_bt_config(struct iwl_priv *priv);
 extern int iwl_send_statistics_request(struct iwl_priv *priv,
 				       u8 flags, bool clear);
-extern int iwl_verify_ucode(struct iwl_priv *priv);
 extern int iwl_send_lq_cmd(struct iwl_priv *priv,
 		struct iwl_link_quality_cmd *lq, u8 flags, bool init);
 void iwl_apm_stop(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 254c35a..ecf98e7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -298,6 +298,7 @@
 #define CSR_HW_REV_TYPE_1000           (0x0000060)
 #define CSR_HW_REV_TYPE_6x00           (0x0000070)
 #define CSR_HW_REV_TYPE_6x50           (0x0000080)
+#define CSR_HW_REV_TYPE_6x50g2         (0x0000084)
 #define CSR_HW_REV_TYPE_6x00g2         (0x00000B0)
 #define CSR_HW_REV_TYPE_NONE           (0x00000F0)
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 9659c5d..e96a1bb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -106,27 +106,6 @@
 	.open = iwl_dbgfs_open_file_generic,                            \
 };
 
-int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
-{
-	int p = 0;
-
-	p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n",
-		       le32_to_cpu(priv->statistics.flag));
-	if (le32_to_cpu(priv->statistics.flag) & UCODE_STATISTICS_CLEAR_MSK)
-		p += scnprintf(buf + p, bufsz - p,
-			       "\tStatistics have been cleared\n");
-	p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
-		       (le32_to_cpu(priv->statistics.flag) &
-			UCODE_STATISTICS_FREQUENCY_MSK)
-			? "2.4 GHz" : "5.2 GHz");
-	p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
-		       (le32_to_cpu(priv->statistics.flag) &
-			UCODE_STATISTICS_NARROW_BAND_MSK)
-			? "enabled" : "disabled");
-	return p;
-}
-EXPORT_SYMBOL(iwl_dbgfs_statistics_flag);
-
 static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
 						char __user *user_buf,
 						size_t count, loff_t *ppos) {
@@ -330,45 +309,35 @@
 
 	for (i = 0; i < max_sta; i++) {
 		station = &priv->stations[i];
-		if (station->used) {
-			pos += scnprintf(buf + pos, bufsz - pos,
-					"station %d:\ngeneral data:\n", i+1);
-			pos += scnprintf(buf + pos, bufsz - pos, "id: %u\n",
-					station->sta.sta.sta_id);
-			pos += scnprintf(buf + pos, bufsz - pos, "mode: %u\n",
-					station->sta.mode);
-			pos += scnprintf(buf + pos, bufsz - pos,
-					"flags: 0x%x\n",
-					station->sta.station_flags_msk);
-			pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n");
-			pos += scnprintf(buf + pos, bufsz - pos,
-					"seq_num\t\ttxq_id");
-			pos += scnprintf(buf + pos, bufsz - pos,
-					"\tframe_count\twait_for_ba\t");
-			pos += scnprintf(buf + pos, bufsz - pos,
-					"start_idx\tbitmap0\t");
-			pos += scnprintf(buf + pos, bufsz - pos,
-					"bitmap1\trate_n_flags");
-			pos += scnprintf(buf + pos, bufsz - pos, "\n");
+		if (!station->used)
+			continue;
+		pos += scnprintf(buf + pos, bufsz - pos,
+				 "station %d - addr: %pM, flags: %#x\n",
+				 i, station->sta.sta.addr,
+				 station->sta.station_flags_msk);
+		pos += scnprintf(buf + pos, bufsz - pos,
+				"TID\tseq_num\ttxq_id\tframes\ttfds\t");
+		pos += scnprintf(buf + pos, bufsz - pos,
+				"start_idx\tbitmap\t\t\trate_n_flags\n");
 
-			for (j = 0; j < MAX_TID_COUNT; j++) {
+		for (j = 0; j < MAX_TID_COUNT; j++) {
+			pos += scnprintf(buf + pos, bufsz - pos,
+				"%d:\t%#x\t%#x\t%u\t%u\t%u\t\t%#.16llx\t%#x",
+				j, station->tid[j].seq_number,
+				station->tid[j].agg.txq_id,
+				station->tid[j].agg.frame_count,
+				station->tid[j].tfds_in_queue,
+				station->tid[j].agg.start_idx,
+				station->tid[j].agg.bitmap,
+				station->tid[j].agg.rate_n_flags);
+
+			if (station->tid[j].agg.wait_for_ba)
 				pos += scnprintf(buf + pos, bufsz - pos,
-						"[%d]:\t\t%u", j,
-						station->tid[j].seq_number);
-				pos += scnprintf(buf + pos, bufsz - pos,
-						"\t%u\t\t%u\t\t%u\t\t",
-						station->tid[j].agg.txq_id,
-						station->tid[j].agg.frame_count,
-						station->tid[j].agg.wait_for_ba);
-				pos += scnprintf(buf + pos, bufsz - pos,
-						"%u\t%llu\t%u",
-						station->tid[j].agg.start_idx,
-						(unsigned long long)station->tid[j].agg.bitmap,
-						station->tid[j].agg.rate_n_flags);
-				pos += scnprintf(buf + pos, bufsz - pos, "\n");
-			}
+						 " - waitforba");
 			pos += scnprintf(buf + pos, bufsz - pos, "\n");
 		}
+
+		pos += scnprintf(buf + pos, bufsz - pos, "\n");
 	}
 
 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
@@ -1049,8 +1018,13 @@
 						rxq->write);
 	pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
 						rxq->free_count);
-	pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
+	if (rxq->rb_stts) {
+		pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
 			 le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF);
+	} else {
+		pos += scnprintf(buf + pos, bufsz - pos,
+					"closed_rb_num: Not Allocated\n");
+	}
 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
@@ -1293,7 +1267,7 @@
 					char __user *user_buf,
 					size_t count, loff_t *ppos) {
 
-	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+	struct iwl_priv *priv = file->private_data;
 	int pos = 0;
 	char buf[128];
 	const size_t bufsz = sizeof(buf);
@@ -1343,7 +1317,7 @@
 					 char __user *user_buf,
 					 size_t count, loff_t *ppos) {
 
-	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+	struct iwl_priv *priv = file->private_data;
 	int len = 0;
 	char buf[20];
 
@@ -1355,7 +1329,7 @@
 						char __user *user_buf,
 						size_t count, loff_t *ppos) {
 
-	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+	struct iwl_priv *priv = file->private_data;
 	int len = 0;
 	char buf[20];
 
@@ -1368,7 +1342,7 @@
 					 char __user *user_buf,
 					 size_t count, loff_t *ppos)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+	struct iwl_priv *priv = file->private_data;
 	char *buf;
 	int pos = 0;
 	ssize_t ret = -EFAULT;
@@ -1430,7 +1404,7 @@
 					char __user *user_buf,
 					size_t count, loff_t *ppos) {
 
-	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+	struct iwl_priv *priv = file->private_data;
 	int pos = 0;
 	char buf[12];
 	const size_t bufsz = sizeof(buf);
@@ -1456,10 +1430,10 @@
 		return -EFAULT;
 	if (sscanf(buf, "%d", &plcp) != 1)
 		return -EINVAL;
-	if ((plcp <= IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
+	if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
 		(plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
 		priv->cfg->plcp_delta_threshold =
-			IWL_MAX_PLCP_ERR_THRESHOLD_DEF;
+			IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE;
 	else
 		priv->cfg->plcp_delta_threshold = plcp;
 	return count;
@@ -1513,7 +1487,7 @@
 	switch (reset) {
 	case IWL_RF_RESET:
 	case IWL_FW_RESET:
-		ret = iwl_force_reset(priv, reset);
+		ret = iwl_force_reset(priv, reset, true);
 		break;
 	default:
 		return -EINVAL;
@@ -1521,6 +1495,40 @@
 	return ret ? ret : count;
 }
 
+static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos) {
+
+	struct iwl_priv *priv = file->private_data;
+	char buf[8];
+	int buf_size;
+	int flush;
+
+	memset(buf, 0, sizeof(buf));
+	buf_size = min(count, sizeof(buf) -  1);
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+	if (sscanf(buf, "%d", &flush) != 1)
+		return -EINVAL;
+
+	if (iwl_is_rfkill(priv))
+		return -EFAULT;
+
+	priv->cfg->ops->lib->dev_txfifo_flush(priv, IWL_DROP_ALL);
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+
+	return priv->cfg->ops->lib->debugfs_ops.bt_stats_read(file,
+			user_buf, count, ppos);
+}
+
 DEBUGFS_READ_FILE_OPS(rx_statistics);
 DEBUGFS_READ_FILE_OPS(tx_statistics);
 DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1542,6 +1550,8 @@
 DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
 DEBUGFS_READ_FILE_OPS(rxon_flags);
 DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
+DEBUGFS_WRITE_FILE_OPS(txfifo_flush);
+DEBUGFS_READ_FILE_OPS(ucode_bt_stats);
 
 /*
  * Create the debugfs files and directories
@@ -1600,6 +1610,8 @@
 	DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
 	DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
 	DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
+	if (priv->cfg->ops->lib->dev_txfifo_flush)
+		DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
 
 	if (priv->cfg->sensitivity_calib_by_driver)
 		DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
@@ -1607,6 +1619,8 @@
 		DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
 	if (priv->cfg->ucode_tracing)
 		DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
+	if (priv->cfg->bt_statistics)
+		DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
 	DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
 	DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
 	if (priv->cfg->sensitivity_calib_by_driver)
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index f3f3473..f35bcad 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -48,25 +48,6 @@
 #include "iwl-power.h"
 #include "iwl-agn-rs.h"
 
-/* configuration for the iwl4965 */
-extern struct iwl_cfg iwl4965_agn_cfg;
-extern struct iwl_cfg iwl5300_agn_cfg;
-extern struct iwl_cfg iwl5100_agn_cfg;
-extern struct iwl_cfg iwl5350_agn_cfg;
-extern struct iwl_cfg iwl5100_bgn_cfg;
-extern struct iwl_cfg iwl5100_abg_cfg;
-extern struct iwl_cfg iwl5150_agn_cfg;
-extern struct iwl_cfg iwl5150_abg_cfg;
-extern struct iwl_cfg iwl6000g2a_2agn_cfg;
-extern struct iwl_cfg iwl6000i_2agn_cfg;
-extern struct iwl_cfg iwl6000i_2abg_cfg;
-extern struct iwl_cfg iwl6000i_2bg_cfg;
-extern struct iwl_cfg iwl6000_3agn_cfg;
-extern struct iwl_cfg iwl6050_2agn_cfg;
-extern struct iwl_cfg iwl6050_2abg_cfg;
-extern struct iwl_cfg iwl1000_bgn_cfg;
-extern struct iwl_cfg iwl1000_bg_cfg;
-
 struct iwl_tx_queue;
 
 /* CT-KILL constants */
@@ -133,8 +114,8 @@
 	 * structure is stored at the end of the shared queue memory. */
 	u32 flags;
 
-	DECLARE_PCI_UNMAP_ADDR(mapping)
-	DECLARE_PCI_UNMAP_LEN(len)
+	DEFINE_DMA_UNMAP_ADDR(mapping);
+	DEFINE_DMA_UNMAP_LEN(len);
 };
 
 /*
@@ -157,11 +138,11 @@
 				* space more than this */
 	int high_mark;         /* high watermark, stop queue if free
 				* space less than this */
-} __attribute__ ((packed));
+} __packed;
 
 /* One for each TFD */
 struct iwl_tx_info {
-	struct sk_buff *skb[IWL_NUM_OF_TBS - 1];
+	struct sk_buff *skb;
 };
 
 /**
@@ -343,8 +324,8 @@
 		struct iwl_tx_cmd tx;
 		struct iwl6000_channel_switch_cmd chswitch;
 		u8 payload[DEF_CMD_PAYLOAD_SIZE];
-	} __attribute__ ((packed)) cmd;
-} __attribute__ ((packed));
+	} __packed cmd;
+} __packed;
 
 #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
 
@@ -367,7 +348,7 @@
 /**
  * struct iwl_rx_queue - Rx queue
  * @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
- * @dma_addr: bus address of buffer of receive buffer descriptors (rbd)
+ * @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
  * @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
@@ -381,7 +362,7 @@
  */
 struct iwl_rx_queue {
 	__le32 *bd;
-	dma_addr_t dma_addr;
+	dma_addr_t bd_dma;
 	struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
 	struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
 	u32 read;
@@ -433,7 +414,7 @@
 
 
 struct iwl_tid_data {
-	u16 seq_number;
+	u16 seq_number; /* agn only */
 	u16 tfds_in_queue;
 	struct iwl_ht_agg agg;
 };
@@ -583,6 +564,14 @@
 	IWL_UCODE_TLV_INIT_DATA		= 4,
 	IWL_UCODE_TLV_BOOT		= 5,
 	IWL_UCODE_TLV_PROBE_MAX_LEN	= 6, /* a u32 value */
+	IWL_UCODE_TLV_RUNT_EVTLOG_PTR	= 8,
+	IWL_UCODE_TLV_RUNT_EVTLOG_SIZE	= 9,
+	IWL_UCODE_TLV_RUNT_ERRLOG_PTR	= 10,
+	IWL_UCODE_TLV_INIT_EVTLOG_PTR	= 11,
+	IWL_UCODE_TLV_INIT_EVTLOG_SIZE	= 12,
+	IWL_UCODE_TLV_INIT_ERRLOG_PTR	= 13,
+	IWL_UCODE_TLV_ENHANCE_SENS_TBL	= 14,
+	IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15,
 };
 
 struct iwl_ucode_tlv {
@@ -590,7 +579,7 @@
 	__le16 alternative;	/* see comment */
 	__le32 length;		/* not including type/length fields */
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define IWL_TLV_UCODE_MAGIC	0x0a4c5749
 
@@ -675,6 +664,7 @@
  * @sw_crypto: 0 for hw, 1 for sw
  * @max_xxx_size: for ucode uses
  * @ct_kill_threshold: temperature threshold
+ * @beacon_time_tsf_bits: number of valid tsf bits for beacon time
  * @calib_init_cfg: setup initial calibrations for the hw
  * @struct iwl_sensitivity_ranges: range of sensitivity values
  */
@@ -701,6 +691,7 @@
 	u32 ct_kill_threshold; /* value in hw-dependent units */
 	u32 ct_kill_exit_threshold; /* value in hw-dependent units */
 				    /* for 1000, 6000 series and up */
+	u16 beacon_time_tsf_bits;
 	u32 calib_init_cfg;
 	const struct iwl_sensitivity_ranges *sens;
 };
@@ -1047,11 +1038,12 @@
  * This is the threshold value of plcp error rate per 100mSecs.  It is
  * used to set and check for the validity of plcp_delta.
  */
-#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN	(0)
+#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN	(1)
 #define IWL_MAX_PLCP_ERR_THRESHOLD_DEF	(50)
 #define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF	(100)
 #define IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF	(200)
 #define IWL_MAX_PLCP_ERR_THRESHOLD_MAX	(255)
+#define IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE	(0)
 
 #define IWL_DELAY_NEXT_FORCE_RF_RESET  (HZ*3)
 #define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5)
@@ -1075,6 +1067,20 @@
 	unsigned long last_force_reset_jiffies;
 };
 
+/* extend beacon time format bit shifting  */
+/*
+ * for _3945 devices
+ * bits 31:24 - extended
+ * bits 23:0  - interval
+ */
+#define IWL3945_EXT_BEACON_TIME_POS	24
+/*
+ * for _agn devices
+ * bits 31:22 - extended
+ * bits 21:0  - interval
+ */
+#define IWLAGN_EXT_BEACON_TIME_POS	22
+
 struct iwl_priv {
 
 	/* ieee device used by generic ieee processing code */
@@ -1109,7 +1115,7 @@
 	/* force reset */
 	struct iwl_force_reset force_reset[IWL_MAX_FORCE_RESET];
 
-	/* we allocate array of iwl4965_channel_info for NIC's valid channels.
+	/* we allocate array of iwl_channel_info for NIC's valid channels.
 	 *    Access via channel # using indirect index array */
 	struct iwl_channel_info *channel_info;	/* channel info array */
 	u8 channel_count;	/* # of channels */
@@ -1127,6 +1133,7 @@
 	void *scan_cmd;
 	enum ieee80211_band scan_band;
 	struct cfg80211_scan_request *scan_request;
+	struct ieee80211_vif *scan_vif;
 	bool is_internal_short_scan;
 	u8 scan_tx_ant[IEEE80211_NUM_BANDS];
 	u8 mgmt_tx_ant;
@@ -1147,6 +1154,9 @@
 	u32  hw_wa_rev;
 	u8   rev_id;
 
+	/* EEPROM MAC addresses */
+	struct mac_address addresses[2];
+
 	/* uCode images, save to reload in case of failure */
 	int fw_index;			/* firmware we're trying to load */
 	u32 ucode_ver;			/* version of ucode, copy of
@@ -1174,7 +1184,7 @@
 	struct iwl_switch_rxon switch_rxon;
 
 	/* 1st responses from initialize and runtime uCode images.
-	 * 4965's initialize alive response contains some calibration data. */
+	 * _agn's initialize alive response contains some calibration data. */
 	struct iwl_init_alive_resp card_alive_init;
 	struct iwl_alive_resp card_alive;
 
@@ -1188,7 +1198,9 @@
 	u8 start_calib;
 	struct iwl_sensitivity_data sensitivity_data;
 	struct iwl_chain_noise_data chain_noise_data;
+	bool enhance_sensitivity_table;
 	__le16 sensitivity_tbl[HD_TABLE_SIZE];
+	__le16 enhance_sensitivity_tbl[ENHANCE_HD_TABLE_ENTRIES];
 
 	struct iwl_ht_config current_ht_config;
 
@@ -1220,18 +1232,12 @@
 	struct iwl_power_mgr power_data;
 	struct iwl_tt_mgmt thermal_throttle;
 
-	struct iwl_notif_statistics statistics;
-#ifdef CONFIG_IWLWIFI_DEBUG
-	struct iwl_notif_statistics accum_statistics;
-	struct iwl_notif_statistics delta_statistics;
-	struct iwl_notif_statistics max_delta;
-#endif
-
 	/* context information */
 	u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */
-	u8 mac_addr[ETH_ALEN];
 
-	/*station table variables */
+	/* station table variables */
+
+	/* Note: if lock and sta_lock are needed, lock must be acquired first */
 	spinlock_t sta_lock;
 	int num_stations;
 	struct iwl_station_entry stations[IWL_STATION_COUNT];
@@ -1273,7 +1279,7 @@
 			struct delayed_work rfkill_poll;
 
 			struct iwl3945_notif_statistics statistics;
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
 			struct iwl3945_notif_statistics accum_statistics;
 			struct iwl3945_notif_statistics delta_statistics;
 			struct iwl3945_notif_statistics max_delta;
@@ -1315,6 +1321,28 @@
 			bool last_phy_res_valid;
 
 			struct completion firmware_loading_complete;
+
+			u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
+			u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
+
+			/*
+			 * chain noise reset and gain commands are the
+			 * two extra calibration commands follows the standard
+			 * phy calibration commands
+			 */
+			u8 phy_calib_chain_noise_reset_cmd;
+			u8 phy_calib_chain_noise_gain_cmd;
+
+			struct iwl_notif_statistics statistics;
+			struct iwl_bt_notif_statistics statistics_bt;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+			struct iwl_notif_statistics accum_statistics;
+			struct iwl_notif_statistics delta_statistics;
+			struct iwl_notif_statistics max_delta;
+			struct iwl_bt_notif_statistics accum_statistics_bt;
+			struct iwl_bt_notif_statistics delta_statistics_bt;
+			struct iwl_bt_notif_statistics max_delta_bt;
+#endif
 		} _agn;
 #endif
 	};
@@ -1336,6 +1364,7 @@
 	struct work_struct ct_enter;
 	struct work_struct ct_exit;
 	struct work_struct start_internal_scan;
+	struct work_struct tx_flush;
 
 	struct tasklet_struct irq_tasklet;
 
@@ -1353,9 +1382,7 @@
 	/* debugging info */
 	u32 debug_level; /* per device debugging will override global
 			    iwl_debug_level if set */
-	u32 framecnt_to_us;
-	atomic_t restrict_refcnt;
-	bool disable_ht40;
+#endif /* CONFIG_IWLWIFI_DEBUG */
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 	/* debugfs */
 	u16 tx_traffic_idx;
@@ -1364,8 +1391,8 @@
 	u8 *rx_traffic;
 	struct dentry *debugfs_dir;
 	u32 dbgfs_sram_offset, dbgfs_sram_len;
+	bool disable_ht40;
 #endif /* CONFIG_IWLWIFI_DEBUGFS */
-#endif /* CONFIG_IWLWIFI_DEBUG */
 
 	struct work_struct txpower_work;
 	u32 disable_sens_cal;
@@ -1419,9 +1446,9 @@
 static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv,
 							 int txq_id, int idx)
 {
-	if (priv->txq[txq_id].txb[idx].skb[0])
+	if (priv->txq[txq_id].txb[idx].skb)
 		return (struct ieee80211_hdr *)priv->txq[txq_id].
-				txb[idx].skb[0]->data;
+				txb[idx].skb->data;
 	return NULL;
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index ee11452..a45d02e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -629,6 +629,9 @@
 	    calib_ver < priv->cfg->eeprom_calib_ver)
 		goto err;
 
+	IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n",
+		 eeprom_ver, calib_ver);
+
 	return 0;
 err:
 	IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 95aa202..a4772af 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -118,7 +118,7 @@
 struct iwl_eeprom_channel {
 	u8 flags;		/* EEPROM_CHANNEL_* flags copied from EEPROM */
 	s8 max_power_avg;	/* max power (dBm) on this chnl, limit 31 */
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * iwl_eeprom_enhanced_txpwr structure
@@ -144,7 +144,7 @@
 	s8 reserved;
 	s8 mimo2_max;
 	s8 mimo3_max;
-} __attribute__ ((packed));
+} __packed;
 
 /* 3945 Specific */
 #define EEPROM_3945_EEPROM_VERSION	(0x2f)
@@ -276,6 +276,10 @@
 #define EEPROM_6050_TX_POWER_VERSION    (4)
 #define EEPROM_6050_EEPROM_VERSION	(0x532)
 
+/* 6x50g2 Specific */
+#define EEPROM_6050G2_TX_POWER_VERSION    (6)
+#define EEPROM_6050G2_EEPROM_VERSION	(0x553)
+
 /* 6x00g2 Specific */
 #define EEPROM_6000G2_TX_POWER_VERSION    (6)
 #define EEPROM_6000G2_EEPROM_VERSION	(0x709)
@@ -312,7 +316,7 @@
 	u8 gain_idx;		/* Index into gain table */
 	u8 actual_pow;		/* Measured RF output power, half-dBm */
 	s8 pa_det;		/* Power amp detector level (not used) */
-} __attribute__ ((packed));
+} __packed;
 
 
 /*
@@ -328,7 +332,7 @@
 	struct iwl_eeprom_calib_measure
 		measurements[EEPROM_TX_POWER_TX_CHAINS]
 			[EEPROM_TX_POWER_MEASUREMENTS];
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * txpower subband info.
@@ -345,7 +349,7 @@
 	u8 ch_to;	/* channel number of highest channel in subband */
 	struct iwl_eeprom_calib_ch_info ch1;
 	struct iwl_eeprom_calib_ch_info ch2;
-} __attribute__ ((packed));
+} __packed;
 
 
 /*
@@ -374,7 +378,7 @@
 	__le16 voltage;		/* signed */
 	struct iwl_eeprom_calib_subband_info
 		band_info[EEPROM_TX_POWER_BANDS];
-} __attribute__ ((packed));
+} __packed;
 
 
 #define ADDRESS_MSK                 0x0000FFFF
@@ -398,6 +402,7 @@
 #define EEPROM_WOWLAN_MODE                  (2*0x47)	/* 2  bytes */
 #define EEPROM_RADIO_CONFIG                 (2*0x48)	/* 2  bytes */
 #define EEPROM_3945_M_VERSION               (2*0x4A)	/* 1  bytes */
+#define EEPROM_NUM_MAC_ADDRESS              (2*0x4C)	/* 2  bytes */
 
 /* The following masks are to be applied on EEPROM_RADIO_CONFIG */
 #define EEPROM_RF_CFG_TYPE_MSK(x)   (x & 0x3)         /* bits 0-1   */
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index 113c366..55b8370 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -398,12 +398,7 @@
  */
 #define FH_TSSR_TX_ERROR_REG		(FH_TSSR_LOWER_BOUND + 0x018)
 
-#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)
-
-#define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \
-	(FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
-	FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
+#define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) ((1 << (_chnl)) << 16)
 
 /* Tx service channels */
 #define FH_SRVC_CHNL		(9)
@@ -449,7 +444,7 @@
 	__le16 finished_rb_num;
 	__le16 finished_fr_nam;
 	__le32 __unused; /* 3945 only */
-} __attribute__ ((packed));
+} __packed;
 
 
 #define TFD_QUEUE_SIZE_MAX      (256)
@@ -475,7 +470,7 @@
 struct iwl_tfd_tb {
 	__le32 lo;
 	__le16 hi_n_len;
-} __attribute__((packed));
+} __packed;
 
 /**
  * struct iwl_tfd
@@ -510,7 +505,7 @@
 	u8 num_tbs;
 	struct iwl_tfd_tb tbs[IWL_NUM_OF_TBS];
 	__le32 __pad;
-} __attribute__ ((packed));
+} __packed;
 
 /* Keep Warm Size */
 #define IWL_KW_SIZE 0x1000	/* 4k */
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 51f89e7..258d059 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -49,6 +49,7 @@
 		IWL_CMD(REPLY_ADD_STA);
 		IWL_CMD(REPLY_REMOVE_STA);
 		IWL_CMD(REPLY_REMOVE_ALL_STA);
+		IWL_CMD(REPLY_TXFIFO_FLUSH);
 		IWL_CMD(REPLY_WEPKEY);
 		IWL_CMD(REPLY_3945_RX);
 		IWL_CMD(REPLY_TX);
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index 3ff6b9d..621abe3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -92,6 +92,11 @@
 static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev,
 				    struct fw_desc *desc)
 {
+	if (!desc->len) {
+		desc->v_addr = NULL;
+		return -EINVAL;
+	}
+
 	desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len,
 					  &desc->p_addr, GFP_KERNEL);
 	return (desc->v_addr != NULL) ? 0 : -ENOMEM;
@@ -170,4 +175,26 @@
 	iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
 }
 
+/**
+ * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time
+ * @priv -- pointer to iwl_priv data structure
+ * @tsf_bits -- number of bits need to shift for masking)
+ */
+static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv,
+					   u16 tsf_bits)
+{
+	return (1 << tsf_bits) - 1;
+}
+
+/**
+ * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time
+ * @priv -- pointer to iwl_priv data structure
+ * @tsf_bits -- number of bits need to shift for masking)
+ */
+static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv,
+					    u16 tsf_bits)
+{
+	return ((1 << (32 - tsf_bits)) - 1) << tsf_bits;
+}
+
 #endif				/* __iwl_helpers_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 0a5d7cf..79773e3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -175,7 +175,7 @@
 	INIT_LIST_HEAD(&rxq->rx_used);
 
 	/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
-	rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr,
+	rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->bd_dma,
 				     GFP_KERNEL);
 	if (!rxq->bd)
 		goto err_bd;
@@ -199,32 +199,12 @@
 
 err_rb:
 	dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
-			  rxq->dma_addr);
+			  rxq->bd_dma);
 err_bd:
 	return -ENOMEM;
 }
 EXPORT_SYMBOL(iwl_rx_queue_alloc);
 
-void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
-				struct iwl_rx_mem_buffer *rxb)
-
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_missed_beacon_notif *missed_beacon;
-
-	missed_beacon = &pkt->u.missed_beacon;
-	if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
-	    priv->missed_beacon_threshold) {
-		IWL_DEBUG_CALIB(priv, "missed bcn cnsq %d totl %d rcd %d expctd %d\n",
-		    le32_to_cpu(missed_beacon->consecutive_missed_beacons),
-		    le32_to_cpu(missed_beacon->total_missed_becons),
-		    le32_to_cpu(missed_beacon->num_recvd_beacons),
-		    le32_to_cpu(missed_beacon->num_expected_beacons));
-		if (!test_bit(STATUS_SCANNING, &priv->status))
-			iwl_init_sensitivity(priv);
-	}
-}
-EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);
 
 void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
 					  struct iwl_rx_mem_buffer *rxb)
@@ -243,161 +223,6 @@
 }
 EXPORT_SYMBOL(iwl_rx_spectrum_measure_notif);
 
-
-
-/* Calculate noise level, based on measurements during network silence just
- *   before arriving beacon.  This measurement can be done only if we know
- *   exactly when to expect beacons, therefore only when we're associated. */
-static void iwl_rx_calc_noise(struct iwl_priv *priv)
-{
-	struct statistics_rx_non_phy *rx_info
-				= &(priv->statistics.rx.general);
-	int num_active_rx = 0;
-	int total_silence = 0;
-	int bcn_silence_a =
-		le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
-	int bcn_silence_b =
-		le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
-	int bcn_silence_c =
-		le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
-	int last_rx_noise;
-
-	if (bcn_silence_a) {
-		total_silence += bcn_silence_a;
-		num_active_rx++;
-	}
-	if (bcn_silence_b) {
-		total_silence += bcn_silence_b;
-		num_active_rx++;
-	}
-	if (bcn_silence_c) {
-		total_silence += bcn_silence_c;
-		num_active_rx++;
-	}
-
-	/* Average among active antennas */
-	if (num_active_rx)
-		last_rx_noise = (total_silence / num_active_rx) - 107;
-	else
-		last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-
-	IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",
-			bcn_silence_a, bcn_silence_b, bcn_silence_c,
-			last_rx_noise);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-/*
- *  based on the assumption of all statistics counter are in DWORD
- *  FIXME: This function is for debugging, do not deal with
- *  the case of counters roll-over.
- */
-static void iwl_accumulative_statistics(struct iwl_priv *priv,
-					__le32 *stats)
-{
-	int i;
-	__le32 *prev_stats;
-	u32 *accum_stats;
-	u32 *delta, *max_delta;
-
-	prev_stats = (__le32 *)&priv->statistics;
-	accum_stats = (u32 *)&priv->accum_statistics;
-	delta = (u32 *)&priv->delta_statistics;
-	max_delta = (u32 *)&priv->max_delta;
-
-	for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics);
-	     i += sizeof(__le32), stats++, prev_stats++, delta++,
-	     max_delta++, accum_stats++) {
-		if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
-			*delta = (le32_to_cpu(*stats) -
-				le32_to_cpu(*prev_stats));
-			*accum_stats += *delta;
-			if (*delta > *max_delta)
-				*max_delta = *delta;
-		}
-	}
-
-	/* reset accumulative statistics for "no-counter" type statistics */
-	priv->accum_statistics.general.temperature =
-		priv->statistics.general.temperature;
-	priv->accum_statistics.general.temperature_m =
-		priv->statistics.general.temperature_m;
-	priv->accum_statistics.general.ttl_timestamp =
-		priv->statistics.general.ttl_timestamp;
-	priv->accum_statistics.tx.tx_power.ant_a =
-		priv->statistics.tx.tx_power.ant_a;
-	priv->accum_statistics.tx.tx_power.ant_b =
-		priv->statistics.tx.tx_power.ant_b;
-	priv->accum_statistics.tx.tx_power.ant_c =
-		priv->statistics.tx.tx_power.ant_c;
-}
-#endif
-
-#define REG_RECALIB_PERIOD (60)
-
-/**
- * iwl_good_plcp_health - checks for plcp error.
- *
- * When the plcp error is exceeding the thresholds, reset the radio
- * to improve the throughput.
- */
-bool iwl_good_plcp_health(struct iwl_priv *priv,
-				struct iwl_rx_packet *pkt)
-{
-	bool rc = true;
-	int combined_plcp_delta;
-	unsigned int plcp_msec;
-	unsigned long plcp_received_jiffies;
-
-	/*
-	 * check for plcp_err and trigger radio reset if it exceeds
-	 * the plcp error threshold plcp_delta.
-	 */
-	plcp_received_jiffies = jiffies;
-	plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
-					(long) priv->plcp_jiffies);
-	priv->plcp_jiffies = plcp_received_jiffies;
-	/*
-	 * check to make sure plcp_msec is not 0 to prevent division
-	 * by zero.
-	 */
-	if (plcp_msec) {
-		combined_plcp_delta =
-			(le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) -
-			le32_to_cpu(priv->statistics.rx.ofdm.plcp_err)) +
-			(le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) -
-			le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err));
-
-		if ((combined_plcp_delta > 0) &&
-		    ((combined_plcp_delta * 100) / plcp_msec) >
-			priv->cfg->plcp_delta_threshold) {
-			/*
-			 * if plcp_err exceed the threshold,
-			 * the following data is printed in csv format:
-			 *    Text: plcp_err exceeded %d,
-			 *    Received ofdm.plcp_err,
-			 *    Current ofdm.plcp_err,
-			 *    Received ofdm_ht.plcp_err,
-			 *    Current ofdm_ht.plcp_err,
-			 *    combined_plcp_delta,
-			 *    plcp_msec
-			 */
-			IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
-				"%u, %u, %u, %u, %d, %u mSecs\n",
-				priv->cfg->plcp_delta_threshold,
-				le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),
-				le32_to_cpu(priv->statistics.rx.ofdm.plcp_err),
-				le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),
-				le32_to_cpu(
-				  priv->statistics.rx.ofdm_ht.plcp_err),
-				combined_plcp_delta, plcp_msec);
-			rc = false;
-		}
-	}
-	return rc;
-}
-EXPORT_SYMBOL(iwl_good_plcp_health);
-
 void iwl_recover_from_statistics(struct iwl_priv *priv,
 				struct iwl_rx_packet *pkt)
 {
@@ -413,7 +238,7 @@
 				 */
 				IWL_ERR(priv, "low ack count detected, "
 					"restart firmware\n");
-				if (!iwl_force_reset(priv, IWL_FW_RESET))
+				if (!iwl_force_reset(priv, IWL_FW_RESET, false))
 					return;
 			}
 		}
@@ -424,76 +249,13 @@
 				 * high plcp error detected
 				 * reset Radio
 				 */
-				iwl_force_reset(priv, IWL_RF_RESET);
+				iwl_force_reset(priv, IWL_RF_RESET, false);
 			}
 		}
 	}
 }
 EXPORT_SYMBOL(iwl_recover_from_statistics);
 
-void iwl_rx_statistics(struct iwl_priv *priv,
-			      struct iwl_rx_mem_buffer *rxb)
-{
-	int change;
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-
-
-	IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
-		     (int)sizeof(priv->statistics),
-		     le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
-
-	change = ((priv->statistics.general.temperature !=
-		   pkt->u.stats.general.temperature) ||
-		  ((priv->statistics.flag &
-		    STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
-		   (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
-#endif
-	iwl_recover_from_statistics(priv, pkt);
-
-	memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
-
-	set_bit(STATUS_STATISTICS, &priv->status);
-
-	/* Reschedule the statistics timer to occur in
-	 * REG_RECALIB_PERIOD seconds to ensure we get a
-	 * thermal update even if the uCode doesn't give
-	 * us one */
-	mod_timer(&priv->statistics_periodic, jiffies +
-		  msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
-
-	if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
-	    (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
-		iwl_rx_calc_noise(priv);
-		queue_work(priv->workqueue, &priv->run_time_calib_work);
-	}
-	if (priv->cfg->ops->lib->temp_ops.temperature && change)
-		priv->cfg->ops->lib->temp_ops.temperature(priv);
-}
-EXPORT_SYMBOL(iwl_rx_statistics);
-
-void iwl_reply_statistics(struct iwl_priv *priv,
-			      struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-
-	if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
-#ifdef CONFIG_IWLWIFI_DEBUG
-		memset(&priv->accum_statistics, 0,
-			sizeof(struct iwl_notif_statistics));
-		memset(&priv->delta_statistics, 0,
-			sizeof(struct iwl_notif_statistics));
-		memset(&priv->max_delta, 0,
-			sizeof(struct iwl_notif_statistics));
-#endif
-		IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
-	}
-	iwl_rx_statistics(priv, rxb);
-}
-EXPORT_SYMBOL(iwl_reply_statistics);
-
 /*
  * returns non-zero if packet should be dropped
  */
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 386c5f9..b0c6b04 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -333,7 +333,8 @@
 		goto out_unlock;
 	}
 
-	if (test_bit(STATUS_SCANNING, &priv->status)) {
+	if (test_bit(STATUS_SCANNING, &priv->status) &&
+	    !priv->is_internal_short_scan) {
 		IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
 		ret = -EAGAIN;
 		goto out_unlock;
@@ -348,8 +349,16 @@
 	/* mac80211 will only ask for one band at a time */
 	priv->scan_band = req->channels[0]->band;
 	priv->scan_request = req;
+	priv->scan_vif = vif;
 
-	ret = iwl_scan_initiate(priv, vif);
+	/*
+	 * If an internal scan is in progress, just set
+	 * up the scan_request as per above.
+	 */
+	if (priv->is_internal_short_scan)
+		ret = 0;
+	else
+		ret = iwl_scan_initiate(priv, vif);
 
 	IWL_DEBUG_MAC80211(priv, "leave\n");
 
@@ -420,11 +429,10 @@
 		return;
 
 	mutex_lock(&priv->mutex);
-	if (test_bit(STATUS_SCANNING, &priv->status) ||
-	    test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-		IWL_DEBUG_SCAN(priv, "Scan completion watchdog resetting "
-			"adapter (%dms)\n",
-			jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
+	if (test_bit(STATUS_SCANNING, &priv->status) &&
+	    !test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_SCAN(priv, "Scan completion watchdog (%dms)\n",
+			       jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
 
 		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
 			iwl_send_scan_abort(priv);
@@ -438,7 +446,7 @@
  */
 
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
-		       const u8 *ies, int ie_len, int left)
+		       const u8 *ta, const u8 *ies, int ie_len, int left)
 {
 	int len = 0;
 	u8 *pos = NULL;
@@ -451,7 +459,7 @@
 
 	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
 	memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
-	memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
+	memcpy(frame->sa, ta, ETH_ALEN);
 	memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
 	frame->seq_ctrl = 0;
 
@@ -489,12 +497,11 @@
 	    !test_bit(STATUS_GEO_CONFIGURED, &priv->status))
 		return;
 
+	cancel_delayed_work(&priv->scan_check);
+
 	mutex_lock(&priv->mutex);
-
-	cancel_delayed_work_sync(&priv->scan_check);
-	set_bit(STATUS_SCAN_ABORTING, &priv->status);
-	iwl_send_scan_abort(priv);
-
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status))
+		iwl_send_scan_abort(priv);
 	mutex_unlock(&priv->mutex);
 }
 EXPORT_SYMBOL(iwl_bg_abort_scan);
@@ -514,7 +521,30 @@
 		priv->is_internal_short_scan = false;
 		IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
 		internal = true;
+	} else {
+		priv->scan_request = NULL;
+		priv->scan_vif = NULL;
 	}
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		goto out;
+
+	if (internal && priv->scan_request)
+		iwl_scan_initiate(priv, priv->scan_vif);
+
+	/* Since setting the TXPOWER may have been deferred while
+	 * performing the scan, fire one off */
+	iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
+
+	/*
+	 * Since setting the RXON may have been deferred while
+	 * performing the scan, fire one off if needed
+	 */
+	if (memcmp(&priv->active_rxon,
+		   &priv->staging_rxon, sizeof(priv->staging_rxon)))
+		iwlcore_commit_rxon(priv);
+
+ out:
 	mutex_unlock(&priv->mutex);
 
 	/*
@@ -524,15 +554,6 @@
 	 */
 	if (!internal)
 		ieee80211_scan_completed(priv->hw, false);
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
-
-	/* Since setting the TXPOWER may have been deferred while
-	 * performing the scan, fire one off */
-	mutex_lock(&priv->mutex);
-	iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
-	mutex_unlock(&priv->mutex);
 }
 EXPORT_SYMBOL(iwl_bg_scan_completed);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
index af6babe..c4ca0b5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
@@ -42,7 +42,7 @@
 	__le64 start_time;
 	__le16 duration;
 	u8 map;
-} __attribute__ ((packed));
+} __packed;
 
 enum {				/* ieee80211_measurement_request.mode */
 	/* Bit 0 is reserved */
@@ -63,13 +63,13 @@
 	u8 channel;
 	__le64 start_time;
 	__le16 duration;
-} __attribute__ ((packed));
+} __packed;
 
 struct ieee80211_info_element {
 	u8 id;
 	u8 len;
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct ieee80211_measurement_request {
 	struct ieee80211_info_element ie;
@@ -77,7 +77,7 @@
 	u8 mode;
 	u8 type;
 	struct ieee80211_measurement_params params[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct ieee80211_measurement_report {
 	struct ieee80211_info_element ie;
@@ -87,6 +87,6 @@
 	union {
 		struct ieee80211_basic_report basic[0];
 	} u;
-} __attribute__ ((packed));
+} __packed;
 
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index c27c13f..9511f03 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -30,6 +30,7 @@
 #include <net/mac80211.h>
 #include <linux/etherdevice.h>
 #include <linux/sched.h>
+#include <linux/lockdep.h>
 
 #include "iwl-dev.h"
 #include "iwl-core.h"
@@ -54,18 +55,19 @@
 	}
 }
 
-static void iwl_process_add_sta_resp(struct iwl_priv *priv,
-				     struct iwl_addsta_cmd *addsta,
-				     struct iwl_rx_packet *pkt,
-				     bool sync)
+static int iwl_process_add_sta_resp(struct iwl_priv *priv,
+				    struct iwl_addsta_cmd *addsta,
+				    struct iwl_rx_packet *pkt,
+				    bool sync)
 {
 	u8 sta_id = addsta->sta.sta_id;
 	unsigned long flags;
+	int ret = -EIO;
 
 	if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
 			pkt->hdr.flags);
-		return;
+		return ret;
 	}
 
 	IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
@@ -77,6 +79,7 @@
 	case ADD_STA_SUCCESS_MSK:
 		IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
 		iwl_sta_ucode_activate(priv, sta_id);
+		ret = 0;
 		break;
 	case ADD_STA_NO_ROOM_IN_TABLE:
 		IWL_ERR(priv, "Adding station %d failed, no room in table.\n",
@@ -114,6 +117,8 @@
 		       STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
 		       addsta->sta.addr);
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	return ret;
 }
 
 static void iwl_add_sta_callback(struct iwl_priv *priv,
@@ -145,8 +150,10 @@
 
 	if (flags & CMD_ASYNC)
 		cmd.callback = iwl_add_sta_callback;
-	else
+	else {
 		cmd.flags |= CMD_WANT_SKB;
+		might_sleep();
+	}
 
 	cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
 	ret = iwl_send_cmd(priv, &cmd);
@@ -156,7 +163,7 @@
 
 	if (ret == 0) {
 		pkt = (struct iwl_rx_packet *)cmd.reply_page;
-		iwl_process_add_sta_resp(priv, sta, pkt, true);
+		ret = iwl_process_add_sta_resp(priv, sta, pkt, true);
 	}
 	iwl_free_pages(priv, cmd.reply_page);
 
@@ -311,10 +318,10 @@
 				  struct ieee80211_sta_ht_cap *ht_info,
 				  u8 *sta_id_r)
 {
-	struct iwl_station_entry *station;
 	unsigned long flags_spin;
 	int ret = 0;
 	u8 sta_id;
+	struct iwl_addsta_cmd sta_cmd;
 
 	*sta_id_r = 0;
 	spin_lock_irqsave(&priv->sta_lock, flags_spin);
@@ -347,14 +354,15 @@
 	}
 
 	priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS;
-	station = &priv->stations[sta_id];
+	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
 	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
 
 	/* Add station to device's station table */
-	ret = iwl_send_add_sta(priv, &station->sta, CMD_SYNC);
+	ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 	if (ret) {
-		IWL_ERR(priv, "Adding station %pM failed.\n", station->sta.sta.addr);
 		spin_lock_irqsave(&priv->sta_lock, flags_spin);
+		IWL_ERR(priv, "Adding station %pM failed.\n",
+			priv->stations[sta_id].sta.sta.addr);
 		priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
 		priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
 		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
@@ -488,7 +496,7 @@
 }
 
 static int iwl_send_remove_station(struct iwl_priv *priv,
-				   struct iwl_station_entry *station)
+				   const u8 *addr, int sta_id)
 {
 	struct iwl_rx_packet *pkt;
 	int ret;
@@ -505,7 +513,7 @@
 
 	memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
 	rm_sta_cmd.num_sta = 1;
-	memcpy(&rm_sta_cmd.addr, &station->sta.sta.addr , ETH_ALEN);
+	memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN);
 
 	cmd.flags |= CMD_WANT_SKB;
 
@@ -525,7 +533,7 @@
 		switch (pkt->u.rem_sta.status) {
 		case REM_STA_SUCCESS_MSK:
 			spin_lock_irqsave(&priv->sta_lock, flags_spin);
-			iwl_sta_ucode_deactivate(priv, station->sta.sta.sta_id);
+			iwl_sta_ucode_deactivate(priv, sta_id);
 			spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
 			IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
 			break;
@@ -546,7 +554,6 @@
 int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
 		       const u8 *addr)
 {
-	struct iwl_station_entry *station;
 	unsigned long flags;
 
 	if (!iwl_is_ready(priv)) {
@@ -592,10 +599,9 @@
 
 	BUG_ON(priv->num_stations < 0);
 
-	station = &priv->stations[sta_id];
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-	return iwl_send_remove_station(priv, station);
+	return iwl_send_remove_station(priv, addr, sta_id);
 out_err:
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 	return -EINVAL;
@@ -643,11 +649,13 @@
  */
 void iwl_restore_stations(struct iwl_priv *priv)
 {
-	struct iwl_station_entry *station;
+	struct iwl_addsta_cmd sta_cmd;
+	struct iwl_link_quality_cmd lq;
 	unsigned long flags_spin;
 	int i;
 	bool found = false;
 	int ret;
+	bool send_lq;
 
 	if (!iwl_is_ready(priv)) {
 		IWL_DEBUG_INFO(priv, "Not ready yet, not restoring any stations.\n");
@@ -669,13 +677,20 @@
 
 	for (i = 0; i < priv->hw_params.max_stations; i++) {
 		if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) {
+			memcpy(&sta_cmd, &priv->stations[i].sta,
+			       sizeof(struct iwl_addsta_cmd));
+			send_lq = false;
+			if (priv->stations[i].lq) {
+				memcpy(&lq, priv->stations[i].lq,
+				       sizeof(struct iwl_link_quality_cmd));
+				send_lq = true;
+			}
 			spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-			station = &priv->stations[i];
-			ret = iwl_send_add_sta(priv, &priv->stations[i].sta, CMD_SYNC);
+			ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 			if (ret) {
-				IWL_ERR(priv, "Adding station %pM failed.\n",
-					station->sta.sta.addr);
 				spin_lock_irqsave(&priv->sta_lock, flags_spin);
+				IWL_ERR(priv, "Adding station %pM failed.\n",
+					priv->stations[i].sta.sta.addr);
 				priv->stations[i].used &= ~IWL_STA_DRIVER_ACTIVE;
 				priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
 				spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
@@ -684,8 +699,8 @@
 			 * Rate scaling has already been initialized, send
 			 * current LQ command
 			 */
-			if (station->lq)
-				iwl_send_lq_cmd(priv, station->lq, CMD_SYNC, true);
+			if (send_lq)
+				iwl_send_lq_cmd(priv, &lq, CMD_SYNC, true);
 			spin_lock_irqsave(&priv->sta_lock, flags_spin);
 			priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
 		}
@@ -823,7 +838,9 @@
 {
 	unsigned long flags;
 	__le16 key_flags = 0;
-	int ret;
+	struct iwl_addsta_cmd sta_cmd;
+
+	lockdep_assert_held(&priv->mutex);
 
 	keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
 
@@ -863,11 +880,10 @@
 	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
 	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 
-	ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-
+	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-	return ret;
+	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 
 static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
@@ -876,7 +892,9 @@
 {
 	unsigned long flags;
 	__le16 key_flags = 0;
-	int ret;
+	struct iwl_addsta_cmd sta_cmd;
+
+	lockdep_assert_held(&priv->mutex);
 
 	key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
 	key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
@@ -911,11 +929,10 @@
 	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
 	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 
-	ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-
+	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-	return ret;
+	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 
 static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
@@ -972,24 +989,16 @@
 	unsigned long flags;
 	int i;
 
-	if (sta) {
-		sta_id = iwl_sta_id(sta);
-
-		if (sta_id == IWL_INVALID_STATION) {
-			IWL_DEBUG_MAC80211(priv, "leave - %pM not initialised.\n",
-					   sta->addr);
-			return;
-		}
-	} else
-		sta_id = priv->hw_params.bcast_sta_id;
-
-
 	if (iwl_scan_cancel(priv)) {
 		/* cancel scan failed, just live w/ bad key and rely
 		   briefly on SW decryption */
 		return;
 	}
 
+	sta_id = iwl_sta_id_or_broadcast(priv, sta);
+	if (sta_id == IWL_INVALID_STATION)
+		return;
+
 	spin_lock_irqsave(&priv->sta_lock, flags);
 
 	priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
@@ -1013,9 +1022,11 @@
 				u8 sta_id)
 {
 	unsigned long flags;
-	int ret = 0;
 	u16 key_flags;
 	u8 keyidx;
+	struct iwl_addsta_cmd sta_cmd;
+
+	lockdep_assert_held(&priv->mutex);
 
 	priv->key_mapping_key--;
 
@@ -1062,9 +1073,10 @@
 		spin_unlock_irqrestore(&priv->sta_lock, flags);
 		return 0;
 	}
-	ret =  iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
-	return ret;
+
+	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 EXPORT_SYMBOL(iwl_remove_dynamic_key);
 
@@ -1073,6 +1085,8 @@
 {
 	int ret;
 
+	lockdep_assert_held(&priv->mutex);
+
 	priv->key_mapping_key++;
 	keyconf->hw_key_idx = HW_KEY_DYNAMIC;
 
@@ -1245,6 +1259,36 @@
 }
 EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station);
 
+/**
+ * iwl_update_bcast_station - update broadcast station's LQ command
+ *
+ * Only used by iwlagn. Placed here to have all bcast station management
+ * code together.
+ */
+int iwl_update_bcast_station(struct iwl_priv *priv)
+{
+	unsigned long flags;
+	struct iwl_link_quality_cmd *link_cmd;
+	u8 sta_id = priv->hw_params.bcast_sta_id;
+
+	link_cmd = iwl_sta_alloc_lq(priv, sta_id);
+	if (!link_cmd) {
+		IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n");
+		return -ENOMEM;
+	}
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	if (priv->stations[sta_id].lq)
+		kfree(priv->stations[sta_id].lq);
+	else
+		IWL_DEBUG_INFO(priv, "Bcast station rate scaling has not been initialized yet.\n");
+	priv->stations[sta_id].lq = link_cmd;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(iwl_update_bcast_station);
+
 void iwl_dealloc_bcast_station(struct iwl_priv *priv)
 {
 	unsigned long flags;
@@ -1268,18 +1312,22 @@
 /**
  * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
  */
-void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
+int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
 {
 	unsigned long flags;
+	struct iwl_addsta_cmd sta_cmd;
+
+	lockdep_assert_held(&priv->mutex);
 
 	/* Remove "disable" flag, to enable Tx for this TID */
 	spin_lock_irqsave(&priv->sta_lock, flags);
 	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
 	priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
 	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);
 
@@ -1288,6 +1336,9 @@
 {
 	unsigned long flags;
 	int sta_id;
+	struct iwl_addsta_cmd sta_cmd;
+
+	lockdep_assert_held(&priv->mutex);
 
 	sta_id = iwl_sta_id(sta);
 	if (sta_id == IWL_INVALID_STATION)
@@ -1299,10 +1350,10 @@
 	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;
+	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-	return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
-				CMD_ASYNC);
+	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 EXPORT_SYMBOL(iwl_sta_rx_agg_start);
 
@@ -1311,6 +1362,9 @@
 {
 	unsigned long flags;
 	int sta_id;
+	struct iwl_addsta_cmd sta_cmd;
+
+	lockdep_assert_held(&priv->mutex);
 
 	sta_id = iwl_sta_id(sta);
 	if (sta_id == IWL_INVALID_STATION) {
@@ -1323,10 +1377,10 @@
 	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;
+	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-	return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
-					CMD_ASYNC);
+	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 EXPORT_SYMBOL(iwl_sta_rx_agg_stop);
 
@@ -1340,9 +1394,9 @@
 	priv->stations[sta_id].sta.sta.modify_mask = 0;
 	priv->stations[sta_id].sta.sleep_tx_count = 0;
 	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_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
 EXPORT_SYMBOL(iwl_sta_modify_ps_wake);
 
@@ -1357,9 +1411,9 @@
 					STA_MODIFY_SLEEP_TX_COUNT_MSK;
 	priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt);
 	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_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
 EXPORT_SYMBOL(iwl_sta_modify_sleep_tx_count);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index dc43ebd..d38a350 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -60,6 +60,7 @@
 void iwl_clear_ucode_stations(struct iwl_priv *priv);
 int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq);
 void iwl_dealloc_bcast_station(struct iwl_priv *priv);
+int iwl_update_bcast_station(struct iwl_priv *priv);
 int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
 int iwl_send_add_sta(struct iwl_priv *priv,
 		     struct iwl_addsta_cmd *sta, u8 flags);
@@ -73,7 +74,7 @@
 		       const u8 *addr);
 int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		       struct ieee80211_sta *sta);
-void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
+int 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, struct ieee80211_sta *sta,
 			 int tid, u16 ssn);
 int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
@@ -118,4 +119,33 @@
 
 	return ((struct iwl_station_priv_common *)sta->drv_priv)->sta_id;
 }
+
+/**
+ * iwl_sta_id_or_broadcast - return sta_id or broadcast sta
+ * @priv: iwl priv
+ * @sta: mac80211 station
+ *
+ * In certain circumstances mac80211 passes a station pointer
+ * that may be %NULL, for example during TX or key setup. In
+ * that case, we need to use the broadcast station, so this
+ * inline wraps that pattern.
+ */
+static inline int iwl_sta_id_or_broadcast(struct iwl_priv *priv,
+					  struct ieee80211_sta *sta)
+{
+	int sta_id;
+
+	if (!sta)
+		return priv->hw_params.bcast_sta_id;
+
+	sta_id = iwl_sta_id(sta);
+
+	/*
+	 * mac80211 should not be passing a partially
+	 * initialised station!
+	 */
+	WARN_ON(sta_id == IWL_INVALID_STATION);
+
+	return sta_id;
+}
 #endif /* __iwl_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 1ece2ea..a81989c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -77,21 +77,6 @@
 }
 EXPORT_SYMBOL(iwl_txq_update_write_ptr);
 
-
-void iwl_free_tfds_in_queue(struct iwl_priv *priv,
-			    int sta_id, int tid, int freed)
-{
-	if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
-		priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
-	else {
-		IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n",
-			priv->stations[sta_id].tid[tid].tfds_in_queue,
-			freed);
-		priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
-	}
-}
-EXPORT_SYMBOL(iwl_free_tfds_in_queue);
-
 /**
  * iwl_tx_queue_free - Deallocate DMA queue.
  * @txq: Transmit queue to deallocate.
@@ -169,15 +154,15 @@
 		}
 
 		pci_unmap_single(priv->pci_dev,
-				 pci_unmap_addr(&txq->meta[i], mapping),
-				 pci_unmap_len(&txq->meta[i], len),
+				 dma_unmap_addr(&txq->meta[i], mapping),
+				 dma_unmap_len(&txq->meta[i], len),
 				 PCI_DMA_BIDIRECTIONAL);
 	}
 	if (huge) {
 		i = q->n_window;
 		pci_unmap_single(priv->pci_dev,
-				 pci_unmap_addr(&txq->meta[i], mapping),
-				 pci_unmap_len(&txq->meta[i], len),
+				 dma_unmap_addr(&txq->meta[i], mapping),
+				 dma_unmap_len(&txq->meta[i], len),
 				 PCI_DMA_BIDIRECTIONAL);
 	}
 
@@ -287,7 +272,7 @@
 	/* Driver private data, only for Tx (not command) queues,
 	 * not shared with device. */
 	if (id != IWL_CMD_QUEUE_NUM) {
-		txq->txb = kmalloc(sizeof(txq->txb[0]) *
+		txq->txb = kzalloc(sizeof(txq->txb[0]) *
 				   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
 		if (!txq->txb) {
 			IWL_ERR(priv, "kmalloc for auxiliary BD "
@@ -531,8 +516,8 @@
 
 	phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
 				   fix_size, PCI_DMA_BIDIRECTIONAL);
-	pci_unmap_addr_set(out_meta, mapping, phys_addr);
-	pci_unmap_len_set(out_meta, len, fix_size);
+	dma_unmap_addr_set(out_meta, mapping, phys_addr);
+	dma_unmap_len_set(out_meta, len, fix_size);
 
 	trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags);
 
@@ -626,8 +611,8 @@
 	meta = &txq->meta[cmd_index];
 
 	pci_unmap_single(priv->pci_dev,
-			 pci_unmap_addr(meta, mapping),
-			 pci_unmap_len(meta, len),
+			 dma_unmap_addr(meta, mapping),
+			 dma_unmap_len(meta, len),
 			 PCI_DMA_BIDIRECTIONAL);
 
 	/* Input error checking is done when commands are added to queue. */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index a27872d..d24eb47 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -27,6 +27,8 @@
  *
  *****************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -197,6 +199,7 @@
 static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
 {
 	unsigned long flags;
+	struct iwl_addsta_cmd sta_cmd;
 
 	spin_lock_irqsave(&priv->sta_lock, flags);
 	memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
@@ -205,11 +208,11 @@
 	priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
 	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
 	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
 	IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n");
-	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0);
-	return 0;
+	return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 
 static int iwl3945_set_dynamic_key(struct iwl_priv *priv,
@@ -310,9 +313,7 @@
 				int left)
 {
 
-	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
-	    ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
-	     (priv->iw_mode != NL80211_IFTYPE_AP)))
+	if (!iwl_is_associated(priv) || !priv->ibss_beacon)
 		return 0;
 
 	if (priv->ibss_beacon->len > left)
@@ -474,10 +475,8 @@
 	u8 unicast;
 	u8 sta_id;
 	u8 tid = 0;
-	u16 seq_number = 0;
 	__le16 fc;
 	u8 wait_write_ptr = 0;
-	u8 *qc = NULL;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -510,10 +509,7 @@
 	hdr_len = ieee80211_hdrlen(fc);
 
 	/* Find index into station table for destination station */
-	if (!info->control.sta)
-		sta_id = priv->hw_params.bcast_sta_id;
-	else
-		sta_id = iwl_sta_id(info->control.sta);
+	sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
 	if (sta_id == IWL_INVALID_STATION) {
 		IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
 			       hdr->addr1);
@@ -523,16 +519,10 @@
 	IWL_DEBUG_RATE(priv, "station Id %d\n", sta_id);
 
 	if (ieee80211_is_data_qos(fc)) {
-		qc = ieee80211_get_qos_ctl(hdr);
+		u8 *qc = ieee80211_get_qos_ctl(hdr);
 		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
 		if (unlikely(tid >= MAX_TID_COUNT))
 			goto drop;
-		seq_number = priv->stations[sta_id].tid[tid].seq_number &
-				IEEE80211_SCTL_SEQ;
-		hdr->seq_ctrl = cpu_to_le16(seq_number) |
-			(hdr->seq_ctrl &
-				cpu_to_le16(IEEE80211_SCTL_FRAG));
-		seq_number += 0x10;
 	}
 
 	/* Descriptor for chosen Tx queue */
@@ -548,7 +538,7 @@
 
 	/* 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;
+	txq->txb[q->write_ptr].skb = skb;
 
 	/* Init first empty entry in queue's array of Tx/cmd buffers */
 	out_cmd = txq->cmd[idx];
@@ -591,8 +581,6 @@
 
 	if (!ieee80211_has_morefrags(hdr->frame_control)) {
 		txq->need_update = 1;
-		if (qc)
-			priv->stations[sta_id].tid[tid].seq_number = seq_number;
 	} else {
 		wait_write_ptr = 1;
 		txq->need_update = 0;
@@ -631,8 +619,8 @@
 				    len, PCI_DMA_TODEVICE);
 	/* we do not map meta data ... so we can safely access address to
 	 * provide to unmap command*/
-	pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
-	pci_unmap_len_set(out_meta, len, len);
+	dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+	dma_unmap_len_set(out_meta, len, len);
 
 	/* Add buffer containing Tx command and MAC(!) header to TFD's
 	 * first entry */
@@ -677,55 +665,6 @@
 	return -1;
 }
 
-#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 iwl3945_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 iwl3945_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 iwl3945_get_measurement(struct iwl_priv *priv,
 			       struct ieee80211_measurement_params *params,
 			       u8 type)
@@ -743,8 +682,7 @@
 	int duration = le16_to_cpu(params->duration);
 
 	if (iwl_is_associated(priv))
-		add_time =
-		    iwl3945_usecs_to_beacons(
+		add_time = iwl_usecs_to_beacons(priv,
 			le64_to_cpu(params->start_time) - priv->_3945.last_tsf,
 			le16_to_cpu(priv->rxon_timing.beacon_interval));
 
@@ -759,8 +697,8 @@
 
 	if (iwl_is_associated(priv))
 		spectrum.start_time =
-		    iwl3945_add_beacon_time(priv->_3945.last_beacon_time,
-				add_time,
+			iwl_add_beacon_time(priv,
+				priv->_3945.last_beacon_time, add_time,
 				le16_to_cpu(priv->rxon_timing.beacon_interval));
 	else
 		spectrum.start_time = 0;
@@ -1233,7 +1171,7 @@
 	}
 
 	dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
-			  rxq->dma_addr);
+			  rxq->bd_dma);
 	dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
 			  rxq->rb_stts, rxq->rb_stts_dma);
 	rxq->bd = NULL;
@@ -1314,6 +1252,8 @@
 		IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i);
 
 	while (i != r) {
+		int len;
+
 		rxb = rxq->queue[i];
 
 		/* If an RXB doesn't have a Rx queue slot associated with it,
@@ -1328,8 +1268,9 @@
 			       PCI_DMA_FROMDEVICE);
 		pkt = rxb_addr(rxb);
 
-		trace_iwlwifi_dev_rx(priv, pkt,
-			le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
+		len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+		len += sizeof(u32); /* account for status word */
+		trace_iwlwifi_dev_rx(priv, pkt, len);
 
 		/* Reclaim a command buffer only if this packet is a response
 		 *   to a (driver-originated) command.
@@ -1483,7 +1424,7 @@
 		    iwl_read_targ_mem(priv, base + i + 6 * sizeof(u32));
 
 		IWL_ERR(priv,
-			"%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
+			"%-13s (0x%X) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
 			desc_lookup(desc), desc, time, blink1, blink2,
 			ilink1, ilink2, data1);
 		trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, 0,
@@ -2942,7 +2883,10 @@
 		IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
 
 		spin_lock_irqsave(&priv->lock, flags);
-		interval = vif ? vif->bss_conf.beacon_int : 0;
+		if (priv->is_internal_short_scan)
+			interval = 0;
+		else
+			interval = vif->bss_conf.beacon_int;
 		spin_unlock_irqrestore(&priv->lock, flags);
 
 		scan->suspend_time = 0;
@@ -3022,14 +2966,16 @@
 		scan->tx_cmd.len = cpu_to_le16(
 			iwl_fill_probe_req(priv,
 				(struct ieee80211_mgmt *)scan->data,
+				vif->addr,
 				priv->scan_request->ie,
 				priv->scan_request->ie_len,
 				IWL_MAX_SCAN_SIZE - sizeof(*scan)));
 	} else {
+		/* use bcast addr, will not be transmitted but must be valid */
 		scan->tx_cmd.len = cpu_to_le16(
 			iwl_fill_probe_req(priv,
 				(struct ieee80211_mgmt *)scan->data,
-				NULL, 0,
+				iwl_bcast_addr, NULL, 0,
 				IWL_MAX_SCAN_SIZE - sizeof(*scan)));
 	}
 	/* select Rx antennas */
@@ -3158,19 +3104,16 @@
 	IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
 			vif->bss_conf.aid, vif->bss_conf.beacon_int);
 
-	if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+	if (vif->bss_conf.use_short_preamble)
 		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
 	else
 		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
 	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
-		if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+		if (vif->bss_conf.use_short_slot)
 			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
 		else
 			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
-		if (vif->type == NL80211_IFTYPE_ADHOC)
-			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 	}
 
 	iwlcore_commit_rxon(priv);
@@ -3334,8 +3277,7 @@
 
 		priv->staging_rxon.assoc_id = 0;
 
-		if (vif->bss_conf.assoc_capability &
-					WLAN_CAPABILITY_SHORT_PREAMBLE)
+		if (vif->bss_conf.use_short_preamble)
 			priv->staging_rxon.flags |=
 				RXON_FLG_SHORT_PREAMBLE_MSK;
 		else
@@ -3343,17 +3285,12 @@
 				~RXON_FLG_SHORT_PREAMBLE_MSK;
 
 		if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
-			if (vif->bss_conf.assoc_capability &
-					WLAN_CAPABILITY_SHORT_SLOT_TIME)
+			if (vif->bss_conf.use_short_slot)
 				priv->staging_rxon.flags |=
 					RXON_FLG_SHORT_SLOT_MSK;
 			else
 				priv->staging_rxon.flags &=
 					~RXON_FLG_SHORT_SLOT_MSK;
-
-			if (vif->type == NL80211_IFTYPE_ADHOC)
-				priv->staging_rxon.flags &=
-					~RXON_FLG_SHORT_SLOT_MSK;
 		}
 		/* restore RXON assoc */
 		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
@@ -3386,17 +3323,9 @@
 	static_key = !iwl_is_associated(priv);
 
 	if (!static_key) {
-		if (!sta) {
-			sta_id = priv->hw_params.bcast_sta_id;
-		} else {
-			sta_id = iwl_sta_id(sta);
-			if (sta_id == IWL_INVALID_STATION) {
-				IWL_DEBUG_MAC80211(priv,
-						   "leave - %pM not in station map.\n",
-						   sta->addr);
-				return -EINVAL;
-			}
-		}
+		sta_id = iwl_sta_id_or_broadcast(priv, sta);
+		if (sta_id == IWL_INVALID_STATION)
+			return -EINVAL;
 	}
 
 	mutex_lock(&priv->mutex);
@@ -4006,7 +3935,7 @@
 	 *   space for this driver's private structure */
 	hw = iwl_alloc_all(cfg, &iwl3945_hw_ops);
 	if (hw == NULL) {
-		printk(KERN_ERR DRV_NAME "Can not allocate network device\n");
+		pr_err("Can not allocate network device\n");
 		err = -ENOMEM;
 		goto out;
 	}
@@ -4028,9 +3957,6 @@
 	priv->pci_dev = pdev;
 	priv->inta_mask = CSR_INI_SET_MASK;
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	atomic_set(&priv->restrict_refcnt, 0);
-#endif
 	if (iwl_alloc_traffic_mem(priv))
 		IWL_ERR(priv, "Not enough memory to generate traffic log\n");
 
@@ -4099,9 +4025,8 @@
 	}
 	/* MAC Address location in EEPROM same for 3945/4965 */
 	eeprom = (struct iwl3945_eeprom *)priv->eeprom;
-	memcpy(priv->mac_addr, eeprom->mac_address, ETH_ALEN);
-	IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->mac_addr);
-	SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+	IWL_DEBUG_INFO(priv, "MAC address: %pM\n", eeprom->mac_address);
+	SET_IEEE80211_PERM_ADDR(priv->hw, eeprom->mac_address);
 
 	/***********************
 	 * 5. Setup HW Constants
@@ -4302,19 +4227,18 @@
 {
 
 	int ret;
-	printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
-	printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+	pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
+	pr_info(DRV_COPYRIGHT "\n");
 
 	ret = iwl3945_rate_control_register();
 	if (ret) {
-		printk(KERN_ERR DRV_NAME
-		       "Unable to register rate control algorithm: %d\n", ret);
+		pr_err("Unable to register rate control algorithm: %d\n", ret);
 		return ret;
 	}
 
 	ret = pci_register_driver(&iwl3945_driver);
 	if (ret) {
-		printk(KERN_ERR DRV_NAME "Unable to initialize PCI module\n");
+		pr_err("Unable to initialize PCI module\n");
 		goto error_register;
 	}
 
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 902e95f..6061967 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -670,20 +670,24 @@
 }
 
 static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
-				    enum tx_power_setting type, int dbm)
+				    enum nl80211_tx_power_setting type, int mbm)
 {
 	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
 	int ret;
 
 	switch (type) {
-	case TX_POWER_AUTOMATIC:
+	case NL80211_TX_POWER_AUTOMATIC:
 		return 0;
-	case TX_POWER_FIXED:
+	case NL80211_TX_POWER_FIXED:
+		if (mbm < 0 || (mbm % 100))
+			return -EOPNOTSUPP;
+
 		if (!test_bit(IWM_STATUS_READY, &iwm->status))
 			return 0;
 
 		ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
-					      CFG_TX_PWR_LIMIT_USR, dbm * 2);
+					      CFG_TX_PWR_LIMIT_USR,
+					      MBM_TO_DBM(mbm) * 2);
 		if (ret < 0)
 			return ret;
 
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index 7e16bcf..6421689 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -56,7 +56,7 @@
 
 struct iwm_umac_cmd_reset {
 	__le32 flags;
-} __attribute__ ((packed));
+} __packed;
 
 #define UMAC_PARAM_TBL_ORD_FIX    0x0
 #define UMAC_PARAM_TBL_ORD_VAR    0x1
@@ -220,37 +220,37 @@
 	__le16 tbl;
 	__le16 key;
 	__le32 value;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_cmd_set_param_var {
 	__le16 tbl;
 	__le16 key;
 	__le16 len;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_cmd_get_param {
 	__le16 tbl;
 	__le16 key;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_cmd_get_param_resp {
 	__le16 tbl;
 	__le16 key;
 	__le16 len;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_cmd_eeprom_proxy_hdr {
 	__le32 type;
 	__le32 offset;
 	__le32 len;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_cmd_eeprom_proxy {
 	struct iwm_umac_cmd_eeprom_proxy_hdr hdr;
 	u8 buf[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define IWM_UMAC_CMD_EEPROM_TYPE_READ       0x1
 #define IWM_UMAC_CMD_EEPROM_TYPE_WRITE      0x2
@@ -267,13 +267,13 @@
 	u8 reserved;
 	u8 flags;
 	__le32 channels_mask;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_cmd_get_channel_list {
 	__le16 count;
 	__le16 reserved;
 	struct iwm_umac_channel_info ch[0];
-} __attribute__ ((packed));
+} __packed;
 
 
 /* UMAC WiFi interface commands */
@@ -304,7 +304,7 @@
 	u8 ssid_len;
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_cmd_scan_request {
 	struct iwm_umac_wifi_if hdr;
@@ -314,7 +314,7 @@
 	u8 timeout; /* In seconds */
 	u8 reserved;
 	struct iwm_umac_ssid ssids[UMAC_WIFI_IF_PROBE_OPTION_MAX];
-} __attribute__ ((packed));
+} __packed;
 
 #define UMAC_CIPHER_TYPE_NONE		0xFF
 #define UMAC_CIPHER_TYPE_USE_GROUPCAST	0x00
@@ -357,7 +357,7 @@
 	u8 ucast_cipher;
 	u8 mcast_cipher;
 	u8 flags;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_ibss {
 	u8 beacon_interval;	/* in millisecond */
@@ -366,7 +366,7 @@
 	u8 band;
 	u8 channel;
 	u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
 
 #define UMAC_MODE_BSS	0
 #define UMAC_MODE_IBSS	1
@@ -385,13 +385,13 @@
 	__le16 flags;
 	u8 wireless_mode;
 	u8 bss_num;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_invalidate_profile {
 	struct iwm_umac_wifi_if hdr;
 	u8 reason;
 	u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
 
 /* Encryption key commands */
 struct iwm_umac_key_wep40 {
@@ -400,7 +400,7 @@
 	u8 key[WLAN_KEY_LEN_WEP40];
 	u8 static_key;
 	u8 reserved[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_key_wep104 {
 	struct iwm_umac_wifi_if hdr;
@@ -408,7 +408,7 @@
 	u8 key[WLAN_KEY_LEN_WEP104];
 	u8 static_key;
 	u8 reserved[2];
-} __attribute__ ((packed));
+} __packed;
 
 #define IWM_TKIP_KEY_SIZE 16
 #define IWM_TKIP_MIC_SIZE 8
@@ -420,7 +420,7 @@
 	u8 tkip_key[IWM_TKIP_KEY_SIZE];
 	u8 mic_rx_key[IWM_TKIP_MIC_SIZE];
 	u8 mic_tx_key[IWM_TKIP_MIC_SIZE];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_key_ccmp {
 	struct iwm_umac_wifi_if hdr;
@@ -428,27 +428,27 @@
 	u8 iv_count[6];
 	u8 reserved[2];
 	u8 key[WLAN_KEY_LEN_CCMP];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_key_remove {
 	struct iwm_umac_wifi_if hdr;
 	struct iwm_umac_key_hdr key_hdr;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_tx_key_id {
 	struct iwm_umac_wifi_if hdr;
 	u8 key_idx;
 	u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_pwr_trigger {
 	struct iwm_umac_wifi_if hdr;
 	__le32 reseved;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_cmd_stats_req {
 	__le32 flags;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_cmd_stop_resume_tx {
 	u8 flags;
@@ -456,7 +456,7 @@
 	__le16 stop_resume_tid_msk;
 	__le16 last_seq_num[IWM_UMAC_TID_NR];
 	u16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 #define IWM_CMD_PMKID_ADD   1
 #define IWM_CMD_PMKID_DEL   2
@@ -468,7 +468,7 @@
 	u8 bssid[ETH_ALEN];
 	__le16 reserved;
 	u8 pmkid[WLAN_PMKID_LEN];
-} __attribute__ ((packed));
+} __packed;
 
 /* LMAC commands */
 int iwm_read_mac(struct iwm_priv *iwm, u8 *mac);
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c
index 9531b18..907ac89 100644
--- a/drivers/net/wireless/iwmc3200wifi/hal.c
+++ b/drivers/net/wireless/iwmc3200wifi/hal.c
@@ -54,7 +54,7 @@
  *   LMAC. If you look at LMAC commands you'll se that they
  *   are actually regular iwlwifi target commands encapsulated
  *   into a special UMAC command called UMAC passthrough.
- *   This is due to the fact the the host talks exclusively
+ *   This is due to the fact the host talks exclusively
  *   to the UMAC and so there needs to be a special UMAC
  *   command for talking to the LMAC.
  *   This is how a wifi command is layed out:
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 13266c3..51d7efa 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -162,7 +162,7 @@
 	u8 mac[ETH_ALEN];
 	u8 key_idx;
 	u8 multicast; /* BCast encrypt & BCast decrypt of frames FROM mac */
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_key {
 	struct iwm_umac_key_hdr hdr;
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
index a855a99..5ddcdf8 100644
--- a/drivers/net/wireless/iwmc3200wifi/lmac.h
+++ b/drivers/net/wireless/iwmc3200wifi/lmac.h
@@ -43,7 +43,7 @@
 	u8 id;
 	u8 flags;
 	__le16 seq_num;
-} __attribute__ ((packed));
+} __packed;
 
 /* LMAC commands */
 #define CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK  0x1
@@ -54,23 +54,23 @@
 	__le32 send_res; /* 1 for sending back results */
 	__le32 apply_res; /* 1 for applying calibration results to HW */
 	__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_lmac_cal_cfg_status {
 	struct iwm_lmac_cal_cfg_elt init;
 	struct iwm_lmac_cal_cfg_elt periodic;
 	__le32 flags; /* CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK */
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_lmac_cal_cfg_cmd {
 	struct iwm_lmac_cal_cfg_status ucode_cfg;
 	struct iwm_lmac_cal_cfg_status driver_cfg;
 	__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_lmac_cal_cfg_resp {
 	__le32 status;
-} __attribute__ ((packed));
+} __packed;
 
 #define IWM_CARD_STATE_SW_HW_ENABLED	0x00
 #define IWM_CARD_STATE_HW_DISABLED	0x01
@@ -80,7 +80,7 @@
 
 struct iwm_lmac_card_state {
 	__le32 flags;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * COEX_PRIORITY_TABLE_CMD
@@ -131,7 +131,7 @@
 	u8 win_med_prio;
 	u8 reserved;
 	u8 flags;
-} __attribute__ ((packed));
+} __packed;
 
 #define COEX_FLAGS_STA_TABLE_VALID_MSK		0x1
 #define COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK	0x4
@@ -142,7 +142,7 @@
 	u8 flags;
 	u8 reserved[3];
 	struct coex_event sta_prio[COEX_EVENTS_NUM];
-} __attribute__ ((packed));
+} __packed;
 
 /* Coexistence definitions
  *
@@ -192,7 +192,7 @@
 	u32 exit_threshold;
 	u32 reserved;
 	u32 entry_threshold;
-} __attribute__ ((packed));
+} __packed;
 
 
 /* LMAC OP CODES */
@@ -428,7 +428,7 @@
 	u8 first_grp;
 	u8 grp_num;
 	u8 all_data_valid;
-} __attribute__ ((packed));
+} __packed;
 
 #define IWM_LMAC_CALIB_FREQ_GROUPS_NR	7
 #define IWM_CALIB_FREQ_GROUPS_NR	5
@@ -437,20 +437,20 @@
 struct iwm_calib_rxiq_entry {
 	u16 ptam_postdist_ars;
 	u16 ptam_postdist_arc;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_calib_rxiq_group {
 	struct iwm_calib_rxiq_entry mode[IWM_CALIB_DC_MODES_NR];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_lmac_calib_rxiq {
 	struct iwm_calib_rxiq_group group[IWM_LMAC_CALIB_FREQ_GROUPS_NR];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_calib_rxiq {
 	struct iwm_lmac_calib_hdr hdr;
 	struct iwm_calib_rxiq_group group[IWM_CALIB_FREQ_GROUPS_NR];
-} __attribute__ ((packed));
+} __packed;
 
 #define LMAC_STA_ID_SEED	0x0f
 #define LMAC_STA_ID_POS		0
@@ -463,7 +463,7 @@
 	u8 pa_integ_res_A[3];
 	u8 pa_integ_res_B[3];
 	u8 pa_integ_res_C[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_lmac_tx_resp {
 	u8 frame_cnt; /* 1-no aggregation, greater then 1 - aggregation */
@@ -479,6 +479,6 @@
 	u8 ra_tid;
 	__le16 frame_ctl;
 	__le32 status;
-} __attribute__ ((packed));
+} __packed;
 
 #endif
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index e1184de..c02fced 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -321,14 +321,14 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
-	ticket_node->ticket = kzalloc(sizeof(struct iwm_rx_ticket), GFP_KERNEL);
+	ticket_node->ticket = kmemdup(ticket, sizeof(struct iwm_rx_ticket),
+				      GFP_KERNEL);
 	if (!ticket_node->ticket) {
 		IWM_ERR(iwm, "Couldn't allocate RX ticket\n");
 		kfree(ticket_node);
 		return ERR_PTR(-ENOMEM);
 	}
 
-	memcpy(ticket_node->ticket, ticket, sizeof(struct iwm_rx_ticket));
 	INIT_LIST_HEAD(&ticket_node->node);
 
 	return ticket_node;
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
index 0cbba3e..4a137d3 100644
--- a/drivers/net/wireless/iwmc3200wifi/umac.h
+++ b/drivers/net/wireless/iwmc3200wifi/umac.h
@@ -42,19 +42,19 @@
 struct iwm_udma_in_hdr {
 	__le32 cmd;
 	__le32 size;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_udma_out_nonwifi_hdr {
 	__le32 cmd;
 	__le32 addr;
 	__le32 op1_sz;
 	__le32 op2;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_udma_out_wifi_hdr {
 	__le32 cmd;
 	__le32 meta_data;
-} __attribute__ ((packed));
+} __packed;
 
 /* Sequence numbering */
 #define UMAC_WIFI_SEQ_NUM_BASE		1
@@ -408,12 +408,12 @@
 	__le16 flags;
 	u8 payload_offset; /* includes: MAC header, pad, IV */
 	u8 tail_len; /* includes: MIC, ICV, CRC (w/o STATUS) */
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_rx_mpdu_hdr {
 	__le16 len;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 /* UMAC SW WIFI API */
 
@@ -421,31 +421,31 @@
 	u8 cmd;
 	u8 flags;
 	__le16 seq_num;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_fw_cmd_hdr {
 	__le32 meta_data;
 	struct iwm_dev_cmd_hdr cmd;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_wifi_out_hdr {
 	struct iwm_udma_out_wifi_hdr hw_hdr;
 	struct iwm_umac_fw_cmd_hdr sw_hdr;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_nonwifi_out_hdr {
 	struct iwm_udma_out_nonwifi_hdr hw_hdr;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_wifi_in_hdr {
 	struct iwm_udma_in_hdr hw_hdr;
 	struct iwm_umac_fw_cmd_hdr sw_hdr;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_nonwifi_in_hdr {
 	struct iwm_udma_in_hdr hw_hdr;
 	__le32 time_stamp;
-} __attribute__ ((packed));
+} __packed;
 
 #define IWM_UMAC_PAGE_SIZE	0x200
 
@@ -521,7 +521,7 @@
 	u8 status;
 	u8 flags;
 	__le16 buf_size;
-} __attribute__ ((packed));
+} __packed;
 
 #define UMAC_ROAM_REASON_FIRST_SELECTION	0x1
 #define UMAC_ROAM_REASON_AP_DEAUTH		0x2
@@ -535,7 +535,7 @@
 	__le32 roam_reason;
 	u8 bssid[ETH_ALEN];
 	u8 reserved[2];
-} __attribute__ ((packed));
+} __packed;
 
 #define UMAC_ASSOC_COMPLETE_SUCCESS		0x0
 #define UMAC_ASSOC_COMPLETE_FAILURE		0x1
@@ -546,7 +546,7 @@
 	u8 bssid[ETH_ALEN];
 	u8 band;
 	u8 channel;
-} __attribute__ ((packed));
+} __packed;
 
 #define UMAC_PROFILE_INVALID_ASSOC_TIMEOUT	0x0
 #define UMAC_PROFILE_INVALID_ROAM_TIMEOUT	0x1
@@ -556,7 +556,7 @@
 struct iwm_umac_notif_profile_invalidate {
 	struct iwm_umac_notif_wifi_if mlme_hdr;
 	__le32 reason;
-} __attribute__ ((packed));
+} __packed;
 
 #define UMAC_SCAN_RESULT_SUCCESS  0x0
 #define UMAC_SCAN_RESULT_ABORTED  0x1
@@ -568,7 +568,7 @@
 	__le32 type;
 	__le32 result;
 	u8 seq_num;
-} __attribute__ ((packed));
+} __packed;
 
 #define UMAC_OPCODE_ADD_MODIFY	0x0
 #define UMAC_OPCODE_REMOVE	0x1
@@ -582,7 +582,7 @@
 	u8 mac_addr[ETH_ALEN];
 	u8 sta_id; /* bits 0-3: station ID, bits 4-7: station color */
 	u8 flags;
-} __attribute__ ((packed));
+} __packed;
 
 #define UMAC_BAND_2GHZ 0
 #define UMAC_BAND_5GHZ 1
@@ -601,7 +601,7 @@
 	s8 rssi;
 	u8 reserved;
 	u8 frame_buf[1];
-} __attribute__ ((packed));
+} __packed;
 
 #define IWM_BSS_REMOVE_INDEX_MSK           0x0fff
 #define IWM_BSS_REMOVE_FLAGS_MSK           0xfc00
@@ -614,13 +614,13 @@
 	struct iwm_umac_notif_wifi_if mlme_hdr;
 	__le32 count;
 	__le16 entries[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_notif_mgt_frame {
 	struct iwm_umac_notif_wifi_if mlme_hdr;
 	__le16 len;
 	u8 frame[1];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_notif_alive {
 	struct iwm_umac_wifi_in_hdr hdr;
@@ -630,13 +630,13 @@
 	__le16 reserved2;
 	__le16 page_grp_count;
 	__le32 page_grp_state[IWM_MACS_OUT_GROUPS];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_notif_init_complete {
 	struct iwm_umac_wifi_in_hdr hdr;
 	__le16 status;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 /* error categories */
 enum {
@@ -667,12 +667,12 @@
 	__le32 dbm_buf_end;
 	__le32 dbm_buf_write_ptr;
 	__le32 dbm_buf_cycle_cnt;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_notif_error {
 	struct iwm_umac_wifi_in_hdr hdr;
 	struct iwm_fw_error_hdr err;
-} __attribute__ ((packed));
+} __packed;
 
 #define UMAC_DEALLOC_NTFY_CHANGES_CNT_POS	0
 #define UMAC_DEALLOC_NTFY_CHANGES_CNT_SEED	0xff
@@ -687,20 +687,20 @@
 	struct iwm_umac_wifi_in_hdr hdr;
 	__le32 changes;
 	__le32 grp_info[IWM_MACS_OUT_GROUPS];
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_notif_wifi_status {
 	struct iwm_umac_wifi_in_hdr hdr;
 	__le16 status;
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct iwm_umac_notif_rx_ticket {
 	struct iwm_umac_wifi_in_hdr hdr;
 	u8 num_tickets;
 	u8 reserved[3];
 	struct iwm_rx_ticket tickets[1];
-} __attribute__ ((packed));
+} __packed;
 
 /* Tx/Rx rates window (number of max of last update window per second) */
 #define UMAC_NTF_RATE_SAMPLE_NR	4
@@ -758,7 +758,7 @@
 	__le32 roam_unassoc;
 	__le32 roam_deauth;
 	__le32 roam_ap_loadblance;
-} __attribute__ ((packed));
+} __packed;
 
 #define UMAC_STOP_TX_FLAG    0x1
 #define UMAC_RESUME_TX_FLAG  0x2
@@ -770,7 +770,7 @@
 	u8 flags; /* UMAC_*_TX_FLAG_* */
 	u8 sta_id;
 	__le16 stop_resume_tid_msk; /* tid bitmask */
-} __attribute__ ((packed));
+} __packed;
 
 #define UMAC_MAX_NUM_PMKIDS 4
 
@@ -779,7 +779,7 @@
 	u8 oid;
 	u8 flags;
 	__le16 buf_size;
-} __attribute__ ((packed));
+} __packed;
 
 #define IWM_SEQ_NUM_HOST_MSK	0x0000
 #define IWM_SEQ_NUM_UMAC_MSK	0x4000
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index 45e870e..f7d01bf 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -1,4 +1,3 @@
-libertas-y += assoc.o
 libertas-y += cfg.o
 libertas-y += cmd.o
 libertas-y += cmdresp.o
@@ -6,9 +5,7 @@
 libertas-y += ethtool.o
 libertas-y += main.o
 libertas-y += rx.o
-libertas-y += scan.o
 libertas-y += tx.o
-libertas-y += wext.o
 libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o
 
 usb8xxx-objs += if_usb.o
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index 2726c04..60fd1af 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -226,6 +226,18 @@
     All entries in the scan table (not just the new scan data when keep=1)
     will be displayed upon completion by use of the getscantable ioctl.
 
+hostsleep
+	This command is used to enable/disable host sleep.
+	Note: Host sleep parameters should be configured using
+	"ethtool -s ethX wol X" command before enabling host sleep.
+
+	Path: /sys/kernel/debug/libertas_wireless/ethX/
+
+	Usage:
+		cat hostsleep: reads the current hostsleep state
+		echo "1" > hostsleep : enable host sleep.
+		echo "0" > hostsleep : disable host sleep
+
 ========================
 IWCONFIG COMMANDS
 ========================
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
deleted file mode 100644
index aa06070e..0000000
--- a/drivers/net/wireless/libertas/assoc.c
+++ /dev/null
@@ -1,2264 +0,0 @@
-/* Copyright (C) 2006, Red Hat, Inc. */
-
-#include <linux/types.h>
-#include <linux/etherdevice.h>
-#include <linux/ieee80211.h>
-#include <linux/if_arp.h>
-#include <linux/slab.h>
-#include <net/lib80211.h>
-
-#include "assoc.h"
-#include "decl.h"
-#include "host.h"
-#include "scan.h"
-#include "cmd.h"
-
-static const u8 bssid_any[ETH_ALEN]  __attribute__ ((aligned (2))) =
-	{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-static const u8 bssid_off[ETH_ALEN]  __attribute__ ((aligned (2))) =
-	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-/* The firmware needs the following bits masked out of the beacon-derived
- * capability field when associating/joining to a BSS:
- *  9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
- */
-#define CAPINFO_MASK	(~(0xda00))
-
-/**
- * 802.11b/g supported bitrates (in 500Kb/s units)
- */
-u8 lbs_bg_rates[MAX_RATES] =
-    { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0x00, 0x00 };
-
-
-static int assoc_helper_wep_keys(struct lbs_private *priv,
-		struct assoc_request *assoc_req);
-
-/**
- *  @brief This function finds common rates between rates and card rates.
- *
- * It will fill common rates in rates as output if found.
- *
- * NOTE: Setting the MSB of the basic rates need to be taken
- *   care, either before or after calling this function
- *
- *  @param priv     A pointer to struct lbs_private structure
- *  @param rates       the buffer which keeps input and output
- *  @param rates_size  the size of rates buffer; new size of buffer on return,
- *                     which will be less than or equal to original rates_size
- *
- *  @return            0 on success, or -1 on error
- */
-static int get_common_rates(struct lbs_private *priv,
-	u8 *rates,
-	u16 *rates_size)
-{
-	int i, j;
-	u8 intersection[MAX_RATES];
-	u16 intersection_size;
-	u16 num_rates = 0;
-
-	intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection));
-
-	/* Allow each rate from 'rates' that is supported by the hardware */
-	for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) {
-		for (j = 0; j < intersection_size && rates[j]; j++) {
-			if (rates[j] == lbs_bg_rates[i])
-				intersection[num_rates++] = rates[j];
-		}
-	}
-
-	lbs_deb_hex(LBS_DEB_JOIN, "AP rates    ", rates, *rates_size);
-	lbs_deb_hex(LBS_DEB_JOIN, "card rates  ", lbs_bg_rates,
-			ARRAY_SIZE(lbs_bg_rates));
-	lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates);
-	lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
-
-	if (!priv->enablehwauto) {
-		for (i = 0; i < num_rates; i++) {
-			if (intersection[i] == priv->cur_rate)
-				goto done;
-		}
-		lbs_pr_alert("Previously set fixed data rate %#x isn't "
-		       "compatible with the network.\n", priv->cur_rate);
-		return -1;
-	}
-
-done:
-	memset(rates, 0, *rates_size);
-	*rates_size = num_rates;
-	memcpy(rates, intersection, num_rates);
-	return 0;
-}
-
-
-/**
- *  @brief Sets the MSB on basic rates as the firmware requires
- *
- * Scan through an array and set the MSB for basic data rates.
- *
- *  @param rates     buffer of data rates
- *  @param len       size of buffer
- */
-static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
-{
-	int i;
-
-	for (i = 0; i < len; i++) {
-		if (rates[i] == 0x02 || rates[i] == 0x04 ||
-		    rates[i] == 0x0b || rates[i] == 0x16)
-			rates[i] |= 0x80;
-	}
-}
-
-
-static u8 iw_auth_to_ieee_auth(u8 auth)
-{
-	if (auth == IW_AUTH_ALG_OPEN_SYSTEM)
-		return 0x00;
-	else if (auth == IW_AUTH_ALG_SHARED_KEY)
-		return 0x01;
-	else if (auth == IW_AUTH_ALG_LEAP)
-		return 0x80;
-
-	lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth);
-	return 0;
-}
-
-/**
- *  @brief This function prepares the authenticate command.  AUTHENTICATE only
- *  sets the authentication suite for future associations, as the firmware
- *  handles authentication internally during the ASSOCIATE command.
- *
- *  @param priv      A pointer to struct lbs_private structure
- *  @param bssid     The peer BSSID with which to authenticate
- *  @param auth      The authentication mode to use (from wireless.h)
- *
- *  @return         0 or -1
- */
-static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth)
-{
-	struct cmd_ds_802_11_authenticate cmd;
-	int ret = -1;
-
-	lbs_deb_enter(LBS_DEB_JOIN);
-
-	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-	memcpy(cmd.bssid, bssid, ETH_ALEN);
-
-	cmd.authtype = iw_auth_to_ieee_auth(auth);
-
-	lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype);
-
-	ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
-
-	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
-	return ret;
-}
-
-
-int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
-			   struct assoc_request *assoc)
-{
-	struct cmd_ds_802_11_set_wep cmd;
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
-	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
-	cmd.action = cpu_to_le16(cmd_action);
-
-	if (cmd_action == CMD_ACT_ADD) {
-		int i;
-
-		/* default tx key index */
-		cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
-					   CMD_WEP_KEY_INDEX_MASK);
-
-		/* Copy key types and material to host command structure */
-		for (i = 0; i < 4; i++) {
-			struct enc_key *pkey = &assoc->wep_keys[i];
-
-			switch (pkey->len) {
-			case KEY_LEN_WEP_40:
-				cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
-				memmove(cmd.keymaterial[i], pkey->key, pkey->len);
-				lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
-				break;
-			case KEY_LEN_WEP_104:
-				cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
-				memmove(cmd.keymaterial[i], pkey->key, pkey->len);
-				lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
-				break;
-			case 0:
-				break;
-			default:
-				lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
-					    i, pkey->len);
-				ret = -1;
-				goto done;
-				break;
-			}
-		}
-	} else if (cmd_action == CMD_ACT_REMOVE) {
-		/* ACT_REMOVE clears _all_ WEP keys */
-
-		/* default tx key index */
-		cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
-					   CMD_WEP_KEY_INDEX_MASK);
-		lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
-	}
-
-	ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
-done:
-	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-	return ret;
-}
-
-int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
-			      uint16_t *enable)
-{
-	struct cmd_ds_802_11_enable_rsn cmd;
-	int ret;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-	cmd.action = cpu_to_le16(cmd_action);
-
-	if (cmd_action == CMD_ACT_GET)
-		cmd.enable = 0;
-	else {
-		if (*enable)
-			cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
-		else
-			cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
-		lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
-	}
-
-	ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
-	if (!ret && cmd_action == CMD_ACT_GET)
-		*enable = le16_to_cpu(cmd.enable);
-
-	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-	return ret;
-}
-
-static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
-		struct enc_key *key)
-{
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	if (key->flags & KEY_INFO_WPA_ENABLED)
-		keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
-	if (key->flags & KEY_INFO_WPA_UNICAST)
-		keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
-	if (key->flags & KEY_INFO_WPA_MCAST)
-		keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
-
-	keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
-	keyparam->keytypeid = cpu_to_le16(key->type);
-	keyparam->keylen = cpu_to_le16(key->len);
-	memcpy(keyparam->key, key->key, key->len);
-
-	/* Length field doesn't include the {type,length} header */
-	keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
-	lbs_deb_leave(LBS_DEB_CMD);
-}
-
-int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
-				struct assoc_request *assoc)
-{
-	struct cmd_ds_802_11_key_material cmd;
-	int ret = 0;
-	int index = 0;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	cmd.action = cpu_to_le16(cmd_action);
-	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
-	if (cmd_action == CMD_ACT_GET) {
-		cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_header) + 2);
-	} else {
-		memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
-
-		if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
-			set_one_wpa_key(&cmd.keyParamSet[index],
-					&assoc->wpa_unicast_key);
-			index++;
-		}
-
-		if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
-			set_one_wpa_key(&cmd.keyParamSet[index],
-					&assoc->wpa_mcast_key);
-			index++;
-		}
-
-		/* The common header and as many keys as we included */
-		cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
-						    keyParamSet[index]));
-	}
-	ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
-	/* Copy the returned key to driver private data */
-	if (!ret && cmd_action == CMD_ACT_GET) {
-		void *buf_ptr = cmd.keyParamSet;
-		void *resp_end = &(&cmd)[1];
-
-		while (buf_ptr < resp_end) {
-			struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
-			struct enc_key *key;
-			uint16_t param_set_len = le16_to_cpu(keyparam->length);
-			uint16_t key_len = le16_to_cpu(keyparam->keylen);
-			uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
-			uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
-			void *end;
-
-			end = (void *)keyparam + sizeof(keyparam->type)
-				+ sizeof(keyparam->length) + param_set_len;
-
-			/* Make sure we don't access past the end of the IEs */
-			if (end > resp_end)
-				break;
-
-			if (key_flags & KEY_INFO_WPA_UNICAST)
-				key = &priv->wpa_unicast_key;
-			else if (key_flags & KEY_INFO_WPA_MCAST)
-				key = &priv->wpa_mcast_key;
-			else
-				break;
-
-			/* Copy returned key into driver */
-			memset(key, 0, sizeof(struct enc_key));
-			if (key_len > sizeof(key->key))
-				break;
-			key->type = key_type;
-			key->flags = key_flags;
-			key->len = key_len;
-			memcpy(key->key, keyparam->key, key->len);
-
-			buf_ptr = end + 1;
-		}
-	}
-
-	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-	return ret;
-}
-
-static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
-{
-/*		Bit  	Rate
-*		15:13 Reserved
-*		12    54 Mbps
-*		11    48 Mbps
-*		10    36 Mbps
-*		9     24 Mbps
-*		8     18 Mbps
-*		7     12 Mbps
-*		6     9 Mbps
-*		5     6 Mbps
-*		4     Reserved
-*		3     11 Mbps
-*		2     5.5 Mbps
-*		1     2 Mbps
-*		0     1 Mbps
-**/
-
-	uint16_t ratemask;
-	int i = lbs_data_rate_to_fw_index(rate);
-	if (lower_rates_ok)
-		ratemask = (0x1fef >> (12 - i));
-	else
-		ratemask = (1 << i);
-	return cpu_to_le16(ratemask);
-}
-
-int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
-				      uint16_t cmd_action)
-{
-	struct cmd_ds_802_11_rate_adapt_rateset cmd;
-	int ret;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	if (!priv->cur_rate && !priv->enablehwauto)
-		return -EINVAL;
-
-	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
-	cmd.action = cpu_to_le16(cmd_action);
-	cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
-	cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
-	ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
-	if (!ret && cmd_action == CMD_ACT_GET)
-		priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
-
-	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-	return ret;
-}
-
-/**
- *  @brief Set the data rate
- *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param rate  	The desired data rate, or 0 to clear a locked rate
- *
- *  @return 	   	0 on success, error on failure
- */
-int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
-{
-	struct cmd_ds_802_11_data_rate cmd;
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
-	if (rate > 0) {
-		cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
-		cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
-		if (cmd.rates[0] == 0) {
-			lbs_deb_cmd("DATA_RATE: invalid requested rate of"
-				" 0x%02X\n", rate);
-			ret = 0;
-			goto out;
-		}
-		lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
-	} else {
-		cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
-		lbs_deb_cmd("DATA_RATE: setting auto\n");
-	}
-
-	ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
-	if (ret)
-		goto out;
-
-	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof(cmd));
-
-	/* FIXME: get actual rates FW can do if this command actually returns
-	 * all data rates supported.
-	 */
-	priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
-	lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
-
-out:
-	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-	return ret;
-}
-
-
-int lbs_cmd_802_11_rssi(struct lbs_private *priv,
-				struct cmd_ds_command *cmd)
-{
-
-	lbs_deb_enter(LBS_DEB_CMD);
-	cmd->command = cpu_to_le16(CMD_802_11_RSSI);
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) +
-		sizeof(struct cmd_header));
-	cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
-
-	/* reset Beacon SNR/NF/RSSI values */
-	priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
-	priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
-	priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
-	priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
-	priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
-	priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
-
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
-}
-
-int lbs_ret_802_11_rssi(struct lbs_private *priv,
-				struct cmd_ds_command *resp)
-{
-	struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	/* store the non average value */
-	priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
-	priv->NF[TYPE_BEACON][TYPE_NOAVG] =
-		get_unaligned_le16(&rssirsp->noisefloor);
-
-	priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
-	priv->NF[TYPE_BEACON][TYPE_AVG] =
-		get_unaligned_le16(&rssirsp->avgnoisefloor);
-
-	priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
-	    CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
-		     priv->NF[TYPE_BEACON][TYPE_NOAVG]);
-
-	priv->RSSI[TYPE_BEACON][TYPE_AVG] =
-	    CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
-		     priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
-
-	lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
-	       priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
-	       priv->RSSI[TYPE_BEACON][TYPE_AVG]);
-
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
-}
-
-
-int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
-				struct cmd_ds_command *cmd,
-				u16 cmd_action)
-{
-	struct cmd_ds_802_11_beacon_control
-		*bcn_ctrl = &cmd->params.bcn_ctrl;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-	cmd->size =
-	    cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
-			     + sizeof(struct cmd_header));
-	cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
-
-	bcn_ctrl->action = cpu_to_le16(cmd_action);
-	bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
-	bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
-
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
-}
-
-int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
-					struct cmd_ds_command *resp)
-{
-	struct cmd_ds_802_11_beacon_control *bcn_ctrl =
-	    &resp->params.bcn_ctrl;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	if (bcn_ctrl->action == CMD_ACT_GET) {
-		priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
-		priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
-	}
-
-	lbs_deb_enter(LBS_DEB_CMD);
-	return 0;
-}
-
-
-
-static int lbs_assoc_post(struct lbs_private *priv,
-			  struct cmd_ds_802_11_associate_response *resp)
-{
-	int ret = 0;
-	union iwreq_data wrqu;
-	struct bss_descriptor *bss;
-	u16 status_code;
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	if (!priv->in_progress_assoc_req) {
-		lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
-		ret = -1;
-		goto done;
-	}
-	bss = &priv->in_progress_assoc_req->bss;
-
-	/*
-	 * Older FW versions map the IEEE 802.11 Status Code in the association
-	 * response to the following values returned in resp->statuscode:
-	 *
-	 *    IEEE Status Code                Marvell Status Code
-	 *    0                       ->      0x0000 ASSOC_RESULT_SUCCESS
-	 *    13                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
-	 *    14                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
-	 *    15                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
-	 *    16                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
-	 *    others                  ->      0x0003 ASSOC_RESULT_REFUSED
-	 *
-	 * Other response codes:
-	 *    0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
-	 *    0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
-	 *                                    association response from the AP)
-	 */
-
-	status_code = le16_to_cpu(resp->statuscode);
-	if (priv->fwrelease < 0x09000000) {
-		switch (status_code) {
-		case 0x00:
-			break;
-		case 0x01:
-			lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
-			break;
-		case 0x02:
-			lbs_deb_assoc("ASSOC_RESP: internal timer "
-				"expired while waiting for the AP\n");
-			break;
-		case 0x03:
-			lbs_deb_assoc("ASSOC_RESP: association "
-				"refused by AP\n");
-			break;
-		case 0x04:
-			lbs_deb_assoc("ASSOC_RESP: authentication "
-				"refused by AP\n");
-			break;
-		default:
-			lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
-				" unknown\n", status_code);
-			break;
-		}
-	} else {
-		/* v9+ returns the AP's association response */
-		lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code);
-	}
-
-	if (status_code) {
-		lbs_mac_event_disconnected(priv);
-		ret = status_code;
-		goto done;
-	}
-
-	lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP",
-		    (void *) (resp + sizeof (resp->hdr)),
-		    le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr));
-
-	/* Send a Media Connected event, according to the Spec */
-	priv->connect_status = LBS_CONNECTED;
-
-	/* Update current SSID and BSSID */
-	memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
-	priv->curbssparams.ssid_len = bss->ssid_len;
-	memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
-
-	priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
-	priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
-
-	memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
-	memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
-	priv->nextSNRNF = 0;
-	priv->numSNRNF = 0;
-
-	netif_carrier_on(priv->dev);
-	if (!priv->tx_pending_len)
-		netif_wake_queue(priv->dev);
-
-	memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
-	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-
-done:
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-/**
- *  @brief This function prepares an association-class command.
- *
- *  @param priv      A pointer to struct lbs_private structure
- *  @param assoc_req The association request describing the BSS to associate
- *                   or reassociate with
- *  @param command   The actual command, either CMD_802_11_ASSOCIATE or
- *                   CMD_802_11_REASSOCIATE
- *
- *  @return         0 or -1
- */
-static int lbs_associate(struct lbs_private *priv,
-			 struct assoc_request *assoc_req,
-			 u16 command)
-{
-	struct cmd_ds_802_11_associate cmd;
-	int ret = 0;
-	struct bss_descriptor *bss = &assoc_req->bss;
-	u8 *pos = &(cmd.iebuf[0]);
-	u16 tmpcap, tmplen, tmpauth;
-	struct mrvl_ie_ssid_param_set *ssid;
-	struct mrvl_ie_ds_param_set *ds;
-	struct mrvl_ie_cf_param_set *cf;
-	struct mrvl_ie_rates_param_set *rates;
-	struct mrvl_ie_rsn_param_set *rsn;
-	struct mrvl_ie_auth_type *auth;
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	BUG_ON((command != CMD_802_11_ASSOCIATE) &&
-		(command != CMD_802_11_REASSOCIATE));
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.hdr.command = cpu_to_le16(command);
-
-	/* Fill in static fields */
-	memcpy(cmd.bssid, bss->bssid, ETH_ALEN);
-	cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
-
-	/* Capability info */
-	tmpcap = (bss->capability & CAPINFO_MASK);
-	if (bss->mode == IW_MODE_INFRA)
-		tmpcap |= WLAN_CAPABILITY_ESS;
-	cmd.capability = cpu_to_le16(tmpcap);
-	lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
-
-	/* SSID */
-	ssid = (struct mrvl_ie_ssid_param_set *) pos;
-	ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
-	tmplen = bss->ssid_len;
-	ssid->header.len = cpu_to_le16(tmplen);
-	memcpy(ssid->ssid, bss->ssid, tmplen);
-	pos += sizeof(ssid->header) + tmplen;
-
-	ds = (struct mrvl_ie_ds_param_set *) pos;
-	ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
-	ds->header.len = cpu_to_le16(1);
-	ds->channel = bss->phy.ds.channel;
-	pos += sizeof(ds->header) + 1;
-
-	cf = (struct mrvl_ie_cf_param_set *) pos;
-	cf->header.type = cpu_to_le16(TLV_TYPE_CF);
-	tmplen = sizeof(*cf) - sizeof (cf->header);
-	cf->header.len = cpu_to_le16(tmplen);
-	/* IE payload should be zeroed, firmware fills it in for us */
-	pos += sizeof(*cf);
-
-	rates = (struct mrvl_ie_rates_param_set *) pos;
-	rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
-	tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES);
-	memcpy(&rates->rates, &bss->rates, tmplen);
-	if (get_common_rates(priv, rates->rates, &tmplen)) {
-		ret = -1;
-		goto done;
-	}
-	pos += sizeof(rates->header) + tmplen;
-	rates->header.len = cpu_to_le16(tmplen);
-	lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
-
-	/* Copy the infra. association rates into Current BSS state structure */
-	memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
-	memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
-
-	/* Set MSB on basic rates as the firmware requires, but _after_
-	 * copying to current bss rates.
-	 */
-	lbs_set_basic_rate_flags(rates->rates, tmplen);
-
-	/* Firmware v9+ indicate authentication suites as a TLV */
-	if (priv->fwrelease >= 0x09000000) {
-		auth = (struct mrvl_ie_auth_type *) pos;
-		auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
-		auth->header.len = cpu_to_le16(2);
-		tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode);
-		auth->auth = cpu_to_le16(tmpauth);
-		pos += sizeof(auth->header) + 2;
-
-		lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
-			bss->bssid, priv->secinfo.auth_mode);
-	}
-
-	/* WPA/WPA2 IEs */
-	if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
-		rsn = (struct mrvl_ie_rsn_param_set *) pos;
-		/* WPA_IE or WPA2_IE */
-		rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
-		tmplen = (u16) assoc_req->wpa_ie[1];
-		rsn->header.len = cpu_to_le16(tmplen);
-		memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
-		lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn,
-			sizeof(rsn->header) + tmplen);
-		pos += sizeof(rsn->header) + tmplen;
-	}
-
-	cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) +
-				   (u16)(pos - (u8 *) &cmd.iebuf));
-
-	/* update curbssparams */
-	priv->channel = bss->phy.ds.channel;
-
-	ret = lbs_cmd_with_response(priv, command, &cmd);
-	if (ret == 0) {
-		ret = lbs_assoc_post(priv,
-			(struct cmd_ds_802_11_associate_response *) &cmd);
-	}
-
-done:
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-/**
- *  @brief Associate to a specific BSS discovered in a scan
- *
- *  @param priv      A pointer to struct lbs_private structure
- *  @param assoc_req The association request describing the BSS to associate with
- *
- *  @return          0-success, otherwise fail
- */
-static int lbs_try_associate(struct lbs_private *priv,
-	struct assoc_request *assoc_req)
-{
-	int ret;
-	u8 preamble = RADIO_PREAMBLE_LONG;
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	/* FW v9 and higher indicate authentication suites as a TLV in the
-	 * association command, not as a separate authentication command.
-	 */
-	if (priv->fwrelease < 0x09000000) {
-		ret = lbs_set_authentication(priv, assoc_req->bss.bssid,
-					     priv->secinfo.auth_mode);
-		if (ret)
-			goto out;
-	}
-
-	/* Use short preamble only when both the BSS and firmware support it */
-	if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
-		preamble = RADIO_PREAMBLE_SHORT;
-
-	ret = lbs_set_radio(priv, preamble, 1);
-	if (ret)
-		goto out;
-
-	ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE);
-	/* If the association fails with current auth mode, let's
-	 * try by changing the auth mode
-	 */
-	if ((priv->authtype_auto) &&
-			(ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) &&
-			(assoc_req->secinfo.wep_enabled) &&
-			(priv->connect_status != LBS_CONNECTED)) {
-		if (priv->secinfo.auth_mode == IW_AUTH_ALG_OPEN_SYSTEM)
-			priv->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
-		else
-			priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-		if (!assoc_helper_wep_keys(priv, assoc_req))
-			ret = lbs_associate(priv, assoc_req,
-						CMD_802_11_ASSOCIATE);
-	}
-
-	if (ret)
-		ret = -1;
-out:
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-static int lbs_adhoc_post(struct lbs_private *priv,
-			  struct cmd_ds_802_11_ad_hoc_result *resp)
-{
-	int ret = 0;
-	u16 command = le16_to_cpu(resp->hdr.command);
-	u16 result = le16_to_cpu(resp->hdr.result);
-	union iwreq_data wrqu;
-	struct bss_descriptor *bss;
-	DECLARE_SSID_BUF(ssid);
-
-	lbs_deb_enter(LBS_DEB_JOIN);
-
-	if (!priv->in_progress_assoc_req) {
-		lbs_deb_join("ADHOC_RESP: no in-progress association "
-			"request\n");
-		ret = -1;
-		goto done;
-	}
-	bss = &priv->in_progress_assoc_req->bss;
-
-	/*
-	 * Join result code 0 --> SUCCESS
-	 */
-	if (result) {
-		lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result);
-		if (priv->connect_status == LBS_CONNECTED)
-			lbs_mac_event_disconnected(priv);
-		ret = -1;
-		goto done;
-	}
-
-	/* Send a Media Connected event, according to the Spec */
-	priv->connect_status = LBS_CONNECTED;
-
-	if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
-		/* Update the created network descriptor with the new BSSID */
-		memcpy(bss->bssid, resp->bssid, ETH_ALEN);
-	}
-
-	/* Set the BSSID from the joined/started descriptor */
-	memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
-
-	/* Set the new SSID to current SSID */
-	memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
-	priv->curbssparams.ssid_len = bss->ssid_len;
-
-	netif_carrier_on(priv->dev);
-	if (!priv->tx_pending_len)
-		netif_wake_queue(priv->dev);
-
-	memset(&wrqu, 0, sizeof(wrqu));
-	memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
-	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-
-	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->channel);
-
-done:
-	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
-	return ret;
-}
-
-/**
- *  @brief Join an adhoc network found in a previous scan
- *
- *  @param priv         A pointer to struct lbs_private structure
- *  @param assoc_req    The association request describing the BSS to join
- *
- *  @return             0 on success, error on failure
- */
-static int lbs_adhoc_join(struct lbs_private *priv,
-	struct assoc_request *assoc_req)
-{
-	struct cmd_ds_802_11_ad_hoc_join cmd;
-	struct bss_descriptor *bss = &assoc_req->bss;
-	u8 preamble = RADIO_PREAMBLE_LONG;
-	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",
-		print_ssid(ssid, priv->curbssparams.ssid,
-		priv->curbssparams.ssid_len),
-		priv->curbssparams.ssid_len);
-	lbs_deb_join("requested ssid '%s', ssid length %u\n",
-		print_ssid(ssid, bss->ssid, bss->ssid_len),
-		bss->ssid_len);
-
-	/* check if the requested SSID is already joined */
-	if (priv->curbssparams.ssid_len &&
-	    !lbs_ssid_cmp(priv->curbssparams.ssid,
-			priv->curbssparams.ssid_len,
-			bss->ssid, bss->ssid_len) &&
-	    (priv->mode == IW_MODE_ADHOC) &&
-	    (priv->connect_status == LBS_CONNECTED)) {
-		union iwreq_data wrqu;
-
-		lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
-			"current, not attempting to re-join");
-
-		/* Send the re-association event though, because the association
-		 * request really was successful, even if just a null-op.
-		 */
-		memset(&wrqu, 0, sizeof(wrqu));
-		memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid,
-		       ETH_ALEN);
-		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-		wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-		goto out;
-	}
-
-	/* Use short preamble only when both the BSS and firmware support it */
-	if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
-		lbs_deb_join("AdhocJoin: Short preamble\n");
-		preamble = RADIO_PREAMBLE_SHORT;
-	}
-
-	ret = lbs_set_radio(priv, preamble, 1);
-	if (ret)
-		goto out;
-
-	lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
-	lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
-
-	priv->adhoccreate = 0;
-	priv->channel = bss->channel;
-
-	/* Build the join command */
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
-	cmd.bss.type = CMD_BSS_TYPE_IBSS;
-	cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
-
-	memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN);
-	memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len);
-
-	memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set));
-
-	memcpy(&cmd.bss.ibss, &bss->ss.ibss,
-	       sizeof(struct ieee_ie_ibss_param_set));
-
-	cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
-	lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
-	       bss->capability, CAPINFO_MASK);
-
-	/* information on BSSID descriptor passed to FW */
-	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) {
-		/* failtimeout */
-		cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
-		/* probedelay */
-		cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
-	}
-
-	/* Copy Data rates from the rates recorded in scan response */
-	memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
-	ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates));
-	memcpy(cmd.bss.rates, bss->rates, ratesize);
-	if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
-		lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
-		ret = -1;
-		goto out;
-	}
-
-	/* Copy the ad-hoc creation rates into Current BSS state structure */
-	memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
-	memcpy(&priv->curbssparams.rates, cmd.bss.rates, ratesize);
-
-	/* Set MSB on basic rates as the firmware requires, but _after_
-	 * copying to current bss rates.
-	 */
-	lbs_set_basic_rate_flags(cmd.bss.rates, ratesize);
-
-	cmd.bss.ibss.atimwindow = bss->atimwindow;
-
-	if (assoc_req->secinfo.wep_enabled) {
-		u16 tmp = le16_to_cpu(cmd.bss.capability);
-		tmp |= WLAN_CAPABILITY_PRIVACY;
-		cmd.bss.capability = cpu_to_le16(tmp);
-	}
-
-	if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
-		__le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM);
-
-		/* wake up first */
-		ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
-						   CMD_ACT_SET, 0, 0,
-						   &local_ps_mode);
-		if (ret) {
-			ret = -1;
-			goto out;
-		}
-	}
-
-	ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
-	if (ret == 0) {
-		ret = lbs_adhoc_post(priv,
-				     (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
-	}
-
-out:
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-/**
- *  @brief Start an Adhoc Network
- *
- *  @param priv         A pointer to struct lbs_private structure
- *  @param assoc_req    The association request describing the BSS to start
- *
- *  @return             0 on success, error on failure
- */
-static int lbs_adhoc_start(struct lbs_private *priv,
-	struct assoc_request *assoc_req)
-{
-	struct cmd_ds_802_11_ad_hoc_start cmd;
-	u8 preamble = RADIO_PREAMBLE_SHORT;
-	size_t ratesize = 0;
-	u16 tmpcap = 0;
-	int ret = 0;
-	DECLARE_SSID_BUF(ssid);
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	ret = lbs_set_radio(priv, preamble, 1);
-	if (ret)
-		goto out;
-
-	/* Build the start command */
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
-	memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len);
-
-	lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n",
-		print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
-		assoc_req->ssid_len);
-
-	cmd.bsstype = CMD_BSS_TYPE_IBSS;
-
-	if (priv->beacon_period == 0)
-		priv->beacon_period = MRVDRV_BEACON_INTERVAL;
-	cmd.beaconperiod = cpu_to_le16(priv->beacon_period);
-
-	WARN_ON(!assoc_req->channel);
-
-	/* set Physical parameter set */
-	cmd.ds.header.id = WLAN_EID_DS_PARAMS;
-	cmd.ds.header.len = 1;
-	cmd.ds.channel = assoc_req->channel;
-
-	/* set IBSS parameter set */
-	cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
-	cmd.ibss.header.len = 2;
-	cmd.ibss.atimwindow = cpu_to_le16(0);
-
-	/* set capability info */
-	tmpcap = WLAN_CAPABILITY_IBSS;
-	if (assoc_req->secinfo.wep_enabled ||
-	    assoc_req->secinfo.WPAenabled ||
-	    assoc_req->secinfo.WPA2enabled) {
-		lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n");
-		tmpcap |= WLAN_CAPABILITY_PRIVACY;
-	} else
-		lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n");
-
-	cmd.capability = cpu_to_le16(tmpcap);
-
-	/* Only v8 and below support setting probe delay */
-	if (priv->fwrelease < 0x09000000)
-		cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
-
-	ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates));
-	memcpy(cmd.rates, lbs_bg_rates, ratesize);
-
-	/* Copy the ad-hoc creating rates into Current BSS state structure */
-	memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
-	memcpy(&priv->curbssparams.rates, &cmd.rates, ratesize);
-
-	/* Set MSB on basic rates as the firmware requires, but _after_
-	 * copying to current bss rates.
-	 */
-	lbs_set_basic_rate_flags(cmd.rates, ratesize);
-
-	lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n",
-	       cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]);
-
-	lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n",
-		     assoc_req->channel, assoc_req->band);
-
-	priv->adhoccreate = 1;
-	priv->mode = IW_MODE_ADHOC;
-
-	ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
-	if (ret == 0)
-		ret = lbs_adhoc_post(priv,
-				     (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
-
-out:
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-/**
- *  @brief Stop and Ad-Hoc network and exit Ad-Hoc mode
- *
- *  @param priv         A pointer to struct lbs_private structure
- *  @return             0 on success, or an error
- */
-int lbs_adhoc_stop(struct lbs_private *priv)
-{
-	struct cmd_ds_802_11_ad_hoc_stop cmd;
-	int ret;
-
-	lbs_deb_enter(LBS_DEB_JOIN);
-
-	memset(&cmd, 0, sizeof (cmd));
-	cmd.hdr.size = cpu_to_le16 (sizeof (cmd));
-
-	ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
-
-	/* Clean up everything even if there was an error */
-	lbs_mac_event_disconnected(priv);
-
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
-					struct bss_descriptor *match_bss)
-{
-	if (!secinfo->wep_enabled &&
-	    !secinfo->WPAenabled && !secinfo->WPA2enabled &&
-	    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
-		return 0;
-}
-
-static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
-				       struct bss_descriptor *match_bss)
-{
-	if (secinfo->wep_enabled &&
-	    !secinfo->WPAenabled && !secinfo->WPA2enabled &&
-	    (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
-		return 1;
-	else
-		return 0;
-}
-
-static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
-				struct bss_descriptor *match_bss)
-{
-	if (!secinfo->wep_enabled && secinfo->WPAenabled &&
-	    (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) */
-	   )
-		return 1;
-	else
-		return 0;
-}
-
-static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
-				 struct bss_descriptor *match_bss)
-{
-	if (!secinfo->wep_enabled && secinfo->WPA2enabled &&
-	    (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) */
-	   )
-		return 1;
-	else
-		return 0;
-}
-
-static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
-					struct bss_descriptor *match_bss)
-{
-	if (!secinfo->wep_enabled &&
-	    !secinfo->WPAenabled && !secinfo->WPA2enabled &&
-	    (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
-		return 0;
-}
-
-/**
- *  @brief Check if a scanned network compatible with the driver settings
- *
- *   WEP     WPA     WPA2    ad-hoc  encrypt                      Network
- * enabled enabled  enabled   AES     mode   privacy  WPA  WPA2  Compatible
- *    0       0        0       0      NONE      0      0    0   yes No security
- *    1       0        0       0      NONE      1      0    0   yes Static WEP
- *    0       1        0       0       x        1x     1    x   yes WPA
- *    0       0        1       0       x        1x     x    1   yes WPA2
- *    0       0        0       1      NONE      1      0    0   yes Ad-hoc AES
- *    0       0        0       0     !=NONE     1      0    0   yes Dynamic WEP
- *
- *
- *  @param priv A pointer to struct lbs_private
- *  @param index   Index in scantable to check against current driver settings
- *  @param mode    Network mode: Infrastructure or IBSS
- *
- *  @return        Index in scantable, or error code if negative
- */
-static int is_network_compatible(struct lbs_private *priv,
-				 struct bss_descriptor *bss, uint8_t mode)
-{
-	int matched = 0;
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-
-	if (bss->mode != mode)
-		goto done;
-
-	matched = match_bss_no_security(&priv->secinfo, bss);
-	if (matched)
-		goto done;
-	matched = match_bss_static_wep(&priv->secinfo, bss);
-	if (matched)
-		goto done;
-	matched = match_bss_wpa(&priv->secinfo, bss);
-	if (matched) {
-		lbs_deb_scan("is_network_compatible() WPA: wpa_ie 0x%x "
-			     "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
-			     "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
-			     priv->secinfo.wep_enabled ? "e" : "d",
-			     priv->secinfo.WPAenabled ? "e" : "d",
-			     priv->secinfo.WPA2enabled ? "e" : "d",
-			     (bss->capability & WLAN_CAPABILITY_PRIVACY));
-		goto done;
-	}
-	matched = match_bss_wpa2(&priv->secinfo, bss);
-	if (matched) {
-		lbs_deb_scan("is_network_compatible() WPA2: wpa_ie 0x%x "
-			     "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
-			     "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
-			     priv->secinfo.wep_enabled ? "e" : "d",
-			     priv->secinfo.WPAenabled ? "e" : "d",
-			     priv->secinfo.WPA2enabled ? "e" : "d",
-			     (bss->capability & WLAN_CAPABILITY_PRIVACY));
-		goto done;
-	}
-	matched = match_bss_dynamic_wep(&priv->secinfo, bss);
-	if (matched) {
-		lbs_deb_scan("is_network_compatible() dynamic WEP: "
-			     "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n",
-			     bss->wpa_ie[0], bss->rsn_ie[0],
-			     (bss->capability & WLAN_CAPABILITY_PRIVACY));
-		goto done;
-	}
-
-	/* bss security settings don't match those configured on card */
-	lbs_deb_scan("is_network_compatible() FAILED: wpa_ie 0x%x "
-		     "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n",
-		     bss->wpa_ie[0], bss->rsn_ie[0],
-		     priv->secinfo.wep_enabled ? "e" : "d",
-		     priv->secinfo.WPAenabled ? "e" : "d",
-		     priv->secinfo.WPA2enabled ? "e" : "d",
-		     (bss->capability & WLAN_CAPABILITY_PRIVACY));
-
-done:
-	lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched);
-	return matched;
-}
-
-/**
- *  @brief This function finds a specific compatible BSSID in the scan list
- *
- *  Used in association code
- *
- *  @param priv  A pointer to struct lbs_private
- *  @param bssid    BSSID to find in the scan list
- *  @param mode     Network mode: Infrastructure or IBSS
- *
- *  @return         index in BSSID list, or error return code (< 0)
- */
-static struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv,
-					      uint8_t *bssid, uint8_t mode)
-{
-	struct bss_descriptor *iter_bss;
-	struct bss_descriptor *found_bss = NULL;
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-
-	if (!bssid)
-		goto out;
-
-	lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN);
-
-	/* Look through the scan table for a compatible match.  The loop will
-	 *   continue past a matched bssid that is not compatible in case there
-	 *   is an AP with multiple SSIDs assigned to the same BSSID
-	 */
-	mutex_lock(&priv->lock);
-	list_for_each_entry(iter_bss, &priv->network_list, list) {
-		if (compare_ether_addr(iter_bss->bssid, bssid))
-			continue; /* bssid doesn't match */
-		switch (mode) {
-		case IW_MODE_INFRA:
-		case IW_MODE_ADHOC:
-			if (!is_network_compatible(priv, iter_bss, mode))
-				break;
-			found_bss = iter_bss;
-			break;
-		default:
-			found_bss = iter_bss;
-			break;
-		}
-	}
-	mutex_unlock(&priv->lock);
-
-out:
-	lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
-	return found_bss;
-}
-
-/**
- *  @brief This function finds ssid in ssid list.
- *
- *  Used in association code
- *
- *  @param priv  A pointer to struct lbs_private
- *  @param ssid     SSID to find in the list
- *  @param bssid    BSSID to qualify the SSID selection (if provided)
- *  @param mode     Network mode: Infrastructure or IBSS
- *
- *  @return         index in BSSID list
- */
-static struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv,
-					     uint8_t *ssid, uint8_t ssid_len,
-					     uint8_t *bssid, uint8_t mode,
-					     int channel)
-{
-	u32 bestrssi = 0;
-	struct bss_descriptor *iter_bss = NULL;
-	struct bss_descriptor *found_bss = NULL;
-	struct bss_descriptor *tmp_oldest = NULL;
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-
-	mutex_lock(&priv->lock);
-
-	list_for_each_entry(iter_bss, &priv->network_list, list) {
-		if (!tmp_oldest ||
-		    (iter_bss->last_scanned < tmp_oldest->last_scanned))
-			tmp_oldest = iter_bss;
-
-		if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len,
-				 ssid, ssid_len) != 0)
-			continue; /* ssid doesn't match */
-		if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0)
-			continue; /* bssid doesn't match */
-		if ((channel > 0) && (iter_bss->channel != channel))
-			continue; /* channel doesn't match */
-
-		switch (mode) {
-		case IW_MODE_INFRA:
-		case IW_MODE_ADHOC:
-			if (!is_network_compatible(priv, iter_bss, mode))
-				break;
-
-			if (bssid) {
-				/* Found requested BSSID */
-				found_bss = iter_bss;
-				goto out;
-			}
-
-			if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
-				bestrssi = SCAN_RSSI(iter_bss->rssi);
-				found_bss = iter_bss;
-			}
-			break;
-		case IW_MODE_AUTO:
-		default:
-			if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
-				bestrssi = SCAN_RSSI(iter_bss->rssi);
-				found_bss = iter_bss;
-			}
-			break;
-		}
-	}
-
-out:
-	mutex_unlock(&priv->lock);
-	lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
-	return found_bss;
-}
-
-static int assoc_helper_essid(struct lbs_private *priv,
-                              struct assoc_request * assoc_req)
-{
-	int ret = 0;
-	struct bss_descriptor * bss;
-	int channel = -1;
-	DECLARE_SSID_BUF(ssid);
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	/* FIXME: take channel into account when picking SSIDs if a channel
-	 * is set.
-	 */
-
-	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
-		channel = assoc_req->channel;
-
-	lbs_deb_assoc("SSID '%s' requested\n",
-	              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);
-
-		bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
-				assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
-		if (bss != NULL) {
-			memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
-			ret = lbs_try_associate(priv, assoc_req);
-		} else {
-			lbs_deb_assoc("SSID not found; cannot associate\n");
-		}
-	} else if (assoc_req->mode == IW_MODE_ADHOC) {
-		/* Scan for the network, do not save previous results.  Stale
-		 *   scan data will cause us to join a non-existant adhoc network
-		 */
-		lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
-			assoc_req->ssid_len);
-
-		/* Search for the requested SSID in the scan table */
-		bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
-				assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel);
-		if (bss != NULL) {
-			lbs_deb_assoc("SSID found, will join\n");
-			memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
-			lbs_adhoc_join(priv, assoc_req);
-		} else {
-			/* else send START command */
-			lbs_deb_assoc("SSID not found, creating adhoc network\n");
-			memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
-				IEEE80211_MAX_SSID_LEN);
-			assoc_req->bss.ssid_len = assoc_req->ssid_len;
-			lbs_adhoc_start(priv, assoc_req);
-		}
-	}
-
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-
-static int assoc_helper_bssid(struct lbs_private *priv,
-                              struct assoc_request * assoc_req)
-{
-	int ret = 0;
-	struct bss_descriptor * bss;
-
-	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 %pM not found, "
-			"cannot associate.\n", assoc_req->bssid);
-		goto out;
-	}
-
-	memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
-	if (assoc_req->mode == IW_MODE_INFRA) {
-		ret = lbs_try_associate(priv, assoc_req);
-		lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n",
-			      ret);
-	} else if (assoc_req->mode == IW_MODE_ADHOC) {
-		lbs_adhoc_join(priv, assoc_req);
-	}
-
-out:
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-
-static int assoc_helper_associate(struct lbs_private *priv,
-                                  struct assoc_request * assoc_req)
-{
-	int ret = 0, done = 0;
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	/* If we're given and 'any' BSSID, try associating based on SSID */
-
-	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
-		if (compare_ether_addr(bssid_any, assoc_req->bssid) &&
-		    compare_ether_addr(bssid_off, assoc_req->bssid)) {
-			ret = assoc_helper_bssid(priv, assoc_req);
-			done = 1;
-		}
-	}
-
-	if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
-		ret = assoc_helper_essid(priv, assoc_req);
-	}
-
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-
-static int assoc_helper_mode(struct lbs_private *priv,
-                             struct assoc_request * assoc_req)
-{
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	if (assoc_req->mode == priv->mode)
-		goto done;
-
-	if (assoc_req->mode == IW_MODE_INFRA) {
-		if (priv->psstate != PS_STATE_FULL_POWER)
-			lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
-		priv->psmode = LBS802_11POWERMODECAM;
-	}
-
-	priv->mode = assoc_req->mode;
-	ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE,
-		assoc_req->mode == IW_MODE_ADHOC ? 2 : 1);
-
-done:
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-static int assoc_helper_channel(struct lbs_private *priv,
-                                struct assoc_request * assoc_req)
-{
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	ret = lbs_update_channel(priv);
-	if (ret) {
-		lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
-		goto done;
-	}
-
-	if (assoc_req->channel == priv->channel)
-		goto done;
-
-	if (priv->mesh_dev) {
-		/* Change mesh channel first; 21.p21 firmware won't let
-		   you change channel otherwise (even though it'll return
-		   an error to this */
-		lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
-				assoc_req->channel);
-	}
-
-	lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
-		      priv->channel, assoc_req->channel);
-
-	ret = lbs_set_channel(priv, assoc_req->channel);
-	if (ret < 0)
-		lbs_deb_assoc("ASSOC: channel: error setting channel.\n");
-
-	/* FIXME: shouldn't need to grab the channel _again_ after setting
-	 * it since the firmware is supposed to return the new channel, but
-	 * whatever... */
-	ret = lbs_update_channel(priv);
-	if (ret) {
-		lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
-		goto done;
-	}
-
-	if (assoc_req->channel != priv->channel) {
-		lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
-		              assoc_req->channel);
-		goto restore_mesh;
-	}
-
-	if (assoc_req->secinfo.wep_enabled &&
-	    (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
-	     assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)) {
-		/* Make sure WEP keys are re-sent to firmware */
-		set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
-	}
-
-	/* Must restart/rejoin adhoc networks after channel change */
- 	set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
-
- restore_mesh:
-	if (priv->mesh_dev)
-		lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
-				priv->channel);
-
- done:
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-
-static int assoc_helper_wep_keys(struct lbs_private *priv,
-				 struct assoc_request *assoc_req)
-{
-	int i;
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	/* Set or remove WEP keys */
-	if (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
-	    assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)
-		ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_ADD, assoc_req);
-	else
-		ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_REMOVE, assoc_req);
-
-	if (ret)
-		goto out;
-
-	/* enable/disable the MAC's WEP packet filter */
-	if (assoc_req->secinfo.wep_enabled)
-		priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
-	else
-		priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
-
-	lbs_set_mac_control(priv);
-
-	mutex_lock(&priv->lock);
-
-	/* Copy WEP keys into priv wep key fields */
-	for (i = 0; i < 4; i++) {
-		memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i],
-		       sizeof(struct enc_key));
-	}
-	priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
-
-	mutex_unlock(&priv->lock);
-
-out:
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-static int assoc_helper_secinfo(struct lbs_private *priv,
-                                struct assoc_request * assoc_req)
-{
-	int ret = 0;
-	uint16_t do_wpa;
-	uint16_t rsn = 0;
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	memcpy(&priv->secinfo, &assoc_req->secinfo,
-		sizeof(struct lbs_802_11_security));
-
-	lbs_set_mac_control(priv);
-
-	/* If RSN is already enabled, don't try to enable it again, since
-	 * ENABLE_RSN resets internal state machines and will clobber the
-	 * 4-way WPA handshake.
-	 */
-
-	/* Get RSN enabled/disabled */
-	ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_GET, &rsn);
-	if (ret) {
-		lbs_deb_assoc("Failed to get RSN status: %d\n", ret);
-		goto out;
-	}
-
-	/* Don't re-enable RSN if it's already enabled */
-	do_wpa = assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled;
-	if (do_wpa == rsn)
-		goto out;
-
-	/* Set RSN enabled/disabled */
-	ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_SET, &do_wpa);
-
-out:
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-
-static int assoc_helper_wpa_keys(struct lbs_private *priv,
-                                 struct assoc_request * assoc_req)
-{
-	int ret = 0;
-	unsigned int flags = assoc_req->flags;
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	/* Work around older firmware bug where WPA unicast and multicast
-	 * keys must be set independently.  Seen in SDIO parts with firmware
-	 * version 5.0.11p0.
-	 */
-
-	if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
-		clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
-		ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
-		assoc_req->flags = flags;
-	}
-
-	if (ret)
-		goto out;
-
-	memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key,
-			sizeof(struct enc_key));
-
-	if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
-		clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
-
-		ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
-		assoc_req->flags = flags;
-
-		memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key,
-				sizeof(struct enc_key));
-	}
-
-out:
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-
-static int assoc_helper_wpa_ie(struct lbs_private *priv,
-                               struct assoc_request * assoc_req)
-{
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
-		memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
-		priv->wpa_ie_len = assoc_req->wpa_ie_len;
-	} else {
-		memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN);
-		priv->wpa_ie_len = 0;
-	}
-
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-
-static int should_deauth_infrastructure(struct lbs_private *priv,
-                                        struct assoc_request * assoc_req)
-{
-	int ret = 0;
-
-	if (priv->connect_status != LBS_CONNECTED)
-		return 0;
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
-		lbs_deb_assoc("Deauthenticating due to new SSID\n");
-		ret = 1;
-		goto out;
-	}
-
-	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
-		if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
-			lbs_deb_assoc("Deauthenticating due to new security\n");
-			ret = 1;
-			goto out;
-		}
-	}
-
-	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
-		lbs_deb_assoc("Deauthenticating due to new BSSID\n");
-		ret = 1;
-		goto out;
-	}
-
-	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
-		lbs_deb_assoc("Deauthenticating due to channel switch\n");
-		ret = 1;
-		goto out;
-	}
-
-	/* FIXME: deal with 'auto' mode somehow */
-	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
-		if (assoc_req->mode != IW_MODE_INFRA) {
-			lbs_deb_assoc("Deauthenticating due to leaving "
-				"infra mode\n");
-			ret = 1;
-			goto out;
-		}
-	}
-
-out:
-	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-	return ret;
-}
-
-
-static int should_stop_adhoc(struct lbs_private *priv,
-                             struct assoc_request * assoc_req)
-{
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	if (priv->connect_status != LBS_CONNECTED)
-		return 0;
-
-	if (lbs_ssid_cmp(priv->curbssparams.ssid,
-	                      priv->curbssparams.ssid_len,
-	                      assoc_req->ssid, assoc_req->ssid_len) != 0)
-		return 1;
-
-	/* FIXME: deal with 'auto' mode somehow */
-	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
-		if (assoc_req->mode != IW_MODE_ADHOC)
-			return 1;
-	}
-
-	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
-		if (assoc_req->channel != priv->channel)
-			return 1;
-	}
-
-	lbs_deb_leave(LBS_DEB_ASSOC);
-	return 0;
-}
-
-
-/**
- *  @brief This function finds the best SSID in the Scan List
- *
- *  Search the scan table for the best SSID that also matches the current
- *   adapter network preference (infrastructure or adhoc)
- *
- *  @param priv  A pointer to struct lbs_private
- *
- *  @return         index in BSSID list
- */
-static struct bss_descriptor *lbs_find_best_ssid_in_list(
-	struct lbs_private *priv, uint8_t mode)
-{
-	uint8_t bestrssi = 0;
-	struct bss_descriptor *iter_bss;
-	struct bss_descriptor *best_bss = NULL;
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-
-	mutex_lock(&priv->lock);
-
-	list_for_each_entry(iter_bss, &priv->network_list, list) {
-		switch (mode) {
-		case IW_MODE_INFRA:
-		case IW_MODE_ADHOC:
-			if (!is_network_compatible(priv, iter_bss, mode))
-				break;
-			if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
-				break;
-			bestrssi = SCAN_RSSI(iter_bss->rssi);
-			best_bss = iter_bss;
-			break;
-		case IW_MODE_AUTO:
-		default:
-			if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
-				break;
-			bestrssi = SCAN_RSSI(iter_bss->rssi);
-			best_bss = iter_bss;
-			break;
-		}
-	}
-
-	mutex_unlock(&priv->lock);
-	lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss);
-	return best_bss;
-}
-
-/**
- *  @brief Find the best AP
- *
- *  Used from association worker.
- *
- *  @param priv         A pointer to struct lbs_private structure
- *  @param pSSID        A pointer to AP's ssid
- *
- *  @return             0--success, otherwise--fail
- */
-static int lbs_find_best_network_ssid(struct lbs_private *priv,
-	uint8_t *out_ssid, uint8_t *out_ssid_len, uint8_t preferred_mode,
-	uint8_t *out_mode)
-{
-	int ret = -1;
-	struct bss_descriptor *found;
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-
-	priv->scan_ssid_len = 0;
-	lbs_scan_networks(priv, 1);
-	if (priv->surpriseremoved)
-		goto out;
-
-	found = lbs_find_best_ssid_in_list(priv, preferred_mode);
-	if (found && (found->ssid_len > 0)) {
-		memcpy(out_ssid, &found->ssid, IEEE80211_MAX_SSID_LEN);
-		*out_ssid_len = found->ssid_len;
-		*out_mode = found->mode;
-		ret = 0;
-	}
-
-out:
-	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-	return ret;
-}
-
-
-void lbs_association_worker(struct work_struct *work)
-{
-	struct lbs_private *priv = container_of(work, struct lbs_private,
-		assoc_work.work);
-	struct assoc_request * assoc_req = NULL;
-	int ret = 0;
-	int find_any_ssid = 0;
-	DECLARE_SSID_BUF(ssid);
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	mutex_lock(&priv->lock);
-	assoc_req = priv->pending_assoc_req;
-	priv->pending_assoc_req = NULL;
-	priv->in_progress_assoc_req = assoc_req;
-	mutex_unlock(&priv->lock);
-
-	if (!assoc_req)
-		goto done;
-
-	lbs_deb_assoc(
-		"Association Request:\n"
-		"    flags:     0x%08lx\n"
-		"    SSID:      '%s'\n"
-		"    chann:     %d\n"
-		"    band:      %d\n"
-		"    mode:      %d\n"
-		"    BSSID:     %pM\n"
-		"    secinfo:  %s%s%s\n"
-		"    auth_mode: %d\n",
-		assoc_req->flags,
-		print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
-		assoc_req->channel, assoc_req->band, assoc_req->mode,
-		assoc_req->bssid,
-		assoc_req->secinfo.WPAenabled ? " WPA" : "",
-		assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
-		assoc_req->secinfo.wep_enabled ? " WEP" : "",
-		assoc_req->secinfo.auth_mode);
-
-	/* If 'any' SSID was specified, find an SSID to associate with */
-	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) &&
-	    !assoc_req->ssid_len)
-		find_any_ssid = 1;
-
-	/* But don't use 'any' SSID if there's a valid locked BSSID to use */
-	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
-		if (compare_ether_addr(assoc_req->bssid, bssid_any) &&
-		    compare_ether_addr(assoc_req->bssid, bssid_off))
-			find_any_ssid = 0;
-	}
-
-	if (find_any_ssid) {
-		u8 new_mode = assoc_req->mode;
-
-		ret = lbs_find_best_network_ssid(priv, assoc_req->ssid,
-				&assoc_req->ssid_len, assoc_req->mode, &new_mode);
-		if (ret) {
-			lbs_deb_assoc("Could not find best network\n");
-			ret = -ENETUNREACH;
-			goto out;
-		}
-
-		/* Ensure we switch to the mode of the AP */
-		if (assoc_req->mode == IW_MODE_AUTO) {
-			set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
-			assoc_req->mode = new_mode;
-		}
-	}
-
-	/*
-	 * Check if the attributes being changing require deauthentication
-	 * from the currently associated infrastructure access point.
-	 */
-	if (priv->mode == IW_MODE_INFRA) {
-		if (should_deauth_infrastructure(priv, assoc_req)) {
-			ret = lbs_cmd_80211_deauthenticate(priv,
-							   priv->curbssparams.bssid,
-							   WLAN_REASON_DEAUTH_LEAVING);
-			if (ret) {
-				lbs_deb_assoc("Deauthentication due to new "
-					"configuration request failed: %d\n",
-					ret);
-			}
-		}
-	} else if (priv->mode == IW_MODE_ADHOC) {
-		if (should_stop_adhoc(priv, assoc_req)) {
-			ret = lbs_adhoc_stop(priv);
-			if (ret) {
-				lbs_deb_assoc("Teardown of AdHoc network due to "
-					"new configuration request failed: %d\n",
-					ret);
-			}
-
-		}
-	}
-
-	/* Send the various configuration bits to the firmware */
-	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
-		ret = assoc_helper_mode(priv, assoc_req);
-		if (ret)
-			goto out;
-	}
-
-	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
-		ret = assoc_helper_channel(priv, assoc_req);
-		if (ret)
-			goto out;
-	}
-
-	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
-		ret = assoc_helper_secinfo(priv, assoc_req);
-		if (ret)
-			goto out;
-	}
-
-	if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
-		ret = assoc_helper_wpa_ie(priv, assoc_req);
-		if (ret)
-			goto out;
-	}
-
-	/*
-	 * v10 FW wants WPA keys to be set/cleared before WEP key operations,
-	 * otherwise it will fail to correctly associate to WEP networks.
-	 * Other firmware versions don't appear to care.
-	 */
-	if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) ||
-	    test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
-		ret = assoc_helper_wpa_keys(priv, assoc_req);
-		if (ret)
-			goto out;
-	}
-
-	if (test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) ||
-	    test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
-		ret = assoc_helper_wep_keys(priv, assoc_req);
-		if (ret)
-			goto out;
-	}
-
-
-	/* SSID/BSSID should be the _last_ config option set, because they
-	 * trigger the association attempt.
-	 */
-	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) ||
-	    test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
-		int success = 1;
-
-		ret = assoc_helper_associate(priv, assoc_req);
-		if (ret) {
-			lbs_deb_assoc("ASSOC: association unsuccessful: %d\n",
-				ret);
-			success = 0;
-		}
-
-		if (priv->connect_status != LBS_CONNECTED) {
-			lbs_deb_assoc("ASSOC: association unsuccessful, "
-				"not connected\n");
-			success = 0;
-		}
-
-		if (success) {
-			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);
-		} else {
-			ret = -1;
-		}
-	}
-
-out:
-	if (ret) {
-		lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
-			ret);
-	}
-
-	mutex_lock(&priv->lock);
-	priv->in_progress_assoc_req = NULL;
-	mutex_unlock(&priv->lock);
-	kfree(assoc_req);
-
-done:
-	lbs_deb_leave(LBS_DEB_ASSOC);
-}
-
-
-/*
- * Caller MUST hold any necessary locks
- */
-struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
-{
-	struct assoc_request * assoc_req;
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-	if (!priv->pending_assoc_req) {
-		priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
-		                                     GFP_KERNEL);
-		if (!priv->pending_assoc_req) {
-			lbs_pr_info("Not enough memory to allocate association"
-				" request!\n");
-			return NULL;
-		}
-	}
-
-	/* Copy current configuration attributes to the association request,
-	 * but don't overwrite any that are already set.
-	 */
-	assoc_req = priv->pending_assoc_req;
-	if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
-		memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
-		       IEEE80211_MAX_SSID_LEN);
-		assoc_req->ssid_len = priv->curbssparams.ssid_len;
-	}
-
-	if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
-		assoc_req->channel = priv->channel;
-
-	if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
-		assoc_req->band = priv->curbssparams.band;
-
-	if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
-		assoc_req->mode = priv->mode;
-
-	if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
-		memcpy(&assoc_req->bssid, priv->curbssparams.bssid,
-			ETH_ALEN);
-	}
-
-	if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
-		int i;
-		for (i = 0; i < 4; i++) {
-			memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i],
-				sizeof(struct enc_key));
-		}
-	}
-
-	if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
-		assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx;
-
-	if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
-		memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key,
-			sizeof(struct enc_key));
-	}
-
-	if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
-		memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key,
-			sizeof(struct enc_key));
-	}
-
-	if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
-		memcpy(&assoc_req->secinfo, &priv->secinfo,
-			sizeof(struct lbs_802_11_security));
-	}
-
-	if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
-		memcpy(&assoc_req->wpa_ie, &priv->wpa_ie,
-			MAX_WPA_IE_LEN);
-		assoc_req->wpa_ie_len = priv->wpa_ie_len;
-	}
-
-	lbs_deb_leave(LBS_DEB_ASSOC);
-	return assoc_req;
-}
-
-
-/**
- *  @brief Deauthenticate from a specific BSS
- *
- *  @param priv        A pointer to struct lbs_private structure
- *  @param bssid       The specific BSS to deauthenticate from
- *  @param reason      The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating
- *
- *  @return            0 on success, error on failure
- */
-int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN],
-				 u16 reason)
-{
-	struct cmd_ds_802_11_deauthenticate cmd;
-	int ret;
-
-	lbs_deb_enter(LBS_DEB_JOIN);
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-	memcpy(cmd.macaddr, &bssid[0], ETH_ALEN);
-	cmd.reasoncode = cpu_to_le16(reason);
-
-	ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
-
-	/* Clean up everything even if there was an error; can't assume that
-	 * we're still authenticated to the AP after trying to deauth.
-	 */
-	lbs_mac_event_disconnected(priv);
-
-	lbs_deb_leave(LBS_DEB_JOIN);
-	return ret;
-}
-
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
deleted file mode 100644
index 40621b7..0000000
--- a/drivers/net/wireless/libertas/assoc.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/* Copyright (C) 2006, Red Hat, Inc. */
-
-#ifndef _LBS_ASSOC_H_
-#define _LBS_ASSOC_H_
-
-
-#include "defs.h"
-#include "host.h"
-
-
-struct lbs_private;
-
-/*
- * In theory, the IE is limited to the IE length, 255,
- * but in practice 64 bytes are enough.
- */
-#define MAX_WPA_IE_LEN 64
-
-
-
-struct lbs_802_11_security {
-	u8 WPAenabled;
-	u8 WPA2enabled;
-	u8 wep_enabled;
-	u8 auth_mode;
-	u32 key_mgmt;
-};
-
-/** Current Basic Service Set State Structure */
-struct current_bss_params {
-	/** bssid */
-	u8 bssid[ETH_ALEN];
-	/** ssid */
-	u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
-	u8 ssid_len;
-
-	/** band */
-	u8 band;
-	/** channel is directly in priv->channel */
-	/** zero-terminated array of supported data rates */
-	u8 rates[MAX_RATES + 1];
-};
-
-/**
- *  @brief Structure used to store information for each beacon/probe response
- */
-struct bss_descriptor {
-	u8 bssid[ETH_ALEN];
-
-	u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
-	u8 ssid_len;
-
-	u16 capability;
-	u32 rssi;
-	u32 channel;
-	u16 beaconperiod;
-	__le16 atimwindow;
-
-	/* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
-	u8 mode;
-
-	/* zero-terminated array of supported data rates */
-	u8 rates[MAX_RATES + 1];
-
-	unsigned long last_scanned;
-
-	union ieee_phy_param_set phy;
-	union ieee_ss_param_set ss;
-
-	u8 wpa_ie[MAX_WPA_IE_LEN];
-	size_t wpa_ie_len;
-	u8 rsn_ie[MAX_WPA_IE_LEN];
-	size_t rsn_ie_len;
-
-	u8 mesh;
-
-	struct list_head list;
-};
-
-/** Association request
- *
- * Encapsulates all the options that describe a specific assocation request
- * or configuration of the wireless card's radio, mode, and security settings.
- */
-struct assoc_request {
-#define ASSOC_FLAG_SSID			1
-#define ASSOC_FLAG_CHANNEL		2
-#define ASSOC_FLAG_BAND			3
-#define ASSOC_FLAG_MODE			4
-#define ASSOC_FLAG_BSSID		5
-#define ASSOC_FLAG_WEP_KEYS		6
-#define ASSOC_FLAG_WEP_TX_KEYIDX	7
-#define ASSOC_FLAG_WPA_MCAST_KEY	8
-#define ASSOC_FLAG_WPA_UCAST_KEY	9
-#define ASSOC_FLAG_SECINFO		10
-#define ASSOC_FLAG_WPA_IE		11
-	unsigned long flags;
-
-	u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
-	u8 ssid_len;
-	u8 channel;
-	u8 band;
-	u8 mode;
-	u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
-
-	/** WEP keys */
-	struct enc_key wep_keys[4];
-	u16 wep_tx_keyidx;
-
-	/** WPA keys */
-	struct enc_key wpa_mcast_key;
-	struct enc_key wpa_unicast_key;
-
-	struct lbs_802_11_security secinfo;
-
-	/** WPA Information Elements*/
-	u8 wpa_ie[MAX_WPA_IE_LEN];
-	u8 wpa_ie_len;
-
-	/* BSS to associate with for infrastructure of Ad-Hoc join */
-	struct bss_descriptor bss;
-};
-
-
-extern u8 lbs_bg_rates[MAX_RATES];
-
-void lbs_association_worker(struct work_struct *work);
-struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
-
-int lbs_adhoc_stop(struct lbs_private *priv);
-
-int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
-				 u8 bssid[ETH_ALEN], u16 reason);
-
-int lbs_cmd_802_11_rssi(struct lbs_private *priv,
-				struct cmd_ds_command *cmd);
-int lbs_ret_802_11_rssi(struct lbs_private *priv,
-				struct cmd_ds_command *resp);
-
-int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
-				struct cmd_ds_command *cmd,
-				u16 cmd_action);
-int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
-					struct cmd_ds_command *resp);
-
-int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
-			   struct assoc_request *assoc);
-
-int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
-			      uint16_t *enable);
-
-int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
-				struct assoc_request *assoc);
-
-#endif /* _LBS_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 9d5d3cc..25f9027 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -7,8 +7,11 @@
  */
 
 #include <linux/slab.h>
+#include <linux/ieee80211.h>
 #include <net/cfg80211.h>
+#include <asm/unaligned.h>
 
+#include "decl.h"
 #include "cfg.h"
 #include "cmd.h"
 
@@ -39,26 +42,27 @@
 	CHAN2G(14, 2484, 0),
 };
 
-#define RATETAB_ENT(_rate, _rateid, _flags) { \
-	.bitrate  = (_rate),                  \
-	.hw_value = (_rateid),                \
-	.flags    = (_flags),                 \
+#define RATETAB_ENT(_rate, _hw_value, _flags) { \
+	.bitrate  = (_rate),                    \
+	.hw_value = (_hw_value),                \
+	.flags    = (_flags),                   \
 }
 
 
+/* Table 6 in section 3.2.1.1 */
 static struct ieee80211_rate lbs_rates[] = {
-	RATETAB_ENT(10,  0x1,   0),
-	RATETAB_ENT(20,  0x2,   0),
-	RATETAB_ENT(55,  0x4,   0),
-	RATETAB_ENT(110, 0x8,   0),
-	RATETAB_ENT(60,  0x10,  0),
-	RATETAB_ENT(90,  0x20,  0),
-	RATETAB_ENT(120, 0x40,  0),
-	RATETAB_ENT(180, 0x80,  0),
-	RATETAB_ENT(240, 0x100, 0),
-	RATETAB_ENT(360, 0x200, 0),
-	RATETAB_ENT(480, 0x400, 0),
-	RATETAB_ENT(540, 0x800, 0),
+	RATETAB_ENT(10,  0,  0),
+	RATETAB_ENT(20,  1,  0),
+	RATETAB_ENT(55,  2,  0),
+	RATETAB_ENT(110, 3,  0),
+	RATETAB_ENT(60,  9,  0),
+	RATETAB_ENT(90,  6,  0),
+	RATETAB_ENT(120, 7,  0),
+	RATETAB_ENT(180, 8,  0),
+	RATETAB_ENT(240, 9,  0),
+	RATETAB_ENT(360, 10, 0),
+	RATETAB_ENT(480, 11, 0),
+	RATETAB_ENT(540, 12, 0),
 };
 
 static struct ieee80211_supported_band lbs_band_2ghz = {
@@ -76,22 +80,639 @@
 	WLAN_CIPHER_SUITE_CCMP,
 };
 
+/* Time to stay on the channel */
+#define LBS_DWELL_PASSIVE 100
+#define LBS_DWELL_ACTIVE  40
 
 
+/***************************************************************************
+ * Misc utility functions
+ *
+ * TLVs are Marvell specific. They are very similar to IEs, they have the
+ * same structure: type, length, data*. The only difference: for IEs, the
+ * type and length are u8, but for TLVs they're __le16.
+ */
+
+/*
+ * Convert NL80211's auth_type to the one from Libertas, see chapter 5.9.1
+ * in the firmware spec
+ */
+static u8 lbs_auth_to_authtype(enum nl80211_auth_type auth_type)
+{
+	int ret = -ENOTSUPP;
+
+	switch (auth_type) {
+	case NL80211_AUTHTYPE_OPEN_SYSTEM:
+	case NL80211_AUTHTYPE_SHARED_KEY:
+		ret = auth_type;
+		break;
+	case NL80211_AUTHTYPE_AUTOMATIC:
+		ret = NL80211_AUTHTYPE_OPEN_SYSTEM;
+		break;
+	case NL80211_AUTHTYPE_NETWORK_EAP:
+		ret = 0x80;
+		break;
+	default:
+		/* silence compiler */
+		break;
+	}
+	return ret;
+}
+
+
+/* Various firmware commands need the list of supported rates, but with
+   the hight-bit set for basic rates */
+static int lbs_add_rates(u8 *rates)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
+		u8 rate = lbs_rates[i].bitrate / 5;
+		if (rate == 0x02 || rate == 0x04 ||
+		    rate == 0x0b || rate == 0x16)
+			rate |= 0x80;
+		rates[i] = rate;
+	}
+	return ARRAY_SIZE(lbs_rates);
+}
+
+
+/***************************************************************************
+ * TLV utility functions
+ *
+ * TLVs are Marvell specific. They are very similar to IEs, they have the
+ * same structure: type, length, data*. The only difference: for IEs, the
+ * type and length are u8, but for TLVs they're __le16.
+ */
+
+
+/*
+ * Add ssid TLV
+ */
+#define LBS_MAX_SSID_TLV_SIZE			\
+	(sizeof(struct mrvl_ie_header)		\
+	 + IEEE80211_MAX_SSID_LEN)
+
+static int lbs_add_ssid_tlv(u8 *tlv, const u8 *ssid, int ssid_len)
+{
+	struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;
+
+	/*
+	 * TLV-ID SSID  00 00
+	 * length       06 00
+	 * ssid         4d 4e 54 45 53 54
+	 */
+	ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
+	ssid_tlv->header.len = cpu_to_le16(ssid_len);
+	memcpy(ssid_tlv->ssid, ssid, ssid_len);
+	return sizeof(ssid_tlv->header) + ssid_len;
+}
+
+
+/*
+ * Add channel list TLV (section 8.4.2)
+ *
+ * Actual channel data comes from priv->wdev->wiphy->channels.
+ */
+#define LBS_MAX_CHANNEL_LIST_TLV_SIZE					\
+	(sizeof(struct mrvl_ie_header)					\
+	 + (LBS_SCAN_BEFORE_NAP * sizeof(struct chanscanparamset)))
+
+static int lbs_add_channel_list_tlv(struct lbs_private *priv, u8 *tlv,
+				    int last_channel, int active_scan)
+{
+	int chanscanparamsize = sizeof(struct chanscanparamset) *
+		(last_channel - priv->scan_channel);
+
+	struct mrvl_ie_header *header = (void *) tlv;
+
+	/*
+	 * TLV-ID CHANLIST  01 01
+	 * length           0e 00
+	 * channel          00 01 00 00 00 64 00
+	 *   radio type     00
+	 *   channel           01
+	 *   scan type            00
+	 *   min scan time           00 00
+	 *   max scan time                 64 00
+	 * channel 2        00 02 00 00 00 64 00
+	 *
+	 */
+
+	header->type = cpu_to_le16(TLV_TYPE_CHANLIST);
+	header->len  = cpu_to_le16(chanscanparamsize);
+	tlv += sizeof(struct mrvl_ie_header);
+
+	/* lbs_deb_scan("scan: channels %d to %d\n", priv->scan_channel,
+		     last_channel); */
+	memset(tlv, 0, chanscanparamsize);
+
+	while (priv->scan_channel < last_channel) {
+		struct chanscanparamset *param = (void *) tlv;
+
+		param->radiotype = CMD_SCAN_RADIO_TYPE_BG;
+		param->channumber =
+			priv->scan_req->channels[priv->scan_channel]->hw_value;
+		if (active_scan) {
+			param->maxscantime = cpu_to_le16(LBS_DWELL_ACTIVE);
+		} else {
+			param->chanscanmode.passivescan = 1;
+			param->maxscantime = cpu_to_le16(LBS_DWELL_PASSIVE);
+		}
+		tlv += sizeof(struct chanscanparamset);
+		priv->scan_channel++;
+	}
+	return sizeof(struct mrvl_ie_header) + chanscanparamsize;
+}
+
+
+/*
+ * Add rates TLV
+ *
+ * The rates are in lbs_bg_rates[], but for the 802.11b
+ * rates the high bit is set. We add this TLV only because
+ * there's a firmware which otherwise doesn't report all
+ * APs in range.
+ */
+#define LBS_MAX_RATES_TLV_SIZE			\
+	(sizeof(struct mrvl_ie_header)		\
+	 + (ARRAY_SIZE(lbs_rates)))
+
+/* Adds a TLV with all rates the hardware supports */
+static int lbs_add_supported_rates_tlv(u8 *tlv)
+{
+	size_t i;
+	struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
+
+	/*
+	 * TLV-ID RATES  01 00
+	 * length        0e 00
+	 * rates         82 84 8b 96 0c 12 18 24 30 48 60 6c
+	 */
+	rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
+	tlv += sizeof(rate_tlv->header);
+	i = lbs_add_rates(tlv);
+	tlv += i;
+	rate_tlv->header.len = cpu_to_le16(i);
+	return sizeof(rate_tlv->header) + i;
+}
+
+
+/*
+ * Adds a TLV with all rates the hardware *and* BSS supports.
+ */
+static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
+{
+	struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
+	const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+	int n;
+
+	/*
+	 * 01 00                   TLV_TYPE_RATES
+	 * 04 00                   len
+	 * 82 84 8b 96             rates
+	 */
+	rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
+	tlv += sizeof(rate_tlv->header);
+
+	if (!rates_eid) {
+		/* Fallback: add basic 802.11b rates */
+		*tlv++ = 0x82;
+		*tlv++ = 0x84;
+		*tlv++ = 0x8b;
+		*tlv++ = 0x96;
+		n = 4;
+	} else {
+		int hw, ap;
+		u8 ap_max = rates_eid[1];
+		n = 0;
+		for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
+			u8 hw_rate = lbs_rates[hw].bitrate / 5;
+			for (ap = 0; ap < ap_max; ap++) {
+				if (hw_rate == (rates_eid[ap+2] & 0x7f)) {
+					*tlv++ = rates_eid[ap+2];
+					n++;
+				}
+			}
+		}
+	}
+
+	rate_tlv->header.len = cpu_to_le16(n);
+	return sizeof(rate_tlv->header) + n;
+}
+
+
+/*
+ * Add auth type TLV.
+ *
+ * This is only needed for newer firmware (V9 and up).
+ */
+#define LBS_MAX_AUTH_TYPE_TLV_SIZE \
+	sizeof(struct mrvl_ie_auth_type)
+
+static int lbs_add_auth_type_tlv(u8 *tlv, enum nl80211_auth_type auth_type)
+{
+	struct mrvl_ie_auth_type *auth = (void *) tlv;
+
+	/*
+	 * 1f 01  TLV_TYPE_AUTH_TYPE
+	 * 01 00  len
+	 * 01     auth type
+	 */
+	auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+	auth->header.len = cpu_to_le16(sizeof(*auth)-sizeof(auth->header));
+	auth->auth = cpu_to_le16(lbs_auth_to_authtype(auth_type));
+	return sizeof(*auth);
+}
+
+
+/*
+ * Add channel (phy ds) TLV
+ */
+#define LBS_MAX_CHANNEL_TLV_SIZE \
+	sizeof(struct mrvl_ie_header)
+
+static int lbs_add_channel_tlv(u8 *tlv, u8 channel)
+{
+	struct mrvl_ie_ds_param_set *ds = (void *) tlv;
+
+	/*
+	 * 03 00  TLV_TYPE_PHY_DS
+	 * 01 00  len
+	 * 06     channel
+	 */
+	ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
+	ds->header.len = cpu_to_le16(sizeof(*ds)-sizeof(ds->header));
+	ds->channel = channel;
+	return sizeof(*ds);
+}
+
+
+/*
+ * Add (empty) CF param TLV of the form:
+ */
+#define LBS_MAX_CF_PARAM_TLV_SIZE		\
+	sizeof(struct mrvl_ie_header)
+
+static int lbs_add_cf_param_tlv(u8 *tlv)
+{
+	struct mrvl_ie_cf_param_set *cf = (void *)tlv;
+
+	/*
+	 * 04 00  TLV_TYPE_CF
+	 * 06 00  len
+	 * 00     cfpcnt
+	 * 00     cfpperiod
+	 * 00 00  cfpmaxduration
+	 * 00 00  cfpdurationremaining
+	 */
+	cf->header.type = cpu_to_le16(TLV_TYPE_CF);
+	cf->header.len = cpu_to_le16(sizeof(*cf)-sizeof(cf->header));
+	return sizeof(*cf);
+}
+
+/*
+ * Add WPA TLV
+ */
+#define LBS_MAX_WPA_TLV_SIZE			\
+	(sizeof(struct mrvl_ie_header)		\
+	 + 128 /* TODO: I guessed the size */)
+
+static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
+{
+	size_t tlv_len;
+
+	/*
+	 * We need just convert an IE to an TLV. IEs use u8 for the header,
+	 *   u8      type
+	 *   u8      len
+	 *   u8[]    data
+	 * but TLVs use __le16 instead:
+	 *   __le16  type
+	 *   __le16  len
+	 *   u8[]    data
+	 */
+	*tlv++ = *ie++;
+	*tlv++ = 0;
+	tlv_len = *tlv++ = *ie++;
+	*tlv++ = 0;
+	while (tlv_len--)
+		*tlv++ = *ie++;
+	/* the TLV is two bytes larger than the IE */
+	return ie_len + 2;
+}
+
+/***************************************************************************
+ * Set Channel
+ */
+
 static int lbs_cfg_set_channel(struct wiphy *wiphy,
 	struct net_device *netdev,
-	struct ieee80211_channel *chan,
+	struct ieee80211_channel *channel,
 	enum nl80211_channel_type channel_type)
 {
 	struct lbs_private *priv = wiphy_priv(wiphy);
 	int ret = -ENOTSUPP;
 
-	lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", chan->center_freq, channel_type);
+	lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
+			   channel->center_freq, channel_type);
 
 	if (channel_type != NL80211_CHAN_NO_HT)
 		goto out;
 
-	ret = lbs_set_channel(priv, chan->hw_value);
+	ret = lbs_set_channel(priv, channel->hw_value);
+
+ out:
+	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+	return ret;
+}
+
+
+
+/***************************************************************************
+ * Scanning
+ */
+
+/*
+ * When scanning, the firmware doesn't send a nul packet with the power-safe
+ * bit to the AP. So we cannot stay away from our current channel too long,
+ * otherwise we loose data. So take a "nap" while scanning every other
+ * while.
+ */
+#define LBS_SCAN_BEFORE_NAP 4
+
+
+/*
+ * When the firmware reports back a scan-result, it gives us an "u8 rssi",
+ * which isn't really an RSSI, as it becomes larger when moving away from
+ * the AP. Anyway, we need to convert that into mBm.
+ */
+#define LBS_SCAN_RSSI_TO_MBM(rssi) \
+	((-(int)rssi + 3)*100)
+
+static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
+	struct cmd_header *resp)
+{
+	struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
+	int bsssize;
+	const u8 *pos;
+	u16 nr_sets;
+	const u8 *tsfdesc;
+	int tsfsize;
+	int i;
+	int ret = -EILSEQ;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	bsssize = get_unaligned_le16(&scanresp->bssdescriptsize);
+	nr_sets = le16_to_cpu(resp->size);
+
+	/*
+	 * The general layout of the scan response is described in chapter
+	 * 5.7.1. Basically we have a common part, then any number of BSS
+	 * descriptor sections. Finally we have section with the same number
+	 * of TSFs.
+	 *
+	 * cmd_ds_802_11_scan_rsp
+	 *   cmd_header
+	 *   pos_size
+	 *   nr_sets
+	 *   bssdesc 1
+	 *     bssid
+	 *     rssi
+	 *     timestamp
+	 *     intvl
+	 *     capa
+	 *     IEs
+	 *   bssdesc 2
+	 *   bssdesc n
+	 *   MrvlIEtypes_TsfFimestamp_t
+	 *     TSF for BSS 1
+	 *     TSF for BSS 2
+	 *     TSF for BSS n
+	 */
+
+	pos = scanresp->bssdesc_and_tlvbuffer;
+
+	tsfdesc = pos + bsssize;
+	tsfsize = 4 + 8 * scanresp->nr_sets;
+
+	/* Validity check: we expect a Marvell-Local TLV */
+	i = get_unaligned_le16(tsfdesc);
+	tsfdesc += 2;
+	if (i != TLV_TYPE_TSFTIMESTAMP)
+		goto done;
+	/* Validity check: the TLV holds TSF values with 8 bytes each, so
+	 * the size in the TLV must match the nr_sets value */
+	i = get_unaligned_le16(tsfdesc);
+	tsfdesc += 2;
+	if (i / 8 != scanresp->nr_sets)
+		goto done;
+
+	for (i = 0; i < scanresp->nr_sets; i++) {
+		const u8 *bssid;
+		const u8 *ie;
+		int left;
+		int ielen;
+		int rssi;
+		u16 intvl;
+		u16 capa;
+		int chan_no = -1;
+		const u8 *ssid = NULL;
+		u8 ssid_len = 0;
+		DECLARE_SSID_BUF(ssid_buf);
+
+		int len = get_unaligned_le16(pos);
+		pos += 2;
+
+		/* BSSID */
+		bssid = pos;
+		pos += ETH_ALEN;
+		/* RSSI */
+		rssi = *pos++;
+		/* Packet time stamp */
+		pos += 8;
+		/* Beacon interval */
+		intvl = get_unaligned_le16(pos);
+		pos += 2;
+		/* Capabilities */
+		capa = get_unaligned_le16(pos);
+		pos += 2;
+
+		/* To find out the channel, we must parse the IEs */
+		ie = pos;
+		/* 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon
+		   interval, capabilities */
+		ielen = left = len - (6 + 1 + 8 + 2 + 2);
+		while (left >= 2) {
+			u8 id, elen;
+			id = *pos++;
+			elen = *pos++;
+			left -= 2;
+			if (elen > left || elen == 0)
+				goto done;
+			if (id == WLAN_EID_DS_PARAMS)
+				chan_no = *pos;
+			if (id == WLAN_EID_SSID) {
+				ssid = pos;
+				ssid_len = elen;
+			}
+			left -= elen;
+			pos += elen;
+		}
+
+		/* No channel, no luck */
+		if (chan_no != -1) {
+			struct wiphy *wiphy = priv->wdev->wiphy;
+			int freq = ieee80211_channel_to_frequency(chan_no);
+			struct ieee80211_channel *channel =
+				ieee80211_get_channel(wiphy, freq);
+
+			lbs_deb_scan("scan: %pM, capa %04x, chan %2d, %s, "
+				     "%d dBm\n",
+				     bssid, capa, chan_no,
+				     print_ssid(ssid_buf, ssid, ssid_len),
+				     LBS_SCAN_RSSI_TO_MBM(rssi)/100);
+
+			if (channel ||
+			    !(channel->flags & IEEE80211_CHAN_DISABLED))
+				cfg80211_inform_bss(wiphy, channel,
+					bssid, le64_to_cpu(*(__le64 *)tsfdesc),
+					capa, intvl, ie, ielen,
+					LBS_SCAN_RSSI_TO_MBM(rssi),
+					GFP_KERNEL);
+		}
+		tsfdesc += 8;
+	}
+	ret = 0;
+
+ done:
+	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
+	return ret;
+}
+
+
+/*
+ * Our scan command contains a TLV, consting of a SSID TLV, a channel list
+ * TLV and a rates TLV. Determine the maximum size of them:
+ */
+#define LBS_SCAN_MAX_CMD_SIZE			\
+	(sizeof(struct cmd_ds_802_11_scan)	\
+	 + LBS_MAX_SSID_TLV_SIZE		\
+	 + LBS_MAX_CHANNEL_LIST_TLV_SIZE	\
+	 + LBS_MAX_RATES_TLV_SIZE)
+
+/*
+ * Assumes priv->scan_req is initialized and valid
+ * Assumes priv->scan_channel is initialized
+ */
+static void lbs_scan_worker(struct work_struct *work)
+{
+	struct lbs_private *priv =
+		container_of(work, struct lbs_private, scan_work.work);
+	struct cmd_ds_802_11_scan *scan_cmd;
+	u8 *tlv; /* pointer into our current, growing TLV storage area */
+	int last_channel;
+	int running, carrier;
+
+	lbs_deb_enter(LBS_DEB_SCAN);
+
+	scan_cmd = kzalloc(LBS_SCAN_MAX_CMD_SIZE, GFP_KERNEL);
+	if (scan_cmd == NULL)
+		goto out_no_scan_cmd;
+
+	/* prepare fixed part of scan command */
+	scan_cmd->bsstype = CMD_BSS_TYPE_ANY;
+
+	/* stop network while we're away from our main channel */
+	running = !netif_queue_stopped(priv->dev);
+	carrier = netif_carrier_ok(priv->dev);
+	if (running)
+		netif_stop_queue(priv->dev);
+	if (carrier)
+		netif_carrier_off(priv->dev);
+
+	/* prepare fixed part of scan command */
+	tlv = scan_cmd->tlvbuffer;
+
+	/* add SSID TLV */
+	if (priv->scan_req->n_ssids)
+		tlv += lbs_add_ssid_tlv(tlv,
+					priv->scan_req->ssids[0].ssid,
+					priv->scan_req->ssids[0].ssid_len);
+
+	/* add channel TLVs */
+	last_channel = priv->scan_channel + LBS_SCAN_BEFORE_NAP;
+	if (last_channel > priv->scan_req->n_channels)
+		last_channel = priv->scan_req->n_channels;
+	tlv += lbs_add_channel_list_tlv(priv, tlv, last_channel,
+		priv->scan_req->n_ssids);
+
+	/* add rates TLV */
+	tlv += lbs_add_supported_rates_tlv(tlv);
+
+	if (priv->scan_channel < priv->scan_req->n_channels) {
+		cancel_delayed_work(&priv->scan_work);
+		queue_delayed_work(priv->work_thread, &priv->scan_work,
+			msecs_to_jiffies(300));
+	}
+
+	/* This is the final data we are about to send */
+	scan_cmd->hdr.size = cpu_to_le16(tlv - (u8 *)scan_cmd);
+	lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd,
+		    sizeof(*scan_cmd));
+	lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
+		    tlv - scan_cmd->tlvbuffer);
+
+	__lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr,
+		le16_to_cpu(scan_cmd->hdr.size),
+		lbs_ret_scan, 0);
+
+	if (priv->scan_channel >= priv->scan_req->n_channels) {
+		/* Mark scan done */
+		cfg80211_scan_done(priv->scan_req, false);
+		priv->scan_req = NULL;
+	}
+
+	/* Restart network */
+	if (carrier)
+		netif_carrier_on(priv->dev);
+	if (running && !priv->tx_pending_len)
+		netif_wake_queue(priv->dev);
+
+	kfree(scan_cmd);
+
+ out_no_scan_cmd:
+	lbs_deb_leave(LBS_DEB_SCAN);
+}
+
+
+static int lbs_cfg_scan(struct wiphy *wiphy,
+	struct net_device *dev,
+	struct cfg80211_scan_request *request)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	if (priv->scan_req || delayed_work_pending(&priv->scan_work)) {
+		/* old scan request not yet processed */
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n",
+		request->n_ssids, request->n_channels, request->ie_len);
+
+	priv->scan_channel = 0;
+	queue_delayed_work(priv->work_thread, &priv->scan_work,
+		msecs_to_jiffies(50));
+
+	if (priv->surpriseremoved)
+		ret = -EIO;
+
+	priv->scan_req = request;
 
  out:
 	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -101,8 +722,1145 @@
 
 
 
+/***************************************************************************
+ * Events
+ */
+
+void lbs_send_disconnect_notification(struct lbs_private *priv)
+{
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	cfg80211_disconnected(priv->dev,
+		0,
+		NULL, 0,
+		GFP_KERNEL);
+
+	lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
+{
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	cfg80211_michael_mic_failure(priv->dev,
+		priv->assoc_bss,
+		event == MACREG_INT_CODE_MIC_ERR_MULTICAST ?
+			NL80211_KEYTYPE_GROUP :
+			NL80211_KEYTYPE_PAIRWISE,
+		-1,
+		NULL,
+		GFP_KERNEL);
+
+	lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+
+
+
+/***************************************************************************
+ * Connect/disconnect
+ */
+
+
+/*
+ * This removes all WEP keys
+ */
+static int lbs_remove_wep_keys(struct lbs_private *priv)
+{
+	struct cmd_ds_802_11_set_wep cmd;
+	int ret;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.keyindex = cpu_to_le16(priv->wep_tx_key);
+	cmd.action = cpu_to_le16(CMD_ACT_REMOVE);
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
+
+	lbs_deb_leave(LBS_DEB_CFG80211);
+	return ret;
+}
+
+/*
+ * Set WEP keys
+ */
+static int lbs_set_wep_keys(struct lbs_private *priv)
+{
+	struct cmd_ds_802_11_set_wep cmd;
+	int i;
+	int ret;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	/*
+	 * command         13 00
+	 * size            50 00
+	 * sequence        xx xx
+	 * result          00 00
+	 * action          02 00     ACT_ADD
+	 * transmit key    00 00
+	 * type for key 1  01        WEP40
+	 * type for key 2  00
+	 * type for key 3  00
+	 * type for key 4  00
+	 * key 1           39 39 39 39 39 00 00 00
+	 *                 00 00 00 00 00 00 00 00
+	 * key 2           00 00 00 00 00 00 00 00
+	 *                 00 00 00 00 00 00 00 00
+	 * key 3           00 00 00 00 00 00 00 00
+	 *                 00 00 00 00 00 00 00 00
+	 * key 4           00 00 00 00 00 00 00 00
+	 */
+	if (priv->wep_key_len[0] || priv->wep_key_len[1] ||
+	    priv->wep_key_len[2] || priv->wep_key_len[3]) {
+		/* Only set wep keys if we have at least one of them */
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+		cmd.keyindex = cpu_to_le16(priv->wep_tx_key);
+		cmd.action = cpu_to_le16(CMD_ACT_ADD);
+
+		for (i = 0; i < 4; i++) {
+			switch (priv->wep_key_len[i]) {
+			case WLAN_KEY_LEN_WEP40:
+				cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
+				break;
+			case WLAN_KEY_LEN_WEP104:
+				cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
+				break;
+			default:
+				cmd.keytype[i] = 0;
+				break;
+			}
+			memcpy(cmd.keymaterial[i], priv->wep_key[i],
+			       priv->wep_key_len[i]);
+		}
+
+		ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
+	} else {
+		/* Otherwise remove all wep keys */
+		ret = lbs_remove_wep_keys(priv);
+	}
+
+	lbs_deb_leave(LBS_DEB_CFG80211);
+	return ret;
+}
+
+
+/*
+ * Enable/Disable RSN status
+ */
+static int lbs_enable_rsn(struct lbs_private *priv, int enable)
+{
+	struct cmd_ds_802_11_enable_rsn cmd;
+	int ret;
+
+	lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", enable);
+
+	/*
+	 * cmd       2f 00
+	 * size      0c 00
+	 * sequence  xx xx
+	 * result    00 00
+	 * action    01 00    ACT_SET
+	 * enable    01 00
+	 */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+	cmd.enable = cpu_to_le16(enable);
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
+
+	lbs_deb_leave(LBS_DEB_CFG80211);
+	return ret;
+}
+
+
+/*
+ * Set WPA/WPA key material
+ */
+
+/* like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we
+ * get rid of WEXT, this should go into host.h */
+
+struct cmd_key_material {
+	struct cmd_header hdr;
+
+	__le16 action;
+	struct MrvlIEtype_keyParamSet param;
+} __packed;
+
+static int lbs_set_key_material(struct lbs_private *priv,
+				int key_type,
+				int key_info,
+				u8 *key, u16 key_len)
+{
+	struct cmd_key_material cmd;
+	int ret;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	/*
+	 * Example for WPA (TKIP):
+	 *
+	 * cmd       5e 00
+	 * size      34 00
+	 * sequence  xx xx
+	 * result    00 00
+	 * action    01 00
+	 * TLV type  00 01    key param
+	 * length    00 26
+	 * key type  01 00    TKIP
+	 * key info  06 00    UNICAST | ENABLED
+	 * key len   20 00
+	 * key       32 bytes
+	 */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+	cmd.param.type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+	cmd.param.length = cpu_to_le16(sizeof(cmd.param) - 4);
+	cmd.param.keytypeid = cpu_to_le16(key_type);
+	cmd.param.keyinfo = cpu_to_le16(key_info);
+	cmd.param.keylen = cpu_to_le16(key_len);
+	if (key && key_len)
+		memcpy(cmd.param.key, key, key_len);
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
+
+	lbs_deb_leave(LBS_DEB_CFG80211);
+	return ret;
+}
+
+
+/*
+ * Sets the auth type (open, shared, etc) in the firmware. That
+ * we use CMD_802_11_AUTHENTICATE is misleading, this firmware
+ * command doesn't send an authentication frame at all, it just
+ * stores the auth_type.
+ */
+static int lbs_set_authtype(struct lbs_private *priv,
+			    struct cfg80211_connect_params *sme)
+{
+	struct cmd_ds_802_11_authenticate cmd;
+	int ret;
+
+	lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", sme->auth_type);
+
+	/*
+	 * cmd        11 00
+	 * size       19 00
+	 * sequence   xx xx
+	 * result     00 00
+	 * BSS id     00 13 19 80 da 30
+	 * auth type  00
+	 * reserved   00 00 00 00 00 00 00 00 00 00
+	 */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	if (sme->bssid)
+		memcpy(cmd.bssid, sme->bssid, ETH_ALEN);
+	/* convert auth_type */
+	ret = lbs_auth_to_authtype(sme->auth_type);
+	if (ret < 0)
+		goto done;
+
+	cmd.authtype = ret;
+	ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
+
+ done:
+	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+	return ret;
+}
+
+
+/*
+ * Create association request
+ */
+#define LBS_ASSOC_MAX_CMD_SIZE                     \
+	(sizeof(struct cmd_ds_802_11_associate)    \
+	 - 512 /* cmd_ds_802_11_associate.iebuf */ \
+	 + LBS_MAX_SSID_TLV_SIZE                   \
+	 + LBS_MAX_CHANNEL_TLV_SIZE                \
+	 + LBS_MAX_CF_PARAM_TLV_SIZE               \
+	 + LBS_MAX_AUTH_TYPE_TLV_SIZE              \
+	 + LBS_MAX_WPA_TLV_SIZE)
+
+static int lbs_associate(struct lbs_private *priv,
+		struct cfg80211_bss *bss,
+		struct cfg80211_connect_params *sme)
+{
+	struct cmd_ds_802_11_associate_response *resp;
+	struct cmd_ds_802_11_associate *cmd = kzalloc(LBS_ASSOC_MAX_CMD_SIZE,
+						      GFP_KERNEL);
+	const u8 *ssid_eid;
+	size_t len, resp_ie_len;
+	int status;
+	int ret;
+	u8 *pos = &(cmd->iebuf[0]);
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	if (!cmd) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	/*
+	 * cmd              50 00
+	 * length           34 00
+	 * sequence         xx xx
+	 * result           00 00
+	 * BSS id           00 13 19 80 da 30
+	 * capabilities     11 00
+	 * listen interval  0a 00
+	 * beacon interval  00 00
+	 * DTIM period      00
+	 * TLVs             xx   (up to 512 bytes)
+	 */
+	cmd->hdr.command = cpu_to_le16(CMD_802_11_ASSOCIATE);
+
+	/* Fill in static fields */
+	memcpy(cmd->bssid, bss->bssid, ETH_ALEN);
+	cmd->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
+	cmd->capability = cpu_to_le16(bss->capability);
+
+	/* add SSID TLV */
+	ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
+	if (ssid_eid)
+		pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]);
+	else
+		lbs_deb_assoc("no SSID\n");
+
+	/* add DS param TLV */
+	if (bss->channel)
+		pos += lbs_add_channel_tlv(pos, bss->channel->hw_value);
+	else
+		lbs_deb_assoc("no channel\n");
+
+	/* add (empty) CF param TLV */
+	pos += lbs_add_cf_param_tlv(pos);
+
+	/* add rates TLV */
+	pos += lbs_add_common_rates_tlv(pos, bss);
+
+	/* add auth type TLV */
+	if (priv->fwrelease >= 0x09000000)
+		pos += lbs_add_auth_type_tlv(pos, sme->auth_type);
+
+	/* add WPA/WPA2 TLV */
+	if (sme->ie && sme->ie_len)
+		pos += lbs_add_wpa_tlv(pos, sme->ie, sme->ie_len);
+
+	len = (sizeof(*cmd) - sizeof(cmd->iebuf)) +
+		(u16)(pos - (u8 *) &cmd->iebuf);
+	cmd->hdr.size = cpu_to_le16(len);
+
+	/* store for later use */
+	memcpy(priv->assoc_bss, bss->bssid, ETH_ALEN);
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_ASSOCIATE, cmd);
+	if (ret)
+		goto done;
+
+
+	/* generate connect message to cfg80211 */
+
+	resp = (void *) cmd; /* recast for easier field access */
+	status = le16_to_cpu(resp->statuscode);
+
+	/* Convert statis code of old firmware */
+	if (priv->fwrelease < 0x09000000)
+		switch (status) {
+		case 0:
+			break;
+		case 1:
+			lbs_deb_assoc("invalid association parameters\n");
+			status = WLAN_STATUS_CAPS_UNSUPPORTED;
+			break;
+		case 2:
+			lbs_deb_assoc("timer expired while waiting for AP\n");
+			status = WLAN_STATUS_AUTH_TIMEOUT;
+			break;
+		case 3:
+			lbs_deb_assoc("association refused by AP\n");
+			status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+			break;
+		case 4:
+			lbs_deb_assoc("authentication refused by AP\n");
+			status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+			break;
+		default:
+			lbs_deb_assoc("association failure %d\n", status);
+			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	lbs_deb_assoc("status %d, capability 0x%04x\n", status,
+		      le16_to_cpu(resp->capability));
+
+	resp_ie_len = le16_to_cpu(resp->hdr.size)
+		- sizeof(resp->hdr)
+		- 6;
+	cfg80211_connect_result(priv->dev,
+				priv->assoc_bss,
+				sme->ie, sme->ie_len,
+				resp->iebuf, resp_ie_len,
+				status,
+				GFP_KERNEL);
+
+	if (status == 0) {
+		/* TODO: get rid of priv->connect_status */
+		priv->connect_status = LBS_CONNECTED;
+		netif_carrier_on(priv->dev);
+		if (!priv->tx_pending_len)
+			netif_tx_wake_all_queues(priv->dev);
+	}
+
+
+done:
+	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+	return ret;
+}
+
+
+
+static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
+			   struct cfg80211_connect_params *sme)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+	struct cfg80211_bss *bss = NULL;
+	int ret = 0;
+	u8 preamble = RADIO_PREAMBLE_SHORT;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	if (sme->bssid) {
+		bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
+			sme->ssid, sme->ssid_len,
+			WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+	} else {
+		/*
+		 * Here we have an impedance mismatch. The firmware command
+		 * CMD_802_11_ASSOCIATE always needs a BSSID, it cannot
+		 * connect otherwise. However, for the connect-API of
+		 * cfg80211 the bssid is purely optional. We don't get one,
+		 * except the user specifies one on the "iw" command line.
+		 *
+		 * If we don't got one, we could initiate a scan and look
+		 * for the best matching cfg80211_bss entry.
+		 *
+		 * Or, better yet, net/wireless/sme.c get's rewritten into
+		 * something more generally useful.
+		 */
+		lbs_pr_err("TODO: no BSS specified\n");
+		ret = -ENOTSUPP;
+		goto done;
+	}
+
+
+	if (!bss) {
+		lbs_pr_err("assicate: bss %pM not in scan results\n",
+			   sme->bssid);
+		ret = -ENOENT;
+		goto done;
+	}
+	lbs_deb_assoc("trying %pM", sme->bssid);
+	lbs_deb_assoc("cipher 0x%x, key index %d, key len %d\n",
+		      sme->crypto.cipher_group,
+		      sme->key_idx, sme->key_len);
+
+	/* As this is a new connection, clear locally stored WEP keys */
+	priv->wep_tx_key = 0;
+	memset(priv->wep_key, 0, sizeof(priv->wep_key));
+	memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
+
+	/* set/remove WEP keys */
+	switch (sme->crypto.cipher_group) {
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+		/* Store provided WEP keys in priv-> */
+		priv->wep_tx_key = sme->key_idx;
+		priv->wep_key_len[sme->key_idx] = sme->key_len;
+		memcpy(priv->wep_key[sme->key_idx], sme->key, sme->key_len);
+		/* Set WEP keys and WEP mode */
+		lbs_set_wep_keys(priv);
+		priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
+		lbs_set_mac_control(priv);
+		/* No RSN mode for WEP */
+		lbs_enable_rsn(priv, 0);
+		break;
+	case 0: /* there's no WLAN_CIPHER_SUITE_NONE definition */
+		/*
+		 * If we don't have no WEP, no WPA and no WPA2,
+		 * we remove all keys like in the WPA/WPA2 setup,
+		 * we just don't set RSN.
+		 *
+		 * Therefore: fall-throught
+		 */
+	case WLAN_CIPHER_SUITE_TKIP:
+	case WLAN_CIPHER_SUITE_CCMP:
+		/* Remove WEP keys and WEP mode */
+		lbs_remove_wep_keys(priv);
+		priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
+		lbs_set_mac_control(priv);
+
+		/* clear the WPA/WPA2 keys */
+		lbs_set_key_material(priv,
+			KEY_TYPE_ID_WEP, /* doesn't matter */
+			KEY_INFO_WPA_UNICAST,
+			NULL, 0);
+		lbs_set_key_material(priv,
+			KEY_TYPE_ID_WEP, /* doesn't matter */
+			KEY_INFO_WPA_MCAST,
+			NULL, 0);
+		/* RSN mode for WPA/WPA2 */
+		lbs_enable_rsn(priv, sme->crypto.cipher_group != 0);
+		break;
+	default:
+		lbs_pr_err("unsupported cipher group 0x%x\n",
+			   sme->crypto.cipher_group);
+		ret = -ENOTSUPP;
+		goto done;
+	}
+
+	lbs_set_authtype(priv, sme);
+	lbs_set_radio(priv, preamble, 1);
+
+	/* Do the actual association */
+	lbs_associate(priv, bss, sme);
+
+ done:
+	if (bss)
+		cfg80211_put_bss(bss);
+	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+	return ret;
+}
+
+static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
+	u16 reason_code)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+	struct cmd_ds_802_11_deauthenticate cmd;
+
+	lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
+
+	/* store for lbs_cfg_ret_disconnect() */
+	priv->disassoc_reason = reason_code;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	/* Mildly ugly to use a locally store my own BSSID ... */
+	memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN);
+	cmd.reasoncode = cpu_to_le16(reason_code);
+
+	if (lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd))
+		return -EFAULT;
+
+	cfg80211_disconnected(priv->dev,
+			priv->disassoc_reason,
+			NULL, 0,
+			GFP_KERNEL);
+	priv->connect_status = LBS_DISCONNECTED;
+
+	return 0;
+}
+
+
+static int lbs_cfg_set_default_key(struct wiphy *wiphy,
+				   struct net_device *netdev,
+				   u8 key_index)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	if (key_index != priv->wep_tx_key) {
+		lbs_deb_assoc("set_default_key: to %d\n", key_index);
+		priv->wep_tx_key = key_index;
+		lbs_set_wep_keys(priv);
+	}
+
+	return 0;
+}
+
+
+static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
+			   u8 idx, const u8 *mac_addr,
+			   struct key_params *params)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+	u16 key_info;
+	u16 key_type;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n",
+		      params->cipher, mac_addr);
+	lbs_deb_assoc("add_key: key index %d, key len %d\n",
+		      idx, params->key_len);
+	if (params->key_len)
+		lbs_deb_hex(LBS_DEB_CFG80211, "KEY",
+			    params->key, params->key_len);
+
+	lbs_deb_assoc("add_key: seq len %d\n", params->seq_len);
+	if (params->seq_len)
+		lbs_deb_hex(LBS_DEB_CFG80211, "SEQ",
+			    params->seq, params->seq_len);
+
+	switch (params->cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+		/* actually compare if something has changed ... */
+		if ((priv->wep_key_len[idx] != params->key_len) ||
+			memcmp(priv->wep_key[idx],
+			       params->key, params->key_len) != 0) {
+			priv->wep_key_len[idx] = params->key_len;
+			memcpy(priv->wep_key[idx],
+			       params->key, params->key_len);
+			lbs_set_wep_keys(priv);
+		}
+		break;
+	case WLAN_CIPHER_SUITE_TKIP:
+	case WLAN_CIPHER_SUITE_CCMP:
+		key_info = KEY_INFO_WPA_ENABLED | ((idx == 0)
+						   ? KEY_INFO_WPA_UNICAST
+						   : KEY_INFO_WPA_MCAST);
+		key_type = (params->cipher == WLAN_CIPHER_SUITE_TKIP)
+			? KEY_TYPE_ID_TKIP
+			: KEY_TYPE_ID_AES;
+		lbs_set_key_material(priv,
+				     key_type,
+				     key_info,
+				     params->key, params->key_len);
+		break;
+	default:
+		lbs_pr_err("unhandled cipher 0x%x\n", params->cipher);
+		ret = -ENOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+
+static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
+			   u8 key_index, const u8 *mac_addr)
+{
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	lbs_deb_assoc("del_key: key_idx %d, mac_addr %pM\n",
+		      key_index, mac_addr);
+
+#ifdef TODO
+	struct lbs_private *priv = wiphy_priv(wiphy);
+	/*
+	 * I think can keep this a NO-OP, because:
+
+	 * - we clear all keys whenever we do lbs_cfg_connect() anyway
+	 * - neither "iw" nor "wpa_supplicant" won't call this during
+	 *   an ongoing connection
+	 * - TODO: but I have to check if this is still true when
+	 *   I set the AP to periodic re-keying
+	 * - we've not kzallec() something when we've added a key at
+	 *   lbs_cfg_connect() or lbs_cfg_add_key().
+	 *
+	 * This causes lbs_cfg_del_key() only called at disconnect time,
+	 * where we'd just waste time deleting a key that is not going
+	 * to be used anyway.
+	 */
+	if (key_index < 3 && priv->wep_key_len[key_index]) {
+		priv->wep_key_len[key_index] = 0;
+		lbs_set_wep_keys(priv);
+	}
+#endif
+
+	return 0;
+}
+
+
+/***************************************************************************
+ * Get station
+ */
+
+static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
+			      u8 *mac, struct station_info *sinfo)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+	s8 signal, noise;
+	int ret;
+	size_t i;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	sinfo->filled |= STATION_INFO_TX_BYTES |
+			 STATION_INFO_TX_PACKETS |
+			 STATION_INFO_RX_BYTES |
+			 STATION_INFO_RX_PACKETS;
+	sinfo->tx_bytes = priv->dev->stats.tx_bytes;
+	sinfo->tx_packets = priv->dev->stats.tx_packets;
+	sinfo->rx_bytes = priv->dev->stats.rx_bytes;
+	sinfo->rx_packets = priv->dev->stats.rx_packets;
+
+	/* Get current RSSI */
+	ret = lbs_get_rssi(priv, &signal, &noise);
+	if (ret == 0) {
+		sinfo->signal = signal;
+		sinfo->filled |= STATION_INFO_SIGNAL;
+	}
+
+	/* Convert priv->cur_rate from hw_value to NL80211 value */
+	for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
+		if (priv->cur_rate == lbs_rates[i].hw_value) {
+			sinfo->txrate.legacy = lbs_rates[i].bitrate;
+			sinfo->filled |= STATION_INFO_TX_BITRATE;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+
+
+
+/***************************************************************************
+ * "Site survey", here just current channel and noise level
+ */
+
+static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev,
+	int idx, struct survey_info *survey)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+	s8 signal, noise;
+	int ret;
+
+	if (idx != 0)
+		ret = -ENOENT;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	survey->channel = ieee80211_get_channel(wiphy,
+		ieee80211_channel_to_frequency(priv->channel));
+
+	ret = lbs_get_rssi(priv, &signal, &noise);
+	if (ret == 0) {
+		survey->filled = SURVEY_INFO_NOISE_DBM;
+		survey->noise = noise;
+	}
+
+	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+	return ret;
+}
+
+
+
+
+/***************************************************************************
+ * Change interface
+ */
+
+static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
+	enum nl80211_iftype type, u32 *flags,
+	       struct vif_params *params)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	switch (type) {
+	case NL80211_IFTYPE_MONITOR:
+		ret = lbs_set_monitor_mode(priv, 1);
+		break;
+	case NL80211_IFTYPE_STATION:
+		if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
+			ret = lbs_set_monitor_mode(priv, 0);
+		if (!ret)
+			ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1);
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
+			ret = lbs_set_monitor_mode(priv, 0);
+		if (!ret)
+			ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2);
+		break;
+	default:
+		ret = -ENOTSUPP;
+	}
+
+	if (!ret)
+		priv->wdev->iftype = type;
+
+	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+	return ret;
+}
+
+
+
+/***************************************************************************
+ * IBSS (Ad-Hoc)
+ */
+
+/* The firmware needs the following bits masked out of the beacon-derived
+ * capability field when associating/joining to a BSS:
+ *  9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
+ */
+#define CAPINFO_MASK (~(0xda00))
+
+
+static void lbs_join_post(struct lbs_private *priv,
+			  struct cfg80211_ibss_params *params,
+			  u8 *bssid, u16 capability)
+{
+	u8 fake_ie[2 + IEEE80211_MAX_SSID_LEN + /* ssid */
+		   2 + 4 +                      /* basic rates */
+		   2 + 1 +                      /* DS parameter */
+		   2 + 2 +                      /* atim */
+		   2 + 8];                      /* extended rates */
+	u8 *fake = fake_ie;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	/*
+	 * For cfg80211_inform_bss, we'll need a fake IE, as we can't get
+	 * the real IE from the firmware. So we fabricate a fake IE based on
+	 * what the firmware actually sends (sniffed with wireshark).
+	 */
+	/* Fake SSID IE */
+	*fake++ = WLAN_EID_SSID;
+	*fake++ = params->ssid_len;
+	memcpy(fake, params->ssid, params->ssid_len);
+	fake += params->ssid_len;
+	/* Fake supported basic rates IE */
+	*fake++ = WLAN_EID_SUPP_RATES;
+	*fake++ = 4;
+	*fake++ = 0x82;
+	*fake++ = 0x84;
+	*fake++ = 0x8b;
+	*fake++ = 0x96;
+	/* Fake DS channel IE */
+	*fake++ = WLAN_EID_DS_PARAMS;
+	*fake++ = 1;
+	*fake++ = params->channel->hw_value;
+	/* Fake IBSS params IE */
+	*fake++ = WLAN_EID_IBSS_PARAMS;
+	*fake++ = 2;
+	*fake++ = 0; /* ATIM=0 */
+	*fake++ = 0;
+	/* Fake extended rates IE, TODO: don't add this for 802.11b only,
+	 * but I don't know how this could be checked */
+	*fake++ = WLAN_EID_EXT_SUPP_RATES;
+	*fake++ = 8;
+	*fake++ = 0x0c;
+	*fake++ = 0x12;
+	*fake++ = 0x18;
+	*fake++ = 0x24;
+	*fake++ = 0x30;
+	*fake++ = 0x48;
+	*fake++ = 0x60;
+	*fake++ = 0x6c;
+	lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie);
+
+	cfg80211_inform_bss(priv->wdev->wiphy,
+			    params->channel,
+			    bssid,
+			    0,
+			    capability,
+			    params->beacon_interval,
+			    fake_ie, fake - fake_ie,
+			    0, GFP_KERNEL);
+
+	memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
+	priv->wdev->ssid_len = params->ssid_len;
+
+	cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL);
+
+	/* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */
+	priv->connect_status = LBS_CONNECTED;
+	netif_carrier_on(priv->dev);
+	if (!priv->tx_pending_len)
+		netif_wake_queue(priv->dev);
+
+	lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+static int lbs_ibss_join_existing(struct lbs_private *priv,
+	struct cfg80211_ibss_params *params,
+	struct cfg80211_bss *bss)
+{
+	const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+	struct cmd_ds_802_11_ad_hoc_join cmd;
+	u8 preamble = RADIO_PREAMBLE_SHORT;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	/* TODO: set preamble based on scan result */
+	ret = lbs_set_radio(priv, preamble, 1);
+	if (ret)
+		goto out;
+
+	/*
+	 * Example CMD_802_11_AD_HOC_JOIN command:
+	 *
+	 * command         2c 00         CMD_802_11_AD_HOC_JOIN
+	 * size            65 00
+	 * sequence        xx xx
+	 * result          00 00
+	 * bssid           02 27 27 97 2f 96
+	 * ssid            49 42 53 53 00 00 00 00
+	 *                 00 00 00 00 00 00 00 00
+	 *                 00 00 00 00 00 00 00 00
+	 *                 00 00 00 00 00 00 00 00
+	 * type            02            CMD_BSS_TYPE_IBSS
+	 * beacon period   64 00
+	 * dtim period     00
+	 * timestamp       00 00 00 00 00 00 00 00
+	 * localtime       00 00 00 00 00 00 00 00
+	 * IE DS           03
+	 * IE DS len       01
+	 * IE DS channel   01
+	 * reserveed       00 00 00 00
+	 * IE IBSS         06
+	 * IE IBSS len     02
+	 * IE IBSS atim    00 00
+	 * reserved        00 00 00 00
+	 * capability      02 00
+	 * rates           82 84 8b 96 0c 12 18 24 30 48 60 6c 00
+	 * fail timeout    ff 00
+	 * probe delay     00 00
+	 */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+	memcpy(cmd.bss.bssid, bss->bssid, ETH_ALEN);
+	memcpy(cmd.bss.ssid, params->ssid, params->ssid_len);
+	cmd.bss.type = CMD_BSS_TYPE_IBSS;
+	cmd.bss.beaconperiod = cpu_to_le16(params->beacon_interval);
+	cmd.bss.ds.header.id = WLAN_EID_DS_PARAMS;
+	cmd.bss.ds.header.len = 1;
+	cmd.bss.ds.channel = params->channel->hw_value;
+	cmd.bss.ibss.header.id = WLAN_EID_IBSS_PARAMS;
+	cmd.bss.ibss.header.len = 2;
+	cmd.bss.ibss.atimwindow = 0;
+	cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
+
+	/* set rates to the intersection of our rates and the rates in the
+	   bss */
+	if (!rates_eid) {
+		lbs_add_rates(cmd.bss.rates);
+	} else {
+		int hw, i;
+		u8 rates_max = rates_eid[1];
+		u8 *rates = cmd.bss.rates;
+		for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
+			u8 hw_rate = lbs_rates[hw].bitrate / 5;
+			for (i = 0; i < rates_max; i++) {
+				if (hw_rate == (rates_eid[i+2] & 0x7f)) {
+					u8 rate = rates_eid[i+2];
+					if (rate == 0x02 || rate == 0x04 ||
+					    rate == 0x0b || rate == 0x16)
+						rate |= 0x80;
+					*rates++ = rate;
+				}
+			}
+		}
+	}
+
+	/* Only v8 and below support setting this */
+	if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
+		cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+		cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
+	}
+	ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
+	if (ret)
+		goto out;
+
+	/*
+	 * This is a sample response to CMD_802_11_AD_HOC_JOIN:
+	 *
+	 * response        2c 80
+	 * size            09 00
+	 * sequence        xx xx
+	 * result          00 00
+	 * reserved        00
+	 */
+	lbs_join_post(priv, params, bss->bssid, bss->capability);
+
+ out:
+	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+	return ret;
+}
+
+
+
+static int lbs_ibss_start_new(struct lbs_private *priv,
+	struct cfg80211_ibss_params *params)
+{
+	struct cmd_ds_802_11_ad_hoc_start cmd;
+	struct cmd_ds_802_11_ad_hoc_result *resp =
+		(struct cmd_ds_802_11_ad_hoc_result *) &cmd;
+	u8 preamble = RADIO_PREAMBLE_SHORT;
+	int ret = 0;
+	u16 capability;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	ret = lbs_set_radio(priv, preamble, 1);
+	if (ret)
+		goto out;
+
+	/*
+	 * Example CMD_802_11_AD_HOC_START command:
+	 *
+	 * command         2b 00         CMD_802_11_AD_HOC_START
+	 * size            b1 00
+	 * sequence        xx xx
+	 * result          00 00
+	 * ssid            54 45 53 54 00 00 00 00
+	 *                 00 00 00 00 00 00 00 00
+	 *                 00 00 00 00 00 00 00 00
+	 *                 00 00 00 00 00 00 00 00
+	 * bss type        02
+	 * beacon period   64 00
+	 * dtim period     00
+	 * IE IBSS         06
+	 * IE IBSS len     02
+	 * IE IBSS atim    00 00
+	 * reserved        00 00 00 00
+	 * IE DS           03
+	 * IE DS len       01
+	 * IE DS channel   01
+	 * reserved        00 00 00 00
+	 * probe delay     00 00
+	 * capability      02 00
+	 * rates           82 84 8b 96   (basic rates with have bit 7 set)
+	 *                 0c 12 18 24 30 48 60 6c
+	 * padding         100 bytes
+	 */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	memcpy(cmd.ssid, params->ssid, params->ssid_len);
+	cmd.bsstype = CMD_BSS_TYPE_IBSS;
+	cmd.beaconperiod = cpu_to_le16(params->beacon_interval);
+	cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
+	cmd.ibss.header.len = 2;
+	cmd.ibss.atimwindow = 0;
+	cmd.ds.header.id = WLAN_EID_DS_PARAMS;
+	cmd.ds.header.len = 1;
+	cmd.ds.channel = params->channel->hw_value;
+	/* Only v8 and below support setting probe delay */
+	if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8)
+		cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
+	/* TODO: mix in WLAN_CAPABILITY_PRIVACY */
+	capability = WLAN_CAPABILITY_IBSS;
+	cmd.capability = cpu_to_le16(capability);
+	lbs_add_rates(cmd.rates);
+
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
+	if (ret)
+		goto out;
+
+	/*
+	 * This is a sample response to CMD_802_11_AD_HOC_JOIN:
+	 *
+	 * response        2b 80
+	 * size            14 00
+	 * sequence        xx xx
+	 * result          00 00
+	 * reserved        00
+	 * bssid           02 2b 7b 0f 86 0e
+	 */
+	lbs_join_post(priv, params, resp->bssid, capability);
+
+ out:
+	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+	return ret;
+}
+
+
+static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+		struct cfg80211_ibss_params *params)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+	int ret = 0;
+	struct cfg80211_bss *bss;
+	DECLARE_SSID_BUF(ssid_buf);
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	if (!params->channel) {
+		ret = -ENOTSUPP;
+		goto out;
+	}
+
+	ret = lbs_set_channel(priv, params->channel->hw_value);
+	if (ret)
+		goto out;
+
+	/* Search if someone is beaconing. This assumes that the
+	 * bss list is populated already */
+	bss = cfg80211_get_bss(wiphy, params->channel, params->bssid,
+		params->ssid, params->ssid_len,
+		WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
+
+	if (bss) {
+		ret = lbs_ibss_join_existing(priv, params, bss);
+		cfg80211_put_bss(bss);
+	} else
+		ret = lbs_ibss_start_new(priv, params);
+
+
+ out:
+	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+	return ret;
+}
+
+
+static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+	struct cmd_ds_802_11_ad_hoc_stop cmd;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
+
+	/* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */
+	lbs_mac_event_disconnected(priv);
+
+	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+	return ret;
+}
+
+
+
+
+/***************************************************************************
+ * Initialization
+ */
+
 static struct cfg80211_ops lbs_cfg80211_ops = {
 	.set_channel = lbs_cfg_set_channel,
+	.scan = lbs_cfg_scan,
+	.connect = lbs_cfg_connect,
+	.disconnect = lbs_cfg_disconnect,
+	.add_key = lbs_cfg_add_key,
+	.del_key = lbs_cfg_del_key,
+	.set_default_key = lbs_cfg_set_default_key,
+	.get_station = lbs_cfg_get_station,
+	.dump_survey = lbs_get_survey,
+	.change_virtual_intf = lbs_change_intf,
+	.join_ibss = lbs_join_ibss,
+	.leave_ibss = lbs_leave_ibss,
 };
 
 
@@ -142,6 +1900,36 @@
 }
 
 
+static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
+{
+	struct region_code_mapping {
+		const char *cn;
+		int code;
+	};
+
+	/* Section 5.17.2 */
+	static struct region_code_mapping regmap[] = {
+		{"US ", 0x10}, /* US FCC */
+		{"CA ", 0x20}, /* Canada */
+		{"EU ", 0x30}, /* ETSI   */
+		{"ES ", 0x31}, /* Spain  */
+		{"FR ", 0x32}, /* France */
+		{"JP ", 0x40}, /* Japan  */
+	};
+	size_t i;
+
+	lbs_deb_enter(LBS_DEB_CFG80211);
+
+	for (i = 0; i < ARRAY_SIZE(regmap); i++)
+		if (regmap[i].code == priv->regioncode) {
+			regulatory_hint(priv->wdev->wiphy, regmap[i].cn);
+			break;
+		}
+
+	lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+
 /*
  * This function get's called after lbs_setup_firmware() determined the
  * firmware capabities. So we can setup the wiphy according to our
@@ -157,10 +1945,12 @@
 	wdev->wiphy->max_scan_ssids = 1;
 	wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 
-	/* TODO: BIT(NL80211_IFTYPE_ADHOC); */
-	wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+	wdev->wiphy->interface_modes =
+			BIT(NL80211_IFTYPE_STATION) |
+			BIT(NL80211_IFTYPE_ADHOC);
+	if (lbs_rtap_supported(priv))
+		wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
 
-	/* TODO: honor priv->regioncode */
 	wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
 
 	/*
@@ -169,6 +1959,7 @@
 	 */
 	wdev->wiphy->cipher_suites = cipher_suites;
 	wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+	wdev->wiphy->reg_notifier = lbs_reg_notifier;
 
 	ret = wiphy_register(wdev->wiphy);
 	if (ret < 0)
@@ -180,10 +1971,36 @@
 	if (ret)
 		lbs_pr_err("cannot register network device\n");
 
+	INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
+
+	lbs_cfg_set_regulatory_hint(priv);
+
 	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
 	return ret;
 }
 
+int lbs_reg_notifier(struct wiphy *wiphy,
+		struct regulatory_request *request)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+	int ret;
+
+	lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
+			"callback for domain %c%c\n", request->alpha2[0],
+			request->alpha2[1]);
+
+	ret = lbs_set_11d_domain_info(priv, request, wiphy->bands);
+
+	lbs_deb_leave(LBS_DEB_CFG80211);
+	return ret;
+}
+
+void lbs_scan_deinit(struct lbs_private *priv)
+{
+	lbs_deb_enter(LBS_DEB_CFG80211);
+	cancel_delayed_work_sync(&priv->scan_work);
+}
+
 
 void lbs_cfg_free(struct lbs_private *priv)
 {
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index e09a193..4f46bb7 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -1,16 +1,21 @@
 #ifndef __LBS_CFG80211_H__
 #define __LBS_CFG80211_H__
 
-#include "dev.h"
+struct device;
+struct lbs_private;
+struct regulatory_request;
+struct wiphy;
 
 struct wireless_dev *lbs_cfg_alloc(struct device *dev);
 int lbs_cfg_register(struct lbs_private *priv);
 void lbs_cfg_free(struct lbs_private *priv);
 
-int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
-	u8 ssid_len);
-int lbs_scan_networks(struct lbs_private *priv, int full_scan);
-void lbs_cfg_scan_worker(struct work_struct *work);
+int lbs_reg_notifier(struct wiphy *wiphy,
+		struct regulatory_request *request);
 
+void lbs_send_disconnect_notification(struct lbs_private *priv);
+void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
+
+void lbs_scan_deinit(struct lbs_private *priv);
 
 #endif
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index cdb9b96..7074592 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -6,18 +6,14 @@
 #include <linux/kfifo.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/if_arp.h>
 
-#include "host.h"
 #include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "assoc.h"
-#include "wext.h"
-#include "scan.h"
+#include "cfg.h"
 #include "cmd.h"
 
-
-static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
+#define CAL_NF(nf)		((s32)(-(s32)(nf)))
+#define CAL_RSSI(snr, nf)	((s32)((s32)(snr) + CAL_NF(nf)))
 
 /**
  *  @brief Simple callback that copies response back into command
@@ -70,6 +66,8 @@
 	switch (cmd) {
 	case CMD_802_11_RSSI:
 		return 1;
+	case CMD_802_11_HOST_SLEEP_CFG:
+		return 1;
 	default:
 		break;
 	}
@@ -77,30 +75,6 @@
 }
 
 /**
- *  @brief This function checks if the command is allowed.
- *
- *  @param priv         A pointer to lbs_private structure
- *  @return             allowed or not allowed.
- */
-
-static int lbs_is_cmd_allowed(struct lbs_private *priv)
-{
-	int ret = 1;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	if (!priv->is_auto_deep_sleep_enabled) {
-		if (priv->is_deep_sleep) {
-			lbs_deb_cmd("command not allowed in deep sleep\n");
-			ret = 0;
-		}
-	}
-
-	lbs_deb_leave(LBS_DEB_CMD);
-	return ret;
-}
-
-/**
  *  @brief Updates the hardware details like MAC address and regulatory region
  *
  *  @param priv    	A pointer to struct lbs_private structure
@@ -175,16 +149,28 @@
 	if (priv->mesh_dev)
 		memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
 
-	if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
-		ret = -1;
-		goto out;
-	}
-
 out:
 	lbs_deb_leave(LBS_DEB_CMD);
 	return ret;
 }
 
+static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,
+			struct cmd_header *resp)
+{
+	lbs_deb_enter(LBS_DEB_CMD);
+	if (priv->is_host_sleep_activated) {
+		priv->is_host_sleep_configured = 0;
+		if (priv->psstate == PS_STATE_FULL_POWER) {
+			priv->is_host_sleep_activated = 0;
+			wake_up_interruptible(&priv->host_sleep_q);
+		}
+	} else {
+		priv->is_host_sleep_configured = 1;
+	}
+	lbs_deb_leave(LBS_DEB_CMD);
+	return 0;
+}
+
 int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
 		struct wol_config *p_wol_config)
 {
@@ -202,12 +188,11 @@
 	else
 		cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;
 
-	ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config);
+	ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config.hdr,
+			le16_to_cpu(cmd_config.hdr.size),
+			lbs_ret_host_sleep_cfg, 0);
 	if (!ret) {
-		if (criteria) {
-			lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
-			priv->wol_criteria = criteria;
-		} else
+		if (p_wol_config)
 			memcpy((uint8_t *) p_wol_config,
 					(uint8_t *)&cmd_config.wol_conf,
 					sizeof(struct wol_config));
@@ -219,42 +204,49 @@
 }
 EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
 
-static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
-				   u16 cmd_action)
+/**
+ *  @brief Sets the Power Save mode
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *  @param cmd_action	The Power Save operation (PS_MODE_ACTION_ENTER_PS or
+ *                         PS_MODE_ACTION_EXIT_PS)
+ *  @param block	Whether to block on a response or not
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
 {
-	struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
+	struct cmd_ds_802_11_ps_mode cmd;
+	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
-				sizeof(struct cmd_header));
-	psm->action = cpu_to_le16(cmd_action);
-	psm->multipledtim = 0;
-	switch (cmd_action) {
-	case CMD_SUBCMD_ENTER_PS:
-		lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(cmd_action);
 
-		psm->locallisteninterval = 0;
-		psm->nullpktinterval = 0;
-		psm->multipledtim =
-		    cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
-		break;
-
-	case CMD_SUBCMD_EXIT_PS:
-		lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
-		break;
-
-	case CMD_SUBCMD_SLEEP_CONFIRMED:
-		lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
-		break;
-
-	default:
-		break;
+	if (cmd_action == PS_MODE_ACTION_ENTER_PS) {
+		lbs_deb_cmd("PS_MODE: action ENTER_PS\n");
+		cmd.multipledtim = cpu_to_le16(1);  /* Default DTIM multiple */
+	} else if (cmd_action == PS_MODE_ACTION_EXIT_PS) {
+		lbs_deb_cmd("PS_MODE: action EXIT_PS\n");
+	} else {
+		/* We don't handle CONFIRM_SLEEP here because it needs to
+		 * be fastpathed to the firmware.
+		 */
+		lbs_deb_cmd("PS_MODE: unknown action 0x%X\n", cmd_action);
+		ret = -EOPNOTSUPP;
+		goto out;
 	}
 
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
+	if (block)
+		ret = lbs_cmd_with_response(priv, CMD_802_11_PS_MODE, &cmd);
+	else
+		lbs_cmd_async(priv, CMD_802_11_PS_MODE, &cmd.hdr, sizeof (cmd));
+
+out:
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
 }
 
 int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
@@ -353,6 +345,65 @@
 	return ret;
 }
 
+static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
+		unsigned long dummy,
+		struct cmd_header *cmd)
+{
+	lbs_deb_enter(LBS_DEB_FW);
+	priv->is_host_sleep_activated = 1;
+	wake_up_interruptible(&priv->host_sleep_q);
+	lbs_deb_leave(LBS_DEB_FW);
+	return 0;
+}
+
+int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
+{
+	struct cmd_header cmd;
+	int ret = 0;
+	uint32_t criteria = EHS_REMOVE_WAKEUP;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	if (host_sleep) {
+		if (priv->is_host_sleep_activated != 1) {
+			memset(&cmd, 0, sizeof(cmd));
+			ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
+					(struct wol_config *)NULL);
+			if (ret) {
+				lbs_pr_info("Host sleep configuration failed: "
+						"%d\n", ret);
+				return ret;
+			}
+			if (priv->psstate == PS_STATE_FULL_POWER) {
+				ret = __lbs_cmd(priv,
+						CMD_802_11_HOST_SLEEP_ACTIVATE,
+						&cmd,
+						sizeof(cmd),
+						lbs_ret_host_sleep_activate, 0);
+				if (ret)
+					lbs_pr_info("HOST_SLEEP_ACTIVATE "
+							"failed: %d\n", ret);
+			}
+
+			if (!wait_event_interruptible_timeout(
+						priv->host_sleep_q,
+						priv->is_host_sleep_activated,
+						(10 * HZ))) {
+				lbs_pr_err("host_sleep_q: timer expired\n");
+				ret = -1;
+			}
+		} else {
+			lbs_pr_err("host sleep: already enabled\n");
+		}
+	} else {
+		if (priv->is_host_sleep_activated)
+			ret = lbs_host_sleep_cfg(priv, criteria,
+					(struct wol_config *)NULL);
+	}
+
+	return ret;
+}
+
 /**
  *  @brief Set an SNMP MIB value
  *
@@ -509,23 +560,35 @@
 	return ret;
 }
 
-static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
-				      u16 cmd_action, void *pdata_buf)
+/**
+ *  @brief Enable or disable monitor mode (only implemented on OLPC usb8388 FW)
+ *
+ *  @param priv        A pointer to struct lbs_private structure
+ *  @param enable      1 to enable monitor mode, 0 to disable
+ *
+ *  @return            0 on success, error on failure
+ */
+int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
 {
-	struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;
+	struct cmd_ds_802_11_monitor_mode cmd;
+	int ret;
 
-	cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
-	cmd->size =
-	    cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
-			     sizeof(struct cmd_header));
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+	if (enable)
+		cmd.mode = cpu_to_le16(0x1);
 
-	monitor->action = cpu_to_le16(cmd_action);
-	if (cmd_action == CMD_ACT_SET) {
-		monitor->mode =
-		    cpu_to_le16((u16) (*(u32 *) pdata_buf));
+	lbs_deb_cmd("SET_MONITOR_MODE: %d\n", enable);
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_MONITOR_MODE, &cmd);
+	if (ret == 0) {
+		priv->dev->type = enable ? ARPHRD_IEEE80211_RADIOTAP :
+						ARPHRD_ETHER;
 	}
 
-	return 0;
+	lbs_deb_leave(LBS_DEB_CMD);
+	return ret;
 }
 
 /**
@@ -610,78 +673,242 @@
 	return ret;
 }
 
-static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
-			       u8 cmd_action, void *pdata_buf)
+/**
+ *  @brief Get current RSSI and noise floor
+ *
+ *  @param priv		A pointer to struct lbs_private structure
+ *  @param rssi		On successful return, signal level in mBm
+ *
+ *  @return 	   	The channel on success, error on failure
+ */
+int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
 {
-	struct lbs_offset_value *offval;
+	struct cmd_ds_802_11_rssi cmd;
+	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	offval = (struct lbs_offset_value *)pdata_buf;
+	BUG_ON(rssi == NULL);
+	BUG_ON(nf == NULL);
 
-	switch (le16_to_cpu(cmdptr->command)) {
-	case CMD_MAC_REG_ACCESS:
-		{
-			struct cmd_ds_mac_reg_access *macreg;
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	/* Average SNR over last 8 beacons */
+	cmd.n_or_snr = cpu_to_le16(8);
 
-			cmdptr->size =
-			    cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
-					+ sizeof(struct cmd_header));
-			macreg =
-			    (struct cmd_ds_mac_reg_access *)&cmdptr->params.
-			    macreg;
-
-			macreg->action = cpu_to_le16(cmd_action);
-			macreg->offset = cpu_to_le16((u16) offval->offset);
-			macreg->value = cpu_to_le32(offval->value);
-
-			break;
-		}
-
-	case CMD_BBP_REG_ACCESS:
-		{
-			struct cmd_ds_bbp_reg_access *bbpreg;
-
-			cmdptr->size =
-			    cpu_to_le16(sizeof
-					     (struct cmd_ds_bbp_reg_access)
-					     + sizeof(struct cmd_header));
-			bbpreg =
-			    (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
-			    bbpreg;
-
-			bbpreg->action = cpu_to_le16(cmd_action);
-			bbpreg->offset = cpu_to_le16((u16) offval->offset);
-			bbpreg->value = (u8) offval->value;
-
-			break;
-		}
-
-	case CMD_RF_REG_ACCESS:
-		{
-			struct cmd_ds_rf_reg_access *rfreg;
-
-			cmdptr->size =
-			    cpu_to_le16(sizeof
-					     (struct cmd_ds_rf_reg_access) +
-					     sizeof(struct cmd_header));
-			rfreg =
-			    (struct cmd_ds_rf_reg_access *)&cmdptr->params.
-			    rfreg;
-
-			rfreg->action = cpu_to_le16(cmd_action);
-			rfreg->offset = cpu_to_le16((u16) offval->offset);
-			rfreg->value = (u8) offval->value;
-
-			break;
-		}
-
-	default:
-		break;
+	ret = lbs_cmd_with_response(priv, CMD_802_11_RSSI, &cmd);
+	if (ret == 0) {
+		*nf = CAL_NF(le16_to_cpu(cmd.nf));
+		*rssi = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), le16_to_cpu(cmd.nf));
 	}
 
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
+}
+
+/**
+ *  @brief Send regulatory and 802.11d domain information to the firmware
+ *
+ *  @param priv		pointer to struct lbs_private
+ *  @param request	cfg80211 regulatory request structure
+ *  @param bands	the device's supported bands and channels
+ *
+ *  @return		0 on success, error code on failure
+*/
+int lbs_set_11d_domain_info(struct lbs_private *priv,
+			    struct regulatory_request *request,
+			    struct ieee80211_supported_band **bands)
+{
+	struct cmd_ds_802_11d_domain_info cmd;
+	struct mrvl_ie_domain_param_set *domain = &cmd.domain;
+	struct ieee80211_country_ie_triplet *t;
+	enum ieee80211_band band;
+	struct ieee80211_channel *ch;
+	u8 num_triplet = 0;
+	u8 num_parsed_chan = 0;
+	u8 first_channel = 0, next_chan = 0, max_pwr = 0;
+	u8 i, flag = 0;
+	size_t triplet_size;
+	int ret;
+
+	lbs_deb_enter(LBS_DEB_11D);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+
+	lbs_deb_11d("Setting country code '%c%c'\n",
+		    request->alpha2[0], request->alpha2[1]);
+
+	domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
+
+	/* Set country code */
+	domain->country_code[0] = request->alpha2[0];
+	domain->country_code[1] = request->alpha2[1];
+	domain->country_code[2] = ' ';
+
+	/* Now set up the channel triplets; firmware is somewhat picky here
+	 * and doesn't validate channel numbers and spans; hence it would
+	 * interpret a triplet of (36, 4, 20) as channels 36, 37, 38, 39.  Since
+	 * the last 3 aren't valid channels, the driver is responsible for
+	 * splitting that up into 4 triplet pairs of (36, 1, 20) + (40, 1, 20)
+	 * etc.
+	 */
+	for (band = 0;
+	     (band < IEEE80211_NUM_BANDS) && (num_triplet < MAX_11D_TRIPLETS);
+	     band++) {
+
+		if (!bands[band])
+			continue;
+
+		for (i = 0;
+		     (i < bands[band]->n_channels) && (num_triplet < MAX_11D_TRIPLETS);
+		     i++) {
+			ch = &bands[band]->channels[i];
+			if (ch->flags & IEEE80211_CHAN_DISABLED)
+				continue;
+
+			if (!flag) {
+				flag = 1;
+				next_chan = first_channel = (u32) ch->hw_value;
+				max_pwr = ch->max_power;
+				num_parsed_chan = 1;
+				continue;
+			}
+
+			if ((ch->hw_value == next_chan + 1) &&
+					(ch->max_power == max_pwr)) {
+				/* Consolidate adjacent channels */
+				next_chan++;
+				num_parsed_chan++;
+			} else {
+				/* Add this triplet */
+				lbs_deb_11d("11D triplet (%d, %d, %d)\n",
+					first_channel, num_parsed_chan,
+					max_pwr);
+				t = &domain->triplet[num_triplet];
+				t->chans.first_channel = first_channel;
+				t->chans.num_channels = num_parsed_chan;
+				t->chans.max_power = max_pwr;
+				num_triplet++;
+				flag = 0;
+			}
+		}
+
+		if (flag) {
+			/* Add last triplet */
+			lbs_deb_11d("11D triplet (%d, %d, %d)\n", first_channel,
+				num_parsed_chan, max_pwr);
+			t = &domain->triplet[num_triplet];
+			t->chans.first_channel = first_channel;
+			t->chans.num_channels = num_parsed_chan;
+			t->chans.max_power = max_pwr;
+			num_triplet++;
+		}
+	}
+
+	lbs_deb_11d("# triplets %d\n", num_triplet);
+
+	/* Set command header sizes */
+	triplet_size = num_triplet * sizeof(struct ieee80211_country_ie_triplet);
+	domain->header.len = cpu_to_le16(sizeof(domain->country_code) +
+					triplet_size);
+
+	lbs_deb_hex(LBS_DEB_11D, "802.11D domain param set",
+			(u8 *) &cmd.domain.country_code,
+			le16_to_cpu(domain->header.len));
+
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd.hdr) +
+				   sizeof(cmd.action) +
+				   sizeof(cmd.domain.header) +
+				   sizeof(cmd.domain.country_code) +
+				   triplet_size);
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd);
+
+	lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
+	return ret;
+}
+
+/**
+ *  @brief Read a MAC, Baseband, or RF register
+ *
+ *  @param priv		pointer to struct lbs_private
+ *  @param cmd		register command, one of CMD_MAC_REG_ACCESS,
+ *                        CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ *  @param offset       byte offset of the register to get
+ *  @param value        on success, the value of the register at 'offset'
+ *
+ *  @return		0 on success, error code on failure
+*/
+int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
+{
+	struct cmd_ds_reg_access cmd;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	BUG_ON(value == NULL);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_GET);
+
+	if (reg != CMD_MAC_REG_ACCESS &&
+	    reg != CMD_BBP_REG_ACCESS &&
+	    reg != CMD_RF_REG_ACCESS) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = lbs_cmd_with_response(priv, reg, &cmd);
+	if (ret) {
+		if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
+			*value = cmd.value.bbp_rf;
+		else if (reg == CMD_MAC_REG_ACCESS)
+			*value = le32_to_cpu(cmd.value.mac);
+	}
+
+out:
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
+}
+
+/**
+ *  @brief Write a MAC, Baseband, or RF register
+ *
+ *  @param priv		pointer to struct lbs_private
+ *  @param cmd		register command, one of CMD_MAC_REG_ACCESS,
+ *                        CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ *  @param offset       byte offset of the register to set
+ *  @param value        the value to write to the register at 'offset'
+ *
+ *  @return		0 on success, error code on failure
+*/
+int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
+{
+	struct cmd_ds_reg_access cmd;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+
+	if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
+		cmd.value.bbp_rf = (u8) (value & 0xFF);
+	else if (reg == CMD_MAC_REG_ACCESS)
+		cmd.value.mac = cpu_to_le32(value);
+	else {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = lbs_cmd_with_response(priv, reg, &cmd);
+
+out:
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
 }
 
 static void lbs_queue_cmd(struct lbs_private *priv,
@@ -704,14 +931,17 @@
 
 	/* Exit_PS command needs to be queued in the header always. */
 	if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
-		struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf[1];
+		struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf;
 
-		if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
+		if (psm->action == cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
 			if (priv->psstate != PS_STATE_FULL_POWER)
 				addtail = 0;
 		}
 	}
 
+	if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_WAKEUP_CONFIRM)
+		addtail = 0;
+
 	spin_lock_irqsave(&priv->driver_lock, flags);
 
 	if (addtail)
@@ -744,7 +974,6 @@
 
 	spin_lock_irqsave(&priv->driver_lock, flags);
 	priv->cur_cmd = cmdnode;
-	priv->cur_cmd_retcode = 0;
 	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 	cmdsize = le16_to_cpu(cmd->size);
@@ -817,9 +1046,6 @@
 void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
 			  int result)
 {
-	if (cmd == priv->cur_cmd)
-		priv->cur_cmd_retcode = result;
-
 	cmd->result = result;
 	cmd->cmdwaitqwoken = 1;
 	wake_up_interruptible(&cmd->cmdwait_q);
@@ -887,175 +1113,6 @@
 }
 
 /**
- *  @brief This function prepare the command before send to firmware.
- *
- *  @param priv		A pointer to struct lbs_private structure
- *  @param cmd_no	command number
- *  @param cmd_action	command action: GET or SET
- *  @param wait_option	wait option: wait response or not
- *  @param cmd_oid	cmd oid: treated as sub command
- *  @param pdata_buf	A pointer to informaion buffer
- *  @return 		0 or -1
- */
-int lbs_prepare_and_send_command(struct lbs_private *priv,
-			  u16 cmd_no,
-			  u16 cmd_action,
-			  u16 wait_option, u32 cmd_oid, void *pdata_buf)
-{
-	int ret = 0;
-	struct cmd_ctrl_node *cmdnode;
-	struct cmd_ds_command *cmdptr;
-	unsigned long flags;
-
-	lbs_deb_enter(LBS_DEB_HOST);
-
-	if (!priv) {
-		lbs_deb_host("PREP_CMD: priv is NULL\n");
-		ret = -1;
-		goto done;
-	}
-
-	if (priv->surpriseremoved) {
-		lbs_deb_host("PREP_CMD: card removed\n");
-		ret = -1;
-		goto done;
-	}
-
-	if (!lbs_is_cmd_allowed(priv)) {
-		ret = -EBUSY;
-		goto done;
-	}
-
-	cmdnode = lbs_get_cmd_ctrl_node(priv);
-
-	if (cmdnode == NULL) {
-		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
-
-		/* Wake up main thread to execute next command */
-		wake_up_interruptible(&priv->waitq);
-		ret = -1;
-		goto done;
-	}
-
-	cmdnode->callback = NULL;
-	cmdnode->callback_arg = (unsigned long)pdata_buf;
-
-	cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
-
-	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
-
-	/* Set sequence number, command and INT option */
-	priv->seqnum++;
-	cmdptr->seqnum = cpu_to_le16(priv->seqnum);
-
-	cmdptr->command = cpu_to_le16(cmd_no);
-	cmdptr->result = 0;
-
-	switch (cmd_no) {
-	case CMD_802_11_PS_MODE:
-		ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action);
-		break;
-
-	case CMD_MAC_REG_ACCESS:
-	case CMD_BBP_REG_ACCESS:
-	case CMD_RF_REG_ACCESS:
-		ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf);
-		break;
-
-	case CMD_802_11_MONITOR_MODE:
-		ret = lbs_cmd_802_11_monitor_mode(cmdptr,
-				          cmd_action, pdata_buf);
-		break;
-
-	case CMD_802_11_RSSI:
-		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
-		break;
-
-	case CMD_802_11_SET_AFC:
-	case CMD_802_11_GET_AFC:
-
-		cmdptr->command = cpu_to_le16(cmd_no);
-		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
-					   sizeof(struct cmd_header));
-
-		memmove(&cmdptr->params.afc,
-			pdata_buf, sizeof(struct cmd_ds_802_11_afc));
-
-		ret = 0;
-		goto done;
-
-	case CMD_802_11_TPC_CFG:
-		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
-		cmdptr->size =
-		    cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
-				     sizeof(struct cmd_header));
-
-		memmove(&cmdptr->params.tpccfg,
-			pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
-
-		ret = 0;
-		break;
-
-#ifdef CONFIG_LIBERTAS_MESH
-
-	case CMD_BT_ACCESS:
-		ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
-		break;
-
-	case CMD_FWT_ACCESS:
-		ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
-		break;
-
-#endif
-
-	case CMD_802_11_BEACON_CTRL:
-		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
-		break;
-	case CMD_802_11_DEEP_SLEEP:
-		cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
-		cmdptr->size = cpu_to_le16(sizeof(struct cmd_header));
-		break;
-	default:
-		lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
-		ret = -1;
-		break;
-	}
-
-	/* return error, since the command preparation failed */
-	if (ret != 0) {
-		lbs_deb_host("PREP_CMD: command preparation failed\n");
-		lbs_cleanup_and_insert_cmd(priv, cmdnode);
-		ret = -1;
-		goto done;
-	}
-
-	cmdnode->cmdwaitqwoken = 0;
-
-	lbs_queue_cmd(priv, cmdnode);
-	wake_up_interruptible(&priv->waitq);
-
-	if (wait_option & CMD_OPTION_WAITFORRSP) {
-		lbs_deb_host("PREP_CMD: wait for response\n");
-		might_sleep();
-		wait_event_interruptible(cmdnode->cmdwait_q,
-					 cmdnode->cmdwaitqwoken);
-	}
-
-	spin_lock_irqsave(&priv->driver_lock, flags);
-	if (priv->cur_cmd_retcode) {
-		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
-		       priv->cur_cmd_retcode);
-		priv->cur_cmd_retcode = 0;
-		ret = -1;
-	}
-	spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-done:
-	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
-	return ret;
-}
-
-/**
  *  @brief This function allocates the command buffer and link
  *  it to command free queue.
  *
@@ -1148,7 +1205,7 @@
  *  @param priv		A pointer to struct lbs_private structure
  *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
  */
-static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
+static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
 {
 	struct cmd_ctrl_node *tempnode;
 	unsigned long flags;
@@ -1231,10 +1288,10 @@
 			/*
 			 * 1. Non-PS command:
 			 * Queue it. set needtowakeup to TRUE if current state
-			 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
-			 * 2. PS command but not Exit_PS:
+			 * is SLEEP, otherwise call send EXIT_PS.
+			 * 2. PS command but not EXIT_PS:
 			 * Ignore it.
-			 * 3. PS command Exit_PS:
+			 * 3. PS command EXIT_PS:
 			 * Set needtowakeup to TRUE if current state is SLEEP,
 			 * otherwise send this command down to firmware
 			 * immediately.
@@ -1248,8 +1305,11 @@
 					/* w/ new scheme, it will not reach here.
 					   since it is blocked in main_thread. */
 					priv->needtowakeup = 1;
-				} else
-					lbs_ps_wakeup(priv, 0);
+				} else {
+					lbs_set_ps_mode(priv,
+							PS_MODE_ACTION_EXIT_PS,
+							false);
+				}
 
 				ret = 0;
 				goto done;
@@ -1264,7 +1324,7 @@
 				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
 				       psm->action);
 				if (psm->action !=
-				    cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
+				    cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
 					lbs_deb_host(
 					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
 					list_del(&cmdnode->list);
@@ -1303,6 +1363,15 @@
 		 * check if in power save mode, if yes, put the device back
 		 * to PS mode
 		 */
+#ifdef TODO
+		/*
+		 * This was the old code for libertas+wext. Someone that
+		 * understands this beast should re-code it in a sane way.
+		 *
+		 * I actually don't understand why this is related to WPA
+		 * and to connection status, shouldn't powering should be
+		 * independ of such things?
+		 */
 		if ((priv->psmode != LBS802_11POWERMODECAM) &&
 		    (priv->psstate == PS_STATE_FULL_POWER) &&
 		    ((priv->connect_status == LBS_CONNECTED) ||
@@ -1315,15 +1384,19 @@
 					lbs_deb_host(
 					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
 					       " go back to PS_SLEEP");
-					lbs_ps_sleep(priv, 0);
+					lbs_set_ps_mode(priv,
+							PS_MODE_ACTION_ENTER_PS,
+							false);
 				}
 			} else {
 				lbs_deb_host(
 				       "EXEC_NEXT_CMD: cmdpendingq empty, "
 				       "go back to PS_SLEEP");
-				lbs_ps_sleep(priv, 0);
+				lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,
+						false);
 			}
 		}
+#endif
 	}
 
 	ret = 0;
@@ -1353,6 +1426,11 @@
 	/* We don't get a response on the sleep-confirmation */
 	priv->dnld_sent = DNLD_RES_RECEIVED;
 
+	if (priv->is_host_sleep_configured) {
+		priv->is_host_sleep_activated = 1;
+		wake_up_interruptible(&priv->host_sleep_q);
+	}
+
 	/* If nothing to do, go back to sleep (?) */
 	if (!kfifo_len(&priv->event_fifo) && !priv->resp_len[priv->resp_idx])
 		priv->psstate = PS_STATE_SLEEP;
@@ -1363,43 +1441,6 @@
 	lbs_deb_leave(LBS_DEB_HOST);
 }
 
-void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
-{
-	lbs_deb_enter(LBS_DEB_HOST);
-
-	/*
-	 * PS is currently supported only in Infrastructure mode
-	 * Remove this check if it is to be supported in IBSS mode also
-	 */
-
-	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
-			      CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
-
-	lbs_deb_leave(LBS_DEB_HOST);
-}
-
-/**
- *  @brief This function sends Exit_PS command to firmware.
- *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param wait_option	wait response or not
- *  @return 	   	n/a
- */
-void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
-{
-	__le32 Localpsmode;
-
-	lbs_deb_enter(LBS_DEB_HOST);
-
-	Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
-
-	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
-			      CMD_SUBCMD_EXIT_PS,
-			      wait_option, 0, &Localpsmode);
-
-	lbs_deb_leave(LBS_DEB_HOST);
-}
-
 /**
  *  @brief This function checks condition and prepares to
  *  send sleep confirm command to firmware if ok.
@@ -1524,12 +1565,18 @@
 		goto done;
 	}
 
-	if (!lbs_is_cmd_allowed(priv)) {
-		cmdnode = ERR_PTR(-EBUSY);
-		goto done;
+	/* No commands are allowed in Deep Sleep until we toggle the GPIO
+	 * to wake up the card and it has signaled that it's ready.
+	 */
+	if (!priv->is_auto_deep_sleep_enabled) {
+		if (priv->is_deep_sleep) {
+			lbs_deb_cmd("command not allowed in deep sleep\n");
+			cmdnode = ERR_PTR(-EBUSY);
+			goto done;
+		}
 	}
 
-	cmdnode = lbs_get_cmd_ctrl_node(priv);
+	cmdnode = lbs_get_free_cmd_node(priv);
 	if (cmdnode == NULL) {
 		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
 
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index cb4138a..7109d6b 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -3,6 +3,8 @@
 #ifndef _LBS_CMD_H_
 #define _LBS_CMD_H_
 
+#include <net/cfg80211.h>
+
 #include "host.h"
 #include "dev.h"
 
@@ -37,11 +39,6 @@
 #define lbs_cmd_with_response(priv, cmdnr, cmd)	\
 	lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd))
 
-int lbs_prepare_and_send_command(struct lbs_private *priv,
-	u16 cmd_no,
-	u16 cmd_action,
-	u16 wait_option, u32 cmd_oid, void *pdata_buf);
-
 void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
 	struct cmd_header *in_cmd, int in_cmd_size);
 
@@ -92,10 +89,6 @@
 int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
 				struct sleep_params *sp);
 
-void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
-
-void lbs_ps_wakeup(struct lbs_private *priv, int wait_option);
-
 void lbs_ps_confirm_sleep(struct lbs_private *priv);
 
 int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
@@ -127,4 +120,20 @@
 
 int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
 
+int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep);
+
+int lbs_set_monitor_mode(struct lbs_private *priv, int enable);
+
+int lbs_get_rssi(struct lbs_private *priv, s8 *snr, s8 *nf);
+
+int lbs_set_11d_domain_info(struct lbs_private *priv,
+			    struct regulatory_request *request,
+			    struct ieee80211_supported_band **bands);
+
+int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value);
+
+int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value);
+
+int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block);
+
 #endif /* _LBS_CMD_H */
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 88f7131..5e95da9 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -5,18 +5,11 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
-#include <linux/if_arp.h>
-#include <linux/netdevice.h>
 #include <asm/unaligned.h>
-#include <net/iw_handler.h>
+#include <net/cfg80211.h>
 
-#include "host.h"
-#include "decl.h"
+#include "cfg.h"
 #include "cmd.h"
-#include "defs.h"
-#include "dev.h"
-#include "assoc.h"
-#include "wext.h"
 
 /**
  *  @brief This function handles disconnect event. it
@@ -38,7 +31,9 @@
 	 * It causes problem in the Supplicant
 	 */
 	msleep_interruptible(1000);
-	lbs_send_disconnect_notification(priv);
+
+	if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
+		lbs_send_disconnect_notification(priv);
 
 	/* report disconnect to upper layer */
 	netif_stop_queue(priv->dev);
@@ -49,141 +44,16 @@
 	priv->currenttxskb = NULL;
 	priv->tx_pending_len = 0;
 
-	/* reset SNR/NF/RSSI values */
-	memset(priv->SNR, 0x00, sizeof(priv->SNR));
-	memset(priv->NF, 0x00, sizeof(priv->NF));
-	memset(priv->RSSI, 0x00, sizeof(priv->RSSI));
-	memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
-	memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
-	priv->nextSNRNF = 0;
-	priv->numSNRNF = 0;
 	priv->connect_status = LBS_DISCONNECTED;
 
-	/* Clear out associated SSID and BSSID since connection is
-	 * no longer valid.
-	 */
-	memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
-	memset(&priv->curbssparams.ssid, 0, IEEE80211_MAX_SSID_LEN);
-	priv->curbssparams.ssid_len = 0;
-
 	if (priv->psstate != PS_STATE_FULL_POWER) {
 		/* make firmware to exit PS mode */
 		lbs_deb_cmd("disconnected, so exit PS mode\n");
-		lbs_ps_wakeup(priv, 0);
+		lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
 	}
 	lbs_deb_leave(LBS_DEB_ASSOC);
 }
 
-static int lbs_ret_reg_access(struct lbs_private *priv,
-			       u16 type, struct cmd_ds_command *resp)
-{
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	switch (type) {
-	case CMD_RET(CMD_MAC_REG_ACCESS):
-		{
-			struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
-
-			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
-			priv->offsetvalue.value = le32_to_cpu(reg->value);
-			break;
-		}
-
-	case CMD_RET(CMD_BBP_REG_ACCESS):
-		{
-			struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
-
-			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
-			priv->offsetvalue.value = reg->value;
-			break;
-		}
-
-	case CMD_RET(CMD_RF_REG_ACCESS):
-		{
-			struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
-
-			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
-			priv->offsetvalue.value = reg->value;
-			break;
-		}
-
-	default:
-		ret = -1;
-	}
-
-	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-	return ret;
-}
-
-static inline int handle_cmd_response(struct lbs_private *priv,
-				      struct cmd_header *cmd_response)
-{
-	struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
-	int ret = 0;
-	unsigned long flags;
-	uint16_t respcmd = le16_to_cpu(resp->command);
-
-	lbs_deb_enter(LBS_DEB_HOST);
-
-	switch (respcmd) {
-	case CMD_RET(CMD_MAC_REG_ACCESS):
-	case CMD_RET(CMD_BBP_REG_ACCESS):
-	case CMD_RET(CMD_RF_REG_ACCESS):
-		ret = lbs_ret_reg_access(priv, respcmd, resp);
-		break;
-
-	case CMD_RET(CMD_802_11_SET_AFC):
-	case CMD_RET(CMD_802_11_GET_AFC):
-		spin_lock_irqsave(&priv->driver_lock, flags);
-		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
-			sizeof(struct cmd_ds_802_11_afc));
-		spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-		break;
-
-	case CMD_RET(CMD_802_11_BEACON_STOP):
-		break;
-
-	case CMD_RET(CMD_802_11_RSSI):
-		ret = lbs_ret_802_11_rssi(priv, resp);
-		break;
-
-	case CMD_RET(CMD_802_11_TPC_CFG):
-		spin_lock_irqsave(&priv->driver_lock, flags);
-		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
-			sizeof(struct cmd_ds_802_11_tpc_cfg));
-		spin_unlock_irqrestore(&priv->driver_lock, flags);
-		break;
-
-	case CMD_RET(CMD_BT_ACCESS):
-		spin_lock_irqsave(&priv->driver_lock, flags);
-		if (priv->cur_cmd->callback_arg)
-			memcpy((void *)priv->cur_cmd->callback_arg,
-			       &resp->params.bt.addr1, 2 * ETH_ALEN);
-		spin_unlock_irqrestore(&priv->driver_lock, flags);
-		break;
-	case CMD_RET(CMD_FWT_ACCESS):
-		spin_lock_irqsave(&priv->driver_lock, flags);
-		if (priv->cur_cmd->callback_arg)
-			memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
-			       sizeof(resp->params.fwt));
-		spin_unlock_irqrestore(&priv->driver_lock, flags);
-		break;
-	case CMD_RET(CMD_802_11_BEACON_CTRL):
-		ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
-		break;
-
-	default:
-		lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
-			   le16_to_cpu(resp->command));
-		break;
-	}
-	lbs_deb_leave(LBS_DEB_HOST);
-	return ret;
-}
-
 int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
 {
 	uint16_t respcmd, curcmd;
@@ -242,9 +112,6 @@
 	del_timer(&priv->command_timer);
 	priv->cmd_timed_out = 0;
 
-	/* Store the response code to cur_cmd_retcode. */
-	priv->cur_cmd_retcode = result;
-
 	if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
 		struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
 		u16 action = le16_to_cpu(psmode->action);
@@ -261,10 +128,10 @@
 			 * ad-hoc mode. It takes place in
 			 * lbs_execute_next_command().
 			 */
-			if (priv->mode == IW_MODE_ADHOC &&
-			    action == CMD_SUBCMD_ENTER_PS)
+			if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR &&
+			    action == PS_MODE_ACTION_ENTER_PS)
 				priv->psmode = LBS802_11POWERMODECAM;
-		} else if (action == CMD_SUBCMD_ENTER_PS) {
+		} else if (action == PS_MODE_ACTION_ENTER_PS) {
 			priv->needtowakeup = 0;
 			priv->psstate = PS_STATE_AWAKE;
 
@@ -279,11 +146,12 @@
 
 				spin_unlock_irqrestore(&priv->driver_lock, flags);
 				mutex_unlock(&priv->lock);
-				lbs_ps_wakeup(priv, 0);
+				lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS,
+						false);
 				mutex_lock(&priv->lock);
 				spin_lock_irqsave(&priv->driver_lock, flags);
 			}
-		} else if (action == CMD_SUBCMD_EXIT_PS) {
+		} else if (action == PS_MODE_ACTION_EXIT_PS) {
 			priv->needtowakeup = 0;
 			priv->psstate = PS_STATE_FULL_POWER;
 			lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
@@ -324,8 +192,7 @@
 	if (priv->cur_cmd && priv->cur_cmd->callback) {
 		ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
 				resp);
-	} else
-		ret = handle_cmd_response(priv, resp);
+	}
 
 	spin_lock_irqsave(&priv->driver_lock, flags);
 
@@ -341,32 +208,10 @@
 	return ret;
 }
 
-static int lbs_send_confirmwake(struct lbs_private *priv)
-{
-	struct cmd_header cmd;
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_HOST);
-
-	cmd.command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM);
-	cmd.size = cpu_to_le16(sizeof(cmd));
-	cmd.seqnum = cpu_to_le16(++priv->seqnum);
-	cmd.result = 0;
-
-	lbs_deb_hex(LBS_DEB_HOST, "wake confirm", (u8 *) &cmd,
-		sizeof(cmd));
-
-	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd));
-	if (ret)
-		lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n");
-
-	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
-	return ret;
-}
-
 int lbs_process_event(struct lbs_private *priv, u32 event)
 {
 	int ret = 0;
+	struct cmd_header cmd;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
@@ -410,7 +255,10 @@
 		if (priv->reset_deep_sleep_wakeup)
 			priv->reset_deep_sleep_wakeup(priv);
 		priv->is_deep_sleep = 0;
-		lbs_send_confirmwake(priv);
+		lbs_cmd_async(priv, CMD_802_11_WAKEUP_CONFIRM, &cmd,
+				sizeof(cmd));
+		priv->is_host_sleep_activated = 0;
+		wake_up_interruptible(&priv->host_sleep_q);
 		break;
 
 	case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
@@ -441,7 +289,7 @@
 			 * in lbs_ps_wakeup()
 			 */
 			lbs_deb_cmd("waking up ...\n");
-			lbs_ps_wakeup(priv, 0);
+			lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
 		}
 		break;
 
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index de2caac..651a79c 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -1,18 +1,13 @@
-#include <linux/module.h>
 #include <linux/dcache.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/slab.h>
-#include <net/iw_handler.h>
-#include <net/lib80211.h>
 
-#include "dev.h"
 #include "decl.h"
-#include "host.h"
-#include "debugfs.h"
 #include "cmd.h"
+#include "debugfs.h"
 
 static struct dentry *lbs_dir;
 static char *szStates[] = {
@@ -60,51 +55,6 @@
 	return res;
 }
 
-
-static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
-				  size_t count, loff_t *ppos)
-{
-	struct lbs_private *priv = file->private_data;
-	size_t pos = 0;
-	int numscansdone = 0, res;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
-	DECLARE_SSID_BUF(ssid);
-	struct bss_descriptor * iter_bss;
-	if (!buf)
-		return -ENOMEM;
-
-	pos += snprintf(buf+pos, len-pos,
-		"# | ch  | rssi |       bssid       |   cap    | Qual | SSID\n");
-
-	mutex_lock(&priv->lock);
-	list_for_each_entry (iter_bss, &priv->network_list, list) {
-		u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
-		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 | %pM |",
-			numscansdone, iter_bss->channel, iter_bss->rssi,
-			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",
-		                print_ssid(ssid, iter_bss->ssid,
-					   iter_bss->ssid_len));
-
-		numscansdone++;
-	}
-	mutex_unlock(&priv->lock);
-
-	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-
-	free_page(addr);
-	return res;
-}
-
 static ssize_t lbs_sleepparams_write(struct file *file,
 				const char __user *user_buf, size_t count,
 				loff_t *ppos)
@@ -174,6 +124,70 @@
 	return ret;
 }
 
+static ssize_t lbs_host_sleep_write(struct file *file,
+				const char __user *user_buf, size_t count,
+				loff_t *ppos)
+{
+	struct lbs_private *priv = file->private_data;
+	ssize_t buf_size, ret;
+	int host_sleep;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+	if (!buf)
+		return -ENOMEM;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, user_buf, buf_size)) {
+		ret = -EFAULT;
+		goto out_unlock;
+	}
+	ret = sscanf(buf, "%d", &host_sleep);
+	if (ret != 1) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	if (host_sleep == 0)
+		ret = lbs_set_host_sleep(priv, 0);
+	else if (host_sleep == 1) {
+		if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
+			lbs_pr_info("wake parameters not configured");
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+		ret = lbs_set_host_sleep(priv, 1);
+	} else {
+		lbs_pr_err("invalid option\n");
+		ret = -EINVAL;
+	}
+
+	if (!ret)
+		ret = count;
+
+out_unlock:
+	free_page(addr);
+	return ret;
+}
+
+static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	struct lbs_private *priv = file->private_data;
+	ssize_t ret;
+	size_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+	if (!buf)
+		return -ENOMEM;
+
+	pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated);
+
+	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+	free_page(addr);
+	return ret;
+}
+
 /*
  * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
  * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
@@ -432,30 +446,24 @@
 }
 
 
-
 static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
 				  size_t count, loff_t *ppos)
 {
 	struct lbs_private *priv = file->private_data;
-	struct lbs_offset_value offval;
 	ssize_t pos = 0;
 	int ret;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
+	u32 val = 0;
+
 	if (!buf)
 		return -ENOMEM;
 
-	offval.offset = priv->mac_offset;
-	offval.value = 0;
-
-	ret = lbs_prepare_and_send_command(priv,
-				CMD_MAC_REG_ACCESS, 0,
-				CMD_OPTION_WAITFORRSP, 0, &offval);
+	ret = lbs_get_reg(priv, CMD_MAC_REG_ACCESS, priv->mac_offset, &val);
 	mdelay(10);
 	if (!ret) {
-		pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
-				priv->mac_offset, priv->offsetvalue.value);
-
+		pos = snprintf(buf, len, "MAC[0x%x] = 0x%08x\n",
+				priv->mac_offset, val);
 		ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	}
 	free_page(addr);
@@ -493,7 +501,6 @@
 	struct lbs_private *priv = file->private_data;
 	ssize_t res, buf_size;
 	u32 offset, value;
-	struct lbs_offset_value offval;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
 	if (!buf)
@@ -510,11 +517,7 @@
 		goto out_unlock;
 	}
 
-	offval.offset = offset;
-	offval.value = value;
-	res = lbs_prepare_and_send_command(priv,
-				CMD_MAC_REG_ACCESS, 1,
-				CMD_OPTION_WAITFORRSP, 0, &offval);
+	res = lbs_set_reg(priv, CMD_MAC_REG_ACCESS, offset, value);
 	mdelay(10);
 
 	if (!res)
@@ -528,25 +531,20 @@
 				  size_t count, loff_t *ppos)
 {
 	struct lbs_private *priv = file->private_data;
-	struct lbs_offset_value offval;
 	ssize_t pos = 0;
 	int ret;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
+	u32 val;
+
 	if (!buf)
 		return -ENOMEM;
 
-	offval.offset = priv->bbp_offset;
-	offval.value = 0;
-
-	ret = lbs_prepare_and_send_command(priv,
-				CMD_BBP_REG_ACCESS, 0,
-				CMD_OPTION_WAITFORRSP, 0, &offval);
+	ret = lbs_get_reg(priv, CMD_BBP_REG_ACCESS, priv->bbp_offset, &val);
 	mdelay(10);
 	if (!ret) {
-		pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
-				priv->bbp_offset, priv->offsetvalue.value);
-
+		pos = snprintf(buf, len, "BBP[0x%x] = 0x%08x\n",
+				priv->bbp_offset, val);
 		ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	}
 	free_page(addr);
@@ -585,7 +583,6 @@
 	struct lbs_private *priv = file->private_data;
 	ssize_t res, buf_size;
 	u32 offset, value;
-	struct lbs_offset_value offval;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
 	if (!buf)
@@ -602,11 +599,7 @@
 		goto out_unlock;
 	}
 
-	offval.offset = offset;
-	offval.value = value;
-	res = lbs_prepare_and_send_command(priv,
-				CMD_BBP_REG_ACCESS, 1,
-				CMD_OPTION_WAITFORRSP, 0, &offval);
+	res = lbs_set_reg(priv, CMD_BBP_REG_ACCESS, offset, value);
 	mdelay(10);
 
 	if (!res)
@@ -620,25 +613,20 @@
 				  size_t count, loff_t *ppos)
 {
 	struct lbs_private *priv = file->private_data;
-	struct lbs_offset_value offval;
 	ssize_t pos = 0;
 	int ret;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
+	u32 val;
+
 	if (!buf)
 		return -ENOMEM;
 
-	offval.offset = priv->rf_offset;
-	offval.value = 0;
-
-	ret = lbs_prepare_and_send_command(priv,
-				CMD_RF_REG_ACCESS, 0,
-				CMD_OPTION_WAITFORRSP, 0, &offval);
+	ret = lbs_get_reg(priv, CMD_RF_REG_ACCESS, priv->rf_offset, &val);
 	mdelay(10);
 	if (!ret) {
-		pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
-				priv->rf_offset, priv->offsetvalue.value);
-
+		pos = snprintf(buf, len, "RF[0x%x] = 0x%08x\n",
+				priv->rf_offset, val);
 		ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	}
 	free_page(addr);
@@ -677,7 +665,6 @@
 	struct lbs_private *priv = file->private_data;
 	ssize_t res, buf_size;
 	u32 offset, value;
-	struct lbs_offset_value offval;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
 	if (!buf)
@@ -694,11 +681,7 @@
 		goto out_unlock;
 	}
 
-	offval.offset = offset;
-	offval.value = value;
-	res = lbs_prepare_and_send_command(priv,
-				CMD_RF_REG_ACCESS, 1,
-				CMD_OPTION_WAITFORRSP, 0, &offval);
+	res = lbs_set_reg(priv, CMD_RF_REG_ACCESS, offset, value);
 	mdelay(10);
 
 	if (!res)
@@ -723,10 +706,10 @@
 
 static const struct lbs_debugfs_files debugfs_files[] = {
 	{ "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
-	{ "getscantable", 0444, FOPS(lbs_getscantable,
-					write_file_dummy), },
 	{ "sleepparams", 0644, FOPS(lbs_sleepparams_read,
 				lbs_sleepparams_write), },
+	{ "hostsleep", 0644, FOPS(lbs_host_sleep_read,
+				lbs_host_sleep_write), },
 };
 
 static const struct lbs_debugfs_files debugfs_events_files[] = {
@@ -891,7 +874,7 @@
 
 	p = buf;
 
-	d = (struct debug_data *)file->private_data;
+	d = file->private_data;
 
 	for (i = 0; i < num_of_items; i++) {
 		if (d[i].size == 1)
@@ -930,7 +913,7 @@
 	char *p0;
 	char *p1;
 	char *p2;
-	struct debug_data *d = (struct debug_data *)f->private_data;
+	struct debug_data *d = f->private_data;
 
 	pdata = kmalloc(cnt, GFP_KERNEL);
 	if (pdata == NULL)
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 709ffca..1d141fe 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -1,3 +1,4 @@
+
 /**
   *  This file contains declaration referring to
   *  functions defined in other source files
@@ -12,6 +13,7 @@
 struct lbs_private;
 struct sk_buff;
 struct net_device;
+struct cmd_ds_command;
 
 
 /* ethtool.c */
@@ -34,11 +36,13 @@
 void lbs_stop_card(struct lbs_private *priv);
 void lbs_host_to_card_done(struct lbs_private *priv);
 
+int lbs_rtap_supported(struct lbs_private *priv);
+
 int lbs_set_mac_address(struct net_device *dev, void *addr);
 void lbs_set_multicast_list(struct net_device *dev);
 
 int lbs_suspend(struct lbs_private *priv);
-void lbs_resume(struct lbs_private *priv);
+int lbs_resume(struct lbs_private *priv);
 
 void lbs_queue_event(struct lbs_private *priv, u32 event);
 void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
@@ -49,5 +53,4 @@
 u32 lbs_fw_index_to_data_rate(u8 index);
 u8 lbs_data_rate_to_fw_index(u32 rate);
 
-
 #endif
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index ea3f10e..d00c728 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -172,11 +172,6 @@
 #define MRVDRV_MAX_BSS_DESCRIPTS		16
 #define MRVDRV_MAX_REGION_CODE			6
 
-#define MRVDRV_IGNORE_MULTIPLE_DTIM		0xfffe
-#define MRVDRV_MIN_MULTIPLE_DTIM		1
-#define MRVDRV_MAX_MULTIPLE_DTIM		5
-#define MRVDRV_DEFAULT_MULTIPLE_DTIM		1
-
 #define MRVDRV_DEFAULT_LISTEN_INTERVAL		10
 
 #define	MRVDRV_CHANNELS_PER_SCAN		4
@@ -301,19 +296,6 @@
 #define	BAND_G			(0x02)
 #define ALL_802_11_BANDS	(BAND_B | BAND_G)
 
-/** MACRO DEFINITIONS */
-#define CAL_NF(NF)			((s32)(-(s32)(NF)))
-#define CAL_RSSI(SNR, NF) 		((s32)((s32)(SNR) + CAL_NF(NF)))
-#define SCAN_RSSI(RSSI)			(0x100 - ((u8)(RSSI)))
-
-#define DEFAULT_BCN_AVG_FACTOR		8
-#define DEFAULT_DATA_AVG_FACTOR		8
-#define AVG_SCALE			100
-#define CAL_AVG_SNR_NF(AVG, SNRNF, N)         \
-                        (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \
-                        ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
-                        AVG_SCALE))  / N))
-
 #define MAX_RATES			14
 
 #define	MAX_LEDS			8
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index a54880e..3c7e255 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -7,8 +7,8 @@
 #define _LBS_DEV_H_
 
 #include "mesh.h"
-#include "scan.h"
-#include "assoc.h"
+#include "defs.h"
+#include "host.h"
 
 #include <linux/kfifo.h>
 
@@ -29,7 +29,6 @@
 	/* Basic networking */
 	struct net_device *dev;
 	u32 connect_status;
-	int infra_open;
 	struct work_struct mcast_work;
 	u32 nr_of_multicastmacaddr;
 	u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
@@ -37,6 +36,9 @@
 	/* CFG80211 */
 	struct wireless_dev *wdev;
 	bool wiphy_registered;
+	struct cfg80211_scan_request *scan_req;
+	u8 assoc_bss[ETH_ALEN];
+	u8 disassoc_reason;
 
 	/* Mesh */
 	struct net_device *mesh_dev; /* Virtual device */
@@ -49,10 +51,6 @@
 	u8 mesh_ssid_len;
 #endif
 
-	/* Monitor mode */
-	struct net_device *rtap_net_dev;
-	u32 monitormode;
-
 	/* Debugfs */
 	struct dentry *debugfs_dir;
 	struct dentry *debugfs_debug;
@@ -66,7 +64,6 @@
 	u32 mac_offset;
 	u32 bbp_offset;
 	u32 rf_offset;
-	struct lbs_offset_value offsetvalue;
 
 	/* Power management */
 	u16 psmode;
@@ -75,6 +72,7 @@
 
 	/* Deep sleep */
 	int is_deep_sleep;
+	int deep_sleep_required;
 	int is_auto_deep_sleep_enabled;
 	int wakeup_dev_required;
 	int is_activity_detected;
@@ -82,6 +80,11 @@
 	wait_queue_head_t ds_awake_q;
 	struct timer_list auto_deepsleep_timer;
 
+	/* Host sleep*/
+	int is_host_sleep_configured;
+	int is_host_sleep_activated;
+	wait_queue_head_t host_sleep_q;
+
 	/* Hardware access */
 	void *card;
 	u8 fw_ready;
@@ -108,12 +111,10 @@
 	struct cmd_ctrl_node *cur_cmd;
 	struct list_head cmdfreeq;    /* free command buffers */
 	struct list_head cmdpendingq; /* pending command buffers */
-	wait_queue_head_t cmd_pending;
 	struct timer_list command_timer;
 	int cmd_timed_out;
 
 	/* Command responses sent from the hardware to the driver */
-	int cur_cmd_retcode;
 	u8 resp_idx;
 	u8 resp_buf[2][LBS_UPLD_SIZE];
 	u32 resp_len[2];
@@ -127,14 +128,10 @@
 	struct workqueue_struct *work_thread;
 
 	/** Encryption stuff */
-	struct lbs_802_11_security secinfo;
-	struct enc_key wpa_mcast_key;
-	struct enc_key wpa_unicast_key;
-	u8 wpa_ie[MAX_WPA_IE_LEN];
-	u8 wpa_ie_len;
-	u16 wep_tx_keyidx;
-	struct enc_key wep_keys[4];
 	u8 authtype_auto;
+	u8 wep_tx_key;
+	u8 wep_key[4][WLAN_KEY_LEN_WEP104];
+	u8 wep_key_len[4];
 
 	/* Wake On LAN */
 	uint32_t wol_criteria;
@@ -155,6 +152,7 @@
 	/* NIC/link operation characteristics */
 	u16 mac_control;
 	u8 radio_on;
+	u8 cur_rate;
 	u8 channel;
 	s16 txpower_cur;
 	s16 txpower_min;
@@ -163,42 +161,6 @@
 	/** Scanning */
 	struct delayed_work scan_work;
 	int scan_channel;
-	/* remember which channel was scanned last, != 0 if currently scanning */
-	u8 scan_ssid[IEEE80211_MAX_SSID_LEN + 1];
-	u8 scan_ssid_len;
-
-	/* Associating */
-	struct delayed_work assoc_work;
-	struct current_bss_params curbssparams;
-	u8 mode;
-	struct list_head network_list;
-	struct list_head network_free_list;
-	struct bss_descriptor *networks;
-	struct assoc_request * pending_assoc_req;
-	struct assoc_request * in_progress_assoc_req;
-	uint16_t enablehwauto;
-
-	/* ADHOC */
-	u16 beacon_period;
-	u8 beacon_enable;
-	u8 adhoccreate;
-
-	/* WEXT */
-	char name[DEV_NAME_LEN];
-	u8 nodename[16];
-	struct iw_statistics wstats;
-	u8 cur_rate;
-#define	MAX_REGION_CHANNEL_NUM	2
-	struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
-
-	/** Requested Signal Strength*/
-	u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
-	u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
-	u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
-	u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
-	u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
-	u16 nextSNRNF;
-	u16 numSNRNF;
 };
 
 extern struct cmd_confirm_sleep confirm_sleep;
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 3804a58..50193aa 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -2,13 +2,8 @@
 #include <linux/ethtool.h>
 #include <linux/delay.h>
 
-#include "host.h"
 #include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "wext.h"
 #include "cmd.h"
-#include "mesh.h"
 
 
 static void lbs_ethtool_get_drvinfo(struct net_device *dev,
@@ -69,14 +64,11 @@
 {
 	struct lbs_private *priv = dev->ml_priv;
 
-	if (priv->wol_criteria == 0xffffffff) {
-		/* Interface driver didn't configure wake */
-		wol->supported = wol->wolopts = 0;
-		return;
-	}
-
 	wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY;
 
+	if (priv->wol_criteria == EHS_REMOVE_WAKEUP)
+		return;
+
 	if (priv->wol_criteria & EHS_WAKE_ON_UNICAST_DATA)
 		wol->wolopts |= WAKE_UCAST;
 	if (priv->wol_criteria & EHS_WAKE_ON_MULTICAST_DATA)
@@ -91,23 +83,22 @@
 			       struct ethtool_wolinfo *wol)
 {
 	struct lbs_private *priv = dev->ml_priv;
-	uint32_t criteria = 0;
 
 	if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY))
 		return -EOPNOTSUPP;
 
+	priv->wol_criteria = 0;
 	if (wol->wolopts & WAKE_UCAST)
-		criteria |= EHS_WAKE_ON_UNICAST_DATA;
+		priv->wol_criteria |= EHS_WAKE_ON_UNICAST_DATA;
 	if (wol->wolopts & WAKE_MCAST)
-		criteria |= EHS_WAKE_ON_MULTICAST_DATA;
+		priv->wol_criteria |= EHS_WAKE_ON_MULTICAST_DATA;
 	if (wol->wolopts & WAKE_BCAST)
-		criteria |= EHS_WAKE_ON_BROADCAST_DATA;
+		priv->wol_criteria |= EHS_WAKE_ON_BROADCAST_DATA;
 	if (wol->wolopts & WAKE_PHY)
-		criteria |= EHS_WAKE_ON_MAC_EVENT;
+		priv->wol_criteria |= EHS_WAKE_ON_MAC_EVENT;
 	if (wol->wolopts == 0)
-		criteria |= EHS_REMOVE_WAKEUP;
-
-	return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL);
+		priv->wol_criteria |= EHS_REMOVE_WAKEUP;
+	return 0;
 }
 
 const struct ethtool_ops lbs_ethtool_ops = {
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 3809c0b..5eac135 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -94,11 +94,9 @@
 #define CMD_802_11_BEACON_CTRL                  0x00b0
 
 /* For the IEEE Power Save */
-#define CMD_SUBCMD_ENTER_PS                     0x0030
-#define CMD_SUBCMD_EXIT_PS                      0x0031
-#define CMD_SUBCMD_SLEEP_CONFIRMED              0x0034
-#define CMD_SUBCMD_FULL_POWERDOWN               0x0035
-#define CMD_SUBCMD_FULL_POWERUP                 0x0036
+#define PS_MODE_ACTION_ENTER_PS                 0x0030
+#define PS_MODE_ACTION_EXIT_PS                  0x0031
+#define PS_MODE_ACTION_SLEEP_CONFIRMED          0x0034
 
 #define CMD_ENABLE_RSN                          0x0001
 #define CMD_DISABLE_RSN                         0x0000
@@ -163,11 +161,6 @@
 #define CMD_ACT_SET_TX_FIX_RATE                 0x0001
 #define CMD_ACT_GET_TX_RATE                     0x0002
 
-/* Define action or option for CMD_802_11_PS_MODE */
-#define CMD_TYPE_CAM                            0x0000
-#define CMD_TYPE_MAX_PSP                        0x0001
-#define CMD_TYPE_FAST_PSP                       0x0002
-
 /* Options for CMD_802_11_FW_WAKE_METHOD */
 #define CMD_WAKE_METHOD_UNCHANGED               0x0000
 #define CMD_WAKE_METHOD_COMMAND_INT             0x0001
@@ -326,7 +319,7 @@
 	u8 pktdelay_2ms;
 	/* reserved */
 	u8 reserved1;
-} __attribute__ ((packed));
+} __packed;
 
 /* RxPD Descriptor */
 struct rxpd {
@@ -339,8 +332,8 @@
 			u8 bss_type;
 			/* BSS number */
 			u8 bss_num;
-		} __attribute__ ((packed)) bss;
-	} __attribute__ ((packed)) u;
+		} __packed bss;
+	} __packed u;
 
 	/* SNR */
 	u8 snr;
@@ -366,14 +359,14 @@
 	/* Pkt Priority */
 	u8 priority;
 	u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_header {
 	__le16 command;
 	__le16 size;
 	__le16 seqnum;
 	__le16 result;
-} __attribute__ ((packed));
+} __packed;
 
 /* Generic structure to hold all key types. */
 struct enc_key {
@@ -387,7 +380,23 @@
 struct lbs_offset_value {
 	u32 offset;
 	u32 value;
-} __attribute__ ((packed));
+} __packed;
+
+#define MAX_11D_TRIPLETS	83
+
+struct mrvl_ie_domain_param_set {
+	struct mrvl_ie_header header;
+
+	u8 country_code[3];
+	struct ieee80211_country_ie_triplet triplet[MAX_11D_TRIPLETS];
+} __packed;
+
+struct cmd_ds_802_11d_domain_info {
+	struct cmd_header hdr;
+
+	__le16 action;
+	struct mrvl_ie_domain_param_set domain;
+} __packed;
 
 /*
  * Define data structure for CMD_GET_HW_SPEC
@@ -426,7 +435,7 @@
 
 	/*FW/HW capability */
 	__le32 fwcapinfo;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_subscribe_event {
 	struct cmd_header hdr;
@@ -440,7 +449,7 @@
 	 * bump this up a bit.
 	 */
 	uint8_t tlv[128];
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * This scan handle Country Information IE(802.11d compliant)
@@ -452,7 +461,7 @@
 	uint8_t bsstype;
 	uint8_t bssid[ETH_ALEN];
 	uint8_t tlvbuffer[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_scan_rsp {
 	struct cmd_header hdr;
@@ -460,7 +469,7 @@
 	__le16 bssdescriptsize;
 	uint8_t nr_sets;
 	uint8_t bssdesc_and_tlvbuffer[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_get_log {
 	struct cmd_header hdr;
@@ -478,20 +487,20 @@
 	__le32 fcserror;
 	__le32 txframe;
 	__le32 wepundecryptable;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_mac_control {
 	struct cmd_header hdr;
 	__le16 action;
 	u16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_mac_multicast_adr {
 	struct cmd_header hdr;
 	__le16 action;
 	__le16 nr_of_adrs;
 	u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_authenticate {
 	struct cmd_header hdr;
@@ -499,14 +508,14 @@
 	u8 bssid[ETH_ALEN];
 	u8 authtype;
 	u8 reserved[10];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_deauthenticate {
 	struct cmd_header hdr;
 
 	u8 macaddr[ETH_ALEN];
 	__le16 reasoncode;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_associate {
 	struct cmd_header hdr;
@@ -517,7 +526,7 @@
 	__le16 bcnperiod;
 	u8 dtimperiod;
 	u8 iebuf[512];    /* Enough for required and most optional IEs */
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_associate_response {
 	struct cmd_header hdr;
@@ -526,7 +535,7 @@
 	__le16 statuscode;
 	__le16 aid;
 	u8 iebuf[512];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_set_wep {
 	struct cmd_header hdr;
@@ -540,7 +549,7 @@
 	/* 40, 128bit or TXWEP */
 	uint8_t keytype[4];
 	uint8_t keymaterial[4][16];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_snmp_mib {
 	struct cmd_header hdr;
@@ -549,40 +558,33 @@
 	__le16 oid;
 	__le16 bufsize;
 	u8 value[128];
-} __attribute__ ((packed));
+} __packed;
 
-struct cmd_ds_mac_reg_access {
+struct cmd_ds_reg_access {
+	struct cmd_header hdr;
+
 	__le16 action;
 	__le16 offset;
-	__le32 value;
-} __attribute__ ((packed));
-
-struct cmd_ds_bbp_reg_access {
-	__le16 action;
-	__le16 offset;
-	u8 value;
-	u8 reserved[3];
-} __attribute__ ((packed));
-
-struct cmd_ds_rf_reg_access {
-	__le16 action;
-	__le16 offset;
-	u8 value;
-	u8 reserved[3];
-} __attribute__ ((packed));
+	union {
+		u8 bbp_rf;  /* for BBP and RF registers */
+		__le32 mac; /* for MAC registers */
+	} value;
+} __packed;
 
 struct cmd_ds_802_11_radio_control {
 	struct cmd_header hdr;
 
 	__le16 action;
 	__le16 control;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_beacon_control {
+	struct cmd_header hdr;
+
 	__le16 action;
 	__le16 beacon_enable;
 	__le16 beacon_period;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_sleep_params {
 	struct cmd_header hdr;
@@ -607,7 +609,7 @@
 
 	/* reserved field, should be set to zero */
 	__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_rf_channel {
 	struct cmd_header hdr;
@@ -617,30 +619,30 @@
 	__le16 rftype;      /* unused */
 	__le16 reserved;    /* unused */
 	u8 channellist[32]; /* unused */
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_rssi {
-	/* weighting factor */
-	__le16 N;
+	struct cmd_header hdr;
 
-	__le16 reserved_0;
-	__le16 reserved_1;
-	__le16 reserved_2;
-} __attribute__ ((packed));
+	/* request:  number of beacons (N) to average the SNR and NF over
+	 * response: SNR of most recent beacon
+	 */
+	__le16 n_or_snr;
 
-struct cmd_ds_802_11_rssi_rsp {
-	__le16 SNR;
-	__le16 noisefloor;
-	__le16 avgSNR;
-	__le16 avgnoisefloor;
-} __attribute__ ((packed));
+	/* The following fields are only set in the response.
+	 * In the request these are reserved and should be set to 0.
+	 */
+	__le16 nf;       /* most recent beacon noise floor */
+	__le16 avg_snr;  /* average SNR weighted by N from request */
+	__le16 avg_nf;   /* average noise floor weighted by N from request */
+} __packed;
 
 struct cmd_ds_802_11_mac_address {
 	struct cmd_header hdr;
 
 	__le16 action;
 	u8 macadd[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_rf_tx_power {
 	struct cmd_header hdr;
@@ -649,34 +651,61 @@
 	__le16 curlevel;
 	s8 maxlevel;
 	s8 minlevel;
-} __attribute__ ((packed));
+} __packed;
 
+/* MONITOR_MODE only exists in OLPC v5 firmware */
 struct cmd_ds_802_11_monitor_mode {
+	struct cmd_header hdr;
+
 	__le16 action;
 	__le16 mode;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_set_boot2_ver {
 	struct cmd_header hdr;
 
 	__le16 action;
 	__le16 version;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_fw_wake_method {
 	struct cmd_header hdr;
 
 	__le16 action;
 	__le16 method;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_ps_mode {
+	struct cmd_header hdr;
+
 	__le16 action;
+
+	/* Interval for keepalive in PS mode:
+	 * 0x0000 = don't change
+	 * 0x001E = firmware default
+	 * 0xFFFF = disable
+	 */
 	__le16 nullpktinterval;
+
+	/* Number of DTIM intervals to wake up for:
+	 * 0 = don't change
+	 * 1 = firmware default
+	 * 5 = max
+	 */
 	__le16 multipledtim;
+
 	__le16 reserved;
 	__le16 locallisteninterval;
-} __attribute__ ((packed));
+
+	/* AdHoc awake period (FW v9+ only):
+	 * 0 = don't change
+	 * 1 = always awake (IEEE standard behavior)
+	 * 2 - 31 = sleep for (n - 1) periods and awake for 1 period
+	 * 32 - 254 = invalid
+	 * 255 = sleep at each ATIM
+	 */
+	__le16 adhoc_awake_period;
+} __packed;
 
 struct cmd_confirm_sleep {
 	struct cmd_header hdr;
@@ -686,7 +715,7 @@
 	__le16 multipledtim;
 	__le16 reserved;
 	__le16 locallisteninterval;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_data_rate {
 	struct cmd_header hdr;
@@ -694,14 +723,14 @@
 	__le16 action;
 	__le16 reserved;
 	u8 rates[MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_rate_adapt_rateset {
 	struct cmd_header hdr;
 	__le16 action;
 	__le16 enablehwauto;
 	__le16 bitmap;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_ad_hoc_start {
 	struct cmd_header hdr;
@@ -718,14 +747,14 @@
 	__le16 capability;
 	u8 rates[MAX_RATES];
 	u8 tlv_memory_size_pad[100];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_ad_hoc_result {
 	struct cmd_header hdr;
 
 	u8 pad[3];
 	u8 bssid[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
 
 struct adhoc_bssdesc {
 	u8 bssid[ETH_ALEN];
@@ -746,7 +775,7 @@
 	 * Adhoc join command and will cause a binary layout mismatch with
 	 * the firmware
 	 */
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_ad_hoc_join {
 	struct cmd_header hdr;
@@ -754,18 +783,18 @@
 	struct adhoc_bssdesc bss;
 	__le16 failtimeout;   /* Reserved on v9 and later */
 	__le16 probedelay;    /* Reserved on v9 and later */
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_ad_hoc_stop {
 	struct cmd_header hdr;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_enable_rsn {
 	struct cmd_header hdr;
 
 	__le16 action;
 	__le16 enable;
-} __attribute__ ((packed));
+} __packed;
 
 struct MrvlIEtype_keyParamSet {
 	/* type ID */
@@ -785,7 +814,7 @@
 
 	/* key material of size keylen */
 	u8 key[32];
-} __attribute__ ((packed));
+} __packed;
 
 #define MAX_WOL_RULES 		16
 
@@ -797,7 +826,7 @@
 	__le16 reserve;
 	__be32 sig_mask;
 	__be32 signature;
-} __attribute__ ((packed));
+} __packed;
 
 struct wol_config {
 	uint8_t action;
@@ -805,7 +834,7 @@
 	uint8_t no_rules_in_cmd;
 	uint8_t result;
 	struct host_wol_rule rule[MAX_WOL_RULES];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_host_sleep {
 	struct cmd_header hdr;
@@ -813,7 +842,7 @@
 	uint8_t gpio;
 	uint16_t gap;
 	struct wol_config wol_conf;
-} __attribute__ ((packed));
+} __packed;
 
 
 
@@ -822,7 +851,7 @@
 
 	__le16 action;
 	struct MrvlIEtype_keyParamSet keyParamSet[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_eeprom_access {
 	struct cmd_header hdr;
@@ -832,7 +861,7 @@
 	/* firmware says it returns a maximum of 20 bytes */
 #define LBS_EEPROM_READ_LEN 20
 	u8 value[LBS_EEPROM_READ_LEN];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_802_11_tpc_cfg {
 	struct cmd_header hdr;
@@ -843,7 +872,7 @@
 	int8_t P1;
 	int8_t P2;
 	uint8_t usesnr;
-} __attribute__ ((packed));
+} __packed;
 
 
 struct cmd_ds_802_11_pa_cfg {
@@ -854,16 +883,21 @@
 	int8_t P0;
 	int8_t P1;
 	int8_t P2;
-} __attribute__ ((packed));
+} __packed;
 
 
 struct cmd_ds_802_11_led_ctrl {
+	struct cmd_header hdr;
+
 	__le16 action;
 	__le16 numled;
 	u8 data[256];
-} __attribute__ ((packed));
+} __packed;
 
+/* Automatic Frequency Control */
 struct cmd_ds_802_11_afc {
+	struct cmd_header hdr;
+
 	__le16 afc_auto;
 	union {
 		struct {
@@ -875,24 +909,28 @@
 			__le16 carrier_offset; /* signed */
 		};
 	};
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_tx_rate_query {
 	__le16 txrate;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_get_tsf {
 	__le64 tsfvalue;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_bt_access {
+	struct cmd_header hdr;
+
 	__le16 action;
 	__le32 id;
 	u8 addr1[ETH_ALEN];
 	u8 addr2[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_fwt_access {
+	struct cmd_header hdr;
+
 	__le16 action;
 	__le32 id;
 	u8 valid;
@@ -910,7 +948,7 @@
 	__le32 snr;
 	__le32 references;
 	u8 prec[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_mesh_config {
 	struct cmd_header hdr;
@@ -920,43 +958,15 @@
 	__le16 type;
 	__le16 length;
 	u8 data[128];	/* last position reserved */
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_mesh_access {
 	struct cmd_header hdr;
 
 	__le16 action;
 	__le32 data[32];	/* last position reserved */
-} __attribute__ ((packed));
+} __packed;
 
 /* Number of stats counters returned by the firmware */
 #define MESH_STATS_NUM 8
-
-struct cmd_ds_command {
-	/* command header */
-	__le16 command;
-	__le16 size;
-	__le16 seqnum;
-	__le16 result;
-
-	/* command Body */
-	union {
-		struct cmd_ds_802_11_ps_mode psmode;
-		struct cmd_ds_802_11_monitor_mode monitor;
-		struct cmd_ds_802_11_rssi rssi;
-		struct cmd_ds_802_11_rssi_rsp rssirsp;
-		struct cmd_ds_mac_reg_access macreg;
-		struct cmd_ds_bbp_reg_access bbpreg;
-		struct cmd_ds_rf_reg_access rfreg;
-
-		struct cmd_ds_802_11_tpc_cfg tpccfg;
-		struct cmd_ds_802_11_afc afc;
-		struct cmd_ds_802_11_led_ctrl ledgpio;
-
-		struct cmd_ds_bt_access bt;
-		struct cmd_ds_fwt_access fwt;
-		struct cmd_ds_802_11_beacon_control bcn_ctrl;
-	} params;
-} __attribute__ ((packed));
-
 #endif
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 64dd345..6e71346 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -1182,11 +1182,69 @@
 	lbs_deb_leave(LBS_DEB_SDIO);
 }
 
+static int if_sdio_suspend(struct device *dev)
+{
+	struct sdio_func *func = dev_to_sdio_func(dev);
+	int ret;
+	struct if_sdio_card *card = sdio_get_drvdata(func);
+
+	mmc_pm_flag_t flags = sdio_get_host_pm_caps(func);
+
+	lbs_pr_info("%s: suspend: PM flags = 0x%x\n",
+						sdio_func_id(func), flags);
+
+	/* If we aren't being asked to wake on anything, we should bail out
+	 * and let the SD stack power down the card.
+	 */
+	if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) {
+		lbs_pr_info("Suspend without wake params -- "
+						"powering down card.");
+		return -ENOSYS;
+	}
+
+	if (!(flags & MMC_PM_KEEP_POWER)) {
+		lbs_pr_err("%s: cannot remain alive while host is suspended\n",
+			sdio_func_id(func));
+		return -ENOSYS;
+	}
+
+	ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+	if (ret)
+		return ret;
+
+	ret = lbs_suspend(card->priv);
+	if (ret)
+		return ret;
+
+	return sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+}
+
+static int if_sdio_resume(struct device *dev)
+{
+	struct sdio_func *func = dev_to_sdio_func(dev);
+	struct if_sdio_card *card = sdio_get_drvdata(func);
+	int ret;
+
+	lbs_pr_info("%s: resume: we're back\n", sdio_func_id(func));
+
+	ret = lbs_resume(card->priv);
+
+	return ret;
+}
+
+static const struct dev_pm_ops if_sdio_pm_ops = {
+	.suspend	= if_sdio_suspend,
+	.resume		= if_sdio_resume,
+};
+
 static struct sdio_driver if_sdio_driver = {
 	.name		= "libertas_sdio",
 	.id_table	= if_sdio_ids,
 	.probe		= if_sdio_probe,
 	.remove		= if_sdio_remove,
+	.drv = {
+		.pm = &if_sdio_pm_ops,
+	},
 };
 
 /*******************************************************************/
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index f41594c..07ece9d 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -433,7 +433,7 @@
 
 static int if_usb_reset_device(struct if_usb_card *cardp)
 {
-	struct cmd_ds_command *cmd = cardp->ep_out_buf + 4;
+	struct cmd_header *cmd = cardp->ep_out_buf + 4;
 	int ret;
 
 	lbs_deb_enter(LBS_DEB_USB);
@@ -441,7 +441,7 @@
 	*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
 
 	cmd->command = cpu_to_le16(CMD_802_11_RESET);
-	cmd->size = cpu_to_le16(sizeof(struct cmd_header));
+	cmd->size = cpu_to_le16(sizeof(cmd));
 	cmd->result = cpu_to_le16(0);
 	cmd->seqnum = cpu_to_le16(0x5a5a);
 	usb_tx_block(cardp, cardp->ep_out_buf, 4 + sizeof(struct cmd_header));
@@ -613,16 +613,14 @@
 		return;
 	}
 
-	syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
+	syncfwheader = kmemdup(skb->data + IPFIELD_ALIGN_OFFSET,
+			       sizeof(struct fwsyncheader), GFP_ATOMIC);
 	if (!syncfwheader) {
 		lbs_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
 		kfree_skb(skb);
 		return;
 	}
 
-	memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
-	       sizeof(struct fwsyncheader));
-
 	if (!syncfwheader->cmd) {
 		lbs_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
 		lbs_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
@@ -1043,6 +1041,12 @@
 	if (priv->psstate != PS_STATE_FULL_POWER)
 		return -1;
 
+	if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
+		lbs_pr_info("Suspend attempt without "
+						"configuring wake params!\n");
+		return -ENOSYS;
+	}
+
 	ret = lbs_suspend(priv);
 	if (ret)
 		goto out;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index d9b8ee1..2589671 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -11,20 +11,14 @@
 #include <linux/if_arp.h>
 #include <linux/kthread.h>
 #include <linux/kfifo.h>
-#include <linux/stddef.h>
-#include <linux/ieee80211.h>
 #include <linux/slab.h>
-#include <net/iw_handler.h>
 #include <net/cfg80211.h>
 
 #include "host.h"
 #include "decl.h"
 #include "dev.h"
-#include "wext.h"
 #include "cfg.h"
 #include "debugfs.h"
-#include "scan.h"
-#include "assoc.h"
 #include "cmd.h"
 
 #define DRIVER_RELEASE_VERSION "323.p0"
@@ -96,72 +90,6 @@
 }
 
 
-static int lbs_add_rtap(struct lbs_private *priv);
-static void lbs_remove_rtap(struct lbs_private *priv);
-
-
-/**
- * Get function for sysfs attribute rtap
- */
-static ssize_t lbs_rtap_get(struct device *dev,
-		struct device_attribute *attr, char * buf)
-{
-	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-	return snprintf(buf, 5, "0x%X\n", priv->monitormode);
-}
-
-/**
- *  Set function for sysfs attribute rtap
- */
-static ssize_t lbs_rtap_set(struct device *dev,
-		struct device_attribute *attr, const char * buf, size_t count)
-{
-	int monitor_mode;
-	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-
-	sscanf(buf, "%x", &monitor_mode);
-	if (monitor_mode) {
-		if (priv->monitormode == monitor_mode)
-			return strlen(buf);
-		if (!priv->monitormode) {
-			if (priv->infra_open || lbs_mesh_open(priv))
-				return -EBUSY;
-			if (priv->mode == IW_MODE_INFRA)
-				lbs_cmd_80211_deauthenticate(priv,
-							     priv->curbssparams.bssid,
-							     WLAN_REASON_DEAUTH_LEAVING);
-			else if (priv->mode == IW_MODE_ADHOC)
-				lbs_adhoc_stop(priv);
-			lbs_add_rtap(priv);
-		}
-		priv->monitormode = monitor_mode;
-	} else {
-		if (!priv->monitormode)
-			return strlen(buf);
-		priv->monitormode = 0;
-		lbs_remove_rtap(priv);
-
-		if (priv->currenttxskb) {
-			dev_kfree_skb_any(priv->currenttxskb);
-			priv->currenttxskb = NULL;
-		}
-
-		/* Wake queues, command thread, etc. */
-		lbs_host_to_card_done(priv);
-	}
-
-	lbs_prepare_and_send_command(priv,
-			CMD_802_11_MONITOR_MODE, CMD_ACT_SET,
-			CMD_OPTION_WAITFORRSP, 0, &priv->monitormode);
-	return strlen(buf);
-}
-
-/**
- * lbs_rtap attribute to be exported per ethX interface
- * through sysfs (/sys/class/net/ethX/lbs_rtap)
- */
-static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set );
-
 /**
  *  @brief This function opens the ethX interface
  *
@@ -177,13 +105,6 @@
 
 	spin_lock_irq(&priv->driver_lock);
 
-	if (priv->monitormode) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	priv->infra_open = 1;
-
 	if (priv->connect_status == LBS_CONNECTED)
 		netif_carrier_on(dev);
 	else
@@ -191,7 +112,6 @@
 
 	if (!priv->tx_pending_len)
 		netif_wake_queue(dev);
- out:
 
 	spin_unlock_irq(&priv->driver_lock);
 	lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
@@ -211,7 +131,6 @@
 	lbs_deb_enter(LBS_DEB_NET);
 
 	spin_lock_irq(&priv->driver_lock);
-	priv->infra_open = 0;
 	netif_stop_queue(dev);
 	spin_unlock_irq(&priv->driver_lock);
 
@@ -238,12 +157,7 @@
 	   to kick it somehow? */
 	lbs_host_to_card_done(priv);
 
-	/* More often than not, this actually happens because the
-	   firmware has crapped itself -- rather than just a very
-	   busy medium. So send a harmless command, and if/when
-	   _that_ times out, we'll kick it in the head. */
-	lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
-				     0, 0, NULL);
+	/* FIXME: reset the card */
 
 	lbs_deb_leave(LBS_DEB_TX);
 }
@@ -588,12 +502,6 @@
 		if (!priv->dnld_sent && !priv->cur_cmd)
 			lbs_execute_next_command(priv);
 
-		/* Wake-up command waiters which can't sleep in
-		 * lbs_prepare_and_send_command
-		 */
-		if (!list_empty(&priv->cmdpendingq))
-			wake_up_all(&priv->cmd_pending);
-
 		spin_lock_irq(&priv->driver_lock);
 		if (!priv->dnld_sent && priv->tx_pending_len > 0) {
 			int ret = priv->hw_host_to_card(priv, MVMS_DAT,
@@ -619,66 +527,58 @@
 
 	del_timer(&priv->command_timer);
 	del_timer(&priv->auto_deepsleep_timer);
-	wake_up_all(&priv->cmd_pending);
 
 	lbs_deb_leave(LBS_DEB_THREAD);
 	return 0;
 }
 
-static int lbs_suspend_callback(struct lbs_private *priv, unsigned long dummy,
-				struct cmd_header *cmd)
-{
-	lbs_deb_enter(LBS_DEB_FW);
-
-	netif_device_detach(priv->dev);
-	if (priv->mesh_dev)
-		netif_device_detach(priv->mesh_dev);
-
-	priv->fw_ready = 0;
-	lbs_deb_leave(LBS_DEB_FW);
-	return 0;
-}
-
 int lbs_suspend(struct lbs_private *priv)
 {
-	struct cmd_header cmd;
 	int ret;
 
 	lbs_deb_enter(LBS_DEB_FW);
 
-	if (priv->wol_criteria == 0xffffffff) {
-		lbs_pr_info("Suspend attempt without configuring wake params!\n");
-		return -EINVAL;
+	if (priv->is_deep_sleep) {
+		ret = lbs_set_deep_sleep(priv, 0);
+		if (ret) {
+			lbs_pr_err("deep sleep cancellation failed: %d\n", ret);
+			return ret;
+		}
+		priv->deep_sleep_required = 1;
 	}
 
-	memset(&cmd, 0, sizeof(cmd));
+	ret = lbs_set_host_sleep(priv, 1);
 
-	ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd,
-			sizeof(cmd), lbs_suspend_callback, 0);
-	if (ret)
-		lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret);
+	netif_device_detach(priv->dev);
+	if (priv->mesh_dev)
+		netif_device_detach(priv->mesh_dev);
 
 	lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(lbs_suspend);
 
-void lbs_resume(struct lbs_private *priv)
+int lbs_resume(struct lbs_private *priv)
 {
+	int ret;
+
 	lbs_deb_enter(LBS_DEB_FW);
 
-	priv->fw_ready = 1;
-
-	/* Firmware doesn't seem to give us RX packets any more
-	   until we send it some command. Might as well update */
-	lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
-				     0, 0, NULL);
+	ret = lbs_set_host_sleep(priv, 0);
 
 	netif_device_attach(priv->dev);
 	if (priv->mesh_dev)
 		netif_device_attach(priv->mesh_dev);
 
-	lbs_deb_leave(LBS_DEB_FW);
+	if (priv->deep_sleep_required) {
+		priv->deep_sleep_required = 0;
+		ret = lbs_set_deep_sleep(priv, 1);
+		if (ret)
+			lbs_pr_err("deep sleep activation failed: %d\n", ret);
+	}
+
+	lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(lbs_resume);
 
@@ -710,6 +610,9 @@
 		priv->txpower_max = maxlevel;
 	}
 
+	/* Send cmd to FW to enable 11D function */
+	ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1);
+
 	lbs_set_mac_control(priv);
 done:
 	lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
@@ -748,7 +651,6 @@
 static void auto_deepsleep_timer_fn(unsigned long data)
 {
 	struct lbs_private *priv = (struct lbs_private *)data;
-	int ret;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
@@ -756,14 +658,15 @@
 		priv->is_activity_detected = 0;
 	} else {
 		if (priv->is_auto_deep_sleep_enabled &&
-				(!priv->wakeup_dev_required) &&
-				(priv->connect_status != LBS_CONNECTED)) {
+		    (!priv->wakeup_dev_required) &&
+		    (priv->connect_status != LBS_CONNECTED)) {
+			struct cmd_header cmd;
+
 			lbs_deb_main("Entering auto deep sleep mode...\n");
-			ret = lbs_prepare_and_send_command(priv,
-					CMD_802_11_DEEP_SLEEP, 0,
-					0, 0, NULL);
-			if (ret)
-				lbs_pr_err("Enter Deep Sleep command failed\n");
+			memset(&cmd, 0, sizeof(cmd));
+			cmd.size = cpu_to_le16(sizeof(cmd));
+			lbs_cmd_async(priv, CMD_802_11_DEEP_SLEEP, &cmd,
+					sizeof(cmd));
 		}
 	}
 	mod_timer(&priv->auto_deepsleep_timer , jiffies +
@@ -799,45 +702,27 @@
 
 static int lbs_init_adapter(struct lbs_private *priv)
 {
-	size_t bufsize;
-	int i, ret = 0;
+	int ret;
 
 	lbs_deb_enter(LBS_DEB_MAIN);
 
-	/* Allocate buffer to store the BSSID list */
-	bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
-	priv->networks = kzalloc(bufsize, GFP_KERNEL);
-	if (!priv->networks) {
-		lbs_pr_err("Out of memory allocating beacons\n");
-		ret = -1;
-		goto out;
-	}
-
-	/* Initialize scan result lists */
-	INIT_LIST_HEAD(&priv->network_free_list);
-	INIT_LIST_HEAD(&priv->network_list);
-	for (i = 0; i < MAX_NETWORK_COUNT; i++) {
-		list_add_tail(&priv->networks[i].list,
-			      &priv->network_free_list);
-	}
-
 	memset(priv->current_addr, 0xff, ETH_ALEN);
 
 	priv->connect_status = LBS_DISCONNECTED;
-	priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-	priv->mode = IW_MODE_INFRA;
 	priv->channel = DEFAULT_AD_HOC_CHANNEL;
 	priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
 	priv->radio_on = 1;
-	priv->enablehwauto = 1;
 	priv->psmode = LBS802_11POWERMODECAM;
 	priv->psstate = PS_STATE_FULL_POWER;
 	priv->is_deep_sleep = 0;
 	priv->is_auto_deep_sleep_enabled = 0;
+	priv->deep_sleep_required = 0;
 	priv->wakeup_dev_required = 0;
 	init_waitqueue_head(&priv->ds_awake_q);
 	priv->authtype_auto = 1;
-
+	priv->is_host_sleep_configured = 0;
+	priv->is_host_sleep_activated = 0;
+	init_waitqueue_head(&priv->host_sleep_q);
 	mutex_init(&priv->lock);
 
 	setup_timer(&priv->command_timer, lbs_cmd_timeout_handler,
@@ -849,7 +734,6 @@
 	INIT_LIST_HEAD(&priv->cmdpendingq);
 
 	spin_lock_init(&priv->driver_lock);
-	init_waitqueue_head(&priv->cmd_pending);
 
 	/* Allocate the command buffers */
 	if (lbs_allocate_cmd_buffer(priv)) {
@@ -881,8 +765,6 @@
 	kfifo_free(&priv->event_fifo);
 	del_timer(&priv->command_timer);
 	del_timer(&priv->auto_deepsleep_timer);
-	kfree(priv->networks);
-	priv->networks = NULL;
 
 	lbs_deb_leave(LBS_DEB_MAIN);
 }
@@ -919,7 +801,7 @@
 		lbs_pr_err("cfg80211 init failed\n");
 		goto done;
 	}
-	/* TODO? */
+
 	wdev->iftype = NL80211_IFTYPE_STATION;
 	priv = wdev_priv(wdev);
 	priv->wdev = wdev;
@@ -929,7 +811,6 @@
 		goto err_wdev;
 	}
 
-	//TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
 	dev = alloc_netdev(0, "wlan%d", ether_setup);
 	if (!dev) {
 		dev_err(dmdev, "no memory for network device instance\n");
@@ -945,20 +826,10 @@
  	dev->netdev_ops = &lbs_netdev_ops;
 	dev->watchdog_timeo = 5 * HZ;
 	dev->ethtool_ops = &lbs_ethtool_ops;
-#ifdef	WIRELESS_EXT
-	dev->wireless_handlers = &lbs_handler_def;
-#endif
 	dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
 
-
-	// TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ??
-
-
 	priv->card = card;
-	priv->infra_open = 0;
 
-
-	priv->rtap_net_dev = NULL;
 	strcpy(dev->name, "wlan%d");
 
 	lbs_deb_thread("Starting main thread...\n");
@@ -970,12 +841,11 @@
 	}
 
 	priv->work_thread = create_singlethread_workqueue("lbs_worker");
-	INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
-	INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
 	INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
 
 	priv->wol_criteria = 0xffffffff;
 	priv->wol_gpio = 0xff;
+	priv->wol_gap = 20;
 
 	goto done;
 
@@ -1004,12 +874,10 @@
 	lbs_deb_enter(LBS_DEB_MAIN);
 
 	lbs_remove_mesh(priv);
-	lbs_remove_rtap(priv);
+	lbs_scan_deinit(priv);
 
 	dev = priv->dev;
 
-	cancel_delayed_work_sync(&priv->scan_work);
-	cancel_delayed_work_sync(&priv->assoc_work);
 	cancel_work_sync(&priv->mcast_work);
 
 	/* worker thread destruction blocks on the in-flight command which
@@ -1021,16 +889,18 @@
 
 	if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
 		priv->psmode = LBS802_11POWERMODECAM;
-		lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
+		lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, true);
 	}
 
-	lbs_send_disconnect_notification(priv);
-
 	if (priv->is_deep_sleep) {
 		priv->is_deep_sleep = 0;
 		wake_up_interruptible(&priv->ds_awake_q);
 	}
 
+	priv->is_host_sleep_configured = 0;
+	priv->is_host_sleep_activated = 0;
+	wake_up_interruptible(&priv->host_sleep_q);
+
 	/* Stop the thread servicing the interrupts */
 	priv->surpriseremoved = 1;
 	kthread_stop(priv->main_thread);
@@ -1046,7 +916,7 @@
 EXPORT_SYMBOL_GPL(lbs_remove_card);
 
 
-static int lbs_rtap_supported(struct lbs_private *priv)
+int lbs_rtap_supported(struct lbs_private *priv)
 {
 	if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
 		return 1;
@@ -1078,16 +948,6 @@
 
 	lbs_init_mesh(priv);
 
-	/*
-	 * While rtap isn't related to mesh, only mesh-enabled
-	 * firmware implements the rtap functionality via
-	 * CMD_802_11_MONITOR_MODE.
-	 */
-	if (lbs_rtap_supported(priv)) {
-		if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
-			lbs_pr_err("cannot register lbs_rtap attribute\n");
-	}
-
 	lbs_debugfs_init_one(priv, dev);
 
 	lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
@@ -1119,9 +979,6 @@
 	lbs_debugfs_remove_one(priv);
 	lbs_deinit_mesh(priv);
 
-	if (lbs_rtap_supported(priv))
-		device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
-
 	/* Delete the timeout of the currently processing command */
 	del_timer_sync(&priv->command_timer);
 	del_timer_sync(&priv->auto_deepsleep_timer);
@@ -1195,7 +1052,7 @@
 	memset(&confirm_sleep, 0, sizeof(confirm_sleep));
 	confirm_sleep.hdr.command = cpu_to_le16(CMD_802_11_PS_MODE);
 	confirm_sleep.hdr.size = cpu_to_le16(sizeof(confirm_sleep));
-	confirm_sleep.action = cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED);
+	confirm_sleep.action = cpu_to_le16(PS_MODE_ACTION_SLEEP_CONFIRMED);
 	lbs_debugfs_init();
 	lbs_deb_leave(LBS_DEB_MAIN);
 	return 0;
@@ -1208,87 +1065,6 @@
 	lbs_deb_leave(LBS_DEB_MAIN);
 }
 
-/*
- * rtap interface support fuctions
- */
-
-static int lbs_rtap_open(struct net_device *dev)
-{
-	/* Yes, _stop_ the queue. Because we don't support injection */
-	lbs_deb_enter(LBS_DEB_MAIN);
-	netif_carrier_off(dev);
-	netif_stop_queue(dev);
-	lbs_deb_leave(LBS_DEB_LEAVE);
-	return 0;
-}
-
-static int lbs_rtap_stop(struct net_device *dev)
-{
-	lbs_deb_enter(LBS_DEB_MAIN);
-	lbs_deb_leave(LBS_DEB_MAIN);
-	return 0;
-}
-
-static netdev_tx_t lbs_rtap_hard_start_xmit(struct sk_buff *skb,
-					    struct net_device *dev)
-{
-	netif_stop_queue(dev);
-	return NETDEV_TX_BUSY;
-}
-
-static void lbs_remove_rtap(struct lbs_private *priv)
-{
-	lbs_deb_enter(LBS_DEB_MAIN);
-	if (priv->rtap_net_dev == NULL)
-		goto out;
-	unregister_netdev(priv->rtap_net_dev);
-	free_netdev(priv->rtap_net_dev);
-	priv->rtap_net_dev = NULL;
-out:
-	lbs_deb_leave(LBS_DEB_MAIN);
-}
-
-static const struct net_device_ops rtap_netdev_ops = {
-	.ndo_open = lbs_rtap_open,
-	.ndo_stop = lbs_rtap_stop,
-	.ndo_start_xmit = lbs_rtap_hard_start_xmit,
-};
-
-static int lbs_add_rtap(struct lbs_private *priv)
-{
-	int ret = 0;
-	struct net_device *rtap_dev;
-
-	lbs_deb_enter(LBS_DEB_MAIN);
-	if (priv->rtap_net_dev) {
-		ret = -EPERM;
-		goto out;
-	}
-
-	rtap_dev = alloc_netdev(0, "rtap%d", ether_setup);
-	if (rtap_dev == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	memcpy(rtap_dev->dev_addr, priv->current_addr, ETH_ALEN);
-	rtap_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-	rtap_dev->netdev_ops = &rtap_netdev_ops;
-	rtap_dev->ml_priv = priv;
-	SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);
-
-	ret = register_netdev(rtap_dev);
-	if (ret) {
-		free_netdev(rtap_dev);
-		goto out;
-	}
-	priv->rtap_net_dev = rtap_dev;
-
-out:
-	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
-	return ret;
-}
-
 module_init(lbs_init_module);
 module_exit(lbs_exit_module);
 
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index e385af1..194762a 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -5,6 +5,7 @@
 #include <linux/if_arp.h>
 #include <linux/kthread.h>
 #include <linux/kfifo.h>
+#include <net/cfg80211.h>
 
 #include "mesh.h"
 #include "decl.h"
@@ -314,7 +315,7 @@
 
 	spin_lock_irq(&priv->driver_lock);
 
-	if (priv->monitormode) {
+	if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
 		ret = -EBUSY;
 		goto out;
 	}
@@ -369,9 +370,6 @@
 
 	SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
 
-#ifdef	WIRELESS_EXT
-	mesh_dev->wireless_handlers = &mesh_handler_def;
-#endif
 	mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
 	/* Register virtual mesh interface */
 	ret = register_netdev(mesh_dev);
@@ -457,65 +455,189 @@
  * Mesh command handling
  */
 
-int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
-			       u16 cmd_action, void *pdata_buf)
+/**
+ *  @brief Add or delete Mesh Blinding Table entries
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *  @param add  	TRUE to add the entry, FALSE to delete it
+ *  @param addr1        Destination address to blind or unblind
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1)
 {
-	struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
-	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
+	struct cmd_ds_bt_access cmd;
+	int ret = 0;
 
-	cmd->command = cpu_to_le16(CMD_BT_ACCESS);
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) +
-		sizeof(struct cmd_header));
-	cmd->result = 0;
-	bt_access->action = cpu_to_le16(cmd_action);
+	lbs_deb_enter(LBS_DEB_CMD);
 
-	switch (cmd_action) {
-	case CMD_ACT_BT_ACCESS_ADD:
-		memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
+	BUG_ON(addr1 == NULL);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	memcpy(cmd.addr1, addr1, ETH_ALEN);
+	if (add) {
+		cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_ADD);
 		lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr",
-			bt_access->addr1, 6);
-		break;
-	case CMD_ACT_BT_ACCESS_DEL:
-		memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
+			addr1, ETH_ALEN);
+	} else {
+		cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_DEL);
 		lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr",
-			bt_access->addr1, 6);
-		break;
-	case CMD_ACT_BT_ACCESS_LIST:
-		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
-		break;
-	case CMD_ACT_BT_ACCESS_RESET:
-		break;
-	case CMD_ACT_BT_ACCESS_SET_INVERT:
-		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
-		break;
-	case CMD_ACT_BT_ACCESS_GET_INVERT:
-		break;
-	default:
-		break;
+			addr1, ETH_ALEN);
 	}
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
+
+	ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
+
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
 }
 
-int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
-			       u16 cmd_action, void *pdata_buf)
+/**
+ *  @brief Reset/clear the mesh blinding table
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_mesh_bt_reset(struct lbs_private *priv)
 {
-	struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
+	struct cmd_ds_bt_access cmd;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_RESET);
+
+	ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
+
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
+}
+
+/**
+ *  @brief Gets the inverted status of the mesh blinding table
+ *
+ *  Normally the firmware "blinds" or ignores traffic from mesh nodes in the
+ *  table, but an inverted table allows *only* traffic from nodes listed in
+ *  the table.
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *  @param invert  	On success, TRUE if the blinding table is inverted,
+ *                        FALSE if it is not inverted
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted)
+{
+	struct cmd_ds_bt_access cmd;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	BUG_ON(inverted == NULL);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_GET_INVERT);
+
+	ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
+	if (ret == 0)
+		*inverted = !!cmd.id;
+
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
+}
+
+/**
+ *  @brief Sets the inverted status of the mesh blinding table
+ *
+ *  Normally the firmware "blinds" or ignores traffic from mesh nodes in the
+ *  table, but an inverted table allows *only* traffic from nodes listed in
+ *  the table.
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *  @param invert  	TRUE to invert the blinding table (only traffic from
+ *                         listed nodes allowed), FALSE to return it
+ *                         to normal state (listed nodes ignored)
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted)
+{
+	struct cmd_ds_bt_access cmd;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
+	cmd.id = !!inverted;
+
+	ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
+
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
+}
+
+/**
+ *  @brief List an entry in the mesh blinding table
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *  @param id		The ID of the entry to list
+ *  @param addr1	MAC address associated with the table entry
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1)
+{
+	struct cmd_ds_bt_access cmd;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	BUG_ON(addr1 == NULL);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
+	cmd.id = cpu_to_le32(id);
+
+	ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
+	if (ret == 0)
+		memcpy(addr1, cmd.addr1, sizeof(cmd.addr1));
+
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
+}
+
+/**
+ *  @brief Access the mesh forwarding table
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *  @param cmd_action	The forwarding table action to perform
+ *  @param cmd		The pre-filled FWT_ACCESS command
+ *
+ *  @return 	   	0 on success and 'cmd' will be filled with the
+ *                        firmware's response
+ */
+int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action,
+			struct cmd_ds_fwt_access *cmd)
+{
+	int ret;
+
 	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
 
-	cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) +
-		sizeof(struct cmd_header));
-	cmd->result = 0;
+	cmd->hdr.command = cpu_to_le16(CMD_FWT_ACCESS);
+	cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access));
+	cmd->hdr.result = 0;
+	cmd->action = cpu_to_le16(cmd_action);
 
-	if (pdata_buf)
-		memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
-	else
-		memset(fwt_access, 0, sizeof(*fwt_access));
+	ret = lbs_cmd_with_response(priv, CMD_FWT_ACCESS, cmd);
 
-	fwt_access->action = cpu_to_le16(cmd_action);
-
-	lbs_deb_leave(LBS_DEB_CMD);
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
 	return 0;
 }
 
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h
index e257330..afb2e8d 100644
--- a/drivers/net/wireless/libertas/mesh.h
+++ b/drivers/net/wireless/libertas/mesh.h
@@ -8,6 +8,7 @@
 #include <net/iw_handler.h>
 #include <net/lib80211.h>
 
+#include "host.h"
 
 #ifdef CONFIG_LIBERTAS_MESH
 
@@ -51,10 +52,15 @@
 struct cmd_ds_mesh_access;
 struct cmd_ds_mesh_config;
 
-int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
-	u16 cmd_action, void *pdata_buf);
-int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
-	u16 cmd_action, void *pdata_buf);
+int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1);
+int lbs_mesh_bt_reset(struct lbs_private *priv);
+int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted);
+int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted);
+int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1);
+
+int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action,
+			struct cmd_ds_fwt_access *cmd);
+
 int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
 		    struct cmd_ds_mesh_access *cmd);
 int lbs_mesh_config_send(struct lbs_private *priv,
@@ -70,11 +76,6 @@
 void lbs_persist_config_remove(struct net_device *net);
 
 
-/* WEXT handler */
-
-extern struct iw_handler_def mesh_handler_def;
-
-
 /* Ethtool statistics */
 
 struct ethtool_stats;
diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h
index d16b264..b3c8ea6 100644
--- a/drivers/net/wireless/libertas/radiotap.h
+++ b/drivers/net/wireless/libertas/radiotap.h
@@ -6,7 +6,7 @@
 	u8 txpower;
 	u8 rts_retries;
 	u8 data_retries;
-} __attribute__ ((packed));
+} __packed;
 
 #define TX_RADIOTAP_PRESENT (				\
 	(1 << IEEE80211_RADIOTAP_RATE) |		\
@@ -34,7 +34,7 @@
 	u8 flags;
 	u8 rate;
 	u8 antsignal;
-} __attribute__ ((packed));
+} __packed;
 
 #define RX_RADIOTAP_PRESENT (			\
 	(1 << IEEE80211_RADIOTAP_FLAGS) |	\
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 7a377f5..a4d0bca 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -4,18 +4,19 @@
 #include <linux/etherdevice.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <net/cfg80211.h>
 
+#include "defs.h"
 #include "host.h"
 #include "radiotap.h"
 #include "decl.h"
 #include "dev.h"
-#include "wext.h"
 
 struct eth803hdr {
 	u8 dest_addr[6];
 	u8 src_addr[6];
 	u16 h803_len;
-} __attribute__ ((packed));
+} __packed;
 
 struct rfc1042hdr {
 	u8 llc_dsap;
@@ -23,114 +24,22 @@
 	u8 llc_ctrl;
 	u8 snap_oui[3];
 	u16 snap_type;
-} __attribute__ ((packed));
+} __packed;
 
 struct rxpackethdr {
 	struct eth803hdr eth803_hdr;
 	struct rfc1042hdr rfc1042_hdr;
-} __attribute__ ((packed));
+} __packed;
 
 struct rx80211packethdr {
 	struct rxpd rx_pd;
 	void *eth80211_hdr;
-} __attribute__ ((packed));
+} __packed;
 
 static int process_rxed_802_11_packet(struct lbs_private *priv,
 	struct sk_buff *skb);
 
 /**
- *  @brief	This function computes the avgSNR .
- *
- *  @param	priv	A pointer to struct lbs_private structure
- *  @return	avgSNR
- */
-static u8 lbs_getavgsnr(struct lbs_private *priv)
-{
-	u8 i;
-	u16 temp = 0;
-	if (priv->numSNRNF == 0)
-		return 0;
-	for (i = 0; i < priv->numSNRNF; i++)
-		temp += priv->rawSNR[i];
-	return (u8) (temp / priv->numSNRNF);
-
-}
-
-/**
- *  @brief	This function computes the AvgNF
- *
- *  @param	priv	A pointer to struct lbs_private structure
- *  @return	AvgNF
- */
-static u8 lbs_getavgnf(struct lbs_private *priv)
-{
-	u8 i;
-	u16 temp = 0;
-	if (priv->numSNRNF == 0)
-		return 0;
-	for (i = 0; i < priv->numSNRNF; i++)
-		temp += priv->rawNF[i];
-	return (u8) (temp / priv->numSNRNF);
-
-}
-
-/**
- *  @brief	This function save the raw SNR/NF to our internel buffer
- *
- *  @param	priv	A pointer to struct lbs_private structure
- *  @param	prxpd	A pointer to rxpd structure of received packet
- *  @return	n/a
- */
-static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd)
-{
-	if (priv->numSNRNF < DEFAULT_DATA_AVG_FACTOR)
-		priv->numSNRNF++;
-	priv->rawSNR[priv->nextSNRNF] = p_rx_pd->snr;
-	priv->rawNF[priv->nextSNRNF] = p_rx_pd->nf;
-	priv->nextSNRNF++;
-	if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
-		priv->nextSNRNF = 0;
-}
-
-/**
- *  @brief	This function computes the RSSI in received packet.
- *
- *  @param	priv	A pointer to struct lbs_private structure
- *  @param	prxpd	A pointer to rxpd structure of received packet
- *  @return	n/a
- */
-static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd)
-{
-
-	lbs_deb_enter(LBS_DEB_RX);
-
-	lbs_deb_rx("rxpd: SNR %d, NF %d\n", p_rx_pd->snr, p_rx_pd->nf);
-	lbs_deb_rx("before computing SNR: SNR-avg = %d, NF-avg = %d\n",
-	       priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
-	       priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
-
-	priv->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
-	priv->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
-	lbs_save_rawSNRNF(priv, p_rx_pd);
-
-	priv->SNR[TYPE_RXPD][TYPE_AVG] = lbs_getavgsnr(priv) * AVG_SCALE;
-	priv->NF[TYPE_RXPD][TYPE_AVG] = lbs_getavgnf(priv) * AVG_SCALE;
-	lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n",
-	       priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
-	       priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
-
-	priv->RSSI[TYPE_RXPD][TYPE_NOAVG] =
-	    CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_NOAVG],
-		     priv->NF[TYPE_RXPD][TYPE_NOAVG]);
-
-	priv->RSSI[TYPE_RXPD][TYPE_AVG] =
-	    CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
-		     priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
-
-	lbs_deb_leave(LBS_DEB_RX);
-}
-
-/**
  *  @brief This function processes received packet and forwards it
  *  to kernel/upper layer
  *
@@ -154,7 +63,7 @@
 
 	skb->ip_summed = CHECKSUM_NONE;
 
-	if (priv->monitormode)
+	if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
 		return process_rxed_802_11_packet(priv, skb);
 
 	p_rx_pd = (struct rxpd *) skb->data;
@@ -225,13 +134,7 @@
 	 */
 	skb_pull(skb, hdrchop);
 
-	/* Take the data rate from the rxpd structure
-	 * only if the rate is auto
-	 */
-	if (priv->enablehwauto)
-		priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
-
-	lbs_compute_rssi(priv, p_rx_pd);
+	priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
 
 	lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
 	dev->stats.rx_bytes += skb->len;
@@ -352,20 +255,18 @@
 	pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr));
 	memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr));
 
-	/* Take the data rate from the rxpd structure
-	 * only if the rate is auto
-	 */
-	if (priv->enablehwauto)
-		priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
-
-	lbs_compute_rssi(priv, prxpd);
+	priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
 
 	lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
 	dev->stats.rx_bytes += skb->len;
 	dev->stats.rx_packets++;
 
-	skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);
-	netif_rx(skb);
+	skb->protocol = eth_type_trans(skb, priv->dev);
+
+	if (in_interrupt())
+		netif_rx(skb);
+	else
+		netif_rx_ni(skb);
 
 	ret = 0;
 
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
deleted file mode 100644
index 24cd54b..0000000
--- a/drivers/net/wireless/libertas/scan.c
+++ /dev/null
@@ -1,1354 +0,0 @@
-/**
-  * Functions implementing wlan scan IOCTL and firmware command APIs
-  *
-  * IOCTL handlers as well as command preperation and response routines
-  *  for sending scan commands to the firmware.
-  */
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <asm/unaligned.h>
-#include <net/lib80211.h>
-
-#include "host.h"
-#include "dev.h"
-#include "scan.h"
-#include "assoc.h"
-#include "wext.h"
-#include "cmd.h"
-
-//! Approximate amount of data needed to pass a scan result back to iwlist
-#define MAX_SCAN_CELL_SIZE  (IW_EV_ADDR_LEN             \
-                             + IEEE80211_MAX_SSID_LEN   \
-                             + IW_EV_UINT_LEN           \
-                             + IW_EV_FREQ_LEN           \
-                             + IW_EV_QUAL_LEN           \
-                             + IEEE80211_MAX_SSID_LEN   \
-                             + IW_EV_PARAM_LEN          \
-                             + 40)	/* 40 for WPAIE */
-
-//! Memory needed to store a max sized channel List TLV for a firmware scan
-#define CHAN_TLV_MAX_SIZE  (sizeof(struct mrvl_ie_header)    \
-                            + (MRVDRV_MAX_CHANNELS_PER_SCAN     \
-                               * sizeof(struct chanscanparamset)))
-
-//! Memory needed to store a max number/size SSID TLV for a firmware scan
-#define SSID_TLV_MAX_SIZE  (1 * sizeof(struct mrvl_ie_ssid_param_set))
-
-//! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max
-#define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan)	\
-                            + CHAN_TLV_MAX_SIZE + SSID_TLV_MAX_SIZE)
-
-//! The maximum number of channels the firmware can scan per command
-#define MRVDRV_MAX_CHANNELS_PER_SCAN   14
-
-/**
- * @brief Number of channels to scan per firmware scan command issuance.
- *
- *  Number restricted to prevent hitting the limit on the amount of scan data
- *  returned in a single firmware scan command.
- */
-#define MRVDRV_CHANNELS_PER_SCAN_CMD   4
-
-//! Scan time specified in the channel TLV for each channel for passive scans
-#define MRVDRV_PASSIVE_SCAN_CHAN_TIME  100
-
-//! 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);
-
-/*********************************************************************/
-/*                                                                   */
-/*  Misc helper functions                                            */
-/*                                                                   */
-/*********************************************************************/
-
-/**
- *  @brief Unsets the MSB on basic rates
- *
- * Scan through an array and unset the MSB for basic data rates.
- *
- *  @param rates     buffer of data rates
- *  @param len       size of buffer
- */
-static void lbs_unset_basic_rate_flags(u8 *rates, size_t len)
-{
-	int i;
-
-	for (i = 0; i < len; i++)
-		rates[i] &= 0x7f;
-}
-
-
-static inline void clear_bss_descriptor(struct bss_descriptor *bss)
-{
-	/* Don't blow away ->list, just BSS data */
-	memset(bss, 0, offsetof(struct bss_descriptor, list));
-}
-
-/**
- *  @brief Compare two SSIDs
- *
- *  @param ssid1    A pointer to ssid to compare
- *  @param ssid2    A pointer to ssid to compare
- *
- *  @return         0: ssid is same, otherwise is different
- */
-int lbs_ssid_cmp(uint8_t *ssid1, uint8_t ssid1_len, uint8_t *ssid2,
-		 uint8_t ssid2_len)
-{
-	if (ssid1_len != ssid2_len)
-		return -1;
-
-	return memcmp(ssid1, ssid2, ssid1_len);
-}
-
-static inline int is_same_network(struct bss_descriptor *src,
-				  struct bss_descriptor *dst)
-{
-	/* A network is only a duplicate if the channel, BSSID, and ESSID
-	 * all match.  We treat all <hidden> with the same BSSID and channel
-	 * as one network */
-	return ((src->ssid_len == dst->ssid_len) &&
-		(src->channel == dst->channel) &&
-		!compare_ether_addr(src->bssid, dst->bssid) &&
-		!memcmp(src->ssid, dst->ssid, src->ssid_len));
-}
-
-
-
-/*********************************************************************/
-/*                                                                   */
-/* Region channel support                                            */
-/*                                                                   */
-/*********************************************************************/
-
-#define LBS_TX_PWR_DEFAULT		20	/*100mW */
-#define LBS_TX_PWR_US_DEFAULT		20	/*100mW */
-#define LBS_TX_PWR_JP_DEFAULT		16	/*50mW */
-#define LBS_TX_PWR_FR_DEFAULT		20	/*100mW */
-#define LBS_TX_PWR_EMEA_DEFAULT	20	/*100mW */
-
-/* Format { channel, frequency (MHz), maxtxpower } */
-/* band: 'B/G', region: USA FCC/Canada IC */
-static struct chan_freq_power channel_freq_power_US_BG[] = {
-	{1, 2412, LBS_TX_PWR_US_DEFAULT},
-	{2, 2417, LBS_TX_PWR_US_DEFAULT},
-	{3, 2422, LBS_TX_PWR_US_DEFAULT},
-	{4, 2427, LBS_TX_PWR_US_DEFAULT},
-	{5, 2432, LBS_TX_PWR_US_DEFAULT},
-	{6, 2437, LBS_TX_PWR_US_DEFAULT},
-	{7, 2442, LBS_TX_PWR_US_DEFAULT},
-	{8, 2447, LBS_TX_PWR_US_DEFAULT},
-	{9, 2452, LBS_TX_PWR_US_DEFAULT},
-	{10, 2457, LBS_TX_PWR_US_DEFAULT},
-	{11, 2462, LBS_TX_PWR_US_DEFAULT}
-};
-
-/* band: 'B/G', region: Europe ETSI */
-static struct chan_freq_power channel_freq_power_EU_BG[] = {
-	{1, 2412, LBS_TX_PWR_EMEA_DEFAULT},
-	{2, 2417, LBS_TX_PWR_EMEA_DEFAULT},
-	{3, 2422, LBS_TX_PWR_EMEA_DEFAULT},
-	{4, 2427, LBS_TX_PWR_EMEA_DEFAULT},
-	{5, 2432, LBS_TX_PWR_EMEA_DEFAULT},
-	{6, 2437, LBS_TX_PWR_EMEA_DEFAULT},
-	{7, 2442, LBS_TX_PWR_EMEA_DEFAULT},
-	{8, 2447, LBS_TX_PWR_EMEA_DEFAULT},
-	{9, 2452, LBS_TX_PWR_EMEA_DEFAULT},
-	{10, 2457, LBS_TX_PWR_EMEA_DEFAULT},
-	{11, 2462, LBS_TX_PWR_EMEA_DEFAULT},
-	{12, 2467, LBS_TX_PWR_EMEA_DEFAULT},
-	{13, 2472, LBS_TX_PWR_EMEA_DEFAULT}
-};
-
-/* band: 'B/G', region: Spain */
-static struct chan_freq_power channel_freq_power_SPN_BG[] = {
-	{10, 2457, LBS_TX_PWR_DEFAULT},
-	{11, 2462, LBS_TX_PWR_DEFAULT}
-};
-
-/* band: 'B/G', region: France */
-static struct chan_freq_power channel_freq_power_FR_BG[] = {
-	{10, 2457, LBS_TX_PWR_FR_DEFAULT},
-	{11, 2462, LBS_TX_PWR_FR_DEFAULT},
-	{12, 2467, LBS_TX_PWR_FR_DEFAULT},
-	{13, 2472, LBS_TX_PWR_FR_DEFAULT}
-};
-
-/* band: 'B/G', region: Japan */
-static struct chan_freq_power channel_freq_power_JPN_BG[] = {
-	{1, 2412, LBS_TX_PWR_JP_DEFAULT},
-	{2, 2417, LBS_TX_PWR_JP_DEFAULT},
-	{3, 2422, LBS_TX_PWR_JP_DEFAULT},
-	{4, 2427, LBS_TX_PWR_JP_DEFAULT},
-	{5, 2432, LBS_TX_PWR_JP_DEFAULT},
-	{6, 2437, LBS_TX_PWR_JP_DEFAULT},
-	{7, 2442, LBS_TX_PWR_JP_DEFAULT},
-	{8, 2447, LBS_TX_PWR_JP_DEFAULT},
-	{9, 2452, LBS_TX_PWR_JP_DEFAULT},
-	{10, 2457, LBS_TX_PWR_JP_DEFAULT},
-	{11, 2462, LBS_TX_PWR_JP_DEFAULT},
-	{12, 2467, LBS_TX_PWR_JP_DEFAULT},
-	{13, 2472, LBS_TX_PWR_JP_DEFAULT},
-	{14, 2484, LBS_TX_PWR_JP_DEFAULT}
-};
-
-/**
- * the structure for channel, frequency and power
- */
-struct region_cfp_table {
-	u8 region;
-	struct chan_freq_power *cfp_BG;
-	int cfp_no_BG;
-};
-
-/**
- * the structure for the mapping between region and CFP
- */
-static struct region_cfp_table region_cfp_table[] = {
-	{0x10,			/*US FCC */
-	 channel_freq_power_US_BG,
-	 ARRAY_SIZE(channel_freq_power_US_BG),
-	 }
-	,
-	{0x20,			/*CANADA IC */
-	 channel_freq_power_US_BG,
-	 ARRAY_SIZE(channel_freq_power_US_BG),
-	 }
-	,
-	{0x30, /*EU*/ channel_freq_power_EU_BG,
-	 ARRAY_SIZE(channel_freq_power_EU_BG),
-	 }
-	,
-	{0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
-	 ARRAY_SIZE(channel_freq_power_SPN_BG),
-	 }
-	,
-	{0x32, /*FRANCE*/ channel_freq_power_FR_BG,
-	 ARRAY_SIZE(channel_freq_power_FR_BG),
-	 }
-	,
-	{0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
-	 ARRAY_SIZE(channel_freq_power_JPN_BG),
-	 }
-	,
-/*Add new region here */
-};
-
-/**
- *  @brief This function finds the CFP in
- *  region_cfp_table based on region and band parameter.
- *
- *  @param region  The region code
- *  @param band	   The band
- *  @param cfp_no  A pointer to CFP number
- *  @return 	   A pointer to CFP
- */
-static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no)
-{
-	int i, end;
-
-	lbs_deb_enter(LBS_DEB_MAIN);
-
-	end = ARRAY_SIZE(region_cfp_table);
-
-	for (i = 0; i < end ; i++) {
-		lbs_deb_main("region_cfp_table[i].region=%d\n",
-			region_cfp_table[i].region);
-		if (region_cfp_table[i].region == region) {
-			*cfp_no = region_cfp_table[i].cfp_no_BG;
-			lbs_deb_leave(LBS_DEB_MAIN);
-			return region_cfp_table[i].cfp_BG;
-		}
-	}
-
-	lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL");
-	return NULL;
-}
-
-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
-{
-	int ret = 0;
-	int i = 0;
-
-	struct chan_freq_power *cfp;
-	int cfp_no;
-
-	lbs_deb_enter(LBS_DEB_MAIN);
-
-	memset(priv->region_channel, 0, sizeof(priv->region_channel));
-
-	cfp = lbs_get_region_cfp_table(region, &cfp_no);
-	if (cfp != NULL) {
-		priv->region_channel[i].nrcfp = cfp_no;
-		priv->region_channel[i].CFP = cfp;
-	} else {
-		lbs_deb_main("wrong region code %#x in band B/G\n",
-		       region);
-		ret = -1;
-		goto out;
-	}
-	priv->region_channel[i].valid = 1;
-	priv->region_channel[i].region = region;
-	priv->region_channel[i].band = band;
-	i++;
-out:
-	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
-	return ret;
-}
-
-
-
-
-/*********************************************************************/
-/*                                                                   */
-/*  Main scanning support                                            */
-/*                                                                   */
-/*********************************************************************/
-
-/**
- *  @brief Create a channel list for the driver to scan based on region info
- *
- *  Only used from lbs_scan_setup_scan_config()
- *
- *  Use the driver region/band information to construct a comprehensive list
- *    of channels to scan.  This routine is used for any scan that is not
- *    provided a specific channel list to scan.
- *
- *  @param priv          A pointer to struct lbs_private structure
- *  @param scanchanlist  Output parameter: resulting channel list to scan
- *
- *  @return              void
- */
-static int lbs_scan_create_channel_list(struct lbs_private *priv,
-					struct chanscanparamset *scanchanlist)
-{
-	struct region_channel *scanregion;
-	struct chan_freq_power *cfp;
-	int rgnidx;
-	int chanidx;
-	int nextchan;
-	uint8_t scantype;
-
-	chanidx = 0;
-
-	/* Set the default scan type to the user specified type, will later
-	 *   be changed to passive on a per channel basis if restricted by
-	 *   regulatory requirements (11d or 11h)
-	 */
-	scantype = CMD_SCAN_TYPE_ACTIVE;
-
-	for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) {
-		if (!priv->region_channel[rgnidx].valid)
-			continue;
-		scanregion = &priv->region_channel[rgnidx];
-
-		for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
-			struct chanscanparamset *chan = &scanchanlist[chanidx];
-
-			cfp = scanregion->CFP + nextchan;
-
-			if (scanregion->band == BAND_B || scanregion->band == BAND_G)
-				chan->radiotype = CMD_SCAN_RADIO_TYPE_BG;
-
-			if (scantype == CMD_SCAN_TYPE_PASSIVE) {
-				chan->maxscantime = cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME);
-				chan->chanscanmode.passivescan = 1;
-			} else {
-				chan->maxscantime = cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME);
-				chan->chanscanmode.passivescan = 0;
-			}
-
-			chan->channumber = cfp->channel;
-		}
-	}
-	return chanidx;
-}
-
-/*
- * Add SSID TLV of the form:
- *
- * TLV-ID SSID     00 00
- * length          06 00
- * ssid            4d 4e 54 45 53 54
- */
-static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv)
-{
-	struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;
-
-	ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
-	ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len);
-	memcpy(ssid_tlv->ssid, priv->scan_ssid, priv->scan_ssid_len);
-	return sizeof(ssid_tlv->header) + priv->scan_ssid_len;
-}
-
-/*
- * Add CHANLIST TLV of the form
- *
- * TLV-ID CHANLIST 01 01
- * length          5b 00
- * channel 1       00 01 00 00 00 64 00
- *   radio type    00
- *   channel          01
- *   scan type           00
- *   min scan time          00 00
- *   max scan time                64 00
- * channel 2       00 02 00 00 00 64 00
- * channel 3       00 03 00 00 00 64 00
- * channel 4       00 04 00 00 00 64 00
- * channel 5       00 05 00 00 00 64 00
- * channel 6       00 06 00 00 00 64 00
- * channel 7       00 07 00 00 00 64 00
- * channel 8       00 08 00 00 00 64 00
- * channel 9       00 09 00 00 00 64 00
- * channel 10      00 0a 00 00 00 64 00
- * channel 11      00 0b 00 00 00 64 00
- * channel 12      00 0c 00 00 00 64 00
- * channel 13      00 0d 00 00 00 64 00
- *
- */
-static int lbs_scan_add_chanlist_tlv(uint8_t *tlv,
-				     struct chanscanparamset *chan_list,
-				     int chan_count)
-{
-	size_t size = sizeof(struct chanscanparamset) *chan_count;
-	struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv;
-
-	chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
-	memcpy(chan_tlv->chanscanparam, chan_list, size);
-	chan_tlv->header.len = cpu_to_le16(size);
-	return sizeof(chan_tlv->header) + size;
-}
-
-/*
- * Add RATES TLV of the form
- *
- * TLV-ID RATES    01 00
- * length          0e 00
- * rates           82 84 8b 96 0c 12 18 24 30 48 60 6c
- *
- * The rates are in lbs_bg_rates[], but for the 802.11b
- * rates the high bit isn't set.
- */
-static int lbs_scan_add_rates_tlv(uint8_t *tlv)
-{
-	int i;
-	struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
-
-	rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
-	tlv += sizeof(rate_tlv->header);
-	for (i = 0; i < MAX_RATES; i++) {
-		*tlv = lbs_bg_rates[i];
-		if (*tlv == 0)
-			break;
-		/* This code makes sure that the 802.11b rates (1 MBit/s, 2
-		   MBit/s, 5.5 MBit/s and 11 MBit/s get's the high bit set.
-		   Note that the values are MBit/s * 2, to mark them as
-		   basic rates so that the firmware likes it better */
-		if (*tlv == 0x02 || *tlv == 0x04 ||
-		    *tlv == 0x0b || *tlv == 0x16)
-			*tlv |= 0x80;
-		tlv++;
-	}
-	rate_tlv->header.len = cpu_to_le16(i);
-	return sizeof(rate_tlv->header) + i;
-}
-
-/*
- * Generate the CMD_802_11_SCAN command with the proper tlv
- * for a bunch of channels.
- */
-static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype,
-		       struct chanscanparamset *chan_list, int chan_count)
-{
-	int ret = -ENOMEM;
-	struct cmd_ds_802_11_scan *scan_cmd;
-	uint8_t *tlv;	/* pointer into our current, growing TLV storage area */
-
-	lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, chan_count %d",
-		bsstype, chan_list ? chan_list[0].channumber : -1,
-		chan_count);
-
-	/* create the fixed part for scan command */
-	scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
-	if (scan_cmd == NULL)
-		goto out;
-
-	tlv = scan_cmd->tlvbuffer;
-	/* TODO: do we need to scan for a specific BSSID?
-	memcpy(scan_cmd->bssid, priv->scan_bssid, ETH_ALEN); */
-	scan_cmd->bsstype = bsstype;
-
-	/* add TLVs */
-	if (priv->scan_ssid_len)
-		tlv += lbs_scan_add_ssid_tlv(priv, tlv);
-	if (chan_list && chan_count)
-		tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count);
-	tlv += lbs_scan_add_rates_tlv(tlv);
-
-	/* This is the final data we are about to send */
-	scan_cmd->hdr.size = cpu_to_le16(tlv - (uint8_t *)scan_cmd);
-	lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd,
-		    sizeof(*scan_cmd));
-	lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
-		    tlv - scan_cmd->tlvbuffer);
-
-	ret = __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr,
-			le16_to_cpu(scan_cmd->hdr.size),
-			lbs_ret_80211_scan, 0);
-
-out:
-	kfree(scan_cmd);
-	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-	return ret;
-}
-
-/**
- *  @brief Internal function used to start a scan based on an input config
- *
- *  Use the input user scan configuration information when provided in
- *    order to send the appropriate scan commands to firmware to populate or
- *    update the internal driver scan table
- *
- *  @param priv          A pointer to struct lbs_private structure
- *  @param full_scan     Do a full-scan (blocking)
- *
- *  @return              0 or < 0 if error
- */
-int lbs_scan_networks(struct lbs_private *priv, int full_scan)
-{
-	int ret = -ENOMEM;
-	struct chanscanparamset *chan_list;
-	struct chanscanparamset *curr_chans;
-	int chan_count;
-	uint8_t bsstype = CMD_BSS_TYPE_ANY;
-	int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD;
-	union iwreq_data wrqu;
-#ifdef CONFIG_LIBERTAS_DEBUG
-	struct bss_descriptor *iter;
-	int i = 0;
-	DECLARE_SSID_BUF(ssid);
-#endif
-
-	lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
-
-	/* Cancel any partial outstanding partial scans if this scan
-	 * is a full scan.
-	 */
-	if (full_scan && delayed_work_pending(&priv->scan_work))
-		cancel_delayed_work(&priv->scan_work);
-
-	/* User-specified bsstype or channel list
-	TODO: this can be implemented if some user-space application
-	need the feature. Formerly, it was accessible from debugfs,
-	but then nowhere used.
-	if (user_cfg) {
-		if (user_cfg->bsstype)
-		bsstype = user_cfg->bsstype;
-	} */
-
-	lbs_deb_scan("numchannels %d, bsstype %d\n", numchannels, bsstype);
-
-	/* Create list of channels to scan */
-	chan_list = kzalloc(sizeof(struct chanscanparamset) *
-			    LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
-	if (!chan_list) {
-		lbs_pr_alert("SCAN: chan_list empty\n");
-		goto out;
-	}
-
-	/* We want to scan all channels */
-	chan_count = lbs_scan_create_channel_list(priv, chan_list);
-
-	netif_stop_queue(priv->dev);
-	if (priv->mesh_dev)
-		netif_stop_queue(priv->mesh_dev);
-
-	/* Prepare to continue an interrupted scan */
-	lbs_deb_scan("chan_count %d, scan_channel %d\n",
-		     chan_count, priv->scan_channel);
-	curr_chans = chan_list;
-	/* advance channel list by already-scanned-channels */
-	if (priv->scan_channel > 0) {
-		curr_chans += priv->scan_channel;
-		chan_count -= priv->scan_channel;
-	}
-
-	/* Send scan command(s)
-	 * numchannels contains the number of channels we should maximally scan
-	 * chan_count is the total number of channels to scan
-	 */
-
-	while (chan_count) {
-		int to_scan = min(numchannels, chan_count);
-		lbs_deb_scan("scanning %d of %d channels\n",
-			     to_scan, chan_count);
-		ret = lbs_do_scan(priv, bsstype, curr_chans,
-				  to_scan);
-		if (ret) {
-			lbs_pr_err("SCAN_CMD failed\n");
-			goto out2;
-		}
-		curr_chans += to_scan;
-		chan_count -= to_scan;
-
-		/* somehow schedule the next part of the scan */
-		if (chan_count && !full_scan &&
-		    !priv->surpriseremoved) {
-			/* -1 marks just that we're currently scanning */
-			if (priv->scan_channel < 0)
-				priv->scan_channel = to_scan;
-			else
-				priv->scan_channel += to_scan;
-			cancel_delayed_work(&priv->scan_work);
-			queue_delayed_work(priv->work_thread, &priv->scan_work,
-					   msecs_to_jiffies(300));
-			/* skip over GIWSCAN event */
-			goto out;
-		}
-
-	}
-	memset(&wrqu, 0, sizeof(union iwreq_data));
-	wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
-
-#ifdef CONFIG_LIBERTAS_DEBUG
-	/* Dump the scan table */
-	mutex_lock(&priv->lock);
-	lbs_deb_scan("scan table:\n");
-	list_for_each_entry(iter, &priv->network_list, list)
-		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
-
-out2:
-	priv->scan_channel = 0;
-
-out:
-	if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len)
-		netif_wake_queue(priv->dev);
-
-	if (priv->mesh_dev && lbs_mesh_connected(priv) &&
-	    !priv->tx_pending_len)
-		netif_wake_queue(priv->mesh_dev);
-
-	kfree(chan_list);
-
-	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-	return ret;
-}
-
-void lbs_scan_worker(struct work_struct *work)
-{
-	struct lbs_private *priv =
-		container_of(work, struct lbs_private, scan_work.work);
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-	lbs_scan_networks(priv, 0);
-	lbs_deb_leave(LBS_DEB_SCAN);
-}
-
-
-/*********************************************************************/
-/*                                                                   */
-/*  Result interpretation                                            */
-/*                                                                   */
-/*********************************************************************/
-
-/**
- *  @brief Interpret a BSS scan response returned from the firmware
- *
- *  Parse the various fixed fields and IEs passed back for a a BSS probe
- *  response or beacon from the scan command.  Record information as needed
- *  in the scan table struct bss_descriptor for that entry.
- *
- *  @param bss  Output parameter: Pointer to the BSS Entry
- *
- *  @return             0 or -1
- */
-static int lbs_process_bss(struct bss_descriptor *bss,
-			   uint8_t **pbeaconinfo, int *bytesleft)
-{
-	struct ieee_ie_fh_param_set *fh;
-	struct ieee_ie_ds_param_set *ds;
-	struct ieee_ie_cf_param_set *cf;
-	struct ieee_ie_ibss_param_set *ibss;
-	DECLARE_SSID_BUF(ssid);
-	uint8_t *pos, *end, *p;
-	uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
-	uint16_t beaconsize = 0;
-	int ret;
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-
-	if (*bytesleft >= sizeof(beaconsize)) {
-		/* Extract & convert beacon size from the command buffer */
-		beaconsize = get_unaligned_le16(*pbeaconinfo);
-		*bytesleft -= sizeof(beaconsize);
-		*pbeaconinfo += sizeof(beaconsize);
-	}
-
-	if (beaconsize == 0 || beaconsize > *bytesleft) {
-		*pbeaconinfo += *bytesleft;
-		*bytesleft = 0;
-		ret = -1;
-		goto done;
-	}
-
-	/* Initialize the current working beacon pointer for this BSS iteration */
-	pos = *pbeaconinfo;
-	end = pos + beaconsize;
-
-	/* Advance the return beacon pointer past the current beacon */
-	*pbeaconinfo += beaconsize;
-	*bytesleft -= beaconsize;
-
-	memcpy(bss->bssid, pos, ETH_ALEN);
-	lbs_deb_scan("process_bss: BSSID %pM\n", bss->bssid);
-	pos += ETH_ALEN;
-
-	if ((end - pos) < 12) {
-		lbs_deb_scan("process_bss: Not enough bytes left\n");
-		ret = -1;
-		goto done;
-	}
-
-	/*
-	 * next 4 fields are RSSI, time stamp, beacon interval,
-	 *   and capability information
-	 */
-
-	/* RSSI is 1 byte long */
-	bss->rssi = *pos;
-	lbs_deb_scan("process_bss: RSSI %d\n", *pos);
-	pos++;
-
-	/* time stamp is 8 bytes long */
-	pos += 8;
-
-	/* beacon interval is 2 bytes long */
-	bss->beaconperiod = get_unaligned_le16(pos);
-	pos += 2;
-
-	/* capability information is 2 bytes long */
-	bss->capability = get_unaligned_le16(pos);
-	lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);
-	pos += 2;
-
-	if (bss->capability & WLAN_CAPABILITY_PRIVACY)
-		lbs_deb_scan("process_bss: WEP enabled\n");
-	if (bss->capability & WLAN_CAPABILITY_IBSS)
-		bss->mode = IW_MODE_ADHOC;
-	else
-		bss->mode = IW_MODE_INFRA;
-
-	/* rest of the current buffer are IE's */
-	lbs_deb_scan("process_bss: IE len %zd\n", end - pos);
-	lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);
-
-	/* process variable IE */
-	while (pos <= end - 2) {
-		if (pos + pos[1] > end) {
-			lbs_deb_scan("process_bss: error in processing IE, "
-				     "bytes left < IE length\n");
-			break;
-		}
-
-		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",
-			             print_ssid(ssid, bss->ssid, bss->ssid_len),
-			             bss->ssid_len);
-			break;
-
-		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 WLAN_EID_FH_PARAMS:
-			fh = (struct ieee_ie_fh_param_set *) pos;
-			memcpy(&bss->phy.fh, fh, sizeof(*fh));
-			lbs_deb_scan("got FH IE\n");
-			break;
-
-		case WLAN_EID_DS_PARAMS:
-			ds = (struct ieee_ie_ds_param_set *) pos;
-			bss->channel = ds->channel;
-			memcpy(&bss->phy.ds, ds, sizeof(*ds));
-			lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
-			break;
-
-		case WLAN_EID_CF_PARAMS:
-			cf = (struct ieee_ie_cf_param_set *) pos;
-			memcpy(&bss->ss.cf, cf, sizeof(*cf));
-			lbs_deb_scan("got CF IE\n");
-			break;
-
-		case WLAN_EID_IBSS_PARAMS:
-			ibss = (struct ieee_ie_ibss_param_set *) pos;
-			bss->atimwindow = ibss->atimwindow;
-			memcpy(&bss->ss.ibss, ibss, sizeof(*ibss));
-			lbs_deb_scan("got IBSS IE\n");
-			break;
-
-		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
-			 */
-			lbs_deb_scan("got RATESEX IE\n");
-			if (!got_basic_rates) {
-				lbs_deb_scan("... but ignoring it\n");
-				break;
-			}
-
-			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, pos + 2, n_ex_rates);
-			break;
-
-		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,
-					    bss->wpa_ie_len);
-			} else if (pos[1] >= MARVELL_MESH_IE_LENGTH &&
-				   pos[2] == 0x00 && pos[3] == 0x50 &&
-				   pos[4] == 0x43 && pos[5] == 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",
-					pos[2], pos[3],
-					pos[4], pos[5],
-					pos[1]);
-			}
-			break;
-
-		case WLAN_EID_RSN:
-			lbs_deb_scan("got RSN IE\n");
-			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, bss->rsn_ie_len);
-			break;
-
-		default:
-			lbs_deb_scan("got IE 0x%04x, len %d\n",
-				     pos[0], pos[1]);
-			break;
-		}
-
-		pos += pos[1] + 2;
-	}
-
-	/* Timestamp */
-	bss->last_scanned = jiffies;
-	lbs_unset_basic_rate_flags(bss->rates, sizeof(bss->rates));
-
-	ret = 0;
-
-done:
-	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-	return ret;
-}
-
-/**
- *  @brief Send a scan command for all available channels filtered on a spec
- *
- *  Used in association code and from debugfs
- *
- *  @param priv             A pointer to struct lbs_private structure
- *  @param ssid             A pointer to the SSID to scan for
- *  @param ssid_len         Length of the SSID
- *
- *  @return                0-success, otherwise fail
- */
-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",
-			   print_ssid(ssid_buf, ssid, ssid_len));
-
-	if (!ssid_len)
-		goto out;
-
-	memcpy(priv->scan_ssid, ssid, ssid_len);
-	priv->scan_ssid_len = ssid_len;
-
-	lbs_scan_networks(priv, 1);
-	if (priv->surpriseremoved) {
-		ret = -1;
-		goto out;
-	}
-
-out:
-	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-	return ret;
-}
-
-
-
-
-/*********************************************************************/
-/*                                                                   */
-/*  Support for Wireless Extensions                                  */
-/*                                                                   */
-/*********************************************************************/
-
-
-#define MAX_CUSTOM_LEN 64
-
-static inline char *lbs_translate_scan(struct lbs_private *priv,
-					    struct iw_request_info *info,
-					    char *start, char *stop,
-					    struct bss_descriptor *bss)
-{
-	struct chan_freq_power *cfp;
-	char *current_val;	/* For rates */
-	struct iw_event iwe;	/* Temporary buffer */
-	int j;
-#define PERFECT_RSSI ((uint8_t)50)
-#define WORST_RSSI   ((uint8_t)0)
-#define RSSI_DIFF    ((uint8_t)(PERFECT_RSSI - WORST_RSSI))
-	uint8_t rssi;
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-
-	cfp = lbs_find_cfp_by_band_and_channel(priv, 0, bss->channel);
-	if (!cfp) {
-		lbs_deb_scan("Invalid channel number %d\n", bss->channel);
-		start = NULL;
-		goto out;
-	}
-
-	/* First entry *MUST* be the BSSID */
-	iwe.cmd = SIOCGIWAP;
-	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-	memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
-	start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
-
-	/* SSID */
-	iwe.cmd = SIOCGIWESSID;
-	iwe.u.data.flags = 1;
-	iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN);
-	start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
-
-	/* Mode */
-	iwe.cmd = SIOCGIWMODE;
-	iwe.u.mode = bss->mode;
-	start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
-
-	/* Frequency */
-	iwe.cmd = SIOCGIWFREQ;
-	iwe.u.freq.m = (long)cfp->freq * 100000;
-	iwe.u.freq.e = 1;
-	start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
-
-	/* Add quality statistics */
-	iwe.cmd = IWEVQUAL;
-	iwe.u.qual.updated = IW_QUAL_ALL_UPDATED;
-	iwe.u.qual.level = SCAN_RSSI(bss->rssi);
-
-	rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;
-	iwe.u.qual.qual =
-		(100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
-		 (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
-		(RSSI_DIFF * RSSI_DIFF);
-	if (iwe.u.qual.qual > 100)
-		iwe.u.qual.qual = 100;
-
-	if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
-		iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
-	} else {
-		iwe.u.qual.noise = CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
-	}
-
-	/* Locally created ad-hoc BSSs won't have beacons if this is the
-	 * only station in the adhoc network; so get signal strength
-	 * from receive statistics.
-	 */
-	if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate
-	    && !lbs_ssid_cmp(priv->curbssparams.ssid,
-			     priv->curbssparams.ssid_len,
-			     bss->ssid, bss->ssid_len)) {
-		int snr, nf;
-		snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
-		nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
-		iwe.u.qual.level = CAL_RSSI(snr, nf);
-	}
-	start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
-
-	/* Add encryption capability */
-	iwe.cmd = SIOCGIWENCODE;
-	if (bss->capability & WLAN_CAPABILITY_PRIVACY) {
-		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
-	} else {
-		iwe.u.data.flags = IW_ENCODE_DISABLED;
-	}
-	iwe.u.data.length = 0;
-	start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
-
-	current_val = start + iwe_stream_lcp_len(info);
-
-	iwe.cmd = SIOCGIWRATE;
-	iwe.u.bitrate.fixed = 0;
-	iwe.u.bitrate.disabled = 0;
-	iwe.u.bitrate.value = 0;
-
-	for (j = 0; j < ARRAY_SIZE(bss->rates) && bss->rates[j]; j++) {
-		/* Bit rate given in 500 kb/s units */
-		iwe.u.bitrate.value = bss->rates[j] * 500000;
-		current_val = iwe_stream_add_value(info, start, current_val,
-						   stop, &iwe, IW_EV_PARAM_LEN);
-	}
-	if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate
-	    && !lbs_ssid_cmp(priv->curbssparams.ssid,
-			     priv->curbssparams.ssid_len,
-			     bss->ssid, bss->ssid_len)) {
-		iwe.u.bitrate.value = 22 * 500000;
-		current_val = iwe_stream_add_value(info, start, current_val,
-						   stop, &iwe, IW_EV_PARAM_LEN);
-	}
-	/* Check if we added any event */
-	if ((current_val - start) > iwe_stream_lcp_len(info))
-		start = current_val;
-
-	memset(&iwe, 0, sizeof(iwe));
-	if (bss->wpa_ie_len) {
-		char buf[MAX_WPA_IE_LEN];
-		memcpy(buf, bss->wpa_ie, bss->wpa_ie_len);
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = bss->wpa_ie_len;
-		start = iwe_stream_add_point(info, start, stop, &iwe, buf);
-	}
-
-	memset(&iwe, 0, sizeof(iwe));
-	if (bss->rsn_ie_len) {
-		char buf[MAX_WPA_IE_LEN];
-		memcpy(buf, bss->rsn_ie, bss->rsn_ie_len);
-		iwe.cmd = IWEVGENIE;
-		iwe.u.data.length = bss->rsn_ie_len;
-		start = iwe_stream_add_point(info, start, stop, &iwe, buf);
-	}
-
-	if (bss->mesh) {
-		char custom[MAX_CUSTOM_LEN];
-		char *p = custom;
-
-		iwe.cmd = IWEVCUSTOM;
-		p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc");
-		iwe.u.data.length = p - custom;
-		if (iwe.u.data.length)
-			start = iwe_stream_add_point(info, start, stop,
-						     &iwe, custom);
-	}
-
-out:
-	lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start);
-	return start;
-}
-
-
-/**
- *  @brief Handle Scan Network ioctl
- *
- *  @param dev          A pointer to net_device structure
- *  @param info         A pointer to iw_request_info structure
- *  @param vwrq         A pointer to iw_param structure
- *  @param extra        A pointer to extra data buf
- *
- *  @return             0 --success, otherwise fail
- */
-int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
-		 union iwreq_data *wrqu, char *extra)
-{
-	DECLARE_SSID_BUF(ssid);
-	struct lbs_private *priv = dev->ml_priv;
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if (!priv->radio_on) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (!netif_running(dev)) {
-		ret = -ENETDOWN;
-		goto out;
-	}
-
-	/* mac80211 does this:
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->type != IEEE80211_IF_TYPE_xxx) {
-		ret = -EOPNOTSUPP;
-		goto out;
-	}
-	*/
-
-	if (wrqu->data.length == sizeof(struct iw_scan_req) &&
-	    wrqu->data.flags & IW_SCAN_THIS_ESSID) {
-		struct iw_scan_req *req = (struct iw_scan_req *)extra;
-		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",
-			print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len));
-	} else {
-		priv->scan_ssid_len = 0;
-	}
-
-	if (!delayed_work_pending(&priv->scan_work))
-		queue_delayed_work(priv->work_thread, &priv->scan_work,
-				   msecs_to_jiffies(50));
-	/* set marker that currently a scan is taking place */
-	priv->scan_channel = -1;
-
-	if (priv->surpriseremoved)
-		ret = -EIO;
-
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-
-/**
- *  @brief  Handle Retrieve scan table ioctl
- *
- *  @param dev          A pointer to net_device structure
- *  @param info         A pointer to iw_request_info structure
- *  @param dwrq         A pointer to iw_point structure
- *  @param extra        A pointer to extra data buf
- *
- *  @return             0 --success, otherwise fail
- */
-int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
-		 struct iw_point *dwrq, char *extra)
-{
-#define SCAN_ITEM_SIZE 128
-	struct lbs_private *priv = dev->ml_priv;
-	int err = 0;
-	char *ev = extra;
-	char *stop = ev + dwrq->length;
-	struct bss_descriptor *iter_bss;
-	struct bss_descriptor *safe;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	/* iwlist should wait until the current scan is finished */
-	if (priv->scan_channel)
-		return -EAGAIN;
-
-	/* Update RSSI if current BSS is a locally created ad-hoc BSS */
-	if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) {
-		err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
-				CMD_OPTION_WAITFORRSP, 0, NULL);
-		if (err)
-			goto out;
-	}
-
-	mutex_lock(&priv->lock);
-	list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
-		char *next_ev;
-		unsigned long stale_time;
-
-		if (stop - ev < SCAN_ITEM_SIZE) {
-			err = -E2BIG;
-			break;
-		}
-
-		/* For mesh device, list only mesh networks */
-		if (dev == priv->mesh_dev && !iter_bss->mesh)
-			continue;
-
-		/* Prune old an old scan result */
-		stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
-		if (time_after(jiffies, stale_time)) {
-			list_move_tail(&iter_bss->list, &priv->network_free_list);
-			clear_bss_descriptor(iter_bss);
-			continue;
-		}
-
-		/* Translate to WE format this entry */
-		next_ev = lbs_translate_scan(priv, info, ev, stop, iter_bss);
-		if (next_ev == NULL)
-			continue;
-		ev = next_ev;
-	}
-	mutex_unlock(&priv->lock);
-
-	dwrq->length = (ev - extra);
-	dwrq->flags = 0;
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
-	return err;
-}
-
-
-
-
-/*********************************************************************/
-/*                                                                   */
-/*  Command execution                                                */
-/*                                                                   */
-/*********************************************************************/
-
-
-/**
- *  @brief This function handles the command response of scan
- *
- *  Called from handle_cmd_response() in cmdrespc.
- *
- *   The response buffer for the scan command has the following
- *      memory layout:
- *
- *     .-----------------------------------------------------------.
- *     |  header (4 * sizeof(u16)):  Standard command response hdr |
- *     .-----------------------------------------------------------.
- *     |  bufsize (u16) : sizeof the BSS Description data          |
- *     .-----------------------------------------------------------.
- *     |  NumOfSet (u8) : Number of BSS Descs returned             |
- *     .-----------------------------------------------------------.
- *     |  BSSDescription data (variable, size given in bufsize)    |
- *     .-----------------------------------------------------------.
- *     |  TLV data (variable, size calculated using header->size,  |
- *     |            bufsize and sizeof the fixed fields above)     |
- *     .-----------------------------------------------------------.
- *
- *  @param priv    A pointer to struct lbs_private structure
- *  @param resp    A pointer to cmd_ds_command
- *
- *  @return        0 or -1
- */
-static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
-			      struct cmd_header *resp)
-{
-	struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
-	struct bss_descriptor *iter_bss;
-	struct bss_descriptor *safe;
-	uint8_t *bssinfo;
-	uint16_t scanrespsize;
-	int bytesleft;
-	int idx;
-	int tlvbufsize;
-	int ret;
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-
-	/* Prune old entries from scan table */
-	list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
-		unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
-		if (time_before(jiffies, stale_time))
-			continue;
-		list_move_tail (&iter_bss->list, &priv->network_free_list);
-		clear_bss_descriptor(iter_bss);
-	}
-
-	if (scanresp->nr_sets > MAX_NETWORK_COUNT) {
-		lbs_deb_scan("SCAN_RESP: too many scan results (%d, max %d)\n",
-			     scanresp->nr_sets, MAX_NETWORK_COUNT);
-		ret = -1;
-		goto done;
-	}
-
-	bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize);
-	lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
-
-	scanrespsize = le16_to_cpu(resp->size);
-	lbs_deb_scan("SCAN_RESP: scan results %d\n", scanresp->nr_sets);
-
-	bssinfo = scanresp->bssdesc_and_tlvbuffer;
-
-	/* The size of the TLV buffer is equal to the entire command response
-	 *   size (scanrespsize) minus the fixed fields (sizeof()'s), the
-	 *   BSS Descriptions (bssdescriptsize as bytesLef) and the command
-	 *   response header (sizeof(struct cmd_header))
-	 */
-	tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize)
-				     + sizeof(scanresp->nr_sets)
-				     + sizeof(struct cmd_header));
-
-	/*
-	 *  Process each scan response returned (scanresp->nr_sets). Save
-	 *    the information in the newbssentry and then insert into the
-	 *    driver scan table either as an update to an existing entry
-	 *    or as an addition at the end of the table
-	 */
-	for (idx = 0; idx < scanresp->nr_sets && bytesleft; idx++) {
-		struct bss_descriptor new;
-		struct bss_descriptor *found = NULL;
-		struct bss_descriptor *oldest = NULL;
-
-		/* Process the data fields and IEs returned for this BSS */
-		memset(&new, 0, sizeof (struct bss_descriptor));
-		if (lbs_process_bss(&new, &bssinfo, &bytesleft) != 0) {
-			/* error parsing the scan response, skipped */
-			lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n");
-			continue;
-		}
-
-		/* Try to find this bss in the scan table */
-		list_for_each_entry (iter_bss, &priv->network_list, list) {
-			if (is_same_network(iter_bss, &new)) {
-				found = iter_bss;
-				break;
-			}
-
-			if ((oldest == NULL) ||
-			    (iter_bss->last_scanned < oldest->last_scanned))
-				oldest = iter_bss;
-		}
-
-		if (found) {
-			/* found, clear it */
-			clear_bss_descriptor(found);
-		} else if (!list_empty(&priv->network_free_list)) {
-			/* Pull one from the free list */
-			found = list_entry(priv->network_free_list.next,
-					   struct bss_descriptor, list);
-			list_move_tail(&found->list, &priv->network_list);
-		} else if (oldest) {
-			/* If there are no more slots, expire the oldest */
-			found = oldest;
-			clear_bss_descriptor(found);
-			list_move_tail(&found->list, &priv->network_list);
-		} else {
-			continue;
-		}
-
-		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));
-	}
-
-	ret = 0;
-
-done:
-	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-	return ret;
-}
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
deleted file mode 100644
index 8fb1706..0000000
--- a/drivers/net/wireless/libertas/scan.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
-  * Interface for the wlan network scan routines
-  *
-  * Driver interface functions and type declarations for the scan module
-  * implemented in scan.c.
-  */
-#ifndef _LBS_SCAN_H
-#define _LBS_SCAN_H
-
-#include <net/iw_handler.h>
-
-struct lbs_private;
-
-#define MAX_NETWORK_COUNT 128
-
-/** Chan-freq-TxPower mapping table*/
-struct chan_freq_power {
-	/** channel Number		*/
-	u16 channel;
-	/** frequency of this channel	*/
-	u32 freq;
-	/** Max allowed Tx power level	*/
-	u16 maxtxpower;
-	/** TRUE:channel unsupported;  FLASE:supported*/
-	u8 unsupported;
-};
-
-/** region-band mapping table*/
-struct region_channel {
-	/** TRUE if this entry is valid		     */
-	u8 valid;
-	/** region code for US, Japan ...	     */
-	u8 region;
-	/** band B/G/A, used for BAND_CONFIG cmd	     */
-	u8 band;
-	/** Actual No. of elements in the array below */
-	u8 nrcfp;
-	/** chan-freq-txpower mapping table*/
-	struct chan_freq_power *CFP;
-};
-
-/**
- *  @brief Maximum number of channels that can be sent in a setuserscan ioctl
- */
-#define LBS_IOCTL_USER_SCAN_CHAN_MAX  50
-
-int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
-
-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
-
-int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
-				u8 ssid_len);
-
-int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
-			 struct iw_point *dwrq, char *extra);
-int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
-			 union iwreq_data *wrqu, char *extra);
-
-int lbs_scan_networks(struct lbs_private *priv, int full_scan);
-
-void lbs_scan_worker(struct work_struct *work);
-
-#endif
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index a9bf658..8000ca6 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -4,13 +4,13 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/sched.h>
+#include <net/cfg80211.h>
 
 #include "host.h"
 #include "radiotap.h"
 #include "decl.h"
 #include "defs.h"
 #include "dev.h"
-#include "wext.h"
 
 /**
  *  @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
@@ -111,7 +111,7 @@
 	p802x_hdr = skb->data;
 	pkt_len = skb->len;
 
-	if (dev == priv->rtap_net_dev) {
+	if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
 		struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
 
 		/* set txpd fields from the radiotap header */
@@ -147,7 +147,7 @@
 	dev->stats.tx_packets++;
 	dev->stats.tx_bytes += skb->len;
 
-	if (priv->monitormode) {
+	if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
 		/* Keep the skb to echo it back once Tx feedback is
 		   received from FW */
 		skb_orphan(skb);
@@ -158,6 +158,7 @@
  free:
 		dev_kfree_skb_any(skb);
 	}
+
  unlock:
 	spin_unlock_irqrestore(&priv->driver_lock, flags);
 	wake_up(&priv->waitq);
@@ -179,7 +180,8 @@
 {
 	struct tx_radiotap_hdr *radiotap_hdr;
 
-	if (!priv->monitormode || priv->currenttxskb == NULL)
+	if (priv->wdev->iftype != NL80211_IFTYPE_MONITOR ||
+	    priv->currenttxskb == NULL)
 		return;
 
 	radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
@@ -188,7 +190,7 @@
 		(1 + priv->txretrycount - try_count) : 0;
 
 	priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
-						      priv->rtap_net_dev);
+						      priv->dev);
 	netif_rx(priv->currenttxskb);
 
 	priv->currenttxskb = NULL;
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 3e72c86..462fbb4 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -11,7 +11,7 @@
 struct ieee_ie_header {
 	u8 id;
 	u8 len;
-} __attribute__ ((packed));
+} __packed;
 
 struct ieee_ie_cf_param_set {
 	struct ieee_ie_header header;
@@ -20,19 +20,19 @@
 	u8 cfpperiod;
 	__le16 cfpmaxduration;
 	__le16 cfpdurationremaining;
-} __attribute__ ((packed));
+} __packed;
 
 
 struct ieee_ie_ibss_param_set {
 	struct ieee_ie_header header;
 
 	__le16 atimwindow;
-} __attribute__ ((packed));
+} __packed;
 
 union ieee_ss_param_set {
 	struct ieee_ie_cf_param_set cf;
 	struct ieee_ie_ibss_param_set ibss;
-} __attribute__ ((packed));
+} __packed;
 
 struct ieee_ie_fh_param_set {
 	struct ieee_ie_header header;
@@ -41,18 +41,18 @@
 	u8 hopset;
 	u8 hoppattern;
 	u8 hopindex;
-} __attribute__ ((packed));
+} __packed;
 
 struct ieee_ie_ds_param_set {
 	struct ieee_ie_header header;
 
 	u8 channel;
-} __attribute__ ((packed));
+} __packed;
 
 union ieee_phy_param_set {
 	struct ieee_ie_fh_param_set fh;
 	struct ieee_ie_ds_param_set ds;
-} __attribute__ ((packed));
+} __packed;
 
 /** TLV  type ID definition */
 #define PROPRIETARY_TLV_BASE_ID		0x0100
@@ -100,28 +100,28 @@
 struct mrvl_ie_header {
 	__le16 type;
 	__le16 len;
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_data {
 	struct mrvl_ie_header header;
 	u8 Data[1];
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_rates_param_set {
 	struct mrvl_ie_header header;
 	u8 rates[1];
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_ssid_param_set {
 	struct mrvl_ie_header header;
 	u8 ssid[1];
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_wildcard_ssid_param_set {
 	struct mrvl_ie_header header;
 	u8 MaxSsidlength;
 	u8 ssid[1];
-} __attribute__ ((packed));
+} __packed;
 
 struct chanscanmode {
 #ifdef __BIG_ENDIAN_BITFIELD
@@ -133,7 +133,7 @@
 	u8 disablechanfilt:1;
 	u8 reserved_2_7:6;
 #endif
-} __attribute__ ((packed));
+} __packed;
 
 struct chanscanparamset {
 	u8 radiotype;
@@ -141,12 +141,12 @@
 	struct chanscanmode chanscanmode;
 	__le16 minscantime;
 	__le16 maxscantime;
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_chanlist_param_set {
 	struct mrvl_ie_header header;
 	struct chanscanparamset chanscanparam[1];
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_cf_param_set {
 	struct mrvl_ie_header header;
@@ -154,86 +154,86 @@
 	u8 cfpperiod;
 	__le16 cfpmaxduration;
 	__le16 cfpdurationremaining;
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_ds_param_set {
 	struct mrvl_ie_header header;
 	u8 channel;
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_rsn_param_set {
 	struct mrvl_ie_header header;
 	u8 rsnie[1];
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_tsf_timestamp {
 	struct mrvl_ie_header header;
 	__le64 tsftable[1];
-} __attribute__ ((packed));
+} __packed;
 
 /* v9 and later firmware only */
 struct mrvl_ie_auth_type {
 	struct mrvl_ie_header header;
 	__le16 auth;
-} __attribute__ ((packed));
+} __packed;
 
 /**  Local Power capability */
 struct mrvl_ie_power_capability {
 	struct mrvl_ie_header header;
 	s8 minpower;
 	s8 maxpower;
-} __attribute__ ((packed));
+} __packed;
 
 /* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
 struct mrvl_ie_thresholds {
 	struct mrvl_ie_header header;
 	u8 value;
 	u8 freq;
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_beacons_missed {
 	struct mrvl_ie_header header;
 	u8 beaconmissed;
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_num_probes {
 	struct mrvl_ie_header header;
 	__le16 numprobes;
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_bcast_probe {
 	struct mrvl_ie_header header;
 	__le16 bcastprobe;
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_num_ssid_probe {
 	struct mrvl_ie_header header;
 	__le16 numssidprobe;
-} __attribute__ ((packed));
+} __packed;
 
 struct led_pin {
 	u8 led;
 	u8 pin;
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_ie_ledgpio {
 	struct mrvl_ie_header header;
 	struct led_pin ledpin[1];
-} __attribute__ ((packed));
+} __packed;
 
 struct led_bhv {
 	uint8_t	firmwarestate;
 	uint8_t	led;
 	uint8_t	ledstate;
 	uint8_t	ledarg;
-} __attribute__ ((packed));
+} __packed;
 
 
 struct mrvl_ie_ledbhv {
 	struct mrvl_ie_header header;
 	struct led_bhv ledbhv[1];
-} __attribute__ ((packed));
+} __packed;
 
 /* Meant to be packed as the value member of a struct ieee80211_info_element.
  * Note that the len member of the ieee80211_info_element varies depending on
@@ -248,12 +248,12 @@
 	uint8_t mesh_capability;
 	uint8_t mesh_id_len;
 	uint8_t mesh_id[IEEE80211_MAX_SSID_LEN];
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_meshie {
 	u8 id, len;
 	struct mrvl_meshie_val val;
-} __attribute__ ((packed));
+} __packed;
 
 struct mrvl_mesh_defaults {
 	__le32 bootflag;
@@ -261,6 +261,6 @@
 	uint8_t reserved;
 	__le16 channel;
 	struct mrvl_meshie meshie;
-} __attribute__ ((packed));
+} __packed;
 
 #endif
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
deleted file mode 100644
index f96a960..0000000
--- a/drivers/net/wireless/libertas/wext.c
+++ /dev/null
@@ -1,2353 +0,0 @@
-/**
-  * This file contains ioctl functions
-  */
-#include <linux/ctype.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/if.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <linux/bitops.h>
-
-#include <net/lib80211.h>
-#include <net/iw_handler.h>
-
-#include "host.h"
-#include "radiotap.h"
-#include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "wext.h"
-#include "scan.h"
-#include "assoc.h"
-#include "cmd.h"
-
-
-static inline void lbs_postpone_association_work(struct lbs_private *priv)
-{
-	if (priv->surpriseremoved)
-		return;
-	cancel_delayed_work(&priv->assoc_work);
-	queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2);
-}
-
-static inline void lbs_do_association_work(struct lbs_private *priv)
-{
-	if (priv->surpriseremoved)
-		return;
-	cancel_delayed_work(&priv->assoc_work);
-	queue_delayed_work(priv->work_thread, &priv->assoc_work, 0);
-}
-
-static inline void lbs_cancel_association_work(struct lbs_private *priv)
-{
-	cancel_delayed_work(&priv->assoc_work);
-	kfree(priv->pending_assoc_req);
-	priv->pending_assoc_req = NULL;
-}
-
-void lbs_send_disconnect_notification(struct lbs_private *priv)
-{
-	union iwreq_data wrqu;
-
-	memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
-	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
-{
-	union iwreq_data iwrq;
-	u8 buf[50];
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	memset(&iwrq, 0, sizeof(union iwreq_data));
-	memset(buf, 0, sizeof(buf));
-
-	snprintf(buf, sizeof(buf) - 1, "%s", str);
-
-	iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
-
-	/* Send Event to upper layer */
-	lbs_deb_wext("event indication string %s\n", (char *)buf);
-	lbs_deb_wext("event indication length %d\n", iwrq.data.length);
-	lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
-
-	wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-}
-
-/**
- *  @brief This function handles MIC failure event.
- *
- *  @param priv    A pointer to struct lbs_private structure
- *  @para  event   the event id
- *  @return 	   n/a
- */
-void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
-{
-	char buf[50];
-
-	lbs_deb_enter(LBS_DEB_CMD);
-	memset(buf, 0, sizeof(buf));
-
-	sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
-
-	if (event == MACREG_INT_CODE_MIC_ERR_UNICAST)
-		strcat(buf, "unicast ");
-	else
-		strcat(buf, "multicast ");
-
-	lbs_send_iwevcustom_event(priv, buf);
-	lbs_deb_leave(LBS_DEB_CMD);
-}
-
-/**
- *  @brief Find the channel frequency power info with specific channel
- *
- *  @param priv 	A pointer to struct lbs_private structure
- *  @param band		it can be BAND_A, BAND_G or BAND_B
- *  @param channel      the channel for looking
- *  @return 	   	A pointer to struct chan_freq_power structure or NULL if not find.
- */
-struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
-	struct lbs_private *priv,
-	u8 band,
-	u16 channel)
-{
-	struct chan_freq_power *cfp = NULL;
-	struct region_channel *rc;
-	int i, j;
-
-	for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
-		rc = &priv->region_channel[j];
-
-		if (!rc->valid || !rc->CFP)
-			continue;
-		if (rc->band != band)
-			continue;
-		for (i = 0; i < rc->nrcfp; i++) {
-			if (rc->CFP[i].channel == channel) {
-				cfp = &rc->CFP[i];
-				break;
-			}
-		}
-	}
-
-	if (!cfp && channel)
-		lbs_deb_wext("lbs_find_cfp_by_band_and_channel: can't find "
-		       "cfp by band %d / channel %d\n", band, channel);
-
-	return cfp;
-}
-
-/**
- *  @brief Find the channel frequency power info with specific frequency
- *
- *  @param priv 	A pointer to struct lbs_private structure
- *  @param band		it can be BAND_A, BAND_G or BAND_B
- *  @param freq	        the frequency for looking
- *  @return 	   	A pointer to struct chan_freq_power structure or NULL if not find.
- */
-static struct chan_freq_power *find_cfp_by_band_and_freq(
-	struct lbs_private *priv,
-	u8 band,
-	u32 freq)
-{
-	struct chan_freq_power *cfp = NULL;
-	struct region_channel *rc;
-	int i, j;
-
-	for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
-		rc = &priv->region_channel[j];
-
-		if (!rc->valid || !rc->CFP)
-			continue;
-		if (rc->band != band)
-			continue;
-		for (i = 0; i < rc->nrcfp; i++) {
-			if (rc->CFP[i].freq == freq) {
-				cfp = &rc->CFP[i];
-				break;
-			}
-		}
-	}
-
-	if (!cfp && freq)
-		lbs_deb_wext("find_cfp_by_band_and_freql: can't find cfp by "
-		       "band %d / freq %d\n", band, freq);
-
-	return cfp;
-}
-
-/**
- *  @brief Copy active data rates based on adapter mode and status
- *
- *  @param priv              A pointer to struct lbs_private structure
- *  @param rate		        The buf to return the active rates
- */
-static void copy_active_data_rates(struct lbs_private *priv, u8 *rates)
-{
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if ((priv->connect_status != LBS_CONNECTED) &&
-		!lbs_mesh_connected(priv))
-		memcpy(rates, lbs_bg_rates, MAX_RATES);
-	else
-		memcpy(rates, priv->curbssparams.rates, MAX_RATES);
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-}
-
-static int lbs_get_name(struct net_device *dev, struct iw_request_info *info,
-			 char *cwrq, char *extra)
-{
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	/* We could add support for 802.11n here as needed. Jean II */
-	snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g");
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-
-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->ml_priv;
-	struct chan_freq_power *cfp;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
-					   priv->channel);
-
-	if (!cfp) {
-		if (priv->channel)
-			lbs_deb_wext("invalid channel %d\n",
-			       priv->channel);
-		return -EINVAL;
-	}
-
-	fwrq->m = (long)cfp->freq * 100000;
-	fwrq->e = 1;
-
-	lbs_deb_wext("freq %u\n", fwrq->m);
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-
-static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info,
-			struct sockaddr *awrq, char *extra)
-{
-	struct lbs_private *priv = dev->ml_priv;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if (priv->connect_status == LBS_CONNECTED) {
-		memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN);
-	} else {
-		memset(awrq->sa_data, 0, ETH_ALEN);
-	}
-	awrq->sa_family = ARPHRD_ETHER;
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-
-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->ml_priv;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	/*
-	 * Check the size of the string
-	 */
-
-	if (dwrq->length > 16) {
-		return -E2BIG;
-	}
-
-	mutex_lock(&priv->lock);
-	memset(priv->nodename, 0, sizeof(priv->nodename));
-	memcpy(priv->nodename, extra, dwrq->length);
-	mutex_unlock(&priv->lock);
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-
-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->ml_priv;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	dwrq->length = strlen(priv->nodename);
-	memcpy(extra, priv->nodename, dwrq->length);
-	extra[dwrq->length] = '\0';
-
-	dwrq->flags = 1;	/* active */
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-
-#ifdef CONFIG_LIBERTAS_MESH
-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->ml_priv;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	/* Use nickname to indicate that mesh is on */
-
-	if (lbs_mesh_connected(priv)) {
-		strncpy(extra, "Mesh", 12);
-		extra[12] = '\0';
-		dwrq->length = strlen(extra);
-	}
-
-	else {
-		extra[0] = '\0';
-		dwrq->length = 0;
-	}
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-#endif
-
-static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
-			struct iw_param *vwrq, char *extra)
-{
-	int ret = 0;
-	struct lbs_private *priv = dev->ml_priv;
-	u32 val = vwrq->value;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if (vwrq->disabled)
-		val = MRVDRV_RTS_MAX_VALUE;
-
-	if (val > MRVDRV_RTS_MAX_VALUE) /* min rts value is 0 */
-		return -EINVAL;
-
-	ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, (u16) val);
-
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-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->ml_priv;
-	int ret = 0;
-	u16 val = 0;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val);
-	if (ret)
-		goto out;
-
-	vwrq->value = val;
-	vwrq->disabled = val > MRVDRV_RTS_MAX_VALUE; /* min rts value is 0 */
-	vwrq->fixed = 1;
-
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-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->ml_priv;
-	int ret = 0;
-	u32 val = vwrq->value;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if (vwrq->disabled)
-		val = MRVDRV_FRAG_MAX_VALUE;
-
-	if (val < MRVDRV_FRAG_MIN_VALUE || val > MRVDRV_FRAG_MAX_VALUE)
-		return -EINVAL;
-
-	ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, (u16) val);
-
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-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->ml_priv;
-	int ret = 0;
-	u16 val = 0;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val);
-	if (ret)
-		goto out;
-
-	vwrq->value = val;
-	vwrq->disabled = ((val < MRVDRV_FRAG_MIN_VALUE)
-			  || (val > MRVDRV_FRAG_MAX_VALUE));
-	vwrq->fixed = 1;
-
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-static int lbs_get_mode(struct net_device *dev,
-			 struct iw_request_info *info, u32 * uwrq, char *extra)
-{
-	struct lbs_private *priv = dev->ml_priv;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	*uwrq = priv->mode;
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-
-#ifdef CONFIG_LIBERTAS_MESH
-static int mesh_wlan_get_mode(struct net_device *dev,
-		              struct iw_request_info *info, u32 * uwrq,
-			      char *extra)
-{
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	*uwrq = IW_MODE_REPEAT;
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-#endif
-
-static int lbs_get_txpow(struct net_device *dev,
-			  struct iw_request_info *info,
-			  struct iw_param *vwrq, char *extra)
-{
-	struct lbs_private *priv = dev->ml_priv;
-	s16 curlevel = 0;
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if (!priv->radio_on) {
-		lbs_deb_wext("tx power off\n");
-		vwrq->value = 0;
-		vwrq->disabled = 1;
-		goto out;
-	}
-
-	ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL);
-	if (ret)
-		goto out;
-
-	lbs_deb_wext("tx power level %d dbm\n", curlevel);
-	priv->txpower_cur = curlevel;
-
-	vwrq->value = curlevel;
-	vwrq->fixed = 1;
-	vwrq->disabled = 0;
-	vwrq->flags = IW_TXPOW_DBM;
-
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-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->ml_priv;
-	int ret = 0;
-	u16 slimit = 0, llimit = 0;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-        if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
-                return -EOPNOTSUPP;
-
-	/* The MAC has a 4-bit Total_Tx_Count register
-	   Total_Tx_Count = 1 + Tx_Retry_Count */
-#define TX_RETRY_MIN 0
-#define TX_RETRY_MAX 14
-	if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
-		return -EINVAL;
-
-	/* Add 1 to convert retry count to try count */
-	if (vwrq->flags & IW_RETRY_SHORT)
-		slimit = (u16) (vwrq->value + 1);
-	else if (vwrq->flags & IW_RETRY_LONG)
-		llimit = (u16) (vwrq->value + 1);
-	else
-		slimit = llimit = (u16) (vwrq->value + 1); /* set both */
-
-	if (llimit) {
-		ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT,
-				       llimit);
-		if (ret)
-			goto out;
-	}
-
-	if (slimit) {
-		/* txretrycount follows the short retry limit */
-		priv->txretrycount = slimit;
-		ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT,
-				       slimit);
-		if (ret)
-			goto out;
-	}
-
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-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->ml_priv;
-	int ret = 0;
-	u16 val = 0;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	vwrq->disabled = 0;
-
-	if (vwrq->flags & IW_RETRY_LONG) {
-		ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, &val);
-		if (ret)
-			goto out;
-
-		/* Subtract 1 to convert try count to retry count */
-		vwrq->value = val - 1;
-		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
-	} else {
-		ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, &val);
-		if (ret)
-			goto out;
-
-		/* txretry count follows the short retry limit */
-		priv->txretrycount = val;
-		/* Subtract 1 to convert try count to retry count */
-		vwrq->value = val - 1;
-		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
-	}
-
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-static inline void sort_channels(struct iw_freq *freq, int num)
-{
-	int i, j;
-	struct iw_freq temp;
-
-	for (i = 0; i < num; i++)
-		for (j = i + 1; j < num; j++)
-			if (freq[i].i > freq[j].i) {
-				temp.i = freq[i].i;
-				temp.m = freq[i].m;
-
-				freq[i].i = freq[j].i;
-				freq[i].m = freq[j].m;
-
-				freq[j].i = temp.i;
-				freq[j].m = temp.m;
-			}
-}
-
-/* data rate listing
-	MULTI_BANDS:
-		abg		a	b	b/g
-   Infra 	G(12)		A(8)	B(4)	G(12)
-   Adhoc 	A+B(12)		A(8)	B(4)	B(4)
-
-	non-MULTI_BANDS:
-					b	b/g
-   Infra 	     		    	B(4)	G(12)
-   Adhoc 	      		    	B(4)	B(4)
- */
-/**
- *  @brief Get Range Info
- *
- *  @param dev                  A pointer to net_device structure
- *  @param info			A pointer to iw_request_info structure
- *  @param vwrq 		A pointer to iw_param structure
- *  @param extra		A pointer to extra data buf
- *  @return 	   		0 --success, otherwise fail
- */
-static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
-			  struct iw_point *dwrq, char *extra)
-{
-	int i, j;
-	struct lbs_private *priv = dev->ml_priv;
-	struct iw_range *range = (struct iw_range *)extra;
-	struct chan_freq_power *cfp;
-	u8 rates[MAX_RATES + 1];
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	dwrq->length = sizeof(struct iw_range);
-	memset(range, 0, sizeof(struct iw_range));
-
-	range->min_nwid = 0;
-	range->max_nwid = 0;
-
-	memset(rates, 0, sizeof(rates));
-	copy_active_data_rates(priv, rates);
-	range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);
-	for (i = 0; i < range->num_bitrates; i++)
-		range->bitrate[i] = rates[i] * 500000;
-	range->num_bitrates = i;
-	lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
-	       range->num_bitrates);
-
-	range->num_frequency = 0;
-
-	range->scan_capa = IW_SCAN_CAPA_ESSID;
-
-	for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
-	     && (j < ARRAY_SIZE(priv->region_channel)); j++) {
-		cfp = priv->region_channel[j].CFP;
-		for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
-		     && priv->region_channel[j].valid
-		     && cfp
-		     && (i < priv->region_channel[j].nrcfp); i++) {
-			range->freq[range->num_frequency].i =
-			    (long)cfp->channel;
-			range->freq[range->num_frequency].m =
-			    (long)cfp->freq * 100000;
-			range->freq[range->num_frequency].e = 1;
-			cfp++;
-			range->num_frequency++;
-		}
-	}
-
-	lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
-	       IW_MAX_FREQUENCIES, range->num_frequency);
-
-	range->num_channels = range->num_frequency;
-
-	sort_channels(&range->freq[0], range->num_frequency);
-
-	/*
-	 * Set an indication of the max TCP throughput in bit/s that we can
-	 * expect using this interface
-	 */
-	if (i > 2)
-		range->throughput = 5000 * 1000;
-	else
-		range->throughput = 1500 * 1000;
-
-	range->min_rts = MRVDRV_RTS_MIN_VALUE;
-	range->max_rts = MRVDRV_RTS_MAX_VALUE;
-	range->min_frag = MRVDRV_FRAG_MIN_VALUE;
-	range->max_frag = MRVDRV_FRAG_MAX_VALUE;
-
-	range->encoding_size[0] = 5;
-	range->encoding_size[1] = 13;
-	range->num_encoding_sizes = 2;
-	range->max_encoding_tokens = 4;
-
-	/*
-	 * Right now we support only "iwconfig ethX power on|off"
-	 */
-	range->pm_capa = IW_POWER_ON;
-
-	/*
-	 * Minimum version we recommend
-	 */
-	range->we_version_source = 15;
-
-	/*
-	 * Version we are compiled with
-	 */
-	range->we_version_compiled = WIRELESS_EXT;
-
-	range->retry_capa = IW_RETRY_LIMIT;
-	range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
-
-	range->min_retry = TX_RETRY_MIN;
-	range->max_retry = TX_RETRY_MAX;
-
-	/*
-	 * Set the qual, level and noise range values
-	 */
-	range->max_qual.qual = 100;
-	range->max_qual.level = 0;
-	range->max_qual.noise = 0;
-	range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
-
-	range->avg_qual.qual = 70;
-	/* TODO: Find real 'good' to 'bad' threshold value for RSSI */
-	range->avg_qual.level = 0;
-	range->avg_qual.noise = 0;
-	range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
-
-	range->sensitivity = 0;
-
-	/* Setup the supported power level ranges */
-	memset(range->txpower, 0, sizeof(range->txpower));
-	range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
-	range->txpower[0] = priv->txpower_min;
-	range->txpower[1] = priv->txpower_max;
-	range->num_txpower = 2;
-
-	range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
-				IW_EVENT_CAPA_MASK(SIOCGIWAP) |
-				IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
-	range->event_capa[1] = IW_EVENT_CAPA_K_1;
-
-	if (priv->fwcapinfo & FW_CAPINFO_WPA) {
-		range->enc_capa =   IW_ENC_CAPA_WPA
-		                  | IW_ENC_CAPA_WPA2
-		                  | IW_ENC_CAPA_CIPHER_TKIP
-		                  | IW_ENC_CAPA_CIPHER_CCMP;
-	}
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-
-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->ml_priv;
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
-		if (vwrq->disabled)
-			return 0;
-		else
-			return -EINVAL;
-	}
-
-	/* PS is currently supported only in Infrastructure mode
-	 * Remove this check if it is to be supported in IBSS mode also
-	 */
-
-	if (vwrq->disabled) {
-		priv->psmode = LBS802_11POWERMODECAM;
-		if (priv->psstate != PS_STATE_FULL_POWER) {
-			lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
-		}
-
-		return 0;
-	}
-
-	if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-		lbs_deb_wext(
-		       "setting power timeout is not supported\n");
-		return -EINVAL;
-	} else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
-		vwrq->value = vwrq->value / 1000;
-		if (!priv->enter_deep_sleep) {
-			lbs_pr_err("deep sleep feature is not implemented "
-					"for this interface driver\n");
-			return -EINVAL;
-		}
-
-		if (priv->connect_status == LBS_CONNECTED) {
-			if ((priv->is_auto_deep_sleep_enabled) &&
-						(vwrq->value == -1000)) {
-				lbs_exit_auto_deep_sleep(priv);
-				return 0;
-			} else {
-				lbs_pr_err("can't use deep sleep cmd in "
-						"connected state\n");
-				return -EINVAL;
-			}
-		}
-
-		if ((vwrq->value < 0) && (vwrq->value != -1000)) {
-			lbs_pr_err("unknown option\n");
-			return -EINVAL;
-		}
-
-		if (vwrq->value > 0) {
-			if (!priv->is_auto_deep_sleep_enabled) {
-				priv->is_activity_detected = 0;
-				priv->auto_deep_sleep_timeout = vwrq->value;
-				lbs_enter_auto_deep_sleep(priv);
-			} else {
-				priv->auto_deep_sleep_timeout = vwrq->value;
-				lbs_deb_debugfs("auto deep sleep: "
-						"already enabled\n");
-			}
-			return 0;
-		} else {
-			if (priv->is_auto_deep_sleep_enabled) {
-				lbs_exit_auto_deep_sleep(priv);
-				/* Try to exit deep sleep if auto */
-				/*deep sleep disabled */
-				ret = lbs_set_deep_sleep(priv, 0);
-			}
-			if (vwrq->value == 0)
-				ret = lbs_set_deep_sleep(priv, 1);
-			else if (vwrq->value == -1000)
-				ret = lbs_set_deep_sleep(priv, 0);
-			return ret;
-		}
-	}
-
-	if (priv->psmode != LBS802_11POWERMODECAM) {
-		return 0;
-	}
-
-	priv->psmode = LBS802_11POWERMODEMAX_PSP;
-
-	if (priv->connect_status == LBS_CONNECTED) {
-		lbs_ps_sleep(priv, CMD_OPTION_WAITFORRSP);
-	}
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-
-	return 0;
-}
-
-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->ml_priv;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	vwrq->value = 0;
-	vwrq->flags = 0;
-	vwrq->disabled = priv->psmode == LBS802_11POWERMODECAM
-		|| priv->connect_status == LBS_DISCONNECTED;
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-
-static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
-{
-	enum {
-		POOR = 30,
-		FAIR = 60,
-		GOOD = 80,
-		VERY_GOOD = 90,
-		EXCELLENT = 95,
-		PERFECT = 100
-	};
-	struct lbs_private *priv = dev->ml_priv;
-	u32 rssi_qual;
-	u32 tx_qual;
-	u32 quality = 0;
-	int ret, stats_valid = 0;
-	u8 rssi;
-	u32 tx_retries;
-	struct cmd_ds_802_11_get_log log;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	priv->wstats.status = priv->mode;
-
-	/* If we're not associated, all quality values are meaningless */
-	if ((priv->connect_status != LBS_CONNECTED) &&
-	    !lbs_mesh_connected(priv))
-		goto out;
-
-	/* Quality by RSSI */
-	priv->wstats.qual.level =
-	    CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
-	     priv->NF[TYPE_BEACON][TYPE_NOAVG]);
-
-	if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
-		priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
-	} else {
-		priv->wstats.qual.noise =
-		    CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
-	}
-
-	lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
-	lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);
-
-	rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
-	if (rssi < 15)
-		rssi_qual = rssi * POOR / 10;
-	else if (rssi < 20)
-		rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
-	else if (rssi < 30)
-		rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
-	else if (rssi < 40)
-		rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
-		    10 + GOOD;
-	else
-		rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
-		    10 + VERY_GOOD;
-	quality = rssi_qual;
-
-	/* Quality by TX errors */
-	priv->wstats.discard.retries = dev->stats.tx_errors;
-
-	memset(&log, 0, sizeof(log));
-	log.hdr.size = cpu_to_le16(sizeof(log));
-	ret = lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
-	if (ret)
-		goto out;
-
-	tx_retries = le32_to_cpu(log.retry);
-
-	if (tx_retries > 75)
-		tx_qual = (90 - tx_retries) * POOR / 15;
-	else if (tx_retries > 70)
-		tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
-	else if (tx_retries > 65)
-		tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
-	else if (tx_retries > 50)
-		tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
-		    15 + GOOD;
-	else
-		tx_qual = (50 - tx_retries) *
-		    (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
-	quality = min(quality, tx_qual);
-
-	priv->wstats.discard.code = le32_to_cpu(log.wepundecryptable);
-	priv->wstats.discard.retries = tx_retries;
-	priv->wstats.discard.misc = le32_to_cpu(log.ackfailure);
-
-	/* Calculate quality */
-	priv->wstats.qual.qual = min_t(u8, quality, 100);
-	priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
-	stats_valid = 1;
-
-	/* update stats asynchronously for future calls */
-	ret = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
-					0, 0, NULL);
-	if (ret)
-		lbs_pr_err("RSSI command failed\n");
-out:
-	if (!stats_valid) {
-		priv->wstats.miss.beacon = 0;
-		priv->wstats.discard.retries = 0;
-		priv->wstats.qual.qual = 0;
-		priv->wstats.qual.level = 0;
-		priv->wstats.qual.noise = 0;
-		priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
-		priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
-		    IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
-	}
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return &priv->wstats;
-
-
-}
-
-static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,
-		  struct iw_freq *fwrq, char *extra)
-{
-	int ret = -EINVAL;
-	struct lbs_private *priv = dev->ml_priv;
-	struct chan_freq_power *cfp;
-	struct assoc_request * assoc_req;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	mutex_lock(&priv->lock);
-	assoc_req = lbs_get_association_request(priv);
-	if (!assoc_req) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	/* If setting by frequency, convert to a channel */
-	if (fwrq->e == 1) {
-		long f = fwrq->m / 100000;
-
-		cfp = find_cfp_by_band_and_freq(priv, 0, f);
-		if (!cfp) {
-			lbs_deb_wext("invalid freq %ld\n", f);
-			goto out;
-		}
-
-		fwrq->e = 0;
-		fwrq->m = (int) cfp->channel;
-	}
-
-	/* Setting by channel number */
-	if (fwrq->m > 1000 || fwrq->e > 0) {
-		goto out;
-	}
-
-	cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
-	if (!cfp) {
-		goto out;
-	}
-
-	assoc_req->channel = fwrq->m;
-	ret = 0;
-
-out:
-	if (ret == 0) {
-		set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags);
-		lbs_postpone_association_work(priv);
-	} else {
-		lbs_cancel_association_work(priv);
-	}
-	mutex_unlock(&priv->lock);
-
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-#ifdef CONFIG_LIBERTAS_MESH
-static int lbs_mesh_set_freq(struct net_device *dev,
-			     struct iw_request_info *info,
-			     struct iw_freq *fwrq, char *extra)
-{
-	struct lbs_private *priv = dev->ml_priv;
-	struct chan_freq_power *cfp;
-	int ret = -EINVAL;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	/* If setting by frequency, convert to a channel */
-	if (fwrq->e == 1) {
-		long f = fwrq->m / 100000;
-
-		cfp = find_cfp_by_band_and_freq(priv, 0, f);
-		if (!cfp) {
-			lbs_deb_wext("invalid freq %ld\n", f);
-			goto out;
-		}
-
-		fwrq->e = 0;
-		fwrq->m = (int) cfp->channel;
-	}
-
-	/* Setting by channel number */
-	if (fwrq->m > 1000 || fwrq->e > 0) {
-		goto out;
-	}
-
-	cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
-	if (!cfp) {
-		goto out;
-	}
-
-	if (fwrq->m != priv->channel) {
-		lbs_deb_wext("mesh channel change forces eth disconnect\n");
-		if (priv->mode == IW_MODE_INFRA)
-			lbs_cmd_80211_deauthenticate(priv,
-						     priv->curbssparams.bssid,
-						     WLAN_REASON_DEAUTH_LEAVING);
-		else if (priv->mode == IW_MODE_ADHOC)
-			lbs_adhoc_stop(priv);
-	}
-	lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m);
-	lbs_update_channel(priv);
-	ret = 0;
-
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-#endif
-
-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->ml_priv;
-	u8 new_rate = 0;
-	int ret = -EINVAL;
-	u8 rates[MAX_RATES + 1];
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	lbs_deb_wext("vwrq->value %d\n", vwrq->value);
-	lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
-
-	if (vwrq->fixed && vwrq->value == -1)
-		goto out;
-
-	/* Auto rate? */
-	priv->enablehwauto = !vwrq->fixed;
-
-	if (vwrq->value == -1)
-		priv->cur_rate = 0;
-	else {
-		if (vwrq->value % 100000)
-			goto out;
-
-		new_rate = vwrq->value / 500000;
-		priv->cur_rate = new_rate;
-		/* the rest is only needed for lbs_set_data_rate() */
-		memset(rates, 0, sizeof(rates));
-		copy_active_data_rates(priv, rates);
-		if (!memchr(rates, new_rate, sizeof(rates))) {
-			lbs_pr_alert("fixed data rate 0x%X out of range\n",
-				new_rate);
-			goto out;
-		}
-		if (priv->fwrelease < 0x09000000) {
-			ret = lbs_set_power_adapt_cfg(priv, 0,
-					POW_ADAPT_DEFAULT_P0,
-					POW_ADAPT_DEFAULT_P1,
-					POW_ADAPT_DEFAULT_P2);
-			if (ret)
-				goto out;
-		}
-		ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
-				TPC_DEFAULT_P2, 1);
-		if (ret)
-			goto out;
-	}
-
-	/* Try the newer command first (Firmware Spec 5.1 and above) */
-	ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET);
-
-	/* Fallback to older version */
-	if (ret)
-		ret = lbs_set_data_rate(priv, new_rate);
-
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-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->ml_priv;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if (priv->connect_status == LBS_CONNECTED) {
-		vwrq->value = priv->cur_rate * 500000;
-
-		if (priv->enablehwauto)
-			vwrq->fixed = 0;
-		else
-			vwrq->fixed = 1;
-
-	} else {
-		vwrq->fixed = 0;
-		vwrq->value = 0;
-	}
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-
-static int lbs_set_mode(struct net_device *dev,
-		  struct iw_request_info *info, u32 * uwrq, char *extra)
-{
-	int ret = 0;
-	struct lbs_private *priv = dev->ml_priv;
-	struct assoc_request * assoc_req;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if (   (*uwrq != IW_MODE_ADHOC)
-	    && (*uwrq != IW_MODE_INFRA)
-	    && (*uwrq != IW_MODE_AUTO)) {
-		lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	mutex_lock(&priv->lock);
-	assoc_req = lbs_get_association_request(priv);
-	if (!assoc_req) {
-		ret = -ENOMEM;
-		lbs_cancel_association_work(priv);
-	} else {
-		assoc_req->mode = *uwrq;
-		set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
-		lbs_postpone_association_work(priv);
-		lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
-	}
-	mutex_unlock(&priv->lock);
-
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-
-/**
- *  @brief Get Encryption key
- *
- *  @param dev                  A pointer to net_device structure
- *  @param info			A pointer to iw_request_info structure
- *  @param vwrq 		A pointer to iw_param structure
- *  @param extra		A pointer to extra data buf
- *  @return 	   		0 --success, otherwise fail
- */
-static int lbs_get_encode(struct net_device *dev,
-			   struct iw_request_info *info,
-			   struct iw_point *dwrq, u8 * extra)
-{
-	struct lbs_private *priv = dev->ml_priv;
-	int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
-	       dwrq->flags, index, dwrq->length, priv->wep_tx_keyidx);
-
-	dwrq->flags = 0;
-
-	/* Authentication method */
-	switch (priv->secinfo.auth_mode) {
-	case IW_AUTH_ALG_OPEN_SYSTEM:
-		dwrq->flags = IW_ENCODE_OPEN;
-		break;
-
-	case IW_AUTH_ALG_SHARED_KEY:
-	case IW_AUTH_ALG_LEAP:
-		dwrq->flags = IW_ENCODE_RESTRICTED;
-		break;
-	default:
-		dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
-		break;
-	}
-
-	memset(extra, 0, 16);
-
-	mutex_lock(&priv->lock);
-
-	/* Default to returning current transmit key */
-	if (index < 0)
-		index = priv->wep_tx_keyidx;
-
-	if ((priv->wep_keys[index].len) && priv->secinfo.wep_enabled) {
-		memcpy(extra, priv->wep_keys[index].key,
-		       priv->wep_keys[index].len);
-		dwrq->length = priv->wep_keys[index].len;
-
-		dwrq->flags |= (index + 1);
-		/* Return WEP enabled */
-		dwrq->flags &= ~IW_ENCODE_DISABLED;
-	} else if ((priv->secinfo.WPAenabled)
-		   || (priv->secinfo.WPA2enabled)) {
-		/* return WPA enabled */
-		dwrq->flags &= ~IW_ENCODE_DISABLED;
-		dwrq->flags |= IW_ENCODE_NOKEY;
-	} else {
-		dwrq->flags |= IW_ENCODE_DISABLED;
-	}
-
-	mutex_unlock(&priv->lock);
-
-	lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
-	       extra[0], extra[1], extra[2],
-	       extra[3], extra[4], extra[5], dwrq->length);
-
-	lbs_deb_wext("return flags 0x%x\n", dwrq->flags);
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-
-/**
- *  @brief Set Encryption key (internal)
- *
- *  @param priv			A pointer to private card structure
- *  @param key_material		A pointer to key material
- *  @param key_length		length of key material
- *  @param index		key index to set
- *  @param set_tx_key		Force set TX key (1 = yes, 0 = no)
- *  @return 	   		0 --success, otherwise fail
- */
-static int lbs_set_wep_key(struct assoc_request *assoc_req,
-			    const char *key_material,
-			    u16 key_length,
-			    u16 index,
-			    int set_tx_key)
-{
-	int ret = 0;
-	struct enc_key *pkey;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	/* Paranoid validation of key index */
-	if (index > 3) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	/* validate max key length */
-	if (key_length > KEY_LEN_WEP_104) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	pkey = &assoc_req->wep_keys[index];
-
-	if (key_length > 0) {
-		memset(pkey, 0, sizeof(struct enc_key));
-		pkey->type = KEY_TYPE_ID_WEP;
-
-		/* Standardize the key length */
-		pkey->len = (key_length > KEY_LEN_WEP_40) ?
-		                KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
-		memcpy(pkey->key, key_material, key_length);
-	}
-
-	if (set_tx_key) {
-		/* Ensure the chosen key is valid */
-		if (!pkey->len) {
-			lbs_deb_wext("key not set, so cannot enable it\n");
-			ret = -EINVAL;
-			goto out;
-		}
-		assoc_req->wep_tx_keyidx = index;
-	}
-
-	assoc_req->secinfo.wep_enabled = 1;
-
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-static int validate_key_index(u16 def_index, u16 raw_index,
-			      u16 *out_index, u16 *is_default)
-{
-	if (!out_index || !is_default)
-		return -EINVAL;
-
-	/* Verify index if present, otherwise use default TX key index */
-	if (raw_index > 0) {
-		if (raw_index > 4)
-			return -EINVAL;
-		*out_index = raw_index - 1;
-	} else {
-		*out_index = def_index;
-		*is_default = 1;
-	}
-	return 0;
-}
-
-static void disable_wep(struct assoc_request *assoc_req)
-{
-	int i;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	/* Set Open System auth mode */
-	assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-
-	/* Clear WEP keys and mark WEP as disabled */
-	assoc_req->secinfo.wep_enabled = 0;
-	for (i = 0; i < 4; i++)
-		assoc_req->wep_keys[i].len = 0;
-
-	set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-	set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-}
-
-static void disable_wpa(struct assoc_request *assoc_req)
-{
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key));
-	assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
-	set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
-
-	memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key));
-	assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
-	set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
-
-	assoc_req->secinfo.WPAenabled = 0;
-	assoc_req->secinfo.WPA2enabled = 0;
-	set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-}
-
-/**
- *  @brief Set Encryption key
- *
- *  @param dev                  A pointer to net_device structure
- *  @param info			A pointer to iw_request_info structure
- *  @param vwrq 		A pointer to iw_param structure
- *  @param extra		A pointer to extra data buf
- *  @return 	   		0 --success, otherwise fail
- */
-static int lbs_set_encode(struct net_device *dev,
-		    struct iw_request_info *info,
-		    struct iw_point *dwrq, char *extra)
-{
-	int ret = 0;
-	struct lbs_private *priv = dev->ml_priv;
-	struct assoc_request * assoc_req;
-	u16 is_default = 0, index = 0, set_tx_key = 0;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	mutex_lock(&priv->lock);
-	assoc_req = lbs_get_association_request(priv);
-	if (!assoc_req) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	if (dwrq->flags & IW_ENCODE_DISABLED) {
-		disable_wep (assoc_req);
-		disable_wpa (assoc_req);
-		goto out;
-	}
-
-	ret = validate_key_index(assoc_req->wep_tx_keyidx,
-	                         (dwrq->flags & IW_ENCODE_INDEX),
-	                         &index, &is_default);
-	if (ret) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	/* If WEP isn't enabled, or if there is no key data but a valid
-	 * index, set the TX key.
-	 */
-	if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
-		set_tx_key = 1;
-
-	ret = lbs_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
-	if (ret)
-		goto out;
-
-	if (dwrq->length)
-		set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
-	if (set_tx_key)
-		set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
-
-	if (dwrq->flags & IW_ENCODE_RESTRICTED) {
-		priv->authtype_auto = 0;
-		assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
-	} else if (dwrq->flags & IW_ENCODE_OPEN) {
-		priv->authtype_auto = 0;
-		assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-	}
-
-out:
-	if (ret == 0) {
-		set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-		lbs_postpone_association_work(priv);
-	} else {
-		lbs_cancel_association_work(priv);
-	}
-	mutex_unlock(&priv->lock);
-
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-/**
- *  @brief Get Extended Encryption key (WPA/802.1x and WEP)
- *
- *  @param dev                  A pointer to net_device structure
- *  @param info			A pointer to iw_request_info structure
- *  @param vwrq 		A pointer to iw_param structure
- *  @param extra		A pointer to extra data buf
- *  @return 	   		0 on success, otherwise failure
- */
-static int lbs_get_encodeext(struct net_device *dev,
-			      struct iw_request_info *info,
-			      struct iw_point *dwrq,
-			      char *extra)
-{
-	int ret = -EINVAL;
-	struct lbs_private *priv = dev->ml_priv;
-	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-	int index, max_key_len;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	max_key_len = dwrq->length - sizeof(*ext);
-	if (max_key_len < 0)
-		goto out;
-
-	index = dwrq->flags & IW_ENCODE_INDEX;
-	if (index) {
-		if (index < 1 || index > 4)
-			goto out;
-		index--;
-	} else {
-		index = priv->wep_tx_keyidx;
-	}
-
-	if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
-	    ext->alg != IW_ENCODE_ALG_WEP) {
-		if (index != 0 || priv->mode != IW_MODE_INFRA)
-			goto out;
-	}
-
-	dwrq->flags = index + 1;
-	memset(ext, 0, sizeof(*ext));
-
-	if (   !priv->secinfo.wep_enabled
-	    && !priv->secinfo.WPAenabled
-	    && !priv->secinfo.WPA2enabled) {
-		ext->alg = IW_ENCODE_ALG_NONE;
-		ext->key_len = 0;
-		dwrq->flags |= IW_ENCODE_DISABLED;
-	} else {
-		u8 *key = NULL;
-
-		if (   priv->secinfo.wep_enabled
-		    && !priv->secinfo.WPAenabled
-		    && !priv->secinfo.WPA2enabled) {
-			/* WEP */
-			ext->alg = IW_ENCODE_ALG_WEP;
-			ext->key_len = priv->wep_keys[index].len;
-			key = &priv->wep_keys[index].key[0];
-		} else if (   !priv->secinfo.wep_enabled
-		           && (priv->secinfo.WPAenabled ||
-		               priv->secinfo.WPA2enabled)) {
-			/* WPA */
-			struct enc_key * pkey = NULL;
-
-			if (   priv->wpa_mcast_key.len
-			    && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
-				pkey = &priv->wpa_mcast_key;
-			else if (   priv->wpa_unicast_key.len
-			         && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
-				pkey = &priv->wpa_unicast_key;
-
-			if (pkey) {
-				if (pkey->type == KEY_TYPE_ID_AES) {
-					ext->alg = IW_ENCODE_ALG_CCMP;
-				} else {
-					ext->alg = IW_ENCODE_ALG_TKIP;
-				}
-				ext->key_len = pkey->len;
-				key = &pkey->key[0];
-			} else {
-				ext->alg = IW_ENCODE_ALG_TKIP;
-				ext->key_len = 0;
-			}
-		} else {
-			goto out;
-		}
-
-		if (ext->key_len > max_key_len) {
-			ret = -E2BIG;
-			goto out;
-		}
-
-		if (ext->key_len)
-			memcpy(ext->key, key, ext->key_len);
-		else
-			dwrq->flags |= IW_ENCODE_NOKEY;
-		dwrq->flags |= IW_ENCODE_ENABLED;
-	}
-	ret = 0;
-
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-/**
- *  @brief Set Encryption key Extended (WPA/802.1x and WEP)
- *
- *  @param dev                  A pointer to net_device structure
- *  @param info			A pointer to iw_request_info structure
- *  @param vwrq 		A pointer to iw_param structure
- *  @param extra		A pointer to extra data buf
- *  @return 	   		0 --success, otherwise fail
- */
-static int lbs_set_encodeext(struct net_device *dev,
-			      struct iw_request_info *info,
-			      struct iw_point *dwrq,
-			      char *extra)
-{
-	int ret = 0;
-	struct lbs_private *priv = dev->ml_priv;
-	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-	int alg = ext->alg;
-	struct assoc_request * assoc_req;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	mutex_lock(&priv->lock);
-	assoc_req = lbs_get_association_request(priv);
-	if (!assoc_req) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
-		disable_wep (assoc_req);
-		disable_wpa (assoc_req);
-	} else if (alg == IW_ENCODE_ALG_WEP) {
-		u16 is_default = 0, index, set_tx_key = 0;
-
-		ret = validate_key_index(assoc_req->wep_tx_keyidx,
-		                         (dwrq->flags & IW_ENCODE_INDEX),
-		                         &index, &is_default);
-		if (ret)
-			goto out;
-
-		/* If WEP isn't enabled, or if there is no key data but a valid
-		 * index, or if the set-TX-key flag was passed, set the TX key.
-		 */
-		if (   !assoc_req->secinfo.wep_enabled
-		    || (dwrq->length == 0 && !is_default)
-		    || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
-			set_tx_key = 1;
-
-		/* Copy key to driver */
-		ret = lbs_set_wep_key(assoc_req, ext->key, ext->key_len, index,
-					set_tx_key);
-		if (ret)
-			goto out;
-
-		if (dwrq->flags & IW_ENCODE_RESTRICTED) {
-			priv->authtype_auto = 0;
-			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
-		} else if (dwrq->flags & IW_ENCODE_OPEN) {
-			priv->authtype_auto = 0;
-			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-		}
-
-		/* Mark the various WEP bits as modified */
-		set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-		if (dwrq->length)
-			set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
-		if (set_tx_key)
-			set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
-	} else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
-		struct enc_key * pkey;
-
-		/* validate key length */
-		if (((alg == IW_ENCODE_ALG_TKIP)
-			&& (ext->key_len != KEY_LEN_WPA_TKIP))
-		    || ((alg == IW_ENCODE_ALG_CCMP)
-		        && (ext->key_len != KEY_LEN_WPA_AES))) {
-				lbs_deb_wext("invalid size %d for key of alg "
-				       "type %d\n",
-				       ext->key_len,
-				       alg);
-				ret = -EINVAL;
-				goto out;
-		}
-
-		if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
-			pkey = &assoc_req->wpa_mcast_key;
-			set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
-		} else {
-			pkey = &assoc_req->wpa_unicast_key;
-			set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
-		}
-
-		memset(pkey, 0, sizeof (struct enc_key));
-		memcpy(pkey->key, ext->key, ext->key_len);
-		pkey->len = ext->key_len;
-		if (pkey->len)
-			pkey->flags |= KEY_INFO_WPA_ENABLED;
-
-		/* Do this after zeroing key structure */
-		if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
-			pkey->flags |= KEY_INFO_WPA_MCAST;
-		} else {
-			pkey->flags |= KEY_INFO_WPA_UNICAST;
-		}
-
-		if (alg == IW_ENCODE_ALG_TKIP) {
-			pkey->type = KEY_TYPE_ID_TKIP;
-		} else if (alg == IW_ENCODE_ALG_CCMP) {
-			pkey->type = KEY_TYPE_ID_AES;
-		}
-
-		/* If WPA isn't enabled yet, do that now */
-		if (   assoc_req->secinfo.WPAenabled == 0
-		    && assoc_req->secinfo.WPA2enabled == 0) {
-			assoc_req->secinfo.WPAenabled = 1;
-			assoc_req->secinfo.WPA2enabled = 1;
-			set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-		}
-
-		/* Only disable wep if necessary: can't waste time here. */
-		if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE)
-			disable_wep(assoc_req);
-	}
-
-out:
-	if (ret == 0) {
-		/* 802.1x and WPA rekeying must happen as quickly as possible,
-		 * especially during the 4-way handshake; thus if in
-		 * infrastructure mode, and either (a) 802.1x is enabled or
-		 * (b) WPA is being used, set the key right away.
-		 */
-		if (assoc_req->mode == IW_MODE_INFRA &&
-		    ((assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_802_1X) ||
-		     (assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_PSK) ||
-		      assoc_req->secinfo.WPAenabled ||
-		      assoc_req->secinfo.WPA2enabled)) {
-			lbs_do_association_work(priv);
-		} else
-			lbs_postpone_association_work(priv);
-	} else {
-		lbs_cancel_association_work(priv);
-	}
-	mutex_unlock(&priv->lock);
-
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-
-static int lbs_set_genie(struct net_device *dev,
-			  struct iw_request_info *info,
-			  struct iw_point *dwrq,
-			  char *extra)
-{
-	struct lbs_private *priv = dev->ml_priv;
-	int ret = 0;
-	struct assoc_request * assoc_req;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	mutex_lock(&priv->lock);
-	assoc_req = lbs_get_association_request(priv);
-	if (!assoc_req) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	if (dwrq->length > MAX_WPA_IE_LEN ||
-	    (dwrq->length && extra == NULL)) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (dwrq->length) {
-		memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
-		assoc_req->wpa_ie_len = dwrq->length;
-	} else {
-		memset(&assoc_req->wpa_ie[0], 0, sizeof(priv->wpa_ie));
-		assoc_req->wpa_ie_len = 0;
-	}
-
-out:
-	if (ret == 0) {
-		set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
-		lbs_postpone_association_work(priv);
-	} else {
-		lbs_cancel_association_work(priv);
-	}
-	mutex_unlock(&priv->lock);
-
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-static int lbs_get_genie(struct net_device *dev,
-			  struct iw_request_info *info,
-			  struct iw_point *dwrq,
-			  char *extra)
-{
-	int ret = 0;
-	struct lbs_private *priv = dev->ml_priv;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if (priv->wpa_ie_len == 0) {
-		dwrq->length = 0;
-		goto out;
-	}
-
-	if (dwrq->length < priv->wpa_ie_len) {
-		ret = -E2BIG;
-		goto out;
-	}
-
-	dwrq->length = priv->wpa_ie_len;
-	memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len);
-
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-
-static int lbs_set_auth(struct net_device *dev,
-			 struct iw_request_info *info,
-			 struct iw_param *dwrq,
-			 char *extra)
-{
-	struct lbs_private *priv = dev->ml_priv;
-	struct assoc_request * assoc_req;
-	int ret = 0;
-	int updated = 0;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	mutex_lock(&priv->lock);
-	assoc_req = lbs_get_association_request(priv);
-	if (!assoc_req) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	switch (dwrq->flags & IW_AUTH_INDEX) {
-	case IW_AUTH_PRIVACY_INVOKED:
-	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
-	case IW_AUTH_TKIP_COUNTERMEASURES:
-	case IW_AUTH_CIPHER_PAIRWISE:
-	case IW_AUTH_CIPHER_GROUP:
-	case IW_AUTH_DROP_UNENCRYPTED:
-		/*
-		 * libertas does not use these parameters
-		 */
-		break;
-
-	case IW_AUTH_KEY_MGMT:
-		assoc_req->secinfo.key_mgmt = dwrq->value;
-		updated = 1;
-		break;
-
-	case IW_AUTH_WPA_VERSION:
-		if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
-			assoc_req->secinfo.WPAenabled = 0;
-			assoc_req->secinfo.WPA2enabled = 0;
-			disable_wpa (assoc_req);
-		}
-		if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
-			assoc_req->secinfo.WPAenabled = 1;
-			assoc_req->secinfo.wep_enabled = 0;
-			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-		}
-		if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
-			assoc_req->secinfo.WPA2enabled = 1;
-			assoc_req->secinfo.wep_enabled = 0;
-			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-		}
-		updated = 1;
-		break;
-
-	case IW_AUTH_80211_AUTH_ALG:
-		if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
-			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
-		} else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
-			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-		} else if (dwrq->value & IW_AUTH_ALG_LEAP) {
-			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
-		} else {
-			ret = -EINVAL;
-		}
-		updated = 1;
-		break;
-
-	case IW_AUTH_WPA_ENABLED:
-		if (dwrq->value) {
-			if (!assoc_req->secinfo.WPAenabled &&
-			    !assoc_req->secinfo.WPA2enabled) {
-				assoc_req->secinfo.WPAenabled = 1;
-				assoc_req->secinfo.WPA2enabled = 1;
-				assoc_req->secinfo.wep_enabled = 0;
-				assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-			}
-		} else {
-			assoc_req->secinfo.WPAenabled = 0;
-			assoc_req->secinfo.WPA2enabled = 0;
-			disable_wpa (assoc_req);
-		}
-		updated = 1;
-		break;
-
-	default:
-		ret = -EOPNOTSUPP;
-		break;
-	}
-
-out:
-	if (ret == 0) {
-		if (updated)
-			set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-		lbs_postpone_association_work(priv);
-	} else if (ret != -EOPNOTSUPP) {
-		lbs_cancel_association_work(priv);
-	}
-	mutex_unlock(&priv->lock);
-
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-static int lbs_get_auth(struct net_device *dev,
-			 struct iw_request_info *info,
-			 struct iw_param *dwrq,
-			 char *extra)
-{
-	int ret = 0;
-	struct lbs_private *priv = dev->ml_priv;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	switch (dwrq->flags & IW_AUTH_INDEX) {
-	case IW_AUTH_KEY_MGMT:
-		dwrq->value = priv->secinfo.key_mgmt;
-		break;
-
-	case IW_AUTH_WPA_VERSION:
-		dwrq->value = 0;
-		if (priv->secinfo.WPAenabled)
-			dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
-		if (priv->secinfo.WPA2enabled)
-			dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
-		if (!dwrq->value)
-			dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
-		break;
-
-	case IW_AUTH_80211_AUTH_ALG:
-		dwrq->value = priv->secinfo.auth_mode;
-		break;
-
-	case IW_AUTH_WPA_ENABLED:
-		if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled)
-			dwrq->value = 1;
-		break;
-
-	default:
-		ret = -EOPNOTSUPP;
-	}
-
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-
-static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
-		   struct iw_param *vwrq, char *extra)
-{
-	int ret = 0;
-	struct lbs_private *priv = dev->ml_priv;
-	s16 dbm = (s16) vwrq->value;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if (vwrq->disabled) {
-		lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);
-		goto out;
-	}
-
-	if (vwrq->fixed == 0) {
-		/* User requests automatic tx power control, however there are
-		 * many auto tx settings.  For now use firmware defaults until
-		 * we come up with a good way to expose these to the user. */
-		if (priv->fwrelease < 0x09000000) {
-			ret = lbs_set_power_adapt_cfg(priv, 1,
-					POW_ADAPT_DEFAULT_P0,
-					POW_ADAPT_DEFAULT_P1,
-					POW_ADAPT_DEFAULT_P2);
-			if (ret)
-				goto out;
-		}
-		ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
-				TPC_DEFAULT_P2, 1);
-		if (ret)
-			goto out;
-		dbm = priv->txpower_max;
-	} else {
-		/* Userspace check in iwrange if it should use dBm or mW,
-		 * therefore this should never happen... Jean II */
-		if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
-			ret = -EOPNOTSUPP;
-			goto out;
-		}
-
-		/* Validate requested power level against firmware allowed
-		 * levels */
-		if (priv->txpower_min && (dbm < priv->txpower_min)) {
-			ret = -EINVAL;
-			goto out;
-		}
-
-		if (priv->txpower_max && (dbm > priv->txpower_max)) {
-			ret = -EINVAL;
-			goto out;
-		}
-		if (priv->fwrelease < 0x09000000) {
-			ret = lbs_set_power_adapt_cfg(priv, 0,
-					POW_ADAPT_DEFAULT_P0,
-					POW_ADAPT_DEFAULT_P1,
-					POW_ADAPT_DEFAULT_P2);
-			if (ret)
-				goto out;
-		}
-		ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
-				TPC_DEFAULT_P2, 1);
-		if (ret)
-			goto out;
-	}
-
-	/* If the radio was off, turn it on */
-	if (!priv->radio_on) {
-		ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1);
-		if (ret)
-			goto out;
-	}
-
-	lbs_deb_wext("txpower set %d dBm\n", dbm);
-
-	ret = lbs_set_tx_power(priv, dbm);
-
-out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-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->ml_priv;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	/*
-	 * Note : if dwrq->flags != 0, we should get the relevant SSID from
-	 * the SSID list...
-	 */
-
-	/*
-	 * Get the current SSID
-	 */
-	if (priv->connect_status == LBS_CONNECTED) {
-		memcpy(extra, priv->curbssparams.ssid,
-		       priv->curbssparams.ssid_len);
-	} else {
-		memset(extra, 0, 32);
-	}
-	/*
-	 * If none, we may want to get the one that was set
-	 */
-
-	dwrq->length = priv->curbssparams.ssid_len;
-
-	dwrq->flags = 1;	/* active */
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-
-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->ml_priv;
-	int ret = 0;
-	u8 ssid[IEEE80211_MAX_SSID_LEN];
-	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);
-
-	if (!priv->radio_on) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	/* Check the size of the string */
-	if (in_ssid_len > IEEE80211_MAX_SSID_LEN) {
-		ret = -E2BIG;
-		goto out;
-	}
-
-	memset(&ssid, 0, sizeof(ssid));
-
-	if (!dwrq->flags || !in_ssid_len) {
-		/* "any" SSID requested; leave SSID blank */
-	} else {
-		/* Specific SSID requested */
-		memcpy(&ssid, extra, in_ssid_len);
-		ssid_len = in_ssid_len;
-	}
-
-	if (!ssid_len) {
-		lbs_deb_wext("requested any SSID\n");
-	} else {
-		lbs_deb_wext("requested SSID '%s'\n",
-		             print_ssid(ssid_buf, ssid, ssid_len));
-	}
-
-out:
-	mutex_lock(&priv->lock);
-	if (ret == 0) {
-		/* Get or create the current association request */
-		assoc_req = lbs_get_association_request(priv);
-		if (!assoc_req) {
-			ret = -ENOMEM;
-		} else {
-			/* Copy the SSID to the association request */
-			memcpy(&assoc_req->ssid, &ssid, IEEE80211_MAX_SSID_LEN);
-			assoc_req->ssid_len = ssid_len;
-			set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
-			lbs_postpone_association_work(priv);
-		}
-	}
-
-	/* Cancel the association request if there was an error */
-	if (ret != 0) {
-		lbs_cancel_association_work(priv);
-	}
-
-	mutex_unlock(&priv->lock);
-
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-
-#ifdef CONFIG_LIBERTAS_MESH
-static int lbs_mesh_get_essid(struct net_device *dev,
-			      struct iw_request_info *info,
-			      struct iw_point *dwrq, char *extra)
-{
-	struct lbs_private *priv = dev->ml_priv;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	memcpy(extra, priv->mesh_ssid, priv->mesh_ssid_len);
-
-	dwrq->length = priv->mesh_ssid_len;
-
-	dwrq->flags = 1;	/* active */
-
-	lbs_deb_leave(LBS_DEB_WEXT);
-	return 0;
-}
-
-static int lbs_mesh_set_essid(struct net_device *dev,
-			      struct iw_request_info *info,
-			      struct iw_point *dwrq, char *extra)
-{
-	struct lbs_private *priv = dev->ml_priv;
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if (!priv->radio_on) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	/* Check the size of the string */
-	if (dwrq->length > IEEE80211_MAX_SSID_LEN) {
-		ret = -E2BIG;
-		goto out;
-	}
-
-	if (!dwrq->flags || !dwrq->length) {
-		ret = -EINVAL;
-		goto out;
-	} else {
-		/* Specific SSID requested */
-		memcpy(priv->mesh_ssid, extra, dwrq->length);
-		priv->mesh_ssid_len = dwrq->length;
-	}
-
-	lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
-			priv->channel);
- out:
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-	return ret;
-}
-#endif
-
-/**
- *  @brief Connect to the AP or Ad-hoc Network with specific bssid
- *
- *  @param dev          A pointer to net_device structure
- *  @param info         A pointer to iw_request_info structure
- *  @param awrq         A pointer to iw_param structure
- *  @param extra        A pointer to extra data buf
- *  @return             0 --success, otherwise fail
- */
-static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
-		 struct sockaddr *awrq, char *extra)
-{
-	struct lbs_private *priv = dev->ml_priv;
-	struct assoc_request * assoc_req;
-	int ret = 0;
-
-	lbs_deb_enter(LBS_DEB_WEXT);
-
-	if (!priv->radio_on)
-		return -EINVAL;
-
-	if (awrq->sa_family != ARPHRD_ETHER)
-		return -EINVAL;
-
-	lbs_deb_wext("ASSOC: WAP: sa_data %pM\n", awrq->sa_data);
-
-	mutex_lock(&priv->lock);
-
-	/* Get or create the current association request */
-	assoc_req = lbs_get_association_request(priv);
-	if (!assoc_req) {
-		lbs_cancel_association_work(priv);
-		ret = -ENOMEM;
-	} else {
-		/* Copy the BSSID to the association request */
-		memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
-		set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
-		lbs_postpone_association_work(priv);
-	}
-
-	mutex_unlock(&priv->lock);
-
-	return ret;
-}
-
-/*
- * iwconfig settable callbacks
- */
-static const iw_handler lbs_handler[] = {
-	(iw_handler) NULL,	/* SIOCSIWCOMMIT */
-	(iw_handler) lbs_get_name,	/* SIOCGIWNAME */
-	(iw_handler) NULL,	/* SIOCSIWNWID */
-	(iw_handler) NULL,	/* SIOCGIWNWID */
-	(iw_handler) lbs_set_freq,	/* SIOCSIWFREQ */
-	(iw_handler) lbs_get_freq,	/* SIOCGIWFREQ */
-	(iw_handler) lbs_set_mode,	/* SIOCSIWMODE */
-	(iw_handler) lbs_get_mode,	/* SIOCGIWMODE */
-	(iw_handler) NULL,	/* SIOCSIWSENS */
-	(iw_handler) NULL,	/* SIOCGIWSENS */
-	(iw_handler) NULL,	/* SIOCSIWRANGE */
-	(iw_handler) lbs_get_range,	/* SIOCGIWRANGE */
-	(iw_handler) NULL,	/* SIOCSIWPRIV */
-	(iw_handler) NULL,	/* SIOCGIWPRIV */
-	(iw_handler) NULL,	/* SIOCSIWSTATS */
-	(iw_handler) NULL,	/* SIOCGIWSTATS */
-	iw_handler_set_spy,	/* SIOCSIWSPY */
-	iw_handler_get_spy,	/* SIOCGIWSPY */
-	iw_handler_set_thrspy,	/* SIOCSIWTHRSPY */
-	iw_handler_get_thrspy,	/* SIOCGIWTHRSPY */
-	(iw_handler) lbs_set_wap,	/* SIOCSIWAP */
-	(iw_handler) lbs_get_wap,	/* SIOCGIWAP */
-	(iw_handler) NULL,	/* SIOCSIWMLME */
-	(iw_handler) NULL,	/* SIOCGIWAPLIST - deprecated */
-	(iw_handler) lbs_set_scan,	/* SIOCSIWSCAN */
-	(iw_handler) lbs_get_scan,	/* SIOCGIWSCAN */
-	(iw_handler) lbs_set_essid,	/* SIOCSIWESSID */
-	(iw_handler) lbs_get_essid,	/* SIOCGIWESSID */
-	(iw_handler) lbs_set_nick,	/* SIOCSIWNICKN */
-	(iw_handler) lbs_get_nick,	/* SIOCGIWNICKN */
-	(iw_handler) NULL,	/* -- hole -- */
-	(iw_handler) NULL,	/* -- hole -- */
-	(iw_handler) lbs_set_rate,	/* SIOCSIWRATE */
-	(iw_handler) lbs_get_rate,	/* SIOCGIWRATE */
-	(iw_handler) lbs_set_rts,	/* SIOCSIWRTS */
-	(iw_handler) lbs_get_rts,	/* SIOCGIWRTS */
-	(iw_handler) lbs_set_frag,	/* SIOCSIWFRAG */
-	(iw_handler) lbs_get_frag,	/* SIOCGIWFRAG */
-	(iw_handler) lbs_set_txpow,	/* SIOCSIWTXPOW */
-	(iw_handler) lbs_get_txpow,	/* SIOCGIWTXPOW */
-	(iw_handler) lbs_set_retry,	/* SIOCSIWRETRY */
-	(iw_handler) lbs_get_retry,	/* SIOCGIWRETRY */
-	(iw_handler) lbs_set_encode,	/* SIOCSIWENCODE */
-	(iw_handler) lbs_get_encode,	/* SIOCGIWENCODE */
-	(iw_handler) lbs_set_power,	/* SIOCSIWPOWER */
-	(iw_handler) lbs_get_power,	/* SIOCGIWPOWER */
-	(iw_handler) NULL,	/* -- hole -- */
-	(iw_handler) NULL,	/* -- hole -- */
-	(iw_handler) lbs_set_genie,	/* SIOCSIWGENIE */
-	(iw_handler) lbs_get_genie,	/* SIOCGIWGENIE */
-	(iw_handler) lbs_set_auth,	/* SIOCSIWAUTH */
-	(iw_handler) lbs_get_auth,	/* SIOCGIWAUTH */
-	(iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
-	(iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
-	(iw_handler) NULL,		/* SIOCSIWPMKSA */
-};
-struct iw_handler_def lbs_handler_def = {
-	.num_standard	= ARRAY_SIZE(lbs_handler),
-	.standard	= (iw_handler *) lbs_handler,
-	.get_wireless_stats = lbs_get_wireless_stats,
-};
-
-#ifdef CONFIG_LIBERTAS_MESH
-static const iw_handler mesh_wlan_handler[] = {
-	(iw_handler) NULL,	/* SIOCSIWCOMMIT */
-	(iw_handler) lbs_get_name,	/* SIOCGIWNAME */
-	(iw_handler) NULL,	/* SIOCSIWNWID */
-	(iw_handler) NULL,	/* SIOCGIWNWID */
-	(iw_handler) lbs_mesh_set_freq,	/* SIOCSIWFREQ */
-	(iw_handler) lbs_get_freq,	/* SIOCGIWFREQ */
-	(iw_handler) NULL,		/* SIOCSIWMODE */
-	(iw_handler) mesh_wlan_get_mode,	/* SIOCGIWMODE */
-	(iw_handler) NULL,	/* SIOCSIWSENS */
-	(iw_handler) NULL,	/* SIOCGIWSENS */
-	(iw_handler) NULL,	/* SIOCSIWRANGE */
-	(iw_handler) lbs_get_range,	/* SIOCGIWRANGE */
-	(iw_handler) NULL,	/* SIOCSIWPRIV */
-	(iw_handler) NULL,	/* SIOCGIWPRIV */
-	(iw_handler) NULL,	/* SIOCSIWSTATS */
-	(iw_handler) NULL,	/* SIOCGIWSTATS */
-	iw_handler_set_spy,	/* SIOCSIWSPY */
-	iw_handler_get_spy,	/* SIOCGIWSPY */
-	iw_handler_set_thrspy,	/* SIOCSIWTHRSPY */
-	iw_handler_get_thrspy,	/* SIOCGIWTHRSPY */
-	(iw_handler) NULL,	/* SIOCSIWAP */
-	(iw_handler) NULL,	/* SIOCGIWAP */
-	(iw_handler) NULL,	/* SIOCSIWMLME */
-	(iw_handler) NULL,	/* SIOCGIWAPLIST - deprecated */
-	(iw_handler) lbs_set_scan,	/* SIOCSIWSCAN */
-	(iw_handler) lbs_get_scan,	/* SIOCGIWSCAN */
-	(iw_handler) lbs_mesh_set_essid,/* SIOCSIWESSID */
-	(iw_handler) lbs_mesh_get_essid,/* SIOCGIWESSID */
-	(iw_handler) NULL,		/* SIOCSIWNICKN */
-	(iw_handler) mesh_get_nick,	/* SIOCGIWNICKN */
-	(iw_handler) NULL,	/* -- hole -- */
-	(iw_handler) NULL,	/* -- hole -- */
-	(iw_handler) lbs_set_rate,	/* SIOCSIWRATE */
-	(iw_handler) lbs_get_rate,	/* SIOCGIWRATE */
-	(iw_handler) lbs_set_rts,	/* SIOCSIWRTS */
-	(iw_handler) lbs_get_rts,	/* SIOCGIWRTS */
-	(iw_handler) lbs_set_frag,	/* SIOCSIWFRAG */
-	(iw_handler) lbs_get_frag,	/* SIOCGIWFRAG */
-	(iw_handler) lbs_set_txpow,	/* SIOCSIWTXPOW */
-	(iw_handler) lbs_get_txpow,	/* SIOCGIWTXPOW */
-	(iw_handler) lbs_set_retry,	/* SIOCSIWRETRY */
-	(iw_handler) lbs_get_retry,	/* SIOCGIWRETRY */
-	(iw_handler) lbs_set_encode,	/* SIOCSIWENCODE */
-	(iw_handler) lbs_get_encode,	/* SIOCGIWENCODE */
-	(iw_handler) lbs_set_power,	/* SIOCSIWPOWER */
-	(iw_handler) lbs_get_power,	/* SIOCGIWPOWER */
-	(iw_handler) NULL,	/* -- hole -- */
-	(iw_handler) NULL,	/* -- hole -- */
-	(iw_handler) lbs_set_genie,	/* SIOCSIWGENIE */
-	(iw_handler) lbs_get_genie,	/* SIOCGIWGENIE */
-	(iw_handler) lbs_set_auth,	/* SIOCSIWAUTH */
-	(iw_handler) lbs_get_auth,	/* SIOCGIWAUTH */
-	(iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
-	(iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
-	(iw_handler) NULL,		/* SIOCSIWPMKSA */
-};
-
-struct iw_handler_def mesh_handler_def = {
-	.num_standard	= ARRAY_SIZE(mesh_wlan_handler),
-	.standard	= (iw_handler *) mesh_wlan_handler,
-	.get_wireless_stats = lbs_get_wireless_stats,
-};
-#endif
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
deleted file mode 100644
index f3f19fe..0000000
--- a/drivers/net/wireless/libertas/wext.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
-  * This file contains definition for IOCTL call.
-  */
-#ifndef	_LBS_WEXT_H_
-#define	_LBS_WEXT_H_
-
-void lbs_send_disconnect_notification(struct lbs_private *priv);
-void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
-
-struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
-	struct lbs_private *priv,
-	u8 band,
-	u16 channel);
-
-extern struct iw_handler_def lbs_handler_def;
-
-#endif
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
index c445500..b172f5d 100644
--- a/drivers/net/wireless/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -538,7 +538,8 @@
 		return;
 	}
 
-	syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
+	syncfwheader = kmemdup(skb->data, sizeof(struct fwsyncheader),
+			       GFP_ATOMIC);
 	if (!syncfwheader) {
 		lbtf_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
 		kfree_skb(skb);
@@ -546,8 +547,6 @@
 		return;
 	}
 
-	memcpy(syncfwheader, skb->data, sizeof(struct fwsyncheader));
-
 	if (!syncfwheader->cmd) {
 		lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
 		lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
diff --git a/drivers/net/wireless/libertas_tf/libertas_tf.h b/drivers/net/wireless/libertas_tf/libertas_tf.h
index fbbaaae..ad77b92 100644
--- a/drivers/net/wireless/libertas_tf/libertas_tf.h
+++ b/drivers/net/wireless/libertas_tf/libertas_tf.h
@@ -253,6 +253,9 @@
 	u8 fw_ready;
 	u8 surpriseremoved;
 	struct sk_buff_head bc_ps_buf;
+
+	/* Most recently reported noise in dBm */
+	s8 noise;
 };
 
 /* 802.11-related definitions */
@@ -316,7 +319,7 @@
 	__le16 size;
 	__le16 seqnum;
 	__le16 result;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ctrl_node {
 	struct list_head list;
@@ -369,7 +372,7 @@
 
 	/*FW/HW capability */
 	__le32 fwcapinfo;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_ds_mac_control {
 	struct cmd_header hdr;
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 817fffc..9278b3c 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -525,6 +525,22 @@
 	lbtf_deb_leave(LBTF_DEB_MACOPS);
 }
 
+static int lbtf_op_get_survey(struct ieee80211_hw *hw, int idx,
+				struct survey_info *survey)
+{
+	struct lbtf_private *priv = hw->priv;
+	struct ieee80211_conf *conf = &hw->conf;
+
+	if (idx != 0)
+		return -ENOENT;
+
+	survey->channel = conf->channel;
+	survey->filled = SURVEY_INFO_NOISE_DBM;
+	survey->noise = priv->noise;
+
+	return 0;
+}
+
 static const struct ieee80211_ops lbtf_ops = {
 	.tx			= lbtf_op_tx,
 	.start			= lbtf_op_start,
@@ -535,6 +551,7 @@
 	.prepare_multicast	= lbtf_op_prepare_multicast,
 	.configure_filter	= lbtf_op_configure_filter,
 	.bss_info_changed	= lbtf_op_bss_info_changed,
+	.get_survey		= lbtf_op_get_survey,
 };
 
 int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
@@ -555,6 +572,7 @@
 	stats.freq = priv->cur_freq;
 	stats.band = IEEE80211_BAND_2GHZ;
 	stats.signal = prxpd->snr;
+	priv->noise = prxpd->nf;
 	/* Marvell rate index has a hole at value 4 */
 	if (prxpd->rx_rate > 4)
 		--prxpd->rx_rate;
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 6f8cb3e..01ad7f7 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -317,7 +317,7 @@
 	u8 rt_rate;
 	__le16 rt_channel;
 	__le16 rt_chbitmask;
-} __attribute__ ((packed));
+} __packed;
 
 
 static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb,
@@ -486,8 +486,7 @@
 	struct ieee80211_rx_status rx_status;
 
 	if (data->idle) {
-		printk(KERN_DEBUG "%s: Trying to TX when idle - reject\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_debug(hw->wiphy, "trying to tx when idle - reject\n");
 		return false;
 	}
 
@@ -576,7 +575,7 @@
 static int mac80211_hwsim_start(struct ieee80211_hw *hw)
 {
 	struct mac80211_hwsim_data *data = hw->priv;
-	printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
+	wiphy_debug(hw->wiphy, "%s\n", __func__);
 	data->started = 1;
 	return 0;
 }
@@ -587,16 +586,15 @@
 	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__);
+	wiphy_debug(hw->wiphy, "%s\n", __func__);
 }
 
 
 static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
 					struct ieee80211_vif *vif)
 {
-	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
-	       wiphy_name(hw->wiphy), __func__, vif->type,
-	       vif->addr);
+	wiphy_debug(hw->wiphy, "%s (type=%d mac_addr=%pM)\n",
+		    __func__, vif->type, vif->addr);
 	hwsim_set_magic(vif);
 	return 0;
 }
@@ -605,9 +603,8 @@
 static void mac80211_hwsim_remove_interface(
 	struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
-	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
-	       wiphy_name(hw->wiphy), __func__, vif->type,
-	       vif->addr);
+	wiphy_debug(hw->wiphy, "%s (type=%d mac_addr=%pM)\n",
+		    __func__, vif->type, vif->addr);
 	hwsim_check_magic(vif);
 	hwsim_clear_magic(vif);
 }
@@ -670,13 +667,14 @@
 		[IEEE80211_SMPS_DYNAMIC] = "dynamic",
 	};
 
-	printk(KERN_DEBUG "%s:%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
-	       wiphy_name(hw->wiphy), __func__,
-	       conf->channel->center_freq,
-	       hwsim_chantypes[conf->channel_type],
-	       !!(conf->flags & IEEE80211_CONF_IDLE),
-	       !!(conf->flags & IEEE80211_CONF_PS),
-	       smps_modes[conf->smps_mode]);
+	wiphy_debug(hw->wiphy,
+		    "%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
+		    __func__,
+		    conf->channel->center_freq,
+		    hwsim_chantypes[conf->channel_type],
+		    !!(conf->flags & IEEE80211_CONF_IDLE),
+		    !!(conf->flags & IEEE80211_CONF_PS),
+		    smps_modes[conf->smps_mode]);
 
 	data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
 
@@ -696,7 +694,7 @@
 {
 	struct mac80211_hwsim_data *data = hw->priv;
 
-	printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
+	wiphy_debug(hw->wiphy, "%s\n", __func__);
 
 	data->rx_filter = 0;
 	if (*total_flags & FIF_PROMISC_IN_BSS)
@@ -717,26 +715,23 @@
 
 	hwsim_check_magic(vif);
 
-	printk(KERN_DEBUG "%s:%s(changed=0x%x)\n",
-	       wiphy_name(hw->wiphy), __func__, changed);
+	wiphy_debug(hw->wiphy, "%s(changed=0x%x)\n", __func__, changed);
 
 	if (changed & BSS_CHANGED_BSSID) {
-		printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n",
-		       wiphy_name(hw->wiphy), __func__,
-		       info->bssid);
+		wiphy_debug(hw->wiphy, "%s: BSSID changed: %pM\n",
+			    __func__, info->bssid);
 		memcpy(vp->bssid, info->bssid, ETH_ALEN);
 	}
 
 	if (changed & BSS_CHANGED_ASSOC) {
-		printk(KERN_DEBUG "  %s: ASSOC: assoc=%d aid=%d\n",
-		       wiphy_name(hw->wiphy), info->assoc, info->aid);
+		wiphy_debug(hw->wiphy, "  ASSOC: assoc=%d aid=%d\n",
+			    info->assoc, info->aid);
 		vp->assoc = info->assoc;
 		vp->aid = info->aid;
 	}
 
 	if (changed & BSS_CHANGED_BEACON_INT) {
-		printk(KERN_DEBUG "  %s: BCNINT: %d\n",
-		       wiphy_name(hw->wiphy), info->beacon_int);
+		wiphy_debug(hw->wiphy, "  BCNINT: %d\n", info->beacon_int);
 		data->beacon_int = 1024 * info->beacon_int / 1000 * HZ / 1000;
 		if (WARN_ON(!data->beacon_int))
 			data->beacon_int = 1;
@@ -746,31 +741,28 @@
 	}
 
 	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
-		printk(KERN_DEBUG "  %s: ERP_CTS_PROT: %d\n",
-		       wiphy_name(hw->wiphy), info->use_cts_prot);
+		wiphy_debug(hw->wiphy, "  ERP_CTS_PROT: %d\n",
+			    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);
+		wiphy_debug(hw->wiphy, "  ERP_PREAMBLE: %d\n",
+			    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);
+		wiphy_debug(hw->wiphy, "  ERP_SLOT: %d\n", info->use_short_slot);
 	}
 
 	if (changed & BSS_CHANGED_HT) {
-		printk(KERN_DEBUG "  %s: HT: op_mode=0x%x, chantype=%s\n",
-		       wiphy_name(hw->wiphy),
-		       info->ht_operation_mode,
-		       hwsim_chantypes[info->channel_type]);
+		wiphy_debug(hw->wiphy, "  HT: op_mode=0x%x, chantype=%s\n",
+			    info->ht_operation_mode,
+			    hwsim_chantypes[info->channel_type]);
 	}
 
 	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);
+		wiphy_debug(hw->wiphy, "  BASIC_RATES: 0x%llx\n",
+			    (unsigned long long) info->basic_rates);
 	}
 }
 
@@ -824,10 +816,11 @@
 	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);
+	wiphy_debug(hw->wiphy,
+		    "%s (queue=%d txop=%d cw_min=%d cw_max=%d aifs=%d)\n",
+		    __func__, queue,
+		    params->txop, params->cw_min,
+		    params->cw_max, params->aifs);
 	return 0;
 }
 
@@ -837,8 +830,7 @@
 {
 	struct ieee80211_conf *conf = &hw->conf;
 
-	printk(KERN_DEBUG "%s:%s (idx=%d)\n",
-	       wiphy_name(hw->wiphy), __func__, idx);
+	wiphy_debug(hw->wiphy, "%s (idx=%d)\n", __func__, idx);
 
 	if (idx != 0)
 		return -ENOENT;
@@ -1108,8 +1100,9 @@
 	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);
+	wiphy_debug(data->hw->wiphy,
+		    "%s: send PS-Poll to %pM for aid %d\n",
+		    __func__, vp->bssid, vp->aid);
 
 	skb = dev_alloc_skb(sizeof(*pspoll));
 	if (!skb)
@@ -1137,8 +1130,9 @@
 	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);
+	wiphy_debug(data->hw->wiphy,
+		    "%s: send data::nullfunc to %pM ps=%d\n",
+		    __func__, vp->bssid, ps);
 
 	skb = dev_alloc_skb(sizeof(*hdr));
 	if (!skb)
@@ -1291,6 +1285,11 @@
 		hw->wiphy->n_addresses = 2;
 		hw->wiphy->addresses = data->addresses;
 
+		if (fake_hw_scan) {
+			hw->wiphy->max_scan_ssids = 255;
+			hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+		}
+
 		hw->channel_change_time = 1;
 		hw->queues = 4;
 		hw->wiphy->interface_modes =
@@ -1468,9 +1467,8 @@
 			break;
 		}
 
-		printk(KERN_DEBUG "%s: hwaddr %pM registered\n",
-		       wiphy_name(hw->wiphy),
-		       hw->wiphy->perm_addr);
+		wiphy_debug(hw->wiphy, "hwaddr %pm registered\n",
+			    hw->wiphy->perm_addr);
 
 		data->debugfs = debugfs_create_dir("hwsim",
 						   hw->wiphy->debugfsdir);
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 808adb9..d761ed2 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -86,7 +86,7 @@
 	void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr);
 	void (*rxd_refill)(void *rxd, dma_addr_t addr, int len);
 	int (*rxd_process)(void *rxd, struct ieee80211_rx_status *status,
-			   __le16 *qos);
+			   __le16 *qos, s8 *noise);
 };
 
 struct mwl8k_device_info {
@@ -109,7 +109,7 @@
 	dma_addr_t rxd_dma;
 	struct {
 		struct sk_buff *skb;
-		DECLARE_PCI_UNMAP_ADDR(dma)
+		DEFINE_DMA_UNMAP_ADDR(dma);
 	} *buf;
 };
 
@@ -207,6 +207,9 @@
 
 	/* Tasklet to perform RX.  */
 	struct tasklet_struct poll_rx_task;
+
+	/* Most recently reported noise in dBm */
+	s8 noise;
 };
 
 /* Per interface specific private data */
@@ -314,13 +317,15 @@
 #define MWL8K_CMD_SET_NEW_STN		0x1111		/* per-vif */
 #define MWL8K_CMD_UPDATE_STADB		0x1123
 
-static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
+static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
 {
+	u16 command = le16_to_cpu(cmd);
+
 #define MWL8K_CMDNAME(x)	case MWL8K_CMD_##x: do {\
 					snprintf(buf, bufsize, "%s", #x);\
 					return buf;\
 					} while (0)
-	switch (cmd & ~0x8000) {
+	switch (command & ~0x8000) {
 		MWL8K_CMDNAME(CODE_DNLD);
 		MWL8K_CMDNAME(GET_HW_SPEC);
 		MWL8K_CMDNAME(SET_HW_SPEC);
@@ -426,7 +431,7 @@
 	__u8	macid;
 	__le16	result;
 	char	payload[0];
-} __attribute__((packed));
+} __packed;
 
 /*
  * Firmware loading.
@@ -632,7 +637,7 @@
 	__le16 fwlen;
 	struct ieee80211_hdr wh;
 	char data[0];
-} __attribute__((packed));
+} __packed;
 
 /* Routines to add/remove DMA header from skb.  */
 static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos)
@@ -711,7 +716,7 @@
 	__u8 rx_status;
 	__u8 channel;
 	__u8 rx_ctrl;
-} __attribute__((packed));
+} __packed;
 
 #define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT	0x80
 #define MWL8K_8366_AP_RATE_INFO_40MHZ		0x40
@@ -739,7 +744,7 @@
 
 static int
 mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
-			  __le16 *qos)
+			  __le16 *qos, s8 *noise)
 {
 	struct mwl8k_rxd_8366_ap *rxd = _rxd;
 
@@ -750,6 +755,7 @@
 	memset(status, 0, sizeof(*status));
 
 	status->signal = -rxd->rssi;
+	*noise = -rxd->noise_floor;
 
 	if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) {
 		status->flag |= RX_FLAG_HT;
@@ -806,7 +812,7 @@
 	__u8 rx_ctrl;
 	__u8 rx_status;
 	__u8 pad2[2];
-} __attribute__((packed));
+} __packed;
 
 #define MWL8K_STA_RATE_INFO_SHORTPRE		0x8000
 #define MWL8K_STA_RATE_INFO_ANTSELECT(x)	(((x) >> 11) & 0x3)
@@ -837,7 +843,7 @@
 
 static int
 mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status,
-		       __le16 *qos)
+		       __le16 *qos, s8 *noise)
 {
 	struct mwl8k_rxd_sta *rxd = _rxd;
 	u16 rate_info;
@@ -851,6 +857,7 @@
 	memset(status, 0, sizeof(*status));
 
 	status->signal = -rxd->rssi;
+	*noise = -rxd->noise_level;
 	status->antenna = MWL8K_STA_RATE_INFO_ANTSELECT(rate_info);
 	status->rate_idx = MWL8K_STA_RATE_INFO_RATEID(rate_info);
 
@@ -903,16 +910,14 @@
 
 	rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma);
 	if (rxq->rxd == NULL) {
-		printk(KERN_ERR "%s: failed to alloc RX descriptors\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_err(hw->wiphy, "failed to alloc rx descriptors\n");
 		return -ENOMEM;
 	}
 	memset(rxq->rxd, 0, size);
 
 	rxq->buf = kmalloc(MWL8K_RX_DESCS * sizeof(*rxq->buf), GFP_KERNEL);
 	if (rxq->buf == NULL) {
-		printk(KERN_ERR "%s: failed to alloc RX skbuff list\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_err(hw->wiphy, "failed to alloc rx skbuff list\n");
 		pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma);
 		return -ENOMEM;
 	}
@@ -963,7 +968,7 @@
 		if (rxq->tail == MWL8K_RX_DESCS)
 			rxq->tail = 0;
 		rxq->buf[rx].skb = skb;
-		pci_unmap_addr_set(&rxq->buf[rx], dma, addr);
+		dma_unmap_addr_set(&rxq->buf[rx], dma, addr);
 
 		rxd = rxq->rxd + (rx * priv->rxd_ops->rxd_size);
 		priv->rxd_ops->rxd_refill(rxd, addr, MWL8K_RX_MAXSZ);
@@ -984,9 +989,9 @@
 	for (i = 0; i < MWL8K_RX_DESCS; i++) {
 		if (rxq->buf[i].skb != NULL) {
 			pci_unmap_single(priv->pdev,
-					 pci_unmap_addr(&rxq->buf[i], dma),
+					 dma_unmap_addr(&rxq->buf[i], dma),
 					 MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
-			pci_unmap_addr_set(&rxq->buf[i], dma, 0);
+			dma_unmap_addr_set(&rxq->buf[i], dma, 0);
 
 			kfree_skb(rxq->buf[i].skb);
 			rxq->buf[i].skb = NULL;
@@ -1053,16 +1058,17 @@
 
 		rxd = rxq->rxd + (rxq->head * priv->rxd_ops->rxd_size);
 
-		pkt_len = priv->rxd_ops->rxd_process(rxd, &status, &qos);
+		pkt_len = priv->rxd_ops->rxd_process(rxd, &status, &qos,
+							&priv->noise);
 		if (pkt_len < 0)
 			break;
 
 		rxq->buf[rxq->head].skb = NULL;
 
 		pci_unmap_single(priv->pdev,
-				 pci_unmap_addr(&rxq->buf[rxq->head], dma),
+				 dma_unmap_addr(&rxq->buf[rxq->head], dma),
 				 MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
-		pci_unmap_addr_set(&rxq->buf[rxq->head], dma, 0);
+		dma_unmap_addr_set(&rxq->buf[rxq->head], dma, 0);
 
 		rxq->head++;
 		if (rxq->head == MWL8K_RX_DESCS)
@@ -1120,7 +1126,7 @@
 	__le16 rate_info;
 	__u8 peer_id;
 	__u8 tx_frag_cnt;
-} __attribute__((packed));
+} __packed;
 
 #define MWL8K_TX_DESCS		128
 
@@ -1139,16 +1145,14 @@
 
 	txq->txd = pci_alloc_consistent(priv->pdev, size, &txq->txd_dma);
 	if (txq->txd == NULL) {
-		printk(KERN_ERR "%s: failed to alloc TX descriptors\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_err(hw->wiphy, "failed to alloc tx descriptors\n");
 		return -ENOMEM;
 	}
 	memset(txq->txd, 0, size);
 
 	txq->skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->skb), GFP_KERNEL);
 	if (txq->skb == NULL) {
-		printk(KERN_ERR "%s: failed to alloc TX skbuff list\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_err(hw->wiphy, "failed to alloc tx skbuff list\n");
 		pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma);
 		return -ENOMEM;
 	}
@@ -1204,11 +1208,12 @@
 				unused++;
 		}
 
-		printk(KERN_ERR "%s: txq[%d] len=%d head=%d tail=%d "
-		       "fw_owned=%d drv_owned=%d unused=%d\n",
-		       wiphy_name(hw->wiphy), i,
-		       txq->len, txq->head, txq->tail,
-		       fw_owned, drv_owned, unused);
+		wiphy_err(hw->wiphy,
+			  "txq[%d] len=%d head=%d tail=%d "
+			  "fw_owned=%d drv_owned=%d unused=%d\n",
+			  i,
+			  txq->len, txq->head, txq->tail,
+			  fw_owned, drv_owned, unused);
 	}
 }
 
@@ -1252,25 +1257,23 @@
 		if (timeout) {
 			WARN_ON(priv->pending_tx_pkts);
 			if (retry) {
-				printk(KERN_NOTICE "%s: tx rings drained\n",
-				       wiphy_name(hw->wiphy));
+				wiphy_notice(hw->wiphy, "tx rings drained\n");
 			}
 			break;
 		}
 
 		if (priv->pending_tx_pkts < oldcount) {
-			printk(KERN_NOTICE "%s: waiting for tx rings "
-			       "to drain (%d -> %d pkts)\n",
-			       wiphy_name(hw->wiphy), oldcount,
-			       priv->pending_tx_pkts);
+			wiphy_notice(hw->wiphy,
+				     "waiting for tx rings to drain (%d -> %d pkts)\n",
+				     oldcount, priv->pending_tx_pkts);
 			retry = 1;
 			continue;
 		}
 
 		priv->tx_wait = NULL;
 
-		printk(KERN_ERR "%s: tx rings stuck for %d ms\n",
-		       wiphy_name(hw->wiphy), MWL8K_TX_WAIT_TIMEOUT_MS);
+		wiphy_err(hw->wiphy, "tx rings stuck for %d ms\n",
+			  MWL8K_TX_WAIT_TIMEOUT_MS);
 		mwl8k_dump_tx_rings(hw);
 
 		rc = -ETIMEDOUT;
@@ -1421,8 +1424,8 @@
 				skb->len, PCI_DMA_TODEVICE);
 
 	if (pci_dma_mapping_error(priv->pdev, dma)) {
-		printk(KERN_DEBUG "%s: failed to dma map skb, "
-		       "dropping TX frame.\n", wiphy_name(hw->wiphy));
+		wiphy_debug(hw->wiphy,
+			    "failed to dma map skb, dropping TX frame.\n");
 		dev_kfree_skb(skb);
 		return NETDEV_TX_OK;
 	}
@@ -1538,7 +1541,7 @@
 	unsigned long timeout = 0;
 	u8 buf[32];
 
-	cmd->result = 0xffff;
+	cmd->result = (__force __le16) 0xffff;
 	dma_size = le16_to_cpu(cmd->length);
 	dma_addr = pci_map_single(priv->pdev, cmd, dma_size,
 				  PCI_DMA_BIDIRECTIONAL);
@@ -1570,10 +1573,9 @@
 					PCI_DMA_BIDIRECTIONAL);
 
 	if (!timeout) {
-		printk(KERN_ERR "%s: Command %s timeout after %u ms\n",
-		       wiphy_name(hw->wiphy),
-		       mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
-		       MWL8K_CMD_TIMEOUT_MS);
+		wiphy_err(hw->wiphy, "command %s timeout after %u ms\n",
+			  mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
+			  MWL8K_CMD_TIMEOUT_MS);
 		rc = -ETIMEDOUT;
 	} else {
 		int ms;
@@ -1582,15 +1584,14 @@
 
 		rc = cmd->result ? -EINVAL : 0;
 		if (rc)
-			printk(KERN_ERR "%s: Command %s error 0x%x\n",
-			       wiphy_name(hw->wiphy),
-			       mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
-			       le16_to_cpu(cmd->result));
+			wiphy_err(hw->wiphy, "command %s error 0x%x\n",
+				  mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
+				  le16_to_cpu(cmd->result));
 		else if (ms > 2000)
-			printk(KERN_NOTICE "%s: Command %s took %d ms\n",
-			       wiphy_name(hw->wiphy),
-			       mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
-			       ms);
+			wiphy_notice(hw->wiphy, "command %s took %d ms\n",
+				     mwl8k_cmd_name(cmd->code,
+						    buf, sizeof(buf)),
+				     ms);
 	}
 
 	return rc;
@@ -1666,7 +1667,7 @@
 	__le32 caps2;
 	__le32 num_tx_desc_per_queue;
 	__le32 total_rxd;
-} __attribute__((packed));
+} __packed;
 
 #define MWL8K_CAP_MAX_AMSDU		0x20000000
 #define MWL8K_CAP_GREENFIELD		0x08000000
@@ -1810,7 +1811,7 @@
 	__le32 wcbbase1;
 	__le32 wcbbase2;
 	__le32 wcbbase3;
-} __attribute__((packed));
+} __packed;
 
 static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
 {
@@ -1842,22 +1843,22 @@
 		priv->sta_macids_supported = 0x00000000;
 
 		off = le32_to_cpu(cmd->wcbbase0) & 0xffff;
-		iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off);
+		iowrite32(priv->txq[0].txd_dma, priv->sram + off);
 
 		off = le32_to_cpu(cmd->rxwrptr) & 0xffff;
-		iowrite32(cpu_to_le32(priv->rxq[0].rxd_dma), priv->sram + off);
+		iowrite32(priv->rxq[0].rxd_dma, priv->sram + off);
 
 		off = le32_to_cpu(cmd->rxrdptr) & 0xffff;
-		iowrite32(cpu_to_le32(priv->rxq[0].rxd_dma), priv->sram + off);
+		iowrite32(priv->rxq[0].rxd_dma, priv->sram + off);
 
 		off = le32_to_cpu(cmd->wcbbase1) & 0xffff;
-		iowrite32(cpu_to_le32(priv->txq[1].txd_dma), priv->sram + off);
+		iowrite32(priv->txq[1].txd_dma, priv->sram + off);
 
 		off = le32_to_cpu(cmd->wcbbase2) & 0xffff;
-		iowrite32(cpu_to_le32(priv->txq[2].txd_dma), priv->sram + off);
+		iowrite32(priv->txq[2].txd_dma, priv->sram + off);
 
 		off = le32_to_cpu(cmd->wcbbase3) & 0xffff;
-		iowrite32(cpu_to_le32(priv->txq[3].txd_dma), priv->sram + off);
+		iowrite32(priv->txq[3].txd_dma, priv->sram + off);
 	}
 
 	kfree(cmd);
@@ -1883,7 +1884,7 @@
 	__le32 flags;
 	__le32 num_tx_desc_per_queue;
 	__le32 total_rxd;
-} __attribute__((packed));
+} __packed;
 
 #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT		0x00000080
 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP	0x00000020
@@ -1985,7 +1986,7 @@
 struct mwl8k_cmd_get_stat {
 	struct mwl8k_cmd_pkt header;
 	__le32 stats[64];
-} __attribute__((packed));
+} __packed;
 
 #define MWL8K_STAT_ACK_FAILURE	9
 #define MWL8K_STAT_RTS_FAILURE	12
@@ -2029,7 +2030,7 @@
 	__le16 action;
 	__le16 control;
 	__le16 radio_on;
-} __attribute__((packed));
+} __packed;
 
 static int
 mwl8k_cmd_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
@@ -2092,7 +2093,7 @@
 	__le16 current_level;
 	__le16 reserved;
 	__le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
-} __attribute__((packed));
+} __packed;
 
 static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm)
 {
@@ -2121,7 +2122,7 @@
 	struct mwl8k_cmd_pkt header;
 	__le16 antenna;
 	__le16 mode;
-} __attribute__((packed));
+} __packed;
 
 #define MWL8K_RF_ANTENNA_RX		1
 #define MWL8K_RF_ANTENNA_TX		2
@@ -2182,7 +2183,7 @@
  */
 struct mwl8k_cmd_set_pre_scan {
 	struct mwl8k_cmd_pkt header;
-} __attribute__((packed));
+} __packed;
 
 static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw)
 {
@@ -2209,7 +2210,7 @@
 	struct mwl8k_cmd_pkt header;
 	__le32 isibss;
 	__u8 bssid[ETH_ALEN];
-} __attribute__((packed));
+} __packed;
 
 static int
 mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac)
@@ -2240,7 +2241,7 @@
 	__le16 action;
 	__u8 current_channel;
 	__le32 channel_flags;
-} __attribute__((packed));
+} __packed;
 
 static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
 				    struct ieee80211_conf *conf)
@@ -2293,7 +2294,7 @@
 	__u8	bssid[ETH_ALEN];
 	__le16	protection_mode;
 	__u8	supp_rates[14];
-} __attribute__((packed));
+} __packed;
 
 static void legacy_rate_mask_to_array(u8 *rates, u32 mask)
 {
@@ -2364,7 +2365,7 @@
 	/* Bitmap for supported MCS codes.  */
 	__u8	mcs_set[16];
 	__u8	reserved[16];
-} __attribute__((packed));
+} __packed;
 
 static int
 mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -2397,7 +2398,7 @@
 	struct mwl8k_cmd_pkt header;
 	__le32 sleep_interval;	/* Number of beacon periods to sleep */
 	__u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN];
-} __attribute__((packed));
+} __packed;
 
 static int mwl8k_cmd_finalize_join(struct ieee80211_hw *hw, void *frame,
 				   int framelen, int dtim)
@@ -2436,7 +2437,7 @@
 	struct mwl8k_cmd_pkt header;
 	__le16 action;
 	__le16 threshold;
-} __attribute__((packed));
+} __packed;
 
 static int
 mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh)
@@ -2466,7 +2467,7 @@
 	struct mwl8k_cmd_pkt header;
 	__le16 action;
 	__u8 short_slot;
-} __attribute__((packed));
+} __packed;
 
 static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
 {
@@ -2528,7 +2529,7 @@
 			__u8 txq;
 		} sta;
 	};
-} __attribute__((packed));
+} __packed;
 
 #define MWL8K_SET_EDCA_CW	0x01
 #define MWL8K_SET_EDCA_TXOP	0x02
@@ -2579,7 +2580,7 @@
 struct mwl8k_cmd_set_wmm_mode {
 	struct mwl8k_cmd_pkt header;
 	__le16 action;
-} __attribute__((packed));
+} __packed;
 
 static int mwl8k_cmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable)
 {
@@ -2612,7 +2613,7 @@
 	__le32 action;
 	__u8 rx_antenna_map;
 	__u8 tx_antenna_map;
-} __attribute__((packed));
+} __packed;
 
 static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx)
 {
@@ -2652,7 +2653,7 @@
 	__le32 rate_type;
 	__le32 reserved1;
 	__le32 reserved2;
-} __attribute__((packed));
+} __packed;
 
 #define MWL8K_USE_AUTO_RATE	0x0002
 #define MWL8K_UCAST_RATE	0
@@ -2694,7 +2695,7 @@
 	u8 multicast_rate;
 	u8 multicast_rate_type;
 	u8 management_rate;
-} __attribute__((packed));
+} __packed;
 
 static int
 mwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt)
@@ -2724,7 +2725,7 @@
 struct mwl8k_cmd_enable_sniffer {
 	struct mwl8k_cmd_pkt header;
 	__le32 action;
-} __attribute__((packed));
+} __packed;
 
 static int mwl8k_cmd_enable_sniffer(struct ieee80211_hw *hw, bool enable)
 {
@@ -2757,7 +2758,7 @@
 		} mbss;
 		__u8 mac_addr[ETH_ALEN];
 	};
-} __attribute__((packed));
+} __packed;
 
 #define MWL8K_MAC_TYPE_PRIMARY_CLIENT		0
 #define MWL8K_MAC_TYPE_SECONDARY_CLIENT		1
@@ -2812,7 +2813,7 @@
 	struct mwl8k_cmd_pkt header;
 	__le16 action;
 	__le16 mode;
-} __attribute__((packed));
+} __packed;
 
 static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode)
 {
@@ -2840,7 +2841,7 @@
 struct mwl8k_cmd_bss_start {
 	struct mwl8k_cmd_pkt header;
 	__le32 enable;
-} __attribute__((packed));
+} __packed;
 
 static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw,
 			       struct ieee80211_vif *vif, int enable)
@@ -2885,7 +2886,7 @@
 	__u8 add_qos_info;
 	__u8 is_qos_sta;
 	__le32 fw_sta_ptr;
-} __attribute__((packed));
+} __packed;
 
 #define MWL8K_STA_ACTION_ADD		0
 #define MWL8K_STA_ACTION_REMOVE		2
@@ -2978,7 +2979,7 @@
 	__le16	control1;
 	__le16	control2;
 	__le16	control3;
-} __attribute__((packed));
+} __packed;
 
 struct peer_capability_info {
 	/* Peer type - AP vs. STA.  */
@@ -3007,7 +3008,7 @@
 	__u8	pad2;
 	__u8	station_id;
 	__le16	amsdu_enabled;
-} __attribute__((packed));
+} __packed;
 
 struct mwl8k_cmd_update_stadb {
 	struct mwl8k_cmd_pkt header;
@@ -3022,7 +3023,7 @@
 
 	/* Peer info - valid during add/update.  */
 	struct peer_capability_info	peer_info;
-} __attribute__((packed));
+} __packed;
 
 #define MWL8K_STA_DB_MODIFY_ENTRY	1
 #define MWL8K_STA_DB_DEL_ENTRY		2
@@ -3052,7 +3053,7 @@
 	p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT;
 	p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability);
 	p->ht_support = sta->ht_cap.ht_supported;
-	p->ht_caps = sta->ht_cap.cap;
+	p->ht_caps = cpu_to_le16(sta->ht_cap.cap);
 	p->extended_ht_caps = (sta->ht_cap.ampdu_factor & 3) |
 		((sta->ht_cap.ampdu_density & 7) << 2);
 	if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
@@ -3190,8 +3191,8 @@
 	int rc;
 
 	if (!priv->radio_on) {
-		printk(KERN_DEBUG "%s: dropped TX frame since radio "
-		       "disabled\n", wiphy_name(hw->wiphy));
+		wiphy_debug(hw->wiphy,
+			    "dropped TX frame since radio disabled\n");
 		dev_kfree_skb(skb);
 		return NETDEV_TX_OK;
 	}
@@ -3209,8 +3210,7 @@
 	rc = request_irq(priv->pdev->irq, mwl8k_interrupt,
 			 IRQF_SHARED, MWL8K_NAME, hw);
 	if (rc) {
-		printk(KERN_ERR "%s: failed to register IRQ handler\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_err(hw->wiphy, "failed to register irq handler\n");
 		return -EIO;
 	}
 
@@ -3297,9 +3297,8 @@
 	 * mode.  (Sniffer mode is only used on STA firmware.)
 	 */
 	if (priv->sniffer_enabled) {
-		printk(KERN_INFO "%s: unable to create STA "
-		       "interface due to sniffer mode being enabled\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_info(hw->wiphy,
+			   "unable to create STA interface because sniffer mode is enabled\n");
 		return -EINVAL;
 	}
 
@@ -3581,9 +3580,8 @@
 	 */
 	if (!list_empty(&priv->vif_list)) {
 		if (net_ratelimit())
-			printk(KERN_INFO "%s: not enabling sniffer "
-			       "mode because STA interface is active\n",
-			       wiphy_name(hw->wiphy));
+			wiphy_info(hw->wiphy,
+				   "not enabling sniffer mode because STA interface is active\n");
 		return 0;
 	}
 
@@ -3763,6 +3761,22 @@
 	return mwl8k_cmd_get_stat(hw, stats);
 }
 
+static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx,
+				struct survey_info *survey)
+{
+	struct mwl8k_priv *priv = hw->priv;
+	struct ieee80211_conf *conf = &hw->conf;
+
+	if (idx != 0)
+		return -ENOENT;
+
+	survey->channel = conf->channel;
+	survey->filled = SURVEY_INFO_NOISE_DBM;
+	survey->noise = priv->noise;
+
+	return 0;
+}
+
 static int
 mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		   enum ieee80211_ampdu_mlme_action action,
@@ -3794,6 +3808,7 @@
 	.sta_remove		= mwl8k_sta_remove,
 	.conf_tx		= mwl8k_conf_tx,
 	.get_stats		= mwl8k_get_stats,
+	.get_survey		= mwl8k_get_survey,
 	.ampdu_action		= mwl8k_ampdu_action,
 };
 
@@ -3911,8 +3926,7 @@
 
 	priv->sram = pci_iomap(pdev, 0, 0x10000);
 	if (priv->sram == NULL) {
-		printk(KERN_ERR "%s: Cannot map device SRAM\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_err(hw->wiphy, "cannot map device sram\n");
 		goto err_iounmap;
 	}
 
@@ -3924,8 +3938,7 @@
 	if (priv->regs == NULL) {
 		priv->regs = pci_iomap(pdev, 2, 0x10000);
 		if (priv->regs == NULL) {
-			printk(KERN_ERR "%s: Cannot map device registers\n",
-			       wiphy_name(hw->wiphy));
+			wiphy_err(hw->wiphy, "cannot map device registers\n");
 			goto err_iounmap;
 		}
 	}
@@ -3937,16 +3950,14 @@
 	/* Ask userland hotplug daemon for the device firmware */
 	rc = mwl8k_request_firmware(priv);
 	if (rc) {
-		printk(KERN_ERR "%s: Firmware files not found\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_err(hw->wiphy, "firmware files not found\n");
 		goto err_stop_firmware;
 	}
 
 	/* Load firmware into hardware */
 	rc = mwl8k_load_firmware(hw);
 	if (rc) {
-		printk(KERN_ERR "%s: Cannot start firmware\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_err(hw->wiphy, "cannot start firmware\n");
 		goto err_stop_firmware;
 	}
 
@@ -3957,9 +3968,8 @@
 	if (priv->ap_fw) {
 		priv->rxd_ops = priv->device_info->ap_rxd_ops;
 		if (priv->rxd_ops == NULL) {
-			printk(KERN_ERR "%s: Driver does not have AP "
-			       "firmware image support for this hardware\n",
-			       wiphy_name(hw->wiphy));
+			wiphy_err(hw->wiphy,
+				  "Driver does not have AP firmware image support for this hardware\n");
 			goto err_stop_firmware;
 		}
 	} else {
@@ -4037,8 +4047,7 @@
 	rc = request_irq(priv->pdev->irq, mwl8k_interrupt,
 			 IRQF_SHARED, MWL8K_NAME, hw);
 	if (rc) {
-		printk(KERN_ERR "%s: failed to register IRQ handler\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_err(hw->wiphy, "failed to register irq handler\n");
 		goto err_free_queues;
 	}
 
@@ -4058,8 +4067,7 @@
 		rc = mwl8k_cmd_get_hw_spec_sta(hw);
 	}
 	if (rc) {
-		printk(KERN_ERR "%s: Cannot initialise firmware\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_err(hw->wiphy, "cannot initialise firmware\n");
 		goto err_free_irq;
 	}
 
@@ -4073,15 +4081,14 @@
 	/* Turn radio off */
 	rc = mwl8k_cmd_radio_disable(hw);
 	if (rc) {
-		printk(KERN_ERR "%s: Cannot disable\n", wiphy_name(hw->wiphy));
+		wiphy_err(hw->wiphy, "cannot disable\n");
 		goto err_free_irq;
 	}
 
 	/* Clear MAC address */
 	rc = mwl8k_cmd_set_mac_addr(hw, NULL, "\x00\x00\x00\x00\x00\x00");
 	if (rc) {
-		printk(KERN_ERR "%s: Cannot clear MAC address\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_err(hw->wiphy, "cannot clear mac address\n");
 		goto err_free_irq;
 	}
 
@@ -4091,17 +4098,16 @@
 
 	rc = ieee80211_register_hw(hw);
 	if (rc) {
-		printk(KERN_ERR "%s: Cannot register device\n",
-		       wiphy_name(hw->wiphy));
+		wiphy_err(hw->wiphy, "cannot register device\n");
 		goto err_free_queues;
 	}
 
-	printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n",
-	       wiphy_name(hw->wiphy), priv->device_info->part_name,
-	       priv->hw_rev, hw->wiphy->perm_addr,
-	       priv->ap_fw ? "AP" : "STA",
-	       (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff,
-	       (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff);
+	wiphy_info(hw->wiphy, "%s v%d, %pm, %s firmware %u.%u.%u.%u\n",
+		   priv->device_info->part_name,
+		   priv->hw_rev, hw->wiphy->perm_addr,
+		   priv->ap_fw ? "AP" : "STA",
+		   (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff,
+		   (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff);
 
 	return 0;
 
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index 8c4169c..09fae2f 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -117,9 +117,8 @@
 
 	case NL80211_IFTYPE_MONITOR:
 		if (priv->broken_monitor && !force_monitor) {
-			printk(KERN_WARNING "%s: Monitor mode support is "
-			       "buggy in this firmware, not enabling\n",
-			       wiphy_name(wiphy));
+			wiphy_warn(wiphy,
+				   "Monitor mode support is buggy in this firmware, not enabling\n");
 			err = -EINVAL;
 		}
 		break;
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c
index 3e1947d..259d758 100644
--- a/drivers/net/wireless/orinoco/fw.c
+++ b/drivers/net/wireless/orinoco/fw.c
@@ -49,7 +49,7 @@
 	__le32 pri_offset;      /* Offset to primary plug data */
 	__le32 compat_offset;   /* Offset to compatibility data*/
 	char signature[0];      /* FW signature length headersize-20 */
-} __attribute__ ((packed));
+} __packed;
 
 /* Check the range of various header entries. Return a pointer to a
  * description of the problem, or NULL if everything checks out. */
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h
index 9ca34e7..d9f18c1 100644
--- a/drivers/net/wireless/orinoco/hermes.h
+++ b/drivers/net/wireless/orinoco/hermes.h
@@ -205,7 +205,7 @@
 	u8 retry_count;
 	u8 tx_rate;
 	__le16 tx_control;
-} __attribute__ ((packed));
+} __packed;
 
 #define HERMES_TXSTAT_RETRYERR		(0x0001)
 #define HERMES_TXSTAT_AGEDERR		(0x0002)
@@ -254,7 +254,7 @@
 	/* Those last are probably not available in very old firmwares */
 	__le16 RxDiscards_WEPICVError;
 	__le16 RxDiscards_WEPExcluded;
-} __attribute__ ((packed));
+} __packed;
 
 /* Grabbed from wlan-ng - Thanks Mark... - Jean II
  * This is the result of a scan inquiry command */
@@ -271,7 +271,7 @@
 	u8 rates[10];		/* Bit rate supported */
 	__le16 proberesp_rate;	/* Data rate of the response frame */
 	__le16 atim;		/* ATIM window time, Kus (hostscan only) */
-} __attribute__ ((packed));
+} __packed;
 
 /* Same stuff for the Lucent/Agere card.
  * Thanks to h1kari <h1kari AT dachb0den.com> - Jean II */
@@ -285,7 +285,7 @@
 	/* bits: 0-ess, 1-ibss, 4-privacy [wep] */
 	__le16 essid_len;	/* ESSID length */
 	u8 essid[32];		/* ESSID of the network */
-} __attribute__ ((packed));
+} __packed;
 
 /* Moustafa: Scan structure for Symbol cards */
 struct symbol_scan_apinfo {
@@ -303,7 +303,7 @@
 	__le16 basic_rates;	/* Basic rates bitmask */
 	u8 unknown2[6];		/* Always FF:FF:FF:FF:00:00 */
 	u8 unknown3[8];		/* Always 0, appeared in f/w 3.91-68 */
-} __attribute__ ((packed));
+} __packed;
 
 union hermes_scan_info {
 	struct agere_scan_apinfo	a;
@@ -343,7 +343,7 @@
 	__le16	beacon_interval;
 	__le16	capabilities;
 	u8	data[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define HERMES_LINKSTATUS_NOT_CONNECTED   (0x0000)
 #define HERMES_LINKSTATUS_CONNECTED       (0x0001)
@@ -355,7 +355,7 @@
 
 struct hermes_linkstatus {
 	__le16 linkstatus;         /* Link status */
-} __attribute__ ((packed));
+} __packed;
 
 struct hermes_response {
 	u16 status, resp0, resp1, resp2;
@@ -365,11 +365,11 @@
 struct hermes_idstring {
 	__le16 len;
 	__le16 val[16];
-} __attribute__ ((packed));
+} __packed;
 
 struct hermes_multicast {
 	u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
 
 /* Timeouts */
 #define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index 6da85e7..2b2b9a1 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -65,10 +65,10 @@
 	__le32 addr;		/* adapter address where to write the block */
 	__le16 len;		/* length of the data only, in bytes */
 	char data[0];		/* data to be written */
-} __attribute__ ((packed));
+} __packed;
 
 /*
- * Plug Data References are located in in the image after the last data
+ * Plug Data References are located in the image after the last data
  * block.  They refer to areas in the adapter memory where the plug data
  * items with matching ID should be written.
  */
@@ -77,7 +77,7 @@
 	__le32 addr;		/* adapter address where to write the data */
 	__le32 len;		/* expected length of the data, in bytes */
 	char next[0];		/* next PDR starts here */
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * Plug Data Items are located in the EEPROM read from the adapter by
@@ -88,7 +88,7 @@
 	__le16 len;		/* length of ID and data, in words */
 	__le16 id;		/* record ID */
 	char data[0];		/* plug data */
-} __attribute__ ((packed));
+} __packed;
 
 /*** FW data block access functions ***/
 
@@ -317,7 +317,7 @@
 	__le16 len;							\
 	__le16 id;							\
 	u8 val[length];							\
-} __attribute__ ((packed)) default_pdr_data_##pid = {			\
+} __packed default_pdr_data_##pid = {			\
 	cpu_to_le16((sizeof(default_pdr_data_##pid)/			\
 				sizeof(__le16)) - 1),			\
 	cpu_to_le16(pid),						\
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index 6fbd788..077baa8 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -45,7 +45,7 @@
 /* Firmware version encoding */
 struct comp_id {
 	u16 id, variant, major, minor;
-} __attribute__ ((packed));
+} __packed;
 
 static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
 {
@@ -995,7 +995,7 @@
 		u8 tx_mic[MIC_KEYLEN];
 		u8 rx_mic[MIC_KEYLEN];
 		u8 tsc[ORINOCO_SEQ_LEN];
-	} __attribute__ ((packed)) buf;
+	} __packed buf;
 	hermes_t *hw = &priv->hw;
 	int ret;
 	int err;
@@ -1326,7 +1326,7 @@
 	struct {
 		u8 addr[ETH_ALEN];
 		__le16 reason_code;
-	} __attribute__ ((packed)) buf;
+	} __packed buf;
 
 	/* Currently only supported by WPA enabled Agere fw */
 	if (!priv->has_wpa)
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index ca71f08..e8e2d0f 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -172,7 +172,7 @@
 	__le16 frame_ctl;
 	__le16 duration_id;
 	u8 addr1[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
 
 /* Rx frame header except compatibility 802.3 header */
 struct hermes_rx_descriptor {
@@ -196,7 +196,7 @@
 
 	/* Data length */
 	__le16 data_len;
-} __attribute__ ((packed));
+} __packed;
 
 struct orinoco_rx_data {
 	struct hermes_rx_descriptor *desc;
@@ -390,7 +390,7 @@
 		struct header_struct {
 			struct ethhdr eth;	/* 802.3 header */
 			u8 encap[6];		/* 802.2 header */
-		} __attribute__ ((packed)) hdr;
+		} __packed hdr;
 		int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN);
 
 		if (skb_headroom(skb) < ENCAPS_OVERHEAD) {
@@ -1170,7 +1170,7 @@
 	struct join_req {
 		u8 bssid[ETH_ALEN];
 		__le16 channel;
-	} __attribute__ ((packed)) req;
+	} __packed req;
 	const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
 	struct prism2_scan_apinfo *atom = NULL;
 	int offset = 4;
@@ -1410,7 +1410,7 @@
 	struct {
 		__le16 len;
 		__le16 type;
-	} __attribute__ ((packed)) info;
+	} __packed info;
 	int len, type;
 	int err;
 
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index a6da86e..255710e 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -32,7 +32,7 @@
 struct orinoco_key {
 	__le16 len;	/* always stored as little-endian */
 	char data[ORINOCO_MAX_KEY_SIZE];
-} __attribute__ ((packed));
+} __packed;
 
 #define TKIP_KEYLEN	16
 #define MIC_KEYLEN	8
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index 78f089b..a38a7bd 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -90,7 +90,7 @@
 	/* SNAP */
 	u8 oui[3];
 	__be16 ethertype;
-} __attribute__ ((packed));
+} __packed;
 
 struct ez_usb_fw {
 	u16 size;
@@ -222,7 +222,7 @@
 	__le16 hermes_len;
 	__le16 hermes_rid;
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Table of devices that work or may work with this driver */
 static struct usb_device_id ezusb_table[] = {
@@ -356,12 +356,10 @@
 {
 	struct request_context *ctx;
 
-	ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
+	ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC);
 	if (!ctx)
 		return NULL;
 
-	memset(ctx, 0, sizeof(*ctx));
-
 	ctx->buf = kmalloc(BULK_BUF_SIZE, GFP_ATOMIC);
 	if (!ctx->buf) {
 		kfree(ctx);
@@ -1504,16 +1502,16 @@
 	    ezusb_ctx_complete(list_entry(item,
 					  struct request_context, list));
 
-	if (upriv->read_urb->status == -EINPROGRESS)
+	if (upriv->read_urb && upriv->read_urb->status == -EINPROGRESS)
 		printk(KERN_ERR PFX "Some URB in progress\n");
 
 	mutex_unlock(&upriv->mtx);
 
-	kfree(upriv->read_urb->transfer_buffer);
-	if (upriv->bap_buf != NULL)
-		kfree(upriv->bap_buf);
-	if (upriv->read_urb != NULL)
+	if (upriv->read_urb) {
+		kfree(upriv->read_urb->transfer_buffer);
 		usb_free_urb(upriv->read_urb);
+	}
+	kfree(upriv->bap_buf);
 	if (upriv->dev) {
 		struct orinoco_private *priv = ndev_priv(upriv->dev);
 		orinoco_if_del(priv);
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index 5775124..cf7be1e 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -128,7 +128,7 @@
 	} else {
 		struct {
 			__le16 qual, signal, noise, unused;
-		} __attribute__ ((packed)) cq;
+		} __packed cq;
 
 		err = HERMES_READ_RECORD(hw, USER_BAP,
 					 HERMES_RID_COMMSQUALITY, &cq);
@@ -993,11 +993,9 @@
 		return -EINVAL;
 
 	if (wrqu->data.length) {
-		buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+		buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
 		if (buf == NULL)
 			return -ENOMEM;
-
-		memcpy(buf, extra, wrqu->data.length);
 	} else
 		buf = NULL;
 
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index 187e263..d687cb7 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -149,16 +149,15 @@
 			continue;
 
 		if (list->channels[i].data != CHAN_HAS_ALL) {
-			printk(KERN_ERR "%s:%s%s%s is/are missing for "
-					"channel:%d [%d MHz].\n",
-			       wiphy_name(dev->wiphy),
-			       (list->channels[i].data & CHAN_HAS_CAL ? "" :
-				" [iqauto calibration data]"),
-			       (list->channels[i].data & CHAN_HAS_LIMIT ? "" :
-				" [output power limits]"),
-			       (list->channels[i].data & CHAN_HAS_CURVE ? "" :
-				" [curve data]"),
-			       list->channels[i].index, list->channels[i].freq);
+			wiphy_err(dev->wiphy,
+				  "%s%s%s is/are missing for channel:%d [%d MHz].\n",
+				  (list->channels[i].data & CHAN_HAS_CAL ? "" :
+				   " [iqauto calibration data]"),
+				  (list->channels[i].data & CHAN_HAS_LIMIT ? "" :
+				   " [output power limits]"),
+				  (list->channels[i].data & CHAN_HAS_CURVE ? "" :
+				   " [curve data]"),
+				  list->channels[i].index, list->channels[i].freq);
 			continue;
 		}
 
@@ -168,9 +167,8 @@
 	}
 
 	if (j == 0) {
-		printk(KERN_ERR "%s: Disabling totally damaged %s band.\n",
-		       wiphy_name(dev->wiphy), (band == IEEE80211_BAND_2GHZ) ?
-		       "2 GHz" : "5 GHz");
+		wiphy_err(dev->wiphy, "disabling totally damaged %d GHz band\n",
+			  (band == IEEE80211_BAND_2GHZ) ? 2 : 5);
 
 		ret = -ENODATA;
 		goto err_out;
@@ -244,9 +242,9 @@
 
 	if ((priv->iq_autocal_len != priv->curve_data->entries) ||
 	    (priv->iq_autocal_len != priv->output_limit->entries))
-		printk(KERN_ERR "%s: Unsupported or damaged EEPROM detected. "
-				"You may not be able to use all channels.\n",
-				wiphy_name(dev->wiphy));
+		wiphy_err(dev->wiphy,
+			  "Unsupported or damaged EEPROM detected. "
+			  "You may not be able to use all channels.\n");
 
 	max_channel_num = max_t(unsigned int, priv->output_limit->entries,
 				priv->iq_autocal_len);
@@ -419,15 +417,14 @@
 	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);
+		wiphy_err(dev->wiphy,
+			  "unknown rssi calibration data packing type:(%x) len:%d.\n",
+			  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));
+		wiphy_err(dev->wiphy, "please report this issue.\n");
 		return;
 	}
 
@@ -445,15 +442,14 @@
 	struct pda_country *country;
 
 	if (len != sizeof(*country)) {
-		printk(KERN_ERR "%s: found possible invalid default country "
-				"eeprom entry. (entry size: %d)\n",
-		       wiphy_name(dev->wiphy), len);
+		wiphy_err(dev->wiphy,
+			  "found possible invalid default country eeprom entry. (entry size: %d)\n",
+			  len);
 
 		print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
 				     data, len);
 
-		printk(KERN_ERR "%s: please report this issue.\n",
-			wiphy_name(dev->wiphy));
+		wiphy_err(dev->wiphy, "please report this issue.\n");
 		return;
 	}
 
@@ -478,8 +474,8 @@
 		return -EINVAL;
 
 	if (data[0] != 0) {
-		printk(KERN_ERR "%s: unknown output power db revision:%x\n",
-		       wiphy_name(dev->wiphy), data[0]);
+		wiphy_err(dev->wiphy, "unknown output power db revision:%x\n",
+			  data[0]);
 		return -EINVAL;
 	}
 
@@ -587,10 +583,9 @@
 				err = p54_convert_rev1(dev, curve_data);
 				break;
 			default:
-				printk(KERN_ERR "%s: unknown curve data "
-						"revision %d\n",
-						wiphy_name(dev->wiphy),
-						curve_data->cal_method_rev);
+				wiphy_err(dev->wiphy,
+					  "unknown curve data revision %d\n",
+					  curve_data->cal_method_rev);
 				err = -ENODEV;
 				break;
 			}
@@ -599,13 +594,13 @@
 			}
 			break;
 		case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
-			priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
+			priv->iq_autocal = kmemdup(entry->data, data_len,
+						   GFP_KERNEL);
 			if (!priv->iq_autocal) {
 				err = -ENOMEM;
 				goto err;
 			}
 
-			memcpy(priv->iq_autocal, entry->data, data_len);
 			priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
 			break;
 		case PDR_DEFAULT_COUNTRY:
@@ -672,8 +667,8 @@
 
 	if (!synth || !priv->iq_autocal || !priv->output_limit ||
 	    !priv->curve_data) {
-		printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
-			wiphy_name(dev->wiphy));
+		wiphy_err(dev->wiphy,
+			  "not all required entries found in eeprom!\n");
 		err = -EINVAL;
 		goto err;
 	}
@@ -699,15 +694,15 @@
 	if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
 		u8 perm_addr[ETH_ALEN];
 
-		printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
-			wiphy_name(dev->wiphy));
+		wiphy_warn(dev->wiphy,
+			   "invalid hwaddr! using randomly generated mac addr\n");
 		random_ether_addr(perm_addr);
 		SET_IEEE80211_PERM_ADDR(dev, perm_addr);
 	}
 
-	printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
-		wiphy_name(dev->wiphy),	dev->wiphy->perm_addr, priv->version,
-		p54_rf_chips[priv->rxhw]);
+	wiphy_info(dev->wiphy, "hwaddr %pm, mac:isl38%02x rf:%s\n",
+		   dev->wiphy->perm_addr, priv->version,
+		   p54_rf_chips[priv->rxhw]);
 
 	return 0;
 
@@ -719,8 +714,7 @@
 	priv->output_limit = NULL;
 	priv->curve_data = NULL;
 
-	printk(KERN_ERR "%s: eeprom parse failed!\n",
-		wiphy_name(dev->wiphy));
+	wiphy_err(dev->wiphy, "eeprom parse failed!\n");
 	return err;
 }
 EXPORT_SYMBOL_GPL(p54_parse_eeprom);
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index c43a5d4..47006bc 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -62,16 +62,15 @@
 			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(priv->hw->wiphy),
-					iftype[2], iftype[3]);
+				wiphy_info(priv->hw->wiphy,
+					   "p54 detected a LM%c%c firmware\n",
+					   iftype[2], iftype[3]);
 				break;
 				}
 			case FW_FMAC:
 			default:
-				printk(KERN_ERR "%s: unsupported firmware\n",
-					wiphy_name(priv->hw->wiphy));
+				wiphy_err(priv->hw->wiphy,
+					  "unsupported firmware\n");
 				return -ENODEV;
 			}
 			break;
@@ -125,15 +124,15 @@
 	}
 
 	if (fw_version)
-		printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
-			wiphy_name(priv->hw->wiphy), fw_version,
-			priv->fw_var >> 8, priv->fw_var & 0xff);
+		wiphy_info(priv->hw->wiphy,
+			   "fw rev %s - softmac protocol %x.%x\n",
+			   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(priv->hw->wiphy));
+		wiphy_info(priv->hw->wiphy,
+			   "you are using an obsolete firmware. "
+			   "visit http://wireless.kernel.org/en/users/Drivers/p54 "
+			   "and grab one for \"kernel >= 2.6.28\"!\n");
 
 	if (priv->fw_var >= 0x300) {
 		/* Firmware supports QoS, use it! */
@@ -152,13 +151,14 @@
 		priv->hw->queues = P54_QUEUE_AC_NUM;
 	}
 
-	printk(KERN_INFO "%s: cryptographic accelerator "
-	       "WEP:%s, TKIP:%s, CCMP:%s\n", wiphy_name(priv->hw->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");
+	wiphy_info(priv->hw->wiphy,
+		   "cryptographic accelerator WEP:%s, TKIP:%s, CCMP:%s\n",
+		   (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");
 
 	if (priv->rx_keycache_size) {
 		/*
@@ -247,8 +247,7 @@
 
 	if (!wait_for_completion_interruptible_timeout(
 	     &priv->eeprom_comp, HZ)) {
-		printk(KERN_ERR "%s: device does not respond!\n",
-		       wiphy_name(priv->hw->wiphy));
+		wiphy_err(priv->hw->wiphy, "device does not respond!\n");
 		ret = -EBUSY;
 	}
 	priv->eeprom = NULL;
@@ -523,9 +522,9 @@
 	return 0;
 
 err:
-	printk(KERN_ERR "%s: frequency change to channel %d failed.\n",
-	       wiphy_name(priv->hw->wiphy), ieee80211_frequency_to_channel(
-	       priv->hw->conf.channel->center_freq));
+	wiphy_err(priv->hw->wiphy, "frequency change to channel %d failed.\n",
+		  ieee80211_frequency_to_channel(
+			  priv->hw->conf.channel->center_freq));
 
 	dev_kfree_skb_any(skb);
 	return -EINVAL;
@@ -676,8 +675,8 @@
 		break;
 
 	default:
-		printk(KERN_ERR "%s: invalid cryptographic algorithm: %d\n",
-		       wiphy_name(priv->hw->wiphy), algo);
+		wiphy_err(priv->hw->wiphy,
+			  "invalid cryptographic algorithm: %d\n", algo);
 		dev_kfree_skb(skb);
 		return -EINVAL;
 	}
diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c
index 9575ac0..ea91f5c 100644
--- a/drivers/net/wireless/p54/led.c
+++ b/drivers/net/wireless/p54/led.c
@@ -57,8 +57,8 @@
 
 	err = p54_set_leds(priv);
 	if (err && net_ratelimit())
-		printk(KERN_ERR "%s: failed to update LEDs (%d).\n",
-			wiphy_name(priv->hw->wiphy), err);
+		wiphy_err(priv->hw->wiphy,
+			  "failed to update leds (%d).\n", err);
 
 	if (rerun)
 		ieee80211_queue_delayed_work(priv->hw, &priv->led_work,
@@ -102,8 +102,8 @@
 
 	err = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_dev);
 	if (err)
-		printk(KERN_ERR "%s: Failed to register %s LED.\n",
-			wiphy_name(priv->hw->wiphy), name);
+		wiphy_err(priv->hw->wiphy,
+			  "failed to register %s led.\n", name);
 	else
 		led->registered = 1;
 
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index c072f41..47db439 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -507,6 +507,22 @@
 	return ret;
 }
 
+static int p54_get_survey(struct ieee80211_hw *dev, int idx,
+				struct survey_info *survey)
+{
+	struct p54_common *priv = dev->priv;
+	struct ieee80211_conf *conf = &dev->conf;
+
+	if (idx != 0)
+		return -ENOENT;
+
+	survey->channel = conf->channel;
+	survey->filled = SURVEY_INFO_NOISE_DBM;
+	survey->noise = clamp_t(s8, priv->noise, -128, 127);
+
+	return 0;
+}
+
 static const struct ieee80211_ops p54_ops = {
 	.tx			= p54_tx_80211,
 	.start			= p54_start,
@@ -523,6 +539,7 @@
 	.configure_filter	= p54_configure_filter,
 	.conf_tx		= p54_conf_tx,
 	.get_stats		= p54_get_stats,
+	.get_survey		= p54_get_survey,
 };
 
 struct ieee80211_hw *p54_init_common(size_t priv_data_len)
diff --git a/drivers/net/wireless/p54/net2280.h b/drivers/net/wireless/p54/net2280.h
index 4915d9d..e3ed893 100644
--- a/drivers/net/wireless/p54/net2280.h
+++ b/drivers/net/wireless/p54/net2280.h
@@ -232,7 +232,7 @@
 #define GPIO2_INTERRUPT						2
 #define GPIO1_INTERRUPT						1
 #define GPIO0_INTERRUPT						0
-} __attribute__ ((packed));
+} __packed;
 
 /* usb control, BAR0 + 0x0080 */
 struct net2280_usb_regs {
@@ -296,7 +296,7 @@
 #define FORCE_IMMEDIATE						7
 #define OUR_USB_ADDRESS						0
 	__le32			ourconfig;
-} __attribute__ ((packed));
+} __packed;
 
 /* pci control, BAR0 + 0x0100 */
 struct net2280_pci_regs {
@@ -323,7 +323,7 @@
 #define PCI_ARBITER_CLEAR					2
 #define PCI_EXTERNAL_ARBITER					1
 #define PCI_HOST_MODE						0
-} __attribute__ ((packed));
+} __packed;
 
 /* dma control, BAR0 + 0x0180 ... array of four structs like this,
  * for channels 0..3.  see also struct net2280_dma:  descriptor
@@ -364,7 +364,7 @@
 	__le32			dmaaddr;
 	__le32			dmadesc;
 	u32			_unused1;
-} __attribute__ ((packed));
+} __packed;
 
 /* dedicated endpoint registers, BAR0 + 0x0200 */
 
@@ -374,7 +374,7 @@
 	/* offset 0x0204, 0x0214, 0x224, 0x234, 0x244 */
 	__le32			dep_rsp;
 	u32			_unused[2];
-} __attribute__ ((packed));
+} __packed;
 
 /* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs
  * like this, for ep0 then the configurable endpoints A..F
@@ -437,16 +437,16 @@
 	__le32			ep_avail;
 	__le32			ep_data;
 	u32			_unused0[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct net2280_reg_write {
 	__le16 port;
 	__le32 addr;
 	__le32 val;
-} __attribute__ ((packed));
+} __packed;
 
 struct net2280_reg_read {
 	__le16 port;
 	__le32 addr;
-} __attribute__ ((packed));
+} __packed;
 #endif /* NET2280_H */
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index a5ea89c..822f8dc 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -466,8 +466,7 @@
 	P54P_READ(dev_int);
 
 	if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
-		printk(KERN_ERR "%s: Cannot boot firmware!\n",
-		       wiphy_name(dev->wiphy));
+		wiphy_err(dev->wiphy, "cannot boot firmware!\n");
 		p54p_stop(dev);
 		return -ETIMEDOUT;
 	}
diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h
index 2feead6..ee9bc62 100644
--- a/drivers/net/wireless/p54/p54pci.h
+++ b/drivers/net/wireless/p54/p54pci.h
@@ -65,7 +65,7 @@
 	u8 unused_6[1924];
 	u8 cardbus_cis[0x800];
 	u8 direct_mem_win[0x1000];
-} __attribute__ ((packed));
+} __packed;
 
 /* usb backend only needs the register defines above */
 #ifndef P54USB_H
@@ -74,7 +74,7 @@
 	__le32 device_addr;
 	__le16 len;
 	__le16 flags;
-} __attribute__ ((packed));
+} __packed;
 
 struct p54p_ring_control {
 	__le32 host_idx[4];
@@ -83,7 +83,7 @@
 	struct p54p_desc tx_data[32];
 	struct p54p_desc rx_mgmt[4];
 	struct p54p_desc tx_mgmt[4];
-} __attribute__ ((packed));
+} __packed;
 
 #define P54P_READ(r) (__force __le32)__raw_readl(&priv->map->r)
 #define P54P_WRITE(r, val) __raw_writel((__force u32)(__le32)(val), &priv->map->r)
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index c8f09da..087bf06 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -697,9 +697,7 @@
 
 static struct spi_driver p54spi_driver = {
 	.driver = {
-		/* use cx3110x name because board-n800.c uses that for the
-		 * SPI port */
-		.name		= "cx3110x",
+		.name		= "p54spi",
 		.bus		= &spi_bus_type,
 		.owner		= THIS_MODULE,
 	},
@@ -733,3 +731,4 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
 MODULE_ALIAS("spi:cx3110x");
+MODULE_ALIAS("spi:p54spi");
diff --git a/drivers/net/wireless/p54/p54spi.h b/drivers/net/wireless/p54/p54spi.h
index 7fbe8d8..dfaa62a 100644
--- a/drivers/net/wireless/p54/p54spi.h
+++ b/drivers/net/wireless/p54/p54spi.h
@@ -96,7 +96,7 @@
 	__le16 cmd;
 	__le16 len;
 	__le32 addr;
-} __attribute__ ((packed));
+} __packed;
 
 struct p54s_tx_info {
 	struct list_head tx_list;
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 7307325..ad59595 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -69,7 +69,8 @@
 	{USB_DEVICE(0x0915, 0x2002)},	/* Cohiba Proto board */
 	{USB_DEVICE(0x0baf, 0x0118)},   /* U.S. Robotics U5 802.11g Adapter*/
 	{USB_DEVICE(0x0bf8, 0x1009)},   /* FUJITSU E-5400 USB D1700*/
-	{USB_DEVICE(0x0cde, 0x0006)},   /* Medion MD40900 */
+	/* {USB_DEVICE(0x0cde, 0x0006)}, * Medion MD40900 already listed above,
+					 * just noting it here for clarity */
 	{USB_DEVICE(0x0cde, 0x0008)},	/* Sagem XG703A */
 	{USB_DEVICE(0x0cde, 0x0015)},	/* Zcomax XG-705A */
 	{USB_DEVICE(0x0d8e, 0x3762)},	/* DLink DWL-G120 Cohiba */
@@ -434,10 +435,9 @@
 	u8 *buf;
 	int ret;
 
-	buf = kmalloc(4, GFP_KERNEL);
+	buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
-	memcpy(buf, p54u_romboot_3887, 4);
 	ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
 			    buf, 4);
 	kfree(buf);
diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h
index e935b79..ed4034a 100644
--- a/drivers/net/wireless/p54/p54usb.h
+++ b/drivers/net/wireless/p54/p54usb.h
@@ -70,12 +70,12 @@
 	__le16 len;
 	__le16 follower;	/* ? */
 	u8 padding[8];
-} __attribute__((packed));
+} __packed;
 
 struct lm87_tx_hdr {
 	__le32 device_addr;
 	__le32 chksum;
-} __attribute__((packed));
+} __packed;
 
 /* Some flags for the isl hardware registers controlling DMA inside the
  * chip */
@@ -103,7 +103,7 @@
 	__le32 fw_load_addr;
 	__le32 fw_length;
 	__le32 crc;
-} __attribute__((packed));
+} __packed;
 
 /* pipes 3 and 4 are not used by the driver */
 #define P54U_PIPE_NUMBER 9
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 4e68910..427b46f 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -38,8 +38,8 @@
 	u32 largest_hole = 0, free;
 
 	spin_lock_irqsave(&priv->tx_queue.lock, flags);
-	printk(KERN_DEBUG "%s: / --- tx queue dump (%d entries) ---\n",
-	       wiphy_name(priv->hw->wiphy), skb_queue_len(&priv->tx_queue));
+	wiphy_debug(priv->hw->wiphy, "/ --- tx queue dump (%d entries) ---\n",
+		    skb_queue_len(&priv->tx_queue));
 
 	prev_addr = priv->rx_start;
 	skb_queue_walk(&priv->tx_queue, skb) {
@@ -48,21 +48,23 @@
 		hdr = (void *) skb->data;
 
 		free = range->start_addr - prev_addr;
-		printk(KERN_DEBUG "%s: | [%02d] => [skb:%p skb_len:0x%04x "
-		       "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} "
-		       "mem:{start:%04x end:%04x, free:%d}]\n",
-		       wiphy_name(priv->hw->wiphy), i++, skb, skb->len,
-		       le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len),
-		       le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type),
-		       range->start_addr, range->end_addr, free);
+		wiphy_debug(priv->hw->wiphy,
+			    "| [%02d] => [skb:%p skb_len:0x%04x "
+			    "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} "
+			    "mem:{start:%04x end:%04x, free:%d}]\n",
+			    i++, skb, skb->len,
+			    le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len),
+			    le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type),
+			    range->start_addr, range->end_addr, free);
 
 		prev_addr = range->end_addr;
 		largest_hole = max(largest_hole, free);
 	}
 	free = priv->rx_end - prev_addr;
 	largest_hole = max(largest_hole, free);
-	printk(KERN_DEBUG "%s: \\ --- [free: %d], largest free block: %d ---\n",
-	       wiphy_name(priv->hw->wiphy), free, largest_hole);
+	wiphy_debug(priv->hw->wiphy,
+		    "\\ --- [free: %d], largest free block: %d ---\n",
+		    free, largest_hole);
 	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 }
 #endif /* P54_MM_DEBUG */
@@ -538,8 +540,7 @@
 	case P54_TRAP_BEACON_TX:
 		break;
 	case P54_TRAP_RADAR:
-		printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
-			wiphy_name(priv->hw->wiphy), freq);
+		wiphy_info(priv->hw->wiphy, "radar (freq:%d mhz)\n", freq);
 		break;
 	case P54_TRAP_NO_BEACON:
 		if (priv->vif)
@@ -558,8 +559,8 @@
 		wiphy_rfkill_set_hw_state(priv->hw->wiphy, false);
 		break;
 	default:
-		printk(KERN_INFO "%s: received event:%x freq:%d\n",
-		       wiphy_name(priv->hw->wiphy), event, freq);
+		wiphy_info(priv->hw->wiphy, "received event:%x freq:%d\n",
+			   event, freq);
 		break;
 	}
 }
@@ -584,8 +585,9 @@
 		p54_rx_eeprom_readback(priv, skb);
 		break;
 	default:
-		printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
-		       wiphy_name(priv->hw->wiphy), le16_to_cpu(hdr->type));
+		wiphy_debug(priv->hw->wiphy,
+			    "not handling 0x%02x type control frame\n",
+			    le16_to_cpu(hdr->type));
 		break;
 	}
 	return 0;
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 8d1190c..77cd65d 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -2067,7 +2067,7 @@
 	memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
 	if (!memptr)
 		return;
-	BUG_ON(n > IW_CUSTOM_MAX);
+	BUG_ON(n >= IW_CUSTOM_MAX);
 	wrqu.data.pointer = memptr;
 	wrqu.data.length = n;
 	strcpy(memptr, str);
@@ -2101,7 +2101,7 @@
 	u8 timestamp[8];
 	u16 beacon_int;
 	u16 capab_info;
-} __attribute__ ((packed));
+} __packed;
 
 #define WLAN_EID_GENERIC 0xdd
 static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
@@ -2751,14 +2751,9 @@
            p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
                return -EINVAL;
 
-       param = kmalloc(p->length, GFP_KERNEL);
-       if (param == NULL)
-               return -ENOMEM;
-
-       if (copy_from_user(param, p->pointer, p->length)) {
-               kfree(param);
-               return -EFAULT;
-       }
+	param = memdup_user(p->pointer, p->length);
+	if (IS_ERR(param))
+		return PTR_ERR(param);
 
        switch (param->cmd) {
        case PRISM2_SET_ENCRYPTION:
diff --git a/drivers/net/wireless/prism54/isl_oid.h b/drivers/net/wireless/prism54/isl_oid.h
index b7534c2..59e3125 100644
--- a/drivers/net/wireless/prism54/isl_oid.h
+++ b/drivers/net/wireless/prism54/isl_oid.h
@@ -29,20 +29,20 @@
 struct obj_ssid {
 	u8 length;
 	char octets[33];
-} __attribute__ ((packed));
+} __packed;
 
 struct obj_key {
 	u8 type;		/* dot11_priv_t */
 	u8 length;
 	char key[32];
-} __attribute__ ((packed));
+} __packed;
 
 struct obj_mlme {
 	u8 address[6];
 	u16 id;
 	u16 state;
 	u16 code;
-} __attribute__ ((packed));
+} __packed;
 
 struct obj_mlmeex {
 	u8 address[6];
@@ -51,12 +51,12 @@
 	u16 code;
 	u16 size;
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct obj_buffer {
 	u32 size;
 	u32 addr;		/* 32bit bus address */
-} __attribute__ ((packed));
+} __packed;
 
 struct obj_bss {
 	u8 address[6];
@@ -77,17 +77,17 @@
 	short rates;
 	short basic_rates;
 	int:16;			/* padding */
-} __attribute__ ((packed));
+} __packed;
 
 struct obj_bsslist {
 	u32 nr;
 	struct obj_bss bsslist[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct obj_frequencies {
 	u16 nr;
 	u16 mhz[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct obj_attachment {
 	char type;
@@ -95,7 +95,7 @@
 	short id;
 	short size;
 	char data[0];
-} __attribute__((packed));
+} __packed;
 
 /*
  * in case everything's ok, the inlined function below will be
diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h
index 54f9a4b..6ca30a5 100644
--- a/drivers/net/wireless/prism54/islpci_eth.h
+++ b/drivers/net/wireless/prism54/islpci_eth.h
@@ -34,13 +34,13 @@
 	__le16 unk3;
 	u8 rssi;
 	u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct rx_annex_header {
 	u8 addr1[ETH_ALEN];
 	u8 addr2[ETH_ALEN];
 	struct rfmon_header rfmon;
-} __attribute__ ((packed));
+} __packed;
 
 /* wlan-ng (and hopefully others) AVS header, version one.  Fields in
  * network byte order. */
diff --git a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h
index 0b27e50..0db93db 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.h
+++ b/drivers/net/wireless/prism54/islpci_mgt.h
@@ -101,7 +101,7 @@
 	u8 device_id;
 	u8 flags;
 	u32 length;
-} __attribute__ ((packed))
+} __packed
 pimfor_header_t;
 
 /* A received and interrupt-processed management frame, either for
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index abff893..9c38fc3 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -97,7 +97,6 @@
 static const struct iw_handler_def ray_handler_def;
 
 /***** Prototypes for raylink functions **************************************/
-static int asc_to_int(char a);
 static void authenticate(ray_dev_t *local);
 static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type);
 static void authenticate_timeout(u_long);
@@ -1717,24 +1716,6 @@
 }
 
 /*===========================================================================*/
-static int asc_to_int(char a)
-{
-	if (a < '0')
-		return -1;
-	if (a <= '9')
-		return (a - '0');
-	if (a < 'A')
-		return -1;
-	if (a <= 'F')
-		return (10 + a - 'A');
-	if (a < 'a')
-		return -1;
-	if (a <= 'f')
-		return (10 + a - 'a');
-	return -1;
-}
-
-/*===========================================================================*/
 static int parse_addr(char *in_str, UCHAR *out)
 {
 	int len;
@@ -1754,14 +1735,14 @@
 	i = 5;
 
 	while (j > 0) {
-		if ((k = asc_to_int(in_str[j--])) != -1)
+		if ((k = hex_to_bin(in_str[j--])) != -1)
 			out[i] = k;
 		else
 			return 0;
 
 		if (j == 0)
 			break;
-		if ((k = asc_to_int(in_str[j--])) != -1)
+		if ((k = hex_to_bin(in_str[j--])) != -1)
 			out[i] += k << 4;
 		else
 			return 0;
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 4bd61ee..719573b 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -238,19 +238,19 @@
 	u8 bssid[6];
 	u8 padding[2];
 	__le32 flags;
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_pmkid_candidate {
 	u8 bssid[6];
 	u8 padding[2];
 	__le32 flags;
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_pmkid_cand_list {
 	__le32 version;
 	__le32 num_candidates;
 	struct ndis_80211_pmkid_candidate candidate_list[0];
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_status_indication {
 	__le32 status_type;
@@ -260,19 +260,19 @@
 		struct ndis_80211_auth_request		auth_request[0];
 		struct ndis_80211_pmkid_cand_list	cand_list;
 	} u;
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_ssid {
 	__le32 length;
 	u8 essid[NDIS_802_11_LENGTH_SSID];
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_conf_freq_hop {
 	__le32 length;
 	__le32 hop_pattern;
 	__le32 hop_set;
 	__le32 dwell_time;
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_conf {
 	__le32 length;
@@ -280,7 +280,7 @@
 	__le32 atim_window;
 	__le32 ds_config;
 	struct ndis_80211_conf_freq_hop fh_config;
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_bssid_ex {
 	__le32 length;
@@ -295,25 +295,25 @@
 	u8 rates[NDIS_802_11_LENGTH_RATES_EX];
 	__le32 ie_length;
 	u8 ies[0];
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_bssid_list_ex {
 	__le32 num_items;
 	struct ndis_80211_bssid_ex bssid[0];
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_fixed_ies {
 	u8 timestamp[8];
 	__le16 beacon_interval;
 	__le16 capabilities;
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_wep_key {
 	__le32 size;
 	__le32 index;
 	__le32 length;
 	u8 material[32];
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_key {
 	__le32 size;
@@ -323,14 +323,14 @@
 	u8 padding[6];
 	u8 rsc[8];
 	u8 material[32];
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_remove_key {
 	__le32 size;
 	__le32 index;
 	u8 bssid[6];
 	u8 padding[2];
-} __attribute__((packed));
+} __packed;
 
 struct ndis_config_param {
 	__le32 name_offs;
@@ -338,7 +338,7 @@
 	__le32 type;
 	__le32 value_offs;
 	__le32 value_length;
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_assoc_info {
 	__le32 length;
@@ -358,12 +358,12 @@
 	} resp_ie;
 	__le32 resp_ie_length;
 	__le32 offset_resp_ies;
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_auth_encr_pair {
 	__le32 auth_mode;
 	__le32 encr_mode;
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_capability {
 	__le32 length;
@@ -371,7 +371,7 @@
 	__le32 num_pmkids;
 	__le32 num_auth_encr_pair;
 	struct ndis_80211_auth_encr_pair auth_encr_pair[0];
-} __attribute__((packed));
+} __packed;
 
 struct ndis_80211_bssid_info {
 	u8 bssid[6];
@@ -520,8 +520,9 @@
 
 static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);
 
-static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
-				int dbm);
+static int rndis_set_tx_power(struct wiphy *wiphy,
+			      enum nl80211_tx_power_setting type,
+			      int mbm);
 static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm);
 
 static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
@@ -1856,20 +1857,25 @@
 	return 0;
 }
 
-static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
-				int dbm)
+static int rndis_set_tx_power(struct wiphy *wiphy,
+			      enum nl80211_tx_power_setting type,
+			      int mbm)
 {
 	struct rndis_wlan_private *priv = wiphy_priv(wiphy);
 	struct usbnet *usbdev = priv->usbdev;
 
-	netdev_dbg(usbdev->net, "%s(): type:0x%x dbm:%i\n",
-		   __func__, type, dbm);
+	netdev_dbg(usbdev->net, "%s(): type:0x%x mbm:%i\n",
+		   __func__, type, mbm);
+
+	if (mbm < 0 || (mbm % 100))
+		return -ENOTSUPP;
 
 	/* Device doesn't support changing txpower after initialization, only
 	 * turn off/on radio. Support 'auto' mode and setting same dBm that is
 	 * currently used.
 	 */
-	if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) {
+	if (type == NL80211_TX_POWER_AUTOMATIC ||
+	    MBM_TO_DBM(mbm) == get_bcm4320_power_dbm(priv)) {
 		if (!priv->radio_on)
 			disassociate(usbdev, true); /* turn on radio */
 
@@ -2495,8 +2501,7 @@
 static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
 {
 	struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
-	struct ndis_80211_assoc_info *info;
-	u8 assoc_buf[sizeof(*info) + IW_CUSTOM_MAX + 32];
+	struct ndis_80211_assoc_info *info = NULL;
 	u8 bssid[ETH_ALEN];
 	int resp_ie_len, req_ie_len;
 	u8 *req_ie, *resp_ie;
@@ -2515,23 +2520,43 @@
 	resp_ie = NULL;
 
 	if (priv->infra_mode == NDIS_80211_INFRA_INFRA) {
-		memset(assoc_buf, 0, sizeof(assoc_buf));
-		info = (void *)assoc_buf;
+		info = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
+		if (!info) {
+			/* No memory? Try resume work later */
+			set_bit(WORK_LINK_UP, &priv->work_pending);
+			queue_work(priv->workqueue, &priv->work);
+			return;
+		}
 
-		/* Get association info IEs from device and send them back to
-		 * userspace. */
-		ret = get_association_info(usbdev, info, sizeof(assoc_buf));
+		/* Get association info IEs from device. */
+		ret = get_association_info(usbdev, info, CONTROL_BUFFER_SIZE);
 		if (!ret) {
 			req_ie_len = le32_to_cpu(info->req_ie_length);
 			if (req_ie_len > 0) {
 				offset = le32_to_cpu(info->offset_req_ies);
+
+				if (offset > CONTROL_BUFFER_SIZE)
+					offset = CONTROL_BUFFER_SIZE;
+
 				req_ie = (u8 *)info + offset;
+
+				if (offset + req_ie_len > CONTROL_BUFFER_SIZE)
+					req_ie_len =
+						CONTROL_BUFFER_SIZE - offset;
 			}
 
 			resp_ie_len = le32_to_cpu(info->resp_ie_length);
 			if (resp_ie_len > 0) {
 				offset = le32_to_cpu(info->offset_resp_ies);
+
+				if (offset > CONTROL_BUFFER_SIZE)
+					offset = CONTROL_BUFFER_SIZE;
+
 				resp_ie = (u8 *)info + offset;
+
+				if (offset + resp_ie_len > CONTROL_BUFFER_SIZE)
+					resp_ie_len =
+						CONTROL_BUFFER_SIZE - offset;
 			}
 		}
 	} else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC))
@@ -2563,6 +2588,9 @@
 	} else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
 		cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
 
+	if (info != NULL)
+		kfree(info);
+
 	priv->connected = true;
 	memcpy(priv->bssid, bssid, ETH_ALEN);
 
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index ad2c98a..5063e01 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -586,9 +586,11 @@
 static inline void rt2400pci_set_vgc(struct rt2x00_dev *rt2x00dev,
 				     struct link_qual *qual, u8 vgc_level)
 {
-	rt2400pci_bbp_write(rt2x00dev, 13, vgc_level);
-	qual->vgc_level = vgc_level;
-	qual->vgc_level_reg = vgc_level;
+	if (qual->vgc_level_reg != vgc_level) {
+		rt2400pci_bbp_write(rt2x00dev, 13, vgc_level);
+		qual->vgc_level = vgc_level;
+		qual->vgc_level_reg = vgc_level;
+	}
 }
 
 static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev,
@@ -877,7 +879,8 @@
 static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
 				 enum dev_state state)
 {
-	int mask = (state == STATE_RADIO_IRQ_OFF);
+	int mask = (state == STATE_RADIO_IRQ_OFF) ||
+		   (state == STATE_RADIO_IRQ_OFF_ISR);
 	u32 reg;
 
 	/*
@@ -978,7 +981,9 @@
 		rt2400pci_toggle_rx(rt2x00dev, state);
 		break;
 	case STATE_RADIO_IRQ_ON:
+	case STATE_RADIO_IRQ_ON_ISR:
 	case STATE_RADIO_IRQ_OFF:
+	case STATE_RADIO_IRQ_OFF_ISR:
 		rt2400pci_toggle_irq(rt2x00dev, state);
 		break;
 	case STATE_DEEP_SLEEP:
@@ -1076,9 +1081,6 @@
 				   struct txentry_desc *txdesc)
 {
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
-	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
-	u32 word;
 	u32 reg;
 
 	/*
@@ -1091,9 +1093,15 @@
 
 	rt2x00queue_map_txskb(rt2x00dev, entry->skb);
 
-	rt2x00_desc_read(entry_priv->desc, 1, &word);
-	rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
-	rt2x00_desc_write(entry_priv->desc, 1, word);
+	/*
+	 * Write the TX descriptor for the beacon.
+	 */
+	rt2400pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+	/*
+	 * Dump beacon to userspace through debugfs.
+	 */
+	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
 
 	/*
 	 * Enable beaconing again.
@@ -1230,23 +1238,10 @@
 	}
 }
 
-static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
+static irqreturn_t rt2400pci_interrupt_thread(int irq, void *dev_instance)
 {
 	struct rt2x00_dev *rt2x00dev = dev_instance;
-	u32 reg;
-
-	/*
-	 * Get the interrupt sources & saved to local variable.
-	 * Write register value back to clear pending interrupts.
-	 */
-	rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
-	rt2x00pci_register_write(rt2x00dev, CSR7, reg);
-
-	if (!reg)
-		return IRQ_NONE;
-
-	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
-		return IRQ_HANDLED;
+	u32 reg = rt2x00dev->irqvalue[0];
 
 	/*
 	 * Handle interrupts, walk through all bits
@@ -1284,9 +1279,40 @@
 	if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
 		rt2400pci_txdone(rt2x00dev, QID_AC_BK);
 
+	/* Enable interrupts again. */
+	rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+					      STATE_RADIO_IRQ_ON_ISR);
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
+{
+	struct rt2x00_dev *rt2x00dev = dev_instance;
+	u32 reg;
+
+	/*
+	 * Get the interrupt sources & saved to local variable.
+	 * Write register value back to clear pending interrupts.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+	rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+
+	if (!reg)
+		return IRQ_NONE;
+
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		return IRQ_HANDLED;
+
+	/* Store irqvalues for use in the interrupt thread. */
+	rt2x00dev->irqvalue[0] = reg;
+
+	/* Disable interrupts, will be enabled again in the interrupt thread. */
+	rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+					      STATE_RADIO_IRQ_OFF_ISR);
+
+	return IRQ_WAKE_THREAD;
+}
+
 /*
  * Device probe functions.
  */
@@ -1396,8 +1422,8 @@
 	/*
 	 * Check if the BBP tuning should be enabled.
 	 */
-	if (!rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING))
-		__set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING))
+		__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
 
 	return 0;
 }
@@ -1563,7 +1589,8 @@
 	.remove_interface	= rt2x00mac_remove_interface,
 	.config			= rt2x00mac_config,
 	.configure_filter	= rt2x00mac_configure_filter,
-	.set_tim		= rt2x00mac_set_tim,
+	.sw_scan_start		= rt2x00mac_sw_scan_start,
+	.sw_scan_complete	= rt2x00mac_sw_scan_complete,
 	.get_stats		= rt2x00mac_get_stats,
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt2400pci_conf_tx,
@@ -1574,6 +1601,7 @@
 
 static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
 	.irq_handler		= rt2400pci_interrupt,
+	.irq_handler_thread	= rt2400pci_interrupt_thread,
 	.probe_hw		= rt2400pci_probe_hw,
 	.initialize		= rt2x00pci_initialize,
 	.uninitialize		= rt2x00pci_uninitialize,
@@ -1585,7 +1613,6 @@
 	.reset_tuner		= rt2400pci_reset_tuner,
 	.link_tuner		= rt2400pci_link_tuner,
 	.write_tx_desc		= rt2400pci_write_tx_desc,
-	.write_tx_data		= rt2x00pci_write_tx_data,
 	.write_beacon		= rt2400pci_write_beacon,
 	.kick_tx_queue		= rt2400pci_kick_tx_queue,
 	.kill_tx_queue		= rt2400pci_kill_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 41da3d2..c2a555d 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -626,6 +626,7 @@
 {
 	if (qual->vgc_level_reg != vgc_level) {
 		rt2500pci_bbp_write(rt2x00dev, 17, vgc_level);
+		qual->vgc_level = vgc_level;
 		qual->vgc_level_reg = vgc_level;
 	}
 }
@@ -700,13 +701,10 @@
 	 * R17 is inside the dynamic tuning range,
 	 * start tuning the link based on the false cca counter.
 	 */
-	if (qual->false_cca > 512 && qual->vgc_level_reg < 0x40) {
+	if (qual->false_cca > 512 && qual->vgc_level_reg < 0x40)
 		rt2500pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level_reg);
-		qual->vgc_level = qual->vgc_level_reg;
-	} else if (qual->false_cca < 100 && qual->vgc_level_reg > 0x32) {
+	else if (qual->false_cca < 100 && qual->vgc_level_reg > 0x32)
 		rt2500pci_set_vgc(rt2x00dev, qual, --qual->vgc_level_reg);
-		qual->vgc_level = qual->vgc_level_reg;
-	}
 }
 
 /*
@@ -1035,7 +1033,8 @@
 static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
 				 enum dev_state state)
 {
-	int mask = (state == STATE_RADIO_IRQ_OFF);
+	int mask = (state == STATE_RADIO_IRQ_OFF) ||
+		   (state == STATE_RADIO_IRQ_OFF_ISR);
 	u32 reg;
 
 	/*
@@ -1136,7 +1135,9 @@
 		rt2500pci_toggle_rx(rt2x00dev, state);
 		break;
 	case STATE_RADIO_IRQ_ON:
+	case STATE_RADIO_IRQ_ON_ISR:
 	case STATE_RADIO_IRQ_OFF:
+	case STATE_RADIO_IRQ_OFF_ISR:
 		rt2500pci_toggle_irq(rt2x00dev, state);
 		break;
 	case STATE_DEEP_SLEEP:
@@ -1233,9 +1234,6 @@
 				   struct txentry_desc *txdesc)
 {
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
-	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
-	u32 word;
 	u32 reg;
 
 	/*
@@ -1248,9 +1246,15 @@
 
 	rt2x00queue_map_txskb(rt2x00dev, entry->skb);
 
-	rt2x00_desc_read(entry_priv->desc, 1, &word);
-	rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
-	rt2x00_desc_write(entry_priv->desc, 1, word);
+	/*
+	 * Write the TX descriptor for the beacon.
+	 */
+	rt2500pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+	/*
+	 * Dump beacon to userspace through debugfs.
+	 */
+	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
 
 	/*
 	 * Enable beaconing again.
@@ -1366,23 +1370,10 @@
 	}
 }
 
-static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
+static irqreturn_t rt2500pci_interrupt_thread(int irq, void *dev_instance)
 {
 	struct rt2x00_dev *rt2x00dev = dev_instance;
-	u32 reg;
-
-	/*
-	 * Get the interrupt sources & saved to local variable.
-	 * Write register value back to clear pending interrupts.
-	 */
-	rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
-	rt2x00pci_register_write(rt2x00dev, CSR7, reg);
-
-	if (!reg)
-		return IRQ_NONE;
-
-	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
-		return IRQ_HANDLED;
+	u32 reg = rt2x00dev->irqvalue[0];
 
 	/*
 	 * Handle interrupts, walk through all bits
@@ -1420,9 +1411,41 @@
 	if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
 		rt2500pci_txdone(rt2x00dev, QID_AC_BK);
 
+	/* Enable interrupts again. */
+	rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+					      STATE_RADIO_IRQ_ON_ISR);
+
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
+{
+	struct rt2x00_dev *rt2x00dev = dev_instance;
+	u32 reg;
+
+	/*
+	 * Get the interrupt sources & saved to local variable.
+	 * Write register value back to clear pending interrupts.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+	rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+
+	if (!reg)
+		return IRQ_NONE;
+
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		return IRQ_HANDLED;
+
+	/* Store irqvalues for use in the interrupt thread. */
+	rt2x00dev->irqvalue[0] = reg;
+
+	/* Disable interrupts, will be enabled again in the interrupt thread. */
+	rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+					      STATE_RADIO_IRQ_OFF_ISR);
+
+	return IRQ_WAKE_THREAD;
+}
+
 /*
  * Device probe functions.
  */
@@ -1554,9 +1577,8 @@
 	 * Check if the BBP tuning should be enabled.
 	 */
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
-
-	if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
-		__set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+	if (!rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
+		__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
 
 	/*
 	 * Read the RSSI <-> dBm offset information.
@@ -1861,7 +1883,8 @@
 	.remove_interface	= rt2x00mac_remove_interface,
 	.config			= rt2x00mac_config,
 	.configure_filter	= rt2x00mac_configure_filter,
-	.set_tim		= rt2x00mac_set_tim,
+	.sw_scan_start		= rt2x00mac_sw_scan_start,
+	.sw_scan_complete	= rt2x00mac_sw_scan_complete,
 	.get_stats		= rt2x00mac_get_stats,
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt2x00mac_conf_tx,
@@ -1872,6 +1895,7 @@
 
 static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
 	.irq_handler		= rt2500pci_interrupt,
+	.irq_handler_thread	= rt2500pci_interrupt_thread,
 	.probe_hw		= rt2500pci_probe_hw,
 	.initialize		= rt2x00pci_initialize,
 	.uninitialize		= rt2x00pci_uninitialize,
@@ -1883,7 +1907,6 @@
 	.reset_tuner		= rt2500pci_reset_tuner,
 	.link_tuner		= rt2500pci_link_tuner,
 	.write_tx_desc		= rt2500pci_write_tx_desc,
-	.write_tx_data		= rt2x00pci_write_tx_data,
 	.write_beacon		= rt2500pci_write_beacon,
 	.kick_tx_queue		= rt2500pci_kick_tx_queue,
 	.kill_tx_queue		= rt2500pci_kill_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 9ae96a6..cdaf93f 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -345,12 +345,20 @@
 				struct rt2x00lib_crypto *crypto,
 				struct ieee80211_key_conf *key)
 {
-	int timeout;
 	u32 mask;
 	u16 reg;
+	enum cipher curr_cipher;
 
 	if (crypto->cmd == SET_KEY) {
 		/*
+		 * Disallow to set WEP key other than with index 0,
+		 * it is known that not work at least on some hardware.
+		 * SW crypto will be used in that case.
+		 */
+		if (key->alg == ALG_WEP && key->keyidx != 0)
+			return -EOPNOTSUPP;
+
+		/*
 		 * Pairwise key will always be entry 0, but this
 		 * could collide with a shared key on the same
 		 * position...
@@ -358,6 +366,7 @@
 		mask = TXRX_CSR0_KEY_ID.bit_mask;
 
 		rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+		curr_cipher = rt2x00_get_field16(reg, TXRX_CSR0_ALGORITHM);
 		reg &= mask;
 
 		if (reg && reg == mask)
@@ -366,19 +375,17 @@
 		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 separately and use
-		 * rt2x00usb_vendor_request() to send the key to the hardware.
+		 * Hardware requires that all keys use the same cipher
+		 * (e.g. TKIP-only, AES-only, but not TKIP+AES).
+		 * If this is not the first key, compare the cipher with the
+		 * first one and fall back to SW crypto if not the same.
 		 */
-		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);
+		if (key->hw_key_idx > 0 && crypto->cipher != curr_cipher)
+			return -EOPNOTSUPP;
+
+		rt2500usb_register_multiwrite(rt2x00dev, KEY_ENTRY(key->hw_key_idx),
+					      crypto->key, sizeof(crypto->key));
 
 		/*
 		 * The driver does not support the IV/EIV generation
@@ -818,6 +825,7 @@
 	rt2500usb_register_write(rt2x00dev, MAC_CSR8, reg);
 
 	rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR0_ALGORITHM, CIPHER_NONE);
 	rt2x00_set_field16(&reg, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER);
 	rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, 0);
 	rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg);
@@ -1005,7 +1013,9 @@
 		rt2500usb_toggle_rx(rt2x00dev, state);
 		break;
 	case STATE_RADIO_IRQ_ON:
+	case STATE_RADIO_IRQ_ON_ISR:
 	case STATE_RADIO_IRQ_OFF:
+	case STATE_RADIO_IRQ_OFF_ISR:
 		/* No support, but no error either */
 		break;
 	case STATE_DEEP_SLEEP:
@@ -1034,7 +1044,7 @@
 				    struct txentry_desc *txdesc)
 {
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-	__le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
+	__le32 *txd = (__le32 *) skb->data;
 	u32 word;
 
 	/*
@@ -1080,6 +1090,7 @@
 	/*
 	 * Register descriptor details in skb frame descriptor.
 	 */
+	skbdesc->flags |= SKBDESC_DESC_IN_SKB;
 	skbdesc->desc = txd;
 	skbdesc->desc_len = TXD_DESC_SIZE;
 }
@@ -1108,9 +1119,20 @@
 	rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
 
 	/*
-	 * Take the descriptor in front of the skb into account.
+	 * Add space for the descriptor in front of the skb.
 	 */
 	skb_push(entry->skb, TXD_DESC_SIZE);
+	memset(entry->skb->data, 0, TXD_DESC_SIZE);
+
+	/*
+	 * Write the TX descriptor for the beacon.
+	 */
+	rt2500usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+	/*
+	 * Dump beacon to userspace through debugfs.
+	 */
+	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
 
 	/*
 	 * USB devices cannot blindly pass the skb->len as the
@@ -1460,13 +1482,6 @@
 		__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
 
 	/*
-	 * Check if the BBP tuning should be disabled.
-	 */
-	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
-	if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
-		__set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
-
-	/*
 	 * Read the RSSI <-> dBm offset information.
 	 */
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom);
@@ -1732,7 +1747,7 @@
 		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
 		__set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags);
 	}
-	__set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+	__set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
 
 	/*
 	 * Set the rssi offset.
@@ -1752,6 +1767,8 @@
 	.configure_filter	= rt2x00mac_configure_filter,
 	.set_tim		= rt2x00mac_set_tim,
 	.set_key		= rt2x00mac_set_key,
+	.sw_scan_start		= rt2x00mac_sw_scan_start,
+	.sw_scan_complete	= rt2x00mac_sw_scan_complete,
 	.get_stats		= rt2x00mac_get_stats,
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt2x00mac_conf_tx,
@@ -1767,8 +1784,8 @@
 	.rfkill_poll		= rt2500usb_rfkill_poll,
 	.link_stats		= rt2500usb_link_stats,
 	.reset_tuner		= rt2500usb_reset_tuner,
+	.watchdog		= rt2x00usb_watchdog,
 	.write_tx_desc		= rt2500usb_write_tx_desc,
-	.write_tx_data		= rt2x00usb_write_tx_data,
 	.write_beacon		= rt2500usb_write_beacon,
 	.get_tx_data_len	= rt2500usb_get_tx_data_len,
 	.kick_tx_queue		= rt2x00usb_kick_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 2aa0375..ed4ebcd 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -63,7 +63,6 @@
  */
 #define REV_RT2860C			0x0100
 #define REV_RT2860D			0x0101
-#define REV_RT2870D			0x0101
 #define REV_RT2872E			0x0200
 #define REV_RT3070E			0x0200
 #define REV_RT3070F			0x0201
@@ -75,7 +74,7 @@
  * Signal information.
  * Default offset is required for RSSI <-> dBm conversion.
  */
-#define DEFAULT_RSSI_OFFSET		120 /* FIXME */
+#define DEFAULT_RSSI_OFFSET		120
 
 /*
  * Register layout information.
@@ -99,6 +98,21 @@
  */
 
 /*
+ * E2PROM_CSR: PCI EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE: 0: 93c46, 1:93c66.
+ * LOAD_STATUS: 1:loading, 0:done.
+ */
+#define E2PROM_CSR			0x0004
+#define E2PROM_CSR_DATA_CLOCK		FIELD32(0x00000001)
+#define E2PROM_CSR_CHIP_SELECT		FIELD32(0x00000002)
+#define E2PROM_CSR_DATA_IN		FIELD32(0x00000004)
+#define E2PROM_CSR_DATA_OUT		FIELD32(0x00000008)
+#define E2PROM_CSR_TYPE			FIELD32(0x00000030)
+#define E2PROM_CSR_LOAD_STATUS		FIELD32(0x00000040)
+#define E2PROM_CSR_RELOAD		FIELD32(0x00000080)
+
+/*
  * OPT_14: Unknown register used by rt3xxx devices.
  */
 #define OPT_14_CSR			0x0114
@@ -322,6 +336,39 @@
 #define RX_DRX_IDX			0x029c
 
 /*
+ * USB_DMA_CFG
+ * RX_BULK_AGG_TIMEOUT: Rx Bulk Aggregation TimeOut in unit of 33ns.
+ * RX_BULK_AGG_LIMIT: Rx Bulk Aggregation Limit in unit of 256 bytes.
+ * PHY_CLEAR: phy watch dog enable.
+ * TX_CLEAR: Clear USB DMA TX path.
+ * TXOP_HALT: Halt TXOP count down when TX buffer is full.
+ * RX_BULK_AGG_EN: Enable Rx Bulk Aggregation.
+ * RX_BULK_EN: Enable USB DMA Rx.
+ * TX_BULK_EN: Enable USB DMA Tx.
+ * EP_OUT_VALID: OUT endpoint data valid.
+ * RX_BUSY: USB DMA RX FSM busy.
+ * TX_BUSY: USB DMA TX FSM busy.
+ */
+#define USB_DMA_CFG			0x02a0
+#define USB_DMA_CFG_RX_BULK_AGG_TIMEOUT	FIELD32(0x000000ff)
+#define USB_DMA_CFG_RX_BULK_AGG_LIMIT	FIELD32(0x0000ff00)
+#define USB_DMA_CFG_PHY_CLEAR		FIELD32(0x00010000)
+#define USB_DMA_CFG_TX_CLEAR		FIELD32(0x00080000)
+#define USB_DMA_CFG_TXOP_HALT		FIELD32(0x00100000)
+#define USB_DMA_CFG_RX_BULK_AGG_EN	FIELD32(0x00200000)
+#define USB_DMA_CFG_RX_BULK_EN		FIELD32(0x00400000)
+#define USB_DMA_CFG_TX_BULK_EN		FIELD32(0x00800000)
+#define USB_DMA_CFG_EP_OUT_VALID	FIELD32(0x3f000000)
+#define USB_DMA_CFG_RX_BUSY		FIELD32(0x40000000)
+#define USB_DMA_CFG_TX_BUSY		FIELD32(0x80000000)
+
+/*
+ * US_CYC_CNT
+ */
+#define US_CYC_CNT			0x02a4
+#define US_CYC_CNT_CLOCK_CYCLE		FIELD32(0x000000ff)
+
+/*
  * PBF_SYS_CTRL
  * HOST_RAM_WRITE: enable Host program ram write selection
  */
@@ -672,14 +719,20 @@
 #define TBTT_TIMER			0x1124
 
 /*
- * INT_TIMER_CFG:
+ * INT_TIMER_CFG: timer configuration
+ * PRE_TBTT_TIMER: leadtime to tbtt for pretbtt interrupt in units of 1/16 TU
+ * GP_TIMER: period of general purpose timer in units of 1/16 TU
  */
 #define INT_TIMER_CFG			0x1128
+#define INT_TIMER_CFG_PRE_TBTT_TIMER	FIELD32(0x0000ffff)
+#define INT_TIMER_CFG_GP_TIMER		FIELD32(0xffff0000)
 
 /*
  * INT_TIMER_EN: GP-timer and pre-tbtt Int enable
  */
 #define INT_TIMER_EN			0x112c
+#define INT_TIMER_EN_PRE_TBTT_TIMER	FIELD32(0x00000001)
+#define INT_TIMER_EN_GP_TIMER		FIELD32(0x00000002)
 
 /*
  * CH_IDLE_STA: channel idle time
@@ -756,6 +809,18 @@
 #define EDCA_TID_AC_MAP			0x1310
 
 /*
+ * TX_PWR_CFG:
+ */
+#define TX_PWR_CFG_RATE0		FIELD32(0x0000000f)
+#define TX_PWR_CFG_RATE1		FIELD32(0x000000f0)
+#define TX_PWR_CFG_RATE2		FIELD32(0x00000f00)
+#define TX_PWR_CFG_RATE3		FIELD32(0x0000f000)
+#define TX_PWR_CFG_RATE4		FIELD32(0x000f0000)
+#define TX_PWR_CFG_RATE5		FIELD32(0x00f00000)
+#define TX_PWR_CFG_RATE6		FIELD32(0x0f000000)
+#define TX_PWR_CFG_RATE7		FIELD32(0xf0000000)
+
+/*
  * TX_PWR_CFG_0:
  */
 #define TX_PWR_CFG_0			0x1314
@@ -1370,17 +1435,17 @@
 struct mac_wcid_entry {
 	u8 mac[6];
 	u8 reserved[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct hw_key_entry {
 	u8 key[16];
 	u8 tx_mic[8];
 	u8 rx_mic[8];
-} __attribute__ ((packed));
+} __packed;
 
 struct mac_iveiv_entry {
 	u8 iv[8];
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * MAC_WCID_ATTRIBUTE:
@@ -1389,6 +1454,10 @@
 #define MAC_WCID_ATTRIBUTE_CIPHER	FIELD32(0x0000000e)
 #define MAC_WCID_ATTRIBUTE_BSS_IDX	FIELD32(0x00000070)
 #define MAC_WCID_ATTRIBUTE_RX_WIUDF	FIELD32(0x00000380)
+#define MAC_WCID_ATTRIBUTE_CIPHER_EXT	FIELD32(0x00000400)
+#define MAC_WCID_ATTRIBUTE_BSS_IDX_EXT	FIELD32(0x00000800)
+#define MAC_WCID_ATTRIBUTE_WAPI_MCBC	FIELD32(0x00008000)
+#define MAC_WCID_ATTRIBUTE_WAPI_KEY_IDX	FIELD32(0xff000000)
 
 /*
  * SHARED_KEY_MODE:
@@ -1510,7 +1579,9 @@
  */
 
 /*
- * BBP 1: TX Antenna
+ * BBP 1: TX Antenna & Power
+ * POWER: 0 - normal, 1 - drop tx power by 6dBm, 2 - drop tx power by 12dBm,
+ *	3 - increase tx power by 6dBm
  */
 #define BBP1_TX_POWER			FIELD8(0x07)
 #define BBP1_TX_ANTENNA			FIELD8(0x18)
@@ -1800,9 +1871,15 @@
 #define EEPROM_TXPOWER_A_2		FIELD16(0xff00)
 
 /*
- * EEPROM TXpower byrate: 20MHZ power
+ * EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode
  */
 #define EEPROM_TXPOWER_BYRATE		0x006f
+#define EEPROM_TXPOWER_BYRATE_SIZE	9
+
+#define EEPROM_TXPOWER_BYRATE_RATE0	FIELD16(0x000f)
+#define EEPROM_TXPOWER_BYRATE_RATE1	FIELD16(0x00f0)
+#define EEPROM_TXPOWER_BYRATE_RATE2	FIELD16(0x0f00)
+#define EEPROM_TXPOWER_BYRATE_RATE3	FIELD16(0xf000)
 
 /*
  * EEPROM BBP.
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index db4250d..b66e0fd 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -1,9 +1,9 @@
 /*
+	Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
 	Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
 	Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com>
 
 	Based on the original rt2800pci.c and rt2800usb.c.
-	  Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
 	  Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
 	  Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
 	  Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
@@ -33,21 +33,14 @@
 	Abstract: rt2800 generic device routines.
  */
 
+#include <linux/crc-ccitt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 
 #include "rt2x00.h"
-#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
-#include "rt2x00usb.h"
-#endif
 #include "rt2800lib.h"
 #include "rt2800.h"
-#include "rt2800usb.h"
-
-MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("rt2800 library");
-MODULE_LICENSE("GPL");
 
 /*
  * Register access.
@@ -107,8 +100,7 @@
 		rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
 		rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
 		rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 0);
-		if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
-			rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
+		rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
 
 		rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);
 	}
@@ -136,8 +128,7 @@
 		rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
 		rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
 		rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 1);
-		if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
-			rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
+		rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
 
 		rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);
 
@@ -282,9 +273,162 @@
 }
 EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
 
-void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc)
+static bool rt2800_check_firmware_crc(const u8 *data, const size_t len)
 {
-	__le32 *txwi = (__le32 *)(skb->data - TXWI_DESC_SIZE);
+	u16 fw_crc;
+	u16 crc;
+
+	/*
+	 * The last 2 bytes in the firmware array are the crc checksum itself,
+	 * this means that we should never pass those 2 bytes to the crc
+	 * algorithm.
+	 */
+	fw_crc = (data[len - 2] << 8 | data[len - 1]);
+
+	/*
+	 * Use the crc ccitt algorithm.
+	 * This will return the same value as the legacy driver which
+	 * used bit ordering reversion on the both the firmware bytes
+	 * before input input as well as on the final output.
+	 * Obviously using crc ccitt directly is much more efficient.
+	 */
+	crc = crc_ccitt(~0, data, len - 2);
+
+	/*
+	 * There is a small difference between the crc-itu-t + bitrev and
+	 * the crc-ccitt crc calculation. In the latter method the 2 bytes
+	 * will be swapped, use swab16 to convert the crc to the correct
+	 * value.
+	 */
+	crc = swab16(crc);
+
+	return fw_crc == crc;
+}
+
+int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
+			  const u8 *data, const size_t len)
+{
+	size_t offset = 0;
+	size_t fw_len;
+	bool multiple;
+
+	/*
+	 * PCI(e) & SOC devices require firmware with a length
+	 * of 8kb. USB devices require firmware files with a length
+	 * of 4kb. Certain USB chipsets however require different firmware,
+	 * which Ralink only provides attached to the original firmware
+	 * file. Thus for USB devices, firmware files have a length
+	 * which is a multiple of 4kb.
+	 */
+	if (rt2x00_is_usb(rt2x00dev)) {
+		fw_len = 4096;
+		multiple = true;
+	} else {
+		fw_len = 8192;
+		multiple = true;
+	}
+
+	/*
+	 * Validate the firmware length
+	 */
+	if (len != fw_len && (!multiple || (len % fw_len) != 0))
+		return FW_BAD_LENGTH;
+
+	/*
+	 * Check if the chipset requires one of the upper parts
+	 * of the firmware.
+	 */
+	if (rt2x00_is_usb(rt2x00dev) &&
+	    !rt2x00_rt(rt2x00dev, RT2860) &&
+	    !rt2x00_rt(rt2x00dev, RT2872) &&
+	    !rt2x00_rt(rt2x00dev, RT3070) &&
+	    ((len / fw_len) == 1))
+		return FW_BAD_VERSION;
+
+	/*
+	 * 8kb firmware files must be checked as if it were
+	 * 2 separate firmware files.
+	 */
+	while (offset < len) {
+		if (!rt2800_check_firmware_crc(data + offset, fw_len))
+			return FW_BAD_CRC;
+
+		offset += fw_len;
+	}
+
+	return FW_OK;
+}
+EXPORT_SYMBOL_GPL(rt2800_check_firmware);
+
+int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
+			 const u8 *data, const size_t len)
+{
+	unsigned int i;
+	u32 reg;
+
+	/*
+	 * Wait for stable hardware.
+	 */
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
+		if (reg && reg != ~0)
+			break;
+		msleep(1);
+	}
+
+	if (i == REGISTER_BUSY_COUNT) {
+		ERROR(rt2x00dev, "Unstable hardware.\n");
+		return -EBUSY;
+	}
+
+	if (rt2x00_is_pci(rt2x00dev))
+		rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
+
+	/*
+	 * Disable DMA, will be reenabled later when enabling
+	 * the radio.
+	 */
+	rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
+	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
+	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
+	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
+	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+	rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+	/*
+	 * Write firmware to the device.
+	 */
+	rt2800_drv_write_firmware(rt2x00dev, data, len);
+
+	/*
+	 * Wait for device to stabilize.
+	 */
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
+		if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
+			break;
+		msleep(1);
+	}
+
+	if (i == REGISTER_BUSY_COUNT) {
+		ERROR(rt2x00dev, "PBF system register not ready.\n");
+		return -EBUSY;
+	}
+
+	/*
+	 * Initialize firmware.
+	 */
+	rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+	rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+	msleep(1);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2800_load_firmware);
+
+void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
+{
 	u32 word;
 
 	/*
@@ -336,9 +480,53 @@
 }
 EXPORT_SYMBOL_GPL(rt2800_write_txwi);
 
-void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc)
+static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2)
 {
-	__le32 *rxwi = (__le32 *) skb->data;
+	int rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0);
+	int rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1);
+	int rssi2 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI2);
+	u16 eeprom;
+	u8 offset0;
+	u8 offset1;
+	u8 offset2;
+
+	if (rt2x00dev->rx_status.band == IEEE80211_BAND_2GHZ) {
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom);
+		offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0);
+		offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1);
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom);
+		offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_OFFSET2);
+	} else {
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &eeprom);
+		offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET0);
+		offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET1);
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom);
+		offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_OFFSET2);
+	}
+
+	/*
+	 * Convert the value from the descriptor into the RSSI value
+	 * If the value in the descriptor is 0, it is considered invalid
+	 * and the default (extremely low) rssi value is assumed
+	 */
+	rssi0 = (rssi0) ? (-12 - offset0 - rt2x00dev->lna_gain - rssi0) : -128;
+	rssi1 = (rssi1) ? (-12 - offset1 - rt2x00dev->lna_gain - rssi1) : -128;
+	rssi2 = (rssi2) ? (-12 - offset2 - rt2x00dev->lna_gain - rssi2) : -128;
+
+	/*
+	 * mac80211 only accepts a single RSSI value. Calculating the
+	 * average doesn't deliver a fair answer either since -60:-60 would
+	 * be considered equally good as -50:-70 while the second is the one
+	 * which gives less energy...
+	 */
+	rssi0 = max(rssi0, rssi1);
+	return max(rssi0, rssi2);
+}
+
+void rt2800_process_rxwi(struct queue_entry *entry,
+			 struct rxdone_entry_desc *rxdesc)
+{
+	__le32 *rxwi = (__le32 *) entry->skb->data;
 	u32 word;
 
 	rt2x00_desc_read(rxwi, 0, &word);
@@ -369,17 +557,93 @@
 
 	rt2x00_desc_read(rxwi, 2, &word);
 
-	rxdesc->rssi =
-	    (rt2x00_get_field32(word, RXWI_W2_RSSI0) +
-	     rt2x00_get_field32(word, RXWI_W2_RSSI1)) / 2;
+	/*
+	 * Convert descriptor AGC value to RSSI value.
+	 */
+	rxdesc->rssi = rt2800_agc_to_rssi(entry->queue->rt2x00dev, word);
 
 	/*
 	 * Remove RXWI descriptor from start of buffer.
 	 */
-	skb_pull(skb, RXWI_DESC_SIZE);
+	skb_pull(entry->skb, RXWI_DESC_SIZE);
 }
 EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
 
+void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
+{
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+	unsigned int beacon_base;
+	u32 reg;
+
+	/*
+	 * Disable beaconing while we are reloading the beacon data,
+	 * otherwise we might be sending out invalid data.
+	 */
+	rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+	rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+	rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+	/*
+	 * Add space for the TXWI in front of the skb.
+	 */
+	skb_push(entry->skb, TXWI_DESC_SIZE);
+	memset(entry->skb, 0, TXWI_DESC_SIZE);
+
+	/*
+	 * Register descriptor details in skb frame descriptor.
+	 */
+	skbdesc->flags |= SKBDESC_DESC_IN_SKB;
+	skbdesc->desc = entry->skb->data;
+	skbdesc->desc_len = TXWI_DESC_SIZE;
+
+	/*
+	 * Add the TXWI for the beacon to the skb.
+	 */
+	rt2800_write_txwi((__le32 *)entry->skb->data, txdesc);
+
+	/*
+	 * Dump beacon to userspace through debugfs.
+	 */
+	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
+
+	/*
+	 * Write entire beacon with TXWI to register.
+	 */
+	beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
+	rt2800_register_multiwrite(rt2x00dev, beacon_base,
+				   entry->skb->data, entry->skb->len);
+
+	/*
+	 * Enable beaconing again.
+	 */
+	rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+	rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+	rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+	rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+	/*
+	 * Clean up beacon skb.
+	 */
+	dev_kfree_skb_any(entry->skb);
+	entry->skb = NULL;
+}
+EXPORT_SYMBOL_GPL(rt2800_write_beacon);
+
+static void inline rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev,
+				       unsigned int beacon_base)
+{
+	int i;
+
+	/*
+	 * For the Beacon base registers we only need to clear
+	 * the whole TXWI which (when set to 0) will invalidate
+	 * the entire beacon.
+	 */
+	for (i = 0; i < TXWI_DESC_SIZE; i += sizeof(__le32))
+		rt2800_register_write(rt2x00dev, beacon_base + i, 0);
+}
+
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 const struct rt2x00debug rt2800_rt2x00debug = {
 	.owner	= THIS_MODULE,
@@ -502,15 +766,28 @@
 
 	offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx);
 
-	rt2800_register_read(rt2x00dev, offset, &reg);
-	rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_KEYTAB,
-			   !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE));
-	rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER,
-			   (crypto->cmd == SET_KEY) * crypto->cipher);
-	rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX,
-			   (crypto->cmd == SET_KEY) * crypto->bssidx);
-	rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher);
-	rt2800_register_write(rt2x00dev, offset, reg);
+	if (crypto->cmd == SET_KEY) {
+		rt2800_register_read(rt2x00dev, offset, &reg);
+		rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_KEYTAB,
+				   !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE));
+		/*
+		 * Both the cipher as the BSS Idx numbers are split in a main
+		 * value of 3 bits, and a extended field for adding one additional
+		 * bit to the value.
+		 */
+		rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER,
+				   (crypto->cipher & 0x7));
+		rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER_EXT,
+				   (crypto->cipher & 0x8) >> 3);
+		rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX,
+				   (crypto->bssidx & 0x7));
+		rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT,
+				   (crypto->bssidx & 0x8) >> 3);
+		rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher);
+		rt2800_register_write(rt2x00dev, offset, reg);
+	} else {
+		rt2800_register_write(rt2x00dev, offset, 0);
+	}
 
 	offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
 
@@ -668,19 +945,14 @@
 void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
 			struct rt2x00intf_conf *conf, const unsigned int flags)
 {
-	unsigned int beacon_base;
 	u32 reg;
 
 	if (flags & CONFIG_UPDATE_TYPE) {
 		/*
 		 * Clear current synchronisation setup.
-		 * For the Beacon base registers we only need to clear
-		 * the first byte since that byte contains the VALID and OWNER
-		 * bits which (when set to 0) will invalidate the entire beacon.
 		 */
-		beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
-		rt2800_register_write(rt2x00dev, beacon_base, 0);
-
+		rt2800_clear_beacon(rt2x00dev,
+				    HW_BEACON_OFFSET(intf->beacon->entry_idx));
 		/*
 		 * Enable synchronisation.
 		 */
@@ -688,8 +960,18 @@
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, conf->sync);
 		rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE,
-				   (conf->sync == TSF_SYNC_BEACON));
+				   (conf->sync == TSF_SYNC_ADHOC ||
+				    conf->sync == TSF_SYNC_AP_NONE));
 		rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+		/*
+		 * Enable pre tbtt interrupt for beaconing modes
+		 */
+		rt2800_register_read(rt2x00dev, INT_TIMER_EN, &reg);
+		rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER,
+				   (conf->sync == TSF_SYNC_AP_NONE));
+		rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
+
 	}
 
 	if (flags & CONFIG_UPDATE_MAC) {
@@ -703,8 +985,8 @@
 
 	if (flags & CONFIG_UPDATE_BSSID) {
 		reg = le32_to_cpu(conf->bssid[1]);
-		rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 0);
-		rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 0);
+		rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
+		rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
 		conf->bssid[1] = cpu_to_le32(reg);
 
 		rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0,
@@ -762,14 +1044,12 @@
 	switch ((int)ant->tx) {
 	case 1:
 		rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
-		if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
-			rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);
 		break;
 	case 2:
 		rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
 		break;
 	case 3:
-		/* Do nothing */
+		rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
 		break;
 	}
 
@@ -1016,66 +1296,115 @@
 }
 
 static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
-				  const int txpower)
+				  const int max_txpower)
 {
+	u8 txpower;
+	u8 max_value = (u8)max_txpower;
+	u16 eeprom;
+	int i;
 	u32 reg;
-	u32 value = TXPOWER_G_TO_DEV(txpower);
 	u8 r1;
+	u32 offset;
 
+	/*
+	 * set to normal tx power mode: +/- 0dBm
+	 */
 	rt2800_bbp_read(rt2x00dev, 1, &r1);
-	rt2x00_set_field8(&reg, BBP1_TX_POWER, 0);
+	rt2x00_set_field8(&r1, BBP1_TX_POWER, 0);
 	rt2800_bbp_write(rt2x00dev, 1, r1);
 
-	rt2800_register_read(rt2x00dev, TX_PWR_CFG_0, &reg);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_0_1MBS, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_0_2MBS, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_0_55MBS, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_0_11MBS, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_0_6MBS, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_0_9MBS, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_0_12MBS, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_0_18MBS, value);
-	rt2800_register_write(rt2x00dev, TX_PWR_CFG_0, reg);
+	/*
+	 * The eeprom contains the tx power values for each rate. These
+	 * values map to 100% tx power. Each 16bit word contains four tx
+	 * power values and the order is the same as used in the TX_PWR_CFG
+	 * registers.
+	 */
+	offset = TX_PWR_CFG_0;
 
-	rt2800_register_read(rt2x00dev, TX_PWR_CFG_1, &reg);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_1_24MBS, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_1_36MBS, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_1_48MBS, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_1_54MBS, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS0, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS1, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS2, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS3, value);
-	rt2800_register_write(rt2x00dev, TX_PWR_CFG_1, reg);
+	for (i = 0; i < EEPROM_TXPOWER_BYRATE_SIZE; i += 2) {
+		/* just to be safe */
+		if (offset > TX_PWR_CFG_4)
+			break;
 
-	rt2800_register_read(rt2x00dev, TX_PWR_CFG_2, &reg);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS4, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS5, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS6, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS7, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS8, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS9, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS10, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS11, value);
-	rt2800_register_write(rt2x00dev, TX_PWR_CFG_2, reg);
+		rt2800_register_read(rt2x00dev, offset, &reg);
 
-	rt2800_register_read(rt2x00dev, TX_PWR_CFG_3, &reg);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS12, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS13, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS14, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS15, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN1, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN2, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN3, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN4, value);
-	rt2800_register_write(rt2x00dev, TX_PWR_CFG_3, reg);
+		/* read the next four txpower values */
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i,
+				   &eeprom);
 
-	rt2800_register_read(rt2x00dev, TX_PWR_CFG_4, &reg);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN5, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN6, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN7, value);
-	rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN8, value);
-	rt2800_register_write(rt2x00dev, TX_PWR_CFG_4, reg);
+		/* TX_PWR_CFG_0: 1MBS, TX_PWR_CFG_1: 24MBS,
+		 * TX_PWR_CFG_2: MCS4, TX_PWR_CFG_3: MCS12,
+		 * TX_PWR_CFG_4: unknown */
+		txpower = rt2x00_get_field16(eeprom,
+					     EEPROM_TXPOWER_BYRATE_RATE0);
+		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE0,
+				   min(txpower, max_value));
+
+		/* TX_PWR_CFG_0: 2MBS, TX_PWR_CFG_1: 36MBS,
+		 * TX_PWR_CFG_2: MCS5, TX_PWR_CFG_3: MCS13,
+		 * TX_PWR_CFG_4: unknown */
+		txpower = rt2x00_get_field16(eeprom,
+					     EEPROM_TXPOWER_BYRATE_RATE1);
+		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE1,
+				   min(txpower, max_value));
+
+		/* TX_PWR_CFG_0: 55MBS, TX_PWR_CFG_1: 48MBS,
+		 * TX_PWR_CFG_2: MCS6,  TX_PWR_CFG_3: MCS14,
+		 * TX_PWR_CFG_4: unknown */
+		txpower = rt2x00_get_field16(eeprom,
+					     EEPROM_TXPOWER_BYRATE_RATE2);
+		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE2,
+				   min(txpower, max_value));
+
+		/* TX_PWR_CFG_0: 11MBS, TX_PWR_CFG_1: 54MBS,
+		 * TX_PWR_CFG_2: MCS7,  TX_PWR_CFG_3: MCS15,
+		 * TX_PWR_CFG_4: unknown */
+		txpower = rt2x00_get_field16(eeprom,
+					     EEPROM_TXPOWER_BYRATE_RATE3);
+		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE3,
+				   min(txpower, max_value));
+
+		/* read the next four txpower values */
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i + 1,
+				   &eeprom);
+
+		/* TX_PWR_CFG_0: 6MBS, TX_PWR_CFG_1: MCS0,
+		 * TX_PWR_CFG_2: MCS8, TX_PWR_CFG_3: unknown,
+		 * TX_PWR_CFG_4: unknown */
+		txpower = rt2x00_get_field16(eeprom,
+					     EEPROM_TXPOWER_BYRATE_RATE0);
+		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE4,
+				   min(txpower, max_value));
+
+		/* TX_PWR_CFG_0: 9MBS, TX_PWR_CFG_1: MCS1,
+		 * TX_PWR_CFG_2: MCS9, TX_PWR_CFG_3: unknown,
+		 * TX_PWR_CFG_4: unknown */
+		txpower = rt2x00_get_field16(eeprom,
+					     EEPROM_TXPOWER_BYRATE_RATE1);
+		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE5,
+				   min(txpower, max_value));
+
+		/* TX_PWR_CFG_0: 12MBS, TX_PWR_CFG_1: MCS2,
+		 * TX_PWR_CFG_2: MCS10, TX_PWR_CFG_3: unknown,
+		 * TX_PWR_CFG_4: unknown */
+		txpower = rt2x00_get_field16(eeprom,
+					     EEPROM_TXPOWER_BYRATE_RATE2);
+		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE6,
+				   min(txpower, max_value));
+
+		/* TX_PWR_CFG_0: 18MBS, TX_PWR_CFG_1: MCS3,
+		 * TX_PWR_CFG_2: MCS11, TX_PWR_CFG_3: unknown,
+		 * TX_PWR_CFG_4: unknown */
+		txpower = rt2x00_get_field16(eeprom,
+					     EEPROM_TXPOWER_BYRATE_RATE3);
+		rt2x00_set_field32(&reg, TX_PWR_CFG_RATE7,
+				   min(txpower, max_value));
+
+		rt2800_register_write(rt2x00dev, offset, reg);
+
+		/* next TX_PWR_CFG register */
+		offset += 4;
+	}
 }
 
 static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev,
@@ -1212,6 +1541,7 @@
 	u32 reg;
 	u16 eeprom;
 	unsigned int i;
+	int ret;
 
 	rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
 	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
@@ -1221,59 +1551,9 @@
 	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
 	rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
 
-	if (rt2x00_is_usb(rt2x00dev)) {
-		/*
-		 * Wait until BBP and RF are ready.
-		 */
-		for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-			rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-			if (reg && reg != ~0)
-				break;
-			msleep(1);
-		}
-
-		if (i == REGISTER_BUSY_COUNT) {
-			ERROR(rt2x00dev, "Unstable hardware.\n");
-			return -EBUSY;
-		}
-
-		rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
-		rt2800_register_write(rt2x00dev, PBF_SYS_CTRL,
-				      reg & ~0x00002000);
-	} else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) {
-		/*
-		 * Reset DMA indexes
-		 */
-		rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
-		rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
-		rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
-		rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
-		rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
-		rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
-		rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
-		rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
-		rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
-
-		rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
-		rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
-
-		rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
-	}
-
-	rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
-	rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
-	rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
-	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
-	if (rt2x00_is_usb(rt2x00dev)) {
-		rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
-#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
-		rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
-					    USB_MODE_RESET, REGISTER_TIMEOUT);
-#endif
-	}
-
-	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+	ret = rt2800_drv_init_registers(rt2x00dev);
+	if (ret)
+		return ret;
 
 	rt2800_register_read(rt2x00dev, BCN_OFFSET0, &reg);
 	rt2x00_set_field32(&reg, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */
@@ -1295,7 +1575,7 @@
 	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
 
 	rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
-	rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL, 0);
+	rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL, 1600);
 	rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
 	rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, 0);
 	rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
@@ -1328,7 +1608,6 @@
 		} else {
 			rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
 		}
-		rt2800_register_write(rt2x00dev, TX_SW_CFG2, reg);
 	} else if (rt2x00_rt(rt2x00dev, RT3070)) {
 		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
 
@@ -1339,6 +1618,10 @@
 			rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
 			rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
 		}
+	} else if (rt2800_is_305x_soc(rt2x00dev)) {
+		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
+		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
+		rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x0000001f);
 	} else {
 		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000);
 		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
@@ -1546,23 +1829,20 @@
 
 	/*
 	 * Clear all beacons
-	 * For the Beacon base registers we only need to clear
-	 * the first byte since that byte contains the VALID and OWNER
-	 * bits which (when set to 0) will invalidate the entire beacon.
 	 */
-	rt2800_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
-	rt2800_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
-	rt2800_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
-	rt2800_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
-	rt2800_register_write(rt2x00dev, HW_BEACON_BASE4, 0);
-	rt2800_register_write(rt2x00dev, HW_BEACON_BASE5, 0);
-	rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0);
-	rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0);
+	rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE0);
+	rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE1);
+	rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE2);
+	rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE3);
+	rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE4);
+	rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE5);
+	rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE6);
+	rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE7);
 
 	if (rt2x00_is_usb(rt2x00dev)) {
-		rt2800_register_read(rt2x00dev, USB_CYC_CFG, &reg);
-		rt2x00_set_field32(&reg, USB_CYC_CFG_CLOCK_CYCLE, 30);
-		rt2800_register_write(rt2x00dev, USB_CYC_CFG, reg);
+		rt2800_register_read(rt2x00dev, US_CYC_CNT, &reg);
+		rt2x00_set_field32(&reg, US_CYC_CNT_CLOCK_CYCLE, 30);
+		rt2800_register_write(rt2x00dev, US_CYC_CNT, reg);
 	}
 
 	rt2800_register_read(rt2x00dev, HT_FBK_CFG0, &reg);
@@ -1617,6 +1897,13 @@
 	rt2800_register_read(rt2x00dev, TX_STA_CNT1, &reg);
 	rt2800_register_read(rt2x00dev, TX_STA_CNT2, &reg);
 
+	/*
+	 * Setup leadtime for pre tbtt interrupt to 6ms
+	 */
+	rt2800_register_read(rt2x00dev, INT_TIMER_CFG, &reg);
+	rt2x00_set_field32(&reg, INT_TIMER_CFG_PRE_TBTT_TIMER, 6 << 4);
+	rt2800_register_write(rt2x00dev, INT_TIMER_CFG, reg);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rt2800_init_registers);
@@ -1706,8 +1993,7 @@
 	rt2800_bbp_write(rt2x00dev, 82, 0x62);
 	rt2800_bbp_write(rt2x00dev, 83, 0x6a);
 
-	if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D) ||
-	    rt2x00_rt_rev(rt2x00dev, RT2870, REV_RT2870D))
+	if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D))
 		rt2800_bbp_write(rt2x00dev, 84, 0x19);
 	else
 		rt2800_bbp_write(rt2x00dev, 84, 0x99);
@@ -2013,8 +2299,7 @@
 	if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
 	    rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
 	    rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
-		if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
+		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
 			rt2x00_set_field8(&rfcsr, RFCSR17_R, 1);
 	}
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &eeprom);
@@ -2147,7 +2432,6 @@
 		rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
 		EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
 	} else if (rt2x00_rt(rt2x00dev, RT2860) ||
-		   rt2x00_rt(rt2x00dev, RT2870) ||
 		   rt2x00_rt(rt2x00dev, RT2872)) {
 		/*
 		 * There is a max of 2 RX streams for RT28x0 series
@@ -2169,6 +2453,8 @@
 		rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0);
 		rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0);
 		rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0);
+		rt2x00_set_field16(&word, EEPROM_NIC_ANT_DIVERSITY, 0);
+		rt2x00_set_field16(&word, EEPROM_NIC_DAC_TEST, 0);
 		rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
 		EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
 	}
@@ -2176,6 +2462,10 @@
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
 	if ((word & 0x00ff) == 0x00ff) {
 		rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
+		EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+	}
+	if ((word & 0xff00) == 0xff00) {
 		rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE,
 				   LED_MODE_TXRX_ACTIVITY);
 		rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);
@@ -2183,7 +2473,7 @@
 		rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555);
 		rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221);
 		rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8);
-		EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+		EEPROM(rt2x00dev, "Led Mode: 0x%04x\n", word);
 	}
 
 	/*
@@ -2251,7 +2541,6 @@
 			value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
 
 	if (!rt2x00_rt(rt2x00dev, RT2860) &&
-	    !rt2x00_rt(rt2x00dev, RT2870) &&
 	    !rt2x00_rt(rt2x00dev, RT2872) &&
 	    !rt2x00_rt(rt2x00dev, RT2883) &&
 	    !rt2x00_rt(rt2x00dev, RT3070) &&
@@ -2484,13 +2773,26 @@
 	    IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
 	    IEEE80211_HW_SIGNAL_DBM |
 	    IEEE80211_HW_SUPPORTS_PS |
-	    IEEE80211_HW_PS_NULLFUNC_STACK;
+	    IEEE80211_HW_PS_NULLFUNC_STACK |
+	    IEEE80211_HW_AMPDU_AGGREGATION;
 
 	SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
 	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
 				rt2x00_eeprom_addr(rt2x00dev,
 						   EEPROM_MAC_ADDR_0));
 
+	/*
+	 * As rt2800 has a global fallback table we cannot specify
+	 * more then one tx rate per frame but since the hw will
+	 * try several rates (based on the fallback table) we should
+	 * still initialize max_rates to the maximum number of rates
+	 * we are going to try. Otherwise mac80211 will truncate our
+	 * reported tx rates and the rc algortihm will end up with
+	 * incorrect data.
+	 */
+	rt2x00dev->hw->max_rates = 7;
+	rt2x00dev->hw->max_rate_tries = 1;
+
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
 
 	/*
@@ -2528,16 +2830,19 @@
 	else
 		spec->ht.ht_supported = false;
 
-	/*
-	 * Don't set IEEE80211_HT_CAP_SUP_WIDTH_20_40 for now as it causes
-	 * reception problems with HT40 capable 11n APs
-	 */
 	spec->ht.cap =
+	    IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
 	    IEEE80211_HT_CAP_GRN_FLD |
 	    IEEE80211_HT_CAP_SGI_20 |
-	    IEEE80211_HT_CAP_SGI_40 |
-	    IEEE80211_HT_CAP_TX_STBC |
-	    IEEE80211_HT_CAP_RX_STBC;
+	    IEEE80211_HT_CAP_SGI_40;
+
+	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) >= 2)
+		spec->ht.cap |= IEEE80211_HT_CAP_TX_STBC;
+
+	spec->ht.cap |=
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) <<
+		IEEE80211_HT_CAP_RX_STBC_SHIFT;
+
 	spec->ht.ampdu_factor = 3;
 	spec->ht.ampdu_density = 4;
 	spec->ht.mcs.tx_params =
@@ -2591,8 +2896,8 @@
 /*
  * IEEE80211 stack callback functions.
  */
-static void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx,
-				u32 *iv32, u16 *iv16)
+void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
+			 u16 *iv16)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct mac_iveiv_entry iveiv_entry;
@@ -2605,8 +2910,9 @@
 	memcpy(iv16, &iveiv_entry.iv[0], sizeof(*iv16));
 	memcpy(iv32, &iveiv_entry.iv[4], sizeof(*iv32));
 }
+EXPORT_SYMBOL_GPL(rt2800_get_tkip_seq);
 
-static int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	u32 reg;
@@ -2642,9 +2948,10 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold);
 
-static int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
-			  const struct ieee80211_tx_queue_params *params)
+int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
+		   const struct ieee80211_tx_queue_params *params)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct data_queue *queue;
@@ -2709,8 +3016,9 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(rt2800_conf_tx);
 
-static u64 rt2800_get_tsf(struct ieee80211_hw *hw)
+u64 rt2800_get_tsf(struct ieee80211_hw *hw)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	u64 tsf;
@@ -2723,23 +3031,37 @@
 
 	return tsf;
 }
+EXPORT_SYMBOL_GPL(rt2800_get_tsf);
 
-const struct ieee80211_ops rt2800_mac80211_ops = {
-	.tx			= rt2x00mac_tx,
-	.start			= rt2x00mac_start,
-	.stop			= rt2x00mac_stop,
-	.add_interface		= rt2x00mac_add_interface,
-	.remove_interface	= rt2x00mac_remove_interface,
-	.config			= rt2x00mac_config,
-	.configure_filter	= rt2x00mac_configure_filter,
-	.set_tim		= rt2x00mac_set_tim,
-	.set_key		= rt2x00mac_set_key,
-	.get_stats		= rt2x00mac_get_stats,
-	.get_tkip_seq		= rt2800_get_tkip_seq,
-	.set_rts_threshold	= rt2800_set_rts_threshold,
-	.bss_info_changed	= rt2x00mac_bss_info_changed,
-	.conf_tx		= rt2800_conf_tx,
-	.get_tsf		= rt2800_get_tsf,
-	.rfkill_poll		= rt2x00mac_rfkill_poll,
-};
-EXPORT_SYMBOL_GPL(rt2800_mac80211_ops);
+int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+			enum ieee80211_ampdu_mlme_action action,
+			struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+	int ret = 0;
+
+	switch (action) {
+	case IEEE80211_AMPDU_RX_START:
+	case IEEE80211_AMPDU_RX_STOP:
+		/* we don't support RX aggregation yet */
+		ret = -ENOTSUPP;
+		break;
+	case IEEE80211_AMPDU_TX_START:
+		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		break;
+	case IEEE80211_AMPDU_TX_STOP:
+		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		break;
+	case IEEE80211_AMPDU_TX_OPERATIONAL:
+		break;
+	default:
+		WARNING((struct rt2x00_dev *)hw->priv, "Unknown AMPDU action\n");
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rt2800_ampdu_action);
+
+MODULE_AUTHOR(DRV_PROJECT ", Bartlomiej Zolnierkiewicz");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT2800 library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 94de999..091641e 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -40,13 +40,17 @@
 	int (*regbusy_read)(struct rt2x00_dev *rt2x00dev,
 			    const unsigned int offset,
 			    const struct rt2x00_field32 field, u32 *reg);
+
+	int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev,
+				  const u8 *data, const size_t len);
+	int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
 };
 
 static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev,
 					const unsigned int offset,
 					u32 *value)
 {
-	const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
 
 	rt2800ops->register_read(rt2x00dev, offset, value);
 }
@@ -55,7 +59,7 @@
 					     const unsigned int offset,
 					     u32 *value)
 {
-	const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
 
 	rt2800ops->register_read_lock(rt2x00dev, offset, value);
 }
@@ -64,7 +68,7 @@
 					 const unsigned int offset,
 					 u32 value)
 {
-	const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
 
 	rt2800ops->register_write(rt2x00dev, offset, value);
 }
@@ -73,7 +77,7 @@
 					      const unsigned int offset,
 					      u32 value)
 {
-	const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
 
 	rt2800ops->register_write_lock(rt2x00dev, offset, value);
 }
@@ -82,7 +86,7 @@
 					     const unsigned int offset,
 					     void *value, const u32 length)
 {
-	const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
 
 	rt2800ops->register_multiread(rt2x00dev, offset, value, length);
 }
@@ -92,7 +96,7 @@
 					      const void *value,
 					      const u32 length)
 {
-	const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
 
 	rt2800ops->register_multiwrite(rt2x00dev, offset, value, length);
 }
@@ -102,17 +106,39 @@
 				      const struct rt2x00_field32 field,
 				      u32 *reg)
 {
-	const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
 
 	return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg);
 }
 
+static inline int rt2800_drv_write_firmware(struct rt2x00_dev *rt2x00dev,
+					    const u8 *data, const size_t len)
+{
+	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
+
+	return rt2800ops->drv_write_firmware(rt2x00dev, data, len);
+}
+
+static inline int rt2800_drv_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
+
+	return rt2800ops->drv_init_registers(rt2x00dev);
+}
+
 void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
 			const u8 command, const u8 token,
 			const u8 arg0, const u8 arg1);
 
-void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc);
-void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *txdesc);
+int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
+			  const u8 *data, const size_t len);
+int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
+			 const u8 *data, const size_t len);
+
+void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc);
+void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc);
+
+void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
 
 extern const struct rt2x00debug rt2800_rt2x00debug;
 
@@ -148,6 +174,14 @@
 int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev);
 int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev);
 
-extern const struct ieee80211_ops rt2800_mac80211_ops;
+void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
+			 u16 *iv16);
+int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
+int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
+		   const struct ieee80211_tx_queue_params *params);
+u64 rt2800_get_tsf(struct ieee80211_hw *hw);
+int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+			enum ieee80211_ampdu_mlme_action action,
+			struct ieee80211_sta *sta, u16 tid, u16 *ssn);
 
 #endif /* RT2800LIB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index b2f2327..39b3846 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -31,7 +31,6 @@
 	Supported chipsets: RT2800E & RT2800ED.
  */
 
-#include <linux/crc-ccitt.h>
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
@@ -51,7 +50,7 @@
 /*
  * Allow hardware encryption to be disabled.
  */
-static int modparam_nohwcrypt = 1;
+static int modparam_nohwcrypt = 0;
 module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
 
@@ -139,8 +138,18 @@
 	eeprom.data = rt2x00dev;
 	eeprom.register_read = rt2800pci_eepromregister_read;
 	eeprom.register_write = rt2800pci_eepromregister_write;
-	eeprom.width = !rt2x00_get_field32(reg, E2PROM_CSR_TYPE) ?
-	    PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+	switch (rt2x00_get_field32(reg, E2PROM_CSR_TYPE))
+	{
+	case 0:
+		eeprom.width = PCI_EEPROM_WIDTH_93C46;
+		break;
+	case 1:
+		eeprom.width = PCI_EEPROM_WIDTH_93C66;
+		break;
+	default:
+		eeprom.width = PCI_EEPROM_WIDTH_93C86;
+		break;
+	}
 	eeprom.reg_data_in = 0;
 	eeprom.reg_data_out = 0;
 	eeprom.reg_data_clock = 0;
@@ -182,82 +191,14 @@
 	return FIRMWARE_RT2860;
 }
 
-static int rt2800pci_check_firmware(struct rt2x00_dev *rt2x00dev,
+static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
 				    const u8 *data, const size_t len)
 {
-	u16 fw_crc;
-	u16 crc;
-
-	/*
-	 * Only support 8kb firmware files.
-	 */
-	if (len != 8192)
-		return FW_BAD_LENGTH;
-
-	/*
-	 * The last 2 bytes in the firmware array are the crc checksum itself,
-	 * this means that we should never pass those 2 bytes to the crc
-	 * algorithm.
-	 */
-	fw_crc = (data[len - 2] << 8 | data[len - 1]);
-
-	/*
-	 * Use the crc ccitt algorithm.
-	 * This will return the same value as the legacy driver which
-	 * used bit ordering reversion on the both the firmware bytes
-	 * before input input as well as on the final output.
-	 * Obviously using crc ccitt directly is much more efficient.
-	 */
-	crc = crc_ccitt(~0, data, len - 2);
-
-	/*
-	 * There is a small difference between the crc-itu-t + bitrev and
-	 * the crc-ccitt crc calculation. In the latter method the 2 bytes
-	 * will be swapped, use swab16 to convert the crc to the correct
-	 * value.
-	 */
-	crc = swab16(crc);
-
-	return (fw_crc == crc) ? FW_OK : FW_BAD_CRC;
-}
-
-static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev,
-				   const u8 *data, const size_t len)
-{
-	unsigned int i;
 	u32 reg;
 
-	/*
-	 * Wait for stable hardware.
-	 */
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-		if (reg && reg != ~0)
-			break;
-		msleep(1);
-	}
-
-	if (i == REGISTER_BUSY_COUNT) {
-		ERROR(rt2x00dev, "Unstable hardware.\n");
-		return -EBUSY;
-	}
-
-	rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
 	rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);
 
 	/*
-	 * Disable DMA, will be reenabled later when enabling
-	 * the radio.
-	 */
-	rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
-	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
-	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
-	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
-	rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
-	rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
-	/*
 	 * enable Host program ram write selection
 	 */
 	reg = 0;
@@ -268,34 +209,11 @@
 	 * Write firmware to device.
 	 */
 	rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
-				      data, len);
+				   data, len);
 
 	rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
 	rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
 
-	/*
-	 * Wait for device to stabilize.
-	 */
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
-		if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
-			break;
-		msleep(1);
-	}
-
-	if (i == REGISTER_BUSY_COUNT) {
-		ERROR(rt2x00dev, "PBF system register not ready.\n");
-		return -EBUSY;
-	}
-
-	/*
-	 * Disable interrupts
-	 */
-	rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_IRQ_OFF);
-
-	/*
-	 * Initialize BBP R/W access agent
-	 */
 	rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
 	rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
 
@@ -412,7 +330,8 @@
 static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
 				 enum dev_state state)
 {
-	int mask = (state == STATE_RADIO_IRQ_ON);
+	int mask = (state == STATE_RADIO_IRQ_ON) ||
+		   (state == STATE_RADIO_IRQ_ON_ISR);
 	u32 reg;
 
 	/*
@@ -446,6 +365,38 @@
 	rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
 }
 
+static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	/*
+	 * Reset DMA indexes
+	 */
+	rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
+	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
+	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
+	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
+	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
+	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
+	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
+	rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
+	rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+
+	rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+	rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
+
+	rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+
+	rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+	rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
+	rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
+	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+
+	return 0;
+}
+
 static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
@@ -465,7 +416,7 @@
 	/*
 	 * Send signal to firmware during boot time.
 	 */
-	rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0);
+	rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
 
 	/*
 	 * Enable RX.
@@ -589,7 +540,9 @@
 		rt2800pci_toggle_rx(rt2x00dev, state);
 		break;
 	case STATE_RADIO_IRQ_ON:
+	case STATE_RADIO_IRQ_ON_ISR:
 	case STATE_RADIO_IRQ_OFF:
+	case STATE_RADIO_IRQ_OFF_ISR:
 		rt2800pci_toggle_irq(rt2x00dev, state);
 		break;
 	case STATE_DEEP_SLEEP:
@@ -613,18 +566,12 @@
 /*
  * TX descriptor initialization
  */
-static int rt2800pci_write_tx_data(struct queue_entry* entry,
-				   struct txentry_desc *txdesc)
+static void rt2800pci_write_tx_data(struct queue_entry* entry,
+				    struct txentry_desc *txdesc)
 {
-	int ret;
+	__le32 *txwi = (__le32 *) entry->skb->data;
 
-	ret = rt2x00pci_write_tx_data(entry, txdesc);
-	if (ret)
-		return ret;
-
-	rt2800_write_txwi(entry->skb, txdesc);
-
-	return 0;
+	rt2800_write_txwi(txwi, txdesc);
 }
 
 
@@ -684,49 +631,6 @@
 /*
  * TX data initialization
  */
-static void rt2800pci_write_beacon(struct queue_entry *entry,
-				   struct txentry_desc *txdesc)
-{
-	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-	unsigned int beacon_base;
-	u32 reg;
-
-	/*
-	 * Disable beaconing while we are reloading the beacon data,
-	 * otherwise we might be sending out invalid data.
-	 */
-	rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
-	rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
-	rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-
-	/*
-	 * Add the TXWI for the beacon to the skb.
-	 */
-	rt2800_write_txwi(entry->skb, txdesc);
-	skb_push(entry->skb, TXWI_DESC_SIZE);
-
-	/*
-	 * Write entire beacon with TXWI to register.
-	 */
-	beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
-	rt2800_register_multiwrite(rt2x00dev, beacon_base,
-				   entry->skb->data, entry->skb->len);
-
-	/*
-	 * Enable beaconing again.
-	 */
-	rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
-	rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
-	rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
-	rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-
-	/*
-	 * Clean up beacon skb.
-	 */
-	dev_kfree_skb_any(entry->skb);
-	entry->skb = NULL;
-}
-
 static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 				    const enum data_queue_qid queue_idx)
 {
@@ -812,7 +716,7 @@
 	/*
 	 * Process the RXWI structure that is at the start of the buffer.
 	 */
-	rt2800_process_rxwi(entry->skb, rxdesc);
+	rt2800_process_rxwi(entry, rxdesc);
 
 	/*
 	 * Set RX IDX in register to inform hardware that we have handled
@@ -832,29 +736,24 @@
 	struct txdone_entry_desc txdesc;
 	u32 word;
 	u32 reg;
-	u32 old_reg;
 	int wcid, ack, pid, tx_wcid, tx_ack, tx_pid;
 	u16 mcs, real_mcs;
+	int i;
 
 	/*
-	 * During each loop we will compare the freshly read
-	 * TX_STA_FIFO register value with the value read from
-	 * the previous loop. If the 2 values are equal then
-	 * we should stop processing because the chance it
-	 * quite big that the device has been unplugged and
-	 * we risk going into an endless loop.
+	 * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
+	 * at most X times and also stop processing once the TX_STA_FIFO_VALID
+	 * flag is not set anymore.
+	 *
+	 * The legacy drivers use X=TX_RING_SIZE but state in a comment
+	 * that the TX_STA_FIFO stack has a size of 16. We stick to our
+	 * tx ring size for now.
 	 */
-	old_reg = 0;
-
-	while (1) {
+	for (i = 0; i < TX_ENTRIES; i++) {
 		rt2800_register_read(rt2x00dev, TX_STA_FIFO, &reg);
 		if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
 			break;
 
-		if (old_reg == reg)
-			break;
-		old_reg = reg;
-
 		wcid    = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
 		ack     = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
 		pid     = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
@@ -880,8 +779,7 @@
 
 		/* Check if we got a match by looking at WCID/ACK/PID
 		 * fields */
-		txwi = (__le32 *)(entry->skb->data -
-				  rt2x00dev->ops->extra_tx_headroom);
+		txwi = (__le32 *) entry->skb->data;
 
 		rt2x00_desc_read(txwi, 1, &word);
 		tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
@@ -923,8 +821,12 @@
 			txdesc.retry = 7;
 		}
 
-		__set_bit(TXDONE_FALLBACK, &txdesc.flags);
-
+		/*
+		 * the frame was retried at least once
+		 * -> hw used fallback rates
+		 */
+		if (txdesc.retry)
+			__set_bit(TXDONE_FALLBACK, &txdesc.flags);
 
 		rt2x00lib_txdone(entry, &txdesc);
 	}
@@ -938,6 +840,48 @@
 	rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
 }
 
+static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
+{
+	struct rt2x00_dev *rt2x00dev = dev_instance;
+	u32 reg = rt2x00dev->irqvalue[0];
+
+	/*
+	 * 1 - Pre TBTT interrupt.
+	 */
+	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
+		rt2x00lib_pretbtt(rt2x00dev);
+
+	/*
+	 * 2 - Beacondone interrupt.
+	 */
+	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
+		rt2x00lib_beacondone(rt2x00dev);
+
+	/*
+	 * 3 - Rx ring done interrupt.
+	 */
+	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
+		rt2x00pci_rxdone(rt2x00dev);
+
+	/*
+	 * 4 - Tx done interrupt.
+	 */
+	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
+		rt2800pci_txdone(rt2x00dev);
+
+	/*
+	 * 5 - Auto wakeup interrupt.
+	 */
+	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
+		rt2800pci_wakeup(rt2x00dev);
+
+	/* Enable interrupts again. */
+	rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+					      STATE_RADIO_IRQ_ON_ISR);
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
 {
 	struct rt2x00_dev *rt2x00dev = dev_instance;
@@ -953,19 +897,15 @@
 	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		return IRQ_HANDLED;
 
-	/*
-	 * 1 - Rx ring done interrupt.
-	 */
-	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
-		rt2x00pci_rxdone(rt2x00dev);
+	/* Store irqvalue for use in the interrupt thread. */
+	rt2x00dev->irqvalue[0] = reg;
 
-	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
-		rt2800pci_txdone(rt2x00dev);
+	/* Disable interrupts, will be enabled again in the interrupt thread. */
+	rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+					      STATE_RADIO_IRQ_OFF_ISR);
 
-	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
-		rt2800pci_wakeup(rt2x00dev);
 
-	return IRQ_HANDLED;
+	return IRQ_WAKE_THREAD;
 }
 
 /*
@@ -986,24 +926,10 @@
 	return rt2800_validate_eeprom(rt2x00dev);
 }
 
-static const struct rt2800_ops rt2800pci_rt2800_ops = {
-	.register_read		= rt2x00pci_register_read,
-	.register_read_lock	= rt2x00pci_register_read, /* same for PCI */
-	.register_write		= rt2x00pci_register_write,
-	.register_write_lock	= rt2x00pci_register_write, /* same for PCI */
-
-	.register_multiread	= rt2x00pci_register_multiread,
-	.register_multiwrite	= rt2x00pci_register_multiwrite,
-
-	.regbusy_read		= rt2x00pci_regbusy_read,
-};
-
 static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 {
 	int retval;
 
-	rt2x00dev->priv = (void *)&rt2800pci_rt2800_ops;
-
 	/*
 	 * Allocate eeprom data.
 	 */
@@ -1030,6 +956,12 @@
 	__set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags);
 
 	/*
+	 * This device has a pre tbtt interrupt and thus fetches
+	 * a new beacon directly prior to transmission.
+	 */
+	__set_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags);
+
+	/*
 	 * This device requires firmware.
 	 */
 	if (!rt2x00_is_soc(rt2x00dev))
@@ -1038,6 +970,7 @@
 	__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
 	if (!modparam_nohwcrypt)
 		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
+	__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
 
 	/*
 	 * Set the rssi offset.
@@ -1047,12 +980,46 @@
 	return 0;
 }
 
+static const struct ieee80211_ops rt2800pci_mac80211_ops = {
+	.tx			= rt2x00mac_tx,
+	.start			= rt2x00mac_start,
+	.stop			= rt2x00mac_stop,
+	.add_interface		= rt2x00mac_add_interface,
+	.remove_interface	= rt2x00mac_remove_interface,
+	.config			= rt2x00mac_config,
+	.configure_filter	= rt2x00mac_configure_filter,
+	.set_key		= rt2x00mac_set_key,
+	.sw_scan_start		= rt2x00mac_sw_scan_start,
+	.sw_scan_complete	= rt2x00mac_sw_scan_complete,
+	.get_stats		= rt2x00mac_get_stats,
+	.get_tkip_seq		= rt2800_get_tkip_seq,
+	.set_rts_threshold	= rt2800_set_rts_threshold,
+	.bss_info_changed	= rt2x00mac_bss_info_changed,
+	.conf_tx		= rt2800_conf_tx,
+	.get_tsf		= rt2800_get_tsf,
+	.rfkill_poll		= rt2x00mac_rfkill_poll,
+	.ampdu_action		= rt2800_ampdu_action,
+};
+
+static const struct rt2800_ops rt2800pci_rt2800_ops = {
+	.register_read		= rt2x00pci_register_read,
+	.register_read_lock	= rt2x00pci_register_read, /* same for PCI */
+	.register_write		= rt2x00pci_register_write,
+	.register_write_lock	= rt2x00pci_register_write, /* same for PCI */
+	.register_multiread	= rt2x00pci_register_multiread,
+	.register_multiwrite	= rt2x00pci_register_multiwrite,
+	.regbusy_read		= rt2x00pci_regbusy_read,
+	.drv_write_firmware	= rt2800pci_write_firmware,
+	.drv_init_registers	= rt2800pci_init_registers,
+};
+
 static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
 	.irq_handler		= rt2800pci_interrupt,
+	.irq_handler_thread	= rt2800pci_interrupt_thread,
 	.probe_hw		= rt2800pci_probe_hw,
 	.get_firmware_name	= rt2800pci_get_firmware_name,
-	.check_firmware		= rt2800pci_check_firmware,
-	.load_firmware		= rt2800pci_load_firmware,
+	.check_firmware		= rt2800_check_firmware,
+	.load_firmware		= rt2800_load_firmware,
 	.initialize		= rt2x00pci_initialize,
 	.uninitialize		= rt2x00pci_uninitialize,
 	.get_entry_state	= rt2800pci_get_entry_state,
@@ -1064,7 +1031,7 @@
 	.link_tuner		= rt2800_link_tuner,
 	.write_tx_desc		= rt2800pci_write_tx_desc,
 	.write_tx_data		= rt2800pci_write_tx_data,
-	.write_beacon		= rt2800pci_write_beacon,
+	.write_beacon		= rt2800_write_beacon,
 	.kick_tx_queue		= rt2800pci_kick_tx_queue,
 	.kill_tx_queue		= rt2800pci_kill_tx_queue,
 	.fill_rxdone		= rt2800pci_fill_rxdone,
@@ -1110,7 +1077,8 @@
 	.tx			= &rt2800pci_queue_tx,
 	.bcn			= &rt2800pci_queue_bcn,
 	.lib			= &rt2800pci_rt2x00_ops,
-	.hw			= &rt2800_mac80211_ops,
+	.drv			= &rt2800pci_rt2800_ops,
+	.hw			= &rt2800pci_mac80211_ops,
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 	.debugfs		= &rt2800_rt2x00debug,
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h
index afc8e7d..5a8dda9 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.h
+++ b/drivers/net/wireless/rt2x00/rt2800pci.h
@@ -35,25 +35,6 @@
 #define RT2800PCI_H
 
 /*
- * PCI registers.
- */
-
-/*
- * E2PROM_CSR: EEPROM control register.
- * RELOAD: Write 1 to reload eeprom content.
- * TYPE: 0: 93c46, 1:93c66.
- * LOAD_STATUS: 1:loading, 0:done.
- */
-#define E2PROM_CSR			0x0004
-#define E2PROM_CSR_DATA_CLOCK		FIELD32(0x00000001)
-#define E2PROM_CSR_CHIP_SELECT		FIELD32(0x00000002)
-#define E2PROM_CSR_DATA_IN		FIELD32(0x00000004)
-#define E2PROM_CSR_DATA_OUT		FIELD32(0x00000008)
-#define E2PROM_CSR_TYPE			FIELD32(0x00000030)
-#define E2PROM_CSR_LOAD_STATUS		FIELD32(0x00000040)
-#define E2PROM_CSR_RELOAD		FIELD32(0x00000080)
-
-/*
  * Queue register offset macros
  */
 #define TX_QUEUE_REG_OFFSET		0x10
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 0f8b84b..5a2dfe8 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -28,7 +28,6 @@
 	Supported chipsets: RT2800U.
  */
 
-#include <linux/crc-ccitt.h>
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
@@ -45,7 +44,7 @@
 /*
  * Allow hardware encryption to be disabled.
  */
-static int modparam_nohwcrypt = 1;
+static int modparam_nohwcrypt = 0;
 module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
 
@@ -57,84 +56,10 @@
 	return FIRMWARE_RT2870;
 }
 
-static bool rt2800usb_check_crc(const u8 *data, const size_t len)
-{
-	u16 fw_crc;
-	u16 crc;
-
-	/*
-	 * The last 2 bytes in the firmware array are the crc checksum itself,
-	 * this means that we should never pass those 2 bytes to the crc
-	 * algorithm.
-	 */
-	fw_crc = (data[len - 2] << 8 | data[len - 1]);
-
-	/*
-	 * Use the crc ccitt algorithm.
-	 * This will return the same value as the legacy driver which
-	 * used bit ordering reversion on the both the firmware bytes
-	 * before input input as well as on the final output.
-	 * Obviously using crc ccitt directly is much more efficient.
-	 */
-	crc = crc_ccitt(~0, data, len - 2);
-
-	/*
-	 * There is a small difference between the crc-itu-t + bitrev and
-	 * the crc-ccitt crc calculation. In the latter method the 2 bytes
-	 * will be swapped, use swab16 to convert the crc to the correct
-	 * value.
-	 */
-	crc = swab16(crc);
-
-	return fw_crc == crc;
-}
-
-static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev,
+static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
 				    const u8 *data, const size_t len)
 {
-	size_t offset = 0;
-
-	/*
-	 * Firmware files:
-	 * There are 2 variations of the rt2870 firmware.
-	 * a) size: 4kb
-	 * b) size: 8kb
-	 * Note that (b) contains 2 separate firmware blobs of 4k
-	 * within the file. The first blob is the same firmware as (a),
-	 * but the second blob is for the additional chipsets.
-	 */
-	if (len != 4096 && len != 8192)
-		return FW_BAD_LENGTH;
-
-	/*
-	 * Check if we need the upper 4kb firmware data or not.
-	 */
-	if ((len == 4096) &&
-	    !rt2x00_rt(rt2x00dev, RT2860) &&
-	    !rt2x00_rt(rt2x00dev, RT2872) &&
-	    !rt2x00_rt(rt2x00dev, RT3070))
-		return FW_BAD_VERSION;
-
-	/*
-	 * 8kb firmware files must be checked as if it were
-	 * 2 separate firmware files.
-	 */
-	while (offset < len) {
-		if (!rt2800usb_check_crc(data + offset, 4096))
-			return FW_BAD_CRC;
-
-		offset += 4096;
-	}
-
-	return FW_OK;
-}
-
-static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
-				   const u8 *data, const size_t len)
-{
-	unsigned int i;
 	int status;
-	u32 reg;
 	u32 offset;
 	u32 length;
 
@@ -152,28 +77,10 @@
 	}
 
 	/*
-	 * Wait for stable hardware.
-	 */
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-		if (reg && reg != ~0)
-			break;
-		msleep(1);
-	}
-
-	if (i == REGISTER_BUSY_COUNT) {
-		ERROR(rt2x00dev, "Unstable hardware.\n");
-		return -EBUSY;
-	}
-
-	/*
 	 * Write firmware to device.
 	 */
-	rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
-					    USB_VENDOR_REQUEST_OUT,
-					    FIRMWARE_IMAGE_BASE,
-					    data + offset, length,
-					    REGISTER_TIMEOUT32(length));
+	rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+				   data + offset, length);
 
 	rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
 	rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
@@ -196,7 +103,7 @@
 	/*
 	 * Send signal to firmware during boot time.
 	 */
-	rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0);
+	rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
 
 	if (rt2x00_rt(rt2x00dev, RT3070) ||
 	    rt2x00_rt(rt2x00dev, RT3071) ||
@@ -206,28 +113,6 @@
 		udelay(10);
 	}
 
-	/*
-	 * Wait for device to stabilize.
-	 */
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
-		if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
-			break;
-		msleep(1);
-	}
-
-	if (i == REGISTER_BUSY_COUNT) {
-		ERROR(rt2x00dev, "PBF system register not ready.\n");
-		return -EBUSY;
-	}
-
-	/*
-	 * Initialize firmware.
-	 */
-	rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
-	rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
-	msleep(1);
-
 	return 0;
 }
 
@@ -246,6 +131,44 @@
 	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
 }
 
+static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+	int i;
+
+	/*
+	 * Wait until BBP and RF are ready.
+	 */
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
+		if (reg && reg != ~0)
+			break;
+		msleep(1);
+	}
+
+	if (i == REGISTER_BUSY_COUNT) {
+		ERROR(rt2x00dev, "Unstable hardware.\n");
+		return -EBUSY;
+	}
+
+	rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
+	rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
+
+	rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+	rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
+	rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
+	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+	rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
+
+	rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
+				    USB_MODE_RESET, REGISTER_TIMEOUT);
+
+	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+
+	return 0;
+}
+
 static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
@@ -371,7 +294,9 @@
 		rt2800usb_toggle_rx(rt2x00dev, state);
 		break;
 	case STATE_RADIO_IRQ_ON:
+	case STATE_RADIO_IRQ_ON_ISR:
 	case STATE_RADIO_IRQ_OFF:
+	case STATE_RADIO_IRQ_OFF_ISR:
 		/* No support, but no error either */
 		break;
 	case STATE_DEEP_SLEEP:
@@ -395,25 +320,29 @@
 /*
  * TX descriptor initialization
  */
+static void rt2800usb_write_tx_data(struct queue_entry* entry,
+				    struct txentry_desc *txdesc)
+{
+	__le32 *txwi = (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE);
+
+	rt2800_write_txwi(txwi, txdesc);
+}
+
+
 static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 				    struct sk_buff *skb,
 				    struct txentry_desc *txdesc)
 {
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-	__le32 *txi = (__le32 *)(skb->data - TXWI_DESC_SIZE - TXINFO_DESC_SIZE);
+	__le32 *txi = (__le32 *) skb->data;
 	u32 word;
 
 	/*
-	 * Initialize TXWI descriptor
-	 */
-	rt2800_write_txwi(skb, txdesc);
-
-	/*
 	 * Initialize TXINFO descriptor
 	 */
 	rt2x00_desc_read(txi, 0, &word);
 	rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN,
-			   skb->len + TXWI_DESC_SIZE);
+			   skb->len - TXINFO_DESC_SIZE);
 	rt2x00_set_field32(&word, TXINFO_W0_WIV,
 			   !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
 	rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2);
@@ -426,6 +355,7 @@
 	/*
 	 * Register descriptor details in skb frame descriptor.
 	 */
+	skbdesc->flags |= SKBDESC_DESC_IN_SKB;
 	skbdesc->desc = txi;
 	skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
 }
@@ -433,51 +363,6 @@
 /*
  * TX data initialization
  */
-static void rt2800usb_write_beacon(struct queue_entry *entry,
-				   struct txentry_desc *txdesc)
-{
-	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-	unsigned int beacon_base;
-	u32 reg;
-
-	/*
-	 * Disable beaconing while we are reloading the beacon data,
-	 * otherwise we might be sending out invalid data.
-	 */
-	rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
-	rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
-	rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-
-	/*
-	 * Add the TXWI for the beacon to the skb.
-	 */
-	rt2800_write_txwi(entry->skb, txdesc);
-	skb_push(entry->skb, TXWI_DESC_SIZE);
-
-	/*
-	 * Write entire beacon with descriptor to register.
-	 */
-	beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
-	rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
-					    USB_VENDOR_REQUEST_OUT, beacon_base,
-					    entry->skb->data, entry->skb->len,
-					    REGISTER_TIMEOUT32(entry->skb->len));
-
-	/*
-	 * Enable beaconing again.
-	 */
-	rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
-	rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
-	rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
-	rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-
-	/*
-	 * Clean up the beacon skb.
-	 */
-	dev_kfree_skb(entry->skb);
-	entry->skb = NULL;
-}
-
 static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
 {
 	int length;
@@ -568,7 +453,7 @@
 	/*
 	 * Process the RXWI structure.
 	 */
-	rt2800_process_rxwi(entry->skb, rxdesc);
+	rt2800_process_rxwi(entry, rxdesc);
 }
 
 /*
@@ -585,24 +470,10 @@
 	return rt2800_validate_eeprom(rt2x00dev);
 }
 
-static const struct rt2800_ops rt2800usb_rt2800_ops = {
-	.register_read		= rt2x00usb_register_read,
-	.register_read_lock	= rt2x00usb_register_read_lock,
-	.register_write		= rt2x00usb_register_write,
-	.register_write_lock	= rt2x00usb_register_write_lock,
-
-	.register_multiread	= rt2x00usb_register_multiread,
-	.register_multiwrite	= rt2x00usb_register_multiwrite,
-
-	.regbusy_read		= rt2x00usb_regbusy_read,
-};
-
 static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 {
 	int retval;
 
-	rt2x00dev->priv = (void *)&rt2800usb_rt2800_ops;
-
 	/*
 	 * Allocate eeprom data.
 	 */
@@ -635,6 +506,8 @@
 	__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
 	if (!modparam_nohwcrypt)
 		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
+	__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
+	__set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
 
 	/*
 	 * Set the rssi offset.
@@ -644,11 +517,45 @@
 	return 0;
 }
 
+static const struct ieee80211_ops rt2800usb_mac80211_ops = {
+	.tx			= rt2x00mac_tx,
+	.start			= rt2x00mac_start,
+	.stop			= rt2x00mac_stop,
+	.add_interface		= rt2x00mac_add_interface,
+	.remove_interface	= rt2x00mac_remove_interface,
+	.config			= rt2x00mac_config,
+	.configure_filter	= rt2x00mac_configure_filter,
+	.set_tim		= rt2x00mac_set_tim,
+	.set_key		= rt2x00mac_set_key,
+	.sw_scan_start		= rt2x00mac_sw_scan_start,
+	.sw_scan_complete	= rt2x00mac_sw_scan_complete,
+	.get_stats		= rt2x00mac_get_stats,
+	.get_tkip_seq		= rt2800_get_tkip_seq,
+	.set_rts_threshold	= rt2800_set_rts_threshold,
+	.bss_info_changed	= rt2x00mac_bss_info_changed,
+	.conf_tx		= rt2800_conf_tx,
+	.get_tsf		= rt2800_get_tsf,
+	.rfkill_poll		= rt2x00mac_rfkill_poll,
+	.ampdu_action		= rt2800_ampdu_action,
+};
+
+static const struct rt2800_ops rt2800usb_rt2800_ops = {
+	.register_read		= rt2x00usb_register_read,
+	.register_read_lock	= rt2x00usb_register_read_lock,
+	.register_write		= rt2x00usb_register_write,
+	.register_write_lock	= rt2x00usb_register_write_lock,
+	.register_multiread	= rt2x00usb_register_multiread,
+	.register_multiwrite	= rt2x00usb_register_multiwrite,
+	.regbusy_read		= rt2x00usb_regbusy_read,
+	.drv_write_firmware	= rt2800usb_write_firmware,
+	.drv_init_registers	= rt2800usb_init_registers,
+};
+
 static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
 	.probe_hw		= rt2800usb_probe_hw,
 	.get_firmware_name	= rt2800usb_get_firmware_name,
-	.check_firmware		= rt2800usb_check_firmware,
-	.load_firmware		= rt2800usb_load_firmware,
+	.check_firmware		= rt2800_check_firmware,
+	.load_firmware		= rt2800_load_firmware,
 	.initialize		= rt2x00usb_initialize,
 	.uninitialize		= rt2x00usb_uninitialize,
 	.clear_entry		= rt2x00usb_clear_entry,
@@ -657,9 +564,10 @@
 	.link_stats		= rt2800_link_stats,
 	.reset_tuner		= rt2800_reset_tuner,
 	.link_tuner		= rt2800_link_tuner,
+	.watchdog		= rt2x00usb_watchdog,
 	.write_tx_desc		= rt2800usb_write_tx_desc,
-	.write_tx_data		= rt2x00usb_write_tx_data,
-	.write_beacon		= rt2800usb_write_beacon,
+	.write_tx_data		= rt2800usb_write_tx_data,
+	.write_beacon		= rt2800_write_beacon,
 	.get_tx_data_len	= rt2800usb_get_tx_data_len,
 	.kick_tx_queue		= rt2x00usb_kick_tx_queue,
 	.kill_tx_queue		= rt2x00usb_kill_tx_queue,
@@ -706,7 +614,8 @@
 	.tx			= &rt2800usb_queue_tx,
 	.bcn			= &rt2800usb_queue_bcn,
 	.lib			= &rt2800usb_rt2x00_ops,
-	.hw			= &rt2800_mac80211_ops,
+	.drv			= &rt2800usb_rt2800_ops,
+	.hw			= &rt2800usb_mac80211_ops,
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 	.debugfs		= &rt2800_rt2x00debug,
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h
index 2bca6a7..0722bad 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.h
+++ b/drivers/net/wireless/rt2x00/rt2800usb.h
@@ -32,43 +32,6 @@
 #define RT2800USB_H
 
 /*
- * USB registers.
- */
-
-/*
- * USB_DMA_CFG
- * RX_BULK_AGG_TIMEOUT: Rx Bulk Aggregation TimeOut in unit of 33ns.
- * RX_BULK_AGG_LIMIT: Rx Bulk Aggregation Limit in unit of 256 bytes.
- * PHY_CLEAR: phy watch dog enable.
- * TX_CLEAR: Clear USB DMA TX path.
- * TXOP_HALT: Halt TXOP count down when TX buffer is full.
- * RX_BULK_AGG_EN: Enable Rx Bulk Aggregation.
- * RX_BULK_EN: Enable USB DMA Rx.
- * TX_BULK_EN: Enable USB DMA Tx.
- * EP_OUT_VALID: OUT endpoint data valid.
- * RX_BUSY: USB DMA RX FSM busy.
- * TX_BUSY: USB DMA TX FSM busy.
- */
-#define USB_DMA_CFG			0x02a0
-#define USB_DMA_CFG_RX_BULK_AGG_TIMEOUT	FIELD32(0x000000ff)
-#define USB_DMA_CFG_RX_BULK_AGG_LIMIT	FIELD32(0x0000ff00)
-#define USB_DMA_CFG_PHY_CLEAR		FIELD32(0x00010000)
-#define USB_DMA_CFG_TX_CLEAR		FIELD32(0x00080000)
-#define USB_DMA_CFG_TXOP_HALT		FIELD32(0x00100000)
-#define USB_DMA_CFG_RX_BULK_AGG_EN	FIELD32(0x00200000)
-#define USB_DMA_CFG_RX_BULK_EN		FIELD32(0x00400000)
-#define USB_DMA_CFG_TX_BULK_EN		FIELD32(0x00800000)
-#define USB_DMA_CFG_EP_OUT_VALID	FIELD32(0x3f000000)
-#define USB_DMA_CFG_RX_BUSY		FIELD32(0x40000000)
-#define USB_DMA_CFG_TX_BUSY		FIELD32(0x80000000)
-
-/*
- * USB_CYC_CFG
- */
-#define USB_CYC_CFG			0x02a4
-#define USB_CYC_CFG_CLOCK_CYCLE		FIELD32(0x000000ff)
-
-/*
  * 8051 firmware image.
  */
 #define FIRMWARE_RT2870			"rt2870.bin"
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 6c1ff4c..c21af38 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -39,6 +39,7 @@
 #include <net/mac80211.h>
 
 #include "rt2x00debug.h"
+#include "rt2x00dump.h"
 #include "rt2x00leds.h"
 #include "rt2x00reg.h"
 #include "rt2x00queue.h"
@@ -159,6 +160,7 @@
 
 enum rt2x00_chip_intf {
 	RT2X00_CHIP_INTF_PCI,
+	RT2X00_CHIP_INTF_PCIE,
 	RT2X00_CHIP_INTF_USB,
 	RT2X00_CHIP_INTF_SOC,
 };
@@ -175,8 +177,7 @@
 #define RT2570		0x2570
 #define RT2661		0x2661
 #define RT2573		0x2573
-#define RT2860		0x2860	/* 2.4GHz PCI/CB */
-#define RT2870		0x2870
+#define RT2860		0x2860	/* 2.4GHz */
 #define RT2872		0x2872	/* WSOC */
 #define RT2883		0x2883	/* WSOC */
 #define RT3070		0x3070
@@ -331,6 +332,11 @@
 	 * Work structure for scheduling periodic link tuning.
 	 */
 	struct delayed_work work;
+
+	/*
+	 * Work structure for scheduling periodic watchdog monitoring.
+	 */
+	struct delayed_work watchdog_work;
 };
 
 /*
@@ -509,6 +515,11 @@
 	irq_handler_t irq_handler;
 
 	/*
+	 * Threaded Interrupt handlers.
+	 */
+	irq_handler_t irq_handler_thread;
+
+	/*
 	 * Device init handlers.
 	 */
 	int (*probe_hw) (struct rt2x00_dev *rt2x00dev);
@@ -542,6 +553,7 @@
 			     struct link_qual *qual);
 	void (*link_tuner) (struct rt2x00_dev *rt2x00dev,
 			    struct link_qual *qual, const u32 count);
+	void (*watchdog) (struct rt2x00_dev *rt2x00dev);
 
 	/*
 	 * TX control handlers
@@ -549,8 +561,8 @@
 	void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
 			       struct sk_buff *skb,
 			       struct txentry_desc *txdesc);
-	int (*write_tx_data) (struct queue_entry *entry,
-			      struct txentry_desc *txdesc);
+	void (*write_tx_data) (struct queue_entry *entry,
+			       struct txentry_desc *txdesc);
 	void (*write_beacon) (struct queue_entry *entry,
 			      struct txentry_desc *txdesc);
 	int (*get_tx_data_len) (struct queue_entry *entry);
@@ -609,6 +621,7 @@
 	const struct data_queue_desc *bcn;
 	const struct data_queue_desc *atim;
 	const struct rt2x00lib_ops *lib;
+	const void *drv;
 	const struct ieee80211_ops *hw;
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 	const struct rt2x00debug *debugfs;
@@ -627,6 +640,7 @@
 	DEVICE_STATE_INITIALIZED,
 	DEVICE_STATE_STARTED,
 	DEVICE_STATE_ENABLED_RADIO,
+	DEVICE_STATE_SCANNING,
 
 	/*
 	 * Driver requirements
@@ -645,6 +659,9 @@
 	CONFIG_SUPPORT_HW_CRYPTO,
 	DRIVER_SUPPORT_CONTROL_FILTERS,
 	DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL,
+	DRIVER_SUPPORT_PRE_TBTT_INTERRUPT,
+	DRIVER_SUPPORT_LINK_TUNING,
+	DRIVER_SUPPORT_WATCHDOG,
 
 	/*
 	 * Driver configuration
@@ -654,7 +671,6 @@
 	CONFIG_EXTERNAL_LNA_A,
 	CONFIG_EXTERNAL_LNA_BG,
 	CONFIG_DOUBLE_ANTENNA,
-	CONFIG_DISABLE_LINK_TUNING,
 	CONFIG_CHANNEL_HT40,
 };
 
@@ -862,9 +878,10 @@
 	const struct firmware *fw;
 
 	/*
-	 * Driver specific data.
+	 * Interrupt values, stored between interrupt service routine
+	 * and interrupt thread routine.
 	 */
-	void *priv;
+	u32 irqvalue[2];
 };
 
 /*
@@ -978,7 +995,13 @@
 
 static inline bool rt2x00_is_pci(struct rt2x00_dev *rt2x00dev)
 {
-	return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
+	return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI) ||
+	       rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
+}
+
+static inline bool rt2x00_is_pcie(struct rt2x00_dev *rt2x00dev)
+{
+	return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
 }
 
 static inline bool rt2x00_is_usb(struct rt2x00_dev *rt2x00dev)
@@ -999,6 +1022,13 @@
 void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
 
 /**
+ * rt2x00queue_unmap_skb - Unmap a skb from DMA.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @skb: The skb to unmap.
+ */
+void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+
+/**
  * rt2x00queue_get_queue - Convert queue index to queue pointer
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
  * @queue: rt2x00 queue index (see &enum data_queue_qid).
@@ -1015,9 +1045,30 @@
 					  enum queue_index index);
 
 /*
+ * Debugfs handlers.
+ */
+/**
+ * rt2x00debug_dump_frame - Dump a frame to userspace through debugfs.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @type: The type of frame that is being dumped.
+ * @skb: The skb containing the frame to be dumped.
+ */
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+			    enum rt2x00_dump_type type, struct sk_buff *skb);
+#else
+static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+					  enum rt2x00_dump_type type,
+					  struct sk_buff *skb)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
  * Interrupt context handlers.
  */
 void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
 void rt2x00lib_txdone(struct queue_entry *entry,
 		      struct txdone_entry_desc *txdesc);
 void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
@@ -1047,6 +1098,8 @@
 #else
 #define rt2x00mac_set_key	NULL
 #endif /* CONFIG_RT2X00_LIB_CRYPTO */
+void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw);
+void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw);
 int rt2x00mac_get_stats(struct ieee80211_hw *hw,
 			struct ieee80211_low_level_stats *stats);
 void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 098315a..953dc4f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -41,10 +41,12 @@
 
 	switch (type) {
 	case NL80211_IFTYPE_ADHOC:
+		conf.sync = TSF_SYNC_ADHOC;
+		break;
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_MESH_POINT:
 	case NL80211_IFTYPE_WDS:
-		conf.sync = TSF_SYNC_BEACON;
+		conf.sync = TSF_SYNC_AP_NONE;
 		break;
 	case NL80211_IFTYPE_STATION:
 		conf.sync = TSF_SYNC_INFRA;
@@ -170,23 +172,27 @@
 		      unsigned int ieee80211_flags)
 {
 	struct rt2x00lib_conf libconf;
+	u16 hw_value;
 
 	memset(&libconf, 0, sizeof(libconf));
 
 	libconf.conf = conf;
 
 	if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
-		if (conf_is_ht40(conf))
+		if (conf_is_ht40(conf)) {
 			__set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
-		else
+			hw_value = rt2x00ht_center_channel(rt2x00dev, conf);
+		} else {
 			__clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
+			hw_value = conf->channel->hw_value;
+		}
 
 		memcpy(&libconf.rf,
-		       &rt2x00dev->spec.channels[conf->channel->hw_value],
+		       &rt2x00dev->spec.channels[hw_value],
 		       sizeof(libconf.rf));
 
 		memcpy(&libconf.channel,
-		       &rt2x00dev->spec.channels_info[conf->channel->hw_value],
+		       &rt2x00dev->spec.channels_info[hw_value],
 		       sizeof(libconf.channel));
 	}
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index e9fe93f..b0498e7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -211,6 +211,7 @@
 	if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
 		skb_queue_purge(&intf->frame_dump_skbqueue);
 }
+EXPORT_SYMBOL_GPL(rt2x00debug_dump_frame);
 
 static int rt2x00debug_file_open(struct inode *inode, struct file *file)
 {
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index f20d3ee..585e816 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -70,6 +70,11 @@
 	rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
 
 	/*
+	 * Start watchdog monitoring.
+	 */
+	rt2x00link_start_watchdog(rt2x00dev);
+
+	/*
 	 * Start the TX queues.
 	 */
 	ieee80211_wake_queues(rt2x00dev->hw);
@@ -89,6 +94,11 @@
 	rt2x00queue_stop_queues(rt2x00dev);
 
 	/*
+	 * Stop watchdog monitoring.
+	 */
+	rt2x00link_stop_watchdog(rt2x00dev);
+
+	/*
 	 * Disable RX.
 	 */
 	rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
@@ -168,10 +178,32 @@
 /*
  * Interrupt context handlers.
  */
-static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
-				      struct ieee80211_vif *vif)
+static void rt2x00lib_bc_buffer_iter(void *data, u8 *mac,
+				     struct ieee80211_vif *vif)
 {
-	struct rt2x00_intf *intf = vif_to_intf(vif);
+	struct rt2x00_dev *rt2x00dev = data;
+	struct sk_buff *skb;
+
+	/*
+	 * Only AP mode interfaces do broad- and multicast buffering
+	 */
+	if (vif->type != NL80211_IFTYPE_AP)
+		return;
+
+	/*
+	 * Send out buffered broad- and multicast frames
+	 */
+	skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif);
+	while (skb) {
+		rt2x00mac_tx(rt2x00dev->hw, skb);
+		skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif);
+	}
+}
+
+static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac,
+					struct ieee80211_vif *vif)
+{
+	struct rt2x00_dev *rt2x00dev = data;
 
 	if (vif->type != NL80211_IFTYPE_AP &&
 	    vif->type != NL80211_IFTYPE_ADHOC &&
@@ -179,9 +211,7 @@
 	    vif->type != NL80211_IFTYPE_WDS)
 		return;
 
-	spin_lock(&intf->lock);
-	intf->delayed_flags |= DELAYED_UPDATE_BEACON;
-	spin_unlock(&intf->lock);
+	rt2x00queue_update_beacon(rt2x00dev, vif, true);
 }
 
 void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
@@ -189,14 +219,37 @@
 	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		return;
 
-	ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
-						   rt2x00lib_beacondone_iter,
-						   rt2x00dev);
+	/* send buffered bc/mc frames out for every bssid */
+	ieee80211_iterate_active_interfaces(rt2x00dev->hw,
+					    rt2x00lib_bc_buffer_iter,
+					    rt2x00dev);
+	/*
+	 * Devices with pre tbtt interrupt don't need to update the beacon
+	 * here as they will fetch the next beacon directly prior to
+	 * transmission.
+	 */
+	if (test_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags))
+		return;
 
-	ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
+	/* fetch next beacon */
+	ieee80211_iterate_active_interfaces(rt2x00dev->hw,
+					    rt2x00lib_beaconupdate_iter,
+					    rt2x00dev);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
 
+void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
+{
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		return;
+
+	/* fetch next beacon */
+	ieee80211_iterate_active_interfaces(rt2x00dev->hw,
+					    rt2x00lib_beaconupdate_iter,
+					    rt2x00dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
+
 void rt2x00lib_txdone(struct queue_entry *entry,
 		      struct txdone_entry_desc *txdesc)
 {
@@ -216,6 +269,16 @@
 	rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
 
 	/*
+	 * Remove the extra tx headroom from the skb.
+	 */
+	skb_pull(entry->skb, rt2x00dev->ops->extra_tx_headroom);
+
+	/*
+	 * Signal that the TX descriptor is no longer in the skb.
+	 */
+	skbdesc->flags &= ~SKBDESC_DESC_IN_SKB;
+
+	/*
 	 * Remove L2 padding which was added during
 	 */
 	if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
@@ -224,7 +287,7 @@
 	/*
 	 * If the IV/EIV data was stripped from the frame before it was
 	 * passed to the hardware, we should now reinsert it again because
-	 * mac80211 will expect the the same data to be present it the
+	 * mac80211 will expect the same data to be present it the
 	 * frame as it was passed to us.
 	 */
 	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
@@ -241,8 +304,7 @@
 	 */
 	success =
 	    test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
-	    test_bit(TXDONE_UNKNOWN, &txdesc->flags) ||
-	    test_bit(TXDONE_FALLBACK, &txdesc->flags);
+	    test_bit(TXDONE_UNKNOWN, &txdesc->flags);
 
 	/*
 	 * Update TX statistics.
@@ -264,11 +326,22 @@
 	/*
 	 * Frame was send with retries, hardware tried
 	 * different rates to send out the frame, at each
-	 * retry it lowered the rate 1 step.
+	 * retry it lowered the rate 1 step except when the
+	 * lowest rate was used.
 	 */
 	for (i = 0; i < retry_rates && i < IEEE80211_TX_MAX_RATES; i++) {
 		tx_info->status.rates[i].idx = rate_idx - i;
 		tx_info->status.rates[i].flags = rate_flags;
+
+		if (rate_idx - i == 0) {
+			/*
+			 * The lowest rate (index 0) was used until the
+			 * number of max retries was reached.
+			 */
+			tx_info->status.rates[i].count = retry_rates - i;
+			i++;
+			break;
+		}
 		tx_info->status.rates[i].count = 1;
 	}
 	if (i < (IEEE80211_TX_MAX_RATES - 1))
@@ -281,6 +354,21 @@
 			rt2x00dev->low_level_stats.dot11ACKFailureCount++;
 	}
 
+	/*
+	 * Every single frame has it's own tx status, hence report
+	 * every frame as ampdu of size 1.
+	 *
+	 * TODO: if we can find out how many frames were aggregated
+	 * by the hw we could provide the real ampdu_len to mac80211
+	 * which would allow the rc algorithm to better decide on
+	 * which rates are suitable.
+	 */
+	if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+		tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
+		tx_info->status.ampdu_len = 1;
+		tx_info->status.ampdu_ack_len = success ? 1 : 0;
+	}
+
 	if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
 		if (success)
 			rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
@@ -295,9 +383,17 @@
 	 * send the status report back.
 	 */
 	if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
-		ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
+		/*
+		 * Only PCI and SOC devices process the tx status in process
+		 * context. Hence use ieee80211_tx_status for PCI and SOC
+		 * devices and stick to ieee80211_tx_status_irqsafe for USB.
+		 */
+		if (rt2x00_is_usb(rt2x00dev))
+			ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
+		else
+			ieee80211_tx_status(rt2x00dev->hw, entry->skb);
 	else
-		dev_kfree_skb_irq(entry->skb);
+		dev_kfree_skb_any(entry->skb);
 
 	/*
 	 * Make this entry available for reuse.
@@ -444,7 +540,16 @@
 	 */
 	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
 	memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
-	ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
+
+	/*
+	 * Currently only PCI and SOC devices handle rx interrupts in process
+	 * context. Hence, use ieee80211_rx_irqsafe for USB and ieee80211_rx_ni
+	 * for PCI and SOC devices.
+	 */
+	if (rt2x00_is_usb(rt2x00dev))
+		ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
+	else
+		ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
 
 	/*
 	 * Replace the skb with the freshly allocated one.
diff --git a/drivers/net/wireless/rt2x00/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h
index ed303b4..5d6e0b8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dump.h
+++ b/drivers/net/wireless/rt2x00/rt2x00dump.h
@@ -20,7 +20,12 @@
 
 /*
 	Module: rt2x00dump
-	Abstract: Data structures for the rt2x00debug & userspace.
+	Abstract:
+		Data structures for the rt2x00debug & userspace.
+
+		The declarations in this file can be used by both rt2x00
+		and userspace and therefore should be kept together in
+		this file.
  */
 
 #ifndef RT2X00DUMP_H
@@ -111,7 +116,7 @@
 
 	__le16 chip_rt;
 	__le16 chip_rf;
-	__le32 chip_rev;
+	__le16 chip_rev;
 
 	__le16 type;
 	__u8 queue_index;
diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c
index 5a40760..c004cd3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00ht.c
+++ b/drivers/net/wireless/rt2x00/rt2x00ht.c
@@ -44,11 +44,22 @@
 		txdesc->mpdu_density = 0;
 
 	txdesc->ba_size = 7;	/* FIXME: What value is needed? */
-	txdesc->stbc = 0;	/* FIXME: What value is needed? */
 
-	txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
-	if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
-		txdesc->mcs |= 0x08;
+	txdesc->stbc =
+	    (tx_info->flags & IEEE80211_TX_CTL_STBC) >> IEEE80211_TX_CTL_STBC_SHIFT;
+
+	/*
+	 * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the
+	 * mcs rate to be used
+	 */
+	if (txrate->flags & IEEE80211_TX_RC_MCS) {
+		txdesc->mcs = txrate->idx;
+	} else {
+		txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
+		if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+			txdesc->mcs |= 0x08;
+	}
+
 
 	/*
 	 * Convert flags
@@ -84,3 +95,31 @@
 	else
 		txdesc->txop = TXOP_HTTXOP;
 }
+
+u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
+			    struct ieee80211_conf *conf)
+{
+	struct hw_mode_spec *spec = &rt2x00dev->spec;
+	int center_channel;
+	u16 i;
+
+	/*
+	 * Initialize center channel to current channel.
+	 */
+	center_channel = spec->channels[conf->channel->hw_value].channel;
+
+	/*
+	 * Adjust center channel to HT40+ and HT40- operation.
+	 */
+	if (conf_is_ht40_plus(conf))
+		center_channel += 2;
+	else if (conf_is_ht40_minus(conf))
+		center_channel -= (center_channel == 14) ? 1 : 2;
+
+	for (i = 0; i < spec->num_channels; i++)
+		if (spec->channels[i].channel == center_channel)
+			return i;
+
+	WARN_ON(1);
+	return conf->channel->hw_value;
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index be2e37f..dc5c657 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -27,11 +27,10 @@
 #ifndef RT2X00LIB_H
 #define RT2X00LIB_H
 
-#include "rt2x00dump.h"
-
 /*
  * Interval defines
  */
+#define WATCHDOG_INTERVAL	round_jiffies_relative(HZ)
 #define LINK_TUNE_INTERVAL	round_jiffies_relative(HZ)
 
 /*
@@ -107,13 +106,6 @@
 					struct queue_entry *entry);
 
 /**
- * rt2x00queue_unmap_skb - Unmap a skb from DMA.
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- * @skb: The skb to unmap.
- */
-void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
-
-/**
  * rt2x00queue_free_skb - free a skb
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
  * @skb: The skb to free.
@@ -266,11 +258,30 @@
 void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna);
 
 /**
- * rt2x00link_register - Initialize link tuning functionality
+ * rt2x00link_start_watchdog - Start periodic watchdog monitoring
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
  *
- * Initialize work structure and all link tuning related
- * parameters. This will not start the link tuning process itself.
+ * This start the watchdog periodic work, this work will
+ *be executed periodically until &rt2x00link_stop_watchdog has
+ * been called.
+ */
+void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00link_stop_watchdog - Stop periodic watchdog monitoring
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * After this function completed the watchdog monitoring will not
+ * be running until &rt2x00link_start_watchdog is called.
+ */
+void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00link_register - Initialize link tuning & watchdog functionality
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * Initialize work structure and all link tuning and watchdog related
+ * parameters. This will not start the periodic work itself.
  */
 void rt2x00link_register(struct rt2x00_dev *rt2x00dev);
 
@@ -296,8 +307,6 @@
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
 void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
-void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
-			    enum rt2x00_dump_type type, struct sk_buff *skb);
 void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
 			       struct rxdone_entry_desc *rxdesc);
 #else
@@ -309,12 +318,6 @@
 {
 }
 
-static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
-					  enum rt2x00_dump_type type,
-					  struct sk_buff *skb)
-{
-}
-
 static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
 					     struct rxdone_entry_desc *rxdesc)
 {
@@ -384,12 +387,21 @@
 void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
 				   struct txentry_desc *txdesc,
 				   const struct rt2x00_rate *hwrate);
+
+u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
+			    struct ieee80211_conf *conf);
 #else
 static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
 						 struct txentry_desc *txdesc,
 						 const struct rt2x00_rate *hwrate)
 {
 }
+
+static inline u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
+					  struct ieee80211_conf *conf)
+{
+	return conf->channel->hw_value;
+}
 #endif /* CONFIG_RT2X00_LIB_HT */
 
 /*
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index 0efbf5a..666cef3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -271,11 +271,20 @@
 
 	/*
 	 * Link tuning should only be performed when
-	 * an active sta or master interface exists.
-	 * Single monitor mode interfaces should never have
-	 * work with link tuners.
+	 * an active sta interface exists. AP interfaces
+	 * don't need link tuning and monitor mode interfaces
+	 * should never have to work with link tuners.
 	 */
-	if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)
+	if (!rt2x00dev->intf_sta_count)
+		return;
+
+	/**
+	 * While scanning, link tuning is disabled. By default
+	 * the most sensitive settings will be used to make sure
+	 * that all beacons and probe responses will be recieved
+	 * during the scan.
+	 */
+	if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
 		return;
 
 	rt2x00link_reset_tuner(rt2x00dev, false);
@@ -293,6 +302,7 @@
 void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
 {
 	struct link_qual *qual = &rt2x00dev->link.qual;
+	u8 vgc_level = qual->vgc_level_reg;
 
 	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		return;
@@ -309,6 +319,13 @@
 	memset(qual, 0, sizeof(*qual));
 
 	/*
+	 * Restore the VGC level as stored in the registers,
+	 * the driver can use this to determine if the register
+	 * must be updated during reset or not.
+	 */
+	qual->vgc_level_reg = vgc_level;
+
+	/*
 	 * Reset the link tuner.
 	 */
 	rt2x00dev->ops->lib->reset_tuner(rt2x00dev, qual);
@@ -338,7 +355,8 @@
 	 * When the radio is shutting down we should
 	 * immediately cease all link tuning.
 	 */
-	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
+	    test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
 		return;
 
 	/*
@@ -359,10 +377,11 @@
 		qual->rssi = link->avg_rssi.avg;
 
 	/*
-	 * Only perform the link tuning when Link tuning
-	 * has been enabled (This could have been disabled from the EEPROM).
+	 * Check if link tuning is supported by the hardware, some hardware
+	 * do not support link tuning at all, while other devices can disable
+	 * the feature from the EEPROM.
 	 */
-	if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
+	if (test_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags))
 		rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
 
 	/*
@@ -388,7 +407,45 @@
 					     &link->work, LINK_TUNE_INTERVAL);
 }
 
+void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+	struct link *link = &rt2x00dev->link;
+
+	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
+	    !test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags))
+		return;
+
+	ieee80211_queue_delayed_work(rt2x00dev->hw,
+				     &link->watchdog_work, WATCHDOG_INTERVAL);
+}
+
+void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+	cancel_delayed_work_sync(&rt2x00dev->link.watchdog_work);
+}
+
+static void rt2x00link_watchdog(struct work_struct *work)
+{
+	struct rt2x00_dev *rt2x00dev =
+	    container_of(work, struct rt2x00_dev, link.watchdog_work.work);
+	struct link *link = &rt2x00dev->link;
+
+	/*
+	 * When the radio is shutting down we should
+	 * immediately cease the watchdog monitoring.
+	 */
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		return;
+
+	rt2x00dev->ops->lib->watchdog(rt2x00dev);
+
+	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+		ieee80211_queue_delayed_work(rt2x00dev->hw,
+					     &link->watchdog_work, WATCHDOG_INTERVAL);
+}
+
 void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
 {
+	INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog);
 	INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
 }
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index abbd857..235e037 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -273,16 +273,24 @@
 	mutex_init(&intf->beacon_skb_mutex);
 	intf->beacon = entry;
 
-	if (vif->type == NL80211_IFTYPE_AP)
-		memcpy(&intf->bssid, vif->addr, ETH_ALEN);
-	memcpy(&intf->mac, vif->addr, ETH_ALEN);
-
 	/*
 	 * The MAC adddress must be configured after the device
 	 * has been initialized. Otherwise the device can reset
 	 * the MAC registers.
+	 * The BSSID address must only be configured in AP mode,
+	 * however we should not send an empty BSSID address for
+	 * STA interfaces at this time, since this can cause
+	 * invalid behavior in the device.
 	 */
-	rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, NULL);
+	memcpy(&intf->mac, vif->addr, ETH_ALEN);
+	if (vif->type == NL80211_IFTYPE_AP) {
+		memcpy(&intf->bssid, vif->addr, ETH_ALEN);
+		rt2x00lib_config_intf(rt2x00dev, intf, vif->type,
+				      intf->mac, intf->bssid);
+	} else {
+		rt2x00lib_config_intf(rt2x00dev, intf, vif->type,
+				      intf->mac, NULL);
+	}
 
 	/*
 	 * Some filters depend on the current working mode. We can force
@@ -346,9 +354,11 @@
 	/*
 	 * Some configuration parameters (e.g. channel and antenna values) can
 	 * only be set when the radio is enabled, but do require the RX to
-	 * be off.
+	 * be off. During this period we should keep link tuning enabled,
+	 * if for any reason the link tuner must be reset, this will be
+	 * handled by rt2x00lib_config().
 	 */
-	rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
+	rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK);
 
 	/*
 	 * When we've just turned on the radio, we want to reprogram
@@ -366,7 +376,7 @@
 	rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant);
 
 	/* Turn RX back on */
-	rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+	rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
 
 	return 0;
 }
@@ -430,12 +440,36 @@
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
 
+static void rt2x00mac_set_tim_iter(void *data, u8 *mac,
+				   struct ieee80211_vif *vif)
+{
+	struct rt2x00_intf *intf = vif_to_intf(vif);
+
+	if (vif->type != NL80211_IFTYPE_AP &&
+	    vif->type != NL80211_IFTYPE_ADHOC &&
+	    vif->type != NL80211_IFTYPE_MESH_POINT &&
+	    vif->type != NL80211_IFTYPE_WDS)
+		return;
+
+	spin_lock(&intf->lock);
+	intf->delayed_flags |= DELAYED_UPDATE_BEACON;
+	spin_unlock(&intf->lock);
+}
+
 int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
 		      bool set)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 
-	rt2x00lib_beacondone(rt2x00dev);
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		return 0;
+
+	ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
+						   rt2x00mac_set_tim_iter,
+						   rt2x00dev);
+
+	/* queue work to upodate the beacon template */
+	ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
@@ -539,6 +573,22 @@
 EXPORT_SYMBOL_GPL(rt2x00mac_set_key);
 #endif /* CONFIG_RT2X00_LIB_CRYPTO */
 
+void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	__set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
+	rt2x00link_stop_tuner(rt2x00dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start);
+
+void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	__clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
+	rt2x00link_start_tuner(rt2x00dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_complete);
+
 int rt2x00mac_get_stats(struct ieee80211_hw *hw,
 			struct ieee80211_low_level_stats *stats)
 {
@@ -562,7 +612,6 @@
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct rt2x00_intf *intf = vif_to_intf(vif);
-	int update_bssid = 0;
 
 	/*
 	 * mac80211 might be calling this function while we are trying
@@ -577,10 +626,8 @@
 	 * conf->bssid can be NULL if coming from the internal
 	 * beacon update routine.
 	 */
-	if (changes & BSS_CHANGED_BSSID) {
-		update_bssid = 1;
+	if (changes & BSS_CHANGED_BSSID)
 		memcpy(&intf->bssid, bss_conf->bssid, ETH_ALEN);
-	}
 
 	spin_unlock(&intf->lock);
 
@@ -592,7 +639,7 @@
 	 */
 	if (changes & BSS_CHANGED_BSSID)
 		rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,
-				      update_bssid ? bss_conf->bssid : NULL);
+				      bss_conf->bssid);
 
 	/*
 	 * Update the beacon.
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index f71eee6..19b262e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -60,34 +60,6 @@
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
 
-/*
- * TX data handlers.
- */
-int rt2x00pci_write_tx_data(struct queue_entry *entry,
-			    struct txentry_desc *txdesc)
-{
-	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-
-	/*
-	 * This should not happen, we already checked the entry
-	 * was ours. When the hardware disagrees there has been
-	 * a queue corruption!
-	 */
-	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);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
-
-/*
- * TX/RX data handlers.
- */
 void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 {
 	struct data_queue *queue = rt2x00dev->rx;
@@ -181,8 +153,10 @@
 	/*
 	 * Register interrupt handler.
 	 */
-	status = request_irq(rt2x00dev->irq, rt2x00dev->ops->lib->irq_handler,
-			     IRQF_SHARED, rt2x00dev->name, rt2x00dev);
+	status = request_threaded_irq(rt2x00dev->irq,
+				      rt2x00dev->ops->lib->irq_handler,
+				      rt2x00dev->ops->lib->irq_handler_thread,
+				      IRQF_SHARED, rt2x00dev->name, rt2x00dev);
 	if (status) {
 		ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
 		      rt2x00dev->irq, status);
@@ -305,7 +279,10 @@
 	rt2x00dev->irq = pci_dev->irq;
 	rt2x00dev->name = pci_name(pci_dev);
 
-	rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
+	if (pci_dev->is_pcie)
+		rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
+	else
+		rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
 
 	retval = rt2x00pci_alloc_reg(rt2x00dev);
 	if (retval)
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 51bcef3..b854d62 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -86,16 +86,6 @@
 			   u32 *reg);
 
 /**
- * rt2x00pci_write_tx_data - Initialize data for TX operation
- * @entry: The entry where the frame is located
- *
- * This function will initialize the DMA and skb descriptor
- * to prepare the entry for the actual TX operation.
- */
-int rt2x00pci_write_tx_data(struct queue_entry *entry,
-			    struct txentry_desc *txdesc);
-
-/**
  * struct queue_entry_priv_pci: Per entry PCI specific information
  *
  * @desc: Pointer to device descriptor
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 20dbdd6..a3401d3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -100,21 +100,8 @@
 {
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
 
-	/*
-	 * If device has requested headroom, we should make sure that
-	 * is also mapped to the DMA so it can be used for transfering
-	 * additional descriptor information to the hardware.
-	 */
-	skb_push(skb, rt2x00dev->ops->extra_tx_headroom);
-
 	skbdesc->skb_dma =
 	    dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
-
-	/*
-	 * Restore data pointer to original location again.
-	 */
-	skb_pull(skb, rt2x00dev->ops->extra_tx_headroom);
-
 	skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
 }
 EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
@@ -130,16 +117,12 @@
 	}
 
 	if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
-		/*
-		 * Add headroom to the skb length, it has been removed
-		 * by the driver, but it was actually mapped to DMA.
-		 */
-		dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma,
-				 skb->len + rt2x00dev->ops->extra_tx_headroom,
+		dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
 				 DMA_TO_DEVICE);
 		skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
 	}
 }
+EXPORT_SYMBOL_GPL(rt2x00queue_unmap_skb);
 
 void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
 {
@@ -370,13 +353,18 @@
 	/*
 	 * Check if more fragments are pending
 	 */
-	if (ieee80211_has_morefrags(hdr->frame_control) ||
-	    (tx_info->flags & IEEE80211_TX_CTL_MORE_FRAMES)) {
+	if (ieee80211_has_morefrags(hdr->frame_control)) {
 		__set_bit(ENTRY_TXD_BURST, &txdesc->flags);
 		__set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags);
 	}
 
 	/*
+	 * Check if more frames (!= fragments) are pending
+	 */
+	if (tx_info->flags & IEEE80211_TX_CTL_MORE_FRAMES)
+		__set_bit(ENTRY_TXD_BURST, &txdesc->flags);
+
+	/*
 	 * Beacons and probe responses require the tsf timestamp
 	 * to be inserted into the frame, except for a frame that has been injected
 	 * through a monitor interface. This latter is needed for testing a
@@ -416,12 +404,51 @@
 	rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate);
 }
 
+static int rt2x00queue_write_tx_data(struct queue_entry *entry,
+				     struct txentry_desc *txdesc)
+{
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+
+	/*
+	 * This should not happen, we already checked the entry
+	 * was ours. When the hardware disagrees there has been
+	 * a queue corruption!
+	 */
+	if (unlikely(rt2x00dev->ops->lib->get_entry_state &&
+		     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);
+		return -EINVAL;
+	}
+
+	/*
+	 * Add the requested extra tx headroom in front of the skb.
+	 */
+	skb_push(entry->skb, rt2x00dev->ops->extra_tx_headroom);
+	memset(entry->skb->data, 0, rt2x00dev->ops->extra_tx_headroom);
+
+	/*
+	 * Call the driver's write_tx_data function, if it exists.
+	 */
+	if (rt2x00dev->ops->lib->write_tx_data)
+		rt2x00dev->ops->lib->write_tx_data(entry, txdesc);
+
+	/*
+	 * Map the skb to DMA.
+	 */
+	if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
+		rt2x00queue_map_txskb(rt2x00dev, entry->skb);
+
+	return 0;
+}
+
 static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
 					    struct txentry_desc *txdesc)
 {
 	struct data_queue *queue = entry->queue;
 	struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
-	enum rt2x00_dump_type dump_type;
 
 	rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
 
@@ -429,9 +456,7 @@
 	 * All processing on the frame has been completed, this means
 	 * it is now ready to be dumped to userspace through debugfs.
 	 */
-	dump_type = (txdesc->queue == QID_BEACON) ?
-					DUMP_FRAME_BEACON : DUMP_FRAME_TX;
-	rt2x00debug_dump_frame(rt2x00dev, dump_type, entry->skb);
+	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
 }
 
 static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
@@ -530,16 +555,12 @@
 	 * 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,
-							       &txdesc))) {
+	if (unlikely(rt2x00queue_write_tx_data(entry, &txdesc))) {
 		clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
 		entry->skb = NULL;
 		return -EIO;
 	}
 
-	if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
-		rt2x00queue_map_txskb(queue->rt2x00dev, skb);
-
 	set_bit(ENTRY_DATA_PENDING, &entry->flags);
 
 	rt2x00queue_index_inc(queue, Q_INDEX);
@@ -595,11 +616,6 @@
 	skbdesc->entry = intf->beacon;
 
 	/*
-	 * Write TX descriptor into reserved room in front of the beacon.
-	 */
-	rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
-
-	/*
 	 * Send beacon to hardware and enable beacon genaration..
 	 */
 	rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
@@ -672,9 +688,11 @@
 
 	if (index == Q_INDEX) {
 		queue->length++;
+		queue->last_index = jiffies;
 	} else if (index == Q_INDEX_DONE) {
 		queue->length--;
 		queue->count++;
+		queue->last_index_done = jiffies;
 	}
 
 	spin_unlock_irqrestore(&queue->lock, irqflags);
@@ -688,6 +706,8 @@
 
 	queue->count = 0;
 	queue->length = 0;
+	queue->last_index = jiffies;
+	queue->last_index_done = jiffies;
 	memset(queue->index, 0, sizeof(queue->index));
 
 	spin_unlock_irqrestore(&queue->lock, irqflags);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index f791708..191e777 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -213,9 +213,16 @@
 /**
  * enum txdone_entry_desc_flags: Flags for &struct txdone_entry_desc
  *
+ * Every txdone report has to contain the basic result of the
+ * transmission, either &TXDONE_UNKNOWN, &TXDONE_SUCCESS or
+ * &TXDONE_FAILURE. The flag &TXDONE_FALLBACK can be used in
+ * conjunction with all of these flags but should only be set
+ * if retires > 0. The flag &TXDONE_EXCESSIVE_RETRY can only be used
+ * in conjunction with &TXDONE_FAILURE.
+ *
  * @TXDONE_UNKNOWN: Hardware could not determine success of transmission.
  * @TXDONE_SUCCESS: Frame was successfully send
- * @TXDONE_FALLBACK: Frame was successfully send using a fallback rate.
+ * @TXDONE_FALLBACK: Hardware used fallback rates for retries
  * @TXDONE_FAILURE: Frame was not successfully send
  * @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the
  *	frame transmission failed due to excessive retries.
@@ -439,6 +446,8 @@
 	enum data_queue_qid qid;
 
 	spinlock_t lock;
+	unsigned long last_index;
+	unsigned long last_index_done;
 	unsigned int count;
 	unsigned short limit;
 	unsigned short threshold;
@@ -592,6 +601,15 @@
 }
 
 /**
+ * rt2x00queue_timeout - Check if a timeout occured for this queue
+ * @queue: Queue to check.
+ */
+static inline int rt2x00queue_timeout(struct data_queue *queue)
+{
+	return time_after(queue->last_index, queue->last_index_done + (HZ / 10));
+}
+
+/**
  * _rt2x00_desc_read - Read a word from the hardware descriptor.
  * @desc: Base descriptor address
  * @word: Word index from where the descriptor should be read.
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index b9fe948..cef9462 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -63,7 +63,8 @@
 enum tsf_sync {
 	TSF_SYNC_NONE = 0,
 	TSF_SYNC_INFRA = 1,
-	TSF_SYNC_BEACON = 2,
+	TSF_SYNC_ADHOC = 2,
+	TSF_SYNC_AP_NONE = 3,
 };
 
 /*
@@ -88,6 +89,8 @@
 	STATE_RADIO_RX_OFF_LINK,
 	STATE_RADIO_IRQ_ON,
 	STATE_RADIO_IRQ_OFF,
+	STATE_RADIO_IRQ_ON_ISR,
+	STATE_RADIO_IRQ_OFF_ISR,
 };
 
 /*
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index bd1546b..ff3a366 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -113,26 +113,6 @@
 				  const u16 offset, void *buffer,
 				  const u16 buffer_length, const int timeout)
 {
-	int status;
-
-	mutex_lock(&rt2x00dev->csr_mutex);
-
-	status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
-						requesttype, offset, buffer,
-						buffer_length, timeout);
-
-	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	return status;
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
-
-int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
-					const u8 request, const u8 requesttype,
-					const u16 offset, const void *buffer,
-					const u16 buffer_length,
-					const int timeout)
-{
 	int status = 0;
 	unsigned char *tb;
 	u16 off, len, bsize;
@@ -157,7 +137,7 @@
 
 	return status;
 }
-EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff);
+EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
 
 int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
 			   const unsigned int offset,
@@ -216,48 +196,28 @@
 	rt2x00lib_txdone(entry, &txdesc);
 }
 
-int rt2x00usb_write_tx_data(struct queue_entry *entry,
-			    struct txentry_desc *txdesc)
+static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
 {
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
 	struct queue_entry_priv_usb *entry_priv = entry->priv_data;
 	u32 length;
 
-	/*
-	 * Add the descriptor in front of the skb.
-	 */
-	skb_push(entry->skb, entry->queue->desc_size);
-	memset(entry->skb->data, 0, entry->queue->desc_size);
+	if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) {
+		/*
+		 * USB devices cannot blindly pass the skb->len as the
+		 * 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(entry);
 
-	/*
-	 * USB devices cannot blindly pass the skb->len as the
-	 * 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(entry);
+		usb_fill_bulk_urb(entry_priv->urb, usb_dev,
+				  usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
+				  entry->skb->data, length,
+				  rt2x00usb_interrupt_txdone, entry);
 
-	usb_fill_bulk_urb(entry_priv->urb, usb_dev,
-			  usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
-			  entry->skb->data, length,
-			  rt2x00usb_interrupt_txdone, entry);
-
-	/*
-	 * Make sure the skb->data pointer points to the frame, not the
-	 * descriptor.
-	 */
-	skb_pull(entry->skb, entry->queue->desc_size);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);
-
-static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
-{
-	struct queue_entry_priv_usb *entry_priv = entry->priv_data;
-
-	if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
 		usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+	}
 }
 
 void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
@@ -332,6 +292,56 @@
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
 
+static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
+{
+	struct queue_entry_priv_usb *entry_priv;
+	unsigned short threshold = queue->threshold;
+
+	WARNING(queue->rt2x00dev, "TX queue %d timed out, invoke reset", queue->qid);
+
+	/*
+	 * Temporarily disable the TX queue, this will force mac80211
+	 * to use the other queues until this queue has been restored.
+	 *
+	 * Set the queue threshold to the queue limit. This prevents the
+	 * queue from being enabled during the txdone handler.
+	 */
+	queue->threshold = queue->limit;
+	ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid);
+
+	/*
+	 * Reset all currently uploaded TX frames.
+	 */
+	while (!rt2x00queue_empty(queue)) {
+		entry_priv = rt2x00queue_get_entry(queue, Q_INDEX_DONE)->priv_data;
+		usb_kill_urb(entry_priv->urb);
+
+		/*
+		 * We need a short delay here to wait for
+		 * the URB to be canceled and invoked the tx_done handler.
+		 */
+		udelay(200);
+	}
+
+	/*
+	 * The queue has been reset, and mac80211 is allowed to use the
+	 * queue again.
+	 */
+	queue->threshold = threshold;
+	ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
+}
+
+void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_queue *queue;
+
+	tx_queue_for_each(rt2x00dev, queue) {
+		if (rt2x00queue_timeout(queue))
+			rt2x00usb_watchdog_reset_tx(queue);
+	}
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
+
 /*
  * RX data handlers.
  */
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 621d0f8..d3d3ddc 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -167,25 +167,6 @@
 				   const u16 buffer_length, const int timeout);
 
 /**
- * rt2x00usb_vendor_request_large_buff - Send register command to device (buffered)
- * @rt2x00dev: Pointer to &struct rt2x00_dev
- * @request: USB vendor command (See &enum rt2x00usb_vendor_request)
- * @requesttype: Request type &USB_VENDOR_REQUEST_*
- * @offset: Register start offset to perform action on
- * @buffer: Buffer where information will be read/written to by device
- * @buffer_length: Size of &buffer
- * @timeout: Operation timeout
- *
- * This function is used to transfer register data in blocks larger
- * then CSR_CACHE_SIZE. Use for firmware upload, keys and beacons.
- */
-int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
-					const u8 request, const u8 requesttype,
-					const u16 offset, const void *buffer,
-					const u16 buffer_length,
-					const int timeout);
-
-/**
  * rt2x00usb_vendor_request_sw - Send single register command to device
  * @rt2x00dev: Pointer to &struct rt2x00_dev
  * @request: USB vendor command (See &enum rt2x00usb_vendor_request)
@@ -370,16 +351,6 @@
 void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);
 
 /**
- * rt2x00usb_write_tx_data - Initialize URB for TX operation
- * @entry: The entry where the frame is located
- *
- * This function will initialize the URB and skb descriptor
- * to prepare the entry for the actual TX operation.
- */
-int rt2x00usb_write_tx_data(struct queue_entry *entry,
-			    struct txentry_desc *txdesc);
-
-/**
  * struct queue_entry_priv_usb: Per entry USB specific information
  *
  * @urb: Urb structure used for device communication.
@@ -428,6 +399,16 @@
 void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
 			      const enum data_queue_qid qid);
 
+/**
+ * rt2x00usb_watchdog - Watchdog for USB communication
+ * @rt2x00dev: Pointer to &struct rt2x00_dev
+ *
+ * Check the health of the USB communication and determine
+ * if timeouts have occured. If this is the case, this function
+ * will reset all communication to restore functionality again.
+ */
+void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev);
+
 /*
  * Device initialization handlers.
  */
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 6a74baf..e539c6c 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -931,6 +931,9 @@
 	u32 reg;
 
 	rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_RATE_DOWN, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_RATE_STEP, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_FALLBACK_CCK, 0);
 	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,
@@ -1619,7 +1622,8 @@
 static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
 			       enum dev_state state)
 {
-	int mask = (state == STATE_RADIO_IRQ_OFF);
+	int mask = (state == STATE_RADIO_IRQ_OFF) ||
+		   (state == STATE_RADIO_IRQ_OFF_ISR);
 	u32 reg;
 
 	/*
@@ -1736,7 +1740,9 @@
 		rt61pci_toggle_rx(rt2x00dev, state);
 		break;
 	case STATE_RADIO_IRQ_ON:
+	case STATE_RADIO_IRQ_ON_ISR:
 	case STATE_RADIO_IRQ_OFF:
+	case STATE_RADIO_IRQ_OFF_ISR:
 		rt61pci_toggle_irq(rt2x00dev, state);
 		break;
 	case STATE_DEEP_SLEEP:
@@ -1874,6 +1880,16 @@
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
 
 	/*
+	 * Write the TX descriptor for the beacon.
+	 */
+	rt61pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+	/*
+	 * Dump beacon to userspace through debugfs.
+	 */
+	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
+
+	/*
 	 * Write entire beacon with descriptor to register.
 	 */
 	beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
@@ -2039,29 +2055,24 @@
 	struct txdone_entry_desc txdesc;
 	u32 word;
 	u32 reg;
-	u32 old_reg;
 	int type;
 	int index;
+	int i;
 
 	/*
-	 * During each loop we will compare the freshly read
-	 * STA_CSR4 register value with the value read from
-	 * the previous loop. If the 2 values are equal then
-	 * we should stop processing because the chance is
-	 * quite big that the device has been unplugged and
-	 * we risk going into an endless loop.
+	 * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
+	 * at most X times and also stop processing once the TX_STA_FIFO_VALID
+	 * flag is not set anymore.
+	 *
+	 * The legacy drivers use X=TX_RING_SIZE but state in a comment
+	 * that the TX_STA_FIFO stack has a size of 16. We stick to our
+	 * tx ring size for now.
 	 */
-	old_reg = 0;
-
-	while (1) {
+	for (i = 0; i < TX_ENTRIES; i++) {
 		rt2x00pci_register_read(rt2x00dev, STA_CSR4, &reg);
 		if (!rt2x00_get_field32(reg, STA_CSR4_VALID))
 			break;
 
-		if (old_reg == reg)
-			break;
-		old_reg = reg;
-
 		/*
 		 * Skip this entry when it contains an invalid
 		 * queue identication number.
@@ -2120,6 +2131,13 @@
 		}
 		txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
 
+		/*
+		 * the frame was retried at least once
+		 * -> hw used fallback rates
+		 */
+		if (txdesc.retry)
+			__set_bit(TXDONE_FALLBACK, &txdesc.flags);
+
 		rt2x00lib_txdone(entry, &txdesc);
 	}
 }
@@ -2132,27 +2150,11 @@
 	rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
 }
 
-static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
+static irqreturn_t rt61pci_interrupt_thread(int irq, void *dev_instance)
 {
 	struct rt2x00_dev *rt2x00dev = dev_instance;
-	u32 reg_mcu;
-	u32 reg;
-
-	/*
-	 * Get the interrupt sources & saved to local variable.
-	 * Write register value back to clear pending interrupts.
-	 */
-	rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg_mcu);
-	rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
-
-	rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
-	rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
-
-	if (!reg && !reg_mcu)
-		return IRQ_NONE;
-
-	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
-		return IRQ_HANDLED;
+	u32 reg = rt2x00dev->irqvalue[0];
+	u32 reg_mcu = rt2x00dev->irqvalue[1];
 
 	/*
 	 * Handle interrupts, walk through all bits
@@ -2185,9 +2187,51 @@
 	if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP))
 		rt61pci_wakeup(rt2x00dev);
 
+	/*
+	 * 5 - Beacon done interrupt.
+	 */
+	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE))
+		rt2x00lib_beacondone(rt2x00dev);
+
+	/* Enable interrupts again. */
+	rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+					      STATE_RADIO_IRQ_ON_ISR);
 	return IRQ_HANDLED;
 }
 
+
+static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
+{
+	struct rt2x00_dev *rt2x00dev = dev_instance;
+	u32 reg_mcu;
+	u32 reg;
+
+	/*
+	 * Get the interrupt sources & saved to local variable.
+	 * Write register value back to clear pending interrupts.
+	 */
+	rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg_mcu);
+	rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
+
+	rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+	rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+
+	if (!reg && !reg_mcu)
+		return IRQ_NONE;
+
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		return IRQ_HANDLED;
+
+	/* Store irqvalues for use in the interrupt thread. */
+	rt2x00dev->irqvalue[0] = reg;
+	rt2x00dev->irqvalue[1] = reg_mcu;
+
+	/* Disable interrupts, will be enabled again in the interrupt thread. */
+	rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+					      STATE_RADIO_IRQ_OFF_ISR);
+	return IRQ_WAKE_THREAD;
+}
+
 /*
  * Device probe functions.
  */
@@ -2577,6 +2621,18 @@
 						   EEPROM_MAC_ADDR_0));
 
 	/*
+	 * As rt61 has a global fallback table we cannot specify
+	 * more then one tx rate per frame but since the hw will
+	 * try several rates (based on the fallback table) we should
+	 * still initialize max_rates to the maximum number of rates
+	 * we are going to try. Otherwise mac80211 will truncate our
+	 * reported tx rates and the rc algortihm will end up with
+	 * incorrect data.
+	 */
+	rt2x00dev->hw->max_rates = 7;
+	rt2x00dev->hw->max_rate_tries = 1;
+
+	/*
 	 * Initialize hw_mode information.
 	 */
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
@@ -2657,6 +2713,7 @@
 	__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
 	if (!modparam_nohwcrypt)
 		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
+	__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
 
 	/*
 	 * Set the rssi offset.
@@ -2748,8 +2805,9 @@
 	.remove_interface	= rt2x00mac_remove_interface,
 	.config			= rt2x00mac_config,
 	.configure_filter	= rt2x00mac_configure_filter,
-	.set_tim		= rt2x00mac_set_tim,
 	.set_key		= rt2x00mac_set_key,
+	.sw_scan_start		= rt2x00mac_sw_scan_start,
+	.sw_scan_complete	= rt2x00mac_sw_scan_complete,
 	.get_stats		= rt2x00mac_get_stats,
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt61pci_conf_tx,
@@ -2759,6 +2817,7 @@
 
 static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
 	.irq_handler		= rt61pci_interrupt,
+	.irq_handler_thread	= rt61pci_interrupt_thread,
 	.probe_hw		= rt61pci_probe_hw,
 	.get_firmware_name	= rt61pci_get_firmware_name,
 	.check_firmware		= rt61pci_check_firmware,
@@ -2773,7 +2832,6 @@
 	.reset_tuner		= rt61pci_reset_tuner,
 	.link_tuner		= rt61pci_link_tuner,
 	.write_tx_desc		= rt61pci_write_tx_desc,
-	.write_tx_data		= rt2x00pci_write_tx_data,
 	.write_beacon		= rt61pci_write_beacon,
 	.kick_tx_queue		= rt61pci_kick_tx_queue,
 	.kill_tx_queue		= rt61pci_kill_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index df80f1a..e2e728a 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -153,13 +153,13 @@
 	u8 key[16];
 	u8 tx_mic[8];
 	u8 rx_mic[8];
-} __attribute__ ((packed));
+} __packed;
 
 struct hw_pairwise_ta_entry {
 	u8 address[6];
 	u8 cipher;
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * Other on-chip shared memory space.
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 6e0d82e..aa9de18 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -270,7 +270,6 @@
 {
 	struct hw_key_entry key_entry;
 	struct rt2x00_field32 field;
-	int timeout;
 	u32 mask;
 	u32 reg;
 
@@ -306,12 +305,8 @@
 		       sizeof(key_entry.rx_mic));
 
 		reg = SHARED_KEY_ENTRY(key->hw_key_idx);
-		timeout = REGISTER_TIMEOUT32(sizeof(key_entry));
-		rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
-						    USB_VENDOR_REQUEST_OUT, reg,
-						    &key_entry,
-						    sizeof(key_entry),
-						    timeout);
+		rt2x00usb_register_multiwrite(rt2x00dev, reg,
+					      &key_entry, sizeof(key_entry));
 
 		/*
 		 * The cipher types are stored over 2 registers.
@@ -372,7 +367,6 @@
 {
 	struct hw_pairwise_ta_entry addr_entry;
 	struct hw_key_entry key_entry;
-	int timeout;
 	u32 mask;
 	u32 reg;
 
@@ -407,17 +401,11 @@
 		       sizeof(key_entry.rx_mic));
 
 		reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
-		timeout = REGISTER_TIMEOUT32(sizeof(key_entry));
-		rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
-						    USB_VENDOR_REQUEST_OUT, reg,
-						    &key_entry,
-						    sizeof(key_entry),
-						    timeout);
+		rt2x00usb_register_multiwrite(rt2x00dev, reg,
+					      &key_entry, sizeof(key_entry));
 
 		/*
 		 * Send the address and cipher type to the hardware register.
-		 * This data fits within the CSR cache size, so we can use
-		 * rt2x00usb_register_multiwrite() directly.
 		 */
 		memset(&addr_entry, 0, sizeof(addr_entry));
 		memcpy(&addr_entry, crypto->address, ETH_ALEN);
@@ -828,6 +816,9 @@
 	u32 reg;
 
 	rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_RATE_DOWN, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_RATE_STEP, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_FALLBACK_CCK, 0);
 	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,
@@ -1092,11 +1083,7 @@
 	/*
 	 * Write firmware to device.
 	 */
-	rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
-					    USB_VENDOR_REQUEST_OUT,
-					    FIRMWARE_IMAGE_BASE,
-					    data, len,
-					    REGISTER_TIMEOUT32(len));
+	rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, data, len);
 
 	/*
 	 * Send firmware request to device to load firmware,
@@ -1413,7 +1400,9 @@
 		rt73usb_toggle_rx(rt2x00dev, state);
 		break;
 	case STATE_RADIO_IRQ_ON:
+	case STATE_RADIO_IRQ_ON_ISR:
 	case STATE_RADIO_IRQ_OFF:
+	case STATE_RADIO_IRQ_OFF_ISR:
 		/* No support, but no error either */
 		break;
 	case STATE_DEEP_SLEEP:
@@ -1442,7 +1431,7 @@
 				  struct txentry_desc *txdesc)
 {
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-	__le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
+	__le32 *txd = (__le32 *) skb->data;
 	u32 word;
 
 	/*
@@ -1505,6 +1494,7 @@
 	/*
 	 * Register descriptor details in skb frame descriptor.
 	 */
+	skbdesc->flags |= SKBDESC_DESC_IN_SKB;
 	skbdesc->desc = txd;
 	skbdesc->desc_len = TXD_DESC_SIZE;
 }
@@ -1528,18 +1518,27 @@
 	rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 
 	/*
-	 * Take the descriptor in front of the skb into account.
+	 * Add space for the descriptor in front of the skb.
 	 */
 	skb_push(entry->skb, TXD_DESC_SIZE);
+	memset(entry->skb->data, 0, TXD_DESC_SIZE);
+
+	/*
+	 * Write the TX descriptor for the beacon.
+	 */
+	rt73usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+	/*
+	 * Dump beacon to userspace through debugfs.
+	 */
+	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
 
 	/*
 	 * Write entire beacon with descriptor to register.
 	 */
 	beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
-	rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
-					    USB_VENDOR_REQUEST_OUT, beacon_base,
-					    entry->skb->data, entry->skb->len,
-					    REGISTER_TIMEOUT32(entry->skb->len));
+	rt2x00usb_register_multiwrite(rt2x00dev, beacon_base,
+				      entry->skb->data, entry->skb->len);
 
 	/*
 	 * Enable beaconing again.
@@ -2138,6 +2137,8 @@
 	__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
 	if (!modparam_nohwcrypt)
 		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
+	__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
+	__set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
 
 	/*
 	 * Set the rssi offset.
@@ -2231,6 +2232,8 @@
 	.configure_filter	= rt2x00mac_configure_filter,
 	.set_tim		= rt2x00mac_set_tim,
 	.set_key		= rt2x00mac_set_key,
+	.sw_scan_start		= rt2x00mac_sw_scan_start,
+	.sw_scan_complete	= rt2x00mac_sw_scan_complete,
 	.get_stats		= rt2x00mac_get_stats,
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt73usb_conf_tx,
@@ -2251,8 +2254,8 @@
 	.link_stats		= rt73usb_link_stats,
 	.reset_tuner		= rt73usb_reset_tuner,
 	.link_tuner		= rt73usb_link_tuner,
+	.watchdog		= rt2x00usb_watchdog,
 	.write_tx_desc		= rt73usb_write_tx_desc,
-	.write_tx_data		= rt2x00usb_write_tx_data,
 	.write_beacon		= rt73usb_write_beacon,
 	.get_tx_data_len	= rt73usb_get_tx_data_len,
 	.kick_tx_queue		= rt2x00usb_kick_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 7abe7eb..44d5b2b 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -108,13 +108,13 @@
 	u8 key[16];
 	u8 tx_mic[8];
 	u8 rx_mic[8];
-} __attribute__ ((packed));
+} __packed;
 
 struct hw_pairwise_ta_entry {
 	u8 address[6];
 	u8 cipher;
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * Since NULL frame won't be that long (256 byte),
diff --git a/drivers/net/wireless/rtl818x/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180.h
index 4baf0cf..3052331 100644
--- a/drivers/net/wireless/rtl818x/rtl8180.h
+++ b/drivers/net/wireless/rtl818x/rtl8180.h
@@ -36,7 +36,7 @@
 	u8 agc;
 	u8 flags2;
 	u32 reserved[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct rtl8180_rx_desc {
 	__le32 flags;
@@ -45,7 +45,7 @@
 		__le32 rx_buf;
 		__le64 tsft;
 	};
-} __attribute__ ((packed));
+} __packed;
 
 struct rtl8180_tx_ring {
 	struct rtl8180_tx_desc *desc;
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index 515817d..1d81785 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -103,6 +103,7 @@
 {
 	struct rtl8180_priv *priv = dev->priv;
 	unsigned int count = 32;
+	u8 signal, agc, sq;
 
 	while (count--) {
 		struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
@@ -130,10 +131,18 @@
 			skb_put(skb, flags & 0xFFF);
 
 			rx_status.antenna = (flags2 >> 15) & 1;
-			/* TODO: improve signal/rssi reporting */
-			rx_status.signal = (flags2 >> 8) & 0x7F;
-			/* XXX: is this correct? */
 			rx_status.rate_idx = (flags >> 20) & 0xF;
+			agc = (flags2 >> 17) & 0x7F;
+			if (priv->r8185) {
+				if (rx_status.rate_idx > 3)
+					signal = 90 - clamp_t(u8, agc, 25, 90);
+				else
+					signal = 95 - clamp_t(u8, agc, 30, 95);
+			} else {
+				sq = flags2 & 0xff;
+				signal = priv->rf->calc_rssi(agc, sq);
+			}
+			rx_status.signal = signal;
 			rx_status.freq = dev->conf.channel->center_freq;
 			rx_status.band = dev->conf.channel->band;
 			rx_status.mactime = le64_to_cpu(entry->tsft);
@@ -352,7 +361,7 @@
 
 	/* check success of reset */
 	if (rtl818x_ioread8(priv, &priv->map->CMD) & RTL818X_CMD_RESET) {
-		printk(KERN_ERR "%s: reset timeout!\n", wiphy_name(dev->wiphy));
+		wiphy_err(dev->wiphy, "reset timeout!\n");
 		return -ETIMEDOUT;
 	}
 
@@ -436,8 +445,7 @@
 					     &priv->rx_ring_dma);
 
 	if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) {
-		printk(KERN_ERR "%s: Cannot allocate RX ring\n",
-		       wiphy_name(dev->wiphy));
+		wiphy_err(dev->wiphy, "cannot allocate rx ring\n");
 		return -ENOMEM;
 	}
 
@@ -494,8 +502,8 @@
 
 	ring = pci_alloc_consistent(priv->pdev, sizeof(*ring) * entries, &dma);
 	if (!ring || (unsigned long)ring & 0xFF) {
-		printk(KERN_ERR "%s: Cannot allocate TX ring (prio = %d)\n",
-		       wiphy_name(dev->wiphy), prio);
+		wiphy_err(dev->wiphy, "cannot allocate tx ring (prio = %d)\n",
+			  prio);
 		return -ENOMEM;
 	}
 
@@ -560,8 +568,7 @@
 	ret = request_irq(priv->pdev->irq, rtl8180_interrupt,
 			  IRQF_SHARED, KBUILD_MODNAME, dev);
 	if (ret) {
-		printk(KERN_ERR "%s: failed to register IRQ handler\n",
-		       wiphy_name(dev->wiphy));
+		wiphy_err(dev->wiphy, "failed to register irq handler\n");
 		goto err_free_rings;
 	}
 
@@ -671,7 +678,7 @@
 	       (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
 }
 
-void rtl8180_beacon_work(struct work_struct *work)
+static void rtl8180_beacon_work(struct work_struct *work)
 {
 	struct rtl8180_vif *vif_priv =
 		container_of(work, struct rtl8180_vif, beacon_work.work);
@@ -1098,9 +1105,8 @@
 		goto err_iounmap;
 	}
 
-	printk(KERN_INFO "%s: hwaddr %pM, %s + %s\n",
-	       wiphy_name(dev->wiphy), mac_addr,
-	       chip_name, priv->rf->name);
+	wiphy_info(dev->wiphy, "hwaddr %pm, %s + %s\n",
+		   mac_addr, chip_name, priv->rf->name);
 
 	return 0;
 
diff --git a/drivers/net/wireless/rtl818x/rtl8180_grf5101.c b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c
index 947ee55..5cab9df 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_grf5101.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c
@@ -69,6 +69,15 @@
 	rtl8180_write_phy(dev, 0x10, ant);
 }
 
+static u8 grf5101_rf_calc_rssi(u8 agc, u8 sq)
+{
+	if (agc > 60)
+		return 65;
+
+	/* TODO(?): just return agc (or agc + 5) to avoid mult / div */
+	return 65 * agc / 60;
+}
+
 static void grf5101_rf_set_channel(struct ieee80211_hw *dev,
 				   struct ieee80211_conf *conf)
 {
@@ -176,5 +185,6 @@
 	.name		= "GCT",
 	.init		= grf5101_rf_init,
 	.stop		= grf5101_rf_stop,
-	.set_chan	= grf5101_rf_set_channel
+	.set_chan	= grf5101_rf_set_channel,
+	.calc_rssi	= grf5101_rf_calc_rssi,
 };
diff --git a/drivers/net/wireless/rtl818x/rtl8180_max2820.c b/drivers/net/wireless/rtl818x/rtl8180_max2820.c
index 6c825fd..16c4655 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_max2820.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_max2820.c
@@ -74,6 +74,22 @@
 	rtl8180_write_phy(dev, 0x10, ant);
 }
 
+static u8 max2820_rf_calc_rssi(u8 agc, u8 sq)
+{
+	bool odd;
+
+	odd = !!(agc & 1);
+
+	agc >>= 1;
+	if (odd)
+		agc += 76;
+	else
+		agc += 66;
+
+	/* TODO: change addends above to avoid mult / div below */
+	return 65 * agc / 100;
+}
+
 static void max2820_rf_set_channel(struct ieee80211_hw *dev,
 				   struct ieee80211_conf *conf)
 {
@@ -148,5 +164,6 @@
 	.name		= "Maxim",
 	.init		= max2820_rf_init,
 	.stop		= max2820_rf_stop,
-	.set_chan	= max2820_rf_set_channel
+	.set_chan	= max2820_rf_set_channel,
+	.calc_rssi	= max2820_rf_calc_rssi,
 };
diff --git a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c
index 4d2be0d..69e4d47 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c
@@ -50,7 +50,10 @@
 	udelay(10);
 
 	for (i = 15; i >= 0; i--) {
-		u16 reg = reg80 | !!(bangdata & (1 << i));
+		u16 reg = reg80;
+
+		if (bangdata & (1 << i))
+			reg |= 1;
 
 		if (i & 1)
 			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
diff --git a/drivers/net/wireless/rtl818x/rtl8180_sa2400.c b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c
index cea4e0c..d064fcc 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_sa2400.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c
@@ -76,6 +76,31 @@
 
 }
 
+static u8 sa2400_rf_rssi_map[] = {
+	0x64, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e,
+	0x5d, 0x5c, 0x5b, 0x5a, 0x57, 0x54, 0x52, 0x50,
+	0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x41, 0x3f,
+	0x3c, 0x3a, 0x37, 0x36, 0x36, 0x1c, 0x1c, 0x1b,
+	0x1b, 0x1a, 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17,
+	0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13,
+	0x13, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10, 0x0f,
+	0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b,
+	0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07,
+	0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02,
+};
+
+static u8 sa2400_rf_calc_rssi(u8 agc, u8 sq)
+{
+	if (sq == 0x80)
+		return 1;
+
+	if (sq > 78)
+		return 32;
+
+	/* TODO: recalc sa2400_rf_rssi_map to avoid mult / div */
+	return 65 * sa2400_rf_rssi_map[sq] / 100;
+}
+
 static void sa2400_rf_set_channel(struct ieee80211_hw *dev,
 				  struct ieee80211_conf *conf)
 {
@@ -198,5 +223,6 @@
 	.name		= "Philips",
 	.init		= sa2400_rf_init,
 	.stop		= sa2400_rf_stop,
-	.set_chan	= sa2400_rf_set_channel
+	.set_chan	= sa2400_rf_set_channel,
+	.calc_rssi	= sa2400_rf_calc_rssi,
 };
diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h
index 6bb3211..9887816 100644
--- a/drivers/net/wireless/rtl818x/rtl8187.h
+++ b/drivers/net/wireless/rtl818x/rtl8187.h
@@ -47,7 +47,7 @@
 	u8 agc;
 	u8 reserved;
 	__le64 mac_time;
-} __attribute__((packed));
+} __packed;
 
 struct rtl8187b_rx_hdr {
 	__le32 flags;
@@ -59,7 +59,7 @@
 	__le16 snr_long2end;
 	s8 pwdb_g12;
 	u8 fot;
-} __attribute__((packed));
+} __packed;
 
 /* {rtl8187,rtl8187b}_tx_info is in skb */
 
@@ -68,7 +68,7 @@
 	__le16 rts_duration;
 	__le16 len;
 	__le32 retry;
-} __attribute__((packed));
+} __packed;
 
 struct rtl8187b_tx_hdr {
 	__le32 flags;
@@ -80,7 +80,7 @@
 	__le32 unused_3;
 	__le32 retry;
 	__le32 unused_4[2];
-} __attribute__((packed));
+} __packed;
 
 enum {
 	DEVICE_RTL8187,
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 891b849..5738a55 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -573,7 +573,7 @@
 	} while (--i);
 
 	if (!i) {
-		printk(KERN_ERR "%s: Reset timeout!\n", wiphy_name(dev->wiphy));
+		wiphy_err(dev->wiphy, "reset timeout!\n");
 		return -ETIMEDOUT;
 	}
 
@@ -589,8 +589,7 @@
 	} while (--i);
 
 	if (!i) {
-		printk(KERN_ERR "%s: eeprom reset timeout!\n",
-		       wiphy_name(dev->wiphy));
+		wiphy_err(dev->wiphy, "eeprom reset timeout!\n");
 		return -ETIMEDOUT;
 	}
 
@@ -1527,9 +1526,9 @@
 	mutex_init(&priv->conf_mutex);
 	skb_queue_head_init(&priv->b_tx_status.queue);
 
-	printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s, rfkill mask %d\n",
-	       wiphy_name(dev->wiphy), mac_addr,
-	       chip_name, priv->asic_rev, priv->rf->name, priv->rfkill_mask);
+	wiphy_info(dev->wiphy, "hwaddr %pm, %s v%d + %s, rfkill mask %d\n",
+		   mac_addr, chip_name, priv->asic_rev, priv->rf->name,
+		   priv->rfkill_mask);
 
 #ifdef CONFIG_RTL8187_LEDS
 	eeprom_93cx6_read(&eeprom, 0x3F, &reg);
diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
index a098193..fd96f91 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
@@ -366,8 +366,8 @@
 		rtl8225_write(dev, 0x02, 0x044d);
 		msleep(100);
 		if (!(rtl8225_read(dev, 6) & (1 << 7)))
-			printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
-			       wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
+			wiphy_warn(dev->wiphy, "rf calibration failed! %x\n",
+				   rtl8225_read(dev, 6));
 	}
 
 	rtl8225_write(dev, 0x0, 0x127);
@@ -735,8 +735,8 @@
 		rtl8225_write(dev, 0x02, 0x044D);
 		msleep(100);
 		if (!(rtl8225_read(dev, 6) & (1 << 7)))
-			printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
-			       wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
+			wiphy_warn(dev->wiphy, "rf calibration failed! %x\n",
+				   rtl8225_read(dev, 6));
 	}
 
 	msleep(200);
diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h
index 8522490..1615f63 100644
--- a/drivers/net/wireless/rtl818x/rtl818x.h
+++ b/drivers/net/wireless/rtl818x/rtl818x.h
@@ -185,7 +185,7 @@
 	u8	reserved_22[4];
 	__le16	TALLY_CNT;
 	u8	TALLY_SEL;
-} __attribute__((packed));
+} __packed;
 
 struct rtl818x_rf_ops {
 	char *name;
@@ -193,6 +193,7 @@
 	void (*stop)(struct ieee80211_hw *);
 	void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *);
 	void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *);
+	u8 (*calc_rssi)(u8 agc, u8 sq);
 };
 
 /**
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 337fc7b..2f98058 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -41,7 +41,7 @@
 
 config WL1271
 	tristate "TI wl1271 support"
-	depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS
+	depends on WL12XX && GENERIC_HARDIRQS
 	depends on INET
 	select FW_LOADER
 	select CRC7
@@ -65,7 +65,7 @@
 
 config WL1271_SDIO
 	tristate "TI wl1271 SDIO support"
-	depends on WL1271 && MMC && ARM
+	depends on WL1271 && MMC
 	---help---
 	  This module adds support for the SDIO interface of adapters using
 	  TI wl1271 chipset.  Select this if your platform is using
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index 27ddd2b..078b439 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -10,7 +10,7 @@
 wl1271-objs		= wl1271_main.o  wl1271_cmd.o wl1271_io.o \
 			  wl1271_event.o wl1271_tx.o  wl1271_rx.o   \
 			  wl1271_ps.o    wl1271_acx.o wl1271_boot.o \
-			  wl1271_init.o  wl1271_debugfs.o
+			  wl1271_init.o  wl1271_debugfs.o wl1271_scan.o
 
 wl1271-$(CONFIG_NL80211_TESTMODE)	+= wl1271_testmode.o
 obj-$(CONFIG_WL1271)	+= wl1271.o
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h
index 4f5f02a..6b942a2 100644
--- a/drivers/net/wireless/wl12xx/wl1251.h
+++ b/drivers/net/wireless/wl12xx/wl1251.h
@@ -381,6 +381,9 @@
 
 	u32 chip_id;
 	char fw_ver[21];
+
+	/* Most recently reported noise in dBm */
+	s8 noise;
 };
 
 int wl1251_plt_start(struct wl1251 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h
index 26160c4..842df31 100644
--- a/drivers/net/wireless/wl12xx/wl1251_acx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.h
@@ -60,7 +60,7 @@
 	/* the number of missed sequence numbers in the squentially */
 	/* values of frames seq numbers */
 	u32 seq_num_miss;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_revision {
 	struct acx_header header;
@@ -89,7 +89,7 @@
 	 * bits 24 - 31: Chip ID - The WiLink chip ID.
 	 */
 	u32 hw_version;
-} __attribute__ ((packed));
+} __packed;
 
 enum wl1251_psm_mode {
 	/* Active mode */
@@ -111,7 +111,7 @@
 	/* 2 - ELP mode: Deep / Max sleep*/
 	u8  sleep_auth;
 	u8  padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 enum {
 	HOSTIF_PCI_MASTER_HOST_INDIRECT,
@@ -159,7 +159,7 @@
 	 * complete ring until an interrupt is generated.
 	 */
 	u32 tx_complete_timeout;
-} __attribute__ ((packed));
+} __packed;
 
 
 struct acx_data_path_params_resp {
@@ -180,7 +180,7 @@
 	u32 tx_control_addr;
 
 	u32 tx_complete_addr;
-} __attribute__ ((packed));
+} __packed;
 
 #define TX_MSDU_LIFETIME_MIN       0
 #define TX_MSDU_LIFETIME_MAX       3000
@@ -197,7 +197,7 @@
 	 * firmware discards the MSDU.
 	 */
 	u32 lifetime;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * RX Config Options Table
@@ -285,7 +285,7 @@
 
 	u32 config_options;
 	u32 filter_options;
-} __attribute__ ((packed));
+} __packed;
 
 enum {
 	QOS_AC_BE = 0,
@@ -325,13 +325,13 @@
 
 	/* Lowest memory blocks guaranteed for this queue */
 	u16 low_threshold;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_packet_detection {
 	struct acx_header header;
 
 	u32 threshold;
-} __attribute__ ((packed));
+} __packed;
 
 
 enum acx_slot_type {
@@ -349,7 +349,7 @@
 	u8 wone_index; /* Reserved */
 	u8 slot_time;
 	u8 reserved[6];
-} __attribute__ ((packed));
+} __packed;
 
 
 #define ADDRESS_GROUP_MAX	(8)
@@ -362,7 +362,7 @@
 	u8 num_groups;
 	u8 pad[2];
 	u8 mac_table[ADDRESS_GROUP_MAX_LEN];
-} __attribute__ ((packed));
+} __packed;
 
 
 #define  RX_TIMEOUT_PS_POLL_MIN    0
@@ -388,7 +388,7 @@
 	 * from an UPSD enabled queue.
 	 */
 	u16 upsd_timeout;
-} __attribute__ ((packed));
+} __packed;
 
 #define RTS_THRESHOLD_MIN              0
 #define RTS_THRESHOLD_MAX              4096
@@ -399,7 +399,7 @@
 
 	u16 threshold;
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_beacon_filter_option {
 	struct acx_header header;
@@ -415,7 +415,7 @@
 	 */
 	u8 max_num_beacons;
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * ACXBeaconFilterEntry (not 221)
@@ -461,7 +461,7 @@
 	u8 num_ie;
 	u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
 	u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
 
 #define SYNCH_FAIL_DEFAULT_THRESHOLD    10     /* number of beacons */
 #define NO_BEACON_DEFAULT_TIMEOUT       (500) /* in microseconds */
@@ -494,7 +494,7 @@
 	 */
 	u8 enable;
 	u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
 
 #define PTA_ANTENNA_TYPE_DEF		  (0)
 #define PTA_BT_HP_MAXTIME_DEF		  (2000)
@@ -648,7 +648,7 @@
 
 	/* range: 0 - 20  default: 1 */
 	u8 bt_hp_respected_num;
-} __attribute__ ((packed));
+} __packed;
 
 #define CCA_THRSH_ENABLE_ENERGY_D       0x140A
 #define CCA_THRSH_DISABLE_ENERGY_D      0xFFEF
@@ -660,7 +660,7 @@
 	u16 rx_cca_threshold;
 	u8 tx_energy_detection;
 	u8 pad;
-} __attribute__ ((packed));
+} __packed;
 
 #define BCN_RX_TIMEOUT_DEF_VALUE        10000
 #define BROADCAST_RX_TIMEOUT_DEF_VALUE  20000
@@ -679,14 +679,14 @@
 	/* Consecutive PS Poll failures before updating the host */
 	u8 ps_poll_threshold;
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_event_mask {
 	struct acx_header header;
 
 	u32 event_mask;
 	u32 high_event_mask; /* Unused */
-} __attribute__ ((packed));
+} __packed;
 
 #define CFG_RX_FCS		BIT(2)
 #define CFG_RX_ALL_GOOD		BIT(3)
@@ -729,7 +729,7 @@
 	u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */
 	u8 tx_mgt_frame_rate;
 	u8 tx_mgt_frame_mod;
-} __attribute__ ((packed));
+} __packed;
 
 /* STA MAC */
 struct acx_dot11_station_id {
@@ -737,28 +737,28 @@
 
 	u8 mac[ETH_ALEN];
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_feature_config {
 	struct acx_header header;
 
 	u32 options;
 	u32 data_flow_options;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_current_tx_power {
 	struct acx_header header;
 
 	u8  current_tx_power;
 	u8  padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_dot11_default_key {
 	struct acx_header header;
 
 	u8 id;
 	u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_tsf_info {
 	struct acx_header header;
@@ -769,7 +769,7 @@
 	u32 last_TBTT_lsb;
 	u8 last_dtim_count;
 	u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
 
 enum acx_wake_up_event {
 	WAKE_UP_EVENT_BEACON_BITMAP	= 0x01, /* Wake on every Beacon*/
@@ -785,7 +785,7 @@
 	u8 wake_up_event; /* Only one bit can be set */
 	u8 listen_interval;
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_aid {
 	struct acx_header header;
@@ -795,7 +795,7 @@
 	 */
 	u16 aid;
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 enum acx_preamble_type {
 	ACX_PREAMBLE_LONG = 0,
@@ -811,7 +811,7 @@
 	 */
 	u8 preamble;
 	u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 enum acx_ctsprotect_type {
 	CTSPROTECT_DISABLE = 0,
@@ -822,11 +822,11 @@
 	struct acx_header header;
 	u8 ctsprotect;
 	u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_tx_statistics {
 	u32 internal_desc_overflow;
-}  __attribute__ ((packed));
+}  __packed;
 
 struct acx_rx_statistics {
 	u32 out_of_mem;
@@ -837,14 +837,14 @@
 	u32 xfr_hint_trig;
 	u32 path_reset;
 	u32 reset_counter;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_dma_statistics {
 	u32 rx_requested;
 	u32 rx_errors;
 	u32 tx_requested;
 	u32 tx_errors;
-}  __attribute__ ((packed));
+}  __packed;
 
 struct acx_isr_statistics {
 	/* host command complete */
@@ -903,7 +903,7 @@
 
 	/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
 	u32 low_rssi;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_wep_statistics {
 	/* WEP address keys configured */
@@ -925,7 +925,7 @@
 
 	/* WEP decrypt interrupts */
 	u32 interrupt;
-} __attribute__ ((packed));
+} __packed;
 
 #define ACX_MISSED_BEACONS_SPREAD 10
 
@@ -985,12 +985,12 @@
 
 	/* the number of beacons in awake mode */
 	u32 rcvd_awake_beacons;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_mic_statistics {
 	u32 rx_pkts;
 	u32 calc_failure;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_aes_statistics {
 	u32 encrypt_fail;
@@ -999,7 +999,7 @@
 	u32 decrypt_packets;
 	u32 encrypt_interrupt;
 	u32 decrypt_interrupt;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_event_statistics {
 	u32 heart_beat;
@@ -1010,7 +1010,7 @@
 	u32 oom_late;
 	u32 phy_transmit_error;
 	u32 tx_stuck;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_ps_statistics {
 	u32 pspoll_timeouts;
@@ -1020,7 +1020,7 @@
 	u32 pspoll_max_apturn;
 	u32 pspoll_utilization;
 	u32 upsd_utilization;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_rxpipe_statistics {
 	u32 rx_prep_beacon_drop;
@@ -1028,7 +1028,7 @@
 	u32 beacon_buffer_thres_host_int_trig_rx_data;
 	u32 missed_beacon_host_int_trig_rx_data;
 	u32 tx_xfr_host_int_trig_rx_data;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_statistics {
 	struct acx_header header;
@@ -1044,7 +1044,7 @@
 	struct acx_event_statistics event;
 	struct acx_ps_statistics ps;
 	struct acx_rxpipe_statistics rxpipe;
-} __attribute__ ((packed));
+} __packed;
 
 #define ACX_MAX_RATE_CLASSES       8
 #define ACX_RATE_MASK_UNSPECIFIED  0
@@ -1063,7 +1063,7 @@
 
 	u32 rate_class_cnt;
 	struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES];
-} __attribute__ ((packed));
+} __packed;
 
 struct wl1251_acx_memory {
 	__le16 num_stations; /* number of STAs to be supported. */
@@ -1082,7 +1082,7 @@
 	u8 tx_min_mem_block_num;
 	u8 num_ssid_profiles;
 	__le16 debug_buffer_size;
-} __attribute__ ((packed));
+} __packed;
 
 
 #define ACX_RX_DESC_MIN                1
@@ -1094,7 +1094,7 @@
 	u8 type;
 	u8 priority;
 	__le32 dma_address;
-} __attribute__ ((packed));
+} __packed;
 
 #define ACX_TX_DESC_MIN                1
 #define ACX_TX_DESC_MAX                127
@@ -1103,7 +1103,7 @@
     u8 num_descs;
     u8 pad[2];
     u8 attributes;
-} __attribute__ ((packed));
+} __packed;
 
 #define MAX_TX_QUEUE_CONFIGS 5
 #define MAX_TX_QUEUES 4
@@ -1113,7 +1113,7 @@
 	struct wl1251_acx_memory mem_config;
 	struct wl1251_acx_rx_queue_config rx_queue_config;
 	struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
-} __attribute__ ((packed));
+} __packed;
 
 struct wl1251_acx_mem_map {
 	struct acx_header header;
@@ -1147,7 +1147,7 @@
 
 	/* Number of blocks FW allocated for RX packets */
 	u32 num_rx_mem_blocks;
-} __attribute__ ((packed));
+} __packed;
 
 
 struct wl1251_acx_wr_tbtt_and_dtim {
@@ -1164,7 +1164,7 @@
 	*/
 	u8  dtim;
 	u8  padding;
-} __attribute__ ((packed));
+} __packed;
 
 struct wl1251_acx_ac_cfg {
 	struct acx_header header;
@@ -1194,7 +1194,7 @@
 
 	/* The TX Op Limit (in microseconds) for the access class. */
 	u16 txop_limit;
-} __attribute__ ((packed));
+} __packed;
 
 
 enum wl1251_acx_channel_type {
@@ -1245,7 +1245,7 @@
 
 	/* not supported */
 	u32 apsdconf[2];
-} __attribute__ ((packed));
+} __packed;
 
 /*************************************************************************
 
diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c
index 2545123..65e0416 100644
--- a/drivers/net/wireless/wl12xx/wl1251_boot.c
+++ b/drivers/net/wireless/wl12xx/wl1251_boot.c
@@ -225,7 +225,7 @@
 int wl1251_boot_run_firmware(struct wl1251 *wl)
 {
 	int loop, ret;
-	u32 chip_id, interrupt;
+	u32 chip_id, acx_intr;
 
 	wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
 
@@ -242,15 +242,15 @@
 	loop = 0;
 	while (loop++ < INIT_LOOP) {
 		udelay(INIT_LOOP_DELAY);
-		interrupt = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+		acx_intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
 
-		if (interrupt == 0xffffffff) {
+		if (acx_intr == 0xffffffff) {
 			wl1251_error("error reading hardware complete "
 				     "init indication");
 			return -EIO;
 		}
 		/* check that ACX_INTR_INIT_COMPLETE is enabled */
-		else if (interrupt & WL1251_ACX_INTR_INIT_COMPLETE) {
+		else if (acx_intr & WL1251_ACX_INTR_INIT_COMPLETE) {
 			wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
 					   WL1251_ACX_INTR_INIT_COMPLETE);
 			break;
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h
index 4ad67ca..a9e4991 100644
--- a/drivers/net/wireless/wl12xx/wl1251_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h
@@ -106,7 +106,7 @@
 	u16 status;
 	/* payload */
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct  wl1251_command {
 	struct wl1251_cmd_header header;
@@ -175,8 +175,8 @@
 #define WL1251_SCAN_NUM_PROBES 3
 
 struct wl1251_scan_parameters {
-	u32 rx_config_options;
-	u32 rx_filter_options;
+	__le32 rx_config_options;
+	__le32 rx_filter_options;
 
 	/*
 	 * Scan options:
@@ -186,7 +186,7 @@
 	 * bit 2: voice mode, 0 for normal scan.
 	 * bit 3: scan priority, 1 for high priority.
 	 */
-	u16 scan_options;
+	__le16 scan_options;
 
 	/* Number of channels to scan */
 	u8 num_channels;
@@ -195,17 +195,17 @@
 	u8 num_probe_requests;
 
 	/* Rate and modulation for probe requests */
-	u16 tx_rate;
+	__le16 tx_rate;
 
 	u8 tid_trigger;
 	u8 ssid_len;
 	u8 ssid[32];
 
-} __attribute__ ((packed));
+} __packed;
 
 struct wl1251_scan_ch_parameters {
-	u32 min_duration; /* in TU */
-	u32 max_duration; /* in TU */
+	__le32 min_duration; /* in TU */
+	__le32 max_duration; /* in TU */
 	u32 bssid_lsb;
 	u16 bssid_msb;
 
@@ -218,7 +218,7 @@
 	u8 tx_power_att;
 	u8 channel;
 	u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
 
 /* SCAN parameters */
 #define SCAN_MAX_NUM_OF_CHANNELS 16
@@ -228,7 +228,7 @@
 
 	struct wl1251_scan_parameters params;
 	struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
-} __attribute__ ((packed));
+} __packed;
 
 enum {
 	BSS_TYPE_IBSS = 0,
@@ -276,14 +276,14 @@
 	u8 tx_mgt_frame_rate; /* OBSOLETE */
 	u8 tx_mgt_frame_mod;  /* OBSOLETE */
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_enabledisable_path {
 	struct wl1251_cmd_header header;
 
 	u8 channel;
 	u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 #define WL1251_MAX_TEMPLATE_SIZE 300
 
@@ -292,7 +292,7 @@
 
 	__le16 size;
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define TIM_ELE_ID    5
 #define PARTIAL_VBM_MAX    251
@@ -304,7 +304,7 @@
 	u8 dtim_period;
 	u8 bitmap_ctrl;
 	u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
-} __attribute__ ((packed));
+} __packed;
 
 /* Virtual Bit Map update */
 struct wl1251_cmd_vbm_update {
@@ -312,7 +312,7 @@
 	__le16 len;
 	u8  padding[2];
 	struct wl1251_tim tim;
-} __attribute__ ((packed));
+} __packed;
 
 enum wl1251_cmd_ps_mode {
 	STATION_ACTIVE_MODE,
@@ -333,7 +333,7 @@
 	u8 hang_over_period;
 	u16 null_data_rate;
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct wl1251_cmd_trigger_scan_to {
 	struct wl1251_cmd_header header;
@@ -411,7 +411,7 @@
 	u8 key[MAX_KEY_SIZE];
 	u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
 	u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __attribute__ ((packed));
+} __packed;
 
 
 #endif /* __WL1251_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1251_event.h b/drivers/net/wireless/wl12xx/wl1251_event.h
index be0ac54..f48a2b6 100644
--- a/drivers/net/wireless/wl12xx/wl1251_event.h
+++ b/drivers/net/wireless/wl12xx/wl1251_event.h
@@ -82,7 +82,7 @@
 	u32 report_1;
 	u32 report_2;
 	u32 report_3;
-} __attribute__ ((packed));
+} __packed;
 
 struct event_mailbox {
 	u32 events_vector;
@@ -112,7 +112,7 @@
 	struct event_debug_report report;
 	u8 average_snr_level;
 	u8 padding[19];
-} __attribute__ ((packed));
+} __packed;
 
 int wl1251_event_unmask(struct wl1251 *wl);
 void wl1251_event_mbox_config(struct wl1251 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 00b2428..861a5f3 100644
--- a/drivers/net/wireless/wl12xx/wl1251_main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -124,7 +124,7 @@
 	}
 
 	wl->nvs_len = fw->size;
-	wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
+	wl->nvs = kmemdup(fw->data, wl->nvs_len, GFP_KERNEL);
 
 	if (!wl->nvs) {
 		wl1251_error("could not allocate memory for the nvs file");
@@ -132,8 +132,6 @@
 		goto out;
 	}
 
-	memcpy(wl->nvs, fw->data, wl->nvs_len);
-
 	ret = 0;
 
 out:
@@ -413,6 +411,7 @@
 static int wl1251_op_start(struct ieee80211_hw *hw)
 {
 	struct wl1251 *wl = hw->priv;
+	struct wiphy *wiphy = hw->wiphy;
 	int ret = 0;
 
 	wl1251_debug(DEBUG_MAC80211, "mac80211 start");
@@ -446,6 +445,10 @@
 
 	wl1251_info("firmware booted (%s)", wl->fw_ver);
 
+	/* update hw/fw version info in wiphy struct */
+	wiphy->hw_version = wl->chip_id;
+	strncpy(wiphy->fw_version, wl->fw_ver, sizeof(wiphy->fw_version));
+
 out:
 	if (ret < 0)
 		wl1251_power_off(wl);
@@ -1174,6 +1177,22 @@
 	return ret;
 }
 
+static int wl1251_op_get_survey(struct ieee80211_hw *hw, int idx,
+				struct survey_info *survey)
+{
+	struct wl1251 *wl = hw->priv;
+	struct ieee80211_conf *conf = &hw->conf;
+ 
+	if (idx != 0)
+		return -ENOENT;
+ 
+	survey->channel = conf->channel;
+	survey->filled = SURVEY_INFO_NOISE_DBM;
+	survey->noise = wl->noise;
+ 
+	return 0;
+}
+
 /* can't be const, mac80211 writes to this */
 static struct ieee80211_supported_band wl1251_band_2ghz = {
 	.channels = wl1251_channels,
@@ -1195,6 +1214,7 @@
 	.bss_info_changed = wl1251_op_bss_info_changed,
 	.set_rts_threshold = wl1251_op_set_rts_threshold,
 	.conf_tx = wl1251_op_conf_tx,
+	.get_survey = wl1251_op_get_survey,
 };
 
 static int wl1251_read_eeprom_byte(struct wl1251 *wl, off_t offset, u8 *data)
@@ -1419,5 +1439,4 @@
 MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
-MODULE_ALIAS("spi:wl1251");
 MODULE_FIRMWARE(WL1251_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c
index 8515158..1b6294b 100644
--- a/drivers/net/wireless/wl12xx/wl1251_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.c
@@ -74,6 +74,12 @@
 
 	status->signal = desc->rssi;
 
+	/*
+	 * FIXME: guessing that snr needs to be divided by two, otherwise
+	 * the values don't make any sense
+	 */
+	wl->noise = desc->rssi - desc->snr / 2;
+
 	status->freq = ieee80211_channel_to_frequency(desc->channel);
 
 	status->flag |= RX_FLAG_TSFT;
diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h
index 563a3fd..da4e534 100644
--- a/drivers/net/wireless/wl12xx/wl1251_rx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.h
@@ -117,7 +117,7 @@
 	s8 rssi; /* in dB */
 	u8 rcpi; /* in dB */
 	u8 snr; /* in dB */
-} __attribute__ ((packed));
+} __packed;
 
 void wl1251_rx(struct wl1251 *wl);
 
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c
index c561332..b901b61 100644
--- a/drivers/net/wireless/wl12xx/wl1251_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c
@@ -37,11 +37,17 @@
 #define SDIO_DEVICE_ID_TI_WL1251	0x9066
 #endif
 
+struct wl1251_sdio {
+	struct sdio_func *func;
+	u32 elp_val;
+};
+
 static struct wl12xx_platform_data *wl12xx_board_data;
 
 static struct sdio_func *wl_to_func(struct wl1251 *wl)
 {
-	return wl->if_priv;
+	struct wl1251_sdio *wl_sdio = wl->if_priv;
+	return wl_sdio->func;
 }
 
 static void wl1251_sdio_interrupt(struct sdio_func *func)
@@ -90,10 +96,17 @@
 static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val)
 {
 	int ret = 0;
-	struct sdio_func *func = wl_to_func(wl);
+	struct wl1251_sdio *wl_sdio = wl->if_priv;
+	struct sdio_func *func = wl_sdio->func;
 
+	/*
+	 * The hardware only supports RAW (read after write) access for
+	 * reading, regular sdio_readb won't work here (it interprets
+	 * the unused bits of CMD52 as write data even if we send read
+	 * request).
+	 */
 	sdio_claim_host(func);
-	*val = sdio_readb(func, addr, &ret);
+	*val = sdio_writeb_readb(func, wl_sdio->elp_val, addr, &ret);
 	sdio_release_host(func);
 
 	if (ret)
@@ -103,7 +116,8 @@
 static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val)
 {
 	int ret = 0;
-	struct sdio_func *func = wl_to_func(wl);
+	struct wl1251_sdio *wl_sdio = wl->if_priv;
+	struct sdio_func *func = wl_sdio->func;
 
 	sdio_claim_host(func);
 	sdio_writeb(func, val, addr, &ret);
@@ -111,6 +125,8 @@
 
 	if (ret)
 		wl1251_error("sdio_writeb failed (%d)", ret);
+	else
+		wl_sdio->elp_val = val;
 }
 
 static void wl1251_sdio_reset(struct wl1251 *wl)
@@ -197,6 +213,7 @@
 	int ret;
 	struct wl1251 *wl;
 	struct ieee80211_hw *hw;
+	struct wl1251_sdio *wl_sdio;
 
 	hw = wl1251_alloc_hw();
 	if (IS_ERR(hw))
@@ -204,6 +221,12 @@
 
 	wl = hw->priv;
 
+	wl_sdio = kzalloc(sizeof(*wl_sdio), GFP_KERNEL);
+	if (wl_sdio == NULL) {
+		ret = -ENOMEM;
+		goto out_free_hw;
+	}
+
 	sdio_claim_host(func);
 	ret = sdio_enable_func(func);
 	if (ret)
@@ -213,7 +236,8 @@
 	sdio_release_host(func);
 
 	SET_IEEE80211_DEV(hw, &func->dev);
-	wl->if_priv = func;
+	wl_sdio->func = func;
+	wl->if_priv = wl_sdio;
 	wl->if_ops = &wl1251_sdio_ops;
 	wl->set_power = wl1251_sdio_set_power;
 
@@ -259,6 +283,8 @@
 	sdio_disable_func(func);
 release:
 	sdio_release_host(func);
+	kfree(wl_sdio);
+out_free_hw:
 	wl1251_free_hw(wl);
 	return ret;
 }
@@ -266,9 +292,11 @@
 static void __devexit wl1251_sdio_remove(struct sdio_func *func)
 {
 	struct wl1251 *wl = sdio_get_drvdata(func);
+	struct wl1251_sdio *wl_sdio = wl->if_priv;
 
 	if (wl->irq)
 		free_irq(wl->irq, wl);
+	kfree(wl_sdio);
 	wl1251_free_hw(wl);
 
 	sdio_claim_host(func);
diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c
index e814742..27fdfaa 100644
--- a/drivers/net/wireless/wl12xx/wl1251_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.c
@@ -345,3 +345,4 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
+MODULE_ALIAS("spi:wl1251");
diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c
index c822318..a38ec19 100644
--- a/drivers/net/wireless/wl12xx/wl1251_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.c
@@ -117,7 +117,7 @@
 	frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
 	tx_hdr->frag_threshold = cpu_to_le16(frag_threshold);
 
-	payload_len = tx_hdr->length + MAX_MSDU_SECURITY_LENGTH;
+	payload_len = le16_to_cpu(tx_hdr->length) + MAX_MSDU_SECURITY_LENGTH;
 
 	if (payload_len > frag_threshold) {
 		mem_blocks_per_frag =
@@ -191,11 +191,13 @@
 	if (control->control.hw_key &&
 	    control->control.hw_key->alg == ALG_TKIP) {
 		int hdrlen;
-		u16 fc;
+		__le16 fc;
+		u16 length;
 		u8 *pos;
 
-		fc = *(u16 *)(skb->data + sizeof(*tx_hdr));
-		tx_hdr->length += WL1251_TKIP_IV_SPACE;
+		fc = *(__le16 *)(skb->data + sizeof(*tx_hdr));
+		length = le16_to_cpu(tx_hdr->length) + WL1251_TKIP_IV_SPACE;
+		tx_hdr->length = cpu_to_le16(length);
 
 		hdrlen = ieee80211_hdrlen(fc);
 
diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h
index 55856c6..f40eeb3 100644
--- a/drivers/net/wireless/wl12xx/wl1251_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.h
@@ -109,12 +109,12 @@
 	unsigned xfer_pad:1;
 
 	unsigned reserved:7;
-} __attribute__ ((packed));
+} __packed;
 
 
 struct tx_double_buffer_desc {
 	/* Length of payload, including headers. */
-	u16 length;
+	__le16 length;
 
 	/*
 	 * A bit mask that specifies the initial rate to be used
@@ -133,10 +133,10 @@
 	 * 0x0800 - 48Mbits
 	 * 0x1000 - 54Mbits
 	 */
-	u16 rate;
+	__le16 rate;
 
 	/* Time in us that a packet can spend in the target */
-	u32 expiry_time;
+	__le32 expiry_time;
 
 	/* index of the TX queue used for this packet */
 	u8 xmit_queue;
@@ -150,13 +150,13 @@
 	 * The FW should cut the packet into fragments
 	 * of this size.
 	 */
-	u16 frag_threshold;
+	__le16 frag_threshold;
 
 	/* Numbers of HW queue blocks to be allocated */
 	u8 num_mem_blocks;
 
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 enum {
 	TX_SUCCESS              = 0,
@@ -208,7 +208,7 @@
 
 	/* See done_1 */
 	u8 done_2;
-} __attribute__ ((packed));
+} __packed;
 
 static inline int wl1251_tx_get_queue(int queue)
 {
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 6f1b6b5..dd3cee6 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -33,6 +33,7 @@
 #include <net/mac80211.h>
 
 #include "wl1271_conf.h"
+#include "wl1271_ini.h"
 
 #define DRIVER_NAME "wl1271"
 #define DRIVER_PREFIX DRIVER_NAME ": "
@@ -116,33 +117,6 @@
 #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
 #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
 
-/* NVS data structure */
-#define WL1271_NVS_SECTION_SIZE                  468
-
-#define WL1271_NVS_GENERAL_PARAMS_SIZE            57
-#define WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED \
-	(WL1271_NVS_GENERAL_PARAMS_SIZE + 1)
-#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE         17
-#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED \
-	(WL1271_NVS_STAT_RADIO_PARAMS_SIZE + 1)
-#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE          65
-#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED \
-	(WL1271_NVS_DYN_RADIO_PARAMS_SIZE + 1)
-#define WL1271_NVS_FEM_COUNT                       2
-#define WL1271_NVS_INI_SPARE_SIZE                124
-
-struct wl1271_nvs_file {
-	/* NVS section */
-	u8 nvs[WL1271_NVS_SECTION_SIZE];
-
-	/* INI section */
-	u8 general_params[WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED];
-	u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED];
-	u8 dyn_radio_params[WL1271_NVS_FEM_COUNT]
-			   [WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED];
-	u8 ini_spare[WL1271_NVS_INI_SPARE_SIZE];
-} __attribute__ ((packed));
-
 /*
  * Enable/disable 802.11a support for WL1273
  */
@@ -317,7 +291,7 @@
 	__le32 tx_released_blks[NUM_TX_QUEUES];
 	__le32 fw_localtime;
 	__le32 padding[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct wl1271_rx_mem_pool_addr {
 	u32 addr;
@@ -325,12 +299,11 @@
 };
 
 struct wl1271_scan {
+	struct cfg80211_scan_request *req;
+	bool *scanned_ch;
 	u8 state;
 	u8 ssid[IW_ESSID_MAX_SIZE+1];
 	size_t ssid_len;
-	u8 active;
-	u8 high_prio;
-	u8 probe_requests;
 };
 
 struct wl1271_if_operations {
@@ -368,13 +341,14 @@
 #define WL1271_FLAG_JOINED             (2)
 #define WL1271_FLAG_GPIO_POWER         (3)
 #define WL1271_FLAG_TX_QUEUE_STOPPED   (4)
-#define WL1271_FLAG_SCANNING           (5)
-#define WL1271_FLAG_IN_ELP             (6)
-#define WL1271_FLAG_PSM                (7)
-#define WL1271_FLAG_PSM_REQUESTED      (8)
-#define WL1271_FLAG_IRQ_PENDING        (9)
-#define WL1271_FLAG_IRQ_RUNNING       (10)
-#define WL1271_FLAG_IDLE              (11)
+#define WL1271_FLAG_IN_ELP             (5)
+#define WL1271_FLAG_PSM                (6)
+#define WL1271_FLAG_PSM_REQUESTED      (7)
+#define WL1271_FLAG_IRQ_PENDING        (8)
+#define WL1271_FLAG_IRQ_RUNNING        (9)
+#define WL1271_FLAG_IDLE              (10)
+#define WL1271_FLAG_IDLE_REQUESTED    (11)
+#define WL1271_FLAG_PSPOLL_FAILURE    (12)
 	unsigned long flags;
 
 	struct wl1271_partition_set part;
@@ -421,6 +395,7 @@
 
 	/* Pending TX frames */
 	struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
+	int tx_frames_cnt;
 
 	/* Security sequence number counters */
 	u8 tx_security_last_seq;
@@ -468,6 +443,10 @@
 
 	struct completion *elp_compl;
 	struct delayed_work elp_work;
+	struct delayed_work pspoll_work;
+
+	/* counter for ps-poll delivery failures */
+	int ps_poll_failures;
 
 	/* retry counter for PSM entries */
 	u8 psm_entry_retry;
@@ -496,6 +475,9 @@
 	bool sg_enabled;
 
 	struct list_head list;
+
+	/* Most recently reported noise in dBm */
+	s8 noise;
 };
 
 int wl1271_plt_start(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c
index e19e2f8..bb245f0 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.c
@@ -1075,8 +1075,7 @@
 	return ret;
 }
 
-int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
-			     u8 version)
+int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address)
 {
 	struct wl1271_acx_arp_filter *acx;
 	int ret;
@@ -1089,17 +1088,11 @@
 		goto out;
 	}
 
-	acx->version = version;
+	acx->version = ACX_IPV4_VERSION;
 	acx->enable = enable;
 
-	if (enable == true) {
-		if (version == ACX_IPV4_VERSION)
-			memcpy(acx->address, address, ACX_IPV4_ADDR_SIZE);
-		else if (version == ACX_IPV6_VERSION)
-			memcpy(acx->address, address, sizeof(acx->address));
-		else
-			wl1271_error("Invalid IP version");
-	}
+	if (enable == true)
+		memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE);
 
 	ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER,
 				   acx, sizeof(*acx));
@@ -1266,3 +1259,29 @@
 	kfree(acx);
 	return ret;
 }
+
+int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
+{
+	struct wl1271_acx_fw_tsf_information *tsf_info;
+	int ret;
+
+	tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
+	if (!tsf_info) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO,
+				     tsf_info, sizeof(*tsf_info));
+	if (ret < 0) {
+		wl1271_warning("acx tsf info interrogate failed");
+		goto out;
+	}
+
+	*mactime = le32_to_cpu(tsf_info->current_tsf_low) |
+		((u64) le32_to_cpu(tsf_info->current_tsf_high) << 32);
+
+out:
+	kfree(tsf_info);
+	return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h
index 420e7e2..4235bc5 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.h
@@ -75,7 +75,7 @@
 
 	/* payload length (not including headers */
 	__le16 len;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_error_counter {
 	struct acx_header header;
@@ -98,7 +98,7 @@
 	/* the number of missed sequence numbers in the squentially */
 	/* values of frames seq numbers */
 	__le32 seq_num_miss;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_revision {
 	struct acx_header header;
@@ -127,7 +127,7 @@
 	 * bits 24 - 31: Chip ID - The WiLink chip ID.
 	 */
 	__le32 hw_version;
-} __attribute__ ((packed));
+} __packed;
 
 enum wl1271_psm_mode {
 	/* Active mode */
@@ -149,7 +149,7 @@
 	/* 2 - ELP mode: Deep / Max sleep*/
 	u8  sleep_auth;
 	u8  padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 enum {
 	HOSTIF_PCI_MASTER_HOST_INDIRECT,
@@ -187,7 +187,7 @@
 	 * firmware discards the MSDU.
 	 */
 	__le32 lifetime;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * RX Config Options Table
@@ -275,13 +275,13 @@
 
 	__le32 config_options;
 	__le32 filter_options;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_packet_detection {
 	struct acx_header header;
 
 	__le32 threshold;
-} __attribute__ ((packed));
+} __packed;
 
 
 enum acx_slot_type {
@@ -299,7 +299,7 @@
 	u8 wone_index; /* Reserved */
 	u8 slot_time;
 	u8 reserved[6];
-} __attribute__ ((packed));
+} __packed;
 
 
 #define ACX_MC_ADDRESS_GROUP_MAX	(8)
@@ -312,21 +312,21 @@
 	u8 num_groups;
 	u8 pad[2];
 	u8 mac_table[ADDRESS_GROUP_MAX_LEN];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_rx_timeout {
 	struct acx_header header;
 
 	__le16 ps_poll_timeout;
 	__le16 upsd_timeout;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_rts_threshold {
 	struct acx_header header;
 
 	__le16 threshold;
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_beacon_filter_option {
 	struct acx_header header;
@@ -342,7 +342,7 @@
 	 */
 	u8 max_num_beacons;
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * ACXBeaconFilterEntry (not 221)
@@ -383,21 +383,21 @@
 	u8 num_ie;
 	u8 pad[3];
 	u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_conn_monit_params {
        struct acx_header header;
 
        __le32 synch_fail_thold; /* number of beacons missed */
        __le32 bss_lose_timeout; /* number of TU's from synch fail */
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_bt_wlan_coex {
 	struct acx_header header;
 
 	u8 enable;
 	u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_bt_wlan_coex_param {
 	struct acx_header header;
@@ -405,7 +405,7 @@
 	__le32 params[CONF_SG_PARAMS_MAX];
 	u8 param_idx;
 	u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_dco_itrim_params {
 	struct acx_header header;
@@ -413,7 +413,7 @@
 	u8 enable;
 	u8 padding[3];
 	__le32 timeout;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_energy_detection {
 	struct acx_header header;
@@ -422,7 +422,7 @@
 	__le16 rx_cca_threshold;
 	u8 tx_energy_detection;
 	u8 pad;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_beacon_broadcast {
 	struct acx_header header;
@@ -436,14 +436,14 @@
 	/* Consecutive PS Poll failures before updating the host */
 	u8 ps_poll_threshold;
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_event_mask {
 	struct acx_header header;
 
 	__le32 event_mask;
 	__le32 high_event_mask; /* Unused */
-} __attribute__ ((packed));
+} __packed;
 
 #define CFG_RX_FCS		BIT(2)
 #define CFG_RX_ALL_GOOD		BIT(3)
@@ -488,14 +488,14 @@
 
 	__le32 options;
 	__le32 data_flow_options;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_current_tx_power {
 	struct acx_header header;
 
 	u8  current_tx_power;
 	u8  padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_wake_up_condition {
 	struct acx_header header;
@@ -503,7 +503,7 @@
 	u8 wake_up_event; /* Only one bit can be set */
 	u8 listen_interval;
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_aid {
 	struct acx_header header;
@@ -513,7 +513,7 @@
 	 */
 	__le16 aid;
 	u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
 
 enum acx_preamble_type {
 	ACX_PREAMBLE_LONG = 0,
@@ -529,7 +529,7 @@
 	 */
 	u8 preamble;
 	u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 enum acx_ctsprotect_type {
 	CTSPROTECT_DISABLE = 0,
@@ -540,11 +540,11 @@
 	struct acx_header header;
 	u8 ctsprotect;
 	u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_tx_statistics {
 	__le32 internal_desc_overflow;
-}  __attribute__ ((packed));
+}  __packed;
 
 struct acx_rx_statistics {
 	__le32 out_of_mem;
@@ -555,14 +555,14 @@
 	__le32 xfr_hint_trig;
 	__le32 path_reset;
 	__le32 reset_counter;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_dma_statistics {
 	__le32 rx_requested;
 	__le32 rx_errors;
 	__le32 tx_requested;
 	__le32 tx_errors;
-}  __attribute__ ((packed));
+}  __packed;
 
 struct acx_isr_statistics {
 	/* host command complete */
@@ -621,7 +621,7 @@
 
 	/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
 	__le32 low_rssi;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_wep_statistics {
 	/* WEP address keys configured */
@@ -643,7 +643,7 @@
 
 	/* WEP decrypt interrupts */
 	__le32 interrupt;
-} __attribute__ ((packed));
+} __packed;
 
 #define ACX_MISSED_BEACONS_SPREAD 10
 
@@ -703,12 +703,12 @@
 
 	/* the number of beacons in awake mode */
 	__le32 rcvd_awake_beacons;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_mic_statistics {
 	__le32 rx_pkts;
 	__le32 calc_failure;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_aes_statistics {
 	__le32 encrypt_fail;
@@ -717,7 +717,7 @@
 	__le32 decrypt_packets;
 	__le32 encrypt_interrupt;
 	__le32 decrypt_interrupt;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_event_statistics {
 	__le32 heart_beat;
@@ -728,7 +728,7 @@
 	__le32 oom_late;
 	__le32 phy_transmit_error;
 	__le32 tx_stuck;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_ps_statistics {
 	__le32 pspoll_timeouts;
@@ -738,7 +738,7 @@
 	__le32 pspoll_max_apturn;
 	__le32 pspoll_utilization;
 	__le32 upsd_utilization;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_rxpipe_statistics {
 	__le32 rx_prep_beacon_drop;
@@ -746,7 +746,7 @@
 	__le32 beacon_buffer_thres_host_int_trig_rx_data;
 	__le32 missed_beacon_host_int_trig_rx_data;
 	__le32 tx_xfr_host_int_trig_rx_data;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_statistics {
 	struct acx_header header;
@@ -762,7 +762,7 @@
 	struct acx_event_statistics event;
 	struct acx_ps_statistics ps;
 	struct acx_rxpipe_statistics rxpipe;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_rate_class {
 	__le32 enabled_rates;
@@ -780,7 +780,7 @@
 
 	__le32 rate_class_cnt;
 	struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_ac_cfg {
 	struct acx_header header;
@@ -790,7 +790,7 @@
 	u8 aifsn;
 	u8 reserved;
 	__le16 tx_op_limit;
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_tid_config {
 	struct acx_header header;
@@ -801,19 +801,19 @@
 	u8 ack_policy;
 	u8 padding[3];
 	__le32 apsd_conf[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_frag_threshold {
 	struct acx_header header;
 	__le16 frag_threshold;
 	u8 padding[2];
-} __attribute__ ((packed));
+} __packed;
 
 struct acx_tx_config_options {
 	struct acx_header header;
 	__le16 tx_compl_timeout;     /* msec */
 	__le16 tx_compl_threshold;   /* number of packets */
-} __attribute__ ((packed));
+} __packed;
 
 #define ACX_RX_MEM_BLOCKS     70
 #define ACX_TX_MIN_MEM_BLOCKS 40
@@ -828,7 +828,7 @@
 	u8 num_stations;
 	u8 num_ssid_profiles;
 	__le32 total_tx_descriptors;
-} __attribute__ ((packed));
+} __packed;
 
 struct wl1271_acx_mem_map {
 	struct acx_header header;
@@ -872,7 +872,7 @@
 	u8 *rx_cbuf;
 	__le32 rx_ctrl;
 	__le32 tx_ctrl;
-} __attribute__ ((packed));
+} __packed;
 
 struct wl1271_acx_rx_config_opt {
 	struct acx_header header;
@@ -882,7 +882,7 @@
 	__le16 timeout;
 	u8 queue_type;
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 
 struct wl1271_acx_bet_enable {
@@ -891,7 +891,7 @@
 	u8 enable;
 	u8 max_consecutive;
 	u8 padding[2];
-} __attribute__ ((packed));
+} __packed;
 
 #define ACX_IPV4_VERSION 4
 #define ACX_IPV6_VERSION 6
@@ -905,7 +905,7 @@
 			       requests directed to this IP address will pass
 			       through. For IPv4, the first four bytes are
 			       used. */
-} __attribute__((packed));
+} __packed;
 
 struct wl1271_acx_pm_config {
 	struct acx_header header;
@@ -913,14 +913,14 @@
 	__le32 host_clk_settling_time;
 	u8 host_fast_wakeup_support;
 	u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct wl1271_acx_keep_alive_mode {
 	struct acx_header header;
 
 	u8 enabled;
 	u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 enum {
 	ACX_KEEP_ALIVE_NO_TX = 0,
@@ -940,7 +940,7 @@
 	u8 tpl_validation;
 	u8 trigger;
 	u8 padding;
-} __attribute__ ((packed));
+} __packed;
 
 enum {
 	WL1271_ACX_TRIG_TYPE_LEVEL = 0,
@@ -993,6 +993,17 @@
 	u8 snr_data;
 };
 
+struct wl1271_acx_fw_tsf_information {
+	struct acx_header header;
+
+	__le32 current_tsf_high;
+	__le32 current_tsf_low;
+	__le32 last_bttt_high;
+	__le32 last_tbtt_low;
+	u8 last_dtim_count;
+	u8 padding[3];
+} __packed;
+
 enum {
 	ACX_WAKE_UP_CONDITIONS      = 0x0002,
 	ACX_MEM_CFG                 = 0x0003,
@@ -1106,13 +1117,13 @@
 int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
 int wl1271_acx_smart_reflex(struct wl1271 *wl);
 int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
-int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
-			     u8 version);
+int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address);
 int wl1271_acx_pm_config(struct wl1271 *wl);
 int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable);
 int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid);
 int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
 				s16 thold, u8 hyst);
 int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
+int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
 
 #endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c
index 1a36d8a..f36430b 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.c
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.c
@@ -414,7 +414,9 @@
 		PS_REPORT_EVENT_ID |
 		JOIN_EVENT_COMPLETE_ID |
 		DISCONNECT_EVENT_COMPLETE_ID |
-		RSSI_SNR_TRIGGER_0_EVENT_ID;
+		RSSI_SNR_TRIGGER_0_EVENT_ID |
+		PSPOLL_DELIVERY_FAILURE_EVENT_ID |
+		SOFT_GEMINI_SENSE_EVENT_ID;
 
 	ret = wl1271_event_unmask(wl);
 	if (ret < 0) {
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index 19393e2..ce503dd 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -104,100 +104,6 @@
 	return ret;
 }
 
-static int wl1271_cmd_cal_channel_tune(struct wl1271 *wl)
-{
-	struct wl1271_cmd_cal_channel_tune *cmd;
-	int ret = 0;
-
-	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-	if (!cmd)
-		return -ENOMEM;
-
-	cmd->test.id = TEST_CMD_CHANNEL_TUNE;
-
-	cmd->band = WL1271_CHANNEL_TUNE_BAND_2_4;
-	/* set up any channel, 7 is in the middle of the range */
-	cmd->channel = 7;
-
-	ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
-	if (ret < 0)
-		wl1271_warning("TEST_CMD_CHANNEL_TUNE failed");
-
-	kfree(cmd);
-	return ret;
-}
-
-static int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl)
-{
-	struct wl1271_cmd_cal_update_ref_point *cmd;
-	int ret = 0;
-
-	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-	if (!cmd)
-		return -ENOMEM;
-
-	cmd->test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT;
-
-	/* FIXME: still waiting for the correct values */
-	cmd->ref_power    = 0;
-	cmd->ref_detector = 0;
-
-	cmd->sub_band     = WL1271_PD_REFERENCE_POINT_BAND_B_G;
-
-	ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
-	if (ret < 0)
-		wl1271_warning("TEST_CMD_UPDATE_PD_REFERENCE_POINT failed");
-
-	kfree(cmd);
-	return ret;
-}
-
-static int wl1271_cmd_cal_p2g(struct wl1271 *wl)
-{
-	struct wl1271_cmd_cal_p2g *cmd;
-	int ret = 0;
-
-	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-	if (!cmd)
-		return -ENOMEM;
-
-	cmd->test.id = TEST_CMD_P2G_CAL;
-
-	cmd->sub_band_mask = WL1271_CAL_P2G_BAND_B_G;
-
-	ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
-	if (ret < 0)
-		wl1271_warning("TEST_CMD_P2G_CAL failed");
-
-	kfree(cmd);
-	return ret;
-}
-
-static int wl1271_cmd_cal(struct wl1271 *wl)
-{
-	/*
-	 * FIXME: we must make sure that we're not sleeping when calibration
-	 * is done
-	 */
-	int ret;
-
-	wl1271_notice("performing tx calibration");
-
-	ret = wl1271_cmd_cal_channel_tune(wl);
-	if (ret < 0)
-		return ret;
-
-	ret = wl1271_cmd_cal_update_ref_point(wl);
-	if (ret < 0)
-		return ret;
-
-	ret = wl1271_cmd_cal_p2g(wl);
-	if (ret < 0)
-		return ret;
-
-	return ret;
-}
-
 int wl1271_cmd_general_parms(struct wl1271 *wl)
 {
 	struct wl1271_general_parms_cmd *gen_parms;
@@ -212,8 +118,8 @@
 
 	gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
 
-	memcpy(gen_parms->params, wl->nvs->general_params,
-	       WL1271_NVS_GENERAL_PARAMS_SIZE);
+	memcpy(&gen_parms->general_params, &wl->nvs->general_params,
+	       sizeof(struct wl1271_ini_general_params));
 
 	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
 	if (ret < 0)
@@ -226,7 +132,7 @@
 int wl1271_cmd_radio_parms(struct wl1271 *wl)
 {
 	struct wl1271_radio_parms_cmd *radio_parms;
-	struct conf_radio_parms *rparam = &wl->conf.init.radioparam;
+	struct wl1271_ini_general_params *gp = &wl->nvs->general_params;
 	int ret;
 
 	if (!wl->nvs)
@@ -238,13 +144,20 @@
 
 	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
 
-	memcpy(radio_parms->stat_radio_params, wl->nvs->stat_radio_params,
-	       WL1271_NVS_STAT_RADIO_PARAMS_SIZE);
-	memcpy(radio_parms->dyn_radio_params,
-	       wl->nvs->dyn_radio_params[rparam->fem],
-	       WL1271_NVS_DYN_RADIO_PARAMS_SIZE);
+	/* 2.4GHz parameters */
+	memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2,
+	       sizeof(struct wl1271_ini_band_params_2));
+	memcpy(&radio_parms->dyn_params_2,
+	       &wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
+	       sizeof(struct wl1271_ini_fem_params_2));
 
-	/* FIXME: current NVS is missing 5GHz parameters */
+	/* 5GHz parameters */
+	memcpy(&radio_parms->static_params_5,
+	       &wl->nvs->stat_radio_params_5,
+	       sizeof(struct wl1271_ini_band_params_5));
+	memcpy(&radio_parms->dyn_params_5,
+	       &wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
+	       sizeof(struct wl1271_ini_fem_params_5));
 
 	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
 		    radio_parms, sizeof(*radio_parms));
@@ -288,20 +201,10 @@
 
 int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
 {
-	static bool do_cal = true;
 	struct wl1271_cmd_join *join;
 	int ret, i;
 	u8 *bssid;
 
-	/* FIXME: remove when we get calibration from the factory */
-	if (do_cal) {
-		ret = wl1271_cmd_cal(wl);
-		if (ret < 0)
-			wl1271_warning("couldn't calibrate");
-		else
-			do_cal = false;
-	}
-
 	join = kzalloc(sizeof(*join), GFP_KERNEL);
 	if (!join) {
 		ret = -ENOMEM;
@@ -329,12 +232,6 @@
 	join->channel = wl->channel;
 	join->ssid_len = wl->ssid_len;
 	memcpy(join->ssid, wl->ssid, wl->ssid_len);
-	join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH;
-
-	/* increment the session counter */
-	wl->session_counter++;
-	if (wl->session_counter >= SESSION_COUNTER_MAX)
-		wl->session_counter = 0;
 
 	join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
 
@@ -517,7 +414,7 @@
 	ps_params->send_null_data = send;
 	ps_params->retries = 5;
 	ps_params->hang_over_period = 1;
-	ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
+	ps_params->null_data_rate = cpu_to_le32(wl->basic_rate_set);
 
 	ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
 			      sizeof(*ps_params), 0);
@@ -566,140 +463,6 @@
 	return ret;
 }
 
-int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
-		    const u8 *ie, size_t ie_len, u8 active_scan,
-		    u8 high_prio, u8 band, u8 probe_requests)
-{
-
-	struct wl1271_cmd_trigger_scan_to *trigger = NULL;
-	struct wl1271_cmd_scan *params = NULL;
-	struct ieee80211_channel *channels;
-	u32 rate;
-	int i, j, n_ch, ret;
-	u16 scan_options = 0;
-	u8 ieee_band;
-
-	if (band == WL1271_SCAN_BAND_2_4_GHZ) {
-		ieee_band = IEEE80211_BAND_2GHZ;
-		rate = wl->conf.tx.basic_rate;
-	} else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) {
-		ieee_band = IEEE80211_BAND_2GHZ;
-		rate = wl->conf.tx.basic_rate;
-	} else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) {
-		ieee_band = IEEE80211_BAND_5GHZ;
-		rate = wl->conf.tx.basic_rate_5;
-	} else
-		return -EINVAL;
-
-	if (wl->hw->wiphy->bands[ieee_band]->channels == NULL)
-		return -EINVAL;
-
-	channels = wl->hw->wiphy->bands[ieee_band]->channels;
-	n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
-
-	if (test_bit(WL1271_FLAG_SCANNING, &wl->flags))
-		return -EINVAL;
-
-	params = kzalloc(sizeof(*params), GFP_KERNEL);
-	if (!params)
-		return -ENOMEM;
-
-	params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
-	params->params.rx_filter_options =
-		cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
-
-	if (!active_scan)
-		scan_options |= WL1271_SCAN_OPT_PASSIVE;
-	if (high_prio)
-		scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH;
-	params->params.scan_options = cpu_to_le16(scan_options);
-
-	params->params.num_probe_requests = probe_requests;
-	params->params.tx_rate = cpu_to_le32(rate);
-	params->params.tid_trigger = 0;
-	params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
-
-	if (band == WL1271_SCAN_BAND_DUAL)
-		params->params.band = WL1271_SCAN_BAND_2_4_GHZ;
-	else
-		params->params.band = band;
-
-	for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) {
-		if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) {
-			params->channels[j].min_duration =
-				cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
-			params->channels[j].max_duration =
-				cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
-			memset(&params->channels[j].bssid_lsb, 0xff, 4);
-			memset(&params->channels[j].bssid_msb, 0xff, 2);
-			params->channels[j].early_termination = 0;
-			params->channels[j].tx_power_att =
-				WL1271_SCAN_CURRENT_TX_PWR;
-			params->channels[j].channel = channels[i].hw_value;
-			j++;
-		}
-	}
-
-	params->params.num_channels = j;
-
-	if (ssid_len && ssid) {
-		params->params.ssid_len = ssid_len;
-		memcpy(params->params.ssid, ssid, ssid_len);
-	}
-
-	ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len,
-					 ie, ie_len, ieee_band);
-	if (ret < 0) {
-		wl1271_error("PROBE request template failed");
-		goto out;
-	}
-
-	trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
-	if (!trigger) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	/* disable the timeout */
-	trigger->timeout = 0;
-
-	ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
-			      sizeof(*trigger), 0);
-	if (ret < 0) {
-		wl1271_error("trigger scan to failed for hw scan");
-		goto out;
-	}
-
-	wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
-
-	set_bit(WL1271_FLAG_SCANNING, &wl->flags);
-	if (wl1271_11a_enabled()) {
-		wl->scan.state = band;
-		if (band == WL1271_SCAN_BAND_DUAL) {
-			wl->scan.active = active_scan;
-			wl->scan.high_prio = high_prio;
-			wl->scan.probe_requests = probe_requests;
-			if (ssid_len && ssid) {
-				wl->scan.ssid_len = ssid_len;
-				memcpy(wl->scan.ssid, ssid, ssid_len);
-			} else
-				wl->scan.ssid_len = 0;
-		}
-	}
-
-	ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0);
-	if (ret < 0) {
-		wl1271_error("SCAN failed");
-		clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
-		goto out;
-	}
-
-out:
-	kfree(params);
-	kfree(trigger);
-	return ret;
-}
-
 int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
 			    void *buf, size_t buf_len, int index, u32 rates)
 {
@@ -804,7 +567,7 @@
 		goto out;
 
 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
-				      skb->len, 0, wl->basic_rate);
+				      skb->len, 0, wl->basic_rate_set);
 
 out:
 	dev_kfree_skb(skb);
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h
index f2820b4..af577ee 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h
@@ -41,9 +41,6 @@
 int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send);
 int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
 			   size_t len);
-int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
-		    const u8 *ie, size_t ie_len, u8 active_scan,
-		    u8 high_prio, u8 band, u8 probe_requests);
 int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
 			    void *buf, size_t buf_len, int index, u32 rates);
 int wl1271_cmd_build_null_data(struct wl1271 *wl);
@@ -136,14 +133,14 @@
 	__le16 status;
 	/* payload */
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define WL1271_CMD_MAX_PARAMS 572
 
 struct wl1271_command {
 	struct wl1271_cmd_header header;
 	u8  parameters[WL1271_CMD_MAX_PARAMS];
-} __attribute__ ((packed));
+} __packed;
 
 enum {
 	CMD_MAILBOX_IDLE		=  0,
@@ -196,7 +193,7 @@
 	   of this field is the Host in WRITE command or the Wilink in READ
 	   command. */
 	u8 value[MAX_READ_SIZE];
-} __attribute__ ((packed));
+} __packed;
 
 #define CMDMBOX_HEADER_LEN 4
 #define CMDMBOX_INFO_ELEM_HEADER_LEN 4
@@ -243,14 +240,14 @@
 	u8 ssid[IW_ESSID_MAX_SIZE];
 	u8 ctrl; /* JOIN_CMD_CTRL_* */
 	u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
 
 struct cmd_enabledisable_path {
 	struct wl1271_cmd_header header;
 
 	u8 channel;
 	u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 #define WL1271_RATE_AUTOMATIC  0
 
@@ -266,7 +263,7 @@
 	u8 aflags;
 	u8 reserved;
 	u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE];
-} __attribute__ ((packed));
+} __packed;
 
 #define TIM_ELE_ID    5
 #define PARTIAL_VBM_MAX    251
@@ -278,7 +275,7 @@
 	u8 dtim_period;
 	u8 bitmap_ctrl;
 	u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
-} __attribute__ ((packed));
+} __packed;
 
 enum wl1271_cmd_ps_mode {
 	STATION_ACTIVE_MODE,
@@ -298,7 +295,7 @@
 	  */
 	u8 hang_over_period;
 	__le32 null_data_rate;
-} __attribute__ ((packed));
+} __packed;
 
 /* HW encryption keys */
 #define NUM_ACCESS_CATEGORIES_COPY 4
@@ -348,77 +345,12 @@
 	u8 key[MAX_KEY_SIZE];
 	__le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
 	__le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __attribute__ ((packed));
-
-
-#define WL1271_SCAN_MAX_CHANNELS       24
-#define WL1271_SCAN_DEFAULT_TAG        1
-#define WL1271_SCAN_CURRENT_TX_PWR     0
-#define WL1271_SCAN_OPT_ACTIVE         0
-#define WL1271_SCAN_OPT_PASSIVE	       1
-#define WL1271_SCAN_OPT_PRIORITY_HIGH  4
-#define WL1271_SCAN_CHAN_MIN_DURATION  30000  /* TU */
-#define WL1271_SCAN_CHAN_MAX_DURATION  60000  /* TU */
-#define WL1271_SCAN_BAND_2_4_GHZ 0
-#define WL1271_SCAN_BAND_5_GHZ 1
-#define WL1271_SCAN_BAND_DUAL 2
-
-struct basic_scan_params {
-	__le32 rx_config_options;
-	__le32 rx_filter_options;
-	/* Scan option flags (WL1271_SCAN_OPT_*) */
-	__le16 scan_options;
-	/* Number of scan channels in the list (maximum 30) */
-	u8 num_channels;
-	/* This field indicates the number of probe requests to send
-	   per channel for an active scan */
-	u8 num_probe_requests;
-	/* Rate bit field for sending the probes */
-	__le32 tx_rate;
-	u8 tid_trigger;
-	u8 ssid_len;
-	/* in order to align */
-	u8 padding1[2];
-	u8 ssid[IW_ESSID_MAX_SIZE];
-	/* Band to scan */
-	u8 band;
-	u8 use_ssid_list;
-	u8 scan_tag;
-	u8 padding2;
-} __attribute__ ((packed));
-
-struct basic_scan_channel_params {
-	/* Duration in TU to wait for frames on a channel for active scan */
-	__le32 min_duration;
-	__le32 max_duration;
-	__le32 bssid_lsb;
-	__le16 bssid_msb;
-	u8 early_termination;
-	u8 tx_power_att;
-	u8 channel;
-	/* FW internal use only! */
-	u8 dfs_candidate;
-	u8 activity_detected;
-	u8 pad;
-} __attribute__ ((packed));
-
-struct wl1271_cmd_scan {
-	struct wl1271_cmd_header header;
-
-	struct basic_scan_params params;
-	struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
-} __attribute__ ((packed));
-
-struct wl1271_cmd_trigger_scan_to {
-	struct wl1271_cmd_header header;
-
-	__le32 timeout;
-} __attribute__ ((packed));
+} __packed;
 
 struct wl1271_cmd_test_header {
 	u8 id;
 	u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 enum wl1271_channel_tune_bands {
 	WL1271_CHANNEL_TUNE_BAND_2_4,
@@ -439,25 +371,31 @@
 
 	struct wl1271_cmd_test_header test;
 
-	u8 params[WL1271_NVS_GENERAL_PARAMS_SIZE];
-	s8 reserved[23];
-} __attribute__ ((packed));
+	struct wl1271_ini_general_params general_params;
 
-#define WL1271_STAT_RADIO_PARAMS_5_SIZE    29
-#define WL1271_DYN_RADIO_PARAMS_5_SIZE    104
+	u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+	u8 sr_sen_n_p;
+	u8 sr_sen_n_p_gain;
+	u8 sr_sen_nrn;
+	u8 sr_sen_prn;
+	u8 padding[3];
+} __packed;
 
 struct wl1271_radio_parms_cmd {
 	struct wl1271_cmd_header header;
 
 	struct wl1271_cmd_test_header test;
 
-	u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE];
-	u8 stat_radio_params_5[WL1271_STAT_RADIO_PARAMS_5_SIZE];
+	/* Static radio parameters */
+	struct wl1271_ini_band_params_2 static_params_2;
+	struct wl1271_ini_band_params_5 static_params_5;
 
-	u8 dyn_radio_params[WL1271_NVS_DYN_RADIO_PARAMS_SIZE];
-	u8 reserved;
-	u8 dyn_radio_params_5[WL1271_DYN_RADIO_PARAMS_5_SIZE];
-} __attribute__ ((packed));
+	/* Dynamic radio parameters */
+	struct wl1271_ini_fem_params_2 dyn_params_2;
+	u8 padding2;
+	struct wl1271_ini_fem_params_5 dyn_params_5;
+	u8 padding3[2];
+} __packed;
 
 struct wl1271_cmd_cal_channel_tune {
 	struct wl1271_cmd_header header;
@@ -468,7 +406,7 @@
 	u8 channel;
 
 	__le16 radio_status;
-} __attribute__ ((packed));
+} __packed;
 
 struct wl1271_cmd_cal_update_ref_point {
 	struct wl1271_cmd_header header;
@@ -479,7 +417,7 @@
 	__le32 ref_detector;
 	u8  sub_band;
 	u8  padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 #define MAX_TLV_LENGTH         400
 #define	MAX_NVS_VERSION_LENGTH 12
@@ -501,7 +439,7 @@
 
 	u8  sub_band_mask;
 	u8  padding2;
-} __attribute__ ((packed));
+} __packed;
 
 
 /*
@@ -529,6 +467,6 @@
 	u8  type;
 
 	u8  padding;
-} __attribute__ ((packed));
+} __packed;
 
 #endif /* __WL1271_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h
index d046d04..0435ffd 100644
--- a/drivers/net/wireless/wl12xx/wl1271_conf.h
+++ b/drivers/net/wireless/wl12xx/wl1271_conf.h
@@ -874,6 +874,13 @@
 	u8 ps_poll_threshold;
 
 	/*
+	 * PS Poll failure recovery ACTIVE period length
+	 *
+	 * Range: u32 (ms)
+	 */
+	u32 ps_poll_recovery_period;
+
+	/*
 	 * Configuration of signal average weights.
 	 */
 	struct conf_sig_weights sig_weights;
@@ -948,14 +955,6 @@
 	u8 fem;
 };
 
-struct conf_init_settings {
-	/*
-	 * Configure radio parameters.
-	 */
-	struct conf_radio_parms radioparam;
-
-};
-
 struct conf_itrim_settings {
 	/* enable dco itrim */
 	u8 enable;
@@ -1022,7 +1021,6 @@
 	struct conf_rx_settings rx;
 	struct conf_tx_settings tx;
 	struct conf_conn_settings conn;
-	struct conf_init_settings init;
 	struct conf_itrim_settings itrim;
 	struct conf_pm_config_settings pm_config;
 	struct conf_roam_trigger_settings roam_trigger;
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c
index cf37aa6..25ce2cd 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.c
+++ b/drivers/net/wireless/wl12xx/wl1271_event.c
@@ -26,36 +26,64 @@
 #include "wl1271_io.h"
 #include "wl1271_event.h"
 #include "wl1271_ps.h"
+#include "wl1271_scan.h"
 #include "wl12xx_80211.h"
 
-static int wl1271_event_scan_complete(struct wl1271 *wl,
-				      struct event_mailbox *mbox)
+void wl1271_pspoll_work(struct work_struct *work)
 {
-	wl1271_debug(DEBUG_EVENT, "status: 0x%x",
-		     mbox->scheduled_scan_status);
+	struct delayed_work *dwork;
+	struct wl1271 *wl;
 
-	if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
-		if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
-			/* 2.4 GHz band scanned, scan 5 GHz band, pretend
-			 * to the wl1271_cmd_scan function that we are not
-			 * scanning as it checks that.
-			 */
-			clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
-			/* FIXME: ie missing! */
-			wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
-						NULL, 0,
-						wl->scan.active,
-						wl->scan.high_prio,
-						WL1271_SCAN_BAND_5_GHZ,
-						wl->scan.probe_requests);
-		} else {
-			mutex_unlock(&wl->mutex);
-			ieee80211_scan_completed(wl->hw, false);
-			mutex_lock(&wl->mutex);
-			clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
-		}
+	dwork = container_of(work, struct delayed_work, work);
+	wl = container_of(dwork, struct wl1271, pspoll_work);
+
+	wl1271_debug(DEBUG_EVENT, "pspoll work");
+
+	mutex_lock(&wl->mutex);
+
+	if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags))
+		goto out;
+
+	if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+		goto out;
+
+	/*
+	 * if we end up here, then we were in powersave when the pspoll
+	 * delivery failure occurred, and no-one changed state since, so
+	 * we should go back to powersave.
+	 */
+	wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, true);
+
+out:
+	mutex_unlock(&wl->mutex);
+};
+
+static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl)
+{
+	int delay = wl->conf.conn.ps_poll_recovery_period;
+	int ret;
+
+	wl->ps_poll_failures++;
+	if (wl->ps_poll_failures == 1)
+		wl1271_info("AP with dysfunctional ps-poll, "
+			    "trying to work around it.");
+
+	/* force active mode receive data from the AP */
+	if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
+		ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, true);
+		if (ret < 0)
+			return;
+		set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
+		ieee80211_queue_delayed_work(wl->hw, &wl->pspoll_work,
+					     msecs_to_jiffies(delay));
 	}
-	return 0;
+
+	/*
+	 * If already in active mode, lets we should be getting data from
+	 * the AP right away. If we enter PSM too fast after this, and data
+	 * remains on the AP, we will get another event like this, and we'll
+	 * go into active once more.
+	 */
 }
 
 static int wl1271_event_ps_report(struct wl1271 *wl,
@@ -163,9 +191,19 @@
 	wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
 
 	if (vector & SCAN_COMPLETE_EVENT_ID) {
-		ret = wl1271_event_scan_complete(wl, mbox);
-		if (ret < 0)
-			return ret;
+		wl1271_debug(DEBUG_EVENT, "status: 0x%x",
+			     mbox->scheduled_scan_status);
+
+		wl1271_scan_stm(wl);
+	}
+
+	/* disable dynamic PS when requested by the firmware */
+	if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
+	    wl->bss_type == BSS_TYPE_STA_BSS) {
+		if (mbox->soft_gemini_sense_info)
+			ieee80211_disable_dyn_ps(wl->vif);
+		else
+			ieee80211_enable_dyn_ps(wl->vif);
 	}
 
 	/*
@@ -191,6 +229,9 @@
 			return ret;
 	}
 
+	if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
+		wl1271_event_pspoll_delivery_fail(wl);
+
 	if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
 		wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
 		if (wl->vif)
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h
index 5837100..e475166 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.h
+++ b/drivers/net/wireless/wl12xx/wl1271_event.h
@@ -85,7 +85,7 @@
 	__le32 report_1;
 	__le32 report_2;
 	__le32 report_3;
-} __attribute__ ((packed));
+} __packed;
 
 #define NUM_OF_RSSI_SNR_TRIGGERS 8
 
@@ -116,10 +116,11 @@
 	u8 ps_status;
 
 	u8 reserved_5[29];
-} __attribute__ ((packed));
+} __packed;
 
 int wl1271_event_unmask(struct wl1271 *wl);
 void wl1271_event_mbox_config(struct wl1271 *wl);
 int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
+void wl1271_pspoll_work(struct work_struct *work);
 
 #endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_ini.h b/drivers/net/wireless/wl12xx/wl1271_ini.h
new file mode 100644
index 0000000..2313047
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_ini.h
@@ -0,0 +1,123 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_INI_H__
+#define __WL1271_INI_H__
+
+#define WL1271_INI_MAX_SMART_REFLEX_PARAM 16
+
+struct wl1271_ini_general_params {
+	u8 ref_clock;
+	u8 settling_time;
+	u8 clk_valid_on_wakeup;
+	u8 dc2dc_mode;
+	u8 dual_mode_select;
+	u8 tx_bip_fem_auto_detect;
+	u8 tx_bip_fem_manufacturer;
+	u8 general_settings;
+	u8 sr_state;
+	u8 srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+	u8 srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+	u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+} __packed;
+
+#define WL1271_INI_RSSI_PROCESS_COMPENS_SIZE 15
+
+struct wl1271_ini_band_params_2 {
+	u8 rx_trace_insertion_loss;
+	u8 tx_trace_loss;
+	u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
+} __packed;
+
+#define WL1271_INI_RATE_GROUP_COUNT 6
+#define WL1271_INI_CHANNEL_COUNT_2 14
+
+struct wl1271_ini_fem_params_2 {
+	__le16 tx_bip_ref_pd_voltage;
+	u8 tx_bip_ref_power;
+	u8 tx_bip_ref_offset;
+	u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT];
+	u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT];
+	u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT];
+	u8 tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2];
+	u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2];
+	u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT];
+	u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT];
+	u8 rx_fem_insertion_loss;
+	u8 degraded_low_to_normal_thr;
+	u8 normal_to_degraded_high_thr;
+} __packed;
+
+#define WL1271_INI_CHANNEL_COUNT_5 35
+#define WL1271_INI_SUB_BAND_COUNT_5 7
+
+struct wl1271_ini_band_params_5 {
+	u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
+	u8 tx_trace_loss[WL1271_INI_SUB_BAND_COUNT_5];
+	u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
+} __packed;
+
+struct wl1271_ini_fem_params_5 {
+	__le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5];
+	u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5];
+	u8 tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5];
+	u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT];
+	u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT];
+	u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT];
+	u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5];
+	u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT];
+	u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT];
+	u8 rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
+	u8 degraded_low_to_normal_thr;
+	u8 normal_to_degraded_high_thr;
+} __packed;
+
+
+/* NVS data structure */
+#define WL1271_INI_NVS_SECTION_SIZE		     468
+#define WL1271_INI_FEM_MODULE_COUNT                  2
+
+#define WL1271_INI_LEGACY_NVS_FILE_SIZE              800
+
+struct wl1271_nvs_file {
+	/* NVS section */
+	u8 nvs[WL1271_INI_NVS_SECTION_SIZE];
+
+	/* INI section */
+	struct wl1271_ini_general_params general_params;
+	u8 padding1;
+	struct wl1271_ini_band_params_2 stat_radio_params_2;
+	u8 padding2;
+	struct {
+		struct wl1271_ini_fem_params_2 params;
+		u8 padding;
+	} dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
+	struct wl1271_ini_band_params_5 stat_radio_params_5;
+	u8 padding3;
+	struct {
+		struct wl1271_ini_fem_params_5 params;
+		u8 padding;
+	} dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
+} __packed;
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index b7d9137..9d68f00 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -28,7 +28,6 @@
 #include <linux/crc32.h>
 #include <linux/etherdevice.h>
 #include <linux/vmalloc.h>
-#include <linux/inetdevice.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
@@ -45,6 +44,7 @@
 #include "wl1271_cmd.h"
 #include "wl1271_boot.h"
 #include "wl1271_testmode.h"
+#include "wl1271_scan.h"
 
 #define WL1271_BOOT_RETRIES 3
 
@@ -55,7 +55,7 @@
 			[CONF_SG_HV3_MAX_OVERRIDE]                  = 0,
 			[CONF_SG_BT_NFS_SAMPLE_INTERVAL]            = 400,
 			[CONF_SG_BT_LOAD_RATIO]                     = 50,
-			[CONF_SG_AUTO_PS_MODE]                      = 0,
+			[CONF_SG_AUTO_PS_MODE]                      = 1,
 			[CONF_SG_AUTO_SCAN_PROBE_REQ]               = 170,
 			[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3]   = 50,
 			[CONF_SG_ANTENNA_CONFIGURATION]             = 0,
@@ -234,18 +234,14 @@
 		.beacon_rx_timeout           = 10000,
 		.broadcast_timeout           = 20000,
 		.rx_broadcast_in_ps          = 1,
-		.ps_poll_threshold           = 20,
+		.ps_poll_threshold           = 10,
+		.ps_poll_recovery_period     = 700,
 		.bet_enable                  = CONF_BET_MODE_ENABLE,
 		.bet_max_consecutive         = 10,
 		.psm_entry_retries           = 3,
 		.keep_alive_interval         = 55000,
 		.max_listen_interval         = 20,
 	},
-	.init = {
-		.radioparam = {
-			.fem                 = 1,
-		}
-	},
 	.itrim = {
 		.enable = false,
 		.timeout = 50000,
@@ -566,14 +562,21 @@
 		return ret;
 	}
 
-	if (fw->size != sizeof(struct wl1271_nvs_file)) {
+	/*
+	 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
+	 * configurations) can be removed when those NVS files stop floating
+	 * around.
+	 */
+	if (fw->size != sizeof(struct wl1271_nvs_file) &&
+	    (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
+	     wl1271_11a_enabled())) {
 		wl1271_error("nvs size is not as expected: %zu != %zu",
 			     fw->size, sizeof(struct wl1271_nvs_file));
 		ret = -EILSEQ;
 		goto out;
 	}
 
-	wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
+	wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
 
 	if (!wl->nvs) {
 		wl1271_error("could not allocate memory for the nvs file");
@@ -581,8 +584,6 @@
 		goto out;
 	}
 
-	memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
-
 out:
 	release_firmware(fw);
 
@@ -811,93 +812,6 @@
 	return NETDEV_TX_OK;
 }
 
-static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
-			     void *arg)
-{
-	struct net_device *dev;
-	struct wireless_dev *wdev;
-	struct wiphy *wiphy;
-	struct ieee80211_hw *hw;
-	struct wl1271 *wl;
-	struct wl1271 *wl_temp;
-	struct in_device *idev;
-	struct in_ifaddr *ifa = arg;
-	int ret = 0;
-
-	/* FIXME: this ugly function should probably be implemented in the
-	 * mac80211, and here should only be a simple callback handling actual
-	 * setting of the filters. Now we need to dig up references to
-	 * various structures to gain access to what we need.
-	 * Also, because of this, there is no "initial" setting of the filter
-	 * in "op_start", because we don't want to dig up struct net_device
-	 * there - the filter will be set upon first change of the interface
-	 * IP address. */
-
-	dev = ifa->ifa_dev->dev;
-
-	wdev = dev->ieee80211_ptr;
-	if (wdev == NULL)
-		return NOTIFY_DONE;
-
-	wiphy = wdev->wiphy;
-	if (wiphy == NULL)
-		return NOTIFY_DONE;
-
-	hw = wiphy_priv(wiphy);
-	if (hw == NULL)
-		return NOTIFY_DONE;
-
-	/* Check that the interface is one supported by this driver. */
-	wl_temp = hw->priv;
-	list_for_each_entry(wl, &wl_list, list) {
-		if (wl == wl_temp)
-			break;
-	}
-	if (wl != wl_temp)
-		return NOTIFY_DONE;
-
-	/* Get the interface IP address for the device. "ifa" will become
-	   NULL if:
-	     - there is no IPV4 protocol address configured
-	     - there are multiple (virtual) IPV4 addresses configured
-	   When "ifa" is NULL, filtering will be disabled.
-	*/
-	ifa = NULL;
-	idev = dev->ip_ptr;
-	if (idev)
-		ifa = idev->ifa_list;
-
-	if (ifa && ifa->ifa_next)
-		ifa = NULL;
-
-	mutex_lock(&wl->mutex);
-
-	if (wl->state == WL1271_STATE_OFF)
-		goto out;
-
-	ret = wl1271_ps_elp_wakeup(wl, false);
-	if (ret < 0)
-		goto out;
-	if (ifa)
-		ret = wl1271_acx_arp_ip_filter(wl, true,
-					       (u8 *)&ifa->ifa_address,
-					       ACX_IPV4_VERSION);
-	else
-		ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
-					       ACX_IPV4_VERSION);
-	wl1271_ps_elp_sleep(wl);
-
-out:
-	mutex_unlock(&wl->mutex);
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block wl1271_dev_notifier = {
-	.notifier_call = wl1271_dev_notify,
-};
-
-
 static int wl1271_op_start(struct ieee80211_hw *hw)
 {
 	wl1271_debug(DEBUG_MAC80211, "mac80211 start");
@@ -925,6 +839,7 @@
 				   struct ieee80211_vif *vif)
 {
 	struct wl1271 *wl = hw->priv;
+	struct wiphy *wiphy = hw->wiphy;
 	int retries = WL1271_BOOT_RETRIES;
 	int ret = 0;
 
@@ -978,6 +893,12 @@
 
 		wl->state = WL1271_STATE_ON;
 		wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
+
+		/* update hw/fw version info in wiphy struct */
+		wiphy->hw_version = wl->chip.id;
+		strncpy(wiphy->fw_version, wl->chip.fw_ver,
+			sizeof(wiphy->fw_version));
+
 		goto out;
 
 irq_disable:
@@ -1001,10 +922,8 @@
 out:
 	mutex_unlock(&wl->mutex);
 
-	if (!ret) {
+	if (!ret)
 		list_add(&wl->list, &wl_list);
-		register_inetaddr_notifier(&wl1271_dev_notifier);
-	}
 
 	return ret;
 }
@@ -1015,8 +934,6 @@
 	struct wl1271 *wl = hw->priv;
 	int i;
 
-	unregister_inetaddr_notifier(&wl1271_dev_notifier);
-
 	mutex_lock(&wl->mutex);
 	wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
 
@@ -1026,10 +943,17 @@
 
 	WARN_ON(wl->state != WL1271_STATE_ON);
 
-	if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
+	/* enable dyn ps just in case (if left on due to fw crash etc) */
+	if (wl->bss_type == BSS_TYPE_STA_BSS)
+		ieee80211_enable_dyn_ps(wl->vif);
+
+	if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
 		mutex_unlock(&wl->mutex);
 		ieee80211_scan_completed(wl->hw, true);
 		mutex_lock(&wl->mutex);
+		wl->scan.state = WL1271_SCAN_STATE_IDLE;
+		kfree(wl->scan.scanned_ch);
+		wl->scan.scanned_ch = NULL;
 	}
 
 	wl->state = WL1271_STATE_OFF;
@@ -1040,11 +964,12 @@
 
 	cancel_work_sync(&wl->irq_work);
 	cancel_work_sync(&wl->tx_work);
+	cancel_delayed_work_sync(&wl->pspoll_work);
 
 	mutex_lock(&wl->mutex);
 
 	/* let's notify MAC80211 about the remaining pending TX frames */
-	wl1271_tx_flush(wl);
+	wl1271_tx_reset(wl);
 	wl1271_power_off(wl);
 
 	memset(wl->bssid, 0, ETH_ALEN);
@@ -1241,6 +1166,42 @@
 	return rate;
 }
 
+static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
+{
+	int ret;
+
+	if (idle) {
+		if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
+			ret = wl1271_unjoin(wl);
+			if (ret < 0)
+				goto out;
+		}
+		wl->rate_set = wl1271_min_rate_get(wl);
+		wl->sta_rate_set = 0;
+		ret = wl1271_acx_rate_policies(wl);
+		if (ret < 0)
+			goto out;
+		ret = wl1271_acx_keep_alive_config(
+			wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
+			ACX_KEEP_ALIVE_TPL_INVALID);
+		if (ret < 0)
+			goto out;
+		set_bit(WL1271_FLAG_IDLE, &wl->flags);
+	} else {
+		/* increment the session counter */
+		wl->session_counter++;
+		if (wl->session_counter >= SESSION_COUNTER_MAX)
+			wl->session_counter = 0;
+		ret = wl1271_dummy_join(wl);
+		if (ret < 0)
+			goto out;
+		clear_bit(WL1271_FLAG_IDLE, &wl->flags);
+	}
+
+out:
+	return ret;
+}
+
 static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct wl1271 *wl = hw->priv;
@@ -1255,6 +1216,15 @@
 		     conf->power_level,
 		     conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
 
+	/*
+	 * mac80211 will go to idle nearly immediately after transmitting some
+	 * frames, such as the deauth. To make sure those frames reach the air,
+	 * wait here until the TX queue is fully flushed.
+	 */
+	if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
+	    (conf->flags & IEEE80211_CONF_IDLE))
+		wl1271_tx_flush(wl);
+
 	mutex_lock(&wl->mutex);
 
 	if (unlikely(wl->state == WL1271_STATE_OFF))
@@ -1295,24 +1265,18 @@
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_IDLE) {
-		if (conf->flags & IEEE80211_CONF_IDLE &&
-		    test_bit(WL1271_FLAG_JOINED, &wl->flags))
-			wl1271_unjoin(wl);
-		else if (!(conf->flags & IEEE80211_CONF_IDLE))
-			wl1271_dummy_join(wl);
-
-		if (conf->flags & IEEE80211_CONF_IDLE) {
-			wl->rate_set = wl1271_min_rate_get(wl);
-			wl->sta_rate_set = 0;
-			wl1271_acx_rate_policies(wl);
-			wl1271_acx_keep_alive_config(
-				wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
-				ACX_KEEP_ALIVE_TPL_INVALID);
-			set_bit(WL1271_FLAG_IDLE, &wl->flags);
-		} else
-			clear_bit(WL1271_FLAG_IDLE, &wl->flags);
+		ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
+		if (ret < 0)
+			wl1271_warning("idle mode change failed %d", ret);
 	}
 
+	/*
+	 * if mac80211 changes the PSM mode, make sure the mode is not
+	 * incorrectly changed after the pspoll failure active window.
+	 */
+	if (changed & IEEE80211_CONF_CHANGE_PS)
+		clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
+
 	if (conf->flags & IEEE80211_CONF_PS &&
 	    !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
 		set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
@@ -1595,13 +1559,9 @@
 		goto out;
 
 	if (wl1271_11a_enabled())
-		ret = wl1271_cmd_scan(hw->priv, ssid, len,
-				      req->ie, req->ie_len, 1, 0,
-				      WL1271_SCAN_BAND_DUAL, 3);
+		ret = wl1271_scan(hw->priv, ssid, len, req);
 	else
-		ret = wl1271_cmd_scan(hw->priv, ssid, len,
-				      req->ie, req->ie_len, 1, 0,
-				      WL1271_SCAN_BAND_2_4_GHZ, 3);
+		ret = wl1271_scan(hw->priv, ssid, len, req);
 
 	wl1271_ps_elp_sleep(wl);
 
@@ -1774,6 +1734,8 @@
 			wl->aid = bss_conf->aid;
 			set_assoc = true;
 
+			wl->ps_poll_failures = 0;
+
 			/*
 			 * use basic rates from AP, and determine lowest rate
 			 * to use with control frames.
@@ -1823,6 +1785,9 @@
 			clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
 			wl->aid = 0;
 
+			/* re-enable dynamic ps - just in case */
+			ieee80211_enable_dyn_ps(wl->vif);
+
 			/* revert back to minimum rates for the current band */
 			wl1271_set_band_rate(wl);
 			wl->basic_rate = wl1271_min_rate_get(wl);
@@ -1871,6 +1836,19 @@
 		}
 	}
 
+	if (changed & BSS_CHANGED_ARP_FILTER) {
+		__be32 addr = bss_conf->arp_addr_list[0];
+		WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
+
+		if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
+			ret = wl1271_acx_arp_ip_filter(wl, true, addr);
+		else
+			ret = wl1271_acx_arp_ip_filter(wl, false, addr);
+
+		if (ret < 0)
+			goto out_sleep;
+	}
+
 	if (do_join) {
 		ret = wl1271_join(wl, set_assoc);
 		if (ret < 0) {
@@ -1929,6 +1907,48 @@
 	return ret;
 }
 
+static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
+{
+
+	struct wl1271 *wl = hw->priv;
+	u64 mactime = ULLONG_MAX;
+	int ret;
+
+	wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
+
+	mutex_lock(&wl->mutex);
+
+	ret = wl1271_ps_elp_wakeup(wl, false);
+	if (ret < 0)
+		goto out;
+
+	ret = wl1271_acx_tsf_info(wl, &mactime);
+	if (ret < 0)
+		goto out_sleep;
+
+out_sleep:
+	wl1271_ps_elp_sleep(wl);
+
+out:
+	mutex_unlock(&wl->mutex);
+	return mactime;
+}
+
+static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
+				struct survey_info *survey)
+{
+	struct wl1271 *wl = hw->priv;
+	struct ieee80211_conf *conf = &hw->conf;
+ 
+	if (idx != 0)
+		return -ENOENT;
+ 
+	survey->channel = conf->channel;
+	survey->filled = SURVEY_INFO_NOISE_DBM;
+	survey->noise = wl->noise;
+ 
+	return 0;
+}
 
 /* can't be const, mac80211 writes to this */
 static struct ieee80211_rate wl1271_rates[] = {
@@ -1991,7 +2011,7 @@
 };
 
 /* mapping to indexes for wl1271_rates */
-const static u8 wl1271_rate_to_idx_2ghz[] = {
+static const u8 wl1271_rate_to_idx_2ghz[] = {
 	/* MCS rates are used only with 11n */
 	CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
 	CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
@@ -2103,7 +2123,7 @@
 };
 
 /* mapping to indexes for wl1271_rates_5ghz */
-const static u8 wl1271_rate_to_idx_5ghz[] = {
+static const u8 wl1271_rate_to_idx_5ghz[] = {
 	/* MCS rates are used only with 11n */
 	CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
 	CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
@@ -2139,7 +2159,7 @@
 	.n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
 };
 
-const static u8 *wl1271_band_rate_to_idx[] = {
+static const u8 *wl1271_band_rate_to_idx[] = {
 	[IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
 	[IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
 };
@@ -2158,6 +2178,8 @@
 	.bss_info_changed = wl1271_op_bss_info_changed,
 	.set_rts_threshold = wl1271_op_set_rts_threshold,
 	.conf_tx = wl1271_op_conf_tx,
+	.get_tsf = wl1271_op_get_tsf,
+	.get_survey = wl1271_op_get_survey,
 	CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
 };
 
@@ -2350,15 +2372,13 @@
 		goto err_hw_alloc;
 	}
 
-	plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
+	plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
 	if (!plat_dev) {
 		wl1271_error("could not allocate platform_device");
 		ret = -ENOMEM;
 		goto err_plat_alloc;
 	}
 
-	memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
-
 	wl = hw->priv;
 	memset(wl, 0, sizeof(*wl));
 
@@ -2370,6 +2390,7 @@
 	skb_queue_head_init(&wl->tx_queue);
 
 	INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
+	INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
 	wl->channel = WL1271_DEFAULT_CHANNEL;
 	wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
 	wl->default_key = 0;
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c
index b98fb64..019aa79 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.c
@@ -53,14 +53,15 @@
 	status->band = wl->band;
 	status->rate_idx = wl1271_rate_to_idx(wl, desc->rate);
 
-	/*
-	 * FIXME: Add mactime handling.  For IBSS (ad-hoc) we need to get the
-	 * timestamp from the beacon (acx_tsf_info).  In BSS mode (infra) we
-	 * only need the mactime for monitor mode.  For now the mactime is
-	 * not valid, so RX_FLAG_TSFT should not be set
-	 */
 	status->signal = desc->rssi;
 
+	/*
+	 * FIXME: In wl1251, the SNR should be divided by two.  In wl1271 we
+	 * need to divide by two for now, but TI has been discussing about
+	 * changing it.  This needs to be rechecked.
+	 */
+	wl->noise = desc->rssi - (desc->snr >> 1);
+
 	status->freq = ieee80211_channel_to_frequency(desc->channel);
 
 	if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/wl1271_rx.h
index b89be47..13a2323 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.h
@@ -113,7 +113,7 @@
 	u8  process_id;
 	u8  pad_len;
 	u8  reserved;
-} __attribute__ ((packed));
+} __packed;
 
 void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status);
 u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c
new file mode 100644
index 0000000..fec43ee
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_scan.c
@@ -0,0 +1,257 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/ieee80211.h>
+
+#include "wl1271.h"
+#include "wl1271_cmd.h"
+#include "wl1271_scan.h"
+#include "wl1271_acx.h"
+
+static int wl1271_get_scan_channels(struct wl1271 *wl,
+				    struct cfg80211_scan_request *req,
+				    struct basic_scan_channel_params *channels,
+				    enum ieee80211_band band, bool passive)
+{
+	int i, j;
+	u32 flags;
+
+	for (i = 0, j = 0;
+	     i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
+	     i++) {
+
+		flags = req->channels[i]->flags;
+
+		if (!wl->scan.scanned_ch[i] &&
+		    !(flags & IEEE80211_CHAN_DISABLED) &&
+		    ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) &&
+		    (req->channels[i]->band == band)) {
+
+			wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
+				     req->channels[i]->band,
+				     req->channels[i]->center_freq);
+			wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
+				     req->channels[i]->hw_value,
+				     req->channels[i]->flags);
+			wl1271_debug(DEBUG_SCAN,
+				     "max_antenna_gain %d, max_power %d",
+				     req->channels[i]->max_antenna_gain,
+				     req->channels[i]->max_power);
+			wl1271_debug(DEBUG_SCAN, "beacon_found %d",
+				     req->channels[i]->beacon_found);
+
+			channels[j].min_duration =
+				cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
+			channels[j].max_duration =
+				cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
+			channels[j].early_termination = 0;
+			channels[j].tx_power_att = req->channels[i]->max_power;
+			channels[j].channel = req->channels[i]->hw_value;
+
+			memset(&channels[j].bssid_lsb, 0xff, 4);
+			memset(&channels[j].bssid_msb, 0xff, 2);
+
+			/* Mark the channels we already used */
+			wl->scan.scanned_ch[i] = true;
+
+			j++;
+		}
+	}
+
+	return j;
+}
+
+#define WL1271_NOTHING_TO_SCAN 1
+
+static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
+			     bool passive, u32 basic_rate)
+{
+	struct wl1271_cmd_scan *cmd;
+	struct wl1271_cmd_trigger_scan_to *trigger;
+	int ret;
+	u16 scan_options = 0;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
+	if (!cmd || !trigger) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* We always use high priority scans */
+	scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH;
+	if(passive)
+		scan_options |= WL1271_SCAN_OPT_PASSIVE;
+	cmd->params.scan_options = cpu_to_le16(scan_options);
+
+	cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
+						    cmd->channels,
+						    band, passive);
+	if (cmd->params.n_ch == 0) {
+		ret = WL1271_NOTHING_TO_SCAN;
+		goto out;
+	}
+
+	cmd->params.tx_rate = cpu_to_le32(basic_rate);
+	cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
+	cmd->params.rx_filter_options =
+		cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
+
+	cmd->params.n_probe_reqs = WL1271_SCAN_PROBE_REQS;
+	cmd->params.tx_rate = cpu_to_le32(basic_rate);
+	cmd->params.tid_trigger = 0;
+	cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
+
+	if (band == IEEE80211_BAND_2GHZ)
+		cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ;
+	else
+		cmd->params.band = WL1271_SCAN_BAND_5_GHZ;
+
+	if (wl->scan.ssid_len && wl->scan.ssid) {
+		cmd->params.ssid_len = wl->scan.ssid_len;
+		memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
+	}
+
+	ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len,
+					 wl->scan.req->ie, wl->scan.req->ie_len,
+					 band);
+	if (ret < 0) {
+		wl1271_error("PROBE request template failed");
+		goto out;
+	}
+
+	/* disable the timeout */
+	trigger->timeout = 0;
+	ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
+			      sizeof(*trigger), 0);
+	if (ret < 0) {
+		wl1271_error("trigger scan to failed for hw scan");
+		goto out;
+	}
+
+	wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+
+	ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
+	if (ret < 0) {
+		wl1271_error("SCAN failed");
+		goto out;
+	}
+
+out:
+	kfree(cmd);
+	kfree(trigger);
+	return ret;
+}
+
+void wl1271_scan_stm(struct wl1271 *wl)
+{
+	int ret;
+
+	switch (wl->scan.state) {
+	case WL1271_SCAN_STATE_IDLE:
+		break;
+
+	case WL1271_SCAN_STATE_2GHZ_ACTIVE:
+		ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false,
+				       wl->conf.tx.basic_rate);
+		if (ret == WL1271_NOTHING_TO_SCAN) {
+			wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
+			wl1271_scan_stm(wl);
+		}
+
+		break;
+
+	case WL1271_SCAN_STATE_2GHZ_PASSIVE:
+		ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true,
+				       wl->conf.tx.basic_rate);
+		if (ret == WL1271_NOTHING_TO_SCAN) {
+			if (wl1271_11a_enabled())
+				wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
+			else
+				wl->scan.state = WL1271_SCAN_STATE_DONE;
+			wl1271_scan_stm(wl);
+		}
+
+		break;
+
+	case WL1271_SCAN_STATE_5GHZ_ACTIVE:
+		ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false,
+				       wl->conf.tx.basic_rate_5);
+		if (ret == WL1271_NOTHING_TO_SCAN) {
+			wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
+			wl1271_scan_stm(wl);
+		}
+
+		break;
+
+	case WL1271_SCAN_STATE_5GHZ_PASSIVE:
+		ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true,
+				       wl->conf.tx.basic_rate_5);
+		if (ret == WL1271_NOTHING_TO_SCAN) {
+			wl->scan.state = WL1271_SCAN_STATE_DONE;
+			wl1271_scan_stm(wl);
+		}
+
+		break;
+
+	case WL1271_SCAN_STATE_DONE:
+		mutex_unlock(&wl->mutex);
+		ieee80211_scan_completed(wl->hw, false);
+		mutex_lock(&wl->mutex);
+
+		kfree(wl->scan.scanned_ch);
+		wl->scan.scanned_ch = NULL;
+
+		wl->scan.state = WL1271_SCAN_STATE_IDLE;
+		break;
+
+	default:
+		wl1271_error("invalid scan state");
+		break;
+	}
+}
+
+int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
+		struct cfg80211_scan_request *req)
+{
+	if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
+		return -EBUSY;
+
+	wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
+
+	if (ssid_len && ssid) {
+		wl->scan.ssid_len = ssid_len;
+		memcpy(wl->scan.ssid, ssid, ssid_len);
+	} else {
+		wl->scan.ssid_len = 0;
+	}
+
+	wl->scan.req = req;
+
+	wl->scan.scanned_ch = kzalloc(req->n_channels *
+				      sizeof(*wl->scan.scanned_ch),
+				      GFP_KERNEL);
+	wl1271_scan_stm(wl);
+
+	return 0;
+}
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.h b/drivers/net/wireless/wl12xx/wl1271_scan.h
new file mode 100644
index 0000000..f181570
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_scan.h
@@ -0,0 +1,109 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_SCAN_H__
+#define __WL1271_SCAN_H__
+
+#include "wl1271.h"
+
+int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
+		struct cfg80211_scan_request *req);
+int wl1271_scan_build_probe_req(struct wl1271 *wl,
+				const u8 *ssid, size_t ssid_len,
+				const u8 *ie, size_t ie_len, u8 band);
+void wl1271_scan_stm(struct wl1271 *wl);
+
+#define WL1271_SCAN_MAX_CHANNELS       24
+#define WL1271_SCAN_DEFAULT_TAG        1
+#define WL1271_SCAN_CURRENT_TX_PWR     0
+#define WL1271_SCAN_OPT_ACTIVE         0
+#define WL1271_SCAN_OPT_PASSIVE	       1
+#define WL1271_SCAN_OPT_PRIORITY_HIGH  4
+#define WL1271_SCAN_CHAN_MIN_DURATION  30000  /* TU */
+#define WL1271_SCAN_CHAN_MAX_DURATION  60000  /* TU */
+#define WL1271_SCAN_BAND_2_4_GHZ 0
+#define WL1271_SCAN_BAND_5_GHZ 1
+#define WL1271_SCAN_PROBE_REQS 3
+
+enum {
+	WL1271_SCAN_STATE_IDLE,
+	WL1271_SCAN_STATE_2GHZ_ACTIVE,
+	WL1271_SCAN_STATE_2GHZ_PASSIVE,
+	WL1271_SCAN_STATE_5GHZ_ACTIVE,
+	WL1271_SCAN_STATE_5GHZ_PASSIVE,
+	WL1271_SCAN_STATE_DONE
+};
+
+struct basic_scan_params {
+	__le32 rx_config_options;
+	__le32 rx_filter_options;
+	/* Scan option flags (WL1271_SCAN_OPT_*) */
+	__le16 scan_options;
+	/* Number of scan channels in the list (maximum 30) */
+	u8 n_ch;
+	/* This field indicates the number of probe requests to send
+	   per channel for an active scan */
+	u8 n_probe_reqs;
+	/* Rate bit field for sending the probes */
+	__le32 tx_rate;
+	u8 tid_trigger;
+	u8 ssid_len;
+	/* in order to align */
+	u8 padding1[2];
+	u8 ssid[IW_ESSID_MAX_SIZE];
+	/* Band to scan */
+	u8 band;
+	u8 use_ssid_list;
+	u8 scan_tag;
+	u8 padding2;
+} __packed;
+
+struct basic_scan_channel_params {
+	/* Duration in TU to wait for frames on a channel for active scan */
+	__le32 min_duration;
+	__le32 max_duration;
+	__le32 bssid_lsb;
+	__le16 bssid_msb;
+	u8 early_termination;
+	u8 tx_power_att;
+	u8 channel;
+	/* FW internal use only! */
+	u8 dfs_candidate;
+	u8 activity_detected;
+	u8 pad;
+} __packed;
+
+struct wl1271_cmd_scan {
+	struct wl1271_cmd_header header;
+
+	struct basic_scan_params params;
+	struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
+} __packed;
+
+struct wl1271_cmd_trigger_scan_to {
+	struct wl1271_cmd_header header;
+
+	__le32 timeout;
+} __packed;
+
+#endif /* __WL1271_SCAN_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c
index d3d6f30..7059b5c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c
@@ -28,7 +28,7 @@
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/card.h>
-#include <plat/gpio.h>
+#include <linux/gpio.h>
 
 #include "wl1271.h"
 #include "wl12xx_80211.h"
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index 5189b81..96d25fb 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -461,3 +461,4 @@
 MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
 MODULE_FIRMWARE(WL1271_FW_NAME);
+MODULE_ALIAS("spi:wl1271");
diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c
index 554deb4..6e0952f 100644
--- a/drivers/net/wireless/wl12xx/wl1271_testmode.c
+++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c
@@ -199,7 +199,14 @@
 	buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
 	len = nla_len(tb[WL1271_TM_ATTR_DATA]);
 
-	if (len != sizeof(struct wl1271_nvs_file)) {
+	/*
+	 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
+	 * configurations) can be removed when those NVS files stop floating
+	 * around.
+	 */
+	if (len != sizeof(struct wl1271_nvs_file) &&
+	    (len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
+	     wl1271_11a_enabled())) {
 		wl1271_error("nvs size is not as expected: %zu != %zu",
 			     len, sizeof(struct wl1271_nvs_file));
 		return -EMSGSIZE;
@@ -209,7 +216,7 @@
 
 	kfree(wl->nvs);
 
-	wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
+	wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
 	if (!wl->nvs) {
 		wl1271_error("could not allocate memory for the nvs file");
 		ret = -ENOMEM;
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index 62db795..c592cc2 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -36,6 +36,7 @@
 	for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
 		if (wl->tx_frames[i] == NULL) {
 			wl->tx_frames[i] = skb;
+			wl->tx_frames_cnt++;
 			return i;
 		}
 
@@ -73,8 +74,10 @@
 		wl1271_debug(DEBUG_TX,
 			     "tx_allocate: size: %d, blocks: %d, id: %d",
 			     total_len, total_blocks, id);
-	} else
+	} else {
 		wl->tx_frames[id] = NULL;
+		wl->tx_frames_cnt--;
+	}
 
 	return ret;
 }
@@ -358,6 +361,7 @@
 	/* return the packet to the stack */
 	ieee80211_tx_status(wl->hw, skb);
 	wl->tx_frames[result->id] = NULL;
+	wl->tx_frames_cnt--;
 }
 
 /* Called upon reception of a TX complete interrupt */
@@ -412,7 +416,7 @@
 }
 
 /* caller must hold wl->mutex */
-void wl1271_tx_flush(struct wl1271 *wl)
+void wl1271_tx_reset(struct wl1271 *wl)
 {
 	int i;
 	struct sk_buff *skb;
@@ -421,7 +425,7 @@
 /* 	control->flags = 0; FIXME */
 
 	while ((skb = skb_dequeue(&wl->tx_queue))) {
-		wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb);
+		wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
 		ieee80211_tx_status(wl->hw, skb);
 	}
 
@@ -429,6 +433,32 @@
 		if (wl->tx_frames[i] != NULL) {
 			skb = wl->tx_frames[i];
 			wl->tx_frames[i] = NULL;
+			wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
 			ieee80211_tx_status(wl->hw, skb);
 		}
+	wl->tx_frames_cnt = 0;
+}
+
+#define WL1271_TX_FLUSH_TIMEOUT 500000
+
+/* caller must *NOT* hold wl->mutex */
+void wl1271_tx_flush(struct wl1271 *wl)
+{
+	unsigned long timeout;
+	timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
+
+	while (!time_after(jiffies, timeout)) {
+		mutex_lock(&wl->mutex);
+		wl1271_debug(DEBUG_TX, "flushing tx buffer: %d",
+			     wl->tx_frames_cnt);
+		if ((wl->tx_frames_cnt == 0) &&
+		    skb_queue_empty(&wl->tx_queue)) {
+			mutex_unlock(&wl->mutex);
+			return;
+		}
+		mutex_unlock(&wl->mutex);
+		msleep(1);
+	}
+
+	wl1271_warning("Unable to flush all TX buffers, timed out.");
 }
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h
index 3b8b7ac..48bf926 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.h
@@ -80,7 +80,7 @@
 	/* Identifier of the remote STA in IBSS, 1 in infra-BSS */
 	u8 aid;
 	u8 reserved;
-} __attribute__ ((packed));
+} __packed;
 
 enum wl1271_tx_hw_res_status {
 	TX_SUCCESS          = 0,
@@ -115,13 +115,13 @@
 	u8 rate_class_index;
 	/* for 4-byte alignment. */
 	u8 spare;
-} __attribute__ ((packed));
+} __packed;
 
 struct wl1271_tx_hw_res_if {
 	__le32 tx_result_fw_counter;
 	__le32 tx_result_host_counter;
 	struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN];
-} __attribute__ ((packed));
+} __packed;
 
 static inline int wl1271_tx_get_queue(int queue)
 {
@@ -158,6 +158,7 @@
 
 void wl1271_tx_work(struct work_struct *work);
 void wl1271_tx_complete(struct wl1271 *wl);
+void wl1271_tx_reset(struct wl1271 *wl);
 void wl1271_tx_flush(struct wl1271 *wl);
 u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
 u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index 055d7bc..1846280 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -66,41 +66,41 @@
 	u8 bssid[ETH_ALEN];
 	__le16 seq_ctl;
 	u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct wl12xx_ie_header {
 	u8 id;
 	u8 len;
-} __attribute__ ((packed));
+} __packed;
 
 /* IEs */
 
 struct wl12xx_ie_ssid {
 	struct wl12xx_ie_header header;
 	char ssid[IW_ESSID_MAX_SIZE];
-} __attribute__ ((packed));
+} __packed;
 
 struct wl12xx_ie_rates {
 	struct wl12xx_ie_header header;
 	u8 rates[MAX_SUPPORTED_RATES];
-} __attribute__ ((packed));
+} __packed;
 
 struct wl12xx_ie_ds_params {
 	struct wl12xx_ie_header header;
 	u8 channel;
-} __attribute__ ((packed));
+} __packed;
 
 struct country_triplet {
 	u8 channel;
 	u8 num_channels;
 	u8 max_tx_power;
-} __attribute__ ((packed));
+} __packed;
 
 struct wl12xx_ie_country {
 	struct wl12xx_ie_header header;
 	u8 country_string[COUNTRY_STRING_LEN];
 	struct country_triplet triplets[MAX_COUNTRY_TRIPLETS];
-} __attribute__ ((packed));
+} __packed;
 
 
 /* Templates */
@@ -115,30 +115,30 @@
 	struct wl12xx_ie_rates ext_rates;
 	struct wl12xx_ie_ds_params ds_params;
 	struct wl12xx_ie_country country;
-} __attribute__ ((packed));
+} __packed;
 
 struct wl12xx_null_data_template {
 	struct ieee80211_header header;
-} __attribute__ ((packed));
+} __packed;
 
 struct wl12xx_ps_poll_template {
 	__le16 fc;
 	__le16 aid;
 	u8 bssid[ETH_ALEN];
 	u8 ta[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
 
 struct wl12xx_qos_null_data_template {
 	struct ieee80211_header header;
 	__le16 qos_ctl;
-} __attribute__ ((packed));
+} __packed;
 
 struct wl12xx_probe_req_template {
 	struct ieee80211_header header;
 	struct wl12xx_ie_ssid ssid;
 	struct wl12xx_ie_rates rates;
 	struct wl12xx_ie_rates ext_rates;
-} __attribute__ ((packed));
+} __packed;
 
 
 struct wl12xx_probe_resp_template {
@@ -151,6 +151,6 @@
 	struct wl12xx_ie_rates ext_rates;
 	struct wl12xx_ie_ds_params ds_params;
 	struct wl12xx_ie_country country;
-} __attribute__ ((packed));
+} __packed;
 
 #endif
diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h
index 8816e37..3fbfd19 100644
--- a/drivers/net/wireless/wl3501.h
+++ b/drivers/net/wireless/wl3501.h
@@ -231,12 +231,12 @@
 		  but sizeof(enum) > sizeof(u8) :-( */
 	u8 len;
 	u8 data[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct iw_mgmt_essid_pset {
 	struct iw_mgmt_info_element el;
 	u8 			    essid[IW_ESSID_MAX_SIZE];
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * According to 802.11 Wireless Netowors, the definitive guide - O'Reilly
@@ -247,12 +247,12 @@
 struct iw_mgmt_data_rset {
 	struct iw_mgmt_info_element el;
 	u8 			    data_rate_labels[IW_DATA_RATE_MAX_LABELS];
-} __attribute__ ((packed));
+} __packed;
 
 struct iw_mgmt_ds_pset {
 	struct iw_mgmt_info_element el;
 	u8 			    chan;
-} __attribute__ ((packed));
+} __packed;
 
 struct iw_mgmt_cf_pset {
 	struct iw_mgmt_info_element el;
@@ -260,12 +260,12 @@
 	u8 			    cfp_period;
 	u16 			    cfp_max_duration;
 	u16 			    cfp_dur_remaining;
-} __attribute__ ((packed));
+} __packed;
 
 struct iw_mgmt_ibss_pset {
 	struct iw_mgmt_info_element el;
 	u16 			    atim_window;
-} __attribute__ ((packed));
+} __packed;
 
 struct wl3501_tx_hdr {
 	u16	tx_cnt;
@@ -544,12 +544,12 @@
 	u8	service;
 	u16	len;
 	u16	crc16;
-} __attribute__ ((packed));
+} __packed;
 
 struct wl3501_80211_tx_hdr {
 	struct wl3501_80211_tx_plcp_hdr	pclp_hdr;
 	struct ieee80211_hdr		mac_hdr;
-} __attribute__ ((packed));
+} __packed;
 
 /*
    Reserve the beginning Tx space for descriptor use.
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index b0b6660..43307bd 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -42,7 +42,8 @@
 	{ ZD_REGDOMAIN_IC, "CA" },
 	{ ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */
 	{ ZD_REGDOMAIN_JAPAN, "JP" },
-	{ ZD_REGDOMAIN_JAPAN_ADD, "JP" },
+	{ ZD_REGDOMAIN_JAPAN_2, "JP" },
+	{ ZD_REGDOMAIN_JAPAN_3, "JP" },
 	{ ZD_REGDOMAIN_SPAIN, "ES" },
 	{ ZD_REGDOMAIN_FRANCE, "FR" },
 };
@@ -855,7 +856,7 @@
 	if (skb == NULL)
 		return -ENOMEM;
 	if (need_padding) {
-		/* Make sure the the payload data is 4 byte aligned. */
+		/* Make sure the payload data is 4 byte aligned. */
 		skb_reserve(skb, 2);
 	}
 
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 630c298..a6d86b9 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -35,7 +35,7 @@
 	__le16 current_length;
 	u8     service;
 	__le16  next_frame_length;
-} __attribute__((packed));
+} __packed;
 
 #define ZD_CS_RESERVED_SIZE	25
 
@@ -106,7 +106,7 @@
 struct rx_length_info {
 	__le16 length[3];
 	__le16 tag;
-} __attribute__((packed));
+} __packed;
 
 #define RX_LENGTH_INFO_TAG		0x697e
 
@@ -117,7 +117,7 @@
 	u8 signal_quality_ofdm;
 	u8 decryption_type;
 	u8 frame_status;
-} __attribute__((packed));
+} __packed;
 
 /* rx_status field decryption_type */
 #define ZD_RX_NO_WEP	0
@@ -153,7 +153,7 @@
 	u8 mac[ETH_ALEN];
 	u8 retry;
 	u8 failure;
-} __attribute__((packed));
+} __packed;
 
 enum mac_flags {
 	MAC_FIXED_CHANNEL = 0x01,
@@ -212,8 +212,9 @@
 #define ZD_REGDOMAIN_ETSI	0x30
 #define ZD_REGDOMAIN_SPAIN	0x31
 #define ZD_REGDOMAIN_FRANCE	0x32
-#define ZD_REGDOMAIN_JAPAN_ADD	0x40
+#define ZD_REGDOMAIN_JAPAN_2	0x40
 #define ZD_REGDOMAIN_JAPAN	0x41
+#define ZD_REGDOMAIN_JAPAN_3	0x49
 
 enum {
 	MIN_CHANNEL24 = 1,
@@ -225,7 +226,7 @@
 struct ofdm_plcp_header {
 	u8 prefix[3];
 	__le16 service;
-} __attribute__((packed));
+} __packed;
 
 static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header)
 {
@@ -252,7 +253,7 @@
 	u8 service;
 	__le16 length;
 	__le16 crc16;
-} __attribute__((packed));
+} __packed;
 
 static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header)
 {
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index c257940..818e1480 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -844,7 +844,7 @@
  * @usb: a &struct zd_usb pointer
  * @urb: URB to be freed
  *
- * Frees the the transmission URB, which means to put it on the free URB
+ * Frees the transmission URB, which means to put it on the free URB
  * list.
  */
 static void free_tx_urb(struct zd_usb *usb, struct urb *urb)
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 049f8b9..1b1655c 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -79,17 +79,17 @@
 struct usb_req_read_regs {
 	__le16 id;
 	__le16 addr[0];
-} __attribute__((packed));
+} __packed;
 
 struct reg_data {
 	__le16 addr;
 	__le16 value;
-} __attribute__((packed));
+} __packed;
 
 struct usb_req_write_regs {
 	__le16 id;
 	struct reg_data reg_writes[0];
-} __attribute__((packed));
+} __packed;
 
 enum {
 	RF_IF_LE = 0x02,
@@ -106,7 +106,7 @@
 	/* RF2595: 24 */
 	__le16 bit_values[0];
 	/* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
-} __attribute__((packed));
+} __packed;
 
 /* USB interrupt */
 
@@ -123,12 +123,12 @@
 struct usb_int_header {
 	u8 type;	/* must always be 1 */
 	u8 id;
-} __attribute__((packed));
+} __packed;
 
 struct usb_int_regs {
 	struct usb_int_header hdr;
 	struct reg_data regs[0];
-} __attribute__((packed));
+} __packed;
 
 struct usb_int_retry_fail {
 	struct usb_int_header hdr;
@@ -136,7 +136,7 @@
 	u8 _dummy;
 	u8 addr[ETH_ALEN];
 	u8 ibss_wakeup_dest;
-} __attribute__((packed));
+} __packed;
 
 struct read_regs_int {
 	struct completion completion;
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index d504e2b..b50fedc 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1621,6 +1621,7 @@
 		if (xennet_connect(netdev) != 0)
 			break;
 		xenbus_switch_state(dev, XenbusStateConnected);
+		netif_notify_peers(netdev);
 		break;
 
 	case XenbusStateClosing:
diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c
index fdba9cb..9f12026 100644
--- a/drivers/net/xtsonic.c
+++ b/drivers/net/xtsonic.c
@@ -93,12 +93,20 @@
 
 static int xtsonic_open(struct net_device *dev)
 {
-	if (request_irq(dev->irq,sonic_interrupt,IRQF_DISABLED,"sonic",dev)) {
+	int retval;
+
+	retval = request_irq(dev->irq, sonic_interrupt, IRQF_DISABLED,
+				"sonic", dev);
+	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
 		       dev->name, dev->irq);
 		return -EAGAIN;
 	}
-	return sonic_open(dev);
+
+	retval = sonic_open(dev);
+	if (retval)
+		free_irq(dev->irq, dev);
+	return retval;
 }
 
 static int xtsonic_close(struct net_device *dev)
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index d02be78..c5c14dd 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -357,12 +357,13 @@
 	rcu_read_lock();
 	for_each_netdev_rcu(&init_net, dev) {
 	    const struct net_device_stats *stats;
+	    struct rtnl_link_stats64 temp;
 	    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, &temp);
 	    rx_total += stats->rx_packets;
 	    tx_total += stats->tx_packets;
 	}
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 2e7a3bf..1ab98bb 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -48,6 +48,7 @@
 	if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) {
 		pci_check_pme_status(pci_dev);
 		pm_runtime_resume(&pci_dev->dev);
+		pci_wakeup_event(pci_dev);
 		if (pci_dev->subordinate)
 			pci_pme_wakeup_bus(pci_dev->subordinate);
 	}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 740fb4e..130ed1d 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1275,6 +1275,22 @@
 	return ret;
 }
 
+/*
+ * Time to wait before the system can be put into a sleep state after reporting
+ * a wakeup event signaled by a PCI device.
+ */
+#define PCI_WAKEUP_COOLDOWN	100
+
+/**
+ * pci_wakeup_event - Report a wakeup event related to a given PCI device.
+ * @dev: Device to report the wakeup event for.
+ */
+void pci_wakeup_event(struct pci_dev *dev)
+{
+	if (device_may_wakeup(&dev->dev))
+		pm_wakeup_event(&dev->dev, PCI_WAKEUP_COOLDOWN);
+}
+
 /**
  * pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set.
  * @dev: Device to handle.
@@ -1285,8 +1301,10 @@
  */
 static int pci_pme_wakeup(struct pci_dev *dev, void *ign)
 {
-	if (pci_check_pme_status(dev))
+	if (pci_check_pme_status(dev)) {
 		pm_request_resume(&dev->dev);
+		pci_wakeup_event(dev);
+	}
 	return 0;
 }
 
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index f8077b3..c8b7fd0 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -56,6 +56,7 @@
 extern void pci_disable_enabled_device(struct pci_dev *dev);
 extern bool pci_check_pme_status(struct pci_dev *dev);
 extern int pci_finish_runtime_suspend(struct pci_dev *dev);
+extern void pci_wakeup_event(struct pci_dev *dev);
 extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
 extern void pci_pme_wakeup_bus(struct pci_bus *bus);
 extern void pci_pm_init(struct pci_dev *dev);
diff --git a/drivers/pci/pcie/pme/pcie_pme.c b/drivers/pci/pcie/pme/pcie_pme.c
index d672a0a..bbdea18 100644
--- a/drivers/pci/pcie/pme/pcie_pme.c
+++ b/drivers/pci/pcie/pme/pcie_pme.c
@@ -154,6 +154,7 @@
 		/* Skip PCIe devices in case we started from a root port. */
 		if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) {
 			pm_request_resume(&dev->dev);
+			pci_wakeup_event(dev);
 			ret = true;
 		}
 
@@ -254,8 +255,10 @@
 	if (found) {
 		/* The device is there, but we have to check its PME status. */
 		found = pci_check_pme_status(dev);
-		if (found)
+		if (found) {
 			pm_request_resume(&dev->dev);
+			pci_wakeup_event(dev);
+		}
 		pci_dev_put(dev);
 	} else if (devfn) {
 		/*
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 3e1b8a2..79baa63 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -5,6 +5,7 @@
 menuconfig X86_PLATFORM_DEVICES
 	bool "X86 Platform Specific Device Drivers"
 	default y
+	depends on X86
 	---help---
 	  Say Y here to get to see options for device drivers for various
 	  x86 platforms, including vendor-specific laptop extension drivers.
@@ -151,6 +152,7 @@
 	depends on ACPI
 	depends on BACKLIGHT_CLASS_DEVICE
 	depends on RFKILL
+	depends on SERIO_I8042
 	---help---
 	  This is a driver for laptops built by MSI (MICRO-STAR
 	  INTERNATIONAL):
@@ -181,6 +183,8 @@
 	depends on ACPI
 	depends on BACKLIGHT_CLASS_DEVICE
 	depends on RFKILL
+	depends on HWMON
+	depends on POWER_SUPPLY
 	---help---
 	  This is a driver for laptops built by Compal:
 
@@ -520,6 +524,7 @@
 config ACPI_CMPC
 	tristate "CMPC Laptop Extras"
 	depends on X86 && ACPI
+	depends on RFKILL || RFKILL=n
 	select INPUT
 	select BACKLIGHT_CLASS_DEVICE
 	default n
@@ -537,4 +542,43 @@
 	  some embedded Intel x86 platforms. This is not needed for PC-type
 	  machines.
 
+config GPIO_INTEL_PMIC
+	bool "Intel PMIC GPIO support"
+	depends on INTEL_SCU_IPC && GPIOLIB
+	---help---
+	  Say Y here to support GPIO via the SCU IPC interface
+	  on Intel MID platforms.
+
+config RAR_REGISTER
+	bool "Restricted Access Region Register Driver"
+	depends on PCI && X86_MRST
+	default n
+	---help---
+	  This driver allows other kernel drivers access to the
+	  contents of the restricted access region control registers.
+
+	  The restricted access region control registers
+	  (rar_registers) are used to pass address and
+	  locking information on restricted access regions
+	  to other drivers that use restricted access regions.
+
+	  The restricted access regions are regions of memory
+	  on the Intel MID Platform that are not accessible to
+	  the x86 processor, but are accessible to dedicated
+	  processors on board peripheral devices.
+
+	  The purpose of the restricted access regions is to
+	  protect sensitive data from compromise by unauthorized
+	  programs running on the x86 processor.
+
+config INTEL_IPS
+	tristate "Intel Intelligent Power Sharing"
+	depends on ACPI
+	---help---
+	  Intel Calpella platforms support dynamic power sharing between the
+	  CPU and GPU, maximizing performance in a given TDP.  This driver,
+	  along with the CPU frequency and i915 drivers, provides that
+	  functionality.  If in doubt, say Y here; it will only load on
+	  supported platforms.
+
 endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 8770bfe..4744c77 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -26,3 +26,7 @@
 obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
 obj-$(CONFIG_TOSHIBA_BT_RFKILL)	+= toshiba_bluetooth.o
 obj-$(CONFIG_INTEL_SCU_IPC)	+= intel_scu_ipc.o
+obj-$(CONFIG_RAR_REGISTER)	+= intel_rar_register.o
+obj-$(CONFIG_INTEL_IPS)		+= intel_ips.o
+obj-$(CONFIG_GPIO_INTEL_PMIC)	+= intel_pmic_gpio.o
+
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 1ea6c43..2badee2 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -50,17 +50,6 @@
 #define ACER_INFO KERN_INFO ACER_LOGPREFIX
 
 /*
- * The following defines quirks to get some specific functions to work
- * which are known to not be supported over ACPI-WMI (such as the mail LED
- * on WMID based Acer's)
- */
-struct acer_quirks {
-	const char *vendor;
-	const char *model;
-	u16 quirks;
-};
-
-/*
  * Magic Number
  * Meaning is unknown - this number is required for writing to ACPI for AMW0
  * (it's also used in acerhk when directly accessing the BIOS)
@@ -200,7 +189,7 @@
 static int dmi_matched(const struct dmi_system_id *dmi)
 {
 	quirks = dmi->driver_data;
-	return 0;
+	return 1;
 }
 
 static struct quirk_entry quirk_unknown = {
@@ -555,6 +544,7 @@
 	obj->buffer.length == sizeof(struct wmab_ret)) {
 		ret = *((struct wmab_ret *) obj->buffer.pointer);
 	} else {
+		kfree(out.pointer);
 		return AE_ERROR;
 	}
 
@@ -570,7 +560,7 @@
 {
 	struct wmab_args args;
 	struct wmab_ret ret;
-	acpi_status status = AE_OK;
+	acpi_status status;
 	struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *obj;
 
@@ -593,12 +583,13 @@
 	if (ACPI_FAILURE(status))
 		return status;
 
-	obj = (union acpi_object *) out.pointer;
+	obj = out.pointer;
 	if (obj && obj->type == ACPI_TYPE_BUFFER &&
 	obj->buffer.length == sizeof(struct wmab_ret)) {
 		ret = *((struct wmab_ret *) obj->buffer.pointer);
 	} else {
-		return AE_ERROR;
+		status = AE_ERROR;
+		goto out;
 	}
 
 	if (ret.eax & 0x1)
@@ -607,23 +598,26 @@
 	args.ebx = 2 << 8;
 	args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
 
+	/*
+	 * It's ok to use existing buffer for next wmab_execute call.
+	 * But we need to kfree(out.pointer) if next wmab_execute fail.
+	 */
 	status = wmab_execute(&args, &out);
 	if (ACPI_FAILURE(status))
-		return status;
+		goto out;
 
 	obj = (union acpi_object *) out.pointer;
 	if (obj && obj->type == ACPI_TYPE_BUFFER
 	&& obj->buffer.length == sizeof(struct wmab_ret)) {
 		ret = *((struct wmab_ret *) obj->buffer.pointer);
 	} else {
-		return AE_ERROR;
+		status = AE_ERROR;
+		goto out;
 	}
 
 	if (ret.eax & 0x1)
 		interface->capability |= ACER_CAP_BLUETOOTH;
 
-	kfree(out.pointer);
-
 	/*
 	 * This appears to be safe to enable, since all Wistron based laptops
 	 * appear to use the same EC register for brightness, even if they
@@ -632,7 +626,10 @@
 	if (quirks->brightness >= 0)
 		interface->capability |= ACER_CAP_BRIGHTNESS;
 
-	return AE_OK;
+	status = AE_OK;
+out:
+	kfree(out.pointer);
+	return status;
 }
 
 static struct wmi_interface AMW0_interface = {
@@ -772,6 +769,7 @@
 		obj->buffer.length == sizeof(u32)) {
 		devices = *((u32 *) obj->buffer.pointer);
 	} else {
+		kfree(out.pointer);
 		return AE_ERROR;
 	}
 
@@ -788,6 +786,7 @@
 	if (!(devices & 0x20))
 		max_brightness = 0x9;
 
+	kfree(out.pointer);
 	return status;
 }
 
@@ -1084,8 +1083,7 @@
 	}
 }
 
-static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR,
-	show_interface, NULL);
+static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL);
 
 /*
  * debugfs functions
@@ -1095,6 +1093,7 @@
 	struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
 	union acpi_object *obj;
 	acpi_status status;
+	u32 devices = 0;
 
 	status = wmi_query_block(WMID_GUID2, 1, &out);
 	if (ACPI_FAILURE(status))
@@ -1103,10 +1102,11 @@
 	obj = (union acpi_object *) out.pointer;
 	if (obj && obj->type == ACPI_TYPE_BUFFER &&
 		obj->buffer.length == sizeof(u32)) {
-		return *((u32 *) obj->buffer.pointer);
-	} else {
-		return 0;
+		devices = *((u32 *) obj->buffer.pointer);
 	}
+
+	kfree(out.pointer);
+	return devices;
 }
 
 /*
@@ -1327,22 +1327,31 @@
 		       "generic video driver\n");
 	}
 
-	if (platform_driver_register(&acer_platform_driver)) {
+	err = platform_driver_register(&acer_platform_driver);
+	if (err) {
 		printk(ACER_ERR "Unable to register platform driver.\n");
 		goto error_platform_register;
 	}
+
 	acer_platform_device = platform_device_alloc("acer-wmi", -1);
-	platform_device_add(acer_platform_device);
+	if (!acer_platform_device) {
+		err = -ENOMEM;
+		goto error_device_alloc;
+	}
+
+	err = platform_device_add(acer_platform_device);
+	if (err)
+		goto error_device_add;
 
 	err = create_sysfs();
 	if (err)
-		return err;
+		goto error_create_sys;
 
 	if (wmi_has_guid(WMID_GUID2)) {
 		interface->debug.wmid_devices = get_wmid_devices();
 		err = create_debugfs();
 		if (err)
-			return err;
+			goto error_create_debugfs;
 	}
 
 	/* Override any initial settings with values from the commandline */
@@ -1350,15 +1359,23 @@
 
 	return 0;
 
+error_create_debugfs:
+	remove_sysfs(acer_platform_device);
+error_create_sys:
+	platform_device_del(acer_platform_device);
+error_device_add:
+	platform_device_put(acer_platform_device);
+error_device_alloc:
+	platform_driver_unregister(&acer_platform_driver);
 error_platform_register:
-	return -ENODEV;
+	return err;
 }
 
 static void __exit acer_wmi_exit(void)
 {
 	remove_sysfs(acer_platform_device);
 	remove_debugfs();
-	platform_device_del(acer_platform_device);
+	platform_device_unregister(acer_platform_device);
 	platform_driver_unregister(&acer_platform_driver);
 
 	printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n");
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 7b2384d..60f9cfc 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -52,7 +52,7 @@
  */
 #undef START_IN_KERNEL_MODE
 
-#define DRV_VER "0.5.22"
+#define DRV_VER "0.5.24"
 
 /*
  * According to the Atom N270 datasheet,
@@ -92,9 +92,9 @@
 static char force_bios[16];
 static char force_product[16];
 static unsigned int prev_interval;
-struct thermal_zone_device *thz_dev;
-struct thermal_cooling_device *cl_dev;
-struct platform_device *acerhdf_dev;
+static struct thermal_zone_device *thz_dev;
+static struct thermal_cooling_device *cl_dev;
+static struct platform_device *acerhdf_dev;
 
 module_param(kernelmode, uint, 0);
 MODULE_PARM_DESC(kernelmode, "Kernel mode fan control on / off");
@@ -112,14 +112,12 @@
 MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check");
 
 /*
- * cmd_off: to switch the fan completely off
- * chk_off: to check if the fan is off
+ * cmd_off: to switch the fan completely off and check if the fan is off
  *	cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then
  *		the fan speed depending on the temperature
  */
 struct fancmd {
 	u8 cmd_off;
-	u8 chk_off;
 	u8 cmd_auto;
 };
 
@@ -136,47 +134,81 @@
 /* Register addresses and values for different BIOS versions */
 static const struct bios_settings_t bios_tbl[] = {
 	/* AOA110 */
-	{"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x1f, 0x00} },
-	{"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x1f, 0x00} },
-	{"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
-	{"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
-	{"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
-	{"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
-	{"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x21, 0x00} },
-	{"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x21, 0x00} },
-	{"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x21, 0x00} },
+	{"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00} },
+	{"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00} },
+	{"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} },
+	{"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} },
+	{"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} },
+	{"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00} },
+	{"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} },
+	{"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} },
+	{"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} },
 	/* AOA150 */
-	{"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x20, 0x00} },
-	{"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x20, 0x00} },
-	{"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x20, 0x00} },
-	{"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x20, 0x00} },
-	{"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x20, 0x00} },
-	{"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x20, 0x00} },
-	{"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x20, 0x00} },
-	{"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x20, 0x00} },
+	{"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x1f, 0x00} },
+	{"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00} },
+	{"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} },
+	{"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} },
+	{"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00} },
+	{"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} },
+	{"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} },
+	{"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} },
 	/* Acer 1410 */
-	{"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
-	{"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
+	{"Acer", "Aspire 1410", "v0.3108", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1410", "v0.3113", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1410", "v0.3115", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1410", "v0.3117", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1410", "v0.3119", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1410", "v1.3204", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1410", "v1.3308", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1410", "v1.3310", 0x55, 0x58, {0x9e, 0x00} },
 	/* Acer 1810xx */
-	{"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
-	{"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
-	{"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
-	{"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
+	{"Acer", "Aspire 1810TZ", "v0.3108", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810T",  "v0.3108", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810TZ", "v0.3113", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810T",  "v0.3113", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810TZ", "v0.3115", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810T",  "v0.3115", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810TZ", "v0.3117", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810T",  "v0.3117", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810TZ", "v0.3119", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810T",  "v0.3119", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810T",  "v0.3120", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810TZ", "v1.3204", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810T",  "v1.3204", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810T",  "v1.3303", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810TZ", "v1.3308", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810T",  "v1.3308", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00} },
+	{"Acer", "Aspire 1810T",  "v1.3310", 0x55, 0x58, {0x9e, 0x00} },
+	/* Acer 531 */
+	{"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00} },
 	/* Gateway */
-	{"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x21, 0x00} },
-	{"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x20, 0x00} },
-	{"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x10, 0x0f, 0x00} },
-	{"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x10, 0x0f, 0x00} },
-	{"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x10, 0x0f, 0x00} },
+	{"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00} },
+	{"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} },
+	{"Gateway", "LT31",   "v1.3103", 0x55, 0x58, {0x9e, 0x00} },
+	{"Gateway", "LT31",   "v1.3201", 0x55, 0x58, {0x9e, 0x00} },
+	{"Gateway", "LT31",   "v1.3302", 0x55, 0x58, {0x9e, 0x00} },
 	/* Packard Bell */
-	{"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x21, 0x00} },
-	{"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} },
-	{"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x21, 0x00} },
-	{"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} },
-	{"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
-	{"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
+	{"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} },
+	{"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} },
+	{"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} },
+	{"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} },
+	{"Packard Bell", "DOTMU",  "v1.3303", 0x55, 0x58, {0x9e, 0x00} },
+	{"Packard Bell", "DOTMU",  "v0.3120", 0x55, 0x58, {0x9e, 0x00} },
+	{"Packard Bell", "DOTMU",  "v0.3108", 0x55, 0x58, {0x9e, 0x00} },
+	{"Packard Bell", "DOTMU",  "v0.3113", 0x55, 0x58, {0x9e, 0x00} },
+	{"Packard Bell", "DOTMU",  "v0.3115", 0x55, 0x58, {0x9e, 0x00} },
+	{"Packard Bell", "DOTMU",  "v0.3117", 0x55, 0x58, {0x9e, 0x00} },
+	{"Packard Bell", "DOTMU",  "v0.3119", 0x55, 0x58, {0x9e, 0x00} },
+	{"Packard Bell", "DOTMU",  "v1.3204", 0x55, 0x58, {0x9e, 0x00} },
+	{"Packard Bell", "DOTMA",  "v1.3201", 0x55, 0x58, {0x9e, 0x00} },
+	{"Packard Bell", "DOTMA",  "v1.3302", 0x55, 0x58, {0x9e, 0x00} },
 	/* pewpew-terminator */
-	{"", "", "", 0, 0, {0, 0, 0} }
+	{"", "", "", 0, 0, {0, 0} }
 };
 
 static const struct bios_settings_t *bios_cfg __read_mostly;
@@ -200,7 +232,7 @@
 	if (ec_read(bios_cfg->fanreg, &fan))
 		return -EINVAL;
 
-	if (fan != bios_cfg->cmd.chk_off)
+	if (fan != bios_cfg->cmd.cmd_off)
 		*state = ACERHDF_FAN_AUTO;
 	else
 		*state = ACERHDF_FAN_OFF;
@@ -374,7 +406,7 @@
 }
 
 /* bind callback functions to thermalzone */
-struct thermal_zone_device_ops acerhdf_dev_ops = {
+static struct thermal_zone_device_ops acerhdf_dev_ops = {
 	.bind = acerhdf_bind,
 	.unbind = acerhdf_unbind,
 	.get_temp = acerhdf_get_ec_temp,
@@ -449,7 +481,7 @@
 }
 
 /* bind fan callbacks to fan device */
-struct thermal_cooling_device_ops acerhdf_cooling_ops = {
+static struct thermal_cooling_device_ops acerhdf_cooling_ops = {
 	.get_max_state = acerhdf_get_max_state,
 	.get_cur_state = acerhdf_get_cur_state,
 	.set_cur_state = acerhdf_set_cur_state,
@@ -518,6 +550,10 @@
 	version = dmi_get_system_info(DMI_BIOS_VERSION);
 	product = dmi_get_system_info(DMI_PRODUCT_NAME);
 
+	if (!vendor || !version || !product) {
+		pr_err("error getting hardware information\n");
+		return -EINVAL;
+	}
 
 	pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER);
 
@@ -579,17 +615,26 @@
 		return err;
 
 	acerhdf_dev = platform_device_alloc("acerhdf", -1);
-	platform_device_add(acerhdf_dev);
+	if (!acerhdf_dev) {
+		err = -ENOMEM;
+		goto err_device_alloc;
+	}
+	err = platform_device_add(acerhdf_dev);
+	if (err)
+		goto err_device_add;
 
 	return 0;
+
+err_device_add:
+	platform_device_put(acerhdf_dev);
+err_device_alloc:
+	platform_driver_unregister(&acerhdf_driver);
+	return err;
 }
 
 static void acerhdf_unregister_platform(void)
 {
-	if (!acerhdf_dev)
-		return;
-
-	platform_device_del(acerhdf_dev);
+	platform_device_unregister(acerhdf_dev);
 	platform_driver_unregister(&acerhdf_driver);
 }
 
@@ -633,7 +678,7 @@
 
 	err = acerhdf_register_platform();
 	if (err)
-		goto err_unreg;
+		goto out_err;
 
 	err = acerhdf_register_thermal();
 	if (err)
@@ -646,7 +691,7 @@
 	acerhdf_unregister_platform();
 
 out_err:
-	return -ENODEV;
+	return err;
 }
 
 static void __exit acerhdf_exit(void)
@@ -662,11 +707,13 @@
 MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:");
 MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1410*:");
 MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1810*:");
+MODULE_ALIAS("dmi:*:*Acer*:pnAO531*:");
 MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:");
 MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:");
 MODULE_ALIAS("dmi:*:*Packard Bell*:pnAOA*:");
 MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOA*:");
 MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMU*:");
+MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMA*:");
 
 module_init(acerhdf_init);
 module_exit(acerhdf_exit);
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index efe8f63..b756e07 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -76,18 +76,18 @@
  * So, if something doesn't work as you want, just try other values =)
  */
 static uint wapf = 1;
-module_param(wapf, uint, 0644);
+module_param(wapf, uint, 0444);
 MODULE_PARM_DESC(wapf, "WAPF value");
 
 static int wlan_status = 1;
 static int bluetooth_status = 1;
 
-module_param(wlan_status, int, 0644);
+module_param(wlan_status, int, 0444);
 MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot "
 		 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
 		 "default is 1");
 
-module_param(bluetooth_status, int, 0644);
+module_param(bluetooth_status, int, 0444);
 MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
 		 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
 		 "default is 1");
@@ -297,7 +297,7 @@
 	acpi_status status;
 
 	if (!handle)
-		return 0;
+		return -1;
 
 	params.count = 1;
 	params.pointer = &in_obj;
@@ -796,10 +796,11 @@
 
 	rv = parse_arg(buf, count, &value);
 	if (rv > 0) {
-		if (write_acpi_int(asus->handle, METHOD_LEDD, value))
+		if (write_acpi_int(asus->handle, METHOD_LEDD, value)) {
 			pr_warning("LED display write failed\n");
-		else
-			asus->ledd_status = (u32) value;
+			return -ENODEV;
+		}
+		asus->ledd_status = (u32) value;
 	}
 	return rv;
 }
@@ -1123,7 +1124,7 @@
 	input = input_allocate_device();
 	if (!input) {
 		pr_info("Unable to allocate input device\n");
-		return 0;
+		return -ENOMEM;
 	}
 	input->name = "Asus Laptop extra buttons";
 	input->phys = ASUS_LAPTOP_FILE "/input0";
@@ -1134,20 +1135,20 @@
 	error = sparse_keymap_setup(input, asus_keymap, NULL);
 	if (error) {
 		pr_err("Unable to setup input device keymap\n");
-		goto err_keymap;
+		goto err_free_dev;
 	}
 	error = input_register_device(input);
 	if (error) {
 		pr_info("Unable to register input device\n");
-		goto err_device;
+		goto err_free_keymap;
 	}
 
 	asus->inputdev = input;
 	return 0;
 
-err_keymap:
+err_free_keymap:
 	sparse_keymap_free(input);
-err_device:
+err_free_dev:
 	input_free_device(input);
 	return error;
 }
@@ -1397,8 +1398,10 @@
 		}
 	}
 	asus->name = kstrdup(string, GFP_KERNEL);
-	if (!asus->name)
+	if (!asus->name) {
+		kfree(buffer.pointer);
 		return -ENOMEM;
+	}
 
 	if (*string)
 		pr_notice("  %s model detected\n", string);
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
index 92fd30c..e058c2b 100644
--- a/drivers/platform/x86/asus_acpi.c
+++ b/drivers/platform/x86/asus_acpi.c
@@ -1330,6 +1330,9 @@
 			hotk->model = P30;
 			printk(KERN_NOTICE
 			       "  Samsung P30 detected, supported\n");
+			hotk->methods = &model_conf[hotk->model];
+			kfree(model);
+			return 0;
 		} else {
 			hotk->model = M2E;
 			printk(KERN_NOTICE "  unsupported model %s, trying "
@@ -1339,8 +1342,6 @@
 			kfree(model);
 			return -ENODEV;
 		}
-		hotk->methods = &model_conf[hotk->model];
-		return AE_OK;
 	}
 	hotk->methods = &model_conf[hotk->model];
 	printk(KERN_NOTICE "  %s model detected, supported\n", string);
@@ -1374,7 +1375,7 @@
 
 	kfree(model);
 
-	return AE_OK;
+	return 0;
 }
 
 static int asus_hotk_check(void)
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
index 3bf399f..341cbfe 100644
--- a/drivers/platform/x86/classmate-laptop.c
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -208,7 +208,7 @@
 	return strnlen(buf, count);
 }
 
-struct device_attribute cmpc_accel_sensitivity_attr = {
+static struct device_attribute cmpc_accel_sensitivity_attr = {
 	.attr = { .name = "sensitivity", .mode = 0660 },
 	.show = cmpc_accel_sensitivity_show,
 	.store = cmpc_accel_sensitivity_store
@@ -573,16 +573,17 @@
 
 	ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
 				&cmpc_rfkill_ops, acpi->handle);
-	/* rfkill_alloc may fail if RFKILL is disabled. We should still work
-	 * anyway. */
-	if (!IS_ERR(ipml->rf)) {
+	/*
+	 * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
+	 * This is OK, however, since all other uses of the device will not
+	 * derefence it.
+	 */
+	if (ipml->rf) {
 		retval = rfkill_register(ipml->rf);
 		if (retval) {
 			rfkill_destroy(ipml->rf);
 			ipml->rf = NULL;
 		}
-	} else {
-		ipml->rf = NULL;
 	}
 
 	dev_set_drvdata(&acpi->dev, ipml);
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index 71ff154..d071ce0 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -24,17 +24,50 @@
  */
 
 /*
- * comapl-laptop.c - Compal laptop support.
+ * compal-laptop.c - Compal laptop support.
  *
- * The driver registers itself with the rfkill subsystem and
- * the Linux backlight control subsystem.
+ * This driver exports a few files in /sys/devices/platform/compal-laptop/:
+ *   wake_up_XXX   Whether or not we listen to such wake up events (rw)
+ *
+ * In addition to these platform device attributes the driver
+ * registers itself in the Linux backlight control, power_supply, rfkill
+ * and hwmon subsystem and is available to userspace under:
+ *
+ *   /sys/class/backlight/compal-laptop/
+ *   /sys/class/power_supply/compal-laptop/
+ *   /sys/class/rfkill/rfkillX/
+ *   /sys/class/hwmon/hwmonX/
+ *
+ * Notes on the power_supply battery interface:
+ *   - the "minimum" design voltage is *the* design voltage
+ *   - the ambient temperature is the average battery temperature
+ *     and the value is an educated guess (see commented code below)
+ *
  *
  * This driver might work on other laptops produced by Compal. If you
  * want to try it you can pass force=1 as argument to the module which
  * will force it to load even when the DMI data doesn't identify the
- * laptop as FL9x.
+ * laptop as compatible.
+ *
+ * Lots of data available at:
+ * http://service1.marasst.com/Compal/JHL90_91/Service%20Manual/
+ * JHL90%20service%20manual-Final-0725.pdf
+ *
+ *
+ *
+ * Support for the Compal JHL90 added by Roald Frederickx
+ * (roald.frederickx@gmail.com):
+ * Driver got large revision. Added functionalities: backlight
+ * power, wake_on_XXX, a hwmon and power_supply interface.
+ *
+ * In case this gets merged into the kernel source: I want to dedicate this
+ * to Kasper Meerts, the awesome guy who showed me Linux and C!
  */
 
+/* NOTE: currently the wake_on_XXX, hwmon and power_supply interfaces are
+ * only enabled on a JHL90 board until it is verified that they work on the
+ * other boards too.  See the extra_features variable. */
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -43,71 +76,296 @@
 #include <linux/backlight.h>
 #include <linux/platform_device.h>
 #include <linux/rfkill.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/power_supply.h>
+#include <linux/fb.h>
 
-#define COMPAL_DRIVER_VERSION "0.2.6"
 
-#define COMPAL_LCD_LEVEL_MAX 8
+/* ======= */
+/* Defines */
+/* ======= */
+#define DRIVER_NAME "compal-laptop"
+#define DRIVER_VERSION	"0.2.7"
 
-#define COMPAL_EC_COMMAND_WIRELESS 0xBB
-#define COMPAL_EC_COMMAND_LCD_LEVEL 0xB9
+#define BACKLIGHT_LEVEL_ADDR		0xB9
+#define BACKLIGHT_LEVEL_MAX		7
+#define BACKLIGHT_STATE_ADDR		0x59
+#define BACKLIGHT_STATE_ON_DATA		0xE1
+#define BACKLIGHT_STATE_OFF_DATA	0xE2
 
-#define KILLSWITCH_MASK 0x10
-#define WLAN_MASK	0x01
-#define BT_MASK 	0x02
+#define WAKE_UP_ADDR			0xA4
+#define WAKE_UP_PME			(1 << 0)
+#define WAKE_UP_MODEM			(1 << 1)
+#define WAKE_UP_LAN			(1 << 2)
+#define WAKE_UP_WLAN			(1 << 4)
+#define WAKE_UP_KEY			(1 << 6)
+#define WAKE_UP_MOUSE			(1 << 7)
 
-static struct rfkill *wifi_rfkill;
-static struct rfkill *bt_rfkill;
-static struct platform_device *compal_device;
+#define WIRELESS_ADDR			0xBB
+#define WIRELESS_WLAN			(1 << 0)
+#define WIRELESS_BT			(1 << 1)
+#define WIRELESS_WLAN_EXISTS		(1 << 2)
+#define WIRELESS_BT_EXISTS		(1 << 3)
+#define WIRELESS_KILLSWITCH		(1 << 4)
 
+#define PWM_ADDRESS			0x46
+#define PWM_DISABLE_ADDR		0x59
+#define PWM_DISABLE_DATA		0xA5
+#define PWM_ENABLE_ADDR			0x59
+#define PWM_ENABLE_DATA			0xA8
+
+#define FAN_ADDRESS			0x46
+#define FAN_DATA			0x81
+#define FAN_FULL_ON_CMD			0x59 /* Doesn't seem to work. Just */
+#define FAN_FULL_ON_ENABLE		0x76 /* force the pwm signal to its */
+#define FAN_FULL_ON_DISABLE		0x77 /* maximum value instead */
+
+#define TEMP_CPU			0xB0
+#define TEMP_CPU_LOCAL			0xB1
+#define TEMP_CPU_DTS			0xB5
+#define TEMP_NORTHBRIDGE		0xB6
+#define TEMP_VGA			0xB4
+#define TEMP_SKIN			0xB2
+
+#define BAT_MANUFACTURER_NAME_ADDR	0x10
+#define BAT_MANUFACTURER_NAME_LEN	9
+#define BAT_MODEL_NAME_ADDR		0x19
+#define BAT_MODEL_NAME_LEN		6
+#define BAT_SERIAL_NUMBER_ADDR		0xC4
+#define BAT_SERIAL_NUMBER_LEN		5
+#define BAT_CHARGE_NOW			0xC2
+#define BAT_CHARGE_DESIGN		0xCA
+#define BAT_VOLTAGE_NOW			0xC6
+#define BAT_VOLTAGE_DESIGN		0xC8
+#define BAT_CURRENT_NOW			0xD0
+#define BAT_CURRENT_AVG			0xD2
+#define BAT_POWER			0xD4
+#define BAT_CAPACITY			0xCE
+#define BAT_TEMP			0xD6
+#define BAT_TEMP_AVG			0xD7
+#define BAT_STATUS0			0xC1
+#define BAT_STATUS1			0xF0
+#define BAT_STATUS2			0xF1
+#define BAT_STOP_CHARGE1		0xF2
+#define BAT_STOP_CHARGE2		0xF3
+
+#define BAT_S0_DISCHARGE		(1 << 0)
+#define BAT_S0_DISCHRG_CRITICAL		(1 << 2)
+#define BAT_S0_LOW			(1 << 3)
+#define BAT_S0_CHARGING			(1 << 1)
+#define BAT_S0_AC			(1 << 7)
+#define BAT_S1_EXISTS			(1 << 0)
+#define BAT_S1_FULL			(1 << 1)
+#define BAT_S1_EMPTY			(1 << 2)
+#define BAT_S1_LiION_OR_NiMH		(1 << 7)
+#define BAT_S2_LOW_LOW			(1 << 0)
+#define BAT_STOP_CHRG1_BAD_CELL		(1 << 1)
+#define BAT_STOP_CHRG1_COMM_FAIL	(1 << 2)
+#define BAT_STOP_CHRG1_OVERVOLTAGE	(1 << 6)
+#define BAT_STOP_CHRG1_OVERTEMPERATURE	(1 << 7)
+
+
+/* ======= */
+/* Structs */
+/* ======= */
+struct compal_data{
+	/* Fan control */
+	struct device *hwmon_dev;
+	int pwm_enable; /* 0:full on, 1:set by pwm1, 2:control by moterboard */
+	unsigned char curr_pwm;
+
+	/* Power supply */
+	struct power_supply psy;
+	struct power_supply_info psy_info;
+	char bat_model_name[BAT_MODEL_NAME_LEN + 1];
+	char bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN + 1];
+	char bat_serial_number[BAT_SERIAL_NUMBER_LEN + 1];
+};
+
+
+/* =============== */
+/* General globals */
+/* =============== */
 static int force;
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
 
-/* Hardware access */
+/* Support for the wake_on_XXX, hwmon and power_supply interface. Currently
+ * only gets enabled on a JHL90 board. Might work with the others too */
+static bool extra_features;
 
-static int set_lcd_level(int level)
+/* Nasty stuff. For some reason the fan control is very un-linear.  I've
+ * come up with these values by looping through the possible inputs and
+ * watching the output of address 0x4F (do an ec_transaction writing 0x33
+ * into 0x4F and read a few bytes from the output, like so:
+ *	u8 writeData = 0x33;
+ *	ec_transaction(0x4F, &writeData, 1, buffer, 32, 0);
+ * That address is labled "fan1 table information" in the service manual.
+ * It should be clear which value in 'buffer' changes). This seems to be
+ * related to fan speed. It isn't a proper 'realtime' fan speed value
+ * though, because physically stopping or speeding up the fan doesn't
+ * change it. It might be the average voltage or current of the pwm output.
+ * Nevertheless, it is more fine-grained than the actual RPM reading */
+static const unsigned char pwm_lookup_table[256] = {
+	0, 0, 0, 1, 1, 1, 2, 253, 254, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6,
+	7, 7, 7, 8, 86, 86, 9, 9, 9, 10, 10, 10, 11, 92, 92, 12, 12, 95,
+	13, 66, 66, 14, 14, 98, 15, 15, 15, 16, 16, 67, 17, 17, 72, 18, 70,
+	75, 19, 90, 90, 73, 73, 73, 21, 21, 91, 91, 91, 96, 23, 94, 94, 94,
+	94, 94, 94, 94, 94, 94, 94, 141, 141, 238, 223, 192, 139, 139, 139,
+	139, 139, 142, 142, 142, 142, 142, 78, 78, 78, 78, 78, 76, 76, 76,
+	76, 76, 79, 79, 79, 79, 79, 79, 79, 20, 20, 20, 20, 20, 22, 22, 22,
+	22, 22, 24, 24, 24, 24, 24, 24, 219, 219, 219, 219, 219, 219, 219,
+	219, 27, 27, 188, 188, 28, 28, 28, 29, 186, 186, 186, 186, 186,
+	186, 186, 186, 186, 186, 31, 31, 31, 31, 31, 32, 32, 32, 41, 33,
+	33, 33, 33, 33, 252, 252, 34, 34, 34, 43, 35, 35, 35, 36, 36, 38,
+	206, 206, 206, 206, 206, 206, 206, 206, 206, 37, 37, 37, 46, 46,
+	47, 47, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 48, 48,
+	48, 48, 48, 40, 40, 40, 49, 42, 42, 42, 42, 42, 42, 42, 42, 44,
+	189, 189, 189, 189, 54, 54, 45, 45, 45, 45, 45, 45, 45, 45, 251,
+	191, 199, 199, 199, 199, 199, 215, 215, 215, 215, 187, 187, 187,
+	187, 187, 193, 50
+};
+
+
+
+
+/* ========================= */
+/* Hardware access functions */
+/* ========================= */
+/* General access */
+static u8 ec_read_u8(u8 addr)
 {
-	if (level < 0 || level >= COMPAL_LCD_LEVEL_MAX)
+	u8 value;
+	ec_read(addr, &value);
+	return value;
+}
+
+static s8 ec_read_s8(u8 addr)
+{
+	return (s8)ec_read_u8(addr);
+}
+
+static u16 ec_read_u16(u8 addr)
+{
+	int hi, lo;
+	lo = ec_read_u8(addr);
+	hi = ec_read_u8(addr + 1);
+	return (hi << 8) + lo;
+}
+
+static s16 ec_read_s16(u8 addr)
+{
+	return (s16) ec_read_u16(addr);
+}
+
+static void ec_read_sequence(u8 addr, u8 *buf, int len)
+{
+	int i;
+	for (i = 0; i < len; i++)
+		ec_read(addr + i, buf + i);
+}
+
+
+/* Backlight access */
+static int set_backlight_level(int level)
+{
+	if (level < 0 || level > BACKLIGHT_LEVEL_MAX)
 		return -EINVAL;
 
-	ec_write(COMPAL_EC_COMMAND_LCD_LEVEL, level);
+	ec_write(BACKLIGHT_LEVEL_ADDR, level);
 
+	return 1;
+}
+
+static int get_backlight_level(void)
+{
+	return (int) ec_read_u8(BACKLIGHT_LEVEL_ADDR);
+}
+
+static void set_backlight_state(bool on)
+{
+	u8 data = on ? BACKLIGHT_STATE_ON_DATA : BACKLIGHT_STATE_OFF_DATA;
+	ec_transaction(BACKLIGHT_STATE_ADDR, &data, 1, NULL, 0, 0);
+}
+
+
+/* Fan control access */
+static void pwm_enable_control(void)
+{
+	unsigned char writeData = PWM_ENABLE_DATA;
+	ec_transaction(PWM_ENABLE_ADDR, &writeData, 1, NULL, 0, 0);
+}
+
+static void pwm_disable_control(void)
+{
+	unsigned char writeData = PWM_DISABLE_DATA;
+	ec_transaction(PWM_DISABLE_ADDR, &writeData, 1, NULL, 0, 0);
+}
+
+static void set_pwm(int pwm)
+{
+	ec_transaction(PWM_ADDRESS, &pwm_lookup_table[pwm], 1, NULL, 0, 0);
+}
+
+static int get_fan_rpm(void)
+{
+	u8 value, data = FAN_DATA;
+	ec_transaction(FAN_ADDRESS, &data, 1, &value, 1, 0);
+	return 100 * (int)value;
+}
+
+
+
+
+/* =================== */
+/* Interface functions */
+/* =================== */
+
+/* Backlight interface */
+static int bl_get_brightness(struct backlight_device *b)
+{
+	return get_backlight_level();
+}
+
+static int bl_update_status(struct backlight_device *b)
+{
+	int ret = set_backlight_level(b->props.brightness);
+	if (ret)
+		return ret;
+
+	set_backlight_state((b->props.power == FB_BLANK_UNBLANK)
+		&&    !(b->props.state & BL_CORE_SUSPENDED)
+		&&    !(b->props.state & BL_CORE_FBBLANK));
 	return 0;
 }
 
-static int get_lcd_level(void)
-{
-	u8 result;
+static const struct backlight_ops compalbl_ops = {
+	.get_brightness = bl_get_brightness,
+	.update_status	= bl_update_status,
+};
 
-	ec_read(COMPAL_EC_COMMAND_LCD_LEVEL, &result);
 
-	return (int) result;
-}
-
+/* Wireless interface */
 static int compal_rfkill_set(void *data, bool blocked)
 {
 	unsigned long radio = (unsigned long) data;
-	u8 result, value;
-
-	ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
+	u8 result = ec_read_u8(WIRELESS_ADDR);
+	u8 value;
 
 	if (!blocked)
 		value = (u8) (result | radio);
 	else
 		value = (u8) (result & ~radio);
-	ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
+	ec_write(WIRELESS_ADDR, value);
 
 	return 0;
 }
 
 static void compal_rfkill_poll(struct rfkill *rfkill, void *data)
 {
-	u8 result;
-	bool hw_blocked;
-
-	ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
-
-	hw_blocked = !(result & KILLSWITCH_MASK);
+	u8 result = ec_read_u8(WIRELESS_ADDR);
+	bool hw_blocked = !(result & WIRELESS_KILLSWITCH);
 	rfkill_set_hw_state(rfkill, hw_blocked);
 }
 
@@ -116,80 +374,404 @@
 	.set_block = compal_rfkill_set,
 };
 
-static int setup_rfkill(void)
+
+/* Wake_up interface */
+#define SIMPLE_MASKED_STORE_SHOW(NAME, ADDR, MASK)			\
+static ssize_t NAME##_show(struct device *dev,				\
+	struct device_attribute *attr, char *buf)			\
+{									\
+	return sprintf(buf, "%d\n", ((ec_read_u8(ADDR) & MASK) != 0));	\
+}									\
+static ssize_t NAME##_store(struct device *dev,				\
+	struct device_attribute *attr, const char *buf, size_t count)	\
+{									\
+	int state;							\
+	u8 old_val = ec_read_u8(ADDR);					\
+	if (sscanf(buf, "%d", &state) != 1 || (state < 0 || state > 1))	\
+		return -EINVAL;						\
+	ec_write(ADDR, state ? (old_val | MASK) : (old_val & ~MASK));	\
+	return count;							\
+}
+
+SIMPLE_MASKED_STORE_SHOW(wake_up_pme,	WAKE_UP_ADDR, WAKE_UP_PME)
+SIMPLE_MASKED_STORE_SHOW(wake_up_modem,	WAKE_UP_ADDR, WAKE_UP_MODEM)
+SIMPLE_MASKED_STORE_SHOW(wake_up_lan,	WAKE_UP_ADDR, WAKE_UP_LAN)
+SIMPLE_MASKED_STORE_SHOW(wake_up_wlan,	WAKE_UP_ADDR, WAKE_UP_WLAN)
+SIMPLE_MASKED_STORE_SHOW(wake_up_key,	WAKE_UP_ADDR, WAKE_UP_KEY)
+SIMPLE_MASKED_STORE_SHOW(wake_up_mouse,	WAKE_UP_ADDR, WAKE_UP_MOUSE)
+
+
+/* General hwmon interface */
+static ssize_t hwmon_name_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	int ret;
+	return sprintf(buf, "%s\n", DRIVER_NAME);
+}
 
-	wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
-				RFKILL_TYPE_WLAN, &compal_rfkill_ops,
-				(void *) WLAN_MASK);
-	if (!wifi_rfkill)
-		return -ENOMEM;
 
-	ret = rfkill_register(wifi_rfkill);
-	if (ret)
-		goto err_wifi;
+/* Fan control interface */
+static ssize_t pwm_enable_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct compal_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", data->pwm_enable);
+}
 
-	bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
-				RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
-				(void *) BT_MASK);
-	if (!bt_rfkill) {
-		ret = -ENOMEM;
-		goto err_allocate_bt;
+static ssize_t pwm_enable_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct compal_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+	err = strict_strtol(buf, 10, &val);
+	if (err)
+		return err;
+	if (val < 0)
+		return -EINVAL;
+
+	data->pwm_enable = val;
+
+	switch (val) {
+	case 0:  /* Full speed */
+		pwm_enable_control();
+		set_pwm(255);
+		break;
+	case 1:  /* As set by pwm1 */
+		pwm_enable_control();
+		set_pwm(data->curr_pwm);
+		break;
+	default: /* Control by motherboard */
+		pwm_disable_control();
+		break;
 	}
-	ret = rfkill_register(bt_rfkill);
-	if (ret)
-		goto err_register_bt;
 
+	return count;
+}
+
+static ssize_t pwm_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct compal_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%hhu\n", data->curr_pwm);
+}
+
+static ssize_t pwm_store(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct compal_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+	err = strict_strtol(buf, 10, &val);
+	if (err)
+		return err;
+	if (val < 0 || val > 255)
+		return -EINVAL;
+
+	data->curr_pwm = val;
+
+	if (data->pwm_enable != 1)
+		return count;
+	set_pwm(val);
+
+	return count;
+}
+
+static ssize_t fan_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	return sprintf(buf, "%d\n", get_fan_rpm());
+}
+
+
+/* Temperature interface */
+#define TEMPERATURE_SHOW_TEMP_AND_LABEL(POSTFIX, ADDRESS, LABEL)	\
+static ssize_t temp_##POSTFIX(struct device *dev,			\
+		struct device_attribute *attr, char *buf)		\
+{									\
+	return sprintf(buf, "%d\n", 1000 * (int)ec_read_s8(ADDRESS));	\
+}									\
+static ssize_t label_##POSTFIX(struct device *dev,			\
+		struct device_attribute *attr, char *buf)		\
+{									\
+	return sprintf(buf, "%s\n", LABEL);				\
+}
+
+/* Labels as in service guide */
+TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu,        TEMP_CPU,        "CPU_TEMP");
+TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_local,  TEMP_CPU_LOCAL,  "CPU_TEMP_LOCAL");
+TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_DTS,    TEMP_CPU_DTS,    "CPU_DTS");
+TEMPERATURE_SHOW_TEMP_AND_LABEL(northbridge,TEMP_NORTHBRIDGE,"NorthBridge");
+TEMPERATURE_SHOW_TEMP_AND_LABEL(vga,        TEMP_VGA,        "VGA_TEMP");
+TEMPERATURE_SHOW_TEMP_AND_LABEL(SKIN,       TEMP_SKIN,       "SKIN_TEMP90");
+
+
+/* Power supply interface */
+static int bat_status(void)
+{
+	u8 status0 = ec_read_u8(BAT_STATUS0);
+	u8 status1 = ec_read_u8(BAT_STATUS1);
+
+	if (status0 & BAT_S0_CHARGING)
+		return POWER_SUPPLY_STATUS_CHARGING;
+	if (status0 & BAT_S0_DISCHARGE)
+		return POWER_SUPPLY_STATUS_DISCHARGING;
+	if (status1 & BAT_S1_FULL)
+		return POWER_SUPPLY_STATUS_FULL;
+	return POWER_SUPPLY_STATUS_NOT_CHARGING;
+}
+
+static int bat_health(void)
+{
+	u8 status = ec_read_u8(BAT_STOP_CHARGE1);
+
+	if (status & BAT_STOP_CHRG1_OVERTEMPERATURE)
+		return POWER_SUPPLY_HEALTH_OVERHEAT;
+	if (status & BAT_STOP_CHRG1_OVERVOLTAGE)
+		return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+	if (status & BAT_STOP_CHRG1_BAD_CELL)
+		return POWER_SUPPLY_HEALTH_DEAD;
+	if (status & BAT_STOP_CHRG1_COMM_FAIL)
+		return POWER_SUPPLY_HEALTH_UNKNOWN;
+	return POWER_SUPPLY_HEALTH_GOOD;
+}
+
+static int bat_is_present(void)
+{
+	u8 status = ec_read_u8(BAT_STATUS2);
+	return ((status & BAT_S1_EXISTS) != 0);
+}
+
+static int bat_technology(void)
+{
+	u8 status = ec_read_u8(BAT_STATUS1);
+
+	if (status & BAT_S1_LiION_OR_NiMH)
+		return POWER_SUPPLY_TECHNOLOGY_LION;
+	return POWER_SUPPLY_TECHNOLOGY_NiMH;
+}
+
+static int bat_capacity_level(void)
+{
+	u8 status0 = ec_read_u8(BAT_STATUS0);
+	u8 status1 = ec_read_u8(BAT_STATUS1);
+	u8 status2 = ec_read_u8(BAT_STATUS2);
+
+	if (status0 & BAT_S0_DISCHRG_CRITICAL
+			|| status1 & BAT_S1_EMPTY
+			|| status2 & BAT_S2_LOW_LOW)
+		return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+	if (status0 & BAT_S0_LOW)
+		return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+	if (status1 & BAT_S1_FULL)
+		return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+	return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+}
+
+static int bat_get_property(struct power_supply *psy,
+				enum power_supply_property psp,
+				union power_supply_propval *val)
+{
+	struct compal_data *data;
+	data = container_of(psy, struct compal_data, psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = bat_status();
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = bat_health();
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = bat_is_present();
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = bat_technology();
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: /* THE design voltage... */
+		val->intval = ec_read_u16(BAT_VOLTAGE_DESIGN) * 1000;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = ec_read_u16(BAT_VOLTAGE_NOW) * 1000;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = ec_read_s16(BAT_CURRENT_NOW) * 1000;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_AVG:
+		val->intval = ec_read_s16(BAT_CURRENT_AVG) * 1000;
+		break;
+	case POWER_SUPPLY_PROP_POWER_NOW:
+		val->intval = ec_read_u8(BAT_POWER) * 1000000;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+		val->intval = ec_read_u16(BAT_CHARGE_DESIGN) * 1000;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_NOW:
+		val->intval = ec_read_u16(BAT_CHARGE_NOW) * 1000;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = ec_read_u8(BAT_CAPACITY);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+		val->intval = bat_capacity_level();
+		break;
+	/* It smees that BAT_TEMP_AVG is a (2's complement?) value showing
+	 * the number of degrees, whereas BAT_TEMP is somewhat more
+	 * complicated. It looks like this is a negative nember with a
+	 * 100/256 divider and an offset of 222. Both were determined
+	 * experimentally by comparing BAT_TEMP and BAT_TEMP_AVG. */
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = ((222 - (int)ec_read_u8(BAT_TEMP)) * 1000) >> 8;
+		break;
+	case POWER_SUPPLY_PROP_TEMP_AMBIENT: /* Ambient, Avg, ... same thing */
+		val->intval = ec_read_s8(BAT_TEMP_AVG) * 10;
+		break;
+	/* Neither the model name nor manufacturer name work for me. */
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = data->bat_model_name;
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = data->bat_manufacturer_name;
+		break;
+	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+		val->strval = data->bat_serial_number;
+		break;
+	default:
+		break;
+	}
 	return 0;
-
-err_register_bt:
-	rfkill_destroy(bt_rfkill);
-
-err_allocate_bt:
-	rfkill_unregister(wifi_rfkill);
-
-err_wifi:
-	rfkill_destroy(wifi_rfkill);
-
-	return ret;
-}
-
-/* Backlight device stuff */
-
-static int bl_get_brightness(struct backlight_device *b)
-{
-	return get_lcd_level();
 }
 
 
-static int bl_update_status(struct backlight_device *b)
-{
-	return set_lcd_level(b->props.brightness);
-}
 
-static struct backlight_ops compalbl_ops = {
-	.get_brightness = bl_get_brightness,
-	.update_status	= bl_update_status,
+
+
+/* ============== */
+/* Driver Globals */
+/* ============== */
+static DEVICE_ATTR(wake_up_pme,
+		0644, wake_up_pme_show,		wake_up_pme_store);
+static DEVICE_ATTR(wake_up_modem,
+		0644, wake_up_modem_show,	wake_up_modem_store);
+static DEVICE_ATTR(wake_up_lan,
+		0644, wake_up_lan_show,	wake_up_lan_store);
+static DEVICE_ATTR(wake_up_wlan,
+		0644, wake_up_wlan_show,	wake_up_wlan_store);
+static DEVICE_ATTR(wake_up_key,
+		0644, wake_up_key_show,	wake_up_key_store);
+static DEVICE_ATTR(wake_up_mouse,
+		0644, wake_up_mouse_show,	wake_up_mouse_store);
+
+static SENSOR_DEVICE_ATTR(name,        S_IRUGO, hwmon_name_show,   NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_input,  S_IRUGO, fan_show,          NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, temp_cpu,          NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, temp_cpu_local,    NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, temp_cpu_DTS,      NULL, 1);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, temp_northbridge,  NULL, 1);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, temp_vga,          NULL, 1);
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, temp_SKIN,         NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, label_cpu,         NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, label_cpu_local,   NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, label_cpu_DTS,     NULL, 1);
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, label_northbridge, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO, label_vga,         NULL, 1);
+static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO, label_SKIN,        NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, pwm_show, pwm_store, 1);
+static SENSOR_DEVICE_ATTR(pwm1_enable,
+		S_IRUGO | S_IWUSR, pwm_enable_show, pwm_enable_store, 0);
+
+static struct attribute *compal_attributes[] = {
+	&dev_attr_wake_up_pme.attr,
+	&dev_attr_wake_up_modem.attr,
+	&dev_attr_wake_up_lan.attr,
+	&dev_attr_wake_up_wlan.attr,
+	&dev_attr_wake_up_key.attr,
+	&dev_attr_wake_up_mouse.attr,
+	/* Maybe put the sensor-stuff in a separate hwmon-driver? That way,
+	 * the hwmon sysfs won't be cluttered with the above files. */
+	&sensor_dev_attr_name.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp5_input.dev_attr.attr,
+	&sensor_dev_attr_temp6_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_label.dev_attr.attr,
+	&sensor_dev_attr_temp2_label.dev_attr.attr,
+	&sensor_dev_attr_temp3_label.dev_attr.attr,
+	&sensor_dev_attr_temp4_label.dev_attr.attr,
+	&sensor_dev_attr_temp5_label.dev_attr.attr,
+	&sensor_dev_attr_temp6_label.dev_attr.attr,
+	NULL
+};
+
+static struct attribute_group compal_attribute_group = {
+	.attrs = compal_attributes
+};
+
+static int __devinit compal_probe(struct platform_device *);
+static int __devexit compal_remove(struct platform_device *);
+static struct platform_driver compal_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe	= compal_probe,
+	.remove	= __devexit_p(compal_remove)
+};
+
+static enum power_supply_property compal_bat_properties[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CURRENT_AVG,
+	POWER_SUPPLY_PROP_POWER_NOW,
+	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_TEMP_AMBIENT,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_SERIAL_NUMBER,
 };
 
 static struct backlight_device *compalbl_device;
 
+static struct platform_device *compal_device;
 
-static struct platform_driver compal_driver = {
-	.driver = {
-		.name = "compal-laptop",
-		.owner = THIS_MODULE,
-	}
-};
+static struct rfkill *wifi_rfkill;
+static struct rfkill *bt_rfkill;
 
-/* Initialization */
+
+
+
+
+/* =================================== */
+/* Initialization & clean-up functions */
+/* =================================== */
 
 static int dmi_check_cb(const struct dmi_system_id *id)
 {
-	printk(KERN_INFO "compal-laptop: Identified laptop model '%s'.\n",
+	printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n",
 		id->ident);
+	extra_features = false;
+	return 0;
+}
 
+static int dmi_check_cb_extra(const struct dmi_system_id *id)
+{
+	printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s', "
+		"enabling extra features\n",
+		id->ident);
+	extra_features = true;
 	return 0;
 }
 
@@ -274,27 +856,106 @@
 		},
 		.callback = dmi_check_cb
 	},
-
+	{
+		.ident = "JHL90",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_NAME, "JHL90"),
+			DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
+		},
+		.callback = dmi_check_cb_extra
+	},
 	{ }
 };
 
+static void initialize_power_supply_data(struct compal_data *data)
+{
+	data->psy.name = DRIVER_NAME;
+	data->psy.type = POWER_SUPPLY_TYPE_BATTERY;
+	data->psy.properties = compal_bat_properties;
+	data->psy.num_properties = ARRAY_SIZE(compal_bat_properties);
+	data->psy.get_property = bat_get_property;
+
+	ec_read_sequence(BAT_MANUFACTURER_NAME_ADDR,
+					data->bat_manufacturer_name,
+					BAT_MANUFACTURER_NAME_LEN);
+	data->bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN] = 0;
+
+	ec_read_sequence(BAT_MODEL_NAME_ADDR,
+					data->bat_model_name,
+					BAT_MODEL_NAME_LEN);
+	data->bat_model_name[BAT_MODEL_NAME_LEN] = 0;
+
+	scnprintf(data->bat_serial_number, BAT_SERIAL_NUMBER_LEN + 1, "%d",
+				ec_read_u16(BAT_SERIAL_NUMBER_ADDR));
+}
+
+static void initialize_fan_control_data(struct compal_data *data)
+{
+	data->pwm_enable = 2; /* Keep motherboard in control for now */
+	data->curr_pwm = 255; /* Try not to cause a CPU_on_fire exception
+				 if we take over... */
+}
+
+static int setup_rfkill(void)
+{
+	int ret;
+
+	wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
+				RFKILL_TYPE_WLAN, &compal_rfkill_ops,
+				(void *) WIRELESS_WLAN);
+	if (!wifi_rfkill)
+		return -ENOMEM;
+
+	ret = rfkill_register(wifi_rfkill);
+	if (ret)
+		goto err_wifi;
+
+	bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
+				RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
+				(void *) WIRELESS_BT);
+	if (!bt_rfkill) {
+		ret = -ENOMEM;
+		goto err_allocate_bt;
+	}
+	ret = rfkill_register(bt_rfkill);
+	if (ret)
+		goto err_register_bt;
+
+	return 0;
+
+err_register_bt:
+	rfkill_destroy(bt_rfkill);
+
+err_allocate_bt:
+	rfkill_unregister(wifi_rfkill);
+
+err_wifi:
+	rfkill_destroy(wifi_rfkill);
+
+	return ret;
+}
+
 static int __init compal_init(void)
 {
 	int ret;
 
-	if (acpi_disabled)
+	if (acpi_disabled) {
+		printk(KERN_ERR DRIVER_NAME": ACPI needs to be enabled for "
+						"this driver to work!\n");
 		return -ENODEV;
+	}
 
-	if (!force && !dmi_check_system(compal_dmi_table))
+	if (!force && !dmi_check_system(compal_dmi_table)) {
+		printk(KERN_ERR DRIVER_NAME": Motherboard not recognized (You "
+				"could try the module's force-parameter)");
 		return -ENODEV;
-
-	/* Register backlight stuff */
+	}
 
 	if (!acpi_video_backlight_support()) {
 		struct backlight_properties props;
 		memset(&props, 0, sizeof(struct backlight_properties));
-		props.max_brightness = COMPAL_LCD_LEVEL_MAX - 1;
-		compalbl_device = backlight_device_register("compal-laptop",
+		props.max_brightness = BACKLIGHT_LEVEL_MAX;
+		compalbl_device = backlight_device_register(DRIVER_NAME,
 							    NULL, NULL,
 							    &compalbl_ops,
 							    &props);
@@ -304,67 +965,122 @@
 
 	ret = platform_driver_register(&compal_driver);
 	if (ret)
-		goto fail_backlight;
+		goto err_backlight;
 
-	/* Register platform stuff */
-
-	compal_device = platform_device_alloc("compal-laptop", -1);
+	compal_device = platform_device_alloc(DRIVER_NAME, -1);
 	if (!compal_device) {
 		ret = -ENOMEM;
-		goto fail_platform_driver;
+		goto err_platform_driver;
 	}
 
-	ret = platform_device_add(compal_device);
+	ret = platform_device_add(compal_device); /* This calls compal_probe */
 	if (ret)
-		goto fail_platform_device;
+		goto err_platform_device;
 
 	ret = setup_rfkill();
 	if (ret)
-		goto fail_rfkill;
+		goto err_rfkill;
 
-	printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION
-		" successfully loaded.\n");
-
+	printk(KERN_INFO DRIVER_NAME": Driver "DRIVER_VERSION
+						" successfully loaded\n");
 	return 0;
 
-fail_rfkill:
+err_rfkill:
 	platform_device_del(compal_device);
 
-fail_platform_device:
-
+err_platform_device:
 	platform_device_put(compal_device);
 
-fail_platform_driver:
-
+err_platform_driver:
 	platform_driver_unregister(&compal_driver);
 
-fail_backlight:
-
+err_backlight:
 	backlight_device_unregister(compalbl_device);
 
 	return ret;
 }
 
+static int __devinit compal_probe(struct platform_device *pdev)
+{
+	int err;
+	struct compal_data *data;
+
+	if (!extra_features)
+		return 0;
+
+	/* Fan control */
+	data = kzalloc(sizeof(struct compal_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	initialize_fan_control_data(data);
+
+	err = sysfs_create_group(&pdev->dev.kobj, &compal_attribute_group);
+	if (err)
+		return err;
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		sysfs_remove_group(&pdev->dev.kobj,
+				&compal_attribute_group);
+		kfree(data);
+		return err;
+	}
+
+	/* Power supply */
+	initialize_power_supply_data(data);
+	power_supply_register(&compal_device->dev, &data->psy);
+
+	platform_set_drvdata(pdev, data);
+
+	return 0;
+}
+
 static void __exit compal_cleanup(void)
 {
-
 	platform_device_unregister(compal_device);
 	platform_driver_unregister(&compal_driver);
 	backlight_device_unregister(compalbl_device);
 	rfkill_unregister(wifi_rfkill);
-	rfkill_destroy(wifi_rfkill);
 	rfkill_unregister(bt_rfkill);
+	rfkill_destroy(wifi_rfkill);
 	rfkill_destroy(bt_rfkill);
 
-	printk(KERN_INFO "compal-laptop: driver unloaded.\n");
+	printk(KERN_INFO DRIVER_NAME": Driver unloaded\n");
 }
 
+static int __devexit compal_remove(struct platform_device *pdev)
+{
+	struct compal_data *data;
+
+	if (!extra_features)
+		return 0;
+
+	printk(KERN_INFO DRIVER_NAME": Unloading: resetting fan control "
+							"to motherboard\n");
+	pwm_disable_control();
+
+	data = platform_get_drvdata(pdev);
+	hwmon_device_unregister(data->hwmon_dev);
+	power_supply_unregister(&data->psy);
+
+	platform_set_drvdata(pdev, NULL);
+	kfree(data);
+
+	sysfs_remove_group(&pdev->dev.kobj, &compal_attribute_group);
+
+	return 0;
+}
+
+
 module_init(compal_init);
 module_exit(compal_cleanup);
 
 MODULE_AUTHOR("Cezary Jackiewicz");
+MODULE_AUTHOR("Roald Frederickx (roald.frederickx@gmail.com)");
 MODULE_DESCRIPTION("Compal Laptop Support");
-MODULE_VERSION(COMPAL_DRIVER_VERSION);
+MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
 MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*");
@@ -372,6 +1088,7 @@
 MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
 MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
 MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
+MODULE_ALIAS("dmi:*:rnJHL90:rvrREFERENCE:*");
 MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*");
 MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*");
 MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 661e3ac..b41ed5c 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -83,6 +83,12 @@
 		},
 	},
 	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /*Laptop*/
+		},
+	},
+	{
 		.ident = "Dell Computer Corporation",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
@@ -467,7 +473,7 @@
 	.update_status  = dell_send_intensity,
 };
 
-bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
+static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
 			      struct serio *port)
 {
 	static bool extended;
@@ -621,4 +627,5 @@
 MODULE_DESCRIPTION("Dell laptop driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*");
+MODULE_ALIAS("dmi:*svnDellInc.:*:ct9:*");
 MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*");
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 66f53c3..08fb70f 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -221,7 +221,7 @@
 			return;
 		}
 
-		if (dell_new_hk_type)
+		if (dell_new_hk_type || buffer_entry[1] == 0x0)
 			reported_key = (int)buffer_entry[2];
 		else
 			reported_key = (int)buffer_entry[1] & 0xffff;
@@ -339,13 +339,18 @@
 	acpi_video = acpi_video_backlight_support();
 
 	err = dell_wmi_input_setup();
-	if (err)
+	if (err) {
+		if (dell_new_hk_type)
+			kfree(dell_wmi_keymap);
 		return err;
+	}
 
 	status = wmi_install_notify_handler(DELL_EVENT_GUID,
 					 dell_wmi_notify, NULL);
 	if (ACPI_FAILURE(status)) {
 		input_unregister_device(dell_wmi_input_dev);
+		if (dell_new_hk_type)
+			kfree(dell_wmi_keymap);
 		printk(KERN_ERR
 			"dell-wmi: Unable to register notify handler - %d\n",
 			status);
@@ -359,6 +364,8 @@
 {
 	wmi_remove_notify_handler(DELL_EVENT_GUID);
 	input_unregister_device(dell_wmi_input_dev);
+	if (dell_new_hk_type)
+		kfree(dell_wmi_keymap);
 }
 
 module_init(dell_wmi_init);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 0306174..6b8e062 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -53,7 +53,7 @@
 
 static bool hotplug_disabled;
 
-module_param(hotplug_disabled, bool, 0644);
+module_param(hotplug_disabled, bool, 0444);
 MODULE_PARM_DESC(hotplug_disabled,
 		 "Disable hotplug for wireless device. "
 		 "If your laptop need that, please report to "
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index e325aeb..f44cd26 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -182,7 +182,7 @@
 static void logolamp_set(struct led_classdev *cdev,
 			       enum led_brightness brightness);
 
-struct led_classdev logolamp_led = {
+static struct led_classdev logolamp_led = {
  .name = "fujitsu::logolamp",
  .brightness_get = logolamp_get,
  .brightness_set = logolamp_set
@@ -192,7 +192,7 @@
 static void kblamps_set(struct led_classdev *cdev,
 			       enum led_brightness brightness);
 
-struct led_classdev kblamps_led = {
+static struct led_classdev kblamps_led = {
  .name = "fujitsu::kblamps",
  .brightness_get = kblamps_get,
  .brightness_set = kblamps_set
@@ -603,7 +603,7 @@
 	dmi_check_cb_common(id);
 	fujitsu->keycode1 = KEY_SCREENLOCK;	/* "Lock" */
 	fujitsu->keycode2 = KEY_HELP;	/* "Mobility Center" */
-	return 0;
+	return 1;
 }
 
 static int dmi_check_cb_s6420(const struct dmi_system_id *id)
@@ -611,7 +611,7 @@
 	dmi_check_cb_common(id);
 	fujitsu->keycode1 = KEY_SCREENLOCK;	/* "Lock" */
 	fujitsu->keycode2 = KEY_HELP;	/* "Mobility Center" */
-	return 0;
+	return 1;
 }
 
 static int dmi_check_cb_p8010(const struct dmi_system_id *id)
@@ -620,7 +620,7 @@
 	fujitsu->keycode1 = KEY_HELP;	/* "Support" */
 	fujitsu->keycode3 = KEY_SWITCHVIDEOMODE;	/* "Presentation" */
 	fujitsu->keycode4 = KEY_WWW;	/* "Internet" */
-	return 0;
+	return 1;
 }
 
 static struct dmi_system_id fujitsu_dmi_table[] = {
@@ -725,6 +725,7 @@
 
 err_unregister_input_dev:
 	input_unregister_device(input);
+	input = NULL;
 err_free_input_dev:
 	input_free_device(input);
 err_stop:
@@ -738,8 +739,6 @@
 
 	input_unregister_device(input);
 
-	input_free_device(input);
-
 	fujitsu->acpi_handle = NULL;
 
 	return 0;
@@ -930,6 +929,7 @@
 
 err_unregister_input_dev:
 	input_unregister_device(input);
+	input = NULL;
 err_free_input_dev:
 	input_free_device(input);
 err_free_fifo:
@@ -953,8 +953,6 @@
 
 	input_unregister_device(input);
 
-	input_free_device(input);
-
 	kfifo_free(&fujitsu_hotkey->fifo);
 
 	fujitsu_hotkey->acpi_handle = NULL;
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 51c07a0..f155163 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -29,7 +29,6 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/input.h>
-#include <acpi/acpi_drivers.h>
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 #include <linux/rfkill.h>
@@ -52,12 +51,25 @@
 #define HPWMI_WIRELESS_QUERY 0x5
 #define HPWMI_HOTKEY_QUERY 0xc
 
+#define PREFIX "HP WMI: "
+#define UNIMP "Unimplemented "
+
 enum hp_wmi_radio {
 	HPWMI_WIFI = 0,
 	HPWMI_BLUETOOTH = 1,
 	HPWMI_WWAN = 2,
 };
 
+enum hp_wmi_event_ids {
+	HPWMI_DOCK_EVENT = 1,
+	HPWMI_PARK_HDD = 2,
+	HPWMI_SMART_ADAPTER = 3,
+	HPWMI_BEZEL_BUTTON = 4,
+	HPWMI_WIRELESS = 5,
+	HPWMI_CPU_BATTERY_THROTTLE = 6,
+	HPWMI_LOCK_SWITCH = 7,
+};
+
 static int __devinit hp_wmi_bios_setup(struct platform_device *device);
 static int __exit hp_wmi_bios_remove(struct platform_device *device);
 static int hp_wmi_resume_handler(struct device *device);
@@ -67,13 +79,12 @@
 	u32 command;
 	u32 commandtype;
 	u32 datasize;
-	u32 data;
+	char *data;
 };
 
 struct bios_return {
 	u32 sigpass;
 	u32 return_code;
-	u32 value;
 };
 
 struct key_entry {
@@ -88,6 +99,7 @@
 	{KE_KEY, 0x02, KEY_BRIGHTNESSUP},
 	{KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
 	{KE_KEY, 0x20e6, KEY_PROG1},
+	{KE_KEY, 0x20e8, KEY_MEDIA},
 	{KE_KEY, 0x2142, KEY_MEDIA},
 	{KE_KEY, 0x213b, KEY_INFO},
 	{KE_KEY, 0x2169, KEY_DIRECTION},
@@ -117,7 +129,27 @@
 	.remove = hp_wmi_bios_remove,
 };
 
-static int hp_wmi_perform_query(int query, int write, int value)
+/*
+ * hp_wmi_perform_query
+ *
+ * query:	The commandtype -> What should be queried
+ * write:	The command -> 0 read, 1 write, 3 ODM specific
+ * buffer:	Buffer used as input and/or output
+ * buffersize:	Size of buffer
+ *
+ * returns zero on success
+ *         an HP WMI query specific error code (which is positive)
+ *         -EINVAL if the query was not successful at all
+ *         -EINVAL if the output buffer size exceeds buffersize
+ *
+ * Note: The buffersize must at least be the maximum of the input and output
+ *       size. E.g. Battery info query (0x7) is defined to have 1 byte input
+ *       and 128 byte output. The caller would do:
+ *       buffer = kzalloc(128, GFP_KERNEL);
+ *       ret = hp_wmi_perform_query(0x7, 0, buffer, 128)
+ */
+static int hp_wmi_perform_query(int query, int write, char *buffer,
+				int buffersize)
 {
 	struct bios_return bios_return;
 	acpi_status status;
@@ -126,8 +158,8 @@
 		.signature = 0x55434553,
 		.command = write ? 0x2 : 0x1,
 		.commandtype = query,
-		.datasize = write ? 0x4 : 0,
-		.data = value,
+		.datasize = buffersize,
+		.data = buffer,
 	};
 	struct acpi_buffer input = { sizeof(struct bios_args), &args };
 	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -144,54 +176,90 @@
 	}
 
 	bios_return = *((struct bios_return *)obj->buffer.pointer);
+
+	if (bios_return.return_code) {
+		printk(KERN_WARNING PREFIX "Query %d returned %d\n", query,
+		       bios_return.return_code);
+		kfree(obj);
+		return bios_return.return_code;
+	}
+	if (obj->buffer.length - sizeof(bios_return) > buffersize) {
+		kfree(obj);
+		return -EINVAL;
+	}
+
+	memset(buffer, 0, buffersize);
+	memcpy(buffer,
+	       ((char *)obj->buffer.pointer) + sizeof(struct bios_return),
+	       obj->buffer.length - sizeof(bios_return));
 	kfree(obj);
-	if (bios_return.return_code > 0)
-		return bios_return.return_code * -1;
-	else
-		return bios_return.value;
+	return 0;
 }
 
 static int hp_wmi_display_state(void)
 {
-	return hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, 0);
+	int state;
+	int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, (char *)&state,
+				       sizeof(state));
+	if (ret)
+		return -EINVAL;
+	return state;
 }
 
 static int hp_wmi_hddtemp_state(void)
 {
-	return hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, 0);
+	int state;
+	int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, (char *)&state,
+				       sizeof(state));
+	if (ret)
+		return -EINVAL;
+	return state;
 }
 
 static int hp_wmi_als_state(void)
 {
-	return hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, 0);
+	int state;
+	int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, (char *)&state,
+				       sizeof(state));
+	if (ret)
+		return -EINVAL;
+	return state;
 }
 
 static int hp_wmi_dock_state(void)
 {
-	int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0);
+	int state;
+	int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state,
+				       sizeof(state));
 
-	if (ret < 0)
-		return ret;
+	if (ret)
+		return -EINVAL;
 
-	return ret & 0x1;
+	return state & 0x1;
 }
 
 static int hp_wmi_tablet_state(void)
 {
-	int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0);
-
-	if (ret < 0)
+	int state;
+	int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state,
+				       sizeof(state));
+	if (ret)
 		return ret;
 
-	return (ret & 0x4) ? 1 : 0;
+	return (state & 0x4) ? 1 : 0;
 }
 
 static int hp_wmi_set_block(void *data, bool blocked)
 {
 	enum hp_wmi_radio r = (enum hp_wmi_radio) data;
 	int query = BIT(r + 8) | ((!blocked) << r);
+	int ret;
 
-	return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
+	ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
+				   (char *)&query, sizeof(query));
+	if (ret)
+		return -EINVAL;
+	return 0;
 }
 
 static const struct rfkill_ops hp_wmi_rfkill_ops = {
@@ -200,8 +268,13 @@
 
 static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
 {
-	int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
-	int mask = 0x200 << (r * 8);
+	int wireless;
+	int mask;
+	hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
+			     (char *)&wireless, sizeof(wireless));
+	/* TBD: Pass error */
+
+	mask = 0x200 << (r * 8);
 
 	if (wireless & mask)
 		return false;
@@ -211,8 +284,13 @@
 
 static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
 {
-	int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
-	int mask = 0x800 << (r * 8);
+	int wireless;
+	int mask;
+	hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
+			     (char *)&wireless, sizeof(wireless));
+	/* TBD: Pass error */
+
+	mask = 0x800 << (r * 8);
 
 	if (wireless & mask)
 		return false;
@@ -269,7 +347,11 @@
 		       const char *buf, size_t count)
 {
 	u32 tmp = simple_strtoul(buf, NULL, 10);
-	hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, tmp);
+	int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, (char *)&tmp,
+				       sizeof(tmp));
+	if (ret)
+		return -EINVAL;
+
 	return count;
 }
 
@@ -338,47 +420,82 @@
 	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
 	static struct key_entry *key;
 	union acpi_object *obj;
-	int eventcode;
+	u32 event_id, event_data;
+	int key_code, ret;
+	u32 *location;
 	acpi_status status;
 
 	status = wmi_get_event_data(value, &response);
 	if (status != AE_OK) {
-		printk(KERN_INFO "hp-wmi: bad event status 0x%x\n", status);
+		printk(KERN_INFO PREFIX "bad event status 0x%x\n", status);
 		return;
 	}
 
 	obj = (union acpi_object *)response.pointer;
 
-	if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) {
-		printk(KERN_INFO "HP WMI: Unknown response received\n");
+	if (!obj)
+		return;
+	if (obj->type != ACPI_TYPE_BUFFER) {
+		printk(KERN_INFO "hp-wmi: Unknown response received %d\n",
+		       obj->type);
 		kfree(obj);
 		return;
 	}
 
-	eventcode = *((u8 *) obj->buffer.pointer);
+	/*
+	 * Depending on ACPI version the concatenation of id and event data
+	 * inside _WED function will result in a 8 or 16 byte buffer.
+	 */
+	location = (u32 *)obj->buffer.pointer;
+	if (obj->buffer.length == 8) {
+		event_id = *location;
+		event_data = *(location + 1);
+	} else if (obj->buffer.length == 16) {
+		event_id = *location;
+		event_data = *(location + 2);
+	} else {
+		printk(KERN_INFO "hp-wmi: Unknown buffer length %d\n",
+		       obj->buffer.length);
+		kfree(obj);
+		return;
+	}
 	kfree(obj);
-	if (eventcode == 0x4)
-		eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
-						0);
-	key = hp_wmi_get_entry_by_scancode(eventcode);
-	if (key) {
-		switch (key->type) {
-		case KE_KEY:
-			input_report_key(hp_wmi_input_dev,
-					 key->keycode, 1);
-			input_sync(hp_wmi_input_dev);
-			input_report_key(hp_wmi_input_dev,
-					 key->keycode, 0);
-			input_sync(hp_wmi_input_dev);
-			break;
-		}
-	} else if (eventcode == 0x1) {
+
+	switch (event_id) {
+	case HPWMI_DOCK_EVENT:
 		input_report_switch(hp_wmi_input_dev, SW_DOCK,
 				    hp_wmi_dock_state());
 		input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
 				    hp_wmi_tablet_state());
 		input_sync(hp_wmi_input_dev);
-	} else if (eventcode == 0x5) {
+		break;
+	case HPWMI_PARK_HDD:
+		break;
+	case HPWMI_SMART_ADAPTER:
+		break;
+	case HPWMI_BEZEL_BUTTON:
+		ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
+					   (char *)&key_code,
+					   sizeof(key_code));
+		if (ret)
+			break;
+		key = hp_wmi_get_entry_by_scancode(key_code);
+		if (key) {
+			switch (key->type) {
+			case KE_KEY:
+				input_report_key(hp_wmi_input_dev,
+						 key->keycode, 1);
+				input_sync(hp_wmi_input_dev);
+				input_report_key(hp_wmi_input_dev,
+						 key->keycode, 0);
+				input_sync(hp_wmi_input_dev);
+				break;
+			}
+		} else
+			printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
+			       key_code);
+		break;
+	case HPWMI_WIRELESS:
 		if (wifi_rfkill)
 			rfkill_set_states(wifi_rfkill,
 					  hp_wmi_get_sw_state(HPWMI_WIFI),
@@ -391,9 +508,18 @@
 			rfkill_set_states(wwan_rfkill,
 					  hp_wmi_get_sw_state(HPWMI_WWAN),
 					  hp_wmi_get_hw_state(HPWMI_WWAN));
-	} else
-		printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
-			eventcode);
+		break;
+	case HPWMI_CPU_BATTERY_THROTTLE:
+		printk(KERN_INFO PREFIX UNIMP "CPU throttle because of 3 Cell"
+		       " battery event detected\n");
+		break;
+	case HPWMI_LOCK_SWITCH:
+		break;
+	default:
+		printk(KERN_INFO PREFIX "Unknown event_id - %d - 0x%x\n",
+		       event_id, event_data);
+		break;
+	}
 }
 
 static int __init hp_wmi_input_setup(void)
@@ -402,6 +528,8 @@
 	int err;
 
 	hp_wmi_input_dev = input_allocate_device();
+	if (!hp_wmi_input_dev)
+		return -ENOMEM;
 
 	hp_wmi_input_dev->name = "HP WMI hotkeys";
 	hp_wmi_input_dev->phys = "wmi/input0";
@@ -450,7 +578,12 @@
 static int __devinit hp_wmi_bios_setup(struct platform_device *device)
 {
 	int err;
-	int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
+	int wireless;
+
+	err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, (char *)&wireless,
+				   sizeof(wireless));
+	if (err)
+		return err;
 
 	err = device_create_file(&device->dev, &dev_attr_display);
 	if (err)
@@ -581,27 +714,51 @@
 static int __init hp_wmi_init(void)
 {
 	int err;
+	int event_capable = wmi_has_guid(HPWMI_EVENT_GUID);
+	int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
 
-	if (wmi_has_guid(HPWMI_EVENT_GUID)) {
+	if (event_capable) {
 		err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
 						 hp_wmi_notify, NULL);
-		if (ACPI_SUCCESS(err))
-			hp_wmi_input_setup();
+		if (ACPI_FAILURE(err))
+			return -EINVAL;
+		err = hp_wmi_input_setup();
+		if (err) {
+			wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+			return err;
+		}
 	}
 
-	if (wmi_has_guid(HPWMI_BIOS_GUID)) {
+	if (bios_capable) {
 		err = platform_driver_register(&hp_wmi_driver);
 		if (err)
-			return 0;
+			goto err_driver_reg;
 		hp_wmi_platform_dev = platform_device_alloc("hp-wmi", -1);
 		if (!hp_wmi_platform_dev) {
-			platform_driver_unregister(&hp_wmi_driver);
-			return 0;
+			err = -ENOMEM;
+			goto err_device_alloc;
 		}
-		platform_device_add(hp_wmi_platform_dev);
+		err = platform_device_add(hp_wmi_platform_dev);
+		if (err)
+			goto err_device_add;
 	}
 
+	if (!bios_capable && !event_capable)
+		return -ENODEV;
+
 	return 0;
+
+err_device_add:
+	platform_device_put(hp_wmi_platform_dev);
+err_device_alloc:
+	platform_driver_unregister(&hp_wmi_driver);
+err_driver_reg:
+	if (wmi_has_guid(HPWMI_EVENT_GUID)) {
+		input_unregister_device(hp_wmi_input_dev);
+		wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+	}
+
+	return err;
 }
 
 static void __exit hp_wmi_exit(void)
@@ -611,7 +768,7 @@
 		input_unregister_device(hp_wmi_input_dev);
 	}
 	if (hp_wmi_platform_dev) {
-		platform_device_del(hp_wmi_platform_dev);
+		platform_device_unregister(hp_wmi_platform_dev);
 		platform_driver_unregister(&hp_wmi_driver);
 	}
 }
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
new file mode 100644
index 0000000..afe82e5
--- /dev/null
+++ b/drivers/platform/x86/intel_ips.c
@@ -0,0 +1,1660 @@
+/*
+ * Copyright (c) 2009-2010 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".
+ *
+ * Authors:
+ *	Jesse Barnes <jbarnes@virtuousgeek.org>
+ */
+
+/*
+ * Some Intel Ibex Peak based platforms support so-called "intelligent
+ * power sharing", which allows the CPU and GPU to cooperate to maximize
+ * performance within a given TDP (thermal design point).  This driver
+ * performs the coordination between the CPU and GPU, monitors thermal and
+ * power statistics in the platform, and initializes power monitoring
+ * hardware.  It also provides a few tunables to control behavior.  Its
+ * primary purpose is to safely allow CPU and GPU turbo modes to be enabled
+ * by tracking power and thermal budget; secondarily it can boost turbo
+ * performance by allocating more power or thermal budget to the CPU or GPU
+ * based on available headroom and activity.
+ *
+ * The basic algorithm is driven by a 5s moving average of tempurature.  If
+ * thermal headroom is available, the CPU and/or GPU power clamps may be
+ * adjusted upwards.  If we hit the thermal ceiling or a thermal trigger,
+ * we scale back the clamp.  Aside from trigger events (when we're critically
+ * close or over our TDP) we don't adjust the clamps more than once every
+ * five seconds.
+ *
+ * The thermal device (device 31, function 6) has a set of registers that
+ * are updated by the ME firmware.  The ME should also take the clamp values
+ * written to those registers and write them to the CPU, but we currently
+ * bypass that functionality and write the CPU MSR directly.
+ *
+ * UNSUPPORTED:
+ *   - dual MCP configs
+ *
+ * TODO:
+ *   - handle CPU hotplug
+ *   - provide turbo enable/disable api
+ *   - make sure we can write turbo enable/disable reg based on MISC_EN
+ *
+ * Related documents:
+ *   - CDI 403777, 403778 - Auburndale EDS vol 1 & 2
+ *   - CDI 401376 - Ibex Peak EDS
+ *   - ref 26037, 26641 - IPS BIOS spec
+ *   - ref 26489 - Nehalem BIOS writer's guide
+ *   - ref 26921 - Ibex Peak BIOS Specification
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/tick.h>
+#include <linux/timer.h>
+#include <drm/i915_drm.h>
+#include <asm/msr.h>
+#include <asm/processor.h>
+
+#define PCI_DEVICE_ID_INTEL_THERMAL_SENSOR 0x3b32
+
+/*
+ * Package level MSRs for monitor/control
+ */
+#define PLATFORM_INFO	0xce
+#define   PLATFORM_TDP		(1<<29)
+#define   PLATFORM_RATIO	(1<<28)
+
+#define IA32_MISC_ENABLE	0x1a0
+#define   IA32_MISC_TURBO_EN	(1ULL<<38)
+
+#define TURBO_POWER_CURRENT_LIMIT	0x1ac
+#define   TURBO_TDC_OVR_EN	(1UL<<31)
+#define   TURBO_TDC_MASK	(0x000000007fff0000UL)
+#define   TURBO_TDC_SHIFT	(16)
+#define   TURBO_TDP_OVR_EN	(1UL<<15)
+#define   TURBO_TDP_MASK	(0x0000000000003fffUL)
+
+/*
+ * Core/thread MSRs for monitoring
+ */
+#define IA32_PERF_CTL		0x199
+#define   IA32_PERF_TURBO_DIS	(1ULL<<32)
+
+/*
+ * Thermal PCI device regs
+ */
+#define THM_CFG_TBAR	0x10
+#define THM_CFG_TBAR_HI	0x14
+
+#define THM_TSIU	0x00
+#define THM_TSE		0x01
+#define   TSE_EN	0xb8
+#define THM_TSS		0x02
+#define THM_TSTR	0x03
+#define THM_TSTTP	0x04
+#define THM_TSCO	0x08
+#define THM_TSES	0x0c
+#define THM_TSGPEN	0x0d
+#define   TSGPEN_HOT_LOHI	(1<<1)
+#define   TSGPEN_CRIT_LOHI	(1<<2)
+#define THM_TSPC	0x0e
+#define THM_PPEC	0x10
+#define THM_CTA		0x12
+#define THM_PTA		0x14
+#define   PTA_SLOPE_MASK	(0xff00)
+#define   PTA_SLOPE_SHIFT	8
+#define   PTA_OFFSET_MASK	(0x00ff)
+#define THM_MGTA	0x16
+#define   MGTA_SLOPE_MASK	(0xff00)
+#define   MGTA_SLOPE_SHIFT	8
+#define   MGTA_OFFSET_MASK	(0x00ff)
+#define THM_TRC		0x1a
+#define   TRC_CORE2_EN	(1<<15)
+#define   TRC_THM_EN	(1<<12)
+#define   TRC_C6_WAR	(1<<8)
+#define   TRC_CORE1_EN	(1<<7)
+#define   TRC_CORE_PWR	(1<<6)
+#define   TRC_PCH_EN	(1<<5)
+#define   TRC_MCH_EN	(1<<4)
+#define   TRC_DIMM4	(1<<3)
+#define   TRC_DIMM3	(1<<2)
+#define   TRC_DIMM2	(1<<1)
+#define   TRC_DIMM1	(1<<0)
+#define THM_TES		0x20
+#define THM_TEN		0x21
+#define   TEN_UPDATE_EN	1
+#define THM_PSC		0x24
+#define   PSC_NTG	(1<<0) /* No GFX turbo support */
+#define   PSC_NTPC	(1<<1) /* No CPU turbo support */
+#define   PSC_PP_DEF	(0<<2) /* Perf policy up to driver */
+#define   PSP_PP_PC	(1<<2) /* BIOS prefers CPU perf */
+#define   PSP_PP_BAL	(2<<2) /* BIOS wants balanced perf */
+#define   PSP_PP_GFX	(3<<2) /* BIOS prefers GFX perf */
+#define   PSP_PBRT	(1<<4) /* BIOS run time support */
+#define THM_CTV1	0x30
+#define   CTV_TEMP_ERROR (1<<15)
+#define   CTV_TEMP_MASK	0x3f
+#define   CTV_
+#define THM_CTV2	0x32
+#define THM_CEC		0x34 /* undocumented power accumulator in joules */
+#define THM_AE		0x3f
+#define THM_HTS		0x50 /* 32 bits */
+#define   HTS_PCPL_MASK	(0x7fe00000)
+#define   HTS_PCPL_SHIFT 21
+#define   HTS_GPL_MASK  (0x001ff000)
+#define   HTS_GPL_SHIFT 12
+#define   HTS_PP_MASK	(0x00000c00)
+#define   HTS_PP_SHIFT  10
+#define   HTS_PP_DEF	0
+#define   HTS_PP_PROC	1
+#define   HTS_PP_BAL	2
+#define   HTS_PP_GFX	3
+#define   HTS_PCTD_DIS	(1<<9)
+#define   HTS_GTD_DIS	(1<<8)
+#define   HTS_PTL_MASK  (0x000000fe)
+#define   HTS_PTL_SHIFT 1
+#define   HTS_NVV	(1<<0)
+#define THM_HTSHI	0x54 /* 16 bits */
+#define   HTS2_PPL_MASK		(0x03ff)
+#define   HTS2_PRST_MASK	(0x3c00)
+#define   HTS2_PRST_SHIFT	10
+#define   HTS2_PRST_UNLOADED	0
+#define   HTS2_PRST_RUNNING	1
+#define   HTS2_PRST_TDISOP	2 /* turbo disabled due to power */
+#define   HTS2_PRST_TDISHT	3 /* turbo disabled due to high temp */
+#define   HTS2_PRST_TDISUSR	4 /* user disabled turbo */
+#define   HTS2_PRST_TDISPLAT	5 /* platform disabled turbo */
+#define   HTS2_PRST_TDISPM	6 /* power management disabled turbo */
+#define   HTS2_PRST_TDISERR	7 /* some kind of error disabled turbo */
+#define THM_PTL		0x56
+#define THM_MGTV	0x58
+#define   TV_MASK	0x000000000000ff00
+#define   TV_SHIFT	8
+#define THM_PTV		0x60
+#define   PTV_MASK	0x00ff
+#define THM_MMGPC	0x64
+#define THM_MPPC	0x66
+#define THM_MPCPC	0x68
+#define THM_TSPIEN	0x82
+#define   TSPIEN_AUX_LOHI	(1<<0)
+#define   TSPIEN_HOT_LOHI	(1<<1)
+#define   TSPIEN_CRIT_LOHI	(1<<2)
+#define   TSPIEN_AUX2_LOHI	(1<<3)
+#define THM_TSLOCK	0x83
+#define THM_ATR		0x84
+#define THM_TOF		0x87
+#define THM_STS		0x98
+#define   STS_PCPL_MASK		(0x7fe00000)
+#define   STS_PCPL_SHIFT	21
+#define   STS_GPL_MASK		(0x001ff000)
+#define   STS_GPL_SHIFT		12
+#define   STS_PP_MASK		(0x00000c00)
+#define   STS_PP_SHIFT		10
+#define   STS_PP_DEF		0
+#define   STS_PP_PROC		1
+#define   STS_PP_BAL		2
+#define   STS_PP_GFX		3
+#define   STS_PCTD_DIS		(1<<9)
+#define   STS_GTD_DIS		(1<<8)
+#define   STS_PTL_MASK		(0x000000fe)
+#define   STS_PTL_SHIFT		1
+#define   STS_NVV		(1<<0)
+#define THM_SEC		0x9c
+#define   SEC_ACK	(1<<0)
+#define THM_TC3		0xa4
+#define THM_TC1		0xa8
+#define   STS_PPL_MASK		(0x0003ff00)
+#define   STS_PPL_SHIFT		16
+#define THM_TC2		0xac
+#define THM_DTV		0xb0
+#define THM_ITV		0xd8
+#define   ITV_ME_SEQNO_MASK 0x000f0000 /* ME should update every ~200ms */
+#define   ITV_ME_SEQNO_SHIFT (16)
+#define   ITV_MCH_TEMP_MASK 0x0000ff00
+#define   ITV_MCH_TEMP_SHIFT (8)
+#define   ITV_PCH_TEMP_MASK 0x000000ff
+
+#define thm_readb(off) readb(ips->regmap + (off))
+#define thm_readw(off) readw(ips->regmap + (off))
+#define thm_readl(off) readl(ips->regmap + (off))
+#define thm_readq(off) readq(ips->regmap + (off))
+
+#define thm_writeb(off, val) writeb((val), ips->regmap + (off))
+#define thm_writew(off, val) writew((val), ips->regmap + (off))
+#define thm_writel(off, val) writel((val), ips->regmap + (off))
+
+static const int IPS_ADJUST_PERIOD = 5000; /* ms */
+
+/* For initial average collection */
+static const int IPS_SAMPLE_PERIOD = 200; /* ms */
+static const int IPS_SAMPLE_WINDOW = 5000; /* 5s moving window of samples */
+#define IPS_SAMPLE_COUNT (IPS_SAMPLE_WINDOW / IPS_SAMPLE_PERIOD)
+
+/* Per-SKU limits */
+struct ips_mcp_limits {
+	int cpu_family;
+	int cpu_model; /* includes extended model... */
+	int mcp_power_limit; /* mW units */
+	int core_power_limit;
+	int mch_power_limit;
+	int core_temp_limit; /* degrees C */
+	int mch_temp_limit;
+};
+
+/* Max temps are -10 degrees C to avoid PROCHOT# */
+
+struct ips_mcp_limits ips_sv_limits = {
+	.mcp_power_limit = 35000,
+	.core_power_limit = 29000,
+	.mch_power_limit = 20000,
+	.core_temp_limit = 95,
+	.mch_temp_limit = 90
+};
+
+struct ips_mcp_limits ips_lv_limits = {
+	.mcp_power_limit = 25000,
+	.core_power_limit = 21000,
+	.mch_power_limit = 13000,
+	.core_temp_limit = 95,
+	.mch_temp_limit = 90
+};
+
+struct ips_mcp_limits ips_ulv_limits = {
+	.mcp_power_limit = 18000,
+	.core_power_limit = 14000,
+	.mch_power_limit = 11000,
+	.core_temp_limit = 95,
+	.mch_temp_limit = 90
+};
+
+struct ips_driver {
+	struct pci_dev *dev;
+	void *regmap;
+	struct task_struct *monitor;
+	struct task_struct *adjust;
+	struct dentry *debug_root;
+
+	/* Average CPU core temps (all averages in .01 degrees C for precision) */
+	u16 ctv1_avg_temp;
+	u16 ctv2_avg_temp;
+	/* GMCH average */
+	u16 mch_avg_temp;
+	/* Average for the CPU (both cores?) */
+	u16 mcp_avg_temp;
+	/* Average power consumption (in mW) */
+	u32 cpu_avg_power;
+	u32 mch_avg_power;
+
+	/* Offset values */
+	u16 cta_val;
+	u16 pta_val;
+	u16 mgta_val;
+
+	/* Maximums & prefs, protected by turbo status lock */
+	spinlock_t turbo_status_lock;
+	u16 mcp_temp_limit;
+	u16 mcp_power_limit;
+	u16 core_power_limit;
+	u16 mch_power_limit;
+	bool cpu_turbo_enabled;
+	bool __cpu_turbo_on;
+	bool gpu_turbo_enabled;
+	bool __gpu_turbo_on;
+	bool gpu_preferred;
+	bool poll_turbo_status;
+	bool second_cpu;
+	struct ips_mcp_limits *limits;
+
+	/* Optional MCH interfaces for if i915 is in use */
+	unsigned long (*read_mch_val)(void);
+	bool (*gpu_raise)(void);
+	bool (*gpu_lower)(void);
+	bool (*gpu_busy)(void);
+	bool (*gpu_turbo_disable)(void);
+
+	/* For restoration at unload */
+	u64 orig_turbo_limit;
+	u64 orig_turbo_ratios;
+};
+
+/**
+ * ips_cpu_busy - is CPU busy?
+ * @ips: IPS driver struct
+ *
+ * Check CPU for load to see whether we should increase its thermal budget.
+ *
+ * RETURNS:
+ * True if the CPU could use more power, false otherwise.
+ */
+static bool ips_cpu_busy(struct ips_driver *ips)
+{
+	if ((avenrun[0] >> FSHIFT) > 1)
+		return true;
+
+	return false;
+}
+
+/**
+ * ips_cpu_raise - raise CPU power clamp
+ * @ips: IPS driver struct
+ *
+ * Raise the CPU power clamp by %IPS_CPU_STEP, in accordance with TDP for
+ * this platform.
+ *
+ * We do this by adjusting the TURBO_POWER_CURRENT_LIMIT MSR upwards (as
+ * long as we haven't hit the TDP limit for the SKU).
+ */
+static void ips_cpu_raise(struct ips_driver *ips)
+{
+	u64 turbo_override;
+	u16 cur_tdp_limit, new_tdp_limit;
+
+	if (!ips->cpu_turbo_enabled)
+		return;
+
+	rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+
+	cur_tdp_limit = turbo_override & TURBO_TDP_MASK;
+	new_tdp_limit = cur_tdp_limit + 8; /* 1W increase */
+
+	/* Clamp to SKU TDP limit */
+	if (((new_tdp_limit * 10) / 8) > ips->core_power_limit)
+		new_tdp_limit = cur_tdp_limit;
+
+	thm_writew(THM_MPCPC, (new_tdp_limit * 10) / 8);
+
+	turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN;
+	wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+
+	turbo_override &= ~TURBO_TDP_MASK;
+	turbo_override |= new_tdp_limit;
+
+	wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+}
+
+/**
+ * ips_cpu_lower - lower CPU power clamp
+ * @ips: IPS driver struct
+ *
+ * Lower CPU power clamp b %IPS_CPU_STEP if possible.
+ *
+ * We do this by adjusting the TURBO_POWER_CURRENT_LIMIT MSR down, going
+ * as low as the platform limits will allow (though we could go lower there
+ * wouldn't be much point).
+ */
+static void ips_cpu_lower(struct ips_driver *ips)
+{
+	u64 turbo_override;
+	u16 cur_limit, new_limit;
+
+	rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+
+	cur_limit = turbo_override & TURBO_TDP_MASK;
+	new_limit = cur_limit - 8; /* 1W decrease */
+
+	/* Clamp to SKU TDP limit */
+	if (((new_limit * 10) / 8) < (ips->orig_turbo_limit & TURBO_TDP_MASK))
+		new_limit = ips->orig_turbo_limit & TURBO_TDP_MASK;
+
+	thm_writew(THM_MPCPC, (new_limit * 10) / 8);
+
+	turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN;
+	wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+
+	turbo_override &= ~TURBO_TDP_MASK;
+	turbo_override |= new_limit;
+
+	wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+}
+
+/**
+ * do_enable_cpu_turbo - internal turbo enable function
+ * @data: unused
+ *
+ * Internal function for actually updating MSRs.  When we enable/disable
+ * turbo, we need to do it on each CPU; this function is the one called
+ * by on_each_cpu() when needed.
+ */
+static void do_enable_cpu_turbo(void *data)
+{
+	u64 perf_ctl;
+
+	rdmsrl(IA32_PERF_CTL, perf_ctl);
+	if (perf_ctl & IA32_PERF_TURBO_DIS) {
+		perf_ctl &= ~IA32_PERF_TURBO_DIS;
+		wrmsrl(IA32_PERF_CTL, perf_ctl);
+	}
+}
+
+/**
+ * ips_enable_cpu_turbo - enable turbo mode on all CPUs
+ * @ips: IPS driver struct
+ *
+ * Enable turbo mode by clearing the disable bit in IA32_PERF_CTL on
+ * all logical threads.
+ */
+static void ips_enable_cpu_turbo(struct ips_driver *ips)
+{
+	/* Already on, no need to mess with MSRs */
+	if (ips->__cpu_turbo_on)
+		return;
+
+	on_each_cpu(do_enable_cpu_turbo, ips, 1);
+
+	ips->__cpu_turbo_on = true;
+}
+
+/**
+ * do_disable_cpu_turbo - internal turbo disable function
+ * @data: unused
+ *
+ * Internal function for actually updating MSRs.  When we enable/disable
+ * turbo, we need to do it on each CPU; this function is the one called
+ * by on_each_cpu() when needed.
+ */
+static void do_disable_cpu_turbo(void *data)
+{
+	u64 perf_ctl;
+
+	rdmsrl(IA32_PERF_CTL, perf_ctl);
+	if (!(perf_ctl & IA32_PERF_TURBO_DIS)) {
+		perf_ctl |= IA32_PERF_TURBO_DIS;
+		wrmsrl(IA32_PERF_CTL, perf_ctl);
+	}
+}
+
+/**
+ * ips_disable_cpu_turbo - disable turbo mode on all CPUs
+ * @ips: IPS driver struct
+ *
+ * Disable turbo mode by setting the disable bit in IA32_PERF_CTL on
+ * all logical threads.
+ */
+static void ips_disable_cpu_turbo(struct ips_driver *ips)
+{
+	/* Already off, leave it */
+	if (!ips->__cpu_turbo_on)
+		return;
+
+	on_each_cpu(do_disable_cpu_turbo, ips, 1);
+
+	ips->__cpu_turbo_on = false;
+}
+
+/**
+ * ips_gpu_busy - is GPU busy?
+ * @ips: IPS driver struct
+ *
+ * Check GPU for load to see whether we should increase its thermal budget.
+ * We need to call into the i915 driver in this case.
+ *
+ * RETURNS:
+ * True if the GPU could use more power, false otherwise.
+ */
+static bool ips_gpu_busy(struct ips_driver *ips)
+{
+	if (!ips->gpu_turbo_enabled)
+		return false;
+
+	return ips->gpu_busy();
+}
+
+/**
+ * ips_gpu_raise - raise GPU power clamp
+ * @ips: IPS driver struct
+ *
+ * Raise the GPU frequency/power if possible.  We need to call into the
+ * i915 driver in this case.
+ */
+static void ips_gpu_raise(struct ips_driver *ips)
+{
+	if (!ips->gpu_turbo_enabled)
+		return;
+
+	if (!ips->gpu_raise())
+		ips->gpu_turbo_enabled = false;
+
+	return;
+}
+
+/**
+ * ips_gpu_lower - lower GPU power clamp
+ * @ips: IPS driver struct
+ *
+ * Lower GPU frequency/power if possible.  Need to call i915.
+ */
+static void ips_gpu_lower(struct ips_driver *ips)
+{
+	if (!ips->gpu_turbo_enabled)
+		return;
+
+	if (!ips->gpu_lower())
+		ips->gpu_turbo_enabled = false;
+
+	return;
+}
+
+/**
+ * ips_enable_gpu_turbo - notify the gfx driver turbo is available
+ * @ips: IPS driver struct
+ *
+ * Call into the graphics driver indicating that it can safely use
+ * turbo mode.
+ */
+static void ips_enable_gpu_turbo(struct ips_driver *ips)
+{
+	if (ips->__gpu_turbo_on)
+		return;
+	ips->__gpu_turbo_on = true;
+}
+
+/**
+ * ips_disable_gpu_turbo - notify the gfx driver to disable turbo mode
+ * @ips: IPS driver struct
+ *
+ * Request that the graphics driver disable turbo mode.
+ */
+static void ips_disable_gpu_turbo(struct ips_driver *ips)
+{
+	/* Avoid calling i915 if turbo is already disabled */
+	if (!ips->__gpu_turbo_on)
+		return;
+
+	if (!ips->gpu_turbo_disable())
+		dev_err(&ips->dev->dev, "failed to disable graphis turbo\n");
+	else
+		ips->__gpu_turbo_on = false;
+}
+
+/**
+ * mcp_exceeded - check whether we're outside our thermal & power limits
+ * @ips: IPS driver struct
+ *
+ * Check whether the MCP is over its thermal or power budget.
+ */
+static bool mcp_exceeded(struct ips_driver *ips)
+{
+	unsigned long flags;
+	bool ret = false;
+
+	spin_lock_irqsave(&ips->turbo_status_lock, flags);
+	if (ips->mcp_avg_temp > (ips->mcp_temp_limit * 100))
+		ret = true;
+	if (ips->cpu_avg_power + ips->mch_avg_power > ips->mcp_power_limit)
+		ret = true;
+	spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
+
+	if (ret)
+		dev_info(&ips->dev->dev,
+			 "MCP power or thermal limit exceeded\n");
+
+	return ret;
+}
+
+/**
+ * cpu_exceeded - check whether a CPU core is outside its limits
+ * @ips: IPS driver struct
+ * @cpu: CPU number to check
+ *
+ * Check a given CPU's average temp or power is over its limit.
+ */
+static bool cpu_exceeded(struct ips_driver *ips, int cpu)
+{
+	unsigned long flags;
+	int avg;
+	bool ret = false;
+
+	spin_lock_irqsave(&ips->turbo_status_lock, flags);
+	avg = cpu ? ips->ctv2_avg_temp : ips->ctv1_avg_temp;
+	if (avg > (ips->limits->core_temp_limit * 100))
+		ret = true;
+	if (ips->cpu_avg_power > ips->core_power_limit * 100)
+		ret = true;
+	spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
+
+	if (ret)
+		dev_info(&ips->dev->dev,
+			 "CPU power or thermal limit exceeded\n");
+
+	return ret;
+}
+
+/**
+ * mch_exceeded - check whether the GPU is over budget
+ * @ips: IPS driver struct
+ *
+ * Check the MCH temp & power against their maximums.
+ */
+static bool mch_exceeded(struct ips_driver *ips)
+{
+	unsigned long flags;
+	bool ret = false;
+
+	spin_lock_irqsave(&ips->turbo_status_lock, flags);
+	if (ips->mch_avg_temp > (ips->limits->mch_temp_limit * 100))
+		ret = true;
+	if (ips->mch_avg_power > ips->mch_power_limit)
+		ret = true;
+	spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
+
+	return ret;
+}
+
+/**
+ * update_turbo_limits - get various limits & settings from regs
+ * @ips: IPS driver struct
+ *
+ * Update the IPS power & temp limits, along with turbo enable flags,
+ * based on latest register contents.
+ *
+ * Used at init time and for runtime BIOS support, which requires polling
+ * the regs for updates (as a result of AC->DC transition for example).
+ *
+ * LOCKING:
+ * Caller must hold turbo_status_lock (outside of init)
+ */
+static void update_turbo_limits(struct ips_driver *ips)
+{
+	u32 hts = thm_readl(THM_HTS);
+
+	ips->cpu_turbo_enabled = !(hts & HTS_PCTD_DIS);
+	ips->gpu_turbo_enabled = !(hts & HTS_GTD_DIS);
+	ips->core_power_limit = thm_readw(THM_MPCPC);
+	ips->mch_power_limit = thm_readw(THM_MMGPC);
+	ips->mcp_temp_limit = thm_readw(THM_PTL);
+	ips->mcp_power_limit = thm_readw(THM_MPPC);
+
+	/* Ignore BIOS CPU vs GPU pref */
+}
+
+/**
+ * ips_adjust - adjust power clamp based on thermal state
+ * @data: ips driver structure
+ *
+ * Wake up every 5s or so and check whether we should adjust the power clamp.
+ * Check CPU and GPU load to determine which needs adjustment.  There are
+ * several things to consider here:
+ *   - do we need to adjust up or down?
+ *   - is CPU busy?
+ *   - is GPU busy?
+ *   - is CPU in turbo?
+ *   - is GPU in turbo?
+ *   - is CPU or GPU preferred? (CPU is default)
+ *
+ * So, given the above, we do the following:
+ *   - up (TDP available)
+ *     - CPU not busy, GPU not busy - nothing
+ *     - CPU busy, GPU not busy - adjust CPU up
+ *     - CPU not busy, GPU busy - adjust GPU up
+ *     - CPU busy, GPU busy - adjust preferred unit up, taking headroom from
+ *       non-preferred unit if necessary
+ *   - down (at TDP limit)
+ *     - adjust both CPU and GPU down if possible
+ *
+		cpu+ gpu+	cpu+gpu-	cpu-gpu+	cpu-gpu-
+cpu < gpu <	cpu+gpu+	cpu+		gpu+		nothing
+cpu < gpu >=	cpu+gpu-(mcp<)	cpu+gpu-(mcp<)	gpu-		gpu-
+cpu >= gpu <	cpu-gpu+(mcp<)	cpu-		cpu-gpu+(mcp<)	cpu-
+cpu >= gpu >=	cpu-gpu-	cpu-gpu-	cpu-gpu-	cpu-gpu-
+ *
+ */
+static int ips_adjust(void *data)
+{
+	struct ips_driver *ips = data;
+	unsigned long flags;
+
+	dev_dbg(&ips->dev->dev, "starting ips-adjust thread\n");
+
+	/*
+	 * Adjust CPU and GPU clamps every 5s if needed.  Doing it more
+	 * often isn't recommended due to ME interaction.
+	 */
+	do {
+		bool cpu_busy = ips_cpu_busy(ips);
+		bool gpu_busy = ips_gpu_busy(ips);
+
+		spin_lock_irqsave(&ips->turbo_status_lock, flags);
+		if (ips->poll_turbo_status)
+			update_turbo_limits(ips);
+		spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
+
+		/* Update turbo status if necessary */
+		if (ips->cpu_turbo_enabled)
+			ips_enable_cpu_turbo(ips);
+		else
+			ips_disable_cpu_turbo(ips);
+
+		if (ips->gpu_turbo_enabled)
+			ips_enable_gpu_turbo(ips);
+		else
+			ips_disable_gpu_turbo(ips);
+
+		/* We're outside our comfort zone, crank them down */
+		if (mcp_exceeded(ips)) {
+			ips_cpu_lower(ips);
+			ips_gpu_lower(ips);
+			goto sleep;
+		}
+
+		if (!cpu_exceeded(ips, 0) && cpu_busy)
+			ips_cpu_raise(ips);
+		else
+			ips_cpu_lower(ips);
+
+		if (!mch_exceeded(ips) && gpu_busy)
+			ips_gpu_raise(ips);
+		else
+			ips_gpu_lower(ips);
+
+sleep:
+		schedule_timeout_interruptible(msecs_to_jiffies(IPS_ADJUST_PERIOD));
+	} while (!kthread_should_stop());
+
+	dev_dbg(&ips->dev->dev, "ips-adjust thread stopped\n");
+
+	return 0;
+}
+
+/*
+ * Helpers for reading out temp/power values and calculating their
+ * averages for the decision making and monitoring functions.
+ */
+
+static u16 calc_avg_temp(struct ips_driver *ips, u16 *array)
+{
+	u64 total = 0;
+	int i;
+	u16 avg;
+
+	for (i = 0; i < IPS_SAMPLE_COUNT; i++)
+		total += (u64)(array[i] * 100);
+
+	do_div(total, IPS_SAMPLE_COUNT);
+
+	avg = (u16)total;
+
+	return avg;
+}
+
+static u16 read_mgtv(struct ips_driver *ips)
+{
+	u16 ret;
+	u64 slope, offset;
+	u64 val;
+
+	val = thm_readq(THM_MGTV);
+	val = (val & TV_MASK) >> TV_SHIFT;
+
+	slope = offset = thm_readw(THM_MGTA);
+	slope = (slope & MGTA_SLOPE_MASK) >> MGTA_SLOPE_SHIFT;
+	offset = offset & MGTA_OFFSET_MASK;
+
+	ret = ((val * slope + 0x40) >> 7) + offset;
+
+	return 0; /* MCH temp reporting buggy */
+}
+
+static u16 read_ptv(struct ips_driver *ips)
+{
+	u16 val, slope, offset;
+
+	slope = (ips->pta_val & PTA_SLOPE_MASK) >> PTA_SLOPE_SHIFT;
+	offset = ips->pta_val & PTA_OFFSET_MASK;
+
+	val = thm_readw(THM_PTV) & PTV_MASK;
+
+	return val;
+}
+
+static u16 read_ctv(struct ips_driver *ips, int cpu)
+{
+	int reg = cpu ? THM_CTV2 : THM_CTV1;
+	u16 val;
+
+	val = thm_readw(reg);
+	if (!(val & CTV_TEMP_ERROR))
+		val = (val) >> 6; /* discard fractional component */
+	else
+		val = 0;
+
+	return val;
+}
+
+static u32 get_cpu_power(struct ips_driver *ips, u32 *last, int period)
+{
+	u32 val;
+	u32 ret;
+
+	/*
+	 * CEC is in joules/65535.  Take difference over time to
+	 * get watts.
+	 */
+	val = thm_readl(THM_CEC);
+
+	/* period is in ms and we want mW */
+	ret = (((val - *last) * 1000) / period);
+	ret = (ret * 1000) / 65535;
+	*last = val;
+
+	return ret;
+}
+
+static const u16 temp_decay_factor = 2;
+static u16 update_average_temp(u16 avg, u16 val)
+{
+	u16 ret;
+
+	/* Multiply by 100 for extra precision */
+	ret = (val * 100 / temp_decay_factor) +
+		(((temp_decay_factor - 1) * avg) / temp_decay_factor);
+	return ret;
+}
+
+static const u16 power_decay_factor = 2;
+static u16 update_average_power(u32 avg, u32 val)
+{
+	u32 ret;
+
+	ret = (val / power_decay_factor) +
+		(((power_decay_factor - 1) * avg) / power_decay_factor);
+
+	return ret;
+}
+
+static u32 calc_avg_power(struct ips_driver *ips, u32 *array)
+{
+	u64 total = 0;
+	u32 avg;
+	int i;
+
+	for (i = 0; i < IPS_SAMPLE_COUNT; i++)
+		total += array[i];
+
+	do_div(total, IPS_SAMPLE_COUNT);
+	avg = (u32)total;
+
+	return avg;
+}
+
+static void monitor_timeout(unsigned long arg)
+{
+	wake_up_process((struct task_struct *)arg);
+}
+
+/**
+ * ips_monitor - temp/power monitoring thread
+ * @data: ips driver structure
+ *
+ * This is the main function for the IPS driver.  It monitors power and
+ * tempurature in the MCP and adjusts CPU and GPU power clams accordingly.
+ *
+ * We keep a 5s moving average of power consumption and tempurature.  Using
+ * that data, along with CPU vs GPU preference, we adjust the power clamps
+ * up or down.
+ */
+static int ips_monitor(void *data)
+{
+	struct ips_driver *ips = data;
+	struct timer_list timer;
+	unsigned long seqno_timestamp, expire, last_msecs, last_sample_period;
+	int i;
+	u32 *cpu_samples, *mchp_samples, old_cpu_power;
+	u16 *mcp_samples, *ctv1_samples, *ctv2_samples, *mch_samples;
+	u8 cur_seqno, last_seqno;
+
+	mcp_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL);
+	ctv1_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL);
+	ctv2_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL);
+	mch_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL);
+	cpu_samples = kzalloc(sizeof(u32) * IPS_SAMPLE_COUNT, GFP_KERNEL);
+	mchp_samples = kzalloc(sizeof(u32) * IPS_SAMPLE_COUNT, GFP_KERNEL);
+	if (!mcp_samples || !ctv1_samples || !ctv2_samples || !mch_samples ||
+			!cpu_samples || !mchp_samples) {
+		dev_err(&ips->dev->dev,
+			"failed to allocate sample array, ips disabled\n");
+		kfree(mcp_samples);
+		kfree(ctv1_samples);
+		kfree(ctv2_samples);
+		kfree(mch_samples);
+		kfree(cpu_samples);
+		kfree(mchp_samples);
+		kthread_stop(ips->adjust);
+		return -ENOMEM;
+	}
+
+	last_seqno = (thm_readl(THM_ITV) & ITV_ME_SEQNO_MASK) >>
+		ITV_ME_SEQNO_SHIFT;
+	seqno_timestamp = get_jiffies_64();
+
+	old_cpu_power = thm_readl(THM_CEC) / 65535;
+	schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD));
+
+	/* Collect an initial average */
+	for (i = 0; i < IPS_SAMPLE_COUNT; i++) {
+		u32 mchp, cpu_power;
+		u16 val;
+
+		mcp_samples[i] = read_ptv(ips);
+
+		val = read_ctv(ips, 0);
+		ctv1_samples[i] = val;
+
+		val = read_ctv(ips, 1);
+		ctv2_samples[i] = val;
+
+		val = read_mgtv(ips);
+		mch_samples[i] = val;
+
+		cpu_power = get_cpu_power(ips, &old_cpu_power,
+					  IPS_SAMPLE_PERIOD);
+		cpu_samples[i] = cpu_power;
+
+		if (ips->read_mch_val) {
+			mchp = ips->read_mch_val();
+			mchp_samples[i] = mchp;
+		}
+
+		schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD));
+		if (kthread_should_stop())
+			break;
+	}
+
+	ips->mcp_avg_temp = calc_avg_temp(ips, mcp_samples);
+	ips->ctv1_avg_temp = calc_avg_temp(ips, ctv1_samples);
+	ips->ctv2_avg_temp = calc_avg_temp(ips, ctv2_samples);
+	ips->mch_avg_temp = calc_avg_temp(ips, mch_samples);
+	ips->cpu_avg_power = calc_avg_power(ips, cpu_samples);
+	ips->mch_avg_power = calc_avg_power(ips, mchp_samples);
+	kfree(mcp_samples);
+	kfree(ctv1_samples);
+	kfree(ctv2_samples);
+	kfree(mch_samples);
+	kfree(cpu_samples);
+	kfree(mchp_samples);
+
+	/* Start the adjustment thread now that we have data */
+	wake_up_process(ips->adjust);
+
+	/*
+	 * Ok, now we have an initial avg.  From here on out, we track the
+	 * running avg using a decaying average calculation.  This allows
+	 * us to reduce the sample frequency if the CPU and GPU are idle.
+	 */
+	old_cpu_power = thm_readl(THM_CEC);
+	schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD));
+	last_sample_period = IPS_SAMPLE_PERIOD;
+
+	setup_deferrable_timer_on_stack(&timer, monitor_timeout,
+					(unsigned long)current);
+	do {
+		u32 cpu_val, mch_val;
+		u16 val;
+
+		/* MCP itself */
+		val = read_ptv(ips);
+		ips->mcp_avg_temp = update_average_temp(ips->mcp_avg_temp, val);
+
+		/* Processor 0 */
+		val = read_ctv(ips, 0);
+		ips->ctv1_avg_temp =
+			update_average_temp(ips->ctv1_avg_temp, val);
+		/* Power */
+		cpu_val = get_cpu_power(ips, &old_cpu_power,
+					last_sample_period);
+		ips->cpu_avg_power =
+			update_average_power(ips->cpu_avg_power, cpu_val);
+
+		if (ips->second_cpu) {
+			/* Processor 1 */
+			val = read_ctv(ips, 1);
+			ips->ctv2_avg_temp =
+				update_average_temp(ips->ctv2_avg_temp, val);
+		}
+
+		/* MCH */
+		val = read_mgtv(ips);
+		ips->mch_avg_temp = update_average_temp(ips->mch_avg_temp, val);
+		/* Power */
+		if (ips->read_mch_val) {
+			mch_val = ips->read_mch_val();
+			ips->mch_avg_power =
+				update_average_power(ips->mch_avg_power,
+						     mch_val);
+		}
+
+		/*
+		 * Make sure ME is updating thermal regs.
+		 * Note:
+		 * If it's been more than a second since the last update,
+		 * the ME is probably hung.
+		 */
+		cur_seqno = (thm_readl(THM_ITV) & ITV_ME_SEQNO_MASK) >>
+			ITV_ME_SEQNO_SHIFT;
+		if (cur_seqno == last_seqno &&
+		    time_after(jiffies, seqno_timestamp + HZ)) {
+			dev_warn(&ips->dev->dev, "ME failed to update for more than 1s, likely hung\n");
+		} else {
+			seqno_timestamp = get_jiffies_64();
+			last_seqno = cur_seqno;
+		}
+
+		last_msecs = jiffies_to_msecs(jiffies);
+		expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD);
+
+		__set_current_state(TASK_UNINTERRUPTIBLE);
+		mod_timer(&timer, expire);
+		schedule();
+
+		/* Calculate actual sample period for power averaging */
+		last_sample_period = jiffies_to_msecs(jiffies) - last_msecs;
+		if (!last_sample_period)
+			last_sample_period = 1;
+	} while (!kthread_should_stop());
+
+	del_timer_sync(&timer);
+	destroy_timer_on_stack(&timer);
+
+	dev_dbg(&ips->dev->dev, "ips-monitor thread stopped\n");
+
+	return 0;
+}
+
+#if 0
+#define THM_DUMPW(reg) \
+	{ \
+	u16 val = thm_readw(reg); \
+	dev_dbg(&ips->dev->dev, #reg ": 0x%04x\n", val); \
+	}
+#define THM_DUMPL(reg) \
+	{ \
+	u32 val = thm_readl(reg); \
+	dev_dbg(&ips->dev->dev, #reg ": 0x%08x\n", val); \
+	}
+#define THM_DUMPQ(reg) \
+	{ \
+	u64 val = thm_readq(reg); \
+	dev_dbg(&ips->dev->dev, #reg ": 0x%016x\n", val); \
+	}
+
+static void dump_thermal_info(struct ips_driver *ips)
+{
+	u16 ptl;
+
+	ptl = thm_readw(THM_PTL);
+	dev_dbg(&ips->dev->dev, "Processor temp limit: %d\n", ptl);
+
+	THM_DUMPW(THM_CTA);
+	THM_DUMPW(THM_TRC);
+	THM_DUMPW(THM_CTV1);
+	THM_DUMPL(THM_STS);
+	THM_DUMPW(THM_PTV);
+	THM_DUMPQ(THM_MGTV);
+}
+#endif
+
+/**
+ * ips_irq_handler - handle temperature triggers and other IPS events
+ * @irq: irq number
+ * @arg: unused
+ *
+ * Handle temperature limit trigger events, generally by lowering the clamps.
+ * If we're at a critical limit, we clamp back to the lowest possible value
+ * to prevent emergency shutdown.
+ */
+static irqreturn_t ips_irq_handler(int irq, void *arg)
+{
+	struct ips_driver *ips = arg;
+	u8 tses = thm_readb(THM_TSES);
+	u8 tes = thm_readb(THM_TES);
+
+	if (!tses && !tes)
+		return IRQ_NONE;
+
+	dev_info(&ips->dev->dev, "TSES: 0x%02x\n", tses);
+	dev_info(&ips->dev->dev, "TES: 0x%02x\n", tes);
+
+	/* STS update from EC? */
+	if (tes & 1) {
+		u32 sts, tc1;
+
+		sts = thm_readl(THM_STS);
+		tc1 = thm_readl(THM_TC1);
+
+		if (sts & STS_NVV) {
+			spin_lock(&ips->turbo_status_lock);
+			ips->core_power_limit = (sts & STS_PCPL_MASK) >>
+				STS_PCPL_SHIFT;
+			ips->mch_power_limit = (sts & STS_GPL_MASK) >>
+				STS_GPL_SHIFT;
+			/* ignore EC CPU vs GPU pref */
+			ips->cpu_turbo_enabled = !(sts & STS_PCTD_DIS);
+			ips->gpu_turbo_enabled = !(sts & STS_GTD_DIS);
+			ips->mcp_temp_limit = (sts & STS_PTL_MASK) >>
+				STS_PTL_SHIFT;
+			ips->mcp_power_limit = (tc1 & STS_PPL_MASK) >>
+				STS_PPL_SHIFT;
+			spin_unlock(&ips->turbo_status_lock);
+
+			thm_writeb(THM_SEC, SEC_ACK);
+		}
+		thm_writeb(THM_TES, tes);
+	}
+
+	/* Thermal trip */
+	if (tses) {
+		dev_warn(&ips->dev->dev,
+			 "thermal trip occurred, tses: 0x%04x\n", tses);
+		thm_writeb(THM_TSES, tses);
+	}
+
+	return IRQ_HANDLED;
+}
+
+#ifndef CONFIG_DEBUG_FS
+static void ips_debugfs_init(struct ips_driver *ips) { return; }
+static void ips_debugfs_cleanup(struct ips_driver *ips) { return; }
+#else
+
+/* Expose current state and limits in debugfs if possible */
+
+struct ips_debugfs_node {
+	struct ips_driver *ips;
+	char *name;
+	int (*show)(struct seq_file *m, void *data);
+};
+
+static int show_cpu_temp(struct seq_file *m, void *data)
+{
+	struct ips_driver *ips = m->private;
+
+	seq_printf(m, "%d.%02d\n", ips->ctv1_avg_temp / 100,
+		   ips->ctv1_avg_temp % 100);
+
+	return 0;
+}
+
+static int show_cpu_power(struct seq_file *m, void *data)
+{
+	struct ips_driver *ips = m->private;
+
+	seq_printf(m, "%dmW\n", ips->cpu_avg_power);
+
+	return 0;
+}
+
+static int show_cpu_clamp(struct seq_file *m, void *data)
+{
+	u64 turbo_override;
+	int tdp, tdc;
+
+	rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+
+	tdp = (int)(turbo_override & TURBO_TDP_MASK);
+	tdc = (int)((turbo_override & TURBO_TDC_MASK) >> TURBO_TDC_SHIFT);
+
+	/* Convert to .1W/A units */
+	tdp = tdp * 10 / 8;
+	tdc = tdc * 10 / 8;
+
+	/* Watts Amperes */
+	seq_printf(m, "%d.%dW %d.%dA\n", tdp / 10, tdp % 10,
+		   tdc / 10, tdc % 10);
+
+	return 0;
+}
+
+static int show_mch_temp(struct seq_file *m, void *data)
+{
+	struct ips_driver *ips = m->private;
+
+	seq_printf(m, "%d.%02d\n", ips->mch_avg_temp / 100,
+		   ips->mch_avg_temp % 100);
+
+	return 0;
+}
+
+static int show_mch_power(struct seq_file *m, void *data)
+{
+	struct ips_driver *ips = m->private;
+
+	seq_printf(m, "%dmW\n", ips->mch_avg_power);
+
+	return 0;
+}
+
+static struct ips_debugfs_node ips_debug_files[] = {
+	{ NULL, "cpu_temp", show_cpu_temp },
+	{ NULL, "cpu_power", show_cpu_power },
+	{ NULL, "cpu_clamp", show_cpu_clamp },
+	{ NULL, "mch_temp", show_mch_temp },
+	{ NULL, "mch_power", show_mch_power },
+};
+
+static int ips_debugfs_open(struct inode *inode, struct file *file)
+{
+	struct ips_debugfs_node *node = inode->i_private;
+
+	return single_open(file, node->show, node->ips);
+}
+
+static const struct file_operations ips_debugfs_ops = {
+	.owner = THIS_MODULE,
+	.open = ips_debugfs_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static void ips_debugfs_cleanup(struct ips_driver *ips)
+{
+	if (ips->debug_root)
+		debugfs_remove_recursive(ips->debug_root);
+	return;
+}
+
+static void ips_debugfs_init(struct ips_driver *ips)
+{
+	int i;
+
+	ips->debug_root = debugfs_create_dir("ips", NULL);
+	if (!ips->debug_root) {
+		dev_err(&ips->dev->dev,
+			"failed to create debugfs entries: %ld\n",
+			PTR_ERR(ips->debug_root));
+		return;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(ips_debug_files); i++) {
+		struct dentry *ent;
+		struct ips_debugfs_node *node = &ips_debug_files[i];
+
+		node->ips = ips;
+		ent = debugfs_create_file(node->name, S_IFREG | S_IRUGO,
+					  ips->debug_root, node,
+					  &ips_debugfs_ops);
+		if (!ent) {
+			dev_err(&ips->dev->dev,
+				"failed to create debug file: %ld\n",
+				PTR_ERR(ent));
+			goto err_cleanup;
+		}
+	}
+
+	return;
+
+err_cleanup:
+	ips_debugfs_cleanup(ips);
+	return;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+/**
+ * ips_detect_cpu - detect whether CPU supports IPS
+ *
+ * Walk our list and see if we're on a supported CPU.  If we find one,
+ * return the limits for it.
+ */
+static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips)
+{
+	u64 turbo_power, misc_en;
+	struct ips_mcp_limits *limits = NULL;
+	u16 tdp;
+
+	if (!(boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 37)) {
+		dev_info(&ips->dev->dev, "Non-IPS CPU detected.\n");
+		goto out;
+	}
+
+	rdmsrl(IA32_MISC_ENABLE, misc_en);
+	/*
+	 * If the turbo enable bit isn't set, we shouldn't try to enable/disable
+	 * turbo manually or we'll get an illegal MSR access, even though
+	 * turbo will still be available.
+	 */
+	if (!(misc_en & IA32_MISC_TURBO_EN))
+		; /* add turbo MSR write allowed flag if necessary */
+
+	if (strstr(boot_cpu_data.x86_model_id, "CPU       M"))
+		limits = &ips_sv_limits;
+	else if (strstr(boot_cpu_data.x86_model_id, "CPU       L"))
+		limits = &ips_lv_limits;
+	else if (strstr(boot_cpu_data.x86_model_id, "CPU       U"))
+		limits = &ips_ulv_limits;
+	else
+		dev_info(&ips->dev->dev, "No CPUID match found.\n");
+
+	rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_power);
+	tdp = turbo_power & TURBO_TDP_MASK;
+
+	/* Sanity check TDP against CPU */
+	if (limits->mcp_power_limit != (tdp / 8) * 1000) {
+		dev_warn(&ips->dev->dev, "Warning: CPU TDP doesn't match expected value (found %d, expected %d)\n",
+			 tdp / 8, limits->mcp_power_limit / 1000);
+	}
+
+out:
+	return limits;
+}
+
+/**
+ * ips_get_i915_syms - try to get GPU control methods from i915 driver
+ * @ips: IPS driver
+ *
+ * The i915 driver exports several interfaces to allow the IPS driver to
+ * monitor and control graphics turbo mode.  If we can find them, we can
+ * enable graphics turbo, otherwise we must disable it to avoid exceeding
+ * thermal and power limits in the MCP.
+ */
+static bool ips_get_i915_syms(struct ips_driver *ips)
+{
+	ips->read_mch_val = symbol_get(i915_read_mch_val);
+	if (!ips->read_mch_val)
+		goto out_err;
+	ips->gpu_raise = symbol_get(i915_gpu_raise);
+	if (!ips->gpu_raise)
+		goto out_put_mch;
+	ips->gpu_lower = symbol_get(i915_gpu_lower);
+	if (!ips->gpu_lower)
+		goto out_put_raise;
+	ips->gpu_busy = symbol_get(i915_gpu_busy);
+	if (!ips->gpu_busy)
+		goto out_put_lower;
+	ips->gpu_turbo_disable = symbol_get(i915_gpu_turbo_disable);
+	if (!ips->gpu_turbo_disable)
+		goto out_put_busy;
+
+	return true;
+
+out_put_busy:
+	symbol_put(i915_gpu_turbo_disable);
+out_put_lower:
+	symbol_put(i915_gpu_lower);
+out_put_raise:
+	symbol_put(i915_gpu_raise);
+out_put_mch:
+	symbol_put(i915_read_mch_val);
+out_err:
+	return false;
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ips_id_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
+		     PCI_DEVICE_ID_INTEL_THERMAL_SENSOR), },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, ips_id_table);
+
+static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	u64 platform_info;
+	struct ips_driver *ips;
+	u32 hts;
+	int ret = 0;
+	u16 htshi, trc, trc_required_mask;
+	u8 tse;
+
+	ips = kzalloc(sizeof(struct ips_driver), GFP_KERNEL);
+	if (!ips)
+		return -ENOMEM;
+
+	pci_set_drvdata(dev, ips);
+	ips->dev = dev;
+
+	ips->limits = ips_detect_cpu(ips);
+	if (!ips->limits) {
+		dev_info(&dev->dev, "IPS not supported on this CPU\n");
+		ret = -ENXIO;
+		goto error_free;
+	}
+
+	spin_lock_init(&ips->turbo_status_lock);
+
+	if (!pci_resource_start(dev, 0)) {
+		dev_err(&dev->dev, "TBAR not assigned, aborting\n");
+		ret = -ENXIO;
+		goto error_free;
+	}
+
+	ret = pci_request_regions(dev, "ips thermal sensor");
+	if (ret) {
+		dev_err(&dev->dev, "thermal resource busy, aborting\n");
+		goto error_free;
+	}
+
+	ret = pci_enable_device(dev);
+	if (ret) {
+		dev_err(&dev->dev, "can't enable PCI device, aborting\n");
+		goto error_free;
+	}
+
+	ips->regmap = ioremap(pci_resource_start(dev, 0),
+			      pci_resource_len(dev, 0));
+	if (!ips->regmap) {
+		dev_err(&dev->dev, "failed to map thermal regs, aborting\n");
+		ret = -EBUSY;
+		goto error_release;
+	}
+
+	tse = thm_readb(THM_TSE);
+	if (tse != TSE_EN) {
+		dev_err(&dev->dev, "thermal device not enabled (0x%02x), aborting\n", tse);
+		ret = -ENXIO;
+		goto error_unmap;
+	}
+
+	trc = thm_readw(THM_TRC);
+	trc_required_mask = TRC_CORE1_EN | TRC_CORE_PWR | TRC_MCH_EN;
+	if ((trc & trc_required_mask) != trc_required_mask) {
+		dev_err(&dev->dev, "thermal reporting for required devices not enabled, aborting\n");
+		ret = -ENXIO;
+		goto error_unmap;
+	}
+
+	if (trc & TRC_CORE2_EN)
+		ips->second_cpu = true;
+
+	update_turbo_limits(ips);
+	dev_dbg(&dev->dev, "max cpu power clamp: %dW\n",
+		ips->mcp_power_limit / 10);
+	dev_dbg(&dev->dev, "max core power clamp: %dW\n",
+		ips->core_power_limit / 10);
+	/* BIOS may update limits at runtime */
+	if (thm_readl(THM_PSC) & PSP_PBRT)
+		ips->poll_turbo_status = true;
+
+	if (!ips_get_i915_syms(ips)) {
+		dev_err(&dev->dev, "failed to get i915 symbols, graphics turbo disabled\n");
+		ips->gpu_turbo_enabled = false;
+	} else {
+		dev_dbg(&dev->dev, "graphics turbo enabled\n");
+		ips->gpu_turbo_enabled = true;
+	}
+
+	/*
+	 * Check PLATFORM_INFO MSR to make sure this chip is
+	 * turbo capable.
+	 */
+	rdmsrl(PLATFORM_INFO, platform_info);
+	if (!(platform_info & PLATFORM_TDP)) {
+		dev_err(&dev->dev, "platform indicates TDP override unavailable, aborting\n");
+		ret = -ENODEV;
+		goto error_unmap;
+	}
+
+	/*
+	 * IRQ handler for ME interaction
+	 * Note: don't use MSI here as the PCH has bugs.
+	 */
+	pci_disable_msi(dev);
+	ret = request_irq(dev->irq, ips_irq_handler, IRQF_SHARED, "ips",
+			  ips);
+	if (ret) {
+		dev_err(&dev->dev, "request irq failed, aborting\n");
+		goto error_unmap;
+	}
+
+	/* Enable aux, hot & critical interrupts */
+	thm_writeb(THM_TSPIEN, TSPIEN_AUX2_LOHI | TSPIEN_CRIT_LOHI |
+		   TSPIEN_HOT_LOHI | TSPIEN_AUX_LOHI);
+	thm_writeb(THM_TEN, TEN_UPDATE_EN);
+
+	/* Collect adjustment values */
+	ips->cta_val = thm_readw(THM_CTA);
+	ips->pta_val = thm_readw(THM_PTA);
+	ips->mgta_val = thm_readw(THM_MGTA);
+
+	/* Save turbo limits & ratios */
+	rdmsrl(TURBO_POWER_CURRENT_LIMIT, ips->orig_turbo_limit);
+
+	ips_enable_cpu_turbo(ips);
+	ips->cpu_turbo_enabled = true;
+
+	/* Set up the work queue and monitor/adjust threads */
+	ips->monitor = kthread_run(ips_monitor, ips, "ips-monitor");
+	if (IS_ERR(ips->monitor)) {
+		dev_err(&dev->dev,
+			"failed to create thermal monitor thread, aborting\n");
+		ret = -ENOMEM;
+		goto error_free_irq;
+	}
+
+	ips->adjust = kthread_create(ips_adjust, ips, "ips-adjust");
+	if (IS_ERR(ips->adjust)) {
+		dev_err(&dev->dev,
+			"failed to create thermal adjust thread, aborting\n");
+		ret = -ENOMEM;
+		goto error_thread_cleanup;
+	}
+
+	hts = (ips->core_power_limit << HTS_PCPL_SHIFT) |
+		(ips->mcp_temp_limit << HTS_PTL_SHIFT) | HTS_NVV;
+	htshi = HTS2_PRST_RUNNING << HTS2_PRST_SHIFT;
+
+	thm_writew(THM_HTSHI, htshi);
+	thm_writel(THM_HTS, hts);
+
+	ips_debugfs_init(ips);
+
+	dev_info(&dev->dev, "IPS driver initialized, MCP temp limit %d\n",
+		 ips->mcp_temp_limit);
+	return ret;
+
+error_thread_cleanup:
+	kthread_stop(ips->monitor);
+error_free_irq:
+	free_irq(ips->dev->irq, ips);
+error_unmap:
+	iounmap(ips->regmap);
+error_release:
+	pci_release_regions(dev);
+error_free:
+	kfree(ips);
+	return ret;
+}
+
+static void ips_remove(struct pci_dev *dev)
+{
+	struct ips_driver *ips = pci_get_drvdata(dev);
+	u64 turbo_override;
+
+	if (!ips)
+		return;
+
+	ips_debugfs_cleanup(ips);
+
+	/* Release i915 driver */
+	if (ips->read_mch_val)
+		symbol_put(i915_read_mch_val);
+	if (ips->gpu_raise)
+		symbol_put(i915_gpu_raise);
+	if (ips->gpu_lower)
+		symbol_put(i915_gpu_lower);
+	if (ips->gpu_busy)
+		symbol_put(i915_gpu_busy);
+	if (ips->gpu_turbo_disable)
+		symbol_put(i915_gpu_turbo_disable);
+
+	rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+	turbo_override &= ~(TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN);
+	wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+	wrmsrl(TURBO_POWER_CURRENT_LIMIT, ips->orig_turbo_limit);
+
+	free_irq(ips->dev->irq, ips);
+	if (ips->adjust)
+		kthread_stop(ips->adjust);
+	if (ips->monitor)
+		kthread_stop(ips->monitor);
+	iounmap(ips->regmap);
+	pci_release_regions(dev);
+	kfree(ips);
+	dev_dbg(&dev->dev, "IPS driver removed\n");
+}
+
+#ifdef CONFIG_PM
+static int ips_suspend(struct pci_dev *dev, pm_message_t state)
+{
+	return 0;
+}
+
+static int ips_resume(struct pci_dev *dev)
+{
+	return 0;
+}
+#else
+#define ips_suspend NULL
+#define ips_resume NULL
+#endif /* CONFIG_PM */
+
+static void ips_shutdown(struct pci_dev *dev)
+{
+}
+
+static struct pci_driver ips_pci_driver = {
+	.name = "intel ips",
+	.id_table = ips_id_table,
+	.probe = ips_probe,
+	.remove = ips_remove,
+	.suspend = ips_suspend,
+	.resume = ips_resume,
+	.shutdown = ips_shutdown,
+};
+
+static int __init ips_init(void)
+{
+	return pci_register_driver(&ips_pci_driver);
+}
+module_init(ips_init);
+
+static void ips_exit(void)
+{
+	pci_unregister_driver(&ips_pci_driver);
+	return;
+}
+module_exit(ips_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jesse Barnes <jbarnes@virtuousgeek.org>");
+MODULE_DESCRIPTION("Intelligent Power Sharing Driver");
diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c
index 2f795ce..eacd5da 100644
--- a/drivers/platform/x86/intel_menlow.c
+++ b/drivers/platform/x86/intel_menlow.c
@@ -53,6 +53,8 @@
 #define MEMORY_ARG_CUR_BANDWIDTH 1
 #define MEMORY_ARG_MAX_BANDWIDTH 0
 
+static void intel_menlow_unregister_sensor(void);
+
 /*
  * GTHS returning 'n' would mean that [0,n-1] states are supported
  * In that case max_cstate would be n-1
@@ -406,8 +408,10 @@
 	attr->handle = handle;
 
 	result = device_create_file(dev, &attr->attr);
-	if (result)
+	if (result) {
+		kfree(attr);
 		return result;
+	}
 
 	mutex_lock(&intel_menlow_attr_lock);
 	list_add_tail(&attr->node, &intel_menlow_attr_list);
@@ -431,11 +435,11 @@
 	/* _TZ must have the AUX0/1 methods */
 	status = acpi_get_handle(handle, GET_AUX0, &dummy);
 	if (ACPI_FAILURE(status))
-		goto not_found;
+		return (status == AE_NOT_FOUND) ? AE_OK : status;
 
 	status = acpi_get_handle(handle, SET_AUX0, &dummy);
 	if (ACPI_FAILURE(status))
-		goto not_found;
+		return (status == AE_NOT_FOUND) ? AE_OK : status;
 
 	result = intel_menlow_add_one_attribute("aux0", 0644,
 						aux0_show, aux0_store,
@@ -445,17 +449,19 @@
 
 	status = acpi_get_handle(handle, GET_AUX1, &dummy);
 	if (ACPI_FAILURE(status))
-		goto not_found;
+		goto aux1_not_found;
 
 	status = acpi_get_handle(handle, SET_AUX1, &dummy);
 	if (ACPI_FAILURE(status))
-		goto not_found;
+		goto aux1_not_found;
 
 	result = intel_menlow_add_one_attribute("aux1", 0644,
 						aux1_show, aux1_store,
 						&thermal->device, handle);
-	if (result)
+	if (result) {
+		intel_menlow_unregister_sensor();
 		return AE_ERROR;
+	}
 
 	/*
 	 * create the "dabney_enabled" attribute which means the user app
@@ -465,14 +471,17 @@
 	result = intel_menlow_add_one_attribute("bios_enabled", 0444,
 						bios_enabled_show, NULL,
 						&thermal->device, handle);
-	if (result)
+	if (result) {
+		intel_menlow_unregister_sensor();
 		return AE_ERROR;
+	}
 
- not_found:
+ aux1_not_found:
 	if (status == AE_NOT_FOUND)
 		return AE_OK;
-	else
-		return status;
+
+	intel_menlow_unregister_sensor();
+	return status;
 }
 
 static void intel_menlow_unregister_sensor(void)
@@ -513,8 +522,10 @@
 	status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT,
 				     ACPI_UINT32_MAX,
 				     intel_menlow_register_sensor, NULL, NULL, NULL);
-	if (ACPI_FAILURE(status))
+	if (ACPI_FAILURE(status)) {
+		acpi_bus_unregister_driver(&intel_menlow_memory_driver);
 		return -ENODEV;
+	}
 
 	return 0;
 }
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c
new file mode 100644
index 0000000..5cdcff6
--- /dev/null
+++ b/drivers/platform/x86/intel_pmic_gpio.c
@@ -0,0 +1,340 @@
+/* Moorestown PMIC GPIO (access through IPC) driver
+ * Copyright (c) 2008 - 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Supports:
+ * Moorestown platform PMIC chip
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <asm/intel_scu_ipc.h>
+#include <linux/device.h>
+#include <linux/intel_pmic_gpio.h>
+#include <linux/platform_device.h>
+
+#define DRIVER_NAME "pmic_gpio"
+
+/* register offset that IPC driver should use
+ * 8 GPIO + 8 GPOSW (6 controllable) + 8GPO
+ */
+enum pmic_gpio_register {
+	GPIO0		= 0xE0,
+	GPIO7		= 0xE7,
+	GPIOINT		= 0xE8,
+	GPOSWCTL0	= 0xEC,
+	GPOSWCTL5	= 0xF1,
+	GPO		= 0xF4,
+};
+
+/* bits definition for GPIO & GPOSW */
+#define GPIO_DRV 0x01
+#define GPIO_DIR 0x02
+#define GPIO_DIN 0x04
+#define GPIO_DOU 0x08
+#define GPIO_INTCTL 0x30
+#define GPIO_DBC 0xc0
+
+#define GPOSW_DRV 0x01
+#define GPOSW_DOU 0x08
+#define GPOSW_RDRV 0x30
+
+
+#define NUM_GPIO 24
+
+struct pmic_gpio_irq {
+	spinlock_t lock;
+	u32 trigger[NUM_GPIO];
+	u32 dirty;
+	struct work_struct work;
+};
+
+
+struct pmic_gpio {
+	struct gpio_chip	chip;
+	struct pmic_gpio_irq	irqtypes;
+	void			*gpiointr;
+	int			irq;
+	unsigned		irq_base;
+};
+
+static void pmic_program_irqtype(int gpio, int type)
+{
+	if (type & IRQ_TYPE_EDGE_RISING)
+		intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20);
+	else
+		intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20);
+
+	if (type & IRQ_TYPE_EDGE_FALLING)
+		intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10);
+	else
+		intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10);
+};
+
+static void pmic_irqtype_work(struct work_struct *work)
+{
+	struct pmic_gpio_irq *t =
+		container_of(work, struct pmic_gpio_irq, work);
+	unsigned long flags;
+	int i;
+	u16 type;
+
+	spin_lock_irqsave(&t->lock, flags);
+	/* As we drop the lock, we may need multiple scans if we race the
+	   pmic_irq_type function */
+	while (t->dirty) {
+		/*
+		 *	For each pin that has the dirty bit set send an IPC
+		 *	message to configure the hardware via the PMIC
+		 */
+		for (i = 0; i < NUM_GPIO; i++) {
+			if (!(t->dirty & (1 << i)))
+				continue;
+			t->dirty &= ~(1 << i);
+			/* We can't trust the array entry or dirty
+			   once the lock is dropped */
+			type = t->trigger[i];
+			spin_unlock_irqrestore(&t->lock, flags);
+			pmic_program_irqtype(i, type);
+			spin_lock_irqsave(&t->lock, flags);
+		}
+	}
+	spin_unlock_irqrestore(&t->lock, flags);
+}
+
+static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	if (offset > 8) {
+		printk(KERN_ERR
+			"%s: only pin 0-7 support input\n", __func__);
+		return -1;/* we only have 8 GPIO can use as input */
+	}
+	return intel_scu_ipc_update_register(GPIO0 + offset,
+							GPIO_DIR, GPIO_DIR);
+}
+
+static int pmic_gpio_direction_output(struct gpio_chip *chip,
+			unsigned offset, int value)
+{
+	int rc = 0;
+
+	if (offset < 8)/* it is GPIO */
+		rc = intel_scu_ipc_update_register(GPIO0 + offset,
+				GPIO_DRV | GPIO_DOU | GPIO_DIR,
+				GPIO_DRV | (value ? GPIO_DOU : 0));
+	else if (offset < 16)/* it is GPOSW */
+		rc = intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8,
+				GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV,
+				GPOSW_DRV | (value ? GPOSW_DOU : 0));
+	else if (offset > 15 && offset < 24)/* it is GPO */
+		rc = intel_scu_ipc_update_register(GPO,
+				1 << (offset - 16),
+				value ? 1 << (offset - 16) : 0);
+	else {
+		printk(KERN_ERR
+			"%s: invalid PMIC GPIO pin %d!\n", __func__, offset);
+		WARN_ON(1);
+	}
+
+	return rc;
+}
+
+static int pmic_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	u8 r;
+	int ret;
+
+	/* we only have 8 GPIO pins we can use as input */
+	if (offset > 8)
+		return -EOPNOTSUPP;
+	ret = intel_scu_ipc_ioread8(GPIO0 + offset, &r);
+	if (ret < 0)
+		return ret;
+	return r & GPIO_DIN;
+}
+
+static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	if (offset < 8)/* it is GPIO */
+		intel_scu_ipc_update_register(GPIO0 + offset,
+			GPIO_DRV | GPIO_DOU,
+			GPIO_DRV | (value ? GPIO_DOU : 0));
+	else if (offset < 16)/* it is GPOSW */
+		intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8,
+			GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV,
+			GPOSW_DRV | (value ? GPOSW_DOU : 0));
+	else if (offset > 15 && offset < 24) /* it is GPO */
+		intel_scu_ipc_update_register(GPO,
+			1 << (offset - 16),
+			value ? 1 << (offset - 16) : 0);
+}
+
+static int pmic_irq_type(unsigned irq, unsigned type)
+{
+	struct pmic_gpio *pg = get_irq_chip_data(irq);
+	u32 gpio = irq - pg->irq_base;
+	unsigned long flags;
+
+	if (gpio > pg->chip.ngpio)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pg->irqtypes.lock, flags);
+	pg->irqtypes.trigger[gpio] = type;
+	pg->irqtypes.dirty |=  (1 << gpio);
+	spin_unlock_irqrestore(&pg->irqtypes.lock, flags);
+	schedule_work(&pg->irqtypes.work);
+	return 0;
+}
+
+
+
+static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct pmic_gpio *pg = container_of(chip, struct pmic_gpio, chip);
+
+	return pg->irq_base + offset;
+}
+
+/* the gpiointr register is read-clear, so just do nothing. */
+static void pmic_irq_unmask(unsigned irq)
+{
+};
+
+static void pmic_irq_mask(unsigned irq)
+{
+};
+
+static struct irq_chip pmic_irqchip = {
+	.name		= "PMIC-GPIO",
+	.mask		= pmic_irq_mask,
+	.unmask		= pmic_irq_unmask,
+	.set_type	= pmic_irq_type,
+};
+
+static void pmic_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+	struct pmic_gpio *pg = (struct pmic_gpio *)get_irq_data(irq);
+	u8 intsts = *((u8 *)pg->gpiointr + 4);
+	int gpio;
+
+	for (gpio = 0; gpio < 8; gpio++) {
+		if (intsts & (1 << gpio)) {
+			pr_debug("pmic pin %d triggered\n", gpio);
+			generic_handle_irq(pg->irq_base + gpio);
+		}
+	}
+	desc->chip->eoi(irq);
+}
+
+static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	int irq = platform_get_irq(pdev, 0);
+	struct intel_pmic_gpio_platform_data *pdata = dev->platform_data;
+
+	struct pmic_gpio *pg;
+	int retval;
+	int i;
+
+	if (irq < 0) {
+		dev_dbg(dev, "no IRQ line\n");
+		return -EINVAL;
+	}
+
+	if (!pdata || !pdata->gpio_base || !pdata->irq_base) {
+		dev_dbg(dev, "incorrect or missing platform data\n");
+		return -EINVAL;
+	}
+
+	pg = kzalloc(sizeof(*pg), GFP_KERNEL);
+	if (!pg)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, pg);
+
+	pg->irq = irq;
+	/* setting up SRAM mapping for GPIOINT register */
+	pg->gpiointr = ioremap_nocache(pdata->gpiointr, 8);
+	if (!pg->gpiointr) {
+		printk(KERN_ERR "%s: Can not map GPIOINT.\n", __func__);
+		retval = -EINVAL;
+		goto err2;
+	}
+	pg->irq_base = pdata->irq_base;
+	pg->chip.label = "intel_pmic";
+	pg->chip.direction_input = pmic_gpio_direction_input;
+	pg->chip.direction_output = pmic_gpio_direction_output;
+	pg->chip.get = pmic_gpio_get;
+	pg->chip.set = pmic_gpio_set;
+	pg->chip.to_irq = pmic_gpio_to_irq;
+	pg->chip.base = pdata->gpio_base;
+	pg->chip.ngpio = NUM_GPIO;
+	pg->chip.can_sleep = 1;
+	pg->chip.dev = dev;
+
+	INIT_WORK(&pg->irqtypes.work, pmic_irqtype_work);
+	spin_lock_init(&pg->irqtypes.lock);
+
+	pg->chip.dev = dev;
+	retval = gpiochip_add(&pg->chip);
+	if (retval) {
+		printk(KERN_ERR "%s: Can not add pmic gpio chip.\n", __func__);
+		goto err;
+	}
+	set_irq_data(pg->irq, pg);
+	set_irq_chained_handler(pg->irq, pmic_irq_handler);
+	for (i = 0; i < 8; i++) {
+		set_irq_chip_and_handler_name(i + pg->irq_base, &pmic_irqchip,
+					handle_simple_irq, "demux");
+		set_irq_chip_data(i + pg->irq_base, pg);
+	}
+	return 0;
+err:
+	iounmap(pg->gpiointr);
+err2:
+	kfree(pg);
+	return retval;
+}
+
+/* at the same time, register a platform driver
+ * this supports the sfi 0.81 fw */
+static struct platform_driver platform_pmic_gpio_driver = {
+	.driver = {
+		.name		= DRIVER_NAME,
+		.owner		= THIS_MODULE,
+	},
+	.probe		= platform_pmic_gpio_probe,
+};
+
+static int __init platform_pmic_gpio_init(void)
+{
+	return platform_driver_register(&platform_pmic_gpio_driver);
+}
+
+subsys_initcall(platform_pmic_gpio_init);
+
+MODULE_AUTHOR("Alek Du <alek.du@intel.com>");
+MODULE_DESCRIPTION("Intel Moorestown PMIC GPIO driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/rar_register/rar_register.c b/drivers/platform/x86/intel_rar_register.c
similarity index 98%
rename from drivers/staging/rar_register/rar_register.c
rename to drivers/platform/x86/intel_rar_register.c
index 618503f..73f8e6d 100644
--- a/drivers/staging/rar_register/rar_register.c
+++ b/drivers/platform/x86/intel_rar_register.c
@@ -40,15 +40,12 @@
  *      Initial publish
  */
 
-#define DEBUG 1
-
-#include "rar_register.h"
-
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
+#include <linux/rar_register.h>
 
 /* === Lincroft Message Bus Interface === */
 #define LNC_MCR_OFFSET		0xD0	/* Message Control Register */
@@ -155,7 +152,6 @@
 	return NULL;
 }
 
-
 /**
  *	rar_to_device		-	return the device handling this RAR
  *	@rar: RAR number
@@ -496,7 +492,7 @@
  *	a driver that do require a valid RAR address. One of those
  *	steps would be to call rar_get_address()
  *
- *	This function return 0 on success an error code on failure.
+ *	This function return 0 on success or an error code on failure.
  */
 int register_rar(int num, int (*callback)(unsigned long data),
 							unsigned long data)
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index bb2f1fb..943f908 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -23,7 +23,7 @@
 #include <linux/pm.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
-#include <asm/setup.h>
+#include <asm/mrst.h>
 #include <asm/intel_scu_ipc.h>
 
 /* IPC defines the following message types */
@@ -38,10 +38,6 @@
 #define IPC_CMD_PCNTRL_R      1 /* Register read */
 #define IPC_CMD_PCNTRL_M      2 /* Register read-modify-write */
 
-/* Miscelaneous Command ids */
-#define IPC_CMD_INDIRECT_RD   2 /* 32bit indirect read */
-#define IPC_CMD_INDIRECT_WR   5 /* 32bit indirect write */
-
 /*
  * IPC register summary
  *
@@ -62,8 +58,8 @@
 
 #define IPC_BASE_ADDR     0xFF11C000	/* IPC1 base register address */
 #define IPC_MAX_ADDR      0x100		/* Maximum IPC regisers */
-#define IPC_WWBUF_SIZE    16		/* IPC Write buffer Size */
-#define IPC_RWBUF_SIZE    16		/* IPC Read buffer Size */
+#define IPC_WWBUF_SIZE    20		/* IPC Write buffer Size */
+#define IPC_RWBUF_SIZE    20		/* IPC Read buffer Size */
 #define IPC_I2C_BASE      0xFF12B000	/* I2C control register base address */
 #define IPC_I2C_MAX_ADDR  0x10		/* Maximum I2C regisers */
 
@@ -78,12 +74,7 @@
 
 static struct intel_scu_ipc_dev  ipcdev; /* Only one for now */
 
-static int platform = 1;
-module_param(platform, int, 0);
-MODULE_PARM_DESC(platform, "1 for moorestown platform");
-
-
-
+static int platform;		/* Platform type */
 
 /*
  * IPC Read Buffer (Read Only):
@@ -119,24 +110,6 @@
 }
 
 /*
- * IPC destination Pointer (Write Only):
- * Use content as pointer for destination write
- */
-static inline void ipc_write_dptr(u32 data) /* Write dptr data */
-{
-	writel(data, ipcdev.ipc_base + 0x0C);
-}
-
-/*
- * IPC Source Pointer (Write Only):
- * Use content as pointer for read location
-*/
-static inline void ipc_write_sptr(u32 data) /* Write dptr data */
-{
-	writel(data, ipcdev.ipc_base + 0x08);
-}
-
-/*
  * Status Register (Read Only):
  * Driver will read this register to get the ready/busy status of the IPC
  * block and error status of the IPC command that was just processed by SCU
@@ -154,7 +127,7 @@
 	return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
 }
 
-static inline u8 ipc_data_readl(u32 offset) /* Read ipc u32 data */
+static inline u32 ipc_data_readl(u32 offset) /* Read ipc u32 data */
 {
 	return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
 }
@@ -175,62 +148,73 @@
 			return -ETIMEDOUT;
 		}
 	}
-	return (status >> 1) & 1;
+	if ((status >> 1) & 1)
+		return -EIO;
+
+	return 0;
 }
 
 /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
 static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
 {
-	int nc;
+	int i, nc, bytes, d;
 	u32 offset = 0;
 	u32 err = 0;
-	u8 cbuf[IPC_WWBUF_SIZE] = { '\0' };
+	u8 cbuf[IPC_WWBUF_SIZE] = { };
 	u32 *wbuf = (u32 *)&cbuf;
 
 	mutex_lock(&ipclock);
+
+	memset(cbuf, 0, sizeof(cbuf));
+
 	if (ipcdev.pdev == NULL) {
 		mutex_unlock(&ipclock);
 		return -ENODEV;
 	}
 
-	if (platform == 1) {
-		/* Entry is 4 bytes for read/write, 5 bytes for read modify */
-		for (nc = 0; nc < count; nc++) {
+	if (platform != MRST_CPU_CHIP_PENWELL) {
+		bytes = 0;
+		d = 0;
+		for (i = 0; i < count; i++) {
+			cbuf[bytes++] = addr[i];
+			cbuf[bytes++] = addr[i] >> 8;
+			if (id != IPC_CMD_PCNTRL_R)
+				cbuf[bytes++] = data[d++];
+			if (id == IPC_CMD_PCNTRL_M)
+				cbuf[bytes++] = data[d++];
+		}
+		for (i = 0; i < bytes; i += 4)
+			ipc_data_writel(wbuf[i/4], i);
+		ipc_command(bytes << 16 |  id << 12 | 0 << 8 | op);
+	} else {
+		for (nc = 0; nc < count; nc++, offset += 2) {
 			cbuf[offset] = addr[nc];
 			cbuf[offset + 1] = addr[nc] >> 8;
-			if (id != IPC_CMD_PCNTRL_R)
-				cbuf[offset + 2] = data[nc];
-			if (id == IPC_CMD_PCNTRL_M) {
-				cbuf[offset + 3] = data[nc + 1];
-				offset += 1;
-			}
-			offset += 3;
 		}
-		for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
-			ipc_data_writel(wbuf[nc], offset); /* Write wbuff */
 
-	} else {
-		for (nc = 0, offset = 0; nc < count; nc++, offset += 2)
-			ipc_data_writel(addr[nc], offset); /* Write addresses */
-		if (id != IPC_CMD_PCNTRL_R) {
-			for (nc = 0; nc < count; nc++, offset++)
-				ipc_data_writel(data[nc], offset); /* Write data */
-			if (id == IPC_CMD_PCNTRL_M)
-				ipc_data_writel(data[nc + 1], offset); /* Mask value*/
+		if (id == IPC_CMD_PCNTRL_R) {
+			for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
+				ipc_data_writel(wbuf[nc], offset);
+			ipc_command((count*2) << 16 |  id << 12 | 0 << 8 | op);
+		} else if (id == IPC_CMD_PCNTRL_W) {
+			for (nc = 0; nc < count; nc++, offset += 1)
+				cbuf[offset] = data[nc];
+			for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
+				ipc_data_writel(wbuf[nc], offset);
+			ipc_command((count*3) << 16 |  id << 12 | 0 << 8 | op);
+		} else if (id == IPC_CMD_PCNTRL_M) {
+			cbuf[offset] = data[0];
+			cbuf[offset + 1] = data[1];
+			ipc_data_writel(wbuf[0], 0); /* Write wbuff */
+			ipc_command(4 << 16 |  id << 12 | 0 << 8 | op);
 		}
 	}
 
-	if (id != IPC_CMD_PCNTRL_M)
-		ipc_command((count * 3) << 16 |  id << 12 | 0 << 8 | op);
-	else
-		ipc_command((count * 4) << 16 |  id << 12 | 0 << 8 | op);
-
 	err = busy_loop();
-
 	if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
 		/* Workaround: values are read as 0 without memcpy_fromio */
-		memcpy_fromio(cbuf, ipcdev.ipc_base + IPC_READ_BUFFER, 16);
-		if (platform == 1) {
+		memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16);
+		if (platform != MRST_CPU_CHIP_PENWELL) {
 			for (nc = 0, offset = 2; nc < count; nc++, offset += 3)
 				data[nc] = ipc_data_readb(offset);
 		} else {
@@ -405,70 +389,6 @@
 EXPORT_SYMBOL(intel_scu_ipc_update_register);
 
 /**
- *	intel_scu_ipc_register_read	-	32bit indirect read
- *	@addr: register address
- *	@value: 32bit value return
- *
- *	Performs IA 32 bit indirect read, returns 0 on success, or an
- *	error code.
- *
- *	Can be used when SCCB(System Controller Configuration Block) register
- *	HRIM(Honor Restricted IPC Messages) is set (bit 23)
- *
- *	This function may sleep. Locking for SCU accesses is handled for
- *	the caller.
- */
-int intel_scu_ipc_register_read(u32 addr, u32 *value)
-{
-	u32 err = 0;
-
-	mutex_lock(&ipclock);
-	if (ipcdev.pdev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-	ipc_write_sptr(addr);
-	ipc_command(4 << 16 | IPC_CMD_INDIRECT_RD);
-	err = busy_loop();
-	*value = ipc_data_readl(0);
-	mutex_unlock(&ipclock);
-	return err;
-}
-EXPORT_SYMBOL(intel_scu_ipc_register_read);
-
-/**
- *	intel_scu_ipc_register_write	-	32bit indirect write
- *	@addr: register address
- *	@value: 32bit value to write
- *
- *	Performs IA 32 bit indirect write, returns 0 on success, or an
- *	error code.
- *
- *	Can be used when SCCB(System Controller Configuration Block) register
- *	HRIM(Honor Restricted IPC Messages) is set (bit 23)
- *
- *	This function may sleep. Locking for SCU accesses is handled for
- *	the caller.
- */
-int intel_scu_ipc_register_write(u32 addr, u32 value)
-{
-	u32 err = 0;
-
-	mutex_lock(&ipclock);
-	if (ipcdev.pdev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-	ipc_write_dptr(addr);
-	ipc_data_writel(value, 0);
-	ipc_command(4 << 16 | IPC_CMD_INDIRECT_WR);
-	err = busy_loop();
-	mutex_unlock(&ipclock);
-	return err;
-}
-EXPORT_SYMBOL(intel_scu_ipc_register_write);
-
-/**
  *	intel_scu_ipc_simple_command	-	send a simple command
  *	@cmd: command
  *	@sub: sub type
@@ -524,7 +444,7 @@
 	for (i = 0; i < inlen; i++)
 		ipc_data_writel(*in++, 4 * i);
 
-	ipc_command((sub << 12) | cmd | (inlen << 18));
+	ipc_command((inlen << 16) | (sub << 12) | cmd);
 	err = busy_loop();
 
 	for (i = 0; i < outlen; i++)
@@ -803,6 +723,7 @@
 
 static const struct pci_device_id pci_ids[] = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)},
 	{ 0,}
 };
 MODULE_DEVICE_TABLE(pci, pci_ids);
@@ -817,6 +738,9 @@
 
 static int __init intel_scu_ipc_init(void)
 {
+	platform = mrst_identify_cpu();
+	if (platform == 0)
+		return -ENODEV;
 	return  pci_register_driver(&ipc_driver);
 }
 
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index afd762b..7e9bb6d 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -434,7 +434,7 @@
 {
 	printk(KERN_INFO "msi-laptop: Identified laptop model '%s'.\n",
 	       id->ident);
-	return 0;
+	return 1;
 }
 
 static struct dmi_system_id __initdata msi_dmi_table[] = {
@@ -562,15 +562,15 @@
 	return 0;
 }
 
-static struct rfkill_ops rfkill_bluetooth_ops = {
+static const struct rfkill_ops rfkill_bluetooth_ops = {
 	.set_block = rfkill_bluetooth_set
 };
 
-static struct rfkill_ops rfkill_wlan_ops = {
+static const struct rfkill_ops rfkill_wlan_ops = {
 	.set_block = rfkill_wlan_set
 };
 
-static struct rfkill_ops rfkill_threeg_ops = {
+static const struct rfkill_ops rfkill_threeg_ops = {
 	.set_block = rfkill_threeg_set
 };
 
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
index d173600..42a5469 100644
--- a/drivers/platform/x86/msi-wmi.c
+++ b/drivers/platform/x86/msi-wmi.c
@@ -57,7 +57,7 @@
 };
 static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1];
 
-struct backlight_device *backlight;
+static struct backlight_device *backlight;
 
 static int backlight_map[] = { 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF };
 
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 2fb9a32..ec01c3d 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -248,7 +248,7 @@
 	status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET,
 				      &params, NULL);
 
-	return status == AE_OK;
+	return (status == AE_OK) ? 0 : -EIO;
 }
 
 static inline int acpi_pcc_get_sqty(struct acpi_device *device)
@@ -586,7 +586,6 @@
 static int acpi_pcc_hotkey_resume(struct acpi_device *device)
 {
 	struct pcc_acpi *pcc = acpi_driver_data(device);
-	acpi_status status = AE_OK;
 
 	if (device == NULL || pcc == NULL)
 		return -EINVAL;
@@ -594,9 +593,7 @@
 	ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Sticky mode restore: %d\n",
 			  pcc->sticky_mode));
 
-	status = acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode);
-
-	return status == AE_OK ? 0 : -EINVAL;
+	return acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode);
 }
 
 static int acpi_pcc_hotkey_add(struct acpi_device *device)
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 1387c5f..e3154ff 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -561,8 +561,7 @@
 	if (!atomic_dec_and_test(&sony_pf_users))
 		return;
 
-	platform_device_del(sony_pf_device);
-	platform_device_put(sony_pf_device);
+	platform_device_unregister(sony_pf_device);
 	platform_driver_unregister(&sony_pf_driver);
 }
 
@@ -1196,9 +1195,13 @@
 	}
 
 	device_enum = (union acpi_object *) buffer.pointer;
-	if (!device_enum || device_enum->type != ACPI_TYPE_BUFFER) {
-		printk(KERN_ERR "Invalid SN06 return object 0x%.2x\n",
-				device_enum->type);
+	if (!device_enum) {
+		pr_err("Invalid SN06 return object\n");
+		goto out_no_enum;
+	}
+	if (device_enum->type != ACPI_TYPE_BUFFER) {
+		pr_err("Invalid SN06 return object type 0x%.2x\n",
+		       device_enum->type);
 		goto out_no_enum;
 	}
 
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 4bdb137..5d6119b 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -5838,75 +5838,6 @@
 };
 
 /*************************************************************************
- * EC Dump subdriver
- */
-
-static u8 ecdump_regs[256];
-
-static int ecdump_read(struct seq_file *m)
-{
-	int i, j;
-	u8 v;
-
-	seq_printf(m, "EC      "
-		       " +00 +01 +02 +03 +04 +05 +06 +07"
-		       " +08 +09 +0a +0b +0c +0d +0e +0f\n");
-	for (i = 0; i < 256; i += 16) {
-		seq_printf(m, "EC 0x%02x:", i);
-		for (j = 0; j < 16; j++) {
-			if (!acpi_ec_read(i + j, &v))
-				break;
-			if (v != ecdump_regs[i + j])
-				seq_printf(m, " *%02x", v);
-			else
-				seq_printf(m, "  %02x", v);
-			ecdump_regs[i + j] = v;
-		}
-		seq_putc(m, '\n');
-		if (j != 16)
-			break;
-	}
-
-	/* These are way too dangerous to advertise openly... */
-#if 0
-	seq_printf(m, "commands:\t0x<offset> 0x<value>"
-		       " (<offset> is 00-ff, <value> is 00-ff)\n");
-	seq_printf(m, "commands:\t0x<offset> <value>  "
-		       " (<offset> is 00-ff, <value> is 0-255)\n");
-#endif
-	return 0;
-}
-
-static int ecdump_write(char *buf)
-{
-	char *cmd;
-	int i, v;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
-			/* i and v set */
-		} else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
-			/* i and v set */
-		} else
-			return -EINVAL;
-		if (i >= 0 && i < 256 && v >= 0 && v < 256) {
-			if (!acpi_ec_write(i, v))
-				return -EIO;
-		} else
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-static struct ibm_struct ecdump_driver_data = {
-	.name = "ecdump",
-	.read = ecdump_read,
-	.write = ecdump_write,
-	.flags.experimental = 1,
-};
-
-/*************************************************************************
  * Backlight/brightness subdriver
  */
 
@@ -8883,9 +8814,6 @@
 		.data = &thermal_driver_data,
 	},
 	{
-		.data = &ecdump_driver_data,
-	},
-	{
 		.init = brightness_init,
 		.data = &brightness_driver_data,
 	},
@@ -8993,7 +8921,6 @@
 TPACPI_PARAM(cmos);
 TPACPI_PARAM(led);
 TPACPI_PARAM(beep);
-TPACPI_PARAM(ecdump);
 TPACPI_PARAM(brightness);
 TPACPI_PARAM(volume);
 TPACPI_PARAM(fan);
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 37aa147..7d67a45 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -4,6 +4,7 @@
  *
  *  Copyright (C) 2002-2004 John Belmonte
  *  Copyright (C) 2008 Philip Langdale
+ *  Copyright (C) 2010 Pierre Ducroquet
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -47,6 +48,7 @@
 #include <linux/platform_device.h>
 #include <linux/rfkill.h>
 #include <linux/input.h>
+#include <linux/leds.h>
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
@@ -129,6 +131,8 @@
 
 static struct key_entry toshiba_acpi_keymap[]  = {
 	{KE_KEY, 0x101, KEY_MUTE},
+	{KE_KEY, 0x102, KEY_ZOOMOUT},
+	{KE_KEY, 0x103, KEY_ZOOMIN},
 	{KE_KEY, 0x13b, KEY_COFFEE},
 	{KE_KEY, 0x13c, KEY_BATTERY},
 	{KE_KEY, 0x13d, KEY_SLEEP},
@@ -285,6 +289,7 @@
 	struct platform_device *p_dev;
 	struct rfkill *bt_rfk;
 	struct input_dev *hotkey_dev;
+	int illumination_installed;
 	acpi_handle handle;
 
 	const char *bt_name;
@@ -292,6 +297,110 @@
 	struct mutex mutex;
 };
 
+/* Illumination support */
+static int toshiba_illumination_available(void)
+{
+	u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 };
+	u32 out[HCI_WORDS];
+	acpi_status status;
+
+	in[0] = 0xf100;
+	status = hci_raw(in, out);
+	if (ACPI_FAILURE(status)) {
+		printk(MY_INFO "Illumination device not available\n");
+		return 0;
+	}
+	in[0] = 0xf400;
+	status = hci_raw(in, out);
+	return 1;
+}
+
+static void toshiba_illumination_set(struct led_classdev *cdev,
+				     enum led_brightness brightness)
+{
+	u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 };
+	u32 out[HCI_WORDS];
+	acpi_status status;
+
+	/* First request : initialize communication. */
+	in[0] = 0xf100;
+	status = hci_raw(in, out);
+	if (ACPI_FAILURE(status)) {
+		printk(MY_INFO "Illumination device not available\n");
+		return;
+	}
+
+	if (brightness) {
+		/* Switch the illumination on */
+		in[0] = 0xf400;
+		in[1] = 0x14e;
+		in[2] = 1;
+		status = hci_raw(in, out);
+		if (ACPI_FAILURE(status)) {
+			printk(MY_INFO "ACPI call for illumination failed.\n");
+			return;
+		}
+	} else {
+		/* Switch the illumination off */
+		in[0] = 0xf400;
+		in[1] = 0x14e;
+		in[2] = 0;
+		status = hci_raw(in, out);
+		if (ACPI_FAILURE(status)) {
+			printk(MY_INFO "ACPI call for illumination failed.\n");
+			return;
+		}
+	}
+
+	/* Last request : close communication. */
+	in[0] = 0xf200;
+	in[1] = 0;
+	in[2] = 0;
+	hci_raw(in, out);
+}
+
+static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
+{
+	u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 };
+	u32 out[HCI_WORDS];
+	acpi_status status;
+	enum led_brightness result;
+
+	/* First request : initialize communication. */
+	in[0] = 0xf100;
+	status = hci_raw(in, out);
+	if (ACPI_FAILURE(status)) {
+		printk(MY_INFO "Illumination device not available\n");
+		return LED_OFF;
+	}
+
+	/* Check the illumination */
+	in[0] = 0xf300;
+	in[1] = 0x14e;
+	status = hci_raw(in, out);
+	if (ACPI_FAILURE(status)) {
+		printk(MY_INFO "ACPI call for illumination failed.\n");
+		return LED_OFF;
+	}
+
+	result = out[2] ? LED_FULL : LED_OFF;
+
+	/* Last request : close communication. */
+	in[0] = 0xf200;
+	in[1] = 0;
+	in[2] = 0;
+	hci_raw(in, out);
+
+	return result;
+}
+
+static struct led_classdev toshiba_led = {
+	.name           = "toshiba::illumination",
+	.max_brightness = 1,
+	.brightness_set = toshiba_illumination_set,
+	.brightness_get = toshiba_illumination_get,
+};
+
 static struct toshiba_acpi_dev toshiba_acpi = {
 	.bt_name = "Toshiba Bluetooth",
 };
@@ -720,25 +829,22 @@
 
 #define PROC_TOSHIBA		"toshiba"
 
-static acpi_status __init add_device(void)
+static void __init create_toshiba_proc_entries(void)
 {
 	proc_create("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, &lcd_proc_fops);
 	proc_create("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, &video_proc_fops);
 	proc_create("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, &fan_proc_fops);
 	proc_create("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, &keys_proc_fops);
 	proc_create("version", S_IRUGO, toshiba_proc_dir, &version_proc_fops);
-
-	return AE_OK;
 }
 
-static acpi_status remove_device(void)
+static void remove_toshiba_proc_entries(void)
 {
 	remove_proc_entry("lcd", toshiba_proc_dir);
 	remove_proc_entry("video", toshiba_proc_dir);
 	remove_proc_entry("fan", toshiba_proc_dir);
 	remove_proc_entry("keys", toshiba_proc_dir);
 	remove_proc_entry("version", toshiba_proc_dir);
-	return AE_OK;
 }
 
 static struct backlight_ops toshiba_backlight_data = {
@@ -906,7 +1012,7 @@
 	if (toshiba_backlight_device)
 		backlight_device_unregister(toshiba_backlight_device);
 
-	remove_device();
+	remove_toshiba_proc_entries();
 
 	if (toshiba_proc_dir)
 		remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
@@ -914,6 +1020,9 @@
 	acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
 				   toshiba_acpi_notify);
 
+	if (toshiba_acpi.illumination_installed)
+		led_classdev_unregister(&toshiba_led);
+
 	platform_device_unregister(toshiba_acpi.p_dev);
 
 	return;
@@ -921,7 +1030,6 @@
 
 static int __init toshiba_acpi_init(void)
 {
-	acpi_status status = AE_OK;
 	u32 hci_result;
 	bool bt_present;
 	int ret = 0;
@@ -969,11 +1077,7 @@
 		toshiba_acpi_exit();
 		return -ENODEV;
 	} else {
-		status = add_device();
-		if (ACPI_FAILURE(status)) {
-			toshiba_acpi_exit();
-			return -ENODEV;
-		}
+		create_toshiba_proc_entries();
 	}
 
 	props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
@@ -1013,6 +1117,13 @@
 		}
 	}
 
+	toshiba_acpi.illumination_installed = 0;
+	if (toshiba_illumination_available()) {
+		if (!led_classdev_register(&(toshiba_acpi.p_dev->dev),
+					   &toshiba_led))
+			toshiba_acpi.illumination_installed = 1;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index e4eaa14..b2978a0 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -518,8 +518,13 @@
 {
 	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *obj;
+	acpi_status status;
 
-	wmi_get_event_data(value, &response);
+	status = wmi_get_event_data(value, &response);
+	if (status != AE_OK) {
+		printk(KERN_INFO "wmi: bad event status 0x%x\n", status);
+		return;
+	}
 
 	obj = (union acpi_object *)response.pointer;
 
@@ -543,6 +548,7 @@
 	default:
 		printk("object type 0x%X\n", obj->type);
 	}
+	kfree(obj);
 }
 
 /**
@@ -804,7 +810,7 @@
 /*
  * Parse the _WDG method for the GUID data blocks
  */
-static __init acpi_status parse_wdg(acpi_handle handle)
+static acpi_status parse_wdg(acpi_handle handle)
 {
 	struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
 	union acpi_object *obj;
@@ -827,8 +833,10 @@
 	total = obj->buffer.length / sizeof(struct guid_block);
 
 	gblock = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL);
-	if (!gblock)
-		return AE_NO_MEMORY;
+	if (!gblock) {
+		status = AE_NO_MEMORY;
+		goto out_free_pointer;
+	}
 
 	for (i = 0; i < total; i++) {
 		/*
@@ -848,8 +856,10 @@
 			wmi_dump_wdg(&gblock[i]);
 
 		wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
-		if (!wblock)
-			return AE_NO_MEMORY;
+		if (!wblock) {
+			status = AE_NO_MEMORY;
+			goto out_free_gblock;
+		}
 
 		wblock->gblock = gblock[i];
 		wblock->handle = handle;
@@ -860,8 +870,10 @@
 		list_add_tail(&wblock->list, &wmi_blocks.list);
 	}
 
-	kfree(out.pointer);
+out_free_gblock:
 	kfree(gblock);
+out_free_pointer:
+	kfree(out.pointer);
 
 	return status;
 }
@@ -947,7 +959,7 @@
 	return 0;
 }
 
-static int __init acpi_wmi_add(struct acpi_device *device)
+static int acpi_wmi_add(struct acpi_device *device)
 {
 	acpi_status status;
 	int result = 0;
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 5dba909..88b3cde 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -164,6 +164,9 @@
 	list_add_tail(&dev->global_list, &pnp_global);
 	list_add_tail(&dev->protocol_list, &dev->protocol->devices);
 	spin_unlock(&pnp_lock);
+	if (dev->protocol->can_wakeup)
+		device_set_wakeup_capable(&dev->dev,
+				dev->protocol->can_wakeup(dev));
 	return device_register(&dev->dev);
 }
 
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index f7ff628..dc4e32e 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -122,17 +122,37 @@
 }
 
 #ifdef CONFIG_ACPI_SLEEP
+static bool pnpacpi_can_wakeup(struct pnp_dev *dev)
+{
+	struct acpi_device *acpi_dev = dev->data;
+	acpi_handle handle = acpi_dev->handle;
+
+	return acpi_bus_can_wakeup(handle);
+}
+
 static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
 {
 	struct acpi_device *acpi_dev = dev->data;
 	acpi_handle handle = acpi_dev->handle;
 	int power_state;
 
+	if (device_can_wakeup(&dev->dev)) {
+		int rc = acpi_pm_device_sleep_wake(&dev->dev,
+				device_may_wakeup(&dev->dev));
+
+		if (rc)
+			return rc;
+	}
 	power_state = acpi_pm_device_sleep_state(&dev->dev, NULL);
 	if (power_state < 0)
 		power_state = (state.event == PM_EVENT_ON) ?
 				ACPI_STATE_D0 : ACPI_STATE_D3;
 
+	/* acpi_bus_set_power() often fails (keyboard port can't be
+	 * powered-down?), and in any case, our return value is ignored
+	 * by pnp_bus_suspend().  Hence we don't revert the wakeup
+	 * setting if the set_power fails.
+	 */
 	return acpi_bus_set_power(handle, power_state);
 }
 
@@ -141,6 +161,8 @@
 	struct acpi_device *acpi_dev = dev->data;
 	acpi_handle handle = acpi_dev->handle;
 
+	if (device_may_wakeup(&dev->dev))
+		acpi_pm_device_sleep_wake(&dev->dev, false);
 	return acpi_bus_set_power(handle, ACPI_STATE_D0);
 }
 #endif
@@ -151,6 +173,7 @@
 	.set	 = pnpacpi_set_resources,
 	.disable = pnpacpi_disable_resources,
 #ifdef CONFIG_ACPI_SLEEP
+	.can_wakeup = pnpacpi_can_wakeup,
 	.suspend = pnpacpi_suspend,
 	.resume = pnpacpi_resume,
 #endif
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 6326b67..34c7e40 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -368,6 +368,8 @@
 	if (qebsm_possible())
 		irq_ptr->qib.rflags |= QIB_RFLAGS_ENABLE_QEBSM;
 
+	irq_ptr->qib.rflags |= init_data->qib_rflags;
+
 	irq_ptr->qib.qfmt = init_data->q_format;
 	if (init_data->no_input_qs)
 		irq_ptr->qib.isliba =
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 147bb1a..a75ed30 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -295,7 +295,7 @@
 	int err;
 	err = ccwgroup_create_from_string(claw_root_dev,
 					  claw_group_driver.driver_id,
-					  &claw_ccw_driver, 3, buf);
+					  &claw_ccw_driver, 2, buf);
 	return err ? err : count;
 }
 
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 7a44c38..d125776 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -40,11 +40,7 @@
  */
 enum qeth_dbf_names {
 	QETH_DBF_SETUP,
-	QETH_DBF_QERR,
-	QETH_DBF_TRACE,
 	QETH_DBF_MSG,
-	QETH_DBF_SENSE,
-	QETH_DBF_MISC,
 	QETH_DBF_CTRL,
 	QETH_DBF_INFOS	/* must be last element */
 };
@@ -71,7 +67,19 @@
 	debug_sprintf_event(qeth_dbf[QETH_DBF_MSG].id, level, text)
 
 #define QETH_DBF_TEXT_(name, level, text...) \
-	qeth_dbf_longtext(QETH_DBF_##name, level, text)
+	qeth_dbf_longtext(qeth_dbf[QETH_DBF_##name].id, level, text)
+
+#define QETH_CARD_TEXT(card, level, text) \
+	debug_text_event(card->debug, level, text)
+
+#define QETH_CARD_HEX(card, level, addr, len) \
+	debug_event(card->debug, level, (void *)(addr), len)
+
+#define QETH_CARD_MESSAGE(card, text...) \
+	debug_sprintf_event(card->debug, level, text)
+
+#define QETH_CARD_TEXT_(card, level, text...) \
+	qeth_dbf_longtext(card->debug, level, text)
 
 #define SENSE_COMMAND_REJECT_BYTE 0
 #define SENSE_COMMAND_REJECT_FLAG 0x80
@@ -180,8 +188,7 @@
 		qeth_is_enabled6(c, f) : qeth_is_enabled(c, f))
 
 #define QETH_IDX_FUNC_LEVEL_OSD		 0x0101
-#define QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT 0x4108
-#define QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT 0x5108
+#define QETH_IDX_FUNC_LEVEL_IQD		 0x4108
 
 #define QETH_MODELLIST_ARRAY \
 	{{0x1731, 0x01, 0x1732, QETH_CARD_TYPE_OSD, QETH_MAX_QUEUES, 0}, \
@@ -733,12 +740,15 @@
 	struct qeth_qdio_info qdio;
 	struct qeth_perf_stats perf_stats;
 	int use_hard_stop;
+	int read_or_write_problem;
 	struct qeth_osn_info osn_info;
 	struct qeth_discipline discipline;
 	atomic_t force_alloc_skb;
 	struct service_level qeth_service_level;
 	struct qdio_ssqd_desc ssqd;
+	debug_info_t *debug;
 	struct mutex conf_mutex;
+	struct mutex discipline_mutex;
 };
 
 struct qeth_card_list_struct {
@@ -857,9 +867,10 @@
 				struct ethtool_stats *, u64 *);
 void qeth_core_get_strings(struct net_device *, u32, u8 *);
 void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
-void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...);
+void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
 int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
 int qeth_set_access_ctrl_online(struct qeth_card *card);
+int qeth_hdr_chk_and_bounce(struct sk_buff *, int);
 
 /* exports for OSN */
 int qeth_osn_assist(struct net_device *, void *, int);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 13ef46b..3a5a18a 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -32,16 +32,8 @@
 	/*                   N  P  A    M  L  V                      H  */
 	[QETH_DBF_SETUP] = {"qeth_setup",
 				8, 1,   8, 5, &debug_hex_ascii_view, NULL},
-	[QETH_DBF_QERR]  = {"qeth_qerr",
-				2, 1,   8, 2, &debug_hex_ascii_view, NULL},
-	[QETH_DBF_TRACE] = {"qeth_trace",
-				4, 1,   8, 3, &debug_hex_ascii_view, NULL},
 	[QETH_DBF_MSG]   = {"qeth_msg",
 				8, 1, 128, 3, &debug_sprintf_view,   NULL},
-	[QETH_DBF_SENSE] = {"qeth_sense",
-				2, 1,  64, 2, &debug_hex_ascii_view, NULL},
-	[QETH_DBF_MISC]	 = {"qeth_misc",
-				2, 1, 256, 2, &debug_hex_ascii_view, NULL},
 	[QETH_DBF_CTRL]  = {"qeth_control",
 		8, 1, QETH_DBF_CTRL_LEN, 5, &debug_hex_ascii_view, NULL},
 };
@@ -65,48 +57,6 @@
 static int qeth_qdio_establish(struct qeth_card *);
 
 
-static inline void __qeth_fill_buffer_frag(struct sk_buff *skb,
-		struct qdio_buffer *buffer, int is_tso,
-		int *next_element_to_fill)
-{
-	struct skb_frag_struct *frag;
-	int fragno;
-	unsigned long addr;
-	int element, cnt, dlen;
-
-	fragno = skb_shinfo(skb)->nr_frags;
-	element = *next_element_to_fill;
-	dlen = 0;
-
-	if (is_tso)
-		buffer->element[element].flags =
-			SBAL_FLAGS_MIDDLE_FRAG;
-	else
-		buffer->element[element].flags =
-			SBAL_FLAGS_FIRST_FRAG;
-	dlen = skb->len - skb->data_len;
-	if (dlen) {
-		buffer->element[element].addr = skb->data;
-		buffer->element[element].length = dlen;
-		element++;
-	}
-	for (cnt = 0; cnt < fragno; cnt++) {
-		frag = &skb_shinfo(skb)->frags[cnt];
-		addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
-			frag->page_offset;
-		buffer->element[element].addr = (char *)addr;
-		buffer->element[element].length = frag->size;
-		if (cnt < (fragno - 1))
-			buffer->element[element].flags =
-				SBAL_FLAGS_MIDDLE_FRAG;
-		else
-			buffer->element[element].flags =
-				SBAL_FLAGS_LAST_FRAG;
-		element++;
-	}
-	*next_element_to_fill = element;
-}
-
 static inline const char *qeth_get_cardname(struct qeth_card *card)
 {
 	if (card->info.guestlan) {
@@ -232,7 +182,7 @@
 {
 	struct qeth_buffer_pool_entry *pool_entry, *tmp;
 
-	QETH_DBF_TEXT(TRACE, 5, "clwrklst");
+	QETH_CARD_TEXT(card, 5, "clwrklst");
 	list_for_each_entry_safe(pool_entry, tmp,
 			    &card->qdio.in_buf_pool.entry_list, list){
 			list_del(&pool_entry->list);
@@ -246,7 +196,7 @@
 	void *ptr;
 	int i, j;
 
-	QETH_DBF_TEXT(TRACE, 5, "alocpool");
+	QETH_CARD_TEXT(card, 5, "alocpool");
 	for (i = 0; i < card->qdio.init_pool.buf_count; ++i) {
 		pool_entry = kmalloc(sizeof(*pool_entry), GFP_KERNEL);
 		if (!pool_entry) {
@@ -273,7 +223,7 @@
 
 int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt)
 {
-	QETH_DBF_TEXT(TRACE, 2, "realcbp");
+	QETH_CARD_TEXT(card, 2, "realcbp");
 
 	if ((card->state != CARD_STATE_DOWN) &&
 	    (card->state != CARD_STATE_RECOVER))
@@ -293,7 +243,7 @@
 	int rc;
 	struct qeth_cmd_buffer *iob;
 
-	QETH_DBF_TEXT(TRACE, 5, "issnxrd");
+	QETH_CARD_TEXT(card, 5, "issnxrd");
 	if (card->read.state != CH_STATE_UP)
 		return -EIO;
 	iob = qeth_get_buffer(&card->read);
@@ -305,13 +255,14 @@
 		return -ENOMEM;
 	}
 	qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE);
-	QETH_DBF_TEXT(TRACE, 6, "noirqpnd");
+	QETH_CARD_TEXT(card, 6, "noirqpnd");
 	rc = ccw_device_start(card->read.ccwdev, &card->read.ccw,
 			      (addr_t) iob, 0, 0);
 	if (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);
+		card->read_or_write_problem = 1;
 		qeth_schedule_recovery(card);
 		wake_up(&card->wait_q);
 	}
@@ -364,7 +315,7 @@
 {
 	struct qeth_ipa_cmd *cmd = NULL;
 
-	QETH_DBF_TEXT(TRACE, 5, "chkipad");
+	QETH_CARD_TEXT(card, 5, "chkipad");
 	if (IS_IPA(iob->data)) {
 		cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
 		if (IS_IPA_REPLY(cmd)) {
@@ -400,10 +351,10 @@
 			case IPA_CMD_MODCCID:
 				return cmd;
 			case IPA_CMD_REGISTER_LOCAL_ADDR:
-				QETH_DBF_TEXT(TRACE, 3, "irla");
+				QETH_CARD_TEXT(card, 3, "irla");
 				break;
 			case IPA_CMD_UNREGISTER_LOCAL_ADDR:
-				QETH_DBF_TEXT(TRACE, 3, "urla");
+				QETH_CARD_TEXT(card, 3, "urla");
 				break;
 			default:
 				QETH_DBF_MESSAGE(2, "Received data is IPA "
@@ -420,7 +371,7 @@
 	struct qeth_reply *reply, *r;
 	unsigned long flags;
 
-	QETH_DBF_TEXT(TRACE, 4, "clipalst");
+	QETH_CARD_TEXT(card, 4, "clipalst");
 
 	spin_lock_irqsave(&card->lock, flags);
 	list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) {
@@ -432,6 +383,7 @@
 		qeth_put_reply(reply);
 	}
 	spin_unlock_irqrestore(&card->lock, flags);
+	atomic_set(&card->write.irq_pending, 0);
 }
 EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list);
 
@@ -448,9 +400,9 @@
 			   buffer[4],
 			   ((buffer[4] == 0x22) ?
 			    " -- try another portname" : ""));
-		QETH_DBF_TEXT(TRACE, 2, "ckidxres");
-		QETH_DBF_TEXT(TRACE, 2, " idxterm");
-		QETH_DBF_TEXT_(TRACE, 2, "  rc%d", -EIO);
+		QETH_CARD_TEXT(card, 2, "ckidxres");
+		QETH_CARD_TEXT(card, 2, " idxterm");
+		QETH_CARD_TEXT_(card, 2, "  rc%d", -EIO);
 		if (buffer[4] == 0xf6) {
 			dev_err(&card->gdev->dev,
 			"The qeth device is not configured "
@@ -467,8 +419,8 @@
 {
 	struct qeth_card *card;
 
-	QETH_DBF_TEXT(TRACE, 4, "setupccw");
 	card = CARD_FROM_CDEV(channel->ccwdev);
+	QETH_CARD_TEXT(card, 4, "setupccw");
 	if (channel == &card->read)
 		memcpy(&channel->ccw, READ_CCW, sizeof(struct ccw1));
 	else
@@ -481,7 +433,7 @@
 {
 	__u8 index;
 
-	QETH_DBF_TEXT(TRACE, 6, "getbuff");
+	QETH_CARD_TEXT(CARD_FROM_CDEV(channel->ccwdev), 6, "getbuff");
 	index = channel->io_buf_no;
 	do {
 		if (channel->iob[index].state == BUF_STATE_FREE) {
@@ -502,7 +454,7 @@
 {
 	unsigned long flags;
 
-	QETH_DBF_TEXT(TRACE, 6, "relbuff");
+	QETH_CARD_TEXT(CARD_FROM_CDEV(channel->ccwdev), 6, "relbuff");
 	spin_lock_irqsave(&channel->iob_lock, flags);
 	memset(iob->data, 0, QETH_BUFSIZE);
 	iob->state = BUF_STATE_FREE;
@@ -553,9 +505,8 @@
 	int keep_reply;
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 4, "sndctlcb");
-
 	card = CARD_FROM_CDEV(channel->ccwdev);
+	QETH_CARD_TEXT(card, 4, "sndctlcb");
 	rc = qeth_check_idx_response(card, iob->data);
 	switch (rc) {
 	case 0:
@@ -563,6 +514,7 @@
 	case -EIO:
 		qeth_clear_ipacmd_list(card);
 		qeth_schedule_recovery(card);
+		/* fall through */
 	default:
 		goto out;
 	}
@@ -722,7 +674,7 @@
 
 void qeth_schedule_recovery(struct qeth_card *card)
 {
-	QETH_DBF_TEXT(TRACE, 2, "startrec");
+	QETH_CARD_TEXT(card, 2, "startrec");
 	if (qeth_set_thread_start_bit(card, QETH_RECOVER_THREAD) == 0)
 		schedule_work(&card->kernel_thread_starter);
 }
@@ -732,15 +684,17 @@
 {
 	int dstat, cstat;
 	char *sense;
+	struct qeth_card *card;
 
 	sense = (char *) irb->ecw;
 	cstat = irb->scsw.cmd.cstat;
 	dstat = irb->scsw.cmd.dstat;
+	card = CARD_FROM_CDEV(cdev);
 
 	if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK |
 		     SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK |
 		     SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) {
-		QETH_DBF_TEXT(TRACE, 2, "CGENCHK");
+		QETH_CARD_TEXT(card, 2, "CGENCHK");
 		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\n",
@@ -753,23 +707,23 @@
 	if (dstat & DEV_STAT_UNIT_CHECK) {
 		if (sense[SENSE_RESETTING_EVENT_BYTE] &
 		    SENSE_RESETTING_EVENT_FLAG) {
-			QETH_DBF_TEXT(TRACE, 2, "REVIND");
+			QETH_CARD_TEXT(card, 2, "REVIND");
 			return 1;
 		}
 		if (sense[SENSE_COMMAND_REJECT_BYTE] &
 		    SENSE_COMMAND_REJECT_FLAG) {
-			QETH_DBF_TEXT(TRACE, 2, "CMDREJi");
+			QETH_CARD_TEXT(card, 2, "CMDREJi");
 			return 1;
 		}
 		if ((sense[2] == 0xaf) && (sense[3] == 0xfe)) {
-			QETH_DBF_TEXT(TRACE, 2, "AFFE");
+			QETH_CARD_TEXT(card, 2, "AFFE");
 			return 1;
 		}
 		if ((!sense[0]) && (!sense[1]) && (!sense[2]) && (!sense[3])) {
-			QETH_DBF_TEXT(TRACE, 2, "ZEROSEN");
+			QETH_CARD_TEXT(card, 2, "ZEROSEN");
 			return 0;
 		}
-		QETH_DBF_TEXT(TRACE, 2, "DGENCHK");
+		QETH_CARD_TEXT(card, 2, "DGENCHK");
 			return 1;
 	}
 	return 0;
@@ -778,6 +732,10 @@
 static long __qeth_check_irb_error(struct ccw_device *cdev,
 		unsigned long intparm, struct irb *irb)
 {
+	struct qeth_card *card;
+
+	card = CARD_FROM_CDEV(cdev);
+
 	if (!IS_ERR(irb))
 		return 0;
 
@@ -785,17 +743,15 @@
 	case -EIO:
 		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);
+		QETH_CARD_TEXT(card, 2, "ckirberr");
+		QETH_CARD_TEXT_(card, 2, "  rc%d", -EIO);
 		break;
 	case -ETIMEDOUT:
 		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);
+		QETH_CARD_TEXT(card, 2, "ckirberr");
+		QETH_CARD_TEXT_(card, 2, "  rc%d", -ETIMEDOUT);
 		if (intparm == QETH_RCD_PARM) {
-			struct qeth_card *card = CARD_FROM_CDEV(cdev);
-
 			if (card && (card->data.ccwdev == cdev)) {
 				card->data.state = CH_STATE_DOWN;
 				wake_up(&card->wait_q);
@@ -805,8 +761,8 @@
 	default:
 		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???");
+		QETH_CARD_TEXT(card, 2, "ckirberr");
+		QETH_CARD_TEXT(card, 2, "  rc???");
 	}
 	return PTR_ERR(irb);
 }
@@ -822,8 +778,6 @@
 	struct qeth_cmd_buffer *iob;
 	__u8 index;
 
-	QETH_DBF_TEXT(TRACE, 5, "irq");
-
 	if (__qeth_check_irb_error(cdev, intparm, irb))
 		return;
 	cstat = irb->scsw.cmd.cstat;
@@ -833,15 +787,17 @@
 	if (!card)
 		return;
 
+	QETH_CARD_TEXT(card, 5, "irq");
+
 	if (card->read.ccwdev == cdev) {
 		channel = &card->read;
-		QETH_DBF_TEXT(TRACE, 5, "read");
+		QETH_CARD_TEXT(card, 5, "read");
 	} else if (card->write.ccwdev == cdev) {
 		channel = &card->write;
-		QETH_DBF_TEXT(TRACE, 5, "write");
+		QETH_CARD_TEXT(card, 5, "write");
 	} else {
 		channel = &card->data;
-		QETH_DBF_TEXT(TRACE, 5, "data");
+		QETH_CARD_TEXT(card, 5, "data");
 	}
 	atomic_set(&channel->irq_pending, 0);
 
@@ -857,12 +813,12 @@
 		goto out;
 
 	if (intparm == QETH_CLEAR_CHANNEL_PARM) {
-		QETH_DBF_TEXT(TRACE, 6, "clrchpar");
+		QETH_CARD_TEXT(card, 6, "clrchpar");
 		/* we don't have to handle this further */
 		intparm = 0;
 	}
 	if (intparm == QETH_HALT_CHANNEL_PARM) {
-		QETH_DBF_TEXT(TRACE, 6, "hltchpar");
+		QETH_CARD_TEXT(card, 6, "hltchpar");
 		/* we don't have to handle this further */
 		intparm = 0;
 	}
@@ -963,7 +919,7 @@
 {
 	int i, j;
 
-	QETH_DBF_TEXT(TRACE, 2, "clearqdbf");
+	QETH_CARD_TEXT(card, 2, "clearqdbf");
 	/* clear outbound buffers to free skbs */
 	for (i = 0; i < card->qdio.no_out_queues; ++i)
 		if (card->qdio.out_qs[i]) {
@@ -978,7 +934,6 @@
 {
 	struct qeth_buffer_pool_entry *pool_entry, *tmp;
 	int i = 0;
-	QETH_DBF_TEXT(TRACE, 5, "freepool");
 	list_for_each_entry_safe(pool_entry, tmp,
 				 &card->qdio.init_pool.entry_list, init_list){
 		for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i)
@@ -992,7 +947,6 @@
 {
 	int i, j;
 
-	QETH_DBF_TEXT(TRACE, 2, "freeqdbf");
 	if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) ==
 		QETH_QDIO_UNINITIALIZED)
 		return;
@@ -1089,7 +1043,7 @@
 	int rc = 0;
 
 	spin_lock_irqsave(&card->thread_mask_lock, flags);
-	QETH_DBF_TEXT_(TRACE, 4, "  %02x%02x%02x",
+	QETH_CARD_TEXT_(card, 4, "  %02x%02x%02x",
 			(u8) card->thread_start_mask,
 			(u8) card->thread_allowed_mask,
 			(u8) card->thread_running_mask);
@@ -1102,7 +1056,7 @@
 {
 	struct qeth_card *card = container_of(work, struct qeth_card,
 					kernel_thread_starter);
-	QETH_DBF_TEXT(TRACE , 2, "strthrd");
+	QETH_CARD_TEXT(card , 2, "strthrd");
 
 	if (card->read.state != CH_STATE_UP &&
 	    card->write.state != CH_STATE_UP)
@@ -1124,6 +1078,7 @@
 	card->state = CARD_STATE_DOWN;
 	card->lan_online = 0;
 	card->use_hard_stop = 0;
+	card->read_or_write_problem = 0;
 	card->dev = NULL;
 	spin_lock_init(&card->vlanlock);
 	spin_lock_init(&card->mclock);
@@ -1132,6 +1087,7 @@
 	spin_lock_init(&card->ip_lock);
 	spin_lock_init(&card->thread_mask_lock);
 	mutex_init(&card->conf_mutex);
+	mutex_init(&card->discipline_mutex);
 	card->thread_start_mask = 0;
 	card->thread_allowed_mask = 0;
 	card->thread_running_mask = 0;
@@ -1229,8 +1185,8 @@
 	struct qeth_card *card;
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "clearch");
 	card = CARD_FROM_CDEV(channel->ccwdev);
+	QETH_CARD_TEXT(card, 3, "clearch");
 	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
 	rc = ccw_device_clear(channel->ccwdev, QETH_CLEAR_CHANNEL_PARM);
 	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
@@ -1253,8 +1209,8 @@
 	struct qeth_card *card;
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "haltch");
 	card = CARD_FROM_CDEV(channel->ccwdev);
+	QETH_CARD_TEXT(card, 3, "haltch");
 	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
 	rc = ccw_device_halt(channel->ccwdev, QETH_HALT_CHANNEL_PARM);
 	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
@@ -1274,7 +1230,7 @@
 {
 	int rc1 = 0, rc2 = 0, rc3 = 0;
 
-	QETH_DBF_TEXT(TRACE, 3, "haltchs");
+	QETH_CARD_TEXT(card, 3, "haltchs");
 	rc1 = qeth_halt_channel(&card->read);
 	rc2 = qeth_halt_channel(&card->write);
 	rc3 = qeth_halt_channel(&card->data);
@@ -1289,7 +1245,7 @@
 {
 	int rc1 = 0, rc2 = 0, rc3 = 0;
 
-	QETH_DBF_TEXT(TRACE, 3, "clearchs");
+	QETH_CARD_TEXT(card, 3, "clearchs");
 	rc1 = qeth_clear_channel(&card->read);
 	rc2 = qeth_clear_channel(&card->write);
 	rc3 = qeth_clear_channel(&card->data);
@@ -1304,8 +1260,7 @@
 {
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 3, "clhacrd");
-	QETH_DBF_HEX(TRACE, 3, &card, sizeof(void *));
+	QETH_CARD_TEXT(card, 3, "clhacrd");
 
 	if (halt)
 		rc = qeth_halt_channels(card);
@@ -1318,7 +1273,7 @@
 {
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 3, "qdioclr");
+	QETH_CARD_TEXT(card, 3, "qdioclr");
 	switch (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ESTABLISHED,
 		QETH_QDIO_CLEANING)) {
 	case QETH_QDIO_ESTABLISHED:
@@ -1329,7 +1284,7 @@
 			rc = qdio_shutdown(CARD_DDEV(card),
 				QDIO_FLAG_CLEANUP_USING_CLEAR);
 		if (rc)
-			QETH_DBF_TEXT_(TRACE, 3, "1err%d", rc);
+			QETH_CARD_TEXT_(card, 3, "1err%d", rc);
 		qdio_free(CARD_DDEV(card));
 		atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
 		break;
@@ -1340,7 +1295,7 @@
 	}
 	rc = qeth_clear_halt_card(card, use_halt);
 	if (rc)
-		QETH_DBF_TEXT_(TRACE, 3, "2err%d", rc);
+		QETH_CARD_TEXT_(card, 3, "2err%d", rc);
 	card->state = CARD_STATE_DOWN;
 	return rc;
 }
@@ -1432,14 +1387,10 @@
 {
 	switch (card->info.type) {
 	case QETH_CARD_TYPE_IQD:
-		if (card->ipato.enabled)
-			card->info.func_level =
-				QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT;
-		else
-			card->info.func_level =
-				QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT;
+		card->info.func_level =	QETH_IDX_FUNC_LEVEL_IQD;
 		break;
 	case QETH_CARD_TYPE_OSD:
+	case QETH_CARD_TYPE_OSN:
 		card->info.func_level = QETH_IDX_FUNC_LEVEL_OSD;
 		break;
 	default:
@@ -1637,15 +1588,18 @@
 				"host\n");
 			break;
 		case QETH_IDX_ACT_ERR_AUTH:
+		case QETH_IDX_ACT_ERR_AUTH_USER:
 			dev_err(&card->read.ccwdev->dev,
 				"Setting the device online failed because of "
-				"insufficient LPAR authorization\n");
+				"insufficient authorization\n");
 			break;
 		default:
 			QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel:"
 				" negative reply\n",
 				dev_name(&card->read.ccwdev->dev));
 		}
+		QETH_CARD_TEXT_(card, 2, "idxread%c",
+			QETH_IDX_ACT_CAUSE_CODE(iob->data));
 		goto out;
 	}
 
@@ -1705,8 +1659,12 @@
 	unsigned long timeout, event_timeout;
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 2, "sendctl");
+	QETH_CARD_TEXT(card, 2, "sendctl");
 
+	if (card->read_or_write_problem) {
+		qeth_release_buffer(iob->channel, iob);
+		return -EIO;
+	}
 	reply = qeth_alloc_reply(card);
 	if (!reply) {
 		return -ENOMEM;
@@ -1732,7 +1690,7 @@
 		event_timeout = QETH_TIMEOUT;
 	timeout = jiffies + event_timeout;
 
-	QETH_DBF_TEXT(TRACE, 6, "noirqpnd");
+	QETH_CARD_TEXT(card, 6, "noirqpnd");
 	spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
 	rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
 			      (addr_t) iob, 0, 0);
@@ -1741,7 +1699,7 @@
 		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);
+		QETH_CARD_TEXT_(card, 2, " err%d", rc);
 		spin_lock_irqsave(&card->lock, flags);
 		list_del_init(&reply->list);
 		qeth_put_reply(reply);
@@ -1778,6 +1736,9 @@
 	spin_unlock_irqrestore(&reply->card->lock, flags);
 	reply->rc = -ETIME;
 	atomic_inc(&reply->received);
+	atomic_set(&card->write.irq_pending, 0);
+	qeth_release_buffer(iob->channel, iob);
+	card->write.buf_no = (card->write.buf_no + 1) % QETH_CMD_BUFFER_NO;
 	wake_up(&reply->wait_q);
 	rc = reply->rc;
 	qeth_put_reply(reply);
@@ -1978,7 +1939,7 @@
 		card->info.link_type = link_type;
 	} else
 		card->info.link_type = 0;
-	QETH_DBF_TEXT_(SETUP, 2, "link%d", link_type);
+	QETH_DBF_TEXT_(SETUP, 2, "link%d", card->info.link_type);
 	QETH_DBF_TEXT_(SETUP, 2, "  rc%d", iob->rc);
 	return 0;
 }
@@ -2035,7 +1996,7 @@
 		QETH_DBF_TEXT(SETUP, 2, "olmlimit");
 		dev_err(&card->gdev->dev, "A connection could not be "
 			"established because of an OLM limit\n");
-		rc = -EMLINK;
+		iob->rc = -EMLINK;
 	}
 	QETH_DBF_TEXT_(SETUP, 2, "  rc%d", iob->rc);
 	return rc;
@@ -2335,7 +2296,7 @@
 {
 	struct qeth_buffer_pool_entry *entry;
 
-	QETH_DBF_TEXT(TRACE, 5, "inwrklst");
+	QETH_CARD_TEXT(card, 5, "inwrklst");
 
 	list_for_each_entry(entry,
 			    &card->qdio.init_pool.entry_list, init_list) {
@@ -2522,7 +2483,7 @@
 	int rc;
 	char prot_type;
 
-	QETH_DBF_TEXT(TRACE, 4, "sendipa");
+	QETH_CARD_TEXT(card, 4, "sendipa");
 
 	if (card->options.layer2)
 		if (card->info.type == QETH_CARD_TYPE_OSN)
@@ -2534,6 +2495,10 @@
 	qeth_prepare_ipa_cmd(card, iob, prot_type);
 	rc = qeth_send_control_data(card, IPA_CMD_LENGTH,
 						iob, reply_cb, reply_param);
+	if (rc == -ETIME) {
+		qeth_clear_ipacmd_list(card);
+		qeth_schedule_recovery(card);
+	}
 	return rc;
 }
 EXPORT_SYMBOL_GPL(qeth_send_ipa_cmd);
@@ -2582,7 +2547,7 @@
 {
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 4, "defadpcb");
+	QETH_CARD_TEXT(card, 4, "defadpcb");
 
 	cmd = (struct qeth_ipa_cmd *) data;
 	if (cmd->hdr.return_code == 0)
@@ -2597,7 +2562,7 @@
 {
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 3, "quyadpcb");
+	QETH_CARD_TEXT(card, 3, "quyadpcb");
 
 	cmd = (struct qeth_ipa_cmd *) data;
 	if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f) {
@@ -2633,7 +2598,7 @@
 	int rc;
 	struct qeth_cmd_buffer *iob;
 
-	QETH_DBF_TEXT(TRACE, 3, "queryadp");
+	QETH_CARD_TEXT(card, 3, "queryadp");
 	iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_COMMANDS_SUPPORTED,
 				   sizeof(struct qeth_ipacmd_setadpparms));
 	rc = qeth_send_ipa_cmd(card, iob, qeth_query_setadapterparms_cb, NULL);
@@ -2645,13 +2610,12 @@
 		unsigned int qdio_error, const char *dbftext)
 {
 	if (qdio_error) {
-		QETH_DBF_TEXT(TRACE, 2, dbftext);
-		QETH_DBF_TEXT(QERR, 2, dbftext);
-		QETH_DBF_TEXT_(QERR, 2, " F15=%02X",
+		QETH_CARD_TEXT(card, 2, dbftext);
+		QETH_CARD_TEXT_(card, 2, " F15=%02X",
 			       buf->element[15].flags & 0xff);
-		QETH_DBF_TEXT_(QERR, 2, " F14=%02X",
+		QETH_CARD_TEXT_(card, 2, " F14=%02X",
 			       buf->element[14].flags & 0xff);
-		QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error);
+		QETH_CARD_TEXT_(card, 2, " qerr=%X", qdio_error);
 		if ((buf->element[15].flags & 0xff) == 0x12) {
 			card->stats.rx_dropped++;
 			return 0;
@@ -2717,8 +2681,7 @@
 		if (rc) {
 			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));
+			QETH_CARD_TEXT(card, 2, "qinberr");
 		}
 		queue->next_buf_to_init = (queue->next_buf_to_init + count) %
 					  QDIO_MAX_BUFFERS_PER_Q;
@@ -2731,7 +2694,7 @@
 {
 	int sbalf15 = buffer->buffer->element[15].flags & 0xff;
 
-	QETH_DBF_TEXT(TRACE, 6, "hdsnderr");
+	QETH_CARD_TEXT(card, 6, "hdsnderr");
 	if (card->info.type == QETH_CARD_TYPE_IQD) {
 		if (sbalf15 == 0) {
 			qdio_err = 0;
@@ -2747,9 +2710,8 @@
 	if ((sbalf15 >= 15) && (sbalf15 <= 31))
 		return QETH_SEND_ERROR_RETRY;
 
-	QETH_DBF_TEXT(TRACE, 1, "lnkfail");
-	QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
-	QETH_DBF_TEXT_(TRACE, 1, "%04x %02x",
+	QETH_CARD_TEXT(card, 1, "lnkfail");
+	QETH_CARD_TEXT_(card, 1, "%04x %02x",
 		       (u16)qdio_err, (u8)sbalf15);
 	return QETH_SEND_ERROR_LINK_FAILURE;
 }
@@ -2764,7 +2726,7 @@
 		if (atomic_read(&queue->used_buffers)
 		    >= QETH_HIGH_WATERMARK_PACK){
 			/* switch non-PACKING -> PACKING */
-			QETH_DBF_TEXT(TRACE, 6, "np->pack");
+			QETH_CARD_TEXT(queue->card, 6, "np->pack");
 			if (queue->card->options.performance_stats)
 				queue->card->perf_stats.sc_dp_p++;
 			queue->do_pack = 1;
@@ -2787,7 +2749,7 @@
 		if (atomic_read(&queue->used_buffers)
 		    <= QETH_LOW_WATERMARK_PACK) {
 			/* switch PACKING -> non-PACKING */
-			QETH_DBF_TEXT(TRACE, 6, "pack->np");
+			QETH_CARD_TEXT(queue->card, 6, "pack->np");
 			if (queue->card->options.performance_stats)
 				queue->card->perf_stats.sc_p_dp++;
 			queue->do_pack = 0;
@@ -2896,9 +2858,8 @@
 		/* ignore temporary SIGA errors without busy condition */
 		if (rc == QDIO_ERROR_SIGA_TARGET)
 			return;
-		QETH_DBF_TEXT(TRACE, 2, "flushbuf");
-		QETH_DBF_TEXT_(TRACE, 2, " err%d", rc);
-		QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_DDEV_ID(queue->card));
+		QETH_CARD_TEXT(queue->card, 2, "flushbuf");
+		QETH_CARD_TEXT_(queue->card, 2, " err%d", rc);
 
 		/* this must not happen under normal circumstances. if it
 		 * happens something is really wrong -> recover */
@@ -2960,10 +2921,9 @@
 	int i;
 	unsigned qeth_send_err;
 
-	QETH_DBF_TEXT(TRACE, 6, "qdouhdl");
+	QETH_CARD_TEXT(card, 6, "qdouhdl");
 	if (qdio_error & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
-		QETH_DBF_TEXT(TRACE, 2, "achkcond");
-		QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_BUS_ID(card));
+		QETH_CARD_TEXT(card, 2, "achkcond");
 		netif_stop_queue(card->dev);
 		qeth_schedule_recovery(card);
 		return;
@@ -3033,13 +2993,11 @@
 int qeth_get_elements_no(struct qeth_card *card, void *hdr,
 		     struct sk_buff *skb, int elems)
 {
-	int elements_needed = 0;
+	int dlen = skb->len - skb->data_len;
+	int elements_needed = PFN_UP((unsigned long)skb->data + dlen - 1) -
+		PFN_DOWN((unsigned long)skb->data);
 
-	if (skb_shinfo(skb)->nr_frags > 0)
-		elements_needed = (skb_shinfo(skb)->nr_frags + 1);
-	if (elements_needed == 0)
-		elements_needed = 1 + (((((unsigned long) skb->data) %
-				PAGE_SIZE) + skb->len) >> PAGE_SHIFT);
+	elements_needed += skb_shinfo(skb)->nr_frags;
 	if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
 		QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
 			"(Number=%d / Length=%d). Discarded.\n",
@@ -3050,15 +3008,35 @@
 }
 EXPORT_SYMBOL_GPL(qeth_get_elements_no);
 
+int qeth_hdr_chk_and_bounce(struct sk_buff *skb, int len)
+{
+	int hroom, inpage, rest;
+
+	if (((unsigned long)skb->data & PAGE_MASK) !=
+	    (((unsigned long)skb->data + len - 1) & PAGE_MASK)) {
+		hroom = skb_headroom(skb);
+		inpage = PAGE_SIZE - ((unsigned long) skb->data % PAGE_SIZE);
+		rest = len - inpage;
+		if (rest > hroom)
+			return 1;
+		memmove(skb->data - rest, skb->data, skb->len - skb->data_len);
+		skb->data -= rest;
+		QETH_DBF_MESSAGE(2, "skb bounce len: %d rest: %d\n", len, rest);
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qeth_hdr_chk_and_bounce);
+
 static inline void __qeth_fill_buffer(struct sk_buff *skb,
 	struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill,
 	int offset)
 {
-	int length = skb->len;
+	int length = skb->len - skb->data_len;
 	int length_here;
 	int element;
 	char *data;
-	int first_lap ;
+	int first_lap, cnt;
+	struct skb_frag_struct *frag;
 
 	element = *next_element_to_fill;
 	data = skb->data;
@@ -3081,10 +3059,14 @@
 		length -= length_here;
 		if (!length) {
 			if (first_lap)
-				buffer->element[element].flags = 0;
+				if (skb_shinfo(skb)->nr_frags)
+					buffer->element[element].flags =
+						SBAL_FLAGS_FIRST_FRAG;
+				else
+					buffer->element[element].flags = 0;
 			else
 				buffer->element[element].flags =
-				    SBAL_FLAGS_LAST_FRAG;
+				    SBAL_FLAGS_MIDDLE_FRAG;
 		} else {
 			if (first_lap)
 				buffer->element[element].flags =
@@ -3097,6 +3079,18 @@
 		element++;
 		first_lap = 0;
 	}
+
+	for (cnt = 0; cnt < skb_shinfo(skb)->nr_frags; cnt++) {
+		frag = &skb_shinfo(skb)->frags[cnt];
+		buffer->element[element].addr = (char *)page_to_phys(frag->page)
+			+ frag->page_offset;
+		buffer->element[element].length = frag->size;
+		buffer->element[element].flags = SBAL_FLAGS_MIDDLE_FRAG;
+		element++;
+	}
+
+	if (buffer->element[element - 1].flags)
+		buffer->element[element - 1].flags = SBAL_FLAGS_LAST_FRAG;
 	*next_element_to_fill = element;
 }
 
@@ -3137,20 +3131,16 @@
 		buf->next_element_to_fill++;
 	}
 
-	if (skb_shinfo(skb)->nr_frags == 0)
-		__qeth_fill_buffer(skb, buffer, large_send,
-				(int *)&buf->next_element_to_fill, offset);
-	else
-		__qeth_fill_buffer_frag(skb, buffer, large_send,
-					(int *)&buf->next_element_to_fill);
+	__qeth_fill_buffer(skb, buffer, large_send,
+		(int *)&buf->next_element_to_fill, offset);
 
 	if (!queue->do_pack) {
-		QETH_DBF_TEXT(TRACE, 6, "fillbfnp");
+		QETH_CARD_TEXT(queue->card, 6, "fillbfnp");
 		/* set state to PRIMED -> will be flushed */
 		atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
 		flush_cnt = 1;
 	} else {
-		QETH_DBF_TEXT(TRACE, 6, "fillbfpa");
+		QETH_CARD_TEXT(queue->card, 6, "fillbfpa");
 		if (queue->card->options.performance_stats)
 			queue->card->perf_stats.skbs_sent_pack++;
 		if (buf->next_element_to_fill >=
@@ -3210,7 +3200,7 @@
 			rc = dev_queue_xmit(skb);
 		} else {
 			dev_kfree_skb_any(skb);
-			QETH_DBF_TEXT(QERR, 2, "qrdrop");
+			QETH_CARD_TEXT(card, 2, "qrdrop");
 		}
 	}
 	return 0;
@@ -3312,14 +3302,14 @@
 	struct qeth_ipa_cmd *cmd;
 	struct qeth_ipacmd_setadpparms *setparms;
 
-	QETH_DBF_TEXT(TRACE, 4, "prmadpcb");
+	QETH_CARD_TEXT(card, 4, "prmadpcb");
 
 	cmd = (struct qeth_ipa_cmd *) data;
 	setparms = &(cmd->data.setadapterparms);
 
 	qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
 	if (cmd->hdr.return_code) {
-		QETH_DBF_TEXT_(TRACE, 4, "prmrc%2.2x", cmd->hdr.return_code);
+		QETH_CARD_TEXT_(card, 4, "prmrc%2.2x", cmd->hdr.return_code);
 		setparms->data.mode = SET_PROMISC_MODE_OFF;
 	}
 	card->info.promisc_mode = setparms->data.mode;
@@ -3333,7 +3323,7 @@
 	struct qeth_cmd_buffer *iob;
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 4, "setprom");
+	QETH_CARD_TEXT(card, 4, "setprom");
 
 	if (((dev->flags & IFF_PROMISC) &&
 	     (card->info.promisc_mode == SET_PROMISC_MODE_ON)) ||
@@ -3343,7 +3333,7 @@
 	mode = SET_PROMISC_MODE_OFF;
 	if (dev->flags & IFF_PROMISC)
 		mode = SET_PROMISC_MODE_ON;
-	QETH_DBF_TEXT_(TRACE, 4, "mode:%x", mode);
+	QETH_CARD_TEXT_(card, 4, "mode:%x", mode);
 
 	iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_PROMISC_MODE,
 			sizeof(struct qeth_ipacmd_setadpparms));
@@ -3360,9 +3350,9 @@
 
 	card = dev->ml_priv;
 
-	QETH_DBF_TEXT(TRACE, 4, "chgmtu");
+	QETH_CARD_TEXT(card, 4, "chgmtu");
 	sprintf(dbf_text, "%8x", new_mtu);
-	QETH_DBF_TEXT(TRACE, 4, dbf_text);
+	QETH_CARD_TEXT(card, 4, dbf_text);
 
 	if (new_mtu < 64)
 		return -EINVAL;
@@ -3382,7 +3372,7 @@
 
 	card = dev->ml_priv;
 
-	QETH_DBF_TEXT(TRACE, 5, "getstat");
+	QETH_CARD_TEXT(card, 5, "getstat");
 
 	return &card->stats;
 }
@@ -3393,7 +3383,7 @@
 {
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 4, "chgmaccb");
+	QETH_CARD_TEXT(card, 4, "chgmaccb");
 
 	cmd = (struct qeth_ipa_cmd *) data;
 	if (!card->options.layer2 ||
@@ -3413,7 +3403,7 @@
 	struct qeth_cmd_buffer *iob;
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 4, "chgmac");
+	QETH_CARD_TEXT(card, 4, "chgmac");
 
 	iob = qeth_get_adapter_cmd(card, IPA_SETADP_ALTER_MAC_ADDRESS,
 				   sizeof(struct qeth_ipacmd_setadpparms));
@@ -3433,9 +3423,8 @@
 {
 	struct qeth_ipa_cmd *cmd;
 	struct qeth_set_access_ctrl *access_ctrl_req;
-	int rc;
 
-	QETH_DBF_TEXT(TRACE, 4, "setaccb");
+	QETH_CARD_TEXT(card, 4, "setaccb");
 
 	cmd = (struct qeth_ipa_cmd *) data;
 	access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl;
@@ -3460,7 +3449,6 @@
 			card->gdev->dev.kobj.name,
 			access_ctrl_req->subcmd_code,
 			cmd->data.setadapterparms.hdr.return_code);
-		rc = 0;
 		break;
 	}
 	case SET_ACCESS_CTRL_RC_NOT_SUPPORTED:
@@ -3474,7 +3462,6 @@
 
 		/* ensure isolation mode is "none" */
 		card->options.isolation = ISOLATION_MODE_NONE;
-		rc = -EOPNOTSUPP;
 		break;
 	}
 	case SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER:
@@ -3489,7 +3476,6 @@
 
 		/* ensure isolation mode is "none" */
 		card->options.isolation = ISOLATION_MODE_NONE;
-		rc = -EOPNOTSUPP;
 		break;
 	}
 	case SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF:
@@ -3503,7 +3489,6 @@
 
 		/* ensure isolation mode is "none" */
 		card->options.isolation = ISOLATION_MODE_NONE;
-		rc = -EPERM;
 		break;
 	}
 	default:
@@ -3517,12 +3502,11 @@
 
 		/* ensure isolation mode is "none" */
 		card->options.isolation = ISOLATION_MODE_NONE;
-		rc = 0;
 		break;
 	}
 	}
 	qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
-	return rc;
+	return 0;
 }
 
 static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
@@ -3533,7 +3517,7 @@
 	struct qeth_ipa_cmd *cmd;
 	struct qeth_set_access_ctrl *access_ctrl_req;
 
-	QETH_DBF_TEXT(TRACE, 4, "setacctl");
+	QETH_CARD_TEXT(card, 4, "setacctl");
 
 	QETH_DBF_TEXT_(SETUP, 2, "setacctl");
 	QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name);
@@ -3555,7 +3539,7 @@
 {
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 4, "setactlo");
+	QETH_CARD_TEXT(card, 4, "setactlo");
 
 	if ((card->info.type == QETH_CARD_TYPE_OSD ||
 	     card->info.type == QETH_CARD_TYPE_OSX) &&
@@ -3583,8 +3567,8 @@
 {
 	struct qeth_card *card;
 
-	QETH_DBF_TEXT(TRACE, 4, "txtimeo");
 	card = dev->ml_priv;
+	QETH_CARD_TEXT(card, 4, "txtimeo");
 	card->stats.tx_errors++;
 	qeth_schedule_recovery(card);
 }
@@ -3663,7 +3647,7 @@
 {
 	u16 s1, s2;
 
-	QETH_DBF_TEXT(TRACE, 4, "sendsnmp");
+	QETH_CARD_TEXT(card, 4, "sendsnmp");
 
 	memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
 	memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data),
@@ -3688,7 +3672,7 @@
 	unsigned char *data;
 	__u16 data_len;
 
-	QETH_DBF_TEXT(TRACE, 3, "snpcmdcb");
+	QETH_CARD_TEXT(card, 3, "snpcmdcb");
 
 	cmd = (struct qeth_ipa_cmd *) sdata;
 	data = (unsigned char *)((char *)cmd - reply->offset);
@@ -3696,13 +3680,13 @@
 	snmp = &cmd->data.setadapterparms.data.snmp;
 
 	if (cmd->hdr.return_code) {
-		QETH_DBF_TEXT_(TRACE, 4, "scer1%i", cmd->hdr.return_code);
+		QETH_CARD_TEXT_(card, 4, "scer1%i", cmd->hdr.return_code);
 		return 0;
 	}
 	if (cmd->data.setadapterparms.hdr.return_code) {
 		cmd->hdr.return_code =
 			cmd->data.setadapterparms.hdr.return_code;
-		QETH_DBF_TEXT_(TRACE, 4, "scer2%i", cmd->hdr.return_code);
+		QETH_CARD_TEXT_(card, 4, "scer2%i", cmd->hdr.return_code);
 		return 0;
 	}
 	data_len = *((__u16 *)QETH_IPA_PDU_LEN_PDU1(data));
@@ -3713,13 +3697,13 @@
 
 	/* check if there is enough room in userspace */
 	if ((qinfo->udata_len - qinfo->udata_offset) < data_len) {
-		QETH_DBF_TEXT_(TRACE, 4, "scer3%i", -ENOMEM);
+		QETH_CARD_TEXT_(card, 4, "scer3%i", -ENOMEM);
 		cmd->hdr.return_code = -ENOMEM;
 		return 0;
 	}
-	QETH_DBF_TEXT_(TRACE, 4, "snore%i",
+	QETH_CARD_TEXT_(card, 4, "snore%i",
 		       cmd->data.setadapterparms.hdr.used_total);
-	QETH_DBF_TEXT_(TRACE, 4, "sseqn%i",
+	QETH_CARD_TEXT_(card, 4, "sseqn%i",
 		cmd->data.setadapterparms.hdr.seq_no);
 	/*copy entries to user buffer*/
 	if (cmd->data.setadapterparms.hdr.seq_no == 1) {
@@ -3733,9 +3717,9 @@
 	}
 	qinfo->udata_offset += data_len;
 	/* check if all replies received ... */
-		QETH_DBF_TEXT_(TRACE, 4, "srtot%i",
+		QETH_CARD_TEXT_(card, 4, "srtot%i",
 			       cmd->data.setadapterparms.hdr.used_total);
-		QETH_DBF_TEXT_(TRACE, 4, "srseq%i",
+		QETH_CARD_TEXT_(card, 4, "srseq%i",
 			       cmd->data.setadapterparms.hdr.seq_no);
 	if (cmd->data.setadapterparms.hdr.seq_no <
 	    cmd->data.setadapterparms.hdr.used_total)
@@ -3752,7 +3736,7 @@
 	struct qeth_arp_query_info qinfo = {0, };
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 3, "snmpcmd");
+	QETH_CARD_TEXT(card, 3, "snmpcmd");
 
 	if (card->info.guestlan)
 		return -EOPNOTSUPP;
@@ -3764,15 +3748,10 @@
 	/* skip 4 bytes (data_len struct member) to get req_len */
 	if (copy_from_user(&req_len, udata + sizeof(int), sizeof(int)))
 		return -EFAULT;
-	ureq = kmalloc(req_len+sizeof(struct qeth_snmp_ureq_hdr), GFP_KERNEL);
-	if (!ureq) {
-		QETH_DBF_TEXT(TRACE, 2, "snmpnome");
-		return -ENOMEM;
-	}
-	if (copy_from_user(ureq, udata,
-			req_len + sizeof(struct qeth_snmp_ureq_hdr))) {
-		kfree(ureq);
-		return -EFAULT;
+	ureq = memdup_user(udata, req_len + sizeof(struct qeth_snmp_ureq_hdr));
+	if (IS_ERR(ureq)) {
+		QETH_CARD_TEXT(card, 2, "snmpnome");
+		return PTR_ERR(ureq);
 	}
 	qinfo.udata_len = ureq->hdr.data_len;
 	qinfo.udata = kzalloc(qinfo.udata_len, GFP_KERNEL);
@@ -3991,6 +3970,7 @@
 		else
 			goto retry;
 	}
+	card->read_or_write_problem = 0;
 	rc = qeth_mpc_initialize(card);
 	if (rc) {
 		QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
@@ -4120,13 +4100,8 @@
 		skb_len -= data_len;
 		if (skb_len) {
 			if (qeth_is_last_sbale(element)) {
-				QETH_DBF_TEXT(TRACE, 4, "unexeob");
-				QETH_DBF_TEXT_(TRACE, 4, "%s",
-					CARD_BUS_ID(card));
-				QETH_DBF_TEXT(QERR, 2, "unexeob");
-				QETH_DBF_TEXT_(QERR, 2, "%s",
-					CARD_BUS_ID(card));
-				QETH_DBF_HEX(MISC, 4, buffer, sizeof(*buffer));
+				QETH_CARD_TEXT(card, 4, "unexeob");
+				QETH_CARD_HEX(card, 2, buffer, sizeof(void *));
 				dev_kfree_skb_any(skb);
 				card->stats.rx_errors++;
 				return NULL;
@@ -4147,8 +4122,7 @@
 	return skb;
 no_mem:
 	if (net_ratelimit()) {
-		QETH_DBF_TEXT(TRACE, 2, "noskbmem");
-		QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_BUS_ID(card));
+		QETH_CARD_TEXT(card, 2, "noskbmem");
 	}
 	card->stats.rx_dropped++;
 	return NULL;
@@ -4164,17 +4138,17 @@
 	}
 }
 
-void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *fmt, ...)
+void qeth_dbf_longtext(debug_info_t *id, int level, char *fmt, ...)
 {
 	char dbf_txt_buf[32];
 	va_list args;
 
-	if (level > (qeth_dbf[dbf_nix].id)->level)
+	if (level > id->level)
 		return;
 	va_start(args, fmt);
 	vsnprintf(dbf_txt_buf, sizeof(dbf_txt_buf), fmt, args);
 	va_end(args);
-	debug_text_event(qeth_dbf[dbf_nix].id, level, dbf_txt_buf);
+	debug_text_event(id, level, dbf_txt_buf);
 }
 EXPORT_SYMBOL_GPL(qeth_dbf_longtext);
 
@@ -4282,6 +4256,7 @@
 	struct device *dev;
 	int rc;
 	unsigned long flags;
+	char dbf_name[20];
 
 	QETH_DBF_TEXT(SETUP, 2, "probedev");
 
@@ -4297,6 +4272,17 @@
 		rc = -ENOMEM;
 		goto err_dev;
 	}
+
+	snprintf(dbf_name, sizeof(dbf_name), "qeth_card_%s",
+		dev_name(&gdev->dev));
+	card->debug = debug_register(dbf_name, 2, 1, 8);
+	if (!card->debug) {
+		QETH_DBF_TEXT_(SETUP, 2, "%s", "qcdbf");
+		rc = -ENOMEM;
+		goto err_card;
+	}
+	debug_register_view(card->debug, &debug_hex_ascii_view);
+
 	card->read.ccwdev  = gdev->cdev[0];
 	card->write.ccwdev = gdev->cdev[1];
 	card->data.ccwdev  = gdev->cdev[2];
@@ -4309,12 +4295,12 @@
 	rc = qeth_determine_card_type(card);
 	if (rc) {
 		QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
-		goto err_card;
+		goto err_dbf;
 	}
 	rc = qeth_setup_card(card);
 	if (rc) {
 		QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
-		goto err_card;
+		goto err_dbf;
 	}
 
 	if (card->info.type == QETH_CARD_TYPE_OSN)
@@ -4322,7 +4308,7 @@
 	else
 		rc = qeth_core_create_device_attributes(dev);
 	if (rc)
-		goto err_card;
+		goto err_dbf;
 	switch (card->info.type) {
 	case QETH_CARD_TYPE_OSN:
 	case QETH_CARD_TYPE_OSM:
@@ -4352,6 +4338,8 @@
 		qeth_core_remove_osn_attributes(dev);
 	else
 		qeth_core_remove_device_attributes(dev);
+err_dbf:
+	debug_unregister(card->debug);
 err_card:
 	qeth_core_free_card(card);
 err_dev:
@@ -4365,16 +4353,19 @@
 	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
 
 	QETH_DBF_TEXT(SETUP, 2, "removedv");
-	if (card->discipline.ccwgdriver) {
-		card->discipline.ccwgdriver->remove(gdev);
-		qeth_core_free_discipline(card);
-	}
 
 	if (card->info.type == QETH_CARD_TYPE_OSN) {
 		qeth_core_remove_osn_attributes(&gdev->dev);
 	} else {
 		qeth_core_remove_device_attributes(&gdev->dev);
 	}
+
+	if (card->discipline.ccwgdriver) {
+		card->discipline.ccwgdriver->remove(gdev);
+		qeth_core_free_discipline(card);
+	}
+
+	debug_unregister(card->debug);
 	write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
 	list_del(&card->list);
 	write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index f9ed24d..e37dd8c 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -616,8 +616,9 @@
 #define QETH_IS_IDX_ACT_POS_REPLY(buffer) (((buffer)[0x08] & 3) == 2)
 #define QETH_IDX_REPLY_LEVEL(buffer) (buffer + 0x12)
 #define QETH_IDX_ACT_CAUSE_CODE(buffer) (buffer)[0x09]
-#define QETH_IDX_ACT_ERR_EXCL	0x19
-#define QETH_IDX_ACT_ERR_AUTH	0x1E
+#define QETH_IDX_ACT_ERR_EXCL		0x19
+#define QETH_IDX_ACT_ERR_AUTH		0x1E
+#define QETH_IDX_ACT_ERR_AUTH_USER	0x20
 
 #define PDU_ENCAPSULATION(buffer) \
 	(buffer + *(buffer + (*(buffer + 0x0b)) + \
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index 2eb022f..42fa783 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -411,7 +411,7 @@
 	if (!card)
 		return -EINVAL;
 
-	mutex_lock(&card->conf_mutex);
+	mutex_lock(&card->discipline_mutex);
 	if (card->state != CARD_STATE_DOWN) {
 		rc = -EPERM;
 		goto out;
@@ -433,6 +433,7 @@
 	if (card->options.layer2 == newdis)
 		goto out;
 	else {
+		card->info.mac_bits  = 0;
 		if (card->discipline.ccwgdriver) {
 			card->discipline.ccwgdriver->remove(card->gdev);
 			qeth_core_free_discipline(card);
@@ -445,7 +446,7 @@
 
 	rc = card->discipline.ccwgdriver->probe(card->gdev);
 out:
-	mutex_unlock(&card->conf_mutex);
+	mutex_unlock(&card->discipline_mutex);
 	return rc ? rc : count;
 }
 
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index d43f57a..830d6352 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -79,7 +79,7 @@
 		rc = -EOPNOTSUPP;
 	}
 	if (rc)
-		QETH_DBF_TEXT_(TRACE, 2, "ioce%d", rc);
+		QETH_CARD_TEXT_(card, 2, "ioce%d", rc);
 	return rc;
 }
 
@@ -130,7 +130,7 @@
 	struct qeth_ipa_cmd *cmd;
 	__u8 *mac;
 
-	QETH_DBF_TEXT(TRACE, 2, "L2Sgmacb");
+	QETH_CARD_TEXT(card, 2, "L2Sgmacb");
 	cmd = (struct qeth_ipa_cmd *) data;
 	mac = &cmd->data.setdelmac.mac[0];
 	/* MAC already registered, needed in couple/uncouple case */
@@ -147,7 +147,7 @@
 
 static int qeth_l2_send_setgroupmac(struct qeth_card *card, __u8 *mac)
 {
-	QETH_DBF_TEXT(TRACE, 2, "L2Sgmac");
+	QETH_CARD_TEXT(card, 2, "L2Sgmac");
 	return qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETGMAC,
 					  qeth_l2_send_setgroupmac_cb);
 }
@@ -159,7 +159,7 @@
 	struct qeth_ipa_cmd *cmd;
 	__u8 *mac;
 
-	QETH_DBF_TEXT(TRACE, 2, "L2Dgmacb");
+	QETH_CARD_TEXT(card, 2, "L2Dgmacb");
 	cmd = (struct qeth_ipa_cmd *) data;
 	mac = &cmd->data.setdelmac.mac[0];
 	if (cmd->hdr.return_code)
@@ -170,7 +170,7 @@
 
 static int qeth_l2_send_delgroupmac(struct qeth_card *card, __u8 *mac)
 {
-	QETH_DBF_TEXT(TRACE, 2, "L2Dgmac");
+	QETH_CARD_TEXT(card, 2, "L2Dgmac");
 	return qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELGMAC,
 					  qeth_l2_send_delgroupmac_cb);
 }
@@ -262,15 +262,14 @@
 {
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 2, "L2sdvcb");
+	QETH_CARD_TEXT(card, 2, "L2sdvcb");
 	cmd = (struct qeth_ipa_cmd *) data;
 	if (cmd->hdr.return_code) {
 		QETH_DBF_MESSAGE(2, "Error in processing VLAN %i on %s: 0x%x. "
 			  "Continuing\n", cmd->data.setdelvlan.vlan_id,
 			  QETH_CARD_IFNAME(card), cmd->hdr.return_code);
-		QETH_DBF_TEXT_(TRACE, 2, "L2VL%4x", cmd->hdr.command);
-		QETH_DBF_TEXT_(TRACE, 2, "L2%s", CARD_BUS_ID(card));
-		QETH_DBF_TEXT_(TRACE, 2, "err%d", cmd->hdr.return_code);
+		QETH_CARD_TEXT_(card, 2, "L2VL%4x", cmd->hdr.command);
+		QETH_CARD_TEXT_(card, 2, "err%d", cmd->hdr.return_code);
 	}
 	return 0;
 }
@@ -281,7 +280,7 @@
 	struct qeth_ipa_cmd *cmd;
 	struct qeth_cmd_buffer *iob;
 
-	QETH_DBF_TEXT_(TRACE, 4, "L2sdv%x", ipacmd);
+	QETH_CARD_TEXT_(card, 4, "L2sdv%x", ipacmd);
 	iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4);
 	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
 	cmd->data.setdelvlan.vlan_id = i;
@@ -292,7 +291,7 @@
 static void qeth_l2_process_vlans(struct qeth_card *card, int clear)
 {
 	struct qeth_vlan_vid *id;
-	QETH_DBF_TEXT(TRACE, 3, "L2prcvln");
+	QETH_CARD_TEXT(card, 3, "L2prcvln");
 	spin_lock_bh(&card->vlanlock);
 	list_for_each_entry(id, &card->vid_list, list) {
 		if (clear)
@@ -310,13 +309,13 @@
 	struct qeth_card *card = dev->ml_priv;
 	struct qeth_vlan_vid *id;
 
-	QETH_DBF_TEXT_(TRACE, 4, "aid:%d", vid);
+	QETH_CARD_TEXT_(card, 4, "aid:%d", vid);
 	if (card->info.type == QETH_CARD_TYPE_OSM) {
-		QETH_DBF_TEXT(TRACE, 3, "aidOSM");
+		QETH_CARD_TEXT(card, 3, "aidOSM");
 		return;
 	}
 	if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
-		QETH_DBF_TEXT(TRACE, 3, "aidREC");
+		QETH_CARD_TEXT(card, 3, "aidREC");
 		return;
 	}
 	id = kmalloc(sizeof(struct qeth_vlan_vid), GFP_ATOMIC);
@@ -334,13 +333,13 @@
 	struct qeth_vlan_vid *id, *tmpid = NULL;
 	struct qeth_card *card = dev->ml_priv;
 
-	QETH_DBF_TEXT_(TRACE, 4, "kid:%d", vid);
+	QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
 	if (card->info.type == QETH_CARD_TYPE_OSM) {
-		QETH_DBF_TEXT(TRACE, 3, "kidOSM");
+		QETH_CARD_TEXT(card, 3, "kidOSM");
 		return;
 	}
 	if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
-		QETH_DBF_TEXT(TRACE, 3, "kidREC");
+		QETH_CARD_TEXT(card, 3, "kidREC");
 		return;
 	}
 	spin_lock_bh(&card->vlanlock);
@@ -456,7 +455,7 @@
 			/* else unknown */
 		default:
 			dev_kfree_skb_any(skb);
-			QETH_DBF_TEXT(TRACE, 3, "inbunkno");
+			QETH_CARD_TEXT(card, 3, "inbunkno");
 			QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN);
 			continue;
 		}
@@ -474,7 +473,7 @@
 	struct qeth_ipa_cmd *cmd;
 	struct qeth_cmd_buffer *iob;
 
-	QETH_DBF_TEXT(TRACE, 2, "L2sdmac");
+	QETH_CARD_TEXT(card, 2, "L2sdmac");
 	iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4);
 	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
 	cmd->data.setdelmac.mac_length = OSA_ADDR_LEN;
@@ -488,10 +487,10 @@
 {
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 2, "L2Smaccb");
+	QETH_CARD_TEXT(card, 2, "L2Smaccb");
 	cmd = (struct qeth_ipa_cmd *) data;
 	if (cmd->hdr.return_code) {
-		QETH_DBF_TEXT_(TRACE, 2, "L2er%x", cmd->hdr.return_code);
+		QETH_CARD_TEXT_(card, 2, "L2er%x", cmd->hdr.return_code);
 		card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
 		switch (cmd->hdr.return_code) {
 		case IPA_RC_L2_DUP_MAC:
@@ -523,7 +522,7 @@
 
 static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
 {
-	QETH_DBF_TEXT(TRACE, 2, "L2Setmac");
+	QETH_CARD_TEXT(card, 2, "L2Setmac");
 	return qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC,
 					  qeth_l2_send_setmac_cb);
 }
@@ -534,10 +533,10 @@
 {
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 2, "L2Dmaccb");
+	QETH_CARD_TEXT(card, 2, "L2Dmaccb");
 	cmd = (struct qeth_ipa_cmd *) data;
 	if (cmd->hdr.return_code) {
-		QETH_DBF_TEXT_(TRACE, 2, "err%d", cmd->hdr.return_code);
+		QETH_CARD_TEXT_(card, 2, "err%d", cmd->hdr.return_code);
 		cmd->hdr.return_code = -EIO;
 		return 0;
 	}
@@ -548,7 +547,7 @@
 
 static int qeth_l2_send_delmac(struct qeth_card *card, __u8 *mac)
 {
-	QETH_DBF_TEXT(TRACE, 2, "L2Delmac");
+	QETH_CARD_TEXT(card, 2, "L2Delmac");
 	if (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
 		return 0;
 	return qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELVMAC,
@@ -594,23 +593,22 @@
 	struct qeth_card *card = dev->ml_priv;
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 3, "setmac");
+	QETH_CARD_TEXT(card, 3, "setmac");
 
 	if (qeth_l2_verify_dev(dev) != QETH_REAL_CARD) {
-		QETH_DBF_TEXT(TRACE, 3, "setmcINV");
+		QETH_CARD_TEXT(card, 3, "setmcINV");
 		return -EOPNOTSUPP;
 	}
 
 	if (card->info.type == QETH_CARD_TYPE_OSN ||
 	    card->info.type == QETH_CARD_TYPE_OSM ||
 	    card->info.type == QETH_CARD_TYPE_OSX) {
-		QETH_DBF_TEXT(TRACE, 3, "setmcTYP");
+		QETH_CARD_TEXT(card, 3, "setmcTYP");
 		return -EOPNOTSUPP;
 	}
-	QETH_DBF_TEXT_(TRACE, 3, "%s", CARD_BUS_ID(card));
-	QETH_DBF_HEX(TRACE, 3, addr->sa_data, OSA_ADDR_LEN);
+	QETH_CARD_HEX(card, 3, addr->sa_data, OSA_ADDR_LEN);
 	if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
-		QETH_DBF_TEXT(TRACE, 3, "setmcREC");
+		QETH_CARD_TEXT(card, 3, "setmcREC");
 		return -ERESTARTSYS;
 	}
 	rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]);
@@ -627,7 +625,7 @@
 	if (card->info.type == QETH_CARD_TYPE_OSN)
 		return ;
 
-	QETH_DBF_TEXT(TRACE, 3, "setmulti");
+	QETH_CARD_TEXT(card, 3, "setmulti");
 	if (qeth_threads_running(card, QETH_RECOVER_THREAD) &&
 	    (card->state != CARD_STATE_UP))
 		return;
@@ -714,10 +712,13 @@
 		goto tx_drop;
 	}
 
-	if (card->info.type != QETH_CARD_TYPE_IQD)
+	if (card->info.type != QETH_CARD_TYPE_IQD) {
+		if (qeth_hdr_chk_and_bounce(new_skb,
+		    sizeof(struct qeth_hdr_layer2)))
+			goto tx_drop;
 		rc = qeth_do_send_packet(card, queue, new_skb, hdr,
 					 elements);
-	else
+	} else
 		rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
 					elements, data_offset, hd_len);
 	if (!rc) {
@@ -771,11 +772,10 @@
 		card->perf_stats.inbound_start_time = qeth_get_micros();
 	}
 	if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
-		QETH_DBF_TEXT(TRACE, 1, "qdinchk");
-		QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
-		QETH_DBF_TEXT_(TRACE, 1, "%04X%04X", first_element,
+		QETH_CARD_TEXT(card, 1, "qdinchk");
+		QETH_CARD_TEXT_(card, 1, "%04X%04X", first_element,
 				count);
-		QETH_DBF_TEXT_(TRACE, 1, "%04X", queue);
+		QETH_CARD_TEXT_(card, 1, "%04X", queue);
 		qeth_schedule_recovery(card);
 		return;
 	}
@@ -799,13 +799,13 @@
 {
 	struct qeth_card *card = dev->ml_priv;
 
-	QETH_DBF_TEXT(TRACE, 4, "qethopen");
+	QETH_CARD_TEXT(card, 4, "qethopen");
 	if (card->state != CARD_STATE_SOFTSETUP)
 		return -ENODEV;
 
 	if ((card->info.type != QETH_CARD_TYPE_OSN) &&
 	     (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))) {
-		QETH_DBF_TEXT(TRACE, 4, "nomacadr");
+		QETH_CARD_TEXT(card, 4, "nomacadr");
 		return -EPERM;
 	}
 	card->data.state = CH_STATE_UP;
@@ -822,7 +822,7 @@
 {
 	struct qeth_card *card = dev->ml_priv;
 
-	QETH_DBF_TEXT(TRACE, 4, "qethstop");
+	QETH_CARD_TEXT(card, 4, "qethstop");
 	netif_tx_disable(dev);
 	if (card->state == CARD_STATE_UP)
 		card->state = CARD_STATE_SOFTSETUP;
@@ -860,8 +860,6 @@
 		unregister_netdev(card->dev);
 		card->dev = NULL;
 	}
-
-	qeth_l2_del_all_mc(card);
 	return;
 }
 
@@ -935,6 +933,7 @@
 	enum qeth_card_states recover_flag;
 
 	BUG_ON(!card);
+	mutex_lock(&card->discipline_mutex);
 	mutex_lock(&card->conf_mutex);
 	QETH_DBF_TEXT(SETUP, 2, "setonlin");
 	QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
@@ -1012,6 +1011,7 @@
 	kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
 out:
 	mutex_unlock(&card->conf_mutex);
+	mutex_unlock(&card->discipline_mutex);
 	return 0;
 
 out_remove:
@@ -1025,6 +1025,7 @@
 	else
 		card->state = CARD_STATE_DOWN;
 	mutex_unlock(&card->conf_mutex);
+	mutex_unlock(&card->discipline_mutex);
 	return rc;
 }
 
@@ -1040,6 +1041,7 @@
 	int rc = 0, rc2 = 0, rc3 = 0;
 	enum qeth_card_states recover_flag;
 
+	mutex_lock(&card->discipline_mutex);
 	mutex_lock(&card->conf_mutex);
 	QETH_DBF_TEXT(SETUP, 3, "setoffl");
 	QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
@@ -1060,6 +1062,7 @@
 	/* let user_space know that device is offline */
 	kobject_uevent(&cgdev->dev.kobj, KOBJ_CHANGE);
 	mutex_unlock(&card->conf_mutex);
+	mutex_unlock(&card->discipline_mutex);
 	return 0;
 }
 
@@ -1074,11 +1077,10 @@
 	int rc = 0;
 
 	card = (struct qeth_card *) ptr;
-	QETH_DBF_TEXT(TRACE, 2, "recover1");
-	QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *));
+	QETH_CARD_TEXT(card, 2, "recover1");
 	if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD))
 		return 0;
-	QETH_DBF_TEXT(TRACE, 2, "recover2");
+	QETH_CARD_TEXT(card, 2, "recover2");
 	dev_warn(&card->gdev->dev,
 		"A recovery process has been started for the device\n");
 	card->use_hard_stop = 1;
@@ -1181,12 +1183,12 @@
 	unsigned long flags;
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 5, "osndctrd");
+	QETH_CARD_TEXT(card, 5, "osndctrd");
 
 	wait_event(card->wait_q,
 		   atomic_cmpxchg(&card->write.irq_pending, 0, 1) == 0);
 	qeth_prepare_control_data(card, len, iob);
-	QETH_DBF_TEXT(TRACE, 6, "osnoirqp");
+	QETH_CARD_TEXT(card, 6, "osnoirqp");
 	spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
 	rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
 			      (addr_t) iob, 0, 0);
@@ -1194,7 +1196,7 @@
 	if (rc) {
 		QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: "
 			   "ccw_device_start rc = %i\n", rc);
-		QETH_DBF_TEXT_(TRACE, 2, " err%d", rc);
+		QETH_CARD_TEXT_(card, 2, " err%d", rc);
 		qeth_release_buffer(iob->channel, iob);
 		atomic_set(&card->write.irq_pending, 0);
 		wake_up(&card->wait_q);
@@ -1207,7 +1209,7 @@
 {
 	u16 s1, s2;
 
-	QETH_DBF_TEXT(TRACE, 4, "osndipa");
+	QETH_CARD_TEXT(card, 4, "osndipa");
 
 	qeth_prepare_ipa_cmd(card, iob, QETH_PROT_OSN2);
 	s1 = (u16)(IPA_PDU_HEADER_SIZE + data_len);
@@ -1225,12 +1227,12 @@
 	struct qeth_card *card;
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 2, "osnsdmc");
 	if (!dev)
 		return -ENODEV;
 	card = dev->ml_priv;
 	if (!card)
 		return -ENODEV;
+	QETH_CARD_TEXT(card, 2, "osnsdmc");
 	if ((card->state != CARD_STATE_UP) &&
 	    (card->state != CARD_STATE_SOFTSETUP))
 		return -ENODEV;
@@ -1247,13 +1249,13 @@
 {
 	struct qeth_card *card;
 
-	QETH_DBF_TEXT(TRACE, 2, "osnreg");
 	*dev = qeth_l2_netdev_by_devno(read_dev_no);
 	if (*dev == NULL)
 		return -ENODEV;
 	card = (*dev)->ml_priv;
 	if (!card)
 		return -ENODEV;
+	QETH_CARD_TEXT(card, 2, "osnreg");
 	if ((assist_cb == NULL) || (data_cb == NULL))
 		return -EINVAL;
 	card->osn_info.assist_cb = assist_cb;
@@ -1266,12 +1268,12 @@
 {
 	struct qeth_card *card;
 
-	QETH_DBF_TEXT(TRACE, 2, "osndereg");
 	if (!dev)
 		return;
 	card = dev->ml_priv;
 	if (!card)
 		return;
+	QETH_CARD_TEXT(card, 2, "osndereg");
 	card->osn_info.assist_cb = NULL;
 	card->osn_info.data_cb = NULL;
 	return;
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h
index 8447d23..e705b27 100644
--- a/drivers/s390/net/qeth_l3.h
+++ b/drivers/s390/net/qeth_l3.h
@@ -64,5 +64,6 @@
 			const u8 *);
 int qeth_l3_set_large_send(struct qeth_card *, enum qeth_large_send_types);
 int qeth_l3_set_rx_csum(struct qeth_card *, enum qeth_checksum_types);
+int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *, struct qeth_ipaddr *);
 
 #endif /* __QETH_L3_H__ */
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 61adae2..e22ae24 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -195,7 +195,7 @@
 	}
 }
 
-static int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card,
+int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card,
 						struct qeth_ipaddr *addr)
 {
 	struct qeth_ipato_entry *ipatoe;
@@ -287,7 +287,7 @@
 				addr->users += add ? 1 : -1;
 			if (add && (addr->type == QETH_IP_TYPE_NORMAL) &&
 			    qeth_l3_is_addr_covered_by_ipato(card, addr)) {
-				QETH_DBF_TEXT(TRACE, 2, "tkovaddr");
+				QETH_CARD_TEXT(card, 2, "tkovaddr");
 				addr->set_flags |= QETH_IPA_SETIP_TAKEOVER_FLAG;
 			}
 			list_add_tail(&addr->entry, card->ip_tbd_list);
@@ -301,13 +301,13 @@
 	unsigned long flags;
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 4, "delip");
+	QETH_CARD_TEXT(card, 4, "delip");
 
 	if (addr->proto == QETH_PROT_IPV4)
-		QETH_DBF_HEX(TRACE, 4, &addr->u.a4.addr, 4);
+		QETH_CARD_HEX(card, 4, &addr->u.a4.addr, 4);
 	else {
-		QETH_DBF_HEX(TRACE, 4, &addr->u.a6.addr, 8);
-		QETH_DBF_HEX(TRACE, 4, ((char *)&addr->u.a6.addr) + 8, 8);
+		QETH_CARD_HEX(card, 4, &addr->u.a6.addr, 8);
+		QETH_CARD_HEX(card, 4, ((char *)&addr->u.a6.addr) + 8, 8);
 	}
 	spin_lock_irqsave(&card->ip_lock, flags);
 	rc = __qeth_l3_insert_ip_todo(card, addr, 0);
@@ -320,12 +320,12 @@
 	unsigned long flags;
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 4, "addip");
+	QETH_CARD_TEXT(card, 4, "addip");
 	if (addr->proto == QETH_PROT_IPV4)
-		QETH_DBF_HEX(TRACE, 4, &addr->u.a4.addr, 4);
+		QETH_CARD_HEX(card, 4, &addr->u.a4.addr, 4);
 	else {
-		QETH_DBF_HEX(TRACE, 4, &addr->u.a6.addr, 8);
-		QETH_DBF_HEX(TRACE, 4, ((char *)&addr->u.a6.addr) + 8, 8);
+		QETH_CARD_HEX(card, 4, &addr->u.a6.addr, 8);
+		QETH_CARD_HEX(card, 4, ((char *)&addr->u.a6.addr) + 8, 8);
 	}
 	spin_lock_irqsave(&card->ip_lock, flags);
 	rc = __qeth_l3_insert_ip_todo(card, addr, 1);
@@ -353,10 +353,10 @@
 	struct qeth_ipaddr *iptodo;
 	unsigned long flags;
 
-	QETH_DBF_TEXT(TRACE, 4, "delmc");
+	QETH_CARD_TEXT(card, 4, "delmc");
 	iptodo = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
 	if (!iptodo) {
-		QETH_DBF_TEXT(TRACE, 2, "dmcnomem");
+		QETH_CARD_TEXT(card, 2, "dmcnomem");
 		return;
 	}
 	iptodo->type = QETH_IP_TYPE_DEL_ALL_MC;
@@ -457,8 +457,8 @@
 	unsigned long flags;
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 2, "sdiplist");
-	QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *));
+	QETH_CARD_TEXT(card, 2, "sdiplist");
+	QETH_CARD_HEX(card, 2, &card, sizeof(void *));
 
 	if (card->options.sniffer)
 		return;
@@ -466,7 +466,7 @@
 	tbd_list = card->ip_tbd_list;
 	card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC);
 	if (!card->ip_tbd_list) {
-		QETH_DBF_TEXT(TRACE, 0, "silnomem");
+		QETH_CARD_TEXT(card, 0, "silnomem");
 		card->ip_tbd_list = tbd_list;
 		spin_unlock_irqrestore(&card->ip_lock, flags);
 		return;
@@ -517,7 +517,7 @@
 	struct qeth_ipaddr *addr, *tmp;
 	unsigned long flags;
 
-	QETH_DBF_TEXT(TRACE, 4, "clearip");
+	QETH_CARD_TEXT(card, 4, "clearip");
 	if (recover && card->options.sniffer)
 		return;
 	spin_lock_irqsave(&card->ip_lock, flags);
@@ -577,7 +577,7 @@
 	struct qeth_cmd_buffer *iob;
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 4, "setdelmc");
+	QETH_CARD_TEXT(card, 4, "setdelmc");
 
 	iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
 	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
@@ -615,8 +615,8 @@
 	struct qeth_ipa_cmd *cmd;
 	__u8 netmask[16];
 
-	QETH_DBF_TEXT(TRACE, 4, "setdelip");
-	QETH_DBF_TEXT_(TRACE, 4, "flags%02X", flags);
+	QETH_CARD_TEXT(card, 4, "setdelip");
+	QETH_CARD_TEXT_(card, 4, "flags%02X", flags);
 
 	iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
 	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
@@ -645,7 +645,7 @@
 	struct qeth_ipa_cmd *cmd;
 	struct qeth_cmd_buffer *iob;
 
-	QETH_DBF_TEXT(TRACE, 4, "setroutg");
+	QETH_CARD_TEXT(card, 4, "setroutg");
 	iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETRTG, prot);
 	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
 	cmd->data.setrtg.type = (type);
@@ -689,7 +689,7 @@
 {
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "setrtg4");
+	QETH_CARD_TEXT(card, 3, "setrtg4");
 
 	qeth_l3_correct_routing_type(card, &card->options.route4.type,
 				  QETH_PROT_IPV4);
@@ -709,7 +709,7 @@
 {
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 3, "setrtg6");
+	QETH_CARD_TEXT(card, 3, "setrtg6");
 #ifdef CONFIG_QETH_IPV6
 
 	if (!qeth_is_supported(card, IPA_IPV6))
@@ -753,7 +753,7 @@
 	unsigned long flags;
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 2, "addipato");
+	QETH_CARD_TEXT(card, 2, "addipato");
 	spin_lock_irqsave(&card->ip_lock, flags);
 	list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
 		if (ipatoe->proto != new->proto)
@@ -778,7 +778,7 @@
 	struct qeth_ipato_entry *ipatoe, *tmp;
 	unsigned long flags;
 
-	QETH_DBF_TEXT(TRACE, 2, "delipato");
+	QETH_CARD_TEXT(card, 2, "delipato");
 	spin_lock_irqsave(&card->ip_lock, flags);
 	list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry) {
 		if (ipatoe->proto != proto)
@@ -806,11 +806,11 @@
 	ipaddr = qeth_l3_get_addr_buffer(proto);
 	if (ipaddr) {
 		if (proto == QETH_PROT_IPV4) {
-			QETH_DBF_TEXT(TRACE, 2, "addvipa4");
+			QETH_CARD_TEXT(card, 2, "addvipa4");
 			memcpy(&ipaddr->u.a4.addr, addr, 4);
 			ipaddr->u.a4.mask = 0;
 		} else if (proto == QETH_PROT_IPV6) {
-			QETH_DBF_TEXT(TRACE, 2, "addvipa6");
+			QETH_CARD_TEXT(card, 2, "addvipa6");
 			memcpy(&ipaddr->u.a6.addr, addr, 16);
 			ipaddr->u.a6.pfxlen = 0;
 		}
@@ -841,11 +841,11 @@
 	ipaddr = qeth_l3_get_addr_buffer(proto);
 	if (ipaddr) {
 		if (proto == QETH_PROT_IPV4) {
-			QETH_DBF_TEXT(TRACE, 2, "delvipa4");
+			QETH_CARD_TEXT(card, 2, "delvipa4");
 			memcpy(&ipaddr->u.a4.addr, addr, 4);
 			ipaddr->u.a4.mask = 0;
 		} else if (proto == QETH_PROT_IPV6) {
-			QETH_DBF_TEXT(TRACE, 2, "delvipa6");
+			QETH_CARD_TEXT(card, 2, "delvipa6");
 			memcpy(&ipaddr->u.a6.addr, addr, 16);
 			ipaddr->u.a6.pfxlen = 0;
 		}
@@ -870,11 +870,11 @@
 	ipaddr = qeth_l3_get_addr_buffer(proto);
 	if (ipaddr) {
 		if (proto == QETH_PROT_IPV4) {
-			QETH_DBF_TEXT(TRACE, 2, "addrxip4");
+			QETH_CARD_TEXT(card, 2, "addrxip4");
 			memcpy(&ipaddr->u.a4.addr, addr, 4);
 			ipaddr->u.a4.mask = 0;
 		} else if (proto == QETH_PROT_IPV6) {
-			QETH_DBF_TEXT(TRACE, 2, "addrxip6");
+			QETH_CARD_TEXT(card, 2, "addrxip6");
 			memcpy(&ipaddr->u.a6.addr, addr, 16);
 			ipaddr->u.a6.pfxlen = 0;
 		}
@@ -905,11 +905,11 @@
 	ipaddr = qeth_l3_get_addr_buffer(proto);
 	if (ipaddr) {
 		if (proto == QETH_PROT_IPV4) {
-			QETH_DBF_TEXT(TRACE, 2, "addrxip4");
+			QETH_CARD_TEXT(card, 2, "addrxip4");
 			memcpy(&ipaddr->u.a4.addr, addr, 4);
 			ipaddr->u.a4.mask = 0;
 		} else if (proto == QETH_PROT_IPV6) {
-			QETH_DBF_TEXT(TRACE, 2, "addrxip6");
+			QETH_CARD_TEXT(card, 2, "addrxip6");
 			memcpy(&ipaddr->u.a6.addr, addr, 16);
 			ipaddr->u.a6.pfxlen = 0;
 		}
@@ -929,15 +929,15 @@
 	int cnt = 3;
 
 	if (addr->proto == QETH_PROT_IPV4) {
-		QETH_DBF_TEXT(TRACE, 2, "setaddr4");
-		QETH_DBF_HEX(TRACE, 3, &addr->u.a4.addr, sizeof(int));
+		QETH_CARD_TEXT(card, 2, "setaddr4");
+		QETH_CARD_HEX(card, 3, &addr->u.a4.addr, sizeof(int));
 	} else if (addr->proto == QETH_PROT_IPV6) {
-		QETH_DBF_TEXT(TRACE, 2, "setaddr6");
-		QETH_DBF_HEX(TRACE, 3, &addr->u.a6.addr, 8);
-		QETH_DBF_HEX(TRACE, 3, ((char *)&addr->u.a6.addr) + 8, 8);
+		QETH_CARD_TEXT(card, 2, "setaddr6");
+		QETH_CARD_HEX(card, 3, &addr->u.a6.addr, 8);
+		QETH_CARD_HEX(card, 3, ((char *)&addr->u.a6.addr) + 8, 8);
 	} else {
-		QETH_DBF_TEXT(TRACE, 2, "setaddr?");
-		QETH_DBF_HEX(TRACE, 3, addr, sizeof(struct qeth_ipaddr));
+		QETH_CARD_TEXT(card, 2, "setaddr?");
+		QETH_CARD_HEX(card, 3, addr, sizeof(struct qeth_ipaddr));
 	}
 	do {
 		if (addr->is_multicast)
@@ -946,10 +946,10 @@
 			rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_SETIP,
 					addr->set_flags);
 		if (rc)
-			QETH_DBF_TEXT(TRACE, 2, "failed");
+			QETH_CARD_TEXT(card, 2, "failed");
 	} while ((--cnt > 0) && rc);
 	if (rc) {
-		QETH_DBF_TEXT(TRACE, 2, "FAILED");
+		QETH_CARD_TEXT(card, 2, "FAILED");
 		qeth_l3_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf);
 		dev_warn(&card->gdev->dev,
 			"Registering IP address %s failed\n", buf);
@@ -963,15 +963,15 @@
 	int rc = 0;
 
 	if (addr->proto == QETH_PROT_IPV4) {
-		QETH_DBF_TEXT(TRACE, 2, "deladdr4");
-		QETH_DBF_HEX(TRACE, 3, &addr->u.a4.addr, sizeof(int));
+		QETH_CARD_TEXT(card, 2, "deladdr4");
+		QETH_CARD_HEX(card, 3, &addr->u.a4.addr, sizeof(int));
 	} else if (addr->proto == QETH_PROT_IPV6) {
-		QETH_DBF_TEXT(TRACE, 2, "deladdr6");
-		QETH_DBF_HEX(TRACE, 3, &addr->u.a6.addr, 8);
-		QETH_DBF_HEX(TRACE, 3, ((char *)&addr->u.a6.addr) + 8, 8);
+		QETH_CARD_TEXT(card, 2, "deladdr6");
+		QETH_CARD_HEX(card, 3, &addr->u.a6.addr, 8);
+		QETH_CARD_HEX(card, 3, ((char *)&addr->u.a6.addr) + 8, 8);
 	} else {
-		QETH_DBF_TEXT(TRACE, 2, "deladdr?");
-		QETH_DBF_HEX(TRACE, 3, addr, sizeof(struct qeth_ipaddr));
+		QETH_CARD_TEXT(card, 2, "deladdr?");
+		QETH_CARD_HEX(card, 3, addr, sizeof(struct qeth_ipaddr));
 	}
 	if (addr->is_multicast)
 		rc = qeth_l3_send_setdelmc(card, addr, IPA_CMD_DELIPM);
@@ -979,7 +979,7 @@
 		rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_DELIP,
 					addr->del_flags);
 	if (rc)
-		QETH_DBF_TEXT(TRACE, 2, "failed");
+		QETH_CARD_TEXT(card, 2, "failed");
 
 	return rc;
 }
@@ -1012,7 +1012,7 @@
 	struct qeth_cmd_buffer *iob;
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 4, "adpmode");
+	QETH_CARD_TEXT(card, 4, "adpmode");
 
 	iob = qeth_get_adapter_cmd(card, command,
 				   sizeof(struct qeth_ipacmd_setadpparms));
@@ -1027,7 +1027,7 @@
 {
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 4, "adphstr");
+	QETH_CARD_TEXT(card, 4, "adphstr");
 
 	if (qeth_adp_supported(card, IPA_SETADP_SET_BROADCAST_MODE)) {
 		rc = qeth_l3_send_setadp_mode(card,
@@ -1093,7 +1093,7 @@
 {
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 4, "defadpcb");
+	QETH_CARD_TEXT(card, 4, "defadpcb");
 
 	cmd = (struct qeth_ipa_cmd *) data;
 	if (cmd->hdr.return_code == 0) {
@@ -1106,13 +1106,13 @@
 	if (cmd->data.setassparms.hdr.assist_no == IPA_INBOUND_CHECKSUM &&
 	    cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_START) {
 		card->info.csum_mask = cmd->data.setassparms.data.flags_32bit;
-		QETH_DBF_TEXT_(TRACE, 3, "csum:%d", card->info.csum_mask);
+		QETH_CARD_TEXT_(card, 3, "csum:%d", card->info.csum_mask);
 	}
 	if (cmd->data.setassparms.hdr.assist_no == IPA_OUTBOUND_CHECKSUM &&
 	    cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_START) {
 		card->info.tx_csum_mask =
 			cmd->data.setassparms.data.flags_32bit;
-		QETH_DBF_TEXT_(TRACE, 3, "tcsu:%d", card->info.tx_csum_mask);
+		QETH_CARD_TEXT_(card, 3, "tcsu:%d", card->info.tx_csum_mask);
 	}
 
 	return 0;
@@ -1125,7 +1125,7 @@
 	struct qeth_cmd_buffer *iob;
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 4, "getasscm");
+	QETH_CARD_TEXT(card, 4, "getasscm");
 	iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETASSPARMS, prot);
 
 	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
@@ -1147,7 +1147,7 @@
 	int rc;
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 4, "sendassp");
+	QETH_CARD_TEXT(card, 4, "sendassp");
 
 	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
 	if (len <= sizeof(__u32))
@@ -1166,7 +1166,7 @@
 	int rc;
 	struct qeth_cmd_buffer *iob;
 
-	QETH_DBF_TEXT(TRACE, 4, "simassp6");
+	QETH_CARD_TEXT(card, 4, "simassp6");
 	iob = qeth_l3_get_setassparms_cmd(card, ipa_func, cmd_code,
 				       0, QETH_PROT_IPV6);
 	rc = qeth_l3_send_setassparms(card, iob, 0, 0,
@@ -1182,7 +1182,7 @@
 	int length = 0;
 	struct qeth_cmd_buffer *iob;
 
-	QETH_DBF_TEXT(TRACE, 4, "simassp4");
+	QETH_CARD_TEXT(card, 4, "simassp4");
 	if (data)
 		length = sizeof(__u32);
 	iob = qeth_l3_get_setassparms_cmd(card, ipa_func, cmd_code,
@@ -1196,7 +1196,7 @@
 {
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "ipaarp");
+	QETH_CARD_TEXT(card, 3, "ipaarp");
 
 	if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
 		dev_info(&card->gdev->dev,
@@ -1218,7 +1218,7 @@
 {
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "ipaipfrg");
+	QETH_CARD_TEXT(card, 3, "ipaipfrg");
 
 	if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) {
 		dev_info(&card->gdev->dev,
@@ -1243,7 +1243,7 @@
 {
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "stsrcmac");
+	QETH_CARD_TEXT(card, 3, "stsrcmac");
 
 	if (!qeth_is_supported(card, IPA_SOURCE_MAC)) {
 		dev_info(&card->gdev->dev,
@@ -1265,7 +1265,7 @@
 {
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 3, "strtvlan");
+	QETH_CARD_TEXT(card, 3, "strtvlan");
 
 	if (!qeth_is_supported(card, IPA_FULL_VLAN)) {
 		dev_info(&card->gdev->dev,
@@ -1289,7 +1289,7 @@
 {
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "stmcast");
+	QETH_CARD_TEXT(card, 3, "stmcast");
 
 	if (!qeth_is_supported(card, IPA_MULTICASTING)) {
 		dev_info(&card->gdev->dev,
@@ -1349,7 +1349,7 @@
 {
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "softipv6");
+	QETH_CARD_TEXT(card, 3, "softipv6");
 
 	if (card->info.type == QETH_CARD_TYPE_IQD)
 		goto out;
@@ -1395,7 +1395,7 @@
 {
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 3, "strtipv6");
+	QETH_CARD_TEXT(card, 3, "strtipv6");
 
 	if (!qeth_is_supported(card, IPA_IPV6)) {
 		dev_info(&card->gdev->dev,
@@ -1412,7 +1412,7 @@
 {
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "stbrdcst");
+	QETH_CARD_TEXT(card, 3, "stbrdcst");
 	card->info.broadcast_capable = 0;
 	if (!qeth_is_supported(card, IPA_FILTERING)) {
 		dev_info(&card->gdev->dev,
@@ -1512,7 +1512,7 @@
 {
 	int rc = 0;
 
-	QETH_DBF_TEXT(TRACE, 3, "strtcsum");
+	QETH_CARD_TEXT(card, 3, "strtcsum");
 
 	if (card->options.checksum_type == NO_CHECKSUMMING) {
 		dev_info(&card->gdev->dev,
@@ -1569,7 +1569,7 @@
 {
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "sttso");
+	QETH_CARD_TEXT(card, 3, "sttso");
 
 	if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
 		dev_info(&card->gdev->dev,
@@ -1596,7 +1596,7 @@
 
 static int qeth_l3_start_ipassists(struct qeth_card *card)
 {
-	QETH_DBF_TEXT(TRACE, 3, "strtipas");
+	QETH_CARD_TEXT(card, 3, "strtipas");
 
 	qeth_set_access_ctrl_online(card);	/* go on*/
 	qeth_l3_start_ipa_arp_processing(card);	/* go on*/
@@ -1619,7 +1619,7 @@
 	struct qeth_cmd_buffer *iob;
 	struct qeth_ipa_cmd *cmd;
 
-	QETH_DBF_TEXT(TRACE, 2, "puniqeid");
+	QETH_CARD_TEXT(card, 2, "puniqeid");
 
 	if ((card->info.unique_id & UNIQUE_ID_NOT_BY_CARD) ==
 		UNIQUE_ID_NOT_BY_CARD)
@@ -1723,7 +1723,7 @@
 	cmd = (struct qeth_ipa_cmd *)data;
 	rc = cmd->hdr.return_code;
 	if (rc)
-		QETH_DBF_TEXT_(TRACE, 2, "dxter%x", rc);
+		QETH_CARD_TEXT_(card, 2, "dxter%x", rc);
 	switch (cmd->data.diagass.action) {
 	case QETH_DIAGS_CMD_TRACE_QUERY:
 		break;
@@ -1800,7 +1800,7 @@
 	struct ip_mc_list *im4;
 	char buf[MAX_ADDR_LEN];
 
-	QETH_DBF_TEXT(TRACE, 4, "addmc");
+	QETH_CARD_TEXT(card, 4, "addmc");
 	for (im4 = in4_dev->mc_list; im4; im4 = im4->next) {
 		qeth_l3_get_mac_for_ipm(im4->multiaddr, buf, in4_dev->dev);
 		ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
@@ -1820,7 +1820,7 @@
 	struct vlan_group *vg;
 	int i;
 
-	QETH_DBF_TEXT(TRACE, 4, "addmcvl");
+	QETH_CARD_TEXT(card, 4, "addmcvl");
 	if (!qeth_is_supported(card, IPA_FULL_VLAN) || (card->vlangrp == NULL))
 		return;
 
@@ -1844,7 +1844,7 @@
 {
 	struct in_device *in4_dev;
 
-	QETH_DBF_TEXT(TRACE, 4, "chkmcv4");
+	QETH_CARD_TEXT(card, 4, "chkmcv4");
 	in4_dev = in_dev_get(card->dev);
 	if (in4_dev == NULL)
 		return;
@@ -1862,7 +1862,7 @@
 	struct ifmcaddr6 *im6;
 	char buf[MAX_ADDR_LEN];
 
-	QETH_DBF_TEXT(TRACE, 4, "addmc6");
+	QETH_CARD_TEXT(card, 4, "addmc6");
 	for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
 		ndisc_mc_map(&im6->mca_addr, buf, in6_dev->dev, 0);
 		ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
@@ -1883,7 +1883,7 @@
 	struct vlan_group *vg;
 	int i;
 
-	QETH_DBF_TEXT(TRACE, 4, "admc6vl");
+	QETH_CARD_TEXT(card, 4, "admc6vl");
 	if (!qeth_is_supported(card, IPA_FULL_VLAN) || (card->vlangrp == NULL))
 		return;
 
@@ -1907,7 +1907,7 @@
 {
 	struct inet6_dev *in6_dev;
 
-	QETH_DBF_TEXT(TRACE, 4, "chkmcv6");
+	QETH_CARD_TEXT(card, 4, "chkmcv6");
 	if (!qeth_is_supported(card, IPA_IPV6))
 		return ;
 	in6_dev = in6_dev_get(card->dev);
@@ -1928,7 +1928,7 @@
 	struct in_ifaddr *ifa;
 	struct qeth_ipaddr *addr;
 
-	QETH_DBF_TEXT(TRACE, 4, "frvaddr4");
+	QETH_CARD_TEXT(card, 4, "frvaddr4");
 
 	in_dev = in_dev_get(vlan_group_get_device(card->vlangrp, vid));
 	if (!in_dev)
@@ -1954,7 +1954,7 @@
 	struct inet6_ifaddr *ifa;
 	struct qeth_ipaddr *addr;
 
-	QETH_DBF_TEXT(TRACE, 4, "frvaddr6");
+	QETH_CARD_TEXT(card, 4, "frvaddr6");
 
 	in6_dev = in6_dev_get(vlan_group_get_device(card->vlangrp, vid));
 	if (!in6_dev)
@@ -1989,7 +1989,7 @@
 	struct qeth_card *card = dev->ml_priv;
 	unsigned long flags;
 
-	QETH_DBF_TEXT(TRACE, 4, "vlanreg");
+	QETH_CARD_TEXT(card, 4, "vlanreg");
 	spin_lock_irqsave(&card->vlanlock, flags);
 	card->vlangrp = grp;
 	spin_unlock_irqrestore(&card->vlanlock, flags);
@@ -2005,9 +2005,9 @@
 	struct qeth_card *card = dev->ml_priv;
 	unsigned long flags;
 
-	QETH_DBF_TEXT_(TRACE, 4, "kid:%d", vid);
+	QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
 	if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
-		QETH_DBF_TEXT(TRACE, 3, "kidREC");
+		QETH_CARD_TEXT(card, 3, "kidREC");
 		return;
 	}
 	spin_lock_irqsave(&card->vlanlock, flags);
@@ -2162,7 +2162,7 @@
 			break;
 		default:
 			dev_kfree_skb_any(skb);
-			QETH_DBF_TEXT(TRACE, 3, "inbunkno");
+			QETH_CARD_TEXT(card, 3, "inbunkno");
 			QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN);
 			continue;
 		}
@@ -2229,7 +2229,8 @@
 		card = vlan_dev_real_dev(dev)->ml_priv;
 	if (card && card->options.layer2)
 		card = NULL;
-	QETH_DBF_TEXT_(TRACE, 4, "%d", rc);
+	if (card)
+		QETH_CARD_TEXT_(card, 4, "%d", rc);
 	return card ;
 }
 
@@ -2307,10 +2308,10 @@
 	} else if (card->options.sniffer &&	/* HiperSockets trace */
 		   qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) {
 		if (dev->flags & IFF_PROMISC) {
-			QETH_DBF_TEXT(TRACE, 3, "+promisc");
+			QETH_CARD_TEXT(card, 3, "+promisc");
 			qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_ENABLE);
 		} else {
-			QETH_DBF_TEXT(TRACE, 3, "-promisc");
+			QETH_CARD_TEXT(card, 3, "-promisc");
 			qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE);
 		}
 	}
@@ -2320,7 +2321,7 @@
 {
 	struct qeth_card *card = dev->ml_priv;
 
-	QETH_DBF_TEXT(TRACE, 3, "setmulti");
+	QETH_CARD_TEXT(card, 3, "setmulti");
 	if (qeth_threads_running(card, QETH_RECOVER_THREAD) &&
 	    (card->state != CARD_STATE_UP))
 		return;
@@ -2365,7 +2366,7 @@
 	int tmp;
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "arpstnoe");
+	QETH_CARD_TEXT(card, 3, "arpstnoe");
 
 	/*
 	 * currently GuestLAN only supports the ARP assist function
@@ -2417,17 +2418,17 @@
 	int uentry_size;
 	int i;
 
-	QETH_DBF_TEXT(TRACE, 4, "arpquecb");
+	QETH_CARD_TEXT(card, 4, "arpquecb");
 
 	qinfo = (struct qeth_arp_query_info *) reply->param;
 	cmd = (struct qeth_ipa_cmd *) data;
 	if (cmd->hdr.return_code) {
-		QETH_DBF_TEXT_(TRACE, 4, "qaer1%i", cmd->hdr.return_code);
+		QETH_CARD_TEXT_(card, 4, "qaer1%i", cmd->hdr.return_code);
 		return 0;
 	}
 	if (cmd->data.setassparms.hdr.return_code) {
 		cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
-		QETH_DBF_TEXT_(TRACE, 4, "qaer2%i", cmd->hdr.return_code);
+		QETH_CARD_TEXT_(card, 4, "qaer2%i", cmd->hdr.return_code);
 		return 0;
 	}
 	qdata = &cmd->data.setassparms.data.query_arp;
@@ -2449,14 +2450,14 @@
 	/* check if there is enough room in userspace */
 	if ((qinfo->udata_len - qinfo->udata_offset) <
 			qdata->no_entries * uentry_size){
-		QETH_DBF_TEXT_(TRACE, 4, "qaer3%i", -ENOMEM);
+		QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM);
 		cmd->hdr.return_code = -ENOMEM;
 		goto out_error;
 	}
-	QETH_DBF_TEXT_(TRACE, 4, "anore%i",
+	QETH_CARD_TEXT_(card, 4, "anore%i",
 		       cmd->data.setassparms.hdr.number_of_replies);
-	QETH_DBF_TEXT_(TRACE, 4, "aseqn%i", cmd->data.setassparms.hdr.seq_no);
-	QETH_DBF_TEXT_(TRACE, 4, "anoen%i", qdata->no_entries);
+	QETH_CARD_TEXT_(card, 4, "aseqn%i", cmd->data.setassparms.hdr.seq_no);
+	QETH_CARD_TEXT_(card, 4, "anoen%i", qdata->no_entries);
 
 	if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) {
 		/* strip off "media specific information" */
@@ -2492,7 +2493,7 @@
 			unsigned long),
 		void *reply_param)
 {
-	QETH_DBF_TEXT(TRACE, 4, "sendarp");
+	QETH_CARD_TEXT(card, 4, "sendarp");
 
 	memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
 	memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data),
@@ -2508,7 +2509,7 @@
 	int tmp;
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "arpquery");
+	QETH_CARD_TEXT(card, 3, "arpquery");
 
 	if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/
 			       IPA_ARP_PROCESSING)) {
@@ -2551,7 +2552,7 @@
 	int tmp;
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "arpadent");
+	QETH_CARD_TEXT(card, 3, "arpadent");
 
 	/*
 	 * currently GuestLAN only supports the ARP assist function
@@ -2590,7 +2591,7 @@
 	int tmp;
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 3, "arprment");
+	QETH_CARD_TEXT(card, 3, "arprment");
 
 	/*
 	 * currently GuestLAN only supports the ARP assist function
@@ -2626,7 +2627,7 @@
 	int rc;
 	int tmp;
 
-	QETH_DBF_TEXT(TRACE, 3, "arpflush");
+	QETH_CARD_TEXT(card, 3, "arpflush");
 
 	/*
 	 * currently GuestLAN only supports the ARP assist function
@@ -2734,7 +2735,7 @@
 		rc = -EOPNOTSUPP;
 	}
 	if (rc)
-		QETH_DBF_TEXT_(TRACE, 2, "ioce%d", rc);
+		QETH_CARD_TEXT_(card, 2, "ioce%d", rc);
 	return rc;
 }
 
@@ -2903,19 +2904,11 @@
 	unsigned long tcpd = (unsigned long)tcp_hdr(skb) +
 		tcp_hdr(skb)->doff * 4;
 	int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data);
-	int elements = PFN_UP(tcpd + tcpd_len) - PFN_DOWN(tcpd);
+	int elements = PFN_UP(tcpd + tcpd_len - 1) - PFN_DOWN(tcpd);
 	elements += skb_shinfo(skb)->nr_frags;
 	return elements;
 }
 
-static inline int qeth_l3_tso_check(struct sk_buff *skb)
-{
-	int len = ((unsigned long)tcp_hdr(skb) + tcp_hdr(skb)->doff * 4) -
-		(unsigned long)skb->data;
-	return (((unsigned long)skb->data & PAGE_MASK) !=
-		(((unsigned long)skb->data + len) & PAGE_MASK));
-}
-
 static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	int rc;
@@ -3015,8 +3008,6 @@
 	    (cast_type == RTN_UNSPEC)) {
 		hdr = (struct qeth_hdr *)skb_push(new_skb,
 						sizeof(struct qeth_hdr_tso));
-		if (qeth_l3_tso_check(new_skb))
-			QETH_DBF_MESSAGE(2, "tso skb misaligned\n");
 		memset(hdr, 0, sizeof(struct qeth_hdr_tso));
 		qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type);
 		qeth_tso_fill_header(card, hdr, new_skb);
@@ -3047,10 +3038,20 @@
 	elements_needed += elems;
 	nr_frags = skb_shinfo(new_skb)->nr_frags;
 
-	if (card->info.type != QETH_CARD_TYPE_IQD)
+	if (card->info.type != QETH_CARD_TYPE_IQD) {
+		int len;
+		if (large_send == QETH_LARGE_SEND_TSO)
+			len = ((unsigned long)tcp_hdr(new_skb) +
+				tcp_hdr(new_skb)->doff * 4) -
+				(unsigned long)new_skb->data;
+		else
+			len = sizeof(struct qeth_hdr_layer3);
+
+		if (qeth_hdr_chk_and_bounce(new_skb, len))
+			goto tx_drop;
 		rc = qeth_do_send_packet(card, queue, new_skb, hdr,
 					 elements_needed);
-	else
+	} else
 		rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
 					elements_needed, data_offset, 0);
 
@@ -3103,7 +3104,7 @@
 {
 	struct qeth_card *card = dev->ml_priv;
 
-	QETH_DBF_TEXT(TRACE, 4, "qethopen");
+	QETH_CARD_TEXT(card, 4, "qethopen");
 	if (card->state != CARD_STATE_SOFTSETUP)
 		return -ENODEV;
 	card->data.state = CH_STATE_UP;
@@ -3119,7 +3120,7 @@
 {
 	struct qeth_card *card = dev->ml_priv;
 
-	QETH_DBF_TEXT(TRACE, 4, "qethstop");
+	QETH_CARD_TEXT(card, 4, "qethstop");
 	netif_tx_disable(dev);
 	if (card->state == CARD_STATE_UP)
 		card->state = CARD_STATE_SOFTSETUP;
@@ -3312,11 +3313,10 @@
 		card->perf_stats.inbound_start_time = qeth_get_micros();
 	}
 	if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
-		QETH_DBF_TEXT(TRACE, 1, "qdinchk");
-		QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
-		QETH_DBF_TEXT_(TRACE, 1, "%04X%04X",
+		QETH_CARD_TEXT(card, 1, "qdinchk");
+		QETH_CARD_TEXT_(card, 1, "%04X%04X",
 				first_element, count);
-		QETH_DBF_TEXT_(TRACE, 1, "%04X", queue);
+		QETH_CARD_TEXT_(card, 1, "%04X", queue);
 		qeth_schedule_recovery(card);
 		return;
 	}
@@ -3354,6 +3354,8 @@
 {
 	struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
 
+	qeth_l3_remove_device_attributes(&cgdev->dev);
+
 	qeth_set_allowed_threads(card, 0, 1);
 	wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
 
@@ -3367,7 +3369,6 @@
 		card->dev = NULL;
 	}
 
-	qeth_l3_remove_device_attributes(&cgdev->dev);
 	qeth_l3_clear_ip_list(card, 0, 0);
 	qeth_l3_clear_ipato_list(card);
 	return;
@@ -3380,6 +3381,7 @@
 	enum qeth_card_states recover_flag;
 
 	BUG_ON(!card);
+	mutex_lock(&card->discipline_mutex);
 	mutex_lock(&card->conf_mutex);
 	QETH_DBF_TEXT(SETUP, 2, "setonlin");
 	QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
@@ -3461,6 +3463,7 @@
 	kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
 out:
 	mutex_unlock(&card->conf_mutex);
+	mutex_unlock(&card->discipline_mutex);
 	return 0;
 out_remove:
 	card->use_hard_stop = 1;
@@ -3473,6 +3476,7 @@
 	else
 		card->state = CARD_STATE_DOWN;
 	mutex_unlock(&card->conf_mutex);
+	mutex_unlock(&card->discipline_mutex);
 	return rc;
 }
 
@@ -3488,6 +3492,7 @@
 	int rc = 0, rc2 = 0, rc3 = 0;
 	enum qeth_card_states recover_flag;
 
+	mutex_lock(&card->discipline_mutex);
 	mutex_lock(&card->conf_mutex);
 	QETH_DBF_TEXT(SETUP, 3, "setoffl");
 	QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
@@ -3508,6 +3513,7 @@
 	/* let user_space know that device is offline */
 	kobject_uevent(&cgdev->dev.kobj, KOBJ_CHANGE);
 	mutex_unlock(&card->conf_mutex);
+	mutex_unlock(&card->discipline_mutex);
 	return 0;
 }
 
@@ -3522,11 +3528,11 @@
 	int rc = 0;
 
 	card = (struct qeth_card *) ptr;
-	QETH_DBF_TEXT(TRACE, 2, "recover1");
-	QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *));
+	QETH_CARD_TEXT(card, 2, "recover1");
+	QETH_CARD_HEX(card, 2, &card, sizeof(void *));
 	if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD))
 		return 0;
-	QETH_DBF_TEXT(TRACE, 2, "recover2");
+	QETH_CARD_TEXT(card, 2, "recover2");
 	dev_warn(&card->gdev->dev,
 		"A recovery process has been started for the device\n");
 	card->use_hard_stop = 1;
@@ -3624,8 +3630,8 @@
 	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
-	QETH_DBF_TEXT(TRACE, 3, "ipevent");
 	card = qeth_l3_get_card_from_dev(dev);
+	QETH_CARD_TEXT(card, 3, "ipevent");
 	if (!card)
 		return NOTIFY_DONE;
 
@@ -3671,11 +3677,11 @@
 	struct qeth_ipaddr *addr;
 	struct qeth_card *card;
 
-	QETH_DBF_TEXT(TRACE, 3, "ip6event");
 
 	card = qeth_l3_get_card_from_dev(dev);
 	if (!card)
 		return NOTIFY_DONE;
+	QETH_CARD_TEXT(card, 3, "ip6event");
 	if (!qeth_is_supported(card, IPA_IPV6))
 		return NOTIFY_DONE;
 
@@ -3714,7 +3720,7 @@
 {
 	int rc;
 
-	QETH_DBF_TEXT(TRACE, 5, "regnotif");
+	QETH_DBF_TEXT(SETUP, 5, "regnotif");
 	rc = register_inetaddr_notifier(&qeth_l3_ip_notifier);
 	if (rc)
 		return rc;
@@ -3733,7 +3739,7 @@
 static void qeth_l3_unregister_notifiers(void)
 {
 
-	QETH_DBF_TEXT(TRACE, 5, "unregnot");
+	QETH_DBF_TEXT(SETUP, 5, "unregnot");
 	BUG_ON(unregister_inetaddr_notifier(&qeth_l3_ip_notifier));
 #ifdef CONFIG_QETH_IPV6
 	BUG_ON(unregister_inet6addr_notifier(&qeth_l3_ip6_notifier));
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index fb5318b..67cfa68 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -479,6 +479,7 @@
 		struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct qeth_card *card = dev_get_drvdata(dev);
+	struct qeth_ipaddr *tmpipa, *t;
 	char *tmp;
 	int rc = 0;
 
@@ -497,8 +498,21 @@
 		card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
 	} else if (!strcmp(tmp, "1")) {
 		card->ipato.enabled = 1;
+		list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
+			if ((tmpipa->type == QETH_IP_TYPE_NORMAL) &&
+				qeth_l3_is_addr_covered_by_ipato(card, tmpipa))
+				tmpipa->set_flags |=
+					QETH_IPA_SETIP_TAKEOVER_FLAG;
+		}
+
 	} else if (!strcmp(tmp, "0")) {
 		card->ipato.enabled = 0;
+		list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
+			if (tmpipa->set_flags &
+				QETH_IPA_SETIP_TAKEOVER_FLAG)
+				tmpipa->set_flags &=
+					~QETH_IPA_SETIP_TAKEOVER_FLAG;
+		}
 	} else
 		rc = -EINVAL;
 out:
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index 7049127..65e1cf1 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -47,6 +47,7 @@
 
 static DEFINE_SPINLOCK(smsg_list_lock);
 static LIST_HEAD(smsg_list);
+static int iucv_path_connected;
 
 static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
 static void smsg_message_pending(struct iucv_path *, struct iucv_message *);
@@ -142,8 +143,10 @@
 #ifdef CONFIG_PM_DEBUG
 	printk(KERN_WARNING "smsg_pm_freeze\n");
 #endif
-	if (smsg_path)
+	if (smsg_path && iucv_path_connected) {
 		iucv_path_sever(smsg_path, NULL);
+		iucv_path_connected = 0;
+	}
 	return 0;
 }
 
@@ -154,7 +157,7 @@
 #ifdef CONFIG_PM_DEBUG
 	printk(KERN_WARNING "smsg_pm_restore_thaw\n");
 #endif
-	if (smsg_path) {
+	if (smsg_path && iucv_path_connected) {
 		memset(smsg_path, 0, sizeof(*smsg_path));
 		smsg_path->msglim = 255;
 		smsg_path->flags = 0;
@@ -165,6 +168,8 @@
 			printk(KERN_ERR
 			       "iucv_path_connect returned with rc %i\n", rc);
 #endif
+		if (!rc)
+			iucv_path_connected = 1;
 		cpcmd("SET SMSG IUCV", NULL, 0, NULL);
 	}
 	return 0;
@@ -214,6 +219,8 @@
 			       NULL, NULL, NULL);
 	if (rc)
 		goto out_free_path;
+	else
+		iucv_path_connected = 1;
 	smsg_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
 	if (!smsg_dev) {
 		rc = -ENOMEM;
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index e331df2..96fa1f5 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -98,13 +98,11 @@
 	u64 wwpn, lun;
 
 	/* duplicate devstr and keep the original for sysfs presentation*/
-	str_saved = kmalloc(strlen(devstr) + 1, GFP_KERNEL);
+	str_saved = kstrdup(devstr, GFP_KERNEL);
 	str = str_saved;
 	if (!str)
 		return;
 
-	strcpy(str, devstr);
-
 	token = strsep(&str, ",");
 	if (!token || strlen(token) >= ZFCP_BUS_ID_SIZE)
 		goto err_out;
@@ -314,7 +312,7 @@
 	}
 	retval = -EINVAL;
 
-	INIT_WORK(&unit->scsi_work, zfcp_scsi_scan);
+	INIT_WORK(&unit->scsi_work, zfcp_scsi_scan_work);
 
 	spin_lock_init(&unit->latencies.lock);
 	unit->latencies.write.channel.min = 0xFFFFFFFF;
@@ -526,6 +524,10 @@
 	rwlock_init(&adapter->port_list_lock);
 	INIT_LIST_HEAD(&adapter->port_list);
 
+	INIT_LIST_HEAD(&adapter->events.list);
+	INIT_WORK(&adapter->events.work, zfcp_fc_post_event);
+	spin_lock_init(&adapter->events.list_lock);
+
 	init_waitqueue_head(&adapter->erp_ready_wq);
 	init_waitqueue_head(&adapter->erp_done_wqh);
 
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c
index 1a2db0a..fcbd2b7 100644
--- a/drivers/s390/scsi/zfcp_cfdc.c
+++ b/drivers/s390/scsi/zfcp_cfdc.c
@@ -189,18 +189,12 @@
 	if (!fsf_cfdc)
 		return -ENOMEM;
 
-	data = kmalloc(sizeof(struct zfcp_cfdc_data), GFP_KERNEL);
-	if (!data) {
-		retval = -ENOMEM;
+	data = memdup_user(data_user, sizeof(*data_user));
+	if (IS_ERR(data)) {
+		retval = PTR_ERR(data);
 		goto no_mem_sense;
 	}
 
-	retval = copy_from_user(data, data_user, sizeof(*data));
-	if (retval) {
-		retval = -EFAULT;
-		goto free_buffer;
-	}
-
 	if (data->signature != 0xCFDCACDF) {
 		retval = -EINVAL;
 		goto free_buffer;
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 075852f..a86117b 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -155,6 +155,8 @@
 		if (scsi_cmnd) {
 			response->u.fcp.cmnd = (unsigned long)scsi_cmnd;
 			response->u.fcp.serial = scsi_cmnd->serial_number;
+			response->u.fcp.data_dir =
+				qtcb->bottom.io.data_direction;
 		}
 		break;
 
@@ -326,6 +328,7 @@
 	case FSF_QTCB_FCP_CMND:
 		if (r->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
 			break;
+		zfcp_dbf_out(p, "data_direction", "0x%04x", r->u.fcp.data_dir);
 		zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd);
 		zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial);
 		*p += sprintf(*p, "\n");
@@ -1005,7 +1008,7 @@
 	char dbf_name[DEBUG_MAX_NAME_LEN];
 	struct zfcp_dbf *dbf;
 
-	dbf = kmalloc(sizeof(struct zfcp_dbf), GFP_KERNEL);
+	dbf = kzalloc(sizeof(struct zfcp_dbf), GFP_KERNEL);
 	if (!dbf)
 		return -ENOMEM;
 
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h
index 457e046..2bcc340 100644
--- a/drivers/s390/scsi/zfcp_dbf.h
+++ b/drivers/s390/scsi/zfcp_dbf.h
@@ -111,6 +111,7 @@
 		struct {
 			u64 cmnd;
 			u64 serial;
+			u32 data_dir;
 		} fcp;
 		struct {
 			u64 wwpn;
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 9fa1b06..e1c6b6e 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -37,6 +37,7 @@
 #include <asm/ebcdic.h>
 #include <asm/sysinfo.h>
 #include "zfcp_fsf.h"
+#include "zfcp_fc.h"
 #include "zfcp_qdio.h"
 
 struct zfcp_reqlist;
@@ -72,10 +73,12 @@
 
 /* adapter status */
 #define ZFCP_STATUS_ADAPTER_QDIOUP		0x00000002
+#define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED	0x00000004
 #define ZFCP_STATUS_ADAPTER_XCONFIG_OK		0x00000008
 #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT	0x00000010
 #define ZFCP_STATUS_ADAPTER_ERP_PENDING		0x00000100
 #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED	0x00000200
+#define ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED	0x00000400
 
 /* remote port status */
 #define ZFCP_STATUS_PORT_PHYS_OPEN		0x00000001
@@ -190,6 +193,7 @@
 	struct service_level	service_level;
 	struct workqueue_struct	*work_queue;
 	struct device_dma_parameters dma_parms;
+	struct zfcp_fc_events events;
 };
 
 struct zfcp_port {
@@ -212,6 +216,7 @@
 	struct work_struct     test_link_work;
 	struct work_struct     rport_work;
 	enum { RPORT_NONE, RPORT_ADD, RPORT_DEL }  rport_task;
+	unsigned int		starget_id;
 };
 
 struct zfcp_unit {
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index fd068bc..160b432 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -141,9 +141,13 @@
 		if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
 			need = ZFCP_ERP_ACTION_REOPEN_PORT;
 		/* fall through */
-	case ZFCP_ERP_ACTION_REOPEN_PORT:
 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
 		p_status = atomic_read(&port->status);
+		if (!(p_status & ZFCP_STATUS_COMMON_OPEN))
+			need = ZFCP_ERP_ACTION_REOPEN_PORT;
+		/* fall through */
+	case ZFCP_ERP_ACTION_REOPEN_PORT:
+		p_status = atomic_read(&port->status);
 		if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
 			return 0;
 		a_status = atomic_read(&adapter->status);
@@ -893,8 +897,7 @@
 		}
 		if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
 			port->d_id = 0;
-			_zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL);
-			return ZFCP_ERP_EXIT;
+			return ZFCP_ERP_FAILED;
 		}
 		/* fall through otherwise */
 	}
@@ -1188,19 +1191,14 @@
 
 	switch (act->action) {
 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
-		if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
-			get_device(&unit->dev);
-			if (scsi_queue_work(unit->port->adapter->scsi_host,
-					    &unit->scsi_work) <= 0)
-				put_device(&unit->dev);
-		}
 		put_device(&unit->dev);
 		break;
 
-	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
 	case ZFCP_ERP_ACTION_REOPEN_PORT:
 		if (result == ZFCP_ERP_SUCCEEDED)
 			zfcp_scsi_schedule_rport_register(port);
+		/* fall through */
+	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
 		put_device(&port->dev);
 		break;
 
@@ -1247,6 +1245,11 @@
 		goto unlock;
 	}
 
+	if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
+		retval = ZFCP_ERP_FAILED;
+		goto check_target;
+	}
+
 	zfcp_erp_action_to_running(erp_action);
 
 	/* no lock to allow for blocking operations */
@@ -1279,6 +1282,7 @@
 		goto unlock;
 	}
 
+check_target:
 	retval = zfcp_erp_strategy_check_target(erp_action, retval);
 	zfcp_erp_action_dequeue(erp_action);
 	retval = zfcp_erp_strategy_statechange(erp_action, retval);
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 48a8f93..3b93239 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -96,6 +96,9 @@
 extern void zfcp_erp_timeout_handler(unsigned long);
 
 /* zfcp_fc.c */
+extern void zfcp_fc_enqueue_event(struct zfcp_adapter *,
+				enum fc_host_event_code event_code, u32);
+extern void zfcp_fc_post_event(struct work_struct *);
 extern void zfcp_fc_scan_ports(struct work_struct *);
 extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *);
 extern void zfcp_fc_port_did_lookup(struct work_struct *);
@@ -146,9 +149,10 @@
 extern int zfcp_qdio_sbal_get(struct zfcp_qdio *);
 extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_qdio_req *);
 extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *,
-				   struct scatterlist *, int);
+				   struct scatterlist *);
 extern int zfcp_qdio_open(struct zfcp_qdio *);
 extern void zfcp_qdio_close(struct zfcp_qdio *);
+extern void zfcp_qdio_siosl(struct zfcp_adapter *);
 
 /* zfcp_scsi.c */
 extern struct zfcp_data zfcp_data;
@@ -159,7 +163,10 @@
 extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *);
 extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *);
 extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *);
-extern void zfcp_scsi_scan(struct work_struct *);
+extern void zfcp_scsi_scan(struct zfcp_unit *);
+extern void zfcp_scsi_scan_work(struct work_struct *);
+extern void zfcp_scsi_set_prot(struct zfcp_adapter *);
+extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int);
 
 /* zfcp_sysfs.c */
 extern struct attribute_group zfcp_sysfs_unit_attrs;
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 6f8ab43..6f3ed2b 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -23,6 +23,58 @@
 	[ELS_ADDR_FMT_FAB]		= 0x000000,
 };
 
+/**
+ * zfcp_fc_post_event - post event to userspace via fc_transport
+ * @work: work struct with enqueued events
+ */
+void zfcp_fc_post_event(struct work_struct *work)
+{
+	struct zfcp_fc_event *event = NULL, *tmp = NULL;
+	LIST_HEAD(tmp_lh);
+	struct zfcp_fc_events *events = container_of(work,
+					struct zfcp_fc_events, work);
+	struct zfcp_adapter *adapter = container_of(events, struct zfcp_adapter,
+						events);
+
+	spin_lock_bh(&events->list_lock);
+	list_splice_init(&events->list, &tmp_lh);
+	spin_unlock_bh(&events->list_lock);
+
+	list_for_each_entry_safe(event, tmp, &tmp_lh, list) {
+		fc_host_post_event(adapter->scsi_host, fc_get_event_number(),
+				event->code, event->data);
+		list_del(&event->list);
+		kfree(event);
+	}
+
+}
+
+/**
+ * zfcp_fc_enqueue_event - safely enqueue FC HBA API event from irq context
+ * @adapter: The adapter where to enqueue the event
+ * @event_code: The event code (as defined in fc_host_event_code in
+ *		scsi_transport_fc.h)
+ * @event_data: The event data (e.g. n_port page in case of els)
+ */
+void zfcp_fc_enqueue_event(struct zfcp_adapter *adapter,
+			enum fc_host_event_code event_code, u32 event_data)
+{
+	struct zfcp_fc_event *event;
+
+	event = kmalloc(sizeof(struct zfcp_fc_event), GFP_ATOMIC);
+	if (!event)
+		return;
+
+	event->code = event_code;
+	event->data = event_data;
+
+	spin_lock(&adapter->events.list_lock);
+	list_add_tail(&event->list, &adapter->events.list);
+	spin_unlock(&adapter->events.list_lock);
+
+	queue_work(adapter->work_queue, &adapter->events.work);
+}
+
 static int zfcp_fc_wka_port_get(struct zfcp_fc_wka_port *wka_port)
 {
 	if (mutex_lock_interruptible(&wka_port->mutex))
@@ -148,6 +200,8 @@
 		afmt = page->rscn_page_flags & ELS_RSCN_ADDR_FMT_MASK;
 		_zfcp_fc_incoming_rscn(fsf_req, zfcp_fc_rscn_range_mask[afmt],
 				       page);
+		zfcp_fc_enqueue_event(fsf_req->adapter, FCH_EVT_RSCN,
+				      *(u32 *)page);
 	}
 	queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work);
 }
diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h
index 0747b08..938d503 100644
--- a/drivers/s390/scsi/zfcp_fc.h
+++ b/drivers/s390/scsi/zfcp_fc.h
@@ -30,6 +30,30 @@
 #define ZFCP_FC_CTELS_TMO	(2 * FC_DEF_R_A_TOV / 1000)
 
 /**
+ * struct zfcp_fc_event - FC HBAAPI event for internal queueing from irq context
+ * @code: Event code
+ * @data: Event data
+ * @list: list_head for zfcp_fc_events list
+ */
+struct zfcp_fc_event {
+	enum fc_host_event_code code;
+	u32 data;
+	struct list_head list;
+};
+
+/**
+ * struct zfcp_fc_events - Infrastructure for posting FC events from irq context
+ * @list: List for queueing of events from irq context to workqueue
+ * @list_lock: Lock for event list
+ * @work: work_struct for forwarding events in workqueue
+*/
+struct zfcp_fc_events {
+	struct list_head list;
+	spinlock_t list_lock;
+	struct work_struct work;
+};
+
+/**
  * struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request
  * @ct_hdr: FC GS common transport header
  * @gid_pn: GID_PN request
@@ -196,6 +220,9 @@
 	memcpy(fcp->fc_cdb, scsi->cmnd, scsi->cmd_len);
 
 	fcp->fc_dl = scsi_bufflen(scsi);
+
+	if (scsi_get_prot_type(scsi) == SCSI_PROT_DIF_TYPE1)
+		fcp->fc_dl += fcp->fc_dl / scsi->device->sector_size * 8;
 }
 
 /**
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 71663fb..9d1d7d1 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -21,6 +21,7 @@
 static void zfcp_fsf_request_timeout_handler(unsigned long data)
 {
 	struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
+	zfcp_qdio_siosl(adapter);
 	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
 				"fsrth_1", NULL);
 }
@@ -274,6 +275,7 @@
 		break;
 	case FSF_STATUS_READ_LINK_DOWN:
 		zfcp_fsf_status_read_link_down(req);
+		zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKDOWN, 0);
 		break;
 	case FSF_STATUS_READ_LINK_UP:
 		dev_info(&adapter->ccw_device->dev,
@@ -286,6 +288,8 @@
 					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
 					ZFCP_STATUS_COMMON_ERP_FAILED,
 					"fssrh_2", req);
+		zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKUP, 0);
+
 		break;
 	case FSF_STATUS_READ_NOTIFICATION_LOST:
 		if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED)
@@ -323,6 +327,7 @@
 		dev_err(&req->adapter->ccw_device->dev,
 			"The FCP adapter reported a problem "
 			"that cannot be recovered\n");
+		zfcp_qdio_siosl(req->adapter);
 		zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req);
 		break;
 	}
@@ -413,6 +418,7 @@
 		dev_err(&adapter->ccw_device->dev,
 			"0x%x is not a valid transfer protocol status\n",
 			qtcb->prefix.prot_status);
+		zfcp_qdio_siosl(adapter);
 		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req);
 	}
 	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -495,7 +501,7 @@
 	fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
 
 	adapter->hydra_version = bottom->adapter_type;
-	adapter->timer_ticks = bottom->timer_interval;
+	adapter->timer_ticks = bottom->timer_interval & ZFCP_FSF_TIMER_INT_MASK;
 	adapter->stat_read_buf_num = max(bottom->status_read_buf_num,
 					 (u16)FSF_STATUS_READS_RECOM);
 
@@ -523,6 +529,8 @@
 		return -EIO;
 	}
 
+	zfcp_scsi_set_prot(adapter);
+
 	return 0;
 }
 
@@ -732,7 +740,7 @@
 
 	zfcp_reqlist_add(adapter->req_list, req);
 
-	req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q.count);
+	req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free);
 	req->issued = get_clock();
 	if (zfcp_qdio_send(qdio, &req->qdio_req)) {
 		del_timer(&req->timer);
@@ -959,8 +967,7 @@
 
 static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
 				       struct scatterlist *sg_req,
-				       struct scatterlist *sg_resp,
-				       int max_sbals)
+				       struct scatterlist *sg_resp)
 {
 	struct zfcp_adapter *adapter = req->adapter;
 	u32 feat = adapter->adapter_features;
@@ -983,18 +990,19 @@
 		return 0;
 	}
 
-	bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
-					sg_req, max_sbals);
+	bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, sg_req);
 	if (bytes <= 0)
 		return -EIO;
+	zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
 	req->qtcb->bottom.support.req_buf_length = bytes;
 	zfcp_qdio_skip_to_last_sbale(&req->qdio_req);
 
 	bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
-					sg_resp, max_sbals);
+					sg_resp);
 	req->qtcb->bottom.support.resp_buf_length = bytes;
 	if (bytes <= 0)
 		return -EIO;
+	zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
 
 	return 0;
 }
@@ -1002,11 +1010,11 @@
 static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
 				 struct scatterlist *sg_req,
 				 struct scatterlist *sg_resp,
-				 int max_sbals, unsigned int timeout)
+				 unsigned int timeout)
 {
 	int ret;
 
-	ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals);
+	ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp);
 	if (ret)
 		return ret;
 
@@ -1046,8 +1054,7 @@
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp,
-				    ZFCP_FSF_MAX_SBALS_PER_REQ, timeout);
+	ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp, timeout);
 	if (ret)
 		goto failed_send;
 
@@ -1143,7 +1150,10 @@
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, 2, timeout);
+
+	zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 2);
+
+	ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, timeout);
 
 	if (ret)
 		goto failed_send;
@@ -2025,7 +2035,7 @@
 	blktrc.magic = ZFCP_BLK_DRV_DATA_MAGIC;
 	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
 		blktrc.flags |= ZFCP_BLK_REQ_ERROR;
-	blktrc.inb_usage = req->qdio_req.qdio_inb_usage;
+	blktrc.inb_usage = 0;
 	blktrc.outb_usage = req->qdio_req.qdio_outb_usage;
 
 	if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA &&
@@ -2035,9 +2045,13 @@
 		blktrc.fabric_lat = lat_in->fabric_lat * ticks;
 
 		switch (req->qtcb->bottom.io.data_direction) {
+		case FSF_DATADIR_DIF_READ_STRIP:
+		case FSF_DATADIR_DIF_READ_CONVERT:
 		case FSF_DATADIR_READ:
 			lat = &unit->latencies.read;
 			break;
+		case FSF_DATADIR_DIF_WRITE_INSERT:
+		case FSF_DATADIR_DIF_WRITE_CONVERT:
 		case FSF_DATADIR_WRITE:
 			lat = &unit->latencies.write;
 			break;
@@ -2078,6 +2092,21 @@
 		goto skip_fsfstatus;
 	}
 
+	switch (req->qtcb->header.fsf_status) {
+	case FSF_INCONSISTENT_PROT_DATA:
+	case FSF_INVALID_PROT_PARM:
+		set_host_byte(scpnt, DID_ERROR);
+		goto skip_fsfstatus;
+	case FSF_BLOCK_GUARD_CHECK_FAILURE:
+		zfcp_scsi_dif_sense_error(scpnt, 0x1);
+		goto skip_fsfstatus;
+	case FSF_APP_TAG_CHECK_FAILURE:
+		zfcp_scsi_dif_sense_error(scpnt, 0x2);
+		goto skip_fsfstatus;
+	case FSF_REF_TAG_CHECK_FAILURE:
+		zfcp_scsi_dif_sense_error(scpnt, 0x3);
+		goto skip_fsfstatus;
+	}
 	fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
 	zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt);
 
@@ -2187,6 +2216,44 @@
 	}
 }
 
+static int zfcp_fsf_set_data_dir(struct scsi_cmnd *scsi_cmnd, u32 *data_dir)
+{
+	switch (scsi_get_prot_op(scsi_cmnd)) {
+	case SCSI_PROT_NORMAL:
+		switch (scsi_cmnd->sc_data_direction) {
+		case DMA_NONE:
+			*data_dir = FSF_DATADIR_CMND;
+			break;
+		case DMA_FROM_DEVICE:
+			*data_dir = FSF_DATADIR_READ;
+			break;
+		case DMA_TO_DEVICE:
+			*data_dir = FSF_DATADIR_WRITE;
+			break;
+		case DMA_BIDIRECTIONAL:
+			return -EINVAL;
+		}
+		break;
+
+	case SCSI_PROT_READ_STRIP:
+		*data_dir = FSF_DATADIR_DIF_READ_STRIP;
+		break;
+	case SCSI_PROT_WRITE_INSERT:
+		*data_dir = FSF_DATADIR_DIF_WRITE_INSERT;
+		break;
+	case SCSI_PROT_READ_PASS:
+		*data_dir = FSF_DATADIR_DIF_READ_CONVERT;
+		break;
+	case SCSI_PROT_WRITE_PASS:
+		*data_dir = FSF_DATADIR_DIF_WRITE_CONVERT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /**
  * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
  * @unit: unit where command is sent to
@@ -2198,16 +2265,17 @@
 	struct zfcp_fsf_req *req;
 	struct fcp_cmnd *fcp_cmnd;
 	unsigned int sbtype = SBAL_FLAGS0_TYPE_READ;
-	int real_bytes, retval = -EIO;
+	int real_bytes, retval = -EIO, dix_bytes = 0;
 	struct zfcp_adapter *adapter = unit->port->adapter;
 	struct zfcp_qdio *qdio = adapter->qdio;
+	struct fsf_qtcb_bottom_io *io;
 
 	if (unlikely(!(atomic_read(&unit->status) &
 		       ZFCP_STATUS_COMMON_UNBLOCKED)))
 		return -EBUSY;
 
 	spin_lock(&qdio->req_q_lock);
-	if (atomic_read(&qdio->req_q.count) <= 0) {
+	if (atomic_read(&qdio->req_q_free) <= 0) {
 		atomic_inc(&qdio->req_q_full);
 		goto out;
 	}
@@ -2223,57 +2291,46 @@
 		goto out;
 	}
 
+	scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
+
+	io = &req->qtcb->bottom.io;
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
 	req->unit = unit;
 	req->data = scsi_cmnd;
 	req->handler = zfcp_fsf_send_fcp_command_handler;
 	req->qtcb->header.lun_handle = unit->handle;
 	req->qtcb->header.port_handle = unit->port->handle;
-	req->qtcb->bottom.io.service_class = FSF_CLASS_3;
-	req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
+	io->service_class = FSF_CLASS_3;
+	io->fcp_cmnd_length = FCP_CMND_LEN;
 
-	scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
-
-	/*
-	 * set depending on data direction:
-	 *      data direction bits in SBALE (SB Type)
-	 *      data direction bits in QTCB
-	 */
-	switch (scsi_cmnd->sc_data_direction) {
-	case DMA_NONE:
-		req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
-		break;
-	case DMA_FROM_DEVICE:
-		req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
-		break;
-	case DMA_TO_DEVICE:
-		req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
-		break;
-	case DMA_BIDIRECTIONAL:
-		goto failed_scsi_cmnd;
+	if (scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) {
+		io->data_block_length = scsi_cmnd->device->sector_size;
+		io->ref_tag_value = scsi_get_lba(scsi_cmnd) & 0xFFFFFFFF;
 	}
 
+	zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction);
+
 	get_device(&unit->dev);
 
 	fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
 	zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
 
-	real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
-					     scsi_sglist(scsi_cmnd),
-					     ZFCP_FSF_MAX_SBALS_PER_REQ);
-	if (unlikely(real_bytes < 0)) {
-		if (req->qdio_req.sbal_number >= ZFCP_FSF_MAX_SBALS_PER_REQ) {
-			dev_err(&adapter->ccw_device->dev,
-				"Oversize data package, unit 0x%016Lx "
-				"on port 0x%016Lx closed\n",
-				(unsigned long long)unit->fcp_lun,
-				(unsigned long long)unit->port->wwpn);
-			zfcp_erp_unit_shutdown(unit, 0, "fssfct1", req);
-			retval = -EINVAL;
-		}
-		goto failed_scsi_cmnd;
+	if (scsi_prot_sg_count(scsi_cmnd)) {
+		zfcp_qdio_set_data_div(qdio, &req->qdio_req,
+				       scsi_prot_sg_count(scsi_cmnd));
+		dix_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
+						scsi_prot_sglist(scsi_cmnd));
+		io->prot_data_length = dix_bytes;
 	}
 
+	real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
+					     scsi_sglist(scsi_cmnd));
+
+	if (unlikely(real_bytes < 0) || unlikely(dix_bytes < 0))
+		goto failed_scsi_cmnd;
+
+	zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
+
 	retval = zfcp_fsf_req_send(req);
 	if (unlikely(retval))
 		goto failed_scsi_cmnd;
@@ -2391,13 +2448,13 @@
 	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
 	bottom->option = fsf_cfdc->option;
 
-	bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
-					fsf_cfdc->sg,
-					ZFCP_FSF_MAX_SBALS_PER_REQ);
+	bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, fsf_cfdc->sg);
+
 	if (bytes != ZFCP_CFDC_MAX_SIZE) {
 		zfcp_fsf_req_free(req);
 		goto out;
 	}
+	zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
 
 	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
 	retval = zfcp_fsf_req_send(req);
@@ -2419,7 +2476,7 @@
 void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
 {
 	struct zfcp_adapter *adapter = qdio->adapter;
-	struct qdio_buffer *sbal = qdio->resp_q.sbal[sbal_idx];
+	struct qdio_buffer *sbal = qdio->res_q[sbal_idx];
 	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *fsf_req;
 	unsigned long req_id;
@@ -2431,17 +2488,17 @@
 		req_id = (unsigned long) sbale->addr;
 		fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id);
 
-		if (!fsf_req)
+		if (!fsf_req) {
 			/*
 			 * Unknown request means that we have potentially memory
 			 * corruption and must stop the machine immediately.
 			 */
+			zfcp_qdio_siosl(adapter);
 			panic("error: unknown req_id (%lx) on adapter %s.\n",
 			      req_id, dev_name(&adapter->ccw_device->dev));
+		}
 
 		fsf_req->qdio_req.sbal_response = sbal_idx;
-		fsf_req->qdio_req.qdio_inb_usage =
-			atomic_read(&qdio->resp_q.count);
 		zfcp_fsf_req_complete(fsf_req);
 
 		if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY))
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
index 519083f..db8c853 100644
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -80,11 +80,15 @@
 #define FSF_REQUEST_SIZE_TOO_LARGE		0x00000061
 #define FSF_RESPONSE_SIZE_TOO_LARGE		0x00000062
 #define FSF_SBAL_MISMATCH			0x00000063
+#define FSF_INCONSISTENT_PROT_DATA		0x00000070
+#define FSF_INVALID_PROT_PARM			0x00000071
+#define FSF_BLOCK_GUARD_CHECK_FAILURE		0x00000081
+#define FSF_APP_TAG_CHECK_FAILURE		0x00000082
+#define FSF_REF_TAG_CHECK_FAILURE		0x00000083
 #define FSF_ADAPTER_STATUS_AVAILABLE		0x000000AD
 #define FSF_UNKNOWN_COMMAND			0x000000E2
 #define FSF_UNKNOWN_OP_SUBTYPE                  0x000000E3
 #define FSF_INVALID_COMMAND_OPTION              0x000000E5
-/* #define FSF_ERROR                             0x000000FF  */
 
 #define FSF_PROT_STATUS_QUAL_SIZE		16
 #define FSF_STATUS_QUALIFIER_SIZE		16
@@ -147,18 +151,17 @@
 #define FSF_DATADIR_WRITE			0x00000001
 #define FSF_DATADIR_READ			0x00000002
 #define FSF_DATADIR_CMND			0x00000004
+#define FSF_DATADIR_DIF_WRITE_INSERT		0x00000009
+#define FSF_DATADIR_DIF_READ_STRIP		0x0000000a
+#define FSF_DATADIR_DIF_WRITE_CONVERT		0x0000000b
+#define FSF_DATADIR_DIF_READ_CONVERT		0X0000000c
+
+/* data protection control flags */
+#define FSF_APP_TAG_CHECK_ENABLE		0x10
 
 /* fc service class */
 #define FSF_CLASS_3				0x00000003
 
-/* SBAL chaining */
-#define ZFCP_FSF_MAX_SBALS_PER_REQ		36
-
-/* max. number of (data buffer) SBALEs in largest SBAL chain
- * request ID + QTCB in SBALE 0 + 1 of first SBAL in chain   */
-#define ZFCP_FSF_MAX_SBALES_PER_REQ	\
-	(ZFCP_FSF_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2)
-
 /* logging space behind QTCB */
 #define FSF_QTCB_LOG_SIZE			1024
 
@@ -170,6 +173,8 @@
 #define FSF_FEATURE_ELS_CT_CHAINED_SBALS	0x00000020
 #define FSF_FEATURE_UPDATE_ALERT		0x00000100
 #define FSF_FEATURE_MEASUREMENT_DATA		0x00000200
+#define FSF_FEATURE_DIF_PROT_TYPE1		0x00010000
+#define FSF_FEATURE_DIX_PROT_TCPIP		0x00020000
 
 /* host connection features */
 #define FSF_FEATURE_NPIV_MODE			0x00000001
@@ -324,9 +329,14 @@
 struct fsf_qtcb_bottom_io {
 	u32 data_direction;
 	u32 service_class;
-	u8  res1[8];
+	u8  res1;
+	u8  data_prot_flags;
+	u16 app_tag_value;
+	u32 ref_tag_value;
 	u32 fcp_cmnd_length;
-	u8  res2[12];
+	u32 data_block_length;
+	u32 prot_data_length;
+	u8  res2[4];
 	u8  fcp_cmnd[FSF_FCP_CMND_SIZE];
 	u8  fcp_rsp[FSF_FCP_RSP_SIZE];
 	u8  res3[64];
@@ -352,6 +362,8 @@
 	u8  els[256];
 } __attribute__ ((packed));
 
+#define ZFCP_FSF_TIMER_INT_MASK	0x3FFF
+
 struct fsf_qtcb_bottom_config {
 	u32 lic_version;
 	u32 feature_selection;
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 6fa5e04..b263575 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -30,12 +30,15 @@
 	return 0;
 }
 
-static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id)
+static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id,
+				    unsigned int qdio_err)
 {
 	struct zfcp_adapter *adapter = qdio->adapter;
 
 	dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
 
+	if (qdio_err & QDIO_ERROR_SLSB_STATE)
+		zfcp_qdio_siosl(adapter);
 	zfcp_erp_adapter_reopen(adapter,
 				ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
 				ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL);
@@ -55,72 +58,47 @@
 static inline void zfcp_qdio_account(struct zfcp_qdio *qdio)
 {
 	unsigned long long now, span;
-	int free, used;
+	int used;
 
 	spin_lock(&qdio->stat_lock);
 	now = get_clock_monotonic();
 	span = (now - qdio->req_q_time) >> 12;
-	free = atomic_read(&qdio->req_q.count);
-	used = QDIO_MAX_BUFFERS_PER_Q - free;
+	used = QDIO_MAX_BUFFERS_PER_Q - atomic_read(&qdio->req_q_free);
 	qdio->req_q_util += used * span;
 	qdio->req_q_time = now;
 	spin_unlock(&qdio->stat_lock);
 }
 
 static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err,
-			      int queue_no, int first, int count,
+			      int queue_no, int idx, int count,
 			      unsigned long parm)
 {
 	struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
-	struct zfcp_qdio_queue *queue = &qdio->req_q;
 
 	if (unlikely(qdio_err)) {
-		zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
-					count);
-		zfcp_qdio_handler_error(qdio, "qdireq1");
+		zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
+		zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err);
 		return;
 	}
 
 	/* cleanup all SBALs being program-owned now */
-	zfcp_qdio_zero_sbals(queue->sbal, first, count);
+	zfcp_qdio_zero_sbals(qdio->req_q, idx, count);
 
 	zfcp_qdio_account(qdio);
-	atomic_add(count, &queue->count);
+	atomic_add(count, &qdio->req_q_free);
 	wake_up(&qdio->req_q_wq);
 }
 
-static void zfcp_qdio_resp_put_back(struct zfcp_qdio *qdio, int processed)
-{
-	struct zfcp_qdio_queue *queue = &qdio->resp_q;
-	struct ccw_device *cdev = qdio->adapter->ccw_device;
-	u8 count, start = queue->first;
-	unsigned int retval;
-
-	count = atomic_read(&queue->count) + processed;
-
-	retval = do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, start, count);
-
-	if (unlikely(retval)) {
-		atomic_set(&queue->count, count);
-		zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdrpb_1", NULL);
-	} else {
-		queue->first += count;
-		queue->first %= QDIO_MAX_BUFFERS_PER_Q;
-		atomic_set(&queue->count, 0);
-	}
-}
-
 static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
-			       int queue_no, int first, int count,
+			       int queue_no, int idx, int count,
 			       unsigned long parm)
 {
 	struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
 	int sbal_idx, sbal_no;
 
 	if (unlikely(qdio_err)) {
-		zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
-					count);
-		zfcp_qdio_handler_error(qdio, "qdires1");
+		zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
+		zfcp_qdio_handler_error(qdio, "qdires1", qdio_err);
 		return;
 	}
 
@@ -129,25 +107,16 @@
 	 * returned by QDIO layer
 	 */
 	for (sbal_no = 0; sbal_no < count; sbal_no++) {
-		sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
+		sbal_idx = (idx + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
 		/* go through all SBALEs of SBAL */
 		zfcp_fsf_reqid_check(qdio, sbal_idx);
 	}
 
 	/*
-	 * put range of SBALs back to response queue
-	 * (including SBALs which have already been free before)
+	 * put SBALs back to response queue
 	 */
-	zfcp_qdio_resp_put_back(qdio, count);
-}
-
-static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
-				 struct zfcp_qdio_req *q_req, int max_sbals)
-{
-	int count = atomic_read(&qdio->req_q.count);
-	count = min(count, max_sbals);
-	q_req->sbal_limit = (q_req->sbal_first + count - 1)
-					% QDIO_MAX_BUFFERS_PER_Q;
+	if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count))
+		zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2", NULL);
 }
 
 static struct qdio_buffer_element *
@@ -173,6 +142,7 @@
 
 	/* keep this requests number of SBALs up-to-date */
 	q_req->sbal_number++;
+	BUG_ON(q_req->sbal_number > ZFCP_QDIO_MAX_SBALS_PER_REQ);
 
 	/* start at first SBALE of new SBAL */
 	q_req->sbale_curr = 0;
@@ -193,17 +163,6 @@
 	return zfcp_qdio_sbale_curr(qdio, q_req);
 }
 
-static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
-				 struct zfcp_qdio_req *q_req)
-{
-	struct qdio_buffer **sbal = qdio->req_q.sbal;
-	int first = q_req->sbal_first;
-	int last = q_req->sbal_last;
-	int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) %
-		QDIO_MAX_BUFFERS_PER_Q + 1;
-	zfcp_qdio_zero_sbals(sbal, first, count);
-}
-
 /**
  * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list
  * @qdio: pointer to struct zfcp_qdio
@@ -213,14 +172,11 @@
  * Returns: number of bytes, or error (negativ)
  */
 int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
-			    struct scatterlist *sg, int max_sbals)
+			    struct scatterlist *sg)
 {
 	struct qdio_buffer_element *sbale;
 	int bytes = 0;
 
-	/* figure out last allowed SBAL */
-	zfcp_qdio_sbal_limit(qdio, q_req, max_sbals);
-
 	/* set storage-block type for this request */
 	sbale = zfcp_qdio_sbale_req(qdio, q_req);
 	sbale->flags |= q_req->sbtype;
@@ -229,7 +185,8 @@
 		sbale = zfcp_qdio_sbale_next(qdio, q_req);
 		if (!sbale) {
 			atomic_inc(&qdio->req_q_full);
-			zfcp_qdio_undo_sbals(qdio, q_req);
+			zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first,
+					     q_req->sbal_number);
 			return -EINVAL;
 		}
 
@@ -239,19 +196,13 @@
 		bytes += sg->length;
 	}
 
-	/* assume that no other SBALEs are to follow in the same SBAL */
-	sbale = zfcp_qdio_sbale_curr(qdio, q_req);
-	sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
-
 	return bytes;
 }
 
 static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
 {
-	struct zfcp_qdio_queue *req_q = &qdio->req_q;
-
 	spin_lock_bh(&qdio->req_q_lock);
-	if (atomic_read(&req_q->count) ||
+	if (atomic_read(&qdio->req_q_free) ||
 	    !(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
 		return 1;
 	spin_unlock_bh(&qdio->req_q_lock);
@@ -300,25 +251,25 @@
  */
 int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 {
-	struct zfcp_qdio_queue *req_q = &qdio->req_q;
-	int first = q_req->sbal_first;
-	int count = q_req->sbal_number;
 	int retval;
-	unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
+	u8 sbal_number = q_req->sbal_number;
 
 	zfcp_qdio_account(qdio);
 
-	retval = do_QDIO(qdio->adapter->ccw_device, qdio_flags, 0, first,
-			 count);
+	retval = do_QDIO(qdio->adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0,
+			 q_req->sbal_first, sbal_number);
+
 	if (unlikely(retval)) {
-		zfcp_qdio_zero_sbals(req_q->sbal, first, count);
+		zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first,
+				     sbal_number);
 		return retval;
 	}
 
 	/* account for transferred buffers */
-	atomic_sub(count, &req_q->count);
-	req_q->first += count;
-	req_q->first %= QDIO_MAX_BUFFERS_PER_Q;
+	atomic_sub(sbal_number, &qdio->req_q_free);
+	qdio->req_q_idx += sbal_number;
+	qdio->req_q_idx %= QDIO_MAX_BUFFERS_PER_Q;
+
 	return 0;
 }
 
@@ -331,6 +282,7 @@
 	id->q_format = QDIO_ZFCP_QFMT;
 	memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);
 	ASCEBC(id->adapter_name, 8);
+	id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV;
 	id->qib_param_field_format = 0;
 	id->qib_param_field = NULL;
 	id->input_slib_elements = NULL;
@@ -340,10 +292,10 @@
 	id->input_handler = zfcp_qdio_int_resp;
 	id->output_handler = zfcp_qdio_int_req;
 	id->int_parm = (unsigned long) qdio;
-	id->input_sbal_addr_array = (void **) (qdio->resp_q.sbal);
-	id->output_sbal_addr_array = (void **) (qdio->req_q.sbal);
-
+	id->input_sbal_addr_array = (void **) (qdio->res_q);
+	id->output_sbal_addr_array = (void **) (qdio->req_q);
 }
+
 /**
  * zfcp_qdio_allocate - allocate queue memory and initialize QDIO data
  * @adapter: pointer to struct zfcp_adapter
@@ -354,8 +306,8 @@
 {
 	struct qdio_initialize init_data;
 
-	if (zfcp_qdio_buffers_enqueue(qdio->req_q.sbal) ||
-	    zfcp_qdio_buffers_enqueue(qdio->resp_q.sbal))
+	if (zfcp_qdio_buffers_enqueue(qdio->req_q) ||
+	    zfcp_qdio_buffers_enqueue(qdio->res_q))
 		return -ENOMEM;
 
 	zfcp_qdio_setup_init_data(&init_data, qdio);
@@ -369,34 +321,30 @@
  */
 void zfcp_qdio_close(struct zfcp_qdio *qdio)
 {
-	struct zfcp_qdio_queue *req_q;
-	int first, count;
+	struct zfcp_adapter *adapter = qdio->adapter;
+	int idx, count;
 
-	if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
+	if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
 		return;
 
 	/* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
-	req_q = &qdio->req_q;
 	spin_lock_bh(&qdio->req_q_lock);
-	atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status);
+	atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
 	spin_unlock_bh(&qdio->req_q_lock);
 
 	wake_up(&qdio->req_q_wq);
 
-	qdio_shutdown(qdio->adapter->ccw_device,
-		      QDIO_FLAG_CLEANUP_USING_CLEAR);
+	qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR);
 
 	/* cleanup used outbound sbals */
-	count = atomic_read(&req_q->count);
+	count = atomic_read(&qdio->req_q_free);
 	if (count < QDIO_MAX_BUFFERS_PER_Q) {
-		first = (req_q->first + count) % QDIO_MAX_BUFFERS_PER_Q;
+		idx = (qdio->req_q_idx + count) % QDIO_MAX_BUFFERS_PER_Q;
 		count = QDIO_MAX_BUFFERS_PER_Q - count;
-		zfcp_qdio_zero_sbals(req_q->sbal, first, count);
+		zfcp_qdio_zero_sbals(qdio->req_q, idx, count);
 	}
-	req_q->first = 0;
-	atomic_set(&req_q->count, 0);
-	qdio->resp_q.first = 0;
-	atomic_set(&qdio->resp_q.count, 0);
+	qdio->req_q_idx = 0;
+	atomic_set(&qdio->req_q_free, 0);
 }
 
 /**
@@ -408,34 +356,45 @@
 {
 	struct qdio_buffer_element *sbale;
 	struct qdio_initialize init_data;
-	struct ccw_device *cdev = qdio->adapter->ccw_device;
+	struct zfcp_adapter *adapter = qdio->adapter;
+	struct ccw_device *cdev = adapter->ccw_device;
+	struct qdio_ssqd_desc ssqd;
 	int cc;
 
-	if (atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
+	if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
 		return -EIO;
 
+	atomic_clear_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
+			  &qdio->adapter->status);
+
 	zfcp_qdio_setup_init_data(&init_data, qdio);
 
 	if (qdio_establish(&init_data))
 		goto failed_establish;
 
+	if (qdio_get_ssqd_desc(init_data.cdev, &ssqd))
+		goto failed_qdio;
+
+	if (ssqd.qdioac2 & CHSC_AC2_DATA_DIV_ENABLED)
+		atomic_set_mask(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED,
+				&qdio->adapter->status);
+
 	if (qdio_activate(cdev))
 		goto failed_qdio;
 
 	for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) {
-		sbale = &(qdio->resp_q.sbal[cc]->element[0]);
+		sbale = &(qdio->res_q[cc]->element[0]);
 		sbale->length = 0;
 		sbale->flags = SBAL_FLAGS_LAST_ENTRY;
 		sbale->addr = NULL;
 	}
 
-	if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0,
-		     QDIO_MAX_BUFFERS_PER_Q))
+	if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q))
 		goto failed_qdio;
 
 	/* set index of first avalable SBALS / number of available SBALS */
-	qdio->req_q.first = 0;
-	atomic_set(&qdio->req_q.count, QDIO_MAX_BUFFERS_PER_Q);
+	qdio->req_q_idx = 0;
+	atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q);
 
 	return 0;
 
@@ -449,7 +408,6 @@
 
 void zfcp_qdio_destroy(struct zfcp_qdio *qdio)
 {
-	struct qdio_buffer **sbal_req, **sbal_resp;
 	int p;
 
 	if (!qdio)
@@ -458,12 +416,9 @@
 	if (qdio->adapter->ccw_device)
 		qdio_free(qdio->adapter->ccw_device);
 
-	sbal_req = qdio->req_q.sbal;
-	sbal_resp = qdio->resp_q.sbal;
-
 	for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) {
-		free_page((unsigned long) sbal_req[p]);
-		free_page((unsigned long) sbal_resp[p]);
+		free_page((unsigned long) qdio->req_q[p]);
+		free_page((unsigned long) qdio->res_q[p]);
 	}
 
 	kfree(qdio);
@@ -491,3 +446,26 @@
 	return 0;
 }
 
+/**
+ * zfcp_qdio_siosl - Trigger logging in FCP channel
+ * @adapter: The zfcp_adapter where to trigger logging
+ *
+ * Call the cio siosl function to trigger hardware logging.  This
+ * wrapper function sets a flag to ensure hardware logging is only
+ * triggered once before going through qdio shutdown.
+ *
+ * The triggers are always run from qdio tasklet context, so no
+ * additional synchronization is necessary.
+ */
+void zfcp_qdio_siosl(struct zfcp_adapter *adapter)
+{
+	int rc;
+
+	if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_SIOSL_ISSUED)
+		return;
+
+	rc = ccw_device_siosl(adapter->ccw_device);
+	if (!rc)
+		atomic_set_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
+				&adapter->status);
+}
diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h
index 138fba5..2297d8d 100644
--- a/drivers/s390/scsi/zfcp_qdio.h
+++ b/drivers/s390/scsi/zfcp_qdio.h
@@ -19,22 +19,20 @@
 /* index of last SBALE (with respect to DMQ bug workaround) */
 #define ZFCP_QDIO_LAST_SBALE_PER_SBAL	(ZFCP_QDIO_MAX_SBALES_PER_SBAL - 1)
 
-/**
- * struct zfcp_qdio_queue - qdio queue buffer, zfcp index and free count
- * @sbal: qdio buffers
- * @first: index of next free buffer in queue
- * @count: number of free buffers in queue
- */
-struct zfcp_qdio_queue {
-	struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q];
-	u8		   first;
-	atomic_t           count;
-};
+/* Max SBALS for chaining */
+#define ZFCP_QDIO_MAX_SBALS_PER_REQ	36
+
+/* max. number of (data buffer) SBALEs in largest SBAL chain
+ * request ID + QTCB in SBALE 0 + 1 of first SBAL in chain   */
+#define ZFCP_QDIO_MAX_SBALES_PER_REQ     \
+	(ZFCP_QDIO_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2)
 
 /**
  * struct zfcp_qdio - basic qdio data structure
- * @resp_q: response queue
+ * @res_q: response queue
  * @req_q: request queue
+ * @req_q_idx: index of next free buffer
+ * @req_q_free: number of free buffers in queue
  * @stat_lock: lock to protect req_q_util and req_q_time
  * @req_q_lock: lock to serialize access to request queue
  * @req_q_time: time of last fill level change
@@ -44,8 +42,10 @@
  * @adapter: adapter used in conjunction with this qdio structure
  */
 struct zfcp_qdio {
-	struct zfcp_qdio_queue	resp_q;
-	struct zfcp_qdio_queue	req_q;
+	struct qdio_buffer	*res_q[QDIO_MAX_BUFFERS_PER_Q];
+	struct qdio_buffer	*req_q[QDIO_MAX_BUFFERS_PER_Q];
+	u8			req_q_idx;
+	atomic_t		req_q_free;
 	spinlock_t		stat_lock;
 	spinlock_t		req_q_lock;
 	unsigned long long	req_q_time;
@@ -65,7 +65,6 @@
  * @sbale_curr: current sbale at creation of this request
  * @sbal_response: sbal used in interrupt
  * @qdio_outb_usage: usage of outbound queue
- * @qdio_inb_usage: usage of inbound queue
  */
 struct zfcp_qdio_req {
 	u32	sbtype;
@@ -76,22 +75,9 @@
 	u8	sbale_curr;
 	u8	sbal_response;
 	u16	qdio_outb_usage;
-	u16	qdio_inb_usage;
 };
 
 /**
- * zfcp_qdio_sbale - return pointer to sbale in qdio queue
- * @q: queue where to find sbal
- * @sbal_idx: sbal index in queue
- * @sbale_idx: sbale index in sbal
- */
-static inline struct qdio_buffer_element *
-zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
-{
-	return &q->sbal[sbal_idx]->element[sbale_idx];
-}
-
-/**
  * zfcp_qdio_sbale_req - return pointer to sbale on req_q for a request
  * @qdio: pointer to struct zfcp_qdio
  * @q_rec: pointer to struct zfcp_qdio_req
@@ -100,7 +86,7 @@
 static inline struct qdio_buffer_element *
 zfcp_qdio_sbale_req(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 {
-	return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last, 0);
+	return &qdio->req_q[q_req->sbal_last]->element[0];
 }
 
 /**
@@ -112,8 +98,7 @@
 static inline struct qdio_buffer_element *
 zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 {
-	return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last,
-			       q_req->sbale_curr);
+	return &qdio->req_q[q_req->sbal_last]->element[q_req->sbale_curr];
 }
 
 /**
@@ -134,21 +119,25 @@
 			unsigned long req_id, u32 sbtype, void *data, u32 len)
 {
 	struct qdio_buffer_element *sbale;
+	int count = min(atomic_read(&qdio->req_q_free),
+			ZFCP_QDIO_MAX_SBALS_PER_REQ);
 
-	q_req->sbal_first = q_req->sbal_last = qdio->req_q.first;
+	q_req->sbal_first = q_req->sbal_last = qdio->req_q_idx;
 	q_req->sbal_number = 1;
 	q_req->sbtype = sbtype;
+	q_req->sbale_curr = 1;
+	q_req->sbal_limit = (q_req->sbal_first + count - 1)
+					% QDIO_MAX_BUFFERS_PER_Q;
 
 	sbale = zfcp_qdio_sbale_req(qdio, q_req);
 	sbale->addr = (void *) req_id;
-	sbale->flags |= SBAL_FLAGS0_COMMAND;
-	sbale->flags |= sbtype;
+	sbale->flags = SBAL_FLAGS0_COMMAND | sbtype;
 
-	q_req->sbale_curr = 1;
+	if (unlikely(!data))
+		return;
 	sbale++;
 	sbale->addr = data;
-	if (likely(data))
-		sbale->length = len;
+	sbale->length = len;
 }
 
 /**
@@ -210,4 +199,36 @@
 	q_req->sbale_curr = ZFCP_QDIO_LAST_SBALE_PER_SBAL;
 }
 
+/**
+ * zfcp_qdio_sbal_limit - set the sbal limit for a request in q_req
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: The current zfcp_qdio_req
+ * @max_sbals: maximum number of SBALs allowed
+ */
+static inline
+void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
+			  struct zfcp_qdio_req *q_req, int max_sbals)
+{
+	int count = min(atomic_read(&qdio->req_q_free), max_sbals);
+
+	q_req->sbal_limit = (q_req->sbal_first + count - 1) %
+				QDIO_MAX_BUFFERS_PER_Q;
+}
+
+/**
+ * zfcp_qdio_set_data_div - set data division count
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: The current zfcp_qdio_req
+ * @count: The data division count
+ */
+static inline
+void zfcp_qdio_set_data_div(struct zfcp_qdio *qdio,
+			    struct zfcp_qdio_req *q_req, u32 count)
+{
+	struct qdio_buffer_element *sbale;
+
+	sbale = &qdio->req_q[q_req->sbal_first]->element[0];
+	sbale->length = count;
+}
+
 #endif /* ZFCP_QDIO_H */
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index be5d2c6..cb000c9 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <scsi/fc/fc_fcp.h>
+#include <scsi/scsi_eh.h>
 #include <asm/atomic.h>
 #include "zfcp_ext.h"
 #include "zfcp_dbf.h"
@@ -22,6 +23,13 @@
 module_param_named(queue_depth, default_depth, uint, 0600);
 MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices");
 
+static bool enable_dif;
+
+#ifdef CONFIG_ZFCP_DIF
+module_param_named(dif, enable_dif, bool, 0600);
+MODULE_PARM_DESC(dif, "Enable DIF/DIX data integrity support");
+#endif
+
 static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,
 					int reason)
 {
@@ -506,8 +514,10 @@
  * @rport: The FC rport where to teminate I/O
  *
  * Abort all pending SCSI commands for a port by closing the
- * port. Using a reopen avoiding a conflict with a shutdown
- * overwriting a reopen.
+ * port. Using a reopen avoids a conflict with a shutdown
+ * overwriting a reopen. The "forced" ensures that a disappeared port
+ * is not opened again as valid due to the cached plogi data in
+ * non-NPIV mode.
  */
 static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
 {
@@ -519,11 +529,25 @@
 	port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
 
 	if (port) {
-		zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL);
+		zfcp_erp_port_forced_reopen(port, 0, "sctrpi1", NULL);
 		put_device(&port->dev);
 	}
 }
 
+static void zfcp_scsi_queue_unit_register(struct zfcp_port *port)
+{
+	struct zfcp_unit *unit;
+
+	read_lock_irq(&port->unit_list_lock);
+	list_for_each_entry(unit, &port->unit_list, list) {
+		get_device(&unit->dev);
+		if (scsi_queue_work(port->adapter->scsi_host,
+				    &unit->scsi_work) <= 0)
+			put_device(&unit->dev);
+	}
+	read_unlock_irq(&port->unit_list_lock);
+}
+
 static void zfcp_scsi_rport_register(struct zfcp_port *port)
 {
 	struct fc_rport_identifiers ids;
@@ -548,6 +572,9 @@
 	rport->maxframe_size = port->maxframe_size;
 	rport->supported_classes = port->supported_classes;
 	port->rport = rport;
+	port->starget_id = rport->scsi_target_id;
+
+	zfcp_scsi_queue_unit_register(port);
 }
 
 static void zfcp_scsi_rport_block(struct zfcp_port *port)
@@ -610,24 +637,74 @@
 	put_device(&port->dev);
 }
 
-
-void zfcp_scsi_scan(struct work_struct *work)
+/**
+ * zfcp_scsi_scan - Register LUN with SCSI midlayer
+ * @unit: The LUN/unit to register
+ */
+void zfcp_scsi_scan(struct zfcp_unit *unit)
 {
-	struct zfcp_unit *unit = container_of(work, struct zfcp_unit,
-					      scsi_work);
-	struct fc_rport *rport;
-
-	flush_work(&unit->port->rport_work);
-	rport = unit->port->rport;
+	struct fc_rport *rport = unit->port->rport;
 
 	if (rport && rport->port_state == FC_PORTSTATE_ONLINE)
 		scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
 				 scsilun_to_int((struct scsi_lun *)
 						&unit->fcp_lun), 0);
+}
 
+void zfcp_scsi_scan_work(struct work_struct *work)
+{
+	struct zfcp_unit *unit = container_of(work, struct zfcp_unit,
+					      scsi_work);
+
+	zfcp_scsi_scan(unit);
 	put_device(&unit->dev);
 }
 
+/**
+ * zfcp_scsi_set_prot - Configure DIF/DIX support in scsi_host
+ * @adapter: The adapter where to configure DIF/DIX for the SCSI host
+ */
+void zfcp_scsi_set_prot(struct zfcp_adapter *adapter)
+{
+	unsigned int mask = 0;
+	unsigned int data_div;
+	struct Scsi_Host *shost = adapter->scsi_host;
+
+	data_div = atomic_read(&adapter->status) &
+		   ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED;
+
+	if (enable_dif &&
+	    adapter->adapter_features & FSF_FEATURE_DIF_PROT_TYPE1)
+		mask |= SHOST_DIF_TYPE1_PROTECTION;
+
+	if (enable_dif && data_div &&
+	    adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) {
+		mask |= SHOST_DIX_TYPE1_PROTECTION;
+		scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP);
+		shost->sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2;
+		shost->max_sectors = ZFCP_QDIO_MAX_SBALES_PER_REQ * 8 / 2;
+	}
+
+	scsi_host_set_prot(shost, mask);
+}
+
+/**
+ * zfcp_scsi_dif_sense_error - Report DIF/DIX error as driver sense error
+ * @scmd: The SCSI command to report the error for
+ * @ascq: The ASCQ to put in the sense buffer
+ *
+ * See the error handling in sd_done for the sense codes used here.
+ * Set DID_SOFT_ERROR to retry the request, if possible.
+ */
+void zfcp_scsi_dif_sense_error(struct scsi_cmnd *scmd, int ascq)
+{
+	scsi_build_sense_buffer(1, scmd->sense_buffer,
+				ILLEGAL_REQUEST, 0x10, ascq);
+	set_driver_byte(scmd, DRIVER_SENSE);
+	scmd->result |= SAM_STAT_CHECK_CONDITION;
+	set_host_byte(scmd, DID_SOFT_ERROR);
+}
+
 struct fc_function_template zfcp_transport_functions = {
 	.show_starget_port_id = 1,
 	.show_starget_port_name = 1,
@@ -677,11 +754,11 @@
 		.eh_host_reset_handler	 = zfcp_scsi_eh_host_reset_handler,
 		.can_queue		 = 4096,
 		.this_id		 = -1,
-		.sg_tablesize		 = ZFCP_FSF_MAX_SBALES_PER_REQ,
+		.sg_tablesize		 = ZFCP_QDIO_MAX_SBALES_PER_REQ,
 		.cmd_per_lun		 = 1,
 		.use_clustering		 = 1,
 		.sdev_attrs		 = zfcp_sysfs_sdev_attrs,
-		.max_sectors		 = (ZFCP_FSF_MAX_SBALES_PER_REQ * 8),
+		.max_sectors		 = (ZFCP_QDIO_MAX_SBALES_PER_REQ * 8),
 		.dma_boundary		 = ZFCP_QDIO_SBALE_LEN - 1,
 		.shost_attrs		 = zfcp_sysfs_shost_attrs,
 	},
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index f5f6069..b4561c86 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -275,7 +275,7 @@
 
 	zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL);
 	zfcp_erp_wait(unit->port->adapter);
-	flush_work(&unit->scsi_work);
+	zfcp_scsi_scan(unit);
 out:
 	put_device(&port->dev);
 	return retval ? retval : (ssize_t) count;
@@ -290,6 +290,7 @@
 	struct zfcp_unit *unit;
 	u64 fcp_lun;
 	int retval = -EINVAL;
+	struct scsi_device *sdev;
 
 	if (!(port && get_device(&port->dev)))
 		return -EBUSY;
@@ -303,8 +304,13 @@
 	else
 		retval = 0;
 
-	/* wait for possible timeout during SCSI probe */
-	flush_work(&unit->scsi_work);
+	sdev = scsi_device_lookup(port->adapter->scsi_host, 0,
+				  port->starget_id,
+				  scsilun_to_int((struct scsi_lun *)&fcp_lun));
+	if (sdev) {
+		scsi_remove_device(sdev);
+		scsi_device_put(sdev);
+	}
 
 	write_lock_irq(&port->unit_list_lock);
 	list_del(&unit->list);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 75f2336..158284f 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1847,6 +1847,10 @@
           called zfcp. If you want to compile it as a module, say M here
           and read <file:Documentation/kbuild/modules.txt>.
 
+config ZFCP_DIF
+	tristate "T10 DIF/DIX support for the zfcp driver (EXPERIMENTAL)"
+	depends on ZFCP && EXPERIMENTAL
+
 config SCSI_PMCRAID
 	tristate "PMC SIERRA Linux MaxRAID adapter support"
 	depends on PCI && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 1c7ac49..2a3fca2 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -163,6 +163,7 @@
 scsi_mod-$(CONFIG_SYSCTL)	+= scsi_sysctl.o
 scsi_mod-$(CONFIG_SCSI_PROC_FS)	+= scsi_proc.o
 scsi_mod-y			+= scsi_trace.o
+scsi_mod-$(CONFIG_PM_OPS)	+= scsi_pm.o
 
 scsi_tgt-y			+= scsi_tgt_lib.o scsi_tgt_if.o
 
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 33898b61..cad6f9a 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -1091,6 +1091,7 @@
 	struct list_head *insert = &aac_devices;
 	int error = -ENODEV;
 	int unique_id = 0;
+	u64 dmamask;
 
 	list_for_each_entry(aac, &aac_devices, entry) {
 		if (aac->id > unique_id)
@@ -1104,17 +1105,18 @@
 		goto out;
 	error = -ENODEV;
 
-	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) ||
-			pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
-		goto out_disable_pdev;
 	/*
 	 * If the quirk31 bit is set, the adapter needs adapter
 	 * to driver communication memory to be allocated below 2gig
 	 */
 	if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
-		if (pci_set_dma_mask(pdev, DMA_BIT_MASK(31)) ||
-				pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(31)))
-			goto out_disable_pdev;
+		dmamask = DMA_BIT_MASK(31);
+	else
+		dmamask = DMA_BIT_MASK(32);
+
+	if (pci_set_dma_mask(pdev, dmamask) ||
+			pci_set_consistent_dma_mask(pdev, dmamask))
+		goto out_disable_pdev;
 
 	pci_set_master(pdev);
 
diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c
index 6d86a9b..5000bd6 100644
--- a/drivers/scsi/aic7xxx/aic7770.c
+++ b/drivers/scsi/aic7xxx/aic7770.c
@@ -170,7 +170,7 @@
 	case 15:
 		break;
 	default:
-		printf("aic7770_config: invalid irq setting %d\n", intdef);
+		printk("aic7770_config: invalid irq setting %d\n", intdef);
 		return (ENXIO);
 	}
 
@@ -221,7 +221,7 @@
 		break;
 	}
 	if (have_seeprom == 0) {
-		free(ahc->seep_config, M_DEVBUF);
+		kfree(ahc->seep_config);
 		ahc->seep_config = NULL;
 	}
 
@@ -293,7 +293,7 @@
 	sc = ahc->seep_config;
 
 	if (bootverbose)
-		printf("%s: Reading SEEPROM...", ahc_name(ahc));
+		printk("%s: Reading SEEPROM...", ahc_name(ahc));
 	have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,
 					/*start_addr*/0, sizeof(*sc)/2);
 
@@ -301,16 +301,16 @@
 
 		if (ahc_verify_cksum(sc) == 0) {
 			if(bootverbose)
-				printf ("checksum error\n");
+				printk ("checksum error\n");
 			have_seeprom = 0;
 		} else if (bootverbose) {
-			printf("done.\n");
+			printk("done.\n");
 		}
 	}
 
 	if (!have_seeprom) {
 		if (bootverbose)
-			printf("%s: No SEEPROM available\n", ahc_name(ahc));
+			printk("%s: No SEEPROM available\n", ahc_name(ahc));
 		ahc->flags |= AHC_USEDEFAULTS;
 	} else {
 		/*
diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c
index f220e5e..0cb8ef6 100644
--- a/drivers/scsi/aic7xxx/aic7770_osm.c
+++ b/drivers/scsi/aic7xxx/aic7770_osm.c
@@ -85,7 +85,7 @@
 	int	error;
 
 	sprintf(buf, "ahc_eisa:%d", eisaBase >> 12);
-	name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+	name = kmalloc(strlen(buf) + 1, GFP_ATOMIC);
 	if (name == NULL)
 		return (ENOMEM);
 	strcpy(name, buf);
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 78971db..3233bf5 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -289,7 +289,7 @@
 	 || ahd->dst_mode == AHD_MODE_UNKNOWN)
 		panic("Setting mode prior to saving it.\n");
 	if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
-		printf("%s: Setting mode 0x%x\n", ahd_name(ahd),
+		printk("%s: Setting mode 0x%x\n", ahd_name(ahd),
 		       ahd_build_mode_state(ahd, src, dst));
 #endif
 	ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst));
@@ -307,7 +307,7 @@
 	mode_ptr = ahd_inb(ahd, MODE_PTR);
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
-		printf("Reading mode 0x%x\n", mode_ptr);
+		printk("Reading mode 0x%x\n", mode_ptr);
 #endif
 	ahd_extract_mode_state(ahd, mode_ptr, &src, &dst);
 	ahd_known_modes(ahd, src, dst);
@@ -877,7 +877,7 @@
 		uint64_t host_dataptr;
 
 		host_dataptr = ahd_le64toh(scb->hscb->dataptr);
-		printf("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
+		printk("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
 		       ahd_name(ahd),
 		       SCB_GET_TAG(scb), scb->hscb->scsiid,
 		       ahd_le32toh(scb->hscb->hscb_busaddr),
@@ -1174,7 +1174,7 @@
 
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_FIFOS) != 0)
-		printf("%s: Clearing FIFO %d\n", ahd_name(ahd), fifo);
+		printk("%s: Clearing FIFO %d\n", ahd_name(ahd), fifo);
 #endif
 	saved_modes = ahd_save_modes(ahd);
 	ahd_set_modes(ahd, fifo, fifo);
@@ -1215,7 +1215,7 @@
 		scbid = ahd_inw(ahd, GSFIFO);
 		scb = ahd_lookup_scb(ahd, scbid);
 		if (scb == NULL) {
-			printf("%s: Warning - GSFIFO SCB %d invalid\n",
+			printk("%s: Warning - GSFIFO SCB %d invalid\n",
 			       ahd_name(ahd), scbid);
 			continue;
 		}
@@ -1339,7 +1339,7 @@
 		next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
 		scb = ahd_lookup_scb(ahd, scbid);
 		if (scb == NULL) {
-			printf("%s: Warning - DMA-up and complete "
+			printk("%s: Warning - DMA-up and complete "
 			       "SCB %d invalid\n", ahd_name(ahd), scbid);
 			continue;
 		}
@@ -1360,7 +1360,7 @@
 		next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
 		scb = ahd_lookup_scb(ahd, scbid);
 		if (scb == NULL) {
-			printf("%s: Warning - Complete Qfrz SCB %d invalid\n",
+			printk("%s: Warning - Complete Qfrz SCB %d invalid\n",
 			       ahd_name(ahd), scbid);
 			continue;
 		}
@@ -1377,7 +1377,7 @@
 		next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
 		scb = ahd_lookup_scb(ahd, scbid);
 		if (scb == NULL) {
-			printf("%s: Warning - Complete SCB %d invalid\n",
+			printk("%s: Warning - Complete SCB %d invalid\n",
 			       ahd_name(ahd), scbid);
 			continue;
 		}
@@ -1682,7 +1682,7 @@
 		scb_index = ahd_le16toh(completion->tag);
 		scb = ahd_lookup_scb(ahd, scb_index);
 		if (scb == NULL) {
-			printf("%s: WARNING no command for scb %d "
+			printk("%s: WARNING no command for scb %d "
 			       "(cmdcmplt)\nQOUTPOS = %d\n",
 			       ahd_name(ahd), scb_index,
 			       ahd->qoutfifonext);
@@ -1714,7 +1714,7 @@
 	error = ahd_inb(ahd, ERROR);
 	for (i = 0; i < num_errors; i++) {
 		if ((error & ahd_hard_errors[i].errno) != 0)
-			printf("%s: hwerrint, %s\n",
+			printk("%s: hwerrint, %s\n",
 			       ahd_name(ahd), ahd_hard_errors[i].errmesg);
 	}
 
@@ -1747,7 +1747,7 @@
 
 				addr = ahd_le64toh(sg_list[i].addr);
 				len = ahd_le32toh(sg_list[i].len);
-				printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
+				printk("sg[%d] - Addr 0x%x%x : Length %d%s\n",
 				       i,
 				       (uint32_t)((addr >> 32) & 0xFFFFFFFF),
 				       (uint32_t)(addr & 0xFFFFFFFF),
@@ -1763,7 +1763,7 @@
 				uint32_t len;
 
 				len = ahd_le32toh(sg_list[i].len);
-				printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
+				printk("sg[%d] - Addr 0x%x%x : Length %d%s\n",
 				       i,
 				       (len & AHD_SG_HIGH_ADDR_MASK) >> 24,
 				       ahd_le32toh(sg_list[i].addr),
@@ -1802,7 +1802,7 @@
 	ahd_update_modes(ahd);
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_MISC) != 0)
-		printf("%s: Handle Seqint Called for code %d\n",
+		printk("%s: Handle Seqint Called for code %d\n",
 		       ahd_name(ahd), seqintcode);
 #endif
 	switch (seqintcode) {
@@ -1836,18 +1836,18 @@
 			 */
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
-				printf("%s: Assuming LQIPHASE_NLQ with "
+				printk("%s: Assuming LQIPHASE_NLQ with "
 				       "P0 assertion\n", ahd_name(ahd));
 #endif
 		}
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
-			printf("%s: Entering NONPACK\n", ahd_name(ahd));
+			printk("%s: Entering NONPACK\n", ahd_name(ahd));
 #endif
 		break;
 	}
 	case INVALID_SEQINT:
-		printf("%s: Invalid Sequencer interrupt occurred, "
+		printk("%s: Invalid Sequencer interrupt occurred, "
 		       "resetting channel.\n",
 		       ahd_name(ahd));
 #ifdef AHD_DEBUG
@@ -1866,8 +1866,8 @@
 		if (scb != NULL)
 			ahd_print_path(ahd, scb);
 		else
-			printf("%s: ", ahd_name(ahd));
-		printf("SCB %d Packetized Status Overrun", scbid);
+			printk("%s: ", ahd_name(ahd));
+		printk("SCB %d Packetized Status Overrun", scbid);
 		ahd_dump_card_state(ahd);
 		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
 		break;
@@ -1881,7 +1881,7 @@
 		scb = ahd_lookup_scb(ahd, scbid);
 		if (scb == NULL) {
 			ahd_dump_card_state(ahd);
-			printf("CFG4ISTAT: Free SCB %d referenced", scbid);
+			printk("CFG4ISTAT: Free SCB %d referenced", scbid);
 			panic("For safety");
 		}
 		ahd_outq(ahd, HADDR, scb->sense_busaddr);
@@ -1896,7 +1896,7 @@
 		u_int bus_phase;
 
 		bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK;
-		printf("%s: ILLEGAL_PHASE 0x%x\n",
+		printk("%s: ILLEGAL_PHASE 0x%x\n",
 		       ahd_name(ahd), bus_phase);
 
 		switch (bus_phase) {
@@ -1908,7 +1908,7 @@
 		case P_STATUS:
 		case P_MESGIN:
 			ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
-			printf("%s: Issued Bus Reset.\n", ahd_name(ahd));
+			printk("%s: Issued Bus Reset.\n", ahd_name(ahd));
 			break;
 		case P_COMMAND:
 		{
@@ -1933,7 +1933,7 @@
 			scbid = ahd_get_scbptr(ahd);
 			scb = ahd_lookup_scb(ahd, scbid);
 			if (scb == NULL) {
-				printf("Invalid phase with no valid SCB.  "
+				printk("Invalid phase with no valid SCB.  "
 				       "Resetting bus.\n");
 				ahd_reset_channel(ahd, 'A',
 						  /*Initiate Reset*/TRUE);
@@ -1997,7 +1997,7 @@
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
 				ahd_print_path(ahd, scb);
-				printf("Unexpected command phase from "
+				printk("Unexpected command phase from "
 				       "packetized target\n");
 			}
 #endif
@@ -2013,7 +2013,7 @@
 		
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
-			printf("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd),
+			printk("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd),
 			       ahd_inb(ahd, MODE_PTR));
 		}
 #endif
@@ -2049,7 +2049,7 @@
 	{
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
-			printf("%s: PDATA_REINIT - DFCNTRL = 0x%x "
+			printk("%s: PDATA_REINIT - DFCNTRL = 0x%x "
 			       "SG_CACHE_SHADOW = 0x%x\n",
 			       ahd_name(ahd), ahd_inb(ahd, DFCNTRL),
 			       ahd_inb(ahd, SG_CACHE_SHADOW));
@@ -2082,7 +2082,7 @@
 			bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK;
 			if (bus_phase != P_MESGIN
 			 && bus_phase != P_MESGOUT) {
-				printf("ahd_intr: HOST_MSG_LOOP bad "
+				printk("ahd_intr: HOST_MSG_LOOP bad "
 				       "phase 0x%x\n", bus_phase);
 				/*
 				 * Probably transitioned to bus free before
@@ -2131,29 +2131,29 @@
 		AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
 		ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
 
-		printf("%s:%c:%d: no active SCB for reconnecting "
+		printk("%s:%c:%d: no active SCB for reconnecting "
 		       "target - issuing BUS DEVICE RESET\n",
 		       ahd_name(ahd), 'A', ahd_inb(ahd, SELID) >> 4);
-		printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
+		printk("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
 		       "REG0 == 0x%x ACCUM = 0x%x\n",
 		       ahd_inb(ahd, SAVED_SCSIID), ahd_inb(ahd, SAVED_LUN),
 		       ahd_inw(ahd, REG0), ahd_inb(ahd, ACCUM));
-		printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
+		printk("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
 		       "SINDEX == 0x%x\n",
 		       ahd_inb(ahd, SEQ_FLAGS), ahd_get_scbptr(ahd),
 		       ahd_find_busy_tcl(ahd,
 					 BUILD_TCL(ahd_inb(ahd, SAVED_SCSIID),
 						   ahd_inb(ahd, SAVED_LUN))),
 		       ahd_inw(ahd, SINDEX));
-		printf("SELID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
+		printk("SELID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
 		       "SCB_CONTROL == 0x%x\n",
 		       ahd_inb(ahd, SELID), ahd_inb_scbram(ahd, SCB_SCSIID),
 		       ahd_inb_scbram(ahd, SCB_LUN),
 		       ahd_inb_scbram(ahd, SCB_CONTROL));
-		printf("SCSIBUS[0] == 0x%x, SCSISIGI == 0x%x\n",
+		printk("SCSIBUS[0] == 0x%x, SCSISIGI == 0x%x\n",
 		       ahd_inb(ahd, SCSIBUS), ahd_inb(ahd, SCSISIGI));
-		printf("SXFRCTL0 == 0x%x\n", ahd_inb(ahd, SXFRCTL0));
-		printf("SEQCTL0 == 0x%x\n", ahd_inb(ahd, SEQCTL0));
+		printk("SXFRCTL0 == 0x%x\n", ahd_inb(ahd, SXFRCTL0));
+		printk("SEQCTL0 == 0x%x\n", ahd_inb(ahd, SEQCTL0));
 		ahd_dump_card_state(ahd);
 		ahd->msgout_buf[0] = MSG_BUS_DEV_RESET;
 		ahd->msgout_len = 1;
@@ -2181,7 +2181,7 @@
 		u_int lastphase;
 
 		lastphase = ahd_inb(ahd, LASTPHASE);
-		printf("%s:%c:%d: unknown scsi bus phase %x, "
+		printk("%s:%c:%d: unknown scsi bus phase %x, "
 		       "lastphase = 0x%x.  Attempting to continue\n",
 		       ahd_name(ahd), 'A',
 		       SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)),
@@ -2193,7 +2193,7 @@
 		u_int lastphase;
 
 		lastphase = ahd_inb(ahd, LASTPHASE);
-		printf("%s:%c:%d: Missed busfree. "
+		printk("%s:%c:%d: Missed busfree. "
 		       "Lastphase = 0x%x, Curphase = 0x%x\n",
 		       ahd_name(ahd), 'A',
 		       SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)),
@@ -2223,11 +2223,11 @@
 		lastphase = ahd_inb(ahd, LASTPHASE);
 		if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
 			ahd_print_path(ahd, scb);
-			printf("data overrun detected %s.  Tag == 0x%x.\n",
+			printk("data overrun detected %s.  Tag == 0x%x.\n",
 			       ahd_lookup_phase_entry(lastphase)->phasemsg,
 			       SCB_GET_TAG(scb));
 			ahd_print_path(ahd, scb);
-			printf("%s seen Data Phase.  Length = %ld.  "
+			printk("%s seen Data Phase.  Length = %ld.  "
 			       "NumSGs = %d.\n",
 			       ahd_inb(ahd, SEQ_FLAGS) & DPHASE
 			       ? "Have" : "Haven't",
@@ -2252,7 +2252,7 @@
 		u_int scbid;
 
 		ahd_fetch_devinfo(ahd, &devinfo);
-		printf("%s:%c:%d:%d: Attempt to issue message failed\n",
+		printk("%s:%c:%d:%d: Attempt to issue message failed\n",
 		       ahd_name(ahd), devinfo.channel, devinfo.target,
 		       devinfo.lun);
 		scbid = ahd_get_scbptr(ahd);
@@ -2285,7 +2285,7 @@
 			cam_status error;
 
 			ahd_print_path(ahd, scb);
-			printf("Task Management Func 0x%x Complete\n",
+			printk("Task Management Func 0x%x Complete\n",
 			       scb->hscb->task_management);
 			lun = CAM_LUN_WILDCARD;
 			tag = SCB_LIST_NULL;
@@ -2341,7 +2341,7 @@
 			 * the QINFIFO if it is still there.
                          */
 			ahd_print_path(ahd, scb);
-			printf("SCB completes before TMF\n");
+			printk("SCB completes before TMF\n");
 			/*
 			 * Handle losing the race.  Wait until any
 			 * current selection completes.  We will then
@@ -2366,7 +2366,7 @@
 	case TRACEPOINT1:
 	case TRACEPOINT2:
 	case TRACEPOINT3:
-		printf("%s: Tracepoint %d\n", ahd_name(ahd),
+		printk("%s: Tracepoint %d\n", ahd_name(ahd),
 		       seqintcode - TRACEPOINT0);
 		break;
 	case NO_SEQINT:
@@ -2375,7 +2375,7 @@
 		ahd_handle_hwerrint(ahd);
 		break;
 	default:
-		printf("%s: Unexpected SEQINTCODE %d\n", ahd_name(ahd),
+		printk("%s: Unexpected SEQINTCODE %d\n", ahd_name(ahd),
 		       seqintcode);
 		break;
 	}
@@ -2440,7 +2440,7 @@
 		u_int now_lvd;
 
 		now_lvd = ahd_inb(ahd, SBLKCTL) & ENAB40;
-		printf("%s: Transceiver State Has Changed to %s mode\n",
+		printk("%s: Transceiver State Has Changed to %s mode\n",
 		       ahd_name(ahd), now_lvd ? "LVD" : "SE");
 		ahd_outb(ahd, CLRSINT0, CLRIOERR);
 		/*
@@ -2452,12 +2452,12 @@
 		ahd_unpause(ahd);
 	} else if ((status0 & OVERRUN) != 0) {
 
-		printf("%s: SCSI offset overrun detected.  Resetting bus.\n",
+		printk("%s: SCSI offset overrun detected.  Resetting bus.\n",
 		       ahd_name(ahd));
 		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
 	} else if ((status & SCSIRSTI) != 0) {
 
-		printf("%s: Someone reset channel A\n", ahd_name(ahd));
+		printk("%s: Someone reset channel A\n", ahd_name(ahd));
 		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/FALSE);
 	} else if ((status & SCSIPERR) != 0) {
 
@@ -2467,7 +2467,7 @@
 		ahd_handle_transmission_error(ahd);
 	} else if (lqostat0 != 0) {
 
-		printf("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0);
+		printk("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0);
 		ahd_outb(ahd, CLRLQOINT0, lqostat0);
 		if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0)
 			ahd_outb(ahd, CLRLQOINT1, 0);
@@ -2497,7 +2497,7 @@
 		scbid = ahd_inw(ahd, WAITING_TID_HEAD);
 		scb = ahd_lookup_scb(ahd, scbid);
 		if (scb == NULL) {
-			printf("%s: ahd_intr - referenced scb not "
+			printk("%s: ahd_intr - referenced scb not "
 			       "valid during SELTO scb(0x%x)\n",
 			       ahd_name(ahd), scbid);
 			ahd_dump_card_state(ahd);
@@ -2506,7 +2506,7 @@
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_SELTO) != 0) {
 				ahd_print_path(ahd, scb);
-				printf("Saw Selection Timeout for SCB 0x%x\n",
+				printk("Saw Selection Timeout for SCB 0x%x\n",
 				       scbid);
 			}
 #endif
@@ -2534,7 +2534,7 @@
 		ahd_iocell_first_selection(ahd);
 		ahd_unpause(ahd);
 	} else if (status3 != 0) {
-		printf("%s: SCSI Cell parity error SSTAT3 == 0x%x\n",
+		printk("%s: SCSI Cell parity error SSTAT3 == 0x%x\n",
 		       ahd_name(ahd), status3);
 		ahd_outb(ahd, CLRSINT3, status3);
 	} else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) {
@@ -2587,7 +2587,7 @@
 			scbid = ahd_get_scbptr(ahd);
 			scb = ahd_lookup_scb(ahd, scbid);
 			if (scb == NULL) {
-				printf("%s: Invalid SCB %d in DFF%d "
+				printk("%s: Invalid SCB %d in DFF%d "
 				       "during unexpected busfree\n",
 				       ahd_name(ahd), scbid, mode);
 				packetized = 0;
@@ -2620,7 +2620,7 @@
 
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_MISC) != 0)
-			printf("Saw Busfree.  Busfreetime = 0x%x.\n",
+			printk("Saw Busfree.  Busfreetime = 0x%x.\n",
 			       busfreetime);
 #endif
 		/*
@@ -2661,7 +2661,7 @@
 			ahd_unpause(ahd);
 		}
 	} else {
-		printf("%s: Missing case in ahd_handle_scsiint. status = %x\n",
+		printk("%s: Missing case in ahd_handle_scsiint. status = %x\n",
 		       ahd_name(ahd), status);
 		ahd_dump_card_state(ahd);
 		ahd_clear_intstat(ahd);
@@ -2697,7 +2697,7 @@
 		 || (lqistate == 0x29)) {
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
-				printf("%s: NLQCRC found via LQISTATE\n",
+				printk("%s: NLQCRC found via LQISTATE\n",
 				       ahd_name(ahd));
 			}
 #endif
@@ -2729,18 +2729,18 @@
 
 	cur_col = 0;
 	if (silent == FALSE) {
-		printf("%s: Transmission error detected\n", ahd_name(ahd));
+		printk("%s: Transmission error detected\n", ahd_name(ahd));
 		ahd_lqistat1_print(lqistat1, &cur_col, 50);
 		ahd_lastphase_print(lastphase, &cur_col, 50);
 		ahd_scsisigi_print(curphase, &cur_col, 50);
 		ahd_perrdiag_print(perrdiag, &cur_col, 50);
-		printf("\n");
+		printk("\n");
 		ahd_dump_card_state(ahd);
 	}
 
 	if ((lqistat1 & (LQIOVERI_LQ|LQIOVERI_NLQ)) != 0) {
 		if (silent == FALSE) {
-			printf("%s: Gross protocol error during incoming "
+			printk("%s: Gross protocol error during incoming "
 			       "packet.  lqistat1 == 0x%x.  Resetting bus.\n",
 			       ahd_name(ahd), lqistat1);
 		}
@@ -2769,7 +2769,7 @@
 		 * (SPI4R09 10.7.3.3.3)
 		 */
 		ahd_outb(ahd, LQCTL2, LQIRETRY);
-		printf("LQIRetry for LQICRCI_LQ to release ACK\n");
+		printk("LQIRetry for LQICRCI_LQ to release ACK\n");
 	} else if ((lqistat1 & LQICRCI_NLQ) != 0) {
 		/*
 		 * We detected a CRC error in a NON-LQ packet.
@@ -2817,22 +2817,22 @@
 		 * Busfree detection is enabled.
 		 */
 		if (silent == FALSE)
-			printf("LQICRC_NLQ\n");
+			printk("LQICRC_NLQ\n");
 		if (scb == NULL) {
-			printf("%s: No SCB valid for LQICRC_NLQ.  "
+			printk("%s: No SCB valid for LQICRC_NLQ.  "
 			       "Resetting bus\n", ahd_name(ahd));
 			ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
 			return;
 		}
 	} else if ((lqistat1 & LQIBADLQI) != 0) {
-		printf("Need to handle BADLQI!\n");
+		printk("Need to handle BADLQI!\n");
 		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
 		return;
 	} else if ((perrdiag & (PARITYERR|PREVPHASE)) == PARITYERR) {
 		if ((curphase & ~P_DATAIN_DT) != 0) {
 			/* Ack the byte.  So we can continue. */
 			if (silent == FALSE)
-				printf("Acking %s to clear perror\n",
+				printk("Acking %s to clear perror\n",
 				    ahd_lookup_phase_entry(curphase)->phasemsg);
 			ahd_inb(ahd, SCSIDAT);
 		}
@@ -2877,10 +2877,10 @@
 	if ((ahd_inb(ahd, SCSISIGO) & ATNO) != 0
 	 && (ahd_inb(ahd, MDFFSTAT) & DLZERO) != 0) {
 		if ((lqistat1 & LQIPHASE_LQ) != 0) {
-			printf("LQIRETRY for LQIPHASE_LQ\n");
+			printk("LQIRETRY for LQIPHASE_LQ\n");
 			ahd_outb(ahd, LQCTL2, LQIRETRY);
 		} else if ((lqistat1 & LQIPHASE_NLQ) != 0) {
-			printf("LQIRETRY for LQIPHASE_NLQ\n");
+			printk("LQIRETRY for LQIPHASE_NLQ\n");
 			ahd_outb(ahd, LQCTL2, LQIRETRY);
 		} else
 			panic("ahd_handle_lqiphase_error: No phase errors\n");
@@ -2888,7 +2888,7 @@
 		ahd_outb(ahd, CLRINT, CLRSCSIINT);
 		ahd_unpause(ahd);
 	} else {
-		printf("Reseting Channel for LQI Phase error\n");
+		printk("Reseting Channel for LQI Phase error\n");
 		ahd_dump_card_state(ahd);
 		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
 	}
@@ -2976,7 +2976,7 @@
 		if (scb->crc_retry_count < AHD_MAX_LQ_CRC_ERRORS) {
 			if (SCB_IS_SILENT(scb) == FALSE) {
 				ahd_print_path(ahd, scb);
-				printf("Probable outgoing LQ CRC error.  "
+				printk("Probable outgoing LQ CRC error.  "
 				       "Retrying command\n");
 			}
 			scb->crc_retry_count++;
@@ -2998,7 +2998,7 @@
 		ahd_outb(ahd, CLRSINT1, CLRSCSIPERR|CLRBUSFREE);
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_MASKED_ERRORS) != 0)
-			printf("%s: Parity on last REQ detected "
+			printk("%s: Parity on last REQ detected "
 			       "during busfree phase.\n",
 			       ahd_name(ahd));
 #endif
@@ -3012,7 +3012,7 @@
 		scbid = ahd_get_scbptr(ahd);
 		scb = ahd_lookup_scb(ahd, scbid);
 		ahd_print_path(ahd, scb);
-		printf("Unexpected PKT busfree condition\n");
+		printk("Unexpected PKT busfree condition\n");
 		ahd_dump_card_state(ahd);
 		ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 'A',
 			       SCB_GET_LUN(scb), SCB_GET_TAG(scb),
@@ -3021,7 +3021,7 @@
 		/* Return restarting the sequencer. */
 		return (1);
 	}
-	printf("%s: Unexpected PKT busfree condition\n", ahd_name(ahd));
+	printk("%s: Unexpected PKT busfree condition\n", ahd_name(ahd));
 	ahd_dump_card_state(ahd);
 	/* Restart the sequencer. */
 	return (1);
@@ -3076,14 +3076,14 @@
 
 			if (scb == NULL) {
 				ahd_print_devinfo(ahd, &devinfo);
-				printf("Abort for unidentified "
+				printk("Abort for unidentified "
 				       "connection completed.\n");
 				/* restart the sequencer. */
 				return (1);
 			}
 			sent_msg = ahd->msgout_buf[ahd->msgout_index - 1];
 			ahd_print_path(ahd, scb);
-			printf("SCB %d - Abort%s Completed.\n",
+			printk("SCB %d - Abort%s Completed.\n",
 			       SCB_GET_TAG(scb),
 			       sent_msg == MSG_ABORT_TAG ? "" : " Tag");
 
@@ -3109,7 +3109,7 @@
 			found = ahd_abort_scbs(ahd, target, 'A', saved_lun,
 					       tag, ROLE_INITIATOR,
 					       CAM_REQ_ABORTED);
-			printf("found == 0x%x\n", found);
+			printk("found == 0x%x\n", found);
 			printerror = 0;
 		} else if (ahd_sent_msg(ahd, AHDMSG_1B,
 					MSG_BUS_DEV_RESET, TRUE)) {
@@ -3147,7 +3147,7 @@
 			 */
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
-				printf("PPR negotiation rejected busfree.\n");
+				printk("PPR negotiation rejected busfree.\n");
 #endif
 			tinfo = ahd_fetch_transinfo(ahd, devinfo.channel,
 						    devinfo.our_scsiid,
@@ -3191,7 +3191,7 @@
 			 */
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
-				printf("WDTR negotiation rejected busfree.\n");
+				printk("WDTR negotiation rejected busfree.\n");
 #endif
 			ahd_set_width(ahd, &devinfo,
 				      MSG_EXT_WDTR_BUS_8_BIT,
@@ -3216,7 +3216,7 @@
 			 */
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
-				printf("SDTR negotiation rejected busfree.\n");
+				printk("SDTR negotiation rejected busfree.\n");
 #endif
 			ahd_set_syncrate(ahd, &devinfo,
 					/*period*/0, /*offset*/0,
@@ -3240,7 +3240,7 @@
 
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
-				printf("Expected IDE Busfree\n");
+				printk("Expected IDE Busfree\n");
 #endif
 			printerror = 0;
 		} else if ((ahd->msg_flags & MSG_FLAG_EXPECT_QASREJ_BUSFREE)
@@ -3249,7 +3249,7 @@
 
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
-				printf("Expected QAS Reject Busfree\n");
+				printk("Expected QAS Reject Busfree\n");
 #endif
 			printerror = 0;
 		}
@@ -3275,7 +3275,7 @@
 		} else {
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
-				printf("PPR Negotiation Busfree.\n");
+				printk("PPR Negotiation Busfree.\n");
 #endif
 			ahd_done(ahd, scb);
 		}
@@ -3302,9 +3302,9 @@
 			 * We had not fully identified this connection,
 			 * so we cannot abort anything.
 			 */
-			printf("%s: ", ahd_name(ahd));
+			printk("%s: ", ahd_name(ahd));
 		}
-		printf("Unexpected busfree %s, %d SCBs aborted, "
+		printk("Unexpected busfree %s, %d SCBs aborted, "
 		       "PRGMCNT == 0x%x\n",
 		       ahd_lookup_phase_entry(lastphase)->phasemsg,
 		       aborted,
@@ -3342,7 +3342,7 @@
 		 * to match.
 		 */
 		ahd_print_devinfo(ahd, &devinfo);
-		printf("Target did not send an IDENTIFY message. "
+		printk("Target did not send an IDENTIFY message. "
 		       "LASTPHASE = 0x%x.\n", lastphase);
 		scb = NULL;
 	} else if (scb == NULL) {
@@ -3351,13 +3351,13 @@
 		 * transaction.  Print an error and reset the bus.
 		 */
 		ahd_print_devinfo(ahd, &devinfo);
-		printf("No SCB found during protocol violation\n");
+		printk("No SCB found during protocol violation\n");
 		goto proto_violation_reset;
 	} else {
 		ahd_set_transaction_status(scb, CAM_SEQUENCE_FAIL);
 		if ((seq_flags & NO_CDB_SENT) != 0) {
 			ahd_print_path(ahd, scb);
-			printf("No or incomplete CDB sent to device.\n");
+			printk("No or incomplete CDB sent to device.\n");
 		} else if ((ahd_inb_scbram(ahd, SCB_CONTROL)
 			  & STATUS_RCVD) == 0) {
 			/*
@@ -3368,10 +3368,10 @@
 			 * message.
 			 */
 			ahd_print_path(ahd, scb);
-			printf("Completed command without status.\n");
+			printk("Completed command without status.\n");
 		} else {
 			ahd_print_path(ahd, scb);
-			printf("Unknown protocol violation.\n");
+			printk("Unknown protocol violation.\n");
 			ahd_dump_card_state(ahd);
 		}
 	}
@@ -3385,7 +3385,7 @@
 		 * it away with a bus reset.
 		 */
 		found = ahd_reset_channel(ahd, 'A', TRUE);
-		printf("%s: Issued Channel %c Bus Reset. "
+		printk("%s: Issued Channel %c Bus Reset. "
 		       "%d SCBs aborted\n", ahd_name(ahd), 'A', found);
 	} else {
 		/*
@@ -3407,7 +3407,7 @@
 			ahd_print_path(ahd, scb);
 			scb->flags |= SCB_ABORT;
 		}
-		printf("Protocol violation %s.  Attempting to abort.\n",
+		printk("Protocol violation %s.  Attempting to abort.\n",
 		       ahd_lookup_phase_entry(curphase)->phasemsg);
 	}
 }
@@ -3425,7 +3425,7 @@
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
 		ahd_print_devinfo(ahd, devinfo);
-		printf("Forcing renegotiation\n");
+		printk("Forcing renegotiation\n");
 	}
 #endif
 	targ_info = ahd_fetch_transinfo(ahd,
@@ -3486,7 +3486,7 @@
 			break;
 
 		if (steps > AHD_MAX_STEPS) {
-			printf("%s: Infinite loop in critical section\n"
+			printk("%s: Infinite loop in critical section\n"
 			       "%s: First Instruction 0x%x now 0x%x\n",
 			       ahd_name(ahd), ahd_name(ahd), first_instr,
 			       seqaddr);
@@ -3497,7 +3497,7 @@
 		steps++;
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_MISC) != 0)
-			printf("%s: Single stepping at 0x%x\n", ahd_name(ahd),
+			printk("%s: Single stepping at 0x%x\n", ahd_name(ahd),
 			       seqaddr);
 #endif
 		if (stepping == FALSE) {
@@ -3601,16 +3601,16 @@
 	int i;
 
 	hscb = scb->hscb;
-	printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
+	printk("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
 	       (void *)scb,
 	       hscb->control,
 	       hscb->scsiid,
 	       hscb->lun,
 	       hscb->cdb_len);
-	printf("Shared Data: ");
+	printk("Shared Data: ");
 	for (i = 0; i < sizeof(hscb->shared_data.idata.cdb); i++)
-		printf("%#02x", hscb->shared_data.idata.cdb[i]);
-	printf("        dataptr:%#x%x datacnt:%#x sgptr:%#x tag:%#x\n",
+		printk("%#02x", hscb->shared_data.idata.cdb[i]);
+	printk("        dataptr:%#x%x datacnt:%#x sgptr:%#x tag:%#x\n",
 	       (uint32_t)((ahd_le64toh(hscb->dataptr) >> 32) & 0xFFFFFFFF),
 	       (uint32_t)(ahd_le64toh(hscb->dataptr) & 0xFFFFFFFF),
 	       ahd_le32toh(hscb->datacnt),
@@ -3637,7 +3637,7 @@
 	 && ahd->enabled_targets[scsi_id] != master_tstate)
 		panic("%s: ahd_alloc_tstate - Target already allocated",
 		      ahd_name(ahd));
-	tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT);
+	tstate = kmalloc(sizeof(*tstate), GFP_ATOMIC);
 	if (tstate == NULL)
 		return (NULL);
 
@@ -3682,7 +3682,7 @@
 
 	tstate = ahd->enabled_targets[scsi_id];
 	if (tstate != NULL)
-		free(tstate, M_DEVBUF);
+		kfree(tstate);
 	ahd->enabled_targets[scsi_id] = NULL;
 }
 #endif
@@ -3942,37 +3942,37 @@
 			if (offset != 0) {
 				int options;
 
-				printf("%s: target %d synchronous with "
+				printk("%s: target %d synchronous with "
 				       "period = 0x%x, offset = 0x%x",
 				       ahd_name(ahd), devinfo->target,
 				       period, offset);
 				options = 0;
 				if ((ppr_options & MSG_EXT_PPR_RD_STRM) != 0) {
-					printf("(RDSTRM");
+					printk("(RDSTRM");
 					options++;
 				}
 				if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
-					printf("%s", options ? "|DT" : "(DT");
+					printk("%s", options ? "|DT" : "(DT");
 					options++;
 				}
 				if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
-					printf("%s", options ? "|IU" : "(IU");
+					printk("%s", options ? "|IU" : "(IU");
 					options++;
 				}
 				if ((ppr_options & MSG_EXT_PPR_RTI) != 0) {
-					printf("%s", options ? "|RTI" : "(RTI");
+					printk("%s", options ? "|RTI" : "(RTI");
 					options++;
 				}
 				if ((ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) {
-					printf("%s", options ? "|QAS" : "(QAS");
+					printk("%s", options ? "|QAS" : "(QAS");
 					options++;
 				}
 				if (options != 0)
-					printf(")\n");
+					printk(")\n");
 				else
-					printf("\n");
+					printk("\n");
 			} else {
-				printf("%s: target %d using "
+				printk("%s: target %d using "
 				       "asynchronous transfers%s\n",
 				       ahd_name(ahd), devinfo->target,
 				       (ppr_options & MSG_EXT_PPR_QAS_REQ) != 0
@@ -4000,7 +4000,7 @@
 #ifdef AHD_DEBUG
 				if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
 					ahd_print_devinfo(ahd, devinfo);
-					printf("Expecting IU Change busfree\n");
+					printk("Expecting IU Change busfree\n");
 				}
 #endif
 				ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE
@@ -4009,7 +4009,7 @@
 			if ((old_ppr & MSG_EXT_PPR_IU_REQ) != 0) {
 #ifdef AHD_DEBUG
 				if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
-					printf("PPR with IU_REQ outstanding\n");
+					printk("PPR with IU_REQ outstanding\n");
 #endif
 				ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE;
 			}
@@ -4061,7 +4061,7 @@
 		ahd_send_async(ahd, devinfo->channel, devinfo->target,
 			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
 		if (bootverbose) {
-			printf("%s: target %d using %dbit transfers\n",
+			printk("%s: target %d using %dbit transfers\n",
 			       ahd_name(ahd), devinfo->target,
 			       8 * (0x01 << width));
 		}
@@ -4337,7 +4337,7 @@
 void
 ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
 {
-	printf("%s:%c:%d:%d: ", ahd_name(ahd), 'A',
+	printk("%s:%c:%d:%d: ", ahd_name(ahd), 'A',
 	       devinfo->target, devinfo->lun);
 }
 
@@ -4419,11 +4419,11 @@
 		ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
-			printf("Setting up for Parity Error delivery\n");
+			printk("Setting up for Parity Error delivery\n");
 #endif
 		return;
 	} else if (scb == NULL) {
-		printf("%s: WARNING. No pending message for "
+		printk("%s: WARNING. No pending message for "
 		       "I_T msgin.  Issuing NO-OP\n", ahd_name(ahd));
 		ahd->msgout_buf[ahd->msgout_index++] = MSG_NOOP;
 		ahd->msgout_len++;
@@ -4454,7 +4454,7 @@
 		ahd->msgout_buf[ahd->msgout_index++] = MSG_BUS_DEV_RESET;
 		ahd->msgout_len++;
 		ahd_print_path(ahd, scb);
-		printf("Bus Device Reset Message Sent\n");
+		printk("Bus Device Reset Message Sent\n");
 		/*
 		 * Clear our selection hardware in advance of
 		 * the busfree.  We may have an entry in the waiting
@@ -4472,7 +4472,7 @@
 		}
 		ahd->msgout_len++;
 		ahd_print_path(ahd, scb);
-		printf("Abort%s Message Sent\n",
+		printk("Abort%s Message Sent\n",
 		       (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : "");
 		/*
 		 * Clear our selection hardware in advance of
@@ -4493,9 +4493,9 @@
 		 */
 		ahd_outb(ahd, SCSISEQ0, 0);
 	} else {
-		printf("ahd_intr: AWAITING_MSG for an SCB that "
+		printk("ahd_intr: AWAITING_MSG for an SCB that "
 		       "does not have a waiting message\n");
-		printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid,
+		printk("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid,
 		       devinfo->target_mask);
 		panic("SCB = %d, SCB Control = %x:%x, MSG_OUT = %x "
 		      "SCB flags = %x", SCB_GET_TAG(scb), scb->hscb->control,
@@ -4577,7 +4577,7 @@
 
 		if (bootverbose) {
 			ahd_print_devinfo(ahd, devinfo);
-			printf("Ensuring async\n");
+			printk("Ensuring async\n");
 		}
 	}
 	/* Target initiated PPR is not allowed in the SCSI spec */
@@ -4624,7 +4624,7 @@
 			ahd->msgout_buf + ahd->msgout_index, period, offset);
 	ahd->msgout_len += 5;
 	if (bootverbose) {
-		printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
+		printk("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
 		       ahd_name(ahd), devinfo->channel, devinfo->target,
 		       devinfo->lun, period, offset);
 	}
@@ -4642,7 +4642,7 @@
 			ahd->msgout_buf + ahd->msgout_index, bus_width);
 	ahd->msgout_len += 4;
 	if (bootverbose) {
-		printf("(%s:%c:%d:%d): Sending WDTR %x\n",
+		printk("(%s:%c:%d:%d): Sending WDTR %x\n",
 		       ahd_name(ahd), devinfo->channel, devinfo->target,
 		       devinfo->lun, bus_width);
 	}
@@ -4671,7 +4671,7 @@
 			bus_width, ppr_options);
 	ahd->msgout_len += 8;
 	if (bootverbose) {
-		printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
+		printk("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
 		       "offset %x, ppr_options %x\n", ahd_name(ahd),
 		       devinfo->channel, devinfo->target, devinfo->lun,
 		       bus_width, period, offset, ppr_options);
@@ -4721,7 +4721,7 @@
 	bus_phase = ahd_inb(ahd, LASTPHASE);
 
 	if ((ahd_inb(ahd, LQISTAT2) & LQIPHASE_OUTPKT) != 0) {
-		printf("LQIRETRY for LQIPHASE_OUTPKT\n");
+		printk("LQIRETRY for LQIPHASE_OUTPKT\n");
 		ahd_outb(ahd, LQCTL2, LQIRETRY);
 	}
 reswitch:
@@ -4738,14 +4738,14 @@
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
 			ahd_print_devinfo(ahd, &devinfo);
-			printf("INITIATOR_MSG_OUT");
+			printk("INITIATOR_MSG_OUT");
 		}
 #endif
 		phasemis = bus_phase != P_MESGOUT;
 		if (phasemis) {
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
-				printf(" PHASEMIS %s\n",
+				printk(" PHASEMIS %s\n",
 				       ahd_lookup_phase_entry(bus_phase)
 							     ->phasemsg);
 			}
@@ -4772,7 +4772,7 @@
 			ahd_outb(ahd, CLRSINT1, CLRREQINIT);
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
-				printf(" byte 0x%x\n", ahd->send_msg_perror);
+				printk(" byte 0x%x\n", ahd->send_msg_perror);
 #endif
 			/*
 			 * If we are notifying the target of a CRC error
@@ -4813,7 +4813,7 @@
 		ahd_outb(ahd, CLRSINT1, CLRREQINIT);
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
-			printf(" byte 0x%x\n",
+			printk(" byte 0x%x\n",
 			       ahd->msgout_buf[ahd->msgout_index]);
 #endif
 		ahd_outb(ahd, RETURN_2, ahd->msgout_buf[ahd->msgout_index++]);
@@ -4828,14 +4828,14 @@
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
 			ahd_print_devinfo(ahd, &devinfo);
-			printf("INITIATOR_MSG_IN");
+			printk("INITIATOR_MSG_IN");
 		}
 #endif
 		phasemis = bus_phase != P_MESGIN;
 		if (phasemis) {
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
-				printf(" PHASEMIS %s\n",
+				printk(" PHASEMIS %s\n",
 				       ahd_lookup_phase_entry(bus_phase)
 							     ->phasemsg);
 			}
@@ -4856,7 +4856,7 @@
 		ahd->msgin_buf[ahd->msgin_index] = ahd_inb(ahd, SCSIBUS);
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
-			printf(" byte 0x%x\n",
+			printk(" byte 0x%x\n",
 			       ahd->msgin_buf[ahd->msgin_index]);
 #endif
 
@@ -4878,7 +4878,7 @@
 #ifdef AHD_DEBUG
 				if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
 					ahd_print_devinfo(ahd, &devinfo);
-					printf("Asserting ATN for response\n");
+					printk("Asserting ATN for response\n");
 				}
 #endif
 				ahd_assert_atn(ahd);
@@ -5026,7 +5026,7 @@
 
 	if (end_session) {
 		if ((ahd->msg_flags & MSG_FLAG_PACKETIZED) != 0) {
-			printf("%s: Returning to Idle Loop\n",
+			printk("%s: Returning to Idle Loop\n",
 			       ahd_name(ahd));
 			ahd_clear_msg_state(ahd);
 
@@ -5178,7 +5178,7 @@
 			ahd_validate_offset(ahd, tinfo, period, &offset,
 					    tinfo->curr.width, devinfo->role);
 			if (bootverbose) {
-				printf("(%s:%c:%d:%d): Received "
+				printk("(%s:%c:%d:%d): Received "
 				       "SDTR period %x, offset %x\n\t"
 				       "Filtered to period %x, offset %x\n",
 				       ahd_name(ahd), devinfo->channel,
@@ -5208,7 +5208,7 @@
 				 */
 				if (bootverbose
 				 && devinfo->role == ROLE_INITIATOR) {
-					printf("(%s:%c:%d:%d): Target "
+					printk("(%s:%c:%d:%d): Target "
 					       "Initiated SDTR\n",
 					       ahd_name(ahd), devinfo->channel,
 					       devinfo->target, devinfo->lun);
@@ -5250,7 +5250,7 @@
 			ahd_validate_width(ahd, tinfo, &bus_width,
 					   devinfo->role);
 			if (bootverbose) {
-				printf("(%s:%c:%d:%d): Received WDTR "
+				printk("(%s:%c:%d:%d): Received WDTR "
 				       "%x filtered to %x\n",
 				       ahd_name(ahd), devinfo->channel,
 				       devinfo->target, devinfo->lun,
@@ -5266,7 +5266,7 @@
 				 */
 				if (saved_width > bus_width) {
 					reject = TRUE;
-					printf("(%s:%c:%d:%d): requested %dBit "
+					printk("(%s:%c:%d:%d): requested %dBit "
 					       "transfers.  Rejecting...\n",
 					       ahd_name(ahd), devinfo->channel,
 					       devinfo->target, devinfo->lun,
@@ -5279,7 +5279,7 @@
 				 */
 				if (bootverbose
 				 && devinfo->role == ROLE_INITIATOR) {
-					printf("(%s:%c:%d:%d): Target "
+					printk("(%s:%c:%d:%d): Target "
 					       "Initiated WDTR\n",
 					       ahd_name(ahd), devinfo->channel,
 					       devinfo->target, devinfo->lun);
@@ -5391,12 +5391,12 @@
 				}
 			} else {
 				if (devinfo->role != ROLE_TARGET)
-					printf("(%s:%c:%d:%d): Target "
+					printk("(%s:%c:%d:%d): Target "
 					       "Initiated PPR\n",
 					       ahd_name(ahd), devinfo->channel,
 					       devinfo->target, devinfo->lun);
 				else
-					printf("(%s:%c:%d:%d): Initiator "
+					printk("(%s:%c:%d:%d): Initiator "
 					       "Initiated PPR\n",
 					       ahd_name(ahd), devinfo->channel,
 					       devinfo->target, devinfo->lun);
@@ -5408,7 +5408,7 @@
 				response = TRUE;
 			}
 			if (bootverbose) {
-				printf("(%s:%c:%d:%d): Received PPR width %x, "
+				printk("(%s:%c:%d:%d): Received PPR width %x, "
 				       "period %x, offset %x,options %x\n"
 				       "\tFiltered to width %x, period %x, "
 				       "offset %x, options %x\n",
@@ -5484,7 +5484,7 @@
 	case MSG_QAS_REQUEST:
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
-			printf("%s: QAS request.  SCSISIGI == 0x%x\n",
+			printk("%s: QAS request.  SCSISIGI == 0x%x\n",
 			       ahd_name(ahd), ahd_inb(ahd, SCSISIGI));
 #endif
 		ahd->msg_flags |= MSG_FLAG_EXPECT_QASREJ_BUSFREE;
@@ -5549,7 +5549,7 @@
 			 * off these options.
 			 */
 			if (bootverbose) {
-				printf("(%s:%c:%d:%d): PPR Rejected. "
+				printk("(%s:%c:%d:%d): PPR Rejected. "
 				       "Trying simple U160 PPR\n",
 				       ahd_name(ahd), devinfo->channel,
 				       devinfo->target, devinfo->lun);
@@ -5564,7 +5564,7 @@
 			 * Attempt to negotiate SPI-2 style.
 			 */
 			if (bootverbose) {
-				printf("(%s:%c:%d:%d): PPR Rejected. "
+				printk("(%s:%c:%d:%d): PPR Rejected. "
 				       "Trying WDTR/SDTR\n",
 				       ahd_name(ahd), devinfo->channel,
 				       devinfo->target, devinfo->lun);
@@ -5581,7 +5581,7 @@
 	} else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) {
 
 		/* note 8bit xfers */
-		printf("(%s:%c:%d:%d): refuses WIDE negotiation.  Using "
+		printk("(%s:%c:%d:%d): refuses WIDE negotiation.  Using "
 		       "8bit transfers\n", ahd_name(ahd),
 		       devinfo->channel, devinfo->target, devinfo->lun);
 		ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
@@ -5609,7 +5609,7 @@
 				 /*offset*/0, /*ppr_options*/0,
 				 AHD_TRANS_ACTIVE|AHD_TRANS_GOAL,
 				 /*paused*/TRUE);
-		printf("(%s:%c:%d:%d): refuses synchronous negotiation. "
+		printk("(%s:%c:%d:%d): refuses synchronous negotiation. "
 		       "Using asynchronous transfers\n",
 		       ahd_name(ahd), devinfo->channel,
 		       devinfo->target, devinfo->lun);
@@ -5620,13 +5620,13 @@
 		tag_type = (scb->hscb->control & MSG_SIMPLE_TASK);
 
 		if (tag_type == MSG_SIMPLE_TASK) {
-			printf("(%s:%c:%d:%d): refuses tagged commands.  "
+			printk("(%s:%c:%d:%d): refuses tagged commands.  "
 			       "Performing non-tagged I/O\n", ahd_name(ahd),
 			       devinfo->channel, devinfo->target, devinfo->lun);
 			ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_NONE);
 			mask = ~0x23;
 		} else {
-			printf("(%s:%c:%d:%d): refuses %s tagged commands.  "
+			printk("(%s:%c:%d:%d): refuses %s tagged commands.  "
 			       "Performing simple queue tagged I/O only\n",
 			       ahd_name(ahd), devinfo->channel, devinfo->target,
 			       devinfo->lun, tag_type == MSG_ORDERED_TASK
@@ -5677,7 +5677,7 @@
 		/*
 		 * Otherwise, we ignore it.
 		 */
-		printf("%s:%c:%d: Message reject for %x -- ignored\n",
+		printk("%s:%c:%d: Message reject for %x -- ignored\n",
 		       ahd_name(ahd), devinfo->channel, devinfo->target,
 		       last_msg);
 	}
@@ -5864,7 +5864,7 @@
 		ahd_delay(100);
 	if (wait == 0) {
 		ahd_print_path(ahd, scb);
-		printf("ahd_reinitialize_dataptrs: Forcing FIFO free.\n");
+		printk("ahd_reinitialize_dataptrs: Forcing FIFO free.\n");
 		ahd_outb(ahd, DFFSXFRCTL, RSTCHN|CLRSHCNT);
 	}
 	saved_modes = ahd_save_modes(ahd);
@@ -5978,7 +5978,7 @@
 			       CAM_LUN_WILDCARD, AC_SENT_BDR);
 
 	if (message != NULL && bootverbose)
-		printf("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd),
+		printk("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd),
 		       message, devinfo->channel, devinfo->target, found);
 }
 
@@ -6074,23 +6074,22 @@
 	struct  ahd_softc *ahd;
 
 #ifndef	__FreeBSD__
-	ahd = malloc(sizeof(*ahd), M_DEVBUF, M_NOWAIT);
+	ahd = kmalloc(sizeof(*ahd), GFP_ATOMIC);
 	if (!ahd) {
-		printf("aic7xxx: cannot malloc softc!\n");
-		free(name, M_DEVBUF);
+		printk("aic7xxx: cannot malloc softc!\n");
+		kfree(name);
 		return NULL;
 	}
 #else
 	ahd = device_get_softc((device_t)platform_arg);
 #endif
 	memset(ahd, 0, sizeof(*ahd));
-	ahd->seep_config = malloc(sizeof(*ahd->seep_config),
-				  M_DEVBUF, M_NOWAIT);
+	ahd->seep_config = kmalloc(sizeof(*ahd->seep_config), GFP_ATOMIC);
 	if (ahd->seep_config == NULL) {
 #ifndef	__FreeBSD__
-		free(ahd, M_DEVBUF);
+		kfree(ahd);
 #endif
-		free(name, M_DEVBUF);
+		kfree(name);
 		return (NULL);
 	}
 	LIST_INIT(&ahd->pending_scbs);
@@ -6120,7 +6119,7 @@
 	}
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_MEMORY) != 0) {
-		printf("%s: scb size = 0x%x, hscb size = 0x%x\n",
+		printk("%s: scb size = 0x%x, hscb size = 0x%x\n",
 		       ahd_name(ahd), (u_int)sizeof(struct scb),
 		       (u_int)sizeof(struct hardware_scb));
 	}
@@ -6147,7 +6146,7 @@
 ahd_set_name(struct ahd_softc *ahd, char *name)
 {
 	if (ahd->name != NULL)
-		free(ahd->name, M_DEVBUF);
+		kfree(ahd->name);
 	ahd->name = name;
 }
 
@@ -6201,27 +6200,27 @@
 				lstate = tstate->enabled_luns[j];
 				if (lstate != NULL) {
 					xpt_free_path(lstate->path);
-					free(lstate, M_DEVBUF);
+					kfree(lstate);
 				}
 			}
 #endif
-			free(tstate, M_DEVBUF);
+			kfree(tstate);
 		}
 	}
 #ifdef AHD_TARGET_MODE
 	if (ahd->black_hole != NULL) {
 		xpt_free_path(ahd->black_hole->path);
-		free(ahd->black_hole, M_DEVBUF);
+		kfree(ahd->black_hole);
 	}
 #endif
 	if (ahd->name != NULL)
-		free(ahd->name, M_DEVBUF);
+		kfree(ahd->name);
 	if (ahd->seep_config != NULL)
-		free(ahd->seep_config, M_DEVBUF);
+		kfree(ahd->seep_config);
 	if (ahd->saved_stack != NULL)
-		free(ahd->saved_stack, M_DEVBUF);
+		kfree(ahd->saved_stack);
 #ifndef __FreeBSD__
-	free(ahd, M_DEVBUF);
+	kfree(ahd);
 #endif
 	return;
 }
@@ -6300,7 +6299,7 @@
 	} while (--wait && !(ahd_inb(ahd, HCNTRL) & CHIPRSTACK));
 
 	if (wait == 0) {
-		printf("%s: WARNING - Failed chip reset!  "
+		printk("%s: WARNING - Failed chip reset!  "
 		       "Trying to initialize anyway.\n", ahd_name(ahd));
 	}
 	ahd_outb(ahd, HCNTRL, ahd->pause);
@@ -6422,7 +6421,7 @@
 	/* Determine the number of hardware SCBs and initialize them */
 	scb_data->maxhscbs = ahd_probe_scbs(ahd);
 	if (scb_data->maxhscbs == 0) {
-		printf("%s: No SCB space found\n", ahd_name(ahd));
+		printk("%s: No SCB space found\n", ahd_name(ahd));
 		return (ENXIO);
 	}
 
@@ -6465,7 +6464,7 @@
 	}
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_MEMORY) != 0)
-		printf("%s: ahd_sglist_allocsize = 0x%x\n", ahd_name(ahd),
+		printk("%s: ahd_sglist_allocsize = 0x%x\n", ahd_name(ahd),
 		       ahd_sglist_allocsize(ahd));
 #endif
 
@@ -6489,7 +6488,7 @@
 	ahd_alloc_scbs(ahd);
 
 	if (scb_data->numscbs == 0) {
-		printf("%s: ahd_init_scbdata - "
+		printk("%s: ahd_init_scbdata - "
 		       "Unable to allocate initial scbs\n",
 		       ahd_name(ahd));
 		goto error_exit;
@@ -6564,7 +6563,7 @@
 					  sns_map->dmamap);
 			ahd_dmamem_free(ahd, scb_data->sense_dmat,
 					sns_map->vaddr, sns_map->dmamap);
-			free(sns_map, M_DEVBUF);
+			kfree(sns_map);
 		}
 		ahd_dma_tag_destroy(ahd, scb_data->sense_dmat);
 		/* FALLTHROUGH */
@@ -6579,7 +6578,7 @@
 					  sg_map->dmamap);
 			ahd_dmamem_free(ahd, scb_data->sg_dmat,
 					sg_map->vaddr, sg_map->dmamap);
-			free(sg_map, M_DEVBUF);
+			kfree(sg_map);
 		}
 		ahd_dma_tag_destroy(ahd, scb_data->sg_dmat);
 		/* FALLTHROUGH */
@@ -6594,7 +6593,7 @@
 					  hscb_map->dmamap);
 			ahd_dmamem_free(ahd, scb_data->hscb_dmat,
 					hscb_map->vaddr, hscb_map->dmamap);
-			free(hscb_map, M_DEVBUF);
+			kfree(hscb_map);
 		}
 		ahd_dma_tag_destroy(ahd, scb_data->hscb_dmat);
 		/* FALLTHROUGH */
@@ -6624,7 +6623,7 @@
 	ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) | (ENSELDO|ENSELDI));
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_MISC) != 0)
-		printf("%s: Setting up iocell workaround\n", ahd_name(ahd));
+		printk("%s: Setting up iocell workaround\n", ahd_name(ahd));
 #endif
 	ahd_restore_modes(ahd, saved_modes);
 	ahd->flags &= ~AHD_HAD_FIRST_SEL;
@@ -6644,14 +6643,14 @@
 	ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_MISC) != 0)
-		printf("%s: iocell first selection\n", ahd_name(ahd));
+		printk("%s: iocell first selection\n", ahd_name(ahd));
 #endif
 	if ((sblkctl & ENAB40) != 0) {
 		ahd_outb(ahd, DSPDATACTL,
 			 ahd_inb(ahd, DSPDATACTL) & ~BYPASSENAB);
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_MISC) != 0)
-			printf("%s: BYPASS now disabled\n", ahd_name(ahd));
+			printk("%s: BYPASS now disabled\n", ahd_name(ahd));
 #endif
 	}
 	ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) & ~(ENSELDO|ENSELDI));
@@ -6833,7 +6832,7 @@
 		hscb = &((struct hardware_scb *)hscb_map->vaddr)[offset];
 		hscb_busaddr = hscb_map->physaddr + (offset * sizeof(*hscb));
 	} else {
-		hscb_map = malloc(sizeof(*hscb_map), M_DEVBUF, M_NOWAIT);
+		hscb_map = kmalloc(sizeof(*hscb_map), GFP_ATOMIC);
 
 		if (hscb_map == NULL)
 			return;
@@ -6842,7 +6841,7 @@
 		if (ahd_dmamem_alloc(ahd, scb_data->hscb_dmat,
 				     (void **)&hscb_map->vaddr,
 				     BUS_DMA_NOWAIT, &hscb_map->dmamap) != 0) {
-			free(hscb_map, M_DEVBUF);
+			kfree(hscb_map);
 			return;
 		}
 
@@ -6866,7 +6865,7 @@
 		segs = sg_map->vaddr + offset;
 		sg_busaddr = sg_map->physaddr + offset;
 	} else {
-		sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
+		sg_map = kmalloc(sizeof(*sg_map), GFP_ATOMIC);
 
 		if (sg_map == NULL)
 			return;
@@ -6875,7 +6874,7 @@
 		if (ahd_dmamem_alloc(ahd, scb_data->sg_dmat,
 				     (void **)&sg_map->vaddr,
 				     BUS_DMA_NOWAIT, &sg_map->dmamap) != 0) {
-			free(sg_map, M_DEVBUF);
+			kfree(sg_map);
 			return;
 		}
 
@@ -6891,7 +6890,7 @@
 		    ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd);
 #ifdef AHD_DEBUG
 		if (ahd_debug & AHD_SHOW_MEMORY)
-			printf("Mapped SG data\n");
+			printk("Mapped SG data\n");
 #endif
 	}
 
@@ -6903,7 +6902,7 @@
 		sense_data = sense_map->vaddr + offset;
 		sense_busaddr = sense_map->physaddr + offset;
 	} else {
-		sense_map = malloc(sizeof(*sense_map), M_DEVBUF, M_NOWAIT);
+		sense_map = kmalloc(sizeof(*sense_map), GFP_ATOMIC);
 
 		if (sense_map == NULL)
 			return;
@@ -6912,7 +6911,7 @@
 		if (ahd_dmamem_alloc(ahd, scb_data->sense_dmat,
 				     (void **)&sense_map->vaddr,
 				     BUS_DMA_NOWAIT, &sense_map->dmamap) != 0) {
-			free(sense_map, M_DEVBUF);
+			kfree(sense_map);
 			return;
 		}
 
@@ -6927,7 +6926,7 @@
 		scb_data->sense_left = PAGE_SIZE / AHD_SENSE_BUFSIZE;
 #ifdef AHD_DEBUG
 		if (ahd_debug & AHD_SHOW_MEMORY)
-			printf("Mapped sense data\n");
+			printk("Mapped sense data\n");
 #endif
 	}
 
@@ -6941,15 +6940,13 @@
 		int error;
 #endif
 
-		next_scb = (struct scb *)malloc(sizeof(*next_scb),
-						M_DEVBUF, M_NOWAIT);
+		next_scb = kmalloc(sizeof(*next_scb), GFP_ATOMIC);
 		if (next_scb == NULL)
 			break;
 
-		pdata = (struct scb_platform_data *)malloc(sizeof(*pdata),
-							   M_DEVBUF, M_NOWAIT);
+		pdata = kmalloc(sizeof(*pdata), GFP_ATOMIC);
 		if (pdata == NULL) {
-			free(next_scb, M_DEVBUF);
+			kfree(next_scb);
 			break;
 		}
 		next_scb->platform_data = pdata;
@@ -6979,8 +6976,8 @@
 		error = ahd_dmamap_create(ahd, ahd->buffer_dmat, /*flags*/0,
 					  &next_scb->dmamap);
 		if (error != 0) {
-			free(next_scb, M_DEVBUF);
-			free(pdata, M_DEVBUF);
+			kfree(next_scb);
+			kfree(pdata);
 			break;
 		}
 #endif
@@ -7077,8 +7074,7 @@
 	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
 
 	ahd->stack_size = ahd_probe_stack_size(ahd);
-	ahd->saved_stack = malloc(ahd->stack_size * sizeof(uint16_t),
-				  M_DEVBUF, M_NOWAIT);
+	ahd->saved_stack = kmalloc(ahd->stack_size * sizeof(uint16_t), GFP_ATOMIC);
 	if (ahd->saved_stack == NULL)
 		return (ENOMEM);
 
@@ -7224,20 +7220,20 @@
 	error = ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL,
 				   CURSENSE_ENB);
 	if (error != 0) {
-		printf("%s: current sensing timeout 1\n", ahd_name(ahd));
+		printk("%s: current sensing timeout 1\n", ahd_name(ahd));
 		goto init_done;
 	}
 	for (i = 20, fstat = FLX_FSTAT_BUSY;
 	     (fstat & FLX_FSTAT_BUSY) != 0 && i; i--) {
 		error = ahd_read_flexport(ahd, FLXADDR_FLEXSTAT, &fstat);
 		if (error != 0) {
-			printf("%s: current sensing timeout 2\n",
+			printk("%s: current sensing timeout 2\n",
 			       ahd_name(ahd));
 			goto init_done;
 		}
 	}
 	if (i == 0) {
-		printf("%s: Timedout during current-sensing test\n",
+		printk("%s: Timedout during current-sensing test\n",
 		       ahd_name(ahd));
 		goto init_done;
 	}
@@ -7245,7 +7241,7 @@
 	/* Latch Current Sensing status. */
 	error = ahd_read_flexport(ahd, FLXADDR_CURRENT_STAT, &current_sensing);
 	if (error != 0) {
-		printf("%s: current sensing timeout 3\n", ahd_name(ahd));
+		printk("%s: current sensing timeout 3\n", ahd_name(ahd));
 		goto init_done;
 	}
 
@@ -7254,7 +7250,7 @@
 
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_TERMCTL) != 0) {
-		printf("%s: current_sensing == 0x%x\n",
+		printk("%s: current_sensing == 0x%x\n",
 		       ahd_name(ahd), current_sensing);
 	}
 #endif
@@ -7271,13 +7267,13 @@
 		case FLX_CSTAT_OKAY:
 			if (warn_user == 0 && bootverbose == 0)
 				break;
-			printf("%s: %s Channel %s\n", ahd_name(ahd),
+			printk("%s: %s Channel %s\n", ahd_name(ahd),
 			       channel_strings[i], termstat_strings[term_stat]);
 			break;
 		}
 	}
 	if (warn_user) {
-		printf("%s: WARNING. Termination is not configured correctly.\n"
+		printk("%s: WARNING. Termination is not configured correctly.\n"
 		       "%s: WARNING. SCSI bus operations may FAIL.\n",
 		       ahd_name(ahd), ahd_name(ahd));
 	}
@@ -7393,7 +7389,7 @@
 		}
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_MISC) != 0)
-			printf("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd),
+			printk("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd),
 			       WRTBIASCTL_HP_DEFAULT);
 #endif
 	}
@@ -7622,9 +7618,9 @@
 		ahd_outb(ahd, NEGCONOPTS, negodat3);
 		negodat3 = ahd_inb(ahd, NEGCONOPTS);
 		if (!(negodat3 & ENSLOWCRC))
-			printf("aic79xx: failed to set the SLOWCRC bit\n");
+			printk("aic79xx: failed to set the SLOWCRC bit\n");
 		else
-			printf("aic79xx: SLOWCRC bit set\n");
+			printk("aic79xx: SLOWCRC bit set\n");
 	}
 }
 
@@ -7646,7 +7642,7 @@
 	 * data for any target mode initiator.
 	 */
 	if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) {
-		printf("%s: unable to allocate ahd_tmode_tstate.  "
+		printk("%s: unable to allocate ahd_tmode_tstate.  "
 		       "Failing attach\n", ahd_name(ahd));
 		return (ENOMEM);
 	}
@@ -7725,7 +7721,7 @@
 	 * data for any target mode initiator.
 	 */
 	if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) {
-		printf("%s: unable to allocate ahd_tmode_tstate.  "
+		printk("%s: unable to allocate ahd_tmode_tstate.  "
 		       "Failing attach\n", ahd_name(ahd));
 		return (ENOMEM);
 	}
@@ -7795,7 +7791,7 @@
 			user_tinfo->width = MSG_EXT_WDTR_BUS_8_BIT;
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_MISC) != 0)
-			printf("(%d): %x:%x:%x:%x\n", targ, user_tinfo->width,
+			printk("(%d): %x:%x:%x:%x\n", targ, user_tinfo->width,
 			       user_tinfo->period, user_tinfo->offset,
 			       user_tinfo->ppr_options);
 #endif
@@ -7951,7 +7947,7 @@
 	       || (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0));
 
 	if (maxloops == 0) {
-		printf("Infinite interrupt loop, INTSTAT = %x",
+		printk("Infinite interrupt loop, INTSTAT = %x",
 		      ahd_inb(ahd, INTSTAT));
 	}
 	ahd->qfreeze_cnt++;
@@ -8241,7 +8237,7 @@
 	prev_scb = NULL;
 
 	if (action == SEARCH_PRINT) {
-		printf("qinstart = %d qinfifonext = %d\nQINFIFO:",
+		printk("qinstart = %d qinfifonext = %d\nQINFIFO:",
 		       qinstart, ahd->qinfifonext);
 	}
 
@@ -8256,7 +8252,7 @@
 	while (qinpos != qintail) {
 		scb = ahd_lookup_scb(ahd, ahd->qinfifo[qinpos]);
 		if (scb == NULL) {
-			printf("qinpos = %d, SCB index = %d\n",
+			printk("qinpos = %d, SCB index = %d\n",
 				qinpos, ahd->qinfifo[qinpos]);
 			panic("Loop 1\n");
 		}
@@ -8269,13 +8265,13 @@
 			switch (action) {
 			case SEARCH_COMPLETE:
 				if ((scb->flags & SCB_ACTIVE) == 0)
-					printf("Inactive SCB in qinfifo\n");
+					printk("Inactive SCB in qinfifo\n");
 				ahd_done_with_status(ahd, scb, status);
 				/* FALLTHROUGH */
 			case SEARCH_REMOVE:
 				break;
 			case SEARCH_PRINT:
-				printf(" 0x%x", ahd->qinfifo[qinpos]);
+				printk(" 0x%x", ahd->qinfifo[qinpos]);
 				/* FALLTHROUGH */
 			case SEARCH_COUNT:
 				ahd_qinfifo_requeue(ahd, prev_scb, scb);
@@ -8292,7 +8288,7 @@
 	ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
 
 	if (action == SEARCH_PRINT)
-		printf("\nWAITING_TID_QUEUES:\n");
+		printk("\nWAITING_TID_QUEUES:\n");
 
 	/*
 	 * Search waiting for selection lists.  We traverse the
@@ -8320,7 +8316,7 @@
 			panic("TID LIST LOOP");
 
 		if (scbid >= ahd->scb_data.numscbs) {
-			printf("%s: Waiting TID List inconsistency. "
+			printk("%s: Waiting TID List inconsistency. "
 			       "SCB index == 0x%x, yet numscbs == 0x%x.",
 			       ahd_name(ahd), scbid, ahd->scb_data.numscbs);
 			ahd_dump_card_state(ahd);
@@ -8328,7 +8324,7 @@
 		}
 		scb = ahd_lookup_scb(ahd, scbid);
 		if (scb == NULL) {
-			printf("%s: SCB = 0x%x Not Active!\n",
+			printk("%s: SCB = 0x%x Not Active!\n",
 			       ahd_name(ahd), scbid);
 			panic("Waiting TID List traversal\n");
 		}
@@ -8344,7 +8340,7 @@
 		 * We found a list of scbs that needs to be searched.
 		 */
 		if (action == SEARCH_PRINT)
-			printf("       %d ( ", SCB_GET_TARGET(ahd, scb));
+			printk("       %d ( ", SCB_GET_TARGET(ahd, scb));
 		tid_head = scbid;
 		found += ahd_search_scb_list(ahd, target, channel,
 					     lun, tag, role, status,
@@ -8365,14 +8361,14 @@
 			switch (action) {
 			case SEARCH_COMPLETE:
 				if ((mk_msg_scb->flags & SCB_ACTIVE) == 0)
-					printf("Inactive SCB pending MK_MSG\n");
+					printk("Inactive SCB pending MK_MSG\n");
 				ahd_done_with_status(ahd, mk_msg_scb, status);
 				/* FALLTHROUGH */
 			case SEARCH_REMOVE:
 			{
 				u_int tail_offset;
 
-				printf("Removing MK_MSG scb\n");
+				printk("Removing MK_MSG scb\n");
 
 				/*
 				 * Reset our tail to the tail of the
@@ -8390,7 +8386,7 @@
 				break;
 			}
 			case SEARCH_PRINT:
-				printf(" 0x%x", SCB_GET_TAG(scb));
+				printk(" 0x%x", SCB_GET_TAG(scb));
 				/* FALLTHROUGH */
 			case SEARCH_COUNT:
 				break;
@@ -8407,7 +8403,7 @@
 			 * queue with a pending MK_MESSAGE scb, we
 			 * must queue the MK_MESSAGE scb.
 			 */
-			printf("Queueing mk_msg_scb\n");
+			printk("Queueing mk_msg_scb\n");
 			tid_head = ahd_inw(ahd, MK_MESSAGE_SCB);
 			seq_flags2 &= ~PENDING_MK_MESSAGE;
 			ahd_outb(ahd, SEQ_FLAGS2, seq_flags2);
@@ -8418,7 +8414,7 @@
 		if (!SCBID_IS_NULL(tid_head))
 			tid_prev = tid_head;
 		if (action == SEARCH_PRINT)
-			printf(")\n");
+			printk(")\n");
 	}
 
 	/* Restore saved state. */
@@ -8446,7 +8442,7 @@
 	*list_tail = SCB_LIST_NULL;
 	for (scbid = next; !SCBID_IS_NULL(scbid); scbid = next) {
 		if (scbid >= ahd->scb_data.numscbs) {
-			printf("%s:SCB List inconsistency. "
+			printk("%s:SCB List inconsistency. "
 			       "SCB == 0x%x, yet numscbs == 0x%x.",
 			       ahd_name(ahd), scbid, ahd->scb_data.numscbs);
 			ahd_dump_card_state(ahd);
@@ -8454,7 +8450,7 @@
 		}
 		scb = ahd_lookup_scb(ahd, scbid);
 		if (scb == NULL) {
-			printf("%s: SCB = %d Not Active!\n",
+			printk("%s: SCB = %d Not Active!\n",
 			       ahd_name(ahd), scbid);
 			panic("Waiting List traversal\n");
 		}
@@ -8470,7 +8466,7 @@
 		switch (action) {
 		case SEARCH_COMPLETE:
 			if ((scb->flags & SCB_ACTIVE) == 0)
-				printf("Inactive SCB in Waiting List\n");
+				printk("Inactive SCB in Waiting List\n");
 			ahd_done_with_status(ahd, scb, status);
 			/* FALLTHROUGH */
 		case SEARCH_REMOVE:
@@ -8480,7 +8476,7 @@
 				*list_head = next;
 			break;
 		case SEARCH_PRINT:
-			printf("0x%x ", scbid);
+			printk("0x%x ", scbid);
 		case SEARCH_COUNT:
 			prev = scbid;
 			break;
@@ -8668,7 +8664,7 @@
 			if (ahd_get_transaction_status(scbp) != CAM_REQ_CMP)
 				ahd_freeze_scb(scbp);
 			if ((scbp->flags & SCB_ACTIVE) == 0)
-				printf("Inactive SCB on pending list\n");
+				printk("Inactive SCB on pending list\n");
 			ahd_done(ahd, scbp);
 			found++;
 		}
@@ -8725,7 +8721,7 @@
 	 * Check if the last bus reset is cleared
 	 */
 	if (ahd->flags & AHD_BUS_RESET_ACTIVE) {
-		printf("%s: bus reset still active\n",
+		printk("%s: bus reset still active\n",
 		       ahd_name(ahd));
 		return 0;
 	}
@@ -8900,7 +8896,7 @@
 		ahd_enable_coalescing(ahd, enint_coal);
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_INT_COALESCING) != 0)
-			printf("%s: Interrupt coalescing "
+			printk("%s: Interrupt coalescing "
 			       "now %sabled. Cmds %d\n",
 			       ahd_name(ahd),
 			       (enint_coal & ENINT_COALESCE) ? "en" : "dis",
@@ -8975,9 +8971,9 @@
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_SENSE) != 0) {
 			ahd_print_path(ahd, scb);
-			printf("SCB 0x%x Received PKT Status of 0x%x\n",
+			printk("SCB 0x%x Received PKT Status of 0x%x\n",
 			       SCB_GET_TAG(scb), siu->status);
-			printf("\tflags = 0x%x, sense len = 0x%x, "
+			printk("\tflags = 0x%x, sense len = 0x%x, "
 			       "pktfail = 0x%x\n",
 			       siu->flags, scsi_4btoul(siu->sense_length),
 			       scsi_4btoul(siu->pkt_failures_length));
@@ -8986,27 +8982,27 @@
 		if ((siu->flags & SIU_RSPVALID) != 0) {
 			ahd_print_path(ahd, scb);
 			if (scsi_4btoul(siu->pkt_failures_length) < 4) {
-				printf("Unable to parse pkt_failures\n");
+				printk("Unable to parse pkt_failures\n");
 			} else {
 
 				switch (SIU_PKTFAIL_CODE(siu)) {
 				case SIU_PFC_NONE:
-					printf("No packet failure found\n");
+					printk("No packet failure found\n");
 					break;
 				case SIU_PFC_CIU_FIELDS_INVALID:
-					printf("Invalid Command IU Field\n");
+					printk("Invalid Command IU Field\n");
 					break;
 				case SIU_PFC_TMF_NOT_SUPPORTED:
-					printf("TMF not supportd\n");
+					printk("TMF not supportd\n");
 					break;
 				case SIU_PFC_TMF_FAILED:
-					printf("TMF failed\n");
+					printk("TMF failed\n");
 					break;
 				case SIU_PFC_INVALID_TYPE_CODE:
-					printf("Invalid L_Q Type code\n");
+					printk("Invalid L_Q Type code\n");
 					break;
 				case SIU_PFC_ILLEGAL_REQUEST:
-					printf("Illegal request\n");
+					printk("Illegal request\n");
 				default:
 					break;
 				}
@@ -9019,7 +9015,7 @@
 			scb->flags |= SCB_PKT_SENSE;
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_SENSE) != 0)
-				printf("Sense data available\n");
+				printk("Sense data available\n");
 #endif
 		}
 		ahd_done(ahd, scb);
@@ -9037,7 +9033,7 @@
 #ifdef AHD_DEBUG
 		if (ahd_debug & AHD_SHOW_SENSE) {
 			ahd_print_path(ahd, scb);
-			printf("SCB %d: requests Check Status\n",
+			printk("SCB %d: requests Check Status\n",
 			       SCB_GET_TAG(scb));
 		}
 #endif
@@ -9065,7 +9061,7 @@
 #ifdef AHD_DEBUG
 		if (ahd_debug & AHD_SHOW_SENSE) {
 			ahd_print_path(ahd, scb);
-			printf("Sending Sense\n");
+			printk("Sending Sense\n");
 		}
 #endif
 		scb->sg_count = 0;
@@ -9117,7 +9113,7 @@
 		break;
 	}
 	case SCSI_STATUS_OK:
-		printf("%s: Interrupted for staus of 0???\n",
+		printk("%s: Interrupted for staus of 0???\n",
 		       ahd_name(ahd));
 		/* FALLTHROUGH */
 	default:
@@ -9192,7 +9188,7 @@
 		return;
 	} else if ((resid_sgptr & SG_OVERRUN_RESID) != 0) {
 		ahd_print_path(ahd, scb);
-		printf("data overrun detected Tag == 0x%x.\n",
+		printk("data overrun detected Tag == 0x%x.\n",
 		       SCB_GET_TAG(scb));
 		ahd_freeze_devq(ahd, scb);
 		ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR);
@@ -9232,7 +9228,7 @@
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_MISC) != 0) {
 		ahd_print_path(ahd, scb);
-		printf("Handled %sResidual of %d bytes\n",
+		printk("Handled %sResidual of %d bytes\n",
 		       (scb->flags & SCB_SENSE) ? "Sense " : "", resid);
 	}
 #endif
@@ -9272,7 +9268,7 @@
 
 	if (pending == AHD_TMODE_EVENT_BUFFER_SIZE) {
 		xpt_print_path(lstate->path);
-		printf("immediate event %x:%x lost\n",
+		printk("immediate event %x:%x lost\n",
 		       lstate->event_buffer[lstate->event_r_idx].event_type,
 		       lstate->event_buffer[lstate->event_r_idx].event_arg);
 		lstate->event_r_idx++;
@@ -9344,7 +9340,7 @@
 		uint8_t ins_bytes[4];
 
 		ahd_insb(ahd, SEQRAM, ins_bytes, 4);
-		printf("0x%08x\n", ins_bytes[0] << 24
+		printk("0x%08x\n", ins_bytes[0] << 24
 				 | ins_bytes[1] << 16
 				 | ins_bytes[2] << 8
 				 | ins_bytes[3]);
@@ -9372,7 +9368,7 @@
 	uint8_t	download_consts[DOWNLOAD_CONST_COUNT];
 
 	if (bootverbose)
-		printf("%s: Downloading Sequencer Program...",
+		printk("%s: Downloading Sequencer Program...",
 		       ahd_name(ahd));
 
 #if DOWNLOAD_CONST_COUNT != 8
@@ -9498,7 +9494,7 @@
 	if (cs_count != 0) {
 
 		cs_count *= sizeof(struct cs);
-		ahd->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT);
+		ahd->critical_sections = kmalloc(cs_count, GFP_ATOMIC);
 		if (ahd->critical_sections == NULL)
 			panic("ahd_loadseq: Could not malloc");
 		memcpy(ahd->critical_sections, cs_table, cs_count);
@@ -9506,8 +9502,8 @@
 	ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE);
 
 	if (bootverbose) {
-		printf(" %d instructions downloaded\n", downloaded);
-		printf("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n",
+		printk(" %d instructions downloaded\n", downloaded);
+		printk("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n",
 		       ahd_name(ahd), ahd->features, ahd->bugs, ahd->flags);
 	}
 }
@@ -9690,12 +9686,12 @@
 	u_int	printed_mask;
 
 	if (cur_column != NULL && *cur_column >= wrap_point) {
-		printf("\n");
+		printk("\n");
 		*cur_column = 0;
 	}
-	printed = printf("%s[0x%x]", name, value);
+	printed = printk("%s[0x%x]", name, value);
 	if (table == NULL) {
-		printed += printf(" ");
+		printed += printk(" ");
 		*cur_column += printed;
 		return (printed);
 	}
@@ -9710,7 +9706,7 @@
 			  == table[entry].mask))
 				continue;
 
-			printed += printf("%s%s",
+			printed += printk("%s%s",
 					  printed_mask == 0 ? ":(" : "|",
 					  table[entry].name);
 			printed_mask |= table[entry].mask;
@@ -9721,9 +9717,9 @@
 			break;
 	}
 	if (printed_mask != 0)
-		printed += printf(") ");
+		printed += printk(") ");
 	else
-		printed += printf(" ");
+		printed += printk(" ");
 	if (cur_column != NULL)
 		*cur_column += printed;
 	return (printed);
@@ -9749,17 +9745,17 @@
 	}
 	saved_modes = ahd_save_modes(ahd);
 	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
-	printf(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n"
+	printk(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n"
 	       "%s: Dumping Card State at program address 0x%x Mode 0x%x\n",
 	       ahd_name(ahd), 
 	       ahd_inw(ahd, CURADDR),
 	       ahd_build_mode_state(ahd, ahd->saved_src_mode,
 				    ahd->saved_dst_mode));
 	if (paused)
-		printf("Card was paused\n");
+		printk("Card was paused\n");
 
 	if (ahd_check_cmdcmpltqueues(ahd))
-		printf("Completions are pending\n");
+		printk("Completions are pending\n");
 
 	/*
 	 * Mode independent registers.
@@ -9801,8 +9797,8 @@
 	ahd_lqostat0_print(ahd_inb(ahd, LQOSTAT0), &cur_col, 50);
 	ahd_lqostat1_print(ahd_inb(ahd, LQOSTAT1), &cur_col, 50);
 	ahd_lqostat2_print(ahd_inb(ahd, LQOSTAT2), &cur_col, 50);
-	printf("\n");
-	printf("\nSCB Count = %d CMDS_PENDING = %d LASTSCB 0x%x "
+	printk("\n");
+	printk("\nSCB Count = %d CMDS_PENDING = %d LASTSCB 0x%x "
 	       "CURRSCB 0x%x NEXTSCB 0x%x\n",
 	       ahd->scb_data.numscbs, ahd_inw(ahd, CMDS_PENDING),
 	       ahd_inw(ahd, LASTSCB), ahd_inw(ahd, CURRSCB),
@@ -9813,12 +9809,12 @@
 			   CAM_LUN_WILDCARD, SCB_LIST_NULL,
 			   ROLE_UNKNOWN, /*status*/0, SEARCH_PRINT);
 	saved_scb_index = ahd_get_scbptr(ahd);
-	printf("Pending list:");
+	printk("Pending list:");
 	i = 0;
 	LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
 		if (i++ > AHD_SCB_MAX)
 			break;
-		cur_col = printf("\n%3d FIFO_USE[0x%x] ", SCB_GET_TAG(scb),
+		cur_col = printk("\n%3d FIFO_USE[0x%x] ", SCB_GET_TAG(scb),
 				 ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT));
 		ahd_set_scbptr(ahd, SCB_GET_TAG(scb));
 		ahd_scb_control_print(ahd_inb_scbram(ahd, SCB_CONTROL),
@@ -9826,16 +9822,16 @@
 		ahd_scb_scsiid_print(ahd_inb_scbram(ahd, SCB_SCSIID),
 				     &cur_col, 60);
 	}
-	printf("\nTotal %d\n", i);
+	printk("\nTotal %d\n", i);
 
-	printf("Kernel Free SCB list: ");
+	printk("Kernel Free SCB list: ");
 	i = 0;
 	TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) {
 		struct scb *list_scb;
 
 		list_scb = scb;
 		do {
-			printf("%d ", SCB_GET_TAG(list_scb));
+			printk("%d ", SCB_GET_TAG(list_scb));
 			list_scb = LIST_NEXT(list_scb, collision_links);
 		} while (list_scb && i++ < AHD_SCB_MAX);
 	}
@@ -9843,49 +9839,49 @@
 	LIST_FOREACH(scb, &ahd->scb_data.any_dev_free_scb_list, links.le) {
 		if (i++ > AHD_SCB_MAX)
 			break;
-		printf("%d ", SCB_GET_TAG(scb));
+		printk("%d ", SCB_GET_TAG(scb));
 	}
-	printf("\n");
+	printk("\n");
 
-	printf("Sequencer Complete DMA-inprog list: ");
+	printk("Sequencer Complete DMA-inprog list: ");
 	scb_index = ahd_inw(ahd, COMPLETE_SCB_DMAINPROG_HEAD);
 	i = 0;
 	while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) {
 		ahd_set_scbptr(ahd, scb_index);
-		printf("%d ", scb_index);
+		printk("%d ", scb_index);
 		scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
 	}
-	printf("\n");
+	printk("\n");
 
-	printf("Sequencer Complete list: ");
+	printk("Sequencer Complete list: ");
 	scb_index = ahd_inw(ahd, COMPLETE_SCB_HEAD);
 	i = 0;
 	while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) {
 		ahd_set_scbptr(ahd, scb_index);
-		printf("%d ", scb_index);
+		printk("%d ", scb_index);
 		scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
 	}
-	printf("\n");
+	printk("\n");
 
 	
-	printf("Sequencer DMA-Up and Complete list: ");
+	printk("Sequencer DMA-Up and Complete list: ");
 	scb_index = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD);
 	i = 0;
 	while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) {
 		ahd_set_scbptr(ahd, scb_index);
-		printf("%d ", scb_index);
+		printk("%d ", scb_index);
 		scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
 	}
-	printf("\n");
-	printf("Sequencer On QFreeze and Complete list: ");
+	printk("\n");
+	printk("Sequencer On QFreeze and Complete list: ");
 	scb_index = ahd_inw(ahd, COMPLETE_ON_QFREEZE_HEAD);
 	i = 0;
 	while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) {
 		ahd_set_scbptr(ahd, scb_index);
-		printf("%d ", scb_index);
+		printk("%d ", scb_index);
 		scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
 	}
-	printf("\n");
+	printk("\n");
 	ahd_set_scbptr(ahd, saved_scb_index);
 	dffstat = ahd_inb(ahd, DFFSTAT);
 	for (i = 0; i < 2; i++) {
@@ -9896,7 +9892,7 @@
 
 		ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i);
 		fifo_scbptr = ahd_get_scbptr(ahd);
-		printf("\n\n%s: FIFO%d %s, LONGJMP == 0x%x, SCB 0x%x\n",
+		printk("\n\n%s: FIFO%d %s, LONGJMP == 0x%x, SCB 0x%x\n",
 		       ahd_name(ahd), i,
 		       (dffstat & (FIFO0FREE << i)) ? "Free" : "Active",
 		       ahd_inw(ahd, LONGJMP_ADDR), fifo_scbptr);
@@ -9912,20 +9908,20 @@
 		ahd_soffcnt_print(ahd_inb(ahd, SOFFCNT), &cur_col, 50);
 		ahd_mdffstat_print(ahd_inb(ahd, MDFFSTAT), &cur_col, 50);
 		if (cur_col > 50) {
-			printf("\n");
+			printk("\n");
 			cur_col = 0;
 		}
-		cur_col += printf("SHADDR = 0x%x%x, SHCNT = 0x%x ",
+		cur_col += printk("SHADDR = 0x%x%x, SHCNT = 0x%x ",
 				  ahd_inl(ahd, SHADDR+4),
 				  ahd_inl(ahd, SHADDR),
 				  (ahd_inb(ahd, SHCNT)
 				| (ahd_inb(ahd, SHCNT + 1) << 8)
 				| (ahd_inb(ahd, SHCNT + 2) << 16)));
 		if (cur_col > 50) {
-			printf("\n");
+			printk("\n");
 			cur_col = 0;
 		}
-		cur_col += printf("HADDR = 0x%x%x, HCNT = 0x%x ",
+		cur_col += printk("HADDR = 0x%x%x, HCNT = 0x%x ",
 				  ahd_inl(ahd, HADDR+4),
 				  ahd_inl(ahd, HADDR),
 				  (ahd_inb(ahd, HCNT)
@@ -9940,52 +9936,52 @@
 		}
 #endif
 	}
-	printf("\nLQIN: ");
+	printk("\nLQIN: ");
 	for (i = 0; i < 20; i++)
-		printf("0x%x ", ahd_inb(ahd, LQIN + i));
-	printf("\n");
+		printk("0x%x ", ahd_inb(ahd, LQIN + i));
+	printk("\n");
 	ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
-	printf("%s: LQISTATE = 0x%x, LQOSTATE = 0x%x, OPTIONMODE = 0x%x\n",
+	printk("%s: LQISTATE = 0x%x, LQOSTATE = 0x%x, OPTIONMODE = 0x%x\n",
 	       ahd_name(ahd), ahd_inb(ahd, LQISTATE), ahd_inb(ahd, LQOSTATE),
 	       ahd_inb(ahd, OPTIONMODE));
-	printf("%s: OS_SPACE_CNT = 0x%x MAXCMDCNT = 0x%x\n",
+	printk("%s: OS_SPACE_CNT = 0x%x MAXCMDCNT = 0x%x\n",
 	       ahd_name(ahd), ahd_inb(ahd, OS_SPACE_CNT),
 	       ahd_inb(ahd, MAXCMDCNT));
-	printf("%s: SAVED_SCSIID = 0x%x SAVED_LUN = 0x%x\n",
+	printk("%s: SAVED_SCSIID = 0x%x SAVED_LUN = 0x%x\n",
 	       ahd_name(ahd), ahd_inb(ahd, SAVED_SCSIID),
 	       ahd_inb(ahd, SAVED_LUN));
 	ahd_simode0_print(ahd_inb(ahd, SIMODE0), &cur_col, 50);
-	printf("\n");
+	printk("\n");
 	ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
 	cur_col = 0;
 	ahd_ccscbctl_print(ahd_inb(ahd, CCSCBCTL), &cur_col, 50);
-	printf("\n");
+	printk("\n");
 	ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
-	printf("%s: REG0 == 0x%x, SINDEX = 0x%x, DINDEX = 0x%x\n",
+	printk("%s: REG0 == 0x%x, SINDEX = 0x%x, DINDEX = 0x%x\n",
 	       ahd_name(ahd), ahd_inw(ahd, REG0), ahd_inw(ahd, SINDEX),
 	       ahd_inw(ahd, DINDEX));
-	printf("%s: SCBPTR == 0x%x, SCB_NEXT == 0x%x, SCB_NEXT2 == 0x%x\n",
+	printk("%s: SCBPTR == 0x%x, SCB_NEXT == 0x%x, SCB_NEXT2 == 0x%x\n",
 	       ahd_name(ahd), ahd_get_scbptr(ahd),
 	       ahd_inw_scbram(ahd, SCB_NEXT),
 	       ahd_inw_scbram(ahd, SCB_NEXT2));
-	printf("CDB %x %x %x %x %x %x\n",
+	printk("CDB %x %x %x %x %x %x\n",
 	       ahd_inb_scbram(ahd, SCB_CDB_STORE),
 	       ahd_inb_scbram(ahd, SCB_CDB_STORE+1),
 	       ahd_inb_scbram(ahd, SCB_CDB_STORE+2),
 	       ahd_inb_scbram(ahd, SCB_CDB_STORE+3),
 	       ahd_inb_scbram(ahd, SCB_CDB_STORE+4),
 	       ahd_inb_scbram(ahd, SCB_CDB_STORE+5));
-	printf("STACK:");
+	printk("STACK:");
 	for (i = 0; i < ahd->stack_size; i++) {
 		ahd->saved_stack[i] =
 		    ahd_inb(ahd, STACK)|(ahd_inb(ahd, STACK) << 8);
-		printf(" 0x%x", ahd->saved_stack[i]);
+		printk(" 0x%x", ahd->saved_stack[i]);
 	}
 	for (i = ahd->stack_size-1; i >= 0; i--) {
 		ahd_outb(ahd, STACK, ahd->saved_stack[i] & 0xFF);
 		ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF);
 	}
-	printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
+	printk("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
 	ahd_restore_modes(ahd, saved_modes);
 	if (paused == 0)
 		ahd_unpause(ahd);
@@ -10004,8 +10000,8 @@
 	saved_scb_index = ahd_get_scbptr(ahd);
 	for (i = 0; i < AHD_SCB_MAX; i++) {
 		ahd_set_scbptr(ahd, i);
-		printf("%3d", i);
-		printf("(CTRL 0x%x ID 0x%x N 0x%x N2 0x%x SG 0x%x, RSG 0x%x)\n",
+		printk("%3d", i);
+		printk("(CTRL 0x%x ID 0x%x N 0x%x N2 0x%x SG 0x%x, RSG 0x%x)\n",
 		       ahd_inb_scbram(ahd, SCB_CONTROL),
 		       ahd_inb_scbram(ahd, SCB_SCSIID),
 		       ahd_inw_scbram(ahd, SCB_NEXT),
@@ -10013,7 +10009,7 @@
 		       ahd_inl_scbram(ahd, SCB_SGPTR),
 		       ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR));
 	}
-	printf("\n");
+	printk("\n");
 	ahd_set_scbptr(ahd, saved_scb_index);
 	ahd_restore_modes(ahd, saved_modes);
 }
@@ -10383,7 +10379,7 @@
 	 && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
 		u_long	s;
 
-		printf("Configuring Target Mode\n");
+		printk("Configuring Target Mode\n");
 		ahd_lock(ahd, &s);
 		if (LIST_FIRST(&ahd->pending_scbs) != NULL) {
 			ccb->ccb_h.status = CAM_BUSY;
@@ -10412,7 +10408,7 @@
 		/* Are we already enabled?? */
 		if (lstate != NULL) {
 			xpt_print_path(ccb->ccb_h.path);
-			printf("Lun already enabled\n");
+			printk("Lun already enabled\n");
 			ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
 			return;
 		}
@@ -10424,7 +10420,7 @@
 			 * specific commands.
 			 */
 			ccb->ccb_h.status = CAM_REQ_INVALID;
-			printf("Non-zero Group Codes\n");
+			printk("Non-zero Group Codes\n");
 			return;
 		}
 
@@ -10436,15 +10432,15 @@
 			tstate = ahd_alloc_tstate(ahd, target, channel);
 			if (tstate == NULL) {
 				xpt_print_path(ccb->ccb_h.path);
-				printf("Couldn't allocate tstate\n");
+				printk("Couldn't allocate tstate\n");
 				ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
 				return;
 			}
 		}
-		lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT);
+		lstate = kmalloc(sizeof(*lstate), GFP_ATOMIC);
 		if (lstate == NULL) {
 			xpt_print_path(ccb->ccb_h.path);
-			printf("Couldn't allocate lstate\n");
+			printk("Couldn't allocate lstate\n");
 			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
 			return;
 		}
@@ -10454,9 +10450,9 @@
 					 xpt_path_target_id(ccb->ccb_h.path),
 					 xpt_path_lun_id(ccb->ccb_h.path));
 		if (status != CAM_REQ_CMP) {
-			free(lstate, M_DEVBUF);
+			kfree(lstate);
 			xpt_print_path(ccb->ccb_h.path);
-			printf("Couldn't allocate path\n");
+			printk("Couldn't allocate path\n");
 			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
 			return;
 		}
@@ -10524,7 +10520,7 @@
 		ahd_unlock(ahd, &s);
 		ccb->ccb_h.status = CAM_REQ_CMP;
 		xpt_print_path(ccb->ccb_h.path);
-		printf("Lun now enabled for target mode\n");
+		printk("Lun now enabled for target mode\n");
 	} else {
 		struct scb *scb;
 		int i, empty;
@@ -10543,7 +10539,7 @@
 			ccbh = &scb->io_ctx->ccb_h;
 			if (ccbh->func_code == XPT_CONT_TARGET_IO
 			 && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){
-				printf("CTIO pending\n");
+				printk("CTIO pending\n");
 				ccb->ccb_h.status = CAM_REQ_INVALID;
 				ahd_unlock(ahd, &s);
 				return;
@@ -10551,12 +10547,12 @@
 		}
 
 		if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
-			printf("ATIOs pending\n");
+			printk("ATIOs pending\n");
 			ccb->ccb_h.status = CAM_REQ_INVALID;
 		}
 
 		if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
-			printf("INOTs pending\n");
+			printk("INOTs pending\n");
 			ccb->ccb_h.status = CAM_REQ_INVALID;
 		}
 
@@ -10566,9 +10562,9 @@
 		}
 
 		xpt_print_path(ccb->ccb_h.path);
-		printf("Target mode disabled\n");
+		printk("Target mode disabled\n");
 		xpt_free_path(lstate->path);
-		free(lstate, M_DEVBUF);
+		kfree(lstate);
 
 		ahd_pause(ahd);
 		/* Can we clean up the target too? */
@@ -10615,7 +10611,7 @@
 			ahd_outb(ahd, SCSISEQ1, scsiseq1);
 
 			if ((ahd->features & AHD_MULTIROLE) == 0) {
-				printf("Configuring Initiator Mode\n");
+				printk("Configuring Initiator Mode\n");
 				ahd->flags &= ~AHD_TARGETROLE;
 				ahd->flags |= AHD_INITIATORROLE;
 				ahd_pause(ahd);
@@ -10749,7 +10745,7 @@
 		ahd->flags &= ~AHD_TQINFIFO_BLOCKED;
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_TQIN) != 0)
-		printf("Incoming command from %d for %d:%d%s\n",
+		printk("Incoming command from %d for %d:%d%s\n",
 		       initiator, target, lun,
 		       lstate == ahd->black_hole ? "(Black Holed)" : "");
 #endif
@@ -10796,7 +10792,7 @@
 	default:
 		/* Only copy the opcode. */
 		atio->cdb_len = 1;
-		printf("Reserved or VU command code type encountered\n");
+		printk("Reserved or VU command code type encountered\n");
 		break;
 	}
 	
@@ -10813,7 +10809,7 @@
 		 */
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_TQIN) != 0)
-			printf("Received Immediate Command %d:%d:%d - %p\n",
+			printk("Received Immediate Command %d:%d:%d - %p\n",
 			       initiator, target, lun, ahd->pending_device);
 #endif
 		ahd->pending_device = lstate;
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 4c41332..88ad848 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -674,7 +674,7 @@
 	struct ahd_linux_device *dev;
 
 	if (bootverbose)
-		printf("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id);
+		printk("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id);
 
 	dev = scsi_transport_device_data(sdev);
 	memset(dev, 0, sizeof(*dev));
@@ -798,10 +798,10 @@
 	scmd_printk(KERN_INFO, cmd,
 		    "Attempting to queue a TARGET RESET message:");
 
-	printf("CDB:");
+	printk("CDB:");
 	for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
-		printf(" 0x%x", cmd->cmnd[cdb_byte]);
-	printf("\n");
+		printk(" 0x%x", cmd->cmnd[cdb_byte]);
+	printk("\n");
 
 	/*
 	 * Determine if we currently own this command.
@@ -857,16 +857,16 @@
 	ahd->platform_data->eh_done = &done;
 	ahd_unlock(ahd, &flags);
 
-	printf("%s: Device reset code sleeping\n", ahd_name(ahd));
+	printk("%s: Device reset code sleeping\n", ahd_name(ahd));
 	if (!wait_for_completion_timeout(&done, 5 * HZ)) {
 		ahd_lock(ahd, &flags);
 		ahd->platform_data->eh_done = NULL;
 		ahd_unlock(ahd, &flags);
-		printf("%s: Device reset timer expired (active %d)\n",
+		printk("%s: Device reset timer expired (active %d)\n",
 		       ahd_name(ahd), dev->active);
 		retval = FAILED;
 	}
-	printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval);
+	printk("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval);
 
 	return (retval);
 }
@@ -884,7 +884,7 @@
 	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
-		printf("%s: Bus reset called for cmd %p\n",
+		printk("%s: Bus reset called for cmd %p\n",
 		       ahd_name(ahd), cmd);
 #endif
 	ahd_lock(ahd, &flags);
@@ -894,7 +894,7 @@
 	ahd_unlock(ahd, &flags);
 
 	if (bootverbose)
-		printf("%s: SCSI bus reset delivered. "
+		printk("%s: SCSI bus reset delivered. "
 		       "%d SCBs aborted.\n", ahd_name(ahd), found);
 
 	return (SUCCESS);
@@ -935,7 +935,7 @@
 {
 	bus_dma_tag_t dmat;
 
-	dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT);
+	dmat = kmalloc(sizeof(*dmat), GFP_ATOMIC);
 	if (dmat == NULL)
 		return (ENOMEM);
 
@@ -956,7 +956,7 @@
 void
 ahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat)
 {
-	free(dmat, M_DEVBUF);
+	kfree(dmat);
 }
 
 int
@@ -1019,7 +1019,7 @@
 		iocell_info = (uint8_t*)&aic79xx_iocell_info[instance];
 		iocell_info[index] = value & 0xFFFF;
 		if (bootverbose)
-			printf("iocell[%d:%ld] = %d\n", instance, index, value);
+			printk("iocell[%d:%ld] = %d\n", instance, index, value);
 	}
 }
 
@@ -1029,7 +1029,7 @@
 	int tags, i, j;
 
 	tags = simple_strtoul(p + 1, NULL, 0) & 0xff;
-	printf("Setting Global Tags= %d\n", tags);
+	printk("Setting Global Tags= %d\n", tags);
 
 	for (i = 0; i < ARRAY_SIZE(aic79xx_tag_info); i++) {
 		for (j = 0; j < AHD_NUM_TARGETS; j++) {
@@ -1047,7 +1047,7 @@
 	 && (targ < AHD_NUM_TARGETS)) {
 		aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF;
 		if (bootverbose)
-			printf("tag_info[%d:%d] = %d\n", instance, targ, value);
+			printk("tag_info[%d:%d] = %d\n", instance, targ, value);
 	}
 }
 
@@ -1088,7 +1088,7 @@
 					if (targ == -1)
 						targ = 0;
 				} else {
-					printf("Malformed Option %s\n",
+					printk("Malformed Option %s\n",
 					       opt_name);
 					done = TRUE;
 				}
@@ -1246,7 +1246,7 @@
 	ahd_set_unit(ahd, ahd_linux_unit++);
 	ahd_unlock(ahd, &s);
 	sprintf(buf, "scsi%d", host->host_no);
-	new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+	new_name = kmalloc(strlen(buf) + 1, GFP_ATOMIC);
 	if (new_name != NULL) {
 		strcpy(new_name, buf);
 		ahd_set_name(ahd, new_name);
@@ -1322,7 +1322,7 @@
 ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
 {
 	ahd->platform_data =
-	    malloc(sizeof(struct ahd_platform_data), M_DEVBUF, M_NOWAIT);
+	    kmalloc(sizeof(struct ahd_platform_data), GFP_ATOMIC);
 	if (ahd->platform_data == NULL)
 		return (ENOMEM);
 	memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data));
@@ -1364,7 +1364,7 @@
 		if (ahd->platform_data->host)
 			scsi_host_put(ahd->platform_data->host);
 
-		free(ahd->platform_data, M_DEVBUF);
+		kfree(ahd->platform_data);
 	}
 }
 
@@ -1502,7 +1502,7 @@
 		if (ahd->unit >= ARRAY_SIZE(aic79xx_tag_info)) {
 
 			if (warned_user == 0) {
-				printf(KERN_WARNING
+				printk(KERN_WARNING
 "aic79xx: WARNING: Insufficient tag_info instances\n"
 "aic79xx: for installed controllers.  Using defaults\n"
 "aic79xx: Please update the aic79xx_tag_info array in\n"
@@ -1544,7 +1544,7 @@
 		ahd_send_async(ahd, devinfo.channel, devinfo.target,
 			       devinfo.lun, AC_TRANSFER_NEG);
 		ahd_print_devinfo(ahd, &devinfo);
-		printf("Tagged Queuing enabled.  Depth %d\n", tags);
+		printk("Tagged Queuing enabled.  Depth %d\n", tags);
 	} else {
 		ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_NONE);
 		ahd_send_async(ahd, devinfo.channel, devinfo.target,
@@ -1794,7 +1794,7 @@
 	struct	  ahd_linux_device *dev;
 
 	if ((scb->flags & SCB_ACTIVE) == 0) {
-		printf("SCB %d done'd twice\n", SCB_GET_TAG(scb));
+		printk("SCB %d done'd twice\n", SCB_GET_TAG(scb));
 		ahd_dump_card_state(ahd);
 		panic("Stopping for safety");
 	}
@@ -1825,7 +1825,7 @@
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_MISC) != 0) {
 				ahd_print_path(ahd, scb);
-				printf("Set CAM_UNCOR_PARITY\n");
+				printk("Set CAM_UNCOR_PARITY\n");
 			}
 #endif
 			ahd_set_transaction_status(scb, CAM_UNCOR_PARITY);
@@ -1843,12 +1843,12 @@
 			u_int i;
 
 			ahd_print_path(ahd, scb);
-			printf("CDB:");
+			printk("CDB:");
 			for (i = 0; i < scb->io_ctx->cmd_len; i++)
-				printf(" 0x%x", scb->io_ctx->cmnd[i]);
-			printf("\n");
+				printk(" 0x%x", scb->io_ctx->cmnd[i]);
+			printk("\n");
 			ahd_print_path(ahd, scb);
-			printf("Saw underflow (%ld of %ld bytes). "
+			printk("Saw underflow (%ld of %ld bytes). "
 			       "Treated as error\n",
 				ahd_get_residual(scb),
 				ahd_get_transfer_length(scb));
@@ -1881,7 +1881,7 @@
 		dev->commands_since_idle_or_otag = 0;
 
 	if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
-		printf("Recovery SCB completes\n");
+		printk("Recovery SCB completes\n");
 		if (ahd_get_transaction_status(scb) == CAM_BDR_SENT
 		 || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED)
 			ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT);
@@ -1963,14 +1963,14 @@
 			if (ahd_debug & AHD_SHOW_SENSE) {
 				int i;
 
-				printf("Copied %d bytes of sense data at %d:",
+				printk("Copied %d bytes of sense data at %d:",
 				       sense_size, sense_offset);
 				for (i = 0; i < sense_size; i++) {
 					if ((i & 0xF) == 0)
-						printf("\n");
-					printf("0x%x ", cmd->sense_buffer[i]);
+						printk("\n");
+					printk("0x%x ", cmd->sense_buffer[i]);
 				}
-				printf("\n");
+				printk("\n");
 			}
 #endif
 		}
@@ -1995,7 +1995,7 @@
 #ifdef AHD_DEBUG
 			if ((ahd_debug & AHD_SHOW_QFULL) != 0) {
 				ahd_print_path(ahd, scb);
-				printf("Dropping tag count to %d\n",
+				printk("Dropping tag count to %d\n",
 				       dev->active);
 			}
 #endif
@@ -2014,7 +2014,7 @@
 				 == AHD_LOCK_TAGS_COUNT) {
 					dev->maxtags = dev->active;
 					ahd_print_path(ahd, scb);
-					printf("Locking max tag count at %d\n",
+					printk("Locking max tag count at %d\n",
 					       dev->active);
 				}
 			} else {
@@ -2138,7 +2138,7 @@
 	}
 
 	if (do_fallback) {
-		printf("%s: device overrun (status %x) on %d:%d:%d\n",
+		printk("%s: device overrun (status %x) on %d:%d:%d\n",
 		       ahd_name(ahd), status, cmd->device->channel,
 		       cmd->device->id, cmd->device->lun);
 	}
@@ -2187,10 +2187,10 @@
 	scmd_printk(KERN_INFO, cmd,
 		    "Attempting to queue an ABORT message:");
 
-	printf("CDB:");
+	printk("CDB:");
 	for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
-		printf(" 0x%x", cmd->cmnd[cdb_byte]);
-	printf("\n");
+		printk(" 0x%x", cmd->cmnd[cdb_byte]);
+	printk("\n");
 
 	ahd_lock(ahd, &flags);
 
@@ -2249,7 +2249,7 @@
 		goto no_cmd;
 	}
 
-	printf("%s: At time of recovery, card was %spaused\n",
+	printk("%s: At time of recovery, card was %spaused\n",
 	       ahd_name(ahd), was_paused ? "" : "not ");
 	ahd_dump_card_state(ahd);
 
@@ -2260,7 +2260,7 @@
 			       pending_scb->hscb->tag,
 			       ROLE_INITIATOR, CAM_REQ_ABORTED,
 			       SEARCH_COMPLETE) > 0) {
-		printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
+		printk("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
 		       ahd_name(ahd), cmd->device->channel, 
 		       cmd->device->id, cmd->device->lun);
 		retval = SUCCESS;
@@ -2355,7 +2355,7 @@
 		ahd_qinfifo_requeue_tail(ahd, pending_scb);
 		ahd_set_scbptr(ahd, saved_scbptr);
 		ahd_print_path(ahd, pending_scb);
-		printf("Device is disconnected, re-queuing SCB\n");
+		printk("Device is disconnected, re-queuing SCB\n");
 		wait = TRUE;
 	} else {
 		scmd_printk(KERN_INFO, cmd, "Unable to deliver message\n");
@@ -2380,21 +2380,21 @@
 		ahd->platform_data->eh_done = &done;
 		ahd_unlock(ahd, &flags);
 
-		printf("%s: Recovery code sleeping\n", ahd_name(ahd));
+		printk("%s: Recovery code sleeping\n", ahd_name(ahd));
 		if (!wait_for_completion_timeout(&done, 5 * HZ)) {
 			ahd_lock(ahd, &flags);
 			ahd->platform_data->eh_done = NULL;
 			ahd_unlock(ahd, &flags);
-			printf("%s: Timer Expired (active %d)\n",
+			printk("%s: Timer Expired (active %d)\n",
 			       ahd_name(ahd), dev->active);
 			retval = FAILED;
 		}
-		printf("Recovery code awake\n");
+		printk("Recovery code awake\n");
 	} else
 		ahd_unlock(ahd, &flags);
 
 	if (retval != SUCCESS)
-		printf("%s: Command abort returning 0x%x\n",
+		printk("%s: Command abort returning 0x%x\n",
 		       ahd_name(ahd), retval);
 
 	return retval;
@@ -2431,7 +2431,7 @@
 
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_DV) != 0)
-		printf("%s: set period to %d\n", ahd_name(ahd), period);
+		printk("%s: set period to %d\n", ahd_name(ahd), period);
 #endif
 	if (offset == 0)
 		offset = MAX_OFFSET;
@@ -2484,7 +2484,7 @@
 
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_DV) != 0)
-		printf("%s: set offset to %d\n", ahd_name(ahd), offset);
+		printk("%s: set offset to %d\n", ahd_name(ahd), offset);
 #endif
 
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
@@ -2520,7 +2520,7 @@
 
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_DV) != 0)
-		printf("%s: %s DT\n", ahd_name(ahd), 
+		printk("%s: %s DT\n", ahd_name(ahd),
 		       dt ? "enabling" : "disabling");
 #endif
 	if (dt && spi_max_width(starget)) {
@@ -2562,7 +2562,7 @@
 
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_DV) != 0)
-		printf("%s: %s QAS\n", ahd_name(ahd), 
+		printk("%s: %s QAS\n", ahd_name(ahd),
 		       qas ? "enabling" : "disabling");
 #endif
 
@@ -2601,7 +2601,7 @@
 
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_DV) != 0)
-		printf("%s: %s IU\n", ahd_name(ahd),
+		printk("%s: %s IU\n", ahd_name(ahd),
 		       iu ? "enabling" : "disabling");
 #endif
 
@@ -2641,7 +2641,7 @@
 
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_DV) != 0)
-		printf("%s: %s Read Streaming\n", ahd_name(ahd), 
+		printk("%s: %s Read Streaming\n", ahd_name(ahd),
 		       rdstrm  ? "enabling" : "disabling");
 #endif
 
@@ -2677,7 +2677,7 @@
 
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_DV) != 0)
-		printf("%s: %s Write Flow Control\n", ahd_name(ahd),
+		printk("%s: %s Write Flow Control\n", ahd_name(ahd),
 		       wrflow ? "enabling" : "disabling");
 #endif
 
@@ -2714,14 +2714,14 @@
 	if ((ahd->features & AHD_RTI) == 0) {
 #ifdef AHD_DEBUG
 		if ((ahd_debug & AHD_SHOW_DV) != 0)
-			printf("%s: RTI not available\n", ahd_name(ahd));
+			printk("%s: RTI not available\n", ahd_name(ahd));
 #endif
 		return;
 	}
 
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_DV) != 0)
-		printf("%s: %s RTI\n", ahd_name(ahd),
+		printk("%s: %s RTI\n", ahd_name(ahd),
 		       rti ? "enabling" : "disabling");
 #endif
 
@@ -2757,7 +2757,7 @@
 
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_DV) != 0)
-		printf("%s: %s Precompensation\n", ahd_name(ahd), 
+		printk("%s: %s Precompensation\n", ahd_name(ahd),
 		       pcomp ? "Enable" : "Disable");
 #endif
 
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 55c1fe0..28e4349 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -363,13 +363,6 @@
 	resource_size_t		 mem_busaddr;	/* Mem Base Addr */
 };
 
-/************************** OS Utility Wrappers *******************************/
-#define printf printk
-#define M_NOWAIT GFP_ATOMIC
-#define M_WAITOK 0
-#define malloc(size, type, flags) kmalloc(size, flags)
-#define free(ptr, type) kfree(ptr)
-
 void ahd_delay(long);
 
 /***************************** Low Level I/O **********************************/
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index 8f68612..3c85873 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -178,7 +178,7 @@
 		ahd_get_pci_bus(pci),
 		ahd_get_pci_slot(pci),
 		ahd_get_pci_function(pci));
-	name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+	name = kmalloc(strlen(buf) + 1, GFP_ATOMIC);
 	if (name == NULL)
 		return (-ENOMEM);
 	strcpy(name, buf);
@@ -333,7 +333,7 @@
 
 		if (ahd_pci_test_register_access(ahd) != 0) {
 
-			printf("aic79xx: PCI Device %d:%d:%d "
+			printk("aic79xx: PCI Device %d:%d:%d "
 			       "failed memory mapped test.  Using PIO.\n",
 			       ahd_get_pci_bus(ahd->dev_softc),
 			       ahd_get_pci_slot(ahd->dev_softc),
@@ -346,7 +346,7 @@
 		} else
 			command |= PCIM_CMD_MEMEN;
 	} else if (bootverbose) {
-		printf("aic79xx: PCI%d:%d:%d MEM region 0x%llx "
+		printk("aic79xx: PCI%d:%d:%d MEM region 0x%llx "
 		       "unavailable. Cannot memory map device.\n",
 		       ahd_get_pci_bus(ahd->dev_softc),
 		       ahd_get_pci_slot(ahd->dev_softc),
@@ -365,7 +365,7 @@
 			ahd->bshs[1].ioport = (u_long)base2;
 			command |= PCIM_CMD_PORTEN;
 		} else {
-			printf("aic79xx: PCI%d:%d:%d IO regions 0x%llx and "
+			printk("aic79xx: PCI%d:%d:%d IO regions 0x%llx and "
 			       "0x%llx unavailable. Cannot map device.\n",
 			       ahd_get_pci_bus(ahd->dev_softc),
 			       ahd_get_pci_slot(ahd->dev_softc),
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 90a04a3..14b5f8d 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -338,7 +338,7 @@
 	 */
 	if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) {
 		if (bootverbose)
-			printf("%s: Enabling 39Bit Addressing\n",
+			printk("%s: Enabling 39Bit Addressing\n",
 			       ahd_name(ahd));
 		devconfig = ahd_pci_read_config(ahd->dev_softc,
 						DEVCONFIG, /*bytes*/4);
@@ -528,7 +528,7 @@
 		 * Fetch VPD for this function and parse it.
 		 */
 		if (bootverbose) 
-			printf("%s: Reading VPD from SEEPROM...",
+			printk("%s: Reading VPD from SEEPROM...",
 			       ahd_name(ahd));
 
 		/* Address is always in units of 16bit words */
@@ -541,12 +541,12 @@
 		if (error == 0)
 			error = ahd_parse_vpddata(ahd, &vpd);
 		if (bootverbose) 
-			printf("%s: VPD parsing %s\n",
+			printk("%s: VPD parsing %s\n",
 			       ahd_name(ahd),
 			       error == 0 ? "successful" : "failed");
 
 		if (bootverbose) 
-			printf("%s: Reading SEEPROM...", ahd_name(ahd));
+			printk("%s: Reading SEEPROM...", ahd_name(ahd));
 
 		/* Address is always in units of 16bit words */
 		start_addr = (sizeof(*sc) / 2) * (ahd->channel - 'A');
@@ -556,16 +556,16 @@
 					 /*bytestream*/FALSE);
 
 		if (error != 0) {
-			printf("Unable to read SEEPROM\n");
+			printk("Unable to read SEEPROM\n");
 			have_seeprom = 0;
 		} else {
 			have_seeprom = ahd_verify_cksum(sc);
 
 			if (bootverbose) {
 				if (have_seeprom == 0)
-					printf ("checksum error\n");
+					printk ("checksum error\n");
 				else
-					printf ("done.\n");
+					printk ("done.\n");
 			}
 		}
 		ahd_release_seeprom(ahd);
@@ -615,21 +615,21 @@
 		uint16_t *sc_data;
 		int	  i;
 
-		printf("%s: Seeprom Contents:", ahd_name(ahd));
+		printk("%s: Seeprom Contents:", ahd_name(ahd));
 		sc_data = (uint16_t *)sc;
 		for (i = 0; i < (sizeof(*sc)); i += 2)
-			printf("\n\t0x%.4x", sc_data[i]);
-		printf("\n");
+			printk("\n\t0x%.4x", sc_data[i]);
+		printk("\n");
 	}
 #endif
 
 	if (!have_seeprom) {
 		if (bootverbose)
-			printf("%s: No SEEPROM available.\n", ahd_name(ahd));
+			printk("%s: No SEEPROM available.\n", ahd_name(ahd));
 		ahd->flags |= AHD_USEDEFAULTS;
 		error = ahd_default_config(ahd);
 		adapter_control = CFAUTOTERM|CFSEAUTOTERM;
-		free(ahd->seep_config, M_DEVBUF);
+		kfree(ahd->seep_config);
 		ahd->seep_config = NULL;
 	} else {
 		error = ahd_parse_cfgdata(ahd, sc);
@@ -656,7 +656,7 @@
 	if ((ahd->flags & AHD_STPWLEVEL_A) != 0)
 		devconfig |= STPWLEVEL;
 	if (bootverbose)
-		printf("%s: STPWLEVEL is %s\n",
+		printk("%s: STPWLEVEL is %s\n",
 		       ahd_name(ahd), (devconfig & STPWLEVEL) ? "on" : "off");
 	ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
  
@@ -671,7 +671,7 @@
 	error = ahd_read_flexport(ahd, FLXADDR_TERMCTL, &termctl);
 	if ((adapter_control & CFAUTOTERM) == 0) {
 		if (bootverbose)
-			printf("%s: Manual Primary Termination\n",
+			printk("%s: Manual Primary Termination\n",
 			       ahd_name(ahd));
 		termctl &= ~(FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH);
 		if ((adapter_control & CFSTERM) != 0)
@@ -679,14 +679,14 @@
 		if ((adapter_control & CFWSTERM) != 0)
 			termctl |= FLX_TERMCTL_ENPRIHIGH;
 	} else if (error != 0) {
-		printf("%s: Primary Auto-Term Sensing failed! "
+		printk("%s: Primary Auto-Term Sensing failed! "
 		       "Using Defaults.\n", ahd_name(ahd));
 		termctl = FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH;
 	}
 
 	if ((adapter_control & CFSEAUTOTERM) == 0) {
 		if (bootverbose)
-			printf("%s: Manual Secondary Termination\n",
+			printk("%s: Manual Secondary Termination\n",
 			       ahd_name(ahd));
 		termctl &= ~(FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH);
 		if ((adapter_control & CFSELOWTERM) != 0)
@@ -694,7 +694,7 @@
 		if ((adapter_control & CFSEHIGHTERM) != 0)
 			termctl |= FLX_TERMCTL_ENSECHIGH;
 	} else if (error != 0) {
-		printf("%s: Secondary Auto-Term Sensing failed! "
+		printk("%s: Secondary Auto-Term Sensing failed! "
 		       "Using Defaults.\n", ahd_name(ahd));
 		termctl |= FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH;
 	}
@@ -714,22 +714,22 @@
 
 	error = ahd_write_flexport(ahd, FLXADDR_TERMCTL, termctl);
 	if (error != 0) {
-		printf("%s: Unable to set termination settings!\n",
+		printk("%s: Unable to set termination settings!\n",
 		       ahd_name(ahd));
 	} else if (bootverbose) {
-		printf("%s: Primary High byte termination %sabled\n",
+		printk("%s: Primary High byte termination %sabled\n",
 		       ahd_name(ahd),
 		       (termctl & FLX_TERMCTL_ENPRIHIGH) ? "En" : "Dis");
 
-		printf("%s: Primary Low byte termination %sabled\n",
+		printk("%s: Primary Low byte termination %sabled\n",
 		       ahd_name(ahd),
 		       (termctl & FLX_TERMCTL_ENPRILOW) ? "En" : "Dis");
 
-		printf("%s: Secondary High byte termination %sabled\n",
+		printk("%s: Secondary High byte termination %sabled\n",
 		       ahd_name(ahd),
 		       (termctl & FLX_TERMCTL_ENSECHIGH) ? "En" : "Dis");
 
-		printf("%s: Secondary Low byte termination %sabled\n",
+		printk("%s: Secondary Low byte termination %sabled\n",
 		       ahd_name(ahd),
 		       (termctl & FLX_TERMCTL_ENSECLOW) ? "En" : "Dis");
 	}
@@ -805,7 +805,7 @@
 	if ((intstat & PCIINT) == 0)
 		return;
 
-	printf("%s: PCI error Interrupt\n", ahd_name(ahd));
+	printk("%s: PCI error Interrupt\n", ahd_name(ahd));
 	saved_modes = ahd_save_modes(ahd);
 	ahd_dump_card_state(ahd);
 	ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
@@ -832,7 +832,7 @@
 				s = pci_status_strings[bit];
 				if (i == 7/*TARG*/ && bit == 3)
 					s = "%s: Signaled Target Abort\n";
-				printf(s, ahd_name(ahd), pci_status_source[i]);
+				printk(s, ahd_name(ahd), pci_status_source[i]);
 			}
 		}	
 	}
@@ -862,7 +862,7 @@
 	 */
 	pcix_status = ahd_pci_read_config(ahd->dev_softc, PCIXR_STATUS,
 					  /*bytes*/2);
-	printf("%s: PCI Split Interrupt - PCI-X status = 0x%x\n",
+	printk("%s: PCI Split Interrupt - PCI-X status = 0x%x\n",
 	       ahd_name(ahd), pcix_status);
 	saved_modes = ahd_save_modes(ahd);
 	for (i = 0; i < 4; i++) {
@@ -891,7 +891,7 @@
 				static const char *s;
 
 				s = split_status_strings[bit];
-				printf(s, ahd_name(ahd),
+				printk(s, ahd_name(ahd),
 				       split_status_source[i]);
 			}
 
@@ -902,7 +902,7 @@
 				static const char *s;
 
 				s = split_status_strings[bit];
-				printf(s, ahd_name(ahd), "SG");
+				printk(s, ahd_name(ahd), "SG");
 			}
 		}
 	}
@@ -950,7 +950,7 @@
 	pci = ahd->dev_softc;
 	rev = ahd_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
 	if (rev < ID_AIC7902_PCI_REV_A4) {
-		printf("%s: Unable to attach to unsupported chip revision %d\n",
+		printk("%s: Unable to attach to unsupported chip revision %d\n",
 		       ahd_name(ahd), rev);
 		ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/2);
 		return (ENXIO);
diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
index 014bed7..59c85d5 100644
--- a/drivers/scsi/aic7xxx/aic79xx_proc.c
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c
@@ -272,33 +272,32 @@
 	saved_modes = ahd_save_modes(ahd);
 	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
 	if (length != sizeof(struct seeprom_config)) {
-		printf("ahd_proc_write_seeprom: incorrect buffer size\n");
+		printk("ahd_proc_write_seeprom: incorrect buffer size\n");
 		goto done;
 	}
 
 	have_seeprom = ahd_verify_cksum((struct seeprom_config*)buffer);
 	if (have_seeprom == 0) {
-		printf("ahd_proc_write_seeprom: cksum verification failed\n");
+		printk("ahd_proc_write_seeprom: cksum verification failed\n");
 		goto done;
 	}
 
 	have_seeprom = ahd_acquire_seeprom(ahd);
 	if (!have_seeprom) {
-		printf("ahd_proc_write_seeprom: No Serial EEPROM\n");
+		printk("ahd_proc_write_seeprom: No Serial EEPROM\n");
 		goto done;
 	} else {
 		u_int start_addr;
 
 		if (ahd->seep_config == NULL) {
-			ahd->seep_config = malloc(sizeof(*ahd->seep_config),
-						  M_DEVBUF, M_NOWAIT);
+			ahd->seep_config = kmalloc(sizeof(*ahd->seep_config), GFP_ATOMIC);
 			if (ahd->seep_config == NULL) {
-				printf("aic79xx: Unable to allocate serial "
+				printk("aic79xx: Unable to allocate serial "
 				       "eeprom buffer.  Write failing\n");
 				goto done;
 			}
 		}
-		printf("aic79xx: Writing Serial EEPROM\n");
+		printk("aic79xx: Writing Serial EEPROM\n");
 		start_addr = 32 * (ahd->channel - 'A');
 		ahd_write_seeprom(ahd, (u_int16_t *)buffer, start_addr,
 				  sizeof(struct seeprom_config)/2);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
index dd11999..9e85a7e 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
@@ -207,14 +207,14 @@
 		reset_seeprom(sd);
 	}
 #ifdef AHC_DUMP_EEPROM
-	printf("\nSerial EEPROM:\n\t");
+	printk("\nSerial EEPROM:\n\t");
 	for (k = 0; k < count; k = k + 1) {
 		if (((k % 8) == 0) && (k != 0)) {
-			printf ("\n\t");
+			printk(KERN_CONT "\n\t");
 		}
-		printf (" 0x%x", buf[k]);
+		printk(KERN_CONT " 0x%x", buf[k]);
 	}
-	printf ("\n");
+	printk(KERN_CONT "\n");
 #endif
 	return (1);
 }
@@ -240,7 +240,7 @@
 		ewen = &seeprom_long_ewen;
 		ewds = &seeprom_long_ewds;
 	} else {
-		printf("ahc_write_seeprom: unsupported seeprom type %d\n",
+		printk("ahc_write_seeprom: unsupported seeprom type %d\n",
 		       sd->sd_chip);
 		return (0);
 	}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 45aa728..3f5a542 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -910,7 +910,7 @@
 
 		scb = ahc_lookup_scb(ahc, scb_index);
 		if (scb == NULL) {
-			printf("%s: WARNING no command for scb %d "
+			printk("%s: WARNING no command for scb %d "
 			       "(cmdcmplt)\nQOUTPOS = %d\n",
 			       ahc_name(ahc), scb_index,
 			       (ahc->qoutfifonext - 1) & 0xFF);
@@ -964,7 +964,7 @@
 	error = ahc_inb(ahc, ERROR);
 	for (i = 0; error != 1 && i < num_errors; i++)
 		error >>= 1;
-	printf("%s: brkadrint, %s at seqaddr = 0x%x\n",
+	printk("%s: brkadrint, %s at seqaddr = 0x%x\n",
 	       ahc_name(ahc), ahc_hard_errors[i].errmesg,
 	       ahc_inb(ahc, SEQADDR0) |
 	       (ahc_inb(ahc, SEQADDR1) << 8));
@@ -1021,7 +1021,7 @@
 		scb = ahc_lookup_scb(ahc, scb_index);
 		if (scb == NULL) {
 			ahc_print_devinfo(ahc, &devinfo);
-			printf("ahc_intr - referenced scb "
+			printk("ahc_intr - referenced scb "
 			       "not valid during seqint 0x%x scb(%d)\n",
 			       intstat, scb_index);
 			ahc_dump_card_state(ahc);
@@ -1049,7 +1049,7 @@
 		ahc_set_scsi_status(scb, hscb->shared_data.status.scsi_status);
 		switch (hscb->shared_data.status.scsi_status) {
 		case SCSI_STATUS_OK:
-			printf("%s: Interrupted for staus of 0???\n",
+			printk("%s: Interrupted for staus of 0???\n",
 			       ahc_name(ahc));
 			break;
 		case SCSI_STATUS_CMD_TERMINATED:
@@ -1063,7 +1063,7 @@
 #ifdef AHC_DEBUG
 			if (ahc_debug & AHC_SHOW_SENSE) {
 				ahc_print_path(ahc, scb);
-				printf("SCB %d: requests Check Status\n",
+				printk("SCB %d: requests Check Status\n",
 				       scb->hscb->tag);
 			}
 #endif
@@ -1086,7 +1086,7 @@
 #ifdef AHC_DEBUG
 			if (ahc_debug & AHC_SHOW_SENSE) {
 				ahc_print_path(ahc, scb);
-				printf("Sending Sense\n");
+				printk("Sending Sense\n");
 			}
 #endif
 			sg->addr = ahc_get_sense_bufaddr(ahc, scb);
@@ -1162,29 +1162,29 @@
 		ahc_outb(ahc, SCSISEQ,
 			 ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
 
-		printf("%s:%c:%d: no active SCB for reconnecting "
+		printk("%s:%c:%d: no active SCB for reconnecting "
 		       "target - issuing BUS DEVICE RESET\n",
 		       ahc_name(ahc), devinfo.channel, devinfo.target);
-		printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
+		printk("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
 		       "ARG_1 == 0x%x ACCUM = 0x%x\n",
 		       ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN),
 		       ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM));
-		printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
+		printk("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
 		       "SINDEX == 0x%x\n",
 		       ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR),
 		       ahc_index_busy_tcl(ahc,
 			    BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID),
 				      ahc_inb(ahc, SAVED_LUN))),
 		       ahc_inb(ahc, SINDEX));
-		printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
+		printk("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
 		       "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n",
 		       ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID),
 		       ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG),
 		       ahc_inb(ahc, SCB_CONTROL));
-		printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n",
+		printk("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n",
 		       ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI));
-		printf("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0));
-		printf("SEQCTL == 0x%x\n", ahc_inb(ahc, SEQCTL));
+		printk("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0));
+		printk("SEQCTL == 0x%x\n", ahc_inb(ahc, SEQCTL));
 		ahc_dump_card_state(ahc);
 		ahc->msgout_buf[0] = MSG_BUS_DEV_RESET;
 		ahc->msgout_len = 1;
@@ -1197,7 +1197,7 @@
 	case SEND_REJECT: 
 	{
 		u_int rejbyte = ahc_inb(ahc, ACCUM);
-		printf("%s:%c:%d: Warning - unknown message received from "
+		printk("%s:%c:%d: Warning - unknown message received from "
 		       "target (0x%x).  Rejecting\n", 
 		       ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte);
 		break; 
@@ -1218,7 +1218,7 @@
 		u_int lastphase;
 
 		lastphase = ahc_inb(ahc, LASTPHASE);
-		printf("%s:%c:%d: unknown scsi bus phase %x, "
+		printk("%s:%c:%d: unknown scsi bus phase %x, "
 		       "lastphase = 0x%x.  Attempting to continue\n",
 		       ahc_name(ahc), devinfo.channel, devinfo.target,
 		       lastphase, ahc_inb(ahc, SCSISIGI));
@@ -1229,7 +1229,7 @@
 		u_int lastphase;
 
 		lastphase = ahc_inb(ahc, LASTPHASE);
-		printf("%s:%c:%d: Missed busfree. "
+		printk("%s:%c:%d: Missed busfree. "
 		       "Lastphase = 0x%x, Curphase = 0x%x\n",
 		       ahc_name(ahc), devinfo.channel, devinfo.target,
 		       lastphase, ahc_inb(ahc, SCSISIGI));
@@ -1257,7 +1257,7 @@
 			bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
 			if (bus_phase != P_MESGIN
 			 && bus_phase != P_MESGOUT) {
-				printf("ahc_intr: HOST_MSG_LOOP bad "
+				printk("ahc_intr: HOST_MSG_LOOP bad "
 				       "phase 0x%x\n",
 				      bus_phase);
 				/*
@@ -1359,7 +1359,7 @@
 					u_int	scb_index;
 
 					ahc_print_devinfo(ahc, &devinfo);
-					printf("Unable to clear parity error.  "
+					printk("Unable to clear parity error.  "
 					       "Resetting bus.\n");
 					scb_index = ahc_inb(ahc, SCB_TAG);
 					scb = ahc_lookup_scb(ahc, scb_index);
@@ -1395,18 +1395,18 @@
 				break;
 		}
 		ahc_print_path(ahc, scb);
-		printf("data overrun detected %s."
+		printk("data overrun detected %s."
 		       "  Tag == 0x%x.\n",
 		       ahc_phase_table[i].phasemsg,
   		       scb->hscb->tag);
 		ahc_print_path(ahc, scb);
-		printf("%s seen Data Phase.  Length = %ld.  NumSGs = %d.\n",
+		printk("%s seen Data Phase.  Length = %ld.  NumSGs = %d.\n",
 		       ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
 		       ahc_get_transfer_length(scb), scb->sg_count);
 		if (scb->sg_count > 0) {
 			for (i = 0; i < scb->sg_count; i++) {
 
-				printf("sg[%d] - Addr 0x%x%x : Length %d\n",
+				printk("sg[%d] - Addr 0x%x%x : Length %d\n",
 				       i,
 				       (ahc_le32toh(scb->sg_list[i].len) >> 24
 				        & SG_HIGH_ADDR_BITS),
@@ -1453,7 +1453,7 @@
 	{
 		u_int scbindex;
 
-		printf("%s:%c:%d:%d: Attempt to issue message failed\n",
+		printk("%s:%c:%d:%d: Attempt to issue message failed\n",
 		       ahc_name(ahc), devinfo.channel, devinfo.target,
 		       devinfo.lun);
 		scbindex = ahc_inb(ahc, SCB_TAG);
@@ -1473,7 +1473,7 @@
 	}
 	case NO_FREE_SCB:
 	{
-		printf("%s: No free or disconnected SCBs\n", ahc_name(ahc));
+		printk("%s: No free or disconnected SCBs\n", ahc_name(ahc));
 		ahc_dump_card_state(ahc);
 		panic("for safety");
 		break;
@@ -1483,7 +1483,7 @@
 		u_int scbptr;
 
 		scbptr = ahc_inb(ahc, SCBPTR);
-		printf("Bogus TAG after DMA.  SCBPTR %d, tag %d, our tag %d\n",
+		printk("Bogus TAG after DMA.  SCBPTR %d, tag %d, our tag %d\n",
 		       scbptr, ahc_inb(ahc, ARG_1),
 		       ahc->scb_data->hscbs[scbptr].tag);
 		ahc_dump_card_state(ahc);
@@ -1492,12 +1492,12 @@
 	}
 	case OUT_OF_RANGE:
 	{
-		printf("%s: BTT calculation out of range\n", ahc_name(ahc));
-		printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
+		printk("%s: BTT calculation out of range\n", ahc_name(ahc));
+		printk("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
 		       "ARG_1 == 0x%x ACCUM = 0x%x\n",
 		       ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN),
 		       ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM));
-		printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
+		printk("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
 		       "SINDEX == 0x%x\n, A == 0x%x\n",
 		       ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR),
 		       ahc_index_busy_tcl(ahc,
@@ -1505,19 +1505,19 @@
 				      ahc_inb(ahc, SAVED_LUN))),
 		       ahc_inb(ahc, SINDEX),
 		       ahc_inb(ahc, ACCUM));
-		printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
+		printk("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
 		       "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n",
 		       ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID),
 		       ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG),
 		       ahc_inb(ahc, SCB_CONTROL));
-		printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n",
+		printk("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n",
 		       ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI));
 		ahc_dump_card_state(ahc);
 		panic("for safety");
 		break;
 	}
 	default:
-		printf("ahc_intr: seqint, "
+		printk("ahc_intr: seqint, "
 		       "intstat == 0x%x, scsisigi = 0x%x\n",
 		       intstat, ahc_inb(ahc, SCSISIGI));
 		break;
@@ -1562,7 +1562,7 @@
 			intr_channel = (cur_channel == 'A') ? 'B' : 'A';
 		}
 		if (status == 0) {
-			printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc));
+			printk("%s: Spurious SCSI interrupt\n", ahc_name(ahc));
 			ahc_outb(ahc, CLRINT, CLRSCSIINT);
 			ahc_unpause(ahc);
 			return;
@@ -1583,7 +1583,7 @@
 		int now_lvd;
 
 		now_lvd = ahc_inb(ahc, SBLKCTL) & ENAB40;
-		printf("%s: Transceiver State Has Changed to %s mode\n",
+		printk("%s: Transceiver State Has Changed to %s mode\n",
 		       ahc_name(ahc), now_lvd ? "LVD" : "SE");
 		ahc_outb(ahc, CLRSINT0, CLRIOERR);
 		/*
@@ -1599,7 +1599,7 @@
 		ahc_reset_channel(ahc, intr_channel,
 				 /*Initiate Reset*/now_lvd == 0);
 	} else if ((status & SCSIRSTI) != 0) {
-		printf("%s: Someone reset channel %c\n",
+		printk("%s: Someone reset channel %c\n",
 			ahc_name(ahc), intr_channel);
 		if (intr_channel != cur_channel)
 		 	ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB);
@@ -1659,26 +1659,26 @@
 				ahc_print_path(ahc, scb);
 			scb->flags |= SCB_TRANSMISSION_ERROR;
 		} else
-			printf("%s:%c:%d: ", ahc_name(ahc), intr_channel,
+			printk("%s:%c:%d: ", ahc_name(ahc), intr_channel,
 			       SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)));
 		scsirate = ahc_inb(ahc, SCSIRATE);
 		if (silent == FALSE) {
-			printf("parity error detected %s. "
+			printk("parity error detected %s. "
 			       "SEQADDR(0x%x) SCSIRATE(0x%x)\n",
 			       ahc_phase_table[i].phasemsg,
 			       ahc_inw(ahc, SEQADDR0),
 			       scsirate);
 			if ((ahc->features & AHC_DT) != 0) {
 				if ((sstat2 & CRCVALERR) != 0)
-					printf("\tCRC Value Mismatch\n");
+					printk("\tCRC Value Mismatch\n");
 				if ((sstat2 & CRCENDERR) != 0)
-					printf("\tNo terminal CRC packet "
+					printk("\tNo terminal CRC packet "
 					       "recevied\n");
 				if ((sstat2 & CRCREQERR) != 0)
-					printf("\tIllegal CRC packet "
+					printk("\tIllegal CRC packet "
 					       "request\n");
 				if ((sstat2 & DUAL_EDGE_ERR) != 0)
-					printf("\tUnexpected %sDT Data Phase\n",
+					printk("\tUnexpected %sDT Data Phase\n",
 					       (scsirate & SINGLE_EDGE)
 					     ? "" : "non-");
 			}
@@ -1746,7 +1746,7 @@
 
 		scb = ahc_lookup_scb(ahc, scb_index);
 		if (scb == NULL) {
-			printf("%s: ahc_intr - referenced scb not "
+			printk("%s: ahc_intr - referenced scb not "
 			       "valid during SELTO scb(%d, %d)\n",
 			       ahc_name(ahc), scbptr, scb_index);
 			ahc_dump_card_state(ahc);
@@ -1755,7 +1755,7 @@
 #ifdef AHC_DEBUG
 			if ((ahc_debug & AHC_SHOW_SELTO) != 0) {
 				ahc_print_path(ahc, scb);
-				printf("Saw Selection Timeout for SCB 0x%x\n",
+				printk("Saw Selection Timeout for SCB 0x%x\n",
 				       scb_index);
 			}
 #endif
@@ -1831,7 +1831,7 @@
 				 == MSG_ABORT_TAG)
 					tag = scb->hscb->tag;
 				ahc_print_path(ahc, scb);
-				printf("SCB %d - Abort%s Completed.\n",
+				printk("SCB %d - Abort%s Completed.\n",
 				       scb->hscb->tag, tag == SCB_LIST_NULL ?
 				       "" : " Tag");
 				ahc_abort_scbs(ahc, target, channel,
@@ -1934,7 +1934,7 @@
 				 * We had not fully identified this connection,
 				 * so we cannot abort anything.
 				 */
-				printf("%s: ", ahc_name(ahc));
+				printk("%s: ", ahc_name(ahc));
 			}
 			for (i = 0; i < num_phases; i++) {
 				if (lastphase == ahc_phase_table[i].phase)
@@ -1949,7 +1949,7 @@
 				 */
 				ahc_force_renegotiation(ahc, &devinfo);
 			}
-			printf("Unexpected busfree %s\n"
+			printk("Unexpected busfree %s\n"
 			       "SEQADDR == 0x%x\n",
 			       ahc_phase_table[i].phasemsg,
 			       ahc_inb(ahc, SEQADDR0)
@@ -1958,7 +1958,7 @@
 		ahc_outb(ahc, CLRINT, CLRSCSIINT);
 		ahc_restart(ahc);
 	} else {
-		printf("%s: Missing case in ahc_handle_scsiint. status = %x\n",
+		printk("%s: Missing case in ahc_handle_scsiint. status = %x\n",
 		       ahc_name(ahc), status);
 		ahc_outb(ahc, CLRINT, CLRSCSIINT);
 	}
@@ -2025,7 +2025,7 @@
 			break;
 
 		if (steps > AHC_MAX_STEPS) {
-			printf("%s: Infinite loop in critical section\n",
+			printk("%s: Infinite loop in critical section\n",
 			       ahc_name(ahc));
 			ahc_dump_card_state(ahc);
 			panic("critical section loop");
@@ -2104,23 +2104,23 @@
 
 	struct hardware_scb *hscb = scb->hscb;
 
-	printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
+	printk("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
 	       (void *)scb,
 	       hscb->control,
 	       hscb->scsiid,
 	       hscb->lun,
 	       hscb->cdb_len);
-	printf("Shared Data: ");
+	printk("Shared Data: ");
 	for (i = 0; i < sizeof(hscb->shared_data.cdb); i++)
-		printf("%#02x", hscb->shared_data.cdb[i]);
-	printf("        dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n",
+		printk("%#02x", hscb->shared_data.cdb[i]);
+	printk("        dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n",
 		ahc_le32toh(hscb->dataptr),
 		ahc_le32toh(hscb->datacnt),
 		ahc_le32toh(hscb->sgptr),
 		hscb->tag);
 	if (scb->sg_count > 0) {
 		for (i = 0; i < scb->sg_count; i++) {
-			printf("sg[%d] - Addr 0x%x%x : Length %d\n",
+			printk("sg[%d] - Addr 0x%x%x : Length %d\n",
 			       i,
 			       (ahc_le32toh(scb->sg_list[i].len) >> 24
 			        & SG_HIGH_ADDR_BITS),
@@ -2152,8 +2152,7 @@
 	 && ahc->enabled_targets[scsi_id] != master_tstate)
 		panic("%s: ahc_alloc_tstate - Target already allocated",
 		      ahc_name(ahc));
-	tstate = (struct ahc_tmode_tstate*)malloc(sizeof(*tstate),
-						   M_DEVBUF, M_NOWAIT);
+	tstate = kmalloc(sizeof(*tstate), GFP_ATOMIC);
 	if (tstate == NULL)
 		return (NULL);
 
@@ -2202,7 +2201,7 @@
 		scsi_id += 8;
 	tstate = ahc->enabled_targets[scsi_id];
 	if (tstate != NULL)
-		free(tstate, M_DEVBUF);
+		kfree(tstate);
 	ahc->enabled_targets[scsi_id] = NULL;
 }
 #endif
@@ -2589,13 +2588,13 @@
 			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
 		if (bootverbose) {
 			if (offset != 0) {
-				printf("%s: target %d synchronous at %sMHz%s, "
+				printk("%s: target %d synchronous at %sMHz%s, "
 				       "offset = 0x%x\n", ahc_name(ahc),
 				       devinfo->target, syncrate->rate,
 				       (ppr_options & MSG_EXT_PPR_DT_REQ)
 				       ? " DT" : "", offset);
 			} else {
-				printf("%s: target %d using "
+				printk("%s: target %d using "
 				       "asynchronous transfers\n",
 				       ahc_name(ahc), devinfo->target);
 			}
@@ -2658,7 +2657,7 @@
 		ahc_send_async(ahc, devinfo->channel, devinfo->target,
 			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
 		if (bootverbose) {
-			printf("%s: target %d using %dbit transfers\n",
+			printk("%s: target %d using %dbit transfers\n",
 			       ahc_name(ahc), devinfo->target,
 			       8 * (0x01 << width));
 		}
@@ -2835,7 +2834,7 @@
 void
 ahc_print_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
 {
-	printf("%s:%c:%d:%d: ", ahc_name(ahc), devinfo->channel,
+	printk("%s:%c:%d:%d: ", ahc_name(ahc), devinfo->channel,
 	       devinfo->target, devinfo->lun);
 }
 
@@ -2907,7 +2906,7 @@
 		ahc->msgout_buf[ahc->msgout_index++] = MSG_BUS_DEV_RESET;
 		ahc->msgout_len++;
 		ahc_print_path(ahc, scb);
-		printf("Bus Device Reset Message Sent\n");
+		printk("Bus Device Reset Message Sent\n");
 		/*
 		 * Clear our selection hardware in advance of
 		 * the busfree.  We may have an entry in the waiting
@@ -2923,7 +2922,7 @@
 			ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT;
 		ahc->msgout_len++;
 		ahc_print_path(ahc, scb);
-		printf("Abort%s Message Sent\n",
+		printk("Abort%s Message Sent\n",
 		       (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : "");
 		/*
 		 * Clear our selection hardware in advance of
@@ -2936,9 +2935,9 @@
 	} else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) {
 		ahc_build_transfer_msg(ahc, devinfo);
 	} else {
-		printf("ahc_intr: AWAITING_MSG for an SCB that "
+		printk("ahc_intr: AWAITING_MSG for an SCB that "
 		       "does not have a waiting message\n");
-		printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid,
+		printk("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid,
 		       devinfo->target_mask);
 		panic("SCB = %d, SCB Control = %x, MSG_OUT = %x "
 		      "SCB flags = %x", scb->hscb->tag, scb->hscb->control,
@@ -3019,7 +3018,7 @@
 
 		if (bootverbose) {
 			ahc_print_devinfo(ahc, devinfo);
-			printf("Ensuring async\n");
+			printk("Ensuring async\n");
 		}
 	}
 
@@ -3067,7 +3066,7 @@
 			ahc->msgout_buf + ahc->msgout_index, period, offset);
 	ahc->msgout_len += 5;
 	if (bootverbose) {
-		printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
+		printk("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
 		       ahc_name(ahc), devinfo->channel, devinfo->target,
 		       devinfo->lun, period, offset);
 	}
@@ -3085,7 +3084,7 @@
 			ahc->msgout_buf + ahc->msgout_index, bus_width);
 	ahc->msgout_len += 4;
 	if (bootverbose) {
-		printf("(%s:%c:%d:%d): Sending WDTR %x\n",
+		printk("(%s:%c:%d:%d): Sending WDTR %x\n",
 		       ahc_name(ahc), devinfo->channel, devinfo->target,
 		       devinfo->lun, bus_width);
 	}
@@ -3107,7 +3106,7 @@
 			bus_width, ppr_options);
 	ahc->msgout_len += 8;
 	if (bootverbose) {
-		printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
+		printk("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
 		       "offset %x, ppr_options %x\n", ahc_name(ahc),
 		       devinfo->channel, devinfo->target, devinfo->lun,
 		       bus_width, period, offset, ppr_options);
@@ -3160,7 +3159,7 @@
 		 * to match.
 		 */
 		ahc_print_devinfo(ahc, &devinfo);
-		printf("Target did not send an IDENTIFY message. "
+		printk("Target did not send an IDENTIFY message. "
 		       "LASTPHASE = 0x%x.\n", lastphase);
 		scb = NULL;
 	} else if (scb == NULL) {
@@ -3169,13 +3168,13 @@
 		 * transaction.  Print an error and reset the bus.
 		 */
 		ahc_print_devinfo(ahc, &devinfo);
-		printf("No SCB found during protocol violation\n");
+		printk("No SCB found during protocol violation\n");
 		goto proto_violation_reset;
 	} else {
 		ahc_set_transaction_status(scb, CAM_SEQUENCE_FAIL);
 		if ((seq_flags & NO_CDB_SENT) != 0) {
 			ahc_print_path(ahc, scb);
-			printf("No or incomplete CDB sent to device.\n");
+			printk("No or incomplete CDB sent to device.\n");
 		} else if ((ahc_inb(ahc, SCB_CONTROL) & STATUS_RCVD) == 0) {
 			/*
 			 * The target never bothered to provide status to
@@ -3185,10 +3184,10 @@
 			 * message.
 			 */
 			ahc_print_path(ahc, scb);
-			printf("Completed command without status.\n");
+			printk("Completed command without status.\n");
 		} else {
 			ahc_print_path(ahc, scb);
-			printf("Unknown protocol violation.\n");
+			printk("Unknown protocol violation.\n");
 			ahc_dump_card_state(ahc);
 		}
 	}
@@ -3202,7 +3201,7 @@
 		 * it away with a bus reset.
 		 */
 		found = ahc_reset_channel(ahc, 'A', TRUE);
-		printf("%s: Issued Channel %c Bus Reset. "
+		printk("%s: Issued Channel %c Bus Reset. "
 		       "%d SCBs aborted\n", ahc_name(ahc), 'A', found);
 	} else {
 		/*
@@ -3224,7 +3223,7 @@
 			ahc_print_path(ahc, scb);
 			scb->flags |= SCB_ABORT;
 		}
-		printf("Protocol violation %s.  Attempting to abort.\n",
+		printk("Protocol violation %s.  Attempting to abort.\n",
 		       ahc_lookup_phase_entry(curphase)->phasemsg);
 	}
 }
@@ -3257,14 +3256,14 @@
 #ifdef AHC_DEBUG
 		if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
 			ahc_print_devinfo(ahc, &devinfo);
-			printf("INITIATOR_MSG_OUT");
+			printk("INITIATOR_MSG_OUT");
 		}
 #endif
 		phasemis = bus_phase != P_MESGOUT;
 		if (phasemis) {
 #ifdef AHC_DEBUG
 			if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
-				printf(" PHASEMIS %s\n",
+				printk(" PHASEMIS %s\n",
 				       ahc_lookup_phase_entry(bus_phase)
 							     ->phasemsg);
 			}
@@ -3291,7 +3290,7 @@
 			ahc_outb(ahc, CLRSINT1, CLRREQINIT);
 #ifdef AHC_DEBUG
 			if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
-				printf(" byte 0x%x\n", ahc->send_msg_perror);
+				printk(" byte 0x%x\n", ahc->send_msg_perror);
 #endif
 			ahc_outb(ahc, SCSIDATL, MSG_PARITY_ERROR);
 			break;
@@ -3321,7 +3320,7 @@
 		ahc_outb(ahc, CLRSINT1, CLRREQINIT);
 #ifdef AHC_DEBUG
 		if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
-			printf(" byte 0x%x\n",
+			printk(" byte 0x%x\n",
 			       ahc->msgout_buf[ahc->msgout_index]);
 #endif
 		ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]);
@@ -3335,14 +3334,14 @@
 #ifdef AHC_DEBUG
 		if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
 			ahc_print_devinfo(ahc, &devinfo);
-			printf("INITIATOR_MSG_IN");
+			printk("INITIATOR_MSG_IN");
 		}
 #endif
 		phasemis = bus_phase != P_MESGIN;
 		if (phasemis) {
 #ifdef AHC_DEBUG
 			if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
-				printf(" PHASEMIS %s\n",
+				printk(" PHASEMIS %s\n",
 				       ahc_lookup_phase_entry(bus_phase)
 							     ->phasemsg);
 			}
@@ -3363,7 +3362,7 @@
 		ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIBUSL);
 #ifdef AHC_DEBUG
 		if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
-			printf(" byte 0x%x\n",
+			printk(" byte 0x%x\n",
 			       ahc->msgin_buf[ahc->msgin_index]);
 #endif
 
@@ -3385,7 +3384,7 @@
 #ifdef AHC_DEBUG
 				if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
 					ahc_print_devinfo(ahc, &devinfo);
-					printf("Asserting ATN for response\n");
+					printk("Asserting ATN for response\n");
 				}
 #endif
 				ahc_assert_atn(ahc);
@@ -3666,7 +3665,7 @@
 					    targ_scsirate & WIDEXFER,
 					    devinfo->role);
 			if (bootverbose) {
-				printf("(%s:%c:%d:%d): Received "
+				printk("(%s:%c:%d:%d): Received "
 				       "SDTR period %x, offset %x\n\t"
 				       "Filtered to period %x, offset %x\n",
 				       ahc_name(ahc), devinfo->channel,
@@ -3697,7 +3696,7 @@
 				 */
 				if (bootverbose
 				 && devinfo->role == ROLE_INITIATOR) {
-					printf("(%s:%c:%d:%d): Target "
+					printk("(%s:%c:%d:%d): Target "
 					       "Initiated SDTR\n",
 					       ahc_name(ahc), devinfo->channel,
 					       devinfo->target, devinfo->lun);
@@ -3739,7 +3738,7 @@
 			ahc_validate_width(ahc, tinfo, &bus_width,
 					   devinfo->role);
 			if (bootverbose) {
-				printf("(%s:%c:%d:%d): Received WDTR "
+				printk("(%s:%c:%d:%d): Received WDTR "
 				       "%x filtered to %x\n",
 				       ahc_name(ahc), devinfo->channel,
 				       devinfo->target, devinfo->lun,
@@ -3755,7 +3754,7 @@
 				 */
 				if (saved_width > bus_width) {
 					reject = TRUE;
-					printf("(%s:%c:%d:%d): requested %dBit "
+					printk("(%s:%c:%d:%d): requested %dBit "
 					       "transfers.  Rejecting...\n",
 					       ahc_name(ahc), devinfo->channel,
 					       devinfo->target, devinfo->lun,
@@ -3768,7 +3767,7 @@
 				 */
 				if (bootverbose
 				 && devinfo->role == ROLE_INITIATOR) {
-					printf("(%s:%c:%d:%d): Target "
+					printk("(%s:%c:%d:%d): Target "
 					       "Initiated WDTR\n",
 					       ahc_name(ahc), devinfo->channel,
 					       devinfo->target, devinfo->lun);
@@ -3886,12 +3885,12 @@
 				}
 			} else {
 				if (devinfo->role != ROLE_TARGET)
-					printf("(%s:%c:%d:%d): Target "
+					printk("(%s:%c:%d:%d): Target "
 					       "Initiated PPR\n",
 					       ahc_name(ahc), devinfo->channel,
 					       devinfo->target, devinfo->lun);
 				else
-					printf("(%s:%c:%d:%d): Initiator "
+					printk("(%s:%c:%d:%d): Initiator "
 					       "Initiated PPR\n",
 					       ahc_name(ahc), devinfo->channel,
 					       devinfo->target, devinfo->lun);
@@ -3903,7 +3902,7 @@
 				response = TRUE;
 			}
 			if (bootverbose) {
-				printf("(%s:%c:%d:%d): Received PPR width %x, "
+				printk("(%s:%c:%d:%d): Received PPR width %x, "
 				       "period %x, offset %x,options %x\n"
 				       "\tFiltered to width %x, period %x, "
 				       "offset %x, options %x\n",
@@ -4033,7 +4032,7 @@
 		 * Attempt to negotiate SPI-2 style.
 		 */
 		if (bootverbose) {
-			printf("(%s:%c:%d:%d): PPR Rejected. "
+			printk("(%s:%c:%d:%d): PPR Rejected. "
 			       "Trying WDTR/SDTR\n",
 			       ahc_name(ahc), devinfo->channel,
 			       devinfo->target, devinfo->lun);
@@ -4049,7 +4048,7 @@
 	} else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) {
 
 		/* note 8bit xfers */
-		printf("(%s:%c:%d:%d): refuses WIDE negotiation.  Using "
+		printk("(%s:%c:%d:%d): refuses WIDE negotiation.  Using "
 		       "8bit transfers\n", ahc_name(ahc),
 		       devinfo->channel, devinfo->target, devinfo->lun);
 		ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
@@ -4077,7 +4076,7 @@
 				 /*offset*/0, /*ppr_options*/0,
 				 AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
 				 /*paused*/TRUE);
-		printf("(%s:%c:%d:%d): refuses synchronous negotiation. "
+		printk("(%s:%c:%d:%d): refuses synchronous negotiation. "
 		       "Using asynchronous transfers\n",
 		       ahc_name(ahc), devinfo->channel,
 		       devinfo->target, devinfo->lun);
@@ -4088,13 +4087,13 @@
 		tag_type = (scb->hscb->control & MSG_SIMPLE_TASK);
 
 		if (tag_type == MSG_SIMPLE_TASK) {
-			printf("(%s:%c:%d:%d): refuses tagged commands.  "
+			printk("(%s:%c:%d:%d): refuses tagged commands.  "
 			       "Performing non-tagged I/O\n", ahc_name(ahc),
 			       devinfo->channel, devinfo->target, devinfo->lun);
 			ahc_set_tags(ahc, scb->io_ctx, devinfo, AHC_QUEUE_NONE);
 			mask = ~0x23;
 		} else {
-			printf("(%s:%c:%d:%d): refuses %s tagged commands.  "
+			printk("(%s:%c:%d:%d): refuses %s tagged commands.  "
 			       "Performing simple queue tagged I/O only\n",
 			       ahc_name(ahc), devinfo->channel, devinfo->target,
 			       devinfo->lun, tag_type == MSG_ORDERED_TASK
@@ -4144,7 +4143,7 @@
 		/*
 		 * Otherwise, we ignore it.
 		 */
-		printf("%s:%c:%d: Message reject for %x -- ignored\n",
+		printk("%s:%c:%d: Message reject for %x -- ignored\n",
 		       ahc_name(ahc), devinfo->channel, devinfo->target,
 		       last_msg);
 	}
@@ -4369,7 +4368,7 @@
 
 	if (message != NULL
 	 && (verbose_level <= bootverbose))
-		printf("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc),
+		printk("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc),
 		       message, devinfo->channel, devinfo->target, found);
 }
 
@@ -4408,23 +4407,22 @@
 	int	i;
 
 #ifndef	__FreeBSD__
-	ahc = malloc(sizeof(*ahc), M_DEVBUF, M_NOWAIT);
+	ahc = kmalloc(sizeof(*ahc), GFP_ATOMIC);
 	if (!ahc) {
-		printf("aic7xxx: cannot malloc softc!\n");
-		free(name, M_DEVBUF);
+		printk("aic7xxx: cannot malloc softc!\n");
+		kfree(name);
 		return NULL;
 	}
 #else
 	ahc = device_get_softc((device_t)platform_arg);
 #endif
 	memset(ahc, 0, sizeof(*ahc));
-	ahc->seep_config = malloc(sizeof(*ahc->seep_config),
-				  M_DEVBUF, M_NOWAIT);
+	ahc->seep_config = kmalloc(sizeof(*ahc->seep_config), GFP_ATOMIC);
 	if (ahc->seep_config == NULL) {
 #ifndef	__FreeBSD__
-		free(ahc, M_DEVBUF);
+		kfree(ahc);
 #endif
-		free(name, M_DEVBUF);
+		kfree(name);
 		return (NULL);
 	}
 	LIST_INIT(&ahc->pending_scbs);
@@ -4466,8 +4464,7 @@
 	ahc->pause = ahc->unpause | PAUSE; 
 	/* XXX The shared scb data stuff should be deprecated */
 	if (ahc->scb_data == NULL) {
-		ahc->scb_data = malloc(sizeof(*ahc->scb_data),
-				       M_DEVBUF, M_NOWAIT);
+		ahc->scb_data = kmalloc(sizeof(*ahc->scb_data), GFP_ATOMIC);
 		if (ahc->scb_data == NULL)
 			return (ENOMEM);
 		memset(ahc->scb_data, 0, sizeof(*ahc->scb_data));
@@ -4486,7 +4483,7 @@
 ahc_set_name(struct ahc_softc *ahc, char *name)
 {
 	if (ahc->name != NULL)
-		free(ahc->name, M_DEVBUF);
+		kfree(ahc->name);
 	ahc->name = name;
 }
 
@@ -4540,25 +4537,25 @@
 				lstate = tstate->enabled_luns[j];
 				if (lstate != NULL) {
 					xpt_free_path(lstate->path);
-					free(lstate, M_DEVBUF);
+					kfree(lstate);
 				}
 			}
 #endif
-			free(tstate, M_DEVBUF);
+			kfree(tstate);
 		}
 	}
 #ifdef AHC_TARGET_MODE
 	if (ahc->black_hole != NULL) {
 		xpt_free_path(ahc->black_hole->path);
-		free(ahc->black_hole, M_DEVBUF);
+		kfree(ahc->black_hole);
 	}
 #endif
 	if (ahc->name != NULL)
-		free(ahc->name, M_DEVBUF);
+		kfree(ahc->name);
 	if (ahc->seep_config != NULL)
-		free(ahc->seep_config, M_DEVBUF);
+		kfree(ahc->seep_config);
 #ifndef __FreeBSD__
-	free(ahc, M_DEVBUF);
+	kfree(ahc);
 #endif
 	return;
 }
@@ -4633,7 +4630,7 @@
 	} while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK));
 
 	if (wait == 0) {
-		printf("%s: WARNING - Failed chip reset!  "
+		printk("%s: WARNING - Failed chip reset!  "
 		       "Trying to initialize anyway.\n", ahc_name(ahc));
 	}
 	ahc_outb(ahc, HCNTRL, ahc->pause);
@@ -4656,7 +4653,7 @@
 		ahc->features |= AHC_TWIN;
 		break;
 	default:
-		printf(" Unsupported adapter type.  Ignoring\n");
+		printk(" Unsupported adapter type.  Ignoring\n");
 		return(-1);
 	}
 
@@ -4783,9 +4780,7 @@
 	SLIST_INIT(&scb_data->sg_maps);
 
 	/* Allocate SCB resources */
-	scb_data->scbarray =
-	    (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC,
-				 M_DEVBUF, M_NOWAIT);
+	scb_data->scbarray = (struct scb *)kmalloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC, GFP_ATOMIC);
 	if (scb_data->scbarray == NULL)
 		return (ENOMEM);
 	memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX_ALLOC);
@@ -4794,7 +4789,7 @@
 
 	scb_data->maxhscbs = ahc_probe_scbs(ahc);
 	if (ahc->scb_data->maxhscbs == 0) {
-		printf("%s: No SCB space found\n", ahc_name(ahc));
+		printk("%s: No SCB space found\n", ahc_name(ahc));
 		return (ENXIO);
 	}
 
@@ -4892,7 +4887,7 @@
 	ahc_alloc_scbs(ahc);
 
 	if (scb_data->numscbs == 0) {
-		printf("%s: ahc_init_scbdata - "
+		printk("%s: ahc_init_scbdata - "
 		       "Unable to allocate initial scbs\n",
 		       ahc_name(ahc));
 		goto error_exit;
@@ -4935,7 +4930,7 @@
 			ahc_dmamem_free(ahc, scb_data->sg_dmat,
 					sg_map->sg_vaddr,
 					sg_map->sg_dmamap);
-			free(sg_map, M_DEVBUF);
+			kfree(sg_map);
 		}
 		ahc_dma_tag_destroy(ahc, scb_data->sg_dmat);
 	}
@@ -4964,7 +4959,7 @@
 		break;
 	}
 	if (scb_data->scbarray != NULL)
-		free(scb_data->scbarray, M_DEVBUF);
+		kfree(scb_data->scbarray);
 }
 
 static void
@@ -4985,7 +4980,7 @@
 
 	next_scb = &scb_data->scbarray[scb_data->numscbs];
 
-	sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
+	sg_map = kmalloc(sizeof(*sg_map), GFP_ATOMIC);
 
 	if (sg_map == NULL)
 		return;
@@ -4994,7 +4989,7 @@
 	if (ahc_dmamem_alloc(ahc, scb_data->sg_dmat,
 			     (void **)&sg_map->sg_vaddr,
 			     BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
-		free(sg_map, M_DEVBUF);
+		kfree(sg_map);
 		return;
 	}
 
@@ -5014,8 +5009,7 @@
 #ifndef __linux__
 		int error;
 #endif
-		pdata = (struct scb_platform_data *)malloc(sizeof(*pdata),
-							   M_DEVBUF, M_NOWAIT);
+		pdata = kmalloc(sizeof(*pdata), GFP_ATOMIC);
 		if (pdata == NULL)
 			break;
 		next_scb->platform_data = pdata;
@@ -5244,7 +5238,7 @@
 	 * in "fast" mode.
 	 */
 	if (bootverbose)
-		printf("%s: Downloading Sequencer Program...",
+		printk("%s: Downloading Sequencer Program...",
 		       ahc_name(ahc));
 
 	error = ahc_loadseq(ahc);
@@ -5290,22 +5284,22 @@
 #endif
 
 #ifdef AHC_PRINT_SRAM
-	printf("Scratch Ram:");
+	printk("Scratch Ram:");
 	for (i = 0x20; i < 0x5f; i++) {
 		if (((i % 8) == 0) && (i != 0)) {
-			printf ("\n              ");
+			printk ("\n              ");
 		}
-		printf (" 0x%x", ahc_inb(ahc, i));
+		printk (" 0x%x", ahc_inb(ahc, i));
 	}
 	if ((ahc->features & AHC_MORE_SRAM) != 0) {
 		for (i = 0x70; i < 0x7f; i++) {
 			if (((i % 8) == 0) && (i != 0)) {
-				printf ("\n              ");
+				printk ("\n              ");
 			}
-			printf (" 0x%x", ahc_inb(ahc, i));
+			printk (" 0x%x", ahc_inb(ahc, i));
 		}
 	}
-	printf ("\n");
+	printk ("\n");
 	/*
 	 * Reading uninitialized scratch ram may
 	 * generate parity errors.
@@ -5419,14 +5413,14 @@
 	 * data for any target mode initiator.
 	 */
 	if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) {
-		printf("%s: unable to allocate ahc_tmode_tstate.  "
+		printk("%s: unable to allocate ahc_tmode_tstate.  "
 		       "Failing attach\n", ahc_name(ahc));
 		return (ENOMEM);
 	}
 
 	if ((ahc->features & AHC_TWIN) != 0) {
 		if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) {
-			printf("%s: unable to allocate ahc_tmode_tstate.  "
+			printk("%s: unable to allocate ahc_tmode_tstate.  "
 			       "Failing attach\n", ahc_name(ahc));
 			return (ENOMEM);
 		}
@@ -5440,7 +5434,7 @@
 
 #ifdef AHC_DEBUG
 	if (ahc_debug & AHC_SHOW_MISC) {
-		printf("%s: hardware scb %u bytes; kernel scb %u bytes; "
+		printk("%s: hardware scb %u bytes; kernel scb %u bytes; "
 		       "ahc_dma %u bytes\n",
 			ahc_name(ahc),
 			(u_int)sizeof(struct hardware_scb),
@@ -5470,7 +5464,7 @@
 
 	/* Grab the disconnection disable table and invert it for our needs */
 	if ((ahc->flags & AHC_USEDEFAULTS) != 0) {
-		printf("%s: Host Adapter Bios disabled.  Using default SCSI "
+		printk("%s: Host Adapter Bios disabled.  Using default SCSI "
 			"device parameters\n", ahc_name(ahc));
 		ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B|
 			      AHC_TERM_ENB_A|AHC_TERM_ENB_B;
@@ -5651,7 +5645,7 @@
 	      && ((intstat & INT_PEND) != 0
 	       || (ahc_inb(ahc, SSTAT0) & (SELDO|SELINGO)) != 0));
 	if (maxloops == 0) {
-		printf("Infinite interrupt loop, INTSTAT = %x",
+		printk("Infinite interrupt loop, INTSTAT = %x",
 		       ahc_inb(ahc, INTSTAT));
 	}
 	ahc_platform_flushwork(ahc);
@@ -5910,7 +5904,7 @@
 	while (qinpos != qintail) {
 		scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinpos]);
 		if (scb == NULL) {
-			printf("qinpos = %d, SCB index = %d\n",
+			printk("qinpos = %d, SCB index = %d\n",
 				qinpos, ahc->qinfifo[qinpos]);
 			panic("Loop 1\n");
 		}
@@ -5933,7 +5927,7 @@
 				if (cstat != CAM_REQ_CMP)
 					ahc_freeze_scb(scb);
 				if ((scb->flags & SCB_ACTIVE) == 0)
-					printf("Inactive SCB in qinfifo\n");
+					printk("Inactive SCB in qinfifo\n");
 				ahc_done(ahc, scb);
 
 				/* FALLTHROUGH */
@@ -5976,7 +5970,7 @@
 		scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinstart]);
 
 		if (scb == NULL) {
-			printf("found = %d, qinstart = %d, qinfifionext = %d\n",
+			printk("found = %d, qinstart = %d, qinfifionext = %d\n",
 				found, qinstart, ahc->qinfifonext);
 			panic("First/Second Qinfifo fixup\n");
 		}
@@ -6014,7 +6008,7 @@
 		ahc_outb(ahc, SCBPTR, next);
 		scb_index = ahc_inb(ahc, SCB_TAG);
 		if (scb_index >= ahc->scb_data->numscbs) {
-			printf("Waiting List inconsistency. "
+			printk("Waiting List inconsistency. "
 			       "SCB index == %d, yet numscbs == %d.",
 			       scb_index, ahc->scb_data->numscbs);
 			ahc_dump_card_state(ahc);
@@ -6022,7 +6016,7 @@
 		}
 		scb = ahc_lookup_scb(ahc, scb_index);
 		if (scb == NULL) {
-			printf("scb_index = %d, next = %d\n",
+			printk("scb_index = %d, next = %d\n",
 				scb_index, next);
 			panic("Waiting List traversal\n");
 		}
@@ -6046,7 +6040,7 @@
 				if (cstat != CAM_REQ_CMP)
 					ahc_freeze_scb(scb);
 				if ((scb->flags & SCB_ACTIVE) == 0)
-					printf("Inactive SCB in Waiting List\n");
+					printk("Inactive SCB in Waiting List\n");
 				ahc_done(ahc, scb);
 				/* FALLTHROUGH */
 			}
@@ -6153,7 +6147,7 @@
 				if (cstat != CAM_REQ_CMP)
 					ahc_freeze_scb(scb);
 				if ((scb->flags & SCB_ACTIVE) == 0)
-					printf("Inactive SCB in untaggedQ\n");
+					printk("Inactive SCB in untaggedQ\n");
 				ahc_done(ahc, scb);
 				break;
 			}
@@ -6200,7 +6194,7 @@
 		ahc_outb(ahc, SCBPTR, next);
 		scb_index = ahc_inb(ahc, SCB_TAG);
 		if (scb_index >= ahc->scb_data->numscbs) {
-			printf("Disconnected List inconsistency. "
+			printk("Disconnected List inconsistency. "
 			       "SCB index == %d, yet numscbs == %d.",
 			       scb_index, ahc->scb_data->numscbs);
 			ahc_dump_card_state(ahc);
@@ -6456,7 +6450,7 @@
 			if (ahc_get_transaction_status(scbp) != CAM_REQ_CMP)
 				ahc_freeze_scb(scbp);
 			if ((scbp->flags & SCB_ACTIVE) == 0)
-				printf("Inactive SCB on pending list\n");
+				printk("Inactive SCB on pending list\n");
 			ahc_done(ahc, scbp);
 			found++;
 		}
@@ -6734,7 +6728,7 @@
 #ifdef AHC_DEBUG
 	if ((ahc_debug & AHC_SHOW_MISC) != 0) {
 		ahc_print_path(ahc, scb);
-		printf("Handled %sResidual of %d bytes\n",
+		printk("Handled %sResidual of %d bytes\n",
 		       (scb->flags & SCB_SENSE) ? "Sense " : "", resid);
 	}
 #endif
@@ -6774,7 +6768,7 @@
 
 	if (pending == AHC_TMODE_EVENT_BUFFER_SIZE) {
 		xpt_print_path(lstate->path);
-		printf("immediate event %x:%x lost\n",
+		printk("immediate event %x:%x lost\n",
 		       lstate->event_buffer[lstate->event_r_idx].event_type,
 		       lstate->event_buffer[lstate->event_r_idx].event_arg);
 		lstate->event_r_idx++;
@@ -6844,7 +6838,7 @@
 		uint8_t ins_bytes[4];
 
 		ahc_insb(ahc, SEQRAM, ins_bytes, 4);
-		printf("0x%08x\n", ins_bytes[0] << 24
+		printk("0x%08x\n", ins_bytes[0] << 24
 				 | ins_bytes[1] << 16
 				 | ins_bytes[2] << 8
 				 | ins_bytes[3]);
@@ -6912,7 +6906,7 @@
 			 * storage capacity for this chip.  Fail
 			 * the load.
 			 */
-			printf("\n%s: Program too large for instruction memory "
+			printk("\n%s: Program too large for instruction memory "
 			       "size of %d!\n", ahc_name(ahc),
 			       ahc->instruction_ram_size);
 			return (ENOMEM);
@@ -6947,7 +6941,7 @@
 	if (cs_count != 0) {
 
 		cs_count *= sizeof(struct cs);
-		ahc->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT);
+		ahc->critical_sections = kmalloc(cs_count, GFP_ATOMIC);
 		if (ahc->critical_sections == NULL)
 			panic("ahc_loadseq: Could not malloc");
 		memcpy(ahc->critical_sections, cs_table, cs_count);
@@ -6955,8 +6949,8 @@
 	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE);
 
 	if (bootverbose) {
-		printf(" %d instructions downloaded\n", downloaded);
-		printf("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n",
+		printk(" %d instructions downloaded\n", downloaded);
+		printk("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n",
 		       ahc_name(ahc), ahc->features, ahc->bugs, ahc->flags);
 	}
 	return (0);
@@ -7132,12 +7126,12 @@
 	u_int	printed_mask;
 
 	if (cur_column != NULL && *cur_column >= wrap_point) {
-		printf("\n");
+		printk("\n");
 		*cur_column = 0;
 	}
-	printed = printf("%s[0x%x]", name, value);
+	printed  = printk("%s[0x%x]", name, value);
 	if (table == NULL) {
-		printed += printf(" ");
+		printed += printk(" ");
 		*cur_column += printed;
 		return (printed);
 	}
@@ -7152,7 +7146,7 @@
 			  == table[entry].mask))
 				continue;
 
-			printed += printf("%s%s",
+			printed += printk("%s%s",
 					  printed_mask == 0 ? ":(" : "|",
 					  table[entry].name);
 			printed_mask |= table[entry].mask;
@@ -7163,9 +7157,9 @@
 			break;
 	}
 	if (printed_mask != 0)
-		printed += printf(") ");
+		printed += printk(") ");
 	else
-		printed += printf(" ");
+		printed += printk(" ");
 	if (cur_column != NULL)
 		*cur_column += printed;
 	return (printed);
@@ -7197,16 +7191,16 @@
 
 	saved_scbptr = ahc_inb(ahc, SCBPTR);
 	last_phase = ahc_inb(ahc, LASTPHASE);
-	printf(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n"
+	printk(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n"
 	       "%s: Dumping Card State %s, at SEQADDR 0x%x\n",
 	       ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg,
 	       ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
 	if (paused)
-		printf("Card was paused\n");
-	printf("ACCUM = 0x%x, SINDEX = 0x%x, DINDEX = 0x%x, ARG_2 = 0x%x\n",
+		printk("Card was paused\n");
+	printk("ACCUM = 0x%x, SINDEX = 0x%x, DINDEX = 0x%x, ARG_2 = 0x%x\n",
 	       ahc_inb(ahc, ACCUM), ahc_inb(ahc, SINDEX), ahc_inb(ahc, DINDEX),
 	       ahc_inb(ahc, ARG_2));
-	printf("HCNT = 0x%x SCBPTR = 0x%x\n", ahc_inb(ahc, HCNT),
+	printk("HCNT = 0x%x SCBPTR = 0x%x\n", ahc_inb(ahc, HCNT),
 	       ahc_inb(ahc, SCBPTR));
 	cur_col = 0;
 	if ((ahc->features & AHC_DT) != 0)
@@ -7230,15 +7224,15 @@
 	ahc_dfcntrl_print(ahc_inb(ahc, DFCNTRL), &cur_col, 50);
 	ahc_dfstatus_print(ahc_inb(ahc, DFSTATUS), &cur_col, 50);
 	if (cur_col != 0)
-		printf("\n");
-	printf("STACK:");
+		printk("\n");
+	printk("STACK:");
 	for (i = 0; i < STACK_SIZE; i++)
-	       printf(" 0x%x", ahc_inb(ahc, STACK)|(ahc_inb(ahc, STACK) << 8));
-	printf("\nSCB count = %d\n", ahc->scb_data->numscbs);
-	printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag);
-	printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB));
+		printk(" 0x%x", ahc_inb(ahc, STACK)|(ahc_inb(ahc, STACK) << 8));
+	printk("\nSCB count = %d\n", ahc->scb_data->numscbs);
+	printk("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag);
+	printk("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB));
 	/* QINFIFO */
-	printf("QINFIFO entries: ");
+	printk("QINFIFO entries: ");
 	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
 		qinpos = ahc_inb(ahc, SNSCB_QOFF);
 		ahc_outb(ahc, SNSCB_QOFF, qinpos);
@@ -7246,109 +7240,109 @@
 		qinpos = ahc_inb(ahc, QINPOS);
 	qintail = ahc->qinfifonext;
 	while (qinpos != qintail) {
-		printf("%d ", ahc->qinfifo[qinpos]);
+		printk("%d ", ahc->qinfifo[qinpos]);
 		qinpos++;
 	}
-	printf("\n");
+	printk("\n");
 
-	printf("Waiting Queue entries: ");
+	printk("Waiting Queue entries: ");
 	scb_index = ahc_inb(ahc, WAITING_SCBH);
 	i = 0;
 	while (scb_index != SCB_LIST_NULL && i++ < 256) {
 		ahc_outb(ahc, SCBPTR, scb_index);
-		printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG));
+		printk("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG));
 		scb_index = ahc_inb(ahc, SCB_NEXT);
 	}
-	printf("\n");
+	printk("\n");
 
-	printf("Disconnected Queue entries: ");
+	printk("Disconnected Queue entries: ");
 	scb_index = ahc_inb(ahc, DISCONNECTED_SCBH);
 	i = 0;
 	while (scb_index != SCB_LIST_NULL && i++ < 256) {
 		ahc_outb(ahc, SCBPTR, scb_index);
-		printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG));
+		printk("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG));
 		scb_index = ahc_inb(ahc, SCB_NEXT);
 	}
-	printf("\n");
+	printk("\n");
 		
 	ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD);
-	printf("QOUTFIFO entries: ");
+	printk("QOUTFIFO entries: ");
 	qoutpos = ahc->qoutfifonext;
 	i = 0;
 	while (ahc->qoutfifo[qoutpos] != SCB_LIST_NULL && i++ < 256) {
-		printf("%d ", ahc->qoutfifo[qoutpos]);
+		printk("%d ", ahc->qoutfifo[qoutpos]);
 		qoutpos++;
 	}
-	printf("\n");
+	printk("\n");
 
-	printf("Sequencer Free SCB List: ");
+	printk("Sequencer Free SCB List: ");
 	scb_index = ahc_inb(ahc, FREE_SCBH);
 	i = 0;
 	while (scb_index != SCB_LIST_NULL && i++ < 256) {
 		ahc_outb(ahc, SCBPTR, scb_index);
-		printf("%d ", scb_index);
+		printk("%d ", scb_index);
 		scb_index = ahc_inb(ahc, SCB_NEXT);
 	}
-	printf("\n");
+	printk("\n");
 
-	printf("Sequencer SCB Info: ");
+	printk("Sequencer SCB Info: ");
 	for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
 		ahc_outb(ahc, SCBPTR, i);
-		cur_col = printf("\n%3d ", i);
+		cur_col  = printk("\n%3d ", i);
 
 		ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL), &cur_col, 60);
 		ahc_scb_scsiid_print(ahc_inb(ahc, SCB_SCSIID), &cur_col, 60);
 		ahc_scb_lun_print(ahc_inb(ahc, SCB_LUN), &cur_col, 60);
 		ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60);
 	}
-	printf("\n");
+	printk("\n");
 
-	printf("Pending list: ");
+	printk("Pending list: ");
 	i = 0;
 	LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) {
 		if (i++ > 256)
 			break;
-		cur_col = printf("\n%3d ", scb->hscb->tag);
+		cur_col  = printk("\n%3d ", scb->hscb->tag);
 		ahc_scb_control_print(scb->hscb->control, &cur_col, 60);
 		ahc_scb_scsiid_print(scb->hscb->scsiid, &cur_col, 60);
 		ahc_scb_lun_print(scb->hscb->lun, &cur_col, 60);
 		if ((ahc->flags & AHC_PAGESCBS) == 0) {
 			ahc_outb(ahc, SCBPTR, scb->hscb->tag);
-			printf("(");
+			printk("(");
 			ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL),
 					      &cur_col, 60);
 			ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60);
-			printf(")");
+			printk(")");
 		}
 	}
-	printf("\n");
+	printk("\n");
 
-	printf("Kernel Free SCB list: ");
+	printk("Kernel Free SCB list: ");
 	i = 0;
 	SLIST_FOREACH(scb, &ahc->scb_data->free_scbs, links.sle) {
 		if (i++ > 256)
 			break;
-		printf("%d ", scb->hscb->tag);
+		printk("%d ", scb->hscb->tag);
 	}
-	printf("\n");
+	printk("\n");
 
 	maxtarget = (ahc->features & (AHC_WIDE|AHC_TWIN)) ? 15 : 7;
 	for (target = 0; target <= maxtarget; target++) {
 		untagged_q = &ahc->untagged_queues[target];
 		if (TAILQ_FIRST(untagged_q) == NULL)
 			continue;
-		printf("Untagged Q(%d): ", target);
+		printk("Untagged Q(%d): ", target);
 		i = 0;
 		TAILQ_FOREACH(scb, untagged_q, links.tqe) {
 			if (i++ > 256)
 				break;
-			printf("%d ", scb->hscb->tag);
+			printk("%d ", scb->hscb->tag);
 		}
-		printf("\n");
+		printk("\n");
 	}
 
 	ahc_platform_dump_card_state(ahc);
-	printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
+	printk("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
 	ahc_outb(ahc, SCBPTR, saved_scbptr);
 	if (paused == 0)
 		ahc_unpause(ahc);
@@ -7489,7 +7483,7 @@
 		u_long	 s;
 		ahc_flag saved_flags;
 
-		printf("Configuring Target Mode\n");
+		printk("Configuring Target Mode\n");
 		ahc_lock(ahc, &s);
 		if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
 			ccb->ccb_h.status = CAM_BUSY;
@@ -7535,7 +7529,7 @@
 		/* Are we already enabled?? */
 		if (lstate != NULL) {
 			xpt_print_path(ccb->ccb_h.path);
-			printf("Lun already enabled\n");
+			printk("Lun already enabled\n");
 			ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
 			return;
 		}
@@ -7547,7 +7541,7 @@
 			 * specific commands.
 			 */
 			ccb->ccb_h.status = CAM_REQ_INVALID;
-			printf("Non-zero Group Codes\n");
+			printk("Non-zero Group Codes\n");
 			return;
 		}
 
@@ -7559,15 +7553,15 @@
 			tstate = ahc_alloc_tstate(ahc, target, channel);
 			if (tstate == NULL) {
 				xpt_print_path(ccb->ccb_h.path);
-				printf("Couldn't allocate tstate\n");
+				printk("Couldn't allocate tstate\n");
 				ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
 				return;
 			}
 		}
-		lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT);
+		lstate = kmalloc(sizeof(*lstate), GFP_ATOMIC);
 		if (lstate == NULL) {
 			xpt_print_path(ccb->ccb_h.path);
-			printf("Couldn't allocate lstate\n");
+			printk("Couldn't allocate lstate\n");
 			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
 			return;
 		}
@@ -7577,9 +7571,9 @@
 					 xpt_path_target_id(ccb->ccb_h.path),
 					 xpt_path_lun_id(ccb->ccb_h.path));
 		if (status != CAM_REQ_CMP) {
-			free(lstate, M_DEVBUF);
+			kfree(lstate);
 			xpt_print_path(ccb->ccb_h.path);
-			printf("Couldn't allocate path\n");
+			printk("Couldn't allocate path\n");
 			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
 			return;
 		}
@@ -7654,7 +7648,7 @@
 		ahc_unlock(ahc, &s);
 		ccb->ccb_h.status = CAM_REQ_CMP;
 		xpt_print_path(ccb->ccb_h.path);
-		printf("Lun now enabled for target mode\n");
+		printk("Lun now enabled for target mode\n");
 	} else {
 		struct scb *scb;
 		int i, empty;
@@ -7673,7 +7667,7 @@
 			ccbh = &scb->io_ctx->ccb_h;
 			if (ccbh->func_code == XPT_CONT_TARGET_IO
 			 && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){
-				printf("CTIO pending\n");
+				printk("CTIO pending\n");
 				ccb->ccb_h.status = CAM_REQ_INVALID;
 				ahc_unlock(ahc, &s);
 				return;
@@ -7681,12 +7675,12 @@
 		}
 
 		if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
-			printf("ATIOs pending\n");
+			printk("ATIOs pending\n");
 			ccb->ccb_h.status = CAM_REQ_INVALID;
 		}
 
 		if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
-			printf("INOTs pending\n");
+			printk("INOTs pending\n");
 			ccb->ccb_h.status = CAM_REQ_INVALID;
 		}
 
@@ -7696,9 +7690,9 @@
 		}
 
 		xpt_print_path(ccb->ccb_h.path);
-		printf("Target mode disabled\n");
+		printk("Target mode disabled\n");
 		xpt_free_path(lstate->path);
-		free(lstate, M_DEVBUF);
+		kfree(lstate);
 
 		ahc_pause(ahc);
 		/* Can we clean up the target too? */
@@ -7750,7 +7744,7 @@
 			ahc_outb(ahc, SCSISEQ, scsiseq);
 
 			if ((ahc->features & AHC_MULTIROLE) == 0) {
-				printf("Configuring Initiator Mode\n");
+				printk("Configuring Initiator Mode\n");
 				ahc->flags &= ~AHC_TARGETROLE;
 				ahc->flags |= AHC_INITIATORROLE;
 				/*
@@ -7897,12 +7891,12 @@
 		 * Wait for more ATIOs from the peripheral driver for this lun.
 		 */
 		if (bootverbose)
-			printf("%s: ATIOs exhausted\n", ahc_name(ahc));
+			printk("%s: ATIOs exhausted\n", ahc_name(ahc));
 		return (1);
 	} else
 		ahc->flags &= ~AHC_TQINFIFO_BLOCKED;
 #if 0
-	printf("Incoming command from %d for %d:%d%s\n",
+	printk("Incoming command from %d for %d:%d%s\n",
 	       initiator, target, lun,
 	       lstate == ahc->black_hole ? "(Black Holed)" : "");
 #endif
@@ -7949,7 +7943,7 @@
 	default:
 		/* Only copy the opcode. */
 		atio->cdb_len = 1;
-		printf("Reserved or VU command code type encountered\n");
+		printk("Reserved or VU command code type encountered\n");
 		break;
 	}
 	
@@ -7965,7 +7959,7 @@
 		 * to this accept tio.
 		 */
 #if 0
-		printf("Received Immediate Command %d:%d:%d - %p\n",
+		printk("Received Immediate Command %d:%d:%d - %p\n",
 		       initiator, target, lun, ahc->pending_device);
 #endif
 		ahc->pending_device = lstate;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 5e42dac..aeea7a6 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -653,7 +653,7 @@
 	struct ahc_linux_device *dev;
 
 	if (bootverbose)
-		printf("%s: Slave Alloc %d\n", ahc_name(ahc), sdev->id);
+		printk("%s: Slave Alloc %d\n", ahc_name(ahc), sdev->id);
 
 	dev = scsi_transport_device_data(sdev);
 	memset(dev, 0, sizeof(*dev));
@@ -755,7 +755,7 @@
 
 	error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT);
 	if (error != 0)
-		printf("aic7xxx_abort returns 0x%x\n", error);
+		printk("aic7xxx_abort returns 0x%x\n", error);
 	return (error);
 }
 
@@ -769,7 +769,7 @@
 
 	error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
 	if (error != 0)
-		printf("aic7xxx_dev_reset returns 0x%x\n", error);
+		printk("aic7xxx_dev_reset returns 0x%x\n", error);
 	return (error);
 }
 
@@ -791,7 +791,7 @@
 	ahc_unlock(ahc, &flags);
 
 	if (bootverbose)
-		printf("%s: SCSI bus reset delivered. "
+		printk("%s: SCSI bus reset delivered. "
 		       "%d SCBs aborted.\n", ahc_name(ahc), found);
 
 	return SUCCESS;
@@ -840,7 +840,7 @@
 {
 	bus_dma_tag_t dmat;
 
-	dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT);
+	dmat = kmalloc(sizeof(*dmat), GFP_ATOMIC);
 	if (dmat == NULL)
 		return (ENOMEM);
 
@@ -861,7 +861,7 @@
 void
 ahc_dma_tag_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat)
 {
-	free(dmat, M_DEVBUF);
+	kfree(dmat);
 }
 
 int
@@ -918,7 +918,7 @@
 	int tags, i, j;
 
 	tags = simple_strtoul(p + 1, NULL, 0) & 0xff;
-	printf("Setting Global Tags= %d\n", tags);
+	printk("Setting Global Tags= %d\n", tags);
 
 	for (i = 0; i < ARRAY_SIZE(aic7xxx_tag_info); i++) {
 		for (j = 0; j < AHC_NUM_TARGETS; j++) {
@@ -936,7 +936,7 @@
 	 && (targ < AHC_NUM_TARGETS)) {
 		aic7xxx_tag_info[instance].tag_commands[targ] = value & 0xff;
 		if (bootverbose)
-			printf("tag_info[%d:%d] = %d\n", instance, targ, value);
+			printk("tag_info[%d:%d] = %d\n", instance, targ, value);
 	}
 }
 
@@ -977,7 +977,7 @@
 					if (targ == -1)
 						targ = 0;
 				} else {
-					printf("Malformed Option %s\n",
+					printk("Malformed Option %s\n",
 					       opt_name);
 					done = TRUE;
 				}
@@ -1120,7 +1120,7 @@
 	ahc_set_unit(ahc, ahc_linux_unit++);
 	ahc_unlock(ahc, &s);
 	sprintf(buf, "scsi%d", host->host_no);
-	new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+	new_name = kmalloc(strlen(buf) + 1, GFP_ATOMIC);
 	if (new_name != NULL) {
 		strcpy(new_name, buf);
 		ahc_set_name(ahc, new_name);
@@ -1220,7 +1220,7 @@
 {
 
 	ahc->platform_data =
-	    malloc(sizeof(struct ahc_platform_data), M_DEVBUF, M_NOWAIT);
+	    kmalloc(sizeof(struct ahc_platform_data), GFP_ATOMIC);
 	if (ahc->platform_data == NULL)
 		return (ENOMEM);
 	memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data));
@@ -1264,7 +1264,7 @@
 		if (ahc->platform_data->host)
 			scsi_host_put(ahc->platform_data->host);
 
-		free(ahc->platform_data, M_DEVBUF);
+		kfree(ahc->platform_data);
 	}
 }
 
@@ -1378,7 +1378,7 @@
 		if (ahc->unit >= ARRAY_SIZE(aic7xxx_tag_info)) {
 			if (warned_user == 0) {
 
-				printf(KERN_WARNING
+				printk(KERN_WARNING
 "aic7xxx: WARNING: Insufficient tag_info instances\n"
 "aic7xxx: for installed controllers. Using defaults\n"
 "aic7xxx: Please update the aic7xxx_tag_info array in\n"
@@ -1421,7 +1421,7 @@
 		ahc_send_async(ahc, devinfo.channel, devinfo.target,
 			       devinfo.lun, AC_TRANSFER_NEG);
 		ahc_print_devinfo(ahc, &devinfo);
-		printf("Tagged Queuing enabled.  Depth %d\n", tags);
+		printk("Tagged Queuing enabled.  Depth %d\n", tags);
 	} else {
 		ahc_platform_set_tags(ahc, sdev, &devinfo, AHC_QUEUE_NONE);
 		ahc_send_async(ahc, devinfo.channel, devinfo.target,
@@ -1735,7 +1735,7 @@
 		 * not have been dispatched to the controller, so
 		 * only check the SCB_ACTIVE flag for tagged transactions.
 		 */
-		printf("SCB %d done'd twice\n", scb->hscb->tag);
+		printk("SCB %d done'd twice\n", scb->hscb->tag);
 		ahc_dump_card_state(ahc);
 		panic("Stopping for safety");
 	}
@@ -1765,7 +1765,7 @@
 #ifdef AHC_DEBUG
 			if ((ahc_debug & AHC_SHOW_MISC) != 0) {
 				ahc_print_path(ahc, scb);
-				printf("Set CAM_UNCOR_PARITY\n");
+				printk("Set CAM_UNCOR_PARITY\n");
 			}
 #endif
 			ahc_set_transaction_status(scb, CAM_UNCOR_PARITY);
@@ -1783,12 +1783,12 @@
 			u_int i;
 
 			ahc_print_path(ahc, scb);
-			printf("CDB:");
+			printk("CDB:");
 			for (i = 0; i < scb->io_ctx->cmd_len; i++)
-				printf(" 0x%x", scb->io_ctx->cmnd[i]);
-			printf("\n");
+				printk(" 0x%x", scb->io_ctx->cmnd[i]);
+			printk("\n");
 			ahc_print_path(ahc, scb);
-			printf("Saw underflow (%ld of %ld bytes). "
+			printk("Saw underflow (%ld of %ld bytes). "
 			       "Treated as error\n",
 				ahc_get_residual(scb),
 				ahc_get_transfer_length(scb));
@@ -1821,7 +1821,7 @@
 		dev->commands_since_idle_or_otag = 0;
 
 	if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
-		printf("Recovery SCB completes\n");
+		printk("Recovery SCB completes\n");
 		if (ahc_get_transaction_status(scb) == CAM_BDR_SENT
 		 || ahc_get_transaction_status(scb) == CAM_REQ_ABORTED)
 			ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT);
@@ -1886,14 +1886,14 @@
 			if (ahc_debug & AHC_SHOW_SENSE) {
 				int i;
 
-				printf("Copied %d bytes of sense data:",
+				printk("Copied %d bytes of sense data:",
 				       sense_size);
 				for (i = 0; i < sense_size; i++) {
 					if ((i & 0xF) == 0)
-						printf("\n");
-					printf("0x%x ", cmd->sense_buffer[i]);
+						printk("\n");
+					printk("0x%x ", cmd->sense_buffer[i]);
 				}
-				printf("\n");
+				printk("\n");
 			}
 #endif
 		}
@@ -1918,7 +1918,7 @@
 			dev->openings = 0;
 /*
 			ahc_print_path(ahc, scb);
-			printf("Dropping tag count to %d\n", dev->active);
+			printk("Dropping tag count to %d\n", dev->active);
  */
 			if (dev->active == dev->tags_on_last_queuefull) {
 
@@ -1935,7 +1935,7 @@
 				 == AHC_LOCK_TAGS_COUNT) {
 					dev->maxtags = dev->active;
 					ahc_print_path(ahc, scb);
-					printf("Locking max tag count at %d\n",
+					printk("Locking max tag count at %d\n",
 					       dev->active);
 				}
 			} else {
@@ -2100,10 +2100,10 @@
 	scmd_printk(KERN_INFO, cmd, "Attempting to queue a%s message\n",
 	       flag == SCB_ABORT ? "n ABORT" : " TARGET RESET");
 
-	printf("CDB:");
+	printk("CDB:");
 	for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
-		printf(" 0x%x", cmd->cmnd[cdb_byte]);
-	printf("\n");
+		printk(" 0x%x", cmd->cmnd[cdb_byte]);
+	printk("\n");
 
 	ahc_lock(ahc, &flags);
 
@@ -2121,7 +2121,7 @@
 		 * No target device for this command exists,
 		 * so we must not still own the command.
 		 */
-		printf("%s:%d:%d:%d: Is not an active device\n",
+		printk("%s:%d:%d:%d: Is not an active device\n",
 		       ahc_name(ahc), cmd->device->channel, cmd->device->id,
 		       cmd->device->lun);
 		retval = SUCCESS;
@@ -2133,7 +2133,7 @@
 				       cmd->device->channel + 'A',
 				       cmd->device->lun,
 				       CAM_REQ_ABORTED, SEARCH_COMPLETE) != 0) {
-		printf("%s:%d:%d:%d: Command found on untagged queue\n",
+		printk("%s:%d:%d:%d: Command found on untagged queue\n",
 		       ahc_name(ahc), cmd->device->channel, cmd->device->id,
 		       cmd->device->lun);
 		retval = SUCCESS;
@@ -2187,7 +2187,7 @@
 		goto no_cmd;
 	}
 
-	printf("%s: At time of recovery, card was %spaused\n",
+	printk("%s: At time of recovery, card was %spaused\n",
 	       ahc_name(ahc), was_paused ? "" : "not ");
 	ahc_dump_card_state(ahc);
 
@@ -2199,7 +2199,7 @@
 				       pending_scb->hscb->tag,
 				       ROLE_INITIATOR, CAM_REQ_ABORTED,
 				       SEARCH_COMPLETE) > 0) {
-			printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
+			printk("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
 			       ahc_name(ahc), cmd->device->channel,
 					cmd->device->id, cmd->device->lun);
 			retval = SUCCESS;
@@ -2313,7 +2313,7 @@
 		ahc_qinfifo_requeue_tail(ahc, pending_scb);
 		ahc_outb(ahc, SCBPTR, saved_scbptr);
 		ahc_print_path(ahc, pending_scb);
-		printf("Device is disconnected, re-queuing SCB\n");
+		printk("Device is disconnected, re-queuing SCB\n");
 		wait = TRUE;
 	} else {
 		scmd_printk(KERN_INFO, cmd, "Unable to deliver message\n");
@@ -2338,16 +2338,16 @@
 		ahc->platform_data->eh_done = &done;
 		ahc_unlock(ahc, &flags);
 
-		printf("Recovery code sleeping\n");
+		printk("Recovery code sleeping\n");
 		if (!wait_for_completion_timeout(&done, 5 * HZ)) {
 			ahc_lock(ahc, &flags);
 			ahc->platform_data->eh_done = NULL;
 			ahc_unlock(ahc, &flags);
 
-			printf("Timer Expired\n");
+			printk("Timer Expired\n");
 			retval = FAILED;
 		}
-		printf("Recovery code awake\n");
+		printk("Recovery code awake\n");
 	} else
 		ahc_unlock(ahc, &flags);
 	return (retval);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index 56f07e5..bca0fb83 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -368,13 +368,6 @@
 	resource_size_t 	 mem_busaddr;	/* Mem Base Addr */
 };
 
-/************************** OS Utility Wrappers *******************************/
-#define printf printk
-#define M_NOWAIT GFP_ATOMIC
-#define M_WAITOK 0
-#define malloc(size, type, flags) kmalloc(size, flags)
-#define free(ptr, type) kfree(ptr)
-
 void ahc_delay(long);
 
 
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index 78fc70c..ee05e84 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -225,7 +225,7 @@
 		ahc_get_pci_bus(pci),
 		ahc_get_pci_slot(pci),
 		ahc_get_pci_function(pci));
-	name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+	name = kmalloc(strlen(buf) + 1, GFP_ATOMIC);
 	if (name == NULL)
 		return (-ENOMEM);
 	strcpy(name, buf);
@@ -412,7 +412,7 @@
 		 */
 		if (ahc_pci_test_register_access(ahc) != 0) {
 
-			printf("aic7xxx: PCI Device %d:%d:%d "
+			printk("aic7xxx: PCI Device %d:%d:%d "
 			       "failed memory mapped test.  Using PIO.\n",
 			       ahc_get_pci_bus(ahc->dev_softc),
 			       ahc_get_pci_slot(ahc->dev_softc),
@@ -425,7 +425,7 @@
 		} else
 			command |= PCIM_CMD_MEMEN;
 	} else {
-		printf("aic7xxx: PCI%d:%d:%d MEM region 0x%llx "
+		printk("aic7xxx: PCI%d:%d:%d MEM region 0x%llx "
 		       "unavailable. Cannot memory map device.\n",
 		       ahc_get_pci_bus(ahc->dev_softc),
 		       ahc_get_pci_slot(ahc->dev_softc),
@@ -444,7 +444,7 @@
 			ahc->bsh.ioport = (u_long)base;
 			command |= PCIM_CMD_PORTEN;
 		} else {
-			printf("aic7xxx: PCI%d:%d:%d IO region 0x%llx[0..255] "
+			printk("aic7xxx: PCI%d:%d:%d IO region 0x%llx[0..255] "
 			       "unavailable. Cannot map device.\n",
 			       ahc_get_pci_bus(ahc->dev_softc),
 			       ahc_get_pci_slot(ahc->dev_softc),
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index 27014b9..2b11a42 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -752,7 +752,7 @@
 	if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
 
 		if (bootverbose)
-			printf("%s: Enabling 39Bit Addressing\n",
+			printk("%s: Enabling 39Bit Addressing\n",
 			       ahc_name(ahc));
 		devconfig |= DACEN;
 	}
@@ -896,7 +896,7 @@
 		/* See if someone else set us up already */
 		if ((ahc->flags & AHC_NO_BIOS_INIT) == 0
 		 && scsiseq != 0) {
-			printf("%s: Using left over BIOS settings\n",
+			printk("%s: Using left over BIOS settings\n",
 				ahc_name(ahc));
 			ahc->flags &= ~AHC_USEDEFAULTS;
 			ahc->flags |= AHC_BIOS_ENABLED;
@@ -1155,7 +1155,7 @@
 	ahc_outb(ahc, CLRINT, CLRPARERR);
 	ahc_outb(ahc, CLRINT, CLRBRKADRINT);
 	if (bootverbose && enable) {
-		printf("%s: External SRAM, %s access%s, %dbytes/SCB\n",
+		printk("%s: External SRAM, %s access%s, %dbytes/SCB\n",
 		       ahc_name(ahc), fast ? "fast" : "slow", 
 		       pcheck ? ", parity checking enabled" : "",
 		       large ? 64 : 32);
@@ -1292,7 +1292,7 @@
 	if (have_seeprom) {
 
 		if (bootverbose) 
-			printf("%s: Reading SEEPROM...", ahc_name(ahc));
+			printk("%s: Reading SEEPROM...", ahc_name(ahc));
 
 		for (;;) {
 			u_int start_addr;
@@ -1309,9 +1309,9 @@
 			if (have_seeprom != 0 || sd.sd_chip == C56_66) {
 				if (bootverbose) {
 					if (have_seeprom == 0)
-						printf ("checksum error\n");
+						printk ("checksum error\n");
 					else
-						printf ("done.\n");
+						printk ("done.\n");
 				}
 				break;
 			}
@@ -1362,9 +1362,9 @@
 
 	if (!have_seeprom) {
 		if (bootverbose)
-			printf("%s: No SEEPROM available.\n", ahc_name(ahc));
+			printk("%s: No SEEPROM available.\n", ahc_name(ahc));
 		ahc->flags |= AHC_USEDEFAULTS;
-		free(ahc->seep_config, M_DEVBUF);
+		kfree(ahc->seep_config);
 		ahc->seep_config = NULL;
 		sc = NULL;
 	} else {
@@ -1399,7 +1399,7 @@
 		if ((sc->adapter_control & CFSTERM) != 0)
 			*sxfrctl1 |= STPWEN;
 		if (bootverbose)
-			printf("%s: Low byte termination %sabled\n",
+			printk("%s: Low byte termination %sabled\n",
 			       ahc_name(ahc),
 			       (*sxfrctl1 & STPWEN) ? "en" : "dis");
 	}
@@ -1569,7 +1569,7 @@
 					    &eeprom_present);
 			if ((adapter_control & CFSEAUTOTERM) == 0) {
 				if (bootverbose)
-					printf("%s: Manual SE Termination\n",
+					printk("%s: Manual SE Termination\n",
 					       ahc_name(ahc));
 				enableSEC_low = (adapter_control & CFSELOWTERM);
 				enableSEC_high =
@@ -1577,7 +1577,7 @@
 			}
 			if ((adapter_control & CFAUTOTERM) == 0) {
 				if (bootverbose)
-					printf("%s: Manual LVD Termination\n",
+					printk("%s: Manual LVD Termination\n",
 					       ahc_name(ahc));
 				enablePRI_low = (adapter_control & CFSTERM);
 				enablePRI_high = (adapter_control & CFWSTERM);
@@ -1604,19 +1604,19 @@
 
 		if (bootverbose
 		 && (ahc->features & AHC_ULTRA2) == 0) {
-			printf("%s: internal 50 cable %s present",
+			printk("%s: internal 50 cable %s present",
 			       ahc_name(ahc),
 			       internal50_present ? "is":"not");
 
 			if ((ahc->features & AHC_WIDE) != 0)
-				printf(", internal 68 cable %s present",
+				printk(", internal 68 cable %s present",
 				       internal68_present ? "is":"not");
-			printf("\n%s: external cable %s present\n",
+			printk("\n%s: external cable %s present\n",
 			       ahc_name(ahc),
 			       externalcable_present ? "is":"not");
 		}
 		if (bootverbose)
-			printf("%s: BIOS eeprom %s present\n",
+			printk("%s: BIOS eeprom %s present\n",
 			       ahc_name(ahc), eeprom_present ? "is" : "not");
 
 		if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) {
@@ -1642,7 +1642,7 @@
 		 && (internal50_present != 0)
 		 && (internal68_present != 0)
 		 && (externalcable_present != 0)) {
-			printf("%s: Illegal cable configuration!!. "
+			printk("%s: Illegal cable configuration!!. "
 			       "Only two connectors on the "
 			       "adapter may be used at a "
 			       "time!\n", ahc_name(ahc));
@@ -1664,10 +1664,10 @@
 			brddat |= BRDDAT6;
 			if (bootverbose) {
 				if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
-					printf("%s: 68 pin termination "
+					printk("%s: 68 pin termination "
 					       "Enabled\n", ahc_name(ahc));
 				else
-					printf("%s: %sHigh byte termination "
+					printk("%s: %sHigh byte termination "
 					       "Enabled\n", ahc_name(ahc),
 					       enableSEC_high ? "Secondary "
 							      : "");
@@ -1683,10 +1683,10 @@
 				*sxfrctl1 |= STPWEN;
 			if (bootverbose) {
 				if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
-					printf("%s: 50 pin termination "
+					printk("%s: 50 pin termination "
 					       "Enabled\n", ahc_name(ahc));
 				else
-					printf("%s: %sLow byte termination "
+					printk("%s: %sLow byte termination "
 					       "Enabled\n", ahc_name(ahc),
 					       enableSEC_low ? "Secondary "
 							     : "");
@@ -1696,7 +1696,7 @@
 		if (enablePRI_low != 0) {
 			*sxfrctl1 |= STPWEN;
 			if (bootverbose)
-				printf("%s: Primary Low Byte termination "
+				printk("%s: Primary Low Byte termination "
 				       "Enabled\n", ahc_name(ahc));
 		}
 
@@ -1709,7 +1709,7 @@
 		if (enablePRI_high != 0) {
 			brddat |= BRDDAT4;
 			if (bootverbose)
-				printf("%s: Primary High Byte "
+				printk("%s: Primary High Byte "
 				       "termination Enabled\n",
 				       ahc_name(ahc));
 		}
@@ -1721,7 +1721,7 @@
 			*sxfrctl1 |= STPWEN;
 
 			if (bootverbose)
-				printf("%s: %sLow byte termination Enabled\n",
+				printk("%s: %sLow byte termination Enabled\n",
 				       ahc_name(ahc),
 				       (ahc->features & AHC_ULTRA2) ? "Primary "
 								    : "");
@@ -1731,7 +1731,7 @@
 		 && (ahc->features & AHC_WIDE) != 0) {
 			brddat |= BRDDAT6;
 			if (bootverbose)
-				printf("%s: %sHigh byte termination Enabled\n",
+				printk("%s: %sHigh byte termination Enabled\n",
 				       ahc_name(ahc),
 				       (ahc->features & AHC_ULTRA2)
 				     ? "Secondary " : "");
@@ -1937,29 +1937,29 @@
 	status1 = ahc_pci_read_config(ahc->dev_softc,
 				      PCIR_STATUS + 1, /*bytes*/1);
 
-	printf("%s: PCI error Interrupt at seqaddr = 0x%x\n",
+	printk("%s: PCI error Interrupt at seqaddr = 0x%x\n",
 	      ahc_name(ahc),
 	      ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
 
 	if (status1 & DPE) {
 		ahc->pci_target_perr_count++;
-		printf("%s: Data Parity Error Detected during address "
+		printk("%s: Data Parity Error Detected during address "
 		       "or write data phase\n", ahc_name(ahc));
 	}
 	if (status1 & SSE) {
-		printf("%s: Signal System Error Detected\n", ahc_name(ahc));
+		printk("%s: Signal System Error Detected\n", ahc_name(ahc));
 	}
 	if (status1 & RMA) {
-		printf("%s: Received a Master Abort\n", ahc_name(ahc));
+		printk("%s: Received a Master Abort\n", ahc_name(ahc));
 	}
 	if (status1 & RTA) {
-		printf("%s: Received a Target Abort\n", ahc_name(ahc));
+		printk("%s: Received a Target Abort\n", ahc_name(ahc));
 	}
 	if (status1 & STA) {
-		printf("%s: Signaled a Target Abort\n", ahc_name(ahc));
+		printk("%s: Signaled a Target Abort\n", ahc_name(ahc));
 	}
 	if (status1 & DPR) {
-		printf("%s: Data Parity Error has been reported via PERR#\n",
+		printk("%s: Data Parity Error has been reported via PERR#\n",
 		       ahc_name(ahc));
 	}
 
@@ -1968,14 +1968,14 @@
 			     status1, /*bytes*/1);
 
 	if ((status1 & (DPE|SSE|RMA|RTA|STA|DPR)) == 0) {
-		printf("%s: Latched PCIERR interrupt with "
+		printk("%s: Latched PCIERR interrupt with "
 		       "no status bits set\n", ahc_name(ahc)); 
 	} else {
 		ahc_outb(ahc, CLRINT, CLRPARERR);
 	}
 
 	if (ahc->pci_target_perr_count > AHC_PCI_TARGET_PERR_THRESH) {
-		printf(
+		printk(
 "%s: WARNING WARNING WARNING WARNING\n"
 "%s: Too many PCI parity errors observed as a target.\n"
 "%s: Some device on this bus is generating bad parity.\n"
@@ -2386,7 +2386,7 @@
 static int
 ahc_raid_setup(struct ahc_softc *ahc)
 {
-	printf("RAID functionality unsupported\n");
+	printk("RAID functionality unsupported\n");
 	return (ENXIO);
 }
 
@@ -2404,7 +2404,7 @@
 		ahc->channel = 'B';
 		break;
 	default:
-		printf("adapter at unexpected slot %d\n"
+		printk("adapter at unexpected slot %d\n"
 		       "unable to map to a channel\n",
 		       ahc_get_pci_slot(pci));
 		ahc->channel = 'A';
@@ -2429,7 +2429,7 @@
 		ahc->channel = 'C';
 		break;
 	default:
-		printf("adapter at unexpected slot %d\n"
+		printk("adapter at unexpected slot %d\n"
 		       "unable to map to a channel\n",
 		       ahc_get_pci_slot(pci));
 		ahc->channel = 'A';
@@ -2459,7 +2459,7 @@
 		ahc->channel = 'D';
 		break;
 	default:
-		printf("adapter at unexpected slot %d\n"
+		printk("adapter at unexpected slot %d\n"
 		       "unable to map to a channel\n",
 		       ahc_get_pci_slot(pci));
 		ahc->channel = 'A';
diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c
index e92991a..f2525f8 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c
@@ -248,13 +248,13 @@
 		ahc_pause(ahc);
 
 	if (length != sizeof(struct seeprom_config)) {
-		printf("ahc_proc_write_seeprom: incorrect buffer size\n");
+		printk("ahc_proc_write_seeprom: incorrect buffer size\n");
 		goto done;
 	}
 
 	have_seeprom = ahc_verify_cksum((struct seeprom_config*)buffer);
 	if (have_seeprom == 0) {
-		printf("ahc_proc_write_seeprom: cksum verification failed\n");
+		printk("ahc_proc_write_seeprom: cksum verification failed\n");
 		goto done;
 	}
 
@@ -290,26 +290,25 @@
 		sd.sd_DI = DI_2840;
 		have_seeprom = TRUE;
 	} else {
-		printf("ahc_proc_write_seeprom: unsupported adapter type\n");
+		printk("ahc_proc_write_seeprom: unsupported adapter type\n");
 		goto done;
 	}
 
 	if (!have_seeprom) {
-		printf("ahc_proc_write_seeprom: No Serial EEPROM\n");
+		printk("ahc_proc_write_seeprom: No Serial EEPROM\n");
 		goto done;
 	} else {
 		u_int start_addr;
 
 		if (ahc->seep_config == NULL) {
-			ahc->seep_config = malloc(sizeof(*ahc->seep_config),
-						  M_DEVBUF, M_NOWAIT);
+			ahc->seep_config = kmalloc(sizeof(*ahc->seep_config), GFP_ATOMIC);
 			if (ahc->seep_config == NULL) {
-				printf("aic7xxx: Unable to allocate serial "
+				printk("aic7xxx: Unable to allocate serial "
 				       "eeprom buffer.  Write failing\n");
 				goto done;
 			}
 		}
-		printf("aic7xxx: Writing Serial EEPROM\n");
+		printk("aic7xxx: Writing Serial EEPROM\n");
 		start_addr = 32 * (ahc->channel - 'A');
 		ahc_write_seeprom(&sd, (u_int16_t *)buffer, start_addr,
 				  sizeof(struct seeprom_config)/2);
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index 75d20f7..532d212 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -223,7 +223,7 @@
 	switch (opcode) {
 	case TC_NO_ERROR:
 		ts->resp = SAS_TASK_COMPLETE;
-		ts->stat = SAM_GOOD;
+		ts->stat = SAM_STAT_GOOD;
 		break;
 	case TC_UNDERRUN:
 		ts->resp = SAS_TASK_COMPLETE;
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index ce5371b..475c31a 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -43,21 +43,27 @@
 *******************************************************************************
 */
 #include <linux/interrupt.h>
-
 struct device_attribute;
 /*The limit of outstanding scsi command that firmware can handle*/
 #define ARCMSR_MAX_OUTSTANDING_CMD						256
 #define ARCMSR_MAX_FREECCB_NUM							320
-#define ARCMSR_DRIVER_VERSION		     "Driver Version 1.20.00.15 2008/11/03"
+#define ARCMSR_DRIVER_VERSION		     "Driver Version 1.20.00.15 2010/02/02"
 #define ARCMSR_SCSI_INITIATOR_ID						255
 #define ARCMSR_MAX_XFER_SECTORS							512
 #define ARCMSR_MAX_XFER_SECTORS_B						4096
+#define ARCMSR_MAX_XFER_SECTORS_C						304
 #define ARCMSR_MAX_TARGETID							17
 #define ARCMSR_MAX_TARGETLUN							8
 #define ARCMSR_MAX_CMD_PERLUN		                 ARCMSR_MAX_OUTSTANDING_CMD
 #define ARCMSR_MAX_QBUFFER							4096
-#define ARCMSR_MAX_SG_ENTRIES							38
+#define ARCMSR_DEFAULT_SG_ENTRIES						38
 #define ARCMSR_MAX_HBB_POSTQUEUE						264
+#define ARCMSR_MAX_XFER_LEN							0x26000 /* 152K */
+#define ARCMSR_CDB_SG_PAGE_LENGTH						256 
+#define SCSI_CMD_ARECA_SPECIFIC						0xE1
+#ifndef PCI_DEVICE_ID_ARECA_1880
+#define PCI_DEVICE_ID_ARECA_1880 0x1880
+ #endif
 /*
 **********************************************************************************
 **
@@ -132,35 +138,28 @@
 #define ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE \
 	ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE
 /* ARECA IOCTL ReturnCode */
-#define ARCMSR_MESSAGE_RETURNCODE_OK              0x00000001
-#define ARCMSR_MESSAGE_RETURNCODE_ERROR           0x00000006
-#define ARCMSR_MESSAGE_RETURNCODE_3F              0x0000003F
+#define ARCMSR_MESSAGE_RETURNCODE_OK		0x00000001
+#define ARCMSR_MESSAGE_RETURNCODE_ERROR		0x00000006
+#define ARCMSR_MESSAGE_RETURNCODE_3F		0x0000003F
 #define ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON	0x00000088
 /*
 *************************************************************
 **   structure for holding DMA address data
 *************************************************************
 */
+#define IS_DMA64			(sizeof(dma_addr_t) == 8)
 #define IS_SG64_ADDR                0x01000000 /* bit24 */
 struct  SG32ENTRY
 {
 	__le32					length;
 	__le32					address;
-};
+}__attribute__ ((packed));
 struct  SG64ENTRY
 {
 	__le32					length;
 	__le32					address;
 	__le32					addresshigh;
-};
-struct SGENTRY_UNION
-{
-	union
-	{
-		struct SG32ENTRY            sg32entry;
-		struct SG64ENTRY            sg64entry;
-	}u;
-};
+}__attribute__ ((packed));
 /*
 ********************************************************************
 **      Q Buffer of IOP Message Transfer
@@ -187,6 +186,9 @@
 	char          model[8];			/*15, 60-67*/
 	char          firmware_ver[16];     	/*17, 68-83*/
 	char          device_map[16];		/*21, 84-99*/
+	uint32_t		cfgVersion;               	/*25,100-103 Added for checking of new firmware capability*/
+	uint8_t		cfgSerial[16];           	/*26,104-119*/
+	uint32_t		cfgPicStatus;            	/*30,120-123*/	
 };
 /* signature of set and get firmware config */
 #define ARCMSR_SIGNATURE_GET_CONFIG		      0x87974060
@@ -210,9 +212,15 @@
 #define ARCMSR_CCBPOST_FLAG_SGL_BSIZE                 0x80000000
 #define ARCMSR_CCBPOST_FLAG_IAM_BIOS                  0x40000000
 #define ARCMSR_CCBREPLY_FLAG_IAM_BIOS                 0x40000000
-#define ARCMSR_CCBREPLY_FLAG_ERROR                    0x10000000
+#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE0              0x10000000
+#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE1              0x00000001
 /* outbound firmware ok */
 #define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK             0x80000000
+/* ARC-1680 Bus Reset*/
+#define ARCMSR_ARC1680_BUS_RESET				0x00000003
+/* ARC-1880 Bus Reset*/
+#define ARCMSR_ARC1880_RESET_ADAPTER				0x00000024
+#define ARCMSR_ARC1880_DiagWrite_ENABLE			0x00000080
 
 /*
 ************************************************************************
@@ -264,11 +272,66 @@
 
 /* data tunnel buffer between user space program and its firmware */
 /* user space data to iop 128bytes */
-#define ARCMSR_IOCTL_WBUFFER			      0x0000fe00
+#define ARCMSR_MESSAGE_WBUFFER			      0x0000fe00
 /* iop data to user space 128bytes */
-#define ARCMSR_IOCTL_RBUFFER			      0x0000ff00
+#define ARCMSR_MESSAGE_RBUFFER			      0x0000ff00
 /* iop message_rwbuffer for message command */
-#define ARCMSR_MSGCODE_RWBUFFER			      0x0000fa00
+#define ARCMSR_MESSAGE_RWBUFFER			      0x0000fa00
+/* 
+************************************************************************
+**                SPEC. for Areca HBC adapter
+************************************************************************
+*/
+#define ARCMSR_HBC_ISR_THROTTLING_LEVEL		12
+#define ARCMSR_HBC_ISR_MAX_DONE_QUEUE		20
+/* Host Interrupt Mask */
+#define ARCMSR_HBCMU_UTILITY_A_ISR_MASK		0x00000001 /* When clear, the Utility_A interrupt routes to the host.*/
+#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK	0x00000004 /* When clear, the General Outbound Doorbell interrupt routes to the host.*/
+#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK	0x00000008 /* When clear, the Outbound Post List FIFO Not Empty interrupt routes to the host.*/
+#define ARCMSR_HBCMU_ALL_INTMASKENABLE		0x0000000D /* disable all ISR */
+/* Host Interrupt Status */
+#define ARCMSR_HBCMU_UTILITY_A_ISR			0x00000001
+	/*
+	** Set when the Utility_A Interrupt bit is set in the Outbound Doorbell Register.
+	** It clears by writing a 1 to the Utility_A bit in the Outbound Doorbell Clear Register or through automatic clearing (if enabled).
+	*/
+#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR		0x00000004
+	/*
+	** Set if Outbound Doorbell register bits 30:1 have a non-zero
+	** value. This bit clears only when Outbound Doorbell bits
+	** 30:1 are ALL clear. Only a write to the Outbound Doorbell
+	** Clear register clears bits in the Outbound Doorbell register.
+	*/
+#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR	0x00000008
+	/*
+	** Set whenever the Outbound Post List Producer/Consumer
+	** Register (FIFO) is not empty. It clears when the Outbound
+	** Post List FIFO is empty.
+	*/
+#define ARCMSR_HBCMU_SAS_ALL_INT			0x00000010
+	/*
+	** This bit indicates a SAS interrupt from a source external to
+	** the PCIe core. This bit is not maskable.
+	*/
+	/* DoorBell*/
+#define ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK			0x00000002
+#define ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK			0x00000004
+	/*inbound message 0 ready*/
+#define ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE		0x00000008
+	/*more than 12 request completed in a time*/
+#define ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING		0x00000010
+#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK			0x00000002
+	/*outbound DATA WRITE isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_DOORBELL_CLEAR	0x00000002
+#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK			0x00000004
+	/*outbound DATA READ isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_DOORBELL_CLEAR	0x00000004
+	/*outbound message 0 ready*/
+#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE		0x00000008
+	/*outbound message cmd isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR	0x00000008
+	/*ARCMSR_HBAMU_MESSAGE_FIRMWARE_OK*/
+#define ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK			0x80000000
 /*
 *******************************************************************************
 **    ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
@@ -290,7 +353,7 @@
 #define ARCMSR_CDB_FLAG_HEADQ              0x08
 #define ARCMSR_CDB_FLAG_ORDEREDQ           0x10
 
-	uint8_t							Reserved1;
+	uint8_t							msgPages;
 	uint32_t						Context;
 	uint32_t						DataLength;
 	uint8_t							Cdb[16];
@@ -303,8 +366,8 @@
 	uint8_t							SenseData[15];
 	union
 	{
-		struct SG32ENTRY                sg32entry[ARCMSR_MAX_SG_ENTRIES];
-		struct SG64ENTRY                sg64entry[ARCMSR_MAX_SG_ENTRIES];
+		struct SG32ENTRY                sg32entry[1];
+		struct SG64ENTRY                sg64entry[1];
 	} u;
 };
 /*
@@ -344,15 +407,89 @@
 	uint32_t	done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
 	uint32_t	postq_index;
 	uint32_t	doneq_index;
-	uint32_t		__iomem *drv2iop_doorbell_reg;
-	uint32_t		__iomem *drv2iop_doorbell_mask_reg;
-	uint32_t		__iomem *iop2drv_doorbell_reg;
-	uint32_t		__iomem *iop2drv_doorbell_mask_reg;
-	uint32_t		__iomem *msgcode_rwbuffer_reg;
-	uint32_t		__iomem *ioctl_wbuffer_reg;
-	uint32_t		__iomem *ioctl_rbuffer_reg;
+	uint32_t		__iomem *drv2iop_doorbell;
+	uint32_t		__iomem *drv2iop_doorbell_mask;
+	uint32_t		__iomem *iop2drv_doorbell;
+	uint32_t		__iomem *iop2drv_doorbell_mask;
+	uint32_t		__iomem *message_rwbuffer;
+	uint32_t		__iomem *message_wbuffer;
+	uint32_t		__iomem *message_rbuffer;
 };
-
+/*
+*********************************************************************
+** LSI
+*********************************************************************
+*/
+struct MessageUnit_C{
+	uint32_t	message_unit_status;			/*0000 0003*/
+	uint32_t	slave_error_attribute;			/*0004 0007*/
+	uint32_t	slave_error_address;			/*0008 000B*/
+	uint32_t	posted_outbound_doorbell;		/*000C 000F*/
+	uint32_t	master_error_attribute;			/*0010 0013*/
+	uint32_t	master_error_address_low;		/*0014 0017*/
+	uint32_t	master_error_address_high;		/*0018 001B*/
+	uint32_t	hcb_size;				/*001C 001F*/
+	uint32_t	inbound_doorbell;			/*0020 0023*/
+	uint32_t	diagnostic_rw_data;			/*0024 0027*/
+	uint32_t	diagnostic_rw_address_low;		/*0028 002B*/
+	uint32_t	diagnostic_rw_address_high;		/*002C 002F*/
+	uint32_t	host_int_status;				/*0030 0033*/
+	uint32_t	host_int_mask;				/*0034 0037*/
+	uint32_t	dcr_data;				/*0038 003B*/
+	uint32_t	dcr_address;				/*003C 003F*/
+	uint32_t	inbound_queueport;			/*0040 0043*/
+	uint32_t	outbound_queueport;			/*0044 0047*/
+	uint32_t	hcb_pci_address_low;			/*0048 004B*/
+	uint32_t	hcb_pci_address_high;			/*004C 004F*/
+	uint32_t	iop_int_status;				/*0050 0053*/
+	uint32_t	iop_int_mask;				/*0054 0057*/
+	uint32_t	iop_inbound_queue_port;			/*0058 005B*/
+	uint32_t	iop_outbound_queue_port;		/*005C 005F*/
+	uint32_t	inbound_free_list_index;			/*0060 0063*/
+	uint32_t	inbound_post_list_index;			/*0064 0067*/
+	uint32_t	outbound_free_list_index;			/*0068 006B*/
+	uint32_t	outbound_post_list_index;			/*006C 006F*/
+	uint32_t	inbound_doorbell_clear;			/*0070 0073*/
+	uint32_t	i2o_message_unit_control;			/*0074 0077*/
+	uint32_t	last_used_message_source_address_low;	/*0078 007B*/
+	uint32_t	last_used_message_source_address_high;	/*007C 007F*/
+	uint32_t	pull_mode_data_byte_count[4];		/*0080 008F*/
+	uint32_t	message_dest_address_index;		/*0090 0093*/
+	uint32_t	done_queue_not_empty_int_counter_timer;	/*0094 0097*/
+	uint32_t	utility_A_int_counter_timer;		/*0098 009B*/
+	uint32_t	outbound_doorbell;			/*009C 009F*/
+	uint32_t	outbound_doorbell_clear;			/*00A0 00A3*/
+	uint32_t	message_source_address_index;		/*00A4 00A7*/
+	uint32_t	message_done_queue_index;		/*00A8 00AB*/
+	uint32_t	reserved0;				/*00AC 00AF*/
+	uint32_t	inbound_msgaddr0;			/*00B0 00B3*/
+	uint32_t	inbound_msgaddr1;			/*00B4 00B7*/
+	uint32_t	outbound_msgaddr0;			/*00B8 00BB*/
+	uint32_t	outbound_msgaddr1;			/*00BC 00BF*/
+	uint32_t	inbound_queueport_low;			/*00C0 00C3*/
+	uint32_t	inbound_queueport_high;			/*00C4 00C7*/
+	uint32_t	outbound_queueport_low;			/*00C8 00CB*/
+	uint32_t	outbound_queueport_high;		/*00CC 00CF*/
+	uint32_t	iop_inbound_queue_port_low;		/*00D0 00D3*/
+	uint32_t	iop_inbound_queue_port_high;		/*00D4 00D7*/
+	uint32_t	iop_outbound_queue_port_low;		/*00D8 00DB*/
+	uint32_t	iop_outbound_queue_port_high;		/*00DC 00DF*/
+	uint32_t	message_dest_queue_port_low;		/*00E0 00E3*/
+	uint32_t	message_dest_queue_port_high;		/*00E4 00E7*/
+	uint32_t	last_used_message_dest_address_low;	/*00E8 00EB*/
+	uint32_t	last_used_message_dest_address_high;	/*00EC 00EF*/
+	uint32_t	message_done_queue_base_address_low;	/*00F0 00F3*/
+	uint32_t	message_done_queue_base_address_high;	/*00F4 00F7*/
+	uint32_t	host_diagnostic;				/*00F8 00FB*/
+	uint32_t	write_sequence;				/*00FC 00FF*/
+	uint32_t	reserved1[34];				/*0100 0187*/
+	uint32_t	reserved2[1950];				/*0188 1FFF*/
+	uint32_t	message_wbuffer[32];			/*2000 207F*/
+	uint32_t	reserved3[32];				/*2080 20FF*/
+	uint32_t	message_rbuffer[32];			/*2100 217F*/
+	uint32_t	reserved4[32];				/*2180 21FF*/
+	uint32_t	msgcode_rwbuffer[256];			/*2200 23FF*/
+};
 /*
 *******************************************************************************
 **                 Adapter Control Block
@@ -370,14 +507,20 @@
 	unsigned long			vir2phy_offset;
 	/* Offset is used in making arc cdb physical to virtual calculations */
 	uint32_t			outbound_int_enable;
-
+	uint32_t			cdb_phyaddr_hi32;
+	uint32_t			reg_mu_acc_handle0;
+	spinlock_t                      			eh_lock;
+	spinlock_t                      			ccblist_lock;
 	union {
-		struct MessageUnit_A __iomem *	pmuA;
-		struct MessageUnit_B *		pmuB;
+		struct MessageUnit_A __iomem *pmuA;
+		struct MessageUnit_B 	*pmuB;
+		struct MessageUnit_C __iomem *pmuC;
 	};
 	/* message unit ATU inbound base address0 */
-
+	void __iomem *mem_base0;
+	void __iomem *mem_base1;
 	uint32_t			acb_flags;
+	u16			dev_id;
 	uint8_t                   		adapter_index;
 	#define ACB_F_SCSISTOPADAPTER         	0x0001
 	#define ACB_F_MSG_STOP_BGRB     	0x0002
@@ -392,8 +535,11 @@
 	/* message clear rqbuffer */
 	#define ACB_F_MESSAGE_WQBUFFER_READED   0x0040
 	#define ACB_F_BUS_RESET               	0x0080
+	#define ACB_F_BUS_HANG_ON		0x0800/* need hardware reset bus */
+
 	#define ACB_F_IOP_INITED              	0x0100
 	/* iop init */
+	#define ACB_F_ABORT				0x0200
 	#define ACB_F_FIRMWARE_TRAP           		0x0400
 	struct CommandControlBlock *			pccb_pool[ARCMSR_MAX_FREECCB_NUM];
 	/* used for memory free */
@@ -408,7 +554,8 @@
 	/* dma_coherent used for memory free */
 	dma_addr_t			dma_coherent_handle;
 	/* dma_coherent_handle used for memory free */
-
+	dma_addr_t				dma_coherent_handle_hbb_mu;
+	unsigned int				uncache_size;
 	uint8_t				rqbuffer[ARCMSR_MAX_QBUFFER];
 	/* data collection buffer for read from 80331 */
 	int32_t				rqbuf_firstindex;
@@ -432,14 +579,18 @@
 	uint32_t			firm_numbers_queue;
 	uint32_t			firm_sdram_size;
 	uint32_t			firm_hd_channels;
-	char				firm_model[12];
-	char				firm_version[20];
+	uint32_t                           	firm_cfg_version;	
+	char			firm_model[12];
+	char			firm_version[20];
 	char			device_map[20];			/*21,84-99*/
 	struct work_struct 		arcmsr_do_message_isr_bh;
 	struct timer_list		eternal_timer;
-	unsigned short		fw_state;
+	unsigned short		fw_flag;
+				#define	FW_NORMAL	0x0000
+				#define	FW_BOG		0x0001
+				#define	FW_DEADLOCK	0x0010
 	atomic_t 			rq_map_token;
-	int			ante_token_value;
+	atomic_t			ante_token_value;
 };/* HW_DEVICE_EXTENSION */
 /*
 *******************************************************************************
@@ -447,67 +598,33 @@
 **             this CCB length must be 32 bytes boundary
 *******************************************************************************
 */
-struct CommandControlBlock
-{
-	struct ARCMSR_CDB		arcmsr_cdb;
-	/*
-	** 0-503 (size of CDB = 504):
-	** arcmsr messenger scsi command descriptor size 504 bytes
-	*/
-	uint32_t			cdb_shifted_phyaddr;
-	/* 504-507 */
-	uint32_t			reserved1;
-	/* 508-511 */
-#if BITS_PER_LONG == 64
+struct CommandControlBlock{
+	/*x32:sizeof struct_CCB=(32+60)byte, x64:sizeof struct_CCB=(64+60)byte*/
+	struct list_head		list;				/*x32: 8byte, x64: 16byte*/
+	struct scsi_cmnd		*pcmd;				/*8 bytes pointer of linux scsi command */
+	struct AdapterControlBlock	*acb;				/*x32: 4byte, x64: 8byte*/
+	uint32_t			cdb_phyaddr_pattern;		/*x32: 4byte, x64: 4byte*/
+	uint32_t			arc_cdb_size;			/*x32:4byte,x64:4byte*/
+	uint16_t			ccb_flags;			/*x32: 2byte, x64: 2byte*/
+	#define			CCB_FLAG_READ			0x0000
+	#define			CCB_FLAG_WRITE		0x0001
+	#define			CCB_FLAG_ERROR		0x0002
+	#define			CCB_FLAG_FLUSHCACHE		0x0004
+	#define			CCB_FLAG_MASTER_ABORTED	0x0008	
+	uint16_t                        	startdone;			/*x32:2byte,x32:2byte*/
+	#define			ARCMSR_CCB_DONE   	        	0x0000
+	#define			ARCMSR_CCB_START		0x55AA
+	#define			ARCMSR_CCB_ABORTED		0xAA55
+	#define			ARCMSR_CCB_ILLEGAL		0xFFFF
+	#if BITS_PER_LONG == 64
 	/*  ======================512+64 bytes========================  */
-	struct list_head		list;
-	/* 512-527 16 bytes next/prev ptrs for ccb lists */
-	struct scsi_cmnd *		pcmd;
-	/* 528-535 8 bytes pointer of linux scsi command */
-	struct AdapterControlBlock *	acb;
-	/* 536-543 8 bytes pointer of acb */
-
-	uint16_t			ccb_flags;
-	/* 544-545 */
-	#define		CCB_FLAG_READ			0x0000
-	#define		CCB_FLAG_WRITE			0x0001
-	#define		CCB_FLAG_ERROR			0x0002
-	#define		CCB_FLAG_FLUSHCACHE		0x0004
-	#define		CCB_FLAG_MASTER_ABORTED		0x0008
-	uint16_t			startdone;
-	/* 546-547 */
-	#define		ARCMSR_CCB_DONE			0x0000
-	#define		ARCMSR_CCB_START		0x55AA
-	#define		ARCMSR_CCB_ABORTED		0xAA55
-	#define		ARCMSR_CCB_ILLEGAL		0xFFFF
-	uint32_t			reserved2[7];
-	/* 548-551 552-555 556-559 560-563 564-567 568-571 572-575 */
-#else
+		uint32_t                        	reserved[5];		/*24 byte*/
+	#else
 	/*  ======================512+32 bytes========================  */
-	struct list_head		list;
-	/* 512-519 8 bytes next/prev ptrs for ccb lists */
-	struct scsi_cmnd *		pcmd;
-	/* 520-523 4 bytes pointer of linux scsi command */
-	struct AdapterControlBlock *	acb;
-	/* 524-527 4 bytes pointer of acb */
-
-	uint16_t			ccb_flags;
-	/* 528-529 */
-	#define		CCB_FLAG_READ			0x0000
-	#define		CCB_FLAG_WRITE			0x0001
-	#define		CCB_FLAG_ERROR			0x0002
-	#define		CCB_FLAG_FLUSHCACHE		0x0004
-	#define		CCB_FLAG_MASTER_ABORTED		0x0008
-	uint16_t			startdone;
-	/* 530-531 */
-	#define		ARCMSR_CCB_DONE			0x0000
-	#define		ARCMSR_CCB_START		0x55AA
-	#define		ARCMSR_CCB_ABORTED		0xAA55
-	#define		ARCMSR_CCB_ILLEGAL		0xFFFF
-	uint32_t			reserved2[3];
-	/* 532-535 536-539 540-543 */
-#endif
-	/*  ==========================================================  */
+		uint32_t                        	reserved;		/*8  byte*/
+	#endif
+	/*  =======================================================   */
+	struct ARCMSR_CDB		arcmsr_cdb;
 };
 /*
 *******************************************************************************
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index ffa5479..95a895d 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -58,7 +58,6 @@
 #include <linux/timer.h>
 #include <linux/pci.h>
 #include <linux/aer.h>
-#include <linux/slab.h>
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
@@ -71,20 +70,13 @@
 #include <scsi/scsi_transport.h>
 #include <scsi/scsicam.h>
 #include "arcmsr.h"
-
-#ifdef CONFIG_SCSI_ARCMSR_RESET
-	static int sleeptime = 20;
-	static int retrycount = 12;
-	module_param(sleeptime, int, S_IRUGO|S_IWUSR);
-	MODULE_PARM_DESC(sleeptime, "The waiting period for FW ready while bus reset");
-	module_param(retrycount, int, S_IRUGO|S_IWUSR);
-	MODULE_PARM_DESC(retrycount, "The retry count for FW ready while bus reset");
-#endif
-MODULE_AUTHOR("Erich Chen <support@areca.com.tw>");
-MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Bus Adapter");
+MODULE_AUTHOR("Nick Cheng <support@areca.com.tw>");
+MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus Adapter");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(ARCMSR_DRIVER_VERSION);
-
+static int sleeptime = 10;
+static int retrycount = 30;
+wait_queue_head_t wait_q;
 static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
 					struct scsi_cmnd *cmd);
 static int arcmsr_iop_confirm(struct AdapterControlBlock *acb);
@@ -107,10 +99,12 @@
 static void arcmsr_request_device_map(unsigned long pacb);
 static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb);
 static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb);
+static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb);
 static void arcmsr_message_isr_bh_fn(struct work_struct *work);
-static void *arcmsr_get_firmware_spec(struct AdapterControlBlock *acb, int mode);
+static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb);
 static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb);
-
+static void arcmsr_hbc_message_isr(struct AdapterControlBlock *pACB);
+static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
 static const char *arcmsr_info(struct Scsi_Host *);
 static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
 static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
@@ -127,18 +121,18 @@
 
 static struct scsi_host_template arcmsr_scsi_host_template = {
 	.module			= THIS_MODULE,
-	.name			= "ARCMSR ARECA SATA/SAS RAID Host Bus Adapter"
-							ARCMSR_DRIVER_VERSION,
+	.name			= "ARCMSR ARECA SATA/SAS RAID Controller"
+				ARCMSR_DRIVER_VERSION,
 	.info			= arcmsr_info,
 	.queuecommand		= arcmsr_queue_command,
-	.eh_abort_handler	= arcmsr_abort,
+	.eh_abort_handler		= arcmsr_abort,
 	.eh_bus_reset_handler	= arcmsr_bus_reset,
 	.bios_param		= arcmsr_bios_param,
 	.change_queue_depth	= arcmsr_adjust_disk_queue_depth,
-	.can_queue		= ARCMSR_MAX_OUTSTANDING_CMD,
-	.this_id		= ARCMSR_SCSI_INITIATOR_ID,
-	.sg_tablesize		= ARCMSR_MAX_SG_ENTRIES,
-	.max_sectors    	= ARCMSR_MAX_XFER_SECTORS,
+	.can_queue		= ARCMSR_MAX_FREECCB_NUM,
+	.this_id			= ARCMSR_SCSI_INITIATOR_ID,
+	.sg_tablesize	        	= ARCMSR_DEFAULT_SG_ENTRIES, 
+	.max_sectors    	    	= ARCMSR_MAX_XFER_SECTORS_C, 
 	.cmd_per_lun		= ARCMSR_MAX_CMD_PERLUN,
 	.use_clustering		= ENABLE_CLUSTERING,
 	.shost_attrs		= arcmsr_host_attrs,
@@ -162,26 +156,125 @@
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880)},
 	{0, 0}, /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table);
 static struct pci_driver arcmsr_pci_driver = {
 	.name			= "arcmsr",
-	.id_table		= arcmsr_device_id_table,
+	.id_table			= arcmsr_device_id_table,
 	.probe			= arcmsr_probe,
 	.remove			= arcmsr_remove,
 	.shutdown		= arcmsr_shutdown,
 };
+/*
+****************************************************************************
+****************************************************************************
+*/
+int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
+{
+		struct Scsi_Host *shost = NULL;
+		int i, isleep;
+		shost = cmd->device->host;
+		isleep = sleeptime / 10;
+		if (isleep > 0) {
+			for (i = 0; i < isleep; i++) {
+				msleep(10000);
+			}
+		}
+
+		isleep = sleeptime % 10;
+		if (isleep > 0) {
+			msleep(isleep*1000);
+		}
+		printk(KERN_NOTICE "wake-up\n");
+		return 0;
+}
+
+static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb)
+{
+	switch (acb->adapter_type) {
+	case ACB_ADAPTER_TYPE_A:
+	case ACB_ADAPTER_TYPE_C:
+		break;
+	case ACB_ADAPTER_TYPE_B:{
+		dma_free_coherent(&acb->pdev->dev,
+			sizeof(struct MessageUnit_B),
+			acb->pmuB, acb->dma_coherent_handle_hbb_mu);
+	}
+	}
+}
+
+static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb)
+{
+	struct pci_dev *pdev = acb->pdev;
+	switch (acb->adapter_type){
+	case ACB_ADAPTER_TYPE_A:{
+		acb->pmuA = ioremap(pci_resource_start(pdev,0), pci_resource_len(pdev,0));
+		if (!acb->pmuA) {
+			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+			return false;
+		}
+		break;
+	}
+	case ACB_ADAPTER_TYPE_B:{
+		void __iomem *mem_base0, *mem_base1;
+		mem_base0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+		if (!mem_base0) {
+			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+			return false;
+		}
+		mem_base1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
+		if (!mem_base1) {
+			iounmap(mem_base0);
+			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+			return false;
+		}
+		acb->mem_base0 = mem_base0;
+		acb->mem_base1 = mem_base1;
+		break;
+	}
+	case ACB_ADAPTER_TYPE_C:{
+		acb->pmuC = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+		if (!acb->pmuC) {
+			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+			return false;
+		}
+		if (readl(&acb->pmuC->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+			writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &acb->pmuC->outbound_doorbell_clear);/*clear interrupt*/
+			return true;
+		}
+		break;
+	}
+	}
+	return true;
+}
+
+static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb)
+{
+	switch (acb->adapter_type) {
+	case ACB_ADAPTER_TYPE_A:{
+		iounmap(acb->pmuA);
+	}
+	break;
+	case ACB_ADAPTER_TYPE_B:{
+		iounmap(acb->mem_base0);
+		iounmap(acb->mem_base1);
+	}
+
+	break;
+	case ACB_ADAPTER_TYPE_C:{
+		iounmap(acb->pmuC);
+	}
+	}
+}
 
 static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
 {
 	irqreturn_t handle_state;
 	struct AdapterControlBlock *acb = dev_id;
 
-	spin_lock(acb->host->host_lock);
 	handle_state = arcmsr_interrupt(acb);
-	spin_unlock(acb->host->host_lock);
-
 	return handle_state;
 }
 
@@ -218,181 +311,228 @@
 	struct pci_dev *pdev = acb->pdev;
 	u16 dev_id;
 	pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
+	acb->dev_id = dev_id;
 	switch (dev_id) {
-	case 0x1201 : {
+	case 0x1880: {
+		acb->adapter_type = ACB_ADAPTER_TYPE_C;
+		}
+		break;
+	case 0x1201: {
 		acb->adapter_type = ACB_ADAPTER_TYPE_B;
 		}
 		break;
 
-	default : acb->adapter_type = ACB_ADAPTER_TYPE_A;
+	default: acb->adapter_type = ACB_ADAPTER_TYPE_A;
+	}
+}	
+
+static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
+{
+	struct MessageUnit_A __iomem *reg = acb->pmuA;
+	uint32_t Index;
+	uint8_t Retries = 0x00;
+	do {
+		for (Index = 0; Index < 100; Index++) {
+			if (readl(&reg->outbound_intstatus) &
+					ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
+				writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
+					&reg->outbound_intstatus);
+				return true;
+			}
+			msleep(10);
+		}/*max 1 seconds*/
+
+	} while (Retries++ < 20);/*max 20 sec*/
+	return false;
+}
+
+static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
+{
+	struct MessageUnit_B *reg = acb->pmuB;
+	uint32_t Index;
+	uint8_t Retries = 0x00;
+	do {
+		for (Index = 0; Index < 100; Index++) {
+			if (readl(reg->iop2drv_doorbell)
+				& ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
+				writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
+					, reg->iop2drv_doorbell);
+				writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
+				return true;
+			}
+			msleep(10);
+		}/*max 1 seconds*/
+
+	} while (Retries++ < 20);/*max 20 sec*/
+	return false;
+}
+
+static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+	unsigned char Retries = 0x00;
+	uint32_t Index;
+	do {
+		for (Index = 0; Index < 100; Index++) {
+			if (readl(&phbcmu->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+				writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &phbcmu->outbound_doorbell_clear);/*clear interrupt*/
+				return true;
+			}
+			/* one us delay	*/
+			msleep(10);
+		} /*max 1 seconds*/
+	} while (Retries++ < 20); /*max 20 sec*/
+	return false;
+}
+static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
+{
+	struct MessageUnit_A __iomem *reg = acb->pmuA;
+	int retry_count = 30;
+	writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
+	do {
+		if (arcmsr_hba_wait_msgint_ready(acb))
+			break;
+		else {
+			retry_count--;
+			printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+			timeout, retry count down = %d \n", acb->host->host_no, retry_count);
+		}
+	} while (retry_count != 0);
+}
+
+static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb)
+{
+	struct MessageUnit_B *reg = acb->pmuB;
+	int retry_count = 30;
+	writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell);
+	do {
+		if (arcmsr_hbb_wait_msgint_ready(acb))
+			break;
+		else {
+			retry_count--;
+			printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+			timeout,retry count down = %d \n", acb->host->host_no, retry_count);
+		}
+	} while (retry_count != 0);
+}
+
+static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+	int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */
+	writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
+	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+	do {
+		if (arcmsr_hbc_wait_msgint_ready(pACB)) {
+			break;
+		} else {
+			retry_count--;
+			printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+			timeout,retry count down = %d \n", pACB->host->host_no, retry_count);
+		}
+	} while (retry_count != 0);
+	return;
+}
+static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
+{
+	switch (acb->adapter_type) {
+
+	case ACB_ADAPTER_TYPE_A: {
+		arcmsr_flush_hba_cache(acb);
+		}
+		break;
+
+	case ACB_ADAPTER_TYPE_B: {
+		arcmsr_flush_hbb_cache(acb);
+		}
+		break;
+	case ACB_ADAPTER_TYPE_C: {
+		arcmsr_flush_hbc_cache(acb);
+		}
 	}
 }
 
 static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
 {
+	struct pci_dev *pdev = acb->pdev;
+	void *dma_coherent;
+	dma_addr_t dma_coherent_handle;
+	struct CommandControlBlock *ccb_tmp;
+	int i = 0, j = 0;
+	dma_addr_t cdb_phyaddr;
+	unsigned long roundup_ccbsize = 0, offset;
+	unsigned long max_xfer_len;
+	unsigned long max_sg_entrys;
+	uint32_t  firm_config_version;
+	for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+		for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+			acb->devstate[i][j] = ARECA_RAID_GONE;
 
-	switch (acb->adapter_type) {
-
-	case ACB_ADAPTER_TYPE_A: {
-		struct pci_dev *pdev = acb->pdev;
-		void *dma_coherent;
-		dma_addr_t dma_coherent_handle, dma_addr;
-		struct CommandControlBlock *ccb_tmp;
-		int i, j;
-
-		acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
-		if (!acb->pmuA) {
-			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n",
-							acb->host->host_no);
-			return -ENOMEM;
-		}
-
-		dma_coherent = dma_alloc_coherent(&pdev->dev,
-			ARCMSR_MAX_FREECCB_NUM *
-			sizeof (struct CommandControlBlock) + 0x20,
-			&dma_coherent_handle, GFP_KERNEL);
-
-		if (!dma_coherent) {
-			iounmap(acb->pmuA);
-			return -ENOMEM;
-		}
-
-		acb->dma_coherent = dma_coherent;
-		acb->dma_coherent_handle = dma_coherent_handle;
-
-		if (((unsigned long)dma_coherent & 0x1F)) {
-			dma_coherent = dma_coherent +
-				(0x20 - ((unsigned long)dma_coherent & 0x1F));
-			dma_coherent_handle = dma_coherent_handle +
-				(0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
-		}
-
-		dma_addr = dma_coherent_handle;
-		ccb_tmp = (struct CommandControlBlock *)dma_coherent;
-		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
-			ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
-			ccb_tmp->acb = acb;
-			acb->pccb_pool[i] = ccb_tmp;
-			list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
-			dma_addr = dma_addr + sizeof(struct CommandControlBlock);
-			ccb_tmp++;
-		}
-
-		acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;
-		for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
-			for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
-				acb->devstate[i][j] = ARECA_RAID_GONE;
-		}
-		break;
-
-	case ACB_ADAPTER_TYPE_B: {
-
-		struct pci_dev *pdev = acb->pdev;
-		struct MessageUnit_B *reg;
-		void __iomem *mem_base0, *mem_base1;
-		void *dma_coherent;
-		dma_addr_t dma_coherent_handle, dma_addr;
-		struct CommandControlBlock *ccb_tmp;
-		int i, j;
-
-		dma_coherent = dma_alloc_coherent(&pdev->dev,
-			((ARCMSR_MAX_FREECCB_NUM *
-			sizeof(struct CommandControlBlock) + 0x20) +
-			sizeof(struct MessageUnit_B)),
-			&dma_coherent_handle, GFP_KERNEL);
-		if (!dma_coherent)
-			return -ENOMEM;
-
-		acb->dma_coherent = dma_coherent;
-		acb->dma_coherent_handle = dma_coherent_handle;
-
-		if (((unsigned long)dma_coherent & 0x1F)) {
-			dma_coherent = dma_coherent +
-				(0x20 - ((unsigned long)dma_coherent & 0x1F));
-			dma_coherent_handle = dma_coherent_handle +
-				(0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
-		}
-
-		dma_addr = dma_coherent_handle;
-		ccb_tmp = (struct CommandControlBlock *)dma_coherent;
-		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
-			ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
-			ccb_tmp->acb = acb;
-			acb->pccb_pool[i] = ccb_tmp;
-			list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
-			dma_addr = dma_addr + sizeof(struct CommandControlBlock);
-			ccb_tmp++;
-		}
-
-		reg = (struct MessageUnit_B *)(dma_coherent +
-		ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));
-		acb->pmuB = reg;
-		mem_base0 = ioremap(pci_resource_start(pdev, 0),
-					pci_resource_len(pdev, 0));
-		if (!mem_base0)
-			goto out;
-
-		mem_base1 = ioremap(pci_resource_start(pdev, 2),
-					pci_resource_len(pdev, 2));
-		if (!mem_base1) {
-			iounmap(mem_base0);
-			goto out;
-		}
-
-		reg->drv2iop_doorbell_reg = mem_base0 + ARCMSR_DRV2IOP_DOORBELL;
-		reg->drv2iop_doorbell_mask_reg = mem_base0 +
-						ARCMSR_DRV2IOP_DOORBELL_MASK;
-		reg->iop2drv_doorbell_reg = mem_base0 + ARCMSR_IOP2DRV_DOORBELL;
-		reg->iop2drv_doorbell_mask_reg = mem_base0 +
-						ARCMSR_IOP2DRV_DOORBELL_MASK;
-		reg->ioctl_wbuffer_reg = mem_base1 + ARCMSR_IOCTL_WBUFFER;
-		reg->ioctl_rbuffer_reg = mem_base1 + ARCMSR_IOCTL_RBUFFER;
-		reg->msgcode_rwbuffer_reg = mem_base1 + ARCMSR_MSGCODE_RWBUFFER;
-
-		acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;
-		for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
-			for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
-				acb->devstate[i][j] = ARECA_RAID_GOOD;
-		}
-		break;
+	max_xfer_len = ARCMSR_MAX_XFER_LEN;
+	max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
+	firm_config_version = acb->firm_cfg_version;
+	if((firm_config_version & 0xFF) >= 3){
+		max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */
+		max_sg_entrys = (max_xfer_len/4096);	
+	}
+	acb->host->max_sectors = max_xfer_len/512;
+	acb->host->sg_tablesize = max_sg_entrys;
+	roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
+	acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM + 32;
+	dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL);
+	if(!dma_coherent){
+		printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error \n", acb->host->host_no);
+		return -ENOMEM;
+	}
+	acb->dma_coherent = dma_coherent;
+	acb->dma_coherent_handle = dma_coherent_handle;
+	memset(dma_coherent, 0, acb->uncache_size);
+	offset = roundup((unsigned long)dma_coherent, 32) - (unsigned long)dma_coherent;
+	dma_coherent_handle = dma_coherent_handle + offset;
+	dma_coherent = (struct CommandControlBlock *)dma_coherent + offset;
+	ccb_tmp = dma_coherent;
+	acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle;
+	for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){
+		cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb);
+		ccb_tmp->cdb_phyaddr_pattern = ((acb->adapter_type == ACB_ADAPTER_TYPE_C) ? cdb_phyaddr : (cdb_phyaddr >> 5));
+		acb->pccb_pool[i] = ccb_tmp;
+		ccb_tmp->acb = acb;
+		INIT_LIST_HEAD(&ccb_tmp->list);
+		list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
+		ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize);
+		dma_coherent_handle = dma_coherent_handle + roundup_ccbsize;
 	}
 	return 0;
-
-out:
-	dma_free_coherent(&acb->pdev->dev,
-		(ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 +
-		sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle);
-	return -ENOMEM;
 }
-static void arcmsr_message_isr_bh_fn(struct work_struct *work)
-{
-	struct AdapterControlBlock *acb = container_of(work, struct AdapterControlBlock, arcmsr_do_message_isr_bh);
 
+static void arcmsr_message_isr_bh_fn(struct work_struct *work) 
+{
+	struct AdapterControlBlock *acb = container_of(work,struct AdapterControlBlock, arcmsr_do_message_isr_bh);
 	switch (acb->adapter_type) {
 		case ACB_ADAPTER_TYPE_A: {
 
 			struct MessageUnit_A __iomem *reg  = acb->pmuA;
 			char *acb_dev_map = (char *)acb->device_map;
-			uint32_t __iomem *signature = (uint32_t __iomem *) (&reg->message_rwbuffer[0]);
-			char __iomem *devicemap = (char __iomem *) (&reg->message_rwbuffer[21]);
+			uint32_t __iomem *signature = (uint32_t __iomem*) (&reg->message_rwbuffer[0]);
+			char __iomem *devicemap = (char __iomem*) (&reg->message_rwbuffer[21]);
 			int target, lun;
 			struct scsi_device *psdev;
 			char diff;
 
 			atomic_inc(&acb->rq_map_token);
 			if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
-				for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) {
+				for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) {
 					diff = (*acb_dev_map)^readb(devicemap);
 					if (diff != 0) {
 						char temp;
 						*acb_dev_map = readb(devicemap);
-						temp = *acb_dev_map;
-						for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
-							if ((temp & 0x01) == 1 && (diff & 0x01) == 1) {
+						temp =*acb_dev_map;
+						for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
+							if((temp & 0x01)==1 && (diff & 0x01) == 1) {	
 								scsi_add_device(acb->host, 0, target, lun);
-							} else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) {
+							}else if((temp & 0x01) == 0 && (diff & 0x01) == 1) {
 								psdev = scsi_device_lookup(acb->host, 0, target, lun);
-								if (psdev != NULL) {
+								if (psdev != NULL ) {
 									scsi_remove_device(psdev);
 									scsi_device_put(psdev);
 								}
@@ -411,8 +551,45 @@
 		case ACB_ADAPTER_TYPE_B: {
 			struct MessageUnit_B *reg  = acb->pmuB;
 			char *acb_dev_map = (char *)acb->device_map;
-			uint32_t __iomem *signature = (uint32_t __iomem *)(&reg->msgcode_rwbuffer_reg[0]);
-			char __iomem *devicemap = (char __iomem *)(&reg->msgcode_rwbuffer_reg[21]);
+			uint32_t __iomem *signature = (uint32_t __iomem*)(&reg->message_rwbuffer[0]);
+			char __iomem *devicemap = (char __iomem*)(&reg->message_rwbuffer[21]);
+			int target, lun;
+			struct scsi_device *psdev;
+			char diff;
+
+			atomic_inc(&acb->rq_map_token);
+			if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
+				for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) {
+					diff = (*acb_dev_map)^readb(devicemap);
+					if (diff != 0) {
+						char temp;
+						*acb_dev_map = readb(devicemap);
+						temp =*acb_dev_map;
+						for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
+							if((temp & 0x01)==1 && (diff & 0x01) == 1) {	
+								scsi_add_device(acb->host, 0, target, lun);
+							}else if((temp & 0x01) == 0 && (diff & 0x01) == 1) {
+								psdev = scsi_device_lookup(acb->host, 0, target, lun);
+								if (psdev != NULL ) {
+									scsi_remove_device(psdev);
+									scsi_device_put(psdev);
+								}
+							}
+							temp >>= 1;
+							diff >>= 1;
+						}
+					}
+					devicemap++;
+					acb_dev_map++;
+				}
+			}
+		}
+		break;
+		case ACB_ADAPTER_TYPE_C: {
+			struct MessageUnit_C *reg  = acb->pmuC;
+			char *acb_dev_map = (char *)acb->device_map;
+			uint32_t __iomem *signature = (uint32_t __iomem *)(&reg->msgcode_rwbuffer[0]);
+			char __iomem *devicemap = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
 			int target, lun;
 			struct scsi_device *psdev;
 			char diff;
@@ -447,185 +624,152 @@
 	}
 }
 
-static int arcmsr_probe(struct pci_dev *pdev,
-	const struct pci_device_id *id)
+static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct Scsi_Host *host;
 	struct AdapterControlBlock *acb;
-	uint8_t bus, dev_fun;
+	uint8_t bus,dev_fun;
 	int error;
-
 	error = pci_enable_device(pdev);
-	if (error)
-		goto out;
-	pci_set_master(pdev);
-
-	host = scsi_host_alloc(&arcmsr_scsi_host_template,
-			sizeof(struct AdapterControlBlock));
-	if (!host) {
-		error = -ENOMEM;
-		goto out_disable_device;
+	if(error){
+		return -ENODEV;
 	}
-	acb = (struct AdapterControlBlock *)host->hostdata;
-	memset(acb, 0, sizeof (struct AdapterControlBlock));
-
+	host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock));
+	if(!host){
+    		goto pci_disable_dev;
+	}
 	error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
-	if (error) {
+	if(error){
 		error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-		if (error) {
+		if(error){
 			printk(KERN_WARNING
 			       "scsi%d: No suitable DMA mask available\n",
 			       host->host_no);
-			goto out_host_put;
+			goto scsi_host_release;
 		}
 	}
+	init_waitqueue_head(&wait_q);
 	bus = pdev->bus->number;
 	dev_fun = pdev->devfn;
-	acb->host = host;
+	acb = (struct AdapterControlBlock *) host->hostdata;
+	memset(acb,0,sizeof(struct AdapterControlBlock));
 	acb->pdev = pdev;
-	host->max_sectors = ARCMSR_MAX_XFER_SECTORS;
+	acb->host = host;
 	host->max_lun = ARCMSR_MAX_TARGETLUN;
-	host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/
-	host->max_cmd_len = 16;    /*this is issue of 64bit LBA, over 2T byte*/
-	host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES;
-	host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */
-	host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;
+	host->max_id = ARCMSR_MAX_TARGETID;		/*16:8*/
+	host->max_cmd_len = 16;	 			/*this is issue of 64bit LBA ,over 2T byte*/
+	host->can_queue = ARCMSR_MAX_FREECCB_NUM;	/* max simultaneous cmds */		
+	host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;	    
 	host->this_id = ARCMSR_SCSI_INITIATOR_ID;
 	host->unique_id = (bus << 8) | dev_fun;
-	host->irq = pdev->irq;
+	pci_set_drvdata(pdev, host);
+	pci_set_master(pdev);
 	error = pci_request_regions(pdev, "arcmsr");
-	if (error) {
-		goto out_host_put;
+	if(error){
+		goto scsi_host_release;
 	}
-	arcmsr_define_adapter_type(acb);
-
+	spin_lock_init(&acb->eh_lock);
+	spin_lock_init(&acb->ccblist_lock);
 	acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
-			   ACB_F_MESSAGE_RQBUFFER_CLEARED |
-			   ACB_F_MESSAGE_WQBUFFER_READED);
+			ACB_F_MESSAGE_RQBUFFER_CLEARED |
+			ACB_F_MESSAGE_WQBUFFER_READED);
 	acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
 	INIT_LIST_HEAD(&acb->ccb_free_list);
-	INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
+	arcmsr_define_adapter_type(acb);
+	error = arcmsr_remap_pciregion(acb);
+	if(!error){
+		goto pci_release_regs;
+	}
+	error = arcmsr_get_firmware_spec(acb);
+	if(!error){
+		goto unmap_pci_region;
+	}
 	error = arcmsr_alloc_ccb_pool(acb);
-	if (error)
-		goto out_release_regions;
-
+	if(error){
+		goto free_hbb_mu;
+	}
 	arcmsr_iop_init(acb);
-	error = request_irq(pdev->irq, arcmsr_do_interrupt,
-			    IRQF_SHARED, "arcmsr", acb);
-	if (error)
-		goto out_free_ccb_pool;
-
-	pci_set_drvdata(pdev, host);
-	if (strncmp(acb->firm_version, "V1.42", 5) >= 0)
-		host->max_sectors= ARCMSR_MAX_XFER_SECTORS_B;
-
 	error = scsi_add_host(host, &pdev->dev);
-	if (error)
-		goto out_free_irq;
-
-	error = arcmsr_alloc_sysfs_attr(acb);
-	if (error)
-		goto out_free_sysfs;
-
-	scsi_scan_host(host);
-	#ifdef CONFIG_SCSI_ARCMSR_AER
-	pci_enable_pcie_error_reporting(pdev);
-	#endif
+	if(error){
+		goto RAID_controller_stop;
+	}
+	error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb);
+	if(error){
+		goto scsi_host_remove;
+	}
+	host->irq = pdev->irq;
+    	scsi_scan_host(host);
+	INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
 	atomic_set(&acb->rq_map_token, 16);
-	acb->fw_state = true;
+	atomic_set(&acb->ante_token_value, 16);
+	acb->fw_flag = FW_NORMAL;
 	init_timer(&acb->eternal_timer);
-	acb->eternal_timer.expires = jiffies + msecs_to_jiffies(10*HZ);
+	acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ);
 	acb->eternal_timer.data = (unsigned long) acb;
 	acb->eternal_timer.function = &arcmsr_request_device_map;
 	add_timer(&acb->eternal_timer);
-
+	if(arcmsr_alloc_sysfs_attr(acb))
+		goto out_free_sysfs;
 	return 0;
- out_free_sysfs:
- out_free_irq:
-	free_irq(pdev->irq, acb);
- out_free_ccb_pool:
+out_free_sysfs:
+scsi_host_remove:
+	scsi_remove_host(host);
+RAID_controller_stop:
+	arcmsr_stop_adapter_bgrb(acb);
+	arcmsr_flush_adapter_cache(acb);
 	arcmsr_free_ccb_pool(acb);
- out_release_regions:
+free_hbb_mu:
+	arcmsr_free_hbb_mu(acb);
+unmap_pci_region:
+	arcmsr_unmap_pciregion(acb);
+pci_release_regs:
 	pci_release_regions(pdev);
- out_host_put:
+scsi_host_release:
 	scsi_host_put(host);
- out_disable_device:
+pci_disable_dev:
 	pci_disable_device(pdev);
- out:
-	return error;
-}
-
-static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
-{
-	struct MessageUnit_A __iomem *reg = acb->pmuA;
-	uint32_t Index;
-	uint8_t Retries = 0x00;
-
-	do {
-		for (Index = 0; Index < 100; Index++) {
-			if (readl(&reg->outbound_intstatus) &
-					ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
-				writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
-					&reg->outbound_intstatus);
-				return 0x00;
-			}
-			msleep(10);
-		}/*max 1 seconds*/
-
-	} while (Retries++ < 20);/*max 20 sec*/
-	return 0xff;
-}
-
-static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
-{
-	struct MessageUnit_B *reg = acb->pmuB;
-	uint32_t Index;
-	uint8_t Retries = 0x00;
-
-	do {
-		for (Index = 0; Index < 100; Index++) {
-			if (readl(reg->iop2drv_doorbell_reg)
-				& ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
-				writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
-					, reg->iop2drv_doorbell_reg);
-				writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
-				return 0x00;
-			}
-			msleep(10);
-		}/*max 1 seconds*/
-
-	} while (Retries++ < 20);/*max 20 sec*/
-	return 0xff;
+	return -ENODEV;
 }
 
 static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
-
 	writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
-	if (arcmsr_hba_wait_msgint_ready(acb)) {
+	if (!arcmsr_hba_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE
 			"arcmsr%d: wait 'abort all outstanding command' timeout \n"
 			, acb->host->host_no);
-		return 0xff;
+		return false;
 	}
-	return 0x00;
+	return true;
 }
 
 static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_B *reg = acb->pmuB;
 
-	writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg);
-	if (arcmsr_hbb_wait_msgint_ready(acb)) {
+	writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell);
+	if (!arcmsr_hbb_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE
 			"arcmsr%d: wait 'abort all outstanding command' timeout \n"
 			, acb->host->host_no);
-		return 0xff;
+		return false;
 	}
-	return 0x00;
+	return true;
 }
-
+static uint8_t arcmsr_abort_hbc_allcmd(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+	writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
+	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+	if (!arcmsr_hbc_wait_msgint_ready(pACB)) {
+		printk(KERN_NOTICE
+			"arcmsr%d: wait 'abort all outstanding command' timeout \n"
+			, pACB->host->host_no);
+		return false;
+	}
+	return true;
+}
 static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
 {
 	uint8_t rtnval = 0;
@@ -638,10 +782,26 @@
 	case ACB_ADAPTER_TYPE_B: {
 		rtnval = arcmsr_abort_hbb_allcmd(acb);
 		}
+		break;
+
+	case ACB_ADAPTER_TYPE_C: {
+		rtnval = arcmsr_abort_hbc_allcmd(acb);
+		}
 	}
 	return rtnval;
 }
 
+static bool arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb)
+{
+	struct MessageUnit_B *reg = pacb->pmuB;
+	writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
+	if (!arcmsr_hbb_wait_msgint_ready(pacb)) {
+		printk(KERN_ERR "arcmsr%d: can't set driver mode. \n", pacb->host->host_no);
+		return false;
+	}
+    	return true;
+}
+
 static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
 {
 	struct scsi_cmnd *pcmd = ccb->pcmd;
@@ -649,75 +809,25 @@
 	scsi_dma_unmap(pcmd);
 }
 
-static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag)
+static void arcmsr_ccb_complete(struct CommandControlBlock *ccb)
 {
 	struct AdapterControlBlock *acb = ccb->acb;
 	struct scsi_cmnd *pcmd = ccb->pcmd;
-
+	unsigned long flags;
+	atomic_dec(&acb->ccboutstandingcount);
 	arcmsr_pci_unmap_dma(ccb);
-	if (stand_flag == 1)
-		atomic_dec(&acb->ccboutstandingcount);
 	ccb->startdone = ARCMSR_CCB_DONE;
-	ccb->ccb_flags = 0;
+	spin_lock_irqsave(&acb->ccblist_lock, flags);
 	list_add_tail(&ccb->list, &acb->ccb_free_list);
+	spin_unlock_irqrestore(&acb->ccblist_lock, flags);
 	pcmd->scsi_done(pcmd);
 }
 
-static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
-{
-	struct MessageUnit_A __iomem *reg = acb->pmuA;
-	int retry_count = 30;
-
-	writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
-	do {
-		if (!arcmsr_hba_wait_msgint_ready(acb))
-			break;
-		else {
-			retry_count--;
-			printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
-			timeout, retry count down = %d \n", acb->host->host_no, retry_count);
-		}
-	} while (retry_count != 0);
-}
-
-static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb)
-{
-	struct MessageUnit_B *reg = acb->pmuB;
-	int retry_count = 30;
-
-	writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell_reg);
-	do {
-		if (!arcmsr_hbb_wait_msgint_ready(acb))
-			break;
-		else {
-			retry_count--;
-			printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
-			timeout,retry count down = %d \n", acb->host->host_no, retry_count);
-		}
-	} while (retry_count != 0);
-}
-
-static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
-{
-	switch (acb->adapter_type) {
-
-	case ACB_ADAPTER_TYPE_A: {
-		arcmsr_flush_hba_cache(acb);
-		}
-		break;
-
-	case ACB_ADAPTER_TYPE_B: {
-		arcmsr_flush_hbb_cache(acb);
-		}
-	}
-}
-
 static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
 {
 
 	struct scsi_cmnd *pcmd = ccb->pcmd;
 	struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
-
 	pcmd->result = DID_OK << 16;
 	if (sensebuffer) {
 		int sense_data_length =
@@ -733,8 +843,7 @@
 static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
 {
 	u32 orig_mask = 0;
-	switch (acb->adapter_type) {
-
+	switch (acb->adapter_type) {	
 	case ACB_ADAPTER_TYPE_A : {
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
 		orig_mask = readl(&reg->outbound_intmask);
@@ -742,35 +851,40 @@
 						&reg->outbound_intmask);
 		}
 		break;
-
 	case ACB_ADAPTER_TYPE_B : {
 		struct MessageUnit_B *reg = acb->pmuB;
-		orig_mask = readl(reg->iop2drv_doorbell_mask_reg);
-		writel(0, reg->iop2drv_doorbell_mask_reg);
+		orig_mask = readl(reg->iop2drv_doorbell_mask);
+		writel(0, reg->iop2drv_doorbell_mask);
+		}
+		break;
+	case ACB_ADAPTER_TYPE_C:{
+		struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+		/* disable all outbound interrupt */
+		orig_mask = readl(&reg->host_int_mask); /* disable outbound message0 int */
+		writel(orig_mask|ARCMSR_HBCMU_ALL_INTMASKENABLE, &reg->host_int_mask);
 		}
 		break;
 	}
 	return orig_mask;
 }
 
-static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \
-			struct CommandControlBlock *ccb, uint32_t flag_ccb)
+static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, 
+			struct CommandControlBlock *ccb, bool error)
 {
-
 	uint8_t id, lun;
 	id = ccb->pcmd->device->id;
 	lun = ccb->pcmd->device->lun;
-	if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+	if (!error) {
 		if (acb->devstate[id][lun] == ARECA_RAID_GONE)
 			acb->devstate[id][lun] = ARECA_RAID_GOOD;
 			ccb->pcmd->result = DID_OK << 16;
-			arcmsr_ccb_complete(ccb, 1);
-	} else {
+			arcmsr_ccb_complete(ccb);
+	}else{
 		switch (ccb->arcmsr_cdb.DeviceStatus) {
 		case ARCMSR_DEV_SELECT_TIMEOUT: {
 			acb->devstate[id][lun] = ARECA_RAID_GONE;
 			ccb->pcmd->result = DID_NO_CONNECT << 16;
-			arcmsr_ccb_complete(ccb, 1);
+			arcmsr_ccb_complete(ccb);
 			}
 			break;
 
@@ -779,49 +893,49 @@
 		case ARCMSR_DEV_INIT_FAIL: {
 			acb->devstate[id][lun] = ARECA_RAID_GONE;
 			ccb->pcmd->result = DID_BAD_TARGET << 16;
-			arcmsr_ccb_complete(ccb, 1);
+			arcmsr_ccb_complete(ccb);
 			}
 			break;
 
 		case ARCMSR_DEV_CHECK_CONDITION: {
 			acb->devstate[id][lun] = ARECA_RAID_GOOD;
 			arcmsr_report_sense_info(ccb);
-			arcmsr_ccb_complete(ccb, 1);
+			arcmsr_ccb_complete(ccb);
 			}
 			break;
 
 		default:
-				printk(KERN_NOTICE
-					"arcmsr%d: scsi id = %d lun = %d"
-					" isr get command error done, "
-					"but got unknown DeviceStatus = 0x%x \n"
-					, acb->host->host_no
-					, id
-					, lun
-					, ccb->arcmsr_cdb.DeviceStatus);
-					acb->devstate[id][lun] = ARECA_RAID_GONE;
-					ccb->pcmd->result = DID_NO_CONNECT << 16;
-					arcmsr_ccb_complete(ccb, 1);
+			printk(KERN_NOTICE
+				"arcmsr%d: scsi id = %d lun = %d isr get command error done, \
+				but got unknown DeviceStatus = 0x%x \n"
+				, acb->host->host_no
+				, id
+				, lun
+				, ccb->arcmsr_cdb.DeviceStatus);
+				acb->devstate[id][lun] = ARECA_RAID_GONE;
+				ccb->pcmd->result = DID_NO_CONNECT << 16;
+				arcmsr_ccb_complete(ccb);
 			break;
 		}
 	}
 }
 
-static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t flag_ccb)
+static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error)
 
 {
-	struct CommandControlBlock *ccb;
-
-	ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5));
-	if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
-		if (ccb->startdone == ARCMSR_CCB_ABORTED) {
-			struct scsi_cmnd *abortcmd = ccb->pcmd;
+	int id, lun;
+	if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
+		if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
+			struct scsi_cmnd *abortcmd = pCCB->pcmd;
 			if (abortcmd) {
+				id = abortcmd->device->id;
+				lun = abortcmd->device->lun;				
 				abortcmd->result |= DID_ABORT << 16;
-				arcmsr_ccb_complete(ccb, 1);
-				printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \
-				isr got aborted command \n", acb->host->host_no, ccb);
+				arcmsr_ccb_complete(pCCB);
+				printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p' isr got aborted command \n",
+				acb->host->host_no, pCCB);
 			}
+			return;
 		}
 		printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \
 				done acb = '0x%p'"
@@ -829,20 +943,22 @@
 				" ccboutstandingcount = %d \n"
 				, acb->host->host_no
 				, acb
-				, ccb
-				, ccb->acb
-				, ccb->startdone
+				, pCCB
+				, pCCB->acb
+				, pCCB->startdone
 				, atomic_read(&acb->ccboutstandingcount));
+		  return;
 		}
-	else
-	arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+	arcmsr_report_ccb_state(acb, pCCB, error);
 }
 
 static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
 {
 	int i = 0;
 	uint32_t flag_ccb;
-
+	struct ARCMSR_CDB *pARCMSR_CDB;
+	bool error;
+	struct CommandControlBlock *pCCB;
 	switch (acb->adapter_type) {
 
 	case ACB_ADAPTER_TYPE_A: {
@@ -852,9 +968,12 @@
 					acb->outbound_int_enable;
 		/*clear and abort all outbound posted Q*/
 		writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
-		while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF)
+		while(((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF)
 				&& (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
-			arcmsr_drain_donequeue(acb, flag_ccb);
+			pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/
+			pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
+			error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+			arcmsr_drain_donequeue(acb, pCCB, error);
 		}
 		}
 		break;
@@ -862,17 +981,37 @@
 	case ACB_ADAPTER_TYPE_B: {
 		struct MessageUnit_B *reg = acb->pmuB;
 		/*clear all outbound posted Q*/
+		writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, &reg->iop2drv_doorbell); /* clear doorbell interrupt */
 		for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
 			if ((flag_ccb = readl(&reg->done_qbuffer[i])) != 0) {
 				writel(0, &reg->done_qbuffer[i]);
-				arcmsr_drain_donequeue(acb, flag_ccb);
+				pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/
+				pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
+				error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+				arcmsr_drain_donequeue(acb, pCCB, error);
 			}
-			writel(0, &reg->post_qbuffer[i]);
+			reg->post_qbuffer[i] = 0;
 		}
 		reg->doneq_index = 0;
 		reg->postq_index = 0;
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C *reg = acb->pmuC;
+		struct  ARCMSR_CDB *pARCMSR_CDB;
+		uint32_t flag_ccb, ccb_cdb_phy;
+		bool error;
+		struct CommandControlBlock *pCCB;
+		while ((readl(&reg->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
+			/*need to do*/
+			flag_ccb = readl(&reg->outbound_queueport_low);
+			ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
+			pARCMSR_CDB = (struct  ARCMSR_CDB *)(acb->vir2phy_offset+ccb_cdb_phy);/*frame must be 32 bytes aligned*/
+			pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
+			error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
+			arcmsr_drain_donequeue(acb, pCCB, error);
+		}
+	}
 	}
 }
 static void arcmsr_remove(struct pci_dev *pdev)
@@ -887,11 +1026,11 @@
 	del_timer_sync(&acb->eternal_timer);
 	arcmsr_disable_outbound_ints(acb);
 	arcmsr_stop_adapter_bgrb(acb);
-	arcmsr_flush_adapter_cache(acb);
+	arcmsr_flush_adapter_cache(acb);	
 	acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
 	acb->acb_flags &= ~ACB_F_IOP_INITED;
 
-	for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++) {
+	for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++){
 		if (!atomic_read(&acb->ccboutstandingcount))
 			break;
 		arcmsr_interrupt(acb);/* FIXME: need spinlock */
@@ -908,17 +1047,16 @@
 			if (ccb->startdone == ARCMSR_CCB_START) {
 				ccb->startdone = ARCMSR_CCB_ABORTED;
 				ccb->pcmd->result = DID_ABORT << 16;
-				arcmsr_ccb_complete(ccb, 1);
+				arcmsr_ccb_complete(ccb);
 			}
 		}
 	}
-
 	free_irq(pdev->irq, acb);
 	arcmsr_free_ccb_pool(acb);
+	arcmsr_free_hbb_mu(acb);
+	arcmsr_unmap_pciregion(acb);
 	pci_release_regions(pdev);
-
 	scsi_host_put(host);
-
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 }
@@ -938,7 +1076,6 @@
 static int arcmsr_module_init(void)
 {
 	int error = 0;
-
 	error = pci_register_driver(&arcmsr_pci_driver);
 	return error;
 }
@@ -954,10 +1091,9 @@
 						u32 intmask_org)
 {
 	u32 mask;
-
 	switch (acb->adapter_type) {
 
-	case ACB_ADAPTER_TYPE_A : {
+	case ACB_ADAPTER_TYPE_A: {
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
 		mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
 			     ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE|
@@ -967,15 +1103,22 @@
 		}
 		break;
 
-	case ACB_ADAPTER_TYPE_B : {
+	case ACB_ADAPTER_TYPE_B: {
 		struct MessageUnit_B *reg = acb->pmuB;
 		mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK |
 			ARCMSR_IOP2DRV_DATA_READ_OK |
 			ARCMSR_IOP2DRV_CDB_DONE |
 			ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
-		writel(mask, reg->iop2drv_doorbell_mask_reg);
+		writel(mask, reg->iop2drv_doorbell_mask);
 		acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
 		}
+		break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C *reg = acb->pmuC;
+		mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK|ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK);
+		writel(intmask_org & mask, &reg->host_int_mask);
+		acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f;
+		}
 	}
 }
 
@@ -986,80 +1129,70 @@
 	int8_t *psge = (int8_t *)&arcmsr_cdb->u;
 	__le32 address_lo, address_hi;
 	int arccdbsize = 0x30;
+	__le32 length = 0;
+	int i;
+	struct scatterlist *sg;
 	int nseg;
-
 	ccb->pcmd = pcmd;
 	memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB));
-	arcmsr_cdb->Bus = 0;
 	arcmsr_cdb->TargetID = pcmd->device->id;
 	arcmsr_cdb->LUN = pcmd->device->lun;
 	arcmsr_cdb->Function = 1;
-	arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len;
-	arcmsr_cdb->Context = (unsigned long)arcmsr_cdb;
+	arcmsr_cdb->Context = 0;
 	memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
 
 	nseg = scsi_dma_map(pcmd);
-	if (nseg > ARCMSR_MAX_SG_ENTRIES)
+	if (unlikely(nseg > acb->host->sg_tablesize || nseg < 0))
 		return FAILED;
-	BUG_ON(nseg < 0);
+	scsi_for_each_sg(pcmd, sg, nseg, i) {
+		/* Get the physical address of the current data pointer */
+		length = cpu_to_le32(sg_dma_len(sg));
+		address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sg)));
+		address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sg)));
+		if (address_hi == 0) {
+			struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
 
-	if (nseg) {
-		__le32 length;
-		int i, cdb_sgcount = 0;
-		struct scatterlist *sg;
+			pdma_sg->address = address_lo;
+			pdma_sg->length = length;
+			psge += sizeof (struct SG32ENTRY);
+			arccdbsize += sizeof (struct SG32ENTRY);
+		} else {
+			struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
 
-		/* map stor port SG list to our iop SG List. */
-		scsi_for_each_sg(pcmd, sg, nseg, i) {
-			/* Get the physical address of the current data pointer */
-			length = cpu_to_le32(sg_dma_len(sg));
-			address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sg)));
-			address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sg)));
-			if (address_hi == 0) {
-				struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
-
-				pdma_sg->address = address_lo;
-				pdma_sg->length = length;
-				psge += sizeof (struct SG32ENTRY);
-				arccdbsize += sizeof (struct SG32ENTRY);
-			} else {
-				struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
-
-				pdma_sg->addresshigh = address_hi;
-				pdma_sg->address = address_lo;
-				pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR);
-				psge += sizeof (struct SG64ENTRY);
-				arccdbsize += sizeof (struct SG64ENTRY);
-			}
-			cdb_sgcount++;
+			pdma_sg->addresshigh = address_hi;
+			pdma_sg->address = address_lo;
+			pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR);
+			psge += sizeof (struct SG64ENTRY);
+			arccdbsize += sizeof (struct SG64ENTRY);
 		}
-		arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
-		arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
-		if ( arccdbsize > 256)
-			arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
 	}
-	if (pcmd->sc_data_direction == DMA_TO_DEVICE ) {
+	arcmsr_cdb->sgcount = (uint8_t)nseg;
+	arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
+	arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0);
+	if ( arccdbsize > 256)
+		arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
+	if (pcmd->cmnd[0]|WRITE_6 || pcmd->cmnd[0]|WRITE_10 || pcmd->cmnd[0]|WRITE_12 ){
 		arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
-		ccb->ccb_flags |= CCB_FLAG_WRITE;
 	}
+	ccb->arc_cdb_size = arccdbsize;
 	return SUCCESS;
 }
 
 static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
 {
-	uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr;
+	uint32_t cdb_phyaddr_pattern = ccb->cdb_phyaddr_pattern;
 	struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
 	atomic_inc(&acb->ccboutstandingcount);
 	ccb->startdone = ARCMSR_CCB_START;
-
 	switch (acb->adapter_type) {
 	case ACB_ADAPTER_TYPE_A: {
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
 
 		if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
-			writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+			writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
 			&reg->inbound_queueport);
 		else {
-				writel(cdb_shifted_phyaddr, &reg->inbound_queueport);
+				writel(cdb_phyaddr_pattern, &reg->inbound_queueport);
 		}
 		}
 		break;
@@ -1071,18 +1204,30 @@
 		ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE);
 		writel(0, &reg->post_qbuffer[ending_index]);
 		if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
-			writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\
+			writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\
 						 &reg->post_qbuffer[index]);
-		}
-		else {
-			writel(cdb_shifted_phyaddr, &reg->post_qbuffer[index]);
+		} else {
+			writel(cdb_phyaddr_pattern, &reg->post_qbuffer[index]);
 		}
 		index++;
 		index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */
 		reg->postq_index = index;
-		writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell_reg);
+		writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell);
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC;
+		uint32_t ccb_post_stamp, arc_cdb_size;
+
+		arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size;
+		ccb_post_stamp = (cdb_phyaddr_pattern | ((arc_cdb_size - 1) >> 6) | 1);
+		if (acb->cdb_phyaddr_hi32) {
+			writel(acb->cdb_phyaddr_hi32, &phbcmu->inbound_queueport_high);
+			writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
+		} else {
+			writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
+		}
+		}
 	}
 }
 
@@ -1091,8 +1236,7 @@
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
 	writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
-
-	if (arcmsr_hba_wait_msgint_ready(acb)) {
+	if (!arcmsr_hba_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE
 			"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
 			, acb->host->host_no);
@@ -1103,15 +1247,28 @@
 {
 	struct MessageUnit_B *reg = acb->pmuB;
 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
-	writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell_reg);
+	writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell);
 
-	if (arcmsr_hbb_wait_msgint_ready(acb)) {
+	if (!arcmsr_hbb_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE
 			"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
 			, acb->host->host_no);
 	}
 }
 
+static void arcmsr_stop_hbc_bgrb(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+	pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
+	writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
+	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+	if (!arcmsr_hbc_wait_msgint_ready(pACB)) {
+		printk(KERN_NOTICE
+			"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
+			, pACB->host->host_no);
+	}
+	return;
+}
 static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
@@ -1124,30 +1281,15 @@
 		arcmsr_stop_hbb_bgrb(acb);
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		arcmsr_stop_hbc_bgrb(acb);
+		}
 	}
 }
 
 static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
 {
-	switch (acb->adapter_type) {
-	case ACB_ADAPTER_TYPE_A: {
-		iounmap(acb->pmuA);
-		dma_free_coherent(&acb->pdev->dev,
-		ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20,
-		acb->dma_coherent,
-		acb->dma_coherent_handle);
-		break;
-	}
-	case ACB_ADAPTER_TYPE_B: {
-		struct MessageUnit_B *reg = acb->pmuB;
-		iounmap((u8 *)reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL);
-		iounmap((u8 *)reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER);
-		dma_free_coherent(&acb->pdev->dev,
-		(ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 +
-		sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle);
-	}
-	}
-
+	dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
 }
 
 void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
@@ -1161,9 +1303,13 @@
 
 	case ACB_ADAPTER_TYPE_B: {
 		struct MessageUnit_B *reg = acb->pmuB;
-		writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg);
+		writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C __iomem *reg = acb->pmuC;
+		writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
+		}
 	}
 }
 
@@ -1186,7 +1332,16 @@
 		** push inbound doorbell tell iop, driver data write ok
 		** and wait reply on next hwinterrupt for next Qbuffer post
 		*/
-		writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell_reg);
+		writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell);
+		}
+		break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C __iomem *reg = acb->pmuC;
+		/*
+		** push inbound doorbell tell iop, driver data write ok
+		** and wait reply on next hwinterrupt for next Qbuffer post
+		*/
+		writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK, &reg->inbound_doorbell);
 		}
 		break;
 	}
@@ -1195,7 +1350,6 @@
 struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
 {
 	struct QBUFFER __iomem *qbuffer = NULL;
-
 	switch (acb->adapter_type) {
 
 	case ACB_ADAPTER_TYPE_A: {
@@ -1206,9 +1360,13 @@
 
 	case ACB_ADAPTER_TYPE_B: {
 		struct MessageUnit_B *reg = acb->pmuB;
-		qbuffer = (struct QBUFFER __iomem *)reg->ioctl_rbuffer_reg;
+		qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer;
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC;
+		qbuffer = (struct QBUFFER __iomem *)&phbcmu->message_rbuffer;
+		}
 	}
 	return qbuffer;
 }
@@ -1216,7 +1374,6 @@
 static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb)
 {
 	struct QBUFFER __iomem *pqbuffer = NULL;
-
 	switch (acb->adapter_type) {
 
 	case ACB_ADAPTER_TYPE_A: {
@@ -1227,9 +1384,14 @@
 
 	case ACB_ADAPTER_TYPE_B: {
 		struct MessageUnit_B  *reg = acb->pmuB;
-		pqbuffer = (struct QBUFFER __iomem *)reg->ioctl_wbuffer_reg;
+		pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer;
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+		pqbuffer = (struct QBUFFER __iomem *)&reg->message_wbuffer;
+	}
+
 	}
 	return pqbuffer;
 }
@@ -1240,19 +1402,18 @@
 	struct QBUFFER *pQbuffer;
 	uint8_t __iomem *iop_data;
 	int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
-
 	rqbuf_lastindex = acb->rqbuf_lastindex;
 	rqbuf_firstindex = acb->rqbuf_firstindex;
 	prbuffer = arcmsr_get_iop_rqbuffer(acb);
 	iop_data = (uint8_t __iomem *)prbuffer->data;
 	iop_len = prbuffer->data_len;
-	my_empty_len = (rqbuf_firstindex - rqbuf_lastindex -1)&(ARCMSR_MAX_QBUFFER -1);
+	my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) & (ARCMSR_MAX_QBUFFER - 1);
 
 	if (my_empty_len >= iop_len)
 	{
 		while (iop_len > 0) {
 			pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex];
-			memcpy(pQbuffer, iop_data,1);
+			memcpy(pQbuffer, iop_data, 1);
 			rqbuf_lastindex++;
 			rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
 			iop_data++;
@@ -1303,25 +1464,52 @@
 {
 	uint32_t outbound_doorbell;
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
-
 	outbound_doorbell = readl(&reg->outbound_doorbell);
 	writel(outbound_doorbell, &reg->outbound_doorbell);
 	if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
 		arcmsr_iop2drv_data_wrote_handle(acb);
 	}
 
-	if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) 	{
+	if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
 		arcmsr_iop2drv_data_read_handle(acb);
 	}
 }
-
+static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB)
+{
+	uint32_t outbound_doorbell;
+	struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+	/*
+	*******************************************************************
+	**  Maybe here we need to check wrqbuffer_lock is lock or not
+	**  DOORBELL: din! don!
+	**  check if there are any mail need to pack from firmware
+	*******************************************************************
+	*/
+	outbound_doorbell = readl(&reg->outbound_doorbell);
+	writel(outbound_doorbell, &reg->outbound_doorbell_clear);/*clear interrupt*/
+	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) {
+		arcmsr_iop2drv_data_wrote_handle(pACB);
+	}
+	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) {
+		arcmsr_iop2drv_data_read_handle(pACB);
+	}
+	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+		arcmsr_hbc_message_isr(pACB);    /* messenger of "driver to iop commands" */
+	}
+	return;
+}
 static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
 {
 	uint32_t flag_ccb;
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
-
+	struct ARCMSR_CDB *pARCMSR_CDB;
+	struct CommandControlBlock *pCCB;
+	bool error;
 	while ((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) {
-		arcmsr_drain_donequeue(acb, flag_ccb);
+		pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/
+		pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
+		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+		arcmsr_drain_donequeue(acb, pCCB, error);
 	}
 }
 
@@ -1330,29 +1518,62 @@
 	uint32_t index;
 	uint32_t flag_ccb;
 	struct MessageUnit_B *reg = acb->pmuB;
-
+	struct ARCMSR_CDB *pARCMSR_CDB;
+	struct CommandControlBlock *pCCB;
+	bool error;
 	index = reg->doneq_index;
-
 	while ((flag_ccb = readl(&reg->done_qbuffer[index])) != 0) {
 		writel(0, &reg->done_qbuffer[index]);
-		arcmsr_drain_donequeue(acb, flag_ccb);
+		pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/
+		pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
+		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+		arcmsr_drain_donequeue(acb, pCCB, error);
 		index++;
 		index %= ARCMSR_MAX_HBB_POSTQUEUE;
 		reg->doneq_index = index;
 	}
 }
+
+static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb)
+{
+	struct MessageUnit_C *phbcmu;
+	struct ARCMSR_CDB *arcmsr_cdb;
+	struct CommandControlBlock *ccb;
+	uint32_t flag_ccb, ccb_cdb_phy, throttling = 0;
+	int error;
+
+	phbcmu = (struct MessageUnit_C *)acb->pmuC;
+	/* areca cdb command done */
+	/* Use correct offset and size for syncing */
+
+	while (readl(&phbcmu->host_int_status) &
+	ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR){
+	/* check if command done with no error*/
+	flag_ccb = readl(&phbcmu->outbound_queueport_low);
+	ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);/*frame must be 32 bytes aligned*/
+	arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);
+	ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
+	error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
+	/* check if command done with no error */
+	arcmsr_drain_donequeue(acb, ccb, error);
+	if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) {
+		writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING, &phbcmu->inbound_doorbell);
+		break;
+	}
+	throttling++;
+	}
+}
 /*
 **********************************************************************************
 ** Handle a message interrupt
 **
-** The only message interrupt we expect is in response to a query for the current adapter config.
+** The only message interrupt we expect is in response to a query for the current adapter config.  
 ** We want this in order to compare the drivemap so that we can detect newly-attached drives.
 **********************************************************************************
 */
 static void arcmsr_hba_message_isr(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A *reg  = acb->pmuA;
-
 	/*clear interrupt and message state*/
 	writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, &reg->outbound_intstatus);
 	schedule_work(&acb->arcmsr_do_message_isr_bh);
@@ -1362,16 +1583,32 @@
 	struct MessageUnit_B *reg  = acb->pmuB;
 
 	/*clear interrupt and message state*/
-	writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
+	writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
 	schedule_work(&acb->arcmsr_do_message_isr_bh);
 }
+/*
+**********************************************************************************
+** Handle a message interrupt
+**
+** The only message interrupt we expect is in response to a query for the
+** current adapter config.
+** We want this in order to compare the drivemap so that we can detect newly-attached drives.
+**********************************************************************************
+*/
+static void arcmsr_hbc_message_isr(struct AdapterControlBlock *acb)
+{
+	struct MessageUnit_C *reg  = acb->pmuC;
+	/*clear interrupt and message state*/
+	writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &reg->outbound_doorbell_clear);
+	schedule_work(&acb->arcmsr_do_message_isr_bh);
+}
+
 static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
 {
 	uint32_t outbound_intstatus;
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
-
 	outbound_intstatus = readl(&reg->outbound_intstatus) &
-							acb->outbound_int_enable;
+		acb->outbound_int_enable;
 	if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))	{
 		return 1;
 	}
@@ -1382,7 +1619,7 @@
 	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
 		arcmsr_hba_postqueue_isr(acb);
 	}
-	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) 	{
+	if(outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) 	{
 		/* messenger of "driver to iop commands" */
 		arcmsr_hba_message_isr(acb);
 	}
@@ -1393,18 +1630,17 @@
 {
 	uint32_t outbound_doorbell;
 	struct MessageUnit_B *reg = acb->pmuB;
-
-	outbound_doorbell = readl(reg->iop2drv_doorbell_reg) &
-							acb->outbound_int_enable;
+	outbound_doorbell = readl(reg->iop2drv_doorbell) &
+				acb->outbound_int_enable;
 	if (!outbound_doorbell)
 		return 1;
 
-	writel(~outbound_doorbell, reg->iop2drv_doorbell_reg);
+	writel(~outbound_doorbell, reg->iop2drv_doorbell);
 	/*in case the last action of doorbell interrupt clearance is cached,
 	this action can push HW to write down the clear bit*/
-	readl(reg->iop2drv_doorbell_reg);
-	writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
-	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) 	{
+	readl(reg->iop2drv_doorbell);
+	writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
+	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) {
 		arcmsr_iop2drv_data_wrote_handle(acb);
 	}
 	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) {
@@ -1413,14 +1649,37 @@
 	if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) {
 		arcmsr_hbb_postqueue_isr(acb);
 	}
-	if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
+	if(outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
 		/* messenger of "driver to iop commands" */
 		arcmsr_hbb_message_isr(acb);
 	}
-
 	return 0;
 }
 
+static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB)
+{
+	uint32_t host_interrupt_status;
+	struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+	/*
+	*********************************************
+	**   check outbound intstatus
+	*********************************************
+	*/
+	host_interrupt_status = readl(&phbcmu->host_int_status);
+	if (!host_interrupt_status) {
+		/*it must be share irq*/
+		return 1;
+	}
+	/* MU ioctl transfer doorbell interrupts*/
+	if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) {
+		arcmsr_hbc_doorbell_isr(pACB);   /* messenger of "ioctl message read write" */
+	}
+	/* MU post queue interrupts*/
+	if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) {
+		arcmsr_hbc_postqueue_isr(pACB);  /* messenger of "scsi commands" */
+	}
+	return 0;
+}
 static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
@@ -1437,6 +1696,11 @@
 		}
 		}
 		break;
+	 case ACB_ADAPTER_TYPE_C: {
+		if (arcmsr_handle_hbc_isr(acb)) {
+			return IRQ_NONE;
+		}
+		}
 	}
 	return IRQ_HANDLED;
 }
@@ -1463,7 +1727,6 @@
 	struct QBUFFER __iomem *pwbuffer;
 	uint8_t __iomem *iop_data;
 	int32_t allxfer_len = 0;
-
 	pwbuffer = arcmsr_get_iop_wqbuffer(acb);
 	iop_data = (uint8_t __iomem *)pwbuffer->data;
 	if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
@@ -1496,7 +1759,6 @@
 						(uint32_t ) cmd->cmnd[7] << 8  |
 						(uint32_t ) cmd->cmnd[8];
 						/* 4 bytes: Areca io control code */
-
 	sg = scsi_sglist(cmd);
 	buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
 	if (scsi_sg_count(cmd) > 1) {
@@ -1522,13 +1784,7 @@
 			retvalue = ARCMSR_MESSAGE_FAIL;
 			goto message_out;
 		}
-
-		if (!acb->fw_state) {
-			pcmdmessagefld->cmdmessage.ReturnCode =
-			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-			goto message_out;
-		}
-
+				
 		ptmpQbuffer = ver_addr;
 		while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
 			&& (allxfer_len < 1031)) {
@@ -1560,7 +1816,11 @@
 		}
 		memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len);
 		pcmdmessagefld->cmdmessage.Length = allxfer_len;
-		pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+		if(acb->fw_flag == FW_DEADLOCK) {
+			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+		}else{
+			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+		}
 		kfree(ver_addr);
 		}
 		break;
@@ -1575,12 +1835,13 @@
 			retvalue = ARCMSR_MESSAGE_FAIL;
 			goto message_out;
 		}
-		if (!acb->fw_state) {
-			pcmdmessagefld->cmdmessage.ReturnCode =
+		if(acb->fw_flag == FW_DEADLOCK) {
+			pcmdmessagefld->cmdmessage.ReturnCode = 
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-			goto message_out;
+		}else{
+			pcmdmessagefld->cmdmessage.ReturnCode = 
+			ARCMSR_MESSAGE_RETURNCODE_OK;
 		}
-
 		ptmpuserbuffer = ver_addr;
 		user_len = pcmdmessagefld->cmdmessage.Length;
 		memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
@@ -1633,12 +1894,6 @@
 
 	case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
 		uint8_t *pQbuffer = acb->rqbuffer;
-		if (!acb->fw_state) {
-			pcmdmessagefld->cmdmessage.ReturnCode =
-			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-			goto message_out;
-		}
-
 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
 			arcmsr_iop_message_read(acb);
@@ -1647,16 +1902,24 @@
 		acb->rqbuf_firstindex = 0;
 		acb->rqbuf_lastindex = 0;
 		memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
-		pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+		if(acb->fw_flag == FW_DEADLOCK) {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+		}else{
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_OK;
+		}
 		}
 		break;
 
 	case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
 		uint8_t *pQbuffer = acb->wqbuffer;
-		if (!acb->fw_state) {
+		if(acb->fw_flag == FW_DEADLOCK) {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-			goto message_out;
+		}else{
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_OK;
 		}
 
 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
@@ -1669,18 +1932,11 @@
 		acb->wqbuf_firstindex = 0;
 		acb->wqbuf_lastindex = 0;
 		memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
-		pcmdmessagefld->cmdmessage.ReturnCode =
-			ARCMSR_MESSAGE_RETURNCODE_OK;
 		}
 		break;
 
 	case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
 		uint8_t *pQbuffer;
-		if (!acb->fw_state) {
-			pcmdmessagefld->cmdmessage.ReturnCode =
-			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-			goto message_out;
-		}
 
 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
@@ -1698,47 +1954,52 @@
 		memset(pQbuffer, 0, sizeof(struct QBUFFER));
 		pQbuffer = acb->wqbuffer;
 		memset(pQbuffer, 0, sizeof(struct QBUFFER));
-		pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+		if(acb->fw_flag == FW_DEADLOCK) {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+		}else{
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_OK;
+		}
 		}
 		break;
 
 	case ARCMSR_MESSAGE_RETURN_CODE_3F: {
-		if (!acb->fw_state) {
+		if(acb->fw_flag == FW_DEADLOCK) {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-			goto message_out;
-		}
-		pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
+		}else{
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_3F;
 		}
 		break;
-
+		}
 	case ARCMSR_MESSAGE_SAY_HELLO: {
 		int8_t *hello_string = "Hello! I am ARCMSR";
-		if (!acb->fw_state) {
+		if(acb->fw_flag == FW_DEADLOCK) {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-			goto message_out;
+		}else{
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_OK;
 		}
 		memcpy(pcmdmessagefld->messagedatabuffer, hello_string
 			, (int16_t)strlen(hello_string));
-		pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
 		}
 		break;
 
 	case ARCMSR_MESSAGE_SAY_GOODBYE:
-		if (!acb->fw_state) {
+		if(acb->fw_flag == FW_DEADLOCK) {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-			goto message_out;
 		}
 		arcmsr_iop_parking(acb);
 		break;
 
 	case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
-		if (!acb->fw_state) {
+		if(acb->fw_flag == FW_DEADLOCK) {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-			goto message_out;
 		}
 		arcmsr_flush_adapter_cache(acb);
 		break;
@@ -1756,11 +2017,16 @@
 {
 	struct list_head *head = &acb->ccb_free_list;
 	struct CommandControlBlock *ccb = NULL;
-
+	unsigned long flags;
+	spin_lock_irqsave(&acb->ccblist_lock, flags);
 	if (!list_empty(head)) {
 		ccb = list_entry(head->next, struct CommandControlBlock, list);
-		list_del(head->next);
+		list_del_init(&ccb->list);
+	}else{
+		spin_unlock_irqrestore(&acb->ccblist_lock, flags);
+		return 0;
 	}
+	spin_unlock_irqrestore(&acb->ccblist_lock, flags);
 	return ccb;
 }
 
@@ -1826,83 +2092,29 @@
 	cmd->scsi_done = done;
 	cmd->host_scribble = NULL;
 	cmd->result = 0;
-
-	if ((scsicmd == SYNCHRONIZE_CACHE) || (scsicmd == SEND_DIAGNOSTIC)) {
-		if (acb->devstate[target][lun] == ARECA_RAID_GONE) {
-			cmd->result = (DID_NO_CONNECT << 16);
+	if ((scsicmd == SYNCHRONIZE_CACHE) ||(scsicmd == SEND_DIAGNOSTIC)){
+		if(acb->devstate[target][lun] == ARECA_RAID_GONE) {
+    			cmd->result = (DID_NO_CONNECT << 16);
 		}
 		cmd->scsi_done(cmd);
 		return 0;
 	}
-
-	if (acb->acb_flags & ACB_F_BUS_RESET) {
-		switch (acb->adapter_type) {
-			case ACB_ADAPTER_TYPE_A: {
-				struct MessageUnit_A __iomem *reg = acb->pmuA;
-				uint32_t intmask_org, outbound_doorbell;
-
-				if ((readl(&reg->outbound_msgaddr1) &
-					ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
-					printk(KERN_NOTICE "arcmsr%d: bus reset and return busy\n",
-						acb->host->host_no);
-		return SCSI_MLQUEUE_HOST_BUSY;
-	}
-
-				acb->acb_flags &= ~ACB_F_FIRMWARE_TRAP;
-				printk(KERN_NOTICE "arcmsr%d: hardware bus reset and reset ok\n",
-					acb->host->host_no);
-				/* disable all outbound interrupt */
-				intmask_org = arcmsr_disable_outbound_ints(acb);
-				arcmsr_get_firmware_spec(acb, 1);
-				/*start background rebuild*/
-				arcmsr_start_adapter_bgrb(acb);
-				/* clear Qbuffer if door bell ringed */
-				outbound_doorbell = readl(&reg->outbound_doorbell);
-				/*clear interrupt */
-				writel(outbound_doorbell, &reg->outbound_doorbell);
-				writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
-					&reg->inbound_doorbell);
-				/* enable outbound Post Queue,outbound doorbell Interrupt */
-				arcmsr_enable_outbound_ints(acb, intmask_org);
-				acb->acb_flags |= ACB_F_IOP_INITED;
-				acb->acb_flags &= ~ACB_F_BUS_RESET;
-			}
-			break;
-			case ACB_ADAPTER_TYPE_B: {
-			}
-		}
-	}
-
 	if (target == 16) {
 		/* virtual device for iop message transfer */
 		arcmsr_handle_virtual_command(acb, cmd);
 		return 0;
 	}
-	if (acb->devstate[target][lun] == ARECA_RAID_GONE) {
-		uint8_t block_cmd;
-
-		block_cmd = cmd->cmnd[0] & 0x0f;
-		if (block_cmd == 0x08 || block_cmd == 0x0a) {
-			printk(KERN_NOTICE
-				"arcmsr%d: block 'read/write'"
-				"command with gone raid volume"
-				" Cmd = %2x, TargetId = %d, Lun = %d \n"
-				, acb->host->host_no
-				, cmd->cmnd[0]
-				, target, lun);
-			cmd->result = (DID_NO_CONNECT << 16);
-			cmd->scsi_done(cmd);
-			return 0;
-		}
-	}
 	if (atomic_read(&acb->ccboutstandingcount) >=
 			ARCMSR_MAX_OUTSTANDING_CMD)
 		return SCSI_MLQUEUE_HOST_BUSY;
-
+	if ((scsicmd == SCSI_CMD_ARECA_SPECIFIC)) {
+		printk(KERN_NOTICE "Receiveing SCSI_CMD_ARECA_SPECIFIC command..\n");
+		return 0;
+	}
 	ccb = arcmsr_get_freeccb(acb);
 	if (!ccb)
 		return SCSI_MLQUEUE_HOST_BUSY;
-	if ( arcmsr_build_ccb( acb, ccb, cmd ) == FAILED ) {
+	if (arcmsr_build_ccb( acb, ccb, cmd ) == FAILED) {
 		cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1);
 		cmd->scsi_done(cmd);
 		return 0;
@@ -1911,7 +2123,7 @@
 	return 0;
 }
 
-static void *arcmsr_get_hba_config(struct AdapterControlBlock *acb, int mode)
+static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
 	char *acb_firm_model = acb->firm_model;
@@ -1919,19 +2131,16 @@
 	char *acb_device_map = acb->device_map;
 	char __iomem *iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]);
 	char __iomem *iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]);
-	char __iomem *iop_device_map = (char __iomem *) (&reg->message_rwbuffer[21]);
+	char __iomem *iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]);
 	int count;
-
 	writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
-	if (arcmsr_hba_wait_msgint_ready(acb)) {
+	if (!arcmsr_hba_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
 			miscellaneous data' timeout \n", acb->host->host_no);
-		return NULL;
+		return false;
 	}
-
-	if (mode == 1) {
 	count = 8;
-	while (count) {
+	while (count){
 		*acb_firm_model = readb(iop_firm_model);
 		acb_firm_model++;
 		iop_firm_model++;
@@ -1939,138 +2148,213 @@
 	}
 
 	count = 16;
-	while (count) {
+	while (count){
 		*acb_firm_version = readb(iop_firm_version);
 		acb_firm_version++;
 		iop_firm_version++;
 		count--;
 	}
 
-		count = 16;
-		while (count) {
-			*acb_device_map = readb(iop_device_map);
-			acb_device_map++;
-			iop_device_map++;
-			count--;
-		}
-
-	printk(KERN_INFO 	"ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
-		, acb->host->host_no
-		, acb->firm_version);
-		acb->signature = readl(&reg->message_rwbuffer[0]);
+	count=16;
+	while(count){
+		*acb_device_map = readb(iop_device_map);
+		acb_device_map++;
+		iop_device_map++;
+		count--;
+	}
+	printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", 
+		acb->host->host_no,
+		acb->firm_version,
+		acb->firm_model);
+	acb->signature = readl(&reg->message_rwbuffer[0]);
 	acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
 	acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
 	acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
 	acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
+	acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]);  /*firm_cfg_version,25,100-103*/
+	return true;
 }
-	return reg->message_rwbuffer;
-}
-static void __iomem *arcmsr_get_hbb_config(struct AdapterControlBlock *acb, int mode)
+static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_B *reg = acb->pmuB;
-	uint32_t __iomem *lrwbuffer = reg->msgcode_rwbuffer_reg;
+	struct pci_dev *pdev = acb->pdev;
+	void *dma_coherent;
+	dma_addr_t dma_coherent_handle;
 	char *acb_firm_model = acb->firm_model;
 	char *acb_firm_version = acb->firm_version;
 	char *acb_device_map = acb->device_map;
-	char __iomem *iop_firm_model = (char __iomem *)(&lrwbuffer[15]);
+	char __iomem *iop_firm_model;
 	/*firm_model,15,60-67*/
-	char __iomem *iop_firm_version = (char __iomem *)(&lrwbuffer[17]);
+	char __iomem *iop_firm_version;
 	/*firm_version,17,68-83*/
-	char __iomem *iop_device_map = (char __iomem *) (&lrwbuffer[21]);
+	char __iomem *iop_device_map;
 	/*firm_version,21,84-99*/
 	int count;
+	dma_coherent = dma_alloc_coherent(&pdev->dev, sizeof(struct MessageUnit_B), &dma_coherent_handle, GFP_KERNEL);
+	if (!dma_coherent){
+		printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error for hbb mu\n", acb->host->host_no);
+		return false;
+	}
+	acb->dma_coherent_handle_hbb_mu = dma_coherent_handle;
+	reg = (struct MessageUnit_B *)dma_coherent;
+	acb->pmuB = reg;
+	reg->drv2iop_doorbell= (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL);
+	reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK);
+	reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL);
+	reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK);
+	reg->message_wbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_WBUFFER);
+	reg->message_rbuffer =  (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RBUFFER);
+	reg->message_rwbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RWBUFFER);
+	iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]);	/*firm_model,15,60-67*/
+	iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]);	/*firm_version,17,68-83*/
+	iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]);	/*firm_version,21,84-99*/
 
-	writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg);
-	if (arcmsr_hbb_wait_msgint_ready(acb)) {
+	writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
+	if (!arcmsr_hbb_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
 			miscellaneous data' timeout \n", acb->host->host_no);
-		return NULL;
+		return false;
 	}
-
-	if (mode == 1) {
 	count = 8;
-	while (count)
-	{
+	while (count){
 		*acb_firm_model = readb(iop_firm_model);
 		acb_firm_model++;
 		iop_firm_model++;
 		count--;
 	}
-
 	count = 16;
-	while (count)
-	{
+	while (count){
 		*acb_firm_version = readb(iop_firm_version);
 		acb_firm_version++;
 		iop_firm_version++;
 		count--;
 	}
 
-		count = 16;
-		while (count) {
-			*acb_device_map = readb(iop_device_map);
-			acb_device_map++;
-			iop_device_map++;
-			count--;
-		}
-
-	printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n",
-			acb->host->host_no,
-			acb->firm_version);
-
-		acb->signature = readl(lrwbuffer++);
-		/*firm_signature,1,00-03*/
-	acb->firm_request_len = readl(lrwbuffer++);
-	/*firm_request_len,1,04-07*/
-	acb->firm_numbers_queue = readl(lrwbuffer++);
-	/*firm_numbers_queue,2,08-11*/
-	acb->firm_sdram_size = readl(lrwbuffer++);
-	/*firm_sdram_size,3,12-15*/
-	acb->firm_hd_channels = readl(lrwbuffer);
-	/*firm_ide_channels,4,16-19*/
-}
-	return reg->msgcode_rwbuffer_reg;
-}
-static void *arcmsr_get_firmware_spec(struct AdapterControlBlock *acb, int mode)
-{
-	void *rtnval = 0;
-	switch (acb->adapter_type) {
-	case ACB_ADAPTER_TYPE_A: {
-		rtnval = arcmsr_get_hba_config(acb, mode);
-		}
-		break;
-
-	case ACB_ADAPTER_TYPE_B: {
-		rtnval = arcmsr_get_hbb_config(acb, mode);
-		}
-		break;
+	count = 16;
+	while(count){
+		*acb_device_map = readb(iop_device_map);
+		acb_device_map++;
+		iop_device_map++;
+		count--;
 	}
-	return rtnval;
+	
+	printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n",
+		acb->host->host_no,
+		acb->firm_version,
+		acb->firm_model);
+
+	acb->signature = readl(&reg->message_rwbuffer[1]);
+	/*firm_signature,1,00-03*/
+	acb->firm_request_len = readl(&reg->message_rwbuffer[2]);
+	/*firm_request_len,1,04-07*/
+	acb->firm_numbers_queue = readl(&reg->message_rwbuffer[3]);
+	/*firm_numbers_queue,2,08-11*/
+	acb->firm_sdram_size = readl(&reg->message_rwbuffer[4]);
+	/*firm_sdram_size,3,12-15*/
+	acb->firm_hd_channels = readl(&reg->message_rwbuffer[5]);
+	/*firm_ide_channels,4,16-19*/
+	acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]);  /*firm_cfg_version,25,100-103*/
+	/*firm_ide_channels,4,16-19*/
+	return true;
 }
 
-static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
+static bool arcmsr_get_hbc_config(struct AdapterControlBlock *pACB)
+{
+	uint32_t intmask_org, Index, firmware_state = 0;
+	struct MessageUnit_C *reg = pACB->pmuC;
+	char *acb_firm_model = pACB->firm_model;
+	char *acb_firm_version = pACB->firm_version;
+	char *iop_firm_model = (char *)(&reg->msgcode_rwbuffer[15]);    /*firm_model,15,60-67*/
+	char *iop_firm_version = (char *)(&reg->msgcode_rwbuffer[17]);  /*firm_version,17,68-83*/
+	int count;
+	/* disable all outbound interrupt */
+	intmask_org = readl(&reg->host_int_mask); /* disable outbound message0 int */
+	writel(intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE, &reg->host_int_mask);
+	/* wait firmware ready */
+	do {
+		firmware_state = readl(&reg->outbound_msgaddr1);
+	} while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
+	/* post "get config" instruction */
+	writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
+	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+	/* wait message ready */
+	for (Index = 0; Index < 2000; Index++) {
+		if (readl(&reg->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+			writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &reg->outbound_doorbell_clear);/*clear interrupt*/
+			break;
+		}
+		udelay(10);
+	} /*max 1 seconds*/
+	if (Index >= 2000) {
+		printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
+			miscellaneous data' timeout \n", pACB->host->host_no);
+		return false;
+	}
+	count = 8;
+	while (count) {
+		*acb_firm_model = readb(iop_firm_model);
+		acb_firm_model++;
+		iop_firm_model++;
+		count--;
+	}
+	count = 16;
+	while (count) {
+		*acb_firm_version = readb(iop_firm_version);
+		acb_firm_version++;
+		iop_firm_version++;
+		count--;
+	}
+	printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n",
+		pACB->host->host_no,
+		pACB->firm_version,
+		pACB->firm_model);
+	pACB->firm_request_len = readl(&reg->msgcode_rwbuffer[1]);   /*firm_request_len,1,04-07*/
+	pACB->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[2]); /*firm_numbers_queue,2,08-11*/
+	pACB->firm_sdram_size = readl(&reg->msgcode_rwbuffer[3]);    /*firm_sdram_size,3,12-15*/
+	pACB->firm_hd_channels = readl(&reg->msgcode_rwbuffer[4]);  /*firm_ide_channels,4,16-19*/
+	pACB->firm_cfg_version = readl(&reg->msgcode_rwbuffer[25]);  /*firm_cfg_version,25,100-103*/
+	/*all interrupt service will be enable at arcmsr_iop_init*/
+	return true;
+}
+static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
+{
+	if (acb->adapter_type == ACB_ADAPTER_TYPE_A)
+		return arcmsr_get_hba_config(acb);
+	else if (acb->adapter_type == ACB_ADAPTER_TYPE_B)
+		return arcmsr_get_hbb_config(acb);
+	else
+		return arcmsr_get_hbc_config(acb);
+}
+
+static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
 	struct CommandControlBlock *poll_ccb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
 	struct CommandControlBlock *ccb;
+	struct ARCMSR_CDB *arcmsr_cdb;
 	uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
-
+	int rtn;
+	bool error;
 	polling_hba_ccb_retry:
 	poll_count++;
 	outbound_intstatus = readl(&reg->outbound_intstatus) & acb->outbound_int_enable;
 	writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
 	while (1) {
 		if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF) {
-			if (poll_ccb_done)
+			if (poll_ccb_done){
+				rtn = SUCCESS;
 				break;
-			else {
+			}else {
 				msleep(25);
-				if (poll_count > 100)
+				if (poll_count > 100){
+					rtn = FAILED;
 					break;
+				}
 				goto polling_hba_ccb_retry;
 			}
 		}
-		ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5));
+		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
+		ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
 		poll_ccb_done = (ccb == poll_ccb) ? 1:0;
 		if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
 			if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
@@ -2081,8 +2365,7 @@
 					, ccb->pcmd->device->lun
 					, ccb);
 				ccb->pcmd->result = DID_ABORT << 16;
-				arcmsr_ccb_complete(ccb, 1);
-				poll_ccb_done = 1;
+				arcmsr_ccb_complete(ccb);
 				continue;
 			}
 			printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
@@ -2093,86 +2376,156 @@
 				, atomic_read(&acb->ccboutstandingcount));
 			continue;
 		}
-		arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+		arcmsr_report_ccb_state(acb, ccb, error);
 	}
+	return rtn;
 }
 
-static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
+static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
 					struct CommandControlBlock *poll_ccb)
 {
-		struct MessageUnit_B *reg = acb->pmuB;
-		struct CommandControlBlock *ccb;
-		uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
-		int index;
-
+	struct MessageUnit_B *reg = acb->pmuB;
+	struct ARCMSR_CDB *arcmsr_cdb;
+	struct CommandControlBlock *ccb;
+	uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
+	int index, rtn;
+	bool error;
 	polling_hbb_ccb_retry:
-		poll_count++;
-		/* clear doorbell interrupt */
-		writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
-		while (1) {
-			index = reg->doneq_index;
-			if ((flag_ccb = readl(&reg->done_qbuffer[index])) == 0) {
-				if (poll_ccb_done)
+	poll_count++;
+	/* clear doorbell interrupt */
+	writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
+	while(1){
+		index = reg->doneq_index;
+		if ((flag_ccb = readl(&reg->done_qbuffer[index])) == 0) {
+			if (poll_ccb_done){
+				rtn = SUCCESS;
+				break;
+			}else {
+				msleep(25);
+				if (poll_count > 100){
+					rtn = FAILED;
 					break;
-				else {
-					msleep(25);
-					if (poll_count > 100)
-						break;
-					goto polling_hbb_ccb_retry;
 				}
+				goto polling_hbb_ccb_retry;
 			}
-			writel(0, &reg->done_qbuffer[index]);
-			index++;
-			/*if last index number set it to 0 */
-			index %= ARCMSR_MAX_HBB_POSTQUEUE;
-			reg->doneq_index = index;
-			/* check ifcommand done with no error*/
-			ccb = (struct CommandControlBlock *)\
-      (acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/
-			poll_ccb_done = (ccb == poll_ccb) ? 1:0;
-			if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
-				if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
-					printk(KERN_NOTICE "arcmsr%d: \
-		scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n"
-						,acb->host->host_no
-						,ccb->pcmd->device->id
-						,ccb->pcmd->device->lun
-						,ccb);
-					ccb->pcmd->result = DID_ABORT << 16;
-					arcmsr_ccb_complete(ccb, 1);
-					continue;
-				}
-				printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
-					" command done ccb = '0x%p'"
-					"ccboutstandingcount = %d \n"
-					, acb->host->host_no
-					, ccb
-					, atomic_read(&acb->ccboutstandingcount));
+		}
+		writel(0, &reg->done_qbuffer[index]);
+		index++;
+		/*if last index number set it to 0 */
+		index %= ARCMSR_MAX_HBB_POSTQUEUE;
+		reg->doneq_index = index;
+		/* check if command done with no error*/
+		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
+		ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
+		poll_ccb_done = (ccb == poll_ccb) ? 1:0;
+		if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
+			if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
+				printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
+					" poll command abort successfully \n"
+					,acb->host->host_no
+					,ccb->pcmd->device->id
+					,ccb->pcmd->device->lun
+					,ccb);
+				ccb->pcmd->result = DID_ABORT << 16;
+				arcmsr_ccb_complete(ccb);
 				continue;
 			}
-			arcmsr_report_ccb_state(acb, ccb, flag_ccb);
-		}	/*drain reply FIFO*/
+			printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
+				" command done ccb = '0x%p'"
+				"ccboutstandingcount = %d \n"
+				, acb->host->host_no
+				, ccb
+				, atomic_read(&acb->ccboutstandingcount));
+			continue;
+		} 
+		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+		arcmsr_report_ccb_state(acb, ccb, error);
+	}
+	return rtn;
 }
 
-static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
+static int arcmsr_polling_hbc_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb)
+{
+	struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+	uint32_t flag_ccb, ccb_cdb_phy;
+	struct ARCMSR_CDB *arcmsr_cdb;
+	bool error;
+	struct CommandControlBlock *pCCB;
+	uint32_t poll_ccb_done = 0, poll_count = 0;
+	int rtn;
+polling_hbc_ccb_retry:
+	poll_count++;
+	while (1) {
+		if ((readl(&reg->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) == 0) {
+			if (poll_ccb_done) {
+				rtn = SUCCESS;
+				break;
+			} else {
+				msleep(25);
+				if (poll_count > 100) {
+					rtn = FAILED;
+					break;
+				}
+				goto polling_hbc_ccb_retry;
+			}
+		}
+		flag_ccb = readl(&reg->outbound_queueport_low);
+		ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
+		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);/*frame must be 32 bytes aligned*/
+		pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
+		poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0;
+		/* check ifcommand done with no error*/
+		if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
+			if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
+				printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
+					" poll command abort successfully \n"
+					, acb->host->host_no
+					, pCCB->pcmd->device->id
+					, pCCB->pcmd->device->lun
+					, pCCB);
+					pCCB->pcmd->result = DID_ABORT << 16;
+					arcmsr_ccb_complete(pCCB);
+				continue;
+			}
+			printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
+				" command done ccb = '0x%p'"
+				"ccboutstandingcount = %d \n"
+				, acb->host->host_no
+				, pCCB
+				, atomic_read(&acb->ccboutstandingcount));
+			continue;
+		}
+		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
+		arcmsr_report_ccb_state(acb, pCCB, error);
+	}
+	return rtn;
+}
+static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
 					struct CommandControlBlock *poll_ccb)
 {
+	int rtn = 0;
 	switch (acb->adapter_type) {
 
 	case ACB_ADAPTER_TYPE_A: {
-		arcmsr_polling_hba_ccbdone(acb,poll_ccb);
+		rtn = arcmsr_polling_hba_ccbdone(acb, poll_ccb);
 		}
 		break;
 
 	case ACB_ADAPTER_TYPE_B: {
-		arcmsr_polling_hbb_ccbdone(acb,poll_ccb);
+		rtn = arcmsr_polling_hbb_ccbdone(acb, poll_ccb);
+		}
+		break;
+	case ACB_ADAPTER_TYPE_C: {
+		rtn = arcmsr_polling_hbc_ccbdone(acb, poll_ccb);
 		}
 	}
+	return rtn;
 }
 
 static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
 {
-	uint32_t cdb_phyaddr, ccb_phyaddr_hi32;
+	uint32_t cdb_phyaddr, cdb_phyaddr_hi32;
 	dma_addr_t dma_coherent_handle;
 	/*
 	********************************************************************
@@ -2182,7 +2535,8 @@
 	*/
 	dma_coherent_handle = acb->dma_coherent_handle;
 	cdb_phyaddr = (uint32_t)(dma_coherent_handle);
-	ccb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+	cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+	acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32;
 	/*
 	***********************************************************************
 	**    if adapter type B, set window of "post command Q"
@@ -2191,16 +2545,16 @@
 	switch (acb->adapter_type) {
 
 	case ACB_ADAPTER_TYPE_A: {
-		if (ccb_phyaddr_hi32 != 0) {
+		if (cdb_phyaddr_hi32 != 0) {
 			struct MessageUnit_A __iomem *reg = acb->pmuA;
 			uint32_t intmask_org;
 			intmask_org = arcmsr_disable_outbound_ints(acb);
 			writel(ARCMSR_SIGNATURE_SET_CONFIG, \
 						&reg->message_rwbuffer[0]);
-			writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);
+			writel(cdb_phyaddr_hi32, &reg->message_rwbuffer[1]);
 			writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \
 							&reg->inbound_msgaddr0);
-			if (arcmsr_hba_wait_msgint_ready(acb)) {
+			if (!arcmsr_hba_wait_msgint_ready(acb)) {
 				printk(KERN_NOTICE "arcmsr%d: ""set ccb high \
 				part physical address timeout\n",
 				acb->host->host_no);
@@ -2220,19 +2574,18 @@
 		intmask_org = arcmsr_disable_outbound_ints(acb);
 		reg->postq_index = 0;
 		reg->doneq_index = 0;
-		writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell_reg);
-		if (arcmsr_hbb_wait_msgint_ready(acb)) {
+		writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell);
+		if (!arcmsr_hbb_wait_msgint_ready(acb)) {
 			printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \
 				acb->host->host_no);
 			return 1;
 		}
-		post_queue_phyaddr = cdb_phyaddr + ARCMSR_MAX_FREECCB_NUM * \
-		sizeof(struct CommandControlBlock) + offsetof(struct MessageUnit_B, post_qbuffer) ;
-		rwbuffer = reg->msgcode_rwbuffer_reg;
+		post_queue_phyaddr = acb->dma_coherent_handle_hbb_mu;
+		rwbuffer = reg->message_rwbuffer;
 		/* driver "set config" signature */
 		writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
 		/* normal should be zero */
-		writel(ccb_phyaddr_hi32, rwbuffer++);
+		writel(cdb_phyaddr_hi32, rwbuffer++);
 		/* postQ size (256 + 8)*4	 */
 		writel(post_queue_phyaddr, rwbuffer++);
 		/* doneQ size (256 + 8)*4	 */
@@ -2240,22 +2593,37 @@
 		/* ccb maxQ size must be --> [(256 + 8)*4]*/
 		writel(1056, rwbuffer);
 
-		writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell_reg);
-		if (arcmsr_hbb_wait_msgint_ready(acb)) {
+		writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell);
+		if (!arcmsr_hbb_wait_msgint_ready(acb)) {
 			printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
 			timeout \n",acb->host->host_no);
 			return 1;
 		}
-
-		writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell_reg);
-		if (arcmsr_hbb_wait_msgint_ready(acb)) {
-			printk(KERN_NOTICE "arcmsr%d: 'can not set diver mode \n"\
-			,acb->host->host_no);
-			return 1;
-		}
+		arcmsr_hbb_enable_driver_mode(acb);
 		arcmsr_enable_outbound_ints(acb, intmask_org);
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		if (cdb_phyaddr_hi32 != 0) {
+			struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+
+			if (cdb_phyaddr_hi32 != 0) {
+				unsigned char Retries = 0x00;
+				do {
+					printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x \n", acb->adapter_index, cdb_phyaddr_hi32);
+				} while (Retries++ < 100);
+			}
+			writel(ARCMSR_SIGNATURE_SET_CONFIG, &reg->msgcode_rwbuffer[0]);
+			writel(cdb_phyaddr_hi32, &reg->msgcode_rwbuffer[1]);
+			writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg->inbound_msgaddr0);
+			writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+			if (!arcmsr_hbc_wait_msgint_ready(acb)) {
+				printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
+				timeout \n", acb->host->host_no);
+				return 1;
+			}
+		}
+		}
 	}
 	return 0;
 }
@@ -2263,7 +2631,6 @@
 static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
 {
 	uint32_t firmware_state = 0;
-
 	switch (acb->adapter_type) {
 
 	case ACB_ADAPTER_TYPE_A: {
@@ -2277,62 +2644,81 @@
 	case ACB_ADAPTER_TYPE_B: {
 		struct MessageUnit_B *reg = acb->pmuB;
 		do {
-			firmware_state = readl(reg->iop2drv_doorbell_reg);
+			firmware_state = readl(reg->iop2drv_doorbell);
 		} while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
-		writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
+		writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+		do {
+			firmware_state = readl(&reg->outbound_msgaddr1);
+		} while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
+		}
 	}
 }
 
 static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
-
-	if (unlikely(atomic_read(&acb->rq_map_token) == 0)) {
-		acb->fw_state = false;
+	if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){
+		return;
 	} else {
-	/*to prevent rq_map_token from changing by other interrupt, then
-	avoid the dead-lock*/
-		acb->fw_state = true;
-		atomic_dec(&acb->rq_map_token);
-		if (!(acb->fw_state) ||
-			(acb->ante_token_value == atomic_read(&acb->rq_map_token))) {
+		acb->fw_flag = FW_NORMAL;
+		if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)){
 			atomic_set(&acb->rq_map_token, 16);
 		}
-		acb->ante_token_value = atomic_read(&acb->rq_map_token);
+		atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+		if (atomic_dec_and_test(&acb->rq_map_token))
+			return;
 		writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
+		mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
 	}
-	mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6000));
 	return;
 }
 
 static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_B __iomem *reg = acb->pmuB;
-
-	if (unlikely(atomic_read(&acb->rq_map_token) == 0)) {
-		acb->fw_state = false;
+	if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){
+		return;
 	} else {
-	/*to prevent rq_map_token from changing by other interrupt, then
-	avoid the dead-lock*/
-		acb->fw_state = true;
-		atomic_dec(&acb->rq_map_token);
-		if (!(acb->fw_state) ||
-			(acb->ante_token_value == atomic_read(&acb->rq_map_token))) {
+		acb->fw_flag = FW_NORMAL;
+		if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
+			atomic_set(&acb->rq_map_token,16);
+		}
+		atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+		if(atomic_dec_and_test(&acb->rq_map_token))
+			return;
+		writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
+		mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+	}
+	return;
+}
+
+static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb)
+{
+	struct MessageUnit_C __iomem *reg = acb->pmuC;
+	if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) {
+		return;
+	} else {
+		acb->fw_flag = FW_NORMAL;
+		if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
 			atomic_set(&acb->rq_map_token, 16);
 		}
-		acb->ante_token_value = atomic_read(&acb->rq_map_token);
-		writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg);
+		atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+		if (atomic_dec_and_test(&acb->rq_map_token))
+			return;
+		writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
+		writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+		mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
 	}
-	mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6000));
 	return;
 }
 
 static void arcmsr_request_device_map(unsigned long pacb)
 {
 	struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb;
-
 	switch (acb->adapter_type) {
 		case ACB_ADAPTER_TYPE_A: {
 			arcmsr_request_hba_device_map(acb);
@@ -2342,6 +2728,9 @@
 			arcmsr_request_hbb_device_map(acb);
 		}
 		break;
+		case ACB_ADAPTER_TYPE_C: {
+			arcmsr_request_hbc_device_map(acb);
+		}
 	}
 }
 
@@ -2350,7 +2739,7 @@
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
 	acb->acb_flags |= ACB_F_MSG_START_BGRB;
 	writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
-	if (arcmsr_hba_wait_msgint_ready(acb)) {
+	if (!arcmsr_hba_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
 				rebulid' timeout \n", acb->host->host_no);
 	}
@@ -2360,13 +2749,25 @@
 {
 	struct MessageUnit_B *reg = acb->pmuB;
 	acb->acb_flags |= ACB_F_MSG_START_BGRB;
-	writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell_reg);
-	if (arcmsr_hbb_wait_msgint_ready(acb)) {
+	writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell);
+	if (!arcmsr_hbb_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
 				rebulid' timeout \n",acb->host->host_no);
 	}
 }
 
+static void arcmsr_start_hbc_bgrb(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+	pACB->acb_flags |= ACB_F_MSG_START_BGRB;
+	writel(ARCMSR_INBOUND_MESG0_START_BGRB, &phbcmu->inbound_msgaddr0);
+	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell);
+	if (!arcmsr_hbc_wait_msgint_ready(pACB)) {
+		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
+				rebulid' timeout \n", pACB->host->host_no);
+	}
+	return;
+}
 static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
@@ -2376,6 +2777,8 @@
 	case ACB_ADAPTER_TYPE_B:
 		arcmsr_start_hbb_bgrb(acb);
 		break;
+	case ACB_ADAPTER_TYPE_C:
+		arcmsr_start_hbc_bgrb(acb);
 	}
 }
 
@@ -2396,11 +2799,19 @@
 	case ACB_ADAPTER_TYPE_B: {
 		struct MessageUnit_B *reg = acb->pmuB;
 		/*clear interrupt and message state*/
-		writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
-		writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg);
+		writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
+		writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
 		/* let IOP know data has been read */
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+		uint32_t outbound_doorbell;
+		/* empty doorbell Qbuffer if door bell ringed */
+		outbound_doorbell = readl(&reg->outbound_doorbell);
+		writel(outbound_doorbell, &reg->outbound_doorbell_clear);
+		writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
+		}
 	}
 }
 
@@ -2412,13 +2823,15 @@
 	case ACB_ADAPTER_TYPE_B:
 		{
 			struct MessageUnit_B *reg = acb->pmuB;
-			writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell_reg);
-			if(arcmsr_hbb_wait_msgint_ready(acb)) {
+			writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell);
+			if (!arcmsr_hbb_wait_msgint_ready(acb)) {
 				printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT");
 				return;
 			}
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C:
+		return;
 	}
 	return;
 }
@@ -2426,15 +2839,33 @@
 static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
 {
 	uint8_t value[64];
-	int i;
-
+	int i, count = 0;
+	struct MessageUnit_A __iomem *pmuA = acb->pmuA;
+	struct MessageUnit_C __iomem *pmuC = acb->pmuC;
+	u32 temp = 0;
 	/* backup pci config data */
+	printk(KERN_NOTICE "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no);
 	for (i = 0; i < 64; i++) {
 		pci_read_config_byte(acb->pdev, i, &value[i]);
 	}
 	/* hardware reset signal */
-	pci_write_config_byte(acb->pdev, 0x84, 0x20);
-	msleep(1000);
+	if ((acb->dev_id == 0x1680)) {
+		writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]);
+	} else if ((acb->dev_id == 0x1880)) {
+		do {
+			count++;
+			writel(0xF, &pmuC->write_sequence);
+			writel(0x4, &pmuC->write_sequence);
+			writel(0xB, &pmuC->write_sequence);
+			writel(0x2, &pmuC->write_sequence);
+			writel(0x7, &pmuC->write_sequence);
+			writel(0xD, &pmuC->write_sequence);
+		} while ((((temp = readl(&pmuC->host_diagnostic)) | ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) && (count < 5));
+		writel(ARCMSR_ARC1880_RESET_ADAPTER, &pmuC->host_diagnostic);
+	} else {
+		pci_write_config_byte(acb->pdev, 0x84, 0x20);
+	}
+	msleep(2000);
 	/* write back pci config data */
 	for (i = 0; i < 64; i++) {
 		pci_write_config_byte(acb->pdev, i, value[i]);
@@ -2442,50 +2873,13 @@
 	msleep(1000);
 	return;
 }
-/*
-****************************************************************************
-****************************************************************************
-*/
-#ifdef CONFIG_SCSI_ARCMSR_RESET
-	int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
-	{
-			struct Scsi_Host *shost = NULL;
-			spinlock_t *host_lock = NULL;
-			int i, isleep;
-
-			shost = cmd->device->host;
-			host_lock = shost->host_lock;
-
-			printk(KERN_NOTICE "Host %d bus reset over, sleep %d seconds (busy %d, can queue %d) ...........\n",
-					shost->host_no, sleeptime, shost->host_busy, shost->can_queue);
-			isleep = sleeptime / 10;
-			spin_unlock_irq(host_lock);
-			if (isleep > 0) {
-				for (i = 0; i < isleep; i++) {
-					msleep(10000);
-					printk(KERN_NOTICE "^%d^\n", i);
-				}
-			}
-
-			isleep = sleeptime % 10;
-			if (isleep > 0) {
-				msleep(isleep * 1000);
-				printk(KERN_NOTICE "^v^\n");
-			}
-			spin_lock_irq(host_lock);
-			printk(KERN_NOTICE "***** wake up *****\n");
-			return 0;
-	}
-#endif
 static void arcmsr_iop_init(struct AdapterControlBlock *acb)
 {
 	uint32_t intmask_org;
-
-       /* disable all outbound interrupt */
-       intmask_org = arcmsr_disable_outbound_ints(acb);
+	/* disable all outbound interrupt */
+	intmask_org = arcmsr_disable_outbound_ints(acb);
 	arcmsr_wait_firmware_ready(acb);
 	arcmsr_iop_confirm(acb);
-	arcmsr_get_firmware_spec(acb, 1);
 	/*start background rebuild*/
 	arcmsr_start_adapter_bgrb(acb);
 	/* empty doorbell Qbuffer if door bell ringed */
@@ -2502,20 +2896,17 @@
 	uint32_t intmask_org;
 	uint8_t rtnval = 0x00;
 	int i = 0;
-
 	if (atomic_read(&acb->ccboutstandingcount) != 0) {
 		/* disable all outbound interrupt */
 		intmask_org = arcmsr_disable_outbound_ints(acb);
 		/* talk to iop 331 outstanding command aborted */
 		rtnval = arcmsr_abort_allcmd(acb);
-		/* wait for 3 sec for all command aborted*/
-		ssleep(3);
 		/* clear all outbound posted Q */
 		arcmsr_done4abort_postqueue(acb);
 		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
 			ccb = acb->pccb_pool[i];
 			if (ccb->startdone == ARCMSR_CCB_START) {
-				arcmsr_ccb_complete(ccb, 1);
+				arcmsr_ccb_complete(ccb);
 			}
 		}
 		atomic_set(&acb->ccboutstandingcount, 0);
@@ -2530,94 +2921,190 @@
 {
 	struct AdapterControlBlock *acb =
 		(struct AdapterControlBlock *)cmd->device->host->hostdata;
-	int retry = 0;
-
-	if (acb->acb_flags & ACB_F_BUS_RESET)
-		return SUCCESS;
-
-	printk(KERN_NOTICE "arcmsr%d: bus reset ..... \n", acb->adapter_index);
-	acb->acb_flags |= ACB_F_BUS_RESET;
+	uint32_t intmask_org, outbound_doorbell;
+	int retry_count = 0;
+	int rtn = FAILED;
+	acb = (struct AdapterControlBlock *) cmd->device->host->hostdata;
+	printk(KERN_ERR "arcmsr: executing bus reset eh.....num_resets = %d, num_aborts = %d \n", acb->num_resets, acb->num_aborts);
 	acb->num_resets++;
-	while (atomic_read(&acb->ccboutstandingcount) != 0 && retry < 4) {
-		arcmsr_interrupt(acb);
-		retry++;
-	}
 
-	if (arcmsr_iop_reset(acb)) {
-		switch (acb->adapter_type) {
-		case ACB_ADAPTER_TYPE_A: {
-			printk(KERN_NOTICE "arcmsr%d: do hardware bus reset, num_resets = %d num_aborts = %d \n",
-				acb->adapter_index, acb->num_resets, acb->num_aborts);
-			arcmsr_hardware_reset(acb);
-			acb->acb_flags |= ACB_F_FIRMWARE_TRAP;
-			acb->acb_flags &= ~ACB_F_IOP_INITED;
-			#ifdef CONFIG_SCSI_ARCMSR_RESET
-			struct MessageUnit_A __iomem *reg = acb->pmuA;
-			uint32_t intmask_org, outbound_doorbell;
-			int retry_count = 0;
+	switch(acb->adapter_type){
+		case ACB_ADAPTER_TYPE_A:{
+			if (acb->acb_flags & ACB_F_BUS_RESET){
+				long timeout;
+				printk(KERN_ERR "arcmsr: there is an  bus reset eh proceeding.......\n");
+				timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
+				if (timeout) {
+					return SUCCESS;
+				}
+			}
+			acb->acb_flags |= ACB_F_BUS_RESET;
+			if (!arcmsr_iop_reset(acb)) {
+				struct MessageUnit_A __iomem *reg;
+				reg = acb->pmuA;
+				arcmsr_hardware_reset(acb);
+				acb->acb_flags &= ~ACB_F_IOP_INITED;
 sleep_again:
-			arcmsr_sleep_for_bus_reset(cmd);
-			if ((readl(&reg->outbound_msgaddr1) &
-			ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
-			printk(KERN_NOTICE "arcmsr%d: hardware bus reset and return busy, retry=%d \n",
-			acb->host->host_no, retry_count);
-			if (retry_count > retrycount) {
-				printk(KERN_NOTICE "arcmsr%d: hardware bus reset and return busy, retry aborted \n",
-				acb->host->host_no);
-			return SUCCESS;
+				arcmsr_sleep_for_bus_reset(cmd);
+				if ((readl(&reg->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
+					printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count);
+					if (retry_count > retrycount) {
+						acb->fw_flag = FW_DEADLOCK;
+						printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no);
+						return FAILED;
+					}
+					retry_count++;
+					goto sleep_again;
+				}
+				acb->acb_flags |= ACB_F_IOP_INITED;
+				/* disable all outbound interrupt */
+				intmask_org = arcmsr_disable_outbound_ints(acb);
+				arcmsr_get_firmware_spec(acb);
+				arcmsr_start_adapter_bgrb(acb);
+				/* clear Qbuffer if door bell ringed */
+				outbound_doorbell = readl(&reg->outbound_doorbell);
+				writel(outbound_doorbell, &reg->outbound_doorbell); /*clear interrupt */
+   				writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+				/* enable outbound Post Queue,outbound doorbell Interrupt */
+				arcmsr_enable_outbound_ints(acb, intmask_org);
+				atomic_set(&acb->rq_map_token, 16);
+				atomic_set(&acb->ante_token_value, 16);
+				acb->fw_flag = FW_NORMAL;
+				init_timer(&acb->eternal_timer);
+				acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
+				acb->eternal_timer.data = (unsigned long) acb;
+				acb->eternal_timer.function = &arcmsr_request_device_map;
+				add_timer(&acb->eternal_timer);
+				acb->acb_flags &= ~ACB_F_BUS_RESET;
+				rtn = SUCCESS;
+				printk(KERN_ERR "arcmsr: scsi  bus reset eh returns with success\n");
+			} else {
+				acb->acb_flags &= ~ACB_F_BUS_RESET;
+				if (atomic_read(&acb->rq_map_token) == 0) {
+					atomic_set(&acb->rq_map_token, 16);
+					atomic_set(&acb->ante_token_value, 16);
+					acb->fw_flag = FW_NORMAL;
+					init_timer(&acb->eternal_timer);
+						acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
+					acb->eternal_timer.data = (unsigned long) acb;
+					acb->eternal_timer.function = &arcmsr_request_device_map;
+					add_timer(&acb->eternal_timer);
+				} else {
+					atomic_set(&acb->rq_map_token, 16);
+					atomic_set(&acb->ante_token_value, 16);
+					acb->fw_flag = FW_NORMAL;
+					mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
+				}
+				rtn = SUCCESS;
 			}
-			retry_count++;
-			goto sleep_again;
-			}
-			acb->acb_flags &= ~ACB_F_FIRMWARE_TRAP;
-			acb->acb_flags |= ACB_F_IOP_INITED;
-			acb->acb_flags &= ~ACB_F_BUS_RESET;
-			printk(KERN_NOTICE "arcmsr%d: hardware bus reset and reset ok \n",
-				acb->host->host_no);
-			/* disable all outbound interrupt */
-			intmask_org = arcmsr_disable_outbound_ints(acb);
-			arcmsr_get_firmware_spec(acb, 1);
-			/*start	background rebuild*/
-			arcmsr_start_adapter_bgrb(acb);
-			/* clear Qbuffer if door bell ringed */
-			outbound_doorbell = readl(&reg->outbound_doorbell);
-			writel(outbound_doorbell, &reg->outbound_doorbell); /*clear interrupt */
-			writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
-			/* enable outbound Post Queue,outbound doorbell Interrupt */
-			arcmsr_enable_outbound_ints(acb, intmask_org);
-			atomic_set(&acb->rq_map_token, 16);
-			init_timer(&acb->eternal_timer);
-			acb->eternal_timer.expires = jiffies + msecs_to_jiffies(20*HZ);
-			acb->eternal_timer.data = (unsigned long) acb;
-			acb->eternal_timer.function = &arcmsr_request_device_map;
-			add_timer(&acb->eternal_timer);
-			#endif
-		}
 			break;
-		case ACB_ADAPTER_TYPE_B: {
-	}
 		}
-	} else {
-	acb->acb_flags &= ~ACB_F_BUS_RESET;
+		case ACB_ADAPTER_TYPE_B:{
+			acb->acb_flags |= ACB_F_BUS_RESET;
+			if (!arcmsr_iop_reset(acb)) {
+				acb->acb_flags &= ~ACB_F_BUS_RESET;
+				rtn = FAILED;
+			} else {
+				acb->acb_flags &= ~ACB_F_BUS_RESET;
+				if (atomic_read(&acb->rq_map_token) == 0) {
+					atomic_set(&acb->rq_map_token, 16);
+					atomic_set(&acb->ante_token_value, 16);
+					acb->fw_flag = FW_NORMAL;
+					init_timer(&acb->eternal_timer);
+						acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
+					acb->eternal_timer.data = (unsigned long) acb;
+					acb->eternal_timer.function = &arcmsr_request_device_map;
+					add_timer(&acb->eternal_timer);
+				} else {
+					atomic_set(&acb->rq_map_token, 16);
+					atomic_set(&acb->ante_token_value, 16);
+					acb->fw_flag = FW_NORMAL;
+					mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
+				}
+				rtn = SUCCESS;
+			}
+			break;
+		}
+		case ACB_ADAPTER_TYPE_C:{
+			if (acb->acb_flags & ACB_F_BUS_RESET) {
+				long timeout;
+				printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n");
+				timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
+				if (timeout) {
+					return SUCCESS;
+				}
+			}
+			acb->acb_flags |= ACB_F_BUS_RESET;
+			if (!arcmsr_iop_reset(acb)) {
+				struct MessageUnit_C __iomem *reg;
+				reg = acb->pmuC;
+				arcmsr_hardware_reset(acb);
+				acb->acb_flags &= ~ACB_F_IOP_INITED;
+sleep:
+				arcmsr_sleep_for_bus_reset(cmd);
+				if ((readl(&reg->host_diagnostic) & 0x04) != 0) {
+					printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count);
+					if (retry_count > retrycount) {
+						acb->fw_flag = FW_DEADLOCK;
+						printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no);
+						return FAILED;
+					}
+					retry_count++;
+					goto sleep;
+				}
+				acb->acb_flags |= ACB_F_IOP_INITED;
+				/* disable all outbound interrupt */
+				intmask_org = arcmsr_disable_outbound_ints(acb);
+				arcmsr_get_firmware_spec(acb);
+				arcmsr_start_adapter_bgrb(acb);
+				/* clear Qbuffer if door bell ringed */
+				outbound_doorbell = readl(&reg->outbound_doorbell);
+				writel(outbound_doorbell, &reg->outbound_doorbell_clear); /*clear interrupt */
+				writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
+				/* enable outbound Post Queue,outbound doorbell Interrupt */
+				arcmsr_enable_outbound_ints(acb, intmask_org);
+				atomic_set(&acb->rq_map_token, 16);
+				atomic_set(&acb->ante_token_value, 16);
+				acb->fw_flag = FW_NORMAL;
+				init_timer(&acb->eternal_timer);
+				acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ);
+				acb->eternal_timer.data = (unsigned long) acb;
+				acb->eternal_timer.function = &arcmsr_request_device_map;
+				add_timer(&acb->eternal_timer);
+				acb->acb_flags &= ~ACB_F_BUS_RESET;
+				rtn = SUCCESS;
+				printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n");
+			} else {
+				acb->acb_flags &= ~ACB_F_BUS_RESET;
+				if (atomic_read(&acb->rq_map_token) == 0) {
+					atomic_set(&acb->rq_map_token, 16);
+					atomic_set(&acb->ante_token_value, 16);
+					acb->fw_flag = FW_NORMAL;
+					init_timer(&acb->eternal_timer);
+						acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
+					acb->eternal_timer.data = (unsigned long) acb;
+					acb->eternal_timer.function = &arcmsr_request_device_map;
+					add_timer(&acb->eternal_timer);
+				} else {
+					atomic_set(&acb->rq_map_token, 16);
+					atomic_set(&acb->ante_token_value, 16);
+					acb->fw_flag = FW_NORMAL;
+					mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
+				}
+				rtn = SUCCESS;
+			}
+			break;
+		}
 	}
-	return SUCCESS;
+	return rtn;
 }
 
-static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
+static int arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
 		struct CommandControlBlock *ccb)
 {
-	u32 intmask;
-
-	ccb->startdone = ARCMSR_CCB_ABORTED;
-
-	/*
-	** Wait for 3 sec for all command done.
-	*/
-	ssleep(3);
-
-	intmask = arcmsr_disable_outbound_ints(acb);
-	arcmsr_polling_ccbdone(acb, ccb);
-	arcmsr_enable_outbound_ints(acb, intmask);
+	int rtn;
+	rtn = arcmsr_polling_ccbdone(acb, ccb);
+	return rtn;
 }
 
 static int arcmsr_abort(struct scsi_cmnd *cmd)
@@ -2625,10 +3112,11 @@
 	struct AdapterControlBlock *acb =
 		(struct AdapterControlBlock *)cmd->device->host->hostdata;
 	int i = 0;
-
+	int rtn = FAILED;
 	printk(KERN_NOTICE
 		"arcmsr%d: abort device command of scsi id = %d lun = %d \n",
 		acb->host->host_no, cmd->device->id, cmd->device->lun);
+	acb->acb_flags |= ACB_F_ABORT;
 	acb->num_aborts++;
 	/*
 	************************************************
@@ -2637,17 +3125,18 @@
 	************************************************
 	*/
 	if (!atomic_read(&acb->ccboutstandingcount))
-		return SUCCESS;
+		return rtn;
 
 	for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
 		struct CommandControlBlock *ccb = acb->pccb_pool[i];
 		if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) {
-			arcmsr_abort_one_cmd(acb, ccb);
+			ccb->startdone = ARCMSR_CCB_ABORTED;
+			rtn = arcmsr_abort_one_cmd(acb, ccb);
 			break;
 		}
 	}
-
-	return SUCCESS;
+	acb->acb_flags &= ~ACB_F_ABORT;
+	return rtn;
 }
 
 static const char *arcmsr_info(struct Scsi_Host *host)
@@ -2657,7 +3146,6 @@
 	static char buf[256];
 	char *type;
 	int raid6 = 1;
-
 	switch (acb->pdev->device) {
 	case PCI_DEVICE_ID_ARECA_1110:
 	case PCI_DEVICE_ID_ARECA_1200:
@@ -2681,6 +3169,7 @@
 	case PCI_DEVICE_ID_ARECA_1381:
 	case PCI_DEVICE_ID_ARECA_1680:
 	case PCI_DEVICE_ID_ARECA_1681:
+	case PCI_DEVICE_ID_ARECA_1880:
 		type = "SAS";
 		break;
 	default:
diff --git a/drivers/scsi/be2iscsi/Kconfig b/drivers/scsi/be2iscsi/Kconfig
index 2952fcd..84c275f 100644
--- a/drivers/scsi/be2iscsi/Kconfig
+++ b/drivers/scsi/be2iscsi/Kconfig
@@ -1,6 +1,6 @@
 config BE2ISCSI
 	tristate "ServerEngines' 10Gbps iSCSI - BladeEngine 2"
-	depends on PCI && SCSI
+	depends on PCI && SCSI && NET
 	select SCSI_ISCSI_ATTRS
 
 	help
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index 136b49c..1cb8a5e 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -128,8 +128,8 @@
 #define mcc_timeout		120000 /* 5s timeout */
 
 /* Returns number of pages spanned by the data starting at the given addr */
-#define PAGES_4K_SPANNED(_address, size) 				\
-		((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + 	\
+#define PAGES_4K_SPANNED(_address, size)				\
+		((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) +	\
 			(size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K))
 
 /* Byte offset into the page corresponding to given address */
@@ -137,7 +137,7 @@
 		((size_t)(addr) & (PAGE_SIZE_4K-1))
 
 /* Returns bit offset within a DWORD of a bitfield */
-#define AMAP_BIT_OFFSET(_struct, field)  				\
+#define AMAP_BIT_OFFSET(_struct, field)					\
 		(((size_t)&(((_struct *)0)->field))%32)
 
 /* Returns the bit mask of the field that is NOT shifted into location. */
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index cda6642..7c75373 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -19,6 +19,86 @@
 #include "be_mgmt.h"
 #include "be_main.h"
 
+int beiscsi_pci_soft_reset(struct beiscsi_hba *phba)
+{
+	u32 sreset;
+	u8 *pci_reset_offset = 0;
+	u8 *pci_online0_offset = 0;
+	u8 *pci_online1_offset = 0;
+	u32 pconline0 = 0;
+	u32 pconline1 = 0;
+	u32 i;
+
+	pci_reset_offset = (u8 *)phba->pci_va + BE2_SOFT_RESET;
+	pci_online0_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE0;
+	pci_online1_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE1;
+	sreset = readl((void *)pci_reset_offset);
+	sreset |= BE2_SET_RESET;
+	writel(sreset, (void *)pci_reset_offset);
+
+	i = 0;
+	while (sreset & BE2_SET_RESET) {
+		if (i > 64)
+			break;
+		msleep(100);
+		sreset = readl((void *)pci_reset_offset);
+		i++;
+	}
+
+	if (sreset & BE2_SET_RESET) {
+		printk(KERN_ERR "Soft Reset  did not deassert\n");
+		return -EIO;
+	}
+	pconline1 = BE2_MPU_IRAM_ONLINE;
+	writel(pconline0, (void *)pci_online0_offset);
+	writel(pconline1, (void *)pci_online1_offset);
+
+	sreset = BE2_SET_RESET;
+	writel(sreset, (void *)pci_reset_offset);
+
+	i = 0;
+	while (sreset & BE2_SET_RESET) {
+		if (i > 64)
+			break;
+		msleep(1);
+		sreset = readl((void *)pci_reset_offset);
+		i++;
+	}
+	if (sreset & BE2_SET_RESET) {
+		printk(KERN_ERR "MPU Online Soft Reset did not deassert\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+int be_chk_reset_complete(struct beiscsi_hba *phba)
+{
+	unsigned int num_loop;
+	u8 *mpu_sem = 0;
+	u32 status;
+
+	num_loop = 1000;
+	mpu_sem = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
+	msleep(5000);
+
+	while (num_loop) {
+		status = readl((void *)mpu_sem);
+
+		if ((status & 0x80000000) || (status & 0x0000FFFF) == 0xC000)
+			break;
+		msleep(60);
+		num_loop--;
+	}
+
+	if ((status & 0x80000000) || (!num_loop)) {
+		printk(KERN_ERR "Failed in be_chk_reset_complete"
+		"status = 0x%x\n", status);
+		return -EIO;
+	}
+
+	return 0;
+}
+
 void be_mcc_notify(struct beiscsi_hba *phba)
 {
 	struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
@@ -98,7 +178,7 @@
 		dev_err(&ctrl->pdev->dev,
 			"error in cmd completion: status(compl/extd)=%d/%d\n",
 			compl_status, extd_status);
-		return -1;
+		return -EBUSY;
 	}
 	return 0;
 }
@@ -151,20 +231,20 @@
 {
 	switch (evt->port_link_status) {
 	case ASYNC_EVENT_LINK_DOWN:
-		SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d \n",
-						evt->physical_port);
+		SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d\n",
+				     evt->physical_port);
 		phba->state |= BE_ADAPTER_LINK_DOWN;
 		iscsi_host_for_each_session(phba->shost,
 					    be2iscsi_fail_session);
 		break;
 	case ASYNC_EVENT_LINK_UP:
 		phba->state = BE_ADAPTER_UP;
-		SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d \n",
+		SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d\n",
 						evt->physical_port);
 		break;
 	default:
 		SE_DEBUG(DBG_LVL_1, "Unexpected Async Notification %d on"
-				    "Physical Port %d \n",
+				    "Physical Port %d\n",
 				     evt->port_link_status,
 				     evt->physical_port);
 	}
@@ -199,7 +279,7 @@
 			else
 				SE_DEBUG(DBG_LVL_1,
 					 " Unsupported Async Event, flags"
-					 " = 0x%08x \n", compl->flags);
+					 " = 0x%08x\n", compl->flags);
 
 		} else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
 				status = be_mcc_compl_process(ctrl, compl);
@@ -231,7 +311,7 @@
 	}
 	if (i == mcc_timeout) {
 		dev_err(&phba->pcidev->dev, "mccq poll timed out\n");
-		return -1;
+		return -EBUSY;
 	}
 	return 0;
 }
@@ -257,7 +337,7 @@
 
 		if (cnt > 6000000) {
 			dev_err(&ctrl->pdev->dev, "mbox_db poll timed out\n");
-			return -1;
+			return -EBUSY;
 		}
 
 		if (cnt > 50) {
@@ -286,7 +366,7 @@
 
 	status = be_mbox_db_ready_wait(ctrl);
 	if (status != 0) {
-		SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed 1\n");
+		SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed\n");
 		return status;
 	}
 	val = 0;
@@ -297,19 +377,19 @@
 
 	status = be_mbox_db_ready_wait(ctrl);
 	if (status != 0) {
-		SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed 2\n");
+		SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed\n");
 		return status;
 	}
 	if (be_mcc_compl_is_new(compl)) {
 		status = be_mcc_compl_process(ctrl, &mbox->compl);
 		be_mcc_compl_use(compl);
 		if (status) {
-			SE_DEBUG(DBG_LVL_1, "After be_mcc_compl_process \n");
+			SE_DEBUG(DBG_LVL_1, "After be_mcc_compl_process\n");
 			return status;
 		}
 	} else {
 		dev_err(&ctrl->pdev->dev, "invalid mailbox completion\n");
-		return -1;
+		return -EBUSY;
 	}
 	return 0;
 }
@@ -355,7 +435,7 @@
 			return status;
 	} else {
 		dev_err(&phba->pcidev->dev, "invalid mailbox completion\n");
-		return -1;
+		return -EBUSY;
 	}
 	return 0;
 }
@@ -500,7 +580,7 @@
 
 	status = be_mbox_notify(ctrl);
 	if (status)
-		SE_DEBUG(DBG_LVL_1, "be_cmd_fw_initialize Failed \n");
+		SE_DEBUG(DBG_LVL_1, "be_cmd_fw_initialize Failed\n");
 
 	spin_unlock(&ctrl->mbox_lock);
 	return status;
@@ -517,7 +597,7 @@
 	void *ctxt = &req->context;
 	int status;
 
-	SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_cq_create \n");
+	SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_cq_create\n");
 	spin_lock(&ctrl->mbox_lock);
 	memset(wrb, 0, sizeof(*wrb));
 
@@ -550,7 +630,7 @@
 		cq->id = le16_to_cpu(resp->cq_id);
 		cq->created = true;
 	} else
-		SE_DEBUG(DBG_LVL_1, "In be_cmd_cq_create, status=ox%08x \n",
+		SE_DEBUG(DBG_LVL_1, "In be_cmd_cq_create, status=ox%08x\n",
 			status);
 	spin_unlock(&ctrl->mbox_lock);
 
@@ -619,7 +699,7 @@
 	u8 subsys = 0, opcode = 0;
 	int status;
 
-	SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_q_destroy \n");
+	SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_q_destroy\n");
 	spin_lock(&ctrl->mbox_lock);
 	memset(wrb, 0, sizeof(*wrb));
 	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -652,7 +732,7 @@
 	default:
 		spin_unlock(&ctrl->mbox_lock);
 		BUG();
-		return -1;
+		return -ENXIO;
 	}
 	be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req));
 	if (queue_type != QTYPE_SGL)
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index 49fcc78..40641d0 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -47,8 +47,8 @@
 
 #define CQE_FLAGS_VALID_MASK (1 << 31)
 #define CQE_FLAGS_ASYNC_MASK (1 << 30)
-#define CQE_FLAGS_COMPLETED_MASK 	(1 << 28)
-#define CQE_FLAGS_CONSUMED_MASK 	(1 << 27)
+#define CQE_FLAGS_COMPLETED_MASK	(1 << 28)
+#define CQE_FLAGS_CONSUMED_MASK		(1 << 27)
 
 /* Completion Status */
 #define MCC_STATUS_SUCCESS 0x0
@@ -56,7 +56,7 @@
 #define CQE_STATUS_COMPL_MASK 0xFFFF
 #define CQE_STATUS_COMPL_SHIFT 0	/* bits 0 - 15 */
 #define CQE_STATUS_EXTD_MASK 0xFFFF
-#define CQE_STATUS_EXTD_SHIFT 0		/* bits 0 - 15 */
+#define CQE_STATUS_EXTD_SHIFT 16		/* bits 0 - 15 */
 
 struct be_mcc_compl {
 	u32 status;		/* dword 0 */
@@ -143,14 +143,14 @@
  */
 #define OPCODE_COMMON_CQ_CREATE				12
 #define OPCODE_COMMON_EQ_CREATE				13
-#define OPCODE_COMMON_MCC_CREATE        		21
-#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES               32
+#define OPCODE_COMMON_MCC_CREATE			21
+#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES		32
 #define OPCODE_COMMON_GET_FW_VERSION			35
 #define OPCODE_COMMON_MODIFY_EQ_DELAY			41
 #define OPCODE_COMMON_FIRMWARE_CONFIG			42
-#define OPCODE_COMMON_MCC_DESTROY        		53
-#define OPCODE_COMMON_CQ_DESTROY        		54
-#define OPCODE_COMMON_EQ_DESTROY        		55
+#define OPCODE_COMMON_MCC_DESTROY			53
+#define OPCODE_COMMON_CQ_DESTROY			54
+#define OPCODE_COMMON_EQ_DESTROY			55
 #define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG		58
 #define OPCODE_COMMON_FUNCTION_RESET			61
 
@@ -164,9 +164,9 @@
 #define OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG		7
 #define OPCODE_COMMON_ISCSI_SET_FRAGNUM_BITS_FOR_SGL_CRA 61
 #define OPCODE_COMMON_ISCSI_DEFQ_CREATE                 64
-#define OPCODE_COMMON_ISCSI_DEFQ_DESTROY 		65
+#define OPCODE_COMMON_ISCSI_DEFQ_DESTROY		65
 #define OPCODE_COMMON_ISCSI_WRBQ_CREATE			66
-#define OPCODE_COMMON_ISCSI_WRBQ_DESTROY 		67
+#define OPCODE_COMMON_ISCSI_WRBQ_DESTROY		67
 
 struct be_cmd_req_hdr {
 	u8 opcode;		/* dword 0 */
@@ -423,7 +423,7 @@
 			struct be_queue_info *cq);
 
 int be_poll_mcc(struct be_ctrl_info *ctrl);
-unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
+int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
 				      struct beiscsi_hba *phba);
 unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba);
 void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag);
@@ -875,7 +875,7 @@
 						 */
 #define UNSOL_HDR_NOTIFY		28	/* Unsolicited header notify.*/
 #define UNSOL_DATA_NOTIFY		29	/* Unsolicited data notify.*/
-#define UNSOL_DATA_DIGEST_ERROR_NOTIFY 	30	/* Unsolicited data digest
+#define UNSOL_DATA_DIGEST_ERROR_NOTIFY	30	/* Unsolicited data digest
 						 * error notify.
 						 */
 #define DRIVERMSG_NOTIFY		31	/* TCP acknowledge based
@@ -901,6 +901,9 @@
 						 * the cxn
 						 */
 
+int beiscsi_pci_soft_reset(struct beiscsi_hba *phba);
+int be_chk_reset_complete(struct beiscsi_hba *phba);
+
 void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
 			bool embedded, u8 sge_cnt);
 
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index c3928cb..6d63e7b 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -52,7 +52,7 @@
 	SE_DEBUG(DBG_LVL_8, "In beiscsi_session_create\n");
 
 	if (!ep) {
-		SE_DEBUG(DBG_LVL_1, "beiscsi_session_create: invalid ep \n");
+		SE_DEBUG(DBG_LVL_1, "beiscsi_session_create: invalid ep\n");
 		return NULL;
 	}
 	beiscsi_ep = ep->dd_data;
@@ -157,7 +157,7 @@
 			 "Connection table already occupied. Detected clash\n");
 		return -EINVAL;
 	} else {
-		SE_DEBUG(DBG_LVL_8, "phba->conn_table[%d]=%p(beiscsi_conn) \n",
+		SE_DEBUG(DBG_LVL_8, "phba->conn_table[%d]=%p(beiscsi_conn)\n",
 			 cid, beiscsi_conn);
 		phba->conn_table[cid] = beiscsi_conn;
 	}
@@ -196,7 +196,7 @@
 
 	if (beiscsi_ep->phba != phba) {
 		SE_DEBUG(DBG_LVL_8,
-			 "beiscsi_ep->hba=%p not equal to phba=%p \n",
+			 "beiscsi_ep->hba=%p not equal to phba=%p\n",
 			 beiscsi_ep->phba, phba);
 		return -EEXIST;
 	}
@@ -204,7 +204,7 @@
 	beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid;
 	beiscsi_conn->ep = beiscsi_ep;
 	beiscsi_ep->conn = beiscsi_conn;
-	SE_DEBUG(DBG_LVL_8, "beiscsi_conn=%p conn=%p ep_cid=%d \n",
+	SE_DEBUG(DBG_LVL_8, "beiscsi_conn=%p conn=%p ep_cid=%d\n",
 		 beiscsi_conn, conn, beiscsi_ep->ep_cid);
 	return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid);
 }
@@ -230,7 +230,7 @@
 	if (!beiscsi_ep) {
 		SE_DEBUG(DBG_LVL_1,
 			 "In beiscsi_conn_get_param , no beiscsi_ep\n");
-		return -1;
+		return -ENODEV;
 	}
 
 	switch (param) {
@@ -277,6 +277,10 @@
 		if (session->max_burst > 262144)
 			session->max_burst = 262144;
 		break;
+	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+		if ((conn->max_xmit_dlength > 65536) ||
+		    (conn->max_xmit_dlength == 0))
+			conn->max_xmit_dlength = 65536;
 	default:
 		return 0;
 	}
@@ -308,8 +312,8 @@
 	case ISCSI_HOST_PARAM_HWADDRESS:
 		tag = be_cmd_get_mac_addr(phba);
 		if (!tag) {
-			SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed \n");
-			return -1;
+			SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n");
+			return -EAGAIN;
 		} else
 			wait_event_interruptible(phba->ctrl.mcc_wait[tag],
 						 phba->ctrl.mcc_numtag[tag]);
@@ -319,10 +323,10 @@
 		status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
 		if (status || extd_status) {
 			SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed"
-					    " status = %d extd_status = %d \n",
+					    " status = %d extd_status = %d\n",
 					    status, extd_status);
 			free_mcc_tag(&phba->ctrl, tag);
-			return -1;
+			return -EAGAIN;
 		} else {
 			wrb = queue_get_wrb(mccq, wrb_num);
 			free_mcc_tag(&phba->ctrl, tag);
@@ -442,75 +446,6 @@
 }
 
 /**
- * beiscsi_open_conn - Ask FW to open a TCP connection
- * @ep:	endpoint to be used
- * @src_addr: The source IP address
- * @dst_addr: The Destination  IP address
- *
- * Asks the FW to open a TCP connection
- */
-static int beiscsi_open_conn(struct iscsi_endpoint *ep,
-			     struct sockaddr *src_addr,
-			     struct sockaddr *dst_addr, int non_blocking)
-{
-	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
-	struct beiscsi_hba *phba = beiscsi_ep->phba;
-	struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
-	struct be_mcc_wrb *wrb;
-	struct tcp_connect_and_offload_out *ptcpcnct_out;
-	unsigned short status, extd_status;
-	unsigned int tag, wrb_num;
-	int ret = -1;
-
-	SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn\n");
-	beiscsi_ep->ep_cid = beiscsi_get_cid(phba);
-	if (beiscsi_ep->ep_cid == 0xFFFF) {
-		SE_DEBUG(DBG_LVL_1, "No free cid available\n");
-		return ret;
-	}
-	SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d ",
-		 beiscsi_ep->ep_cid);
-	phba->ep_array[beiscsi_ep->ep_cid -
-		       phba->fw_config.iscsi_cid_start] = ep;
-	if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start +
-				  phba->params.cxns_per_ctrl * 2)) {
-		SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
-		return ret;
-	}
-
-	beiscsi_ep->cid_vld = 0;
-	tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep);
-	if (!tag) {
-		SE_DEBUG(DBG_LVL_1,
-			 "mgmt_open_connection Failed for cid=%d \n",
-			 beiscsi_ep->ep_cid);
-	} else {
-		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-					 phba->ctrl.mcc_numtag[tag]);
-	}
-	wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
-	extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
-	status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
-	if (status || extd_status) {
-		SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed"
-				    " status = %d extd_status = %d \n",
-				    status, extd_status);
-		free_mcc_tag(&phba->ctrl, tag);
-		return -1;
-	} else {
-		wrb = queue_get_wrb(mccq, wrb_num);
-		free_mcc_tag(&phba->ctrl, tag);
-
-		ptcpcnct_out = 	embedded_payload(wrb);
-		beiscsi_ep = ep->dd_data;
-		beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle;
-		beiscsi_ep->cid_vld = 1;
-		SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n");
-	}
-	return 0;
-}
-
-/**
  * beiscsi_put_cid - Free the cid
  * @phba: The phba for which the cid is being freed
  * @cid: The cid to free
@@ -536,6 +471,103 @@
 }
 
 /**
+ * beiscsi_open_conn - Ask FW to open a TCP connection
+ * @ep:	endpoint to be used
+ * @src_addr: The source IP address
+ * @dst_addr: The Destination  IP address
+ *
+ * Asks the FW to open a TCP connection
+ */
+static int beiscsi_open_conn(struct iscsi_endpoint *ep,
+			     struct sockaddr *src_addr,
+			     struct sockaddr *dst_addr, int non_blocking)
+{
+	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
+	struct beiscsi_hba *phba = beiscsi_ep->phba;
+	struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+	struct be_mcc_wrb *wrb;
+	struct tcp_connect_and_offload_out *ptcpcnct_out;
+	unsigned short status, extd_status;
+	struct be_dma_mem nonemb_cmd;
+	unsigned int tag, wrb_num;
+	int ret = -ENOMEM;
+
+	SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn\n");
+	beiscsi_ep->ep_cid = beiscsi_get_cid(phba);
+	if (beiscsi_ep->ep_cid == 0xFFFF) {
+		SE_DEBUG(DBG_LVL_1, "No free cid available\n");
+		return ret;
+	}
+	SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d\n",
+		 beiscsi_ep->ep_cid);
+	phba->ep_array[beiscsi_ep->ep_cid -
+		       phba->fw_config.iscsi_cid_start] = ep;
+	if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start +
+				  phba->params.cxns_per_ctrl * 2)) {
+		SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
+		beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
+		goto free_ep;
+	}
+
+	beiscsi_ep->cid_vld = 0;
+	nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
+				sizeof(struct tcp_connect_and_offload_in),
+				&nonemb_cmd.dma);
+	if (nonemb_cmd.va == NULL) {
+		SE_DEBUG(DBG_LVL_1,
+			 "Failed to allocate memory for mgmt_open_connection"
+			 "\n");
+		beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
+		return -ENOMEM;
+	}
+	nonemb_cmd.size = sizeof(struct tcp_connect_and_offload_in);
+	memset(nonemb_cmd.va, 0, nonemb_cmd.size);
+	tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep, &nonemb_cmd);
+	if (!tag) {
+		SE_DEBUG(DBG_LVL_1,
+			 "mgmt_open_connection Failed for cid=%d\n",
+			 beiscsi_ep->ep_cid);
+		beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
+		pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+				    nonemb_cmd.va, nonemb_cmd.dma);
+		return -EAGAIN;
+	} else {
+		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+					 phba->ctrl.mcc_numtag[tag]);
+	}
+	wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
+	extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
+	status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+	if (status || extd_status) {
+		SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed"
+				    " status = %d extd_status = %d\n",
+				    status, extd_status);
+		beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
+		free_mcc_tag(&phba->ctrl, tag);
+		pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+			    nonemb_cmd.va, nonemb_cmd.dma);
+		goto free_ep;
+	} else {
+		wrb = queue_get_wrb(mccq, wrb_num);
+		free_mcc_tag(&phba->ctrl, tag);
+
+		ptcpcnct_out = embedded_payload(wrb);
+		beiscsi_ep = ep->dd_data;
+		beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle;
+		beiscsi_ep->cid_vld = 1;
+		SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n");
+	}
+	beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
+	pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+			    nonemb_cmd.va, nonemb_cmd.dma);
+	return 0;
+
+free_ep:
+	beiscsi_free_ep(beiscsi_ep);
+	return -EBUSY;
+}
+
+/**
  * beiscsi_ep_connect - Ask chip to create TCP Conn
  * @scsi_host: Pointer to scsi_host structure
  * @dst_addr: The IP address of Target
@@ -552,18 +584,18 @@
 	struct iscsi_endpoint *ep;
 	int ret;
 
-	SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_connect \n");
+	SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_connect\n");
 	if (shost)
 		phba = iscsi_host_priv(shost);
 	else {
 		ret = -ENXIO;
-		SE_DEBUG(DBG_LVL_1, "shost is NULL \n");
+		SE_DEBUG(DBG_LVL_1, "shost is NULL\n");
 		return ERR_PTR(ret);
 	}
 
 	if (phba->state != BE_ADAPTER_UP) {
 		ret = -EBUSY;
-		SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP \n");
+		SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP\n");
 		return ERR_PTR(ret);
 	}
 
@@ -576,16 +608,16 @@
 	beiscsi_ep = ep->dd_data;
 	beiscsi_ep->phba = phba;
 	beiscsi_ep->openiscsi_ep = ep;
-	if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) {
-		SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn \n");
-		ret = -ENOMEM;
+	ret = beiscsi_open_conn(ep, NULL, dst_addr, non_blocking);
+	if (ret) {
+		SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn\n");
 		goto free_ep;
 	}
 
 	return ep;
 
 free_ep:
-	beiscsi_free_ep(beiscsi_ep);
+	iscsi_destroy_endpoint(ep);
 	return ERR_PTR(ret);
 }
 
@@ -620,9 +652,9 @@
 
 	tag = mgmt_upload_connection(phba, beiscsi_ep->ep_cid, flag);
 	if (!tag) {
-		SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x",
+		SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x\n",
 			 beiscsi_ep->ep_cid);
-		ret = -1;
+		ret = -EAGAIN;
 	} else {
 		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
 					 phba->ctrl.mcc_numtag[tag]);
@@ -632,30 +664,6 @@
 }
 
 /**
- * beiscsi_ep_disconnect - Tears down the TCP connection
- * @ep:	endpoint to be used
- *
- * Tears down the TCP connection
- */
-void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
-{
-	struct beiscsi_conn *beiscsi_conn;
-	struct beiscsi_endpoint *beiscsi_ep;
-	struct beiscsi_hba *phba;
-
-	beiscsi_ep = ep->dd_data;
-	phba = beiscsi_ep->phba;
-	SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n",
-			     beiscsi_ep->ep_cid);
-
-	if (beiscsi_ep->conn) {
-		beiscsi_conn = beiscsi_ep->conn;
-		iscsi_suspend_queue(beiscsi_conn->conn);
-	}
-
-}
-
-/**
  * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table
  * @phba: The phba instance
  * @cid: The cid to free
@@ -666,50 +674,57 @@
 	if (phba->conn_table[cid])
 		phba->conn_table[cid] = NULL;
 	else {
-		SE_DEBUG(DBG_LVL_8, "Connection table Not occupied. \n");
+		SE_DEBUG(DBG_LVL_8, "Connection table Not occupied.\n");
 		return -EINVAL;
 	}
 	return 0;
 }
 
 /**
- * beiscsi_conn_stop - Invalidate and stop the connection
- * @cls_conn: pointer to get iscsi_conn
- * @flag: The type of connection closure
+ * beiscsi_ep_disconnect - Tears down the TCP connection
+ * @ep:	endpoint to be used
+ *
+ * Tears down the TCP connection
  */
-void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
+void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
 {
-	struct iscsi_conn *conn = cls_conn->dd_data;
-	struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+	struct beiscsi_conn *beiscsi_conn;
 	struct beiscsi_endpoint *beiscsi_ep;
-	struct iscsi_session *session = conn->session;
-	struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
-	struct beiscsi_hba *phba = iscsi_host_priv(shost);
+	struct beiscsi_hba *phba;
 	unsigned int tag;
 	unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH;
 
-	beiscsi_ep = beiscsi_conn->ep;
-	if (!beiscsi_ep) {
-		SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n");
+	beiscsi_ep = ep->dd_data;
+	phba = beiscsi_ep->phba;
+	SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n",
+			     beiscsi_ep->ep_cid);
+
+	if (!beiscsi_ep->conn) {
+		SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect, no "
+			 "beiscsi_ep\n");
 		return;
 	}
-	SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop  ep_cid = %d\n",
-			     beiscsi_ep->ep_cid);
+	beiscsi_conn = beiscsi_ep->conn;
+	iscsi_suspend_queue(beiscsi_conn->conn);
+
+	SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect ep_cid = %d\n",
+		 beiscsi_ep->ep_cid);
+
 	tag = mgmt_invalidate_connection(phba, beiscsi_ep,
 					    beiscsi_ep->ep_cid, 1,
 					    savecfg_flag);
 	if (!tag) {
 		SE_DEBUG(DBG_LVL_1,
-			 "mgmt_invalidate_connection Failed for cid=%d \n",
+			 "mgmt_invalidate_connection Failed for cid=%d\n",
 			  beiscsi_ep->ep_cid);
 	} else {
 		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
 					 phba->ctrl.mcc_numtag[tag]);
 		free_mcc_tag(&phba->ctrl, tag);
 	}
+
 	beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL);
 	beiscsi_free_ep(beiscsi_ep);
-	iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
 	beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
-	iscsi_conn_stop(cls_conn, flag);
+	iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
 }
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
index 1f512c2..870cdb2 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.h
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -59,8 +59,6 @@
 
 int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn);
 
-void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag);
-
 struct iscsi_endpoint *beiscsi_ep_connect(struct Scsi_Host *shost,
 					  struct sockaddr *dst_addr,
 					  int non_blocking);
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index dd5b105..7436c5a 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -41,6 +41,8 @@
 static unsigned int be_iopoll_budget = 10;
 static unsigned int be_max_phys_size = 64;
 static unsigned int enable_msix = 1;
+static unsigned int gcrashmode = 0;
+static unsigned int num_hba = 0;
 
 MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
 MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR);
@@ -69,6 +71,7 @@
 	struct beiscsi_hba *phba;
 	struct iscsi_session *session;
 	struct invalidate_command_table *inv_tbl;
+	struct be_dma_mem nonemb_cmd;
 	unsigned int cid, tag, num_invalidate;
 
 	cls_session = starget_to_session(scsi_target(sc->device));
@@ -99,18 +102,34 @@
 	inv_tbl->cid = cid;
 	inv_tbl->icd = aborted_io_task->psgl_handle->sgl_index;
 	num_invalidate = 1;
-	tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, cid);
+	nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
+				sizeof(struct invalidate_commands_params_in),
+				&nonemb_cmd.dma);
+	if (nonemb_cmd.va == NULL) {
+		SE_DEBUG(DBG_LVL_1,
+			 "Failed to allocate memory for"
+			 "mgmt_invalidate_icds\n");
+		return FAILED;
+	}
+	nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
+
+	tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate,
+				   cid, &nonemb_cmd);
 	if (!tag) {
 		shost_printk(KERN_WARNING, phba->shost,
 			     "mgmt_invalidate_icds could not be"
 			     " submitted\n");
+		pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+				    nonemb_cmd.va, nonemb_cmd.dma);
+
 		return FAILED;
 	} else {
 		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
 					 phba->ctrl.mcc_numtag[tag]);
 		free_mcc_tag(&phba->ctrl, tag);
 	}
-
+	pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+			    nonemb_cmd.va, nonemb_cmd.dma);
 	return iscsi_eh_abort(sc);
 }
 
@@ -124,6 +143,7 @@
 	struct iscsi_session *session;
 	struct iscsi_cls_session *cls_session;
 	struct invalidate_command_table *inv_tbl;
+	struct be_dma_mem nonemb_cmd;
 	unsigned int cid, tag, i, num_invalidate;
 	int rc = FAILED;
 
@@ -158,18 +178,33 @@
 	spin_unlock_bh(&session->lock);
 	inv_tbl = phba->inv_tbl;
 
-	tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, cid);
+	nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
+				sizeof(struct invalidate_commands_params_in),
+				&nonemb_cmd.dma);
+	if (nonemb_cmd.va == NULL) {
+		SE_DEBUG(DBG_LVL_1,
+			 "Failed to allocate memory for"
+			 "mgmt_invalidate_icds\n");
+		return FAILED;
+	}
+	nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
+	memset(nonemb_cmd.va, 0, nonemb_cmd.size);
+	tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate,
+				   cid, &nonemb_cmd);
 	if (!tag) {
 		shost_printk(KERN_WARNING, phba->shost,
 			     "mgmt_invalidate_icds could not be"
 			     " submitted\n");
+		pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+				    nonemb_cmd.va, nonemb_cmd.dma);
 		return FAILED;
 	} else {
 		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
 					 phba->ctrl.mcc_numtag[tag]);
 		free_mcc_tag(&phba->ctrl, tag);
 	}
-
+	pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+			    nonemb_cmd.va, nonemb_cmd.dma);
 	return iscsi_eh_device_reset(sc);
 unlock:
 	spin_unlock_bh(&session->lock);
@@ -216,7 +251,7 @@
 	shost = iscsi_host_alloc(&beiscsi_sht, sizeof(*phba), 0);
 	if (!shost) {
 		dev_err(&pcidev->dev, "beiscsi_hba_alloc -"
-			"iscsi_host_alloc failed \n");
+			"iscsi_host_alloc failed\n");
 		return NULL;
 	}
 	shost->dma_boundary = pcidev->dma_mask;
@@ -371,7 +406,7 @@
 				    + BE2_TMFS) / 512) + 1) * 512;
 	phba->params.num_eq_entries = (phba->params.num_eq_entries < 1024)
 				? 1024 : phba->params.num_eq_entries;
-	SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d \n",
+	SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d\n",
 			     phba->params.num_eq_entries);
 	phba->params.num_cq_entries =
 	    (((BE2_CMDS_PER_CXN * 2 +  phba->fw_config.iscsi_cid_count * 2
@@ -616,7 +651,7 @@
 	struct pci_dev *pcidev = phba->pcidev;
 	struct hwi_controller *phwi_ctrlr;
 	struct hwi_context_memory *phwi_context;
-	int ret, msix_vec, i = 0;
+	int ret, msix_vec, i, j;
 	char desc[32];
 
 	phwi_ctrlr = phba->phwi_ctrlr;
@@ -628,10 +663,25 @@
 			msix_vec = phba->msix_entries[i].vector;
 			ret = request_irq(msix_vec, be_isr_msix, 0, desc,
 					  &phwi_context->be_eq[i]);
+			if (ret) {
+				shost_printk(KERN_ERR, phba->shost,
+					     "beiscsi_init_irqs-Failed to"
+					     "register msix for i = %d\n", i);
+				if (!i)
+					return ret;
+				goto free_msix_irqs;
+			}
 		}
 		msix_vec = phba->msix_entries[i].vector;
 		ret = request_irq(msix_vec, be_isr_mcc, 0, "beiscsi_msix_mcc",
 				  &phwi_context->be_eq[i]);
+		if (ret) {
+			shost_printk(KERN_ERR, phba->shost, "beiscsi_init_irqs-"
+				     "Failed to register beiscsi_msix_mcc\n");
+			i++;
+			goto free_msix_irqs;
+		}
+
 	} else {
 		ret = request_irq(pcidev->irq, be_isr, IRQF_SHARED,
 				  "beiscsi", phba);
@@ -642,6 +692,10 @@
 		}
 	}
 	return 0;
+free_msix_irqs:
+	for (j = i - 1; j == 0; j++)
+		free_irq(msix_vec, &phwi_context->be_eq[j]);
+	return ret;
 }
 
 static void hwi_ring_cq_db(struct beiscsi_hba *phba,
@@ -692,7 +746,7 @@
 		break;
 	default:
 		shost_printk(KERN_WARNING, phba->shost,
-			     "Unrecognized opcode 0x%x in async msg \n",
+			     "Unrecognized opcode 0x%x in async msg\n",
 			     (ppdu->
 			     dw[offsetof(struct amap_pdu_base, opcode) / 32]
 						& PDUBASE_OPCODE_MASK));
@@ -711,7 +765,7 @@
 
 	if (phba->io_sgl_hndl_avbl) {
 		SE_DEBUG(DBG_LVL_8,
-			 "In alloc_io_sgl_handle,io_sgl_alloc_index=%d \n",
+			 "In alloc_io_sgl_handle,io_sgl_alloc_index=%d\n",
 			 phba->io_sgl_alloc_index);
 		psgl_handle = phba->io_sgl_hndl_base[phba->
 						io_sgl_alloc_index];
@@ -730,7 +784,7 @@
 static void
 free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
 {
-	SE_DEBUG(DBG_LVL_8, "In free_,io_sgl_free_index=%d \n",
+	SE_DEBUG(DBG_LVL_8, "In free_,io_sgl_free_index=%d\n",
 		 phba->io_sgl_free_index);
 	if (phba->io_sgl_hndl_base[phba->io_sgl_free_index]) {
 		/*
@@ -739,7 +793,7 @@
 		 */
 		 SE_DEBUG(DBG_LVL_8,
 			 "Double Free in IO SGL io_sgl_free_index=%d,"
-			 "value there=%p \n", phba->io_sgl_free_index,
+			 "value there=%p\n", phba->io_sgl_free_index,
 			 phba->io_sgl_hndl_base[phba->io_sgl_free_index]);
 		return;
 	}
@@ -804,7 +858,7 @@
 
 	SE_DEBUG(DBG_LVL_8,
 		 "FREE WRB: pwrb_handle=%p free_index=0x%x"
-		 "wrb_handles_available=%d \n",
+		 "wrb_handles_available=%d\n",
 		 pwrb_handle, pwrb_context->free_index,
 		 pwrb_context->wrb_handles_available);
 }
@@ -816,7 +870,7 @@
 	if (phba->eh_sgl_hndl_avbl) {
 		psgl_handle = phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index];
 		phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index] = NULL;
-		SE_DEBUG(DBG_LVL_8, "mgmt_sgl_alloc_index=%d=0x%x \n",
+		SE_DEBUG(DBG_LVL_8, "mgmt_sgl_alloc_index=%d=0x%x\n",
 			 phba->eh_sgl_alloc_index, phba->eh_sgl_alloc_index);
 		phba->eh_sgl_hndl_avbl--;
 		if (phba->eh_sgl_alloc_index ==
@@ -834,7 +888,7 @@
 free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
 {
 
-	SE_DEBUG(DBG_LVL_8, "In  free_mgmt_sgl_handle,eh_sgl_free_index=%d \n",
+	SE_DEBUG(DBG_LVL_8, "In  free_mgmt_sgl_handle,eh_sgl_free_index=%d\n",
 			     phba->eh_sgl_free_index);
 	if (phba->eh_sgl_hndl_base[phba->eh_sgl_free_index]) {
 		/*
@@ -842,7 +896,7 @@
 		 * failed in xmit_task or alloc_pdu.
 		 */
 		SE_DEBUG(DBG_LVL_8,
-			 "Double Free in eh SGL ,eh_sgl_free_index=%d \n",
+			 "Double Free in eh SGL ,eh_sgl_free_index=%d\n",
 			 phba->eh_sgl_free_index);
 		return;
 	}
@@ -1081,7 +1135,7 @@
 	case HWH_TYPE_LOGIN:
 		SE_DEBUG(DBG_LVL_1,
 			 "\t\t No HWH_TYPE_LOGIN Expected in hwi_complete_cmd"
-			 "- Solicited path \n");
+			 "- Solicited path\n");
 		break;
 
 	case HWH_TYPE_NOP:
@@ -1164,7 +1218,7 @@
 	default:
 		pbusy_list = NULL;
 		shost_printk(KERN_WARNING, phba->shost,
-			"Unexpected code=%d \n",
+			"Unexpected code=%d\n",
 			 pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
 					code) / 32] & PDUCQE_CODE_MASK);
 		return NULL;
@@ -1552,7 +1606,7 @@
 			else
 				SE_DEBUG(DBG_LVL_1,
 					" Unsupported Async Event, flags"
-					" = 0x%08x \n", mcc_compl->flags);
+					" = 0x%08x\n", mcc_compl->flags);
 		} else if (mcc_compl->flags & CQE_FLAGS_COMPLETED_MASK) {
 			be_mcc_compl_process_isr(&phba->ctrl, mcc_compl);
 			atomic_dec(&phba->ctrl.mcc_obj.q.used);
@@ -1611,7 +1665,7 @@
 			hwi_complete_cmd(beiscsi_conn, phba, sol);
 			break;
 		case DRIVERMSG_NOTIFY:
-			SE_DEBUG(DBG_LVL_8, "Received DRIVERMSG_NOTIFY \n");
+			SE_DEBUG(DBG_LVL_8, "Received DRIVERMSG_NOTIFY\n");
 			dmsg = (struct dmsg_cqe *)sol;
 			hwi_complete_drvr_msgs(beiscsi_conn, phba, sol);
 			break;
@@ -1782,9 +1836,9 @@
 			sg_len = sg_dma_len(sg);
 			addr = (u64) sg_dma_address(sg);
 			AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb,
-							(addr & 0xFFFFFFFF));
+						((u32)(addr & 0xFFFFFFFF)));
 			AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb,
-							(addr >> 32));
+							((u32)(addr >> 32)));
 			AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb,
 							sg_len);
 			sge_len = sg_len;
@@ -1794,9 +1848,9 @@
 			sg_len = sg_dma_len(sg);
 			addr = (u64) sg_dma_address(sg);
 			AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_lo, pwrb,
-							(addr & 0xFFFFFFFF));
+						((u32)(addr & 0xFFFFFFFF)));
 			AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_hi, pwrb,
-							(addr >> 32));
+							((u32)(addr >> 32)));
 			AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_len, pwrb,
 							sg_len);
 		}
@@ -1872,9 +1926,9 @@
 			addr = 0;
 		}
 		AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb,
-						(addr & 0xFFFFFFFF));
+						((u32)(addr & 0xFFFFFFFF)));
 		AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb,
-						(addr >> 32));
+						((u32)(addr >> 32)));
 		AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb,
 						task->data_count);
 
@@ -1904,9 +1958,9 @@
 		psgl++;
 		if (task->data) {
 			AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
-						(addr & 0xFFFFFFFF));
+						((u32)(addr & 0xFFFFFFFF)));
 			AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl,
-						(addr >> 32));
+						((u32)(addr >> 32)));
 		}
 		AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0x106);
 	}
@@ -2054,7 +2108,8 @@
 					    mem_descr->mem_array[j - 1].size,
 					    mem_descr->mem_array[j - 1].
 					    virtual_address,
-					    mem_descr->mem_array[j - 1].
+					    (unsigned long)mem_descr->
+					    mem_array[j - 1].
 					    bus_address.u.a64.address);
 		}
 		if (i) {
@@ -2223,10 +2278,10 @@
 	if (mem_descr->mem_array[0].virtual_address) {
 		SE_DEBUG(DBG_LVL_8,
 			 "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_BUF"
-			 "va=%p \n", mem_descr->mem_array[0].virtual_address);
+			 "va=%p\n", mem_descr->mem_array[0].virtual_address);
 	} else
 		shost_printk(KERN_WARNING, phba->shost,
-			     "No Virtual address \n");
+			     "No Virtual address\n");
 
 	pasync_ctx->async_header.va_base =
 			mem_descr->mem_array[0].virtual_address;
@@ -2239,10 +2294,10 @@
 	if (mem_descr->mem_array[0].virtual_address) {
 		SE_DEBUG(DBG_LVL_8,
 			 "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_RING"
-			 "va=%p \n", mem_descr->mem_array[0].virtual_address);
+			 "va=%p\n", mem_descr->mem_array[0].virtual_address);
 	} else
 		shost_printk(KERN_WARNING, phba->shost,
-			    "No Virtual address \n");
+			    "No Virtual address\n");
 	pasync_ctx->async_header.ring_base =
 			mem_descr->mem_array[0].virtual_address;
 
@@ -2251,10 +2306,10 @@
 	if (mem_descr->mem_array[0].virtual_address) {
 		SE_DEBUG(DBG_LVL_8,
 			 "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_HANDLE"
-			 "va=%p \n", mem_descr->mem_array[0].virtual_address);
+			 "va=%p\n", mem_descr->mem_array[0].virtual_address);
 	} else
 		shost_printk(KERN_WARNING, phba->shost,
-			    "No Virtual address \n");
+			    "No Virtual address\n");
 
 	pasync_ctx->async_header.handle_base =
 			mem_descr->mem_array[0].virtual_address;
@@ -2266,10 +2321,10 @@
 	if (mem_descr->mem_array[0].virtual_address) {
 		SE_DEBUG(DBG_LVL_8,
 			 "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_BUF"
-			 "va=%p \n", mem_descr->mem_array[0].virtual_address);
+			 "va=%p\n", mem_descr->mem_array[0].virtual_address);
 	} else
 		shost_printk(KERN_WARNING, phba->shost,
-			    "No Virtual address \n");
+			    "No Virtual address\n");
 	pasync_ctx->async_data.va_base =
 			mem_descr->mem_array[0].virtual_address;
 	pasync_ctx->async_data.pa_base.u.a64.address =
@@ -2280,10 +2335,10 @@
 	if (mem_descr->mem_array[0].virtual_address) {
 		SE_DEBUG(DBG_LVL_8,
 			 "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_RING"
-			 "va=%p \n", mem_descr->mem_array[0].virtual_address);
+			 "va=%p\n", mem_descr->mem_array[0].virtual_address);
 	} else
 		shost_printk(KERN_WARNING, phba->shost,
-			     "No Virtual address \n");
+			     "No Virtual address\n");
 
 	pasync_ctx->async_data.ring_base =
 			mem_descr->mem_array[0].virtual_address;
@@ -2292,7 +2347,7 @@
 	mem_descr += HWI_MEM_ASYNC_DATA_HANDLE;
 	if (!mem_descr->mem_array[0].virtual_address)
 		shost_printk(KERN_WARNING, phba->shost,
-			    "No Virtual address \n");
+			    "No Virtual address\n");
 
 	pasync_ctx->async_data.handle_base =
 			mem_descr->mem_array[0].virtual_address;
@@ -2364,7 +2419,7 @@
 	WARN_ON(!sgl);
 
 	sgl->va = virtual_address;
-	sgl->dma = physical_address;
+	sgl->dma = (unsigned long)physical_address;
 	sgl->size = length;
 
 	return 0;
@@ -2447,7 +2502,7 @@
 				    sizeof(struct be_eq_entry), eq_vaddress);
 		if (ret) {
 			shost_printk(KERN_ERR, phba->shost,
-				     "be_fill_queue Failed for EQ \n");
+				     "be_fill_queue Failed for EQ\n");
 			goto create_eq_error;
 		}
 
@@ -2457,7 +2512,7 @@
 		if (ret) {
 			shost_printk(KERN_ERR, phba->shost,
 				     "beiscsi_cmd_eq_create"
-				     "Failedfor EQ \n");
+				     "Failedfor EQ\n");
 			goto create_eq_error;
 		}
 		SE_DEBUG(DBG_LVL_8, "eqid = %d\n", phwi_context->be_eq[i].q.id);
@@ -2505,7 +2560,7 @@
 				    sizeof(struct sol_cqe), cq_vaddress);
 		if (ret) {
 			shost_printk(KERN_ERR, phba->shost,
-				     "be_fill_queue Failed for ISCSI CQ \n");
+				     "be_fill_queue Failed for ISCSI CQ\n");
 			goto create_cq_error;
 		}
 
@@ -2515,7 +2570,7 @@
 		if (ret) {
 			shost_printk(KERN_ERR, phba->shost,
 				     "beiscsi_cmd_eq_create"
-				     "Failed for ISCSI CQ \n");
+				     "Failed for ISCSI CQ\n");
 			goto create_cq_error;
 		}
 		SE_DEBUG(DBG_LVL_8, "iscsi cq_id is %d for eq_id %d\n",
@@ -2565,7 +2620,8 @@
 			     "be_fill_queue Failed for DEF PDU HDR\n");
 		return ret;
 	}
-	mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
+	mem->dma = (unsigned long)mem_descr->mem_array[idx].
+				  bus_address.u.a64.address;
 	ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dq,
 					      def_pdu_ring_sz,
 					      phba->params.defpdu_hdr_sz);
@@ -2609,7 +2665,8 @@
 			     "be_fill_queue Failed for DEF PDU DATA\n");
 		return ret;
 	}
-	mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
+	mem->dma = (unsigned long)mem_descr->mem_array[idx].
+				  bus_address.u.a64.address;
 	ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dataq,
 					      def_pdu_ring_sz,
 					      phba->params.defpdu_data_sz);
@@ -2623,7 +2680,7 @@
 	SE_DEBUG(DBG_LVL_8, "iscsi def data id is %d\n",
 		 phwi_context->be_def_dataq.id);
 	hwi_post_async_buffers(phba, 0);
-	SE_DEBUG(DBG_LVL_8, "DEFAULT PDU DATA RING CREATED \n");
+	SE_DEBUG(DBG_LVL_8, "DEFAULT PDU DATA RING CREATED\n");
 	return 0;
 }
 
@@ -2655,7 +2712,7 @@
 		}
 		pm_arr++;
 	}
-	SE_DEBUG(DBG_LVL_8, "POSTED PAGES \n");
+	SE_DEBUG(DBG_LVL_8, "POSTED PAGES\n");
 	return 0;
 }
 
@@ -2678,7 +2735,7 @@
 	mem->size = len * entry_size;
 	mem->va = pci_alloc_consistent(phba->pcidev, mem->size, &mem->dma);
 	if (!mem->va)
-		return -1;
+		return -ENOMEM;
 	memset(mem->va, 0, mem->size);
 	return 0;
 }
@@ -2750,6 +2807,7 @@
 		if (status != 0) {
 			shost_printk(KERN_ERR, phba->shost,
 				     "wrbq create failed.");
+			kfree(pwrb_arr);
 			return status;
 		}
 		phwi_ctrlr->wrb_context[i * 2].cid = phwi_context->be_wrbq[i].
@@ -2873,7 +2931,7 @@
 mcc_cq_free:
 	be_queue_free(phba, cq);
 err:
-	return -1;
+	return -ENOMEM;
 }
 
 static int find_num_cpus(void)
@@ -2884,7 +2942,7 @@
 	if (num_cpus >= MAX_CPUS)
 		num_cpus = MAX_CPUS - 1;
 
-	SE_DEBUG(DBG_LVL_8, "num_cpus = %d \n", num_cpus);
+	SE_DEBUG(DBG_LVL_8, "num_cpus = %d\n", num_cpus);
 	return num_cpus;
 }
 
@@ -2907,7 +2965,7 @@
 
 	status = beiscsi_create_eqs(phba, phwi_context);
 	if (status != 0) {
-		shost_printk(KERN_ERR, phba->shost, "EQ not created \n");
+		shost_printk(KERN_ERR, phba->shost, "EQ not created\n");
 		goto error;
 	}
 
@@ -2918,7 +2976,7 @@
 	status = mgmt_check_supported_fw(ctrl, phba);
 	if (status != 0) {
 		shost_printk(KERN_ERR, phba->shost,
-			     "Unsupported fw version \n");
+			     "Unsupported fw version\n");
 		goto error;
 	}
 
@@ -2974,7 +3032,7 @@
 	if (1 == phba->init_mem[HWI_MEM_ADDN_CONTEXT].num_elements) {
 		phwi_ctrlr->phwi_ctxt = (struct hwi_context_memory *)phba->
 		    init_mem[HWI_MEM_ADDN_CONTEXT].mem_array[0].virtual_address;
-		SE_DEBUG(DBG_LVL_8, " phwi_ctrlr->phwi_ctxt=%p \n",
+		SE_DEBUG(DBG_LVL_8, " phwi_ctrlr->phwi_ctxt=%p\n",
 			 phwi_ctrlr->phwi_ctxt);
 	} else {
 		shost_printk(KERN_ERR, phba->shost,
@@ -3007,8 +3065,8 @@
 			pci_free_consistent(phba->pcidev,
 			  mem_descr->mem_array[j - 1].size,
 			  mem_descr->mem_array[j - 1].virtual_address,
-			  mem_descr->mem_array[j - 1].bus_address.
-				u.a64.address);
+			  (unsigned long)mem_descr->mem_array[j - 1].
+			  bus_address.u.a64.address);
 		}
 		kfree(mem_descr->mem_array);
 		mem_descr++;
@@ -3024,7 +3082,7 @@
 	ret = beiscsi_get_memory(phba);
 	if (ret < 0) {
 		shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe -"
-			     "Failed in beiscsi_alloc_memory \n");
+			     "Failed in beiscsi_alloc_memory\n");
 		return ret;
 	}
 
@@ -3101,12 +3159,12 @@
 	}
 	SE_DEBUG(DBG_LVL_8,
 		 "phba->io_sgl_hndl_avbl=%d"
-		 "phba->eh_sgl_hndl_avbl=%d \n",
+		 "phba->eh_sgl_hndl_avbl=%d\n",
 		 phba->io_sgl_hndl_avbl,
 		 phba->eh_sgl_hndl_avbl);
 	mem_descr_sg = phba->init_mem;
 	mem_descr_sg += HWI_MEM_SGE;
-	SE_DEBUG(DBG_LVL_8, "\n mem_descr_sg->num_elements=%d \n",
+	SE_DEBUG(DBG_LVL_8, "\n mem_descr_sg->num_elements=%d\n",
 		 mem_descr_sg->num_elements);
 	arr_index = 0;
 	idx = 0;
@@ -3155,7 +3213,7 @@
 	if (!phba->ep_array) {
 		shost_printk(KERN_ERR, phba->shost,
 			     "Failed to allocate memory in "
-			     "hba_setup_cid_tbls \n");
+			     "hba_setup_cid_tbls\n");
 		kfree(phba->cid_array);
 		return -ENOMEM;
 	}
@@ -3168,7 +3226,7 @@
 	return 0;
 }
 
-static unsigned char hwi_enable_intr(struct beiscsi_hba *phba)
+static void hwi_enable_intr(struct beiscsi_hba *phba)
 {
 	struct be_ctrl_info *ctrl = &phba->ctrl;
 	struct hwi_controller *phwi_ctrlr;
@@ -3184,26 +3242,25 @@
 	addr = (u8 __iomem *) ((u8 __iomem *) ctrl->pcicfg +
 			PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET);
 	reg = ioread32(addr);
-	SE_DEBUG(DBG_LVL_8, "reg =x%08x \n", reg);
+	SE_DEBUG(DBG_LVL_8, "reg =x%08x\n", reg);
 
 	enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
 	if (!enabled) {
 		reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
-		SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p \n", reg, addr);
+		SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p\n", reg, addr);
 		iowrite32(reg, addr);
 		if (!phba->msix_enabled) {
 			eq = &phwi_context->be_eq[0].q;
-			SE_DEBUG(DBG_LVL_8, "eq->id=%d \n", eq->id);
+			SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id);
 			hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1);
 		} else {
 			for (i = 0; i <= phba->num_cpus; i++) {
 				eq = &phwi_context->be_eq[i].q;
-				SE_DEBUG(DBG_LVL_8, "eq->id=%d \n", eq->id);
+				SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id);
 				hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1);
 			}
 		}
 	}
-	return true;
 }
 
 static void hwi_disable_intr(struct beiscsi_hba *phba)
@@ -3219,7 +3276,7 @@
 		iowrite32(reg, addr);
 	} else
 		shost_printk(KERN_WARNING, phba->shost,
-			     "In hwi_disable_intr, Already Disabled \n");
+			     "In hwi_disable_intr, Already Disabled\n");
 }
 
 static int beiscsi_init_port(struct beiscsi_hba *phba)
@@ -3230,14 +3287,14 @@
 	if (ret < 0) {
 		shost_printk(KERN_ERR, phba->shost,
 			     "beiscsi_dev_probe - Failed in"
-			     "beiscsi_init_controller \n");
+			     "beiscsi_init_controller\n");
 		return ret;
 	}
 	ret = beiscsi_init_sgl_handle(phba);
 	if (ret < 0) {
 		shost_printk(KERN_ERR, phba->shost,
 			     "beiscsi_dev_probe - Failed in"
-			     "beiscsi_init_sgl_handle \n");
+			     "beiscsi_init_sgl_handle\n");
 		goto do_cleanup_ctrlr;
 	}
 
@@ -3291,12 +3348,12 @@
 
 static void beiscsi_clean_port(struct beiscsi_hba *phba)
 {
-	unsigned char mgmt_status;
+	int mgmt_status;
 
 	mgmt_status = mgmt_epfw_cleanup(phba, CMD_CONNECTION_CHUTE_0);
 	if (mgmt_status)
 		shost_printk(KERN_WARNING, phba->shost,
-			     "mgmt_epfw_cleanup FAILED \n");
+			     "mgmt_epfw_cleanup FAILED\n");
 
 	hwi_purge_eq(phba);
 	hwi_cleanup(phba);
@@ -3428,14 +3485,12 @@
 		return -ENOMEM;
 	io_task->bhs_pa.u.a64.address = paddr;
 	io_task->libiscsi_itt = (itt_t)task->itt;
-	io_task->pwrb_handle = alloc_wrb_handle(phba,
-						beiscsi_conn->beiscsi_conn_cid -
-						phba->fw_config.iscsi_cid_start
-						);
 	io_task->conn = beiscsi_conn;
 
 	task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr;
 	task->hdr_max = sizeof(struct be_cmd_bhs);
+	io_task->psgl_handle = NULL;
+	io_task->psgl_handle = NULL;
 
 	if (task->sc) {
 		spin_lock(&phba->io_sgl_lock);
@@ -3443,6 +3498,11 @@
 		spin_unlock(&phba->io_sgl_lock);
 		if (!io_task->psgl_handle)
 			goto free_hndls;
+		io_task->pwrb_handle = alloc_wrb_handle(phba,
+					beiscsi_conn->beiscsi_conn_cid -
+					phba->fw_config.iscsi_cid_start);
+		if (!io_task->pwrb_handle)
+			goto free_io_hndls;
 	} else {
 		io_task->scsi_cmnd = NULL;
 		if ((opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) {
@@ -3457,9 +3517,20 @@
 				beiscsi_conn->login_in_progress = 1;
 				beiscsi_conn->plogin_sgl_handle =
 							io_task->psgl_handle;
+				io_task->pwrb_handle =
+					alloc_wrb_handle(phba,
+					beiscsi_conn->beiscsi_conn_cid -
+					phba->fw_config.iscsi_cid_start);
+				if (!io_task->pwrb_handle)
+					goto free_io_hndls;
+				beiscsi_conn->plogin_wrb_handle =
+							io_task->pwrb_handle;
+
 			} else {
 				io_task->psgl_handle =
 						beiscsi_conn->plogin_sgl_handle;
+				io_task->pwrb_handle =
+						beiscsi_conn->plogin_wrb_handle;
 			}
 		} else {
 			spin_lock(&phba->mgmt_sgl_lock);
@@ -3467,6 +3538,13 @@
 			spin_unlock(&phba->mgmt_sgl_lock);
 			if (!io_task->psgl_handle)
 				goto free_hndls;
+			io_task->pwrb_handle =
+					alloc_wrb_handle(phba,
+					beiscsi_conn->beiscsi_conn_cid -
+					phba->fw_config.iscsi_cid_start);
+			if (!io_task->pwrb_handle)
+				goto free_mgmt_hndls;
+
 		}
 	}
 	itt = (itt_t) cpu_to_be32(((unsigned int)io_task->pwrb_handle->
@@ -3477,16 +3555,26 @@
 	io_task->cmd_bhs->iscsi_hdr.itt = itt;
 	return 0;
 
+free_io_hndls:
+	spin_lock(&phba->io_sgl_lock);
+	free_io_sgl_handle(phba, io_task->psgl_handle);
+	spin_unlock(&phba->io_sgl_lock);
+	goto free_hndls;
+free_mgmt_hndls:
+	spin_lock(&phba->mgmt_sgl_lock);
+	free_mgmt_sgl_handle(phba, io_task->psgl_handle);
+	spin_unlock(&phba->mgmt_sgl_lock);
 free_hndls:
 	phwi_ctrlr = phba->phwi_ctrlr;
 	pwrb_context = &phwi_ctrlr->wrb_context[
 			beiscsi_conn->beiscsi_conn_cid -
 			phba->fw_config.iscsi_cid_start];
-	free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle);
+	if (io_task->pwrb_handle)
+		free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle);
 	io_task->pwrb_handle = NULL;
 	pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
 		      io_task->bhs_pa.u.a64.address);
-	SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed \n");
+	SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed\n");
 	return -ENOMEM;
 }
 
@@ -3653,7 +3741,7 @@
 		break;
 
 	default:
-		SE_DEBUG(DBG_LVL_1, "opcode =%d Not supported \n",
+		SE_DEBUG(DBG_LVL_1, "opcode =%d Not supported\n",
 			 task->hdr->opcode & ISCSI_OPCODE_MASK);
 		return -EINVAL;
 	}
@@ -3689,13 +3777,11 @@
 		SE_DEBUG(DBG_LVL_1, " scsi_dma_map Failed\n")
 		return num_sg;
 	}
-	SE_DEBUG(DBG_LVL_4, "xferlen=0x%08x scmd=%p num_sg=%d sernum=%lu\n",
-		  (scsi_bufflen(sc)), sc, num_sg, sc->serial_number);
 	xferlen = scsi_bufflen(sc);
 	sg = scsi_sglist(sc);
 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
 		writedir = 1;
-		SE_DEBUG(DBG_LVL_4, "task->imm_count=0x%08x \n",
+		SE_DEBUG(DBG_LVL_4, "task->imm_count=0x%08x\n",
 			 task->imm_count);
 	} else
 		writedir = 0;
@@ -3709,10 +3795,12 @@
 	struct hwi_context_memory *phwi_context;
 	struct be_eq_obj *pbe_eq;
 	unsigned int i, msix_vec;
+	u8 *real_offset = 0;
+	u32 value = 0;
 
 	phba = (struct beiscsi_hba *)pci_get_drvdata(pcidev);
 	if (!phba) {
-		dev_err(&pcidev->dev, "beiscsi_remove called with no phba \n");
+		dev_err(&pcidev->dev, "beiscsi_remove called with no phba\n");
 		return;
 	}
 
@@ -3737,6 +3825,14 @@
 
 	beiscsi_clean_port(phba);
 	beiscsi_free_mem(phba);
+	real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
+
+	value = readl((void *)real_offset);
+
+	if (value & 0x00010000) {
+		value &= 0xfffeffff;
+		writel(value, (void *)real_offset);
+	}
 	beiscsi_unmap_pci_function(phba);
 	pci_free_consistent(phba->pcidev,
 			    phba->ctrl.mbox_mem_alloced.size,
@@ -3769,19 +3865,21 @@
 	struct hwi_controller *phwi_ctrlr;
 	struct hwi_context_memory *phwi_context;
 	struct be_eq_obj *pbe_eq;
-	int ret, msix_vec, num_cpus, i;
+	int ret, num_cpus, i;
+	u8 *real_offset = 0;
+	u32 value = 0;
 
 	ret = beiscsi_enable_pci(pcidev);
 	if (ret < 0) {
-		shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
-			     "Failed to enable pci device \n");
+		dev_err(&pcidev->dev, "beiscsi_dev_probe-"
+			" Failed to enable pci device\n");
 		return ret;
 	}
 
 	phba = beiscsi_hba_alloc(pcidev);
 	if (!phba) {
 		dev_err(&pcidev->dev, "beiscsi_dev_probe-"
-			" Failed in beiscsi_hba_alloc \n");
+			" Failed in beiscsi_hba_alloc\n");
 		goto disable_pci;
 	}
 
@@ -3804,7 +3902,7 @@
 	else
 		num_cpus = 1;
 	phba->num_cpus = num_cpus;
-	SE_DEBUG(DBG_LVL_8, "num_cpus = %d \n", phba->num_cpus);
+	SE_DEBUG(DBG_LVL_8, "num_cpus = %d\n", phba->num_cpus);
 
 	if (enable_msix)
 		beiscsi_msix_enable(phba);
@@ -3815,6 +3913,33 @@
 		goto hba_free;
 	}
 
+	if (!num_hba) {
+		real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
+		value = readl((void *)real_offset);
+		if (value & 0x00010000) {
+			gcrashmode++;
+			shost_printk(KERN_ERR, phba->shost,
+				"Loading Driver in crashdump mode\n");
+			ret = beiscsi_pci_soft_reset(phba);
+			if (ret) {
+				shost_printk(KERN_ERR, phba->shost,
+					"Reset Failed. Aborting Crashdump\n");
+				goto hba_free;
+			}
+			ret = be_chk_reset_complete(phba);
+			if (ret) {
+				shost_printk(KERN_ERR, phba->shost,
+					"Failed to get out of reset."
+					"Aborting Crashdump\n");
+				goto hba_free;
+			}
+		} else {
+			value |= 0x00010000;
+			writel(value, (void *)real_offset);
+			num_hba++;
+		}
+	}
+
 	spin_lock_init(&phba->io_sgl_lock);
 	spin_lock_init(&phba->mgmt_sgl_lock);
 	spin_lock_init(&phba->isr_lock);
@@ -3870,25 +3995,10 @@
 			     "Failed to beiscsi_init_irqs\n");
 		goto free_blkenbld;
 	}
-	ret = hwi_enable_intr(phba);
-	if (ret < 0) {
-		shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
-			     "Failed to hwi_enable_intr\n");
-		goto free_ctrlr;
-	}
-	SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED \n\n\n");
+	hwi_enable_intr(phba);
+	SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n");
 	return 0;
 
-free_ctrlr:
-	if (phba->msix_enabled) {
-		for (i = 0; i <= phba->num_cpus; i++) {
-			msix_vec = phba->msix_entries[i].vector;
-			free_irq(msix_vec, &phwi_context->be_eq[i]);
-		}
-	} else
-		if (phba->pcidev->irq)
-			free_irq(phba->pcidev->irq, phba);
-	pci_disable_msix(phba->pcidev);
 free_blkenbld:
 	destroy_workqueue(phba->wq);
 	if (blk_iopoll_enabled)
@@ -3900,12 +4010,23 @@
 	beiscsi_clean_port(phba);
 	beiscsi_free_mem(phba);
 free_port:
+	real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
+
+	value = readl((void *)real_offset);
+
+	if (value & 0x00010000) {
+		value &= 0xfffeffff;
+		writel(value, (void *)real_offset);
+	}
+
 	pci_free_consistent(phba->pcidev,
 			    phba->ctrl.mbox_mem_alloced.size,
 			    phba->ctrl.mbox_mem_alloced.va,
 			   phba->ctrl.mbox_mem_alloced.dma);
 	beiscsi_unmap_pci_function(phba);
 hba_free:
+	if (phba->msix_enabled)
+		pci_disable_msix(phba->pcidev);
 	iscsi_host_remove(phba->shost);
 	pci_dev_put(phba->pcidev);
 	iscsi_host_free(phba->shost);
@@ -3955,7 +4076,7 @@
 	.get_session_param = iscsi_session_get_param,
 	.get_host_param = beiscsi_get_host_param,
 	.start_conn = beiscsi_conn_start,
-	.stop_conn = beiscsi_conn_stop,
+	.stop_conn = iscsi_conn_stop,
 	.send_pdu = iscsi_conn_send_pdu,
 	.xmit_task = beiscsi_task_xmit,
 	.cleanup_task = beiscsi_cleanup_task,
@@ -3988,7 +4109,7 @@
 			 "transport.\n");
 		return -ENOMEM;
 	}
-	SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p \n",
+	SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p\n",
 		 &beiscsi_iscsi_transport);
 
 	ret = pci_register_driver(&beiscsi_pci_driver);
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index 87ec212..c643bb3 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -23,6 +23,7 @@
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/if_ether.h>
 #include <linux/in.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -39,7 +40,7 @@
 				"Linux iSCSI Driver version" BUILD_STR
 #define DRV_DESC		BE_NAME " " "Driver"
 
-#define BE_VENDOR_ID 		0x19A2
+#define BE_VENDOR_ID		0x19A2
 /* DEVICE ID's for BE2 */
 #define BE_DEVICE_ID1		0x212
 #define OC_DEVICE_ID1		0x702
@@ -68,8 +69,15 @@
 #define BEISCSI_NUM_MAX_LUN	256	/* scsi_host->max_lun */
 #define BEISCSI_NUM_DEVICES_SUPPORTED	0x01
 #define BEISCSI_MAX_FRAGS_INIT	192
-#define BE_NUM_MSIX_ENTRIES 	1
-#define MPU_EP_SEMAPHORE 	0xac
+#define BE_NUM_MSIX_ENTRIES	1
+
+#define MPU_EP_CONTROL          0
+#define MPU_EP_SEMAPHORE        0xac
+#define BE2_SOFT_RESET          0x5c
+#define BE2_PCI_ONLINE0         0xb0
+#define BE2_PCI_ONLINE1         0xb4
+#define BE2_SET_RESET           0x80
+#define BE2_MPU_IRAM_ONLINE     0x00000080
 
 #define BE_SENSE_INFO_SIZE		258
 #define BE_ISCSI_PDU_HEADER_SIZE	64
@@ -105,7 +113,7 @@
 #define HWI_GET_ASYNC_PDU_CTX(phwi)	(phwi->phwi_ctxt->pasync_ctx)
 
 /********* Memory BAR register ************/
-#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 	0xfc
+#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET	0xfc
 /**
  * Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt
  * Disable" may still globally block interrupts in addition to individual
@@ -116,7 +124,7 @@
 #define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK	(1 << 29)	/* bit 29 */
 
 /********* ISR0 Register offset **********/
-#define CEV_ISR0_OFFSET 			0xC18
+#define CEV_ISR0_OFFSET				0xC18
 #define CEV_ISR_SIZE				4
 
 /**
@@ -139,12 +147,12 @@
 #define DB_EQ_REARM_SHIFT		(29)	/* bit 29 */
 
 /********* Compl Q door bell *************/
-#define DB_CQ_OFFSET 			0x120
+#define DB_CQ_OFFSET			0x120
 #define DB_CQ_RING_ID_MASK		0x3FF	/* bits 0 - 9 */
 /* Number of event entries processed */
-#define DB_CQ_NUM_POPPED_SHIFT		(16) 	/* bits 16 - 28 */
+#define DB_CQ_NUM_POPPED_SHIFT		(16)	/* bits 16 - 28 */
 /* Rearm bit */
-#define DB_CQ_REARM_SHIFT		(29) 	/* bit 29 */
+#define DB_CQ_REARM_SHIFT		(29)	/* bit 29 */
 
 #define GET_HWI_CONTROLLER_WS(pc)	(pc->phwi_ctrlr)
 #define HWI_GET_DEF_BUFQ_ID(pc) (((struct hwi_controller *)\
@@ -161,12 +169,12 @@
 	HWI_MEM_WRBH,
 	HWI_MEM_SGLH,
 	HWI_MEM_SGE,
-	HWI_MEM_ASYNC_HEADER_BUF, 	/* 5 */
+	HWI_MEM_ASYNC_HEADER_BUF,	/* 5 */
 	HWI_MEM_ASYNC_DATA_BUF,
 	HWI_MEM_ASYNC_HEADER_RING,
 	HWI_MEM_ASYNC_DATA_RING,
 	HWI_MEM_ASYNC_HEADER_HANDLE,
-	HWI_MEM_ASYNC_DATA_HANDLE, 	/* 10 */
+	HWI_MEM_ASYNC_DATA_HANDLE,	/* 10 */
 	HWI_MEM_ASYNC_PDU_CONTEXT,
 	ISCSI_MEM_GLOBAL_HEADER,
 	SE_MEM_MAX
@@ -352,6 +360,7 @@
 	u32 beiscsi_conn_cid;
 	struct beiscsi_endpoint *ep;
 	unsigned short login_in_progress;
+	struct wrb_handle *plogin_wrb_handle;
 	struct sgl_handle *plogin_sgl_handle;
 	struct beiscsi_session *beiscsi_sess;
 	struct iscsi_task *task;
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index 350cbea..3f3fab9 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -21,7 +21,7 @@
 #include "be_mgmt.h"
 #include "be_iscsi.h"
 
-unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl,
+int mgmt_get_fw_config(struct be_ctrl_info *ctrl,
 				struct beiscsi_hba *phba)
 {
 	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
@@ -50,7 +50,7 @@
 					pfw_cfg->ulp[0].sq_count;
 		if (phba->fw_config.iscsi_cid_count > (BE2_MAX_SESSIONS / 2)) {
 			SE_DEBUG(DBG_LVL_8,
-				"FW reported MAX CXNS as %d \t"
+				"FW reported MAX CXNS as %d\t"
 				"Max Supported = %d.\n",
 				phba->fw_config.iscsi_cid_count,
 				BE2_MAX_SESSIONS);
@@ -58,14 +58,14 @@
 		}
 	} else {
 		shost_printk(KERN_WARNING, phba->shost,
-			     "Failed in mgmt_get_fw_config \n");
+			     "Failed in mgmt_get_fw_config\n");
 	}
 
 	spin_unlock(&ctrl->mbox_lock);
 	return status;
 }
 
-unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
+int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
 				      struct beiscsi_hba *phba)
 {
 	struct be_dma_mem nonemb_cmd;
@@ -81,7 +81,7 @@
 		SE_DEBUG(DBG_LVL_1,
 			 "Failed to allocate memory for mgmt_check_supported_fw"
 			 "\n");
-		return -1;
+		return -ENOMEM;
 	}
 	nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes);
 	req = nonemb_cmd.va;
@@ -117,8 +117,7 @@
 	return status;
 }
 
-
-unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
+int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
 {
 	struct be_ctrl_info *ctrl = &phba->ctrl;
 	struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
@@ -144,11 +143,12 @@
 	return status;
 }
 
-unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
+unsigned int  mgmt_invalidate_icds(struct beiscsi_hba *phba,
 				struct invalidate_command_table *inv_tbl,
-				unsigned int num_invalidate, unsigned int cid)
+				unsigned int num_invalidate, unsigned int cid,
+				struct be_dma_mem *nonemb_cmd)
+
 {
-	struct be_dma_mem nonemb_cmd;
 	struct be_ctrl_info *ctrl = &phba->ctrl;
 	struct be_mcc_wrb *wrb;
 	struct be_sge *sge;
@@ -162,17 +162,7 @@
 		return tag;
 	}
 
-	nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev,
-				sizeof(struct invalidate_commands_params_in),
-				&nonemb_cmd.dma);
-	if (nonemb_cmd.va == NULL) {
-		SE_DEBUG(DBG_LVL_1,
-			 "Failed to allocate memory for mgmt_invalidate_icds\n");
-		spin_unlock(&ctrl->mbox_lock);
-		return 0;
-	}
-	nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
-	req = nonemb_cmd.va;
+	req = nonemb_cmd->va;
 	memset(req, 0, sizeof(*req));
 	wrb = wrb_from_mccq(phba);
 	sge = nonembedded_sgl(wrb);
@@ -190,19 +180,16 @@
 		req->icd_count++;
 		inv_tbl++;
 	}
-	sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma));
-	sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF);
-	sge->len = cpu_to_le32(nonemb_cmd.size);
+	sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+	sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+	sge->len = cpu_to_le32(nonemb_cmd->size);
 
 	be_mcc_notify(phba);
 	spin_unlock(&ctrl->mbox_lock);
-	if (nonemb_cmd.va)
-		pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
-				    nonemb_cmd.va, nonemb_cmd.dma);
 	return tag;
 }
 
-unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
+unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
 					 struct beiscsi_endpoint *beiscsi_ep,
 					 unsigned short cid,
 					 unsigned short issue_reset,
@@ -239,7 +226,7 @@
 	return tag;
 }
 
-unsigned char mgmt_upload_connection(struct beiscsi_hba *phba,
+unsigned int mgmt_upload_connection(struct beiscsi_hba *phba,
 				unsigned short cid, unsigned int upload_flag)
 {
 	struct be_ctrl_info *ctrl = &phba->ctrl;
@@ -269,7 +256,9 @@
 
 int mgmt_open_connection(struct beiscsi_hba *phba,
 			 struct sockaddr *dst_addr,
-			 struct beiscsi_endpoint *beiscsi_ep)
+			 struct beiscsi_endpoint *beiscsi_ep,
+			 struct be_dma_mem *nonemb_cmd)
+
 {
 	struct hwi_controller *phwi_ctrlr;
 	struct hwi_context_memory *phwi_context;
@@ -285,6 +274,7 @@
 	unsigned int tag = 0;
 	unsigned int i;
 	unsigned short cid = beiscsi_ep->ep_cid;
+	struct be_sge *sge;
 
 	phwi_ctrlr = phba->phwi_ctrlr;
 	phwi_context = phwi_ctrlr->phwi_ctxt;
@@ -300,10 +290,14 @@
 		return tag;
 	}
 	wrb = wrb_from_mccq(phba);
-	req = embedded_payload(wrb);
+	memset(wrb, 0, sizeof(*wrb));
+	sge = nonembedded_sgl(wrb);
+
+	req = nonemb_cmd->va;
+	memset(req, 0, sizeof(*req));
 	wrb->tag0 |= tag;
 
-	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 1);
 	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
 			   OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD,
 			   sizeof(*req));
@@ -331,6 +325,7 @@
 		shost_printk(KERN_ERR, phba->shost, "unknown addr family %d\n",
 			     dst_addr->sa_family);
 		spin_unlock(&ctrl->mbox_lock);
+		free_mcc_tag(&phba->ctrl, tag);
 		return -EINVAL;
 
 	}
@@ -339,13 +334,16 @@
 	if (phba->nxt_cqid == phba->num_cpus)
 		phba->nxt_cqid = 0;
 	req->cq_id = phwi_context->be_cq[i].id;
-	SE_DEBUG(DBG_LVL_8, "i=%d cq_id=%d \n", i, req->cq_id);
+	SE_DEBUG(DBG_LVL_8, "i=%d cq_id=%d\n", i, req->cq_id);
 	req->defq_id = def_hdr_id;
 	req->hdr_ring_id = def_hdr_id;
 	req->data_ring_id = def_data_id;
 	req->do_offload = 1;
 	req->dataout_template_pa.lo = ptemplate_address->lo;
 	req->dataout_template_pa.hi = ptemplate_address->hi;
+	sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+	sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+	sge->len = cpu_to_le32(nonemb_cmd->size);
 	be_mcc_notify(phba);
 	spin_unlock(&ctrl->mbox_lock);
 	return tag;
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index 3d316b8..b9acedf 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -86,16 +86,19 @@
 	struct mcc_wrb_payload payload;
 };
 
-unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute);
-int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr,
-			 struct beiscsi_endpoint *beiscsi_ep);
+int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute);
+int mgmt_open_connection(struct beiscsi_hba *phba,
+			 struct sockaddr *dst_addr,
+			 struct beiscsi_endpoint *beiscsi_ep,
+			 struct be_dma_mem *nonemb_cmd);
 
-unsigned char mgmt_upload_connection(struct beiscsi_hba *phba,
+unsigned int mgmt_upload_connection(struct beiscsi_hba *phba,
 				     unsigned short cid,
 				     unsigned int upload_flag);
-unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
+unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
 				struct invalidate_command_table *inv_tbl,
-				unsigned int num_invalidate, unsigned int cid);
+				unsigned int num_invalidate, unsigned int cid,
+				struct be_dma_mem *nonemb_cmd);
 
 struct iscsi_invalidate_connection_params_in {
 	struct be_cmd_req_hdr hdr;
@@ -237,10 +240,10 @@
 	u16 cid_vld;
 };
 
-unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl,
+int mgmt_get_fw_config(struct be_ctrl_info *ctrl,
 				 struct beiscsi_hba *phba);
 
-unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
+unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
 					 struct beiscsi_endpoint *beiscsi_ep,
 					 unsigned short cid,
 					 unsigned short issue_reset,
diff --git a/drivers/scsi/bfa/Makefile b/drivers/scsi/bfa/Makefile
index 17e06ca..ac3fdf0 100644
--- a/drivers/scsi/bfa/Makefile
+++ b/drivers/scsi/bfa/Makefile
@@ -1,7 +1,7 @@
 obj-$(CONFIG_SCSI_BFA_FC) := bfa.o
 
 bfa-y := bfad.o bfad_intr.o bfad_os.o bfad_im.o bfad_attr.o bfad_fwimg.o
-
+bfa-y += bfad_debugfs.o
 bfa-y += bfa_core.o bfa_ioc.o bfa_ioc_ct.o bfa_ioc_cb.o bfa_iocfc.o bfa_fcxp.o
 bfa-y += bfa_lps.o bfa_hw_cb.o bfa_hw_ct.o bfa_intr.o bfa_timer.o bfa_rport.o
 bfa-y += bfa_fcport.o bfa_port.o bfa_uf.o bfa_sgpg.o bfa_module.o bfa_ioim.o
diff --git a/drivers/scsi/bfa/bfa_cb_ioim_macros.h b/drivers/scsi/bfa/bfa_cb_ioim_macros.h
index 53a616f..3906ed9 100644
--- a/drivers/scsi/bfa/bfa_cb_ioim_macros.h
+++ b/drivers/scsi/bfa/bfa_cb_ioim_macros.h
@@ -171,6 +171,11 @@
 	return cmnd->cmd_len;
 }
 
-
+/**
+ * Assign queue to be used for the I/O request. This value depends on whether
+ * the driver wants to use the queues via any specific algorithm. Currently,
+ * this is not supported.
+ */
+#define bfa_cb_ioim_get_reqq(__dio) BFA_FALSE
 
 #endif /* __BFA_HCB_IOIM_MACROS_H__ */
diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c
index d845506..76fa5c5 100644
--- a/drivers/scsi/bfa/bfa_core.c
+++ b/drivers/scsi/bfa/bfa_core.c
@@ -333,6 +333,7 @@
 		{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G2P},
 		{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G1P},
 		{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT},
+		{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT_FC},
 	};
 
 	*npciids = ARRAY_SIZE(__pciids);
diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c
index 790c945..8c703d8 100644
--- a/drivers/scsi/bfa/bfa_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcpim.c
@@ -80,11 +80,6 @@
 }
 
 static void
-bfa_fcpim_initdone(struct bfa_s *bfa)
-{
-}
-
-static void
 bfa_fcpim_detach(struct bfa_s *bfa)
 {
 	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
@@ -172,4 +167,28 @@
 	return fcpim->q_depth;
 }
 
+void
+bfa_fcpim_update_ioredirect(struct bfa_s *bfa)
+{
+	bfa_boolean_t ioredirect;
 
+	/*
+	 * IO redirection is turned off when QoS is enabled and vice versa
+	 */
+	ioredirect = bfa_fcport_is_qos_enabled(bfa) ? BFA_FALSE : BFA_TRUE;
+
+	/*
+	 * Notify the bfad module of a possible state change in
+	 * IO redirection capability, due to a QoS state change. bfad will
+	 * check on the support for io redirection and update the
+	 * fcpim's ioredirect state accordingly.
+	 */
+	bfa_cb_ioredirect_state_change((void *)(bfa->bfad), ioredirect);
+}
+
+void
+bfa_fcpim_set_ioredirect(struct bfa_s *bfa, bfa_boolean_t state)
+{
+	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+	fcpim->ioredirect = state;
+}
diff --git a/drivers/scsi/bfa/bfa_fcpim_priv.h b/drivers/scsi/bfa/bfa_fcpim_priv.h
index 5cf4184..762516c 100644
--- a/drivers/scsi/bfa/bfa_fcpim_priv.h
+++ b/drivers/scsi/bfa/bfa_fcpim_priv.h
@@ -49,7 +49,8 @@
 	int			num_tskim_reqs;
 	u32		path_tov;
 	u16		q_depth;
-	u16		rsvd;
+	u8              reqq;           /* Request queue to be used */
+	u8		rsvd;
 	struct list_head 	itnim_q;        /*  queue of active itnim    */
 	struct list_head 	ioim_free_q;    /*  free IO resources        */
 	struct list_head 	ioim_resfree_q; /*  IOs waiting for f/w      */
@@ -58,6 +59,7 @@
 	u32	ios_active;	/*  current active IOs	      */
 	u32	delay_comp;
 	struct bfa_fcpim_stats_s stats;
+	bfa_boolean_t           ioredirect;
 };
 
 struct bfa_ioim_s;
@@ -82,6 +84,7 @@
 	struct bfa_cb_qe_s hcb_qe;	/*  bfa callback qelem       */
 	bfa_cb_cbfn_t io_cbfn;		/*  IO completion handler    */
 	struct bfa_ioim_sp_s *iosp;	/*  slow-path IO handling    */
+	u8 reqq;           		/* Request queue for I/O    */
 };
 
 struct bfa_ioim_sp_s {
@@ -141,6 +144,7 @@
 	struct bfa_reqq_wait_s reqq_wait; /*  to wait for room in reqq */
 	struct bfa_fcpim_mod_s *fcpim;	/*  fcpim module                */
 	struct bfa_itnim_hal_stats_s	stats;
+	struct bfa_itnim_latency_s  io_latency;
 };
 
 #define bfa_itnim_is_online(_itnim) ((_itnim)->is_online)
diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c
index c589488..f0933d8 100644
--- a/drivers/scsi/bfa/bfa_fcport.c
+++ b/drivers/scsi/bfa/bfa_fcport.c
@@ -18,6 +18,7 @@
 #include <bfa.h>
 #include <bfa_svc.h>
 #include <bfi/bfi_pport.h>
+#include <bfi/bfi_pbc.h>
 #include <cs/bfa_debug.h>
 #include <aen/bfa_aen.h>
 #include <cs/bfa_plog.h>
@@ -310,10 +311,12 @@
 
 		if (!bfa_ioc_get_fcmode(&fcport->bfa->ioc)) {
 
-			bfa_trc(fcport->bfa, pevent->link_state.fcf.fipenabled);
-			bfa_trc(fcport->bfa, pevent->link_state.fcf.fipfailed);
+			bfa_trc(fcport->bfa,
+				pevent->link_state.vc_fcf.fcf.fipenabled);
+			bfa_trc(fcport->bfa,
+				pevent->link_state.vc_fcf.fcf.fipfailed);
 
-			if (pevent->link_state.fcf.fipfailed)
+			if (pevent->link_state.vc_fcf.fcf.fipfailed)
 				bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
 					BFA_PL_EID_FIP_FCF_DISC, 0,
 					"FIP FCF Discovery Failed");
@@ -888,6 +891,7 @@
 	struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 	struct bfa_pport_cfg_s *port_cfg = &fcport->cfg;
 	struct bfa_fcport_ln_s *ln = &fcport->ln;
+	struct bfa_timeval_s tv;
 
 	bfa_os_memset(fcport, 0, sizeof(struct bfa_fcport_s));
 	fcport->bfa = bfa;
@@ -899,6 +903,12 @@
 	bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn);
 
 	/**
+	 * initialize time stamp for stats reset
+	 */
+	bfa_os_gettimeofday(&tv);
+	fcport->stats_reset_time = tv.tv_sec;
+
+	/**
 	 * initialize and set default configuration
 	 */
 	port_cfg->topology = BFA_PPORT_TOPOLOGY_P2P;
@@ -912,25 +922,6 @@
 }
 
 static void
-bfa_fcport_initdone(struct bfa_s *bfa)
-{
-	struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
-
-	/**
-	 * Initialize port attributes from IOC hardware data.
-	 */
-	bfa_fcport_set_wwns(fcport);
-	if (fcport->cfg.maxfrsize == 0)
-		fcport->cfg.maxfrsize = bfa_ioc_maxfrsize(&bfa->ioc);
-	fcport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc);
-	fcport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc);
-
-	bfa_assert(fcport->cfg.maxfrsize);
-	bfa_assert(fcport->cfg.rx_bbcredit);
-	bfa_assert(fcport->speed_sup);
-}
-
-static void
 bfa_fcport_detach(struct bfa_s *bfa)
 {
 }
@@ -971,14 +962,15 @@
 	fcport->topology = pevent->link_state.topology;
 
 	if (fcport->topology == BFA_PPORT_TOPOLOGY_LOOP)
-		fcport->myalpa =
-			pevent->link_state.tl.loop_info.myalpa;
+		fcport->myalpa = 0;
 
 	/*
 	 * QoS Details
 	 */
 	bfa_os_assign(fcport->qos_attr, pevent->link_state.qos_attr);
-	bfa_os_assign(fcport->qos_vc_attr, pevent->link_state.qos_vc_attr);
+	bfa_os_assign(fcport->qos_vc_attr,
+		pevent->link_state.vc_fcf.qos_vc_attr);
+
 
 	bfa_trc(fcport->bfa, fcport->speed);
 	bfa_trc(fcport->bfa, fcport->topology);
@@ -1145,16 +1137,22 @@
 
 	if (complete) {
 		if (fcport->stats_status == BFA_STATUS_OK) {
+			struct bfa_timeval_s tv;
 
 			/* Swap FC QoS or FCoE stats */
-			if (bfa_ioc_get_fcmode(&fcport->bfa->ioc))
+			if (bfa_ioc_get_fcmode(&fcport->bfa->ioc)) {
 				bfa_fcport_qos_stats_swap(
 					&fcport->stats_ret->fcqos,
 					&fcport->stats->fcqos);
-			else
+			} else {
 				bfa_fcport_fcoe_stats_swap(
 					&fcport->stats_ret->fcoe,
 					&fcport->stats->fcoe);
+
+				bfa_os_gettimeofday(&tv);
+				fcport->stats_ret->fcoe.secs_reset =
+					tv.tv_sec - fcport->stats_reset_time;
+			}
 		}
 		fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
 	} else {
@@ -1210,6 +1208,14 @@
 	struct bfa_fcport_s *fcport = cbarg;
 
 	if (complete) {
+		struct bfa_timeval_s tv;
+
+		/**
+		 * re-initialize time stamp for stats reset
+		 */
+		bfa_os_gettimeofday(&tv);
+		fcport->stats_reset_time = tv.tv_sec;
+
 		fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
 	} else {
 		fcport->stats_busy = BFA_FALSE;
@@ -1263,6 +1269,29 @@
  */
 
 /**
+ * Called to initialize port attributes
+ */
+void
+bfa_fcport_init(struct bfa_s *bfa)
+{
+	struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
+
+	/**
+	 * Initialize port attributes from IOC hardware data.
+	 */
+	bfa_fcport_set_wwns(fcport);
+	if (fcport->cfg.maxfrsize == 0)
+		fcport->cfg.maxfrsize = bfa_ioc_maxfrsize(&bfa->ioc);
+	fcport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc);
+	fcport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc);
+
+	bfa_assert(fcport->cfg.maxfrsize);
+	bfa_assert(fcport->cfg.rx_bbcredit);
+	bfa_assert(fcport->speed_sup);
+}
+
+
+/**
  * Firmware message handler.
  */
 void
@@ -1355,6 +1384,17 @@
 bfa_fcport_enable(struct bfa_s *bfa)
 {
 	struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
+	struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+	struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+
+	/* if port is PBC disabled, return error */
+	if (cfgrsp->pbc_cfg.port_enabled == BFI_PBC_PORT_DISABLED) {
+		bfa_trc(bfa, fcport->pwwn);
+		return BFA_STATUS_PBC;
+	}
+
+	if (bfa_ioc_is_disabled(&bfa->ioc))
+		return BFA_STATUS_IOC_DISABLED;
 
 	if (fcport->diag_busy)
 		return BFA_STATUS_DIAG_BUSY;
@@ -1369,6 +1409,16 @@
 bfa_status_t
 bfa_fcport_disable(struct bfa_s *bfa)
 {
+	struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
+	struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+	struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+
+	/* if port is PBC disabled, return error */
+	if (cfgrsp->pbc_cfg.port_enabled == BFI_PBC_PORT_DISABLED) {
+		bfa_trc(bfa, fcport->pwwn);
+		return BFA_STATUS_PBC;
+	}
+
 	bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_DISABLE);
 	return BFA_STATUS_OK;
 }
@@ -1559,12 +1609,17 @@
 bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr)
 {
 	struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
+	struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+	struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
 
 	bfa_os_memset(attr, 0, sizeof(struct bfa_pport_attr_s));
 
 	attr->nwwn = fcport->nwwn;
 	attr->pwwn = fcport->pwwn;
 
+	attr->factorypwwn =  bfa_ioc_get_mfg_pwwn(&bfa->ioc);
+	attr->factorynwwn =  bfa_ioc_get_mfg_nwwn(&bfa->ioc);
+
 	bfa_os_memcpy(&attr->pport_cfg, &fcport->cfg,
 		      sizeof(struct bfa_pport_cfg_s));
 	/*
@@ -1590,11 +1645,18 @@
 
 	attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa);
 	attr->pport_cfg.q_depth = bfa_fcpim_qdepth_get(bfa);
-	attr->port_state = bfa_sm_to_state(hal_pport_sm_table, fcport->sm);
-	if (bfa_ioc_is_disabled(&fcport->bfa->ioc))
-		attr->port_state = BFA_PPORT_ST_IOCDIS;
-	else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc))
-		attr->port_state = BFA_PPORT_ST_FWMISMATCH;
+
+	/* PBC Disabled State */
+	if (cfgrsp->pbc_cfg.port_enabled == BFI_PBC_PORT_DISABLED)
+		attr->port_state = BFA_PPORT_ST_PREBOOT_DISABLED;
+	else {
+		attr->port_state = bfa_sm_to_state(
+				hal_pport_sm_table, fcport->sm);
+		if (bfa_ioc_is_disabled(&fcport->bfa->ioc))
+			attr->port_state = BFA_PPORT_ST_IOCDIS;
+		else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc))
+			attr->port_state = BFA_PPORT_ST_FWMISMATCH;
+	}
 }
 
 #define BFA_FCPORT_STATS_TOV	1000
@@ -1801,8 +1863,13 @@
 
 	bfa_trc(bfa, ioc_type);
 
-	if (ioc_type == BFA_IOC_TYPE_FC)
+	if (ioc_type == BFA_IOC_TYPE_FC) {
 		fcport->cfg.qos_enabled = on_off;
+		/**
+		 * Notify fcpim of the change in QoS state
+		 */
+		bfa_fcpim_update_ioredirect(bfa);
+	}
 }
 
 void
@@ -1886,4 +1953,10 @@
 	return bfa_sm_cmp_state(BFA_FCPORT_MOD(bfa), bfa_fcport_sm_linkup);
 }
 
+bfa_boolean_t
+bfa_fcport_is_qos_enabled(struct bfa_s *bfa)
+{
+	struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
+	return fcport->cfg.qos_enabled;
+}
diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c
index 153cb2a..d1a9920 100644
--- a/drivers/scsi/bfa/bfa_fcs.c
+++ b/drivers/scsi/bfa/bfa_fcs.c
@@ -99,14 +99,22 @@
 void
 bfa_fcs_init(struct bfa_fcs_s *fcs)
 {
-	int             i;
+	int i, npbc_vports;
 	struct bfa_fcs_mod_s  *mod;
+	struct bfi_pbc_vport_s pbc_vports[BFI_PBC_MAX_VPORTS];
 
 	for (i = 0; i < ARRAY_SIZE(fcs_modules); i++) {
 		mod = &fcs_modules[i];
 		if (mod->modinit)
 			mod->modinit(fcs);
 	}
+	/* Initialize pbc vports */
+	if (!fcs->min_cfg) {
+		npbc_vports =
+			bfa_iocfc_get_pbc_vports(fcs->bfa, pbc_vports);
+		for (i = 0; i < npbc_vports; i++)
+			bfa_fcb_pbc_vport_create(fcs->bfa->bfad, pbc_vports[i]);
+	}
 }
 
 /**
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index 7c1251c..35df20e 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -135,6 +135,9 @@
 		bfa_fcs_port_deleted(port);
 		break;
 
+	case BFA_FCS_PORT_SM_OFFLINE:
+		break;
+
 	default:
 		bfa_sm_fault(port->fcs, event);
 	}
diff --git a/drivers/scsi/bfa/bfa_fcxp.c b/drivers/scsi/bfa/bfa_fcxp.c
index cf0ad67..8258f88 100644
--- a/drivers/scsi/bfa/bfa_fcxp.c
+++ b/drivers/scsi/bfa/bfa_fcxp.c
@@ -149,11 +149,6 @@
 }
 
 static void
-bfa_fcxp_initdone(struct bfa_s *bfa)
-{
-}
-
-static void
 bfa_fcxp_detach(struct bfa_s *bfa)
 {
 }
@@ -225,7 +220,7 @@
 		       bfa_status_t req_status, u32 rsp_len,
 		       u32 resid_len, struct fchs_s *rsp_fchs)
 {
-	/**discarded fcxp completion */
+	/* discarded fcxp completion */
 }
 
 static void
@@ -527,11 +522,8 @@
 		if (nreq_sgles > BFI_SGE_INLINE) {
 			nreq_sgpg = BFA_SGPG_NPAGE(nreq_sgles);
 
-			if (bfa_sgpg_malloc
-			    (bfa, &fcxp->req_sgpg_q, nreq_sgpg)
+			if (bfa_sgpg_malloc(bfa, &fcxp->req_sgpg_q, nreq_sgpg)
 			    != BFA_STATUS_OK) {
-				/* bfa_sgpg_wait(bfa, &fcxp->req_sgpg_wqe,
-				nreq_sgpg); */
 				/*
 				 * TODO
 				 */
@@ -685,7 +677,7 @@
 	fcxp->send_cbarg = cbarg;
 
 	/**
-	 * If no room in CPE queue, wait for
+	 * If no room in CPE queue, wait for space in request queue
 	 */
 	send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP);
 	if (!send_req) {
diff --git a/drivers/scsi/bfa/bfa_fwimg_priv.h b/drivers/scsi/bfa/bfa_fwimg_priv.h
index 1ec1355..d33e19e 100644
--- a/drivers/scsi/bfa/bfa_fwimg_priv.h
+++ b/drivers/scsi/bfa/bfa_fwimg_priv.h
@@ -21,11 +21,24 @@
 #define	BFI_FLASH_CHUNK_SZ		256	/*  Flash chunk size */
 #define	BFI_FLASH_CHUNK_SZ_WORDS	(BFI_FLASH_CHUNK_SZ/sizeof(u32))
 
-extern u32 *bfi_image_ct_get_chunk(u32 off);
-extern u32 bfi_image_ct_size;
-extern u32 *bfi_image_cb_get_chunk(u32 off);
-extern u32 bfi_image_cb_size;
-extern u32 *bfi_image_cb;
-extern u32 *bfi_image_ct;
+/**
+ * BFI FW image type
+ */
+enum {
+	BFI_IMAGE_CB_FC,
+	BFI_IMAGE_CT_FC,
+	BFI_IMAGE_CT_CNA,
+	BFI_IMAGE_MAX,
+};
+
+extern u32 *bfi_image_get_chunk(int type, uint32_t off);
+extern u32 bfi_image_get_size(int type);
+extern u32 bfi_image_ct_fc_size;
+extern u32 bfi_image_ct_cna_size;
+extern u32 bfi_image_cb_fc_size;
+extern u32 *bfi_image_ct_fc;
+extern u32 *bfi_image_ct_cna;
+extern u32 *bfi_image_cb_fc;
+
 
 #endif /* __BFA_FWIMG_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_hw_cb.c b/drivers/scsi/bfa/bfa_hw_cb.c
index 871a4e2..edfd729 100644
--- a/drivers/scsi/bfa/bfa_hw_cb.c
+++ b/drivers/scsi/bfa/bfa_hw_cb.c
@@ -152,4 +152,9 @@
 	bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack_msix;
 }
 
-
+void
+bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end)
+{
+	*start = BFA_MSIX_RME_Q0;
+	*end = BFA_MSIX_RME_Q7;
+}
diff --git a/drivers/scsi/bfa/bfa_hw_ct.c b/drivers/scsi/bfa/bfa_hw_ct.c
index 76ceb9a..a357fb3 100644
--- a/drivers/scsi/bfa/bfa_hw_ct.c
+++ b/drivers/scsi/bfa/bfa_hw_ct.c
@@ -168,4 +168,9 @@
 	bfa_ioc_isr_mode_set(&bfa->ioc, msix);
 }
 
-
+void
+bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end)
+{
+	*start = BFA_MSIX_RME_Q0;
+	*end = BFA_MSIX_RME_Q3;
+}
diff --git a/drivers/scsi/bfa/bfa_intr.c b/drivers/scsi/bfa/bfa_intr.c
index 0eba3f9..4936788 100644
--- a/drivers/scsi/bfa/bfa_intr.c
+++ b/drivers/scsi/bfa/bfa_intr.c
@@ -134,6 +134,7 @@
 
 	bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr_unmask);
 	bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, ~intr_unmask);
+	bfa->iocfc.intr_mask = ~intr_unmask;
 	bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0);
 }
 
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index e038bc9..8e78f20 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -59,22 +59,18 @@
 			((__ioc)->ioc_hwif->ioc_firmware_lock(__ioc))
 #define bfa_ioc_firmware_unlock(__ioc)                  \
 			((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc))
-#define bfa_ioc_fwimg_get_chunk(__ioc, __off)           \
-			((__ioc)->ioc_hwif->ioc_fwimg_get_chunk(__ioc, __off))
-#define bfa_ioc_fwimg_get_size(__ioc)                   \
-			((__ioc)->ioc_hwif->ioc_fwimg_get_size(__ioc))
 #define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc))
 #define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))
 #define bfa_ioc_notify_hbfail(__ioc)                    \
 			((__ioc)->ioc_hwif->ioc_notify_hbfail(__ioc))
+#define bfa_ioc_is_optrom(__ioc)        \
+	(bfi_image_get_size(BFA_IOC_FWIMG_TYPE(__ioc)) < BFA_IOC_FWIMG_MINSZ)
 
 bfa_boolean_t   bfa_auto_recover = BFA_TRUE;
 
 /*
  * forward declarations
  */
-static void     bfa_ioc_aen_post(struct bfa_ioc_s *bfa,
-				 enum bfa_ioc_aen_event event);
 static void     bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc);
 static void     bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc);
 static void     bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force);
@@ -88,6 +84,7 @@
 static void     bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc);
 static void     bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc);
 static void     bfa_ioc_recover(struct bfa_ioc_s *ioc);
+static void	bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc);
 static void     bfa_ioc_disable_comp(struct bfa_ioc_s *ioc);
 static void     bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc);
 
@@ -433,6 +430,7 @@
 	switch (event) {
 	case IOC_E_FWRSP_GETATTR:
 		bfa_ioc_timer_stop(ioc);
+		bfa_ioc_check_attr_wwns(ioc);
 		bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
 		break;
 
@@ -879,8 +877,8 @@
 	struct bfi_ioc_image_hdr_s *drv_fwhdr;
 	int             i;
 
-	drv_fwhdr =
-		(struct bfi_ioc_image_hdr_s *)bfa_ioc_fwimg_get_chunk(ioc, 0);
+	drv_fwhdr = (struct bfi_ioc_image_hdr_s *)
+			bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0);
 
 	for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) {
 		if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i]) {
@@ -907,12 +905,13 @@
 	/**
 	 * If bios/efi boot (flash based) -- return true
 	 */
-	if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+	if (bfa_ioc_is_optrom(ioc))
 		return BFA_TRUE;
 
 	bfa_ioc_fwver_get(ioc, &fwhdr);
-	drv_fwhdr =
-		(struct bfi_ioc_image_hdr_s *)bfa_ioc_fwimg_get_chunk(ioc, 0);
+	drv_fwhdr = (struct bfi_ioc_image_hdr_s *)
+			bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0);
+
 
 	if (fwhdr.signature != drv_fwhdr->signature) {
 		bfa_trc(ioc, fwhdr.signature);
@@ -980,8 +979,13 @@
 	/**
 	 * If IOC function is disabled and firmware version is same,
 	 * just re-enable IOC.
+	 *
+	 * If option rom, IOC must not be in operational state. With
+	 * convergence, IOC will be in operational state when 2nd driver
+	 * is loaded.
 	 */
-	if (ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP) {
+	if (ioc_fwstate == BFI_IOC_DISABLED ||
+		(!bfa_ioc_is_optrom(ioc) && ioc_fwstate == BFI_IOC_OP)) {
 		bfa_trc(ioc, ioc_fwstate);
 
 		/**
@@ -1125,21 +1129,22 @@
 	/**
 	 * Flash based firmware boot
 	 */
-	bfa_trc(ioc, bfa_ioc_fwimg_get_size(ioc));
-	if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+	bfa_trc(ioc, bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)));
+	if (bfa_ioc_is_optrom(ioc))
 		boot_type = BFI_BOOT_TYPE_FLASH;
-	fwimg = bfa_ioc_fwimg_get_chunk(ioc, chunkno);
+	fwimg = bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno);
+
 
 	pgnum = bfa_ioc_smem_pgnum(ioc, loff);
 	pgoff = bfa_ioc_smem_pgoff(ioc, loff);
 
 	bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
 
-	for (i = 0; i < bfa_ioc_fwimg_get_size(ioc); i++) {
+	for (i = 0; i < bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)); i++) {
 
 		if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) {
 			chunkno = BFA_IOC_FLASH_CHUNK_NO(i);
-			fwimg = bfa_ioc_fwimg_get_chunk(ioc,
+			fwimg = bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc),
 					BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
 		}
 
@@ -1188,6 +1193,7 @@
 	struct bfi_ioc_attr_s *attr = ioc->attr;
 
 	attr->adapter_prop = bfa_os_ntohl(attr->adapter_prop);
+	attr->card_type     = bfa_os_ntohl(attr->card_type);
 	attr->maxfrsize = bfa_os_ntohs(attr->maxfrsize);
 
 	bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);
@@ -1282,6 +1288,7 @@
 		bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_INITING);
 	}
 
+	bfa_ioc_msgflush(ioc);
 	bfa_ioc_download_fw(ioc, boot_type, boot_param);
 
 	/**
@@ -1416,7 +1423,7 @@
 {
 	ioc->ioc_mc = mc;
 	ioc->pcidev = *pcidev;
-	ioc->ctdev = (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT);
+	ioc->ctdev  = bfa_asic_id_ct(ioc->pcidev.device_id);
 	ioc->cna = ioc->ctdev && !ioc->fcmode;
 
 	/**
@@ -1607,6 +1614,13 @@
 	bfa_fsm_send_event(ioc, IOC_E_HWERROR);
 }
 
+void
+bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc)
+{
+	ioc->fcmode  = BFA_TRUE;
+	ioc->port_id = bfa_ioc_pcifn(ioc);
+}
+
 #ifndef BFA_BIOS_BUILD
 
 /**
@@ -1696,6 +1710,9 @@
 	/* For now, model descr uses same model string */
 	bfa_ioc_get_adapter_model(ioc, ad_attr->model_descr);
 
+	ad_attr->card_type = ioc_attr->card_type;
+	ad_attr->is_mezz = bfa_mfg_is_mezz(ioc_attr->card_type);
+
 	if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop))
 		ad_attr->prototype = 1;
 	else
@@ -1779,28 +1796,17 @@
 bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model)
 {
 	struct bfi_ioc_attr_s   *ioc_attr;
-	u8              nports;
-	u8              max_speed;
 
 	bfa_assert(model);
 	bfa_os_memset((void *)model, 0, BFA_ADAPTER_MODEL_NAME_LEN);
 
 	ioc_attr = ioc->attr;
 
-	nports = bfa_ioc_get_nports(ioc);
-	max_speed = bfa_ioc_speed_sup(ioc);
-
 	/**
 	 * model name
 	 */
-	if (max_speed == 10) {
-		strcpy(model, "BR-10?0");
-		model[5] = '0' + nports;
-	} else {
-		strcpy(model, "Brocade-??5");
-		model[8] = '0' + max_speed;
-		model[9] = '0' + nports;
-	}
+	snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u",
+			BFA_MFG_NAME, ioc_attr->card_type);
 }
 
 enum bfa_ioc_state
@@ -1827,78 +1833,54 @@
 }
 
 /**
- *  hal_wwn_public
+ *  bfa_wwn_public
  */
 wwn_t
 bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc)
 {
-	union {
-		wwn_t           wwn;
-		u8         byte[sizeof(wwn_t)];
-	}
-	w;
-
-	w.wwn = ioc->attr->mfg_wwn;
-
-	if (bfa_ioc_portid(ioc) == 1)
-		w.byte[7]++;
-
-	return w.wwn;
+	return ioc->attr->pwwn;
 }
 
 wwn_t
 bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc)
 {
-	union {
-		wwn_t           wwn;
-		u8         byte[sizeof(wwn_t)];
-	}
-	w;
-
-	w.wwn = ioc->attr->mfg_wwn;
-
-	if (bfa_ioc_portid(ioc) == 1)
-		w.byte[7]++;
-
-	w.byte[0] = 0x20;
-
-	return w.wwn;
-}
-
-wwn_t
-bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst)
-{
-	union {
-		wwn_t           wwn;
-		u8         byte[sizeof(wwn_t)];
-	}
-	w              , w5;
-
-	bfa_trc(ioc, inst);
-
-	w.wwn = ioc->attr->mfg_wwn;
-	w5.byte[0] = 0x50 | w.byte[2] >> 4;
-	w5.byte[1] = w.byte[2] << 4 | w.byte[3] >> 4;
-	w5.byte[2] = w.byte[3] << 4 | w.byte[4] >> 4;
-	w5.byte[3] = w.byte[4] << 4 | w.byte[5] >> 4;
-	w5.byte[4] = w.byte[5] << 4 | w.byte[6] >> 4;
-	w5.byte[5] = w.byte[6] << 4 | w.byte[7] >> 4;
-	w5.byte[6] = w.byte[7] << 4 | (inst & 0x0f00) >> 8;
-	w5.byte[7] = (inst & 0xff);
-
-	return w5.wwn;
+	return ioc->attr->nwwn;
 }
 
 u64
 bfa_ioc_get_adid(struct bfa_ioc_s *ioc)
 {
-	return ioc->attr->mfg_wwn;
+	return ioc->attr->mfg_pwwn;
 }
 
 mac_t
 bfa_ioc_get_mac(struct bfa_ioc_s *ioc)
 {
-	mac_t           mac;
+	/*
+	 * Currently mfg mac is used as FCoE enode mac (not configured by PBC)
+	 */
+	if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_FCoE)
+		return bfa_ioc_get_mfg_mac(ioc);
+	else
+		return ioc->attr->mac;
+}
+
+wwn_t
+bfa_ioc_get_mfg_pwwn(struct bfa_ioc_s *ioc)
+{
+	return ioc->attr->mfg_pwwn;
+}
+
+wwn_t
+bfa_ioc_get_mfg_nwwn(struct bfa_ioc_s *ioc)
+{
+	return ioc->attr->mfg_nwwn;
+}
+
+mac_t
+bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc)
+{
+	mac_t   mac;
 
 	mac = ioc->attr->mfg_mac;
 	mac.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc);
@@ -1906,23 +1888,16 @@
 	return mac;
 }
 
-void
-bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc)
-{
-	ioc->fcmode = BFA_TRUE;
-	ioc->port_id = bfa_ioc_pcifn(ioc);
-}
-
 bfa_boolean_t
 bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc)
 {
-	return ioc->fcmode || (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_CT);
+	return ioc->fcmode || !bfa_asic_id_ct(ioc->pcidev.device_id);
 }
 
 /**
  * Send AEN notification
  */
-static void
+void
 bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
 {
 	union bfa_aen_data_u aen_data;
@@ -2070,19 +2045,16 @@
 	bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
 }
 
-#else
-
 static void
-bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
+bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc)
 {
-}
+	if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_LL)
+		return;
 
-static void
-bfa_ioc_recover(struct bfa_ioc_s *ioc)
-{
-	bfa_assert(0);
+	if (ioc->attr->nwwn == 0)
+		bfa_ioc_aen_post(ioc, BFA_IOC_AEN_INVALID_NWWN);
+	if (ioc->attr->pwwn == 0)
+		bfa_ioc_aen_post(ioc, BFA_IOC_AEN_INVALID_PWWN);
 }
 
 #endif
-
-
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
index d080440..cae05b2 100644
--- a/drivers/scsi/bfa/bfa_ioc.h
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -186,9 +186,6 @@
 	bfa_status_t    (*ioc_pll_init) (struct bfa_ioc_s *ioc);
 	bfa_boolean_t   (*ioc_firmware_lock)    (struct bfa_ioc_s *ioc);
 	void            (*ioc_firmware_unlock)  (struct bfa_ioc_s *ioc);
-	u32 *   	(*ioc_fwimg_get_chunk)  (struct bfa_ioc_s *ioc,
-						u32 off);
-	u32		(*ioc_fwimg_get_size)   (struct bfa_ioc_s *ioc);
 	void		(*ioc_reg_init) (struct bfa_ioc_s *ioc);
 	void		(*ioc_map_port) (struct bfa_ioc_s *ioc);
 	void		(*ioc_isr_mode_set)     (struct bfa_ioc_s *ioc,
@@ -214,6 +211,10 @@
 
 #define bfa_ioc_stats(_ioc, _stats)     ((_ioc)->stats._stats++)
 #define BFA_IOC_FWIMG_MINSZ     (16 * 1024)
+#define BFA_IOC_FWIMG_TYPE(__ioc)                                       \
+	(((__ioc)->ctdev) ?                                             \
+	 (((__ioc)->fcmode) ? BFI_IMAGE_CT_FC : BFI_IMAGE_CT_CNA) :     \
+	 BFI_IMAGE_CB_FC)
 
 #define BFA_IOC_FLASH_CHUNK_NO(off)             (off / BFI_FLASH_CHUNK_SZ_WORDS)
 #define BFA_IOC_FLASH_OFFSET_IN_CHUNK(off)      (off % BFI_FLASH_CHUNK_SZ_WORDS)
@@ -296,14 +297,17 @@
 			struct bfi_ioc_image_hdr_s *fwhdr);
 bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc,
 			struct bfi_ioc_image_hdr_s *fwhdr);
+void bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event);
 
 /*
  * bfa mfg wwn API functions
  */
 wwn_t bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc);
 wwn_t bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc);
-wwn_t bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst);
 mac_t bfa_ioc_get_mac(struct bfa_ioc_s *ioc);
+wwn_t bfa_ioc_get_mfg_pwwn(struct bfa_ioc_s *ioc);
+wwn_t bfa_ioc_get_mfg_nwwn(struct bfa_ioc_s *ioc);
+mac_t bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc);
 u64 bfa_ioc_get_adid(struct bfa_ioc_s *ioc);
 
 #endif /* __BFA_IOC_H__ */
diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c
index 3ce8531..324bdde 100644
--- a/drivers/scsi/bfa/bfa_ioc_cb.c
+++ b/drivers/scsi/bfa/bfa_ioc_cb.c
@@ -33,26 +33,13 @@
 static bfa_status_t bfa_ioc_cb_pll_init(struct bfa_ioc_s *ioc);
 static bfa_boolean_t bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc);
 static void bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc);
-static u32  *bfa_ioc_cb_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off);
-static u32 bfa_ioc_cb_fwimg_get_size(struct bfa_ioc_s *ioc);
 static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc);
 static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc);
 static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
 static void bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc);
 static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc);
 
-struct bfa_ioc_hwif_s hwif_cb = {
-	bfa_ioc_cb_pll_init,
-	bfa_ioc_cb_firmware_lock,
-	bfa_ioc_cb_firmware_unlock,
-	bfa_ioc_cb_fwimg_get_chunk,
-	bfa_ioc_cb_fwimg_get_size,
-	bfa_ioc_cb_reg_init,
-	bfa_ioc_cb_map_port,
-	bfa_ioc_cb_isr_mode_set,
-	bfa_ioc_cb_notify_hbfail,
-	bfa_ioc_cb_ownership_reset,
-};
+struct bfa_ioc_hwif_s hwif_cb;
 
 /**
  * Called from bfa_ioc_attach() to map asic specific calls.
@@ -60,21 +47,18 @@
 void
 bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc)
 {
+	hwif_cb.ioc_pll_init = bfa_ioc_cb_pll_init;
+	hwif_cb.ioc_firmware_lock = bfa_ioc_cb_firmware_lock;
+	hwif_cb.ioc_firmware_unlock = bfa_ioc_cb_firmware_unlock;
+	hwif_cb.ioc_reg_init = bfa_ioc_cb_reg_init;
+	hwif_cb.ioc_map_port = bfa_ioc_cb_map_port;
+	hwif_cb.ioc_isr_mode_set = bfa_ioc_cb_isr_mode_set;
+	hwif_cb.ioc_notify_hbfail = bfa_ioc_cb_notify_hbfail;
+	hwif_cb.ioc_ownership_reset = bfa_ioc_cb_ownership_reset;
+
 	ioc->ioc_hwif = &hwif_cb;
 }
 
-static u32 *
-bfa_ioc_cb_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off)
-{
-	return bfi_image_cb_get_chunk(off);
-}
-
-static u32
-bfa_ioc_cb_fwimg_get_size(struct bfa_ioc_s *ioc)
-{
-	return bfi_image_cb_size;
-}
-
 /**
  * Return true if firmware of current driver matches the running firmware.
  */
diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c
index 20b58ad..68f027d 100644
--- a/drivers/scsi/bfa/bfa_ioc_ct.c
+++ b/drivers/scsi/bfa/bfa_ioc_ct.c
@@ -33,27 +33,13 @@
 static bfa_status_t bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc);
 static bfa_boolean_t bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc);
 static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc);
-static u32* bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc_s *ioc,
-					u32 off);
-static u32 bfa_ioc_ct_fwimg_get_size(struct bfa_ioc_s *ioc);
 static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc);
 static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc);
 static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
 static void bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc);
 static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc);
 
-struct bfa_ioc_hwif_s hwif_ct = {
-	bfa_ioc_ct_pll_init,
-	bfa_ioc_ct_firmware_lock,
-	bfa_ioc_ct_firmware_unlock,
-	bfa_ioc_ct_fwimg_get_chunk,
-	bfa_ioc_ct_fwimg_get_size,
-	bfa_ioc_ct_reg_init,
-	bfa_ioc_ct_map_port,
-	bfa_ioc_ct_isr_mode_set,
-	bfa_ioc_ct_notify_hbfail,
-	bfa_ioc_ct_ownership_reset,
-};
+struct bfa_ioc_hwif_s hwif_ct;
 
 /**
  * Called from bfa_ioc_attach() to map asic specific calls.
@@ -61,21 +47,18 @@
 void
 bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc)
 {
+	hwif_ct.ioc_pll_init = bfa_ioc_ct_pll_init;
+	hwif_ct.ioc_firmware_lock = bfa_ioc_ct_firmware_lock;
+	hwif_ct.ioc_firmware_unlock = bfa_ioc_ct_firmware_unlock;
+	hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init;
+	hwif_ct.ioc_map_port = bfa_ioc_ct_map_port;
+	hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set;
+	hwif_ct.ioc_notify_hbfail = bfa_ioc_ct_notify_hbfail;
+	hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset;
+
 	ioc->ioc_hwif = &hwif_ct;
 }
 
-static u32*
-bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off)
-{
-	return bfi_image_ct_get_chunk(off);
-}
-
-static u32
-bfa_ioc_ct_fwimg_get_size(struct bfa_ioc_s *ioc)
-{
-	return bfi_image_ct_size;
-}
-
 /**
  * Return true if firmware of current driver matches the running firmware.
  */
@@ -95,7 +78,7 @@
 	/**
 	 * If bios boot (flash based) -- do not increment usage count
 	 */
-	if (bfa_ioc_ct_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+	if (bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) < BFA_IOC_FWIMG_MINSZ)
 		return BFA_TRUE;
 
 	bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
@@ -146,9 +129,14 @@
 
 	/**
 	 * Firmware lock is relevant only for CNA.
+	 */
+	if (!ioc->cna)
+		return;
+
+	/**
 	 * If bios boot (flash based) -- do not decrement usage count
 	 */
-	if (!ioc->cna || bfa_ioc_ct_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+	if (bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) < BFA_IOC_FWIMG_MINSZ)
 		return;
 
 	/**
@@ -388,10 +376,35 @@
 	bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk |
 		__APP_PLL_425_ENABLE);
 
+	/**
+	 * PSS memory reset is asserted at power-on-reset. Need to clear
+	 * this before running EDRAM BISTR
+	 */
+	if (ioc->cna) {
+		bfa_reg_write((rb + PMM_1T_RESET_REG_P0), __PMM_1T_RESET_P);
+		bfa_reg_write((rb + PMM_1T_RESET_REG_P1), __PMM_1T_RESET_P);
+	}
+
+	r32 = bfa_reg_read((rb + PSS_CTL_REG));
+	r32 &= ~__PSS_LMEM_RESET;
+	bfa_reg_write((rb + PSS_CTL_REG), r32);
+	bfa_os_udelay(1000);
+
+	if (ioc->cna) {
+		bfa_reg_write((rb + PMM_1T_RESET_REG_P0), 0);
+		bfa_reg_write((rb + PMM_1T_RESET_REG_P1), 0);
+	}
+
 	bfa_reg_write((rb + MBIST_CTL_REG), __EDRAM_BISTR_START);
 	bfa_os_udelay(1000);
 	r32 = bfa_reg_read((rb + MBIST_STAT_REG));
 	bfa_trc(ioc, r32);
+
+	/**
+	 * Clear BISTR
+	 */
+	bfa_reg_write((rb + MBIST_CTL_REG), 0);
+
 	/*
 	 *  release semaphore.
 	 */
diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c
index a76de26..90820be 100644
--- a/drivers/scsi/bfa/bfa_iocfc.c
+++ b/drivers/scsi/bfa/bfa_iocfc.c
@@ -113,7 +113,6 @@
 	bfa_assert(cfg->fwcfg.num_cqs <= BFI_IOC_MAX_CQS);
 	bfa_trc(bfa, cfg->fwcfg.num_cqs);
 
-	iocfc->cfgdone = BFA_FALSE;
 	bfa_iocfc_reset_queues(bfa);
 
 	/**
@@ -145,6 +144,15 @@
 	}
 
 	/**
+	 * Enable interrupt coalescing if it is driver init path
+	 * and not ioc disable/enable path.
+	 */
+	if (!iocfc->cfgdone)
+		cfg_info->intr_attr.coalesce = BFA_TRUE;
+
+	iocfc->cfgdone = BFA_FALSE;
+
+	/**
 	 * dma map IOC configuration itself
 	 */
 	bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ,
@@ -170,7 +178,7 @@
 	/**
 	 * Initialize chip specific handlers.
 	 */
-	if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) {
+	if (bfa_asic_id_ct(bfa_ioc_devid(&bfa->ioc))) {
 		iocfc->hwif.hw_reginit = bfa_hwct_reginit;
 		iocfc->hwif.hw_reqq_ack = bfa_hwct_reqq_ack;
 		iocfc->hwif.hw_rspq_ack = bfa_hwct_rspq_ack;
@@ -179,6 +187,7 @@
 		iocfc->hwif.hw_msix_uninstall = bfa_hwct_msix_uninstall;
 		iocfc->hwif.hw_isr_mode_set = bfa_hwct_isr_mode_set;
 		iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs;
+		iocfc->hwif.hw_msix_get_rme_range = bfa_hwct_msix_get_rme_range;
 	} else {
 		iocfc->hwif.hw_reginit = bfa_hwcb_reginit;
 		iocfc->hwif.hw_reqq_ack = bfa_hwcb_reqq_ack;
@@ -188,6 +197,7 @@
 		iocfc->hwif.hw_msix_uninstall = bfa_hwcb_msix_uninstall;
 		iocfc->hwif.hw_isr_mode_set = bfa_hwcb_isr_mode_set;
 		iocfc->hwif.hw_msix_getvecs = bfa_hwcb_msix_getvecs;
+		iocfc->hwif.hw_msix_get_rme_range = bfa_hwcb_msix_get_rme_range;
 	}
 
 	iocfc->hwif.hw_reginit(bfa);
@@ -291,18 +301,6 @@
 }
 
 /**
- * BFA submodules initialization completion notification.
- */
-static void
-bfa_iocfc_initdone_submod(struct bfa_s *bfa)
-{
-	int             i;
-
-	for (i = 0; hal_mods[i]; i++)
-		hal_mods[i]->initdone(bfa);
-}
-
-/**
  * Start BFA submodules.
  */
 static void
@@ -376,7 +374,6 @@
 	struct bfa_iocfc_s		*iocfc	 = &bfa->iocfc;
 	struct bfi_iocfc_cfgrsp_s	*cfgrsp  = iocfc->cfgrsp;
 	struct bfa_iocfc_fwcfg_s	*fwcfg   = &cfgrsp->fwcfg;
-	struct bfi_iocfc_cfg_s 		*cfginfo = iocfc->cfginfo;
 
 	fwcfg->num_cqs        = fwcfg->num_cqs;
 	fwcfg->num_ioim_reqs  = bfa_os_ntohs(fwcfg->num_ioim_reqs);
@@ -385,15 +382,13 @@
 	fwcfg->num_uf_bufs    = bfa_os_ntohs(fwcfg->num_uf_bufs);
 	fwcfg->num_rports     = bfa_os_ntohs(fwcfg->num_rports);
 
-	cfginfo->intr_attr.coalesce = cfgrsp->intr_attr.coalesce;
-	cfginfo->intr_attr.delay    = bfa_os_ntohs(cfgrsp->intr_attr.delay);
-	cfginfo->intr_attr.latency  = bfa_os_ntohs(cfgrsp->intr_attr.latency);
-
 	iocfc->cfgdone = BFA_TRUE;
 
 	/**
 	 * Configuration is complete - initialize/start submodules
 	 */
+	bfa_fcport_init(bfa);
+
 	if (iocfc->action == BFA_IOCFC_ACT_INIT)
 		bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa);
 	else
@@ -531,7 +526,6 @@
 		return;
 	}
 
-	bfa_iocfc_initdone_submod(bfa);
 	bfa_iocfc_send_cfg(bfa);
 }
 
@@ -625,9 +619,9 @@
 		bfa->trcmod, bfa->aen, bfa->logm);
 
 	/**
-	 * Choose FC (ssid: 0x1C) v/s FCoE (ssid: 0x14) mode.
+	 * Set FC mode for BFA_PCI_DEVICE_ID_CT_FC.
 	 */
-	if (0)
+	if (pcidev->device_id == BFA_PCI_DEVICE_ID_CT_FC)
 		bfa_ioc_set_fcmode(&bfa->ioc);
 
 	bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_MC_IOCFC);
@@ -748,10 +742,20 @@
 void
 bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr)
 {
-	struct bfa_iocfc_s	*iocfc = &bfa->iocfc;
+	struct bfa_iocfc_s      *iocfc = &bfa->iocfc;
 
-	attr->intr_attr = iocfc->cfginfo->intr_attr;
-	attr->config	= iocfc->cfg;
+	attr->intr_attr.coalesce = iocfc->cfginfo->intr_attr.coalesce;
+
+	attr->intr_attr.delay = iocfc->cfginfo->intr_attr.delay ?
+			bfa_os_ntohs(iocfc->cfginfo->intr_attr.delay) :
+			bfa_os_ntohs(iocfc->cfgrsp->intr_attr.delay);
+
+	attr->intr_attr.latency = iocfc->cfginfo->intr_attr.latency ?
+			bfa_os_ntohs(iocfc->cfginfo->intr_attr.latency) :
+			bfa_os_ntohs(iocfc->cfgrsp->intr_attr.latency);
+
+	attr->config    = iocfc->cfg;
+
 }
 
 bfa_status_t
@@ -760,7 +764,10 @@
 	struct bfa_iocfc_s		*iocfc = &bfa->iocfc;
 	struct bfi_iocfc_set_intr_req_s *m;
 
-	iocfc->cfginfo->intr_attr = *attr;
+	iocfc->cfginfo->intr_attr.coalesce = attr->coalesce;
+	iocfc->cfginfo->intr_attr.delay = bfa_os_htons(attr->delay);
+	iocfc->cfginfo->intr_attr.latency = bfa_os_htons(attr->latency);
+
 	if (!bfa_iocfc_is_operational(bfa))
 		return BFA_STATUS_OK;
 
@@ -770,9 +777,10 @@
 
 	bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ,
 			bfa_lpuid(bfa));
-	m->coalesce = attr->coalesce;
-	m->delay    = bfa_os_htons(attr->delay);
-	m->latency  = bfa_os_htons(attr->latency);
+	m->coalesce = iocfc->cfginfo->intr_attr.coalesce;
+	m->delay    = iocfc->cfginfo->intr_attr.delay;
+	m->latency  = iocfc->cfginfo->intr_attr.latency;
+
 
 	bfa_trc(bfa, attr->delay);
 	bfa_trc(bfa, attr->latency);
@@ -872,15 +880,48 @@
  * Return boot target port wwns -- read from boot information in flash.
  */
 void
-bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns)
+bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns)
 {
-	struct bfa_iocfc_s		*iocfc	 = &bfa->iocfc;
-	struct bfi_iocfc_cfgrsp_s	*cfgrsp  = iocfc->cfgrsp;
+	struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+	struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+	int i;
+
+	if (cfgrsp->pbc_cfg.boot_enabled && cfgrsp->pbc_cfg.nbluns) {
+		bfa_trc(bfa, cfgrsp->pbc_cfg.nbluns);
+		*nwwns = cfgrsp->pbc_cfg.nbluns;
+		for (i = 0; i < cfgrsp->pbc_cfg.nbluns; i++)
+			wwns[i] = cfgrsp->pbc_cfg.blun[i].tgt_pwwn;
+
+		return;
+	}
 
 	*nwwns = cfgrsp->bootwwns.nwwns;
-	*wwns = cfgrsp->bootwwns.wwn;
+	memcpy(wwns, cfgrsp->bootwwns.wwn, sizeof(cfgrsp->bootwwns.wwn));
 }
 
+void
+bfa_iocfc_get_pbc_boot_cfg(struct bfa_s *bfa, struct bfa_boot_pbc_s *pbcfg)
+{
+	struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+	struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+
+	pbcfg->enable = cfgrsp->pbc_cfg.boot_enabled;
+	pbcfg->nbluns = cfgrsp->pbc_cfg.nbluns;
+	pbcfg->speed = cfgrsp->pbc_cfg.port_speed;
+	memcpy(pbcfg->pblun, cfgrsp->pbc_cfg.blun, sizeof(pbcfg->pblun));
+}
+
+int
+bfa_iocfc_get_pbc_vports(struct bfa_s *bfa, struct bfi_pbc_vport_s *pbc_vport)
+{
+	struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+	struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+
+	memcpy(pbc_vport, cfgrsp->pbc_cfg.vport, sizeof(cfgrsp->pbc_cfg.vport));
+	return cfgrsp->pbc_cfg.nvports;
+}
+
+
 #endif
 
 
diff --git a/drivers/scsi/bfa/bfa_iocfc.h b/drivers/scsi/bfa/bfa_iocfc.h
index fbb4bdc..74a6a04 100644
--- a/drivers/scsi/bfa/bfa_iocfc.h
+++ b/drivers/scsi/bfa/bfa_iocfc.h
@@ -21,6 +21,7 @@
 #include <bfa_ioc.h>
 #include <bfa.h>
 #include <bfi/bfi_iocfc.h>
+#include <bfi/bfi_pbc.h>
 #include <bfa_callback_priv.h>
 
 #define BFA_REQQ_NELEMS_MIN	(4)
@@ -62,6 +63,8 @@
 	void (*hw_isr_mode_set)(struct bfa_s *bfa, bfa_boolean_t msix);
 	void (*hw_msix_getvecs)(struct bfa_s *bfa, u32 *vecmap,
 			u32 *nvecs, u32 *maxvec);
+	void (*hw_msix_get_rme_range) (struct bfa_s *bfa, u32 *start,
+			u32 *end);
 };
 typedef void (*bfa_cb_iocfc_t) (void *cbarg, enum bfa_status status);
 
@@ -103,7 +106,8 @@
 	struct bfa_hwif_s	hwif;
 
 	bfa_cb_iocfc_t		updateq_cbfn; /*  bios callback function */
-	void				*updateq_cbarg;	/*  bios callback arg */
+	void			*updateq_cbarg;	/*  bios callback arg */
+	u32			intr_mask;
 };
 
 #define bfa_lpuid(__bfa)		bfa_ioc_portid(&(__bfa)->ioc)
@@ -116,7 +120,10 @@
 #define bfa_isr_mode_set(__bfa, __msix)	\
 	((__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix))
 #define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec)	\
-	(__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec)
+	((__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap,	\
+		 __nvecs, __maxvec))
+#define bfa_msix_get_rme_range(__bfa, __start, __end)   \
+	((__bfa)->iocfc.hwif.hw_msix_get_rme_range(__bfa, __start, __end))
 
 /*
  * FC specific IOC functions.
@@ -152,6 +159,7 @@
 void bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix);
 void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap,
 			u32 *nvecs, u32 *maxvec);
+void bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end);
 void bfa_hwct_reginit(struct bfa_s *bfa);
 void bfa_hwct_reqq_ack(struct bfa_s *bfa, int rspq);
 void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq);
@@ -161,11 +169,16 @@
 void bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix);
 void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *vecmap,
 			u32 *nvecs, u32 *maxvec);
+void bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end);
 
 void bfa_com_meminfo(bfa_boolean_t mincfg, u32 *dm_len);
 void bfa_com_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi,
 		bfa_boolean_t mincfg);
-void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns);
+void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns);
+void bfa_iocfc_get_pbc_boot_cfg(struct bfa_s *bfa,
+		struct bfa_boot_pbc_s *pbcfg);
+int bfa_iocfc_get_pbc_vports(struct bfa_s *bfa,
+		struct bfi_pbc_vport_s *pbc_vport);
 
 #endif /* __BFA_IOCFC_H__ */
 
diff --git a/drivers/scsi/bfa/bfa_ioim.c b/drivers/scsi/bfa/bfa_ioim.c
index 3d2eac1..bdfdc19 100644
--- a/drivers/scsi/bfa/bfa_ioim.c
+++ b/drivers/scsi/bfa/bfa_ioim.c
@@ -133,6 +133,8 @@
 
 	case BFA_IOIM_SM_IOTOV:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
 				__bfa_cb_ioim_pathtov, ioim);
 		break;
@@ -182,6 +184,8 @@
 	case BFA_IOIM_SM_ABORT:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
 		bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
 			      ioim);
 		break;
@@ -189,6 +193,8 @@
 	case BFA_IOIM_SM_HWFAIL:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
 		bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
 			      ioim);
 		break;
@@ -210,18 +216,24 @@
 	switch (event) {
 	case BFA_IOIM_SM_COMP_GOOD:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
 			      __bfa_cb_ioim_good_comp, ioim);
 		break;
 
 	case BFA_IOIM_SM_COMP:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp,
 			      ioim);
 		break;
 
 	case BFA_IOIM_SM_DONE:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp,
 			      ioim);
 		break;
@@ -234,8 +246,8 @@
 			bfa_sm_set_state(ioim, bfa_ioim_sm_abort);
 		else {
 			bfa_sm_set_state(ioim, bfa_ioim_sm_abort_qfull);
-			bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
-					  &ioim->iosp->reqq_wait);
+			bfa_reqq_wait(ioim->bfa, ioim->reqq,
+					&ioim->iosp->reqq_wait);
 		}
 		break;
 
@@ -247,13 +259,15 @@
 			bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup);
 		else {
 			bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
-			bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
-					  &ioim->iosp->reqq_wait);
+			bfa_reqq_wait(ioim->bfa, ioim->reqq,
+					&ioim->iosp->reqq_wait);
 		}
 		break;
 
 	case BFA_IOIM_SM_HWFAIL:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
 			      ioim);
 		break;
@@ -287,12 +301,16 @@
 
 	case BFA_IOIM_SM_ABORT_COMP:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
 			      ioim);
 		break;
 
 	case BFA_IOIM_SM_COMP_UTAG:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
 			      ioim);
 		break;
@@ -305,13 +323,15 @@
 			bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup);
 		else {
 			bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
-			bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
+			bfa_reqq_wait(ioim->bfa, ioim->reqq,
 					  &ioim->iosp->reqq_wait);
 		}
 		break;
 
 	case BFA_IOIM_SM_HWFAIL:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
 			      ioim);
 		break;
@@ -365,6 +385,8 @@
 
 	case BFA_IOIM_SM_HWFAIL:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
 			      ioim);
 		break;
@@ -399,6 +421,8 @@
 	case BFA_IOIM_SM_ABORT:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
 		bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
 			      ioim);
 		break;
@@ -414,6 +438,8 @@
 	case BFA_IOIM_SM_HWFAIL:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
 		bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
 			      ioim);
 		break;
@@ -448,6 +474,8 @@
 	case BFA_IOIM_SM_COMP:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
 		bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
 			      ioim);
 		break;
@@ -455,6 +483,8 @@
 	case BFA_IOIM_SM_DONE:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
 		bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
 			      ioim);
 		break;
@@ -462,6 +492,8 @@
 	case BFA_IOIM_SM_HWFAIL:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
 		bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
 			      ioim);
 		break;
@@ -511,6 +543,8 @@
 	case BFA_IOIM_SM_HWFAIL:
 		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
 		bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+		list_del(&ioim->qe);
+		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
 		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
 			      ioim);
 		break;
@@ -738,9 +772,9 @@
 	/**
 	 * check for room in queue to send request now
 	 */
-	m = bfa_reqq_next(ioim->bfa, itnim->reqq);
+	m = bfa_reqq_next(ioim->bfa, ioim->reqq);
 	if (!m) {
-		bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
+		bfa_reqq_wait(ioim->bfa, ioim->reqq,
 				  &ioim->iosp->reqq_wait);
 		return BFA_FALSE;
 	}
@@ -832,7 +866,7 @@
 	/**
 	 * queue I/O message to firmware
 	 */
-	bfa_reqq_produce(ioim->bfa, itnim->reqq);
+	bfa_reqq_produce(ioim->bfa, ioim->reqq);
 	return BFA_TRUE;
 }
 
@@ -930,14 +964,13 @@
 static          bfa_boolean_t
 bfa_ioim_send_abort(struct bfa_ioim_s *ioim)
 {
-	struct bfa_itnim_s          *itnim = ioim->itnim;
 	struct bfi_ioim_abort_req_s *m;
 	enum bfi_ioim_h2i       msgop;
 
 	/**
 	 * check for room in queue to send request now
 	 */
-	m = bfa_reqq_next(ioim->bfa, itnim->reqq);
+	m = bfa_reqq_next(ioim->bfa, ioim->reqq);
 	if (!m)
 		return BFA_FALSE;
 
@@ -956,7 +989,7 @@
 	/**
 	 * queue I/O message to firmware
 	 */
-	bfa_reqq_produce(ioim->bfa, itnim->reqq);
+	bfa_reqq_produce(ioim->bfa, ioim->reqq);
 	return BFA_TRUE;
 }
 
@@ -1306,6 +1339,14 @@
 bfa_ioim_start(struct bfa_ioim_s *ioim)
 {
 	bfa_trc_fp(ioim->bfa, ioim->iotag);
+
+	/**
+	 * Obtain the queue over which this request has to be issued
+	 */
+	ioim->reqq = bfa_fcpim_ioredirect_enabled(ioim->bfa) ?
+			bfa_cb_ioim_get_reqq(ioim->dio) :
+			bfa_itnim_get_reqq(ioim);
+
 	bfa_sm_send_event(ioim, BFA_IOIM_SM_START);
 }
 
diff --git a/drivers/scsi/bfa/bfa_log_module.c b/drivers/scsi/bfa/bfa_log_module.c
index 5c154d3..cf577ef 100644
--- a/drivers/scsi/bfa/bfa_log_module.c
+++ b/drivers/scsi/bfa/bfa_log_module.c
@@ -110,6 +110,27 @@
  "Running firmware version is incompatible with the driver version.",
  (0), 0},
 
+{BFA_AEN_IOC_FWCFG_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_CRITICAL, "BFA_AEN_IOC_FWCFG_ERROR",
+ "Link initialization failed due to firmware configuration read error:"
+ " WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_IOC_INVALID_VENDOR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "BFA_AEN_IOC_INVALID_VENDOR",
+ "Unsupported switch vendor. Link initialization failed: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_IOC_INVALID_NWWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "BFA_AEN_IOC_INVALID_NWWN",
+ "Invalid NWWN. Link initialization failed: NWWN = 00:00:00:00:00:00:00:00.",
+ (0), 0},
+
+{BFA_AEN_IOC_INVALID_PWWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "BFA_AEN_IOC_INVALID_PWWN",
+ "Invalid PWWN. Link initialization failed: PWWN = 00:00:00:00:00:00:00:00.",
+ (0), 0},
+
 
 
 
@@ -347,6 +368,22 @@
  ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
   (BFA_LOG_D << BFA_LOG_ARG2) | 0), 3},
 
+{BFA_LOG_HAL_DRIVER_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "HAL_DRIVER_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_HAL_DRIVER_CONFIG_ERROR,
+ BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "HAL_DRIVER_CONFIG_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_HAL_MBOX_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "HAL_MBOX_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
 
 
 
@@ -412,6 +449,55 @@
  ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_P << BFA_LOG_ARG1) |
   (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3},
 
+{BFA_LOG_LINUX_DRIVER_CONFIG_ERROR,
+ BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_DRIVER_CONFIG_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_BNA_STATE_MACHINE,
+ BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_BNA_STATE_MACHINE",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_IOC_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_IOC_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_RESOURCE_ALLOC_ERROR,
+ BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_RESOURCE_ALLOC_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_RING_BUFFER_ERROR,
+ BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_RING_BUFFER_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_DRIVER_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "LINUX_DRIVER_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_DRIVER_INFO, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_DRIVER_INFO",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_DRIVER_DIAG, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_DRIVER_DIAG",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_DRIVER_AEN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_DRIVER_AEN",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
 
 
 
diff --git a/drivers/scsi/bfa/bfa_lps.c b/drivers/scsi/bfa/bfa_lps.c
index ad06f61..acabb44 100644
--- a/drivers/scsi/bfa/bfa_lps.c
+++ b/drivers/scsi/bfa/bfa_lps.c
@@ -41,7 +41,6 @@
 			   struct bfa_iocfc_cfg_s *cfg,
 			   struct bfa_meminfo_s *meminfo,
 			   struct bfa_pcidev_s *pcidev);
-static void bfa_lps_initdone(struct bfa_s *bfa);
 static void bfa_lps_detach(struct bfa_s *bfa);
 static void bfa_lps_start(struct bfa_s *bfa);
 static void bfa_lps_stop(struct bfa_s *bfa);
@@ -347,11 +346,6 @@
 }
 
 static void
-bfa_lps_initdone(struct bfa_s *bfa)
-{
-}
-
-static void
 bfa_lps_detach(struct bfa_s *bfa)
 {
 }
diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c
index cab1902..c7e69f1 100644
--- a/drivers/scsi/bfa/bfa_port.c
+++ b/drivers/scsi/bfa/bfa_port.c
@@ -102,9 +102,14 @@
 	port->stats_busy = BFA_FALSE;
 
 	if (status == BFA_STATUS_OK) {
+		struct bfa_timeval_s tv;
+
 		memcpy(port->stats, port->stats_dma.kva,
 		       sizeof(union bfa_pport_stats_u));
 		bfa_port_stats_swap(port, port->stats);
+
+		bfa_os_gettimeofday(&tv);
+		port->stats->fc.secs_reset = tv.tv_sec - port->stats_reset_time;
 	}
 
 	if (port->stats_cbfn) {
@@ -125,9 +130,17 @@
 static void
 bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status)
 {
+	struct bfa_timeval_s tv;
+
 	port->stats_status = status;
 	port->stats_busy = BFA_FALSE;
 
+	/**
+	 * re-initialize time stamp for stats reset
+	 */
+	bfa_os_gettimeofday(&tv);
+	port->stats_reset_time = tv.tv_sec;
+
 	if (port->stats_cbfn) {
 		port->stats_cbfn(port->stats_cbarg, status);
 		port->stats_cbfn = NULL;
@@ -394,7 +407,7 @@
 	 */
 	if (port->stats_busy) {
 		if (port->stats_cbfn)
-			port->stats_cbfn(port->dev, BFA_STATUS_FAILED);
+			port->stats_cbfn(port->stats_cbarg, BFA_STATUS_FAILED);
 		port->stats_cbfn = NULL;
 		port->stats_busy = BFA_FALSE;
 	}
@@ -404,7 +417,7 @@
 	 */
 	if (port->endis_pending) {
 		if (port->endis_cbfn)
-			port->endis_cbfn(port->dev, BFA_STATUS_FAILED);
+			port->endis_cbfn(port->endis_cbarg, BFA_STATUS_FAILED);
 		port->endis_cbfn = NULL;
 		port->endis_pending = BFA_FALSE;
 	}
@@ -428,6 +441,8 @@
 bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, void *dev,
 		struct bfa_trc_mod_s *trcmod, struct bfa_log_mod_s *logmod)
 {
+	struct bfa_timeval_s tv;
+
 	bfa_assert(port);
 
 	port->dev = dev;
@@ -435,13 +450,21 @@
 	port->trcmod = trcmod;
 	port->logmod = logmod;
 
-	port->stats_busy = port->endis_pending = BFA_FALSE;
-	port->stats_cbfn = port->endis_cbfn = NULL;
+	port->stats_busy = BFA_FALSE;
+	port->endis_pending = BFA_FALSE;
+	port->stats_cbfn = NULL;
+	port->endis_cbfn = NULL;
 
 	bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port);
 	bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port);
 	bfa_ioc_hbfail_register(port->ioc, &port->hbfail);
 
+	/**
+	 * initialize time stamp for stats reset
+	 */
+	bfa_os_gettimeofday(&tv);
+	port->stats_reset_time = tv.tv_sec;
+
 	bfa_trc(port, 0);
 }
 
diff --git a/drivers/scsi/bfa/bfa_port_priv.h b/drivers/scsi/bfa/bfa_port_priv.h
index 40e256e..c9ebe04 100644
--- a/drivers/scsi/bfa/bfa_port_priv.h
+++ b/drivers/scsi/bfa/bfa_port_priv.h
@@ -75,8 +75,9 @@
 	bfa_status_t            stats_status; /*  stats/statsclr status */
 	bfa_boolean_t           stats_busy; /*  outstanding stats/statsclr */
 	bfa_boolean_t           stats_qfull;
+	u32                	stats_reset_time; /* stats reset time stamp */
 	bfa_cb_pport_t          stats_cbfn; /*  driver callback function */
-	void                    *stats_cbarg; /* *!< user callback arg */
+	void                    *stats_cbarg; /* user callback arg */
 	bfa_boolean_t           diag_busy; /*  diag busy status */
 	bfa_boolean_t           beacon; /*  port beacon status */
 	bfa_boolean_t           link_e2e_beacon; /*  link beacon status */
@@ -87,5 +88,7 @@
 /*
  * public functions
  */
-void	bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+void bfa_fcport_init(struct bfa_s *bfa);
+void bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+
 #endif /* __BFA_PORT_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_priv.h b/drivers/scsi/bfa/bfa_priv.h
index be80fc7..bf4939b 100644
--- a/drivers/scsi/bfa/bfa_priv.h
+++ b/drivers/scsi/bfa/bfa_priv.h
@@ -37,7 +37,6 @@
 			void *bfad, struct bfa_iocfc_cfg_s *cfg, 	\
 			struct bfa_meminfo_s *meminfo,			\
 			struct bfa_pcidev_s *pcidev);      \
-	static void bfa_ ## __mod ## _initdone(struct bfa_s *bfa);      \
 	static void bfa_ ## __mod ## _detach(struct bfa_s *bfa);      \
 	static void bfa_ ## __mod ## _start(struct bfa_s *bfa);      \
 	static void bfa_ ## __mod ## _stop(struct bfa_s *bfa);      \
@@ -47,7 +46,6 @@
 	struct bfa_module_s hal_mod_ ## __mod = {			\
 		bfa_ ## __mod ## _meminfo,				\
 		bfa_ ## __mod ## _attach,				\
-		bfa_ ## __mod ## _initdone,				\
 		bfa_ ## __mod ## _detach,				\
 		bfa_ ## __mod ## _start,				\
 		bfa_ ## __mod ## _stop,					\
@@ -69,7 +67,6 @@
 			struct bfa_iocfc_cfg_s *cfg,
 			struct bfa_meminfo_s *meminfo,
 			struct bfa_pcidev_s *pcidev);
-	void (*initdone) (struct bfa_s *bfa);
 	void (*detach) (struct bfa_s *bfa);
 	void (*start) (struct bfa_s *bfa);
 	void (*stop) (struct bfa_s *bfa);
diff --git a/drivers/scsi/bfa/bfa_rport.c b/drivers/scsi/bfa/bfa_rport.c
index 7c509fa..ccd0680 100644
--- a/drivers/scsi/bfa/bfa_rport.c
+++ b/drivers/scsi/bfa/bfa_rport.c
@@ -636,11 +636,6 @@
 }
 
 static void
-bfa_rport_initdone(struct bfa_s *bfa)
-{
-}
-
-static void
 bfa_rport_detach(struct bfa_s *bfa)
 {
 }
diff --git a/drivers/scsi/bfa/bfa_sgpg.c b/drivers/scsi/bfa/bfa_sgpg.c
index 279d8f9..ae452c4 100644
--- a/drivers/scsi/bfa/bfa_sgpg.c
+++ b/drivers/scsi/bfa/bfa_sgpg.c
@@ -94,11 +94,6 @@
 }
 
 static void
-bfa_sgpg_initdone(struct bfa_s *bfa)
-{
-}
-
-static void
 bfa_sgpg_detach(struct bfa_s *bfa)
 {
 }
diff --git a/drivers/scsi/bfa/bfa_uf.c b/drivers/scsi/bfa/bfa_uf.c
index 4b3c241..b9a9a68 100644
--- a/drivers/scsi/bfa/bfa_uf.c
+++ b/drivers/scsi/bfa/bfa_uf.c
@@ -170,11 +170,6 @@
 }
 
 static void
-bfa_uf_initdone(struct bfa_s *bfa)
-{
-}
-
-static void
 bfa_uf_detach(struct bfa_s *bfa)
 {
 }
@@ -256,7 +251,10 @@
 				      (struct fchs_s *) buf, pld_w0);
 	}
 
-	bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf);
+	if (bfa->fcs)
+		__bfa_cb_uf_recv(uf, BFA_TRUE);
+	else
+		bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf);
 }
 
 static void
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index d4fc428..915a29d 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -54,31 +54,62 @@
 static int      log_level = BFA_LOG_WARNING;
 static int      ioc_auto_recover = BFA_TRUE;
 static int      ipfc_enable = BFA_FALSE;
-static int      ipfc_mtu = -1;
 static int	fdmi_enable = BFA_TRUE;
 int 		bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH;
 int      	bfa_linkup_delay = -1;
+int		bfa_debugfs_enable = 1;
 
 module_param(os_name, charp, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(os_name, "OS name of the hba host machine");
 module_param(os_patch, charp, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(os_patch, "OS patch level of the hba host machine");
 module_param(host_name, charp, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(host_name, "Hostname of the hba host machine");
 module_param(num_rports, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(num_rports, "Max number of rports supported per port"
+		" (physical/logical), default=1024");
 module_param(num_ios, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(num_ios, "Max number of ioim requests, default=2000");
 module_param(num_tms, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(num_tms, "Max number of task im requests, default=128");
 module_param(num_fcxps, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(num_fcxps, "Max number of fcxp requests, default=64");
 module_param(num_ufbufs, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(num_ufbufs, "Max number of unsolicited frame buffers,"
+		" default=64");
 module_param(reqq_size, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(reqq_size, "Max number of request queue elements,"
+		" default=256");
 module_param(rspq_size, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rspq_size, "Max number of response queue elements,"
+		" default=64");
 module_param(num_sgpgs, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(num_sgpgs, "Number of scatter/gather pages, default=2048");
 module_param(rport_del_timeout, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rport_del_timeout, "Rport delete timeout, default=90 secs,"
+		" Range[>0]");
 module_param(bfa_lun_queue_depth, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(bfa_lun_queue_depth, "Lun queue depth, default=32,"
+		" Range[>0]");
 module_param(bfa_io_max_sge, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(bfa_io_max_sge, "Max io scatter/gather elements, default=255");
 module_param(log_level, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(log_level, "Driver log level, default=3,"
+		" Range[Critical:1|Error:2|Warning:3|Info:4]");
 module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ioc_auto_recover, "IOC auto recovery, default=1,"
+		" Range[off:0|on:1]");
 module_param(ipfc_enable, int, S_IRUGO | S_IWUSR);
-module_param(ipfc_mtu, int, S_IRUGO | S_IWUSR);
-module_param(fdmi_enable, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ipfc_enable, "Enable IPoFC, default=0, Range[off:0|on:1]");
 module_param(bfa_linkup_delay, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(bfa_linkup_delay, "Link up delay, default=30 secs for boot"
+		" port. Otherwise Range[>0]");
+module_param(fdmi_enable, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(fdmi_enable, "Enables fdmi registration, default=1,"
+		" Range[false:0|true:1]");
+module_param(bfa_debugfs_enable, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(bfa_debugfs_enable, "Enables debugfs feature, default=1,"
+		" Range[false:0|true:1]");
 
 /*
  * Stores the module parm num_sgpgs value;
@@ -322,7 +353,31 @@
 	return rc;
 }
 
+/**
+ * @brief
+ * FCS PBC VPORT Create
+ */
+void
+bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s pbc_vport)
+{
 
+	struct bfad_pcfg_s *pcfg;
+
+	pcfg = kzalloc(sizeof(struct bfad_pcfg_s), GFP_ATOMIC);
+	if (!pcfg) {
+		bfa_trc(bfad, 0);
+		return;
+	}
+
+	pcfg->port_cfg.roles = BFA_PORT_ROLE_FCP_IM;
+	pcfg->port_cfg.pwwn = pbc_vport.vp_pwwn;
+	pcfg->port_cfg.nwwn = pbc_vport.vp_nwwn;
+	pcfg->port_cfg.preboot_vp  = BFA_TRUE;
+
+	list_add_tail(&pcfg->list_entry, &bfad->pbc_pcfg_list);
+
+	return;
+}
 
 void
 bfad_hal_mem_release(struct bfad_s *bfad)
@@ -481,10 +536,10 @@
  */
 bfa_status_t
 bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
-		  struct bfa_port_cfg_s *port_cfg, struct device *dev)
+			struct bfa_port_cfg_s *port_cfg, struct device *dev)
 {
 	struct bfad_vport_s *vport;
-	int             rc = BFA_STATUS_OK;
+	int rc = BFA_STATUS_OK;
 	unsigned long   flags;
 	struct completion fcomp;
 
@@ -496,8 +551,12 @@
 
 	vport->drv_port.bfad = bfad;
 	spin_lock_irqsave(&bfad->bfad_lock, flags);
-	rc = bfa_fcs_vport_create(&vport->fcs_vport, &bfad->bfa_fcs, vf_id,
-				  port_cfg, vport);
+	if (port_cfg->preboot_vp == BFA_TRUE)
+		rc = bfa_fcs_pbc_vport_create(&vport->fcs_vport,
+				&bfad->bfa_fcs, vf_id, port_cfg, vport);
+	else
+		rc = bfa_fcs_vport_create(&vport->fcs_vport,
+				&bfad->bfa_fcs, vf_id, port_cfg, vport);
 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 
 	if (rc != BFA_STATUS_OK)
@@ -848,6 +907,10 @@
 		bfad->pport.roles |= BFA_PORT_ROLE_FCP_IM;
 	}
 
+	/* Setup the debugfs node for this scsi_host */
+	if (bfa_debugfs_enable)
+		bfad_debugfs_init(&bfad->pport);
+
 	bfad->bfad_flags |= BFAD_CFG_PPORT_DONE;
 
 out:
@@ -857,6 +920,10 @@
 void
 bfad_uncfg_pport(struct bfad_s *bfad)
 {
+	 /* Remove the debugfs node for this scsi_host */
+	kfree(bfad->regdata);
+	bfad_debugfs_exit(&bfad->pport);
+
 	if ((bfad->pport.roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) {
 		bfad_ipfc_port_delete(bfad, &bfad->pport);
 		bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IPFC;
@@ -884,6 +951,7 @@
 bfad_start_ops(struct bfad_s *bfad)
 {
 	int retval;
+	struct bfad_pcfg_s *pcfg, *pcfg_new;
 
 	/* PPORT FCS config */
 	bfad_fcs_port_cfg(bfad);
@@ -901,6 +969,27 @@
 
 	bfad_drv_start(bfad);
 
+	/* pbc vport creation */
+	list_for_each_entry_safe(pcfg, pcfg_new,  &bfad->pbc_pcfg_list,
+					list_entry) {
+		struct fc_vport_identifiers vid;
+		struct fc_vport *fc_vport;
+
+		memset(&vid, 0, sizeof(vid));
+		vid.roles = FC_PORT_ROLE_FCP_INITIATOR;
+		vid.vport_type = FC_PORTTYPE_NPIV;
+		vid.disable = false;
+		vid.node_name = wwn_to_u64((u8 *)&pcfg->port_cfg.nwwn);
+		vid.port_name = wwn_to_u64((u8 *)&pcfg->port_cfg.pwwn);
+		fc_vport = fc_vport_create(bfad->pport.im_port->shost, 0, &vid);
+		if (!fc_vport)
+			printk(KERN_WARNING "bfad%d: failed to create pbc vport"
+				" %llx\n", bfad->inst_no, vid.port_name);
+		list_del(&pcfg->list_entry);
+		kfree(pcfg);
+
+	}
+
 	/*
 	 * If bfa_linkup_delay is set to -1 default; try to retrive the
 	 * value using the bfad_os_get_linkup_delay(); else use the
@@ -928,7 +1017,7 @@
 }
 
 int
-bfad_worker (void *ptr)
+bfad_worker(void *ptr)
 {
 	struct bfad_s *bfad;
 	unsigned long   flags;
@@ -1031,6 +1120,7 @@
 
 	bfad->ref_count = 0;
 	bfad->pport.bfad = bfad;
+	INIT_LIST_HEAD(&bfad->pbc_pcfg_list);
 
 	bfad->bfad_tsk = kthread_create(bfad_worker, (void *) bfad, "%s",
 					"bfad_worker");
@@ -1172,6 +1262,14 @@
 	 .class = (PCI_CLASS_SERIAL_FIBER << 8),
 	 .class_mask = ~0,
 	 },
+	{
+	 .vendor = BFA_PCI_VENDOR_ID_BROCADE,
+	 .device = BFA_PCI_DEVICE_ID_CT_FC,
+	 .subvendor = PCI_ANY_ID,
+	 .subdevice = PCI_ANY_ID,
+	 .class = (PCI_CLASS_SERIAL_FIBER << 8),
+	 .class_mask = ~0,
+	},
 
 	{0, 0},
 };
diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c
index e477bfb..0818eb0 100644
--- a/drivers/scsi/bfa/bfad_attr.c
+++ b/drivers/scsi/bfa/bfad_attr.c
@@ -373,47 +373,53 @@
 		(struct bfad_im_port_s *) shost->hostdata[0];
 	struct bfad_s *bfad = im_port->bfad;
 	struct bfa_port_cfg_s port_cfg;
+	struct bfad_pcfg_s *pcfg;
 	int status = 0, rc;
 	unsigned long flags;
 
 	memset(&port_cfg, 0, sizeof(port_cfg));
-
-	port_cfg.pwwn = wwn_to_u64((u8 *) &fc_vport->port_name);
-	port_cfg.nwwn = wwn_to_u64((u8 *) &fc_vport->node_name);
-
+	u64_to_wwn(fc_vport->node_name, (u8 *)&port_cfg.nwwn);
+	u64_to_wwn(fc_vport->port_name, (u8 *)&port_cfg.pwwn);
 	if (strlen(vname) > 0)
 		strcpy((char *)&port_cfg.sym_name, vname);
-
 	port_cfg.roles = BFA_PORT_ROLE_FCP_IM;
-	rc = bfad_vport_create(bfad, 0, &port_cfg, &fc_vport->dev);
 
+	spin_lock_irqsave(&bfad->bfad_lock, flags);
+	list_for_each_entry(pcfg, &bfad->pbc_pcfg_list, list_entry) {
+		if (port_cfg.pwwn == pcfg->port_cfg.pwwn) {
+			port_cfg.preboot_vp = pcfg->port_cfg.preboot_vp;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+	rc = bfad_vport_create(bfad, 0, &port_cfg, &fc_vport->dev);
 	if (rc == BFA_STATUS_OK) {
-		struct bfad_vport_s   *vport;
+		struct bfad_vport_s *vport;
 		struct bfa_fcs_vport_s *fcs_vport;
 		struct Scsi_Host *vshost;
 
 		spin_lock_irqsave(&bfad->bfad_lock, flags);
 		fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0,
 					port_cfg.pwwn);
-		if (fcs_vport == NULL) {
-			spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+		if (fcs_vport == NULL)
 			return VPCERR_BAD_WWN;
-		}
 
 		fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
 		if (disable) {
+			spin_lock_irqsave(&bfad->bfad_lock, flags);
 			bfa_fcs_vport_stop(fcs_vport);
+			spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 			fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
 		}
-		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 
 		vport = fcs_vport->vport_drv;
 		vshost = vport->drv_port.im_port->shost;
-		fc_host_node_name(vshost) = wwn_to_u64((u8 *) &port_cfg.nwwn);
-		fc_host_port_name(vshost) = wwn_to_u64((u8 *) &port_cfg.pwwn);
+		fc_host_node_name(vshost) = wwn_to_u64((u8 *)&port_cfg.nwwn);
+		fc_host_port_name(vshost) = wwn_to_u64((u8 *)&port_cfg.pwwn);
 		fc_vport->dd_data = vport;
 		vport->drv_port.im_port->fc_vport = fc_vport;
-
 	} else if (rc == BFA_STATUS_INVALID_WWN)
 		return VPCERR_BAD_WWN;
 	else if (rc == BFA_STATUS_VPORT_EXISTS)
@@ -422,7 +428,7 @@
 		return VPCERR_NO_FABRIC_SUPP;
 	else if (rc == BFA_STATUS_VPORT_WWN_BP)
 		return VPCERR_BAD_WWN;
-	 else
+	else
 		return FC_VPORT_FAILED;
 
 	return status;
@@ -449,7 +455,7 @@
 	port = im_port->port;
 
 	vshost = vport->drv_port.im_port->shost;
-	pwwn = wwn_to_u64((u8 *) &fc_host_port_name(vshost));
+	u64_to_wwn(fc_host_port_name(vshost), (u8 *)&pwwn);
 
 	spin_lock_irqsave(&bfad->bfad_lock, flags);
 	fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn);
@@ -467,6 +473,12 @@
 	rc = bfa_fcs_vport_delete(&vport->fcs_vport);
 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 
+	if (rc == BFA_STATUS_PBC) {
+		vport->drv_port.flags &= ~BFAD_PORT_DELETE;
+		vport->comp_del = NULL;
+		return -1;
+	}
+
 	wait_for_completion(vport->comp_del);
 
 free_scsi_host:
@@ -490,7 +502,7 @@
 	vport = (struct bfad_vport_s *)fc_vport->dd_data;
 	bfad = vport->drv_port.bfad;
 	vshost = vport->drv_port.im_port->shost;
-	pwwn = wwn_to_u64((u8 *) &fc_vport->port_name);
+	u64_to_wwn(fc_host_port_name(vshost), (u8 *)&pwwn);
 
 	spin_lock_irqsave(&bfad->bfad_lock, flags);
 	fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn);
diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c
new file mode 100644
index 0000000..4b82f12
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_debugfs.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+
+#include <bfad_drv.h>
+#include <bfad_im.h>
+
+/*
+ * BFA debufs interface
+ *
+ * To access the interface, debugfs file system should be mounted
+ * if not already mounted using:
+ * mount -t debugfs none /sys/kernel/debug
+ *
+ * BFA Hierarchy:
+ * 	- bfa/host#
+ * where the host number corresponds to the one under /sys/class/scsi_host/host#
+ *
+ * Debugging service available per host:
+ * fwtrc:  To collect current firmware trace.
+ * drvtrc: To collect current driver trace
+ * fwsave: To collect last saved fw trace as a result of firmware crash.
+ * regwr:  To write one word to chip register
+ * regrd:  To read one or more words from chip register.
+ */
+
+struct bfad_debug_info {
+	char *debug_buffer;
+	void *i_private;
+	int buffer_len;
+};
+
+static int
+bfad_debugfs_open_drvtrc(struct inode *inode, struct file *file)
+{
+	struct bfad_port_s *port = inode->i_private;
+	struct bfad_s *bfad = port->bfad;
+	struct bfad_debug_info *debug;
+
+	debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
+	if (!debug)
+		return -ENOMEM;
+
+	debug->debug_buffer = (void *) bfad->trcmod;
+	debug->buffer_len = sizeof(struct bfa_trc_mod_s);
+
+	file->private_data = debug;
+
+	return 0;
+}
+
+static int
+bfad_debugfs_open_fwtrc(struct inode *inode, struct file *file)
+{
+	struct bfad_port_s *port = inode->i_private;
+	struct bfad_s *bfad = port->bfad;
+	struct bfad_debug_info *fw_debug;
+	unsigned long flags;
+	int rc;
+
+	fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
+	if (!fw_debug)
+		return -ENOMEM;
+
+	fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s);
+
+	fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len);
+	if (!fw_debug->debug_buffer) {
+		kfree(fw_debug);
+		printk(KERN_INFO "bfad[%d]: Failed to allocate fwtrc buffer\n",
+				bfad->inst_no);
+		return -ENOMEM;
+	}
+
+	memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len);
+
+	spin_lock_irqsave(&bfad->bfad_lock, flags);
+	rc = bfa_debug_fwtrc(&bfad->bfa,
+			fw_debug->debug_buffer,
+			&fw_debug->buffer_len);
+	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+	if (rc != BFA_STATUS_OK) {
+		vfree(fw_debug->debug_buffer);
+		fw_debug->debug_buffer = NULL;
+		kfree(fw_debug);
+		printk(KERN_INFO "bfad[%d]: Failed to collect fwtrc\n",
+				bfad->inst_no);
+		return -ENOMEM;
+	}
+
+	file->private_data = fw_debug;
+
+	return 0;
+}
+
+static int
+bfad_debugfs_open_fwsave(struct inode *inode, struct file *file)
+{
+	struct bfad_port_s *port = inode->i_private;
+	struct bfad_s *bfad = port->bfad;
+	struct bfad_debug_info *fw_debug;
+	unsigned long flags;
+	int rc;
+
+	fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
+	if (!fw_debug)
+		return -ENOMEM;
+
+	fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s);
+
+	fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len);
+	if (!fw_debug->debug_buffer) {
+		kfree(fw_debug);
+		printk(KERN_INFO "bfad[%d]: Failed to allocate fwsave buffer\n",
+				bfad->inst_no);
+		return -ENOMEM;
+	}
+
+	memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len);
+
+	spin_lock_irqsave(&bfad->bfad_lock, flags);
+	rc = bfa_debug_fwsave(&bfad->bfa,
+			fw_debug->debug_buffer,
+			&fw_debug->buffer_len);
+	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+	if (rc != BFA_STATUS_OK) {
+		vfree(fw_debug->debug_buffer);
+		fw_debug->debug_buffer = NULL;
+		kfree(fw_debug);
+		printk(KERN_INFO "bfad[%d]: Failed to collect fwsave\n",
+				bfad->inst_no);
+		return -ENOMEM;
+	}
+
+	file->private_data = fw_debug;
+
+	return 0;
+}
+
+static int
+bfad_debugfs_open_reg(struct inode *inode, struct file *file)
+{
+	struct bfad_debug_info *reg_debug;
+
+	reg_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
+	if (!reg_debug)
+		return -ENOMEM;
+
+	reg_debug->i_private = inode->i_private;
+
+	file->private_data = reg_debug;
+
+	return 0;
+}
+
+/* Changes the current file position */
+static loff_t
+bfad_debugfs_lseek(struct file *file, loff_t offset, int orig)
+{
+	struct bfad_debug_info *debug;
+	loff_t pos = file->f_pos;
+
+	debug = file->private_data;
+
+	switch (orig) {
+	case 0:
+		file->f_pos = offset;
+		break;
+	case 1:
+		file->f_pos += offset;
+		break;
+	case 2:
+		file->f_pos = debug->buffer_len - offset;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (file->f_pos < 0 || file->f_pos > debug->buffer_len) {
+		file->f_pos = pos;
+		return -EINVAL;
+	}
+
+	return file->f_pos;
+}
+
+static ssize_t
+bfad_debugfs_read(struct file *file, char __user *buf,
+			size_t nbytes, loff_t *pos)
+{
+	struct bfad_debug_info *debug = file->private_data;
+
+	if (!debug || !debug->debug_buffer)
+		return 0;
+
+	return memory_read_from_buffer(buf, nbytes, pos,
+				debug->debug_buffer, debug->buffer_len);
+}
+
+#define BFA_REG_CT_ADDRSZ	(0x40000)
+#define BFA_REG_CB_ADDRSZ	(0x20000)
+#define BFA_REG_ADDRSZ(__bfa)	\
+	((bfa_ioc_devid(&(__bfa)->ioc) == BFA_PCI_DEVICE_ID_CT) ?	\
+		BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ)
+#define BFA_REG_ADDRMSK(__bfa)  ((uint32_t)(BFA_REG_ADDRSZ(__bfa) - 1))
+
+static bfa_status_t
+bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len)
+{
+	u8	area;
+
+	/* check [16:15] */
+	area = (offset >> 15) & 0x7;
+	if (area == 0) {
+		/* PCIe core register */
+		if ((offset + (len<<2)) > 0x8000)    /* 8k dwords or 32KB */
+			return BFA_STATUS_EINVAL;
+	} else if (area == 0x1) {
+		/* CB 32 KB memory page */
+		if ((offset + (len<<2)) > 0x10000)    /* 8k dwords or 32KB */
+			return BFA_STATUS_EINVAL;
+	} else {
+		/* CB register space 64KB */
+		if ((offset + (len<<2)) > BFA_REG_ADDRMSK(bfa))
+			return BFA_STATUS_EINVAL;
+	}
+	return BFA_STATUS_OK;
+}
+
+static ssize_t
+bfad_debugfs_read_regrd(struct file *file, char __user *buf,
+		size_t nbytes, loff_t *pos)
+{
+	struct bfad_debug_info *regrd_debug = file->private_data;
+	struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private;
+	struct bfad_s *bfad = port->bfad;
+	ssize_t rc;
+
+	if (!bfad->regdata)
+		return 0;
+
+	rc = memory_read_from_buffer(buf, nbytes, pos,
+			bfad->regdata, bfad->reglen);
+
+	if ((*pos + nbytes) >= bfad->reglen) {
+		kfree(bfad->regdata);
+		bfad->regdata = NULL;
+		bfad->reglen = 0;
+	}
+
+	return rc;
+}
+
+static ssize_t
+bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
+		size_t nbytes, loff_t *ppos)
+{
+	struct bfad_debug_info *regrd_debug = file->private_data;
+	struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private;
+	struct bfad_s *bfad = port->bfad;
+	struct bfa_s *bfa = &bfad->bfa;
+	struct bfa_ioc_s *ioc = &bfa->ioc;
+	int addr, len, rc, i;
+	u32 *regbuf;
+	void __iomem *rb, *reg_addr;
+	unsigned long flags;
+
+	rc = sscanf(buf, "%x:%x", &addr, &len);
+	if (rc < 2) {
+		printk(KERN_INFO
+			"bfad[%d]: %s failed to read user buf\n",
+			bfad->inst_no, __func__);
+		return -EINVAL;
+	}
+
+	kfree(bfad->regdata);
+	bfad->regdata = NULL;
+	bfad->reglen = 0;
+
+	bfad->regdata = kzalloc(len << 2, GFP_KERNEL);
+	if (!bfad->regdata) {
+		printk(KERN_INFO "bfad[%d]: Failed to allocate regrd buffer\n",
+				bfad->inst_no);
+		return -ENOMEM;
+	}
+
+	bfad->reglen = len << 2;
+	rb = bfa_ioc_bar0(ioc);
+	addr &= BFA_REG_ADDRMSK(bfa);
+
+	/* offset and len sanity check */
+	rc = bfad_reg_offset_check(bfa, addr, len);
+	if (rc) {
+		printk(KERN_INFO "bfad[%d]: Failed reg offset check\n",
+				bfad->inst_no);
+		kfree(bfad->regdata);
+		bfad->regdata = NULL;
+		bfad->reglen = 0;
+		return -EINVAL;
+	}
+
+	reg_addr = rb + addr;
+	regbuf =  (u32 *)bfad->regdata;
+	spin_lock_irqsave(&bfad->bfad_lock, flags);
+	for (i = 0; i < len; i++) {
+		*regbuf = bfa_reg_read(reg_addr);
+		regbuf++;
+		reg_addr += sizeof(u32);
+	}
+	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+	return nbytes;
+}
+
+static ssize_t
+bfad_debugfs_write_regwr(struct file *file, const char __user *buf,
+		size_t nbytes, loff_t *ppos)
+{
+	struct bfad_debug_info *debug = file->private_data;
+	struct bfad_port_s *port = (struct bfad_port_s *)debug->i_private;
+	struct bfad_s *bfad = port->bfad;
+	struct bfa_s *bfa = &bfad->bfa;
+	struct bfa_ioc_s *ioc = &bfa->ioc;
+	int addr, val, rc;
+	void __iomem *reg_addr;
+	unsigned long flags;
+
+	rc = sscanf(buf, "%x:%x", &addr, &val);
+	if (rc < 2) {
+		printk(KERN_INFO
+			"bfad[%d]: %s failed to read user buf\n",
+			bfad->inst_no, __func__);
+		return -EINVAL;
+	}
+
+	addr &= BFA_REG_ADDRMSK(bfa); /* offset only 17 bit and word align */
+
+	/* offset and len sanity check */
+	rc = bfad_reg_offset_check(bfa, addr, 1);
+	if (rc) {
+		printk(KERN_INFO
+			"bfad[%d]: Failed reg offset check\n",
+			bfad->inst_no);
+		return -EINVAL;
+	}
+
+	reg_addr = (uint32_t *) ((uint8_t *) bfa_ioc_bar0(ioc) + addr);
+	spin_lock_irqsave(&bfad->bfad_lock, flags);
+	bfa_reg_write(reg_addr, val);
+	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+	return nbytes;
+}
+
+static int
+bfad_debugfs_release(struct inode *inode, struct file *file)
+{
+	struct bfad_debug_info *debug = file->private_data;
+
+	if (!debug)
+		return 0;
+
+	file->private_data = NULL;
+	kfree(debug);
+	return 0;
+}
+
+static int
+bfad_debugfs_release_fwtrc(struct inode *inode, struct file *file)
+{
+	struct bfad_debug_info *fw_debug = file->private_data;
+
+	if (!fw_debug)
+		return 0;
+
+	if (fw_debug->debug_buffer)
+		vfree(fw_debug->debug_buffer);
+
+	file->private_data = NULL;
+	kfree(fw_debug);
+	return 0;
+}
+
+static const struct file_operations bfad_debugfs_op_drvtrc = {
+	.owner		=	THIS_MODULE,
+	.open		=	bfad_debugfs_open_drvtrc,
+	.llseek		=	bfad_debugfs_lseek,
+	.read		=	bfad_debugfs_read,
+	.release	=	bfad_debugfs_release,
+};
+
+static const struct file_operations bfad_debugfs_op_fwtrc = {
+	.owner		=	THIS_MODULE,
+	.open		=	bfad_debugfs_open_fwtrc,
+	.llseek		=	bfad_debugfs_lseek,
+	.read		=	bfad_debugfs_read,
+	.release	=	bfad_debugfs_release_fwtrc,
+};
+
+static const struct file_operations bfad_debugfs_op_fwsave = {
+	.owner		=	THIS_MODULE,
+	.open		=	bfad_debugfs_open_fwsave,
+	.llseek		=	bfad_debugfs_lseek,
+	.read		=	bfad_debugfs_read,
+	.release	=	bfad_debugfs_release_fwtrc,
+};
+
+static const struct file_operations bfad_debugfs_op_regrd = {
+	.owner		=	THIS_MODULE,
+	.open		=	bfad_debugfs_open_reg,
+	.llseek		=	bfad_debugfs_lseek,
+	.read		=	bfad_debugfs_read_regrd,
+	.write		=	bfad_debugfs_write_regrd,
+	.release	=	bfad_debugfs_release,
+};
+
+static const struct file_operations bfad_debugfs_op_regwr = {
+	.owner		=	THIS_MODULE,
+	.open		=	bfad_debugfs_open_reg,
+	.llseek		=	bfad_debugfs_lseek,
+	.write		=	bfad_debugfs_write_regwr,
+	.release	=	bfad_debugfs_release,
+};
+
+struct bfad_debugfs_entry {
+	const char *name;
+	mode_t	mode;
+	const struct file_operations *fops;
+};
+
+static const struct bfad_debugfs_entry bfad_debugfs_files[] = {
+	{ "drvtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_drvtrc, },
+	{ "fwtrc",  S_IFREG|S_IRUGO, &bfad_debugfs_op_fwtrc,  },
+	{ "fwsave", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwsave, },
+	{ "regrd",  S_IFREG|S_IRUGO|S_IWUSR, &bfad_debugfs_op_regrd,  },
+	{ "regwr",  S_IFREG|S_IWUSR, &bfad_debugfs_op_regwr,  },
+};
+
+static struct dentry *bfa_debugfs_root;
+static atomic_t bfa_debugfs_port_count;
+
+inline void
+bfad_debugfs_init(struct bfad_port_s *port)
+{
+	struct bfad_im_port_s *im_port = port->im_port;
+	struct bfad_s *bfad = im_port->bfad;
+	struct Scsi_Host *shost = im_port->shost;
+	const struct bfad_debugfs_entry *file;
+	char name[16];
+	int i;
+
+	if (!bfa_debugfs_enable)
+		return;
+
+	/* Setup the BFA debugfs root directory*/
+	if (!bfa_debugfs_root) {
+		bfa_debugfs_root = debugfs_create_dir("bfa", NULL);
+		atomic_set(&bfa_debugfs_port_count, 0);
+		if (!bfa_debugfs_root) {
+			printk(KERN_WARNING
+				"BFA debugfs root dir creation failed\n");
+			goto err;
+		}
+	}
+
+	/*
+	 * Setup the host# directory for the port,
+	 * corresponds to the scsi_host num of this port.
+	 */
+	snprintf(name, sizeof(name), "host%d", shost->host_no);
+	if (!port->port_debugfs_root) {
+		port->port_debugfs_root =
+			debugfs_create_dir(name, bfa_debugfs_root);
+		if (!port->port_debugfs_root) {
+			printk(KERN_WARNING
+				"BFA host root dir creation failed\n");
+			goto err;
+		}
+
+		atomic_inc(&bfa_debugfs_port_count);
+
+		for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) {
+			file = &bfad_debugfs_files[i];
+			bfad->bfad_dentry_files[i] =
+					debugfs_create_file(file->name,
+							file->mode,
+							port->port_debugfs_root,
+							port,
+							file->fops);
+			if (!bfad->bfad_dentry_files[i]) {
+				printk(KERN_WARNING
+					"BFA host%d: create %s entry failed\n",
+					shost->host_no, file->name);
+				goto err;
+			}
+		}
+	}
+
+err:
+	return;
+}
+
+inline void
+bfad_debugfs_exit(struct bfad_port_s *port)
+{
+	struct bfad_im_port_s *im_port = port->im_port;
+	struct bfad_s *bfad = im_port->bfad;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) {
+		if (bfad->bfad_dentry_files[i]) {
+			debugfs_remove(bfad->bfad_dentry_files[i]);
+			bfad->bfad_dentry_files[i] = NULL;
+		}
+	}
+
+	/*
+	 * Remove the host# directory for the port,
+	 * corresponds to the scsi_host num of this port.
+	*/
+	if (port->port_debugfs_root) {
+		debugfs_remove(port->port_debugfs_root);
+		port->port_debugfs_root = NULL;
+		atomic_dec(&bfa_debugfs_port_count);
+	}
+
+	/* Remove the BFA debugfs root directory */
+	if (atomic_read(&bfa_debugfs_port_count) == 0) {
+		debugfs_remove(bfa_debugfs_root);
+		bfa_debugfs_root = NULL;
+	}
+}
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
index 6c920c1..465b8b8 100644
--- a/drivers/scsi/bfa/bfad_drv.h
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -46,7 +46,7 @@
 #ifdef BFA_DRIVER_VERSION
 #define BFAD_DRIVER_VERSION    BFA_DRIVER_VERSION
 #else
-#define BFAD_DRIVER_VERSION    "2.1.2.1"
+#define BFAD_DRIVER_VERSION    "2.2.2.1"
 #endif
 
 
@@ -111,6 +111,9 @@
 	struct bfad_im_port_s *im_port;	/* IM specific data */
 	struct bfad_tm_port_s *tm_port;	/* TM specific data */
 	struct bfad_ipfc_port_s *ipfc_port;	/* IPFC specific data */
+
+	/* port debugfs specific data */
+	struct dentry *port_debugfs_root;
 };
 
 /*
@@ -120,6 +123,8 @@
 	struct bfad_port_s     drv_port;
 	struct bfa_fcs_vport_s fcs_vport;
 	struct completion *comp_del;
+	struct list_head list_entry;
+	struct bfa_port_cfg_s port_cfg;
 };
 
 /*
@@ -139,18 +144,6 @@
 	u32        binding_method;
 };
 
-union bfad_tmp_buf {
-	/* From struct bfa_adapter_attr_s */
-	char            manufacturer[BFA_ADAPTER_MFG_NAME_LEN];
-	char            serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
-	char            model[BFA_ADAPTER_MODEL_NAME_LEN];
-	char            fw_ver[BFA_VERSION_LEN];
-	char            optrom_ver[BFA_VERSION_LEN];
-
-	/* From struct bfa_ioc_pci_attr_s */
-	u8         chip_rev[BFA_IOC_CHIP_REV_LEN];  /*  chip revision */
-};
-
 /*
  * BFAD (PCI function) data structure
  */
@@ -193,8 +186,18 @@
 	struct bfa_plog_s      plog_buf;
 	int             ref_count;
 	bfa_boolean_t	ipfc_enabled;
-	union bfad_tmp_buf tmp_buf;
 	struct fc_host_statistics link_stats;
+	struct list_head pbc_pcfg_list;
+	atomic_t wq_reqcnt;
+	/* debugfs specific data */
+	char *regdata;
+	u32 reglen;
+	struct dentry *bfad_dentry_files[5];
+};
+
+struct bfad_pcfg_s {
+	struct list_head list_entry;
+	struct bfa_port_cfg_s port_cfg;
 };
 
 /*
@@ -280,7 +283,9 @@
 void		bfad_drv_log_level_set(struct bfad_s *bfad);
 bfa_status_t	bfad_fc4_module_init(void);
 void		bfad_fc4_module_exit(void);
-int		bfad_worker (void *ptr);
+int		bfad_worker(void *ptr);
+void		bfad_debugfs_init(struct bfad_port_s *port);
+void		bfad_debugfs_exit(struct bfad_port_s *port);
 
 void bfad_pci_remove(struct pci_dev *pdev);
 int bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid);
@@ -293,6 +298,7 @@
 extern int bfa_lun_queue_depth;
 extern int bfad_supported_fc4s;
 extern int bfa_linkup_delay;
+extern int bfa_debugfs_enable;
 extern struct mutex bfad_mutex;
 
 #endif /* __BFAD_DRV_H__ */
diff --git a/drivers/scsi/bfa/bfad_fwimg.c b/drivers/scsi/bfa/bfad_fwimg.c
index 2ad65f2..1baca1a 100644
--- a/drivers/scsi/bfa/bfad_fwimg.c
+++ b/drivers/scsi/bfa/bfad_fwimg.c
@@ -33,16 +33,20 @@
 #include <bfa_fwimg_priv.h>
 #include <bfa.h>
 
-u32 bfi_image_ct_size;
-u32 bfi_image_cb_size;
-u32 *bfi_image_ct;
-u32 *bfi_image_cb;
+u32 bfi_image_ct_fc_size;
+u32 bfi_image_ct_cna_size;
+u32 bfi_image_cb_fc_size;
+u32 *bfi_image_ct_fc;
+u32 *bfi_image_ct_cna;
+u32 *bfi_image_cb_fc;
 
 
-#define	BFAD_FW_FILE_CT	"ctfw.bin"
-#define	BFAD_FW_FILE_CB	"cbfw.bin"
-MODULE_FIRMWARE(BFAD_FW_FILE_CT);
-MODULE_FIRMWARE(BFAD_FW_FILE_CB);
+#define	BFAD_FW_FILE_CT_FC	"ctfw_fc.bin"
+#define	BFAD_FW_FILE_CT_CNA	"ctfw_cna.bin"
+#define	BFAD_FW_FILE_CB_FC	"cbfw_fc.bin"
+MODULE_FIRMWARE(BFAD_FW_FILE_CT_FC);
+MODULE_FIRMWARE(BFAD_FW_FILE_CT_CNA);
+MODULE_FIRMWARE(BFAD_FW_FILE_CB_FC);
 
 u32 *
 bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
@@ -74,24 +78,54 @@
 u32 *
 bfad_get_firmware_buf(struct pci_dev *pdev)
 {
-	if (pdev->device == BFA_PCI_DEVICE_ID_CT) {
-		if (bfi_image_ct_size == 0)
-			bfad_read_firmware(pdev, &bfi_image_ct,
-				&bfi_image_ct_size, BFAD_FW_FILE_CT);
-		return bfi_image_ct;
+	if (pdev->device == BFA_PCI_DEVICE_ID_CT_FC) {
+		if (bfi_image_ct_fc_size == 0)
+			bfad_read_firmware(pdev, &bfi_image_ct_fc,
+				&bfi_image_ct_fc_size, BFAD_FW_FILE_CT_FC);
+		return bfi_image_ct_fc;
+	} else if (pdev->device == BFA_PCI_DEVICE_ID_CT) {
+		if (bfi_image_ct_cna_size == 0)
+			bfad_read_firmware(pdev, &bfi_image_ct_cna,
+				&bfi_image_ct_cna_size, BFAD_FW_FILE_CT_CNA);
+		return bfi_image_ct_cna;
 	} else {
-		if (bfi_image_cb_size == 0)
-			bfad_read_firmware(pdev, &bfi_image_cb,
-				&bfi_image_cb_size, BFAD_FW_FILE_CB);
-		return bfi_image_cb;
+		if (bfi_image_cb_fc_size == 0)
+			bfad_read_firmware(pdev, &bfi_image_cb_fc,
+				&bfi_image_cb_fc_size, BFAD_FW_FILE_CB_FC);
+		return bfi_image_cb_fc;
 	}
 }
 
 u32 *
-bfi_image_ct_get_chunk(u32 off)
-{ return (u32 *)(bfi_image_ct + off); }
+bfi_image_ct_fc_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_ct_fc + off); }
 
 u32 *
-bfi_image_cb_get_chunk(u32 off)
-{ return (u32 *)(bfi_image_cb + off); }
+bfi_image_ct_cna_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_ct_cna + off); }
 
+u32 *
+bfi_image_cb_fc_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_cb_fc + off); }
+
+uint32_t *
+bfi_image_get_chunk(int type, uint32_t off)
+{
+	switch (type) {
+	case BFI_IMAGE_CT_FC: return bfi_image_ct_fc_get_chunk(off); break;
+	case BFI_IMAGE_CT_CNA: return bfi_image_ct_cna_get_chunk(off); break;
+	case BFI_IMAGE_CB_FC: return bfi_image_cb_fc_get_chunk(off); break;
+	default: return 0; break;
+	}
+}
+
+uint32_t
+bfi_image_get_size(int type)
+{
+	switch (type) {
+	case BFI_IMAGE_CT_FC: return bfi_image_ct_fc_size; break;
+	case BFI_IMAGE_CT_CNA: return bfi_image_ct_cna_size; break;
+	case BFI_IMAGE_CB_FC: return bfi_image_cb_fc_size; break;
+	default: return 0; break;
+	}
+}
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index 5b7cf53..678120b 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -554,7 +554,7 @@
 		im_port->shost->transportt =
 				bfad_im_scsi_vport_transport_template;
 
-	error = scsi_add_host(im_port->shost, dev);
+	error = scsi_add_host_with_dma(im_port->shost, dev, &bfad->pcidev->dev);
 	if (error) {
 		printk(KERN_WARNING "scsi_add_host failure %d\n", error);
 		goto out_fc_rel;
@@ -567,6 +567,7 @@
 
 out_fc_rel:
 	scsi_host_put(im_port->shost);
+	im_port->shost = NULL;
 out_free_idr:
 	mutex_lock(&bfad_mutex);
 	idr_remove(&bfad_im_port_index, im_port->idr_id);
@@ -597,10 +598,12 @@
 {
 	struct bfad_im_port_s *im_port =
 		container_of(work, struct bfad_im_port_s, port_delete_work);
+	struct bfad_s *bfad = im_port->bfad;
 
 	if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) {
 		im_port->flags |= BFAD_PORT_DELETE;
 		fc_vport_terminate(im_port->fc_vport);
+		atomic_dec(&bfad->wq_reqcnt);
 	}
 
 }
@@ -633,8 +636,11 @@
 {
 	struct bfad_im_port_s *im_port = port->im_port;
 
-	queue_work(bfad->im->drv_workq,
+	if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) {
+		atomic_inc(&bfad->wq_reqcnt);
+		queue_work(bfad->im->drv_workq,
 				&im_port->port_delete_work);
+	}
 }
 
 void
@@ -695,12 +701,27 @@
 bfad_im_probe_undo(struct bfad_s *bfad)
 {
 	if (bfad->im) {
+		while (atomic_read(&bfad->wq_reqcnt)) {
+			printk(KERN_INFO "bfa %s: waiting workq processing,"
+				" wq_reqcnt:%x\n", bfad->pci_name,
+				atomic_read(&bfad->wq_reqcnt));
+			schedule_timeout_uninterruptible(HZ);
+		}
 		bfad_os_destroy_workq(bfad->im);
 		kfree(bfad->im);
 		bfad->im = NULL;
 	}
 }
 
+/**
+ * Call back function to handle IO redirection state change
+ */
+void
+bfa_cb_ioredirect_state_change(void *hcb_bfad, bfa_boolean_t ioredirect)
+{
+	/* Do nothing */
+}
+
 struct Scsi_Host *
 bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
 {
@@ -1204,9 +1225,9 @@
 bfad_os_get_linkup_delay(struct bfad_s *bfad)
 {
 
-	u8         nwwns = 0;
-	wwn_t           *wwns;
-	int             ldelay;
+	u8      nwwns = 0;
+	wwn_t	wwns[BFA_PREBOOT_BOOTLUN_MAX];
+	int     ldelay;
 
 	/*
 	 * Querying for the boot target port wwns
@@ -1215,7 +1236,7 @@
 	 * else => local boot machine set bfa_linkup_delay = 10
 	 */
 
-	bfa_iocfc_get_bootwwns(&bfad->bfa, &nwwns, &wwns);
+	bfa_iocfc_get_bootwwns(&bfad->bfa, &nwwns, wwns);
 
 	if (nwwns > 0) {
 		/* If boot over SAN; linkup_delay = 30sec */
diff --git a/drivers/scsi/bfa/bfad_im_compat.h b/drivers/scsi/bfa/bfad_im_compat.h
index b36be15..0a122ab 100644
--- a/drivers/scsi/bfa/bfad_im_compat.h
+++ b/drivers/scsi/bfa/bfad_im_compat.h
@@ -18,9 +18,6 @@
 #ifndef __BFAD_IM_COMPAT_H__
 #define __BFAD_IM_COMPAT_H__
 
-extern u32 *bfi_image_buf;
-extern u32 bfi_image_size;
-
 extern struct device_attribute *bfad_im_host_attrs[];
 extern struct device_attribute *bfad_im_vport_attrs[];
 
@@ -37,10 +34,12 @@
 static inline void
 bfad_free_fwimg(void)
 {
-	if (bfi_image_ct_size && bfi_image_ct)
-		vfree(bfi_image_ct);
-	if (bfi_image_cb_size && bfi_image_cb)
-		vfree(bfi_image_cb);
+	if (bfi_image_ct_fc_size && bfi_image_ct_fc)
+		vfree(bfi_image_ct_fc);
+	if (bfi_image_ct_cna_size && bfi_image_ct_cna)
+		vfree(bfi_image_ct_cna);
+	if (bfi_image_cb_fc_size && bfi_image_cb_fc)
+		vfree(bfi_image_cb_fc);
 }
 
 #endif
diff --git a/drivers/scsi/bfa/bfad_intr.c b/drivers/scsi/bfa/bfad_intr.c
index 2b7dbec..56a3515 100644
--- a/drivers/scsi/bfa/bfad_intr.c
+++ b/drivers/scsi/bfa/bfad_intr.c
@@ -26,7 +26,11 @@
 static int msix_disable_cb;
 static int msix_disable_ct;
 module_param(msix_disable_cb, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(msix_disable_cb, "Disable MSIX for Brocade-415/425/815/825"
+		" cards, default=0, Range[false:0|true:1]");
 module_param(msix_disable_ct, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(msix_disable_ct, "Disable MSIX for Brocade-1010/1020/804"
+		" cards, default=0, Range[false:0|true:1]");
 /**
  * Line based interrupt handler.
  */
@@ -151,8 +155,8 @@
 	/* Set up the msix entry table */
 	bfad_init_msix_entry(bfad, msix_entries, mask, max_bit);
 
-	if ((pdev->device == BFA_PCI_DEVICE_ID_CT && !msix_disable_ct) ||
-	    (pdev->device != BFA_PCI_DEVICE_ID_CT && !msix_disable_cb)) {
+	if ((bfa_asic_id_ct(pdev->device) && !msix_disable_ct) ||
+		(!bfa_asic_id_ct(pdev->device) && !msix_disable_cb)) {
 
 		error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec);
 		if (error) {
diff --git a/drivers/scsi/bfa/fabric.c b/drivers/scsi/bfa/fabric.c
index 8166e97..ddd4ba9 100644
--- a/drivers/scsi/bfa/fabric.c
+++ b/drivers/scsi/bfa/fabric.c
@@ -789,7 +789,7 @@
 
 	list_for_each_safe(qe, qen, &fabric->vport_q) {
 		vport = (struct bfa_fcs_vport_s *)qe;
-		bfa_fcs_vport_delete(vport);
+		bfa_fcs_vport_fcs_delete(vport);
 	}
 
 	bfa_fcs_port_delete(&fabric->bport);
@@ -1027,6 +1027,32 @@
 	return fabric->num_vports;
 }
 
+/*
+ *  Get OUI of the attached switch.
+ *
+ *  Note : Use of this function should be avoided as much as possible.
+ *         This function should be used only if there is any requirement
+ *         to check for FOS version below 6.3.
+ *         To check if the attached fabric is a brocade fabric, use
+ *         bfa_lps_is_brcd_fabric() which works for FOS versions 6.3
+ *         or above only.
+ */
+
+u16
+bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric)
+{
+	wwn_t fab_nwwn;
+	u8 *tmp;
+	u16 oui;
+
+	fab_nwwn = bfa_lps_get_peer_nwwn(fabric->lps);
+
+	tmp = (uint8_t *)&fab_nwwn;
+	oui = (tmp[3] << 8) | tmp[4];
+
+	return oui;
+}
+
 /**
  * 		Unsolicited frame receive handling.
  */
@@ -1271,6 +1297,22 @@
 }
 
 /**
+ *
+ * @param[in] fabric - fabric
+ * @param[in] node_symname -
+ *              Caller allocated buffer to receive the symbolic name
+ *
+ * @return - none
+ */
+void
+bfa_fcs_get_sym_name(const struct bfa_fcs_s *fcs, char *node_symname)
+{
+	bfa_os_memcpy(node_symname,
+			fcs->fabric.bport.port_cfg.sym_name.symname,
+			BFA_SYMNAME_MAXLEN);
+}
+
+/**
  * Not used by FCS.
  */
 void
diff --git a/drivers/scsi/bfa/fcpim.c b/drivers/scsi/bfa/fcpim.c
index 8ae4a2cf..6b8976a 100644
--- a/drivers/scsi/bfa/fcpim.c
+++ b/drivers/scsi/bfa/fcpim.c
@@ -110,6 +110,7 @@
 	switch (event) {
 	case BFA_FCS_ITNIM_SM_ONLINE:
 		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
+		itnim->prli_retries = 0;
 		bfa_fcs_itnim_send_prli(itnim, NULL);
 		break;
 
@@ -174,8 +175,12 @@
 
 	switch (event) {
 	case BFA_FCS_ITNIM_SM_RSP_OK:
-		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online);
-		bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec);
+		if (itnim->rport->scsi_function == BFA_RPORT_INITIATOR) {
+			bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
+		} else {
+			bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online);
+			bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec);
+		}
 		break;
 
 	case BFA_FCS_ITNIM_SM_RSP_ERROR:
@@ -193,9 +198,7 @@
 
 	case BFA_FCS_ITNIM_SM_INITIATOR:
 		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
-		/*
-		 * dont discard fcxp. accept will reach same state
-		 */
+		bfa_fcxp_discard(itnim->fcxp);
 		break;
 
 	case BFA_FCS_ITNIM_SM_DELETE:
@@ -218,8 +221,16 @@
 
 	switch (event) {
 	case BFA_FCS_ITNIM_SM_TIMEOUT:
-		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
-		bfa_fcs_itnim_send_prli(itnim, NULL);
+		if (itnim->prli_retries < BFA_FCS_RPORT_MAX_RETRIES) {
+			itnim->prli_retries++;
+			bfa_trc(itnim->fcs, itnim->prli_retries);
+			bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
+			bfa_fcs_itnim_send_prli(itnim, NULL);
+		} else {
+			/* invoke target offline */
+			bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+			bfa_fcs_rport_logo_imp(itnim->rport);
+		}
 		break;
 
 	case BFA_FCS_ITNIM_SM_OFFLINE:
@@ -422,7 +433,7 @@
 	bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag,
 		      BFA_FALSE, FC_CLASS_3, len, &fchs,
 		      bfa_fcs_itnim_prli_response, (void *)itnim, FC_MAX_PDUSZ,
-		      FC_RA_TOV);
+		      FC_ELS_TOV);
 
 	itnim->stats.prli_sent++;
 	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT);
@@ -467,7 +478,7 @@
 					BFA_RPORT_INITIATOR;
 				itnim->stats.prli_rsp_acc++;
 				bfa_sm_send_event(itnim,
-						  BFA_FCS_ITNIM_SM_INITIATOR);
+						  BFA_FCS_ITNIM_SM_RSP_OK);
 				return;
 			}
 
@@ -738,6 +749,7 @@
 	attr->rec_support = itnim->rec_support;
 	attr->conf_comp = itnim->conf_comp;
 	attr->task_retry_id = itnim->task_retry_id;
+	bfa_os_memset(&attr->io_latency, 0, sizeof(struct bfa_itnim_latency_s));
 
 	return BFA_STATUS_OK;
 }
@@ -793,7 +805,7 @@
 
 	switch (els_cmd->els_code) {
 	case FC_ELS_PRLO:
-		/* bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_PRLO); */
+		bfa_fcs_rport_prlo(itnim->rport, fchs->ox_id);
 		break;
 
 	default:
diff --git a/drivers/scsi/bfa/fcs_fabric.h b/drivers/scsi/bfa/fcs_fabric.h
index 244c3f0..432ab8a 100644
--- a/drivers/scsi/bfa/fcs_fabric.h
+++ b/drivers/scsi/bfa/fcs_fabric.h
@@ -26,6 +26,8 @@
 #include <fcs/bfa_fcs_vport.h>
 #include <fcs/bfa_fcs_lport.h>
 
+#define BFA_FCS_BRCD_SWITCH_OUI  0x051e
+
 /*
 * fcs friend functions: only between fcs modules
  */
@@ -60,4 +62,7 @@
 
 void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
 			wwn_t fabric_name);
+u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric);
+void bfa_fcs_get_sym_name(const struct bfa_fcs_s *fcs, char *node_symname);
+
 #endif /* __FCS_FABRIC_H__ */
diff --git a/drivers/scsi/bfa/fcs_rport.h b/drivers/scsi/bfa/fcs_rport.h
index 9c8d1d2..e634fb7 100644
--- a/drivers/scsi/bfa/fcs_rport.h
+++ b/drivers/scsi/bfa/fcs_rport.h
@@ -24,6 +24,8 @@
 
 #include <fcs/bfa_fcs_rport.h>
 
+#define BFA_FCS_RPORT_MAX_RETRIES               (5)
+
 void bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
 			u16 len);
 void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport);
@@ -41,6 +43,7 @@
 void bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
 			struct fc_logi_s *plogi);
 void bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, uint16_t ox_id);
 void bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport);
 void bfa_fcs_rport_itntm_ack(struct bfa_fcs_rport_s *rport);
 void bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport);
diff --git a/drivers/scsi/bfa/fcs_vport.h b/drivers/scsi/bfa/fcs_vport.h
index 13c32eb..bb647a4 100644
--- a/drivers/scsi/bfa/fcs_vport.h
+++ b/drivers/scsi/bfa/fcs_vport.h
@@ -26,6 +26,7 @@
 void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport);
 void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport);
 void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport);
+void bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport);
 
 #endif /* __FCS_VPORT_H__ */
 
diff --git a/drivers/scsi/bfa/fdmi.c b/drivers/scsi/bfa/fdmi.c
index 8f17076..2b50eab 100644
--- a/drivers/scsi/bfa/fdmi.c
+++ b/drivers/scsi/bfa/fdmi.c
@@ -532,7 +532,7 @@
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, (len + attr_len), &fchs,
 		      bfa_fcs_port_fdmi_rhba_response, (void *)fdmi,
-		      FC_MAX_PDUSZ, FC_RA_TOV);
+		      FC_MAX_PDUSZ, FC_FCCT_TOV);
 
 	bfa_sm_send_event(fdmi, FDMISM_EVENT_RHBA_SENT);
 }
@@ -823,7 +823,7 @@
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len + attr_len, &fchs,
 		      bfa_fcs_port_fdmi_rprt_response, (void *)fdmi,
-		      FC_MAX_PDUSZ, FC_RA_TOV);
+		      FC_MAX_PDUSZ, FC_FCCT_TOV);
 
 	bfa_sm_send_event(fdmi, FDMISM_EVENT_RPRT_SENT);
 }
@@ -1043,7 +1043,7 @@
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len + attr_len, &fchs,
 		      bfa_fcs_port_fdmi_rpa_response, (void *)fdmi,
-		      FC_MAX_PDUSZ, FC_RA_TOV);
+		      FC_MAX_PDUSZ, FC_FCCT_TOV);
 
 	bfa_sm_send_event(fdmi, FDMISM_EVENT_RPA_SENT);
 }
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h b/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h
index 71378b4..4daf96f 100644
--- a/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h
@@ -32,6 +32,14 @@
 	BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_DISABLE)
 #define BFA_AEN_IOC_FWMISMATCH \
 	BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_FWMISMATCH)
+#define BFA_AEN_IOC_FWCFG_ERROR \
+	BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_FWCFG_ERROR)
+#define BFA_AEN_IOC_INVALID_VENDOR      \
+	BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_INVALID_VENDOR)
+#define BFA_AEN_IOC_INVALID_NWWN        \
+	BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_INVALID_NWWN)
+#define BFA_AEN_IOC_INVALID_PWWN        \
+	BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_INVALID_PWWN)
 
 #endif
 
diff --git a/drivers/scsi/bfa/include/bfa.h b/drivers/scsi/bfa/include/bfa.h
index 1f5966c..d52b32f 100644
--- a/drivers/scsi/bfa/include/bfa.h
+++ b/drivers/scsi/bfa/include/bfa.h
@@ -126,6 +126,10 @@
 	bfa_ioc_get_type(&(__bfa)->ioc)
 #define bfa_get_mac(__bfa)  \
 	bfa_ioc_get_mac(&(__bfa)->ioc)
+#define bfa_get_mfg_mac(__bfa)  \
+	bfa_ioc_get_mfg_mac(&(__bfa)->ioc)
+#define bfa_get_fw_clock_res(__bfa)    \
+	((__bfa)->iocfc.cfgrsp->fwcfg.fw_tick_res)
 
 /*
  * bfa API functions
diff --git a/drivers/scsi/bfa/include/bfa_fcpim.h b/drivers/scsi/bfa/include/bfa_fcpim.h
index 0478979..4bc9453 100644
--- a/drivers/scsi/bfa/include/bfa_fcpim.h
+++ b/drivers/scsi/bfa/include/bfa_fcpim.h
@@ -42,6 +42,24 @@
 bfa_status_t bfa_fcpim_get_modstats(struct bfa_s *bfa,
 			struct bfa_fcpim_stats_s *modstats);
 bfa_status_t bfa_fcpim_clr_modstats(struct bfa_s *bfa);
+void bfa_fcpim_set_ioredirect(struct bfa_s *bfa, bfa_boolean_t state);
+void bfa_fcpim_update_ioredirect(struct bfa_s *bfa);
+void bfa_cb_ioredirect_state_change(void *hcb_bfad, bfa_boolean_t ioredirect);
+
+#define bfa_fcpim_ioredirect_enabled(__bfa)                             \
+	(((struct bfa_fcpim_mod_s *)(BFA_FCPIM_MOD(__bfa)))->ioredirect)
+
+#define bfa_fcpim_get_next_reqq(__bfa, __qid)                           \
+{                                                                       \
+	struct bfa_fcpim_mod_s *__fcpim = BFA_FCPIM_MOD(__bfa);         \
+	__fcpim->reqq++;                                                \
+	__fcpim->reqq &= (BFI_IOC_MAX_CQS - 1);                          \
+	*(__qid) = __fcpim->reqq;                                       \
+}
+
+#define bfa_iocfc_map_msg_to_qid(__msg, __qid)                          \
+	*(__qid) = (u8)((__msg) & (BFI_IOC_MAX_CQS - 1));
+
 
 /*
  * bfa itnim API functions
@@ -56,6 +74,7 @@
 			struct bfa_itnim_hal_stats_s *stats);
 void		bfa_itnim_clear_stats(struct bfa_itnim_s *itnim);
 
+#define bfa_itnim_get_reqq(__ioim) (((struct bfa_ioim_s *)__ioim)->itnim->reqq)
 
 /**
  * 		BFA completion callback for bfa_itnim_online().
@@ -156,4 +175,3 @@
 				  enum bfi_tskim_status tsk_status);
 
 #endif /* __BFA_FCPIM_H__ */
-
diff --git a/drivers/scsi/bfa/include/bfa_svc.h b/drivers/scsi/bfa/include/bfa_svc.h
index 1349b99..7840943 100644
--- a/drivers/scsi/bfa/include/bfa_svc.h
+++ b/drivers/scsi/bfa/include/bfa_svc.h
@@ -215,6 +215,7 @@
 		bfa_cb_pport_t cbfn, void *cbarg);
 bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn,
 		void *cbarg);
+bfa_boolean_t bfa_fcport_is_qos_enabled(struct bfa_s *bfa);
 
 /*
  * bfa rport API functions
diff --git a/drivers/scsi/bfa/include/bfi/bfi_ctreg.h b/drivers/scsi/bfa/include/bfi/bfi_ctreg.h
index 57a8497..c0ef5a9 100644
--- a/drivers/scsi/bfa/include/bfi/bfi_ctreg.h
+++ b/drivers/scsi/bfa/include/bfi/bfi_ctreg.h
@@ -455,6 +455,9 @@
 #define __PSS_LPU0_RAM_ERR               0x00000001
 #define ERR_SET_REG			 0x00018818
 #define __PSS_ERR_STATUS_SET		 0x003fffff
+#define PMM_1T_RESET_REG_P0              0x0002381c
+#define __PMM_1T_RESET_P                 0x00000001
+#define PMM_1T_RESET_REG_P1              0x00023c1c
 #define HQM_QSET0_RXQ_DRBL_P0            0x00038000
 #define __RXQ0_ADD_VECTORS_P             0x80000000
 #define __RXQ0_STOP_P                    0x40000000
diff --git a/drivers/scsi/bfa/include/bfi/bfi_ioc.h b/drivers/scsi/bfa/include/bfi/bfi_ioc.h
index a0158aa..450ded6 100644
--- a/drivers/scsi/bfa/include/bfi/bfi_ioc.h
+++ b/drivers/scsi/bfa/include/bfi/bfi_ioc.h
@@ -48,9 +48,14 @@
 };
 
 struct bfi_ioc_attr_s {
-	wwn_t           mfg_wwn;
-	mac_t		mfg_mac;
-	u16	rsvd_a;
+	wwn_t           mfg_pwwn;       /* Mfg port wwn */
+	wwn_t           mfg_nwwn;       /* Mfg node wwn */
+	mac_t		mfg_mac;	/* Mfg mac      */
+	u16		rsvd_a;
+	wwn_t           pwwn;
+	wwn_t           nwwn;
+	mac_t           mac;            /* PBC or Mfg mac */
+	u16        	rsvd_b;
 	char            brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)];
 	u8         pcie_gen;
 	u8         pcie_lanes_orig;
@@ -58,11 +63,12 @@
 	u8         rx_bbcredit;	/*  receive buffer credits */
 	u32        adapter_prop;	/*  adapter properties     */
 	u16        maxfrsize;	/*  max receive frame size */
-	char         	asic_rev;
-	u8         rsvd_b;
-	char            fw_version[BFA_VERSION_LEN];
-	char            optrom_version[BFA_VERSION_LEN];
+	char       asic_rev;
+	u8         rsvd_c;
+	char       fw_version[BFA_VERSION_LEN];
+	char       optrom_version[BFA_VERSION_LEN];
 	struct bfa_mfg_vpd_s	vpd;
+	u32        card_type;	/* card type */
 };
 
 /**
diff --git a/drivers/scsi/bfa/include/bfi/bfi_iocfc.h b/drivers/scsi/bfa/include/bfi/bfi_iocfc.h
index c3760df..ccdfcc5 100644
--- a/drivers/scsi/bfa/include/bfi/bfi_iocfc.h
+++ b/drivers/scsi/bfa/include/bfi/bfi_iocfc.h
@@ -19,6 +19,7 @@
 #define __BFI_IOCFC_H__
 
 #include "bfi.h"
+#include <bfi/bfi_pbc.h>
 #include <defs/bfa_defs_ioc.h>
 #include <defs/bfa_defs_iocfc.h>
 #include <defs/bfa_defs_boot.h>
@@ -78,6 +79,7 @@
 	struct bfa_iocfc_fwcfg_s	fwcfg;
 	struct bfa_iocfc_intr_attr_s	intr_attr;
 	struct bfi_iocfc_bootwwns	bootwwns;
+	struct bfi_pbc_s                pbc_cfg;
 };
 
 /**
diff --git a/drivers/scsi/bfa/include/bfi/bfi_pbc.h b/drivers/scsi/bfa/include/bfi/bfi_pbc.h
new file mode 100644
index 0000000..88a4154
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_pbc.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFI_PBC_H__
+#define __BFI_PBC_H__
+
+#pragma pack(1)
+
+#define BFI_PBC_MAX_BLUNS	8
+#define BFI_PBC_MAX_VPORTS	16
+
+#define BFI_PBC_PORT_DISABLED	 2
+/**
+ * PBC boot lun configuration
+ */
+struct bfi_pbc_blun_s {
+	wwn_t		tgt_pwwn;
+	lun_t		tgt_lun;
+};
+
+/**
+ * PBC virtual port configuration
+ */
+struct bfi_pbc_vport_s {
+	wwn_t		vp_pwwn;
+	wwn_t		vp_nwwn;
+};
+
+/**
+ * BFI pre-boot configuration information
+ */
+struct bfi_pbc_s {
+	u8		port_enabled;
+	u8		boot_enabled;
+	u8		nbluns;
+	u8		nvports;
+	u8		port_speed;
+	u8		rsvd_a;
+	u16		hss;
+	wwn_t		pbc_pwwn;
+	wwn_t		pbc_nwwn;
+	struct bfi_pbc_blun_s blun[BFI_PBC_MAX_BLUNS];
+	struct bfi_pbc_vport_s vport[BFI_PBC_MAX_VPORTS];
+};
+
+#pragma pack()
+
+#endif /* __BFI_PBC_H__ */
diff --git a/drivers/scsi/bfa/include/cna/port/bfa_port.h b/drivers/scsi/bfa/include/cna/port/bfa_port.h
index 7cbf17d..d7babaf 100644
--- a/drivers/scsi/bfa/include/cna/port/bfa_port.h
+++ b/drivers/scsi/bfa/include/cna/port/bfa_port.h
@@ -37,6 +37,7 @@
 	bfa_port_stats_cbfn_t stats_cbfn;
 	void           *stats_cbarg;
 	bfa_status_t    stats_status;
+	u32             stats_reset_time;
 	union bfa_pport_stats_u *stats;
 	struct bfa_dma_s stats_dma;
 	bfa_boolean_t   endis_pending;
diff --git a/drivers/scsi/bfa/include/cs/bfa_debug.h b/drivers/scsi/bfa/include/cs/bfa_debug.h
index 441be86..75a911e 100644
--- a/drivers/scsi/bfa/include/cs/bfa_debug.h
+++ b/drivers/scsi/bfa/include/cs/bfa_debug.h
@@ -28,7 +28,8 @@
 } while (0)
 
 #define bfa_sm_fault(__mod, __event)	do {				\
-	bfa_sm_panic((__mod)->logm, __LINE__, __FILE__, __event);      \
+	bfa_trc(__mod, (((uint32_t)0xDEAD << 16) | __event));		\
+	bfa_sm_panic((__mod)->logm, __LINE__, __FILE__, __event); 	\
 } while (0)
 
 #ifndef BFA_PERF_BUILD
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h b/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h
index 8c208fc..aea0360 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h
@@ -39,7 +39,7 @@
 struct bfa_adapter_attr_s {
 	char            manufacturer[BFA_ADAPTER_MFG_NAME_LEN];
 	char            serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
-	u32	rsvd1;
+	u32		card_type;
 	char            model[BFA_ADAPTER_MODEL_NAME_LEN];
 	char            model_descr[BFA_ADAPTER_MODEL_DESCR_LEN];
 	wwn_t           pwwn;
@@ -60,6 +60,7 @@
 	u8         pcie_lanes_orig;
 	u8         pcie_lanes;
 	u8	        cna_capable;
+	u8         is_mezz;
 };
 
 /**
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_auth.h b/drivers/scsi/bfa/include/defs/bfa_defs_auth.h
index 45df328..f56ed87 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_auth.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_auth.h
@@ -125,10 +125,10 @@
 	enum bfa_auth_status 	status;
 	enum bfa_auth_algo 	algo;
 	enum bfa_auth_group 	dh_grp;
-	u16		rjt_code;
-	u16		rjt_code_exp;
+	enum bfa_auth_rej_code  rjt_code;
+	enum bfa_auth_rej_code_exp rjt_code_exp;
 	u8			secret_set;
-	u8			resv[7];
+	u8			resv[3];
 };
 
 #endif /* __BFA_DEFS_AUTH_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_boot.h b/drivers/scsi/bfa/include/defs/bfa_defs_boot.h
index 6f4aa52..0fca10b 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_boot.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_boot.h
@@ -24,6 +24,8 @@
 
 enum {
 	BFA_BOOT_BOOTLUN_MAX = 4,	/*  maximum boot lun per IOC */
+	BFA_PREBOOT_BOOTLUN_MAX = 8,    /*  maximum preboot lun per IOC */
+
 };
 
 #define BOOT_CFG_REV1	1
@@ -67,5 +69,13 @@
 	struct bfa_boot_bootlun_s blun_disc[BFA_BOOT_BOOTLUN_MAX];
 };
 
+struct bfa_boot_pbc_s {
+	u8         enable;         /* enable/disable SAN boot */
+	u8         speed;          /* boot speed settings */
+	u8         topology;       /* boot topology setting */
+	u8         rsvd1;
+	u32        nbluns;         /* number of boot luns */
+	struct bfa_boot_bootlun_s pblun[BFA_PREBOOT_BOOTLUN_MAX];
+};
 
 #endif /* __BFA_DEFS_BOOT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_driver.h b/drivers/scsi/bfa/include/defs/bfa_defs_driver.h
index 50382dd..7d00d00 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_driver.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_driver.h
@@ -29,7 +29,7 @@
     u16    tm_target_reset;
     u16    tm_bus_reset;
     u16    ioc_restart;        /*  IOC restart count */
-    u16    io_pending;         /*  outstanding io count per-IOC */
+    u16    rsvd;
     u64    control_req;
     u64    input_req;
     u64    output_req;
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h b/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h
index a07ef4a..af86a63 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h
@@ -48,7 +48,7 @@
 	u64	disc_fcf_unavail; /*  Discovery FCF not avail	     */
 	u64	linksvc_unsupp;	/*  FIP link service req unsupp.    */
 	u64	linksvc_err;	/*  FIP link service req errors     */
-	u64	logo_req;	/*  FIP logo			     */
+	u64	logo_req;	/*  FIP logos received			     */
 	u64	clrvlink_req;	/*  Clear virtual link requests     */
 	u64	op_unsupp;	/*  FIP operation unsupp.	     */
 	u64	untagged;	/*  FIP untagged frames	     */
@@ -64,21 +64,15 @@
 	u64	txf_timeout;	/*  Tx timeouts		     */
 	u64	txf_parity_errors; /*  Transmit parity err	     */
 	u64	txf_fid_parity_errors; /*  Transmit FID parity err  */
-	u64	tx_pause;	/*  Tx pause frames		     */
-	u64	tx_zero_pause;	/*  Tx zero pause frames	     */
-	u64	tx_first_pause;	/*  Tx first pause frames	     */
-	u64	rx_pause;	/*  Rx pause frames		     */
-	u64	rx_zero_pause;	/*  Rx zero pause frames	     */
-	u64	rx_first_pause;	/*  Rx first pause frames	     */
-	u64	rxf_ucast_octets; /*  Rx unicast octets	     */
-	u64	rxf_ucast;	/*  Rx unicast frames		     */
-	u64	rxf_ucast_vlan;	/*  Rx unicast vlan frames	     */
-	u64	rxf_mcast_octets; /*  Rx multicast octets	     */
-	u64	rxf_mcast;	/*  Rx multicast frames	     */
-	u64	rxf_mcast_vlan;	/*  Rx multicast vlan frames	     */
-	u64	rxf_bcast_octets; /*  Rx broadcast octests	     */
-	u64	rxf_bcast;	/*  Rx broadcast frames	     */
-	u64	rxf_bcast_vlan;	/*  Rx broadcast vlan frames	     */
+	u64     rxf_ucast_octets; /* Rx FCoE unicast octets        */
+	u64     rxf_ucast;      /* Rx FCoE unicast frames          */
+	u64     rxf_ucast_vlan; /* Rx FCoE unicast vlan frames     */
+	u64     rxf_mcast_octets; /* Rx FCoE multicast octets      */
+	u64     rxf_mcast;      /* Rx FCoE multicast frames        */
+	u64     rxf_mcast_vlan; /* Rx FCoE multicast vlan frames   */
+	u64     rxf_bcast_octets; /* Rx FCoE broadcast octets      */
+	u64     rxf_bcast;      /* Rx FCoE broadcast frames        */
+	u64     rxf_bcast_vlan; /* Rx FCoE broadcast vlan frames   */
 };
 
 /**
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h b/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h
index 8d8e6a9..add0a05 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h
@@ -126,7 +126,7 @@
 	struct bfa_ioc_driver_attr_s 	driver_attr;	/*  driver attr    */
 	struct bfa_ioc_pci_attr_s	pci_attr;
 	u8				port_id;	/*  port number    */
-	u8				rsvd[7];	/*!< 64bit align    */
+	u8				rsvd[7];	/*  64bit align    */
 };
 
 /**
@@ -138,6 +138,11 @@
 	BFA_IOC_AEN_ENABLE	= 3,	/*  IOC enabled event		*/
 	BFA_IOC_AEN_DISABLE	= 4,	/*  IOC disabled event		*/
 	BFA_IOC_AEN_FWMISMATCH	= 5,	/*  IOC firmware mismatch	*/
+	BFA_IOC_AEN_FWCFG_ERROR = 6,    /*  IOC firmware config error   */
+	BFA_IOC_AEN_INVALID_VENDOR = 7,
+	BFA_IOC_AEN_INVALID_NWWN = 8,   /*  Zero NWWN                   */
+	BFA_IOC_AEN_INVALID_PWWN = 9    /*  Zero PWWN                   */
+
 };
 
 /**
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h b/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h
index c290fb1..31e728a 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h
@@ -51,8 +51,10 @@
 	u16        num_tsktm_reqs;	/*  TM task management requests*/
 	u16        num_fcxp_reqs;	/*  unassisted FC exchanges	*/
 	u16        num_uf_bufs;	/*  unsolicited recv buffers	*/
-	u8		num_cqs;
-	u8		rsvd[5];
+	u8	   num_cqs;
+	u8         fw_tick_res;    /*!< FW clock resolution in ms */
+	u8         rsvd[4];
+
 };
 
 struct bfa_iocfc_drvcfg_s {
@@ -176,10 +178,10 @@
     u32    nos_rx;
     u32    lip_rx;
     u32    arbf0_rx;
+    u32    arb_rx;
     u32    mrk_rx;
     u32    const_mrk_rx;
     u32    prim_unknown;
-    u32    rsvd;
 };
 
 
@@ -200,6 +202,8 @@
     u32    lrr_tx;             /*  No. of times LRR tx started         */
     u32    ols_tx;             /*  No. of times OLS tx started         */
     u32    nos_tx;             /*  No. of times NOS tx started         */
+    u32    hwsm_lrr_rx;        /*  No. of times LRR rx-ed by HWSM      */
+    u32    hwsm_lr_rx;         /* No. of times LR rx-ed by HWSM        */
 };
 
 
@@ -239,7 +243,7 @@
     u32    disc_fcf_unavail;   /*  Discovery FCF Not Avail.            */
     u32    linksvc_unsupp;     /*  Unsupported link service req        */
     u32    linksvc_err;        /*  Parse error in link service req     */
-    u32    logo_req;           /*  Number of FIP logos received        */
+    u32    logo_req;           /*  FIP logos received	               */
     u32    clrvlink_req;       /*  Clear virtual link req              */
     u32    op_unsupp;          /*  Unsupported FIP operation           */
     u32    untagged;           /*  Untagged frames (ignored)           */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h b/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h
index 2ec7699..d77788b 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h
@@ -34,6 +34,15 @@
 	BFA_ITNIM_INITIATIOR 	= 7,	/*  initiator */
 };
 
+struct bfa_itnim_latency_s {
+	u32	min;
+	u32	max;
+	u32	count;
+	u32	clock_res;
+	u32	avg;
+	u32	rsvd;
+};
+
 struct bfa_itnim_hal_stats_s {
 	u32	onlines;	/*  ITN nexus onlines (PRLI done) */
 	u32	offlines;	/*  ITN Nexus offlines 	*/
@@ -91,6 +100,7 @@
 	u8	task_retry_id;  /*  task retry ident support   */
 	u8 rec_support;    /*  REC supported              */
 	u8 conf_comp;      /*  confirmed completion supp  */
+	struct bfa_itnim_latency_s  io_latency; /* IO latency  */
 };
 
 /**
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h
index c5bd9c3..d22fb79 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h
@@ -45,26 +45,6 @@
 #define BFA_MFG_CHKSUM_SIZE			16
 
 /**
- * Manufacturing block encrypted version
- */
-#define BFA_MFG_ENC_VER				2
-
-/**
- * Manufacturing block version 1 length
- */
-#define BFA_MFG_VER1_LEN			128
-
-/**
- * Manufacturing block header length
- */
-#define BFA_MFG_HDR_LEN				4
-
-/**
- * Checksum size
- */
-#define BFA_MFG_CHKSUM_SIZE			16
-
-/**
  * Manufacturing block format
  */
 #define BFA_MFG_SERIALNUM_SIZE			11
@@ -86,6 +66,9 @@
 	BFA_MFG_TYPE_FC4P1   = 415,      /*  4G 1port FC card		*/
 	BFA_MFG_TYPE_CNA10P2 = 1020,     /*  10G 2port CNA card	*/
 	BFA_MFG_TYPE_CNA10P1 = 1010,     /*  10G 1port CNA card	*/
+	BFA_MFG_TYPE_JAYHAWK = 804,      /*  Jayhawk mezz card */
+	BFA_MFG_TYPE_WANCHESE = 1007,    /*  Wanchese mezz card */
+	BFA_MFG_TYPE_INVALID = 0,        /*  Invalid card type */
 };
 
 #pragma pack(1)
@@ -95,6 +78,24 @@
  */
 #define bfa_mfg_type2port_num(card_type) (((card_type) / 10) % 10)
 
+/**
+ * Check if Mezz card
+ */
+#define bfa_mfg_is_mezz(type) (( \
+	(type) == BFA_MFG_TYPE_JAYHAWK || \
+	(type) == BFA_MFG_TYPE_WANCHESE))
+
+/**
+ * Check if card type valid
+ */
+#define bfa_mfg_is_card_type_valid(type) (( \
+	(type) == BFA_MFG_TYPE_FC8P2 || \
+	(type) == BFA_MFG_TYPE_FC8P1 || \
+	(type) == BFA_MFG_TYPE_FC4P2 || \
+	(type) == BFA_MFG_TYPE_FC4P1 || \
+	(type) == BFA_MFG_TYPE_CNA10P2 || \
+	(type) == BFA_MFG_TYPE_CNA10P1 || \
+	bfa_mfg_is_mezz(type)))
 
 /**
  * All numerical fields are in big-endian format.
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pci.h b/drivers/scsi/bfa/include/defs/bfa_defs_pci.h
index c9b8332..ea7d89b 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_pci.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_pci.h
@@ -26,8 +26,13 @@
 	BFA_PCI_DEVICE_ID_FC_8G2P	= 0x13,
 	BFA_PCI_DEVICE_ID_FC_8G1P	= 0x17,
 	BFA_PCI_DEVICE_ID_CT		= 0x14,
+	BFA_PCI_DEVICE_ID_CT_FC         = 0x21,
 };
 
+#define bfa_asic_id_ct(devid)                   \
+	((devid) == BFA_PCI_DEVICE_ID_CT ||     \
+	 (devid) == BFA_PCI_DEVICE_ID_CT_FC)
+
 /**
  * PCI sub-system device and vendor ID information
  */
@@ -35,7 +40,9 @@
 	BFA_PCI_FCOE_SSDEVICE_ID	= 0x14,
 };
 
-#define BFA_PCI_ACCESS_RANGES 1	/* Maximum number of device address ranges
-				 * mapped through different BAR(s). */
+/**
+ * Maximum number of device address ranges mapped through different BAR(s)
+ */
+#define BFA_PCI_ACCESS_RANGES 1
 
 #endif /* __BFA_DEFS_PCI_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_port.h b/drivers/scsi/bfa/include/defs/bfa_defs_port.h
index 501bc97..ebdf0d1 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_port.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_port.h
@@ -50,12 +50,12 @@
  * FCS port configuration.
  */
 struct bfa_port_cfg_s {
-    wwn_t               pwwn;       /*  port wwn */
-    wwn_t               nwwn;       /*  node wwn */
-    struct bfa_port_symname_s  sym_name;   /*  vm port symbolic name */
-    enum bfa_port_role     roles;      /*  FCS port roles */
-	u32			rsvd;
-    u8             tag[16];	/*  opaque tag from application */
+	wwn_t               pwwn;       /*  port wwn */
+	wwn_t               nwwn;       /*  node wwn */
+	struct bfa_port_symname_s  sym_name;   /*  vm port symbolic name */
+	bfa_boolean_t       preboot_vp;  /* vport created from PBC */
+	enum bfa_port_role     roles;      /*  FCS port roles */
+	u8             tag[16];	/*  opaque tag from application */
 };
 
 /**
@@ -159,7 +159,7 @@
 	u32        ms_plogi_rsp_err;
 	u32        ms_plogi_acc_err;
 	u32        ms_plogi_accepts;
-	u32        ms_rejects;	/* NS command rejects */
+	u32        ms_rejects;	/* MS command rejects */
 	u32        ms_plogi_unknown_rsp;
 	u32        ms_plogi_alloc_wait;
 
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h
index 26e5cc7..2de6758 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h
@@ -38,6 +38,7 @@
 	BFA_PPORT_ST_IOCDOWN 		= 10,
 	BFA_PPORT_ST_IOCDIS 		= 11,
 	BFA_PPORT_ST_FWMISMATCH		= 12,
+	BFA_PPORT_ST_PREBOOT_DISABLED   = 13,
 	BFA_PPORT_ST_MAX_STATE,
 };
 
@@ -203,6 +204,8 @@
 	 */
 	wwn_t           nwwn;		/*  node wwn */
 	wwn_t           pwwn;		/*  port wwn */
+	wwn_t           factorynwwn;    /*  factory node wwn */
+	wwn_t           factorypwwn;    /*  factory port wwn */
 	enum fc_cos     cos_supported;	/*  supported class of services */
 	u32        rsvd;
 	struct fc_symname_s    port_symname;	/*  port symbolic name */
@@ -243,7 +246,7 @@
 	u64    secs_reset; /* Seconds since stats is reset     */
 	u64    tx_frames;  /* Tx frames                */
 	u64    tx_words;   /* Tx words                 */
-	u64    tx_lip;     /* TX LIP               */
+	u64    tx_lip;     /* Tx LIP               */
 	u64    tx_nos;     /* Tx NOS               */
 	u64    tx_ols;     /* Tx OLS               */
 	u64    tx_lr;      /* Tx LR                */
@@ -309,7 +312,7 @@
 	u64    rx_zero_pause;    /* Rx zero pause              */
 	u64    tx_pause;     /* Tx pause               */
 	u64    tx_zero_pause;    /* Tx zero pause              */
-	u64    rx_fcoe_pause;    /* Rx fcoe pause              */
+	u64    rx_fcoe_pause;    /* Rx FCoE pause              */
 	u64    rx_fcoe_zero_pause; /* Rx FCoE zero pause       */
 	u64    tx_fcoe_pause;    /* Tx FCoE pause              */
 	u64    tx_fcoe_zero_pause; /* Tx FCoE zero pause       */
@@ -381,26 +384,10 @@
 	u8         trunked;	/*  Trunked or not (1 or 0) */
 	u8         resvd[3];
 	struct bfa_qos_attr_s  qos_attr;   /* QoS Attributes */
-	struct bfa_qos_vc_attr_s qos_vc_attr;  /*  VC info from ELP */
 	union {
-		struct {
-			u8         tmaster;/*  Trunk Master or
-						 *    not (1 or 0) */
-			u8         tlinks;	/*  Trunk links bitmap
-						 *    (linkup) */
-			u8         resv1;	/*  Reserved */
-		} trunk_info;
-
-		struct {
-			u8         myalpa;	   /*  alpa claimed */
-			u8         login_req; /*  Login required or
-						    *    not (1 or 0) */
-			u8         alpabm_val;/*  alpa bitmap valid
-						    *    or not (1 or 0) */
-			struct fc_alpabm_s     alpabm;	   /*  alpa bitmap */
-		} loop_info;
-	} tl;
-	struct bfa_fcport_fcf_s fcf;    /*!< FCF information (for FCoE) */
+		struct bfa_qos_vc_attr_s qos_vc_attr;  /* VC info from ELP */
+		struct bfa_fcport_fcf_s fcf;    /* FCF information (for FCoE) */
+	} vc_fcf;
 };
 
 #endif /* __BFA_DEFS_PPORT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_status.h b/drivers/scsi/bfa/include/defs/bfa_defs_status.h
index ec78b4c..6eb4e62 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_status.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_status.h
@@ -84,8 +84,9 @@
 	BFA_STATUS_BADFRMHDR 	= 48,	/*  Bad frame header */
 	BFA_STATUS_BADFRMSZ 	= 49,	/*  Bad frame size check and replace
 					 * SFP/cable */
-	BFA_STATUS_MISSINGFRM 	= 50,	/*  Missing frame check and replace
-					 * SFP/cable */
+	BFA_STATUS_MISSINGFRM 	= 50,   /* Missing frame check and replace
+					 * SFP/cable or for Mezz card check and
+					 * replace pass through module */
 	BFA_STATUS_LINKTIMEOUT 	= 51,	/*  Link timeout check and replace
 					 * SFP/cable */
 	BFA_STATUS_NO_FCPIM_NEXUS = 52,	/*  No FCP Nexus exists with the
@@ -173,7 +174,7 @@
 	BFA_STATUS_LEDTEST_OP = 109, /*  LED test is operating */
 	BFA_STATUS_CEE_NOT_DN = 110, /*  eth port is not at down state, please
 				      * bring down first */
-	BFA_STATUS_10G_SPD = 111, /*  Speed setting not valid for 10G HBA */
+	BFA_STATUS_10G_SPD = 111, /*  Speed setting not valid for 10G CNA */
 	BFA_STATUS_IM_INV_TEAM_NAME = 112, /*  Invalid team name */
 	BFA_STATUS_IM_DUP_TEAM_NAME = 113, /*  Given team name already
 					    * exists */
@@ -213,12 +214,13 @@
 					     * loaded */
 	BFA_STATUS_CARD_TYPE_MISMATCH = 131, /*  Card type mismatch */
 	BFA_STATUS_BAD_ASICBLK = 132, /*  Bad ASIC block */
-	BFA_STATUS_NO_DRIVER = 133, /*  Brocade adapter/driver not installed or loaded */
-	BFA_STATUS_INVALID_MAC = 134, /*  Invalid mac address */
+	BFA_STATUS_NO_DRIVER = 133, /*  Brocade adapter/driver not installed
+				     *  or loaded */
+	BFA_STATUS_INVALID_MAC = 134, /*  Invalid MAC address */
 	BFA_STATUS_IM_NO_VLAN = 135, /*  No VLANs configured on the adapter */
 	BFA_STATUS_IM_ETH_LB_FAILED = 136, /*  Ethernet loopback test failed */
-	BFA_STATUS_IM_PVID_REMOVE = 137, /*  Cannot remove port vlan (PVID) */
-	BFA_STATUS_IM_PVID_EDIT = 138, /*  Cannot edit port vlan (PVID) */
+	BFA_STATUS_IM_PVID_REMOVE = 137, /* Cannot remove port VLAN (PVID) */
+	BFA_STATUS_IM_PVID_EDIT = 138, /* Cannot edit port VLAN (PVID) */
 	BFA_STATUS_CNA_NO_BOOT = 139, /*  Boot upload not allowed for CNA */
 	BFA_STATUS_IM_PVID_NON_ZERO = 140, /*  Port VLAN ID (PVID) is Set to
 					    * Non-Zero Value */
@@ -232,14 +234,15 @@
 	BFA_STATUS_INSUFFICIENT_PERMS = 144, /*  User doesn't have sufficient
 					      * permissions to execute the BCU
 					      * application */
-	BFA_STATUS_IM_INV_VLAN_NAME = 145, /*  Invalid/Reserved Vlan name
+	BFA_STATUS_IM_INV_VLAN_NAME = 145, /* Invalid/Reserved VLAN name
 					    * string. The name is not allowed
-					    * for the normal Vlans */
+					    * for the normal VLAN */
 	BFA_STATUS_CMD_NOTSUPP_CNA = 146, /*  Command not supported for CNA */
-	BFA_STATUS_IM_PASSTHRU_EDIT = 147, /*  Can not edit passthru vlan id */
-	BFA_STATUS_IM_BIND_FAILED = 148, /*! < IM Driver bind operation
+	BFA_STATUS_IM_PASSTHRU_EDIT = 147, /* Can not edit passthrough VLAN
+					    * id */
+	BFA_STATUS_IM_BIND_FAILED = 148, /* IM Driver bind operation
 					  * failed */
-	BFA_STATUS_IM_UNBIND_FAILED = 149, /* ! < IM Driver unbind operation
+	BFA_STATUS_IM_UNBIND_FAILED = 149, /* IM Driver unbind operation
 					    * failed */
 	BFA_STATUS_IM_PORT_IN_TEAM = 150, /*  Port is already part of the
 					   * team */
@@ -249,7 +252,24 @@
 	BFA_STATUS_IM_TEAM_CFG_NOT_ALLOWED = 153, /*  Given settings are not
 						* allowed for the current
 						* Teaming mode */
-	BFA_STATUS_MAX_VAL		/*  Unknown error code */
+	BFA_STATUS_PBC = 154, /* Operation not allowed for pre-boot
+			       * configuration */
+	BFA_STATUS_DEVID_MISSING = 155, /* Boot image is not for the adapter(s)
+					 * installed */
+	BFA_STATUS_BAD_FWCFG = 156, /* Bad firmware configuration */
+	BFA_STATUS_CREATE_FILE = 157, /* Failed to create temporary file */
+	BFA_STATUS_INVALID_VENDOR = 158, /* Invalid switch vendor */
+	BFA_STATUS_SFP_NOT_READY = 159, /* SFP info is not ready. Retry */
+	BFA_STATUS_NO_TOPOLOGY_FOR_CNA = 160, /* Topology command not
+					       * applicable to CNA */
+	BFA_STATUS_BOOT_CODE_UPDATED = 161, /* reboot -- -r is needed after
+					     * boot code updated */
+	BFA_STATUS_BOOT_VERSION = 162, /* Boot code version not compatible with
+					* the driver installed */
+	BFA_STATUS_CARDTYPE_MISSING = 163, /* Boot image is not for the
+					    * adapter(s) installed */
+	BFA_STATUS_INVALID_CARDTYPE = 164, /* Invalid card type provided */
+	BFA_STATUS_MAX_VAL              /* Unknown error code */
 };
 #define bfa_status_t enum bfa_status
 
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h
index a39f474..cfd6ba7 100644
--- a/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h
@@ -40,7 +40,8 @@
  *
  * @return None
  */
-void            bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv);
+void bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv);
+void bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s);
 
 
 
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs.h b/drivers/scsi/bfa/include/fcs/bfa_fcs.h
index f2fd35f..54e5b81 100644
--- a/drivers/scsi/bfa/include/fcs/bfa_fcs.h
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs.h
@@ -61,8 +61,8 @@
 /*
  * bfa fcs API functions
  */
-void bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
-			bfa_boolean_t min_cfg);
+void bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa,
+			struct bfad_s *bfad, bfa_boolean_t min_cfg);
 void bfa_fcs_init(struct bfa_fcs_s *fcs);
 void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
 			struct bfa_fcs_driver_info_s *driver_info);
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h
index e719f2c..9a35ecf 100644
--- a/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h
@@ -41,6 +41,7 @@
 	struct bfa_fcs_s      	*fcs;		/*  fcs instance         */
 	struct bfa_timer_s 	timer;		/*  timer functions      */
 	struct bfa_itnim_s 	*bfa_itnim;	/*  BFA itnim struct     */
+	u32                	prli_retries;   /*  max prli retry attempts */
 	bfa_boolean_t	 	seq_rec;	/*  seq recovery support */
 	bfa_boolean_t	 	rec_support;	/*  REC supported        */
 	bfa_boolean_t	 	conf_comp;	/*  FCP_CONF     support */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h
index 702b95b..3027fc6 100644
--- a/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h
@@ -58,6 +58,7 @@
 	u16        reply_oxid;	/*  OX_ID of inbound requests */
 	enum fc_cos        fc_cos;	/*  FC classes of service supp */
 	bfa_boolean_t   cisc;	/*  CISC capable device */
+	bfa_boolean_t   prlo;   /*  processing prlo or LOGO */
 	wwn_t           pwwn;	/*  port wwn of rport */
 	wwn_t           nwwn;	/*  node wwn of rport */
 	struct bfa_rport_symname_s psym_name; /*  port symbolic name  */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h
index cd33f2c..0af2624 100644
--- a/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h
@@ -49,6 +49,10 @@
 			struct bfa_fcs_s *fcs, u16 vf_id,
 			struct bfa_port_cfg_s *port_cfg,
 			struct bfad_vport_s *vport_drv);
+bfa_status_t bfa_fcs_pbc_vport_create(struct bfa_fcs_vport_s *vport,
+			struct bfa_fcs_s *fcs, uint16_t vf_id,
+			struct bfa_port_cfg_s *port_cfg,
+			struct bfad_vport_s *vport_drv);
 bfa_status_t bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport);
 bfa_status_t bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport);
 bfa_status_t bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport);
diff --git a/drivers/scsi/bfa/include/log/bfa_log_linux.h b/drivers/scsi/bfa/include/log/bfa_log_linux.h
index bd451db..44bc897 100644
--- a/drivers/scsi/bfa/include/log/bfa_log_linux.h
+++ b/drivers/scsi/bfa/include/log/bfa_log_linux.h
@@ -53,8 +53,10 @@
 	(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 16)
 #define BFA_LOG_LINUX_DRIVER_ERROR \
 	(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 17)
-#define BFA_LOG_LINUX_DRIVER_DIAG \
+#define BFA_LOG_LINUX_DRIVER_INFO \
 	(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 18)
-#define BFA_LOG_LINUX_DRIVER_AEN \
+#define BFA_LOG_LINUX_DRIVER_DIAG \
 	(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 19)
+#define BFA_LOG_LINUX_DRIVER_AEN \
+	(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 20)
 #endif
diff --git a/drivers/scsi/bfa/include/protocol/fc.h b/drivers/scsi/bfa/include/protocol/fc.h
index 8d10380..436dd7c 100644
--- a/drivers/scsi/bfa/include/protocol/fc.h
+++ b/drivers/scsi/bfa/include/protocol/fc.h
@@ -1080,6 +1080,7 @@
 #define FC_REC_TOV		(FC_ED_TOV + 1)
 #define FC_RA_TOV		10
 #define FC_ELS_TOV		(2 * FC_RA_TOV)
+#define FC_FCCT_TOV		(3 * FC_RA_TOV)
 
 /*
  * virtual fabric related defines
diff --git a/drivers/scsi/bfa/lport_api.c b/drivers/scsi/bfa/lport_api.c
index d3907d1..72b3f50 100644
--- a/drivers/scsi/bfa/lport_api.c
+++ b/drivers/scsi/bfa/lport_api.c
@@ -137,6 +137,8 @@
 /*
  * Iterate's through all the rport's in the given port to
  * determine the maximum operating speed.
+ *
+ * To be used in TRL Functionality only
  */
 enum bfa_pport_speed
 bfa_fcs_port_get_rport_max_speed(struct bfa_fcs_port_s *port)
@@ -146,7 +148,8 @@
 	struct bfa_fcs_s *fcs;
 	enum bfa_pport_speed max_speed = 0;
 	struct bfa_pport_attr_s pport_attr;
-	enum bfa_pport_speed pport_speed;
+	enum bfa_pport_speed pport_speed, rport_speed;
+	bfa_boolean_t     trl_enabled = bfa_fcport_is_ratelim(port->fcs->bfa);
 
 	if (port == NULL)
 		return 0;
@@ -164,19 +167,28 @@
 	qe = bfa_q_first(qh);
 
 	while (qe != qh) {
-		rport = (struct bfa_fcs_rport_s *)qe;
-		if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000)
-		    || (bfa_fcs_rport_get_state(rport) == BFA_RPORT_OFFLINE)) {
+		rport = (struct bfa_fcs_rport_s *) qe;
+		if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000) ||
+			(bfa_fcs_rport_get_state(rport) ==
+						BFA_RPORT_OFFLINE)) {
 			qe = bfa_q_next(qe);
 			continue;
 		}
 
-		if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_8GBPS)
-		    || (rport->rpf.rpsc_speed > pport_speed)) {
-			max_speed = rport->rpf.rpsc_speed;
+		rport_speed = rport->rpf.rpsc_speed;
+		if ((trl_enabled) &&  (rport_speed ==
+						BFA_PPORT_SPEED_UNKNOWN)) {
+			/* Use default ratelim speed setting */
+			rport_speed =
+				bfa_fcport_get_ratelim_speed(port->fcs->bfa);
+		}
+
+		if ((rport_speed  == BFA_PPORT_SPEED_8GBPS) ||
+			(rport_speed > pport_speed)) {
+			max_speed = rport_speed;
 			break;
-		} else if (rport->rpf.rpsc_speed > max_speed) {
-			max_speed = rport->rpf.rpsc_speed;
+		} else if (rport_speed > max_speed) {
+			max_speed = rport_speed;
 		}
 
 		qe = bfa_q_next(qe);
diff --git a/drivers/scsi/bfa/ms.c b/drivers/scsi/bfa/ms.c
index 5e8c8de..1d579ef 100644
--- a/drivers/scsi/bfa/ms.c
+++ b/drivers/scsi/bfa/ms.c
@@ -157,6 +157,7 @@
 		 * Start timer for a delayed retry
 		 */
 		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_retry);
+		ms->port->stats.ms_retries++;
 		bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), &ms->timer,
 				bfa_fcs_port_ms_timeout, ms,
 				BFA_FCS_RETRY_TIMEOUT);
@@ -279,6 +280,7 @@
 		 */
 		if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) {
 			bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_retry);
+			ms->port->stats.ms_retries++;
 			bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
 					&ms->timer, bfa_fcs_port_ms_timeout, ms,
 					BFA_FCS_RETRY_TIMEOUT);
@@ -359,7 +361,7 @@
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gmal_response,
-		      (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
+		      (void *)ms, FC_MAX_PDUSZ, FC_FCCT_TOV);
 
 	bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
 }
@@ -479,6 +481,7 @@
 		 */
 		if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) {
 			bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_retry);
+			ms->port->stats.ms_retries++;
 			bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
 					&ms->timer, bfa_fcs_port_ms_timeout, ms,
 					BFA_FCS_RETRY_TIMEOUT);
@@ -557,7 +560,7 @@
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gfn_response,
-		      (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
+		      (void *)ms, FC_MAX_PDUSZ, FC_FCCT_TOV);
 
 	bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
 }
@@ -637,7 +640,7 @@
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_plogi_response,
-		      (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
+		      (void *)ms, FC_MAX_PDUSZ, FC_ELS_TOV);
 
 	port->stats.ms_plogi_sent++;
 	bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
diff --git a/drivers/scsi/bfa/ns.c b/drivers/scsi/bfa/ns.c
index d20dd7e..ae0edcc 100644
--- a/drivers/scsi/bfa/ns.c
+++ b/drivers/scsi/bfa/ns.c
@@ -664,7 +664,7 @@
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_plogi_response,
-		      (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+		      (void *)ns, FC_MAX_PDUSZ, FC_ELS_TOV);
 	port->stats.ns_plogi_sent++;
 
 	bfa_sm_send_event(ns, NSSM_EVENT_PLOGI_SENT);
@@ -791,7 +791,7 @@
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rspn_id_response,
-		      (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+		      (void *)ns, FC_MAX_PDUSZ, FC_FCCT_TOV);
 
 	port->stats.ns_rspnid_sent++;
 
@@ -865,7 +865,7 @@
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rft_id_response,
-		      (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+		      (void *)ns, FC_MAX_PDUSZ, FC_FCCT_TOV);
 
 	port->stats.ns_rftid_sent++;
 	bfa_sm_send_event(ns, NSSM_EVENT_RFTID_SENT);
@@ -943,7 +943,7 @@
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rff_id_response,
-		      (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+		      (void *)ns, FC_MAX_PDUSZ, FC_FCCT_TOV);
 
 	port->stats.ns_rffid_sent++;
 	bfa_sm_send_event(ns, NSSM_EVENT_RFFID_SENT);
@@ -1029,7 +1029,7 @@
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_gid_ft_response,
 		      (void *)ns, bfa_fcxp_get_maxrsp(port->fcs->bfa),
-		      FC_RA_TOV);
+		      FC_FCCT_TOV);
 
 	port->stats.ns_gidft_sent++;
 
@@ -1228,10 +1228,10 @@
 
 	struct bfa_fcs_rport_s *rport;
 	u8         nwwns;
-	wwn_t          *wwns;
+	wwn_t  wwns[BFA_PREBOOT_BOOTLUN_MAX];
 	int             ii;
 
-	bfa_iocfc_get_bootwwns(port->fcs->bfa, &nwwns, &wwns);
+	bfa_iocfc_get_bootwwns(port->fcs->bfa, &nwwns, wwns);
 
 	for (ii = 0; ii < nwwns; ++ii) {
 		rport = bfa_fcs_rport_create_by_wwn(port, wwns[ii]);
diff --git a/drivers/scsi/bfa/rport.c b/drivers/scsi/bfa/rport.c
index 7b096f2..9b4c2c9 100644
--- a/drivers/scsi/bfa/rport.c
+++ b/drivers/scsi/bfa/rport.c
@@ -36,8 +36,6 @@
 
 BFA_TRC_FILE(FCS, RPORT);
 
-#define BFA_FCS_RPORT_MAX_RETRIES		(5)
-
 /* In millisecs */
 static u32 bfa_fcs_rport_del_timeout =
 			BFA_FCS_RPORT_DEF_DEL_TIMEOUT * 1000;
@@ -95,6 +93,7 @@
 			u8 reason_code_expl);
 static void     bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport,
 			struct fchs_s *rx_fchs, u16 len);
+static void	bfa_fcs_rport_send_prlo_acc(struct bfa_fcs_rport_s *rport);
 /**
  *  fcs_rport_sm FCS rport state machine events
  */
@@ -115,7 +114,8 @@
 	RPSM_EVENT_HCB_OFFLINE = 13,	/*  BFA rport offline callback */
 	RPSM_EVENT_FC4_OFFLINE = 14,	/*  FC-4 offline complete */
 	RPSM_EVENT_ADDRESS_CHANGE = 15,	/*  Rport's PID has changed */
-	RPSM_EVENT_ADDRESS_DISC = 16	/*  Need to Discover rport's PID */
+	RPSM_EVENT_ADDRESS_DISC = 16,	/*  Need to Discover rport's PID */
+	RPSM_EVENT_PRLO_RCVD = 17,      /*  PRLO from remote device      */
 };
 
 static void     bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport,
@@ -356,8 +356,8 @@
 		 */
 
 	case RPSM_EVENT_TIMEOUT:
-		rport->plogi_retries++;
 		if (rport->plogi_retries < BFA_FCS_RPORT_MAX_RETRIES) {
+			rport->plogi_retries++;
 			bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending);
 			bfa_fcs_rport_send_plogi(rport, NULL);
 		} else {
@@ -375,6 +375,7 @@
 		bfa_fcs_rport_free(rport);
 		break;
 
+	case RPSM_EVENT_PRLO_RCVD:
 	case RPSM_EVENT_LOGO_RCVD:
 		break;
 
@@ -430,6 +431,13 @@
 
 	case RPSM_EVENT_LOGO_RCVD:
 		bfa_fcs_rport_send_logo_acc(rport);
+		/*
+		 * !! fall through !!
+		 */
+	case RPSM_EVENT_PRLO_RCVD:
+		if (rport->prlo == BFA_TRUE)
+			bfa_fcs_rport_send_prlo_acc(rport);
+
 		bfa_fcxp_discard(rport->fcxp);
 		/*
 		 * !! fall through !!
@@ -504,6 +512,9 @@
 		bfa_fcs_rport_online_action(rport);
 		break;
 
+	case RPSM_EVENT_PRLO_RCVD:
+		break;
+
 	case RPSM_EVENT_LOGO_RCVD:
 		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv);
 		bfa_rport_offline(rport->bfa_rport);
@@ -582,6 +593,7 @@
 		break;
 
 	case RPSM_EVENT_LOGO_RCVD:
+	case RPSM_EVENT_PRLO_RCVD:
 		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
 		bfa_fcs_rport_offline_action(rport);
 		break;
@@ -624,6 +636,7 @@
 		break;
 
 	case RPSM_EVENT_LOGO_RCVD:
+	case RPSM_EVENT_PRLO_RCVD:
 		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
 		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
 		bfa_fcs_rport_offline_action(rport);
@@ -690,6 +703,7 @@
 		break;
 
 	case RPSM_EVENT_LOGO_RCVD:
+	case RPSM_EVENT_PRLO_RCVD:
 		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
 		bfa_fcxp_discard(rport->fcxp);
 		bfa_fcs_rport_offline_action(rport);
@@ -740,6 +754,7 @@
 		break;
 
 	case RPSM_EVENT_LOGO_RCVD:
+	case RPSM_EVENT_PRLO_RCVD:
 		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
 		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
 		bfa_fcs_rport_offline_action(rport);
@@ -811,6 +826,7 @@
 		break;
 
 	case RPSM_EVENT_LOGO_RCVD:
+	case RPSM_EVENT_PRLO_RCVD:
 		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
 		bfa_fcxp_discard(rport->fcxp);
 		bfa_fcs_rport_offline_action(rport);
@@ -843,6 +859,7 @@
 		break;
 
 	case RPSM_EVENT_LOGO_RCVD:
+	case RPSM_EVENT_PRLO_RCVD:
 	case RPSM_EVENT_ADDRESS_CHANGE:
 		break;
 
@@ -894,6 +911,7 @@
 	case RPSM_EVENT_SCN:
 	case RPSM_EVENT_LOGO_IMP:
 	case RPSM_EVENT_LOGO_RCVD:
+	case RPSM_EVENT_PRLO_RCVD:
 	case RPSM_EVENT_ADDRESS_CHANGE:
 		/**
 		 * rport is already going offline.
@@ -953,6 +971,7 @@
 
 	case RPSM_EVENT_SCN:
 	case RPSM_EVENT_LOGO_RCVD:
+	case RPSM_EVENT_PRLO_RCVD:
 		/**
 		 * Ignore, already offline.
 		 */
@@ -978,8 +997,11 @@
 	switch (event) {
 	case RPSM_EVENT_HCB_OFFLINE:
 	case RPSM_EVENT_ADDRESS_CHANGE:
-		if (rport->pid)
+		if (rport->pid && (rport->prlo == BFA_TRUE))
+			bfa_fcs_rport_send_prlo_acc(rport);
+		if (rport->pid && (rport->prlo == BFA_FALSE))
 			bfa_fcs_rport_send_logo_acc(rport);
+
 		/*
 		 * If the lport is online and if the rport is not a well known
 		 * address port, we try to re-discover the r-port.
@@ -1013,6 +1035,7 @@
 		break;
 
 	case RPSM_EVENT_LOGO_RCVD:
+	case RPSM_EVENT_PRLO_RCVD:
 		/**
 		 * Ignore - already processing a LOGO.
 		 */
@@ -1042,6 +1065,7 @@
 		break;
 
 	case RPSM_EVENT_LOGO_RCVD:
+	case RPSM_EVENT_PRLO_RCVD:
 	case RPSM_EVENT_ADDRESS_CHANGE:
 		break;
 
@@ -1075,6 +1099,7 @@
 		break;
 
 	case RPSM_EVENT_LOGO_RCVD:
+	case RPSM_EVENT_PRLO_RCVD:
 		bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
 		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
 		bfa_fcs_rport_free(rport);
@@ -1123,6 +1148,7 @@
 		break;
 
 	case RPSM_EVENT_LOGO_RCVD:
+	case RPSM_EVENT_PRLO_RCVD:
 	case RPSM_EVENT_LOGO_IMP:
 		break;
 
@@ -1174,6 +1200,7 @@
 
 	case RPSM_EVENT_SCN:
 	case RPSM_EVENT_LOGO_RCVD:
+	case RPSM_EVENT_PRLO_RCVD:
 	case RPSM_EVENT_PLOGI_SEND:
 		break;
 
@@ -1250,6 +1277,10 @@
 		bfa_fcs_rport_send_logo_acc(rport);
 		break;
 
+	case RPSM_EVENT_PRLO_RCVD:
+		bfa_fcs_rport_send_prlo_acc(rport);
+		break;
+
 	case RPSM_EVENT_PLOGI_COMP:
 		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
 		bfa_timer_stop(&rport->timer);
@@ -1322,6 +1353,10 @@
 				bfa_fcs_rport_del_timeout);
 		break;
 
+	case RPSM_EVENT_PRLO_RCVD:
+		bfa_fcs_rport_send_prlo_acc(rport);
+		break;
+
 	case RPSM_EVENT_SCN:
 		/**
 		 * ignore, wait for NS query response
@@ -1378,7 +1413,7 @@
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, bfa_fcs_rport_plogi_response,
-		      (void *)rport, FC_MAX_PDUSZ, FC_RA_TOV);
+		      (void *)rport, FC_MAX_PDUSZ, FC_ELS_TOV);
 
 	rport->stats.plogis++;
 	bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
@@ -1519,7 +1554,7 @@
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, bfa_fcs_rport_adisc_response,
-		      rport, FC_MAX_PDUSZ, FC_RA_TOV);
+		      rport, FC_MAX_PDUSZ, FC_ELS_TOV);
 
 	rport->stats.adisc_sent++;
 	bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
@@ -1580,7 +1615,7 @@
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, bfa_fcs_rport_gidpn_response,
-		      (void *)rport, FC_MAX_PDUSZ, FC_RA_TOV);
+		      (void *)rport, FC_MAX_PDUSZ, FC_FCCT_TOV);
 
 	bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
 }
@@ -1692,7 +1727,7 @@
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, NULL, rport, FC_MAX_PDUSZ,
-		      FC_ED_TOV);
+		      FC_ELS_TOV);
 
 	rport->stats.logos++;
 	bfa_fcxp_discard(rport->fcxp);
@@ -2184,6 +2219,7 @@
 	rport->reply_oxid = fchs->ox_id;
 	bfa_trc(rport->fcs, rport->reply_oxid);
 
+	rport->prlo = BFA_FALSE;
 	rport->stats.logo_rcvd++;
 	bfa_sm_send_event(rport, RPSM_EVENT_LOGO_RCVD);
 }
@@ -2553,6 +2589,30 @@
 	}
 }
 
+/* Send best case acc to prlo */
+static void
+bfa_fcs_rport_send_prlo_acc(struct bfa_fcs_rport_s *rport)
+{
+	struct bfa_fcs_port_s *port = rport->port;
+	struct fchs_s fchs;
+	struct bfa_fcxp_s *fcxp;
+	int len;
+
+	bfa_trc(rport->fcs, rport->pid);
+
+	fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+	if (!fcxp)
+		return;
+
+	len = fc_prlo_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+			rport->pid, bfa_fcs_port_get_fcid(port),
+			rport->reply_oxid, 0);
+
+	bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id,
+			port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs,
+			NULL, NULL, FC_MAX_PDUSZ, 0);
+}
+
 /*
  * Send a LS reject
  */
@@ -2604,3 +2664,13 @@
 	if (rport_tmo > 0)
 		bfa_fcs_rport_del_timeout = rport_tmo * 1000;
 }
+
+void
+bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, uint16_t ox_id)
+{
+	bfa_trc(rport->fcs, rport->pid);
+
+	rport->prlo = BFA_TRUE;
+	rport->reply_oxid = ox_id;
+	bfa_sm_send_event(rport, RPSM_EVENT_PRLO_RCVD);
+}
diff --git a/drivers/scsi/bfa/rport_api.c b/drivers/scsi/bfa/rport_api.c
index a441f41..15e0c47 100644
--- a/drivers/scsi/bfa/rport_api.c
+++ b/drivers/scsi/bfa/rport_api.c
@@ -83,6 +83,7 @@
 {
 	struct bfa_rport_qos_attr_s qos_attr;
 	struct bfa_fcs_port_s *port = rport->port;
+	enum bfa_pport_speed rport_speed = rport->rpf.rpsc_speed;
 
 	bfa_os_memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s));
 
@@ -102,10 +103,14 @@
 	rport_attr->qos_attr = qos_attr;
 
 	rport_attr->trl_enforced = BFA_FALSE;
+
 	if (bfa_fcport_is_ratelim(port->fcs->bfa)) {
-		if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_UNKNOWN) ||
-			(rport->rpf.rpsc_speed <
-			bfa_fcs_port_get_rport_max_speed(port)))
+		if (rport_speed == BFA_PPORT_SPEED_UNKNOWN) {
+			/* Use default ratelim speed setting */
+			rport_speed =
+				bfa_fcport_get_ratelim_speed(rport->fcs->bfa);
+		}
+		if (rport_speed < bfa_fcs_port_get_rport_max_speed(port))
 			rport_attr->trl_enforced = BFA_TRUE;
 	}
 
diff --git a/drivers/scsi/bfa/rport_ftrs.c b/drivers/scsi/bfa/rport_ftrs.c
index ae7bba6..f2a9361 100644
--- a/drivers/scsi/bfa/rport_ftrs.c
+++ b/drivers/scsi/bfa/rport_ftrs.c
@@ -73,6 +73,7 @@
 bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
 {
 	struct bfa_fcs_rport_s *rport = rpf->rport;
+	struct bfa_fcs_fabric_s *fabric = &rport->fcs->fabric;
 
 	bfa_trc(rport->fcs, rport->pwwn);
 	bfa_trc(rport->fcs, rport->pid);
@@ -80,12 +81,16 @@
 
 	switch (event) {
 	case RPFSM_EVENT_RPORT_ONLINE:
-		if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
+		/* Send RPSC2 to a Brocade fabric only. */
+		if ((!BFA_FCS_PID_IS_WKA(rport->pid)) &&
+			((bfa_lps_is_brcd_fabric(rport->port->fabric->lps)) ||
+			(bfa_fcs_fabric_get_switch_oui(fabric) ==
+						BFA_FCS_BRCD_SWITCH_OUI))) {
 			bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
 			rpf->rpsc_retries = 0;
 			bfa_fcs_rpf_send_rpsc2(rpf, NULL);
-			break;
-		};
+		}
+		break;
 
 	case RPFSM_EVENT_RPORT_OFFLINE:
 		break;
@@ -269,6 +274,7 @@
 	if (__fcs_min_cfg(rport->port->fcs))
 		return;
 
+	rport->rpf.rpsc_speed = 0;
 	bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_OFFLINE);
 }
 
@@ -307,7 +313,7 @@
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 			  FC_CLASS_3, len, &fchs, bfa_fcs_rpf_rpsc2_response,
-			  rpf, FC_MAX_PDUSZ, FC_RA_TOV);
+			  rpf, FC_MAX_PDUSZ, FC_ELS_TOV);
 	rport->stats.rpsc_sent++;
 	bfa_sm_send_event(rpf, RPFSM_EVENT_FCXP_SENT);
 
diff --git a/drivers/scsi/bfa/scn.c b/drivers/scsi/bfa/scn.c
index 8fe09ba..8a60129 100644
--- a/drivers/scsi/bfa/scn.c
+++ b/drivers/scsi/bfa/scn.c
@@ -218,7 +218,7 @@
 
 	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
 		      FC_CLASS_3, len, &fchs, bfa_fcs_port_scn_scr_response,
-		      (void *)scn, FC_MAX_PDUSZ, FC_RA_TOV);
+		      (void *)scn, FC_MAX_PDUSZ, FC_ELS_TOV);
 
 	bfa_sm_send_event(scn, SCNSM_EVENT_SCR_SENT);
 }
diff --git a/drivers/scsi/bfa/vport.c b/drivers/scsi/bfa/vport.c
index e2720c8..b378ec7 100644
--- a/drivers/scsi/bfa/vport.c
+++ b/drivers/scsi/bfa/vport.c
@@ -218,9 +218,9 @@
 
 	switch (event) {
 	case BFA_FCS_VPORT_SM_DELETE:
-		bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo);
+		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
 		bfa_lps_discard(vport->lps);
-		bfa_fcs_vport_do_logo(vport);
+		bfa_fcs_port_delete(&vport->lport);
 		break;
 
 	case BFA_FCS_VPORT_SM_OFFLINE:
@@ -357,8 +357,9 @@
 
 	switch (event) {
 	case BFA_FCS_VPORT_SM_DELETE:
-		bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit);
-		bfa_fcs_vport_free(vport);
+		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
+		bfa_fcs_port_delete(&vport->lport);
+
 		break;
 
 	default:
@@ -594,6 +595,15 @@
 }
 
 /**
+ * delete notification from fabric SM. To be invoked from within FCS.
+ */
+void
+bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport)
+{
+	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE);
+}
+
+/**
  * Delete completion callback from associated lport
  */
 void
@@ -646,6 +656,7 @@
 		return BFA_STATUS_VPORT_MAX;
 
 	vport->vport_drv = vport_drv;
+	vport_cfg->preboot_vp = BFA_FALSE;
 	bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit);
 
 	bfa_fcs_lport_attach(&vport->lport, fcs, vf_id, vport);
@@ -657,6 +668,36 @@
 }
 
 /**
+ *      Use this function to instantiate a new FCS PBC vport object. This
+ *      function will not trigger any HW initialization process (which will be
+ *      done in vport_start() call)
+ *
+ *      param[in] vport        -       pointer to bfa_fcs_vport_t. This space
+ *                                      needs to be allocated by the driver.
+ *      param[in] fcs          -       FCS instance
+ *      param[in] vport_cfg    -       vport configuration
+ *      param[in] vf_id        -       VF_ID if vport is created within a VF.
+ *                                      FC_VF_ID_NULL to specify base fabric.
+ *      param[in] vport_drv    -       Opaque handle back to the driver's vport
+ *                                      structure
+ *
+ *      retval BFA_STATUS_OK - on success.
+ *      retval BFA_STATUS_FAILED - on failure.
+ */
+bfa_status_t
+bfa_fcs_pbc_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
+			uint16_t vf_id, struct bfa_port_cfg_s *vport_cfg,
+			struct bfad_vport_s *vport_drv)
+{
+	bfa_status_t rc;
+
+	rc = bfa_fcs_vport_create(vport, fcs, vf_id, vport_cfg, vport_drv);
+	vport->lport.port_cfg.preboot_vp = BFA_TRUE;
+
+	return rc;
+}
+
+/**
  *  	Use this function initialize the vport.
  *
  *  @param[in] vport - pointer to bfa_fcs_vport_t.
@@ -692,6 +733,8 @@
  *  	Use this function to delete a vport object. Fabric object should
  * 		be stopped before this function call.
  *
+ *	Donot invoke this from within FCS
+ *
  * 	param[in] vport - pointer to bfa_fcs_vport_t.
  *
  * 	return     None
@@ -699,6 +742,9 @@
 bfa_status_t
 bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport)
 {
+	if (vport->lport.port_cfg.preboot_vp)
+		return BFA_STATUS_PBC;
+
 	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE);
 
 	return BFA_STATUS_OK;
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index 6b624e7..00c0335 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -295,16 +295,21 @@
  * @max_cqes:              CQ size
  * @num_ccell:             number of command cells per connection
  * @ofld_conns_active:     active connection list
+ * @eh_wait:               wait queue for the endpoint to shutdown
  * @max_active_conns:      max offload connections supported by this device
  * @cid_que:               iscsi cid queue
  * @ep_rdwr_lock:          read / write lock to synchronize various ep lists
  * @ep_ofld_list:          connection list for pending offload completion
+ * @ep_active_list:        connection list for active offload endpoints
  * @ep_destroy_list:       connection list for pending offload completion
  * @mp_bd_tbl:             BD table to be used with middle path requests
  * @mp_bd_dma:             DMA address of 'mp_bd_tbl' memory buffer
  * @dummy_buffer:          Dummy buffer to be used with zero length scsicmd reqs
  * @dummy_buf_dma:         DMA address of 'dummy_buffer' memory buffer
  * @lock:              	   lock to synchonize access to hba structure
+ * @hba_shutdown_tmo:      Timeout value to shutdown each connection
+ * @conn_teardown_tmo:     Timeout value to tear down each connection
+ * @conn_ctx_destroy_tmo:  Timeout value to destroy context of each connection
  * @pci_did:               PCI device ID
  * @pci_vid:               PCI vendor ID
  * @pci_sdid:              PCI subsystem device ID
@@ -369,6 +374,7 @@
 
 	rwlock_t ep_rdwr_lock;
 	struct list_head ep_ofld_list;
+	struct list_head ep_active_list;
 	struct list_head ep_destroy_list;
 
 	/*
@@ -383,6 +389,8 @@
 	struct mutex net_dev_lock;/* sync net device access */
 
 	int hba_shutdown_tmo;
+	int conn_teardown_tmo;
+	int conn_ctx_destroy_tmo;
 	/*
 	 * PCI related info.
 	 */
@@ -631,6 +639,8 @@
 	EP_STATE_CLEANUP_CMPL           = 0x800,
 	EP_STATE_TCP_FIN_RCVD           = 0x1000,
 	EP_STATE_TCP_RST_RCVD           = 0x2000,
+	EP_STATE_LOGOUT_SENT            = 0x4000,
+	EP_STATE_LOGOUT_RESP_RCVD       = 0x8000,
 	EP_STATE_PG_OFLD_FAILED         = 0x1000000,
 	EP_STATE_ULP_UPDATE_FAILED      = 0x2000000,
 	EP_STATE_CLEANUP_FAILED         = 0x4000000,
@@ -645,6 +655,7 @@
  * @link:               list head to link elements
  * @hba:                adapter to which this connection belongs
  * @conn:               iscsi connection this EP is linked to
+ * @cls_ep:             associated iSCSI endpoint pointer
  * @sess:               iscsi session this EP is linked to
  * @cm_sk:              cnic sock struct
  * @hba_age:            age to detect if 'iscsid' issues ep_disconnect()
@@ -664,6 +675,7 @@
 	struct list_head link;
 	struct bnx2i_hba *hba;
 	struct bnx2i_conn *conn;
+	struct iscsi_endpoint *cls_ep;
 	struct cnic_sock *cm_sk;
 	u32 hba_age;
 	u32 state;
@@ -766,6 +778,8 @@
 extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep);
 extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action);
 
+extern int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep);
+
 /* Debug related function prototypes */
 extern void bnx2i_print_pend_cmd_queue(struct bnx2i_conn *conn);
 extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn);
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 3a66ca2..d23fc25 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -562,6 +562,8 @@
 	logout_wqe->num_bds = 1;
 	logout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
 
+	bnx2i_conn->ep->state = EP_STATE_LOGOUT_SENT;
+
 	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
 	return 0;
 }
@@ -1482,6 +1484,8 @@
 	resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain);
 
 	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
+
+	bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD;
 done:
 	spin_unlock(&session->lock);
 	return 0;
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index af6a00a..a796f56 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -17,8 +17,8 @@
 static u32 adapter_count;
 
 #define DRV_MODULE_NAME		"bnx2i"
-#define DRV_MODULE_VERSION	"2.1.1"
-#define DRV_MODULE_RELDATE	"Mar 24, 2010"
+#define DRV_MODULE_VERSION	"2.1.2"
+#define DRV_MODULE_RELDATE	"Jun 28, 2010"
 
 static char version[] __devinitdata =
 		"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
@@ -176,6 +176,9 @@
 void bnx2i_stop(void *handle)
 {
 	struct bnx2i_hba *hba = handle;
+	struct list_head *pos, *tmp;
+	struct bnx2i_endpoint *bnx2i_ep;
+	int conns_active;
 
 	/* check if cleanup happened in GOING_DOWN context */
 	if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN,
@@ -187,9 +190,33 @@
 	 *  control returns to network driver. So it is required to cleanup and
 	 * release all connection resources before returning from this routine.
 	 */
-	wait_event_interruptible_timeout(hba->eh_wait,
-					 (hba->ofld_conns_active == 0),
-					 hba->hba_shutdown_tmo);
+	while (hba->ofld_conns_active) {
+		conns_active = hba->ofld_conns_active;
+		wait_event_interruptible_timeout(hba->eh_wait,
+				(hba->ofld_conns_active != conns_active),
+				hba->hba_shutdown_tmo);
+		if (hba->ofld_conns_active == conns_active)
+			break;
+	}
+	if (hba->ofld_conns_active) {
+		/* Stage to force the disconnection
+		 * This is the case where the daemon is either slow or
+		 * not present
+		 */
+		printk(KERN_ALERT "bnx2i: Wait timeout, force all eps "
+			"to disconnect (%d)\n", hba->ofld_conns_active);
+		mutex_lock(&hba->net_dev_lock);
+		list_for_each_safe(pos, tmp, &hba->ep_active_list) {
+			bnx2i_ep = list_entry(pos, struct bnx2i_endpoint, link);
+			/* Clean up the chip only */
+			bnx2i_hw_ep_disconnect(bnx2i_ep);
+		}
+		mutex_unlock(&hba->net_dev_lock);
+		if (hba->ofld_conns_active)
+			printk(KERN_ERR "bnx2i: EP disconnect timeout (%d)!\n",
+				hba->ofld_conns_active);
+	}
+
 	/* This flag should be cleared last so that ep_disconnect() gracefully
 	 * cleans up connection context
 	 */
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index fa68ab3..a46ccc3 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -386,6 +386,7 @@
 	}
 
 	bnx2i_ep = ep->dd_data;
+	bnx2i_ep->cls_ep = ep;
 	INIT_LIST_HEAD(&bnx2i_ep->link);
 	bnx2i_ep->state = EP_STATE_IDLE;
 	bnx2i_ep->ep_iscsi_cid = (u16) -1;
@@ -678,7 +679,6 @@
 	return ep;
 }
 
-
 /**
  * bnx2i_find_ep_in_destroy_list - find iscsi_cid in destroy list
  * @hba: 		pointer to adapter instance
@@ -709,6 +709,38 @@
 }
 
 /**
+ * bnx2i_ep_active_list_add - add an entry to ep active list
+ * @hba:	pointer to adapter instance
+ * @ep:		pointer to endpoint (transport indentifier) structure
+ *
+ * current active conn queue manager
+ */
+static void bnx2i_ep_active_list_add(struct bnx2i_hba *hba,
+				     struct bnx2i_endpoint *ep)
+{
+	write_lock_bh(&hba->ep_rdwr_lock);
+	list_add_tail(&ep->link, &hba->ep_active_list);
+	write_unlock_bh(&hba->ep_rdwr_lock);
+}
+
+
+/**
+ * bnx2i_ep_active_list_del - deletes an entry to ep active list
+ * @hba:	pointer to adapter instance
+ * @ep:		pointer to endpoint (transport indentifier) structure
+ *
+ * current active conn queue manager
+ */
+static void bnx2i_ep_active_list_del(struct bnx2i_hba *hba,
+				     struct bnx2i_endpoint *ep)
+{
+	write_lock_bh(&hba->ep_rdwr_lock);
+	list_del_init(&ep->link);
+	write_unlock_bh(&hba->ep_rdwr_lock);
+}
+
+
+/**
  * bnx2i_setup_host_queue_size - assigns shost->can_queue param
  * @hba:	pointer to adapter instance
  * @shost:	scsi host pointer
@@ -784,6 +816,7 @@
 		goto mp_bdt_mem_err;
 
 	INIT_LIST_HEAD(&hba->ep_ofld_list);
+	INIT_LIST_HEAD(&hba->ep_active_list);
 	INIT_LIST_HEAD(&hba->ep_destroy_list);
 	rwlock_init(&hba->ep_rdwr_lock);
 
@@ -821,10 +854,15 @@
 	spin_lock_init(&hba->lock);
 	mutex_init(&hba->net_dev_lock);
 	init_waitqueue_head(&hba->eh_wait);
-	if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
-		hba->hba_shutdown_tmo = 240 * HZ;
-	else	/* 5706/5708/5709 */
-		hba->hba_shutdown_tmo = 30 * HZ;
+	if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
+		hba->hba_shutdown_tmo = 20 * HZ;
+		hba->conn_teardown_tmo = 20 * HZ;
+		hba->conn_ctx_destroy_tmo = 6 * HZ;
+	} else {	/* 5706/5708/5709 */
+		hba->hba_shutdown_tmo = 20 * HZ;
+		hba->conn_teardown_tmo = 10 * HZ;
+		hba->conn_ctx_destroy_tmo = 2 * HZ;
+	}
 
 	if (iscsi_host_add(shost, &hba->pcidev->dev))
 		goto free_dump_mem;
@@ -857,6 +895,7 @@
 
 	iscsi_host_remove(shost);
 	INIT_LIST_HEAD(&hba->ep_ofld_list);
+	INIT_LIST_HEAD(&hba->ep_active_list);
 	INIT_LIST_HEAD(&hba->ep_destroy_list);
 	pci_dev_put(hba->pcidev);
 
@@ -1461,6 +1500,26 @@
 	case ISCSI_HOST_PARAM_NETDEV_NAME:
 		len = sprintf(buf, "%s\n", hba->netdev->name);
 		break;
+	case ISCSI_HOST_PARAM_IPADDRESS: {
+		struct list_head *active_list = &hba->ep_active_list;
+
+		read_lock_bh(&hba->ep_rdwr_lock);
+		if (!list_empty(&hba->ep_active_list)) {
+			struct bnx2i_endpoint *bnx2i_ep;
+			struct cnic_sock *csk;
+
+			bnx2i_ep = list_first_entry(active_list,
+						    struct bnx2i_endpoint,
+						    link);
+			csk = bnx2i_ep->cm_sk;
+			if (test_bit(SK_F_IPV6, &csk->flags))
+				len = sprintf(buf, "%pI6\n", csk->src_ip);
+			else
+				len = sprintf(buf, "%pI4\n", csk->src_ip);
+		}
+		read_unlock_bh(&hba->ep_rdwr_lock);
+		break;
+	}
 	default:
 		return iscsi_host_get_param(shost, param, buf);
 	}
@@ -1599,7 +1658,7 @@
 
 	ep->state = EP_STATE_CLEANUP_START;
 	init_timer(&ep->ofld_timer);
-	ep->ofld_timer.expires = 10*HZ + jiffies;
+	ep->ofld_timer.expires = hba->conn_ctx_destroy_tmo + jiffies;
 	ep->ofld_timer.function = bnx2i_ep_ofld_timer;
 	ep->ofld_timer.data = (unsigned long) ep;
 	add_timer(&ep->ofld_timer);
@@ -1665,10 +1724,11 @@
 
 	if (!hba || test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) {
 		rc = -EINVAL;
-		goto check_busy;
+		goto nohba;
 	}
 
 	cnic = hba->cnic;
+	mutex_lock(&hba->net_dev_lock);
 	ep = bnx2i_alloc_ep(hba);
 	if (!ep) {
 		rc = -ENOMEM;
@@ -1676,7 +1736,6 @@
 	}
 	bnx2i_ep = ep->dd_data;
 
-	mutex_lock(&hba->net_dev_lock);
 	if (bnx2i_adapter_ready(hba)) {
 		rc = -EPERM;
 		goto net_if_down;
@@ -1754,15 +1813,19 @@
 		goto conn_failed;
 	} else
 		rc = cnic->cm_connect(bnx2i_ep->cm_sk, &saddr);
-
 	if (rc)
 		goto release_ep;
 
+	bnx2i_ep_active_list_add(hba, bnx2i_ep);
+
 	if (bnx2i_map_ep_dbell_regs(bnx2i_ep))
-		goto release_ep;
+		goto del_active_ep;
+
 	mutex_unlock(&hba->net_dev_lock);
 	return ep;
 
+del_active_ep:
+	bnx2i_ep_active_list_del(hba, bnx2i_ep);
 release_ep:
 	if (bnx2i_tear_down_conn(hba, bnx2i_ep)) {
 		mutex_unlock(&hba->net_dev_lock);
@@ -1774,8 +1837,9 @@
 	bnx2i_free_qp_resc(hba, bnx2i_ep);
 qp_resc_err:
 	bnx2i_free_ep(ep);
-	mutex_unlock(&hba->net_dev_lock);
 check_busy:
+	mutex_unlock(&hba->net_dev_lock);
+nohba:
 	bnx2i_unreg_dev_all();
 	return ERR_PTR(rc);
 }
@@ -1846,6 +1910,8 @@
 	case EP_STATE_ULP_UPDATE_START:
 	case EP_STATE_ULP_UPDATE_COMPL:
 	case EP_STATE_TCP_FIN_RCVD:
+	case EP_STATE_LOGOUT_SENT:
+	case EP_STATE_LOGOUT_RESP_RCVD:
 	case EP_STATE_ULP_UPDATE_FAILED:
 		ret = 1;
 		break;
@@ -1866,9 +1932,96 @@
 }
 
 
+/*
+ * bnx2i_hw_ep_disconnect - executes TCP connection teardown process in the hw
+ * @ep:		TCP connection (bnx2i endpoint) handle
+ *
+ * executes  TCP connection teardown process
+ */
+int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
+{
+	struct bnx2i_hba *hba = bnx2i_ep->hba;
+	struct cnic_dev *cnic;
+	struct iscsi_session *session = NULL;
+	struct iscsi_conn *conn = NULL;
+	int ret = 0;
+	int close = 0;
+	int close_ret = 0;
+
+	if (!hba)
+		return 0;
+
+	cnic = hba->cnic;
+	if (!cnic)
+		return 0;
+
+	if (!bnx2i_ep_tcp_conn_active(bnx2i_ep))
+		goto destroy_conn;
+
+	if (bnx2i_ep->conn) {
+		conn = bnx2i_ep->conn->cls_conn->dd_data;
+		session = conn->session;
+	}
+
+	init_timer(&bnx2i_ep->ofld_timer);
+	bnx2i_ep->ofld_timer.expires = hba->conn_teardown_tmo + jiffies;
+	bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
+	bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
+	add_timer(&bnx2i_ep->ofld_timer);
+
+	if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic))
+		goto out;
+
+	if (session) {
+		spin_lock_bh(&session->lock);
+		if (bnx2i_ep->state != EP_STATE_TCP_FIN_RCVD) {
+			if (session->state == ISCSI_STATE_LOGGING_OUT) {
+				if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) {
+					/* Logout sent, but no resp */
+					printk(KERN_ALERT "bnx2i - WARNING "
+						"logout response was not "
+						"received!\n");
+				} else if (bnx2i_ep->state ==
+					   EP_STATE_LOGOUT_RESP_RCVD)
+					close = 1;
+			}
+		} else
+			close = 1;
+
+		spin_unlock_bh(&session->lock);
+	}
+
+	bnx2i_ep->state = EP_STATE_DISCONN_START;
+
+	if (close)
+		close_ret = cnic->cm_close(bnx2i_ep->cm_sk);
+	else
+		close_ret = cnic->cm_abort(bnx2i_ep->cm_sk);
+
+	if (close_ret)
+		bnx2i_ep->state = EP_STATE_DISCONN_COMPL;
+
+	/* wait for option-2 conn teardown */
+	wait_event_interruptible(bnx2i_ep->ofld_wait,
+				 bnx2i_ep->state != EP_STATE_DISCONN_START);
+
+	if (signal_pending(current))
+		flush_signals(current);
+	del_timer_sync(&bnx2i_ep->ofld_timer);
+
+destroy_conn:
+	bnx2i_ep_active_list_del(hba, bnx2i_ep);
+	if (bnx2i_tear_down_conn(hba, bnx2i_ep))
+		ret = -EINVAL;
+out:
+	bnx2i_ep->state = EP_STATE_IDLE;
+	return ret;
+}
+
+
 /**
  * bnx2i_ep_disconnect - executes TCP connection teardown process
- * @ep:		TCP connection (endpoint) handle
+ * @ep:		TCP connection (iscsi endpoint) handle
  *
  * executes  TCP connection teardown process
  */
@@ -1876,9 +2029,7 @@
 {
 	struct bnx2i_endpoint *bnx2i_ep;
 	struct bnx2i_conn *bnx2i_conn = NULL;
-	struct iscsi_session *session = NULL;
-	struct iscsi_conn *conn;
-	struct cnic_dev *cnic;
+	struct iscsi_conn *conn = NULL;
 	struct bnx2i_hba *hba;
 
 	bnx2i_ep = ep->dd_data;
@@ -1894,72 +2045,34 @@
 	if (bnx2i_ep->conn) {
 		bnx2i_conn = bnx2i_ep->conn;
 		conn = bnx2i_conn->cls_conn->dd_data;
-		session = conn->session;
-
 		iscsi_suspend_queue(conn);
 	}
-
 	hba = bnx2i_ep->hba;
-	if (bnx2i_ep->state == EP_STATE_IDLE)
-		goto return_bnx2i_ep;
-	cnic = hba->cnic;
 
 	mutex_lock(&hba->net_dev_lock);
 
+	if (bnx2i_ep->state == EP_STATE_IDLE)
+		goto return_bnx2i_ep;
+
 	if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
 		goto free_resc;
+
 	if (bnx2i_ep->hba_age != hba->age)
 		goto free_resc;
 
-	if (!bnx2i_ep_tcp_conn_active(bnx2i_ep))
-		goto destory_conn;
-
-	bnx2i_ep->state = EP_STATE_DISCONN_START;
-
-	init_timer(&bnx2i_ep->ofld_timer);
-	bnx2i_ep->ofld_timer.expires = 10*HZ + jiffies;
-	bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
-	bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
-	add_timer(&bnx2i_ep->ofld_timer);
-
-	if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
-		int close = 0;
-
-		if (session) {
-			spin_lock_bh(&session->lock);
-			if (session->state == ISCSI_STATE_LOGGING_OUT)
-				close = 1;
-			spin_unlock_bh(&session->lock);
-		}
-		if (close)
-			cnic->cm_close(bnx2i_ep->cm_sk);
-		else
-			cnic->cm_abort(bnx2i_ep->cm_sk);
-	} else
-		goto free_resc;
-
-	/* wait for option-2 conn teardown */
-	wait_event_interruptible(bnx2i_ep->ofld_wait,
-				 bnx2i_ep->state != EP_STATE_DISCONN_START);
-
-	if (signal_pending(current))
-		flush_signals(current);
-	del_timer_sync(&bnx2i_ep->ofld_timer);
-
-destory_conn:
-	if (bnx2i_tear_down_conn(hba, bnx2i_ep)) {
+	/* Do all chip cleanup here */
+	if (bnx2i_hw_ep_disconnect(bnx2i_ep)) {
 		mutex_unlock(&hba->net_dev_lock);
 		return;
 	}
 free_resc:
-	mutex_unlock(&hba->net_dev_lock);
 	bnx2i_free_qp_resc(hba, bnx2i_ep);
 return_bnx2i_ep:
 	if (bnx2i_conn)
 		bnx2i_conn->ep = NULL;
 
 	bnx2i_free_ep(ep);
-
+	mutex_unlock(&hba->net_dev_lock);
 	if (!hba->ofld_conns_active)
 		bnx2i_unreg_dev_all();
 
@@ -2038,7 +2151,8 @@
 				  ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
 				  ISCSI_PING_TMO | ISCSI_RECV_TMO |
 				  ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
-	.host_param_mask	= ISCSI_HOST_HWADDRESS | ISCSI_HOST_NETDEV_NAME,
+	.host_param_mask	= ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
+				  ISCSI_HOST_NETDEV_NAME,
 	.create_session		= bnx2i_session_create,
 	.destroy_session	= bnx2i_session_destroy,
 	.create_conn		= bnx2i_conn_create,
diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.c b/drivers/scsi/cxgb3i/cxgb3i_ddp.c
index b58d913..be0e230 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_ddp.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.c
@@ -499,6 +499,7 @@
 	/* set up ulp submode and page size */
 	req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));
 	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+	req->wr.wr_lo = 0;
 	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
 	req->reply = V_NO_REPLY(reply ? 0 : 1);
 	req->cpu_idx = 0;
@@ -564,6 +565,7 @@
 	/* set up ulp submode and page size */
 	req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));
 	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+	req->wr.wr_lo = 0;
 	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
 	req->reply = V_NO_REPLY(reply ? 0 : 1);
 	req->cpu_idx = 0;
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c
index a175be9..3ee13cf 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_offload.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c
@@ -264,6 +264,7 @@
 	skb->priority = CPL_PRIORITY_SETUP;
 	req = (struct cpl_act_open_req *)__skb_put(skb, sizeof(*req));
 	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+	req->wr.wr_lo = 0;
 	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, atid));
 	req->local_port = c3cn->saddr.sin_port;
 	req->peer_port = c3cn->daddr.sin_port;
@@ -273,6 +274,7 @@
 			   V_TX_CHANNEL(e->smt_idx));
 	req->opt0l = htonl(calc_opt0l(c3cn));
 	req->params = 0;
+	req->opt2 = 0;
 }
 
 static void fail_act_open(struct s3_conn *c3cn, int errno)
@@ -379,6 +381,7 @@
 
 	c3cn->cpl_abort_req = NULL;
 	req = (struct cpl_abort_req *)skb->head;
+	memset(req, 0, sizeof(*req));
 
 	skb->priority = CPL_PRIORITY_DATA;
 	set_arp_failure_handler(skb, abort_arp_failure);
@@ -406,6 +409,7 @@
 	c3cn->cpl_abort_rpl = NULL;
 
 	skb->priority = CPL_PRIORITY_DATA;
+	memset(rpl, 0, sizeof(*rpl));
 	rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));
 	rpl->wr.wr_lo = htonl(V_WR_TID(c3cn->tid));
 	OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, c3cn->tid));
@@ -430,6 +434,7 @@
 
 	req = (struct cpl_rx_data_ack *)__skb_put(skb, sizeof(*req));
 	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+	req->wr.wr_lo = 0;
 	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, c3cn->tid));
 	req->credit_dack = htonl(dack | V_RX_CREDITS(credits));
 	skb->priority = CPL_PRIORITY_ACK;
@@ -1587,7 +1592,7 @@
 
 	err = ip_route_output_key(dev ? dev_net(dev) : &init_net, &rt, &fl);
 	if (!err)
-		return (&rt->u.dst)->dev;
+		return (&rt->dst)->dev;
 
 	return NULL;
 }
@@ -1649,7 +1654,7 @@
 		c3cn->saddr.sin_addr.s_addr = rt->rt_src;
 
 	/* now commit destination to connection */
-	c3cn->dst_cache = &rt->u.dst;
+	c3cn->dst_cache = &rt->dst;
 
 	/* try to establish an offloaded connection */
 	dev = cxgb3_egress_dev(c3cn->dst_cache->dev, c3cn, 0);
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 5b683e4..b9bcfa4 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -768,6 +768,7 @@
 	{"DELL", "MD3000i"},
 	{"DELL", "MD32xx"},
 	{"DELL", "MD32xxi"},
+	{"DELL", "MD36xxi"},
 	{"LSI", "INF-01-00"},
 	{"ENGENIO", "INF-01-00"},
 	{"STK", "FLEXLINE 380"},
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index b0c576f..ffc1edf 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -1290,7 +1290,7 @@
 	ulong flags = 0;
 	struct adpt_i2o_post_wait_data *p1, *p2;
 	struct adpt_i2o_post_wait_data *wait_data =
-		kmalloc(sizeof(struct adpt_i2o_post_wait_data),GFP_KERNEL);
+		kmalloc(sizeof(struct adpt_i2o_post_wait_data), GFP_ATOMIC);
 	DECLARE_WAITQUEUE(wait, current);
 
 	if (!wait_data)
@@ -2640,6 +2640,13 @@
 				continue;
 			}
 			bus_no = buf[0]>>16;
+			if (bus_no >= MAX_CHANNEL) {	/* Something wrong skip it */
+				printk(KERN_WARNING
+					"%s: Channel number %d out of range\n",
+					pHba->name, bus_no);
+				continue;
+			}
+
 			scsi_id = buf[1];
 			scsi_lun = (buf[2]>>8 )&0xff;
 			pDev = pHba->channel[bus_no].device[scsi_id];
@@ -2651,7 +2658,8 @@
 				pDev = pDev->next_lun;
 			}
 			if(!pDev ) { // Something new add it
-				d = kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
+				d = kmalloc(sizeof(struct i2o_device),
+					    GFP_ATOMIC);
 				if(d==NULL)
 				{
 					printk(KERN_CRIT "Out of memory for I2O device data.\n");
@@ -2667,13 +2675,11 @@
 				adpt_i2o_report_hba_unit(pHba, d);
 				adpt_i2o_install_device(pHba, d);
 	
-				if(bus_no >= MAX_CHANNEL) {	// Something wrong skip it
-					printk(KERN_WARNING"%s: Channel number %d out of range \n", pHba->name, bus_no);
-					continue;
-				}
 				pDev = pHba->channel[bus_no].device[scsi_id];	
 				if( pDev == NULL){
-					pDev =  kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
+					pDev =
+					  kzalloc(sizeof(struct adpt_device),
+						  GFP_ATOMIC);
 					if(pDev == NULL) {
 						return -ENOMEM;
 					}
@@ -2682,7 +2688,9 @@
 					while (pDev->next_lun) {
 						pDev = pDev->next_lun;
 					}
-					pDev = pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
+					pDev = pDev->next_lun =
+					  kzalloc(sizeof(struct adpt_device),
+						  GFP_ATOMIC);
 					if(pDev == NULL) {
 						return -ENOMEM;
 					}
@@ -3127,7 +3135,7 @@
 		if (pHba->lct == NULL) {
 			pHba->lct = dma_alloc_coherent(&pHba->pDev->dev,
 					pHba->lct_size, &pHba->lct_pa,
-					GFP_KERNEL);
+					GFP_ATOMIC);
 			if(pHba->lct == NULL) {
 				printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
 					pHba->name);
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index fe568ef..844d618 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -117,9 +117,14 @@
 
 static void fcoe_get_lesb(struct fc_lport *, struct fc_els_lesb *);
 
-module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR);
+module_param_call(create, fcoe_create, NULL, (void *)FIP_MODE_AUTO, S_IWUSR);
 __MODULE_PARM_TYPE(create, "string");
 MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface");
+module_param_call(create_vn2vn, fcoe_create, NULL,
+		  (void *)FIP_MODE_VN2VN, S_IWUSR);
+__MODULE_PARM_TYPE(create_vn2vn, "string");
+MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance "
+		 "on an Ethernet interface");
 module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR);
 __MODULE_PARM_TYPE(destroy, "string");
 MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface");
@@ -315,7 +320,11 @@
 	dev_uc_add(netdev, flogi_maddr);
 	if (fip->spma)
 		dev_uc_add(netdev, fip->ctl_src_addr);
-	dev_mc_add(netdev, FIP_ALL_ENODE_MACS);
+	if (fip->mode == FIP_MODE_VN2VN) {
+		dev_mc_add(netdev, FIP_ALL_VN2VN_MACS);
+		dev_mc_add(netdev, FIP_ALL_P2P_MACS);
+	} else
+		dev_mc_add(netdev, FIP_ALL_ENODE_MACS);
 
 	/*
 	 * setup the receive function from ethernet driver
@@ -337,10 +346,12 @@
 /**
  * fcoe_interface_create() - Create a FCoE interface on a net device
  * @netdev: The net device to create the FCoE interface on
+ * @fip_mode: The mode to use for FIP
  *
  * Returns: pointer to a struct fcoe_interface or NULL on error
  */
-static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev)
+static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
+						    enum fip_state fip_mode)
 {
 	struct fcoe_interface *fcoe;
 	int err;
@@ -357,7 +368,7 @@
 	/*
 	 * Initialize FIP.
 	 */
-	fcoe_ctlr_init(&fcoe->ctlr);
+	fcoe_ctlr_init(&fcoe->ctlr, fip_mode);
 	fcoe->ctlr.send = fcoe_fip_send;
 	fcoe->ctlr.update_mac = fcoe_update_src_mac;
 	fcoe->ctlr.get_src_addr = fcoe_get_src_mac;
@@ -401,7 +412,11 @@
 	dev_uc_del(netdev, flogi_maddr);
 	if (fip->spma)
 		dev_uc_del(netdev, fip->ctl_src_addr);
-	dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
+	if (fip->mode == FIP_MODE_VN2VN) {
+		dev_mc_del(netdev, FIP_ALL_VN2VN_MACS);
+		dev_mc_del(netdev, FIP_ALL_P2P_MACS);
+	} else
+		dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
 
 	/* Tell the LLD we are done w/ FCoE */
 	ops = netdev->netdev_ops;
@@ -574,6 +589,50 @@
 }
 
 /**
+ * fcoe_netdev_features_change - Updates the lport's offload flags based
+ * on the LLD netdev's FCoE feature flags
+ */
+static void fcoe_netdev_features_change(struct fc_lport *lport,
+					struct net_device *netdev)
+{
+	mutex_lock(&lport->lp_mutex);
+
+	if (netdev->features & NETIF_F_SG)
+		lport->sg_supp = 1;
+	else
+		lport->sg_supp = 0;
+
+	if (netdev->features & NETIF_F_FCOE_CRC) {
+		lport->crc_offload = 1;
+		FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n");
+	} else {
+		lport->crc_offload = 0;
+	}
+
+	if (netdev->features & NETIF_F_FSO) {
+		lport->seq_offload = 1;
+		lport->lso_max = netdev->gso_max_size;
+		FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n",
+				lport->lso_max);
+	} else {
+		lport->seq_offload = 0;
+		lport->lso_max = 0;
+	}
+
+	if (netdev->fcoe_ddp_xid) {
+		lport->lro_enabled = 1;
+		lport->lro_xid = netdev->fcoe_ddp_xid;
+		FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n",
+				lport->lro_xid);
+	} else {
+		lport->lro_enabled = 0;
+		lport->lro_xid = 0;
+	}
+
+	mutex_unlock(&lport->lp_mutex);
+}
+
+/**
  * fcoe_netdev_config() - Set up net devive for SW FCoE
  * @lport:  The local port that is associated with the net device
  * @netdev: The associated net device
@@ -588,7 +647,6 @@
 	u64 wwnn, wwpn;
 	struct fcoe_interface *fcoe;
 	struct fcoe_port *port;
-	int vid = 0;
 
 	/* Setup lport private data to point to fcoe softc */
 	port = lport_priv(lport);
@@ -609,25 +667,8 @@
 		return -EINVAL;
 
 	/* offload features support */
-	if (netdev->features & NETIF_F_SG)
-		lport->sg_supp = 1;
+	fcoe_netdev_features_change(lport, netdev);
 
-	if (netdev->features & NETIF_F_FCOE_CRC) {
-		lport->crc_offload = 1;
-		FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n");
-	}
-	if (netdev->features & NETIF_F_FSO) {
-		lport->seq_offload = 1;
-		lport->lso_max = netdev->gso_max_size;
-		FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n",
-				lport->lso_max);
-	}
-	if (netdev->fcoe_ddp_xid) {
-		lport->lro_enabled = 1;
-		lport->lro_xid = netdev->fcoe_ddp_xid;
-		FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n",
-				lport->lro_xid);
-	}
 	skb_queue_head_init(&port->fcoe_pending_queue);
 	port->fcoe_pending_queue_active = 0;
 	setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport);
@@ -635,20 +676,12 @@
 	fcoe_link_speed_update(lport);
 
 	if (!lport->vport) {
-		/*
-		 * Use NAA 1&2 (FC-FS Rev. 2.0, Sec. 15) to generate WWNN/WWPN:
-		 * For WWNN, we use NAA 1 w/ bit 27-16 of word 0 as 0.
-		 * For WWPN, we use NAA 2 w/ bit 27-16 of word 0 from VLAN ID
-		 */
-		if (netdev->priv_flags & IFF_802_1Q_VLAN)
-			vid = vlan_dev_vlan_id(netdev);
-
 		if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN))
 			wwnn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, 1, 0);
 		fc_set_wwnn(lport, wwnn);
 		if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN))
 			wwpn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr,
-						 2, vid);
+						 2, 0);
 		fc_set_wwpn(lport, wwpn);
 	}
 
@@ -967,7 +1000,7 @@
 	}
 
 	/* Initialize the library */
-	rc = fcoe_libfc_config(lport, &fcoe_libfc_fcn_templ);
+	rc = fcoe_libfc_config(lport, &fcoe->ctlr, &fcoe_libfc_fcn_templ, 1);
 	if (rc) {
 		FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the "
 				"interface\n");
@@ -1210,6 +1243,8 @@
 	struct fcoe_interface *fcoe;
 	struct fc_frame_header *fh;
 	struct fcoe_percpu_s *fps;
+	struct fcoe_port *port;
+	struct ethhdr *eh;
 	unsigned int cpu;
 
 	fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type);
@@ -1227,9 +1262,21 @@
 			skb_tail_pointer(skb), skb_end_pointer(skb),
 			skb->csum, skb->dev ? skb->dev->name : "<NULL>");
 
-	/* check for FCOE packet type */
-	if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) {
-		FCOE_NETDEV_DBG(netdev, "Wrong FC type frame");
+	/* check for mac addresses */
+	eh = eth_hdr(skb);
+	port = lport_priv(lport);
+	if (compare_ether_addr(eh->h_dest, port->data_src_addr) &&
+	    compare_ether_addr(eh->h_dest, fcoe->ctlr.ctl_src_addr) &&
+	    compare_ether_addr(eh->h_dest, (u8[6])FC_FCOE_FLOGI_MAC)) {
+		FCOE_NETDEV_DBG(netdev, "wrong destination mac address:%pM\n",
+				eh->h_dest);
+		goto err;
+	}
+
+	if (is_fip_mode(&fcoe->ctlr) &&
+	    compare_ether_addr(eh->h_source, fcoe->ctlr.dest_addr)) {
+		FCOE_NETDEV_DBG(netdev, "wrong source mac address:%pM\n",
+				eh->h_source);
 		goto err;
 	}
 
@@ -1512,11 +1559,9 @@
 	/* fill up mac and fcoe headers */
 	eh = eth_hdr(skb);
 	eh->h_proto = htons(ETH_P_FCOE);
+	memcpy(eh->h_dest, fcoe->ctlr.dest_addr, ETH_ALEN);
 	if (fcoe->ctlr.map_dest)
-		fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id);
-	else
-		/* insert GW address */
-		memcpy(eh->h_dest, fcoe->ctlr.dest_addr, ETH_ALEN);
+		memcpy(eh->h_dest + 3, fh->fh_d_id, 3);
 
 	if (unlikely(fcoe->ctlr.flogi_oxid != FC_XID_UNKNOWN))
 		memcpy(eh->h_source, fcoe->ctlr.ctl_src_addr, ETH_ALEN);
@@ -1834,6 +1879,9 @@
 		schedule_work(&port->destroy_work);
 		goto out;
 		break;
+	case NETDEV_FEAT_CHANGE:
+		fcoe_netdev_features_change(lport, netdev);
+		break;
 	default:
 		FCOE_NETDEV_DBG(netdev, "Unknown event %ld "
 				"from netdev netlink\n", event);
@@ -1918,8 +1966,8 @@
 	rtnl_unlock();
 
 	if (fcoe) {
-		fc_fabric_logoff(fcoe->ctlr.lp);
 		fcoe_ctlr_link_down(&fcoe->ctlr);
+		fcoe_clean_pending_queue(fcoe->ctlr.lp);
 	} else
 		rc = -ENODEV;
 
@@ -1972,12 +2020,10 @@
 	fcoe = fcoe_hostlist_lookup_port(netdev);
 	rtnl_unlock();
 
-	if (fcoe) {
-		if (!fcoe_link_ok(fcoe->ctlr.lp))
-			fcoe_ctlr_link_up(&fcoe->ctlr);
-		rc = fc_fabric_login(fcoe->ctlr.lp);
-	} else
+	if (!fcoe)
 		rc = -ENODEV;
+	else if (!fcoe_link_ok(fcoe->ctlr.lp))
+		fcoe_ctlr_link_up(&fcoe->ctlr);
 
 	dev_put(netdev);
 out_nodev:
@@ -2031,8 +2077,8 @@
 		rc = -ENODEV;
 		goto out_putdev;
 	}
-	list_del(&fcoe->list);
 	fcoe_interface_cleanup(fcoe);
+	list_del(&fcoe->list);
 	/* RTNL mutex is dropped by fcoe_if_destroy */
 	fcoe_if_destroy(fcoe->ctlr.lp);
 
@@ -2070,6 +2116,7 @@
  */
 static int fcoe_create(const char *buffer, struct kernel_param *kp)
 {
+	enum fip_state fip_mode = (enum fip_state)(long)kp->arg;
 	int rc;
 	struct fcoe_interface *fcoe;
 	struct fc_lport *lport;
@@ -2111,7 +2158,7 @@
 		goto out_putdev;
 	}
 
-	fcoe = fcoe_interface_create(netdev);
+	fcoe = fcoe_interface_create(netdev, fip_mode);
 	if (!fcoe) {
 		rc = -ENOMEM;
 		goto out_putdev;
@@ -2521,6 +2568,8 @@
 	switch (op) {
 	case ELS_FLOGI:
 	case ELS_FDISC:
+		if (lport->point_to_multipoint)
+			break;
 		return fc_elsct_send(lport, did, fp, op, fcoe_flogi_resp,
 				     fip, timeout);
 	case ELS_LOGO:
@@ -2653,6 +2702,7 @@
 	u32 lfc, vlfc, mdac;
 	struct fcoe_dev_stats *devst;
 	struct fcoe_fc_els_lesb *lesb;
+	struct rtnl_link_stats64 temp;
 	struct net_device *netdev = fcoe_netdev(lport);
 
 	lfc = 0;
@@ -2669,7 +2719,7 @@
 	lesb->lesb_link_fail = htonl(lfc);
 	lesb->lesb_vlink_fail = htonl(vlfc);
 	lesb->lesb_miss_fka = htonl(mdac);
-	lesb->lesb_fcs_error = htonl(dev_get_stats(netdev)->rx_crc_errors);
+	lesb->lesb_fcs_error = htonl(dev_get_stats(netdev, &temp)->rx_crc_errors);
 }
 
 /**
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index 50aaa4b..aa503d8 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -39,6 +39,7 @@
 #include <scsi/fc/fc_fip.h>
 #include <scsi/fc/fc_encaps.h>
 #include <scsi/fc/fc_fcoe.h>
+#include <scsi/fc/fc_fcp.h>
 
 #include <scsi/libfc.h>
 #include <scsi/libfcoe.h>
@@ -54,7 +55,15 @@
 static void fcoe_ctlr_timer_work(struct work_struct *);
 static void fcoe_ctlr_recv_work(struct work_struct *);
 
+static void fcoe_ctlr_vn_start(struct fcoe_ctlr *);
+static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *, struct sk_buff *);
+static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *);
+static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *, u32, u8 *);
+
 static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS;
+static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS;
+static u8 fcoe_all_vn2vn[ETH_ALEN] = FIP_ALL_VN2VN_MACS;
+static u8 fcoe_all_p2p[ETH_ALEN] = FIP_ALL_P2P_MACS;
 
 unsigned int libfcoe_debug_logging;
 module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR);
@@ -80,6 +89,45 @@
 			      printk(KERN_INFO "host%d: fip: " fmt, 	\
 				     (fip)->lp->host->host_no, ##args);)
 
+static const char *fcoe_ctlr_states[] = {
+	[FIP_ST_DISABLED] =	"DISABLED",
+	[FIP_ST_LINK_WAIT] =	"LINK_WAIT",
+	[FIP_ST_AUTO] =		"AUTO",
+	[FIP_ST_NON_FIP] =	"NON_FIP",
+	[FIP_ST_ENABLED] =	"ENABLED",
+	[FIP_ST_VNMP_START] =	"VNMP_START",
+	[FIP_ST_VNMP_PROBE1] =	"VNMP_PROBE1",
+	[FIP_ST_VNMP_PROBE2] =	"VNMP_PROBE2",
+	[FIP_ST_VNMP_CLAIM] =	"VNMP_CLAIM",
+	[FIP_ST_VNMP_UP] =	"VNMP_UP",
+};
+
+static const char *fcoe_ctlr_state(enum fip_state state)
+{
+	const char *cp = "unknown";
+
+	if (state < ARRAY_SIZE(fcoe_ctlr_states))
+		cp = fcoe_ctlr_states[state];
+	if (!cp)
+		cp = "unknown";
+	return cp;
+}
+
+/**
+ * fcoe_ctlr_set_state() - Set and do debug printing for the new FIP state.
+ * @fip: The FCoE controller
+ * @state: The new state
+ */
+static void fcoe_ctlr_set_state(struct fcoe_ctlr *fip, enum fip_state state)
+{
+	if (state == fip->state)
+		return;
+	if (fip->lp)
+		LIBFCOE_FIP_DBG(fip, "state %s -> %s\n",
+			fcoe_ctlr_state(fip->state), fcoe_ctlr_state(state));
+	fip->state = state;
+}
+
 /**
  * fcoe_ctlr_mtu_valid() - Check if a FCF's MTU is valid
  * @fcf: The FCF to check
@@ -105,15 +153,29 @@
 }
 
 /**
+ * fcoe_ctlr_map_dest() - Set flag and OUI for mapping destination addresses
+ * @fip: The FCoE controller
+ */
+static void fcoe_ctlr_map_dest(struct fcoe_ctlr *fip)
+{
+	if (fip->mode == FIP_MODE_VN2VN)
+		hton24(fip->dest_addr, FIP_VN_FC_MAP);
+	else
+		hton24(fip->dest_addr, FIP_DEF_FC_MAP);
+	hton24(fip->dest_addr + 3, 0);
+	fip->map_dest = 1;
+}
+
+/**
  * fcoe_ctlr_init() - Initialize the FCoE Controller instance
  * @fip: The FCoE controller to initialize
  */
-void fcoe_ctlr_init(struct fcoe_ctlr *fip)
+void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode)
 {
-	fip->state = FIP_ST_LINK_WAIT;
-	fip->mode = FIP_ST_AUTO;
+	fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT);
+	fip->mode = mode;
 	INIT_LIST_HEAD(&fip->fcfs);
-	spin_lock_init(&fip->lock);
+	mutex_init(&fip->ctlr_mutex);
 	fip->flogi_oxid = FC_XID_UNKNOWN;
 	setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
 	INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work);
@@ -159,10 +221,10 @@
 	cancel_work_sync(&fip->recv_work);
 	skb_queue_purge(&fip->fip_recv_list);
 
-	spin_lock_bh(&fip->lock);
-	fip->state = FIP_ST_DISABLED;
+	mutex_lock(&fip->ctlr_mutex);
+	fcoe_ctlr_set_state(fip, FIP_ST_DISABLED);
 	fcoe_ctlr_reset_fcfs(fip);
-	spin_unlock_bh(&fip->lock);
+	mutex_unlock(&fip->ctlr_mutex);
 	del_timer_sync(&fip->timer);
 	cancel_work_sync(&fip->timer_work);
 }
@@ -255,19 +317,33 @@
  */
 void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
 {
-	spin_lock_bh(&fip->lock);
+	mutex_lock(&fip->ctlr_mutex);
 	if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) {
-		spin_unlock_bh(&fip->lock);
+		mutex_unlock(&fip->ctlr_mutex);
 		fc_linkup(fip->lp);
 	} else if (fip->state == FIP_ST_LINK_WAIT) {
-		fip->state = fip->mode;
-		spin_unlock_bh(&fip->lock);
-		if (fip->state == FIP_ST_AUTO)
+		fcoe_ctlr_set_state(fip, fip->mode);
+		switch (fip->mode) {
+		default:
+			LIBFCOE_FIP_DBG(fip, "invalid mode %d\n", fip->mode);
+			/* fall-through */
+		case FIP_MODE_AUTO:
 			LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n");
-		fc_linkup(fip->lp);
-		fcoe_ctlr_solicit(fip, NULL);
+			/* fall-through */
+		case FIP_MODE_FABRIC:
+		case FIP_MODE_NON_FIP:
+			mutex_unlock(&fip->ctlr_mutex);
+			fc_linkup(fip->lp);
+			fcoe_ctlr_solicit(fip, NULL);
+			break;
+		case FIP_MODE_VN2VN:
+			fcoe_ctlr_vn_start(fip);
+			mutex_unlock(&fip->ctlr_mutex);
+			fc_linkup(fip->lp);
+			break;
+		}
 	} else
-		spin_unlock_bh(&fip->lock);
+		mutex_unlock(&fip->ctlr_mutex);
 }
 EXPORT_SYMBOL(fcoe_ctlr_link_up);
 
@@ -283,7 +359,7 @@
 	fip->port_ka_time = 0;
 	fip->sol_time = 0;
 	fip->flogi_oxid = FC_XID_UNKNOWN;
-	fip->map_dest = 0;
+	fcoe_ctlr_map_dest(fip);
 }
 
 /**
@@ -300,11 +376,11 @@
 	int link_dropped;
 
 	LIBFCOE_FIP_DBG(fip, "link down.\n");
-	spin_lock_bh(&fip->lock);
+	mutex_lock(&fip->ctlr_mutex);
 	fcoe_ctlr_reset(fip);
 	link_dropped = fip->state != FIP_ST_LINK_WAIT;
-	fip->state = FIP_ST_LINK_WAIT;
-	spin_unlock_bh(&fip->lock);
+	fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT);
+	mutex_unlock(&fip->ctlr_mutex);
 
 	if (link_dropped)
 		fc_linkdown(fip->lp);
@@ -343,7 +419,7 @@
 
 	fcf = fip->sel_fcf;
 	lp = fip->lp;
-	if (!fcf || !lp->port_id)
+	if (!fcf || (ports && !lp->port_id))
 		return;
 
 	len = sizeof(*kal) + ports * sizeof(*vn);
@@ -389,6 +465,7 @@
  * @fip:   The FCoE controller for the ELS frame
  * @dtype: The FIP descriptor type for the frame
  * @skb:   The FCoE ELS frame including FC header but no FCoE headers
+ * @d_id:  The destination port ID.
  *
  * Returns non-zero error code on failure.
  *
@@ -399,58 +476,75 @@
  * Ethernet header.  The tailroom is for the FIP MAC descriptor.
  */
 static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
-			    u8 dtype, struct sk_buff *skb)
+			    u8 dtype, struct sk_buff *skb, u32 d_id)
 {
 	struct fip_encaps_head {
 		struct ethhdr eth;
 		struct fip_header fip;
 		struct fip_encaps encaps;
 	} __attribute__((packed)) *cap;
+	struct fc_frame_header *fh;
 	struct fip_mac_desc *mac;
 	struct fcoe_fcf *fcf;
 	size_t dlen;
 	u16 fip_flags;
+	u8 op;
 
-	fcf = fip->sel_fcf;
-	if (!fcf)
-		return -ENODEV;
-
-	/* set flags according to both FCF and lport's capability on SPMA */
-	fip_flags = fcf->flags;
-	fip_flags &= fip->spma ? FIP_FL_SPMA | FIP_FL_FPMA : FIP_FL_FPMA;
-	if (!fip_flags)
-		return -ENODEV;
-
+	fh = (struct fc_frame_header *)skb->data;
+	op = *(u8 *)(fh + 1);
 	dlen = sizeof(struct fip_encaps) + skb->len;	/* len before push */
 	cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap));
-
 	memset(cap, 0, sizeof(*cap));
-	memcpy(cap->eth.h_dest, fcf->fcf_mac, ETH_ALEN);
+
+	if (lport->point_to_multipoint) {
+		if (fcoe_ctlr_vn_lookup(fip, d_id, cap->eth.h_dest))
+			return -ENODEV;
+		fip_flags = 0;
+	} else {
+		fcf = fip->sel_fcf;
+		if (!fcf)
+			return -ENODEV;
+		fip_flags = fcf->flags;
+		fip_flags &= fip->spma ? FIP_FL_SPMA | FIP_FL_FPMA :
+					 FIP_FL_FPMA;
+		if (!fip_flags)
+			return -ENODEV;
+		memcpy(cap->eth.h_dest, fcf->fcf_mac, ETH_ALEN);
+	}
 	memcpy(cap->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
 	cap->eth.h_proto = htons(ETH_P_FIP);
 
 	cap->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
 	cap->fip.fip_op = htons(FIP_OP_LS);
-	cap->fip.fip_subcode = FIP_SC_REQ;
-	cap->fip.fip_dl_len = htons((dlen + sizeof(*mac)) / FIP_BPW);
+	if (op == ELS_LS_ACC || op == ELS_LS_RJT)
+		cap->fip.fip_subcode = FIP_SC_REP;
+	else
+		cap->fip.fip_subcode = FIP_SC_REQ;
 	cap->fip.fip_flags = htons(fip_flags);
 
 	cap->encaps.fd_desc.fip_dtype = dtype;
 	cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW;
 
-	mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac));
-	memset(mac, 0, sizeof(*mac));
-	mac->fd_desc.fip_dtype = FIP_DT_MAC;
-	mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
-	if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) {
-		memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
-	} else if (fip_flags & FIP_FL_SPMA) {
-		LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n");
-		memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
-	} else {
-		LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n");
-		/* FPMA only FLOGI must leave the MAC desc set to all 0s */
+	if (op != ELS_LS_RJT) {
+		dlen += sizeof(*mac);
+		mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac));
+		memset(mac, 0, sizeof(*mac));
+		mac->fd_desc.fip_dtype = FIP_DT_MAC;
+		mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
+		if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) {
+			memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
+		} else if (fip->mode == FIP_MODE_VN2VN) {
+			hton24(mac->fd_mac, FIP_VN_FC_MAP);
+			hton24(mac->fd_mac + 3, fip->port_id);
+		} else if (fip_flags & FIP_FL_SPMA) {
+			LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n");
+			memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
+		} else {
+			LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n");
+			/* FPMA only FLOGI.  Must leave the MAC desc zeroed. */
+		}
 	}
+	cap->fip.fip_dl_len = htons(dlen / FIP_BPW);
 
 	skb->protocol = htons(ETH_P_FIP);
 	skb_reset_mac_header(skb);
@@ -469,19 +563,22 @@
  *
  * The caller must check that the length is a multiple of 4.
  * The SKB must have enough headroom (28 bytes) and tailroom (8 bytes).
+ * The the skb must also be an fc_frame.
  */
 int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
 		       struct sk_buff *skb)
 {
+	struct fc_frame *fp;
 	struct fc_frame_header *fh;
 	u16 old_xid;
 	u8 op;
 	u8 mac[ETH_ALEN];
 
+	fp = container_of(skb, struct fc_frame, skb);
 	fh = (struct fc_frame_header *)skb->data;
 	op = *(u8 *)(fh + 1);
 
-	if (op == ELS_FLOGI) {
+	if (op == ELS_FLOGI && fip->mode != FIP_MODE_VN2VN) {
 		old_xid = fip->flogi_oxid;
 		fip->flogi_oxid = ntohs(fh->fh_ox_id);
 		if (fip->state == FIP_ST_AUTO) {
@@ -490,18 +587,17 @@
 			fip->flogi_count++;
 			if (fip->flogi_count < 3)
 				goto drop;
-			fip->map_dest = 1;
+			fcoe_ctlr_map_dest(fip);
 			return 0;
 		}
 		if (fip->state == FIP_ST_NON_FIP)
-			fip->map_dest = 1;
+			fcoe_ctlr_map_dest(fip);
 	}
 
 	if (fip->state == FIP_ST_NON_FIP)
 		return 0;
-	if (!fip->sel_fcf)
+	if (!fip->sel_fcf && fip->mode != FIP_MODE_VN2VN)
 		goto drop;
-
 	switch (op) {
 	case ELS_FLOGI:
 		op = FIP_DT_FLOGI;
@@ -512,36 +608,49 @@
 		op = FIP_DT_FDISC;
 		break;
 	case ELS_LOGO:
-		if (fip->state != FIP_ST_ENABLED)
-			return 0;
-		if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI)
-			return 0;
+		if (fip->mode == FIP_MODE_VN2VN) {
+			if (fip->state != FIP_ST_VNMP_UP)
+				return -EINVAL;
+			if (ntoh24(fh->fh_d_id) == FC_FID_FLOGI)
+				return -EINVAL;
+		} else {
+			if (fip->state != FIP_ST_ENABLED)
+				return 0;
+			if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI)
+				return 0;
+		}
 		op = FIP_DT_LOGO;
 		break;
 	case ELS_LS_ACC:
-		if (fip->flogi_oxid == FC_XID_UNKNOWN)
-			return 0;
-		if (!ntoh24(fh->fh_s_id))
-			return 0;
-		if (fip->state == FIP_ST_AUTO)
-			return 0;
 		/*
-		 * Here we must've gotten an SID by accepting an FLOGI
+		 * If non-FIP, we may have gotten an SID by accepting an FLOGI
 		 * from a point-to-point connection.  Switch to using
 		 * the source mac based on the SID.  The destination
 		 * MAC in this case would have been set by receving the
 		 * FLOGI.
 		 */
-		fip->flogi_oxid = FC_XID_UNKNOWN;
-		fc_fcoe_set_mac(mac, fh->fh_d_id);
-		fip->update_mac(lport, mac);
+		if (fip->state == FIP_ST_NON_FIP) {
+			if (fip->flogi_oxid == FC_XID_UNKNOWN)
+				return 0;
+			fip->flogi_oxid = FC_XID_UNKNOWN;
+			fc_fcoe_set_mac(mac, fh->fh_d_id);
+			fip->update_mac(lport, mac);
+		}
+		/* fall through */
+	case ELS_LS_RJT:
+		op = fr_encaps(fp);
+		if (op)
+			break;
 		return 0;
 	default:
-		if (fip->state != FIP_ST_ENABLED)
+		if (fip->state != FIP_ST_ENABLED &&
+		    fip->state != FIP_ST_VNMP_UP)
 			goto drop;
 		return 0;
 	}
-	if (fcoe_ctlr_encaps(fip, lport, op, skb))
+	LIBFCOE_FIP_DBG(fip, "els_send op %u d_id %x\n",
+			op, ntoh24(fh->fh_d_id));
+	if (fcoe_ctlr_encaps(fip, lport, op, skb, ntoh24(fh->fh_d_id)))
 		goto drop;
 	fip->send(fip, skb);
 	return -EINPROGRESS;
@@ -557,60 +666,66 @@
  *
  * Called with lock held and preemption disabled.
  *
- * An FCF is considered old if we have missed three advertisements.
- * That is, there have been no valid advertisement from it for three
- * times its keep-alive period including fuzz.
+ * An FCF is considered old if we have missed two advertisements.
+ * That is, there have been no valid advertisement from it for 2.5
+ * times its keep-alive period.
  *
  * In addition, determine the time when an FCF selection can occur.
  *
  * Also, increment the MissDiscAdvCount when no advertisement is received
  * for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB).
+ *
+ * Returns the time in jiffies for the next call.
  */
-static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
+static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
 {
 	struct fcoe_fcf *fcf;
 	struct fcoe_fcf *next;
+	unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
+	unsigned long deadline;
 	unsigned long sel_time = 0;
-	unsigned long mda_time = 0;
 	struct fcoe_dev_stats *stats;
 
+	stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu());
+
 	list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
-		mda_time = fcf->fka_period + (fcf->fka_period >> 1);
-		if ((fip->sel_fcf == fcf) &&
-		    (time_after(jiffies, fcf->time + mda_time))) {
-			mod_timer(&fip->timer, jiffies + mda_time);
-			stats = per_cpu_ptr(fip->lp->dev_stats,
-					    smp_processor_id());
-			stats->MissDiscAdvCount++;
-			printk(KERN_INFO "libfcoe: host%d: Missing Discovery "
-			       "Advertisement for fab %16.16llx count %lld\n",
-			       fip->lp->host->host_no, fcf->fabric_name,
-			       stats->MissDiscAdvCount);
+		deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2;
+		if (fip->sel_fcf == fcf) {
+			if (time_after(jiffies, deadline)) {
+				stats->MissDiscAdvCount++;
+				printk(KERN_INFO "libfcoe: host%d: "
+				       "Missing Discovery Advertisement "
+				       "for fab %16.16llx count %lld\n",
+				       fip->lp->host->host_no, fcf->fabric_name,
+				       stats->MissDiscAdvCount);
+			} else if (time_after(next_timer, deadline))
+				next_timer = deadline;
 		}
-		if (time_after(jiffies, fcf->time + fcf->fka_period * 3 +
-			       msecs_to_jiffies(FIP_FCF_FUZZ * 3))) {
+
+		deadline += fcf->fka_period;
+		if (time_after_eq(jiffies, deadline)) {
 			if (fip->sel_fcf == fcf)
 				fip->sel_fcf = NULL;
 			list_del(&fcf->list);
 			WARN_ON(!fip->fcf_count);
 			fip->fcf_count--;
 			kfree(fcf);
-			stats = per_cpu_ptr(fip->lp->dev_stats,
-					    smp_processor_id());
 			stats->VLinkFailureCount++;
-		} else if (fcoe_ctlr_mtu_valid(fcf) &&
-			   (!sel_time || time_before(sel_time, fcf->time))) {
-			sel_time = fcf->time;
+		} else {
+			if (time_after(next_timer, deadline))
+				next_timer = deadline;
+			if (fcoe_ctlr_mtu_valid(fcf) &&
+			    (!sel_time || time_before(sel_time, fcf->time)))
+				sel_time = fcf->time;
 		}
 	}
-	if (sel_time) {
+	put_cpu();
+	if (sel_time && !fip->sel_fcf && !fip->sel_time) {
 		sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY);
 		fip->sel_time = sel_time;
-		if (time_before(sel_time, fip->timer.expires))
-			mod_timer(&fip->timer, sel_time);
-	} else {
-		fip->sel_time = 0;
 	}
+
+	return next_timer;
 }
 
 /**
@@ -633,6 +748,7 @@
 	unsigned long t;
 	size_t rlen;
 	size_t dlen;
+	u32 desc_mask;
 
 	memset(fcf, 0, sizeof(*fcf));
 	fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA);
@@ -640,6 +756,12 @@
 	fiph = (struct fip_header *)skb->data;
 	fcf->flags = ntohs(fiph->fip_flags);
 
+	/*
+	 * mask of required descriptors. validating each one clears its bit.
+	 */
+	desc_mask = BIT(FIP_DT_PRI) | BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
+			BIT(FIP_DT_FAB) | BIT(FIP_DT_FKA);
+
 	rlen = ntohs(fiph->fip_dl_len) * 4;
 	if (rlen + sizeof(*fiph) > skb->len)
 		return -EINVAL;
@@ -649,11 +771,19 @@
 		dlen = desc->fip_dlen * FIP_BPW;
 		if (dlen < sizeof(*desc) || dlen > rlen)
 			return -EINVAL;
+		/* Drop Adv if there are duplicate critical descriptors */
+		if ((desc->fip_dtype < 32) &&
+		    !(desc_mask & 1U << desc->fip_dtype)) {
+			LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
+					"Descriptors in FIP adv\n");
+			return -EINVAL;
+		}
 		switch (desc->fip_dtype) {
 		case FIP_DT_PRI:
 			if (dlen != sizeof(struct fip_pri_desc))
 				goto len_err;
 			fcf->pri = ((struct fip_pri_desc *)desc)->fd_pri;
+			desc_mask &= ~BIT(FIP_DT_PRI);
 			break;
 		case FIP_DT_MAC:
 			if (dlen != sizeof(struct fip_mac_desc))
@@ -662,16 +792,19 @@
 			       ((struct fip_mac_desc *)desc)->fd_mac,
 			       ETH_ALEN);
 			if (!is_valid_ether_addr(fcf->fcf_mac)) {
-				LIBFCOE_FIP_DBG(fip, "Invalid MAC address "
-						"in FIP adv\n");
+				LIBFCOE_FIP_DBG(fip,
+					"Invalid MAC addr %pM in FIP adv\n",
+					fcf->fcf_mac);
 				return -EINVAL;
 			}
+			desc_mask &= ~BIT(FIP_DT_MAC);
 			break;
 		case FIP_DT_NAME:
 			if (dlen != sizeof(struct fip_wwn_desc))
 				goto len_err;
 			wwn = (struct fip_wwn_desc *)desc;
 			fcf->switch_name = get_unaligned_be64(&wwn->fd_wwn);
+			desc_mask &= ~BIT(FIP_DT_NAME);
 			break;
 		case FIP_DT_FAB:
 			if (dlen != sizeof(struct fip_fab_desc))
@@ -680,6 +813,7 @@
 			fcf->fabric_name = get_unaligned_be64(&fab->fd_wwn);
 			fcf->vfid = ntohs(fab->fd_vfid);
 			fcf->fc_map = ntoh24(fab->fd_map);
+			desc_mask &= ~BIT(FIP_DT_FAB);
 			break;
 		case FIP_DT_FKA:
 			if (dlen != sizeof(struct fip_fka_desc))
@@ -690,6 +824,7 @@
 			t = ntohl(fka->fd_fka_period);
 			if (t >= FCOE_CTLR_MIN_FKA)
 				fcf->fka_period = msecs_to_jiffies(t);
+			desc_mask &= ~BIT(FIP_DT_FKA);
 			break;
 		case FIP_DT_MAP_OUI:
 		case FIP_DT_FCOE_SIZE:
@@ -703,15 +838,20 @@
 			/* standard says ignore unknown descriptors >= 128 */
 			if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
 				return -EINVAL;
-			continue;
+			break;
 		}
 		desc = (struct fip_desc *)((char *)desc + dlen);
 		rlen -= dlen;
 	}
 	if (!fcf->fc_map || (fcf->fc_map & 0x10000))
 		return -EINVAL;
-	if (!fcf->switch_name || !fcf->fabric_name)
+	if (!fcf->switch_name)
 		return -EINVAL;
+	if (desc_mask) {
+		LIBFCOE_FIP_DBG(fip, "adv missing descriptors mask %x\n",
+				desc_mask);
+		return -EINVAL;
+	}
 	return 0;
 
 len_err:
@@ -737,7 +877,7 @@
 	if (fcoe_ctlr_parse_adv(fip, skb, &new))
 		return;
 
-	spin_lock_bh(&fip->lock);
+	mutex_lock(&fip->ctlr_mutex);
 	first = list_empty(&fip->fcfs);
 	found = NULL;
 	list_for_each_entry(fcf, &fip->fcfs, list) {
@@ -762,18 +902,21 @@
 		list_add(&fcf->list, &fip->fcfs);
 	} else {
 		/*
-		 * Flags in advertisements are ignored once the FCF is
-		 * selected.  Flags in unsolicited advertisements are
-		 * ignored after a usable solicited advertisement
-		 * has been received.
+		 * Update the FCF's keep-alive descriptor flags.
+		 * Other flag changes from new advertisements are
+		 * ignored after a solicited advertisement is
+		 * received and the FCF is selectable (usable).
 		 */
-		if (fcf == fip->sel_fcf) {
+		fcf->fd_flags = new.fd_flags;
+		if (!fcoe_ctlr_fcf_usable(fcf))
+			fcf->flags = new.flags;
+
+		if (fcf == fip->sel_fcf && !fcf->fd_flags) {
 			fip->ctlr_ka_time -= fcf->fka_period;
 			fip->ctlr_ka_time += new.fka_period;
 			if (time_before(fip->ctlr_ka_time, fip->timer.expires))
 				mod_timer(&fip->timer, fip->ctlr_ka_time);
-		} else if (!fcoe_ctlr_fcf_usable(fcf))
-			fcf->flags = new.flags;
+		}
 		fcf->fka_period = new.fka_period;
 		memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN);
 	}
@@ -805,7 +948,7 @@
 	 * If this is the first validated FCF, note the time and
 	 * set a timer to trigger selection.
 	 */
-	if (mtu_valid && !fip->sel_time && fcoe_ctlr_fcf_usable(fcf)) {
+	if (mtu_valid && !fip->sel_fcf && fcoe_ctlr_fcf_usable(fcf)) {
 		fip->sel_time = jiffies +
 			msecs_to_jiffies(FCOE_CTLR_START_DELAY);
 		if (!timer_pending(&fip->timer) ||
@@ -813,7 +956,7 @@
 			mod_timer(&fip->timer, fip->sel_time);
 	}
 out:
-	spin_unlock_bh(&fip->lock);
+	mutex_unlock(&fip->ctlr_mutex);
 }
 
 /**
@@ -837,6 +980,8 @@
 	size_t els_len = 0;
 	size_t rlen;
 	size_t dlen;
+	u32 desc_mask = 0;
+	u32 desc_cnt = 0;
 
 	fiph = (struct fip_header *)skb->data;
 	sub = fiph->fip_subcode;
@@ -849,27 +994,42 @@
 
 	desc = (struct fip_desc *)(fiph + 1);
 	while (rlen > 0) {
+		desc_cnt++;
 		dlen = desc->fip_dlen * FIP_BPW;
 		if (dlen < sizeof(*desc) || dlen > rlen)
 			goto drop;
+		/* Drop ELS if there are duplicate critical descriptors */
+		if (desc->fip_dtype < 32) {
+			if (desc_mask & 1U << desc->fip_dtype) {
+				LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
+						"Descriptors in FIP ELS\n");
+				goto drop;
+			}
+			desc_mask |= (1 << desc->fip_dtype);
+		}
 		switch (desc->fip_dtype) {
 		case FIP_DT_MAC:
+			if (desc_cnt == 1) {
+				LIBFCOE_FIP_DBG(fip, "FIP descriptors "
+						"received out of order\n");
+				goto drop;
+			}
+
 			if (dlen != sizeof(struct fip_mac_desc))
 				goto len_err;
 			memcpy(granted_mac,
 			       ((struct fip_mac_desc *)desc)->fd_mac,
 			       ETH_ALEN);
-			if (!is_valid_ether_addr(granted_mac)) {
-				LIBFCOE_FIP_DBG(fip, "Invalid MAC address "
-						"in FIP ELS\n");
-				goto drop;
-			}
-			memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN);
 			break;
 		case FIP_DT_FLOGI:
 		case FIP_DT_FDISC:
 		case FIP_DT_LOGO:
 		case FIP_DT_ELP:
+			if (desc_cnt != 1) {
+				LIBFCOE_FIP_DBG(fip, "FIP descriptors "
+						"received out of order\n");
+				goto drop;
+			}
 			if (fh)
 				goto drop;
 			if (dlen < sizeof(*els) + sizeof(*fh) + 1)
@@ -885,7 +1045,12 @@
 			/* standard says ignore unknown descriptors >= 128 */
 			if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
 				goto drop;
-			continue;
+			if (desc_cnt <= 2) {
+				LIBFCOE_FIP_DBG(fip, "FIP descriptors "
+						"received out of order\n");
+				goto drop;
+			}
+			break;
 		}
 		desc = (struct fip_desc *)((char *)desc + dlen);
 		rlen -= dlen;
@@ -895,10 +1060,27 @@
 		goto drop;
 	els_op = *(u8 *)(fh + 1);
 
-	if (els_dtype == FIP_DT_FLOGI && sub == FIP_SC_REP &&
-	    fip->flogi_oxid == ntohs(fh->fh_ox_id) &&
-	    els_op == ELS_LS_ACC && is_valid_ether_addr(granted_mac))
-		fip->flogi_oxid = FC_XID_UNKNOWN;
+	if ((els_dtype == FIP_DT_FLOGI || els_dtype == FIP_DT_FDISC) &&
+	    sub == FIP_SC_REP && els_op == ELS_LS_ACC &&
+	    fip->mode != FIP_MODE_VN2VN) {
+		if (!is_valid_ether_addr(granted_mac)) {
+			LIBFCOE_FIP_DBG(fip,
+				"Invalid MAC address %pM in FIP ELS\n",
+				granted_mac);
+			goto drop;
+		}
+		memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN);
+
+		if (fip->flogi_oxid == ntohs(fh->fh_ox_id))
+			fip->flogi_oxid = FC_XID_UNKNOWN;
+	}
+
+	if ((desc_cnt == 0) || ((els_op != ELS_LS_RJT) &&
+	    (!(1U << FIP_DT_MAC & desc_mask)))) {
+		LIBFCOE_FIP_DBG(fip, "Missing critical descriptors "
+				"in FIP ELS\n");
+		goto drop;
+	}
 
 	/*
 	 * Convert skb into an fc_frame containing only the ELS.
@@ -910,6 +1092,7 @@
 	fr_sof(fp) = FC_SOF_I3;
 	fr_eof(fp) = FC_EOF_T;
 	fr_dev(fp) = lport;
+	fr_encaps(fp) = els_dtype;
 
 	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
 	stats->RxFrames++;
@@ -945,7 +1128,9 @@
 	size_t dlen;
 	struct fcoe_fcf *fcf = fip->sel_fcf;
 	struct fc_lport *lport = fip->lp;
-	u32	desc_mask;
+	struct fc_lport *vn_port = NULL;
+	u32 desc_mask;
+	int is_vn_port = 0;
 
 	LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
 
@@ -963,6 +1148,13 @@
 		dlen = desc->fip_dlen * FIP_BPW;
 		if (dlen > rlen)
 			return;
+		/* Drop CVL if there are duplicate critical descriptors */
+		if ((desc->fip_dtype < 32) &&
+		    !(desc_mask & 1U << desc->fip_dtype)) {
+			LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
+					"Descriptors in FIP CVL\n");
+			return;
+		}
 		switch (desc->fip_dtype) {
 		case FIP_DT_MAC:
 			mp = (struct fip_mac_desc *)desc;
@@ -987,8 +1179,26 @@
 			if (compare_ether_addr(vp->fd_mac,
 					       fip->get_src_addr(lport)) == 0 &&
 			    get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn &&
-			    ntoh24(vp->fd_fc_id) == lport->port_id)
+			    ntoh24(vp->fd_fc_id) == lport->port_id) {
 				desc_mask &= ~BIT(FIP_DT_VN_ID);
+				break;
+			}
+			/* check if clr_vlink is for NPIV port */
+			mutex_lock(&lport->lp_mutex);
+			list_for_each_entry(vn_port, &lport->vports, list) {
+				if (compare_ether_addr(vp->fd_mac,
+				    fip->get_src_addr(vn_port)) == 0 &&
+				    (get_unaligned_be64(&vp->fd_wwpn)
+							== vn_port->wwpn) &&
+				    (ntoh24(vp->fd_fc_id) ==
+					    fc_host_port_id(vn_port->host))) {
+					desc_mask &= ~BIT(FIP_DT_VN_ID);
+					is_vn_port = 1;
+					break;
+				}
+			}
+			mutex_unlock(&lport->lp_mutex);
+
 			break;
 		default:
 			/* standard says ignore unknown descriptors >= 128 */
@@ -1009,14 +1219,19 @@
 	} else {
 		LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
 
-		spin_lock_bh(&fip->lock);
-		per_cpu_ptr(lport->dev_stats,
-			    smp_processor_id())->VLinkFailureCount++;
-		fcoe_ctlr_reset(fip);
-		spin_unlock_bh(&fip->lock);
+		if (is_vn_port)
+			fc_lport_reset(vn_port);
+		else {
+			mutex_lock(&fip->ctlr_mutex);
+			per_cpu_ptr(lport->dev_stats,
+				    get_cpu())->VLinkFailureCount++;
+			put_cpu();
+			fcoe_ctlr_reset(fip);
+			mutex_unlock(&fip->ctlr_mutex);
 
-		fc_lport_reset(fip->lp);
-		fcoe_ctlr_solicit(fip, NULL);
+			fc_lport_reset(fip->lp);
+			fcoe_ctlr_solicit(fip, NULL);
+		}
 	}
 }
 
@@ -1054,8 +1269,13 @@
 	if (skb->len < sizeof(*fiph))
 		goto drop;
 	eh = eth_hdr(skb);
-	if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) &&
-	    compare_ether_addr(eh->h_dest, FIP_ALL_ENODE_MACS))
+	if (fip->mode == FIP_MODE_VN2VN) {
+		if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) &&
+		    compare_ether_addr(eh->h_dest, fcoe_all_vn2vn) &&
+		    compare_ether_addr(eh->h_dest, fcoe_all_p2p))
+			goto drop;
+	} else if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) &&
+		   compare_ether_addr(eh->h_dest, fcoe_all_enode))
 		goto drop;
 	fiph = (struct fip_header *)skb->data;
 	op = ntohs(fiph->fip_op);
@@ -1066,22 +1286,31 @@
 	if (ntohs(fiph->fip_dl_len) * FIP_BPW + sizeof(*fiph) > skb->len)
 		goto drop;
 
-	spin_lock_bh(&fip->lock);
+	mutex_lock(&fip->ctlr_mutex);
 	state = fip->state;
 	if (state == FIP_ST_AUTO) {
 		fip->map_dest = 0;
-		fip->state = FIP_ST_ENABLED;
+		fcoe_ctlr_set_state(fip, FIP_ST_ENABLED);
 		state = FIP_ST_ENABLED;
 		LIBFCOE_FIP_DBG(fip, "Using FIP mode\n");
 	}
-	spin_unlock_bh(&fip->lock);
-	if (state != FIP_ST_ENABLED)
+	mutex_unlock(&fip->ctlr_mutex);
+
+	if (fip->mode == FIP_MODE_VN2VN && op == FIP_OP_VN2VN)
+		return fcoe_ctlr_vn_recv(fip, skb);
+
+	if (state != FIP_ST_ENABLED && state != FIP_ST_VNMP_UP &&
+	    state != FIP_ST_VNMP_CLAIM)
 		goto drop;
 
 	if (op == FIP_OP_LS) {
 		fcoe_ctlr_recv_els(fip, skb);	/* consumes skb */
 		return 0;
 	}
+
+	if (state != FIP_ST_ENABLED)
+		goto drop;
+
 	if (op == FIP_OP_DISC && sub == FIP_SC_ADV)
 		fcoe_ctlr_recv_adv(fip, skb);
 	else if (op == FIP_OP_CTRL && sub == FIP_SC_CLR_VLINK)
@@ -1140,30 +1369,53 @@
 /**
  * fcoe_ctlr_timeout() - FIP timeout handler
  * @arg: The FCoE controller that timed out
- *
- * Ages FCFs.  Triggers FCF selection if possible.  Sends keep-alives.
  */
 static void fcoe_ctlr_timeout(unsigned long arg)
 {
 	struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg;
+
+	schedule_work(&fip->timer_work);
+}
+
+/**
+ * fcoe_ctlr_timer_work() - Worker thread function for timer work
+ * @work: Handle to a FCoE controller
+ *
+ * Ages FCFs.  Triggers FCF selection if possible.
+ * Sends keep-alives and resets.
+ */
+static void fcoe_ctlr_timer_work(struct work_struct *work)
+{
+	struct fcoe_ctlr *fip;
+	struct fc_lport *vport;
+	u8 *mac;
+	u8 reset = 0;
+	u8 send_ctlr_ka = 0;
+	u8 send_port_ka = 0;
 	struct fcoe_fcf *sel;
 	struct fcoe_fcf *fcf;
-	unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
+	unsigned long next_timer;
 
-	spin_lock_bh(&fip->lock);
+	fip = container_of(work, struct fcoe_ctlr, timer_work);
+	if (fip->mode == FIP_MODE_VN2VN)
+		return fcoe_ctlr_vn_timeout(fip);
+	mutex_lock(&fip->ctlr_mutex);
 	if (fip->state == FIP_ST_DISABLED) {
-		spin_unlock_bh(&fip->lock);
+		mutex_unlock(&fip->ctlr_mutex);
 		return;
 	}
 
 	fcf = fip->sel_fcf;
-	fcoe_ctlr_age_fcfs(fip);
+	next_timer = fcoe_ctlr_age_fcfs(fip);
 
 	sel = fip->sel_fcf;
-	if (!sel && fip->sel_time && time_after_eq(jiffies, fip->sel_time)) {
-		fcoe_ctlr_select(fip);
-		sel = fip->sel_fcf;
-		fip->sel_time = 0;
+	if (!sel && fip->sel_time) {
+		if (time_after_eq(jiffies, fip->sel_time)) {
+			fcoe_ctlr_select(fip);
+			sel = fip->sel_fcf;
+			fip->sel_time = 0;
+		} else if (time_after(next_timer, fip->sel_time))
+			next_timer = fip->sel_time;
 	}
 
 	if (sel != fcf) {
@@ -1173,23 +1425,25 @@
 			       "Fibre-Channel Forwarder MAC %pM\n",
 			       fip->lp->host->host_no, sel->fcf_mac);
 			memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN);
+			fip->map_dest = 0;
 			fip->port_ka_time = jiffies +
 				msecs_to_jiffies(FIP_VN_KA_PERIOD);
 			fip->ctlr_ka_time = jiffies + sel->fka_period;
+			if (time_after(next_timer, fip->ctlr_ka_time))
+				next_timer = fip->ctlr_ka_time;
 		} else {
 			printk(KERN_NOTICE "libfcoe: host%d: "
 			       "FIP Fibre-Channel Forwarder timed out.	"
 			       "Starting FCF discovery.\n",
 			       fip->lp->host->host_no);
-			fip->reset_req = 1;
-			schedule_work(&fip->timer_work);
+			reset = 1;
 		}
 	}
 
 	if (sel && !sel->fd_flags) {
 		if (time_after_eq(jiffies, fip->ctlr_ka_time)) {
 			fip->ctlr_ka_time = jiffies + sel->fka_period;
-			fip->send_ctlr_ka = 1;
+			send_ctlr_ka = 1;
 		}
 		if (time_after(next_timer, fip->ctlr_ka_time))
 			next_timer = fip->ctlr_ka_time;
@@ -1197,50 +1451,25 @@
 		if (time_after_eq(jiffies, fip->port_ka_time)) {
 			fip->port_ka_time = jiffies +
 				msecs_to_jiffies(FIP_VN_KA_PERIOD);
-			fip->send_port_ka = 1;
+			send_port_ka = 1;
 		}
 		if (time_after(next_timer, fip->port_ka_time))
 			next_timer = fip->port_ka_time;
-		mod_timer(&fip->timer, next_timer);
-	} else if (fip->sel_time) {
-		next_timer = fip->sel_time +
-			msecs_to_jiffies(FCOE_CTLR_START_DELAY);
-		mod_timer(&fip->timer, next_timer);
 	}
-	if (fip->send_ctlr_ka || fip->send_port_ka)
-		schedule_work(&fip->timer_work);
-	spin_unlock_bh(&fip->lock);
-}
+	if (!list_empty(&fip->fcfs))
+		mod_timer(&fip->timer, next_timer);
+	mutex_unlock(&fip->ctlr_mutex);
 
-/**
- * fcoe_ctlr_timer_work() - Worker thread function for timer work
- * @work: Handle to a FCoE controller
- *
- * Sends keep-alives and resets which must not
- * be called from the timer directly, since they use a mutex.
- */
-static void fcoe_ctlr_timer_work(struct work_struct *work)
-{
-	struct fcoe_ctlr *fip;
-	struct fc_lport *vport;
-	u8 *mac;
-	int reset;
-
-	fip = container_of(work, struct fcoe_ctlr, timer_work);
-	spin_lock_bh(&fip->lock);
-	reset = fip->reset_req;
-	fip->reset_req = 0;
-	spin_unlock_bh(&fip->lock);
-
-	if (reset)
+	if (reset) {
 		fc_lport_reset(fip->lp);
-
-	if (fip->send_ctlr_ka) {
-		fip->send_ctlr_ka = 0;
-		fcoe_ctlr_send_keep_alive(fip, NULL, 0, fip->ctl_src_addr);
+		/* restart things with a solicitation */
+		fcoe_ctlr_solicit(fip, NULL);
 	}
-	if (fip->send_port_ka) {
-		fip->send_port_ka = 0;
+
+	if (send_ctlr_ka)
+		fcoe_ctlr_send_keep_alive(fip, NULL, 0, fip->ctl_src_addr);
+
+	if (send_port_ka) {
 		mutex_lock(&fip->lp->lp_mutex);
 		mac = fip->get_src_addr(fip->lp);
 		fcoe_ctlr_send_keep_alive(fip, fip->lp, 1, mac);
@@ -1297,12 +1526,12 @@
 	if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP &&
 	    fip->flogi_oxid == ntohs(fh->fh_ox_id)) {
 
-		spin_lock_bh(&fip->lock);
+		mutex_lock(&fip->ctlr_mutex);
 		if (fip->state != FIP_ST_AUTO && fip->state != FIP_ST_NON_FIP) {
-			spin_unlock_bh(&fip->lock);
+			mutex_unlock(&fip->ctlr_mutex);
 			return -EINVAL;
 		}
-		fip->state = FIP_ST_NON_FIP;
+		fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP);
 		LIBFCOE_FIP_DBG(fip,
 				"received FLOGI LS_ACC using non-FIP mode\n");
 
@@ -1313,28 +1542,28 @@
 		 * Otherwise we use the FCoE gateway addr
 		 */
 		if (!compare_ether_addr(sa, (u8[6])FC_FCOE_FLOGI_MAC)) {
-			fip->map_dest = 1;
+			fcoe_ctlr_map_dest(fip);
 		} else {
 			memcpy(fip->dest_addr, sa, ETH_ALEN);
 			fip->map_dest = 0;
 		}
 		fip->flogi_oxid = FC_XID_UNKNOWN;
-		spin_unlock_bh(&fip->lock);
+		mutex_unlock(&fip->ctlr_mutex);
 		fc_fcoe_set_mac(fr_cb(fp)->granted_mac, fh->fh_d_id);
 	} else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) {
 		/*
 		 * Save source MAC for point-to-point responses.
 		 */
-		spin_lock_bh(&fip->lock);
+		mutex_lock(&fip->ctlr_mutex);
 		if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) {
 			memcpy(fip->dest_addr, sa, ETH_ALEN);
 			fip->map_dest = 0;
 			if (fip->state == FIP_ST_AUTO)
 				LIBFCOE_FIP_DBG(fip, "received non-FIP FLOGI. "
 						"Setting non-FIP mode\n");
-			fip->state = FIP_ST_NON_FIP;
+			fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP);
 		}
-		spin_unlock_bh(&fip->lock);
+		mutex_unlock(&fip->ctlr_mutex);
 	}
 	return 0;
 }
@@ -1382,26 +1611,916 @@
 EXPORT_SYMBOL_GPL(fcoe_wwn_from_mac);
 
 /**
+ * fcoe_ctlr_rport() - return the fcoe_rport for a given fc_rport_priv
+ * @rdata: libfc remote port
+ */
+static inline struct fcoe_rport *fcoe_ctlr_rport(struct fc_rport_priv *rdata)
+{
+	return (struct fcoe_rport *)(rdata + 1);
+}
+
+/**
+ * fcoe_ctlr_vn_send() - Send a FIP VN2VN Probe Request or Reply.
+ * @fip: The FCoE controller
+ * @sub: sub-opcode for probe request, reply, or advertisement.
+ * @dest: The destination Ethernet MAC address
+ * @min_len: minimum size of the Ethernet payload to be sent
+ */
+static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip,
+			      enum fip_vn2vn_subcode sub,
+			      const u8 *dest, size_t min_len)
+{
+	struct sk_buff *skb;
+	struct fip_frame {
+		struct ethhdr eth;
+		struct fip_header fip;
+		struct fip_mac_desc mac;
+		struct fip_wwn_desc wwnn;
+		struct fip_vn_desc vn;
+	} __attribute__((packed)) *frame;
+	struct fip_fc4_feat *ff;
+	struct fip_size_desc *size;
+	u32 fcp_feat;
+	size_t len;
+	size_t dlen;
+
+	len = sizeof(*frame);
+	dlen = 0;
+	if (sub == FIP_SC_VN_CLAIM_NOTIFY || sub == FIP_SC_VN_CLAIM_REP) {
+		dlen = sizeof(struct fip_fc4_feat) +
+		       sizeof(struct fip_size_desc);
+		len += dlen;
+	}
+	dlen += sizeof(frame->mac) + sizeof(frame->wwnn) + sizeof(frame->vn);
+	len = max(len, min_len + sizeof(struct ethhdr));
+
+	skb = dev_alloc_skb(len);
+	if (!skb)
+		return;
+
+	frame = (struct fip_frame *)skb->data;
+	memset(frame, 0, len);
+	memcpy(frame->eth.h_dest, dest, ETH_ALEN);
+	memcpy(frame->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
+	frame->eth.h_proto = htons(ETH_P_FIP);
+
+	frame->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
+	frame->fip.fip_op = htons(FIP_OP_VN2VN);
+	frame->fip.fip_subcode = sub;
+	frame->fip.fip_dl_len = htons(dlen / FIP_BPW);
+
+	frame->mac.fd_desc.fip_dtype = FIP_DT_MAC;
+	frame->mac.fd_desc.fip_dlen = sizeof(frame->mac) / FIP_BPW;
+	memcpy(frame->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN);
+
+	frame->wwnn.fd_desc.fip_dtype = FIP_DT_NAME;
+	frame->wwnn.fd_desc.fip_dlen = sizeof(frame->wwnn) / FIP_BPW;
+	put_unaligned_be64(fip->lp->wwnn, &frame->wwnn.fd_wwn);
+
+	frame->vn.fd_desc.fip_dtype = FIP_DT_VN_ID;
+	frame->vn.fd_desc.fip_dlen = sizeof(frame->vn) / FIP_BPW;
+	hton24(frame->vn.fd_mac, FIP_VN_FC_MAP);
+	hton24(frame->vn.fd_mac + 3, fip->port_id);
+	hton24(frame->vn.fd_fc_id, fip->port_id);
+	put_unaligned_be64(fip->lp->wwpn, &frame->vn.fd_wwpn);
+
+	/*
+	 * For claims, add FC-4 features.
+	 * TBD: Add interface to get fc-4 types and features from libfc.
+	 */
+	if (sub == FIP_SC_VN_CLAIM_NOTIFY || sub == FIP_SC_VN_CLAIM_REP) {
+		ff = (struct fip_fc4_feat *)(frame + 1);
+		ff->fd_desc.fip_dtype = FIP_DT_FC4F;
+		ff->fd_desc.fip_dlen = sizeof(*ff) / FIP_BPW;
+		ff->fd_fts = fip->lp->fcts;
+
+		fcp_feat = 0;
+		if (fip->lp->service_params & FCP_SPPF_INIT_FCN)
+			fcp_feat |= FCP_FEAT_INIT;
+		if (fip->lp->service_params & FCP_SPPF_TARG_FCN)
+			fcp_feat |= FCP_FEAT_TARG;
+		fcp_feat <<= (FC_TYPE_FCP * 4) % 32;
+		ff->fd_ff.fd_feat[FC_TYPE_FCP * 4 / 32] = htonl(fcp_feat);
+
+		size = (struct fip_size_desc *)(ff + 1);
+		size->fd_desc.fip_dtype = FIP_DT_FCOE_SIZE;
+		size->fd_desc.fip_dlen = sizeof(*size) / FIP_BPW;
+		size->fd_size = htons(fcoe_ctlr_fcoe_size(fip));
+	}
+
+	skb_put(skb, len);
+	skb->protocol = htons(ETH_P_FIP);
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
+
+	fip->send(fip, skb);
+}
+
+/**
+ * fcoe_ctlr_vn_rport_callback - Event handler for rport events.
+ * @lport: The lport which is receiving the event
+ * @rdata: remote port private data
+ * @event: The event that occured
+ *
+ * Locking Note:  The rport lock must not be held when calling this function.
+ */
+static void fcoe_ctlr_vn_rport_callback(struct fc_lport *lport,
+					struct fc_rport_priv *rdata,
+					enum fc_rport_event event)
+{
+	struct fcoe_ctlr *fip = lport->disc.priv;
+	struct fcoe_rport *frport = fcoe_ctlr_rport(rdata);
+
+	LIBFCOE_FIP_DBG(fip, "vn_rport_callback %x event %d\n",
+			rdata->ids.port_id, event);
+
+	mutex_lock(&fip->ctlr_mutex);
+	switch (event) {
+	case RPORT_EV_READY:
+		frport->login_count = 0;
+		break;
+	case RPORT_EV_LOGO:
+	case RPORT_EV_FAILED:
+	case RPORT_EV_STOP:
+		frport->login_count++;
+		if (frport->login_count > FCOE_CTLR_VN2VN_LOGIN_LIMIT) {
+			LIBFCOE_FIP_DBG(fip,
+					"rport FLOGI limited port_id %6.6x\n",
+					rdata->ids.port_id);
+			lport->tt.rport_logoff(rdata);
+		}
+		break;
+	default:
+		break;
+	}
+	mutex_unlock(&fip->ctlr_mutex);
+}
+
+static struct fc_rport_operations fcoe_ctlr_vn_rport_ops = {
+	.event_callback = fcoe_ctlr_vn_rport_callback,
+};
+
+/**
+ * fcoe_ctlr_disc_stop_locked() - stop discovery in VN2VN mode
+ * @fip: The FCoE controller
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_disc_stop_locked(struct fc_lport *lport)
+{
+	mutex_lock(&lport->disc.disc_mutex);
+	lport->disc.disc_callback = NULL;
+	mutex_unlock(&lport->disc.disc_mutex);
+}
+
+/**
+ * fcoe_ctlr_disc_stop() - stop discovery in VN2VN mode
+ * @fip: The FCoE controller
+ *
+ * Called through the local port template for discovery.
+ * Called without the ctlr_mutex held.
+ */
+static void fcoe_ctlr_disc_stop(struct fc_lport *lport)
+{
+	struct fcoe_ctlr *fip = lport->disc.priv;
+
+	mutex_lock(&fip->ctlr_mutex);
+	fcoe_ctlr_disc_stop_locked(lport);
+	mutex_unlock(&fip->ctlr_mutex);
+}
+
+/**
+ * fcoe_ctlr_disc_stop_final() - stop discovery for shutdown in VN2VN mode
+ * @fip: The FCoE controller
+ *
+ * Called through the local port template for discovery.
+ * Called without the ctlr_mutex held.
+ */
+static void fcoe_ctlr_disc_stop_final(struct fc_lport *lport)
+{
+	fcoe_ctlr_disc_stop(lport);
+	lport->tt.rport_flush_queue();
+	synchronize_rcu();
+}
+
+/**
+ * fcoe_ctlr_vn_restart() - VN2VN probe restart with new port_id
+ * @fip: The FCoE controller
+ *
+ * Called with fcoe_ctlr lock held.
+ */
+static void fcoe_ctlr_vn_restart(struct fcoe_ctlr *fip)
+{
+	unsigned long wait;
+	u32 port_id;
+
+	fcoe_ctlr_disc_stop_locked(fip->lp);
+
+	/*
+	 * Get proposed port ID.
+	 * If this is the first try after link up, use any previous port_id.
+	 * If there was none, use the low bits of the port_name.
+	 * On subsequent tries, get the next random one.
+	 * Don't use reserved IDs, use another non-zero value, just as random.
+	 */
+	port_id = fip->port_id;
+	if (fip->probe_tries)
+		port_id = prandom32(&fip->rnd_state) & 0xffff;
+	else if (!port_id)
+		port_id = fip->lp->wwpn & 0xffff;
+	if (!port_id || port_id == 0xffff)
+		port_id = 1;
+	fip->port_id = port_id;
+
+	if (fip->probe_tries < FIP_VN_RLIM_COUNT) {
+		fip->probe_tries++;
+		wait = random32() % FIP_VN_PROBE_WAIT;
+	} else
+		wait = FIP_VN_RLIM_INT;
+	mod_timer(&fip->timer, jiffies + msecs_to_jiffies(wait));
+	fcoe_ctlr_set_state(fip, FIP_ST_VNMP_START);
+}
+
+/**
+ * fcoe_ctlr_vn_start() - Start in VN2VN mode
+ * @fip: The FCoE controller
+ *
+ * Called with fcoe_ctlr lock held.
+ */
+static void fcoe_ctlr_vn_start(struct fcoe_ctlr *fip)
+{
+	fip->probe_tries = 0;
+	prandom32_seed(&fip->rnd_state, fip->lp->wwpn);
+	fcoe_ctlr_vn_restart(fip);
+}
+
+/**
+ * fcoe_ctlr_vn_parse - parse probe request or response
+ * @fip: The FCoE controller
+ * @skb: incoming packet
+ * @rdata: buffer for resulting parsed VN entry plus fcoe_rport
+ *
+ * Returns non-zero error number on error.
+ * Does not consume the packet.
+ */
+static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip,
+			      struct sk_buff *skb,
+			      struct fc_rport_priv *rdata)
+{
+	struct fip_header *fiph;
+	struct fip_desc *desc = NULL;
+	struct fip_mac_desc *macd = NULL;
+	struct fip_wwn_desc *wwn = NULL;
+	struct fip_vn_desc *vn = NULL;
+	struct fip_size_desc *size = NULL;
+	struct fcoe_rport *frport;
+	size_t rlen;
+	size_t dlen;
+	u32 desc_mask = 0;
+	u32 dtype;
+	u8 sub;
+
+	memset(rdata, 0, sizeof(*rdata) + sizeof(*frport));
+	frport = fcoe_ctlr_rport(rdata);
+
+	fiph = (struct fip_header *)skb->data;
+	frport->flags = ntohs(fiph->fip_flags);
+
+	sub = fiph->fip_subcode;
+	switch (sub) {
+	case FIP_SC_VN_PROBE_REQ:
+	case FIP_SC_VN_PROBE_REP:
+	case FIP_SC_VN_BEACON:
+		desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
+			    BIT(FIP_DT_VN_ID);
+		break;
+	case FIP_SC_VN_CLAIM_NOTIFY:
+	case FIP_SC_VN_CLAIM_REP:
+		desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
+			    BIT(FIP_DT_VN_ID) | BIT(FIP_DT_FC4F) |
+			    BIT(FIP_DT_FCOE_SIZE);
+		break;
+	default:
+		LIBFCOE_FIP_DBG(fip, "vn_parse unknown subcode %u\n", sub);
+		return -EINVAL;
+	}
+
+	rlen = ntohs(fiph->fip_dl_len) * 4;
+	if (rlen + sizeof(*fiph) > skb->len)
+		return -EINVAL;
+
+	desc = (struct fip_desc *)(fiph + 1);
+	while (rlen > 0) {
+		dlen = desc->fip_dlen * FIP_BPW;
+		if (dlen < sizeof(*desc) || dlen > rlen)
+			return -EINVAL;
+
+		dtype = desc->fip_dtype;
+		if (dtype < 32) {
+			if (!(desc_mask & BIT(dtype))) {
+				LIBFCOE_FIP_DBG(fip,
+						"unexpected or duplicated desc "
+						"desc type %u in "
+						"FIP VN2VN subtype %u\n",
+						dtype, sub);
+				return -EINVAL;
+			}
+			desc_mask &= ~BIT(dtype);
+		}
+
+		switch (dtype) {
+		case FIP_DT_MAC:
+			if (dlen != sizeof(struct fip_mac_desc))
+				goto len_err;
+			macd = (struct fip_mac_desc *)desc;
+			if (!is_valid_ether_addr(macd->fd_mac)) {
+				LIBFCOE_FIP_DBG(fip,
+					"Invalid MAC addr %pM in FIP VN2VN\n",
+					 macd->fd_mac);
+				return -EINVAL;
+			}
+			memcpy(frport->enode_mac, macd->fd_mac, ETH_ALEN);
+			break;
+		case FIP_DT_NAME:
+			if (dlen != sizeof(struct fip_wwn_desc))
+				goto len_err;
+			wwn = (struct fip_wwn_desc *)desc;
+			rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn);
+			break;
+		case FIP_DT_VN_ID:
+			if (dlen != sizeof(struct fip_vn_desc))
+				goto len_err;
+			vn = (struct fip_vn_desc *)desc;
+			memcpy(frport->vn_mac, vn->fd_mac, ETH_ALEN);
+			rdata->ids.port_id = ntoh24(vn->fd_fc_id);
+			rdata->ids.port_name = get_unaligned_be64(&vn->fd_wwpn);
+			break;
+		case FIP_DT_FC4F:
+			if (dlen != sizeof(struct fip_fc4_feat))
+				goto len_err;
+			break;
+		case FIP_DT_FCOE_SIZE:
+			if (dlen != sizeof(struct fip_size_desc))
+				goto len_err;
+			size = (struct fip_size_desc *)desc;
+			frport->fcoe_len = ntohs(size->fd_size);
+			break;
+		default:
+			LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
+					"in FIP probe\n", dtype);
+			/* standard says ignore unknown descriptors >= 128 */
+			if (dtype < FIP_DT_VENDOR_BASE)
+				return -EINVAL;
+			break;
+		}
+		desc = (struct fip_desc *)((char *)desc + dlen);
+		rlen -= dlen;
+	}
+	return 0;
+
+len_err:
+	LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n",
+			dtype, dlen);
+	return -EINVAL;
+}
+
+/**
+ * fcoe_ctlr_vn_send_claim() - send multicast FIP VN2VN Claim Notification.
+ * @fip: The FCoE controller
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_send_claim(struct fcoe_ctlr *fip)
+{
+	fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_NOTIFY, fcoe_all_vn2vn, 0);
+	fip->sol_time = jiffies;
+}
+
+/**
+ * fcoe_ctlr_vn_probe_req() - handle incoming VN2VN probe request.
+ * @fip: The FCoE controller
+ * @rdata: parsed remote port with frport from the probe request
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_probe_req(struct fcoe_ctlr *fip,
+				   struct fc_rport_priv *rdata)
+{
+	struct fcoe_rport *frport = fcoe_ctlr_rport(rdata);
+
+	if (rdata->ids.port_id != fip->port_id)
+		return;
+
+	switch (fip->state) {
+	case FIP_ST_VNMP_CLAIM:
+	case FIP_ST_VNMP_UP:
+		fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP,
+				  frport->enode_mac, 0);
+		break;
+	case FIP_ST_VNMP_PROBE1:
+	case FIP_ST_VNMP_PROBE2:
+		/*
+		 * Decide whether to reply to the Probe.
+		 * Our selected address is never a "recorded" one, so
+		 * only reply if our WWPN is greater and the
+		 * Probe's REC bit is not set.
+		 * If we don't reply, we will change our address.
+		 */
+		if (fip->lp->wwpn > rdata->ids.port_name &&
+		    !(frport->flags & FIP_FL_REC_OR_P2P)) {
+			fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP,
+					  frport->enode_mac, 0);
+			break;
+		}
+		/* fall through */
+	case FIP_ST_VNMP_START:
+		fcoe_ctlr_vn_restart(fip);
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * fcoe_ctlr_vn_probe_reply() - handle incoming VN2VN probe reply.
+ * @fip: The FCoE controller
+ * @rdata: parsed remote port with frport from the probe request
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_probe_reply(struct fcoe_ctlr *fip,
+				   struct fc_rport_priv *rdata)
+{
+	if (rdata->ids.port_id != fip->port_id)
+		return;
+	switch (fip->state) {
+	case FIP_ST_VNMP_START:
+	case FIP_ST_VNMP_PROBE1:
+	case FIP_ST_VNMP_PROBE2:
+	case FIP_ST_VNMP_CLAIM:
+		fcoe_ctlr_vn_restart(fip);
+		break;
+	case FIP_ST_VNMP_UP:
+		fcoe_ctlr_vn_send_claim(fip);
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * fcoe_ctlr_vn_add() - Add a VN2VN entry to the list, based on a claim reply.
+ * @fip: The FCoE controller
+ * @new: newly-parsed remote port with frport as a template for new rdata
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_add(struct fcoe_ctlr *fip, struct fc_rport_priv *new)
+{
+	struct fc_lport *lport = fip->lp;
+	struct fc_rport_priv *rdata;
+	struct fc_rport_identifiers *ids;
+	struct fcoe_rport *frport;
+	u32 port_id;
+
+	port_id = new->ids.port_id;
+	if (port_id == fip->port_id)
+		return;
+
+	mutex_lock(&lport->disc.disc_mutex);
+	rdata = lport->tt.rport_create(lport, port_id);
+	if (!rdata) {
+		mutex_unlock(&lport->disc.disc_mutex);
+		return;
+	}
+
+	rdata->ops = &fcoe_ctlr_vn_rport_ops;
+	rdata->disc_id = lport->disc.disc_id;
+
+	ids = &rdata->ids;
+	if ((ids->port_name != -1 && ids->port_name != new->ids.port_name) ||
+	    (ids->node_name != -1 && ids->node_name != new->ids.node_name))
+		lport->tt.rport_logoff(rdata);
+	ids->port_name = new->ids.port_name;
+	ids->node_name = new->ids.node_name;
+	mutex_unlock(&lport->disc.disc_mutex);
+
+	frport = fcoe_ctlr_rport(rdata);
+	LIBFCOE_FIP_DBG(fip, "vn_add rport %6.6x %s\n",
+			port_id, frport->fcoe_len ? "old" : "new");
+	*frport = *fcoe_ctlr_rport(new);
+	frport->time = 0;
+}
+
+/**
+ * fcoe_ctlr_vn_lookup() - Find VN remote port's MAC address
+ * @fip: The FCoE controller
+ * @port_id:  The port_id of the remote VN_node
+ * @mac: buffer which will hold the VN_NODE destination MAC address, if found.
+ *
+ * Returns non-zero error if no remote port found.
+ */
+static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *fip, u32 port_id, u8 *mac)
+{
+	struct fc_lport *lport = fip->lp;
+	struct fc_rport_priv *rdata;
+	struct fcoe_rport *frport;
+	int ret = -1;
+
+	rcu_read_lock();
+	rdata = lport->tt.rport_lookup(lport, port_id);
+	if (rdata) {
+		frport = fcoe_ctlr_rport(rdata);
+		memcpy(mac, frport->enode_mac, ETH_ALEN);
+		ret = 0;
+	}
+	rcu_read_unlock();
+	return ret;
+}
+
+/**
+ * fcoe_ctlr_vn_claim_notify() - handle received FIP VN2VN Claim Notification
+ * @fip: The FCoE controller
+ * @new: newly-parsed remote port with frport as a template for new rdata
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_claim_notify(struct fcoe_ctlr *fip,
+				      struct fc_rport_priv *new)
+{
+	struct fcoe_rport *frport = fcoe_ctlr_rport(new);
+
+	if (frport->flags & FIP_FL_REC_OR_P2P) {
+		fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
+		return;
+	}
+	switch (fip->state) {
+	case FIP_ST_VNMP_START:
+	case FIP_ST_VNMP_PROBE1:
+	case FIP_ST_VNMP_PROBE2:
+		if (new->ids.port_id == fip->port_id)
+			fcoe_ctlr_vn_restart(fip);
+		break;
+	case FIP_ST_VNMP_CLAIM:
+	case FIP_ST_VNMP_UP:
+		if (new->ids.port_id == fip->port_id) {
+			if (new->ids.port_name > fip->lp->wwpn) {
+				fcoe_ctlr_vn_restart(fip);
+				break;
+			}
+			fcoe_ctlr_vn_send_claim(fip);
+			break;
+		}
+		fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_REP, frport->enode_mac,
+				  min((u32)frport->fcoe_len,
+				      fcoe_ctlr_fcoe_size(fip)));
+		fcoe_ctlr_vn_add(fip, new);
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * fcoe_ctlr_vn_claim_resp() - handle received Claim Response
+ * @fip: The FCoE controller that received the frame
+ * @new: newly-parsed remote port with frport from the Claim Response
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_claim_resp(struct fcoe_ctlr *fip,
+				    struct fc_rport_priv *new)
+{
+	LIBFCOE_FIP_DBG(fip, "claim resp from from rport %x - state %s\n",
+			new->ids.port_id, fcoe_ctlr_state(fip->state));
+	if (fip->state == FIP_ST_VNMP_UP || fip->state == FIP_ST_VNMP_CLAIM)
+		fcoe_ctlr_vn_add(fip, new);
+}
+
+/**
+ * fcoe_ctlr_vn_beacon() - handle received beacon.
+ * @fip: The FCoE controller that received the frame
+ * @new: newly-parsed remote port with frport from the Beacon
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_beacon(struct fcoe_ctlr *fip,
+				struct fc_rport_priv *new)
+{
+	struct fc_lport *lport = fip->lp;
+	struct fc_rport_priv *rdata;
+	struct fcoe_rport *frport;
+
+	frport = fcoe_ctlr_rport(new);
+	if (frport->flags & FIP_FL_REC_OR_P2P) {
+		fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
+		return;
+	}
+	mutex_lock(&lport->disc.disc_mutex);
+	rdata = lport->tt.rport_lookup(lport, new->ids.port_id);
+	if (rdata)
+		kref_get(&rdata->kref);
+	mutex_unlock(&lport->disc.disc_mutex);
+	if (rdata) {
+		if (rdata->ids.node_name == new->ids.node_name &&
+		    rdata->ids.port_name == new->ids.port_name) {
+			frport = fcoe_ctlr_rport(rdata);
+			if (!frport->time && fip->state == FIP_ST_VNMP_UP)
+				lport->tt.rport_login(rdata);
+			frport->time = jiffies;
+		}
+		kref_put(&rdata->kref, lport->tt.rport_destroy);
+		return;
+	}
+	if (fip->state != FIP_ST_VNMP_UP)
+		return;
+
+	/*
+	 * Beacon from a new neighbor.
+	 * Send a claim notify if one hasn't been sent recently.
+	 * Don't add the neighbor yet.
+	 */
+	LIBFCOE_FIP_DBG(fip, "beacon from new rport %x. sending claim notify\n",
+			new->ids.port_id);
+	if (time_after(jiffies,
+		       fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT)))
+		fcoe_ctlr_vn_send_claim(fip);
+}
+
+/**
+ * fcoe_ctlr_vn_age() - Check for VN_ports without recent beacons
+ * @fip: The FCoE controller
+ *
+ * Called with ctlr_mutex held.
+ * Called only in state FIP_ST_VNMP_UP.
+ * Returns the soonest time for next age-out or a time far in the future.
+ */
+static unsigned long fcoe_ctlr_vn_age(struct fcoe_ctlr *fip)
+{
+	struct fc_lport *lport = fip->lp;
+	struct fc_rport_priv *rdata;
+	struct fcoe_rport *frport;
+	unsigned long next_time;
+	unsigned long deadline;
+
+	next_time = jiffies + msecs_to_jiffies(FIP_VN_BEACON_INT * 10);
+	mutex_lock(&lport->disc.disc_mutex);
+	list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) {
+		frport = fcoe_ctlr_rport(rdata);
+		if (!frport->time)
+			continue;
+		deadline = frport->time +
+			   msecs_to_jiffies(FIP_VN_BEACON_INT * 25 / 10);
+		if (time_after_eq(jiffies, deadline)) {
+			frport->time = 0;
+			LIBFCOE_FIP_DBG(fip,
+				"port %16.16llx fc_id %6.6x beacon expired\n",
+				rdata->ids.port_name, rdata->ids.port_id);
+			lport->tt.rport_logoff(rdata);
+		} else if (time_before(deadline, next_time))
+			next_time = deadline;
+	}
+	mutex_unlock(&lport->disc.disc_mutex);
+	return next_time;
+}
+
+/**
+ * fcoe_ctlr_vn_recv() - Receive a FIP frame
+ * @fip: The FCoE controller that received the frame
+ * @skb: The received FIP frame
+ *
+ * Returns non-zero if the frame is dropped.
+ * Always consumes the frame.
+ */
+static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
+{
+	struct fip_header *fiph;
+	enum fip_vn2vn_subcode sub;
+	union {
+		struct fc_rport_priv rdata;
+		struct fcoe_rport frport;
+	} buf;
+	int rc;
+
+	fiph = (struct fip_header *)skb->data;
+	sub = fiph->fip_subcode;
+
+	rc = fcoe_ctlr_vn_parse(fip, skb, &buf.rdata);
+	if (rc) {
+		LIBFCOE_FIP_DBG(fip, "vn_recv vn_parse error %d\n", rc);
+		goto drop;
+	}
+
+	mutex_lock(&fip->ctlr_mutex);
+	switch (sub) {
+	case FIP_SC_VN_PROBE_REQ:
+		fcoe_ctlr_vn_probe_req(fip, &buf.rdata);
+		break;
+	case FIP_SC_VN_PROBE_REP:
+		fcoe_ctlr_vn_probe_reply(fip, &buf.rdata);
+		break;
+	case FIP_SC_VN_CLAIM_NOTIFY:
+		fcoe_ctlr_vn_claim_notify(fip, &buf.rdata);
+		break;
+	case FIP_SC_VN_CLAIM_REP:
+		fcoe_ctlr_vn_claim_resp(fip, &buf.rdata);
+		break;
+	case FIP_SC_VN_BEACON:
+		fcoe_ctlr_vn_beacon(fip, &buf.rdata);
+		break;
+	default:
+		LIBFCOE_FIP_DBG(fip, "vn_recv unknown subcode %d\n", sub);
+		rc = -1;
+		break;
+	}
+	mutex_unlock(&fip->ctlr_mutex);
+drop:
+	kfree_skb(skb);
+	return rc;
+}
+
+/**
+ * fcoe_ctlr_disc_recv - discovery receive handler for VN2VN mode.
+ * @lport: The local port
+ * @fp: The received frame
+ *
+ * This should never be called since we don't see RSCNs or other
+ * fabric-generated ELSes.
+ */
+static void fcoe_ctlr_disc_recv(struct fc_lport *lport, struct fc_frame *fp)
+{
+	struct fc_seq_els_data rjt_data;
+
+	rjt_data.reason = ELS_RJT_UNSUP;
+	rjt_data.explan = ELS_EXPL_NONE;
+	lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data);
+	fc_frame_free(fp);
+}
+
+/**
+ * fcoe_ctlr_disc_recv - start discovery for VN2VN mode.
+ * @fip: The FCoE controller
+ *
+ * This sets a flag indicating that remote ports should be created
+ * and started for the peers we discover.  We use the disc_callback
+ * pointer as that flag.  Peers already discovered are created here.
+ *
+ * The lport lock is held during this call. The callback must be done
+ * later, without holding either the lport or discovery locks.
+ * The fcoe_ctlr lock may also be held during this call.
+ */
+static void fcoe_ctlr_disc_start(void (*callback)(struct fc_lport *,
+						  enum fc_disc_event),
+				 struct fc_lport *lport)
+{
+	struct fc_disc *disc = &lport->disc;
+	struct fcoe_ctlr *fip = disc->priv;
+
+	mutex_lock(&disc->disc_mutex);
+	disc->disc_callback = callback;
+	disc->disc_id = (disc->disc_id + 2) | 1;
+	disc->pending = 1;
+	schedule_work(&fip->timer_work);
+	mutex_unlock(&disc->disc_mutex);
+}
+
+/**
+ * fcoe_ctlr_vn_disc() - report FIP VN_port discovery results after claim state.
+ * @fip: The FCoE controller
+ *
+ * Starts the FLOGI and PLOGI login process to each discovered rport for which
+ * we've received at least one beacon.
+ * Performs the discovery complete callback.
+ */
+static void fcoe_ctlr_vn_disc(struct fcoe_ctlr *fip)
+{
+	struct fc_lport *lport = fip->lp;
+	struct fc_disc *disc = &lport->disc;
+	struct fc_rport_priv *rdata;
+	struct fcoe_rport *frport;
+	void (*callback)(struct fc_lport *, enum fc_disc_event);
+
+	mutex_lock(&disc->disc_mutex);
+	callback = disc->pending ? disc->disc_callback : NULL;
+	disc->pending = 0;
+	list_for_each_entry_rcu(rdata, &disc->rports, peers) {
+		frport = fcoe_ctlr_rport(rdata);
+		if (frport->time)
+			lport->tt.rport_login(rdata);
+	}
+	mutex_unlock(&disc->disc_mutex);
+	if (callback)
+		callback(lport, DISC_EV_SUCCESS);
+}
+
+/**
+ * fcoe_ctlr_vn_timeout - timer work function for VN2VN mode.
+ * @fip: The FCoE controller
+ */
+static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip)
+{
+	unsigned long next_time;
+	u8 mac[ETH_ALEN];
+	u32 new_port_id = 0;
+
+	mutex_lock(&fip->ctlr_mutex);
+	switch (fip->state) {
+	case FIP_ST_VNMP_START:
+		fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE1);
+		fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
+		next_time = jiffies + msecs_to_jiffies(FIP_VN_PROBE_WAIT);
+		break;
+	case FIP_ST_VNMP_PROBE1:
+		fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE2);
+		fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
+		next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT);
+		break;
+	case FIP_ST_VNMP_PROBE2:
+		fcoe_ctlr_set_state(fip, FIP_ST_VNMP_CLAIM);
+		new_port_id = fip->port_id;
+		hton24(mac, FIP_VN_FC_MAP);
+		hton24(mac + 3, new_port_id);
+		fcoe_ctlr_map_dest(fip);
+		fip->update_mac(fip->lp, mac);
+		fcoe_ctlr_vn_send_claim(fip);
+		next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT);
+		break;
+	case FIP_ST_VNMP_CLAIM:
+		/*
+		 * This may be invoked either by starting discovery so don't
+		 * go to the next state unless it's been long enough.
+		 */
+		next_time = fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT);
+		if (time_after_eq(jiffies, next_time)) {
+			fcoe_ctlr_set_state(fip, FIP_ST_VNMP_UP);
+			fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON,
+					  fcoe_all_vn2vn, 0);
+			next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT);
+			fip->port_ka_time = next_time;
+		}
+		fcoe_ctlr_vn_disc(fip);
+		break;
+	case FIP_ST_VNMP_UP:
+		next_time = fcoe_ctlr_vn_age(fip);
+		if (time_after_eq(jiffies, fip->port_ka_time)) {
+			fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON,
+					  fcoe_all_vn2vn, 0);
+			fip->port_ka_time = jiffies +
+				 msecs_to_jiffies(FIP_VN_BEACON_INT +
+					(random32() % FIP_VN_BEACON_FUZZ));
+		}
+		if (time_before(fip->port_ka_time, next_time))
+			next_time = fip->port_ka_time;
+		break;
+	case FIP_ST_LINK_WAIT:
+		goto unlock;
+	default:
+		WARN(1, "unexpected state %d", fip->state);
+		goto unlock;
+	}
+	mod_timer(&fip->timer, next_time);
+unlock:
+	mutex_unlock(&fip->ctlr_mutex);
+
+	/* If port ID is new, notify local port after dropping ctlr_mutex */
+	if (new_port_id)
+		fc_lport_set_local_id(fip->lp, new_port_id);
+}
+
+/**
  * fcoe_libfc_config() - Sets up libfc related properties for local port
  * @lp: The local port to configure libfc for
+ * @fip: The FCoE controller in use by the local port
  * @tt: The libfc function template
+ * @init_fcp: If non-zero, the FCP portion of libfc should be initialized
  *
  * Returns : 0 for success
  */
-int fcoe_libfc_config(struct fc_lport *lport,
-		      struct libfc_function_template *tt)
+int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip,
+		      const struct libfc_function_template *tt, int init_fcp)
 {
 	/* Set the function pointers set by the LLDD */
 	memcpy(&lport->tt, tt, sizeof(*tt));
-	if (fc_fcp_init(lport))
+	if (init_fcp && fc_fcp_init(lport))
 		return -ENOMEM;
 	fc_exch_init(lport);
 	fc_elsct_init(lport);
 	fc_lport_init(lport);
+	if (fip->mode == FIP_MODE_VN2VN)
+		lport->rport_priv_size = sizeof(struct fcoe_rport);
 	fc_rport_init(lport);
-	fc_disc_init(lport);
-
+	if (fip->mode == FIP_MODE_VN2VN) {
+		lport->point_to_multipoint = 1;
+		lport->tt.disc_recv_req = fcoe_ctlr_disc_recv;
+		lport->tt.disc_start = fcoe_ctlr_disc_start;
+		lport->tt.disc_stop = fcoe_ctlr_disc_stop;
+		lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final;
+		mutex_init(&lport->disc.disc_mutex);
+		INIT_LIST_HEAD(&lport->disc.rports);
+		lport->disc.priv = fip;
+	} else {
+		fc_disc_init(lport);
+	}
 	return 0;
 }
 EXPORT_SYMBOL_GPL(fcoe_libfc_config);
-
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index 265e73d..9eb7a9e 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -617,7 +617,6 @@
 	fnic->ctlr.send = fnic_eth_send;
 	fnic->ctlr.update_mac = fnic_update_mac;
 	fnic->ctlr.get_src_addr = fnic_get_mac;
-	fcoe_ctlr_init(&fnic->ctlr);
 	if (fnic->config.flags & VFCF_FIP_CAPABLE) {
 		shost_printk(KERN_INFO, fnic->lport->host,
 			     "firmware supports FIP\n");
@@ -625,10 +624,11 @@
 		vnic_dev_packet_filter(fnic->vdev, 1, 1, 0, 0, 0);
 		vnic_dev_add_addr(fnic->vdev, FIP_ALL_ENODE_MACS);
 		vnic_dev_add_addr(fnic->vdev, fnic->ctlr.ctl_src_addr);
+		fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_AUTO);
 	} else {
 		shost_printk(KERN_INFO, fnic->lport->host,
 			     "firmware uses non-FIP mode\n");
-		fnic->ctlr.mode = FIP_ST_NON_FIP;
+		fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_NON_FIP);
 	}
 	fnic->state = FNIC_IN_FC_MODE;
 
@@ -673,7 +673,6 @@
 	/* Start local port initiatialization */
 
 	lp->link_up = 0;
-	lp->tt = fnic_transport_template;
 
 	lp->max_retry_count = fnic->config.flogi_retries;
 	lp->max_rport_retry_count = fnic->config.plogi_retries;
@@ -689,11 +688,7 @@
 	fc_set_wwnn(lp, fnic->config.node_wwn);
 	fc_set_wwpn(lp, fnic->config.port_wwn);
 
-	fc_lport_init(lp);
-	fc_exch_init(lp);
-	fc_elsct_init(lp);
-	fc_rport_init(lp);
-	fc_disc_init(lp);
+	fcoe_libfc_config(lp, &fnic->ctlr, &fnic_transport_template, 0);
 
 	if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START,
 			       FCPIO_HOST_EXCH_RANGE_END, NULL)) {
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
index 3cc47c6..198cbab 100644
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -1246,11 +1246,10 @@
 	lp = shost_priv(sc->device->host);
 
 	fnic = lport_priv(lp);
-	FNIC_SCSI_DBG(KERN_DEBUG,
-		      fnic->lport->host,
-		      "Abort Cmd called FCID 0x%x, LUN 0x%x TAG %d\n",
-		      (starget_to_rport(scsi_target(sc->device)))->port_id,
-		      sc->device->lun, sc->request->tag);
+	rport = starget_to_rport(scsi_target(sc->device));
+	FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+			"Abort Cmd called FCID 0x%x, LUN 0x%x TAG %d\n",
+			rport->port_id, sc->device->lun, sc->request->tag);
 
 	if (lp->state != LPORT_ST_READY || !(lp->link_up)) {
 		ret = FAILED;
@@ -1299,7 +1298,6 @@
 	 * port is up, then send abts to the remote port to terminate
 	 * the IO. Else, just locally terminate the IO in the firmware
 	 */
-	rport = starget_to_rport(scsi_target(sc->device));
 	if (fc_remote_port_chkready(rport) == 0)
 		task_req = FCPIO_ITMF_ABT_TASK;
 	else
@@ -1418,7 +1416,6 @@
 	unsigned long flags;
 	int ret = 0;
 	struct scsi_cmnd *sc;
-	struct fc_rport *rport;
 	struct scsi_lun fc_lun;
 	struct scsi_device *lun_dev = lr_sc->device;
 	DECLARE_COMPLETION_ONSTACK(tm_done);
@@ -1458,7 +1455,6 @@
 
 		/* Now queue the abort command to firmware */
 		int_to_scsilun(sc->device->lun, &fc_lun);
-		rport = starget_to_rport(scsi_target(sc->device));
 
 		if (fnic_queue_abort_io_req(fnic, tag,
 					    FCPIO_ITMF_ABT_TASK_TERM,
@@ -1528,18 +1524,16 @@
 	lp = shost_priv(sc->device->host);
 
 	fnic = lport_priv(lp);
-	FNIC_SCSI_DBG(KERN_DEBUG,
-		      fnic->lport->host,
-		      "Device reset called FCID 0x%x, LUN 0x%x\n",
-		      (starget_to_rport(scsi_target(sc->device)))->port_id,
-		      sc->device->lun);
 
+	rport = starget_to_rport(scsi_target(sc->device));
+	FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+			"Device reset called FCID 0x%x, LUN 0x%x\n",
+			rport->port_id, sc->device->lun);
 
 	if (lp->state != LPORT_ST_READY || !(lp->link_up))
 		goto fnic_device_reset_end;
 
 	/* Check if remote port up */
-	rport = starget_to_rport(scsi_target(sc->device));
 	if (fc_remote_port_chkready(rport))
 		goto fnic_device_reset_end;
 
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 6660fa9..8a8f803 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -32,6 +32,7 @@
 #include <linux/completion.h>
 #include <linux/transport_class.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
@@ -156,6 +157,7 @@
 void scsi_remove_host(struct Scsi_Host *shost)
 {
 	unsigned long flags;
+
 	mutex_lock(&shost->scan_mutex);
 	spin_lock_irqsave(shost->host_lock, flags);
 	if (scsi_host_set_state(shost, SHOST_CANCEL))
@@ -165,6 +167,8 @@
 			return;
 		}
 	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	scsi_autopm_get_host(shost);
 	scsi_forget_host(shost);
 	mutex_unlock(&shost->scan_mutex);
 	scsi_proc_host_rm(shost);
@@ -216,12 +220,14 @@
 		shost->shost_gendev.parent = dev ? dev : &platform_bus;
 	shost->dma_dev = dma_dev;
 
-	device_enable_async_suspend(&shost->shost_gendev);
-
 	error = device_add(&shost->shost_gendev);
 	if (error)
 		goto out;
 
+	pm_runtime_set_active(&shost->shost_gendev);
+	pm_runtime_enable(&shost->shost_gendev);
+	device_enable_async_suspend(&shost->shost_gendev);
+
 	scsi_host_set_state(shost, SHOST_RUNNING);
 	get_device(shost->shost_gendev.parent);
 
@@ -325,7 +331,6 @@
 {
 	struct Scsi_Host *shost;
 	gfp_t gfp_mask = GFP_KERNEL;
-	int rval;
 
 	if (sht->unchecked_isa_dma && privsize)
 		gfp_mask |= __GFP_DMA;
@@ -420,7 +425,8 @@
 	shost->ehandler = kthread_run(scsi_error_handler, shost,
 			"scsi_eh_%d", shost->host_no);
 	if (IS_ERR(shost->ehandler)) {
-		rval = PTR_ERR(shost->ehandler);
+		printk(KERN_WARNING "scsi%d: error handler thread failed to spawn, error = %ld\n",
+			shost->host_no, PTR_ERR(shost->ehandler));
 		goto fail_kfree;
 	}
 
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index c016426b..4f5551b 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -86,10 +86,17 @@
 	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324a},
 	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324b},
 	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3233},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3250},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3251},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3252},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3253},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3254},
 #define PCI_DEVICE_ID_HP_CISSF 0x333f
 	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x333F},
 	{PCI_VENDOR_ID_HP,     PCI_ANY_ID,             PCI_ANY_ID, PCI_ANY_ID,
 		PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
+	{PCI_VENDOR_ID_COMPAQ,     PCI_ANY_ID,             PCI_ANY_ID, PCI_ANY_ID,
+		PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
 	{0,}
 };
 
@@ -109,12 +116,18 @@
 	{0x324b103C, "Smart Array P711m", &SA5_access},
 	{0x3233103C, "StorageWorks P1210m", &SA5_access},
 	{0x333F103C, "StorageWorks P1210m", &SA5_access},
+	{0x3250103C, "Smart Array", &SA5_access},
+	{0x3250113C, "Smart Array", &SA5_access},
+	{0x3250123C, "Smart Array", &SA5_access},
+	{0x3250133C, "Smart Array", &SA5_access},
+	{0x3250143C, "Smart Array", &SA5_access},
 	{0xFFFF103C, "Unknown Smart Array", &SA5_access},
 };
 
 static int number_of_controllers;
 
-static irqreturn_t do_hpsa_intr(int irq, void *dev_id);
+static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id);
+static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id);
 static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg);
 static void start_io(struct ctlr_info *h);
 
@@ -148,6 +161,8 @@
 	struct device_attribute *attr, char *buf);
 static ssize_t unique_id_show(struct device *dev,
 	struct device_attribute *attr, char *buf);
+static ssize_t host_show_firmware_revision(struct device *dev,
+	     struct device_attribute *attr, char *buf);
 static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno);
 static ssize_t host_store_rescan(struct device *dev,
 	 struct device_attribute *attr, const char *buf, size_t count);
@@ -158,13 +173,21 @@
 /* performant mode helper functions */
 static void calc_bucket_map(int *bucket, int num_buckets,
 	int nsgs, int *bucket_map);
-static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
+static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
 static inline u32 next_command(struct ctlr_info *h);
+static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
+	void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+	u64 *cfg_offset);
+static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
+	unsigned long *memory_bar);
+static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
 
 static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
 static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
 static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL);
 static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
+static DEVICE_ATTR(firmware_revision, S_IRUGO,
+	host_show_firmware_revision, NULL);
 
 static struct device_attribute *hpsa_sdev_attrs[] = {
 	&dev_attr_raid_level,
@@ -175,6 +198,7 @@
 
 static struct device_attribute *hpsa_shost_attrs[] = {
 	&dev_attr_rescan,
+	&dev_attr_firmware_revision,
 	NULL,
 };
 
@@ -260,6 +284,21 @@
 	return count;
 }
 
+static ssize_t host_show_firmware_revision(struct device *dev,
+	     struct device_attribute *attr, char *buf)
+{
+	struct ctlr_info *h;
+	struct Scsi_Host *shost = class_to_shost(dev);
+	unsigned char *fwrev;
+
+	h = shost_to_hba(shost);
+	if (!h->hba_inquiry_data)
+		return 0;
+	fwrev = &h->hba_inquiry_data[32];
+	return snprintf(buf, 20, "%c%c%c%c\n",
+		fwrev[0], fwrev[1], fwrev[2], fwrev[3]);
+}
+
 /* Enqueuing and dequeuing functions for cmdlists. */
 static inline void addQ(struct hlist_head *list, struct CommandList *c)
 {
@@ -1440,12 +1479,6 @@
 		goto bail_out;
 	}
 
-	/* As a side effect, record the firmware version number
-	 * if we happen to be talking to the RAID controller.
-	 */
-	if (is_hba_lunid(scsi3addr))
-		memcpy(h->firm_ver, &inq_buff[32], 4);
-
 	this_device->devtype = (inq_buff[0] & 0x1f);
 	memcpy(this_device->scsi3addr, scsi3addr, 8);
 	memcpy(this_device->vendor, &inq_buff[8],
@@ -2826,9 +2859,8 @@
 
 static inline long interrupt_not_for_us(struct ctlr_info *h)
 {
-	return !(h->msi_vector || h->msix_vector) &&
-		((h->access.intr_pending(h) == 0) ||
-		(h->interrupts_enabled == 0));
+	return (h->access.intr_pending(h) == 0) ||
+		(h->interrupts_enabled == 0);
 }
 
 static inline int bad_tag(struct ctlr_info *h, u32 tag_index,
@@ -2902,7 +2934,7 @@
 	return next_command(h);
 }
 
-static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
+static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id)
 {
 	struct ctlr_info *h = dev_id;
 	unsigned long flags;
@@ -2911,6 +2943,26 @@
 	if (interrupt_not_for_us(h))
 		return IRQ_NONE;
 	spin_lock_irqsave(&h->lock, flags);
+	while (interrupt_pending(h)) {
+		raw_tag = get_next_completion(h);
+		while (raw_tag != FIFO_EMPTY) {
+			if (hpsa_tag_contains_index(raw_tag))
+				raw_tag = process_indexed_cmd(h, raw_tag);
+			else
+				raw_tag = process_nonindexed_cmd(h, raw_tag);
+		}
+	}
+	spin_unlock_irqrestore(&h->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id)
+{
+	struct ctlr_info *h = dev_id;
+	unsigned long flags;
+	u32 raw_tag;
+
+	spin_lock_irqsave(&h->lock, flags);
 	raw_tag = get_next_completion(h);
 	while (raw_tag != FIFO_EMPTY) {
 		if (hpsa_tag_contains_index(raw_tag))
@@ -3052,17 +3104,75 @@
 	return 0;
 }
 
-/* This does a hard reset of the controller using PCI power management
- * states.
- */
-static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
+static int hpsa_controller_hard_reset(struct pci_dev *pdev,
+	void * __iomem vaddr, bool use_doorbell)
 {
-	u16 pmcsr, saved_config_space[32];
-	int i, pos;
+	u16 pmcsr;
+	int pos;
 
-	dev_info(&pdev->dev, "using PCI PM to reset controller\n");
+	if (use_doorbell) {
+		/* For everything after the P600, the PCI power state method
+		 * of resetting the controller doesn't work, so we have this
+		 * other way using the doorbell register.
+		 */
+		dev_info(&pdev->dev, "using doorbell to reset controller\n");
+		writel(DOORBELL_CTLR_RESET, vaddr + SA5_DOORBELL);
+		msleep(1000);
+	} else { /* Try to do it the PCI power state way */
 
-	/* This is very nearly the same thing as
+		/* Quoting from the Open CISS Specification: "The Power
+		 * Management Control/Status Register (CSR) controls the power
+		 * state of the device.  The normal operating state is D0,
+		 * CSR=00h.  The software off state is D3, CSR=03h.  To reset
+		 * the controller, place the interface device in D3 then to D0,
+		 * this causes a secondary PCI reset which will reset the
+		 * controller." */
+
+		pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
+		if (pos == 0) {
+			dev_err(&pdev->dev,
+				"hpsa_reset_controller: "
+				"PCI PM not supported\n");
+			return -ENODEV;
+		}
+		dev_info(&pdev->dev, "using PCI PM to reset controller\n");
+		/* enter the D3hot power management state */
+		pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
+		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+		pmcsr |= PCI_D3hot;
+		pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+		msleep(500);
+
+		/* enter the D0 power management state */
+		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+		pmcsr |= PCI_D0;
+		pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+		msleep(500);
+	}
+	return 0;
+}
+
+/* This does a hard reset of the controller using PCI power management
+ * states or the using the doorbell register.
+ */
+static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
+{
+	u16 saved_config_space[32];
+	u64 cfg_offset;
+	u32 cfg_base_addr;
+	u64 cfg_base_addr_index;
+	void __iomem *vaddr;
+	unsigned long paddr;
+	u32 misc_fw_support, active_transport;
+	int rc, i;
+	struct CfgTable __iomem *cfgtable;
+	bool use_doorbell;
+	u32 board_id;
+
+	/* For controllers as old as the P600, this is very nearly
+	 * the same thing as
 	 *
 	 * pci_save_state(pci_dev);
 	 * pci_set_power_state(pci_dev, PCI_D3hot);
@@ -3076,41 +3186,54 @@
 	 * violate the ordering requirements for restoring the
 	 * configuration space from the CCISS document (see the
 	 * comment below).  So we roll our own ....
+	 *
+	 * For controllers newer than the P600, the pci power state
+	 * method of resetting doesn't work so we have another way
+	 * using the doorbell register.
 	 */
 
+	/* Exclude 640x boards.  These are two pci devices in one slot
+	 * which share a battery backed cache module.  One controls the
+	 * cache, the other accesses the cache through the one that controls
+	 * it.  If we reset the one controlling the cache, the other will
+	 * likely not be happy.  Just forbid resetting this conjoined mess.
+	 * The 640x isn't really supported by hpsa anyway.
+	 */
+	hpsa_lookup_board_id(pdev, &board_id);
+	if (board_id == 0x409C0E11 || board_id == 0x409D0E11)
+		return -ENOTSUPP;
+
 	for (i = 0; i < 32; i++)
 		pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
 
-	pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
-	if (pos == 0) {
-		dev_err(&pdev->dev,
-			"hpsa_reset_controller: PCI PM not supported\n");
-		return -ENODEV;
+
+	/* find the first memory BAR, so we can find the cfg table */
+	rc = hpsa_pci_find_memory_BAR(pdev, &paddr);
+	if (rc)
+		return rc;
+	vaddr = remap_pci_mem(paddr, 0x250);
+	if (!vaddr)
+		return -ENOMEM;
+
+	/* find cfgtable in order to check if reset via doorbell is supported */
+	rc = hpsa_find_cfg_addrs(pdev, vaddr, &cfg_base_addr,
+					&cfg_base_addr_index, &cfg_offset);
+	if (rc)
+		goto unmap_vaddr;
+	cfgtable = remap_pci_mem(pci_resource_start(pdev,
+		       cfg_base_addr_index) + cfg_offset, sizeof(*cfgtable));
+	if (!cfgtable) {
+		rc = -ENOMEM;
+		goto unmap_vaddr;
 	}
 
-	/* Quoting from the Open CISS Specification: "The Power
-	 * Management Control/Status Register (CSR) controls the power
-	 * state of the device.  The normal operating state is D0,
-	 * CSR=00h.  The software off state is D3, CSR=03h.  To reset
-	 * the controller, place the interface device in D3 then to
-	 * D0, this causes a secondary PCI reset which will reset the
-	 * controller."
-	 */
+	/* If reset via doorbell register is supported, use that. */
+	misc_fw_support = readl(&cfgtable->misc_fw_support);
+	use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
 
-	/* enter the D3hot power management state */
-	pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
-	pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
-	pmcsr |= PCI_D3hot;
-	pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
-
-	msleep(500);
-
-	/* enter the D0 power management state */
-	pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
-	pmcsr |= PCI_D0;
-	pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
-
-	msleep(500);
+	rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell);
+	if (rc)
+		goto unmap_cfgtable;
 
 	/* Restore the PCI configuration space.  The Open CISS
 	 * Specification says, "Restore the PCI Configuration
@@ -3127,7 +3250,29 @@
 	wmb();
 	pci_write_config_word(pdev, 4, saved_config_space[2]);
 
-	return 0;
+	/* Some devices (notably the HP Smart Array 5i Controller)
+	   need a little pause here */
+	msleep(HPSA_POST_RESET_PAUSE_MSECS);
+
+	/* Controller should be in simple mode at this point.  If it's not,
+	 * It means we're on one of those controllers which doesn't support
+	 * the doorbell reset method and on which the PCI power management reset
+	 * method doesn't work (P800, for example.)
+	 * In those cases, pretend the reset worked and hope for the best.
+	 */
+	active_transport = readl(&cfgtable->TransportActive);
+	if (active_transport & PERFORMANT_MODE) {
+		dev_warn(&pdev->dev, "Unable to successfully reset controller,"
+			" proceeding anyway.\n");
+		rc = -ENOTSUPP;
+	}
+
+unmap_cfgtable:
+	iounmap(cfgtable);
+
+unmap_vaddr:
+	iounmap(vaddr);
+	return rc;
 }
 
 /*
@@ -3135,9 +3280,9 @@
  *   the io functions.
  *   This is for debug only.
  */
-#ifdef HPSA_DEBUG
 static void print_cfg_table(struct device *dev, struct CfgTable *tb)
 {
+#ifdef HPSA_DEBUG
 	int i;
 	char temp_name[17];
 
@@ -3167,8 +3312,8 @@
 	dev_info(dev, "   Server Name = %s\n", temp_name);
 	dev_info(dev, "   Heartbeat Counter = 0x%x\n\n\n",
 		readl(&(tb->HeartBeat)));
-}
 #endif				/* HPSA_DEBUG */
+}
 
 static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
 {
@@ -3209,8 +3354,7 @@
  * controllers that are capable. If not, we use IO-APIC mode.
  */
 
-static void __devinit hpsa_interrupt_mode(struct ctlr_info *h,
-					   struct pci_dev *pdev, u32 board_id)
+static void __devinit hpsa_interrupt_mode(struct ctlr_info *h)
 {
 #ifdef CONFIG_PCI_MSI
 	int err;
@@ -3219,13 +3363,12 @@
 	};
 
 	/* Some boards advertise MSI but don't really support it */
-	if ((board_id == 0x40700E11) ||
-	    (board_id == 0x40800E11) ||
-	    (board_id == 0x40820E11) || (board_id == 0x40830E11))
+	if ((h->board_id == 0x40700E11) || (h->board_id == 0x40800E11) ||
+	    (h->board_id == 0x40820E11) || (h->board_id == 0x40830E11))
 		goto default_int_mode;
-	if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
-		dev_info(&pdev->dev, "MSIX\n");
-		err = pci_enable_msix(pdev, hpsa_msix_entries, 4);
+	if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
+		dev_info(&h->pdev->dev, "MSIX\n");
+		err = pci_enable_msix(h->pdev, hpsa_msix_entries, 4);
 		if (!err) {
 			h->intr[0] = hpsa_msix_entries[0].vector;
 			h->intr[1] = hpsa_msix_entries[1].vector;
@@ -3235,144 +3378,158 @@
 			return;
 		}
 		if (err > 0) {
-			dev_warn(&pdev->dev, "only %d MSI-X vectors "
+			dev_warn(&h->pdev->dev, "only %d MSI-X vectors "
 			       "available\n", err);
 			goto default_int_mode;
 		} else {
-			dev_warn(&pdev->dev, "MSI-X init failed %d\n",
+			dev_warn(&h->pdev->dev, "MSI-X init failed %d\n",
 			       err);
 			goto default_int_mode;
 		}
 	}
-	if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
-		dev_info(&pdev->dev, "MSI\n");
-		if (!pci_enable_msi(pdev))
+	if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) {
+		dev_info(&h->pdev->dev, "MSI\n");
+		if (!pci_enable_msi(h->pdev))
 			h->msi_vector = 1;
 		else
-			dev_warn(&pdev->dev, "MSI init failed\n");
+			dev_warn(&h->pdev->dev, "MSI init failed\n");
 	}
 default_int_mode:
 #endif				/* CONFIG_PCI_MSI */
 	/* if we get here we're going to use the default interrupt mode */
-	h->intr[PERF_MODE_INT] = pdev->irq;
+	h->intr[PERF_MODE_INT] = h->pdev->irq;
 }
 
-static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
+static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
 {
-	ushort subsystem_vendor_id, subsystem_device_id, command;
-	u32 board_id, scratchpad = 0;
+	int i;
+	u32 subsystem_vendor_id, subsystem_device_id;
+
+	subsystem_vendor_id = pdev->subsystem_vendor;
+	subsystem_device_id = pdev->subsystem_device;
+	*board_id = ((subsystem_device_id << 16) & 0xffff0000) |
+		    subsystem_vendor_id;
+
+	for (i = 0; i < ARRAY_SIZE(products); i++)
+		if (*board_id == products[i].board_id)
+			return i;
+
+	if ((subsystem_vendor_id != PCI_VENDOR_ID_HP &&
+		subsystem_vendor_id != PCI_VENDOR_ID_COMPAQ) ||
+		!hpsa_allow_any) {
+		dev_warn(&pdev->dev, "unrecognized board ID: "
+			"0x%08x, ignoring.\n", *board_id);
+			return -ENODEV;
+	}
+	return ARRAY_SIZE(products) - 1; /* generic unknown smart array */
+}
+
+static inline bool hpsa_board_disabled(struct pci_dev *pdev)
+{
+	u16 command;
+
+	(void) pci_read_config_word(pdev, PCI_COMMAND, &command);
+	return ((command & PCI_COMMAND_MEMORY) == 0);
+}
+
+static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
+	unsigned long *memory_bar)
+{
+	int i;
+
+	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
+		if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
+			/* addressing mode bits already removed */
+			*memory_bar = pci_resource_start(pdev, i);
+			dev_dbg(&pdev->dev, "memory BAR = %lx\n",
+				*memory_bar);
+			return 0;
+		}
+	dev_warn(&pdev->dev, "no memory BAR found\n");
+	return -ENODEV;
+}
+
+static int __devinit hpsa_wait_for_board_ready(struct ctlr_info *h)
+{
+	int i;
+	u32 scratchpad;
+
+	for (i = 0; i < HPSA_BOARD_READY_ITERATIONS; i++) {
+		scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
+		if (scratchpad == HPSA_FIRMWARE_READY)
+			return 0;
+		msleep(HPSA_BOARD_READY_POLL_INTERVAL_MSECS);
+	}
+	dev_warn(&h->pdev->dev, "board not ready, timed out.\n");
+	return -ENODEV;
+}
+
+static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
+	void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+	u64 *cfg_offset)
+{
+	*cfg_base_addr = readl(vaddr + SA5_CTCFG_OFFSET);
+	*cfg_offset = readl(vaddr + SA5_CTMEM_OFFSET);
+	*cfg_base_addr &= (u32) 0x0000ffff;
+	*cfg_base_addr_index = find_PCI_BAR_index(pdev, *cfg_base_addr);
+	if (*cfg_base_addr_index == -1) {
+		dev_warn(&pdev->dev, "cannot find cfg_base_addr_index\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int __devinit hpsa_find_cfgtables(struct ctlr_info *h)
+{
 	u64 cfg_offset;
 	u32 cfg_base_addr;
 	u64 cfg_base_addr_index;
 	u32 trans_offset;
-	int i, prod_index, err;
+	int rc;
 
-	subsystem_vendor_id = pdev->subsystem_vendor;
-	subsystem_device_id = pdev->subsystem_device;
-	board_id = (((u32) (subsystem_device_id << 16) & 0xffff0000) |
-		    subsystem_vendor_id);
-
-	for (i = 0; i < ARRAY_SIZE(products); i++)
-		if (board_id == products[i].board_id)
-			break;
-
-	prod_index = i;
-
-	if (prod_index == ARRAY_SIZE(products)) {
-		prod_index--;
-		if (subsystem_vendor_id != PCI_VENDOR_ID_HP ||
-				!hpsa_allow_any) {
-			dev_warn(&pdev->dev, "unrecognized board ID:"
-				" 0x%08lx, ignoring.\n",
-				(unsigned long) board_id);
-			return -ENODEV;
-		}
-	}
-	/* check to see if controller has been disabled
-	 * BEFORE trying to enable it
-	 */
-	(void)pci_read_config_word(pdev, PCI_COMMAND, &command);
-	if (!(command & 0x02)) {
-		dev_warn(&pdev->dev, "controller appears to be disabled\n");
-		return -ENODEV;
-	}
-
-	err = pci_enable_device(pdev);
-	if (err) {
-		dev_warn(&pdev->dev, "unable to enable PCI device\n");
-		return err;
-	}
-
-	err = pci_request_regions(pdev, "hpsa");
-	if (err) {
-		dev_err(&pdev->dev, "cannot obtain PCI resources, aborting\n");
-		return err;
-	}
-
-	/* If the kernel supports MSI/MSI-X we will try to enable that,
-	 * else we use the IO-APIC interrupt assigned to us by system ROM.
-	 */
-	hpsa_interrupt_mode(h, pdev, board_id);
-
-	/* find the memory BAR */
-	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
-		if (pci_resource_flags(pdev, i) & IORESOURCE_MEM)
-			break;
-	}
-	if (i == DEVICE_COUNT_RESOURCE) {
-		dev_warn(&pdev->dev, "no memory BAR found\n");
-		err = -ENODEV;
-		goto err_out_free_res;
-	}
-
-	h->paddr = pci_resource_start(pdev, i); /* addressing mode bits
-						 * already removed
-						 */
-
-	h->vaddr = remap_pci_mem(h->paddr, 0x250);
-
-	/* Wait for the board to become ready.  */
-	for (i = 0; i < HPSA_BOARD_READY_ITERATIONS; i++) {
-		scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
-		if (scratchpad == HPSA_FIRMWARE_READY)
-			break;
-		msleep(HPSA_BOARD_READY_POLL_INTERVAL_MSECS);
-	}
-	if (scratchpad != HPSA_FIRMWARE_READY) {
-		dev_warn(&pdev->dev, "board not ready, timed out.\n");
-		err = -ENODEV;
-		goto err_out_free_res;
-	}
-
-	/* get the address index number */
-	cfg_base_addr = readl(h->vaddr + SA5_CTCFG_OFFSET);
-	cfg_base_addr &= (u32) 0x0000ffff;
-	cfg_base_addr_index = find_PCI_BAR_index(pdev, cfg_base_addr);
-	if (cfg_base_addr_index == -1) {
-		dev_warn(&pdev->dev, "cannot find cfg_base_addr_index\n");
-		err = -ENODEV;
-		goto err_out_free_res;
-	}
-
-	cfg_offset = readl(h->vaddr + SA5_CTMEM_OFFSET);
-	h->cfgtable = remap_pci_mem(pci_resource_start(pdev,
-			       cfg_base_addr_index) + cfg_offset,
-				sizeof(h->cfgtable));
+	rc = hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr,
+		&cfg_base_addr_index, &cfg_offset);
+	if (rc)
+		return rc;
+	h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev,
+		       cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable));
+	if (!h->cfgtable)
+		return -ENOMEM;
 	/* Find performant mode table. */
-	trans_offset = readl(&(h->cfgtable->TransMethodOffset));
-	h->transtable = remap_pci_mem(pci_resource_start(pdev,
+	trans_offset = readl(&h->cfgtable->TransMethodOffset);
+	h->transtable = remap_pci_mem(pci_resource_start(h->pdev,
 				cfg_base_addr_index)+cfg_offset+trans_offset,
 				sizeof(*h->transtable));
+	if (!h->transtable)
+		return -ENOMEM;
+	return 0;
+}
 
-	h->board_id = board_id;
+static void __devinit hpsa_get_max_perf_mode_cmds(struct ctlr_info *h)
+{
 	h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
-	h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
+	if (h->max_commands < 16) {
+		dev_warn(&h->pdev->dev, "Controller reports "
+			"max supported commands of %d, an obvious lie. "
+			"Using 16.  Ensure that firmware is up to date.\n",
+			h->max_commands);
+		h->max_commands = 16;
+	}
+}
 
+/* Interrogate the hardware for some limits:
+ * max commands, max SG elements without chaining, and with chaining,
+ * SG chain block size, etc.
+ */
+static void __devinit hpsa_find_board_params(struct ctlr_info *h)
+{
+	hpsa_get_max_perf_mode_cmds(h);
+	h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
+	h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
 	/*
 	 * Limit in-command s/g elements to 32 save dma'able memory.
 	 * Howvever spec says if 0, use 31
 	 */
-
 	h->max_cmd_sg_entries = 31;
 	if (h->maxsgentries > 512) {
 		h->max_cmd_sg_entries = 32;
@@ -3382,45 +3539,49 @@
 		h->maxsgentries = 31; /* default to traditional values */
 		h->chainsize = 0;
 	}
+}
 
-	h->product_name = products[prod_index].product_name;
-	h->access = *(products[prod_index].access);
-	/* Allow room for some ioctls */
-	h->nr_cmds = h->max_commands - 4;
-
+static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
+{
 	if ((readb(&h->cfgtable->Signature[0]) != 'C') ||
 	    (readb(&h->cfgtable->Signature[1]) != 'I') ||
 	    (readb(&h->cfgtable->Signature[2]) != 'S') ||
 	    (readb(&h->cfgtable->Signature[3]) != 'S')) {
-		dev_warn(&pdev->dev, "not a valid CISS config table\n");
-		err = -ENODEV;
-		goto err_out_free_res;
+		dev_warn(&h->pdev->dev, "not a valid CISS config table\n");
+		return false;
 	}
+	return true;
+}
+
+/* Need to enable prefetch in the SCSI core for 6400 in x86 */
+static inline void hpsa_enable_scsi_prefetch(struct ctlr_info *h)
+{
 #ifdef CONFIG_X86
-	{
-		/* Need to enable prefetch in the SCSI core for 6400 in x86 */
-		u32 prefetch;
-		prefetch = readl(&(h->cfgtable->SCSI_Prefetch));
-		prefetch |= 0x100;
-		writel(prefetch, &(h->cfgtable->SCSI_Prefetch));
-	}
+	u32 prefetch;
+
+	prefetch = readl(&(h->cfgtable->SCSI_Prefetch));
+	prefetch |= 0x100;
+	writel(prefetch, &(h->cfgtable->SCSI_Prefetch));
 #endif
+}
 
-	/* Disabling DMA prefetch for the P600
-	 * An ASIC bug may result in a prefetch beyond
-	 * physical memory.
-	 */
-	if (board_id == 0x3225103C) {
-		u32 dma_prefetch;
-		dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG);
-		dma_prefetch |= 0x8000;
-		writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
-	}
+/* Disable DMA prefetch for the P600.  Otherwise an ASIC bug may result
+ * in a prefetch beyond physical memory.
+ */
+static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h)
+{
+	u32 dma_prefetch;
 
-	h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
-	/* Update the field, and then ring the doorbell */
-	writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
-	writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+	if (h->board_id != 0x3225103C)
+		return;
+	dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG);
+	dma_prefetch |= 0x8000;
+	writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
+}
+
+static void __devinit hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
+{
+	int i;
 
 	/* under certain very rare conditions, this can take awhile.
 	 * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
@@ -3432,24 +3593,96 @@
 		/* delay and try again */
 		msleep(10);
 	}
+}
 
-#ifdef HPSA_DEBUG
-	print_cfg_table(&pdev->dev, h->cfgtable);
-#endif				/* HPSA_DEBUG */
+static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h)
+{
+	u32 trans_support;
 
+	trans_support = readl(&(h->cfgtable->TransportSupport));
+	if (!(trans_support & SIMPLE_MODE))
+		return -ENOTSUPP;
+
+	h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
+	/* Update the field, and then ring the doorbell */
+	writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
+	writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+	hpsa_wait_for_mode_change_ack(h);
+	print_cfg_table(&h->pdev->dev, h->cfgtable);
 	if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
-		dev_warn(&pdev->dev, "unable to get board into simple mode\n");
+		dev_warn(&h->pdev->dev,
+			"unable to get board into simple mode\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int __devinit hpsa_pci_init(struct ctlr_info *h)
+{
+	int prod_index, err;
+
+	prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id);
+	if (prod_index < 0)
+		return -ENODEV;
+	h->product_name = products[prod_index].product_name;
+	h->access = *(products[prod_index].access);
+
+	if (hpsa_board_disabled(h->pdev)) {
+		dev_warn(&h->pdev->dev, "controller appears to be disabled\n");
+		return -ENODEV;
+	}
+	err = pci_enable_device(h->pdev);
+	if (err) {
+		dev_warn(&h->pdev->dev, "unable to enable PCI device\n");
+		return err;
+	}
+
+	err = pci_request_regions(h->pdev, "hpsa");
+	if (err) {
+		dev_err(&h->pdev->dev,
+			"cannot obtain PCI resources, aborting\n");
+		return err;
+	}
+	hpsa_interrupt_mode(h);
+	err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr);
+	if (err)
+		goto err_out_free_res;
+	h->vaddr = remap_pci_mem(h->paddr, 0x250);
+	if (!h->vaddr) {
+		err = -ENOMEM;
+		goto err_out_free_res;
+	}
+	err = hpsa_wait_for_board_ready(h);
+	if (err)
+		goto err_out_free_res;
+	err = hpsa_find_cfgtables(h);
+	if (err)
+		goto err_out_free_res;
+	hpsa_find_board_params(h);
+
+	if (!hpsa_CISS_signature_present(h)) {
 		err = -ENODEV;
 		goto err_out_free_res;
 	}
+	hpsa_enable_scsi_prefetch(h);
+	hpsa_p600_dma_prefetch_quirk(h);
+	err = hpsa_enter_simple_mode(h);
+	if (err)
+		goto err_out_free_res;
 	return 0;
 
 err_out_free_res:
+	if (h->transtable)
+		iounmap(h->transtable);
+	if (h->cfgtable)
+		iounmap(h->cfgtable);
+	if (h->vaddr)
+		iounmap(h->vaddr);
 	/*
 	 * Deliberately omit pci_disable_device(): it does something nasty to
 	 * Smart Array controllers that pci_enable_device does not undo
 	 */
-	pci_release_regions(pdev);
+	pci_release_regions(h->pdev);
 	return err;
 }
 
@@ -3469,33 +3702,51 @@
 	}
 }
 
+static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev)
+{
+	int rc, i;
+
+	if (!reset_devices)
+		return 0;
+
+	/* Reset the controller with a PCI power-cycle or via doorbell */
+	rc = hpsa_kdump_hard_reset_controller(pdev);
+
+	/* -ENOTSUPP here means we cannot reset the controller
+	 * but it's already (and still) up and running in
+	 * "performant mode".  Or, it might be 640x, which can't reset
+	 * due to concerns about shared bbwc between 6402/6404 pair.
+	 */
+	if (rc == -ENOTSUPP)
+		return 0; /* just try to do the kdump anyhow. */
+	if (rc)
+		return -ENODEV;
+	if (hpsa_reset_msi(pdev))
+		return -ENODEV;
+
+	/* Now try to get the controller to respond to a no-op */
+	for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
+		if (hpsa_noop(pdev) == 0)
+			break;
+		else
+			dev_warn(&pdev->dev, "no-op failed%s\n",
+					(i < 11 ? "; re-trying" : ""));
+	}
+	return 0;
+}
+
 static int __devinit hpsa_init_one(struct pci_dev *pdev,
 				    const struct pci_device_id *ent)
 {
-	int i, rc;
-	int dac;
+	int dac, rc;
 	struct ctlr_info *h;
 
 	if (number_of_controllers == 0)
 		printk(KERN_INFO DRIVER_NAME "\n");
-	if (reset_devices) {
-		/* Reset the controller with a PCI power-cycle */
-		if (hpsa_hard_reset_controller(pdev) || hpsa_reset_msi(pdev))
-			return -ENODEV;
 
-		/* Some devices (notably the HP Smart Array 5i Controller)
-		   need a little pause here */
-		msleep(HPSA_POST_RESET_PAUSE_MSECS);
-
-		/* Now try to get the controller to respond to a no-op */
-		for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
-			if (hpsa_noop(pdev) == 0)
-				break;
-			else
-				dev_warn(&pdev->dev, "no-op failed%s\n",
-						(i < 11 ? "; re-trying" : ""));
-		}
-	}
+	rc = hpsa_init_reset_devices(pdev);
+	if (rc)
+		return rc;
 
 	/* Command structures must be aligned on a 32-byte boundary because
 	 * the 5 lower bits of the address are used by the hardware. and by
@@ -3507,17 +3758,17 @@
 	if (!h)
 		return -ENOMEM;
 
+	h->pdev = pdev;
 	h->busy_initializing = 1;
 	INIT_HLIST_HEAD(&h->cmpQ);
 	INIT_HLIST_HEAD(&h->reqQ);
-	rc = hpsa_pci_init(h, pdev);
+	rc = hpsa_pci_init(h);
 	if (rc != 0)
 		goto clean1;
 
 	sprintf(h->devname, "hpsa%d", number_of_controllers);
 	h->ctlr = number_of_controllers;
 	number_of_controllers++;
-	h->pdev = pdev;
 
 	/* configure PCI DMA stuff */
 	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -3535,8 +3786,13 @@
 
 	/* make sure the board interrupts are off */
 	h->access.set_intr_mask(h, HPSA_INTR_OFF);
-	rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr,
-			IRQF_DISABLED, h->devname, h);
+
+	if (h->msix_vector || h->msi_vector)
+		rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_msi,
+				IRQF_DISABLED, h->devname, h);
+	else
+		rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_intx,
+				IRQF_DISABLED, h->devname, h);
 	if (rc) {
 		dev_err(&pdev->dev, "unable to get irq %d for %s\n",
 		       h->intr[PERF_MODE_INT], h->devname);
@@ -3663,6 +3919,8 @@
 	hpsa_unregister_scsi(h);	/* unhook from SCSI subsystem */
 	hpsa_shutdown(pdev);
 	iounmap(h->vaddr);
+	iounmap(h->transtable);
+	iounmap(h->cfgtable);
 	hpsa_free_sg_chain_blocks(h);
 	pci_free_consistent(h->pdev,
 		h->nr_cmds * sizeof(struct CommandList),
@@ -3742,38 +4000,35 @@
 	}
 }
 
-static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
+static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h)
 {
-	u32 trans_support;
-	u64 trans_offset;
+	int i;
+	unsigned long register_value;
+
+	/* This is a bit complicated.  There are 8 registers on
+	 * the controller which we write to to tell it 8 different
+	 * sizes of commands which there may be.  It's a way of
+	 * reducing the DMA done to fetch each command.  Encoded into
+	 * each command's tag are 3 bits which communicate to the controller
+	 * which of the eight sizes that command fits within.  The size of
+	 * each command depends on how many scatter gather entries there are.
+	 * Each SG entry requires 16 bytes.  The eight registers are programmed
+	 * with the number of 16-byte blocks a command of that size requires.
+	 * The smallest command possible requires 5 such 16 byte blocks.
+	 * the largest command possible requires MAXSGENTRIES + 4 16-byte
+	 * blocks.  Note, this only extends to the SG entries contained
+	 * within the command block, and does not extend to chained blocks
+	 * of SG elements.   bft[] contains the eight values we write to
+	 * the registers.  They are not evenly distributed, but have more
+	 * sizes for small commands, and fewer sizes for larger commands.
+	 */
+	int bft[8] = {5, 6, 8, 10, 12, 20, 28, MAXSGENTRIES + 4};
+	BUILD_BUG_ON(28 > MAXSGENTRIES + 4);
 	/*  5 = 1 s/g entry or 4k
 	 *  6 = 2 s/g entry or 8k
 	 *  8 = 4 s/g entry or 16k
 	 * 10 = 6 s/g entry or 24k
 	 */
-	int bft[8] = {5, 6, 8, 10, 12, 20, 28, 35}; /* for scatter/gathers */
-	int i = 0;
-	int l = 0;
-	unsigned long register_value;
-
-	trans_support = readl(&(h->cfgtable->TransportSupport));
-	if (!(trans_support & PERFORMANT_MODE))
-		return;
-
-	h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
-	h->max_sg_entries = 32;
-	/* Performant mode ring buffer and supporting data structures */
-	h->reply_pool_size = h->max_commands * sizeof(u64);
-	h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size,
-				&(h->reply_pool_dhandle));
-
-	/* Need a block fetch table for performant mode */
-	h->blockFetchTable = kmalloc(((h->max_sg_entries+1) *
-				sizeof(u32)), GFP_KERNEL);
-
-	if ((h->reply_pool == NULL)
-		|| (h->blockFetchTable == NULL))
-		goto clean_up;
 
 	h->reply_pool_wraparound = 1; /* spec: init to 1 */
 
@@ -3781,7 +4036,6 @@
 	memset(h->reply_pool, 0, h->reply_pool_size);
 	h->reply_pool_head = h->reply_pool;
 
-	trans_offset = readl(&(h->cfgtable->TransMethodOffset));
 	bft[7] = h->max_sg_entries + 4;
 	calc_bucket_map(bft, ARRAY_SIZE(bft), 32, h->blockFetchTable);
 	for (i = 0; i < 8; i++)
@@ -3797,23 +4051,39 @@
 	writel(CFGTBL_Trans_Performant,
 		&(h->cfgtable->HostWrite.TransportRequest));
 	writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
-	/* under certain very rare conditions, this can take awhile.
-	 * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
-	 * as we enter this code.) */
-	for (l = 0; l < MAX_CONFIG_WAIT; l++) {
-		register_value = readl(h->vaddr + SA5_DOORBELL);
-		if (!(register_value & CFGTBL_ChangeReq))
-			break;
-		/* delay and try again */
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(10);
-	}
+	hpsa_wait_for_mode_change_ack(h);
 	register_value = readl(&(h->cfgtable->TransportActive));
 	if (!(register_value & CFGTBL_Trans_Performant)) {
 		dev_warn(&h->pdev->dev, "unable to get board into"
 					" performant mode\n");
 		return;
 	}
+}
+
+static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
+{
+	u32 trans_support;
+
+	trans_support = readl(&(h->cfgtable->TransportSupport));
+	if (!(trans_support & PERFORMANT_MODE))
+		return;
+
+	hpsa_get_max_perf_mode_cmds(h);
+	h->max_sg_entries = 32;
+	/* Performant mode ring buffer and supporting data structures */
+	h->reply_pool_size = h->max_commands * sizeof(u64);
+	h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size,
+				&(h->reply_pool_dhandle));
+
+	/* Need a block fetch table for performant mode */
+	h->blockFetchTable = kmalloc(((h->max_sg_entries+1) *
+				sizeof(u32)), GFP_KERNEL);
+
+	if ((h->reply_pool == NULL)
+		|| (h->blockFetchTable == NULL))
+		goto clean_up;
+
+	hpsa_enter_performant_mode(h);
 
 	/* Change the access methods to the performant access methods */
 	h->access = SA5_performant_access;
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 1bb5233..a203ef6 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -53,7 +53,6 @@
 	int	ctlr;
 	char	devname[8];
 	char    *product_name;
-	char	firm_ver[4]; /* Firmware version */
 	struct pci_dev *pdev;
 	u32	board_id;
 	void __iomem *vaddr;
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 78de9b6..f5c4c3c 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -100,6 +100,7 @@
 /* Configuration Table */
 #define CFGTBL_ChangeReq        0x00000001l
 #define CFGTBL_AccCmds          0x00000001l
+#define DOORBELL_CTLR_RESET	0x00000004l
 
 #define CFGTBL_Trans_Simple     0x00000002l
 #define CFGTBL_Trans_Performant 0x00000004l
@@ -339,6 +340,9 @@
 	u32		MaxPhysicalDevices;
 	u32		MaxPhysicalDrivesPerLogicalUnit;
 	u32		MaxPerformantModeCommands;
+	u8		reserved[0x78 - 0x58];
+	u32		misc_fw_support; /* offset 0x78 */
+#define			MISC_FW_DOORBELL_RESET (0x02)
 };
 
 #define NUM_BLOCKFETCH_ENTRIES 8
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 645f7cd..0729f15 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -1157,7 +1157,7 @@
 disable_pci_device:
 	pci_disable_device(pcidev);
 
-	dprintk("scsi%d: hptiop_probe fail\n", host->host_no);
+	dprintk("scsi%d: hptiop_probe fail\n", host ? host->host_no : 0);
 	return -ENODEV;
 }
 
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index fef4952..bd96cec 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -504,12 +504,23 @@
 		if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS)
 			vhost->action = action;
 		break;
-	case IBMVFC_HOST_ACTION_LOGO:
 	case IBMVFC_HOST_ACTION_INIT:
 	case IBMVFC_HOST_ACTION_TGT_DEL:
+		switch (vhost->action) {
+		case IBMVFC_HOST_ACTION_RESET:
+		case IBMVFC_HOST_ACTION_REENABLE:
+			break;
+		default:
+			vhost->action = action;
+			break;
+		};
+		break;
+	case IBMVFC_HOST_ACTION_LOGO:
 	case IBMVFC_HOST_ACTION_QUERY_TGTS:
 	case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
 	case IBMVFC_HOST_ACTION_NONE:
+	case IBMVFC_HOST_ACTION_RESET:
+	case IBMVFC_HOST_ACTION_REENABLE:
 	default:
 		vhost->action = action;
 		break;
@@ -641,7 +652,7 @@
  **/
 static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
 {
-	long rc;
+	long rc = 0;
 	struct vio_dev *vdev = to_vio_dev(vhost->dev);
 	struct ibmvfc_crq_queue *crq = &vhost->crq;
 
@@ -649,6 +660,8 @@
 	free_irq(vdev->irq, vhost);
 	tasklet_kill(&vhost->tasklet);
 	do {
+		if (rc)
+			msleep(100);
 		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
 	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
 
@@ -667,11 +680,13 @@
  **/
 static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)
 {
-	int rc;
+	int rc = 0;
 	struct vio_dev *vdev = to_vio_dev(vhost->dev);
 
 	/* Re-enable the CRQ */
 	do {
+		if (rc)
+			msleep(100);
 		rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
 	} while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
 
@@ -690,15 +705,19 @@
  **/
 static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
 {
-	int rc;
+	int rc = 0;
+	unsigned long flags;
 	struct vio_dev *vdev = to_vio_dev(vhost->dev);
 	struct ibmvfc_crq_queue *crq = &vhost->crq;
 
 	/* Close the CRQ */
 	do {
+		if (rc)
+			msleep(100);
 		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
 	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
 
+	spin_lock_irqsave(vhost->host->host_lock, flags);
 	vhost->state = IBMVFC_NO_CRQ;
 	vhost->logged_in = 0;
 	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
@@ -716,6 +735,7 @@
 		dev_warn(vhost->dev, "Partner adapter not ready\n");
 	else if (rc != 0)
 		dev_warn(vhost->dev, "Couldn't register crq (rc=%d)\n", rc);
+	spin_unlock_irqrestore(vhost->host->host_lock, flags);
 
 	return rc;
 }
@@ -821,17 +841,9 @@
  **/
 static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost)
 {
-	int rc;
-
-	scsi_block_requests(vhost->host);
 	ibmvfc_purge_requests(vhost, DID_ERROR);
-	if ((rc = ibmvfc_reset_crq(vhost)) ||
-	    (rc = ibmvfc_send_crq_init(vhost)) ||
-	    (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) {
-		dev_err(vhost->dev, "Error after reset rc=%d\n", rc);
-		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
-	} else
-		ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+	ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET);
 }
 
 /**
@@ -2299,6 +2311,7 @@
 	int rc = FAILED;
 
 	ENTER;
+	fc_block_scsi_eh(cmd);
 	ibmvfc_wait_while_resetting(vhost);
 	cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET);
 	abort_rc = ibmvfc_abort_task_set(sdev);
@@ -2325,6 +2338,7 @@
 	int rc = FAILED;
 
 	ENTER;
+	fc_block_scsi_eh(cmd);
 	ibmvfc_wait_while_resetting(vhost);
 	cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_LUN_RESET);
 	reset_rc = ibmvfc_reset_device(sdev, IBMVFC_LUN_RESET, "LUN");
@@ -2389,6 +2403,7 @@
 	unsigned long cancel_rc = 0;
 
 	ENTER;
+	fc_block_scsi_eh(cmd);
 	ibmvfc_wait_while_resetting(vhost);
 	starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all_reset);
 	reset_rc = ibmvfc_reset_device(sdev, IBMVFC_TARGET_RESET, "target");
@@ -2410,6 +2425,7 @@
 	int rc;
 	struct ibmvfc_host *vhost = shost_priv(cmd->device->host);
 
+	fc_block_scsi_eh(cmd);
 	dev_err(vhost->dev, "Resetting connection due to error recovery\n");
 	rc = ibmvfc_issue_fc_host_lip(vhost->host);
 	return rc ? FAILED : SUCCESS;
@@ -2606,22 +2622,13 @@
 			dev_info(vhost->dev, "Re-enabling adapter\n");
 			vhost->client_migrated = 1;
 			ibmvfc_purge_requests(vhost, DID_REQUEUE);
-			if ((rc = ibmvfc_reenable_crq_queue(vhost)) ||
-			    (rc = ibmvfc_send_crq_init(vhost))) {
-				ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
-				dev_err(vhost->dev, "Error after enable (rc=%ld)\n", rc);
-			} else
-				ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+			ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_REENABLE);
 		} else {
 			dev_err(vhost->dev, "Virtual adapter failed (rc=%d)\n", crq->format);
-
 			ibmvfc_purge_requests(vhost, DID_ERROR);
-			if ((rc = ibmvfc_reset_crq(vhost)) ||
-			    (rc = ibmvfc_send_crq_init(vhost))) {
-				ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
-				dev_err(vhost->dev, "Error after reset (rc=%ld)\n", rc);
-			} else
-				ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+			ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET);
 		}
 		return;
 	case IBMVFC_CRQ_CMD_RSP:
@@ -4123,6 +4130,8 @@
 	case IBMVFC_HOST_ACTION_TGT_DEL:
 	case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
 	case IBMVFC_HOST_ACTION_QUERY:
+	case IBMVFC_HOST_ACTION_RESET:
+	case IBMVFC_HOST_ACTION_REENABLE:
 	default:
 		break;
 	};
@@ -4220,6 +4229,7 @@
 	struct ibmvfc_target *tgt;
 	unsigned long flags;
 	struct fc_rport *rport;
+	int rc;
 
 	ibmvfc_log_ae(vhost, vhost->events_to_log);
 	spin_lock_irqsave(vhost->host->host_lock, flags);
@@ -4229,6 +4239,27 @@
 	case IBMVFC_HOST_ACTION_LOGO_WAIT:
 	case IBMVFC_HOST_ACTION_INIT_WAIT:
 		break;
+	case IBMVFC_HOST_ACTION_RESET:
+		vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
+		spin_unlock_irqrestore(vhost->host->host_lock, flags);
+		rc = ibmvfc_reset_crq(vhost);
+		spin_lock_irqsave(vhost->host->host_lock, flags);
+		if (rc || (rc = ibmvfc_send_crq_init(vhost)) ||
+		    (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) {
+			ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+			dev_err(vhost->dev, "Error after reset (rc=%d)\n", rc);
+		}
+		break;
+	case IBMVFC_HOST_ACTION_REENABLE:
+		vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
+		spin_unlock_irqrestore(vhost->host->host_lock, flags);
+		rc = ibmvfc_reenable_crq_queue(vhost);
+		spin_lock_irqsave(vhost->host->host_lock, flags);
+		if (rc || (rc = ibmvfc_send_crq_init(vhost))) {
+			ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+			dev_err(vhost->dev, "Error after enable (rc=%d)\n", rc);
+		}
+		break;
 	case IBMVFC_HOST_ACTION_LOGO:
 		vhost->job_step(vhost);
 		break;
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index 7e97427..d7e8dcd 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -29,8 +29,8 @@
 #include "viosrp.h"
 
 #define IBMVFC_NAME	"ibmvfc"
-#define IBMVFC_DRIVER_VERSION		"1.0.7"
-#define IBMVFC_DRIVER_DATE		"(October 16, 2009)"
+#define IBMVFC_DRIVER_VERSION		"1.0.8"
+#define IBMVFC_DRIVER_DATE		"(June 17, 2010)"
 
 #define IBMVFC_DEFAULT_TIMEOUT	60
 #define IBMVFC_ADISC_CANCEL_TIMEOUT	45
@@ -649,6 +649,8 @@
 
 enum ibmvfc_host_action {
 	IBMVFC_HOST_ACTION_NONE = 0,
+	IBMVFC_HOST_ACTION_RESET,
+	IBMVFC_HOST_ACTION_REENABLE,
 	IBMVFC_HOST_ACTION_LOGO,
 	IBMVFC_HOST_ACTION_LOGO_WAIT,
 	IBMVFC_HOST_ACTION_INIT,
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index aad35cc..67f78a4 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -73,6 +73,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/pm.h>
+#include <linux/kthread.h>
 #include <asm/firmware.h>
 #include <asm/vio.h>
 #include <scsi/scsi.h>
@@ -101,7 +102,7 @@
 
 static struct scsi_transport_template *ibmvscsi_transport_template;
 
-#define IBMVSCSI_VERSION "1.5.8"
+#define IBMVSCSI_VERSION "1.5.9"
 
 static struct ibmvscsi_ops *ibmvscsi_ops;
 
@@ -473,23 +474,26 @@
  */
 static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
 {
-	struct srp_event_struct *tmp_evt, *pos;
+	struct srp_event_struct *evt;
 	unsigned long flags;
 
 	spin_lock_irqsave(hostdata->host->host_lock, flags);
-	list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
-		list_del(&tmp_evt->list);
-		del_timer(&tmp_evt->timer);
-		if (tmp_evt->cmnd) {
-			tmp_evt->cmnd->result = (error_code << 16);
-			unmap_cmd_data(&tmp_evt->iu.srp.cmd,
-				       tmp_evt,
-				       tmp_evt->hostdata->dev);
-			if (tmp_evt->cmnd_done)
-				tmp_evt->cmnd_done(tmp_evt->cmnd);
-		} else if (tmp_evt->done)
-			tmp_evt->done(tmp_evt);
-		free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
+	while (!list_empty(&hostdata->sent)) {
+		evt = list_first_entry(&hostdata->sent, struct srp_event_struct, list);
+		list_del(&evt->list);
+		del_timer(&evt->timer);
+
+		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+		if (evt->cmnd) {
+			evt->cmnd->result = (error_code << 16);
+			unmap_cmd_data(&evt->iu.srp.cmd, evt,
+				       evt->hostdata->dev);
+			if (evt->cmnd_done)
+				evt->cmnd_done(evt->cmnd);
+		} else if (evt->done)
+			evt->done(evt);
+		free_event_struct(&evt->hostdata->pool, evt);
+		spin_lock_irqsave(hostdata->host->host_lock, flags);
 	}
 	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
 }
@@ -504,14 +508,8 @@
 	atomic_set(&hostdata->request_limit, 0);
 
 	purge_requests(hostdata, DID_ERROR);
-	if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata)) ||
-	    (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0)) ||
-	    (vio_enable_interrupts(to_vio_dev(hostdata->dev)))) {
-		atomic_set(&hostdata->request_limit, -1);
-		dev_err(hostdata->dev, "error after reset\n");
-	}
-
-	scsi_unblock_requests(hostdata->host);
+	hostdata->reset_crq = 1;
+	wake_up(&hostdata->work_wait_q);
 }
 
 /**
@@ -550,6 +548,7 @@
 	u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
 	int request_status = 0;
 	int rc;
+	int srp_req = 0;
 
 	/* If we have exhausted our request limit, just fail this request,
 	 * unless it is for a reset or abort.
@@ -558,6 +557,7 @@
 	 * can handle more requests (can_queue) when we actually can't
 	 */
 	if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) {
+		srp_req = 1;
 		request_status =
 			atomic_dec_if_positive(&hostdata->request_limit);
 		/* If request limit was -1 when we started, it is now even
@@ -632,7 +632,8 @@
 			goto send_busy;
 		}
 		dev_err(hostdata->dev, "send error %d\n", rc);
-		atomic_inc(&hostdata->request_limit);
+		if (srp_req)
+			atomic_inc(&hostdata->request_limit);
 		goto send_error;
 	}
 
@@ -642,7 +643,7 @@
 	unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
 
 	free_event_struct(&hostdata->pool, evt_struct);
-	if (request_status != -1)
+	if (srp_req && request_status != -1)
 		atomic_inc(&hostdata->request_limit);
 	return SCSI_MLQUEUE_HOST_BUSY;
 
@@ -1462,30 +1463,14 @@
 			/* We need to re-setup the interpartition connection */
 			dev_info(hostdata->dev, "Re-enabling adapter!\n");
 			hostdata->client_migrated = 1;
+			hostdata->reenable_crq = 1;
 			purge_requests(hostdata, DID_REQUEUE);
-			if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue,
-							      hostdata)) ||
-			    (ibmvscsi_ops->send_crq(hostdata,
-						    0xC001000000000000LL, 0))) {
-					atomic_set(&hostdata->request_limit,
-						   -1);
-					dev_err(hostdata->dev, "error after enable\n");
-			}
+			wake_up(&hostdata->work_wait_q);
 		} else {
 			dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n",
 				crq->format);
-
-			purge_requests(hostdata, DID_ERROR);
-			if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue,
-							   hostdata)) ||
-			    (ibmvscsi_ops->send_crq(hostdata,
-						    0xC001000000000000LL, 0))) {
-					atomic_set(&hostdata->request_limit,
-						   -1);
-					dev_err(hostdata->dev, "error after reset\n");
-			}
+			ibmvscsi_reset_host(hostdata);
 		}
-		scsi_unblock_requests(hostdata->host);
 		return;
 	case 0x80:		/* real payload */
 		break;
@@ -1850,6 +1835,75 @@
 	return desired_io;
 }
 
+static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata)
+{
+	int rc;
+	char *action = "reset";
+
+	if (hostdata->reset_crq) {
+		smp_rmb();
+		hostdata->reset_crq = 0;
+
+		rc = ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata);
+		if (!rc)
+			rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0);
+		if (!rc)
+			rc = vio_enable_interrupts(to_vio_dev(hostdata->dev));
+	} else if (hostdata->reenable_crq) {
+		smp_rmb();
+		action = "enable";
+		rc = ibmvscsi_ops->reenable_crq_queue(&hostdata->queue, hostdata);
+		hostdata->reenable_crq = 0;
+		if (!rc)
+			rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0);
+	} else
+		return;
+
+	if (rc) {
+		atomic_set(&hostdata->request_limit, -1);
+		dev_err(hostdata->dev, "error after %s\n", action);
+	}
+
+	scsi_unblock_requests(hostdata->host);
+}
+
+static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
+{
+	if (kthread_should_stop())
+		return 1;
+	else if (hostdata->reset_crq) {
+		smp_rmb();
+		return 1;
+	} else if (hostdata->reenable_crq) {
+		smp_rmb();
+		return 1;
+	}
+
+	return 0;
+}
+
+static int ibmvscsi_work(void *data)
+{
+	struct ibmvscsi_host_data *hostdata = data;
+	int rc;
+
+	set_user_nice(current, -20);
+
+	while (1) {
+		rc = wait_event_interruptible(hostdata->work_wait_q,
+					      ibmvscsi_work_to_do(hostdata));
+
+		BUG_ON(rc);
+
+		if (kthread_should_stop())
+			break;
+
+		ibmvscsi_do_work(hostdata);
+	}
+
+	return 0;
+}
+
 /**
  * Called by bus code for each adapter
  */
@@ -1875,6 +1929,7 @@
 	hostdata = shost_priv(host);
 	memset(hostdata, 0x00, sizeof(*hostdata));
 	INIT_LIST_HEAD(&hostdata->sent);
+	init_waitqueue_head(&hostdata->work_wait_q);
 	hostdata->host = host;
 	hostdata->dev = dev;
 	atomic_set(&hostdata->request_limit, -1);
@@ -1885,10 +1940,19 @@
 		goto persist_bufs_failed;
 	}
 
+	hostdata->work_thread = kthread_run(ibmvscsi_work, hostdata, "%s_%d",
+					    "ibmvscsi", host->host_no);
+
+	if (IS_ERR(hostdata->work_thread)) {
+		dev_err(&vdev->dev, "couldn't initialize kthread. rc=%ld\n",
+			PTR_ERR(hostdata->work_thread));
+		goto init_crq_failed;
+	}
+
 	rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events);
 	if (rc != 0 && rc != H_RESOURCE) {
 		dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
-		goto init_crq_failed;
+		goto kill_kthread;
 	}
 	if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) {
 		dev_err(&vdev->dev, "couldn't initialize event pool\n");
@@ -1944,6 +2008,8 @@
 	release_event_pool(&hostdata->pool, hostdata);
       init_pool_failed:
 	ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events);
+      kill_kthread:
+      kthread_stop(hostdata->work_thread);
       init_crq_failed:
 	unmap_persist_bufs(hostdata);
       persist_bufs_failed:
@@ -1960,6 +2026,7 @@
 	ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
 					max_events);
 
+	kthread_stop(hostdata->work_thread);
 	srp_remove_host(hostdata->host);
 	scsi_remove_host(hostdata->host);
 	scsi_host_put(hostdata->host);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 9cb7c6a..02197a2 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -91,12 +91,16 @@
 struct ibmvscsi_host_data {
 	atomic_t request_limit;
 	int client_migrated;
+	int reset_crq;
+	int reenable_crq;
 	struct device *dev;
 	struct event_pool pool;
 	struct crq_queue queue;
 	struct tasklet_struct srp_task;
 	struct list_head sent;
 	struct Scsi_Host *host;
+	struct task_struct *work_thread;
+	wait_queue_head_t work_wait_q;
 	struct mad_adapter_info_data madapter_info;
 	struct capabilities caps;
 	dma_addr_t caps_addr;
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index e2056d5..2256bab 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -956,7 +956,7 @@
 	.it_nexus_response = ibmvstgt_it_nexus_response,
 };
 
-static int ibmvstgt_init(void)
+static int __init ibmvstgt_init(void)
 {
 	int err = -ENOMEM;
 
@@ -987,7 +987,7 @@
 	return err;
 }
 
-static void ibmvstgt_exit(void)
+static void __exit ibmvstgt_exit(void)
 {
 	printk("Unregister IBM virtual SCSI driver\n");
 
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 989b9a8..f48ae01 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -31,6 +31,7 @@
 #include <asm/prom.h>
 #include <asm/iommu.h>
 #include <asm/hvcall.h>
+#include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/gfp.h>
 #include <linux/interrupt.h>
@@ -71,11 +72,13 @@
 				       struct ibmvscsi_host_data *hostdata,
 				       int max_requests)
 {
-	long rc;
+	long rc = 0;
 	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
 	free_irq(vdev->irq, (void *)hostdata);
 	tasklet_kill(&hostdata->srp_task);
 	do {
+		if (rc)
+			msleep(100);
 		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
 	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
 	dma_unmap_single(hostdata->dev,
@@ -200,11 +203,13 @@
 static int rpavscsi_reset_crq_queue(struct crq_queue *queue,
 				    struct ibmvscsi_host_data *hostdata)
 {
-	int rc;
+	int rc = 0;
 	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
 
 	/* Close the CRQ */
 	do {
+		if (rc)
+			msleep(100);
 		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
 	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
 
@@ -301,7 +306,10 @@
 
       req_irq_failed:
 	tasklet_kill(&hostdata->srp_task);
+	rc = 0;
 	do {
+		if (rc)
+			msleep(100);
 		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
 	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
       reg_crq_failed:
@@ -323,11 +331,13 @@
 static int rpavscsi_reenable_crq_queue(struct crq_queue *queue,
 				       struct ibmvscsi_host_data *hostdata)
 {
-	int rc;
+	int rc = 0;
 	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
 
 	/* Re-enable the CRQ */
 	do {
+		if (rc)
+			msleep(100);
 		rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
 	} while ((rc == H_IN_PROGRESS) || (rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
 
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index f820cff..5256858 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -167,21 +167,22 @@
 			.clr_uproc_interrupt_reg32 = 0x0002C,
 			.init_feedback_reg = 0x0005C,
 			.dump_addr_reg = 0x00064,
-			.dump_data_reg = 0x00068
+			.dump_data_reg = 0x00068,
+			.endian_swap_reg = 0x00084
 		}
 	},
 };
 
 static const struct ipr_chip_t ipr_chip[] = {
-	{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] },
-	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, IPR_USE_MSI, IPR_SIS32, &ipr_chip_cfg[0] },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[1] },
-	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[1] },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, IPR_USE_MSI, IPR_SIS64, &ipr_chip_cfg[2] },
-	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2, IPR_USE_MSI, IPR_SIS64, &ipr_chip_cfg[2] }
+	{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, IPR_USE_MSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] },
+	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }
 };
 
 static int ipr_max_bus_speeds [] = {
@@ -1167,7 +1168,7 @@
 	if (res->ioa_cfg->sis64) {
 		res->flags = cfgtew->u.cfgte64->flags;
 		res->res_flags = cfgtew->u.cfgte64->res_flags;
-		res->type = cfgtew->u.cfgte64->res_type & 0x0f;
+		res->type = cfgtew->u.cfgte64->res_type;
 
 		memcpy(&res->std_inq_data, &cfgtew->u.cfgte64->std_inq_data,
 			sizeof(struct ipr_std_inq_data));
@@ -3761,6 +3762,36 @@
 	.store = ipr_store_update_fw
 };
 
+/**
+ * ipr_show_fw_type - Show the adapter's firmware type.
+ * @dev:	class device struct
+ * @buf:	buffer
+ *
+ * Return value:
+ *	number of bytes printed to buffer
+ **/
+static ssize_t ipr_show_fw_type(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(dev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	unsigned long lock_flags = 0;
+	int len;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	len = snprintf(buf, PAGE_SIZE, "%d\n", ioa_cfg->sis64);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	return len;
+}
+
+static struct device_attribute ipr_ioa_fw_type_attr = {
+	.attr = {
+		.name =		"fw_type",
+		.mode =		S_IRUGO,
+	},
+	.show = ipr_show_fw_type
+};
+
 static struct device_attribute *ipr_ioa_attrs[] = {
 	&ipr_fw_version_attr,
 	&ipr_log_level_attr,
@@ -3768,6 +3799,7 @@
 	&ipr_ioa_state_attr,
 	&ipr_ioa_reset_attr,
 	&ipr_update_fw_attr,
+	&ipr_ioa_fw_type_attr,
 	NULL,
 };
 
@@ -4121,14 +4153,49 @@
 static struct device_attribute ipr_resource_path_attr = {
 	.attr = {
 		.name = 	"resource_path",
-		.mode =		S_IRUSR,
+		.mode =		S_IRUGO,
 	},
 	.show = ipr_show_resource_path
 };
 
+/**
+ * ipr_show_resource_type - Show the resource type for this device.
+ * @dev:	device struct
+ * @buf:	buffer
+ *
+ * Return value:
+ *	number of bytes printed to buffer
+ **/
+static ssize_t ipr_show_resource_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
+	struct ipr_resource_entry *res;
+	unsigned long lock_flags = 0;
+	ssize_t len = -ENXIO;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	res = (struct ipr_resource_entry *)sdev->hostdata;
+
+	if (res)
+		len = snprintf(buf, PAGE_SIZE, "%x\n", res->type);
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	return len;
+}
+
+static struct device_attribute ipr_resource_type_attr = {
+	.attr = {
+		.name =		"resource_type",
+		.mode =		S_IRUGO,
+	},
+	.show = ipr_show_resource_type
+};
+
 static struct device_attribute *ipr_dev_attrs[] = {
 	&ipr_adapter_handle_attr,
 	&ipr_resource_path_attr,
+	&ipr_resource_type_attr,
 	NULL,
 };
 
@@ -4352,8 +4419,6 @@
 					     IPR_VSET_RW_TIMEOUT);
 			blk_queue_max_hw_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
 		}
-		if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
-			sdev->allow_restart = 1;
 		if (ipr_is_gata(res) && res->sata_port)
 			ap = res->sata_port->ap;
 		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
@@ -6770,7 +6835,8 @@
 			list_move_tail(&res->queue, &ioa_cfg->used_res_q);
 			ipr_init_res_entry(res, &cfgtew);
 			res->add_to_ml = 1;
-		}
+		} else if (res->sdev && (ipr_is_vset_device(res) || ipr_is_scsi_disk(res)))
+			res->sdev->allow_restart = 1;
 
 		if (found)
 			ipr_update_res_entry(res, &cfgtew);
@@ -7169,12 +7235,15 @@
 		stage_time = ioa_cfg->transop_timeout;
 		ipr_cmd->job_step = ipr_ioafp_identify_hrrq;
 	} else if (stage == IPR_IPL_INIT_STAGE_TRANSOP) {
-		ipr_cmd->job_step = ipr_ioafp_identify_hrrq;
-		maskval = IPR_PCII_IPL_STAGE_CHANGE;
-		maskval = (maskval << 32) | IPR_PCII_IOA_TRANS_TO_OPER;
-		writeq(maskval, ioa_cfg->regs.set_interrupt_mask_reg);
-		int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
-		return IPR_RC_JOB_CONTINUE;
+		int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
+		if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
+			ipr_cmd->job_step = ipr_ioafp_identify_hrrq;
+			maskval = IPR_PCII_IPL_STAGE_CHANGE;
+			maskval = (maskval << 32) | IPR_PCII_IOA_TRANS_TO_OPER;
+			writeq(maskval, ioa_cfg->regs.set_interrupt_mask_reg);
+			int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+			return IPR_RC_JOB_CONTINUE;
+		}
 	}
 
 	ipr_cmd->timer.data = (unsigned long) ipr_cmd;
@@ -7208,6 +7277,12 @@
 	ipr_init_ioa_mem(ioa_cfg);
 
 	ioa_cfg->allow_interrupts = 1;
+	if (ioa_cfg->sis64) {
+		/* Set the adapter to the correct endian mode. */
+		writel(IPR_ENDIAN_SWAP_KEY, ioa_cfg->regs.endian_swap_reg);
+		int_reg = readl(ioa_cfg->regs.endian_swap_reg);
+	}
+
 	int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
 
 	if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
@@ -7365,6 +7440,7 @@
 static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
 {
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	volatile u32 int_reg;
 	int rc;
 
 	ENTER;
@@ -7383,6 +7459,12 @@
 
 	ipr_fail_all_ops(ioa_cfg);
 
+	if (ioa_cfg->sis64) {
+		/* Set the adapter to the correct endian mode. */
+		writel(IPR_ENDIAN_SWAP_KEY, ioa_cfg->regs.endian_swap_reg);
+		int_reg = readl(ioa_cfg->regs.endian_swap_reg);
+	}
+
 	if (ioa_cfg->ioa_unit_checked) {
 		ioa_cfg->ioa_unit_checked = 0;
 		ipr_get_unit_check_buffer(ioa_cfg);
@@ -7438,20 +7520,25 @@
 static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
 {
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
-	int rc;
+	int rc = PCIBIOS_SUCCESSFUL;
 
 	ENTER;
 	pci_block_user_cfg_access(ioa_cfg->pdev);
-	rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START);
 
-	if (rc != PCIBIOS_SUCCESSFUL) {
-		pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev);
-		ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
-		rc = IPR_RC_JOB_CONTINUE;
-	} else {
+	if (ioa_cfg->ipr_chip->bist_method == IPR_MMIO)
+		writel(IPR_UPROCI_SIS64_START_BIST,
+		       ioa_cfg->regs.set_uproc_interrupt_reg32);
+	else
+		rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START);
+
+	if (rc == PCIBIOS_SUCCESSFUL) {
 		ipr_cmd->job_step = ipr_reset_bist_done;
 		ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
 		rc = IPR_RC_JOB_RETURN;
+	} else {
+		pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev);
+		ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
+		rc = IPR_RC_JOB_CONTINUE;
 	}
 
 	LEAVE;
@@ -7547,7 +7634,7 @@
 }
 
 /**
- * ipr_reset_alert_part2 - Alert the adapter of a pending reset
+ * ipr_reset_alert - Alert the adapter of a pending reset
  * @ipr_cmd:	ipr command struct
  *
  * Description: This function alerts the adapter that it will be reset.
@@ -8318,6 +8405,7 @@
 		t->init_feedback_reg = base + p->init_feedback_reg;
 		t->dump_addr_reg = base + p->dump_addr_reg;
 		t->dump_data_reg = base + p->dump_data_reg;
+		t->endian_swap_reg = base + p->endian_swap_reg;
 	}
 }
 
@@ -8873,6 +8961,8 @@
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57CC, 0, 0, 0 },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0,
 	      IPR_USE_LONG_TRANSOP_TIMEOUT | IPR_USE_PCI_WARM_RESET },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index b965f35..4d31625 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -62,12 +62,12 @@
 #define IPR_SUBS_DEV_ID_2780	0x0264
 #define IPR_SUBS_DEV_ID_5702	0x0266
 #define IPR_SUBS_DEV_ID_5703	0x0278
-#define IPR_SUBS_DEV_ID_572E  0x028D
-#define IPR_SUBS_DEV_ID_573E  0x02D3
-#define IPR_SUBS_DEV_ID_573D  0x02D4
+#define IPR_SUBS_DEV_ID_572E	0x028D
+#define IPR_SUBS_DEV_ID_573E	0x02D3
+#define IPR_SUBS_DEV_ID_573D	0x02D4
 #define IPR_SUBS_DEV_ID_571A	0x02C0
 #define IPR_SUBS_DEV_ID_571B	0x02BE
-#define IPR_SUBS_DEV_ID_571E  0x02BF
+#define IPR_SUBS_DEV_ID_571E	0x02BF
 #define IPR_SUBS_DEV_ID_571F	0x02D5
 #define IPR_SUBS_DEV_ID_572A	0x02C1
 #define IPR_SUBS_DEV_ID_572B	0x02C2
@@ -82,6 +82,7 @@
 #define IPR_SUBS_DEV_ID_57B4    0x033B
 #define IPR_SUBS_DEV_ID_57B2    0x035F
 #define IPR_SUBS_DEV_ID_57C6    0x0357
+#define IPR_SUBS_DEV_ID_57CC    0x035C
 
 #define IPR_SUBS_DEV_ID_57B5    0x033C
 #define IPR_SUBS_DEV_ID_57CE    0x035E
@@ -272,6 +273,7 @@
 
 #define IPR_UPROCI_RESET_ALERT			(0x80000000 >> 7)
 #define IPR_UPROCI_IO_DEBUG_ALERT			(0x80000000 >> 9)
+#define IPR_UPROCI_SIS64_START_BIST			(0x80000000 >> 23)
 
 #define IPR_LDUMP_MAX_LONG_ACK_DELAY_IN_USEC		200000	/* 200 ms */
 #define IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC		200000	/* 200 ms */
@@ -996,7 +998,7 @@
 	__be16 length;
 	u8 descriptor_id;
 
-	u8 reserved;
+	u8 reserved[2];
 	u8 path_state;
 
 	u8 reserved2[2];
@@ -1054,7 +1056,7 @@
 	__be64 fd_lun;
 	u8 fd_res_path[8];
 	__be64 time_stamp;
-	u8 reserved[2];
+	u8 reserved[16];
 	union {
 		struct ipr_hostrcb_type_ff_error type_ff_error;
 		struct ipr_hostrcb_type_12_error type_12_error;
@@ -1254,6 +1256,9 @@
 
 	unsigned long dump_addr_reg;
 	unsigned long dump_data_reg;
+
+#define IPR_ENDIAN_SWAP_KEY		0x00080800
+	unsigned long endian_swap_reg;
 };
 
 struct ipr_interrupts {
@@ -1279,6 +1284,8 @@
 
 	void __iomem *dump_addr_reg;
 	void __iomem *dump_data_reg;
+
+	void __iomem *endian_swap_reg;
 };
 
 struct ipr_chip_cfg_t {
@@ -1296,6 +1303,9 @@
 	u16 sis_type;
 #define IPR_SIS32			0x00
 #define IPR_SIS64			0x01
+	u16 bist_method;
+#define IPR_PCI_CFG			0x00
+#define IPR_MMIO			0x01
 	const struct ipr_chip_cfg_t *cfg;
 };
 
@@ -1855,4 +1865,12 @@
 	return 0;
 }
 
+#ifndef writeq
+static inline void writeq(u64 val, void __iomem *addr)
+{
+        writel(((u32) (val >> 32)), addr);
+        writel(((u32) (val)), (addr + 4));
+}
 #endif
+
+#endif /* _IPR_H */
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index c7985da..32f67c4 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -63,27 +63,25 @@
 void fc_disc_stop_rports(struct fc_disc *disc)
 {
 	struct fc_lport *lport;
-	struct fc_rport_priv *rdata, *next;
+	struct fc_rport_priv *rdata;
 
-	lport = disc->lport;
+	lport = fc_disc_lport(disc);
 
 	mutex_lock(&disc->disc_mutex);
-	list_for_each_entry_safe(rdata, next, &disc->rports, peers)
+	list_for_each_entry_rcu(rdata, &disc->rports, peers)
 		lport->tt.rport_logoff(rdata);
 	mutex_unlock(&disc->disc_mutex);
 }
 
 /**
  * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN)
- * @sp:	   The sequence of the RSCN exchange
+ * @disc:  The discovery object to which the RSCN applies
  * @fp:	   The RSCN frame
- * @lport: The local port that the request will be sent on
  *
  * Locking Note: This function expects that the disc_mutex is locked
  *		 before it is called.
  */
-static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
-				  struct fc_disc *disc)
+static void fc_disc_recv_rscn_req(struct fc_disc *disc, struct fc_frame *fp)
 {
 	struct fc_lport *lport;
 	struct fc_els_rscn *rp;
@@ -96,7 +94,7 @@
 	LIST_HEAD(disc_ports);
 	struct fc_disc_port *dp, *next;
 
-	lport = disc->lport;
+	lport = fc_disc_lport(disc);
 
 	FC_DISC_DBG(disc, "Received an RSCN event\n");
 
@@ -151,7 +149,7 @@
 			break;
 		}
 	}
-	lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
+	lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL);
 
 	/*
 	 * If not doing a complete rediscovery, do GPN_ID on
@@ -177,25 +175,22 @@
 	return;
 reject:
 	FC_DISC_DBG(disc, "Received a bad RSCN frame\n");
-	rjt_data.fp = NULL;
 	rjt_data.reason = ELS_RJT_LOGIC;
 	rjt_data.explan = ELS_EXPL_NONE;
-	lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+	lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data);
 	fc_frame_free(fp);
 }
 
 /**
  * fc_disc_recv_req() - Handle incoming requests
- * @sp:	   The sequence of the request exchange
- * @fp:	   The request frame
  * @lport: The local port receiving the request
+ * @fp:	   The request frame
  *
  * Locking Note: This function is called from the EM and will lock
  *		 the disc_mutex before calling the handler for the
  *		 request.
  */
-static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp,
-			     struct fc_lport *lport)
+static void fc_disc_recv_req(struct fc_lport *lport, struct fc_frame *fp)
 {
 	u8 op;
 	struct fc_disc *disc = &lport->disc;
@@ -204,7 +199,7 @@
 	switch (op) {
 	case ELS_RSCN:
 		mutex_lock(&disc->disc_mutex);
-		fc_disc_recv_rscn_req(sp, fp, disc);
+		fc_disc_recv_rscn_req(disc, fp);
 		mutex_unlock(&disc->disc_mutex);
 		break;
 	default:
@@ -275,7 +270,7 @@
  */
 static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
 {
-	struct fc_lport *lport = disc->lport;
+	struct fc_lport *lport = fc_disc_lport(disc);
 	struct fc_rport_priv *rdata;
 
 	FC_DISC_DBG(disc, "Discovery complete\n");
@@ -292,7 +287,7 @@
 	 * Skip ports which were never discovered.  These are the dNS port
 	 * and ports which were created by PLOGI.
 	 */
-	list_for_each_entry(rdata, &disc->rports, peers) {
+	list_for_each_entry_rcu(rdata, &disc->rports, peers) {
 		if (!rdata->disc_id)
 			continue;
 		if (rdata->disc_id == disc->disc_id)
@@ -313,7 +308,7 @@
  */
 static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp)
 {
-	struct fc_lport *lport = disc->lport;
+	struct fc_lport *lport = fc_disc_lport(disc);
 	unsigned long delay = 0;
 
 	FC_DISC_DBG(disc, "Error %ld, retries %d/%d\n",
@@ -353,7 +348,7 @@
 static void fc_disc_gpn_ft_req(struct fc_disc *disc)
 {
 	struct fc_frame *fp;
-	struct fc_lport *lport = disc->lport;
+	struct fc_lport *lport = fc_disc_lport(disc);
 
 	WARN_ON(!fc_lport_test_ready(lport));
 
@@ -396,7 +391,7 @@
 	struct fc_rport_identifiers ids;
 	struct fc_rport_priv *rdata;
 
-	lport = disc->lport;
+	lport = fc_disc_lport(disc);
 	disc->seq_count++;
 
 	/*
@@ -733,7 +728,7 @@
 	mutex_init(&disc->disc_mutex);
 	INIT_LIST_HEAD(&disc->rports);
 
-	disc->lport = lport;
+	disc->priv = lport;
 
 	return 0;
 }
diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c
index e9412b7..9b25969 100644
--- a/drivers/scsi/libfc/fc_elsct.c
+++ b/drivers/scsi/libfc/fc_elsct.c
@@ -64,7 +64,7 @@
 	}
 
 	fc_fill_fc_hdr(fp, r_ctl, did, lport->port_id, fh_type,
-		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+		       FC_FCTL_REQ, 0);
 
 	return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec);
 }
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index ca52bfa..ec2a1ae 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -129,11 +129,11 @@
 };
 
 static void fc_exch_rrq(struct fc_exch *);
-static void fc_seq_ls_acc(struct fc_seq *);
-static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason,
+static void fc_seq_ls_acc(struct fc_frame *);
+static void fc_seq_ls_rjt(struct fc_frame *, enum fc_els_rjt_reason,
 			  enum fc_els_rjt_explan);
-static void fc_exch_els_rec(struct fc_seq *, struct fc_frame *);
-static void fc_exch_els_rrq(struct fc_seq *, struct fc_frame *);
+static void fc_exch_els_rec(struct fc_frame *);
+static void fc_exch_els_rrq(struct fc_frame *);
 
 /*
  * Internal implementation notes.
@@ -462,6 +462,7 @@
 
 	f_ctl = ntoh24(fh->fh_f_ctl);
 	fc_exch_setup_hdr(ep, fp, f_ctl);
+	fr_encaps(fp) = ep->encaps;
 
 	/*
 	 * update sequence count if this frame is carrying
@@ -1000,28 +1001,30 @@
 /**
  * fc_seq_els_rsp_send() - Send an ELS response using infomation from
  *			   the existing sequence/exchange.
- * @sp:	      The sequence/exchange to get information from
+ * @fp:	      The received frame
  * @els_cmd:  The ELS command to be sent
  * @els_data: The ELS data to be sent
+ *
+ * The received frame is not freed.
  */
-static void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd,
+static void fc_seq_els_rsp_send(struct fc_frame *fp, enum fc_els_cmd els_cmd,
 				struct fc_seq_els_data *els_data)
 {
 	switch (els_cmd) {
 	case ELS_LS_RJT:
-		fc_seq_ls_rjt(sp, els_data->reason, els_data->explan);
+		fc_seq_ls_rjt(fp, els_data->reason, els_data->explan);
 		break;
 	case ELS_LS_ACC:
-		fc_seq_ls_acc(sp);
+		fc_seq_ls_acc(fp);
 		break;
 	case ELS_RRQ:
-		fc_exch_els_rrq(sp, els_data->fp);
+		fc_exch_els_rrq(fp);
 		break;
 	case ELS_REC:
-		fc_exch_els_rec(sp, els_data->fp);
+		fc_exch_els_rec(fp);
 		break;
 	default:
-		FC_EXCH_DBG(fc_seq_exch(sp), "Invalid ELS CMD:%x\n", els_cmd);
+		FC_LPORT_DBG(fr_dev(fp), "Invalid ELS CMD:%x\n", els_cmd);
 	}
 }
 
@@ -1228,11 +1231,35 @@
 }
 
 /**
- * fc_exch_recv_req() - Handler for an incoming request where is other
- *			end is originating the sequence
+ * fc_seq_assign() - Assign exchange and sequence for incoming request
+ * @lport: The local port that received the request
+ * @fp:    The request frame
+ *
+ * On success, the sequence pointer will be returned and also in fr_seq(@fp).
+ */
+static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp)
+{
+	struct fc_exch_mgr_anchor *ema;
+
+	WARN_ON(lport != fr_dev(fp));
+	WARN_ON(fr_seq(fp));
+	fr_seq(fp) = NULL;
+
+	list_for_each_entry(ema, &lport->ema_list, ema_list)
+		if ((!ema->match || ema->match(fp)) &&
+		    fc_seq_lookup_recip(lport, ema->mp, fp) != FC_RJT_NONE)
+			break;
+	return fr_seq(fp);
+}
+
+/**
+ * fc_exch_recv_req() - Handler for an incoming request
  * @lport: The local port that received the request
  * @mp:	   The EM that the exchange is on
  * @fp:	   The request frame
+ *
+ * This is used when the other end is originating the exchange
+ * and the sequence.
  */
 static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
 			     struct fc_frame *fp)
@@ -1250,13 +1277,23 @@
 		fc_frame_free(fp);
 		return;
 	}
+	fr_dev(fp) = lport;
 
-	fr_seq(fp) = NULL;
+	BUG_ON(fr_seq(fp));		/* XXX remove later */
+
+	/*
+	 * If the RX_ID is 0xffff, don't allocate an exchange.
+	 * The upper-level protocol may request one later, if needed.
+	 */
+	if (fh->fh_rx_id == htons(FC_XID_UNKNOWN))
+		return lport->tt.lport_recv(lport, fp);
+
 	reject = fc_seq_lookup_recip(lport, mp, fp);
 	if (reject == FC_RJT_NONE) {
 		sp = fr_seq(fp);	/* sequence will be held */
 		ep = fc_seq_exch(sp);
 		fc_seq_send_ack(sp, fp);
+		ep->encaps = fr_encaps(fp);
 
 		/*
 		 * Call the receive function.
@@ -1272,7 +1309,7 @@
 		if (ep->resp)
 			ep->resp(sp, fp, ep->arg);
 		else
-			lport->tt.lport_recv(lport, sp, fp);
+			lport->tt.lport_recv(lport, fp);
 		fc_exch_release(ep);	/* release from lookup */
 	} else {
 		FC_LPORT_DBG(lport, "exch/seq lookup failed: reject %x\n",
@@ -1540,53 +1577,55 @@
 
 /**
  * fc_seq_ls_acc() - Accept sequence with LS_ACC
- * @req_sp: The request sequence
+ * @rx_fp: The received frame, not freed here.
  *
  * If this fails due to allocation or transmit congestion, assume the
  * originator will repeat the sequence.
  */
-static void fc_seq_ls_acc(struct fc_seq *req_sp)
+static void fc_seq_ls_acc(struct fc_frame *rx_fp)
 {
-	struct fc_seq *sp;
+	struct fc_lport *lport;
 	struct fc_els_ls_acc *acc;
 	struct fc_frame *fp;
 
-	sp = fc_seq_start_next(req_sp);
-	fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc));
-	if (fp) {
-		acc = fc_frame_payload_get(fp, sizeof(*acc));
-		memset(acc, 0, sizeof(*acc));
-		acc->la_cmd = ELS_LS_ACC;
-		fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS);
-	}
+	lport = fr_dev(rx_fp);
+	fp = fc_frame_alloc(lport, sizeof(*acc));
+	if (!fp)
+		return;
+	acc = fc_frame_payload_get(fp, sizeof(*acc));
+	memset(acc, 0, sizeof(*acc));
+	acc->la_cmd = ELS_LS_ACC;
+	fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+	lport->tt.frame_send(lport, fp);
 }
 
 /**
  * fc_seq_ls_rjt() - Reject a sequence with ELS LS_RJT
- * @req_sp: The request sequence
+ * @rx_fp: The received frame, not freed here.
  * @reason: The reason the sequence is being rejected
- * @explan: The explaination for the rejection
+ * @explan: The explanation for the rejection
  *
  * If this fails due to allocation or transmit congestion, assume the
  * originator will repeat the sequence.
  */
-static void fc_seq_ls_rjt(struct fc_seq *req_sp, enum fc_els_rjt_reason reason,
+static void fc_seq_ls_rjt(struct fc_frame *rx_fp, enum fc_els_rjt_reason reason,
 			  enum fc_els_rjt_explan explan)
 {
-	struct fc_seq *sp;
+	struct fc_lport *lport;
 	struct fc_els_ls_rjt *rjt;
 	struct fc_frame *fp;
 
-	sp = fc_seq_start_next(req_sp);
-	fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*rjt));
-	if (fp) {
-		rjt = fc_frame_payload_get(fp, sizeof(*rjt));
-		memset(rjt, 0, sizeof(*rjt));
-		rjt->er_cmd = ELS_LS_RJT;
-		rjt->er_reason = reason;
-		rjt->er_explan = explan;
-		fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS);
-	}
+	lport = fr_dev(rx_fp);
+	fp = fc_frame_alloc(lport, sizeof(*rjt));
+	if (!fp)
+		return;
+	rjt = fc_frame_payload_get(fp, sizeof(*rjt));
+	memset(rjt, 0, sizeof(*rjt));
+	rjt->er_cmd = ELS_LS_RJT;
+	rjt->er_reason = reason;
+	rjt->er_explan = explan;
+	fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+	lport->tt.frame_send(lport, fp);
 }
 
 /**
@@ -1689,17 +1728,33 @@
 EXPORT_SYMBOL(fc_exch_mgr_reset);
 
 /**
+ * fc_exch_lookup() - find an exchange
+ * @lport: The local port
+ * @xid: The exchange ID
+ *
+ * Returns exchange pointer with hold for caller, or NULL if not found.
+ */
+static struct fc_exch *fc_exch_lookup(struct fc_lport *lport, u32 xid)
+{
+	struct fc_exch_mgr_anchor *ema;
+
+	list_for_each_entry(ema, &lport->ema_list, ema_list)
+		if (ema->mp->min_xid <= xid && xid <= ema->mp->max_xid)
+			return fc_exch_find(ema->mp, xid);
+	return NULL;
+}
+
+/**
  * fc_exch_els_rec() - Handler for ELS REC (Read Exchange Concise) requests
- * @sp:	 The sequence the REC is on
- * @rfp: The REC frame
+ * @rfp: The REC frame, not freed here.
  *
  * Note that the requesting port may be different than the S_ID in the request.
  */
-static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
+static void fc_exch_els_rec(struct fc_frame *rfp)
 {
+	struct fc_lport *lport;
 	struct fc_frame *fp;
 	struct fc_exch *ep;
-	struct fc_exch_mgr *em;
 	struct fc_els_rec *rp;
 	struct fc_els_rec_acc *acc;
 	enum fc_els_rjt_reason reason = ELS_RJT_LOGIC;
@@ -1708,6 +1763,7 @@
 	u16 rxid;
 	u16 oxid;
 
+	lport = fr_dev(rfp);
 	rp = fc_frame_payload_get(rfp, sizeof(*rp));
 	explan = ELS_EXPL_INV_LEN;
 	if (!rp)
@@ -1716,35 +1772,19 @@
 	rxid = ntohs(rp->rec_rx_id);
 	oxid = ntohs(rp->rec_ox_id);
 
-	/*
-	 * Currently it's hard to find the local S_ID from the exchange
-	 * manager.  This will eventually be fixed, but for now it's easier
-	 * to lookup the subject exchange twice, once as if we were
-	 * the initiator, and then again if we weren't.
-	 */
-	em = fc_seq_exch(sp)->em;
-	ep = fc_exch_find(em, oxid);
+	ep = fc_exch_lookup(lport,
+			    sid == fc_host_port_id(lport->host) ? oxid : rxid);
 	explan = ELS_EXPL_OXID_RXID;
-	if (ep && ep->oid == sid) {
-		if (ep->rxid != FC_XID_UNKNOWN &&
-		    rxid != FC_XID_UNKNOWN &&
-		    ep->rxid != rxid)
-			goto rel;
-	} else {
-		if (ep)
-			fc_exch_release(ep);
-		ep = NULL;
-		if (rxid != FC_XID_UNKNOWN)
-			ep = fc_exch_find(em, rxid);
-		if (!ep)
-			goto reject;
-	}
-
-	fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc));
-	if (!fp) {
-		fc_exch_done(sp);
+	if (!ep)
+		goto reject;
+	if (ep->oid != sid || oxid != ep->oxid)
+		goto rel;
+	if (rxid != FC_XID_UNKNOWN && rxid != ep->rxid)
+		goto rel;
+	fp = fc_frame_alloc(lport, sizeof(*acc));
+	if (!fp)
 		goto out;
-	}
+
 	acc = fc_frame_payload_get(fp, sizeof(*acc));
 	memset(acc, 0, sizeof(*acc));
 	acc->reca_cmd = ELS_LS_ACC;
@@ -1759,18 +1799,16 @@
 	acc->reca_e_stat = htonl(ep->esb_stat & (ESB_ST_RESP |
 						 ESB_ST_SEQ_INIT |
 						 ESB_ST_COMPLETE));
-	sp = fc_seq_start_next(sp);
-	fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS);
+	fc_fill_reply_hdr(fp, rfp, FC_RCTL_ELS_REP, 0);
+	lport->tt.frame_send(lport, fp);
 out:
 	fc_exch_release(ep);
-	fc_frame_free(rfp);
 	return;
 
 rel:
 	fc_exch_release(ep);
 reject:
-	fc_seq_ls_rjt(sp, reason, explan);
-	fc_frame_free(rfp);
+	fc_seq_ls_rjt(rfp, reason, explan);
 }
 
 /**
@@ -1945,20 +1983,20 @@
 	spin_unlock_bh(&ep->ex_lock);
 }
 
-
 /**
  * fc_exch_els_rrq() - Handler for ELS RRQ (Reset Recovery Qualifier) requests
- * @sp: The sequence that the RRQ is on
- * @fp: The RRQ frame
+ * @fp: The RRQ frame, not freed here.
  */
-static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp)
+static void fc_exch_els_rrq(struct fc_frame *fp)
 {
+	struct fc_lport *lport;
 	struct fc_exch *ep = NULL;	/* request or subject exchange */
 	struct fc_els_rrq *rp;
 	u32 sid;
 	u16 xid;
 	enum fc_els_rjt_explan explan;
 
+	lport = fr_dev(fp);
 	rp = fc_frame_payload_get(fp, sizeof(*rp));
 	explan = ELS_EXPL_INV_LEN;
 	if (!rp)
@@ -1967,11 +2005,10 @@
 	/*
 	 * lookup subject exchange.
 	 */
-	ep = fc_seq_exch(sp);
 	sid = ntoh24(rp->rrq_s_id);		/* subject source */
-	xid = ep->did == sid ? ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id);
-	ep = fc_exch_find(ep->em, xid);
-
+	xid = fc_host_port_id(lport->host) == sid ?
+			ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id);
+	ep = fc_exch_lookup(lport, xid);
 	explan = ELS_EXPL_OXID_RXID;
 	if (!ep)
 		goto reject;
@@ -2002,15 +2039,14 @@
 	/*
 	 * Send LS_ACC.
 	 */
-	fc_seq_ls_acc(sp);
+	fc_seq_ls_acc(fp);
 	goto out;
 
 unlock_reject:
 	spin_unlock_bh(&ep->ex_lock);
 reject:
-	fc_seq_ls_rjt(sp, ELS_RJT_LOGIC, explan);
+	fc_seq_ls_rjt(fp, ELS_RJT_LOGIC, explan);
 out:
-	fc_frame_free(fp);
 	if (ep)
 		fc_exch_release(ep);	/* drop hold from fc_exch_find */
 }
@@ -2241,7 +2277,7 @@
 			fc_exch_recv_seq_resp(ema->mp, fp);
 		else if (f_ctl & FC_FC_SEQ_CTX)
 			fc_exch_recv_resp(ema->mp, fp);
-		else
+		else	/* no EX_CTX and no SEQ_CTX */
 			fc_exch_recv_req(lport, ema->mp, fp);
 		break;
 	default:
@@ -2279,6 +2315,9 @@
 	if (!lport->tt.seq_exch_abort)
 		lport->tt.seq_exch_abort = fc_seq_exch_abort;
 
+	if (!lport->tt.seq_assign)
+		lport->tt.seq_assign = fc_seq_assign;
+
 	return 0;
 }
 EXPORT_SYMBOL(fc_exch_init);
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index ec1f66c..eac4d09 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -580,10 +580,8 @@
 			   fsp, seq_blen, lport->lso_max, t_blen);
 	}
 
-	WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD);
 	if (t_blen > 512)
 		t_blen &= ~(512 - 1);	/* round down to block size */
-	WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD);	/* won't go below 256 */
 	sc = fsp->cmd;
 
 	remaining = seq_blen;
@@ -745,7 +743,7 @@
 	fh = fc_frame_header_get(fp);
 	r_ctl = fh->fh_r_ctl;
 
-	if (!(lport->state & LPORT_ST_READY))
+	if (lport->state != LPORT_ST_READY)
 		goto out;
 	if (fc_fcp_lock_pkt(fsp))
 		goto out;
@@ -1110,7 +1108,7 @@
 
 	fc_fill_fc_hdr(fp, FC_RCTL_DD_UNSOL_CMD, rport->port_id,
 		       rpriv->local_port->port_id, FC_TYPE_FCP,
-		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+		       FC_FCTL_REQ, 0);
 
 	seq = lport->tt.exch_seq_send(lport, fp, resp, fc_fcp_pkt_destroy,
 				      fsp, 0);
@@ -1383,7 +1381,7 @@
 	fr_seq(fp) = fsp->seq_ptr;
 	fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id,
 		       rpriv->local_port->port_id, FC_TYPE_ELS,
-		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+		       FC_FCTL_REQ, 0);
 	if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC,
 				 fc_fcp_rec_resp, fsp,
 				 jiffies_to_msecs(FC_SCSI_REC_TOV))) {
@@ -1641,7 +1639,7 @@
 
 	fc_fill_fc_hdr(fp, FC_RCTL_ELS4_REQ, rport->port_id,
 		       rpriv->local_port->port_id, FC_TYPE_FCP,
-		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+		       FC_FCTL_REQ, 0);
 
 	seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL,
 				      fsp, jiffies_to_msecs(FC_SCSI_REC_TOV));
@@ -1973,6 +1971,11 @@
 		break;
 	}
 
+	if (lport->state != LPORT_ST_READY && fsp->status_code != FC_COMPLETE) {
+		sc_cmd->result = (DID_REQUEUE << 16);
+		FC_FCP_DBG(fsp, "Returning DID_REQUEUE to scsi-ml\n");
+	}
+
 	spin_lock_irqsave(&si->scsi_queue_lock, flags);
 	list_del(&fsp->list);
 	spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c
index 39f4b6a..6a48c28 100644
--- a/drivers/scsi/libfc/fc_libfc.c
+++ b/drivers/scsi/libfc/fc_libfc.c
@@ -23,6 +23,7 @@
 #include <linux/crc32.h>
 
 #include <scsi/libfc.h>
+#include <scsi/fc_encode.h>
 
 #include "fc_libfc.h"
 
@@ -132,3 +133,80 @@
 	}
 	return copy_len;
 }
+
+/**
+ * fc_fill_hdr() -  fill FC header fields based on request
+ * @fp: reply frame containing header to be filled in
+ * @in_fp: request frame containing header to use in filling in reply
+ * @r_ctl: R_CTL value for header
+ * @f_ctl: F_CTL value for header, with 0 pad
+ * @seq_cnt: sequence count for the header, ignored if frame has a sequence
+ * @parm_offset: parameter / offset value
+ */
+void fc_fill_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
+		 enum fc_rctl r_ctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset)
+{
+	struct fc_frame_header *fh;
+	struct fc_frame_header *in_fh;
+	struct fc_seq *sp;
+	u32 fill;
+
+	fh = __fc_frame_header_get(fp);
+	in_fh = __fc_frame_header_get(in_fp);
+
+	if (f_ctl & FC_FC_END_SEQ) {
+		fill = -fr_len(fp) & 3;
+		if (fill) {
+			/* TODO, this may be a problem with fragmented skb */
+			memset(skb_put(fp_skb(fp), fill), 0, fill);
+			f_ctl |= fill;
+		}
+		fr_eof(fp) = FC_EOF_T;
+	} else {
+		WARN_ON(fr_len(fp) % 4 != 0);	/* no pad to non last frame */
+		fr_eof(fp) = FC_EOF_N;
+	}
+
+	fh->fh_r_ctl = r_ctl;
+	memcpy(fh->fh_d_id, in_fh->fh_s_id, sizeof(fh->fh_d_id));
+	memcpy(fh->fh_s_id, in_fh->fh_d_id, sizeof(fh->fh_s_id));
+	fh->fh_type = in_fh->fh_type;
+	hton24(fh->fh_f_ctl, f_ctl);
+	fh->fh_ox_id = in_fh->fh_ox_id;
+	fh->fh_rx_id = in_fh->fh_rx_id;
+	fh->fh_cs_ctl = 0;
+	fh->fh_df_ctl = 0;
+	fh->fh_parm_offset = htonl(parm_offset);
+
+	sp = fr_seq(in_fp);
+	if (sp) {
+		fr_seq(fp) = sp;
+		fh->fh_seq_id = sp->id;
+		seq_cnt = sp->cnt;
+	} else {
+		fh->fh_seq_id = 0;
+	}
+	fh->fh_seq_cnt = ntohs(seq_cnt);
+	fr_sof(fp) = seq_cnt ? FC_SOF_N3 : FC_SOF_I3;
+	fr_encaps(fp) = fr_encaps(in_fp);
+}
+EXPORT_SYMBOL(fc_fill_hdr);
+
+/**
+ * fc_fill_reply_hdr() -  fill FC reply header fields based on request
+ * @fp: reply frame containing header to be filled in
+ * @in_fp: request frame containing header to use in filling in reply
+ * @r_ctl: R_CTL value for reply
+ * @parm_offset: parameter / offset value
+ */
+void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
+		       enum fc_rctl r_ctl, u32 parm_offset)
+{
+	struct fc_seq *sp;
+
+	sp = fr_seq(in_fp);
+	if (sp)
+		fr_seq(fp) = fr_dev(in_fp)->tt.seq_start_next(sp);
+	fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset);
+}
+EXPORT_SYMBOL(fc_fill_reply_hdr);
diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h
index f5c0ca4..16d2162 100644
--- a/drivers/scsi/libfc/fc_libfc.h
+++ b/drivers/scsi/libfc/fc_libfc.h
@@ -52,7 +52,7 @@
 #define FC_DISC_DBG(disc, fmt, args...)				\
 	FC_CHECK_LOGGING(FC_DISC_LOGGING,			\
 			 printk(KERN_INFO "host%u: disc: " fmt,	\
-				(disc)->lport->host->host_no,	\
+				fc_disc_lport(disc)->host->host_no,	\
 				##args))
 
 #define FC_RPORT_ID_DBG(lport, port_id, fmt, args...)			\
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index ef32b06..d9b6e11 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -375,41 +375,36 @@
 
 /**
  * fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report.
- * @sp:	   The sequence in the RLIR exchange
- * @fp:	   The RLIR request frame
  * @lport: Fibre Channel local port recieving the RLIR
+ * @fp:	   The RLIR request frame
  *
  * Locking Note: The lport lock is expected to be held before calling
  * this function.
  */
-static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp,
-				   struct fc_lport *lport)
+static void fc_lport_recv_rlir_req(struct fc_lport *lport, struct fc_frame *fp)
 {
 	FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n",
 		     fc_lport_state(lport));
 
-	lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
+	lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL);
 	fc_frame_free(fp);
 }
 
 /**
  * fc_lport_recv_echo_req() - Handle received ECHO request
- * @sp:	   The sequence in the ECHO exchange
- * @fp:	   ECHO request frame
  * @lport: The local port recieving the ECHO
+ * @fp:	   ECHO request frame
  *
  * Locking Note: The lport lock is expected to be held before calling
  * this function.
  */
-static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
-				   struct fc_lport *lport)
+static void fc_lport_recv_echo_req(struct fc_lport *lport,
+				   struct fc_frame *in_fp)
 {
 	struct fc_frame *fp;
-	struct fc_exch *ep = fc_seq_exch(sp);
 	unsigned int len;
 	void *pp;
 	void *dp;
-	u32 f_ctl;
 
 	FC_LPORT_DBG(lport, "Received ECHO request while in state %s\n",
 		     fc_lport_state(lport));
@@ -425,29 +420,24 @@
 		dp = fc_frame_payload_get(fp, len);
 		memcpy(dp, pp, len);
 		*((__be32 *)dp) = htonl(ELS_LS_ACC << 24);
-		sp = lport->tt.seq_start_next(sp);
-		f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
-		fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
-			       FC_TYPE_ELS, f_ctl, 0);
-		lport->tt.seq_send(lport, sp, fp);
+		fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0);
+		lport->tt.frame_send(lport, fp);
 	}
 	fc_frame_free(in_fp);
 }
 
 /**
  * fc_lport_recv_rnid_req() - Handle received Request Node ID data request
- * @sp:	   The sequence in the RNID exchange
- * @fp:	   The RNID request frame
  * @lport: The local port recieving the RNID
+ * @fp:	   The RNID request frame
  *
  * Locking Note: The lport lock is expected to be held before calling
  * this function.
  */
-static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
-				   struct fc_lport *lport)
+static void fc_lport_recv_rnid_req(struct fc_lport *lport,
+				   struct fc_frame *in_fp)
 {
 	struct fc_frame *fp;
-	struct fc_exch *ep = fc_seq_exch(sp);
 	struct fc_els_rnid *req;
 	struct {
 		struct fc_els_rnid_resp rnid;
@@ -457,17 +447,15 @@
 	struct fc_seq_els_data rjt_data;
 	u8 fmt;
 	size_t len;
-	u32 f_ctl;
 
 	FC_LPORT_DBG(lport, "Received RNID request while in state %s\n",
 		     fc_lport_state(lport));
 
 	req = fc_frame_payload_get(in_fp, sizeof(*req));
 	if (!req) {
-		rjt_data.fp = NULL;
 		rjt_data.reason = ELS_RJT_LOGIC;
 		rjt_data.explan = ELS_EXPL_NONE;
-		lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+		lport->tt.seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data);
 	} else {
 		fmt = req->rnid_fmt;
 		len = sizeof(*rp);
@@ -490,12 +478,8 @@
 				memcpy(&rp->gen, &lport->rnid_gen,
 				       sizeof(rp->gen));
 			}
-			sp = lport->tt.seq_start_next(sp);
-			f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
-			f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
-			fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
-				       FC_TYPE_ELS, f_ctl, 0);
-			lport->tt.seq_send(lport, sp, fp);
+			fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0);
+			lport->tt.frame_send(lport, fp);
 		}
 	}
 	fc_frame_free(in_fp);
@@ -503,17 +487,15 @@
 
 /**
  * fc_lport_recv_logo_req() - Handle received fabric LOGO request
- * @sp:	   The sequence in the LOGO exchange
- * @fp:	   The LOGO request frame
  * @lport: The local port recieving the LOGO
+ * @fp:	   The LOGO request frame
  *
  * Locking Note: The lport lock is exected to be held before calling
  * this function.
  */
-static void fc_lport_recv_logo_req(struct fc_seq *sp, struct fc_frame *fp,
-				   struct fc_lport *lport)
+static void fc_lport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp)
 {
-	lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
+	lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL);
 	fc_lport_enter_reset(lport);
 	fc_frame_free(fp);
 }
@@ -755,10 +737,37 @@
 }
 
 /**
+ * fc_lport_set_port_id() - set the local port Port ID for point-to-multipoint
+ * @lport: The local port which will have its Port ID set.
+ * @port_id: The new port ID.
+ *
+ * Called by the lower-level driver when transport sets the local port_id.
+ * This is used in VN_port to VN_port mode for FCoE, and causes FLOGI and
+ * discovery to be skipped.
+ */
+void fc_lport_set_local_id(struct fc_lport *lport, u32 port_id)
+{
+	mutex_lock(&lport->lp_mutex);
+
+	fc_lport_set_port_id(lport, port_id, NULL);
+
+	switch (lport->state) {
+	case LPORT_ST_RESET:
+	case LPORT_ST_FLOGI:
+		if (port_id)
+			fc_lport_enter_ready(lport);
+		break;
+	default:
+		break;
+	}
+	mutex_unlock(&lport->lp_mutex);
+}
+EXPORT_SYMBOL(fc_lport_set_local_id);
+
+/**
  * fc_lport_recv_flogi_req() - Receive a FLOGI request
- * @sp_in: The sequence the FLOGI is on
- * @rx_fp: The FLOGI frame
  * @lport: The local port that recieved the request
+ * @rx_fp: The FLOGI frame
  *
  * A received FLOGI request indicates a point-to-point connection.
  * Accept it with the common service parameters indicating our N port.
@@ -767,26 +776,21 @@
  * Locking Note: The lport lock is expected to be held before calling
  * this function.
  */
-static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
-				    struct fc_frame *rx_fp,
-				    struct fc_lport *lport)
+static void fc_lport_recv_flogi_req(struct fc_lport *lport,
+				    struct fc_frame *rx_fp)
 {
 	struct fc_frame *fp;
 	struct fc_frame_header *fh;
-	struct fc_seq *sp;
-	struct fc_exch *ep;
 	struct fc_els_flogi *flp;
 	struct fc_els_flogi *new_flp;
 	u64 remote_wwpn;
 	u32 remote_fid;
 	u32 local_fid;
-	u32 f_ctl;
 
 	FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n",
 		     fc_lport_state(lport));
 
-	fh = fc_frame_header_get(rx_fp);
-	remote_fid = ntoh24(fh->fh_s_id);
+	remote_fid = fc_frame_sid(rx_fp);
 	flp = fc_frame_payload_get(rx_fp, sizeof(*flp));
 	if (!flp)
 		goto out;
@@ -817,7 +821,6 @@
 
 	fp = fc_frame_alloc(lport, sizeof(*flp));
 	if (fp) {
-		sp = lport->tt.seq_start_next(fr_seq(rx_fp));
 		new_flp = fc_frame_payload_get(fp, sizeof(*flp));
 		fc_lport_flogi_fill(lport, new_flp, ELS_FLOGI);
 		new_flp->fl_cmd = (u8) ELS_LS_ACC;
@@ -826,27 +829,24 @@
 		 * Send the response.  If this fails, the originator should
 		 * repeat the sequence.
 		 */
-		f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
-		ep = fc_seq_exch(sp);
-		fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, remote_fid, local_fid,
-			       FC_TYPE_ELS, f_ctl, 0);
-		lport->tt.seq_send(lport, sp, fp);
+		fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+		fh = fc_frame_header_get(fp);
+		hton24(fh->fh_s_id, local_fid);
+		hton24(fh->fh_d_id, remote_fid);
+		lport->tt.frame_send(lport, fp);
 
 	} else {
 		fc_lport_error(lport, fp);
 	}
 	fc_lport_ptp_setup(lport, remote_fid, remote_wwpn,
 			   get_unaligned_be64(&flp->fl_wwnn));
-
 out:
-	sp = fr_seq(rx_fp);
 	fc_frame_free(rx_fp);
 }
 
 /**
  * fc_lport_recv_req() - The generic lport request handler
  * @lport: The local port that received the request
- * @sp:	   The sequence the request is on
  * @fp:	   The request frame
  *
  * This function will see if the lport handles the request or
@@ -855,11 +855,10 @@
  * Locking Note: This function should not be called with the lport
  *		 lock held becuase it will grab the lock.
  */
-static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
-			      struct fc_frame *fp)
+static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
 {
 	struct fc_frame_header *fh = fc_frame_header_get(fp);
-	void (*recv) (struct fc_seq *, struct fc_frame *, struct fc_lport *);
+	void (*recv)(struct fc_lport *, struct fc_frame *);
 
 	mutex_lock(&lport->lp_mutex);
 
@@ -878,11 +877,11 @@
 		recv = lport->tt.rport_recv_req;
 		switch (fc_frame_payload_op(fp)) {
 		case ELS_FLOGI:
-			recv = fc_lport_recv_flogi_req;
+			if (!lport->point_to_multipoint)
+				recv = fc_lport_recv_flogi_req;
 			break;
 		case ELS_LOGO:
-			fh = fc_frame_header_get(fp);
-			if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI)
+			if (fc_frame_sid(fp) == FC_FID_FLOGI)
 				recv = fc_lport_recv_logo_req;
 			break;
 		case ELS_RSCN:
@@ -899,19 +898,13 @@
 			break;
 		}
 
-		recv(sp, fp, lport);
+		recv(lport, fp);
 	} else {
 		FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n",
 			     fr_eof(fp));
 		fc_frame_free(fp);
 	}
 	mutex_unlock(&lport->lp_mutex);
-
-	/*
-	 *  The common exch_done for all request may not be good
-	 *  if any request requires longer hold on exhange. XXX
-	 */
-	lport->tt.exch_done(sp);
 }
 
 /**
@@ -954,7 +947,7 @@
 	lport->tt.exch_mgr_reset(lport, 0, 0);
 	fc_host_fabric_name(lport->host) = 0;
 
-	if (lport->port_id)
+	if (lport->port_id && (!lport->point_to_multipoint || !lport->link_up))
 		fc_lport_set_port_id(lport, 0, NULL);
 }
 
@@ -1019,38 +1012,24 @@
 		     PTR_ERR(fp), fc_lport_state(lport),
 		     lport->retry_count);
 
-	if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) {
-		/*
-		 * Memory allocation failure, or the exchange timed out.
-		 *  Retry after delay
-		 */
-		if (lport->retry_count < lport->max_retry_count) {
-			lport->retry_count++;
-			if (!fp)
-				delay = msecs_to_jiffies(500);
-			else
-				delay =	msecs_to_jiffies(lport->e_d_tov);
+	if (PTR_ERR(fp) == -FC_EX_CLOSED)
+		return;
 
-			schedule_delayed_work(&lport->retry_work, delay);
-		} else {
-			switch (lport->state) {
-			case LPORT_ST_DISABLED:
-			case LPORT_ST_READY:
-			case LPORT_ST_RESET:
-			case LPORT_ST_RNN_ID:
-			case LPORT_ST_RSNN_NN:
-			case LPORT_ST_RSPN_ID:
-			case LPORT_ST_RFT_ID:
-			case LPORT_ST_RFF_ID:
-			case LPORT_ST_SCR:
-			case LPORT_ST_DNS:
-			case LPORT_ST_FLOGI:
-			case LPORT_ST_LOGO:
-				fc_lport_enter_reset(lport);
-				break;
-			}
-		}
-	}
+	/*
+	 * Memory allocation failure, or the exchange timed out
+	 * or we received LS_RJT.
+	 * Retry after delay
+	 */
+	if (lport->retry_count < lport->max_retry_count) {
+		lport->retry_count++;
+		if (!fp)
+			delay = msecs_to_jiffies(500);
+		else
+			delay =	msecs_to_jiffies(lport->e_d_tov);
+
+		schedule_delayed_work(&lport->retry_work, delay);
+	} else
+		fc_lport_enter_reset(lport);
 }
 
 /**
@@ -1440,7 +1419,6 @@
 			 void *lp_arg)
 {
 	struct fc_lport *lport = lp_arg;
-	struct fc_frame_header *fh;
 	struct fc_els_flogi *flp;
 	u32 did;
 	u16 csp_flags;
@@ -1468,9 +1446,14 @@
 		goto err;
 	}
 
-	fh = fc_frame_header_get(fp);
-	did = ntoh24(fh->fh_d_id);
-	if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) {
+	did = fc_frame_did(fp);
+
+	if (!did) {
+		FC_LPORT_DBG(lport, "Bad FLOGI response\n");
+		goto out;
+	}
+
+	if (fc_frame_payload_op(fp) == ELS_LS_ACC) {
 		flp = fc_frame_payload_get(fp, sizeof(*flp));
 		if (flp) {
 			mfs = ntohs(flp->fl_csp.sp_bb_data) &
@@ -1495,7 +1478,7 @@
 				       "Port (%6.6x) entered "
 				       "point-to-point mode\n",
 				       lport->host->host_no, did);
-				fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id),
+				fc_lport_ptp_setup(lport, fc_frame_sid(fp),
 						   get_unaligned_be64(
 							   &flp->fl_wwpn),
 						   get_unaligned_be64(
@@ -1509,9 +1492,8 @@
 				fc_lport_enter_dns(lport);
 			}
 		}
-	} else {
-		FC_LPORT_DBG(lport, "Bad FLOGI response\n");
-	}
+	} else
+		fc_lport_error(lport, fp);
 
 out:
 	fc_frame_free(fp);
@@ -1536,6 +1518,12 @@
 
 	fc_lport_state_enter(lport, LPORT_ST_FLOGI);
 
+	if (lport->point_to_multipoint) {
+		if (lport->port_id)
+			fc_lport_enter_ready(lport);
+		return;
+	}
+
 	fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
 	if (!fp)
 		return fc_lport_error(lport, fp);
@@ -1701,8 +1689,7 @@
 	hton24(fh->fh_d_id, did);
 	hton24(fh->fh_s_id, lport->port_id);
 	fh->fh_type = FC_TYPE_ELS;
-	hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
-	       FC_FC_END_SEQ | FC_FC_SEQ_INIT);
+	hton24(fh->fh_f_ctl, FC_FCTL_REQ);
 	fh->fh_cs_ctl = 0;
 	fh->fh_df_ctl = 0;
 	fh->fh_parm_offset = 0;
@@ -1761,8 +1748,7 @@
 	hton24(fh->fh_d_id, did);
 	hton24(fh->fh_s_id, lport->port_id);
 	fh->fh_type = FC_TYPE_CT;
-	hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
-	       FC_FC_END_SEQ | FC_FC_SEQ_INIT);
+	hton24(fh->fh_f_ctl, FC_FCTL_REQ);
 	fh->fh_cs_ctl = 0;
 	fh->fh_df_ctl = 0;
 	fh->fh_parm_offset = 0;
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 2aa5993..b9f2286 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -60,6 +60,7 @@
 
 struct workqueue_struct *rport_event_queue;
 
+static void fc_rport_enter_flogi(struct fc_rport_priv *);
 static void fc_rport_enter_plogi(struct fc_rport_priv *);
 static void fc_rport_enter_prli(struct fc_rport_priv *);
 static void fc_rport_enter_rtv(struct fc_rport_priv *);
@@ -67,14 +68,10 @@
 static void fc_rport_enter_logo(struct fc_rport_priv *);
 static void fc_rport_enter_adisc(struct fc_rport_priv *);
 
-static void fc_rport_recv_plogi_req(struct fc_lport *,
-				    struct fc_seq *, struct fc_frame *);
-static void fc_rport_recv_prli_req(struct fc_rport_priv *,
-				   struct fc_seq *, struct fc_frame *);
-static void fc_rport_recv_prlo_req(struct fc_rport_priv *,
-				   struct fc_seq *, struct fc_frame *);
-static void fc_rport_recv_logo_req(struct fc_lport *,
-				   struct fc_seq *, struct fc_frame *);
+static void fc_rport_recv_plogi_req(struct fc_lport *, struct fc_frame *);
+static void fc_rport_recv_prli_req(struct fc_rport_priv *, struct fc_frame *);
+static void fc_rport_recv_prlo_req(struct fc_rport_priv *, struct fc_frame *);
+static void fc_rport_recv_logo_req(struct fc_lport *, struct fc_frame *);
 static void fc_rport_timeout(struct work_struct *);
 static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *);
 static void fc_rport_error_retry(struct fc_rport_priv *, struct fc_frame *);
@@ -82,27 +79,29 @@
 
 static const char *fc_rport_state_names[] = {
 	[RPORT_ST_INIT] = "Init",
+	[RPORT_ST_FLOGI] = "FLOGI",
+	[RPORT_ST_PLOGI_WAIT] = "PLOGI_WAIT",
 	[RPORT_ST_PLOGI] = "PLOGI",
 	[RPORT_ST_PRLI] = "PRLI",
 	[RPORT_ST_RTV] = "RTV",
 	[RPORT_ST_READY] = "Ready",
-	[RPORT_ST_LOGO] = "LOGO",
 	[RPORT_ST_ADISC] = "ADISC",
 	[RPORT_ST_DELETE] = "Delete",
-	[RPORT_ST_RESTART] = "Restart",
 };
 
 /**
  * fc_rport_lookup() - Lookup a remote port by port_id
  * @lport:   The local port to lookup the remote port on
  * @port_id: The remote port ID to look up
+ *
+ * The caller must hold either disc_mutex or rcu_read_lock().
  */
 static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
 					     u32 port_id)
 {
 	struct fc_rport_priv *rdata;
 
-	list_for_each_entry(rdata, &lport->disc.rports, peers)
+	list_for_each_entry_rcu(rdata, &lport->disc.rports, peers)
 		if (rdata->ids.port_id == port_id)
 			return rdata;
 	return NULL;
@@ -126,7 +125,7 @@
 	if (rdata)
 		return rdata;
 
-	rdata = kzalloc(sizeof(*rdata), GFP_KERNEL);
+	rdata = kzalloc(sizeof(*rdata) + lport->rport_priv_size, GFP_KERNEL);
 	if (!rdata)
 		return NULL;
 
@@ -147,11 +146,23 @@
 	INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
 	INIT_WORK(&rdata->event_work, fc_rport_work);
 	if (port_id != FC_FID_DIR_SERV)
-		list_add(&rdata->peers, &lport->disc.rports);
+		list_add_rcu(&rdata->peers, &lport->disc.rports);
 	return rdata;
 }
 
 /**
+ * fc_rport_free_rcu() - Free a remote port
+ * @rcu: The rcu_head structure inside the remote port
+ */
+static void fc_rport_free_rcu(struct rcu_head *rcu)
+{
+	struct fc_rport_priv *rdata;
+
+	rdata = container_of(rcu, struct fc_rport_priv, rcu);
+	kfree(rdata);
+}
+
+/**
  * fc_rport_destroy() - Free a remote port after last reference is released
  * @kref: The remote port's kref
  */
@@ -160,7 +171,7 @@
 	struct fc_rport_priv *rdata;
 
 	rdata = container_of(kref, struct fc_rport_priv, kref);
-	kfree(rdata);
+	call_rcu(&rdata->rcu, fc_rport_free_rcu);
 }
 
 /**
@@ -194,7 +205,7 @@
 /**
  * fc_plogi_get_maxframe() - Get the maximum payload from the common service
  *			     parameters in a FLOGI frame
- * @flp:    The FLOGI payload
+ * @flp:    The FLOGI or PLOGI payload
  * @maxval: The maximum frame size upper limit; this may be less than what
  *	    is in the service parameters
  */
@@ -246,7 +257,6 @@
 	struct fc_rport_operations *rport_ops;
 	struct fc_rport_identifiers ids;
 	struct fc_rport *rport;
-	int restart = 0;
 
 	mutex_lock(&rdata->rp_mutex);
 	event = rdata->event;
@@ -259,6 +269,7 @@
 	case RPORT_EV_READY:
 		ids = rdata->ids;
 		rdata->event = RPORT_EV_NONE;
+		rdata->major_retries = 0;
 		kref_get(&rdata->kref);
 		mutex_unlock(&rdata->rp_mutex);
 
@@ -298,24 +309,6 @@
 		port_id = rdata->ids.port_id;
 		mutex_unlock(&rdata->rp_mutex);
 
-		if (port_id != FC_FID_DIR_SERV) {
-			/*
-			 * We must drop rp_mutex before taking disc_mutex.
-			 * Re-evaluate state to allow for restart.
-			 * A transition to RESTART state must only happen
-			 * while disc_mutex is held and rdata is on the list.
-			 */
-			mutex_lock(&lport->disc.disc_mutex);
-			mutex_lock(&rdata->rp_mutex);
-			if (rdata->rp_state == RPORT_ST_RESTART)
-				restart = 1;
-			else
-				list_del(&rdata->peers);
-			rdata->event = RPORT_EV_NONE;
-			mutex_unlock(&rdata->rp_mutex);
-			mutex_unlock(&lport->disc.disc_mutex);
-		}
-
 		if (rport_ops && rport_ops->event_callback) {
 			FC_RPORT_DBG(rdata, "callback ev %d\n", event);
 			rport_ops->event_callback(lport, rdata, event);
@@ -336,13 +329,37 @@
 			mutex_unlock(&rdata->rp_mutex);
 			fc_remote_port_delete(rport);
 		}
-		if (restart) {
-			mutex_lock(&rdata->rp_mutex);
-			FC_RPORT_DBG(rdata, "work restart\n");
-			fc_rport_enter_plogi(rdata);
+
+		mutex_lock(&lport->disc.disc_mutex);
+		mutex_lock(&rdata->rp_mutex);
+		if (rdata->rp_state == RPORT_ST_DELETE) {
+			if (port_id == FC_FID_DIR_SERV) {
+				rdata->event = RPORT_EV_NONE;
+				mutex_unlock(&rdata->rp_mutex);
+			} else if ((rdata->flags & FC_RP_STARTED) &&
+				   rdata->major_retries <
+				   lport->max_rport_retry_count) {
+				rdata->major_retries++;
+				rdata->event = RPORT_EV_NONE;
+				FC_RPORT_DBG(rdata, "work restart\n");
+				fc_rport_enter_flogi(rdata);
+				mutex_unlock(&rdata->rp_mutex);
+			} else {
+				FC_RPORT_DBG(rdata, "work delete\n");
+				list_del_rcu(&rdata->peers);
+				mutex_unlock(&rdata->rp_mutex);
+				kref_put(&rdata->kref, lport->tt.rport_destroy);
+			}
+		} else {
+			/*
+			 * Re-open for events.  Reissue READY event if ready.
+			 */
+			rdata->event = RPORT_EV_NONE;
+			if (rdata->rp_state == RPORT_ST_READY)
+				fc_rport_enter_ready(rdata);
 			mutex_unlock(&rdata->rp_mutex);
-		} else
-			kref_put(&rdata->kref, lport->tt.rport_destroy);
+		}
+		mutex_unlock(&lport->disc.disc_mutex);
 		break;
 
 	default:
@@ -367,20 +384,18 @@
 {
 	mutex_lock(&rdata->rp_mutex);
 
+	rdata->flags |= FC_RP_STARTED;
 	switch (rdata->rp_state) {
 	case RPORT_ST_READY:
 		FC_RPORT_DBG(rdata, "ADISC port\n");
 		fc_rport_enter_adisc(rdata);
 		break;
-	case RPORT_ST_RESTART:
-		break;
 	case RPORT_ST_DELETE:
 		FC_RPORT_DBG(rdata, "Restart deleted port\n");
-		fc_rport_state_enter(rdata, RPORT_ST_RESTART);
 		break;
 	default:
 		FC_RPORT_DBG(rdata, "Login to port\n");
-		fc_rport_enter_plogi(rdata);
+		fc_rport_enter_flogi(rdata);
 		break;
 	}
 	mutex_unlock(&rdata->rp_mutex);
@@ -431,15 +446,12 @@
 
 	FC_RPORT_DBG(rdata, "Remove port\n");
 
+	rdata->flags &= ~FC_RP_STARTED;
 	if (rdata->rp_state == RPORT_ST_DELETE) {
 		FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
 		goto out;
 	}
-
-	if (rdata->rp_state == RPORT_ST_RESTART)
-		FC_RPORT_DBG(rdata, "Port in Restart state, deleting\n");
-	else
-		fc_rport_enter_logo(rdata);
+	fc_rport_enter_logo(rdata);
 
 	/*
 	 * Change the state to Delete so that we discard
@@ -485,6 +497,9 @@
 	mutex_lock(&rdata->rp_mutex);
 
 	switch (rdata->rp_state) {
+	case RPORT_ST_FLOGI:
+		fc_rport_enter_flogi(rdata);
+		break;
 	case RPORT_ST_PLOGI:
 		fc_rport_enter_plogi(rdata);
 		break;
@@ -494,16 +509,13 @@
 	case RPORT_ST_RTV:
 		fc_rport_enter_rtv(rdata);
 		break;
-	case RPORT_ST_LOGO:
-		fc_rport_enter_logo(rdata);
-		break;
 	case RPORT_ST_ADISC:
 		fc_rport_enter_adisc(rdata);
 		break;
+	case RPORT_ST_PLOGI_WAIT:
 	case RPORT_ST_READY:
 	case RPORT_ST_INIT:
 	case RPORT_ST_DELETE:
-	case RPORT_ST_RESTART:
 		break;
 	}
 
@@ -525,8 +537,9 @@
 		     fc_rport_state(rdata), rdata->retries);
 
 	switch (rdata->rp_state) {
+	case RPORT_ST_FLOGI:
 	case RPORT_ST_PLOGI:
-	case RPORT_ST_LOGO:
+		rdata->flags &= ~FC_RP_STARTED;
 		fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
 		break;
 	case RPORT_ST_RTV:
@@ -536,8 +549,8 @@
 	case RPORT_ST_ADISC:
 		fc_rport_enter_logo(rdata);
 		break;
+	case RPORT_ST_PLOGI_WAIT:
 	case RPORT_ST_DELETE:
-	case RPORT_ST_RESTART:
 	case RPORT_ST_READY:
 	case RPORT_ST_INIT:
 		break;
@@ -579,7 +592,250 @@
 }
 
 /**
- * fc_rport_plogi_recv_resp() - Handler for ELS PLOGI responses
+ * fc_rport_login_complete() - Handle parameters and completion of p-mp login.
+ * @rdata:  The remote port which we logged into or which logged into us.
+ * @fp:     The FLOGI or PLOGI request or response frame
+ *
+ * Returns non-zero error if a problem is detected with the frame.
+ * Does not free the frame.
+ *
+ * This is only used in point-to-multipoint mode for FIP currently.
+ */
+static int fc_rport_login_complete(struct fc_rport_priv *rdata,
+				   struct fc_frame *fp)
+{
+	struct fc_lport *lport = rdata->local_port;
+	struct fc_els_flogi *flogi;
+	unsigned int e_d_tov;
+	u16 csp_flags;
+
+	flogi = fc_frame_payload_get(fp, sizeof(*flogi));
+	if (!flogi)
+		return -EINVAL;
+
+	csp_flags = ntohs(flogi->fl_csp.sp_features);
+
+	if (fc_frame_payload_op(fp) == ELS_FLOGI) {
+		if (csp_flags & FC_SP_FT_FPORT) {
+			FC_RPORT_DBG(rdata, "Fabric bit set in FLOGI\n");
+			return -EINVAL;
+		}
+	} else {
+
+		/*
+		 * E_D_TOV is not valid on an incoming FLOGI request.
+		 */
+		e_d_tov = ntohl(flogi->fl_csp.sp_e_d_tov);
+		if (csp_flags & FC_SP_FT_EDTR)
+			e_d_tov /= 1000000;
+		if (e_d_tov > rdata->e_d_tov)
+			rdata->e_d_tov = e_d_tov;
+	}
+	rdata->maxframe_size = fc_plogi_get_maxframe(flogi, lport->mfs);
+	return 0;
+}
+
+/**
+ * fc_rport_flogi_resp() - Handle response to FLOGI request for p-mp mode
+ * @sp:	    The sequence that the FLOGI was on
+ * @fp:	    The FLOGI response frame
+ * @rp_arg: The remote port that received the FLOGI response
+ */
+void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
+			 void *rp_arg)
+{
+	struct fc_rport_priv *rdata = rp_arg;
+	struct fc_lport *lport = rdata->local_port;
+	struct fc_els_flogi *flogi;
+	unsigned int r_a_tov;
+
+	FC_RPORT_DBG(rdata, "Received a FLOGI %s\n", fc_els_resp_type(fp));
+
+	if (fp == ERR_PTR(-FC_EX_CLOSED))
+		return;
+
+	mutex_lock(&rdata->rp_mutex);
+
+	if (rdata->rp_state != RPORT_ST_FLOGI) {
+		FC_RPORT_DBG(rdata, "Received a FLOGI response, but in state "
+			     "%s\n", fc_rport_state(rdata));
+		if (IS_ERR(fp))
+			goto err;
+		goto out;
+	}
+
+	if (IS_ERR(fp)) {
+		fc_rport_error(rdata, fp);
+		goto err;
+	}
+
+	if (fc_frame_payload_op(fp) != ELS_LS_ACC)
+		goto bad;
+	if (fc_rport_login_complete(rdata, fp))
+		goto bad;
+
+	flogi = fc_frame_payload_get(fp, sizeof(*flogi));
+	if (!flogi)
+		goto bad;
+	r_a_tov = ntohl(flogi->fl_csp.sp_r_a_tov);
+	if (r_a_tov > rdata->r_a_tov)
+		rdata->r_a_tov = r_a_tov;
+
+	if (rdata->ids.port_name < lport->wwpn)
+		fc_rport_enter_plogi(rdata);
+	else
+		fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT);
+out:
+	fc_frame_free(fp);
+err:
+	mutex_unlock(&rdata->rp_mutex);
+	kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
+	return;
+bad:
+	FC_RPORT_DBG(rdata, "Bad FLOGI response\n");
+	fc_rport_error_retry(rdata, fp);
+	goto out;
+}
+
+/**
+ * fc_rport_enter_flogi() - Send a FLOGI request to the remote port for p-mp
+ * @rdata: The remote port to send a FLOGI to
+ *
+ * Locking Note: The rport lock is expected to be held before calling
+ * this routine.
+ */
+static void fc_rport_enter_flogi(struct fc_rport_priv *rdata)
+{
+	struct fc_lport *lport = rdata->local_port;
+	struct fc_frame *fp;
+
+	if (!lport->point_to_multipoint)
+		return fc_rport_enter_plogi(rdata);
+
+	FC_RPORT_DBG(rdata, "Entered FLOGI state from %s state\n",
+		     fc_rport_state(rdata));
+
+	fc_rport_state_enter(rdata, RPORT_ST_FLOGI);
+
+	fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
+	if (!fp)
+		return fc_rport_error_retry(rdata, fp);
+
+	if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_FLOGI,
+				  fc_rport_flogi_resp, rdata,
+				  2 * lport->r_a_tov))
+		fc_rport_error_retry(rdata, NULL);
+	else
+		kref_get(&rdata->kref);
+}
+
+/**
+ * fc_rport_recv_flogi_req() - Handle Fabric Login (FLOGI) request in p-mp mode
+ * @lport: The local port that received the PLOGI request
+ * @rx_fp: The PLOGI request frame
+ */
+static void fc_rport_recv_flogi_req(struct fc_lport *lport,
+				    struct fc_frame *rx_fp)
+{
+	struct fc_disc *disc;
+	struct fc_els_flogi *flp;
+	struct fc_rport_priv *rdata;
+	struct fc_frame *fp = rx_fp;
+	struct fc_seq_els_data rjt_data;
+	u32 sid;
+
+	sid = fc_frame_sid(fp);
+
+	FC_RPORT_ID_DBG(lport, sid, "Received FLOGI request\n");
+
+	disc = &lport->disc;
+	mutex_lock(&disc->disc_mutex);
+
+	if (!lport->point_to_multipoint) {
+		rjt_data.reason = ELS_RJT_UNSUP;
+		rjt_data.explan = ELS_EXPL_NONE;
+		goto reject;
+	}
+
+	flp = fc_frame_payload_get(fp, sizeof(*flp));
+	if (!flp) {
+		rjt_data.reason = ELS_RJT_LOGIC;
+		rjt_data.explan = ELS_EXPL_INV_LEN;
+		goto reject;
+	}
+
+	rdata = lport->tt.rport_lookup(lport, sid);
+	if (!rdata) {
+		rjt_data.reason = ELS_RJT_FIP;
+		rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR;
+		goto reject;
+	}
+	mutex_lock(&rdata->rp_mutex);
+
+	FC_RPORT_DBG(rdata, "Received FLOGI in %s state\n",
+		     fc_rport_state(rdata));
+
+	switch (rdata->rp_state) {
+	case RPORT_ST_INIT:
+	case RPORT_ST_DELETE:
+		mutex_unlock(&rdata->rp_mutex);
+		rjt_data.reason = ELS_RJT_FIP;
+		rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR;
+		goto reject;
+	case RPORT_ST_FLOGI:
+	case RPORT_ST_PLOGI_WAIT:
+	case RPORT_ST_PLOGI:
+		break;
+	case RPORT_ST_PRLI:
+	case RPORT_ST_RTV:
+	case RPORT_ST_READY:
+	case RPORT_ST_ADISC:
+		/*
+		 * Set the remote port to be deleted and to then restart.
+		 * This queues work to be sure exchanges are reset.
+		 */
+		fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
+		mutex_unlock(&rdata->rp_mutex);
+		rjt_data.reason = ELS_RJT_BUSY;
+		rjt_data.explan = ELS_EXPL_NONE;
+		goto reject;
+	}
+	if (fc_rport_login_complete(rdata, fp)) {
+		mutex_unlock(&rdata->rp_mutex);
+		rjt_data.reason = ELS_RJT_LOGIC;
+		rjt_data.explan = ELS_EXPL_NONE;
+		goto reject;
+	}
+
+	fp = fc_frame_alloc(lport, sizeof(*flp));
+	if (!fp)
+		goto out;
+
+	fc_flogi_fill(lport, fp);
+	flp = fc_frame_payload_get(fp, sizeof(*flp));
+	flp->fl_cmd = ELS_LS_ACC;
+
+	fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+	lport->tt.frame_send(lport, fp);
+
+	if (rdata->ids.port_name < lport->wwpn)
+		fc_rport_enter_plogi(rdata);
+	else
+		fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT);
+out:
+	mutex_unlock(&rdata->rp_mutex);
+	mutex_unlock(&disc->disc_mutex);
+	fc_frame_free(rx_fp);
+	return;
+
+reject:
+	mutex_unlock(&disc->disc_mutex);
+	lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data);
+	fc_frame_free(rx_fp);
+}
+
+/**
+ * fc_rport_plogi_resp() - Handler for ELS PLOGI responses
  * @sp:	       The sequence the PLOGI is on
  * @fp:	       The PLOGI response frame
  * @rdata_arg: The remote port that sent the PLOGI response
@@ -594,7 +850,6 @@
 	struct fc_rport_priv *rdata = rdata_arg;
 	struct fc_lport *lport = rdata->local_port;
 	struct fc_els_flogi *plp = NULL;
-	unsigned int tov;
 	u16 csp_seq;
 	u16 cssp_seq;
 	u8 op;
@@ -622,11 +877,8 @@
 		rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn);
 		rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn);
 
-		tov = ntohl(plp->fl_csp.sp_e_d_tov);
-		if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR)
-			tov /= 1000000;
-		if (tov > rdata->e_d_tov)
-			rdata->e_d_tov = tov;
+		if (lport->point_to_multipoint)
+			fc_rport_login_complete(rdata, fp);
 		csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
 		cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq);
 		if (cssp_seq < csp_seq)
@@ -664,6 +916,7 @@
 	rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
 	fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
 	if (!fp) {
+		FC_RPORT_DBG(rdata, "%s frame alloc failed\n", __func__);
 		fc_rport_error_retry(rdata, fp);
 		return;
 	}
@@ -698,6 +951,7 @@
 	u32 roles = FC_RPORT_ROLE_UNKNOWN;
 	u32 fcp_parm = 0;
 	u8 op;
+	u8 resp_code = 0;
 
 	mutex_lock(&rdata->rp_mutex);
 
@@ -722,11 +976,25 @@
 	op = fc_frame_payload_op(fp);
 	if (op == ELS_LS_ACC) {
 		pp = fc_frame_payload_get(fp, sizeof(*pp));
-		if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) {
-			fcp_parm = ntohl(pp->spp.spp_params);
-			if (fcp_parm & FCP_SPPF_RETRY)
-				rdata->flags |= FC_RP_FLAGS_RETRY;
+		if (!pp)
+			goto out;
+
+		resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK);
+		FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x\n",
+			     pp->spp.spp_flags);
+		if (resp_code != FC_SPP_RESP_ACK) {
+			if (resp_code == FC_SPP_RESP_CONF)
+				fc_rport_error(rdata, fp);
+			else
+				fc_rport_error_retry(rdata, fp);
+			goto out;
 		}
+		if (pp->prli.prli_spp_len < sizeof(pp->spp))
+			goto out;
+
+		fcp_parm = ntohl(pp->spp.spp_params);
+		if (fcp_parm & FCP_SPPF_RETRY)
+			rdata->flags |= FC_RP_FLAGS_RETRY;
 
 		rdata->supported_classes = FC_COS_CLASS3;
 		if (fcp_parm & FCP_SPPF_INIT_FCN)
@@ -739,55 +1007,9 @@
 
 	} else {
 		FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n");
-		fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
-	}
-
-out:
-	fc_frame_free(fp);
-err:
-	mutex_unlock(&rdata->rp_mutex);
-	kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
-}
-
-/**
- * fc_rport_logo_resp() - Handler for logout (LOGO) responses
- * @sp:	       The sequence the LOGO was on
- * @fp:	       The LOGO response frame
- * @rdata_arg: The remote port that sent the LOGO response
- *
- * Locking Note: This function will be called without the rport lock
- * held, but it will lock, call an _enter_* function or fc_rport_error
- * and then unlock the rport.
- */
-static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
-			       void *rdata_arg)
-{
-	struct fc_rport_priv *rdata = rdata_arg;
-	u8 op;
-
-	mutex_lock(&rdata->rp_mutex);
-
-	FC_RPORT_DBG(rdata, "Received a LOGO %s\n", fc_els_resp_type(fp));
-
-	if (rdata->rp_state != RPORT_ST_LOGO) {
-		FC_RPORT_DBG(rdata, "Received a LOGO response, but in state "
-			     "%s\n", fc_rport_state(rdata));
-		if (IS_ERR(fp))
-			goto err;
-		goto out;
-	}
-
-	if (IS_ERR(fp)) {
 		fc_rport_error_retry(rdata, fp);
-		goto err;
 	}
 
-	op = fc_frame_payload_op(fp);
-	if (op != ELS_LS_ACC)
-		FC_RPORT_DBG(rdata, "Bad ELS response op %x for LOGO command\n",
-			     op);
-	fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
-
 out:
 	fc_frame_free(fp);
 err:
@@ -937,6 +1159,24 @@
 }
 
 /**
+ * fc_rport_logo_resp() - Handler for logout (LOGO) responses
+ * @sp:	       The sequence the LOGO was on
+ * @fp:	       The LOGO response frame
+ * @lport_arg: The local port
+ */
+static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
+			       void *lport_arg)
+{
+	struct fc_lport *lport = lport_arg;
+
+	FC_RPORT_ID_DBG(lport, fc_seq_exch(sp)->did,
+			"Received a LOGO %s\n", fc_els_resp_type(fp));
+	if (IS_ERR(fp))
+		return;
+	fc_frame_free(fp);
+}
+
+/**
  * fc_rport_enter_logo() - Send a logout (LOGO) request
  * @rdata: The remote port to send the LOGO request to
  *
@@ -948,23 +1188,14 @@
 	struct fc_lport *lport = rdata->local_port;
 	struct fc_frame *fp;
 
-	FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n",
+	FC_RPORT_DBG(rdata, "Port sending LOGO from %s state\n",
 		     fc_rport_state(rdata));
 
-	fc_rport_state_enter(rdata, RPORT_ST_LOGO);
-
 	fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
-	if (!fp) {
-		fc_rport_error_retry(rdata, fp);
+	if (!fp)
 		return;
-	}
-
-	if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
-				  fc_rport_logo_resp, rdata,
-				  2 * lport->r_a_tov))
-		fc_rport_error_retry(rdata, NULL);
-	else
-		kref_get(&rdata->kref);
+	(void)lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
+				   fc_rport_logo_resp, lport, 0);
 }
 
 /**
@@ -1013,7 +1244,7 @@
 	    get_unaligned_be64(&adisc->adisc_wwpn) != rdata->ids.port_name ||
 	    get_unaligned_be64(&adisc->adisc_wwnn) != rdata->ids.node_name) {
 		FC_RPORT_DBG(rdata, "ADISC error or mismatch\n");
-		fc_rport_enter_plogi(rdata);
+		fc_rport_enter_flogi(rdata);
 	} else {
 		FC_RPORT_DBG(rdata, "ADISC OK\n");
 		fc_rport_enter_ready(rdata);
@@ -1058,29 +1289,25 @@
 /**
  * fc_rport_recv_adisc_req() - Handler for Address Discovery (ADISC) requests
  * @rdata: The remote port that sent the ADISC request
- * @sp:	   The sequence the ADISC request was on
  * @in_fp: The ADISC request frame
  *
  * Locking Note:  Called with the lport and rport locks held.
  */
 static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata,
-				    struct fc_seq *sp, struct fc_frame *in_fp)
+				    struct fc_frame *in_fp)
 {
 	struct fc_lport *lport = rdata->local_port;
 	struct fc_frame *fp;
-	struct fc_exch *ep = fc_seq_exch(sp);
 	struct fc_els_adisc *adisc;
 	struct fc_seq_els_data rjt_data;
-	u32 f_ctl;
 
 	FC_RPORT_DBG(rdata, "Received ADISC request\n");
 
 	adisc = fc_frame_payload_get(in_fp, sizeof(*adisc));
 	if (!adisc) {
-		rjt_data.fp = NULL;
 		rjt_data.reason = ELS_RJT_PROT;
 		rjt_data.explan = ELS_EXPL_INV_LEN;
-		lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+		lport->tt.seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data);
 		goto drop;
 	}
 
@@ -1090,11 +1317,8 @@
 	fc_adisc_fill(lport, fp);
 	adisc = fc_frame_payload_get(fp, sizeof(*adisc));
 	adisc->adisc_cmd = ELS_LS_ACC;
-	sp = lport->tt.seq_start_next(sp);
-	f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT;
-	fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
-		       FC_TYPE_ELS, f_ctl, 0);
-	lport->tt.seq_send(lport, sp, fp);
+	fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0);
+	lport->tt.frame_send(lport, fp);
 drop:
 	fc_frame_free(in_fp);
 }
@@ -1102,25 +1326,22 @@
 /**
  * fc_rport_recv_rls_req() - Handle received Read Link Status request
  * @rdata: The remote port that sent the RLS request
- * @sp:	The sequence that the RLS was on
  * @rx_fp: The PRLI request frame
  *
  * Locking Note: The rport lock is expected to be held before calling
  * this function.
  */
 static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata,
-				  struct fc_seq *sp, struct fc_frame *rx_fp)
+				  struct fc_frame *rx_fp)
 
 {
 	struct fc_lport *lport = rdata->local_port;
 	struct fc_frame *fp;
-	struct fc_exch *ep = fc_seq_exch(sp);
 	struct fc_els_rls *rls;
 	struct fc_els_rls_resp *rsp;
 	struct fc_els_lesb *lesb;
 	struct fc_seq_els_data rjt_data;
 	struct fc_host_statistics *hst;
-	u32 f_ctl;
 
 	FC_RPORT_DBG(rdata, "Received RLS request while in state %s\n",
 		     fc_rport_state(rdata));
@@ -1157,16 +1378,12 @@
 		lesb->lesb_inv_crc = htonl(hst->invalid_crc_count);
 	}
 
-	sp = lport->tt.seq_start_next(sp);
-	f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
-	fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
-		       FC_TYPE_ELS, f_ctl, 0);
-	lport->tt.seq_send(lport, sp, fp);
+	fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+	lport->tt.frame_send(lport, fp);
 	goto out;
 
 out_rjt:
-	rjt_data.fp = NULL;
-	lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+	lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data);
 out:
 	fc_frame_free(rx_fp);
 }
@@ -1174,7 +1391,6 @@
 /**
  * fc_rport_recv_els_req() - Handler for validated ELS requests
  * @lport: The local port that received the ELS request
- * @sp:	   The sequence that the ELS request was on
  * @fp:	   The ELS request frame
  *
  * Handle incoming ELS requests that require port login.
@@ -1182,21 +1398,13 @@
  *
  * Locking Note: Called with the lport lock held.
  */
-static void fc_rport_recv_els_req(struct fc_lport *lport,
-				  struct fc_seq *sp, struct fc_frame *fp)
+static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp)
 {
 	struct fc_rport_priv *rdata;
-	struct fc_frame_header *fh;
 	struct fc_seq_els_data els_data;
 
-	els_data.fp = NULL;
-	els_data.reason = ELS_RJT_UNAB;
-	els_data.explan = ELS_EXPL_PLOGI_REQD;
-
-	fh = fc_frame_header_get(fp);
-
 	mutex_lock(&lport->disc.disc_mutex);
-	rdata = lport->tt.rport_lookup(lport, ntoh24(fh->fh_s_id));
+	rdata = lport->tt.rport_lookup(lport, fc_frame_sid(fp));
 	if (!rdata) {
 		mutex_unlock(&lport->disc.disc_mutex);
 		goto reject;
@@ -1217,24 +1425,24 @@
 
 	switch (fc_frame_payload_op(fp)) {
 	case ELS_PRLI:
-		fc_rport_recv_prli_req(rdata, sp, fp);
+		fc_rport_recv_prli_req(rdata, fp);
 		break;
 	case ELS_PRLO:
-		fc_rport_recv_prlo_req(rdata, sp, fp);
+		fc_rport_recv_prlo_req(rdata, fp);
 		break;
 	case ELS_ADISC:
-		fc_rport_recv_adisc_req(rdata, sp, fp);
+		fc_rport_recv_adisc_req(rdata, fp);
 		break;
 	case ELS_RRQ:
-		els_data.fp = fp;
-		lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data);
+		lport->tt.seq_els_rsp_send(fp, ELS_RRQ, NULL);
+		fc_frame_free(fp);
 		break;
 	case ELS_REC:
-		els_data.fp = fp;
-		lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data);
+		lport->tt.seq_els_rsp_send(fp, ELS_REC, NULL);
+		fc_frame_free(fp);
 		break;
 	case ELS_RLS:
-		fc_rport_recv_rls_req(rdata, sp, fp);
+		fc_rport_recv_rls_req(rdata, fp);
 		break;
 	default:
 		fc_frame_free(fp);	/* can't happen */
@@ -1245,35 +1453,38 @@
 	return;
 
 reject:
-	lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
+	els_data.reason = ELS_RJT_UNAB;
+	els_data.explan = ELS_EXPL_PLOGI_REQD;
+	lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &els_data);
 	fc_frame_free(fp);
 }
 
 /**
  * fc_rport_recv_req() - Handler for requests
- * @sp:	   The sequence the request was on
- * @fp:	   The request frame
  * @lport: The local port that received the request
+ * @fp:	   The request frame
  *
  * Locking Note: Called with the lport lock held.
  */
-void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
-		       struct fc_lport *lport)
+void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
 {
 	struct fc_seq_els_data els_data;
 
 	/*
-	 * Handle PLOGI and LOGO requests separately, since they
+	 * Handle FLOGI, PLOGI and LOGO requests separately, since they
 	 * don't require prior login.
 	 * Check for unsupported opcodes first and reject them.
 	 * For some ops, it would be incorrect to reject with "PLOGI required".
 	 */
 	switch (fc_frame_payload_op(fp)) {
+	case ELS_FLOGI:
+		fc_rport_recv_flogi_req(lport, fp);
+		break;
 	case ELS_PLOGI:
-		fc_rport_recv_plogi_req(lport, sp, fp);
+		fc_rport_recv_plogi_req(lport, fp);
 		break;
 	case ELS_LOGO:
-		fc_rport_recv_logo_req(lport, sp, fp);
+		fc_rport_recv_logo_req(lport, fp);
 		break;
 	case ELS_PRLI:
 	case ELS_PRLO:
@@ -1281,14 +1492,13 @@
 	case ELS_RRQ:
 	case ELS_REC:
 	case ELS_RLS:
-		fc_rport_recv_els_req(lport, sp, fp);
+		fc_rport_recv_els_req(lport, fp);
 		break;
 	default:
-		fc_frame_free(fp);
-		els_data.fp = NULL;
 		els_data.reason = ELS_RJT_UNSUP;
 		els_data.explan = ELS_EXPL_NONE;
-		lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
+		lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &els_data);
+		fc_frame_free(fp);
 		break;
 	}
 }
@@ -1296,26 +1506,21 @@
 /**
  * fc_rport_recv_plogi_req() - Handler for Port Login (PLOGI) requests
  * @lport: The local port that received the PLOGI request
- * @sp:	   The sequence that the PLOGI request was on
  * @rx_fp: The PLOGI request frame
  *
  * Locking Note: The rport lock is held before calling this function.
  */
 static void fc_rport_recv_plogi_req(struct fc_lport *lport,
-				    struct fc_seq *sp, struct fc_frame *rx_fp)
+				    struct fc_frame *rx_fp)
 {
 	struct fc_disc *disc;
 	struct fc_rport_priv *rdata;
 	struct fc_frame *fp = rx_fp;
-	struct fc_exch *ep;
-	struct fc_frame_header *fh;
 	struct fc_els_flogi *pl;
 	struct fc_seq_els_data rjt_data;
-	u32 sid, f_ctl;
+	u32 sid;
 
-	rjt_data.fp = NULL;
-	fh = fc_frame_header_get(fp);
-	sid = ntoh24(fh->fh_s_id);
+	sid = fc_frame_sid(fp);
 
 	FC_RPORT_ID_DBG(lport, sid, "Received PLOGI request\n");
 
@@ -1358,6 +1563,9 @@
 	case RPORT_ST_INIT:
 		FC_RPORT_DBG(rdata, "Received PLOGI in INIT state\n");
 		break;
+	case RPORT_ST_PLOGI_WAIT:
+		FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI_WAIT state\n");
+		break;
 	case RPORT_ST_PLOGI:
 		FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state\n");
 		if (rdata->ids.port_name < lport->wwpn) {
@@ -1375,9 +1583,8 @@
 			     "- ignored for now\n", rdata->rp_state);
 		/* XXX TBD - should reset */
 		break;
+	case RPORT_ST_FLOGI:
 	case RPORT_ST_DELETE:
-	case RPORT_ST_LOGO:
-	case RPORT_ST_RESTART:
 		FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n",
 			     fc_rport_state(rdata));
 		mutex_unlock(&rdata->rp_mutex);
@@ -1390,50 +1597,41 @@
 	 * Get session payload size from incoming PLOGI.
 	 */
 	rdata->maxframe_size = fc_plogi_get_maxframe(pl, lport->mfs);
-	fc_frame_free(rx_fp);
 
 	/*
 	 * Send LS_ACC.	 If this fails, the originator should retry.
 	 */
-	sp = lport->tt.seq_start_next(sp);
-	if (!sp)
-		goto out;
 	fp = fc_frame_alloc(lport, sizeof(*pl));
 	if (!fp)
 		goto out;
 
 	fc_plogi_fill(lport, fp, ELS_LS_ACC);
-	f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT;
-	ep = fc_seq_exch(sp);
-	fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
-		       FC_TYPE_ELS, f_ctl, 0);
-	lport->tt.seq_send(lport, sp, fp);
+	fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+	lport->tt.frame_send(lport, fp);
 	fc_rport_enter_prli(rdata);
 out:
 	mutex_unlock(&rdata->rp_mutex);
+	fc_frame_free(rx_fp);
 	return;
 
 reject:
-	lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+	lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data);
 	fc_frame_free(fp);
 }
 
 /**
  * fc_rport_recv_prli_req() - Handler for process login (PRLI) requests
  * @rdata: The remote port that sent the PRLI request
- * @sp:	   The sequence that the PRLI was on
  * @rx_fp: The PRLI request frame
  *
  * Locking Note: The rport lock is exected to be held before calling
  * this function.
  */
 static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
-				   struct fc_seq *sp, struct fc_frame *rx_fp)
+				   struct fc_frame *rx_fp)
 {
 	struct fc_lport *lport = rdata->local_port;
-	struct fc_exch *ep;
 	struct fc_frame *fp;
-	struct fc_frame_header *fh;
 	struct {
 		struct fc_els_prli prli;
 		struct fc_els_spp spp;
@@ -1444,17 +1642,13 @@
 	unsigned int plen;
 	enum fc_els_spp_resp resp;
 	struct fc_seq_els_data rjt_data;
-	u32 f_ctl;
 	u32 fcp_parm;
 	u32 roles = FC_RPORT_ROLE_UNKNOWN;
 
-	rjt_data.fp = NULL;
-	fh = fc_frame_header_get(rx_fp);
-
 	FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
 		     fc_rport_state(rdata));
 
-	len = fr_len(rx_fp) - sizeof(*fh);
+	len = fr_len(rx_fp) - sizeof(struct fc_frame_header);
 	pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
 	if (!pp)
 		goto reject_len;
@@ -1475,8 +1669,6 @@
 		rjt_data.explan = ELS_EXPL_INSUF_RES;
 		goto reject;
 	}
-	sp = lport->tt.seq_start_next(sp);
-	WARN_ON(!sp);
 	pp = fc_frame_payload_get(fp, len);
 	WARN_ON(!pp);
 	memset(pp, 0, len);
@@ -1529,12 +1721,8 @@
 	/*
 	 * Send LS_ACC.	 If this fails, the originator should retry.
 	 */
-	f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
-	f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
-	ep = fc_seq_exch(sp);
-	fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
-		       FC_TYPE_ELS, f_ctl, 0);
-	lport->tt.seq_send(lport, sp, fp);
+	fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+	lport->tt.frame_send(lport, fp);
 
 	switch (rdata->rp_state) {
 	case RPORT_ST_PRLI:
@@ -1549,7 +1737,7 @@
 	rjt_data.reason = ELS_RJT_PROT;
 	rjt_data.explan = ELS_EXPL_INV_LEN;
 reject:
-	lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+	lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data);
 drop:
 	fc_frame_free(rx_fp);
 }
@@ -1557,54 +1745,90 @@
 /**
  * fc_rport_recv_prlo_req() - Handler for process logout (PRLO) requests
  * @rdata: The remote port that sent the PRLO request
- * @sp:	   The sequence that the PRLO was on
- * @fp:	   The PRLO request frame
+ * @rx_fp: The PRLO request frame
  *
  * Locking Note: The rport lock is exected to be held before calling
  * this function.
  */
 static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
-				   struct fc_seq *sp,
-				   struct fc_frame *fp)
+				   struct fc_frame *rx_fp)
 {
 	struct fc_lport *lport = rdata->local_port;
-
-	struct fc_frame_header *fh;
+	struct fc_frame *fp;
+	struct {
+		struct fc_els_prlo prlo;
+		struct fc_els_spp spp;
+	} *pp;
+	struct fc_els_spp *rspp;	/* request service param page */
+	struct fc_els_spp *spp;		/* response spp */
+	unsigned int len;
+	unsigned int plen;
 	struct fc_seq_els_data rjt_data;
 
-	fh = fc_frame_header_get(fp);
-
 	FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n",
 		     fc_rport_state(rdata));
 
-	rjt_data.fp = NULL;
-	rjt_data.reason = ELS_RJT_UNAB;
-	rjt_data.explan = ELS_EXPL_NONE;
-	lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
-	fc_frame_free(fp);
+	len = fr_len(rx_fp) - sizeof(struct fc_frame_header);
+	pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
+	if (!pp)
+		goto reject_len;
+	plen = ntohs(pp->prlo.prlo_len);
+	if (plen != 20)
+		goto reject_len;
+	if (plen < len)
+		len = plen;
+
+	rspp = &pp->spp;
+
+	fp = fc_frame_alloc(lport, len);
+	if (!fp) {
+		rjt_data.reason = ELS_RJT_UNAB;
+		rjt_data.explan = ELS_EXPL_INSUF_RES;
+		goto reject;
+	}
+
+	pp = fc_frame_payload_get(fp, len);
+	WARN_ON(!pp);
+	memset(pp, 0, len);
+	pp->prlo.prlo_cmd = ELS_LS_ACC;
+	pp->prlo.prlo_obs = 0x10;
+	pp->prlo.prlo_len = htons(len);
+	spp = &pp->spp;
+	spp->spp_type = rspp->spp_type;
+	spp->spp_type_ext = rspp->spp_type_ext;
+	spp->spp_flags = FC_SPP_RESP_ACK;
+
+	fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
+
+	fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+	lport->tt.frame_send(lport, fp);
+	goto drop;
+
+reject_len:
+	rjt_data.reason = ELS_RJT_PROT;
+	rjt_data.explan = ELS_EXPL_INV_LEN;
+reject:
+	lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data);
+drop:
+	fc_frame_free(rx_fp);
 }
 
 /**
  * fc_rport_recv_logo_req() - Handler for logout (LOGO) requests
  * @lport: The local port that received the LOGO request
- * @sp:	   The sequence that the LOGO request was on
  * @fp:	   The LOGO request frame
  *
  * Locking Note: The rport lock is exected to be held before calling
  * this function.
  */
-static void fc_rport_recv_logo_req(struct fc_lport *lport,
-				   struct fc_seq *sp,
-				   struct fc_frame *fp)
+static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp)
 {
-	struct fc_frame_header *fh;
 	struct fc_rport_priv *rdata;
 	u32 sid;
 
-	lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
+	lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL);
 
-	fh = fc_frame_header_get(fp);
-	sid = ntoh24(fh->fh_s_id);
+	sid = fc_frame_sid(fp);
 
 	mutex_lock(&lport->disc.disc_mutex);
 	rdata = lport->tt.rport_lookup(lport, sid);
@@ -1614,13 +1838,6 @@
 			     fc_rport_state(rdata));
 
 		fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
-
-		/*
-		 * If the remote port was created due to discovery, set state
-		 * to log back in.  It may have seen a stale RSCN about us.
-		 */
-		if (rdata->disc_id)
-			fc_rport_state_enter(rdata, RPORT_ST_RESTART);
 		mutex_unlock(&rdata->rp_mutex);
 	} else
 		FC_RPORT_ID_DBG(lport, sid,
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 8c496b5..042153c 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -71,7 +71,7 @@
 		case SAS_SG_ERR:
 			return AC_ERR_INVALID;
 
-		case SAM_CHECK_COND:
+		case SAM_STAT_CHECK_CONDITION:
 		case SAS_OPEN_TO:
 		case SAS_OPEN_REJECT:
 			SAS_DPRINTK("%s: Saw error %d.  What to do?\n",
@@ -107,7 +107,7 @@
 	sas_ha = dev->port->ha;
 
 	spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
-	if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_GOOD) {
+	if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD) {
 		ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf);
 		qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command);
 		dev->sata_dev.sstatus = resp->sstatus;
@@ -511,12 +511,12 @@
 					goto ex_err;
 			}
 		}
-		if (task->task_status.stat == SAM_BUSY ||
-			   task->task_status.stat == SAM_TASK_SET_FULL ||
+		if (task->task_status.stat == SAM_STAT_BUSY ||
+			   task->task_status.stat == SAM_STAT_TASK_SET_FULL ||
 			   task->task_status.stat == SAS_QUEUE_FULL) {
 			SAS_DPRINTK("task: q busy, sleeping...\n");
 			schedule_timeout_interruptible(HZ);
-		} else if (task->task_status.stat == SAM_CHECK_COND) {
+		} else if (task->task_status.stat == SAM_STAT_CHECK_CONDITION) {
 			struct scsi_sense_hdr shdr;
 
 			if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size,
@@ -549,7 +549,7 @@
 					    shdr.asc, shdr.ascq);
 			}
 		} else if (task->task_status.resp != SAS_TASK_COMPLETE ||
-			   task->task_status.stat != SAM_GOOD) {
+			   task->task_status.stat != SAM_STAT_GOOD) {
 			SAS_DPRINTK("task finished with resp:0x%x, "
 				    "stat:0x%x\n",
 				    task->task_status.resp,
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index c65af02..83dd507 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -107,7 +107,7 @@
 			}
 		}
 		if (task->task_status.resp == SAS_TASK_COMPLETE &&
-		    task->task_status.stat == SAM_GOOD) {
+		    task->task_status.stat == SAM_STAT_GOOD) {
 			res = 0;
 			break;
 		} if (task->task_status.resp == SAS_TASK_COMPLETE &&
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index a7890c6..f0cfba9 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -113,10 +113,10 @@
 		case SAS_ABORTED_TASK:
 			hs = DID_ABORT;
 			break;
-		case SAM_CHECK_COND:
+		case SAM_STAT_CHECK_CONDITION:
 			memcpy(sc->sense_buffer, ts->buf,
 			       min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
-			stat = SAM_CHECK_COND;
+			stat = SAM_STAT_CHECK_CONDITION;
 			break;
 		default:
 			stat = ts->stat;
diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c
index 594524d..b13a334 100644
--- a/drivers/scsi/libsas/sas_task.c
+++ b/drivers/scsi/libsas/sas_task.c
@@ -15,13 +15,13 @@
 	else if (iu->datapres == 1)
 		tstat->stat = iu->resp_data[3];
 	else if (iu->datapres == 2) {
-		tstat->stat = SAM_CHECK_COND;
+		tstat->stat = SAM_STAT_CHECK_CONDITION;
 		tstat->buf_valid_size =
 			min_t(int, SAS_STATUS_BUF_SIZE,
 			      be32_to_cpu(iu->sense_data_len));
 		memcpy(tstat->buf, iu->sense_data, tstat->buf_valid_size);
 
-		if (iu->status != SAM_CHECK_COND)
+		if (iu->status != SAM_STAT_CHECK_CONDITION)
 			dev_printk(KERN_WARNING, dev,
 				   "dev %llx sent sense data, but "
 				   "stat(%x) is not CHECK CONDITION\n",
@@ -30,7 +30,7 @@
 	}
 	else
 		/* when datapres contains corrupt/unknown value... */
-		tstat->stat = SAM_CHECK_COND;
+		tstat->stat = SAM_STAT_CHECK_CONDITION;
 }
 EXPORT_SYMBOL_GPL(sas_ssp_task_response);
 
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index e35a4c7..3482d5a 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -20,7 +20,6 @@
  *******************************************************************/
 
 #include <scsi/scsi_host.h>
-
 struct lpfc_sli2_slim;
 
 #define LPFC_PCI_DEV_LP		0x1
@@ -49,7 +48,7 @@
 #define LPFC_TGTQ_INTERVAL	40000	/* Min amount of time between tgt
 					   queue depth change in millisecs */
 #define LPFC_TGTQ_RAMPUP_PCENT	5	/* Target queue rampup in percentage */
-#define LPFC_MIN_TGT_QDEPTH	100
+#define LPFC_MIN_TGT_QDEPTH	10
 #define LPFC_MAX_TGT_QDEPTH	0xFFFF
 
 #define  LPFC_MAX_BUCKET_COUNT 20	/* Maximum no. of buckets for stat data
@@ -376,6 +375,7 @@
 #define WORKER_FABRIC_BLOCK_TMO        0x400	/* hba: fabric block timeout */
 #define WORKER_RAMP_DOWN_QUEUE         0x800	/* hba: Decrease Q depth */
 #define WORKER_RAMP_UP_QUEUE           0x1000	/* hba: Increase Q depth */
+#define WORKER_SERVICE_TXQ             0x2000	/* hba: IOCBs on the txq */
 
 	struct timer_list fc_fdmitmo;
 	struct timer_list els_tmofunc;
@@ -400,6 +400,7 @@
 	uint32_t cfg_max_luns;
 	uint32_t cfg_enable_da_id;
 	uint32_t cfg_max_scsicmpl_time;
+	uint32_t cfg_tgt_queue_depth;
 
 	uint32_t dev_loss_tmo_changed;
 
@@ -510,9 +511,9 @@
 	void (*lpfc_stop_port)
 		(struct lpfc_hba *);
 	int (*lpfc_hba_init_link)
-		(struct lpfc_hba *);
+		(struct lpfc_hba *, uint32_t);
 	int (*lpfc_hba_down_link)
-		(struct lpfc_hba *);
+		(struct lpfc_hba *, uint32_t);
 
 	/* SLI4 specific HBA data structure */
 	struct lpfc_sli4_hba sli4_hba;
@@ -525,7 +526,6 @@
 #define LPFC_SLI3_NPIV_ENABLED		0x02
 #define LPFC_SLI3_VPORT_TEARDOWN	0x04
 #define LPFC_SLI3_CRP_ENABLED		0x08
-#define LPFC_SLI3_INB_ENABLED		0x10
 #define LPFC_SLI3_BG_ENABLED		0x20
 #define LPFC_SLI3_DSS_ENABLED		0x40
 	uint32_t iocb_cmd_size;
@@ -557,9 +557,6 @@
 
 	MAILBOX_t *mbox;
 	uint32_t *mbox_ext;
-	uint32_t *inb_ha_copy;
-	uint32_t *inb_counter;
-	uint32_t inb_last_counter;
 	uint32_t ha_copy;
 	struct _PCB *pcb;
 	struct _IOCB *IOCBs;
@@ -628,6 +625,7 @@
 	uint32_t cfg_hostmem_hgp;
 	uint32_t cfg_log_verbose;
 	uint32_t cfg_aer_support;
+	uint32_t cfg_iocb_cnt;
 	uint32_t cfg_suppress_link_up;
 #define LPFC_INITIALIZE_LINK              0	/* do normal init_link mbox */
 #define LPFC_DELAY_INIT_LINK              1	/* layered driver hold off */
@@ -816,6 +814,9 @@
 
 	uint8_t menlo_flag;	/* menlo generic flags */
 #define HBA_MENLO_SUPPORT	0x1 /* HBA supports menlo commands */
+	uint32_t iocb_cnt;
+	uint32_t iocb_max;
+	atomic_t sdev_cnt;
 };
 
 static inline struct Scsi_Host *
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index bf33b31..868874c 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -506,10 +506,10 @@
 
 	if ((strncmp(buf, "up", sizeof("up") - 1) == 0) &&
 			(phba->link_state == LPFC_LINK_DOWN))
-		status = phba->lpfc_hba_init_link(phba);
+		status = phba->lpfc_hba_init_link(phba, MBX_NOWAIT);
 	else if ((strncmp(buf, "down", sizeof("down") - 1) == 0) &&
 			(phba->link_state >= LPFC_LINK_UP))
-		status = phba->lpfc_hba_down_link(phba);
+		status = phba->lpfc_hba_down_link(phba, MBX_NOWAIT);
 
 	if (status == 0)
 		return strlen(buf);
@@ -864,7 +864,6 @@
 		  uint32_t *mrpi, uint32_t *arpi,
 		  uint32_t *mvpi, uint32_t *avpi)
 {
-	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_mbx_read_config *rd_config;
 	LPFC_MBOXQ_t *pmboxq;
 	MAILBOX_t *pmb;
@@ -893,8 +892,7 @@
 	pmb->mbxOwner = OWN_HOST;
 	pmboxq->context1 = NULL;
 
-	if ((phba->pport->fc_flag & FC_OFFLINE_MODE) ||
-		(!(psli->sli_flag & LPFC_SLI_ACTIVE)))
+	if (phba->pport->fc_flag & FC_OFFLINE_MODE)
 		rc = MBX_NOT_FINISHED;
 	else
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -1949,6 +1947,59 @@
 LPFC_ATTR_R(suppress_link_up, LPFC_INITIALIZE_LINK, LPFC_INITIALIZE_LINK,
 		LPFC_DELAY_INIT_LINK_INDEFINITELY,
 		"Suppress Link Up at initialization");
+/*
+# lpfc_cnt: Number of IOCBs allocated for ELS, CT, and ABTS
+#       1 - (1024)
+#       2 - (2048)
+#       3 - (3072)
+#       4 - (4096)
+#       5 - (5120)
+*/
+static ssize_t
+lpfc_iocb_hw_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct Scsi_Host  *shost = class_to_shost(dev);
+	struct lpfc_hba   *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", phba->iocb_max);
+}
+
+static DEVICE_ATTR(iocb_hw, S_IRUGO,
+			 lpfc_iocb_hw_show, NULL);
+static ssize_t
+lpfc_txq_hw_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct Scsi_Host  *shost = class_to_shost(dev);
+	struct lpfc_hba   *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+		phba->sli.ring[LPFC_ELS_RING].txq_max);
+}
+
+static DEVICE_ATTR(txq_hw, S_IRUGO,
+			 lpfc_txq_hw_show, NULL);
+static ssize_t
+lpfc_txcmplq_hw_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+	struct Scsi_Host  *shost = class_to_shost(dev);
+	struct lpfc_hba   *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+		phba->sli.ring[LPFC_ELS_RING].txcmplq_max);
+}
+
+static DEVICE_ATTR(txcmplq_hw, S_IRUGO,
+			 lpfc_txcmplq_hw_show, NULL);
+
+int lpfc_iocb_cnt = 2;
+module_param(lpfc_iocb_cnt, int, 1);
+MODULE_PARM_DESC(lpfc_iocb_cnt,
+	"Number of IOCBs alloc for ELS, CT, and ABTS: 1k to 5k IOCBs");
+lpfc_param_show(iocb_cnt);
+lpfc_param_init(iocb_cnt, 2, 1, 5);
+static DEVICE_ATTR(lpfc_iocb_cnt, S_IRUGO,
+			 lpfc_iocb_cnt_show, NULL);
 
 /*
 # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
@@ -2157,6 +2208,13 @@
 		  "Max number of FCP commands we can queue to a specific LUN");
 
 /*
+# tgt_queue_depth:  This parameter is used to limit the number of outstanding
+# commands per target port. Value range is [10,65535]. Default value is 65535.
+*/
+LPFC_VPORT_ATTR_R(tgt_queue_depth, 65535, 10, 65535,
+	"Max number of FCP commands we can queue to a specific target port");
+
+/*
 # hba_queue_depth:  This parameter is used to limit the number of outstanding
 # commands per lpfc HBA. Value range is [32,8192]. If this parameter
 # value is greater than the maximum number of exchanges supported by the HBA,
@@ -2890,9 +2948,6 @@
 	struct lpfc_hba *phba = vport->phba;
 	int val = 0, rc = -EINVAL;
 
-	/* AER not supported on OC devices yet */
-	if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
-		return -EPERM;
 	if (!isdigit(buf[0]))
 		return -EINVAL;
 	if (sscanf(buf, "%i", &val) != 1)
@@ -2965,12 +3020,6 @@
 static int
 lpfc_aer_support_init(struct lpfc_hba *phba, int val)
 {
-	/* AER not supported on OC devices yet */
-	if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
-		phba->cfg_aer_support = 0;
-		return -EPERM;
-	}
-
 	if (val == 0 || val == 1) {
 		phba->cfg_aer_support = val;
 		return 0;
@@ -3015,9 +3064,6 @@
 	struct lpfc_hba   *phba = vport->phba;
 	int val, rc = -1;
 
-	/* AER not supported on OC devices yet */
-	if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
-		return -EPERM;
 	if (!isdigit(buf[0]))
 		return -EINVAL;
 	if (sscanf(buf, "%i", &val) != 1)
@@ -3083,7 +3129,7 @@
 			continue;
 		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
 			continue;
-		ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
+		ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
 	}
 	spin_unlock_irq(shost->host_lock);
 	return 0;
@@ -3287,6 +3333,7 @@
 	&dev_attr_lpfc_temp_sensor,
 	&dev_attr_lpfc_log_verbose,
 	&dev_attr_lpfc_lun_queue_depth,
+	&dev_attr_lpfc_tgt_queue_depth,
 	&dev_attr_lpfc_hba_queue_depth,
 	&dev_attr_lpfc_peer_port_login,
 	&dev_attr_lpfc_nodev_tmo,
@@ -3334,6 +3381,10 @@
 	&dev_attr_lpfc_aer_support,
 	&dev_attr_lpfc_aer_state_cleanup,
 	&dev_attr_lpfc_suppress_link_up,
+	&dev_attr_lpfc_iocb_cnt,
+	&dev_attr_iocb_hw,
+	&dev_attr_txq_hw,
+	&dev_attr_txcmplq_hw,
 	NULL,
 };
 
@@ -3344,6 +3395,7 @@
 	&dev_attr_lpfc_drvr_version,
 	&dev_attr_lpfc_log_verbose,
 	&dev_attr_lpfc_lun_queue_depth,
+	&dev_attr_lpfc_tgt_queue_depth,
 	&dev_attr_lpfc_nodev_tmo,
 	&dev_attr_lpfc_devloss_tmo,
 	&dev_attr_lpfc_hba_queue_depth,
@@ -4042,8 +4094,7 @@
 	pmboxq->context1 = NULL;
 	pmboxq->vport = vport;
 
-	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-		(!(psli->sli_flag & LPFC_SLI_ACTIVE)))
+	if (vport->fc_flag & FC_OFFLINE_MODE)
 		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
 	else
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -4067,8 +4118,7 @@
 	pmboxq->context1 = NULL;
 	pmboxq->vport = vport;
 
-	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-	    (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
+	if (vport->fc_flag & FC_OFFLINE_MODE)
 		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
 	else
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -4521,6 +4571,7 @@
 	lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
 	lpfc_aer_support_init(phba, lpfc_aer_support);
 	lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
+	lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt);
 	return;
 }
 
@@ -4533,6 +4584,7 @@
 {
 	lpfc_log_verbose_init(vport, lpfc_log_verbose);
 	lpfc_lun_queue_depth_init(vport, lpfc_lun_queue_depth);
+	lpfc_tgt_queue_depth_init(vport, lpfc_tgt_queue_depth);
 	lpfc_devloss_tmo_init(vport, lpfc_devloss_tmo);
 	lpfc_nodev_tmo_init(vport, lpfc_nodev_tmo);
 	lpfc_peer_port_login_init(vport, lpfc_peer_port_login);
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index dcf0882..d521569 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -377,6 +377,11 @@
 
 	if (rc == IOCB_SUCCESS)
 		return 0; /* done for now */
+	else if (rc == IOCB_BUSY)
+		rc = EAGAIN;
+	else
+		rc = EIO;
+
 
 	/* iocb failed so cleanup */
 	pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
@@ -625,6 +630,10 @@
 	lpfc_nlp_put(ndlp);
 	if (rc == IOCB_SUCCESS)
 		return 0; /* done for now */
+	else if (rc == IOCB_BUSY)
+		rc = EAGAIN;
+	else
+		rc = EIO;
 
 	pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
 		     job->request_payload.sg_cnt, DMA_TO_DEVICE);
@@ -953,10 +962,22 @@
 		if (phba->sli_rev == LPFC_SLI_REV4) {
 			evt_dat->immed_dat = phba->ctx_idx;
 			phba->ctx_idx = (phba->ctx_idx + 1) % 64;
+			/* Provide warning for over-run of the ct_ctx array */
+			if (phba->ct_ctx[evt_dat->immed_dat].flags &
+			    UNSOL_VALID)
+				lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
+						"2717 CT context array entry "
+						"[%d] over-run: oxid:x%x, "
+						"sid:x%x\n", phba->ctx_idx,
+						phba->ct_ctx[
+						    evt_dat->immed_dat].oxid,
+						phba->ct_ctx[
+						    evt_dat->immed_dat].SID);
 			phba->ct_ctx[evt_dat->immed_dat].oxid =
 						piocbq->iocb.ulpContext;
 			phba->ct_ctx[evt_dat->immed_dat].SID =
 				piocbq->iocb.un.rcvels.remoteID;
+			phba->ct_ctx[evt_dat->immed_dat].flags = UNSOL_VALID;
 		} else
 			evt_dat->immed_dat = piocbq->iocb.ulpContext;
 
@@ -1314,6 +1335,21 @@
 			rc = IOCB_ERROR;
 			goto issue_ct_rsp_exit;
 		}
+
+		/* Check if the ndlp is active */
+		if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
+			rc = -IOCB_ERROR;
+			goto issue_ct_rsp_exit;
+		}
+
+		/* get a refernece count so the ndlp doesn't go away while
+		 * we respond
+		 */
+		if (!lpfc_nlp_get(ndlp)) {
+			rc = -IOCB_ERROR;
+			goto issue_ct_rsp_exit;
+		}
+
 		icmd->un.ulpWord[3] = ndlp->nlp_rpi;
 		/* The exchange is done, mark the entry as invalid */
 		phba->ct_ctx[tag].flags &= ~UNSOL_VALID;
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index fbc9bae..03f4ddc 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -41,6 +41,7 @@
 void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
 int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
 		 LPFC_MBOXQ_t *, uint32_t);
+void lpfc_set_var(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
 void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
 void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
 void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *);
@@ -190,6 +191,7 @@
 irqreturn_t lpfc_sli4_fp_intr_handler(int, void *);
 
 void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_sli4_swap_str(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
 void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -402,3 +404,12 @@
 int lpfc_bsg_timeout(struct fc_bsg_job *);
 int lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
 			     struct lpfc_iocbq *);
+void __lpfc_sli_ringtx_put(struct lpfc_hba *, struct lpfc_sli_ring *,
+	struct lpfc_iocbq *);
+struct lpfc_iocbq *lpfc_sli_ringtx_get(struct lpfc_hba *,
+	struct lpfc_sli_ring *);
+int __lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
+	struct lpfc_iocbq *, uint32_t);
+uint32_t lpfc_drain_txq(struct lpfc_hba *);
+
+
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 36257a6..7cae69d 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -114,6 +114,8 @@
 };
 
 /* Defines for nlp_flag (uint32) */
+#define NLP_IGNR_REG_CMPL  0x00000001 /* Rcvd rscn before we cmpl reg login */
+#define NLP_REG_LOGIN_SEND 0x00000002   /* sent reglogin to adapter */
 #define NLP_PLOGI_SND      0x00000020	/* sent PLOGI request for this entry */
 #define NLP_PRLI_SND       0x00000040	/* sent PRLI request for this entry */
 #define NLP_ADISC_SND      0x00000080	/* sent ADISC request for this entry */
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index c4c7f0a..afbed6b 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -796,7 +796,9 @@
 		 * due to new FCF discovery
 		 */
 		if ((phba->hba_flag & HBA_FIP_SUPPORT) &&
-		    (phba->fcf.fcf_flag & FCF_DISCOVERY)) {
+		    (phba->fcf.fcf_flag & FCF_DISCOVERY) &&
+		    (irsp->ulpStatus != IOSTAT_LOCAL_REJECT) &&
+		    (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED)) {
 			lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS,
 					"2611 FLOGI failed on registered "
 					"FCF record fcf_index:%d, trying "
@@ -811,18 +813,21 @@
 				 */
 				lpfc_printf_log(phba, KERN_WARNING,
 						LOG_FIP | LOG_ELS,
-						"2760 FLOGI exhausted FCF "
-						"round robin failover list, "
-						"retry FLOGI on the current "
-						"registered FCF index:%d\n",
+						"2760 Completed one round "
+						"of FLOGI FCF round robin "
+						"failover list, retry FLOGI "
+						"on currently registered "
+						"FCF index:%d\n",
 						phba->fcf.current_rec.fcf_indx);
-				spin_lock_irq(&phba->hbalock);
-				phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
-				spin_unlock_irq(&phba->hbalock);
 			} else {
+				lpfc_printf_log(phba, KERN_INFO,
+						LOG_FIP | LOG_ELS,
+						"2794 FLOGI FCF round robin "
+						"failover to FCF index x%x\n",
+						fcf_index);
 				rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba,
 								   fcf_index);
-				if (rc) {
+				if (rc)
 					lpfc_printf_log(phba, KERN_WARNING,
 							LOG_FIP | LOG_ELS,
 							"2761 FLOGI round "
@@ -831,10 +836,7 @@
 							"rc:x%x, fcf_index:"
 							"%d\n", rc,
 						phba->fcf.current_rec.fcf_indx);
-					spin_lock_irq(&phba->hbalock);
-					phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
-					spin_unlock_irq(&phba->hbalock);
-				} else
+				else
 					goto out;
 			}
 		}
@@ -890,9 +892,39 @@
 		 */
 		if (sp->cmn.fPort)
 			rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
-		else
+		else if (!(phba->hba_flag & HBA_FCOE_SUPPORT))
 			rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
-
+		else {
+			lpfc_printf_vlog(vport, KERN_ERR,
+				LOG_FIP | LOG_ELS,
+				"2831 FLOGI response with cleared Fabric "
+				"bit fcf_index 0x%x "
+				"Switch Name %02x%02x%02x%02x%02x%02x%02x%02x "
+				"Fabric Name "
+				"%02x%02x%02x%02x%02x%02x%02x%02x\n",
+				phba->fcf.current_rec.fcf_indx,
+				phba->fcf.current_rec.switch_name[0],
+				phba->fcf.current_rec.switch_name[1],
+				phba->fcf.current_rec.switch_name[2],
+				phba->fcf.current_rec.switch_name[3],
+				phba->fcf.current_rec.switch_name[4],
+				phba->fcf.current_rec.switch_name[5],
+				phba->fcf.current_rec.switch_name[6],
+				phba->fcf.current_rec.switch_name[7],
+				phba->fcf.current_rec.fabric_name[0],
+				phba->fcf.current_rec.fabric_name[1],
+				phba->fcf.current_rec.fabric_name[2],
+				phba->fcf.current_rec.fabric_name[3],
+				phba->fcf.current_rec.fabric_name[4],
+				phba->fcf.current_rec.fabric_name[5],
+				phba->fcf.current_rec.fabric_name[6],
+				phba->fcf.current_rec.fabric_name[7]);
+			lpfc_nlp_put(ndlp);
+			spin_lock_irq(&phba->hbalock);
+			phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+			spin_unlock_irq(&phba->hbalock);
+			goto out;
+		}
 		if (!rc) {
 			/* Mark the FCF discovery process done */
 			if (phba->hba_flag & HBA_FIP_SUPPORT)
@@ -1472,8 +1504,12 @@
 			}
 			goto out;
 		}
-		/* PLOGI failed */
-		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+		/* PLOGI failed Don't print the vport to vport rjts */
+		if (irsp->ulpStatus != IOSTAT_LS_RJT ||
+			(((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) &&
+			((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) ||
+			(phba)->pport->cfg_log_verbose & LOG_ELS)
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
 				 "2753 PLOGI failure DID:%06X Status:x%x/x%x\n",
 				 ndlp->nlp_DID, irsp->ulpStatus,
 				 irsp->un.ulpWord[4]);
@@ -2740,6 +2776,15 @@
 				retry = 1;
 				break;
 			}
+			if (stat.un.b.lsRjtRsnCodeExp ==
+			    LSEXP_CANT_GIVE_DATA) {
+				if (cmd == ELS_CMD_PLOGI) {
+					delay = 1000;
+					maxretry = 48;
+				}
+				retry = 1;
+				break;
+			}
 			if (cmd == ELS_CMD_PLOGI) {
 				delay = 1000;
 				maxretry = lpfc_max_els_tries + 1;
@@ -5135,6 +5180,7 @@
 	return;
 }
 
+
 /**
  * lpfc_els_timeout_handler - Process an els timeout event
  * @vport: pointer to a virtual N_Port data structure.
@@ -5155,13 +5201,19 @@
 	uint32_t els_command = 0;
 	uint32_t timeout;
 	uint32_t remote_ID = 0xffffffff;
+	LIST_HEAD(txcmplq_completions);
+	LIST_HEAD(abort_list);
 
-	spin_lock_irq(&phba->hbalock);
+
 	timeout = (uint32_t)(phba->fc_ratov << 1);
 
 	pring = &phba->sli.ring[LPFC_ELS_RING];
 
-	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
+	spin_lock_irq(&phba->hbalock);
+	list_splice_init(&pring->txcmplq, &txcmplq_completions);
+	spin_unlock_irq(&phba->hbalock);
+
+	list_for_each_entry_safe(piocb, tmp_iocb, &txcmplq_completions, list) {
 		cmd = &piocb->iocb;
 
 		if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
@@ -5198,14 +5250,23 @@
 			if (ndlp && NLP_CHK_NODE_ACT(ndlp))
 				remote_ID = ndlp->nlp_DID;
 		}
-		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-				 "0127 ELS timeout Data: x%x x%x x%x "
-				 "x%x\n", els_command,
-				 remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
-		lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+		list_add_tail(&piocb->dlist, &abort_list);
 	}
+	spin_lock_irq(&phba->hbalock);
+	list_splice(&txcmplq_completions, &pring->txcmplq);
 	spin_unlock_irq(&phba->hbalock);
 
+	list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+			 "0127 ELS timeout Data: x%x x%x x%x "
+			 "x%x\n", els_command,
+			 remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
+		spin_lock_irq(&phba->hbalock);
+		list_del_init(&piocb->dlist);
+		lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+		spin_unlock_irq(&phba->hbalock);
+	}
+
 	if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
 		mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
 }
@@ -6901,6 +6962,7 @@
 	uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
 	struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
 	unsigned long iflag = 0;
+	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
 
 	spin_lock_irqsave(&phba->hbalock, iflag);
 	spin_lock(&phba->sli4_hba.abts_sgl_list_lock);
@@ -6913,6 +6975,10 @@
 			sglq_entry->state = SGL_FREED;
 			spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
 			spin_unlock_irqrestore(&phba->hbalock, iflag);
+
+			/* Check if TXQ queue needs to be serviced */
+			if (pring->txq_cnt)
+				lpfc_worker_wake_up(phba);
 			return;
 		}
 	}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 1f87b4f..0639c99 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -275,7 +275,9 @@
 	if (!(vport->load_flag & FC_UNLOADING) &&
 	    !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
 	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
-	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
+	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
+	    (ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) &&
+	    (ndlp->nlp_state != NLP_STE_PRLI_ISSUE))
 		lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
 
 	lpfc_unregister_unused_fcf(phba);
@@ -586,6 +588,8 @@
 							(status &
 							 HA_RXMASK));
 		}
+		if (pring->txq_cnt)
+			lpfc_drain_txq(phba);
 		/*
 		 * Turn on Ring interrupts
 		 */
@@ -1297,7 +1301,7 @@
  * used for this FCF when the function returns.
  * If the FCF record need to be used with a particular vlan id, the vlan is
  * set in the vlan_id on return of the function. If not VLAN tagging need to
- * be used with the FCF vlan_id will be set to 0xFFFF;
+ * be used with the FCF vlan_id will be set to LPFC_FCOE_NULL_VID;
  **/
 static int
 lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
@@ -1333,7 +1337,7 @@
 		if (phba->valid_vlan)
 			*vlan_id = phba->vlan_id;
 		else
-			*vlan_id = 0xFFFF;
+			*vlan_id = LPFC_FCOE_NULL_VID;
 		return 1;
 	}
 
@@ -1357,7 +1361,7 @@
 		if (fcf_vlan_id)
 			*vlan_id = fcf_vlan_id;
 		else
-			*vlan_id = 0xFFFF;
+			*vlan_id = LPFC_FCOE_NULL_VID;
 		return 1;
 	}
 
@@ -1466,7 +1470,7 @@
 		else if (fcf_vlan_id)
 			*vlan_id = fcf_vlan_id;
 		else
-			*vlan_id = 0xFFFF;
+			*vlan_id = LPFC_FCOE_NULL_VID;
 
 		return 1;
 	}
@@ -1518,6 +1522,9 @@
 		 * Do not continue FCF discovery and clear FCF_DISC_INPROGRESS
 		 * flag
 		 */
+		lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
+				"2833 Stop FCF discovery process due to link "
+				"state change (x%x)\n", phba->link_state);
 		spin_lock_irq(&phba->hbalock);
 		phba->hba_flag &= ~FCF_DISC_INPROGRESS;
 		phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | FCF_DISCOVERY);
@@ -1565,7 +1572,7 @@
 }
 
 /**
- * lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox.
+ * lpfc_sli4_fcf_rec_mbox_parse - Parse read_fcf mbox command.
  * @phba: pointer to lpfc hba data structure.
  * @mboxq: pointer to mailbox object.
  * @next_fcf_index: pointer to holder of next fcf index.
@@ -1693,6 +1700,37 @@
 }
 
 /**
+ lpfc_sli4_fcf_record_match - testing new FCF record for matching existing FCF
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_rec: pointer to an existing FCF record.
+ * @new_fcf_record: pointer to a new FCF record.
+ * @new_vlan_id: vlan id from the new FCF record.
+ *
+ * This function performs matching test of a new FCF record against an existing
+ * FCF record. If the new_vlan_id passed in is LPFC_FCOE_IGNORE_VID, vlan id
+ * will not be used as part of the FCF record matching criteria.
+ *
+ * Returns true if all the fields matching, otherwise returns false.
+ */
+static bool
+lpfc_sli4_fcf_record_match(struct lpfc_hba *phba,
+			   struct lpfc_fcf_rec *fcf_rec,
+			   struct fcf_record *new_fcf_record,
+			   uint16_t new_vlan_id)
+{
+	if (new_vlan_id != LPFC_FCOE_IGNORE_VID)
+		if (!lpfc_vlan_id_match(fcf_rec->vlan_id, new_vlan_id))
+			return false;
+	if (!lpfc_mac_addr_match(fcf_rec->mac_addr, new_fcf_record))
+		return false;
+	if (!lpfc_sw_name_match(fcf_rec->switch_name, new_fcf_record))
+		return false;
+	if (!lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record))
+		return false;
+	return true;
+}
+
+/**
  * lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler.
  * @phba: pointer to lpfc hba data structure.
  * @mboxq: pointer to mailbox object.
@@ -1755,7 +1793,7 @@
 	 */
 	if (!rc) {
 		lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
-				"2781 FCF record fcf_index:x%x failed FCF "
+				"2781 FCF record (x%x) failed FCF "
 				"connection list check, fcf_avail:x%x, "
 				"fcf_valid:x%x\n",
 				bf_get(lpfc_fcf_record_fcf_index,
@@ -1764,6 +1802,32 @@
 				       new_fcf_record),
 				bf_get(lpfc_fcf_record_fcf_valid,
 				       new_fcf_record));
+		if ((phba->fcf.fcf_flag & FCF_IN_USE) &&
+		    lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
+		    new_fcf_record, LPFC_FCOE_IGNORE_VID)) {
+			/*
+			 * In case the current in-use FCF record becomes
+			 * invalid/unavailable during FCF discovery that
+			 * was not triggered by fast FCF failover process,
+			 * treat it as fast FCF failover.
+			 */
+			if (!(phba->fcf.fcf_flag & FCF_REDISC_PEND) &&
+			    !(phba->fcf.fcf_flag & FCF_REDISC_FOV)) {
+				lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+						"2835 Invalid in-use FCF "
+						"record (x%x) reported, "
+						"entering fast FCF failover "
+						"mode scanning.\n",
+						phba->fcf.current_rec.fcf_indx);
+				spin_lock_irq(&phba->hbalock);
+				phba->fcf.fcf_flag |= FCF_REDISC_FOV;
+				spin_unlock_irq(&phba->hbalock);
+				lpfc_sli4_mbox_cmd_free(phba, mboxq);
+				lpfc_sli4_fcf_scan_read_fcf_rec(phba,
+						LPFC_FCOE_FCF_GET_FIRST);
+				return;
+			}
+		}
 		goto read_next_fcf;
 	} else {
 		fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
@@ -1780,14 +1844,8 @@
 	 */
 	spin_lock_irq(&phba->hbalock);
 	if (phba->fcf.fcf_flag & FCF_IN_USE) {
-		if (lpfc_fab_name_match(phba->fcf.current_rec.fabric_name,
-					new_fcf_record) &&
-		    lpfc_sw_name_match(phba->fcf.current_rec.switch_name,
-					new_fcf_record) &&
-		    lpfc_mac_addr_match(phba->fcf.current_rec.mac_addr,
-					new_fcf_record) &&
-		    lpfc_vlan_id_match(phba->fcf.current_rec.vlan_id,
-					vlan_id)) {
+		if (lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
+		    new_fcf_record, vlan_id)) {
 			phba->fcf.fcf_flag |= FCF_AVAILABLE;
 			if (phba->fcf.fcf_flag & FCF_REDISC_PEND)
 				/* Stop FCF redisc wait timer if pending */
@@ -1797,6 +1855,13 @@
 				phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV |
 							FCF_DISCOVERY);
 			spin_unlock_irq(&phba->hbalock);
+			lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+					"2836 The new FCF record (x%x) "
+					"matches the in-use FCF record "
+					"(x%x)\n",
+					phba->fcf.current_rec.fcf_indx,
+					bf_get(lpfc_fcf_record_fcf_index,
+					       new_fcf_record));
 			goto out;
 		}
 		/*
@@ -1828,6 +1893,12 @@
 		 */
 		if (boot_flag && !(fcf_rec->flag & BOOT_ENABLE)) {
 			/* Choose this FCF record */
+			lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+					"2837 Update current FCF record "
+					"(x%x) with new FCF record (x%x)\n",
+					fcf_rec->fcf_indx,
+					bf_get(lpfc_fcf_record_fcf_index,
+					new_fcf_record));
 			__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
 					addr_mode, vlan_id, BOOT_ENABLE);
 			spin_unlock_irq(&phba->hbalock);
@@ -1848,6 +1919,12 @@
 		 */
 		if (new_fcf_record->fip_priority < fcf_rec->priority) {
 			/* Choose the new FCF record with lower priority */
+			lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+					"2838 Update current FCF record "
+					"(x%x) with new FCF record (x%x)\n",
+					fcf_rec->fcf_indx,
+					bf_get(lpfc_fcf_record_fcf_index,
+					       new_fcf_record));
 			__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
 					addr_mode, vlan_id, 0);
 			/* Reset running random FCF selection count */
@@ -1857,11 +1934,18 @@
 			phba->fcf.eligible_fcf_cnt++;
 			select_new_fcf = lpfc_sli4_new_fcf_random_select(phba,
 						phba->fcf.eligible_fcf_cnt);
-			if (select_new_fcf)
+			if (select_new_fcf) {
+				lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+					"2839 Update current FCF record "
+					"(x%x) with new FCF record (x%x)\n",
+					fcf_rec->fcf_indx,
+					bf_get(lpfc_fcf_record_fcf_index,
+					       new_fcf_record));
 				/* Choose the new FCF by random selection */
 				__lpfc_update_fcf_record(phba, fcf_rec,
 							 new_fcf_record,
 							 addr_mode, vlan_id, 0);
+			}
 		}
 		spin_unlock_irq(&phba->hbalock);
 		goto read_next_fcf;
@@ -1871,6 +1955,11 @@
 	 * initial best-fit FCF.
 	 */
 	if (fcf_rec) {
+		lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+				"2840 Update current FCF record "
+				"with initial FCF record (x%x)\n",
+				bf_get(lpfc_fcf_record_fcf_index,
+				       new_fcf_record));
 		__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
 					 addr_mode, vlan_id, (boot_flag ?
 					 BOOT_ENABLE : 0));
@@ -1928,12 +2017,23 @@
 			lpfc_unregister_fcf(phba);
 
 			/* Replace in-use record with the new record */
+			lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+					"2842 Replace the current in-use "
+					"FCF record (x%x) with failover FCF "
+					"record (x%x)\n",
+					phba->fcf.current_rec.fcf_indx,
+					phba->fcf.failover_rec.fcf_indx);
 			memcpy(&phba->fcf.current_rec,
 			       &phba->fcf.failover_rec,
 			       sizeof(struct lpfc_fcf_rec));
-			/* mark the FCF fast failover completed */
+			/*
+			 * Mark the fast FCF failover rediscovery completed
+			 * and the start of the first round of the roundrobin
+			 * FCF failover.
+			 */
 			spin_lock_irq(&phba->hbalock);
-			phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
+			phba->fcf.fcf_flag &=
+					~(FCF_REDISC_FOV | FCF_REDISC_RRU);
 			spin_unlock_irq(&phba->hbalock);
 			/*
 			 * Set up the initial registered FCF index for FLOGI
@@ -1951,15 +2051,42 @@
 			if ((phba->fcf.fcf_flag & FCF_REDISC_EVT) ||
 			    (phba->fcf.fcf_flag & FCF_REDISC_PEND))
 				return;
+
+			if (phba->fcf.fcf_flag & FCF_IN_USE) {
+				/*
+				 * In case the current in-use FCF record no
+				 * longer existed during FCF discovery that
+				 * was not triggered by fast FCF failover
+				 * process, treat it as fast FCF failover.
+				 */
+				lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+						"2841 In-use FCF record (x%x) "
+						"not reported, entering fast "
+						"FCF failover mode scanning.\n",
+						phba->fcf.current_rec.fcf_indx);
+				spin_lock_irq(&phba->hbalock);
+				phba->fcf.fcf_flag |= FCF_REDISC_FOV;
+				spin_unlock_irq(&phba->hbalock);
+				lpfc_sli4_mbox_cmd_free(phba, mboxq);
+				lpfc_sli4_fcf_scan_read_fcf_rec(phba,
+						LPFC_FCOE_FCF_GET_FIRST);
+				return;
+			}
+
 			/*
 			 * Otherwise, initial scan or post linkdown rescan,
 			 * register with the best FCF record found so far
 			 * through the FCF scanning process.
 			 */
 
-			/* mark the initial FCF discovery completed */
+			/*
+			 * Mark the initial FCF discovery completed and
+			 * the start of the first round of the roundrobin
+			 * FCF failover.
+			 */
 			spin_lock_irq(&phba->hbalock);
-			phba->fcf.fcf_flag &= ~FCF_INIT_DISC;
+			phba->fcf.fcf_flag &=
+					~(FCF_INIT_DISC | FCF_REDISC_RRU);
 			spin_unlock_irq(&phba->hbalock);
 			/*
 			 * Set up the initial registered FCF index for FLOGI
@@ -2033,6 +2160,11 @@
 				      next_fcf_index);
 
 	/* Upload new FCF record to the failover FCF record */
+	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+			"2834 Update the current FCF record (x%x) "
+			"with the next FCF record (x%x)\n",
+			phba->fcf.failover_rec.fcf_indx,
+			bf_get(lpfc_fcf_record_fcf_index, new_fcf_record));
 	spin_lock_irq(&phba->hbalock);
 	__lpfc_update_fcf_record(phba, &phba->fcf.failover_rec,
 				 new_fcf_record, addr_mode, vlan_id,
@@ -2050,7 +2182,7 @@
 
 	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
 			"2783 FLOGI round robin FCF failover from FCF "
-			"(index:x%x) to FCF (index:x%x).\n",
+			"(x%x) to FCF (x%x).\n",
 			current_fcf_index,
 			bf_get(lpfc_fcf_record_fcf_index, new_fcf_record));
 
@@ -2084,7 +2216,7 @@
 		goto out;
 
 	/* If FCF discovery period is over, no need to proceed */
-	if (phba->fcf.fcf_flag & FCF_DISCOVERY)
+	if (!(phba->fcf.fcf_flag & FCF_DISCOVERY))
 		goto out;
 
 	/* Parse the FCF record from the non-embedded mailbox command */
@@ -2715,11 +2847,35 @@
 	struct lpfc_vport  *vport = pmb->vport;
 	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 
 	pmb->context1 = NULL;
 
-	/* Good status, call state machine */
-	lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
+	if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
+		ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
+
+	if (ndlp->nlp_flag &  NLP_IGNR_REG_CMPL ||
+		ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) {
+		/* We rcvd a rscn after issuing this
+		 * mbox reg login, we may have cycled
+		 * back through the state and be
+		 * back at reg login state so this
+		 * mbox needs to be ignored becase
+		 * there is another reg login in
+		 * proccess.
+		 */
+		spin_lock_irq(shost->host_lock);
+		ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
+		spin_unlock_irq(shost->host_lock);
+		if (phba->sli_rev == LPFC_SLI_REV4)
+			lpfc_sli4_free_rpi(phba,
+				pmb->u.mb.un.varRegLogin.rpi);
+
+	} else
+		/* Good status, call state machine */
+		lpfc_disc_state_machine(vport, ndlp, pmb,
+				NLP_EVT_CMPL_REG_LOGIN);
+
 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
 	kfree(mp);
 	mempool_free(pmb, phba->mbox_mem_pool);
@@ -3427,7 +3583,7 @@
 	kref_init(&ndlp->kref);
 	NLP_INT_NODE_ACT(ndlp);
 	atomic_set(&ndlp->cmd_pending, 0);
-	ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
+	ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
 }
 
 struct lpfc_nodelist *
@@ -3700,6 +3856,7 @@
 				mempool_free(mbox, phba->mbox_mem_pool);
 		}
 		lpfc_no_rpi(phba, ndlp);
+
 		ndlp->nlp_rpi = 0;
 		ndlp->nlp_flag &= ~NLP_RPI_VALID;
 		ndlp->nlp_flag &= ~NLP_NPR_ADISC;
@@ -3842,6 +3999,9 @@
 				kfree(mp);
 			}
 			list_del(&mb->list);
+			if (phba->sli_rev == LPFC_SLI_REV4)
+				lpfc_sli4_free_rpi(phba,
+					 mb->u.mb.un.varRegLogin.rpi);
 			mempool_free(mb, phba->mbox_mem_pool);
 			/* We shall not invoke the lpfc_nlp_put to decrement
 			 * the ndlp reference count as we are in the process
@@ -3883,6 +4043,7 @@
 
 	lpfc_cancel_retry_delay_tmo(vport, ndlp);
 	if ((ndlp->nlp_flag & NLP_DEFER_RM) &&
+		!(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) &&
 	    !(ndlp->nlp_flag & NLP_RPI_VALID)) {
 		/* For this case we need to cleanup the default rpi
 		 * allocated by the firmware.
@@ -5180,13 +5341,16 @@
 lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
 {
 	/*
-	 * If HBA is not running in FIP mode or if HBA does not support
-	 * FCoE or if FCF is not registered, do nothing.
+	 * If HBA is not running in FIP mode, if HBA does not support
+	 * FCoE, if FCF discovery is ongoing, or if FCF has not been
+	 * registered, do nothing.
 	 */
 	spin_lock_irq(&phba->hbalock);
 	if (!(phba->hba_flag & HBA_FCOE_SUPPORT) ||
 	    !(phba->fcf.fcf_flag & FCF_REGISTERED) ||
-	    !(phba->hba_flag & HBA_FIP_SUPPORT)) {
+	    !(phba->hba_flag & HBA_FIP_SUPPORT) ||
+	    (phba->fcf.fcf_flag & FCF_DISCOVERY) ||
+	    (phba->pport->port_state == LPFC_FLOGI)) {
 		spin_unlock_irq(&phba->hbalock);
 		return;
 	}
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index e654d01..f5dbf2b 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1170,6 +1170,7 @@
 #define PCI_DEVICE_ID_TIGERSHARK    0x0704
 #define PCI_DEVICE_ID_TOMCAT        0x0714
 #define PCI_DEVICE_ID_FALCON        0xf180
+#define PCI_DEVICE_ID_BALIUS        0xe131
 
 #define JEDEC_ID_ADDRESS            0x0080001c
 #define FIREFLY_JEDEC_ID            0x1ACC
@@ -3014,18 +3015,10 @@
 	uint32_t hbq_get[16];
 };
 
-struct sli3_inb_pgp {
-	uint32_t ha_copy;
-	uint32_t counter;
-	struct lpfc_pgp port[MAX_RINGS];
-	uint32_t hbq_get[16];
-};
-
 union sli_var {
 	struct sli2_desc	s2;
 	struct sli3_desc	s3;
 	struct sli3_pgp		s3_pgp;
-	struct sli3_inb_pgp	s3_inb_pgp;
 };
 
 typedef struct {
@@ -3132,6 +3125,14 @@
 #define IOERR_BUFFER_SHORTAGE         0x28
 #define IOERR_DEFAULT                 0x29
 #define IOERR_CNT                     0x2A
+#define IOERR_SLER_FAILURE            0x46
+#define IOERR_SLER_CMD_RCV_FAILURE    0x47
+#define IOERR_SLER_REC_RJT_ERR        0x48
+#define IOERR_SLER_REC_SRR_RETRY_ERR  0x49
+#define IOERR_SLER_SRR_RJT_ERR        0x4A
+#define IOERR_SLER_RRQ_RJT_ERR        0x4C
+#define IOERR_SLER_RRQ_RETRY_ERR      0x4D
+#define IOERR_SLER_ABTS_ERR           0x4E
 
 #define IOERR_DRVR_MASK               0x100
 #define IOERR_SLI_DOWN                0x101  /* ulpStatus  - Driver defined */
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index cd9697e..2786ee3 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -621,6 +621,7 @@
 /**
  * lpfc_hba_init_link - Initialize the FC link
  * @phba: pointer to lpfc hba data structure.
+ * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT
  *
  * This routine will issue the INIT_LINK mailbox command call.
  * It is available to other drivers through the lpfc_hba data
@@ -632,7 +633,7 @@
  *		Any other value - error
  **/
 int
-lpfc_hba_init_link(struct lpfc_hba *phba)
+lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag)
 {
 	struct lpfc_vport *vport = phba->pport;
 	LPFC_MBOXQ_t *pmb;
@@ -651,7 +652,7 @@
 		phba->cfg_link_speed);
 	pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 	lpfc_set_loopback_flag(phba);
-	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+	rc = lpfc_sli_issue_mbox(phba, pmb, flag);
 	if (rc != MBX_SUCCESS) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 			"0498 Adapter failed to init, mbxCmd x%x "
@@ -664,17 +665,21 @@
 		writel(0xffffffff, phba->HAregaddr);
 		readl(phba->HAregaddr); /* flush */
 		phba->link_state = LPFC_HBA_ERROR;
-		if (rc != MBX_BUSY)
+		if (rc != MBX_BUSY || flag == MBX_POLL)
 			mempool_free(pmb, phba->mbox_mem_pool);
 		return -EIO;
 	}
 	phba->cfg_suppress_link_up = LPFC_INITIALIZE_LINK;
+	if (flag == MBX_POLL)
+		mempool_free(pmb, phba->mbox_mem_pool);
 
 	return 0;
 }
 
 /**
  * lpfc_hba_down_link - this routine downs the FC link
+ * @phba: pointer to lpfc hba data structure.
+ * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT
  *
  * This routine will issue the DOWN_LINK mailbox command call.
  * It is available to other drivers through the lpfc_hba data
@@ -685,7 +690,7 @@
  *		Any other value - error
  **/
 int
-lpfc_hba_down_link(struct lpfc_hba *phba)
+lpfc_hba_down_link(struct lpfc_hba *phba, uint32_t flag)
 {
 	LPFC_MBOXQ_t *pmb;
 	int rc;
@@ -701,7 +706,7 @@
 		"0491 Adapter Link is disabled.\n");
 	lpfc_down_link(phba, pmb);
 	pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+	rc = lpfc_sli_issue_mbox(phba, pmb, flag);
 	if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
 		lpfc_printf_log(phba,
 		KERN_ERR, LOG_INIT,
@@ -711,6 +716,9 @@
 		mempool_free(pmb, phba->mbox_mem_pool);
 		return -EIO;
 	}
+	if (flag == MBX_POLL)
+		mempool_free(pmb, phba->mbox_mem_pool);
+
 	return 0;
 }
 
@@ -1818,6 +1826,10 @@
 		m = (typeof(m)){"LPSe12002-ML1-E", "PCIe",
 				"EmulexSecure Fibre"};
 		break;
+	case PCI_DEVICE_ID_BALIUS:
+		m = (typeof(m)){"LPVe12002", "PCIe Shared I/O",
+				"Fibre Channel Adapter"};
+		break;
 	default:
 		m = (typeof(m)){"Unknown", "", ""};
 		break;
@@ -2279,10 +2291,32 @@
 lpfc_block_mgmt_io(struct lpfc_hba * phba)
 {
 	unsigned long iflag;
+	uint8_t actcmd = MBX_HEARTBEAT;
+	unsigned long timeout;
+
 
 	spin_lock_irqsave(&phba->hbalock, iflag);
 	phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
+	if (phba->sli.mbox_active)
+		actcmd = phba->sli.mbox_active->u.mb.mbxCommand;
 	spin_unlock_irqrestore(&phba->hbalock, iflag);
+	/* Determine how long we might wait for the active mailbox
+	 * command to be gracefully completed by firmware.
+	 */
+	timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, actcmd) * 1000) +
+			jiffies;
+	/* Wait for the outstnading mailbox command to complete */
+	while (phba->sli.mbox_active) {
+		/* Check active mailbox complete status every 2ms */
+		msleep(2);
+		if (time_after(jiffies, timeout)) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"2813 Mgmt IO is Blocked %x "
+				"- mbox cmd %x still active\n",
+				phba->sli.sli_flag, actcmd);
+			break;
+		}
+	}
 }
 
 /**
@@ -3323,22 +3357,14 @@
 					"evt_tag:x%x, fcf_index:x%x\n",
 					acqe_fcoe->event_tag,
 					acqe_fcoe->index);
+		/* If the FCF discovery is in progress, do nothing. */
 		spin_lock_irq(&phba->hbalock);
-		if ((phba->fcf.fcf_flag & FCF_SCAN_DONE) ||
-		    (phba->hba_flag & FCF_DISC_INPROGRESS)) {
-			/*
-			 * If the current FCF is in discovered state or
-			 * FCF discovery is in progress, do nothing.
-			 */
+		if (phba->hba_flag & FCF_DISC_INPROGRESS) {
 			spin_unlock_irq(&phba->hbalock);
 			break;
 		}
-
+		/* If fast FCF failover rescan event is pending, do nothing */
 		if (phba->fcf.fcf_flag & FCF_REDISC_EVT) {
-			/*
-			 * If fast FCF failover rescan event is pending,
-			 * do nothing.
-			 */
 			spin_unlock_irq(&phba->hbalock);
 			break;
 		}
@@ -3359,7 +3385,13 @@
 					acqe_fcoe->index);
 			rc = lpfc_sli4_read_fcf_rec(phba, acqe_fcoe->index);
 		}
-
+		/* If the FCF has been in discovered state, do nothing. */
+		spin_lock_irq(&phba->hbalock);
+		if (phba->fcf.fcf_flag & FCF_SCAN_DONE) {
+			spin_unlock_irq(&phba->hbalock);
+			break;
+		}
+		spin_unlock_irq(&phba->hbalock);
 		/* Otherwise, scan the entire FCF table and re-discover SAN */
 		lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
 				"2770 Start FCF table scan due to new FCF "
@@ -4885,6 +4917,7 @@
 	phba->fc_altov = FF_DEF_ALTOV;
 	phba->fc_arbtov = FF_DEF_ARBTOV;
 
+	atomic_set(&phba->sdev_cnt, 0);
 	vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
 	if (!vport)
 		return -ENODEV;
@@ -5533,9 +5566,12 @@
 	mempool_free(pmb, phba->mbox_mem_pool);
 
 	/* Reset the DFT_HBA_Q_DEPTH to the max xri  */
-	if (phba->cfg_hba_queue_depth > (phba->sli4_hba.max_cfg_param.max_xri))
+	if (phba->cfg_hba_queue_depth >
+		(phba->sli4_hba.max_cfg_param.max_xri -
+			lpfc_sli4_get_els_iocb_cnt(phba)))
 		phba->cfg_hba_queue_depth =
-				phba->sli4_hba.max_cfg_param.max_xri;
+			phba->sli4_hba.max_cfg_param.max_xri -
+				lpfc_sli4_get_els_iocb_cnt(phba);
 	return rc;
 }
 
@@ -6993,22 +7029,28 @@
 static int
 lpfc_sli4_enable_msix(struct lpfc_hba *phba)
 {
-	int rc, index;
+	int vectors, rc, index;
 
 	/* Set up MSI-X multi-message vectors */
 	for (index = 0; index < phba->sli4_hba.cfg_eqn; index++)
 		phba->sli4_hba.msix_entries[index].entry = index;
 
 	/* Configure MSI-X capability structure */
+	vectors = phba->sli4_hba.cfg_eqn;
+enable_msix_vectors:
 	rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries,
-			     phba->sli4_hba.cfg_eqn);
-	if (rc) {
+			     vectors);
+	if (rc > 1) {
+		vectors = rc;
+		goto enable_msix_vectors;
+	} else if (rc) {
 		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
 				"0484 PCI enable MSI-X failed (%d)\n", rc);
 		goto msi_fail_out;
 	}
+
 	/* Log MSI-X vector assignment */
-	for (index = 0; index < phba->sli4_hba.cfg_eqn; index++)
+	for (index = 0; index < vectors; index++)
 		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
 				"0489 MSI-X entry[%d]: vector=x%x "
 				"message=%d\n", index,
@@ -7030,7 +7072,7 @@
 	}
 
 	/* The rest of the vector(s) are associated to fast-path handler(s) */
-	for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) {
+	for (index = 1; index < vectors; index++) {
 		phba->sli4_hba.fcp_eq_hdl[index - 1].idx = index - 1;
 		phba->sli4_hba.fcp_eq_hdl[index - 1].phba = phba;
 		rc = request_irq(phba->sli4_hba.msix_entries[index].vector,
@@ -7044,6 +7086,7 @@
 			goto cfg_fail_out;
 		}
 	}
+	phba->sli4_hba.msix_vec_nr = vectors;
 
 	return rc;
 
@@ -7077,9 +7120,10 @@
 	/* Free up MSI-X multi-message vectors */
 	free_irq(phba->sli4_hba.msix_entries[0].vector, phba);
 
-	for (index = 1; index < phba->sli4_hba.cfg_eqn; index++)
+	for (index = 1; index < phba->sli4_hba.msix_vec_nr; index++)
 		free_irq(phba->sli4_hba.msix_entries[index].vector,
 			 &phba->sli4_hba.fcp_eq_hdl[index - 1]);
+
 	/* Disable MSI-X */
 	pci_disable_msix(phba->pcidev);
 
@@ -7121,6 +7165,7 @@
 		pci_disable_msi(phba->pcidev);
 		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
 				"0490 MSI request_irq failed (%d)\n", rc);
+		return rc;
 	}
 
 	for (index = 0; index < phba->cfg_fcp_eq_count; index++) {
@@ -7128,7 +7173,7 @@
 		phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
 	}
 
-	return rc;
+	return 0;
 }
 
 /**
@@ -7839,6 +7884,9 @@
 	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 			"2710 PCI channel disable preparing for reset\n");
 
+	/* Block any management I/Os to the device */
+	lpfc_block_mgmt_io(phba);
+
 	/* Block all SCSI devices' I/Os on the host */
 	lpfc_scsi_dev_block(phba);
 
@@ -7848,6 +7896,7 @@
 	/* Disable interrupt and pci device */
 	lpfc_sli_disable_intr(phba);
 	pci_disable_device(phba->pcidev);
+
 	/* Flush all driver's outstanding SCSI I/Os as we are to reset */
 	lpfc_sli_flush_fcp_rings(phba);
 }
@@ -7861,7 +7910,7 @@
  * pending I/Os.
  **/
 static void
-lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba)
+lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba)
 {
 	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 			"2711 PCI channel permanent disable for failure\n");
@@ -7910,7 +7959,7 @@
 		return PCI_ERS_RESULT_NEED_RESET;
 	case pci_channel_io_perm_failure:
 		/* Permanent failure, prepare for device down */
-		lpfc_prep_dev_for_perm_failure(phba);
+		lpfc_sli_prep_dev_for_perm_failure(phba);
 		return PCI_ERS_RESULT_DISCONNECT;
 	default:
 		/* Unknown state, prepare and request slot reset */
@@ -7979,7 +8028,8 @@
 	} else
 		phba->intr_mode = intr_mode;
 
-	/* Take device offline; this will perform cleanup */
+	/* Take device offline, it will perform cleanup */
+	lpfc_offline_prep(phba);
 	lpfc_offline(phba);
 	lpfc_sli_brdrestart(phba);
 
@@ -8110,8 +8160,12 @@
 	}
 
 	/* Initialize and populate the iocb list per host */
-	error = lpfc_init_iocb_list(phba,
-			phba->sli4_hba.max_cfg_param.max_xri);
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"2821 initialize iocb list %d.\n",
+			phba->cfg_iocb_cnt*1024);
+	error = lpfc_init_iocb_list(phba, phba->cfg_iocb_cnt*1024);
+
 	if (error) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"1413 Failed to initialize iocb list.\n");
@@ -8160,6 +8214,8 @@
 		/* Default to single FCP EQ for non-MSI-X */
 		if (phba->intr_type != MSIX)
 			phba->cfg_fcp_eq_count = 1;
+		else if (phba->sli4_hba.msix_vec_nr < phba->cfg_fcp_eq_count)
+			phba->cfg_fcp_eq_count = phba->sli4_hba.msix_vec_nr - 1;
 		/* Set up SLI-4 HBA */
 		if (lpfc_sli4_hba_setup(phba)) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -8321,7 +8377,7 @@
 	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
 
 	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-			"0298 PCI device Power Management suspend.\n");
+			"2843 PCI device Power Management suspend.\n");
 
 	/* Bring down the device */
 	lpfc_offline_prep(phba);
@@ -8412,6 +8468,84 @@
 }
 
 /**
+ * lpfc_sli4_prep_dev_for_recover - Prepare SLI4 device for pci slot recover
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI4 device for PCI slot recover. It
+ * aborts all the outstanding SCSI I/Os to the pci device.
+ **/
+static void
+lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba)
+{
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_sli_ring  *pring;
+
+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"2828 PCI channel I/O abort preparing for recovery\n");
+	/*
+	 * There may be errored I/Os through HBA, abort all I/Os on txcmplq
+	 * and let the SCSI mid-layer to retry them to recover.
+	 */
+	pring = &psli->ring[psli->fcp_ring];
+	lpfc_sli_abort_iocb_ring(phba, pring);
+}
+
+/**
+ * lpfc_sli4_prep_dev_for_reset - Prepare SLI4 device for pci slot reset
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI4 device for PCI slot reset. It
+ * disables the device interrupt and pci device, and aborts the internal FCP
+ * pending I/Os.
+ **/
+static void
+lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba)
+{
+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"2826 PCI channel disable preparing for reset\n");
+
+	/* Block any management I/Os to the device */
+	lpfc_block_mgmt_io(phba);
+
+	/* Block all SCSI devices' I/Os on the host */
+	lpfc_scsi_dev_block(phba);
+
+	/* stop all timers */
+	lpfc_stop_hba_timers(phba);
+
+	/* Disable interrupt and pci device */
+	lpfc_sli4_disable_intr(phba);
+	pci_disable_device(phba->pcidev);
+
+	/* Flush all driver's outstanding SCSI I/Os as we are to reset */
+	lpfc_sli_flush_fcp_rings(phba);
+}
+
+/**
+ * lpfc_sli4_prep_dev_for_perm_failure - Prepare SLI4 dev for pci slot disable
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI4 device for PCI slot permanently
+ * disabling. It blocks the SCSI transport layer traffic and flushes the FCP
+ * pending I/Os.
+ **/
+static void
+lpfc_sli4_prep_dev_for_perm_failure(struct lpfc_hba *phba)
+{
+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"2827 PCI channel permanent disable for failure\n");
+
+	/* Block all SCSI devices' I/Os on the host */
+	lpfc_scsi_dev_block(phba);
+
+	/* stop all timers */
+	lpfc_stop_hba_timers(phba);
+
+	/* Clean up all driver's outstanding SCSI I/Os */
+	lpfc_sli_flush_fcp_rings(phba);
+}
+
+/**
  * lpfc_io_error_detected_s4 - Method for handling PCI I/O error to SLI-4 device
  * @pdev: pointer to PCI device.
  * @state: the current PCI connection state.
@@ -8430,7 +8564,29 @@
 static pci_ers_result_t
 lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state)
 {
-	return PCI_ERS_RESULT_NEED_RESET;
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+	switch (state) {
+	case pci_channel_io_normal:
+		/* Non-fatal error, prepare for recovery */
+		lpfc_sli4_prep_dev_for_recover(phba);
+		return PCI_ERS_RESULT_CAN_RECOVER;
+	case pci_channel_io_frozen:
+		/* Fatal error, prepare for slot reset */
+		lpfc_sli4_prep_dev_for_reset(phba);
+		return PCI_ERS_RESULT_NEED_RESET;
+	case pci_channel_io_perm_failure:
+		/* Permanent failure, prepare for device down */
+		lpfc_sli4_prep_dev_for_perm_failure(phba);
+		return PCI_ERS_RESULT_DISCONNECT;
+	default:
+		/* Unknown state, prepare and request slot reset */
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2825 Unknown PCI error state: x%x\n", state);
+		lpfc_sli4_prep_dev_for_reset(phba);
+		return PCI_ERS_RESULT_NEED_RESET;
+	}
 }
 
 /**
@@ -8454,6 +8610,39 @@
 static pci_ers_result_t
 lpfc_io_slot_reset_s4(struct pci_dev *pdev)
 {
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+	struct lpfc_sli *psli = &phba->sli;
+	uint32_t intr_mode;
+
+	dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
+	if (pci_enable_device_mem(pdev)) {
+		printk(KERN_ERR "lpfc: Cannot re-enable "
+			"PCI device after reset.\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+
+	pci_restore_state(pdev);
+	if (pdev->is_busmaster)
+		pci_set_master(pdev);
+
+	spin_lock_irq(&phba->hbalock);
+	psli->sli_flag &= ~LPFC_SLI_ACTIVE;
+	spin_unlock_irq(&phba->hbalock);
+
+	/* Configure and enable interrupt */
+	intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode);
+	if (intr_mode == LPFC_INTR_ERROR) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"2824 Cannot re-enable interrupt after "
+				"slot reset.\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	} else
+		phba->intr_mode = intr_mode;
+
+	/* Log the current active interrupt mode */
+	lpfc_log_intr_mode(phba, phba->intr_mode);
+
 	return PCI_ERS_RESULT_RECOVERED;
 }
 
@@ -8470,7 +8659,27 @@
 static void
 lpfc_io_resume_s4(struct pci_dev *pdev)
 {
-	return;
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+	/*
+	 * In case of slot reset, as function reset is performed through
+	 * mailbox command which needs DMA to be enabled, this operation
+	 * has to be moved to the io resume phase. Taking device offline
+	 * will perform the necessary cleanup.
+	 */
+	if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) {
+		/* Perform device reset */
+		lpfc_offline_prep(phba);
+		lpfc_offline(phba);
+		lpfc_sli_brdrestart(phba);
+		/* Bring the device back online */
+		lpfc_online(phba);
+	}
+
+	/* Clean up Advanced Error Reporting (AER) if needed */
+	if (phba->hba_flag & HBA_AER_ENABLED)
+		pci_cleanup_aer_uncorrect_error_status(pdev);
 }
 
 /**
@@ -8802,6 +9011,8 @@
 		PCI_ANY_ID, PCI_ANY_ID, },
 	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON,
 		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS,
+		PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0 }
 };
 
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index e84dc33..9c2c7c7 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -955,6 +955,26 @@
 	return;
 }
 
+void
+lpfc_sli4_swap_str(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+	MAILBOX_t *mb = &pmb->u.mb;
+	struct lpfc_mqe *mqe;
+
+	switch (mb->mbxCommand) {
+	case  MBX_READ_REV:
+		 mqe = &pmb->u.mqe;
+		lpfc_sli_pcimem_bcopy(mqe->un.read_rev.fw_name,
+				 mqe->un.read_rev.fw_name, 16);
+		lpfc_sli_pcimem_bcopy(mqe->un.read_rev.ulp_fw_name,
+				 mqe->un.read_rev.ulp_fw_name, 16);
+		break;
+	default:
+		break;
+	}
+	return;
+}
+
 /**
  * lpfc_build_hbq_profile2 - Set up the HBQ Selection Profile 2
  * @hbqmb: pointer to the HBQ configuration data structure in mailbox command.
@@ -1199,7 +1219,6 @@
 		mb->un.varCfgPort.cdss = 1; /* Configure Security */
 		mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
 		mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */
-		mb->un.varCfgPort.cinb = 1; /* Interrupt Notification Block */
 		mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count();
 		if (phba->max_vpi && phba->cfg_enable_npiv &&
 		    phba->vpd.sli3Feat.cmv) {
@@ -2026,7 +2045,7 @@
 	       phba->fcf.current_rec.fcf_indx);
 	/* reg_fcf addr mode is bit wise inverted value of fcf addr_mode */
 	bf_set(lpfc_reg_fcfi_mam, reg_fcfi, (~phba->fcf.addr_mode) & 0x3);
-	if (phba->fcf.current_rec.vlan_id != 0xFFFF) {
+	if (phba->fcf.current_rec.vlan_id != LPFC_FCOE_NULL_VID) {
 		bf_set(lpfc_reg_fcfi_vv, reg_fcfi, 1);
 		bf_set(lpfc_reg_fcfi_vlan_tag, reg_fcfi,
 		       phba->fcf.current_rec.vlan_id);
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index b90820a..bccc9c6 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -190,6 +190,7 @@
 }
 
 
+
 /*
  * Free resources / clean up outstanding I/Os
  * associated with a LPFC_NODELIST entry. This
@@ -199,13 +200,15 @@
 lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 {
 	LIST_HEAD(completions);
+	LIST_HEAD(txcmplq_completions);
+	LIST_HEAD(abort_list);
 	struct lpfc_sli  *psli = &phba->sli;
 	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
 	struct lpfc_iocbq *iocb, *next_iocb;
 
 	/* Abort outstanding I/O on NPort <nlp_DID> */
 	lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_DISCOVERY,
-			 "0205 Abort outstanding I/O on NPort x%x "
+			 "2819 Abort outstanding I/O on NPort x%x "
 			 "Data: x%x x%x x%x\n",
 			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
 			 ndlp->nlp_rpi);
@@ -224,14 +227,25 @@
 	}
 
 	/* Next check the txcmplq */
-	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
-		/* Check to see if iocb matches the nport we are looking for */
-		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
-			lpfc_sli_issue_abort_iotag(phba, pring, iocb);
-		}
-	}
+	list_splice_init(&pring->txcmplq, &txcmplq_completions);
 	spin_unlock_irq(&phba->hbalock);
 
+	list_for_each_entry_safe(iocb, next_iocb, &txcmplq_completions, list) {
+		/* Check to see if iocb matches the nport we are looking for */
+		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
+			list_add_tail(&iocb->dlist, &abort_list);
+	}
+	spin_lock_irq(&phba->hbalock);
+	list_splice(&txcmplq_completions, &pring->txcmplq);
+	spin_unlock_irq(&phba->hbalock);
+
+	list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) {
+			spin_lock_irq(&phba->hbalock);
+			list_del_init(&iocb->dlist);
+			lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+			spin_unlock_irq(&phba->hbalock);
+	}
+
 	/* Cancel all the IOCBs from the completions list */
 	lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
 			      IOERR_SLI_ABORTED);
@@ -626,7 +640,8 @@
 	if (!(vport->fc_flag & FC_PT2PT)) {
 		/* Check config parameter use-adisc or FCP-2 */
 		if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
-		    ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
+		    ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) &&
+		     (ndlp->nlp_type & NLP_FCP_TARGET))) {
 			spin_lock_irq(shost->host_lock);
 			ndlp->nlp_flag |= NLP_NPR_ADISC;
 			spin_unlock_irq(shost->host_lock);
@@ -962,6 +977,7 @@
 			mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login;
 			break;
 		default:
+			ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
 			mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
 		}
 		mbox->context2 = lpfc_nlp_get(ndlp);
@@ -972,6 +988,8 @@
 					   NLP_STE_REG_LOGIN_ISSUE);
 			return ndlp->nlp_state;
 		}
+		if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
+			ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
 		/* decrement node reference count to the failed mbox
 		 * command
 		 */
@@ -1458,6 +1476,7 @@
 	ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 	spin_lock_irq(shost->host_lock);
+	ndlp->nlp_flag |= NLP_IGNR_REG_CMPL;
 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
 	spin_unlock_irq(shost->host_lock);
 	lpfc_disc_set_adisc(vport, ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index f4a3b2e..c818a72 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -623,6 +623,7 @@
 	unsigned long iflag = 0;
 	struct lpfc_iocbq *iocbq;
 	int i;
+	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
 
 	spin_lock_irqsave(&phba->hbalock, iflag);
 	spin_lock(&phba->sli4_hba.abts_scsi_buf_list_lock);
@@ -651,6 +652,8 @@
 		psb = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq);
 		psb->exch_busy = 0;
 		spin_unlock_irqrestore(&phba->hbalock, iflag);
+		if (pring->txq_cnt)
+			lpfc_worker_wake_up(phba);
 		return;
 
 	}
@@ -747,7 +750,6 @@
 	int status = 0, index;
 	int bcnt;
 	int non_sequential_xri = 0;
-	int rc = 0;
 	LIST_HEAD(sblist);
 
 	for (bcnt = 0; bcnt < num_to_alloc; bcnt++) {
@@ -774,6 +776,8 @@
 		/* Allocate iotag for psb->cur_iocbq. */
 		iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq);
 		if (iotag == 0) {
+			pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
+				psb->data, psb->dma_handle);
 			kfree(psb);
 			break;
 		}
@@ -858,7 +862,6 @@
 			if (status) {
 				/* Put this back on the abort scsi list */
 				psb->exch_busy = 1;
-				rc++;
 			} else {
 				psb->exch_busy = 0;
 				psb->status = IOSTAT_SUCCESS;
@@ -877,7 +880,6 @@
 			if (status) {
 				/* Put this back on the abort scsi list */
 				psb->exch_busy = 1;
-				rc++;
 			} else {
 				psb->exch_busy = 0;
 				psb->status = IOSTAT_SUCCESS;
@@ -887,7 +889,7 @@
 		}
 	}
 
-	return bcnt + non_sequential_xri - rc;
+	return bcnt + non_sequential_xri;
 }
 
 /**
@@ -1323,6 +1325,10 @@
 	bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
 	pde5->reftag = reftag;
 
+	/* Endian convertion if necessary for PDE5 */
+	pde5->word0 = cpu_to_le32(pde5->word0);
+	pde5->reftag = cpu_to_le32(pde5->reftag);
+
 	/* advance bpl and increment bde count */
 	num_bde++;
 	bpl++;
@@ -1341,6 +1347,11 @@
 	bf_set(pde6_ai, pde6, 1);
 	bf_set(pde6_apptagval, pde6, apptagval);
 
+	/* Endian convertion if necessary for PDE6 */
+	pde6->word0 = cpu_to_le32(pde6->word0);
+	pde6->word1 = cpu_to_le32(pde6->word1);
+	pde6->word2 = cpu_to_le32(pde6->word2);
+
 	/* advance bpl and increment bde count */
 	num_bde++;
 	bpl++;
@@ -1448,6 +1459,10 @@
 		bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
 		pde5->reftag = reftag;
 
+		/* Endian convertion if necessary for PDE5 */
+		pde5->word0 = cpu_to_le32(pde5->word0);
+		pde5->reftag = cpu_to_le32(pde5->reftag);
+
 		/* advance bpl and increment bde count */
 		num_bde++;
 		bpl++;
@@ -1464,6 +1479,11 @@
 		bf_set(pde6_ai, pde6, 1);
 		bf_set(pde6_apptagval, pde6, apptagval);
 
+		/* Endian convertion if necessary for PDE6 */
+		pde6->word0 = cpu_to_le32(pde6->word0);
+		pde6->word1 = cpu_to_le32(pde6->word1);
+		pde6->word2 = cpu_to_le32(pde6->word2);
+
 		/* advance bpl and increment bde count */
 		num_bde++;
 		bpl++;
@@ -1475,7 +1495,6 @@
 		prot_bde->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));
 		protgroup_len = sg_dma_len(sgpe);
 
-
 		/* must be integer multiple of the DIF block length */
 		BUG_ON(protgroup_len % 8);
 
@@ -2293,15 +2312,21 @@
 	struct lpfc_vport      *vport = pIocbIn->vport;
 	struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
 	struct lpfc_nodelist *pnode = rdata->pnode;
-	struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
+	struct scsi_cmnd *cmd;
 	int result;
 	struct scsi_device *tmp_sdev;
 	int depth;
 	unsigned long flags;
 	struct lpfc_fast_path_event *fast_path_evt;
-	struct Scsi_Host *shost = cmd->device->host;
+	struct Scsi_Host *shost;
 	uint32_t queue_depth, scsi_id;
 
+	/* Sanity check on return of outstanding command */
+	if (!(lpfc_cmd->pCmd))
+		return;
+	cmd = lpfc_cmd->pCmd;
+	shost = cmd->device->host;
+
 	lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
 	lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
 	/* pick up SLI4 exhange busy status from HBA */
@@ -2363,7 +2388,8 @@
 		case IOSTAT_LOCAL_REJECT:
 			if (lpfc_cmd->result == IOERR_INVALID_RPI ||
 			    lpfc_cmd->result == IOERR_NO_RESOURCES ||
-			    lpfc_cmd->result == IOERR_ABORT_REQUESTED) {
+			    lpfc_cmd->result == IOERR_ABORT_REQUESTED ||
+			    lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) {
 				cmd->result = ScsiResult(DID_REQUEUE, 0);
 				break;
 			}
@@ -2432,14 +2458,16 @@
 		}
 		spin_unlock_irqrestore(shost->host_lock, flags);
 	} else if (pnode && NLP_CHK_NODE_ACT(pnode)) {
-		if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) &&
+		if ((pnode->cmd_qdepth < vport->cfg_tgt_queue_depth) &&
 		   time_after(jiffies, pnode->last_change_time +
 			      msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) {
 			spin_lock_irqsave(shost->host_lock, flags);
-			pnode->cmd_qdepth += pnode->cmd_qdepth *
-				LPFC_TGTQ_RAMPUP_PCENT / 100;
-			if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH)
-				pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
+			depth = pnode->cmd_qdepth * LPFC_TGTQ_RAMPUP_PCENT
+				/ 100;
+			depth = depth ? depth : 1;
+			pnode->cmd_qdepth += depth;
+			if (pnode->cmd_qdepth > vport->cfg_tgt_queue_depth)
+				pnode->cmd_qdepth = vport->cfg_tgt_queue_depth;
 			pnode->last_change_time = jiffies;
 			spin_unlock_irqrestore(shost->host_lock, flags);
 		}
@@ -2894,8 +2922,7 @@
 		cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0);
 		goto out_fail_command;
 	}
-	if (vport->cfg_max_scsicmpl_time &&
-		(atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth))
+	if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
 		goto out_host_busy;
 
 	lpfc_cmd = lpfc_get_scsi_buf(phba);
@@ -3041,7 +3068,9 @@
 	int ret = SUCCESS;
 	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
 
-	fc_block_scsi_eh(cmnd);
+	ret = fc_block_scsi_eh(cmnd);
+	if (ret)
+		return ret;
 	lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
 	BUG_ON(!lpfc_cmd);
 
@@ -3225,7 +3254,9 @@
 			 lpfc_taskmgmt_name(task_mgmt_cmd),
 			 tgt_id, lun_id, iocbqrsp->iocb.ulpStatus,
 			 iocbqrsp->iocb.un.ulpWord[4]);
-	} else
+	} else if (status == IOCB_BUSY)
+		ret = FAILED;
+	else
 		ret = SUCCESS;
 
 	lpfc_sli_release_iocbq(phba, iocbqrsp);
@@ -3357,7 +3388,9 @@
 		return FAILED;
 	}
 	pnode = rdata->pnode;
-	fc_block_scsi_eh(cmnd);
+	status = fc_block_scsi_eh(cmnd);
+	if (status)
+		return status;
 
 	status = lpfc_chk_tgt_mapped(vport, cmnd);
 	if (status == FAILED) {
@@ -3422,7 +3455,9 @@
 		return FAILED;
 	}
 	pnode = rdata->pnode;
-	fc_block_scsi_eh(cmnd);
+	status = fc_block_scsi_eh(cmnd);
+	if (status)
+		return status;
 
 	status = lpfc_chk_tgt_mapped(vport, cmnd);
 	if (status == FAILED) {
@@ -3488,7 +3523,9 @@
 	fc_host_post_vendor_event(shost, fc_get_event_number(),
 		sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID);
 
-	fc_block_scsi_eh(cmnd);
+	ret = fc_block_scsi_eh(cmnd);
+	if (ret)
+		return ret;
 
 	/*
 	 * Since the driver manages a single bus device, reset all
@@ -3561,11 +3598,13 @@
 	uint32_t total = 0;
 	uint32_t num_to_alloc = 0;
 	int num_allocated = 0;
+	uint32_t sdev_cnt;
 
 	if (!rport || fc_remote_port_chkready(rport))
 		return -ENXIO;
 
 	sdev->hostdata = rport->dd_data;
+	sdev_cnt = atomic_inc_return(&phba->sdev_cnt);
 
 	/*
 	 * Populate the cmds_per_lun count scsi_bufs into this host's globally
@@ -3577,6 +3616,10 @@
 	total = phba->total_scsi_bufs;
 	num_to_alloc = vport->cfg_lun_queue_depth + 2;
 
+	/* If allocated buffers are enough do nothing */
+	if ((sdev_cnt * (vport->cfg_lun_queue_depth + 2)) < total)
+		return 0;
+
 	/* Allow some exchanges to be available always to complete discovery */
 	if (total >= phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
 		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
@@ -3658,6 +3701,9 @@
 static void
 lpfc_slave_destroy(struct scsi_device *sdev)
 {
+	struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
+	struct lpfc_hba   *phba = vport->phba;
+	atomic_dec(&phba->sdev_cnt);
 	sdev->hostdata = NULL;
 	return;
 }
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 7a61455..e758eae 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -455,6 +455,11 @@
 	struct lpfc_iocbq * iocbq = NULL;
 
 	list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list);
+
+	if (iocbq)
+		phba->iocb_cnt++;
+	if (phba->iocb_cnt > phba->iocb_max)
+		phba->iocb_max = phba->iocb_cnt;
 	return iocbq;
 }
 
@@ -575,7 +580,8 @@
 {
 	struct lpfc_sglq *sglq;
 	size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
-	unsigned long iflag;
+	unsigned long iflag = 0;
+	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
 
 	if (iocbq->sli4_xritag == NO_XRI)
 		sglq = NULL;
@@ -593,6 +599,10 @@
 		} else {
 			sglq->state = SGL_FREED;
 			list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list);
+
+			/* Check if TXQ queue needs to be serviced */
+			if (pring->txq_cnt)
+				lpfc_worker_wake_up(phba);
 		}
 	}
 
@@ -605,6 +615,7 @@
 	list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
 }
 
+
 /**
  * __lpfc_sli_release_iocbq_s3 - Release iocb to the iocb pool
  * @phba: Pointer to HBA context object.
@@ -642,6 +653,7 @@
 __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
 {
 	phba->__lpfc_sli_release_iocbq(phba, iocbq);
+	phba->iocb_cnt--;
 }
 
 /**
@@ -872,7 +884,11 @@
 			struct lpfc_iocbq *piocb)
 {
 	list_add_tail(&piocb->list, &pring->txcmplq);
+	piocb->iocb_flag |= LPFC_IO_ON_Q;
 	pring->txcmplq_cnt++;
+	if (pring->txcmplq_cnt > pring->txcmplq_max)
+		pring->txcmplq_max = pring->txcmplq_cnt;
+
 	if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
 	   (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
 	   (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
@@ -897,7 +913,7 @@
  * the txq, the function returns first iocb in the list after
  * removing the iocb from the list, else it returns NULL.
  **/
-static struct lpfc_iocbq *
+struct lpfc_iocbq *
 lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
 	struct lpfc_iocbq *cmd_iocb;
@@ -2150,7 +2166,10 @@
 	if (iotag != 0 && iotag <= phba->sli.last_iotag) {
 		cmd_iocb = phba->sli.iocbq_lookup[iotag];
 		list_del_init(&cmd_iocb->list);
-		pring->txcmplq_cnt--;
+		if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) {
+			pring->txcmplq_cnt--;
+			cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+		}
 		return cmd_iocb;
 	}
 
@@ -2183,7 +2202,10 @@
 	if (iotag != 0 && iotag <= phba->sli.last_iotag) {
 		cmd_iocb = phba->sli.iocbq_lookup[iotag];
 		list_del_init(&cmd_iocb->list);
-		pring->txcmplq_cnt--;
+		if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) {
+			cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+			pring->txcmplq_cnt--;
+		}
 		return cmd_iocb;
 	}
 
@@ -3564,13 +3586,16 @@
 lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
 {
 	struct lpfc_sli *psli = &phba->sli;
-
+	uint32_t hba_aer_enabled;
 
 	/* Restart HBA */
 	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
 			"0296 Restart HBA Data: x%x x%x\n",
 			phba->pport->port_state, psli->sli_flag);
 
+	/* Take PCIe device Advanced Error Reporting (AER) state */
+	hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED;
+
 	lpfc_sli4_brdreset(phba);
 
 	spin_lock_irq(&phba->hbalock);
@@ -3582,6 +3607,10 @@
 	memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
 	psli->stats_start = get_seconds();
 
+	/* Reset HBA AER if it was enabled, note hba_flag was reset above */
+	if (hba_aer_enabled)
+		pci_disable_pcie_error_reporting(phba->pcidev);
+
 	lpfc_hba_down_post(phba);
 
 	return 0;
@@ -3794,7 +3823,7 @@
 
 			phba->link_state = LPFC_HBA_ERROR;
 			mempool_free(pmb, phba->mbox_mem_pool);
-			return ENXIO;
+			return -ENXIO;
 		}
 	}
 	phba->hbq_count = hbq_count;
@@ -3885,7 +3914,6 @@
 		phba->sli3_options &= ~(LPFC_SLI3_NPIV_ENABLED |
 					LPFC_SLI3_HBQ_ENABLED |
 					LPFC_SLI3_CRP_ENABLED |
-					LPFC_SLI3_INB_ENABLED |
 					LPFC_SLI3_BG_ENABLED);
 		if (rc != MBX_SUCCESS) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -3927,20 +3955,9 @@
 			phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
 		if (pmb->u.mb.un.varCfgPort.gcrp)
 			phba->sli3_options |= LPFC_SLI3_CRP_ENABLED;
-		if (pmb->u.mb.un.varCfgPort.ginb) {
-			phba->sli3_options |= LPFC_SLI3_INB_ENABLED;
-			phba->hbq_get = phba->mbox->us.s3_inb_pgp.hbq_get;
-			phba->port_gp = phba->mbox->us.s3_inb_pgp.port;
-			phba->inb_ha_copy = &phba->mbox->us.s3_inb_pgp.ha_copy;
-			phba->inb_counter = &phba->mbox->us.s3_inb_pgp.counter;
-			phba->inb_last_counter =
-					phba->mbox->us.s3_inb_pgp.counter;
-		} else {
-			phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
-			phba->port_gp = phba->mbox->us.s3_pgp.port;
-			phba->inb_ha_copy = NULL;
-			phba->inb_counter = NULL;
-		}
+
+		phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
+		phba->port_gp = phba->mbox->us.s3_pgp.port;
 
 		if (phba->cfg_enable_bg) {
 			if (pmb->u.mb.un.varCfgPort.gbg)
@@ -3953,8 +3970,6 @@
 	} else {
 		phba->hbq_get = NULL;
 		phba->port_gp = phba->mbox->us.s2.port;
-		phba->inb_ha_copy = NULL;
-		phba->inb_counter = NULL;
 		phba->max_vpi = 0;
 	}
 do_prep_failed:
@@ -4214,7 +4229,8 @@
 	if (mqe->un.read_rev.avail_vpd_len < *vpd_size)
 		*vpd_size = mqe->un.read_rev.avail_vpd_len;
 
-	lpfc_sli_pcimem_bcopy(dmabuf->virt, vpd, *vpd_size);
+	memcpy(vpd, dmabuf->virt, *vpd_size);
+
 	dma_free_coherent(&phba->pcidev->dev, dma_size,
 			  dmabuf->virt, dmabuf->phys);
 	kfree(dmabuf);
@@ -4539,6 +4555,24 @@
 	/* Start error attention (ERATT) polling timer */
 	mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL);
 
+	/* Enable PCIe device Advanced Error Reporting (AER) if configured */
+	if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) {
+		rc = pci_enable_pcie_error_reporting(phba->pcidev);
+		if (!rc) {
+			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+					"2829 This device supports "
+					"Advanced Error Reporting (AER)\n");
+			spin_lock_irq(&phba->hbalock);
+			phba->hba_flag |= HBA_AER_ENABLED;
+			spin_unlock_irq(&phba->hbalock);
+		} else {
+			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+					"2830 This device does not support "
+					"Advanced Error Reporting (AER)\n");
+			phba->cfg_aer_support = 0;
+		}
+	}
+
 	/*
 	 * The port is ready, set the host's link state to LINK_DOWN
 	 * in preparation for link interrupts.
@@ -5265,7 +5299,8 @@
 	if (mcqe_status != MB_CQE_STATUS_SUCCESS) {
 		bf_set(lpfc_mqe_status, mb, LPFC_MBX_ERROR_RANGE | mcqe_status);
 		rc = MBXERR_ERROR;
-	}
+	} else
+		lpfc_sli4_swap_str(phba, mboxq);
 
 	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
 			"(%d):0356 Mailbox cmd x%x (x%x) Status x%x "
@@ -5592,7 +5627,7 @@
  * iocb to the txq when SLI layer cannot submit the command iocb
  * to the ring.
  **/
-static void
+void
 __lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		    struct lpfc_iocbq *piocb)
 {
@@ -6209,7 +6244,6 @@
 			 struct lpfc_iocbq *piocb, uint32_t flag)
 {
 	struct lpfc_sglq *sglq;
-	uint16_t xritag;
 	union lpfc_wqe wqe;
 	struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
 
@@ -6218,10 +6252,26 @@
 		    piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
 			sglq = NULL;
 		else {
+			if (pring->txq_cnt) {
+				if (!(flag & SLI_IOCB_RET_IOCB)) {
+					__lpfc_sli_ringtx_put(phba,
+						pring, piocb);
+					return IOCB_SUCCESS;
+				} else {
+					return IOCB_BUSY;
+				}
+			} else {
 			sglq = __lpfc_sli_get_sglq(phba);
-			if (!sglq)
-				return IOCB_ERROR;
-			piocb->sli4_xritag = sglq->sli4_xritag;
+				if (!sglq) {
+					if (!(flag & SLI_IOCB_RET_IOCB)) {
+						__lpfc_sli_ringtx_put(phba,
+								pring,
+								piocb);
+						return IOCB_SUCCESS;
+					} else
+						return IOCB_BUSY;
+				}
+			}
 		}
 	} else if (piocb->iocb_flag &  LPFC_IO_FCP) {
 		sglq = NULL; /* These IO's already have an XRI and
@@ -6237,8 +6287,9 @@
 	}
 
 	if (sglq) {
-		xritag = lpfc_sli4_bpl2sgl(phba, piocb, sglq);
-		if (xritag != sglq->sli4_xritag)
+		piocb->sli4_xritag = sglq->sli4_xritag;
+
+		if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocb, sglq))
 			return IOCB_ERROR;
 	}
 
@@ -6278,7 +6329,7 @@
  * 	IOCB_SUCCESS - Success
  * 	IOCB_BUSY - Busy
  **/
-static inline int
+int
 __lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
 		struct lpfc_iocbq *piocb, uint32_t flag)
 {
@@ -7095,13 +7146,6 @@
 			 */
 			abort_iocb = phba->sli.iocbq_lookup[abort_context];
 
-		lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI,
-				"0327 Cannot abort els iocb %p "
-				"with tag %x context %x, abort status %x, "
-				"abort code %x\n",
-				abort_iocb, abort_iotag, abort_context,
-				irsp->ulpStatus, irsp->un.ulpWord[4]);
-
 		/*
 		 *  If the iocb is not found in Firmware queue the iocb
 		 *  might have completed already. Do not free it again.
@@ -7120,6 +7164,13 @@
 			if (abort_iocb && phba->sli_rev == LPFC_SLI_REV4)
 				abort_context = abort_iocb->iocb.ulpContext;
 		}
+
+		lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_SLI,
+				"0327 Cannot abort els iocb %p "
+				"with tag %x context %x, abort status %x, "
+				"abort code %x\n",
+				abort_iocb, abort_iotag, abort_context,
+				irsp->ulpStatus, irsp->un.ulpWord[4]);
 		/*
 		 * make sure we have the right iocbq before taking it
 		 * off the txcmplq and try to call completion routine.
@@ -7137,7 +7188,10 @@
 			 * following abort XRI from the HBA.
 			 */
 			list_del_init(&abort_iocb->list);
-			pring->txcmplq_cnt--;
+			if (abort_iocb->iocb_flag & LPFC_IO_ON_Q) {
+				abort_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+				pring->txcmplq_cnt--;
+			}
 
 			/* Firmware could still be in progress of DMAing
 			 * payload, so don't free data buffer till after
@@ -7269,8 +7323,9 @@
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
 			 "0339 Abort xri x%x, original iotag x%x, "
 			 "abort cmd iotag x%x\n",
+			 iabt->un.acxri.abortIoTag,
 			 iabt->un.acxri.abortContextTag,
-			 iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
+			 abtsiocbp->iotag);
 	retval = __lpfc_sli_issue_iocb(phba, pring->ringno, abtsiocbp, 0);
 
 	if (retval)
@@ -7600,7 +7655,7 @@
 	long timeleft, timeout_req = 0;
 	int retval = IOCB_SUCCESS;
 	uint32_t creg_val;
-
+	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
 	/*
 	 * If the caller has provided a response iocbq buffer, then context2
 	 * is NULL or its an error.
@@ -7622,7 +7677,8 @@
 		readl(phba->HCregaddr); /* flush */
 	}
 
-	retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, 0);
+	retval = lpfc_sli_issue_iocb(phba, ring_number, piocb,
+				     SLI_IOCB_RET_IOCB);
 	if (retval == IOCB_SUCCESS) {
 		timeout_req = timeout * HZ;
 		timeleft = wait_event_timeout(done_q,
@@ -7644,6 +7700,11 @@
 					timeout, (timeleft / jiffies));
 			retval = IOCB_TIMEDOUT;
 		}
+	} else if (retval == IOCB_BUSY) {
+		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+			"2818 Max IOCBs %d txq cnt %d txcmplq cnt %d\n",
+			phba->iocb_cnt, pring->txq_cnt, pring->txcmplq_cnt);
+		return retval;
 	} else {
 		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
 				"0332 IOCB wait issue failed, Data x%x\n",
@@ -7724,9 +7785,10 @@
 		 * if LPFC_MBX_WAKE flag is set the mailbox is completed
 		 * else do not free the resources.
 		 */
-		if (pmboxq->mbox_flag & LPFC_MBX_WAKE)
+		if (pmboxq->mbox_flag & LPFC_MBX_WAKE) {
 			retval = MBX_SUCCESS;
-		else {
+			lpfc_sli4_swap_str(phba, pmboxq);
+		} else {
 			retval = MBX_TIMEOUT;
 			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 		}
@@ -8789,12 +8851,17 @@
 {
 	struct lpfc_iocbq *irspiocbq;
 	unsigned long iflags;
+	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING];
 
 	/* Get an irspiocbq for later ELS response processing use */
 	irspiocbq = lpfc_sli_get_iocbq(phba);
 	if (!irspiocbq) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-				"0387 Failed to allocate an iocbq\n");
+			"0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d "
+			"fcp_txcmplq_cnt=%d, els_txcmplq_cnt=%d\n",
+			pring->txq_cnt, phba->iocb_cnt,
+			phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt,
+			phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt);
 		return false;
 	}
 
@@ -9043,9 +9110,10 @@
 		}
 	}
 	if (unlikely(!cq)) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-				"0365 Slow-path CQ identifier (%d) does "
-				"not exist\n", cqid);
+		if (phba->sli.sli_flag & LPFC_SLI_ACTIVE)
+			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+					"0365 Slow-path CQ identifier "
+					"(%d) does not exist\n", cqid);
 		return;
 	}
 
@@ -9208,6 +9276,7 @@
 {
 	struct lpfc_wcqe_release wcqe;
 	bool workposted = false;
+	unsigned long iflag;
 
 	/* Copy the work queue CQE and convert endian order if needed */
 	lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe));
@@ -9216,6 +9285,9 @@
 	switch (bf_get(lpfc_wcqe_c_code, &wcqe)) {
 	case CQE_CODE_COMPL_WQE:
 		/* Process the WQ complete event */
+		spin_lock_irqsave(&phba->hbalock, iflag);
+		phba->last_completion_time = jiffies;
+		spin_unlock_irqrestore(&phba->hbalock, iflag);
 		lpfc_sli4_fp_handle_fcp_wcqe(phba,
 				(struct lpfc_wcqe_complete *)&wcqe);
 		break;
@@ -9271,9 +9343,10 @@
 
 	cq = phba->sli4_hba.fcp_cq[fcp_cqidx];
 	if (unlikely(!cq)) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-				"0367 Fast-path completion queue does not "
-				"exist\n");
+		if (phba->sli.sli_flag & LPFC_SLI_ACTIVE)
+			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+					"0367 Fast-path completion queue "
+					"does not exist\n");
 		return;
 	}
 
@@ -11898,12 +11971,26 @@
  * available rpis maintained by the driver.
  **/
 void
+__lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
+{
+	if (test_and_clear_bit(rpi, phba->sli4_hba.rpi_bmask)) {
+		phba->sli4_hba.rpi_count--;
+		phba->sli4_hba.max_cfg_param.rpi_used--;
+	}
+}
+
+/**
+ * lpfc_sli4_free_rpi - Release an rpi for reuse.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release an rpi to the pool of
+ * available rpis maintained by the driver.
+ **/
+void
 lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
 {
 	spin_lock_irq(&phba->hbalock);
-	clear_bit(rpi, phba->sli4_hba.rpi_bmask);
-	phba->sli4_hba.rpi_count--;
-	phba->sli4_hba.max_cfg_param.rpi_used--;
+	__lpfc_sli4_free_rpi(phba, rpi);
 	spin_unlock_irq(&phba->hbalock);
 }
 
@@ -12318,18 +12405,47 @@
 {
 	uint16_t next_fcf_index;
 
-	/* Search from the currently registered FCF index */
+	/* Search start from next bit of currently registered FCF index */
+	next_fcf_index = (phba->fcf.current_rec.fcf_indx + 1) %
+					LPFC_SLI4_FCF_TBL_INDX_MAX;
 	next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
 				       LPFC_SLI4_FCF_TBL_INDX_MAX,
-				       phba->fcf.current_rec.fcf_indx);
+				       next_fcf_index);
+
 	/* Wrap around condition on phba->fcf.fcf_rr_bmask */
 	if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX)
 		next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
 					       LPFC_SLI4_FCF_TBL_INDX_MAX, 0);
-	/* Round robin failover stop condition */
-	if (next_fcf_index == phba->fcf.fcf_rr_init_indx)
-		return LPFC_FCOE_FCF_NEXT_NONE;
 
+	/* Check roundrobin failover list empty condition */
+	if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+				"2844 No roundrobin failover FCF available\n");
+		return LPFC_FCOE_FCF_NEXT_NONE;
+	}
+
+	/* Check roundrobin failover index bmask stop condition */
+	if (next_fcf_index == phba->fcf.fcf_rr_init_indx) {
+		if (!(phba->fcf.fcf_flag & FCF_REDISC_RRU)) {
+			lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+					"2847 Round robin failover FCF index "
+					"search hit stop condition:x%x\n",
+					next_fcf_index);
+			return LPFC_FCOE_FCF_NEXT_NONE;
+		}
+		/* The roundrobin failover index bmask updated, start over */
+		lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+				"2848 Round robin failover FCF index bmask "
+				"updated, start over\n");
+		spin_lock_irq(&phba->hbalock);
+		phba->fcf.fcf_flag &= ~FCF_REDISC_RRU;
+		spin_unlock_irq(&phba->hbalock);
+		return phba->fcf.fcf_rr_init_indx;
+	}
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+			"2845 Get next round robin failover "
+			"FCF index x%x\n", next_fcf_index);
 	return next_fcf_index;
 }
 
@@ -12359,11 +12475,20 @@
 	/* Set the eligible FCF record index bmask */
 	set_bit(fcf_index, phba->fcf.fcf_rr_bmask);
 
+	/* Set the roundrobin index bmask updated */
+	spin_lock_irq(&phba->hbalock);
+	phba->fcf.fcf_flag |= FCF_REDISC_RRU;
+	spin_unlock_irq(&phba->hbalock);
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+			"2790 Set FCF index x%x to round robin failover "
+			"bmask\n", fcf_index);
+
 	return 0;
 }
 
 /**
- * lpfc_sli4_fcf_rr_index_set - Clear bmask from eligible fcf record index
+ * lpfc_sli4_fcf_rr_index_clear - Clear bmask from eligible fcf record index
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine clears the FCF record index from the eligible bmask for
@@ -12384,6 +12509,10 @@
 	}
 	/* Clear the eligible FCF record index bmask */
 	clear_bit(fcf_index, phba->fcf.fcf_rr_bmask);
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+			"2791 Clear FCF index x%x from round robin failover "
+			"bmask\n", fcf_index);
 }
 
 /**
@@ -12446,7 +12575,7 @@
 }
 
 /**
- * lpfc_sli4_redisc_all_fcf - Request to rediscover entire FCF table by port.
+ * lpfc_sli4_redisc_fcf_table - Request to rediscover entire FCF table by port.
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to request for rediscovery of the entire FCF table
@@ -12662,6 +12791,7 @@
 	LPFC_MBOXQ_t *mb, *nextmb;
 	struct lpfc_dmabuf *mp;
 	struct lpfc_nodelist *ndlp;
+	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 
 	spin_lock_irq(&phba->hbalock);
 	list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
@@ -12673,6 +12803,9 @@
 			continue;
 
 		if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
+			if (phba->sli_rev == LPFC_SLI_REV4)
+				__lpfc_sli4_free_rpi(phba,
+						mb->u.mb.un.varRegLogin.rpi);
 			mp = (struct lpfc_dmabuf *) (mb->context1);
 			if (mp) {
 				__lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -12680,6 +12813,9 @@
 			}
 			ndlp = (struct lpfc_nodelist *) mb->context2;
 			if (ndlp) {
+				spin_lock_irq(shost->host_lock);
+				ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
+				spin_unlock_irq(shost->host_lock);
 				lpfc_nlp_put(ndlp);
 				mb->context2 = NULL;
 			}
@@ -12695,6 +12831,9 @@
 		if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
 			ndlp = (struct lpfc_nodelist *) mb->context2;
 			if (ndlp) {
+				spin_lock_irq(shost->host_lock);
+				ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
+				spin_unlock_irq(shost->host_lock);
 				lpfc_nlp_put(ndlp);
 				mb->context2 = NULL;
 			}
@@ -12705,3 +12844,85 @@
 	spin_unlock_irq(&phba->hbalock);
 }
 
+/**
+ * lpfc_drain_txq - Drain the txq
+ * @phba: Pointer to HBA context object.
+ *
+ * This function attempt to submit IOCBs on the txq
+ * to the adapter.  For SLI4 adapters, the txq contains
+ * ELS IOCBs that have been deferred because the there
+ * are no SGLs.  This congestion can occur with large
+ * vport counts during node discovery.
+ **/
+
+uint32_t
+lpfc_drain_txq(struct lpfc_hba *phba)
+{
+	LIST_HEAD(completions);
+	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+	struct lpfc_iocbq *piocbq = 0;
+	unsigned long iflags = 0;
+	char *fail_msg = NULL;
+	struct lpfc_sglq *sglq;
+	union lpfc_wqe wqe;
+
+	spin_lock_irqsave(&phba->hbalock, iflags);
+	if (pring->txq_cnt > pring->txq_max)
+		pring->txq_max = pring->txq_cnt;
+
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+	while (pring->txq_cnt) {
+		spin_lock_irqsave(&phba->hbalock, iflags);
+
+		sglq = __lpfc_sli_get_sglq(phba);
+		if (!sglq) {
+			spin_unlock_irqrestore(&phba->hbalock, iflags);
+			break;
+		} else {
+			piocbq = lpfc_sli_ringtx_get(phba, pring);
+			if (!piocbq) {
+				/* The txq_cnt out of sync. This should
+				 * never happen
+				 */
+				sglq = __lpfc_clear_active_sglq(phba,
+						 sglq->sli4_xritag);
+				spin_unlock_irqrestore(&phba->hbalock, iflags);
+				lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+					"2823 txq empty and txq_cnt is %d\n ",
+					pring->txq_cnt);
+				break;
+			}
+		}
+
+		/* The xri and iocb resources secured,
+		 * attempt to issue request
+		 */
+		piocbq->sli4_xritag = sglq->sli4_xritag;
+		if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq))
+			fail_msg = "to convert bpl to sgl";
+		else if (lpfc_sli4_iocb2wqe(phba, piocbq, &wqe))
+			fail_msg = "to convert iocb to wqe";
+		else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe))
+			fail_msg = " - Wq is full";
+		else
+			lpfc_sli_ringtxcmpl_put(phba, pring, piocbq);
+
+		if (fail_msg) {
+			/* Failed means we can't issue and need to cancel */
+			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+					"2822 IOCB failed %s iotag 0x%x "
+					"xri 0x%x\n",
+					fail_msg,
+					piocbq->iotag, piocbq->sli4_xritag);
+			list_add_tail(&piocbq->list, &completions);
+		}
+		spin_unlock_irqrestore(&phba->hbalock, iflags);
+	}
+
+	/* Cancel all the IOCBs that cannot be issued */
+	lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
+				IOERR_SLI_ABORTED);
+
+	return pring->txq_cnt;
+}
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index e379215..cd56d6c 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -48,6 +48,7 @@
 	/* lpfc_iocbqs are used in double linked lists */
 	struct list_head list;
 	struct list_head clist;
+	struct list_head dlist;
 	uint16_t iotag;         /* pre-assigned IO tag */
 	uint16_t sli4_xritag;   /* pre-assigned XRI, (OXID) tag. */
 	struct lpfc_cq_event cq_event;
@@ -64,6 +65,7 @@
 #define LPFC_EXCHANGE_BUSY	0x40    /* SLI4 hba reported XB in response */
 #define LPFC_USE_FCPWQIDX	0x80    /* Submit to specified FCPWQ index */
 #define DSS_SECURITY_OP		0x100	/* security IO */
+#define LPFC_IO_ON_Q		0x200	/* The IO is still on the TXCMPLQ */
 
 #define LPFC_FIP_ELS_ID_MASK	0xc000	/* ELS_ID range 0-3, non-shifted mask */
 #define LPFC_FIP_ELS_ID_SHIFT	14
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 58bb4c8..a3b24d9 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -51,6 +51,9 @@
 #define LPFC_FCOE_FCF_GET_FIRST	0xFFFF
 #define LPFC_FCOE_FCF_NEXT_NONE	0xFFFF
 
+#define LPFC_FCOE_NULL_VID	0xFFF
+#define LPFC_FCOE_IGNORE_VID	0xFFFF
+
 /* First 3 bytes of default FCF MAC is specified by FC_MAP */
 #define LPFC_FCOE_FCF_MAC3	0xFF
 #define LPFC_FCOE_FCF_MAC4	0xFF
@@ -58,7 +61,7 @@
 #define LPFC_FCOE_FCF_MAP0	0x0E
 #define LPFC_FCOE_FCF_MAP1	0xFC
 #define LPFC_FCOE_FCF_MAP2	0x00
-#define LPFC_FCOE_MAX_RCV_SIZE	0x5AC
+#define LPFC_FCOE_MAX_RCV_SIZE	0x800
 #define LPFC_FCOE_FKA_ADV_PER	0
 #define LPFC_FCOE_FIP_PRIORITY	0x80
 
@@ -160,6 +163,7 @@
 #define FCF_REDISC_PEND	0x80 /* FCF rediscovery pending */
 #define FCF_REDISC_EVT	0x100 /* FCF rediscovery event to worker thread */
 #define FCF_REDISC_FOV	0x200 /* Post FCF rediscovery fast failover */
+#define FCF_REDISC_RRU	0x400 /* Roundrobin bitmap updated */
 	uint32_t addr_mode;
 	uint16_t fcf_rr_init_indx;
 	uint32_t eligible_fcf_cnt;
@@ -382,6 +386,7 @@
 	struct lpfc_pc_sli4_params pc_sli4_params;
 	struct msix_entry *msix_entries;
 	uint32_t cfg_eqn;
+	uint32_t msix_vec_nr;
 	struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */
 	/* Pointers to the constructed SLI4 queues */
 	struct lpfc_queue **fp_eq; /* Fast-path event queue */
@@ -524,6 +529,7 @@
 struct lpfc_rpi_hdr *lpfc_sli4_create_rpi_hdr(struct lpfc_hba *);
 void lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *);
 int lpfc_sli4_alloc_rpi(struct lpfc_hba *);
+void __lpfc_sli4_free_rpi(struct lpfc_hba *, int);
 void lpfc_sli4_free_rpi(struct lpfc_hba *, int);
 void lpfc_sli4_remove_rpis(struct lpfc_hba *);
 void lpfc_sli4_async_event_proc(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 5294c3a..d28830a 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.3.12"
+#define LPFC_DRIVER_VERSION "8.3.15"
 #define LPFC_DRIVER_NAME		"lpfc"
 #define LPFC_SP_DRIVER_HANDLER_NAME	"lpfc:sp"
 #define LPFC_FP_DRIVER_HANDLER_NAME	"lpfc:fp"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index ab91359..1655507 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -782,7 +782,7 @@
 	int i;
 	if (vports == NULL)
 		return;
-	for (i = 0; vports[i] != NULL && i <= phba->max_vports; i++)
+	for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
 		scsi_host_put(lpfc_shost_from_vport(vports[i]));
 	kfree(vports);
 }
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index dada0a1..4b1c2f0 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h
@@ -8,7 +8,7 @@
  *                  scatter/gather formats.
  *  Creation Date:  June 21, 2006
  *
- *  mpi2.h Version:  02.00.14
+ *  mpi2.h Version:  02.00.15
  *
  *  Version History
  *  ---------------
@@ -57,6 +57,10 @@
  *                      Added MSI-x index mask and shift for Reply Post Host
  *                      Index register.
  *                      Added function code for Host Based Discovery Action.
+ *  02-10-10  02.00.15  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL.
+ *                      Added defines for product-specific range of message
+ *                      function codes, 0xF0 to 0xFF.
  *  --------------------------------------------------------------------------
  */
 
@@ -82,7 +86,7 @@
 #define MPI2_VERSION_02_00                  (0x0200)
 
 /* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT            (0x0E)
+#define MPI2_HEADER_VERSION_UNIT            (0x0F)
 #define MPI2_HEADER_VERSION_DEV             (0x00)
 #define MPI2_HEADER_VERSION_UNIT_MASK       (0xFF00)
 #define MPI2_HEADER_VERSION_UNIT_SHIFT      (8)
@@ -473,8 +477,6 @@
 /*****************************************************************************
 *
 *        Message Functions
-*              0x80 -> 0x8F reserved for private message use per product
-*
 *
 *****************************************************************************/
 
@@ -506,6 +508,13 @@
 #define MPI2_FUNCTION_RAID_ACCELERATOR              (0x2C) /* RAID Accelerator*/
 /* Host Based Discovery Action */
 #define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION   (0x2F)
+/* Power Management Control */
+#define MPI2_FUNCTION_PWR_MGMT_CONTROL              (0x30)
+/* beginning of product-specific range */
+#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC          (0xF0)
+/* end of product-specific range */
+#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC          (0xFF)
+
 
 
 
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index d4e9d6f..e3728d7 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
@@ -6,7 +6,7 @@
  *          Title:  MPI Configuration messages and pages
  *  Creation Date:  November 10, 2006
  *
- *    mpi2_cnfg.h Version:  02.00.13
+ *    mpi2_cnfg.h Version:  02.00.14
  *
  *  Version History
  *  ---------------
@@ -109,6 +109,18 @@
  *                      Added Ethernet configuration pages.
  *  10-28-09  02.00.13  Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
  *                      Added SAS PHY Page 4 structure and defines.
+ *  02-10-10  02.00.14  Modified the comments for the configuration page
+ *                      structures that contain an array of data. The host
+ *                      should use the "count" field in the page data (e.g. the
+ *                      NumPhys field) to determine the number of valid elements
+ *                      in the array.
+ *                      Added/modified some MPI2_MFGPAGE_DEVID_SAS defines.
+ *                      Added PowerManagementCapabilities to IO Unit Page 7.
+ *                      Added PortWidthModGroup field to
+ *                      MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS.
+ *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.
+ *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.
+ *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines.
  *  --------------------------------------------------------------------------
  */
 
@@ -373,8 +385,9 @@
 #define MPI2_MFGPAGE_DEVID_SAS2208_4                (0x0083)
 #define MPI2_MFGPAGE_DEVID_SAS2208_5                (0x0084)
 #define MPI2_MFGPAGE_DEVID_SAS2208_6                (0x0085)
-#define MPI2_MFGPAGE_DEVID_SAS2208_7                (0x0086)
-#define MPI2_MFGPAGE_DEVID_SAS2208_8                (0x0087)
+#define MPI2_MFGPAGE_DEVID_SAS2308_1                (0x0086)
+#define MPI2_MFGPAGE_DEVID_SAS2308_2                (0x0087)
+#define MPI2_MFGPAGE_DEVID_SAS2308_3                (0x006E)
 
 
 /* Manufacturing Page 0 */
@@ -540,7 +553,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES
 #define MPI2_MAN_PAGE_5_PHY_ENTRIES         (1)
@@ -618,7 +631,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX
 #define MPI2_MANPAGE7_CONNECTOR_INFO_MAX  (1)
@@ -731,7 +744,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
+ * one and check the value returned for GPIOCount at runtime.
  */
 #ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX
 #define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX    (1)
@@ -760,7 +773,7 @@
 
 /*
  * Upper layer code (drivers, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumDmaEngines at runtime.
+ * one and check the value returned for NumDmaEngines at runtime.
  */
 #ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES
 #define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES      (1)
@@ -823,7 +836,7 @@
     U8                      PCIeWidth;                              /* 0x06 */
     U8                      PCIeSpeed;                              /* 0x07 */
     U32                     ProcessorState;                         /* 0x08 */
-    U32                     Reserved2;                              /* 0x0C */
+    U32                     PowerManagementCapabilities;            /* 0x0C */
     U16                     IOCTemperature;                         /* 0x10 */
     U8                      IOCTemperatureUnits;                    /* 0x12 */
     U8                      IOCSpeed;                               /* 0x13 */
@@ -831,7 +844,7 @@
 } MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7,
   Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t;
 
-#define MPI2_IOUNITPAGE7_PAGEVERSION                    (0x00)
+#define MPI2_IOUNITPAGE7_PAGEVERSION                    (0x01)
 
 /* defines for IO Unit Page 7 PCIeWidth field */
 #define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1              (0x01)
@@ -852,6 +865,14 @@
 #define MPI2_IOUNITPAGE7_PSTATE_DISABLED            (0x01)
 #define MPI2_IOUNITPAGE7_PSTATE_ENABLED             (0x02)
 
+/* defines for IO Unit Page 7 PowerManagementCapabilities field */
+#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED    (0x00000400)
+#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED    (0x00000200)
+#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED    (0x00000100)
+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE    (0x00000008)
+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE    (0x00000004)
+
+
 /* defines for IO Unit Page 7 IOCTemperatureUnits field */
 #define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT       (0x00)
 #define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT        (0x01)
@@ -1195,7 +1216,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES
 #define MPI2_BIOS_PAGE_4_PHY_ENTRIES        (1)
@@ -1269,7 +1290,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
+ * one and check the value returned for NumPhysDisks at runtime.
  */
 #ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX
 #define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX       (1)
@@ -1471,7 +1492,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhysDiskPaths at runtime.
+ * one and check the value returned for NumPhysDiskPaths at runtime.
  */
 #ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX
 #define MPI2_RAID_PHYS_DISK1_PATH_MAX   (1)
@@ -1633,7 +1654,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_SAS_IOUNIT0_PHY_MAX
 #define MPI2_SAS_IOUNIT0_PHY_MAX        (1)
@@ -1704,7 +1725,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_SAS_IOUNIT1_PHY_MAX
 #define MPI2_SAS_IOUNIT1_PHY_MAX        (1)
@@ -1795,7 +1816,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * four and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_SAS_IOUNIT4_PHY_MAX
 #define MPI2_SAS_IOUNIT4_PHY_MAX        (4)
@@ -1833,7 +1854,7 @@
 
 typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS {
     U8          ControlFlags;               /* 0x00 */
-    U8          Reserved1;                  /* 0x01 */
+    U8          PortWidthModGroup;          /* 0x01 */
     U16         InactivityTimerExponent;    /* 0x02 */
     U8          SATAPartialTimeout;         /* 0x04 */
     U8          Reserved2;                  /* 0x05 */
@@ -1853,6 +1874,9 @@
 #define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE     (0x02)
 #define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE     (0x01)
 
+/* defines for PortWidthModeGroup field */
+#define MPI2_SASIOUNIT5_PWMG_DISABLE                    (0xFF)
+
 /* defines for InactivityTimerExponent field */
 #define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER            (0x7000)
 #define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER           (12)
@@ -1874,7 +1898,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
  */
 #ifndef MPI2_SAS_IOUNIT5_PHY_MAX
 #define MPI2_SAS_IOUNIT5_PHY_MAX        (1)
@@ -1892,7 +1916,132 @@
   MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5,
   Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t;
 
-#define MPI2_SASIOUNITPAGE5_PAGEVERSION     (0x00)
+#define MPI2_SASIOUNITPAGE5_PAGEVERSION     (0x01)
+
+
+/* SAS IO Unit Page 6 */
+
+typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS {
+    U8          CurrentStatus;              /* 0x00 */
+    U8          CurrentModulation;          /* 0x01 */
+    U8          CurrentUtilization;         /* 0x02 */
+    U8          Reserved1;                  /* 0x03 */
+    U32         Reserved2;                  /* 0x04 */
+} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
+  MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
+  Mpi2SasIOUnit6PortWidthModGroupStatus_t,
+  MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t;
+
+/* defines for CurrentStatus field */
+#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE                      (0x00)
+#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED                     (0x01)
+#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG                   (0x02)
+#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN                        (0x03)
+#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY                 (0x04)
+#define MPI2_SASIOUNIT6_STATUS_INACTIVE                         (0x05)
+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT                    (0x06)
+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST                      (0x07)
+
+/* defines for CurrentModulation field */
+#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT                   (0x00)
+#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT                   (0x01)
+#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT                   (0x02)
+#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT                  (0x03)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumGroups at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX
+#define MPI2_SAS_IOUNIT6_GROUP_MAX      (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 {
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U32                                 Reserved1;                  /* 0x08 */
+    U32                                 Reserved2;                  /* 0x0C */
+    U8                                  NumGroups;                  /* 0x10 */
+    U8                                  Reserved3;                  /* 0x11 */
+    U16                                 Reserved4;                  /* 0x12 */
+    MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS
+	PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_6,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6,
+  Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t;
+
+#define MPI2_SASIOUNITPAGE6_PAGEVERSION     (0x00)
+
+
+/* SAS IO Unit Page 7 */
+
+typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS {
+    U8          Flags;                      /* 0x00 */
+    U8          Reserved1;                  /* 0x01 */
+    U16         Reserved2;                  /* 0x02 */
+    U8          Threshold75Pct;             /* 0x04 */
+    U8          Threshold50Pct;             /* 0x05 */
+    U8          Threshold25Pct;             /* 0x06 */
+    U8          Reserved3;                  /* 0x07 */
+} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
+  MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
+  Mpi2SasIOUnit7PortWidthModGroupSettings_t,
+  MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t;
+
+/* defines for Flags field */
+#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION  (0x01)
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumGroups at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX
+#define MPI2_SAS_IOUNIT7_GROUP_MAX      (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 {
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER            Header;             /* 0x00 */
+    U8                                          SamplingInterval;   /* 0x08 */
+    U8                                          WindowLength;       /* 0x09 */
+    U16                                         Reserved1;          /* 0x0A */
+    U32                                         Reserved2;          /* 0x0C */
+    U32                                         Reserved3;          /* 0x10 */
+    U8                                          NumGroups;          /* 0x14 */
+    U8                                          Reserved4;          /* 0x15 */
+    U16                                         Reserved5;          /* 0x16 */
+    MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS
+	PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_7,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7,
+  Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t;
+
+#define MPI2_SASIOUNITPAGE7_PAGEVERSION     (0x00)
+
+
+/* SAS IO Unit Page 8 */
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 {
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;			/* 0x00 */
+    U32                                 Reserved1;		/* 0x08 */
+    U32                                 PowerManagementCapabilities;/* 0x0C */
+    U32                                 Reserved2;		/* 0x10 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_8,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8,
+  Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t;
+
+#define MPI2_SASIOUNITPAGE8_PAGEVERSION     (0x00)
+
+/* defines for PowerManagementCapabilities field */
+#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD          (0x000001000)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE        (0x000000800)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE        (0x000000400)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE       (0x000000200)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE       (0x000000100)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD        (0x000000010)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE      (0x000000008)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE      (0x000000004)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE     (0x000000002)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE     (0x000000001)
 
 
 
@@ -2182,7 +2331,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ * one and check the value returned for NumPhyEvents at runtime.
  */
 #ifndef MPI2_SASPHY2_PHY_EVENT_MAX
 #define MPI2_SASPHY2_PHY_EVENT_MAX      (1)
@@ -2274,7 +2423,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ * one and check the value returned for NumPhyEvents at runtime.
  */
 #ifndef MPI2_SASPHY3_PHY_EVENT_MAX
 #define MPI2_SASPHY3_PHY_EVENT_MAX      (1)
@@ -2385,7 +2534,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumLogEntries at runtime.
  */
 #ifndef MPI2_LOG_0_NUM_LOG_ENTRIES
 #define MPI2_LOG_0_NUM_LOG_ENTRIES          (1)
@@ -2435,7 +2584,7 @@
 
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumElements at runtime.
  */
 #ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS
 #define MPI2_RAIDCONFIG0_MAX_ELEMENTS       (1)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
index 220bf65..c4c99df 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
@@ -6,7 +6,7 @@
  *          Title:  MPI SCSI initiator mode messages and structures
  *  Creation Date:  June 23, 2006
  *
- *    mpi2_init.h Version:  02.00.08
+ *    mpi2_init.h Version:  02.00.09
  *
  *  Version History
  *  ---------------
@@ -31,6 +31,7 @@
  *                      both SCSI IO Error Reply and SCSI Task Management Reply.
  *                      Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
  *                      Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
+ *  02-10-10  02.00.09  Removed unused structure that had "#if 0" around it.
  *  --------------------------------------------------------------------------
  */
 
@@ -57,20 +58,6 @@
 } MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32,
   Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t;
 
-/* TBD: I don't think this is needed for MPI2/Gen2 */
-#if 0
-typedef struct
-{
-    U8                      CDB[16];                    /* 0x00 */
-    U32                     DataLength;                 /* 0x10 */
-    U32                     PrimaryReferenceTag;        /* 0x14 */
-    U16                     PrimaryApplicationTag;      /* 0x18 */
-    U16                     PrimaryApplicationTagMask;  /* 0x1A */
-    U32                     TransferLength;             /* 0x1C */
-} MPI2_SCSI_IO32_CDB_EEDP16, MPI2_POINTER PTR_MPI2_SCSI_IO32_CDB_EEDP16,
-  Mpi2ScsiIo32CdbEedp16_t, MPI2_POINTER pMpi2ScsiIo32CdbEedp16_t;
-#endif
-
 typedef union
 {
     U8                      CDB32[32];
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
index f18f114..495bedc 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
@@ -6,7 +6,7 @@
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  October 11, 2006
  *
- *  mpi2_ioc.h Version:  02.00.13
+ *  mpi2_ioc.h Version:  02.00.14
  *
  *  Version History
  *  ---------------
@@ -98,6 +98,9 @@
  *                      (MPI2_FW_HEADER_PID_).
  *                      Modified values for SAS ProductID Family
  *                      (MPI2_FW_HEADER_PID_FAMILY_).
+ *  02-10-10  02.00.14  Added SAS Quiesce Event structure and defines.
+ *                      Added PowerManagementControl Request structures and
+ *                      defines.
  *  --------------------------------------------------------------------------
  */
 
@@ -469,6 +472,7 @@
 #define MPI2_EVENT_SAS_PHY_COUNTER                  (0x0022)
 #define MPI2_EVENT_GPIO_INTERRUPT                   (0x0023)
 #define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY         (0x0024)
+#define MPI2_EVENT_SAS_QUIESCE                      (0x0025)
 
 
 /* Log Entry Added Event data */
@@ -895,6 +899,22 @@
  * */
 
 
+/* SAS Quiesce Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE {
+    U8                      ReasonCode;                 /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U16                     Reserved2;                  /* 0x02 */
+    U32                     Reserved3;                  /* 0x04 */
+} MPI2_EVENT_DATA_SAS_QUIESCE,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE,
+  Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t;
+
+/* SAS Quiesce Event data ReasonCode values */
+#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED                   (0x01)
+#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED                 (0x02)
+
+
 /* Host Based Discovery Phy Event data */
 
 typedef struct _MPI2_EVENT_HBD_PHY_SAS {
@@ -1006,6 +1026,7 @@
 #define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1             (0x07)
 #define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2             (0x08)
 #define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID             (0x09)
+#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE             (0x0A)
 #define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK    (0x0B)
 
 /* FWDownload TransactionContext Element */
@@ -1183,7 +1204,6 @@
 
 #define MPI2_FW_HEADER_PID_PROD_MASK                    (0x0F00)
 #define MPI2_FW_HEADER_PID_PROD_A                       (0x0000)
-#define MPI2_FW_HEADER_PID_PROD_MASK                    (0x0F00)
 #define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI   (0x0200)
 #define MPI2_FW_HEADER_PID_PROD_IR_SCSI                 (0x0700)
 
@@ -1407,5 +1427,100 @@
 #define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET      (0x14)
 
 
+/****************************************************************************
+*  PowerManagementControl message
+****************************************************************************/
+
+/* PowerManagementControl Request message */
+typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST {
+    U8                      Feature;                    /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U8                      ChainOffset;                /* 0x02 */
+    U8                      Function;                   /* 0x03 */
+    U16                     Reserved2;                  /* 0x04 */
+    U8                      Reserved3;                  /* 0x06 */
+    U8                      MsgFlags;                   /* 0x07 */
+    U8                      VP_ID;                      /* 0x08 */
+    U8                      VF_ID;                      /* 0x09 */
+    U16                     Reserved4;                  /* 0x0A */
+    U8                      Parameter1;                 /* 0x0C */
+    U8                      Parameter2;                 /* 0x0D */
+    U8                      Parameter3;                 /* 0x0E */
+    U8                      Parameter4;                 /* 0x0F */
+    U32                     Reserved5;                  /* 0x10 */
+    U32                     Reserved6;                  /* 0x14 */
+} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST,
+  Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t;
+
+/* defines for the Feature field */
+#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND       (0x01)
+#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION   (0x02)
+#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK               (0x03)
+#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED               (0x04)
+#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC    (0x80)
+#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC    (0xFF)
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */
+/* Parameter1 contains a PHY number */
+/* Parameter2 indicates power condition action using these defines */
+#define MPI2_PM_CONTROL_PARAM2_PARTIAL                  (0x01)
+#define MPI2_PM_CONTROL_PARAM2_SLUMBER                  (0x02)
+#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT            (0x03)
+/* Parameter3 and Parameter4 are reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION
+ *  Feature */
+/* Parameter1 contains SAS port width modulation group number */
+/* Parameter2 indicates IOC action using these defines */
+#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP        (0x01)
+#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION        (0x02)
+#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP     (0x03)
+/* Parameter3 indicates desired modulation level using these defines */
+#define MPI2_PM_CONTROL_PARAM3_25_PERCENT               (0x00)
+#define MPI2_PM_CONTROL_PARAM3_50_PERCENT               (0x01)
+#define MPI2_PM_CONTROL_PARAM3_75_PERCENT               (0x02)
+#define MPI2_PM_CONTROL_PARAM3_100_PERCENT              (0x03)
+/* Parameter4 is reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */
+/* Parameter1 indicates desired PCIe link speed using these defines */
+#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS            (0x00)
+#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS            (0x01)
+#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS            (0x02)
+/* Parameter2 indicates desired PCIe link width using these defines */
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1                 (0x01)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2                 (0x02)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4                 (0x04)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8                 (0x08)
+/* Parameter3 and Parameter4 are reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */
+/* Parameter1 indicates desired IOC hardware clock speed using these defines */
+#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED           (0x01)
+#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED           (0x02)
+#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED        (0x04)
+#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED         (0x08)
+/* Parameter2, Parameter3, and Parameter4 are reserved */
+
+
+/* PowerManagementControl Reply message */
+typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY {
+    U8                      Feature;                    /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U8                      MsgLength;                  /* 0x02 */
+    U8                      Function;                   /* 0x03 */
+    U16                     Reserved2;                  /* 0x04 */
+    U8                      Reserved3;                  /* 0x06 */
+    U8                      MsgFlags;                   /* 0x07 */
+    U8                      VP_ID;                      /* 0x08 */
+    U8                      VF_ID;                      /* 0x09 */
+    U16                     Reserved4;                  /* 0x0A */
+    U16                     Reserved5;                  /* 0x0C */
+    U16                     IOCStatus;                  /* 0x0E */
+    U32                     IOCLogInfo;                 /* 0x10 */
+} MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY,
+  Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t;
+
+
 #endif
 
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 0ec1ed3..57bcd5c 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -95,6 +95,10 @@
 MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault "
     "and halt firmware - (default=0)");
 
+static int disable_discovery = -1;
+module_param(disable_discovery, int, 0);
+MODULE_PARM_DESC(disable_discovery, " disable discovery ");
+
 /**
  * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
  *
@@ -1238,7 +1242,7 @@
 	u64 pio_chip = 0;
 	u64 chip_phys = 0;
 
-	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n",
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n",
 	    ioc->name, __func__));
 
 	ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
@@ -1307,6 +1311,9 @@
 	printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n",
 	    ioc->name, (unsigned long long)pio_chip, pio_sz);
 
+	/* Save PCI configuration state for recovery from PCI AER/EEH errors */
+	pci_save_state(pdev);
+
 	return 0;
 
  out_fail:
@@ -1861,7 +1868,7 @@
 static void
 _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
 {
-	dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	if (ioc->request) {
@@ -1947,7 +1954,7 @@
 	u32 retry_sz;
 	u16 max_request_credit;
 
-	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	retry_sz = 0;
@@ -2374,7 +2381,7 @@
 	do {
 		int_status = readl(&ioc->chip->HostInterruptStatus);
 		if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
-			dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+			dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 			    "successfull count(%d), timeout(%d)\n", ioc->name,
 			    __func__, count, timeout));
 			return 0;
@@ -2415,7 +2422,7 @@
 	do {
 		int_status = readl(&ioc->chip->HostInterruptStatus);
 		if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
-			dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+			dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 			    "successfull count(%d), timeout(%d)\n", ioc->name,
 			    __func__, count, timeout));
 			return 0;
@@ -2463,7 +2470,7 @@
 	do {
 		doorbell_reg = readl(&ioc->chip->Doorbell);
 		if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
-			dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+			dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 			    "successfull count(%d), timeout(%d)\n", ioc->name,
 			    __func__, count, timeout));
 			return 0;
@@ -2637,9 +2644,9 @@
 
 	if (ioc->logging_level & MPT_DEBUG_INIT) {
 		mfp = (u32 *)reply;
-		printk(KERN_DEBUG "\toffset:data\n");
+		printk(KERN_INFO "\toffset:data\n");
 		for (i = 0; i < reply_bytes/4; i++)
-			printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4,
+			printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
 			    le32_to_cpu(mfp[i]));
 	}
 	return 0;
@@ -2672,7 +2679,7 @@
 	void *request;
 	u16 wait_state_count;
 
-	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	mutex_lock(&ioc->base_cmds.mutex);
@@ -2777,7 +2784,7 @@
 	void *request;
 	u16 wait_state_count;
 
-	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	mutex_lock(&ioc->base_cmds.mutex);
@@ -2865,7 +2872,7 @@
 	Mpi2PortFactsReply_t mpi_reply, *pfacts;
 	int mpi_reply_sz, mpi_request_sz, r;
 
-	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	mpi_reply_sz = sizeof(Mpi2PortFactsReply_t);
@@ -2907,7 +2914,7 @@
 	Mpi2IOCFactsReply_t mpi_reply, *facts;
 	int mpi_reply_sz, mpi_request_sz, r;
 
-	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
@@ -2979,7 +2986,7 @@
 	struct timeval current_time;
 	u16 ioc_status;
 
-	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t));
@@ -3040,9 +3047,9 @@
 		int i;
 
 		mfp = (u32 *)&mpi_request;
-		printk(KERN_DEBUG "\toffset:data\n");
+		printk(KERN_INFO "\toffset:data\n");
 		for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++)
-			printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4,
+			printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
 			    le32_to_cpu(mfp[i]));
 	}
 
@@ -3121,7 +3128,7 @@
 			r = -ETIME;
 		goto out;
 	} else
-		dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n",
+		dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n",
 		    ioc->name, __func__));
 
 	ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_OPERATIONAL,
@@ -3181,7 +3188,7 @@
 	int r = 0;
 	int i;
 
-	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
@@ -3219,7 +3226,7 @@
 		else
 			r = -ETIME;
 	} else
-		dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n",
+		dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n",
 		    ioc->name, __func__));
 	ioc->base_cmds.status = MPT2_CMD_NOT_USED;
 	return r;
@@ -3281,7 +3288,7 @@
 
 	_base_save_msix_table(ioc);
 
-	drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "clear interrupts\n",
+	drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n",
 	    ioc->name));
 
 	count = 0;
@@ -3289,7 +3296,7 @@
 		/* Write magic sequence to WriteSequence register
 		 * Loop until in diagnostic mode
 		 */
-		drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "write magic "
+		drsprintk(ioc, printk(MPT2SAS_INFO_FMT "write magic "
 		    "sequence\n", ioc->name));
 		writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
 		writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence);
@@ -3309,7 +3316,7 @@
 			goto out;
 
 		host_diagnostic = readl(&ioc->chip->HostDiagnostic);
-		drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "wrote magic "
+		drsprintk(ioc, printk(MPT2SAS_INFO_FMT "wrote magic "
 		    "sequence: count(%d), host_diagnostic(0x%08x)\n",
 		    ioc->name, count, host_diagnostic));
 
@@ -3317,7 +3324,7 @@
 
 	hcb_size = readl(&ioc->chip->HCBSize);
 
-	drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "diag reset: issued\n",
+	drsprintk(ioc, printk(MPT2SAS_INFO_FMT "diag reset: issued\n",
 	    ioc->name));
 	writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,
 	     &ioc->chip->HostDiagnostic);
@@ -3344,29 +3351,29 @@
 
 	if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
 
-		drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter "
+		drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter "
 		    "assuming the HCB Address points to good F/W\n",
 		    ioc->name));
 		host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
 		host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
 		writel(host_diagnostic, &ioc->chip->HostDiagnostic);
 
-		drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+		drsprintk(ioc, printk(MPT2SAS_INFO_FMT
 		    "re-enable the HCDW\n", ioc->name));
 		writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE,
 		    &ioc->chip->HCBSize);
 	}
 
-	drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter\n",
+	drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter\n",
 	    ioc->name));
 	writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET,
 	    &ioc->chip->HostDiagnostic);
 
-	drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "disable writes to the "
+	drsprintk(ioc, printk(MPT2SAS_INFO_FMT "disable writes to the "
 	    "diagnostic register\n", ioc->name));
 	writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
 
-	drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "Wait for FW to go to the "
+	drsprintk(ioc, printk(MPT2SAS_INFO_FMT "Wait for FW to go to the "
 	    "READY state\n", ioc->name));
 	ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20,
 	    sleep_flag);
@@ -3398,19 +3405,23 @@
     enum reset_type type)
 {
 	u32 ioc_state;
+	int rc;
 
-	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
+	if (ioc->pci_error_recovery)
+		return 0;
+
 	ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
-	dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: ioc_state(0x%08x)\n",
+	dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n",
 	    ioc->name, __func__, ioc_state));
 
 	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY)
 		return 0;
 
 	if (ioc_state & MPI2_DOORBELL_USED) {
-		dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
+		dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "
 		    "active!\n", ioc->name));
 		goto issue_diag_reset;
 	}
@@ -3426,11 +3437,15 @@
 
 	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL)
 		if (!(_base_send_ioc_reset(ioc,
-		    MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP)))
+		    MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) {
+			ioc->ioc_reset_count++;
 			return 0;
+	}
 
  issue_diag_reset:
-	return _base_diag_reset(ioc, CAN_SLEEP);
+	rc = _base_diag_reset(ioc, CAN_SLEEP);
+	ioc->ioc_reset_count++;
+	return rc;
 }
 
 /**
@@ -3449,7 +3464,7 @@
 	u16 smid;
 	struct _tr_list *delayed_tr, *delayed_tr_next;
 
-	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	/* clean the delayed target reset list */
@@ -3459,6 +3474,12 @@
 		kfree(delayed_tr);
 	}
 
+	list_for_each_entry_safe(delayed_tr, delayed_tr_next,
+	    &ioc->delayed_tr_volume_list, list) {
+		list_del(&delayed_tr->list);
+		kfree(delayed_tr);
+	}
+
 	/* initialize the scsi lookup free list */
 	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
 	INIT_LIST_HEAD(&ioc->free_list);
@@ -3520,6 +3541,13 @@
 	if (sleep_flag == CAN_SLEEP)
 		_base_static_config_pages(ioc);
 
+	if (ioc->wait_for_port_enable_to_complete) {
+		if (diag_buffer_enable != 0)
+			mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
+		if (disable_discovery > 0)
+			return r;
+	}
+
 	r = _base_send_port_enable(ioc, sleep_flag);
 	if (r)
 		return r;
@@ -3538,7 +3566,7 @@
 {
 	struct pci_dev *pdev = ioc->pdev;
 
-	dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	_base_mask_interrupts(ioc);
@@ -3571,7 +3599,7 @@
 {
 	int r, i;
 
-	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	r = mpt2sas_base_map_resources(ioc);
@@ -3606,6 +3634,17 @@
 
 	init_waitqueue_head(&ioc->reset_wq);
 
+	/* allocate memory pd handle bitmask list */
+	ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8);
+	if (ioc->facts.MaxDevHandle % 8)
+		ioc->pd_handles_sz++;
+	ioc->pd_handles = kzalloc(ioc->pd_handles_sz,
+	    GFP_KERNEL);
+	if (!ioc->pd_handles) {
+		r = -ENOMEM;
+		goto out_free_resources;
+	}
+
 	ioc->fwfault_debug = mpt2sas_fwfault_debug;
 
 	/* base internal command bits */
@@ -3635,11 +3674,20 @@
 
 	/* ctl module internal command bits */
 	ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
+	ioc->ctl_cmds.sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
 	ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
 	mutex_init(&ioc->ctl_cmds.mutex);
 
 	if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply ||
 	    !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply ||
+	    !ioc->config_cmds.reply || !ioc->ctl_cmds.reply ||
+	    !ioc->ctl_cmds.sense) {
+		r = -ENOMEM;
+		goto out_free_resources;
+	}
+
+	if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply ||
+	    !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply ||
 	    !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) {
 		r = -ENOMEM;
 		goto out_free_resources;
@@ -3667,8 +3715,6 @@
 		goto out_free_resources;
 
 	mpt2sas_base_start_watchdog(ioc);
-	if (diag_buffer_enable != 0)
-		mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
 	return 0;
 
  out_free_resources:
@@ -3677,12 +3723,14 @@
 	mpt2sas_base_free_resources(ioc);
 	_base_release_memory_pools(ioc);
 	pci_set_drvdata(ioc->pdev, NULL);
+	kfree(ioc->pd_handles);
 	kfree(ioc->tm_cmds.reply);
 	kfree(ioc->transport_cmds.reply);
 	kfree(ioc->scsih_cmds.reply);
 	kfree(ioc->config_cmds.reply);
 	kfree(ioc->base_cmds.reply);
 	kfree(ioc->ctl_cmds.reply);
+	kfree(ioc->ctl_cmds.sense);
 	kfree(ioc->pfacts);
 	ioc->ctl_cmds.reply = NULL;
 	ioc->base_cmds.reply = NULL;
@@ -3705,15 +3753,17 @@
 mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
 {
 
-	dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	mpt2sas_base_stop_watchdog(ioc);
 	mpt2sas_base_free_resources(ioc);
 	_base_release_memory_pools(ioc);
 	pci_set_drvdata(ioc->pdev, NULL);
+	kfree(ioc->pd_handles);
 	kfree(ioc->pfacts);
 	kfree(ioc->ctl_cmds.reply);
+	kfree(ioc->ctl_cmds.sense);
 	kfree(ioc->base_cmds.reply);
 	kfree(ioc->tm_cmds.reply);
 	kfree(ioc->transport_cmds.reply);
@@ -3738,11 +3788,11 @@
 {
 	switch (reset_phase) {
 	case MPT2_IOC_PRE_RESET:
-		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 		    "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
 		break;
 	case MPT2_IOC_AFTER_RESET:
-		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 		    "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
 		if (ioc->transport_cmds.status & MPT2_CMD_PENDING) {
 			ioc->transport_cmds.status |= MPT2_CMD_RESET;
@@ -3762,7 +3812,7 @@
 		}
 		break;
 	case MPT2_IOC_DONE_RESET:
-		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 		    "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
 		break;
 	}
@@ -3804,7 +3854,7 @@
 		return;
 
 	/* wait for pending commands to complete */
-	wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 3 * HZ);
+	wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ);
 }
 
 /**
@@ -3822,19 +3872,37 @@
 	int r;
 	unsigned long flags;
 
-	dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+	dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
 	    __func__));
 
+	if (ioc->pci_error_recovery) {
+		printk(MPT2SAS_ERR_FMT "%s: pci error recovery reset\n",
+		    ioc->name, __func__);
+		r = 0;
+		goto out;
+	}
+
 	if (mpt2sas_fwfault_debug)
 		mpt2sas_halt_firmware(ioc);
 
-	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
-	if (ioc->shost_recovery) {
-		spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
-		printk(MPT2SAS_ERR_FMT "%s: busy\n",
-		    ioc->name, __func__);
-		return -EBUSY;
+	/* TODO - What we really should be doing is pulling
+	 * out all the code associated with NO_SLEEP; its never used.
+	 * That is legacy code from mpt fusion driver, ported over.
+	 * I will leave this BUG_ON here for now till its been resolved.
+	 */
+	BUG_ON(sleep_flag == NO_SLEEP);
+
+	/* wait for an active reset in progress to complete */
+	if (!mutex_trylock(&ioc->reset_in_progress_mutex)) {
+		do {
+			ssleep(1);
+		} while (ioc->shost_recovery == 1);
+		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name,
+		    __func__));
+		return ioc->ioc_reset_in_progress_status;
 	}
+
+	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
 	ioc->shost_recovery = 1;
 	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
 
@@ -3849,13 +3917,17 @@
 	if (!r)
 		_base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
  out:
-	dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: %s\n",
+	dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %s\n",
 	    ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED")));
 
 	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+	ioc->ioc_reset_in_progress_status = r;
 	ioc->shost_recovery = 0;
 	complete(&ioc->shost_recovery_done);
 	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+	mutex_unlock(&ioc->reset_in_progress_mutex);
 
+	dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name,
+	    __func__));
 	return r;
 }
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 41c29a8..0b15a8b 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -69,11 +69,11 @@
 #define MPT2SAS_DRIVER_NAME		"mpt2sas"
 #define MPT2SAS_AUTHOR	"LSI Corporation <DL-MPTFusionLinux@lsi.com>"
 #define MPT2SAS_DESCRIPTION	"LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION		"05.100.00.02"
-#define MPT2SAS_MAJOR_VERSION		05
+#define MPT2SAS_DRIVER_VERSION		"06.100.00.00"
+#define MPT2SAS_MAJOR_VERSION		06
 #define MPT2SAS_MINOR_VERSION		100
 #define MPT2SAS_BUILD_VERSION		00
-#define MPT2SAS_RELEASE_VERSION		02
+#define MPT2SAS_RELEASE_VERSION		00
 
 /*
  * Set MPT2SAS_SG_DEPTH value based on user input.
@@ -124,7 +124,6 @@
  * logging format
  */
 #define MPT2SAS_FMT			"%s: "
-#define MPT2SAS_DEBUG_FMT		KERN_DEBUG MPT2SAS_FMT
 #define MPT2SAS_INFO_FMT		KERN_INFO MPT2SAS_FMT
 #define MPT2SAS_NOTE_FMT		KERN_NOTICE MPT2SAS_FMT
 #define MPT2SAS_WARN_FMT		KERN_WARNING MPT2SAS_FMT
@@ -248,6 +247,7 @@
  * @mutex: mutex
  * @done: completion
  * @reply: reply message pointer
+ * @sense: sense data
  * @status: MPT2_CMD_XXX status
  * @smid: system message id
  */
@@ -255,6 +255,7 @@
 	struct mutex mutex;
 	struct completion done;
 	void 	*reply;
+	void	*sense;
 	u16	status;
 	u16	smid;
 };
@@ -276,7 +277,7 @@
  * @id: target id
  * @channel: target channel
  * @slot: number number
- * @hidden_raid_component: set to 1 when this is a raid member
+ * @phy: phy identifier provided in sas device page 0
  * @responding: used in _scsih_sas_device_mark_responding
  */
 struct _sas_device {
@@ -294,7 +295,7 @@
 	int	id;
 	int	channel;
 	u16	slot;
-	u8	hidden_raid_component;
+	u8	phy;
 	u8	responding;
 };
 
@@ -476,6 +477,7 @@
  * @ioc_link_reset_in_progress: phy/hard reset in progress
  * @ignore_loginfos: ignore loginfos during task management
  * @remove_host: flag for when driver unloads, to avoid sending dev resets
+ * @pci_error_recovery: flag to prevent ioc access until slot reset completes
  * @wait_for_port_enable_to_complete:
  * @msix_enable: flag indicating msix is enabled
  * @msix_vector_count: number msix vectors
@@ -488,6 +490,8 @@
  * @ctl_cb_idx: clt internal commands
  * @base_cb_idx: base internal commands
  * @config_cb_idx: base internal commands
+ * @tm_tr_cb_idx : device removal target reset handshake
+ * @tm_tr_volume_cb_idx : volume removal target reset
  * @base_cmds:
  * @transport_cmds:
  * @scsih_cmds:
@@ -516,6 +520,9 @@
  * @sas_device_lock:
  * @io_missing_delay: time for IO completed by fw when PDR enabled
  * @device_missing_delay: time for device missing by fw when PDR enabled
+ * @sas_id : used for setting volume target IDs
+ * @pd_handles : bitmask for PD handles
+ * @pd_handles_sz : size of pd_handle bitmask
  * @config_page_sz: config page size
  * @config_page: reserve memory for config page payload
  * @config_page_dma:
@@ -568,6 +575,8 @@
  * @reply_post_free_dma:
  * @reply_post_free_dma_pool:
  * @reply_post_host_index: head index in the pool where FW completes IO
+ * @delayed_tr_list: target reset link list
+ * @delayed_tr_volume_list: volume target reset link list
  */
 struct MPT2SAS_ADAPTER {
 	struct list_head list;
@@ -600,17 +609,23 @@
 	int		aen_event_read_flag;
 	u8		broadcast_aen_busy;
 	u8		shost_recovery;
+
+	struct mutex	reset_in_progress_mutex;
 	struct completion	shost_recovery_done;
 	spinlock_t 	ioc_reset_in_progress_lock;
 	u8		ioc_link_reset_in_progress;
+	int		ioc_reset_in_progress_status;
+
 	u8		ignore_loginfos;
 	u8		remove_host;
+	u8		pci_error_recovery;
 	u8		wait_for_port_enable_to_complete;
 
 	u8		msix_enable;
 	u16		msix_vector_count;
 	u32		*msix_table;
 	u32		*msix_table_backup;
+	u32		ioc_reset_count;
 
 	/* internal commands, callback index */
 	u8		scsi_io_cb_idx;
@@ -621,6 +636,7 @@
 	u8		base_cb_idx;
 	u8		config_cb_idx;
 	u8		tm_tr_cb_idx;
+	u8		tm_tr_volume_cb_idx;
 	u8		tm_sas_control_cb_idx;
 	struct _internal_cmd base_cmds;
 	struct _internal_cmd transport_cmds;
@@ -664,6 +680,9 @@
 	u16		device_missing_delay;
 	int		sas_id;
 
+	void		*pd_handles;
+	u16		pd_handles_sz;
+
 	/* config page */
 	u16		config_page_sz;
 	void 		*config_page;
@@ -735,6 +754,7 @@
 	u32		reply_post_host_index;
 
 	struct list_head delayed_tr_list;
+	struct list_head delayed_tr_volume_list;
 
 	/* diag buffer support */
 	u8		*diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];
@@ -745,6 +765,8 @@
 	Mpi2ManufacturingPage10_t manu_pg10;
 	u32		product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23];
 	u32		diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];
+	u32		ring_buffer_offset;
+	u32		ring_buffer_sz;
 };
 
 typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c
index c654429..6afd67b 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_config.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_config.c
@@ -159,7 +159,7 @@
 	if (!desc)
 		return;
 
-	printk(MPT2SAS_DEBUG_FMT "%s: %s(%d), action(%d), form(0x%08x), "
+	printk(MPT2SAS_INFO_FMT "%s: %s(%d), action(%d), form(0x%08x), "
 	    "smid(%d)\n", ioc->name, calling_function_name, desc,
 	    mpi_request->Header.PageNumber, mpi_request->Action,
 	    le32_to_cpu(mpi_request->PageAddress), smid);
@@ -168,7 +168,7 @@
 		return;
 
 	if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
-		printk(MPT2SAS_DEBUG_FMT
+		printk(MPT2SAS_INFO_FMT
 		    "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
 		    ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
 		    le32_to_cpu(mpi_reply->IOCLogInfo));
@@ -401,7 +401,7 @@
 		if (ioc->config_cmds.smid == smid)
 			mpt2sas_base_free_smid(ioc, smid);
 		if ((ioc->shost_recovery) || (ioc->config_cmds.status &
-		    MPT2_CMD_RESET))
+		    MPT2_CMD_RESET) || ioc->pci_error_recovery)
 			goto retry_config;
 		issue_host_reset = 1;
 		r = -EFAULT;
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index d88e975..b774973 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -80,6 +80,32 @@
 	BLOCKING,
 };
 
+/**
+ * _ctl_sas_device_find_by_handle - sas device search
+ * @ioc: per adapter object
+ * @handle: sas device handle (assigned by firmware)
+ * Context: Calling function should acquire ioc->sas_device_lock
+ *
+ * This searches for sas_device based on sas_address, then return sas_device
+ * object.
+ */
+static struct _sas_device *
+_ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+	struct _sas_device *sas_device, *r;
+
+	r = NULL;
+	list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
+		if (sas_device->handle != handle)
+			continue;
+		r = sas_device;
+		goto out;
+	}
+
+ out:
+	return r;
+}
+
 #ifdef CONFIG_SCSI_MPT2SAS_LOGGING
 /**
  * _ctl_display_some_debug - debug routine
@@ -188,14 +214,14 @@
 	if (!desc)
 		return;
 
-	printk(MPT2SAS_DEBUG_FMT "%s: %s, smid(%d)\n",
+	printk(MPT2SAS_INFO_FMT "%s: %s, smid(%d)\n",
 	    ioc->name, calling_function_name, desc, smid);
 
 	if (!mpi_reply)
 		return;
 
 	if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
-		printk(MPT2SAS_DEBUG_FMT
+		printk(MPT2SAS_INFO_FMT
 		    "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
 		    ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
 		    le32_to_cpu(mpi_reply->IOCLogInfo));
@@ -205,8 +231,24 @@
 	    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
 		Mpi2SCSIIOReply_t *scsi_reply =
 		    (Mpi2SCSIIOReply_t *)mpi_reply;
+		struct _sas_device *sas_device = NULL;
+		unsigned long flags;
+
+		spin_lock_irqsave(&ioc->sas_device_lock, flags);
+		sas_device = _ctl_sas_device_find_by_handle(ioc,
+		    le16_to_cpu(scsi_reply->DevHandle));
+		if (sas_device) {
+			printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), "
+			    "phy(%d)\n", ioc->name, (unsigned long long)
+			    sas_device->sas_address, sas_device->phy);
+			printk(MPT2SAS_WARN_FMT
+			    "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
+			    ioc->name, sas_device->enclosure_logical_id,
+			    sas_device->slot);
+		}
+		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 		if (scsi_reply->SCSIState || scsi_reply->SCSIStatus)
-			printk(MPT2SAS_DEBUG_FMT
+			printk(MPT2SAS_INFO_FMT
 			    "\tscsi_state(0x%02x), scsi_status"
 			    "(0x%02x)\n", ioc->name,
 			    scsi_reply->SCSIState,
@@ -233,6 +275,9 @@
 	u32 reply)
 {
 	MPI2DefaultReply_t *mpi_reply;
+	Mpi2SCSIIOReply_t *scsiio_reply;
+	const void *sense_data;
+	u32 sz;
 
 	if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED)
 		return 1;
@@ -243,6 +288,20 @@
 	if (mpi_reply) {
 		memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
 		ioc->ctl_cmds.status |= MPT2_CMD_REPLY_VALID;
+		/* get sense data */
+		if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
+		    mpi_reply->Function ==
+		    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
+			scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply;
+			if (scsiio_reply->SCSIState &
+			    MPI2_SCSI_STATE_AUTOSENSE_VALID) {
+				sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
+				    le32_to_cpu(scsiio_reply->SenseCount));
+				sense_data = mpt2sas_base_get_sense_buffer(ioc,
+				    smid);
+				memcpy(ioc->ctl_cmds.sense, sense_data, sz);
+			}
+		}
 	}
 #ifdef CONFIG_SCSI_MPT2SAS_LOGGING
 	_ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply);
@@ -392,7 +451,7 @@
 
 	switch (reset_phase) {
 	case MPT2_IOC_PRE_RESET:
-		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 		    "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
 		for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
 			if (!(ioc->diag_buffer_status[i] &
@@ -405,7 +464,7 @@
 		}
 		break;
 	case MPT2_IOC_AFTER_RESET:
-		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 		    "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
 		if (ioc->ctl_cmds.status & MPT2_CMD_PENDING) {
 			ioc->ctl_cmds.status |= MPT2_CMD_RESET;
@@ -414,7 +473,7 @@
 		}
 		break;
 	case MPT2_IOC_DONE_RESET:
-		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 		    "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
 
 		for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
@@ -531,7 +590,7 @@
 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
 
 	if (!found) {
-		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 		    "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name,
 		    desc, le16_to_cpu(tm_request->DevHandle), lun));
 		tm_reply = ioc->ctl_cmds.reply;
@@ -549,7 +608,7 @@
 		return 1;
 	}
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 	    "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name,
 	    desc, le16_to_cpu(tm_request->DevHandle), lun,
 	     le16_to_cpu(tm_request->TaskMID)));
@@ -567,7 +626,7 @@
 _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
     struct mpt2_ioctl_command karg, void __user *mf, enum block_state state)
 {
-	MPI2RequestHeader_t *mpi_request;
+	MPI2RequestHeader_t *mpi_request = NULL, *request;
 	MPI2DefaultReply_t *mpi_reply;
 	u32 ioc_state;
 	u16 ioc_status;
@@ -576,7 +635,6 @@
 	u8 issue_reset;
 	u32 sz;
 	void *psge;
-	void *priv_sense = NULL;
 	void *data_out = NULL;
 	dma_addr_t data_out_dma;
 	size_t data_out_sz = 0;
@@ -621,31 +679,50 @@
 		printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
 		    ioc->name, __func__);
 
-	smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL);
-	if (!smid) {
-		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
-		    ioc->name, __func__);
-		ret = -EAGAIN;
+	mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL);
+	if (!mpi_request) {
+		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a memory for "
+		    "mpi_request\n", ioc->name, __func__);
+		ret = -ENOMEM;
 		goto out;
 	}
 
-	ret = 0;
-	ioc->ctl_cmds.status = MPT2_CMD_PENDING;
-	memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
-	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
-	ioc->ctl_cmds.smid = smid;
-	data_out_sz = karg.data_out_size;
-	data_in_sz = karg.data_in_size;
-
 	/* copy in request message frame from user */
 	if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) {
 		printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__,
 		    __func__);
 		ret = -EFAULT;
-		mpt2sas_base_free_smid(ioc, smid);
 		goto out;
 	}
 
+	if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
+		smid = mpt2sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx);
+		if (!smid) {
+			printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+			    ioc->name, __func__);
+			ret = -EAGAIN;
+			goto out;
+		}
+	} else {
+
+		smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL);
+		if (!smid) {
+			printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+			    ioc->name, __func__);
+			ret = -EAGAIN;
+			goto out;
+		}
+	}
+
+	ret = 0;
+	ioc->ctl_cmds.status = MPT2_CMD_PENDING;
+	memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
+	request = mpt2sas_base_get_msg_frame(ioc, smid);
+	memcpy(request, mpi_request, karg.data_sge_offset*4);
+	ioc->ctl_cmds.smid = smid;
+	data_out_sz = karg.data_out_size;
+	data_in_sz = karg.data_in_size;
+
 	if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
 	    mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
 		if (!le16_to_cpu(mpi_request->FunctionDependent1) ||
@@ -691,7 +768,7 @@
 	}
 
 	/* add scatter gather elements */
-	psge = (void *)mpi_request + (karg.data_sge_offset*4);
+	psge = (void *)request + (karg.data_sge_offset*4);
 
 	if (!data_out_sz && !data_in_sz) {
 		mpt2sas_base_build_zero_len_sge(ioc, psge);
@@ -739,11 +816,11 @@
 	case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
 	{
 		Mpi2SCSIIORequest_t *scsiio_request =
-		    (Mpi2SCSIIORequest_t *)mpi_request;
+		    (Mpi2SCSIIORequest_t *)request;
+		scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
 		scsiio_request->SenseBufferLowAddress =
 		    mpt2sas_base_get_sense_buffer_dma(ioc, smid);
-		priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);
-		memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE);
+		memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE);
 		if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)
 			mpt2sas_base_put_smid_scsi_io(ioc, smid,
 			    le16_to_cpu(mpi_request->FunctionDependent1));
@@ -754,9 +831,9 @@
 	case MPI2_FUNCTION_SCSI_TASK_MGMT:
 	{
 		Mpi2SCSITaskManagementRequest_t *tm_request =
-		    (Mpi2SCSITaskManagementRequest_t *)mpi_request;
+		    (Mpi2SCSITaskManagementRequest_t *)request;
 
-		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: "
+		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "TASK_MGMT: "
 		    "handle(0x%04x), task_type(0x%02x)\n", ioc->name,
 		    le16_to_cpu(tm_request->DevHandle), tm_request->TaskType));
 
@@ -851,7 +928,7 @@
 		Mpi2SCSITaskManagementReply_t *tm_reply =
 		    (Mpi2SCSITaskManagementReply_t *)mpi_reply;
 
-		printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: "
+		printk(MPT2SAS_INFO_FMT "TASK_MGMT: "
 		    "IOCStatus(0x%04x), IOCLogInfo(0x%08x), "
 		    "TerminationCount(0x%08x)\n", ioc->name,
 		    le16_to_cpu(tm_reply->IOCStatus),
@@ -887,7 +964,8 @@
 	    MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function ==
 	    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
 		sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE);
-		if (copy_to_user(karg.sense_data_ptr, priv_sense, sz)) {
+		if (copy_to_user(karg.sense_data_ptr,
+			ioc->ctl_cmds.sense, sz)) {
 			printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
 			    __LINE__, __func__);
 			ret = -ENODATA;
@@ -926,6 +1004,7 @@
 		pci_free_consistent(ioc->pdev, data_out_sz, data_out,
 		    data_out_dma);
 
+	kfree(mpi_request);
 	ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
 	mutex_unlock(&ioc->ctl_cmds.mutex);
 	return ret;
@@ -950,7 +1029,7 @@
 	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
 		return -ENODEV;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
 	    __func__));
 
 	memset(&karg, 0 , sizeof(karg));
@@ -998,7 +1077,7 @@
 	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
 		return -ENODEV;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
 	    __func__));
 
 	karg.event_entries = MPT2SAS_CTL_EVENT_LOG_SIZE;
@@ -1031,7 +1110,7 @@
 	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
 		return -ENODEV;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
 	    __func__));
 
 	if (ioc->event_log)
@@ -1073,7 +1152,7 @@
 	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
 		return -ENODEV;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
 	    __func__));
 
 	number_bytes = karg.hdr.max_data_size -
@@ -1118,7 +1197,7 @@
 	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
 		return -ENODEV;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
 	    __func__));
 
 	retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
@@ -1219,7 +1298,7 @@
 	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
 		return -ENODEV;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	rc = _ctl_btdh_search_sas_device(ioc, &karg);
@@ -1288,7 +1367,7 @@
 	u16 ioc_status;
 	u8 issue_reset = 0;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
@@ -1376,7 +1455,7 @@
 	mpi_request->VF_ID = 0; /* TODO */
 	mpi_request->VP_ID = 0;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), "
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(0x%p), "
 	    "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data,
 	    (unsigned long long)request_data_dma,
 	    le32_to_cpu(mpi_request->BufferLength)));
@@ -1414,10 +1493,10 @@
 	if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
 		ioc->diag_buffer_status[buffer_type] |=
 			MPT2_DIAG_BUFFER_IS_REGISTERED;
-		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
+		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
 		    ioc->name, __func__));
 	} else {
-		printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
+		printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "
 		    "log_info(0x%08x)\n", ioc->name, __func__,
 		    ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
 		rc = -EFAULT;
@@ -1541,7 +1620,7 @@
 	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
 		return -ENODEV;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	buffer_type = karg.unique_id & 0x000000ff;
@@ -1611,7 +1690,7 @@
 	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
 		return -ENODEV;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	karg.application_flags = 0;
@@ -1689,7 +1768,7 @@
 	int rc;
 	unsigned long timeleft;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	rc = 0;
@@ -1697,7 +1776,7 @@
 
 	ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
 	if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
-		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 		    "skipping due to FAULT state\n", ioc->name,
 		    __func__));
 		rc = -EAGAIN;
@@ -1759,10 +1838,10 @@
 	if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
 		ioc->diag_buffer_status[buffer_type] |=
 		    MPT2_DIAG_BUFFER_IS_RELEASED;
-		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
+		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
 		    ioc->name, __func__));
 	} else {
-		printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
+		printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "
 		    "log_info(0x%08x)\n", ioc->name, __func__,
 		    ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
 		rc = -EFAULT;
@@ -1800,7 +1879,7 @@
 	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
 		return -ENODEV;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	buffer_type = karg.unique_id & 0x000000ff;
@@ -1896,7 +1975,7 @@
 	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
 		return -ENODEV;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
 	buffer_type = karg.unique_id & 0x000000ff;
@@ -1927,7 +2006,7 @@
 	}
 
 	diag_data = (void *)(request_data + karg.starting_offset);
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(%p), "
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), "
 	    "offset(%d), sz(%d)\n", ioc->name, __func__,
 	    diag_data, karg.starting_offset, karg.bytes_to_read));
 
@@ -1942,11 +2021,11 @@
 	if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0)
 		return 0;
 
-	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: Reregister "
+	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: Reregister "
 		"buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type));
 	if ((ioc->diag_buffer_status[buffer_type] &
 	    MPT2_DIAG_BUFFER_IS_RELEASED) == 0) {
-		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 		    "buffer_type(0x%02x) is still registered\n", ioc->name,
 		     __func__, buffer_type));
 		return 0;
@@ -2020,10 +2099,10 @@
 	if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
 		ioc->diag_buffer_status[buffer_type] |=
 		    MPT2_DIAG_BUFFER_IS_REGISTERED;
-		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
+		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
 		    ioc->name, __func__));
 	} else {
-		printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
+		printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "
 		    "log_info(0x%08x)\n", ioc->name, __func__,
 		    ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
 		rc = -EFAULT;
@@ -2077,7 +2156,7 @@
 		    !ioc)
 			return -ENODEV;
 
-		if (ioc->shost_recovery)
+		if (ioc->shost_recovery || ioc->pci_error_recovery)
 			return -EAGAIN;
 
 		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) {
@@ -2140,7 +2219,7 @@
 		    !ioc)
 			return -ENODEV;
 
-		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT
 		    "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd));
 		break;
 	}
@@ -2196,7 +2275,7 @@
 	if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc)
 		return -ENODEV;
 
-	if (ioc->shost_recovery)
+	if (ioc->shost_recovery || ioc->pci_error_recovery)
 		return -EAGAIN;
 
 	memset(&karg, 0, sizeof(struct mpt2_ioctl_command));
@@ -2581,6 +2660,218 @@
 static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,
     _ctl_fwfault_debug_show, _ctl_fwfault_debug_store);
 
+
+/**
+ * _ctl_ioc_reset_count_show - ioc reset count
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * This is firmware queue depth limit
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
+    char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+	return snprintf(buf, PAGE_SIZE, "%08d\n", ioc->ioc_reset_count);
+}
+static DEVICE_ATTR(ioc_reset_count, S_IRUGO,
+    _ctl_ioc_reset_count_show, NULL);
+
+struct DIAG_BUFFER_START {
+	u32 Size;
+	u32 DiagVersion;
+	u8 BufferType;
+	u8 Reserved[3];
+	u32 Reserved1;
+	u32 Reserved2;
+	u32 Reserved3;
+};
+/**
+ * _ctl_host_trace_buffer_size_show - host buffer size (trace only)
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_host_trace_buffer_size_show(struct device *cdev,
+    struct device_attribute *attr, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+	u32 size = 0;
+	struct DIAG_BUFFER_START *request_data;
+
+	if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
+		printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
+		    "registered\n", ioc->name, __func__);
+		return 0;
+	}
+
+	if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+	    MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
+		printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
+		    "registered\n", ioc->name, __func__);
+		return 0;
+	}
+
+	request_data = (struct DIAG_BUFFER_START *)
+	    ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE];
+	if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 ||
+	    le32_to_cpu(request_data->DiagVersion) == 0x01000000) &&
+	    le32_to_cpu(request_data->Reserved3) == 0x4742444c)
+		size = le32_to_cpu(request_data->Size);
+
+	ioc->ring_buffer_sz = size;
+	return snprintf(buf, PAGE_SIZE, "%d\n", size);
+}
+static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO,
+	 _ctl_host_trace_buffer_size_show, NULL);
+
+/**
+ * _ctl_host_trace_buffer_show - firmware ring buffer (trace only)
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read/write' shost attribute.
+ *
+ * You will only be able to read 4k bytes of ring buffer at a time.
+ * In order to read beyond 4k bytes, you will have to write out the
+ * offset to the same attribute, it will move the pointer.
+ */
+static ssize_t
+_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
+     char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+	void *request_data;
+	u32 size;
+
+	if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
+		printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
+		    "registered\n", ioc->name, __func__);
+		return 0;
+	}
+
+	if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+	    MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
+		printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
+		    "registered\n", ioc->name, __func__);
+		return 0;
+	}
+
+	if (ioc->ring_buffer_offset > ioc->ring_buffer_sz)
+		return 0;
+
+	size = ioc->ring_buffer_sz - ioc->ring_buffer_offset;
+	size = (size > PAGE_SIZE) ? PAGE_SIZE : size;
+	request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset;
+	memcpy(buf, request_data, size);
+	return size;
+}
+
+static ssize_t
+_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
+    const char *buf, size_t count)
+{
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+	int val = 0;
+
+	if (sscanf(buf, "%d", &val) != 1)
+		return -EINVAL;
+
+	ioc->ring_buffer_offset = val;
+	return strlen(buf);
+}
+static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR,
+    _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store);
+
+/*****************************************/
+
+/**
+ * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only)
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read/write' shost attribute.
+ *
+ * This is a mechnism to post/release host_trace_buffers
+ */
+static ssize_t
+_ctl_host_trace_buffer_enable_show(struct device *cdev,
+    struct device_attribute *attr, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+	if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) ||
+	   ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+	    MPT2_DIAG_BUFFER_IS_REGISTERED) == 0))
+		return snprintf(buf, PAGE_SIZE, "off\n");
+	else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+	    MPT2_DIAG_BUFFER_IS_RELEASED))
+		return snprintf(buf, PAGE_SIZE, "release\n");
+	else
+		return snprintf(buf, PAGE_SIZE, "post\n");
+}
+
+static ssize_t
+_ctl_host_trace_buffer_enable_store(struct device *cdev,
+    struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+	char str[10] = "";
+	struct mpt2_diag_register diag_register;
+	u8 issue_reset = 0;
+
+	if (sscanf(buf, "%s", str) != 1)
+		return -EINVAL;
+
+	if (!strcmp(str, "post")) {
+		/* exit out if host buffers are already posted */
+		if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) &&
+		    (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+		    MPT2_DIAG_BUFFER_IS_REGISTERED) &&
+		    ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+		    MPT2_DIAG_BUFFER_IS_RELEASED) == 0))
+			goto out;
+		memset(&diag_register, 0, sizeof(struct mpt2_diag_register));
+		printk(MPT2SAS_INFO_FMT "posting host trace buffers\n",
+		    ioc->name);
+		diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
+		diag_register.requested_buffer_size = (1024 * 1024);
+		diag_register.unique_id = 0x7075900;
+		ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0;
+		_ctl_diag_register_2(ioc,  &diag_register);
+	} else if (!strcmp(str, "release")) {
+		/* exit out if host buffers are already released */
+		if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE])
+			goto out;
+		if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+		    MPT2_DIAG_BUFFER_IS_REGISTERED) == 0)
+			goto out;
+		if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+		    MPT2_DIAG_BUFFER_IS_RELEASED))
+			goto out;
+		printk(MPT2SAS_INFO_FMT "releasing host trace buffer\n",
+		    ioc->name);
+		_ctl_send_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset);
+	}
+
+ out:
+	return strlen(buf);
+}
+static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR,
+    _ctl_host_trace_buffer_enable_show, _ctl_host_trace_buffer_enable_store);
+
 struct device_attribute *mpt2sas_host_attrs[] = {
 	&dev_attr_version_fw,
 	&dev_attr_version_bios,
@@ -2597,6 +2888,10 @@
 	&dev_attr_fwfault_debug,
 	&dev_attr_fw_queue_depth,
 	&dev_attr_host_sas_address,
+	&dev_attr_ioc_reset_count,
+	&dev_attr_host_trace_buffer_size,
+	&dev_attr_host_trace_buffer,
+	&dev_attr_host_trace_buffer_enable,
 	NULL,
 };
 
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 06d645a..16e99b6 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -70,6 +70,8 @@
     struct _sas_node *sas_expander);
 static void _firmware_event_work(struct work_struct *work);
 
+static u8 _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid);
+
 /* global parameters */
 LIST_HEAD(mpt2sas_ioc_list);
 
@@ -84,6 +86,7 @@
 static int mpt_ids;
 
 static u8 tm_tr_cb_idx = -1 ;
+static u8 tm_tr_volume_cb_idx = -1 ;
 static u8 tm_sas_control_cb_idx = -1;
 
 /* command line options */
@@ -223,9 +226,12 @@
 		PCI_ANY_ID, PCI_ANY_ID },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
 		PCI_ANY_ID, PCI_ANY_ID },
-	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7,
+	/* Mustang ~ 2308 */
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1,
 		PCI_ANY_ID, PCI_ANY_ID },
-	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_8,
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
 		PCI_ANY_ID, PCI_ANY_ID },
 	{0}	/* Terminating entry */
 };
@@ -432,7 +438,7 @@
 		    (ioc->bios_pg2.ReqBootDeviceForm &
 		    MPI2_BIOSPAGE2_FORM_MASK),
 		    &ioc->bios_pg2.RequestedBootDevice)) {
-			dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+			dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
 			   "%s: req_boot_device(0x%016llx)\n",
 			    ioc->name, __func__,
 			    (unsigned long long)sas_address));
@@ -447,7 +453,7 @@
 		    (ioc->bios_pg2.ReqAltBootDeviceForm &
 		    MPI2_BIOSPAGE2_FORM_MASK),
 		    &ioc->bios_pg2.RequestedAltBootDevice)) {
-			dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+			dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
 			   "%s: req_alt_boot_device(0x%016llx)\n",
 			    ioc->name, __func__,
 			    (unsigned long long)sas_address));
@@ -462,7 +468,7 @@
 		    (ioc->bios_pg2.CurrentBootDeviceForm &
 		    MPI2_BIOSPAGE2_FORM_MASK),
 		    &ioc->bios_pg2.CurrentBootDevice)) {
-			dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+			dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
 			   "%s: current_boot_device(0x%016llx)\n",
 			    ioc->name, __func__,
 			    (unsigned long long)sas_address));
@@ -563,7 +569,7 @@
 {
 	unsigned long flags;
 
-	dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
+	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
 	    "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
 	    sas_device->handle, (unsigned long long)sas_device->sas_address));
 
@@ -590,7 +596,7 @@
 {
 	unsigned long flags;
 
-	dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
+	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
 	    "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
 	    sas_device->handle, (unsigned long long)sas_device->sas_address));
 
@@ -692,7 +698,7 @@
 {
 	unsigned long flags;
 
-	dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
+	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
 	    "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
 	    raid_device->handle, (unsigned long long)raid_device->wwid));
 
@@ -1223,7 +1229,7 @@
 		sas_device->starget = starget;
 		sas_device->id = starget->id;
 		sas_device->channel = starget->channel;
-		if (sas_device->hidden_raid_component)
+		if (test_bit(sas_device->handle, ioc->pd_handles))
 			sas_target_priv_data->flags |=
 			    MPT_TARGET_FLAGS_RAID_COMPONENT;
 	}
@@ -1746,9 +1752,10 @@
 		}
 
 		sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
-		    "sas_addr(0x%016llx), device_name(0x%016llx)\n",
+		    "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n",
 		    ds, sas_device->handle,
 		    (unsigned long long)sas_device->sas_address,
+		    sas_device->phy,
 		    (unsigned long long)sas_device->device_name);
 		sdev_printk(KERN_INFO, sdev, "%s: "
 		    "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
@@ -1990,7 +1997,8 @@
 		goto err_out;
 	}
 
-	if (ioc->shost_recovery || ioc->remove_host) {
+	if (ioc->shost_recovery || ioc->remove_host ||
+	    ioc->pci_error_recovery) {
 		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
 		    __func__, ioc->name);
 		rc = FAILED;
@@ -1999,7 +2007,7 @@
 
 	ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
 	if (ioc_state & MPI2_DOORBELL_USED) {
-		dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
+		dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "
 		    "active!\n", ioc->name));
 		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
 		    FORCE_BIG_HAMMER);
@@ -2116,8 +2124,59 @@
 }
 
 /**
+ * _scsih_tm_display_info - displays info about the device
+ * @ioc: per adapter struct
+ * @scmd: pointer to scsi command object
+ *
+ * Called by task management callback handlers.
+ */
+static void
+_scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
+{
+	struct scsi_target *starget = scmd->device->sdev_target;
+	struct MPT2SAS_TARGET *priv_target = starget->hostdata;
+	struct _sas_device *sas_device = NULL;
+	unsigned long flags;
+
+	if (!priv_target)
+		return;
+
+	scsi_print_command(scmd);
+	if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
+		starget_printk(KERN_INFO, starget, "volume handle(0x%04x), "
+		    "volume wwid(0x%016llx)\n",
+		    priv_target->handle,
+		    (unsigned long long)priv_target->sas_address);
+	} else {
+		spin_lock_irqsave(&ioc->sas_device_lock, flags);
+		sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+		    priv_target->sas_address);
+		if (sas_device) {
+			if (priv_target->flags &
+			    MPT_TARGET_FLAGS_RAID_COMPONENT) {
+				starget_printk(KERN_INFO, starget,
+				    "volume handle(0x%04x), "
+				    "volume wwid(0x%016llx)\n",
+				    sas_device->volume_handle,
+				   (unsigned long long)sas_device->volume_wwid);
+			}
+			starget_printk(KERN_INFO, starget,
+			    "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n",
+			    sas_device->handle,
+			    (unsigned long long)sas_device->sas_address,
+			    sas_device->phy);
+			starget_printk(KERN_INFO, starget,
+			    "enclosure_logical_id(0x%016llx), slot(%d)\n",
+			   (unsigned long long)sas_device->enclosure_logical_id,
+			    sas_device->slot);
+		}
+		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+	}
+}
+
+/**
  * _scsih_abort - eh threads main abort routine
- * @sdev: scsi device struct
+ * @scmd: pointer to scsi command object
  *
  * Returns SUCCESS if command aborted else FAILED
  */
@@ -2130,14 +2189,14 @@
 	u16 handle;
 	int r;
 
-	printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",
-	    ioc->name, scmd);
-	scsi_print_command(scmd);
+	sdev_printk(KERN_INFO, scmd->device, "attempting task abort! "
+	    "scmd(%p)\n", scmd);
+	_scsih_tm_display_info(ioc, scmd);
 
 	sas_device_priv_data = scmd->device->hostdata;
 	if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
-		printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
-		    ioc->name, scmd);
+		sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
+		    "scmd(%p)\n", scmd);
 		scmd->result = DID_NO_CONNECT << 16;
 		scmd->scsi_done(scmd);
 		r = SUCCESS;
@@ -2169,14 +2228,14 @@
 	    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd);
 
  out:
-	printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n",
-	    ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+	sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
+	    ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
 	return r;
 }
 
 /**
  * _scsih_dev_reset - eh threads main device reset routine
- * @sdev: scsi device struct
+ * @scmd: pointer to scsi command object
  *
  * Returns SUCCESS if command aborted else FAILED
  */
@@ -2190,14 +2249,16 @@
 	u16	handle;
 	int r;
 
-	printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n",
-	    ioc->name, scmd);
-	scsi_print_command(scmd);
+	struct scsi_target *starget = scmd->device->sdev_target;
+
+	starget_printk(KERN_INFO, starget, "attempting target reset! "
+	    "scmd(%p)\n", scmd);
+	_scsih_tm_display_info(ioc, scmd);
 
 	sas_device_priv_data = scmd->device->hostdata;
 	if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
-		printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
-		    ioc->name, scmd);
+		starget_printk(KERN_INFO, starget, "target been deleted! "
+		    "scmd(%p)\n", scmd);
 		scmd->result = DID_NO_CONNECT << 16;
 		scmd->scsi_done(scmd);
 		r = SUCCESS;
@@ -2228,14 +2289,14 @@
 	    MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd);
 
  out:
-	printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
-	    ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+	sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
+	    ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
 	return r;
 }
 
 /**
  * _scsih_target_reset - eh threads main target reset routine
- * @sdev: scsi device struct
+ * @scmd: pointer to scsi command object
  *
  * Returns SUCCESS if command aborted else FAILED
  */
@@ -2248,15 +2309,16 @@
 	unsigned long flags;
 	u16	handle;
 	int r;
+	struct scsi_target *starget = scmd->device->sdev_target;
 
-	printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n",
-	    ioc->name, scmd);
-	scsi_print_command(scmd);
+	starget_printk(KERN_INFO, starget, "attempting target reset! "
+	    "scmd(%p)\n", scmd);
+	_scsih_tm_display_info(ioc, scmd);
 
 	sas_device_priv_data = scmd->device->hostdata;
 	if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
-		printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n",
-		    ioc->name, scmd);
+		starget_printk(KERN_INFO, starget, "target been deleted! "
+		    "scmd(%p)\n", scmd);
 		scmd->result = DID_NO_CONNECT << 16;
 		scmd->scsi_done(scmd);
 		r = SUCCESS;
@@ -2287,14 +2349,14 @@
 	    30, scmd);
 
  out:
-	printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n",
-	    ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+	starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
+	    ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
 	return r;
 }
 
 /**
  * _scsih_host_reset - eh threads main host reset routine
- * @sdev: scsi device struct
+ * @scmd: pointer to scsi command object
  *
  * Returns SUCCESS if command aborted else FAILED
  */
@@ -2579,20 +2641,31 @@
 	Mpi2SCSITaskManagementRequest_t *mpi_request;
 	u16 smid;
 	struct _sas_device *sas_device;
+	struct MPT2SAS_TARGET *sas_target_priv_data;
 	unsigned long flags;
 	struct _tr_list *delayed_tr;
 
-	if (ioc->shost_recovery || ioc->remove_host) {
+	if (ioc->shost_recovery || ioc->remove_host ||
+	    ioc->pci_error_recovery) {
 		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
 		   "progress!\n", __func__, ioc->name));
 		return;
 	}
 
+	/* if PD, then return */
+	if (test_bit(handle, ioc->pd_handles))
+		return;
+
 	spin_lock_irqsave(&ioc->sas_device_lock, flags);
 	sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
-	if (sas_device && sas_device->hidden_raid_component) {
-		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-		return;
+	if (sas_device && sas_device->starget &&
+	     sas_device->starget->hostdata) {
+		sas_target_priv_data = sas_device->starget->hostdata;
+		sas_target_priv_data->deleted = 1;
+		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "setting delete flag: handle(0x%04x), "
+		    "sas_addr(0x%016llx)\n", ioc->name, handle,
+		    (unsigned long long) sas_device->sas_address));
 	}
 	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 
@@ -2655,6 +2728,101 @@
 }
 
 /**
+ * _scsih_tm_tr_volume_send - send target reset request for volumes
+ * @ioc: per adapter object
+ * @handle: device handle
+ * Context: interrupt time.
+ *
+ * This is designed to send muliple task management request at the same
+ * time to the fifo. If the fifo is full, we will append the request,
+ * and process it in a future completion.
+ */
+static void
+_scsih_tm_tr_volume_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+	Mpi2SCSITaskManagementRequest_t *mpi_request;
+	u16 smid;
+	struct _tr_list *delayed_tr;
+
+	if (ioc->shost_recovery || ioc->remove_host ||
+	    ioc->pci_error_recovery) {
+		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
+		   "progress!\n", __func__, ioc->name));
+		return;
+	}
+
+	smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx);
+	if (!smid) {
+		delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
+		if (!delayed_tr)
+			return;
+		INIT_LIST_HEAD(&delayed_tr->list);
+		delayed_tr->handle = handle;
+		list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list);
+		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "DELAYED:tr:handle(0x%04x), (open)\n",
+		    ioc->name, handle));
+		return;
+	}
+
+	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
+	    "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
+	    ioc->tm_tr_volume_cb_idx));
+	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+	memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
+	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+	mpi_request->DevHandle = cpu_to_le16(handle);
+	mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+	mpt2sas_base_put_smid_hi_priority(ioc, smid);
+}
+
+/**
+ * _scsih_tm_volume_tr_complete - target reset completion
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @msix_index: MSIX table index supplied by the OS
+ * @reply: reply message frame(lower 32bit addr)
+ * Context: interrupt time.
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ *        0 means the mf is freed from this function.
+ */
+static u8
+_scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
+    u8 msix_index, u32 reply)
+{
+	u16 handle;
+	Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
+	Mpi2SCSITaskManagementReply_t *mpi_reply =
+	    mpt2sas_base_get_reply_virt_addr(ioc, reply);
+
+	if (ioc->shost_recovery || ioc->remove_host ||
+	    ioc->pci_error_recovery) {
+		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
+		   "progress!\n", __func__, ioc->name));
+		return 1;
+	}
+
+	mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
+	handle = le16_to_cpu(mpi_request_tm->DevHandle);
+	if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
+		dewtprintk(ioc, printk("spurious interrupt: "
+		    "handle(0x%04x:0x%04x), smid(%d)!!!\n", handle,
+		    le16_to_cpu(mpi_reply->DevHandle), smid));
+		return 0;
+	}
+
+	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+	    "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
+	    "loginfo(0x%08x), completed(%d)\n", ioc->name,
+	    handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
+	    le32_to_cpu(mpi_reply->IOCLogInfo),
+	    le32_to_cpu(mpi_reply->TerminationCount)));
+
+	return _scsih_check_for_pending_tm(ioc, smid);
+}
+
+/**
  * _scsih_tm_tr_complete -
  * @ioc: per adapter object
  * @smid: system request message index
@@ -2680,9 +2848,9 @@
 	    mpt2sas_base_get_reply_virt_addr(ioc, reply);
 	Mpi2SasIoUnitControlRequest_t *mpi_request;
 	u16 smid_sas_ctrl;
-	struct _tr_list *delayed_tr;
 
-	if (ioc->shost_recovery || ioc->remove_host) {
+	if (ioc->shost_recovery || ioc->remove_host ||
+	    ioc->pci_error_recovery) {
 		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
 		   "progress!\n", __func__, ioc->name));
 		return 1;
@@ -2721,6 +2889,35 @@
 	mpi_request->DevHandle = mpi_request_tm->DevHandle;
 	mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
 
+	return _scsih_check_for_pending_tm(ioc, smid);
+}
+
+/**
+ * _scsih_check_for_pending_tm - check for pending task management
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * This will check delayed target reset list, and feed the
+ * next reqeust.
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ *        0 means the mf is freed from this function.
+ */
+static u8
+_scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+	struct _tr_list *delayed_tr;
+
+	if (!list_empty(&ioc->delayed_tr_volume_list)) {
+		delayed_tr = list_entry(ioc->delayed_tr_volume_list.next,
+		    struct _tr_list, list);
+		mpt2sas_base_free_smid(ioc, smid);
+		_scsih_tm_tr_volume_send(ioc, delayed_tr->handle);
+		list_del(&delayed_tr->list);
+		kfree(delayed_tr);
+		return 0;
+	}
+
 	if (!list_empty(&ioc->delayed_tr_list)) {
 		delayed_tr = list_entry(ioc->delayed_tr_list.next,
 		    struct _tr_list, list);
@@ -2728,8 +2925,9 @@
 		_scsih_tm_tr_send(ioc, delayed_tr->handle);
 		list_del(&delayed_tr->list);
 		kfree(delayed_tr);
-		return 0; /* tells base_interrupt not to free mf */
+		return 0;
 	}
+
 	return 1;
 }
 
@@ -2803,7 +3001,7 @@
 		    MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
 			if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
 			    expander_handle) {
-				dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+				dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
 				    "setting ignoring flag\n", ioc->name));
 				fw_event->ignore = 1;
 			}
@@ -2813,6 +3011,165 @@
 }
 
 /**
+ * _scsih_set_volume_delete_flag - setting volume delete flag
+ * @ioc: per adapter object
+ * @handle: device handle
+ *
+ * This
+ * Return nothing.
+ */
+static void
+_scsih_set_volume_delete_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+	struct _raid_device *raid_device;
+	struct MPT2SAS_TARGET *sas_target_priv_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioc->raid_device_lock, flags);
+	raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+	if (raid_device && raid_device->starget &&
+	    raid_device->starget->hostdata) {
+		sas_target_priv_data =
+		    raid_device->starget->hostdata;
+		sas_target_priv_data->deleted = 1;
+		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "setting delete flag: handle(0x%04x), "
+		    "wwid(0x%016llx)\n", ioc->name, handle,
+		    (unsigned long long) raid_device->wwid));
+	}
+	spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+}
+
+/**
+ * _scsih_set_volume_handle_for_tr - set handle for target reset to volume
+ * @handle: input handle
+ * @a: handle for volume a
+ * @b: handle for volume b
+ *
+ * IR firmware only supports two raid volumes.  The purpose of this
+ * routine is to set the volume handle in either a or b. When the given
+ * input handle is non-zero, or when a and b have not been set before.
+ */
+static void
+_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b)
+{
+	if (!handle || handle == *a || handle == *b)
+		return;
+	if (!*a)
+		*a = handle;
+	else if (!*b)
+		*b = handle;
+}
+
+/**
+ * _scsih_check_ir_config_unhide_events - check for UNHIDE events
+ * @ioc: per adapter object
+ * @event_data: the event data payload
+ * Context: interrupt time.
+ *
+ * This routine will send target reset to volume, followed by target
+ * resets to the PDs. This is called when a PD has been removed, or
+ * volume has been deleted or removed. When the target reset is sent
+ * to volume, the PD target resets need to be queued to start upon
+ * completion of the volume target reset.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventDataIrConfigChangeList_t *event_data)
+{
+	Mpi2EventIrConfigElement_t *element;
+	int i;
+	u16 handle, volume_handle, a, b;
+	struct _tr_list *delayed_tr;
+
+	a = 0;
+	b = 0;
+
+	/* Volume Resets for Deleted or Removed */
+	element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
+	for (i = 0; i < event_data->NumElements; i++, element++) {
+		if (element->ReasonCode ==
+		    MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED ||
+		    element->ReasonCode ==
+		    MPI2_EVENT_IR_CHANGE_RC_REMOVED) {
+			volume_handle = le16_to_cpu(element->VolDevHandle);
+			_scsih_set_volume_delete_flag(ioc, volume_handle);
+			_scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
+		}
+	}
+
+	/* Volume Resets for UNHIDE events */
+	element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
+	for (i = 0; i < event_data->NumElements; i++, element++) {
+		if (le32_to_cpu(event_data->Flags) &
+		    MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
+			continue;
+		if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) {
+			volume_handle = le16_to_cpu(element->VolDevHandle);
+			_scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
+		}
+	}
+
+	if (a)
+		_scsih_tm_tr_volume_send(ioc, a);
+	if (b)
+		_scsih_tm_tr_volume_send(ioc, b);
+
+	/* PD target resets */
+	element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
+	for (i = 0; i < event_data->NumElements; i++, element++) {
+		if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE)
+			continue;
+		handle = le16_to_cpu(element->PhysDiskDevHandle);
+		volume_handle = le16_to_cpu(element->VolDevHandle);
+		clear_bit(handle, ioc->pd_handles);
+		if (!volume_handle)
+			_scsih_tm_tr_send(ioc, handle);
+		else if (volume_handle == a || volume_handle == b) {
+			delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
+			BUG_ON(!delayed_tr);
+			INIT_LIST_HEAD(&delayed_tr->list);
+			delayed_tr->handle = handle;
+			list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
+			dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+			    "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name,
+			    handle));
+		} else
+			_scsih_tm_tr_send(ioc, handle);
+	}
+}
+
+
+/**
+ * _scsih_check_volume_delete_events - set delete flag for volumes
+ * @ioc: per adapter object
+ * @event_data: the event data payload
+ * Context: interrupt time.
+ *
+ * This will handle the case when the cable connected to entire volume is
+ * pulled. We will take care of setting the deleted flag so normal IO will
+ * not be sent.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc,
+    Mpi2EventDataIrVolume_t *event_data)
+{
+	u32 state;
+
+	if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
+		return;
+	state = le32_to_cpu(event_data->NewValue);
+	if (state == MPI2_RAID_VOL_STATE_MISSING || state ==
+	    MPI2_RAID_VOL_STATE_FAILED)
+		_scsih_set_volume_delete_flag(ioc,
+		    le16_to_cpu(event_data->VolDevHandle));
+}
+
+/**
  * _scsih_flush_running_cmds - completing outstanding commands.
  * @ioc: per adapter object
  *
@@ -2835,7 +3192,10 @@
 		count++;
 		mpt2sas_base_free_smid(ioc, smid);
 		scsi_dma_unmap(scmd);
-		scmd->result = DID_RESET << 16;
+		if (ioc->pci_error_recovery)
+			scmd->result = DID_NO_CONNECT << 16;
+		else
+			scmd->result = DID_RESET << 16;
 		scmd->scsi_done(scmd);
 	}
 	dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
@@ -2858,9 +3218,7 @@
 	unsigned char prot_op = scsi_get_prot_op(scmd);
 	unsigned char prot_type = scsi_get_prot_type(scmd);
 
-	if (prot_type == SCSI_PROT_DIF_TYPE0 ||
-	   prot_type == SCSI_PROT_DIF_TYPE2 ||
-	   prot_op == SCSI_PROT_NORMAL)
+	if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL)
 		return;
 
 	if (prot_op ==  SCSI_PROT_READ_STRIP)
@@ -2882,7 +3240,13 @@
 		    MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
 		mpi_request->CDB.EEDP32.PrimaryReferenceTag =
 		    cpu_to_be32(scsi_get_lba(scmd));
+		break;
 
+	case SCSI_PROT_DIF_TYPE2:
+
+		eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
+		    MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
+		    MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
 		break;
 
 	case SCSI_PROT_DIF_TYPE3:
@@ -2968,6 +3332,12 @@
 		return 0;
 	}
 
+	if (ioc->pci_error_recovery) {
+		scmd->result = DID_NO_CONNECT << 16;
+		scmd->scsi_done(scmd);
+		return 0;
+	}
+
 	sas_target_priv_data = sas_device_priv_data->sas_target;
 	/* invalid device handle */
 	if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) {
@@ -3013,7 +3383,7 @@
 		mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
 	/* Make sure Device is not raid volume */
 	if (!_scsih_is_raid(&scmd->device->sdev_gendev) &&
-	    sas_is_tlr_enabled(scmd->device))
+	    sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32)
 		mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
 
 	smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
@@ -3025,6 +3395,8 @@
 	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
 	memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
 	_scsih_setup_eedp(scmd, mpi_request);
+	if (scmd->cmd_len == 32)
+		mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
 	mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
 	if (sas_device_priv_data->sas_target->flags &
 	    MPT_TARGET_FLAGS_RAID_COMPONENT)
@@ -3119,6 +3491,13 @@
 	char *desc_scsi_status = NULL;
 	char *desc_scsi_state = ioc->tmp_string;
 	u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
+	struct _sas_device *sas_device = NULL;
+	unsigned long flags;
+	struct scsi_target *starget = scmd->device->sdev_target;
+	struct MPT2SAS_TARGET *priv_target = starget->hostdata;
+
+	if (!priv_target)
+		return;
 
 	if (log_info == 0x31170000)
 		return;
@@ -3234,10 +3613,29 @@
 		strcat(desc_scsi_state, "autosense valid ");
 
 	scsi_print_command(scmd);
-	printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), "
-	    "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name,
-	    le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state,
-		ioc_status, smid);
+
+	if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
+		printk(MPT2SAS_WARN_FMT "\tvolume wwid(0x%016llx)\n", ioc->name,
+		    (unsigned long long)priv_target->sas_address);
+	} else {
+		spin_lock_irqsave(&ioc->sas_device_lock, flags);
+		sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+		    priv_target->sas_address);
+		if (sas_device) {
+			printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), "
+			    "phy(%d)\n", ioc->name, sas_device->sas_address,
+			    sas_device->phy);
+			printk(MPT2SAS_WARN_FMT
+			    "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
+			    ioc->name, sas_device->enclosure_logical_id,
+			    sas_device->slot);
+		}
+		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+	}
+
+	printk(MPT2SAS_WARN_FMT "\thandle(0x%04x), ioc_status(%s)(0x%04x), "
+	    "smid(%d)\n", ioc->name, le16_to_cpu(mpi_reply->DevHandle),
+	    desc_ioc_state, ioc_status, smid);
 	printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
 	    "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
 	    scsi_get_resid(scmd));
@@ -3772,7 +4170,7 @@
 	if (!handle)
 		return -1;
 
-	if (ioc->shost_recovery)
+	if (ioc->shost_recovery || ioc->pci_error_recovery)
 		return -1;
 
 	if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
@@ -4178,7 +4576,7 @@
 	    le16_to_cpu(sas_device_pg0.Slot);
 	sas_device->device_info = device_info;
 	sas_device->sas_address = sas_address;
-	sas_device->hidden_raid_component = is_pd;
+	sas_device->phy = sas_device_pg0.PhyNum;
 
 	/* get enclosure_logical_id */
 	if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
@@ -4199,62 +4597,6 @@
 }
 
 /**
- * _scsih_remove_pd_device -  removing sas device pd object
- * @ioc: per adapter object
- * @sas_device_delete: the sas_device object
- *
- * For hidden raid components, we do driver-fw handshake from
- * hotplug work threads.
- * Return nothing.
- */
-static void
-_scsih_remove_pd_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
-    sas_device)
-{
-	Mpi2SasIoUnitControlReply_t mpi_reply;
-	Mpi2SasIoUnitControlRequest_t mpi_request;
-	u16 vol_handle, handle;
-
-	handle = sas_device.handle;
-	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"
-	    " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
-	    (unsigned long long) sas_device.sas_address));
-
-	vol_handle = sas_device.volume_handle;
-	if (!vol_handle)
-		return;
-	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
-	    "handle(0x%04x)\n", ioc->name, vol_handle));
-	mpt2sas_scsih_issue_tm(ioc, vol_handle, 0, 0, 0,
-	    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30, NULL);
-	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
-	    "done: handle(0x%04x)\n", ioc->name, vol_handle));
-	if (ioc->shost_recovery)
-		return;
-
-	/* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
-	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
-	    "(0x%04x)\n", ioc->name, handle));
-	memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
-	mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
-	mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
-	mpi_request.DevHandle = cpu_to_le16(handle);
-	if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
-	    &mpi_request)) != 0)
-		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
-		    ioc->name, __FILE__, __LINE__, __func__);
-
-	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
-	    "(0x%04x), loginfo(0x%08x)\n", ioc->name,
-	    le16_to_cpu(mpi_reply.IOCStatus),
-	    le32_to_cpu(mpi_reply.IOCLogInfo)));
-
-	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle(0x%04x),"
-	    " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
-	    (unsigned long long) sas_device.sas_address));
-}
-
-/**
  * _scsih_remove_device -  removing sas device object
  * @ioc: per adapter object
  * @sas_device_delete: the sas_device object
@@ -4284,9 +4626,6 @@
 		sas_target_priv_data->deleted = 1;
 	}
 
-	if (sas_device_backup.hidden_raid_component)
-		_scsih_remove_pd_device(ioc, sas_device_backup);
-
 	_scsih_ublock_io_device(ioc, sas_device_backup.handle);
 
 	mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address,
@@ -4338,9 +4677,9 @@
 		status_str = "unknown status";
 		break;
 	}
-	printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
+	printk(MPT2SAS_INFO_FMT "sas topology change: (%s)\n",
 	    ioc->name, status_str);
-	printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
+	printk(KERN_INFO "\thandle(0x%04x), enclosure_handle(0x%04x) "
 	    "start_phy(%02d), count(%d)\n",
 	    le16_to_cpu(event_data->ExpanderDevHandle),
 	    le16_to_cpu(event_data->EnclosureHandle),
@@ -4374,7 +4713,7 @@
 		}
 		link_rate = event_data->PHY[i].LinkRate >> 4;
 		prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
-		printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x): %s:"
+		printk(KERN_INFO "\tphy(%02d), attached_handle(0x%04x): %s:"
 		    " link rate: new(0x%02x), old(0x%02x)\n", phy_number,
 		    handle, status_str, link_rate, prev_link_rate);
 
@@ -4409,7 +4748,7 @@
 		_scsih_sas_topology_change_event_debug(ioc, event_data);
 #endif
 
-	if (ioc->shost_recovery || ioc->remove_host)
+	if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery)
 		return;
 
 	if (!ioc->sas_hba.num_phys)
@@ -4418,7 +4757,7 @@
 		_scsih_sas_host_refresh(ioc);
 
 	if (fw_event->ignore) {
-		dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
+		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring expander "
 		    "event\n", ioc->name));
 		return;
 	}
@@ -4444,11 +4783,12 @@
 	/* handle siblings events */
 	for (i = 0; i < event_data->NumEntries; i++) {
 		if (fw_event->ignore) {
-			dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
+			dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring "
 			    "expander event\n", ioc->name));
 			return;
 		}
-		if (ioc->shost_recovery || ioc->remove_host)
+		if (ioc->shost_recovery || ioc->remove_host ||
+		    ioc->pci_error_recovery)
 			return;
 		phy_number = event_data->StartPhyNum + i;
 		reason_code = event_data->PHY[i].PhyStatus &
@@ -4564,12 +4904,12 @@
 		reason_str = "unknown reason";
 		break;
 	}
-	printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
+	printk(MPT2SAS_INFO_FMT "device status change: (%s)\n"
 	    "\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
 	    reason_str, le16_to_cpu(event_data->DevHandle),
 	    (unsigned long long)le64_to_cpu(event_data->SASAddress));
 	if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
-		printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
+		printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
 		    event_data->ASC, event_data->ASCQ);
 	printk(KERN_INFO "\n");
 }
@@ -4653,7 +4993,7 @@
 		break;
 	}
 
-	printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
+	printk(MPT2SAS_INFO_FMT "enclosure status change: (%s)\n"
 	    "\thandle(0x%04x), enclosure logical id(0x%016llx)"
 	    " number slots(%d)\n", ioc->name, reason_str,
 	    le16_to_cpu(event_data->EnclosureHandle),
@@ -4704,10 +5044,10 @@
 	Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
 #endif
 	u16 ioc_status;
-	dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
+	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "broadcast primative: "
 	    "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
 	    event_data->PortWidth));
-	dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+	dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
 	    __func__));
 
 	termination_count = 0;
@@ -4751,7 +5091,7 @@
 	}
 	ioc->broadcast_aen_busy = 0;
 
-	dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+	dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
 	    "%s - exit, query_count = %d termination_count = %d\n",
 	    ioc->name, __func__, query_count, termination_count));
 }
@@ -4772,7 +5112,7 @@
 
 #ifdef CONFIG_SCSI_MPT2SAS_LOGGING
 	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
-		printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
+		printk(MPT2SAS_INFO_FMT "discovery event: (%s)", ioc->name,
 		    (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
 		    "start" : "stop");
 	if (event_data->DiscoveryStatus)
@@ -4883,17 +5223,15 @@
 /**
  * _scsih_sas_volume_delete - delete volume
  * @ioc: per adapter object
- * @element: IR config element data
+ * @handle: volume device handle
  * Context: user.
  *
  * Return nothing.
  */
 static void
-_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
-    Mpi2EventIrConfigElement_t *element)
+_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle)
 {
 	struct _raid_device *raid_device;
-	u16 handle = le16_to_cpu(element->VolDevHandle);
 	unsigned long flags;
 	struct MPT2SAS_TARGET *sas_target_priv_data;
 
@@ -4907,6 +5245,9 @@
 		sas_target_priv_data->deleted = 1;
 		scsi_remove_target(&raid_device->starget->dev);
 	}
+	printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
+	    "(0x%016llx)\n", ioc->name,  raid_device->handle,
+	    (unsigned long long) raid_device->wwid);
 	_scsih_raid_device_remove(ioc, raid_device);
 }
 
@@ -4935,7 +5276,7 @@
 	/* exposing raid component */
 	sas_device->volume_handle = 0;
 	sas_device->volume_wwid = 0;
-	sas_device->hidden_raid_component = 0;
+	clear_bit(handle, ioc->pd_handles);
 	_scsih_reprobe_target(sas_device->starget, 0);
 }
 
@@ -4966,7 +5307,7 @@
 	    &sas_device->volume_handle);
 	mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
 	    &sas_device->volume_wwid);
-	sas_device->hidden_raid_component = 1;
+	set_bit(handle, ioc->pd_handles);
 	_scsih_reprobe_target(sas_device->starget, 1);
 }
 
@@ -5015,13 +5356,13 @@
 	u64 sas_address;
 	u16 parent_handle;
 
+	set_bit(handle, ioc->pd_handles);
+
 	spin_lock_irqsave(&ioc->sas_device_lock, flags);
 	sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
 	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-	if (sas_device) {
-		sas_device->hidden_raid_component = 1;
+	if (sas_device)
 		return;
-	}
 
 	if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
 	    MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
@@ -5066,7 +5407,7 @@
 
 	element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
 
-	printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
+	printk(MPT2SAS_INFO_FMT "raid config change: (%s), elements(%d)\n",
 	    ioc->name, (le32_to_cpu(event_data->Flags) &
 	    MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
 	    "foreign" : "native", event_data->NumElements);
@@ -5119,7 +5460,7 @@
 			element_str = "unknown element";
 			break;
 		}
-		printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
+		printk(KERN_INFO "\t(%s:%s), vol handle(0x%04x), "
 		    "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
 		    reason_str, le16_to_cpu(element->VolDevHandle),
 		    le16_to_cpu(element->PhysDiskDevHandle),
@@ -5165,7 +5506,8 @@
 		case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
 		case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
 			if (!foreign_config)
-				_scsih_sas_volume_delete(ioc, element);
+				_scsih_sas_volume_delete(ioc,
+				    le16_to_cpu(element->VolDevHandle));
 			break;
 		case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
 			_scsih_sas_pd_hide(ioc, element);
@@ -5201,7 +5543,6 @@
 	u16 handle;
 	u32 state;
 	int rc;
-	struct MPT2SAS_TARGET *sas_target_priv_data;
 	Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
 
 	if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
@@ -5209,30 +5550,24 @@
 
 	handle = le16_to_cpu(event_data->VolDevHandle);
 	state = le32_to_cpu(event_data->NewValue);
-	dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
+	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
 	    "old(0x%08x), new(0x%08x)\n", ioc->name, __func__,  handle,
 	    le32_to_cpu(event_data->PreviousValue), state));
 
-	spin_lock_irqsave(&ioc->raid_device_lock, flags);
-	raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
-	spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-
 	switch (state) {
 	case MPI2_RAID_VOL_STATE_MISSING:
 	case MPI2_RAID_VOL_STATE_FAILED:
-		if (!raid_device)
-			break;
-		if (raid_device->starget) {
-			sas_target_priv_data = raid_device->starget->hostdata;
-			sas_target_priv_data->deleted = 1;
-			scsi_remove_target(&raid_device->starget->dev);
-		}
-		_scsih_raid_device_remove(ioc, raid_device);
+		_scsih_sas_volume_delete(ioc, handle);
 		break;
 
 	case MPI2_RAID_VOL_STATE_ONLINE:
 	case MPI2_RAID_VOL_STATE_DEGRADED:
 	case MPI2_RAID_VOL_STATE_OPTIMAL:
+
+		spin_lock_irqsave(&ioc->raid_device_lock, flags);
+		raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+		spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+
 		if (raid_device)
 			break;
 
@@ -5297,23 +5632,25 @@
 	handle = le16_to_cpu(event_data->PhysDiskDevHandle);
 	state = le32_to_cpu(event_data->NewValue);
 
-	dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
+	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
 	    "old(0x%08x), new(0x%08x)\n", ioc->name, __func__,  handle,
 	    le32_to_cpu(event_data->PreviousValue), state));
 
-	spin_lock_irqsave(&ioc->sas_device_lock, flags);
-	sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
-	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
 	switch (state) {
 	case MPI2_RAID_PD_STATE_ONLINE:
 	case MPI2_RAID_PD_STATE_DEGRADED:
 	case MPI2_RAID_PD_STATE_REBUILDING:
 	case MPI2_RAID_PD_STATE_OPTIMAL:
-		if (sas_device) {
-			sas_device->hidden_raid_component = 1;
+	case MPI2_RAID_PD_STATE_HOT_SPARE:
+
+		set_bit(handle, ioc->pd_handles);
+
+		spin_lock_irqsave(&ioc->sas_device_lock, flags);
+		sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+		if (sas_device)
 			return;
-		}
 
 		if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
 		    &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
@@ -5343,7 +5680,6 @@
 	case MPI2_RAID_PD_STATE_OFFLINE:
 	case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
 	case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
-	case MPI2_RAID_PD_STATE_HOT_SPARE:
 	default:
 		break;
 	}
@@ -5471,7 +5807,7 @@
 	sas_address = sas_device->sas_address;
 
 	/* if hidden raid component, then change to volume characteristics */
-	if (sas_device->hidden_raid_component && sas_device->volume_handle) {
+	if (test_bit(handle, ioc->pd_handles) && sas_device->volume_handle) {
 		spin_lock_irqsave(&ioc->raid_device_lock, flags);
 		raid_device = _scsih_raid_device_find_by_handle(
 		    ioc, sas_device->volume_handle);
@@ -5485,7 +5821,7 @@
 	}
 
 	if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
-		starget_printk(KERN_DEBUG, sas_device->starget, "task set "
+		starget_printk(KERN_INFO, sas_device->starget, "task set "
 		    "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
 		    handle, (unsigned long long)sas_address, current_depth);
 
@@ -5696,9 +6032,12 @@
 _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
 {
 	Mpi2RaidVolPage1_t volume_pg1;
+	Mpi2RaidVolPage0_t volume_pg0;
+	Mpi2RaidPhysDiskPage0_t pd_pg0;
 	Mpi2ConfigReply_t mpi_reply;
 	u16 ioc_status;
 	u16 handle;
+	u8 phys_disk_num;
 
 	printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
 
@@ -5713,8 +6052,32 @@
 		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
 			break;
 		handle = le16_to_cpu(volume_pg1.DevHandle);
-		_scsih_mark_responding_raid_device(ioc,
-		    le64_to_cpu(volume_pg1.WWID), handle);
+
+		if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply,
+		    &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
+		     sizeof(Mpi2RaidVolPage0_t)))
+			continue;
+
+		if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL ||
+		    volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE ||
+		    volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED)
+			_scsih_mark_responding_raid_device(ioc,
+			    le64_to_cpu(volume_pg1.WWID), handle);
+	}
+
+	/* refresh the pd_handles */
+	phys_disk_num = 0xFF;
+	memset(ioc->pd_handles, 0, ioc->pd_handles_sz);
+	while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
+	    &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM,
+	    phys_disk_num))) {
+		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+		    MPI2_IOCSTATUS_MASK;
+		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+			break;
+		phys_disk_num = pd_pg0.PhysDiskNum;
+		handle = le16_to_cpu(pd_pg0.DevHandle);
+		set_bit(handle, ioc->pd_handles);
 	}
 }
 
@@ -5876,11 +6239,11 @@
 {
 	switch (reset_phase) {
 	case MPT2_IOC_PRE_RESET:
-		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 		    "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
 		break;
 	case MPT2_IOC_AFTER_RESET:
-		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 		    "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
 		if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) {
 			ioc->scsih_cmds.status |= MPT2_CMD_RESET;
@@ -5897,7 +6260,7 @@
 		_scsih_queue_rescan(ioc);
 		break;
 	case MPT2_IOC_DONE_RESET:
-		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
 		    "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
 		_scsih_sas_host_refresh(ioc);
 		_scsih_prep_device_scan(ioc);
@@ -5925,7 +6288,8 @@
 	struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
 
 	/* the queue is being flushed so ignore this event */
-	if (ioc->remove_host || fw_event->cancel_pending_work) {
+	if (ioc->remove_host || fw_event->cancel_pending_work ||
+	    ioc->pci_error_recovery) {
 		_scsih_fw_event_free(ioc, fw_event);
 		return;
 	}
@@ -6007,7 +6371,7 @@
 	u16 sz;
 
 	/* events turned off due to host reset or driver unloading */
-	if (ioc->remove_host)
+	if (ioc->remove_host || ioc->pci_error_recovery)
 		return 1;
 
 	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
@@ -6034,14 +6398,21 @@
 		    (Mpi2EventDataSasTopologyChangeList_t *)
 		    mpi_reply->EventData);
 		break;
-
+	case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
+		_scsih_check_ir_config_unhide_events(ioc,
+		    (Mpi2EventDataIrConfigChangeList_t *)
+		    mpi_reply->EventData);
+		break;
+	case MPI2_EVENT_IR_VOLUME:
+		_scsih_check_volume_delete_events(ioc,
+		    (Mpi2EventDataIrVolume_t *)
+		    mpi_reply->EventData);
+		break;
 	case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
 	case MPI2_EVENT_IR_OPERATION_STATUS:
 	case MPI2_EVENT_SAS_DISCOVERY:
 	case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
-	case MPI2_EVENT_IR_VOLUME:
 	case MPI2_EVENT_IR_PHYSICAL_DISK:
-	case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
 	case MPI2_EVENT_TASK_SET_FULL:
 		break;
 
@@ -6548,9 +6919,11 @@
 	ioc->scsih_cb_idx = scsih_cb_idx;
 	ioc->config_cb_idx = config_cb_idx;
 	ioc->tm_tr_cb_idx = tm_tr_cb_idx;
+	ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx;
 	ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
 	ioc->logging_level = logging_level;
 	/* misc semaphores and spin locks */
+	mutex_init(&ioc->reset_in_progress_mutex);
 	spin_lock_init(&ioc->ioc_reset_in_progress_lock);
 	spin_lock_init(&ioc->scsi_lookup_lock);
 	spin_lock_init(&ioc->sas_device_lock);
@@ -6565,9 +6938,10 @@
 	INIT_LIST_HEAD(&ioc->raid_device_list);
 	INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
 	INIT_LIST_HEAD(&ioc->delayed_tr_list);
+	INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
 
 	/* init shost parameters */
-	shost->max_cmd_len = 16;
+	shost->max_cmd_len = 32;
 	shost->max_lun = max_lun;
 	shost->transportt = mpt2sas_transport_template;
 	shost->unique_id = ioc->id;
@@ -6580,7 +6954,7 @@
 	}
 
 	scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
-	    | SHOST_DIF_TYPE3_PROTECTION);
+	    | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION);
 	scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
 
 	/* event thread */
@@ -6700,12 +7074,17 @@
 	case pci_channel_io_normal:
 		return PCI_ERS_RESULT_CAN_RECOVER;
 	case pci_channel_io_frozen:
+		/* Fatal error, prepare for slot reset */
+		ioc->pci_error_recovery = 1;
 		scsi_block_requests(ioc->shost);
 		mpt2sas_base_stop_watchdog(ioc);
 		mpt2sas_base_free_resources(ioc);
 		return PCI_ERS_RESULT_NEED_RESET;
 	case pci_channel_io_perm_failure:
-		_scsih_remove(pdev);
+		/* Permanent error, prepare for device removal */
+		ioc->pci_error_recovery = 1;
+		mpt2sas_base_stop_watchdog(ioc);
+		_scsih_flush_running_cmds(ioc);
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
 	return PCI_ERS_RESULT_NEED_RESET;
@@ -6729,7 +7108,9 @@
 	printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n",
 		ioc->name);
 
+	ioc->pci_error_recovery = 0;
 	ioc->pdev = pdev;
+	pci_restore_state(pdev);
 	rc = mpt2sas_base_map_resources(ioc);
 	if (rc)
 		return PCI_ERS_RESULT_DISCONNECT;
@@ -6867,6 +7248,10 @@
 
 	tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
 	    _scsih_tm_tr_complete);
+
+	tm_tr_volume_cb_idx = mpt2sas_base_register_callback_handler(
+	    _scsih_tm_volume_tr_complete);
+
 	tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
 	    _scsih_sas_control_complete);
 
@@ -6906,6 +7291,7 @@
 	mpt2sas_base_release_callback_handler(ctl_cb_idx);
 
 	mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
+	mpt2sas_base_release_callback_handler(tm_tr_volume_cb_idx);
 	mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
 
 	/* raid transport support */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index 2727c3b..b55c6dc 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -140,7 +140,7 @@
 	u32 device_info;
 	u32 ioc_status;
 
-	if (ioc->shost_recovery) {
+	if (ioc->shost_recovery || ioc->pci_error_recovery) {
 		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
 		    __func__, ioc->name);
 		return -EFAULT;
@@ -302,7 +302,7 @@
 	u64 *sas_address_le;
 	u16 wait_state_count;
 
-	if (ioc->shost_recovery) {
+	if (ioc->shost_recovery || ioc->pci_error_recovery) {
 		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
 		    __func__, ioc->name);
 		return -EFAULT;
@@ -397,7 +397,7 @@
 	    sizeof(struct rep_manu_reply), data_out_dma +
 	    sizeof(struct rep_manu_request));
 
-	dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
+	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - "
 	    "send to sas_addr(0x%016llx)\n", ioc->name,
 	    (unsigned long long)sas_address));
 	mpt2sas_base_put_smid_default(ioc, smid);
@@ -415,7 +415,7 @@
 		goto issue_host_reset;
 	}
 
-	dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
+	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - "
 	    "complete\n", ioc->name));
 
 	if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
@@ -423,7 +423,7 @@
 
 		mpi_reply = ioc->transport_cmds.reply;
 
-		dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
 		    "report_manufacture - reply data transfer size(%d)\n",
 		    ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
 
@@ -449,7 +449,7 @@
 			    manufacture_reply->component_revision_id;
 		}
 	} else
-		dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
 		    "report_manufacture - no reply\n", ioc->name));
 
  issue_host_reset:
@@ -894,7 +894,7 @@
 	struct _sas_node *sas_node;
 	struct _sas_phy *mpt2sas_phy;
 
-	if (ioc->shost_recovery)
+	if (ioc->shost_recovery || ioc->pci_error_recovery)
 		return;
 
 	spin_lock_irqsave(&ioc->sas_node_lock, flags);
@@ -940,22 +940,230 @@
 	return shost_priv(shost);
 }
 
-static struct _sas_phy *
-_transport_find_local_phy(struct MPT2SAS_ADAPTER *ioc, struct sas_phy *phy)
-{
-	int i;
 
-	for (i = 0; i < ioc->sas_hba.num_phys; i++)
-		if (ioc->sas_hba.phy[i].phy == phy)
-			return(&ioc->sas_hba.phy[i]);
-	return NULL;
+/* report phy error log structure */
+struct phy_error_log_request{
+	u8 smp_frame_type; /* 0x40 */
+	u8 function; /* 0x11 */
+	u8 allocated_response_length;
+	u8 request_length; /* 02 */
+	u8 reserved_1[5];
+	u8 phy_identifier;
+	u8 reserved_2[2];
+};
+
+/* report phy error log reply structure */
+struct phy_error_log_reply{
+	u8 smp_frame_type; /* 0x41 */
+	u8 function; /* 0x11 */
+	u8 function_result;
+	u8 response_length;
+	u16 expander_change_count;
+	u8 reserved_1[3];
+	u8 phy_identifier;
+	u8 reserved_2[2];
+	u32 invalid_dword;
+	u32 running_disparity_error;
+	u32 loss_of_dword_sync;
+	u32 phy_reset_problem;
+};
+
+/**
+ * _transport_get_expander_phy_error_log - return expander counters
+ * @ioc: per adapter object
+ * @phy: The sas phy object
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ */
+static int
+_transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc,
+    struct sas_phy *phy)
+{
+	Mpi2SmpPassthroughRequest_t *mpi_request;
+	Mpi2SmpPassthroughReply_t *mpi_reply;
+	struct phy_error_log_request *phy_error_log_request;
+	struct phy_error_log_reply *phy_error_log_reply;
+	int rc;
+	u16 smid;
+	u32 ioc_state;
+	unsigned long timeleft;
+	void *psge;
+	u32 sgl_flags;
+	u8 issue_reset = 0;
+	void *data_out = NULL;
+	dma_addr_t data_out_dma;
+	u32 sz;
+	u64 *sas_address_le;
+	u16 wait_state_count;
+
+	if (ioc->shost_recovery || ioc->pci_error_recovery) {
+		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
+		    __func__, ioc->name);
+		return -EFAULT;
+	}
+
+	mutex_lock(&ioc->transport_cmds.mutex);
+
+	if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
+		printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
+		    ioc->name, __func__);
+		rc = -EAGAIN;
+		goto out;
+	}
+	ioc->transport_cmds.status = MPT2_CMD_PENDING;
+
+	wait_state_count = 0;
+	ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+	while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+		if (wait_state_count++ == 10) {
+			printk(MPT2SAS_ERR_FMT
+			    "%s: failed due to ioc not operational\n",
+			    ioc->name, __func__);
+			rc = -EFAULT;
+			goto out;
+		}
+		ssleep(1);
+		ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+		printk(MPT2SAS_INFO_FMT "%s: waiting for "
+		    "operational state(count=%d)\n", ioc->name,
+		    __func__, wait_state_count);
+	}
+	if (wait_state_count)
+		printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
+		    ioc->name, __func__);
+
+	smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
+	if (!smid) {
+		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+		    ioc->name, __func__);
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+	ioc->transport_cmds.smid = smid;
+
+	sz = sizeof(struct phy_error_log_request) +
+	    sizeof(struct phy_error_log_reply);
+	data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
+	if (!data_out) {
+		printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
+		    __LINE__, __func__);
+		rc = -ENOMEM;
+		mpt2sas_base_free_smid(ioc, smid);
+		goto out;
+	}
+
+	rc = -EINVAL;
+	memset(data_out, 0, sz);
+	phy_error_log_request = data_out;
+	phy_error_log_request->smp_frame_type = 0x40;
+	phy_error_log_request->function = 0x11;
+	phy_error_log_request->request_length = 2;
+	phy_error_log_request->allocated_response_length = 0;
+	phy_error_log_request->phy_identifier = phy->number;
+
+	memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
+	mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
+	mpi_request->PhysicalPort = 0xFF;
+	mpi_request->VF_ID = 0; /* TODO */
+	mpi_request->VP_ID = 0;
+	sas_address_le = (u64 *)&mpi_request->SASAddress;
+	*sas_address_le = cpu_to_le64(phy->identify.sas_address);
+	mpi_request->RequestDataLength =
+	    cpu_to_le16(sizeof(struct phy_error_log_request));
+	psge = &mpi_request->SGL;
+
+	/* WRITE sgel first */
+	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+	    MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
+	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+	ioc->base_add_sg_single(psge, sgl_flags |
+	    sizeof(struct phy_error_log_request), data_out_dma);
+
+	/* incr sgel */
+	psge += ioc->sge_size;
+
+	/* READ sgel last */
+	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+	    MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
+	    MPI2_SGE_FLAGS_END_OF_LIST);
+	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+	ioc->base_add_sg_single(psge, sgl_flags |
+	    sizeof(struct phy_error_log_reply), data_out_dma +
+	    sizeof(struct phy_error_log_request));
+
+	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - "
+	    "send to sas_addr(0x%016llx), phy(%d)\n", ioc->name,
+	    (unsigned long long)phy->identify.sas_address, phy->number));
+	mpt2sas_base_put_smid_default(ioc, smid);
+	init_completion(&ioc->transport_cmds.done);
+	timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
+	    10*HZ);
+
+	if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
+		printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+		    ioc->name, __func__);
+		_debug_dump_mf(mpi_request,
+		    sizeof(Mpi2SmpPassthroughRequest_t)/4);
+		if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
+			issue_reset = 1;
+		goto issue_host_reset;
+	}
+
+	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - "
+	    "complete\n", ioc->name));
+
+	if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
+
+		mpi_reply = ioc->transport_cmds.reply;
+
+		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "phy_error_log - reply data transfer size(%d)\n",
+		    ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
+
+		if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
+		    sizeof(struct phy_error_log_reply))
+			goto out;
+
+		phy_error_log_reply = data_out +
+		    sizeof(struct phy_error_log_request);
+
+		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "phy_error_log - function_result(%d)\n",
+		    ioc->name, phy_error_log_reply->function_result));
+
+		phy->invalid_dword_count =
+		    be32_to_cpu(phy_error_log_reply->invalid_dword);
+		phy->running_disparity_error_count =
+		    be32_to_cpu(phy_error_log_reply->running_disparity_error);
+		phy->loss_of_dword_sync_count =
+		    be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);
+		phy->phy_reset_problem_count =
+		    be32_to_cpu(phy_error_log_reply->phy_reset_problem);
+		rc = 0;
+	} else
+		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "phy_error_log - no reply\n", ioc->name));
+
+ issue_host_reset:
+	if (issue_reset)
+		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+		    FORCE_BIG_HAMMER);
+ out:
+	ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
+	if (data_out)
+		pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
+
+	mutex_unlock(&ioc->transport_cmds.mutex);
+	return rc;
 }
 
 /**
- * _transport_get_linkerrors -
+ * _transport_get_linkerrors - return phy counters for both hba and expanders
  * @phy: The sas phy object
  *
- * Only support sas_host direct attached phys.
  * Returns 0 for success, non-zero for failure.
  *
  */
@@ -963,17 +1171,24 @@
 _transport_get_linkerrors(struct sas_phy *phy)
 {
 	struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
-	struct _sas_phy *mpt2sas_phy;
+	unsigned long flags;
 	Mpi2ConfigReply_t mpi_reply;
 	Mpi2SasPhyPage1_t phy_pg1;
 
-	mpt2sas_phy = _transport_find_local_phy(ioc, phy);
-
-	if (!mpt2sas_phy) /* this phy not on sas_host */
+	spin_lock_irqsave(&ioc->sas_node_lock, flags);
+	if (_transport_sas_node_find_by_sas_address(ioc,
+	    phy->identify.sas_address) == NULL) {
+		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
 		return -EINVAL;
+	}
+	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
 
+	if (phy->identify.sas_address != ioc->sas_hba.sas_address)
+		return _transport_get_expander_phy_error_log(ioc, phy);
+
+	/* get hba phy error logs */
 	if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1,
-		    mpt2sas_phy->phy_id))) {
+		    phy->number))) {
 		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 		    ioc->name, __FILE__, __LINE__, __func__);
 		return -ENXIO;
@@ -982,8 +1197,7 @@
 	if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
 		printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
 		    "(0x%04x), loginfo(0x%08x)\n", ioc->name,
-		    mpt2sas_phy->phy_id,
-		    le16_to_cpu(mpi_reply.IOCStatus),
+		    phy->number, le16_to_cpu(mpi_reply.IOCStatus),
 		    le32_to_cpu(mpi_reply.IOCLogInfo));
 
 	phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount);
@@ -1007,18 +1221,18 @@
 _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
 {
 	struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
-	struct _sas_node *sas_expander;
+	struct _sas_device *sas_device;
 	unsigned long flags;
 
-	spin_lock_irqsave(&ioc->sas_node_lock, flags);
-	sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
+	spin_lock_irqsave(&ioc->sas_device_lock, flags);
+	sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
 	    rphy->identify.sas_address);
-	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 
-	if (!sas_expander)
+	if (!sas_device)
 		return -ENXIO;
 
-	*identifier = sas_expander->enclosure_logical_id;
+	*identifier = sas_device->enclosure_logical_id;
 	return 0;
 }
 
@@ -1046,32 +1260,260 @@
 	return sas_device->slot;
 }
 
+/* phy control request structure */
+struct phy_control_request{
+	u8 smp_frame_type; /* 0x40 */
+	u8 function; /* 0x91 */
+	u8 allocated_response_length;
+	u8 request_length; /* 0x09 */
+	u16 expander_change_count;
+	u8 reserved_1[3];
+	u8 phy_identifier;
+	u8 phy_operation;
+	u8 reserved_2[13];
+	u64 attached_device_name;
+	u8 programmed_min_physical_link_rate;
+	u8 programmed_max_physical_link_rate;
+	u8 reserved_3[6];
+};
+
+/* phy control reply structure */
+struct phy_control_reply{
+	u8 smp_frame_type; /* 0x41 */
+	u8 function; /* 0x11 */
+	u8 function_result;
+	u8 response_length;
+};
+
+#define SMP_PHY_CONTROL_LINK_RESET	(0x01)
+#define SMP_PHY_CONTROL_HARD_RESET	(0x02)
+#define SMP_PHY_CONTROL_DISABLE		(0x03)
+
+/**
+ * _transport_expander_phy_control - expander phy control
+ * @ioc: per adapter object
+ * @phy: The sas phy object
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ */
+static int
+_transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc,
+    struct sas_phy *phy, u8 phy_operation)
+{
+	Mpi2SmpPassthroughRequest_t *mpi_request;
+	Mpi2SmpPassthroughReply_t *mpi_reply;
+	struct phy_control_request *phy_control_request;
+	struct phy_control_reply *phy_control_reply;
+	int rc;
+	u16 smid;
+	u32 ioc_state;
+	unsigned long timeleft;
+	void *psge;
+	u32 sgl_flags;
+	u8 issue_reset = 0;
+	void *data_out = NULL;
+	dma_addr_t data_out_dma;
+	u32 sz;
+	u64 *sas_address_le;
+	u16 wait_state_count;
+
+	if (ioc->shost_recovery) {
+		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
+		    __func__, ioc->name);
+		return -EFAULT;
+	}
+
+	mutex_lock(&ioc->transport_cmds.mutex);
+
+	if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
+		printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
+		    ioc->name, __func__);
+		rc = -EAGAIN;
+		goto out;
+	}
+	ioc->transport_cmds.status = MPT2_CMD_PENDING;
+
+	wait_state_count = 0;
+	ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+	while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+		if (wait_state_count++ == 10) {
+			printk(MPT2SAS_ERR_FMT
+			    "%s: failed due to ioc not operational\n",
+			    ioc->name, __func__);
+			rc = -EFAULT;
+			goto out;
+		}
+		ssleep(1);
+		ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+		printk(MPT2SAS_INFO_FMT "%s: waiting for "
+		    "operational state(count=%d)\n", ioc->name,
+		    __func__, wait_state_count);
+	}
+	if (wait_state_count)
+		printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
+		    ioc->name, __func__);
+
+	smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
+	if (!smid) {
+		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+		    ioc->name, __func__);
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+	ioc->transport_cmds.smid = smid;
+
+	sz = sizeof(struct phy_control_request) +
+	    sizeof(struct phy_control_reply);
+	data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
+	if (!data_out) {
+		printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
+		    __LINE__, __func__);
+		rc = -ENOMEM;
+		mpt2sas_base_free_smid(ioc, smid);
+		goto out;
+	}
+
+	rc = -EINVAL;
+	memset(data_out, 0, sz);
+	phy_control_request = data_out;
+	phy_control_request->smp_frame_type = 0x40;
+	phy_control_request->function = 0x91;
+	phy_control_request->request_length = 9;
+	phy_control_request->allocated_response_length = 0;
+	phy_control_request->phy_identifier = phy->number;
+	phy_control_request->phy_operation = phy_operation;
+	phy_control_request->programmed_min_physical_link_rate =
+	    phy->minimum_linkrate << 4;
+	phy_control_request->programmed_max_physical_link_rate =
+	    phy->maximum_linkrate << 4;
+
+	memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
+	mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
+	mpi_request->PhysicalPort = 0xFF;
+	mpi_request->VF_ID = 0; /* TODO */
+	mpi_request->VP_ID = 0;
+	sas_address_le = (u64 *)&mpi_request->SASAddress;
+	*sas_address_le = cpu_to_le64(phy->identify.sas_address);
+	mpi_request->RequestDataLength =
+	    cpu_to_le16(sizeof(struct phy_error_log_request));
+	psge = &mpi_request->SGL;
+
+	/* WRITE sgel first */
+	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+	    MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
+	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+	ioc->base_add_sg_single(psge, sgl_flags |
+	    sizeof(struct phy_control_request), data_out_dma);
+
+	/* incr sgel */
+	psge += ioc->sge_size;
+
+	/* READ sgel last */
+	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+	    MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
+	    MPI2_SGE_FLAGS_END_OF_LIST);
+	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+	ioc->base_add_sg_single(psge, sgl_flags |
+	    sizeof(struct phy_control_reply), data_out_dma +
+	    sizeof(struct phy_control_request));
+
+	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - "
+	    "send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", ioc->name,
+	    (unsigned long long)phy->identify.sas_address, phy->number,
+	    phy_operation));
+	mpt2sas_base_put_smid_default(ioc, smid);
+	init_completion(&ioc->transport_cmds.done);
+	timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
+	    10*HZ);
+
+	if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
+		printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+		    ioc->name, __func__);
+		_debug_dump_mf(mpi_request,
+		    sizeof(Mpi2SmpPassthroughRequest_t)/4);
+		if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
+			issue_reset = 1;
+		goto issue_host_reset;
+	}
+
+	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - "
+	    "complete\n", ioc->name));
+
+	if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
+
+		mpi_reply = ioc->transport_cmds.reply;
+
+		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "phy_control - reply data transfer size(%d)\n",
+		    ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
+
+		if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
+		    sizeof(struct phy_control_reply))
+			goto out;
+
+		phy_control_reply = data_out +
+		    sizeof(struct phy_control_request);
+
+		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "phy_control - function_result(%d)\n",
+		    ioc->name, phy_control_reply->function_result));
+
+		rc = 0;
+	} else
+		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "phy_control - no reply\n", ioc->name));
+
+ issue_host_reset:
+	if (issue_reset)
+		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+		    FORCE_BIG_HAMMER);
+ out:
+	ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
+	if (data_out)
+		pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
+
+	mutex_unlock(&ioc->transport_cmds.mutex);
+	return rc;
+}
+
 /**
  * _transport_phy_reset -
  * @phy: The sas phy object
  * @hard_reset:
  *
- * Only support sas_host direct attached phys.
  * Returns 0 for success, non-zero for failure.
  */
 static int
 _transport_phy_reset(struct sas_phy *phy, int hard_reset)
 {
 	struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
-	struct _sas_phy *mpt2sas_phy;
 	Mpi2SasIoUnitControlReply_t mpi_reply;
 	Mpi2SasIoUnitControlRequest_t mpi_request;
+	unsigned long flags;
 
-	mpt2sas_phy = _transport_find_local_phy(ioc, phy);
-
-	if (!mpt2sas_phy) /* this phy not on sas_host */
+	spin_lock_irqsave(&ioc->sas_node_lock, flags);
+	if (_transport_sas_node_find_by_sas_address(ioc,
+	    phy->identify.sas_address) == NULL) {
+		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
 		return -EINVAL;
+	}
+	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
 
+	/* handle expander phys */
+	if (phy->identify.sas_address != ioc->sas_hba.sas_address)
+		return _transport_expander_phy_control(ioc, phy,
+		    (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :
+		    SMP_PHY_CONTROL_LINK_RESET);
+
+	/* handle hba phys */
 	memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t));
 	mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
 	mpi_request.Operation = hard_reset ?
 	    MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;
-	mpi_request.PhyNum = mpt2sas_phy->phy_id;
+	mpi_request.PhyNum = phy->number;
 
 	if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) {
 		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
@@ -1082,8 +1524,7 @@
 	if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
 		printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
 		    "(0x%04x), loginfo(0x%08x)\n", ioc->name,
-		    mpt2sas_phy->phy_id,
-		    le16_to_cpu(mpi_reply.IOCStatus),
+		    phy->number, le16_to_cpu(mpi_reply.IOCStatus),
 		    le32_to_cpu(mpi_reply.IOCLogInfo));
 
 	return 0;
@@ -1101,17 +1542,28 @@
 _transport_phy_enable(struct sas_phy *phy, int enable)
 {
 	struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
-	struct _sas_phy *mpt2sas_phy;
 	Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
 	Mpi2ConfigReply_t mpi_reply;
 	u16 ioc_status;
 	u16 sz;
 	int rc = 0;
+	unsigned long flags;
 
-	mpt2sas_phy = _transport_find_local_phy(ioc, phy);
-
-	if (!mpt2sas_phy) /* this phy not on sas_host */
+	spin_lock_irqsave(&ioc->sas_node_lock, flags);
+	if (_transport_sas_node_find_by_sas_address(ioc,
+	    phy->identify.sas_address) == NULL) {
+		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
 		return -EINVAL;
+	}
+	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+
+	/* handle expander phys */
+	if (phy->identify.sas_address != ioc->sas_hba.sas_address)
+		return _transport_expander_phy_control(ioc, phy,
+		    (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :
+		    SMP_PHY_CONTROL_DISABLE);
+
+	/* handle hba phys */
 
 	/* sas_iounit page 1 */
 	sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
@@ -1140,14 +1592,18 @@
 	}
 
 	if (enable)
-		sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
+		sas_iounit_pg1->PhyData[phy->number].PhyFlags
 		    &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
 	else
-		sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
+		sas_iounit_pg1->PhyData[phy->number].PhyFlags
 		    |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
 
 	mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz);
 
+	/* link reset */
+	if (enable)
+		_transport_phy_reset(phy, 0);
+
  out:
 	kfree(sas_iounit_pg1);
 	return rc;
@@ -1165,7 +1621,6 @@
 _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
 {
 	struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
-	struct _sas_phy *mpt2sas_phy;
 	Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
 	Mpi2SasPhyPage0_t phy_pg0;
 	Mpi2ConfigReply_t mpi_reply;
@@ -1173,11 +1628,15 @@
 	u16 sz;
 	int i;
 	int rc = 0;
+	unsigned long flags;
 
-	mpt2sas_phy = _transport_find_local_phy(ioc, phy);
-
-	if (!mpt2sas_phy) /* this phy not on sas_host */
+	spin_lock_irqsave(&ioc->sas_node_lock, flags);
+	if (_transport_sas_node_find_by_sas_address(ioc,
+	    phy->identify.sas_address) == NULL) {
+		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
 		return -EINVAL;
+	}
+	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
 
 	if (!rates->minimum_linkrate)
 		rates->minimum_linkrate = phy->minimum_linkrate;
@@ -1189,6 +1648,16 @@
 	else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
 		rates->maximum_linkrate = phy->maximum_linkrate_hw;
 
+	/* handle expander phys */
+	if (phy->identify.sas_address != ioc->sas_hba.sas_address) {
+		phy->minimum_linkrate = rates->minimum_linkrate;
+		phy->maximum_linkrate = rates->maximum_linkrate;
+		return _transport_expander_phy_control(ioc, phy,
+		    SMP_PHY_CONTROL_LINK_RESET);
+	}
+
+	/* handle hba phys */
+
 	/* sas_iounit page 1 */
 	sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
 	    sizeof(Mpi2SasIOUnit1PhyData_t));
@@ -1216,7 +1685,7 @@
 	}
 
 	for (i = 0; i < ioc->sas_hba.num_phys; i++) {
-		if (mpt2sas_phy->phy_id != i) {
+		if (phy->number != i) {
 			sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
 			    (ioc->sas_hba.phy[i].phy->minimum_linkrate +
 			    (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4));
@@ -1240,7 +1709,7 @@
 
 	/* read phy page 0, then update the rates in the sas transport phy */
 	if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
-	    mpt2sas_phy->phy_id)) {
+	    phy->number)) {
 		phy->minimum_linkrate = _transport_convert_phy_link_rate(
 		    phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
 		phy->maximum_linkrate = _transport_convert_phy_link_rate(
@@ -1392,7 +1861,7 @@
 	ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4),
 	    dma_addr_in);
 
-	dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
+	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
 	    "sending smp request\n", ioc->name, __func__));
 
 	mpt2sas_base_put_smid_default(ioc, smid);
@@ -1410,14 +1879,14 @@
 		goto issue_host_reset;
 	}
 
-	dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
+	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
 	    "complete\n", ioc->name, __func__));
 
 	if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
 
 		mpi_reply = ioc->transport_cmds.reply;
 
-		dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
 		    "%s - reply data transfer size(%d)\n",
 		    ioc->name, __func__,
 		    le16_to_cpu(mpi_reply->ResponseDataLength)));
@@ -1428,7 +1897,7 @@
 		rsp->resid_len -=
 		    le16_to_cpu(mpi_reply->ResponseDataLength);
 	} else {
-		dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
 		    "%s - no reply\n", ioc->name, __func__));
 		rc = -ENXIO;
 	}
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index f5e3217..adedaa9 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -1483,7 +1483,7 @@
 		}
 
 		if (task->task_status.resp == SAS_TASK_COMPLETE &&
-		    task->task_status.stat == SAM_GOOD) {
+		    task->task_status.stat == SAM_STAT_GOOD) {
 			res = TMF_RESP_FUNC_COMPLETE;
 			break;
 		}
@@ -1640,7 +1640,7 @@
 	struct mvs_tmf_task tmf_task;
 	struct domain_device *dev = task->dev;
 	struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
-	struct mvs_info *mvi = mvi_dev->mvi_info;
+	struct mvs_info *mvi;
 	int rc = TMF_RESP_FUNC_FAILED;
 	unsigned long flags;
 	u32 tag;
@@ -1650,6 +1650,8 @@
 		rc = TMF_RESP_FUNC_FAILED;
 	}
 
+	mvi = mvi_dev->mvi_info;
+
 	spin_lock_irqsave(&task->task_state_lock, flags);
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
@@ -1756,7 +1758,7 @@
 	struct mvs_device *mvi_dev = task->dev->lldd_dev;
 	struct task_status_struct *tstat = &task->task_status;
 	struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf;
-	int stat = SAM_GOOD;
+	int stat = SAM_STAT_GOOD;
 
 
 	resp->frame_len = sizeof(struct dev_to_host_fis);
@@ -1788,13 +1790,13 @@
 
 	MVS_CHIP_DISP->command_active(mvi, slot_idx);
 
-	stat = SAM_CHECK_COND;
+	stat = SAM_STAT_CHECK_CONDITION;
 	switch (task->task_proto) {
 	case SAS_PROTOCOL_SSP:
 		stat = SAS_ABORTED_TASK;
 		break;
 	case SAS_PROTOCOL_SMP:
-		stat = SAM_CHECK_COND;
+		stat = SAM_STAT_CHECK_CONDITION;
 		break;
 
 	case SAS_PROTOCOL_SATA:
@@ -1879,7 +1881,7 @@
 	case SAS_PROTOCOL_SSP:
 		/* hw says status == 0, datapres == 0 */
 		if (rx_desc & RXQ_GOOD) {
-			tstat->stat = SAM_GOOD;
+			tstat->stat = SAM_STAT_GOOD;
 			tstat->resp = SAS_TASK_COMPLETE;
 		}
 		/* response frame present */
@@ -1888,12 +1890,12 @@
 						sizeof(struct mvs_err_info);
 			sas_ssp_task_response(mvi->dev, task, iu);
 		} else
-			tstat->stat = SAM_CHECK_COND;
+			tstat->stat = SAM_STAT_CHECK_CONDITION;
 		break;
 
 	case SAS_PROTOCOL_SMP: {
 			struct scatterlist *sg_resp = &task->smp_task.smp_resp;
-			tstat->stat = SAM_GOOD;
+			tstat->stat = SAM_STAT_GOOD;
 			to = kmap_atomic(sg_page(sg_resp), KM_IRQ0);
 			memcpy(to + sg_resp->offset,
 				slot->response + sizeof(struct mvs_err_info),
@@ -1910,7 +1912,7 @@
 		}
 
 	default:
-		tstat->stat = SAM_CHECK_COND;
+		tstat->stat = SAM_STAT_CHECK_CONDITION;
 		break;
 	}
 	if (!slot->port->port_attached) {
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index e81efac..58d1134 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -1480,7 +1480,7 @@
 			",param = %d \n", param));
 		if (param == 0) {
 			ts->resp = SAS_TASK_COMPLETE;
-			ts->stat = SAM_GOOD;
+			ts->stat = SAM_STAT_GOOD;
 		} else {
 			ts->resp = SAS_TASK_COMPLETE;
 			ts->stat = SAS_PROTO_RESPONSE;
@@ -1909,7 +1909,7 @@
 		PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n"));
 		if (param == 0) {
 			ts->resp = SAS_TASK_COMPLETE;
-			ts->stat = SAM_GOOD;
+			ts->stat = SAM_STAT_GOOD;
 		} else {
 			u8 len;
 			ts->resp = SAS_TASK_COMPLETE;
@@ -2450,7 +2450,7 @@
 	case IO_SUCCESS:
 		PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n"));
 		ts->resp = SAS_TASK_COMPLETE;
-		ts->stat = SAM_GOOD;
+		ts->stat = SAM_STAT_GOOD;
 	if (pm8001_dev)
 			pm8001_dev->running_req--;
 		break;
@@ -2479,19 +2479,19 @@
 		PM8001_IO_DBG(pm8001_ha,
 			pm8001_printk("IO_ERROR_HW_TIMEOUT\n"));
 		ts->resp = SAS_TASK_COMPLETE;
-		ts->stat = SAM_BUSY;
+		ts->stat = SAM_STAT_BUSY;
 		break;
 	case IO_XFER_ERROR_BREAK:
 		PM8001_IO_DBG(pm8001_ha,
 			pm8001_printk("IO_XFER_ERROR_BREAK\n"));
 		ts->resp = SAS_TASK_COMPLETE;
-		ts->stat = SAM_BUSY;
+		ts->stat = SAM_STAT_BUSY;
 		break;
 	case IO_XFER_ERROR_PHY_NOT_READY:
 		PM8001_IO_DBG(pm8001_ha,
 			pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n"));
 		ts->resp = SAS_TASK_COMPLETE;
-		ts->stat = SAM_BUSY;
+		ts->stat = SAM_STAT_BUSY;
 		break;
 	case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
 		PM8001_IO_DBG(pm8001_ha,
@@ -3260,7 +3260,7 @@
 	case IO_SUCCESS:
 		PM8001_EH_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n"));
 		ts->resp = SAS_TASK_COMPLETE;
-		ts->stat = SAM_GOOD;
+		ts->stat = SAM_STAT_GOOD;
 		break;
 	case IO_NOT_VALID:
 		PM8001_EH_DBG(pm8001_ha, pm8001_printk("IO_NOT_VALID\n"));
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index cd02cea..6ae059e 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -763,7 +763,7 @@
 		}
 
 		if (task->task_status.resp == SAS_TASK_COMPLETE &&
-			task->task_status.stat == SAM_GOOD) {
+			task->task_status.stat == SAM_STAT_GOOD) {
 			res = TMF_RESP_FUNC_COMPLETE;
 			break;
 		}
@@ -853,7 +853,7 @@
 		}
 
 		if (task->task_status.resp == SAS_TASK_COMPLETE &&
-			task->task_status.stat == SAM_GOOD) {
+			task->task_status.stat == SAM_STAT_GOOD) {
 			res = TMF_RESP_FUNC_COMPLETE;
 			break;
 
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index c44e4ab..ecc45c8 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -113,6 +113,7 @@
 	 .global_intr_mask = 0x00034,
 	 .ioa_host_intr = 0x0009C,
 	 .ioa_host_intr_clr = 0x000A0,
+	 .ioa_host_msix_intr = 0x7FC40,
 	 .ioa_host_mask = 0x7FC28,
 	 .ioa_host_mask_clr = 0x7FC28,
 	 .host_ioa_intr = 0x00020,
@@ -154,8 +155,12 @@
 	u8 target, bus, lun;
 	unsigned long lock_flags;
 	int rc = -ENXIO;
+	u16 fw_version;
+
 	pinstance = shost_priv(scsi_dev->host);
 
+	fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
+
 	/* Driver exposes VSET and GSCSI resources only; all other device types
 	 * are not exposed. Resource list is synchronized using resource lock
 	 * so any traversal or modifications to the list should be done inside
@@ -166,7 +171,11 @@
 
 		/* do not expose VSETs with order-ids > MAX_VSET_TARGETS */
 		if (RES_IS_VSET(temp->cfg_entry)) {
-			target = temp->cfg_entry.unique_flags1;
+			if (fw_version <= PMCRAID_FW_VERSION_1)
+				target = temp->cfg_entry.unique_flags1;
+			else
+				target = temp->cfg_entry.array_id & 0xFF;
+
 			if (target > PMCRAID_MAX_VSET_TARGETS)
 				continue;
 			bus = PMCRAID_VSET_BUS_ID;
@@ -283,7 +292,7 @@
  * @reason: calling context
  *
  * Return value
- * 	actual depth set
+ *	actual depth set
  */
 static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth,
 				      int reason)
@@ -305,7 +314,7 @@
  * @tag: type of tags to use
  *
  * Return value:
- * 	actual queue type set
+ *	actual queue type set
  */
 static int pmcraid_change_queue_type(struct scsi_device *scsi_dev, int tag)
 {
@@ -357,6 +366,7 @@
 		 * processed by IOA
 		 */
 		memset(&cmd->ioa_cb->ioarcb.cdb, 0, PMCRAID_MAX_CDB_LEN);
+		ioarcb->hrrq_id = 0;
 		ioarcb->request_flags0 = 0;
 		ioarcb->request_flags1 = 0;
 		ioarcb->cmd_timeout = 0;
@@ -368,13 +378,15 @@
 		ioarcb->add_cmd_param_offset = 0;
 		cmd->ioa_cb->ioasa.ioasc = 0;
 		cmd->ioa_cb->ioasa.residual_data_length = 0;
-		cmd->u.time_left = 0;
+		cmd->time_left = 0;
 	}
 
 	cmd->cmd_done = NULL;
 	cmd->scsi_cmd = NULL;
 	cmd->release = 0;
 	cmd->completion_req = 0;
+	cmd->sense_buffer = 0;
+	cmd->sense_buffer_dma = 0;
 	cmd->dma_handle = 0;
 	init_timer(&cmd->timer);
 }
@@ -449,7 +461,9 @@
  */
 static u32 pmcraid_read_interrupts(struct pmcraid_instance *pinstance)
 {
-	return ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
+	return (pinstance->interrupt_mode) ?
+		ioread32(pinstance->int_regs.ioa_host_msix_interrupt_reg) :
+		ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
 }
 
 /**
@@ -469,10 +483,15 @@
 	u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg);
 	u32 nmask = gmask | GLOBAL_INTERRUPT_MASK;
 
-	iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg);
 	iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_clr_reg);
-	iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_mask_reg);
-	ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+	iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg);
+	ioread32(pinstance->int_regs.global_interrupt_mask_reg);
+
+	if (!pinstance->interrupt_mode) {
+		iowrite32(intrs,
+			pinstance->int_regs.ioa_host_interrupt_mask_reg);
+		ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+	}
 }
 
 /**
@@ -493,8 +512,12 @@
 	u32 nmask = gmask & (~GLOBAL_INTERRUPT_MASK);
 
 	iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg);
-	iowrite32(~intrs, pinstance->int_regs.ioa_host_interrupt_mask_reg);
-	ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+
+	if (!pinstance->interrupt_mode) {
+		iowrite32(~intrs,
+			 pinstance->int_regs.ioa_host_interrupt_mask_reg);
+		ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+	}
 
 	pmcraid_info("enabled interrupts global mask = %x intr_mask = %x\n",
 		ioread32(pinstance->int_regs.global_interrupt_mask_reg),
@@ -502,6 +525,39 @@
 }
 
 /**
+ * pmcraid_clr_trans_op - clear trans to op interrupt
+ *
+ * @pinstance: pointer to per adapter instance structure
+ *
+ * Return Value
+ *	 None
+ */
+static void pmcraid_clr_trans_op(
+	struct pmcraid_instance *pinstance
+)
+{
+	unsigned long lock_flags;
+
+	if (!pinstance->interrupt_mode) {
+		iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
+			pinstance->int_regs.ioa_host_interrupt_mask_reg);
+		ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+		iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
+			pinstance->int_regs.ioa_host_interrupt_clr_reg);
+		ioread32(pinstance->int_regs.ioa_host_interrupt_clr_reg);
+	}
+
+	if (pinstance->reset_cmd != NULL) {
+		del_timer(&pinstance->reset_cmd->timer);
+		spin_lock_irqsave(
+			pinstance->host->host_lock, lock_flags);
+		pinstance->reset_cmd->cmd_done(pinstance->reset_cmd);
+		spin_unlock_irqrestore(
+			pinstance->host->host_lock, lock_flags);
+	}
+}
+
+/**
  * pmcraid_reset_type - Determine the required reset type
  * @pinstance: pointer to adapter instance structure
  *
@@ -536,7 +592,7 @@
  * pmcraid_bist_done - completion function for PCI BIST
  * @cmd: pointer to reset command
  * Return Value
- * 	none
+ *	none
  */
 
 static void pmcraid_ioa_reset(struct pmcraid_cmd *);
@@ -552,16 +608,16 @@
 
 	/* If PCI config space can't be accessed wait for another two secs */
 	if ((rc != PCIBIOS_SUCCESSFUL || (!(pci_reg & PCI_COMMAND_MEMORY))) &&
-	    cmd->u.time_left > 0) {
+	    cmd->time_left > 0) {
 		pmcraid_info("BIST not complete, waiting another 2 secs\n");
-		cmd->timer.expires = jiffies + cmd->u.time_left;
-		cmd->u.time_left = 0;
+		cmd->timer.expires = jiffies + cmd->time_left;
+		cmd->time_left = 0;
 		cmd->timer.data = (unsigned long)cmd;
 		cmd->timer.function =
 			(void (*)(unsigned long))pmcraid_bist_done;
 		add_timer(&cmd->timer);
 	} else {
-		cmd->u.time_left = 0;
+		cmd->time_left = 0;
 		pmcraid_info("BIST is complete, proceeding with reset\n");
 		spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
 		pmcraid_ioa_reset(cmd);
@@ -585,10 +641,10 @@
 		pinstance->int_regs.host_ioa_interrupt_reg);
 	doorbells = ioread32(pinstance->int_regs.host_ioa_interrupt_reg);
 	intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
-	pmcraid_info("doorbells after start bist: %x intrs: %x \n",
+	pmcraid_info("doorbells after start bist: %x intrs: %x\n",
 		      doorbells, intrs);
 
-	cmd->u.time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT);
+	cmd->time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT);
 	cmd->timer.data = (unsigned long)cmd;
 	cmd->timer.expires = jiffies + msecs_to_jiffies(PMCRAID_BIST_TIMEOUT);
 	cmd->timer.function = (void (*)(unsigned long))pmcraid_bist_done;
@@ -612,7 +668,7 @@
 	 * some more time to wait, restart the timer
 	 */
 	if (((status & INTRS_CRITICAL_OP_IN_PROGRESS) == 0) ||
-	    cmd->u.time_left <= 0) {
+	    cmd->time_left <= 0) {
 		pmcraid_info("critical op is reset proceeding with reset\n");
 		spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
 		pmcraid_ioa_reset(cmd);
@@ -620,7 +676,7 @@
 	} else {
 		pmcraid_info("critical op is not yet reset waiting again\n");
 		/* restart timer if some more time is available to wait */
-		cmd->u.time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT;
+		cmd->time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT;
 		cmd->timer.data = (unsigned long)cmd;
 		cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT;
 		cmd->timer.function =
@@ -638,6 +694,7 @@
  *	successfully written to IOA. Returns non-zero in case pci_config_space
  *	is not accessible
  */
+static void pmcraid_notify_ioastate(struct pmcraid_instance *, u32);
 static void pmcraid_reset_alert(struct pmcraid_cmd *cmd)
 {
 	struct pmcraid_instance *pinstance = cmd->drv_inst;
@@ -658,7 +715,7 @@
 		 * OPERATION bit is reset. A timer is started to wait for this
 		 * bit to be reset.
 		 */
-		cmd->u.time_left = PMCRAID_RESET_TIMEOUT;
+		cmd->time_left = PMCRAID_RESET_TIMEOUT;
 		cmd->timer.data = (unsigned long)cmd;
 		cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT;
 		cmd->timer.function =
@@ -693,7 +750,8 @@
 	unsigned long lock_flags;
 
 	dev_info(&pinstance->pdev->dev,
-		"Adapter being reset due to command timeout.\n");
+		"Adapter being reset due to cmd(CDB[0] = %x) timeout\n",
+		cmd->ioa_cb->ioarcb.cdb[0]);
 
 	/* Command timeouts result in hard reset sequence. The command that got
 	 * timed out may be the one used as part of reset sequence. In this
@@ -736,9 +794,14 @@
 		 */
 		if (cmd == pinstance->reset_cmd)
 			cmd->cmd_done = pmcraid_ioa_reset;
-
 	}
 
+	/* Notify apps of important IOA bringup/bringdown sequences */
+	if (pinstance->scn.ioa_state != PMC_DEVICE_EVENT_RESET_START &&
+	    pinstance->scn.ioa_state != PMC_DEVICE_EVENT_SHUTDOWN_START)
+		pmcraid_notify_ioastate(pinstance,
+					PMC_DEVICE_EVENT_RESET_START);
+
 	pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
 	scsi_block_requests(pinstance->host);
 	pmcraid_reset_alert(cmd);
@@ -866,7 +929,7 @@
 	/* Add this command block to pending cmd pool. We do this prior to
 	 * writting IOARCB to ioarrin because IOA might complete the command
 	 * by the time we are about to add it to the list. Response handler
-	 * (isr/tasklet) looks for cmb block in the pending pending list.
+	 * (isr/tasklet) looks for cmd block in the pending pending list.
 	 */
 	spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags);
 	list_add_tail(&cmd->free_list, &pinstance->pending_cmd_pool);
@@ -916,6 +979,23 @@
 }
 
 /**
+ * pmcraid_ioa_shutdown_done - completion function for IOA shutdown command
+ * @cmd: pointer to the command block used for sending IOA shutdown command
+ *
+ * Return value
+ *  None
+ */
+static void pmcraid_ioa_shutdown_done(struct pmcraid_cmd *cmd)
+{
+	struct pmcraid_instance *pinstance = cmd->drv_inst;
+	unsigned long lock_flags;
+
+	spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
+	pmcraid_ioa_reset(cmd);
+	spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+}
+
+/**
  * pmcraid_ioa_shutdown - sends SHUTDOWN command to ioa
  *
  * @cmd: pointer to the command block used as part of reset sequence
@@ -943,30 +1023,112 @@
 	pmcraid_info("firing normal shutdown command (%d) to IOA\n",
 		     le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle));
 
-	pmcraid_send_cmd(cmd, pmcraid_ioa_reset,
+	pmcraid_notify_ioastate(cmd->drv_inst, PMC_DEVICE_EVENT_SHUTDOWN_START);
+
+	pmcraid_send_cmd(cmd, pmcraid_ioa_shutdown_done,
 			 PMCRAID_SHUTDOWN_TIMEOUT,
 			 pmcraid_timeout_handler);
 }
 
 /**
+ * pmcraid_get_fwversion_done - completion function for get_fwversion
+ *
+ * @cmd: pointer to command block used to send INQUIRY command
+ *
+ * Return Value
+ *	none
+ */
+static void pmcraid_querycfg(struct pmcraid_cmd *);
+
+static void pmcraid_get_fwversion_done(struct pmcraid_cmd *cmd)
+{
+	struct pmcraid_instance *pinstance = cmd->drv_inst;
+	u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc);
+	unsigned long lock_flags;
+
+	/* configuration table entry size depends on firmware version. If fw
+	 * version is not known, it is not possible to interpret IOA config
+	 * table
+	 */
+	if (ioasc) {
+		pmcraid_err("IOA Inquiry failed with %x\n", ioasc);
+		spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
+		pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
+		pmcraid_reset_alert(cmd);
+		spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+	} else  {
+		pmcraid_querycfg(cmd);
+	}
+}
+
+/**
+ * pmcraid_get_fwversion - reads firmware version information
+ *
+ * @cmd: pointer to command block used to send INQUIRY command
+ *
+ * Return Value
+ *	none
+ */
+static void pmcraid_get_fwversion(struct pmcraid_cmd *cmd)
+{
+	struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb;
+	struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl;
+	struct pmcraid_instance *pinstance = cmd->drv_inst;
+	u16 data_size = sizeof(struct pmcraid_inquiry_data);
+
+	pmcraid_reinit_cmdblk(cmd);
+	ioarcb->request_type = REQ_TYPE_SCSI;
+	ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE);
+	ioarcb->cdb[0] = INQUIRY;
+	ioarcb->cdb[1] = 1;
+	ioarcb->cdb[2] = 0xD0;
+	ioarcb->cdb[3] = (data_size >> 8) & 0xFF;
+	ioarcb->cdb[4] = data_size & 0xFF;
+
+	/* Since entire inquiry data it can be part of IOARCB itself
+	 */
+	ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) +
+					offsetof(struct pmcraid_ioarcb,
+						add_data.u.ioadl[0]));
+	ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc));
+	ioarcb->ioarcb_bus_addr &= ~(0x1FULL);
+
+	ioarcb->request_flags0 |= NO_LINK_DESCS;
+	ioarcb->data_transfer_length = cpu_to_le32(data_size);
+	ioadl = &(ioarcb->add_data.u.ioadl[0]);
+	ioadl->flags = IOADL_FLAGS_LAST_DESC;
+	ioadl->address = cpu_to_le64(pinstance->inq_data_baddr);
+	ioadl->data_len = cpu_to_le32(data_size);
+
+	pmcraid_send_cmd(cmd, pmcraid_get_fwversion_done,
+			 PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler);
+}
+
+/**
  * pmcraid_identify_hrrq - registers host rrq buffers with IOA
  * @cmd: pointer to command block to be used for identify hrrq
  *
  * Return Value
- *	 0 in case of success, otherwise non-zero failure code
+ *	 none
  */
-
-static void pmcraid_querycfg(struct pmcraid_cmd *);
-
 static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd)
 {
 	struct pmcraid_instance *pinstance = cmd->drv_inst;
 	struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb;
-	int index = 0;
+	int index = cmd->hrrq_index;
 	__be64 hrrq_addr = cpu_to_be64(pinstance->hrrq_start_bus_addr[index]);
 	u32 hrrq_size = cpu_to_be32(sizeof(u32) * PMCRAID_MAX_CMD);
+	void (*done_function)(struct pmcraid_cmd *);
 
 	pmcraid_reinit_cmdblk(cmd);
+	cmd->hrrq_index = index + 1;
+
+	if (cmd->hrrq_index < pinstance->num_hrrq) {
+		done_function = pmcraid_identify_hrrq;
+	} else {
+		cmd->hrrq_index = 0;
+		done_function = pmcraid_get_fwversion;
+	}
 
 	/* Initialize ioarcb */
 	ioarcb->request_type = REQ_TYPE_IOACMD;
@@ -980,8 +1142,8 @@
 	/* IOA expects 64-bit pci address to be written in B.E format
 	 * (i.e cdb[2]=MSByte..cdb[9]=LSB.
 	 */
-	pmcraid_info("HRRQ_IDENTIFY with hrrq:ioarcb => %llx:%llx\n",
-		     hrrq_addr, ioarcb->ioarcb_bus_addr);
+	pmcraid_info("HRRQ_IDENTIFY with hrrq:ioarcb:index => %llx:%llx:%x\n",
+		     hrrq_addr, ioarcb->ioarcb_bus_addr, index);
 
 	memcpy(&(ioarcb->cdb[2]), &hrrq_addr, sizeof(hrrq_addr));
 	memcpy(&(ioarcb->cdb[10]), &hrrq_size, sizeof(hrrq_size));
@@ -990,7 +1152,7 @@
 	 * Note that this gets called even during reset from SCSI mid-layer
 	 * or tasklet
 	 */
-	pmcraid_send_cmd(cmd, pmcraid_querycfg,
+	pmcraid_send_cmd(cmd, done_function,
 			 PMCRAID_INTERNAL_TIMEOUT,
 			 pmcraid_timeout_handler);
 }
@@ -1047,7 +1209,7 @@
 	}
 
 	if (type == PMCRAID_HCAM_CODE_CONFIG_CHANGE) {
-		rcb_size = sizeof(struct pmcraid_hcam_ccn);
+		rcb_size = sizeof(struct pmcraid_hcam_ccn_ext);
 		cmd_done = pmcraid_process_ccn;
 		dma = pinstance->ccn.baddr + PMCRAID_AEN_HDR_SIZE;
 		hcam = &pinstance->ccn;
@@ -1094,7 +1256,7 @@
  * This function will send a Host Controlled Async command to IOA.
  *
  * Return value:
- * 	none
+ *	none
  */
 static void pmcraid_send_hcam(struct pmcraid_instance *pinstance, u8 type)
 {
@@ -1202,18 +1364,25 @@
 /**
  * pmcraid_expose_resource - check if the resource can be exposed to OS
  *
+ * @fw_version: firmware version code
  * @cfgte: pointer to configuration table entry of the resource
  *
  * Return value:
- * 	true if resource can be added to midlayer, false(0) otherwise
+ *	true if resource can be added to midlayer, false(0) otherwise
  */
-static int pmcraid_expose_resource(struct pmcraid_config_table_entry *cfgte)
+static int pmcraid_expose_resource(u16 fw_version,
+				   struct pmcraid_config_table_entry *cfgte)
 {
 	int retval = 0;
 
-	if (cfgte->resource_type == RES_TYPE_VSET)
-		retval = ((cfgte->unique_flags1 & 0x80) == 0);
-	else if (cfgte->resource_type == RES_TYPE_GSCSI)
+	if (cfgte->resource_type == RES_TYPE_VSET) {
+		if (fw_version <= PMCRAID_FW_VERSION_1)
+			retval = ((cfgte->unique_flags1 & 0x80) == 0);
+		else
+			retval = ((cfgte->unique_flags0 & 0x80) == 0 &&
+				  (cfgte->unique_flags1 & 0x80) == 0);
+
+	} else if (cfgte->resource_type == RES_TYPE_GSCSI)
 		retval = (RES_BUS(cfgte->resource_address) !=
 				PMCRAID_VIRTUAL_ENCL_BUS_ID);
 	return retval;
@@ -1246,8 +1415,8 @@
  * pmcraid_netlink_init - registers pmcraid_event_family
  *
  * Return value:
- * 	0 if the pmcraid_event_family is successfully registered
- * 	with netlink generic, non-zero otherwise
+ *	0 if the pmcraid_event_family is successfully registered
+ *	with netlink generic, non-zero otherwise
  */
 static int pmcraid_netlink_init(void)
 {
@@ -1268,7 +1437,7 @@
  * pmcraid_netlink_release - unregisters pmcraid_event_family
  *
  * Return value:
- * 	none
+ *	none
  */
 static void pmcraid_netlink_release(void)
 {
@@ -1283,31 +1452,30 @@
  * Return value:
  *	0 if success, error value in case of any failure.
  */
-static int pmcraid_notify_aen(struct pmcraid_instance *pinstance, u8 type)
+static int pmcraid_notify_aen(
+	struct pmcraid_instance *pinstance,
+	struct pmcraid_aen_msg  *aen_msg,
+	u32    data_size
+)
 {
 	struct sk_buff *skb;
-	struct pmcraid_aen_msg *aen_msg;
 	void *msg_header;
-	int data_size, total_size;
+	u32  total_size, nla_genl_hdr_total_size;
 	int result;
 
-
-	if (type == PMCRAID_HCAM_CODE_LOG_DATA) {
-		aen_msg = pinstance->ldn.msg;
-		data_size = pinstance->ldn.hcam->data_len;
-	} else {
-		aen_msg = pinstance->ccn.msg;
-		data_size = pinstance->ccn.hcam->data_len;
-	}
-
-	data_size += sizeof(struct pmcraid_hcam_hdr);
 	aen_msg->hostno = (pinstance->host->unique_id << 16 |
 			   MINOR(pinstance->cdev.dev));
 	aen_msg->length = data_size;
+
 	data_size += sizeof(*aen_msg);
 
 	total_size = nla_total_size(data_size);
-	skb = genlmsg_new(total_size, GFP_ATOMIC);
+	/* Add GENL_HDR to total_size */
+	nla_genl_hdr_total_size =
+		(total_size + (GENL_HDRLEN +
+		((struct genl_family *)&pmcraid_event_family)->hdrsize)
+		 + NLMSG_HDRLEN);
+	skb = genlmsg_new(nla_genl_hdr_total_size, GFP_ATOMIC);
 
 
 	if (!skb) {
@@ -1329,7 +1497,7 @@
 	result = nla_put(skb, PMCRAID_AEN_ATTR_EVENT, data_size, aen_msg);
 
 	if (result) {
-		pmcraid_err("failed to copy AEN attribute data \n");
+		pmcraid_err("failed to copy AEN attribute data\n");
 		nlmsg_free(skb);
 		return -EINVAL;
 	}
@@ -1350,13 +1518,57 @@
 	 * value.
 	 */
 	if (result)
-		pmcraid_info("failed to send %s event message %x!\n",
-			type == PMCRAID_HCAM_CODE_LOG_DATA ? "LDN" : "CCN",
-			result);
+		pmcraid_info("error (%x) sending aen event message\n", result);
 	return result;
 }
 
 /**
+ * pmcraid_notify_ccn - notifies about CCN event msg to user space
+ * @pinstance: pointer adapter instance structure
+ *
+ * Return value:
+ *	0 if success, error value in case of any failure
+ */
+static int pmcraid_notify_ccn(struct pmcraid_instance *pinstance)
+{
+	return pmcraid_notify_aen(pinstance,
+				pinstance->ccn.msg,
+				pinstance->ccn.hcam->data_len +
+				sizeof(struct pmcraid_hcam_hdr));
+}
+
+/**
+ * pmcraid_notify_ldn - notifies about CCN event msg to user space
+ * @pinstance: pointer adapter instance structure
+ *
+ * Return value:
+ *	0 if success, error value in case of any failure
+ */
+static int pmcraid_notify_ldn(struct pmcraid_instance *pinstance)
+{
+	return pmcraid_notify_aen(pinstance,
+				pinstance->ldn.msg,
+				pinstance->ldn.hcam->data_len +
+				sizeof(struct pmcraid_hcam_hdr));
+}
+
+/**
+ * pmcraid_notify_ioastate - sends IOA state event msg to user space
+ * @pinstance: pointer adapter instance structure
+ * @evt: controller state event to be sent
+ *
+ * Return value:
+ *	0 if success, error value in case of any failure
+ */
+static void pmcraid_notify_ioastate(struct pmcraid_instance *pinstance, u32 evt)
+{
+	pinstance->scn.ioa_state = evt;
+	pmcraid_notify_aen(pinstance,
+			  &pinstance->scn.msg,
+			  sizeof(u32));
+}
+
+/**
  * pmcraid_handle_config_change - Handle a config change from the adapter
  * @pinstance: pointer to per adapter instance structure
  *
@@ -1375,10 +1587,12 @@
 	unsigned long host_lock_flags;
 	u32 new_entry = 1;
 	u32 hidden_entry = 0;
+	u16 fw_version;
 	int rc;
 
 	ccn_hcam = (struct pmcraid_hcam_ccn *)pinstance->ccn.hcam;
 	cfg_entry = &ccn_hcam->cfg_entry;
+	fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
 
 	pmcraid_info
 		("CCN(%x): %x type: %x lost: %x flags: %x res: %x:%x:%x:%x\n",
@@ -1391,7 +1605,10 @@
 		 RES_IS_VSET(*cfg_entry) ? PMCRAID_VSET_BUS_ID :
 		 (RES_IS_GSCSI(*cfg_entry) ? PMCRAID_PHYS_BUS_ID :
 			RES_BUS(cfg_entry->resource_address)),
-		 RES_IS_VSET(*cfg_entry) ? cfg_entry->unique_flags1 :
+		 RES_IS_VSET(*cfg_entry) ?
+			(fw_version <= PMCRAID_FW_VERSION_1 ?
+				cfg_entry->unique_flags1 :
+					cfg_entry->array_id & 0xFF) :
 			RES_TARGET(cfg_entry->resource_address),
 		 RES_LUN(cfg_entry->resource_address));
 
@@ -1415,11 +1632,16 @@
 	 */
 	if (pinstance->ccn.hcam->notification_type ==
 	    NOTIFICATION_TYPE_ENTRY_CHANGED &&
-	    cfg_entry->resource_type == RES_TYPE_VSET &&
-	    cfg_entry->unique_flags1 & 0x80) {
-		hidden_entry = 1;
-	} else if (!pmcraid_expose_resource(cfg_entry))
+	    cfg_entry->resource_type == RES_TYPE_VSET) {
+
+		if (fw_version <= PMCRAID_FW_VERSION_1)
+			hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0;
+		else
+			hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0;
+
+	} else if (!pmcraid_expose_resource(fw_version, cfg_entry)) {
 		goto out_notify_apps;
+	}
 
 	spin_lock_irqsave(&pinstance->resource_lock, lock_flags);
 	list_for_each_entry(res, &pinstance->used_res_q, queue) {
@@ -1466,13 +1688,15 @@
 		list_add_tail(&res->queue, &pinstance->used_res_q);
 	}
 
-	memcpy(&res->cfg_entry, cfg_entry,
-		sizeof(struct pmcraid_config_table_entry));
+	memcpy(&res->cfg_entry, cfg_entry, pinstance->config_table_entry_size);
 
 	if (pinstance->ccn.hcam->notification_type ==
 	    NOTIFICATION_TYPE_ENTRY_DELETED || hidden_entry) {
 		if (res->scsi_dev) {
-			res->cfg_entry.unique_flags1 &= 0x7F;
+			if (fw_version <= PMCRAID_FW_VERSION_1)
+				res->cfg_entry.unique_flags1 &= 0x7F;
+			else
+				res->cfg_entry.array_id &= 0xFF;
 			res->change_detected = RES_CHANGE_DEL;
 			res->cfg_entry.resource_handle =
 				PMCRAID_INVALID_RES_HANDLE;
@@ -1491,7 +1715,7 @@
 
 	/* Notify configuration changes to registered applications.*/
 	if (!pmcraid_disable_aen)
-		pmcraid_notify_aen(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE);
+		pmcraid_notify_ccn(pinstance);
 
 	cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE);
 	if (cmd)
@@ -1528,7 +1752,7 @@
 		return;
 
 	/* log the error string */
-	pmcraid_err("cmd [%d] for resource %x failed with %x(%s)\n",
+	pmcraid_err("cmd [%x] for resource %x failed with %x(%s)\n",
 		cmd->ioa_cb->ioarcb.cdb[0],
 		cmd->ioa_cb->ioarcb.resource_handle,
 		le32_to_cpu(ioasc), error_info->error_string);
@@ -1663,7 +1887,7 @@
 	}
 	/* send netlink message for HCAM notification if enabled */
 	if (!pmcraid_disable_aen)
-		pmcraid_notify_aen(pinstance, PMCRAID_HCAM_CODE_LOG_DATA);
+		pmcraid_notify_ldn(pinstance);
 
 	cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA);
 	if (cmd)
@@ -1701,10 +1925,13 @@
 	atomic_set(&pinstance->ldn.ignore, 1);
 
 	/* If adapter reset was forced as part of runtime reset sequence,
-	 * start the reset sequence.
+	 * start the reset sequence. Reset will be triggered even in case
+	 * IOA unit_check.
 	 */
-	if (pinstance->force_ioa_reset && !pinstance->ioa_bringdown) {
+	if ((pinstance->force_ioa_reset && !pinstance->ioa_bringdown) ||
+	     pinstance->ioa_unit_check) {
 		pinstance->force_ioa_reset = 0;
+		pinstance->ioa_unit_check = 0;
 		pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
 		pmcraid_reset_alert(cmd);
 		return;
@@ -1735,10 +1962,13 @@
 	pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS);
 
 	if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) {
-		iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
-			pinstance->int_regs.ioa_host_interrupt_mask_reg);
-		iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
-			pinstance->int_regs.ioa_host_interrupt_clr_reg);
+		if (!pinstance->interrupt_mode) {
+			iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
+				pinstance->int_regs.
+				ioa_host_interrupt_mask_reg);
+			iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
+				pinstance->int_regs.ioa_host_interrupt_clr_reg);
+		}
 		return 1;
 	} else {
 		return 0;
@@ -1777,8 +2007,19 @@
 	doorbell = DOORBELL_RUNTIME_RESET |
 		   DOORBELL_ENABLE_DESTRUCTIVE_DIAGS;
 
+	/* Since we do RESET_ALERT and Start BIST we have to again write
+	 * MSIX Doorbell to indicate the interrupt mode
+	 */
+	if (pinstance->interrupt_mode) {
+		iowrite32(DOORBELL_INTR_MODE_MSIX,
+			  pinstance->int_regs.host_ioa_interrupt_reg);
+		ioread32(pinstance->int_regs.host_ioa_interrupt_reg);
+	}
+
 	iowrite32(doorbell, pinstance->int_regs.host_ioa_interrupt_reg);
+	ioread32(pinstance->int_regs.host_ioa_interrupt_reg),
 	int_reg = ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
+
 	pmcraid_info("Waiting for IOA to become operational %x:%x\n",
 		     ioread32(pinstance->int_regs.host_ioa_interrupt_reg),
 		     int_reg);
@@ -1854,7 +2095,8 @@
 		} else if (cmd->cmd_done == pmcraid_internal_done ||
 			   cmd->cmd_done == pmcraid_erp_done) {
 			cmd->cmd_done(cmd);
-		} else if (cmd->cmd_done != pmcraid_ioa_reset) {
+		} else if (cmd->cmd_done != pmcraid_ioa_reset &&
+			   cmd->cmd_done != pmcraid_ioa_shutdown_done) {
 			pmcraid_return_cmd(cmd);
 		}
 
@@ -1964,6 +2206,13 @@
 			pinstance->ioa_reset_attempts = 0;
 			pmcraid_err("IOA didn't respond marking it as dead\n");
 			pinstance->ioa_state = IOA_STATE_DEAD;
+
+			if (pinstance->ioa_bringdown)
+				pmcraid_notify_ioastate(pinstance,
+					PMC_DEVICE_EVENT_SHUTDOWN_FAILED);
+			else
+				pmcraid_notify_ioastate(pinstance,
+						PMC_DEVICE_EVENT_RESET_FAILED);
 			reset_complete = 1;
 			break;
 		}
@@ -1971,7 +2220,6 @@
 		/* Once either bist or pci reset is done, restore PCI config
 		 * space. If this fails, proceed with hard reset again
 		 */
-
 		if (pci_restore_state(pinstance->pdev)) {
 			pmcraid_info("config-space error resetting again\n");
 			pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
@@ -2002,6 +2250,8 @@
 			pinstance->ioa_shutdown_type = SHUTDOWN_NONE;
 			pinstance->ioa_bringdown = 0;
 			pinstance->ioa_state = IOA_STATE_UNKNOWN;
+			pmcraid_notify_ioastate(pinstance,
+					PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS);
 			reset_complete = 1;
 		} else {
 			/* bring-up IOA, so proceed with soft reset
@@ -2051,6 +2301,8 @@
 		 */
 		if (pinstance->ioa_shutdown_type == SHUTDOWN_NONE &&
 		    pinstance->force_ioa_reset == 0) {
+			pmcraid_notify_ioastate(pinstance,
+						PMC_DEVICE_EVENT_RESET_SUCCESS);
 			reset_complete = 1;
 		} else {
 			if (pinstance->ioa_shutdown_type != SHUTDOWN_NONE)
@@ -2116,6 +2368,8 @@
 		pinstance->ioa_shutdown_type = SHUTDOWN_NONE;
 		pinstance->reset_cmd = cmd;
 		pinstance->force_ioa_reset = 1;
+		pmcraid_notify_ioastate(pinstance,
+					PMC_DEVICE_EVENT_RESET_START);
 		pmcraid_ioa_reset(cmd);
 	}
 }
@@ -2191,7 +2445,7 @@
 		wait_event(pinstance->reset_wait_q,
 			   !pinstance->ioa_reset_in_progress);
 
-		pmcraid_info("reset_reload: reset is complete !! \n");
+		pmcraid_info("reset_reload: reset is complete !!\n");
 		scsi_unblock_requests(pinstance->host);
 		if (pinstance->ioa_state == target_state)
 			reset = 0;
@@ -2225,6 +2479,8 @@
  */
 static int pmcraid_reset_bringup(struct pmcraid_instance *pinstance)
 {
+	pmcraid_notify_ioastate(pinstance, PMC_DEVICE_EVENT_RESET_START);
+
 	return pmcraid_reset_reload(pinstance,
 				    SHUTDOWN_NONE,
 				    IOA_STATE_OPERATIONAL);
@@ -2704,7 +2960,7 @@
 
 	pmcraid_info("command (%d) CDB[0] = %x for %x\n",
 		le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.response_handle) >> 2,
-		cmd->ioa_cb->ioarcb.cdb[0],
+		cancel_cmd->ioa_cb->ioarcb.cdb[0],
 		le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.resource_handle));
 
 	pmcraid_send_cmd(cancel_cmd,
@@ -2729,8 +2985,8 @@
 	u32 ioasc;
 
 	wait_for_completion(&cancel_cmd->wait_for_completion);
-	res = cancel_cmd->u.res;
-	cancel_cmd->u.res = NULL;
+	res = cancel_cmd->res;
+	cancel_cmd->res = NULL;
 	ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc);
 
 	/* If the abort task is not timed out we will get a Good completion
@@ -2823,7 +3079,7 @@
 			       host_lock_flags);
 
 	if (cancel_cmd) {
-		cancel_cmd->u.res = cmd->scsi_cmd->device->hostdata;
+		cancel_cmd->res = cmd->scsi_cmd->device->hostdata;
 		rc = pmcraid_abort_complete(cancel_cmd);
 	}
 
@@ -2842,7 +3098,7 @@
  * takes care by locking/unlocking host_lock.
  *
  * Return value
- * 	SUCCESS or FAILED
+ *	SUCCESS or FAILED
  */
 static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd)
 {
@@ -2879,7 +3135,7 @@
  * Initiates adapter reset to bring it up to operational state
  *
  * Return value
- * 	SUCCESS or FAILED
+ *	SUCCESS or FAILED
  */
 static int pmcraid_eh_host_reset_handler(struct scsi_cmnd *scmd)
 {
@@ -2991,7 +3247,7 @@
  * to firmware. This builds ioadl descriptors and sets up ioarcb fields.
  *
  * Return value:
- * 	0 on success or -1 on failure
+ *	0 on success or -1 on failure
  */
 static int pmcraid_build_ioadl(
 	struct pmcraid_instance *pinstance,
@@ -3049,7 +3305,7 @@
  * Free a DMA'able memory previously allocated with pmcraid_alloc_sglist
  *
  * Return value:
- * 	none
+ *	none
  */
 static void pmcraid_free_sglist(struct pmcraid_sglist *sglist)
 {
@@ -3070,7 +3326,7 @@
  * list.
  *
  * Return value
- * 	pointer to sglist / NULL on failure
+ *	pointer to sglist / NULL on failure
  */
 static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen)
 {
@@ -3224,11 +3480,12 @@
 	struct pmcraid_resource_entry *res;
 	struct pmcraid_ioarcb *ioarcb;
 	struct pmcraid_cmd *cmd;
+	u32 fw_version;
 	int rc = 0;
 
 	pinstance =
 		(struct pmcraid_instance *)scsi_cmd->device->host->hostdata;
-
+	fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
 	scsi_cmd->scsi_done = done;
 	res = scsi_cmd->device->hostdata;
 	scsi_cmd->result = (DID_OK << 16);
@@ -3247,6 +3504,15 @@
 	if (pinstance->ioa_reset_in_progress)
 		return SCSI_MLQUEUE_HOST_BUSY;
 
+	/* Firmware doesn't support SYNCHRONIZE_CACHE command (0x35), complete
+	 * the command here itself with success return
+	 */
+	if (scsi_cmd->cmnd[0] == SYNCHRONIZE_CACHE) {
+		pmcraid_info("SYNC_CACHE(0x35), completing in driver itself\n");
+		scsi_cmd->scsi_done(scsi_cmd);
+		return 0;
+	}
+
 	/* initialize the command and IOARCB to be sent to IOA */
 	cmd = pmcraid_get_free_cmd(pinstance);
 
@@ -3261,6 +3527,13 @@
 	ioarcb->resource_handle = res->cfg_entry.resource_handle;
 	ioarcb->request_type = REQ_TYPE_SCSI;
 
+	/* set hrrq number where the IOA should respond to. Note that all cmds
+	 * generated internally uses hrrq_id 0, exception to this is the cmd
+	 * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses
+	 * hrrq_id assigned here in queuecommand
+	 */
+	ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) %
+			  pinstance->num_hrrq;
 	cmd->cmd_done = pmcraid_io_done;
 
 	if (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry)) {
@@ -3287,7 +3560,9 @@
 		     RES_IS_VSET(res->cfg_entry) ? PMCRAID_VSET_BUS_ID :
 			PMCRAID_PHYS_BUS_ID,
 		     RES_IS_VSET(res->cfg_entry) ?
-			res->cfg_entry.unique_flags1 :
+			(fw_version <= PMCRAID_FW_VERSION_1 ?
+				res->cfg_entry.unique_flags1 :
+					res->cfg_entry.array_id & 0xFF) :
 			RES_TARGET(res->cfg_entry.resource_address),
 		     RES_LUN(res->cfg_entry.resource_address));
 
@@ -3324,8 +3599,7 @@
  */
 static int pmcraid_chr_release(struct inode *inode, struct file *filep)
 {
-	struct pmcraid_instance *pinstance =
-		((struct pmcraid_instance *)filep->private_data);
+	struct pmcraid_instance *pinstance = filep->private_data;
 
 	filep->private_data = NULL;
 	fasync_helper(-1, filep, 0, &pinstance->aen_queue);
@@ -3344,7 +3618,7 @@
 	struct pmcraid_instance *pinstance;
 	int rc;
 
-	pinstance = (struct pmcraid_instance *)filep->private_data;
+	pinstance = filep->private_data;
 	mutex_lock(&pinstance->aen_queue_lock);
 	rc = fasync_helper(fd, filep, mode, &pinstance->aen_queue);
 	mutex_unlock(&pinstance->aen_queue_lock);
@@ -3465,6 +3739,7 @@
 	unsigned long request_buffer;
 	unsigned long request_offset;
 	unsigned long lock_flags;
+	u32 ioasc;
 	int request_size;
 	int buffer_size;
 	u8 access, direction;
@@ -3566,6 +3841,14 @@
 			buffer->ioarcb.add_cmd_param_length);
 	}
 
+	/* set hrrq number where the IOA should respond to. Note that all cmds
+	 * generated internally uses hrrq_id 0, exception to this is the cmd
+	 * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses
+	 * hrrq_id assigned here in queuecommand
+	 */
+	ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) %
+			  pinstance->num_hrrq;
+
 	if (request_size) {
 		rc = pmcraid_build_passthrough_ioadls(cmd,
 						      request_size,
@@ -3606,6 +3889,14 @@
 	_pmcraid_fire_command(cmd);
 	spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
 
+	/* NOTE ! Remove the below line once abort_task is implemented
+	 * in firmware. This line disables ioctl command timeout handling logic
+	 * similar to IO command timeout handling, making ioctl commands to wait
+	 * until the command completion regardless of timeout value specified in
+	 * ioarcb
+	 */
+	buffer->ioarcb.cmd_timeout = 0;
+
 	/* If command timeout is specified put caller to wait till that time,
 	 * otherwise it would be blocking wait. If command gets timed out, it
 	 * will be aborted.
@@ -3620,25 +3911,47 @@
 			le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle >> 2),
 			cmd->ioa_cb->ioarcb.cdb[0]);
 
-		rc = -ETIMEDOUT;
 		spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
 		cancel_cmd = pmcraid_abort_cmd(cmd);
 		spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
 
 		if (cancel_cmd) {
 			wait_for_completion(&cancel_cmd->wait_for_completion);
+			ioasc = cancel_cmd->ioa_cb->ioasa.ioasc;
 			pmcraid_return_cmd(cancel_cmd);
+
+			/* if abort task couldn't find the command i.e it got
+			 * completed prior to aborting, return good completion.
+			 * if command got aborted succesfully or there was IOA
+			 * reset due to abort task itself getting timedout then
+			 * return -ETIMEDOUT
+			 */
+			if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET ||
+			    PMCRAID_IOASC_SENSE_KEY(ioasc) == 0x00) {
+				if (ioasc != PMCRAID_IOASC_GC_IOARCB_NOTFOUND)
+					rc = -ETIMEDOUT;
+				goto out_handle_response;
+			}
 		}
 
-		goto out_free_sglist;
+		/* no command block for abort task or abort task failed to abort
+		 * the IOARCB, then wait for 150 more seconds and initiate reset
+		 * sequence after timeout
+		 */
+		if (!wait_for_completion_timeout(
+			&cmd->wait_for_completion,
+			msecs_to_jiffies(150 * 1000))) {
+			pmcraid_reset_bringup(cmd->drv_inst);
+			rc = -ETIMEDOUT;
+		}
 	}
 
+out_handle_response:
 	/* If the command failed for any reason, copy entire IOASA buffer and
 	 * return IOCTL success. If copying IOASA to user-buffer fails, return
 	 * EFAULT
 	 */
-	if (le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)) {
-
+	if (PMCRAID_IOASC_SENSE_KEY(le32_to_cpu(cmd->ioa_cb->ioasa.ioasc))) {
 		void *ioasa =
 		    (void *)(arg +
 		    offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa));
@@ -3651,6 +3964,7 @@
 			rc = -EFAULT;
 		}
 	}
+
 	/* If the data transfer was from device, copy the data onto user
 	 * buffers
 	 */
@@ -3699,7 +4013,7 @@
 	int rc = -ENOSYS;
 
 	if (!access_ok(VERIFY_READ, user_buffer, _IOC_SIZE(cmd))) {
-		pmcraid_err("ioctl_driver: access fault in request buffer \n");
+		pmcraid_err("ioctl_driver: access fault in request buffer\n");
 		return -EFAULT;
 	}
 
@@ -3795,7 +4109,7 @@
 		return retval;
 	}
 
-	pinstance = (struct pmcraid_instance *)filep->private_data;
+	pinstance = filep->private_data;
 
 	if (!pinstance) {
 		pmcraid_info("adapter instance is not found\n");
@@ -4011,36 +4325,77 @@
 	.proc_name = PMCRAID_DRIVER_NAME
 };
 
-/**
- * pmcraid_isr_common - Common interrupt handler routine
- *
- * @pinstance: pointer to adapter instance
- * @intrs: active interrupts (contents of ioa_host_interrupt register)
- * @hrrq_id: Host RRQ index
+/*
+ * pmcraid_isr_msix - implements MSI-X interrupt handling routine
+ * @irq: interrupt vector number
+ * @dev_id: pointer hrrq_vector
  *
  * Return Value
- *	none
+ *	 IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored
  */
-static void pmcraid_isr_common(
-	struct pmcraid_instance *pinstance,
-	u32 intrs,
-	int hrrq_id
-)
-{
-	u32 intrs_clear =
-		(intrs & INTRS_CRITICAL_OP_IN_PROGRESS) ? intrs
-							: INTRS_HRRQ_VALID;
-	iowrite32(intrs_clear,
-		  pinstance->int_regs.ioa_host_interrupt_clr_reg);
-	intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
 
-	/* hrrq valid bit was set, schedule tasklet to handle the response */
-	if (intrs_clear == INTRS_HRRQ_VALID)
-		tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id]));
+static irqreturn_t pmcraid_isr_msix(int irq, void *dev_id)
+{
+	struct pmcraid_isr_param *hrrq_vector;
+	struct pmcraid_instance *pinstance;
+	unsigned long lock_flags;
+	u32 intrs_val;
+	int hrrq_id;
+
+	hrrq_vector = (struct pmcraid_isr_param *)dev_id;
+	hrrq_id = hrrq_vector->hrrq_id;
+	pinstance = hrrq_vector->drv_inst;
+
+	if (!hrrq_id) {
+		/* Read the interrupt */
+		intrs_val = pmcraid_read_interrupts(pinstance);
+		if (intrs_val &&
+			((ioread32(pinstance->int_regs.host_ioa_interrupt_reg)
+			& DOORBELL_INTR_MSIX_CLR) == 0)) {
+			/* Any error interrupts including unit_check,
+			 * initiate IOA reset.In case of unit check indicate
+			 * to reset_sequence that IOA unit checked and prepare
+			 * for a dump during reset sequence
+			 */
+			if (intrs_val & PMCRAID_ERROR_INTERRUPTS) {
+				if (intrs_val & INTRS_IOA_UNIT_CHECK)
+					pinstance->ioa_unit_check = 1;
+
+				pmcraid_err("ISR: error interrupts: %x \
+					initiating reset\n", intrs_val);
+				spin_lock_irqsave(pinstance->host->host_lock,
+					lock_flags);
+				pmcraid_initiate_reset(pinstance);
+				spin_unlock_irqrestore(
+					pinstance->host->host_lock,
+					lock_flags);
+			}
+			/* If interrupt was as part of the ioa initialization,
+			 * clear it. Delete the timer and wakeup the
+			 * reset engine to proceed with reset sequence
+			 */
+			if (intrs_val & INTRS_TRANSITION_TO_OPERATIONAL)
+				pmcraid_clr_trans_op(pinstance);
+
+			/* Clear the interrupt register by writing
+			 * to host to ioa doorbell. Once done
+			 * FW will clear the interrupt.
+			 */
+			iowrite32(DOORBELL_INTR_MSIX_CLR,
+				pinstance->int_regs.host_ioa_interrupt_reg);
+			ioread32(pinstance->int_regs.host_ioa_interrupt_reg);
+
+
+		}
+	}
+
+	tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id]));
+
+	return IRQ_HANDLED;
 }
 
 /**
- * pmcraid_isr  - implements interrupt handling routine
+ * pmcraid_isr  - implements legacy interrupt handling routine
  *
  * @irq: interrupt vector number
  * @dev_id: pointer hrrq_vector
@@ -4052,8 +4407,9 @@
 {
 	struct pmcraid_isr_param *hrrq_vector;
 	struct pmcraid_instance *pinstance;
-	unsigned long lock_flags;
 	u32 intrs;
+	unsigned long lock_flags;
+	int hrrq_id = 0;
 
 	/* In case of legacy interrupt mode where interrupts are shared across
 	 * isrs, it may be possible that the current interrupt is not from IOA
@@ -4062,21 +4418,13 @@
 		printk(KERN_INFO "%s(): NULL host pointer\n", __func__);
 		return IRQ_NONE;
 	}
-
 	hrrq_vector = (struct pmcraid_isr_param *)dev_id;
 	pinstance = hrrq_vector->drv_inst;
 
-	/* Acquire the lock (currently host_lock) while processing interrupts.
-	 * This interval is small as most of the response processing is done by
-	 * tasklet without the lock.
-	 */
-	spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
 	intrs = pmcraid_read_interrupts(pinstance);
 
-	if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0)) {
-		spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+	if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0))
 		return IRQ_NONE;
-	}
 
 	/* Any error interrupts including unit_check, initiate IOA reset.
 	 * In case of unit check indicate to reset_sequence that IOA unit
@@ -4091,13 +4439,28 @@
 			  pinstance->int_regs.ioa_host_interrupt_clr_reg);
 		pmcraid_err("ISR: error interrupts: %x initiating reset\n",
 			    intrs);
-		intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
+		intrs = ioread32(
+				pinstance->int_regs.ioa_host_interrupt_clr_reg);
+		spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
 		pmcraid_initiate_reset(pinstance);
+		spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
 	} else {
-		pmcraid_isr_common(pinstance, intrs, hrrq_vector->hrrq_id);
-	}
+		/* If interrupt was as part of the ioa initialization,
+		 * clear. Delete the timer and wakeup the
+		 * reset engine to proceed with reset sequence
+		 */
+		if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) {
+			pmcraid_clr_trans_op(pinstance);
+		} else {
+			iowrite32(intrs,
+				pinstance->int_regs.ioa_host_interrupt_clr_reg);
+			ioread32(
+				pinstance->int_regs.ioa_host_interrupt_clr_reg);
 
-	spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+			tasklet_schedule(
+					&(pinstance->isr_tasklet[hrrq_id]));
+		}
+	}
 
 	return IRQ_HANDLED;
 }
@@ -4120,6 +4483,7 @@
 	struct scsi_device *sdev;
 	unsigned long lock_flags;
 	unsigned long host_lock_flags;
+	u16 fw_version;
 	u8 bus, target, lun;
 
 	pinstance = container_of(workp, struct pmcraid_instance, worker_q);
@@ -4127,6 +4491,8 @@
 	if (!atomic_read(&pinstance->expose_resources))
 		return;
 
+	fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
+
 	spin_lock_irqsave(&pinstance->resource_lock, lock_flags);
 	list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) {
 
@@ -4166,12 +4532,16 @@
 
 		if (res->change_detected == RES_CHANGE_ADD) {
 
-			if (!pmcraid_expose_resource(&res->cfg_entry))
+			if (!pmcraid_expose_resource(fw_version,
+						     &res->cfg_entry))
 				continue;
 
 			if (RES_IS_VSET(res->cfg_entry)) {
 				bus = PMCRAID_VSET_BUS_ID;
-				target = res->cfg_entry.unique_flags1;
+				if (fw_version <= PMCRAID_FW_VERSION_1)
+					target = res->cfg_entry.unique_flags1;
+				else
+					target = res->cfg_entry.array_id & 0xFF;
 				lun = PMCRAID_VSET_LUN_ID;
 			} else {
 				bus = PMCRAID_PHYS_BUS_ID;
@@ -4201,7 +4571,7 @@
  * Return Value
  *	None
  */
-void pmcraid_tasklet_function(unsigned long instance)
+static void pmcraid_tasklet_function(unsigned long instance)
 {
 	struct pmcraid_isr_param *hrrq_vector;
 	struct pmcraid_instance *pinstance;
@@ -4210,35 +4580,12 @@
 	unsigned long host_lock_flags;
 	spinlock_t *lockp; /* hrrq buffer lock */
 	int id;
-	u32 intrs;
 	__le32 resp;
 
 	hrrq_vector = (struct pmcraid_isr_param *)instance;
 	pinstance = hrrq_vector->drv_inst;
 	id = hrrq_vector->hrrq_id;
 	lockp = &(pinstance->hrrq_lock[id]);
-	intrs = pmcraid_read_interrupts(pinstance);
-
-	/* If interrupts was as part of the ioa initialization, clear and mask
-	 * it. Delete the timer and wakeup the reset engine to proceed with
-	 * reset sequence
-	 */
-	if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) {
-		iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
-			pinstance->int_regs.ioa_host_interrupt_mask_reg);
-		iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
-			pinstance->int_regs.ioa_host_interrupt_clr_reg);
-
-		if (pinstance->reset_cmd != NULL) {
-			del_timer(&pinstance->reset_cmd->timer);
-			spin_lock_irqsave(pinstance->host->host_lock,
-					  host_lock_flags);
-			pinstance->reset_cmd->cmd_done(pinstance->reset_cmd);
-			spin_unlock_irqrestore(pinstance->host->host_lock,
-					       host_lock_flags);
-		}
-		return;
-	}
 
 	/* loop through each of the commands responded by IOA. Each HRRQ buf is
 	 * protected by its own lock. Traversals must be done within this lock
@@ -4256,27 +4603,6 @@
 		int cmd_index = resp >> 2;
 		struct pmcraid_cmd *cmd = NULL;
 
-		if (cmd_index < PMCRAID_MAX_CMD) {
-			cmd = pinstance->cmd_list[cmd_index];
-		} else {
-			/* In case of invalid response handle, initiate IOA
-			 * reset sequence.
-			 */
-			spin_unlock_irqrestore(lockp, hrrq_lock_flags);
-
-			pmcraid_err("Invalid response %d initiating reset\n",
-				    cmd_index);
-
-			spin_lock_irqsave(pinstance->host->host_lock,
-					  host_lock_flags);
-			pmcraid_initiate_reset(pinstance);
-			spin_unlock_irqrestore(pinstance->host->host_lock,
-					       host_lock_flags);
-
-			spin_lock_irqsave(lockp, hrrq_lock_flags);
-			break;
-		}
-
 		if (pinstance->hrrq_curr[id] < pinstance->hrrq_end[id]) {
 			pinstance->hrrq_curr[id]++;
 		} else {
@@ -4284,6 +4610,14 @@
 			pinstance->host_toggle_bit[id] ^= 1u;
 		}
 
+		if (cmd_index >= PMCRAID_MAX_CMD) {
+			/* In case of invalid response handle, log message */
+			pmcraid_err("Invalid response handle %d\n", cmd_index);
+			resp = le32_to_cpu(*(pinstance->hrrq_curr[id]));
+			continue;
+		}
+
+		cmd = pinstance->cmd_list[cmd_index];
 		spin_unlock_irqrestore(lockp, hrrq_lock_flags);
 
 		spin_lock_irqsave(&pinstance->pending_pool_lock,
@@ -4324,7 +4658,16 @@
 static
 void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance)
 {
-	free_irq(pinstance->pdev->irq, &(pinstance->hrrq_vector[0]));
+	int i;
+
+	for (i = 0; i < pinstance->num_hrrq; i++)
+		free_irq(pinstance->hrrq_vector[i].vector,
+			 &(pinstance->hrrq_vector[i]));
+
+	if (pinstance->interrupt_mode) {
+		pci_disable_msix(pinstance->pdev);
+		pinstance->interrupt_mode = 0;
+	}
 }
 
 /**
@@ -4337,14 +4680,70 @@
 static int
 pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance)
 {
+	int rc;
 	struct pci_dev *pdev = pinstance->pdev;
 
+	if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+		int num_hrrq = PMCRAID_NUM_MSIX_VECTORS;
+		struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS];
+		int i;
+		for (i = 0; i < PMCRAID_NUM_MSIX_VECTORS; i++)
+			entries[i].entry = i;
+
+		rc = pci_enable_msix(pdev, entries, num_hrrq);
+		if (rc < 0)
+			goto pmcraid_isr_legacy;
+
+		/* Check how many MSIX vectors are allocated and register
+		 * msi-x handlers for each of them giving appropriate buffer
+		 */
+		if (rc > 0) {
+			num_hrrq = rc;
+			if (pci_enable_msix(pdev, entries, num_hrrq))
+				goto pmcraid_isr_legacy;
+		}
+
+		for (i = 0; i < num_hrrq; i++) {
+			pinstance->hrrq_vector[i].hrrq_id = i;
+			pinstance->hrrq_vector[i].drv_inst = pinstance;
+			pinstance->hrrq_vector[i].vector = entries[i].vector;
+			rc = request_irq(pinstance->hrrq_vector[i].vector,
+					pmcraid_isr_msix, 0,
+					PMCRAID_DRIVER_NAME,
+					&(pinstance->hrrq_vector[i]));
+
+			if (rc) {
+				int j;
+				for (j = 0; j < i; j++)
+					free_irq(entries[j].vector,
+						 &(pinstance->hrrq_vector[j]));
+				pci_disable_msix(pdev);
+				goto pmcraid_isr_legacy;
+			}
+		}
+
+		pinstance->num_hrrq = num_hrrq;
+		pinstance->interrupt_mode = 1;
+		iowrite32(DOORBELL_INTR_MODE_MSIX,
+			  pinstance->int_regs.host_ioa_interrupt_reg);
+		ioread32(pinstance->int_regs.host_ioa_interrupt_reg);
+		goto pmcraid_isr_out;
+	}
+
+pmcraid_isr_legacy:
+	/* If MSI-X registration failed fallback to legacy mode, where
+	 * only one hrrq entry will be used
+	 */
 	pinstance->hrrq_vector[0].hrrq_id = 0;
 	pinstance->hrrq_vector[0].drv_inst = pinstance;
-	pinstance->hrrq_vector[0].vector = 0;
+	pinstance->hrrq_vector[0].vector = pdev->irq;
 	pinstance->num_hrrq = 1;
-	return request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED,
-			   PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]);
+	rc = 0;
+
+	rc = request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED,
+			 PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]);
+pmcraid_isr_out:
+	return rc;
 }
 
 /**
@@ -4516,12 +4915,11 @@
 static int __devinit
 pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance)
 {
-	int i;
-	int buf_count = PMCRAID_MAX_CMD / pinstance->num_hrrq;
+	int i, buffer_size;
+
+	buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD;
 
 	for (i = 0; i < pinstance->num_hrrq; i++) {
-		int buffer_size = HRRQ_ENTRY_SIZE * buf_count;
-
 		pinstance->hrrq_start[i] =
 			pci_alloc_consistent(
 					pinstance->pdev,
@@ -4529,7 +4927,8 @@
 					&(pinstance->hrrq_start_bus_addr[i]));
 
 		if (pinstance->hrrq_start[i] == 0) {
-			pmcraid_err("could not allocate host rrq: %d\n", i);
+			pmcraid_err("pci_alloc failed for hrrq vector : %d\n",
+				    i);
 			pmcraid_release_host_rrqs(pinstance, i);
 			return -ENOMEM;
 		}
@@ -4537,7 +4936,7 @@
 		memset(pinstance->hrrq_start[i], 0, buffer_size);
 		pinstance->hrrq_curr[i] = pinstance->hrrq_start[i];
 		pinstance->hrrq_end[i] =
-			pinstance->hrrq_start[i] + buf_count - 1;
+			pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1;
 		pinstance->host_toggle_bit[i] = 1;
 		spin_lock_init(&pinstance->hrrq_lock[i]);
 	}
@@ -4557,7 +4956,7 @@
 	if (pinstance->ccn.msg != NULL) {
 		pci_free_consistent(pinstance->pdev,
 				    PMCRAID_AEN_HDR_SIZE +
-				    sizeof(struct pmcraid_hcam_ccn),
+				    sizeof(struct pmcraid_hcam_ccn_ext),
 				    pinstance->ccn.msg,
 				    pinstance->ccn.baddr);
 
@@ -4591,7 +4990,7 @@
 	pinstance->ccn.msg = pci_alloc_consistent(
 					pinstance->pdev,
 					PMCRAID_AEN_HDR_SIZE +
-					sizeof(struct pmcraid_hcam_ccn),
+					sizeof(struct pmcraid_hcam_ccn_ext),
 					&(pinstance->ccn.baddr));
 
 	pinstance->ldn.msg = pci_alloc_consistent(
@@ -4724,6 +5123,32 @@
 }
 
 /**
+ * pmcraid_release_buffers - release per-adapter buffers allocated
+ *
+ * @pinstance: pointer to adapter soft state
+ *
+ * Return Value
+ *	none
+ */
+static void pmcraid_release_buffers(struct pmcraid_instance *pinstance)
+{
+	pmcraid_release_config_buffers(pinstance);
+	pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD);
+	pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD);
+	pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq);
+
+	if (pinstance->inq_data != NULL) {
+		pci_free_consistent(pinstance->pdev,
+				    sizeof(struct pmcraid_inquiry_data),
+				    pinstance->inq_data,
+				    pinstance->inq_data_baddr);
+
+		pinstance->inq_data = NULL;
+		pinstance->inq_data_baddr = 0;
+	}
+}
+
+/**
  * pmcraid_init_buffers - allocates memory and initializes various structures
  * @pinstance: pointer to per adapter instance structure
  *
@@ -4753,20 +5178,32 @@
 	}
 
 	if (pmcraid_allocate_cmd_blocks(pinstance)) {
-		pmcraid_err("couldn't allocate memory for cmd blocks \n");
+		pmcraid_err("couldn't allocate memory for cmd blocks\n");
 		pmcraid_release_config_buffers(pinstance);
 		pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq);
 		return -ENOMEM;
 	}
 
 	if (pmcraid_allocate_control_blocks(pinstance)) {
-		pmcraid_err("couldn't allocate memory control blocks \n");
+		pmcraid_err("couldn't allocate memory control blocks\n");
 		pmcraid_release_config_buffers(pinstance);
 		pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD);
 		pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq);
 		return -ENOMEM;
 	}
 
+	/* allocate DMAable memory for page D0 INQUIRY buffer */
+	pinstance->inq_data = pci_alloc_consistent(
+					pinstance->pdev,
+					sizeof(struct pmcraid_inquiry_data),
+					&pinstance->inq_data_baddr);
+
+	if (pinstance->inq_data == NULL) {
+		pmcraid_err("couldn't allocate DMA memory for INQUIRY\n");
+		pmcraid_release_buffers(pinstance);
+		return -ENOMEM;
+	}
+
 	/* Initialize all the command blocks and add them to free pool. No
 	 * need to lock (free_pool_lock) as this is done in initialization
 	 * itself
@@ -4785,7 +5222,7 @@
  * pmcraid_reinit_buffers - resets various buffer pointers
  * @pinstance: pointer to adapter instance
  * Return value
- * 	none
+ *	none
  */
 static void pmcraid_reinit_buffers(struct pmcraid_instance *pinstance)
 {
@@ -4836,6 +5273,8 @@
 			mapped_pci_addr + chip_cfg->ioa_host_intr;
 		pint_regs->ioa_host_interrupt_clr_reg =
 			mapped_pci_addr + chip_cfg->ioa_host_intr_clr;
+		pint_regs->ioa_host_msix_interrupt_reg =
+			mapped_pci_addr + chip_cfg->ioa_host_msix_intr;
 		pint_regs->host_ioa_interrupt_reg =
 			mapped_pci_addr + chip_cfg->host_ioa_intr;
 		pint_regs->host_ioa_interrupt_clr_reg =
@@ -4858,6 +5297,7 @@
 	init_waitqueue_head(&pinstance->reset_wait_q);
 
 	atomic_set(&pinstance->outstanding_cmds, 0);
+	atomic_set(&pinstance->last_message_id, 0);
 	atomic_set(&pinstance->expose_resources, 0);
 
 	INIT_LIST_HEAD(&pinstance->free_res_q);
@@ -4883,23 +5323,6 @@
 }
 
 /**
- * pmcraid_release_buffers - release per-adapter buffers allocated
- *
- * @pinstance: pointer to adapter soft state
- *
- * Return Value
- * 	none
- */
-static void pmcraid_release_buffers(struct pmcraid_instance *pinstance)
-{
-	pmcraid_release_config_buffers(pinstance);
-	pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD);
-	pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD);
-	pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq);
-
-}
-
-/**
  * pmcraid_shutdown - shutdown adapter controller.
  * @pdev: pci device struct
  *
@@ -4958,7 +5381,7 @@
 		pmcraid_release_minor(minor);
 	else
 		device_create(pmcraid_class, NULL, MKDEV(pmcraid_major, minor),
-			      NULL, "pmcsas%u", minor);
+			      NULL, "%s%u", PMCRAID_DEVFILE, minor);
 	return error;
 }
 
@@ -5050,7 +5473,6 @@
 	struct pmcraid_instance *pinstance = pci_get_drvdata(pdev);
 	struct Scsi_Host *host = pinstance->host;
 	int rc;
-	int hrrqs;
 
 	pci_set_power_state(pdev, PCI_D0);
 	pci_enable_wake(pdev, PCI_D0, 0);
@@ -5077,8 +5499,8 @@
 		goto disable_device;
 	}
 
+	pmcraid_disable_interrupts(pinstance, ~0);
 	atomic_set(&pinstance->outstanding_cmds, 0);
-	hrrqs = pinstance->num_hrrq;
 	rc = pmcraid_register_interrupt_handler(pinstance);
 
 	if (rc) {
@@ -5100,7 +5522,7 @@
 	 * state.
 	 */
 	if (pmcraid_reset_bringup(pinstance)) {
-		dev_err(&pdev->dev, "couldn't initialize IOA \n");
+		dev_err(&pdev->dev, "couldn't initialize IOA\n");
 		rc = -ENODEV;
 		goto release_tasklets;
 	}
@@ -5108,6 +5530,7 @@
 	return 0;
 
 release_tasklets:
+	pmcraid_disable_interrupts(pinstance, ~0);
 	pmcraid_kill_tasklets(pinstance);
 	pmcraid_unregister_interrupt_handler(pinstance);
 
@@ -5129,7 +5552,7 @@
 
 /**
  * pmcraid_complete_ioa_reset - Called by either timer or tasklet during
- * 	                        completion of the ioa reset
+ *				completion of the ioa reset
  * @cmd: pointer to reset command block
  */
 static void pmcraid_complete_ioa_reset(struct pmcraid_cmd *cmd)
@@ -5204,11 +5627,14 @@
 	struct pmcraid_config_table_entry *cfgte;
 	unsigned long lock_flags;
 	int found, rc, i;
+	u16 fw_version;
 	LIST_HEAD(old_res);
 
 	if (pinstance->cfg_table->flags & MICROCODE_UPDATE_REQUIRED)
 		pmcraid_err("IOA requires microcode download\n");
 
+	fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
+
 	/* resource list is protected by pinstance->resource_lock.
 	 * init_res_table can be called from probe (user-thread) or runtime
 	 * reset (timer/tasklet)
@@ -5219,9 +5645,14 @@
 		list_move_tail(&res->queue, &old_res);
 
 	for (i = 0; i < pinstance->cfg_table->num_entries; i++) {
-		cfgte = &pinstance->cfg_table->entries[i];
+		if (be16_to_cpu(pinstance->inq_data->fw_version) <=
+						PMCRAID_FW_VERSION_1)
+			cfgte = &pinstance->cfg_table->entries[i];
+		else
+			cfgte = (struct pmcraid_config_table_entry *)
+					&pinstance->cfg_table->entries_ext[i];
 
-		if (!pmcraid_expose_resource(cfgte))
+		if (!pmcraid_expose_resource(fw_version, cfgte))
 			continue;
 
 		found = 0;
@@ -5263,10 +5694,12 @@
 		 */
 		if (found) {
 			memcpy(&res->cfg_entry, cfgte,
-				sizeof(struct pmcraid_config_table_entry));
+					pinstance->config_table_entry_size);
 			pmcraid_info("New res type:%x, vset:%x, addr:%x:\n",
 				 res->cfg_entry.resource_type,
-				 res->cfg_entry.unique_flags1,
+				 (fw_version <= PMCRAID_FW_VERSION_1 ?
+					res->cfg_entry.unique_flags1 :
+						res->cfg_entry.array_id & 0xFF),
 				 le32_to_cpu(res->cfg_entry.resource_address));
 		}
 	}
@@ -5306,6 +5739,14 @@
 	struct pmcraid_instance *pinstance = cmd->drv_inst;
 	int cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table));
 
+	if (be16_to_cpu(pinstance->inq_data->fw_version) <=
+					PMCRAID_FW_VERSION_1)
+		pinstance->config_table_entry_size =
+			sizeof(struct pmcraid_config_table_entry);
+	else
+		pinstance->config_table_entry_size =
+			sizeof(struct pmcraid_config_table_entry_ext);
+
 	ioarcb->request_type = REQ_TYPE_IOACMD;
 	ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE);
 
@@ -5338,7 +5779,7 @@
 
 
 /**
- * pmcraid_probe - PCI probe entry pointer for PMC MaxRaid controller driver
+ * pmcraid_probe - PCI probe entry pointer for PMC MaxRAID controller driver
  * @pdev: pointer to pci device structure
  * @dev_id: pointer to device ids structure
  *
@@ -5485,7 +5926,7 @@
 	 */
 	pmcraid_info("starting IOA initialization sequence\n");
 	if (pmcraid_reset_bringup(pinstance)) {
-		dev_err(&pdev->dev, "couldn't initialize IOA \n");
+		dev_err(&pdev->dev, "couldn't initialize IOA\n");
 		rc = 1;
 		goto out_release_bufs;
 	}
diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h
index b8ad07c..6cfa014 100644
--- a/drivers/scsi/pmcraid.h
+++ b/drivers/scsi/pmcraid.h
@@ -40,10 +40,12 @@
  * Driver version: version string in major_version.minor_version.patch format
  * Driver date   : date information in "Mon dd yyyy" format
  */
-#define PMCRAID_DRIVER_NAME       	"PMC MaxRAID"
+#define PMCRAID_DRIVER_NAME		"PMC MaxRAID"
 #define PMCRAID_DEVFILE			"pmcsas"
-#define PMCRAID_DRIVER_VERSION    	"1.0.2"
-#define PMCRAID_DRIVER_DATE       	__DATE__
+#define PMCRAID_DRIVER_VERSION		"2.0.2"
+#define PMCRAID_DRIVER_DATE		__DATE__
+
+#define PMCRAID_FW_VERSION_1		0x002
 
 /* Maximum number of adapters supported by current version of the driver */
 #define PMCRAID_MAX_ADAPTERS		1024
@@ -85,17 +87,17 @@
 #define PMCRAID_IOARCB_ALIGNMENT                 32
 #define PMCRAID_IOADL_ALIGNMENT                  16
 #define PMCRAID_IOASA_ALIGNMENT                  4
-#define PMCRAID_NUM_MSIX_VECTORS                 1
+#define PMCRAID_NUM_MSIX_VECTORS                 16
 
 /* various other limits */
-#define PMCRAID_VENDOR_ID_LEN           	 8
-#define PMCRAID_PRODUCT_ID_LEN            	 16
-#define PMCRAID_SERIAL_NUM_LEN          	 8
-#define PMCRAID_LUN_LEN			         8
-#define PMCRAID_MAX_CDB_LEN                      16
-#define PMCRAID_DEVICE_ID_LEN			 8
-#define PMCRAID_SENSE_DATA_LEN			 256
-#define PMCRAID_ADD_CMD_PARAM_LEN		 48
+#define PMCRAID_VENDOR_ID_LEN			8
+#define PMCRAID_PRODUCT_ID_LEN			16
+#define PMCRAID_SERIAL_NUM_LEN			8
+#define PMCRAID_LUN_LEN				8
+#define PMCRAID_MAX_CDB_LEN			16
+#define PMCRAID_DEVICE_ID_LEN			8
+#define PMCRAID_SENSE_DATA_LEN			256
+#define PMCRAID_ADD_CMD_PARAM_LEN		48
 
 #define PMCRAID_MAX_BUS_TO_SCAN                  1
 #define PMCRAID_MAX_NUM_TARGETS_PER_BUS          256
@@ -116,17 +118,10 @@
 #define PMCRAID_VSET_MAX_SECTORS                 512
 #define PMCRAID_MAX_CMD_PER_LUN                  254
 
-/* Number of configuration table entries (resources) */
-#define PMCRAID_MAX_NUM_OF_VSETS                 240
-
-/* Todo : Check max limit for Phase 1 */
-#define PMCRAID_MAX_NUM_OF_PHY_DEVS              256
-
-/* MAX_NUM_OF_DEVS includes 1 FP, 1 Dummy Enclosure device */
-#define PMCRAID_MAX_NUM_OF_DEVS                        \
-    (PMCRAID_MAX_NUM_OF_VSETS + PMCRAID_MAX_NUM_OF_PHY_DEVS + 2)
-
-#define PMCRAID_MAX_RESOURCES                    PMCRAID_MAX_NUM_OF_DEVS
+/* Number of configuration table entries (resources), includes 1 FP,
+ * 1 Enclosure device
+ */
+#define PMCRAID_MAX_RESOURCES                    256
 
 /* Adapter Commands used by driver */
 #define PMCRAID_QUERY_RESOURCE_STATE             0xC2
@@ -177,6 +172,7 @@
 #define PMCRAID_IOASC_SENSE_STATUS(ioasc)        ((ioasc) & 0x000000ff)
 
 #define PMCRAID_IOASC_GOOD_COMPLETION			0x00000000
+#define PMCRAID_IOASC_GC_IOARCB_NOTFOUND		0x005A0000
 #define PMCRAID_IOASC_NR_INIT_CMD_REQUIRED		0x02040200
 #define PMCRAID_IOASC_NR_IOA_RESET_REQUIRED		0x02048000
 #define PMCRAID_IOASC_NR_SYNC_REQUIRED			0x023F0000
@@ -187,12 +183,12 @@
 #define PMCRAID_IOASC_HW_IOA_RESET_REQUIRED		0x04448600
 #define PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE        0x05250000
 #define PMCRAID_IOASC_AC_TERMINATED_BY_HOST		0x0B5A0000
-#define PMCRAID_IOASC_UA_BUS_WAS_RESET           	0x06290000
-#define PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER  	0x06298000
+#define PMCRAID_IOASC_UA_BUS_WAS_RESET			0x06290000
+#define PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER		0x06298000
 
 /* Driver defined IOASCs */
-#define PMCRAID_IOASC_IOA_WAS_RESET              	0x10000001
-#define PMCRAID_IOASC_PCI_ACCESS_ERROR           	0x10000002
+#define PMCRAID_IOASC_IOA_WAS_RESET			0x10000001
+#define PMCRAID_IOASC_PCI_ACCESS_ERROR			0x10000002
 
 /* Various timeout values (in milliseconds) used. If any of these are chip
  * specific, move them to pmcraid_chip_details structure.
@@ -336,6 +332,13 @@
 	__u8  lun[PMCRAID_LUN_LEN];
 } __attribute__((packed, aligned(4)));
 
+/* extended configuration table sizes are of 64 bytes in size */
+#define PMCRAID_CFGTE_EXT_SIZE	32
+struct pmcraid_config_table_entry_ext {
+	struct pmcraid_config_table_entry cfgte;
+	__u8  cfgte_ext[PMCRAID_CFGTE_EXT_SIZE];
+};
+
 /* resource types (config_table_entry.resource_type values) */
 #define RES_TYPE_AF_DASD     0x00
 #define RES_TYPE_GSCSI       0x01
@@ -376,7 +379,12 @@
 	__u8  reserved1;
 	__u8  flags;
 	__u8  reserved2[11];
-	struct pmcraid_config_table_entry entries[PMCRAID_MAX_RESOURCES];
+	union {
+		struct pmcraid_config_table_entry
+				entries[PMCRAID_MAX_RESOURCES];
+		struct pmcraid_config_table_entry_ext
+				entries_ext[PMCRAID_MAX_RESOURCES];
+	};
 } __attribute__((packed, aligned(4)));
 
 /* config_table.flags value */
@@ -385,7 +393,7 @@
 /*
  * HCAM format
  */
-#define PMCRAID_HOSTRCB_LDNSIZE 		4056
+#define PMCRAID_HOSTRCB_LDNSIZE			4056
 
 /* Error log notification format */
 struct pmcraid_hostrcb_error {
@@ -416,6 +424,15 @@
 struct pmcraid_hcam_ccn {
 	struct pmcraid_hcam_hdr header;
 	struct pmcraid_config_table_entry cfg_entry;
+	struct pmcraid_config_table_entry cfg_entry_old;
+} __attribute__((packed, aligned(4)));
+
+#define PMCRAID_CCN_EXT_SIZE	3944
+struct pmcraid_hcam_ccn_ext {
+	struct pmcraid_hcam_hdr header;
+	struct pmcraid_config_table_entry_ext cfg_entry;
+	struct pmcraid_config_table_entry_ext cfg_entry_old;
+	__u8   reserved[PMCRAID_CCN_EXT_SIZE];
 } __attribute__((packed, aligned(4)));
 
 struct pmcraid_hcam_ldn {
@@ -431,6 +448,8 @@
 #define NOTIFICATION_TYPE_ENTRY_CHANGED		0x0
 #define NOTIFICATION_TYPE_ENTRY_NEW		0x1
 #define NOTIFICATION_TYPE_ENTRY_DELETED		0x2
+#define NOTIFICATION_TYPE_STATE_CHANGE		0x3
+#define NOTIFICATION_TYPE_ENTRY_STATECHANGED	0x4
 #define NOTIFICATION_TYPE_ERROR_LOG		0x10
 #define NOTIFICATION_TYPE_INFORMATION_LOG	0x11
 
@@ -460,6 +479,7 @@
 	unsigned long  mailbox;
 	unsigned long  global_intr_mask;
 	unsigned long  ioa_host_intr;
+	unsigned long  ioa_host_msix_intr;
 	unsigned long  ioa_host_intr_clr;
 	unsigned long  ioa_host_mask;
 	unsigned long  ioa_host_mask_clr;
@@ -482,6 +502,7 @@
 #define INTRS_IOA_PROCESSOR_ERROR		PMC_BIT32(29)
 #define INTRS_HRRQ_VALID			PMC_BIT32(30)
 #define INTRS_OPERATIONAL_STATUS		PMC_BIT32(0)
+#define INTRS_ALLOW_MSIX_VECTOR0		PMC_BIT32(31)
 
 /* Host to IOA Doorbells */
 #define DOORBELL_RUNTIME_RESET			PMC_BIT32(1)
@@ -489,10 +510,12 @@
 #define DOORBELL_IOA_DEBUG_ALERT		PMC_BIT32(9)
 #define DOORBELL_ENABLE_DESTRUCTIVE_DIAGS	PMC_BIT32(8)
 #define DOORBELL_IOA_START_BIST			PMC_BIT32(23)
+#define DOORBELL_INTR_MODE_MSIX			PMC_BIT32(25)
+#define DOORBELL_INTR_MSIX_CLR			PMC_BIT32(26)
 #define DOORBELL_RESET_IOA			PMC_BIT32(31)
 
 /* Global interrupt mask register value */
-#define GLOBAL_INTERRUPT_MASK			0x4ULL
+#define GLOBAL_INTERRUPT_MASK			0x5ULL
 
 #define PMCRAID_ERROR_INTERRUPTS	(INTRS_IOARCB_TRANSFER_FAILED | \
 					 INTRS_IOA_UNIT_CHECK | \
@@ -503,8 +526,8 @@
 
 #define PMCRAID_PCI_INTERRUPTS		(PMCRAID_ERROR_INTERRUPTS | \
 					 INTRS_HRRQ_VALID | \
-					 INTRS_CRITICAL_OP_IN_PROGRESS |\
-					 INTRS_TRANSITION_TO_OPERATIONAL)
+					 INTRS_TRANSITION_TO_OPERATIONAL |\
+					 INTRS_ALLOW_MSIX_VECTOR0)
 
 /* control_block, associated with each of the commands contains IOARCB, IOADLs
  * memory for IOASA. Additional 3 * 16 bytes are allocated in order to support
@@ -526,17 +549,24 @@
 	struct scatterlist scatterlist[1];
 };
 
+/* page D0 inquiry data of focal point resource */
+struct pmcraid_inquiry_data {
+	__u8	ph_dev_type;
+	__u8	page_code;
+	__u8	reserved1;
+	__u8	add_page_len;
+	__u8	length;
+	__u8	reserved2;
+	__le16	fw_version;
+	__u8	reserved3[16];
+};
+
 /* pmcraid_cmd - LLD representation of SCSI command */
 struct pmcraid_cmd {
 
 	/* Ptr and bus address of DMA.able control block for this command */
 	struct pmcraid_control_block *ioa_cb;
 	dma_addr_t ioa_cb_bus_addr;
-
-	/* sense buffer for REQUEST SENSE command if firmware is not sending
-	 * auto sense data
-	 */
-	dma_addr_t sense_buffer_dma;
 	dma_addr_t dma_handle;
 	u8 *sense_buffer;
 
@@ -556,11 +586,22 @@
 
 	struct pmcraid_sglist *sglist; /* used for passthrough IOCTLs */
 
-	/* scratch used during reset sequence */
+	/* scratch used */
 	union {
+		/* during reset sequence */
 		unsigned long time_left;
 		struct pmcraid_resource_entry *res;
-	} u;
+		int hrrq_index;
+
+		/* used during IO command error handling. Sense buffer
+		 * for REQUEST SENSE command if firmware is not sending
+		 * auto sense data
+		 */
+		struct  {
+			u8 *sense_buffer;
+			dma_addr_t sense_buffer_dma;
+		};
+	};
 };
 
 /*
@@ -568,6 +609,7 @@
  */
 struct pmcraid_interrupts {
 	void __iomem *ioa_host_interrupt_reg;
+	void __iomem *ioa_host_msix_interrupt_reg;
 	void __iomem *ioa_host_interrupt_clr_reg;
 	void __iomem *ioa_host_interrupt_mask_reg;
 	void __iomem *ioa_host_interrupt_mask_clr_reg;
@@ -578,11 +620,12 @@
 
 /* ISR parameters LLD allocates (one for each MSI-X if enabled) vectors */
 struct pmcraid_isr_param {
-	u8 hrrq_id;			/* hrrq entry index */
-	u16 vector;			/* allocated msi-x vector */
 	struct pmcraid_instance *drv_inst;
+	u16 vector;			/* allocated msi-x vector */
+	u8 hrrq_id;			/* hrrq entry index */
 };
 
+
 /* AEN message header sent as part of event data to applications */
 struct pmcraid_aen_msg {
 	u32 hostno;
@@ -591,6 +634,19 @@
 	u8  data[0];
 };
 
+/* Controller state event message type */
+struct pmcraid_state_msg {
+	struct pmcraid_aen_msg msg;
+	u32 ioa_state;
+};
+
+#define PMC_DEVICE_EVENT_RESET_START		0x11000000
+#define PMC_DEVICE_EVENT_RESET_SUCCESS		0x11000001
+#define PMC_DEVICE_EVENT_RESET_FAILED		0x11000002
+#define PMC_DEVICE_EVENT_SHUTDOWN_START		0x11000003
+#define PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS	0x11000004
+#define PMC_DEVICE_EVENT_SHUTDOWN_FAILED	0x11000005
+
 struct pmcraid_hostrcb {
 	struct pmcraid_instance *drv_inst;
 	struct pmcraid_aen_msg *msg;
@@ -628,6 +684,7 @@
 	/* HostRCBs needed for HCAM */
 	struct pmcraid_hostrcb ldn;
 	struct pmcraid_hostrcb ccn;
+	struct pmcraid_state_msg scn;	/* controller state change msg */
 
 
 	/* Bus address of start of HRRQ */
@@ -645,12 +702,15 @@
 	/* Lock for HRRQ access */
 	spinlock_t hrrq_lock[PMCRAID_NUM_MSIX_VECTORS];
 
+	struct pmcraid_inquiry_data *inq_data;
+	dma_addr_t  inq_data_baddr;
+
+	/* size of configuration table entry, varies based on the firmware */
+	u32	config_table_entry_size;
+
 	/* Expected toggle bit at host */
 	u8 host_toggle_bit[PMCRAID_NUM_MSIX_VECTORS];
 
-	/* No of Reset IOA retries . IOA marked dead if threshold exceeds */
-	u8 ioa_reset_attempts;
-#define PMCRAID_RESET_ATTEMPTS 3
 
 	/* Wait Q for  threads to wait for Reset IOA completion */
 	wait_queue_head_t reset_wait_q;
@@ -664,14 +724,22 @@
 	struct Scsi_Host *host;	/* mid layer interface structure handle */
 	struct pci_dev *pdev;	/* PCI device structure handle */
 
+	/* No of Reset IOA retries . IOA marked dead if threshold exceeds */
+	u8 ioa_reset_attempts;
+#define PMCRAID_RESET_ATTEMPTS 3
+
 	u8  current_log_level;	/* default level for logging IOASC errors */
 
 	u8  num_hrrq;		/* Number of interrupt vectors allocated */
+	u8  interrupt_mode;	/* current interrupt mode legacy or msix */
 	dev_t dev;		/* Major-Minor numbers for Char device */
 
 	/* Used as ISR handler argument */
 	struct pmcraid_isr_param hrrq_vector[PMCRAID_NUM_MSIX_VECTORS];
 
+	/* Message id as filled in last fired IOARCB, used to identify HRRQ */
+	atomic_t last_message_id;
+
 	/* configuration table */
 	struct pmcraid_config_table *cfg_table;
 	dma_addr_t cfg_table_bus_addr;
@@ -686,8 +754,14 @@
 
 	struct list_head free_cmd_pool;
 	struct list_head pending_cmd_pool;
-	spinlock_t free_pool_lock;	 	/* free pool lock */
-	spinlock_t pending_pool_lock;	 	/* pending pool lock */
+	spinlock_t free_pool_lock;		/* free pool lock */
+	spinlock_t pending_pool_lock;		/* pending pool lock */
+
+	/* Tasklet to handle deferred processing */
+	struct tasklet_struct isr_tasklet[PMCRAID_NUM_MSIX_VECTORS];
+
+	/* Work-queue (Shared) for deferred reset processing */
+	struct work_struct worker_q;
 
 	/* No of IO commands pending with FW */
 	atomic_t outstanding_cmds;
@@ -695,11 +769,6 @@
 	/* should add/delete resources to mid-layer now ?*/
 	atomic_t expose_resources;
 
-	/* Tasklet to handle deferred processing */
-	struct tasklet_struct isr_tasklet[PMCRAID_NUM_MSIX_VECTORS];
-
-	/* Work-queue (Shared) for deferred reset processing */
-	struct work_struct worker_q;
 
 
 	u32 ioa_state:4;	/* For IOA Reset sequence FSM */
@@ -728,7 +797,10 @@
 /* LLD maintained resource entry structure */
 struct pmcraid_resource_entry {
 	struct list_head queue;	/* link to "to be exposed" resources */
-	struct pmcraid_config_table_entry cfg_entry;
+	union {
+		struct pmcraid_config_table_entry cfg_entry;
+		struct pmcraid_config_table_entry_ext cfg_entry_ext;
+	};
 	struct scsi_device *scsi_dev;	/* Link scsi_device structure */
 	atomic_t read_failures;		/* count of failed READ commands */
 	atomic_t write_failures;	/* count of failed WRITE commands */
@@ -771,73 +843,75 @@
  * statically.
  */
 static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = {
-	{0x01180600, IOASC_LOG_LEVEL_MUST,
+	{0x01180600, IOASC_LOG_LEVEL_HARD,
 	 "Recovered Error, soft media error, sector reassignment suggested"},
-	{0x015D0000, IOASC_LOG_LEVEL_MUST,
-	 "Recovered Error, failure prediction threshold exceeded"},
-	{0x015D9200, IOASC_LOG_LEVEL_MUST,
-	 "Recovered Error, soft Cache Card Battery error threshold"},
-	{0x015D9200, IOASC_LOG_LEVEL_MUST,
-	 "Recovered Error, soft Cache Card Battery error threshold"},
-	{0x02048000, IOASC_LOG_LEVEL_MUST,
+	{0x015D0000, IOASC_LOG_LEVEL_HARD,
+	 "Recovered Error, failure prediction thresold exceeded"},
+	{0x015D9200, IOASC_LOG_LEVEL_HARD,
+	 "Recovered Error, soft Cache Card Battery error thresold"},
+	{0x015D9200, IOASC_LOG_LEVEL_HARD,
+	 "Recovered Error, soft Cache Card Battery error thresold"},
+	{0x02048000, IOASC_LOG_LEVEL_HARD,
 	 "Not Ready, IOA Reset Required"},
-	{0x02408500, IOASC_LOG_LEVEL_MUST,
+	{0x02408500, IOASC_LOG_LEVEL_HARD,
 	 "Not Ready, IOA microcode download required"},
-	{0x03110B00, IOASC_LOG_LEVEL_MUST,
+	{0x03110B00, IOASC_LOG_LEVEL_HARD,
 	 "Medium Error, data unreadable, reassignment suggested"},
 	{0x03110C00, IOASC_LOG_LEVEL_MUST,
 	 "Medium Error, data unreadable do not reassign"},
-	{0x03310000, IOASC_LOG_LEVEL_MUST,
+	{0x03310000, IOASC_LOG_LEVEL_HARD,
 	 "Medium Error, media corrupted"},
-	{0x04050000, IOASC_LOG_LEVEL_MUST,
+	{0x04050000, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, IOA can't communicate with device"},
 	{0x04080000, IOASC_LOG_LEVEL_MUST,
 	 "Hardware Error, device bus error"},
-	{0x04080000, IOASC_LOG_LEVEL_MUST,
+	{0x04088000, IOASC_LOG_LEVEL_MUST,
 	 "Hardware Error, device bus is not functioning"},
-	{0x04118000, IOASC_LOG_LEVEL_MUST,
+	{0x04118000, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, IOA reserved area data check"},
-	{0x04118100, IOASC_LOG_LEVEL_MUST,
+	{0x04118100, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, IOA reserved area invalid data pattern"},
-	{0x04118200, IOASC_LOG_LEVEL_MUST,
+	{0x04118200, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, IOA reserved area LRC error"},
-	{0x04320000, IOASC_LOG_LEVEL_MUST,
+	{0x04320000, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, reassignment space exhausted"},
-	{0x04330000, IOASC_LOG_LEVEL_MUST,
+	{0x04330000, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, data transfer underlength error"},
-	{0x04330000, IOASC_LOG_LEVEL_MUST,
+	{0x04330000, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, data transfer overlength error"},
 	{0x04418000, IOASC_LOG_LEVEL_MUST,
 	 "Hardware Error, PCI bus error"},
-	{0x04440000, IOASC_LOG_LEVEL_MUST,
+	{0x04440000, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, device error"},
-	{0x04448300, IOASC_LOG_LEVEL_MUST,
+	{0x04448200, IOASC_LOG_LEVEL_MUST,
+	 "Hardware Error, IOA error"},
+	{0x04448300, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, undefined device response"},
-	{0x04448400, IOASC_LOG_LEVEL_MUST,
+	{0x04448400, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, IOA microcode error"},
-	{0x04448600, IOASC_LOG_LEVEL_MUST,
+	{0x04448600, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, IOA reset required"},
-	{0x04449200, IOASC_LOG_LEVEL_MUST,
+	{0x04449200, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, hard Cache Fearuee Card Battery error"},
-	{0x0444A000, IOASC_LOG_LEVEL_MUST,
+	{0x0444A000, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, failed device altered"},
-	{0x0444A200, IOASC_LOG_LEVEL_MUST,
+	{0x0444A200, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, data check after reassignment"},
-	{0x0444A300, IOASC_LOG_LEVEL_MUST,
+	{0x0444A300, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, LRC error after reassignment"},
-	{0x044A0000, IOASC_LOG_LEVEL_MUST,
+	{0x044A0000, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, device bus error (msg/cmd phase)"},
-	{0x04670400, IOASC_LOG_LEVEL_MUST,
+	{0x04670400, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, new device can't be used"},
-	{0x04678000, IOASC_LOG_LEVEL_MUST,
+	{0x04678000, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, invalid multiadapter configuration"},
-	{0x04678100, IOASC_LOG_LEVEL_MUST,
+	{0x04678100, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, incorrect connection between enclosures"},
-	{0x04678200, IOASC_LOG_LEVEL_MUST,
+	{0x04678200, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, connections exceed IOA design limits"},
-	{0x04678300, IOASC_LOG_LEVEL_MUST,
+	{0x04678300, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, incorrect multipath connection"},
-	{0x04679000, IOASC_LOG_LEVEL_MUST,
+	{0x04679000, IOASC_LOG_LEVEL_HARD,
 	 "Hardware Error, command to LUN failed"},
 	{0x064C8000, IOASC_LOG_LEVEL_HARD,
 	 "Unit Attention, cache exists for missing/failed device"},
@@ -845,15 +919,15 @@
 	 "Unit Attention, incompatible exposed mode device"},
 	{0x06670600, IOASC_LOG_LEVEL_HARD,
 	 "Unit Attention, attachment of logical unit failed"},
-	{0x06678000, IOASC_LOG_LEVEL_MUST,
+	{0x06678000, IOASC_LOG_LEVEL_HARD,
 	 "Unit Attention, cables exceed connective design limit"},
-	{0x06678300, IOASC_LOG_LEVEL_MUST,
+	{0x06678300, IOASC_LOG_LEVEL_HARD,
 	 "Unit Attention, incomplete multipath connection between" \
 	 "IOA and enclosure"},
-	{0x06678400, IOASC_LOG_LEVEL_MUST,
+	{0x06678400, IOASC_LOG_LEVEL_HARD,
 	 "Unit Attention, incomplete multipath connection between" \
 	 "device and enclosure"},
-	{0x06678500, IOASC_LOG_LEVEL_MUST,
+	{0x06678500, IOASC_LOG_LEVEL_HARD,
 	 "Unit Attention, incomplete multipath connection between" \
 	 "IOA and remote IOA"},
 	{0x06678600, IOASC_LOG_LEVEL_HARD,
@@ -863,11 +937,11 @@
 	 "function"},
 	{0x06698200, IOASC_LOG_LEVEL_HARD,
 	 "Unit Attention, corrupt array parity detected on device"},
-	{0x066B0200, IOASC_LOG_LEVEL_MUST,
+	{0x066B0200, IOASC_LOG_LEVEL_HARD,
 	 "Unit Attention, array exposed"},
 	{0x066B8200, IOASC_LOG_LEVEL_HARD,
 	 "Unit Attention, exposed array is still protected"},
-	{0x066B9200, IOASC_LOG_LEVEL_MUST,
+	{0x066B9200, IOASC_LOG_LEVEL_HARD,
 	 "Unit Attention, Multipath redundancy level got worse"},
 	{0x07270000, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, device is read/write protected by IOA"},
@@ -875,37 +949,37 @@
 	 "Data Protect, IOA doesn't support device attribute"},
 	{0x07278100, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, NVRAM mirroring prohibited"},
-	{0x07278400, IOASC_LOG_LEVEL_MUST,
+	{0x07278400, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, array is short 2 or more devices"},
-	{0x07278600, IOASC_LOG_LEVEL_MUST,
+	{0x07278600, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, exposed array is short a required device"},
-	{0x07278700, IOASC_LOG_LEVEL_MUST,
+	{0x07278700, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, array members not at required addresses"},
-	{0x07278800, IOASC_LOG_LEVEL_MUST,
+	{0x07278800, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, exposed mode device resource address conflict"},
-	{0x07278900, IOASC_LOG_LEVEL_MUST,
+	{0x07278900, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, incorrect resource address of exposed mode device"},
-	{0x07278A00, IOASC_LOG_LEVEL_MUST,
+	{0x07278A00, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, Array is missing a device and parity is out of sync"},
-	{0x07278B00, IOASC_LOG_LEVEL_MUST,
+	{0x07278B00, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, maximum number of arrays already exist"},
 	{0x07278C00, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, cannot locate cache data for device"},
 	{0x07278D00, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, cache data exits for a changed device"},
-	{0x07279100, IOASC_LOG_LEVEL_MUST,
+	{0x07279100, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, detection of a device requiring format"},
-	{0x07279200, IOASC_LOG_LEVEL_MUST,
+	{0x07279200, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, IOA exceeds maximum number of devices"},
-	{0x07279600, IOASC_LOG_LEVEL_MUST,
+	{0x07279600, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, missing array, volume set is not functional"},
-	{0x07279700, IOASC_LOG_LEVEL_MUST,
+	{0x07279700, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, single device for a volume set"},
-	{0x07279800, IOASC_LOG_LEVEL_MUST,
+	{0x07279800, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, missing multiple devices for a volume set"},
 	{0x07279900, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, maximum number of volument sets already exists"},
-	{0x07279A00, IOASC_LOG_LEVEL_MUST,
+	{0x07279A00, IOASC_LOG_LEVEL_HARD,
 	 "Data Protect, other volume set problem"},
 };
 
@@ -952,27 +1026,6 @@
 
 #define PMCRAID_IOCTL_SIGNATURE      "PMCRAID"
 
-
-/*
- * pmcraid_event_details - defines AEN details that apps can retrieve from LLD
- *
- * .rcb_ccn - complete RCB of CCN
- * .rcb_ldn - complete RCB of CCN
- */
-struct pmcraid_event_details {
-	struct pmcraid_hcam_ccn rcb_ccn;
-	struct pmcraid_hcam_ldn rcb_ldn;
-};
-
-/*
- * pmcraid_driver_ioctl_buffer - structure passed as argument to most of the
- * PMC driver handled ioctls.
- */
-struct pmcraid_driver_ioctl_buffer {
-	struct pmcraid_ioctl_header ioctl_header;
-	struct pmcraid_event_details event_details;
-};
-
 /*
  * pmcraid_passthrough_ioctl_buffer - structure given as argument to
  * passthrough(or firmware handled) IOCTL commands. Note that ioarcb requires
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 1e4cafa..420238c 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -1187,6 +1187,21 @@
 }
 
 static ssize_t
+qla2x00_optrom_gold_fw_version_show(struct device *dev,
+    struct device_attribute *attr, char *buf)
+{
+	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+	struct qla_hw_data *ha = vha->hw;
+
+	if (!IS_QLA81XX(ha))
+		return snprintf(buf, PAGE_SIZE, "\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%d)\n",
+	    ha->gold_fw_version[0], ha->gold_fw_version[1],
+	    ha->gold_fw_version[2], ha->gold_fw_version[3]);
+}
+
+static ssize_t
 qla2x00_total_isp_aborts_show(struct device *dev,
 			      struct device_attribute *attr, char *buf)
 {
@@ -1208,7 +1223,7 @@
 	if (!IS_QLA84XX(ha))
 		return snprintf(buf, PAGE_SIZE, "\n");
 
-	if (ha->cs84xx && ha->cs84xx->op_fw_version == 0)
+	if (ha->cs84xx->op_fw_version == 0)
 		rval = qla84xx_verify_chip(vha, status);
 
 	if ((rval == QLA_SUCCESS) && (status[0] == 0))
@@ -1336,6 +1351,8 @@
 		   qla2x00_optrom_fcode_version_show, NULL);
 static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show,
 		   NULL);
+static DEVICE_ATTR(optrom_gold_fw_version, S_IRUGO,
+    qla2x00_optrom_gold_fw_version_show, NULL);
 static DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show,
 		   NULL);
 static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show,
@@ -1376,6 +1393,7 @@
 	&dev_attr_vn_port_mac_address,
 	&dev_attr_fabric_param,
 	&dev_attr_fw_state,
+	&dev_attr_optrom_gold_fw_version,
 	NULL,
 };
 
@@ -1732,7 +1750,7 @@
 			fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
 	}
 
-	if (IS_QLA25XX(ha) && ql2xenabledif) {
+	if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
 		if (ha->fw_attributes & BIT_4) {
 			vha->flags.difdix_supported = 1;
 			DEBUG18(qla_printk(KERN_INFO, ha,
@@ -1740,8 +1758,10 @@
 			    " protection.\n"));
 			scsi_host_set_prot(vha->host,
 			    SHOST_DIF_TYPE1_PROTECTION
+			    | SHOST_DIF_TYPE2_PROTECTION
 			    | SHOST_DIF_TYPE3_PROTECTION
 			    | SHOST_DIX_TYPE1_PROTECTION
+			    | SHOST_DIX_TYPE2_PROTECTION
 			    | SHOST_DIX_TYPE3_PROTECTION);
 			scsi_host_set_guard(vha->host, SHOST_DIX_GUARD_CRC);
 		} else
@@ -1809,7 +1829,6 @@
 qla24xx_vport_delete(struct fc_vport *fc_vport)
 {
 	scsi_qla_host_t *vha = fc_vport->dd_data;
-	fc_port_t *fcport, *tfcport;
 	struct qla_hw_data *ha = vha->hw;
 	uint16_t id = vha->vp_idx;
 
@@ -1823,11 +1842,7 @@
 
 	scsi_remove_host(vha->host);
 
-	list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list) {
-		list_del(&fcport->list);
-		kfree(fcport);
-		fcport = NULL;
-	}
+	qla2x00_free_fcports(vha);
 
 	qla24xx_deallocate_vp_id(vha);
 
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index b905dfe..9067629 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -41,13 +41,28 @@
 	int i, ret, num_valid;
 	uint8_t *bcode;
 	struct qla_fcp_prio_entry *pri_entry;
+	uint32_t *bcode_val_ptr, bcode_val;
 
 	ret = 1;
 	num_valid = 0;
 	bcode = (uint8_t *)pri_cfg;
+	bcode_val_ptr = (uint32_t *)pri_cfg;
+	bcode_val = (uint32_t)(*bcode_val_ptr);
 
-	if (bcode[0x0] != 'H' || bcode[0x1] != 'Q' || bcode[0x2] != 'O' ||
-			bcode[0x3] != 'S') {
+	if (bcode_val == 0xFFFFFFFF) {
+		/* No FCP Priority config data in flash */
+		DEBUG2(printk(KERN_INFO
+		    "%s: No FCP priority config data.\n",
+		    __func__));
+		return 0;
+	}
+
+	if (bcode[0] != 'H' || bcode[1] != 'Q' || bcode[2] != 'O' ||
+			bcode[3] != 'S') {
+		/* Invalid FCP priority data header*/
+		DEBUG2(printk(KERN_ERR
+		    "%s: Invalid FCP Priority data header. bcode=0x%x\n",
+		    __func__, bcode_val));
 		return 0;
 	}
 	if (flag != 1)
@@ -60,8 +75,18 @@
 		pri_entry++;
 	}
 
-	if (num_valid == 0)
+	if (num_valid == 0) {
+		/* No valid FCP priority data entries */
+		DEBUG2(printk(KERN_ERR
+		    "%s: No valid FCP Priority data entries.\n",
+		    __func__));
 		ret = 0;
+	} else {
+		/* FCP priority data is valid */
+		DEBUG2(printk(KERN_INFO
+		    "%s: Valid FCP priority data. num entries = %d\n",
+		    __func__, num_valid));
+	}
 
 	return ret;
 }
@@ -78,6 +103,11 @@
 
 	bsg_job->reply->reply_payload_rcv_len = 0;
 
+	if (!IS_QLA24XX_TYPE(ha) || !IS_QLA25XX(ha)) {
+		ret = -EINVAL;
+		goto exit_fcp_prio_cfg;
+	}
+
 	if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
 		test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
 		test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
@@ -199,7 +229,7 @@
 qla2x00_process_els(struct fc_bsg_job *bsg_job)
 {
 	struct fc_rport *rport;
-	fc_port_t *fcport;
+	fc_port_t *fcport = NULL;
 	struct Scsi_Host *host;
 	scsi_qla_host_t *vha;
 	struct qla_hw_data *ha;
@@ -210,6 +240,29 @@
 	uint16_t nextlid = 0;
 	struct srb_ctx *els;
 
+	if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
+		rport = bsg_job->rport;
+		fcport = *(fc_port_t **) rport->dd_data;
+		host = rport_to_shost(rport);
+		vha = shost_priv(host);
+		ha = vha->hw;
+		type = "FC_BSG_RPT_ELS";
+	} else {
+		host = bsg_job->shost;
+		vha = shost_priv(host);
+		ha = vha->hw;
+		type = "FC_BSG_HST_ELS_NOLOGIN";
+	}
+
+	/* pass through is supported only for ISP 4Gb or higher */
+	if (!IS_FWI2_CAPABLE(ha)) {
+		DEBUG2(qla_printk(KERN_INFO, ha,
+		    "scsi(%ld):ELS passthru not supported for ISP23xx based "
+		    "adapters\n", vha->host_no));
+		rval = -EPERM;
+		goto done;
+	}
+
 	/*  Multiple SG's are not supported for ELS requests */
 	if (bsg_job->request_payload.sg_cnt > 1 ||
 		bsg_job->reply_payload.sg_cnt > 1) {
@@ -224,13 +277,6 @@
 
 	/* ELS request for rport */
 	if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
-		rport = bsg_job->rport;
-		fcport = *(fc_port_t **) rport->dd_data;
-		host = rport_to_shost(rport);
-		vha = shost_priv(host);
-		ha = vha->hw;
-		type = "FC_BSG_RPT_ELS";
-
 		/* make sure the rport is logged in,
 		 * if not perform fabric login
 		 */
@@ -242,11 +288,6 @@
 			goto done;
 		}
 	} else {
-		host = bsg_job->shost;
-		vha = shost_priv(host);
-		ha = vha->hw;
-		type = "FC_BSG_HST_ELS_NOLOGIN";
-
 		/* Allocate a dummy fcport structure, since functions
 		 * preparing the IOCB and mailbox command retrieves port
 		 * specific information from fcport structure. For Host based
@@ -366,15 +407,6 @@
 	char  *type = "FC_BSG_HST_CT";
 	struct srb_ctx *ct;
 
-	/* pass through is supported only for ISP 4Gb or higher */
-	if (!IS_FWI2_CAPABLE(ha)) {
-		DEBUG2(qla_printk(KERN_INFO, ha,
-		    "scsi(%ld):Firmware is not capable to support FC "
-		    "CT pass thru\n", vha->host_no));
-		rval = -EPERM;
-		goto done;
-	}
-
 	req_sg_cnt =
 		dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
 			bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
@@ -483,6 +515,98 @@
 	return rval;
 }
 
+/* Set the port configuration to enable the
+ * internal loopback on ISP81XX
+ */
+static inline int
+qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
+    uint16_t *new_config)
+{
+	int ret = 0;
+	int rval = 0;
+	struct qla_hw_data *ha = vha->hw;
+
+	if (!IS_QLA81XX(ha))
+		goto done_set_internal;
+
+	new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1);
+	memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
+
+	ha->notify_dcbx_comp = 1;
+	ret = qla81xx_set_port_config(vha, new_config);
+	if (ret != QLA_SUCCESS) {
+		DEBUG2(printk(KERN_ERR
+		    "%s(%lu): Set port config failed\n",
+		    __func__, vha->host_no));
+		ha->notify_dcbx_comp = 0;
+		rval = -EINVAL;
+		goto done_set_internal;
+	}
+
+	/* Wait for DCBX complete event */
+	if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) {
+		DEBUG2(qla_printk(KERN_WARNING, ha,
+		    "State change notificaition not received.\n"));
+	} else
+		DEBUG2(qla_printk(KERN_INFO, ha,
+		    "State change RECEIVED\n"));
+
+	ha->notify_dcbx_comp = 0;
+
+done_set_internal:
+	return rval;
+}
+
+/* Set the port configuration to disable the
+ * internal loopback on ISP81XX
+ */
+static inline int
+qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
+    int wait)
+{
+	int ret = 0;
+	int rval = 0;
+	uint16_t new_config[4];
+	struct qla_hw_data *ha = vha->hw;
+
+	if (!IS_QLA81XX(ha))
+		goto done_reset_internal;
+
+	memset(new_config, 0 , sizeof(new_config));
+	if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==
+			ENABLE_INTERNAL_LOOPBACK) {
+		new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK;
+		memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
+
+		ha->notify_dcbx_comp = wait;
+		ret = qla81xx_set_port_config(vha, new_config);
+		if (ret != QLA_SUCCESS) {
+			DEBUG2(printk(KERN_ERR
+			    "%s(%lu): Set port config failed\n",
+			     __func__, vha->host_no));
+			ha->notify_dcbx_comp = 0;
+			rval = -EINVAL;
+			goto done_reset_internal;
+		}
+
+		/* Wait for DCBX complete event */
+		if (wait && !wait_for_completion_timeout(&ha->dcbx_comp,
+			(20 * HZ))) {
+			DEBUG2(qla_printk(KERN_WARNING, ha,
+			    "State change notificaition not received.\n"));
+			ha->notify_dcbx_comp = 0;
+			rval = -EINVAL;
+			goto done_reset_internal;
+		} else
+			DEBUG2(qla_printk(KERN_INFO, ha,
+			    "State change RECEIVED\n"));
+
+		ha->notify_dcbx_comp = 0;
+	}
+done_reset_internal:
+	return rval;
+}
+
 static int
 qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
 {
@@ -494,6 +618,7 @@
 	char *type;
 	struct msg_echo_lb elreq;
 	uint16_t response[MAILBOX_REGISTER_COUNT];
+	uint16_t config[4], new_config[4];
 	uint8_t *fw_sts_ptr;
 	uint8_t *req_data = NULL;
 	dma_addr_t req_data_dma;
@@ -568,29 +693,102 @@
 
 	elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
 
-	if (ha->current_topology != ISP_CFG_F) {
-		type = "FC_BSG_HST_VENDOR_LOOPBACK";
-		DEBUG2(qla_printk(KERN_INFO, ha,
-			"scsi(%ld) bsg rqst type: %s\n",
-			vha->host_no, type));
-
-		command_sent = INT_DEF_LB_LOOPBACK_CMD;
-		rval = qla2x00_loopback_test(vha, &elreq, response);
-		if (IS_QLA81XX(ha)) {
-			if (response[0] == MBS_COMMAND_ERROR &&
-				response[1] == MBS_LB_RESET) {
-				DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing "
-				"ISP\n", __func__, vha->host_no));
-				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
-				qla2xxx_wake_dpc(vha);
-			}
-		}
-	} else {
+	if ((ha->current_topology == ISP_CFG_F ||
+	    (IS_QLA81XX(ha) &&
+	    le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
+	    && req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
+		elreq.options == EXTERNAL_LOOPBACK) {
 		type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
 		DEBUG2(qla_printk(KERN_INFO, ha,
-		    "scsi(%ld) bsg rqst type: %s\n", vha->host_no, type));
+			"scsi(%ld) bsg rqst type: %s\n", vha->host_no, type));
 		command_sent = INT_DEF_LB_ECHO_CMD;
 		rval = qla2x00_echo_test(vha, &elreq, response);
+	} else {
+		if (IS_QLA81XX(ha)) {
+			memset(config, 0, sizeof(config));
+			memset(new_config, 0, sizeof(new_config));
+			if (qla81xx_get_port_config(vha, config)) {
+				DEBUG2(printk(KERN_ERR
+					"%s(%lu): Get port config failed\n",
+					__func__, vha->host_no));
+				bsg_job->reply->reply_payload_rcv_len = 0;
+				bsg_job->reply->result = (DID_ERROR << 16);
+				rval = -EPERM;
+				goto done_free_dma_req;
+			}
+
+			if (elreq.options != EXTERNAL_LOOPBACK) {
+				DEBUG2(qla_printk(KERN_INFO, ha,
+					"Internal: current port config = %x\n",
+					config[0]));
+				if (qla81xx_set_internal_loopback(vha, config,
+					new_config)) {
+					bsg_job->reply->reply_payload_rcv_len =
+						0;
+					bsg_job->reply->result =
+						(DID_ERROR << 16);
+					rval = -EPERM;
+					goto done_free_dma_req;
+				}
+			} else {
+				/* For external loopback to work
+				 * ensure internal loopback is disabled
+				 */
+				if (qla81xx_reset_internal_loopback(vha,
+					config, 1)) {
+					bsg_job->reply->reply_payload_rcv_len =
+						0;
+					bsg_job->reply->result =
+						(DID_ERROR << 16);
+					rval = -EPERM;
+					goto done_free_dma_req;
+				}
+			}
+
+			type = "FC_BSG_HST_VENDOR_LOOPBACK";
+			DEBUG2(qla_printk(KERN_INFO, ha,
+				"scsi(%ld) bsg rqst type: %s\n",
+				vha->host_no, type));
+
+			command_sent = INT_DEF_LB_LOOPBACK_CMD;
+			rval = qla2x00_loopback_test(vha, &elreq, response);
+
+			if (new_config[1]) {
+				/* Revert back to original port config
+				 * Also clear internal loopback
+				 */
+				qla81xx_reset_internal_loopback(vha,
+				    new_config, 0);
+			}
+
+			if (response[0] == MBS_COMMAND_ERROR &&
+					response[1] == MBS_LB_RESET) {
+				DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing "
+					"ISP\n", __func__, vha->host_no));
+				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+				qla2xxx_wake_dpc(vha);
+				qla2x00_wait_for_chip_reset(vha);
+				/* Also reset the MPI */
+				if (qla81xx_restart_mpi_firmware(vha) !=
+				    QLA_SUCCESS) {
+					qla_printk(KERN_INFO, ha,
+					    "MPI reset failed for host%ld.\n",
+					    vha->host_no);
+				}
+
+				bsg_job->reply->reply_payload_rcv_len = 0;
+				bsg_job->reply->result = (DID_ERROR << 16);
+				rval = -EIO;
+				goto done_free_dma_req;
+			}
+		} else {
+			type = "FC_BSG_HST_VENDOR_LOOPBACK";
+			DEBUG2(qla_printk(KERN_INFO, ha,
+				"scsi(%ld) bsg rqst type: %s\n",
+				vha->host_no, type));
+			command_sent = INT_DEF_LB_LOOPBACK_CMD;
+			rval = qla2x00_loopback_test(vha, &elreq, response);
+		}
 	}
 
 	if (rval) {
@@ -1056,6 +1254,20 @@
 		return -EINVAL;
 	}
 
+	if (fcport->loop_id == FC_NO_LOOP_ID) {
+		DEBUG2(printk(KERN_ERR "%s(%ld): Invalid port loop id, "
+			"loop_id = 0x%x\n",
+			__func__, vha->host_no, fcport->loop_id));
+		return -EINVAL;
+	}
+
+	if (fcport->flags & FCF_LOGIN_NEEDED) {
+		DEBUG2(printk(KERN_ERR "%s(%ld): Remote port not logged in, "
+		    "flags = 0x%x\n",
+		    __func__, vha->host_no, fcport->flags));
+		return -EINVAL;
+	}
+
 	if (port_param->mode)
 		rval = qla2x00_set_idma_speed(vha, fcport->loop_id,
 			port_param->speed, mb);
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index 76ed92d..cc7c52f 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -19,6 +19,13 @@
 #define INT_DEF_LB_LOOPBACK_CMD         0
 #define INT_DEF_LB_ECHO_CMD             1
 
+/* Loopback related definations */
+#define EXTERNAL_LOOPBACK		0xF2
+#define ENABLE_INTERNAL_LOOPBACK	0x02
+#define INTERNAL_LOOPBACK_MASK		0x000E
+#define MAX_ELS_FRAME_PAYLOAD		252
+#define ELS_OPCODE_BYTE			0x10
+
 /* BSG Vendor specific definations */
 #define A84_ISSUE_WRITE_TYPE_CMD        0
 #define A84_ISSUE_READ_TYPE_CMD         1
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 2afc8a3..0961411 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index 916c81f..6cfc28a 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 8396109..3a432ea 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -202,6 +202,7 @@
  * SCSI Request Block
  */
 typedef struct srb {
+	atomic_t ref_count;
 	struct fc_port *fcport;
 	uint32_t handle;
 
@@ -249,16 +250,6 @@
 			uint32_t lun;
 			uint32_t data;
 		} tmf;
-		struct {
-			/*
-			 * values for modif field below are as
-			 * defined in mrk_entry_24xx struct
-			 * for the modifier field in qla_fw.h.
-			 */
-			uint8_t modif;
-			uint16_t lun;
-			uint32_t data;
-		} marker;
 	} u;
 
 	struct timer_list timer;
@@ -276,7 +267,6 @@
 #define SRB_CT_CMD	5
 #define SRB_ADISC_CMD	6
 #define SRB_TM_CMD	7
-#define SRB_MARKER_CMD	8
 
 struct srb_ctx {
 	uint16_t type;
@@ -713,6 +703,8 @@
 #define MBC_SEND_RNFT_ELS		0x5e	/* Send RNFT ELS request */
 #define MBC_GET_LINK_PRIV_STATS		0x6d	/* Get link & private data. */
 #define MBC_SET_VENDOR_ID		0x76	/* Set Vendor ID. */
+#define MBC_SET_PORT_CONFIG		0x122	/* Set port configuration */
+#define MBC_GET_PORT_CONFIG		0x123	/* Get port configuration */
 
 /* Firmware return data sizes */
 #define FCAL_MAP_SIZE	128
@@ -1660,8 +1652,14 @@
 	uint8_t port_name[WWN_SIZE];
 	uint8_t fabric_port_name[WWN_SIZE];
 	uint16_t fp_speed;
+	uint8_t fc4_type;
 } sw_info_t;
 
+/* FCP-4 types */
+#define FC4_TYPE_FCP_SCSI	0x08
+#define FC4_TYPE_OTHER		0x0
+#define FC4_TYPE_UNKNOWN	0xff
+
 /*
  * Fibre channel port type.
  */
@@ -1705,6 +1703,7 @@
 	u32 supported_classes;
 
 	uint16_t vp_idx;
+	uint8_t fc4_type;
 } fc_port_t;
 
 /*
@@ -1787,6 +1786,9 @@
 #define	GPSC_REQ_SIZE	(16 + 8)
 #define	GPSC_RSP_SIZE	(16 + 2 + 2)
 
+#define GFF_ID_CMD	0x011F
+#define GFF_ID_REQ_SIZE	(16 + 4)
+#define GFF_ID_RSP_SIZE (16 + 128)
 
 /*
  * HBA attribute types.
@@ -1988,6 +1990,11 @@
 		struct {
 			uint8_t port_name[8];
 		} gpsc;
+
+		struct {
+			uint8_t reserved;
+			uint8_t port_name[3];
+		} gff_id;
 	} req;
 };
 
@@ -2060,6 +2067,11 @@
 			uint16_t speeds;
 			uint16_t speed;
 		} gpsc;
+
+#define GFF_FCP_SCSI_OFFSET	7
+		struct {
+			uint8_t fc4_features[128];
+		} gff_id;
 	} rsp;
 };
 
@@ -2410,6 +2422,7 @@
 		uint32_t	cpu_affinity_enabled	:1;
 		uint32_t	disable_msix_handshake	:1;
 		uint32_t	fcp_prio_enabled	:1;
+		uint32_t	fw_hung	:1;
 	} flags;
 
 	/* This spinlock is used to protect "io transactions", you must
@@ -2630,6 +2643,8 @@
 	struct mutex vport_lock;        /* Virtual port synchronization */
 	struct completion mbx_cmd_comp; /* Serialize mbx access */
 	struct completion mbx_intr_comp;  /* Used for completion notification */
+	struct completion dcbx_comp;	/* For set port config notification */
+	int notify_dcbx_comp;
 
 	/* Basic firmware related information. */
 	uint16_t	fw_major_version;
@@ -2699,6 +2714,8 @@
 	uint8_t 	fcode_revision[16];
 	uint32_t	fw_revision[4];
 
+	uint32_t	gold_fw_version[4];
+
 	/* Offsets for flash/nvram access (set to ~0 if not used). */
 	uint32_t	flash_conf_off;
 	uint32_t	flash_data_off;
@@ -2783,6 +2800,9 @@
 	uint16_t	gbl_dsd_avail;
 	struct list_head gbl_dsd_list;
 #define NUM_DSD_CHAIN 4096
+
+	uint8_t fw_type;
+	__le32 file_prd_off;	/* File firmware product offset */
 };
 
 /*
@@ -2961,9 +2981,15 @@
 
 #define	QLA_DSDS_PER_IOCB	37
 
+#define CMD_SP(Cmnd)		((Cmnd)->SCp.ptr)
+
+enum nexus_wait_type {
+	WAIT_HOST = 0,
+	WAIT_TARGET,
+	WAIT_LUN,
+};
+
 #include "qla_gbl.h"
 #include "qla_dbg.h"
 #include "qla_inline.h"
-
-#define CMD_SP(Cmnd)		((Cmnd)->SCp.ptr)
 #endif
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 3a9a6ca..6271353 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 93f8339..631fefc 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 8217c3b..1a1b281 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -59,7 +59,6 @@
 extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *,
     uint16_t *);
 extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t);
-extern int qla2x00_async_marker(fc_port_t *, uint16_t, uint8_t);
 extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,
     uint16_t *);
 extern void qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *,
@@ -68,8 +67,7 @@
     uint16_t *);
 extern void qla2x00_async_tm_cmd_done(struct scsi_qla_host *, fc_port_t *,
 	struct srb_iocb *);
-extern void qla2x00_async_marker_done(struct scsi_qla_host *, fc_port_t *,
-	struct srb_iocb *);
+extern void *qla2x00_alloc_iocbs(struct scsi_qla_host *, srb_t *);
 
 extern fc_port_t *
 qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t );
@@ -124,6 +122,7 @@
 extern void qla2x00_free_host(struct scsi_qla_host *);
 extern void qla2x00_relogin(struct scsi_qla_host *);
 extern void qla2x00_do_work(struct scsi_qla_host *);
+extern void qla2x00_free_fcports(struct scsi_qla_host *);
 
 /*
  * Global Functions in qla_mid.c source file.
@@ -176,10 +175,7 @@
 extern int qla24xx_start_scsi(srb_t *sp);
 int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
 						uint16_t, uint16_t, uint8_t);
-int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
-						uint16_t, uint16_t, uint8_t);
 extern int qla2x00_start_sp(srb_t *);
-extern void qla2x00_ctx_sp_free(srb_t *);
 extern uint16_t qla24xx_calc_iocbs(uint16_t);
 extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t);
 extern int qla24xx_dif_start_scsi(srb_t *);
@@ -293,7 +289,9 @@
 qla24xx_abort_target(struct fc_port *, unsigned int, int);
 extern int
 qla24xx_lun_reset(struct fc_port *, unsigned int, int);
-
+extern int
+qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *, unsigned int,
+	unsigned int, enum nexus_wait_type);
 extern int
 qla2x00_system_error(scsi_qla_host_t *);
 
@@ -357,6 +355,11 @@
 extern int qla2x00_get_data_rate(scsi_qla_host_t *);
 extern int qla24xx_set_fcp_prio(scsi_qla_host_t *, uint16_t, uint16_t,
 	uint16_t *);
+extern int
+qla81xx_get_port_config(scsi_qla_host_t *, uint16_t *);
+
+extern int
+qla81xx_set_port_config(scsi_qla_host_t *, uint16_t *);
 
 /*
  * Global Function Prototypes in qla_isr.c source file.
@@ -438,6 +441,7 @@
 extern int qla2x00_gid_pt(scsi_qla_host_t *, sw_info_t *);
 extern int qla2x00_gpn_id(scsi_qla_host_t *, sw_info_t *);
 extern int qla2x00_gnn_id(scsi_qla_host_t *, sw_info_t *);
+extern void qla2x00_gff_id(scsi_qla_host_t *, sw_info_t *);
 extern int qla2x00_rft_id(scsi_qla_host_t *);
 extern int qla2x00_rff_id(scsi_qla_host_t *);
 extern int qla2x00_rnn_id(scsi_qla_host_t *);
@@ -482,11 +486,8 @@
 	uint16_t, int, uint8_t);
 extern int qla25xx_create_rsp_que(struct qla_hw_data *, uint16_t, uint8_t,
 	uint16_t, int);
-extern int qla25xx_update_req_que(struct scsi_qla_host *, uint8_t, uint8_t);
 extern void qla2x00_init_response_q_entries(struct rsp_que *);
 extern int qla25xx_delete_req_que(struct scsi_qla_host *, struct req_que *);
-extern int qla25xx_delete_rsp_que(struct scsi_qla_host *, struct rsp_que *);
-extern int qla25xx_create_queues(struct scsi_qla_host *, uint8_t);
 extern int qla25xx_delete_queues(struct scsi_qla_host *);
 extern uint16_t qla24xx_rd_req_reg(struct qla_hw_data *, uint16_t);
 extern uint16_t qla25xx_rd_req_reg(struct qla_hw_data *, uint16_t);
@@ -503,17 +504,12 @@
 extern int qla82xx_pci_mem_write_2M(struct qla_hw_data *, u64, void *, int);
 extern char *qla82xx_pci_info_str(struct scsi_qla_host *, char *);
 extern int qla82xx_pci_region_offset(struct pci_dev *, int);
-extern int qla82xx_pci_region_len(struct pci_dev *, int);
 extern int qla82xx_iospace_config(struct qla_hw_data *);
 
 /* Initialization related functions */
 extern void qla82xx_reset_chip(struct scsi_qla_host *);
 extern void qla82xx_config_rings(struct scsi_qla_host *);
-extern int qla82xx_nvram_config(struct scsi_qla_host *);
 extern int qla82xx_pinit_from_rom(scsi_qla_host_t *);
-extern int qla82xx_load_firmware(scsi_qla_host_t *);
-extern int qla82xx_reset_hw(scsi_qla_host_t *);
-extern int qla82xx_load_risc_blob(scsi_qla_host_t *, uint32_t *);
 extern void qla82xx_watchdog(scsi_qla_host_t *);
 
 /* Firmware and flash related functions */
@@ -569,7 +565,6 @@
 extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *);
 extern void qla82xx_start_iocbs(srb_t *);
 extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *);
-extern void qla82xx_wait_for_pending_commands(scsi_qla_host_t *);
 
 /* BSG related functions */
 extern int qla24xx_bsg_request(struct fc_bsg_job *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 872c55f..4c08392 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -1913,3 +1913,75 @@
 
 	return (rval);
 }
+
+/**
+ * qla2x00_gff_id() - SNS Get FC-4 Features (GFF_ID) query.
+ *
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ */
+void
+qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list)
+{
+	int		rval;
+	uint16_t	i;
+
+	ms_iocb_entry_t	*ms_pkt;
+	struct ct_sns_req	*ct_req;
+	struct ct_sns_rsp	*ct_rsp;
+	struct qla_hw_data *ha = vha->hw;
+	uint8_t fcp_scsi_features = 0;
+
+	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+		/* Set default FC4 Type as UNKNOWN so the default is to
+		 * Process this port */
+		list[i].fc4_type = FC4_TYPE_UNKNOWN;
+
+		/* Do not attempt GFF_ID if we are not FWI_2 capable */
+		if (!IS_FWI2_CAPABLE(ha))
+			continue;
+
+		/* Prepare common MS IOCB */
+		ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GFF_ID_REQ_SIZE,
+		    GFF_ID_RSP_SIZE);
+
+		/* Prepare CT request */
+		ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFF_ID_CMD,
+		    GFF_ID_RSP_SIZE);
+		ct_rsp = &ha->ct_sns->p.rsp;
+
+		/* Prepare CT arguments -- port_id */
+		ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain;
+		ct_req->req.port_id.port_id[1] = list[i].d_id.b.area;
+		ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa;
+
+		/* Execute MS IOCB */
+		rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
+		   sizeof(ms_iocb_entry_t));
+
+		if (rval != QLA_SUCCESS) {
+			DEBUG2_3(printk(KERN_INFO
+			    "scsi(%ld): GFF_ID issue IOCB failed "
+			    "(%d).\n", vha->host_no, rval));
+		} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
+			       "GPN_ID") != QLA_SUCCESS) {
+			DEBUG2_3(printk(KERN_INFO
+			    "scsi(%ld): GFF_ID IOCB status had a "
+			    "failure status code\n", vha->host_no));
+		} else {
+			fcp_scsi_features =
+			   ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET];
+			fcp_scsi_features &= 0x0f;
+
+			if (fcp_scsi_features)
+				list[i].fc4_type = FC4_TYPE_FCP_SCSI;
+			else
+				list[i].fc4_type = FC4_TYPE_OTHER;
+		}
+
+		/* Last device exit. */
+		if (list[i].d_id.b.rsvd_1 != 0)
+			break;
+	}
+}
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index ab2cc71..d863ed2 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -60,12 +60,11 @@
 	ctx = sp->ctx;
 	iocb = ctx->u.iocb_cmd;
 	iocb->timeout(sp);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
 	iocb->free(sp);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
-void
+static void
 qla2x00_ctx_sp_free(srb_t *sp)
 {
 	struct srb_ctx *ctx = sp->ctx;
@@ -122,7 +121,23 @@
 
 /* Asynchronous Login/Logout Routines -------------------------------------- */
 
-#define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2)
+static inline unsigned long
+qla2x00_get_async_timeout(struct scsi_qla_host *vha)
+{
+	unsigned long tmo;
+	struct qla_hw_data *ha = vha->hw;
+
+	/* Firmware should use switch negotiated r_a_tov for timeout. */
+	tmo = ha->r_a_tov / 10 * 2;
+	if (!IS_FWI2_CAPABLE(ha)) {
+		/*
+		 * Except for earlier ISPs where the timeout is seeded from the
+		 * initialization control block.
+		 */
+		tmo = ha->login_timeout;
+	}
+	return tmo;
+}
 
 static void
 qla2x00_async_iocb_timeout(srb_t *sp)
@@ -131,12 +146,22 @@
 	struct srb_ctx *ctx = sp->ctx;
 
 	DEBUG2(printk(KERN_WARNING
-	    "scsi(%ld:%x): Async-%s timeout.\n",
-	    fcport->vha->host_no, sp->handle, ctx->name));
+		"scsi(%ld:%x): Async-%s timeout - portid=%02x%02x%02x.\n",
+		fcport->vha->host_no, sp->handle,
+		ctx->name, fcport->d_id.b.domain,
+		fcport->d_id.b.area, fcport->d_id.b.al_pa));
 
 	fcport->flags &= ~FCF_ASYNC_SENT;
-	if (ctx->type == SRB_LOGIN_CMD)
+	if (ctx->type == SRB_LOGIN_CMD) {
+		struct srb_iocb *lio = ctx->u.iocb_cmd;
 		qla2x00_post_async_logout_work(fcport->vha, fcport, NULL);
+		/* Retry as needed. */
+		lio->u.logio.data[0] = MBS_COMMAND_ERROR;
+		lio->u.logio.data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
+			QLA_LOGIO_LOGIN_RETRIED : 0;
+		qla2x00_post_async_login_done_work(fcport->vha, fcport,
+			lio->u.logio.data);
+	}
 }
 
 static void
@@ -154,7 +179,6 @@
 qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
     uint16_t *data)
 {
-	struct qla_hw_data *ha = vha->hw;
 	srb_t *sp;
 	struct srb_ctx *ctx;
 	struct srb_iocb *lio;
@@ -162,7 +186,7 @@
 
 	rval = QLA_FUNCTION_FAILED;
 	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
-	    ELS_TMO_2_RATOV(ha) + 2);
+	    qla2x00_get_async_timeout(vha) + 2);
 	if (!sp)
 		goto done;
 
@@ -206,7 +230,6 @@
 int
 qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
 {
-	struct qla_hw_data *ha = vha->hw;
 	srb_t *sp;
 	struct srb_ctx *ctx;
 	struct srb_iocb *lio;
@@ -214,7 +237,7 @@
 
 	rval = QLA_FUNCTION_FAILED;
 	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
-	    ELS_TMO_2_RATOV(ha) + 2);
+	    qla2x00_get_async_timeout(vha) + 2);
 	if (!sp)
 		goto done;
 
@@ -255,7 +278,6 @@
 qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
     uint16_t *data)
 {
-	struct qla_hw_data *ha = vha->hw;
 	srb_t *sp;
 	struct srb_ctx *ctx;
 	struct srb_iocb *lio;
@@ -263,7 +285,7 @@
 
 	rval = QLA_FUNCTION_FAILED;
 	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
-	    ELS_TMO_2_RATOV(ha) + 2);
+	    qla2x00_get_async_timeout(vha) + 2);
 	if (!sp)
 		goto done;
 
@@ -307,7 +329,6 @@
 	uint32_t tag)
 {
 	struct scsi_qla_host *vha = fcport->vha;
-	struct qla_hw_data *ha = vha->hw;
 	srb_t *sp;
 	struct srb_ctx *ctx;
 	struct srb_iocb *tcf;
@@ -315,7 +336,7 @@
 
 	rval = QLA_FUNCTION_FAILED;
 	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
-	    ELS_TMO_2_RATOV(ha) + 2);
+	    qla2x00_get_async_timeout(vha) + 2);
 	if (!sp)
 		goto done;
 
@@ -346,58 +367,6 @@
 	return rval;
 }
 
-static void
-qla2x00_async_marker_ctx_done(srb_t *sp)
-{
-	struct srb_ctx *ctx = sp->ctx;
-	struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd;
-
-	qla2x00_async_marker_done(sp->fcport->vha, sp->fcport, iocb);
-	iocb->free(sp);
-}
-
-int
-qla2x00_async_marker(fc_port_t *fcport, uint16_t lun, uint8_t modif)
-{
-	struct scsi_qla_host *vha = fcport->vha;
-	srb_t *sp;
-	struct srb_ctx *ctx;
-	struct srb_iocb *mrk;
-	int rval;
-
-	rval = QLA_FUNCTION_FAILED;
-	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), 0);
-	if (!sp)
-		goto done;
-
-	ctx = sp->ctx;
-	ctx->type = SRB_MARKER_CMD;
-	ctx->name = "marker";
-	mrk = ctx->u.iocb_cmd;
-	mrk->u.marker.lun = lun;
-	mrk->u.marker.modif = modif;
-	mrk->timeout = qla2x00_async_iocb_timeout;
-	mrk->done = qla2x00_async_marker_ctx_done;
-
-	rval = qla2x00_start_sp(sp);
-	if (rval != QLA_SUCCESS)
-		goto done_free_sp;
-
-	DEBUG2(printk(KERN_DEBUG
-	    "scsi(%ld:%x): Async-marker - loop-id=%x "
-	    "portid=%02x%02x%02x.\n",
-	    fcport->vha->host_no, sp->handle, fcport->loop_id,
-	    fcport->d_id.b.domain, fcport->d_id.b.area,
-	    fcport->d_id.b.al_pa));
-
-	return rval;
-
-done_free_sp:
-	mrk->free(sp);
-done:
-	return rval;
-}
-
 void
 qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
     uint16_t *data)
@@ -418,10 +387,11 @@
 		if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
 			set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
 		else
-			qla2x00_mark_device_lost(vha, fcport, 1, 0);
+			qla2x00_mark_device_lost(vha, fcport, 1, 1);
 		break;
 	case MBS_PORT_ID_USED:
 		fcport->loop_id = data[1];
+		qla2x00_post_async_logout_work(vha, fcport, NULL);
 		qla2x00_post_async_login_work(vha, fcport, NULL);
 		break;
 	case MBS_LOOP_ID_USED:
@@ -429,7 +399,7 @@
 		rval = qla2x00_find_new_loop_id(vha, fcport);
 		if (rval != QLA_SUCCESS) {
 			fcport->flags &= ~FCF_ASYNC_SENT;
-			qla2x00_mark_device_lost(vha, fcport, 1, 0);
+			qla2x00_mark_device_lost(vha, fcport, 1, 1);
 			break;
 		}
 		qla2x00_post_async_login_work(vha, fcport, NULL);
@@ -461,7 +431,7 @@
 	if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
 		set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
 	else
-		qla2x00_mark_device_lost(vha, fcport, 1, 0);
+		qla2x00_mark_device_lost(vha, fcport, 1, 1);
 
 	return;
 }
@@ -478,7 +448,8 @@
 	lun = (uint16_t)iocb->u.tmf.lun;
 
 	/* Issue Marker IOCB */
-	rval = qla2x00_async_marker(fcport, lun,
+	rval = qla2x00_marker(vha, vha->hw->req_q_map[0],
+		vha->hw->rsp_q_map[0], fcport->loop_id, lun,
 		flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
 
 	if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) {
@@ -490,24 +461,6 @@
 	return;
 }
 
-void
-qla2x00_async_marker_done(struct scsi_qla_host *vha, fc_port_t *fcport,
-    struct srb_iocb *iocb)
-{
-	/*
-	 * Currently we dont have any specific post response processing
-	 * for this IOCB. We'll just return success or failed
-	 * depending on whether the IOCB command succeeded or failed.
-	 */
-	if (iocb->u.tmf.data) {
-		DEBUG2_3_11(printk(KERN_WARNING
-		    "%s(%ld): Marker IOCB failed (%x).\n",
-		    __func__, vha->host_no, iocb->u.tmf.data));
-	}
-
-	return;
-}
-
 /****************************************************************************/
 /*                QLogic ISP2x00 Hardware Support Functions.                */
 /****************************************************************************/
@@ -613,11 +566,8 @@
 		}
 	}
 
-	if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) {
-		if (qla24xx_read_fcp_prio_cfg(vha))
-			qla_printk(KERN_ERR, ha,
-			"Unable to read FCP priority data.\n");
-	}
+	if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))
+		qla24xx_read_fcp_prio_cfg(vha);
 
 	return (rval);
 }
@@ -1452,8 +1402,11 @@
 
 	if (IS_QLA82XX(ha)) {
 		rval = ha->isp_ops->load_risc(vha, &srisc_address);
-		if (rval == QLA_SUCCESS)
+		if (rval == QLA_SUCCESS) {
+			qla2x00_stop_firmware(vha);
 			goto enable_82xx_npiv;
+		} else
+			goto failed;
 	}
 
 	if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
@@ -1960,7 +1913,8 @@
 			}
 		} else {
 			/* Mailbox cmd failed. Timeout on min_wait. */
-			if (time_after_eq(jiffies, mtime))
+			if (time_after_eq(jiffies, mtime) ||
+			    (IS_QLA82XX(ha) && ha->flags.fw_hung))
 				break;
 		}
 
@@ -2396,7 +2350,7 @@
 	ha->retry_count = nv->retry_count;
 
 	/* Set minimum login_timeout to 4 seconds. */
-	if (nv->login_timeout < ql2xlogintimeout)
+	if (nv->login_timeout != ql2xlogintimeout)
 		nv->login_timeout = ql2xlogintimeout;
 	if (nv->login_timeout < 4)
 		nv->login_timeout = 4;
@@ -2639,7 +2593,8 @@
 			set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
 		if (test_bit(RSCN_UPDATE, &save_flags)) {
 			set_bit(RSCN_UPDATE, &vha->dpc_flags);
-			vha->flags.rscn_queue_overflow = 1;
+			if (!IS_ALOGIO_CAPABLE(ha))
+				vha->flags.rscn_queue_overflow = 1;
 		}
 	}
 
@@ -3124,7 +3079,6 @@
 	return (rval);
 }
 
-
 /*
  * qla2x00_find_all_fabric_devs
  *
@@ -3177,6 +3131,10 @@
 		    qla2x00_gfpn_id(vha, swl) == QLA_SUCCESS) {
 			qla2x00_gpsc(vha, swl);
 		}
+
+		/* If other queries succeeded probe for FC-4 type */
+		if (swl)
+			qla2x00_gff_id(vha, swl);
 	}
 	swl_idx = 0;
 
@@ -3197,8 +3155,9 @@
 		if (qla2x00_is_reserved_id(vha, loop_id))
 			continue;
 
-		if (atomic_read(&vha->loop_down_timer) ||
-		    LOOP_TRANSITION(vha)) {
+		if (ha->current_topology == ISP_CFG_FL &&
+		    (atomic_read(&vha->loop_down_timer) ||
+		     LOOP_TRANSITION(vha))) {
 			atomic_set(&vha->loop_down_timer, 0);
 			set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
 			set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
@@ -3217,6 +3176,7 @@
 				memcpy(new_fcport->fabric_port_name,
 				    swl[swl_idx].fabric_port_name, WWN_SIZE);
 				new_fcport->fp_speed = swl[swl_idx].fp_speed;
+				new_fcport->fc4_type = swl[swl_idx].fc4_type;
 
 				if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
 					last_dev = 1;
@@ -3278,6 +3238,11 @@
 		if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0)
 			continue;
 
+		/* Bypass ports whose FCP-4 type is not FCP_SCSI */
+		if (new_fcport->fc4_type != FC4_TYPE_FCP_SCSI &&
+		    new_fcport->fc4_type != FC4_TYPE_UNKNOWN)
+			continue;
+
 		/* Locate matching device in database. */
 		found = 0;
 		list_for_each_entry(fcport, &vha->vp_fcports, list) {
@@ -3868,8 +3833,13 @@
 	}
 
 	/* Make sure for ISP 82XX IO DMA is complete */
-	if (IS_QLA82XX(ha))
-		qla82xx_wait_for_pending_commands(vha);
+	if (IS_QLA82XX(ha)) {
+		if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
+			WAIT_HOST) == QLA_SUCCESS) {
+			DEBUG2(qla_printk(KERN_INFO, ha,
+			"Done wait for pending commands\n"));
+		}
+	}
 
 	/* Requeue all commands in outstanding command list. */
 	qla2x00_abort_all_cmds(vha, DID_RESET << 16);
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 84c2fea..48f97a9 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 782b30d..579f028 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -11,8 +11,6 @@
 
 #include <scsi/scsi_tcq.h>
 
-static request_t *qla2x00_req_pkt(struct scsi_qla_host *, struct req_que *,
-							struct rsp_que *rsp);
 static void qla2x00_isp_cmd(struct scsi_qla_host *, struct req_que *);
 
 static void qla25xx_set_que(srb_t *, struct rsp_que **);
@@ -463,7 +461,7 @@
  *
  * Returns non-zero if a failure occurred, else zero.
  */
-int
+static int
 __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
 			struct rsp_que *rsp, uint16_t loop_id,
 			uint16_t lun, uint8_t type)
@@ -474,7 +472,7 @@
 	scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
 
 	mrk24 = NULL;
-	mrk = (mrk_entry_t *)qla2x00_req_pkt(vha, req, rsp);
+	mrk = (mrk_entry_t *)qla2x00_alloc_iocbs(vha, 0);
 	if (mrk == NULL) {
 		DEBUG2_3(printk("%s(%ld): failed to allocate Marker IOCB.\n",
 		    __func__, base_vha->host_no));
@@ -521,84 +519,6 @@
 }
 
 /**
- * qla2x00_req_pkt() - Retrieve a request packet from the request ring.
- * @ha: HA context
- *
- * Note: The caller must hold the hardware lock before calling this routine.
- *
- * Returns NULL if function failed, else, a pointer to the request packet.
- */
-static request_t *
-qla2x00_req_pkt(struct scsi_qla_host *vha, struct req_que *req,
-		struct rsp_que *rsp)
-{
-	struct qla_hw_data *ha = vha->hw;
-	device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
-	request_t	*pkt = NULL;
-	uint16_t	cnt;
-	uint32_t	*dword_ptr;
-	uint32_t	timer;
-	uint16_t	req_cnt = 1;
-
-	/* Wait 1 second for slot. */
-	for (timer = HZ; timer; timer--) {
-		if ((req_cnt + 2) >= req->cnt) {
-			/* Calculate number of free request entries. */
-			if (ha->mqenable)
-				cnt = (uint16_t)
-					RD_REG_DWORD(&reg->isp25mq.req_q_out);
-			else {
-				if (IS_QLA82XX(ha))
-					cnt = (uint16_t)RD_REG_DWORD(
-					    &reg->isp82.req_q_out);
-				else if (IS_FWI2_CAPABLE(ha))
-					cnt = (uint16_t)RD_REG_DWORD(
-						&reg->isp24.req_q_out);
-				else
-					cnt = qla2x00_debounce_register(
-						ISP_REQ_Q_OUT(ha, &reg->isp));
-			}
-			if  (req->ring_index < cnt)
-				req->cnt = cnt - req->ring_index;
-			else
-				req->cnt = req->length -
-				    (req->ring_index - cnt);
-		}
-		/* If room for request in request ring. */
-		if ((req_cnt + 2) < req->cnt) {
-			req->cnt--;
-			pkt = req->ring_ptr;
-
-			/* Zero out packet. */
-			dword_ptr = (uint32_t *)pkt;
-			for (cnt = 0; cnt < REQUEST_ENTRY_SIZE / 4; cnt++)
-				*dword_ptr++ = 0;
-
-			/* Set entry count. */
-			pkt->entry_count = 1;
-
-			break;
-		}
-
-		/* Release ring specific lock */
-		spin_unlock_irq(&ha->hardware_lock);
-
-		udelay(2);   /* 2 us */
-
-		/* Check for pending interrupts. */
-		/* During init we issue marker directly */
-		if (!vha->marker_needed && !vha->flags.init_done)
-			qla2x00_poll(rsp);
-		spin_lock_irq(&ha->hardware_lock);
-	}
-	if (!pkt) {
-		DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
-	}
-
-	return (pkt);
-}
-
-/**
  * qla2x00_isp_cmd() - Modify the request ring pointer.
  * @ha: HA context
  *
@@ -792,6 +712,25 @@
 	 * match LBA in CDB + N
 	 */
 	case SCSI_PROT_DIF_TYPE2:
+		if (!ql2xenablehba_err_chk)
+			break;
+
+		if (scsi_prot_sg_count(cmd)) {
+			spt = page_address(sg_page(scsi_prot_sglist(cmd))) +
+			    scsi_prot_sglist(cmd)[0].offset;
+			pkt->app_tag = swab32(spt->app_tag);
+			pkt->app_tag_mask[0] =  0xff;
+			pkt->app_tag_mask[1] =  0xff;
+		}
+
+		pkt->ref_tag = cpu_to_le32((uint32_t)
+		    (0xffffffff & scsi_get_lba(cmd)));
+
+		/* enable ALL bytes of the ref tag */
+		pkt->ref_tag_mask[0] = 0xff;
+		pkt->ref_tag_mask[1] = 0xff;
+		pkt->ref_tag_mask[2] = 0xff;
+		pkt->ref_tag_mask[3] = 0xff;
 		break;
 
 	/* For Type 3 protection: 16 bit GUARD only */
@@ -1142,7 +1081,7 @@
 	total_bytes = data_bytes;
 	dif_bytes = 0;
 	blk_size = cmd->device->sector_size;
-	if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE1) {
+	if (scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
 		dif_bytes = (data_bytes / blk_size) * 8;
 		total_bytes += dif_bytes;
 	}
@@ -1180,6 +1119,12 @@
 	    vha->host_no, dif_bytes, dif_bytes, total_bytes, total_bytes,
 	    crc_ctx_pkt->blk_size, crc_ctx_pkt->blk_size));
 
+	if (!data_bytes || cmd->sc_data_direction == DMA_NONE) {
+		DEBUG18(printk(KERN_INFO "%s: Zero data bytes or DMA-NONE %d\n",
+		    __func__, data_bytes));
+		cmd_pkt->byte_count = __constant_cpu_to_le32(0);
+		return QLA_SUCCESS;
+	}
 	/* Walks data segments */
 
 	cmd_pkt->control_flags |=
@@ -1390,9 +1335,11 @@
 
 #define QDSS_GOT_Q_SPACE	BIT_0
 
-	/* Only process protection in this routine */
-	if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL)
-		return qla24xx_start_scsi(sp);
+	/* Only process protection or >16 cdb in this routine */
+	if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) {
+		if (cmd->cmd_len <= 16)
+			return qla24xx_start_scsi(sp);
+	}
 
 	/* Setup device pointers. */
 
@@ -1559,11 +1506,9 @@
 }
 
 /* Generic Control-SRB manipulation functions. */
-
-static void *
-qla2x00_alloc_iocbs(srb_t *sp)
+void *
+qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp)
 {
-	scsi_qla_host_t	*vha = sp->fcport->vha;
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req = ha->req_q_map[0];
 	device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
@@ -1573,6 +1518,10 @@
 
 	pkt = NULL;
 	req_cnt = 1;
+	handle = 0;
+
+	if (!sp)
+		goto skip_cmd_array;
 
 	/* Check for room in outstanding command list. */
 	handle = req->current_outstanding_cmd;
@@ -1586,10 +1535,18 @@
 	if (index == MAX_OUTSTANDING_COMMANDS)
 		goto queuing_error;
 
+	/* Prep command array. */
+	req->current_outstanding_cmd = handle;
+	req->outstanding_cmds[handle] = sp;
+	sp->handle = handle;
+
+skip_cmd_array:
 	/* Check for room on request queue. */
 	if (req->cnt < req_cnt) {
 		if (ha->mqenable)
 			cnt = RD_REG_DWORD(&reg->isp25mq.req_q_out);
+		else if (IS_QLA82XX(ha))
+			cnt = RD_REG_DWORD(&reg->isp82.req_q_out);
 		else if (IS_FWI2_CAPABLE(ha))
 			cnt = RD_REG_DWORD(&reg->isp24.req_q_out);
 		else
@@ -1606,15 +1563,11 @@
 		goto queuing_error;
 
 	/* Prep packet */
-	req->current_outstanding_cmd = handle;
-	req->outstanding_cmds[handle] = sp;
 	req->cnt -= req_cnt;
-
 	pkt = req->ring_ptr;
 	memset(pkt, 0, REQUEST_ENTRY_SIZE);
 	pkt->entry_count = req_cnt;
 	pkt->handle = handle;
-	sp->handle = handle;
 
 queuing_error:
 	return pkt;
@@ -1683,7 +1636,7 @@
 	struct srb_iocb *lio = ctx->u.iocb_cmd;
 	uint16_t opts;
 
-	mbx->entry_type = MBX_IOCB_TYPE;;
+	mbx->entry_type = MBX_IOCB_TYPE;
 	SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
 	mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT);
 	opts = lio->u.logio.flags & SRB_LOGIN_COND_PLOGI ? BIT_0 : 0;
@@ -1718,7 +1671,7 @@
 {
 	struct qla_hw_data *ha = sp->fcport->vha->hw;
 
-	mbx->entry_type = MBX_IOCB_TYPE;;
+	mbx->entry_type = MBX_IOCB_TYPE;
 	SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
 	mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT);
 	mbx->mb1 = HAS_EXTENDED_IDS(ha) ?
@@ -1795,31 +1748,6 @@
 }
 
 static void
-qla24xx_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk)
-{
-	uint16_t lun;
-	uint8_t modif;
-	struct fc_port *fcport = sp->fcport;
-	scsi_qla_host_t *vha = fcport->vha;
-	struct srb_ctx *ctx = sp->ctx;
-	struct srb_iocb *iocb = ctx->u.iocb_cmd;
-	struct req_que *req = vha->req;
-
-	lun = iocb->u.marker.lun;
-	modif = iocb->u.marker.modif;
-	mrk->entry_type = MARKER_TYPE;
-	mrk->modifier = modif;
-	if (modif !=  MK_SYNC_ALL) {
-		mrk->nport_handle = cpu_to_le16(fcport->loop_id);
-		mrk->lun[1] = LSB(lun);
-		mrk->lun[2] = MSB(lun);
-		host_to_fcp_swap(mrk->lun, sizeof(mrk->lun));
-		mrk->vp_index = vha->vp_idx;
-		mrk->handle = MAKE_HANDLE(req->id, mrk->handle);
-	}
-}
-
-static void
 qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
 {
 	struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job;
@@ -1864,6 +1792,82 @@
 }
 
 static void
+qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb)
+{
+	uint16_t        avail_dsds;
+	uint32_t        *cur_dsd;
+	struct scatterlist *sg;
+	int index;
+	uint16_t tot_dsds;
+	scsi_qla_host_t *vha = sp->fcport->vha;
+	struct qla_hw_data *ha = vha->hw;
+	struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job;
+	int loop_iterartion = 0;
+	int cont_iocb_prsnt = 0;
+	int entry_count = 1;
+
+	memset(ct_iocb, 0, sizeof(ms_iocb_entry_t));
+	ct_iocb->entry_type = CT_IOCB_TYPE;
+	ct_iocb->entry_status = 0;
+	ct_iocb->handle1 = sp->handle;
+	SET_TARGET_ID(ha, ct_iocb->loop_id, sp->fcport->loop_id);
+	ct_iocb->status = __constant_cpu_to_le16(0);
+	ct_iocb->control_flags = __constant_cpu_to_le16(0);
+	ct_iocb->timeout = 0;
+	ct_iocb->cmd_dsd_count =
+	    __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt);
+	ct_iocb->total_dsd_count =
+	    __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt + 1);
+	ct_iocb->req_bytecount =
+	    cpu_to_le32(bsg_job->request_payload.payload_len);
+	ct_iocb->rsp_bytecount =
+	    cpu_to_le32(bsg_job->reply_payload.payload_len);
+
+	ct_iocb->dseg_req_address[0] = cpu_to_le32(LSD(sg_dma_address
+	    (bsg_job->request_payload.sg_list)));
+	ct_iocb->dseg_req_address[1] = cpu_to_le32(MSD(sg_dma_address
+	    (bsg_job->request_payload.sg_list)));
+	ct_iocb->dseg_req_length = ct_iocb->req_bytecount;
+
+	ct_iocb->dseg_rsp_address[0] = cpu_to_le32(LSD(sg_dma_address
+	    (bsg_job->reply_payload.sg_list)));
+	ct_iocb->dseg_rsp_address[1] = cpu_to_le32(MSD(sg_dma_address
+	    (bsg_job->reply_payload.sg_list)));
+	ct_iocb->dseg_rsp_length = ct_iocb->rsp_bytecount;
+
+	avail_dsds = 1;
+	cur_dsd = (uint32_t *)ct_iocb->dseg_rsp_address;
+	index = 0;
+	tot_dsds = bsg_job->reply_payload.sg_cnt;
+
+	for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) {
+		dma_addr_t       sle_dma;
+		cont_a64_entry_t *cont_pkt;
+
+		/* Allocate additional continuation packets? */
+		if (avail_dsds == 0) {
+			/*
+			* Five DSDs are available in the Cont.
+			* Type 1 IOCB.
+			       */
+			cont_pkt = qla2x00_prep_cont_type1_iocb(vha);
+			cur_dsd = (uint32_t *) cont_pkt->dseg_0_address;
+			avail_dsds = 5;
+			cont_iocb_prsnt = 1;
+			entry_count++;
+		}
+
+		sle_dma = sg_dma_address(sg);
+		*cur_dsd++   = cpu_to_le32(LSD(sle_dma));
+		*cur_dsd++   = cpu_to_le32(MSD(sle_dma));
+		*cur_dsd++   = cpu_to_le32(sg_dma_len(sg));
+		loop_iterartion++;
+		avail_dsds--;
+	}
+	ct_iocb->entry_count = entry_count;
+}
+
+static void
 qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
 {
 	uint16_t        avail_dsds;
@@ -1945,7 +1949,7 @@
 
 	rval = QLA_FUNCTION_FAILED;
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	pkt = qla2x00_alloc_iocbs(sp);
+	pkt = qla2x00_alloc_iocbs(sp->fcport->vha, sp);
 	if (!pkt)
 		goto done;
 
@@ -1966,7 +1970,9 @@
 		qla24xx_els_iocb(sp, pkt);
 		break;
 	case SRB_CT_CMD:
-		qla24xx_ct_iocb(sp, pkt);
+		IS_FWI2_CAPABLE(ha) ?
+		qla24xx_ct_iocb(sp, pkt) :
+		qla2x00_ct_iocb(sp, pkt);
 		break;
 	case SRB_ADISC_CMD:
 		IS_FWI2_CAPABLE(ha) ?
@@ -1976,9 +1982,6 @@
 	case SRB_TM_CMD:
 		qla24xx_tm_iocb(sp, pkt);
 		break;
-	case SRB_MARKER_CMD:
-		qla24xx_marker_iocb(sp, pkt);
-		break;
 	default:
 		break;
 	}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index be3d8be..6982ba7 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -545,10 +545,13 @@
 		if (IS_QLA2100(ha))
 			break;
 
-		if (IS_QLA8XXX_TYPE(ha))
+		if (IS_QLA8XXX_TYPE(ha)) {
 			DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x "
 			    "%04x\n", vha->host_no, mb[1], mb[2], mb[3]));
-		else
+			if (ha->notify_dcbx_comp)
+				complete(&ha->dcbx_comp);
+
+		} else
 			DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE "
 			    "received.\n", vha->host_no));
 
@@ -918,12 +921,15 @@
 	    QLA_LOGIO_LOGIN_RETRIED : 0;
 	if (mbx->entry_status) {
 		DEBUG2(printk(KERN_WARNING
-		    "scsi(%ld:%x): Async-%s error entry - entry-status=%x "
-		    "status=%x state-flag=%x status-flags=%x.\n",
+		    "scsi(%ld:%x): Async-%s error entry - portid=%02x%02x%02x "
+		    "entry-status=%x status=%x state-flag=%x "
+		    "status-flags=%x.\n",
 		    fcport->vha->host_no, sp->handle, type,
-		    mbx->entry_status, le16_to_cpu(mbx->status),
-		    le16_to_cpu(mbx->state_flags),
+		    fcport->d_id.b.domain, fcport->d_id.b.area,
+		    fcport->d_id.b.al_pa, mbx->entry_status,
+		    le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags),
 		    le16_to_cpu(mbx->status_flags)));
+
 		DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx)));
 
 		goto logio_done;
@@ -935,16 +941,18 @@
 		status = 0;
 	if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
 		DEBUG2(printk(KERN_DEBUG
-		    "scsi(%ld:%x): Async-%s complete - mbx1=%x.\n",
+		    "scsi(%ld:%x): Async-%s complete - portid=%02x%02x%02x "
+		    "mbx1=%x.\n",
 		    fcport->vha->host_no, sp->handle, type,
-		    le16_to_cpu(mbx->mb1)));
+		    fcport->d_id.b.domain, fcport->d_id.b.area,
+		    fcport->d_id.b.al_pa, le16_to_cpu(mbx->mb1)));
 
 		data[0] = MBS_COMMAND_COMPLETE;
 		if (ctx->type == SRB_LOGIN_CMD) {
 			fcport->port_type = FCT_TARGET;
 			if (le16_to_cpu(mbx->mb1) & BIT_0)
 				fcport->port_type = FCT_INITIATOR;
-			if (le16_to_cpu(mbx->mb1) & BIT_1)
+			else if (le16_to_cpu(mbx->mb1) & BIT_1)
 				fcport->flags |= FCF_FCP2_DEVICE;
 		}
 		goto logio_done;
@@ -963,9 +971,10 @@
 	}
 
 	DEBUG2(printk(KERN_WARNING
-	    "scsi(%ld:%x): Async-%s failed - status=%x mb0=%x mb1=%x mb2=%x "
-	    "mb6=%x mb7=%x.\n",
-	    fcport->vha->host_no, sp->handle, type, status,
+	    "scsi(%ld:%x): Async-%s failed - portid=%02x%02x%02x status=%x "
+	    "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n",
+	    fcport->vha->host_no, sp->handle, type, fcport->d_id.b.domain,
+	    fcport->d_id.b.area, fcport->d_id.b.al_pa, status,
 	    le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
 	    le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
 	    le16_to_cpu(mbx->mb7)));
@@ -975,6 +984,86 @@
 }
 
 static void
+qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
+    sts_entry_t *pkt, int iocb_type)
+{
+	const char func[] = "CT_IOCB";
+	const char *type;
+	struct qla_hw_data *ha = vha->hw;
+	srb_t *sp;
+	struct srb_ctx *sp_bsg;
+	struct fc_bsg_job *bsg_job;
+	uint16_t comp_status;
+
+	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
+	if (!sp)
+		return;
+
+	sp_bsg = sp->ctx;
+	bsg_job = sp_bsg->u.bsg_job;
+
+	type = NULL;
+	switch (sp_bsg->type) {
+	case SRB_CT_CMD:
+		type = "ct pass-through";
+		break;
+	default:
+		qla_printk(KERN_WARNING, ha,
+		    "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
+		    sp_bsg->type);
+		return;
+	}
+
+	comp_status = le16_to_cpu(pkt->comp_status);
+
+	/* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
+	 * fc payload  to the caller
+	 */
+	bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
+	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+
+	if (comp_status != CS_COMPLETE) {
+		if (comp_status == CS_DATA_UNDERRUN) {
+			bsg_job->reply->result = DID_OK << 16;
+			bsg_job->reply->reply_payload_rcv_len =
+			    le16_to_cpu(((sts_entry_t *)pkt)->rsp_info_len);
+
+			DEBUG2(qla_printk(KERN_WARNING, ha,
+			    "scsi(%ld): CT pass-through-%s error "
+			    "comp_status-status=0x%x total_byte = 0x%x.\n",
+			    vha->host_no, type, comp_status,
+			    bsg_job->reply->reply_payload_rcv_len));
+		} else {
+			DEBUG2(qla_printk(KERN_WARNING, ha,
+			    "scsi(%ld): CT pass-through-%s error "
+			    "comp_status-status=0x%x.\n",
+			    vha->host_no, type, comp_status));
+			bsg_job->reply->result = DID_ERROR << 16;
+			bsg_job->reply->reply_payload_rcv_len = 0;
+		}
+		DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt)));
+	} else {
+		bsg_job->reply->result =  DID_OK << 16;;
+		bsg_job->reply->reply_payload_rcv_len =
+		    bsg_job->reply_payload.payload_len;
+		bsg_job->reply_len = 0;
+	}
+
+	dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+	    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+	dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+	    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+
+	if (sp_bsg->type == SRB_ELS_CMD_HST || sp_bsg->type == SRB_CT_CMD)
+		kfree(sp->fcport);
+
+	kfree(sp->ctx);
+	mempool_free(sp, ha->srb_mempool);
+	bsg_job->job_done(bsg_job);
+}
+
+static void
 qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
     struct sts_entry_24xx *pkt, int iocb_type)
 {
@@ -1096,9 +1185,11 @@
 		QLA_LOGIO_LOGIN_RETRIED : 0;
 	if (logio->entry_status) {
 		DEBUG2(printk(KERN_WARNING
-		    "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n",
+		    "scsi(%ld:%x): Async-%s error entry - "
+		    "portid=%02x%02x%02x entry-status=%x.\n",
 		    fcport->vha->host_no, sp->handle, type,
-		    logio->entry_status));
+		    fcport->d_id.b.domain, fcport->d_id.b.area,
+		    fcport->d_id.b.al_pa, logio->entry_status));
 		DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio)));
 
 		goto logio_done;
@@ -1106,8 +1197,11 @@
 
 	if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
 		DEBUG2(printk(KERN_DEBUG
-		    "scsi(%ld:%x): Async-%s complete - iop0=%x.\n",
+		    "scsi(%ld:%x): Async-%s complete - portid=%02x%02x%02x "
+		    "iop0=%x.\n",
 		    fcport->vha->host_no, sp->handle, type,
+		    fcport->d_id.b.domain, fcport->d_id.b.area,
+		    fcport->d_id.b.al_pa,
 		    le32_to_cpu(logio->io_parameter[0])));
 
 		data[0] = MBS_COMMAND_COMPLETE;
@@ -1119,9 +1213,9 @@
 			fcport->port_type = FCT_TARGET;
 			if (iop[0] & BIT_8)
 				fcport->flags |= FCF_FCP2_DEVICE;
-		}
-		if (iop[0] & BIT_5)
+		} else if (iop[0] & BIT_5)
 			fcport->port_type = FCT_INITIATOR;
+
 		if (logio->io_parameter[7] || logio->io_parameter[8])
 			fcport->supported_classes |= FC_COS_CLASS2;
 		if (logio->io_parameter[9] || logio->io_parameter[10])
@@ -1152,8 +1246,10 @@
 	}
 
 	DEBUG2(printk(KERN_WARNING
-	    "scsi(%ld:%x): Async-%s failed - comp=%x iop0=%x iop1=%x.\n",
-	    fcport->vha->host_no, sp->handle, type,
+	    "scsi(%ld:%x): Async-%s failed - portid=%02x%02x%02x comp=%x "
+	    "iop0=%x iop1=%x.\n",
+	    fcport->vha->host_no, sp->handle, type, fcport->d_id.b.domain,
+	    fcport->d_id.b.area, fcport->d_id.b.al_pa,
 	    le16_to_cpu(logio->comp_status),
 	    le32_to_cpu(logio->io_parameter[0]),
 	    le32_to_cpu(logio->io_parameter[1])));
@@ -1222,39 +1318,6 @@
 	iocb->done(sp);
 }
 
-static void
-qla24xx_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
-    struct mrk_entry_24xx *mrk)
-{
-	const char func[] = "MRK-IOCB";
-	const char *type;
-	fc_port_t *fcport;
-	srb_t *sp;
-	struct srb_iocb *iocb;
-	struct srb_ctx *ctx;
-	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)mrk;
-
-	sp = qla2x00_get_sp_from_handle(vha, func, req, mrk);
-	if (!sp)
-		return;
-
-	ctx = sp->ctx;
-	iocb = ctx->u.iocb_cmd;
-	type = ctx->name;
-	fcport = sp->fcport;
-
-	if (sts->entry_status) {
-		iocb->u.marker.data = 1;
-		DEBUG2(printk(KERN_WARNING
-		    "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n",
-		    fcport->vha->host_no, sp->handle, type,
-		    sts->entry_status));
-		DEBUG2(qla2x00_dump_buffer((uint8_t *)mrk, sizeof(*sts)));
-	}
-
-	iocb->done(sp);
-}
-
 /**
  * qla2x00_process_response_queue() - Process response queue entries.
  * @ha: SCSI driver HA context
@@ -1320,6 +1383,9 @@
 			qla2x00_mbx_iocb_entry(vha, rsp->req,
 			    (struct mbx_entry *)pkt);
 			break;
+		case CT_IOCB_TYPE:
+			qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
+			break;
 		default:
 			/* Type Not Supported. */
 			DEBUG4(printk(KERN_WARNING
@@ -1337,8 +1403,9 @@
 }
 
 static inline void
-qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len,
-	struct rsp_que *rsp)
+
+qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
+    uint32_t sense_len, struct rsp_que *rsp)
 {
 	struct scsi_cmnd *cp = sp->cmd;
 
@@ -1347,8 +1414,8 @@
 
 	sp->request_sense_length = sense_len;
 	sp->request_sense_ptr = cp->sense_buffer;
-	if (sp->request_sense_length > 32)
-		sense_len = 32;
+	if (sp->request_sense_length > par_sense_len)
+		sense_len = par_sense_len;
 
 	memcpy(cp->sense_buffer, sense_data, sense_len);
 
@@ -1455,7 +1522,8 @@
 	uint16_t	ox_id;
 	uint8_t		lscsi_status;
 	int32_t		resid;
-	uint32_t	sense_len, rsp_info_len, resid_len, fw_resid_len;
+	uint32_t sense_len, par_sense_len, rsp_info_len, resid_len,
+	    fw_resid_len;
 	uint8_t		*rsp_info, *sense_data;
 	struct qla_hw_data *ha = vha->hw;
 	uint32_t handle;
@@ -1513,7 +1581,8 @@
 	fcport = sp->fcport;
 
 	ox_id = 0;
-	sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
+	sense_len = par_sense_len = rsp_info_len = resid_len =
+	    fw_resid_len = 0;
 	if (IS_FWI2_CAPABLE(ha)) {
 		if (scsi_status & SS_SENSE_LEN_VALID)
 			sense_len = le32_to_cpu(sts24->sense_len);
@@ -1527,6 +1596,7 @@
 		sense_data = sts24->data;
 		host_to_fcp_swap(sts24->data, sizeof(sts24->data));
 		ox_id = le16_to_cpu(sts24->ox_id);
+		par_sense_len = sizeof(sts24->data);
 	} else {
 		if (scsi_status & SS_SENSE_LEN_VALID)
 			sense_len = le16_to_cpu(sts->req_sense_length);
@@ -1535,13 +1605,16 @@
 		resid_len = le32_to_cpu(sts->residual_length);
 		rsp_info = sts->rsp_info;
 		sense_data = sts->req_sense_data;
+		par_sense_len = sizeof(sts->req_sense_data);
 	}
 
 	/* Check for any FCP transport errors. */
 	if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
 		/* Sense data lies beyond any FCP RESPONSE data. */
-		if (IS_FWI2_CAPABLE(ha))
+		if (IS_FWI2_CAPABLE(ha)) {
 			sense_data += rsp_info_len;
+			par_sense_len -= rsp_info_len;
+		}
 		if (rsp_info_len > 3 && rsp_info[3]) {
 			DEBUG2(qla_printk(KERN_INFO, ha,
 			    "scsi(%ld:%d:%d): FCP I/O protocol failure "
@@ -1601,7 +1674,8 @@
 		if (!(scsi_status & SS_SENSE_LEN_VALID))
 			break;
 
-		qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
+		qla2x00_handle_sense(sp, sense_data, par_sense_len, sense_len,
+		    rsp);
 		break;
 
 	case CS_DATA_UNDERRUN:
@@ -1665,7 +1739,8 @@
 			if (!(scsi_status & SS_SENSE_LEN_VALID))
 				break;
 
-			qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
+			qla2x00_handle_sense(sp, sense_data, par_sense_len,
+			    sense_len, rsp);
 		}
 		break;
 
@@ -1700,6 +1775,9 @@
 		break;
 
 	case CS_RESET:
+		cp->result = DID_TRANSPORT_DISRUPTED << 16;
+		break;
+
 	case CS_ABORTED:
 		cp->result = DID_RESET << 16;
 		break;
@@ -1926,10 +2004,6 @@
 			qla24xx_tm_iocb_entry(vha, rsp->req,
 			    (struct tsk_mgmt_entry *)pkt);
 			break;
-		case MARKER_TYPE:
-			qla24xx_marker_iocb_entry(vha, rsp->req,
-			    (struct mrk_entry_24xx *)pkt);
-			break;
                 case CT_IOCB_TYPE:
 			qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
 			clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index f3650d0..6009b0c 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -37,7 +37,7 @@
 	device_reg_t __iomem *reg;
 	uint8_t		abort_active;
 	uint8_t		io_lock_on;
-	uint16_t	command;
+	uint16_t	command = 0;
 	uint16_t	*iptr;
 	uint16_t __iomem *optr;
 	uint32_t	cnt;
@@ -83,6 +83,13 @@
 		return QLA_FUNCTION_TIMEOUT;
 	}
 
+	if (IS_QLA82XX(ha) && ha->flags.fw_hung) {
+		/* Setting Link-Down error */
+		mcp->mb[0] = MBS_LINK_DOWN_ERROR;
+		rval = QLA_FUNCTION_FAILED;
+		goto premature_exit;
+	}
+
 	ha->flags.mbox_busy = 1;
 	/* Save mailbox command for debug */
 	ha->mcp = mcp;
@@ -151,7 +158,8 @@
 				DEBUG2_3_11(printk(KERN_INFO
 				    "%s(%ld): Pending Mailbox timeout. "
 				    "Exiting.\n", __func__, base_vha->host_no));
-				return QLA_FUNCTION_TIMEOUT;
+				rval = QLA_FUNCTION_TIMEOUT;
+				goto premature_exit;
 			}
 			WRT_REG_DWORD(&reg->isp82.hint, HINT_MBX_INT_PENDING);
 		} else if (IS_FWI2_CAPABLE(ha))
@@ -176,7 +184,8 @@
 				DEBUG2_3_11(printk(KERN_INFO
 				    "%s(%ld): Pending Mailbox timeout. "
 				    "Exiting.\n", __func__, base_vha->host_no));
-				return QLA_FUNCTION_TIMEOUT;
+				rval = QLA_FUNCTION_TIMEOUT;
+				goto premature_exit;
 			}
 			WRT_REG_DWORD(&reg->isp82.hint, HINT_MBX_INT_PENDING);
 		} else if (IS_FWI2_CAPABLE(ha))
@@ -214,6 +223,15 @@
 		ha->flags.mbox_int = 0;
 		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
 
+		if (IS_QLA82XX(ha) && ha->flags.fw_hung) {
+			ha->flags.mbox_busy = 0;
+			/* Setting Link-Down error */
+			mcp->mb[0] = MBS_LINK_DOWN_ERROR;
+			ha->mcp = NULL;
+			rval = QLA_FUNCTION_FAILED;
+			goto premature_exit;
+		}
+
 		if (ha->mailbox_out[0] != MBS_COMMAND_COMPLETE)
 			rval = QLA_FUNCTION_FAILED;
 
@@ -279,35 +297,51 @@
 			DEBUG2_3_11(printk("%s(%ld): timeout schedule "
 			"isp_abort_needed.\n", __func__,
 			base_vha->host_no));
-			qla_printk(KERN_WARNING, ha,
-			    "Mailbox command timeout occurred. Scheduling ISP "
-			    "abort. eeh_busy: 0x%x\n", ha->flags.eeh_busy);
-			set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
-			qla2xxx_wake_dpc(vha);
+
+			if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
+			    !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
+			    !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+
+				qla_printk(KERN_WARNING, ha,
+				    "Mailbox command timeout occured. "
+				    "Scheduling ISP " "abort. eeh_busy: 0x%x\n",
+				    ha->flags.eeh_busy);
+				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+				qla2xxx_wake_dpc(vha);
+			}
 		} else if (!abort_active) {
 			/* call abort directly since we are in the DPC thread */
 			DEBUG(printk("%s(%ld): timeout calling abort_isp\n",
 			    __func__, base_vha->host_no));
 			DEBUG2_3_11(printk("%s(%ld): timeout calling "
 			    "abort_isp\n", __func__, base_vha->host_no));
-			qla_printk(KERN_WARNING, ha,
-			    "Mailbox command timeout occurred. Issuing ISP "
-			    "abort.\n");
 
-			set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
-			clear_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
-			if (ha->isp_ops->abort_isp(base_vha)) {
-				/* Failed. retry later. */
-				set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
+			if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
+			    !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
+			    !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+
+				qla_printk(KERN_WARNING, ha,
+				    "Mailbox command timeout occured. "
+				    "Issuing ISP abort.\n");
+
+				set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
+				clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+				if (ha->isp_ops->abort_isp(vha)) {
+					/* Failed. retry later. */
+					set_bit(ISP_ABORT_NEEDED,
+					    &vha->dpc_flags);
+				}
+				clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
+				DEBUG(printk("%s(%ld): finished abort_isp\n",
+				    __func__, vha->host_no));
+				DEBUG2_3_11(printk(
+				    "%s(%ld): finished abort_isp\n",
+				    __func__, vha->host_no));
 			}
-			clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
-			DEBUG(printk("%s(%ld): finished abort_isp\n", __func__,
-			    base_vha->host_no));
-			DEBUG2_3_11(printk("%s(%ld): finished abort_isp\n",
-			    __func__, base_vha->host_no));
 		}
 	}
 
+premature_exit:
 	/* Allow next mbx cmd to come in. */
 	complete(&ha->mbx_cmd_comp);
 
@@ -866,8 +900,8 @@
 
 	l = l;
 	vha = fcport->vha;
-	req = vha->hw->req_q_map[tag];
-	rsp = vha->hw->rsp_q_map[tag];
+	req = vha->hw->req_q_map[0];
+	rsp = req->rsp;
 	mcp->mb[0] = MBC_ABORT_TARGET;
 	mcp->out_mb = MBX_9|MBX_2|MBX_1|MBX_0;
 	if (HAS_EXTENDED_IDS(vha->hw)) {
@@ -915,8 +949,8 @@
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no));
 
 	vha = fcport->vha;
-	req = vha->hw->req_q_map[tag];
-	rsp = vha->hw->rsp_q_map[tag];
+	req = vha->hw->req_q_map[0];
+	rsp = req->rsp;
 	mcp->mb[0] = MBC_LUN_RESET;
 	mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0;
 	if (HAS_EXTENDED_IDS(vha->hw))
@@ -3950,6 +3984,72 @@
 }
 
 int
+qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+	struct qla_hw_data *ha = vha->hw;
+
+	DEBUG11(printk(KERN_INFO
+	    "%s(%ld): entered.\n", __func__, vha->host_no));
+
+	if (!IS_QLA81XX(ha))
+		return QLA_FUNCTION_FAILED;
+	mcp->mb[0] = MBC_GET_PORT_CONFIG;
+	mcp->out_mb = MBX_0;
+	mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+
+	rval = qla2x00_mailbox_command(vha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk(KERN_WARNING
+		    "%s(%ld): failed=%x (%x).\n", __func__,
+		    vha->host_no, rval, mcp->mb[0]));
+	} else {
+		/* Copy all bits to preserve original value */
+		memcpy(mb, &mcp->mb[1], sizeof(uint16_t) * 4);
+
+		DEBUG11(printk(KERN_INFO
+		    "%s(%ld): done.\n", __func__, vha->host_no));
+	}
+	return rval;
+}
+
+int
+qla81xx_set_port_config(scsi_qla_host_t *vha, uint16_t *mb)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk(KERN_INFO
+	    "%s(%ld): entered.\n", __func__, vha->host_no));
+
+	mcp->mb[0] = MBC_SET_PORT_CONFIG;
+	/* Copy all bits to preserve original setting */
+	memcpy(&mcp->mb[1], mb, sizeof(uint16_t) * 4);
+	mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(vha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk(KERN_WARNING
+		    "%s(%ld): failed=%x (%x).\n", __func__,
+		    vha->host_no, rval, mcp->mb[0]));
+	} else
+		DEBUG11(printk(KERN_INFO
+		    "%s(%ld): done.\n", __func__, vha->host_no));
+
+	return rval;
+}
+
+
+int
 qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority,
 		uint16_t *mb)
 {
@@ -4011,7 +4111,7 @@
 		"%s(%ld): entered.\n", __func__, vha->host_no));
 
 	memset(mcp, 0, sizeof(mbx_cmd_t));
-	mcp->mb[0] = MBC_TOGGLE_INTR;
+	mcp->mb[0] = MBC_TOGGLE_INTERRUPT;
 	mcp->mb[1] = 1;
 
 	mcp->out_mb = MBX_1|MBX_0;
@@ -4047,7 +4147,7 @@
 		"%s(%ld): entered.\n", __func__, vha->host_no));
 
 	memset(mcp, 0, sizeof(mbx_cmd_t));
-	mcp->mb[0] = MBC_TOGGLE_INTR;
+	mcp->mb[0] = MBC_TOGGLE_INTERRUPT;
 	mcp->mb[1] = 0;
 
 	mcp->out_mb = MBX_1|MBX_0;
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 8220e7b..987c5b0 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -136,7 +136,8 @@
 
 	/* Check if physical ha port is Up */
 	if (atomic_read(&base_vha->loop_state) == LOOP_DOWN  ||
-		atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
+		atomic_read(&base_vha->loop_state) == LOOP_DEAD ||
+		!(ha->current_topology & ISP_CFG_F)) {
 		vha->vp_err_state =  VP_ERR_PORTDWN;
 		fc_vport_set_state(vha->fc_vport, FC_VPORT_LINKDOWN);
 		goto enable_failed;
@@ -398,7 +399,10 @@
 	host->can_queue = base_vha->req->length + 128;
 	host->this_id = 255;
 	host->cmd_per_lun = 3;
-	host->max_cmd_len = MAX_CMDSZ;
+	if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif)
+		host->max_cmd_len = 32;
+	else
+		host->max_cmd_len = MAX_CMDSZ;
 	host->max_channel = MAX_BUSES - 1;
 	host->max_lun = MAX_LUNS;
 	host->unique_id = host->host_no;
@@ -481,7 +485,7 @@
 	return ret;
 }
 
-int
+static int
 qla25xx_delete_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
 {
 	int ret = -1;
@@ -496,23 +500,6 @@
 	return ret;
 }
 
-int qla25xx_update_req_que(struct scsi_qla_host *vha, uint8_t que, uint8_t qos)
-{
-	int ret = 0;
-	struct qla_hw_data *ha = vha->hw;
-	struct req_que *req = ha->req_q_map[que];
-
-	req->options |= BIT_3;
-	req->qos = qos;
-	ret = qla25xx_init_req_que(vha, req);
-	if (ret != QLA_SUCCESS)
-		DEBUG2_17(printk(KERN_WARNING "%s failed\n", __func__));
-	/* restore options bit */
-	req->options &= ~BIT_3;
-	return ret;
-}
-
-
 /* Delete all queues for a given vhost */
 int
 qla25xx_delete_queues(struct scsi_qla_host *vha)
@@ -739,35 +726,3 @@
 failed:
 	return 0;
 }
-
-int
-qla25xx_create_queues(struct scsi_qla_host *vha, uint8_t qos)
-{
-	uint16_t options = 0;
-	uint8_t ret = 0;
-	struct qla_hw_data *ha = vha->hw;
-	struct rsp_que *rsp;
-
-	options |= BIT_1;
-	ret = qla25xx_create_rsp_que(ha, options, vha->vp_idx, 0, -1);
-	if (!ret) {
-		qla_printk(KERN_WARNING, ha, "Response Que create failed\n");
-		return ret;
-	} else
-		qla_printk(KERN_INFO, ha, "Response Que:%d created.\n", ret);
-	rsp = ha->rsp_q_map[ret];
-
-	options = 0;
-	if (qos & BIT_7)
-		options |= BIT_8;
-	ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, ret,
-					qos & ~BIT_7);
-	if (ret) {
-		vha->req = ha->req_q_map[ret];
-		qla_printk(KERN_INFO, ha, "Request Que:%d created.\n", ret);
-	} else
-		qla_printk(KERN_WARNING, ha, "Request Que create failed\n");
-	rsp->req = ha->req_q_map[ret];
-
-	return ret;
-}
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index ff562de..915b77a 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -19,6 +19,7 @@
 #define QLA82XX_PCI_OCM0_2M (0xc0000)
 #define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800)
 #define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
+#define BLOCK_PROTECT_BITS 0x0F
 
 /* CRB window related */
 #define CRB_BLK(off)	((off >> 20) & 0x3f)
@@ -796,179 +797,6 @@
 	return ret;
 }
 
-int
-qla82xx_wrmem(struct qla_hw_data *ha, u64 off, void *data, int size)
-{
-	int i, j, ret = 0, loop, sz[2], off0;
-	u32 temp;
-	u64 off8, mem_crb, tmpw, word[2] = {0, 0};
-#define MAX_CTL_CHECK   1000
-	/*
-	 * If not MN, go check for MS or invalid.
-	 */
-	if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) {
-		mem_crb = QLA82XX_CRB_QDR_NET;
-	} else {
-		mem_crb = QLA82XX_CRB_DDR_NET;
-		if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
-			return qla82xx_pci_mem_write_direct(ha, off,
-			    data, size);
-	}
-
-	off8 = off & 0xfffffff8;
-	off0 = off & 0x7;
-	sz[0] = (size < (8 - off0)) ? size : (8 - off0);
-	sz[1] = size - sz[0];
-	loop = ((off0 + size - 1) >> 3) + 1;
-
-	if ((size != 8) || (off0 != 0))  {
-		for (i = 0; i < loop; i++) {
-			if (qla82xx_rdmem(ha, off8 + (i << 3), &word[i], 8))
-				return -1;
-		}
-	}
-
-	switch (size) {
-	case 1:
-		tmpw = *((u8 *)data);
-		break;
-	case 2:
-		tmpw = *((u16 *)data);
-		break;
-	case 4:
-		tmpw = *((u32 *)data);
-		break;
-	case 8:
-	default:
-		tmpw = *((u64 *)data);
-		break;
-	}
-
-	word[0] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
-	word[0] |= tmpw << (off0 * 8);
-
-	if (loop == 2) {
-		word[1] &= ~(~0ULL << (sz[1] * 8));
-		word[1] |= tmpw >> (sz[0] * 8);
-	}
-
-	for (i = 0; i < loop; i++) {
-		temp = off8 + (i << 3);
-		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp);
-		temp = 0;
-		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp);
-		temp = word[i] & 0xffffffff;
-		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp);
-		temp = (word[i] >> 32) & 0xffffffff;
-		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp);
-		temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
-		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp);
-		temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
-		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp);
-
-		for (j = 0; j < MAX_CTL_CHECK; j++) {
-			temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
-			if ((temp & MIU_TA_CTL_BUSY) == 0)
-				break;
-		}
-
-		if (j >= MAX_CTL_CHECK) {
-			qla_printk(KERN_WARNING, ha,
-				"%s: Fail to write through agent\n",
-				QLA2XXX_DRIVER_NAME);
-			ret = -1;
-			break;
-		}
-	}
-	return ret;
-}
-
-int
-qla82xx_rdmem(struct qla_hw_data *ha, u64 off, void *data, int size)
-{
-	int i, j = 0, k, start, end, loop, sz[2], off0[2];
-	u32 temp;
-	u64 off8, val, mem_crb, word[2] = {0, 0};
-#define MAX_CTL_CHECK   1000
-
-	/*
-	 * If not MN, go check for MS or invalid.
-	 */
-	if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
-		mem_crb = QLA82XX_CRB_QDR_NET;
-	else {
-		mem_crb = QLA82XX_CRB_DDR_NET;
-		if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
-			return qla82xx_pci_mem_read_direct(ha, off,
-				data, size);
-	}
-
-	off8 = off & 0xfffffff8;
-	off0[0] = off & 0x7;
-	off0[1] = 0;
-	sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]);
-	sz[1] = size - sz[0];
-	loop = ((off0[0] + size - 1) >> 3) + 1;
-
-	for (i = 0; i < loop; i++) {
-		temp = off8 + (i << 3);
-		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp);
-		temp = 0;
-		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp);
-		temp = MIU_TA_CTL_ENABLE;
-		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
-		temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE;
-		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
-
-		for (j = 0; j < MAX_CTL_CHECK; j++) {
-			temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
-			if ((temp & MIU_TA_CTL_BUSY) == 0)
-				break;
-		}
-
-		if (j >= MAX_CTL_CHECK) {
-			qla_printk(KERN_INFO, ha,
-				"%s: Fail to read through agent\n",
-				QLA2XXX_DRIVER_NAME);
-			break;
-		}
-
-		start = off0[i] >> 2;
-		end   = (off0[i] + sz[i] - 1) >> 2;
-		for (k = start; k <= end; k++) {
-			temp = qla82xx_rd_32(ha,
-			    mem_crb + MIU_TEST_AGT_RDDATA(k));
-			word[i] |= ((u64)temp << (32 * k));
-		}
-	}
-
-	if (j >= MAX_CTL_CHECK)
-		return -1;
-
-	if (sz[0] == 8) {
-		val = word[0];
-	} else {
-		val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) |
-			((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8));
-	}
-
-	switch (size) {
-	case 1:
-		*(u8  *)data = val;
-		break;
-	case 2:
-		*(u16 *)data = val;
-		break;
-	case 4:
-		*(u32 *)data = val;
-		break;
-	case 8:
-		*(u64 *)data = val;
-		break;
-	}
-	return 0;
-}
-
 #define MTU_FUDGE_FACTOR 100
 unsigned long qla82xx_decode_crb_addr(unsigned long addr)
 {
@@ -1346,11 +1174,6 @@
 			continue;
 		}
 
-		if (off == (QLA82XX_CRB_PEG_NET_1 + 0x18)) {
-			if (!QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision))
-				buf[i].data = 0x1020;
-		}
-
 		qla82xx_wr_32(ha, off, buf[i].data);
 
 		/* ISP requires much bigger delay to settle down,
@@ -1407,7 +1230,8 @@
 {
 	int  i;
 	long size = 0;
-	long flashaddr = BOOTLD_START, memaddr = BOOTLD_START;
+	long flashaddr = ha->flt_region_bootload << 2;
+	long memaddr = BOOTLD_START;
 	u64 data;
 	u32 high, low;
 	size = (IMAGE_START - BOOTLD_START) / 8;
@@ -1427,12 +1251,8 @@
 	}
 	udelay(100);
 	read_lock(&ha->hw_lock);
-	if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
-		qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
-		qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
-	} else {
-		qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d);
-	}
+	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
+	qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
 	read_unlock(&ha->hw_lock);
 	return 0;
 }
@@ -1459,17 +1279,10 @@
 			    off, data, size);
 	}
 
-	if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
-		off8 = off & 0xfffffff0;
-		off0[0] = off & 0xf;
-		sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]);
-		shift_amount = 4;
-	} else {
-		off8 = off & 0xfffffff8;
-		off0[0] = off & 0x7;
-		sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]);
-		shift_amount = 4;
-	}
+	off8 = off & 0xfffffff0;
+	off0[0] = off & 0xf;
+	sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]);
+	shift_amount = 4;
 	loop = ((off0[0] + size - 1) >> shift_amount) + 1;
 	off0[1] = 0;
 	sz[1] = size - sz[0];
@@ -1549,7 +1362,7 @@
 		u64 off, void *data, int size)
 {
 	int i, j, ret = 0, loop, sz[2], off0;
-	int scale, shift_amount, p3p, startword;
+	int scale, shift_amount, startword;
 	uint32_t temp;
 	uint64_t off8, mem_crb, tmpw, word[2] = {0, 0};
 
@@ -1569,28 +1382,16 @@
 	sz[0] = (size < (8 - off0)) ? size : (8 - off0);
 	sz[1] = size - sz[0];
 
-	if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
-		off8 = off & 0xfffffff0;
-		loop = (((off & 0xf) + size - 1) >> 4) + 1;
-		shift_amount = 4;
-		scale = 2;
-		p3p = 1;
-		startword = (off & 0xf)/8;
-	} else {
-		off8 = off & 0xfffffff8;
-		loop = ((off0 + size - 1) >> 3) + 1;
-		shift_amount = 3;
-		scale = 1;
-		p3p = 0;
-		startword = 0;
-	}
+	off8 = off & 0xfffffff0;
+	loop = (((off & 0xf) + size - 1) >> 4) + 1;
+	shift_amount = 4;
+	scale = 2;
+	startword = (off & 0xf)/8;
 
-	if (p3p || (size != 8) || (off0 != 0)) {
-		for (i = 0; i < loop; i++) {
-			if (qla82xx_pci_mem_read_2M(ha, off8 +
-			    (i << shift_amount), &word[i * scale], 8))
-				return -1;
-		}
+	for (i = 0; i < loop; i++) {
+		if (qla82xx_pci_mem_read_2M(ha, off8 +
+		    (i << shift_amount), &word[i * scale], 8))
+			return -1;
 	}
 
 	switch (size) {
@@ -1609,26 +1410,16 @@
 		break;
 	}
 
-	if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
-		if (sz[0] == 8) {
-			word[startword] = tmpw;
-		} else {
-			word[startword] &=
-				~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
-			word[startword] |= tmpw << (off0 * 8);
-		}
-		if (sz[1] != 0) {
-			word[startword+1] &= ~(~0ULL << (sz[1] * 8));
-			word[startword+1] |= tmpw >> (sz[0] * 8);
-		}
+	if (sz[0] == 8) {
+		word[startword] = tmpw;
 	} else {
-		word[startword] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
+		word[startword] &=
+			~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
 		word[startword] |= tmpw << (off0 * 8);
-
-		if (loop == 2) {
-			word[1] &= ~(~0ULL << (sz[1] * 8));
-			word[1] |= tmpw >> (sz[0] * 8);
-		}
+	}
+	if (sz[1] != 0) {
+		word[startword+1] &= ~(~0ULL << (sz[1] * 8));
+		word[startword+1] |= tmpw >> (sz[0] * 8);
 	}
 
 	/*
@@ -1645,14 +1436,12 @@
 		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp);
 		temp = (word[i * scale] >> 32) & 0xffffffff;
 		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp);
-		if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
-			temp = word[i*scale + 1] & 0xffffffff;
-			qla82xx_wr_32(ha, mem_crb +
-			    MIU_TEST_AGT_WRDATA_UPPER_LO, temp);
-			temp = (word[i*scale + 1] >> 32) & 0xffffffff;
-			qla82xx_wr_32(ha, mem_crb +
-			    MIU_TEST_AGT_WRDATA_UPPER_HI, temp);
-		}
+		temp = word[i*scale + 1] & 0xffffffff;
+		qla82xx_wr_32(ha, mem_crb +
+		    MIU_TEST_AGT_WRDATA_UPPER_LO, temp);
+		temp = (word[i*scale + 1] >> 32) & 0xffffffff;
+		qla82xx_wr_32(ha, mem_crb +
+		    MIU_TEST_AGT_WRDATA_UPPER_HI, temp);
 
 		temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
 		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
@@ -1677,6 +1466,94 @@
 	return ret;
 }
 
+static struct qla82xx_uri_table_desc *
+qla82xx_get_table_desc(const u8 *unirom, int section)
+{
+	uint32_t i;
+	struct qla82xx_uri_table_desc *directory =
+		(struct qla82xx_uri_table_desc *)&unirom[0];
+	__le32 offset;
+	__le32 tab_type;
+	__le32 entries = cpu_to_le32(directory->num_entries);
+
+	for (i = 0; i < entries; i++) {
+		offset = cpu_to_le32(directory->findex) +
+		    (i * cpu_to_le32(directory->entry_size));
+		tab_type = cpu_to_le32(*((u32 *)&unirom[offset] + 8));
+
+		if (tab_type == section)
+			return (struct qla82xx_uri_table_desc *)&unirom[offset];
+	}
+
+	return NULL;
+}
+
+static struct qla82xx_uri_data_desc *
+qla82xx_get_data_desc(struct qla_hw_data *ha,
+	u32 section, u32 idx_offset)
+{
+	const u8 *unirom = ha->hablob->fw->data;
+	int idx = cpu_to_le32(*((int *)&unirom[ha->file_prd_off] + idx_offset));
+	struct qla82xx_uri_table_desc *tab_desc = NULL;
+	__le32 offset;
+
+	tab_desc = qla82xx_get_table_desc(unirom, section);
+	if (!tab_desc)
+		return NULL;
+
+	offset = cpu_to_le32(tab_desc->findex) +
+	    (cpu_to_le32(tab_desc->entry_size) * idx);
+
+	return (struct qla82xx_uri_data_desc *)&unirom[offset];
+}
+
+static u8 *
+qla82xx_get_bootld_offset(struct qla_hw_data *ha)
+{
+	u32 offset = BOOTLD_START;
+	struct qla82xx_uri_data_desc *uri_desc = NULL;
+
+	if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
+		uri_desc = qla82xx_get_data_desc(ha,
+		    QLA82XX_URI_DIR_SECT_BOOTLD, QLA82XX_URI_BOOTLD_IDX_OFF);
+		if (uri_desc)
+			offset = cpu_to_le32(uri_desc->findex);
+	}
+
+	return (u8 *)&ha->hablob->fw->data[offset];
+}
+
+static __le32
+qla82xx_get_fw_size(struct qla_hw_data *ha)
+{
+	struct qla82xx_uri_data_desc *uri_desc = NULL;
+
+	if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
+		uri_desc =  qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW,
+		    QLA82XX_URI_FIRMWARE_IDX_OFF);
+		if (uri_desc)
+			return cpu_to_le32(uri_desc->size);
+	}
+
+	return cpu_to_le32(*(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]);
+}
+
+static u8 *
+qla82xx_get_fw_offs(struct qla_hw_data *ha)
+{
+	u32 offset = IMAGE_START;
+	struct qla82xx_uri_data_desc *uri_desc = NULL;
+
+	if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
+		uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW,
+			QLA82XX_URI_FIRMWARE_IDX_OFF);
+		if (uri_desc)
+			offset = cpu_to_le32(uri_desc->findex);
+	}
+
+	return (u8 *)&ha->hablob->fw->data[offset];
+}
+
 /* PCI related functions */
 char *
 qla82xx_pci_info_str(struct scsi_qla_host *vha, char *str)
@@ -1714,22 +1591,6 @@
 	return val;
 }
 
-int qla82xx_pci_region_len(struct pci_dev *pdev, int region)
-{
-	unsigned long val = 0;
-	u32 control;
-	switch (region) {
-	case 0:
-		pci_read_config_dword(pdev, QLA82XX_PCI_REG_MSIX_TBL, &control);
-		val = control;
-		break;
-	case 1:
-		val = pci_resource_len(pdev, 0) -
-		    qla82xx_pci_region_offset(pdev, 1);
-		break;
-	}
-	return val;
-}
 
 int
 qla82xx_iospace_config(struct qla_hw_data *ha)
@@ -1851,12 +1712,6 @@
 	icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
 	icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
 
-	icb->version = 1;
-	icb->frame_payload_size = 2112;
-	icb->execution_throttle = 8;
-	icb->exchange_count = 128;
-	icb->login_retry_count = 8;
-
 	WRT_REG_DWORD((unsigned long  __iomem *)&reg->req_q_out[0], 0);
 	WRT_REG_DWORD((unsigned long  __iomem *)&reg->rsp_q_in[0], 0);
 	WRT_REG_DWORD((unsigned long  __iomem *)&reg->rsp_q_out[0], 0);
@@ -1878,19 +1733,19 @@
 
 	size = (IMAGE_START - BOOTLD_START) / 8;
 
-	ptr64 = (u64 *)&ha->hablob->fw->data[BOOTLD_START];
+	ptr64 = (u64 *)qla82xx_get_bootld_offset(ha);
 	flashaddr = BOOTLD_START;
 
 	for (i = 0; i < size; i++) {
 		data = cpu_to_le64(ptr64[i]);
-		qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8);
+		if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8))
+			return -EIO;
 		flashaddr += 8;
 	}
 
-	size = *(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET];
-	size = (__force u32)cpu_to_le32(size) / 8;
-	ptr64 = (u64 *)&ha->hablob->fw->data[IMAGE_START];
 	flashaddr = FLASH_ADDR_START;
+	size = (__force u32)qla82xx_get_fw_size(ha) / 8;
+	ptr64 = (u64 *)qla82xx_get_fw_offs(ha);
 
 	for (i = 0; i < size; i++) {
 		data = cpu_to_le64(ptr64[i]);
@@ -1899,19 +1754,85 @@
 			return -EIO;
 		flashaddr += 8;
 	}
+	udelay(100);
 
 	/* Write a magic value to CAMRAM register
 	 * at a specified offset to indicate
 	 * that all data is written and
 	 * ready for firmware to initialize.
 	 */
-	qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), 0x12345678);
+	qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), QLA82XX_BDINFO_MAGIC);
 
-	if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
-		qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
-		qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
-	} else
-		qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d);
+	read_lock(&ha->hw_lock);
+	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
+	qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
+	read_unlock(&ha->hw_lock);
+	return 0;
+}
+
+static int
+qla82xx_set_product_offset(struct qla_hw_data *ha)
+{
+	struct qla82xx_uri_table_desc *ptab_desc = NULL;
+	const uint8_t *unirom = ha->hablob->fw->data;
+	uint32_t i;
+	__le32 entries;
+	__le32 flags, file_chiprev, offset;
+	uint8_t chiprev = ha->chip_revision;
+	/* Hardcoding mn_present flag for P3P */
+	int mn_present = 0;
+	uint32_t flagbit;
+
+	ptab_desc = qla82xx_get_table_desc(unirom,
+		 QLA82XX_URI_DIR_SECT_PRODUCT_TBL);
+       if (!ptab_desc)
+		return -1;
+
+	entries = cpu_to_le32(ptab_desc->num_entries);
+
+	for (i = 0; i < entries; i++) {
+		offset = cpu_to_le32(ptab_desc->findex) +
+			(i * cpu_to_le32(ptab_desc->entry_size));
+		flags = cpu_to_le32(*((int *)&unirom[offset] +
+			QLA82XX_URI_FLAGS_OFF));
+		file_chiprev = cpu_to_le32(*((int *)&unirom[offset] +
+			QLA82XX_URI_CHIP_REV_OFF));
+
+		flagbit = mn_present ? 1 : 2;
+
+		if ((chiprev == file_chiprev) && ((1ULL << flagbit) & flags)) {
+			ha->file_prd_off = offset;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int
+qla82xx_validate_firmware_blob(scsi_qla_host_t *vha, uint8_t fw_type)
+{
+	__le32 val;
+	uint32_t min_size;
+	struct qla_hw_data *ha = vha->hw;
+	const struct firmware *fw = ha->hablob->fw;
+
+	ha->fw_type = fw_type;
+
+	if (fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
+		if (qla82xx_set_product_offset(ha))
+			return -EINVAL;
+
+		min_size = QLA82XX_URI_FW_MIN_SIZE;
+	} else {
+		val = cpu_to_le32(*(u32 *)&fw->data[QLA82XX_FW_MAGIC_OFFSET]);
+		if ((__force u32)val != QLA82XX_BDINFO_MAGIC)
+			return -EINVAL;
+
+		min_size = QLA82XX_FW_MIN_SIZE;
+	}
+
+	if (fw->size < min_size)
+		return -EINVAL;
 	return 0;
 }
 
@@ -2097,8 +2018,6 @@
 
 		if (RD_REG_DWORD(&reg->host_int)) {
 			stat = RD_REG_DWORD(&reg->host_status);
-			if ((stat & HSRX_RISC_INT) == 0)
-				break;
 
 			switch (stat & 0xff) {
 			case 0x1:
@@ -2173,8 +2092,6 @@
 	do {
 		if (RD_REG_DWORD(&reg->host_int)) {
 			stat = RD_REG_DWORD(&reg->host_status);
-			if ((stat & HSRX_RISC_INT) == 0)
-				break;
 
 			switch (stat & 0xff) {
 			case 0x1:
@@ -2424,12 +2341,6 @@
 	struct fw_blob *blob;
 	struct qla_hw_data *ha = vha->hw;
 
-	/* Put both the PEG CMD and RCV PEG to default state
-	 * of 0 before resetting the hardware
-	 */
-	qla82xx_wr_32(ha, CRB_CMDPEG_STATE, 0);
-	qla82xx_wr_32(ha, CRB_RCVPEG_STATE, 0);
-
 	if (qla82xx_pinit_from_rom(vha) != QLA_SUCCESS) {
 		qla_printk(KERN_ERR, ha,
 			"%s: Error during CRB Initialization\n", __func__);
@@ -2470,6 +2381,18 @@
 		goto fw_load_failed;
 	}
 
+	/* Validating firmware blob */
+	if (qla82xx_validate_firmware_blob(vha,
+		QLA82XX_FLASH_ROMIMAGE)) {
+		/* Fallback to URI format */
+		if (qla82xx_validate_firmware_blob(vha,
+			QLA82XX_UNIFIED_ROMIMAGE)) {
+			qla_printk(KERN_ERR, ha,
+				"No valid firmware image found!!!");
+			return QLA_FUNCTION_FAILED;
+		}
+	}
+
 	if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) {
 		qla_printk(KERN_ERR, ha,
 			"%s: Firmware loaded successfully "
@@ -2498,6 +2421,12 @@
 	/* scrub dma mask expansion register */
 	qla82xx_wr_32(ha, CRB_DMA_SHIFT, 0x55555555);
 
+	/* Put both the PEG CMD and RCV PEG to default state
+	 * of 0 before resetting the hardware
+	 */
+	qla82xx_wr_32(ha, CRB_CMDPEG_STATE, 0);
+	qla82xx_wr_32(ha, CRB_RCVPEG_STATE, 0);
+
 	/* Overwrite stale initialization register values */
 	qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0);
 	qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0);
@@ -2977,10 +2906,10 @@
 	if (ret < 0)
 		goto done_unprotect;
 
-	val &= ~(0x7 << 2);
+	val &= ~(BLOCK_PROTECT_BITS << 2);
 	ret = qla82xx_write_status_reg(ha, val);
 	if (ret < 0) {
-		val |= (0x7 << 2);
+		val |= (BLOCK_PROTECT_BITS << 2);
 		qla82xx_write_status_reg(ha, val);
 	}
 
@@ -3008,7 +2937,7 @@
 	if (ret < 0)
 		goto done_protect;
 
-	val |= (0x7 << 2);
+	val |= (BLOCK_PROTECT_BITS << 2);
 	/* LOCK all sectors */
 	ret = qla82xx_write_status_reg(ha, val);
 	if (ret < 0)
@@ -3201,11 +3130,16 @@
 	dbval = 0x04 | (ha->portnum << 5);
 
 	dbval = dbval | (req->id << 8) | (req->ring_index << 16);
-	WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval);
-	wmb();
-	while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) {
-		WRT_REG_DWORD((unsigned long  __iomem *)ha->nxdb_wr_ptr, dbval);
+	if (ql2xdbwr)
+		qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval);
+	else {
+		WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval);
 		wmb();
+		while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) {
+			WRT_REG_DWORD((unsigned long  __iomem *)ha->nxdb_wr_ptr,
+				dbval);
+			wmb();
+		}
 	}
 }
 
@@ -3279,6 +3213,10 @@
 	/* Disable the board */
 	qla_printk(KERN_INFO, ha, "Disabling the board\n");
 
+	qla82xx_idc_lock(ha);
+	qla82xx_clear_drv_active(ha);
+	qla82xx_idc_unlock(ha);
+
 	/* Set DEV_FAILED flag to disable timer */
 	vha->device_flags |= DFLG_DEV_FAILED;
 	qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
@@ -3369,6 +3307,14 @@
 				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
 			}
 			qla2xxx_wake_dpc(vha);
+			if (ha->flags.mbox_busy) {
+				ha->flags.fw_hung = 1;
+				ha->flags.mbox_int = 1;
+				DEBUG2(qla_printk(KERN_ERR, ha,
+				    "Due to fw hung, doing premature "
+				    "completion of mbx command\n"));
+				complete(&ha->mbx_intr_comp);
+			}
 		}
 	}
 	vha->fw_heartbeat_counter = fw_heartbeat_counter;
@@ -3472,6 +3418,14 @@
 				"%s(): Adapter reset needed!\n", __func__);
 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
 			qla2xxx_wake_dpc(vha);
+			if (ha->flags.mbox_busy) {
+				ha->flags.fw_hung = 1;
+				ha->flags.mbox_int = 1;
+				DEBUG2(qla_printk(KERN_ERR, ha,
+				    "Need reset, doing premature "
+				    "completion of mbx command\n"));
+				complete(&ha->mbx_intr_comp);
+			}
 		} else {
 			qla82xx_check_fw_alive(vha);
 		}
@@ -3527,8 +3481,10 @@
 	qla82xx_clear_rst_ready(ha);
 	qla82xx_idc_unlock(ha);
 
-	if (rval == QLA_SUCCESS)
+	if (rval == QLA_SUCCESS) {
+		ha->flags.fw_hung = 0;
 		qla82xx_restart_isp(vha);
+	}
 
 	if (rval) {
 		vha->flags.online = 1;
diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h
index 1b44d01..15559ca 100644
--- a/drivers/scsi/qla2xxx/qla_nx.h
+++ b/drivers/scsi/qla2xxx/qla_nx.h
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -538,11 +538,10 @@
 /* Driver Coexistence Defines */
 #define QLA82XX_CRB_DRV_ACTIVE	     (QLA82XX_CAM_RAM(0x138))
 #define QLA82XX_CRB_DEV_STATE	     (QLA82XX_CAM_RAM(0x140))
-#define QLA82XX_CRB_DEV_PART_INFO    (QLA82XX_CAM_RAM(0x14c))
-#define QLA82XX_CRB_DRV_IDC_VERSION  (QLA82XX_CAM_RAM(0x174))
 #define QLA82XX_CRB_DRV_STATE	     (QLA82XX_CAM_RAM(0x144))
 #define QLA82XX_CRB_DRV_SCRATCH      (QLA82XX_CAM_RAM(0x148))
 #define QLA82XX_CRB_DEV_PART_INFO    (QLA82XX_CAM_RAM(0x14c))
+#define QLA82XX_CRB_DRV_IDC_VERSION  (QLA82XX_CAM_RAM(0x174))
 
 /* Every driver should use these Device State */
 #define QLA82XX_DEV_COLD		1
@@ -774,15 +773,49 @@
 		.pci_int_reg	=	ISR_MSI_INT_TRIGGER(7) },	\
 }
 
+#define BRDCFG_START		0x4000
 #define	BOOTLD_START		0x10000
 #define	IMAGE_START		0x100000
 #define FLASH_ADDR_START	0x43000
 
 /* Magic number to let user know flash is programmed */
 #define QLA82XX_BDINFO_MAGIC	0x12345678
+#define QLA82XX_FW_MAGIC_OFFSET	(BRDCFG_START + 0x128)
 #define FW_SIZE_OFFSET		(0x3e840c)
+#define QLA82XX_FW_MIN_SIZE	0x3fffff
 
-#define QLA82XX_IS_REVISION_P3PLUS(_rev_)	((_rev_) >= 0x50)
+/* UNIFIED ROMIMAGE START */
+#define QLA82XX_URI_FW_MIN_SIZE			0xc8000
+#define QLA82XX_URI_DIR_SECT_PRODUCT_TBL	0x0
+#define QLA82XX_URI_DIR_SECT_BOOTLD		0x6
+#define QLA82XX_URI_DIR_SECT_FW			0x7
+
+/* Offsets */
+#define QLA82XX_URI_CHIP_REV_OFF	10
+#define QLA82XX_URI_FLAGS_OFF		11
+#define QLA82XX_URI_BIOS_VERSION_OFF	12
+#define QLA82XX_URI_BOOTLD_IDX_OFF	27
+#define QLA82XX_URI_FIRMWARE_IDX_OFF	29
+
+struct qla82xx_uri_table_desc{
+	uint32_t	findex;
+	uint32_t	num_entries;
+	uint32_t	entry_size;
+	uint32_t	reserved[5];
+};
+
+struct qla82xx_uri_data_desc{
+	uint32_t	findex;
+	uint32_t	size;
+	uint32_t	reserved[5];
+};
+
+/* UNIFIED ROMIMAGE END */
+
+#define QLA82XX_UNIFIED_ROMIMAGE	3
+#define QLA82XX_FLASH_ROMIMAGE		4
+#define QLA82XX_UNKNOWN_ROMIMAGE	0xff
+
 #define MIU_TEST_AGT_WRDATA_UPPER_LO		(0x0b0)
 #define	MIU_TEST_AGT_WRDATA_UPPER_HI		(0x0b4)
 
@@ -853,7 +886,7 @@
 	struct list_head dsd_list;
 };
 
-#define MBC_TOGGLE_INTR			0x10
+#define MBC_TOGGLE_INTERRUPT	0x10
 
 /* Flash  offset */
 #define FLT_REG_BOOTLOAD_82XX	0x72
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index be1a8fc..ff2172d 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -140,7 +140,7 @@
 		"Enables firmware ETS burst."
 		"Default is 0 - skip ETS enablement.");
 
-int ql2xdbwr;
+int ql2xdbwr = 1;
 module_param(ql2xdbwr, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(ql2xdbwr,
 	"Option to specify scheme for request queue posting\n"
@@ -517,6 +517,7 @@
 	if (!sp)
 		return sp;
 
+	atomic_set(&sp->ref_count, 1);
 	sp->fcport = fcport;
 	sp->cmd = cmd;
 	sp->flags = 0;
@@ -700,7 +701,7 @@
  *    Success (Adapter is online/no flash ops) : 0
  *    Failed  (Adapter is offline/disabled/flash ops in progress) : 1
  */
-int
+static int
 qla2x00_wait_for_reset_ready(scsi_qla_host_t *vha)
 {
 	int		return_status;
@@ -797,6 +798,12 @@
 	return (return_status);
 }
 
+static void
+sp_get(struct srb *sp)
+{
+	atomic_inc(&sp->ref_count);
+}
+
 /**************************************************************************
 * qla2xxx_eh_abort
 *
@@ -825,6 +832,7 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req = vha->req;
 	srb_t *spt;
+	int got_ref = 0;
 
 	fc_block_scsi_eh(cmd);
 
@@ -856,6 +864,10 @@
 		DEBUG2(printk("%s(%ld): aborting sp %p from RISC."
 		" pid=%ld.\n", __func__, vha->host_no, sp, serial));
 
+		/* Get a reference to the sp and drop the lock.*/
+		sp_get(sp);
+		got_ref++;
+
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		if (ha->isp_ops->abort_command(sp)) {
 			DEBUG2(printk("%s(%ld): abort_command "
@@ -881,6 +893,9 @@
 		}
 	}
 
+	if (got_ref)
+		qla2x00_sp_compl(ha, sp);
+
 	qla_printk(KERN_INFO, ha,
 	    "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n",
 	    vha->host_no, id, lun, wait, serial, ret);
@@ -888,24 +903,17 @@
 	return ret;
 }
 
-enum nexus_wait_type {
-	WAIT_HOST = 0,
-	WAIT_TARGET,
-	WAIT_LUN,
-};
-
-static int
+int
 qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t,
-	unsigned int l, srb_t *sp, enum nexus_wait_type type)
+	unsigned int l, enum nexus_wait_type type)
 {
 	int cnt, match, status;
 	unsigned long flags;
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req;
+	srb_t *sp;
 
 	status = QLA_SUCCESS;
-	if (!sp)
-		return status;
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	req = vha->req;
@@ -943,24 +951,6 @@
 	return status;
 }
 
-void qla82xx_wait_for_pending_commands(scsi_qla_host_t *vha)
-{
-	int cnt;
-	srb_t *sp;
-	struct req_que *req = vha->req;
-
-	DEBUG2(qla_printk(KERN_INFO, vha->hw,
-		"Waiting for pending commands\n"));
-	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
-		sp = req->outstanding_cmds[cnt];
-		if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
-			sp, WAIT_HOST) == QLA_SUCCESS) {
-			DEBUG2(qla_printk(KERN_INFO, vha->hw,
-				"Done wait for pending commands\n"));
-		}
-	}
-}
-
 static char *reset_errors[] = {
 	"HBA not online",
 	"HBA not ready",
@@ -996,7 +986,7 @@
 		goto eh_reset_failed;
 	err = 3;
 	if (qla2x00_eh_wait_for_pending_commands(vha, cmd->device->id,
-	    cmd->device->lun, (srb_t *) CMD_SP(cmd), type) != QLA_SUCCESS)
+	    cmd->device->lun, type) != QLA_SUCCESS)
 		goto eh_reset_failed;
 
 	qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n",
@@ -1004,7 +994,7 @@
 
 	return SUCCESS;
 
- eh_reset_failed:
+eh_reset_failed:
 	qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n"
 	    , vha->host_no, cmd->device->id, cmd->device->lun, name,
 	    reset_errors[err]);
@@ -1054,7 +1044,6 @@
 	int ret = FAILED;
 	unsigned int id, lun;
 	unsigned long serial;
-	srb_t *sp = (srb_t *) CMD_SP(cmd);
 
 	fc_block_scsi_eh(cmd);
 
@@ -1081,7 +1070,7 @@
 		goto eh_bus_reset_done;
 
 	/* Flush outstanding commands. */
-	if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, sp, WAIT_HOST) !=
+	if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) !=
 	    QLA_SUCCESS)
 		ret = FAILED;
 
@@ -1116,7 +1105,6 @@
 	int ret = FAILED;
 	unsigned int id, lun;
 	unsigned long serial;
-	srb_t *sp = (srb_t *) CMD_SP(cmd);
 	scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
 
 	fc_block_scsi_eh(cmd);
@@ -1171,7 +1159,7 @@
 	}
 
 	/* Waiting for command to be returned to OS.*/
-	if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, sp, WAIT_HOST) ==
+	if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) ==
 		QLA_SUCCESS)
 		ret = SUCCESS;
 
@@ -1662,7 +1650,7 @@
 	.read_optrom		= qla25xx_read_optrom_data,
 	.write_optrom		= qla24xx_write_optrom_data,
 	.get_flash_version	= qla24xx_get_flash_version,
-	.start_scsi		= qla24xx_start_scsi,
+	.start_scsi		= qla24xx_dif_start_scsi,
 	.abort_isp		= qla2x00_abort_isp,
 };
 
@@ -2113,6 +2101,7 @@
 	init_completion(&ha->mbx_cmd_comp);
 	complete(&ha->mbx_cmd_comp);
 	init_completion(&ha->mbx_intr_comp);
+	init_completion(&ha->dcbx_comp);
 
 	set_bit(0, (unsigned long *) ha->vp_idx_map);
 
@@ -2158,7 +2147,10 @@
 	host->this_id = 255;
 	host->cmd_per_lun = 3;
 	host->unique_id = host->host_no;
-	host->max_cmd_len = MAX_CMDSZ;
+	if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif)
+		host->max_cmd_len = 32;
+	else
+		host->max_cmd_len = MAX_CMDSZ;
 	host->max_channel = MAX_BUSES - 1;
 	host->max_lun = MAX_LUNS;
 	host->transportt = qla2xxx_transport_template;
@@ -2258,7 +2250,7 @@
 	DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
 	    base_vha->host_no, ha));
 
-	if (IS_QLA25XX(ha) && ql2xenabledif) {
+	if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
 		if (ha->fw_attributes & BIT_4) {
 			base_vha->flags.difdix_supported = 1;
 			DEBUG18(qla_printk(KERN_INFO, ha,
@@ -2266,8 +2258,10 @@
 			    " protection.\n"));
 			scsi_host_set_prot(host,
 			    SHOST_DIF_TYPE1_PROTECTION
+			    | SHOST_DIF_TYPE2_PROTECTION
 			    | SHOST_DIF_TYPE3_PROTECTION
 			    | SHOST_DIX_TYPE1_PROTECTION
+			    | SHOST_DIX_TYPE2_PROTECTION
 			    | SHOST_DIX_TYPE3_PROTECTION);
 			scsi_host_set_guard(host, SHOST_DIX_GUARD_CRC);
 		} else
@@ -2402,6 +2396,10 @@
 	scsi_host_put(base_vha->host);
 
 	if (IS_QLA82XX(ha)) {
+		qla82xx_idc_lock(ha);
+		qla82xx_clear_drv_active(ha);
+		qla82xx_idc_unlock(ha);
+
 		iounmap((device_reg_t __iomem *)ha->nx_pcibase);
 		if (!ql2xdbwr)
 			iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr);
@@ -2467,11 +2465,24 @@
 
 	qla2x00_free_irqs(vha);
 
+	qla2x00_free_fcports(vha);
+
 	qla2x00_mem_free(ha);
 
 	qla2x00_free_queues(ha);
 }
 
+void qla2x00_free_fcports(struct scsi_qla_host *vha)
+{
+	fc_port_t *fcport, *tfcport;
+
+	list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list) {
+		list_del(&fcport->list);
+		kfree(fcport);
+		fcport = NULL;
+	}
+}
+
 static inline void
 qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport,
     int defer)
@@ -3463,8 +3474,8 @@
 	CMD_SP(cmd) = NULL;
 }
 
-void
-qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
+static void
+qla2x00_sp_final_compl(struct qla_hw_data *ha, srb_t *sp)
 {
 	struct scsi_cmnd *cmd = sp->cmd;
 
@@ -3485,6 +3496,20 @@
 	cmd->scsi_done(cmd);
 }
 
+void
+qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
+{
+	if (atomic_read(&sp->ref_count) == 0) {
+		DEBUG2(qla_printk(KERN_WARNING, ha,
+		    "SP reference-count to ZERO -- sp=%p\n", sp));
+		DEBUG2(BUG());
+		return;
+	}
+	if (!atomic_dec_and_test(&sp->ref_count))
+		return;
+	qla2x00_sp_final_compl(ha, sp);
+}
+
 /**************************************************************************
 *   qla2x00_timer
 *
diff --git a/drivers/scsi/qla2xxx/qla_settings.h b/drivers/scsi/qla2xxx/qla_settings.h
index 2801c26..f0b2b99 100644
--- a/drivers/scsi/qla2xxx/qla_settings.h
+++ b/drivers/scsi/qla2xxx/qla_settings.h
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index de92504..76de957 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -664,6 +664,11 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req = ha->req_q_map[0];
 
+	def = 0;
+	if (IS_QLA25XX(ha))
+		def = 1;
+	else if (IS_QLA81XX(ha))
+		def = 2;
 	ha->flt_region_flt = flt_addr;
 	wptr = (uint16_t *)req->ring;
 	flt = (struct qla_flt_header *)req->ring;
@@ -691,6 +696,10 @@
 		goto no_flash_data;
 	}
 
+	/* Assign FCP prio region since older FLT's may not have it */
+	ha->flt_region_fcp_prio = ha->flags.port0 ?
+	    fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
+
 	loc = locations[1];
 	cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
 	for ( ; cnt; cnt--, region++) {
@@ -773,13 +782,6 @@
 no_flash_data:
 	/* Use hardcoded defaults. */
 	loc = locations[0];
-	def = 0;
-	if (IS_QLA24XX_TYPE(ha))
-		def = 0;
-	else if (IS_QLA25XX(ha))
-		def = 1;
-	else if (IS_QLA81XX(ha))
-		def = 2;
 	ha->flt_region_fw = def_fw[def];
 	ha->flt_region_boot = def_boot[def];
 	ha->flt_region_vpd_nvram = def_vpd_nvram[def];
@@ -790,14 +792,13 @@
 	ha->flt_region_fdt = def_fdt[def];
 	ha->flt_region_npiv_conf = ha->flags.port0 ?
 	    def_npiv_conf0[def] : def_npiv_conf1[def];
-	ha->flt_region_fcp_prio = ha->flags.port0 ?
-	    fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
 done:
 	DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x "
 	    "vpd_nvram=0x%x vpd=0x%x nvram=0x%x fdt=0x%x flt=0x%x "
-	    "npiv=0x%x.\n", loc, ha->flt_region_boot, ha->flt_region_fw,
-	    ha->flt_region_vpd_nvram, ha->flt_region_vpd, ha->flt_region_nvram,
-	    ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_npiv_conf));
+	    "npiv=0x%x. fcp_prio_cfg=0x%x\n", loc, ha->flt_region_boot,
+	    ha->flt_region_fw, ha->flt_region_vpd_nvram, ha->flt_region_vpd,
+	    ha->flt_region_nvram, ha->flt_region_fdt, ha->flt_region_flt,
+	    ha->flt_region_npiv_conf, ha->flt_region_fcp_prio));
 }
 
 static void
@@ -2758,6 +2759,28 @@
 		ha->fw_revision[3] = dcode[3];
 	}
 
+	/* Check for golden firmware and get version if available */
+	if (!IS_QLA81XX(ha)) {
+		/* Golden firmware is not present in non 81XX adapters */
+		return ret;
+	}
+
+	memset(ha->gold_fw_version, 0, sizeof(ha->gold_fw_version));
+	dcode = mbuf;
+	ha->isp_ops->read_optrom(vha, (uint8_t *)dcode,
+	    ha->flt_region_gold_fw << 2, 32);
+
+	if (dcode[4] == 0xFFFFFFFF && dcode[5] == 0xFFFFFFFF &&
+	    dcode[6] == 0xFFFFFFFF && dcode[7] == 0xFFFFFFFF) {
+		DEBUG2(qla_printk(KERN_INFO, ha,
+		    "%s(%ld): Unrecognized golden fw at 0x%x.\n",
+		    __func__, vha->host_no, ha->flt_region_gold_fw * 4));
+		return ret;
+	}
+
+	for (i = 4; i < 8; i++)
+		ha->gold_fw_version[i-4] = be32_to_cpu(dcode[i]);
+
 	return ret;
 }
 
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 109068d..e75ccb9 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -1,15 +1,15 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2008 QLogic Corporation
+ * Copyright (c)  2003-2010 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.03.02-k2"
+#define QLA2XXX_VERSION      "8.03.03-k0"
 
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MINOR_VER	3
-#define QLA_DRIVER_PATCH_VER	2
-#define QLA_DRIVER_BETA_VER	2
+#define QLA_DRIVER_PATCH_VER	3
+#define QLA_DRIVER_BETA_VER	0
diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig
index 69cbff3..2c33ce6 100644
--- a/drivers/scsi/qla4xxx/Kconfig
+++ b/drivers/scsi/qla4xxx/Kconfig
@@ -1,7 +1,7 @@
 config SCSI_QLA_ISCSI
-	tristate "QLogic ISP4XXX host adapter family support"
-	depends on PCI && SCSI && NET
+	tristate "QLogic ISP4XXX and ISP82XX host adapter family support"
+	depends on PCI && SCSI
 	select SCSI_ISCSI_ATTRS
 	---help---
-	This driver supports the QLogic 40xx (ISP4XXX) iSCSI host
-	adapter family.
+	This driver supports the QLogic 40xx (ISP4XXX) and 8022 (ISP82XX)
+	iSCSI host adapter family.
diff --git a/drivers/scsi/qla4xxx/Makefile b/drivers/scsi/qla4xxx/Makefile
index 86ea37b..0339ff0 100644
--- a/drivers/scsi/qla4xxx/Makefile
+++ b/drivers/scsi/qla4xxx/Makefile
@@ -1,5 +1,5 @@
 qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \
-		ql4_nvram.o ql4_dbg.o
+		ql4_nx.o ql4_nvram.o ql4_dbg.o
 
 obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o
 
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 4288026..a79da8d 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -33,6 +33,8 @@
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_iscsi.h>
 
+#include "ql4_dbg.h"
+#include "ql4_nx.h"
 
 #ifndef PCI_DEVICE_ID_QLOGIC_ISP4010
 #define PCI_DEVICE_ID_QLOGIC_ISP4010	0x4010
@@ -46,6 +48,10 @@
 #define PCI_DEVICE_ID_QLOGIC_ISP4032	0x4032
 #endif
 
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP8022
+#define PCI_DEVICE_ID_QLOGIC_ISP8022	0x8022
+#endif
+
 #define QLA_SUCCESS			0
 #define QLA_ERROR			1
 
@@ -85,15 +91,22 @@
 #define BIT_30	0x40000000
 #define BIT_31	0x80000000
 
+/**
+ * Macros to help code, maintain, etc.
+ **/
+#define ql4_printk(level, ha, format, arg...) \
+	dev_printk(level , &((ha)->pdev->dev) , format , ## arg)
+
+
 /*
  * Host adapter default definitions
  ***********************************/
 #define MAX_HBAS		16
 #define MAX_BUSES		1
-#define MAX_TARGETS		(MAX_PRST_DEV_DB_ENTRIES +  MAX_DEV_DB_ENTRIES)
+#define MAX_TARGETS		MAX_DEV_DB_ENTRIES
 #define MAX_LUNS		0xffff
 #define MAX_AEN_ENTRIES		256 /* should be > EXT_DEF_MAX_AEN_QUEUE */
-#define MAX_DDB_ENTRIES		(MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES)
+#define MAX_DDB_ENTRIES		MAX_DEV_DB_ENTRIES
 #define MAX_PDU_ENTRIES		32
 #define INVALID_ENTRY		0xFFFF
 #define MAX_CMDS_TO_RISC	1024
@@ -118,7 +131,7 @@
 #define DRIVER_NAME			"qla4xxx"
 
 #define MAX_LINKED_CMDS_PER_LUN		3
-#define MAX_REQS_SERVICED_PER_INTR	16
+#define MAX_REQS_SERVICED_PER_INTR	1
 
 #define ISCSI_IPADDR_SIZE		4	/* IP address size */
 #define ISCSI_ALIAS_SIZE		32	/* ISCSI Alias name size */
@@ -134,7 +147,7 @@
 #define SOFT_RESET_TOV			30
 #define RESET_INTR_TOV			3
 #define SEMAPHORE_TOV			10
-#define ADAPTER_INIT_TOV		120
+#define ADAPTER_INIT_TOV		30
 #define ADAPTER_RESET_TOV		180
 #define EXTEND_CMD_TOV			60
 #define WAIT_CMD_TOV			30
@@ -184,8 +197,6 @@
 	uint16_t iocb_tov;
 	uint16_t iocb_cnt;	/* Number of used iocbs */
 	uint16_t cc_stat;
-	u_long r_start;		/* Time we recieve a cmd from OS */
-	u_long u_start;		/* Time when we handed the cmd to F/W */
 
 	/* Used for extended sense / status continuation */
 	uint8_t *req_sense_ptr;
@@ -221,7 +232,6 @@
 	unsigned long dev_scan_wait_to_start_relogin;
 	unsigned long dev_scan_wait_to_complete_relogin;
 
-	uint16_t os_target_id;	/* Target ID */
 	uint16_t fw_ddb_index;	/* DDB firmware index */
 	uint16_t options;
 	uint32_t fw_ddb_device_state; /* F/W Device State  -- see ql4_fw.h */
@@ -285,6 +295,67 @@
 #include "ql4_fw.h"
 #include "ql4_nvram.h"
 
+struct ql82xx_hw_data {
+	/* Offsets for flash/nvram access (set to ~0 if not used). */
+	uint32_t flash_conf_off;
+	uint32_t flash_data_off;
+
+	uint32_t fdt_wrt_disable;
+	uint32_t fdt_erase_cmd;
+	uint32_t fdt_block_size;
+	uint32_t fdt_unprotect_sec_cmd;
+	uint32_t fdt_protect_sec_cmd;
+
+	uint32_t flt_region_flt;
+	uint32_t flt_region_fdt;
+	uint32_t flt_region_boot;
+	uint32_t flt_region_bootload;
+	uint32_t flt_region_fw;
+	uint32_t reserved;
+};
+
+struct qla4_8xxx_legacy_intr_set {
+	uint32_t int_vec_bit;
+	uint32_t tgt_status_reg;
+	uint32_t tgt_mask_reg;
+	uint32_t pci_int_reg;
+};
+
+/* MSI-X Support */
+
+#define QLA_MSIX_DEFAULT	0x00
+#define QLA_MSIX_RSP_Q		0x01
+
+#define QLA_MSIX_ENTRIES	2
+#define QLA_MIDX_DEFAULT	0
+#define QLA_MIDX_RSP_Q		1
+
+struct ql4_msix_entry {
+	int have_irq;
+	uint16_t msix_vector;
+	uint16_t msix_entry;
+};
+
+/*
+ * ISP Operations
+ */
+struct isp_operations {
+	int (*iospace_config) (struct scsi_qla_host *ha);
+	void (*pci_config) (struct scsi_qla_host *);
+	void (*disable_intrs) (struct scsi_qla_host *);
+	void (*enable_intrs) (struct scsi_qla_host *);
+	int (*start_firmware) (struct scsi_qla_host *);
+	irqreturn_t (*intr_handler) (int , void *);
+	void (*interrupt_service_routine) (struct scsi_qla_host *, uint32_t);
+	int (*reset_chip) (struct scsi_qla_host *);
+	int (*reset_firmware) (struct scsi_qla_host *);
+	void (*queue_iocb) (struct scsi_qla_host *);
+	void (*complete_iocb) (struct scsi_qla_host *);
+	uint16_t (*rd_shdw_req_q_out) (struct scsi_qla_host *);
+	uint16_t (*rd_shdw_rsp_q_in) (struct scsi_qla_host *);
+	int (*get_sys_info) (struct scsi_qla_host *);
+};
+
 /*
  * Linux Host Adapter structure
  */
@@ -296,28 +367,39 @@
 #define AF_INIT_DONE			1 /* 0x00000002 */
 #define AF_MBOX_COMMAND			2 /* 0x00000004 */
 #define AF_MBOX_COMMAND_DONE		3 /* 0x00000008 */
+#define AF_DPC_SCHEDULED		5 /* 0x00000020 */
 #define AF_INTERRUPTS_ON		6 /* 0x00000040 */
 #define AF_GET_CRASH_RECORD		7 /* 0x00000080 */
 #define AF_LINK_UP			8 /* 0x00000100 */
 #define AF_IRQ_ATTACHED			10 /* 0x00000400 */
 #define AF_DISABLE_ACB_COMPLETE		11 /* 0x00000800 */
+#define AF_HBA_GOING_AWAY		12 /* 0x00001000 */
+#define AF_INTx_ENABLED			15 /* 0x00008000 */
+#define AF_MSI_ENABLED			16 /* 0x00010000 */
+#define AF_MSIX_ENABLED			17 /* 0x00020000 */
+#define AF_MBOX_COMMAND_NOPOLL		18 /* 0x00040000 */
+
 
 	unsigned long dpc_flags;
 
 #define DPC_RESET_HA			1 /* 0x00000002 */
 #define DPC_RETRY_RESET_HA		2 /* 0x00000004 */
 #define DPC_RELOGIN_DEVICE		3 /* 0x00000008 */
-#define DPC_RESET_HA_DESTROY_DDB_LIST	4 /* 0x00000010 */
+#define DPC_RESET_HA_FW_CONTEXT		4 /* 0x00000010 */
 #define DPC_RESET_HA_INTR		5 /* 0x00000020 */
 #define DPC_ISNS_RESTART		7 /* 0x00000080 */
 #define DPC_AEN				9 /* 0x00000200 */
 #define DPC_GET_DHCP_IP_ADDR		15 /* 0x00008000 */
 #define DPC_LINK_CHANGED		18 /* 0x00040000 */
+#define DPC_RESET_ACTIVE		20 /* 0x00040000 */
+#define DPC_HA_UNRECOVERABLE		21 /* 0x00080000 ISP-82xx only*/
+#define DPC_HA_NEED_QUIESCENT		22 /* 0x00100000 ISP-82xx only*/
+
 
 	struct Scsi_Host *host; /* pointer to host data */
 	uint32_t tot_ddbs;
 
-	uint16_t	iocb_cnt;
+	uint16_t iocb_cnt;
 
 	/* SRB cache. */
 #define SRB_MIN_REQ	128
@@ -332,14 +414,13 @@
 #define MIN_IOBASE_LEN		0x100
 
 	uint16_t req_q_count;
-	uint8_t rsvd1[2];
 
 	unsigned long host_no;
 
 	/* NVRAM registers */
 	struct eeprom_data *nvram;
 	spinlock_t hardware_lock ____cacheline_aligned;
-	uint32_t   eeprom_cmd_data;
+	uint32_t eeprom_cmd_data;
 
 	/* Counters for general statistics */
 	uint64_t isr_count;
@@ -375,7 +456,6 @@
 	uint8_t alias[32];
 	uint8_t name_string[256];
 	uint8_t heartbeat_interval;
-	uint8_t rsvd;
 
 	/* --- From FlashSysInfo --- */
 	uint8_t my_mac[MAC_ADDR_LEN];
@@ -469,6 +549,40 @@
 	struct in6_addr ipv6_addr0;
 	struct in6_addr ipv6_addr1;
 	struct in6_addr ipv6_default_router_addr;
+
+	/* qla82xx specific fields */
+	struct device_reg_82xx  __iomem *qla4_8xxx_reg; /* Base I/O address */
+	unsigned long nx_pcibase;	/* Base I/O address */
+	uint8_t *nx_db_rd_ptr;		/* Doorbell read pointer */
+	unsigned long nx_db_wr_ptr;	/* Door bell write pointer */
+	unsigned long first_page_group_start;
+	unsigned long first_page_group_end;
+
+	uint32_t crb_win;
+	uint32_t curr_window;
+	uint32_t ddr_mn_window;
+	unsigned long mn_win_crb;
+	unsigned long ms_win_crb;
+	int qdr_sn_window;
+	rwlock_t hw_lock;
+	uint16_t func_num;
+	int link_width;
+
+	struct qla4_8xxx_legacy_intr_set nx_legacy_intr;
+	u32 nx_crb_mask;
+
+	uint8_t revision_id;
+	uint32_t fw_heartbeat_counter;
+
+	struct isp_operations *isp_ops;
+	struct ql82xx_hw_data hw;
+
+	struct ql4_msix_entry msix_entries[QLA_MSIX_ENTRIES];
+
+	uint32_t nx_dev_init_timeout;
+	uint32_t nx_reset_timeout;
+
+	struct completion mbx_intr_comp;
 };
 
 static inline int is_ipv4_enabled(struct scsi_qla_host *ha)
@@ -496,6 +610,11 @@
 	return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4032;
 }
 
+static inline int is_qla8022(struct scsi_qla_host *ha)
+{
+	return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022;
+}
+
 static inline int adapter_up(struct scsi_qla_host *ha)
 {
 	return (test_bit(AF_ONLINE, &ha->flags) != 0) &&
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index 855226e..c94c9dd 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -11,7 +11,7 @@
 
 #define MAX_PRST_DEV_DB_ENTRIES		64
 #define MIN_DISC_DEV_DB_ENTRY		MAX_PRST_DEV_DB_ENTRIES
-#define MAX_DEV_DB_ENTRIES 512
+#define MAX_DEV_DB_ENTRIES		512
 
 /*************************************************************************
  *
@@ -37,6 +37,33 @@
 	__le32 rsrvd1[31];	/* 0x84-0xFF */
 };
 
+/*
+ * ISP 82xx I/O Register Set structure definitions.
+ */
+struct device_reg_82xx {
+	__le32 req_q_out;	/* 0x0000 (R): Request Queue out-Pointer. */
+	__le32 reserve1[63];	/* Request Queue out-Pointer. (64 * 4) */
+	__le32 rsp_q_in;	/* 0x0100 (R/W): Response Queue In-Pointer. */
+	__le32 reserve2[63];	/* Response Queue In-Pointer. */
+	__le32 rsp_q_out;	/* 0x0200 (R/W): Response Queue Out-Pointer. */
+	__le32 reserve3[63];	/* Response Queue Out-Pointer. */
+
+	__le32 mailbox_in[8];	/* 0x0300 (R/W): Mail box In registers */
+	__le32 reserve4[24];
+	__le32 hint;		/* 0x0380 (R/W): Host interrupt register */
+#define HINT_MBX_INT_PENDING	BIT_0
+	__le32 reserve5[31];
+	__le32 mailbox_out[8];	/* 0x0400 (R): Mail box Out registers */
+	__le32 reserve6[56];
+
+	__le32 host_status;	/* Offset 0x500 (R): host status */
+#define HSRX_RISC_MB_INT	BIT_0  /* RISC to Host Mailbox interrupt */
+#define HSRX_RISC_IOCB_INT	BIT_1  /* RISC to Host IOCB interrupt */
+
+	__le32 host_int;	/* Offset 0x0504 (R/W): Interrupt status. */
+#define ISRX_82XX_RISC_INT	BIT_0 /* RISC interrupt. */
+};
+
 /*  remote register set (access via PCI memory read/write) */
 struct isp_reg {
 #define MBOX_REG_COUNT 8
@@ -206,6 +233,79 @@
 	uint32_t Asuint32_t;
 };
 
+/* 82XX Support  start */
+/* 82xx Default FLT Addresses */
+#define FA_FLASH_LAYOUT_ADDR_82		0xFC400
+#define FA_FLASH_DESCR_ADDR_82		0xFC000
+#define FA_BOOT_LOAD_ADDR_82		0x04000
+#define FA_BOOT_CODE_ADDR_82		0x20000
+#define FA_RISC_CODE_ADDR_82		0x40000
+#define FA_GOLD_RISC_CODE_ADDR_82	0x80000
+
+/* Flash Description Table */
+struct qla_fdt_layout {
+	uint8_t sig[4];
+	uint16_t version;
+	uint16_t len;
+	uint16_t checksum;
+	uint8_t unused1[2];
+	uint8_t model[16];
+	uint16_t man_id;
+	uint16_t id;
+	uint8_t flags;
+	uint8_t erase_cmd;
+	uint8_t alt_erase_cmd;
+	uint8_t wrt_enable_cmd;
+	uint8_t wrt_enable_bits;
+	uint8_t wrt_sts_reg_cmd;
+	uint8_t unprotect_sec_cmd;
+	uint8_t read_man_id_cmd;
+	uint32_t block_size;
+	uint32_t alt_block_size;
+	uint32_t flash_size;
+	uint32_t wrt_enable_data;
+	uint8_t read_id_addr_len;
+	uint8_t wrt_disable_bits;
+	uint8_t read_dev_id_len;
+	uint8_t chip_erase_cmd;
+	uint16_t read_timeout;
+	uint8_t protect_sec_cmd;
+	uint8_t unused2[65];
+};
+
+/* Flash Layout Table */
+
+struct qla_flt_location {
+	uint8_t sig[4];
+	uint16_t start_lo;
+	uint16_t start_hi;
+	uint8_t version;
+	uint8_t unused[5];
+	uint16_t checksum;
+};
+
+struct qla_flt_header {
+	uint16_t version;
+	uint16_t length;
+	uint16_t checksum;
+	uint16_t unused;
+};
+
+/* 82xx FLT Regions */
+#define FLT_REG_FDT		0x1a
+#define FLT_REG_FLT		0x1c
+#define FLT_REG_BOOTLOAD_82	0x72
+#define FLT_REG_FW_82		0x74
+#define FLT_REG_GOLD_FW_82	0x75
+#define FLT_REG_BOOT_CODE_82	0x78
+
+struct qla_flt_region {
+	uint32_t code;
+	uint32_t size;
+	uint32_t start;
+	uint32_t end;
+};
+
 /*************************************************************************
  *
  *		Mailbox Commands Structures and Definitions
@@ -215,6 +315,10 @@
 /*  Mailbox command definitions */
 #define MBOX_CMD_ABOUT_FW			0x0009
 #define MBOX_CMD_PING				0x000B
+#define MBOX_CMD_ENABLE_INTRS			0x0010
+#define INTR_DISABLE				0
+#define INTR_ENABLE				1
+#define MBOX_CMD_STOP_FW			0x0014
 #define MBOX_CMD_ABORT_TASK			0x0015
 #define MBOX_CMD_LUN_RESET			0x0016
 #define MBOX_CMD_TARGET_WARM_RESET		0x0017
@@ -243,6 +347,7 @@
 #define DDB_DS_LOGIN_IN_PROCESS			0x07
 #define MBOX_CMD_GET_FW_STATE			0x0069
 #define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK_DEFAULTS 0x006A
+#define MBOX_CMD_GET_SYS_INFO			0x0078
 #define MBOX_CMD_RESTORE_FACTORY_DEFAULTS	0x0087
 #define MBOX_CMD_SET_ACB			0x0088
 #define MBOX_CMD_GET_ACB			0x0089
@@ -318,6 +423,15 @@
 #define MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR	0x8022
 #define MBOX_ASTS_SUBNET_STATE_CHANGE		0x8027
 
+/* ACB State Defines */
+#define ACB_STATE_UNCONFIGURED	0x00
+#define ACB_STATE_INVALID	0x01
+#define ACB_STATE_ACQUIRING	0x02
+#define ACB_STATE_TENTATIVE	0x03
+#define ACB_STATE_DEPRICATED	0x04
+#define ACB_STATE_VALID		0x05
+#define ACB_STATE_DISABLING	0x06
+
 /*************************************************************************/
 
 /* Host Adapter Initialization Control Block (from host) */
@@ -558,6 +672,20 @@
 	uint32_t reserved1[39]; /* 170-1ff */
 };	/* 200 */
 
+struct mbx_sys_info {
+	uint8_t board_id_str[16];	/* Keep board ID string first */
+					/* in this structure for GUI. */
+	uint16_t board_id;	/* board ID code */
+	uint16_t phys_port_cnt;	/* number of physical network ports */
+	uint16_t port_num;	/* network port for this PCI function */
+				/* (port 0 is first port) */
+	uint8_t mac_addr[6];	/* MAC address for this PCI function */
+	uint32_t iscsi_pci_func_cnt;	/* number of iSCSI PCI functions */
+	uint32_t pci_func;		/* this PCI function */
+	unsigned char serial_number[16];	/* serial number string */
+	uint8_t reserved[16];
+};
+
 struct crash_record {
 	uint16_t fw_major_version;	/* 00 - 01 */
 	uint16_t fw_minor_version;	/* 02 - 03 */
@@ -814,4 +942,13 @@
 	uint8_t res4[16];	/* 30-3F */
 };
 
+/*
+ * ISP queue - response queue entry definition.
+ */
+struct response {
+	uint8_t data[60];
+	uint32_t signature;
+#define RESPONSE_PROCESSED	0xDEADDEAD	/* Signature */
+};
+
 #endif /*  _QLA4X_FW_H */
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index c4636f6..c9cd5d6 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -10,31 +10,32 @@
 
 struct iscsi_cls_conn;
 
-void qla4xxx_hw_reset(struct scsi_qla_host *ha);
+int qla4xxx_hw_reset(struct scsi_qla_host *ha);
 int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a);
 int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port);
-int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb);
-int qla4xxx_initialize_adapter(struct scsi_qla_host * ha,
+int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb *srb);
+int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
 			       uint8_t renew_ddb_list);
 int qla4xxx_soft_reset(struct scsi_qla_host *ha);
 irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id);
 
-void qla4xxx_free_ddb_list(struct scsi_qla_host * ha);
-void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen);
+void qla4xxx_free_ddb_list(struct scsi_qla_host *ha);
+void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry);
+void qla4xxx_process_aen(struct scsi_qla_host *ha, uint8_t process_aen);
 
-int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha);
-int qla4xxx_relogin_device(struct scsi_qla_host * ha,
-			   struct ddb_entry * ddb_entry);
+int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host *ha);
+int qla4xxx_relogin_device(struct scsi_qla_host *ha,
+			   struct ddb_entry *ddb_entry);
 int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb);
-int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
+int qla4xxx_reset_lun(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry,
 		      int lun);
-int qla4xxx_reset_target(struct scsi_qla_host * ha,
-			 struct ddb_entry * ddb_entry);
-int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
+int qla4xxx_reset_target(struct scsi_qla_host *ha,
+			 struct ddb_entry *ddb_entry);
+int qla4xxx_get_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr,
 		      uint32_t offset, uint32_t len);
-int qla4xxx_get_firmware_status(struct scsi_qla_host * ha);
-int qla4xxx_get_firmware_state(struct scsi_qla_host * ha);
-int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha);
+int qla4xxx_get_firmware_status(struct scsi_qla_host *ha);
+int qla4xxx_get_firmware_state(struct scsi_qla_host *ha);
+int qla4xxx_initialize_fw_cb(struct scsi_qla_host *ha);
 
 /* FIXME: Goodness!  this really wants a small struct to hold the
  * parameters. On x86 the args will get passed on the stack! */
@@ -54,20 +55,20 @@
 
 void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
 				 struct ddb_entry *ddb_entry);
-u16 rd_nvram_word(struct scsi_qla_host * ha, int offset);
-void qla4xxx_get_crash_record(struct scsi_qla_host * ha);
+u16 rd_nvram_word(struct scsi_qla_host *ha, int offset);
+void qla4xxx_get_crash_record(struct scsi_qla_host *ha);
 struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha);
 int qla4xxx_add_sess(struct ddb_entry *);
 void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry);
-int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha);
+int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host *ha);
 int qla4xxx_get_fw_version(struct scsi_qla_host * ha);
-void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
+void qla4xxx_interrupt_service_routine(struct scsi_qla_host *ha,
 				       uint32_t intr_status);
-int qla4xxx_init_rings(struct scsi_qla_host * ha);
-struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
-					uint32_t index);
+int qla4xxx_init_rings(struct scsi_qla_host *ha);
 void qla4xxx_srb_compl(struct kref *ref);
-int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
+struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
+		uint32_t index);
+int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha);
 int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
 		uint32_t state, uint32_t conn_error);
 void qla4xxx_dump_buffer(void *b, uint32_t size);
@@ -75,8 +76,65 @@
 	struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod);
 int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err);
 
+int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+		uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts);
+
+void qla4xxx_queue_iocb(struct scsi_qla_host *ha);
+void qla4xxx_complete_iocb(struct scsi_qla_host *ha);
+int qla4xxx_get_sys_info(struct scsi_qla_host *ha);
+int qla4xxx_iospace_config(struct scsi_qla_host *ha);
+void qla4xxx_pci_config(struct scsi_qla_host *ha);
+int qla4xxx_start_firmware(struct scsi_qla_host *ha);
+irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id);
+uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha);
+uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha);
+int qla4xxx_request_irqs(struct scsi_qla_host *ha);
+void qla4xxx_free_irqs(struct scsi_qla_host *ha);
+void qla4xxx_process_response_queue(struct scsi_qla_host *ha);
+void qla4xxx_wake_dpc(struct scsi_qla_host *ha);
+void qla4xxx_get_conn_event_log(struct scsi_qla_host *ha);
+
+void qla4_8xxx_pci_config(struct scsi_qla_host *);
+int qla4_8xxx_iospace_config(struct scsi_qla_host *ha);
+int qla4_8xxx_load_risc(struct scsi_qla_host *);
+irqreturn_t qla4_8xxx_intr_handler(int irq, void *dev_id);
+void qla4_8xxx_queue_iocb(struct scsi_qla_host *ha);
+void qla4_8xxx_complete_iocb(struct scsi_qla_host *ha);
+
+int qla4_8xxx_crb_win_lock(struct scsi_qla_host *);
+void qla4_8xxx_crb_win_unlock(struct scsi_qla_host *);
+int qla4_8xxx_pci_get_crb_addr_2M(struct scsi_qla_host *, ulong *);
+void qla4_8xxx_wr_32(struct scsi_qla_host *, ulong, u32);
+int qla4_8xxx_rd_32(struct scsi_qla_host *, ulong);
+int qla4_8xxx_pci_mem_read_2M(struct scsi_qla_host *, u64, void *, int);
+int qla4_8xxx_pci_mem_write_2M(struct scsi_qla_host *ha, u64, void *, int);
+int qla4_8xxx_isp_reset(struct scsi_qla_host *ha);
+void qla4_8xxx_interrupt_service_routine(struct scsi_qla_host *ha,
+		uint32_t intr_status);
+uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha);
+uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha);
+int qla4_8xxx_get_sys_info(struct scsi_qla_host *ha);
+void qla4_8xxx_watchdog(struct scsi_qla_host *ha);
+int qla4_8xxx_stop_firmware(struct scsi_qla_host *ha);
+int qla4_8xxx_get_flash_info(struct scsi_qla_host *ha);
+void qla4_8xxx_enable_intrs(struct scsi_qla_host *ha);
+void qla4_8xxx_disable_intrs(struct scsi_qla_host *ha);
+int qla4_8xxx_enable_msix(struct scsi_qla_host *ha);
+void qla4_8xxx_disable_msix(struct scsi_qla_host *ha);
+irqreturn_t qla4_8xxx_msi_handler(int irq, void *dev_id);
+irqreturn_t qla4_8xxx_default_intr_handler(int irq, void *dev_id);
+irqreturn_t qla4_8xxx_msix_rsp_q(int irq, void *dev_id);
+void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha);
+void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha);
+int qla4_8xxx_idc_lock(struct scsi_qla_host *ha);
+void qla4_8xxx_idc_unlock(struct scsi_qla_host *ha);
+int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha);
+void qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha);
+void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha);
+
 extern int ql4xextended_error_logging;
 extern int ql4xdiscoverywait;
 extern int ql4xdontresethba;
-extern int ql4_mod_unload;
+extern int ql4xenablemsix;
+
 #endif /* _QLA4x_GBL_H */
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index cd30432..3007357 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -11,8 +11,8 @@
 #include "ql4_dbg.h"
 #include "ql4_inline.h"
 
-static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
-					    uint32_t fw_ddb_index);
+static struct ddb_entry *qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+					   uint32_t fw_ddb_index);
 
 static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
 {
@@ -51,8 +51,8 @@
  * This routine deallocates and unlinks the specified ddb_entry from the
  * adapter's
  **/
-static void qla4xxx_free_ddb(struct scsi_qla_host *ha,
-			     struct ddb_entry *ddb_entry)
+void qla4xxx_free_ddb(struct scsi_qla_host *ha,
+    struct ddb_entry *ddb_entry)
 {
 	/* Remove device entry from list */
 	list_del_init(&ddb_entry->list);
@@ -86,6 +86,25 @@
 }
 
 /**
+ * qla4xxx_init_response_q_entries() - Initializes response queue entries.
+ * @ha: HA context
+ *
+ * Beginning of request ring has initialization control block already built
+ * by nvram config routine.
+ **/
+static void qla4xxx_init_response_q_entries(struct scsi_qla_host *ha)
+{
+	uint16_t cnt;
+	struct response *pkt;
+
+	pkt = (struct response *)ha->response_ptr;
+	for (cnt = 0; cnt < RESPONSE_QUEUE_DEPTH; cnt++) {
+		pkt->signature = RESPONSE_PROCESSED;
+		pkt++;
+	}
+}
+
+/**
  * qla4xxx_init_rings - initialize hw queues
  * @ha: pointer to host adapter structure.
  *
@@ -109,19 +128,31 @@
 	ha->response_out = 0;
 	ha->response_ptr = &ha->response_ring[ha->response_out];
 
-	/*
-	 * Initialize DMA Shadow registers.  The firmware is really supposed to
-	 * take care of this, but on some uniprocessor systems, the shadow
-	 * registers aren't cleared-- causing the interrupt_handler to think
-	 * there are responses to be processed when there aren't.
-	 */
-	ha->shadow_regs->req_q_out = __constant_cpu_to_le32(0);
-	ha->shadow_regs->rsp_q_in = __constant_cpu_to_le32(0);
-	wmb();
+	if (is_qla8022(ha)) {
+		writel(0,
+		    (unsigned long  __iomem *)&ha->qla4_8xxx_reg->req_q_out);
+		writel(0,
+		    (unsigned long  __iomem *)&ha->qla4_8xxx_reg->rsp_q_in);
+		writel(0,
+		    (unsigned long  __iomem *)&ha->qla4_8xxx_reg->rsp_q_out);
+	} else {
+		/*
+		 * Initialize DMA Shadow registers.  The firmware is really
+		 * supposed to take care of this, but on some uniprocessor
+		 * systems, the shadow registers aren't cleared-- causing
+		 * the interrupt_handler to think there are responses to be
+		 * processed when there aren't.
+		 */
+		ha->shadow_regs->req_q_out = __constant_cpu_to_le32(0);
+		ha->shadow_regs->rsp_q_in = __constant_cpu_to_le32(0);
+		wmb();
 
-	writel(0, &ha->reg->req_q_in);
-	writel(0, &ha->reg->rsp_q_out);
-	readl(&ha->reg->rsp_q_out);
+		writel(0, &ha->reg->req_q_in);
+		writel(0, &ha->reg->rsp_q_out);
+		readl(&ha->reg->rsp_q_out);
+	}
+
+	qla4xxx_init_response_q_entries(ha);
 
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
@@ -129,11 +160,11 @@
 }
 
 /**
- * qla4xxx_validate_mac_address - validate adapter MAC address(es)
+ * qla4xxx_get_sys_info - validate adapter MAC address(es)
  * @ha: pointer to host adapter structure.
  *
  **/
-static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha)
+int qla4xxx_get_sys_info(struct scsi_qla_host *ha)
 {
 	struct flash_sys_info *sys_info;
 	dma_addr_t sys_info_dma;
@@ -145,7 +176,7 @@
 		DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
 			      ha->host_no, __func__));
 
-		goto exit_validate_mac_no_free;
+		goto exit_get_sys_info_no_free;
 	}
 	memset(sys_info, 0, sizeof(*sys_info));
 
@@ -155,7 +186,7 @@
 		DEBUG2(printk("scsi%ld: %s: get_flash FLASH_OFFSET_SYS_INFO "
 			      "failed\n", ha->host_no, __func__));
 
-		goto exit_validate_mac;
+		goto exit_get_sys_info;
 	}
 
 	/* Save M.A.C. address & serial_number */
@@ -168,11 +199,11 @@
 
 	status = QLA_SUCCESS;
 
- exit_validate_mac:
+exit_get_sys_info:
 	dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info,
 			  sys_info_dma);
 
- exit_validate_mac_no_free:
+exit_get_sys_info_no_free:
 	return status;
 }
 
@@ -266,7 +297,7 @@
 	uint32_t timeout_count;
 	int ready = 0;
 
-	DEBUG2(dev_info(&ha->pdev->dev, "Waiting for Firmware Ready..\n"));
+	DEBUG2(ql4_printk(KERN_INFO, ha, "Waiting for Firmware Ready..\n"));
 	for (timeout_count = ADAPTER_INIT_TOV; timeout_count > 0;
 	     timeout_count--) {
 		if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
@@ -339,29 +370,29 @@
 
 			if (!qla4xxx_wait_for_ip_config(ha) ||
 							timeout_count == 1) {
-				DEBUG2(dev_info(&ha->pdev->dev,
-						"Firmware Ready..\n"));
+				DEBUG2(ql4_printk(KERN_INFO, ha,
+				    "Firmware Ready..\n"));
 				/* The firmware is ready to process SCSI
 				   commands. */
-				DEBUG2(dev_info(&ha->pdev->dev,
+				DEBUG2(ql4_printk(KERN_INFO, ha,
 					"scsi%ld: %s: MEDIA TYPE"
 					" - %s\n", ha->host_no,
 					__func__, (ha->addl_fw_state &
 					FW_ADDSTATE_OPTICAL_MEDIA)
 					!= 0 ? "OPTICAL" : "COPPER"));
-				DEBUG2(dev_info(&ha->pdev->dev,
+				DEBUG2(ql4_printk(KERN_INFO, ha,
 					"scsi%ld: %s: DHCPv4 STATE"
 					" Enabled %s\n", ha->host_no,
 					 __func__, (ha->addl_fw_state &
 					 FW_ADDSTATE_DHCPv4_ENABLED) != 0 ?
 					"YES" : "NO"));
-				DEBUG2(dev_info(&ha->pdev->dev,
+				DEBUG2(ql4_printk(KERN_INFO, ha,
 					"scsi%ld: %s: LINK %s\n",
 					ha->host_no, __func__,
 					(ha->addl_fw_state &
 					 FW_ADDSTATE_LINK_UP) != 0 ?
 					"UP" : "DOWN"));
-				DEBUG2(dev_info(&ha->pdev->dev,
+				DEBUG2(ql4_printk(KERN_INFO, ha,
 					"scsi%ld: %s: iSNS Service "
 					"Started %s\n",
 					ha->host_no, __func__,
@@ -399,6 +430,7 @@
 		DEBUG2(printk("scsi%ld: %s: FW initialized, but "
 			      "auto-discovery still in process\n",
 			       ha->host_no, __func__));
+		ready = 1;
 	}
 
 	return ready;
@@ -413,7 +445,7 @@
 {
 	int status = QLA_ERROR;
 
-	dev_info(&ha->pdev->dev, "Initializing firmware..\n");
+	ql4_printk(KERN_INFO, ha, "Initializing firmware..\n");
 	if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) {
 		DEBUG2(printk("scsi%ld: %s: Failed to initialize firmware "
 			      "control block\n", ha->host_no, __func__));
@@ -443,17 +475,17 @@
 	if (fw_ddb_entry == NULL) {
 		DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
 			      ha->host_no, __func__));
-		return NULL;
+		goto exit_get_ddb_entry_no_free;
 	}
 
 	if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
 				    fw_ddb_entry_dma, NULL, NULL,
 				    &device_state, NULL, NULL, NULL) ==
-	    QLA_ERROR) {
+				    QLA_ERROR) {
 		DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "
 			      "fw_ddb_index %d\n", ha->host_no, __func__,
 			      fw_ddb_index));
-		return NULL;
+		goto exit_get_ddb_entry;
 	}
 
 	/* Allocate DDB if not already allocated. */
@@ -471,6 +503,7 @@
 		}
 	}
 
+	/* if not found allocate new ddb */
 	if (!found) {
 		DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating "
 			      "new ddb\n", ha->host_no, __func__,
@@ -479,10 +512,11 @@
 		ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
 	}
 
-	/* if not found allocate new ddb */
+exit_get_ddb_entry:
 	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
 			  fw_ddb_entry_dma);
 
+exit_get_ddb_entry_no_free:
 	return ddb_entry;
 }
 
@@ -510,7 +544,8 @@
 	if (ddb_entry == NULL) {
 		DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no,
 			      __func__));
-		goto exit_update_ddb;
+
+		goto exit_update_ddb_no_free;
 	}
 
 	/* Make sure the dma buffer is valid */
@@ -521,7 +556,7 @@
 		DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
 			      ha->host_no, __func__));
 
-		goto exit_update_ddb;
+		goto exit_update_ddb_no_free;
 	}
 
 	if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
@@ -529,7 +564,7 @@
 				    &ddb_entry->fw_ddb_device_state, &conn_err,
 				    &ddb_entry->tcp_source_port_num,
 				    &ddb_entry->connection_id) ==
-	    QLA_ERROR) {
+				    QLA_ERROR) {
 		DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "
 			      "fw_ddb_index %d\n", ha->host_no, __func__,
 			      fw_ddb_index));
@@ -559,6 +594,9 @@
 	memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsi_name[0],
 	       min(sizeof(ddb_entry->iscsi_name),
 		   sizeof(fw_ddb_entry->iscsi_name)));
+	memcpy(&ddb_entry->iscsi_alias[0], &fw_ddb_entry->iscsi_alias[0],
+	       min(sizeof(ddb_entry->iscsi_alias),
+		   sizeof(fw_ddb_entry->iscsi_alias)));
 	memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0],
 	       min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr)));
 
@@ -580,21 +618,19 @@
 			min(sizeof(ddb_entry->link_local_ipv6_addr),
 			sizeof(fw_ddb_entry->link_local_ipv6_addr)));
 
-		DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d "
-					"State %04x ConnErr %08x IP %pI6 "
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DDB[%d] State %04x"
+					" ConnErr %08x IP %pI6 "
 					":%04d \"%s\"\n",
 					__func__, fw_ddb_index,
-					ddb_entry->os_target_id,
 					ddb_entry->fw_ddb_device_state,
 					conn_err, fw_ddb_entry->ip_addr,
 					le16_to_cpu(fw_ddb_entry->port),
 					fw_ddb_entry->iscsi_name));
 	} else
-		DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d "
-					"State %04x ConnErr %08x IP %pI4 "
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DDB[%d] State %04x"
+					" ConnErr %08x IP %pI4 "
 					":%04d \"%s\"\n",
 					__func__, fw_ddb_index,
-					ddb_entry->os_target_id,
 					ddb_entry->fw_ddb_device_state,
 					conn_err, fw_ddb_entry->ip_addr,
 					le16_to_cpu(fw_ddb_entry->port),
@@ -604,6 +640,7 @@
 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
 				  fw_ddb_entry, fw_ddb_entry_dma);
 
+exit_update_ddb_no_free:
 	return status;
 }
 
@@ -660,18 +697,18 @@
 	err_code = ((conn_err & 0x00ff0000) >> 16);
 	login_rsp_sts_class = ((conn_err & 0x0000ff00) >> 8);
 	if (err_code == 0x1c || err_code == 0x06) {
-		DEBUG2(dev_info(&ha->pdev->dev,
-				": conn_err=0x%08x, send target completed"
-				" or access denied failure\n", conn_err));
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+		    ": conn_err=0x%08x, send target completed"
+		    " or access denied failure\n", conn_err));
 		relogin = 0;
 	}
 	if ((err_code == 0x08) && (login_rsp_sts_class == 0x02)) {
 		/* Login Response PDU returned an error.
 		   Login Response Status in Error Code Detail
 		   indicates login should not be retried.*/
-		DEBUG2(dev_info(&ha->pdev->dev,
-				": conn_err=0x%08x, do not retry relogin\n",
-				conn_err));
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+		    ": conn_err=0x%08x, do not retry relogin\n",
+		    conn_err));
 		relogin = 0;
 	}
 
@@ -688,7 +725,7 @@
  **/
 static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
 {
-	int status = QLA_SUCCESS;
+	int status = QLA_ERROR;
 	uint32_t fw_ddb_index = 0;
 	uint32_t next_fw_ddb_index = 0;
 	uint32_t ddb_state;
@@ -702,12 +739,13 @@
 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
 			&fw_ddb_entry_dma, GFP_KERNEL);
 	if (fw_ddb_entry == NULL) {
-		DEBUG2(dev_info(&ha->pdev->dev, "%s: DMA alloc failed\n",
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DMA alloc failed\n",
 				__func__));
-		return QLA_ERROR;
+
+		goto exit_build_ddb_list_no_free;
 	}
 
-	dev_info(&ha->pdev->dev, "Initializing DDBs ...\n");
+	ql4_printk(KERN_INFO, ha, "Initializing DDBs ...\n");
 	for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES;
 	     fw_ddb_index = next_fw_ddb_index) {
 		/* First, let's see if a device exists here */
@@ -719,7 +757,7 @@
 			DEBUG2(printk("scsi%ld: %s: get_ddb_entry, "
 				      "fw_ddb_index %d failed", ha->host_no,
 				      __func__, fw_ddb_index));
-			return QLA_ERROR;
+			goto exit_build_ddb_list;
 		}
 
 		DEBUG2(printk("scsi%ld: %s: Getting DDB[%d] ddbstate=0x%x, "
@@ -749,7 +787,7 @@
 						"get_ddb_entry %d failed\n",
 						ha->host_no,
 						__func__, fw_ddb_index));
-					return QLA_ERROR;
+					goto exit_build_ddb_list;
 				}
 			}
 		}
@@ -769,7 +807,7 @@
 			DEBUG2(printk("scsi%ld: %s: Unable to allocate memory "
 				      "for device at fw_ddb_index %d\n",
 				      ha->host_no, __func__, fw_ddb_index));
-			return QLA_ERROR;
+			goto exit_build_ddb_list;
 		}
 		/* Fill in the device structure */
 		if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) ==
@@ -777,11 +815,10 @@
 			ha->fw_ddb_index_map[fw_ddb_index] =
 				(struct ddb_entry *)INVALID_ENTRY;
 
-
 			DEBUG2(printk("scsi%ld: %s: update_ddb_entry failed "
 				      "for fw_ddb_index %d.\n",
 				      ha->host_no, __func__, fw_ddb_index));
-			return QLA_ERROR;
+			goto exit_build_ddb_list;
 		}
 
 next_one:
@@ -791,8 +828,14 @@
 			break;
 	}
 
-	dev_info(&ha->pdev->dev, "DDB list done..\n");
+	status = QLA_SUCCESS;
+	ql4_printk(KERN_INFO, ha, "DDB list done..\n");
 
+exit_build_ddb_list:
+	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
+		fw_ddb_entry_dma);
+
+exit_build_ddb_list_no_free:
 	return status;
 }
 
@@ -951,6 +994,9 @@
 
 	qla4xxx_flush_AENS(ha);
 
+	/* Wait for an AEN */
+	qla4xxx_devices_ready(ha);
+
 	/*
 	 * First perform device discovery for active
 	 * fw ddb indexes and build
@@ -959,9 +1005,6 @@
 	if ((status = qla4xxx_build_ddb_list(ha)) == QLA_ERROR)
 		return status;
 
-	/* Wait for an AEN */
-	qla4xxx_devices_ready(ha);
-
 	/*
 	 * Targets can come online after the inital discovery, so processing
 	 * the aens here will catch them.
@@ -973,7 +1016,7 @@
 }
 
 /**
- * qla4xxx_update_ddb_list - update the driver ddb list
+ * qla4xxx_reinitialize_ddb_list - update the driver ddb list
  * @ha: pointer to host adapter structure.
  *
  * This routine obtains device information from the F/W database after
@@ -993,6 +1036,7 @@
 			DEBUG2(printk ("scsi%ld: %s: ddb index [%d] marked "
 				       "ONLINE\n", ha->host_no, __func__,
 				       ddb_entry->fw_ddb_index));
+			iscsi_unblock_session(ddb_entry->sess);
 		} else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
 			qla4xxx_mark_device_missing(ha, ddb_entry);
 	}
@@ -1016,7 +1060,7 @@
 			    (uint16_t)RELOGIN_TOV);
 	atomic_set(&ddb_entry->relogin_timer, relogin_timer);
 
-	DEBUG2(printk("scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no,
+	DEBUG2(printk("scsi%ld: Relogin ddb [%d]. TOV=%d\n", ha->host_no,
 		      ddb_entry->fw_ddb_index, relogin_timer));
 
 	qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, 0);
@@ -1039,17 +1083,17 @@
 	}
 
 	/* Get EEPRom Parameters from NVRAM and validate */
-	dev_info(&ha->pdev->dev, "Configuring NVRAM ...\n");
+	ql4_printk(KERN_INFO, ha, "Configuring NVRAM ...\n");
 	if (qla4xxx_is_nvram_configuration_valid(ha) == QLA_SUCCESS) {
 		spin_lock_irqsave(&ha->hardware_lock, flags);
 		extHwConfig.Asuint32_t =
 			rd_nvram_word(ha, eeprom_ext_hw_conf_offset(ha));
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	} else {
-		dev_warn(&ha->pdev->dev,
-			   "scsi%ld: %s: EEProm checksum invalid.  "
-			   "Please update your EEPROM\n", ha->host_no,
-			   __func__);
+		ql4_printk(KERN_WARNING, ha,
+		    "scsi%ld: %s: EEProm checksum invalid.  "
+		    "Please update your EEPROM\n", ha->host_no,
+		    __func__);
 
 		/* Attempt to set defaults */
 		if (is_qla4010(ha))
@@ -1073,12 +1117,21 @@
 	return QLA_SUCCESS;
 }
 
-static void qla4x00_pci_config(struct scsi_qla_host *ha)
+/**
+ * qla4_8xxx_pci_config() - Setup ISP82xx PCI configuration registers.
+ * @ha: HA context
+ */
+void qla4_8xxx_pci_config(struct scsi_qla_host *ha)
+{
+	pci_set_master(ha->pdev);
+}
+
+void qla4xxx_pci_config(struct scsi_qla_host *ha)
 {
 	uint16_t w;
 	int status;
 
-	dev_info(&ha->pdev->dev, "Configuring PCI space...\n");
+	ql4_printk(KERN_INFO, ha, "Configuring PCI space...\n");
 
 	pci_set_master(ha->pdev);
 	status = pci_set_mwi(ha->pdev);
@@ -1100,7 +1153,7 @@
 	unsigned long flags;
 	uint32_t mbox_status;
 
-	dev_info(&ha->pdev->dev, "Starting firmware ...\n");
+	ql4_printk(KERN_INFO, ha, "Starting firmware ...\n");
 
 	/*
 	 * Start firmware from flash ROM
@@ -1204,7 +1257,7 @@
  * This routine performs the necessary steps to start the firmware for
  * the QLA4010 adapter.
  **/
-static int qla4xxx_start_firmware(struct scsi_qla_host *ha)
+int qla4xxx_start_firmware(struct scsi_qla_host *ha)
 {
 	unsigned long flags = 0;
 	uint32_t mbox_status;
@@ -1283,7 +1336,8 @@
 	if (soft_reset) {
 		DEBUG(printk("scsi%ld: %s: Issue Soft Reset\n", ha->host_no,
 			     __func__));
-		status = qla4xxx_soft_reset(ha);
+		status = qla4xxx_soft_reset(ha);	/* NOTE: acquires drvr
+							 * lock again, but ok */
 		if (status == QLA_ERROR) {
 			DEBUG(printk("scsi%d: %s: Soft Reset failed!\n",
 				     ha->host_no, __func__));
@@ -1304,7 +1358,6 @@
 
 	ql4xxx_unlock_drvr(ha);
 	if (status == QLA_SUCCESS) {
-		qla4xxx_get_fw_version(ha);
 		if (test_and_clear_bit(AF_GET_CRASH_RECORD, &ha->flags))
 			qla4xxx_get_crash_record(ha);
 	} else {
@@ -1331,18 +1384,21 @@
 	int status = QLA_ERROR;
 	int8_t ip_address[IP_ADDR_LEN] = {0} ;
 
-	clear_bit(AF_ONLINE, &ha->flags);
 	ha->eeprom_cmd_data = 0;
 
-	qla4x00_pci_config(ha);
+	ql4_printk(KERN_INFO, ha, "Configuring PCI space...\n");
+	ha->isp_ops->pci_config(ha);
 
-	qla4xxx_disable_intrs(ha);
+	ha->isp_ops->disable_intrs(ha);
 
 	/* Initialize the Host adapter request/response queues and firmware */
-	if (qla4xxx_start_firmware(ha) == QLA_ERROR)
+	if (ha->isp_ops->start_firmware(ha) == QLA_ERROR)
 		goto exit_init_hba;
 
-	if (qla4xxx_validate_mac_address(ha) == QLA_ERROR)
+	if (qla4xxx_get_fw_version(ha) == QLA_ERROR)
+		goto exit_init_hba;
+
+	if (ha->isp_ops->get_sys_info(ha) == QLA_ERROR)
 		goto exit_init_hba;
 
 	if (qla4xxx_init_local_data(ha) == QLA_ERROR)
@@ -1395,6 +1451,8 @@
 exit_init_online:
 	set_bit(AF_ONLINE, &ha->flags);
 exit_init_hba:
+	DEBUG2(printk("scsi%ld: initialize adapter: %s\n", ha->host_no,
+	    status == QLA_ERROR ? "FAILED" : "SUCCEDED"));
 	return status;
 }
 
@@ -1487,7 +1545,10 @@
 		      ddb_entry->fw_ddb_device_state, state, fw_ddb_index));
 	if (old_fw_ddb_device_state == state &&
 	    state == DDB_DS_SESSION_ACTIVE) {
-		/* Do nothing, state not changed. */
+		if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
+			atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
+			iscsi_unblock_session(ddb_entry->sess);
+		}
 		return QLA_SUCCESS;
 	}
 
@@ -1511,7 +1572,7 @@
 	} else {
 		/* Device went away, mark device missing */
 		if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) {
-			DEBUG2(dev_info(&ha->pdev->dev, "%s mark missing "
+			DEBUG2(ql4_printk(KERN_INFO, ha, "%s mark missing "
 					"ddb_entry 0x%p sess 0x%p conn 0x%p\n",
 					__func__, ddb_entry,
 					ddb_entry->sess, ddb_entry->conn));
@@ -1543,9 +1604,20 @@
 			atomic_set(&ddb_entry->relogin_timer, 0);
 			atomic_set(&ddb_entry->retry_relogin_timer,
 				   ddb_entry->default_time2wait + 4);
+			DEBUG(printk("scsi%ld: %s: ddb[%d] "
+			    "initiate relogin after %d seconds\n",
+			    ha->host_no, __func__,
+			    ddb_entry->fw_ddb_index,
+			    ddb_entry->default_time2wait + 4));
+		} else {
+			DEBUG(printk("scsi%ld: %s: ddb[%d] "
+			    "relogin not initiated, state = %d, "
+			    "ddb_entry->flags = 0x%lx\n",
+			    ha->host_no, __func__,
+			    ddb_entry->fw_ddb_index,
+			    ddb_entry->fw_ddb_device_state,
+			    ddb_entry->flags));
 		}
 	}
-
 	return QLA_SUCCESS;
 }
-
diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h
index 6375eb0..9471ac7 100644
--- a/drivers/scsi/qla4xxx/ql4_inline.h
+++ b/drivers/scsi/qla4xxx/ql4_inline.h
@@ -29,7 +29,7 @@
 		ddb_entry = ha->fw_ddb_index_map[fw_ddb_index];
 	}
 
-	DEBUG3(printk("scsi%d: %s: index [%d], ddb_entry = %p\n",
+	DEBUG3(printk("scsi%d: %s: ddb [%d], ddb_entry = %p\n",
 	    ha->host_no, __func__, fw_ddb_index, ddb_entry));
 
 	return ddb_entry;
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index e66f3f2..f89973d 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -108,8 +108,7 @@
 	wmb();
 
 	/* Tell ISP it's got a new I/O request */
-	writel(ha->request_in, &ha->reg->req_q_in);
-	readl(&ha->reg->req_q_in);
+	ha->isp_ops->queue_iocb(ha);
 
 exit_send_marker:
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -194,6 +193,72 @@
 }
 
 /**
+ * qla4_8xxx_queue_iocb - Tell ISP it's got new request(s)
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine notifies the ISP that one or more new request
+ * queue entries have been placed on the request queue.
+ **/
+void qla4_8xxx_queue_iocb(struct scsi_qla_host *ha)
+{
+	uint32_t dbval = 0;
+	unsigned long wtime;
+
+	dbval = 0x14 | (ha->func_num << 5);
+	dbval = dbval | (0 << 8) | (ha->request_in << 16);
+	writel(dbval, (unsigned long __iomem *)ha->nx_db_wr_ptr);
+	wmb();
+
+	wtime = jiffies + (2 * HZ);
+	while (readl((void __iomem *)ha->nx_db_rd_ptr) != dbval &&
+	    !time_after_eq(jiffies, wtime)) {
+		writel(dbval, (unsigned long __iomem *)ha->nx_db_wr_ptr);
+		wmb();
+	}
+}
+
+/**
+ * qla4_8xxx_complete_iocb - Tell ISP we're done with response(s)
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine notifies the ISP that one or more response/completion
+ * queue entries have been processed by the driver.
+ * This also clears the interrupt.
+ **/
+void qla4_8xxx_complete_iocb(struct scsi_qla_host *ha)
+{
+	writel(ha->response_out, &ha->qla4_8xxx_reg->rsp_q_out);
+	readl(&ha->qla4_8xxx_reg->rsp_q_out);
+}
+
+/**
+ * qla4xxx_queue_iocb - Tell ISP it's got new request(s)
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine is notifies the ISP that one or more new request
+ * queue entries have been placed on the request queue.
+ **/
+void qla4xxx_queue_iocb(struct scsi_qla_host *ha)
+{
+	writel(ha->request_in, &ha->reg->req_q_in);
+	readl(&ha->reg->req_q_in);
+}
+
+/**
+ * qla4xxx_complete_iocb - Tell ISP we're done with response(s)
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine is notifies the ISP that one or more response/completion
+ * queue entries have been processed by the driver.
+ * This also clears the interrupt.
+ **/
+void qla4xxx_complete_iocb(struct scsi_qla_host *ha)
+{
+	writel(ha->response_out, &ha->reg->rsp_q_out);
+	readl(&ha->reg->rsp_q_out);
+}
+
+/**
  * qla4xxx_send_command_to_isp - issues command to HBA
  * @ha: pointer to host adapter structure.
  * @srb: pointer to SCSI Request Block to be sent to ISP
@@ -310,9 +375,7 @@
 	srb->iocb_cnt = req_cnt;
 	ha->req_q_count -= req_cnt;
 
-	/* Debug print statements */
-	writel(ha->request_in, &ha->reg->req_q_in);
-	readl(&ha->reg->req_q_in);
+	ha->isp_ops->queue_iocb(ha);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	return QLA_SUCCESS;
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 596c303..aa65697 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -118,13 +118,12 @@
 
 	srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle));
 	if (!srb) {
-		/* FIXMEdg: Don't we need to reset ISP in this case??? */
 		DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Status Entry invalid "
 			      "handle 0x%x, sp=%p. This cmd may have already "
 			      "been completed.\n", ha->host_no, __func__,
 			      le32_to_cpu(sts_entry->handle), srb));
-		dev_warn(&ha->pdev->dev, "%s invalid status entry:"
-			" handle=0x%0x\n", __func__, sts_entry->handle);
+		ql4_printk(KERN_WARNING, ha, "%s invalid status entry:"
+		    " handle=0x%0x\n", __func__, sts_entry->handle);
 		set_bit(DPC_RESET_HA, &ha->dpc_flags);
 		return;
 	}
@@ -135,8 +134,8 @@
 			      "OS pkt->handle=%d srb=%p srb->state:%d\n",
 			      ha->host_no, __func__, sts_entry->handle,
 			      srb, srb->state));
-		dev_warn(&ha->pdev->dev, "Command is NULL:"
-			" already returned to OS (srb=%p)\n", srb);
+		ql4_printk(KERN_WARNING, ha, "Command is NULL:"
+		    " already returned to OS (srb=%p)\n", srb);
 		return;
 	}
 
@@ -293,6 +292,10 @@
 
 	case SCS_DEVICE_LOGGED_OUT:
 	case SCS_DEVICE_UNAVAILABLE:
+		DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: SCS_DEVICE "
+		    "state: 0x%x\n", ha->host_no,
+		    cmd->device->channel, cmd->device->id,
+		    cmd->device->lun, sts_entry->completionStatus));
 		/*
 		 * Mark device missing so that we won't continue to
 		 * send I/O to this device.  We should get a ddb
@@ -339,16 +342,14 @@
  * This routine process response queue completions in interrupt context.
  * Hardware_lock locked upon entry
  **/
-static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
+void qla4xxx_process_response_queue(struct scsi_qla_host *ha)
 {
 	uint32_t count = 0;
 	struct srb *srb = NULL;
 	struct status_entry *sts_entry;
 
 	/* Process all responses from response queue */
-	while ((ha->response_in =
-		(uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in)) !=
-	       ha->response_out) {
+	while ((ha->response_ptr->signature != RESPONSE_PROCESSED)) {
 		sts_entry = (struct status_entry *) ha->response_ptr;
 		count++;
 
@@ -413,14 +414,14 @@
 				      sts_entry->hdr.entryType));
 			goto exit_prq_error;
 		}
+		((struct response *)sts_entry)->signature = RESPONSE_PROCESSED;
+		wmb();
 	}
 
 	/*
-	 * Done with responses, update the ISP For QLA4010, this also clears
-	 * the interrupt.
+	 * Tell ISP we're done with response(s). This also clears the interrupt.
 	 */
-	writel(ha->response_out, &ha->reg->rsp_q_out);
-	readl(&ha->reg->rsp_q_out);
+	ha->isp_ops->complete_iocb(ha);
 
 	return;
 
@@ -430,9 +431,7 @@
 		      sts_entry->completionStatus));
 
 exit_prq_error:
-	writel(ha->response_out, &ha->reg->rsp_q_out);
-	readl(&ha->reg->rsp_q_out);
-
+	ha->isp_ops->complete_iocb(ha);
 	set_bit(DPC_RESET_HA, &ha->dpc_flags);
 }
 
@@ -448,7 +447,7 @@
 				       uint32_t mbox_status)
 {
 	int i;
-	uint32_t mbox_stat2, mbox_stat3;
+	uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
 
 	if ((mbox_status == MBOX_STS_BUSY) ||
 	    (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) ||
@@ -460,27 +459,37 @@
 			 * Copy all mailbox registers to a temporary
 			 * location and set mailbox command done flag
 			 */
-			for (i = 1; i < ha->mbox_status_count; i++)
-				ha->mbox_status[i] =
-					readl(&ha->reg->mailbox[i]);
+			for (i = 0; i < ha->mbox_status_count; i++)
+				ha->mbox_status[i] = is_qla8022(ha)
+				    ? readl(&ha->qla4_8xxx_reg->mailbox_out[i])
+				    : readl(&ha->reg->mailbox[i]);
 
 			set_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+
+			if (test_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags))
+				complete(&ha->mbx_intr_comp);
 		}
 	} else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) {
+		for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
+			mbox_sts[i] = is_qla8022(ha)
+			    ? readl(&ha->qla4_8xxx_reg->mailbox_out[i])
+			    : readl(&ha->reg->mailbox[i]);
+
 		/* Immediately process the AENs that don't require much work.
 		 * Only queue the database_changed AENs */
 		if (ha->aen_log.count < MAX_AEN_ENTRIES) {
 			for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
 				ha->aen_log.entry[ha->aen_log.count].mbox_sts[i] =
-					readl(&ha->reg->mailbox[i]);
+				    mbox_sts[i];
 			ha->aen_log.count++;
 		}
 		switch (mbox_status) {
 		case MBOX_ASTS_SYSTEM_ERROR:
 			/* Log Mailbox registers */
+			ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__);
 			if (ql4xdontresethba) {
-				DEBUG2(printk("%s:Dont Reset HBA\n",
-					      __func__));
+				DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n",
+				    ha->host_no, __func__));
 			} else {
 				set_bit(AF_GET_CRASH_RECORD, &ha->flags);
 				set_bit(DPC_RESET_HA, &ha->dpc_flags);
@@ -502,18 +511,15 @@
 			if (test_bit(AF_INIT_DONE, &ha->flags))
 				set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);
 
-			DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x Adapter"
-					" LINK UP\n", ha->host_no,
-					mbox_status));
+			ql4_printk(KERN_INFO, ha, "%s: LINK UP\n", __func__);
 			break;
 
 		case MBOX_ASTS_LINK_DOWN:
 			clear_bit(AF_LINK_UP, &ha->flags);
-			set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);
+			if (test_bit(AF_INIT_DONE, &ha->flags))
+				set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);
 
-			DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x Adapter"
-					" LINK DOWN\n", ha->host_no,
-					mbox_status));
+			ql4_printk(KERN_INFO, ha, "%s: LINK DOWN\n", __func__);
 			break;
 
 		case MBOX_ASTS_HEARTBEAT:
@@ -539,12 +545,17 @@
 			break;
 
 		case MBOX_ASTS_IP_ADDR_STATE_CHANGED:
-			mbox_stat2 = readl(&ha->reg->mailbox[2]);
-			mbox_stat3 = readl(&ha->reg->mailbox[3]);
+			printk("scsi%ld: AEN %04x, mbox_sts[2]=%04x, "
+			    "mbox_sts[3]=%04x\n", ha->host_no, mbox_sts[0],
+			    mbox_sts[2], mbox_sts[3]);
 
-			if ((mbox_stat3 == 5) && (mbox_stat2 == 3))
+			/* mbox_sts[2] = Old ACB state
+			 * mbox_sts[3] = new ACB state */
+			if ((mbox_sts[3] == ACB_STATE_VALID) &&
+			    (mbox_sts[2] == ACB_STATE_TENTATIVE))
 				set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
-			else if ((mbox_stat3 == 2) && (mbox_stat2 == 5))
+			else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) &&
+			    (mbox_sts[2] == ACB_STATE_VALID))
 				set_bit(DPC_RESET_HA, &ha->dpc_flags);
 			break;
 
@@ -553,9 +564,8 @@
 			/* No action */
 			DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x, "
 				      "mbox_sts[1]=%04x, mbox_sts[2]=%04x\n",
-				      ha->host_no, mbox_status,
-				      readl(&ha->reg->mailbox[1]),
-				      readl(&ha->reg->mailbox[2])));
+				      ha->host_no, mbox_sts[0],
+				      mbox_sts[1], mbox_sts[2]));
 			break;
 
 		case MBOX_ASTS_SELF_TEST_FAILED:
@@ -563,10 +573,8 @@
 			/* No action */
 			DEBUG2(printk("scsi%ld: AEN %04x, mbox_sts[1]=%04x, "
 				      "mbox_sts[2]=%04x, mbox_sts[3]=%04x\n",
-				      ha->host_no, mbox_status,
-				      readl(&ha->reg->mailbox[1]),
-				      readl(&ha->reg->mailbox[2]),
-				      readl(&ha->reg->mailbox[3])));
+				      ha->host_no, mbox_sts[0], mbox_sts[1],
+				      mbox_sts[2], mbox_sts[3]));
 			break;
 
 		case MBOX_ASTS_DATABASE_CHANGED:
@@ -577,21 +585,17 @@
 				/* decrement available counter */
 				ha->aen_q_count--;
 
-				for (i = 1; i < MBOX_AEN_REG_COUNT; i++)
+				for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
 					ha->aen_q[ha->aen_in].mbox_sts[i] =
-						readl(&ha->reg->mailbox[i]);
-
-				ha->aen_q[ha->aen_in].mbox_sts[0] = mbox_status;
+					    mbox_sts[i];
 
 				/* print debug message */
 				DEBUG2(printk("scsi%ld: AEN[%d] %04x queued"
-					      " mb1:0x%x mb2:0x%x mb3:0x%x mb4:0x%x\n",
-					      ha->host_no, ha->aen_in,
-					      mbox_status,
-					      ha->aen_q[ha->aen_in].mbox_sts[1],
-					      ha->aen_q[ha->aen_in].mbox_sts[2],
-					      ha->aen_q[ha->aen_in].mbox_sts[3],
-					      ha->aen_q[ha->aen_in].  mbox_sts[4]));
+				    " mb1:0x%x mb2:0x%x mb3:0x%x mb4:0x%x\n",
+				    ha->host_no, ha->aen_in, mbox_sts[0],
+				    mbox_sts[1], mbox_sts[2],  mbox_sts[3],
+				    mbox_sts[4]));
+
 				/* advance pointer */
 				ha->aen_in++;
 				if (ha->aen_in == MAX_AEN_ENTRIES)
@@ -603,18 +607,16 @@
 				DEBUG2(printk("scsi%ld: %s: aen %04x, queue "
 					      "overflowed!  AEN LOST!!\n",
 					      ha->host_no, __func__,
-					      mbox_status));
+					      mbox_sts[0]));
 
 				DEBUG2(printk("scsi%ld: DUMP AEN QUEUE\n",
 					      ha->host_no));
 
 				for (i = 0; i < MAX_AEN_ENTRIES; i++) {
 					DEBUG2(printk("AEN[%d] %04x %04x %04x "
-						      "%04x\n", i,
-						      ha->aen_q[i].mbox_sts[0],
-						      ha->aen_q[i].mbox_sts[1],
-						      ha->aen_q[i].mbox_sts[2],
-						      ha->aen_q[i].mbox_sts[3]));
+						      "%04x\n", i, mbox_sts[0],
+						      mbox_sts[1], mbox_sts[2],
+						      mbox_sts[3]));
 				}
 			}
 			break;
@@ -622,7 +624,7 @@
 		default:
 			DEBUG2(printk(KERN_WARNING
 				      "scsi%ld: AEN %04x UNKNOWN\n",
-				      ha->host_no, mbox_status));
+				      ha->host_no, mbox_sts[0]));
 			break;
 		}
 	} else {
@@ -634,6 +636,30 @@
 }
 
 /**
+ * qla4_8xxx_interrupt_service_routine - isr
+ * @ha: pointer to host adapter structure.
+ *
+ * This is the main interrupt service routine.
+ * hardware_lock locked upon entry. runs in interrupt context.
+ **/
+void qla4_8xxx_interrupt_service_routine(struct scsi_qla_host *ha,
+    uint32_t intr_status)
+{
+	/* Process response queue interrupt. */
+	if (intr_status & HSRX_RISC_IOCB_INT)
+		qla4xxx_process_response_queue(ha);
+
+	/* Process mailbox/asynch event interrupt.*/
+	if (intr_status & HSRX_RISC_MB_INT)
+		qla4xxx_isr_decode_mailbox(ha,
+		    readl(&ha->qla4_8xxx_reg->mailbox_out[0]));
+
+	/* clear the interrupt */
+	writel(0, &ha->qla4_8xxx_reg->host_int);
+	readl(&ha->qla4_8xxx_reg->host_int);
+}
+
+/**
  * qla4xxx_interrupt_service_routine - isr
  * @ha: pointer to host adapter structure.
  *
@@ -660,6 +686,28 @@
 }
 
 /**
+ * qla4_8xxx_spurious_interrupt - processes spurious interrupt
+ * @ha: pointer to host adapter structure.
+ * @reqs_count: .
+ *
+ **/
+static void qla4_8xxx_spurious_interrupt(struct scsi_qla_host *ha,
+    uint8_t reqs_count)
+{
+	if (reqs_count)
+		return;
+
+	DEBUG2(ql4_printk(KERN_INFO, ha, "Spurious Interrupt\n"));
+	if (is_qla8022(ha)) {
+		writel(0, &ha->qla4_8xxx_reg->host_int);
+		if (test_bit(AF_INTx_ENABLED, &ha->flags))
+			qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg,
+			    0xfbff);
+	}
+	ha->spurious_int_count++;
+}
+
+/**
  * qla4xxx_intr_handler - hardware interrupt handler.
  * @irq: Unused
  * @dev_id: Pointer to host adapter structure
@@ -689,15 +737,14 @@
 		/*
 		 * Read interrupt status
 		 */
-		if (le32_to_cpu(ha->shadow_regs->rsp_q_in) !=
+		if (ha->isp_ops->rd_shdw_rsp_q_in(ha) !=
 		    ha->response_out)
 			intr_status = CSR_SCSI_COMPLETION_INTR;
 		else
 			intr_status = readl(&ha->reg->ctrl_status);
 
 		if ((intr_status &
-		     (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) ==
-		    0) {
+		    (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) == 0) {
 			if (reqs_count == 0)
 				ha->spurious_int_count++;
 			break;
@@ -739,17 +786,15 @@
 			       &ha->reg->ctrl_status);
 			readl(&ha->reg->ctrl_status);
 
-			if (!ql4_mod_unload)
+			if (!test_bit(AF_HBA_GOING_AWAY, &ha->flags))
 				set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
 
 			break;
 		} else if (intr_status & INTR_PENDING) {
-			qla4xxx_interrupt_service_routine(ha, intr_status);
+			ha->isp_ops->interrupt_service_routine(ha, intr_status);
 			ha->total_io_count++;
 			if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)
 				break;
-
-			intr_status = 0;
 		}
 	}
 
@@ -759,6 +804,145 @@
 }
 
 /**
+ * qla4_8xxx_intr_handler - hardware interrupt handler.
+ * @irq: Unused
+ * @dev_id: Pointer to host adapter structure
+ **/
+irqreturn_t qla4_8xxx_intr_handler(int irq, void *dev_id)
+{
+	struct scsi_qla_host *ha = dev_id;
+	uint32_t intr_status;
+	uint32_t status;
+	unsigned long flags = 0;
+	uint8_t reqs_count = 0;
+
+	ha->isr_count++;
+	status = qla4_8xxx_rd_32(ha, ISR_INT_VECTOR);
+	if (!(status & ha->nx_legacy_intr.int_vec_bit))
+		return IRQ_NONE;
+
+	status = qla4_8xxx_rd_32(ha, ISR_INT_STATE_REG);
+	if (!ISR_IS_LEGACY_INTR_TRIGGERED(status)) {
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+		    "%s legacy Int not triggered\n", __func__));
+		return IRQ_NONE;
+	}
+
+	/* clear the interrupt */
+	qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff);
+
+	/* read twice to ensure write is flushed */
+	qla4_8xxx_rd_32(ha, ISR_INT_VECTOR);
+	qla4_8xxx_rd_32(ha, ISR_INT_VECTOR);
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	while (1) {
+		if (!(readl(&ha->qla4_8xxx_reg->host_int) &
+		    ISRX_82XX_RISC_INT)) {
+			qla4_8xxx_spurious_interrupt(ha, reqs_count);
+			break;
+		}
+		intr_status =  readl(&ha->qla4_8xxx_reg->host_status);
+		if ((intr_status &
+		    (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0)  {
+			qla4_8xxx_spurious_interrupt(ha, reqs_count);
+			break;
+		}
+
+		ha->isp_ops->interrupt_service_routine(ha, intr_status);
+
+		/* Enable Interrupt */
+		qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
+
+		if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)
+			break;
+	}
+
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t
+qla4_8xxx_msi_handler(int irq, void *dev_id)
+{
+	struct scsi_qla_host *ha;
+
+	ha = (struct scsi_qla_host *) dev_id;
+	if (!ha) {
+		DEBUG2(printk(KERN_INFO
+		    "qla4xxx: MSIX: Interrupt with NULL host ptr\n"));
+		return IRQ_NONE;
+	}
+
+	ha->isr_count++;
+	/* clear the interrupt */
+	qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff);
+
+	/* read twice to ensure write is flushed */
+	qla4_8xxx_rd_32(ha, ISR_INT_VECTOR);
+	qla4_8xxx_rd_32(ha, ISR_INT_VECTOR);
+
+	return qla4_8xxx_default_intr_handler(irq, dev_id);
+}
+
+/**
+ * qla4_8xxx_default_intr_handler - hardware interrupt handler.
+ * @irq: Unused
+ * @dev_id: Pointer to host adapter structure
+ *
+ * This interrupt handler is called directly for MSI-X, and
+ * called indirectly for MSI.
+ **/
+irqreturn_t
+qla4_8xxx_default_intr_handler(int irq, void *dev_id)
+{
+	struct scsi_qla_host *ha = dev_id;
+	unsigned long   flags;
+	uint32_t intr_status;
+	uint8_t reqs_count = 0;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	while (1) {
+		if (!(readl(&ha->qla4_8xxx_reg->host_int) &
+		    ISRX_82XX_RISC_INT)) {
+			qla4_8xxx_spurious_interrupt(ha, reqs_count);
+			break;
+		}
+
+		intr_status =  readl(&ha->qla4_8xxx_reg->host_status);
+		if ((intr_status &
+		    (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) {
+			qla4_8xxx_spurious_interrupt(ha, reqs_count);
+			break;
+		}
+
+		ha->isp_ops->interrupt_service_routine(ha, intr_status);
+
+		if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)
+			break;
+	}
+
+	ha->isr_count++;
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t
+qla4_8xxx_msix_rsp_q(int irq, void *dev_id)
+{
+	struct scsi_qla_host *ha = dev_id;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	qla4xxx_process_response_queue(ha);
+	writel(0, &ha->qla4_8xxx_reg->host_int);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	ha->isr_count++;
+	return IRQ_HANDLED;
+}
+
+/**
  * qla4xxx_process_aen - processes AENs generated by firmware
  * @ha: pointer to host adapter structure.
  * @process_aen: type of AENs to process
@@ -825,7 +1009,7 @@
 					((ddb_entry->default_time2wait +
 					  4) * HZ);
 
-				DEBUG2(printk("scsi%ld: ddb index [%d] initate"
+				DEBUG2(printk("scsi%ld: ddb [%d] initate"
 					      " RELOGIN after %d seconds\n",
 					      ha->host_no,
 					      ddb_entry->fw_ddb_index,
@@ -847,3 +1031,81 @@
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
+int qla4xxx_request_irqs(struct scsi_qla_host *ha)
+{
+	int ret;
+
+	if (!is_qla8022(ha))
+		goto try_intx;
+
+	if (ql4xenablemsix == 2)
+		goto try_msi;
+
+	if (ql4xenablemsix == 0 || ql4xenablemsix != 1)
+		goto try_intx;
+
+	/* Trying MSI-X */
+	ret = qla4_8xxx_enable_msix(ha);
+	if (!ret) {
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+		    "MSI-X: Enabled (0x%X).\n", ha->revision_id));
+		goto irq_attached;
+	}
+
+	ql4_printk(KERN_WARNING, ha,
+	    "MSI-X: Falling back-to MSI mode -- %d.\n", ret);
+
+try_msi:
+	/* Trying MSI */
+	ret = pci_enable_msi(ha->pdev);
+	if (!ret) {
+		ret = request_irq(ha->pdev->irq, qla4_8xxx_msi_handler,
+			IRQF_DISABLED|IRQF_SHARED, DRIVER_NAME, ha);
+		if (!ret) {
+			DEBUG2(ql4_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
+			set_bit(AF_MSI_ENABLED, &ha->flags);
+			goto irq_attached;
+		} else {
+			ql4_printk(KERN_WARNING, ha,
+			    "MSI: Failed to reserve interrupt %d "
+			    "already in use.\n", ha->pdev->irq);
+			pci_disable_msi(ha->pdev);
+		}
+	}
+	ql4_printk(KERN_WARNING, ha,
+	    "MSI: Falling back-to INTx mode -- %d.\n", ret);
+
+try_intx:
+	/* Trying INTx */
+	ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
+	    IRQF_DISABLED|IRQF_SHARED, DRIVER_NAME, ha);
+	if (!ret) {
+		DEBUG2(ql4_printk(KERN_INFO, ha, "INTx: Enabled.\n"));
+		set_bit(AF_INTx_ENABLED, &ha->flags);
+		goto irq_attached;
+
+	} else {
+		ql4_printk(KERN_WARNING, ha,
+		    "INTx: Failed to reserve interrupt %d already in"
+		    " use.\n", ha->pdev->irq);
+		return ret;
+	}
+
+irq_attached:
+	set_bit(AF_IRQ_ATTACHED, &ha->flags);
+	ha->host->irq = ha->pdev->irq;
+	ql4_printk(KERN_INFO, ha, "%s: irq %d attached\n",
+	    __func__, ha->pdev->irq);
+	return ret;
+}
+
+void qla4xxx_free_irqs(struct scsi_qla_host *ha)
+{
+	if (test_bit(AF_MSIX_ENABLED, &ha->flags))
+		qla4_8xxx_disable_msix(ha);
+	else if (test_and_clear_bit(AF_MSI_ENABLED, &ha->flags)) {
+		free_irq(ha->pdev->irq, ha);
+		pci_disable_msi(ha->pdev);
+	} else if (test_and_clear_bit(AF_INTx_ENABLED, &ha->flags))
+		free_irq(ha->pdev->irq, ha);
+}
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 75496fb..940ee56 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -19,13 +19,13 @@
  * @mbx_cmd: data pointer for mailbox in registers.
  * @mbx_sts: data pointer for mailbox out registers.
  *
- * This routine sssue mailbox commands and waits for completion.
+ * This routine isssue mailbox commands and waits for completion.
  * If outCount is 0, this routine completes successfully WITHOUT waiting
  * for the mailbox command to complete.
  **/
-static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
-				   uint8_t outCount, uint32_t *mbx_cmd,
-				   uint32_t *mbx_sts)
+int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+			    uint8_t outCount, uint32_t *mbx_cmd,
+			    uint32_t *mbx_sts)
 {
 	int status = QLA_ERROR;
 	uint8_t i;
@@ -59,32 +59,66 @@
 	}
 
 	/* To prevent overwriting mailbox registers for a command that has
-	 * not yet been serviced, check to see if a previously issued
-	 * mailbox command is interrupting.
+	 * not yet been serviced, check to see if an active command
+	 * (AEN, IOCB, etc.) is interrupting, then service it.
 	 * -----------------------------------------------------------------
 	 */
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	intr_status = readl(&ha->reg->ctrl_status);
-	if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
-		/* Service existing interrupt */
-		qla4xxx_interrupt_service_routine(ha, intr_status);
-		clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+
+	if (is_qla8022(ha)) {
+		intr_status = readl(&ha->qla4_8xxx_reg->host_int);
+		if (intr_status & ISRX_82XX_RISC_INT) {
+			/* Service existing interrupt */
+			DEBUG2(printk("scsi%ld: %s: "
+			    "servicing existing interrupt\n",
+			    ha->host_no, __func__));
+			intr_status = readl(&ha->qla4_8xxx_reg->host_status);
+			ha->isp_ops->interrupt_service_routine(ha, intr_status);
+			clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+			if (test_bit(AF_INTERRUPTS_ON, &ha->flags) &&
+			    test_bit(AF_INTx_ENABLED, &ha->flags))
+				qla4_8xxx_wr_32(ha,
+				    ha->nx_legacy_intr.tgt_mask_reg,
+				    0xfbff);
+		}
+	} else {
+		intr_status = readl(&ha->reg->ctrl_status);
+		if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
+			/* Service existing interrupt */
+			ha->isp_ops->interrupt_service_routine(ha, intr_status);
+			clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+		}
 	}
 
-	/* Send the mailbox command to the firmware */
 	ha->mbox_status_count = outCount;
 	for (i = 0; i < outCount; i++)
 		ha->mbox_status[i] = 0;
 
-	/* Load all mailbox registers, except mailbox 0. */
-	for (i = 1; i < inCount; i++)
-		writel(mbx_cmd[i], &ha->reg->mailbox[i]);
+	if (is_qla8022(ha)) {
+		/* Load all mailbox registers, except mailbox 0. */
+		DEBUG5(
+		    printk("scsi%ld: %s: Cmd ", ha->host_no, __func__);
+		    for (i = 0; i < inCount; i++)
+			printk("mb%d=%04x ", i, mbx_cmd[i]);
+		    printk("\n"));
 
-	/* Wakeup firmware  */
-	writel(mbx_cmd[0], &ha->reg->mailbox[0]);
-	readl(&ha->reg->mailbox[0]);
-	writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status);
-	readl(&ha->reg->ctrl_status);
+		for (i = 1; i < inCount; i++)
+			writel(mbx_cmd[i], &ha->qla4_8xxx_reg->mailbox_in[i]);
+		writel(mbx_cmd[0], &ha->qla4_8xxx_reg->mailbox_in[0]);
+		readl(&ha->qla4_8xxx_reg->mailbox_in[0]);
+		writel(HINT_MBX_INT_PENDING, &ha->qla4_8xxx_reg->hint);
+	} else {
+		/* Load all mailbox registers, except mailbox 0. */
+		for (i = 1; i < inCount; i++)
+			writel(mbx_cmd[i], &ha->reg->mailbox[i]);
+
+		/* Wakeup firmware  */
+		writel(mbx_cmd[0], &ha->reg->mailbox[0]);
+		readl(&ha->reg->mailbox[0]);
+		writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status);
+		readl(&ha->reg->ctrl_status);
+	}
+
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	/* Wait for completion */
@@ -98,26 +132,66 @@
 		status = QLA_SUCCESS;
 		goto mbox_exit;
 	}
-	/* Wait for command to complete */
-	wait_count = jiffies + MBOX_TOV * HZ;
-	while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
-		if (time_after_eq(jiffies, wait_count))
-			break;
 
-		spin_lock_irqsave(&ha->hardware_lock, flags);
-		intr_status = readl(&ha->reg->ctrl_status);
-		if (intr_status & INTR_PENDING) {
+	/*
+	 * Wait for completion: Poll or completion queue
+	 */
+	if (test_bit(AF_IRQ_ATTACHED, &ha->flags) &&
+	    test_bit(AF_INTERRUPTS_ON, &ha->flags) &&
+	    test_bit(AF_ONLINE, &ha->flags) &&
+	    !test_bit(AF_HBA_GOING_AWAY, &ha->flags)) {
+		/* Do not poll for completion. Use completion queue */
+		set_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags);
+		wait_for_completion_timeout(&ha->mbx_intr_comp, MBOX_TOV * HZ);
+		clear_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags);
+	} else {
+		/* Poll for command to complete */
+		wait_count = jiffies + MBOX_TOV * HZ;
+		while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
+			if (time_after_eq(jiffies, wait_count))
+				break;
 			/*
 			 * Service the interrupt.
 			 * The ISR will save the mailbox status registers
 			 * to a temporary storage location in the adapter
 			 * structure.
 			 */
-			ha->mbox_status_count = outCount;
-			qla4xxx_interrupt_service_routine(ha, intr_status);
+
+			spin_lock_irqsave(&ha->hardware_lock, flags);
+			if (is_qla8022(ha)) {
+				intr_status =
+				    readl(&ha->qla4_8xxx_reg->host_int);
+				if (intr_status & ISRX_82XX_RISC_INT) {
+					ha->mbox_status_count = outCount;
+					intr_status =
+					 readl(&ha->qla4_8xxx_reg->host_status);
+					ha->isp_ops->interrupt_service_routine(
+					    ha, intr_status);
+					if (test_bit(AF_INTERRUPTS_ON,
+					    &ha->flags) &&
+					    test_bit(AF_INTx_ENABLED,
+					    &ha->flags))
+						qla4_8xxx_wr_32(ha,
+						ha->nx_legacy_intr.tgt_mask_reg,
+						0xfbff);
+				}
+			} else {
+				intr_status = readl(&ha->reg->ctrl_status);
+				if (intr_status & INTR_PENDING) {
+					/*
+					 * Service the interrupt.
+					 * The ISR will save the mailbox status
+					 * registers to a temporary storage
+					 * location in the adapter structure.
+					 */
+					ha->mbox_status_count = outCount;
+					ha->isp_ops->interrupt_service_routine(
+					    ha, intr_status);
+				}
+			}
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
+			msleep(10);
 		}
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
-		msleep(10);
 	}
 
 	/* Check for mailbox timeout. */
@@ -172,7 +246,7 @@
 	return status;
 }
 
-uint8_t
+static uint8_t
 qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
 		 uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma)
 {
@@ -196,7 +270,7 @@
 	return QLA_SUCCESS;
 }
 
-uint8_t
+static uint8_t
 qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
 		 uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma)
 {
@@ -218,7 +292,7 @@
 	return QLA_SUCCESS;
 }
 
-void
+static void
 qla4xxx_update_local_ip(struct scsi_qla_host *ha,
 			 struct addr_ctrl_blk  *init_fw_cb)
 {
@@ -256,7 +330,7 @@
 	}
 }
 
-uint8_t
+static uint8_t
 qla4xxx_update_local_ifcb(struct scsi_qla_host *ha,
 			  uint32_t *mbox_cmd,
 			  uint32_t *mbox_sts,
@@ -317,7 +391,7 @@
 	if (init_fw_cb == NULL) {
 		DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n",
 			      ha->host_no, __func__));
-		return 10;
+		goto exit_init_fw_cb_no_free;
 	}
 	memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk));
 
@@ -373,7 +447,7 @@
 exit_init_fw_cb:
 	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk),
 				init_fw_cb, init_fw_cb_dma);
-
+exit_init_fw_cb_no_free:
 	return status;
 }
 
@@ -394,7 +468,7 @@
 	if (init_fw_cb == NULL) {
 		printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no,
 		       __func__);
-		return 10;
+		return QLA_ERROR;
 	}
 
 	/* Get Initialize Firmware Control Block. */
@@ -445,7 +519,7 @@
 	DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n",
 		      ha->host_no, __func__, ha->firmware_state);)
 
-		return QLA_SUCCESS;
+	return QLA_SUCCESS;
 }
 
 /**
@@ -470,6 +544,10 @@
 			      mbox_sts[0]));
 		return QLA_ERROR;
 	}
+
+	ql4_printk(KERN_INFO, ha, "%ld firmare IOCBs available (%d).\n",
+	    ha->host_no, mbox_cmd[2]);
+
 	return QLA_SUCCESS;
 }
 
@@ -500,7 +578,7 @@
 
 	/* Make sure the device index is valid */
 	if (fw_ddb_index >= MAX_DDB_ENTRIES) {
-		DEBUG2(printk("scsi%ld: %s: index [%d] out of range.\n",
+		DEBUG2(printk("scsi%ld: %s: ddb [%d] out of range.\n",
 			      ha->host_no, __func__, fw_ddb_index));
 		goto exit_get_fwddb;
 	}
@@ -521,7 +599,7 @@
 		goto exit_get_fwddb;
 	}
 	if (fw_ddb_index != mbox_sts[1]) {
-		DEBUG2(printk("scsi%ld: %s: index mismatch [%d] != [%d].\n",
+		DEBUG2(printk("scsi%ld: %s: ddb mismatch [%d] != [%d].\n",
 			      ha->host_no, __func__, fw_ddb_index,
 			      mbox_sts[1]));
 		goto exit_get_fwddb;
@@ -529,7 +607,7 @@
 	if (fw_ddb_entry) {
 		options = le16_to_cpu(fw_ddb_entry->options);
 		if (options & DDB_OPT_IPV6_DEVICE) {
-			dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d "
+			ql4_printk(KERN_INFO, ha, "%s: DDB[%d] MB0 %04x Tot %d "
 				"Next %d State %04x ConnErr %08x %pI6 "
 				":%04d \"%s\"\n", __func__, fw_ddb_index,
 				mbox_sts[0], mbox_sts[2], mbox_sts[3],
@@ -538,7 +616,7 @@
 				le16_to_cpu(fw_ddb_entry->port),
 				fw_ddb_entry->iscsi_name);
 		} else {
-			dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d "
+			ql4_printk(KERN_INFO, ha, "%s: DDB[%d] MB0 %04x Tot %d "
 				"Next %d State %04x ConnErr %08x %pI4 "
 				":%04d \"%s\"\n", __func__, fw_ddb_index,
 				mbox_sts[0], mbox_sts[2], mbox_sts[3],
@@ -590,6 +668,7 @@
 {
 	uint32_t mbox_cmd[MBOX_REG_COUNT];
 	uint32_t mbox_sts[MBOX_REG_COUNT];
+	int status;
 
 	/* Do not wait for completion. The firmware will send us an
 	 * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
@@ -603,7 +682,12 @@
 	mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
 	mbox_cmd[4] = sizeof(struct dev_db_entry);
 
-	return qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]);
+	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0],
+	    &mbox_sts[0]);
+	DEBUG2(printk("scsi%ld: %s: status=%d mbx0=0x%x mbx4=0x%x\n",
+	    ha->host_no, __func__, status, mbox_sts[0], mbox_sts[4]);)
+
+	return status;
 }
 
 /**
@@ -817,8 +901,8 @@
 /**
  * qla4xxx_reset_lun - issues LUN Reset
  * @ha: Pointer to host adapter structure.
- * @db_entry: Pointer to device database entry
- * @un_entry: Pointer to lun entry structure
+ * @ddb_entry: Pointer to device database entry
+ * @lun: lun number
  *
  * This routine performs a LUN RESET on the specified target/lun.
  * The caller must ensure that the ddb_entry and lun_entry pointers
@@ -832,7 +916,7 @@
 	int status = QLA_SUCCESS;
 
 	DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no,
-		      ddb_entry->os_target_id, lun));
+		      ddb_entry->fw_ddb_index, lun));
 
 	/*
 	 * Send lun reset command to ISP, so that the ISP will return all
@@ -872,7 +956,7 @@
 	int status = QLA_SUCCESS;
 
 	DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no,
-		      ddb_entry->os_target_id));
+		      ddb_entry->fw_ddb_index));
 
 	/*
 	 * Send target reset command to ISP, so that the ISP will return all
@@ -1019,16 +1103,16 @@
 		DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
 			      ha->host_no, __func__));
 		ret_val = QLA_ERROR;
-		goto qla4xxx_send_tgts_exit;
+		goto exit_send_tgts_no_free;
 	}
 
 	ret_val = qla4xxx_get_default_ddb(ha, fw_ddb_entry_dma);
 	if (ret_val != QLA_SUCCESS)
-		goto qla4xxx_send_tgts_exit;
+		goto exit_send_tgts;
 
 	ret_val = qla4xxx_req_ddb_entry(ha, &ddb_index);
 	if (ret_val != QLA_SUCCESS)
-		goto qla4xxx_send_tgts_exit;
+		goto exit_send_tgts;
 
 	memset(fw_ddb_entry->iscsi_alias, 0,
 	       sizeof(fw_ddb_entry->iscsi_alias));
@@ -1050,9 +1134,10 @@
 
 	ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma);
 
-qla4xxx_send_tgts_exit:
+exit_send_tgts:
 	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
 			  fw_ddb_entry, fw_ddb_entry_dma);
+exit_send_tgts_no_free:
 	return ret_val;
 }
 
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c
index 7fe0482..f0d0fbf 100644
--- a/drivers/scsi/qla4xxx/ql4_nvram.c
+++ b/drivers/scsi/qla4xxx/ql4_nvram.c
@@ -149,7 +149,7 @@
 /* Hardware_lock must be set before calling */
 u16 rd_nvram_word(struct scsi_qla_host * ha, int offset)
 {
-	u16 val;
+	u16 val = 0;
 
 	/* NOTE: NVRAM uses half-word addresses */
 	eeprom_readword(offset, &val, ha);
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h
index b47b4fc..7a8fc66 100644
--- a/drivers/scsi/qla4xxx/ql4_nvram.h
+++ b/drivers/scsi/qla4xxx/ql4_nvram.h
@@ -8,9 +8,9 @@
 #ifndef _QL4XNVRM_H_
 #define _QL4XNVRM_H_
 
-/*
+/**
  * AM29LV Flash definitions
- */
+ **/
 #define FM93C56A_SIZE_8	 0x100
 #define FM93C56A_SIZE_16 0x80
 #define FM93C66A_SIZE_8	 0x200
@@ -19,7 +19,7 @@
 
 #define	 FM93C56A_START	      0x1
 
-// Commands
+/* Commands */
 #define	 FM93C56A_READ	      0x2
 #define	 FM93C56A_WEN	      0x0
 #define	 FM93C56A_WRITE	      0x1
@@ -62,9 +62,9 @@
 #define	 AUBURN_EEPROM_CLK_RISE	    0x1
 #define	 AUBURN_EEPROM_CLK_FALL	    0x0
 
-/* */
+/**/
 /* EEPROM format */
-/* */
+/**/
 struct bios_params {
 	uint16_t SpinUpDelay:1;
 	uint16_t BIOSDisable:1;
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
new file mode 100644
index 0000000..3e119ae
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -0,0 +1,2321 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c)  2003-2009 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include "ql4_def.h"
+#include "ql4_glbl.h"
+
+#define MASK(n)		DMA_BIT_MASK(n)
+#define MN_WIN(addr)	(((addr & 0x1fc0000) >> 1) | ((addr >> 25) & 0x3ff))
+#define OCM_WIN(addr)	(((addr & 0x1ff0000) >> 1) | ((addr >> 25) & 0x3ff))
+#define MS_WIN(addr)	(addr & 0x0ffc0000)
+#define QLA82XX_PCI_MN_2M	(0)
+#define QLA82XX_PCI_MS_2M	(0x80000)
+#define QLA82XX_PCI_OCM0_2M	(0xc0000)
+#define VALID_OCM_ADDR(addr)	(((addr) & 0x3f800) != 0x3f800)
+#define GET_MEM_OFFS_2M(addr)	(addr & MASK(18))
+
+/* CRB window related */
+#define CRB_BLK(off)	((off >> 20) & 0x3f)
+#define CRB_SUBBLK(off)	((off >> 16) & 0xf)
+#define CRB_WINDOW_2M	(0x130060)
+#define CRB_HI(off)	((qla4_8xxx_crb_hub_agt[CRB_BLK(off)] << 20) | \
+			((off) & 0xf0000))
+#define QLA82XX_PCI_CAMQM_2M_END	(0x04800800UL)
+#define QLA82XX_PCI_CAMQM_2M_BASE	(0x000ff800UL)
+#define CRB_INDIRECT_2M			(0x1e0000UL)
+
+static inline void __iomem *
+qla4_8xxx_pci_base_offsetfset(struct scsi_qla_host *ha, unsigned long off)
+{
+	if ((off < ha->first_page_group_end) &&
+	    (off >= ha->first_page_group_start))
+		return (void __iomem *)(ha->nx_pcibase + off);
+
+	return NULL;
+}
+
+#define MAX_CRB_XFORM 60
+static unsigned long crb_addr_xform[MAX_CRB_XFORM];
+static int qla4_8xxx_crb_table_initialized;
+
+#define qla4_8xxx_crb_addr_transform(name) \
+	(crb_addr_xform[QLA82XX_HW_PX_MAP_CRB_##name] = \
+	 QLA82XX_HW_CRB_HUB_AGT_ADR_##name << 20)
+static void
+qla4_8xxx_crb_addr_transform_setup(void)
+{
+	qla4_8xxx_crb_addr_transform(XDMA);
+	qla4_8xxx_crb_addr_transform(TIMR);
+	qla4_8xxx_crb_addr_transform(SRE);
+	qla4_8xxx_crb_addr_transform(SQN3);
+	qla4_8xxx_crb_addr_transform(SQN2);
+	qla4_8xxx_crb_addr_transform(SQN1);
+	qla4_8xxx_crb_addr_transform(SQN0);
+	qla4_8xxx_crb_addr_transform(SQS3);
+	qla4_8xxx_crb_addr_transform(SQS2);
+	qla4_8xxx_crb_addr_transform(SQS1);
+	qla4_8xxx_crb_addr_transform(SQS0);
+	qla4_8xxx_crb_addr_transform(RPMX7);
+	qla4_8xxx_crb_addr_transform(RPMX6);
+	qla4_8xxx_crb_addr_transform(RPMX5);
+	qla4_8xxx_crb_addr_transform(RPMX4);
+	qla4_8xxx_crb_addr_transform(RPMX3);
+	qla4_8xxx_crb_addr_transform(RPMX2);
+	qla4_8xxx_crb_addr_transform(RPMX1);
+	qla4_8xxx_crb_addr_transform(RPMX0);
+	qla4_8xxx_crb_addr_transform(ROMUSB);
+	qla4_8xxx_crb_addr_transform(SN);
+	qla4_8xxx_crb_addr_transform(QMN);
+	qla4_8xxx_crb_addr_transform(QMS);
+	qla4_8xxx_crb_addr_transform(PGNI);
+	qla4_8xxx_crb_addr_transform(PGND);
+	qla4_8xxx_crb_addr_transform(PGN3);
+	qla4_8xxx_crb_addr_transform(PGN2);
+	qla4_8xxx_crb_addr_transform(PGN1);
+	qla4_8xxx_crb_addr_transform(PGN0);
+	qla4_8xxx_crb_addr_transform(PGSI);
+	qla4_8xxx_crb_addr_transform(PGSD);
+	qla4_8xxx_crb_addr_transform(PGS3);
+	qla4_8xxx_crb_addr_transform(PGS2);
+	qla4_8xxx_crb_addr_transform(PGS1);
+	qla4_8xxx_crb_addr_transform(PGS0);
+	qla4_8xxx_crb_addr_transform(PS);
+	qla4_8xxx_crb_addr_transform(PH);
+	qla4_8xxx_crb_addr_transform(NIU);
+	qla4_8xxx_crb_addr_transform(I2Q);
+	qla4_8xxx_crb_addr_transform(EG);
+	qla4_8xxx_crb_addr_transform(MN);
+	qla4_8xxx_crb_addr_transform(MS);
+	qla4_8xxx_crb_addr_transform(CAS2);
+	qla4_8xxx_crb_addr_transform(CAS1);
+	qla4_8xxx_crb_addr_transform(CAS0);
+	qla4_8xxx_crb_addr_transform(CAM);
+	qla4_8xxx_crb_addr_transform(C2C1);
+	qla4_8xxx_crb_addr_transform(C2C0);
+	qla4_8xxx_crb_addr_transform(SMB);
+	qla4_8xxx_crb_addr_transform(OCM0);
+	qla4_8xxx_crb_addr_transform(I2C0);
+
+	qla4_8xxx_crb_table_initialized = 1;
+}
+
+static struct crb_128M_2M_block_map crb_128M_2M_map[64] = {
+	{{{0, 0,         0,         0} } },		/* 0: PCI */
+	{{{1, 0x0100000, 0x0102000, 0x120000},	/* 1: PCIE */
+		{1, 0x0110000, 0x0120000, 0x130000},
+		{1, 0x0120000, 0x0122000, 0x124000},
+		{1, 0x0130000, 0x0132000, 0x126000},
+		{1, 0x0140000, 0x0142000, 0x128000},
+		{1, 0x0150000, 0x0152000, 0x12a000},
+		{1, 0x0160000, 0x0170000, 0x110000},
+		{1, 0x0170000, 0x0172000, 0x12e000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{1, 0x01e0000, 0x01e0800, 0x122000},
+		{0, 0x0000000, 0x0000000, 0x000000} } },
+	{{{1, 0x0200000, 0x0210000, 0x180000} } },/* 2: MN */
+	{{{0, 0,         0,         0} } },	    /* 3: */
+	{{{1, 0x0400000, 0x0401000, 0x169000} } },/* 4: P2NR1 */
+	{{{1, 0x0500000, 0x0510000, 0x140000} } },/* 5: SRE   */
+	{{{1, 0x0600000, 0x0610000, 0x1c0000} } },/* 6: NIU   */
+	{{{1, 0x0700000, 0x0704000, 0x1b8000} } },/* 7: QM    */
+	{{{1, 0x0800000, 0x0802000, 0x170000},  /* 8: SQM0  */
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{1, 0x08f0000, 0x08f2000, 0x172000} } },
+	{{{1, 0x0900000, 0x0902000, 0x174000},	/* 9: SQM1*/
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{1, 0x09f0000, 0x09f2000, 0x176000} } },
+	{{{0, 0x0a00000, 0x0a02000, 0x178000},	/* 10: SQM2*/
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{1, 0x0af0000, 0x0af2000, 0x17a000} } },
+	{{{0, 0x0b00000, 0x0b02000, 0x17c000},	/* 11: SQM3*/
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{1, 0x0bf0000, 0x0bf2000, 0x17e000} } },
+	{{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },/* 12: I2Q */
+	{{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },/* 13: TMR */
+	{{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },/* 14: ROMUSB */
+	{{{1, 0x0f00000, 0x0f01000, 0x164000} } },/* 15: PEG4 */
+	{{{0, 0x1000000, 0x1004000, 0x1a8000} } },/* 16: XDMA */
+	{{{1, 0x1100000, 0x1101000, 0x160000} } },/* 17: PEG0 */
+	{{{1, 0x1200000, 0x1201000, 0x161000} } },/* 18: PEG1 */
+	{{{1, 0x1300000, 0x1301000, 0x162000} } },/* 19: PEG2 */
+	{{{1, 0x1400000, 0x1401000, 0x163000} } },/* 20: PEG3 */
+	{{{1, 0x1500000, 0x1501000, 0x165000} } },/* 21: P2ND */
+	{{{1, 0x1600000, 0x1601000, 0x166000} } },/* 22: P2NI */
+	{{{0, 0,         0,         0} } },	/* 23: */
+	{{{0, 0,         0,         0} } },	/* 24: */
+	{{{0, 0,         0,         0} } },	/* 25: */
+	{{{0, 0,         0,         0} } },	/* 26: */
+	{{{0, 0,         0,         0} } },	/* 27: */
+	{{{0, 0,         0,         0} } },	/* 28: */
+	{{{1, 0x1d00000, 0x1d10000, 0x190000} } },/* 29: MS */
+	{{{1, 0x1e00000, 0x1e01000, 0x16a000} } },/* 30: P2NR2 */
+	{{{1, 0x1f00000, 0x1f10000, 0x150000} } },/* 31: EPG */
+	{{{0} } },				/* 32: PCI */
+	{{{1, 0x2100000, 0x2102000, 0x120000},	/* 33: PCIE */
+		{1, 0x2110000, 0x2120000, 0x130000},
+		{1, 0x2120000, 0x2122000, 0x124000},
+		{1, 0x2130000, 0x2132000, 0x126000},
+		{1, 0x2140000, 0x2142000, 0x128000},
+		{1, 0x2150000, 0x2152000, 0x12a000},
+		{1, 0x2160000, 0x2170000, 0x110000},
+		{1, 0x2170000, 0x2172000, 0x12e000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000},
+		{0, 0x0000000, 0x0000000, 0x000000} } },
+	{{{1, 0x2200000, 0x2204000, 0x1b0000} } },/* 34: CAM */
+	{{{0} } },				/* 35: */
+	{{{0} } },				/* 36: */
+	{{{0} } },				/* 37: */
+	{{{0} } },				/* 38: */
+	{{{0} } },				/* 39: */
+	{{{1, 0x2800000, 0x2804000, 0x1a4000} } },/* 40: TMR */
+	{{{1, 0x2900000, 0x2901000, 0x16b000} } },/* 41: P2NR3 */
+	{{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },/* 42: RPMX1 */
+	{{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },/* 43: RPMX2 */
+	{{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },/* 44: RPMX3 */
+	{{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },/* 45: RPMX4 */
+	{{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },/* 46: RPMX5 */
+	{{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },/* 47: RPMX6 */
+	{{{1, 0x3000000, 0x3000400, 0x1adc00} } },/* 48: RPMX7 */
+	{{{0, 0x3100000, 0x3104000, 0x1a8000} } },/* 49: XDMA */
+	{{{1, 0x3200000, 0x3204000, 0x1d4000} } },/* 50: I2Q */
+	{{{1, 0x3300000, 0x3304000, 0x1a0000} } },/* 51: ROMUSB */
+	{{{0} } },				/* 52: */
+	{{{1, 0x3500000, 0x3500400, 0x1ac000} } },/* 53: RPMX0 */
+	{{{1, 0x3600000, 0x3600400, 0x1ae000} } },/* 54: RPMX8 */
+	{{{1, 0x3700000, 0x3700400, 0x1ae400} } },/* 55: RPMX9 */
+	{{{1, 0x3800000, 0x3804000, 0x1d0000} } },/* 56: OCM0 */
+	{{{1, 0x3900000, 0x3904000, 0x1b4000} } },/* 57: CRYPTO */
+	{{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },/* 58: SMB */
+	{{{0} } },				/* 59: I2C0 */
+	{{{0} } },				/* 60: I2C1 */
+	{{{1, 0x3d00000, 0x3d04000, 0x1dc000} } },/* 61: LPC */
+	{{{1, 0x3e00000, 0x3e01000, 0x167000} } },/* 62: P2NC */
+	{{{1, 0x3f00000, 0x3f01000, 0x168000} } }	/* 63: P2NR0 */
+};
+
+/*
+ * top 12 bits of crb internal address (hub, agent)
+ */
+static unsigned qla4_8xxx_crb_hub_agt[64] = {
+	0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PS,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_MN,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_MS,
+	0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_SRE,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_NIU,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_QMN,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PGND,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3,
+	0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_SN,
+	0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_EG,
+	0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PS,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_CAM,
+	0,
+	0,
+	0,
+	0,
+	0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR,
+	0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB,
+	0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0,
+	0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_SMB,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1,
+	0,
+	QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC,
+	0,
+};
+
+/* Device states */
+static char *qdev_state[] = {
+	"Unknown",
+	"Cold",
+	"Initializing",
+	"Ready",
+	"Need Reset",
+	"Need Quiescent",
+	"Failed",
+	"Quiescent",
+};
+
+/*
+ * In: 'off' is offset from CRB space in 128M pci map
+ * Out: 'off' is 2M pci map addr
+ * side effect: lock crb window
+ */
+static void
+qla4_8xxx_pci_set_crbwindow_2M(struct scsi_qla_host *ha, ulong *off)
+{
+	u32 win_read;
+
+	ha->crb_win = CRB_HI(*off);
+	writel(ha->crb_win,
+		(void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase));
+
+	/* Read back value to make sure write has gone through before trying
+	* to use it. */
+	win_read = readl((void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase));
+	if (win_read != ha->crb_win) {
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+		    "%s: Written crbwin (0x%x) != Read crbwin (0x%x),"
+		    " off=0x%lx\n", __func__, ha->crb_win, win_read, *off));
+	}
+	*off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase;
+}
+
+void
+qla4_8xxx_wr_32(struct scsi_qla_host *ha, ulong off, u32 data)
+{
+	unsigned long flags = 0;
+	int rv;
+
+	rv = qla4_8xxx_pci_get_crb_addr_2M(ha, &off);
+
+	BUG_ON(rv == -1);
+
+	if (rv == 1) {
+		write_lock_irqsave(&ha->hw_lock, flags);
+		qla4_8xxx_crb_win_lock(ha);
+		qla4_8xxx_pci_set_crbwindow_2M(ha, &off);
+	}
+
+	writel(data, (void __iomem *)off);
+
+	if (rv == 1) {
+		qla4_8xxx_crb_win_unlock(ha);
+		write_unlock_irqrestore(&ha->hw_lock, flags);
+	}
+}
+
+int
+qla4_8xxx_rd_32(struct scsi_qla_host *ha, ulong off)
+{
+	unsigned long flags = 0;
+	int rv;
+	u32 data;
+
+	rv = qla4_8xxx_pci_get_crb_addr_2M(ha, &off);
+
+	BUG_ON(rv == -1);
+
+	if (rv == 1) {
+		write_lock_irqsave(&ha->hw_lock, flags);
+		qla4_8xxx_crb_win_lock(ha);
+		qla4_8xxx_pci_set_crbwindow_2M(ha, &off);
+	}
+	data = readl((void __iomem *)off);
+
+	if (rv == 1) {
+		qla4_8xxx_crb_win_unlock(ha);
+		write_unlock_irqrestore(&ha->hw_lock, flags);
+	}
+	return data;
+}
+
+#define CRB_WIN_LOCK_TIMEOUT 100000000
+
+int qla4_8xxx_crb_win_lock(struct scsi_qla_host *ha)
+{
+	int i;
+	int done = 0, timeout = 0;
+
+	while (!done) {
+		/* acquire semaphore3 from PCI HW block */
+		done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK));
+		if (done == 1)
+			break;
+		if (timeout >= CRB_WIN_LOCK_TIMEOUT)
+			return -1;
+
+		timeout++;
+
+		/* Yield CPU */
+		if (!in_interrupt())
+			schedule();
+		else {
+			for (i = 0; i < 20; i++)
+				cpu_relax();    /*This a nop instr on i386*/
+		}
+	}
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->func_num);
+	return 0;
+}
+
+void qla4_8xxx_crb_win_unlock(struct scsi_qla_host *ha)
+{
+	qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK));
+}
+
+#define IDC_LOCK_TIMEOUT 100000000
+
+/**
+ * qla4_8xxx_idc_lock - hw_lock
+ * @ha: pointer to adapter structure
+ *
+ * General purpose lock used to synchronize access to
+ * CRB_DEV_STATE, CRB_DEV_REF_COUNT, etc.
+ **/
+int qla4_8xxx_idc_lock(struct scsi_qla_host *ha)
+{
+	int i;
+	int done = 0, timeout = 0;
+
+	while (!done) {
+		/* acquire semaphore5 from PCI HW block */
+		done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_LOCK));
+		if (done == 1)
+			break;
+		if (timeout >= IDC_LOCK_TIMEOUT)
+			return -1;
+
+		timeout++;
+
+		/* Yield CPU */
+		if (!in_interrupt())
+			schedule();
+		else {
+			for (i = 0; i < 20; i++)
+				cpu_relax();    /*This a nop instr on i386*/
+		}
+	}
+	return 0;
+}
+
+void qla4_8xxx_idc_unlock(struct scsi_qla_host *ha)
+{
+	qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK));
+}
+
+int
+qla4_8xxx_pci_get_crb_addr_2M(struct scsi_qla_host *ha, ulong *off)
+{
+	struct crb_128M_2M_sub_block_map *m;
+
+	if (*off >= QLA82XX_CRB_MAX)
+		return -1;
+
+	if (*off >= QLA82XX_PCI_CAMQM && (*off < QLA82XX_PCI_CAMQM_2M_END)) {
+		*off = (*off - QLA82XX_PCI_CAMQM) +
+		    QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase;
+		return 0;
+	}
+
+	if (*off < QLA82XX_PCI_CRBSPACE)
+		return -1;
+
+	*off -= QLA82XX_PCI_CRBSPACE;
+	/*
+	 * Try direct map
+	 */
+
+	m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)];
+
+	if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) {
+		*off = *off + m->start_2M - m->start_128M + ha->nx_pcibase;
+		return 0;
+	}
+
+	/*
+	 * Not in direct map, use crb window
+	 */
+	return 1;
+}
+
+/*  PCI Windowing for DDR regions.  */
+#define QLA82XX_ADDR_IN_RANGE(addr, low, high)            \
+	(((addr) <= (high)) && ((addr) >= (low)))
+
+/*
+* check memory access boundary.
+* used by test agent. support ddr access only for now
+*/
+static unsigned long
+qla4_8xxx_pci_mem_bound_check(struct scsi_qla_host *ha,
+		unsigned long long addr, int size)
+{
+	if (!QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET,
+	    QLA82XX_ADDR_DDR_NET_MAX) ||
+	    !QLA82XX_ADDR_IN_RANGE(addr + size - 1,
+	    QLA82XX_ADDR_DDR_NET, QLA82XX_ADDR_DDR_NET_MAX) ||
+	    ((size != 1) && (size != 2) && (size != 4) && (size != 8))) {
+		return 0;
+	}
+	return 1;
+}
+
+static int qla4_8xxx_pci_set_window_warning_count;
+
+static unsigned long
+qla4_8xxx_pci_set_window(struct scsi_qla_host *ha, unsigned long long addr)
+{
+	int window;
+	u32 win_read;
+
+	if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET,
+	    QLA82XX_ADDR_DDR_NET_MAX)) {
+		/* DDR network side */
+		window = MN_WIN(addr);
+		ha->ddr_mn_window = window;
+		qla4_8xxx_wr_32(ha, ha->mn_win_crb |
+		    QLA82XX_PCI_CRBSPACE, window);
+		win_read = qla4_8xxx_rd_32(ha, ha->mn_win_crb |
+		    QLA82XX_PCI_CRBSPACE);
+		if ((win_read << 17) != window) {
+			ql4_printk(KERN_WARNING, ha,
+			"%s: Written MNwin (0x%x) != Read MNwin (0x%x)\n",
+			__func__, window, win_read);
+		}
+		addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_DDR_NET;
+	} else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0,
+				QLA82XX_ADDR_OCM0_MAX)) {
+		unsigned int temp1;
+		/* if bits 19:18&17:11 are on */
+		if ((addr & 0x00ff800) == 0xff800) {
+			printk("%s: QM access not handled.\n", __func__);
+			addr = -1UL;
+		}
+
+		window = OCM_WIN(addr);
+		ha->ddr_mn_window = window;
+		qla4_8xxx_wr_32(ha, ha->mn_win_crb |
+		    QLA82XX_PCI_CRBSPACE, window);
+		win_read = qla4_8xxx_rd_32(ha, ha->mn_win_crb |
+		    QLA82XX_PCI_CRBSPACE);
+		temp1 = ((window & 0x1FF) << 7) |
+		    ((window & 0x0FFFE0000) >> 17);
+		if (win_read != temp1) {
+			printk("%s: Written OCMwin (0x%x) != Read"
+			    " OCMwin (0x%x)\n", __func__, temp1, win_read);
+		}
+		addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_OCM0_2M;
+
+	} else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET,
+				QLA82XX_P3_ADDR_QDR_NET_MAX)) {
+		/* QDR network side */
+		window = MS_WIN(addr);
+		ha->qdr_sn_window = window;
+		qla4_8xxx_wr_32(ha, ha->ms_win_crb |
+		    QLA82XX_PCI_CRBSPACE, window);
+		win_read = qla4_8xxx_rd_32(ha,
+		     ha->ms_win_crb | QLA82XX_PCI_CRBSPACE);
+		if (win_read != window) {
+			printk("%s: Written MSwin (0x%x) != Read "
+			    "MSwin (0x%x)\n", __func__, window, win_read);
+		}
+		addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_QDR_NET;
+
+	} else {
+		/*
+		 * peg gdb frequently accesses memory that doesn't exist,
+		 * this limits the chit chat so debugging isn't slowed down.
+		 */
+		if ((qla4_8xxx_pci_set_window_warning_count++ < 8) ||
+		    (qla4_8xxx_pci_set_window_warning_count%64 == 0)) {
+			printk("%s: Warning:%s Unknown address range!\n",
+			    __func__, DRIVER_NAME);
+		}
+		addr = -1UL;
+	}
+	return addr;
+}
+
+/* check if address is in the same windows as the previous access */
+static int qla4_8xxx_pci_is_same_window(struct scsi_qla_host *ha,
+		unsigned long long addr)
+{
+	int window;
+	unsigned long long qdr_max;
+
+	qdr_max = QLA82XX_P3_ADDR_QDR_NET_MAX;
+
+	if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET,
+	    QLA82XX_ADDR_DDR_NET_MAX)) {
+		/* DDR network side */
+		BUG();	/* MN access can not come here */
+	} else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0,
+	     QLA82XX_ADDR_OCM0_MAX)) {
+		return 1;
+	} else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM1,
+	     QLA82XX_ADDR_OCM1_MAX)) {
+		return 1;
+	} else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET,
+	    qdr_max)) {
+		/* QDR network side */
+		window = ((addr - QLA82XX_ADDR_QDR_NET) >> 22) & 0x3f;
+		if (ha->qdr_sn_window == window)
+			return 1;
+	}
+
+	return 0;
+}
+
+static int qla4_8xxx_pci_mem_read_direct(struct scsi_qla_host *ha,
+		u64 off, void *data, int size)
+{
+	unsigned long flags;
+	void __iomem *addr;
+	int ret = 0;
+	u64 start;
+	void __iomem *mem_ptr = NULL;
+	unsigned long mem_base;
+	unsigned long mem_page;
+
+	write_lock_irqsave(&ha->hw_lock, flags);
+
+	/*
+	 * If attempting to access unknown address or straddle hw windows,
+	 * do not access.
+	 */
+	start = qla4_8xxx_pci_set_window(ha, off);
+	if ((start == -1UL) ||
+	    (qla4_8xxx_pci_is_same_window(ha, off + size - 1) == 0)) {
+		write_unlock_irqrestore(&ha->hw_lock, flags);
+		printk(KERN_ERR"%s out of bound pci memory access. "
+				"offset is 0x%llx\n", DRIVER_NAME, off);
+		return -1;
+	}
+
+	addr = qla4_8xxx_pci_base_offsetfset(ha, start);
+	if (!addr) {
+		write_unlock_irqrestore(&ha->hw_lock, flags);
+		mem_base = pci_resource_start(ha->pdev, 0);
+		mem_page = start & PAGE_MASK;
+		/* Map two pages whenever user tries to access addresses in two
+		   consecutive pages.
+		 */
+		if (mem_page != ((start + size - 1) & PAGE_MASK))
+			mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2);
+		else
+			mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
+
+		if (mem_ptr == NULL) {
+			*(u8 *)data = 0;
+			return -1;
+		}
+		addr = mem_ptr;
+		addr += start & (PAGE_SIZE - 1);
+		write_lock_irqsave(&ha->hw_lock, flags);
+	}
+
+	switch (size) {
+	case 1:
+		*(u8  *)data = readb(addr);
+		break;
+	case 2:
+		*(u16 *)data = readw(addr);
+		break;
+	case 4:
+		*(u32 *)data = readl(addr);
+		break;
+	case 8:
+		*(u64 *)data = readq(addr);
+		break;
+	default:
+		ret = -1;
+		break;
+	}
+	write_unlock_irqrestore(&ha->hw_lock, flags);
+
+	if (mem_ptr)
+		iounmap(mem_ptr);
+	return ret;
+}
+
+static int
+qla4_8xxx_pci_mem_write_direct(struct scsi_qla_host *ha, u64 off,
+		void *data, int size)
+{
+	unsigned long flags;
+	void __iomem *addr;
+	int ret = 0;
+	u64 start;
+	void __iomem *mem_ptr = NULL;
+	unsigned long mem_base;
+	unsigned long mem_page;
+
+	write_lock_irqsave(&ha->hw_lock, flags);
+
+	/*
+	 * If attempting to access unknown address or straddle hw windows,
+	 * do not access.
+	 */
+	start = qla4_8xxx_pci_set_window(ha, off);
+	if ((start == -1UL) ||
+	    (qla4_8xxx_pci_is_same_window(ha, off + size - 1) == 0)) {
+		write_unlock_irqrestore(&ha->hw_lock, flags);
+		printk(KERN_ERR"%s out of bound pci memory access. "
+				"offset is 0x%llx\n", DRIVER_NAME, off);
+		return -1;
+	}
+
+	addr = qla4_8xxx_pci_base_offsetfset(ha, start);
+	if (!addr) {
+		write_unlock_irqrestore(&ha->hw_lock, flags);
+		mem_base = pci_resource_start(ha->pdev, 0);
+		mem_page = start & PAGE_MASK;
+		/* Map two pages whenever user tries to access addresses in two
+		   consecutive pages.
+		 */
+		if (mem_page != ((start + size - 1) & PAGE_MASK))
+			mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2);
+		else
+			mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
+		if (mem_ptr == NULL)
+			return -1;
+
+		addr = mem_ptr;
+		addr += start & (PAGE_SIZE - 1);
+		write_lock_irqsave(&ha->hw_lock, flags);
+	}
+
+	switch (size) {
+	case 1:
+		writeb(*(u8 *)data, addr);
+		break;
+	case 2:
+		writew(*(u16 *)data, addr);
+		break;
+	case 4:
+		writel(*(u32 *)data, addr);
+		break;
+	case 8:
+		writeq(*(u64 *)data, addr);
+		break;
+	default:
+		ret = -1;
+		break;
+	}
+	write_unlock_irqrestore(&ha->hw_lock, flags);
+	if (mem_ptr)
+		iounmap(mem_ptr);
+	return ret;
+}
+
+#define MTU_FUDGE_FACTOR 100
+
+static unsigned long
+qla4_8xxx_decode_crb_addr(unsigned long addr)
+{
+	int i;
+	unsigned long base_addr, offset, pci_base;
+
+	if (!qla4_8xxx_crb_table_initialized)
+		qla4_8xxx_crb_addr_transform_setup();
+
+	pci_base = ADDR_ERROR;
+	base_addr = addr & 0xfff00000;
+	offset = addr & 0x000fffff;
+
+	for (i = 0; i < MAX_CRB_XFORM; i++) {
+		if (crb_addr_xform[i] == base_addr) {
+			pci_base = i << 20;
+			break;
+		}
+	}
+	if (pci_base == ADDR_ERROR)
+		return pci_base;
+	else
+		return pci_base + offset;
+}
+
+static long rom_max_timeout = 100;
+static long qla4_8xxx_rom_lock_timeout = 100;
+
+static int
+qla4_8xxx_rom_lock(struct scsi_qla_host *ha)
+{
+	int i;
+	int done = 0, timeout = 0;
+
+	while (!done) {
+		/* acquire semaphore2 from PCI HW block */
+
+		done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK));
+		if (done == 1)
+			break;
+		if (timeout >= qla4_8xxx_rom_lock_timeout)
+			return -1;
+
+		timeout++;
+
+		/* Yield CPU */
+		if (!in_interrupt())
+			schedule();
+		else {
+			for (i = 0; i < 20; i++)
+				cpu_relax();    /*This a nop instr on i386*/
+		}
+	}
+	qla4_8xxx_wr_32(ha, QLA82XX_ROM_LOCK_ID, ROM_LOCK_DRIVER);
+	return 0;
+}
+
+static void
+qla4_8xxx_rom_unlock(struct scsi_qla_host *ha)
+{
+	qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK));
+}
+
+static int
+qla4_8xxx_wait_rom_done(struct scsi_qla_host *ha)
+{
+	long timeout = 0;
+	long done = 0 ;
+
+	while (done == 0) {
+		done = qla4_8xxx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS);
+		done &= 2;
+		timeout++;
+		if (timeout >= rom_max_timeout) {
+			printk("%s: Timeout reached  waiting for rom done",
+					DRIVER_NAME);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int
+qla4_8xxx_do_rom_fast_read(struct scsi_qla_host *ha, int addr, int *valp)
+{
+	qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr);
+	qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
+	qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3);
+	qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0xb);
+	if (qla4_8xxx_wait_rom_done(ha)) {
+		printk("%s: Error waiting for rom done\n", DRIVER_NAME);
+		return -1;
+	}
+	/* reset abyte_cnt and dummy_byte_cnt */
+	qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
+	udelay(10);
+	qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
+
+	*valp = qla4_8xxx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA);
+	return 0;
+}
+
+static int
+qla4_8xxx_rom_fast_read(struct scsi_qla_host *ha, int addr, int *valp)
+{
+	int ret, loops = 0;
+
+	while ((qla4_8xxx_rom_lock(ha) != 0) && (loops < 50000)) {
+		udelay(100);
+		loops++;
+	}
+	if (loops >= 50000) {
+		printk("%s: qla4_8xxx_rom_lock failed\n", DRIVER_NAME);
+		return -1;
+	}
+	ret = qla4_8xxx_do_rom_fast_read(ha, addr, valp);
+	qla4_8xxx_rom_unlock(ha);
+	return ret;
+}
+
+/**
+ * This routine does CRB initialize sequence
+ * to put the ISP into operational state
+ **/
+static int
+qla4_8xxx_pinit_from_rom(struct scsi_qla_host *ha, int verbose)
+{
+	int addr, val;
+	int i ;
+	struct crb_addr_pair *buf;
+	unsigned long off;
+	unsigned offset, n;
+
+	struct crb_addr_pair {
+		long addr;
+		long data;
+	};
+
+	/* Halt all the indiviual PEGs and other blocks of the ISP */
+	qla4_8xxx_rom_lock(ha);
+	if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
+		/* don't reset CAM block on reset */
+		qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff);
+	else
+		qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff);
+
+	qla4_8xxx_rom_unlock(ha);
+
+	/* Read the signature value from the flash.
+	 * Offset 0: Contain signature (0xcafecafe)
+	 * Offset 4: Offset and number of addr/value pairs
+	 * that present in CRB initialize sequence
+	 */
+	if (qla4_8xxx_rom_fast_read(ha, 0, &n) != 0 || n != 0xcafecafeUL ||
+	    qla4_8xxx_rom_fast_read(ha, 4, &n) != 0) {
+		ql4_printk(KERN_WARNING, ha,
+			"[ERROR] Reading crb_init area: n: %08x\n", n);
+		return -1;
+	}
+
+	/* Offset in flash = lower 16 bits
+	 * Number of enteries = upper 16 bits
+	 */
+	offset = n & 0xffffU;
+	n = (n >> 16) & 0xffffU;
+
+	/* number of addr/value pair should not exceed 1024 enteries */
+	if (n  >= 1024) {
+		ql4_printk(KERN_WARNING, ha,
+		    "%s: %s:n=0x%x [ERROR] Card flash not initialized.\n",
+		    DRIVER_NAME, __func__, n);
+		return -1;
+	}
+
+	ql4_printk(KERN_INFO, ha,
+		"%s: %d CRB init values found in ROM.\n", DRIVER_NAME, n);
+
+	buf = kmalloc(n * sizeof(struct crb_addr_pair), GFP_KERNEL);
+	if (buf == NULL) {
+		ql4_printk(KERN_WARNING, ha,
+		    "%s: [ERROR] Unable to malloc memory.\n", DRIVER_NAME);
+		return -1;
+	}
+
+	for (i = 0; i < n; i++) {
+		if (qla4_8xxx_rom_fast_read(ha, 8*i + 4*offset, &val) != 0 ||
+		    qla4_8xxx_rom_fast_read(ha, 8*i + 4*offset + 4, &addr) !=
+		    0) {
+			kfree(buf);
+			return -1;
+		}
+
+		buf[i].addr = addr;
+		buf[i].data = val;
+	}
+
+	for (i = 0; i < n; i++) {
+		/* Translate internal CRB initialization
+		 * address to PCI bus address
+		 */
+		off = qla4_8xxx_decode_crb_addr((unsigned long)buf[i].addr) +
+		    QLA82XX_PCI_CRBSPACE;
+		/* Not all CRB  addr/value pair to be written,
+		 * some of them are skipped
+		 */
+
+		/* skip if LS bit is set*/
+		if (off & 0x1) {
+			DEBUG2(ql4_printk(KERN_WARNING, ha,
+			    "Skip CRB init replay for offset = 0x%lx\n", off));
+			continue;
+		}
+
+		/* skipping cold reboot MAGIC */
+		if (off == QLA82XX_CAM_RAM(0x1fc))
+			continue;
+
+		/* do not reset PCI */
+		if (off == (ROMUSB_GLB + 0xbc))
+			continue;
+
+		/* skip core clock, so that firmware can increase the clock */
+		if (off == (ROMUSB_GLB + 0xc8))
+			continue;
+
+		/* skip the function enable register */
+		if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION))
+			continue;
+
+		if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION2))
+			continue;
+
+		if ((off & 0x0ff00000) == QLA82XX_CRB_SMB)
+			continue;
+
+		if ((off & 0x0ff00000) == QLA82XX_CRB_DDR_NET)
+			continue;
+
+		if (off == ADDR_ERROR) {
+			ql4_printk(KERN_WARNING, ha,
+			    "%s: [ERROR] Unknown addr: 0x%08lx\n",
+			    DRIVER_NAME, buf[i].addr);
+			continue;
+		}
+
+		qla4_8xxx_wr_32(ha, off, buf[i].data);
+
+		/* ISP requires much bigger delay to settle down,
+		 * else crb_window returns 0xffffffff
+		 */
+		if (off == QLA82XX_ROMUSB_GLB_SW_RESET)
+			msleep(1000);
+
+		/* ISP requires millisec delay between
+		 * successive CRB register updation
+		 */
+		msleep(1);
+	}
+
+	kfree(buf);
+
+	/* Resetting the data and instruction cache */
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0xec, 0x1e);
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0x4c, 8);
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_I+0x4c, 8);
+
+	/* Clear all protocol processing engines */
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0x8, 0);
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0xc, 0);
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0x8, 0);
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0xc, 0);
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0x8, 0);
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0xc, 0);
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0x8, 0);
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0xc, 0);
+
+	return 0;
+}
+
+static int qla4_8xxx_check_for_bad_spd(struct scsi_qla_host *ha)
+{
+	u32 val = 0;
+	val = qla4_8xxx_rd_32(ha, BOOT_LOADER_DIMM_STATUS) ;
+	val &= QLA82XX_BOOT_LOADER_MN_ISSUE;
+	if (val & QLA82XX_PEG_TUNE_MN_SPD_ZEROED) {
+		printk("Memory DIMM SPD not programmed.  Assumed valid.\n");
+		return 1;
+	} else if (val) {
+		printk("Memory DIMM type incorrect.  Info:%08X.\n", val);
+		return 2;
+	}
+	return 0;
+}
+
+static int
+qla4_8xxx_load_from_flash(struct scsi_qla_host *ha, uint32_t image_start)
+{
+	int  i;
+	long size = 0;
+	long flashaddr, memaddr;
+	u64 data;
+	u32 high, low;
+
+	flashaddr = memaddr = ha->hw.flt_region_bootload;
+	size = (image_start - flashaddr)/8;
+
+	DEBUG2(printk("scsi%ld: %s: bootldr=0x%lx, fw_image=0x%x\n",
+	    ha->host_no, __func__, flashaddr, image_start));
+
+	for (i = 0; i < size; i++) {
+		if ((qla4_8xxx_rom_fast_read(ha, flashaddr, (int *)&low)) ||
+		    (qla4_8xxx_rom_fast_read(ha, flashaddr + 4,
+		    (int *)&high))) {
+			return -1;
+		}
+		data = ((u64)high << 32) | low ;
+		qla4_8xxx_pci_mem_write_2M(ha, memaddr, &data, 8);
+		flashaddr += 8;
+		memaddr   += 8;
+
+		if (i%0x1000 == 0)
+			msleep(1);
+
+	}
+
+	udelay(100);
+
+	read_lock(&ha->hw_lock);
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
+	qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
+	read_unlock(&ha->hw_lock);
+
+	return 0;
+}
+
+static int qla4_8xxx_load_fw(struct scsi_qla_host *ha, uint32_t image_start)
+{
+	u32 rst;
+
+	qla4_8xxx_wr_32(ha, CRB_CMDPEG_STATE, 0);
+	if (qla4_8xxx_pinit_from_rom(ha, 0) != QLA_SUCCESS) {
+		printk(KERN_WARNING "%s: Error during CRB Initialization\n",
+		    __func__);
+		return QLA_ERROR;
+	}
+
+	udelay(500);
+
+	/* at this point, QM is in reset. This could be a problem if there are
+	 * incoming d* transition queue messages. QM/PCIE could wedge.
+	 * To get around this, QM is brought out of reset.
+	 */
+
+	rst = qla4_8xxx_rd_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET);
+	/* unreset qm */
+	rst &= ~(1 << 28);
+	qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, rst);
+
+	if (qla4_8xxx_load_from_flash(ha, image_start)) {
+		printk("%s: Error trying to load fw from flash!\n", __func__);
+		return QLA_ERROR;
+	}
+
+	return QLA_SUCCESS;
+}
+
+int
+qla4_8xxx_pci_mem_read_2M(struct scsi_qla_host *ha,
+		u64 off, void *data, int size)
+{
+	int i, j = 0, k, start, end, loop, sz[2], off0[2];
+	int shift_amount;
+	uint32_t temp;
+	uint64_t off8, val, mem_crb, word[2] = {0, 0};
+
+	/*
+	 * If not MN, go check for MS or invalid.
+	 */
+
+	if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
+		mem_crb = QLA82XX_CRB_QDR_NET;
+	else {
+		mem_crb = QLA82XX_CRB_DDR_NET;
+		if (qla4_8xxx_pci_mem_bound_check(ha, off, size) == 0)
+			return qla4_8xxx_pci_mem_read_direct(ha,
+					off, data, size);
+	}
+
+
+	off8 = off & 0xfffffff0;
+	off0[0] = off & 0xf;
+	sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]);
+	shift_amount = 4;
+
+	loop = ((off0[0] + size - 1) >> shift_amount) + 1;
+	off0[1] = 0;
+	sz[1] = size - sz[0];
+
+	for (i = 0; i < loop; i++) {
+		temp = off8 + (i << shift_amount);
+		qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp);
+		temp = 0;
+		qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp);
+		temp = MIU_TA_CTL_ENABLE;
+		qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
+		temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE;
+		qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
+
+		for (j = 0; j < MAX_CTL_CHECK; j++) {
+			temp = qla4_8xxx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
+			if ((temp & MIU_TA_CTL_BUSY) == 0)
+				break;
+		}
+
+		if (j >= MAX_CTL_CHECK) {
+			if (printk_ratelimit())
+				ql4_printk(KERN_ERR, ha,
+				    "failed to read through agent\n");
+			break;
+		}
+
+		start = off0[i] >> 2;
+		end   = (off0[i] + sz[i] - 1) >> 2;
+		for (k = start; k <= end; k++) {
+			temp = qla4_8xxx_rd_32(ha,
+				mem_crb + MIU_TEST_AGT_RDDATA(k));
+			word[i] |= ((uint64_t)temp << (32 * (k & 1)));
+		}
+	}
+
+	if (j >= MAX_CTL_CHECK)
+		return -1;
+
+	if ((off0[0] & 7) == 0) {
+		val = word[0];
+	} else {
+		val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) |
+		((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8));
+	}
+
+	switch (size) {
+	case 1:
+		*(uint8_t  *)data = val;
+		break;
+	case 2:
+		*(uint16_t *)data = val;
+		break;
+	case 4:
+		*(uint32_t *)data = val;
+		break;
+	case 8:
+		*(uint64_t *)data = val;
+		break;
+	}
+	return 0;
+}
+
+int
+qla4_8xxx_pci_mem_write_2M(struct scsi_qla_host *ha,
+		u64 off, void *data, int size)
+{
+	int i, j, ret = 0, loop, sz[2], off0;
+	int scale, shift_amount, startword;
+	uint32_t temp;
+	uint64_t off8, mem_crb, tmpw, word[2] = {0, 0};
+
+	/*
+	 * If not MN, go check for MS or invalid.
+	 */
+	if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
+		mem_crb = QLA82XX_CRB_QDR_NET;
+	else {
+		mem_crb = QLA82XX_CRB_DDR_NET;
+		if (qla4_8xxx_pci_mem_bound_check(ha, off, size) == 0)
+			return qla4_8xxx_pci_mem_write_direct(ha,
+					off, data, size);
+	}
+
+	off0 = off & 0x7;
+	sz[0] = (size < (8 - off0)) ? size : (8 - off0);
+	sz[1] = size - sz[0];
+
+	off8 = off & 0xfffffff0;
+	loop = (((off & 0xf) + size - 1) >> 4) + 1;
+	shift_amount = 4;
+	scale = 2;
+	startword = (off & 0xf)/8;
+
+	for (i = 0; i < loop; i++) {
+		if (qla4_8xxx_pci_mem_read_2M(ha, off8 +
+		    (i << shift_amount), &word[i * scale], 8))
+			return -1;
+	}
+
+	switch (size) {
+	case 1:
+		tmpw = *((uint8_t *)data);
+		break;
+	case 2:
+		tmpw = *((uint16_t *)data);
+		break;
+	case 4:
+		tmpw = *((uint32_t *)data);
+		break;
+	case 8:
+	default:
+		tmpw = *((uint64_t *)data);
+		break;
+	}
+
+	if (sz[0] == 8)
+		word[startword] = tmpw;
+	else {
+		word[startword] &=
+		    ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
+		word[startword] |= tmpw << (off0 * 8);
+	}
+
+	if (sz[1] != 0) {
+		word[startword+1] &= ~(~0ULL << (sz[1] * 8));
+		word[startword+1] |= tmpw >> (sz[0] * 8);
+	}
+
+	for (i = 0; i < loop; i++) {
+		temp = off8 + (i << shift_amount);
+		qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp);
+		temp = 0;
+		qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp);
+		temp = word[i * scale] & 0xffffffff;
+		qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp);
+		temp = (word[i * scale] >> 32) & 0xffffffff;
+		qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp);
+		temp = word[i*scale + 1] & 0xffffffff;
+		qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_WRDATA_UPPER_LO,
+		    temp);
+		temp = (word[i*scale + 1] >> 32) & 0xffffffff;
+		qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_WRDATA_UPPER_HI,
+		    temp);
+
+		temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
+		qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp);
+		temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
+		qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp);
+
+		for (j = 0; j < MAX_CTL_CHECK; j++) {
+			temp = qla4_8xxx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
+			if ((temp & MIU_TA_CTL_BUSY) == 0)
+				break;
+		}
+
+		if (j >= MAX_CTL_CHECK) {
+			if (printk_ratelimit())
+				ql4_printk(KERN_ERR, ha,
+				    "failed to write through agent\n");
+			ret = -1;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int qla4_8xxx_cmdpeg_ready(struct scsi_qla_host *ha, int pegtune_val)
+{
+	u32 val = 0;
+	int retries = 60;
+
+	if (!pegtune_val) {
+		do {
+			val = qla4_8xxx_rd_32(ha, CRB_CMDPEG_STATE);
+			if ((val == PHAN_INITIALIZE_COMPLETE) ||
+			    (val == PHAN_INITIALIZE_ACK))
+				return 0;
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(500);
+
+		} while (--retries);
+
+		qla4_8xxx_check_for_bad_spd(ha);
+
+		if (!retries) {
+			pegtune_val = qla4_8xxx_rd_32(ha,
+				QLA82XX_ROMUSB_GLB_PEGTUNE_DONE);
+			printk(KERN_WARNING "%s: init failed, "
+				"pegtune_val = %x\n", __func__, pegtune_val);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int qla4_8xxx_rcvpeg_ready(struct scsi_qla_host *ha)
+{
+	uint32_t state = 0;
+	int loops = 0;
+
+	/* Window 1 call */
+	read_lock(&ha->hw_lock);
+	state = qla4_8xxx_rd_32(ha, CRB_RCVPEG_STATE);
+	read_unlock(&ha->hw_lock);
+
+	while ((state != PHAN_PEG_RCV_INITIALIZED) && (loops < 30000)) {
+		udelay(100);
+		/* Window 1 call */
+		read_lock(&ha->hw_lock);
+		state = qla4_8xxx_rd_32(ha, CRB_RCVPEG_STATE);
+		read_unlock(&ha->hw_lock);
+
+		loops++;
+	}
+
+	if (loops >= 30000) {
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+		    "Receive Peg initialization not complete: 0x%x.\n", state));
+		return QLA_ERROR;
+	}
+
+	return QLA_SUCCESS;
+}
+
+static inline void
+qla4_8xxx_set_drv_active(struct scsi_qla_host *ha)
+{
+	uint32_t drv_active;
+
+	drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+	drv_active |= (1 << (ha->func_num * 4));
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active);
+}
+
+void
+qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha)
+{
+	uint32_t drv_active;
+
+	drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+	drv_active &= ~(1 << (ha->func_num * 4));
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active);
+}
+
+static inline int
+qla4_8xxx_need_reset(struct scsi_qla_host *ha)
+{
+	uint32_t drv_state;
+	int rval;
+
+	drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+	rval = drv_state & (1 << (ha->func_num * 4));
+	return rval;
+}
+
+static inline void
+qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha)
+{
+	uint32_t drv_state;
+
+	drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+	drv_state |= (1 << (ha->func_num * 4));
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state);
+}
+
+static inline void
+qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha)
+{
+	uint32_t drv_state;
+
+	drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+	drv_state &= ~(1 << (ha->func_num * 4));
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state);
+}
+
+static inline void
+qla4_8xxx_set_qsnt_ready(struct scsi_qla_host *ha)
+{
+	uint32_t qsnt_state;
+
+	qsnt_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+	qsnt_state |= (2 << (ha->func_num * 4));
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
+}
+
+
+static int
+qla4_8xxx_start_firmware(struct scsi_qla_host *ha, uint32_t image_start)
+{
+	int pcie_cap;
+	uint16_t lnk;
+
+	/* scrub dma mask expansion register */
+	qla4_8xxx_wr_32(ha, CRB_DMA_SHIFT, 0x55555555);
+
+	/* Overwrite stale initialization register values */
+	qla4_8xxx_wr_32(ha, CRB_CMDPEG_STATE, 0);
+	qla4_8xxx_wr_32(ha, CRB_RCVPEG_STATE, 0);
+	qla4_8xxx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0);
+	qla4_8xxx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0);
+
+	if (qla4_8xxx_load_fw(ha, image_start) != QLA_SUCCESS) {
+		printk("%s: Error trying to start fw!\n", __func__);
+		return QLA_ERROR;
+	}
+
+	/* Handshake with the card before we register the devices. */
+	if (qla4_8xxx_cmdpeg_ready(ha, 0) != QLA_SUCCESS) {
+		printk("%s: Error during card handshake!\n", __func__);
+		return QLA_ERROR;
+	}
+
+	/* Negotiated Link width */
+	pcie_cap = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
+	pci_read_config_word(ha->pdev, pcie_cap + PCI_EXP_LNKSTA, &lnk);
+	ha->link_width = (lnk >> 4) & 0x3f;
+
+	/* Synchronize with Receive peg */
+	return qla4_8xxx_rcvpeg_ready(ha);
+}
+
+static int
+qla4_8xxx_try_start_fw(struct scsi_qla_host *ha)
+{
+	int rval = QLA_ERROR;
+
+	/*
+	 * FW Load priority:
+	 * 1) Operational firmware residing in flash.
+	 * 2) Fail
+	 */
+
+	ql4_printk(KERN_INFO, ha,
+	    "FW: Retrieving flash offsets from FLT/FDT ...\n");
+	rval = qla4_8xxx_get_flash_info(ha);
+	if (rval != QLA_SUCCESS)
+		return rval;
+
+	ql4_printk(KERN_INFO, ha,
+	    "FW: Attempting to load firmware from flash...\n");
+	rval = qla4_8xxx_start_firmware(ha, ha->hw.flt_region_fw);
+	if (rval == QLA_SUCCESS)
+		return rval;
+
+	ql4_printk(KERN_ERR, ha, "FW: Load firmware from flash FAILED...\n");
+
+	return rval;
+}
+
+/**
+ * qla4_8xxx_device_bootstrap - Initialize device, set DEV_READY, start fw
+ * @ha: pointer to adapter structure
+ *
+ * Note: IDC lock must be held upon entry
+ **/
+static int
+qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha)
+{
+	int rval, i, timeout;
+	uint32_t old_count, count;
+
+	if (qla4_8xxx_need_reset(ha))
+		goto dev_initialize;
+
+	old_count = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
+
+	for (i = 0; i < 10; i++) {
+		timeout = msleep_interruptible(200);
+		if (timeout) {
+			qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+			   QLA82XX_DEV_FAILED);
+			return QLA_ERROR;
+		}
+
+		count = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
+		if (count != old_count)
+			goto dev_ready;
+	}
+
+dev_initialize:
+	/* set to DEV_INITIALIZING */
+	ql4_printk(KERN_INFO, ha, "HW State: INITIALIZING\n");
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_INITIALIZING);
+
+	/* Driver that sets device state to initializating sets IDC version */
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, QLA82XX_IDC_VERSION);
+
+	qla4_8xxx_idc_unlock(ha);
+	rval = qla4_8xxx_try_start_fw(ha);
+	qla4_8xxx_idc_lock(ha);
+
+	if (rval != QLA_SUCCESS) {
+		ql4_printk(KERN_INFO, ha, "HW State: FAILED\n");
+		qla4_8xxx_clear_drv_active(ha);
+		qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_FAILED);
+		return rval;
+	}
+
+dev_ready:
+	ql4_printk(KERN_INFO, ha, "HW State: READY\n");
+	qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY);
+
+	return QLA_SUCCESS;
+}
+
+/**
+ * qla4_8xxx_need_reset_handler - Code to start reset sequence
+ * @ha: pointer to adapter structure
+ *
+ * Note: IDC lock must be held upon entry
+ **/
+static void
+qla4_8xxx_need_reset_handler(struct scsi_qla_host *ha)
+{
+	uint32_t dev_state, drv_state, drv_active;
+	unsigned long reset_timeout;
+
+	ql4_printk(KERN_INFO, ha,
+		"Performing ISP error recovery\n");
+
+	if (test_and_clear_bit(AF_ONLINE, &ha->flags)) {
+		qla4_8xxx_idc_unlock(ha);
+		ha->isp_ops->disable_intrs(ha);
+		qla4_8xxx_idc_lock(ha);
+	}
+
+	qla4_8xxx_set_rst_ready(ha);
+
+	/* wait for 10 seconds for reset ack from all functions */
+	reset_timeout = jiffies + (ha->nx_reset_timeout * HZ);
+
+	drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+	drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+
+	ql4_printk(KERN_INFO, ha,
+		"%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n",
+		__func__, ha->host_no, drv_state, drv_active);
+
+	while (drv_state != drv_active) {
+		if (time_after_eq(jiffies, reset_timeout)) {
+			printk("%s: RESET TIMEOUT!\n", DRIVER_NAME);
+			break;
+		}
+
+		qla4_8xxx_idc_unlock(ha);
+		msleep(1000);
+		qla4_8xxx_idc_lock(ha);
+
+		drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+		drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+	}
+
+	dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+	ql4_printk(KERN_INFO, ha, "3:Device state is 0x%x = %s\n", dev_state,
+		dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
+
+	/* Force to DEV_COLD unless someone else is starting a reset */
+	if (dev_state != QLA82XX_DEV_INITIALIZING) {
+		ql4_printk(KERN_INFO, ha, "HW State: COLD/RE-INIT\n");
+		qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD);
+	}
+}
+
+/**
+ * qla4_8xxx_need_qsnt_handler - Code to start qsnt
+ * @ha: pointer to adapter structure
+ **/
+void
+qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha)
+{
+	qla4_8xxx_idc_lock(ha);
+	qla4_8xxx_set_qsnt_ready(ha);
+	qla4_8xxx_idc_unlock(ha);
+}
+
+/**
+ * qla4_8xxx_device_state_handler - Adapter state machine
+ * @ha: pointer to host adapter structure.
+ *
+ * Note: IDC lock must be UNLOCKED upon entry
+ **/
+int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha)
+{
+	uint32_t dev_state;
+	int rval = QLA_SUCCESS;
+	unsigned long dev_init_timeout;
+
+	if (!test_bit(AF_INIT_DONE, &ha->flags))
+		qla4_8xxx_set_drv_active(ha);
+
+	dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+	ql4_printk(KERN_INFO, ha, "1:Device state is 0x%x = %s\n", dev_state,
+		dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
+
+	/* wait for 30 seconds for device to go ready */
+	dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ);
+
+	while (1) {
+		qla4_8xxx_idc_lock(ha);
+
+		if (time_after_eq(jiffies, dev_init_timeout)) {
+			ql4_printk(KERN_WARNING, ha, "Device init failed!\n");
+			qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+				QLA82XX_DEV_FAILED);
+		}
+
+		dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+		ql4_printk(KERN_INFO, ha,
+		    "2:Device state is 0x%x = %s\n", dev_state,
+		    dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
+
+		/* NOTE: Make sure idc unlocked upon exit of switch statement */
+		switch (dev_state) {
+		case QLA82XX_DEV_READY:
+			qla4_8xxx_idc_unlock(ha);
+			goto exit;
+		case QLA82XX_DEV_COLD:
+			rval = qla4_8xxx_device_bootstrap(ha);
+			qla4_8xxx_idc_unlock(ha);
+			goto exit;
+		case QLA82XX_DEV_INITIALIZING:
+			qla4_8xxx_idc_unlock(ha);
+			msleep(1000);
+			break;
+		case QLA82XX_DEV_NEED_RESET:
+			if (!ql4xdontresethba) {
+				qla4_8xxx_need_reset_handler(ha);
+				/* Update timeout value after need
+				 * reset handler */
+				dev_init_timeout = jiffies +
+					(ha->nx_dev_init_timeout * HZ);
+			}
+			qla4_8xxx_idc_unlock(ha);
+			break;
+		case QLA82XX_DEV_NEED_QUIESCENT:
+			qla4_8xxx_idc_unlock(ha);
+			/* idc locked/unlocked in handler */
+			qla4_8xxx_need_qsnt_handler(ha);
+			qla4_8xxx_idc_lock(ha);
+			/* fall thru needs idc_locked */
+		case QLA82XX_DEV_QUIESCENT:
+			qla4_8xxx_idc_unlock(ha);
+			msleep(1000);
+			break;
+		case QLA82XX_DEV_FAILED:
+			qla4_8xxx_idc_unlock(ha);
+			qla4xxx_dead_adapter_cleanup(ha);
+			rval = QLA_ERROR;
+			goto exit;
+		default:
+			qla4_8xxx_idc_unlock(ha);
+			qla4xxx_dead_adapter_cleanup(ha);
+			rval = QLA_ERROR;
+			goto exit;
+		}
+	}
+exit:
+	return rval;
+}
+
+int qla4_8xxx_load_risc(struct scsi_qla_host *ha)
+{
+	int retval;
+	retval = qla4_8xxx_device_state_handler(ha);
+
+	if (retval == QLA_SUCCESS &&
+	    !test_bit(AF_INIT_DONE, &ha->flags)) {
+		retval = qla4xxx_request_irqs(ha);
+		if (retval != QLA_SUCCESS) {
+			ql4_printk(KERN_WARNING, ha,
+			    "Failed to reserve interrupt %d already in use.\n",
+			    ha->pdev->irq);
+		} else {
+			set_bit(AF_IRQ_ATTACHED, &ha->flags);
+			ha->host->irq = ha->pdev->irq;
+			ql4_printk(KERN_INFO, ha, "%s: irq %d attached\n",
+			    __func__, ha->pdev->irq);
+		}
+	}
+	return retval;
+}
+
+/*****************************************************************************/
+/* Flash Manipulation Routines                                               */
+/*****************************************************************************/
+
+#define OPTROM_BURST_SIZE       0x1000
+#define OPTROM_BURST_DWORDS     (OPTROM_BURST_SIZE / 4)
+
+#define FARX_DATA_FLAG	BIT_31
+#define FARX_ACCESS_FLASH_CONF	0x7FFD0000
+#define FARX_ACCESS_FLASH_DATA	0x7FF00000
+
+static inline uint32_t
+flash_conf_addr(struct ql82xx_hw_data *hw, uint32_t faddr)
+{
+	return hw->flash_conf_off | faddr;
+}
+
+static inline uint32_t
+flash_data_addr(struct ql82xx_hw_data *hw, uint32_t faddr)
+{
+	return hw->flash_data_off | faddr;
+}
+
+static uint32_t *
+qla4_8xxx_read_flash_data(struct scsi_qla_host *ha, uint32_t *dwptr,
+    uint32_t faddr, uint32_t length)
+{
+	uint32_t i;
+	uint32_t val;
+	int loops = 0;
+	while ((qla4_8xxx_rom_lock(ha) != 0) && (loops < 50000)) {
+		udelay(100);
+		cond_resched();
+		loops++;
+	}
+	if (loops >= 50000) {
+		ql4_printk(KERN_WARNING, ha, "ROM lock failed\n");
+		return dwptr;
+	}
+
+	/* Dword reads to flash. */
+	for (i = 0; i < length/4; i++, faddr += 4) {
+		if (qla4_8xxx_do_rom_fast_read(ha, faddr, &val)) {
+			ql4_printk(KERN_WARNING, ha,
+			    "Do ROM fast read failed\n");
+			goto done_read;
+		}
+		dwptr[i] = __constant_cpu_to_le32(val);
+	}
+
+done_read:
+	qla4_8xxx_rom_unlock(ha);
+	return dwptr;
+}
+
+/**
+ * Address and length are byte address
+ **/
+static uint8_t *
+qla4_8xxx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
+		uint32_t offset, uint32_t length)
+{
+	qla4_8xxx_read_flash_data(ha, (uint32_t *)buf, offset, length);
+	return buf;
+}
+
+static int
+qla4_8xxx_find_flt_start(struct scsi_qla_host *ha, uint32_t *start)
+{
+	const char *loc, *locations[] = { "DEF", "PCI" };
+
+	/*
+	 * FLT-location structure resides after the last PCI region.
+	 */
+
+	/* Begin with sane defaults. */
+	loc = locations[0];
+	*start = FA_FLASH_LAYOUT_ADDR_82;
+
+	DEBUG2(ql4_printk(KERN_INFO, ha, "FLTL[%s] = 0x%x.\n", loc, *start));
+	return QLA_SUCCESS;
+}
+
+static void
+qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr)
+{
+	const char *loc, *locations[] = { "DEF", "FLT" };
+	uint16_t *wptr;
+	uint16_t cnt, chksum;
+	uint32_t start;
+	struct qla_flt_header *flt;
+	struct qla_flt_region *region;
+	struct ql82xx_hw_data *hw = &ha->hw;
+
+	hw->flt_region_flt = flt_addr;
+	wptr = (uint16_t *)ha->request_ring;
+	flt = (struct qla_flt_header *)ha->request_ring;
+	region = (struct qla_flt_region *)&flt[1];
+	qla4_8xxx_read_optrom_data(ha, (uint8_t *)ha->request_ring,
+			flt_addr << 2, OPTROM_BURST_SIZE);
+	if (*wptr == __constant_cpu_to_le16(0xffff))
+		goto no_flash_data;
+	if (flt->version != __constant_cpu_to_le16(1)) {
+		DEBUG2(ql4_printk(KERN_INFO, ha, "Unsupported FLT detected: "
+			"version=0x%x length=0x%x checksum=0x%x.\n",
+			le16_to_cpu(flt->version), le16_to_cpu(flt->length),
+			le16_to_cpu(flt->checksum)));
+		goto no_flash_data;
+	}
+
+	cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1;
+	for (chksum = 0; cnt; cnt--)
+		chksum += le16_to_cpu(*wptr++);
+	if (chksum) {
+		DEBUG2(ql4_printk(KERN_INFO, ha, "Inconsistent FLT detected: "
+			"version=0x%x length=0x%x checksum=0x%x.\n",
+			le16_to_cpu(flt->version), le16_to_cpu(flt->length),
+			chksum));
+		goto no_flash_data;
+	}
+
+	loc = locations[1];
+	cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
+	for ( ; cnt; cnt--, region++) {
+		/* Store addresses as DWORD offsets. */
+		start = le32_to_cpu(region->start) >> 2;
+
+		DEBUG3(ql4_printk(KERN_DEBUG, ha, "FLT[%02x]: start=0x%x "
+		    "end=0x%x size=0x%x.\n", le32_to_cpu(region->code), start,
+		    le32_to_cpu(region->end) >> 2, le32_to_cpu(region->size)));
+
+		switch (le32_to_cpu(region->code) & 0xff) {
+		case FLT_REG_FDT:
+			hw->flt_region_fdt = start;
+			break;
+		case FLT_REG_BOOT_CODE_82:
+			hw->flt_region_boot = start;
+			break;
+		case FLT_REG_FW_82:
+			hw->flt_region_fw = start;
+			break;
+		case FLT_REG_BOOTLOAD_82:
+			hw->flt_region_bootload = start;
+			break;
+		}
+	}
+	goto done;
+
+no_flash_data:
+	/* Use hardcoded defaults. */
+	loc = locations[0];
+
+	hw->flt_region_fdt      = FA_FLASH_DESCR_ADDR_82;
+	hw->flt_region_boot     = FA_BOOT_CODE_ADDR_82;
+	hw->flt_region_bootload = FA_BOOT_LOAD_ADDR_82;
+	hw->flt_region_fw       = FA_RISC_CODE_ADDR_82;
+done:
+	DEBUG2(ql4_printk(KERN_INFO, ha, "FLT[%s]: flt=0x%x fdt=0x%x "
+	    "boot=0x%x bootload=0x%x fw=0x%x\n", loc, hw->flt_region_flt,
+	    hw->flt_region_fdt,	hw->flt_region_boot, hw->flt_region_bootload,
+	    hw->flt_region_fw));
+}
+
+static void
+qla4_8xxx_get_fdt_info(struct scsi_qla_host *ha)
+{
+#define FLASH_BLK_SIZE_4K       0x1000
+#define FLASH_BLK_SIZE_32K      0x8000
+#define FLASH_BLK_SIZE_64K      0x10000
+	const char *loc, *locations[] = { "MID", "FDT" };
+	uint16_t cnt, chksum;
+	uint16_t *wptr;
+	struct qla_fdt_layout *fdt;
+	uint16_t mid, fid;
+	struct ql82xx_hw_data *hw = &ha->hw;
+
+	hw->flash_conf_off = FARX_ACCESS_FLASH_CONF;
+	hw->flash_data_off = FARX_ACCESS_FLASH_DATA;
+
+	wptr = (uint16_t *)ha->request_ring;
+	fdt = (struct qla_fdt_layout *)ha->request_ring;
+	qla4_8xxx_read_optrom_data(ha, (uint8_t *)ha->request_ring,
+	    hw->flt_region_fdt << 2, OPTROM_BURST_SIZE);
+
+	if (*wptr == __constant_cpu_to_le16(0xffff))
+		goto no_flash_data;
+
+	if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' ||
+	    fdt->sig[3] != 'D')
+		goto no_flash_data;
+
+	for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1;
+	    cnt++)
+		chksum += le16_to_cpu(*wptr++);
+
+	if (chksum) {
+		DEBUG2(ql4_printk(KERN_INFO, ha, "Inconsistent FDT detected: "
+		    "checksum=0x%x id=%c version=0x%x.\n", chksum, fdt->sig[0],
+		    le16_to_cpu(fdt->version)));
+		goto no_flash_data;
+	}
+
+	loc = locations[1];
+	mid = le16_to_cpu(fdt->man_id);
+	fid = le16_to_cpu(fdt->id);
+	hw->fdt_wrt_disable = fdt->wrt_disable_bits;
+	hw->fdt_erase_cmd = flash_conf_addr(hw, 0x0300 | fdt->erase_cmd);
+	hw->fdt_block_size = le32_to_cpu(fdt->block_size);
+
+	if (fdt->unprotect_sec_cmd) {
+		hw->fdt_unprotect_sec_cmd = flash_conf_addr(hw, 0x0300 |
+		    fdt->unprotect_sec_cmd);
+		hw->fdt_protect_sec_cmd = fdt->protect_sec_cmd ?
+		    flash_conf_addr(hw, 0x0300 | fdt->protect_sec_cmd) :
+		    flash_conf_addr(hw, 0x0336);
+	}
+	goto done;
+
+no_flash_data:
+	loc = locations[0];
+	hw->fdt_block_size = FLASH_BLK_SIZE_64K;
+done:
+	DEBUG2(ql4_printk(KERN_INFO, ha, "FDT[%s]: (0x%x/0x%x) erase=0x%x "
+		"pro=%x upro=%x wrtd=0x%x blk=0x%x.\n", loc, mid, fid,
+		hw->fdt_erase_cmd, hw->fdt_protect_sec_cmd,
+		hw->fdt_unprotect_sec_cmd, hw->fdt_wrt_disable,
+		hw->fdt_block_size));
+}
+
+static void
+qla4_8xxx_get_idc_param(struct scsi_qla_host *ha)
+{
+#define QLA82XX_IDC_PARAM_ADDR      0x003e885c
+	uint32_t *wptr;
+
+	if (!is_qla8022(ha))
+		return;
+	wptr = (uint32_t *)ha->request_ring;
+	qla4_8xxx_read_optrom_data(ha, (uint8_t *)ha->request_ring,
+			QLA82XX_IDC_PARAM_ADDR , 8);
+
+	if (*wptr == __constant_cpu_to_le32(0xffffffff)) {
+		ha->nx_dev_init_timeout = ROM_DEV_INIT_TIMEOUT;
+		ha->nx_reset_timeout = ROM_DRV_RESET_ACK_TIMEOUT;
+	} else {
+		ha->nx_dev_init_timeout = le32_to_cpu(*wptr++);
+		ha->nx_reset_timeout = le32_to_cpu(*wptr);
+	}
+
+	DEBUG2(ql4_printk(KERN_DEBUG, ha,
+		"ha->nx_dev_init_timeout = %d\n", ha->nx_dev_init_timeout));
+	DEBUG2(ql4_printk(KERN_DEBUG, ha,
+		"ha->nx_reset_timeout = %d\n", ha->nx_reset_timeout));
+	return;
+}
+
+int
+qla4_8xxx_get_flash_info(struct scsi_qla_host *ha)
+{
+	int ret;
+	uint32_t flt_addr;
+
+	ret = qla4_8xxx_find_flt_start(ha, &flt_addr);
+	if (ret != QLA_SUCCESS)
+		return ret;
+
+	qla4_8xxx_get_flt_info(ha, flt_addr);
+	qla4_8xxx_get_fdt_info(ha);
+	qla4_8xxx_get_idc_param(ha);
+
+	return QLA_SUCCESS;
+}
+
+/**
+ * qla4_8xxx_stop_firmware - stops firmware on specified adapter instance
+ * @ha: pointer to host adapter structure.
+ *
+ * Remarks:
+ * For iSCSI, throws away all I/O and AENs into bit bucket, so they will
+ * not be available after successful return.  Driver must cleanup potential
+ * outstanding I/O's after calling this funcion.
+ **/
+int
+qla4_8xxx_stop_firmware(struct scsi_qla_host *ha)
+{
+	int status;
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+	mbox_cmd[0] = MBOX_CMD_STOP_FW;
+	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1,
+	    &mbox_cmd[0], &mbox_sts[0]);
+
+	DEBUG2(printk("scsi%ld: %s: status = %d\n", ha->host_no,
+	    __func__, status));
+	return status;
+}
+
+/**
+ * qla4_8xxx_isp_reset - Resets ISP and aborts all outstanding commands.
+ * @ha: pointer to host adapter structure.
+ **/
+int
+qla4_8xxx_isp_reset(struct scsi_qla_host *ha)
+{
+	int rval;
+	uint32_t dev_state;
+
+	qla4_8xxx_idc_lock(ha);
+	dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+
+	if (dev_state == QLA82XX_DEV_READY) {
+		ql4_printk(KERN_INFO, ha, "HW State: NEED RESET\n");
+		qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+		    QLA82XX_DEV_NEED_RESET);
+	} else
+		ql4_printk(KERN_INFO, ha, "HW State: DEVICE INITIALIZING\n");
+
+	qla4_8xxx_idc_unlock(ha);
+
+	rval = qla4_8xxx_device_state_handler(ha);
+
+	qla4_8xxx_idc_lock(ha);
+	qla4_8xxx_clear_rst_ready(ha);
+	qla4_8xxx_idc_unlock(ha);
+
+	return rval;
+}
+
+/**
+ * qla4_8xxx_get_sys_info - get adapter MAC address(es) and serial number
+ * @ha: pointer to host adapter structure.
+ *
+ **/
+int qla4_8xxx_get_sys_info(struct scsi_qla_host *ha)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+	struct mbx_sys_info *sys_info;
+	dma_addr_t sys_info_dma;
+	int status = QLA_ERROR;
+
+	sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info),
+				      &sys_info_dma, GFP_KERNEL);
+	if (sys_info == NULL) {
+		DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
+		    ha->host_no, __func__));
+		return status;
+	}
+
+	memset(sys_info, 0, sizeof(*sys_info));
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+	mbox_cmd[0] = MBOX_CMD_GET_SYS_INFO;
+	mbox_cmd[1] = LSDW(sys_info_dma);
+	mbox_cmd[2] = MSDW(sys_info_dma);
+	mbox_cmd[4] = sizeof(*sys_info);
+
+	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 6, &mbox_cmd[0],
+	    &mbox_sts[0]) != QLA_SUCCESS) {
+		DEBUG2(printk("scsi%ld: %s: GET_SYS_INFO failed\n",
+		    ha->host_no, __func__));
+		goto exit_validate_mac82;
+	}
+
+	if (mbox_sts[4] < sizeof(*sys_info)) {
+		DEBUG2(printk("scsi%ld: %s: GET_SYS_INFO data receive"
+		    " error (%x)\n", ha->host_no, __func__, mbox_sts[4]));
+		goto exit_validate_mac82;
+
+	}
+
+	/* Save M.A.C. address & serial_number */
+	memcpy(ha->my_mac, &sys_info->mac_addr[0],
+	    min(sizeof(ha->my_mac), sizeof(sys_info->mac_addr)));
+	memcpy(ha->serial_number, &sys_info->serial_number,
+	    min(sizeof(ha->serial_number), sizeof(sys_info->serial_number)));
+
+	DEBUG2(printk("scsi%ld: %s: "
+	    "mac %02x:%02x:%02x:%02x:%02x:%02x "
+	    "serial %s\n", ha->host_no, __func__,
+	    ha->my_mac[0], ha->my_mac[1], ha->my_mac[2],
+	    ha->my_mac[3], ha->my_mac[4], ha->my_mac[5],
+	    ha->serial_number));
+
+	status = QLA_SUCCESS;
+
+exit_validate_mac82:
+	dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info,
+			  sys_info_dma);
+	return status;
+}
+
+/* Interrupt handling helpers. */
+
+static int
+qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+
+	DEBUG2(ql4_printk(KERN_INFO, ha, "%s\n", __func__));
+
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+	mbox_cmd[0] = MBOX_CMD_ENABLE_INTRS;
+	mbox_cmd[1] = INTR_ENABLE;
+	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+		&mbox_sts[0]) != QLA_SUCCESS) {
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+		    "%s: MBOX_CMD_ENABLE_INTRS failed (0x%04x)\n",
+		    __func__, mbox_sts[0]));
+		return QLA_ERROR;
+	}
+	return QLA_SUCCESS;
+}
+
+static int
+qla4_8xxx_mbx_intr_disable(struct scsi_qla_host *ha)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+
+	DEBUG2(ql4_printk(KERN_INFO, ha, "%s\n", __func__));
+
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+	mbox_cmd[0] = MBOX_CMD_ENABLE_INTRS;
+	mbox_cmd[1] = INTR_DISABLE;
+	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+	    &mbox_sts[0]) != QLA_SUCCESS) {
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+			"%s: MBOX_CMD_ENABLE_INTRS failed (0x%04x)\n",
+			__func__, mbox_sts[0]));
+		return QLA_ERROR;
+	}
+
+	return QLA_SUCCESS;
+}
+
+void
+qla4_8xxx_enable_intrs(struct scsi_qla_host *ha)
+{
+	qla4_8xxx_mbx_intr_enable(ha);
+
+	spin_lock_irq(&ha->hardware_lock);
+	/* BIT 10 - reset */
+	qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
+	spin_unlock_irq(&ha->hardware_lock);
+	set_bit(AF_INTERRUPTS_ON, &ha->flags);
+}
+
+void
+qla4_8xxx_disable_intrs(struct scsi_qla_host *ha)
+{
+	if (test_bit(AF_INTERRUPTS_ON, &ha->flags))
+		qla4_8xxx_mbx_intr_disable(ha);
+
+	spin_lock_irq(&ha->hardware_lock);
+	/* BIT 10 - set */
+	qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400);
+	spin_unlock_irq(&ha->hardware_lock);
+	clear_bit(AF_INTERRUPTS_ON, &ha->flags);
+}
+
+struct ql4_init_msix_entry {
+	uint16_t entry;
+	uint16_t index;
+	const char *name;
+	irq_handler_t handler;
+};
+
+static struct ql4_init_msix_entry qla4_8xxx_msix_entries[QLA_MSIX_ENTRIES] = {
+	{ QLA_MSIX_DEFAULT, QLA_MIDX_DEFAULT,
+	    "qla4xxx (default)",
+	    (irq_handler_t)qla4_8xxx_default_intr_handler },
+	{ QLA_MSIX_RSP_Q, QLA_MIDX_RSP_Q,
+	    "qla4xxx (rsp_q)", (irq_handler_t)qla4_8xxx_msix_rsp_q },
+};
+
+void
+qla4_8xxx_disable_msix(struct scsi_qla_host *ha)
+{
+	int i;
+	struct ql4_msix_entry *qentry;
+
+	for (i = 0; i < QLA_MSIX_ENTRIES; i++) {
+		qentry = &ha->msix_entries[qla4_8xxx_msix_entries[i].index];
+		if (qentry->have_irq) {
+			free_irq(qentry->msix_vector, ha);
+			DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %s\n",
+				__func__, qla4_8xxx_msix_entries[i].name));
+		}
+	}
+	pci_disable_msix(ha->pdev);
+	clear_bit(AF_MSIX_ENABLED, &ha->flags);
+}
+
+int
+qla4_8xxx_enable_msix(struct scsi_qla_host *ha)
+{
+	int i, ret;
+	struct msix_entry entries[QLA_MSIX_ENTRIES];
+	struct ql4_msix_entry *qentry;
+
+	for (i = 0; i < QLA_MSIX_ENTRIES; i++)
+		entries[i].entry = qla4_8xxx_msix_entries[i].entry;
+
+	ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries));
+	if (ret) {
+		ql4_printk(KERN_WARNING, ha,
+		    "MSI-X: Failed to enable support -- %d/%d\n",
+		    QLA_MSIX_ENTRIES, ret);
+		goto msix_out;
+	}
+	set_bit(AF_MSIX_ENABLED, &ha->flags);
+
+	for (i = 0; i < QLA_MSIX_ENTRIES; i++) {
+		qentry = &ha->msix_entries[qla4_8xxx_msix_entries[i].index];
+		qentry->msix_vector = entries[i].vector;
+		qentry->msix_entry = entries[i].entry;
+		qentry->have_irq = 0;
+		ret = request_irq(qentry->msix_vector,
+		    qla4_8xxx_msix_entries[i].handler, 0,
+		    qla4_8xxx_msix_entries[i].name, ha);
+		if (ret) {
+			ql4_printk(KERN_WARNING, ha,
+			    "MSI-X: Unable to register handler -- %x/%d.\n",
+			    qla4_8xxx_msix_entries[i].index, ret);
+			qla4_8xxx_disable_msix(ha);
+			goto msix_out;
+		}
+		qentry->have_irq = 1;
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %s\n",
+			__func__, qla4_8xxx_msix_entries[i].name));
+	}
+msix_out:
+	return ret;
+}
diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h
new file mode 100644
index 0000000..931ad3f
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_nx.h
@@ -0,0 +1,779 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c)  2003-2008 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#ifndef __QLA_NX_H
+#define __QLA_NX_H
+
+/*
+ * Following are the states of the Phantom. Phantom will set them and
+ * Host will read to check if the fields are correct.
+*/
+#define PHAN_INITIALIZE_FAILED		0xffff
+#define PHAN_INITIALIZE_COMPLETE	0xff01
+
+/* Host writes the following to notify that it has done the init-handshake */
+#define PHAN_INITIALIZE_ACK		0xf00f
+#define PHAN_PEG_RCV_INITIALIZED	0xff01
+
+/*CRB_RELATED*/
+#define QLA82XX_CRB_BASE	QLA82XX_CAM_RAM(0x200)
+#define QLA82XX_REG(X)		(QLA82XX_CRB_BASE+(X))
+
+#define CRB_CMDPEG_STATE		QLA82XX_REG(0x50)
+#define CRB_RCVPEG_STATE		QLA82XX_REG(0x13c)
+#define BOOT_LOADER_DIMM_STATUS		QLA82XX_REG(0x54)
+#define CRB_DMA_SHIFT			QLA82XX_REG(0xcc)
+
+#define QLA82XX_HW_H0_CH_HUB_ADR	0x05
+#define QLA82XX_HW_H1_CH_HUB_ADR	0x0E
+#define QLA82XX_HW_H2_CH_HUB_ADR	0x03
+#define QLA82XX_HW_H3_CH_HUB_ADR	0x01
+#define QLA82XX_HW_H4_CH_HUB_ADR	0x06
+#define QLA82XX_HW_H5_CH_HUB_ADR	0x07
+#define QLA82XX_HW_H6_CH_HUB_ADR	0x08
+
+/*  Hub 0 */
+#define QLA82XX_HW_MN_CRB_AGT_ADR	0x15
+#define QLA82XX_HW_MS_CRB_AGT_ADR	0x25
+
+/*  Hub 1 */
+#define QLA82XX_HW_PS_CRB_AGT_ADR	0x73
+#define QLA82XX_HW_QMS_CRB_AGT_ADR	0x00
+#define QLA82XX_HW_RPMX3_CRB_AGT_ADR	0x0b
+#define QLA82XX_HW_SQGS0_CRB_AGT_ADR	0x01
+#define QLA82XX_HW_SQGS1_CRB_AGT_ADR	0x02
+#define QLA82XX_HW_SQGS2_CRB_AGT_ADR	0x03
+#define QLA82XX_HW_SQGS3_CRB_AGT_ADR	0x04
+#define QLA82XX_HW_C2C0_CRB_AGT_ADR	0x58
+#define QLA82XX_HW_C2C1_CRB_AGT_ADR	0x59
+#define QLA82XX_HW_C2C2_CRB_AGT_ADR	0x5a
+#define QLA82XX_HW_RPMX2_CRB_AGT_ADR	0x0a
+#define QLA82XX_HW_RPMX4_CRB_AGT_ADR	0x0c
+#define QLA82XX_HW_RPMX7_CRB_AGT_ADR	0x0f
+#define QLA82XX_HW_RPMX9_CRB_AGT_ADR	0x12
+#define QLA82XX_HW_SMB_CRB_AGT_ADR	0x18
+
+/*  Hub 2 */
+#define QLA82XX_HW_NIU_CRB_AGT_ADR	0x31
+#define QLA82XX_HW_I2C0_CRB_AGT_ADR	0x19
+#define QLA82XX_HW_I2C1_CRB_AGT_ADR	0x29
+
+#define QLA82XX_HW_SN_CRB_AGT_ADR	0x10
+#define QLA82XX_HW_I2Q_CRB_AGT_ADR	0x20
+#define QLA82XX_HW_LPC_CRB_AGT_ADR	0x22
+#define QLA82XX_HW_ROMUSB_CRB_AGT_ADR   0x21
+#define QLA82XX_HW_QM_CRB_AGT_ADR	0x66
+#define QLA82XX_HW_SQG0_CRB_AGT_ADR	0x60
+#define QLA82XX_HW_SQG1_CRB_AGT_ADR	0x61
+#define QLA82XX_HW_SQG2_CRB_AGT_ADR	0x62
+#define QLA82XX_HW_SQG3_CRB_AGT_ADR	0x63
+#define QLA82XX_HW_RPMX1_CRB_AGT_ADR    0x09
+#define QLA82XX_HW_RPMX5_CRB_AGT_ADR    0x0d
+#define QLA82XX_HW_RPMX6_CRB_AGT_ADR    0x0e
+#define QLA82XX_HW_RPMX8_CRB_AGT_ADR    0x11
+
+/*  Hub 3 */
+#define QLA82XX_HW_PH_CRB_AGT_ADR	0x1A
+#define QLA82XX_HW_SRE_CRB_AGT_ADR	0x50
+#define QLA82XX_HW_EG_CRB_AGT_ADR	0x51
+#define QLA82XX_HW_RPMX0_CRB_AGT_ADR	0x08
+
+/*  Hub 4 */
+#define QLA82XX_HW_PEGN0_CRB_AGT_ADR	0x40
+#define QLA82XX_HW_PEGN1_CRB_AGT_ADR	0x41
+#define QLA82XX_HW_PEGN2_CRB_AGT_ADR	0x42
+#define QLA82XX_HW_PEGN3_CRB_AGT_ADR	0x43
+#define QLA82XX_HW_PEGNI_CRB_AGT_ADR	0x44
+#define QLA82XX_HW_PEGND_CRB_AGT_ADR	0x45
+#define QLA82XX_HW_PEGNC_CRB_AGT_ADR	0x46
+#define QLA82XX_HW_PEGR0_CRB_AGT_ADR	0x47
+#define QLA82XX_HW_PEGR1_CRB_AGT_ADR	0x48
+#define QLA82XX_HW_PEGR2_CRB_AGT_ADR	0x49
+#define QLA82XX_HW_PEGR3_CRB_AGT_ADR	0x4a
+#define QLA82XX_HW_PEGN4_CRB_AGT_ADR	0x4b
+
+/*  Hub 5 */
+#define QLA82XX_HW_PEGS0_CRB_AGT_ADR	0x40
+#define QLA82XX_HW_PEGS1_CRB_AGT_ADR	0x41
+#define QLA82XX_HW_PEGS2_CRB_AGT_ADR	0x42
+#define QLA82XX_HW_PEGS3_CRB_AGT_ADR	0x43
+
+#define QLA82XX_HW_PEGSI_CRB_AGT_ADR	0x44
+#define QLA82XX_HW_PEGSD_CRB_AGT_ADR	0x45
+#define QLA82XX_HW_PEGSC_CRB_AGT_ADR	0x46
+
+/*  Hub 6 */
+#define QLA82XX_HW_CAS0_CRB_AGT_ADR	0x46
+#define QLA82XX_HW_CAS1_CRB_AGT_ADR	0x47
+#define QLA82XX_HW_CAS2_CRB_AGT_ADR	0x48
+#define QLA82XX_HW_CAS3_CRB_AGT_ADR	0x49
+#define QLA82XX_HW_NCM_CRB_AGT_ADR	0x16
+#define QLA82XX_HW_TMR_CRB_AGT_ADR	0x17
+#define QLA82XX_HW_XDMA_CRB_AGT_ADR	0x05
+#define QLA82XX_HW_OCM0_CRB_AGT_ADR	0x06
+#define QLA82XX_HW_OCM1_CRB_AGT_ADR	0x07
+
+/*  This field defines PCI/X adr [25:20] of agents on the CRB */
+/*  */
+#define QLA82XX_HW_PX_MAP_CRB_PH	0
+#define QLA82XX_HW_PX_MAP_CRB_PS	1
+#define QLA82XX_HW_PX_MAP_CRB_MN	2
+#define QLA82XX_HW_PX_MAP_CRB_MS	3
+#define QLA82XX_HW_PX_MAP_CRB_SRE	5
+#define QLA82XX_HW_PX_MAP_CRB_NIU	6
+#define QLA82XX_HW_PX_MAP_CRB_QMN	7
+#define QLA82XX_HW_PX_MAP_CRB_SQN0	8
+#define QLA82XX_HW_PX_MAP_CRB_SQN1	9
+#define QLA82XX_HW_PX_MAP_CRB_SQN2	10
+#define QLA82XX_HW_PX_MAP_CRB_SQN3	11
+#define QLA82XX_HW_PX_MAP_CRB_QMS	12
+#define QLA82XX_HW_PX_MAP_CRB_SQS0	13
+#define QLA82XX_HW_PX_MAP_CRB_SQS1	14
+#define QLA82XX_HW_PX_MAP_CRB_SQS2	15
+#define QLA82XX_HW_PX_MAP_CRB_SQS3	16
+#define QLA82XX_HW_PX_MAP_CRB_PGN0	17
+#define QLA82XX_HW_PX_MAP_CRB_PGN1	18
+#define QLA82XX_HW_PX_MAP_CRB_PGN2	19
+#define QLA82XX_HW_PX_MAP_CRB_PGN3	20
+#define QLA82XX_HW_PX_MAP_CRB_PGN4	QLA82XX_HW_PX_MAP_CRB_SQS2
+#define QLA82XX_HW_PX_MAP_CRB_PGND	21
+#define QLA82XX_HW_PX_MAP_CRB_PGNI	22
+#define QLA82XX_HW_PX_MAP_CRB_PGS0	23
+#define QLA82XX_HW_PX_MAP_CRB_PGS1	24
+#define QLA82XX_HW_PX_MAP_CRB_PGS2	25
+#define QLA82XX_HW_PX_MAP_CRB_PGS3	26
+#define QLA82XX_HW_PX_MAP_CRB_PGSD	27
+#define QLA82XX_HW_PX_MAP_CRB_PGSI	28
+#define QLA82XX_HW_PX_MAP_CRB_SN	29
+#define QLA82XX_HW_PX_MAP_CRB_EG	31
+#define QLA82XX_HW_PX_MAP_CRB_PH2	32
+#define QLA82XX_HW_PX_MAP_CRB_PS2	33
+#define QLA82XX_HW_PX_MAP_CRB_CAM	34
+#define QLA82XX_HW_PX_MAP_CRB_CAS0	35
+#define QLA82XX_HW_PX_MAP_CRB_CAS1	36
+#define QLA82XX_HW_PX_MAP_CRB_CAS2	37
+#define QLA82XX_HW_PX_MAP_CRB_C2C0	38
+#define QLA82XX_HW_PX_MAP_CRB_C2C1	39
+#define QLA82XX_HW_PX_MAP_CRB_TIMR	40
+#define QLA82XX_HW_PX_MAP_CRB_RPMX1	42
+#define QLA82XX_HW_PX_MAP_CRB_RPMX2	43
+#define QLA82XX_HW_PX_MAP_CRB_RPMX3	44
+#define QLA82XX_HW_PX_MAP_CRB_RPMX4	45
+#define QLA82XX_HW_PX_MAP_CRB_RPMX5	46
+#define QLA82XX_HW_PX_MAP_CRB_RPMX6	47
+#define QLA82XX_HW_PX_MAP_CRB_RPMX7	48
+#define QLA82XX_HW_PX_MAP_CRB_XDMA	49
+#define QLA82XX_HW_PX_MAP_CRB_I2Q	50
+#define QLA82XX_HW_PX_MAP_CRB_ROMUSB    51
+#define QLA82XX_HW_PX_MAP_CRB_CAS3	52
+#define QLA82XX_HW_PX_MAP_CRB_RPMX0	53
+#define QLA82XX_HW_PX_MAP_CRB_RPMX8	54
+#define QLA82XX_HW_PX_MAP_CRB_RPMX9	55
+#define QLA82XX_HW_PX_MAP_CRB_OCM0	56
+#define QLA82XX_HW_PX_MAP_CRB_OCM1	57
+#define QLA82XX_HW_PX_MAP_CRB_SMB	58
+#define QLA82XX_HW_PX_MAP_CRB_I2C0	59
+#define QLA82XX_HW_PX_MAP_CRB_I2C1	60
+#define QLA82XX_HW_PX_MAP_CRB_LPC	61
+#define QLA82XX_HW_PX_MAP_CRB_PGNC	62
+#define QLA82XX_HW_PX_MAP_CRB_PGR0	63
+#define QLA82XX_HW_PX_MAP_CRB_PGR1	4
+#define QLA82XX_HW_PX_MAP_CRB_PGR2	30
+#define QLA82XX_HW_PX_MAP_CRB_PGR3	41
+
+/*  This field defines CRB adr [31:20] of the agents */
+/*  */
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_MN	((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \
+					QLA82XX_HW_MN_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PH	((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \
+					QLA82XX_HW_PH_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_MS	((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \
+					QLA82XX_HW_MS_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PS	((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					QLA82XX_HW_PS_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SS	((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					QLA82XX_HW_SS_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_RPMX3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMS	    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_QMS_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS0     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_SQGS0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS1     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_SQGS1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS2     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_SQGS2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS3     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_SQGS3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C0     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_C2C0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C1     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_C2C1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_RPMX2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_RPMX4_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_RPMX7_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_RPMX9_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SMB	    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_SMB_CRB_AGT_ADR)
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_NIU      ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_NIU_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0     ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_I2C0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1     ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_I2C1_CRB_AGT_ADR)
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SRE      ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_SRE_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_EG       ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_EG_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_RPMX0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMN      ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_QM_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_SQG0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_SQG1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_SQG2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_SQG3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_RPMX1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_RPMX5_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_RPMX6_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_RPMX8_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS0     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_CAS0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS1     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_CAS1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS2     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_CAS2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS3     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_CAS3_CRB_AGT_ADR)
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGNI_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGND     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGND_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGN0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGN1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGN2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGN3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGN4_CRB_AGT_ADR)
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGNC_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR0     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGR0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR1     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGR1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR2     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGR2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR3     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGR3_CRB_AGT_ADR)
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGSI_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSD     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGSD_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGS0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGS1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGS2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGS3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSC     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_PEGSC_CRB_AGT_ADR)
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAM      ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_NCM_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_TMR_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_XDMA_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SN       ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_SN_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q      ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_I2Q_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB   ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_ROMUSB_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_OCM0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM1     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_OCM1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_LPC      ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+					    QLA82XX_HW_LPC_CRB_AGT_ADR)
+
+#define ROMUSB_GLB	(QLA82XX_CRB_ROMUSB + 0x00000)
+#define QLA82XX_ROMUSB_GLB_PEGTUNE_DONE		(ROMUSB_GLB + 0x005c)
+#define QLA82XX_ROMUSB_GLB_STATUS		(ROMUSB_GLB + 0x0004)
+#define QLA82XX_ROMUSB_GLB_SW_RESET		(ROMUSB_GLB + 0x0008)
+#define QLA82XX_ROMUSB_ROM_ADDRESS		(ROMUSB_ROM + 0x0008)
+#define QLA82XX_ROMUSB_ROM_WDATA		(ROMUSB_ROM + 0x000c)
+#define QLA82XX_ROMUSB_ROM_ABYTE_CNT		(ROMUSB_ROM + 0x0010)
+#define QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT	(ROMUSB_ROM + 0x0014)
+#define QLA82XX_ROMUSB_ROM_RDATA		(ROMUSB_ROM + 0x0018)
+
+#define ROMUSB_ROM	(QLA82XX_CRB_ROMUSB + 0x10000)
+#define QLA82XX_ROMUSB_ROM_INSTR_OPCODE	(ROMUSB_ROM + 0x0004)
+#define QLA82XX_ROMUSB_GLB_CAS_RST	(ROMUSB_GLB + 0x0038)
+
+/* Lock IDs for ROM lock */
+#define ROM_LOCK_DRIVER		0x0d417340
+
+#define QLA82XX_PCI_CRB_WINDOWSIZE	0x00100000    /* all are 1MB windows */
+#define QLA82XX_PCI_CRB_WINDOW(A)	(QLA82XX_PCI_CRBSPACE + \
+					(A)*QLA82XX_PCI_CRB_WINDOWSIZE)
+
+#define QLA82XX_CRB_C2C_0 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C0)
+#define QLA82XX_CRB_C2C_1 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C1)
+#define QLA82XX_CRB_C2C_2 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C2)
+#define QLA82XX_CRB_CAM	\
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAM)
+#define QLA82XX_CRB_CASPER \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS)
+#define QLA82XX_CRB_CASPER_0 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS0)
+#define QLA82XX_CRB_CASPER_1 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS1)
+#define QLA82XX_CRB_CASPER_2 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS2)
+#define QLA82XX_CRB_DDR_MD \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MS)
+#define QLA82XX_CRB_DDR_NET \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MN)
+#define QLA82XX_CRB_EPG \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_EG)
+#define QLA82XX_CRB_I2Q \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2Q)
+#define QLA82XX_CRB_NIU	\
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_NIU)
+/* HACK upon HACK upon HACK (for PCIE builds) */
+#define QLA82XX_CRB_PCIX_HOST \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH)
+#define QLA82XX_CRB_PCIX_HOST2 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH2)
+#define QLA82XX_CRB_PCIX_MD \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS)
+#define QLA82XX_CRB_PCIE	QLA82XX_CRB_PCIX_MD
+/* window 1 pcie slot */
+#define QLA82XX_CRB_PCIE2 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS2)
+
+#define QLA82XX_CRB_PEG_MD_0 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS0)
+#define QLA82XX_CRB_PEG_MD_1 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS1)
+#define QLA82XX_CRB_PEG_MD_2 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS2)
+#define QLA82XX_CRB_PEG_MD_3 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3)
+#define QLA82XX_CRB_PEG_MD_3 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3)
+#define QLA82XX_CRB_PEG_MD_D \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSD)
+#define QLA82XX_CRB_PEG_MD_I \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSI)
+#define QLA82XX_CRB_PEG_NET_0 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN0)
+#define QLA82XX_CRB_PEG_NET_1 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN1)
+#define QLA82XX_CRB_PEG_NET_2 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN2)
+#define QLA82XX_CRB_PEG_NET_3 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN3)
+#define QLA82XX_CRB_PEG_NET_4 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN4)
+#define QLA82XX_CRB_PEG_NET_D \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGND)
+#define QLA82XX_CRB_PEG_NET_I \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGNI)
+#define QLA82XX_CRB_PQM_MD \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMS)
+#define QLA82XX_CRB_PQM_NET \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMN)
+#define QLA82XX_CRB_QDR_MD \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SS)
+#define QLA82XX_CRB_QDR_NET \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SN)
+#define QLA82XX_CRB_ROMUSB \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_ROMUSB)
+#define QLA82XX_CRB_RPMX_0 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX0)
+#define QLA82XX_CRB_RPMX_1 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX1)
+#define QLA82XX_CRB_RPMX_2 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX2)
+#define QLA82XX_CRB_RPMX_3 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX3)
+#define QLA82XX_CRB_RPMX_4 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX4)
+#define QLA82XX_CRB_RPMX_5 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX5)
+#define QLA82XX_CRB_RPMX_6 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX6)
+#define QLA82XX_CRB_RPMX_7 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX7)
+#define QLA82XX_CRB_SQM_MD_0 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS0)
+#define QLA82XX_CRB_SQM_MD_1 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS1)
+#define QLA82XX_CRB_SQM_MD_2 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS2)
+#define QLA82XX_CRB_SQM_MD_3 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS3)
+#define QLA82XX_CRB_SQM_NET_0 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN0)
+#define QLA82XX_CRB_SQM_NET_1 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN1)
+#define QLA82XX_CRB_SQM_NET_2 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN2)
+#define QLA82XX_CRB_SQM_NET_3 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN3)
+#define QLA82XX_CRB_SRE \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SRE)
+#define QLA82XX_CRB_TIMER \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_TIMR)
+#define QLA82XX_CRB_XDMA \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_XDMA)
+#define QLA82XX_CRB_I2C0 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C0)
+#define QLA82XX_CRB_I2C1 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C1)
+#define QLA82XX_CRB_OCM0 \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_OCM0)
+#define QLA82XX_CRB_SMB \
+	QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SMB)
+
+#define QLA82XX_CRB_MAX		QLA82XX_PCI_CRB_WINDOW(64)
+
+/*
+ * ====================== BASE ADDRESSES ON-CHIP ======================
+ * Base addresses of major components on-chip.
+ * ====================== BASE ADDRESSES ON-CHIP ======================
+ */
+#define QLA82XX_ADDR_DDR_NET		(0x0000000000000000ULL)
+#define QLA82XX_ADDR_DDR_NET_MAX	(0x000000000fffffffULL)
+
+/* Imbus address bit used to indicate a host address. This bit is
+ * eliminated by the pcie bar and bar select before presentation
+ * over pcie. */
+/* host memory via IMBUS */
+#define QLA82XX_P2_ADDR_PCIE	(0x0000000800000000ULL)
+#define QLA82XX_P3_ADDR_PCIE	(0x0000008000000000ULL)
+#define QLA82XX_ADDR_PCIE_MAX	(0x0000000FFFFFFFFFULL)
+#define QLA82XX_ADDR_OCM0	(0x0000000200000000ULL)
+#define QLA82XX_ADDR_OCM0_MAX	(0x00000002000fffffULL)
+#define QLA82XX_ADDR_OCM1	(0x0000000200400000ULL)
+#define QLA82XX_ADDR_OCM1_MAX	(0x00000002004fffffULL)
+#define QLA82XX_ADDR_QDR_NET	(0x0000000300000000ULL)
+
+#define QLA82XX_P2_ADDR_QDR_NET_MAX	(0x00000003001fffffULL)
+#define QLA82XX_P3_ADDR_QDR_NET_MAX	(0x0000000303ffffffULL)
+
+#define QLA82XX_PCI_CRBSPACE		(unsigned long)0x06000000
+#define QLA82XX_PCI_DIRECT_CRB		(unsigned long)0x04400000
+#define QLA82XX_PCI_CAMQM		(unsigned long)0x04800000
+#define QLA82XX_PCI_CAMQM_MAX		(unsigned long)0x04ffffff
+#define QLA82XX_PCI_DDR_NET		(unsigned long)0x00000000
+#define QLA82XX_PCI_QDR_NET		(unsigned long)0x04000000
+#define QLA82XX_PCI_QDR_NET_MAX		(unsigned long)0x043fffff
+
+/*
+ *   Register offsets for MN
+ */
+#define MIU_CONTROL			(0x000)
+#define MIU_TAG				(0x004)
+#define MIU_TEST_AGT_CTRL		(0x090)
+#define MIU_TEST_AGT_ADDR_LO		(0x094)
+#define MIU_TEST_AGT_ADDR_HI		(0x098)
+#define MIU_TEST_AGT_WRDATA_LO		(0x0a0)
+#define MIU_TEST_AGT_WRDATA_HI		(0x0a4)
+#define MIU_TEST_AGT_WRDATA(i)		(0x0a0+(4*(i)))
+#define MIU_TEST_AGT_RDDATA_LO		(0x0a8)
+#define MIU_TEST_AGT_RDDATA_HI		(0x0ac)
+#define MIU_TEST_AGT_RDDATA(i)		(0x0a8+(4*(i)))
+#define MIU_TEST_AGT_ADDR_MASK		0xfffffff8
+#define MIU_TEST_AGT_UPPER_ADDR(off)	(0)
+
+/* MIU_TEST_AGT_CTRL flags. work for SIU as well */
+#define MIU_TA_CTL_START	1
+#define MIU_TA_CTL_ENABLE	2
+#define MIU_TA_CTL_WRITE	4
+#define MIU_TA_CTL_BUSY		8
+
+/*CAM RAM */
+# define QLA82XX_CAM_RAM_BASE	(QLA82XX_CRB_CAM + 0x02000)
+# define QLA82XX_CAM_RAM(reg)	(QLA82XX_CAM_RAM_BASE + (reg))
+
+#define QLA82XX_PEG_TUNE_MN_SPD_ZEROED	0x80000000
+#define QLA82XX_BOOT_LOADER_MN_ISSUE	0xff00ffff
+#define QLA82XX_PORT_MODE_ADDR		(QLA82XX_CAM_RAM(0x24))
+#define QLA82XX_PEG_HALT_STATUS1	(QLA82XX_CAM_RAM(0xa8))
+#define QLA82XX_PEG_HALT_STATUS2	(QLA82XX_CAM_RAM(0xac))
+#define QLA82XX_PEG_ALIVE_COUNTER	(QLA82XX_CAM_RAM(0xb0))
+
+#define HALT_STATUS_UNRECOVERABLE	0x80000000
+#define HALT_STATUS_RECOVERABLE		0x40000000
+
+
+#define QLA82XX_ROM_LOCK_ID		(QLA82XX_CAM_RAM(0x100))
+#define QLA82XX_CRB_WIN_LOCK_ID		(QLA82XX_CAM_RAM(0x124))
+#define QLA82XX_FW_VERSION_MAJOR	(QLA82XX_CAM_RAM(0x150))
+#define QLA82XX_FW_VERSION_MINOR	(QLA82XX_CAM_RAM(0x154))
+#define QLA82XX_FW_VERSION_SUB		(QLA82XX_CAM_RAM(0x158))
+#define QLA82XX_PCIE_REG(reg)		(QLA82XX_CRB_PCIE + (reg))
+
+/* Driver Coexistence Defines */
+#define QLA82XX_CRB_DRV_ACTIVE		(QLA82XX_CAM_RAM(0x138))
+#define QLA82XX_CRB_DEV_STATE		(QLA82XX_CAM_RAM(0x140))
+#define QLA82XX_CRB_DEV_PART_INFO	(QLA82XX_CAM_RAM(0x14c))
+#define QLA82XX_CRB_DRV_IDC_VERSION	(QLA82XX_CAM_RAM(0x174))
+#define QLA82XX_CRB_DRV_STATE		(QLA82XX_CAM_RAM(0x144))
+#define QLA82XX_CRB_DRV_SCRATCH		(QLA82XX_CAM_RAM(0x148))
+#define QLA82XX_CRB_DEV_PART_INFO	(QLA82XX_CAM_RAM(0x14c))
+
+/* Every driver should use these Device State */
+#define QLA82XX_DEV_COLD		1
+#define QLA82XX_DEV_INITIALIZING	2
+#define QLA82XX_DEV_READY		3
+#define QLA82XX_DEV_NEED_RESET		4
+#define QLA82XX_DEV_NEED_QUIESCENT	5
+#define QLA82XX_DEV_FAILED		6
+#define QLA82XX_DEV_QUIESCENT		7
+#define MAX_STATES			8 /* Increment if new state added */
+
+#define QLA82XX_IDC_VERSION		0x1
+#define ROM_DEV_INIT_TIMEOUT		30
+#define ROM_DRV_RESET_ACK_TIMEOUT	10
+
+#define PCIE_SETUP_FUNCTION		(0x12040)
+#define PCIE_SETUP_FUNCTION2		(0x12048)
+
+#define QLA82XX_PCIX_PS_REG(reg)	(QLA82XX_CRB_PCIX_MD + (reg))
+#define QLA82XX_PCIX_PS2_REG(reg)	(QLA82XX_CRB_PCIE2 + (reg))
+
+#define PCIE_SEM2_LOCK		(0x1c010)  /* Flash lock   */
+#define PCIE_SEM2_UNLOCK	(0x1c014)  /* Flash unlock */
+#define PCIE_SEM5_LOCK		(0x1c028)  /* Coexistence lock   */
+#define PCIE_SEM5_UNLOCK	(0x1c02c)  /* Coexistence unlock */
+#define PCIE_SEM7_LOCK		(0x1c038)  /* crb win lock */
+#define PCIE_SEM7_UNLOCK	(0x1c03c)  /* crbwin unlock*/
+
+/*
+ * The PCI VendorID and DeviceID for our board.
+ */
+#define QLA82XX_MSIX_TBL_SPACE		8192
+#define QLA82XX_PCI_REG_MSIX_TBL	0x44
+#define QLA82XX_PCI_MSIX_CONTROL	0x40
+
+struct crb_128M_2M_sub_block_map {
+	unsigned valid;
+	unsigned start_128M;
+	unsigned end_128M;
+	unsigned start_2M;
+};
+
+struct crb_128M_2M_block_map {
+	struct crb_128M_2M_sub_block_map sub_block[16];
+};
+
+struct crb_addr_pair {
+	long addr;
+	long data;
+};
+
+#define ADDR_ERROR	((unsigned long) 0xffffffff)
+#define MAX_CTL_CHECK	1000
+
+/***************************************************************************
+ *		PCI related defines.
+ **************************************************************************/
+
+/*
+ * Interrupt related defines.
+ */
+#define PCIX_TARGET_STATUS	(0x10118)
+#define PCIX_TARGET_STATUS_F1	(0x10160)
+#define PCIX_TARGET_STATUS_F2	(0x10164)
+#define PCIX_TARGET_STATUS_F3	(0x10168)
+#define PCIX_TARGET_STATUS_F4	(0x10360)
+#define PCIX_TARGET_STATUS_F5	(0x10364)
+#define PCIX_TARGET_STATUS_F6	(0x10368)
+#define PCIX_TARGET_STATUS_F7	(0x1036c)
+
+#define PCIX_TARGET_MASK	(0x10128)
+#define PCIX_TARGET_MASK_F1	(0x10170)
+#define PCIX_TARGET_MASK_F2	(0x10174)
+#define PCIX_TARGET_MASK_F3	(0x10178)
+#define PCIX_TARGET_MASK_F4	(0x10370)
+#define PCIX_TARGET_MASK_F5	(0x10374)
+#define PCIX_TARGET_MASK_F6	(0x10378)
+#define PCIX_TARGET_MASK_F7	(0x1037c)
+
+/*
+ * Message Signaled Interrupts
+ */
+#define PCIX_MSI_F0		(0x13000)
+#define PCIX_MSI_F1		(0x13004)
+#define PCIX_MSI_F2		(0x13008)
+#define PCIX_MSI_F3		(0x1300c)
+#define PCIX_MSI_F4		(0x13010)
+#define PCIX_MSI_F5		(0x13014)
+#define PCIX_MSI_F6		(0x13018)
+#define PCIX_MSI_F7		(0x1301c)
+#define PCIX_MSI_F(FUNC)	(0x13000 + ((FUNC) * 4))
+
+/*
+ *
+ */
+#define PCIX_INT_VECTOR		(0x10100)
+#define PCIX_INT_MASK		(0x10104)
+
+/*
+ * Interrupt state machine and other bits.
+ */
+#define PCIE_MISCCFG_RC		(0x1206c)
+
+
+#define ISR_INT_TARGET_STATUS \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS))
+#define ISR_INT_TARGET_STATUS_F1 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F1))
+#define ISR_INT_TARGET_STATUS_F2 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F2))
+#define ISR_INT_TARGET_STATUS_F3 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F3))
+#define ISR_INT_TARGET_STATUS_F4 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F4))
+#define ISR_INT_TARGET_STATUS_F5 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F5))
+#define ISR_INT_TARGET_STATUS_F6 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F6))
+#define ISR_INT_TARGET_STATUS_F7 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F7))
+
+#define ISR_INT_TARGET_MASK \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK))
+#define ISR_INT_TARGET_MASK_F1 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F1))
+#define ISR_INT_TARGET_MASK_F2 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F2))
+#define ISR_INT_TARGET_MASK_F3 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F3))
+#define ISR_INT_TARGET_MASK_F4 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F4))
+#define ISR_INT_TARGET_MASK_F5 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F5))
+#define ISR_INT_TARGET_MASK_F6 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F6))
+#define ISR_INT_TARGET_MASK_F7 \
+	(QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F7))
+
+#define ISR_INT_VECTOR			(QLA82XX_PCIX_PS_REG(PCIX_INT_VECTOR))
+#define ISR_INT_MASK			(QLA82XX_PCIX_PS_REG(PCIX_INT_MASK))
+#define ISR_INT_STATE_REG		(QLA82XX_PCIX_PS_REG(PCIE_MISCCFG_RC))
+
+#define	ISR_MSI_INT_TRIGGER(FUNC)	(QLA82XX_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
+
+
+#define	ISR_IS_LEGACY_INTR_IDLE(VAL)		(((VAL) & 0x300) == 0)
+#define	ISR_IS_LEGACY_INTR_TRIGGERED(VAL)	(((VAL) & 0x300) == 0x200)
+
+/*
+ * PCI Interrupt Vector Values.
+ */
+#define	PCIX_INT_VECTOR_BIT_F0	0x0080
+#define	PCIX_INT_VECTOR_BIT_F1	0x0100
+#define	PCIX_INT_VECTOR_BIT_F2	0x0200
+#define	PCIX_INT_VECTOR_BIT_F3	0x0400
+#define	PCIX_INT_VECTOR_BIT_F4	0x0800
+#define	PCIX_INT_VECTOR_BIT_F5	0x1000
+#define	PCIX_INT_VECTOR_BIT_F6	0x2000
+#define	PCIX_INT_VECTOR_BIT_F7	0x4000
+
+/* struct qla4_8xxx_legacy_intr_set defined in ql4_def.h */
+
+#define QLA82XX_LEGACY_INTR_CONFIG                                      \
+{                                                                       \
+	{                                                               \
+		.int_vec_bit    =	PCIX_INT_VECTOR_BIT_F0,         \
+		.tgt_status_reg =	ISR_INT_TARGET_STATUS,          \
+		.tgt_mask_reg   =	ISR_INT_TARGET_MASK,            \
+		.pci_int_reg    =	ISR_MSI_INT_TRIGGER(0) },       \
+									\
+	{								\
+		.int_vec_bit    =	PCIX_INT_VECTOR_BIT_F1,         \
+		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F1,       \
+		.tgt_mask_reg   =	ISR_INT_TARGET_MASK_F1,         \
+		.pci_int_reg    =	ISR_MSI_INT_TRIGGER(1) },       \
+									\
+	{								\
+		.int_vec_bit    =	PCIX_INT_VECTOR_BIT_F2,         \
+		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F2,       \
+		.tgt_mask_reg   =	ISR_INT_TARGET_MASK_F2,         \
+		.pci_int_reg    =	ISR_MSI_INT_TRIGGER(2) },       \
+									\
+	{								\
+		.int_vec_bit    =	PCIX_INT_VECTOR_BIT_F3,         \
+		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F3,       \
+		.tgt_mask_reg   =	ISR_INT_TARGET_MASK_F3,         \
+		.pci_int_reg    =	ISR_MSI_INT_TRIGGER(3) },       \
+									\
+	{								\
+		.int_vec_bit    =	PCIX_INT_VECTOR_BIT_F4,         \
+		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F4,       \
+		.tgt_mask_reg   =	ISR_INT_TARGET_MASK_F4,         \
+		.pci_int_reg    =	ISR_MSI_INT_TRIGGER(4) },       \
+									\
+	{								\
+		.int_vec_bit    =	PCIX_INT_VECTOR_BIT_F5,         \
+		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F5,       \
+		.tgt_mask_reg   =	ISR_INT_TARGET_MASK_F5,         \
+		.pci_int_reg    =	ISR_MSI_INT_TRIGGER(5) },       \
+									\
+	{								\
+		.int_vec_bit    =	PCIX_INT_VECTOR_BIT_F6,         \
+		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F6,       \
+		.tgt_mask_reg   =	ISR_INT_TARGET_MASK_F6,         \
+		.pci_int_reg    =	ISR_MSI_INT_TRIGGER(6) },       \
+									\
+	{								\
+		.int_vec_bit    =	PCIX_INT_VECTOR_BIT_F7,         \
+		.tgt_status_reg =	ISR_INT_TARGET_STATUS_F7,       \
+		.tgt_mask_reg   =	ISR_INT_TARGET_MASK_F7,         \
+		.pci_int_reg    =	ISR_MSI_INT_TRIGGER(7) },       \
+}
+
+/* Magic number to let user know flash is programmed */
+#define	QLA82XX_BDINFO_MAGIC	0x12345678
+#define FW_SIZE_OFFSET		(0x3e840c)
+
+/* QLA82XX additions */
+#define MIU_TEST_AGT_WRDATA_UPPER_LO	(0x0b0)
+#define	MIU_TEST_AGT_WRDATA_UPPER_HI	(0x0b4)
+
+#endif
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 38b1d38..5529b2a 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -30,22 +30,29 @@
  * Module parameter information and variables
  */
 int ql4xdiscoverywait = 60;
-module_param(ql4xdiscoverywait, int, S_IRUGO | S_IRUSR);
+module_param(ql4xdiscoverywait, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ql4xdiscoverywait, "Discovery wait time");
+
 int ql4xdontresethba = 0;
-module_param(ql4xdontresethba, int, S_IRUGO | S_IRUSR);
+module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ql4xdontresethba,
-		 "Dont reset the HBA when the driver gets 0x8002 AEN "
-		 " default it will reset hba :0"
-		 " set to 1 to avoid resetting HBA");
+		"Don't reset the HBA for driver recovery \n"
+		" 0 - It will reset HBA (Default)\n"
+		" 1 - It will NOT reset HBA");
 
 int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */
-module_param(ql4xextended_error_logging, int, S_IRUGO | S_IRUSR);
+module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ql4xextended_error_logging,
 		 "Option to enable extended error logging, "
 		 "Default is 0 - no logging, 1 - debug logging");
 
-int ql4_mod_unload = 0;
+int ql4xenablemsix = 1;
+module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql4xenablemsix,
+		"Set to enable MSI or MSI-X interrupt mechanism.\n"
+		" 0 = enable INTx interrupt mechanism.\n"
+		" 1 = enable MSI-X interrupt mechanism (Default).\n"
+		" 2 = enable MSI interrupt mechanism.");
 
 #define QL4_DEF_QDEPTH 32
 
@@ -83,6 +90,9 @@
 static void qla4xxx_slave_destroy(struct scsi_device *sdev);
 static void qla4xxx_scan_start(struct Scsi_Host *shost);
 
+static struct qla4_8xxx_legacy_intr_set legacy_intr[] =
+    QLA82XX_LEGACY_INTR_CONFIG;
+
 static struct scsi_host_template qla4xxx_driver_template = {
 	.module			= THIS_MODULE,
 	.name			= DRIVER_NAME,
@@ -116,7 +126,8 @@
 	.caps			= CAP_FW_DB | CAP_SENDTARGETS_OFFLOAD |
 				  CAP_DATA_PATH_OFFLOAD,
 	.param_mask		= ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS |
-				  ISCSI_TARGET_NAME | ISCSI_TPGT,
+				  ISCSI_TARGET_NAME | ISCSI_TPGT |
+				  ISCSI_TARGET_ALIAS,
 	.host_param_mask	= ISCSI_HOST_HWADDRESS |
 				  ISCSI_HOST_IPADDRESS |
 				  ISCSI_HOST_INITIATOR_NAME,
@@ -152,15 +163,12 @@
 	if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
 		atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
 
-		DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count "
+		DEBUG2(printk("scsi%ld: %s: ddb [%d] port down retry count "
 			      "of (%d) secs exhausted, marking device DEAD.\n",
 			      ha->host_no, __func__, ddb_entry->fw_ddb_index,
 			      ha->port_down_retry_count));
 
-		DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc "
-			      "flags = 0x%lx\n",
-			      ha->host_no, __func__, ha->dpc_flags));
-		queue_work(ha->dpc_thread, &ha->dpc_work);
+		qla4xxx_wake_dpc(ha);
 	}
 }
 
@@ -203,6 +211,10 @@
 	case ISCSI_PARAM_TPGT:
 		len = sprintf(buf, "%u\n", ddb_entry->tpgt);
 		break;
+	case ISCSI_PARAM_TARGET_ALIAS:
+		len = snprintf(buf, PAGE_SIZE - 1, "%s\n",
+		    ddb_entry->iscsi_alias);
+		break;
 	default:
 		return -ENOSYS;
 	}
@@ -362,19 +374,37 @@
  * @ha: Pointer to host adapter structure.
  * @ddb_entry: Pointer to device database entry
  *
- * This routine marks a device missing and resets the relogin retry count.
+ * This routine marks a device missing and close connection.
  **/
 void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
 				 struct ddb_entry *ddb_entry)
 {
-	atomic_set(&ddb_entry->state, DDB_STATE_MISSING);
-	DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n",
-		      ha->host_no, ddb_entry->bus, ddb_entry->target,
-		      ddb_entry->fw_ddb_index));
+	if ((atomic_read(&ddb_entry->state) != DDB_STATE_DEAD)) {
+		atomic_set(&ddb_entry->state, DDB_STATE_MISSING);
+		DEBUG2(printk("scsi%ld: ddb [%d] marked MISSING\n",
+		    ha->host_no, ddb_entry->fw_ddb_index));
+	} else
+		DEBUG2(printk("scsi%ld: ddb [%d] DEAD\n", ha->host_no,
+		    ddb_entry->fw_ddb_index))
+
 	iscsi_block_session(ddb_entry->sess);
 	iscsi_conn_error_event(ddb_entry->conn, ISCSI_ERR_CONN_FAILED);
 }
 
+/**
+ * qla4xxx_mark_all_devices_missing - mark all devices as missing.
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine marks a device missing and resets the relogin retry count.
+ **/
+void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha)
+{
+	struct ddb_entry *ddb_entry, *ddbtemp;
+	list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) {
+		qla4xxx_mark_device_missing(ha, ddb_entry);
+	}
+}
+
 static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
 				       struct ddb_entry *ddb_entry,
 				       struct scsi_cmnd *cmd,
@@ -463,7 +493,13 @@
 		return SCSI_MLQUEUE_TARGET_BUSY;
 	}
 
-	if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags))
+	if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
+	    test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
+	    test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
+	    test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
+	    test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
+	    !test_bit(AF_ONLINE, &ha->flags) ||
+	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))
 		goto qc_host_busy;
 
 	spin_unlock_irq(ha->host->host_lock);
@@ -524,7 +560,15 @@
 	ha->srb_mempool = NULL;
 
 	/* release io space registers  */
-	if (ha->reg)
+	if (is_qla8022(ha)) {
+		if (ha->nx_pcibase)
+			iounmap(
+			    (struct device_reg_82xx __iomem *)ha->nx_pcibase);
+
+		if (ha->nx_db_wr_ptr)
+			iounmap(
+			    (struct device_reg_82xx __iomem *)ha->nx_db_wr_ptr);
+	} else if (ha->reg)
 		iounmap(ha->reg);
 	pci_release_regions(ha->pdev);
 }
@@ -549,8 +593,8 @@
 	ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len,
 					&ha->queues_dma, GFP_KERNEL);
 	if (ha->queues == NULL) {
-		dev_warn(&ha->pdev->dev,
-			"Memory Allocation failed - queues.\n");
+		ql4_printk(KERN_WARNING, ha,
+		    "Memory Allocation failed - queues.\n");
 
 		goto mem_alloc_error_exit;
 	}
@@ -586,8 +630,8 @@
 	ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,
 					 mempool_free_slab, srb_cachep);
 	if (ha->srb_mempool == NULL) {
-		dev_warn(&ha->pdev->dev,
-			"Memory Allocation failed - SRB Pool.\n");
+		ql4_printk(KERN_WARNING, ha,
+		    "Memory Allocation failed - SRB Pool.\n");
 
 		goto mem_alloc_error_exit;
 	}
@@ -600,6 +644,74 @@
 }
 
 /**
+ * qla4_8xxx_check_fw_alive  - Check firmware health
+ * @ha: Pointer to host adapter structure.
+ *
+ * Context: Interrupt
+ **/
+static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
+{
+	uint32_t fw_heartbeat_counter, halt_status;
+
+	fw_heartbeat_counter = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
+
+	if (ha->fw_heartbeat_counter == fw_heartbeat_counter) {
+		ha->seconds_since_last_heartbeat++;
+		/* FW not alive after 2 seconds */
+		if (ha->seconds_since_last_heartbeat == 2) {
+			ha->seconds_since_last_heartbeat = 0;
+			halt_status = qla4_8xxx_rd_32(ha,
+			    QLA82XX_PEG_HALT_STATUS1);
+			/* Since we cannot change dev_state in interrupt
+			 * context, set appropriate DPC flag then wakeup
+			 * DPC */
+			if (halt_status & HALT_STATUS_UNRECOVERABLE)
+				set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
+			else {
+				printk("scsi%ld: %s: detect abort needed!\n",
+				    ha->host_no, __func__);
+				set_bit(DPC_RESET_HA, &ha->dpc_flags);
+			}
+			qla4xxx_wake_dpc(ha);
+		}
+	}
+	ha->fw_heartbeat_counter = fw_heartbeat_counter;
+}
+
+/**
+ * qla4_8xxx_watchdog - Poll dev state
+ * @ha: Pointer to host adapter structure.
+ *
+ * Context: Interrupt
+ **/
+void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
+{
+	uint32_t dev_state;
+
+	dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+
+	/* don't poll if reset is going on */
+	if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags)) {
+		if (dev_state == QLA82XX_DEV_NEED_RESET &&
+		    !test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+			printk("scsi%ld: %s: HW State: NEED RESET!\n",
+			    ha->host_no, __func__);
+			set_bit(DPC_RESET_HA, &ha->dpc_flags);
+			qla4xxx_wake_dpc(ha);
+		} else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
+		    !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
+			printk("scsi%ld: %s: HW State: NEED QUIES!\n",
+			    ha->host_no, __func__);
+			set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags);
+			qla4xxx_wake_dpc(ha);
+		} else  {
+			/* Check firmware health */
+			qla4_8xxx_check_fw_alive(ha);
+		}
+	}
+}
+
+/**
  * qla4xxx_timer - checks every second for work to do.
  * @ha: Pointer to host adapter structure.
  **/
@@ -608,6 +720,16 @@
 	struct ddb_entry *ddb_entry, *dtemp;
 	int start_dpc = 0;
 
+	if (test_bit(AF_HBA_GOING_AWAY, &ha->flags)) {
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s exited. HBA GOING AWAY\n",
+		    __func__));
+		return;
+	}
+
+	if (is_qla8022(ha)) {
+		qla4_8xxx_watchdog(ha);
+	}
+
 	/* Search for relogin's to time-out and port down retry. */
 	list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) {
 		/* Count down time between sending relogins */
@@ -624,7 +746,7 @@
 					set_bit(DPC_RELOGIN_DEVICE,
 						&ha->dpc_flags);
 					set_bit(DF_RELOGIN, &ddb_entry->flags);
-					DEBUG2(printk("scsi%ld: %s: index [%d]"
+					DEBUG2(printk("scsi%ld: %s: ddb [%d]"
 						      " login device\n",
 						      ha->host_no, __func__,
 						      ddb_entry->fw_ddb_index));
@@ -647,7 +769,7 @@
 			    DDB_DS_SESSION_FAILED) {
 				/* Reset retry relogin timer */
 				atomic_inc(&ddb_entry->relogin_retry_count);
-				DEBUG2(printk("scsi%ld: index[%d] relogin"
+				DEBUG2(printk("scsi%ld: ddb [%d] relogin"
 					      " timed out-retrying"
 					      " relogin (%d)\n",
 					      ha->host_no,
@@ -656,7 +778,7 @@
 							  relogin_retry_count))
 					);
 				start_dpc++;
-				DEBUG(printk("scsi%ld:%d:%d: index [%d] "
+				DEBUG(printk("scsi%ld:%d:%d: ddb [%d] "
 					     "initate relogin after"
 					     " %d seconds\n",
 					     ha->host_no, ddb_entry->bus,
@@ -671,31 +793,35 @@
 		}
 	}
 
-	/* Check for heartbeat interval. */
-	if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&
-	    ha->heartbeat_interval != 0) {
-		ha->seconds_since_last_heartbeat++;
-		if (ha->seconds_since_last_heartbeat >
-		    ha->heartbeat_interval + 2)
-			set_bit(DPC_RESET_HA, &ha->dpc_flags);
+	if (!is_qla8022(ha)) {
+		/* Check for heartbeat interval. */
+		if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&
+		    ha->heartbeat_interval != 0) {
+			ha->seconds_since_last_heartbeat++;
+			if (ha->seconds_since_last_heartbeat >
+			    ha->heartbeat_interval + 2)
+				set_bit(DPC_RESET_HA, &ha->dpc_flags);
+		}
 	}
 
-
 	/* Wakeup the dpc routine for this adapter, if needed. */
 	if ((start_dpc ||
 	     test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
 	     test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) ||
 	     test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) ||
-	     test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
+	     test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
 	     test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
 	     test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
 	     test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) ||
+	     test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
+	     test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
 	     test_bit(DPC_AEN, &ha->dpc_flags)) &&
+	     !test_bit(AF_DPC_SCHEDULED, &ha->flags) &&
 	     ha->dpc_thread) {
 		DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
 			      " - dpc flags = 0x%lx\n",
 			      ha->host_no, __func__, ha->dpc_flags));
-		queue_work(ha->dpc_thread, &ha->dpc_work);
+		qla4xxx_wake_dpc(ha);
 	}
 
 	/* Reschedule timer thread to call us back in one second */
@@ -714,16 +840,15 @@
 static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
 {
 	uint32_t index = 0;
-	int stat = QLA_SUCCESS;
 	unsigned long flags;
 	struct scsi_cmnd *cmd;
-	int wait_cnt = WAIT_CMD_TOV;	/*
-					 * Initialized for 30 seconds as we
-					 * expect all commands to retuned
-					 * ASAP.
-					 */
 
-	while (wait_cnt) {
+	unsigned long wtime = jiffies + (WAIT_CMD_TOV * HZ);
+
+	DEBUG2(ql4_printk(KERN_INFO, ha, "Wait up to %d seconds for cmds to "
+	    "complete\n", WAIT_CMD_TOV));
+
+	while (!time_after_eq(jiffies, wtime)) {
 		spin_lock_irqsave(&ha->hardware_lock, flags);
 		/* Find a command that hasn't completed. */
 		for (index = 0; index < ha->host->can_queue; index++) {
@@ -734,31 +859,26 @@
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 		/* If No Commands are pending, wait is complete */
-		if (index == ha->host->can_queue) {
-			break;
-		}
+		if (index == ha->host->can_queue)
+			return QLA_SUCCESS;
 
-		/* If we timed out on waiting for commands to come back
-		 * return ERROR.
-		 */
-		wait_cnt--;
-		if (wait_cnt == 0)
-			stat = QLA_ERROR;
-		else {
-			msleep(1000);
-		}
-	}			/* End of While (wait_cnt) */
-
-	return stat;
+		msleep(1000);
+	}
+	/* If we timed out on waiting for commands to come back
+	 * return ERROR. */
+	return QLA_ERROR;
 }
 
-void qla4xxx_hw_reset(struct scsi_qla_host *ha)
+int qla4xxx_hw_reset(struct scsi_qla_host *ha)
 {
 	uint32_t ctrl_status;
 	unsigned long flags = 0;
 
 	DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__));
 
+	if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
+		return QLA_ERROR;
+
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
 	/*
@@ -774,6 +894,7 @@
 	readl(&ha->reg->ctrl_status);
 
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	return QLA_SUCCESS;
 }
 
 /**
@@ -872,15 +993,16 @@
 }
 
 /**
- * qla4xxx_flush_active_srbs - returns all outstanding i/o requests to O.S.
+ * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S.
  * @ha: Pointer to host adapter structure.
+ * @res: returned scsi status
  *
  * This routine is called just prior to a HARD RESET to return all
  * outstanding commands back to the Operating System.
  * Caller should make sure that the following locks are released
  * before this calling routine: Hardware lock, and io_request_lock.
  **/
-static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)
+static void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res)
 {
 	struct srb *srb;
 	int i;
@@ -890,74 +1012,116 @@
 	for (i = 0; i < ha->host->can_queue; i++) {
 		srb = qla4xxx_del_from_active_array(ha, i);
 		if (srb != NULL) {
-			srb->cmd->result = DID_RESET << 16;
+			srb->cmd->result = res;
 			kref_put(&srb->srb_ref, qla4xxx_srb_compl);
 		}
 	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
+void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha)
+{
+	clear_bit(AF_ONLINE, &ha->flags);
+
+	/* Disable the board */
+	ql4_printk(KERN_INFO, ha, "Disabling the board\n");
+	set_bit(AF_HBA_GOING_AWAY, &ha->flags);
+
+	qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
+	qla4xxx_mark_all_devices_missing(ha);
+	clear_bit(AF_INIT_DONE, &ha->flags);
+}
+
 /**
  * qla4xxx_recover_adapter - recovers adapter after a fatal error
  * @ha: Pointer to host adapter structure.
- * @renew_ddb_list: Indicates what to do with the adapter's ddb list
- *
- * renew_ddb_list value can be 0=preserve ddb list, 1=destroy and rebuild
- * ddb list.
  **/
-static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
-				uint8_t renew_ddb_list)
+static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
 {
-	int status;
+	int status = QLA_ERROR;
+	uint8_t reset_chip = 0;
 
 	/* Stall incoming I/O until we are done */
+	scsi_block_requests(ha->host);
 	clear_bit(AF_ONLINE, &ha->flags);
 
-	DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no,
-		      __func__));
+	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__));
 
-	/* Wait for outstanding commands to complete.
-	 * Stalls the driver for max 30 secs
-	 */
-	status = qla4xxx_cmd_wait(ha);
+	set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
 
-	qla4xxx_disable_intrs(ha);
+	if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
+		reset_chip = 1;
 
-	/* Flush any pending ddb changed AENs */
-	qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
-
-	qla4xxx_flush_active_srbs(ha);
-
-	/* Reset the firmware.	If successful, function
-	 * returns with ISP interrupts enabled.
-	 */
-	DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
-		      ha->host_no, __func__));
-	if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
-		status = qla4xxx_soft_reset(ha);
-	else
-		status = QLA_ERROR;
-
-	/* Flush any pending ddb changed AENs */
-	qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
-
-	/* Re-initialize firmware. If successful, function returns
-	 * with ISP interrupts enabled */
-	if (status == QLA_SUCCESS) {
-		DEBUG2(printk("scsi%ld: %s - Initializing adapter..\n",
-			      ha->host_no, __func__));
-
-		/* If successful, AF_ONLINE flag set in
-		 * qla4xxx_initialize_adapter */
-		status = qla4xxx_initialize_adapter(ha, renew_ddb_list);
+	/* For the DPC_RESET_HA_INTR case (ISP-4xxx specific)
+	 * do not reset adapter, jump to initialize_adapter */
+	if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
+		status = QLA_SUCCESS;
+		goto recover_ha_init_adapter;
 	}
 
-	/* Failed adapter initialization?
-	 * Retry reset_ha only if invoked via DPC (DPC_RESET_HA) */
-	if ((test_bit(AF_ONLINE, &ha->flags) == 0) &&
-	    (test_bit(DPC_RESET_HA, &ha->dpc_flags))) {
+	/* For the ISP-82xx adapter, issue a stop_firmware if invoked
+	 * from eh_host_reset or ioctl module */
+	if (is_qla8022(ha) && !reset_chip &&
+	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
+
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+		    "scsi%ld: %s - Performing stop_firmware...\n",
+		    ha->host_no, __func__));
+		status = ha->isp_ops->reset_firmware(ha);
+		if (status == QLA_SUCCESS) {
+			qla4xxx_cmd_wait(ha);
+			ha->isp_ops->disable_intrs(ha);
+			qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+			qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
+		} else {
+			/* If the stop_firmware fails then
+			 * reset the entire chip */
+			reset_chip = 1;
+			clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
+			set_bit(DPC_RESET_HA, &ha->dpc_flags);
+		}
+	}
+
+	/* Issue full chip reset if recovering from a catastrophic error,
+	 * or if stop_firmware fails for ISP-82xx.
+	 * This is the default case for ISP-4xxx */
+	if (!is_qla8022(ha) || reset_chip) {
+		qla4xxx_cmd_wait(ha);
+		qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+		qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+		    "scsi%ld: %s - Performing chip reset..\n",
+		    ha->host_no, __func__));
+		status = ha->isp_ops->reset_chip(ha);
+	}
+
+	/* Flush any pending ddb changed AENs */
+	qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+
+recover_ha_init_adapter:
+	/* Upon successful firmware/chip reset, re-initialize the adapter */
+	if (status == QLA_SUCCESS) {
+		/* For ISP-4xxx, force function 1 to always initialize
+		 * before function 3 to prevent both funcions from
+		 * stepping on top of the other */
+		if (!is_qla8022(ha) && (ha->mac_index == 3))
+			ssleep(6);
+
+		/* NOTE: AF_ONLINE flag set upon successful completion of
+		 *       qla4xxx_initialize_adapter */
+		status = qla4xxx_initialize_adapter(ha, PRESERVE_DDB_LIST);
+	}
+
+	/* Retry failed adapter initialization, if necessary
+	 * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific)
+	 * case to prevent ping-pong resets between functions */
+	if (!test_bit(AF_ONLINE, &ha->flags) &&
+	    !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
 		/* Adapter initialization failed, see if we can retry
-		 * resetting the ha */
+		 * resetting the ha.
+		 * Since we don't want to block the DPC for too long
+		 * with multiple resets in the same thread,
+		 * utilize DPC to retry */
 		if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) {
 			ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES;
 			DEBUG2(printk("scsi%ld: recover adapter - retrying "
@@ -982,29 +1146,43 @@
 				DEBUG2(printk("scsi%ld: recover adapter "
 					      "failed - board disabled\n",
 					      ha->host_no));
-				qla4xxx_flush_active_srbs(ha);
+				qla4xxx_dead_adapter_cleanup(ha);
 				clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
 				clear_bit(DPC_RESET_HA, &ha->dpc_flags);
-				clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST,
+				clear_bit(DPC_RESET_HA_FW_CONTEXT,
 					  &ha->dpc_flags);
 				status = QLA_ERROR;
 			}
 		}
 	} else {
 		clear_bit(DPC_RESET_HA, &ha->dpc_flags);
-		clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags);
+		clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
 		clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
 	}
 
 	ha->adapter_error_count++;
 
-	if (status == QLA_SUCCESS)
-		qla4xxx_enable_intrs(ha);
+	if (test_bit(AF_ONLINE, &ha->flags))
+		ha->isp_ops->enable_intrs(ha);
 
-	DEBUG2(printk("scsi%ld: recover adapter .. DONE\n", ha->host_no));
+	scsi_unblock_requests(ha->host);
+
+	clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
+	DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no,
+	    status == QLA_ERROR ? "FAILED" : "SUCCEDED"));
+
 	return status;
 }
 
+void qla4xxx_wake_dpc(struct scsi_qla_host *ha)
+{
+	if (ha->dpc_thread &&
+	    !test_bit(AF_DPC_SCHEDULED, &ha->flags)) {
+		set_bit(AF_DPC_SCHEDULED, &ha->flags);
+		queue_work(ha->dpc_thread, &ha->dpc_work);
+	}
+}
+
 /**
  * qla4xxx_do_dpc - dpc routine
  * @data: in our case pointer to adapter structure
@@ -1024,21 +1202,47 @@
 	int status = QLA_ERROR;
 
 	DEBUG2(printk("scsi%ld: %s: DPC handler waking up."
-		"flags = 0x%08lx, dpc_flags = 0x%08lx ctrl_stat = 0x%08x\n",
-		ha->host_no, __func__, ha->flags, ha->dpc_flags,
-		readw(&ha->reg->ctrl_status)));
+	    "flags = 0x%08lx, dpc_flags = 0x%08lx\n",
+	    ha->host_no, __func__, ha->flags, ha->dpc_flags))
 
 	/* Initialization not yet finished. Don't do anything yet. */
 	if (!test_bit(AF_INIT_DONE, &ha->flags))
 		return;
 
-	if (adapter_up(ha) ||
-	    test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
+	/* HBA is in the process of being permanently disabled.
+	 * Don't process anything */
+	if (test_bit(AF_HBA_GOING_AWAY, &ha->flags))
+		return;
+
+	if (is_qla8022(ha)) {
+		if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) {
+			qla4_8xxx_idc_lock(ha);
+			qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+			    QLA82XX_DEV_FAILED);
+			qla4_8xxx_idc_unlock(ha);
+			ql4_printk(KERN_INFO, ha, "HW State: FAILED\n");
+			qla4_8xxx_device_state_handler(ha);
+		}
+		if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
+			qla4_8xxx_need_qsnt_handler(ha);
+		}
+	}
+
+	if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) &&
+	    (test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
 	    test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
-	    test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) {
-		if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
-			test_bit(DPC_RESET_HA, &ha->dpc_flags))
-			qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST);
+	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) {
+		if (ql4xdontresethba) {
+			DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
+			    ha->host_no, __func__));
+			clear_bit(DPC_RESET_HA, &ha->dpc_flags);
+			clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
+			clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
+			goto dpc_post_reset_ha;
+		}
+		if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
+		    test_bit(DPC_RESET_HA, &ha->dpc_flags))
+			qla4xxx_recover_adapter(ha);
 
 		if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
 			uint8_t wait_time = RESET_INTR_TOV;
@@ -1053,18 +1257,18 @@
 				DEBUG2(printk("scsi%ld: %s: SR|FSR "
 					      "bit not cleared-- resetting\n",
 					      ha->host_no, __func__));
-			qla4xxx_flush_active_srbs(ha);
+			qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
 			if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) {
 				qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
-				status = qla4xxx_initialize_adapter(ha,
-						PRESERVE_DDB_LIST);
+				status = qla4xxx_recover_adapter(ha);
 			}
 			clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
 			if (status == QLA_SUCCESS)
-				qla4xxx_enable_intrs(ha);
+				ha->isp_ops->enable_intrs(ha);
 		}
 	}
 
+dpc_post_reset_ha:
 	/* ---- process AEN? --- */
 	if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
 		qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
@@ -1102,13 +1306,11 @@
 					    DDB_DS_SESSION_ACTIVE) {
 						atomic_set(&ddb_entry->state,
 							   DDB_STATE_ONLINE);
-						dev_info(&ha->pdev->dev,
+						ql4_printk(KERN_INFO, ha,
 						    "scsi%ld: %s: ddb[%d]"
-						    " os[%d] marked"
-						    " ONLINE\n",
+						    " marked ONLINE\n",
 						    ha->host_no, __func__,
-						    ddb_entry->fw_ddb_index,
-						    ddb_entry->os_target_id);
+						    ddb_entry->fw_ddb_index);
 
 						iscsi_unblock_session(
 						    ddb_entry->sess);
@@ -1144,6 +1346,7 @@
 			}
 		}
 	}
+	clear_bit(AF_DPC_SCHEDULED, &ha->flags);
 }
 
 /**
@@ -1155,30 +1358,99 @@
 
 	if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) {
 		/* Turn-off interrupts on the card. */
-		qla4xxx_disable_intrs(ha);
+		ha->isp_ops->disable_intrs(ha);
 	}
 
-	/* Kill the kernel thread for this host */
-	if (ha->dpc_thread)
-		destroy_workqueue(ha->dpc_thread);
-
-	/* Issue Soft Reset to put firmware in unknown state */
-	if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
-		qla4xxx_hw_reset(ha);
-
 	/* Remove timer thread, if present */
 	if (ha->timer_active)
 		qla4xxx_stop_timer(ha);
 
+	/* Kill the kernel thread for this host */
+	if (ha->dpc_thread)
+		destroy_workqueue(ha->dpc_thread);
+
+	/* Put firmware in known state */
+	ha->isp_ops->reset_firmware(ha);
+
+	if (is_qla8022(ha)) {
+		qla4_8xxx_idc_lock(ha);
+		qla4_8xxx_clear_drv_active(ha);
+		qla4_8xxx_idc_unlock(ha);
+	}
+
 	/* Detach interrupts */
 	if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags))
-		free_irq(ha->pdev->irq, ha);
+		qla4xxx_free_irqs(ha);
 
 	/* free extra memory */
 	qla4xxx_mem_free(ha);
+}
 
-	pci_disable_device(ha->pdev);
+int qla4_8xxx_iospace_config(struct scsi_qla_host *ha)
+{
+	int status = 0;
+	uint8_t revision_id;
+	unsigned long mem_base, mem_len, db_base, db_len;
+	struct pci_dev *pdev = ha->pdev;
 
+	status = pci_request_regions(pdev, DRIVER_NAME);
+	if (status) {
+		printk(KERN_WARNING
+		    "scsi(%ld) Failed to reserve PIO regions (%s) "
+		    "status=%d\n", ha->host_no, pci_name(pdev), status);
+		goto iospace_error_exit;
+	}
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &revision_id);
+	DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n",
+	    __func__, revision_id));
+	ha->revision_id = revision_id;
+
+	/* remap phys address */
+	mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
+	mem_len = pci_resource_len(pdev, 0);
+	DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n",
+	    __func__, mem_base, mem_len));
+
+	/* mapping of pcibase pointer */
+	ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len);
+	if (!ha->nx_pcibase) {
+		printk(KERN_ERR
+		    "cannot remap MMIO (%s), aborting\n", pci_name(pdev));
+		pci_release_regions(ha->pdev);
+		goto iospace_error_exit;
+	}
+
+	/* Mapping of IO base pointer, door bell read and write pointer */
+
+	/* mapping of IO base pointer */
+	ha->qla4_8xxx_reg =
+	    (struct device_reg_82xx  __iomem *)((uint8_t *)ha->nx_pcibase +
+	    0xbc000 + (ha->pdev->devfn << 11));
+
+	db_base = pci_resource_start(pdev, 4);  /* doorbell is on bar 4 */
+	db_len = pci_resource_len(pdev, 4);
+
+	/* mapping of doorbell write pointer */
+	ha->nx_db_wr_ptr = (unsigned long)ioremap(db_base +
+	    (ha->pdev->devfn << 12), 4);
+	if (!ha->nx_db_wr_ptr) {
+		printk(KERN_ERR
+		    "cannot remap MMIO doorbell-write (%s), aborting\n",
+		    pci_name(pdev));
+		goto iospace_error_exit;
+	}
+	/* mapping of doorbell read pointer */
+	ha->nx_db_rd_ptr = (uint8_t *) ha->nx_pcibase + (512 * 1024) +
+	    (ha->pdev->devfn * 8);
+	if (!ha->nx_db_rd_ptr)
+		printk(KERN_ERR
+		    "cannot remap MMIO doorbell-read (%s), aborting\n",
+		    pci_name(pdev));
+	return 0;
+
+iospace_error_exit:
+	return -ENOMEM;
 }
 
 /***
@@ -1188,7 +1460,7 @@
  * This routines maps HBA's registers from the pci address space
  * into the kernel virtual address space for memory mapped i/o.
  **/
-static int qla4xxx_iospace_config(struct scsi_qla_host *ha)
+int qla4xxx_iospace_config(struct scsi_qla_host *ha)
 {
 	unsigned long pio, pio_len, pio_flags;
 	unsigned long mmio, mmio_len, mmio_flags;
@@ -1198,12 +1470,12 @@
 	pio_flags = pci_resource_flags(ha->pdev, 0);
 	if (pio_flags & IORESOURCE_IO) {
 		if (pio_len < MIN_IOBASE_LEN) {
-			dev_warn(&ha->pdev->dev,
+			ql4_printk(KERN_WARNING, ha,
 				"Invalid PCI I/O region size\n");
 			pio = 0;
 		}
 	} else {
-		dev_warn(&ha->pdev->dev, "region #0 not a PIO resource\n");
+		ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n");
 		pio = 0;
 	}
 
@@ -1213,20 +1485,21 @@
 	mmio_flags = pci_resource_flags(ha->pdev, 1);
 
 	if (!(mmio_flags & IORESOURCE_MEM)) {
-		dev_err(&ha->pdev->dev,
-			"region #0 not an MMIO resource, aborting\n");
+		ql4_printk(KERN_ERR, ha,
+		    "region #0 not an MMIO resource, aborting\n");
 
 		goto iospace_error_exit;
 	}
+
 	if (mmio_len < MIN_IOBASE_LEN) {
-		dev_err(&ha->pdev->dev,
-			"Invalid PCI mem region size, aborting\n");
+		ql4_printk(KERN_ERR, ha,
+		    "Invalid PCI mem region size, aborting\n");
 		goto iospace_error_exit;
 	}
 
 	if (pci_request_regions(ha->pdev, DRIVER_NAME)) {
-		dev_warn(&ha->pdev->dev,
-			"Failed to reserve PIO/MMIO regions\n");
+		ql4_printk(KERN_WARNING, ha,
+		    "Failed to reserve PIO/MMIO regions\n");
 
 		goto iospace_error_exit;
 	}
@@ -1235,8 +1508,8 @@
 	ha->pio_length = pio_len;
 	ha->reg = ioremap(mmio, MIN_IOBASE_LEN);
 	if (!ha->reg) {
-		dev_err(&ha->pdev->dev,
-			"cannot remap MMIO, aborting\n");
+		ql4_printk(KERN_ERR, ha,
+		    "cannot remap MMIO, aborting\n");
 
 		goto iospace_error_exit;
 	}
@@ -1247,6 +1520,60 @@
 	return -ENOMEM;
 }
 
+static struct isp_operations qla4xxx_isp_ops = {
+	.iospace_config         = qla4xxx_iospace_config,
+	.pci_config             = qla4xxx_pci_config,
+	.disable_intrs          = qla4xxx_disable_intrs,
+	.enable_intrs           = qla4xxx_enable_intrs,
+	.start_firmware         = qla4xxx_start_firmware,
+	.intr_handler           = qla4xxx_intr_handler,
+	.interrupt_service_routine = qla4xxx_interrupt_service_routine,
+	.reset_chip             = qla4xxx_soft_reset,
+	.reset_firmware         = qla4xxx_hw_reset,
+	.queue_iocb             = qla4xxx_queue_iocb,
+	.complete_iocb          = qla4xxx_complete_iocb,
+	.rd_shdw_req_q_out      = qla4xxx_rd_shdw_req_q_out,
+	.rd_shdw_rsp_q_in       = qla4xxx_rd_shdw_rsp_q_in,
+	.get_sys_info           = qla4xxx_get_sys_info,
+};
+
+static struct isp_operations qla4_8xxx_isp_ops = {
+	.iospace_config         = qla4_8xxx_iospace_config,
+	.pci_config             = qla4_8xxx_pci_config,
+	.disable_intrs          = qla4_8xxx_disable_intrs,
+	.enable_intrs           = qla4_8xxx_enable_intrs,
+	.start_firmware         = qla4_8xxx_load_risc,
+	.intr_handler           = qla4_8xxx_intr_handler,
+	.interrupt_service_routine = qla4_8xxx_interrupt_service_routine,
+	.reset_chip             = qla4_8xxx_isp_reset,
+	.reset_firmware         = qla4_8xxx_stop_firmware,
+	.queue_iocb             = qla4_8xxx_queue_iocb,
+	.complete_iocb          = qla4_8xxx_complete_iocb,
+	.rd_shdw_req_q_out      = qla4_8xxx_rd_shdw_req_q_out,
+	.rd_shdw_rsp_q_in       = qla4_8xxx_rd_shdw_rsp_q_in,
+	.get_sys_info           = qla4_8xxx_get_sys_info,
+};
+
+uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
+{
+	return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out);
+}
+
+uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
+{
+	return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->req_q_out));
+}
+
+uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
+{
+	return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in);
+}
+
+uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
+{
+	return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in));
+}
+
 /**
  * qla4xxx_probe_adapter - callback function to probe HBA
  * @pdev: pointer to pci_dev structure
@@ -1264,6 +1591,7 @@
 	struct scsi_qla_host *ha;
 	uint8_t init_retry_count = 0;
 	char buf[34];
+	struct qla4_8xxx_legacy_intr_set *nx_legacy_intr;
 
 	if (pci_enable_device(pdev))
 		return -1;
@@ -1284,12 +1612,30 @@
 	ha->host = host;
 	ha->host_no = host->host_no;
 
-	/* Configure PCI I/O space. */
-	ret = qla4xxx_iospace_config(ha);
-	if (ret)
-		goto probe_failed;
+	/* Setup Runtime configurable options */
+	if (is_qla8022(ha)) {
+		ha->isp_ops = &qla4_8xxx_isp_ops;
+		rwlock_init(&ha->hw_lock);
+		ha->qdr_sn_window = -1;
+		ha->ddr_mn_window = -1;
+		ha->curr_window = 255;
+		ha->func_num = PCI_FUNC(ha->pdev->devfn);
+		nx_legacy_intr = &legacy_intr[ha->func_num];
+		ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit;
+		ha->nx_legacy_intr.tgt_status_reg =
+			nx_legacy_intr->tgt_status_reg;
+		ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
+		ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
+	} else {
+		ha->isp_ops = &qla4xxx_isp_ops;
+	}
 
-	dev_info(&ha->pdev->dev, "Found an ISP%04x, irq %d, iobase 0x%p\n",
+	/* Configure PCI I/O space. */
+	ret = ha->isp_ops->iospace_config(ha);
+	if (ret)
+		goto probe_failed_ioconfig;
+
+	ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n",
 		   pdev->device, pdev->irq, ha->reg);
 
 	qla4xxx_config_dma_addressing(ha);
@@ -1299,32 +1645,41 @@
 	INIT_LIST_HEAD(&ha->free_srb_q);
 
 	mutex_init(&ha->mbox_sem);
+	init_completion(&ha->mbx_intr_comp);
 
 	spin_lock_init(&ha->hardware_lock);
 
 	/* Allocate dma buffers */
 	if (qla4xxx_mem_alloc(ha)) {
-		dev_warn(&ha->pdev->dev,
-			   "[ERROR] Failed to allocate memory for adapter\n");
+		ql4_printk(KERN_WARNING, ha,
+		    "[ERROR] Failed to allocate memory for adapter\n");
 
 		ret = -ENOMEM;
 		goto probe_failed;
 	}
 
+	if (is_qla8022(ha))
+		(void) qla4_8xxx_get_flash_info(ha);
+
 	/*
 	 * Initialize the Host adapter request/response queues and
 	 * firmware
 	 * NOTE: interrupts enabled upon successful completion
 	 */
 	status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST);
-	while (status == QLA_ERROR && init_retry_count++ < MAX_INIT_RETRIES) {
+	while ((!test_bit(AF_ONLINE, &ha->flags)) &&
+	    init_retry_count++ < MAX_INIT_RETRIES) {
 		DEBUG2(printk("scsi: %s: retrying adapter initialization "
 			      "(%d)\n", __func__, init_retry_count));
-		qla4xxx_soft_reset(ha);
+
+		if (ha->isp_ops->reset_chip(ha) == QLA_ERROR)
+			continue;
+
 		status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST);
 	}
-	if (status == QLA_ERROR) {
-		dev_warn(&ha->pdev->dev, "Failed to initialize adapter\n");
+
+	if (!test_bit(AF_ONLINE, &ha->flags)) {
+		ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n");
 
 		ret = -ENODEV;
 		goto probe_failed;
@@ -1340,8 +1695,9 @@
 
         ret = scsi_init_shared_tag_map(host, MAX_SRBS);
         if (ret) {
-                dev_warn(&ha->pdev->dev, "scsi_init_shared_tag_map failed\n");
-                goto probe_failed;
+		ql4_printk(KERN_WARNING, ha,
+		    "scsi_init_shared_tag_map failed\n");
+		goto probe_failed;
         }
 
 	/* Startup the kernel thread for this host adapter. */
@@ -1350,24 +1706,27 @@
 	sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no);
 	ha->dpc_thread = create_singlethread_workqueue(buf);
 	if (!ha->dpc_thread) {
-		dev_warn(&ha->pdev->dev, "Unable to start DPC thread!\n");
+		ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n");
 		ret = -ENODEV;
 		goto probe_failed;
 	}
 	INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc);
 
-	ret = request_irq(pdev->irq, qla4xxx_intr_handler,
-			  IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha);
-	if (ret) {
-		dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d"
-			" already in use.\n", pdev->irq);
-		goto probe_failed;
+	/* For ISP-82XX, request_irqs is called in qla4_8xxx_load_risc
+	 * (which is called indirectly by qla4xxx_initialize_adapter),
+	 * so that irqs will be registered after crbinit but before
+	 * mbx_intr_enable.
+	 */
+	if (!is_qla8022(ha)) {
+		ret = qla4xxx_request_irqs(ha);
+		if (ret) {
+			ql4_printk(KERN_WARNING, ha, "Failed to reserve "
+			    "interrupt %d already in use.\n", pdev->irq);
+			goto probe_failed;
+		}
 	}
-	set_bit(AF_IRQ_ATTACHED, &ha->flags);
-	host->irq = pdev->irq;
-	DEBUG(printk("scsi%d: irq %d attached\n", ha->host_no, ha->pdev->irq));
 
-	qla4xxx_enable_intrs(ha);
+	ha->isp_ops->enable_intrs(ha);
 
 	/* Start timer thread. */
 	qla4xxx_start_timer(ha, qla4xxx_timer, 1);
@@ -1391,6 +1750,8 @@
 
 probe_failed:
 	qla4xxx_free_adapter(ha);
+
+probe_failed_ioconfig:
 	scsi_host_put(ha->host);
 
 probe_disable_device:
@@ -1409,10 +1770,7 @@
 
 	ha = pci_get_drvdata(pdev);
 
-	qla4xxx_disable_intrs(ha);
-
-	while (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags))
-		ssleep(1);
+	set_bit(AF_HBA_GOING_AWAY, &ha->flags);
 
 	/* remove devs from iscsi_sessions to scsi_devices */
 	qla4xxx_free_ddb_list(ha);
@@ -1423,6 +1781,7 @@
 
 	scsi_host_put(ha->host);
 
+	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 }
 
@@ -1479,7 +1838,8 @@
  *
  * This routine removes and returns the srb at the specified index
  **/
-struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index)
+struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
+    uint32_t index)
 {
 	struct srb *srb = NULL;
 	struct scsi_cmnd *cmd = NULL;
@@ -1605,7 +1965,7 @@
 	int ret = SUCCESS;
 	int wait = 0;
 
-	dev_info(&ha->pdev->dev,
+	ql4_printk(KERN_INFO, ha,
 	    "scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n",
 	    ha->host_no, id, lun, cmd, serial);
 
@@ -1637,7 +1997,7 @@
 		}
 	}
 
-	dev_info(&ha->pdev->dev,
+	ql4_printk(KERN_INFO, ha,
 	    "scsi%ld:%d:%d: Abort command - %s\n",
 	    ha->host_no, id, lun, (ret == SUCCESS) ? "succeded" : "failed");
 
@@ -1660,7 +2020,12 @@
 	if (!ddb_entry)
 		return ret;
 
-	dev_info(&ha->pdev->dev,
+	ret = iscsi_block_scsi_eh(cmd);
+	if (ret)
+		return ret;
+	ret = FAILED;
+
+	ql4_printk(KERN_INFO, ha,
 		   "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no,
 		   cmd->device->channel, cmd->device->id, cmd->device->lun);
 
@@ -1673,13 +2038,13 @@
 	/* FIXME: wait for hba to go online */
 	stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
 	if (stat != QLA_SUCCESS) {
-		dev_info(&ha->pdev->dev, "DEVICE RESET FAILED. %d\n", stat);
+		ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat);
 		goto eh_dev_reset_done;
 	}
 
 	if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
 					 cmd->device)) {
-		dev_info(&ha->pdev->dev,
+		ql4_printk(KERN_INFO, ha,
 			   "DEVICE RESET FAILED - waiting for "
 			   "commands.\n");
 		goto eh_dev_reset_done;
@@ -1690,7 +2055,7 @@
 		MM_LUN_RESET) != QLA_SUCCESS)
 		goto eh_dev_reset_done;
 
-	dev_info(&ha->pdev->dev,
+	ql4_printk(KERN_INFO, ha,
 		   "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n",
 		   ha->host_no, cmd->device->channel, cmd->device->id,
 		   cmd->device->lun);
@@ -1712,11 +2077,15 @@
 {
 	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
 	struct ddb_entry *ddb_entry = cmd->device->hostdata;
-	int stat;
+	int stat, ret;
 
 	if (!ddb_entry)
 		return FAILED;
 
+	ret = iscsi_block_scsi_eh(cmd);
+	if (ret)
+		return ret;
+
 	starget_printk(KERN_INFO, scsi_target(cmd->device),
 		       "WARM TARGET RESET ISSUED.\n");
 
@@ -1769,7 +2138,13 @@
 
 	ha = (struct scsi_qla_host *) cmd->device->host->hostdata;
 
-	dev_info(&ha->pdev->dev,
+	if (ql4xdontresethba) {
+		DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
+		     ha->host_no, __func__));
+		return FAILED;
+	}
+
+	ql4_printk(KERN_INFO, ha,
 		   "scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no,
 		   cmd->device->channel, cmd->device->id, cmd->device->lun);
 
@@ -1781,20 +2156,22 @@
 		return FAILED;
 	}
 
-	/* make sure the dpc thread is stopped while we reset the hba */
-	clear_bit(AF_ONLINE, &ha->flags);
-	flush_workqueue(ha->dpc_thread);
+	if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+		if (is_qla8022(ha))
+			set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
+		else
+			set_bit(DPC_RESET_HA, &ha->dpc_flags);
+	}
 
-	if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS)
+	if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS)
 		return_status = SUCCESS;
 
-	dev_info(&ha->pdev->dev, "HOST RESET %s.\n",
+	ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n",
 		   return_status == FAILED ? "FAILED" : "SUCCEDED");
 
 	return return_status;
 }
 
-
 static struct pci_device_id qla4xxx_pci_tbl[] = {
 	{
 		.vendor		= PCI_VENDOR_ID_QLOGIC,
@@ -1814,6 +2191,12 @@
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
 	},
+	{
+		.vendor         = PCI_VENDOR_ID_QLOGIC,
+		.device         = PCI_DEVICE_ID_QLOGIC_ISP8022,
+		.subvendor      = PCI_ANY_ID,
+		.subdevice      = PCI_ANY_ID,
+	},
 	{0, 0},
 };
 MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
@@ -1869,7 +2252,6 @@
 
 static void __exit qla4xxx_module_exit(void)
 {
-	ql4_mod_unload = 1;
 	pci_unregister_driver(&qla4xxx_pci_driver);
 	iscsi_unregister_transport(&qla4xxx_iscsi_transport);
 	kmem_cache_destroy(srb_cachep);
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index 28a6c49..c905dbd 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -5,4 +5,4 @@
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
 
-#define QLA4XXX_DRIVER_VERSION	"5.02.00-k1"
+#define QLA4XXX_DRIVER_VERSION	"5.02.00-k2"
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 136329b..b02bdc6 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1991,7 +1991,8 @@
 		block = lba + alignment;
 		rem = do_div(block, granularity);
 
-		set_bit(block, map_storep);
+		if (block < map_size)
+			set_bit(block, map_storep);
 
 		lba += granularity - rem;
 	}
@@ -2011,7 +2012,8 @@
 		block = lba + alignment;
 		rem = do_div(block, granularity);
 
-		if (rem == 0 && lba + granularity <= end)
+		if (rem == 0 && lba + granularity <= end &&
+		    block < map_size)
 			clear_bit(block, map_storep);
 
 		lba += granularity - rem;
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index a5d630f..2bf9846 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -307,6 +307,19 @@
 		    (sshdr.asc == 0x04) && (sshdr.ascq == 0x02))
 			return FAILED;
 
+		if (sshdr.asc == 0x3f && sshdr.ascq == 0x0e)
+			scmd_printk(KERN_WARNING, scmd,
+				    "Warning! Received an indication that the "
+				    "LUN assignments on this target have "
+				    "changed. The Linux SCSI layer does not "
+				    "automatically remap LUN assignments.\n");
+		else if (sshdr.asc == 0x3f)
+			scmd_printk(KERN_WARNING, scmd,
+				    "Warning! Received an indication that the "
+				    "operating parameters on this target have "
+				    "changed. The Linux SCSI layer does not "
+				    "automatically adjust these parameters.\n");
+
 		if (blk_barrier_rq(scmd->request))
 			/*
 			 * barrier requests should always retry on UA
@@ -1762,6 +1775,14 @@
 		 * what we need to do to get it up and online again (if we can).
 		 * If we fail, we end up taking the thing offline.
 		 */
+		if (scsi_autopm_get_host(shost) != 0) {
+			SCSI_LOG_ERROR_RECOVERY(1,
+				printk(KERN_ERR "Error handler scsi_eh_%d "
+						"unable to autoresume\n",
+						shost->host_no));
+			continue;
+		}
+
 		if (shost->transportt->eh_strategy_handler)
 			shost->transportt->eh_strategy_handler(shost);
 		else
@@ -1775,6 +1796,7 @@
 		 * which are still online.
 		 */
 		scsi_restart_operations(shost);
+		scsi_autopm_put_host(shost);
 		set_current_state(TASK_INTERRUPTIBLE);
 	}
 	__set_current_state(TASK_RUNNING);
@@ -1872,12 +1894,16 @@
 int
 scsi_reset_provider(struct scsi_device *dev, int flag)
 {
-	struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL);
+	struct scsi_cmnd *scmd;
 	struct Scsi_Host *shost = dev->host;
 	struct request req;
 	unsigned long flags;
 	int rtn;
 
+	if (scsi_autopm_get_host(shost) < 0)
+		return FAILED;
+
+	scmd = scsi_get_command(dev, GFP_KERNEL);
 	blk_rq_init(NULL, &req);
 	scmd->request = &req;
 
@@ -1934,6 +1960,7 @@
 	scsi_run_host_queues(shost);
 
 	scsi_next_command(scmd);
+	scsi_autopm_put_host(shost);
 	return rtn;
 }
 EXPORT_SYMBOL(scsi_reset_provider);
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
new file mode 100644
index 0000000..d70e91a
--- /dev/null
+++ b/drivers/scsi/scsi_pm.c
@@ -0,0 +1,206 @@
+/*
+ *	scsi_pm.c	Copyright (C) 2010 Alan Stern
+ *
+ *	SCSI dynamic Power Management
+ *		Initial version: Alan Stern <stern@rowland.harvard.edu>
+ */
+
+#include <linux/pm_runtime.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_host.h>
+
+#include "scsi_priv.h"
+
+static int scsi_dev_type_suspend(struct device *dev, pm_message_t msg)
+{
+	struct device_driver *drv;
+	int err;
+
+	err = scsi_device_quiesce(to_scsi_device(dev));
+	if (err == 0) {
+		drv = dev->driver;
+		if (drv && drv->suspend)
+			err = drv->suspend(dev, msg);
+	}
+	dev_dbg(dev, "scsi suspend: %d\n", err);
+	return err;
+}
+
+static int scsi_dev_type_resume(struct device *dev)
+{
+	struct device_driver *drv;
+	int err = 0;
+
+	drv = dev->driver;
+	if (drv && drv->resume)
+		err = drv->resume(dev);
+	scsi_device_resume(to_scsi_device(dev));
+	dev_dbg(dev, "scsi resume: %d\n", err);
+	return err;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int scsi_bus_suspend_common(struct device *dev, pm_message_t msg)
+{
+	int err = 0;
+
+	if (scsi_is_sdev_device(dev))
+		err = scsi_dev_type_suspend(dev, msg);
+	return err;
+}
+
+static int scsi_bus_resume_common(struct device *dev)
+{
+	int err = 0;
+
+	if (scsi_is_sdev_device(dev))
+		err = scsi_dev_type_resume(dev);
+
+	if (err == 0) {
+		pm_runtime_disable(dev);
+		pm_runtime_set_active(dev);
+		pm_runtime_enable(dev);
+	}
+	return err;
+}
+
+static int scsi_bus_suspend(struct device *dev)
+{
+	return scsi_bus_suspend_common(dev, PMSG_SUSPEND);
+}
+
+static int scsi_bus_freeze(struct device *dev)
+{
+	return scsi_bus_suspend_common(dev, PMSG_FREEZE);
+}
+
+static int scsi_bus_poweroff(struct device *dev)
+{
+	return scsi_bus_suspend_common(dev, PMSG_HIBERNATE);
+}
+
+#else /* CONFIG_PM_SLEEP */
+
+#define scsi_bus_resume_common		NULL
+#define scsi_bus_suspend		NULL
+#define scsi_bus_freeze			NULL
+#define scsi_bus_poweroff		NULL
+
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int scsi_runtime_suspend(struct device *dev)
+{
+	int err = 0;
+
+	dev_dbg(dev, "scsi_runtime_suspend\n");
+	if (scsi_is_sdev_device(dev)) {
+		err = scsi_dev_type_suspend(dev, PMSG_AUTO_SUSPEND);
+		if (err == -EAGAIN)
+			pm_schedule_suspend(dev, jiffies_to_msecs(
+				round_jiffies_up_relative(HZ/10)));
+	}
+
+	/* Insert hooks here for targets, hosts, and transport classes */
+
+	return err;
+}
+
+static int scsi_runtime_resume(struct device *dev)
+{
+	int err = 0;
+
+	dev_dbg(dev, "scsi_runtime_resume\n");
+	if (scsi_is_sdev_device(dev))
+		err = scsi_dev_type_resume(dev);
+
+	/* Insert hooks here for targets, hosts, and transport classes */
+
+	return err;
+}
+
+static int scsi_runtime_idle(struct device *dev)
+{
+	int err;
+
+	dev_dbg(dev, "scsi_runtime_idle\n");
+
+	/* Insert hooks here for targets, hosts, and transport classes */
+
+	if (scsi_is_sdev_device(dev))
+		err = pm_schedule_suspend(dev, 100);
+	else
+		err = pm_runtime_suspend(dev);
+	return err;
+}
+
+int scsi_autopm_get_device(struct scsi_device *sdev)
+{
+	int	err;
+
+	err = pm_runtime_get_sync(&sdev->sdev_gendev);
+	if (err < 0)
+		pm_runtime_put_sync(&sdev->sdev_gendev);
+	else if (err > 0)
+		err = 0;
+	return err;
+}
+EXPORT_SYMBOL_GPL(scsi_autopm_get_device);
+
+void scsi_autopm_put_device(struct scsi_device *sdev)
+{
+	pm_runtime_put_sync(&sdev->sdev_gendev);
+}
+EXPORT_SYMBOL_GPL(scsi_autopm_put_device);
+
+void scsi_autopm_get_target(struct scsi_target *starget)
+{
+	pm_runtime_get_sync(&starget->dev);
+}
+
+void scsi_autopm_put_target(struct scsi_target *starget)
+{
+	pm_runtime_put_sync(&starget->dev);
+}
+
+int scsi_autopm_get_host(struct Scsi_Host *shost)
+{
+	int	err;
+
+	err = pm_runtime_get_sync(&shost->shost_gendev);
+	if (err < 0)
+		pm_runtime_put_sync(&shost->shost_gendev);
+	else if (err > 0)
+		err = 0;
+	return err;
+}
+
+void scsi_autopm_put_host(struct Scsi_Host *shost)
+{
+	pm_runtime_put_sync(&shost->shost_gendev);
+}
+
+#else
+
+#define scsi_runtime_suspend	NULL
+#define scsi_runtime_resume	NULL
+#define scsi_runtime_idle	NULL
+
+#endif /* CONFIG_PM_RUNTIME */
+
+const struct dev_pm_ops scsi_bus_pm_ops = {
+	.suspend =		scsi_bus_suspend,
+	.resume =		scsi_bus_resume_common,
+	.freeze =		scsi_bus_freeze,
+	.thaw =			scsi_bus_resume_common,
+	.poweroff =		scsi_bus_poweroff,
+	.restore =		scsi_bus_resume_common,
+	.runtime_suspend =	scsi_runtime_suspend,
+	.runtime_resume =	scsi_runtime_resume,
+	.runtime_idle =		scsi_runtime_idle,
+};
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 1fbf7c7..026295e 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -7,6 +7,7 @@
 struct request;
 struct scsi_cmnd;
 struct scsi_device;
+struct scsi_target;
 struct scsi_host_template;
 struct Scsi_Host;
 struct scsi_nl_hdr;
@@ -144,6 +145,24 @@
 static inline void scsi_netlink_exit(void) {}
 #endif
 
+/* scsi_pm.c */
+#ifdef CONFIG_PM_OPS
+extern const struct dev_pm_ops scsi_bus_pm_ops;
+#else /* CONFIG_PM_OPS */
+#define scsi_bus_pm_ops		(*NULL)
+#endif
+#ifdef CONFIG_PM_RUNTIME
+extern void scsi_autopm_get_target(struct scsi_target *);
+extern void scsi_autopm_put_target(struct scsi_target *);
+extern int scsi_autopm_get_host(struct Scsi_Host *);
+extern void scsi_autopm_put_host(struct Scsi_Host *);
+#else
+static inline void scsi_autopm_get_target(struct scsi_target *t) {}
+static inline void scsi_autopm_put_target(struct scsi_target *t) {}
+static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; }
+static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
+#endif /* CONFIG_PM_RUNTIME */
+
 /* 
  * internal scsi timeout functions: for use by mid-layer and transport
  * classes.
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 1c027a9..3d0a1e6 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -1513,14 +1513,18 @@
 	starget = scsi_alloc_target(parent, channel, id);
 	if (!starget)
 		return ERR_PTR(-ENOMEM);
+	scsi_autopm_get_target(starget);
 
 	mutex_lock(&shost->scan_mutex);
 	if (!shost->async_scan)
 		scsi_complete_async_scans();
 
-	if (scsi_host_scan_allowed(shost))
+	if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
 		scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
+		scsi_autopm_put_host(shost);
+	}
 	mutex_unlock(&shost->scan_mutex);
+	scsi_autopm_put_target(starget);
 	scsi_target_reap(starget);
 	put_device(&starget->dev);
 
@@ -1574,6 +1578,7 @@
 	starget = scsi_alloc_target(parent, channel, id);
 	if (!starget)
 		return;
+	scsi_autopm_get_target(starget);
 
 	if (lun != SCAN_WILD_CARD) {
 		/*
@@ -1599,6 +1604,7 @@
 	}
 
  out_reap:
+	scsi_autopm_put_target(starget);
 	/* now determine if the target has any children at all
 	 * and if not, nuke it */
 	scsi_target_reap(starget);
@@ -1633,8 +1639,10 @@
 	if (!shost->async_scan)
 		scsi_complete_async_scans();
 
-	if (scsi_host_scan_allowed(shost))
+	if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
 		__scsi_scan_target(parent, channel, id, lun, rescan);
+		scsi_autopm_put_host(shost);
+	}
 	mutex_unlock(&shost->scan_mutex);
 }
 EXPORT_SYMBOL(scsi_scan_target);
@@ -1686,7 +1694,7 @@
 	if (!shost->async_scan)
 		scsi_complete_async_scans();
 
-	if (scsi_host_scan_allowed(shost)) {
+	if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
 		if (channel == SCAN_WILD_CARD)
 			for (channel = 0; channel <= shost->max_channel;
 			     channel++)
@@ -1694,6 +1702,7 @@
 						  rescan);
 		else
 			scsi_scan_channel(shost, channel, id, lun, rescan);
+		scsi_autopm_put_host(shost);
 	}
 	mutex_unlock(&shost->scan_mutex);
 
@@ -1831,8 +1840,11 @@
 static int do_scan_async(void *_data)
 {
 	struct async_scan_data *data = _data;
-	do_scsi_scan_host(data->shost);
+	struct Scsi_Host *shost = data->shost;
+
+	do_scsi_scan_host(shost);
 	scsi_finish_async_scan(data);
+	scsi_autopm_put_host(shost);
 	return 0;
 }
 
@@ -1847,16 +1859,20 @@
 
 	if (strncmp(scsi_scan_type, "none", 4) == 0)
 		return;
+	if (scsi_autopm_get_host(shost) < 0)
+		return;
 
 	data = scsi_prep_async_scan(shost);
 	if (!data) {
 		do_scsi_scan_host(shost);
+		scsi_autopm_put_host(shost);
 		return;
 	}
 
 	p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
 	if (IS_ERR(p))
 		do_scan_async(data);
+	/* scsi_autopm_put_host(shost) is called in do_scan_async() */
 }
 EXPORT_SYMBOL(scsi_scan_host);
 
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index c23ab97..562fb3b 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/device.h>
+#include <linux/pm_runtime.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
@@ -376,57 +377,11 @@
 	return 0;
 }
 
-static int scsi_bus_suspend(struct device * dev, pm_message_t state)
-{
-	struct device_driver *drv;
-	struct scsi_device *sdev;
-	int err;
-
-	if (dev->type != &scsi_dev_type)
-		return 0;
-
-	drv = dev->driver;
-	sdev = to_scsi_device(dev);
-
-	err = scsi_device_quiesce(sdev);
-	if (err)
-		return err;
-
-	if (drv && drv->suspend) {
-		err = drv->suspend(dev, state);
-		if (err)
-			return err;
-	}
-
-	return 0;
-}
-
-static int scsi_bus_resume(struct device * dev)
-{
-	struct device_driver *drv;
-	struct scsi_device *sdev;
-	int err = 0;
-
-	if (dev->type != &scsi_dev_type)
-		return 0;
-
-	drv = dev->driver;
-	sdev = to_scsi_device(dev);
-
-	if (drv && drv->resume)
-		err = drv->resume(dev);
-
-	scsi_device_resume(sdev);
-
-	return err;
-}
-
 struct bus_type scsi_bus_type = {
         .name		= "scsi",
         .match		= scsi_bus_match,
 	.uevent		= scsi_bus_uevent,
-	.suspend	= scsi_bus_suspend,
-	.resume		= scsi_bus_resume,
+	.pm		= &scsi_bus_pm_ops,
 };
 EXPORT_SYMBOL_GPL(scsi_bus_type);
 
@@ -848,8 +803,6 @@
 	if (starget->state != STARGET_CREATED)
 		return 0;
 
-	device_enable_async_suspend(&starget->dev);
-
 	error = device_add(&starget->dev);
 	if (error) {
 		dev_err(&starget->dev, "target device_add failed, error %d\n", error);
@@ -858,6 +811,10 @@
 	transport_add_device(&starget->dev);
 	starget->state = STARGET_RUNNING;
 
+	pm_runtime_set_active(&starget->dev);
+	pm_runtime_enable(&starget->dev);
+	device_enable_async_suspend(&starget->dev);
+
 	return 0;
 }
 
@@ -887,7 +844,20 @@
 		return error;
 
 	transport_configure_device(&starget->dev);
+
 	device_enable_async_suspend(&sdev->sdev_gendev);
+	scsi_autopm_get_target(starget);
+	pm_runtime_set_active(&sdev->sdev_gendev);
+	pm_runtime_forbid(&sdev->sdev_gendev);
+	pm_runtime_enable(&sdev->sdev_gendev);
+	scsi_autopm_put_target(starget);
+
+	/* The following call will keep sdev active indefinitely, until
+	 * its driver does a corresponding scsi_autopm_pm_device().  Only
+	 * drivers supporting autosuspend will do this.
+	 */
+	scsi_autopm_get_device(sdev);
+
 	error = device_add(&sdev->sdev_gendev);
 	if (error) {
 		printk(KERN_INFO "error 1\n");
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 1e6d479..e84026d 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -30,8 +30,9 @@
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_iscsi.h>
 #include <scsi/iscsi_if.h>
+#include <scsi/scsi_cmnd.h>
 
-#define ISCSI_SESSION_ATTRS 22
+#define ISCSI_SESSION_ATTRS 23
 #define ISCSI_CONN_ATTRS 13
 #define ISCSI_HOST_ATTRS 4
 
@@ -534,6 +535,37 @@
 	atomic_dec(&ihost->nr_scans);
 }
 
+/**
+ * iscsi_block_scsi_eh - block scsi eh until session state has transistioned
+ * cmd: scsi cmd passed to scsi eh handler
+ *
+ * If the session is down this function will wait for the recovery
+ * timer to fire or for the session to be logged back in. If the
+ * recovery timer fires then FAST_IO_FAIL is returned. The caller
+ * should pass this error value to the scsi eh.
+ */
+int iscsi_block_scsi_eh(struct scsi_cmnd *cmd)
+{
+	struct iscsi_cls_session *session =
+			starget_to_session(scsi_target(cmd->device));
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&session->lock, flags);
+	while (session->state != ISCSI_SESSION_LOGGED_IN) {
+		if (session->state == ISCSI_SESSION_FREE) {
+			ret = FAST_IO_FAIL;
+			break;
+		}
+		spin_unlock_irqrestore(&session->lock, flags);
+		msleep(1000);
+		spin_lock_irqsave(&session->lock, flags);
+	}
+	spin_unlock_irqrestore(&session->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iscsi_block_scsi_eh);
+
 static void session_recovery_timedout(struct work_struct *work)
 {
 	struct iscsi_cls_session *session =
@@ -1763,7 +1795,8 @@
 iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
 iscsi_session_attr(tgt_reset_tmo, ISCSI_PARAM_TGT_RESET_TMO, 0);
 iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
-iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
+iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0);
+iscsi_session_attr(targetalias, ISCSI_PARAM_TARGET_ALIAS, 0);
 
 static ssize_t
 show_priv_session_state(struct device *dev, struct device_attribute *attr,
@@ -1782,14 +1815,42 @@
 {									\
 	struct iscsi_cls_session *session = 				\
 			iscsi_dev_to_session(dev->parent);		\
+	if (session->field == -1)					\
+		return sprintf(buf, "off\n");				\
 	return sprintf(buf, format"\n", session->field);		\
 }
 
-#define iscsi_priv_session_attr(field, format)				\
+#define iscsi_priv_session_attr_store(field)				\
+static ssize_t								\
+store_priv_session_##field(struct device *dev,				\
+			   struct device_attribute *attr,		\
+			   const char *buf, size_t count)		\
+{									\
+	int val;							\
+	char *cp;							\
+	struct iscsi_cls_session *session =				\
+		iscsi_dev_to_session(dev->parent);			\
+	if ((session->state == ISCSI_SESSION_FREE) ||			\
+	    (session->state == ISCSI_SESSION_FAILED))			\
+		return -EBUSY;						\
+	if (strncmp(buf, "off", 3) == 0)				\
+		session->field = -1;					\
+	else {								\
+		val = simple_strtoul(buf, &cp, 0);			\
+		if (*cp != '\0' && *cp != '\n')				\
+			return -EINVAL;					\
+		session->field = val;					\
+	}								\
+	return count;							\
+}
+
+#define iscsi_priv_session_rw_attr(field, format)			\
 	iscsi_priv_session_attr_show(field, format)			\
-static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \
-			NULL)
-iscsi_priv_session_attr(recovery_tmo, "%d");
+	iscsi_priv_session_attr_store(field)				\
+static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO | S_IWUGO,		\
+			show_priv_session_##field,			\
+			store_priv_session_##field)
+iscsi_priv_session_rw_attr(recovery_tmo, "%d");
 
 /*
  * iSCSI host attrs
@@ -1820,6 +1881,11 @@
 	count++;							\
 } while (0)
 
+#define SETUP_PRIV_SESSION_RW_ATTR(field)				\
+do {									\
+	priv->session_attrs[count] = &dev_attr_priv_sess_##field;	\
+	count++;							\
+} while (0)
 
 #define SETUP_SESSION_RD_ATTR(field, param_flag)			\
 do {									\
@@ -2006,7 +2072,8 @@
 	SETUP_SESSION_RD_ATTR(tgt_reset_tmo,ISCSI_TGT_RESET_TMO);
 	SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME);
 	SETUP_SESSION_RD_ATTR(initiatorname, ISCSI_INITIATOR_NAME);
-	SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
+	SETUP_SESSION_RD_ATTR(targetalias, ISCSI_TARGET_ALIAS);
+	SETUP_PRIV_SESSION_RW_ATTR(recovery_tmo);
 	SETUP_PRIV_SESSION_RD_ATTR(state);
 
 	BUG_ON(count > ISCSI_SESSION_ATTRS);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 8802e48..cc8a1d1 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -759,6 +759,10 @@
 
 	sdev = sdkp->device;
 
+	retval = scsi_autopm_get_device(sdev);
+	if (retval)
+		goto error_autopm;
+
 	/*
 	 * If the device is in error recovery, wait until it is done.
 	 * If the device is offline, then disallow any access to it.
@@ -803,6 +807,8 @@
 	return 0;
 
 error_out:
+	scsi_autopm_put_device(sdev);
+error_autopm:
 	scsi_disk_put(sdkp);
 	return retval;	
 }
@@ -834,6 +840,8 @@
 	 * XXX and what if there are packets in flight and this close()
 	 * XXX is followed by a "rmmod sd_mod"?
 	 */
+
+	scsi_autopm_put_device(sdev);
 	scsi_disk_put(sdkp);
 	return 0;
 }
@@ -2232,7 +2240,6 @@
 	if (sdp->removable)
 		gd->flags |= GENHD_FL_REMOVABLE;
 
-	dev_set_drvdata(dev, sdkp);
 	add_disk(gd);
 	sd_dif_config_host(sdkp);
 
@@ -2240,6 +2247,7 @@
 
 	sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
 		  sdp->removable ? "removable " : "");
+	scsi_autopm_put_device(sdp);
 	put_device(&sdkp->dev);
 }
 
@@ -2317,14 +2325,15 @@
 	}
 
 	device_initialize(&sdkp->dev);
-	sdkp->dev.parent = &sdp->sdev_gendev;
+	sdkp->dev.parent = dev;
 	sdkp->dev.class = &sd_disk_class;
-	dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev));
+	dev_set_name(&sdkp->dev, dev_name(dev));
 
 	if (device_add(&sdkp->dev))
 		goto out_free_index;
 
-	get_device(&sdp->sdev_gendev);
+	get_device(dev);
+	dev_set_drvdata(dev, sdkp);
 
 	get_device(&sdkp->dev);	/* prevent release before async_schedule */
 	async_schedule(sd_probe_async, sdkp);
@@ -2358,8 +2367,10 @@
 {
 	struct scsi_disk *sdkp;
 
-	async_synchronize_full();
 	sdkp = dev_get_drvdata(dev);
+	scsi_autopm_get_device(sdkp->device);
+
+	async_synchronize_full();
 	blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn);
 	device_del(&sdkp->dev);
 	del_gendisk(sdkp->disk);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index ef752b2..2968c6b 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -245,6 +245,10 @@
 	if (retval)
 		goto sg_put;
 
+	retval = scsi_autopm_get_device(sdp->device);
+	if (retval)
+		goto sdp_put;
+
 	if (!((flags & O_NONBLOCK) ||
 	      scsi_block_when_processing_errors(sdp->device))) {
 		retval = -ENXIO;
@@ -302,8 +306,11 @@
 	}
 	retval = 0;
 error_out:
-	if (retval)
+	if (retval) {
+		scsi_autopm_put_device(sdp->device);
+sdp_put:
 		scsi_device_put(sdp->device);
+	}
 sg_put:
 	if (sdp)
 		sg_put_dev(sdp);
@@ -327,6 +334,7 @@
 	sdp->exclude = 0;
 	wake_up_interruptible(&sdp->o_excl_wait);
 
+	scsi_autopm_put_device(sdp->device);
 	kref_put(&sfp->f_ref, sg_remove_sfp);
 	return 0;
 }
@@ -729,6 +737,8 @@
 		return k;	/* probably out of space --> ENOMEM */
 	}
 	if (sdp->detached) {
+		if (srp->bio)
+			blk_end_request_all(srp->rq, -EIO);
 		sg_finish_rem_req(srp);
 		return -ENODEV;
 	}
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
index 59ae76b..7c031fd 100644
--- a/drivers/ssb/driver_chipcommon.c
+++ b/drivers/ssb/driver_chipcommon.c
@@ -209,6 +209,24 @@
 	}
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PmuFastPwrupDelay */
+static u16 pmu_fast_powerup_delay(struct ssb_chipcommon *cc)
+{
+	struct ssb_bus *bus = cc->dev->bus;
+
+	switch (bus->chip_id) {
+	case 0x4312:
+	case 0x4322:
+	case 0x4328:
+		return 7000;
+	case 0x4325:
+		/* TODO: */
+	default:
+		return 15000;
+	}
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/ClkctlFastPwrupDelay */
 static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
 {
 	struct ssb_bus *bus = cc->dev->bus;
@@ -218,6 +236,12 @@
 
 	if (bus->bustype != SSB_BUSTYPE_PCI)
 		return;
+
+	if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
+		cc->fast_pwrup_delay = pmu_fast_powerup_delay(cc);
+		return;
+	}
+
 	if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
 		return;
 
@@ -235,6 +259,7 @@
 		return; /* We don't have a ChipCommon */
 	if (cc->dev->id.revision >= 11)
 		cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
+	ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
 	ssb_pmu_init(cc);
 	chipco_powercontrol_init(cc);
 	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 3d55124..5732bb2 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -502,9 +502,9 @@
 		chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk);
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */
 void ssb_pmu_init(struct ssb_chipcommon *cc)
 {
-	struct ssb_bus *bus = cc->dev->bus;
 	u32 pmucap;
 
 	if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU))
@@ -516,15 +516,12 @@
 	ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n",
 		    cc->pmu.rev, pmucap);
 
-	if (cc->pmu.rev >= 1) {
-		if ((bus->chip_id == 0x4325) && (bus->chip_rev < 2)) {
-			chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
-				      ~SSB_CHIPCO_PMU_CTL_NOILPONW);
-		} else {
-			chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
-				     SSB_CHIPCO_PMU_CTL_NOILPONW);
-		}
-	}
+	if (cc->pmu.rev == 1)
+		chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
+			      ~SSB_CHIPCO_PMU_CTL_NOILPONW);
+	else
+		chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
+			     SSB_CHIPCO_PMU_CTL_NOILPONW);
 	ssb_pmu_pll_init(cc);
 	ssb_pmu_resources_init(cc);
 }
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 51275aa..7cee7f4 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -486,6 +486,7 @@
 #ifdef CONFIG_SSB_PCIHOST
 			sdev->irq = bus->host_pci->irq;
 			dev->parent = &bus->host_pci->dev;
+			sdev->dma_dev = dev->parent;
 #endif
 			break;
 		case SSB_BUSTYPE_PCMCIA:
@@ -501,6 +502,7 @@
 			break;
 		case SSB_BUSTYPE_SSB:
 			dev->dma_mask = &dev->coherent_dma_mask;
+			sdev->dma_dev = dev;
 			break;
 		}
 
@@ -1226,80 +1228,6 @@
 }
 EXPORT_SYMBOL(ssb_dma_translation);
 
-int ssb_dma_set_mask(struct ssb_device *dev, u64 mask)
-{
-#ifdef CONFIG_SSB_PCIHOST
-	int err;
-#endif
-
-	switch (dev->bus->bustype) {
-	case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
-		err = pci_set_dma_mask(dev->bus->host_pci, mask);
-		if (err)
-			return err;
-		err = pci_set_consistent_dma_mask(dev->bus->host_pci, mask);
-		return err;
-#endif
-	case SSB_BUSTYPE_SSB:
-		return dma_set_mask(dev->dev, mask);
-	default:
-		__ssb_dma_not_implemented(dev);
-	}
-	return -ENOSYS;
-}
-EXPORT_SYMBOL(ssb_dma_set_mask);
-
-void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
-				dma_addr_t *dma_handle, gfp_t gfp_flags)
-{
-	switch (dev->bus->bustype) {
-	case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
-		if (gfp_flags & GFP_DMA) {
-			/* Workaround: The PCI API does not support passing
-			 * a GFP flag. */
-			return dma_alloc_coherent(&dev->bus->host_pci->dev,
-						  size, dma_handle, gfp_flags);
-		}
-		return pci_alloc_consistent(dev->bus->host_pci, size, dma_handle);
-#endif
-	case SSB_BUSTYPE_SSB:
-		return dma_alloc_coherent(dev->dev, size, dma_handle, gfp_flags);
-	default:
-		__ssb_dma_not_implemented(dev);
-	}
-	return NULL;
-}
-EXPORT_SYMBOL(ssb_dma_alloc_consistent);
-
-void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
-			     void *vaddr, dma_addr_t dma_handle,
-			     gfp_t gfp_flags)
-{
-	switch (dev->bus->bustype) {
-	case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
-		if (gfp_flags & GFP_DMA) {
-			/* Workaround: The PCI API does not support passing
-			 * a GFP flag. */
-			dma_free_coherent(&dev->bus->host_pci->dev,
-					  size, vaddr, dma_handle);
-			return;
-		}
-		pci_free_consistent(dev->bus->host_pci, size,
-				    vaddr, dma_handle);
-		return;
-#endif
-	case SSB_BUSTYPE_SSB:
-		dma_free_coherent(dev->dev, size, vaddr, dma_handle);
-		return;
-	default:
-		__ssb_dma_not_implemented(dev);
-	}
-}
-EXPORT_SYMBOL(ssb_dma_free_consistent);
-
 int ssb_bus_may_powerdown(struct ssb_bus *bus)
 {
 	struct ssb_chipcommon *cc;
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 6dcda86..6e88d2b 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -626,11 +626,22 @@
 		return -ENODEV;
 	}
 	if (bus->chipco.dev) {	/* can be unavailible! */
-		bus->sprom_offset = (bus->chipco.dev->id.revision < 31) ?
-			SSB_SPROM_BASE1 : SSB_SPROM_BASE31;
+		/*
+		 * get SPROM offset: SSB_SPROM_BASE1 except for
+		 * chipcommon rev >= 31 or chip ID is 0x4312 and
+		 * chipcommon status & 3 == 2
+		 */
+		if (bus->chipco.dev->id.revision >= 31)
+			bus->sprom_offset = SSB_SPROM_BASE31;
+		else if (bus->chip_id == 0x4312 &&
+			 (bus->chipco.status & 0x03) == 2)
+			bus->sprom_offset = SSB_SPROM_BASE31;
+		else
+			bus->sprom_offset = SSB_SPROM_BASE1;
 	} else {
 		bus->sprom_offset = SSB_SPROM_BASE1;
 	}
+	ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset);
 
 	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
 	if (!buf)
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 984a754..0e4122e 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -109,8 +109,6 @@
 
 source "drivers/staging/vme/Kconfig"
 
-source "drivers/staging/rar_register/Kconfig"
-
 source "drivers/staging/memrar/Kconfig"
 
 source "drivers/staging/sep/Kconfig"
@@ -147,5 +145,7 @@
 
 source "drivers/staging/msm/Kconfig"
 
+source "drivers/staging/lirc/Kconfig"
+
 endif # !STAGING_EXCLUDE_BUILD
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 9fa2513..ecfb0bb 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_VIDEO_GO7007)	+= go7007/
 obj-$(CONFIG_VIDEO_CX25821)	+= cx25821/
 obj-$(CONFIG_VIDEO_TM6000)	+= tm6000/
+obj-$(CONFIG_LIRC_STAGING)	+= lirc/
 obj-$(CONFIG_USB_IP_COMMON)	+= usbip/
 obj-$(CONFIG_W35UND)		+= winbond/
 obj-$(CONFIG_PRISM2_USB)	+= wlan-ng/
@@ -35,7 +36,6 @@
 obj-$(CONFIG_FB_UDL)		+= udlfb/
 obj-$(CONFIG_HYPERV)		+= hv/
 obj-$(CONFIG_VME_BUS)		+= vme/
-obj-$(CONFIG_RAR_REGISTER)	+= rar_register/
 obj-$(CONFIG_MRST_RAR_HANDLER)	+= memrar/
 obj-$(CONFIG_DX_SEP)		+= sep/
 obj-$(CONFIG_IIO)		+= iio/
diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c
index 7a582e8..96c86c8 100644
--- a/drivers/staging/batman-adv/hard-interface.c
+++ b/drivers/staging/batman-adv/hard-interface.c
@@ -71,7 +71,7 @@
 #endif
 
 	/* Device is being bridged */
-	/* if (net_dev->br_port != NULL)
+	/* if (net_dev->priv_flags & IFF_BRIDGE_PORT)
 		return 0; */
 
 	return 1;
@@ -440,6 +440,7 @@
 	struct batman_packet *batman_packet;
 	struct batman_if *batman_if;
 	struct net_device_stats *stats;
+	struct rtnl_link_stats64 temp;
 	int ret;
 
 	skb = skb_share_check(skb, GFP_ATOMIC);
@@ -468,7 +469,7 @@
 	if (batman_if->if_status != IF_ACTIVE)
 		goto err_free;
 
-	stats = (struct net_device_stats *)dev_get_stats(skb->dev);
+	stats = (struct net_device_stats *)dev_get_stats(skb->dev, &temp);
 	if (stats) {
 		stats->rx_packets++;
 		stats->rx_bytes += skb->len;
diff --git a/drivers/staging/cx25821/Makefile b/drivers/staging/cx25821/Makefile
index 10f87f0..d0eb16e 100644
--- a/drivers/staging/cx25821/Makefile
+++ b/drivers/staging/cx25821/Makefile
@@ -1,9 +1,8 @@
-cx25821-objs	:= cx25821-core.o cx25821-cards.o cx25821-i2c.o cx25821-gpio.o 				\
-				cx25821-medusa-video.o cx25821-video.o cx25821-video0.o cx25821-video1.o    \
-				cx25821-video2.o cx25821-video3.o cx25821-video4.o cx25821-video5.o         \
-				cx25821-video6.o cx25821-video7.o cx25821-vidups9.o cx25821-vidups10.o      \
-				cx25821-audups11.o cx25821-video-upstream.o cx25821-video-upstream-ch2.o 	\
-				cx25821-audio-upstream.o cx25821-videoioctl.o
+cx25821-objs   := cx25821-core.o cx25821-cards.o cx25821-i2c.o \
+		       cx25821-gpio.o cx25821-medusa-video.o \
+		       cx25821-video.o cx25821-video-upstream.o \
+		       cx25821-video-upstream-ch2.o \
+		       cx25821-audio-upstream.o
 
 obj-$(CONFIG_VIDEO_CX25821) += cx25821.o
 obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o
diff --git a/drivers/staging/cx25821/cx25821-alsa.c b/drivers/staging/cx25821/cx25821-alsa.c
index 1798975..a43b188 100644
--- a/drivers/staging/cx25821/cx25821-alsa.c
+++ b/drivers/staging/cx25821/cx25821-alsa.c
@@ -55,6 +55,12 @@
 static struct snd_card *snd_cx25821_cards[SNDRV_CARDS];
 static int devno;
 
+struct cx25821_audio_buffer {
+	unsigned int bpl;
+	struct btcx_riscmem risc;
+	struct videobuf_dmabuf dma;
+};
+
 struct cx25821_audio_dev {
 	struct cx25821_dev *dev;
 	struct cx25821_dmaqueue q;
@@ -77,7 +83,7 @@
 
 	struct videobuf_dmabuf *dma_risc;
 
-	struct cx25821_buffer *buf;
+	struct cx25821_audio_buffer *buf;
 
 	struct snd_pcm_substream *substream;
 };
@@ -136,7 +142,7 @@
 
 static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip)
 {
-	struct cx25821_buffer *buf = chip->buf;
+	struct cx25821_audio_buffer *buf = chip->buf;
 	struct cx25821_dev *dev = chip->dev;
 	struct sram_channel *audio_ch =
 	    &cx25821_sram_channels[AUDIO_SRAM_CHANNEL];
@@ -331,7 +337,7 @@
 	BUG_ON(!chip->dma_size);
 
 	dprintk(2, "Freeing buffer\n");
-	videobuf_sg_dma_unmap(&chip->pci->dev, chip->dma_risc);
+	videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
 	videobuf_dma_free(chip->dma_risc);
 	btcx_riscmem_free(chip->pci, &chip->buf->risc);
 	kfree(chip->buf);
@@ -432,7 +438,7 @@
 	struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
 	struct videobuf_dmabuf *dma;
 
-	struct cx25821_buffer *buf;
+	struct cx25821_audio_buffer *buf;
 	int ret;
 
 	if (substream->runtime->dma_area) {
@@ -447,36 +453,31 @@
 	BUG_ON(!chip->dma_size);
 	BUG_ON(chip->num_periods & (chip->num_periods - 1));
 
-	buf = videobuf_sg_alloc(sizeof(*buf));
+	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
 	if (NULL == buf)
 		return -ENOMEM;
 
 	if (chip->period_size > AUDIO_LINE_SIZE)
 		chip->period_size = AUDIO_LINE_SIZE;
 
-	buf->vb.memory = V4L2_MEMORY_MMAP;
-	buf->vb.field = V4L2_FIELD_NONE;
-	buf->vb.width = chip->period_size;
 	buf->bpl = chip->period_size;
-	buf->vb.height = chip->num_periods;
-	buf->vb.size = chip->dma_size;
 
-	dma = videobuf_to_dma(&buf->vb);
+	dma = &buf->dma;
 	videobuf_dma_init(dma);
-
 	ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
-				       (PAGE_ALIGN(buf->vb.size) >>
+				       (PAGE_ALIGN(chip->dma_size) >>
 					PAGE_SHIFT));
 	if (ret < 0)
 		goto error;
 
-	ret = videobuf_sg_dma_map(&chip->pci->dev, dma);
+	ret = videobuf_dma_map(&chip->pci->dev, dma);
 	if (ret < 0)
 		goto error;
 
 	ret =
 	    cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist,
-					  buf->vb.width, buf->vb.height, 1);
+					  chip->period_size, chip->num_periods,
+					  1);
 	if (ret < 0) {
 		printk(KERN_INFO
 			"DEBUG: ERROR after cx25821_risc_databuffer_audio()\n");
@@ -488,12 +489,10 @@
 	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
 
-	buf->vb.state = VIDEOBUF_PREPARED;
-
 	chip->buf = buf;
 	chip->dma_risc = dma;
 
-	substream->runtime->dma_area = chip->dma_risc->vmalloc;
+	substream->runtime->dma_area = chip->dma_risc->vaddr;
 	substream->runtime->dma_bytes = chip->dma_size;
 	substream->runtime->dma_addr = 0;
 
diff --git a/drivers/staging/cx25821/cx25821-audio-upstream.c b/drivers/staging/cx25821/cx25821-audio-upstream.c
index eb39d13..cdff49f 100644
--- a/drivers/staging/cx25821/cx25821-audio-upstream.c
+++ b/drivers/staging/cx25821/cx25821-audio-upstream.c
@@ -106,7 +106,7 @@
 {
 	unsigned int line;
 	struct sram_channel *sram_ch =
-	    &dev->sram_channels[dev->_audio_upstream_channel_select];
+	   dev->channels[dev->_audio_upstream_channel_select].sram_channels;
 	int offset = 0;
 
 	/* scan lines */
@@ -217,7 +217,7 @@
 void cx25821_stop_upstream_audio(struct cx25821_dev *dev)
 {
 	struct sram_channel *sram_ch =
-	    &dev->sram_channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B];
+	   dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels;
 	u32 tmp = 0;
 
 	if (!dev->_audio_is_running) {
@@ -287,14 +287,14 @@
 		return PTR_ERR(myfile);
 	} else {
 		if (!(myfile->f_op)) {
-			printk("%s: File has no file operations registered!\n",
+			printk(KERN_ERR "%s: File has no file operations registered!\n",
 			       __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
 		}
 
 		if (!myfile->f_op->read) {
-			printk("%s: File has no READ operations registered!\n",
+			printk(KERN_ERR "%s: File has no READ operations registered!\n",
 			       __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
@@ -353,8 +353,9 @@
 	}
 
 	cx25821_get_audio_data(dev,
-			       &dev->sram_channels[dev->
-						   _audio_upstream_channel_select]);
+			      dev->channels[dev->
+				       _audio_upstream_channel_select].
+				       sram_channels);
 }
 
 int cx25821_openfile_audio(struct cx25821_dev *dev,
@@ -378,14 +379,14 @@
 		return PTR_ERR(myfile);
 	} else {
 		if (!(myfile->f_op)) {
-			printk("%s: File has no file operations registered!\n",
+			printk(KERN_ERR "%s: File has no file operations registered!\n",
 			       __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
 		}
 
 		if (!myfile->f_op->read) {
-			printk("%s: File has no READ operations registered!\n",
+			printk(KERN_ERR "%s: File has no READ operations registered!\n",
 			       __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
@@ -505,7 +506,7 @@
 {
 	int i = 0;
 	u32 int_msk_tmp;
-	struct sram_channel *channel = &dev->sram_channels[chan_num];
+       struct sram_channel *channel = dev->channels[chan_num].sram_channels;
 	dma_addr_t risc_phys_jump_addr;
 	__le32 *rp;
 
@@ -569,15 +570,15 @@
 		spin_unlock(&dev->slock);
 	} else {
 		if (status & FLD_AUD_SRC_OF)
-			printk("%s: Audio Received Overflow Error Interrupt!\n",
+			printk(KERN_WARNING "%s: Audio Received Overflow Error Interrupt!\n",
 			       __func__);
 
 		if (status & FLD_AUD_SRC_SYNC)
-			printk("%s: Audio Received Sync Error Interrupt!\n",
+			printk(KERN_WARNING "%s: Audio Received Sync Error Interrupt!\n",
 			       __func__);
 
 		if (status & FLD_AUD_SRC_OPC_ERR)
-			printk("%s: Audio Received OpCode Error Interrupt!\n",
+			printk(KERN_WARNING "%s: Audio Received OpCode Error Interrupt!\n",
 			       __func__);
 
 		/* Read and write back the interrupt status register to clear
@@ -586,7 +587,7 @@
 	}
 
 	if (dev->_audiofile_status == END_OF_FILE) {
-		printk("cx25821: EOF Channel Audio Framecount = %d\n",
+		printk(KERN_WARNING "cx25821: EOF Channel Audio Framecount = %d\n",
 		       dev->_audioframe_count);
 		return -1;
 	}
@@ -607,7 +608,8 @@
 	if (!dev)
 		return -1;
 
-	sram_ch = &dev->sram_channels[dev->_audio_upstream_channel_select];
+       sram_ch = dev->channels[dev->_audio_upstream_channel_select].
+				       sram_channels;
 
 	msk_stat = cx_read(sram_ch->int_mstat);
 	audio_status = cx_read(sram_ch->int_stat);
@@ -644,8 +646,8 @@
 
 		/* 10 millisecond timeout */
 		if (count++ > 1000) {
-			printk
-			    ("cx25821 ERROR: %s() fifo is NOT turned on. Timeout!\n",
+			printk(KERN_ERR
+			       "cx25821 ERROR: %s() fifo is NOT turned on. Timeout!\n",
 			     __func__);
 			return;
 		}
@@ -726,12 +728,12 @@
 	int str_length = 0;
 
 	if (dev->_audio_is_running) {
-		printk("Audio Channel is still running so return!\n");
+		printk(KERN_WARNING "Audio Channel is still running so return!\n");
 		return 0;
 	}
 
 	dev->_audio_upstream_channel_select = channel_select;
-	sram_ch = &dev->sram_channels[channel_select];
+       sram_ch = dev->channels[channel_select].sram_channels;
 
 	/* Work queue */
 	INIT_WORK(&dev->_audio_work_entry, cx25821_audioups_handler);
diff --git a/drivers/staging/cx25821/cx25821-audio.h b/drivers/staging/cx25821/cx25821-audio.h
index 503f42f..434b2a3 100644
--- a/drivers/staging/cx25821/cx25821-audio.h
+++ b/drivers/staging/cx25821/cx25821-audio.h
@@ -27,24 +27,25 @@
 #define LINES_PER_BUFFER            15
 #define AUDIO_LINE_SIZE             128
 
-//Number of buffer programs to use at once.
+/* Number of buffer programs to use at once. */
 #define NUMBER_OF_PROGRAMS  8
 
-//Max size of the RISC program for a buffer. - worst case is 2 writes per line
-// Space is also added for the 4 no-op instructions added on the end.
-
+/*
+  Max size of the RISC program for a buffer. - worst case is 2 writes per line
+  Space is also added for the 4 no-op instructions added on the end.
+*/
 #ifndef USE_RISC_NOOP
 #define MAX_BUFFER_PROGRAM_SIZE     \
     (2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE*4)
 #endif
 
-// MAE 12 July 2005 Try to use NOOP RISC instruction instead
+/* MAE 12 July 2005 Try to use NOOP RISC instruction instead */
 #ifdef USE_RISC_NOOP
 #define MAX_BUFFER_PROGRAM_SIZE     \
     (2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_NOOP_INSTRUCTION_SIZE*4)
 #endif
 
-//Sizes of various instructions in bytes.  Used when adding instructions.
+/* Sizes of various instructions in bytes.  Used when adding instructions. */
 #define RISC_WRITE_INSTRUCTION_SIZE 12
 #define RISC_JUMP_INSTRUCTION_SIZE  12
 #define RISC_SKIP_INSTRUCTION_SIZE  4
diff --git a/drivers/staging/cx25821/cx25821-audups11.c b/drivers/staging/cx25821/cx25821-audups11.c
deleted file mode 100644
index e49ead9..0000000
--- a/drivers/staging/cx25821/cx25821-audups11.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/slab.h>
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-	struct cx25821_buffer *buf =
-	    container_of(vb, struct cx25821_buffer, vb);
-	struct cx25821_buffer *prev;
-	struct cx25821_fh *fh = vq->priv_data;
-	struct cx25821_dev *dev = fh->dev;
-	struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH11];
-
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
-
-	dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-	if (!list_empty(&q->queued)) {
-		list_add_tail(&buf->vb.queue, &q->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-			buf->vb.i);
-
-	} else if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx25821_start_video_dma(dev, q, buf,
-					&dev->sram_channels[SRAM_CH11]);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count = q->count++;
-		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-		dprintk(2,
-			"[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-			buf, buf->vb.i, buf->count, q->count);
-	} else {
-		prev =
-		    list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-		if (prev->vb.width == buf->vb.width
-		    && prev->vb.height == buf->vb.height
-		    && prev->fmt == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-			/* 64 bit bits 63-32 */
-			prev->risc.jmp[2] = cpu_to_le32(0);
-			dprintk(2,
-				"[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-				buf, buf->vb.i, buf->count);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &q->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-				buf->vb.i);
-		}
-	}
-
-	if (list_empty(&q->active)) {
-		dprintk(2, "active queue empty!\n");
-	}
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = cx25821_buffer_setup,
-	.buf_prepare = cx25821_buffer_prepare,
-	.buf_queue = buffer_queue,
-	.buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct cx25821_dev *dev = video_drvdata(file);
-	struct cx25821_fh *fh;
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-	printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-		v4l2_type_names[type]);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-
-	lock_kernel();
-
-	file->private_data = fh;
-	fh->dev = dev;
-	fh->type = type;
-	fh->width = 720;
-
-	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-		fh->height = 576;
-	else
-		fh->height = 480;
-
-	dev->channel_opened = 10;
-	fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
-
-	v4l2_prio_open(&dev->prio, &fh->prio);
-
-	videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-			       &dev->pci->dev, &dev->slock,
-			       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			       V4L2_FIELD_INTERLACED,
-			       sizeof(struct cx25821_buffer), fh);
-
-	dprintk(1, "post videobuf_queue_init()\n");
-	unlock_kernel();
-
-	return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-			  loff_t * ppos)
-{
-	struct cx25821_fh *fh = file->private_data;
-
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO11))
-			return -EBUSY;
-
-		return videobuf_read_one(&fh->vidq, data, count, ppos,
-					 file->f_flags & O_NONBLOCK);
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static unsigned int video_poll(struct file *file,
-			       struct poll_table_struct *wait)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_buffer *buf;
-
-	if (cx25821_res_check(fh, RESOURCE_VIDEO11)) {
-		/* streaming capture */
-		if (list_empty(&fh->vidq.stream))
-			return POLLERR;
-		buf = list_entry(fh->vidq.stream.next,
-				 struct cx25821_buffer, vb.stream);
-	} else {
-		/* read() capture */
-		buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-		if (NULL == buf)
-			return POLLERR;
-	}
-
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-static int video_release(struct file *file)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-
-	//stop the risc engine and fifo
-	//cx_write(channel11->dma_ctl, 0);
-
-	/* stop video capture */
-	if (cx25821_res_check(fh, RESOURCE_VIDEO11)) {
-		videobuf_queue_cancel(&fh->vidq);
-		cx25821_res_free(dev, fh, RESOURCE_VIDEO11);
-	}
-
-	if (fh->vidq.read_buf) {
-		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-		kfree(fh->vidq.read_buf);
-	}
-
-	videobuf_mmap_free(&fh->vidq);
-
-	v4l2_prio_close(&dev->prio, fh->prio);
-
-	file->private_data = NULL;
-	kfree(fh);
-
-	return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-
-	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(i != fh->type)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO11)))) {
-		return -EBUSY;
-	}
-
-	return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-	int err, res;
-
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	res = cx25821_get_resource(fh, RESOURCE_VIDEO11);
-	err = videobuf_streamoff(get_queue(fh));
-	if (err < 0)
-		return err;
-	cx25821_res_free(dev, fh, res);
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	dprintk(2, "%s()\n", __func__);
-	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-	if (0 != err)
-		return err;
-	fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-	fh->width = f->fmt.pix.width;
-	fh->height = f->fmt.pix.height;
-	fh->vidq.field = f->fmt.pix.field;
-	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-		fh->height, fh->vidq.field);
-	cx25821_call_all(dev, video, s_fmt, f);
-	return 0;
-}
-
-static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
-				   unsigned long arg)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-	int command = 0;
-	struct upstream_user_struct *data_from_user;
-
-	data_from_user = (struct upstream_user_struct *)arg;
-
-	if (!data_from_user) {
-		printk
-		    ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
-		     __func__);
-		return 0;
-	}
-
-	command = data_from_user->command;
-
-	if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO) {
-		return 0;
-	}
-
-	dev->input_filename = data_from_user->input_filename;
-	dev->input_audiofilename = data_from_user->input_filename;
-	dev->vid_stdname = data_from_user->vid_stdname;
-	dev->pixel_format = data_from_user->pixel_format;
-	dev->channel_select = data_from_user->channel_select;
-	dev->command = data_from_user->command;
-
-	switch (command) {
-	case UPSTREAM_START_AUDIO:
-		cx25821_start_upstream_audio(dev, data_from_user);
-		break;
-
-	case UPSTREAM_STOP_AUDIO:
-		cx25821_stop_upstream_audio(dev);
-		break;
-	}
-
-	return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	struct cx25821_fh *fh = priv;
-	return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	char name[32 + 2];
-
-	snprintf(name, sizeof(name), "%s/2", dev->name);
-	printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-	       dev->name);
-	cx25821_call_all(dev, core, log_status);
-	printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-	       dev->name);
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctl)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev;
-	int err;
-
-	if (fh) {
-		dev = fh->dev;
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-	return 0;
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-	.owner = THIS_MODULE,
-	.open = video_open,
-	.release = video_release,
-	.read = video_read,
-	.poll = video_poll,
-	.mmap = cx25821_video_mmap,
-	.ioctl = video_ioctl_upstream11,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = cx25821_vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
-	.vidioc_querybuf = cx25821_vidioc_querybuf,
-	.vidioc_qbuf = cx25821_vidioc_qbuf,
-	.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-	.vidioc_s_std = cx25821_vidioc_s_std,
-	.vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-	.vidioc_cropcap = cx25821_vidioc_cropcap,
-	.vidioc_s_crop = cx25821_vidioc_s_crop,
-	.vidioc_g_crop = cx25821_vidioc_g_crop,
-	.vidioc_enum_input = cx25821_vidioc_enum_input,
-	.vidioc_g_input = cx25821_vidioc_g_input,
-	.vidioc_s_input = cx25821_vidioc_s_input,
-	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
-	.vidioc_streamon = vidioc_streamon,
-	.vidioc_streamoff = vidioc_streamoff,
-	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = cx25821_vidioc_g_priority,
-	.vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
-	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
-	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
-	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = cx25821_vidioc_g_register,
-	.vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template11 = {
-	.name = "cx25821-audioupstream",
-	.fops = &video_fops,
-	.ioctl_ops = &video_ioctl_ops,
-	.tvnorms = CX25821_NORMS,
-	.current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-core.c b/drivers/staging/cx25821/cx25821-core.c
index d90abb3..c487c19 100644
--- a/drivers/staging/cx25821/cx25821-core.c
+++ b/drivers/staging/cx25821/cx25821-core.c
@@ -781,14 +781,14 @@
 
 	/* Disable Video A/B activity */
 	for (i = 0; i < VID_CHANNEL_NUM; i++) {
-		cx_write(dev->sram_channels[i].dma_ctl, 0);
-		cx_write(dev->sram_channels[i].int_msk, 0);
+	       cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
+	       cx_write(dev->channels[i].sram_channels->int_msk, 0);
 	}
 
 	for (i = VID_UPSTREAM_SRAM_CHANNEL_I; i <= VID_UPSTREAM_SRAM_CHANNEL_J;
 	     i++) {
-		cx_write(dev->sram_channels[i].dma_ctl, 0);
-		cx_write(dev->sram_channels[i].int_msk, 0);
+	       cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
+	       cx_write(dev->channels[i].sram_channels->int_msk, 0);
 	}
 
 	/* Disable Audio activity */
@@ -805,12 +805,10 @@
 void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select,
 			      u32 format)
 {
-	struct sram_channel *ch;
-
 	if (channel_select <= 7 && channel_select >= 0) {
-		ch = &cx25821_sram_channels[channel_select];
-		cx_write(ch->pix_frmt, format);
-		dev->pixel_formats[channel_select] = format;
+	       cx_write(dev->channels[channel_select].
+			       sram_channels->pix_frmt, format);
+	       dev->channels[channel_select].pixel_formats = format;
 	}
 }
 
@@ -831,7 +829,7 @@
 	cx_write(PCI_INT_STAT, 0xffffffff);
 
 	for (i = 0; i < VID_CHANNEL_NUM; i++)
-		cx_write(dev->sram_channels[i].int_stat, 0xffffffff);
+	       cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff);
 
 	cx_write(AUD_A_INT_STAT, 0xffffffff);
 	cx_write(AUD_B_INT_STAT, 0xffffffff);
@@ -845,21 +843,22 @@
 	mdelay(100);
 
 	for (i = 0; i < VID_CHANNEL_NUM; i++) {
-		cx25821_set_vip_mode(dev, &dev->sram_channels[i]);
-		cx25821_sram_channel_setup(dev, &dev->sram_channels[i], 1440,
-					   0);
-		dev->pixel_formats[i] = PIXEL_FRMT_422;
-		dev->use_cif_resolution[i] = FALSE;
+	       cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
+	       cx25821_sram_channel_setup(dev, dev->channels[i].sram_channels,
+					       1440, 0);
+	       dev->channels[i].pixel_formats = PIXEL_FRMT_422;
+	       dev->channels[i].use_cif_resolution = FALSE;
 	}
 
 	/* Probably only affect Downstream */
 	for (i = VID_UPSTREAM_SRAM_CHANNEL_I; i <= VID_UPSTREAM_SRAM_CHANNEL_J;
 	     i++) {
-		cx25821_set_vip_mode(dev, &dev->sram_channels[i]);
+	       cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
 	}
 
-	cx25821_sram_channel_setup_audio(dev, &dev->sram_channels[SRAM_CH08],
-					 128, 0);
+       cx25821_sram_channel_setup_audio(dev,
+			       dev->channels[SRAM_CH08].sram_channels,
+			       128, 0);
 
 	cx25821_gpio_init(dev);
 }
@@ -902,21 +901,6 @@
 {
 	int io_size = 0, i;
 
-	struct video_device *video_template[] = {
-		&cx25821_video_template0,
-		&cx25821_video_template1,
-		&cx25821_video_template2,
-		&cx25821_video_template3,
-		&cx25821_video_template4,
-		&cx25821_video_template5,
-		&cx25821_video_template6,
-		&cx25821_video_template7,
-		&cx25821_video_template9,
-		&cx25821_video_template10,
-		&cx25821_video_template11,
-		&cx25821_videoioctl_template,
-	};
-
 	printk(KERN_INFO "\n***********************************\n");
 	printk(KERN_INFO "cx25821 set up\n");
 	printk(KERN_INFO "***********************************\n\n");
@@ -947,7 +931,8 @@
 
 	/* Apply a sensible clock frequency for the PCIe bridge */
 	dev->clk_freq = 28000000;
-	dev->sram_channels = cx25821_sram_channels;
+       for (i = 0; i < MAX_VID_CHANNEL_NUM; i++)
+	       dev->channels[i].sram_channels = &cx25821_sram_channels[i];
 
 	if (dev->nr > 1)
 		CX25821_INFO("dev->nr > 1!");
@@ -970,7 +955,6 @@
 	dev->i2c_bus[0].reg_wdata = I2C1_WDATA;
 	dev->i2c_bus[0].i2c_period = (0x07 << 24);	/* 1.95MHz */
 
-
 	if (cx25821_get_resources(dev) < 0) {
 		printk(KERN_ERR "%s No more PCIe resources for "
 		       "subsystem: %04x:%04x\n",
@@ -1018,37 +1002,24 @@
 		     dev->i2c_bus[0].i2c_rc);
 
 	cx25821_card_setup(dev);
-	medusa_video_init(dev);
 
-	for (i = 0; i < VID_CHANNEL_NUM; i++) {
-		if (cx25821_video_register(dev, i, video_template[i]) < 0) {
-			printk(KERN_ERR
-			       "%s() Failed to register analog video adapters on VID channel %d\n",
-			       __func__, i);
-		}
-	}
+       if (medusa_video_init(dev) < 0)
+	       CX25821_ERR("%s() Failed to initialize medusa!\n"
+	       , __func__);
 
-	for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
-	     i <= AUDIO_UPSTREAM_SRAM_CHANNEL_B; i++) {
-		/* Since we don't have template8 for Audio Downstream */
-		if (cx25821_video_register(dev, i, video_template[i - 1]) < 0) {
-			printk(KERN_ERR
-			       "%s() Failed to register analog video adapters for Upstream channel %d.\n",
-			       __func__, i);
-		}
-	}
+       cx25821_video_register(dev);
 
 	/* register IOCTL device */
 	dev->ioctl_dev =
-	    cx25821_vdev_init(dev, dev->pci, video_template[VIDEO_IOCTL_CH],
+	   cx25821_vdev_init(dev, dev->pci, &cx25821_videoioctl_template,
 			      "video");
 
 	if (video_register_device
 	    (dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) {
 		cx25821_videoioctl_unregister(dev);
 		printk(KERN_ERR
-		       "%s() Failed to register video adapter for IOCTL so releasing.\n",
-		       __func__);
+		   "%s() Failed to register video adapter for IOCTL, so \
+		   unregistering videoioctl device.\n", __func__);
 	}
 
 	cx25821_dev_checkrevision(dev);
@@ -1349,7 +1320,7 @@
 
 	BUG_ON(in_interrupt());
 	videobuf_waiton(&buf->vb, 0, 0);
-	videobuf_dma_unmap(q, dma);
+	videobuf_dma_unmap(q->dev, dma);
 	videobuf_dma_free(dma);
 	btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -1371,7 +1342,8 @@
 
 	for (i = 0; i < VID_CHANNEL_NUM; i++) {
 		if (pci_status & mask[i]) {
-			vid_status = cx_read(dev->sram_channels[i].int_stat);
+		       vid_status = cx_read(dev->channels[i].
+			       sram_channels->int_stat);
 
 			if (vid_status)
 				handled +=
diff --git a/drivers/staging/cx25821/cx25821-i2c.c b/drivers/staging/cx25821/cx25821-i2c.c
index 08f45b5..e43572e 100644
--- a/drivers/staging/cx25821/cx25821-i2c.c
+++ b/drivers/staging/cx25821/cx25821-i2c.c
@@ -282,6 +282,9 @@
 static struct i2c_algorithm cx25821_i2c_algo_template = {
 	.master_xfer = i2c_xfer,
 	.functionality = cx25821_functionality,
+#ifdef NEED_ALGO_CONTROL
+       .algo_control = dummy_algo_control,
+#endif
 };
 
 static struct i2c_adapter cx25821_i2c_adap_template = {
diff --git a/drivers/staging/cx25821/cx25821-medusa-defines.h b/drivers/staging/cx25821/cx25821-medusa-defines.h
index b0d216b..60d197f 100644
--- a/drivers/staging/cx25821/cx25821-medusa-defines.h
+++ b/drivers/staging/cx25821/cx25821-medusa-defines.h
@@ -23,7 +23,7 @@
 #ifndef _MEDUSA_DEF_H_
 #define _MEDUSA_DEF_H_
 
-// Video deocder that we supported
+/* Video deocder that we supported */
 #define VDEC_A		0
 #define VDEC_B		1
 #define VDEC_C		2
@@ -33,19 +33,10 @@
 #define VDEC_G		6
 #define VDEC_H		7
 
-//#define AUTO_SWITCH_BIT[]  = { 8, 9, 10, 11, 12, 13, 14, 15 };
-
-// The following bit position enables automatic source switching for decoder A-H.
-// Display index per camera.
-//#define VDEC_INDEX[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7};
-
-// Select input bit to video decoder A-H.
-//#define CH_SRC_SEL_BIT[] = {24, 25, 26, 27, 28, 29, 30, 31};
-
-// end of display sequence
+/* end of display sequence */
 #define END_OF_SEQ					0xF;
 
-// registry string size
+/* registry string size */
 #define MAX_REGISTRY_SZ					40;
 
 #endif
diff --git a/drivers/staging/cx25821/cx25821-medusa-reg.h b/drivers/staging/cx25821/cx25821-medusa-reg.h
index 12c90f8..f7f33b3 100644
--- a/drivers/staging/cx25821/cx25821-medusa-reg.h
+++ b/drivers/staging/cx25821/cx25821-medusa-reg.h
@@ -23,11 +23,11 @@
 #ifndef __MEDUSA_REGISTERS__
 #define __MEDUSA_REGISTERS__
 
-// Serial Slave Registers
+/* Serial Slave Registers */
 #define	HOST_REGISTER1				0x0000
 #define	HOST_REGISTER2				0x0001
 
-// Chip Configuration Registers
+/* Chip Configuration Registers */
 #define	CHIP_CTRL					0x0100
 #define	AFE_AB_CTRL					0x0104
 #define	AFE_CD_CTRL					0x0108
@@ -92,7 +92,7 @@
 #define	ABIST_CLAMP_E				0x01F4
 #define	ABIST_CLAMP_F				0x01F8
 
-//              Digital Video Encoder A Registers
+/*              Digital Video Encoder A Registers */
 #define	DENC_A_REG_1					0x0200
 #define	DENC_A_REG_2					0x0204
 #define	DENC_A_REG_3					0x0208
@@ -102,7 +102,7 @@
 #define	DENC_A_REG_7					0x0218
 #define	DENC_A_REG_8					0x021C
 
-//      Digital Video Encoder B Registers
+/*      Digital Video Encoder B Registers */
 #define	DENC_B_REG_1					0x0300
 #define	DENC_B_REG_2					0x0304
 #define	DENC_B_REG_3					0x0308
@@ -112,7 +112,7 @@
 #define	DENC_B_REG_7					0x0318
 #define	DENC_B_REG_8					0x031C
 
-//              Video Decoder A Registers
+/*              Video Decoder A Registers */
 #define	MODE_CTRL						0x1000
 #define	OUT_CTRL1						0x1004
 #define	OUT_CTRL_NS						0x1008
@@ -153,7 +153,7 @@
 #define	VERSION							0x11F8
 #define	SOFT_RST_CTRL					0x11FC
 
-//      Video Decoder B Registers
+/*      Video Decoder B Registers */
 #define	VDEC_B_MODE_CTRL				0x1200
 #define	VDEC_B_OUT_CTRL1				0x1204
 #define	VDEC_B_OUT_CTRL_NS				0x1208
@@ -194,7 +194,7 @@
 #define	VDEC_B_VERSION					0x13F8
 #define	VDEC_B_SOFT_RST_CTRL			0x13FC
 
-// Video Decoder C Registers
+/* Video Decoder C Registers */
 #define	VDEC_C_MODE_CTRL				0x1400
 #define	VDEC_C_OUT_CTRL1				0x1404
 #define	VDEC_C_OUT_CTRL_NS				0x1408
@@ -235,7 +235,7 @@
 #define	VDEC_C_VERSION					0x15F8
 #define	VDEC_C_SOFT_RST_CTRL			0x15FC
 
-// Video Decoder D Registers
+/* Video Decoder D Registers */
 #define VDEC_D_MODE_CTRL				0x1600
 #define VDEC_D_OUT_CTRL1				0x1604
 #define VDEC_D_OUT_CTRL_NS				0x1608
@@ -276,7 +276,7 @@
 #define VDEC_D_VERSION					0x17F8
 #define VDEC_D_SOFT_RST_CTRL			0x17FC
 
-// Video Decoder E Registers
+/* Video Decoder E Registers */
 #define	VDEC_E_MODE_CTRL				0x1800
 #define	VDEC_E_OUT_CTRL1				0x1804
 #define	VDEC_E_OUT_CTRL_NS				0x1808
@@ -317,7 +317,7 @@
 #define	VDEC_E_VERSION					0x19F8
 #define	VDEC_E_SOFT_RST_CTRL			0x19FC
 
-// Video Decoder F Registers
+/* Video Decoder F Registers */
 #define	VDEC_F_MODE_CTRL				0x1A00
 #define	VDEC_F_OUT_CTRL1				0x1A04
 #define	VDEC_F_OUT_CTRL_NS				0x1A08
@@ -358,7 +358,7 @@
 #define	VDEC_F_VERSION					0x1BF8
 #define	VDEC_F_SOFT_RST_CTRL			0x1BFC
 
-// Video Decoder G Registers
+/* Video Decoder G Registers */
 #define	VDEC_G_MODE_CTRL				0x1C00
 #define	VDEC_G_OUT_CTRL1				0x1C04
 #define	VDEC_G_OUT_CTRL_NS				0x1C08
@@ -399,7 +399,7 @@
 #define	VDEC_G_VERSION					0x1DF8
 #define	VDEC_G_SOFT_RST_CTRL			0x1DFC
 
-//              Video Decoder H Registers
+/*              Video Decoder H Registers  */
 #define	VDEC_H_MODE_CTRL				0x1E00
 #define	VDEC_H_OUT_CTRL1				0x1E04
 #define	VDEC_H_OUT_CTRL_NS				0x1E08
@@ -440,14 +440,14 @@
 #define	VDEC_H_VERSION					0x1FF8
 #define	VDEC_H_SOFT_RST_CTRL			0x1FFC
 
-//*****************************************************************************
-// LUMA_CTRL register fields
+/*****************************************************************************/
+/* LUMA_CTRL register fields */
 #define VDEC_A_BRITE_CTRL				0x1014
 #define VDEC_A_CNTRST_CTRL       		0x1015
 #define VDEC_A_PEAK_SEL          		0x1016
 
-//*****************************************************************************
-// CHROMA_CTRL register fields
+/*****************************************************************************/
+/* CHROMA_CTRL register fields */
 #define VDEC_A_USAT_CTRL         		0x1018
 #define VDEC_A_VSAT_CTRL         		0x1019
 #define VDEC_A_HUE_CTRL          		0x101A
diff --git a/drivers/staging/cx25821/cx25821-medusa-video.c b/drivers/staging/cx25821/cx25821-medusa-video.c
index 34616dc..ef9f2b8 100644
--- a/drivers/staging/cx25821/cx25821-medusa-video.c
+++ b/drivers/staging/cx25821/cx25821-medusa-video.c
@@ -778,9 +778,9 @@
 
 int medusa_video_init(struct cx25821_dev *dev)
 {
-	u32 value, tmp = 0;
-	int ret_val;
-	int i;
+       u32 value = 0, tmp = 0;
+       int ret_val = 0;
+       int i = 0;
 
 	mutex_lock(&dev->lock);
 
@@ -790,6 +790,7 @@
 	value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp);
 	value &= 0xFFFFF0FF;
 	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value);
+
 	if (ret_val < 0)
 		goto error;
 
@@ -797,6 +798,7 @@
 	value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp);
 	value &= 0xFFFFFFDF;
 	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value);
+
 	if (ret_val < 0)
 		goto error;
 
@@ -812,6 +814,7 @@
 	value &= 0xFF70FF70;
 	value |= 0x00090008;	/* set en_active */
 	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], DENC_AB_CTRL, value);
+
 	if (ret_val < 0)
 		goto error;
 
@@ -826,8 +829,10 @@
 	/* select AFE clock to output mode */
 	value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp);
 	value &= 0x83FFFFFF;
-	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
-				    value | 0x10000000);
+       ret_val =
+	   cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
+			     value | 0x10000000);
+
 	if (ret_val < 0)
 		goto error;
 
@@ -849,12 +854,15 @@
 
 	value |= 7;
 	ret_val = cx25821_i2c_write(&dev->i2c_bus[0], PIN_OE_CTRL, value);
+
 	if (ret_val < 0)
 		goto error;
 
+
 	mutex_unlock(&dev->lock);
 
 	ret_val = medusa_set_videostandard(dev);
+
 	return ret_val;
 
 error:
diff --git a/drivers/staging/cx25821/cx25821-medusa-video.h b/drivers/staging/cx25821/cx25821-medusa-video.h
index 2fab4b2..6175e09 100644
--- a/drivers/staging/cx25821/cx25821-medusa-video.h
+++ b/drivers/staging/cx25821/cx25821-medusa-video.h
@@ -25,7 +25,7 @@
 
 #include "cx25821-medusa-defines.h"
 
-// Color control constants
+/* Color control constants */
 #define VIDEO_PROCAMP_MIN                 0
 #define VIDEO_PROCAMP_MAX                 10000
 #define UNSIGNED_BYTE_MIN                 0
@@ -33,7 +33,7 @@
 #define SIGNED_BYTE_MIN                   -128
 #define SIGNED_BYTE_MAX                   127
 
-// Default video color settings
+/* Default video color settings */
 #define SHARPNESS_DEFAULT                 50
 #define SATURATION_DEFAULT              5000
 #define BRIGHTNESS_DEFAULT              6200
diff --git a/drivers/staging/cx25821/cx25821-reg.h b/drivers/staging/cx25821/cx25821-reg.h
index 7241e7e..cfe0f32 100644
--- a/drivers/staging/cx25821/cx25821-reg.h
+++ b/drivers/staging/cx25821/cx25821-reg.h
@@ -48,24 +48,24 @@
 #define RISC_SYNC_EVEN_VBI	 0x00000207
 #define RISC_NOOP			 0xF0000000
 
-//*****************************************************************************
-// ASB SRAM
-//*****************************************************************************
-#define  TX_SRAM                   0x000000	// Transmit SRAM
+/*****************************************************************************
+* ASB SRAM
+ *****************************************************************************/
+#define  TX_SRAM                   0x000000	/* Transmit SRAM */
 
-//*****************************************************************************
-#define  RX_RAM                    0x010000	// Receive SRAM
+/*****************************************************************************/
+#define  RX_RAM                    0x010000	/* Receive SRAM */
 
-//*****************************************************************************
-// Application Layer (AL)
-//*****************************************************************************
-#define  DEV_CNTRL2                0x040000	// Device control
+/*****************************************************************************
+* Application Layer (AL)
+ *****************************************************************************/
+#define  DEV_CNTRL2                0x040000	/* Device control */
 #define  FLD_RUN_RISC              0x00000020
 
-//*****************************************************************************
-#define  PCI_INT_MSK               0x040010	// PCI interrupt mask
-#define  PCI_INT_STAT              0x040014	// PCI interrupt status
-#define  PCI_INT_MSTAT             0x040018	// PCI interrupt masked status
+/* ***************************************************************************** */
+#define  PCI_INT_MSK               0x040010	/* PCI interrupt mask */
+#define  PCI_INT_STAT              0x040014	/* PCI interrupt status */
+#define  PCI_INT_MSTAT             0x040018	/* PCI interrupt masked status */
 #define  FLD_HAMMERHEAD_INT        (1 << 27)
 #define  FLD_UART_INT              (1 << 26)
 #define  FLD_IRQN_INT              (1 << 25)
@@ -93,65 +93,65 @@
 #define  FLD_VID_B_INT             (1 << 1)
 #define  FLD_VID_A_INT             (1 << 0)
 
-//*****************************************************************************
-#define  VID_A_INT_MSK             0x040020	// Video A interrupt mask
-#define  VID_A_INT_STAT            0x040024	// Video A interrupt status
-#define  VID_A_INT_MSTAT           0x040028	// Video A interrupt masked status
-#define  VID_A_INT_SSTAT           0x04002C	// Video A interrupt set status
+/* ***************************************************************************** */
+#define  VID_A_INT_MSK             0x040020	/* Video A interrupt mask */
+#define  VID_A_INT_STAT            0x040024	/* Video A interrupt status */
+#define  VID_A_INT_MSTAT           0x040028	/* Video A interrupt masked status */
+#define  VID_A_INT_SSTAT           0x04002C	/* Video A interrupt set status */
 
-//*****************************************************************************
-#define  VID_B_INT_MSK             0x040030	// Video B interrupt mask
-#define  VID_B_INT_STAT            0x040034	// Video B interrupt status
-#define  VID_B_INT_MSTAT           0x040038	// Video B interrupt masked status
-#define  VID_B_INT_SSTAT           0x04003C	// Video B interrupt set status
+/* ***************************************************************************** */
+#define  VID_B_INT_MSK             0x040030	/* Video B interrupt mask */
+#define  VID_B_INT_STAT            0x040034	/* Video B interrupt status */
+#define  VID_B_INT_MSTAT           0x040038	/* Video B interrupt masked status */
+#define  VID_B_INT_SSTAT           0x04003C	/* Video B interrupt set status */
 
-//*****************************************************************************
-#define  VID_C_INT_MSK             0x040040	// Video C interrupt mask
-#define  VID_C_INT_STAT            0x040044	// Video C interrupt status
-#define  VID_C_INT_MSTAT           0x040048	// Video C interrupt masked status
-#define  VID_C_INT_SSTAT           0x04004C	// Video C interrupt set status
+/* ***************************************************************************** */
+#define  VID_C_INT_MSK             0x040040	/* Video C interrupt mask */
+#define  VID_C_INT_STAT            0x040044	/* Video C interrupt status */
+#define  VID_C_INT_MSTAT           0x040048	/* Video C interrupt masked status */
+#define  VID_C_INT_SSTAT           0x04004C	/* Video C interrupt set status */
 
-//*****************************************************************************
-#define  VID_D_INT_MSK             0x040050	// Video D interrupt mask
-#define  VID_D_INT_STAT            0x040054	// Video D interrupt status
-#define  VID_D_INT_MSTAT           0x040058	// Video D interrupt masked status
-#define  VID_D_INT_SSTAT           0x04005C	// Video D interrupt set status
+/* ***************************************************************************** */
+#define  VID_D_INT_MSK             0x040050	/* Video D interrupt mask */
+#define  VID_D_INT_STAT            0x040054	/* Video D interrupt status */
+#define  VID_D_INT_MSTAT           0x040058	/* Video D interrupt masked status */
+#define  VID_D_INT_SSTAT           0x04005C	/* Video D interrupt set status */
 
-//*****************************************************************************
-#define  VID_E_INT_MSK             0x040060	// Video E interrupt mask
-#define  VID_E_INT_STAT            0x040064	// Video E interrupt status
-#define  VID_E_INT_MSTAT           0x040068	// Video E interrupt masked status
-#define  VID_E_INT_SSTAT           0x04006C	// Video E interrupt set status
+/* ***************************************************************************** */
+#define  VID_E_INT_MSK             0x040060	/* Video E interrupt mask */
+#define  VID_E_INT_STAT            0x040064	/* Video E interrupt status */
+#define  VID_E_INT_MSTAT           0x040068	/* Video E interrupt masked status */
+#define  VID_E_INT_SSTAT           0x04006C	/* Video E interrupt set status */
 
-//*****************************************************************************
-#define  VID_F_INT_MSK             0x040070	// Video F interrupt mask
-#define  VID_F_INT_STAT            0x040074	// Video F interrupt status
-#define  VID_F_INT_MSTAT           0x040078	// Video F interrupt masked status
-#define  VID_F_INT_SSTAT           0x04007C	// Video F interrupt set status
+/* ***************************************************************************** */
+#define  VID_F_INT_MSK             0x040070	/* Video F interrupt mask */
+#define  VID_F_INT_STAT            0x040074	/* Video F interrupt status */
+#define  VID_F_INT_MSTAT           0x040078	/* Video F interrupt masked status */
+#define  VID_F_INT_SSTAT           0x04007C	/* Video F interrupt set status */
 
-//*****************************************************************************
-#define  VID_G_INT_MSK             0x040080	// Video G interrupt mask
-#define  VID_G_INT_STAT            0x040084	// Video G interrupt status
-#define  VID_G_INT_MSTAT           0x040088	// Video G interrupt masked status
-#define  VID_G_INT_SSTAT           0x04008C	// Video G interrupt set status
+/* ***************************************************************************** */
+#define  VID_G_INT_MSK             0x040080	/* Video G interrupt mask */
+#define  VID_G_INT_STAT            0x040084	/* Video G interrupt status */
+#define  VID_G_INT_MSTAT           0x040088	/* Video G interrupt masked status */
+#define  VID_G_INT_SSTAT           0x04008C	/* Video G interrupt set status */
 
-//*****************************************************************************
-#define  VID_H_INT_MSK             0x040090	// Video H interrupt mask
-#define  VID_H_INT_STAT            0x040094	// Video H interrupt status
-#define  VID_H_INT_MSTAT           0x040098	// Video H interrupt masked status
-#define  VID_H_INT_SSTAT           0x04009C	// Video H interrupt set status
+/* ***************************************************************************** */
+#define  VID_H_INT_MSK             0x040090	/* Video H interrupt mask */
+#define  VID_H_INT_STAT            0x040094	/* Video H interrupt status */
+#define  VID_H_INT_MSTAT           0x040098	/* Video H interrupt masked status */
+#define  VID_H_INT_SSTAT           0x04009C	/* Video H interrupt set status */
 
-//*****************************************************************************
-#define  VID_I_INT_MSK             0x0400A0	// Video I interrupt mask
-#define  VID_I_INT_STAT            0x0400A4	// Video I interrupt status
-#define  VID_I_INT_MSTAT           0x0400A8	// Video I interrupt masked status
-#define  VID_I_INT_SSTAT           0x0400AC	// Video I interrupt set status
+/* ***************************************************************************** */
+#define  VID_I_INT_MSK             0x0400A0	/* Video I interrupt mask */
+#define  VID_I_INT_STAT            0x0400A4	/* Video I interrupt status */
+#define  VID_I_INT_MSTAT           0x0400A8	/* Video I interrupt masked status */
+#define  VID_I_INT_SSTAT           0x0400AC	/* Video I interrupt set status */
 
-//*****************************************************************************
-#define  VID_J_INT_MSK             0x0400B0	// Video J interrupt mask
-#define  VID_J_INT_STAT            0x0400B4	// Video J interrupt status
-#define  VID_J_INT_MSTAT           0x0400B8	// Video J interrupt masked status
-#define  VID_J_INT_SSTAT           0x0400BC	// Video J interrupt set status
+/* ***************************************************************************** */
+#define  VID_J_INT_MSK             0x0400B0	/* Video J interrupt mask */
+#define  VID_J_INT_STAT            0x0400B4	/* Video J interrupt status */
+#define  VID_J_INT_MSTAT           0x0400B8	/* Video J interrupt masked status */
+#define  VID_J_INT_SSTAT           0x0400BC	/* Video J interrupt set status */
 
 #define  FLD_VID_SRC_OPC_ERR       0x00020000
 #define  FLD_VID_DST_OPC_ERR       0x00010000
@@ -166,35 +166,35 @@
 #define  FLD_VID_SRC_ERRORS		FLD_VID_SRC_OPC_ERR | FLD_VID_SRC_SYNC | FLD_VID_SRC_UF
 #define  FLD_VID_DST_ERRORS		FLD_VID_DST_OPC_ERR | FLD_VID_DST_SYNC | FLD_VID_DST_OF
 
-//*****************************************************************************
-#define  AUD_A_INT_MSK             0x0400C0	// Audio Int interrupt mask
-#define  AUD_A_INT_STAT            0x0400C4	// Audio Int interrupt status
-#define  AUD_A_INT_MSTAT           0x0400C8	// Audio Int interrupt masked status
-#define  AUD_A_INT_SSTAT           0x0400CC	// Audio Int interrupt set status
+/* ***************************************************************************** */
+#define  AUD_A_INT_MSK             0x0400C0	/* Audio Int interrupt mask */
+#define  AUD_A_INT_STAT            0x0400C4	/* Audio Int interrupt status */
+#define  AUD_A_INT_MSTAT           0x0400C8	/* Audio Int interrupt masked status */
+#define  AUD_A_INT_SSTAT           0x0400CC	/* Audio Int interrupt set status */
 
-//*****************************************************************************
-#define  AUD_B_INT_MSK             0x0400D0	// Audio Int interrupt mask
-#define  AUD_B_INT_STAT            0x0400D4	// Audio Int interrupt status
-#define  AUD_B_INT_MSTAT           0x0400D8	// Audio Int interrupt masked status
-#define  AUD_B_INT_SSTAT           0x0400DC	// Audio Int interrupt set status
+/* ***************************************************************************** */
+#define  AUD_B_INT_MSK             0x0400D0	/* Audio Int interrupt mask */
+#define  AUD_B_INT_STAT            0x0400D4	/* Audio Int interrupt status */
+#define  AUD_B_INT_MSTAT           0x0400D8	/* Audio Int interrupt masked status */
+#define  AUD_B_INT_SSTAT           0x0400DC	/* Audio Int interrupt set status */
 
-//*****************************************************************************
-#define  AUD_C_INT_MSK             0x0400E0	// Audio Int interrupt mask
-#define  AUD_C_INT_STAT            0x0400E4	// Audio Int interrupt status
-#define  AUD_C_INT_MSTAT           0x0400E8	// Audio Int interrupt masked status
-#define  AUD_C_INT_SSTAT           0x0400EC	// Audio Int interrupt set status
+/* ***************************************************************************** */
+#define  AUD_C_INT_MSK             0x0400E0	/* Audio Int interrupt mask */
+#define  AUD_C_INT_STAT            0x0400E4	/* Audio Int interrupt status */
+#define  AUD_C_INT_MSTAT           0x0400E8	/* Audio Int interrupt masked status */
+#define  AUD_C_INT_SSTAT           0x0400EC	/* Audio Int interrupt set status */
 
-//*****************************************************************************
-#define  AUD_D_INT_MSK             0x0400F0	// Audio Int interrupt mask
-#define  AUD_D_INT_STAT            0x0400F4	// Audio Int interrupt status
-#define  AUD_D_INT_MSTAT           0x0400F8	// Audio Int interrupt masked status
-#define  AUD_D_INT_SSTAT           0x0400FC	// Audio Int interrupt set status
+/* ***************************************************************************** */
+#define  AUD_D_INT_MSK             0x0400F0	/* Audio Int interrupt mask */
+#define  AUD_D_INT_STAT            0x0400F4	/* Audio Int interrupt status */
+#define  AUD_D_INT_MSTAT           0x0400F8	/* Audio Int interrupt masked status */
+#define  AUD_D_INT_SSTAT           0x0400FC	/* Audio Int interrupt set status */
 
-//*****************************************************************************
-#define  AUD_E_INT_MSK             0x040100	// Audio Int interrupt mask
-#define  AUD_E_INT_STAT            0x040104	// Audio Int interrupt status
-#define  AUD_E_INT_MSTAT           0x040108	// Audio Int interrupt masked status
-#define  AUD_E_INT_SSTAT           0x04010C	// Audio Int interrupt set status
+/* ***************************************************************************** */
+#define  AUD_E_INT_MSK             0x040100	/* Audio Int interrupt mask */
+#define  AUD_E_INT_STAT            0x040104	/* Audio Int interrupt status */
+#define  AUD_E_INT_MSTAT           0x040108	/* Audio Int interrupt masked status */
+#define  AUD_E_INT_SSTAT           0x04010C	/* Audio Int interrupt set status */
 
 #define  FLD_AUD_SRC_OPC_ERR       0x00020000
 #define  FLD_AUD_DST_OPC_ERR       0x00010000
@@ -207,17 +207,17 @@
 #define  FLD_AUD_SRC_RISCI1        0x00000002
 #define  FLD_AUD_DST_RISCI1        0x00000001
 
-//*****************************************************************************
-#define  MBIF_A_INT_MSK             0x040110	// MBIF Int interrupt mask
-#define  MBIF_A_INT_STAT            0x040114	// MBIF Int interrupt status
-#define  MBIF_A_INT_MSTAT           0x040118	// MBIF Int interrupt masked status
-#define  MBIF_A_INT_SSTAT           0x04011C	// MBIF Int interrupt set status
+/* ***************************************************************************** */
+#define  MBIF_A_INT_MSK             0x040110	/* MBIF Int interrupt mask */
+#define  MBIF_A_INT_STAT            0x040114	/* MBIF Int interrupt status */
+#define  MBIF_A_INT_MSTAT           0x040118	/* MBIF Int interrupt masked status */
+#define  MBIF_A_INT_SSTAT           0x04011C	/* MBIF Int interrupt set status */
 
-//*****************************************************************************
-#define  MBIF_B_INT_MSK             0x040120	// MBIF Int interrupt mask
-#define  MBIF_B_INT_STAT            0x040124	// MBIF Int interrupt status
-#define  MBIF_B_INT_MSTAT           0x040128	// MBIF Int interrupt masked status
-#define  MBIF_B_INT_SSTAT           0x04012C	// MBIF Int interrupt set status
+/* ***************************************************************************** */
+#define  MBIF_B_INT_MSK             0x040120	/* MBIF Int interrupt mask */
+#define  MBIF_B_INT_STAT            0x040124	/* MBIF Int interrupt status */
+#define  MBIF_B_INT_MSTAT           0x040128	/* MBIF Int interrupt masked status */
+#define  MBIF_B_INT_SSTAT           0x04012C	/* MBIF Int interrupt set status */
 
 #define  FLD_MBIF_DST_OPC_ERR       0x00010000
 #define  FLD_MBIF_DST_SYNC          0x00001000
@@ -225,35 +225,35 @@
 #define  FLD_MBIF_DST_RISCI2        0x00000010
 #define  FLD_MBIF_DST_RISCI1        0x00000001
 
-//*****************************************************************************
-#define  AUD_EXT_INT_MSK           0x040060	// Audio Ext interrupt mask
-#define  AUD_EXT_INT_STAT          0x040064	// Audio Ext interrupt status
-#define  AUD_EXT_INT_MSTAT         0x040068	// Audio Ext interrupt masked status
-#define  AUD_EXT_INT_SSTAT         0x04006C	// Audio Ext interrupt set status
+/* ***************************************************************************** */
+#define  AUD_EXT_INT_MSK           0x040060	/* Audio Ext interrupt mask */
+#define  AUD_EXT_INT_STAT          0x040064	/* Audio Ext interrupt status */
+#define  AUD_EXT_INT_MSTAT         0x040068	/* Audio Ext interrupt masked status */
+#define  AUD_EXT_INT_SSTAT         0x04006C	/* Audio Ext interrupt set status */
 #define  FLD_AUD_EXT_OPC_ERR       0x00010000
 #define  FLD_AUD_EXT_SYNC          0x00001000
 #define  FLD_AUD_EXT_OF            0x00000100
 #define  FLD_AUD_EXT_RISCI2        0x00000010
 #define  FLD_AUD_EXT_RISCI1        0x00000001
 
-//*****************************************************************************
-#define  GPIO_LO                   0x110010	// Lower  of GPIO pins [31:0]
-#define  GPIO_HI                   0x110014	// Upper WORD  of GPIO pins [47:31]
+/* ***************************************************************************** */
+#define  GPIO_LO                   0x110010	/* Lower  of GPIO pins [31:0] */
+#define  GPIO_HI                   0x110014	/* Upper WORD  of GPIO pins [47:31] */
 
-#define  GPIO_LO_OE                0x110018	// Lower  of GPIO output enable [31:0]
-#define  GPIO_HI_OE                0x11001C	// Upper word  of GPIO output enable [47:32]
+#define  GPIO_LO_OE                0x110018	/* Lower  of GPIO output enable [31:0] */
+#define  GPIO_HI_OE                0x11001C	/* Upper word  of GPIO output enable [47:32] */
 
-#define  GPIO_LO_INT_MSK           0x11003C	// GPIO interrupt mask
-#define  GPIO_LO_INT_STAT          0x110044	// GPIO interrupt status
-#define  GPIO_LO_INT_MSTAT         0x11004C	// GPIO interrupt masked status
-#define  GPIO_LO_ISM_SNS           0x110054	// GPIO interrupt sensitivity
-#define  GPIO_LO_ISM_POL           0x11005C	// GPIO interrupt polarity
+#define  GPIO_LO_INT_MSK           0x11003C	/* GPIO interrupt mask */
+#define  GPIO_LO_INT_STAT          0x110044	/* GPIO interrupt status */
+#define  GPIO_LO_INT_MSTAT         0x11004C	/* GPIO interrupt masked status */
+#define  GPIO_LO_ISM_SNS           0x110054	/* GPIO interrupt sensitivity */
+#define  GPIO_LO_ISM_POL           0x11005C	/* GPIO interrupt polarity */
 
-#define  GPIO_HI_INT_MSK           0x110040	// GPIO interrupt mask
-#define  GPIO_HI_INT_STAT          0x110048	// GPIO interrupt status
-#define  GPIO_HI_INT_MSTAT         0x110050	// GPIO interrupt masked status
-#define  GPIO_HI_ISM_SNS           0x110058	// GPIO interrupt sensitivity
-#define  GPIO_HI_ISM_POL           0x110060	// GPIO interrupt polarity
+#define  GPIO_HI_INT_MSK           0x110040	/* GPIO interrupt mask */
+#define  GPIO_HI_INT_STAT          0x110048	/* GPIO interrupt status */
+#define  GPIO_HI_INT_MSTAT         0x110050	/* GPIO interrupt masked status */
+#define  GPIO_HI_ISM_SNS           0x110058	/* GPIO interrupt sensitivity */
+#define  GPIO_HI_ISM_POL           0x110060	/* GPIO interrupt polarity */
 
 #define  FLD_GPIO43_INT            (1 << 11)
 #define  FLD_GPIO42_INT            (1 << 10)
@@ -271,236 +271,236 @@
 #define  FLD_GPIO1_INT             (1 << 1)
 #define  FLD_GPIO0_INT             (1 << 0)
 
-//*****************************************************************************
-#define  TC_REQ                    0x040090	// Rider PCI Express traFFic class request
+/* ***************************************************************************** */
+#define  TC_REQ                    0x040090	/* Rider PCI Express traFFic class request */
 
-//*****************************************************************************
-#define  TC_REQ_SET                0x040094	// Rider PCI Express traFFic class request set
+/* ***************************************************************************** */
+#define  TC_REQ_SET                0x040094	/* Rider PCI Express traFFic class request set */
 
-//*****************************************************************************
-// Rider
-//*****************************************************************************
+/* ***************************************************************************** */
+/* Rider */
+/* ***************************************************************************** */
 
-// PCI Compatible Header
-//*****************************************************************************
+/* PCI Compatible Header */
+/* ***************************************************************************** */
 #define  RDR_CFG0                  0x050000
 #define  RDR_VENDOR_DEVICE_ID_CFG  0x050000
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG1                  0x050004
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG2                  0x050008
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG3                  0x05000C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG4                  0x050010
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG5                  0x050014
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG6                  0x050018
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG7                  0x05001C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG8                  0x050020
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFG9                  0x050024
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFGA                  0x050028
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFGB                  0x05002C
 #define  RDR_SUSSYSTEM_ID_CFG      0x05002C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFGC                  0x050030
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFGD                  0x050034
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFGE                  0x050038
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_CFGF                  0x05003C
 
-//*****************************************************************************
-// PCI-Express Capabilities
-//*****************************************************************************
+/* ***************************************************************************** */
+/* PCI-Express Capabilities */
+/* ***************************************************************************** */
 #define  RDR_PECAP                 0x050040
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_PEDEVCAP              0x050044
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_PEDEVSC               0x050048
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_PELINKCAP             0x05004C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_PELINKSC              0x050050
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_PMICAP                0x050080
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_PMCSR                 0x050084
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VPDCAP                0x050090
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VPDDATA               0x050094
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MSICAP                0x0500A0
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MSIARL                0x0500A4
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MSIARU                0x0500A8
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MSIDATA               0x0500AC
 
-//*****************************************************************************
-// PCI Express Extended Capabilities
-//*****************************************************************************
+/* ***************************************************************************** */
+/* PCI Express Extended Capabilities */
+/* ***************************************************************************** */
 #define  RDR_AERXCAP               0x050100
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERUESTA              0x050104
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERUEMSK              0x050108
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERUESEV              0x05010C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERCESTA              0x050110
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERCEMSK              0x050114
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERCC                 0x050118
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERHL0                0x05011C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERHL1                0x050120
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERHL2                0x050124
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_AERHL3                0x050128
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCXCAP                0x050200
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCCAP1                0x050204
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCCAP2                0x050208
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCSC                  0x05020C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR0_CAP              0x050210
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR0_CTRL             0x050214
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR0_STAT             0x050218
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR1_CAP              0x05021C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR1_CTRL             0x050220
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR1_STAT             0x050224
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR2_CAP              0x050228
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR2_CTRL             0x05022C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR2_STAT             0x050230
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR3_CAP              0x050234
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR3_CTRL             0x050238
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR3_STAT             0x05023C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB0                0x050240
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB1                0x050244
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB2                0x050248
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB3                0x05024C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB4                0x050250
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB5                0x050254
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB6                0x050258
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCARB7                0x05025C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RDRSTAT0              0x050300
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RDRSTAT1              0x050304
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RDRCTL0               0x050308
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RDRCTL1               0x05030C
 
-//*****************************************************************************
-// Transaction Layer Registers
-//*****************************************************************************
+/* ***************************************************************************** */
+/* Transaction Layer Registers */
+/* ***************************************************************************** */
 #define  RDR_TLSTAT0               0x050310
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_TLSTAT1               0x050314
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_TLCTL0                0x050318
 #define  FLD_CFG_UR_CPL_MODE       0x00000040
 #define  FLD_CFG_CORR_ERR_QUITE    0x00000020
@@ -510,569 +510,569 @@
 #define  FLD_CFG_RELAX_ORDER_MSK   0x00000002
 #define  FLD_CFG_TAG_ORDER_EN      0x00000001
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_TLCTL1                0x05031C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_REQRCAL               0x050320
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_REQRCAU               0x050324
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_REQEPA                0x050328
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_REQCTRL               0x05032C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_REQSTAT               0x050330
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_TL_TEST               0x050334
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR01_CTL             0x050348
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_VCR23_CTL             0x05034C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RX_VCR0_FC            0x050350
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RX_VCR1_FC            0x050354
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RX_VCR2_FC            0x050358
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_RX_VCR3_FC            0x05035C
 
-//*****************************************************************************
-// Data Link Layer Registers
-//*****************************************************************************
+/* ***************************************************************************** */
+/* Data Link Layer Registers */
+/* ***************************************************************************** */
 #define  RDR_DLLSTAT               0x050360
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_DLLCTRL               0x050364
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_REPLAYTO              0x050368
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_ACKLATTO              0x05036C
 
-//*****************************************************************************
-// MAC Layer Registers
-//*****************************************************************************
+/* ***************************************************************************** */
+/* MAC Layer Registers */
+/* ***************************************************************************** */
 #define  RDR_MACSTAT0              0x050380
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MACSTAT1              0x050384
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MACCTRL0              0x050388
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MACCTRL1              0x05038C
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MACCTRL2              0x050390
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_MAC_LB_DATA           0x050394
 
-//*****************************************************************************
+/* ***************************************************************************** */
 #define  RDR_L0S_EXIT_LAT          0x050398
 
-//*****************************************************************************
-// DMAC
-//*****************************************************************************
-#define  DMA1_PTR1                 0x100000	// DMA Current Ptr : Ch#1
+/* ***************************************************************************** */
+/* DMAC */
+/* ***************************************************************************** */
+#define  DMA1_PTR1                 0x100000	/* DMA Current Ptr : Ch#1 */
 
-//*****************************************************************************
-#define  DMA2_PTR1                 0x100004	// DMA Current Ptr : Ch#2
+/* ***************************************************************************** */
+#define  DMA2_PTR1                 0x100004	/* DMA Current Ptr : Ch#2 */
 
-//*****************************************************************************
-#define  DMA3_PTR1                 0x100008	// DMA Current Ptr : Ch#3
+/* ***************************************************************************** */
+#define  DMA3_PTR1                 0x100008	/* DMA Current Ptr : Ch#3 */
 
-//*****************************************************************************
-#define  DMA4_PTR1                 0x10000C	// DMA Current Ptr : Ch#4
+/* ***************************************************************************** */
+#define  DMA4_PTR1                 0x10000C	/* DMA Current Ptr : Ch#4 */
 
-//*****************************************************************************
-#define  DMA5_PTR1                 0x100010	// DMA Current Ptr : Ch#5
+/* ***************************************************************************** */
+#define  DMA5_PTR1                 0x100010	/* DMA Current Ptr : Ch#5 */
 
-//*****************************************************************************
-#define  DMA6_PTR1                 0x100014	// DMA Current Ptr : Ch#6
+/* ***************************************************************************** */
+#define  DMA6_PTR1                 0x100014	/* DMA Current Ptr : Ch#6 */
 
-//*****************************************************************************
-#define  DMA7_PTR1                 0x100018	// DMA Current Ptr : Ch#7
+/* ***************************************************************************** */
+#define  DMA7_PTR1                 0x100018	/* DMA Current Ptr : Ch#7 */
 
-//*****************************************************************************
-#define  DMA8_PTR1                 0x10001C	// DMA Current Ptr : Ch#8
+/* ***************************************************************************** */
+#define  DMA8_PTR1                 0x10001C	/* DMA Current Ptr : Ch#8 */
 
-//*****************************************************************************
-#define  DMA9_PTR1                 0x100020	// DMA Current Ptr : Ch#9
+/* ***************************************************************************** */
+#define  DMA9_PTR1                 0x100020	/* DMA Current Ptr : Ch#9 */
 
-//*****************************************************************************
-#define  DMA10_PTR1                0x100024	// DMA Current Ptr : Ch#10
+/* ***************************************************************************** */
+#define  DMA10_PTR1                0x100024	/* DMA Current Ptr : Ch#10 */
 
-//*****************************************************************************
-#define  DMA11_PTR1                0x100028	// DMA Current Ptr : Ch#11
+/* ***************************************************************************** */
+#define  DMA11_PTR1                0x100028	/* DMA Current Ptr : Ch#11 */
 
-//*****************************************************************************
-#define  DMA12_PTR1                0x10002C	// DMA Current Ptr : Ch#12
+/* ***************************************************************************** */
+#define  DMA12_PTR1                0x10002C	/* DMA Current Ptr : Ch#12 */
 
-//*****************************************************************************
-#define  DMA13_PTR1                0x100030	// DMA Current Ptr : Ch#13
+/* ***************************************************************************** */
+#define  DMA13_PTR1                0x100030	/* DMA Current Ptr : Ch#13 */
 
-//*****************************************************************************
-#define  DMA14_PTR1                0x100034	// DMA Current Ptr : Ch#14
+/* ***************************************************************************** */
+#define  DMA14_PTR1                0x100034	/* DMA Current Ptr : Ch#14 */
 
-//*****************************************************************************
-#define  DMA15_PTR1                0x100038	// DMA Current Ptr : Ch#15
+/* ***************************************************************************** */
+#define  DMA15_PTR1                0x100038	/* DMA Current Ptr : Ch#15 */
 
-//*****************************************************************************
-#define  DMA16_PTR1                0x10003C	// DMA Current Ptr : Ch#16
+/* ***************************************************************************** */
+#define  DMA16_PTR1                0x10003C	/* DMA Current Ptr : Ch#16 */
 
-//*****************************************************************************
-#define  DMA17_PTR1                0x100040	// DMA Current Ptr : Ch#17
+/* ***************************************************************************** */
+#define  DMA17_PTR1                0x100040	/* DMA Current Ptr : Ch#17 */
 
-//*****************************************************************************
-#define  DMA18_PTR1                0x100044	// DMA Current Ptr : Ch#18
+/* ***************************************************************************** */
+#define  DMA18_PTR1                0x100044	/* DMA Current Ptr : Ch#18 */
 
-//*****************************************************************************
-#define  DMA19_PTR1                0x100048	// DMA Current Ptr : Ch#19
+/* ***************************************************************************** */
+#define  DMA19_PTR1                0x100048	/* DMA Current Ptr : Ch#19 */
 
-//*****************************************************************************
-#define  DMA20_PTR1                0x10004C	// DMA Current Ptr : Ch#20
+/* ***************************************************************************** */
+#define  DMA20_PTR1                0x10004C	/* DMA Current Ptr : Ch#20 */
 
-//*****************************************************************************
-#define  DMA21_PTR1                0x100050	// DMA Current Ptr : Ch#21
+/* ***************************************************************************** */
+#define  DMA21_PTR1                0x100050	/* DMA Current Ptr : Ch#21 */
 
-//*****************************************************************************
-#define  DMA22_PTR1                0x100054	// DMA Current Ptr : Ch#22
+/* ***************************************************************************** */
+#define  DMA22_PTR1                0x100054	/* DMA Current Ptr : Ch#22 */
 
-//*****************************************************************************
-#define  DMA23_PTR1                0x100058	// DMA Current Ptr : Ch#23
+/* ***************************************************************************** */
+#define  DMA23_PTR1                0x100058	/* DMA Current Ptr : Ch#23 */
 
-//*****************************************************************************
-#define  DMA24_PTR1                0x10005C	// DMA Current Ptr : Ch#24
+/* ***************************************************************************** */
+#define  DMA24_PTR1                0x10005C	/* DMA Current Ptr : Ch#24 */
 
-//*****************************************************************************
-#define  DMA25_PTR1                0x100060	// DMA Current Ptr : Ch#25
+/* ***************************************************************************** */
+#define  DMA25_PTR1                0x100060	/* DMA Current Ptr : Ch#25 */
 
-//*****************************************************************************
-#define  DMA26_PTR1                0x100064	// DMA Current Ptr : Ch#26
+/* ***************************************************************************** */
+#define  DMA26_PTR1                0x100064	/* DMA Current Ptr : Ch#26 */
 
-//*****************************************************************************
-#define  DMA1_PTR2                 0x100080	// DMA Tab Ptr : Ch#1
+/* ***************************************************************************** */
+#define  DMA1_PTR2                 0x100080	/* DMA Tab Ptr : Ch#1 */
 
-//*****************************************************************************
-#define  DMA2_PTR2                 0x100084	// DMA Tab Ptr : Ch#2
+/* ***************************************************************************** */
+#define  DMA2_PTR2                 0x100084	/* DMA Tab Ptr : Ch#2 */
 
-//*****************************************************************************
-#define  DMA3_PTR2                 0x100088	// DMA Tab Ptr : Ch#3
+/* ***************************************************************************** */
+#define  DMA3_PTR2                 0x100088	/* DMA Tab Ptr : Ch#3 */
 
-//*****************************************************************************
-#define  DMA4_PTR2                 0x10008C	// DMA Tab Ptr : Ch#4
+/* ***************************************************************************** */
+#define  DMA4_PTR2                 0x10008C	/* DMA Tab Ptr : Ch#4 */
 
-//*****************************************************************************
-#define  DMA5_PTR2                 0x100090	// DMA Tab Ptr : Ch#5
+/* ***************************************************************************** */
+#define  DMA5_PTR2                 0x100090	/* DMA Tab Ptr : Ch#5 */
 
-//*****************************************************************************
-#define  DMA6_PTR2                 0x100094	// DMA Tab Ptr : Ch#6
+/* ***************************************************************************** */
+#define  DMA6_PTR2                 0x100094	/* DMA Tab Ptr : Ch#6 */
 
-//*****************************************************************************
-#define  DMA7_PTR2                 0x100098	// DMA Tab Ptr : Ch#7
+/* ***************************************************************************** */
+#define  DMA7_PTR2                 0x100098	/* DMA Tab Ptr : Ch#7 */
 
-//*****************************************************************************
-#define  DMA8_PTR2                 0x10009C	// DMA Tab Ptr : Ch#8
+/* ***************************************************************************** */
+#define  DMA8_PTR2                 0x10009C	/* DMA Tab Ptr : Ch#8 */
 
-//*****************************************************************************
-#define  DMA9_PTR2                 0x1000A0	// DMA Tab Ptr : Ch#9
+/* ***************************************************************************** */
+#define  DMA9_PTR2                 0x1000A0	/* DMA Tab Ptr : Ch#9 */
 
-//*****************************************************************************
-#define  DMA10_PTR2                0x1000A4	// DMA Tab Ptr : Ch#10
+/* ***************************************************************************** */
+#define  DMA10_PTR2                0x1000A4	/* DMA Tab Ptr : Ch#10 */
 
-//*****************************************************************************
-#define  DMA11_PTR2                0x1000A8	// DMA Tab Ptr : Ch#11
+/* ***************************************************************************** */
+#define  DMA11_PTR2                0x1000A8	/* DMA Tab Ptr : Ch#11 */
 
-//*****************************************************************************
-#define  DMA12_PTR2                0x1000AC	// DMA Tab Ptr : Ch#12
+/* ***************************************************************************** */
+#define  DMA12_PTR2                0x1000AC	/* DMA Tab Ptr : Ch#12 */
 
-//*****************************************************************************
-#define  DMA13_PTR2                0x1000B0	// DMA Tab Ptr : Ch#13
+/* ***************************************************************************** */
+#define  DMA13_PTR2                0x1000B0	/* DMA Tab Ptr : Ch#13 */
 
-//*****************************************************************************
-#define  DMA14_PTR2                0x1000B4	// DMA Tab Ptr : Ch#14
+/* ***************************************************************************** */
+#define  DMA14_PTR2                0x1000B4	/* DMA Tab Ptr : Ch#14 */
 
-//*****************************************************************************
-#define  DMA15_PTR2                0x1000B8	// DMA Tab Ptr : Ch#15
+/* ***************************************************************************** */
+#define  DMA15_PTR2                0x1000B8	/* DMA Tab Ptr : Ch#15 */
 
-//*****************************************************************************
-#define  DMA16_PTR2                0x1000BC	// DMA Tab Ptr : Ch#16
+/* ***************************************************************************** */
+#define  DMA16_PTR2                0x1000BC	/* DMA Tab Ptr : Ch#16 */
 
-//*****************************************************************************
-#define  DMA17_PTR2                0x1000C0	// DMA Tab Ptr : Ch#17
+/* ***************************************************************************** */
+#define  DMA17_PTR2                0x1000C0	/* DMA Tab Ptr : Ch#17 */
 
-//*****************************************************************************
-#define  DMA18_PTR2                0x1000C4	// DMA Tab Ptr : Ch#18
+/* ***************************************************************************** */
+#define  DMA18_PTR2                0x1000C4	/* DMA Tab Ptr : Ch#18 */
 
-//*****************************************************************************
-#define  DMA19_PTR2                0x1000C8	// DMA Tab Ptr : Ch#19
+/* ***************************************************************************** */
+#define  DMA19_PTR2                0x1000C8	/* DMA Tab Ptr : Ch#19 */
 
-//*****************************************************************************
-#define  DMA20_PTR2                0x1000CC	// DMA Tab Ptr : Ch#20
+/* ***************************************************************************** */
+#define  DMA20_PTR2                0x1000CC	/* DMA Tab Ptr : Ch#20 */
 
-//*****************************************************************************
-#define  DMA21_PTR2                0x1000D0	// DMA Tab Ptr : Ch#21
+/* ***************************************************************************** */
+#define  DMA21_PTR2                0x1000D0	/* DMA Tab Ptr : Ch#21 */
 
-//*****************************************************************************
-#define  DMA22_PTR2                0x1000D4	// DMA Tab Ptr : Ch#22
+/* ***************************************************************************** */
+#define  DMA22_PTR2                0x1000D4	/* DMA Tab Ptr : Ch#22 */
 
-//*****************************************************************************
-#define  DMA23_PTR2                0x1000D8	// DMA Tab Ptr : Ch#23
+/* ***************************************************************************** */
+#define  DMA23_PTR2                0x1000D8	/* DMA Tab Ptr : Ch#23 */
 
-//*****************************************************************************
-#define  DMA24_PTR2                0x1000DC	// DMA Tab Ptr : Ch#24
+/* ***************************************************************************** */
+#define  DMA24_PTR2                0x1000DC	/* DMA Tab Ptr : Ch#24 */
 
-//*****************************************************************************
-#define  DMA25_PTR2                0x1000E0	// DMA Tab Ptr : Ch#25
+/* ***************************************************************************** */
+#define  DMA25_PTR2                0x1000E0	/* DMA Tab Ptr : Ch#25 */
 
-//*****************************************************************************
-#define  DMA26_PTR2                0x1000E4	// DMA Tab Ptr : Ch#26
+/* ***************************************************************************** */
+#define  DMA26_PTR2                0x1000E4	/* DMA Tab Ptr : Ch#26 */
 
-//*****************************************************************************
-#define  DMA1_CNT1                 0x100100	// DMA BuFFer Size : Ch#1
+/* ***************************************************************************** */
+#define  DMA1_CNT1                 0x100100	/* DMA BuFFer Size : Ch#1 */
 
-//*****************************************************************************
-#define  DMA2_CNT1                 0x100104	// DMA BuFFer Size : Ch#2
+/* ***************************************************************************** */
+#define  DMA2_CNT1                 0x100104	/* DMA BuFFer Size : Ch#2 */
 
-//*****************************************************************************
-#define  DMA3_CNT1                 0x100108	// DMA BuFFer Size : Ch#3
+/* ***************************************************************************** */
+#define  DMA3_CNT1                 0x100108	/* DMA BuFFer Size : Ch#3 */
 
-//*****************************************************************************
-#define  DMA4_CNT1                 0x10010C	// DMA BuFFer Size : Ch#4
+/* ***************************************************************************** */
+#define  DMA4_CNT1                 0x10010C	/* DMA BuFFer Size : Ch#4 */
 
-//*****************************************************************************
-#define  DMA5_CNT1                 0x100110	// DMA BuFFer Size : Ch#5
+/* ***************************************************************************** */
+#define  DMA5_CNT1                 0x100110	/* DMA BuFFer Size : Ch#5 */
 
-//*****************************************************************************
-#define  DMA6_CNT1                 0x100114	// DMA BuFFer Size : Ch#6
+/* ***************************************************************************** */
+#define  DMA6_CNT1                 0x100114	/* DMA BuFFer Size : Ch#6 */
 
-//*****************************************************************************
-#define  DMA7_CNT1                 0x100118	// DMA BuFFer Size : Ch#7
+/* ***************************************************************************** */
+#define  DMA7_CNT1                 0x100118	/* DMA BuFFer Size : Ch#7 */
 
-//*****************************************************************************
-#define  DMA8_CNT1                 0x10011C	// DMA BuFFer Size : Ch#8
+/* ***************************************************************************** */
+#define  DMA8_CNT1                 0x10011C	/* DMA BuFFer Size : Ch#8 */
 
-//*****************************************************************************
-#define  DMA9_CNT1                 0x100120	// DMA BuFFer Size : Ch#9
+/* ***************************************************************************** */
+#define  DMA9_CNT1                 0x100120	/* DMA BuFFer Size : Ch#9 */
 
-//*****************************************************************************
-#define  DMA10_CNT1                0x100124	// DMA BuFFer Size : Ch#10
+/* ***************************************************************************** */
+#define  DMA10_CNT1                0x100124	/* DMA BuFFer Size : Ch#10 */
 
-//*****************************************************************************
-#define  DMA11_CNT1                0x100128	// DMA BuFFer Size : Ch#11
+/* ***************************************************************************** */
+#define  DMA11_CNT1                0x100128	/* DMA BuFFer Size : Ch#11 */
 
-//*****************************************************************************
-#define  DMA12_CNT1                0x10012C	// DMA BuFFer Size : Ch#12
+/* ***************************************************************************** */
+#define  DMA12_CNT1                0x10012C	/* DMA BuFFer Size : Ch#12 */
 
-//*****************************************************************************
-#define  DMA13_CNT1                0x100130	// DMA BuFFer Size : Ch#13
+/* ***************************************************************************** */
+#define  DMA13_CNT1                0x100130	/* DMA BuFFer Size : Ch#13 */
 
-//*****************************************************************************
-#define  DMA14_CNT1                0x100134	// DMA BuFFer Size : Ch#14
+/* ***************************************************************************** */
+#define  DMA14_CNT1                0x100134	/* DMA BuFFer Size : Ch#14 */
 
-//*****************************************************************************
-#define  DMA15_CNT1                0x100138	// DMA BuFFer Size : Ch#15
+/* ***************************************************************************** */
+#define  DMA15_CNT1                0x100138	/* DMA BuFFer Size : Ch#15 */
 
-//*****************************************************************************
-#define  DMA16_CNT1                0x10013C	// DMA BuFFer Size : Ch#16
+/* ***************************************************************************** */
+#define  DMA16_CNT1                0x10013C	/* DMA BuFFer Size : Ch#16 */
 
-//*****************************************************************************
-#define  DMA17_CNT1                0x100140	// DMA BuFFer Size : Ch#17
+/* ***************************************************************************** */
+#define  DMA17_CNT1                0x100140	/* DMA BuFFer Size : Ch#17 */
 
-//*****************************************************************************
-#define  DMA18_CNT1                0x100144	// DMA BuFFer Size : Ch#18
+/* ***************************************************************************** */
+#define  DMA18_CNT1                0x100144	/* DMA BuFFer Size : Ch#18 */
 
-//*****************************************************************************
-#define  DMA19_CNT1                0x100148	// DMA BuFFer Size : Ch#19
+/* ***************************************************************************** */
+#define  DMA19_CNT1                0x100148	/* DMA BuFFer Size : Ch#19 */
 
-//*****************************************************************************
-#define  DMA20_CNT1                0x10014C	// DMA BuFFer Size : Ch#20
+/* ***************************************************************************** */
+#define  DMA20_CNT1                0x10014C	/* DMA BuFFer Size : Ch#20 */
 
-//*****************************************************************************
-#define  DMA21_CNT1                0x100150	// DMA BuFFer Size : Ch#21
+/* ***************************************************************************** */
+#define  DMA21_CNT1                0x100150	/* DMA BuFFer Size : Ch#21 */
 
-//*****************************************************************************
-#define  DMA22_CNT1                0x100154	// DMA BuFFer Size : Ch#22
+/* ***************************************************************************** */
+#define  DMA22_CNT1                0x100154	/* DMA BuFFer Size : Ch#22 */
 
-//*****************************************************************************
-#define  DMA23_CNT1                0x100158	// DMA BuFFer Size : Ch#23
+/* ***************************************************************************** */
+#define  DMA23_CNT1                0x100158	/* DMA BuFFer Size : Ch#23 */
 
-//*****************************************************************************
-#define  DMA24_CNT1                0x10015C	// DMA BuFFer Size : Ch#24
+/* ***************************************************************************** */
+#define  DMA24_CNT1                0x10015C	/* DMA BuFFer Size : Ch#24 */
 
-//*****************************************************************************
-#define  DMA25_CNT1                0x100160	// DMA BuFFer Size : Ch#25
+/* ***************************************************************************** */
+#define  DMA25_CNT1                0x100160	/* DMA BuFFer Size : Ch#25 */
 
-//*****************************************************************************
-#define  DMA26_CNT1                0x100164	// DMA BuFFer Size : Ch#26
+/* ***************************************************************************** */
+#define  DMA26_CNT1                0x100164	/* DMA BuFFer Size : Ch#26 */
 
-//*****************************************************************************
-#define  DMA1_CNT2                 0x100180	// DMA Table Size : Ch#1
+/* ***************************************************************************** */
+#define  DMA1_CNT2                 0x100180	/* DMA Table Size : Ch#1 */
 
-//*****************************************************************************
-#define  DMA2_CNT2                 0x100184	// DMA Table Size : Ch#2
+/* ***************************************************************************** */
+#define  DMA2_CNT2                 0x100184	/* DMA Table Size : Ch#2 */
 
-//*****************************************************************************
-#define  DMA3_CNT2                 0x100188	// DMA Table Size : Ch#3
+/* ***************************************************************************** */
+#define  DMA3_CNT2                 0x100188	/* DMA Table Size : Ch#3 */
 
-//*****************************************************************************
-#define  DMA4_CNT2                 0x10018C	// DMA Table Size : Ch#4
+/* ***************************************************************************** */
+#define  DMA4_CNT2                 0x10018C	/* DMA Table Size : Ch#4 */
 
-//*****************************************************************************
-#define  DMA5_CNT2                 0x100190	// DMA Table Size : Ch#5
+/* ***************************************************************************** */
+#define  DMA5_CNT2                 0x100190	/* DMA Table Size : Ch#5 */
 
-//*****************************************************************************
-#define  DMA6_CNT2                 0x100194	// DMA Table Size : Ch#6
+/* ***************************************************************************** */
+#define  DMA6_CNT2                 0x100194	/* DMA Table Size : Ch#6 */
 
-//*****************************************************************************
-#define  DMA7_CNT2                 0x100198	// DMA Table Size : Ch#7
+/* ***************************************************************************** */
+#define  DMA7_CNT2                 0x100198	/* DMA Table Size : Ch#7 */
 
-//*****************************************************************************
-#define  DMA8_CNT2                 0x10019C	// DMA Table Size : Ch#8
+/* ***************************************************************************** */
+#define  DMA8_CNT2                 0x10019C	/* DMA Table Size : Ch#8 */
 
-//*****************************************************************************
-#define  DMA9_CNT2                 0x1001A0	// DMA Table Size : Ch#9
+/* ***************************************************************************** */
+#define  DMA9_CNT2                 0x1001A0	/* DMA Table Size : Ch#9 */
 
-//*****************************************************************************
-#define  DMA10_CNT2                0x1001A4	// DMA Table Size : Ch#10
+/* ***************************************************************************** */
+#define  DMA10_CNT2                0x1001A4	/* DMA Table Size : Ch#10 */
 
-//*****************************************************************************
-#define  DMA11_CNT2                0x1001A8	// DMA Table Size : Ch#11
+/* ***************************************************************************** */
+#define  DMA11_CNT2                0x1001A8	/* DMA Table Size : Ch#11 */
 
-//*****************************************************************************
-#define  DMA12_CNT2                0x1001AC	// DMA Table Size : Ch#12
+/* ***************************************************************************** */
+#define  DMA12_CNT2                0x1001AC	/* DMA Table Size : Ch#12 */
 
-//*****************************************************************************
-#define  DMA13_CNT2                0x1001B0	// DMA Table Size : Ch#13
+/* ***************************************************************************** */
+#define  DMA13_CNT2                0x1001B0	/* DMA Table Size : Ch#13 */
 
-//*****************************************************************************
-#define  DMA14_CNT2                0x1001B4	// DMA Table Size : Ch#14
+/* ***************************************************************************** */
+#define  DMA14_CNT2                0x1001B4	/* DMA Table Size : Ch#14 */
 
-//*****************************************************************************
-#define  DMA15_CNT2                0x1001B8	// DMA Table Size : Ch#15
+/* ***************************************************************************** */
+#define  DMA15_CNT2                0x1001B8	/* DMA Table Size : Ch#15 */
 
-//*****************************************************************************
-#define  DMA16_CNT2                0x1001BC	// DMA Table Size : Ch#16
+/* ***************************************************************************** */
+#define  DMA16_CNT2                0x1001BC	/* DMA Table Size : Ch#16 */
 
-//*****************************************************************************
-#define  DMA17_CNT2                0x1001C0	// DMA Table Size : Ch#17
+/* ***************************************************************************** */
+#define  DMA17_CNT2                0x1001C0	/* DMA Table Size : Ch#17 */
 
-//*****************************************************************************
-#define  DMA18_CNT2                0x1001C4	// DMA Table Size : Ch#18
+/* ***************************************************************************** */
+#define  DMA18_CNT2                0x1001C4	/* DMA Table Size : Ch#18 */
 
-//*****************************************************************************
-#define  DMA19_CNT2                0x1001C8	// DMA Table Size : Ch#19
+/* ***************************************************************************** */
+#define  DMA19_CNT2                0x1001C8	/* DMA Table Size : Ch#19 */
 
-//*****************************************************************************
-#define  DMA20_CNT2                0x1001CC	// DMA Table Size : Ch#20
+/* ***************************************************************************** */
+#define  DMA20_CNT2                0x1001CC	/* DMA Table Size : Ch#20 */
 
-//*****************************************************************************
-#define  DMA21_CNT2                0x1001D0	// DMA Table Size : Ch#21
+/* ***************************************************************************** */
+#define  DMA21_CNT2                0x1001D0	/* DMA Table Size : Ch#21 */
 
-//*****************************************************************************
-#define  DMA22_CNT2                0x1001D4	// DMA Table Size : Ch#22
+/* ***************************************************************************** */
+#define  DMA22_CNT2                0x1001D4	/* DMA Table Size : Ch#22 */
 
-//*****************************************************************************
-#define  DMA23_CNT2                0x1001D8	// DMA Table Size : Ch#23
+/* ***************************************************************************** */
+#define  DMA23_CNT2                0x1001D8	/* DMA Table Size : Ch#23 */
 
-//*****************************************************************************
-#define  DMA24_CNT2                0x1001DC	// DMA Table Size : Ch#24
+/* ***************************************************************************** */
+#define  DMA24_CNT2                0x1001DC	/* DMA Table Size : Ch#24 */
 
-//*****************************************************************************
-#define  DMA25_CNT2                0x1001E0	// DMA Table Size : Ch#25
+/* ***************************************************************************** */
+#define  DMA25_CNT2                0x1001E0	/* DMA Table Size : Ch#25 */
 
-//*****************************************************************************
-#define  DMA26_CNT2                0x1001E4	// DMA Table Size : Ch#26
+/* ***************************************************************************** */
+#define  DMA26_CNT2                0x1001E4	/* DMA Table Size : Ch#26 */
 
-//*****************************************************************************
- // ITG
-//*****************************************************************************
-#define  TM_CNT_LDW                0x110000	// Timer : Counter low
+/* ***************************************************************************** */
+ /* ITG */
+/* ***************************************************************************** */
+#define  TM_CNT_LDW                0x110000	/* Timer : Counter low */
 
-//*****************************************************************************
-#define  TM_CNT_UW                 0x110004	// Timer : Counter high word
+/* ***************************************************************************** */
+#define  TM_CNT_UW                 0x110004	/* Timer : Counter high word */
 
-//*****************************************************************************
-#define  TM_LMT_LDW                0x110008	// Timer : Limit low
+/* ***************************************************************************** */
+#define  TM_LMT_LDW                0x110008	/* Timer : Limit low */
 
-//*****************************************************************************
-#define  TM_LMT_UW                 0x11000C	// Timer : Limit high word
+/* ***************************************************************************** */
+#define  TM_LMT_UW                 0x11000C	/* Timer : Limit high word */
 
-//*****************************************************************************
-#define  GP0_IO                    0x110010	// GPIO output enables data I/O
-#define  FLD_GP_OE                 0x00FF0000	// GPIO: GP_OE output enable
-#define  FLD_GP_IN                 0x0000FF00	// GPIO: GP_IN status
-#define  FLD_GP_OUT                0x000000FF	// GPIO: GP_OUT control
+/* ***************************************************************************** */
+#define  GP0_IO                    0x110010	/* GPIO output enables data I/O */
+#define  FLD_GP_OE                 0x00FF0000	/* GPIO: GP_OE output enable */
+#define  FLD_GP_IN                 0x0000FF00	/* GPIO: GP_IN status */
+#define  FLD_GP_OUT                0x000000FF	/* GPIO: GP_OUT control */
 
-//*****************************************************************************
-#define  GPIO_ISM                  0x110014	// GPIO interrupt sensitivity mode
+/* ***************************************************************************** */
+#define  GPIO_ISM                  0x110014	/* GPIO interrupt sensitivity mode */
 #define  FLD_GP_ISM_SNS            0x00000070
 #define  FLD_GP_ISM_POL            0x00000007
 
-//*****************************************************************************
-#define  SOFT_RESET                0x11001C	// Output system reset reg
+/* ***************************************************************************** */
+#define  SOFT_RESET                0x11001C	/* Output system reset reg */
 #define  FLD_PECOS_SOFT_RESET      0x00000001
 
-//*****************************************************************************
-#define  MC416_RWD                 0x110020	// MC416 GPIO[18:3] pin
-#define  MC416_OEN                 0x110024	// Output enable of GPIO[18:3]
+/* ***************************************************************************** */
+#define  MC416_RWD                 0x110020	/* MC416 GPIO[18:3] pin */
+#define  MC416_OEN                 0x110024	/* Output enable of GPIO[18:3] */
 #define  MC416_CTL                 0x110028
 
-//*****************************************************************************
-#define  ALT_PIN_OUT_SEL           0x11002C	// Alternate GPIO output select
+/* ***************************************************************************** */
+#define  ALT_PIN_OUT_SEL           0x11002C	/* Alternate GPIO output select */
 
 #define  FLD_ALT_GPIO_OUT_SEL      0xF0000000
-// 0          Disabled <-- default
-// 1          GPIO[0]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
-// 8          ATT_IF
+/* 0          Disabled <-- default */
+/* 1          GPIO[0] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
+/* 8          ATT_IF */
 
 #define  FLD_AUX_PLL_CLK_ALT_SEL   0x0F000000
-// 0          AUX_PLL_CLK<-- default
-// 1          GPIO[2]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          AUX_PLL_CLK<-- default */
+/* 1          GPIO[2] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
 #define  FLD_IR_TX_ALT_SEL         0x00F00000
-// 0          IR_TX <-- default
-// 1          GPIO[1]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          IR_TX <-- default */
+/* 1          GPIO[1] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
 #define  FLD_IR_RX_ALT_SEL         0x000F0000
-// 0          IR_RX <-- default
-// 1          GPIO[0]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          IR_RX <-- default */
+/* 1          GPIO[0] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
 #define  FLD_GPIO10_ALT_SEL        0x0000F000
-// 0          GPIO[10] <-- default
-// 1          GPIO[0]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          GPIO[10] <-- default */
+/* 1          GPIO[0] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
 #define  FLD_GPIO2_ALT_SEL         0x00000F00
-// 0          GPIO[2] <-- default
-// 1          GPIO[1]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          GPIO[2] <-- default */
+/* 1          GPIO[1] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
 #define  FLD_GPIO1_ALT_SEL         0x000000F0
-// 0          GPIO[1] <-- default
-// 1          GPIO[0]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          GPIO[1] <-- default */
+/* 1          GPIO[0] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
 #define  FLD_GPIO0_ALT_SEL         0x0000000F
-// 0          GPIO[0] <-- default
-// 1          GPIO[1]
-// 2          GPIO[10]
-// 3          VIP_656_DATA_VAL
-// 4          VIP_656_DATA[0]
-// 5          VIP_656_CLK
-// 6          VIP_656_DATA_EXT[1]
-// 7          VIP_656_DATA_EXT[0]
+/* 0          GPIO[0] <-- default */
+/* 1          GPIO[1] */
+/* 2          GPIO[10] */
+/* 3          VIP_656_DATA_VAL */
+/* 4          VIP_656_DATA[0] */
+/* 5          VIP_656_CLK */
+/* 6          VIP_656_DATA_EXT[1] */
+/* 7          VIP_656_DATA_EXT[0] */
 
-#define  ALT_PIN_IN_SEL            0x110030	// Alternate GPIO input select
+#define  ALT_PIN_IN_SEL            0x110030	/* Alternate GPIO input select */
 
 #define  FLD_GPIO10_ALT_IN_SEL     0x0000F000
-// 0          GPIO[10] <-- default
-// 1          IR_RX
-// 2          IR_TX
-// 3          AUX_PLL_CLK
-// 4          IF_ATT_SEL
-// 5          GPIO[0]
-// 6          GPIO[1]
-// 7          GPIO[2]
+/* 0          GPIO[10] <-- default */
+/* 1          IR_RX */
+/* 2          IR_TX */
+/* 3          AUX_PLL_CLK */
+/* 4          IF_ATT_SEL */
+/* 5          GPIO[0] */
+/* 6          GPIO[1] */
+/* 7          GPIO[2] */
 
 #define  FLD_GPIO2_ALT_IN_SEL      0x00000F00
-// 0          GPIO[2] <-- default
-// 1          IR_RX
-// 2          IR_TX
-// 3          AUX_PLL_CLK
-// 4          IF_ATT_SEL
+/* 0          GPIO[2] <-- default */
+/* 1          IR_RX */
+/* 2          IR_TX */
+/* 3          AUX_PLL_CLK */
+/* 4          IF_ATT_SEL */
 
 #define  FLD_GPIO1_ALT_IN_SEL      0x000000F0
-// 0          GPIO[1] <-- default
-// 1          IR_RX
-// 2          IR_TX
-// 3          AUX_PLL_CLK
-// 4          IF_ATT_SEL
+/* 0          GPIO[1] <-- default */
+/* 1          IR_RX */
+/* 2          IR_TX */
+/* 3          AUX_PLL_CLK */
+/* 4          IF_ATT_SEL */
 
 #define  FLD_GPIO0_ALT_IN_SEL      0x0000000F
-// 0          GPIO[0] <-- default
-// 1          IR_RX
-// 2          IR_TX
-// 3          AUX_PLL_CLK
-// 4          IF_ATT_SEL
+/* 0          GPIO[0] <-- default */
+/* 1          IR_RX */
+/* 2          IR_TX */
+/* 3          AUX_PLL_CLK */
+/* 4          IF_ATT_SEL */
 
-//*****************************************************************************
-#define  TEST_BUS_CTL1             0x110040	// Test bus control register #1
+/* ***************************************************************************** */
+#define  TEST_BUS_CTL1             0x110040	/* Test bus control register #1 */
 
-//*****************************************************************************
-#define  TEST_BUS_CTL2             0x110044	// Test bus control register #2
+/* ***************************************************************************** */
+#define  TEST_BUS_CTL2             0x110044	/* Test bus control register #2 */
 
-//*****************************************************************************
-#define  CLK_DELAY                 0x110048	// Clock delay
-#define  FLD_MOE_CLK_DIS           0x80000000	// Disable MoE clock
+/* ***************************************************************************** */
+#define  CLK_DELAY                 0x110048	/* Clock delay */
+#define  FLD_MOE_CLK_DIS           0x80000000	/* Disable MoE clock */
 
-//*****************************************************************************
-#define  PAD_CTRL                  0x110068	// Pad drive strength control
+/* ***************************************************************************** */
+#define  PAD_CTRL                  0x110068	/* Pad drive strength control */
 
-//*****************************************************************************
-#define  MBIST_CTRL                0x110050	// SRAM memory built-in self test control
+/* ***************************************************************************** */
+#define  MBIST_CTRL                0x110050	/* SRAM memory built-in self test control */
 
-//*****************************************************************************
-#define  MBIST_STAT                0x110054	// SRAM memory built-in self test status
+/* ***************************************************************************** */
+#define  MBIST_STAT                0x110054	/* SRAM memory built-in self test status */
 
-//*****************************************************************************
-// PLL registers
-//*****************************************************************************
+/* ***************************************************************************** */
+/* PLL registers */
+/* ***************************************************************************** */
 #define  PLL_A_INT_FRAC            0x110088
 #define  PLL_A_POST_STAT_BIST      0x11008C
 #define  PLL_B_INT_FRAC            0x110090
@@ -1090,260 +1090,260 @@
 #define  VID_CH_MODE_SEL           0x110078
 #define  VID_CH_CLK_SEL            0x11007C
 
-//*****************************************************************************
-#define  VBI_A_DMA                 0x130008	// VBI A DMA data port
+/* ***************************************************************************** */
+#define  VBI_A_DMA                 0x130008	/* VBI A DMA data port */
 
-//*****************************************************************************
-#define  VID_A_VIP_CTL             0x130080	// Video A VIP format control
+/* ***************************************************************************** */
+#define  VID_A_VIP_CTL             0x130080	/* Video A VIP format control */
 #define  FLD_VIP_MODE              0x00000001
 
-//*****************************************************************************
-#define  VID_A_PIXEL_FRMT          0x130084	// Video A pixel format
+/* ***************************************************************************** */
+#define  VID_A_PIXEL_FRMT          0x130084	/* Video A pixel format */
 #define  FLD_VID_A_GAMMA_DIS       0x00000008
 #define  FLD_VID_A_FORMAT          0x00000007
 #define  FLD_VID_A_GAMMA_FACTOR    0x00000010
 
-//*****************************************************************************
-#define  VID_A_VBI_CTL             0x130088	// Video A VBI miscellaneous control
+/* ***************************************************************************** */
+#define  VID_A_VBI_CTL             0x130088	/* Video A VBI miscellaneous control */
 #define  FLD_VID_A_VIP_EXT         0x00000003
 
-//*****************************************************************************
-#define  VID_B_DMA                 0x130100	// Video B DMA data port
+/* ***************************************************************************** */
+#define  VID_B_DMA                 0x130100	/* Video B DMA data port */
 
-//*****************************************************************************
-#define  VBI_B_DMA                 0x130108	// VBI B DMA data port
+/* ***************************************************************************** */
+#define  VBI_B_DMA                 0x130108	/* VBI B DMA data port */
 
-//*****************************************************************************
-#define  VID_B_SRC_SEL             0x130144	// Video B source select
+/* ***************************************************************************** */
+#define  VID_B_SRC_SEL             0x130144	/* Video B source select */
 #define  FLD_VID_B_SRC_SEL         0x00000000
 
-//*****************************************************************************
-#define  VID_B_LNGTH               0x130150	// Video B line length
+/* ***************************************************************************** */
+#define  VID_B_LNGTH               0x130150	/* Video B line length */
 #define  FLD_VID_B_LN_LNGTH        0x00000FFF
 
-//*****************************************************************************
-#define  VID_B_VIP_CTL             0x130180	// Video B VIP format control
+/* ***************************************************************************** */
+#define  VID_B_VIP_CTL             0x130180	/* Video B VIP format control */
 
-//*****************************************************************************
-#define  VID_B_PIXEL_FRMT          0x130184	// Video B pixel format
+/* ***************************************************************************** */
+#define  VID_B_PIXEL_FRMT          0x130184	/* Video B pixel format */
 #define  FLD_VID_B_GAMMA_DIS       0x00000008
 #define  FLD_VID_B_FORMAT          0x00000007
 #define  FLD_VID_B_GAMMA_FACTOR    0x00000010
 
-//*****************************************************************************
-#define  VID_C_DMA                 0x130200	// Video C DMA data port
+/* ***************************************************************************** */
+#define  VID_C_DMA                 0x130200	/* Video C DMA data port */
 
-//*****************************************************************************
-#define  VID_C_LNGTH               0x130250	// Video C line length
+/* ***************************************************************************** */
+#define  VID_C_LNGTH               0x130250	/* Video C line length */
 #define  FLD_VID_C_LN_LNGTH        0x00000FFF
 
-//*****************************************************************************
-// Video Destination Channels
-//*****************************************************************************
+/* ***************************************************************************** */
+/* Video Destination Channels */
+/* ***************************************************************************** */
 
-#define  VID_DST_A_GPCNT           0x130020	// Video A general purpose counter
-#define  VID_DST_B_GPCNT           0x130120	// Video B general purpose counter
-#define  VID_DST_C_GPCNT           0x130220	// Video C general purpose counter
-#define  VID_DST_D_GPCNT           0x130320	// Video D general purpose counter
-#define  VID_DST_E_GPCNT           0x130420	// Video E general purpose counter
-#define  VID_DST_F_GPCNT           0x130520	// Video F general purpose counter
-#define  VID_DST_G_GPCNT           0x130620	// Video G general purpose counter
-#define  VID_DST_H_GPCNT           0x130720	// Video H general purpose counter
+#define  VID_DST_A_GPCNT           0x130020	/* Video A general purpose counter */
+#define  VID_DST_B_GPCNT           0x130120	/* Video B general purpose counter */
+#define  VID_DST_C_GPCNT           0x130220	/* Video C general purpose counter */
+#define  VID_DST_D_GPCNT           0x130320	/* Video D general purpose counter */
+#define  VID_DST_E_GPCNT           0x130420	/* Video E general purpose counter */
+#define  VID_DST_F_GPCNT           0x130520	/* Video F general purpose counter */
+#define  VID_DST_G_GPCNT           0x130620	/* Video G general purpose counter */
+#define  VID_DST_H_GPCNT           0x130720	/* Video H general purpose counter */
 
-//*****************************************************************************
+/* ***************************************************************************** */
 
-#define  VID_DST_A_GPCNT_CTL       0x130030	// Video A general purpose control
-#define  VID_DST_B_GPCNT_CTL       0x130130	// Video B general purpose control
-#define  VID_DST_C_GPCNT_CTL       0x130230	// Video C general purpose control
-#define  VID_DST_D_GPCNT_CTL       0x130330	// Video D general purpose control
-#define  VID_DST_E_GPCNT_CTL       0x130430	// Video E general purpose control
-#define  VID_DST_F_GPCNT_CTL       0x130530	// Video F general purpose control
-#define  VID_DST_G_GPCNT_CTL       0x130630	// Video G general purpose control
-#define  VID_DST_H_GPCNT_CTL       0x130730	// Video H general purpose control
+#define  VID_DST_A_GPCNT_CTL       0x130030	/* Video A general purpose control */
+#define  VID_DST_B_GPCNT_CTL       0x130130	/* Video B general purpose control */
+#define  VID_DST_C_GPCNT_CTL       0x130230	/* Video C general purpose control */
+#define  VID_DST_D_GPCNT_CTL       0x130330	/* Video D general purpose control */
+#define  VID_DST_E_GPCNT_CTL       0x130430	/* Video E general purpose control */
+#define  VID_DST_F_GPCNT_CTL       0x130530	/* Video F general purpose control */
+#define  VID_DST_G_GPCNT_CTL       0x130630	/* Video G general purpose control */
+#define  VID_DST_H_GPCNT_CTL       0x130730	/* Video H general purpose control */
 
-//*****************************************************************************
+/* ***************************************************************************** */
 
-#define  VID_DST_A_DMA_CTL         0x130040	// Video A DMA control
-#define  VID_DST_B_DMA_CTL         0x130140	// Video B DMA control
-#define  VID_DST_C_DMA_CTL         0x130240	// Video C DMA control
-#define  VID_DST_D_DMA_CTL         0x130340	// Video D DMA control
-#define  VID_DST_E_DMA_CTL         0x130440	// Video E DMA control
-#define  VID_DST_F_DMA_CTL         0x130540	// Video F DMA control
-#define  VID_DST_G_DMA_CTL         0x130640	// Video G DMA control
-#define  VID_DST_H_DMA_CTL         0x130740	// Video H DMA control
+#define  VID_DST_A_DMA_CTL         0x130040	/* Video A DMA control */
+#define  VID_DST_B_DMA_CTL         0x130140	/* Video B DMA control */
+#define  VID_DST_C_DMA_CTL         0x130240	/* Video C DMA control */
+#define  VID_DST_D_DMA_CTL         0x130340	/* Video D DMA control */
+#define  VID_DST_E_DMA_CTL         0x130440	/* Video E DMA control */
+#define  VID_DST_F_DMA_CTL         0x130540	/* Video F DMA control */
+#define  VID_DST_G_DMA_CTL         0x130640	/* Video G DMA control */
+#define  VID_DST_H_DMA_CTL         0x130740	/* Video H DMA control */
 
 #define  FLD_VID_RISC_EN           0x00000010
 #define  FLD_VID_FIFO_EN           0x00000001
 
-//*****************************************************************************
+/* ***************************************************************************** */
 
-#define  VID_DST_A_VIP_CTL         0x130080	// Video A VIP control
-#define  VID_DST_B_VIP_CTL         0x130180	// Video B VIP control
-#define  VID_DST_C_VIP_CTL         0x130280	// Video C VIP control
-#define  VID_DST_D_VIP_CTL         0x130380	// Video D VIP control
-#define  VID_DST_E_VIP_CTL         0x130480	// Video E VIP control
-#define  VID_DST_F_VIP_CTL         0x130580	// Video F VIP control
-#define  VID_DST_G_VIP_CTL         0x130680	// Video G VIP control
-#define  VID_DST_H_VIP_CTL         0x130780	// Video H VIP control
+#define  VID_DST_A_VIP_CTL         0x130080	/* Video A VIP control */
+#define  VID_DST_B_VIP_CTL         0x130180	/* Video B VIP control */
+#define  VID_DST_C_VIP_CTL         0x130280	/* Video C VIP control */
+#define  VID_DST_D_VIP_CTL         0x130380	/* Video D VIP control */
+#define  VID_DST_E_VIP_CTL         0x130480	/* Video E VIP control */
+#define  VID_DST_F_VIP_CTL         0x130580	/* Video F VIP control */
+#define  VID_DST_G_VIP_CTL         0x130680	/* Video G VIP control */
+#define  VID_DST_H_VIP_CTL         0x130780	/* Video H VIP control */
 
-//*****************************************************************************
+/* ***************************************************************************** */
 
-#define  VID_DST_A_PIX_FRMT        0x130084	// Video A Pixel format
-#define  VID_DST_B_PIX_FRMT        0x130184	// Video B Pixel format
-#define  VID_DST_C_PIX_FRMT        0x130284	// Video C Pixel format
-#define  VID_DST_D_PIX_FRMT        0x130384	// Video D Pixel format
-#define  VID_DST_E_PIX_FRMT        0x130484	// Video E Pixel format
-#define  VID_DST_F_PIX_FRMT        0x130584	// Video F Pixel format
-#define  VID_DST_G_PIX_FRMT        0x130684	// Video G Pixel format
-#define  VID_DST_H_PIX_FRMT        0x130784	// Video H Pixel format
+#define  VID_DST_A_PIX_FRMT        0x130084	/* Video A Pixel format */
+#define  VID_DST_B_PIX_FRMT        0x130184	/* Video B Pixel format */
+#define  VID_DST_C_PIX_FRMT        0x130284	/* Video C Pixel format */
+#define  VID_DST_D_PIX_FRMT        0x130384	/* Video D Pixel format */
+#define  VID_DST_E_PIX_FRMT        0x130484	/* Video E Pixel format */
+#define  VID_DST_F_PIX_FRMT        0x130584	/* Video F Pixel format */
+#define  VID_DST_G_PIX_FRMT        0x130684	/* Video G Pixel format */
+#define  VID_DST_H_PIX_FRMT        0x130784	/* Video H Pixel format */
 
-//*****************************************************************************
-// Video Source Channels
-//*****************************************************************************
+/* ***************************************************************************** */
+/* Video Source Channels */
+/* ***************************************************************************** */
 
-#define  VID_SRC_A_GPCNT_CTL       0x130804	// Video A general purpose control
-#define  VID_SRC_B_GPCNT_CTL       0x130904	// Video B general purpose control
-#define  VID_SRC_C_GPCNT_CTL       0x130A04	// Video C general purpose control
-#define  VID_SRC_D_GPCNT_CTL       0x130B04	// Video D general purpose control
-#define  VID_SRC_E_GPCNT_CTL       0x130C04	// Video E general purpose control
-#define  VID_SRC_F_GPCNT_CTL       0x130D04	// Video F general purpose control
-#define  VID_SRC_I_GPCNT_CTL       0x130E04	// Video I general purpose control
-#define  VID_SRC_J_GPCNT_CTL       0x130F04	// Video J general purpose control
+#define  VID_SRC_A_GPCNT_CTL       0x130804	/* Video A general purpose control */
+#define  VID_SRC_B_GPCNT_CTL       0x130904	/* Video B general purpose control */
+#define  VID_SRC_C_GPCNT_CTL       0x130A04	/* Video C general purpose control */
+#define  VID_SRC_D_GPCNT_CTL       0x130B04	/* Video D general purpose control */
+#define  VID_SRC_E_GPCNT_CTL       0x130C04	/* Video E general purpose control */
+#define  VID_SRC_F_GPCNT_CTL       0x130D04	/* Video F general purpose control */
+#define  VID_SRC_I_GPCNT_CTL       0x130E04	/* Video I general purpose control */
+#define  VID_SRC_J_GPCNT_CTL       0x130F04	/* Video J general purpose control */
 
-//*****************************************************************************
+/* ***************************************************************************** */
 
-#define  VID_SRC_A_GPCNT           0x130808	// Video A general purpose counter
-#define  VID_SRC_B_GPCNT           0x130908	// Video B general purpose counter
-#define  VID_SRC_C_GPCNT           0x130A08	// Video C general purpose counter
-#define  VID_SRC_D_GPCNT           0x130B08	// Video D general purpose counter
-#define  VID_SRC_E_GPCNT           0x130C08	// Video E general purpose counter
-#define  VID_SRC_F_GPCNT           0x130D08	// Video F general purpose counter
-#define  VID_SRC_I_GPCNT           0x130E08	// Video I general purpose counter
-#define  VID_SRC_J_GPCNT           0x130F08	// Video J general purpose counter
+#define  VID_SRC_A_GPCNT           0x130808	/* Video A general purpose counter */
+#define  VID_SRC_B_GPCNT           0x130908	/* Video B general purpose counter */
+#define  VID_SRC_C_GPCNT           0x130A08	/* Video C general purpose counter */
+#define  VID_SRC_D_GPCNT           0x130B08	/* Video D general purpose counter */
+#define  VID_SRC_E_GPCNT           0x130C08	/* Video E general purpose counter */
+#define  VID_SRC_F_GPCNT           0x130D08	/* Video F general purpose counter */
+#define  VID_SRC_I_GPCNT           0x130E08	/* Video I general purpose counter */
+#define  VID_SRC_J_GPCNT           0x130F08	/* Video J general purpose counter */
 
-//*****************************************************************************
+/* ***************************************************************************** */
 
-#define  VID_SRC_A_DMA_CTL         0x13080C	// Video A DMA control
-#define  VID_SRC_B_DMA_CTL         0x13090C	// Video B DMA control
-#define  VID_SRC_C_DMA_CTL         0x130A0C	// Video C DMA control
-#define  VID_SRC_D_DMA_CTL         0x130B0C	// Video D DMA control
-#define  VID_SRC_E_DMA_CTL         0x130C0C	// Video E DMA control
-#define  VID_SRC_F_DMA_CTL         0x130D0C	// Video F DMA control
-#define  VID_SRC_I_DMA_CTL         0x130E0C	// Video I DMA control
-#define  VID_SRC_J_DMA_CTL         0x130F0C	// Video J DMA control
+#define  VID_SRC_A_DMA_CTL         0x13080C	/* Video A DMA control */
+#define  VID_SRC_B_DMA_CTL         0x13090C	/* Video B DMA control */
+#define  VID_SRC_C_DMA_CTL         0x130A0C	/* Video C DMA control */
+#define  VID_SRC_D_DMA_CTL         0x130B0C	/* Video D DMA control */
+#define  VID_SRC_E_DMA_CTL         0x130C0C	/* Video E DMA control */
+#define  VID_SRC_F_DMA_CTL         0x130D0C	/* Video F DMA control */
+#define  VID_SRC_I_DMA_CTL         0x130E0C	/* Video I DMA control */
+#define  VID_SRC_J_DMA_CTL         0x130F0C	/* Video J DMA control */
 
 #define  FLD_APB_RISC_EN           0x00000010
 #define  FLD_APB_FIFO_EN           0x00000001
 
-//*****************************************************************************
+/* ***************************************************************************** */
 
-#define  VID_SRC_A_FMT_CTL         0x130810	// Video A format control
-#define  VID_SRC_B_FMT_CTL         0x130910	// Video B format control
-#define  VID_SRC_C_FMT_CTL         0x130A10	// Video C format control
-#define  VID_SRC_D_FMT_CTL         0x130B10	// Video D format control
-#define  VID_SRC_E_FMT_CTL         0x130C10	// Video E format control
-#define  VID_SRC_F_FMT_CTL         0x130D10	// Video F format control
-#define  VID_SRC_I_FMT_CTL         0x130E10	// Video I format control
-#define  VID_SRC_J_FMT_CTL         0x130F10	// Video J format control
+#define  VID_SRC_A_FMT_CTL         0x130810	/* Video A format control */
+#define  VID_SRC_B_FMT_CTL         0x130910	/* Video B format control */
+#define  VID_SRC_C_FMT_CTL         0x130A10	/* Video C format control */
+#define  VID_SRC_D_FMT_CTL         0x130B10	/* Video D format control */
+#define  VID_SRC_E_FMT_CTL         0x130C10	/* Video E format control */
+#define  VID_SRC_F_FMT_CTL         0x130D10	/* Video F format control */
+#define  VID_SRC_I_FMT_CTL         0x130E10	/* Video I format control */
+#define  VID_SRC_J_FMT_CTL         0x130F10	/* Video J format control */
 
-//*****************************************************************************
+/* ***************************************************************************** */
 
-#define  VID_SRC_A_ACTIVE_CTL1     0x130814	// Video A active control      1
-#define  VID_SRC_B_ACTIVE_CTL1     0x130914	// Video B active control      1
-#define  VID_SRC_C_ACTIVE_CTL1     0x130A14	// Video C active control      1
-#define  VID_SRC_D_ACTIVE_CTL1     0x130B14	// Video D active control      1
-#define  VID_SRC_E_ACTIVE_CTL1     0x130C14	// Video E active control      1
-#define  VID_SRC_F_ACTIVE_CTL1     0x130D14	// Video F active control      1
-#define  VID_SRC_I_ACTIVE_CTL1     0x130E14	// Video I active control      1
-#define  VID_SRC_J_ACTIVE_CTL1     0x130F14	// Video J active control      1
+#define  VID_SRC_A_ACTIVE_CTL1     0x130814	/* Video A active control      1 */
+#define  VID_SRC_B_ACTIVE_CTL1     0x130914	/* Video B active control      1 */
+#define  VID_SRC_C_ACTIVE_CTL1     0x130A14	/* Video C active control      1 */
+#define  VID_SRC_D_ACTIVE_CTL1     0x130B14	/* Video D active control      1 */
+#define  VID_SRC_E_ACTIVE_CTL1     0x130C14	/* Video E active control      1 */
+#define  VID_SRC_F_ACTIVE_CTL1     0x130D14	/* Video F active control      1 */
+#define  VID_SRC_I_ACTIVE_CTL1     0x130E14	/* Video I active control      1 */
+#define  VID_SRC_J_ACTIVE_CTL1     0x130F14	/* Video J active control      1 */
 
-//*****************************************************************************
+/* ***************************************************************************** */
 
-#define  VID_SRC_A_ACTIVE_CTL2     0x130818	// Video A active control      2
-#define  VID_SRC_B_ACTIVE_CTL2     0x130918	// Video B active control      2
-#define  VID_SRC_C_ACTIVE_CTL2     0x130A18	// Video C active control      2
-#define  VID_SRC_D_ACTIVE_CTL2     0x130B18	// Video D active control      2
-#define  VID_SRC_E_ACTIVE_CTL2     0x130C18	// Video E active control      2
-#define  VID_SRC_F_ACTIVE_CTL2     0x130D18	// Video F active control      2
-#define  VID_SRC_I_ACTIVE_CTL2     0x130E18	// Video I active control      2
-#define  VID_SRC_J_ACTIVE_CTL2     0x130F18	// Video J active control      2
+#define  VID_SRC_A_ACTIVE_CTL2     0x130818	/* Video A active control      2 */
+#define  VID_SRC_B_ACTIVE_CTL2     0x130918	/* Video B active control      2 */
+#define  VID_SRC_C_ACTIVE_CTL2     0x130A18	/* Video C active control      2 */
+#define  VID_SRC_D_ACTIVE_CTL2     0x130B18	/* Video D active control      2 */
+#define  VID_SRC_E_ACTIVE_CTL2     0x130C18	/* Video E active control      2 */
+#define  VID_SRC_F_ACTIVE_CTL2     0x130D18	/* Video F active control      2 */
+#define  VID_SRC_I_ACTIVE_CTL2     0x130E18	/* Video I active control      2 */
+#define  VID_SRC_J_ACTIVE_CTL2     0x130F18	/* Video J active control      2 */
 
-//*****************************************************************************
+/* ***************************************************************************** */
 
-#define  VID_SRC_A_CDT_SZ          0x13081C	// Video A CDT size
-#define  VID_SRC_B_CDT_SZ          0x13091C	// Video B CDT size
-#define  VID_SRC_C_CDT_SZ          0x130A1C	// Video C CDT size
-#define  VID_SRC_D_CDT_SZ          0x130B1C	// Video D CDT size
-#define  VID_SRC_E_CDT_SZ          0x130C1C	// Video E CDT size
-#define  VID_SRC_F_CDT_SZ          0x130D1C	// Video F CDT size
-#define  VID_SRC_I_CDT_SZ          0x130E1C	// Video I CDT size
-#define  VID_SRC_J_CDT_SZ          0x130F1C	// Video J CDT size
+#define  VID_SRC_A_CDT_SZ          0x13081C	/* Video A CDT size */
+#define  VID_SRC_B_CDT_SZ          0x13091C	/* Video B CDT size */
+#define  VID_SRC_C_CDT_SZ          0x130A1C	/* Video C CDT size */
+#define  VID_SRC_D_CDT_SZ          0x130B1C	/* Video D CDT size */
+#define  VID_SRC_E_CDT_SZ          0x130C1C	/* Video E CDT size */
+#define  VID_SRC_F_CDT_SZ          0x130D1C	/* Video F CDT size */
+#define  VID_SRC_I_CDT_SZ          0x130E1C	/* Video I CDT size */
+#define  VID_SRC_J_CDT_SZ          0x130F1C	/* Video J CDT size */
 
-//*****************************************************************************
-// Audio I/F
-//*****************************************************************************
-#define  AUD_DST_A_DMA             0x140000	// Audio Int A DMA data port
-#define  AUD_SRC_A_DMA             0x140008	// Audio Int A DMA data port
+/* ***************************************************************************** */
+/* Audio I/F */
+/* ***************************************************************************** */
+#define  AUD_DST_A_DMA             0x140000	/* Audio Int A DMA data port */
+#define  AUD_SRC_A_DMA             0x140008	/* Audio Int A DMA data port */
 
-#define  AUD_A_GPCNT               0x140010	// Audio Int A gp counter
+#define  AUD_A_GPCNT               0x140010	/* Audio Int A gp counter */
 #define  FLD_AUD_A_GP_CNT          0x0000FFFF
 
-#define  AUD_A_GPCNT_CTL           0x140014	// Audio Int A gp control
+#define  AUD_A_GPCNT_CTL           0x140014	/* Audio Int A gp control */
 
-#define  AUD_A_LNGTH               0x140018	// Audio Int A line length
+#define  AUD_A_LNGTH               0x140018	/* Audio Int A line length */
 
-#define  AUD_A_CFG                 0x14001C	// Audio Int A configuration
+#define  AUD_A_CFG                 0x14001C	/* Audio Int A configuration */
 
-//*****************************************************************************
-#define  AUD_DST_B_DMA             0x140100	// Audio Int B DMA data port
-#define  AUD_SRC_B_DMA             0x140108	// Audio Int B DMA data port
+/* ***************************************************************************** */
+#define  AUD_DST_B_DMA             0x140100	/* Audio Int B DMA data port */
+#define  AUD_SRC_B_DMA             0x140108	/* Audio Int B DMA data port */
 
-#define  AUD_B_GPCNT               0x140110	// Audio Int B gp counter
+#define  AUD_B_GPCNT               0x140110	/* Audio Int B gp counter */
 #define  FLD_AUD_B_GP_CNT          0x0000FFFF
 
-#define  AUD_B_GPCNT_CTL           0x140114	// Audio Int B gp control
+#define  AUD_B_GPCNT_CTL           0x140114	/* Audio Int B gp control */
 
-#define  AUD_B_LNGTH               0x140118	// Audio Int B line length
+#define  AUD_B_LNGTH               0x140118	/* Audio Int B line length */
 
-#define  AUD_B_CFG                 0x14011C	// Audio Int B configuration
+#define  AUD_B_CFG                 0x14011C	/* Audio Int B configuration */
 
-//*****************************************************************************
-#define  AUD_DST_C_DMA             0x140200	// Audio Int C DMA data port
-#define  AUD_SRC_C_DMA             0x140208	// Audio Int C DMA data port
+/* ***************************************************************************** */
+#define  AUD_DST_C_DMA             0x140200	/* Audio Int C DMA data port */
+#define  AUD_SRC_C_DMA             0x140208	/* Audio Int C DMA data port */
 
-#define  AUD_C_GPCNT               0x140210	// Audio Int C gp counter
+#define  AUD_C_GPCNT               0x140210	/* Audio Int C gp counter */
 #define  FLD_AUD_C_GP_CNT          0x0000FFFF
 
-#define  AUD_C_GPCNT_CTL           0x140214	// Audio Int C gp control
+#define  AUD_C_GPCNT_CTL           0x140214	/* Audio Int C gp control */
 
-#define  AUD_C_LNGTH               0x140218	// Audio Int C line length
+#define  AUD_C_LNGTH               0x140218	/* Audio Int C line length */
 
-#define  AUD_C_CFG                 0x14021C	// Audio Int C configuration
+#define  AUD_C_CFG                 0x14021C	/* Audio Int C configuration */
 
-//*****************************************************************************
-#define  AUD_DST_D_DMA             0x140300	// Audio Int D DMA data port
-#define  AUD_SRC_D_DMA             0x140308	// Audio Int D DMA data port
+/* ***************************************************************************** */
+#define  AUD_DST_D_DMA             0x140300	/* Audio Int D DMA data port */
+#define  AUD_SRC_D_DMA             0x140308	/* Audio Int D DMA data port */
 
-#define  AUD_D_GPCNT               0x140310	// Audio Int D gp counter
+#define  AUD_D_GPCNT               0x140310	/* Audio Int D gp counter */
 #define  FLD_AUD_D_GP_CNT          0x0000FFFF
 
-#define  AUD_D_GPCNT_CTL           0x140314	// Audio Int D gp control
+#define  AUD_D_GPCNT_CTL           0x140314	/* Audio Int D gp control */
 
-#define  AUD_D_LNGTH               0x140318	// Audio Int D line length
+#define  AUD_D_LNGTH               0x140318	/* Audio Int D line length */
 
-#define  AUD_D_CFG                 0x14031C	// Audio Int D configuration
+#define  AUD_D_CFG                 0x14031C	/* Audio Int D configuration */
 
-//*****************************************************************************
-#define  AUD_SRC_E_DMA             0x140400	// Audio Int E DMA data port
+/* ***************************************************************************** */
+#define  AUD_SRC_E_DMA             0x140400	/* Audio Int E DMA data port */
 
-#define  AUD_E_GPCNT               0x140410	// Audio Int E gp counter
+#define  AUD_E_GPCNT               0x140410	/* Audio Int E gp counter */
 #define  FLD_AUD_E_GP_CNT          0x0000FFFF
 
-#define  AUD_E_GPCNT_CTL           0x140414	// Audio Int E gp control
+#define  AUD_E_GPCNT_CTL           0x140414	/* Audio Int E gp control */
 
-#define  AUD_E_CFG                 0x14041C	// Audio Int E configuration
+#define  AUD_E_CFG                 0x14041C	/* Audio Int E configuration */
 
-//*****************************************************************************
+/* ***************************************************************************** */
 
 #define  FLD_AUD_DST_LN_LNGTH      0x00000FFF
 
@@ -1361,8 +1361,8 @@
 
 #define  FLD_AUD_SRC_ENABLE        0x00010000
 
-//*****************************************************************************
-#define  AUD_INT_DMA_CTL           0x140500	// Audio Int DMA control
+/* ***************************************************************************** */
+#define  AUD_INT_DMA_CTL           0x140500	/* Audio Int DMA control */
 
 #define  FLD_AUD_SRC_E_RISC_EN     0x00008000
 #define  FLD_AUD_SRC_C_RISC_EN     0x00004000
@@ -1384,15 +1384,15 @@
 #define  FLD_AUD_DST_B_FIFO_EN     0x00000002
 #define  FLD_AUD_DST_A_FIFO_EN     0x00000001
 
-//*****************************************************************************
-//
-//                   Mobilygen Interface Registers
-//
-//*****************************************************************************
-// Mobilygen Interface A
-//*****************************************************************************
-#define  MB_IF_A_DMA               0x150000	// MBIF A DMA data port
-#define  MB_IF_A_GPCN              0x150008	// MBIF A GP counter
+/* ***************************************************************************** */
+/*  */
+/* Mobilygen Interface Registers */
+/*  */
+/* ***************************************************************************** */
+/* Mobilygen Interface A */
+/* ***************************************************************************** */
+#define  MB_IF_A_DMA               0x150000	/* MBIF A DMA data port */
+#define  MB_IF_A_GPCN              0x150008	/* MBIF A GP counter */
 #define  MB_IF_A_GPCN_CTRL         0x15000C
 #define  MB_IF_A_DMA_CTRL          0x150010
 #define  MB_IF_A_LENGTH            0x150014
@@ -1415,11 +1415,11 @@
 #define  MB_IF_A_DATA_STRUCT_D     0x150058
 #define  MB_IF_A_DATA_STRUCT_E     0x15005C
 #define  MB_IF_A_DATA_STRUCT_F     0x150060
-//*****************************************************************************
-// Mobilygen Interface B
-//*****************************************************************************
-#define  MB_IF_B_DMA               0x160000	// MBIF A DMA data port
-#define  MB_IF_B_GPCN              0x160008	// MBIF A GP counter
+/* ***************************************************************************** */
+/* Mobilygen Interface B */
+/* ***************************************************************************** */
+#define  MB_IF_B_DMA               0x160000	/* MBIF A DMA data port */
+#define  MB_IF_B_GPCN              0x160008	/* MBIF A GP counter */
 #define  MB_IF_B_GPCN_CTRL         0x16000C
 #define  MB_IF_B_DMA_CTRL          0x160010
 #define  MB_IF_B_LENGTH            0x160014
@@ -1443,14 +1443,14 @@
 #define  MB_IF_B_DATA_STRUCT_E     0x16005C
 #define  MB_IF_B_DATA_STRUCT_F     0x160060
 
-// MB_DMA_CTRL
+/* MB_DMA_CTRL */
 #define  FLD_MB_IF_RISC_EN         0x00000010
 #define  FLD_MB_IF_FIFO_EN         0x00000001
 
-// MB_LENGTH
+/* MB_LENGTH */
 #define  FLD_MB_IF_LN_LNGTH        0x00000FFF
 
-// MB_HCMD register
+/* MB_HCMD register */
 #define  FLD_MB_HCMD_H_GO          0x80000000
 #define  FLD_MB_HCMD_H_BUSY        0x40000000
 #define  FLD_MB_HCMD_H_DMA_HOLD    0x10000000
@@ -1461,118 +1461,118 @@
 #define  FLD_MB_HCMD_H_ADDR        0x00FF0000
 #define  FLD_MB_HCMD_H_DATA        0x0000FFFF
 
-//*****************************************************************************
-// I2C #1
-//*****************************************************************************
-#define  I2C1_ADDR                 0x180000	// I2C #1 address
-#define  FLD_I2C_DADDR             0xfe000000	// RW [31:25] I2C Device Address
-						 // RO [24] reserved
-//*****************************************************************************
-#define  FLD_I2C_SADDR             0x00FFFFFF	// RW [23:0]  I2C Sub-address
+/* ***************************************************************************** */
+/* I2C #1 */
+/* ***************************************************************************** */
+#define  I2C1_ADDR                 0x180000	/* I2C #1 address */
+#define  FLD_I2C_DADDR             0xfe000000	/* RW [31:25] I2C Device Address */
+						 /* RO [24] reserved */
+/* ***************************************************************************** */
+#define  FLD_I2C_SADDR             0x00FFFFFF	/* RW [23:0]  I2C Sub-address */
 
-//*****************************************************************************
-#define  I2C1_WDATA                0x180004	// I2C #1 write data
-#define  FLD_I2C_WDATA             0xFFFFFFFF	// RW [31:0]
+/* ***************************************************************************** */
+#define  I2C1_WDATA                0x180004	/* I2C #1 write data */
+#define  FLD_I2C_WDATA             0xFFFFFFFF	/* RW [31:0] */
 
-//*****************************************************************************
-#define  I2C1_CTRL                 0x180008	// I2C #1 control
-#define  FLD_I2C_PERIOD            0xFF000000	// RW [31:24]
-#define  FLD_I2C_SCL_IN            0x00200000	// RW [21]
-#define  FLD_I2C_SDA_IN            0x00100000	// RW [20]
-						 // RO [19:18] reserved
-#define  FLD_I2C_SCL_OUT           0x00020000	// RW [17]
-#define  FLD_I2C_SDA_OUT           0x00010000	// RW [16]
-						 // RO [15] reserved
-#define  FLD_I2C_DATA_LEN          0x00007000	// RW [14:12]
-#define  FLD_I2C_SADDR_INC         0x00000800	// RW [11]
-						 // RO [10:9] reserved
-#define  FLD_I2C_SADDR_LEN         0x00000300	// RW [9:8]
-						 // RO [7:6] reserved
-#define  FLD_I2C_SOFT              0x00000020	// RW [5]
-#define  FLD_I2C_NOSTOP            0x00000010	// RW [4]
-#define  FLD_I2C_EXTEND            0x00000008	// RW [3]
-#define  FLD_I2C_SYNC              0x00000004	// RW [2]
-#define  FLD_I2C_READ_SA           0x00000002	// RW [1]
-#define  FLD_I2C_READ_WRN          0x00000001	// RW [0]
+/* ***************************************************************************** */
+#define  I2C1_CTRL                 0x180008	/* I2C #1 control */
+#define  FLD_I2C_PERIOD            0xFF000000	/* RW [31:24] */
+#define  FLD_I2C_SCL_IN            0x00200000	/* RW [21] */
+#define  FLD_I2C_SDA_IN            0x00100000	/* RW [20] */
+						 /* RO [19:18] reserved */
+#define  FLD_I2C_SCL_OUT           0x00020000	/* RW [17] */
+#define  FLD_I2C_SDA_OUT           0x00010000	/* RW [16] */
+						 /* RO [15] reserved */
+#define  FLD_I2C_DATA_LEN          0x00007000	/* RW [14:12] */
+#define  FLD_I2C_SADDR_INC         0x00000800	/* RW [11] */
+						 /* RO [10:9] reserved */
+#define  FLD_I2C_SADDR_LEN         0x00000300	/* RW [9:8] */
+						 /* RO [7:6] reserved */
+#define  FLD_I2C_SOFT              0x00000020	/* RW [5] */
+#define  FLD_I2C_NOSTOP            0x00000010	/* RW [4] */
+#define  FLD_I2C_EXTEND            0x00000008	/* RW [3] */
+#define  FLD_I2C_SYNC              0x00000004	/* RW [2] */
+#define  FLD_I2C_READ_SA           0x00000002	/* RW [1] */
+#define  FLD_I2C_READ_WRN          0x00000001	/* RW [0] */
 
-//*****************************************************************************
-#define  I2C1_RDATA                0x18000C	// I2C #1 read data
-#define  FLD_I2C_RDATA             0xFFFFFFFF	// RO [31:0]
+/* ***************************************************************************** */
+#define  I2C1_RDATA                0x18000C	/* I2C #1 read data */
+#define  FLD_I2C_RDATA             0xFFFFFFFF	/* RO [31:0] */
 
-//*****************************************************************************
-#define  I2C1_STAT                 0x180010	// I2C #1 status
-#define  FLD_I2C_XFER_IN_PROG      0x00000002	// RO [1]
-#define  FLD_I2C_RACK              0x00000001	// RO [0]
+/* ***************************************************************************** */
+#define  I2C1_STAT                 0x180010	/* I2C #1 status */
+#define  FLD_I2C_XFER_IN_PROG      0x00000002	/* RO [1] */
+#define  FLD_I2C_RACK              0x00000001	/* RO [0] */
 
-//*****************************************************************************
-// I2C #2
-//*****************************************************************************
-#define  I2C2_ADDR                 0x190000	// I2C #2 address
+/* ***************************************************************************** */
+/* I2C #2 */
+/* ***************************************************************************** */
+#define  I2C2_ADDR                 0x190000	/* I2C #2 address */
 
-//*****************************************************************************
-#define  I2C2_WDATA                0x190004	// I2C #2 write data
+/* ***************************************************************************** */
+#define  I2C2_WDATA                0x190004	/* I2C #2 write data */
 
-//*****************************************************************************
-#define  I2C2_CTRL                 0x190008	// I2C #2 control
+/* ***************************************************************************** */
+#define  I2C2_CTRL                 0x190008	/* I2C #2 control */
 
-//*****************************************************************************
-#define  I2C2_RDATA                0x19000C	// I2C #2 read data
+/* ***************************************************************************** */
+#define  I2C2_RDATA                0x19000C	/* I2C #2 read data */
 
-//*****************************************************************************
-#define  I2C2_STAT                 0x190010	// I2C #2 status
+/* ***************************************************************************** */
+#define  I2C2_STAT                 0x190010	/* I2C #2 status */
 
-//*****************************************************************************
-// I2C #3
-//*****************************************************************************
-#define  I2C3_ADDR                 0x1A0000	// I2C #3 address
+/* ***************************************************************************** */
+/* I2C #3 */
+/* ***************************************************************************** */
+#define  I2C3_ADDR                 0x1A0000	/* I2C #3 address */
 
-//*****************************************************************************
-#define  I2C3_WDATA                0x1A0004	// I2C #3 write data
+/* ***************************************************************************** */
+#define  I2C3_WDATA                0x1A0004	/* I2C #3 write data */
 
-//*****************************************************************************
-#define  I2C3_CTRL                 0x1A0008	// I2C #3 control
+/* ***************************************************************************** */
+#define  I2C3_CTRL                 0x1A0008	/* I2C #3 control */
 
-//*****************************************************************************
-#define  I2C3_RDATA                0x1A000C	// I2C #3 read data
+/* ***************************************************************************** */
+#define  I2C3_RDATA                0x1A000C	/* I2C #3 read data */
 
-//*****************************************************************************
-#define  I2C3_STAT                 0x1A0010	// I2C #3 status
+/* ***************************************************************************** */
+#define  I2C3_STAT                 0x1A0010	/* I2C #3 status */
 
-//*****************************************************************************
-// UART
-//*****************************************************************************
-#define  UART_CTL                  0x1B0000	// UART Control Register
-#define  FLD_LOOP_BACK_EN          (1 << 7)	// RW field - default 0
-#define  FLD_RX_TRG_SZ             (3 << 2)	// RW field - default 0
-#define  FLD_RX_EN                 (1 << 1)	// RW field - default 0
-#define  FLD_TX_EN                 (1 << 0)	// RW field - default 0
+/* ***************************************************************************** */
+/* UART */
+/* ***************************************************************************** */
+#define  UART_CTL                  0x1B0000	/* UART Control Register */
+#define  FLD_LOOP_BACK_EN          (1 << 7)	/* RW field - default 0 */
+#define  FLD_RX_TRG_SZ             (3 << 2)	/* RW field - default 0 */
+#define  FLD_RX_EN                 (1 << 1)	/* RW field - default 0 */
+#define  FLD_TX_EN                 (1 << 0)	/* RW field - default 0 */
 
-//*****************************************************************************
-#define  UART_BRD                  0x1B0004	// UART Baud Rate Divisor
-#define  FLD_BRD                   0x0000FFFF	// RW field - default 0x197
+/* ***************************************************************************** */
+#define  UART_BRD                  0x1B0004	/* UART Baud Rate Divisor */
+#define  FLD_BRD                   0x0000FFFF	/* RW field - default 0x197 */
 
-//*****************************************************************************
-#define  UART_DBUF                 0x1B0008	// UART Tx/Rx Data BuFFer
-#define  FLD_DB                    0xFFFFFFFF	// RW field - default 0
+/* ***************************************************************************** */
+#define  UART_DBUF                 0x1B0008	/* UART Tx/Rx Data BuFFer */
+#define  FLD_DB                    0xFFFFFFFF	/* RW field - default 0 */
 
-//*****************************************************************************
-#define  UART_ISR                  0x1B000C	// UART Interrupt Status
-#define  FLD_RXD_TIMEOUT_EN        (1 << 7)	// RW field - default 0
-#define  FLD_FRM_ERR_EN            (1 << 6)	// RW field - default 0
-#define  FLD_RXD_RDY_EN            (1 << 5)	// RW field - default 0
-#define  FLD_TXD_EMPTY_EN          (1 << 4)	// RW field - default 0
-#define  FLD_RXD_OVERFLOW          (1 << 3)	// RW field - default 0
-#define  FLD_FRM_ERR               (1 << 2)	// RW field - default 0
-#define  FLD_RXD_RDY               (1 << 1)	// RW field - default 0
-#define  FLD_TXD_EMPTY             (1 << 0)	// RW field - default 0
+/* ***************************************************************************** */
+#define  UART_ISR                  0x1B000C	/* UART Interrupt Status */
+#define  FLD_RXD_TIMEOUT_EN        (1 << 7)	/* RW field - default 0 */
+#define  FLD_FRM_ERR_EN            (1 << 6)	/* RW field - default 0 */
+#define  FLD_RXD_RDY_EN            (1 << 5)	/* RW field - default 0 */
+#define  FLD_TXD_EMPTY_EN          (1 << 4)	/* RW field - default 0 */
+#define  FLD_RXD_OVERFLOW          (1 << 3)	/* RW field - default 0 */
+#define  FLD_FRM_ERR               (1 << 2)	/* RW field - default 0 */
+#define  FLD_RXD_RDY               (1 << 1)	/* RW field - default 0 */
+#define  FLD_TXD_EMPTY             (1 << 0)	/* RW field - default 0 */
 
-//*****************************************************************************
-#define  UART_CNT                  0x1B0010	// UART Tx/Rx FIFO Byte Count
-#define  FLD_TXD_CNT               (0x1F << 8)	// RW field - default 0
-#define  FLD_RXD_CNT               (0x1F << 0)	// RW field - default 0
+/* ***************************************************************************** */
+#define  UART_CNT                  0x1B0010	/* UART Tx/Rx FIFO Byte Count */
+#define  FLD_TXD_CNT               (0x1F << 8)	/* RW field - default 0 */
+#define  FLD_RXD_CNT               (0x1F << 0)	/* RW field - default 0 */
 
-//*****************************************************************************
-// Motion Detection
+/* ***************************************************************************** */
+/* Motion Detection */
 #define  MD_CH0_GRID_BLOCK_YCNT    0x170014
 #define  MD_CH1_GRID_BLOCK_YCNT    0x170094
 #define  MD_CH2_GRID_BLOCK_YCNT    0x170114
@@ -1589,4 +1589,4 @@
 #define PIXEL_ENGINE_VIP1 0
 #define PIXEL_ENGINE_VIP2 1
 
-#endif //Athena_REGISTERS
+#endif /* Athena_REGISTERS */
diff --git a/drivers/staging/cx25821/cx25821-sram.h b/drivers/staging/cx25821/cx25821-sram.h
index bd677ee..5f05d15 100644
--- a/drivers/staging/cx25821/cx25821-sram.h
+++ b/drivers/staging/cx25821/cx25821-sram.h
@@ -23,34 +23,34 @@
 #ifndef __ATHENA_SRAM_H__
 #define __ATHENA_SRAM_H__
 
-//#define RX_SRAM_START_SIZE        = 0;  //  Start of reserved SRAM
-#define VID_CMDS_SIZE             80	//  Video CMDS size in bytes
-#define AUDIO_CMDS_SIZE           80	//  AUDIO CMDS size in bytes
-#define MBIF_CMDS_SIZE            80	//  MBIF  CMDS size in bytes
+/* #define RX_SRAM_START_SIZE        = 0;  //  Start of reserved SRAM */
+#define VID_CMDS_SIZE             80	/* Video CMDS size in bytes */
+#define AUDIO_CMDS_SIZE           80	/* AUDIO CMDS size in bytes */
+#define MBIF_CMDS_SIZE            80	/* MBIF  CMDS size in bytes */
 
-//#define RX_SRAM_POOL_START_SIZE   = 0;  //  Start of useable RX SRAM for buffers
-#define VID_IQ_SIZE               64	//  VID instruction queue size in bytes
+/* #define RX_SRAM_POOL_START_SIZE   = 0;  //  Start of useable RX SRAM for buffers */
+#define VID_IQ_SIZE               64	/* VID instruction queue size in bytes */
 #define MBIF_IQ_SIZE              64
-#define AUDIO_IQ_SIZE             64	//  AUD instruction queue size in bytes
+#define AUDIO_IQ_SIZE             64	/* AUD instruction queue size in bytes */
 
-#define VID_CDT_SIZE              64	//  VID cluster descriptor table size in bytes
-#define MBIF_CDT_SIZE             64	//  MBIF/HBI cluster descriptor table size in bytes
-#define AUDIO_CDT_SIZE            48	//  AUD cluster descriptor table size in bytes
+#define VID_CDT_SIZE              64	/* VID cluster descriptor table size in bytes */
+#define MBIF_CDT_SIZE             64	/* MBIF/HBI cluster descriptor table size in bytes */
+#define AUDIO_CDT_SIZE            48	/* AUD cluster descriptor table size in bytes */
 
-//#define RX_SRAM_POOL_FREE_SIZE    = 16; //  Start of available RX SRAM
-//#define RX_SRAM_END_SIZE          = 0;  //  End of RX SRAM
+/* #define RX_SRAM_POOL_FREE_SIZE    = 16; //  Start of available RX SRAM */
+/* #define RX_SRAM_END_SIZE          = 0;  //  End of RX SRAM */
 
-//#define TX_SRAM_POOL_START_SIZE   = 0;  //  Start of transmit pool SRAM
-//#define MSI_DATA_SIZE             = 64; //  Reserved (MSI Data, RISC working stora
+/* #define TX_SRAM_POOL_START_SIZE   = 0;  //  Start of transmit pool SRAM */
+/* #define MSI_DATA_SIZE             = 64; //  Reserved (MSI Data, RISC working stora */
 
-#define VID_CLUSTER_SIZE          1440	//  VID cluster data line
-#define AUDIO_CLUSTER_SIZE        128	//  AUDIO cluster data line
-#define MBIF_CLUSTER_SIZE         1440	//  MBIF/HBI cluster data line
+#define VID_CLUSTER_SIZE          1440	/* VID cluster data line */
+#define AUDIO_CLUSTER_SIZE        128	/* AUDIO cluster data line */
+#define MBIF_CLUSTER_SIZE         1440	/* MBIF/HBI cluster data line */
 
-//#define TX_SRAM_POOL_FREE_SIZE    = 704;    //  Start of available TX SRAM
-//#define TX_SRAM_END_SIZE          = 0;      //  End of TX SRAM
+/* #define TX_SRAM_POOL_FREE_SIZE    = 704;    //  Start of available TX SRAM */
+/* #define TX_SRAM_END_SIZE          = 0;      //  End of TX SRAM */
 
-// Receive SRAM
+/* Receive SRAM */
 #define RX_SRAM_START             0x10000
 #define VID_A_DOWN_CMDS           0x10000
 #define VID_B_DOWN_CMDS           0x10050
@@ -78,9 +78,9 @@
 #define AUD_E_UP_CMDS             0x10730
 #define MBIF_A_DOWN_CMDS          0x10780
 #define MBIF_B_DOWN_CMDS          0x107D0
-#define DMA_SCRATCH_PAD           0x10820	// Scratch pad area from 0x10820 to 0x10B40
+#define DMA_SCRATCH_PAD           0x10820	/* Scratch pad area from 0x10820 to 0x10B40 */
 
-//#define RX_SRAM_POOL_START        = 0x105B0;
+/* #define RX_SRAM_POOL_START        = 0x105B0; */
 
 #define VID_A_IQ                  0x11000
 #define VID_B_IQ                  0x11040
@@ -118,7 +118,7 @@
 #define MBIF_A_CDT                0x10C00
 #define MBIF_B_CDT                0x10CC0
 
-// Cluster Buffer for RX
+/* Cluster Buffer for RX */
 #define VID_A_UP_CLUSTER_1        0x11400
 #define VID_A_UP_CLUSTER_2        0x119A0
 #define VID_A_UP_CLUSTER_3        0x11F40
@@ -178,9 +178,9 @@
 #define RX_SRAM_POOL_FREE         0x1CE00
 #define RX_SRAM_END               0x1D000
 
-// Free Receive SRAM    144 Bytes
+/* Free Receive SRAM    144 Bytes */
 
-// Transmit SRAM
+/* Transmit SRAM */
 #define TX_SRAM_POOL_START        0x00000
 
 #define VID_A_DOWN_CLUSTER_1      0x00040
diff --git a/drivers/staging/cx25821/cx25821-video-upstream-ch2.c b/drivers/staging/cx25821/cx25821-video-upstream-ch2.c
index 343df66..d12dbb5 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream-ch2.c
+++ b/drivers/staging/cx25821/cx25821-video-upstream-ch2.c
@@ -84,7 +84,7 @@
 {
 	unsigned int line, i;
 	struct sram_channel *sram_ch =
-	    &dev->sram_channels[dev->_channel2_upstream_select];
+	   dev->channels[dev->_channel2_upstream_select].sram_channels;
 	int dist_betwn_starts = bpl * 2;
 
 	/* sync instruction */
@@ -110,8 +110,11 @@
 			offset += dist_betwn_starts;
 		}
 
-		// check if we need to enable the FIFO after the first 4 lines
-		// For the upstream video channel, the risc engine will enable the FIFO.
+	       /*
+		 check if we need to enable the FIFO after the first 4 lines
+		  For the upstream video channel, the risc engine will enable
+		  the FIFO.
+	       */
 		if (fifo_enable && line == 3) {
 			*(rp++) = RISC_WRITECR;
 			*(rp++) = sram_ch->dma_ctl;
@@ -130,7 +133,7 @@
 {
 	__le32 *rp;
 	int fifo_enable = 0;
-	int singlefield_lines = lines >> 1;	//get line count for single field
+       int singlefield_lines = lines >> 1; /*get line count for single field */
 	int odd_num_lines = singlefield_lines;
 	int frame = 0;
 	int frame_size = 0;
@@ -174,7 +177,7 @@
 
 		fifo_enable = FIFO_DISABLE;
 
-		//Even field
+	       /* Even field */
 		rp = cx25821_risc_field_upstream_ch2(dev, rp,
 						     dev->
 						     _data_buf_phys_addr_ch2 +
@@ -192,7 +195,10 @@
 			risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2;
 		}
 
-		// Loop to 2ndFrameRISC or to Start of Risc program & generate IRQ
+	       /*
+		  Loop to 2ndFrameRISC or to Start of
+		  Risc program & generate IRQ
+	       */
 		*(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag);
 		*(rp++) = cpu_to_le32(risc_phys_jump_addr);
 		*(rp++) = cpu_to_le32(0);
@@ -204,7 +210,7 @@
 void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev)
 {
 	struct sram_channel *sram_ch =
-	    &dev->sram_channels[VID_UPSTREAM_SRAM_CHANNEL_J];
+	   dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels;
 	u32 tmp = 0;
 
 	if (!dev->_is_running_ch2) {
@@ -212,15 +218,15 @@
 		    ("cx25821: No video file is currently running so return!\n");
 		return;
 	}
-	//Disable RISC interrupts
+       /* Disable RISC interrupts */
 	tmp = cx_read(sram_ch->int_msk);
 	cx_write(sram_ch->int_msk, tmp & ~_intr_msk);
 
-	//Turn OFF risc and fifo
+       /* Turn OFF risc and fifo */
 	tmp = cx_read(sram_ch->dma_ctl);
 	cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN));
 
-	//Clear data buffer memory
+       /* Clear data buffer memory */
 	if (dev->_data_buf_virt_addr_ch2)
 		memset(dev->_data_buf_virt_addr_ch2, 0,
 		       dev->_data_buf_size_ch2);
@@ -371,8 +377,8 @@
 	}
 
 	cx25821_get_frame_ch2(dev,
-			      &dev->sram_channels[dev->
-						  _channel2_upstream_select]);
+			     dev->channels[dev->
+			       _channel2_upstream_select].sram_channels);
 }
 
 int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
@@ -488,7 +494,7 @@
 		return -ENOMEM;
 	}
 
-	//Iniitize at this address until n bytes to 0
+       /* Iniitize at this address until n bytes to 0 */
 	memset(dev->_dma_virt_addr_ch2, 0, dev->_risc_size_ch2);
 
 	if (dev->_data_buf_virt_addr_ch2 != NULL) {
@@ -496,7 +502,7 @@
 				    dev->_data_buf_virt_addr_ch2,
 				    dev->_data_buf_phys_addr_ch2);
 	}
-	//For Video Data buffer allocation
+       /* For Video Data buffer allocation */
 	dev->_data_buf_virt_addr_ch2 =
 	    pci_alloc_consistent(dev->pci, dev->upstream_databuf_size_ch2,
 				 &data_dma_addr);
@@ -509,14 +515,14 @@
 		return -ENOMEM;
 	}
 
-	//Initialize at this address until n bytes to 0
+       /* Initialize at this address until n bytes to 0 */
 	memset(dev->_data_buf_virt_addr_ch2, 0, dev->_data_buf_size_ch2);
 
 	ret = cx25821_openfile_ch2(dev, sram_ch);
 	if (ret < 0)
 		return ret;
 
-	//Creating RISC programs
+       /* Creating RISC programs */
 	ret =
 	    cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl,
 					     dev->_lines_count_ch2);
@@ -536,7 +542,7 @@
 				   u32 status)
 {
 	u32 int_msk_tmp;
-	struct sram_channel *channel = &dev->sram_channels[chan_num];
+       struct sram_channel *channel = dev->channels[chan_num].sram_channels;
 	int singlefield_lines = NTSC_FIELD_HEIGHT;
 	int line_size_in_bytes = Y422_LINE_SZ;
 	int odd_risc_prog_size = 0;
@@ -544,10 +550,13 @@
 	__le32 *rp;
 
 	if (status & FLD_VID_SRC_RISC1) {
-		// We should only process one program per call
+	       /* We should only process one program per call */
 		u32 prog_cnt = cx_read(channel->gpcnt);
 
-		//Since we've identified our IRQ, clear our bits from the interrupt mask and interrupt status registers
+	       /*
+		  Since we've identified our IRQ, clear our bits from the
+		  interrupt mask and interrupt status registers
+	       */
 		int_msk_tmp = cx_read(channel->int_msk);
 		cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk);
 		cx_write(channel->int_stat, _intr_msk);
@@ -588,7 +597,7 @@
 								    FIFO_DISABLE,
 								    ODD_FIELD);
 
-				// Jump to Even Risc program of 1st Frame
+			       /* Jump to Even Risc program of 1st Frame */
 				*(rp++) = cpu_to_le32(RISC_JUMP);
 				*(rp++) = cpu_to_le32(risc_phys_jump_addr);
 				*(rp++) = cpu_to_le32(0);
@@ -603,7 +612,7 @@
 		       dev->_frame_count_ch2);
 		return -1;
 	}
-	//ElSE, set the interrupt mask register, re-enable irq.
+       /* ElSE, set the interrupt mask register, re-enable irq. */
 	int_msk_tmp = cx_read(channel->int_msk);
 	cx_write(channel->int_msk, int_msk_tmp |= _intr_msk);
 
@@ -623,12 +632,12 @@
 
 	channel_num = VID_UPSTREAM_SRAM_CHANNEL_J;
 
-	sram_ch = &dev->sram_channels[channel_num];
+       sram_ch = dev->channels[channel_num].sram_channels;
 
 	msk_stat = cx_read(sram_ch->int_mstat);
 	vid_status = cx_read(sram_ch->int_stat);
 
-	// Only deal with our interrupt
+       /* Only deal with our interrupt */
 	if (vid_status) {
 		handled =
 		    cx25821_video_upstream_irq_ch2(dev, channel_num,
@@ -658,7 +667,10 @@
 	value |= dev->_isNTSC_ch2 ? 0 : 0x10;
 	cx_write(ch->vid_fmt_ctl, value);
 
-	// set number of active pixels in each line. Default is 720 pixels in both NTSC and PAL format
+       /*
+	  set number of active pixels in each line. Default is 720
+	  pixels in both NTSC and PAL format
+       */
 	cx_write(ch->vid_active_ctl1, width);
 
 	num_lines = (height / 2) & 0x3FF;
@@ -670,7 +682,7 @@
 
 	value = (num_lines << 16) | odd_num_lines;
 
-	// set number of active lines in field 0 (top) and field 1 (bottom)
+       /* set number of active lines in field 0 (top) and field 1 (bottom) */
 	cx_write(ch->vid_active_ctl2, value);
 
 	cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3);
@@ -682,21 +694,27 @@
 	u32 tmp = 0;
 	int err = 0;
 
-	// 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for channel A-C
+       /*
+	  656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface
+	  for channel A-C
+       */
 	tmp = cx_read(VID_CH_MODE_SEL);
 	cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
 
-	// Set the physical start address of the RISC program in the initial program counter(IPC) member of the cmds.
+       /*
+	  Set the physical start address of the RISC program in the initial
+	  program counter(IPC) member of the cmds.
+       */
 	cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr_ch2);
-	cx_write(sram_ch->cmds_start + 4, 0);	/* Risc IPC High 64 bits 63-32 */
+       cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */
 
 	/* reset counter */
 	cx_write(sram_ch->gpcnt_ctl, 3);
 
-	// Clear our bits from the interrupt status register.
+       /* Clear our bits from the interrupt status register. */
 	cx_write(sram_ch->int_stat, _intr_msk);
 
-	//Set the interrupt mask register, enable irq.
+       /* Set the interrupt mask register, enable irq. */
 	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit));
 	tmp = cx_read(sram_ch->int_msk);
 	cx_write(sram_ch->int_msk, tmp |= _intr_msk);
@@ -709,7 +727,7 @@
 		       dev->pci->irq);
 		goto fail_irq;
 	}
-	// Start the DMA  engine
+       /* Start the DMA  engine */
 	tmp = cx_read(sram_ch->dma_ctl);
 	cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN);
 
@@ -740,7 +758,7 @@
 	}
 
 	dev->_channel2_upstream_select = channel_select;
-	sram_ch = &dev->sram_channels[channel_select];
+       sram_ch = dev->channels[channel_select].sram_channels;
 
 	INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2);
 	dev->_irq_queues_ch2 =
@@ -751,7 +769,10 @@
 		    ("cx25821: create_singlethread_workqueue() for Video FAILED!\n");
 		return -ENOMEM;
 	}
-	// 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for channel A-C
+       /*
+	  656/VIP SRC Upstream Channel I & J and 7 -
+	  Host Bus Interface for channel A-C
+       */
 	tmp = cx_read(VID_CH_MODE_SEL);
 	cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
 
@@ -787,7 +808,7 @@
 		       str_length + 1);
 	}
 
-	//Default if filename is empty string
+       /* Default if filename is empty string */
 	if (strcmp(dev->input_filename_ch2, "") == 0) {
 		if (dev->_isNTSC_ch2) {
 			dev->_filename_ch2 =
@@ -812,7 +833,7 @@
 	dev->upstream_riscbuf_size_ch2 = risc_buffer_size * 2;
 	dev->upstream_databuf_size_ch2 = data_frame_size * 2;
 
-	//Allocating buffers and prepare RISC program
+       /* Allocating buffers and prepare RISC program */
 	retval =
 	    cx25821_upstream_buffer_prepare_ch2(dev, sram_ch,
 						dev->_line_size_ch2);
diff --git a/drivers/staging/cx25821/cx25821-video-upstream-ch2.h b/drivers/staging/cx25821/cx25821-video-upstream-ch2.h
index 73feea1..6234063 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream-ch2.h
+++ b/drivers/staging/cx25821/cx25821-video-upstream-ch2.h
@@ -37,7 +37,7 @@
 #define RESET_STATUS          -1
 #define NUM_NO_OPS            5
 
-// PAL and NTSC line sizes and number of lines.
+/* PAL and NTSC line sizes and number of lines. */
 #define WIDTH_D1              720
 #define NTSC_LINES_PER_FRAME  480
 #define PAL_LINES_PER_FRAME   576
diff --git a/drivers/staging/cx25821/cx25821-video-upstream.c b/drivers/staging/cx25821/cx25821-video-upstream.c
index 7a3dad9..756a820 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream.c
+++ b/drivers/staging/cx25821/cx25821-video-upstream.c
@@ -134,7 +134,7 @@
 {
 	unsigned int line, i;
 	struct sram_channel *sram_ch =
-	    &dev->sram_channels[dev->_channel_upstream_select];
+	   dev->channels[dev->_channel_upstream_select].sram_channels;
 	int dist_betwn_starts = bpl * 2;
 
 	/* sync instruction */
@@ -253,7 +253,7 @@
 void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev)
 {
 	struct sram_channel *sram_ch =
-	    &dev->sram_channels[VID_UPSTREAM_SRAM_CHANNEL_I];
+	   dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels;
 	u32 tmp = 0;
 
 	if (!dev->_is_running) {
@@ -346,20 +346,23 @@
 
 	if (IS_ERR(myfile)) {
 		const int open_errno = -PTR_ERR(myfile);
-		printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
-		       __func__, dev->_filename, open_errno);
+	       printk(KERN_ERR
+		   "%s(): ERROR opening file(%s) with errno = %d!\n",
+		   __func__, dev->_filename, open_errno);
 		return PTR_ERR(myfile);
 	} else {
 		if (!(myfile->f_op)) {
-			printk(KERN_ERR "%s: File has no file operations registered!",
-			       __func__);
+		       printk(KERN_ERR
+			   "%s: File has no file operations registered!",
+			   __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
 		}
 
 		if (!myfile->f_op->read) {
-			printk(KERN_ERR "%s: File has no READ operations registered!",
-			       __func__);
+		       printk(KERN_ERR
+			   "%s: File has no READ operations registered!",
+			   __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
 		}
@@ -386,7 +389,8 @@
 
 			if (vfs_read_retval < line_size) {
 				printk(KERN_INFO
-				       "Done: exit %s() since no more bytes to read from Video file.\n",
+				      "Done: exit %s() since no more bytes to \
+				      read from Video file.\n",
 				       __func__);
 				break;
 			}
@@ -411,13 +415,15 @@
 	    container_of(work, struct cx25821_dev, _irq_work_entry);
 
 	if (!dev) {
-		printk(KERN_ERR "ERROR %s(): since container_of(work_struct) FAILED!\n",
-		       __func__);
+	       printk(KERN_ERR
+		   "ERROR %s(): since container_of(work_struct) FAILED!\n",
+		   __func__);
 		return;
 	}
 
 	cx25821_get_frame(dev,
-			  &dev->sram_channels[dev->_channel_upstream_select]);
+			 dev->channels[dev->_channel_upstream_select].
+					       sram_channels);
 }
 
 int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
@@ -437,20 +443,22 @@
 
 	if (IS_ERR(myfile)) {
 		const int open_errno = -PTR_ERR(myfile);
-		printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
+	       printk(KERN_ERR  "%s(): ERROR opening file(%s) with errno = %d!\n",
 		       __func__, dev->_filename, open_errno);
 		return PTR_ERR(myfile);
 	} else {
 		if (!(myfile->f_op)) {
-			printk(KERN_ERR "%s: File has no file operations registered!",
-			       __func__);
+		       printk(KERN_ERR
+			   "%s: File has no file operations registered!",
+			   __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
 		}
 
 		if (!myfile->f_op->read) {
-			printk
-			    (KERN_ERR "%s: File has no READ operations registered!  Returning.",
+		       printk(KERN_ERR
+			   "%s: File has no READ operations registered!  \
+			   Returning.",
 			     __func__);
 			filp_close(myfile, NULL);
 			return -EIO;
@@ -480,7 +488,8 @@
 
 				if (vfs_read_retval < line_size) {
 					printk(KERN_INFO
-					       "Done: exit %s() since no more bytes to read from Video file.\n",
+					    "Done: exit %s() since no more \
+					    bytes to read from Video file.\n",
 					       __func__);
 					break;
 				}
@@ -526,7 +535,8 @@
 
 	if (!dev->_dma_virt_addr) {
 		printk
-		    (KERN_ERR "cx25821: FAILED to allocate memory for Risc buffer! Returning.\n");
+		   (KERN_ERR "cx25821: FAILED to allocate memory for Risc \
+		   buffer! Returning.\n");
 		return -ENOMEM;
 	}
 
@@ -547,7 +557,8 @@
 
 	if (!dev->_data_buf_virt_addr) {
 		printk
-		    (KERN_ERR "cx25821: FAILED to allocate memory for data buffer! Returning.\n");
+		   (KERN_ERR "cx25821: FAILED to allocate memory for data \
+		   buffer! Returning.\n");
 		return -ENOMEM;
 	}
 
@@ -578,7 +589,7 @@
 			       u32 status)
 {
 	u32 int_msk_tmp;
-	struct sram_channel *channel = &dev->sram_channels[chan_num];
+       struct sram_channel *channel = dev->channels[chan_num].sram_channels;
 	int singlefield_lines = NTSC_FIELD_HEIGHT;
 	int line_size_in_bytes = Y422_LINE_SZ;
 	int odd_risc_prog_size = 0;
@@ -642,16 +653,16 @@
 	} else {
 		if (status & FLD_VID_SRC_UF)
 			printk
-			    (KERN_ERR "%s: Video Received Underflow Error Interrupt!\n",
-			     __func__);
+			   (KERN_ERR "%s: Video Received Underflow Error \
+			   Interrupt!\n", __func__);
 
 		if (status & FLD_VID_SRC_SYNC)
-			printk(KERN_ERR "%s: Video Received Sync Error Interrupt!\n",
-			       __func__);
+		       printk(KERN_ERR "%s: Video Received Sync Error \
+		       Interrupt!\n", __func__);
 
 		if (status & FLD_VID_SRC_OPC_ERR)
-			printk(KERN_ERR "%s: Video Received OpCode Error Interrupt!\n",
-			       __func__);
+		       printk(KERN_ERR "%s: Video Received OpCode Error \
+		       Interrupt!\n", __func__);
 	}
 
 	if (dev->_file_status == END_OF_FILE) {
@@ -679,7 +690,7 @@
 
 	channel_num = VID_UPSTREAM_SRAM_CHANNEL_I;
 
-	sram_ch = &dev->sram_channels[channel_num];
+       sram_ch = dev->channels[channel_num].sram_channels;
 
 	msk_stat = cx_read(sram_ch->int_mstat);
 	vid_status = cx_read(sram_ch->int_stat);
@@ -800,14 +811,15 @@
 	}
 
 	dev->_channel_upstream_select = channel_select;
-	sram_ch = &dev->sram_channels[channel_select];
+       sram_ch = dev->channels[channel_select].sram_channels;
 
 	INIT_WORK(&dev->_irq_work_entry, cx25821_vidups_handler);
 	dev->_irq_queues = create_singlethread_workqueue("cx25821_workqueue");
 
 	if (!dev->_irq_queues) {
 		printk
-		    (KERN_ERR "cx25821: create_singlethread_workqueue() for Video FAILED!\n");
+		   (KERN_ERR "cx25821: create_singlethread_workqueue() for \
+		   Video FAILED!\n");
 		return -ENOMEM;
 	}
 	/* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for
diff --git a/drivers/staging/cx25821/cx25821-video-upstream.h b/drivers/staging/cx25821/cx25821-video-upstream.h
index cc9f938..10dee5c 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream.h
+++ b/drivers/staging/cx25821/cx25821-video-upstream.h
@@ -38,7 +38,7 @@
 #define RESET_STATUS          -1
 #define NUM_NO_OPS            5
 
-// PAL and NTSC line sizes and number of lines.
+/* PAL and NTSC line sizes and number of lines. */
 #define WIDTH_D1              720
 #define NTSC_LINES_PER_FRAME  480
 #define PAL_LINES_PER_FRAME   576
diff --git a/drivers/staging/cx25821/cx25821-video.c b/drivers/staging/cx25821/cx25821-video.c
index 791212c..1d5e879 100644
--- a/drivers/staging/cx25821/cx25821-video.c
+++ b/drivers/staging/cx25821/cx25821-video.c
@@ -4,6 +4,9 @@
  *  Copyright (C) 2009 Conexant Systems Inc.
  *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
  *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
+ *  Parts adapted/taken from Eduardo Moscoso Rubino
+ *  Copyright (C) 2009 Eduardo Moscoso Rubino <moscoso@TopoLogica.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
@@ -24,7 +27,7 @@
 #include "cx25821-video.h"
 
 MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
-MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
+MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
 MODULE_LICENSE("GPL");
 
 static unsigned int video_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
@@ -48,7 +51,10 @@
 module_param(vid_limit, int, 0644);
 MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
 
-static void init_controls(struct cx25821_dev *dev, int chan_num);
+static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num);
+
+static const struct v4l2_file_operations video_fops;
+static const struct v4l2_ioctl_ops video_ioctl_ops;
 
 #define FORMAT_FLAGS_PACKED       0x01
 
@@ -211,7 +217,7 @@
 }
 */
 
-// resource management
+/* resource management */
 int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bit)
 {
 	dprintk(1, "%s()\n", __func__);
@@ -221,14 +227,14 @@
 
 	/* is it free? */
 	mutex_lock(&dev->lock);
-	if (dev->resources & bit) {
+       if (dev->channels[fh->channel_id].resources & bit) {
 		/* no, someone else uses it */
 		mutex_unlock(&dev->lock);
 		return 0;
 	}
 	/* it's free, grab it */
 	fh->resources |= bit;
-	dev->resources |= bit;
+       dev->channels[fh->channel_id].resources |= bit;
 	dprintk(1, "res: get %d\n", bit);
 	mutex_unlock(&dev->lock);
 	return 1;
@@ -239,9 +245,9 @@
 	return fh->resources & bit;
 }
 
-int cx25821_res_locked(struct cx25821_dev *dev, unsigned int bit)
+int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit)
 {
-	return dev->resources & bit;
+       return fh->dev->channels[fh->channel_id].resources & bit;
 }
 
 void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bits)
@@ -251,7 +257,7 @@
 
 	mutex_lock(&dev->lock);
 	fh->resources &= ~bits;
-	dev->resources &= ~bits;
+       dev->channels[fh->channel_id].resources &= ~bits;
 	dprintk(1, "res: put %d\n", bits);
 	mutex_unlock(&dev->lock);
 }
@@ -358,11 +364,11 @@
 	struct cx25821_data *timeout_data = (struct cx25821_data *)data;
 	struct cx25821_dev *dev = timeout_data->dev;
 	struct sram_channel *channel = timeout_data->channel;
-	struct cx25821_dmaqueue *q = &dev->vidq[channel->i];
+       struct cx25821_dmaqueue *q = &dev->channels[channel->i].vidq;
 	struct cx25821_buffer *buf;
 	unsigned long flags;
 
-	//cx25821_sram_channel_dump(dev, channel);
+       /* cx25821_sram_channel_dump(dev, channel); */
 	cx_clear(channel->dma_ctl, 0x11);
 
 	spin_lock_irqsave(&dev->slock, flags);
@@ -384,7 +390,7 @@
 	u32 count = 0;
 	int handled = 0;
 	u32 mask;
-	struct sram_channel *channel = &dev->sram_channels[chan_num];
+       struct sram_channel *channel = dev->channels[chan_num].sram_channels;
 
 	mask = cx_read(channel->int_msk);
 	if (0 == (status & mask))
@@ -404,7 +410,8 @@
 	if (status & FLD_VID_DST_RISC1) {
 		spin_lock(&dev->slock);
 		count = cx_read(channel->gpcnt);
-		cx25821_video_wakeup(dev, &dev->vidq[channel->i], count);
+	       cx25821_video_wakeup(dev,
+		       &dev->channels[channel->i].vidq, count);
 		spin_unlock(&dev->slock);
 		handled++;
 	}
@@ -413,8 +420,9 @@
 	if (status & 0x10) {
 		dprintk(2, "stopper video\n");
 		spin_lock(&dev->slock);
-		cx25821_restart_video_queue(dev, &dev->vidq[channel->i],
-					    channel);
+	       cx25821_restart_video_queue(dev,
+			       &dev->channels[channel->i].vidq,
+				       channel);
 		spin_unlock(&dev->slock);
 		handled++;
 	}
@@ -437,72 +445,95 @@
 {
 	cx_clear(PCI_INT_MSK, 1);
 
-	if (dev->video_dev[chan_num]) {
-		if (video_is_registered(dev->video_dev[chan_num]))
-			video_unregister_device(dev->video_dev[chan_num]);
+       if (dev->channels[chan_num].video_dev) {
+	       if (video_is_registered(dev->channels[chan_num].video_dev))
+		       video_unregister_device(
+			       dev->channels[chan_num].video_dev);
 		else
-			video_device_release(dev->video_dev[chan_num]);
+		       video_device_release(
+			       dev->channels[chan_num].video_dev);
 
-		dev->video_dev[chan_num] = NULL;
+	       dev->channels[chan_num].video_dev = NULL;
 
-		btcx_riscmem_free(dev->pci, &dev->vidq[chan_num].stopper);
+	       btcx_riscmem_free(dev->pci,
+		       &dev->channels[chan_num].vidq.stopper);
 
 		printk(KERN_WARNING "device %d released!\n", chan_num);
 	}
 
 }
 
-int cx25821_video_register(struct cx25821_dev *dev, int chan_num,
-			   struct video_device *video_template)
+int cx25821_video_register(struct cx25821_dev *dev)
 {
 	int err;
+       int i;
+
+       struct video_device cx25821_video_device = {
+	       .name = "cx25821-video",
+	       .fops = &video_fops,
+	       .minor = -1,
+	       .ioctl_ops = &video_ioctl_ops,
+	       .tvnorms = CX25821_NORMS,
+	       .current_norm = V4L2_STD_NTSC_M,
+       };
 
 	spin_lock_init(&dev->slock);
 
-	//printk(KERN_WARNING "Channel %d\n", chan_num);
+    for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) {
+	       cx25821_init_controls(dev, i);
 
-#ifdef TUNER_FLAG
-	dev->tvnorm = video_template->current_norm;
-#endif
+	       cx25821_risc_stopper(dev->pci,
+			       &dev->channels[i].vidq.stopper,
+			       dev->channels[i].sram_channels->dma_ctl,
+			       0x11, 0);
 
-	/* init video dma queues */
-	dev->timeout_data[chan_num].dev = dev;
-	dev->timeout_data[chan_num].channel = &dev->sram_channels[chan_num];
-	INIT_LIST_HEAD(&dev->vidq[chan_num].active);
-	INIT_LIST_HEAD(&dev->vidq[chan_num].queued);
-	dev->vidq[chan_num].timeout.function = cx25821_vid_timeout;
-	dev->vidq[chan_num].timeout.data =
-	    (unsigned long)&dev->timeout_data[chan_num];
-	init_timer(&dev->vidq[chan_num].timeout);
-	cx25821_risc_stopper(dev->pci, &dev->vidq[chan_num].stopper,
-			     dev->sram_channels[chan_num].dma_ctl, 0x11, 0);
+	       dev->channels[i].sram_channels = &cx25821_sram_channels[i];
+	       dev->channels[i].video_dev = NULL;
+	       dev->channels[i].resources = 0;
 
-	/* register v4l devices */
-	dev->video_dev[chan_num] =
-	    cx25821_vdev_init(dev, dev->pci, video_template, "video");
-	err =
-	    video_register_device(dev->video_dev[chan_num], VFL_TYPE_GRABBER,
-				  video_nr[dev->nr]);
+	       cx_write(dev->channels[i].sram_channels->int_stat,
+			       0xffffffff);
 
-	if (err < 0) {
-		goto fail_unreg;
+	       INIT_LIST_HEAD(&dev->channels[i].vidq.active);
+	       INIT_LIST_HEAD(&dev->channels[i].vidq.queued);
+
+	       dev->channels[i].timeout_data.dev = dev;
+	       dev->channels[i].timeout_data.channel =
+				       &cx25821_sram_channels[i];
+	       dev->channels[i].vidq.timeout.function =
+				       cx25821_vid_timeout;
+	       dev->channels[i].vidq.timeout.data =
+		       (unsigned long)&dev->channels[i].timeout_data;
+	       init_timer(&dev->channels[i].vidq.timeout);
+
+	       /* register v4l devices */
+	       dev->channels[i].video_dev = cx25821_vdev_init(dev,
+		       dev->pci, &cx25821_video_device, "video");
+
+	       err = video_register_device(dev->channels[i].video_dev,
+			       VFL_TYPE_GRABBER, video_nr[dev->nr]);
+
+	       if (err < 0)
+		       goto fail_unreg;
+
 	}
-	//set PCI interrupt
+
+    /* set PCI interrupt */
 	cx_set(PCI_INT_MSK, 0xff);
 
 	/* initial device configuration */
 	mutex_lock(&dev->lock);
 #ifdef TUNER_FLAG
+       dev->tvnorm = cx25821_video_device.current_norm;
 	cx25821_set_tvnorm(dev, dev->tvnorm);
 #endif
 	mutex_unlock(&dev->lock);
 
-	init_controls(dev, chan_num);
 
-	return 0;
+    return 0;
 
-      fail_unreg:
-	cx25821_video_unregister(dev, chan_num);
+fail_unreg:
+       cx25821_video_unregister(dev, i);
 	return err;
 }
 
@@ -533,7 +564,7 @@
 	u32 line0_offset, line1_offset;
 	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
 	int bpl_local = LINE_SIZE_D1;
-	int channel_opened = 0;
+       int channel_opened = fh->channel_id;
 
 	BUG_ON(NULL == fh->fmt);
 	if (fh->width < 48 || fh->width > 720 ||
@@ -572,26 +603,29 @@
 		channel_opened = (channel_opened < 0
 				  || channel_opened > 7) ? 7 : channel_opened;
 
-		if (dev->pixel_formats[channel_opened] == PIXEL_FRMT_411)
+	       if (dev->channels[channel_opened]
+		       .pixel_formats == PIXEL_FRMT_411)
 			buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3;
 		else
 			buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width);
 
-		if (dev->pixel_formats[channel_opened] == PIXEL_FRMT_411) {
+	       if (dev->channels[channel_opened]
+		       .pixel_formats == PIXEL_FRMT_411) {
 			bpl_local = buf->bpl;
 		} else {
-			bpl_local = buf->bpl;	//Default
+		       bpl_local = buf->bpl;   /* Default */
 
 			if (channel_opened >= 0 && channel_opened <= 7) {
-				if (dev->use_cif_resolution[channel_opened]) {
+			       if (dev->channels[channel_opened]
+					       .use_cif_resolution) {
 					if (dev->tvnorm & V4L2_STD_PAL_BG
 					    || dev->tvnorm & V4L2_STD_PAL_DK)
 						bpl_local = 352 << 1;
 					else
 						bpl_local =
-						    dev->
-						    cif_width[channel_opened] <<
-						    1;
+						 dev->channels[channel_opened].
+						 cif_width <<
+						 1;
 				}
 			}
 		}
@@ -685,6 +719,383 @@
 	return videobuf_mmap_mapper(get_queue(fh), vma);
 }
 
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct cx25821_buffer *buf =
+	   container_of(vb, struct cx25821_buffer, vb);
+       struct cx25821_buffer *prev;
+       struct cx25821_fh *fh = vq->priv_data;
+       struct cx25821_dev *dev = fh->dev;
+       struct cx25821_dmaqueue *q = &dev->channels[fh->channel_id].vidq;
+
+       /* add jump to stopper */
+       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+       buf->risc.jmp[2] = cpu_to_le32(0);      /* bits 63-32 */
+
+       dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
+
+       if (!list_empty(&q->queued)) {
+	       list_add_tail(&buf->vb.queue, &q->queued);
+	       buf->vb.state = VIDEOBUF_QUEUED;
+	       dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
+		       buf->vb.i);
+
+       } else if (list_empty(&q->active)) {
+	       list_add_tail(&buf->vb.queue, &q->active);
+	       cx25821_start_video_dma(dev, q, buf,
+				       dev->channels[fh->channel_id].
+				       sram_channels);
+	       buf->vb.state = VIDEOBUF_ACTIVE;
+	       buf->count = q->count++;
+	       mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+	       dprintk(2,
+		       "[%p/%d] buffer_queue - first active, buf cnt = %d, \
+		       q->count = %d\n",
+		       buf, buf->vb.i, buf->count, q->count);
+       } else {
+	       prev =
+		   list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
+	       if (prev->vb.width == buf->vb.width
+		   && prev->vb.height == buf->vb.height
+		   && prev->fmt == buf->fmt) {
+		       list_add_tail(&buf->vb.queue, &q->active);
+		       buf->vb.state = VIDEOBUF_ACTIVE;
+		       buf->count = q->count++;
+		       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+
+		       /* 64 bit bits 63-32 */
+		       prev->risc.jmp[2] = cpu_to_le32(0);
+		       dprintk(2,
+			       "[%p/%d] buffer_queue - append to active, \
+			       buf->count=%d\n",
+			       buf, buf->vb.i, buf->count);
+
+	       } else {
+		       list_add_tail(&buf->vb.queue, &q->queued);
+		       buf->vb.state = VIDEOBUF_QUEUED;
+		       dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
+			       buf->vb.i);
+	       }
+       }
+
+       if (list_empty(&q->active))
+	       dprintk(2, "active queue empty!\n");
+}
+
+static struct videobuf_queue_ops cx25821_video_qops = {
+       .buf_setup = cx25821_buffer_setup,
+       .buf_prepare = cx25821_buffer_prepare,
+       .buf_queue = buffer_queue,
+       .buf_release = cx25821_buffer_release,
+};
+
+static int video_open(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct cx25821_dev *h, *dev = video_drvdata(file);
+       struct cx25821_fh *fh;
+       struct list_head *list;
+       int minor = video_devdata(file)->minor;
+       enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       u32 pix_format;
+       int ch_id = 0;
+       int i;
+
+       dprintk(1, "open dev=%s type=%s\n",
+		       video_device_node_name(vdev),
+		       v4l2_type_names[type]);
+
+       /* allocate + initialize per filehandle data */
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (NULL == fh)
+	       return -ENOMEM;
+
+       lock_kernel();
+
+       list_for_each(list, &cx25821_devlist)
+       {
+	       h = list_entry(list, struct cx25821_dev, devlist);
+
+	       for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) {
+		       if (h->channels[i].video_dev &&
+			   h->channels[i].video_dev->minor == minor) {
+			       dev = h;
+			       ch_id = i;
+			       type  = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		       }
+	       }
+       }
+
+       if (NULL == dev) {
+	       unlock_kernel();
+	       return -ENODEV;
+       }
+
+       file->private_data = fh;
+       fh->dev = dev;
+       fh->type = type;
+       fh->width = 720;
+    fh->channel_id = ch_id;
+
+       if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
+	       fh->height = 576;
+       else
+	       fh->height = 480;
+
+       dev->channel_opened = fh->channel_id;
+       pix_format =
+	   (dev->channels[ch_id].pixel_formats ==
+	    PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
+       fh->fmt = format_by_fourcc(pix_format);
+
+       v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio);
+
+       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
+			      &dev->pci->dev, &dev->slock,
+			      V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			      V4L2_FIELD_INTERLACED,
+			      sizeof(struct cx25821_buffer), fh);
+
+       dprintk(1, "post videobuf_queue_init()\n");
+       unlock_kernel();
+
+       return 0;
+}
+
+static ssize_t video_read(struct file *file, char __user * data, size_t count,
+			 loff_t *ppos)
+{
+       struct cx25821_fh *fh = file->private_data;
+
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	       if (cx25821_res_locked(fh, RESOURCE_VIDEO0))
+		       return -EBUSY;
+
+	       return videobuf_read_one(&fh->vidq, data, count, ppos,
+					file->f_flags & O_NONBLOCK);
+
+       default:
+	       BUG();
+	       return 0;
+       }
+}
+
+static unsigned int video_poll(struct file *file,
+			      struct poll_table_struct *wait)
+{
+       struct cx25821_fh *fh = file->private_data;
+       struct cx25821_buffer *buf;
+
+       if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
+	       /* streaming capture */
+	       if (list_empty(&fh->vidq.stream))
+		       return POLLERR;
+	       buf = list_entry(fh->vidq.stream.next,
+				struct cx25821_buffer, vb.stream);
+       } else {
+	       /* read() capture */
+	       buf = (struct cx25821_buffer *)fh->vidq.read_buf;
+	       if (NULL == buf)
+		       return POLLERR;
+       }
+
+       poll_wait(file, &buf->vb.done, wait);
+       if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
+	       if (buf->vb.state == VIDEOBUF_DONE) {
+		       struct cx25821_dev *dev = fh->dev;
+
+		       if (dev && dev->channels[fh->channel_id]
+					       .use_cif_resolution) {
+			       u8 cam_id = *((char *)buf->vb.baddr + 3);
+			       memcpy((char *)buf->vb.baddr,
+				      (char *)buf->vb.baddr + (fh->width * 2),
+				      (fh->width * 2));
+			       *((char *)buf->vb.baddr + 3) = cam_id;
+		       }
+	       }
+
+	       return POLLIN | POLLRDNORM;
+       }
+
+       return 0;
+}
+
+static int video_release(struct file *file)
+{
+       struct cx25821_fh *fh = file->private_data;
+       struct cx25821_dev *dev = fh->dev;
+
+       /* stop the risc engine and fifo */
+       cx_write(channel0->dma_ctl, 0); /* FIFO and RISC disable */
+
+       /* stop video capture */
+       if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
+	       videobuf_queue_cancel(&fh->vidq);
+	       cx25821_res_free(dev, fh, RESOURCE_VIDEO0);
+       }
+
+       if (fh->vidq.read_buf) {
+	       cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
+	       kfree(fh->vidq.read_buf);
+       }
+
+       videobuf_mmap_free(&fh->vidq);
+
+       v4l2_prio_close(&dev->channels[fh->channel_id].prio, fh->prio);
+       file->private_data = NULL;
+       kfree(fh);
+
+       return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct cx25821_fh *fh = priv;
+       struct cx25821_dev *dev = fh->dev;
+
+       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
+	       return -EINVAL;
+
+       if (unlikely(i != fh->type))
+	       return -EINVAL;
+
+       if (unlikely(!cx25821_res_get(dev, fh,
+		       cx25821_get_resource(fh, RESOURCE_VIDEO0))))
+	       return -EBUSY;
+
+       return videobuf_streamon(get_queue(fh));
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct cx25821_fh *fh = priv;
+       struct cx25821_dev *dev = fh->dev;
+       int err, res;
+
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	       return -EINVAL;
+       if (i != fh->type)
+	       return -EINVAL;
+
+       res = cx25821_get_resource(fh, RESOURCE_VIDEO0);
+       err = videobuf_streamoff(get_queue(fh));
+       if (err < 0)
+	       return err;
+       cx25821_res_free(dev, fh, res);
+       return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+			       struct v4l2_format *f)
+{
+       struct cx25821_fh *fh = priv;
+       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+       int err;
+       int pix_format = PIXEL_FRMT_422;
+
+       if (fh) {
+	       err = v4l2_prio_check(&dev->channels[fh->channel_id]
+					       .prio, fh->prio);
+	       if (0 != err)
+		       return err;
+       }
+
+       dprintk(2, "%s()\n", __func__);
+       err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
+
+       if (0 != err)
+	       return err;
+
+       fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       fh->vidq.field = f->fmt.pix.field;
+
+       /* check if width and height is valid based on set standard */
+       if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm))
+	       fh->width = f->fmt.pix.width;
+
+       if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm))
+	       fh->height = f->fmt.pix.height;
+
+       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
+	       pix_format = PIXEL_FRMT_411;
+       else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
+	       pix_format = PIXEL_FRMT_422;
+       else
+	       return -EINVAL;
+
+       cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
+
+       /* check if cif resolution */
+       if (fh->width == 320 || fh->width == 352)
+	       dev->channels[fh->channel_id].use_cif_resolution = 1;
+       else
+	       dev->channels[fh->channel_id].use_cif_resolution = 0;
+
+       dev->channels[fh->channel_id].cif_width = fh->width;
+       medusa_set_resolution(dev, fh->width, SRAM_CH00);
+
+       dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
+	       fh->height, fh->vidq.field);
+       cx25821_call_all(dev, video, s_fmt, f);
+
+       return 0;
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       int ret_val = 0;
+       struct cx25821_fh *fh = priv;
+       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+
+       ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
+
+    p->sequence = dev->channels[fh->channel_id].vidq.count;
+
+       return ret_val;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+       struct cx25821_fh *fh = priv;
+       char name[32 + 2];
+
+       struct sram_channel *sram_ch = dev->channels[fh->channel_id]
+						       .sram_channels;
+       u32 tmp = 0;
+
+       snprintf(name, sizeof(name), "%s/2", dev->name);
+       printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
+	      dev->name);
+       cx25821_call_all(dev, core, log_status);
+       tmp = cx_read(sram_ch->dma_ctl);
+       printk(KERN_INFO "Video input 0 is %s\n",
+	      (tmp & 0x11) ? "streaming" : "stopped");
+       printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
+	      dev->name);
+       return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+			struct v4l2_control *ctl)
+{
+       struct cx25821_fh *fh = priv;
+       struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+       int err;
+
+       if (fh) {
+	       err = v4l2_prio_check(&dev->channels[fh->channel_id]
+					       .prio, fh->prio);
+	       if (0 != err)
+		       return err;
+       }
+
+       return cx25821_set_control(dev, ctl, fh->channel_id);
+}
+
 /* VIDEO IOCTLS                                                       */
 int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
 {
@@ -822,8 +1233,9 @@
 int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p)
 {
 	struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
+       struct cx25821_fh *fh = f;
 
-	*p = v4l2_prio_max(&dev->prio);
+       *p = v4l2_prio_max(&dev->channels[fh->channel_id].prio);
 
 	return 0;
 }
@@ -833,7 +1245,8 @@
 	struct cx25821_fh *fh = f;
 	struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
 
-	return v4l2_prio_change(&dev->prio, &fh->prio, prio);
+       return v4l2_prio_change(&dev->channels[fh->channel_id]
+				       .prio, &fh->prio, prio);
 }
 
 #ifdef TUNER_FLAG
@@ -846,7 +1259,8 @@
 	dprintk(1, "%s()\n", __func__);
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
+	       err = v4l2_prio_check(&dev->channels[fh->channel_id]
+					       .prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -916,7 +1330,8 @@
 	dprintk(1, "%s(%d)\n", __func__, i);
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
+	       err = v4l2_prio_check(&dev->channels[fh->channel_id]
+					       .prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -967,9 +1382,14 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
+	       dev = fh->dev;
+	       err = v4l2_prio_check(&dev->channels[fh->channel_id]
+					       .prio, fh->prio);
 		if (0 != err)
 			return err;
+       } else {
+	       printk(KERN_ERR "Invalid fh pointer!\n");
+	       return -EINVAL;
 	}
 
 	return cx25821_set_freq(dev, f);
@@ -1031,7 +1451,8 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
+	       err = v4l2_prio_check(&dev->channels[fh->channel_id]
+					       .prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
@@ -1046,7 +1467,7 @@
 }
 
 #endif
-// ******************************************************************************************
+/*****************************************************************************/
 static const struct v4l2_queryctrl no_ctl = {
 	.name = "42",
 	.flags = V4L2_CTRL_FLAG_DISABLED,
@@ -1129,6 +1550,7 @@
 int cx25821_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctl)
 {
 	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+       struct cx25821_fh *fh = priv;
 
 	const struct v4l2_queryctrl *ctrl;
 
@@ -1138,16 +1560,16 @@
 		return -EINVAL;
 	switch (ctl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		ctl->value = dev->ctl_bright;
+	       ctl->value = dev->channels[fh->channel_id].ctl_bright;
 		break;
 	case V4L2_CID_HUE:
-		ctl->value = dev->ctl_hue;
+	       ctl->value = dev->channels[fh->channel_id].ctl_hue;
 		break;
 	case V4L2_CID_CONTRAST:
-		ctl->value = dev->ctl_contrast;
+	       ctl->value = dev->channels[fh->channel_id].ctl_contrast;
 		break;
 	case V4L2_CID_SATURATION:
-		ctl->value = dev->ctl_saturation;
+	       ctl->value = dev->channels[fh->channel_id].ctl_saturation;
 		break;
 	}
 	return 0;
@@ -1181,19 +1603,19 @@
 
 	switch (ctl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		dev->ctl_bright = ctl->value;
+	       dev->channels[chan_num].ctl_bright = ctl->value;
 		medusa_set_brightness(dev, ctl->value, chan_num);
 		break;
 	case V4L2_CID_HUE:
-		dev->ctl_hue = ctl->value;
+	       dev->channels[chan_num].ctl_hue = ctl->value;
 		medusa_set_hue(dev, ctl->value, chan_num);
 		break;
 	case V4L2_CID_CONTRAST:
-		dev->ctl_contrast = ctl->value;
+	       dev->channels[chan_num].ctl_contrast = ctl->value;
 		medusa_set_contrast(dev, ctl->value, chan_num);
 		break;
 	case V4L2_CID_SATURATION:
-		dev->ctl_saturation = ctl->value;
+	       dev->channels[chan_num].ctl_saturation = ctl->value;
 		medusa_set_saturation(dev, ctl->value, chan_num);
 		break;
 	}
@@ -1203,7 +1625,7 @@
 	return err;
 }
 
-static void init_controls(struct cx25821_dev *dev, int chan_num)
+static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num)
 {
 	struct v4l2_control ctrl;
 	int i;
@@ -1239,23 +1661,24 @@
 	int err;
 
 	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
+	       err = v4l2_prio_check(&dev->channels[fh->channel_id].
+					       prio, fh->prio);
 		if (0 != err)
 			return err;
 	}
-	// cx25821_vidioc_s_crop not supported
+       /* cx25821_vidioc_s_crop not supported */
 	return -EINVAL;
 }
 
 int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
 {
-	// cx25821_vidioc_g_crop not supported
+       /* cx25821_vidioc_g_crop not supported */
 	return -EINVAL;
 }
 
 int cx25821_vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm)
 {
-	// medusa does not support video standard sensing of current input
+       /* medusa does not support video standard sensing of current input */
 	*norm = CX25821_NORMS;
 
 	return 0;
@@ -1297,3 +1720,325 @@
 
 	return 0;
 }
+
+static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
+				 unsigned long arg)
+{
+       struct cx25821_fh *fh = file->private_data;
+       struct cx25821_dev *dev = fh->dev;
+       int command = 0;
+       struct upstream_user_struct *data_from_user;
+
+       data_from_user = (struct upstream_user_struct *)arg;
+
+       if (!data_from_user) {
+	       printk
+		   ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
+		    __func__);
+	       return 0;
+       }
+
+       command = data_from_user->command;
+
+       if (command != UPSTREAM_START_VIDEO &&
+	       command != UPSTREAM_STOP_VIDEO)
+	       return 0;
+
+       dev->input_filename = data_from_user->input_filename;
+       dev->input_audiofilename = data_from_user->input_filename;
+       dev->vid_stdname = data_from_user->vid_stdname;
+       dev->pixel_format = data_from_user->pixel_format;
+       dev->channel_select = data_from_user->channel_select;
+       dev->command = data_from_user->command;
+
+       switch (command) {
+       case UPSTREAM_START_VIDEO:
+	       cx25821_start_upstream_video_ch1(dev, data_from_user);
+	       break;
+
+       case UPSTREAM_STOP_VIDEO:
+	       cx25821_stop_upstream_video_ch1(dev);
+	       break;
+       }
+
+       return 0;
+}
+
+static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
+				  unsigned long arg)
+{
+       struct cx25821_fh *fh = file->private_data;
+       struct cx25821_dev *dev = fh->dev;
+       int command = 0;
+       struct upstream_user_struct *data_from_user;
+
+       data_from_user = (struct upstream_user_struct *)arg;
+
+       if (!data_from_user) {
+	       printk
+		   ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
+		    __func__);
+	       return 0;
+       }
+
+       command = data_from_user->command;
+
+       if (command != UPSTREAM_START_VIDEO &&
+	       command != UPSTREAM_STOP_VIDEO)
+	       return 0;
+
+       dev->input_filename_ch2 = data_from_user->input_filename;
+       dev->input_audiofilename = data_from_user->input_filename;
+       dev->vid_stdname_ch2 = data_from_user->vid_stdname;
+       dev->pixel_format_ch2 = data_from_user->pixel_format;
+       dev->channel_select_ch2 = data_from_user->channel_select;
+       dev->command_ch2 = data_from_user->command;
+
+       switch (command) {
+       case UPSTREAM_START_VIDEO:
+	       cx25821_start_upstream_video_ch2(dev, data_from_user);
+	       break;
+
+       case UPSTREAM_STOP_VIDEO:
+	       cx25821_stop_upstream_video_ch2(dev);
+	       break;
+       }
+
+       return 0;
+}
+
+static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
+				  unsigned long arg)
+{
+       struct cx25821_fh *fh = file->private_data;
+       struct cx25821_dev *dev = fh->dev;
+       int command = 0;
+       struct upstream_user_struct *data_from_user;
+
+       data_from_user = (struct upstream_user_struct *)arg;
+
+       if (!data_from_user) {
+	       printk
+		   ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
+		    __func__);
+	       return 0;
+       }
+
+       command = data_from_user->command;
+
+       if (command != UPSTREAM_START_AUDIO &&
+	       command != UPSTREAM_STOP_AUDIO)
+	       return 0;
+
+       dev->input_filename = data_from_user->input_filename;
+       dev->input_audiofilename = data_from_user->input_filename;
+       dev->vid_stdname = data_from_user->vid_stdname;
+       dev->pixel_format = data_from_user->pixel_format;
+       dev->channel_select = data_from_user->channel_select;
+       dev->command = data_from_user->command;
+
+       switch (command) {
+       case UPSTREAM_START_AUDIO:
+	       cx25821_start_upstream_audio(dev, data_from_user);
+	       break;
+
+       case UPSTREAM_STOP_AUDIO:
+	       cx25821_stop_upstream_audio(dev);
+	       break;
+       }
+
+       return 0;
+}
+
+static long video_ioctl_set(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+       struct cx25821_fh *fh = file->private_data;
+       struct cx25821_dev *dev = fh->dev;
+       struct downstream_user_struct *data_from_user;
+       int command;
+       int width = 720;
+       int selected_channel = 0, pix_format = 0, i = 0;
+       int cif_enable = 0, cif_width = 0;
+       u32 value = 0;
+
+       data_from_user = (struct downstream_user_struct *)arg;
+
+       if (!data_from_user) {
+	       printk(
+	       "cx25821 in %s(): User data is INVALID. Returning.\n",
+	       __func__);
+	       return 0;
+       }
+
+       command = data_from_user->command;
+
+       if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
+	   && command != ENABLE_CIF_RESOLUTION && command != REG_READ
+	   && command != REG_WRITE && command != MEDUSA_READ
+	   && command != MEDUSA_WRITE) {
+	       return 0;
+       }
+
+       switch (command) {
+       case SET_VIDEO_STD:
+	       dev->tvnorm =
+		   !strcmp(data_from_user->vid_stdname,
+			   "PAL") ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
+	       medusa_set_videostandard(dev);
+	       break;
+
+       case SET_PIXEL_FORMAT:
+	       selected_channel = data_from_user->decoder_select;
+	       pix_format = data_from_user->pixel_format;
+
+	       if (!(selected_channel <= 7 && selected_channel >= 0)) {
+		       selected_channel -= 4;
+		       selected_channel = selected_channel % 8;
+	       }
+
+	       if (selected_channel >= 0)
+		       cx25821_set_pixel_format(dev, selected_channel,
+						pix_format);
+
+	       break;
+
+       case ENABLE_CIF_RESOLUTION:
+	       selected_channel = data_from_user->decoder_select;
+	       cif_enable = data_from_user->cif_resolution_enable;
+	       cif_width = data_from_user->cif_width;
+
+	       if (cif_enable) {
+		       if (dev->tvnorm & V4L2_STD_PAL_BG
+			   || dev->tvnorm & V4L2_STD_PAL_DK)
+			       width = 352;
+		       else
+			       width = (cif_width == 320
+					|| cif_width == 352) ? cif_width : 320;
+	       }
+
+	       if (!(selected_channel <= 7 && selected_channel >= 0)) {
+		       selected_channel -= 4;
+		       selected_channel = selected_channel % 8;
+	       }
+
+	       if (selected_channel <= 7 && selected_channel >= 0) {
+		       dev->channels[selected_channel].
+			       use_cif_resolution = cif_enable;
+		       dev->channels[selected_channel].cif_width = width;
+	       } else {
+		       for (i = 0; i < VID_CHANNEL_NUM; i++) {
+			       dev->channels[i].use_cif_resolution =
+				       cif_enable;
+			       dev->channels[i].cif_width = width;
+		       }
+	       }
+
+	       medusa_set_resolution(dev, width, selected_channel);
+	       break;
+       case REG_READ:
+	       data_from_user->reg_data = cx_read(data_from_user->reg_address);
+	       break;
+       case REG_WRITE:
+	       cx_write(data_from_user->reg_address, data_from_user->reg_data);
+	       break;
+       case MEDUSA_READ:
+	       value =
+		   cx25821_i2c_read(&dev->i2c_bus[0],
+				    (u16) data_from_user->reg_address,
+				    &data_from_user->reg_data);
+	       break;
+       case MEDUSA_WRITE:
+	       cx25821_i2c_write(&dev->i2c_bus[0],
+				 (u16) data_from_user->reg_address,
+				 data_from_user->reg_data);
+	       break;
+       }
+
+       return 0;
+}
+
+static long cx25821_video_ioctl(struct file *file,
+			       unsigned int cmd, unsigned long arg)
+{
+       int  ret = 0;
+
+       struct cx25821_fh  *fh  = file->private_data;
+
+       /* check to see if it's the video upstream */
+       if (fh->channel_id == SRAM_CH09) {
+	       ret = video_ioctl_upstream9(file, cmd, arg);
+	       return ret;
+       } else if (fh->channel_id == SRAM_CH10) {
+	       ret = video_ioctl_upstream10(file, cmd, arg);
+	       return ret;
+       } else if (fh->channel_id == SRAM_CH11) {
+	       ret = video_ioctl_upstream11(file, cmd, arg);
+	       ret = video_ioctl_set(file, cmd, arg);
+	       return ret;
+       }
+
+    return video_ioctl2(file, cmd, arg);
+}
+
+/* exported stuff */
+static const struct v4l2_file_operations video_fops = {
+       .owner = THIS_MODULE,
+       .open = video_open,
+       .release = video_release,
+       .read = video_read,
+       .poll = video_poll,
+       .mmap = cx25821_video_mmap,
+       .ioctl = cx25821_video_ioctl,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+       .vidioc_querycap = cx25821_vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+       .vidioc_reqbufs = cx25821_vidioc_reqbufs,
+       .vidioc_querybuf = cx25821_vidioc_querybuf,
+       .vidioc_qbuf = cx25821_vidioc_qbuf,
+       .vidioc_dqbuf = vidioc_dqbuf,
+#ifdef TUNER_FLAG
+       .vidioc_s_std = cx25821_vidioc_s_std,
+       .vidioc_querystd = cx25821_vidioc_querystd,
+#endif
+       .vidioc_cropcap = cx25821_vidioc_cropcap,
+       .vidioc_s_crop = cx25821_vidioc_s_crop,
+       .vidioc_g_crop = cx25821_vidioc_g_crop,
+       .vidioc_enum_input = cx25821_vidioc_enum_input,
+       .vidioc_g_input = cx25821_vidioc_g_input,
+       .vidioc_s_input = cx25821_vidioc_s_input,
+       .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
+       .vidioc_s_ctrl = vidioc_s_ctrl,
+       .vidioc_queryctrl = cx25821_vidioc_queryctrl,
+       .vidioc_streamon = vidioc_streamon,
+       .vidioc_streamoff = vidioc_streamoff,
+       .vidioc_log_status = vidioc_log_status,
+       .vidioc_g_priority = cx25821_vidioc_g_priority,
+       .vidioc_s_priority = cx25821_vidioc_s_priority,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+       .vidiocgmbuf = cx25821_vidiocgmbuf,
+#endif
+#ifdef TUNER_FLAG
+       .vidioc_g_tuner = cx25821_vidioc_g_tuner,
+       .vidioc_s_tuner = cx25821_vidioc_s_tuner,
+       .vidioc_g_frequency = cx25821_vidioc_g_frequency,
+       .vidioc_s_frequency = cx25821_vidioc_s_frequency,
+#endif
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register = cx25821_vidioc_g_register,
+       .vidioc_s_register = cx25821_vidioc_s_register,
+#endif
+};
+
+struct video_device cx25821_videoioctl_template = {
+	       .name = "cx25821-videoioctl",
+	       .fops = &video_fops,
+	       .ioctl_ops = &video_ioctl_ops,
+	       .tvnorms = CX25821_NORMS,
+	       .current_norm = V4L2_STD_NTSC_M,
+};
diff --git a/drivers/staging/cx25821/cx25821-video.h b/drivers/staging/cx25821/cx25821-video.h
index 0bddc02..cc6034b 100644
--- a/drivers/staging/cx25821/cx25821-video.h
+++ b/drivers/staging/cx25821/cx25821-video.h
@@ -54,7 +54,7 @@
 	printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
     } while (0)
 
-//For IOCTL to identify running upstream
+/* For IOCTL to identify running upstream */
 #define UPSTREAM_START_VIDEO        700
 #define UPSTREAM_STOP_VIDEO         701
 #define UPSTREAM_START_AUDIO        702
@@ -80,19 +80,8 @@
 extern struct sram_channel *channel9;
 extern struct sram_channel *channel10;
 extern struct sram_channel *channel11;
-extern struct video_device cx25821_video_template0;
-extern struct video_device cx25821_video_template1;
-extern struct video_device cx25821_video_template2;
-extern struct video_device cx25821_video_template3;
-extern struct video_device cx25821_video_template4;
-extern struct video_device cx25821_video_template5;
-extern struct video_device cx25821_video_template6;
-extern struct video_device cx25821_video_template7;
-extern struct video_device cx25821_video_template9;
-extern struct video_device cx25821_video_template10;
-extern struct video_device cx25821_video_template11;
 extern struct video_device cx25821_videoioctl_template;
-//extern const u32 *ctrl_classes[];
+/* extern const u32 *ctrl_classes[]; */
 
 extern unsigned int vid_limit;
 
@@ -113,7 +102,7 @@
 extern int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh,
 		   unsigned int bit);
 extern int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit);
-extern int cx25821_res_locked(struct cx25821_dev *dev, unsigned int bit);
+extern int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit);
 extern void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh,
 		     unsigned int bits);
 extern int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input);
@@ -126,8 +115,7 @@
 			     unsigned int height, enum v4l2_field field);
 extern int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status);
 extern void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num);
-extern int cx25821_video_register(struct cx25821_dev *dev, int chan_num,
-				  struct video_device *video_template);
+extern int cx25821_video_register(struct cx25821_dev *dev);
 extern int cx25821_get_format_size(void);
 
 extern int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
diff --git a/drivers/staging/cx25821/cx25821-video0.c b/drivers/staging/cx25821/cx25821-video0.c
deleted file mode 100644
index 0be2cc1..0000000
--- a/drivers/staging/cx25821/cx25821-video0.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-	struct cx25821_buffer *buf =
-	    container_of(vb, struct cx25821_buffer, vb);
-	struct cx25821_buffer *prev;
-	struct cx25821_fh *fh = vq->priv_data;
-	struct cx25821_dev *dev = fh->dev;
-	struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH00];
-
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
-
-	dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-	if (!list_empty(&q->queued)) {
-		list_add_tail(&buf->vb.queue, &q->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-			buf->vb.i);
-
-	} else if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx25821_start_video_dma(dev, q, buf,
-					&dev->sram_channels[SRAM_CH00]);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count = q->count++;
-		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-		dprintk(2,
-			"[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-			buf, buf->vb.i, buf->count, q->count);
-	} else {
-		prev =
-		    list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-		if (prev->vb.width == buf->vb.width
-		    && prev->vb.height == buf->vb.height
-		    && prev->fmt == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-			/* 64 bit bits 63-32 */
-			prev->risc.jmp[2] = cpu_to_le32(0);
-			dprintk(2,
-				"[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-				buf, buf->vb.i, buf->count);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &q->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-				buf->vb.i);
-		}
-	}
-
-	if (list_empty(&q->active)) {
-		dprintk(2, "active queue empty!\n");
-	}
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = cx25821_buffer_setup,
-	.buf_prepare = cx25821_buffer_prepare,
-	.buf_queue = buffer_queue,
-	.buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct cx25821_dev *dev = video_drvdata(file);
-	struct cx25821_fh *fh;
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	u32 pix_format;
-
-	printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-		v4l2_type_names[type]);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-
-	lock_kernel();
-
-	file->private_data = fh;
-	fh->dev = dev;
-	fh->type = type;
-	fh->width = 720;
-
-	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-		fh->height = 576;
-	else
-		fh->height = 480;
-
-	dev->channel_opened = SRAM_CH00;
-	pix_format =
-	    (dev->pixel_formats[dev->channel_opened] ==
-	     PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-	fh->fmt = format_by_fourcc(pix_format);
-
-	v4l2_prio_open(&dev->prio, &fh->prio);
-
-	videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-			       &dev->pci->dev, &dev->slock,
-			       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			       V4L2_FIELD_INTERLACED,
-			       sizeof(struct cx25821_buffer), fh);
-
-	dprintk(1, "post videobuf_queue_init()\n");
-	unlock_kernel();
-
-	return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-			  loff_t * ppos)
-{
-	struct cx25821_fh *fh = file->private_data;
-
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO0))
-			return -EBUSY;
-
-		return videobuf_read_one(&fh->vidq, data, count, ppos,
-					 file->f_flags & O_NONBLOCK);
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static unsigned int video_poll(struct file *file,
-			       struct poll_table_struct *wait)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_buffer *buf;
-
-	if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
-		/* streaming capture */
-		if (list_empty(&fh->vidq.stream))
-			return POLLERR;
-		buf = list_entry(fh->vidq.stream.next,
-				 struct cx25821_buffer, vb.stream);
-	} else {
-		/* read() capture */
-		buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-		if (NULL == buf)
-			return POLLERR;
-	}
-
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-		if (buf->vb.state == VIDEOBUF_DONE) {
-			struct cx25821_dev *dev = fh->dev;
-
-			if (dev && dev->use_cif_resolution[SRAM_CH00]) {
-				u8 cam_id = *((char *)buf->vb.baddr + 3);
-				memcpy((char *)buf->vb.baddr,
-				       (char *)buf->vb.baddr + (fh->width * 2),
-				       (fh->width * 2));
-				*((char *)buf->vb.baddr + 3) = cam_id;
-			}
-		}
-
-		return POLLIN | POLLRDNORM;
-	}
-
-	return 0;
-}
-
-static int video_release(struct file *file)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-
-	//stop the risc engine and fifo
-	cx_write(channel0->dma_ctl, 0);	/* FIFO and RISC disable */
-
-	/* stop video capture */
-	if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
-		videobuf_queue_cancel(&fh->vidq);
-		cx25821_res_free(dev, fh, RESOURCE_VIDEO0);
-	}
-
-	if (fh->vidq.read_buf) {
-		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-		kfree(fh->vidq.read_buf);
-	}
-
-	videobuf_mmap_free(&fh->vidq);
-
-	v4l2_prio_close(&dev->prio, fh->prio);
-	file->private_data = NULL;
-	kfree(fh);
-
-	return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-
-	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(i != fh->type)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO0)))) {
-		return -EBUSY;
-	}
-
-	return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-	int err, res;
-
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	res = cx25821_get_resource(fh, RESOURCE_VIDEO0);
-	err = videobuf_streamoff(get_queue(fh));
-	if (err < 0)
-		return err;
-	cx25821_res_free(dev, fh, res);
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-	int pix_format = PIXEL_FRMT_422;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	dprintk(2, "%s()\n", __func__);
-	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-	if (0 != err)
-		return err;
-
-	fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-	fh->vidq.field = f->fmt.pix.field;
-
-	// check if width and height is valid based on set standard
-	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-		fh->width = f->fmt.pix.width;
-	}
-
-	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-		fh->height = f->fmt.pix.height;
-	}
-
-	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-		pix_format = PIXEL_FRMT_411;
-	else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-		pix_format = PIXEL_FRMT_422;
-	else
-		return -EINVAL;
-
-	cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
-
-	// check if cif resolution
-	if (fh->width == 320 || fh->width == 352) {
-		dev->use_cif_resolution[SRAM_CH00] = 1;
-	} else {
-		dev->use_cif_resolution[SRAM_CH00] = 0;
-	}
-	dev->cif_width[SRAM_CH00] = fh->width;
-	medusa_set_resolution(dev, fh->width, SRAM_CH00);
-
-	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-		fh->height, fh->vidq.field);
-	cx25821_call_all(dev, video, s_fmt, f);
-
-	return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	int ret_val = 0;
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-	ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-	p->sequence = dev->vidq[SRAM_CH00].count;
-
-	return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	char name[32 + 2];
-
-	struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH00];
-	u32 tmp = 0;
-
-	snprintf(name, sizeof(name), "%s/2", dev->name);
-	printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-	       dev->name);
-	cx25821_call_all(dev, core, log_status);
-	tmp = cx_read(sram_ch->dma_ctl);
-	printk(KERN_INFO "Video input 0 is %s\n",
-	       (tmp & 0x11) ? "streaming" : "stopped");
-	printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-	       dev->name);
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctl)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	return cx25821_set_control(dev, ctl, SRAM_CH00);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-	.owner = THIS_MODULE,
-	.open = video_open,
-	.release = video_release,
-	.read = video_read,
-	.poll = video_poll,
-	.mmap = cx25821_video_mmap,
-	.ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = cx25821_vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
-	.vidioc_querybuf = cx25821_vidioc_querybuf,
-	.vidioc_qbuf = cx25821_vidioc_qbuf,
-	.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-	.vidioc_s_std = cx25821_vidioc_s_std,
-	.vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-	.vidioc_cropcap = cx25821_vidioc_cropcap,
-	.vidioc_s_crop = cx25821_vidioc_s_crop,
-	.vidioc_g_crop = cx25821_vidioc_g_crop,
-	.vidioc_enum_input = cx25821_vidioc_enum_input,
-	.vidioc_g_input = cx25821_vidioc_g_input,
-	.vidioc_s_input = cx25821_vidioc_s_input,
-	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
-	.vidioc_streamon = vidioc_streamon,
-	.vidioc_streamoff = vidioc_streamoff,
-	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = cx25821_vidioc_g_priority,
-	.vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
-	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
-	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
-	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = cx25821_vidioc_g_register,
-	.vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template0 = {
-	.name = "cx25821-video",
-	.fops = &video_fops,
-	.ioctl_ops = &video_ioctl_ops,
-	.tvnorms = CX25821_NORMS,
-	.current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video1.c b/drivers/staging/cx25821/cx25821-video1.c
deleted file mode 100644
index b0bae627..0000000
--- a/drivers/staging/cx25821/cx25821-video1.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-	struct cx25821_buffer *buf =
-	    container_of(vb, struct cx25821_buffer, vb);
-	struct cx25821_buffer *prev;
-	struct cx25821_fh *fh = vq->priv_data;
-	struct cx25821_dev *dev = fh->dev;
-	struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH01];
-
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
-
-	dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-	if (!list_empty(&q->queued)) {
-		list_add_tail(&buf->vb.queue, &q->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-			buf->vb.i);
-
-	} else if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx25821_start_video_dma(dev, q, buf,
-					&dev->sram_channels[SRAM_CH01]);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count = q->count++;
-		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-		dprintk(2,
-			"[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-			buf, buf->vb.i, buf->count, q->count);
-	} else {
-		prev =
-		    list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-		if (prev->vb.width == buf->vb.width
-		    && prev->vb.height == buf->vb.height
-		    && prev->fmt == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-			/* 64 bit bits 63-32 */
-			prev->risc.jmp[2] = cpu_to_le32(0);
-			dprintk(2,
-				"[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-				buf, buf->vb.i, buf->count);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &q->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-				buf->vb.i);
-		}
-	}
-
-	if (list_empty(&q->active)) {
-		dprintk(2, "active queue empty!\n");
-	}
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = cx25821_buffer_setup,
-	.buf_prepare = cx25821_buffer_prepare,
-	.buf_queue = buffer_queue,
-	.buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct cx25821_dev *dev = video_drvdata(file);
-	struct cx25821_fh *fh;
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	u32 pix_format;
-
-	printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-		v4l2_type_names[type]);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-
-	lock_kernel();
-
-	file->private_data = fh;
-	fh->dev = dev;
-	fh->type = type;
-	fh->width = 720;
-
-	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-		fh->height = 576;
-	else
-		fh->height = 480;
-
-	dev->channel_opened = SRAM_CH01;
-	pix_format =
-	    (dev->pixel_formats[dev->channel_opened] ==
-	     PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-	fh->fmt = format_by_fourcc(pix_format);
-
-	v4l2_prio_open(&dev->prio, &fh->prio);
-
-	videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-			       &dev->pci->dev, &dev->slock,
-			       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			       V4L2_FIELD_INTERLACED,
-			       sizeof(struct cx25821_buffer), fh);
-
-	dprintk(1, "post videobuf_queue_init()\n");
-	unlock_kernel();
-
-	return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-			  loff_t * ppos)
-{
-	struct cx25821_fh *fh = file->private_data;
-
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO1))
-			return -EBUSY;
-
-		return videobuf_read_one(&fh->vidq, data, count, ppos,
-					 file->f_flags & O_NONBLOCK);
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static unsigned int video_poll(struct file *file,
-			       struct poll_table_struct *wait)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_buffer *buf;
-
-	if (cx25821_res_check(fh, RESOURCE_VIDEO1)) {
-		/* streaming capture */
-		if (list_empty(&fh->vidq.stream))
-			return POLLERR;
-		buf = list_entry(fh->vidq.stream.next,
-				 struct cx25821_buffer, vb.stream);
-	} else {
-		/* read() capture */
-		buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-		if (NULL == buf)
-			return POLLERR;
-	}
-
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-		if (buf->vb.state == VIDEOBUF_DONE) {
-			struct cx25821_dev *dev = fh->dev;
-
-			if (dev && dev->use_cif_resolution[SRAM_CH01]) {
-				u8 cam_id = *((char *)buf->vb.baddr + 3);
-				memcpy((char *)buf->vb.baddr,
-				       (char *)buf->vb.baddr + (fh->width * 2),
-				       (fh->width * 2));
-				*((char *)buf->vb.baddr + 3) = cam_id;
-			}
-		}
-
-		return POLLIN | POLLRDNORM;
-	}
-
-	return 0;
-}
-
-static int video_release(struct file *file)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-
-	//stop the risc engine and fifo
-	cx_write(channel1->dma_ctl, 0);	/* FIFO and RISC disable */
-
-	/* stop video capture */
-	if (cx25821_res_check(fh, RESOURCE_VIDEO1)) {
-		videobuf_queue_cancel(&fh->vidq);
-		cx25821_res_free(dev, fh, RESOURCE_VIDEO1);
-	}
-
-	if (fh->vidq.read_buf) {
-		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-		kfree(fh->vidq.read_buf);
-	}
-
-	videobuf_mmap_free(&fh->vidq);
-
-	v4l2_prio_close(&dev->prio, fh->prio);
-	file->private_data = NULL;
-	kfree(fh);
-
-	return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-
-	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(i != fh->type)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO1)))) {
-		return -EBUSY;
-	}
-
-	return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-	int err, res;
-
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	res = cx25821_get_resource(fh, RESOURCE_VIDEO1);
-	err = videobuf_streamoff(get_queue(fh));
-	if (err < 0)
-		return err;
-	cx25821_res_free(dev, fh, res);
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-	int pix_format = 0;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	dprintk(2, "%s()\n", __func__);
-	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-	if (0 != err)
-		return err;
-
-	fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-	fh->vidq.field = f->fmt.pix.field;
-
-	// check if width and height is valid based on set standard
-	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-		fh->width = f->fmt.pix.width;
-	}
-
-	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-		fh->height = f->fmt.pix.height;
-	}
-
-	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-		pix_format = PIXEL_FRMT_411;
-	else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-		pix_format = PIXEL_FRMT_422;
-	else
-		return -EINVAL;
-
-	cx25821_set_pixel_format(dev, SRAM_CH01, pix_format);
-
-	// check if cif resolution
-	if (fh->width == 320 || fh->width == 352) {
-		dev->use_cif_resolution[SRAM_CH01] = 1;
-	} else {
-		dev->use_cif_resolution[SRAM_CH01] = 0;
-	}
-	dev->cif_width[SRAM_CH01] = fh->width;
-	medusa_set_resolution(dev, fh->width, SRAM_CH01);
-
-	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-		fh->height, fh->vidq.field);
-	cx25821_call_all(dev, video, s_fmt, f);
-
-	return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	int ret_val = 0;
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-	ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-	p->sequence = dev->vidq[SRAM_CH01].count;
-
-	return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	char name[32 + 2];
-
-	struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH01];
-	u32 tmp = 0;
-
-	snprintf(name, sizeof(name), "%s/2", dev->name);
-	printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-	       dev->name);
-	cx25821_call_all(dev, core, log_status);
-	tmp = cx_read(sram_ch->dma_ctl);
-	printk(KERN_INFO "Video input 1 is %s\n",
-	       (tmp & 0x11) ? "streaming" : "stopped");
-	printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-	       dev->name);
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctl)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	return cx25821_set_control(dev, ctl, SRAM_CH01);
-}
-
-//exported stuff
-static const struct v4l2_file_operations video_fops = {
-	.owner = THIS_MODULE,
-	.open = video_open,
-	.release = video_release,
-	.read = video_read,
-	.poll = video_poll,
-	.mmap = cx25821_video_mmap,
-	.ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = cx25821_vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
-	.vidioc_querybuf = cx25821_vidioc_querybuf,
-	.vidioc_qbuf = cx25821_vidioc_qbuf,
-	.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-	.vidioc_s_std = cx25821_vidioc_s_std,
-	.vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-	.vidioc_cropcap = cx25821_vidioc_cropcap,
-	.vidioc_s_crop = cx25821_vidioc_s_crop,
-	.vidioc_g_crop = cx25821_vidioc_g_crop,
-	.vidioc_enum_input = cx25821_vidioc_enum_input,
-	.vidioc_g_input = cx25821_vidioc_g_input,
-	.vidioc_s_input = cx25821_vidioc_s_input,
-	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
-	.vidioc_streamon = vidioc_streamon,
-	.vidioc_streamoff = vidioc_streamoff,
-	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = cx25821_vidioc_g_priority,
-	.vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
-	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
-	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
-	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = cx25821_vidioc_g_register,
-	.vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template1 = {
-	.name = "cx25821-video",
-	.fops = &video_fops,
-	.ioctl_ops = &video_ioctl_ops,
-	.tvnorms = CX25821_NORMS,
-	.current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video2.c b/drivers/staging/cx25821/cx25821-video2.c
deleted file mode 100644
index 400cdb8..0000000
--- a/drivers/staging/cx25821/cx25821-video2.c
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-	struct cx25821_buffer *buf =
-	    container_of(vb, struct cx25821_buffer, vb);
-	struct cx25821_buffer *prev;
-	struct cx25821_fh *fh = vq->priv_data;
-	struct cx25821_dev *dev = fh->dev;
-	struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH02];
-
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
-
-	dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-	if (!list_empty(&q->queued)) {
-		list_add_tail(&buf->vb.queue, &q->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-			buf->vb.i);
-
-	} else if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx25821_start_video_dma(dev, q, buf,
-					&dev->sram_channels[SRAM_CH02]);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count = q->count++;
-		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-		dprintk(2,
-			"[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-			buf, buf->vb.i, buf->count, q->count);
-	} else {
-		prev =
-		    list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-		if (prev->vb.width == buf->vb.width
-		    && prev->vb.height == buf->vb.height
-		    && prev->fmt == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-			/* 64 bit bits 63-32 */
-			prev->risc.jmp[2] = cpu_to_le32(0);
-			dprintk(2,
-				"[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-				buf, buf->vb.i, buf->count);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &q->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-				buf->vb.i);
-		}
-	}
-
-	if (list_empty(&q->active)) {
-		dprintk(2, "active queue empty!\n");
-	}
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = cx25821_buffer_setup,
-	.buf_prepare = cx25821_buffer_prepare,
-	.buf_queue = buffer_queue,
-	.buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct cx25821_dev *dev = video_drvdata(file);
-	struct cx25821_fh *fh;
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	u32 pix_format;
-
-	printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-		v4l2_type_names[type]);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-
-	lock_kernel();
-
-	file->private_data = fh;
-	fh->dev = dev;
-	fh->type = type;
-	fh->width = 720;
-
-	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-		fh->height = 576;
-	else
-		fh->height = 480;
-
-	dev->channel_opened = SRAM_CH02;
-	pix_format =
-	    (dev->pixel_formats[dev->channel_opened] ==
-	     PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-	fh->fmt = format_by_fourcc(pix_format);
-
-	v4l2_prio_open(&dev->prio, &fh->prio);
-
-	videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-			       &dev->pci->dev, &dev->slock,
-			       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			       V4L2_FIELD_INTERLACED,
-			       sizeof(struct cx25821_buffer), fh);
-
-	dprintk(1, "post videobuf_queue_init()\n");
-	unlock_kernel();
-
-	return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-			  loff_t * ppos)
-{
-	struct cx25821_fh *fh = file->private_data;
-
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO2))
-			return -EBUSY;
-
-		return videobuf_read_one(&fh->vidq, data, count, ppos,
-					 file->f_flags & O_NONBLOCK);
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static unsigned int video_poll(struct file *file,
-			       struct poll_table_struct *wait)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_buffer *buf;
-
-	if (cx25821_res_check(fh, RESOURCE_VIDEO2)) {
-		/* streaming capture */
-		if (list_empty(&fh->vidq.stream))
-			return POLLERR;
-		buf = list_entry(fh->vidq.stream.next,
-				 struct cx25821_buffer, vb.stream);
-	} else {
-		/* read() capture */
-		buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-		if (NULL == buf)
-			return POLLERR;
-	}
-
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-		if (buf->vb.state == VIDEOBUF_DONE) {
-			struct cx25821_dev *dev = fh->dev;
-
-			if (dev && dev->use_cif_resolution[SRAM_CH02]) {
-				u8 cam_id = *((char *)buf->vb.baddr + 3);
-				memcpy((char *)buf->vb.baddr,
-				       (char *)buf->vb.baddr + (fh->width * 2),
-				       (fh->width * 2));
-				*((char *)buf->vb.baddr + 3) = cam_id;
-			}
-		}
-
-		return POLLIN | POLLRDNORM;
-	}
-
-	return 0;
-}
-
-static int video_release(struct file *file)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-
-	//stop the risc engine and fifo
-	cx_write(channel2->dma_ctl, 0);	/* FIFO and RISC disable */
-
-	/* stop video capture */
-	if (cx25821_res_check(fh, RESOURCE_VIDEO2)) {
-		videobuf_queue_cancel(&fh->vidq);
-		cx25821_res_free(dev, fh, RESOURCE_VIDEO2);
-	}
-
-	if (fh->vidq.read_buf) {
-		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-		kfree(fh->vidq.read_buf);
-	}
-
-	videobuf_mmap_free(&fh->vidq);
-
-	v4l2_prio_close(&dev->prio, fh->prio);
-	file->private_data = NULL;
-	kfree(fh);
-
-	return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-
-	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(i != fh->type)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO2)))) {
-		return -EBUSY;
-	}
-
-	return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-	int err, res;
-
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	res = cx25821_get_resource(fh, RESOURCE_VIDEO2);
-	err = videobuf_streamoff(get_queue(fh));
-	if (err < 0)
-		return err;
-	cx25821_res_free(dev, fh, res);
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-	int pix_format = 0;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	dprintk(2, "%s()\n", __func__);
-	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-	if (0 != err)
-		return err;
-
-	fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-	fh->vidq.field = f->fmt.pix.field;
-
-	// check if width and height is valid based on set standard
-	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-		fh->width = f->fmt.pix.width;
-	}
-
-	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-		fh->height = f->fmt.pix.height;
-	}
-
-	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-		pix_format = PIXEL_FRMT_411;
-	else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-		pix_format = PIXEL_FRMT_422;
-	else
-		return -EINVAL;
-
-	cx25821_set_pixel_format(dev, SRAM_CH02, pix_format);
-
-	// check if cif resolution
-	if (fh->width == 320 || fh->width == 352) {
-		dev->use_cif_resolution[SRAM_CH02] = 1;
-	} else {
-		dev->use_cif_resolution[SRAM_CH02] = 0;
-	}
-	dev->cif_width[SRAM_CH02] = fh->width;
-	medusa_set_resolution(dev, fh->width, SRAM_CH02);
-
-	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-		fh->height, fh->vidq.field);
-	cx25821_call_all(dev, video, s_fmt, f);
-
-	return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	int ret_val = 0;
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-	ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-	p->sequence = dev->vidq[SRAM_CH02].count;
-
-	return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	char name[32 + 2];
-
-	struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH02];
-	u32 tmp = 0;
-
-	snprintf(name, sizeof(name), "%s/2", dev->name);
-	printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-	       dev->name);
-
-	cx25821_call_all(dev, core, log_status);
-
-	tmp = cx_read(sram_ch->dma_ctl);
-	printk(KERN_INFO "Video input 2 is %s\n",
-	       (tmp & 0x11) ? "streaming" : "stopped");
-	printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-	       dev->name);
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctl)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	return cx25821_set_control(dev, ctl, SRAM_CH02);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-	.owner = THIS_MODULE,
-	.open = video_open,
-	.release = video_release,
-	.read = video_read,
-	.poll = video_poll,
-	.mmap = cx25821_video_mmap,
-	.ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = cx25821_vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
-	.vidioc_querybuf = cx25821_vidioc_querybuf,
-	.vidioc_qbuf = cx25821_vidioc_qbuf,
-	.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-	.vidioc_s_std = cx25821_vidioc_s_std,
-	.vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-	.vidioc_cropcap = cx25821_vidioc_cropcap,
-	.vidioc_s_crop = cx25821_vidioc_s_crop,
-	.vidioc_g_crop = cx25821_vidioc_g_crop,
-	.vidioc_enum_input = cx25821_vidioc_enum_input,
-	.vidioc_g_input = cx25821_vidioc_g_input,
-	.vidioc_s_input = cx25821_vidioc_s_input,
-	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
-	.vidioc_streamon = vidioc_streamon,
-	.vidioc_streamoff = vidioc_streamoff,
-	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = cx25821_vidioc_g_priority,
-	.vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
-	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
-	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
-	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = cx25821_vidioc_g_register,
-	.vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template2 = {
-	.name = "cx25821-video",
-	.fops = &video_fops,
-	.ioctl_ops = &video_ioctl_ops,
-	.tvnorms = CX25821_NORMS,
-	.current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video3.c b/drivers/staging/cx25821/cx25821-video3.c
deleted file mode 100644
index 3b216ed..0000000
--- a/drivers/staging/cx25821/cx25821-video3.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-	struct cx25821_buffer *buf =
-	    container_of(vb, struct cx25821_buffer, vb);
-	struct cx25821_buffer *prev;
-	struct cx25821_fh *fh = vq->priv_data;
-	struct cx25821_dev *dev = fh->dev;
-	struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH03];
-
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
-
-	dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-	if (!list_empty(&q->queued)) {
-		list_add_tail(&buf->vb.queue, &q->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-			buf->vb.i);
-
-	} else if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx25821_start_video_dma(dev, q, buf,
-					&dev->sram_channels[SRAM_CH03]);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count = q->count++;
-		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-		dprintk(2,
-			"[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-			buf, buf->vb.i, buf->count, q->count);
-	} else {
-		prev =
-		    list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-		if (prev->vb.width == buf->vb.width
-		    && prev->vb.height == buf->vb.height
-		    && prev->fmt == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-			/* 64 bit bits 63-32 */
-			prev->risc.jmp[2] = cpu_to_le32(0);
-			dprintk(2,
-				"[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-				buf, buf->vb.i, buf->count);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &q->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-				buf->vb.i);
-		}
-	}
-
-	if (list_empty(&q->active)) {
-		dprintk(2, "active queue empty!\n");
-	}
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = cx25821_buffer_setup,
-	.buf_prepare = cx25821_buffer_prepare,
-	.buf_queue = buffer_queue,
-	.buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct cx25821_dev *dev = video_drvdata(file);
-	struct cx25821_fh *fh;
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	u32 pix_format;
-
-	printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-		v4l2_type_names[type]);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-
-	lock_kernel();
-
-	file->private_data = fh;
-	fh->dev = dev;
-	fh->type = type;
-	fh->width = 720;
-
-	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-		fh->height = 576;
-	else
-		fh->height = 480;
-
-	dev->channel_opened = SRAM_CH03;
-	pix_format =
-	    (dev->pixel_formats[dev->channel_opened] ==
-	     PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-	fh->fmt = format_by_fourcc(pix_format);
-
-	v4l2_prio_open(&dev->prio, &fh->prio);
-
-	videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-			       &dev->pci->dev, &dev->slock,
-			       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			       V4L2_FIELD_INTERLACED,
-			       sizeof(struct cx25821_buffer), fh);
-
-	dprintk(1, "post videobuf_queue_init()\n");
-	unlock_kernel();
-
-	return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-			  loff_t * ppos)
-{
-	struct cx25821_fh *fh = file->private_data;
-
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO3))
-			return -EBUSY;
-
-		return videobuf_read_one(&fh->vidq, data, count, ppos,
-					 file->f_flags & O_NONBLOCK);
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static unsigned int video_poll(struct file *file,
-			       struct poll_table_struct *wait)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_buffer *buf;
-
-	if (cx25821_res_check(fh, RESOURCE_VIDEO3)) {
-		/* streaming capture */
-		if (list_empty(&fh->vidq.stream))
-			return POLLERR;
-		buf = list_entry(fh->vidq.stream.next,
-				 struct cx25821_buffer, vb.stream);
-	} else {
-		/* read() capture */
-		buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-		if (NULL == buf)
-			return POLLERR;
-	}
-
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-		if (buf->vb.state == VIDEOBUF_DONE) {
-			struct cx25821_dev *dev = fh->dev;
-
-			if (dev && dev->use_cif_resolution[SRAM_CH03]) {
-				u8 cam_id = *((char *)buf->vb.baddr + 3);
-				memcpy((char *)buf->vb.baddr,
-				       (char *)buf->vb.baddr + (fh->width * 2),
-				       (fh->width * 2));
-				*((char *)buf->vb.baddr + 3) = cam_id;
-			}
-		}
-
-		return POLLIN | POLLRDNORM;
-	}
-
-	return 0;
-}
-
-static int video_release(struct file *file)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-
-	//stop the risc engine and fifo
-	cx_write(channel3->dma_ctl, 0);	/* FIFO and RISC disable */
-
-	/* stop video capture */
-	if (cx25821_res_check(fh, RESOURCE_VIDEO3)) {
-		videobuf_queue_cancel(&fh->vidq);
-		cx25821_res_free(dev, fh, RESOURCE_VIDEO3);
-	}
-
-	if (fh->vidq.read_buf) {
-		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-		kfree(fh->vidq.read_buf);
-	}
-
-	videobuf_mmap_free(&fh->vidq);
-
-	v4l2_prio_close(&dev->prio, fh->prio);
-	file->private_data = NULL;
-	kfree(fh);
-
-	return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-
-	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(i != fh->type)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO3)))) {
-		return -EBUSY;
-	}
-
-	return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-	int err, res;
-
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	res = cx25821_get_resource(fh, RESOURCE_VIDEO3);
-	err = videobuf_streamoff(get_queue(fh));
-	if (err < 0)
-		return err;
-	cx25821_res_free(dev, fh, res);
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-	int pix_format = 0;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	dprintk(2, "%s()\n", __func__);
-	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-	if (0 != err)
-		return err;
-
-	fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-	fh->vidq.field = f->fmt.pix.field;
-
-	// check if width and height is valid based on set standard
-	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-		fh->width = f->fmt.pix.width;
-	}
-
-	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-		fh->height = f->fmt.pix.height;
-	}
-
-	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-		pix_format = PIXEL_FRMT_411;
-	else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-		pix_format = PIXEL_FRMT_422;
-	else
-		return -EINVAL;
-
-	cx25821_set_pixel_format(dev, SRAM_CH03, pix_format);
-
-	// check if cif resolution
-	if (fh->width == 320 || fh->width == 352) {
-		dev->use_cif_resolution[SRAM_CH03] = 1;
-	} else {
-		dev->use_cif_resolution[SRAM_CH03] = 0;
-	}
-	dev->cif_width[SRAM_CH03] = fh->width;
-	medusa_set_resolution(dev, fh->width, SRAM_CH03);
-
-	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-		fh->height, fh->vidq.field);
-	cx25821_call_all(dev, video, s_fmt, f);
-
-	return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	int ret_val = 0;
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-	ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-	p->sequence = dev->vidq[SRAM_CH03].count;
-
-	return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	char name[32 + 2];
-
-	struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH03];
-	u32 tmp = 0;
-
-	snprintf(name, sizeof(name), "%s/2", dev->name);
-	printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-	       dev->name);
-	cx25821_call_all(dev, core, log_status);
-
-	tmp = cx_read(sram_ch->dma_ctl);
-	printk(KERN_INFO "Video input 3 is %s\n",
-	       (tmp & 0x11) ? "streaming" : "stopped");
-	printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-	       dev->name);
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctl)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	return cx25821_set_control(dev, ctl, SRAM_CH03);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-	.owner = THIS_MODULE,
-	.open = video_open,
-	.release = video_release,
-	.read = video_read,
-	.poll = video_poll,
-	.mmap = cx25821_video_mmap,
-	.ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = cx25821_vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
-	.vidioc_querybuf = cx25821_vidioc_querybuf,
-	.vidioc_qbuf = cx25821_vidioc_qbuf,
-	.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-	.vidioc_s_std = cx25821_vidioc_s_std,
-	.vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-	.vidioc_cropcap = cx25821_vidioc_cropcap,
-	.vidioc_s_crop = cx25821_vidioc_s_crop,
-	.vidioc_g_crop = cx25821_vidioc_g_crop,
-	.vidioc_enum_input = cx25821_vidioc_enum_input,
-	.vidioc_g_input = cx25821_vidioc_g_input,
-	.vidioc_s_input = cx25821_vidioc_s_input,
-	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
-	.vidioc_streamon = vidioc_streamon,
-	.vidioc_streamoff = vidioc_streamoff,
-	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = cx25821_vidioc_g_priority,
-	.vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
-	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
-	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
-	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = cx25821_vidioc_g_register,
-	.vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template3 = {
-	.name = "cx25821-video",
-	.fops = &video_fops,
-	.ioctl_ops = &video_ioctl_ops,
-	.tvnorms = CX25821_NORMS,
-	.current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video4.c b/drivers/staging/cx25821/cx25821-video4.c
deleted file mode 100644
index f7b08c5..0000000
--- a/drivers/staging/cx25821/cx25821-video4.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-	struct cx25821_buffer *buf =
-	    container_of(vb, struct cx25821_buffer, vb);
-	struct cx25821_buffer *prev;
-	struct cx25821_fh *fh = vq->priv_data;
-	struct cx25821_dev *dev = fh->dev;
-	struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH04];
-
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
-
-	dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-	if (!list_empty(&q->queued)) {
-		list_add_tail(&buf->vb.queue, &q->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-			buf->vb.i);
-
-	} else if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx25821_start_video_dma(dev, q, buf,
-					&dev->sram_channels[SRAM_CH04]);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count = q->count++;
-		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-		dprintk(2,
-			"[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-			buf, buf->vb.i, buf->count, q->count);
-	} else {
-		prev =
-		    list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-		if (prev->vb.width == buf->vb.width
-		    && prev->vb.height == buf->vb.height
-		    && prev->fmt == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-			/* 64 bit bits 63-32 */
-			prev->risc.jmp[2] = cpu_to_le32(0);
-			dprintk(2,
-				"[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-				buf, buf->vb.i, buf->count);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &q->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-				buf->vb.i);
-		}
-	}
-
-	if (list_empty(&q->active)) {
-		dprintk(2, "active queue empty!\n");
-	}
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = cx25821_buffer_setup,
-	.buf_prepare = cx25821_buffer_prepare,
-	.buf_queue = buffer_queue,
-	.buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct cx25821_dev *dev = video_drvdata(file);
-	struct cx25821_fh *fh;
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	u32 pix_format;
-
-	printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-		v4l2_type_names[type]);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-
-	lock_kernel();
-
-	file->private_data = fh;
-	fh->dev = dev;
-	fh->type = type;
-	fh->width = 720;
-
-	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-		fh->height = 576;
-	else
-		fh->height = 480;
-
-	dev->channel_opened = SRAM_CH04;
-	pix_format =
-	    (dev->pixel_formats[dev->channel_opened] ==
-	     PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-	fh->fmt = format_by_fourcc(pix_format);
-
-	v4l2_prio_open(&dev->prio, &fh->prio);
-	videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-			       &dev->pci->dev, &dev->slock,
-			       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			       V4L2_FIELD_INTERLACED,
-			       sizeof(struct cx25821_buffer), fh);
-
-	dprintk(1, "post videobuf_queue_init()\n");
-	unlock_kernel();
-
-	return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-			  loff_t * ppos)
-{
-	struct cx25821_fh *fh = file->private_data;
-
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO4))
-			return -EBUSY;
-
-		return videobuf_read_one(&fh->vidq, data, count, ppos,
-					 file->f_flags & O_NONBLOCK);
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static unsigned int video_poll(struct file *file,
-			       struct poll_table_struct *wait)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_buffer *buf;
-
-	if (cx25821_res_check(fh, RESOURCE_VIDEO4)) {
-		/* streaming capture */
-		if (list_empty(&fh->vidq.stream))
-			return POLLERR;
-		buf = list_entry(fh->vidq.stream.next,
-				 struct cx25821_buffer, vb.stream);
-	} else {
-		/* read() capture */
-		buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-		if (NULL == buf)
-			return POLLERR;
-	}
-
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-		if (buf->vb.state == VIDEOBUF_DONE) {
-			struct cx25821_dev *dev = fh->dev;
-
-			if (dev && dev->use_cif_resolution[SRAM_CH04]) {
-				u8 cam_id = *((char *)buf->vb.baddr + 3);
-				memcpy((char *)buf->vb.baddr,
-				       (char *)buf->vb.baddr + (fh->width * 2),
-				       (fh->width * 2));
-				*((char *)buf->vb.baddr + 3) = cam_id;
-			}
-		}
-
-		return POLLIN | POLLRDNORM;
-	}
-
-	return 0;
-}
-
-static int video_release(struct file *file)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-
-	//stop the risc engine and fifo
-	cx_write(channel4->dma_ctl, 0);	/* FIFO and RISC disable */
-
-	/* stop video capture */
-	if (cx25821_res_check(fh, RESOURCE_VIDEO4)) {
-		videobuf_queue_cancel(&fh->vidq);
-		cx25821_res_free(dev, fh, RESOURCE_VIDEO4);
-	}
-
-	if (fh->vidq.read_buf) {
-		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-		kfree(fh->vidq.read_buf);
-	}
-
-	videobuf_mmap_free(&fh->vidq);
-
-	v4l2_prio_close(&dev->prio, fh->prio);
-	file->private_data = NULL;
-	kfree(fh);
-
-	return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-
-	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(i != fh->type)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO4)))) {
-		return -EBUSY;
-	}
-
-	return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-	int err, res;
-
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	res = cx25821_get_resource(fh, RESOURCE_VIDEO4);
-	err = videobuf_streamoff(get_queue(fh));
-	if (err < 0)
-		return err;
-	cx25821_res_free(dev, fh, res);
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-	int pix_format = 0;
-
-	// check priority
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-	dprintk(2, "%s()\n", __func__);
-	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-	if (0 != err)
-		return err;
-
-	fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-	fh->vidq.field = f->fmt.pix.field;
-
-	// check if width and height is valid based on set standard
-	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-		fh->width = f->fmt.pix.width;
-	}
-
-	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-		fh->height = f->fmt.pix.height;
-	}
-
-	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-		pix_format = PIXEL_FRMT_411;
-	else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-		pix_format = PIXEL_FRMT_422;
-	else
-		return -EINVAL;
-
-	cx25821_set_pixel_format(dev, SRAM_CH04, pix_format);
-
-	// check if cif resolution
-	if (fh->width == 320 || fh->width == 352) {
-		dev->use_cif_resolution[SRAM_CH04] = 1;
-	} else {
-		dev->use_cif_resolution[SRAM_CH04] = 0;
-	}
-	dev->cif_width[SRAM_CH04] = fh->width;
-	medusa_set_resolution(dev, fh->width, SRAM_CH04);
-
-	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-		fh->height, fh->vidq.field);
-	cx25821_call_all(dev, video, s_fmt, f);
-
-	return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	int ret_val = 0;
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-	ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-	p->sequence = dev->vidq[SRAM_CH04].count;
-
-	return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	char name[32 + 2];
-
-	struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH04];
-	u32 tmp = 0;
-
-	snprintf(name, sizeof(name), "%s/2", dev->name);
-	printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-	       dev->name);
-	cx25821_call_all(dev, core, log_status);
-
-	tmp = cx_read(sram_ch->dma_ctl);
-	printk(KERN_INFO "Video input 4 is %s\n",
-	       (tmp & 0x11) ? "streaming" : "stopped");
-	printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-	       dev->name);
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctl)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	return cx25821_set_control(dev, ctl, SRAM_CH04);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-	.owner = THIS_MODULE,
-	.open = video_open,
-	.release = video_release,
-	.read = video_read,
-	.poll = video_poll,
-	.mmap = cx25821_video_mmap,
-	.ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = cx25821_vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
-	.vidioc_querybuf = cx25821_vidioc_querybuf,
-	.vidioc_qbuf = cx25821_vidioc_qbuf,
-	.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-	.vidioc_s_std = cx25821_vidioc_s_std,
-	.vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-	.vidioc_cropcap = cx25821_vidioc_cropcap,
-	.vidioc_s_crop = cx25821_vidioc_s_crop,
-	.vidioc_g_crop = cx25821_vidioc_g_crop,
-	.vidioc_enum_input = cx25821_vidioc_enum_input,
-	.vidioc_g_input = cx25821_vidioc_g_input,
-	.vidioc_s_input = cx25821_vidioc_s_input,
-	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
-	.vidioc_streamon = vidioc_streamon,
-	.vidioc_streamoff = vidioc_streamoff,
-	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = cx25821_vidioc_g_priority,
-	.vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
-	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
-	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
-	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = cx25821_vidioc_g_register,
-	.vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template4 = {
-	.name = "cx25821-video",
-	.fops = &video_fops,
-	.ioctl_ops = &video_ioctl_ops,
-	.tvnorms = CX25821_NORMS,
-	.current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video5.c b/drivers/staging/cx25821/cx25821-video5.c
deleted file mode 100644
index 5937033..0000000
--- a/drivers/staging/cx25821/cx25821-video5.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-	struct cx25821_buffer *buf =
-	    container_of(vb, struct cx25821_buffer, vb);
-	struct cx25821_buffer *prev;
-	struct cx25821_fh *fh = vq->priv_data;
-	struct cx25821_dev *dev = fh->dev;
-	struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH05];
-
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
-
-	dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-	if (!list_empty(&q->queued)) {
-		list_add_tail(&buf->vb.queue, &q->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-			buf->vb.i);
-
-	} else if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx25821_start_video_dma(dev, q, buf,
-					&dev->sram_channels[SRAM_CH05]);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count = q->count++;
-		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-		dprintk(2,
-			"[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-			buf, buf->vb.i, buf->count, q->count);
-	} else {
-		prev =
-		    list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-		if (prev->vb.width == buf->vb.width
-		    && prev->vb.height == buf->vb.height
-		    && prev->fmt == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-			/* 64 bit bits 63-32 */
-			prev->risc.jmp[2] = cpu_to_le32(0);
-			dprintk(2,
-				"[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-				buf, buf->vb.i, buf->count);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &q->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-				buf->vb.i);
-		}
-	}
-
-	if (list_empty(&q->active)) {
-		dprintk(2, "active queue empty!\n");
-	}
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = cx25821_buffer_setup,
-	.buf_prepare = cx25821_buffer_prepare,
-	.buf_queue = buffer_queue,
-	.buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct cx25821_dev *dev = video_drvdata(file);
-	struct cx25821_fh *fh;
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	u32 pix_format;
-
-	printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-		v4l2_type_names[type]);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-
-	lock_kernel();
-
-	file->private_data = fh;
-	fh->dev = dev;
-	fh->type = type;
-	fh->width = 720;
-
-	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-		fh->height = 576;
-	else
-		fh->height = 480;
-
-	dev->channel_opened = SRAM_CH05;
-	pix_format =
-	    (dev->pixel_formats[dev->channel_opened] ==
-	     PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-	fh->fmt = format_by_fourcc(pix_format);
-
-	v4l2_prio_open(&dev->prio, &fh->prio);
-
-	videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-			       &dev->pci->dev, &dev->slock,
-			       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			       V4L2_FIELD_INTERLACED,
-			       sizeof(struct cx25821_buffer), fh);
-
-	dprintk(1, "post videobuf_queue_init()\n");
-	unlock_kernel();
-
-	return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-			  loff_t * ppos)
-{
-	struct cx25821_fh *fh = file->private_data;
-
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO5))
-			return -EBUSY;
-
-		return videobuf_read_one(&fh->vidq, data, count, ppos,
-					 file->f_flags & O_NONBLOCK);
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static unsigned int video_poll(struct file *file,
-			       struct poll_table_struct *wait)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_buffer *buf;
-
-	if (cx25821_res_check(fh, RESOURCE_VIDEO5)) {
-		/* streaming capture */
-		if (list_empty(&fh->vidq.stream))
-			return POLLERR;
-		buf = list_entry(fh->vidq.stream.next,
-				 struct cx25821_buffer, vb.stream);
-	} else {
-		/* read() capture */
-		buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-		if (NULL == buf)
-			return POLLERR;
-	}
-
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-		if (buf->vb.state == VIDEOBUF_DONE) {
-			struct cx25821_dev *dev = fh->dev;
-
-			if (dev && dev->use_cif_resolution[SRAM_CH05]) {
-				u8 cam_id = *((char *)buf->vb.baddr + 3);
-				memcpy((char *)buf->vb.baddr,
-				       (char *)buf->vb.baddr + (fh->width * 2),
-				       (fh->width * 2));
-				*((char *)buf->vb.baddr + 3) = cam_id;
-			}
-		}
-
-		return POLLIN | POLLRDNORM;
-	}
-
-	return 0;
-}
-
-static int video_release(struct file *file)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-
-	//stop the risc engine and fifo
-	cx_write(channel5->dma_ctl, 0);	/* FIFO and RISC disable */
-
-	/* stop video capture */
-	if (cx25821_res_check(fh, RESOURCE_VIDEO5)) {
-		videobuf_queue_cancel(&fh->vidq);
-		cx25821_res_free(dev, fh, RESOURCE_VIDEO5);
-	}
-
-	if (fh->vidq.read_buf) {
-		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-		kfree(fh->vidq.read_buf);
-	}
-
-	videobuf_mmap_free(&fh->vidq);
-
-	v4l2_prio_close(&dev->prio, fh->prio);
-	file->private_data = NULL;
-	kfree(fh);
-
-	return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-
-	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(i != fh->type)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO5)))) {
-		return -EBUSY;
-	}
-
-	return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-	int err, res;
-
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	res = cx25821_get_resource(fh, RESOURCE_VIDEO5);
-	err = videobuf_streamoff(get_queue(fh));
-	if (err < 0)
-		return err;
-	cx25821_res_free(dev, fh, res);
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-	int pix_format = 0;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	dprintk(2, "%s()\n", __func__);
-	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-	if (0 != err)
-		return err;
-
-	fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-	fh->vidq.field = f->fmt.pix.field;
-
-	// check if width and height is valid based on set standard
-	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-		fh->width = f->fmt.pix.width;
-	}
-
-	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-		fh->height = f->fmt.pix.height;
-	}
-
-	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-		pix_format = PIXEL_FRMT_411;
-	else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-		pix_format = PIXEL_FRMT_422;
-	else
-		return -EINVAL;
-
-	cx25821_set_pixel_format(dev, SRAM_CH05, pix_format);
-
-	// check if cif resolution
-	if (fh->width == 320 || fh->width == 352) {
-		dev->use_cif_resolution[SRAM_CH05] = 1;
-	} else {
-		dev->use_cif_resolution[SRAM_CH05] = 0;
-	}
-	dev->cif_width[SRAM_CH05] = fh->width;
-	medusa_set_resolution(dev, fh->width, SRAM_CH05);
-
-	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-		fh->height, fh->vidq.field);
-	cx25821_call_all(dev, video, s_fmt, f);
-
-	return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	int ret_val = 0;
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-	ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-	p->sequence = dev->vidq[SRAM_CH05].count;
-
-	return ret_val;
-}
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	char name[32 + 2];
-
-	struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH05];
-	u32 tmp = 0;
-
-	snprintf(name, sizeof(name), "%s/2", dev->name);
-	printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-	       dev->name);
-	cx25821_call_all(dev, core, log_status);
-
-	tmp = cx_read(sram_ch->dma_ctl);
-	printk(KERN_INFO "Video input 5 is %s\n",
-	       (tmp & 0x11) ? "streaming" : "stopped");
-	printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-	       dev->name);
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctl)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	return cx25821_set_control(dev, ctl, SRAM_CH05);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-	.owner = THIS_MODULE,
-	.open = video_open,
-	.release = video_release,
-	.read = video_read,
-	.poll = video_poll,
-	.mmap = cx25821_video_mmap,
-	.ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = cx25821_vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
-	.vidioc_querybuf = cx25821_vidioc_querybuf,
-	.vidioc_qbuf = cx25821_vidioc_qbuf,
-	.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-	.vidioc_s_std = cx25821_vidioc_s_std,
-	.vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-	.vidioc_cropcap = cx25821_vidioc_cropcap,
-	.vidioc_s_crop = cx25821_vidioc_s_crop,
-	.vidioc_g_crop = cx25821_vidioc_g_crop,
-	.vidioc_enum_input = cx25821_vidioc_enum_input,
-	.vidioc_g_input = cx25821_vidioc_g_input,
-	.vidioc_s_input = cx25821_vidioc_s_input,
-	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
-	.vidioc_streamon = vidioc_streamon,
-	.vidioc_streamoff = vidioc_streamoff,
-	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = cx25821_vidioc_g_priority,
-	.vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
-	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
-	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
-	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = cx25821_vidioc_g_register,
-	.vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template5 = {
-	.name = "cx25821-video",
-	.fops = &video_fops,
-	.ioctl_ops = &video_ioctl_ops,
-	.tvnorms = CX25821_NORMS,
-	.current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video6.c b/drivers/staging/cx25821/cx25821-video6.c
deleted file mode 100644
index 4db2eb8..0000000
--- a/drivers/staging/cx25821/cx25821-video6.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-	struct cx25821_buffer *buf =
-	    container_of(vb, struct cx25821_buffer, vb);
-	struct cx25821_buffer *prev;
-	struct cx25821_fh *fh = vq->priv_data;
-	struct cx25821_dev *dev = fh->dev;
-	struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH06];
-
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
-
-	dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-	if (!list_empty(&q->queued)) {
-		list_add_tail(&buf->vb.queue, &q->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-			buf->vb.i);
-
-	} else if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx25821_start_video_dma(dev, q, buf,
-					&dev->sram_channels[SRAM_CH06]);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count = q->count++;
-		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-		dprintk(2,
-			"[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-			buf, buf->vb.i, buf->count, q->count);
-	} else {
-		prev =
-		    list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-		if (prev->vb.width == buf->vb.width
-		    && prev->vb.height == buf->vb.height
-		    && prev->fmt == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-			/* 64 bit bits 63-32 */
-			prev->risc.jmp[2] = cpu_to_le32(0);
-			dprintk(2,
-				"[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-				buf, buf->vb.i, buf->count);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &q->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-				buf->vb.i);
-		}
-	}
-
-	if (list_empty(&q->active)) {
-		dprintk(2, "active queue empty!\n");
-	}
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = cx25821_buffer_setup,
-	.buf_prepare = cx25821_buffer_prepare,
-	.buf_queue = buffer_queue,
-	.buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct cx25821_dev *dev = video_drvdata(file);
-	struct cx25821_fh *fh;
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	u32 pix_format;
-
-	printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-		v4l2_type_names[type]);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-
-	lock_kernel();
-
-	file->private_data = fh;
-	fh->dev = dev;
-	fh->type = type;
-	fh->width = 720;
-
-	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-		fh->height = 576;
-	else
-		fh->height = 480;
-
-	dev->channel_opened = SRAM_CH06;
-	pix_format =
-	    (dev->pixel_formats[dev->channel_opened] ==
-	     PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-	fh->fmt = format_by_fourcc(pix_format);
-
-	v4l2_prio_open(&dev->prio, &fh->prio);
-
-	videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-			       &dev->pci->dev, &dev->slock,
-			       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			       V4L2_FIELD_INTERLACED,
-			       sizeof(struct cx25821_buffer), fh);
-
-	dprintk(1, "post videobuf_queue_init()\n");
-	unlock_kernel();
-
-	return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-			  loff_t * ppos)
-{
-	struct cx25821_fh *fh = file->private_data;
-
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO6))
-			return -EBUSY;
-
-		return videobuf_read_one(&fh->vidq, data, count, ppos,
-					 file->f_flags & O_NONBLOCK);
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static unsigned int video_poll(struct file *file,
-			       struct poll_table_struct *wait)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_buffer *buf;
-
-	if (cx25821_res_check(fh, RESOURCE_VIDEO6)) {
-		/* streaming capture */
-		if (list_empty(&fh->vidq.stream))
-			return POLLERR;
-		buf = list_entry(fh->vidq.stream.next,
-				 struct cx25821_buffer, vb.stream);
-	} else {
-		/* read() capture */
-		buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-		if (NULL == buf)
-			return POLLERR;
-	}
-
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-		if (buf->vb.state == VIDEOBUF_DONE) {
-			struct cx25821_dev *dev = fh->dev;
-
-			if (dev && dev->use_cif_resolution[SRAM_CH06]) {
-				u8 cam_id = *((char *)buf->vb.baddr + 3);
-				memcpy((char *)buf->vb.baddr,
-				       (char *)buf->vb.baddr + (fh->width * 2),
-				       (fh->width * 2));
-				*((char *)buf->vb.baddr + 3) = cam_id;
-			}
-		}
-
-		return POLLIN | POLLRDNORM;
-	}
-
-	return 0;
-}
-
-static int video_release(struct file *file)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-
-	//stop the risc engine and fifo
-	cx_write(channel6->dma_ctl, 0);	/* FIFO and RISC disable */
-
-	/* stop video capture */
-	if (cx25821_res_check(fh, RESOURCE_VIDEO6)) {
-		videobuf_queue_cancel(&fh->vidq);
-		cx25821_res_free(dev, fh, RESOURCE_VIDEO6);
-	}
-	if (fh->vidq.read_buf) {
-		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-		kfree(fh->vidq.read_buf);
-	}
-
-	videobuf_mmap_free(&fh->vidq);
-
-	v4l2_prio_close(&dev->prio, fh->prio);
-	file->private_data = NULL;
-	kfree(fh);
-
-	return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-
-	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(i != fh->type)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO6)))) {
-		return -EBUSY;
-	}
-
-	return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-	int err, res;
-
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	res = cx25821_get_resource(fh, RESOURCE_VIDEO6);
-	err = videobuf_streamoff(get_queue(fh));
-	if (err < 0)
-		return err;
-	cx25821_res_free(dev, fh, res);
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-	int pix_format = 0;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	dprintk(2, "%s()\n", __func__);
-	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-	if (0 != err)
-		return err;
-
-	fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-	fh->vidq.field = f->fmt.pix.field;
-
-	// check if width and height is valid based on set standard
-	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-		fh->width = f->fmt.pix.width;
-	}
-
-	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-		fh->height = f->fmt.pix.height;
-	}
-
-	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-		pix_format = PIXEL_FRMT_411;
-	else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-		pix_format = PIXEL_FRMT_422;
-	else
-		return -EINVAL;
-
-	cx25821_set_pixel_format(dev, SRAM_CH06, pix_format);
-
-	// check if cif resolution
-	if (fh->width == 320 || fh->width == 352) {
-		dev->use_cif_resolution[SRAM_CH06] = 1;
-	} else {
-		dev->use_cif_resolution[SRAM_CH06] = 0;
-	}
-	dev->cif_width[SRAM_CH06] = fh->width;
-	medusa_set_resolution(dev, fh->width, SRAM_CH06);
-
-	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-		fh->height, fh->vidq.field);
-	cx25821_call_all(dev, video, s_fmt, f);
-
-	return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	int ret_val = 0;
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-	ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-	p->sequence = dev->vidq[SRAM_CH06].count;
-
-	return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	char name[32 + 2];
-
-	struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH06];
-	u32 tmp = 0;
-
-	snprintf(name, sizeof(name), "%s/2", dev->name);
-	printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-	       dev->name);
-	cx25821_call_all(dev, core, log_status);
-
-	tmp = cx_read(sram_ch->dma_ctl);
-	printk(KERN_INFO "Video input 6 is %s\n",
-	       (tmp & 0x11) ? "streaming" : "stopped");
-	printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-	       dev->name);
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctl)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	return cx25821_set_control(dev, ctl, SRAM_CH06);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-	.owner = THIS_MODULE,
-	.open = video_open,
-	.release = video_release,
-	.read = video_read,
-	.poll = video_poll,
-	.mmap = cx25821_video_mmap,
-	.ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = cx25821_vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
-	.vidioc_querybuf = cx25821_vidioc_querybuf,
-	.vidioc_qbuf = cx25821_vidioc_qbuf,
-	.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-	.vidioc_s_std = cx25821_vidioc_s_std,
-	.vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-	.vidioc_cropcap = cx25821_vidioc_cropcap,
-	.vidioc_s_crop = cx25821_vidioc_s_crop,
-	.vidioc_g_crop = cx25821_vidioc_g_crop,
-	.vidioc_enum_input = cx25821_vidioc_enum_input,
-	.vidioc_g_input = cx25821_vidioc_g_input,
-	.vidioc_s_input = cx25821_vidioc_s_input,
-	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
-	.vidioc_streamon = vidioc_streamon,
-	.vidioc_streamoff = vidioc_streamoff,
-	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = cx25821_vidioc_g_priority,
-	.vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
-	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
-	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
-	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = cx25821_vidioc_g_register,
-	.vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template6 = {
-	.name = "cx25821-video",
-	.fops = &video_fops,
-	.ioctl_ops = &video_ioctl_ops,
-	.tvnorms = CX25821_NORMS,
-	.current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video7.c b/drivers/staging/cx25821/cx25821-video7.c
deleted file mode 100644
index 5e4a769..0000000
--- a/drivers/staging/cx25821/cx25821-video7.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-	struct cx25821_buffer *buf =
-	    container_of(vb, struct cx25821_buffer, vb);
-	struct cx25821_buffer *prev;
-	struct cx25821_fh *fh = vq->priv_data;
-	struct cx25821_dev *dev = fh->dev;
-	struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH07];
-
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
-
-	dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-	if (!list_empty(&q->queued)) {
-		list_add_tail(&buf->vb.queue, &q->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-			buf->vb.i);
-
-	} else if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx25821_start_video_dma(dev, q, buf,
-					&dev->sram_channels[SRAM_CH07]);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count = q->count++;
-		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-		dprintk(2,
-			"[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-			buf, buf->vb.i, buf->count, q->count);
-	} else {
-		prev =
-		    list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-		if (prev->vb.width == buf->vb.width
-		    && prev->vb.height == buf->vb.height
-		    && prev->fmt == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-			/* 64 bit bits 63-32 */
-			prev->risc.jmp[2] = cpu_to_le32(0);
-			dprintk(2,
-				"[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-				buf, buf->vb.i, buf->count);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &q->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-				buf->vb.i);
-		}
-	}
-
-	if (list_empty(&q->active)) {
-		dprintk(2, "active queue empty!\n");
-	}
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = cx25821_buffer_setup,
-	.buf_prepare = cx25821_buffer_prepare,
-	.buf_queue = buffer_queue,
-	.buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct cx25821_dev *dev = video_drvdata(file);
-	struct cx25821_fh *fh;
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	u32 pix_format;
-
-	printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-		v4l2_type_names[type]);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-
-	lock_kernel();
-
-	file->private_data = fh;
-	fh->dev = dev;
-	fh->type = type;
-	fh->width = 720;
-
-	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-		fh->height = 576;
-	else
-		fh->height = 480;
-
-	dev->channel_opened = SRAM_CH07;
-	pix_format =
-	    (dev->pixel_formats[dev->channel_opened] ==
-	     PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
-	fh->fmt = format_by_fourcc(pix_format);
-
-	v4l2_prio_open(&dev->prio, &fh->prio);
-
-	videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-			       &dev->pci->dev, &dev->slock,
-			       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			       V4L2_FIELD_INTERLACED,
-			       sizeof(struct cx25821_buffer), fh);
-
-	dprintk(1, "post videobuf_queue_init()\n");
-	unlock_kernel();
-
-	return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-			  loff_t * ppos)
-{
-	struct cx25821_fh *fh = file->private_data;
-
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO7))
-			return -EBUSY;
-
-		return videobuf_read_one(&fh->vidq, data, count, ppos,
-					 file->f_flags & O_NONBLOCK);
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static unsigned int video_poll(struct file *file,
-			       struct poll_table_struct *wait)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_buffer *buf;
-
-	if (cx25821_res_check(fh, RESOURCE_VIDEO7)) {
-		/* streaming capture */
-		if (list_empty(&fh->vidq.stream))
-			return POLLERR;
-		buf = list_entry(fh->vidq.stream.next,
-				 struct cx25821_buffer, vb.stream);
-	} else {
-		/* read() capture */
-		buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-		if (NULL == buf)
-			return POLLERR;
-	}
-
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
-		if (buf->vb.state == VIDEOBUF_DONE) {
-			struct cx25821_dev *dev = fh->dev;
-
-			if (dev && dev->use_cif_resolution[SRAM_CH07]) {
-				u8 cam_id = *((char *)buf->vb.baddr + 3);
-				memcpy((char *)buf->vb.baddr,
-				       (char *)buf->vb.baddr + (fh->width * 2),
-				       (fh->width * 2));
-				*((char *)buf->vb.baddr + 3) = cam_id;
-			}
-		}
-
-		return POLLIN | POLLRDNORM;
-	}
-
-	return 0;
-}
-
-static int video_release(struct file *file)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-
-	//stop the risc engine and fifo
-	cx_write(channel7->dma_ctl, 0);	/* FIFO and RISC disable */
-
-	/* stop video capture */
-	if (cx25821_res_check(fh, RESOURCE_VIDEO7)) {
-		videobuf_queue_cancel(&fh->vidq);
-		cx25821_res_free(dev, fh, RESOURCE_VIDEO7);
-	}
-
-	if (fh->vidq.read_buf) {
-		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-		kfree(fh->vidq.read_buf);
-	}
-
-	videobuf_mmap_free(&fh->vidq);
-
-	v4l2_prio_close(&dev->prio, fh->prio);
-	file->private_data = NULL;
-	kfree(fh);
-
-	return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-
-	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(i != fh->type)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO7)))) {
-		return -EBUSY;
-	}
-
-	return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-	int err, res;
-
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	res = cx25821_get_resource(fh, RESOURCE_VIDEO7);
-	err = videobuf_streamoff(get_queue(fh));
-	if (err < 0)
-		return err;
-	cx25821_res_free(dev, fh, res);
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-	int pix_format = 0;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	dprintk(2, "%s()\n", __func__);
-	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-	if (0 != err)
-		return err;
-
-	fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-	fh->vidq.field = f->fmt.pix.field;
-
-	// check if width and height is valid based on set standard
-	if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
-		fh->width = f->fmt.pix.width;
-	}
-
-	if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
-		fh->height = f->fmt.pix.height;
-	}
-
-	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
-		pix_format = PIXEL_FRMT_411;
-	else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
-		pix_format = PIXEL_FRMT_422;
-	else
-		return -EINVAL;
-
-	cx25821_set_pixel_format(dev, SRAM_CH07, pix_format);
-
-	// check if cif resolution
-	if (fh->width == 320 || fh->width == 352) {
-		dev->use_cif_resolution[SRAM_CH07] = 1;
-	} else {
-		dev->use_cif_resolution[SRAM_CH07] = 0;
-	}
-	dev->cif_width[SRAM_CH07] = fh->width;
-	medusa_set_resolution(dev, fh->width, SRAM_CH07);
-
-	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-		fh->height, fh->vidq.field);
-	cx25821_call_all(dev, video, s_fmt, f);
-
-	return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	int ret_val = 0;
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
-	ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
-	p->sequence = dev->vidq[SRAM_CH07].count;
-
-	return ret_val;
-}
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	char name[32 + 2];
-
-	struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH07];
-	u32 tmp = 0;
-
-	snprintf(name, sizeof(name), "%s/2", dev->name);
-	printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-	       dev->name);
-	cx25821_call_all(dev, core, log_status);
-
-	tmp = cx_read(sram_ch->dma_ctl);
-	printk(KERN_INFO "Video input 7 is %s\n",
-	       (tmp & 0x11) ? "streaming" : "stopped");
-	printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-	       dev->name);
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctl)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	return cx25821_set_control(dev, ctl, SRAM_CH07);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-	.owner = THIS_MODULE,
-	.open = video_open,
-	.release = video_release,
-	.read = video_read,
-	.poll = video_poll,
-	.mmap = cx25821_video_mmap,
-	.ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = cx25821_vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
-	.vidioc_querybuf = cx25821_vidioc_querybuf,
-	.vidioc_qbuf = cx25821_vidioc_qbuf,
-	.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-	.vidioc_s_std = cx25821_vidioc_s_std,
-	.vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-	.vidioc_cropcap = cx25821_vidioc_cropcap,
-	.vidioc_s_crop = cx25821_vidioc_s_crop,
-	.vidioc_g_crop = cx25821_vidioc_g_crop,
-	.vidioc_enum_input = cx25821_vidioc_enum_input,
-	.vidioc_g_input = cx25821_vidioc_g_input,
-	.vidioc_s_input = cx25821_vidioc_s_input,
-	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
-	.vidioc_streamon = vidioc_streamon,
-	.vidioc_streamoff = vidioc_streamoff,
-	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = cx25821_vidioc_g_priority,
-	.vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
-	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
-	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
-	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = cx25821_vidioc_g_register,
-	.vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template7 = {
-	.name = "cx25821-video",
-	.fops = &video_fops,
-	.ioctl_ops = &video_ioctl_ops,
-	.tvnorms = CX25821_NORMS,
-	.current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-videoioctl.c b/drivers/staging/cx25821/cx25821-videoioctl.c
deleted file mode 100644
index d16807d..0000000
--- a/drivers/staging/cx25821/cx25821-videoioctl.c
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-	struct cx25821_buffer *buf =
-	    container_of(vb, struct cx25821_buffer, vb);
-	struct cx25821_buffer *prev;
-	struct cx25821_fh *fh = vq->priv_data;
-	struct cx25821_dev *dev = fh->dev;
-	struct cx25821_dmaqueue *q = &dev->vidq[VIDEO_IOCTL_CH];
-
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
-
-	dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-	if (!list_empty(&q->queued)) {
-		list_add_tail(&buf->vb.queue, &q->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-			buf->vb.i);
-
-	} else if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx25821_start_video_dma(dev, q, buf,
-					&dev->sram_channels[VIDEO_IOCTL_CH]);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count = q->count++;
-		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-		dprintk(2,
-			"[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-			buf, buf->vb.i, buf->count, q->count);
-	} else {
-		prev =
-		    list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-		if (prev->vb.width == buf->vb.width
-		    && prev->vb.height == buf->vb.height
-		    && prev->fmt == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-			/* 64 bit bits 63-32 */
-			prev->risc.jmp[2] = cpu_to_le32(0);
-			dprintk(2,
-				"[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-				buf, buf->vb.i, buf->count);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &q->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-				buf->vb.i);
-		}
-	}
-
-	if (list_empty(&q->active)) {
-		dprintk(2, "active queue empty!\n");
-	}
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = cx25821_buffer_setup,
-	.buf_prepare = cx25821_buffer_prepare,
-	.buf_queue = buffer_queue,
-	.buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct cx25821_dev *dev = video_drvdata(file);
-	struct cx25821_fh *fh;
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	u32 pix_format;
-
-	printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-		v4l2_type_names[type]);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-
-	lock_kernel();
-
-	file->private_data = fh;
-	fh->dev = dev;
-	fh->type = type;
-	fh->width = 720;
-
-	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-		fh->height = 576;
-	else
-		fh->height = 480;
-
-	dev->channel_opened = VIDEO_IOCTL_CH;
-	pix_format = V4L2_PIX_FMT_YUYV;
-	fh->fmt = format_by_fourcc(pix_format);
-
-	v4l2_prio_open(&dev->prio, &fh->prio);
-
-	videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-			       &dev->pci->dev, &dev->slock,
-			       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			       V4L2_FIELD_INTERLACED,
-			       sizeof(struct cx25821_buffer), fh);
-
-	dprintk(1, "post videobuf_queue_init()\n");
-	unlock_kernel();
-
-	return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-			  loff_t * ppos)
-{
-	struct cx25821_fh *fh = file->private_data;
-
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO_IOCTL))
-			return -EBUSY;
-
-		return videobuf_read_one(&fh->vidq, data, count, ppos,
-					 file->f_flags & O_NONBLOCK);
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static unsigned int video_poll(struct file *file,
-			       struct poll_table_struct *wait)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_buffer *buf;
-
-	if (cx25821_res_check(fh, RESOURCE_VIDEO_IOCTL)) {
-		/* streaming capture */
-		if (list_empty(&fh->vidq.stream))
-			return POLLERR;
-		buf = list_entry(fh->vidq.stream.next,
-				 struct cx25821_buffer, vb.stream);
-	} else {
-		/* read() capture */
-		buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-		if (NULL == buf)
-			return POLLERR;
-	}
-
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
-		return POLLIN | POLLRDNORM;
-
-	return 0;
-}
-
-static int video_release(struct file *file)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-
-	/* stop video capture */
-	if (cx25821_res_check(fh, RESOURCE_VIDEO_IOCTL)) {
-		videobuf_queue_cancel(&fh->vidq);
-		cx25821_res_free(dev, fh, RESOURCE_VIDEO_IOCTL);
-	}
-
-	if (fh->vidq.read_buf) {
-		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-		kfree(fh->vidq.read_buf);
-	}
-
-	videobuf_mmap_free(&fh->vidq);
-
-	v4l2_prio_close(&dev->prio, fh->prio);
-
-	file->private_data = NULL;
-	kfree(fh);
-
-	return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-
-	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(i != fh->type)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO_IOCTL)))) {
-		return -EBUSY;
-	}
-
-	return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-	int err, res;
-
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	res = cx25821_get_resource(fh, RESOURCE_VIDEO_IOCTL);
-	err = videobuf_streamoff(get_queue(fh));
-	if (err < 0)
-		return err;
-	cx25821_res_free(dev, fh, res);
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	dprintk(2, "%s()\n", __func__);
-	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-	if (0 != err)
-		return err;
-	fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-	fh->width = f->fmt.pix.width;
-	fh->height = f->fmt.pix.height;
-	fh->vidq.field = f->fmt.pix.field;
-	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-		fh->height, fh->vidq.field);
-	cx25821_call_all(dev, video, s_fmt, f);
-	return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	struct cx25821_fh *fh = priv;
-	return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-}
-
-static long video_ioctl_set(struct file *file, unsigned int cmd,
-			    unsigned long arg)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-	struct downstream_user_struct *data_from_user;
-	int command;
-	int width = 720;
-	int selected_channel = 0, pix_format = 0, i = 0;
-	int cif_enable = 0, cif_width = 0;
-	u32 value = 0;
-
-	data_from_user = (struct downstream_user_struct *)arg;
-
-	if (!data_from_user) {
-		printk("cx25821 in %s(): User data is INVALID. Returning.\n",
-		       __func__);
-		return 0;
-	}
-
-	command = data_from_user->command;
-
-	if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
-	    && command != ENABLE_CIF_RESOLUTION && command != REG_READ
-	    && command != REG_WRITE && command != MEDUSA_READ
-	    && command != MEDUSA_WRITE) {
-		return 0;
-	}
-
-	switch (command) {
-	case SET_VIDEO_STD:
-		dev->tvnorm =
-		    !strcmp(data_from_user->vid_stdname,
-			    "PAL") ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
-		medusa_set_videostandard(dev);
-		break;
-
-	case SET_PIXEL_FORMAT:
-		selected_channel = data_from_user->decoder_select;
-		pix_format = data_from_user->pixel_format;
-
-		if (!(selected_channel <= 7 && selected_channel >= 0)) {
-			selected_channel -= 4;
-			selected_channel = selected_channel % 8;
-		}
-
-		if (selected_channel >= 0)
-			cx25821_set_pixel_format(dev, selected_channel,
-						 pix_format);
-
-		break;
-
-	case ENABLE_CIF_RESOLUTION:
-		selected_channel = data_from_user->decoder_select;
-		cif_enable = data_from_user->cif_resolution_enable;
-		cif_width = data_from_user->cif_width;
-
-		if (cif_enable) {
-			if (dev->tvnorm & V4L2_STD_PAL_BG
-			    || dev->tvnorm & V4L2_STD_PAL_DK)
-				width = 352;
-			else
-				width = (cif_width == 320
-					 || cif_width == 352) ? cif_width : 320;
-		}
-
-		if (!(selected_channel <= 7 && selected_channel >= 0)) {
-			selected_channel -= 4;
-			selected_channel = selected_channel % 8;
-		}
-
-		if (selected_channel <= 7 && selected_channel >= 0) {
-			dev->use_cif_resolution[selected_channel] = cif_enable;
-			dev->cif_width[selected_channel] = width;
-		} else {
-			for (i = 0; i < VID_CHANNEL_NUM; i++) {
-				dev->use_cif_resolution[i] = cif_enable;
-				dev->cif_width[i] = width;
-			}
-		}
-
-		medusa_set_resolution(dev, width, selected_channel);
-		break;
-	case REG_READ:
-		data_from_user->reg_data = cx_read(data_from_user->reg_address);
-		break;
-	case REG_WRITE:
-		cx_write(data_from_user->reg_address, data_from_user->reg_data);
-		break;
-	case MEDUSA_READ:
-		value =
-		    cx25821_i2c_read(&dev->i2c_bus[0],
-				     (u16) data_from_user->reg_address,
-				     &data_from_user->reg_data);
-		break;
-	case MEDUSA_WRITE:
-		cx25821_i2c_write(&dev->i2c_bus[0],
-				  (u16) data_from_user->reg_address,
-				  data_from_user->reg_data);
-		break;
-	}
-
-	return 0;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	char name[32 + 2];
-
-	snprintf(name, sizeof(name), "%s/2", dev->name);
-	printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-	       dev->name);
-	cx25821_call_all(dev, core, log_status);
-	printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-	       dev->name);
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctl)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	return 0;
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-	.owner = THIS_MODULE,
-	.open = video_open,
-	.release = video_release,
-	.read = video_read,
-	.poll = video_poll,
-	.mmap = cx25821_video_mmap,
-	.ioctl = video_ioctl_set,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = cx25821_vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
-	.vidioc_querybuf = cx25821_vidioc_querybuf,
-	.vidioc_qbuf = cx25821_vidioc_qbuf,
-	.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-	.vidioc_s_std = cx25821_vidioc_s_std,
-	.vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-	.vidioc_cropcap = cx25821_vidioc_cropcap,
-	.vidioc_s_crop = cx25821_vidioc_s_crop,
-	.vidioc_g_crop = cx25821_vidioc_g_crop,
-	.vidioc_enum_input = cx25821_vidioc_enum_input,
-	.vidioc_g_input = cx25821_vidioc_g_input,
-	.vidioc_s_input = cx25821_vidioc_s_input,
-	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
-	.vidioc_streamon = vidioc_streamon,
-	.vidioc_streamoff = vidioc_streamoff,
-	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = cx25821_vidioc_g_priority,
-	.vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
-	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
-	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
-	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = cx25821_vidioc_g_register,
-	.vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_videoioctl_template = {
-	.name = "cx25821-videoioctl",
-	.fops = &video_fops,
-	.ioctl_ops = &video_ioctl_ops,
-	.tvnorms = CX25821_NORMS,
-	.current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-vidups10.c b/drivers/staging/cx25821/cx25821-vidups10.c
deleted file mode 100644
index c746a17..0000000
--- a/drivers/staging/cx25821/cx25821-vidups10.c
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-	struct cx25821_buffer *buf =
-	    container_of(vb, struct cx25821_buffer, vb);
-	struct cx25821_buffer *prev;
-	struct cx25821_fh *fh = vq->priv_data;
-	struct cx25821_dev *dev = fh->dev;
-	struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH10];
-
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
-
-	dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-	if (!list_empty(&q->queued)) {
-		list_add_tail(&buf->vb.queue, &q->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-			buf->vb.i);
-
-	} else if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx25821_start_video_dma(dev, q, buf,
-					&dev->sram_channels[SRAM_CH10]);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count = q->count++;
-		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-		dprintk(2,
-			"[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-			buf, buf->vb.i, buf->count, q->count);
-	} else {
-		prev =
-		    list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-		if (prev->vb.width == buf->vb.width
-		    && prev->vb.height == buf->vb.height
-		    && prev->fmt == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-			/* 64 bit bits 63-32 */
-			prev->risc.jmp[2] = cpu_to_le32(0);
-			dprintk(2,
-				"[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-				buf, buf->vb.i, buf->count);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &q->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-				buf->vb.i);
-		}
-	}
-
-	if (list_empty(&q->active)) {
-		dprintk(2, "active queue empty!\n");
-	}
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = cx25821_buffer_setup,
-	.buf_prepare = cx25821_buffer_prepare,
-	.buf_queue = buffer_queue,
-	.buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct cx25821_dev *dev = video_drvdata(file);
-	struct cx25821_fh *fh;
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-	printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-		v4l2_type_names[type]);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-
-	lock_kernel();
-
-	file->private_data = fh;
-	fh->dev = dev;
-	fh->type = type;
-	fh->width = 720;
-
-	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-		fh->height = 576;
-	else
-		fh->height = 480;
-
-	dev->channel_opened = 9;
-	fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
-
-	v4l2_prio_open(&dev->prio, &fh->prio);
-
-	videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-			       &dev->pci->dev, &dev->slock,
-			       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			       V4L2_FIELD_INTERLACED,
-			       sizeof(struct cx25821_buffer), fh);
-
-	dprintk(1, "post videobuf_queue_init()\n");
-	unlock_kernel();
-
-	return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-			  loff_t * ppos)
-{
-	struct cx25821_fh *fh = file->private_data;
-
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO10))
-			return -EBUSY;
-
-		return videobuf_read_one(&fh->vidq, data, count, ppos,
-					 file->f_flags & O_NONBLOCK);
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static unsigned int video_poll(struct file *file,
-			       struct poll_table_struct *wait)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_buffer *buf;
-
-	if (cx25821_res_check(fh, RESOURCE_VIDEO10)) {
-		/* streaming capture */
-		if (list_empty(&fh->vidq.stream))
-			return POLLERR;
-		buf = list_entry(fh->vidq.stream.next,
-				 struct cx25821_buffer, vb.stream);
-	} else {
-		/* read() capture */
-		buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-		if (NULL == buf)
-			return POLLERR;
-	}
-
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-static int video_release(struct file *file)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-
-	//stop the risc engine and fifo
-	//cx_write(channel10->dma_ctl, 0);
-
-	/* stop video capture */
-	if (cx25821_res_check(fh, RESOURCE_VIDEO10)) {
-		videobuf_queue_cancel(&fh->vidq);
-		cx25821_res_free(dev, fh, RESOURCE_VIDEO10);
-	}
-
-	if (fh->vidq.read_buf) {
-		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-		kfree(fh->vidq.read_buf);
-	}
-
-	videobuf_mmap_free(&fh->vidq);
-
-	v4l2_prio_close(&dev->prio, fh->prio);
-
-	file->private_data = NULL;
-	kfree(fh);
-
-	return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-
-	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(i != fh->type)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO10)))) {
-		return -EBUSY;
-	}
-
-	return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-	int err, res;
-
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	res = cx25821_get_resource(fh, RESOURCE_VIDEO10);
-	err = videobuf_streamoff(get_queue(fh));
-	if (err < 0)
-		return err;
-	cx25821_res_free(dev, fh, res);
-	return 0;
-}
-
-static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
-				   unsigned long arg)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-	int command = 0;
-	struct upstream_user_struct *data_from_user;
-
-	data_from_user = (struct upstream_user_struct *)arg;
-
-	if (!data_from_user) {
-		printk
-		    ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
-		     __func__);
-		return 0;
-	}
-
-	command = data_from_user->command;
-
-	if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO) {
-		return 0;
-	}
-
-	dev->input_filename_ch2 = data_from_user->input_filename;
-	dev->input_audiofilename = data_from_user->input_filename;
-	dev->vid_stdname_ch2 = data_from_user->vid_stdname;
-	dev->pixel_format_ch2 = data_from_user->pixel_format;
-	dev->channel_select_ch2 = data_from_user->channel_select;
-	dev->command_ch2 = data_from_user->command;
-
-	switch (command) {
-	case UPSTREAM_START_VIDEO:
-		cx25821_start_upstream_video_ch2(dev, data_from_user);
-		break;
-
-	case UPSTREAM_STOP_VIDEO:
-		cx25821_stop_upstream_video_ch2(dev);
-		break;
-	}
-
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	dprintk(2, "%s()\n", __func__);
-	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-	if (0 != err)
-		return err;
-	fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-	fh->width = f->fmt.pix.width;
-	fh->height = f->fmt.pix.height;
-	fh->vidq.field = f->fmt.pix.field;
-	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-		fh->height, fh->vidq.field);
-	cx25821_call_all(dev, video, s_fmt, f);
-	return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	struct cx25821_fh *fh = priv;
-	return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	char name[32 + 2];
-
-	snprintf(name, sizeof(name), "%s/2", dev->name);
-	printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-	       dev->name);
-	cx25821_call_all(dev, core, log_status);
-	printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-	       dev->name);
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctl)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	return 0;
-}
-
-//exported stuff
-static const struct v4l2_file_operations video_fops = {
-	.owner = THIS_MODULE,
-	.open = video_open,
-	.release = video_release,
-	.read = video_read,
-	.poll = video_poll,
-	.mmap = cx25821_video_mmap,
-	.ioctl = video_ioctl_upstream10,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = cx25821_vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
-	.vidioc_querybuf = cx25821_vidioc_querybuf,
-	.vidioc_qbuf = cx25821_vidioc_qbuf,
-	.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-	.vidioc_s_std = cx25821_vidioc_s_std,
-	.vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-	.vidioc_cropcap = cx25821_vidioc_cropcap,
-	.vidioc_s_crop = cx25821_vidioc_s_crop,
-	.vidioc_g_crop = cx25821_vidioc_g_crop,
-	.vidioc_enum_input = cx25821_vidioc_enum_input,
-	.vidioc_g_input = cx25821_vidioc_g_input,
-	.vidioc_s_input = cx25821_vidioc_s_input,
-	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
-	.vidioc_streamon = vidioc_streamon,
-	.vidioc_streamoff = vidioc_streamoff,
-	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = cx25821_vidioc_g_priority,
-	.vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
-	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
-	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
-	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = cx25821_vidioc_g_register,
-	.vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template10 = {
-	.name = "cx25821-upstream10",
-	.fops = &video_fops,
-	.ioctl_ops = &video_ioctl_ops,
-	.tvnorms = CX25821_NORMS,
-	.current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-vidups9.c b/drivers/staging/cx25821/cx25821-vidups9.c
deleted file mode 100644
index 466e0f3..0000000
--- a/drivers/staging/cx25821/cx25821-vidups9.c
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- *  Driver for the Conexant CX25821 PCIe bridge
- *
- *  Copyright (C) 2009 Conexant Systems Inc.
- *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-	struct cx25821_buffer *buf =
-	    container_of(vb, struct cx25821_buffer, vb);
-	struct cx25821_buffer *prev;
-	struct cx25821_fh *fh = vq->priv_data;
-	struct cx25821_dev *dev = fh->dev;
-	struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH09];
-
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-	buf->risc.jmp[2] = cpu_to_le32(0);	/* bits 63-32 */
-
-	dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
-	if (!list_empty(&q->queued)) {
-		list_add_tail(&buf->vb.queue, &q->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
-			buf->vb.i);
-
-	} else if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx25821_start_video_dma(dev, q, buf,
-					&dev->sram_channels[SRAM_CH09]);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count = q->count++;
-		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-		dprintk(2,
-			"[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
-			buf, buf->vb.i, buf->count, q->count);
-	} else {
-		prev =
-		    list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
-		if (prev->vb.width == buf->vb.width
-		    && prev->vb.height == buf->vb.height
-		    && prev->fmt == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
-			/* 64 bit bits 63-32 */
-			prev->risc.jmp[2] = cpu_to_le32(0);
-			dprintk(2,
-				"[%p/%d] buffer_queue - append to active, buf->count=%d\n",
-				buf, buf->vb.i, buf->count);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &q->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
-				buf->vb.i);
-		}
-	}
-
-	if (list_empty(&q->active)) {
-		dprintk(2, "active queue empty!\n");
-	}
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
-	.buf_setup = cx25821_buffer_setup,
-	.buf_prepare = cx25821_buffer_prepare,
-	.buf_queue = buffer_queue,
-	.buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct cx25821_dev *dev = video_drvdata(file);
-	struct cx25821_fh *fh;
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-	printk("open dev=%s type=%s\n", video_device_node_name(vdev),
-		v4l2_type_names[type]);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-
-	lock_kernel();
-
-	file->private_data = fh;
-	fh->dev = dev;
-	fh->type = type;
-	fh->width = 720;
-
-	if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
-		fh->height = 576;
-	else
-		fh->height = 480;
-
-	dev->channel_opened = 8;
-	fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
-
-	v4l2_prio_open(&dev->prio, &fh->prio);
-
-	videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-			       &dev->pci->dev, &dev->slock,
-			       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			       V4L2_FIELD_INTERLACED,
-			       sizeof(struct cx25821_buffer), fh);
-
-	dprintk(1, "post videobuf_queue_init()\n");
-	unlock_kernel();
-
-	return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
-			  loff_t * ppos)
-{
-	struct cx25821_fh *fh = file->private_data;
-
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO9))
-			return -EBUSY;
-
-		return videobuf_read_one(&fh->vidq, data, count, ppos,
-					 file->f_flags & O_NONBLOCK);
-
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static unsigned int video_poll(struct file *file,
-			       struct poll_table_struct *wait)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_buffer *buf;
-
-	if (cx25821_res_check(fh, RESOURCE_VIDEO9)) {
-		/* streaming capture */
-		if (list_empty(&fh->vidq.stream))
-			return POLLERR;
-		buf = list_entry(fh->vidq.stream.next,
-				 struct cx25821_buffer, vb.stream);
-	} else {
-		/* read() capture */
-		buf = (struct cx25821_buffer *)fh->vidq.read_buf;
-		if (NULL == buf)
-			return POLLERR;
-	}
-
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-static int video_release(struct file *file)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-
-	//stop the risc engine and fifo
-	//cx_write(channel9->dma_ctl, 0);
-
-	/* stop video capture */
-	if (cx25821_res_check(fh, RESOURCE_VIDEO9)) {
-		videobuf_queue_cancel(&fh->vidq);
-		cx25821_res_free(dev, fh, RESOURCE_VIDEO9);
-	}
-
-	if (fh->vidq.read_buf) {
-		cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
-		kfree(fh->vidq.read_buf);
-	}
-
-	videobuf_mmap_free(&fh->vidq);
-
-	v4l2_prio_close(&dev->prio, fh->prio);
-
-	file->private_data = NULL;
-	kfree(fh);
-
-	return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-
-	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(i != fh->type)) {
-		return -EINVAL;
-	}
-
-	if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO9)))) {
-		return -EBUSY;
-	}
-
-	return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = fh->dev;
-	int err, res;
-
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	res = cx25821_get_resource(fh, RESOURCE_VIDEO9);
-	err = videobuf_streamoff(get_queue(fh));
-	if (err < 0)
-		return err;
-	cx25821_res_free(dev, fh, res);
-	return 0;
-}
-
-static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
-				  unsigned long arg)
-{
-	struct cx25821_fh *fh = file->private_data;
-	struct cx25821_dev *dev = fh->dev;
-	int command = 0;
-	struct upstream_user_struct *data_from_user;
-
-	data_from_user = (struct upstream_user_struct *)arg;
-
-	if (!data_from_user) {
-		printk
-		    ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
-		     __func__);
-		return 0;
-	}
-
-	command = data_from_user->command;
-
-	if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO) {
-		return 0;
-	}
-
-	dev->input_filename = data_from_user->input_filename;
-	dev->input_audiofilename = data_from_user->input_filename;
-	dev->vid_stdname = data_from_user->vid_stdname;
-	dev->pixel_format = data_from_user->pixel_format;
-	dev->channel_select = data_from_user->channel_select;
-	dev->command = data_from_user->command;
-
-	switch (command) {
-	case UPSTREAM_START_VIDEO:
-		cx25821_start_upstream_video_ch1(dev, data_from_user);
-		break;
-
-	case UPSTREAM_STOP_VIDEO:
-		cx25821_stop_upstream_video_ch1(dev);
-		break;
-	}
-
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct cx25821_fh *fh = priv;
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	int err;
-
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	dprintk(2, "%s()\n", __func__);
-	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
-	if (0 != err)
-		return err;
-	fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-	fh->width = f->fmt.pix.width;
-	fh->height = f->fmt.pix.height;
-	fh->vidq.field = f->fmt.pix.field;
-	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
-		fh->height, fh->vidq.field);
-	cx25821_call_all(dev, video, s_fmt, f);
-	return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	struct cx25821_fh *fh = priv;
-	return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-}
-static int vidioc_log_status(struct file *file, void *priv)
-{
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	char name[32 + 2];
-
-	snprintf(name, sizeof(name), "%s/2", dev->name);
-	printk(KERN_INFO "%s/2: ============  START LOG STATUS  ============\n",
-	       dev->name);
-	cx25821_call_all(dev, core, log_status);
-	printk(KERN_INFO "%s/2: =============  END LOG STATUS  =============\n",
-	       dev->name);
-	return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctl)
-{
-	struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-	struct cx25821_fh *fh = priv;
-	int err;
-	if (fh) {
-		err = v4l2_prio_check(&dev->prio, fh->prio);
-		if (0 != err)
-			return err;
-	}
-
-	return 0;
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
-	.owner = THIS_MODULE,
-	.open = video_open,
-	.release = video_release,
-	.read = video_read,
-	.poll = video_poll,
-	.mmap = cx25821_video_mmap,
-	.ioctl = video_ioctl_upstream9,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-	.vidioc_querycap = cx25821_vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs = cx25821_vidioc_reqbufs,
-	.vidioc_querybuf = cx25821_vidioc_querybuf,
-	.vidioc_qbuf = cx25821_vidioc_qbuf,
-	.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
-	.vidioc_s_std = cx25821_vidioc_s_std,
-	.vidioc_querystd = cx25821_vidioc_querystd,
-#endif
-	.vidioc_cropcap = cx25821_vidioc_cropcap,
-	.vidioc_s_crop = cx25821_vidioc_s_crop,
-	.vidioc_g_crop = cx25821_vidioc_g_crop,
-	.vidioc_enum_input = cx25821_vidioc_enum_input,
-	.vidioc_g_input = cx25821_vidioc_g_input,
-	.vidioc_s_input = cx25821_vidioc_s_input,
-	.vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
-	.vidioc_s_ctrl = vidioc_s_ctrl,
-	.vidioc_queryctrl = cx25821_vidioc_queryctrl,
-	.vidioc_streamon = vidioc_streamon,
-	.vidioc_streamoff = vidioc_streamoff,
-	.vidioc_log_status = vidioc_log_status,
-	.vidioc_g_priority = cx25821_vidioc_g_priority,
-	.vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	.vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
-	.vidioc_g_tuner = cx25821_vidioc_g_tuner,
-	.vidioc_s_tuner = cx25821_vidioc_s_tuner,
-	.vidioc_g_frequency = cx25821_vidioc_g_frequency,
-	.vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.vidioc_g_register = cx25821_vidioc_g_register,
-	.vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template9 = {
-	.name = "cx25821-upstream9",
-	.fops = &video_fops,
-	.ioctl_ops = &video_ioctl_ops,
-	.tvnorms = CX25821_NORMS,
-	.current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821.h b/drivers/staging/cx25821/cx25821.h
index cf2286d..1b628f6 100644
--- a/drivers/staging/cx25821/cx25821.h
+++ b/drivers/staging/cx25821/cx25821.h
@@ -61,7 +61,7 @@
 #define FALSE   0
 #define LINE_SIZE_D1    1440
 
-// Number of decoders and encoders
+/* Number of decoders and encoders */
 #define MAX_DECODERS            8
 #define MAX_ENCODERS            2
 #define QUAD_DECODERS           4
@@ -139,6 +139,7 @@
 	/* video capture */
 	struct cx25821_fmt *fmt;
 	unsigned int width, height;
+    int channel_id;
 
 	/* vbi capture */
 	struct videobuf_queue vidq;
@@ -236,13 +237,34 @@
 	struct sram_channel *channel;
 };
 
+struct cx25821_channel {
+       struct v4l2_prio_state prio;
+
+       int ctl_bright;
+       int ctl_contrast;
+       int ctl_hue;
+       int ctl_saturation;
+
+       struct cx25821_data timeout_data;
+
+       struct video_device *video_dev;
+       struct cx25821_dmaqueue vidq;
+
+       struct sram_channel *sram_channels;
+
+       struct mutex lock;
+       int resources;
+
+       int pixel_formats;
+       int use_cif_resolution;
+       int cif_width;
+};
+
 struct cx25821_dev {
 	struct list_head devlist;
 	atomic_t refcount;
 	struct v4l2_device v4l2_dev;
 
-	struct v4l2_prio_state prio;
-
 	/* pci stuff */
 	struct pci_dev *pci;
 	unsigned char pci_rev, pci_lat;
@@ -261,13 +283,12 @@
 	int nr;
 	struct mutex lock;
 
+    struct cx25821_channel channels[MAX_VID_CHANNEL_NUM];
+
 	/* board details */
 	unsigned int board;
 	char name[32];
 
-	/* sram configuration */
-	struct sram_channel *sram_channels;
-
 	/* Analog video */
 	u32 resources;
 	unsigned int input;
@@ -282,13 +303,6 @@
 	unsigned char videc_addr;
 	unsigned short _max_num_decoders;
 
-	int ctl_bright;
-	int ctl_contrast;
-	int ctl_hue;
-	int ctl_saturation;
-
-	struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM];
-
 	/* Analog Audio Upstream */
 	int _audio_is_running;
 	int _audiopixel_format;
@@ -297,7 +311,7 @@
 	int _audio_lines_count;
 	int _audioframe_count;
 	int _audio_upstream_channel_select;
-	int _last_index_irq;	//The last interrupt index processed.
+       int _last_index_irq;    /* The last interrupt index processed. */
 
 	__le32 *_risc_audio_jmp_addr;
 	__le32 *_risc_virt_start_addr;
@@ -313,12 +327,10 @@
 
 	/* V4l */
 	u32 freq;
-	struct video_device *video_dev[MAX_VID_CHANNEL_NUM];
 	struct video_device *vbi_dev;
 	struct video_device *radio_dev;
 	struct video_device *ioctl_dev;
 
-	struct cx25821_dmaqueue vidq[MAX_VID_CHANNEL_NUM];
 	spinlock_t slock;
 
 	/* Video Upstream */
@@ -401,9 +413,6 @@
 	int pixel_format;
 	int channel_select;
 	int command;
-	int pixel_formats[VID_CHANNEL_NUM];
-	int use_cif_resolution[VID_CHANNEL_NUM];
-	int cif_width[VID_CHANNEL_NUM];
 	int channel_opened;
 };
 
@@ -482,7 +491,7 @@
 	u32 fld_aud_fifo_en;
 	u32 fld_aud_risc_en;
 
-	//For Upstream Video
+       /* For Upstream Video */
 	u32 vid_fmt_ctl;
 	u32 vid_active_ctl1;
 	u32 vid_active_ctl2;
diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/lirc/Kconfig
new file mode 100644
index 0000000..968c2ade
--- /dev/null
+++ b/drivers/staging/lirc/Kconfig
@@ -0,0 +1,110 @@
+#
+# LIRC driver(s) configuration
+#
+menuconfig LIRC_STAGING
+	bool "Linux Infrared Remote Control IR receiver/transmitter drivers"
+	help
+	  Say Y here, and all supported Linux Infrared Remote Control IR and
+	  RF receiver and transmitter drivers will be displayed. When paired
+	  with a remote control and the lirc daemon, the receiver drivers
+	  allow control of your Linux system via remote control.
+
+if LIRC_STAGING
+
+config LIRC_BT829
+        tristate "BT829 based hardware"
+	depends on LIRC_STAGING
+	help
+	  Driver for the IR interface on BT829-based hardware
+
+config LIRC_ENE0100
+	tristate "ENE KB3924/ENE0100 CIR Port Reciever"
+	depends on LIRC_STAGING
+	help
+	  This is a driver for CIR port handled by ENE KB3924 embedded
+	  controller found on some notebooks.
+	  It appears on PNP list as ENE0100.
+
+config LIRC_I2C
+	tristate "I2C Based IR Receivers"
+	depends on LIRC_STAGING
+	help
+	  Driver for I2C-based IR receivers, such as those commonly
+	  found onboard Hauppauge PVR-150/250/350 video capture cards
+
+config LIRC_IGORPLUGUSB
+	tristate "Igor Cesko's USB IR Receiver"
+	depends on LIRC_STAGING && USB
+	help
+	  Driver for Igor Cesko's USB IR Receiver
+
+config LIRC_IMON
+	tristate "Legacy SoundGraph iMON Receiver and Display"
+	depends on LIRC_STAGING
+	help
+	  Driver for the original SoundGraph iMON IR Receiver and Display
+
+	  Current generation iMON devices use the input layer imon driver.
+
+config LIRC_IT87
+	tristate "ITE IT87XX CIR Port Receiver"
+	depends on LIRC_STAGING
+	help
+	  Driver for the ITE IT87xx IR Receiver
+
+config LIRC_ITE8709
+	tristate "ITE8709 CIR Port Receiver"
+	depends on LIRC_STAGING && PNP
+	help
+	  Driver for the ITE8709 IR Receiver
+
+config LIRC_PARALLEL
+	tristate "Homebrew Parallel Port Receiver"
+	depends on LIRC_STAGING && !SMP
+	help
+	  Driver for Homebrew Parallel Port Receivers
+
+config LIRC_SASEM
+	tristate "Sasem USB IR Remote"
+	depends on LIRC_STAGING
+	help
+	  Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module
+
+config LIRC_SERIAL
+	tristate "Homebrew Serial Port Receiver"
+	depends on LIRC_STAGING
+	help
+	  Driver for Homebrew Serial Port Receivers
+
+config LIRC_SERIAL_TRANSMITTER
+	bool "Serial Port Transmitter"
+	default y
+	depends on LIRC_SERIAL
+	help
+	  Serial Port Transmitter support
+
+config LIRC_SIR
+	tristate "Built-in SIR IrDA port"
+	depends on LIRC_STAGING
+	help
+	  Driver for the SIR IrDA port
+
+config LIRC_STREAMZAP
+	tristate "Streamzap PC Receiver"
+	depends on LIRC_STAGING
+	help
+	  Driver for the Streamzap PC Receiver
+
+config LIRC_TTUSBIR
+	tristate "Technotrend USB IR Receiver"
+	depends on LIRC_STAGING && USB
+	help
+	  Driver for the Technotrend USB IR Receiver
+
+config LIRC_ZILOG
+	tristate "Zilog/Hauppauge IR Transmitter"
+	depends on LIRC_STAGING
+	help
+	  Driver for the Zilog/Hauppauge IR Transmitter, found on
+	  PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards
+endif
diff --git a/drivers/staging/lirc/Makefile b/drivers/staging/lirc/Makefile
new file mode 100644
index 0000000..a019182
--- /dev/null
+++ b/drivers/staging/lirc/Makefile
@@ -0,0 +1,19 @@
+# Makefile for the lirc drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_LIRC_BT829)	+= lirc_bt829.o
+obj-$(CONFIG_LIRC_ENE0100)	+= lirc_ene0100.o
+obj-$(CONFIG_LIRC_I2C)		+= lirc_i2c.o
+obj-$(CONFIG_LIRC_IGORPLUGUSB)	+= lirc_igorplugusb.o
+obj-$(CONFIG_LIRC_IMON)		+= lirc_imon.o
+obj-$(CONFIG_LIRC_IT87)		+= lirc_it87.o
+obj-$(CONFIG_LIRC_ITE8709)	+= lirc_ite8709.o
+obj-$(CONFIG_LIRC_PARALLEL)	+= lirc_parallel.o
+obj-$(CONFIG_LIRC_SASEM)	+= lirc_sasem.o
+obj-$(CONFIG_LIRC_SERIAL)	+= lirc_serial.o
+obj-$(CONFIG_LIRC_SIR)		+= lirc_sir.o
+obj-$(CONFIG_LIRC_STREAMZAP)	+= lirc_streamzap.o
+obj-$(CONFIG_LIRC_TTUSBIR)	+= lirc_ttusbir.o
+obj-$(CONFIG_LIRC_ZILOG)	+= lirc_zilog.o
diff --git a/drivers/staging/lirc/TODO b/drivers/staging/lirc/TODO
new file mode 100644
index 0000000..b6cb593
--- /dev/null
+++ b/drivers/staging/lirc/TODO
@@ -0,0 +1,8 @@
+- All drivers should either be ported to ir-core, or dropped entirely
+  (see drivers/media/IR/mceusb.c vs. lirc_mceusb.c in lirc cvs for an
+  example of a previously completed port).
+
+Please send patches to:
+Jarod Wilson <jarod@wilsonet.com>
+Greg Kroah-Hartman <greg@kroah.com>
+
diff --git a/drivers/staging/lirc/TODO.lirc_i2c b/drivers/staging/lirc/TODO.lirc_i2c
new file mode 100644
index 0000000..1f0a6ff
--- /dev/null
+++ b/drivers/staging/lirc/TODO.lirc_i2c
@@ -0,0 +1,3 @@
+lirc_i2c provides support for some drivers that have already a RC
+driver under drivers/media/video. It should be integrated into those
+drivers, in special with drivers/media/video/ir-kbd-i2c.c.
diff --git a/drivers/staging/lirc/lirc_bt829.c b/drivers/staging/lirc/lirc_bt829.c
new file mode 100644
index 0000000..3388102
--- /dev/null
+++ b/drivers/staging/lirc/lirc_bt829.c
@@ -0,0 +1,383 @@
+/*
+ * Remote control driver for the TV-card based on bt829
+ *
+ *  by Leonid Froenchenko <lfroen@galileo.co.il>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/threads.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include <media/lirc_dev.h>
+
+static int poll_main(void);
+static int atir_init_start(void);
+
+static void write_index(unsigned char index, unsigned int value);
+static unsigned int read_index(unsigned char index);
+
+static void do_i2c_start(void);
+static void do_i2c_stop(void);
+
+static void seems_wr_byte(unsigned char al);
+static unsigned char seems_rd_byte(void);
+
+static unsigned int read_index(unsigned char al);
+static void write_index(unsigned char ah, unsigned int edx);
+
+static void cycle_delay(int cycle);
+
+static void do_set_bits(unsigned char bl);
+static unsigned char do_get_bits(void);
+
+#define DATA_PCI_OFF 0x7FFC00
+#define WAIT_CYCLE   20
+
+#define DRIVER_NAME "lirc_bt829"
+
+static int debug;
+#define dprintk(fmt, args...)						 \
+	do {								 \
+		if (debug)						 \
+			printk(KERN_DEBUG DRIVER_NAME ": "fmt, ## args); \
+	} while (0)
+
+static int atir_minor;
+static unsigned long pci_addr_phys;
+static unsigned char *pci_addr_lin;
+
+static struct lirc_driver atir_driver;
+
+static struct pci_dev *do_pci_probe(void)
+{
+	struct pci_dev *my_dev;
+	my_dev = pci_get_device(PCI_VENDOR_ID_ATI,
+				PCI_DEVICE_ID_ATI_264VT, NULL);
+	if (my_dev) {
+		printk(KERN_ERR DRIVER_NAME ": Using device: %s\n",
+		       pci_name(my_dev));
+		pci_addr_phys = 0;
+		if (my_dev->resource[0].flags & IORESOURCE_MEM) {
+			pci_addr_phys = my_dev->resource[0].start;
+			printk(KERN_INFO DRIVER_NAME ": memory at 0x%08X\n",
+			       (unsigned int)pci_addr_phys);
+		}
+		if (pci_addr_phys == 0) {
+			printk(KERN_ERR DRIVER_NAME ": no memory resource ?\n");
+			return NULL;
+		}
+	} else {
+		printk(KERN_ERR DRIVER_NAME ": pci_probe failed\n");
+		return NULL;
+	}
+	return my_dev;
+}
+
+static int atir_add_to_buf(void *data, struct lirc_buffer *buf)
+{
+	unsigned char key;
+	int status;
+	status = poll_main();
+	key = (status >> 8) & 0xFF;
+	if (status & 0xFF) {
+		dprintk("reading key %02X\n", key);
+		lirc_buffer_write(buf, &key);
+		return 0;
+	}
+	return -ENODATA;
+}
+
+static int atir_set_use_inc(void *data)
+{
+	dprintk("driver is opened\n");
+	return 0;
+}
+
+static void atir_set_use_dec(void *data)
+{
+	dprintk("driver is closed\n");
+}
+
+int init_module(void)
+{
+	struct pci_dev *pdev;
+
+	pdev = do_pci_probe();
+	if (pdev == NULL)
+		return 1;
+
+	if (!atir_init_start())
+		return 1;
+
+	strcpy(atir_driver.name, "ATIR");
+	atir_driver.minor       = -1;
+	atir_driver.code_length = 8;
+	atir_driver.sample_rate = 10;
+	atir_driver.data        = 0;
+	atir_driver.add_to_buf  = atir_add_to_buf;
+	atir_driver.set_use_inc = atir_set_use_inc;
+	atir_driver.set_use_dec = atir_set_use_dec;
+	atir_driver.dev         = &pdev->dev;
+	atir_driver.owner       = THIS_MODULE;
+
+	atir_minor = lirc_register_driver(&atir_driver);
+	if (atir_minor < 0) {
+		printk(KERN_ERR DRIVER_NAME ": failed to register driver!\n");
+		return atir_minor;
+	}
+	dprintk("driver is registered on minor %d\n", atir_minor);
+
+	return 0;
+}
+
+
+void cleanup_module(void)
+{
+	lirc_unregister_driver(atir_minor);
+}
+
+
+static int atir_init_start(void)
+{
+	pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400);
+	if (pci_addr_lin == 0) {
+		printk(KERN_INFO DRIVER_NAME ": pci mem must be mapped\n");
+		return 0;
+	}
+	return 1;
+}
+
+static void cycle_delay(int cycle)
+{
+	udelay(WAIT_CYCLE*cycle);
+}
+
+
+static int poll_main()
+{
+	unsigned char status_high, status_low;
+
+	do_i2c_start();
+
+	seems_wr_byte(0xAA);
+	seems_wr_byte(0x01);
+
+	do_i2c_start();
+
+	seems_wr_byte(0xAB);
+
+	status_low = seems_rd_byte();
+	status_high = seems_rd_byte();
+
+	do_i2c_stop();
+
+	return (status_high << 8) | status_low;
+}
+
+static void do_i2c_start(void)
+{
+	do_set_bits(3);
+	cycle_delay(4);
+
+	do_set_bits(1);
+	cycle_delay(7);
+
+	do_set_bits(0);
+	cycle_delay(2);
+}
+
+static void do_i2c_stop(void)
+{
+	unsigned char bits;
+	bits =  do_get_bits() & 0xFD;
+	do_set_bits(bits);
+	cycle_delay(1);
+
+	bits |= 1;
+	do_set_bits(bits);
+	cycle_delay(2);
+
+	bits |= 2;
+	do_set_bits(bits);
+	bits = 3;
+	do_set_bits(bits);
+	cycle_delay(2);
+}
+
+static void seems_wr_byte(unsigned char value)
+{
+	int i;
+	unsigned char reg;
+
+	reg = do_get_bits();
+	for (i = 0; i < 8; i++) {
+		if (value & 0x80)
+			reg |= 0x02;
+		else
+			reg &= 0xFD;
+
+		do_set_bits(reg);
+		cycle_delay(1);
+
+		reg |= 1;
+		do_set_bits(reg);
+		cycle_delay(1);
+
+		reg &= 0xFE;
+		do_set_bits(reg);
+		cycle_delay(1);
+		value <<= 1;
+	}
+	cycle_delay(2);
+
+	reg |= 2;
+	do_set_bits(reg);
+
+	reg |= 1;
+	do_set_bits(reg);
+
+	cycle_delay(1);
+	do_get_bits();
+
+	reg &= 0xFE;
+	do_set_bits(reg);
+	cycle_delay(3);
+}
+
+static unsigned char seems_rd_byte(void)
+{
+	int i;
+	int rd_byte;
+	unsigned char bits_2, bits_1;
+
+	bits_1 = do_get_bits() | 2;
+	do_set_bits(bits_1);
+
+	rd_byte = 0;
+	for (i = 0; i < 8; i++) {
+		bits_1 &= 0xFE;
+		do_set_bits(bits_1);
+		cycle_delay(2);
+
+		bits_1 |= 1;
+		do_set_bits(bits_1);
+		cycle_delay(1);
+
+		bits_2 = do_get_bits();
+		if (bits_2 & 2)
+			rd_byte |= 1;
+
+		rd_byte <<= 1;
+	}
+
+	bits_1 = 0;
+	if (bits_2 == 0)
+		bits_1 |= 2;
+
+	do_set_bits(bits_1);
+	cycle_delay(2);
+
+	bits_1 |= 1;
+	do_set_bits(bits_1);
+	cycle_delay(3);
+
+	bits_1 &= 0xFE;
+	do_set_bits(bits_1);
+	cycle_delay(2);
+
+	rd_byte >>= 1;
+	rd_byte &= 0xFF;
+	return rd_byte;
+}
+
+static void do_set_bits(unsigned char new_bits)
+{
+	int reg_val;
+	reg_val = read_index(0x34);
+	if (new_bits & 2) {
+		reg_val &= 0xFFFFFFDF;
+		reg_val |= 1;
+	} else {
+		reg_val &= 0xFFFFFFFE;
+		reg_val |= 0x20;
+	}
+	reg_val |= 0x10;
+	write_index(0x34, reg_val);
+
+	reg_val = read_index(0x31);
+	if (new_bits & 1)
+		reg_val |= 0x1000000;
+	else
+		reg_val &= 0xFEFFFFFF;
+
+	reg_val |= 0x8000000;
+	write_index(0x31, reg_val);
+}
+
+static unsigned char do_get_bits(void)
+{
+	unsigned char bits;
+	int reg_val;
+
+	reg_val = read_index(0x34);
+	reg_val |= 0x10;
+	reg_val &= 0xFFFFFFDF;
+	write_index(0x34, reg_val);
+
+	reg_val = read_index(0x34);
+	bits = 0;
+	if (reg_val & 8)
+		bits |= 2;
+	else
+		bits &= 0xFD;
+
+	reg_val = read_index(0x31);
+	if (reg_val & 0x1000000)
+		bits |= 1;
+	else
+		bits &= 0xFE;
+
+	return bits;
+}
+
+static unsigned int read_index(unsigned char index)
+{
+	unsigned char *addr;
+	unsigned int value;
+	/*  addr = pci_addr_lin + DATA_PCI_OFF + ((index & 0xFF) << 2); */
+	addr = pci_addr_lin + ((index & 0xFF) << 2);
+	value = readl(addr);
+	return value;
+}
+
+static void write_index(unsigned char index, unsigned int reg_val)
+{
+	unsigned char *addr;
+	addr = pci_addr_lin + ((index & 0xFF) << 2);
+	writel(reg_val, addr);
+}
+
+MODULE_AUTHOR("Froenchenko Leonid");
+MODULE_DESCRIPTION("IR remote driver for bt829 based TV cards");
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/lirc/lirc_ene0100.c b/drivers/staging/lirc/lirc_ene0100.c
new file mode 100644
index 0000000..a152c52
--- /dev/null
+++ b/drivers/staging/lirc/lirc_ene0100.c
@@ -0,0 +1,646 @@
+/*
+ * driver for ENE KB3926 B/C/D CIR (also known as ENE0100)
+ *
+ * Copyright (C) 2009 Maxim Levitsky <maximlevitsky@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pnp.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include "lirc_ene0100.h"
+
+static int sample_period = 75;
+static int enable_idle = 1;
+static int enable_learning;
+
+static void ene_set_idle(struct ene_device *dev, int idle);
+static void ene_set_inputs(struct ene_device *dev, int enable);
+
+/* read a hardware register */
+static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg)
+{
+	outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+	outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+	return inb(dev->hw_io + ENE_IO);
+}
+
+/* write a hardware register */
+static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value)
+{
+	outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+	outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+	outb(value, dev->hw_io + ENE_IO);
+}
+
+/* change specific bits in hardware register */
+static void ene_hw_write_reg_mask(struct ene_device *dev,
+				  u16 reg, u8 value, u8 mask)
+{
+	u8 regvalue;
+
+	outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+	outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+
+	regvalue = inb(dev->hw_io + ENE_IO) & ~mask;
+	regvalue |= (value & mask);
+	outb(regvalue, dev->hw_io + ENE_IO);
+}
+
+/* read irq status and ack it */
+static int ene_hw_irq_status(struct ene_device *dev, int *buffer_pointer)
+{
+	u8 irq_status;
+	u8 fw_flags1, fw_flags2;
+
+	fw_flags2 = ene_hw_read_reg(dev, ENE_FW2);
+
+	if (buffer_pointer)
+		*buffer_pointer = 4 * (fw_flags2 & ENE_FW2_BUF_HIGH);
+
+	if (dev->hw_revision < ENE_HW_C) {
+		irq_status = ene_hw_read_reg(dev, ENEB_IRQ_STATUS);
+
+		if (!(irq_status & ENEB_IRQ_STATUS_IR))
+			return 0;
+		ene_hw_write_reg(dev, ENEB_IRQ_STATUS,
+				 irq_status & ~ENEB_IRQ_STATUS_IR);
+
+		/* rev B support only recieving */
+		return ENE_IRQ_RX;
+	}
+
+	irq_status = ene_hw_read_reg(dev, ENEC_IRQ);
+
+	if (!(irq_status & ENEC_IRQ_STATUS))
+		return 0;
+
+	/* original driver does that twice - a workaround ? */
+	ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS);
+	ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS);
+
+	/* clear unknown flag in F8F9 */
+	if (fw_flags2 & ENE_FW2_IRQ_CLR)
+		ene_hw_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_IRQ_CLR);
+
+	/* check if this is a TX interrupt */
+	fw_flags1 = ene_hw_read_reg(dev, ENE_FW1);
+
+	if (fw_flags1 & ENE_FW1_TXIRQ) {
+		ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ);
+		return ENE_IRQ_TX;
+	} else
+		return ENE_IRQ_RX;
+}
+
+static int ene_hw_detect(struct ene_device *dev)
+{
+	u8 chip_major, chip_minor;
+	u8 hw_revision, old_ver;
+	u8 tmp;
+	u8 fw_capabilities;
+
+	tmp = ene_hw_read_reg(dev, ENE_HW_UNK);
+	ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR);
+
+	chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR);
+	chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR);
+
+	ene_hw_write_reg(dev, ENE_HW_UNK, tmp);
+	hw_revision = ene_hw_read_reg(dev, ENE_HW_VERSION);
+	old_ver = ene_hw_read_reg(dev, ENE_HW_VER_OLD);
+
+	if (hw_revision == 0xFF) {
+
+		ene_printk(KERN_WARNING, "device seems to be disabled\n");
+		ene_printk(KERN_WARNING,
+			"send a mail to lirc-list@lists.sourceforge.net\n");
+		ene_printk(KERN_WARNING, "please attach output of acpidump\n");
+
+		return -ENODEV;
+	}
+
+	if (chip_major == 0x33) {
+		ene_printk(KERN_WARNING, "chips 0x33xx aren't supported yet\n");
+		return -ENODEV;
+	}
+
+	if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) {
+		dev->hw_revision = ENE_HW_C;
+		ene_printk(KERN_WARNING,
+		       "KB3926C detected, driver support is not complete!\n");
+
+	} else if (old_ver == 0x24 && hw_revision == 0xC0) {
+		dev->hw_revision = ENE_HW_B;
+		ene_printk(KERN_NOTICE, "KB3926B detected\n");
+	} else {
+		dev->hw_revision = ENE_HW_D;
+		ene_printk(KERN_WARNING,
+			"unknown ENE chip detected, assuming KB3926D\n");
+		ene_printk(KERN_WARNING, "driver support incomplete");
+
+	}
+
+	ene_printk(KERN_DEBUG, "chip is 0x%02x%02x - 0x%02x, 0x%02x\n",
+		chip_major, chip_minor, old_ver, hw_revision);
+
+
+	/* detect features hardware supports */
+
+	if (dev->hw_revision < ENE_HW_C)
+		return 0;
+
+	fw_capabilities = ene_hw_read_reg(dev, ENE_FW2);
+
+	dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN;
+	dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING;
+
+	dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable &&
+	    fw_capabilities & ENE_FW2_FAN_AS_NRML_IN;
+
+	ene_printk(KERN_NOTICE, "hardware features:\n");
+	ene_printk(KERN_NOTICE,
+		"learning and tx %s, gpio40_learn %s, fan_in %s\n",
+	       dev->hw_learning_and_tx_capable ? "on" : "off",
+	       dev->hw_gpio40_learning ? "on" : "off",
+	       dev->hw_fan_as_normal_input ? "on" : "off");
+
+	if (!dev->hw_learning_and_tx_capable && enable_learning)
+		enable_learning = 0;
+
+	if (dev->hw_learning_and_tx_capable) {
+		ene_printk(KERN_WARNING,
+		"Device supports transmitting, but the driver doesn't\n");
+		ene_printk(KERN_WARNING,
+		"due to lack of hardware to test against.\n");
+		ene_printk(KERN_WARNING,
+		"Send a mail to: lirc-list@lists.sourceforge.net\n");
+	}
+	return 0;
+}
+
+/* hardware initialization */
+static int ene_hw_init(void *data)
+{
+	u8 reg_value;
+	struct ene_device *dev = (struct ene_device *)data;
+	dev->in_use = 1;
+
+	if (dev->hw_revision < ENE_HW_C) {
+		ene_hw_write_reg(dev, ENEB_IRQ, dev->irq << 1);
+		ene_hw_write_reg(dev, ENEB_IRQ_UNK1, 0x01);
+	} else {
+		reg_value = ene_hw_read_reg(dev, ENEC_IRQ) & 0xF0;
+		reg_value |= ENEC_IRQ_UNK_EN;
+		reg_value &= ~ENEC_IRQ_STATUS;
+		reg_value |= (dev->irq & ENEC_IRQ_MASK);
+		ene_hw_write_reg(dev, ENEC_IRQ, reg_value);
+		ene_hw_write_reg(dev, ENE_TX_UNK1, 0x63);
+	}
+
+	ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00);
+	ene_set_inputs(dev, enable_learning);
+
+	/* set sampling period */
+	ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period);
+
+	/* ack any pending irqs - just in case */
+	ene_hw_irq_status(dev, NULL);
+
+	/* enter idle mode */
+	ene_set_idle(dev, 1);
+
+	/* enable firmware bits */
+	ene_hw_write_reg_mask(dev, ENE_FW1,
+			      ENE_FW1_ENABLE | ENE_FW1_IRQ,
+			      ENE_FW1_ENABLE | ENE_FW1_IRQ);
+	/* clear stats */
+	dev->sample = 0;
+	return 0;
+}
+
+/* this enables gpio40 signal, used if connected to wide band input*/
+static void ene_enable_gpio40(struct ene_device *dev, int enable)
+{
+	ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, enable ?
+			      0 : ENE_CIR_CONF2_GPIO40DIS,
+			      ENE_CIR_CONF2_GPIO40DIS);
+}
+
+/* this enables the classic sampler */
+static void ene_enable_normal_recieve(struct ene_device *dev, int enable)
+{
+	ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_ADC_ON : 0);
+}
+
+/* this enables recieve via fan input */
+static void ene_enable_fan_recieve(struct ene_device *dev, int enable)
+{
+	if (!enable)
+		ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0);
+	else {
+		ene_hw_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN);
+		ene_hw_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN);
+	}
+	dev->fan_input_inuse = enable;
+}
+
+/* determine which input to use*/
+static void ene_set_inputs(struct ene_device *dev, int learning_enable)
+{
+	ene_enable_normal_recieve(dev, 1);
+
+	/* old hardware doesn't support learning mode for sure */
+	if (dev->hw_revision <= ENE_HW_B)
+		return;
+
+	/* reciever not learning capable, still set gpio40 correctly */
+	if (!dev->hw_learning_and_tx_capable) {
+		ene_enable_gpio40(dev, !dev->hw_gpio40_learning);
+		return;
+	}
+
+	/* enable learning mode */
+	if (learning_enable) {
+		ene_enable_gpio40(dev, dev->hw_gpio40_learning);
+
+		/* fan input is not used for learning */
+		if (dev->hw_fan_as_normal_input)
+			ene_enable_fan_recieve(dev, 0);
+
+	/* disable learning mode */
+	} else {
+		if (dev->hw_fan_as_normal_input) {
+			ene_enable_fan_recieve(dev, 1);
+			ene_enable_normal_recieve(dev, 0);
+		} else
+			ene_enable_gpio40(dev, !dev->hw_gpio40_learning);
+	}
+
+	/* set few additional settings for this mode */
+	ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_enable ?
+			      ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1);
+
+	ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_enable ?
+			      ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2);
+}
+
+/* deinitialization */
+static void ene_hw_deinit(void *data)
+{
+	struct ene_device *dev = (struct ene_device *)data;
+
+	/* disable samplers */
+	ene_enable_normal_recieve(dev, 0);
+
+	if (dev->hw_fan_as_normal_input)
+		ene_enable_fan_recieve(dev, 0);
+
+	/* disable hardware IRQ and firmware flag */
+	ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ);
+
+	ene_set_idle(dev, 1);
+	dev->in_use = 0;
+}
+
+/*  sends current sample to userspace */
+static void send_sample(struct ene_device *dev)
+{
+	int value = abs(dev->sample) & PULSE_MASK;
+
+	if (dev->sample > 0)
+		value |= PULSE_BIT;
+
+	if (!lirc_buffer_full(dev->lirc_driver->rbuf)) {
+		lirc_buffer_write(dev->lirc_driver->rbuf, (void *)&value);
+		wake_up(&dev->lirc_driver->rbuf->wait_poll);
+	}
+	dev->sample = 0;
+}
+
+/*  this updates current sample */
+static void update_sample(struct ene_device *dev, int sample)
+{
+	if (!dev->sample)
+		dev->sample = sample;
+	else if (same_sign(dev->sample, sample))
+		dev->sample += sample;
+	else {
+		send_sample(dev);
+		dev->sample = sample;
+	}
+}
+
+/* enable or disable idle mode */
+static void ene_set_idle(struct ene_device *dev, int idle)
+{
+	struct timeval now;
+	int disable = idle && enable_idle && (dev->hw_revision < ENE_HW_C);
+
+	ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD,
+			      disable ? 0 : ENE_CIR_SAMPLE_OVERFLOW,
+			      ENE_CIR_SAMPLE_OVERFLOW);
+	dev->idle = idle;
+
+	/* remember when we have entered the idle mode */
+	if (idle) {
+		do_gettimeofday(&dev->gap_start);
+		return;
+	}
+
+	/* send the gap between keypresses now */
+	do_gettimeofday(&now);
+
+	if (now.tv_sec - dev->gap_start.tv_sec > 16)
+		dev->sample = space(PULSE_MASK);
+	else
+		dev->sample = dev->sample +
+		    space(1000000ull * (now.tv_sec - dev->gap_start.tv_sec))
+		    + space(now.tv_usec - dev->gap_start.tv_usec);
+
+	if (abs(dev->sample) > PULSE_MASK)
+		dev->sample = space(PULSE_MASK);
+	send_sample(dev);
+}
+
+/* interrupt handler */
+static irqreturn_t ene_hw_irq(int irq, void *data)
+{
+	u16 hw_value;
+	int i, hw_sample;
+	int space;
+	int buffer_pointer;
+	int irq_status;
+
+	struct ene_device *dev = (struct ene_device *)data;
+	irq_status = ene_hw_irq_status(dev, &buffer_pointer);
+
+	if (!irq_status)
+		return IRQ_NONE;
+
+	/* TODO: only RX for now */
+	if (irq_status == ENE_IRQ_TX)
+		return IRQ_HANDLED;
+
+	for (i = 0; i < ENE_SAMPLES_SIZE; i++) {
+
+		hw_value = ene_hw_read_reg(dev,
+				ENE_SAMPLE_BUFFER + buffer_pointer + i);
+
+		if (dev->fan_input_inuse) {
+			/* read high part of the sample */
+			hw_value |= ene_hw_read_reg(dev,
+			    ENE_SAMPLE_BUFFER_FAN + buffer_pointer + i) << 8;
+
+			/* test for _space_ bit */
+			space = !(hw_value & ENE_FAN_SMPL_PULS_MSK);
+
+			/* clear space bit, and other unused bits */
+			hw_value &= ENE_FAN_VALUE_MASK;
+			hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN;
+
+		} else {
+			space = hw_value & ENE_SAMPLE_SPC_MASK;
+			hw_value &= ENE_SAMPLE_VALUE_MASK;
+			hw_sample = hw_value * sample_period;
+		}
+
+		/* no more data */
+		if (!(hw_value))
+			break;
+
+		if (space)
+			hw_sample *= -1;
+
+		/* overflow sample recieved, handle it */
+
+		if (!dev->fan_input_inuse && hw_value == ENE_SAMPLE_OVERFLOW) {
+
+			if (dev->idle)
+				continue;
+
+			if (dev->sample > 0 || abs(dev->sample) <= ENE_MAXGAP)
+				update_sample(dev, hw_sample);
+			else
+				ene_set_idle(dev, 1);
+
+			continue;
+		}
+
+		/* normal first sample recieved */
+		if (!dev->fan_input_inuse && dev->idle) {
+			ene_set_idle(dev, 0);
+
+			/* discard first recieved value, its random
+			   since its the time signal was off before
+			   first pulse if idle mode is enabled, HW
+			   does that for us */
+
+			if (!enable_idle)
+				continue;
+		}
+		update_sample(dev, hw_sample);
+		send_sample(dev);
+	}
+	return IRQ_HANDLED;
+}
+
+static int ene_probe(struct pnp_dev *pnp_dev,
+		     const struct pnp_device_id *dev_id)
+{
+	struct ene_device *dev;
+	struct lirc_driver *lirc_driver;
+	int error = -ENOMEM;
+
+	dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL);
+
+	if (!dev)
+		goto err1;
+
+	dev->pnp_dev = pnp_dev;
+	pnp_set_drvdata(pnp_dev, dev);
+
+
+	/* prepare lirc interface */
+	error = -ENOMEM;
+	lirc_driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+
+	if (!lirc_driver)
+		goto err2;
+
+	dev->lirc_driver = lirc_driver;
+
+	strcpy(lirc_driver->name, ENE_DRIVER_NAME);
+	lirc_driver->minor = -1;
+	lirc_driver->code_length = sizeof(int) * 8;
+	lirc_driver->features = LIRC_CAN_REC_MODE2;
+	lirc_driver->data = dev;
+	lirc_driver->set_use_inc = ene_hw_init;
+	lirc_driver->set_use_dec = ene_hw_deinit;
+	lirc_driver->dev = &pnp_dev->dev;
+	lirc_driver->owner = THIS_MODULE;
+
+	lirc_driver->rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+
+	if (!lirc_driver->rbuf)
+		goto err3;
+
+	if (lirc_buffer_init(lirc_driver->rbuf, sizeof(int), sizeof(int) * 256))
+		goto err4;
+
+	error = -ENODEV;
+	if (lirc_register_driver(lirc_driver))
+		goto err5;
+
+	/* validate resources */
+	if (!pnp_port_valid(pnp_dev, 0) ||
+	    pnp_port_len(pnp_dev, 0) < ENE_MAX_IO)
+		goto err6;
+
+	if (!pnp_irq_valid(pnp_dev, 0))
+		goto err6;
+
+	dev->hw_io = pnp_port_start(pnp_dev, 0);
+	dev->irq = pnp_irq(pnp_dev, 0);
+
+	/* claim the resources */
+	error = -EBUSY;
+	if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME))
+		goto err6;
+
+	if (request_irq(dev->irq, ene_hw_irq,
+			IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev))
+		goto err7;
+
+	/* detect hardware version and features */
+	error = ene_hw_detect(dev);
+	if (error)
+		goto err8;
+
+	ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n");
+	return 0;
+
+err8:
+	free_irq(dev->irq, dev);
+err7:
+	release_region(dev->hw_io, ENE_MAX_IO);
+err6:
+	lirc_unregister_driver(lirc_driver->minor);
+err5:
+	lirc_buffer_free(lirc_driver->rbuf);
+err4:
+	kfree(lirc_driver->rbuf);
+err3:
+	kfree(lirc_driver);
+err2:
+	kfree(dev);
+err1:
+	return error;
+}
+
+static void ene_remove(struct pnp_dev *pnp_dev)
+{
+	struct ene_device *dev = pnp_get_drvdata(pnp_dev);
+	ene_hw_deinit(dev);
+	free_irq(dev->irq, dev);
+	release_region(dev->hw_io, ENE_MAX_IO);
+	lirc_unregister_driver(dev->lirc_driver->minor);
+	lirc_buffer_free(dev->lirc_driver->rbuf);
+	kfree(dev->lirc_driver);
+	kfree(dev);
+}
+
+#ifdef CONFIG_PM
+
+/* TODO: make 'wake on IR' configurable and add .shutdown */
+/* currently impossible due to lack of kernel support */
+
+static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
+{
+	struct ene_device *dev = pnp_get_drvdata(pnp_dev);
+	ene_hw_write_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, ENE_FW1_WAKE);
+	return 0;
+}
+
+static int ene_resume(struct pnp_dev *pnp_dev)
+{
+	struct ene_device *dev = pnp_get_drvdata(pnp_dev);
+	if (dev->in_use)
+		ene_hw_init(dev);
+
+	ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_WAKE);
+	return 0;
+}
+
+#endif
+
+static const struct pnp_device_id ene_ids[] = {
+	{.id = "ENE0100",},
+	{},
+};
+
+static struct pnp_driver ene_driver = {
+	.name = ENE_DRIVER_NAME,
+	.id_table = ene_ids,
+	.flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
+
+	.probe = ene_probe,
+	.remove = __devexit_p(ene_remove),
+
+#ifdef CONFIG_PM
+	.suspend = ene_suspend,
+	.resume = ene_resume,
+#endif
+};
+
+static int __init ene_init(void)
+{
+	if (sample_period < 5) {
+		ene_printk(KERN_ERR, "sample period must be at\n");
+		ene_printk(KERN_ERR, "least 5 us, (at least 30 recommended)\n");
+		return -EINVAL;
+	}
+	return pnp_register_driver(&ene_driver);
+}
+
+static void ene_exit(void)
+{
+	pnp_unregister_driver(&ene_driver);
+}
+
+module_param(sample_period, int, S_IRUGO);
+MODULE_PARM_DESC(sample_period, "Hardware sample period (75 us default)");
+
+module_param(enable_idle, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(enable_idle,
+	"Enables turning off signal sampling after long inactivity time; "
+	"if disabled might help detecting input signal (default: enabled)");
+
+module_param(enable_learning, bool, S_IRUGO);
+MODULE_PARM_DESC(enable_learning, "Use wide band (learning) reciever");
+
+MODULE_DEVICE_TABLE(pnp, ene_ids);
+MODULE_DESCRIPTION
+    ("LIRC driver for KB3926B/KB3926C/KB3926D (aka ENE0100) CIR port");
+MODULE_AUTHOR("Maxim Levitsky");
+MODULE_LICENSE("GPL");
+
+module_init(ene_init);
+module_exit(ene_exit);
diff --git a/drivers/staging/lirc/lirc_ene0100.h b/drivers/staging/lirc/lirc_ene0100.h
new file mode 100644
index 0000000..776b693
--- /dev/null
+++ b/drivers/staging/lirc/lirc_ene0100.h
@@ -0,0 +1,169 @@
+/*
+ * driver for ENE KB3926 B/C/D CIR (also known as ENE0100)
+ *
+ * Copyright (C) 2009 Maxim Levitsky <maximlevitsky@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+/* hardware address */
+#define ENE_STATUS		0	 /* hardware status - unused */
+#define ENE_ADDR_HI		1	 /* hi byte of register address */
+#define ENE_ADDR_LO		2	 /* low byte of register address */
+#define ENE_IO			3	 /* read/write window */
+#define ENE_MAX_IO		4
+
+/* 8 bytes of samples, divided in 2 halfs*/
+#define ENE_SAMPLE_BUFFER	0xF8F0	 /* regular sample buffer */
+#define ENE_SAMPLE_SPC_MASK	(1 << 7) /* sample is space */
+#define ENE_SAMPLE_VALUE_MASK	0x7F
+#define ENE_SAMPLE_OVERFLOW	0x7F
+#define ENE_SAMPLES_SIZE	4
+
+/* fan input sample buffer */
+#define ENE_SAMPLE_BUFFER_FAN	0xF8FB	 /* this buffer holds high byte of */
+					 /* each sample of normal buffer */
+
+#define ENE_FAN_SMPL_PULS_MSK	0x8000	 /* this bit of combined sample */
+					 /* if set, says that sample is pulse */
+#define ENE_FAN_VALUE_MASK	0x0FFF   /* mask for valid bits of the value */
+
+/* first firmware register */
+#define ENE_FW1			0xF8F8
+#define	ENE_FW1_ENABLE		(1 << 0) /* enable fw processing */
+#define ENE_FW1_TXIRQ		(1 << 1) /* TX interrupt pending */
+#define ENE_FW1_WAKE		(1 << 6) /* enable wake from S3 */
+#define ENE_FW1_IRQ		(1 << 7) /* enable interrupt */
+
+/* second firmware register */
+#define ENE_FW2			0xF8F9
+#define ENE_FW2_BUF_HIGH	(1 << 0) /* which half of the buffer to read */
+#define ENE_FW2_IRQ_CLR		(1 << 2) /* clear this on IRQ */
+#define ENE_FW2_GP40_AS_LEARN	(1 << 4) /* normal input is used as */
+					 /* learning input */
+#define ENE_FW2_FAN_AS_NRML_IN	(1 << 6) /* fan is used as normal input */
+#define ENE_FW2_LEARNING	(1 << 7) /* hardware supports learning and TX */
+
+/* fan as input settings - only if learning capable */
+#define ENE_FAN_AS_IN1		0xFE30   /* fan init reg 1 */
+#define ENE_FAN_AS_IN1_EN	0xCD
+#define ENE_FAN_AS_IN2		0xFE31   /* fan init reg 2 */
+#define ENE_FAN_AS_IN2_EN	0x03
+#define ENE_SAMPLE_PERIOD_FAN   61	 /* fan input has fixed sample period */
+
+/* IRQ registers block (for revision B) */
+#define ENEB_IRQ		0xFD09	 /* IRQ number */
+#define ENEB_IRQ_UNK1		0xFD17	 /* unknown setting = 1 */
+#define ENEB_IRQ_STATUS		0xFD80	 /* irq status */
+#define ENEB_IRQ_STATUS_IR	(1 << 5) /* IR irq */
+
+/* IRQ registers block (for revision C,D) */
+#define ENEC_IRQ		0xFE9B	 /* new irq settings register */
+#define ENEC_IRQ_MASK		0x0F	 /* irq number mask */
+#define ENEC_IRQ_UNK_EN		(1 << 4) /* always enabled */
+#define ENEC_IRQ_STATUS		(1 << 5) /* irq status and ACK */
+
+/* CIR block settings */
+#define ENE_CIR_CONF1		0xFEC0
+#define ENE_CIR_CONF1_ADC_ON	0x7	 /* reciever on gpio40 enabled */
+#define ENE_CIR_CONF1_LEARN1	(1 << 3) /* enabled on learning mode */
+#define ENE_CIR_CONF1_TX_ON	0x30	 /* enabled on transmit */
+#define ENE_CIR_CONF1_TX_CARR	(1 << 7) /* send TX carrier or not */
+
+#define ENE_CIR_CONF2		0xFEC1	 /* unknown setting = 0 */
+#define ENE_CIR_CONF2_LEARN2	(1 << 4) /* set on enable learning */
+#define ENE_CIR_CONF2_GPIO40DIS	(1 << 5) /* disable normal input via gpio40 */
+
+#define ENE_CIR_SAMPLE_PERIOD	0xFEC8	 /* sample period in us */
+#define ENE_CIR_SAMPLE_OVERFLOW	(1 << 7) /* interrupt on overflows if set */
+
+
+/* transmitter - not implemented yet */
+/* KB3926C and higher */
+/* transmission is very similiar to recieving, a byte is written to */
+/* ENE_TX_INPUT, in same manner as it is read from sample buffer */
+/* sample period is fixed*/
+
+
+/* transmitter ports */
+#define ENE_TX_PORT1		0xFC01	 /* this enables one or both */
+#define ENE_TX_PORT1_EN		(1 << 5) /* TX ports */
+#define ENE_TX_PORT2		0xFC08
+#define ENE_TX_PORT2_EN		(1 << 1)
+
+#define ENE_TX_INPUT		0xFEC9	 /* next byte to transmit */
+#define ENE_TX_SPC_MASK		(1 << 7) /* Transmitted sample is space */
+#define ENE_TX_UNK1		0xFECB	 /* set to 0x63 */
+#define ENE_TX_SMPL_PERIOD	50	 /* transmit sample period */
+
+
+#define ENE_TX_CARRIER		0xFECE	 /* TX carrier * 2 (khz) */
+#define ENE_TX_CARRIER_UNKBIT	0x80	 /* This bit set on transmit */
+#define ENE_TX_CARRIER_LOW	0xFECF	 /* TX carrier / 2 */
+
+/* Hardware versions */
+#define ENE_HW_VERSION		0xFF00	 /* hardware revision */
+#define ENE_HW_UNK		0xFF1D
+#define ENE_HW_UNK_CLR		(1 << 2)
+#define ENE_HW_VER_MAJOR	0xFF1E	 /* chip version */
+#define ENE_HW_VER_MINOR	0xFF1F
+#define ENE_HW_VER_OLD		0xFD00
+
+#define same_sign(a, b) ((((a) > 0) && (b) > 0) || ((a) < 0 && (b) < 0))
+
+#define ENE_DRIVER_NAME		"enecir"
+#define ENE_MAXGAP		250000	 /* this is amount of time we wait
+					 before turning the sampler, chosen
+					 arbitry */
+
+#define space(len)	       (-(len))	 /* add a space */
+
+/* software defines */
+#define ENE_IRQ_RX		1
+#define ENE_IRQ_TX		2
+
+#define  ENE_HW_B		1	/* 3926B */
+#define  ENE_HW_C		2	/* 3926C */
+#define  ENE_HW_D		3	/* 3926D */
+
+#define ene_printk(level, text, ...) \
+	printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__)
+
+struct ene_device {
+	struct pnp_dev *pnp_dev;
+	struct lirc_driver *lirc_driver;
+
+	/* hw settings */
+	unsigned long hw_io;
+	int irq;
+
+	int hw_revision;			/* hardware revision */
+	int hw_learning_and_tx_capable;		/* learning capable */
+	int hw_gpio40_learning;			/* gpio40 is learning */
+	int hw_fan_as_normal_input;	/* fan input is used as regular input */
+
+	/* device data */
+	int idle;
+	int fan_input_inuse;
+
+	int sample;
+	int in_use;
+
+	struct timeval gap_start;
+};
diff --git a/drivers/staging/lirc/lirc_i2c.c b/drivers/staging/lirc/lirc_i2c.c
new file mode 100644
index 0000000..6df2c0e
--- /dev/null
+++ b/drivers/staging/lirc/lirc_i2c.c
@@ -0,0 +1,536 @@
+/*
+ * lirc_i2c.c
+ *
+ * i2c IR driver for the onboard IR port on many TV tuner cards, including:
+ *  -Flavors of the Hauppauge PVR-150/250/350
+ *  -Hauppauge HVR-1300
+ *  -PixelView (BT878P+W/FM)
+ *  -KNC ONE TV Station/Anubis Typhoon TView Tuner
+ *  -Asus TV-Box and Creative/VisionTek BreakOut-Box
+ *  -Leadtek Winfast PVR2000
+ *
+ * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ * modified for PixelView (BT878P+W/FM) by
+ *      Michal Kochanowicz <mkochano@pld.org.pl>
+ *      Christoph Bartelmus <lirc@bartelmus.de>
+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
+ *      Ulrich Mueller <ulrich.mueller42@web.de>
+ * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by
+ *      Stefan Jahn <stefan@lkcc.org>
+ * modified for inclusion into kernel sources by
+ *      Jerome Brock <jbrock@users.sourceforge.net>
+ * modified for Leadtek Winfast PVR2000 by
+ *      Thomas Reitmayr (treitmayr@yahoo.com)
+ * modified for Hauppauge HVR-1300 by
+ *      Jan Frey (jfrey@gmx.de)
+ *
+ * parts are cut&pasted from the old lirc_haup.c driver
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <media/lirc_dev.h>
+
+struct IR {
+	struct lirc_driver l;
+	struct i2c_client  c;
+	int nextkey;
+	unsigned char b[3];
+	unsigned char bits;
+	unsigned char flag;
+};
+
+#define DEVICE_NAME "lirc_i2c"
+
+/* module parameters */
+static int debug;	/* debug output */
+static int minor = -1;	/* minor number */
+
+#define dprintk(fmt, args...)						\
+	do {								\
+		if (debug)						\
+			printk(KERN_DEBUG DEVICE_NAME ": " fmt,		\
+			       ## args);				\
+	} while (0)
+
+static int reverse(int data, int bits)
+{
+	int i;
+	int c;
+
+	for (c = 0, i = 0; i < bits; i++)
+		c |= ((data & (1<<i)) ? 1 : 0) << (bits-1-i);
+
+	return c;
+}
+
+static int add_to_buf_adap(void *data, struct lirc_buffer *buf)
+{
+	struct IR *ir = data;
+	unsigned char keybuf[4];
+
+	keybuf[0] = 0x00;
+	i2c_master_send(&ir->c, keybuf, 1);
+	/* poll IR chip */
+	if (i2c_master_recv(&ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) {
+		dprintk("read error\n");
+		return -EIO;
+	}
+
+	dprintk("key (0x%02x%02x%02x%02x)\n",
+		keybuf[0], keybuf[1], keybuf[2], keybuf[3]);
+
+	/* key pressed ? */
+	if (keybuf[2] == 0xff)
+		return -ENODATA;
+
+	/* remove repeat bit */
+	keybuf[2] &= 0x7f;
+	keybuf[3] |= 0x80;
+
+	lirc_buffer_write(buf, keybuf);
+	return 0;
+}
+
+static int add_to_buf_pcf8574(void *data, struct lirc_buffer *buf)
+{
+	struct IR *ir = data;
+	int rc;
+	unsigned char all, mask;
+	unsigned char key;
+
+	/* compute all valid bits (key code + pressed/release flag) */
+	all = ir->bits | ir->flag;
+
+	/* save IR writable mask bits */
+	mask = i2c_smbus_read_byte(&ir->c) & ~all;
+
+	/* send bit mask */
+	rc = i2c_smbus_write_byte(&ir->c, (0xff & all) | mask);
+
+	/* receive scan code */
+	rc = i2c_smbus_read_byte(&ir->c);
+
+	if (rc == -1) {
+		dprintk("%s read error\n", ir->c.name);
+		return -EIO;
+	}
+
+	/* drop duplicate polls */
+	if (ir->b[0] == (rc & all))
+		return -ENODATA;
+
+	ir->b[0] = rc & all;
+
+	dprintk("%s key 0x%02X %s\n", ir->c.name, rc & ir->bits,
+		(rc & ir->flag) ? "released" : "pressed");
+
+	/* ignore released buttons */
+	if (rc & ir->flag)
+		return -ENODATA;
+
+	/* set valid key code */
+	key  = rc & ir->bits;
+	lirc_buffer_write(buf, &key);
+	return 0;
+}
+
+/* common for Hauppauge IR receivers */
+static int add_to_buf_haup_common(void *data, struct lirc_buffer *buf,
+		unsigned char *keybuf, int size, int offset)
+{
+	struct IR *ir = data;
+	__u16 code;
+	unsigned char codes[2];
+	int ret;
+
+	/* poll IR chip */
+	ret = i2c_master_recv(&ir->c, keybuf, size);
+	if (ret == size) {
+		ir->b[0] = keybuf[offset];
+		ir->b[1] = keybuf[offset+1];
+		ir->b[2] = keybuf[offset+2];
+		if (ir->b[0] != 0x00 && ir->b[1] != 0x00)
+			dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]);
+	} else {
+		dprintk("read error (ret=%d)\n", ret);
+		/* keep last successful read buffer */
+	}
+
+	/* key pressed ? */
+	if ((ir->b[0] & 0x80) == 0)
+		return -ENODATA;
+
+	/* look what we have */
+	code = (((__u16)ir->b[0]&0x7f)<<6) | (ir->b[1]>>2);
+
+	codes[0] = (code >> 8) & 0xff;
+	codes[1] = code & 0xff;
+
+	/* return it */
+	dprintk("sending code 0x%02x%02x to lirc\n", codes[0], codes[1]);
+	lirc_buffer_write(buf, codes);
+	return 0;
+}
+
+/* specific for the Hauppauge PVR150 IR receiver */
+static int add_to_buf_haup_pvr150(void *data, struct lirc_buffer *buf)
+{
+	unsigned char keybuf[6];
+	/* fetch 6 bytes, first relevant is at offset 3 */
+	return add_to_buf_haup_common(data, buf, keybuf, 6, 3);
+}
+
+/* used for all Hauppauge IR receivers but the PVR150 */
+static int add_to_buf_haup(void *data, struct lirc_buffer *buf)
+{
+	unsigned char keybuf[3];
+	/* fetch 3 bytes, first relevant is at offset 0 */
+	return add_to_buf_haup_common(data, buf, keybuf, 3, 0);
+}
+
+
+static int add_to_buf_pvr2000(void *data, struct lirc_buffer *buf)
+{
+	struct IR *ir = data;
+	unsigned char key;
+	s32 flags;
+	s32 code;
+
+	/* poll IR chip */
+	flags = i2c_smbus_read_byte_data(&ir->c, 0x10);
+	if (-1 == flags) {
+		dprintk("read error\n");
+		return -ENODATA;
+	}
+	/* key pressed ? */
+	if (0 == (flags & 0x80))
+		return -ENODATA;
+
+	/* read actual key code */
+	code = i2c_smbus_read_byte_data(&ir->c, 0x00);
+	if (-1 == code) {
+		dprintk("read error\n");
+		return -ENODATA;
+	}
+
+	key = code & 0xFF;
+
+	dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", key, flags & 0xFF);
+
+	/* return it */
+	lirc_buffer_write(buf, &key);
+	return 0;
+}
+
+static int add_to_buf_pixelview(void *data, struct lirc_buffer *buf)
+{
+	struct IR *ir = data;
+	unsigned char key;
+
+	/* poll IR chip */
+	if (1 != i2c_master_recv(&ir->c, &key, 1)) {
+		dprintk("read error\n");
+		return -1;
+	}
+	dprintk("key %02x\n", key);
+
+	/* return it */
+	lirc_buffer_write(buf, &key);
+	return 0;
+}
+
+static int add_to_buf_pv951(void *data, struct lirc_buffer *buf)
+{
+	struct IR *ir = data;
+	unsigned char key;
+	unsigned char codes[4];
+
+	/* poll IR chip */
+	if (1 != i2c_master_recv(&ir->c, &key, 1)) {
+		dprintk("read error\n");
+		return -ENODATA;
+	}
+	/* ignore 0xaa */
+	if (key == 0xaa)
+		return -ENODATA;
+	dprintk("key %02x\n", key);
+
+	codes[0] = 0x61;
+	codes[1] = 0xD6;
+	codes[2] = reverse(key, 8);
+	codes[3] = (~codes[2])&0xff;
+
+	lirc_buffer_write(buf, codes);
+	return 0;
+}
+
+static int add_to_buf_knc1(void *data, struct lirc_buffer *buf)
+{
+	static unsigned char last_key = 0xFF;
+	struct IR *ir = data;
+	unsigned char key;
+
+	/* poll IR chip */
+	if (1 != i2c_master_recv(&ir->c, &key, 1)) {
+		dprintk("read error\n");
+		return -ENODATA;
+	}
+
+	/*
+	 * it seems that 0xFE indicates that a button is still held
+	 * down, while 0xFF indicates that no button is held
+	 * down. 0xFE sequences are sometimes interrupted by 0xFF
+	 */
+
+	dprintk("key %02x\n", key);
+
+	if (key == 0xFF)
+		return -ENODATA;
+
+	if (key == 0xFE)
+		key = last_key;
+
+	last_key = key;
+	lirc_buffer_write(buf, &key);
+
+	return 0;
+}
+
+static int set_use_inc(void *data)
+{
+	struct IR *ir = data;
+
+	dprintk("%s called\n", __func__);
+
+	/* lock bttv in memory while /dev/lirc is in use  */
+	i2c_use_client(&ir->c);
+
+	return 0;
+}
+
+static void set_use_dec(void *data)
+{
+	struct IR *ir = data;
+
+	dprintk("%s called\n", __func__);
+
+	i2c_release_client(&ir->c);
+}
+
+static struct lirc_driver lirc_template = {
+	.name		= "lirc_i2c",
+	.set_use_inc	= set_use_inc,
+	.set_use_dec	= set_use_dec,
+	.dev		= NULL,
+	.owner		= THIS_MODULE,
+};
+
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id);
+static int ir_remove(struct i2c_client *client);
+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg);
+
+static const struct i2c_device_id ir_receiver_id[] = {
+	/* Generic entry for any IR receiver */
+	{ "ir_video", 0 },
+	/* IR device specific entries could be added here */
+	{ }
+};
+
+static struct i2c_driver driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "i2c ir driver",
+	},
+	.probe		= ir_probe,
+	.remove		= ir_remove,
+	.id_table	= ir_receiver_id,
+	.command	= ir_command,
+};
+
+static void pcf_probe(struct i2c_client *client, struct IR *ir)
+{
+	int ret1, ret2, ret3, ret4;
+
+	ret1 = i2c_smbus_write_byte(client, 0xff);
+	ret2 = i2c_smbus_read_byte(client);
+	ret3 = i2c_smbus_write_byte(client, 0x00);
+	ret4 = i2c_smbus_read_byte(client);
+
+	/* in the Asus TV-Box: bit 1-0 */
+	if (((ret2 & 0x03) == 0x03) && ((ret4 & 0x03) == 0x00)) {
+		ir->bits = (unsigned char) ~0x07;
+		ir->flag = 0x04;
+	/* in the Creative/VisionTek BreakOut-Box: bit 7-6 */
+	} else if (((ret2 & 0xc0) == 0xc0) && ((ret4 & 0xc0) == 0x00)) {
+		ir->bits = (unsigned char) ~0xe0;
+		ir->flag = 0x20;
+	}
+
+	return;
+}
+
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct IR *ir;
+	struct i2c_adapter *adap = client->adapter;
+	unsigned short addr = client->addr;
+	int retval;
+
+	ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+	if (!ir)
+		return -ENOMEM;
+	memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
+	memcpy(&ir->c, client, sizeof(struct i2c_client));
+
+	i2c_set_clientdata(client, ir);
+	ir->l.data    = ir;
+	ir->l.minor   = minor;
+	ir->l.sample_rate = 10;
+	ir->l.dev     = &ir->c.dev;
+	ir->nextkey   = -1;
+
+	switch (addr) {
+	case 0x64:
+		strlcpy(ir->c.name, "Pixelview IR", I2C_NAME_SIZE);
+		ir->l.code_length = 8;
+		ir->l.add_to_buf = add_to_buf_pixelview;
+		break;
+	case 0x4b:
+		strlcpy(ir->c.name, "PV951 IR", I2C_NAME_SIZE);
+		ir->l.code_length = 32;
+		ir->l.add_to_buf = add_to_buf_pv951;
+		break;
+	case 0x71:
+		if (adap->id == I2C_HW_B_CX2388x)
+			strlcpy(ir->c.name, "Hauppauge HVR1300", I2C_NAME_SIZE);
+		else /* bt8xx or cx2341x */
+			/*
+			 * The PVR150 IR receiver uses the same protocol as
+			 * other Hauppauge cards, but the data flow is
+			 * different, so we need to deal with it by its own.
+			 */
+			strlcpy(ir->c.name, "Hauppauge PVR150", I2C_NAME_SIZE);
+		ir->l.code_length = 13;
+		ir->l.add_to_buf = add_to_buf_haup_pvr150;
+		break;
+	case 0x6b:
+		strlcpy(ir->c.name, "Adaptec IR", I2C_NAME_SIZE);
+		ir->l.code_length = 32;
+		ir->l.add_to_buf = add_to_buf_adap;
+		break;
+	case 0x18:
+	case 0x1a:
+		if (adap->id == I2C_HW_B_CX2388x) {
+			strlcpy(ir->c.name, "Leadtek IR", I2C_NAME_SIZE);
+			ir->l.code_length = 8;
+			ir->l.add_to_buf = add_to_buf_pvr2000;
+		} else { /* bt8xx or cx2341x */
+			strlcpy(ir->c.name, "Hauppauge IR", I2C_NAME_SIZE);
+			ir->l.code_length = 13;
+			ir->l.add_to_buf = add_to_buf_haup;
+		}
+		break;
+	case 0x30:
+		strlcpy(ir->c.name, "KNC ONE IR", I2C_NAME_SIZE);
+		ir->l.code_length = 8;
+		ir->l.add_to_buf = add_to_buf_knc1;
+		break;
+	case 0x21:
+	case 0x23:
+		pcf_probe(client, ir);
+		strlcpy(ir->c.name, "TV-Box IR", I2C_NAME_SIZE);
+		ir->l.code_length = 8;
+		ir->l.add_to_buf = add_to_buf_pcf8574;
+		break;
+	default:
+		/* shouldn't happen */
+		printk("lirc_i2c: Huh? unknown i2c address (0x%02x)?\n", addr);
+		kfree(ir);
+		return -EINVAL;
+	}
+	printk(KERN_INFO "lirc_i2c: chip 0x%x found @ 0x%02x (%s)\n",
+	       adap->id, addr, ir->c.name);
+
+	retval = lirc_register_driver(&ir->l);
+
+	if (retval < 0) {
+		printk(KERN_ERR "lirc_i2c: failed to register driver!\n");
+		kfree(ir);
+		return retval;
+	}
+
+	ir->l.minor = retval;
+
+	return 0;
+}
+
+static int ir_remove(struct i2c_client *client)
+{
+	struct IR *ir = i2c_get_clientdata(client);
+
+	/* unregister device */
+	lirc_unregister_driver(ir->l.minor);
+
+	/* free memory */
+	kfree(ir);
+	return 0;
+}
+
+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	/* nothing */
+	return 0;
+}
+
+static int __init lirc_i2c_init(void)
+{
+	i2c_add_driver(&driver);
+	return 0;
+}
+
+static void __exit lirc_i2c_exit(void)
+{
+	i2c_del_driver(&driver);
+}
+
+MODULE_DESCRIPTION("Infrared receiver driver for Hauppauge and "
+		   "Pixelview cards (i2c stack)");
+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, "
+	      "Ulrich Mueller, Stefan Jahn, Jerome Brock");
+MODULE_LICENSE("GPL");
+
+module_param(minor, int, S_IRUGO);
+MODULE_PARM_DESC(minor, "Preferred minor device number");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
+module_init(lirc_i2c_init);
+module_exit(lirc_i2c_exit);
diff --git a/drivers/staging/lirc/lirc_igorplugusb.c b/drivers/staging/lirc/lirc_igorplugusb.c
new file mode 100644
index 0000000..bce600e
--- /dev/null
+++ b/drivers/staging/lirc/lirc_igorplugusb.c
@@ -0,0 +1,555 @@
+/*
+ * lirc_igorplugusb - USB remote support for LIRC
+ *
+ * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware.
+ * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm
+ *
+ * The device can only record bursts of up to 36 pulses/spaces.
+ * Works fine with RC5. Longer commands lead to device buffer overrun.
+ * (Maybe a better firmware or a microcontroller with more ram can help?)
+ *
+ * Version 0.1  [beta status]
+ *
+ * Copyright (C) 2004 Jan M. Hochstein
+ *	<hochstein@algo.informatik.tu-darmstadt.de>
+ *
+ * This driver was derived from:
+ *   Paul Miller <pmiller9@users.sourceforge.net>
+ *      "lirc_atiusb" module
+ *   Vladimir Dergachev <volodya@minspring.com>'s 2002
+ *      "USB ATI Remote support" (input device)
+ *   Adrian Dewhurst <sailor-lk@sailorfrag.net>'s 2002
+ *      "USB StreamZap remote driver" (LIRC)
+ *   Artur Lipowski <alipowski@kki.net.pl>'s 2002
+ *      "lirc_dev" and "lirc_gpio" LIRC modules
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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/kernel.h>
+#include <linux/kmod.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/usb.h>
+#include <linux/time.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+
+/* module identification */
+#define DRIVER_VERSION		"0.1"
+#define DRIVER_AUTHOR		\
+	"Jan M. Hochstein <hochstein@algo.informatik.tu-darmstadt.de>"
+#define DRIVER_DESC		"USB remote driver for LIRC"
+#define DRIVER_NAME		"lirc_igorplugusb"
+
+/* debugging support */
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+#define dprintk(fmt, args...)					\
+	do {							\
+		if (debug)					\
+			printk(KERN_DEBUG fmt, ## args);	\
+	} while (0)
+
+/* One mode2 pulse/space has 4 bytes. */
+#define CODE_LENGTH	     sizeof(int)
+
+/* Igor's firmware cannot record bursts longer than 36. */
+#define DEVICE_BUFLEN	   36
+
+/*
+ * Header at the beginning of the device's buffer:
+ *	unsigned char data_length
+ *	unsigned char data_start    (!=0 means ring-buffer overrun)
+ *	unsigned char counter       (incremented by each burst)
+ */
+#define DEVICE_HEADERLEN	3
+
+/* This is for the gap */
+#define ADDITIONAL_LIRC_BYTES   2
+
+/* times to poll per second */
+#define SAMPLE_RATE	     100
+static int sample_rate = SAMPLE_RATE;
+
+
+/**** Igor's USB Request Codes */
+
+#define SET_INFRABUFFER_EMPTY   1
+/**
+ * Params: none
+ * Answer: empty
+ */
+
+#define GET_INFRACODE	   2
+/**
+ * Params:
+ *   wValue: offset to begin reading infra buffer
+ *
+ * Answer: infra data
+ */
+
+#define SET_DATAPORT_DIRECTION  3
+/**
+ * Params:
+ *   wValue: (byte) 1 bit for each data port pin (0=in, 1=out)
+ *
+ * Answer: empty
+ */
+
+#define GET_DATAPORT_DIRECTION  4
+/**
+ * Params: none
+ *
+ * Answer: (byte) 1 bit for each data port pin (0=in, 1=out)
+ */
+
+#define SET_OUT_DATAPORT	5
+/**
+ * Params:
+ *   wValue: byte to write to output data port
+ *
+ * Answer: empty
+ */
+
+#define GET_OUT_DATAPORT	6
+/**
+ * Params: none
+ *
+ * Answer: least significant 3 bits read from output data port
+ */
+
+#define GET_IN_DATAPORT	 7
+/**
+ * Params: none
+ *
+ * Answer: least significant 3 bits read from input data port
+ */
+
+#define READ_EEPROM	     8
+/**
+ * Params:
+ *   wValue: offset to begin reading EEPROM
+ *
+ * Answer: EEPROM bytes
+ */
+
+#define WRITE_EEPROM	    9
+/**
+ * Params:
+ *   wValue: offset to EEPROM byte
+ *   wIndex: byte to write
+ *
+ * Answer: empty
+ */
+
+#define SEND_RS232	      10
+/**
+ * Params:
+ *   wValue: byte to send
+ *
+ * Answer: empty
+ */
+
+#define RECV_RS232	      11
+/**
+ * Params: none
+ *
+ * Answer: byte received
+ */
+
+#define SET_RS232_BAUD	  12
+/**
+ * Params:
+ *   wValue: byte to write to UART bit rate register (UBRR)
+ *
+ * Answer: empty
+ */
+
+#define GET_RS232_BAUD	  13
+/**
+ * Params: none
+ *
+ * Answer: byte read from UART bit rate register (UBRR)
+ */
+
+
+/* data structure for each usb remote */
+struct igorplug {
+
+	/* usb */
+	struct usb_device *usbdev;
+	struct urb *urb_in;
+	int devnum;
+
+	unsigned char *buf_in;
+	unsigned int len_in;
+	int in_space;
+	struct timeval last_time;
+
+	dma_addr_t dma_in;
+
+	/* lirc */
+	struct lirc_driver *d;
+
+	/* handle sending (init strings) */
+	int send_flags;
+	wait_queue_head_t wait_out;
+};
+
+static int unregister_from_lirc(struct igorplug *ir)
+{
+	struct lirc_driver *d = ir->d;
+	int devnum;
+
+	if (!ir->d)
+		return -EINVAL;
+
+	devnum = ir->devnum;
+	dprintk(DRIVER_NAME "[%d]: unregister from lirc called\n", devnum);
+
+	lirc_unregister_driver(d->minor);
+
+	printk(DRIVER_NAME "[%d]: usb remote disconnected\n", devnum);
+
+	kfree(d);
+	ir->d = NULL;
+	kfree(ir);
+	return 0;
+}
+
+static int set_use_inc(void *data)
+{
+	struct igorplug *ir = data;
+
+	if (!ir) {
+		printk(DRIVER_NAME "[?]: set_use_inc called with no context\n");
+		return -EIO;
+	}
+	dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum);
+
+	if (!ir->usbdev)
+		return -ENODEV;
+
+	return 0;
+}
+
+static void set_use_dec(void *data)
+{
+	struct igorplug *ir = data;
+
+	if (!ir) {
+		printk(DRIVER_NAME "[?]: set_use_dec called with no context\n");
+		return;
+	}
+	dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum);
+}
+
+
+/**
+ * Called in user context.
+ * return 0 if data was added to the buffer and
+ * -ENODATA if none was available. This should add some number of bits
+ * evenly divisible by code_length to the buffer
+ */
+static int usb_remote_poll(void *data, struct lirc_buffer *buf)
+{
+	int ret;
+	struct igorplug *ir = (struct igorplug *)data;
+
+	if (!ir->usbdev)  /* Has the device been removed? */
+		return -ENODEV;
+
+	memset(ir->buf_in, 0, ir->len_in);
+
+	ret = usb_control_msg(
+	      ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+	      GET_INFRACODE, USB_TYPE_VENDOR|USB_DIR_IN,
+	      0/* offset */, /*unused*/0,
+	      ir->buf_in, ir->len_in,
+	      /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+	if (ret > 0) {
+		int i = DEVICE_HEADERLEN;
+		int code, timediff;
+		struct timeval now;
+
+		if (ret <= 1)  /* ACK packet has 1 byte --> ignore */
+			return -ENODATA;
+
+		dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n",
+			ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]);
+
+		if (ir->buf_in[2] != 0) {
+			printk(DRIVER_NAME "[%d]: Device buffer overrun.\n",
+				ir->devnum);
+			/* start at earliest byte */
+			i = DEVICE_HEADERLEN + ir->buf_in[2];
+			/* where are we now? space, gap or pulse? */
+		}
+
+		do_gettimeofday(&now);
+		timediff = now.tv_sec - ir->last_time.tv_sec;
+		if (timediff + 1 > PULSE_MASK / 1000000)
+			timediff = PULSE_MASK;
+		else {
+			timediff *= 1000000;
+			timediff += now.tv_usec - ir->last_time.tv_usec;
+		}
+		ir->last_time.tv_sec = now.tv_sec;
+		ir->last_time.tv_usec = now.tv_usec;
+
+		/* create leading gap  */
+		code = timediff;
+		lirc_buffer_write(buf, (unsigned char *)&code);
+		ir->in_space = 1;   /* next comes a pulse */
+
+		/* MODE2: pulse/space (PULSE_BIT) in 1us units */
+
+		while (i < ret) {
+			/* 1 Igor-tick = 85.333333 us */
+			code = (unsigned int)ir->buf_in[i] * 85
+				+ (unsigned int)ir->buf_in[i] / 3;
+			if (ir->in_space)
+				code |= PULSE_BIT;
+			lirc_buffer_write(buf, (unsigned char *)&code);
+			/* 1 chunk = CODE_LENGTH bytes */
+			ir->in_space ^= 1;
+			++i;
+		}
+
+		ret = usb_control_msg(
+		      ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+		      SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN,
+		      /*unused*/0, /*unused*/0,
+		      /*dummy*/ir->buf_in, /*dummy*/ir->len_in,
+		      /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+		if (ret < 0)
+			printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: "
+			       "error %d\n", ir->devnum, ret);
+		return 0;
+	} else if (ret < 0)
+		printk(DRIVER_NAME "[%d]: GET_INFRACODE: error %d\n",
+			ir->devnum, ret);
+
+	return -ENODATA;
+}
+
+
+
+static int usb_remote_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	struct usb_device *dev = NULL;
+	struct usb_host_interface *idesc = NULL;
+	struct usb_host_endpoint *ep_ctl2;
+	struct igorplug *ir = NULL;
+	struct lirc_driver *driver = NULL;
+	int devnum, pipe, maxp;
+	int minor = 0;
+	char buf[63], name[128] = "";
+	int mem_failure = 0;
+	int ret;
+
+	dprintk(DRIVER_NAME ": usb probe called.\n");
+
+	dev = interface_to_usbdev(intf);
+
+	idesc = intf->cur_altsetting;
+
+	if (idesc->desc.bNumEndpoints != 1)
+		return -ENODEV;
+	ep_ctl2 = idesc->endpoint;
+	if (((ep_ctl2->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+	    != USB_DIR_IN)
+	    || (ep_ctl2->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+	    != USB_ENDPOINT_XFER_CONTROL)
+		return -ENODEV;
+	pipe = usb_rcvctrlpipe(dev, ep_ctl2->desc.bEndpointAddress);
+	devnum = dev->devnum;
+	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+	dprintk(DRIVER_NAME "[%d]: bytes_in_key=%lu maxp=%d\n",
+		devnum, CODE_LENGTH, maxp);
+
+
+	mem_failure = 0;
+	ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL);
+	if (!ir) {
+		mem_failure = 1;
+		goto mem_failure_switch;
+	}
+	driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+	if (!driver) {
+		mem_failure = 2;
+		goto mem_failure_switch;
+	}
+
+	ir->buf_in = usb_alloc_coherent(dev,
+			      DEVICE_BUFLEN+DEVICE_HEADERLEN,
+			      GFP_ATOMIC, &ir->dma_in);
+	if (!ir->buf_in) {
+		mem_failure = 3;
+		goto mem_failure_switch;
+	}
+
+	strcpy(driver->name, DRIVER_NAME " ");
+	driver->minor = -1;
+	driver->code_length = CODE_LENGTH * 8; /* in bits */
+	driver->features = LIRC_CAN_REC_MODE2;
+	driver->data = ir;
+	driver->chunk_size = CODE_LENGTH;
+	driver->buffer_size = DEVICE_BUFLEN + ADDITIONAL_LIRC_BYTES;
+	driver->set_use_inc = &set_use_inc;
+	driver->set_use_dec = &set_use_dec;
+	driver->sample_rate = sample_rate;    /* per second */
+	driver->add_to_buf = &usb_remote_poll;
+	driver->dev = &intf->dev;
+	driver->owner = THIS_MODULE;
+
+	init_waitqueue_head(&ir->wait_out);
+
+	minor = lirc_register_driver(driver);
+	if (minor < 0)
+		mem_failure = 9;
+
+mem_failure_switch:
+
+	switch (mem_failure) {
+	case 9:
+		usb_free_coherent(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN,
+			ir->buf_in, ir->dma_in);
+	case 3:
+		kfree(driver);
+	case 2:
+		kfree(ir);
+	case 1:
+		printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n",
+			devnum, mem_failure);
+		return -ENOMEM;
+	}
+
+	driver->minor = minor;
+	ir->d = driver;
+	ir->devnum = devnum;
+	ir->usbdev = dev;
+	ir->len_in = DEVICE_BUFLEN+DEVICE_HEADERLEN;
+	ir->in_space = 1; /* First mode2 event is a space. */
+	do_gettimeofday(&ir->last_time);
+
+	if (dev->descriptor.iManufacturer
+	    && usb_string(dev, dev->descriptor.iManufacturer,
+			  buf, sizeof(buf)) > 0)
+		strlcpy(name, buf, sizeof(name));
+	if (dev->descriptor.iProduct
+	    && usb_string(dev, dev->descriptor.iProduct, buf, sizeof(buf)) > 0)
+		snprintf(name + strlen(name), sizeof(name) - strlen(name),
+			 " %s", buf);
+	printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name,
+	       dev->bus->busnum, devnum);
+
+	/* clear device buffer */
+	ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+		SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN,
+		/*unused*/0, /*unused*/0,
+		/*dummy*/ir->buf_in, /*dummy*/ir->len_in,
+		/*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+	if (ret < 0)
+		printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n",
+			devnum, ret);
+
+	usb_set_intfdata(intf, ir);
+	return 0;
+}
+
+
+static void usb_remote_disconnect(struct usb_interface *intf)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct igorplug *ir = usb_get_intfdata(intf);
+	usb_set_intfdata(intf, NULL);
+
+	if (!ir || !ir->d)
+		return;
+
+	ir->usbdev = NULL;
+	wake_up_all(&ir->wait_out);
+
+	usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
+
+	unregister_from_lirc(ir);
+}
+
+static struct usb_device_id usb_remote_id_table[] = {
+	/* Igor Plug USB (Atmel's Manufact. ID) */
+	{ USB_DEVICE(0x03eb, 0x0002) },
+
+	/* Terminating entry */
+	{ }
+};
+
+static struct usb_driver usb_remote_driver = {
+	.name =		DRIVER_NAME,
+	.probe =	usb_remote_probe,
+	.disconnect =	usb_remote_disconnect,
+	.id_table =	usb_remote_id_table
+};
+
+static int __init usb_remote_init(void)
+{
+	int i;
+
+	printk(KERN_INFO "\n"
+	       DRIVER_NAME ": " DRIVER_DESC " v" DRIVER_VERSION "\n");
+	printk(DRIVER_NAME ": " DRIVER_AUTHOR "\n");
+	dprintk(DRIVER_NAME ": debug mode enabled\n");
+
+	i = usb_register(&usb_remote_driver);
+	if (i < 0) {
+		printk(DRIVER_NAME ": usb register failed, result = %d\n", i);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit usb_remote_exit(void)
+{
+	usb_deregister(&usb_remote_driver);
+}
+
+module_init(usb_remote_init);
+module_exit(usb_remote_exit);
+
+#include <linux/vermagic.h>
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, usb_remote_id_table);
+
+module_param(sample_rate, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)");
+
diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/lirc/lirc_imon.c
new file mode 100644
index 0000000..6649325
--- /dev/null
+++ b/drivers/staging/lirc/lirc_imon.c
@@ -0,0 +1,1058 @@
+/*
+ *   lirc_imon.c:  LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD
+ *		   including the iMON PAD model
+ *
+ *   Copyright(C) 2004  Venky Raju(dev@venky.ws)
+ *   Copyright(C) 2009  Jarod Wilson <jarod@wilsonet.com>
+ *
+ *   lirc_imon is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+
+#define MOD_AUTHOR	"Venky Raju <dev@venky.ws>"
+#define MOD_DESC	"Driver for SoundGraph iMON MultiMedia IR/Display"
+#define MOD_NAME	"lirc_imon"
+#define MOD_VERSION	"0.8"
+
+#define DISPLAY_MINOR_BASE	144
+#define DEVICE_NAME	"lcd%d"
+
+#define BUF_CHUNK_SIZE	4
+#define BUF_SIZE	128
+
+#define BIT_DURATION	250	/* each bit received is 250us */
+
+/*** P R O T O T Y P E S ***/
+
+/* USB Callback prototypes */
+static int imon_probe(struct usb_interface *interface,
+		      const struct usb_device_id *id);
+static void imon_disconnect(struct usb_interface *interface);
+static void usb_rx_callback(struct urb *urb);
+static void usb_tx_callback(struct urb *urb);
+
+/* suspend/resume support */
+static int imon_resume(struct usb_interface *intf);
+static int imon_suspend(struct usb_interface *intf, pm_message_t message);
+
+/* Display file_operations function prototypes */
+static int display_open(struct inode *inode, struct file *file);
+static int display_close(struct inode *inode, struct file *file);
+
+/* VFD write operation */
+static ssize_t vfd_write(struct file *file, const char *buf,
+			 size_t n_bytes, loff_t *pos);
+
+/* LIRC driver function prototypes */
+static int ir_open(void *data);
+static void ir_close(void *data);
+
+/* Driver init/exit prototypes */
+static int __init imon_init(void);
+static void __exit imon_exit(void);
+
+/*** G L O B A L S ***/
+#define IMON_DATA_BUF_SZ	35
+
+struct imon_context {
+	struct usb_device *usbdev;
+	/* Newer devices have two interfaces */
+	int display;			/* not all controllers do */
+	int display_isopen;		/* display port has been opened */
+	int ir_isopen;			/* IR port open	*/
+	int dev_present;		/* USB device presence */
+	struct mutex ctx_lock;		/* to lock this object */
+	wait_queue_head_t remove_ok;	/* For unexpected USB disconnects */
+
+	int vfd_proto_6p;		/* some VFD require a 6th packet */
+
+	struct lirc_driver *driver;
+	struct usb_endpoint_descriptor *rx_endpoint;
+	struct usb_endpoint_descriptor *tx_endpoint;
+	struct urb *rx_urb;
+	struct urb *tx_urb;
+	unsigned char usb_rx_buf[8];
+	unsigned char usb_tx_buf[8];
+
+	struct rx_data {
+		int count;		/* length of 0 or 1 sequence */
+		int prev_bit;		/* logic level of sequence */
+		int initial_space;	/* initial space flag */
+	} rx;
+
+	struct tx_t {
+		unsigned char data_buf[IMON_DATA_BUF_SZ]; /* user data buffer */
+		struct completion finished;	/* wait for write to finish */
+		atomic_t busy;			/* write in progress */
+		int status;			/* status of tx completion */
+	} tx;
+};
+
+static const struct file_operations display_fops = {
+	.owner		= THIS_MODULE,
+	.open		= &display_open,
+	.write		= &vfd_write,
+	.release	= &display_close
+};
+
+/*
+ * USB Device ID for iMON USB Control Boards
+ *
+ * The Windows drivers contain 6 different inf files, more or less one for
+ * each new device until the 0x0034-0x0046 devices, which all use the same
+ * driver. Some of the devices in the 34-46 range haven't been definitively
+ * identified yet. Early devices have either a TriGem Computer, Inc. or a
+ * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later
+ * devices use the SoundGraph vendor ID (0x15c2).
+ */
+static struct usb_device_id imon_usb_id_table[] = {
+	/* TriGem iMON (IR only) -- TG_iMON.inf */
+	{ USB_DEVICE(0x0aa8, 0x8001) },
+
+	/* SoundGraph iMON (IR only) -- sg_imon.inf */
+	{ USB_DEVICE(0x04e8, 0xff30) },
+
+	/* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */
+	{ USB_DEVICE(0x0aa8, 0xffda) },
+
+	/* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */
+	{ USB_DEVICE(0x15c2, 0xffda) },
+
+	{}
+};
+
+/* Some iMON VFD models requires a 6th packet for VFD writes */
+static struct usb_device_id vfd_proto_6p_list[] = {
+	{ USB_DEVICE(0x15c2, 0xffda) },
+	{}
+};
+
+/* Some iMON devices have no lcd/vfd, don't set one up */
+static struct usb_device_id ir_only_list[] = {
+	{ USB_DEVICE(0x0aa8, 0x8001) },
+	{ USB_DEVICE(0x04e8, 0xff30) },
+	{}
+};
+
+/* USB Device data */
+static struct usb_driver imon_driver = {
+	.name		= MOD_NAME,
+	.probe		= imon_probe,
+	.disconnect	= imon_disconnect,
+	.suspend	= imon_suspend,
+	.resume		= imon_resume,
+	.id_table	= imon_usb_id_table,
+};
+
+static struct usb_class_driver imon_class = {
+	.name		= DEVICE_NAME,
+	.fops		= &display_fops,
+	.minor_base	= DISPLAY_MINOR_BASE,
+};
+
+/* to prevent races between open() and disconnect(), probing, etc */
+static DEFINE_MUTEX(driver_lock);
+
+static int debug;
+
+/***  M O D U L E   C O D E ***/
+
+MODULE_AUTHOR(MOD_AUTHOR);
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_VERSION(MOD_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, imon_usb_id_table);
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)");
+
+static void free_imon_context(struct imon_context *context)
+{
+	struct device *dev = context->driver->dev;
+	usb_free_urb(context->tx_urb);
+	usb_free_urb(context->rx_urb);
+	lirc_buffer_free(context->driver->rbuf);
+	kfree(context->driver->rbuf);
+	kfree(context->driver);
+	kfree(context);
+
+	dev_dbg(dev, "%s: iMON context freed\n", __func__);
+}
+
+static void deregister_from_lirc(struct imon_context *context)
+{
+	int retval;
+	int minor = context->driver->minor;
+
+	retval = lirc_unregister_driver(minor);
+	if (retval)
+		err("%s: unable to deregister from lirc(%d)",
+			__func__, retval);
+	else
+		printk(KERN_INFO MOD_NAME ": Deregistered iMON driver "
+		       "(minor:%d)\n", minor);
+
+}
+
+/**
+ * Called when the Display device (e.g. /dev/lcd0)
+ * is opened by the application.
+ */
+static int display_open(struct inode *inode, struct file *file)
+{
+	struct usb_interface *interface;
+	struct imon_context *context = NULL;
+	int subminor;
+	int retval = 0;
+
+	/* prevent races with disconnect */
+	mutex_lock(&driver_lock);
+
+	subminor = iminor(inode);
+	interface = usb_find_interface(&imon_driver, subminor);
+	if (!interface) {
+		err("%s: could not find interface for minor %d",
+		    __func__, subminor);
+		retval = -ENODEV;
+		goto exit;
+	}
+	context = usb_get_intfdata(interface);
+
+	if (!context) {
+		err("%s: no context found for minor %d",
+					__func__, subminor);
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	mutex_lock(&context->ctx_lock);
+
+	if (!context->display) {
+		err("%s: display not supported by device", __func__);
+		retval = -ENODEV;
+	} else if (context->display_isopen) {
+		err("%s: display port is already open", __func__);
+		retval = -EBUSY;
+	} else {
+		context->display_isopen = 1;
+		file->private_data = context;
+		dev_info(context->driver->dev, "display port opened\n");
+	}
+
+	mutex_unlock(&context->ctx_lock);
+
+exit:
+	mutex_unlock(&driver_lock);
+	return retval;
+}
+
+/**
+ * Called when the display device (e.g. /dev/lcd0)
+ * is closed by the application.
+ */
+static int display_close(struct inode *inode, struct file *file)
+{
+	struct imon_context *context = NULL;
+	int retval = 0;
+
+	context = (struct imon_context *)file->private_data;
+
+	if (!context) {
+		err("%s: no context for device", __func__);
+		return -ENODEV;
+	}
+
+	mutex_lock(&context->ctx_lock);
+
+	if (!context->display) {
+		err("%s: display not supported by device", __func__);
+		retval = -ENODEV;
+	} else if (!context->display_isopen) {
+		err("%s: display is not open", __func__);
+		retval = -EIO;
+	} else {
+		context->display_isopen = 0;
+		dev_info(context->driver->dev, "display port closed\n");
+		if (!context->dev_present && !context->ir_isopen) {
+			/*
+			 * Device disconnected before close and IR port is not
+			 * open. If IR port is open, context will be deleted by
+			 * ir_close.
+			 */
+			mutex_unlock(&context->ctx_lock);
+			free_imon_context(context);
+			return retval;
+		}
+	}
+
+	mutex_unlock(&context->ctx_lock);
+	return retval;
+}
+
+/**
+ * Sends a packet to the device -- this function must be called
+ * with context->ctx_lock held.
+ */
+static int send_packet(struct imon_context *context)
+{
+	unsigned int pipe;
+	int interval = 0;
+	int retval = 0;
+	struct usb_ctrlrequest *control_req = NULL;
+
+	/* Check if we need to use control or interrupt urb */
+	pipe = usb_sndintpipe(context->usbdev,
+			      context->tx_endpoint->bEndpointAddress);
+	interval = context->tx_endpoint->bInterval;
+
+	usb_fill_int_urb(context->tx_urb, context->usbdev, pipe,
+			 context->usb_tx_buf,
+			 sizeof(context->usb_tx_buf),
+			 usb_tx_callback, context, interval);
+
+	context->tx_urb->actual_length = 0;
+
+	init_completion(&context->tx.finished);
+	atomic_set(&(context->tx.busy), 1);
+
+	retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
+	if (retval) {
+		atomic_set(&(context->tx.busy), 0);
+		err("%s: error submitting urb(%d)", __func__, retval);
+	} else {
+		/* Wait for transmission to complete (or abort) */
+		mutex_unlock(&context->ctx_lock);
+		retval = wait_for_completion_interruptible(
+				&context->tx.finished);
+		if (retval)
+			err("%s: task interrupted", __func__);
+		mutex_lock(&context->ctx_lock);
+
+		retval = context->tx.status;
+		if (retval)
+			err("%s: packet tx failed (%d)", __func__, retval);
+	}
+
+	kfree(control_req);
+
+	return retval;
+}
+
+/**
+ * Writes data to the VFD.  The iMON VFD is 2x16 characters
+ * and requires data in 5 consecutive USB interrupt packets,
+ * each packet but the last carrying 7 bytes.
+ *
+ * I don't know if the VFD board supports features such as
+ * scrolling, clearing rows, blanking, etc. so at
+ * the caller must provide a full screen of data.  If fewer
+ * than 32 bytes are provided spaces will be appended to
+ * generate a full screen.
+ */
+static ssize_t vfd_write(struct file *file, const char *buf,
+			 size_t n_bytes, loff_t *pos)
+{
+	int i;
+	int offset;
+	int seq;
+	int retval = 0;
+	struct imon_context *context;
+	const unsigned char vfd_packet6[] = {
+		0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
+	int *data_buf;
+
+	context = (struct imon_context *)file->private_data;
+	if (!context) {
+		err("%s: no context for device", __func__);
+		return -ENODEV;
+	}
+
+	mutex_lock(&context->ctx_lock);
+
+	if (!context->dev_present) {
+		err("%s: no iMON device present", __func__);
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) {
+		err("%s: invalid payload size", __func__);
+		retval = -EINVAL;
+		goto exit;
+	}
+
+	data_buf = memdup_user(buf, n_bytes);
+	if (IS_ERR(data_buf)) {
+		retval = PTR_ERR(data_buf);
+		goto exit;
+	}
+
+	memcpy(context->tx.data_buf, data_buf, n_bytes);
+
+	/* Pad with spaces */
+	for (i = n_bytes; i < IMON_DATA_BUF_SZ - 3; ++i)
+		context->tx.data_buf[i] = ' ';
+
+	for (i = IMON_DATA_BUF_SZ - 3; i < IMON_DATA_BUF_SZ; ++i)
+		context->tx.data_buf[i] = 0xFF;
+
+	offset = 0;
+	seq = 0;
+
+	do {
+		memcpy(context->usb_tx_buf, context->tx.data_buf + offset, 7);
+		context->usb_tx_buf[7] = (unsigned char) seq;
+
+		retval = send_packet(context);
+		if (retval) {
+			err("%s: send packet failed for packet #%d",
+					__func__, seq/2);
+			goto exit;
+		} else {
+			seq += 2;
+			offset += 7;
+		}
+
+	} while (offset < IMON_DATA_BUF_SZ);
+
+	if (context->vfd_proto_6p) {
+		/* Send packet #6 */
+		memcpy(context->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6));
+		context->usb_tx_buf[7] = (unsigned char) seq;
+		retval = send_packet(context);
+		if (retval)
+			err("%s: send packet failed for packet #%d",
+					__func__, seq/2);
+	}
+
+exit:
+	mutex_unlock(&context->ctx_lock);
+
+	return (!retval) ? n_bytes : retval;
+}
+
+/**
+ * Callback function for USB core API: transmit data
+ */
+static void usb_tx_callback(struct urb *urb)
+{
+	struct imon_context *context;
+
+	if (!urb)
+		return;
+	context = (struct imon_context *)urb->context;
+	if (!context)
+		return;
+
+	context->tx.status = urb->status;
+
+	/* notify waiters that write has finished */
+	atomic_set(&context->tx.busy, 0);
+	complete(&context->tx.finished);
+
+	return;
+}
+
+/**
+ * Called by lirc_dev when the application opens /dev/lirc
+ */
+static int ir_open(void *data)
+{
+	int retval = 0;
+	struct imon_context *context;
+
+	/* prevent races with disconnect */
+	mutex_lock(&driver_lock);
+
+	context = (struct imon_context *)data;
+
+	/* initial IR protocol decode variables */
+	context->rx.count = 0;
+	context->rx.initial_space = 1;
+	context->rx.prev_bit = 0;
+
+	context->ir_isopen = 1;
+	dev_info(context->driver->dev, "IR port opened\n");
+
+	mutex_unlock(&driver_lock);
+	return retval;
+}
+
+/**
+ * Called by lirc_dev when the application closes /dev/lirc
+ */
+static void ir_close(void *data)
+{
+	struct imon_context *context;
+
+	context = (struct imon_context *)data;
+	if (!context) {
+		err("%s: no context for device", __func__);
+		return;
+	}
+
+	mutex_lock(&context->ctx_lock);
+
+	context->ir_isopen = 0;
+	dev_info(context->driver->dev, "IR port closed\n");
+
+	if (!context->dev_present) {
+		/*
+		 * Device disconnected while IR port was still open. Driver
+		 * was not deregistered at disconnect time, so do it now.
+		 */
+		deregister_from_lirc(context);
+
+		if (!context->display_isopen) {
+			mutex_unlock(&context->ctx_lock);
+			free_imon_context(context);
+			return;
+		}
+		/*
+		 * If display port is open, context will be deleted by
+		 * display_close
+		 */
+	}
+
+	mutex_unlock(&context->ctx_lock);
+	return;
+}
+
+/**
+ * Convert bit count to time duration (in us) and submit
+ * the value to lirc_dev.
+ */
+static void submit_data(struct imon_context *context)
+{
+	unsigned char buf[4];
+	int value = context->rx.count;
+	int i;
+
+	dev_dbg(context->driver->dev, "submitting data to LIRC\n");
+
+	value *= BIT_DURATION;
+	value &= PULSE_MASK;
+	if (context->rx.prev_bit)
+		value |= PULSE_BIT;
+
+	for (i = 0; i < 4; ++i)
+		buf[i] = value>>(i*8);
+
+	lirc_buffer_write(context->driver->rbuf, buf);
+	wake_up(&context->driver->rbuf->wait_poll);
+	return;
+}
+
+static inline int tv2int(const struct timeval *a, const struct timeval *b)
+{
+	int usecs = 0;
+	int sec   = 0;
+
+	if (b->tv_usec > a->tv_usec) {
+		usecs = 1000000;
+		sec--;
+	}
+
+	usecs += a->tv_usec - b->tv_usec;
+
+	sec += a->tv_sec - b->tv_sec;
+	sec *= 1000;
+	usecs /= 1000;
+	sec += usecs;
+
+	if (sec < 0)
+		sec = 1000;
+
+	return sec;
+}
+
+/**
+ * Process the incoming packet
+ */
+static void imon_incoming_packet(struct imon_context *context,
+				 struct urb *urb, int intf)
+{
+	int len = urb->actual_length;
+	unsigned char *buf = urb->transfer_buffer;
+	struct device *dev = context->driver->dev;
+	int octet, bit;
+	unsigned char mask;
+	int i, chunk_num;
+
+	/*
+	 * just bail out if no listening IR client
+	 */
+	if (!context->ir_isopen)
+		return;
+
+	if (len != 8) {
+		dev_warn(dev, "imon %s: invalid incoming packet "
+			 "size (len = %d, intf%d)\n", __func__, len, intf);
+		return;
+	}
+
+	if (debug) {
+		printk(KERN_INFO "raw packet: ");
+		for (i = 0; i < len; ++i)
+			printk("%02x ", buf[i]);
+		printk("\n");
+	}
+
+	/*
+	 * Translate received data to pulse and space lengths.
+	 * Received data is active low, i.e. pulses are 0 and
+	 * spaces are 1.
+	 *
+	 * My original algorithm was essentially similar to
+	 * Changwoo Ryu's with the exception that he switched
+	 * the incoming bits to active high and also fed an
+	 * initial space to LIRC at the start of a new sequence
+	 * if the previous bit was a pulse.
+	 *
+	 * I've decided to adopt his algorithm.
+	 */
+
+	if (buf[7] == 1 && context->rx.initial_space) {
+		/* LIRC requires a leading space */
+		context->rx.prev_bit = 0;
+		context->rx.count = 4;
+		submit_data(context);
+		context->rx.count = 0;
+	}
+
+	for (octet = 0; octet < 5; ++octet) {
+		mask = 0x80;
+		for (bit = 0; bit < 8; ++bit) {
+			int curr_bit = !(buf[octet] & mask);
+			if (curr_bit != context->rx.prev_bit) {
+				if (context->rx.count) {
+					submit_data(context);
+					context->rx.count = 0;
+				}
+				context->rx.prev_bit = curr_bit;
+			}
+			++context->rx.count;
+			mask >>= 1;
+		}
+	}
+
+	if (chunk_num == 10) {
+		if (context->rx.count) {
+			submit_data(context);
+			context->rx.count = 0;
+		}
+		context->rx.initial_space = context->rx.prev_bit;
+	}
+}
+
+/**
+ * Callback function for USB core API: receive data
+ */
+static void usb_rx_callback(struct urb *urb)
+{
+	struct imon_context *context;
+	unsigned char *buf;
+	int len;
+	int intfnum = 0;
+
+	if (!urb)
+		return;
+
+	context = (struct imon_context *)urb->context;
+	if (!context)
+		return;
+
+	buf = urb->transfer_buffer;
+	len = urb->actual_length;
+
+	switch (urb->status) {
+	case -ENOENT:		/* usbcore unlink successful! */
+		return;
+
+	case 0:
+		imon_incoming_packet(context, urb, intfnum);
+		break;
+
+	default:
+		dev_warn(context->driver->dev, "imon %s: status(%d): ignored\n",
+			 __func__, urb->status);
+		break;
+	}
+
+	usb_submit_urb(context->rx_urb, GFP_ATOMIC);
+
+	return;
+}
+
+/**
+ * Callback function for USB core API: Probe
+ */
+static int imon_probe(struct usb_interface *interface,
+		      const struct usb_device_id *id)
+{
+	struct usb_device *usbdev = NULL;
+	struct usb_host_interface *iface_desc = NULL;
+	struct usb_endpoint_descriptor *rx_endpoint = NULL;
+	struct usb_endpoint_descriptor *tx_endpoint = NULL;
+	struct urb *rx_urb = NULL;
+	struct urb *tx_urb = NULL;
+	struct lirc_driver *driver = NULL;
+	struct lirc_buffer *rbuf = NULL;
+	struct device *dev = &interface->dev;
+	int ifnum;
+	int lirc_minor = 0;
+	int num_endpts;
+	int retval = 0;
+	int display_ep_found = 0;
+	int ir_ep_found = 0;
+	int alloc_status = 0;
+	int vfd_proto_6p = 0;
+	int code_length;
+	struct imon_context *context = NULL;
+	int i;
+	u16 vendor, product;
+
+	context = kzalloc(sizeof(struct imon_context), GFP_KERNEL);
+	if (!context) {
+		err("%s: kzalloc failed for context", __func__);
+		alloc_status = 1;
+		goto alloc_status_switch;
+	}
+
+	/*
+	 * Try to auto-detect the type of display if the user hasn't set
+	 * it by hand via the display_type modparam. Default is VFD.
+	 */
+	if (usb_match_id(interface, ir_only_list))
+		context->display = 0;
+	else
+		context->display = 1;
+
+	code_length = BUF_CHUNK_SIZE * 8;
+
+	usbdev     = usb_get_dev(interface_to_usbdev(interface));
+	iface_desc = interface->cur_altsetting;
+	num_endpts = iface_desc->desc.bNumEndpoints;
+	ifnum      = iface_desc->desc.bInterfaceNumber;
+	vendor     = le16_to_cpu(usbdev->descriptor.idVendor);
+	product    = le16_to_cpu(usbdev->descriptor.idProduct);
+
+	dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n",
+		__func__, vendor, product, ifnum);
+
+	/* prevent races probing devices w/multiple interfaces */
+	mutex_lock(&driver_lock);
+
+	/*
+	 * Scan the endpoint list and set:
+	 *	first input endpoint = IR endpoint
+	 *	first output endpoint = display endpoint
+	 */
+	for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
+		struct usb_endpoint_descriptor *ep;
+		int ep_dir;
+		int ep_type;
+		ep = &iface_desc->endpoint[i].desc;
+		ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+		ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+		if (!ir_ep_found &&
+			ep_dir == USB_DIR_IN &&
+			ep_type == USB_ENDPOINT_XFER_INT) {
+
+			rx_endpoint = ep;
+			ir_ep_found = 1;
+			dev_dbg(dev, "%s: found IR endpoint\n", __func__);
+
+		} else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
+			   ep_type == USB_ENDPOINT_XFER_INT) {
+			tx_endpoint = ep;
+			display_ep_found = 1;
+			dev_dbg(dev, "%s: found display endpoint\n", __func__);
+		}
+	}
+
+	/*
+	 * Some iMON receivers have no display. Unfortunately, it seems
+	 * that SoundGraph recycles device IDs between devices both with
+	 * and without... :\
+	 */
+	if (context->display == 0) {
+		display_ep_found = 0;
+		dev_dbg(dev, "%s: device has no display\n", __func__);
+	}
+
+	/* Input endpoint is mandatory */
+	if (!ir_ep_found) {
+		err("%s: no valid input (IR) endpoint found.", __func__);
+		retval = -ENODEV;
+		alloc_status = 2;
+		goto alloc_status_switch;
+	}
+
+	/* Determine if display requires 6 packets */
+	if (display_ep_found) {
+		if (usb_match_id(interface, vfd_proto_6p_list))
+			vfd_proto_6p = 1;
+
+		dev_dbg(dev, "%s: vfd_proto_6p: %d\n",
+			__func__, vfd_proto_6p);
+	}
+
+	driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+	if (!driver) {
+		err("%s: kzalloc failed for lirc_driver", __func__);
+		alloc_status = 2;
+		goto alloc_status_switch;
+	}
+	rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+	if (!rbuf) {
+		err("%s: kmalloc failed for lirc_buffer", __func__);
+		alloc_status = 3;
+		goto alloc_status_switch;
+	}
+	if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
+		err("%s: lirc_buffer_init failed", __func__);
+		alloc_status = 4;
+		goto alloc_status_switch;
+	}
+	rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!rx_urb) {
+		err("%s: usb_alloc_urb failed for IR urb", __func__);
+		alloc_status = 5;
+		goto alloc_status_switch;
+	}
+	tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!tx_urb) {
+		err("%s: usb_alloc_urb failed for display urb",
+		    __func__);
+		alloc_status = 6;
+		goto alloc_status_switch;
+	}
+
+	mutex_init(&context->ctx_lock);
+	context->vfd_proto_6p = vfd_proto_6p;
+
+	strcpy(driver->name, MOD_NAME);
+	driver->minor = -1;
+	driver->code_length = sizeof(int) * 8;
+	driver->sample_rate = 0;
+	driver->features = LIRC_CAN_REC_MODE2;
+	driver->data = context;
+	driver->rbuf = rbuf;
+	driver->set_use_inc = ir_open;
+	driver->set_use_dec = ir_close;
+	driver->dev = &interface->dev;
+	driver->owner = THIS_MODULE;
+
+	mutex_lock(&context->ctx_lock);
+
+	context->driver = driver;
+	/* start out in keyboard mode */
+
+	lirc_minor = lirc_register_driver(driver);
+	if (lirc_minor < 0) {
+		err("%s: lirc_register_driver failed", __func__);
+		alloc_status = 7;
+		goto alloc_status_switch;
+	} else
+		dev_info(dev, "Registered iMON driver "
+			 "(lirc minor: %d)\n", lirc_minor);
+
+	/* Needed while unregistering! */
+	driver->minor = lirc_minor;
+
+	context->usbdev = usbdev;
+	context->dev_present = 1;
+	context->rx_endpoint = rx_endpoint;
+	context->rx_urb = rx_urb;
+
+	/*
+	 * tx is used to send characters to lcd/vfd, associate RF
+	 * remotes, set IR protocol, and maybe more...
+	 */
+	context->tx_endpoint = tx_endpoint;
+	context->tx_urb = tx_urb;
+
+	if (display_ep_found)
+		context->display = 1;
+
+	usb_fill_int_urb(context->rx_urb, context->usbdev,
+		usb_rcvintpipe(context->usbdev,
+			context->rx_endpoint->bEndpointAddress),
+		context->usb_rx_buf, sizeof(context->usb_rx_buf),
+		usb_rx_callback, context,
+		context->rx_endpoint->bInterval);
+
+	retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
+
+	if (retval) {
+		err("%s: usb_submit_urb failed for intf0 (%d)",
+		    __func__, retval);
+		mutex_unlock(&context->ctx_lock);
+		goto exit;
+	}
+
+	usb_set_intfdata(interface, context);
+
+	if (context->display && ifnum == 0) {
+		dev_dbg(dev, "%s: Registering iMON display with sysfs\n",
+			__func__);
+
+		if (usb_register_dev(interface, &imon_class)) {
+			/* Not a fatal error, so ignore */
+			dev_info(dev, "%s: could not get a minor number for "
+				 "display\n", __func__);
+		}
+	}
+
+	dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
+		 "usb<%d:%d> initialized\n", vendor, product, ifnum,
+		 usbdev->bus->busnum, usbdev->devnum);
+
+alloc_status_switch:
+	mutex_unlock(&context->ctx_lock);
+
+	switch (alloc_status) {
+	case 7:
+		usb_free_urb(tx_urb);
+	case 6:
+		usb_free_urb(rx_urb);
+	case 5:
+		if (rbuf)
+			lirc_buffer_free(rbuf);
+	case 4:
+		kfree(rbuf);
+	case 3:
+		kfree(driver);
+	case 2:
+		kfree(context);
+		context = NULL;
+	case 1:
+		if (retval != -ENODEV)
+			retval = -ENOMEM;
+		break;
+	case 0:
+		retval = 0;
+	}
+
+exit:
+	mutex_unlock(&driver_lock);
+
+	return retval;
+}
+
+/**
+ * Callback function for USB core API: disconnect
+ */
+static void imon_disconnect(struct usb_interface *interface)
+{
+	struct imon_context *context;
+	int ifnum;
+
+	/* prevent races with ir_open()/display_open() */
+	mutex_lock(&driver_lock);
+
+	context = usb_get_intfdata(interface);
+	ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
+
+	mutex_lock(&context->ctx_lock);
+
+	usb_set_intfdata(interface, NULL);
+
+	/* Abort ongoing write */
+	if (atomic_read(&context->tx.busy)) {
+		usb_kill_urb(context->tx_urb);
+		complete_all(&context->tx.finished);
+	}
+
+	context->dev_present = 0;
+	usb_kill_urb(context->rx_urb);
+	if (context->display)
+		usb_deregister_dev(interface, &imon_class);
+
+	if (!context->ir_isopen && !context->dev_present) {
+		deregister_from_lirc(context);
+		mutex_unlock(&context->ctx_lock);
+		if (!context->display_isopen)
+			free_imon_context(context);
+	} else
+		mutex_unlock(&context->ctx_lock);
+
+	mutex_unlock(&driver_lock);
+
+	printk(KERN_INFO "%s: iMON device (intf%d) disconnected\n",
+	       __func__, ifnum);
+}
+
+static int imon_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct imon_context *context = usb_get_intfdata(intf);
+
+	usb_kill_urb(context->rx_urb);
+
+	return 0;
+}
+
+static int imon_resume(struct usb_interface *intf)
+{
+	int rc = 0;
+	struct imon_context *context = usb_get_intfdata(intf);
+
+	usb_fill_int_urb(context->rx_urb, context->usbdev,
+		usb_rcvintpipe(context->usbdev,
+			context->rx_endpoint->bEndpointAddress),
+		context->usb_rx_buf, sizeof(context->usb_rx_buf),
+		usb_rx_callback, context,
+		context->rx_endpoint->bInterval);
+
+	rc = usb_submit_urb(context->rx_urb, GFP_ATOMIC);
+
+	return rc;
+}
+
+static int __init imon_init(void)
+{
+	int rc;
+
+	printk(KERN_INFO MOD_NAME ": " MOD_DESC ", v" MOD_VERSION "\n");
+
+	rc = usb_register(&imon_driver);
+	if (rc) {
+		err("%s: usb register failed(%d)", __func__, rc);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit imon_exit(void)
+{
+	usb_deregister(&imon_driver);
+	printk(KERN_INFO MOD_NAME ": module removed. Goodbye!\n");
+}
+
+module_init(imon_init);
+module_exit(imon_exit);
diff --git a/drivers/staging/lirc/lirc_it87.c b/drivers/staging/lirc/lirc_it87.c
new file mode 100644
index 0000000..09f3696
--- /dev/null
+++ b/drivers/staging/lirc/lirc_it87.c
@@ -0,0 +1,1019 @@
+/*
+ * LIRC driver for ITE IT8712/IT8705 CIR port
+ *
+ * Copyright (C) 2001 Hans-Gunter Lutke Uphues <hg_lu@web.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * ITE IT8705 and IT8712(not tested) and IT8720 CIR-port support for lirc based
+ * via cut and paste from lirc_sir.c (C) 2000 Milan Pikula
+ *
+ * Attention: Sendmode only tested with debugging logs
+ *
+ * 2001/02/27 Christoph Bartelmus <lirc@bartelmus.de> :
+ *   reimplemented read function
+ * 2005/06/05 Andrew Calkin implemented support for Asus Digimatrix,
+ *   based on work of the following member of the Outertrack Digimatrix
+ *   Forum: Art103 <r_tay@hotmail.com>
+ * 2009/12/24 James Edwards <jimbo-lirc@edwardsclan.net> implemeted support
+ *   for ITE8704/ITE8718, on my machine, the DSDT reports 8704, but the
+ *   chip identifies as 18.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <asm/system.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/fcntl.h>
+
+#include <linux/timer.h>
+#include <linux/pnp.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#include "lirc_it87.h"
+
+#ifdef LIRC_IT87_DIGIMATRIX
+static int digimatrix = 1;
+static int it87_freq = 36; /* kHz */
+static int irq = 9;
+#else
+static int digimatrix;
+static int it87_freq = 38; /* kHz */
+static int irq = IT87_CIR_DEFAULT_IRQ;
+#endif
+
+static unsigned long it87_bits_in_byte_out;
+static unsigned long it87_send_counter;
+static unsigned char it87_RXEN_mask = IT87_CIR_RCR_RXEN;
+
+#define RBUF_LEN 1024
+
+#define LIRC_DRIVER_NAME "lirc_it87"
+
+/* timeout for sequences in jiffies (=5/100s) */
+/* must be longer than TIME_CONST */
+#define IT87_TIMEOUT	(HZ*5/100)
+
+/* module parameters */
+static int debug;
+#define dprintk(fmt, args...)					\
+	do {							\
+		if (debug)					\
+			printk(KERN_DEBUG LIRC_DRIVER_NAME ": "	\
+			       fmt, ## args);			\
+	} while (0)
+
+static int io = IT87_CIR_DEFAULT_IOBASE;
+/* receiver demodulator default: off */
+static int it87_enable_demodulator;
+
+static int timer_enabled;
+static DEFINE_SPINLOCK(timer_lock);
+static struct timer_list timerlist;
+/* time of last signal change detected */
+static struct timeval last_tv = {0, 0};
+/* time of last UART data ready interrupt */
+static struct timeval last_intr_tv = {0, 0};
+static int last_value;
+
+static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue);
+
+static DEFINE_SPINLOCK(hardware_lock);
+static DEFINE_SPINLOCK(dev_lock);
+
+static int rx_buf[RBUF_LEN];
+unsigned int rx_tail, rx_head;
+
+static struct pnp_driver it87_pnp_driver;
+
+/* SECTION: Prototypes */
+
+/* Communication with user-space */
+static int lirc_open(struct inode *inode, struct file *file);
+static int lirc_close(struct inode *inode, struct file *file);
+static unsigned int lirc_poll(struct file *file, poll_table *wait);
+static ssize_t lirc_read(struct file *file, char *buf,
+			 size_t count, loff_t *ppos);
+static ssize_t lirc_write(struct file *file, const char *buf,
+			  size_t n, loff_t *pos);
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
+static void add_read_queue(int flag, unsigned long val);
+static int init_chrdev(void);
+static void drop_chrdev(void);
+/* Hardware */
+static irqreturn_t it87_interrupt(int irq, void *dev_id);
+static void send_space(unsigned long len);
+static void send_pulse(unsigned long len);
+static void init_send(void);
+static void terminate_send(unsigned long len);
+static int init_hardware(void);
+static void drop_hardware(void);
+/* Initialisation */
+static int init_port(void);
+static void drop_port(void);
+
+
+/* SECTION: Communication with user-space */
+
+static int lirc_open(struct inode *inode, struct file *file)
+{
+	spin_lock(&dev_lock);
+	if (module_refcount(THIS_MODULE)) {
+		spin_unlock(&dev_lock);
+		return -EBUSY;
+	}
+	spin_unlock(&dev_lock);
+	return 0;
+}
+
+
+static int lirc_close(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+
+static unsigned int lirc_poll(struct file *file, poll_table *wait)
+{
+	poll_wait(file, &lirc_read_queue, wait);
+	if (rx_head != rx_tail)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+
+static ssize_t lirc_read(struct file *file, char *buf,
+			 size_t count, loff_t *ppos)
+{
+	int n = 0;
+	int retval = 0;
+
+	while (n < count) {
+		if (file->f_flags & O_NONBLOCK && rx_head == rx_tail) {
+			retval = -EAGAIN;
+			break;
+		}
+		retval = wait_event_interruptible(lirc_read_queue,
+						  rx_head != rx_tail);
+		if (retval)
+			break;
+
+		if (copy_to_user((void *) buf + n, (void *) (rx_buf + rx_head),
+				 sizeof(int))) {
+			retval = -EFAULT;
+			break;
+		}
+		rx_head = (rx_head + 1) & (RBUF_LEN - 1);
+		n += sizeof(int);
+	}
+	if (n)
+		return n;
+	return retval;
+}
+
+
+static ssize_t lirc_write(struct file *file, const char *buf,
+			  size_t n, loff_t *pos)
+{
+	int i = 0;
+	int *tx_buf;
+
+	if (n % sizeof(int))
+		return -EINVAL;
+	tx_buf = memdup_user(buf, n);
+	if (IS_ERR(tx_buf))
+		return PTR_ERR(tx_buf);
+	n /= sizeof(int);
+	init_send();
+	while (1) {
+		if (i >= n)
+			break;
+		if (tx_buf[i])
+			send_pulse(tx_buf[i]);
+		i++;
+		if (i >= n)
+			break;
+		if (tx_buf[i])
+			send_space(tx_buf[i]);
+		i++;
+	}
+	terminate_send(tx_buf[i - 1]);
+	return n;
+}
+
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+	int retval = 0;
+	unsigned long value = 0;
+	unsigned int ivalue;
+	unsigned long hw_flags;
+
+	if (cmd == LIRC_GET_FEATURES)
+		value = LIRC_CAN_SEND_PULSE |
+			LIRC_CAN_SET_SEND_CARRIER |
+			LIRC_CAN_REC_MODE2;
+	else if (cmd == LIRC_GET_SEND_MODE)
+		value = LIRC_MODE_PULSE;
+	else if (cmd == LIRC_GET_REC_MODE)
+		value = LIRC_MODE_MODE2;
+
+	switch (cmd) {
+	case LIRC_GET_FEATURES:
+	case LIRC_GET_SEND_MODE:
+	case LIRC_GET_REC_MODE:
+		retval = put_user(value, (unsigned long *) arg);
+		break;
+
+	case LIRC_SET_SEND_MODE:
+	case LIRC_SET_REC_MODE:
+		retval = get_user(value, (unsigned long *) arg);
+		break;
+
+	case LIRC_SET_SEND_CARRIER:
+		retval = get_user(ivalue, (unsigned int *) arg);
+		if (retval)
+			return retval;
+		ivalue /= 1000;
+		if (ivalue > IT87_CIR_FREQ_MAX ||
+		    ivalue < IT87_CIR_FREQ_MIN)
+			return -EINVAL;
+
+		it87_freq = ivalue;
+
+		spin_lock_irqsave(&hardware_lock, hw_flags);
+		outb(((inb(io + IT87_CIR_TCR2) & IT87_CIR_TCR2_TXMPW) |
+		      (it87_freq - IT87_CIR_FREQ_MIN) << 3),
+		      io + IT87_CIR_TCR2);
+		spin_unlock_irqrestore(&hardware_lock, hw_flags);
+		dprintk("demodulation frequency: %d kHz\n", it87_freq);
+
+		break;
+
+	default:
+		retval = -EINVAL;
+	}
+
+	if (retval)
+		return retval;
+
+	if (cmd == LIRC_SET_REC_MODE) {
+		if (value != LIRC_MODE_MODE2)
+			retval = -ENOSYS;
+	} else if (cmd == LIRC_SET_SEND_MODE) {
+		if (value != LIRC_MODE_PULSE)
+			retval = -ENOSYS;
+	}
+	return retval;
+}
+
+static void add_read_queue(int flag, unsigned long val)
+{
+	unsigned int new_rx_tail;
+	int newval;
+
+	dprintk("add flag %d with val %lu\n", flag, val);
+
+	newval = val & PULSE_MASK;
+
+	/*
+	 * statistically, pulses are ~TIME_CONST/2 too long. we could
+	 * maybe make this more exact, but this is good enough
+	 */
+	if (flag) {
+		/* pulse */
+		if (newval > TIME_CONST / 2)
+			newval -= TIME_CONST / 2;
+		else /* should not ever happen */
+			newval = 1;
+		newval |= PULSE_BIT;
+	} else
+		newval += TIME_CONST / 2;
+	new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1);
+	if (new_rx_tail == rx_head) {
+		dprintk("Buffer overrun.\n");
+		return;
+	}
+	rx_buf[rx_tail] = newval;
+	rx_tail = new_rx_tail;
+	wake_up_interruptible(&lirc_read_queue);
+}
+
+
+static const struct file_operations lirc_fops = {
+	.owner		= THIS_MODULE,
+	.read		= lirc_read,
+	.write		= lirc_write,
+	.poll		= lirc_poll,
+	.unlocked_ioctl	= lirc_ioctl,
+	.open		= lirc_open,
+	.release	= lirc_close,
+};
+
+static int set_use_inc(void *data)
+{
+       return 0;
+}
+
+static void set_use_dec(void *data)
+{
+}
+
+static struct lirc_driver driver = {
+       .name		= LIRC_DRIVER_NAME,
+       .minor		= -1,
+       .code_length	= 1,
+       .sample_rate	= 0,
+       .data		= NULL,
+       .add_to_buf	= NULL,
+       .set_use_inc	= set_use_inc,
+       .set_use_dec	= set_use_dec,
+       .fops		= &lirc_fops,
+       .dev		= NULL,
+       .owner		= THIS_MODULE,
+};
+
+
+#ifdef MODULE
+static int init_chrdev(void)
+{
+	driver.minor = lirc_register_driver(&driver);
+
+	if (driver.minor < 0) {
+		printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+
+static void drop_chrdev(void)
+{
+	lirc_unregister_driver(driver.minor);
+}
+#endif
+
+
+/* SECTION: Hardware */
+static long delta(struct timeval *tv1, struct timeval *tv2)
+{
+	unsigned long deltv;
+
+	deltv = tv2->tv_sec - tv1->tv_sec;
+	if (deltv > 15)
+		deltv = 0xFFFFFF;
+	else
+		deltv = deltv*1000000 + tv2->tv_usec - tv1->tv_usec;
+	return deltv;
+}
+
+static void it87_timeout(unsigned long data)
+{
+	unsigned long flags;
+
+	/* avoid interference with interrupt */
+	spin_lock_irqsave(&timer_lock, flags);
+
+	if (digimatrix) {
+		/* We have timed out. Disable the RX mechanism. */
+
+		outb((inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN) |
+		     IT87_CIR_RCR_RXACT, io + IT87_CIR_RCR);
+		if (it87_RXEN_mask)
+			outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN,
+			     io + IT87_CIR_RCR);
+		dprintk(" TIMEOUT\n");
+		timer_enabled = 0;
+
+		/* fifo clear */
+		outb(inb(io + IT87_CIR_TCR1) | IT87_CIR_TCR1_FIFOCLR,
+		     io+IT87_CIR_TCR1);
+
+	} else {
+		/*
+		 * if last received signal was a pulse, but receiving stopped
+		 * within the 9 bit frame, we need to finish this pulse and
+		 * simulate a signal change to from pulse to space. Otherwise
+		 * upper layers will receive two sequences next time.
+		 */
+
+		if (last_value) {
+			unsigned long pulse_end;
+
+			/* determine 'virtual' pulse end: */
+			pulse_end = delta(&last_tv, &last_intr_tv);
+			dprintk("timeout add %d for %lu usec\n",
+				last_value, pulse_end);
+			add_read_queue(last_value, pulse_end);
+			last_value = 0;
+			last_tv = last_intr_tv;
+		}
+	}
+	spin_unlock_irqrestore(&timer_lock, flags);
+}
+
+static irqreturn_t it87_interrupt(int irq, void *dev_id)
+{
+	unsigned char data;
+	struct timeval curr_tv;
+	static unsigned long deltv;
+	unsigned long deltintrtv;
+	unsigned long flags, hw_flags;
+	int iir, lsr;
+	int fifo = 0;
+	static char lastbit;
+	char bit;
+
+	/* Bit duration in microseconds */
+	const unsigned long bit_duration = 1000000ul /
+		(115200 / IT87_CIR_BAUDRATE_DIVISOR);
+
+
+	iir = inb(io + IT87_CIR_IIR);
+
+	switch (iir & IT87_CIR_IIR_IID) {
+	case 0x4:
+	case 0x6:
+		lsr = inb(io + IT87_CIR_RSR) & (IT87_CIR_RSR_RXFTO |
+						IT87_CIR_RSR_RXFBC);
+		fifo = lsr & IT87_CIR_RSR_RXFBC;
+		dprintk("iir: 0x%x fifo: 0x%x\n", iir, lsr);
+
+		/* avoid interference with timer */
+		spin_lock_irqsave(&timer_lock, flags);
+		spin_lock_irqsave(&hardware_lock, hw_flags);
+		if (digimatrix) {
+			static unsigned long acc_pulse;
+			static unsigned long acc_space;
+
+			do {
+				data = inb(io + IT87_CIR_DR);
+				data = ~data;
+				fifo--;
+				if (data != 0x00) {
+					if (timer_enabled)
+						del_timer(&timerlist);
+					/*
+					 * start timer for end of
+					 * sequence detection
+					 */
+					timerlist.expires = jiffies +
+							    IT87_TIMEOUT;
+					add_timer(&timerlist);
+					timer_enabled = 1;
+				}
+				/* Loop through */
+				for (bit = 0; bit < 8; ++bit) {
+					if ((data >> bit) & 1) {
+						++acc_pulse;
+						if (lastbit == 0) {
+							add_read_queue(0,
+								acc_space *
+								 bit_duration);
+							acc_space = 0;
+						}
+					} else {
+						++acc_space;
+						if (lastbit == 1) {
+							add_read_queue(1,
+								acc_pulse *
+								 bit_duration);
+							acc_pulse = 0;
+						}
+					}
+					lastbit = (data >> bit) & 1;
+				}
+
+			} while (fifo != 0);
+		} else { /* Normal Operation */
+			do {
+				del_timer(&timerlist);
+				data = inb(io + IT87_CIR_DR);
+
+				dprintk("data=%02x\n", data);
+				do_gettimeofday(&curr_tv);
+				deltv = delta(&last_tv, &curr_tv);
+				deltintrtv = delta(&last_intr_tv, &curr_tv);
+
+				dprintk("t %lu , d %d\n",
+					deltintrtv, (int)data);
+
+				/*
+				 * if nothing came in last 2 cycles,
+				 * it was gap
+				 */
+				if (deltintrtv > TIME_CONST * 2) {
+					if (last_value) {
+						dprintk("GAP\n");
+
+						/* simulate signal change */
+						add_read_queue(last_value,
+							       deltv -
+							       deltintrtv);
+						last_value = 0;
+						last_tv.tv_sec =
+							last_intr_tv.tv_sec;
+						last_tv.tv_usec =
+							last_intr_tv.tv_usec;
+						deltv = deltintrtv;
+					}
+				}
+				data = 1;
+				if (data ^ last_value) {
+					/*
+					 * deltintrtv > 2*TIME_CONST,
+					 * remember ? the other case is
+					 * timeout
+					 */
+					add_read_queue(last_value,
+						       deltv-TIME_CONST);
+					last_value = data;
+					last_tv = curr_tv;
+					if (last_tv.tv_usec >= TIME_CONST)
+						last_tv.tv_usec -= TIME_CONST;
+					else {
+						last_tv.tv_sec--;
+						last_tv.tv_usec += 1000000 -
+							TIME_CONST;
+					}
+				}
+				last_intr_tv = curr_tv;
+				if (data) {
+					/*
+					 * start timer for end of
+					 * sequence detection
+					 */
+					timerlist.expires =
+						jiffies + IT87_TIMEOUT;
+					add_timer(&timerlist);
+				}
+				outb((inb(io + IT87_CIR_RCR) &
+				     ~IT87_CIR_RCR_RXEN) |
+				     IT87_CIR_RCR_RXACT,
+				     io + IT87_CIR_RCR);
+				if (it87_RXEN_mask)
+					outb(inb(io + IT87_CIR_RCR) |
+					     IT87_CIR_RCR_RXEN,
+					     io + IT87_CIR_RCR);
+				fifo--;
+			} while (fifo != 0);
+		}
+		spin_unlock_irqrestore(&hardware_lock, hw_flags);
+		spin_unlock_irqrestore(&timer_lock, flags);
+
+		return IRQ_RETVAL(IRQ_HANDLED);
+
+	default:
+		/* not our irq */
+		dprintk("unknown IRQ (shouldn't happen) !!\n");
+		return IRQ_RETVAL(IRQ_NONE);
+	}
+}
+
+
+static void send_it87(unsigned long len, unsigned long stime,
+		      unsigned char send_byte, unsigned int count_bits)
+{
+	long count = len / stime;
+	long time_left = 0;
+	static unsigned char byte_out;
+	unsigned long hw_flags;
+
+	dprintk("%s: len=%ld, sb=%d\n", __func__, len, send_byte);
+
+	time_left = (long)len - (long)count * (long)stime;
+	count += ((2 * time_left) / stime);
+	while (count) {
+		long i = 0;
+		for (i = 0; i < count_bits; i++) {
+			byte_out = (byte_out << 1) | (send_byte & 1);
+			it87_bits_in_byte_out++;
+		}
+		if (it87_bits_in_byte_out == 8) {
+			dprintk("out=0x%x, tsr_txfbc: 0x%x\n",
+				byte_out,
+				inb(io + IT87_CIR_TSR) &
+				IT87_CIR_TSR_TXFBC);
+
+			while ((inb(io + IT87_CIR_TSR) &
+				IT87_CIR_TSR_TXFBC) >= IT87_CIR_FIFO_SIZE)
+				;
+
+			spin_lock_irqsave(&hardware_lock, hw_flags);
+			outb(byte_out, io + IT87_CIR_DR);
+			spin_unlock_irqrestore(&hardware_lock, hw_flags);
+
+			it87_bits_in_byte_out = 0;
+			it87_send_counter++;
+			byte_out = 0;
+		}
+		count--;
+	}
+}
+
+
+/*TODO: maybe exchange space and pulse because it8705 only modulates 0-bits */
+
+static void send_space(unsigned long len)
+{
+	send_it87(len, TIME_CONST, IT87_CIR_SPACE, IT87_CIR_BAUDRATE_DIVISOR);
+}
+
+static void send_pulse(unsigned long len)
+{
+	send_it87(len, TIME_CONST, IT87_CIR_PULSE, IT87_CIR_BAUDRATE_DIVISOR);
+}
+
+
+static void init_send()
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hardware_lock, flags);
+	/* RXEN=0: receiver disable */
+	it87_RXEN_mask = 0;
+	outb(inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN,
+	     io + IT87_CIR_RCR);
+	spin_unlock_irqrestore(&hardware_lock, flags);
+	it87_bits_in_byte_out = 0;
+	it87_send_counter = 0;
+}
+
+
+static void terminate_send(unsigned long len)
+{
+	unsigned long flags;
+	unsigned long last = 0;
+
+	last = it87_send_counter;
+	/* make sure all necessary data has been sent */
+	while (last == it87_send_counter)
+		send_space(len);
+	/* wait until all data sent */
+	while ((inb(io + IT87_CIR_TSR) & IT87_CIR_TSR_TXFBC) != 0)
+		;
+	/* then re-enable receiver */
+	spin_lock_irqsave(&hardware_lock, flags);
+	it87_RXEN_mask = IT87_CIR_RCR_RXEN;
+	outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN,
+	     io + IT87_CIR_RCR);
+	spin_unlock_irqrestore(&hardware_lock, flags);
+}
+
+
+static int init_hardware(void)
+{
+	unsigned long flags;
+	unsigned char it87_rcr = 0;
+
+	spin_lock_irqsave(&hardware_lock, flags);
+	/* init cir-port */
+	/* enable r/w-access to Baudrate-Register */
+	outb(IT87_CIR_IER_BR, io + IT87_CIR_IER);
+	outb(IT87_CIR_BAUDRATE_DIVISOR % 0x100, io+IT87_CIR_BDLR);
+	outb(IT87_CIR_BAUDRATE_DIVISOR / 0x100, io+IT87_CIR_BDHR);
+	/* Baudrate Register off, define IRQs: Input only */
+	if (digimatrix) {
+		outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RFOIE, io + IT87_CIR_IER);
+		/* RX: HCFS=0, RXDCR = 001b (33,75..38,25 kHz), RXEN=1 */
+	} else {
+		outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RDAIE, io + IT87_CIR_IER);
+		/* RX: HCFS=0, RXDCR = 001b (35,6..40,3 kHz), RXEN=1 */
+	}
+	it87_rcr = (IT87_CIR_RCR_RXEN & it87_RXEN_mask) | 0x1;
+	if (it87_enable_demodulator)
+		it87_rcr |= IT87_CIR_RCR_RXEND;
+	outb(it87_rcr, io + IT87_CIR_RCR);
+	if (digimatrix) {
+		/* Set FIFO depth to 1 byte, and disable TX */
+		outb(inb(io + IT87_CIR_TCR1) |  0x00,
+		     io + IT87_CIR_TCR1);
+
+		/*
+		 * TX: it87_freq (36kHz), 'reserved' sensitivity
+		 * setting (0x00)
+		 */
+		outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x00,
+		     io + IT87_CIR_TCR2);
+	} else {
+		/* TX: 38kHz, 13,3us (pulse-width) */
+		outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x06,
+		     io + IT87_CIR_TCR2);
+	}
+	spin_unlock_irqrestore(&hardware_lock, flags);
+	return 0;
+}
+
+
+static void drop_hardware(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hardware_lock, flags);
+	disable_irq(irq);
+	/* receiver disable */
+	it87_RXEN_mask = 0;
+	outb(0x1, io + IT87_CIR_RCR);
+	/* turn off irqs */
+	outb(0, io + IT87_CIR_IER);
+	/* fifo clear */
+	outb(IT87_CIR_TCR1_FIFOCLR, io+IT87_CIR_TCR1);
+	/* reset */
+	outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER);
+	enable_irq(irq);
+	spin_unlock_irqrestore(&hardware_lock, flags);
+}
+
+
+static unsigned char it87_read(unsigned char port)
+{
+	outb(port, IT87_ADRPORT);
+	return inb(IT87_DATAPORT);
+}
+
+
+static void it87_write(unsigned char port, unsigned char data)
+{
+	outb(port, IT87_ADRPORT);
+	outb(data, IT87_DATAPORT);
+}
+
+
+/* SECTION: Initialisation */
+
+static int init_port(void)
+{
+	unsigned long hw_flags;
+	int retval = 0;
+
+	unsigned char init_bytes[4] = IT87_INIT;
+	unsigned char it87_chipid = 0;
+	unsigned char ldn = 0;
+	unsigned int  it87_io = 0;
+	unsigned int  it87_irq = 0;
+
+	/* Enter MB PnP Mode */
+	outb(init_bytes[0], IT87_ADRPORT);
+	outb(init_bytes[1], IT87_ADRPORT);
+	outb(init_bytes[2], IT87_ADRPORT);
+	outb(init_bytes[3], IT87_ADRPORT);
+
+	/* 8712 or 8705 ? */
+	it87_chipid = it87_read(IT87_CHIP_ID1);
+	if (it87_chipid != 0x87) {
+		retval = -ENXIO;
+		return retval;
+	}
+	it87_chipid = it87_read(IT87_CHIP_ID2);
+	if ((it87_chipid != 0x05) &&
+		(it87_chipid != 0x12) &&
+		(it87_chipid != 0x18) &&
+		(it87_chipid != 0x20)) {
+		printk(KERN_INFO LIRC_DRIVER_NAME
+		       ": no IT8704/05/12/18/20 found (claimed IT87%02x), "
+		       "exiting..\n", it87_chipid);
+		retval = -ENXIO;
+		return retval;
+	}
+	printk(KERN_INFO LIRC_DRIVER_NAME
+	       ": found IT87%02x.\n",
+	       it87_chipid);
+
+	/* get I/O-Port and IRQ */
+	if (it87_chipid == 0x12 || it87_chipid == 0x18)
+		ldn = IT8712_CIR_LDN;
+	else
+		ldn = IT8705_CIR_LDN;
+	it87_write(IT87_LDN, ldn);
+
+	it87_io = it87_read(IT87_CIR_BASE_MSB) * 256 +
+		  it87_read(IT87_CIR_BASE_LSB);
+	if (it87_io == 0) {
+		if (io == 0)
+			io = IT87_CIR_DEFAULT_IOBASE;
+		printk(KERN_INFO LIRC_DRIVER_NAME
+		       ": set default io 0x%x\n",
+		       io);
+		it87_write(IT87_CIR_BASE_MSB, io / 0x100);
+		it87_write(IT87_CIR_BASE_LSB, io % 0x100);
+	} else
+		io = it87_io;
+
+	it87_irq = it87_read(IT87_CIR_IRQ);
+	if (digimatrix || it87_irq == 0) {
+		if (irq == 0)
+			irq = IT87_CIR_DEFAULT_IRQ;
+		printk(KERN_INFO LIRC_DRIVER_NAME
+		       ": set default irq 0x%x\n",
+		       irq);
+		it87_write(IT87_CIR_IRQ, irq);
+	} else
+		irq = it87_irq;
+
+	spin_lock_irqsave(&hardware_lock, hw_flags);
+	/* reset */
+	outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER);
+	/* fifo clear */
+	outb(IT87_CIR_TCR1_FIFOCLR |
+	     /*	     IT87_CIR_TCR1_ILE | */
+	     IT87_CIR_TCR1_TXRLE |
+	     IT87_CIR_TCR1_TXENDF, io+IT87_CIR_TCR1);
+	spin_unlock_irqrestore(&hardware_lock, hw_flags);
+
+	/* get I/O port access and IRQ line */
+	if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) {
+		printk(KERN_ERR LIRC_DRIVER_NAME
+		       ": i/o port 0x%.4x already in use.\n", io);
+		/* Leaving MB PnP Mode */
+		it87_write(IT87_CFGCTRL, 0x2);
+		return -EBUSY;
+	}
+
+	/* activate CIR-Device */
+	it87_write(IT87_CIR_ACT, 0x1);
+
+	/* Leaving MB PnP Mode */
+	it87_write(IT87_CFGCTRL, 0x2);
+
+	retval = request_irq(irq, it87_interrupt, 0 /*IRQF_DISABLED*/,
+			     LIRC_DRIVER_NAME, NULL);
+	if (retval < 0) {
+		printk(KERN_ERR LIRC_DRIVER_NAME
+		       ": IRQ %d already in use.\n",
+		       irq);
+		release_region(io, 8);
+		return retval;
+	}
+
+	printk(KERN_INFO LIRC_DRIVER_NAME
+	       ": I/O port 0x%.4x, IRQ %d.\n", io, irq);
+
+	init_timer(&timerlist);
+	timerlist.function = it87_timeout;
+	timerlist.data = 0xabadcafe;
+
+	return 0;
+}
+
+
+static void drop_port(void)
+{
+#if 0
+	unsigned char init_bytes[4] = IT87_INIT;
+
+	/* Enter MB PnP Mode */
+	outb(init_bytes[0], IT87_ADRPORT);
+	outb(init_bytes[1], IT87_ADRPORT);
+	outb(init_bytes[2], IT87_ADRPORT);
+	outb(init_bytes[3], IT87_ADRPORT);
+
+	/* deactivate CIR-Device */
+	it87_write(IT87_CIR_ACT, 0x0);
+
+	/* Leaving MB PnP Mode */
+	it87_write(IT87_CFGCTRL, 0x2);
+#endif
+
+	del_timer_sync(&timerlist);
+	free_irq(irq, NULL);
+	release_region(io, 8);
+}
+
+
+static int init_lirc_it87(void)
+{
+	int retval;
+
+	init_waitqueue_head(&lirc_read_queue);
+	retval = init_port();
+	if (retval < 0)
+		return retval;
+	init_hardware();
+	printk(KERN_INFO LIRC_DRIVER_NAME ": Installed.\n");
+	return 0;
+}
+
+static int it87_probe(struct pnp_dev *pnp_dev,
+		      const struct pnp_device_id *dev_id)
+{
+	int retval;
+
+	driver.dev = &pnp_dev->dev;
+
+	retval = init_chrdev();
+	if (retval < 0)
+		return retval;
+
+	retval = init_lirc_it87();
+	if (retval)
+		goto init_lirc_it87_failed;
+
+	return 0;
+
+init_lirc_it87_failed:
+	drop_chrdev();
+
+	return retval;
+}
+
+static int __init lirc_it87_init(void)
+{
+	return pnp_register_driver(&it87_pnp_driver);
+}
+
+
+static void __exit lirc_it87_exit(void)
+{
+	drop_hardware();
+	drop_chrdev();
+	drop_port();
+	pnp_unregister_driver(&it87_pnp_driver);
+	printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
+}
+
+/* SECTION: PNP for ITE8704/18 */
+
+static const struct pnp_device_id pnp_dev_table[] = {
+	{"ITE8704", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
+
+static struct pnp_driver it87_pnp_driver = {
+	.name           = LIRC_DRIVER_NAME,
+	.id_table       = pnp_dev_table,
+	.probe		= it87_probe,
+};
+
+module_init(lirc_it87_init);
+module_exit(lirc_it87_exit);
+
+MODULE_DESCRIPTION("LIRC driver for ITE IT8704/05/12/18/20 CIR port");
+MODULE_AUTHOR("Hans-Gunter Lutke Uphues");
+MODULE_LICENSE("GPL");
+
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O base address (default: 0x310)");
+
+module_param(irq, int, S_IRUGO);
+#ifdef LIRC_IT87_DIGIMATRIX
+MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 9)");
+#else
+MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 7)");
+#endif
+
+module_param(it87_enable_demodulator, bool, S_IRUGO);
+MODULE_PARM_DESC(it87_enable_demodulator,
+		 "Receiver demodulator enable/disable (1/0), default: 0");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
+module_param(digimatrix, bool, S_IRUGO | S_IWUSR);
+#ifdef LIRC_IT87_DIGIMATRIX
+MODULE_PARM_DESC(digimatrix,
+	"Asus Digimatrix it87 compat. enable/disable (1/0), default: 1");
+#else
+MODULE_PARM_DESC(digimatrix,
+	"Asus Digimatrix it87 compat. enable/disable (1/0), default: 0");
+#endif
+
+
+module_param(it87_freq, int, S_IRUGO);
+#ifdef LIRC_IT87_DIGIMATRIX
+MODULE_PARM_DESC(it87_freq,
+    "Carrier demodulator frequency (kHz), (default: 36)");
+#else
+MODULE_PARM_DESC(it87_freq,
+    "Carrier demodulator frequency (kHz), (default: 38)");
+#endif
diff --git a/drivers/staging/lirc/lirc_it87.h b/drivers/staging/lirc/lirc_it87.h
new file mode 100644
index 0000000..cf021c8
--- /dev/null
+++ b/drivers/staging/lirc/lirc_it87.h
@@ -0,0 +1,116 @@
+/* lirc_it87.h */
+/* SECTION: Definitions */
+
+/********************************* ITE IT87xx ************************/
+
+/* based on the following documentation from ITE:
+   a) IT8712F Preliminary CIR Programming Guide V0.1
+   b) IT8705F Simple LPC I/O Preliminary Specification V0.3
+   c) IT8712F EC-LPC I/O Preliminary Specification V0.5
+*/
+
+/* IT8712/05 Ports: */
+#define IT87_ADRPORT      0x2e
+#define IT87_DATAPORT     0x2f
+#define IT87_INIT         {0x87, 0x01, 0x55, 0x55}
+
+/* alternate Ports: */
+/*
+#define IT87_ADRPORT      0x4e
+#define IT87_DATAPORT     0x4f
+#define IT87_INIT         {0x87, 0x01, 0x55, 0xaa}
+ */
+
+/* IT8712/05 Registers */
+#define IT87_CFGCTRL      0x2
+#define IT87_LDN          0x7
+#define IT87_CHIP_ID1     0x20
+#define IT87_CHIP_ID2     0x21
+#define IT87_CFG_VERSION  0x22
+#define IT87_SWSUSPEND    0x23
+
+#define IT8712_CIR_LDN    0xa
+#define IT8705_CIR_LDN    0x7
+
+/* CIR Configuration Registers: */
+#define IT87_CIR_ACT      0x30
+#define IT87_CIR_BASE_MSB 0x60
+#define IT87_CIR_BASE_LSB 0x61
+#define IT87_CIR_IRQ      0x70
+#define IT87_CIR_CONFIG   0xf0
+
+/* List of IT87_CIR registers: offset to BaseAddr */
+#define IT87_CIR_DR   0
+#define IT87_CIR_IER  1
+#define IT87_CIR_RCR  2
+#define IT87_CIR_TCR1 3
+#define IT87_CIR_TCR2 4
+#define IT87_CIR_TSR  5
+#define IT87_CIR_RSR  6
+#define IT87_CIR_BDLR 5
+#define IT87_CIR_BDHR 6
+#define IT87_CIR_IIR  7
+
+/* Bit Definition */
+/* IER: */
+#define IT87_CIR_IER_TM_EN   0x80
+#define IT87_CIR_IER_RESEVED 0x40
+#define IT87_CIR_IER_RESET   0x20
+#define IT87_CIR_IER_BR      0x10
+#define IT87_CIR_IER_IEC     0x8
+#define IT87_CIR_IER_RFOIE   0x4
+#define IT87_CIR_IER_RDAIE   0x2
+#define IT87_CIR_IER_TLDLIE  0x1
+
+/* RCR: */
+#define IT87_CIR_RCR_RDWOS  0x80
+#define IT87_CIR_RCR_HCFS   0x40
+#define IT87_CIR_RCR_RXEN   0x20
+#define IT87_CIR_RCR_RXEND  0x10
+#define IT87_CIR_RCR_RXACT  0x8
+#define IT87_CIR_RCR_RXDCR  0x7
+
+/* TCR1: */
+#define IT87_CIR_TCR1_FIFOCLR 0x80
+#define IT87_CIR_TCR1_ILE     0x40
+#define IT87_CIR_TCR1_FIFOTL  0x30
+#define IT87_CIR_TCR1_TXRLE   0x8
+#define IT87_CIR_TCR1_TXENDF  0x4
+#define IT87_CIR_TCR1_TXMPM   0x3
+
+/* TCR2: */
+#define IT87_CIR_TCR2_CFQ   0xf8
+#define IT87_CIR_TCR2_TXMPW 0x7
+
+/* TSR: */
+#define IT87_CIR_TSR_RESERVED 0xc0
+#define IT87_CIR_TSR_TXFBC    0x3f
+
+/* RSR: */
+#define IT87_CIR_RSR_RXFTO    0x80
+#define IT87_CIR_RSR_RESERVED 0x40
+#define IT87_CIR_RSR_RXFBC    0x3f
+
+/* IIR: */
+#define IT87_CIR_IIR_RESERVED 0xf8
+#define IT87_CIR_IIR_IID      0x6
+#define IT87_CIR_IIR_IIP      0x1
+
+/* TM: */
+#define IT87_CIR_TM_IL_SEL    0x80
+#define IT87_CIR_TM_RESERVED  0x40
+#define IT87_CIR_TM_TM_REG    0x3f
+
+#define IT87_CIR_FIFO_SIZE 32
+
+/* Baudratedivisor for IT87: power of 2: only 1,2,4 or 8) */
+#define IT87_CIR_BAUDRATE_DIVISOR 0x1
+#define IT87_CIR_DEFAULT_IOBASE 0x310
+#define IT87_CIR_DEFAULT_IRQ    0x7
+#define IT87_CIR_SPACE 0x00
+#define IT87_CIR_PULSE 0xff
+#define IT87_CIR_FREQ_MIN 27
+#define IT87_CIR_FREQ_MAX 58
+#define TIME_CONST (IT87_CIR_BAUDRATE_DIVISOR * 8000000ul / 115200ul)
+
+/********************************* ITE IT87xx ************************/
diff --git a/drivers/staging/lirc/lirc_ite8709.c b/drivers/staging/lirc/lirc_ite8709.c
new file mode 100644
index 0000000..9352f45
--- /dev/null
+++ b/drivers/staging/lirc/lirc_ite8709.c
@@ -0,0 +1,542 @@
+/*
+ * LIRC driver for ITE8709 CIR port
+ *
+ * Copyright (C) 2008 Grégory Lardière <spmf2004-lirc@yahoo.fr>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You 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/interrupt.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pnp.h>
+#include <linux/io.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#define LIRC_DRIVER_NAME "lirc_ite8709"
+
+#define BUF_CHUNK_SIZE	sizeof(int)
+#define BUF_SIZE	(128*BUF_CHUNK_SIZE)
+
+/*
+ * The ITE8709 device seems to be the combination of IT8512 superIO chip and
+ * a specific firmware running on the IT8512's embedded micro-controller.
+ * In addition of the embedded micro-controller, the IT8512 chip contains a
+ * CIR module and several other modules. A few modules are directly accessible
+ * by the host CPU, but most of them are only accessible by the
+ * micro-controller. The CIR module is only accessible by the micro-controller.
+ * The battery-backed SRAM module is accessible by the host CPU and the
+ * micro-controller. So one of the MC's firmware role is to act as a bridge
+ * between the host CPU and the CIR module. The firmware implements a kind of
+ * communication protocol using the SRAM module as a shared memory. The IT8512
+ * specification is publicly available on ITE's web site, but the communication
+ * protocol is not, so it was reverse-engineered.
+ */
+
+/* ITE8709 Registers addresses and values (reverse-engineered) */
+#define ITE8709_MODE		0x1a
+#define ITE8709_REG_ADR		0x1b
+#define ITE8709_REG_VAL		0x1c
+#define ITE8709_IIR		0x1e  /* Interrupt identification register */
+#define ITE8709_RFSR		0x1f  /* Receiver FIFO status register */
+#define ITE8709_FIFO_START	0x20
+
+#define ITE8709_MODE_READY	0X00
+#define ITE8709_MODE_WRITE	0X01
+#define ITE8709_MODE_READ	0X02
+#define ITE8709_IIR_RDAI	0x02  /* Receiver data available interrupt */
+#define ITE8709_IIR_RFOI	0x04  /* Receiver FIFO overrun interrupt */
+#define ITE8709_RFSR_MASK	0x3f  /* FIFO byte count mask */
+
+/*
+ * IT8512 CIR-module registers addresses and values
+ * (from IT8512 E/F specification v0.4.1)
+ */
+#define IT8512_REG_MSTCR	0x01  /* Master control register */
+#define IT8512_REG_IER		0x02  /* Interrupt enable register */
+#define IT8512_REG_CFR		0x04  /* Carrier frequency register */
+#define IT8512_REG_RCR		0x05  /* Receive control register */
+#define IT8512_REG_BDLR		0x08  /* Baud rate divisor low byte register */
+#define IT8512_REG_BDHR		0x09  /* Baud rate divisor high byte register */
+
+#define IT8512_MSTCR_RESET	0x01  /* Reset registers to default value */
+#define IT8512_MSTCR_FIFOCLR	0x02  /* Clear FIFO */
+#define IT8512_MSTCR_FIFOTL_7	0x04  /* FIFO threshold level : 7 */
+#define IT8512_MSTCR_FIFOTL_25	0x0c  /* FIFO threshold level : 25 */
+#define IT8512_IER_RDAIE	0x02  /* Enable data interrupt request */
+#define IT8512_IER_RFOIE	0x04  /* Enable FIFO overrun interrupt req */
+#define IT8512_IER_IEC		0x80  /* Enable interrupt request */
+#define IT8512_CFR_CF_36KHZ	0x09  /* Carrier freq : low speed, 36kHz */
+#define IT8512_RCR_RXDCR_1	0x01  /* Demodulation carrier range : 1 */
+#define IT8512_RCR_RXACT	0x08  /* Receiver active */
+#define IT8512_RCR_RXEN		0x80  /* Receiver enable */
+#define IT8512_BDR_6		6     /* Baud rate divisor : 6 */
+
+/* Actual values used by this driver */
+#define CFG_FIFOTL	IT8512_MSTCR_FIFOTL_25
+#define CFG_CR_FREQ	IT8512_CFR_CF_36KHZ
+#define CFG_DCR		IT8512_RCR_RXDCR_1
+#define CFG_BDR		IT8512_BDR_6
+#define CFG_TIMEOUT	100000 /* Rearm interrupt when a space is > 100 ms */
+
+static int debug;
+
+struct ite8709_device {
+	int use_count;
+	int io;
+	int irq;
+	spinlock_t hardware_lock;
+	unsigned long long acc_pulse;
+	unsigned long long acc_space;
+	char lastbit;
+	struct timeval last_tv;
+	struct lirc_driver driver;
+	struct tasklet_struct tasklet;
+	char force_rearm;
+	char rearmed;
+	char device_busy;
+};
+
+#define dprintk(fmt, args...)					\
+	do {							\
+		if (debug)					\
+			printk(KERN_DEBUG LIRC_DRIVER_NAME ": "	\
+				fmt, ## args);			\
+	} while (0)
+
+
+static unsigned char ite8709_read(struct ite8709_device *dev,
+					unsigned char port)
+{
+	outb(port, dev->io);
+	return inb(dev->io+1);
+}
+
+static void ite8709_write(struct ite8709_device *dev, unsigned char port,
+				unsigned char data)
+{
+	outb(port, dev->io);
+	outb(data, dev->io+1);
+}
+
+static void ite8709_wait_device(struct ite8709_device *dev)
+{
+	int i = 0;
+	/*
+	 * loop until device tells it's ready to continue
+	 * iterations count is usually ~750 but can sometimes achieve 13000
+	 */
+	for (i = 0; i < 15000; i++) {
+		udelay(2);
+		if (ite8709_read(dev, ITE8709_MODE) == ITE8709_MODE_READY)
+			break;
+	}
+}
+
+static void ite8709_write_register(struct ite8709_device *dev,
+				unsigned char reg_adr, unsigned char reg_value)
+{
+	ite8709_wait_device(dev);
+
+	ite8709_write(dev, ITE8709_REG_VAL, reg_value);
+	ite8709_write(dev, ITE8709_REG_ADR, reg_adr);
+	ite8709_write(dev, ITE8709_MODE, ITE8709_MODE_WRITE);
+}
+
+static void ite8709_init_hardware(struct ite8709_device *dev)
+{
+	spin_lock_irq(&dev->hardware_lock);
+	dev->device_busy = 1;
+	spin_unlock_irq(&dev->hardware_lock);
+
+	ite8709_write_register(dev, IT8512_REG_BDHR, (CFG_BDR >> 8) & 0xff);
+	ite8709_write_register(dev, IT8512_REG_BDLR, CFG_BDR & 0xff);
+	ite8709_write_register(dev, IT8512_REG_CFR, CFG_CR_FREQ);
+	ite8709_write_register(dev, IT8512_REG_IER,
+			IT8512_IER_IEC | IT8512_IER_RFOIE | IT8512_IER_RDAIE);
+	ite8709_write_register(dev, IT8512_REG_RCR, CFG_DCR);
+	ite8709_write_register(dev, IT8512_REG_MSTCR,
+					CFG_FIFOTL | IT8512_MSTCR_FIFOCLR);
+	ite8709_write_register(dev, IT8512_REG_RCR,
+				IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR);
+
+	spin_lock_irq(&dev->hardware_lock);
+	dev->device_busy = 0;
+	spin_unlock_irq(&dev->hardware_lock);
+
+	tasklet_enable(&dev->tasklet);
+}
+
+static void ite8709_drop_hardware(struct ite8709_device *dev)
+{
+	tasklet_disable(&dev->tasklet);
+
+	spin_lock_irq(&dev->hardware_lock);
+	dev->device_busy = 1;
+	spin_unlock_irq(&dev->hardware_lock);
+
+	ite8709_write_register(dev, IT8512_REG_RCR, 0);
+	ite8709_write_register(dev, IT8512_REG_MSTCR,
+				IT8512_MSTCR_RESET | IT8512_MSTCR_FIFOCLR);
+
+	spin_lock_irq(&dev->hardware_lock);
+	dev->device_busy = 0;
+	spin_unlock_irq(&dev->hardware_lock);
+}
+
+static int ite8709_set_use_inc(void *data)
+{
+	struct ite8709_device *dev;
+	dev = data;
+	if (dev->use_count == 0)
+		ite8709_init_hardware(dev);
+	dev->use_count++;
+	return 0;
+}
+
+static void ite8709_set_use_dec(void *data)
+{
+	struct ite8709_device *dev;
+	dev = data;
+	dev->use_count--;
+	if (dev->use_count == 0)
+		ite8709_drop_hardware(dev);
+}
+
+static void ite8709_add_read_queue(struct ite8709_device *dev, int flag,
+					unsigned long long val)
+{
+	int value;
+
+	dprintk("add a %llu usec %s\n", val, flag ? "pulse" : "space");
+
+	value = (val > PULSE_MASK) ? PULSE_MASK : val;
+	if (flag)
+		value |= PULSE_BIT;
+
+	if (!lirc_buffer_full(dev->driver.rbuf)) {
+		lirc_buffer_write(dev->driver.rbuf, (void *) &value);
+		wake_up(&dev->driver.rbuf->wait_poll);
+	}
+}
+
+static irqreturn_t ite8709_interrupt(int irq, void *dev_id)
+{
+	unsigned char data;
+	int iir, rfsr, i;
+	int fifo = 0;
+	char bit;
+	struct timeval curr_tv;
+
+	/* Bit duration in microseconds */
+	const unsigned long bit_duration = 1000000ul / (115200 / CFG_BDR);
+
+	struct ite8709_device *dev;
+	dev = dev_id;
+
+	/*
+	 * If device is busy, we simply discard data because we are in one of
+	 * these two cases : shutting down or rearming the device, so this
+	 * doesn't really matter and this avoids waiting too long in IRQ ctx
+	 */
+	spin_lock(&dev->hardware_lock);
+	if (dev->device_busy) {
+		spin_unlock(&dev->hardware_lock);
+		return IRQ_RETVAL(IRQ_HANDLED);
+	}
+
+	iir = ite8709_read(dev, ITE8709_IIR);
+
+	switch (iir) {
+	case ITE8709_IIR_RFOI:
+		dprintk("fifo overrun, scheduling forced rearm just in case\n");
+		dev->force_rearm = 1;
+		tasklet_schedule(&dev->tasklet);
+		spin_unlock(&dev->hardware_lock);
+		return IRQ_RETVAL(IRQ_HANDLED);
+
+	case ITE8709_IIR_RDAI:
+		rfsr = ite8709_read(dev, ITE8709_RFSR);
+		fifo = rfsr & ITE8709_RFSR_MASK;
+		if (fifo > 32)
+			fifo = 32;
+		dprintk("iir: 0x%x rfsr: 0x%x fifo: %d\n", iir, rfsr, fifo);
+
+		if (dev->rearmed) {
+			do_gettimeofday(&curr_tv);
+			dev->acc_space += 1000000ull
+				* (curr_tv.tv_sec - dev->last_tv.tv_sec)
+				+ (curr_tv.tv_usec - dev->last_tv.tv_usec);
+			dev->rearmed = 0;
+		}
+		for (i = 0; i < fifo; i++) {
+			data = ite8709_read(dev, i+ITE8709_FIFO_START);
+			data = ~data;
+			/* Loop through */
+			for (bit = 0; bit < 8; ++bit) {
+				if ((data >> bit) & 1) {
+					dev->acc_pulse += bit_duration;
+					if (dev->lastbit == 0) {
+						ite8709_add_read_queue(dev, 0,
+							dev->acc_space);
+						dev->acc_space = 0;
+					}
+				} else {
+					dev->acc_space += bit_duration;
+					if (dev->lastbit == 1) {
+						ite8709_add_read_queue(dev, 1,
+							dev->acc_pulse);
+						dev->acc_pulse = 0;
+					}
+				}
+				dev->lastbit = (data >> bit) & 1;
+			}
+		}
+		ite8709_write(dev, ITE8709_RFSR, 0);
+
+		if (dev->acc_space > CFG_TIMEOUT) {
+			dprintk("scheduling rearm IRQ\n");
+			do_gettimeofday(&dev->last_tv);
+			dev->force_rearm = 0;
+			tasklet_schedule(&dev->tasklet);
+		}
+
+		spin_unlock(&dev->hardware_lock);
+		return IRQ_RETVAL(IRQ_HANDLED);
+
+	default:
+		/* not our irq */
+		dprintk("unknown IRQ (shouldn't happen) !!\n");
+		spin_unlock(&dev->hardware_lock);
+		return IRQ_RETVAL(IRQ_NONE);
+	}
+}
+
+static void ite8709_rearm_irq(unsigned long data)
+{
+	struct ite8709_device *dev;
+	unsigned long flags;
+	dev = (struct ite8709_device *) data;
+
+	spin_lock_irqsave(&dev->hardware_lock, flags);
+	dev->device_busy = 1;
+	spin_unlock_irqrestore(&dev->hardware_lock, flags);
+
+	if (dev->force_rearm || dev->acc_space > CFG_TIMEOUT) {
+		dprintk("rearming IRQ\n");
+		ite8709_write_register(dev, IT8512_REG_RCR,
+						IT8512_RCR_RXACT | CFG_DCR);
+		ite8709_write_register(dev, IT8512_REG_MSTCR,
+					CFG_FIFOTL | IT8512_MSTCR_FIFOCLR);
+		ite8709_write_register(dev, IT8512_REG_RCR,
+				IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR);
+		if (!dev->force_rearm)
+			dev->rearmed = 1;
+		dev->force_rearm = 0;
+	}
+
+	spin_lock_irqsave(&dev->hardware_lock, flags);
+	dev->device_busy = 0;
+	spin_unlock_irqrestore(&dev->hardware_lock, flags);
+}
+
+static int ite8709_cleanup(struct ite8709_device *dev, int stage, int errno,
+				char *msg)
+{
+	if (msg != NULL)
+		printk(KERN_ERR LIRC_DRIVER_NAME ": %s\n", msg);
+
+	switch (stage) {
+	case 6:
+		if (dev->use_count > 0)
+			ite8709_drop_hardware(dev);
+	case 5:
+		free_irq(dev->irq, dev);
+	case 4:
+		release_region(dev->io, 2);
+	case 3:
+		lirc_unregister_driver(dev->driver.minor);
+	case 2:
+		lirc_buffer_free(dev->driver.rbuf);
+		kfree(dev->driver.rbuf);
+	case 1:
+		kfree(dev);
+	case 0:
+		;
+	}
+
+	return errno;
+}
+
+static int __devinit ite8709_pnp_probe(struct pnp_dev *dev,
+					const struct pnp_device_id *dev_id)
+{
+	struct lirc_driver *driver;
+	struct ite8709_device *ite8709_dev;
+	int ret;
+
+	/* Check resources validity */
+	if (!pnp_irq_valid(dev, 0))
+		return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IRQ");
+	if (!pnp_port_valid(dev, 2))
+		return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IO port");
+
+	/* Allocate memory for device struct */
+	ite8709_dev = kzalloc(sizeof(struct ite8709_device), GFP_KERNEL);
+	if (ite8709_dev == NULL)
+		return ite8709_cleanup(NULL, 0, -ENOMEM, "kzalloc failed");
+	pnp_set_drvdata(dev, ite8709_dev);
+
+	/* Initialize device struct */
+	ite8709_dev->use_count = 0;
+	ite8709_dev->irq = pnp_irq(dev, 0);
+	ite8709_dev->io = pnp_port_start(dev, 2);
+	ite8709_dev->hardware_lock =
+		__SPIN_LOCK_UNLOCKED(ite8709_dev->hardware_lock);
+	ite8709_dev->acc_pulse = 0;
+	ite8709_dev->acc_space = 0;
+	ite8709_dev->lastbit = 0;
+	do_gettimeofday(&ite8709_dev->last_tv);
+	tasklet_init(&ite8709_dev->tasklet, ite8709_rearm_irq,
+							(long) ite8709_dev);
+	ite8709_dev->force_rearm = 0;
+	ite8709_dev->rearmed = 0;
+	ite8709_dev->device_busy = 0;
+
+	/* Initialize driver struct */
+	driver = &ite8709_dev->driver;
+	strcpy(driver->name, LIRC_DRIVER_NAME);
+	driver->minor = -1;
+	driver->code_length = sizeof(int) * 8;
+	driver->sample_rate = 0;
+	driver->features = LIRC_CAN_REC_MODE2;
+	driver->data = ite8709_dev;
+	driver->add_to_buf = NULL;
+	driver->set_use_inc = ite8709_set_use_inc;
+	driver->set_use_dec = ite8709_set_use_dec;
+	driver->dev = &dev->dev;
+	driver->owner = THIS_MODULE;
+
+	/* Initialize LIRC buffer */
+	driver->rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+	if (!driver->rbuf)
+		return ite8709_cleanup(ite8709_dev, 1, -ENOMEM,
+				       "can't allocate lirc_buffer");
+	if (lirc_buffer_init(driver->rbuf, BUF_CHUNK_SIZE, BUF_SIZE))
+		return ite8709_cleanup(ite8709_dev, 1, -ENOMEM,
+				       "lirc_buffer_init() failed");
+
+	/* Register LIRC driver */
+	ret = lirc_register_driver(driver);
+	if (ret < 0)
+		return ite8709_cleanup(ite8709_dev, 2, ret,
+					"lirc_register_driver() failed");
+
+	/* Reserve I/O port access */
+	if (!request_region(ite8709_dev->io, 2, LIRC_DRIVER_NAME))
+		return ite8709_cleanup(ite8709_dev, 3, -EBUSY,
+						"i/o port already in use");
+
+	/* Reserve IRQ line */
+	ret = request_irq(ite8709_dev->irq, ite8709_interrupt, 0,
+					LIRC_DRIVER_NAME, ite8709_dev);
+	if (ret < 0)
+		return ite8709_cleanup(ite8709_dev, 4, ret,
+						"IRQ already in use");
+
+	/* Initialize hardware */
+	ite8709_drop_hardware(ite8709_dev); /* Shutdown hw until first use */
+
+	printk(KERN_INFO LIRC_DRIVER_NAME ": device found : irq=%d io=0x%x\n",
+					ite8709_dev->irq, ite8709_dev->io);
+
+	return 0;
+}
+
+static void __devexit ite8709_pnp_remove(struct pnp_dev *dev)
+{
+	struct ite8709_device *ite8709_dev;
+	ite8709_dev = pnp_get_drvdata(dev);
+
+	ite8709_cleanup(ite8709_dev, 6, 0, NULL);
+
+	printk(KERN_INFO LIRC_DRIVER_NAME ": device removed\n");
+}
+
+#ifdef CONFIG_PM
+static int ite8709_pnp_suspend(struct pnp_dev *dev, pm_message_t state)
+{
+	struct ite8709_device *ite8709_dev;
+	ite8709_dev = pnp_get_drvdata(dev);
+
+	if (ite8709_dev->use_count > 0)
+		ite8709_drop_hardware(ite8709_dev);
+
+	return 0;
+}
+
+static int ite8709_pnp_resume(struct pnp_dev *dev)
+{
+	struct ite8709_device *ite8709_dev;
+	ite8709_dev = pnp_get_drvdata(dev);
+
+	if (ite8709_dev->use_count > 0)
+		ite8709_init_hardware(ite8709_dev);
+
+	return 0;
+}
+#else
+#define ite8709_pnp_suspend NULL
+#define ite8709_pnp_resume NULL
+#endif
+
+static const struct pnp_device_id pnp_dev_table[] = {
+	{"ITE8709", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
+
+static struct pnp_driver ite8709_pnp_driver = {
+	.name           = LIRC_DRIVER_NAME,
+	.probe          = ite8709_pnp_probe,
+	.remove         = __devexit_p(ite8709_pnp_remove),
+	.suspend        = ite8709_pnp_suspend,
+	.resume         = ite8709_pnp_resume,
+	.id_table       = pnp_dev_table,
+};
+
+static int __init ite8709_init_module(void)
+{
+	return pnp_register_driver(&ite8709_pnp_driver);
+}
+module_init(ite8709_init_module);
+
+static void __exit ite8709_cleanup_module(void)
+{
+	pnp_unregister_driver(&ite8709_pnp_driver);
+}
+module_exit(ite8709_cleanup_module);
+
+MODULE_DESCRIPTION("LIRC driver for ITE8709 CIR port");
+MODULE_AUTHOR("Grégory Lardière");
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/lirc/lirc_parallel.c
new file mode 100644
index 0000000..a1ebd07
--- /dev/null
+++ b/drivers/staging/lirc/lirc_parallel.c
@@ -0,0 +1,705 @@
+/*
+ * lirc_parallel.c
+ *
+ * lirc_parallel - device driver for infra-red signal receiving and
+ *                 transmitting unit built by the author
+ *
+ * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*** Includes ***/
+
+#ifdef CONFIG_SMP
+#error "--- Sorry, this driver is not SMP safe. ---"
+#endif
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <linux/io.h>
+#include <linux/signal.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <asm/div64.h>
+
+#include <linux/poll.h>
+#include <linux/parport.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#include "lirc_parallel.h"
+
+#define LIRC_DRIVER_NAME "lirc_parallel"
+
+#ifndef LIRC_IRQ
+#define LIRC_IRQ 7
+#endif
+#ifndef LIRC_PORT
+#define LIRC_PORT 0x378
+#endif
+#ifndef LIRC_TIMER
+#define LIRC_TIMER 65536
+#endif
+
+/*** Global Variables ***/
+
+static int debug;
+static int check_pselecd;
+
+unsigned int irq = LIRC_IRQ;
+unsigned int io = LIRC_PORT;
+#ifdef LIRC_TIMER
+unsigned int timer;
+unsigned int default_timer = LIRC_TIMER;
+#endif
+
+#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */
+
+static int rbuf[RBUF_SIZE];
+
+DECLARE_WAIT_QUEUE_HEAD(lirc_wait);
+
+unsigned int rptr;
+unsigned int wptr;
+unsigned int lost_irqs;
+int is_open;
+
+struct parport *pport;
+struct pardevice *ppdevice;
+int is_claimed;
+
+unsigned int tx_mask = 1;
+
+/*** Internal Functions ***/
+
+static unsigned int in(int offset)
+{
+	switch (offset) {
+	case LIRC_LP_BASE:
+		return parport_read_data(pport);
+	case LIRC_LP_STATUS:
+		return parport_read_status(pport);
+	case LIRC_LP_CONTROL:
+		return parport_read_control(pport);
+	}
+	return 0; /* make compiler happy */
+}
+
+static void out(int offset, int value)
+{
+	switch (offset) {
+	case LIRC_LP_BASE:
+		parport_write_data(pport, value);
+		break;
+	case LIRC_LP_CONTROL:
+		parport_write_control(pport, value);
+		break;
+	case LIRC_LP_STATUS:
+		printk(KERN_INFO "%s: attempt to write to status register\n",
+		       LIRC_DRIVER_NAME);
+		break;
+	}
+}
+
+static unsigned int lirc_get_timer(void)
+{
+	return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT;
+}
+
+static unsigned int lirc_get_signal(void)
+{
+	return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT;
+}
+
+static void lirc_on(void)
+{
+	out(LIRC_PORT_DATA, tx_mask);
+}
+
+static void lirc_off(void)
+{
+	out(LIRC_PORT_DATA, 0);
+}
+
+static unsigned int init_lirc_timer(void)
+{
+	struct timeval tv, now;
+	unsigned int level, newlevel, timeelapsed, newtimer;
+	int count = 0;
+
+	do_gettimeofday(&tv);
+	tv.tv_sec++;                     /* wait max. 1 sec. */
+	level = lirc_get_timer();
+	do {
+		newlevel = lirc_get_timer();
+		if (level == 0 && newlevel != 0)
+			count++;
+		level = newlevel;
+		do_gettimeofday(&now);
+	} while (count < 1000 && (now.tv_sec < tv.tv_sec
+			     || (now.tv_sec == tv.tv_sec
+				 && now.tv_usec < tv.tv_usec)));
+
+	timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000
+		     + (now.tv_usec - tv.tv_usec));
+	if (count >= 1000 && timeelapsed > 0) {
+		if (default_timer == 0) {
+			/* autodetect timer */
+			newtimer = (1000000*count)/timeelapsed;
+			printk(KERN_INFO "%s: %u Hz timer detected\n",
+			       LIRC_DRIVER_NAME, newtimer);
+			return newtimer;
+		}  else {
+			newtimer = (1000000*count)/timeelapsed;
+			if (abs(newtimer - default_timer) > default_timer/10) {
+				/* bad timer */
+				printk(KERN_NOTICE "%s: bad timer: %u Hz\n",
+				       LIRC_DRIVER_NAME, newtimer);
+				printk(KERN_NOTICE "%s: using default timer: "
+				       "%u Hz\n",
+				       LIRC_DRIVER_NAME, default_timer);
+				return default_timer;
+			} else {
+				printk(KERN_INFO "%s: %u Hz timer detected\n",
+				       LIRC_DRIVER_NAME, newtimer);
+				return newtimer; /* use detected value */
+			}
+		}
+	} else {
+		printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME);
+		return 0;
+	}
+}
+
+static int lirc_claim(void)
+{
+	if (parport_claim(ppdevice) != 0) {
+		printk(KERN_WARNING "%s: could not claim port\n",
+		       LIRC_DRIVER_NAME);
+		printk(KERN_WARNING "%s: waiting for port becoming available"
+		       "\n", LIRC_DRIVER_NAME);
+		if (parport_claim_or_block(ppdevice) < 0) {
+			printk(KERN_NOTICE "%s: could not claim port, giving"
+			       " up\n", LIRC_DRIVER_NAME);
+			return 0;
+		}
+	}
+	out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
+	is_claimed = 1;
+	return 1;
+}
+
+/*** interrupt handler ***/
+
+static void rbuf_write(int signal)
+{
+	unsigned int nwptr;
+
+	nwptr = (wptr + 1) & (RBUF_SIZE - 1);
+	if (nwptr == rptr) {
+		/* no new signals will be accepted */
+		lost_irqs++;
+		printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME);
+		return;
+	}
+	rbuf[wptr] = signal;
+	wptr = nwptr;
+}
+
+static void irq_handler(void *blah)
+{
+	struct timeval tv;
+	static struct timeval lasttv;
+	static int init;
+	long signal;
+	int data;
+	unsigned int level, newlevel;
+	unsigned int timeout;
+
+	if (!module_refcount(THIS_MODULE))
+		return;
+
+	if (!is_claimed)
+		return;
+
+#if 0
+	/* disable interrupt */
+	  disable_irq(irq);
+	  out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN));
+#endif
+	if (check_pselecd && (in(1) & LP_PSELECD))
+		return;
+
+#ifdef LIRC_TIMER
+	if (init) {
+		do_gettimeofday(&tv);
+
+		signal = tv.tv_sec - lasttv.tv_sec;
+		if (signal > 15)
+			/* really long time */
+			data = PULSE_MASK;
+		else
+			data = (int) (signal*1000000 +
+					 tv.tv_usec - lasttv.tv_usec +
+					 LIRC_SFH506_DELAY);
+
+		rbuf_write(data); /* space */
+	} else {
+		if (timer == 0) {
+			/*
+			 * wake up; we'll lose this signal, but it will be
+			 * garbage if the device is turned on anyway
+			 */
+			timer = init_lirc_timer();
+			/* enable_irq(irq); */
+			return;
+		}
+		init = 1;
+	}
+
+	timeout = timer/10;	/* timeout after 1/10 sec. */
+	signal = 1;
+	level = lirc_get_timer();
+	do {
+		newlevel = lirc_get_timer();
+		if (level == 0 && newlevel != 0)
+			signal++;
+		level = newlevel;
+
+		/* giving up */
+		if (signal > timeout
+		    || (check_pselecd && (in(1) & LP_PSELECD))) {
+			signal = 0;
+			printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME);
+			break;
+		}
+	} while (lirc_get_signal());
+
+	if (signal != 0) {
+		/* ajust value to usecs */
+		unsigned long long helper;
+
+		helper = ((unsigned long long) signal)*1000000;
+		do_div(helper, timer);
+		signal = (long) helper;
+
+		if (signal > LIRC_SFH506_DELAY)
+			data = signal - LIRC_SFH506_DELAY;
+		else
+			data = 1;
+		rbuf_write(PULSE_BIT|data); /* pulse */
+	}
+	do_gettimeofday(&lasttv);
+#else
+	/* add your code here */
+#endif
+
+	wake_up_interruptible(&lirc_wait);
+
+	/* enable interrupt */
+	/*
+	  enable_irq(irq);
+	  out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN);
+	*/
+}
+
+/*** file operations ***/
+
+static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig)
+{
+	return -ESPIPE;
+}
+
+static ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos)
+{
+	int result = 0;
+	int count = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (n % sizeof(int))
+		return -EINVAL;
+
+	add_wait_queue(&lirc_wait, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	while (count < n) {
+		if (rptr != wptr) {
+			if (copy_to_user(buf+count, (char *) &rbuf[rptr],
+					 sizeof(int))) {
+				result = -EFAULT;
+				break;
+			}
+			rptr = (rptr + 1) & (RBUF_SIZE - 1);
+			count += sizeof(int);
+		} else {
+			if (filep->f_flags & O_NONBLOCK) {
+				result = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				result = -ERESTARTSYS;
+				break;
+			}
+			schedule();
+			set_current_state(TASK_INTERRUPTIBLE);
+		}
+	}
+	remove_wait_queue(&lirc_wait, &wait);
+	set_current_state(TASK_RUNNING);
+	return count ? count : result;
+}
+
+static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
+			  loff_t *ppos)
+{
+	int count;
+	unsigned int i;
+	unsigned int level, newlevel;
+	unsigned long flags;
+	int counttimer;
+	int *wbuf;
+
+	if (!is_claimed)
+		return -EBUSY;
+
+	count = n / sizeof(int);
+
+	if (n % sizeof(int) || count % 2 == 0)
+		return -EINVAL;
+
+	wbuf = memdup_user(buf, n);
+	if (IS_ERR(wbuf))
+		return PTR_ERR(wbuf);
+
+#ifdef LIRC_TIMER
+	if (timer == 0) {
+		/* try again if device is ready */
+		timer = init_lirc_timer();
+		if (timer == 0)
+			return -EIO;
+	}
+
+	/* adjust values from usecs */
+	for (i = 0; i < count; i++) {
+		unsigned long long helper;
+
+		helper = ((unsigned long long) wbuf[i])*timer;
+		do_div(helper, 1000000);
+		wbuf[i] = (int) helper;
+	}
+
+	local_irq_save(flags);
+	i = 0;
+	while (i < count) {
+		level = lirc_get_timer();
+		counttimer = 0;
+		lirc_on();
+		do {
+			newlevel = lirc_get_timer();
+			if (level == 0 && newlevel != 0)
+				counttimer++;
+			level = newlevel;
+			if (check_pselecd && (in(1) & LP_PSELECD)) {
+				lirc_off();
+				local_irq_restore(flags);
+				return -EIO;
+			}
+		} while (counttimer < wbuf[i]);
+		i++;
+
+		lirc_off();
+		if (i == count)
+			break;
+		counttimer = 0;
+		do {
+			newlevel = lirc_get_timer();
+			if (level == 0 && newlevel != 0)
+				counttimer++;
+			level = newlevel;
+			if (check_pselecd && (in(1) & LP_PSELECD)) {
+				local_irq_restore(flags);
+				return -EIO;
+			}
+		} while (counttimer < wbuf[i]);
+		i++;
+	}
+	local_irq_restore(flags);
+#else
+	/* place code that handles write without external timer here */
+#endif
+	return n;
+}
+
+static unsigned int lirc_poll(struct file *file, poll_table *wait)
+{
+	poll_wait(file, &lirc_wait, wait);
+	if (rptr != wptr)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+	int result;
+	unsigned long features = LIRC_CAN_SET_TRANSMITTER_MASK |
+				 LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
+	unsigned long mode;
+	unsigned int ivalue;
+
+	switch (cmd) {
+	case LIRC_GET_FEATURES:
+		result = put_user(features, (unsigned long *) arg);
+		if (result)
+			return result;
+		break;
+	case LIRC_GET_SEND_MODE:
+		result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
+		if (result)
+			return result;
+		break;
+	case LIRC_GET_REC_MODE:
+		result = put_user(LIRC_MODE_MODE2, (unsigned long *) arg);
+		if (result)
+			return result;
+		break;
+	case LIRC_SET_SEND_MODE:
+		result = get_user(mode, (unsigned long *) arg);
+		if (result)
+			return result;
+		if (mode != LIRC_MODE_PULSE)
+			return -EINVAL;
+		break;
+	case LIRC_SET_REC_MODE:
+		result = get_user(mode, (unsigned long *) arg);
+		if (result)
+			return result;
+		if (mode != LIRC_MODE_MODE2)
+			return -ENOSYS;
+		break;
+	case LIRC_SET_TRANSMITTER_MASK:
+		result = get_user(ivalue, (unsigned int *) arg);
+		if (result)
+			return result;
+		if ((ivalue & LIRC_PARALLEL_TRANSMITTER_MASK) != ivalue)
+			return LIRC_PARALLEL_MAX_TRANSMITTERS;
+		tx_mask = ivalue;
+		break;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static int lirc_open(struct inode *node, struct file *filep)
+{
+	if (module_refcount(THIS_MODULE) || !lirc_claim())
+		return -EBUSY;
+
+	parport_enable_irq(pport);
+
+	/* init read ptr */
+	rptr = 0;
+	wptr = 0;
+	lost_irqs = 0;
+
+	is_open = 1;
+	return 0;
+}
+
+static int lirc_close(struct inode *node, struct file *filep)
+{
+	if (is_claimed) {
+		is_claimed = 0;
+		parport_release(ppdevice);
+	}
+	is_open = 0;
+	return 0;
+}
+
+static const struct file_operations lirc_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= lirc_lseek,
+	.read		= lirc_read,
+	.write		= lirc_write,
+	.poll		= lirc_poll,
+	.unlocked_ioctl	= lirc_ioctl,
+	.open		= lirc_open,
+	.release	= lirc_close
+};
+
+static int set_use_inc(void *data)
+{
+	return 0;
+}
+
+static void set_use_dec(void *data)
+{
+}
+
+static struct lirc_driver driver = {
+       .name		= LIRC_DRIVER_NAME,
+       .minor		= -1,
+       .code_length	= 1,
+       .sample_rate	= 0,
+       .data		= NULL,
+       .add_to_buf	= NULL,
+       .set_use_inc	= set_use_inc,
+       .set_use_dec	= set_use_dec,
+       .fops		= &lirc_fops,
+       .dev		= NULL,
+       .owner		= THIS_MODULE,
+};
+
+static int pf(void *handle);
+static void kf(void *handle);
+
+static struct timer_list poll_timer;
+static void poll_state(unsigned long ignored);
+
+static void poll_state(unsigned long ignored)
+{
+	printk(KERN_NOTICE "%s: time\n",
+	       LIRC_DRIVER_NAME);
+	del_timer(&poll_timer);
+	if (is_claimed)
+		return;
+	kf(NULL);
+	if (!is_claimed) {
+		printk(KERN_NOTICE "%s: could not claim port, giving up\n",
+		       LIRC_DRIVER_NAME);
+		init_timer(&poll_timer);
+		poll_timer.expires = jiffies + HZ;
+		poll_timer.data = (unsigned long)current;
+		poll_timer.function = poll_state;
+		add_timer(&poll_timer);
+	}
+}
+
+static int pf(void *handle)
+{
+	parport_disable_irq(pport);
+	is_claimed = 0;
+	return 0;
+}
+
+static void kf(void *handle)
+{
+	if (!is_open)
+		return;
+	if (!lirc_claim())
+		return;
+	parport_enable_irq(pport);
+	lirc_off();
+	/* this is a bit annoying when you actually print...*/
+	/*
+	printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME);
+	*/
+}
+
+/*** module initialization and cleanup ***/
+
+static int __init lirc_parallel_init(void)
+{
+	pport = parport_find_base(io);
+	if (pport == NULL) {
+		printk(KERN_NOTICE "%s: no port at %x found\n",
+		       LIRC_DRIVER_NAME, io);
+		return -ENXIO;
+	}
+	ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME,
+					   pf, kf, irq_handler, 0, NULL);
+	parport_put_port(pport);
+	if (ppdevice == NULL) {
+		printk(KERN_NOTICE "%s: parport_register_device() failed\n",
+		       LIRC_DRIVER_NAME);
+		return -ENXIO;
+	}
+	if (parport_claim(ppdevice) != 0)
+		goto skip_init;
+	is_claimed = 1;
+	out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
+
+#ifdef LIRC_TIMER
+	if (debug)
+		out(LIRC_PORT_DATA, tx_mask);
+
+	timer = init_lirc_timer();
+
+#if 0	/* continue even if device is offline */
+	if (timer == 0) {
+		is_claimed = 0;
+		parport_release(pport);
+		parport_unregister_device(ppdevice);
+		return -EIO;
+	}
+
+#endif
+	if (debug)
+		out(LIRC_PORT_DATA, 0);
+#endif
+
+	is_claimed = 0;
+	parport_release(ppdevice);
+ skip_init:
+	driver.minor = lirc_register_driver(&driver);
+	if (driver.minor < 0) {
+		printk(KERN_NOTICE "%s: register_chrdev() failed\n",
+		       LIRC_DRIVER_NAME);
+		parport_unregister_device(ppdevice);
+		return -EIO;
+	}
+	printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n",
+	       LIRC_DRIVER_NAME, io, irq);
+	return 0;
+}
+
+static void __exit lirc_parallel_exit(void)
+{
+	parport_unregister_device(ppdevice);
+	lirc_unregister_driver(driver.minor);
+}
+
+module_init(lirc_parallel_init);
+module_exit(lirc_parallel_exit);
+
+MODULE_DESCRIPTION("Infrared receiver driver for parallel ports.");
+MODULE_AUTHOR("Christoph Bartelmus");
+MODULE_LICENSE("GPL");
+
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)");
+
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (7 or 5)");
+
+module_param(tx_mask, int, S_IRUGO);
+MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
+module_param(check_pselecd, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Check for printer (default: 0)");
diff --git a/drivers/staging/lirc/lirc_parallel.h b/drivers/staging/lirc/lirc_parallel.h
new file mode 100644
index 0000000..4bed6af
--- /dev/null
+++ b/drivers/staging/lirc/lirc_parallel.h
@@ -0,0 +1,26 @@
+/* lirc_parallel.h */
+
+#ifndef _LIRC_PARALLEL_H
+#define _LIRC_PARALLEL_H
+
+#include <linux/lp.h>
+
+#define LIRC_PORT_LEN 3
+
+#define LIRC_LP_BASE    0
+#define LIRC_LP_STATUS  1
+#define LIRC_LP_CONTROL 2
+
+#define LIRC_PORT_DATA           LIRC_LP_BASE    /* base */
+#define LIRC_PORT_TIMER        LIRC_LP_STATUS    /* status port */
+#define LIRC_PORT_TIMER_BIT          LP_PBUSY    /* busy signal */
+#define LIRC_PORT_SIGNAL       LIRC_LP_STATUS    /* status port */
+#define LIRC_PORT_SIGNAL_BIT          LP_PACK    /* ack signal */
+#define LIRC_PORT_IRQ         LIRC_LP_CONTROL    /* control port */
+
+#define LIRC_SFH506_DELAY 0             /* delay t_phl in usecs */
+
+#define LIRC_PARALLEL_MAX_TRANSMITTERS 8
+#define LIRC_PARALLEL_TRANSMITTER_MASK ((1<<LIRC_PARALLEL_MAX_TRANSMITTERS) - 1)
+
+#endif
diff --git a/drivers/staging/lirc/lirc_sasem.c b/drivers/staging/lirc/lirc_sasem.c
new file mode 100644
index 0000000..73166c3
--- /dev/null
+++ b/drivers/staging/lirc/lirc_sasem.c
@@ -0,0 +1,933 @@
+/*
+ * lirc_sasem.c - USB remote support for LIRC
+ * Version 0.5
+ *
+ * Copyright (C) 2004-2005 Oliver Stabel <oliver.stabel@gmx.de>
+ *			 Tim Davies <tim@opensystems.net.au>
+ *
+ * This driver was derived from:
+ *   Venky Raju <dev@venky.ws>
+ *      "lirc_imon - "LIRC/VFD driver for Ahanix/Soundgraph IMON IR/VFD"
+ *   Paul Miller <pmiller9@users.sourceforge.net>'s 2003-2004
+ *      "lirc_atiusb - USB remote support for LIRC"
+ *   Culver Consulting Services <henry@culcon.com>'s 2003
+ *      "Sasem OnAir VFD/IR USB driver"
+ *
+ *
+ * NOTE - The LCDproc iMon driver should work with this module.  More info at
+ *	http://www.frogstorm.info/sasem
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+
+#define MOD_AUTHOR	"Oliver Stabel <oliver.stabel@gmx.de>, " \
+			"Tim Davies <tim@opensystems.net.au>"
+#define MOD_DESC	"USB Driver for Sasem Remote Controller V1.1"
+#define MOD_NAME	"lirc_sasem"
+#define MOD_VERSION	"0.5"
+
+#define VFD_MINOR_BASE	144	/* Same as LCD */
+#define DEVICE_NAME	"lcd%d"
+
+#define BUF_CHUNK_SIZE	8
+#define BUF_SIZE	128
+
+#define IOCTL_LCD_CONTRAST 1
+
+/*** P R O T O T Y P E S ***/
+
+/* USB Callback prototypes */
+static int sasem_probe(struct usb_interface *interface,
+			const struct usb_device_id *id);
+static void sasem_disconnect(struct usb_interface *interface);
+static void usb_rx_callback(struct urb *urb);
+static void usb_tx_callback(struct urb *urb);
+
+/* VFD file_operations function prototypes */
+static int vfd_open(struct inode *inode, struct file *file);
+static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg);
+static int vfd_close(struct inode *inode, struct file *file);
+static ssize_t vfd_write(struct file *file, const char *buf,
+				size_t n_bytes, loff_t *pos);
+
+/* LIRC driver function prototypes */
+static int ir_open(void *data);
+static void ir_close(void *data);
+
+/* Driver init/exit prototypes */
+static int __init sasem_init(void);
+static void __exit sasem_exit(void);
+
+/*** G L O B A L S ***/
+#define SASEM_DATA_BUF_SZ	32
+
+struct sasem_context {
+
+	struct usb_device *dev;
+	int vfd_isopen;			/* VFD port has been opened       */
+	unsigned int vfd_contrast;	/* VFD contrast		   */
+	int ir_isopen;			/* IR port has been opened	*/
+	int dev_present;		/* USB device presence	    */
+	struct mutex ctx_lock;		/* to lock this object	    */
+	wait_queue_head_t remove_ok;	/* For unexpected USB disconnects */
+
+	struct lirc_driver *driver;
+	struct usb_endpoint_descriptor *rx_endpoint;
+	struct usb_endpoint_descriptor *tx_endpoint;
+	struct urb *rx_urb;
+	struct urb *tx_urb;
+	unsigned char usb_rx_buf[8];
+	unsigned char usb_tx_buf[8];
+
+	struct tx_t {
+		unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data buffer */
+		struct completion finished;  /* wait for write to finish  */
+		atomic_t busy;		     /* write in progress	 */
+		int status;		     /* status of tx completion   */
+	} tx;
+
+	/* for dealing with repeat codes (wish there was a toggle bit!) */
+	struct timeval presstime;
+	char lastcode[8];
+	int codesaved;
+};
+
+/* VFD file operations */
+static const struct file_operations vfd_fops = {
+	.owner		= THIS_MODULE,
+	.open		= &vfd_open,
+	.write		= &vfd_write,
+	.unlocked_ioctl	= &vfd_ioctl,
+	.release	= &vfd_close,
+};
+
+/* USB Device ID for Sasem USB Control Board */
+static struct usb_device_id sasem_usb_id_table[] = {
+	/* Sasem USB Control Board */
+	{ USB_DEVICE(0x11ba, 0x0101) },
+	/* Terminating entry */
+	{}
+};
+
+/* USB Device data */
+static struct usb_driver sasem_driver = {
+	.name		= MOD_NAME,
+	.probe		= sasem_probe,
+	.disconnect	= sasem_disconnect,
+	.id_table	= sasem_usb_id_table,
+};
+
+static struct usb_class_driver sasem_class = {
+	.name		= DEVICE_NAME,
+	.fops		= &vfd_fops,
+	.minor_base	= VFD_MINOR_BASE,
+};
+
+/* to prevent races between open() and disconnect() */
+static DEFINE_MUTEX(disconnect_lock);
+
+static int debug;
+
+
+/*** M O D U L E   C O D E ***/
+
+MODULE_AUTHOR(MOD_AUTHOR);
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_LICENSE("GPL");
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)");
+
+static void delete_context(struct sasem_context *context)
+{
+	usb_free_urb(context->tx_urb);  /* VFD */
+	usb_free_urb(context->rx_urb);  /* IR */
+	lirc_buffer_free(context->driver->rbuf);
+	kfree(context->driver->rbuf);
+	kfree(context->driver);
+	kfree(context);
+
+	if (debug)
+		printk(KERN_INFO "%s: context deleted\n", __func__);
+}
+
+static void deregister_from_lirc(struct sasem_context *context)
+{
+	int retval;
+	int minor = context->driver->minor;
+
+	retval = lirc_unregister_driver(minor);
+	if (retval)
+		err("%s: unable to deregister from lirc (%d)",
+			__func__, retval);
+	else
+		printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n",
+		       minor);
+
+}
+
+/**
+ * Called when the VFD device (e.g. /dev/usb/lcd)
+ * is opened by the application.
+ */
+static int vfd_open(struct inode *inode, struct file *file)
+{
+	struct usb_interface *interface;
+	struct sasem_context *context = NULL;
+	int subminor;
+	int retval = 0;
+
+	/* prevent races with disconnect */
+	mutex_lock(&disconnect_lock);
+
+	subminor = iminor(inode);
+	interface = usb_find_interface(&sasem_driver, subminor);
+	if (!interface) {
+		err("%s: could not find interface for minor %d",
+		    __func__, subminor);
+		retval = -ENODEV;
+		goto exit;
+	}
+	context = usb_get_intfdata(interface);
+
+	if (!context) {
+		err("%s: no context found for minor %d",
+					__func__, subminor);
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	mutex_lock(&context->ctx_lock);
+
+	if (context->vfd_isopen) {
+		err("%s: VFD port is already open", __func__);
+		retval = -EBUSY;
+	} else {
+		context->vfd_isopen = 1;
+		file->private_data = context;
+		printk(KERN_INFO "VFD port opened\n");
+	}
+
+	mutex_unlock(&context->ctx_lock);
+
+exit:
+	mutex_unlock(&disconnect_lock);
+	return retval;
+}
+
+/**
+ * Called when the VFD device (e.g. /dev/usb/lcd)
+ * is closed by the application.
+ */
+static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+	struct sasem_context *context = NULL;
+
+	context = (struct sasem_context *) file->private_data;
+
+	if (!context) {
+		err("%s: no context for device", __func__);
+		return -ENODEV;
+	}
+
+	mutex_lock(&context->ctx_lock);
+
+	switch (cmd) {
+	case IOCTL_LCD_CONTRAST:
+		if (arg > 1000)
+			arg = 1000;
+		context->vfd_contrast = (unsigned int)arg;
+		break;
+	default:
+		printk(KERN_INFO "Unknown IOCTL command\n");
+		mutex_unlock(&context->ctx_lock);
+		return -ENOIOCTLCMD;  /* not supported */
+	}
+
+	mutex_unlock(&context->ctx_lock);
+	return 0;
+}
+
+/**
+ * Called when the VFD device (e.g. /dev/usb/lcd)
+ * is closed by the application.
+ */
+static int vfd_close(struct inode *inode, struct file *file)
+{
+	struct sasem_context *context = NULL;
+	int retval = 0;
+
+	context = (struct sasem_context *) file->private_data;
+
+	if (!context) {
+		err("%s: no context for device", __func__);
+		return -ENODEV;
+	}
+
+	mutex_lock(&context->ctx_lock);
+
+	if (!context->vfd_isopen) {
+		err("%s: VFD is not open", __func__);
+		retval = -EIO;
+	} else {
+		context->vfd_isopen = 0;
+		printk(KERN_INFO "VFD port closed\n");
+		if (!context->dev_present && !context->ir_isopen) {
+
+			/* Device disconnected before close and IR port is
+			 * not open. If IR port is open, context will be
+			 * deleted by ir_close. */
+			mutex_unlock(&context->ctx_lock);
+			delete_context(context);
+			return retval;
+		}
+	}
+
+	mutex_unlock(&context->ctx_lock);
+	return retval;
+}
+
+/**
+ * Sends a packet to the VFD.
+ */
+static int send_packet(struct sasem_context *context)
+{
+	unsigned int pipe;
+	int interval = 0;
+	int retval = 0;
+
+	pipe = usb_sndintpipe(context->dev,
+			context->tx_endpoint->bEndpointAddress);
+	interval = context->tx_endpoint->bInterval;
+
+	usb_fill_int_urb(context->tx_urb, context->dev, pipe,
+		context->usb_tx_buf, sizeof(context->usb_tx_buf),
+		usb_tx_callback, context, interval);
+
+	context->tx_urb->actual_length = 0;
+
+	init_completion(&context->tx.finished);
+	atomic_set(&(context->tx.busy), 1);
+
+	retval =  usb_submit_urb(context->tx_urb, GFP_KERNEL);
+	if (retval) {
+		atomic_set(&(context->tx.busy), 0);
+		err("%s: error submitting urb (%d)", __func__, retval);
+	} else {
+		/* Wait for transmission to complete (or abort) */
+		mutex_unlock(&context->ctx_lock);
+		wait_for_completion(&context->tx.finished);
+		mutex_lock(&context->ctx_lock);
+
+		retval = context->tx.status;
+		if (retval)
+			err("%s: packet tx failed (%d)", __func__, retval);
+	}
+
+	return retval;
+}
+
+/**
+ * Writes data to the VFD.  The Sasem VFD is 2x16 characters
+ * and requires data in 9 consecutive USB interrupt packets,
+ * each packet carrying 8 bytes.
+ */
+static ssize_t vfd_write(struct file *file, const char *buf,
+				size_t n_bytes, loff_t *pos)
+{
+	int i;
+	int retval = 0;
+	struct sasem_context *context;
+	int *data_buf;
+
+	context = (struct sasem_context *) file->private_data;
+	if (!context) {
+		err("%s: no context for device", __func__);
+		return -ENODEV;
+	}
+
+	mutex_lock(&context->ctx_lock);
+
+	if (!context->dev_present) {
+		err("%s: no Sasem device present", __func__);
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) {
+		err("%s: invalid payload size", __func__);
+		retval = -EINVAL;
+		goto exit;
+	}
+
+	data_buf = memdup_user(buf, n_bytes);
+	if (PTR_ERR(data_buf))
+		return PTR_ERR(data_buf);
+
+	memcpy(context->tx.data_buf, data_buf, n_bytes);
+
+	/* Pad with spaces */
+	for (i = n_bytes; i < SASEM_DATA_BUF_SZ; ++i)
+		context->tx.data_buf[i] = ' ';
+
+	/* Nine 8 byte packets to be sent */
+	/* NOTE: "\x07\x01\0\0\0\0\0\0" or "\x0c\0\0\0\0\0\0\0"
+	 *       will clear the VFD */
+	for (i = 0; i < 9; i++) {
+		switch (i) {
+		case 0:
+			memcpy(context->usb_tx_buf, "\x07\0\0\0\0\0\0\0", 8);
+			context->usb_tx_buf[1] = (context->vfd_contrast) ?
+				(0x2B - (context->vfd_contrast - 1) / 250)
+				: 0x2B;
+			break;
+		case 1:
+			memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
+			break;
+		case 2:
+			memcpy(context->usb_tx_buf, "\x0b\x01\0\0\0\0\0\0", 8);
+			break;
+		case 3:
+			memcpy(context->usb_tx_buf, context->tx.data_buf, 8);
+			break;
+		case 4:
+			memcpy(context->usb_tx_buf,
+			       context->tx.data_buf + 8, 8);
+			break;
+		case 5:
+			memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
+			break;
+		case 6:
+			memcpy(context->usb_tx_buf, "\x0b\x02\0\0\0\0\0\0", 8);
+			break;
+		case 7:
+			memcpy(context->usb_tx_buf,
+			       context->tx.data_buf + 16, 8);
+			break;
+		case 8:
+			memcpy(context->usb_tx_buf,
+			       context->tx.data_buf + 24, 8);
+			break;
+		}
+		retval = send_packet(context);
+		if (retval) {
+
+			err("%s: send packet failed for packet #%d",
+					__func__, i);
+			goto exit;
+		}
+	}
+exit:
+
+	mutex_unlock(&context->ctx_lock);
+
+	return (!retval) ? n_bytes : retval;
+}
+
+/**
+ * Callback function for USB core API: transmit data
+ */
+static void usb_tx_callback(struct urb *urb)
+{
+	struct sasem_context *context;
+
+	if (!urb)
+		return;
+	context = (struct sasem_context *) urb->context;
+	if (!context)
+		return;
+
+	context->tx.status = urb->status;
+
+	/* notify waiters that write has finished */
+	atomic_set(&context->tx.busy, 0);
+	complete(&context->tx.finished);
+
+	return;
+}
+
+/**
+ * Called by lirc_dev when the application opens /dev/lirc
+ */
+static int ir_open(void *data)
+{
+	int retval = 0;
+	struct sasem_context *context;
+
+	/* prevent races with disconnect */
+	mutex_lock(&disconnect_lock);
+
+	context = (struct sasem_context *) data;
+
+	mutex_lock(&context->ctx_lock);
+
+	if (context->ir_isopen) {
+		err("%s: IR port is already open", __func__);
+		retval = -EBUSY;
+		goto exit;
+	}
+
+	usb_fill_int_urb(context->rx_urb, context->dev,
+		usb_rcvintpipe(context->dev,
+				context->rx_endpoint->bEndpointAddress),
+		context->usb_rx_buf, sizeof(context->usb_rx_buf),
+		usb_rx_callback, context, context->rx_endpoint->bInterval);
+
+	retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
+
+	if (retval)
+		err("%s: usb_submit_urb failed for ir_open (%d)",
+		    __func__, retval);
+	else {
+		context->ir_isopen = 1;
+		printk(KERN_INFO "IR port opened\n");
+	}
+
+exit:
+	mutex_unlock(&context->ctx_lock);
+
+	mutex_unlock(&disconnect_lock);
+	return 0;
+}
+
+/**
+ * Called by lirc_dev when the application closes /dev/lirc
+ */
+static void ir_close(void *data)
+{
+	struct sasem_context *context;
+
+	context = (struct sasem_context *)data;
+	if (!context) {
+		err("%s: no context for device", __func__);
+		return;
+	}
+
+	mutex_lock(&context->ctx_lock);
+
+	usb_kill_urb(context->rx_urb);
+	context->ir_isopen = 0;
+	printk(KERN_INFO "IR port closed\n");
+
+	if (!context->dev_present) {
+
+		/*
+		 * Device disconnected while IR port was
+		 * still open. Driver was not deregistered
+		 * at disconnect time, so do it now.
+		 */
+		deregister_from_lirc(context);
+
+		if (!context->vfd_isopen) {
+
+			mutex_unlock(&context->ctx_lock);
+			delete_context(context);
+			return;
+		}
+		/* If VFD port is open, context will be deleted by vfd_close */
+	}
+
+	mutex_unlock(&context->ctx_lock);
+	return;
+}
+
+/**
+ * Process the incoming packet
+ */
+static void incoming_packet(struct sasem_context *context,
+				   struct urb *urb)
+{
+	int len = urb->actual_length;
+	unsigned char *buf = urb->transfer_buffer;
+	long ms;
+	struct timeval tv;
+
+	if (len != 8) {
+		printk(KERN_WARNING "%s: invalid incoming packet size (%d)\n",
+		     __func__, len);
+		return;
+	}
+
+#ifdef DEBUG
+	int i;
+	for (i = 0; i < 8; ++i)
+		printk(KERN_INFO "%02x ", buf[i]);
+	printk(KERN_INFO "\n");
+#endif
+
+	/*
+	 * Lirc could deal with the repeat code, but we really need to block it
+	 * if it arrives too late.  Otherwise we could repeat the wrong code.
+	 */
+
+	/* get the time since the last button press */
+	do_gettimeofday(&tv);
+	ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 +
+	     (tv.tv_usec - context->presstime.tv_usec) / 1000;
+
+	if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) {
+		/*
+		 * the repeat code is being sent, so we copy
+		 * the old code to LIRC
+		 */
+
+		/*
+		 * NOTE: Only if the last code was less than 250ms ago
+		 * - no one should be able to push another (undetected) button
+		 *   in that time and then get a false repeat of the previous
+		 *   press but it is long enough for a genuine repeat
+		 */
+		if ((ms < 250) && (context->codesaved != 0)) {
+			memcpy(buf, &context->lastcode, 8);
+			context->presstime.tv_sec = tv.tv_sec;
+			context->presstime.tv_usec = tv.tv_usec;
+		}
+	} else {
+		/* save the current valid code for repeats */
+		memcpy(&context->lastcode, buf, 8);
+		/*
+		 * set flag to signal a valid code was save;
+		 * just for safety reasons
+		 */
+		context->codesaved = 1;
+		context->presstime.tv_sec = tv.tv_sec;
+		context->presstime.tv_usec = tv.tv_usec;
+	}
+
+	lirc_buffer_write(context->driver->rbuf, buf);
+	wake_up(&context->driver->rbuf->wait_poll);
+}
+
+/**
+ * Callback function for USB core API: receive data
+ */
+static void usb_rx_callback(struct urb *urb)
+{
+	struct sasem_context *context;
+
+	if (!urb)
+		return;
+	context = (struct sasem_context *) urb->context;
+	if (!context)
+		return;
+
+	switch (urb->status) {
+
+	case -ENOENT:		/* usbcore unlink successful! */
+		return;
+
+	case 0:
+		if (context->ir_isopen)
+			incoming_packet(context, urb);
+		break;
+
+	default:
+		printk(KERN_WARNING "%s: status (%d): ignored",
+			 __func__, urb->status);
+		break;
+	}
+
+	usb_submit_urb(context->rx_urb, GFP_ATOMIC);
+	return;
+}
+
+
+
+/**
+ * Callback function for USB core API: Probe
+ */
+static int sasem_probe(struct usb_interface *interface,
+			const struct usb_device_id *id)
+{
+	struct usb_device *dev = NULL;
+	struct usb_host_interface *iface_desc = NULL;
+	struct usb_endpoint_descriptor *rx_endpoint = NULL;
+	struct usb_endpoint_descriptor *tx_endpoint = NULL;
+	struct urb *rx_urb = NULL;
+	struct urb *tx_urb = NULL;
+	struct lirc_driver *driver = NULL;
+	struct lirc_buffer *rbuf = NULL;
+	int lirc_minor = 0;
+	int num_endpoints;
+	int retval = 0;
+	int vfd_ep_found;
+	int ir_ep_found;
+	int alloc_status;
+	struct sasem_context *context = NULL;
+	int i;
+
+	printk(KERN_INFO "%s: found Sasem device\n", __func__);
+
+
+	dev = usb_get_dev(interface_to_usbdev(interface));
+	iface_desc = interface->cur_altsetting;
+	num_endpoints = iface_desc->desc.bNumEndpoints;
+
+	/*
+	 * Scan the endpoint list and set:
+	 *	first input endpoint = IR endpoint
+	 *	first output endpoint = VFD endpoint
+	 */
+
+	ir_ep_found = 0;
+	vfd_ep_found = 0;
+
+	for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) {
+
+		struct usb_endpoint_descriptor *ep;
+		int ep_dir;
+		int ep_type;
+		ep = &iface_desc->endpoint [i].desc;
+		ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+		ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+		if (!ir_ep_found &&
+			ep_dir == USB_DIR_IN &&
+			ep_type == USB_ENDPOINT_XFER_INT) {
+
+			rx_endpoint = ep;
+			ir_ep_found = 1;
+			if (debug)
+				printk(KERN_INFO "%s: found IR endpoint\n",
+				       __func__);
+
+		} else if (!vfd_ep_found &&
+			ep_dir == USB_DIR_OUT &&
+			ep_type == USB_ENDPOINT_XFER_INT) {
+
+			tx_endpoint = ep;
+			vfd_ep_found = 1;
+			if (debug)
+				printk(KERN_INFO "%s: found VFD endpoint\n",
+				       __func__);
+		}
+	}
+
+	/* Input endpoint is mandatory */
+	if (!ir_ep_found) {
+
+		err("%s: no valid input (IR) endpoint found.", __func__);
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	if (!vfd_ep_found)
+		printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n",
+		       __func__);
+
+
+	/* Allocate memory */
+	alloc_status = 0;
+
+	context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL);
+	if (!context) {
+		err("%s: kzalloc failed for context", __func__);
+		alloc_status = 1;
+		goto alloc_status_switch;
+	}
+	driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+	if (!driver) {
+		err("%s: kzalloc failed for lirc_driver", __func__);
+		alloc_status = 2;
+		goto alloc_status_switch;
+	}
+	rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+	if (!rbuf) {
+		err("%s: kmalloc failed for lirc_buffer", __func__);
+		alloc_status = 3;
+		goto alloc_status_switch;
+	}
+	if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
+		err("%s: lirc_buffer_init failed", __func__);
+		alloc_status = 4;
+		goto alloc_status_switch;
+	}
+	rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!rx_urb) {
+		err("%s: usb_alloc_urb failed for IR urb", __func__);
+		alloc_status = 5;
+		goto alloc_status_switch;
+	}
+	if (vfd_ep_found) {
+		tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!tx_urb) {
+			err("%s: usb_alloc_urb failed for VFD urb",
+			    __func__);
+			alloc_status = 6;
+			goto alloc_status_switch;
+		}
+	}
+
+	mutex_init(&context->ctx_lock);
+
+	strcpy(driver->name, MOD_NAME);
+	driver->minor = -1;
+	driver->code_length = 64;
+	driver->sample_rate = 0;
+	driver->features = LIRC_CAN_REC_LIRCCODE;
+	driver->data = context;
+	driver->rbuf = rbuf;
+	driver->set_use_inc = ir_open;
+	driver->set_use_dec = ir_close;
+	driver->dev   = &interface->dev;
+	driver->owner = THIS_MODULE;
+
+	mutex_lock(&context->ctx_lock);
+
+	lirc_minor = lirc_register_driver(driver);
+	if (lirc_minor < 0) {
+		err("%s: lirc_register_driver failed", __func__);
+		alloc_status = 7;
+		mutex_unlock(&context->ctx_lock);
+	} else
+		printk(KERN_INFO "%s: Registered Sasem driver (minor:%d)\n",
+			__func__, lirc_minor);
+
+alloc_status_switch:
+
+	switch (alloc_status) {
+
+	case 7:
+		if (vfd_ep_found)
+			usb_free_urb(tx_urb);
+	case 6:
+		usb_free_urb(rx_urb);
+	case 5:
+		lirc_buffer_free(rbuf);
+	case 4:
+		kfree(rbuf);
+	case 3:
+		kfree(driver);
+	case 2:
+		kfree(context);
+		context = NULL;
+	case 1:
+		retval = -ENOMEM;
+		goto exit;
+	}
+
+	/* Needed while unregistering! */
+	driver->minor = lirc_minor;
+
+	context->dev = dev;
+	context->dev_present = 1;
+	context->rx_endpoint = rx_endpoint;
+	context->rx_urb = rx_urb;
+	if (vfd_ep_found) {
+		context->tx_endpoint = tx_endpoint;
+		context->tx_urb = tx_urb;
+		context->vfd_contrast = 1000;   /* range 0 - 1000 */
+	}
+	context->driver = driver;
+
+	usb_set_intfdata(interface, context);
+
+	if (vfd_ep_found) {
+
+		if (debug)
+			printk(KERN_INFO "Registering VFD with sysfs\n");
+		if (usb_register_dev(interface, &sasem_class))
+			/* Not a fatal error, so ignore */
+			printk(KERN_INFO "%s: could not get a minor number "
+			       "for VFD\n", __func__);
+	}
+
+	printk(KERN_INFO "%s: Sasem device on usb<%d:%d> initialized\n",
+			__func__, dev->bus->busnum, dev->devnum);
+
+	mutex_unlock(&context->ctx_lock);
+exit:
+	return retval;
+}
+
+/**
+ * Callback function for USB core API: disonnect
+ */
+static void sasem_disconnect(struct usb_interface *interface)
+{
+	struct sasem_context *context;
+
+	/* prevent races with ir_open()/vfd_open() */
+	mutex_lock(&disconnect_lock);
+
+	context = usb_get_intfdata(interface);
+	mutex_lock(&context->ctx_lock);
+
+	printk(KERN_INFO "%s: Sasem device disconnected\n", __func__);
+
+	usb_set_intfdata(interface, NULL);
+	context->dev_present = 0;
+
+	/* Stop reception */
+	usb_kill_urb(context->rx_urb);
+
+	/* Abort ongoing write */
+	if (atomic_read(&context->tx.busy)) {
+
+		usb_kill_urb(context->tx_urb);
+		wait_for_completion(&context->tx.finished);
+	}
+
+	/* De-register from lirc_dev if IR port is not open */
+	if (!context->ir_isopen)
+		deregister_from_lirc(context);
+
+	usb_deregister_dev(interface, &sasem_class);
+
+	mutex_unlock(&context->ctx_lock);
+
+	if (!context->ir_isopen && !context->vfd_isopen)
+		delete_context(context);
+
+	mutex_unlock(&disconnect_lock);
+}
+
+static int __init sasem_init(void)
+{
+	int rc;
+
+	printk(KERN_INFO MOD_DESC ", v" MOD_VERSION "\n");
+	printk(KERN_INFO MOD_AUTHOR "\n");
+
+	rc = usb_register(&sasem_driver);
+	if (rc < 0) {
+		err("%s: usb register failed (%d)", __func__, rc);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void __exit sasem_exit(void)
+{
+	usb_deregister(&sasem_driver);
+	printk(KERN_INFO "module removed. Goodbye!\n");
+}
+
+
+module_init(sasem_init);
+module_exit(sasem_exit);
diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/lirc/lirc_serial.c
new file mode 100644
index 0000000..9456f8e
--- /dev/null
+++ b/drivers/staging/lirc/lirc_serial.c
@@ -0,0 +1,1313 @@
+/*
+ * lirc_serial.c
+ *
+ * lirc_serial - Device driver that records pulse- and pause-lengths
+ *	       (space-lengths) between DDCD event on a serial port.
+ *
+ * Copyright (C) 1996,97 Ralph Metzler <rjkm@thp.uni-koeln.de>
+ * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu>
+ * Copyright (C) 1998 Ben Pfaff <blp@gnu.org>
+ * Copyright (C) 1999 Christoph Bartelmus <lirc@bartelmus.de>
+ * Copyright (C) 2007 Andrei Tanas <andrei@tanas.ca> (suspend/resume support)
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * Steve's changes to improve transmission fidelity:
+ *   - for systems with the rdtsc instruction and the clock counter, a
+ *     send_pule that times the pulses directly using the counter.
+ *     This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is
+ *     not needed. Measurement shows very stable waveform, even where
+ *     PCI activity slows the access to the UART, which trips up other
+ *     versions.
+ *   - For other system, non-integer-microsecond pulse/space lengths,
+ *     done using fixed point binary. So, much more accurate carrier
+ *     frequency.
+ *   - fine tuned transmitter latency, taking advantage of fractional
+ *     microseconds in previous change
+ *   - Fixed bug in the way transmitter latency was accounted for by
+ *     tuning the pulse lengths down - the send_pulse routine ignored
+ *     this overhead as it timed the overall pulse length - so the
+ *     pulse frequency was right but overall pulse length was too
+ *     long. Fixed by accounting for latency on each pulse/space
+ *     iteration.
+ *
+ * Steve Davies <steve@daviesfam.org>  July 2001
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+
+#include <asm/system.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/fcntl.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+#include <asm/hardware.h>
+#endif
+/* From Intel IXP42X Developer's Manual (#252480-005): */
+/* ftp://download.intel.com/design/network/manuals/25248005.pdf */
+#define UART_IE_IXP42X_UUE   0x40 /* IXP42X UART Unit enable */
+#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#define LIRC_DRIVER_NAME "lirc_serial"
+
+struct lirc_serial {
+	int signal_pin;
+	int signal_pin_change;
+	u8 on;
+	u8 off;
+	long (*send_pulse)(unsigned long length);
+	void (*send_space)(long length);
+	int features;
+	spinlock_t lock;
+};
+
+#define LIRC_HOMEBREW		0
+#define LIRC_IRDEO		1
+#define LIRC_IRDEO_REMOTE	2
+#define LIRC_ANIMAX		3
+#define LIRC_IGOR		4
+#define LIRC_NSLU2		5
+
+/*** module parameters ***/
+static int type;
+static int io;
+static int irq;
+static int iommap;
+static int ioshift;
+static int softcarrier = 1;
+static int share_irq;
+static int debug;
+static int sense = -1;	/* -1 = auto, 0 = active high, 1 = active low */
+static int txsense;	/* 0 = active high, 1 = active low */
+
+#define dprintk(fmt, args...)					\
+	do {							\
+		if (debug)					\
+			printk(KERN_DEBUG LIRC_DRIVER_NAME ": "	\
+			       fmt, ## args);			\
+	} while (0)
+
+/* forward declarations */
+static long send_pulse_irdeo(unsigned long length);
+static long send_pulse_homebrew(unsigned long length);
+static void send_space_irdeo(long length);
+static void send_space_homebrew(long length);
+
+static struct lirc_serial hardware[] = {
+	[LIRC_HOMEBREW] = {
+		.signal_pin        = UART_MSR_DCD,
+		.signal_pin_change = UART_MSR_DDCD,
+		.on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
+		.off = (UART_MCR_RTS | UART_MCR_OUT2),
+		.send_pulse = send_pulse_homebrew,
+		.send_space = send_space_homebrew,
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+		.features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+				LIRC_CAN_SET_SEND_CARRIER |
+				LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+#else
+		.features    = LIRC_CAN_REC_MODE2
+#endif
+	},
+
+	[LIRC_IRDEO] = {
+		.signal_pin        = UART_MSR_DSR,
+		.signal_pin_change = UART_MSR_DDSR,
+		.on  = UART_MCR_OUT2,
+		.off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+		.send_pulse  = send_pulse_irdeo,
+		.send_space  = send_space_irdeo,
+		.features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+				LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+	},
+
+	[LIRC_IRDEO_REMOTE] = {
+		.signal_pin        = UART_MSR_DSR,
+		.signal_pin_change = UART_MSR_DDSR,
+		.on  = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+		.off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+		.send_pulse  = send_pulse_irdeo,
+		.send_space  = send_space_irdeo,
+		.features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+				LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+	},
+
+	[LIRC_ANIMAX] = {
+		.signal_pin        = UART_MSR_DCD,
+		.signal_pin_change = UART_MSR_DDCD,
+		.on  = 0,
+		.off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+		.send_pulse = NULL,
+		.send_space = NULL,
+		.features   = LIRC_CAN_REC_MODE2
+	},
+
+	[LIRC_IGOR] = {
+		.signal_pin        = UART_MSR_DSR,
+		.signal_pin_change = UART_MSR_DDSR,
+		.on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
+		.off = (UART_MCR_RTS | UART_MCR_OUT2),
+		.send_pulse = send_pulse_homebrew,
+		.send_space = send_space_homebrew,
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+		.features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+				LIRC_CAN_SET_SEND_CARRIER |
+				LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+#else
+		.features    = LIRC_CAN_REC_MODE2
+#endif
+	},
+
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+	/*
+	 * Modified Linksys Network Storage Link USB 2.0 (NSLU2):
+	 * We receive on CTS of the 2nd serial port (R142,LHS), we
+	 * transmit with a IR diode between GPIO[1] (green status LED),
+	 * and ground (Matthias Goebl <matthias.goebl@goebl.net>).
+	 * See also http://www.nslu2-linux.org for this device
+	 */
+	[LIRC_NSLU2] = {
+		.signal_pin        = UART_MSR_CTS,
+		.signal_pin_change = UART_MSR_DCTS,
+		.on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
+		.off = (UART_MCR_RTS | UART_MCR_OUT2),
+		.send_pulse = send_pulse_homebrew,
+		.send_space = send_space_homebrew,
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+		.features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+				LIRC_CAN_SET_SEND_CARRIER |
+				LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+#else
+		.features    = LIRC_CAN_REC_MODE2
+#endif
+	},
+#endif
+
+};
+
+#define RS_ISR_PASS_LIMIT 256
+
+/*
+ * A long pulse code from a remote might take up to 300 bytes.  The
+ * daemon should read the bytes as soon as they are generated, so take
+ * the number of keys you think you can push before the daemon runs
+ * and multiply by 300.  The driver will warn you if you overrun this
+ * buffer.  If you have a slow computer or non-busmastering IDE disks,
+ * maybe you will need to increase this.
+ */
+
+/* This MUST be a power of two!  It has to be larger than 1 as well. */
+
+#define RBUF_LEN 256
+
+static struct timeval lasttv = {0, 0};
+
+static struct lirc_buffer rbuf;
+
+static unsigned int freq = 38000;
+static unsigned int duty_cycle = 50;
+
+/* Initialized in init_timing_params() */
+static unsigned long period;
+static unsigned long pulse_width;
+static unsigned long space_width;
+
+#if defined(__i386__)
+/*
+ * From:
+ * Linux I/O port programming mini-HOWTO
+ * Author: Riku Saikkonen <Riku.Saikkonen@hut.fi>
+ * v, 28 December 1997
+ *
+ * [...]
+ * Actually, a port I/O instruction on most ports in the 0-0x3ff range
+ * takes almost exactly 1 microsecond, so if you're, for example, using
+ * the parallel port directly, just do additional inb()s from that port
+ * to delay.
+ * [...]
+ */
+/* transmitter latency 1.5625us 0x1.90 - this figure arrived at from
+ * comment above plus trimming to match actual measured frequency.
+ * This will be sensitive to cpu speed, though hopefully most of the 1.5us
+ * is spent in the uart access.  Still - for reference test machine was a
+ * 1.13GHz Athlon system - Steve
+ */
+
+/*
+ * changed from 400 to 450 as this works better on slower machines;
+ * faster machines will use the rdtsc code anyway
+ */
+#define LIRC_SERIAL_TRANSMITTER_LATENCY 450
+
+#else
+
+/* does anybody have information on other platforms ? */
+/* 256 = 1<<8 */
+#define LIRC_SERIAL_TRANSMITTER_LATENCY 256
+
+#endif  /* __i386__ */
+/*
+ * FIXME: should we be using hrtimers instead of this
+ * LIRC_SERIAL_TRANSMITTER_LATENCY nonsense?
+ */
+
+/* fetch serial input packet (1 byte) from register offset */
+static u8 sinp(int offset)
+{
+	if (iommap != 0)
+		/* the register is memory-mapped */
+		offset <<= ioshift;
+
+	return inb(io + offset);
+}
+
+/* write serial output packet (1 byte) of value to register offset */
+static void soutp(int offset, u8 value)
+{
+	if (iommap != 0)
+		/* the register is memory-mapped */
+		offset <<= ioshift;
+
+	outb(value, io + offset);
+}
+
+static void on(void)
+{
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+	/*
+	 * On NSLU2, we put the transmit diode between the output of the green
+	 * status LED and ground
+	 */
+	if (type == LIRC_NSLU2) {
+		gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW);
+		return;
+	}
+#endif
+	if (txsense)
+		soutp(UART_MCR, hardware[type].off);
+	else
+		soutp(UART_MCR, hardware[type].on);
+}
+
+static void off(void)
+{
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+	if (type == LIRC_NSLU2) {
+		gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH);
+		return;
+	}
+#endif
+	if (txsense)
+		soutp(UART_MCR, hardware[type].on);
+	else
+		soutp(UART_MCR, hardware[type].off);
+}
+
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_US 5000
+#else
+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
+#endif
+
+static void safe_udelay(unsigned long usecs)
+{
+	while (usecs > MAX_UDELAY_US) {
+		udelay(MAX_UDELAY_US);
+		usecs -= MAX_UDELAY_US;
+	}
+	udelay(usecs);
+}
+
+#ifdef USE_RDTSC
+/*
+ * This is an overflow/precision juggle, complicated in that we can't
+ * do long long divide in the kernel
+ */
+
+/*
+ * When we use the rdtsc instruction to measure clocks, we keep the
+ * pulse and space widths as clock cycles.  As this is CPU speed
+ * dependent, the widths must be calculated in init_port and ioctl
+ * time
+ */
+
+/* So send_pulse can quickly convert microseconds to clocks */
+static unsigned long conv_us_to_clocks;
+
+static int init_timing_params(unsigned int new_duty_cycle,
+		unsigned int new_freq)
+{
+	unsigned long long loops_per_sec, work;
+
+	duty_cycle = new_duty_cycle;
+	freq = new_freq;
+
+	loops_per_sec = current_cpu_data.loops_per_jiffy;
+	loops_per_sec *= HZ;
+
+	/* How many clocks in a microsecond?, avoiding long long divide */
+	work = loops_per_sec;
+	work *= 4295;  /* 4295 = 2^32 / 1e6 */
+	conv_us_to_clocks = (work >> 32);
+
+	/*
+	 * Carrier period in clocks, approach good up to 32GHz clock,
+	 * gets carrier frequency within 8Hz
+	 */
+	period = loops_per_sec >> 3;
+	period /= (freq >> 3);
+
+	/* Derive pulse and space from the period */
+	pulse_width = period * duty_cycle / 100;
+	space_width = period - pulse_width;
+	dprintk("in init_timing_params, freq=%d, duty_cycle=%d, "
+		"clk/jiffy=%ld, pulse=%ld, space=%ld, "
+		"conv_us_to_clocks=%ld\n",
+		freq, duty_cycle, current_cpu_data.loops_per_jiffy,
+		pulse_width, space_width, conv_us_to_clocks);
+	return 0;
+}
+#else /* ! USE_RDTSC */
+static int init_timing_params(unsigned int new_duty_cycle,
+		unsigned int new_freq)
+{
+/*
+ * period, pulse/space width are kept with 8 binary places -
+ * IE multiplied by 256.
+ */
+	if (256 * 1000000L / new_freq * new_duty_cycle / 100 <=
+	    LIRC_SERIAL_TRANSMITTER_LATENCY)
+		return -EINVAL;
+	if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <=
+	    LIRC_SERIAL_TRANSMITTER_LATENCY)
+		return -EINVAL;
+	duty_cycle = new_duty_cycle;
+	freq = new_freq;
+	period = 256 * 1000000L / freq;
+	pulse_width = period * duty_cycle / 100;
+	space_width = period - pulse_width;
+	dprintk("in init_timing_params, freq=%d pulse=%ld, "
+		"space=%ld\n", freq, pulse_width, space_width);
+	return 0;
+}
+#endif /* USE_RDTSC */
+
+
+/* return value: space length delta */
+
+static long send_pulse_irdeo(unsigned long length)
+{
+	long rawbits, ret;
+	int i;
+	unsigned char output;
+	unsigned char chunk, shifted;
+
+	/* how many bits have to be sent ? */
+	rawbits = length * 1152 / 10000;
+	if (duty_cycle > 50)
+		chunk = 3;
+	else
+		chunk = 1;
+	for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) {
+		shifted = chunk << (i * 3);
+		shifted >>= 1;
+		output &= (~shifted);
+		i++;
+		if (i == 3) {
+			soutp(UART_TX, output);
+			while (!(sinp(UART_LSR) & UART_LSR_THRE))
+				;
+			output = 0x7f;
+			i = 0;
+		}
+	}
+	if (i != 0) {
+		soutp(UART_TX, output);
+		while (!(sinp(UART_LSR) & UART_LSR_TEMT))
+			;
+	}
+
+	if (i == 0)
+		ret = (-rawbits) * 10000 / 1152;
+	else
+		ret = (3 - i) * 3 * 10000 / 1152 + (-rawbits) * 10000 / 1152;
+
+	return ret;
+}
+
+#ifdef USE_RDTSC
+/* Version that uses Pentium rdtsc instruction to measure clocks */
+
+/*
+ * This version does sub-microsecond timing using rdtsc instruction,
+ * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY
+ * Implicitly i586 architecture...  - Steve
+ */
+
+static long send_pulse_homebrew_softcarrier(unsigned long length)
+{
+	int flag;
+	unsigned long target, start, now;
+
+	/* Get going quick as we can */
+	rdtscl(start);
+	on();
+	/* Convert length from microseconds to clocks */
+	length *= conv_us_to_clocks;
+	/* And loop till time is up - flipping at right intervals */
+	now = start;
+	target = pulse_width;
+	flag = 1;
+	/*
+	 * FIXME: This looks like a hard busy wait, without even an occasional,
+	 * polite, cpu_relax() call.  There's got to be a better way?
+	 *
+	 * The i2c code has the result of a lot of bit-banging work, I wonder if
+	 * there's something there which could be helpful here.
+	 */
+	while ((now - start) < length) {
+		/* Delay till flip time */
+		do {
+			rdtscl(now);
+		} while ((now - start) < target);
+
+		/* flip */
+		if (flag) {
+			rdtscl(now);
+			off();
+			target += space_width;
+		} else {
+			rdtscl(now); on();
+			target += pulse_width;
+		}
+		flag = !flag;
+	}
+	rdtscl(now);
+	return ((now - start) - length) / conv_us_to_clocks;
+}
+#else /* ! USE_RDTSC */
+/* Version using udelay() */
+
+/*
+ * here we use fixed point arithmetic, with 8
+ * fractional bits.  that gets us within 0.1% or so of the right average
+ * frequency, albeit with some jitter in pulse length - Steve
+ */
+
+/* To match 8 fractional bits used for pulse/space length */
+
+static long send_pulse_homebrew_softcarrier(unsigned long length)
+{
+	int flag;
+	unsigned long actual, target, d;
+	length <<= 8;
+
+	actual = 0; target = 0; flag = 0;
+	while (actual < length) {
+		if (flag) {
+			off();
+			target += space_width;
+		} else {
+			on();
+			target += pulse_width;
+		}
+		d = (target - actual -
+		     LIRC_SERIAL_TRANSMITTER_LATENCY + 128) >> 8;
+		/*
+		 * Note - we've checked in ioctl that the pulse/space
+		 * widths are big enough so that d is > 0
+		 */
+		udelay(d);
+		actual += (d << 8) + LIRC_SERIAL_TRANSMITTER_LATENCY;
+		flag = !flag;
+	}
+	return (actual-length) >> 8;
+}
+#endif /* USE_RDTSC */
+
+static long send_pulse_homebrew(unsigned long length)
+{
+	if (length <= 0)
+		return 0;
+
+	if (softcarrier)
+		return send_pulse_homebrew_softcarrier(length);
+	else {
+		on();
+		safe_udelay(length);
+		return 0;
+	}
+}
+
+static void send_space_irdeo(long length)
+{
+	if (length <= 0)
+		return;
+
+	safe_udelay(length);
+}
+
+static void send_space_homebrew(long length)
+{
+	off();
+	if (length <= 0)
+		return;
+	safe_udelay(length);
+}
+
+static void rbwrite(int l)
+{
+	if (lirc_buffer_full(&rbuf)) {
+		/* no new signals will be accepted */
+		dprintk("Buffer overrun\n");
+		return;
+	}
+	lirc_buffer_write(&rbuf, (void *)&l);
+}
+
+static void frbwrite(int l)
+{
+	/* simple noise filter */
+	static int pulse, space;
+	static unsigned int ptr;
+
+	if (ptr > 0 && (l & PULSE_BIT)) {
+		pulse += l & PULSE_MASK;
+		if (pulse > 250) {
+			rbwrite(space);
+			rbwrite(pulse | PULSE_BIT);
+			ptr = 0;
+			pulse = 0;
+		}
+		return;
+	}
+	if (!(l & PULSE_BIT)) {
+		if (ptr == 0) {
+			if (l > 20000) {
+				space = l;
+				ptr++;
+				return;
+			}
+		} else {
+			if (l > 20000) {
+				space += pulse;
+				if (space > PULSE_MASK)
+					space = PULSE_MASK;
+				space += l;
+				if (space > PULSE_MASK)
+					space = PULSE_MASK;
+				pulse = 0;
+				return;
+			}
+			rbwrite(space);
+			rbwrite(pulse | PULSE_BIT);
+			ptr = 0;
+			pulse = 0;
+		}
+	}
+	rbwrite(l);
+}
+
+static irqreturn_t irq_handler(int i, void *blah)
+{
+	struct timeval tv;
+	int counter, dcd;
+	u8 status;
+	long deltv;
+	int data;
+	static int last_dcd = -1;
+
+	if ((sinp(UART_IIR) & UART_IIR_NO_INT)) {
+		/* not our interrupt */
+		return IRQ_NONE;
+	}
+
+	counter = 0;
+	do {
+		counter++;
+		status = sinp(UART_MSR);
+		if (counter > RS_ISR_PASS_LIMIT) {
+			printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: "
+			       "We're caught!\n");
+			break;
+		}
+		if ((status & hardware[type].signal_pin_change)
+		    && sense != -1) {
+			/* get current time */
+			do_gettimeofday(&tv);
+
+			/* New mode, written by Trent Piepho
+			   <xyzzy@u.washington.edu>. */
+
+			/*
+			 * The old format was not very portable.
+			 * We now use an int to pass pulses
+			 * and spaces to user space.
+			 *
+			 * If PULSE_BIT is set a pulse has been
+			 * received, otherwise a space has been
+			 * received.  The driver needs to know if your
+			 * receiver is active high or active low, or
+			 * the space/pulse sense could be
+			 * inverted. The bits denoted by PULSE_MASK are
+			 * the length in microseconds. Lengths greater
+			 * than or equal to 16 seconds are clamped to
+			 * PULSE_MASK.  All other bits are unused.
+			 * This is a much simpler interface for user
+			 * programs, as well as eliminating "out of
+			 * phase" errors with space/pulse
+			 * autodetection.
+			 */
+
+			/* calc time since last interrupt in microseconds */
+			dcd = (status & hardware[type].signal_pin) ? 1 : 0;
+
+			if (dcd == last_dcd) {
+				printk(KERN_WARNING LIRC_DRIVER_NAME
+				": ignoring spike: %d %d %lx %lx %lx %lx\n",
+				dcd, sense,
+				tv.tv_sec, lasttv.tv_sec,
+				tv.tv_usec, lasttv.tv_usec);
+				continue;
+			}
+
+			deltv = tv.tv_sec-lasttv.tv_sec;
+			if (tv.tv_sec < lasttv.tv_sec ||
+			    (tv.tv_sec == lasttv.tv_sec &&
+			     tv.tv_usec < lasttv.tv_usec)) {
+				printk(KERN_WARNING LIRC_DRIVER_NAME
+				       ": AIEEEE: your clock just jumped "
+				       "backwards\n");
+				printk(KERN_WARNING LIRC_DRIVER_NAME
+				       ": %d %d %lx %lx %lx %lx\n",
+				       dcd, sense,
+				       tv.tv_sec, lasttv.tv_sec,
+				       tv.tv_usec, lasttv.tv_usec);
+				data = PULSE_MASK;
+			} else if (deltv > 15) {
+				data = PULSE_MASK; /* really long time */
+				if (!(dcd^sense)) {
+					/* sanity check */
+					printk(KERN_WARNING LIRC_DRIVER_NAME
+					       ": AIEEEE: "
+					       "%d %d %lx %lx %lx %lx\n",
+					       dcd, sense,
+					       tv.tv_sec, lasttv.tv_sec,
+					       tv.tv_usec, lasttv.tv_usec);
+					/*
+					 * detecting pulse while this
+					 * MUST be a space!
+					 */
+					sense = sense ? 0 : 1;
+				}
+			} else
+				data = (int) (deltv*1000000 +
+					       tv.tv_usec -
+					       lasttv.tv_usec);
+			frbwrite(dcd^sense ? data : (data|PULSE_BIT));
+			lasttv = tv;
+			last_dcd = dcd;
+			wake_up_interruptible(&rbuf.wait_poll);
+		}
+	} while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */
+	return IRQ_HANDLED;
+}
+
+
+static int hardware_init_port(void)
+{
+	u8 scratch, scratch2, scratch3;
+
+	/*
+	 * This is a simple port existence test, borrowed from the autoconfig
+	 * function in drivers/serial/8250.c
+	 */
+	scratch = sinp(UART_IER);
+	soutp(UART_IER, 0);
+#ifdef __i386__
+	outb(0xff, 0x080);
+#endif
+	scratch2 = sinp(UART_IER) & 0x0f;
+	soutp(UART_IER, 0x0f);
+#ifdef __i386__
+	outb(0x00, 0x080);
+#endif
+	scratch3 = sinp(UART_IER) & 0x0f;
+	soutp(UART_IER, scratch);
+	if (scratch2 != 0 || scratch3 != 0x0f) {
+		/* we fail, there's nothing here */
+		printk(KERN_ERR LIRC_DRIVER_NAME ": port existence test "
+		       "failed, cannot continue\n");
+		return -EINVAL;
+	}
+
+
+
+	/* Set DLAB 0. */
+	soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+	/* First of all, disable all interrupts */
+	soutp(UART_IER, sinp(UART_IER) &
+	      (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+
+	/* Clear registers. */
+	sinp(UART_LSR);
+	sinp(UART_RX);
+	sinp(UART_IIR);
+	sinp(UART_MSR);
+
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+	if (type == LIRC_NSLU2) {
+		/* Setup NSLU2 UART */
+
+		/* Enable UART */
+		soutp(UART_IER, sinp(UART_IER) | UART_IE_IXP42X_UUE);
+		/* Disable Receiver data Time out interrupt */
+		soutp(UART_IER, sinp(UART_IER) & ~UART_IE_IXP42X_RTOIE);
+		/* set out2 = interrupt unmask; off() doesn't set MCR
+		   on NSLU2 */
+		soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+	}
+#endif
+
+	/* Set line for power source */
+	off();
+
+	/* Clear registers again to be sure. */
+	sinp(UART_LSR);
+	sinp(UART_RX);
+	sinp(UART_IIR);
+	sinp(UART_MSR);
+
+	switch (type) {
+	case LIRC_IRDEO:
+	case LIRC_IRDEO_REMOTE:
+		/* setup port to 7N1 @ 115200 Baud */
+		/* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */
+
+		/* Set DLAB 1. */
+		soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+		/* Set divisor to 1 => 115200 Baud */
+		soutp(UART_DLM, 0);
+		soutp(UART_DLL, 1);
+		/* Set DLAB 0 +  7N1 */
+		soutp(UART_LCR, UART_LCR_WLEN7);
+		/* THR interrupt already disabled at this point */
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int init_port(void)
+{
+	int i, nlow, nhigh;
+
+	/* Reserve io region. */
+	/*
+	 * Future MMAP-Developers: Attention!
+	 * For memory mapped I/O you *might* need to use ioremap() first,
+	 * for the NSLU2 it's done in boot code.
+	 */
+	if (((iommap != 0)
+	     && (request_mem_region(iommap, 8 << ioshift,
+				    LIRC_DRIVER_NAME) == NULL))
+	   || ((iommap == 0)
+	       && (request_region(io, 8, LIRC_DRIVER_NAME) == NULL))) {
+		printk(KERN_ERR  LIRC_DRIVER_NAME
+		       ": port %04x already in use\n", io);
+		printk(KERN_WARNING LIRC_DRIVER_NAME
+		       ": use 'setserial /dev/ttySX uart none'\n");
+		printk(KERN_WARNING LIRC_DRIVER_NAME
+		       ": or compile the serial port driver as module and\n");
+		printk(KERN_WARNING LIRC_DRIVER_NAME
+		       ": make sure this module is loaded first\n");
+		return -EBUSY;
+	}
+
+	if (hardware_init_port() < 0)
+		return -EINVAL;
+
+	/* Initialize pulse/space widths */
+	init_timing_params(duty_cycle, freq);
+
+	/* If pin is high, then this must be an active low receiver. */
+	if (sense == -1) {
+		/* wait 1/2 sec for the power supply */
+		msleep(500);
+
+		/*
+		 * probe 9 times every 0.04s, collect "votes" for
+		 * active high/low
+		 */
+		nlow = 0;
+		nhigh = 0;
+		for (i = 0; i < 9; i++) {
+			if (sinp(UART_MSR) & hardware[type].signal_pin)
+				nlow++;
+			else
+				nhigh++;
+			msleep(40);
+		}
+		sense = (nlow >= nhigh ? 1 : 0);
+		printk(KERN_INFO LIRC_DRIVER_NAME  ": auto-detected active "
+		       "%s receiver\n", sense ? "low" : "high");
+	} else
+		printk(KERN_INFO LIRC_DRIVER_NAME  ": Manually using active "
+		       "%s receiver\n", sense ? "low" : "high");
+
+	return 0;
+}
+
+static int set_use_inc(void *data)
+{
+	int result;
+	unsigned long flags;
+
+	/* initialize timestamp */
+	do_gettimeofday(&lasttv);
+
+	result = request_irq(irq, irq_handler,
+			     IRQF_DISABLED | (share_irq ? IRQF_SHARED : 0),
+			     LIRC_DRIVER_NAME, (void *)&hardware);
+
+	switch (result) {
+	case -EBUSY:
+		printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq);
+		return -EBUSY;
+	case -EINVAL:
+		printk(KERN_ERR LIRC_DRIVER_NAME
+		       ": Bad irq number or handler\n");
+		return -EINVAL;
+	default:
+		dprintk("Interrupt %d, port %04x obtained\n", irq, io);
+		break;
+	};
+
+	spin_lock_irqsave(&hardware[type].lock, flags);
+
+	/* Set DLAB 0. */
+	soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+	soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI);
+
+	spin_unlock_irqrestore(&hardware[type].lock, flags);
+
+	return 0;
+}
+
+static void set_use_dec(void *data)
+{	unsigned long flags;
+
+	spin_lock_irqsave(&hardware[type].lock, flags);
+
+	/* Set DLAB 0. */
+	soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+	/* First of all, disable all interrupts */
+	soutp(UART_IER, sinp(UART_IER) &
+	      (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+	spin_unlock_irqrestore(&hardware[type].lock, flags);
+
+	free_irq(irq, (void *)&hardware);
+
+	dprintk("freed IRQ %d\n", irq);
+}
+
+static ssize_t lirc_write(struct file *file, const char *buf,
+			 size_t n, loff_t *ppos)
+{
+	int i, count;
+	unsigned long flags;
+	long delta = 0;
+	int *wbuf;
+
+	if (!(hardware[type].features & LIRC_CAN_SEND_PULSE))
+		return -EBADF;
+
+	count = n / sizeof(int);
+	if (n % sizeof(int) || count % 2 == 0)
+		return -EINVAL;
+	wbuf = memdup_user(buf, n);
+	if (PTR_ERR(wbuf))
+		return PTR_ERR(wbuf);
+	spin_lock_irqsave(&hardware[type].lock, flags);
+	if (type == LIRC_IRDEO) {
+		/* DTR, RTS down */
+		on();
+	}
+	for (i = 0; i < count; i++) {
+		if (i%2)
+			hardware[type].send_space(wbuf[i] - delta);
+		else
+			delta = hardware[type].send_pulse(wbuf[i]);
+	}
+	off();
+	spin_unlock_irqrestore(&hardware[type].lock, flags);
+	return n;
+}
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+	int result;
+	unsigned long value;
+	unsigned int ivalue;
+
+	switch (cmd) {
+	case LIRC_GET_SEND_MODE:
+		if (!(hardware[type].features&LIRC_CAN_SEND_MASK))
+			return -ENOIOCTLCMD;
+
+		result = put_user(LIRC_SEND2MODE
+				  (hardware[type].features&LIRC_CAN_SEND_MASK),
+				  (unsigned long *) arg);
+		if (result)
+			return result;
+		break;
+
+	case LIRC_SET_SEND_MODE:
+		if (!(hardware[type].features&LIRC_CAN_SEND_MASK))
+			return -ENOIOCTLCMD;
+
+		result = get_user(value, (unsigned long *) arg);
+		if (result)
+			return result;
+		/* only LIRC_MODE_PULSE supported */
+		if (value != LIRC_MODE_PULSE)
+			return -ENOSYS;
+		break;
+
+	case LIRC_GET_LENGTH:
+		return -ENOSYS;
+		break;
+
+	case LIRC_SET_SEND_DUTY_CYCLE:
+		dprintk("SET_SEND_DUTY_CYCLE\n");
+		if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE))
+			return -ENOIOCTLCMD;
+
+		result = get_user(ivalue, (unsigned int *) arg);
+		if (result)
+			return result;
+		if (ivalue <= 0 || ivalue > 100)
+			return -EINVAL;
+		return init_timing_params(ivalue, freq);
+		break;
+
+	case LIRC_SET_SEND_CARRIER:
+		dprintk("SET_SEND_CARRIER\n");
+		if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER))
+			return -ENOIOCTLCMD;
+
+		result = get_user(ivalue, (unsigned int *) arg);
+		if (result)
+			return result;
+		if (ivalue > 500000 || ivalue < 20000)
+			return -EINVAL;
+		return init_timing_params(duty_cycle, ivalue);
+		break;
+
+	default:
+		return lirc_dev_fop_ioctl(filep, cmd, arg);
+	}
+	return 0;
+}
+
+static const struct file_operations lirc_fops = {
+	.owner		= THIS_MODULE,
+	.write		= lirc_write,
+	.unlocked_ioctl	= lirc_ioctl,
+	.read		= lirc_dev_fop_read,
+	.poll		= lirc_dev_fop_poll,
+	.open		= lirc_dev_fop_open,
+	.release	= lirc_dev_fop_close,
+};
+
+static struct lirc_driver driver = {
+	.name		= LIRC_DRIVER_NAME,
+	.minor		= -1,
+	.code_length	= 1,
+	.sample_rate	= 0,
+	.data		= NULL,
+	.add_to_buf	= NULL,
+	.rbuf		= &rbuf,
+	.set_use_inc	= set_use_inc,
+	.set_use_dec	= set_use_dec,
+	.fops		= &lirc_fops,
+	.dev		= NULL,
+	.owner		= THIS_MODULE,
+};
+
+static struct platform_device *lirc_serial_dev;
+
+static int __devinit lirc_serial_probe(struct platform_device *dev)
+{
+	return 0;
+}
+
+static int __devexit lirc_serial_remove(struct platform_device *dev)
+{
+	return 0;
+}
+
+static int lirc_serial_suspend(struct platform_device *dev,
+			       pm_message_t state)
+{
+	/* Set DLAB 0. */
+	soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+	/* Disable all interrupts */
+	soutp(UART_IER, sinp(UART_IER) &
+	      (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+
+	/* Clear registers. */
+	sinp(UART_LSR);
+	sinp(UART_RX);
+	sinp(UART_IIR);
+	sinp(UART_MSR);
+
+	return 0;
+}
+
+/* twisty maze... need a forward-declaration here... */
+static void lirc_serial_exit(void);
+
+static int lirc_serial_resume(struct platform_device *dev)
+{
+	unsigned long flags;
+
+	if (hardware_init_port() < 0) {
+		lirc_serial_exit();
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&hardware[type].lock, flags);
+	/* Enable Interrupt */
+	do_gettimeofday(&lasttv);
+	soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI);
+	off();
+
+	lirc_buffer_clear(&rbuf);
+
+	spin_unlock_irqrestore(&hardware[type].lock, flags);
+
+	return 0;
+}
+
+static struct platform_driver lirc_serial_driver = {
+	.probe		= lirc_serial_probe,
+	.remove		= __devexit_p(lirc_serial_remove),
+	.suspend	= lirc_serial_suspend,
+	.resume		= lirc_serial_resume,
+	.driver		= {
+		.name	= "lirc_serial",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init lirc_serial_init(void)
+{
+	int result;
+
+	/* Init read buffer. */
+	result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN);
+	if (result < 0)
+		return -ENOMEM;
+
+	result = platform_driver_register(&lirc_serial_driver);
+	if (result) {
+		printk("lirc register returned %d\n", result);
+		goto exit_buffer_free;
+	}
+
+	lirc_serial_dev = platform_device_alloc("lirc_serial", 0);
+	if (!lirc_serial_dev) {
+		result = -ENOMEM;
+		goto exit_driver_unregister;
+	}
+
+	result = platform_device_add(lirc_serial_dev);
+	if (result)
+		goto exit_device_put;
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(lirc_serial_dev);
+exit_driver_unregister:
+	platform_driver_unregister(&lirc_serial_driver);
+exit_buffer_free:
+	lirc_buffer_free(&rbuf);
+	return result;
+}
+
+static void lirc_serial_exit(void)
+{
+	platform_device_unregister(lirc_serial_dev);
+	platform_driver_unregister(&lirc_serial_driver);
+	lirc_buffer_free(&rbuf);
+}
+
+static int __init lirc_serial_init_module(void)
+{
+	int result;
+
+	result = lirc_serial_init();
+	if (result)
+		return result;
+
+	switch (type) {
+	case LIRC_HOMEBREW:
+	case LIRC_IRDEO:
+	case LIRC_IRDEO_REMOTE:
+	case LIRC_ANIMAX:
+	case LIRC_IGOR:
+		/* if nothing specified, use ttyS0/com1 and irq 4 */
+		io = io ? io : 0x3f8;
+		irq = irq ? irq : 4;
+		break;
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+	case LIRC_NSLU2:
+		io = io ? io : IRQ_IXP4XX_UART2;
+		irq = irq ? irq : (IXP4XX_UART2_BASE_VIRT + REG_OFFSET);
+		iommap = iommap ? iommap : IXP4XX_UART2_BASE_PHYS;
+		ioshift = ioshift ? ioshift : 2;
+		break;
+#endif
+	default:
+		result = -EINVAL;
+		goto exit_serial_exit;
+	}
+	if (!softcarrier) {
+		switch (type) {
+		case LIRC_HOMEBREW:
+		case LIRC_IGOR:
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+		case LIRC_NSLU2:
+#endif
+			hardware[type].features &=
+				~(LIRC_CAN_SET_SEND_DUTY_CYCLE|
+				  LIRC_CAN_SET_SEND_CARRIER);
+			break;
+		}
+	}
+
+	result = init_port();
+	if (result < 0)
+		goto exit_serial_exit;
+	driver.features = hardware[type].features;
+	driver.dev = &lirc_serial_dev->dev;
+	driver.minor = lirc_register_driver(&driver);
+	if (driver.minor < 0) {
+		printk(KERN_ERR  LIRC_DRIVER_NAME
+		       ": register_chrdev failed!\n");
+		result = -EIO;
+		goto exit_release;
+	}
+	return 0;
+exit_release:
+	release_region(io, 8);
+exit_serial_exit:
+	lirc_serial_exit();
+	return result;
+}
+
+static void __exit lirc_serial_exit_module(void)
+{
+	lirc_serial_exit();
+	if (iommap != 0)
+		release_mem_region(iommap, 8 << ioshift);
+	else
+		release_region(io, 8);
+	lirc_unregister_driver(driver.minor);
+	dprintk("cleaned up module\n");
+}
+
+
+module_init(lirc_serial_init_module);
+module_exit(lirc_serial_exit_module);
+
+MODULE_DESCRIPTION("Infra-red receiver driver for serial ports.");
+MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, "
+	      "Christoph Bartelmus, Andrei Tanas");
+MODULE_LICENSE("GPL");
+
+module_param(type, int, S_IRUGO);
+MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo,"
+		 " 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug,"
+		 " 5 = NSLU2 RX:CTS2/TX:GreenLED)");
+
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");
+
+/* some architectures (e.g. intel xscale) have memory mapped registers */
+module_param(iommap, bool, S_IRUGO);
+MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O"
+		" (0 = no memory mapped io)");
+
+/*
+ * some architectures (e.g. intel xscale) align the 8bit serial registers
+ * on 32bit word boundaries.
+ * See linux-kernel/serial/8250.c serial_in()/out()
+ */
+module_param(ioshift, int, S_IRUGO);
+MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)");
+
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");
+
+module_param(share_irq, bool, S_IRUGO);
+MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)");
+
+module_param(sense, bool, S_IRUGO);
+MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit"
+		 " (0 = active high, 1 = active low )");
+
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+module_param(txsense, bool, S_IRUGO);
+MODULE_PARM_DESC(txsense, "Sense of transmitter circuit"
+		 " (0 = active high, 1 = active low )");
+#endif
+
+module_param(softcarrier, bool, S_IRUGO);
+MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/lirc/lirc_sir.c
new file mode 100644
index 0000000..eb08fa7
--- /dev/null
+++ b/drivers/staging/lirc/lirc_sir.c
@@ -0,0 +1,1282 @@
+/*
+ * LIRC SIR driver, (C) 2000 Milan Pikula <www@fornax.sk>
+ *
+ * lirc_sir - Device driver for use with SIR (serial infra red)
+ * mode of IrDA on many notebooks.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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
+ *
+ *
+ * 2000/09/16 Frank Przybylski <mail@frankprzybylski.de> :
+ *  added timeout and relaxed pulse detection, removed gap bug
+ *
+ * 2000/12/15 Christoph Bartelmus <lirc@bartelmus.de> :
+ *   added support for Tekram Irmate 210 (sending does not work yet,
+ *   kind of disappointing that nobody was able to implement that
+ *   before),
+ *   major clean-up
+ *
+ * 2001/02/27 Christoph Bartelmus <lirc@bartelmus.de> :
+ *   added support for StrongARM SA1100 embedded microprocessor
+ *   parts cut'n'pasted from sa1100_ir.c (C) 2000 Russell King
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <asm/system.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <linux/fcntl.h>
+#ifdef LIRC_ON_SA1100
+#include <asm/hardware.h>
+#ifdef CONFIG_SA1100_COLLIE
+#include <asm/arch/tc35143.h>
+#include <asm/ucb1200.h>
+#endif
+#endif
+
+#include <linux/timer.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+/* SECTION: Definitions */
+
+/*** Tekram dongle ***/
+#ifdef LIRC_SIR_TEKRAM
+/* stolen from kernel source */
+/* definitions for Tekram dongle */
+#define TEKRAM_115200 0x00
+#define TEKRAM_57600  0x01
+#define TEKRAM_38400  0x02
+#define TEKRAM_19200  0x03
+#define TEKRAM_9600   0x04
+#define TEKRAM_2400   0x08
+
+#define TEKRAM_PW 0x10 /* Pulse select bit */
+
+/* 10bit * 1s/115200bit in milliseconds = 87ms*/
+#define TIME_CONST (10000000ul/115200ul)
+
+#endif
+
+#ifdef LIRC_SIR_ACTISYS_ACT200L
+static void init_act200(void);
+#elif defined(LIRC_SIR_ACTISYS_ACT220L)
+static void init_act220(void);
+#endif
+
+/*** SA1100 ***/
+#ifdef LIRC_ON_SA1100
+struct sa1100_ser2_registers {
+	/* HSSP control register */
+	unsigned char hscr0;
+	/* UART registers */
+	unsigned char utcr0;
+	unsigned char utcr1;
+	unsigned char utcr2;
+	unsigned char utcr3;
+	unsigned char utcr4;
+	unsigned char utdr;
+	unsigned char utsr0;
+	unsigned char utsr1;
+} sr;
+
+static int irq = IRQ_Ser2ICP;
+
+#define LIRC_ON_SA1100_TRANSMITTER_LATENCY 0
+
+/* pulse/space ratio of 50/50 */
+static unsigned long pulse_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY);
+/* 1000000/freq-pulse_width */
+static unsigned long space_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY);
+static unsigned int freq = 38000;      /* modulation frequency */
+static unsigned int duty_cycle = 50;   /* duty cycle of 50% */
+
+#endif
+
+#define RBUF_LEN 1024
+#define WBUF_LEN 1024
+
+#define LIRC_DRIVER_NAME "lirc_sir"
+
+#define PULSE '['
+
+#ifndef LIRC_SIR_TEKRAM
+/* 9bit * 1s/115200bit in milli seconds = 78.125ms*/
+#define TIME_CONST (9000000ul/115200ul)
+#endif
+
+
+/* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */
+#define SIR_TIMEOUT	(HZ*5/100)
+
+#ifndef LIRC_ON_SA1100
+#ifndef LIRC_IRQ
+#define LIRC_IRQ 4
+#endif
+#ifndef LIRC_PORT
+/* for external dongles, default to com1 */
+#if defined(LIRC_SIR_ACTISYS_ACT200L) || \
+    defined(LIRC_SIR_ACTISYS_ACT220L) || \
+    defined(LIRC_SIR_TEKRAM)
+#define LIRC_PORT 0x3f8
+#else
+/* onboard sir ports are typically com3 */
+#define LIRC_PORT 0x3e8
+#endif
+#endif
+
+static int io = LIRC_PORT;
+static int irq = LIRC_IRQ;
+static int threshold = 3;
+#endif
+
+static DEFINE_SPINLOCK(timer_lock);
+static struct timer_list timerlist;
+/* time of last signal change detected */
+static struct timeval last_tv = {0, 0};
+/* time of last UART data ready interrupt */
+static struct timeval last_intr_tv = {0, 0};
+static int last_value;
+
+static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue);
+
+static DEFINE_SPINLOCK(hardware_lock);
+
+static int rx_buf[RBUF_LEN];
+static unsigned int rx_tail, rx_head;
+
+static int debug;
+#define dprintk(fmt, args...)						\
+	do {								\
+		if (debug)						\
+			printk(KERN_DEBUG LIRC_DRIVER_NAME ": "		\
+				fmt, ## args);				\
+	} while (0)
+
+/* SECTION: Prototypes */
+
+/* Communication with user-space */
+static unsigned int lirc_poll(struct file *file, poll_table *wait);
+static ssize_t lirc_read(struct file *file, char *buf, size_t count,
+		loff_t *ppos);
+static ssize_t lirc_write(struct file *file, const char *buf, size_t n,
+		loff_t *pos);
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
+static void add_read_queue(int flag, unsigned long val);
+static int init_chrdev(void);
+static void drop_chrdev(void);
+/* Hardware */
+static irqreturn_t sir_interrupt(int irq, void *dev_id);
+static void send_space(unsigned long len);
+static void send_pulse(unsigned long len);
+static int init_hardware(void);
+static void drop_hardware(void);
+/* Initialisation */
+static int init_port(void);
+static void drop_port(void);
+
+#ifdef LIRC_ON_SA1100
+static void on(void)
+{
+	PPSR |= PPC_TXD2;
+}
+
+static void off(void)
+{
+	PPSR &= ~PPC_TXD2;
+}
+#else
+static inline unsigned int sinp(int offset)
+{
+	return inb(io + offset);
+}
+
+static inline void soutp(int offset, int value)
+{
+	outb(value, io + offset);
+}
+#endif
+
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_US 5000
+#else
+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
+#endif
+
+static void safe_udelay(unsigned long usecs)
+{
+	while (usecs > MAX_UDELAY_US) {
+		udelay(MAX_UDELAY_US);
+		usecs -= MAX_UDELAY_US;
+	}
+	udelay(usecs);
+}
+
+/* SECTION: Communication with user-space */
+
+static unsigned int lirc_poll(struct file *file, poll_table *wait)
+{
+	poll_wait(file, &lirc_read_queue, wait);
+	if (rx_head != rx_tail)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static ssize_t lirc_read(struct file *file, char *buf, size_t count,
+		loff_t *ppos)
+{
+	int n = 0;
+	int retval = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (count % sizeof(int))
+		return -EINVAL;
+
+	add_wait_queue(&lirc_read_queue, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	while (n < count) {
+		if (rx_head != rx_tail) {
+			if (copy_to_user((void *) buf + n,
+					(void *) (rx_buf + rx_head),
+					sizeof(int))) {
+				retval = -EFAULT;
+				break;
+			}
+			rx_head = (rx_head + 1) & (RBUF_LEN - 1);
+			n += sizeof(int);
+		} else {
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				retval = -ERESTARTSYS;
+				break;
+			}
+			schedule();
+			set_current_state(TASK_INTERRUPTIBLE);
+		}
+	}
+	remove_wait_queue(&lirc_read_queue, &wait);
+	set_current_state(TASK_RUNNING);
+	return n ? n : retval;
+}
+static ssize_t lirc_write(struct file *file, const char *buf, size_t n,
+				loff_t *pos)
+{
+	unsigned long flags;
+	int i, count;
+	int *tx_buf;
+
+	count = n / sizeof(int);
+	if (n % sizeof(int) || count % 2 == 0)
+		return -EINVAL;
+	tx_buf = memdup_user(buf, n);
+	if (IS_ERR(tx_buf))
+		return PTR_ERR(tx_buf);
+	i = 0;
+#ifdef LIRC_ON_SA1100
+	/* disable receiver */
+	Ser2UTCR3 = 0;
+#endif
+	local_irq_save(flags);
+	while (1) {
+		if (i >= count)
+			break;
+		if (tx_buf[i])
+			send_pulse(tx_buf[i]);
+		i++;
+		if (i >= count)
+			break;
+		if (tx_buf[i])
+			send_space(tx_buf[i]);
+		i++;
+	}
+	local_irq_restore(flags);
+#ifdef LIRC_ON_SA1100
+	off();
+	udelay(1000); /* wait 1ms for IR diode to recover */
+	Ser2UTCR3 = 0;
+	/* clear status register to prevent unwanted interrupts */
+	Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+	/* enable receiver */
+	Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE;
+#endif
+	return count;
+}
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+	int retval = 0;
+	unsigned long value = 0;
+#ifdef LIRC_ON_SA1100
+	unsigned int ivalue;
+
+	if (cmd == LIRC_GET_FEATURES)
+		value = LIRC_CAN_SEND_PULSE |
+			LIRC_CAN_SET_SEND_DUTY_CYCLE |
+			LIRC_CAN_SET_SEND_CARRIER |
+			LIRC_CAN_REC_MODE2;
+	else if (cmd == LIRC_GET_SEND_MODE)
+		value = LIRC_MODE_PULSE;
+	else if (cmd == LIRC_GET_REC_MODE)
+		value = LIRC_MODE_MODE2;
+#else
+	if (cmd == LIRC_GET_FEATURES)
+		value = LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
+	else if (cmd == LIRC_GET_SEND_MODE)
+		value = LIRC_MODE_PULSE;
+	else if (cmd == LIRC_GET_REC_MODE)
+		value = LIRC_MODE_MODE2;
+#endif
+
+	switch (cmd) {
+	case LIRC_GET_FEATURES:
+	case LIRC_GET_SEND_MODE:
+	case LIRC_GET_REC_MODE:
+		retval = put_user(value, (unsigned long *) arg);
+		break;
+
+	case LIRC_SET_SEND_MODE:
+	case LIRC_SET_REC_MODE:
+		retval = get_user(value, (unsigned long *) arg);
+		break;
+#ifdef LIRC_ON_SA1100
+	case LIRC_SET_SEND_DUTY_CYCLE:
+		retval = get_user(ivalue, (unsigned int *) arg);
+		if (retval)
+			return retval;
+		if (ivalue <= 0 || ivalue > 100)
+			return -EINVAL;
+		/* (ivalue/100)*(1000000/freq) */
+		duty_cycle = ivalue;
+		pulse_width = (unsigned long) duty_cycle*10000/freq;
+		space_width = (unsigned long) 1000000L/freq-pulse_width;
+		if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+			pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+		if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+			space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+		break;
+	case LIRC_SET_SEND_CARRIER:
+		retval = get_user(ivalue, (unsigned int *) arg);
+		if (retval)
+			return retval;
+		if (ivalue > 500000 || ivalue < 20000)
+			return -EINVAL;
+		freq = ivalue;
+		pulse_width = (unsigned long) duty_cycle*10000/freq;
+		space_width = (unsigned long) 1000000L/freq-pulse_width;
+		if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+			pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+		if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+			space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+		break;
+#endif
+	default:
+		retval = -ENOIOCTLCMD;
+
+	}
+
+	if (retval)
+		return retval;
+	if (cmd == LIRC_SET_REC_MODE) {
+		if (value != LIRC_MODE_MODE2)
+			retval = -ENOSYS;
+	} else if (cmd == LIRC_SET_SEND_MODE) {
+		if (value != LIRC_MODE_PULSE)
+			retval = -ENOSYS;
+	}
+
+	return retval;
+}
+
+static void add_read_queue(int flag, unsigned long val)
+{
+	unsigned int new_rx_tail;
+	int newval;
+
+	dprintk("add flag %d with val %lu\n", flag, val);
+
+	newval = val & PULSE_MASK;
+
+	/*
+	 * statistically, pulses are ~TIME_CONST/2 too long. we could
+	 * maybe make this more exact, but this is good enough
+	 */
+	if (flag) {
+		/* pulse */
+		if (newval > TIME_CONST/2)
+			newval -= TIME_CONST/2;
+		else /* should not ever happen */
+			newval = 1;
+		newval |= PULSE_BIT;
+	} else {
+		newval += TIME_CONST/2;
+	}
+	new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1);
+	if (new_rx_tail == rx_head) {
+		dprintk("Buffer overrun.\n");
+		return;
+	}
+	rx_buf[rx_tail] = newval;
+	rx_tail = new_rx_tail;
+	wake_up_interruptible(&lirc_read_queue);
+}
+
+static const struct file_operations lirc_fops = {
+	.owner		= THIS_MODULE,
+	.read		= lirc_read,
+	.write		= lirc_write,
+	.poll		= lirc_poll,
+	.unlocked_ioctl	= lirc_ioctl,
+	.open		= lirc_dev_fop_open,
+	.release	= lirc_dev_fop_close,
+};
+
+static int set_use_inc(void *data)
+{
+       return 0;
+}
+
+static void set_use_dec(void *data)
+{
+}
+
+static struct lirc_driver driver = {
+       .name		= LIRC_DRIVER_NAME,
+       .minor		= -1,
+       .code_length	= 1,
+       .sample_rate	= 0,
+       .data		= NULL,
+       .add_to_buf	= NULL,
+       .set_use_inc	= set_use_inc,
+       .set_use_dec	= set_use_dec,
+       .fops		= &lirc_fops,
+       .dev		= NULL,
+       .owner		= THIS_MODULE,
+};
+
+
+static int init_chrdev(void)
+{
+	driver.minor = lirc_register_driver(&driver);
+	if (driver.minor < 0) {
+		printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static void drop_chrdev(void)
+{
+	lirc_unregister_driver(driver.minor);
+}
+
+/* SECTION: Hardware */
+static long delta(struct timeval *tv1, struct timeval *tv2)
+{
+	unsigned long deltv;
+
+	deltv = tv2->tv_sec - tv1->tv_sec;
+	if (deltv > 15)
+		deltv = 0xFFFFFF;
+	else
+		deltv = deltv*1000000 +
+			tv2->tv_usec -
+			tv1->tv_usec;
+	return deltv;
+}
+
+static void sir_timeout(unsigned long data)
+{
+	/*
+	 * if last received signal was a pulse, but receiving stopped
+	 * within the 9 bit frame, we need to finish this pulse and
+	 * simulate a signal change to from pulse to space. Otherwise
+	 * upper layers will receive two sequences next time.
+	 */
+
+	unsigned long flags;
+	unsigned long pulse_end;
+
+	/* avoid interference with interrupt */
+	spin_lock_irqsave(&timer_lock, flags);
+	if (last_value) {
+#ifndef LIRC_ON_SA1100
+		/* clear unread bits in UART and restart */
+		outb(UART_FCR_CLEAR_RCVR, io + UART_FCR);
+#endif
+		/* determine 'virtual' pulse end: */
+		pulse_end = delta(&last_tv, &last_intr_tv);
+		dprintk("timeout add %d for %lu usec\n", last_value, pulse_end);
+		add_read_queue(last_value, pulse_end);
+		last_value = 0;
+		last_tv = last_intr_tv;
+	}
+	spin_unlock_irqrestore(&timer_lock, flags);
+}
+
+static irqreturn_t sir_interrupt(int irq, void *dev_id)
+{
+	unsigned char data;
+	struct timeval curr_tv;
+	static unsigned long deltv;
+#ifdef LIRC_ON_SA1100
+	int status;
+	static int n;
+
+	status = Ser2UTSR0;
+	/*
+	 * Deal with any receive errors first.  The bytes in error may be
+	 * the only bytes in the receive FIFO, so we do this first.
+	 */
+	while (status & UTSR0_EIF) {
+		int bstat;
+
+		if (debug) {
+			dprintk("EIF\n");
+			bstat = Ser2UTSR1;
+
+			if (bstat & UTSR1_FRE)
+				dprintk("frame error\n");
+			if (bstat & UTSR1_ROR)
+				dprintk("receive fifo overrun\n");
+			if (bstat & UTSR1_PRE)
+				dprintk("parity error\n");
+		}
+
+		bstat = Ser2UTDR;
+		n++;
+		status = Ser2UTSR0;
+	}
+
+	if (status & (UTSR0_RFS | UTSR0_RID)) {
+		do_gettimeofday(&curr_tv);
+		deltv = delta(&last_tv, &curr_tv);
+		do {
+			data = Ser2UTDR;
+			dprintk("%d data: %u\n", n, (unsigned int) data);
+			n++;
+		} while (status & UTSR0_RID && /* do not empty fifo in order to
+						* get UTSR0_RID in any case */
+		      Ser2UTSR1 & UTSR1_RNE); /* data ready */
+
+		if (status&UTSR0_RID) {
+			add_read_queue(0 , deltv - n * TIME_CONST); /*space*/
+			add_read_queue(1, n * TIME_CONST); /*pulse*/
+			n = 0;
+			last_tv = curr_tv;
+		}
+	}
+
+	if (status & UTSR0_TFS)
+		printk(KERN_ERR "transmit fifo not full, shouldn't happen\n");
+
+	/* We must clear certain bits. */
+	status &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+	if (status)
+		Ser2UTSR0 = status;
+#else
+	unsigned long deltintrtv;
+	unsigned long flags;
+	int iir, lsr;
+
+	while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) {
+		switch (iir&UART_IIR_ID) { /* FIXME toto treba preriedit */
+		case UART_IIR_MSI:
+			(void) inb(io + UART_MSR);
+			break;
+		case UART_IIR_RLSI:
+			(void) inb(io + UART_LSR);
+			break;
+		case UART_IIR_THRI:
+#if 0
+			if (lsr & UART_LSR_THRE) /* FIFO is empty */
+				outb(data, io + UART_TX)
+#endif
+			break;
+		case UART_IIR_RDI:
+			/* avoid interference with timer */
+			spin_lock_irqsave(&timer_lock, flags);
+			do {
+				del_timer(&timerlist);
+				data = inb(io + UART_RX);
+				do_gettimeofday(&curr_tv);
+				deltv = delta(&last_tv, &curr_tv);
+				deltintrtv = delta(&last_intr_tv, &curr_tv);
+				dprintk("t %lu, d %d\n", deltintrtv, (int)data);
+				/*
+				 * if nothing came in last X cycles,
+				 * it was gap
+				 */
+				if (deltintrtv > TIME_CONST * threshold) {
+					if (last_value) {
+						dprintk("GAP\n");
+						/* simulate signal change */
+						add_read_queue(last_value,
+							       deltv -
+							       deltintrtv);
+						last_value = 0;
+						last_tv.tv_sec =
+							last_intr_tv.tv_sec;
+						last_tv.tv_usec =
+							last_intr_tv.tv_usec;
+						deltv = deltintrtv;
+					}
+				}
+				data = 1;
+				if (data ^ last_value) {
+					/*
+					 * deltintrtv > 2*TIME_CONST, remember?
+					 * the other case is timeout
+					 */
+					add_read_queue(last_value,
+						       deltv-TIME_CONST);
+					last_value = data;
+					last_tv = curr_tv;
+					if (last_tv.tv_usec >= TIME_CONST) {
+						last_tv.tv_usec -= TIME_CONST;
+					} else {
+						last_tv.tv_sec--;
+						last_tv.tv_usec += 1000000 -
+							TIME_CONST;
+					}
+				}
+				last_intr_tv = curr_tv;
+				if (data) {
+					/*
+					 * start timer for end of
+					 * sequence detection
+					 */
+					timerlist.expires = jiffies +
+								SIR_TIMEOUT;
+					add_timer(&timerlist);
+				}
+
+				lsr = inb(io + UART_LSR);
+			} while (lsr & UART_LSR_DR); /* data ready */
+			spin_unlock_irqrestore(&timer_lock, flags);
+			break;
+		default:
+			break;
+		}
+	}
+#endif
+	return IRQ_RETVAL(IRQ_HANDLED);
+}
+
+#ifdef LIRC_ON_SA1100
+static void send_pulse(unsigned long length)
+{
+	unsigned long k, delay;
+	int flag;
+
+	if (length == 0)
+		return;
+	/*
+	 * this won't give us the carrier frequency we really want
+	 * due to integer arithmetic, but we can accept this inaccuracy
+	 */
+
+	for (k = flag = 0; k < length; k += delay, flag = !flag) {
+		if (flag) {
+			off();
+			delay = space_width;
+		} else {
+			on();
+			delay = pulse_width;
+		}
+		safe_udelay(delay);
+	}
+	off();
+}
+
+static void send_space(unsigned long length)
+{
+	if (length == 0)
+		return;
+	off();
+	safe_udelay(length);
+}
+#else
+static void send_space(unsigned long len)
+{
+	safe_udelay(len);
+}
+
+static void send_pulse(unsigned long len)
+{
+	long bytes_out = len / TIME_CONST;
+	long time_left;
+
+	time_left = (long)len - (long)bytes_out * (long)TIME_CONST;
+	if (bytes_out == 0) {
+		bytes_out++;
+		time_left = 0;
+	}
+	while (bytes_out--) {
+		outb(PULSE, io + UART_TX);
+		/* FIXME treba seriozne cakanie z char/serial.c */
+		while (!(inb(io + UART_LSR) & UART_LSR_THRE))
+			;
+	}
+#if 0
+	if (time_left > 0)
+		safe_udelay(time_left);
+#endif
+}
+#endif
+
+#ifdef CONFIG_SA1100_COLLIE
+static int sa1100_irda_set_power_collie(int state)
+{
+	if (state) {
+		/*
+		 *  0 - off
+		 *  1 - short range, lowest power
+		 *  2 - medium range, medium power
+		 *  3 - maximum range, high power
+		 */
+		ucb1200_set_io_direction(TC35143_GPIO_IR_ON,
+					 TC35143_IODIR_OUTPUT);
+		ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_LOW);
+		udelay(100);
+	} else {
+		/* OFF */
+		ucb1200_set_io_direction(TC35143_GPIO_IR_ON,
+					 TC35143_IODIR_OUTPUT);
+		ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_HIGH);
+	}
+	return 0;
+}
+#endif
+
+static int init_hardware(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hardware_lock, flags);
+	/* reset UART */
+#ifdef LIRC_ON_SA1100
+#ifdef CONFIG_SA1100_BITSY
+	if (machine_is_bitsy()) {
+		printk(KERN_INFO "Power on IR module\n");
+		set_bitsy_egpio(EGPIO_BITSY_IR_ON);
+	}
+#endif
+#ifdef CONFIG_SA1100_COLLIE
+	sa1100_irda_set_power_collie(3);	/* power on */
+#endif
+	sr.hscr0 = Ser2HSCR0;
+
+	sr.utcr0 = Ser2UTCR0;
+	sr.utcr1 = Ser2UTCR1;
+	sr.utcr2 = Ser2UTCR2;
+	sr.utcr3 = Ser2UTCR3;
+	sr.utcr4 = Ser2UTCR4;
+
+	sr.utdr = Ser2UTDR;
+	sr.utsr0 = Ser2UTSR0;
+	sr.utsr1 = Ser2UTSR1;
+
+	/* configure GPIO */
+	/* output */
+	PPDR |= PPC_TXD2;
+	PSDR |= PPC_TXD2;
+	/* set output to 0 */
+	off();
+
+	/* Enable HP-SIR modulation, and ensure that the port is disabled. */
+	Ser2UTCR3 = 0;
+	Ser2HSCR0 = sr.hscr0 & (~HSCR0_HSSP);
+
+	/* clear status register to prevent unwanted interrupts */
+	Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+
+	/* 7N1 */
+	Ser2UTCR0 = UTCR0_1StpBit|UTCR0_7BitData;
+	/* 115200 */
+	Ser2UTCR1 = 0;
+	Ser2UTCR2 = 1;
+	/* use HPSIR, 1.6 usec pulses */
+	Ser2UTCR4 = UTCR4_HPSIR|UTCR4_Z1_6us;
+
+	/* enable receiver, receive fifo interrupt */
+	Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE;
+
+	/* clear status register to prevent unwanted interrupts */
+	Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+
+#elif defined(LIRC_SIR_TEKRAM)
+	/* disable FIFO */
+	soutp(UART_FCR,
+	      UART_FCR_CLEAR_RCVR|
+	      UART_FCR_CLEAR_XMIT|
+	      UART_FCR_TRIGGER_1);
+
+	/* Set DLAB 0. */
+	soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+	/* First of all, disable all interrupts */
+	soutp(UART_IER, sinp(UART_IER) &
+	      (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+
+	/* Set DLAB 1. */
+	soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+
+	/* Set divisor to 12 => 9600 Baud */
+	soutp(UART_DLM, 0);
+	soutp(UART_DLL, 12);
+
+	/* Set DLAB 0. */
+	soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+	/* power supply */
+	soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+	safe_udelay(50*1000);
+
+	/* -DTR low -> reset PIC */
+	soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+	udelay(1*1000);
+
+	soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+	udelay(100);
+
+
+	/* -RTS low -> send control byte */
+	soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
+	udelay(7);
+	soutp(UART_TX, TEKRAM_115200|TEKRAM_PW);
+
+	/* one byte takes ~1042 usec to transmit at 9600,8N1 */
+	udelay(1500);
+
+	/* back to normal operation */
+	soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+	udelay(50);
+
+	udelay(1500);
+
+	/* read previous control byte */
+	printk(KERN_INFO LIRC_DRIVER_NAME
+	       ": 0x%02x\n", sinp(UART_RX));
+
+	/* Set DLAB 1. */
+	soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+
+	/* Set divisor to 1 => 115200 Baud */
+	soutp(UART_DLM, 0);
+	soutp(UART_DLL, 1);
+
+	/* Set DLAB 0, 8 Bit */
+	soutp(UART_LCR, UART_LCR_WLEN8);
+	/* enable interrupts */
+	soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI);
+#else
+	outb(0, io + UART_MCR);
+	outb(0, io + UART_IER);
+	/* init UART */
+	/* set DLAB, speed = 115200 */
+	outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR);
+	outb(1, io + UART_DLL); outb(0, io + UART_DLM);
+	/* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */
+	outb(UART_LCR_WLEN7, io + UART_LCR);
+	/* FIFO operation */
+	outb(UART_FCR_ENABLE_FIFO, io + UART_FCR);
+	/* interrupts */
+	/* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */
+	outb(UART_IER_RDI, io + UART_IER);
+	/* turn on UART */
+	outb(UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2, io + UART_MCR);
+#ifdef LIRC_SIR_ACTISYS_ACT200L
+	init_act200();
+#elif defined(LIRC_SIR_ACTISYS_ACT220L)
+	init_act220();
+#endif
+#endif
+	spin_unlock_irqrestore(&hardware_lock, flags);
+	return 0;
+}
+
+static void drop_hardware(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hardware_lock, flags);
+
+#ifdef LIRC_ON_SA1100
+	Ser2UTCR3 = 0;
+
+	Ser2UTCR0 = sr.utcr0;
+	Ser2UTCR1 = sr.utcr1;
+	Ser2UTCR2 = sr.utcr2;
+	Ser2UTCR4 = sr.utcr4;
+	Ser2UTCR3 = sr.utcr3;
+
+	Ser2HSCR0 = sr.hscr0;
+#ifdef CONFIG_SA1100_BITSY
+	if (machine_is_bitsy())
+		clr_bitsy_egpio(EGPIO_BITSY_IR_ON);
+#endif
+#ifdef CONFIG_SA1100_COLLIE
+	sa1100_irda_set_power_collie(0);	/* power off */
+#endif
+#else
+	/* turn off interrupts */
+	outb(0, io + UART_IER);
+#endif
+	spin_unlock_irqrestore(&hardware_lock, flags);
+}
+
+/* SECTION: Initialisation */
+
+static int init_port(void)
+{
+	int retval;
+
+	/* get I/O port access and IRQ line */
+#ifndef LIRC_ON_SA1100
+	if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) {
+		printk(KERN_ERR LIRC_DRIVER_NAME
+		       ": i/o port 0x%.4x already in use.\n", io);
+		return -EBUSY;
+	}
+#endif
+	retval = request_irq(irq, sir_interrupt, IRQF_DISABLED,
+			     LIRC_DRIVER_NAME, NULL);
+	if (retval < 0) {
+#               ifndef LIRC_ON_SA1100
+		release_region(io, 8);
+#               endif
+		printk(KERN_ERR LIRC_DRIVER_NAME
+			": IRQ %d already in use.\n",
+			irq);
+		return retval;
+	}
+#ifndef LIRC_ON_SA1100
+	printk(KERN_INFO LIRC_DRIVER_NAME
+		": I/O port 0x%.4x, IRQ %d.\n",
+		io, irq);
+#endif
+
+	init_timer(&timerlist);
+	timerlist.function = sir_timeout;
+	timerlist.data = 0xabadcafe;
+
+	return 0;
+}
+
+static void drop_port(void)
+{
+	free_irq(irq, NULL);
+	del_timer_sync(&timerlist);
+#ifndef LIRC_ON_SA1100
+	release_region(io, 8);
+#endif
+}
+
+#ifdef LIRC_SIR_ACTISYS_ACT200L
+/* Crystal/Cirrus CS8130 IR transceiver, used in Actisys Act200L dongle */
+/* some code borrowed from Linux IRDA driver */
+
+/* Register 0: Control register #1 */
+#define ACT200L_REG0    0x00
+#define ACT200L_TXEN    0x01 /* Enable transmitter */
+#define ACT200L_RXEN    0x02 /* Enable receiver */
+#define ACT200L_ECHO    0x08 /* Echo control chars */
+
+/* Register 1: Control register #2 */
+#define ACT200L_REG1    0x10
+#define ACT200L_LODB    0x01 /* Load new baud rate count value */
+#define ACT200L_WIDE    0x04 /* Expand the maximum allowable pulse */
+
+/* Register 3: Transmit mode register #2 */
+#define ACT200L_REG3    0x30
+#define ACT200L_B0      0x01 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P)  */
+#define ACT200L_B1      0x02 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P)  */
+#define ACT200L_CHSY    0x04 /* StartBit Synced 0=bittime, 1=startbit */
+
+/* Register 4: Output Power register */
+#define ACT200L_REG4    0x40
+#define ACT200L_OP0     0x01 /* Enable LED1C output */
+#define ACT200L_OP1     0x02 /* Enable LED2C output */
+#define ACT200L_BLKR    0x04
+
+/* Register 5: Receive Mode register */
+#define ACT200L_REG5    0x50
+#define ACT200L_RWIDL   0x01 /* fixed 1.6us pulse mode */
+    /*.. other various IRDA bit modes, and TV remote modes..*/
+
+/* Register 6: Receive Sensitivity register #1 */
+#define ACT200L_REG6    0x60
+#define ACT200L_RS0     0x01 /* receive threshold bit 0 */
+#define ACT200L_RS1     0x02 /* receive threshold bit 1 */
+
+/* Register 7: Receive Sensitivity register #2 */
+#define ACT200L_REG7    0x70
+#define ACT200L_ENPOS   0x04 /* Ignore the falling edge */
+
+/* Register 8,9: Baud Rate Divider register #1,#2 */
+#define ACT200L_REG8    0x80
+#define ACT200L_REG9    0x90
+
+#define ACT200L_2400    0x5f
+#define ACT200L_9600    0x17
+#define ACT200L_19200   0x0b
+#define ACT200L_38400   0x05
+#define ACT200L_57600   0x03
+#define ACT200L_115200  0x01
+
+/* Register 13: Control register #3 */
+#define ACT200L_REG13   0xd0
+#define ACT200L_SHDW    0x01 /* Enable access to shadow registers */
+
+/* Register 15: Status register */
+#define ACT200L_REG15   0xf0
+
+/* Register 21: Control register #4 */
+#define ACT200L_REG21   0x50
+#define ACT200L_EXCK    0x02 /* Disable clock output driver */
+#define ACT200L_OSCL    0x04 /* oscillator in low power, medium accuracy mode */
+
+static void init_act200(void)
+{
+	int i;
+	__u8 control[] = {
+		ACT200L_REG15,
+		ACT200L_REG13 | ACT200L_SHDW,
+		ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL,
+		ACT200L_REG13,
+		ACT200L_REG7  | ACT200L_ENPOS,
+		ACT200L_REG6  | ACT200L_RS0  | ACT200L_RS1,
+		ACT200L_REG5  | ACT200L_RWIDL,
+		ACT200L_REG4  | ACT200L_OP0  | ACT200L_OP1 | ACT200L_BLKR,
+		ACT200L_REG3  | ACT200L_B0,
+		ACT200L_REG0  | ACT200L_TXEN | ACT200L_RXEN,
+		ACT200L_REG8 |  (ACT200L_115200       & 0x0f),
+		ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f),
+		ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE
+	};
+
+	/* Set DLAB 1. */
+	soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8);
+
+	/* Set divisor to 12 => 9600 Baud */
+	soutp(UART_DLM, 0);
+	soutp(UART_DLL, 12);
+
+	/* Set DLAB 0. */
+	soutp(UART_LCR, UART_LCR_WLEN8);
+	/* Set divisor to 12 => 9600 Baud */
+
+	/* power supply */
+	soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+	for (i = 0; i < 50; i++)
+		safe_udelay(1000);
+
+		/* Reset the dongle : set RTS low for 25 ms */
+	soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
+	for (i = 0; i < 25; i++)
+		udelay(1000);
+
+	soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+	udelay(100);
+
+	/* Clear DTR and set RTS to enter command mode */
+	soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+	udelay(7);
+
+	/* send out the control register settings for 115K 7N1 SIR operation */
+	for (i = 0; i < sizeof(control); i++) {
+		soutp(UART_TX, control[i]);
+		/* one byte takes ~1042 usec to transmit at 9600,8N1 */
+		udelay(1500);
+	}
+
+	/* back to normal operation */
+	soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+	udelay(50);
+
+	udelay(1500);
+	soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+
+	/* Set DLAB 1. */
+	soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7);
+
+	/* Set divisor to 1 => 115200 Baud */
+	soutp(UART_DLM, 0);
+	soutp(UART_DLL, 1);
+
+	/* Set DLAB 0. */
+	soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+	/* Set DLAB 0, 7 Bit */
+	soutp(UART_LCR, UART_LCR_WLEN7);
+
+	/* enable interrupts */
+	soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI);
+}
+#endif
+
+#ifdef LIRC_SIR_ACTISYS_ACT220L
+/*
+ * Derived from linux IrDA driver (net/irda/actisys.c)
+ * Drop me a mail for any kind of comment: maxx@spaceboyz.net
+ */
+
+void init_act220(void)
+{
+	int i;
+
+	/* DLAB 1 */
+	soutp(UART_LCR, UART_LCR_DLAB|UART_LCR_WLEN7);
+
+	/* 9600 baud */
+	soutp(UART_DLM, 0);
+	soutp(UART_DLL, 12);
+
+	/* DLAB 0 */
+	soutp(UART_LCR, UART_LCR_WLEN7);
+
+	/* reset the dongle, set DTR low for 10us */
+	soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+	udelay(10);
+
+	/* back to normal (still 9600) */
+	soutp(UART_MCR, UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2);
+
+	/*
+	 * send RTS pulses until we reach 115200
+	 * i hope this is really the same for act220l/act220l+
+	 */
+	for (i = 0; i < 3; i++) {
+		udelay(10);
+		/* set RTS low for 10 us */
+		soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
+		udelay(10);
+		/* set RTS high for 10 us */
+		soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+	}
+
+	/* back to normal operation */
+	udelay(1500); /* better safe than sorry ;) */
+
+	/* Set DLAB 1. */
+	soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7);
+
+	/* Set divisor to 1 => 115200 Baud */
+	soutp(UART_DLM, 0);
+	soutp(UART_DLL, 1);
+
+	/* Set DLAB 0, 7 Bit */
+	/* The dongle doesn't seem to have any problems with operation at 7N1 */
+	soutp(UART_LCR, UART_LCR_WLEN7);
+
+	/* enable interrupts */
+	soutp(UART_IER, UART_IER_RDI);
+}
+#endif
+
+static int init_lirc_sir(void)
+{
+	int retval;
+
+	init_waitqueue_head(&lirc_read_queue);
+	retval = init_port();
+	if (retval < 0)
+		return retval;
+	init_hardware();
+	printk(KERN_INFO LIRC_DRIVER_NAME
+		": Installed.\n");
+	return 0;
+}
+
+
+static int __init lirc_sir_init(void)
+{
+	int retval;
+
+	retval = init_chrdev();
+	if (retval < 0)
+		return retval;
+	retval = init_lirc_sir();
+	if (retval) {
+		drop_chrdev();
+		return retval;
+	}
+	return 0;
+}
+
+static void __exit lirc_sir_exit(void)
+{
+	drop_hardware();
+	drop_chrdev();
+	drop_port();
+	printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
+}
+
+module_init(lirc_sir_init);
+module_exit(lirc_sir_exit);
+
+#ifdef LIRC_SIR_TEKRAM
+MODULE_DESCRIPTION("Infrared receiver driver for Tekram Irmate 210");
+MODULE_AUTHOR("Christoph Bartelmus");
+#elif defined(LIRC_ON_SA1100)
+MODULE_DESCRIPTION("LIRC driver for StrongARM SA1100 embedded microprocessor");
+MODULE_AUTHOR("Christoph Bartelmus");
+#elif defined(LIRC_SIR_ACTISYS_ACT200L)
+MODULE_DESCRIPTION("LIRC driver for Actisys Act200L");
+MODULE_AUTHOR("Karl Bongers");
+#elif defined(LIRC_SIR_ACTISYS_ACT220L)
+MODULE_DESCRIPTION("LIRC driver for Actisys Act220L(+)");
+MODULE_AUTHOR("Jan Roemisch");
+#else
+MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports");
+MODULE_AUTHOR("Milan Pikula");
+#endif
+MODULE_LICENSE("GPL");
+
+#ifdef LIRC_ON_SA1100
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (16)");
+#else
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");
+
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");
+
+module_param(threshold, int, S_IRUGO);
+MODULE_PARM_DESC(threshold, "space detection threshold (3)");
+#endif
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/lirc/lirc_streamzap.c b/drivers/staging/lirc/lirc_streamzap.c
new file mode 100644
index 0000000..be09c10
--- /dev/null
+++ b/drivers/staging/lirc/lirc_streamzap.c
@@ -0,0 +1,821 @@
+/*
+ * Streamzap Remote Control driver
+ *
+ * Copyright (c) 2005 Christoph Bartelmus <lirc@bartelmus.de>
+ *
+ * This driver was based on the work of Greg Wickham and Adrian
+ * Dewhurst. It was substantially rewritten to support correct signal
+ * gaps and now maintains a delay buffer, which is used to present
+ * consistent timing behaviour to user space applications. Without the
+ * delay buffer an ugly hack would be required in lircd, which can
+ * cause sluggish signal decoding in certain situations.
+ *
+ * This driver is based on the USB skeleton driver packaged with the
+ * kernel; copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#define DRIVER_VERSION	"1.28"
+#define DRIVER_NAME	"lirc_streamzap"
+#define DRIVER_DESC	"Streamzap Remote Control driver"
+
+static int debug;
+
+#define USB_STREAMZAP_VENDOR_ID		0x0e9c
+#define USB_STREAMZAP_PRODUCT_ID	0x0000
+
+/* Use our own dbg macro */
+#define dprintk(fmt, args...)					\
+	do {							\
+		if (debug)					\
+			printk(KERN_DEBUG DRIVER_NAME "[%d]: "	\
+			       fmt "\n", ## args);		\
+	} while (0)
+
+/* table of devices that work with this driver */
+static struct usb_device_id streamzap_table[] = {
+	/* Streamzap Remote Control */
+	{ USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) },
+	/* Terminating entry */
+	{ }
+};
+
+MODULE_DEVICE_TABLE(usb, streamzap_table);
+
+#define STREAMZAP_PULSE_MASK 0xf0
+#define STREAMZAP_SPACE_MASK 0x0f
+#define STREAMZAP_TIMEOUT    0xff
+#define STREAMZAP_RESOLUTION 256
+
+/* number of samples buffered */
+#define STREAMZAP_BUF_LEN 128
+
+enum StreamzapDecoderState {
+	PulseSpace,
+	FullPulse,
+	FullSpace,
+	IgnorePulse
+};
+
+/* Structure to hold all of our device specific stuff
+ *
+ * some remarks regarding locking:
+ * theoretically this struct can be accessed from three threads:
+ *
+ * - from lirc_dev through set_use_inc/set_use_dec
+ *
+ * - from the USB layer throuh probe/disconnect/irq
+ *
+ *   Careful placement of lirc_register_driver/lirc_unregister_driver
+ *   calls will prevent conflicts. lirc_dev makes sure that
+ *   set_use_inc/set_use_dec are not being executed and will not be
+ *   called after lirc_unregister_driver returns.
+ *
+ * - by the timer callback
+ *
+ *   The timer is only running when the device is connected and the
+ *   LIRC device is open. Making sure the timer is deleted by
+ *   set_use_dec will make conflicts impossible.
+ */
+struct usb_streamzap {
+
+	/* usb */
+	/* save off the usb device pointer */
+	struct usb_device	*udev;
+	/* the interface for this device */
+	struct usb_interface	*interface;
+
+	/* buffer & dma */
+	unsigned char		*buf_in;
+	dma_addr_t		dma_in;
+	unsigned int		buf_in_len;
+
+	struct usb_endpoint_descriptor *endpoint;
+
+	/* IRQ */
+	struct urb		*urb_in;
+
+	/* lirc */
+	struct lirc_driver	*driver;
+	struct lirc_buffer	*delay_buf;
+
+	/* timer used to support delay buffering */
+	struct timer_list	delay_timer;
+	int			timer_running;
+	spinlock_t		timer_lock;
+
+	/* tracks whether we are currently receiving some signal */
+	int			idle;
+	/* sum of signal lengths received since signal start */
+	unsigned long		sum;
+	/* start time of signal; necessary for gap tracking */
+	struct timeval		signal_last;
+	struct timeval		signal_start;
+	enum StreamzapDecoderState decoder_state;
+	struct timer_list	flush_timer;
+	int			flush;
+	int			in_use;
+	int			timeout_enabled;
+};
+
+
+/* local function prototypes */
+static int streamzap_probe(struct usb_interface *interface,
+			   const struct usb_device_id *id);
+static void streamzap_disconnect(struct usb_interface *interface);
+static void usb_streamzap_irq(struct urb *urb);
+static int streamzap_use_inc(void *data);
+static void streamzap_use_dec(void *data);
+static long streamzap_ioctl(struct file *filep, unsigned int cmd,
+			    unsigned long arg);
+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message);
+static int streamzap_resume(struct usb_interface *intf);
+
+/* usb specific object needed to register this driver with the usb subsystem */
+
+static struct usb_driver streamzap_driver = {
+	.name =		DRIVER_NAME,
+	.probe =	streamzap_probe,
+	.disconnect =	streamzap_disconnect,
+	.suspend =	streamzap_suspend,
+	.resume =	streamzap_resume,
+	.id_table =	streamzap_table,
+};
+
+static void stop_timer(struct usb_streamzap *sz)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sz->timer_lock, flags);
+	if (sz->timer_running) {
+		sz->timer_running = 0;
+		spin_unlock_irqrestore(&sz->timer_lock, flags);
+		del_timer_sync(&sz->delay_timer);
+	} else {
+		spin_unlock_irqrestore(&sz->timer_lock, flags);
+	}
+}
+
+static void flush_timeout(unsigned long arg)
+{
+	struct usb_streamzap *sz = (struct usb_streamzap *) arg;
+
+	/* finally start accepting data */
+	sz->flush = 0;
+}
+static void delay_timeout(unsigned long arg)
+{
+	unsigned long flags;
+	/* deliver data every 10 ms */
+	static unsigned long timer_inc =
+		(10000/(1000000/HZ)) == 0 ? 1 : (10000/(1000000/HZ));
+	struct usb_streamzap *sz = (struct usb_streamzap *) arg;
+	int data;
+
+	spin_lock_irqsave(&sz->timer_lock, flags);
+
+	if (!lirc_buffer_empty(sz->delay_buf) &&
+	    !lirc_buffer_full(sz->driver->rbuf)) {
+		lirc_buffer_read(sz->delay_buf, (unsigned char *) &data);
+		lirc_buffer_write(sz->driver->rbuf, (unsigned char *) &data);
+	}
+	if (!lirc_buffer_empty(sz->delay_buf)) {
+		while (lirc_buffer_available(sz->delay_buf) <
+		       STREAMZAP_BUF_LEN / 2 &&
+		       !lirc_buffer_full(sz->driver->rbuf)) {
+			lirc_buffer_read(sz->delay_buf,
+					   (unsigned char *) &data);
+			lirc_buffer_write(sz->driver->rbuf,
+					    (unsigned char *) &data);
+		}
+		if (sz->timer_running) {
+			sz->delay_timer.expires = jiffies + timer_inc;
+			add_timer(&sz->delay_timer);
+		}
+	} else {
+		sz->timer_running = 0;
+	}
+
+	if (!lirc_buffer_empty(sz->driver->rbuf))
+		wake_up(&sz->driver->rbuf->wait_poll);
+
+	spin_unlock_irqrestore(&sz->timer_lock, flags);
+}
+
+static void flush_delay_buffer(struct usb_streamzap *sz)
+{
+	int data;
+	int empty = 1;
+
+	while (!lirc_buffer_empty(sz->delay_buf)) {
+		empty = 0;
+		lirc_buffer_read(sz->delay_buf, (unsigned char *) &data);
+		if (!lirc_buffer_full(sz->driver->rbuf)) {
+			lirc_buffer_write(sz->driver->rbuf,
+					    (unsigned char *) &data);
+		} else {
+			dprintk("buffer overflow", sz->driver->minor);
+		}
+	}
+	if (!empty)
+		wake_up(&sz->driver->rbuf->wait_poll);
+}
+
+static void push(struct usb_streamzap *sz, unsigned char *data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sz->timer_lock, flags);
+	if (lirc_buffer_full(sz->delay_buf)) {
+		int read_data;
+
+		lirc_buffer_read(sz->delay_buf,
+				   (unsigned char *) &read_data);
+		if (!lirc_buffer_full(sz->driver->rbuf)) {
+			lirc_buffer_write(sz->driver->rbuf,
+					    (unsigned char *) &read_data);
+		} else {
+			dprintk("buffer overflow", sz->driver->minor);
+		}
+	}
+
+	lirc_buffer_write(sz->delay_buf, data);
+
+	if (!sz->timer_running) {
+		sz->delay_timer.expires = jiffies + HZ/10;
+		add_timer(&sz->delay_timer);
+		sz->timer_running = 1;
+	}
+
+	spin_unlock_irqrestore(&sz->timer_lock, flags);
+}
+
+static void push_full_pulse(struct usb_streamzap *sz,
+			    unsigned char value)
+{
+	int pulse;
+
+	if (sz->idle) {
+		long deltv;
+		int tmp;
+
+		sz->signal_last = sz->signal_start;
+		do_gettimeofday(&sz->signal_start);
+
+		deltv = sz->signal_start.tv_sec-sz->signal_last.tv_sec;
+		if (deltv > 15) {
+			/* really long time */
+			tmp = LIRC_SPACE(LIRC_VALUE_MASK);
+		} else {
+			tmp = (int) (deltv*1000000+
+					sz->signal_start.tv_usec -
+					sz->signal_last.tv_usec);
+			tmp -= sz->sum;
+			tmp = LIRC_SPACE(tmp);
+		}
+		dprintk("ls %u", sz->driver->minor, tmp);
+		push(sz, (char *)&tmp);
+
+		sz->idle = 0;
+		sz->sum = 0;
+	}
+
+	pulse = ((int) value) * STREAMZAP_RESOLUTION;
+	pulse += STREAMZAP_RESOLUTION / 2;
+	sz->sum += pulse;
+	pulse = LIRC_PULSE(pulse);
+
+	dprintk("p %u", sz->driver->minor, pulse & PULSE_MASK);
+	push(sz, (char *)&pulse);
+}
+
+static void push_half_pulse(struct usb_streamzap *sz,
+			    unsigned char value)
+{
+	push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK)>>4);
+}
+
+static void push_full_space(struct usb_streamzap *sz,
+			    unsigned char value)
+{
+	int space;
+
+	space = ((int) value)*STREAMZAP_RESOLUTION;
+	space += STREAMZAP_RESOLUTION/2;
+	sz->sum += space;
+	space = LIRC_SPACE(space);
+	dprintk("s %u", sz->driver->minor, space);
+	push(sz, (char *)&space);
+}
+
+static void push_half_space(struct usb_streamzap *sz,
+			    unsigned char value)
+{
+	push_full_space(sz, value & STREAMZAP_SPACE_MASK);
+}
+
+/**
+ * usb_streamzap_irq - IRQ handler
+ *
+ * This procedure is invoked on reception of data from
+ * the usb remote.
+ */
+static void usb_streamzap_irq(struct urb *urb)
+{
+	struct usb_streamzap *sz;
+	int		len;
+	unsigned int	i = 0;
+
+	if (!urb)
+		return;
+
+	sz = urb->context;
+	len = urb->actual_length;
+
+	switch (urb->status) {
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/*
+		 * this urb is terminated, clean up.
+		 * sz might already be invalid at this point
+		 */
+		dprintk("urb status: %d", -1, urb->status);
+		return;
+	default:
+		break;
+	}
+
+	dprintk("received %d", sz->driver->minor, urb->actual_length);
+	if (!sz->flush) {
+		for (i = 0; i < urb->actual_length; i++) {
+			dprintk("%d: %x", sz->driver->minor,
+				i, (unsigned char) sz->buf_in[i]);
+			switch (sz->decoder_state) {
+			case PulseSpace:
+				if ((sz->buf_in[i]&STREAMZAP_PULSE_MASK) ==
+				    STREAMZAP_PULSE_MASK) {
+					sz->decoder_state = FullPulse;
+					continue;
+				} else if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK)
+					   == STREAMZAP_SPACE_MASK) {
+					push_half_pulse(sz, sz->buf_in[i]);
+					sz->decoder_state = FullSpace;
+					continue;
+				} else {
+					push_half_pulse(sz, sz->buf_in[i]);
+					push_half_space(sz, sz->buf_in[i]);
+				}
+				break;
+			case FullPulse:
+				push_full_pulse(sz, sz->buf_in[i]);
+				sz->decoder_state = IgnorePulse;
+				break;
+			case FullSpace:
+				if (sz->buf_in[i] == STREAMZAP_TIMEOUT) {
+					sz->idle = 1;
+					stop_timer(sz);
+					if (sz->timeout_enabled) {
+						int timeout =
+							LIRC_TIMEOUT
+							(STREAMZAP_TIMEOUT *
+							STREAMZAP_RESOLUTION);
+						push(sz, (char *)&timeout);
+					}
+					flush_delay_buffer(sz);
+				} else
+					push_full_space(sz, sz->buf_in[i]);
+				sz->decoder_state = PulseSpace;
+				break;
+			case IgnorePulse:
+				if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) ==
+				    STREAMZAP_SPACE_MASK) {
+					sz->decoder_state = FullSpace;
+					continue;
+				}
+				push_half_space(sz, sz->buf_in[i]);
+				sz->decoder_state = PulseSpace;
+				break;
+			}
+		}
+	}
+
+	usb_submit_urb(urb, GFP_ATOMIC);
+
+	return;
+}
+
+static const struct file_operations streamzap_fops = {
+	.owner		= THIS_MODULE,
+	.unlocked_ioctl	= streamzap_ioctl,
+	.read		= lirc_dev_fop_read,
+	.write		= lirc_dev_fop_write,
+	.poll		= lirc_dev_fop_poll,
+	.open		= lirc_dev_fop_open,
+	.release	= lirc_dev_fop_close,
+};
+
+
+/**
+ *	streamzap_probe
+ *
+ *	Called by usb-core to associated with a candidate device
+ *	On any failure the return value is the ERROR
+ *	On success return 0
+ */
+static int streamzap_probe(struct usb_interface *interface,
+			   const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct usb_host_interface *iface_host;
+	struct usb_streamzap *sz;
+	struct lirc_driver *driver;
+	struct lirc_buffer *lirc_buf;
+	struct lirc_buffer *delay_buf;
+	char buf[63], name[128] = "";
+	int retval = -ENOMEM;
+	int minor = 0;
+
+	/* Allocate space for device driver specific data */
+	sz = kzalloc(sizeof(struct usb_streamzap), GFP_KERNEL);
+	if (sz == NULL)
+		return -ENOMEM;
+
+	sz->udev = udev;
+	sz->interface = interface;
+
+	/* Check to ensure endpoint information matches requirements */
+	iface_host = interface->cur_altsetting;
+
+	if (iface_host->desc.bNumEndpoints != 1) {
+		err("%s: Unexpected desc.bNumEndpoints (%d)", __func__,
+		    iface_host->desc.bNumEndpoints);
+		retval = -ENODEV;
+		goto free_sz;
+	}
+
+	sz->endpoint = &(iface_host->endpoint[0].desc);
+	if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+	    != USB_DIR_IN) {
+		err("%s: endpoint doesn't match input device 02%02x",
+		    __func__, sz->endpoint->bEndpointAddress);
+		retval = -ENODEV;
+		goto free_sz;
+	}
+
+	if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+	    != USB_ENDPOINT_XFER_INT) {
+		err("%s: endpoint attributes don't match xfer 02%02x",
+		    __func__, sz->endpoint->bmAttributes);
+		retval = -ENODEV;
+		goto free_sz;
+	}
+
+	if (sz->endpoint->wMaxPacketSize == 0) {
+		err("%s: endpoint message size==0? ", __func__);
+		retval = -ENODEV;
+		goto free_sz;
+	}
+
+	/* Allocate the USB buffer and IRQ URB */
+
+	sz->buf_in_len = sz->endpoint->wMaxPacketSize;
+	sz->buf_in = usb_alloc_coherent(sz->udev, sz->buf_in_len,
+				      GFP_ATOMIC, &sz->dma_in);
+	if (sz->buf_in == NULL)
+		goto free_sz;
+
+	sz->urb_in = usb_alloc_urb(0, GFP_KERNEL);
+	if (sz->urb_in == NULL)
+		goto free_sz;
+
+	/* Connect this device to the LIRC sub-system */
+	driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+	if (!driver)
+		goto free_sz;
+
+	lirc_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+	if (!lirc_buf)
+		goto free_driver;
+	if (lirc_buffer_init(lirc_buf, sizeof(int), STREAMZAP_BUF_LEN))
+		goto kfree_lirc_buf;
+
+	delay_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+	if (!delay_buf)
+		goto free_lirc_buf;
+	if (lirc_buffer_init(delay_buf, sizeof(int), STREAMZAP_BUF_LEN))
+		goto kfree_delay_buf;
+
+	sz->driver = driver;
+	strcpy(sz->driver->name, DRIVER_NAME);
+	sz->driver->minor = -1;
+	sz->driver->sample_rate = 0;
+	sz->driver->code_length = sizeof(int) * 8;
+	sz->driver->features = LIRC_CAN_REC_MODE2 |
+		LIRC_CAN_GET_REC_RESOLUTION |
+		LIRC_CAN_SET_REC_TIMEOUT;
+	sz->driver->data = sz;
+	sz->driver->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION;
+	sz->driver->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION;
+	sz->driver->rbuf = lirc_buf;
+	sz->delay_buf = delay_buf;
+	sz->driver->set_use_inc = &streamzap_use_inc;
+	sz->driver->set_use_dec = &streamzap_use_dec;
+	sz->driver->fops = &streamzap_fops;
+	sz->driver->dev = &interface->dev;
+	sz->driver->owner = THIS_MODULE;
+
+	sz->idle = 1;
+	sz->decoder_state = PulseSpace;
+	init_timer(&sz->delay_timer);
+	sz->delay_timer.function = delay_timeout;
+	sz->delay_timer.data = (unsigned long) sz;
+	sz->timer_running = 0;
+	spin_lock_init(&sz->timer_lock);
+
+	init_timer(&sz->flush_timer);
+	sz->flush_timer.function = flush_timeout;
+	sz->flush_timer.data = (unsigned long) sz;
+	/* Complete final initialisations */
+
+	usb_fill_int_urb(sz->urb_in, udev,
+		usb_rcvintpipe(udev, sz->endpoint->bEndpointAddress),
+		sz->buf_in, sz->buf_in_len, usb_streamzap_irq, sz,
+		sz->endpoint->bInterval);
+	sz->urb_in->transfer_dma = sz->dma_in;
+	sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	if (udev->descriptor.iManufacturer
+	    && usb_string(udev, udev->descriptor.iManufacturer,
+			  buf, sizeof(buf)) > 0)
+		strlcpy(name, buf, sizeof(name));
+
+	if (udev->descriptor.iProduct
+	    && usb_string(udev, udev->descriptor.iProduct,
+			  buf, sizeof(buf)) > 0)
+		snprintf(name + strlen(name), sizeof(name) - strlen(name),
+			 " %s", buf);
+
+	minor = lirc_register_driver(driver);
+
+	if (minor < 0)
+		goto free_delay_buf;
+
+	sz->driver->minor = minor;
+
+	usb_set_intfdata(interface, sz);
+
+	printk(KERN_INFO DRIVER_NAME "[%d]: %s on usb%d:%d attached\n",
+	       sz->driver->minor, name,
+	       udev->bus->busnum, sz->udev->devnum);
+
+	return 0;
+
+free_delay_buf:
+	lirc_buffer_free(sz->delay_buf);
+kfree_delay_buf:
+	kfree(delay_buf);
+free_lirc_buf:
+	lirc_buffer_free(sz->driver->rbuf);
+kfree_lirc_buf:
+	kfree(lirc_buf);
+free_driver:
+	kfree(driver);
+free_sz:
+	if (retval == -ENOMEM)
+		err("Out of memory");
+
+	if (sz) {
+		usb_free_urb(sz->urb_in);
+		usb_free_coherent(udev, sz->buf_in_len, sz->buf_in, sz->dma_in);
+		kfree(sz);
+	}
+
+	return retval;
+}
+
+static int streamzap_use_inc(void *data)
+{
+	struct usb_streamzap *sz = data;
+
+	if (!sz) {
+		dprintk("%s called with no context", -1, __func__);
+		return -EINVAL;
+	}
+	dprintk("set use inc", sz->driver->minor);
+
+	lirc_buffer_clear(sz->driver->rbuf);
+	lirc_buffer_clear(sz->delay_buf);
+
+	sz->flush_timer.expires = jiffies + HZ;
+	sz->flush = 1;
+	add_timer(&sz->flush_timer);
+
+	sz->urb_in->dev = sz->udev;
+	if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
+		dprintk("open result = -EIO error submitting urb",
+			sz->driver->minor);
+		return -EIO;
+	}
+	sz->in_use++;
+
+	return 0;
+}
+
+static void streamzap_use_dec(void *data)
+{
+	struct usb_streamzap *sz = data;
+
+	if (!sz) {
+		dprintk("%s called with no context", -1, __func__);
+		return;
+	}
+	dprintk("set use dec", sz->driver->minor);
+
+	if (sz->flush) {
+		sz->flush = 0;
+		del_timer_sync(&sz->flush_timer);
+	}
+
+	usb_kill_urb(sz->urb_in);
+
+	stop_timer(sz);
+
+	sz->in_use--;
+}
+
+static long streamzap_ioctl(struct file *filep, unsigned int cmd,
+			    unsigned long arg)
+{
+	int result = 0;
+	int val;
+	struct usb_streamzap *sz = lirc_get_pdata(filep);
+
+	switch (cmd) {
+	case LIRC_GET_REC_RESOLUTION:
+		result = put_user(STREAMZAP_RESOLUTION, (unsigned int *) arg);
+		break;
+	case LIRC_SET_REC_TIMEOUT:
+		result = get_user(val, (int *)arg);
+		if (result == 0) {
+			if (val == STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION)
+				sz->timeout_enabled = 1;
+			else if (val == 0)
+				sz->timeout_enabled = 0;
+			else
+				result = -EINVAL;
+		}
+		break;
+	default:
+		return lirc_dev_fop_ioctl(filep, cmd, arg);
+	}
+	return result;
+}
+
+/**
+ * streamzap_disconnect
+ *
+ * Called by the usb core when the device is removed from the system.
+ *
+ * This routine guarantees that the driver will not submit any more urbs
+ * by clearing dev->udev.  It is also supposed to terminate any currently
+ * active urbs.  Unfortunately, usb_bulk_msg(), used in streamzap_read(),
+ * does not provide any way to do this.
+ */
+static void streamzap_disconnect(struct usb_interface *interface)
+{
+	struct usb_streamzap *sz;
+	int errnum;
+	int minor;
+
+	sz = usb_get_intfdata(interface);
+
+	/* unregister from the LIRC sub-system */
+
+	errnum = lirc_unregister_driver(sz->driver->minor);
+	if (errnum != 0)
+		dprintk("error in lirc_unregister: (returned %d)",
+			sz->driver->minor, errnum);
+
+	lirc_buffer_free(sz->delay_buf);
+	lirc_buffer_free(sz->driver->rbuf);
+
+	/* unregister from the USB sub-system */
+
+	usb_free_urb(sz->urb_in);
+
+	usb_free_coherent(sz->udev, sz->buf_in_len, sz->buf_in, sz->dma_in);
+
+	minor = sz->driver->minor;
+	kfree(sz->driver->rbuf);
+	kfree(sz->driver);
+	kfree(sz->delay_buf);
+	kfree(sz);
+
+	printk(KERN_INFO DRIVER_NAME "[%d]: disconnected\n", minor);
+}
+
+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct usb_streamzap *sz = usb_get_intfdata(intf);
+
+	printk(KERN_INFO DRIVER_NAME "[%d]: suspend\n", sz->driver->minor);
+	if (sz->in_use) {
+		if (sz->flush) {
+			sz->flush = 0;
+			del_timer_sync(&sz->flush_timer);
+		}
+
+		stop_timer(sz);
+
+		usb_kill_urb(sz->urb_in);
+	}
+	return 0;
+}
+
+static int streamzap_resume(struct usb_interface *intf)
+{
+	struct usb_streamzap *sz = usb_get_intfdata(intf);
+
+	lirc_buffer_clear(sz->driver->rbuf);
+	lirc_buffer_clear(sz->delay_buf);
+
+	if (sz->in_use) {
+		sz->flush_timer.expires = jiffies + HZ;
+		sz->flush = 1;
+		add_timer(&sz->flush_timer);
+
+		sz->urb_in->dev = sz->udev;
+		if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
+			dprintk("open result = -EIO error submitting urb",
+				sz->driver->minor);
+			return -EIO;
+		}
+	}
+	return 0;
+}
+
+/**
+ *	usb_streamzap_init
+ */
+static int __init usb_streamzap_init(void)
+{
+	int result;
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&streamzap_driver);
+
+	if (result) {
+		err("usb_register failed. Error number %d",
+		    result);
+		return result;
+	}
+
+	printk(KERN_INFO DRIVER_NAME " " DRIVER_VERSION " registered\n");
+	return 0;
+}
+
+/**
+ *	usb_streamzap_exit
+ */
+static void __exit usb_streamzap_exit(void)
+{
+	usb_deregister(&streamzap_driver);
+}
+
+
+module_init(usb_streamzap_init);
+module_exit(usb_streamzap_exit);
+
+MODULE_AUTHOR("Christoph Bartelmus, Greg Wickham, Adrian Dewhurst");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/lirc/lirc_ttusbir.c b/drivers/staging/lirc/lirc_ttusbir.c
new file mode 100644
index 0000000..e345ab9
--- /dev/null
+++ b/drivers/staging/lirc/lirc_ttusbir.c
@@ -0,0 +1,396 @@
+/*
+ * lirc_ttusbir.c
+ *
+ * lirc_ttusbir - LIRC device driver for the TechnoTrend USB IR Receiver
+ *
+ * Copyright (C) 2007 Stefan Macher <st_maker-lirc@yahoo.de>
+ *
+ * This LIRC driver provides access to the TechnoTrend USB IR Receiver.
+ * The receiver delivers the IR signal as raw sampled true/false data in
+ * isochronous USB packets each of size 128 byte.
+ * Currently the driver reduces the sampling rate by factor of 8 as this
+ * is still more than enough to decode RC-5 - others should be analyzed.
+ * But the driver does not rely on RC-5 it should be able to decode every
+ * IR signal that is not too fast.
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC");
+MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)");
+MODULE_LICENSE("GPL");
+
+/* #define DEBUG */
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+#define DPRINTK(_x_, a...)
+#endif
+
+/* function declarations */
+static int probe(struct usb_interface *intf, const struct usb_device_id *id);
+static void disconnect(struct usb_interface *intf);
+static void urb_complete(struct urb *urb);
+static int set_use_inc(void *data);
+static void set_use_dec(void *data);
+
+static int num_urbs = 2;
+module_param(num_urbs, int, S_IRUGO);
+MODULE_PARM_DESC(num_urbs,
+		 "Number of URBs in queue. Try to increase to 4 in case "
+		 "of problems (default: 2; minimum: 2)");
+
+/* table of devices that work with this driver */
+static struct usb_device_id device_id_table[] = {
+	/* TechnoTrend USB IR Receiver */
+	{ USB_DEVICE(0x0B48, 0x2003) },
+	/* Terminating entry */
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, device_id_table);
+
+/* USB driver definition */
+static struct usb_driver usb_driver = {
+	.name = "TTUSBIR",
+	.id_table = &(device_id_table[0]),
+	.probe = probe,
+	.disconnect = disconnect,
+};
+
+/* USB device definition */
+struct ttusbir_device {
+	struct usb_driver *usb_driver;
+	struct usb_device *udev;
+	struct usb_interface *interf;
+	struct usb_class_driver class_driver;
+	unsigned int ifnum; /* Interface number to use */
+	unsigned int alt_setting; /* alternate setting to use */
+	unsigned int endpoint; /* Endpoint to use */
+	struct urb **urb; /* num_urb URB pointers*/
+	char **buffer; /* 128 byte buffer for each URB */
+	struct lirc_buffer rbuf; /* Buffer towards LIRC */
+	struct lirc_driver driver;
+	int minor;
+	int last_pulse; /* remembers if last received byte was pulse or space */
+	int last_num; /* remembers how many last bytes appeared */
+	int opened;
+};
+
+/*** LIRC specific functions ***/
+static int set_use_inc(void *data)
+{
+	int i, retval;
+	struct ttusbir_device *ttusbir = data;
+
+	DPRINTK("Sending first URBs\n");
+	/* @TODO Do I need to check if I am already opened */
+	ttusbir->opened = 1;
+
+	for (i = 0; i < num_urbs; i++) {
+		retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL);
+		if (retval) {
+			err("%s: usb_submit_urb failed on urb %d",
+			    __func__, i);
+			return retval;
+		}
+	}
+	return 0;
+}
+
+static void set_use_dec(void *data)
+{
+	struct ttusbir_device *ttusbir = data;
+
+	DPRINTK("Device closed\n");
+
+	ttusbir->opened = 0;
+}
+
+/*** USB specific functions ***/
+
+/*
+ * This mapping table is used to do a very simple filtering of the
+ * input signal.
+ * For a value with at least 4 bits set it returns 0xFF otherwise
+ * 0x00.  For faster IR signals this can not be used. But for RC-5 we
+ * still have about 14 samples per pulse/space, i.e. we sample with 14
+ * times higher frequency than the signal frequency
+ */
+const unsigned char map_table[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+	0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+	0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+	0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+	0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+static void urb_complete(struct urb *urb)
+{
+	struct ttusbir_device *ttusbir;
+	unsigned char *buf;
+	int i;
+	int l;
+
+	ttusbir = urb->context;
+
+	if (!ttusbir->opened)
+		return;
+
+	buf = (unsigned char *)urb->transfer_buffer;
+
+	for (i = 0; i < 128; i++) {
+		/* Here we do the filtering and some kind of down sampling */
+		buf[i] = ~map_table[buf[i]];
+		if (ttusbir->last_pulse == buf[i]) {
+			if (ttusbir->last_num < PULSE_MASK/63)
+				ttusbir->last_num++;
+		/*
+		 * else we are in a idle period and do not need to
+		 * increment any longer
+		 */
+		} else {
+			l = ttusbir->last_num * 62; /* about 62 = us/byte */
+			if (ttusbir->last_pulse) /* pulse or space? */
+				l |= PULSE_BIT;
+			if (!lirc_buffer_full(&ttusbir->rbuf)) {
+				lirc_buffer_write(&ttusbir->rbuf, (void *)&l);
+				wake_up_interruptible(&ttusbir->rbuf.wait_poll);
+			}
+			ttusbir->last_num = 0;
+			ttusbir->last_pulse = buf[i];
+		}
+	}
+	usb_submit_urb(urb, GFP_ATOMIC); /* keep data rolling :-) */
+}
+
+/*
+ * Called whenever the USB subsystem thinks we could be the right driver
+ * to handle this device
+ */
+static int probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	int alt_set, endp;
+	int found = 0;
+	int i, j;
+	int struct_size;
+	struct usb_host_interface *host_interf;
+	struct usb_interface_descriptor *interf_desc;
+	struct usb_host_endpoint *host_endpoint;
+	struct ttusbir_device *ttusbir;
+
+	DPRINTK("Module ttusbir probe\n");
+
+	/* To reduce memory fragmentation we use only one allocation */
+	struct_size =  sizeof(struct ttusbir_device) +
+		(sizeof(struct urb *) * num_urbs) +
+		(sizeof(char *) * num_urbs) +
+		(num_urbs * 128);
+	ttusbir = kzalloc(struct_size, GFP_KERNEL);
+	if (!ttusbir)
+		return -ENOMEM;
+
+	ttusbir->urb = (struct urb **)((char *)ttusbir +
+				      sizeof(struct ttusbir_device));
+	ttusbir->buffer = (char **)((char *)ttusbir->urb +
+				   (sizeof(struct urb *) * num_urbs));
+	for (i = 0; i < num_urbs; i++)
+		ttusbir->buffer[i] = (char *)ttusbir->buffer +
+			(sizeof(char *)*num_urbs) + (i * 128);
+
+	ttusbir->usb_driver = &usb_driver;
+	ttusbir->alt_setting = -1;
+	/* @TODO check if error can be returned */
+	ttusbir->udev = usb_get_dev(interface_to_usbdev(intf));
+	ttusbir->interf = intf;
+	ttusbir->last_pulse = 0x00;
+	ttusbir->last_num = 0;
+
+	/*
+	 * Now look for interface setting we can handle
+	 * We are searching for the alt setting where end point
+	 * 0x82 has max packet size 16
+	 */
+	for (alt_set = 0; alt_set < intf->num_altsetting && !found; alt_set++) {
+		host_interf = &intf->altsetting[alt_set];
+		interf_desc = &host_interf->desc;
+		for (endp = 0; endp < interf_desc->bNumEndpoints; endp++) {
+			host_endpoint = &host_interf->endpoint[endp];
+			if ((host_endpoint->desc.bEndpointAddress == 0x82) &&
+			    (host_endpoint->desc.wMaxPacketSize == 0x10)) {
+				ttusbir->alt_setting = alt_set;
+				ttusbir->endpoint = endp;
+				found = 1;
+				break;
+			}
+		}
+	}
+	if (ttusbir->alt_setting != -1)
+		DPRINTK("alt setting: %d\n", ttusbir->alt_setting);
+	else {
+		err("Could not find alternate setting\n");
+		kfree(ttusbir);
+		return -EINVAL;
+	}
+
+	/* OK lets setup this interface setting */
+	usb_set_interface(ttusbir->udev, 0, ttusbir->alt_setting);
+
+	/* Store device info in interface structure */
+	usb_set_intfdata(intf, ttusbir);
+
+	/* Register as a LIRC driver */
+	if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) {
+		err("Could not get memory for LIRC data buffer\n");
+		usb_set_intfdata(intf, NULL);
+		kfree(ttusbir);
+		return -ENOMEM;
+	}
+	strcpy(ttusbir->driver.name, "TTUSBIR");
+	ttusbir->driver.minor = -1;
+	ttusbir->driver.code_length = 1;
+	ttusbir->driver.sample_rate = 0;
+	ttusbir->driver.data = ttusbir;
+	ttusbir->driver.add_to_buf = NULL;
+	ttusbir->driver.rbuf = &ttusbir->rbuf;
+	ttusbir->driver.set_use_inc = set_use_inc;
+	ttusbir->driver.set_use_dec = set_use_dec;
+	ttusbir->driver.dev = &intf->dev;
+	ttusbir->driver.owner = THIS_MODULE;
+	ttusbir->driver.features = LIRC_CAN_REC_MODE2;
+	ttusbir->minor = lirc_register_driver(&ttusbir->driver);
+	if (ttusbir->minor < 0) {
+		err("Error registering as LIRC driver\n");
+		usb_set_intfdata(intf, NULL);
+		lirc_buffer_free(&ttusbir->rbuf);
+		kfree(ttusbir);
+		return -EIO;
+	}
+
+	/* Allocate and setup the URB that we will use to talk to the device */
+	for (i = 0; i < num_urbs; i++) {
+		ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL);
+		if (!ttusbir->urb[i]) {
+			err("Could not allocate memory for the URB\n");
+			for (j = i - 1; j >= 0; j--)
+				kfree(ttusbir->urb[j]);
+			lirc_buffer_free(&ttusbir->rbuf);
+			lirc_unregister_driver(ttusbir->minor);
+			kfree(ttusbir);
+			usb_set_intfdata(intf, NULL);
+			return -ENOMEM;
+		}
+		ttusbir->urb[i]->dev = ttusbir->udev;
+		ttusbir->urb[i]->context = ttusbir;
+		ttusbir->urb[i]->pipe = usb_rcvisocpipe(ttusbir->udev,
+							ttusbir->endpoint);
+		ttusbir->urb[i]->interval = 1;
+		ttusbir->urb[i]->transfer_flags = URB_ISO_ASAP;
+		ttusbir->urb[i]->transfer_buffer = &ttusbir->buffer[i][0];
+		ttusbir->urb[i]->complete = urb_complete;
+		ttusbir->urb[i]->number_of_packets = 8;
+		ttusbir->urb[i]->transfer_buffer_length = 128;
+		for (j = 0; j < 8; j++) {
+			ttusbir->urb[i]->iso_frame_desc[j].offset = j*16;
+			ttusbir->urb[i]->iso_frame_desc[j].length = 16;
+		}
+	}
+	return 0;
+}
+
+/**
+ * Called when the driver is unloaded or the device is unplugged
+ */
+static void disconnect(struct usb_interface *intf)
+{
+	int i;
+	struct ttusbir_device *ttusbir;
+
+	DPRINTK("Module ttusbir disconnect\n");
+
+	ttusbir = (struct ttusbir_device *) usb_get_intfdata(intf);
+	usb_set_intfdata(intf, NULL);
+	lirc_unregister_driver(ttusbir->minor);
+	DPRINTK("unregistered\n");
+
+	for (i = 0; i < num_urbs; i++) {
+		usb_kill_urb(ttusbir->urb[i]);
+		usb_free_urb(ttusbir->urb[i]);
+	}
+	DPRINTK("URBs killed\n");
+	lirc_buffer_free(&ttusbir->rbuf);
+	kfree(ttusbir);
+}
+
+static int ttusbir_init_module(void)
+{
+	int result;
+
+	DPRINTK(KERN_DEBUG "Module ttusbir init\n");
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&usb_driver);
+	if (result)
+		err("usb_register failed. Error number %d", result);
+	return result;
+}
+
+static void ttusbir_exit_module(void)
+{
+	printk(KERN_DEBUG "Module ttusbir exit\n");
+	usb_deregister(&usb_driver);
+}
+
+module_init(ttusbir_init_module);
+module_exit(ttusbir_exit_module);
diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c
new file mode 100644
index 0000000..100caab1
--- /dev/null
+++ b/drivers/staging/lirc/lirc_zilog.c
@@ -0,0 +1,1387 @@
+/*
+ * i2c IR lirc driver for devices with zilog IR processors
+ *
+ * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ * modified for PixelView (BT878P+W/FM) by
+ *      Michal Kochanowicz <mkochano@pld.org.pl>
+ *      Christoph Bartelmus <lirc@bartelmus.de>
+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
+ *      Ulrich Mueller <ulrich.mueller42@web.de>
+ * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by
+ *      Stefan Jahn <stefan@lkcc.org>
+ * modified for inclusion into kernel sources by
+ *      Jerome Brock <jbrock@users.sourceforge.net>
+ * modified for Leadtek Winfast PVR2000 by
+ *      Thomas Reitmayr (treitmayr@yahoo.com)
+ * modified for Hauppauge PVR-150 IR TX device by
+ *      Mark Weaver <mark@npsl.co.uk>
+ * changed name from lirc_pvr150 to lirc_zilog, works on more than pvr-150
+ *	Jarod Wilson <jarod@redhat.com>
+ *
+ * parts are cut&pasted from the lirc_i2c.c driver
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+
+#include <media/lirc_dev.h>
+#include <media/lirc.h>
+
+struct IR {
+	struct lirc_driver l;
+
+	/* Device info */
+	struct mutex ir_lock;
+	int open;
+
+	/* RX device */
+	struct i2c_client c_rx;
+	int have_rx;
+
+	/* RX device buffer & lock */
+	struct lirc_buffer buf;
+	struct mutex buf_lock;
+
+	/* RX polling thread data */
+	struct completion *t_notify;
+	struct completion *t_notify2;
+	int shutdown;
+	struct task_struct *task;
+
+	/* RX read data */
+	unsigned char b[3];
+
+	/* TX device */
+	struct i2c_client c_tx;
+	int need_boot;
+	int have_tx;
+};
+
+/* Minor -> data mapping */
+static struct IR *ir_devices[MAX_IRCTL_DEVICES];
+
+/* Block size for IR transmitter */
+#define TX_BLOCK_SIZE	99
+
+/* Hauppauge IR transmitter data */
+struct tx_data_struct {
+	/* Boot block */
+	unsigned char *boot_data;
+
+	/* Start of binary data block */
+	unsigned char *datap;
+
+	/* End of binary data block */
+	unsigned char *endp;
+
+	/* Number of installed codesets */
+	unsigned int num_code_sets;
+
+	/* Pointers to codesets */
+	unsigned char **code_sets;
+
+	/* Global fixed data template */
+	int fixed[TX_BLOCK_SIZE];
+};
+
+static struct tx_data_struct *tx_data;
+static struct mutex tx_data_lock;
+
+#define zilog_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, \
+					## args)
+#define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
+
+#define ZILOG_HAUPPAUGE_IR_RX_NAME "Zilog/Hauppauge IR RX"
+#define ZILOG_HAUPPAUGE_IR_TX_NAME "Zilog/Hauppauge IR TX"
+
+/* module parameters */
+static int debug;	/* debug output */
+static int disable_rx;	/* disable RX device */
+static int disable_tx;	/* disable TX device */
+static int minor = -1;	/* minor number */
+
+#define dprintk(fmt, args...)						\
+	do {								\
+		if (debug)						\
+			printk(KERN_DEBUG KBUILD_MODNAME ": " fmt,	\
+				 ## args);				\
+	} while (0)
+
+static int add_to_buf(struct IR *ir)
+{
+	__u16 code;
+	unsigned char codes[2];
+	unsigned char keybuf[6];
+	int got_data = 0;
+	int ret;
+	int failures = 0;
+	unsigned char sendbuf[1] = { 0 };
+
+	if (lirc_buffer_full(&ir->buf)) {
+		dprintk("buffer overflow\n");
+		return -EOVERFLOW;
+	}
+
+	/*
+	 * service the device as long as it is returning
+	 * data and we have space
+	 */
+	do {
+		/*
+		 * Lock i2c bus for the duration.  RX/TX chips interfere so
+		 * this is worth it
+		 */
+		mutex_lock(&ir->ir_lock);
+
+		/*
+		 * Send random "poll command" (?)  Windows driver does this
+		 * and it is a good point to detect chip failure.
+		 */
+		ret = i2c_master_send(&ir->c_rx, sendbuf, 1);
+		if (ret != 1) {
+			zilog_error("i2c_master_send failed with %d\n",	ret);
+			if (failures >= 3) {
+				mutex_unlock(&ir->ir_lock);
+				zilog_error("unable to read from the IR chip "
+					    "after 3 resets, giving up\n");
+				return ret;
+			}
+
+			/* Looks like the chip crashed, reset it */
+			zilog_error("polling the IR receiver chip failed, "
+				    "trying reset\n");
+
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout((100 * HZ + 999) / 1000);
+			ir->need_boot = 1;
+
+			++failures;
+			mutex_unlock(&ir->ir_lock);
+			continue;
+		}
+
+		ret = i2c_master_recv(&ir->c_rx, keybuf, sizeof(keybuf));
+		mutex_unlock(&ir->ir_lock);
+		if (ret != sizeof(keybuf)) {
+			zilog_error("i2c_master_recv failed with %d -- "
+				    "keeping last read buffer\n", ret);
+		} else {
+			ir->b[0] = keybuf[3];
+			ir->b[1] = keybuf[4];
+			ir->b[2] = keybuf[5];
+			dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]);
+		}
+
+		/* key pressed ? */
+#ifdef I2C_HW_B_HDPVR
+		if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR) {
+			if (got_data && (keybuf[0] == 0x80))
+				return 0;
+			else if (got_data && (keybuf[0] == 0x00))
+				return -ENODATA;
+		} else if ((ir->b[0] & 0x80) == 0)
+#else
+		if ((ir->b[0] & 0x80) == 0)
+#endif
+			return got_data ? 0 : -ENODATA;
+
+		/* look what we have */
+		code = (((__u16)ir->b[0] & 0x7f) << 6) | (ir->b[1] >> 2);
+
+		codes[0] = (code >> 8) & 0xff;
+		codes[1] = code & 0xff;
+
+		/* return it */
+		lirc_buffer_write(&ir->buf, codes);
+		++got_data;
+	} while (!lirc_buffer_full(&ir->buf));
+
+	return 0;
+}
+
+/*
+ * Main function of the polling thread -- from lirc_dev.
+ * We don't fit the LIRC model at all anymore.  This is horrible, but
+ * basically we have a single RX/TX device with a nasty failure mode
+ * that needs to be accounted for across the pair.  lirc lets us provide
+ * fops, but prevents us from using the internal polling, etc. if we do
+ * so.  Hence the replication.  Might be neater to extend the LIRC model
+ * to account for this but I'd think it's a very special case of seriously
+ * messed up hardware.
+ */
+static int lirc_thread(void *arg)
+{
+	struct IR *ir = arg;
+
+	if (ir->t_notify != NULL)
+		complete(ir->t_notify);
+
+	dprintk("poll thread started\n");
+
+	do {
+		if (ir->open) {
+			set_current_state(TASK_INTERRUPTIBLE);
+
+			/*
+			 * This is ~113*2 + 24 + jitter (2*repeat gap +
+			 * code length).  We use this interval as the chip
+			 * resets every time you poll it (bad!).  This is
+			 * therefore just sufficient to catch all of the
+			 * button presses.  It makes the remote much more
+			 * responsive.  You can see the difference by
+			 * running irw and holding down a button.  With
+			 * 100ms, the old polling interval, you'll notice
+			 * breaks in the repeat sequence corresponding to
+			 * lost keypresses.
+			 */
+			schedule_timeout((260 * HZ) / 1000);
+			if (ir->shutdown)
+				break;
+			if (!add_to_buf(ir))
+				wake_up_interruptible(&ir->buf.wait_poll);
+		} else {
+			/* if device not opened so we can sleep half a second */
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(HZ/2);
+		}
+	} while (!ir->shutdown);
+
+	if (ir->t_notify2 != NULL)
+		wait_for_completion(ir->t_notify2);
+
+	ir->task = NULL;
+	if (ir->t_notify != NULL)
+		complete(ir->t_notify);
+
+	dprintk("poll thread ended\n");
+	return 0;
+}
+
+static int set_use_inc(void *data)
+{
+	struct IR *ir = data;
+
+	if (ir->l.owner == NULL || try_module_get(ir->l.owner) == 0)
+		return -ENODEV;
+
+	/* lock bttv in memory while /dev/lirc is in use  */
+	/*
+	 * this is completely broken code. lirc_unregister_driver()
+	 * must be possible even when the device is open
+	 */
+	if (ir->c_rx.addr)
+		i2c_use_client(&ir->c_rx);
+	if (ir->c_tx.addr)
+		i2c_use_client(&ir->c_tx);
+
+	return 0;
+}
+
+static void set_use_dec(void *data)
+{
+	struct IR *ir = data;
+
+	if (ir->c_rx.addr)
+		i2c_release_client(&ir->c_rx);
+	if (ir->c_tx.addr)
+		i2c_release_client(&ir->c_tx);
+	if (ir->l.owner != NULL)
+		module_put(ir->l.owner);
+}
+
+/* safe read of a uint32 (always network byte order) */
+static int read_uint32(unsigned char **data,
+				     unsigned char *endp, unsigned int *val)
+{
+	if (*data + 4 > endp)
+		return 0;
+	*val = ((*data)[0] << 24) | ((*data)[1] << 16) |
+	       ((*data)[2] << 8) | (*data)[3];
+	*data += 4;
+	return 1;
+}
+
+/* safe read of a uint8 */
+static int read_uint8(unsigned char **data,
+				    unsigned char *endp, unsigned char *val)
+{
+	if (*data + 1 > endp)
+		return 0;
+	*val = *((*data)++);
+	return 1;
+}
+
+/* safe skipping of N bytes */
+static int skip(unsigned char **data,
+			      unsigned char *endp, unsigned int distance)
+{
+	if (*data + distance > endp)
+		return 0;
+	*data += distance;
+	return 1;
+}
+
+/* decompress key data into the given buffer */
+static int get_key_data(unsigned char *buf,
+			     unsigned int codeset, unsigned int key)
+{
+	unsigned char *data, *endp, *diffs, *key_block;
+	unsigned char keys, ndiffs, id;
+	unsigned int base, lim, pos, i;
+
+	/* Binary search for the codeset */
+	for (base = 0, lim = tx_data->num_code_sets; lim; lim >>= 1) {
+		pos = base + (lim >> 1);
+		data = tx_data->code_sets[pos];
+
+		if (!read_uint32(&data, tx_data->endp, &i))
+			goto corrupt;
+
+		if (i == codeset)
+			break;
+		else if (codeset > i) {
+			base = pos + 1;
+			--lim;
+		}
+	}
+	/* Not found? */
+	if (!lim)
+		return -EPROTO;
+
+	/* Set end of data block */
+	endp = pos < tx_data->num_code_sets - 1 ?
+		tx_data->code_sets[pos + 1] : tx_data->endp;
+
+	/* Read the block header */
+	if (!read_uint8(&data, endp, &keys) ||
+	    !read_uint8(&data, endp, &ndiffs) ||
+	    ndiffs > TX_BLOCK_SIZE || keys == 0)
+		goto corrupt;
+
+	/* Save diffs & skip */
+	diffs = data;
+	if (!skip(&data, endp, ndiffs))
+		goto corrupt;
+
+	/* Read the id of the first key */
+	if (!read_uint8(&data, endp, &id))
+		goto corrupt;
+
+	/* Unpack the first key's data */
+	for (i = 0; i < TX_BLOCK_SIZE; ++i) {
+		if (tx_data->fixed[i] == -1) {
+			if (!read_uint8(&data, endp, &buf[i]))
+				goto corrupt;
+		} else {
+			buf[i] = (unsigned char)tx_data->fixed[i];
+		}
+	}
+
+	/* Early out key found/not found */
+	if (key == id)
+		return 0;
+	if (keys == 1)
+		return -EPROTO;
+
+	/* Sanity check */
+	key_block = data;
+	if (!skip(&data, endp, (keys - 1) * (ndiffs + 1)))
+		goto corrupt;
+
+	/* Binary search for the key */
+	for (base = 0, lim = keys - 1; lim; lim >>= 1) {
+		/* Seek to block */
+		unsigned char *key_data;
+		pos = base + (lim >> 1);
+		key_data = key_block + (ndiffs + 1) * pos;
+
+		if (*key_data == key) {
+			/* skip key id */
+			++key_data;
+
+			/* found, so unpack the diffs */
+			for (i = 0; i < ndiffs; ++i) {
+				unsigned char val;
+				if (!read_uint8(&key_data, endp, &val) ||
+				    diffs[i] >= TX_BLOCK_SIZE)
+					goto corrupt;
+				buf[diffs[i]] = val;
+			}
+
+			return 0;
+		} else if (key > *key_data) {
+			base = pos + 1;
+			--lim;
+		}
+	}
+	/* Key not found */
+	return -EPROTO;
+
+corrupt:
+	zilog_error("firmware is corrupt\n");
+	return -EFAULT;
+}
+
+/* send a block of data to the IR TX device */
+static int send_data_block(struct IR *ir, unsigned char *data_block)
+{
+	int i, j, ret;
+	unsigned char buf[5];
+
+	for (i = 0; i < TX_BLOCK_SIZE;) {
+		int tosend = TX_BLOCK_SIZE - i;
+		if (tosend > 4)
+			tosend = 4;
+		buf[0] = (unsigned char)(i + 1);
+		for (j = 0; j < tosend; ++j)
+			buf[1 + j] = data_block[i + j];
+		dprintk("%02x %02x %02x %02x %02x",
+			buf[0], buf[1], buf[2], buf[3], buf[4]);
+		ret = i2c_master_send(&ir->c_tx, buf, tosend + 1);
+		if (ret != tosend + 1) {
+			zilog_error("i2c_master_send failed with %d\n", ret);
+			return ret < 0 ? ret : -EFAULT;
+		}
+		i += tosend;
+	}
+	return 0;
+}
+
+/* send boot data to the IR TX device */
+static int send_boot_data(struct IR *ir)
+{
+	int ret;
+	unsigned char buf[4];
+
+	/* send the boot block */
+	ret = send_data_block(ir, tx_data->boot_data);
+	if (ret != 0)
+		return ret;
+
+	/* kick it off? */
+	buf[0] = 0x00;
+	buf[1] = 0x20;
+	ret = i2c_master_send(&ir->c_tx, buf, 2);
+	if (ret != 2) {
+		zilog_error("i2c_master_send failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+	ret = i2c_master_send(&ir->c_tx, buf, 1);
+	if (ret != 1) {
+		zilog_error("i2c_master_send failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+
+	/* Here comes the firmware version... (hopefully) */
+	ret = i2c_master_recv(&ir->c_tx, buf, 4);
+	if (ret != 4) {
+		zilog_error("i2c_master_recv failed with %d\n", ret);
+		return 0;
+	}
+	if (buf[0] != 0x80) {
+		zilog_error("unexpected IR TX response: %02x\n", buf[0]);
+		return 0;
+	}
+	zilog_notify("Zilog/Hauppauge IR blaster firmware version "
+		     "%d.%d.%d loaded\n", buf[1], buf[2], buf[3]);
+
+	return 0;
+}
+
+/* unload "firmware", lock held */
+static void fw_unload_locked(void)
+{
+	if (tx_data) {
+		if (tx_data->code_sets)
+			vfree(tx_data->code_sets);
+
+		if (tx_data->datap)
+			vfree(tx_data->datap);
+
+		vfree(tx_data);
+		tx_data = NULL;
+		dprintk("successfully unloaded IR blaster firmware\n");
+	}
+}
+
+/* unload "firmware" for the IR TX device */
+static void fw_unload(void)
+{
+	mutex_lock(&tx_data_lock);
+	fw_unload_locked();
+	mutex_unlock(&tx_data_lock);
+}
+
+/* load "firmware" for the IR TX device */
+static int fw_load(struct IR *ir)
+{
+	int ret;
+	unsigned int i;
+	unsigned char *data, version, num_global_fixed;
+	const struct firmware *fw_entry;
+
+	/* Already loaded? */
+	mutex_lock(&tx_data_lock);
+	if (tx_data) {
+		ret = 0;
+		goto out;
+	}
+
+	/* Request codeset data file */
+	ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &ir->c_tx.dev);
+	if (ret != 0) {
+		zilog_error("firmware haup-ir-blaster.bin not available "
+			    "(%d)\n", ret);
+		ret = ret < 0 ? ret : -EFAULT;
+		goto out;
+	}
+	dprintk("firmware of size %zu loaded\n", fw_entry->size);
+
+	/* Parse the file */
+	tx_data = vmalloc(sizeof(*tx_data));
+	if (tx_data == NULL) {
+		zilog_error("out of memory\n");
+		release_firmware(fw_entry);
+		ret = -ENOMEM;
+		goto out;
+	}
+	tx_data->code_sets = NULL;
+
+	/* Copy the data so hotplug doesn't get confused and timeout */
+	tx_data->datap = vmalloc(fw_entry->size);
+	if (tx_data->datap == NULL) {
+		zilog_error("out of memory\n");
+		release_firmware(fw_entry);
+		vfree(tx_data);
+		ret = -ENOMEM;
+		goto out;
+	}
+	memcpy(tx_data->datap, fw_entry->data, fw_entry->size);
+	tx_data->endp = tx_data->datap + fw_entry->size;
+	release_firmware(fw_entry); fw_entry = NULL;
+
+	/* Check version */
+	data = tx_data->datap;
+	if (!read_uint8(&data, tx_data->endp, &version))
+		goto corrupt;
+	if (version != 1) {
+		zilog_error("unsupported code set file version (%u, expected"
+			    "1) -- please upgrade to a newer driver",
+			    version);
+		fw_unload_locked();
+		ret = -EFAULT;
+		goto out;
+	}
+
+	/* Save boot block for later */
+	tx_data->boot_data = data;
+	if (!skip(&data, tx_data->endp, TX_BLOCK_SIZE))
+		goto corrupt;
+
+	if (!read_uint32(&data, tx_data->endp,
+			      &tx_data->num_code_sets))
+		goto corrupt;
+
+	dprintk("%u IR blaster codesets loaded\n", tx_data->num_code_sets);
+
+	tx_data->code_sets = vmalloc(
+		tx_data->num_code_sets * sizeof(char *));
+	if (tx_data->code_sets == NULL) {
+		fw_unload_locked();
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	for (i = 0; i < TX_BLOCK_SIZE; ++i)
+		tx_data->fixed[i] = -1;
+
+	/* Read global fixed data template */
+	if (!read_uint8(&data, tx_data->endp, &num_global_fixed) ||
+	    num_global_fixed > TX_BLOCK_SIZE)
+		goto corrupt;
+	for (i = 0; i < num_global_fixed; ++i) {
+		unsigned char pos, val;
+		if (!read_uint8(&data, tx_data->endp, &pos) ||
+		    !read_uint8(&data, tx_data->endp, &val) ||
+		    pos >= TX_BLOCK_SIZE)
+			goto corrupt;
+		tx_data->fixed[pos] = (int)val;
+	}
+
+	/* Filch out the position of each code set */
+	for (i = 0; i < tx_data->num_code_sets; ++i) {
+		unsigned int id;
+		unsigned char keys;
+		unsigned char ndiffs;
+
+		/* Save the codeset position */
+		tx_data->code_sets[i] = data;
+
+		/* Read header */
+		if (!read_uint32(&data, tx_data->endp, &id) ||
+		    !read_uint8(&data, tx_data->endp, &keys) ||
+		    !read_uint8(&data, tx_data->endp, &ndiffs) ||
+		    ndiffs > TX_BLOCK_SIZE || keys == 0)
+			goto corrupt;
+
+		/* skip diff positions */
+		if (!skip(&data, tx_data->endp, ndiffs))
+			goto corrupt;
+
+		/*
+		 * After the diffs we have the first key id + data -
+		 * global fixed
+		 */
+		if (!skip(&data, tx_data->endp,
+			       1 + TX_BLOCK_SIZE - num_global_fixed))
+			goto corrupt;
+
+		/* Then we have keys-1 blocks of key id+diffs */
+		if (!skip(&data, tx_data->endp,
+			       (ndiffs + 1) * (keys - 1)))
+			goto corrupt;
+	}
+	ret = 0;
+	goto out;
+
+corrupt:
+	zilog_error("firmware is corrupt\n");
+	fw_unload_locked();
+	ret = -EFAULT;
+
+out:
+	mutex_unlock(&tx_data_lock);
+	return ret;
+}
+
+/* initialise the IR TX device */
+static int tx_init(struct IR *ir)
+{
+	int ret;
+
+	/* Load 'firmware' */
+	ret = fw_load(ir);
+	if (ret != 0)
+		return ret;
+
+	/* Send boot block */
+	ret = send_boot_data(ir);
+	if (ret != 0)
+		return ret;
+	ir->need_boot = 0;
+
+	/* Looks good */
+	return 0;
+}
+
+/* do nothing stub to make LIRC happy */
+static loff_t lseek(struct file *filep, loff_t offset, int orig)
+{
+	return -ESPIPE;
+}
+
+/* copied from lirc_dev */
+static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
+{
+	struct IR *ir = (struct IR *)filep->private_data;
+	unsigned char buf[ir->buf.chunk_size];
+	int ret = 0, written = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	dprintk("read called\n");
+	if (ir->c_rx.addr == 0)
+		return -ENODEV;
+
+	if (mutex_lock_interruptible(&ir->buf_lock))
+		return -ERESTARTSYS;
+
+	if (n % ir->buf.chunk_size) {
+		dprintk("read result = -EINVAL\n");
+		mutex_unlock(&ir->buf_lock);
+		return -EINVAL;
+	}
+
+	/*
+	 * we add ourselves to the task queue before buffer check
+	 * to avoid losing scan code (in case when queue is awaken somewhere
+	 * between while condition checking and scheduling)
+	 */
+	add_wait_queue(&ir->buf.wait_poll, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	/*
+	 * while we didn't provide 'length' bytes, device is opened in blocking
+	 * mode and 'copy_to_user' is happy, wait for data.
+	 */
+	while (written < n && ret == 0) {
+		if (lirc_buffer_empty(&ir->buf)) {
+			/*
+			 * According to the read(2) man page, 'written' can be
+			 * returned as less than 'n', instead of blocking
+			 * again, returning -EWOULDBLOCK, or returning
+			 * -ERESTARTSYS
+			 */
+			if (written)
+				break;
+			if (filep->f_flags & O_NONBLOCK) {
+				ret = -EWOULDBLOCK;
+				break;
+			}
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+			schedule();
+			set_current_state(TASK_INTERRUPTIBLE);
+		} else {
+			lirc_buffer_read(&ir->buf, buf);
+			ret = copy_to_user((void *)outbuf+written, buf,
+					   ir->buf.chunk_size);
+			written += ir->buf.chunk_size;
+		}
+	}
+
+	remove_wait_queue(&ir->buf.wait_poll, &wait);
+	set_current_state(TASK_RUNNING);
+	mutex_unlock(&ir->buf_lock);
+
+	dprintk("read result = %s (%d)\n",
+		ret ? "-EFAULT" : "OK", ret);
+
+	return ret ? ret : written;
+}
+
+/* send a keypress to the IR TX device */
+static int send_code(struct IR *ir, unsigned int code, unsigned int key)
+{
+	unsigned char data_block[TX_BLOCK_SIZE];
+	unsigned char buf[2];
+	int i, ret;
+
+	/* Get data for the codeset/key */
+	ret = get_key_data(data_block, code, key);
+
+	if (ret == -EPROTO) {
+		zilog_error("failed to get data for code %u, key %u -- check "
+			    "lircd.conf entries\n", code, key);
+		return ret;
+	} else if (ret != 0)
+		return ret;
+
+	/* Send the data block */
+	ret = send_data_block(ir, data_block);
+	if (ret != 0)
+		return ret;
+
+	/* Send data block length? */
+	buf[0] = 0x00;
+	buf[1] = 0x40;
+	ret = i2c_master_send(&ir->c_tx, buf, 2);
+	if (ret != 2) {
+		zilog_error("i2c_master_send failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+	ret = i2c_master_send(&ir->c_tx, buf, 1);
+	if (ret != 1) {
+		zilog_error("i2c_master_send failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+
+	/* Send finished download? */
+	ret = i2c_master_recv(&ir->c_tx, buf, 1);
+	if (ret != 1) {
+		zilog_error("i2c_master_recv failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+	if (buf[0] != 0xA0) {
+		zilog_error("unexpected IR TX response #1: %02x\n",
+			buf[0]);
+		return -EFAULT;
+	}
+
+	/* Send prepare command? */
+	buf[0] = 0x00;
+	buf[1] = 0x80;
+	ret = i2c_master_send(&ir->c_tx, buf, 2);
+	if (ret != 2) {
+		zilog_error("i2c_master_send failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+
+#ifdef I2C_HW_B_HDPVR
+	/*
+	 * The sleep bits aren't necessary on the HD PVR, and in fact, the
+	 * last i2c_master_recv always fails with a -5, so for now, we're
+	 * going to skip this whole mess and say we're done on the HD PVR
+	 */
+	if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR)
+		goto done;
+#endif
+
+	/*
+	 * This bit NAKs until the device is ready, so we retry it
+	 * sleeping a bit each time.  This seems to be what the windows
+	 * driver does, approximately.
+	 * Try for up to 1s.
+	 */
+	for (i = 0; i < 20; ++i) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((50 * HZ + 999) / 1000);
+		ret = i2c_master_send(&ir->c_tx, buf, 1);
+		if (ret == 1)
+			break;
+		dprintk("NAK expected: i2c_master_send "
+			"failed with %d (try %d)\n", ret, i+1);
+	}
+	if (ret != 1) {
+		zilog_error("IR TX chip never got ready: last i2c_master_send "
+			    "failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+
+	/* Seems to be an 'ok' response */
+	i = i2c_master_recv(&ir->c_tx, buf, 1);
+	if (i != 1) {
+		zilog_error("i2c_master_recv failed with %d\n", ret);
+		return -EFAULT;
+	}
+	if (buf[0] != 0x80) {
+		zilog_error("unexpected IR TX response #2: %02x\n", buf[0]);
+		return -EFAULT;
+	}
+
+done:
+	/* Oh good, it worked */
+	dprintk("sent code %u, key %u\n", code, key);
+	return 0;
+}
+
+/*
+ * Write a code to the device.  We take in a 32-bit number (an int) and then
+ * decode this to a codeset/key index.  The key data is then decompressed and
+ * sent to the device.  We have a spin lock as per i2c documentation to prevent
+ * multiple concurrent sends which would probably cause the device to explode.
+ */
+static ssize_t write(struct file *filep, const char *buf, size_t n,
+			  loff_t *ppos)
+{
+	struct IR *ir = (struct IR *)filep->private_data;
+	size_t i;
+	int failures = 0;
+
+	if (ir->c_tx.addr == 0)
+		return -ENODEV;
+
+	/* Validate user parameters */
+	if (n % sizeof(int))
+		return -EINVAL;
+
+	/* Lock i2c bus for the duration */
+	mutex_lock(&ir->ir_lock);
+
+	/* Send each keypress */
+	for (i = 0; i < n;) {
+		int ret = 0;
+		int command;
+
+		if (copy_from_user(&command, buf + i, sizeof(command))) {
+			mutex_unlock(&ir->ir_lock);
+			return -EFAULT;
+		}
+
+		/* Send boot data first if required */
+		if (ir->need_boot == 1) {
+			ret = send_boot_data(ir);
+			if (ret == 0)
+				ir->need_boot = 0;
+		}
+
+		/* Send the code */
+		if (ret == 0) {
+			ret = send_code(ir, (unsigned)command >> 16,
+					    (unsigned)command & 0xFFFF);
+			if (ret == -EPROTO) {
+				mutex_unlock(&ir->ir_lock);
+				return ret;
+			}
+		}
+
+		/*
+		 * Hmm, a failure.  If we've had a few then give up, otherwise
+		 * try a reset
+		 */
+		if (ret != 0) {
+			/* Looks like the chip crashed, reset it */
+			zilog_error("sending to the IR transmitter chip "
+				    "failed, trying reset\n");
+
+			if (failures >= 3) {
+				zilog_error("unable to send to the IR chip "
+					    "after 3 resets, giving up\n");
+				mutex_unlock(&ir->ir_lock);
+				return ret;
+			}
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout((100 * HZ + 999) / 1000);
+			ir->need_boot = 1;
+			++failures;
+		} else
+			i += sizeof(int);
+	}
+
+	/* Release i2c bus */
+	mutex_unlock(&ir->ir_lock);
+
+	/* All looks good */
+	return n;
+}
+
+/* copied from lirc_dev */
+static unsigned int poll(struct file *filep, poll_table *wait)
+{
+	struct IR *ir = (struct IR *)filep->private_data;
+	unsigned int ret;
+
+	dprintk("poll called\n");
+	if (ir->c_rx.addr == 0)
+		return -ENODEV;
+
+	mutex_lock(&ir->buf_lock);
+
+	poll_wait(filep, &ir->buf.wait_poll, wait);
+
+	dprintk("poll result = %s\n",
+		lirc_buffer_empty(&ir->buf) ? "0" : "POLLIN|POLLRDNORM");
+
+	ret = lirc_buffer_empty(&ir->buf) ? 0 : (POLLIN|POLLRDNORM);
+
+	mutex_unlock(&ir->buf_lock);
+	return ret;
+}
+
+static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+	struct IR *ir = (struct IR *)filep->private_data;
+	int result;
+	unsigned long mode, features = 0;
+
+	if (ir->c_rx.addr != 0)
+		features |= LIRC_CAN_REC_LIRCCODE;
+	if (ir->c_tx.addr != 0)
+		features |= LIRC_CAN_SEND_PULSE;
+
+	switch (cmd) {
+	case LIRC_GET_LENGTH:
+		result = put_user((unsigned long)13,
+				  (unsigned long *)arg);
+		break;
+	case LIRC_GET_FEATURES:
+		result = put_user(features, (unsigned long *) arg);
+		break;
+	case LIRC_GET_REC_MODE:
+		if (!(features&LIRC_CAN_REC_MASK))
+			return -ENOSYS;
+
+		result = put_user(LIRC_REC2MODE
+				  (features&LIRC_CAN_REC_MASK),
+				  (unsigned long *)arg);
+		break;
+	case LIRC_SET_REC_MODE:
+		if (!(features&LIRC_CAN_REC_MASK))
+			return -ENOSYS;
+
+		result = get_user(mode, (unsigned long *)arg);
+		if (!result && !(LIRC_MODE2REC(mode) & features))
+			result = -EINVAL;
+		break;
+	case LIRC_GET_SEND_MODE:
+		if (!(features&LIRC_CAN_SEND_MASK))
+			return -ENOSYS;
+
+		result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
+		break;
+	case LIRC_SET_SEND_MODE:
+		if (!(features&LIRC_CAN_SEND_MASK))
+			return -ENOSYS;
+
+		result = get_user(mode, (unsigned long *) arg);
+		if (!result && mode != LIRC_MODE_PULSE)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return result;
+}
+
+/*
+ * Open the IR device.  Get hold of our IR structure and
+ * stash it in private_data for the file
+ */
+static int open(struct inode *node, struct file *filep)
+{
+	struct IR *ir;
+	int ret;
+
+	/* find our IR struct */
+	unsigned minor = MINOR(node->i_rdev);
+	if (minor >= MAX_IRCTL_DEVICES) {
+		dprintk("minor %d: open result = -ENODEV\n",
+			minor);
+		return -ENODEV;
+	}
+	ir = ir_devices[minor];
+
+	/* increment in use count */
+	mutex_lock(&ir->ir_lock);
+	++ir->open;
+	ret = set_use_inc(ir);
+	if (ret != 0) {
+		--ir->open;
+		mutex_unlock(&ir->ir_lock);
+		return ret;
+	}
+	mutex_unlock(&ir->ir_lock);
+
+	/* stash our IR struct */
+	filep->private_data = ir;
+
+	return 0;
+}
+
+/* Close the IR device */
+static int close(struct inode *node, struct file *filep)
+{
+	/* find our IR struct */
+	struct IR *ir = (struct IR *)filep->private_data;
+	if (ir == NULL) {
+		zilog_error("close: no private_data attached to the file!\n");
+		return -ENODEV;
+	}
+
+	/* decrement in use count */
+	mutex_lock(&ir->ir_lock);
+	--ir->open;
+	set_use_dec(ir);
+	mutex_unlock(&ir->ir_lock);
+
+	return 0;
+}
+
+static struct lirc_driver lirc_template = {
+	.name		= "lirc_zilog",
+	.set_use_inc	= set_use_inc,
+	.set_use_dec	= set_use_dec,
+	.owner		= THIS_MODULE
+};
+
+static int ir_remove(struct i2c_client *client);
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id);
+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg);
+
+static const struct i2c_device_id ir_transceiver_id[] = {
+	/* Generic entry for any IR transceiver */
+	{ "ir_video", 0 },
+	/* IR device specific entries should be added here */
+	{ "ir_tx_z8f0811_haup", 0 },
+	{ "ir_rx_z8f0811_haup", 0 },
+	{ }
+};
+
+static struct i2c_driver driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "Zilog/Hauppauge i2c IR",
+	},
+	.probe		= ir_probe,
+	.remove		= ir_remove,
+	.command	= ir_command,
+	.id_table	= ir_transceiver_id,
+};
+
+static const struct file_operations lirc_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= lseek,
+	.read		= read,
+	.write		= write,
+	.poll		= poll,
+	.unlocked_ioctl	= ioctl,
+	.open		= open,
+	.release	= close
+};
+
+static int ir_remove(struct i2c_client *client)
+{
+	struct IR *ir = i2c_get_clientdata(client);
+
+	mutex_lock(&ir->ir_lock);
+
+	if (ir->have_rx || ir->have_tx) {
+		DECLARE_COMPLETION(tn);
+		DECLARE_COMPLETION(tn2);
+
+		/* end up polling thread */
+		if (ir->task && !IS_ERR(ir->task)) {
+			ir->t_notify = &tn;
+			ir->t_notify2 = &tn2;
+			ir->shutdown = 1;
+			wake_up_process(ir->task);
+			complete(&tn2);
+			wait_for_completion(&tn);
+			ir->t_notify = NULL;
+			ir->t_notify2 = NULL;
+		}
+
+	} else {
+		mutex_unlock(&ir->ir_lock);
+		zilog_error("%s: detached from something we didn't "
+			    "attach to\n", __func__);
+		return -ENODEV;
+	}
+
+	/* unregister lirc driver */
+	if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) {
+		lirc_unregister_driver(ir->l.minor);
+		ir_devices[ir->l.minor] = NULL;
+	}
+
+	/* free memory */
+	lirc_buffer_free(&ir->buf);
+	mutex_unlock(&ir->ir_lock);
+	kfree(ir);
+
+	return 0;
+}
+
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct IR *ir = NULL;
+	struct i2c_adapter *adap = client->adapter;
+	char buf;
+	int ret;
+	int have_rx = 0, have_tx = 0;
+
+	dprintk("%s: adapter id=0x%x, client addr=0x%02x\n",
+		__func__, adap->id, client->addr);
+
+	/*
+	 * The external IR receiver is at i2c address 0x71.
+	 * The IR transmitter is at 0x70.
+	 */
+	client->addr = 0x70;
+
+	if (!disable_tx) {
+		if (i2c_master_recv(client, &buf, 1) == 1)
+			have_tx = 1;
+		dprintk("probe 0x70 @ %s: %s\n",
+			adap->name, have_tx ? "success" : "failed");
+	}
+
+	if (!disable_rx) {
+		client->addr = 0x71;
+		if (i2c_master_recv(client, &buf, 1) == 1)
+			have_rx = 1;
+		dprintk("probe 0x71 @ %s: %s\n",
+			adap->name, have_rx ? "success" : "failed");
+	}
+
+	if (!(have_rx || have_tx)) {
+		zilog_error("%s: no devices found\n", adap->name);
+		goto out_nodev;
+	}
+
+	printk(KERN_INFO "lirc_zilog: chip found with %s\n",
+		have_rx && have_tx ? "RX and TX" :
+			have_rx ? "RX only" : "TX only");
+
+	ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+
+	if (!ir)
+		goto out_nomem;
+
+	ret = lirc_buffer_init(&ir->buf, 2, BUFLEN / 2);
+	if (ret)
+		goto out_nomem;
+
+	mutex_init(&ir->ir_lock);
+	mutex_init(&ir->buf_lock);
+	ir->need_boot = 1;
+
+	memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
+	ir->l.minor = -1;
+
+	/* I2C attach to device */
+	i2c_set_clientdata(client, ir);
+
+	/* initialise RX device */
+	if (have_rx) {
+		DECLARE_COMPLETION(tn);
+		memcpy(&ir->c_rx, client, sizeof(struct i2c_client));
+
+		ir->c_rx.addr = 0x71;
+		strlcpy(ir->c_rx.name, ZILOG_HAUPPAUGE_IR_RX_NAME,
+			I2C_NAME_SIZE);
+
+		/* try to fire up polling thread */
+		ir->t_notify = &tn;
+		ir->task = kthread_run(lirc_thread, ir, "lirc_zilog");
+		if (IS_ERR(ir->task)) {
+			ret = PTR_ERR(ir->task);
+			zilog_error("lirc_register_driver: cannot run "
+				    "poll thread %d\n", ret);
+			goto err;
+		}
+		wait_for_completion(&tn);
+		ir->t_notify = NULL;
+		ir->have_rx = 1;
+	}
+
+	/* initialise TX device */
+	if (have_tx) {
+		memcpy(&ir->c_tx, client, sizeof(struct i2c_client));
+		ir->c_tx.addr = 0x70;
+		strlcpy(ir->c_tx.name, ZILOG_HAUPPAUGE_IR_TX_NAME,
+			I2C_NAME_SIZE);
+		ir->have_tx = 1;
+	}
+
+	/* set lirc_dev stuff */
+	ir->l.code_length = 13;
+	ir->l.rbuf	  = &ir->buf;
+	ir->l.fops	  = &lirc_fops;
+	ir->l.data	  = ir;
+	ir->l.minor       = minor;
+	ir->l.dev         = &adap->dev;
+	ir->l.sample_rate = 0;
+
+	/* register with lirc */
+	ir->l.minor = lirc_register_driver(&ir->l);
+	if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) {
+		zilog_error("ir_attach: \"minor\" must be between 0 and %d "
+			    "(%d)!\n", MAX_IRCTL_DEVICES-1, ir->l.minor);
+		ret = -EBADRQC;
+		goto err;
+	}
+
+	/* store this for getting back in open() later on */
+	ir_devices[ir->l.minor] = ir;
+
+	/*
+	 * if we have the tx device, load the 'firmware'.  We do this
+	 * after registering with lirc as otherwise hotplug seems to take
+	 * 10s to create the lirc device.
+	 */
+	if (have_tx) {
+		/* Special TX init */
+		ret = tx_init(ir);
+		if (ret != 0)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	/* undo everything, hopefully... */
+	if (ir->c_rx.addr)
+		ir_remove(&ir->c_rx);
+	if (ir->c_tx.addr)
+		ir_remove(&ir->c_tx);
+	return ret;
+
+out_nodev:
+	zilog_error("no device found\n");
+	return -ENODEV;
+
+out_nomem:
+	zilog_error("memory allocation failure\n");
+	kfree(ir);
+	return -ENOMEM;
+}
+
+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	/* nothing */
+	return 0;
+}
+
+static int __init zilog_init(void)
+{
+	int ret;
+
+	zilog_notify("Zilog/Hauppauge IR driver initializing\n");
+
+	mutex_init(&tx_data_lock);
+
+	request_module("firmware_class");
+
+	ret = i2c_add_driver(&driver);
+	if (ret)
+		zilog_error("initialization failed\n");
+	else
+		zilog_notify("initialization complete\n");
+
+	return ret;
+}
+
+static void __exit zilog_exit(void)
+{
+	i2c_del_driver(&driver);
+	/* if loaded */
+	fw_unload();
+	zilog_notify("Zilog/Hauppauge IR driver unloaded\n");
+}
+
+module_init(zilog_init);
+module_exit(zilog_exit);
+
+MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)");
+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, "
+	      "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver");
+MODULE_LICENSE("GPL");
+/* for compat with old name, which isn't all that accurate anymore */
+MODULE_ALIAS("lirc_pvr150");
+
+module_param(minor, int, 0444);
+MODULE_PARM_DESC(minor, "Preferred minor device number");
+
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
+module_param(disable_rx, bool, 0644);
+MODULE_PARM_DESC(disable_rx, "Disable the IR receiver device");
+
+module_param(disable_tx, bool, 0644);
+MODULE_PARM_DESC(disable_tx, "Disable the IR transmitter device");
diff --git a/drivers/staging/memrar/memrar_handler.c b/drivers/staging/memrar/memrar_handler.c
index efa7fd6..41876f2 100644
--- a/drivers/staging/memrar/memrar_handler.c
+++ b/drivers/staging/memrar/memrar_handler.c
@@ -47,8 +47,7 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/io.h>
-
-#include "../rar_register/rar_register.h"
+#include <linux/rar_register.h>
 
 #include "memrar.h"
 #include "memrar_allocator.h"
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index 7e0be8d..10a82ef 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -113,7 +113,7 @@
 	if (!priv->phydev)
 		return -EINVAL;
 
-	return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
+	return phy_mii_ioctl(priv->phydev, rq, cmd);
 }
 
 static void cvm_oct_adjust_link(struct net_device *dev)
diff --git a/drivers/staging/rar_register/Kconfig b/drivers/staging/rar_register/Kconfig
deleted file mode 100644
index e9c2773..0000000
--- a/drivers/staging/rar_register/Kconfig
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-# RAR device configuration
-#
-
-menu "RAR Register Driver"
-#
-#	Restricted Access Register Manager
-#
-config RAR_REGISTER
-	tristate "Restricted Access Region Register Driver"
-	depends on PCI
-	default n
-	---help---
-	  This driver allows other kernel drivers access to the
-	  contents of the restricted access region control registers.
-
-	  The restricted access region control registers
-	  (rar_registers) are used to pass address and
-	  locking information on restricted access regions
-	  to other drivers that use restricted access regions.
-
-	  The restricted access regions are regions of memory
-	  on the Intel MID Platform that are not accessible to
-	  the x86 processor, but are accessible to dedicated
-	  processors on board peripheral devices.
-
-	  The purpose of the restricted access regions is to
-	  protect sensitive data from compromise by unauthorized
-	  programs running on the x86 processor.
-endmenu
diff --git a/drivers/staging/rar_register/Makefile b/drivers/staging/rar_register/Makefile
deleted file mode 100644
index d5954cc..0000000
--- a/drivers/staging/rar_register/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-EXTRA_CFLAGS += -DLITTLE__ENDIAN
-obj-$(CONFIG_RAR_REGISTER) += rar_register.o
diff --git a/drivers/staging/tm6000/Kconfig b/drivers/staging/tm6000/Kconfig
index 3657e33..c725356 100644
--- a/drivers/staging/tm6000/Kconfig
+++ b/drivers/staging/tm6000/Kconfig
@@ -26,8 +26,8 @@
 	  module will be called tm6000-alsa.
 
 config VIDEO_TM6000_DVB
-	bool "DVB Support for tm6000 based TV cards"
-	depends on VIDEO_TM6000 && DVB_CORE && EXPERIMENTAL
+	tristate "DVB Support for tm6000 based TV cards"
+	depends on VIDEO_TM6000 && DVB_CORE && USB && EXPERIMENTAL
 	select DVB_ZL10353
 	---help---
 	  This adds support for DVB cards based on the tm5600/tm6000 chip.
diff --git a/drivers/staging/tm6000/Makefile b/drivers/staging/tm6000/Makefile
index 93370fc..77e06bf 100644
--- a/drivers/staging/tm6000/Makefile
+++ b/drivers/staging/tm6000/Makefile
@@ -2,14 +2,12 @@
 		   tm6000-core.o  \
 		   tm6000-i2c.o   \
 		   tm6000-video.o \
-		   tm6000-stds.o
-
-ifeq ($(CONFIG_VIDEO_TM6000_DVB),y)
-tm6000-objs += tm6000-dvb.o
-endif
+		   tm6000-stds.o \
+		   tm6000-input.o
 
 obj-$(CONFIG_VIDEO_TM6000) += tm6000.o
 obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o
+obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o
 
 EXTRA_CFLAGS = -Idrivers/media/video
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c
index 273e26e..087137d 100644
--- a/drivers/staging/tm6000/tm6000-alsa.c
+++ b/drivers/staging/tm6000/tm6000-alsa.c
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 
 #include <asm/delay.h>
 #include <sound/core.h>
@@ -36,34 +37,11 @@
 	} while (0)
 
 /****************************************************************************
-	Data type declarations - Can be moded to a header file later
- ****************************************************************************/
-
-struct snd_tm6000_card {
-	struct snd_card            *card;
-
-	spinlock_t                 reg_lock;
-
-	atomic_t		   count;
-
-	unsigned int               period_size;
-	unsigned int               num_periods;
-
-	struct tm6000_core         *core;
-	struct tm6000_buffer       *buf;
-
-	int			   bufsize;
-
-	struct snd_pcm_substream *substream;
-};
-
-
-/****************************************************************************
 			Module global static vars
  ****************************************************************************/
 
 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] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
 
 module_param_array(enable, bool, NULL, 0444);
@@ -100,11 +78,15 @@
 	struct tm6000_core *core = chip->core;
 	int val;
 
+	dprintk(1, "Starting audio DMA\n");
+
 	/* Enables audio */
 	val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0);
 	val |= 0x20;
 	tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
 
+	tm6000_set_audio_bitrate(core, 48000);
+
 	tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0x80);
 
 	return 0;
@@ -129,19 +111,39 @@
 	return 0;
 }
 
-static int dsp_buffer_free(struct snd_tm6000_card *chip)
+static void dsp_buffer_free(struct snd_pcm_substream *substream)
 {
-	BUG_ON(!chip->bufsize);
+	struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
 
 	dprintk(2, "Freeing buffer\n");
 
-	/* FIXME: Frees buffer */
-
-	chip->bufsize = 0;
-
-       return 0;
+	vfree(substream->runtime->dma_area);
+	substream->runtime->dma_area = NULL;
+	substream->runtime->dma_bytes = 0;
 }
 
+static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
+{
+	struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+	dprintk(2, "Allocating buffer\n");
+
+	if (substream->runtime->dma_area) {
+		if (substream->runtime->dma_bytes > size)
+			return 0;
+		dsp_buffer_free(substream);
+	}
+
+	substream->runtime->dma_area = vmalloc(size);
+	if (!substream->runtime->dma_area)
+		return -ENOMEM;
+
+	substream->runtime->dma_bytes = size;
+
+	return 0;
+}
+
+
 /****************************************************************************
 				ALSA PCM Interface
  ****************************************************************************/
@@ -158,16 +160,16 @@
 		SNDRV_PCM_INFO_MMAP_VALID,
 	.formats = SNDRV_PCM_FMTBIT_S16_LE,
 
-	.rates =		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
-	.rate_min =		44100,
+	.rates =		SNDRV_PCM_RATE_48000,
+	.rate_min =		48000,
 	.rate_max =		48000,
 	.channels_min = 2,
 	.channels_max = 2,
-	.period_bytes_min = DEFAULT_FIFO_SIZE/4,
-	.period_bytes_max = DEFAULT_FIFO_SIZE/4,
+	.period_bytes_min = 62720,
+	.period_bytes_max = 62720,
 	.periods_min = 1,
 	.periods_max = 1024,
-	.buffer_bytes_max = (1024*1024),
+	.buffer_bytes_max = 62720 * 8,
 };
 
 /*
@@ -202,29 +204,64 @@
 	return 0;
 }
 
+static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
+{
+	struct snd_tm6000_card *chip = core->adev;
+	struct snd_pcm_substream *substream = chip->substream;
+	struct snd_pcm_runtime *runtime;
+	int period_elapsed = 0;
+	unsigned int stride, buf_pos;
+
+	if (!size || !substream)
+		return -EINVAL;
+
+	runtime = substream->runtime;
+	if (!runtime || !runtime->dma_area)
+		return -EINVAL;
+
+	buf_pos = chip->buf_pos;
+	stride = runtime->frame_bits >> 3;
+
+	dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
+		runtime->dma_area, buf_pos,
+		(unsigned int)runtime->buffer_size, stride);
+
+	if (buf_pos + size >= runtime->buffer_size * stride) {
+		unsigned int cnt = runtime->buffer_size * stride - buf_pos;
+		memcpy(runtime->dma_area + buf_pos, buf, cnt);
+		memcpy(runtime->dma_area, buf + cnt, size - cnt);
+	} else
+		memcpy(runtime->dma_area + buf_pos, buf, size);
+
+	chip->buf_pos += size;
+	if (chip->buf_pos >= runtime->buffer_size * stride)
+		chip->buf_pos -= runtime->buffer_size * stride;
+
+	chip->period_pos += size;
+	if (chip->period_pos >= runtime->period_size) {
+		chip->period_pos -= runtime->period_size;
+		period_elapsed = 1;
+	}
+
+	if (period_elapsed)
+		snd_pcm_period_elapsed(substream);
+
+	return 0;
+}
+
 /*
  * hw_params callback
  */
 static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
 			      struct snd_pcm_hw_params *hw_params)
 {
-	struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+	int size, rc;
 
-	if (substream->runtime->dma_area) {
-		dsp_buffer_free(chip);
-		substream->runtime->dma_area = NULL;
-	}
+	size = params_period_bytes(hw_params) * params_periods(hw_params);
 
-	chip->period_size = params_period_bytes(hw_params);
-	chip->num_periods = params_periods(hw_params);
-	chip->bufsize = chip->period_size * params_periods(hw_params);
-
-	BUG_ON(!chip->bufsize);
-
-	dprintk(1, "Setting buffer\n");
-
-	/* FIXME: Allocate buffer for audio */
-
+	rc = dsp_buffer_alloc(substream, size);
+	if (rc < 0)
+		return rc;
 
 	return 0;
 }
@@ -234,13 +271,9 @@
  */
 static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
 {
-
 	struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
 
-	if (substream->runtime->dma_area) {
-		dsp_buffer_free(chip);
-		substream->runtime->dma_area = NULL;
-	}
+	_tm6000_stop_audio_dma(chip);
 
 	return 0;
 }
@@ -250,6 +283,11 @@
  */
 static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
 {
+	struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+	chip->buf_pos = 0;
+	chip->period_pos = 0;
+
 	return 0;
 }
 
@@ -287,12 +325,8 @@
 static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	u16 count;
 
-	count = atomic_read(&chip->count);
-
-	return runtime->period_size * (count & (runtime->periods-1));
+	return chip->buf_pos;
 }
 
 /*
@@ -312,21 +346,6 @@
 /*
  * create a PCM device
  */
-static int __devinit snd_tm6000_pcm(struct snd_tm6000_card *chip,
-				    int device, char *name)
-{
-	int err;
-	struct snd_pcm *pcm;
-
-	err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
-	if (err < 0)
-		return err;
-	pcm->private_data = chip;
-	strcpy(pcm->name, name);
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
-
-	return 0;
-}
 
 /* FIXME: Control interface - How to control volume/mute? */
 
@@ -337,27 +356,41 @@
 /*
  * Alsa Constructor - Component probe
  */
-
-int tm6000_audio_init(struct tm6000_core *dev, int idx)
+int tm6000_audio_init(struct tm6000_core *dev)
 {
-	struct snd_card         *card;
-	struct snd_tm6000_card  *chip;
-	int                     rc, len;
-	char                    component[14];
+	struct snd_card		*card;
+	struct snd_tm6000_card	*chip;
+	int			rc;
+	static int		devnr;
+	char			component[14];
+	struct snd_pcm		*pcm;
 
-	if (idx >= SNDRV_CARDS)
+	if (!dev)
+		return 0;
+
+	if (devnr >= SNDRV_CARDS)
 		return -ENODEV;
 
-	if (!enable[idx])
+	if (!enable[devnr])
 		return -ENOENT;
 
-	rc = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card);
+	rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
 	if (rc < 0) {
-		snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
+		snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
 		return rc;
 	}
+	strcpy(card->driver, "tm6000-alsa");
+	strcpy(card->shortname, "TM5600/60x0");
+	sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
+		dev->udev->bus->busnum, dev->udev->devnum);
 
-	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	sprintf(component, "USB%04x:%04x",
+		le16_to_cpu(dev->udev->descriptor.idVendor),
+		le16_to_cpu(dev->udev->descriptor.idProduct));
+	snd_component_add(card, component);
+	snd_card_set_dev(card, &dev->udev->dev);
+
+	chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
 	if (!chip) {
 		rc = -ENOMEM;
 		goto error;
@@ -365,45 +398,24 @@
 
 	chip->core = dev;
 	chip->card = card;
+	dev->adev = chip;
+	spin_lock_init(&chip->reg_lock);
 
-	strcpy(card->driver, "tm6000-alsa");
-	sprintf(component, "USB%04x:%04x",
-		le16_to_cpu(dev->udev->descriptor.idVendor),
-		le16_to_cpu(dev->udev->descriptor.idProduct));
-	snd_component_add(card, component);
-
-	if (dev->udev->descriptor.iManufacturer)
-		len = usb_string(dev->udev,
-				 dev->udev->descriptor.iManufacturer,
-				 card->longname, sizeof(card->longname));
-	else
-		len = 0;
-
-	if (len > 0)
-		strlcat(card->longname, " ", sizeof(card->longname));
-
-	strlcat(card->longname, card->shortname, sizeof(card->longname));
-
-	len = strlcat(card->longname, " at ", sizeof(card->longname));
-
-	if (len < sizeof(card->longname))
-		usb_make_path(dev->udev, card->longname + len,
-			      sizeof(card->longname) - len);
-
-	strlcat(card->longname,
-		dev->udev->speed == USB_SPEED_LOW ? ", low speed" :
-		dev->udev->speed == USB_SPEED_FULL ? ", full speed" :
-							   ", high speed",
-		sizeof(card->longname));
-
-	rc = snd_tm6000_pcm(chip, 0, "tm6000 Digital");
+	rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
 	if (rc < 0)
 		goto error;
 
+	pcm->info_flags = 0;
+	pcm->private_data = chip;
+	strcpy(pcm->name, "Trident TM5600/60x0");
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
+
 	rc = snd_card_register(card);
 	if (rc < 0)
 		goto error;
 
+	dprintk(1,"Registered audio driver for %s\n", card->longname);
 
 	return 0;
 
@@ -414,14 +426,31 @@
 
 static int tm6000_audio_fini(struct tm6000_core *dev)
 {
+	struct snd_tm6000_card	*chip = dev->adev;
+
+	if (!dev)
+		return 0;
+
+	if (!chip)
+		return 0;
+
+	if (!chip->card)
+		return 0;
+
+	snd_card_free(chip->card);
+	chip->card = NULL;
+	kfree(chip);
+	dev->adev = NULL;
+
 	return 0;
 }
 
 struct tm6000_ops audio_ops = {
-	.id	= TM6000_AUDIO,
+	.type	= TM6000_AUDIO,
 	.name	= "TM6000 Audio Extension",
 	.init	= tm6000_audio_init,
 	.fini	= tm6000_audio_fini,
+	.fillbuf = tm6000_fillbuf,
 };
 
 static int __init tm6000_alsa_register(void)
diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c
index 6a9ae40..9d091c3 100644
--- a/drivers/staging/tm6000/tm6000-cards.c
+++ b/drivers/staging/tm6000/tm6000-cards.c
@@ -29,6 +29,7 @@
 #include <media/tuner.h>
 #include <media/tvaudio.h>
 #include <media/i2c-addr.h>
+#include <media/rc-map.h>
 
 #include "tm6000.h"
 #include "tm6000-regs.h"
@@ -69,6 +70,8 @@
 	int             demod_addr;     /* demodulator address */
 
 	struct tm6000_gpio gpio;
+
+	char		*ir_codes;
 };
 
 struct tm6000_board tm6000_boards[] = {
@@ -276,6 +279,7 @@
 			.dvb_led	= TM6010_GPIO_5,
 			.ir		= TM6010_GPIO_0,
 		},
+		.ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
 	},
 	[TM6010_BOARD_TWINHAN_TU501] = {
 		.name         = "Twinhan TU501(704D1)",
@@ -347,7 +351,7 @@
 	}
 	return (rc);
 }
-
+EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
 
 /* Tuner callback to provide the proper gpio changes needed for xc2028 */
 
@@ -361,6 +365,8 @@
 
 	switch (command) {
 	case XC2028_RESET_CLK:
+		tm6000_ir_wait(dev, 0);
+
 		tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
 					0x02, arg);
 		msleep(10);
@@ -410,13 +416,14 @@
 				msleep(130);
 				break;
 			}
+
+			tm6000_ir_wait(dev, 1);
 			break;
 		case 1:
 			tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
 						0x02, 0x01);
 			msleep(10);
 			break;
-
 		case 2:
 			rc = tm6000_i2c_reset(dev, 100);
 			break;
@@ -424,6 +431,7 @@
 	}
 	return rc;
 }
+EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
 
 int tm6000_cards_setup(struct tm6000_core *dev)
 {
@@ -635,6 +643,8 @@
 
 	dev->gpio = tm6000_boards[dev->model].gpio;
 
+	dev->ir_codes = tm6000_boards[dev->model].ir_codes;
+
 	dev->demod_addr = tm6000_boards[dev->model].demod_addr;
 
 	dev->caps = tm6000_boards[dev->model].caps;
@@ -681,31 +691,13 @@
 		goto err;
 
 	tm6000_add_into_devlist(dev);
-
 	tm6000_init_extension(dev);
 
-	if (dev->caps.has_dvb) {
-		dev->dvb = kzalloc(sizeof(*(dev->dvb)), GFP_KERNEL);
-		if (!dev->dvb) {
-			rc = -ENOMEM;
-			goto err2;
-		}
+	tm6000_ir_init(dev);
 
-#ifdef CONFIG_VIDEO_TM6000_DVB
-		rc = tm6000_dvb_register(dev);
-		if (rc < 0) {
-			kfree(dev->dvb);
-			dev->dvb = NULL;
-			goto err2;
-		}
-#endif
-	}
 	mutex_unlock(&dev->lock);
 	return 0;
 
-err2:
-	v4l2_device_unregister(&dev->v4l2_dev);
-
 err:
 	mutex_unlock(&dev->lock);
 	return rc;
@@ -724,7 +716,7 @@
 	unsigned int size = tmp & 0x7ff;
 
 	if (udev->speed == USB_SPEED_HIGH)
-		size = size * hb_mult (tmp);
+		size = size * hb_mult(tmp);
 
 	if (size > tm_ep->maxsize) {
 		tm_ep->endp = curr_e;
@@ -848,6 +840,19 @@
 							 &dev->isoc_out);
 				}
 				break;
+			case USB_ENDPOINT_XFER_INT:
+				if (!dir_out) {
+					get_max_endpoint(usbdev,
+							&interface->altsetting[i],
+							"INT IN", e,
+							&dev->int_in);
+				} else {
+					get_max_endpoint(usbdev,
+							&interface->altsetting[i],
+							"INT OUT", e,
+							&dev->int_out);
+				}
+				break;
 			}
 		}
 	}
@@ -906,12 +911,7 @@
 
 	mutex_lock(&dev->lock);
 
-#ifdef CONFIG_VIDEO_TM6000_DVB
-	if (dev->dvb) {
-		tm6000_dvb_unregister(dev);
-		kfree(dev->dvb);
-	}
-#endif
+	tm6000_ir_fini(dev);
 
 	if (dev->gpio.power_led) {
 		switch (dev->model) {
@@ -942,8 +942,8 @@
 
 	usb_put_dev(dev->udev);
 
-	tm6000_remove_from_devlist(dev);
 	tm6000_close_extension(dev);
+	tm6000_remove_from_devlist(dev);
 
 	mutex_unlock(&dev->lock);
 	kfree(dev);
diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c
index c3690e3..cded411 100644
--- a/drivers/staging/tm6000/tm6000-core.c
+++ b/drivers/staging/tm6000/tm6000-core.c
@@ -32,66 +32,64 @@
 
 #define USB_TIMEOUT	5*HZ /* ms */
 
-int tm6000_read_write_usb (struct tm6000_core *dev, u8 req_type, u8 req,
-			   u16 value, u16 index, u8 *buf, u16 len)
+int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
+			  u16 value, u16 index, u8 *buf, u16 len)
 {
 	int          ret, i;
 	unsigned int pipe;
-	static int   ini=0, last=0, n=0;
-	u8	     *data=NULL;
+	static int   ini = 0, last = 0, n = 0;
+	u8	     *data = NULL;
 
 	if (len)
 		data = kzalloc(len, GFP_KERNEL);
 
 
 	if (req_type & USB_DIR_IN)
-		pipe=usb_rcvctrlpipe(dev->udev, 0);
+		pipe = usb_rcvctrlpipe(dev->udev, 0);
 	else {
-		pipe=usb_sndctrlpipe(dev->udev, 0);
+		pipe = usb_sndctrlpipe(dev->udev, 0);
 		memcpy(data, buf, len);
 	}
 
 	if (tm6000_debug & V4L2_DEBUG_I2C) {
 		if (!ini)
-			last=ini=jiffies;
+			last = ini = jiffies;
 
 		printk("%06i (dev %p, pipe %08x): ", n, dev->udev, pipe);
 
-		printk( "%s: %06u ms %06u ms %02x %02x %02x %02x %02x %02x %02x %02x ",
-			(req_type & USB_DIR_IN)?" IN":"OUT",
+		printk("%s: %06u ms %06u ms %02x %02x %02x %02x %02x %02x %02x %02x ",
+			(req_type & USB_DIR_IN) ? " IN" : "OUT",
 			jiffies_to_msecs(jiffies-last),
 			jiffies_to_msecs(jiffies-ini),
-			req_type, req,value&0xff,value>>8, index&0xff, index>>8,
-			len&0xff, len>>8);
-		last=jiffies;
+			req_type, req, value&0xff, value>>8, index&0xff,
+			index>>8, len&0xff, len>>8);
+		last = jiffies;
 		n++;
 
-		if ( !(req_type & USB_DIR_IN) ) {
+		if (!(req_type & USB_DIR_IN)) {
 			printk(">>> ");
-			for (i=0;i<len;i++) {
-				printk(" %02x",buf[i]);
-			}
+			for (i = 0; i < len; i++)
+				printk(" %02x", buf[i]);
 		printk("\n");
 		}
 	}
 
-	ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index, data,
-			      len, USB_TIMEOUT);
+	ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index,
+			      data, len, USB_TIMEOUT);
 
 	if (req_type &  USB_DIR_IN)
 		memcpy(buf, data, len);
 
 	if (tm6000_debug & V4L2_DEBUG_I2C) {
-		if (ret<0) {
+		if (ret < 0) {
 			if (req_type &  USB_DIR_IN)
-				printk("<<< (len=%d)\n",len);
+				printk("<<< (len=%d)\n", len);
 
 			printk("%s: Error #%d\n", __FUNCTION__, ret);
 		} else if (req_type &  USB_DIR_IN) {
 			printk("<<< ");
-			for (i=0;i<len;i++) {
-				printk(" %02x",buf[i]);
-			}
+			for (i = 0; i < len; i++)
+				printk(" %02x", buf[i]);
 			printk("\n");
 		}
 	}
@@ -103,52 +101,52 @@
 	return ret;
 }
 
-int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
 {
 	return
-		tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR,
-				       req, value, index, NULL, 0);
+		tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
+				      req, value, index, NULL, 0);
 }
 EXPORT_SYMBOL_GPL(tm6000_set_reg);
 
-int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
 {
 	int rc;
 	u8 buf[1];
 
-	rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
-				       value, index, buf, 1);
+	rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+					value, index, buf, 1);
 
-	if (rc<0)
+	if (rc < 0)
 		return rc;
 
 	return *buf;
 }
 EXPORT_SYMBOL_GPL(tm6000_get_reg);
 
-int tm6000_get_reg16 (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index)
 {
 	int rc;
 	u8 buf[2];
 
-	rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
-				       value, index, buf, 2);
+	rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+					value, index, buf, 2);
 
-	if (rc<0)
+	if (rc < 0)
 		return rc;
 
 	return buf[1]|buf[0]<<8;
 }
 
-int tm6000_get_reg32 (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index)
 {
 	int rc;
 	u8 buf[4];
 
-	rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
-				       value, index, buf, 4);
+	rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+					value, index, buf, 4);
 
-	if (rc<0)
+	if (rc < 0)
 		return rc;
 
 	return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24;
@@ -188,7 +186,7 @@
 	}
 }
 
-int tm6000_init_analog_mode (struct tm6000_core *dev)
+int tm6000_init_analog_mode(struct tm6000_core *dev)
 {
 	if (dev->dev_type == TM6010) {
 		int val;
@@ -294,12 +292,10 @@
 		/* Enables soft reset */
 		tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
 
-		if (dev->scaler) {
+		if (dev->scaler)
 			tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20);
-		} else {
-			/* Enable Hfilter and disable TS Drop err */
+		else	/* Enable Hfilter and disable TS Drop err */
 			tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80);
-		}
 
 		tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88);
 		tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23);
@@ -332,13 +328,13 @@
 	/*FIXME: Hack!!! */
 	struct v4l2_frequency f;
 	mutex_lock(&dev->lock);
-	f.frequency=dev->freq;
+	f.frequency = dev->freq;
 	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
 	mutex_unlock(&dev->lock);
 
 	msleep(100);
-	tm6000_set_standard (dev, &dev->norm);
-	tm6000_set_audio_bitrate (dev,48000);
+	tm6000_set_standard(dev, &dev->norm);
+	tm6000_set_audio_bitrate(dev, 48000);
 
 	/* switch dvb led off */
 	if (dev->gpio.dvb_led) {
@@ -349,7 +345,7 @@
 	return 0;
 }
 
-int tm6000_init_digital_mode (struct tm6000_core *dev)
+int tm6000_init_digital_mode(struct tm6000_core *dev)
 {
 	if (dev->dev_type == TM6010) {
 		int val;
@@ -366,10 +362,8 @@
 		tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc);
 		tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff);
 		tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe);
-		tm6000_read_write_usb (dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
-		printk (KERN_INFO "buf %#x %#x \n", buf[0], buf[1]);
-
-
+		tm6000_read_write_usb(dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
+		printk(KERN_INFO"buf %#x %#x\n", buf[0], buf[1]);
 	} else  {
 		tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
 		tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
@@ -377,7 +371,7 @@
 		tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x08);
 		tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c);
 		tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff);
-		tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
+		tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
 		tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40);
 		tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
 		tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09);
@@ -388,14 +382,14 @@
 
 		tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c);
 		tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff);
-		tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
+		tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
 		msleep(50);
 
-		tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+		tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
 		msleep(50);
-		tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
+		tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
 		msleep(50);
-		tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+		tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
 		msleep(100);
 	}
 
@@ -407,6 +401,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(tm6000_init_digital_mode);
 
 struct reg_init {
 	u8 req;
@@ -566,9 +561,9 @@
 	{ TM6010_REQ07_RD8_IR_WAKEUP_SEL,  0xff },
 };
 
-int tm6000_init (struct tm6000_core *dev)
+int tm6000_init(struct tm6000_core *dev)
 {
-	int board, rc=0, i, size;
+	int board, rc = 0, i, size;
 	struct reg_init *tab;
 
 	if (dev->dev_type == TM6010) {
@@ -580,12 +575,12 @@
 	}
 
 	/* Load board's initialization table */
-	for (i=0; i< size; i++) {
-		rc= tm6000_set_reg (dev, tab[i].req, tab[i].reg, tab[i].val);
-		if (rc<0) {
-			printk (KERN_ERR "Error %i while setting req %d, "
-					 "reg %d to value %d\n", rc,
-					 tab[i].req,tab[i].reg, tab[i].val);
+	for (i = 0; i < size; i++) {
+		rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val);
+		if (rc < 0) {
+			printk(KERN_ERR "Error %i while setting req %d, "
+					"reg %d to value %d\n", rc,
+					tab[i].req, tab[i].reg, tab[i].val);
 			return rc;
 		}
 	}
@@ -593,12 +588,11 @@
 	msleep(5); /* Just to be conservative */
 
 	/* Check board version - maybe 10Moons specific */
-	board=tm6000_get_reg32 (dev, REQ_40_GET_VERSION, 0, 0);
-	if (board >=0) {
-		printk (KERN_INFO "Board version = 0x%08x\n",board);
-	} else {
-		printk (KERN_ERR "Error %i while retrieving board version\n",board);
-	}
+	board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0);
+	if (board >= 0)
+		printk(KERN_INFO "Board version = 0x%08x\n", board);
+	else
+		printk(KERN_ERR "Error %i while retrieving board version\n", board);
 
 	rc = tm6000_cards_setup(dev);
 
@@ -609,23 +603,32 @@
 {
 	int val;
 
-	val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0);
-printk("Original value=%d\n",val);
-	if (val<0)
+	if (dev->dev_type == TM6010) {
+		val = tm6000_get_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0);
+		if (val < 0)
+			return val;
+		val = (val & 0xf0) | 0x1; /* 48 kHz, not muted */
+		val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, val);
+		if (val < 0)
+			return val;
+	}
+
+	val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0);
+	if (val < 0)
 		return val;
 
 	val &= 0x0f;		/* Preserve the audio input control bits */
 	switch (bitrate) {
 	case 44100:
-		val|=0xd0;
-		dev->audio_bitrate=bitrate;
+		val |= 0xd0;
+		dev->audio_bitrate = bitrate;
 		break;
 	case 48000:
-		val|=0x60;
-		dev->audio_bitrate=bitrate;
+		val |= 0x60;
+		dev->audio_bitrate = bitrate;
 		break;
 	}
-	val=tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, val);
+	val = tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, val);
 
 	return val;
 }
@@ -659,6 +662,23 @@
 static LIST_HEAD(tm6000_extension_devlist);
 static DEFINE_MUTEX(tm6000_extension_devlist_lock);
 
+int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
+			char *buf, int size)
+{
+	struct tm6000_ops *ops = NULL;
+
+	/* FIXME: tm6000_extension_devlist_lock should be a spinlock */
+
+	if (!list_empty(&tm6000_extension_devlist)) {
+		list_for_each_entry(ops, &tm6000_extension_devlist, next) {
+			if (ops->fillbuf && ops->type == type)
+				ops->fillbuf(dev, buf, size);
+		}
+	}
+
+	return 0;
+}
+
 int tm6000_register_extension(struct tm6000_ops *ops)
 {
 	struct tm6000_core *dev = NULL;
@@ -667,10 +687,10 @@
 	mutex_lock(&tm6000_extension_devlist_lock);
 	list_add_tail(&ops->next, &tm6000_extension_devlist);
 	list_for_each_entry(dev, &tm6000_devlist, devlist) {
-		if (dev)
-			ops->init(dev);
+		ops->init(dev);
+		printk(KERN_INFO "%s: Initialized (%s) extension\n",
+		       dev->name, ops->name);
 	}
-	printk(KERN_INFO "tm6000: Initialized (%s) extension\n", ops->name);
 	mutex_unlock(&tm6000_extension_devlist_lock);
 	mutex_unlock(&tm6000_devlist_mutex);
 	return 0;
diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c
index 86c1c8b..f501edc 100644
--- a/drivers/staging/tm6000/tm6000-dvb.c
+++ b/drivers/staging/tm6000/tm6000-dvb.c
@@ -31,12 +31,25 @@
 #include "tuner-xc2028.h"
 #include "xc5000.h"
 
-static void inline print_err_status (struct tm6000_core *dev,
-				     int packet, int status)
+MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
+
+MODULE_SUPPORTED_DEVICE("{{Trident, tm5600},"
+			"{{Trident, tm6000},"
+			"{{Trident, tm6010}");
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug message");
+
+static inline void print_err_status(struct tm6000_core *dev,
+				    int packet, int status)
 {
 	char *errmsg = "Unknown";
 
-	switch(status) {
+	switch (status) {
 	case -ENOENT:
 		errmsg = "unlinked synchronuously";
 		break;
@@ -62,7 +75,7 @@
 		errmsg = "Device does not respond";
 		break;
 	}
-	if (packet<0) {
+	if (packet < 0) {
 		dprintk(dev, 1, "URB status %d [%s].\n",
 			status, errmsg);
 	} else {
@@ -74,19 +87,17 @@
 static void tm6000_urb_received(struct urb *urb)
 {
 	int ret;
-	struct tm6000_core* dev = urb->context;
+	struct tm6000_core *dev = urb->context;
 
-	if(urb->status != 0) {
-		print_err_status (dev,0,urb->status);
-	}
-	else if(urb->actual_length>0){
+	if (urb->status != 0)
+		print_err_status(dev, 0, urb->status);
+	else if (urb->actual_length > 0)
 		dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
 						   urb->actual_length);
-	}
 
-	if(dev->dvb->streams > 0) {
+	if (dev->dvb->streams > 0) {
 		ret = usb_submit_urb(urb, GFP_ATOMIC);
-		if(ret < 0) {
+		if (ret < 0) {
 			printk(KERN_ERR "tm6000:  error %s\n", __FUNCTION__);
 			kfree(urb->transfer_buffer);
 			usb_free_urb(urb);
@@ -100,7 +111,7 @@
 	unsigned int pipe, size;
 	struct tm6000_dvb *dvb = dev->dvb;
 
-	printk(KERN_INFO "tm6000: got start stream request %s\n",__FUNCTION__);
+	printk(KERN_INFO "tm6000: got start stream request %s\n", __FUNCTION__);
 
 	if (dev->mode != TM6000_MODE_DIGITAL) {
 		tm6000_init_digital_mode(dev);
@@ -108,7 +119,7 @@
 	}
 
 	dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if(dvb->bulk_urb == NULL) {
+	if (dvb->bulk_urb == NULL) {
 		printk(KERN_ERR "tm6000: couldn't allocate urb\n");
 		return -ENOMEM;
 	}
@@ -120,7 +131,7 @@
 	size = size * 15; /* 512 x 8 or 12 or 15 */
 
 	dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
-	if(dvb->bulk_urb->transfer_buffer == NULL) {
+	if (dvb->bulk_urb->transfer_buffer == NULL) {
 		usb_free_urb(dvb->bulk_urb);
 		printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
 		return -ENOMEM;
@@ -132,20 +143,20 @@
 						 tm6000_urb_received, dev);
 
 	ret = usb_clear_halt(dev->udev, pipe);
-	if(ret < 0) {
-		printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",ret,__FUNCTION__);
+	if (ret < 0) {
+		printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",
+							ret, __FUNCTION__);
 		return ret;
-	}
-	else {
+	} else
 		printk(KERN_ERR "tm6000: pipe resetted\n");
-	}
 
 /*	mutex_lock(&tm6000_driver.open_close_mutex); */
 	ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
 
 /*	mutex_unlock(&tm6000_driver.open_close_mutex); */
 	if (ret) {
-		printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",ret);
+		printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",
+									ret);
 
 		kfree(dvb->bulk_urb->transfer_buffer);
 		usb_free_urb(dvb->bulk_urb);
@@ -159,10 +170,10 @@
 {
 	struct tm6000_dvb *dvb = dev->dvb;
 
-	if(dvb->bulk_urb) {
-		printk (KERN_INFO "urb killing\n");
+	if (dvb->bulk_urb) {
+		printk(KERN_INFO "urb killing\n");
 		usb_kill_urb(dvb->bulk_urb);
-		printk (KERN_INFO "urb buffer free\n");
+		printk(KERN_INFO "urb buffer free\n");
 		kfree(dvb->bulk_urb->transfer_buffer);
 		usb_free_urb(dvb->bulk_urb);
 		dvb->bulk_urb = NULL;
@@ -174,35 +185,34 @@
 	struct dvb_demux *demux = feed->demux;
 	struct tm6000_core *dev = demux->priv;
 	struct tm6000_dvb *dvb = dev->dvb;
-	printk(KERN_INFO "tm6000: got start feed request %s\n",__FUNCTION__);
+	printk(KERN_INFO "tm6000: got start feed request %s\n", __FUNCTION__);
 
 	mutex_lock(&dvb->mutex);
-	if(dvb->streams == 0) {
+	if (dvb->streams == 0) {
 		dvb->streams = 1;
 /*		mutex_init(&tm6000_dev->streming_mutex); */
 		tm6000_start_stream(dev);
-	}
-	else {
+	} else
 		++(dvb->streams);
-	}
 	mutex_unlock(&dvb->mutex);
 
 	return 0;
 }
 
-int tm6000_stop_feed(struct dvb_demux_feed *feed) {
+int tm6000_stop_feed(struct dvb_demux_feed *feed)
+{
 	struct dvb_demux *demux = feed->demux;
 	struct tm6000_core *dev = demux->priv;
 	struct tm6000_dvb *dvb = dev->dvb;
 
-	printk(KERN_INFO "tm6000: got stop feed request %s\n",__FUNCTION__);
+	printk(KERN_INFO "tm6000: got stop feed request %s\n", __FUNCTION__);
 
 	mutex_lock(&dvb->mutex);
 
-	printk (KERN_INFO "stream %#x\n", dvb->streams);
+	printk(KERN_INFO "stream %#x\n", dvb->streams);
 	--(dvb->streams);
-	if(dvb->streams == 0) {
-		printk (KERN_INFO "stop stream\n");
+	if (dvb->streams == 0) {
+		printk(KERN_INFO "stop stream\n");
 		tm6000_stop_stream(dev);
 /*		mutex_destroy(&tm6000_dev->streaming_mutex); */
 	}
@@ -216,9 +226,9 @@
 {
 	struct tm6000_dvb *dvb = dev->dvb;
 
-	if(dev->caps.has_zl10353) {
-		struct zl10353_config config =
-				    {.demod_address = dev->demod_addr,
+	if (dev->caps.has_zl10353) {
+		struct zl10353_config config = {
+				     .demod_address = dev->demod_addr,
 				     .no_tuner = 1,
 				     .parallel_ts = 1,
 				     .if2 = 45700,
@@ -227,8 +237,7 @@
 
 		dvb->frontend = dvb_attach(zl10353_attach, &config,
 							   &dev->i2c_adap);
-	}
-	else {
+	} else {
 		printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
 		return -1;
 	}
@@ -238,7 +247,7 @@
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-int tm6000_dvb_register(struct tm6000_core *dev)
+int register_dvb(struct tm6000_core *dev)
 {
 	int ret = -1;
 	struct tm6000_dvb *dvb = dev->dvb;
@@ -249,13 +258,13 @@
 
 	/* attach the frontend */
 	ret = tm6000_dvb_attach_frontend(dev);
-	if(ret < 0) {
+	if (ret < 0) {
 		printk(KERN_ERR "tm6000: couldn't attach the frontend!\n");
 		goto err;
 	}
 
 	ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
-							  THIS_MODULE, &dev->udev->dev, adapter_nr);
+					THIS_MODULE, &dev->udev->dev, adapter_nr);
 	dvb->adapter.priv = dev;
 
 	if (dvb->frontend) {
@@ -308,9 +317,8 @@
 			break;
 			}
 		}
-	} else {
+	} else
 		printk(KERN_ERR "tm6000: no frontend found\n");
-	}
 
 	dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
 							    | DMX_MEMORY_BASED_FILTERING;
@@ -321,7 +329,7 @@
 	dvb->demux.stop_feed = tm6000_stop_feed;
 	dvb->demux.write_to_decoder = NULL;
 	ret = dvb_dmx_init(&dvb->demux);
-	if(ret < 0) {
+	if (ret < 0) {
 		printk("tm6000: dvb_dmx_init failed (errno = %d)\n", ret);
 		goto frontend_err;
 	}
@@ -331,7 +339,7 @@
 	dvb->dmxdev.capabilities = 0;
 
 	ret =  dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
-	if(ret < 0) {
+	if (ret < 0) {
 		printk("tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret);
 		goto dvb_dmx_err;
 	}
@@ -341,7 +349,7 @@
 dvb_dmx_err:
 	dvb_dmx_release(&dvb->demux);
 frontend_err:
-	if(dvb->frontend) {
+	if (dvb->frontend) {
 		dvb_frontend_detach(dvb->frontend);
 		dvb_unregister_frontend(dvb->frontend);
 	}
@@ -351,11 +359,11 @@
 	return ret;
 }
 
-void tm6000_dvb_unregister(struct tm6000_core *dev)
+void unregister_dvb(struct tm6000_core *dev)
 {
 	struct tm6000_dvb *dvb = dev->dvb;
 
-	if(dvb->bulk_urb != NULL) {
+	if (dvb->bulk_urb != NULL) {
 		struct urb *bulk_urb = dvb->bulk_urb;
 
 		kfree(bulk_urb->transfer_buffer);
@@ -365,7 +373,7 @@
 	}
 
 /*	mutex_lock(&tm6000_driver.open_close_mutex); */
-	if(dvb->frontend) {
+	if (dvb->frontend) {
 		dvb_frontend_detach(dvb->frontend);
 		dvb_unregister_frontend(dvb->frontend);
 	}
@@ -375,5 +383,70 @@
 	dvb_unregister_adapter(&dvb->adapter);
 	mutex_destroy(&dvb->mutex);
 /*	mutex_unlock(&tm6000_driver.open_close_mutex); */
-
 }
+
+static int dvb_init(struct tm6000_core *dev)
+{
+	struct tm6000_dvb *dvb;
+	int rc;
+
+	if (!dev)
+		return 0;
+
+	if (!dev->caps.has_dvb)
+		return 0;
+
+	dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL);
+	if (!dvb) {
+		printk(KERN_INFO "Cannot allocate memory\n");
+		return -ENOMEM;
+	}
+
+	dev->dvb = dvb;
+
+	rc = register_dvb(dev);
+	if (rc < 0) {
+		kfree(dvb);
+		dev->dvb = NULL;
+		return 0;
+	}
+
+	return 0;
+}
+
+static int dvb_fini(struct tm6000_core *dev)
+{
+	if (!dev)
+		return 0;
+
+	if (!dev->caps.has_dvb)
+		return 0;
+
+	if (dev->dvb) {
+		unregister_dvb(dev);
+		kfree(dev->dvb);
+		dev->dvb = NULL;
+	}
+
+	return 0;
+}
+
+static struct tm6000_ops dvb_ops = {
+	.type	= TM6000_DVB,
+	.name	= "TM6000 dvb Extension",
+	.init	= dvb_init,
+	.fini	= dvb_fini,
+};
+
+static int __init tm6000_dvb_register(void)
+{
+	return tm6000_register_extension(&dvb_ops);
+}
+
+static void __exit tm6000_dvb_unregister(void)
+{
+	tm6000_unregister_extension(&dvb_ops);
+}
+
+module_init(tm6000_dvb_register);
+module_exit(tm6000_dvb_unregister);
diff --git a/drivers/staging/tm6000/tm6000-i2c.c b/drivers/staging/tm6000/tm6000-i2c.c
index 94ff489..79bc67f 100644
--- a/drivers/staging/tm6000/tm6000-i2c.c
+++ b/drivers/staging/tm6000/tm6000-i2c.c
@@ -40,7 +40,7 @@
 module_param(i2c_debug, int, 0644);
 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
 
-#define i2c_dprintk(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
+#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \
 			printk(KERN_DEBUG "%s at %s: " fmt, \
 			dev->name, __FUNCTION__ , ##args); } while (0)
 
@@ -171,7 +171,7 @@
 		return 0;
 	for (i = 0; i < num; i++) {
 		addr = (msgs[i].addr << 1) & 0xff;
-		i2c_dprintk(2,"%s %s addr=0x%x len=%d:",
+		i2c_dprintk(2, "%s %s addr=0x%x len=%d:",
 			 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
 			 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
 		if (msgs[i].flags & I2C_M_RD) {
@@ -235,7 +235,7 @@
 
 	return num;
 err:
-	i2c_dprintk(2," ERROR: %i\n", rc);
+	i2c_dprintk(2, " ERROR: %i\n", rc);
 	return rc;
 }
 
@@ -266,11 +266,10 @@
 		if (0 == (i % 16))
 			printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
 		printk(" %02x", eedata[i]);
-		if ((eedata[i] >= ' ') && (eedata[i] <= 'z')) {
+		if ((eedata[i] >= ' ') && (eedata[i] <= 'z'))
 			bytes[i%16] = eedata[i];
-		} else {
-			bytes[i%16]='.';
-		}
+		else
+			bytes[i%16] = '.';
 
 		i++;
 
@@ -305,15 +304,15 @@
 }
 
 #define mass_write(addr, reg, data...)					\
-	{ const static u8 _val[] = data;				\
-	rc=tm6000_read_write_usb(dev,USB_DIR_OUT | USB_TYPE_VENDOR,	\
-	REQ_16_SET_GET_I2C_WR1_RDN,(reg<<8)+addr, 0x00, (u8 *) _val,	\
+	{ static const u8 _val[] = data;				\
+	rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,	\
+	REQ_16_SET_GET_I2C_WR1_RDN, (reg<<8)+addr, 0x00, (u8 *) _val,	\
 	ARRAY_SIZE(_val));						\
-	if (rc<0) {							\
-		printk(KERN_ERR "Error on line %d: %d\n",__LINE__,rc);	\
+	if (rc < 0) {							\
+		printk(KERN_ERR "Error on line %d: %d\n", __LINE__, rc);	\
 		return rc;						\
 	}								\
-	msleep (10);							\
+	msleep(10);							\
 	}
 
 static struct i2c_algorithm tm6000_algo = {
diff --git a/drivers/staging/tm6000/tm6000-input.c b/drivers/staging/tm6000/tm6000-input.c
new file mode 100644
index 0000000..32f7a0a
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-input.c
@@ -0,0 +1,364 @@
+/*
+   tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+
+   Copyright (C) 2010 Stefan Ringel <stefan.ringel@arcor.de>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation version 2
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include <media/ir-core.h>
+#include <media/ir-common.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+static unsigned int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable debug message [IR]");
+
+static unsigned int enable_ir = 1;
+module_param(enable_ir, int, 0644);
+MODULE_PARM_DESC(enable_ir, "enable ir (default is enable");
+
+#undef dprintk
+
+#define dprintk(fmt, arg...) \
+	if (ir_debug) { \
+		printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
+	}
+
+struct tm6000_ir_poll_result {
+	u8 rc_data[4];
+};
+
+struct tm6000_IR {
+	struct tm6000_core	*dev;
+	struct ir_input_dev	*input;
+	struct ir_input_state	ir;
+	char			name[32];
+	char			phys[32];
+
+	/* poll expernal decoder */
+	int			polling;
+	struct delayed_work	work;
+	u8			wait:1;
+	struct urb		*int_urb;
+	u8			*urb_data;
+	u8			key:1;
+
+	int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *);
+
+	/* IR device properties */
+	struct ir_dev_props	props;
+};
+
+
+void tm6000_ir_wait(struct tm6000_core *dev, u8 state)
+{
+	struct tm6000_IR *ir = dev->ir;
+
+	if (!dev->ir)
+		return;
+
+	if (state)
+		ir->wait = 1;
+	else
+		ir->wait = 0;
+}
+
+
+static int tm6000_ir_config(struct tm6000_IR *ir)
+{
+	struct tm6000_core *dev = ir->dev;
+	u8 buf[10];
+	int rc;
+
+	/* hack */
+	buf[0] = 0xff;
+	buf[1] = 0xff;
+	buf[2] = 0xf2;
+	buf[3] = 0x2b;
+	buf[4] = 0x20;
+	buf[5] = 0x35;
+	buf[6] = 0x60;
+	buf[7] = 0x04;
+	buf[8] = 0xc0;
+	buf[9] = 0x08;
+
+	rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
+		USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
+	msleep(100);
+
+	if (rc < 0) {
+		printk(KERN_INFO "IR configuration failed");
+		return rc;
+	}
+	return 0;
+}
+
+static void tm6000_ir_urb_received(struct urb *urb)
+{
+	struct tm6000_core *dev = urb->context;
+	struct tm6000_IR *ir = dev->ir;
+	int rc;
+
+	if (urb->status != 0)
+		printk(KERN_INFO "not ready\n");
+	else if (urb->actual_length > 0)
+		memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length);
+
+	dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0],
+	ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]);
+
+	ir->key = 1;
+
+	rc = usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int default_polling_getkey(struct tm6000_IR *ir,
+				struct tm6000_ir_poll_result *poll_result)
+{
+	struct tm6000_core *dev = ir->dev;
+	int rc;
+	u8 buf[2];
+
+	if (ir->wait && !&dev->int_in) {
+		poll_result->rc_data[0] = 0xff;
+		return 0;
+	}
+
+	if (&dev->int_in) {
+		poll_result->rc_data[0] = ir->urb_data[0];
+		poll_result->rc_data[1] = ir->urb_data[1];
+	} else {
+		tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
+		msleep(10);
+		tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
+		msleep(10);
+
+		rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
+		 USB_RECIP_DEVICE, REQ_02_GET_IR_CODE, 0, 0, buf, 1);
+
+		msleep(10);
+
+		dprintk("read data=%02x\n", buf[0]);
+		if (rc < 0)
+			return rc;
+
+		poll_result->rc_data[0] = buf[0];
+	}
+	return 0;
+}
+
+static void tm6000_ir_handle_key(struct tm6000_IR *ir)
+{
+	int result;
+	struct tm6000_ir_poll_result poll_result;
+
+	/* read the registers containing the IR status */
+	result = ir->get_key(ir, &poll_result);
+	if (result < 0) {
+		printk(KERN_INFO "ir->get_key() failed %d\n", result);
+		return;
+	}
+
+	dprintk("ir->get_key result data=%02x %02x\n",
+		poll_result.rc_data[0], poll_result.rc_data[1]);
+
+	if (poll_result.rc_data[0] != 0xff && ir->key == 1) {
+		ir_input_keydown(ir->input->input_dev, &ir->ir,
+			poll_result.rc_data[0] | poll_result.rc_data[1] << 8);
+
+		ir_input_nokey(ir->input->input_dev, &ir->ir);
+		ir->key = 0;
+	}
+	return;
+}
+
+static void tm6000_ir_work(struct work_struct *work)
+{
+	struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
+
+	tm6000_ir_handle_key(ir);
+	schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+}
+
+static int tm6000_ir_start(void *priv)
+{
+	struct tm6000_IR *ir = priv;
+
+	INIT_DELAYED_WORK(&ir->work, tm6000_ir_work);
+	schedule_delayed_work(&ir->work, 0);
+
+	return 0;
+}
+
+static void tm6000_ir_stop(void *priv)
+{
+	struct tm6000_IR *ir = priv;
+
+	cancel_delayed_work_sync(&ir->work);
+}
+
+int tm6000_ir_change_protocol(void *priv, u64 ir_type)
+{
+	struct tm6000_IR *ir = priv;
+
+	ir->get_key = default_polling_getkey;
+
+	tm6000_ir_config(ir);
+	/* TODO */
+	return 0;
+}
+
+int tm6000_ir_init(struct tm6000_core *dev)
+{
+	struct tm6000_IR *ir;
+	struct ir_input_dev *ir_input_dev;
+	int err = -ENOMEM;
+	int pipe, size, rc;
+
+	if (!enable_ir)
+		return -ENODEV;
+
+	if (!dev->caps.has_remote)
+		return 0;
+
+	if (!dev->ir_codes)
+		return 0;
+
+	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+	ir_input_dev = kzalloc(sizeof(*ir_input_dev), GFP_KERNEL);
+	ir_input_dev->input_dev = input_allocate_device();
+	if (!ir || !ir_input_dev || !ir_input_dev->input_dev)
+		goto err_out_free;
+
+	/* record handles to ourself */
+	ir->dev = dev;
+	dev->ir = ir;
+
+	ir->input = ir_input_dev;
+
+	/* input einrichten */
+	ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
+	ir->props.priv = ir;
+	ir->props.change_protocol = tm6000_ir_change_protocol;
+	ir->props.open = tm6000_ir_start;
+	ir->props.close = tm6000_ir_stop;
+	ir->props.driver_type = RC_DRIVER_SCANCODE;
+
+	ir->polling = 50;
+
+	snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
+						dev->name);
+
+	usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
+	strlcat(ir->phys, "/input0", sizeof(ir->phys));
+
+	tm6000_ir_change_protocol(ir, IR_TYPE_UNKNOWN);
+	err = ir_input_init(ir_input_dev->input_dev, &ir->ir, IR_TYPE_OTHER);
+	if (err < 0)
+		goto err_out_free;
+
+	ir_input_dev->input_dev->name = ir->name;
+	ir_input_dev->input_dev->phys = ir->phys;
+	ir_input_dev->input_dev->id.bustype = BUS_USB;
+	ir_input_dev->input_dev->id.version = 1;
+	ir_input_dev->input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+	ir_input_dev->input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+	ir_input_dev->input_dev->dev.parent = &dev->udev->dev;
+
+	if (&dev->int_in) {
+		dprintk("IR over int\n");
+
+		ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+		pipe = usb_rcvintpipe(dev->udev,
+			dev->int_in.endp->desc.bEndpointAddress
+			& USB_ENDPOINT_NUMBER_MASK);
+
+		size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+		dprintk("IR max size: %d\n", size);
+
+		ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
+		if (ir->int_urb->transfer_buffer == NULL) {
+			usb_free_urb(ir->int_urb);
+			goto err_out_stop;
+		}
+		dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
+		usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
+			ir->int_urb->transfer_buffer, size,
+			tm6000_ir_urb_received, dev,
+			dev->int_in.endp->desc.bInterval);
+		rc = usb_submit_urb(ir->int_urb, GFP_KERNEL);
+		if (rc) {
+			kfree(ir->int_urb->transfer_buffer);
+			usb_free_urb(ir->int_urb);
+			err = rc;
+			goto err_out_stop;
+		}
+		ir->urb_data = kzalloc(size, GFP_KERNEL);
+	}
+
+	/* ir register */
+	err = ir_input_register(ir->input->input_dev, dev->ir_codes,
+		&ir->props, "tm6000");
+	if (err)
+		goto err_out_stop;
+
+	return 0;
+
+err_out_stop:
+	dev->ir = NULL;
+err_out_free:
+	kfree(ir_input_dev);
+	kfree(ir);
+	return err;
+}
+
+int tm6000_ir_fini(struct tm6000_core *dev)
+{
+	struct tm6000_IR *ir = dev->ir;
+
+	/* skip detach on non attached board */
+
+	if (!ir)
+		return 0;
+
+	ir_input_unregister(ir->input->input_dev);
+
+	if (ir->int_urb) {
+		usb_kill_urb(ir->int_urb);
+		kfree(ir->int_urb->transfer_buffer);
+		usb_free_urb(ir->int_urb);
+		ir->int_urb = NULL;
+		kfree(ir->urb_data);
+		ir->urb_data = NULL;
+	}
+
+	kfree(ir->input);
+	ir->input = NULL;
+	kfree(ir);
+	dev->ir = NULL;
+
+	return 0;
+}
diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c
index b3564f6..6bf4a73 100644
--- a/drivers/staging/tm6000/tm6000-stds.c
+++ b/drivers/staging/tm6000/tm6000-stds.c
@@ -77,7 +77,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
@@ -135,7 +135,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
@@ -193,7 +193,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
@@ -251,7 +251,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
@@ -308,7 +308,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2},
@@ -354,7 +354,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
@@ -396,7 +396,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
@@ -438,7 +438,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
@@ -480,7 +480,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
@@ -521,7 +521,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2},
@@ -567,7 +567,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
@@ -609,7 +609,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
@@ -651,7 +651,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x00},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
@@ -693,7 +693,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
 			{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
@@ -734,7 +734,7 @@
 			{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
 			{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
 			{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03},
-			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x00},
+			{TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30},
 			{TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b},
 			{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
 			{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
@@ -763,11 +763,11 @@
 void tm6000_get_std_res(struct tm6000_core *dev)
 {
 	/* Currently, those are the only supported resoltions */
-	if (dev->norm & V4L2_STD_525_60) {
+	if (dev->norm & V4L2_STD_525_60)
 		dev->height = 480;
-	} else {
+	else
 		dev->height = 576;
-	}
+
 	dev->width = 720;
 }
 
diff --git a/drivers/staging/tm6000/tm6000-usb-isoc.h b/drivers/staging/tm6000/tm6000-usb-isoc.h
index 5a5049a..138716a 100644
--- a/drivers/staging/tm6000/tm6000-usb-isoc.h
+++ b/drivers/staging/tm6000/tm6000-usb-isoc.h
@@ -39,7 +39,7 @@
 	int				pos, size, pktsize;
 
 		/* Last field: ODD or EVEN? */
-	int				field;
+	int				vfield;
 
 		/* Stores incomplete commands */
 	u32				tmp_buf;
@@ -47,7 +47,4 @@
 
 		/* Stores already requested buffers */
 	struct tm6000_buffer    	*buf;
-
-		/* Stores the number of received fields */
-	int				nfields;
 };
diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c
index 56fa371..ce0a089 100644
--- a/drivers/staging/tm6000/tm6000-video.c
+++ b/drivers/staging/tm6000/tm6000-video.c
@@ -56,6 +56,7 @@
 
 /* Debug level */
 int tm6000_debug;
+EXPORT_SYMBOL_GPL(tm6000_debug);
 
 /* supported controls */
 static struct v4l2_queryctrl tm6000_qctrl[] = {
@@ -149,8 +150,6 @@
 
 	/* Cleans up buffer - Usefull for testing for frame/URB loss */
 	outp = videobuf_to_vmalloc(&(*buf)->vb);
-//	if (outp)
-//		memset(outp, 0, (*buf)->vb.size);
 
 	return;
 }
@@ -186,236 +185,152 @@
 /*
  * Identify the tm5600/6000 buffer header type and properly handles
  */
-static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp,
-			u8 *out_p, struct tm6000_buffer **buf)
-{
-	struct tm6000_dmaqueue  *dma_q = urb->context;
-	struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
-	u8 c;
-	unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
-	int rc = 0;
-	/* FIXME: move to tm6000-isoc */
-	static int last_line = -2, start_line = -2, last_field = -2;
-
-	/* FIXME: this is the hardcoded window size
-	 */
-	unsigned int linewidth = (*buf)->vb.width << 1;
-
-	if (!dev->isoc_ctl.cmd) {
-		c = (header >> 24) & 0xff;
-
-		/* split the header fields */
-		size  = ((header & 0x7e) << 1);
-
-		if (size > 0)
-			size -= 4;
-
-		block = (header >> 7) & 0xf;
-		field = (header >> 11) & 0x1;
-		line  = (header >> 12) & 0x1ff;
-		cmd   = (header >> 21) & 0x7;
-
-		/* Validates header fields */
-		if(size > TM6000_URB_MSG_LEN)
-			size = TM6000_URB_MSG_LEN;
-
-		if (cmd == TM6000_URB_MSG_VIDEO) {
-			if ((block+1)*TM6000_URB_MSG_LEN>linewidth)
-				cmd = TM6000_URB_MSG_ERR;
-
-			/* FIXME: Mounts the image as field0+field1
-			 * It should, instead, check if the user selected
-			 * entrelaced or non-entrelaced mode
-			 */
-			pos = ((line << 1) - field - 1) * linewidth +
-				block * TM6000_URB_MSG_LEN;
-
-			/* Don't allow to write out of the buffer */
-			if (pos+TM6000_URB_MSG_LEN > (*buf)->vb.size) {
-				dprintk(dev, V4L2_DEBUG_ISOC,
-					"ERR: size=%d, num=%d, line=%d, "
-					"field=%d\n",
-					size, block, line, field);
-
-				cmd = TM6000_URB_MSG_ERR;
-			}
-		} else {
-			pos=0;
-		}
-
-		/* Prints debug info */
-		dprintk(dev, V4L2_DEBUG_ISOC, "size=%d, num=%d, "
-				" line=%d, field=%d\n",
-				size, block, line, field);
-
-		if ((last_line!=line)&&(last_line+1!=line) &&
-		    (cmd != TM6000_URB_MSG_ERR) )  {
-			if (cmd != TM6000_URB_MSG_VIDEO)  {
-				dprintk(dev, V4L2_DEBUG_ISOC,  "cmd=%d, "
-					"size=%d, num=%d, line=%d, field=%d\n",
-					cmd, size, block, line, field);
-			}
-			if (start_line<0)
-				start_line=last_line;
-			/* Prints debug info */
-			dprintk(dev, V4L2_DEBUG_ISOC, "lines= %d-%d, "
-					"field=%d\n",
-					start_line, last_line, field);
-
-			if ((start_line<6 && last_line>200) &&
-				(last_field != field) ) {
-
-				dev->isoc_ctl.nfields++;
-				if (dev->isoc_ctl.nfields>=2) {
-					dev->isoc_ctl.nfields=0;
-
-					/* Announces that a new buffer were filled */
-					buffer_filled (dev, dma_q, *buf);
-					dprintk(dev, V4L2_DEBUG_ISOC,
-							"new buffer filled\n");
-					get_next_buf (dma_q, buf);
-					if (!*buf)
-						return rc;
-					out_p = videobuf_to_vmalloc(&((*buf)->vb));
-					if (!out_p)
-						return rc;
-
-					pos = dev->isoc_ctl.pos = 0;
-				}
-			}
-
-			start_line=line;
-			last_field=field;
-		}
-		if (cmd == TM6000_URB_MSG_VIDEO)
-			last_line = line;
-
-		pktsize = TM6000_URB_MSG_LEN;
-	} else {
-		/* Continue the last copy */
-		cmd = dev->isoc_ctl.cmd;
-		size= dev->isoc_ctl.size;
-		pos = dev->isoc_ctl.pos;
-		pktsize = dev->isoc_ctl.pktsize;
-	}
-
-	cpysize = (endp-(*ptr) > size) ? size : endp - *ptr;
-
-	if (cpysize) {
-		/* handles each different URB message */
-		switch(cmd) {
-		case TM6000_URB_MSG_VIDEO:
-			/* Fills video buffer */
-			memcpy(&out_p[pos], *ptr, cpysize);
-			break;
-		case TM6000_URB_MSG_PTS:
-			break;
-		case TM6000_URB_MSG_AUDIO:
-			/* Need some code to process audio */
-			printk ("%ld: cmd=%s, size=%d\n", jiffies,
-				tm6000_msg_type[cmd],size);
-			break;
-		case TM6000_URB_MSG_VBI:
-			break;
-		default:
-			dprintk (dev, V4L2_DEBUG_ISOC, "cmd=%s, size=%d\n",
-						tm6000_msg_type[cmd],size);
-		}
-	}
-	if (cpysize<size) {
-		/* End of URB packet, but cmd processing is not
-		 * complete. Preserve the state for a next packet
-		 */
-		dev->isoc_ctl.pos = pos+cpysize;
-		dev->isoc_ctl.size= size-cpysize;
-		dev->isoc_ctl.cmd = cmd;
-		dev->isoc_ctl.pktsize = pktsize-cpysize;
-		(*ptr)+=cpysize;
-	} else {
-		dev->isoc_ctl.cmd = 0;
-		(*ptr)+=pktsize;
-	}
-
-	return rc;
-}
-
 static int copy_streams(u8 *data, unsigned long len,
 			struct urb *urb)
 {
 	struct tm6000_dmaqueue  *dma_q = urb->context;
 	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
-	u8 *ptr=data, *endp=data+len;
+	u8 *ptr=data, *endp=data+len, c;
 	unsigned long header=0;
 	int rc=0;
-	struct tm6000_buffer *buf;
-	char *outp = NULL;
+	unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
+	struct tm6000_buffer *vbuf;
+	char *voutp = NULL;
+	unsigned int linewidth;
 
-	get_next_buf(dma_q, &buf);
-	if (buf)
-		outp = videobuf_to_vmalloc(&buf->vb);
-
-	if (!outp)
+	/* get video buffer */
+	get_next_buf (dma_q, &vbuf);
+	if (!vbuf)
+		return rc;
+	voutp = videobuf_to_vmalloc(&vbuf->vb);
+	if (!voutp)
 		return 0;
 
-	for (ptr=data; ptr<endp;) {
+	for (ptr = data; ptr < endp;) {
 		if (!dev->isoc_ctl.cmd) {
-			u8 *p=(u8 *)&dev->isoc_ctl.tmp_buf;
-			/* FIXME: This seems very complex
-			 * It just recovers up to 3 bytes of the header that
-			 * might be at the previous packet
-			 */
-			if (dev->isoc_ctl.tmp_buf_len) {
-				while (dev->isoc_ctl.tmp_buf_len) {
-					if ( *(ptr+3-dev->isoc_ctl.tmp_buf_len) == 0x47) {
-						break;
-					}
-					p++;
-					dev->isoc_ctl.tmp_buf_len--;
-				}
-				if (dev->isoc_ctl.tmp_buf_len) {
-					memcpy(&header, p,
-						dev->isoc_ctl.tmp_buf_len);
-					memcpy((u8 *)&header +
+			/* Header */
+			if (dev->isoc_ctl.tmp_buf_len > 0) {
+				/* from last urb or packet */
+				header = dev->isoc_ctl.tmp_buf;
+				if (4 - dev->isoc_ctl.tmp_buf_len > 0) {
+					memcpy ((u8 *)&header +
 						dev->isoc_ctl.tmp_buf_len,
 						ptr,
 						4 - dev->isoc_ctl.tmp_buf_len);
 					ptr += 4 - dev->isoc_ctl.tmp_buf_len;
-					goto HEADER;
 				}
-			}
-			/* Seek for sync */
-			for (;ptr<endp-3;ptr++) {
-				if (*(ptr+3)==0x47)
-					break;
+				dev->isoc_ctl.tmp_buf_len = 0;
+			} else {
+				if (ptr + 3 >= endp) {
+					/* have incomplete header */
+					dev->isoc_ctl.tmp_buf_len = endp - ptr;
+					memcpy (&dev->isoc_ctl.tmp_buf, ptr,
+						dev->isoc_ctl.tmp_buf_len);
+					return rc;
+				}
+				/* Seek for sync */
+				for (; ptr < endp - 3; ptr++) {
+					if (*(ptr + 3) == 0x47)
+						break;
+				}
+				/* Get message header */
+				header = *(unsigned long *)ptr;
+				ptr += 4;
 			}
 
-			if (ptr+3>=endp) {
-				dev->isoc_ctl.tmp_buf_len=endp-ptr;
-				memcpy (&dev->isoc_ctl.tmp_buf,ptr,
-					dev->isoc_ctl.tmp_buf_len);
-				dev->isoc_ctl.cmd=0;
-				return rc;
+			/* split the header fields */
+			c = (header >> 24) & 0xff;
+			size = ((header & 0x7e) << 1);
+			if (size > 0)
+				size -= 4;
+			block = (header >> 7) & 0xf;
+			field = (header >> 11) & 0x1;
+			line  = (header >> 12) & 0x1ff;
+			cmd   = (header >> 21) & 0x7;
+			/* Validates haeder fields */
+			if (size > TM6000_URB_MSG_LEN)
+				size = TM6000_URB_MSG_LEN;
+			pktsize = TM6000_URB_MSG_LEN;
+			/* calculate position in buffer
+			 * and change the buffer
+			 */
+			switch (cmd) {
+			case TM6000_URB_MSG_VIDEO:
+				if ((dev->isoc_ctl.vfield != field) &&
+					(field == 1)) {
+					/* Announces that a new buffer
+					 * were filled
+					 */
+					buffer_filled (dev, dma_q, vbuf);
+					dprintk (dev, V4L2_DEBUG_ISOC,
+							"new buffer filled\n");
+					get_next_buf (dma_q, &vbuf);
+					if (!vbuf)
+						return rc;
+					voutp = videobuf_to_vmalloc (&vbuf->vb);
+					if (!voutp)
+						return rc;
+					memset(voutp, 0, vbuf->vb.size);
+				}
+				linewidth = vbuf->vb.width << 1;
+				pos = ((line << 1) - field - 1) * linewidth +
+					block * TM6000_URB_MSG_LEN;
+				/* Don't allow to write out of the buffer */
+				if (pos + size > vbuf->vb.size)
+					cmd = TM6000_URB_MSG_ERR;
+				dev->isoc_ctl.vfield = field;
+				break;
+			case TM6000_URB_MSG_VBI:
+				break;
+			case TM6000_URB_MSG_AUDIO:
+			case TM6000_URB_MSG_PTS:
+				size = pktsize;		/* Size is always 180 bytes */
+				break;
 			}
-
-			/* Get message header */
-			header=*(unsigned long *)ptr;
-			ptr+=4;
+		} else {
+			/* Continue the last copy */
+			cmd = dev->isoc_ctl.cmd;
+			size = dev->isoc_ctl.size;
+			pos = dev->isoc_ctl.pos;
+			pktsize = dev->isoc_ctl.pktsize;
 		}
-HEADER:
-		/* Copy or continue last copy */
-		rc=copy_packet(urb,header,&ptr,endp,outp,&buf);
-		if (rc<0) {
-			buf=NULL;
-			printk(KERN_ERR "tm6000: buffer underrun at %ld\n",
-					jiffies);
-			return rc;
+		cpysize = (endp - ptr > size) ? size : endp - ptr;
+		if (cpysize) {
+			/* copy data in different buffers */
+			switch (cmd) {
+			case TM6000_URB_MSG_VIDEO:
+				/* Fills video buffer */
+				if (vbuf)
+					memcpy (&voutp[pos], ptr, cpysize);
+				break;
+			case TM6000_URB_MSG_AUDIO:
+				tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize);
+				break;
+			case TM6000_URB_MSG_VBI:
+				/* Need some code to copy vbi buffer */
+				break;
+			case TM6000_URB_MSG_PTS:
+				/* Need some code to copy pts */
+				break;
+			}
 		}
-		if (!buf)
-			return 0;
+		if (ptr + pktsize > endp) {
+			/* End of URB packet, but cmd processing is not
+			 * complete. Preserve the state for a next packet
+			 */
+			dev->isoc_ctl.pos = pos + cpysize;
+			dev->isoc_ctl.size = size - cpysize;
+			dev->isoc_ctl.cmd = cmd;
+			dev->isoc_ctl.pktsize = pktsize - (endp - ptr);
+			ptr += endp - ptr;
+		} else {
+			dev->isoc_ctl.cmd = 0;
+			ptr += pktsize;
+		}
 	}
-
 	return 0;
 }
+
 /*
  * Identify the tm5600/6000 buffer header type and properly handles
  */
@@ -510,7 +425,6 @@
 {
 	struct tm6000_dmaqueue  *dma_q = urb->context;
 	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
-	struct tm6000_buffer *buf;
 	int i, len=0, rc=1, status;
 	char *p;
 
@@ -585,7 +499,6 @@
 	struct urb *urb;
 	int i;
 
-	dev->isoc_ctl.nfields = -1;
 	dev->isoc_ctl.buf = NULL;
 	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
 		urb=dev->isoc_ctl.urb[i];
@@ -610,8 +523,6 @@
 	dev->isoc_ctl.urb=NULL;
 	dev->isoc_ctl.transfer_buffer=NULL;
 	dev->isoc_ctl.num_bufs = 0;
-
-	dev->isoc_ctl.num_bufs=0;
 }
 
 /*
diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h
index 7bbaf26..1ec1bff 100644
--- a/drivers/staging/tm6000/tm6000.h
+++ b/drivers/staging/tm6000/tm6000.h
@@ -20,8 +20,8 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-// Use the tm6000-hack, instead of the proper initialization code
-//#define HACK 1
+/* Use the tm6000-hack, instead of the proper initialization code i*/
+/* #define HACK 1 */
 
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
@@ -98,7 +98,7 @@
 };
 
 enum tm6000_mode {
-	TM6000_MODE_UNKNOWN=0,
+	TM6000_MODE_UNKNOWN = 0,
 	TM6000_MODE_ANALOG,
 	TM6000_MODE_DIGITAL,
 };
@@ -128,10 +128,21 @@
 	struct dvb_frontend	*frontend;
 	struct dmxdev		dmxdev;
 	unsigned int		streams;
-	struct urb 		*bulk_urb;
+	struct urb		*bulk_urb;
 	struct mutex		mutex;
 };
 
+struct snd_tm6000_card {
+	struct snd_card			*card;
+	spinlock_t			reg_lock;
+	struct tm6000_core		*core;
+	struct snd_pcm_substream	*substream;
+
+	/* temporary data for buffer fill processing */
+	unsigned			buf_pos;
+	unsigned			period_pos;
+};
+
 struct tm6000_endpoint {
 	struct usb_host_endpoint	*endp;
 	__u8				bInterfaceNumber;
@@ -147,7 +158,7 @@
 	enum tm6000_devtype		dev_type;	/* type of device */
 
 	v4l2_std_id                     norm;           /* Current norm */
-	int				width,height;	/* Selected resolution */
+	int				width, height;	/* Selected resolution */
 
 	enum tm6000_core_state		state;
 
@@ -160,6 +171,8 @@
 
 	struct tm6000_gpio		gpio;
 
+	char				*ir_codes;
+
 	/* Demodulator configuration */
 	int				demod_addr;	/* demodulator address */
 
@@ -190,6 +203,11 @@
 	/* DVB-T support */
 	struct tm6000_dvb		*dvb;
 
+	/* audio support */
+	struct snd_tm6000_card		*adev;
+
+	struct tm6000_IR		*ir;
+
 	/* locks */
 	struct mutex			lock;
 
@@ -197,6 +215,7 @@
 	struct usb_device		*udev;		/* the usb device */
 
 	struct tm6000_endpoint		bulk_in, bulk_out, isoc_in, isoc_out;
+	struct tm6000_endpoint		int_in, int_out;
 
 	/* scaler!=0 if scaler is active*/
 	int				scaler;
@@ -207,14 +226,18 @@
 	spinlock_t                   slock;
 };
 
-#define TM6000_AUDIO 0x10
+enum tm6000_ops_type {
+	TM6000_AUDIO = 0x10,
+	TM6000_DVB = 0x20,
+};
 
 struct tm6000_ops {
 	struct list_head	next;
 	char			*name;
-	int			id;
+	enum tm6000_ops_type	type;
 	int (*init)(struct tm6000_core *);
 	int (*fini)(struct tm6000_core *);
+	int (*fillbuf)(struct tm6000_core *, char *buf, int size);
 };
 
 struct tm6000_fh {
@@ -222,7 +245,7 @@
 
 	/* video capture */
 	struct tm6000_fmt            *fmt;
-	unsigned int                 width,height;
+	unsigned int                 width, height;
 	struct videobuf_queue        vb_vidq;
 
 	enum v4l2_buf_type           type;
@@ -234,28 +257,24 @@
 
 /* In tm6000-cards.c */
 
-int tm6000_tuner_callback (void *ptr, int component, int command, int arg);
-int tm6000_xc5000_callback (void *ptr, int component, int command, int arg);
+int tm6000_tuner_callback(void *ptr, int component, int command, int arg);
+int tm6000_xc5000_callback(void *ptr, int component, int command, int arg);
 int tm6000_cards_setup(struct tm6000_core *dev);
 
 /* In tm6000-core.c */
 
-int tm6000_read_write_usb (struct tm6000_core *dev, u8 reqtype, u8 req,
+int tm6000_read_write_usb(struct tm6000_core *dev, u8 reqtype, u8 req,
 			   u16 value, u16 index, u8 *buf, u16 len);
-int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
 int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index);
 int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index);
-int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
 int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep);
+int tm6000_init(struct tm6000_core *dev);
 
-int tm6000_init (struct tm6000_core *dev);
-
-int tm6000_init_analog_mode (struct tm6000_core *dev);
-int tm6000_init_digital_mode (struct tm6000_core *dev);
-int tm6000_set_audio_bitrate (struct tm6000_core *dev, int bitrate);
-
-int tm6000_dvb_register(struct tm6000_core *dev);
-void tm6000_dvb_unregister(struct tm6000_core *dev);
+int tm6000_init_analog_mode(struct tm6000_core *dev);
+int tm6000_init_digital_mode(struct tm6000_core *dev);
+int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate);
 
 int tm6000_v4l2_register(struct tm6000_core *dev);
 int tm6000_v4l2_unregister(struct tm6000_core *dev);
@@ -268,10 +287,13 @@
 void tm6000_unregister_extension(struct tm6000_ops *ops);
 void tm6000_init_extension(struct tm6000_core *dev);
 void tm6000_close_extension(struct tm6000_core *dev);
+int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
+			char *buf, int size);
+
 
 /* In tm6000-stds.c */
 void tm6000_get_std_res(struct tm6000_core *dev);
-int tm6000_set_standard (struct tm6000_core *dev, v4l2_std_id *norm);
+int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id *norm);
 
 /* In tm6000-i2c.c */
 int tm6000_i2c_register(struct tm6000_core *dev);
@@ -285,14 +307,14 @@
 			   enum v4l2_buf_type i);
 int tm6000_vidioc_streamoff(struct file *file, void *priv,
 			    enum v4l2_buf_type i);
-int tm6000_vidioc_reqbufs (struct file *file, void *priv,
-			   struct v4l2_requestbuffers *rb);
-int tm6000_vidioc_querybuf (struct file *file, void *priv,
-			    struct v4l2_buffer *b);
-int tm6000_vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *b);
-int tm6000_vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *b);
+int tm6000_vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *rb);
+int tm6000_vidioc_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *b);
+int tm6000_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b);
+int tm6000_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b);
 ssize_t tm6000_v4l2_read(struct file *filp, char __user * buf, size_t count,
-			 loff_t * f_pos);
+			 loff_t *f_pos);
 unsigned int tm6000_v4l2_poll(struct file *file,
 			      struct poll_table_struct *wait);
 int tm6000_queue_init(struct tm6000_core *dev);
@@ -300,6 +322,10 @@
 /* In tm6000-alsa.c */
 /*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/
 
+/* In tm6000-input.c */
+int tm6000_ir_init(struct tm6000_core *dev);
+int tm6000_ir_fini(struct tm6000_core *dev);
+void tm6000_ir_wait(struct tm6000_core *dev, u8 state);
 
 /* Debug stuff */
 
@@ -307,7 +333,7 @@
 
 #define dprintk(dev, level, fmt, arg...) do {\
 	if (tm6000_debug & level) \
-		printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, 		\
+		printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \
 			 dev->name, __FUNCTION__ , ##arg); } while (0)
 
 #define V4L2_DEBUG_REG		0x0004
@@ -320,5 +346,3 @@
 #define tm6000_err(fmt, arg...) do {\
 	printk(KERN_ERR "tm6000 %s :"fmt, \
 		__FUNCTION__ , ##arg); } while (0)
-
-
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index c89990f..101ffc9 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -866,50 +866,50 @@
 	instance->line_status = buf[CXINF_LINE_STATUS];
 	switch (instance->line_status) {
 	case 0:
-		atm_dev->signal = ATM_PHY_SIG_LOST;
+		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
 		atm_info(usbatm, "ADSL line: down\n");
 		break;
 
 	case 1:
-		atm_dev->signal = ATM_PHY_SIG_LOST;
+		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
 		atm_info(usbatm, "ADSL line: attempting to activate\n");
 		break;
 
 	case 2:
-		atm_dev->signal = ATM_PHY_SIG_LOST;
+		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
 		atm_info(usbatm, "ADSL line: training\n");
 		break;
 
 	case 3:
-		atm_dev->signal = ATM_PHY_SIG_LOST;
+		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
 		atm_info(usbatm, "ADSL line: channel analysis\n");
 		break;
 
 	case 4:
-		atm_dev->signal = ATM_PHY_SIG_LOST;
+		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
 		atm_info(usbatm, "ADSL line: exchange\n");
 		break;
 
 	case 5:
 		atm_dev->link_rate = buf[CXINF_DOWNSTREAM_RATE] * 1000 / 424;
-		atm_dev->signal = ATM_PHY_SIG_FOUND;
+		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_FOUND);
 
 		atm_info(usbatm, "ADSL line: up (%d kb/s down | %d kb/s up)\n",
 		     buf[CXINF_DOWNSTREAM_RATE], buf[CXINF_UPSTREAM_RATE]);
 		break;
 
 	case 6:
-		atm_dev->signal = ATM_PHY_SIG_LOST;
+		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
 		atm_info(usbatm, "ADSL line: waiting\n");
 		break;
 
 	case 7:
-		atm_dev->signal = ATM_PHY_SIG_LOST;
+		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
 		atm_info(usbatm, "ADSL line: initializing\n");
 		break;
 
 	default:
-		atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN);
 		atm_info(usbatm, "Unknown line state %02x\n", instance->line_status);
 		break;
 	}
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 1335456..80f9617 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -525,7 +525,7 @@
 
 		switch (status) {
 		case 0:
-			atm_dev->signal = ATM_PHY_SIG_LOST;
+			atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
 			if (instance->last_status)
 				atm_info(usbatm, "ADSL line is down\n");
 			/* It may never resync again unless we ask it to... */
@@ -533,12 +533,12 @@
 			break;
 
 		case 0x08:
-			atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+			atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN);
 			atm_info(usbatm, "ADSL line is blocked?\n");
 			break;
 
 		case 0x10:
-			atm_dev->signal = ATM_PHY_SIG_LOST;
+			atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
 			atm_info(usbatm, "ADSL line is synchronising\n");
 			break;
 
@@ -554,7 +554,7 @@
 			}
 
 			atm_dev->link_rate = down_speed * 1000 / 424;
-			atm_dev->signal = ATM_PHY_SIG_FOUND;
+			atm_dev_signal_change(atm_dev, ATM_PHY_SIG_FOUND);
 
 			atm_info(usbatm,
 				 "ADSL line is up (%d kb/s down | %d kb/s up)\n",
@@ -562,7 +562,7 @@
 			break;
 
 		default:
-			atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+			atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN);
 			atm_info(usbatm, "unknown line state %02x\n", status);
 			break;
 		}
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index e213d3f..ebae944 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -575,6 +575,13 @@
 			sc->usbatm->atm_dev->type = val; \
 	} while (0)
 
+#define UPDATE_ATM_SIGNAL(val) \
+	do { \
+		if (sc->usbatm->atm_dev) \
+			atm_dev_signal_change(sc->usbatm->atm_dev, val); \
+	} while (0)
+
+
 /* Firmware loading */
 #define LOAD_INTERNAL     0xA0
 #define F8051_USBCS       0x7f92
@@ -1359,7 +1366,7 @@
 	/* always update it as atm layer could not be init when we switch to
 	 * operational state
 	 */
-	UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND);
+	UPDATE_ATM_SIGNAL(ATM_PHY_SIG_FOUND);
 
 	/* wake up processes waiting for synchronization */
 	wake_up(&sc->sync_q);
@@ -1498,7 +1505,7 @@
 	/* always update it as atm layer could not be init when we switch to
 	 * operational state
 	 */
-	UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND);
+	UPDATE_ATM_SIGNAL(ATM_PHY_SIG_FOUND);
 
 	/* wake up processes waiting for synchronization */
 	wake_up(&sc->sync_q);
@@ -1825,7 +1832,7 @@
 	 * So we will failed to wait Ready CMV.
 	 */
 	sc->cmv_ack = 0;
-	UPDATE_ATM_STAT(signal, ATM_PHY_SIG_LOST);
+	UPDATE_ATM_SIGNAL(ATM_PHY_SIG_LOST);
 
 	/* reset statistics */
 	memset(&sc->stats, 0, sizeof(struct uea_stats));
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c
index dbe6db0..be446b7 100644
--- a/drivers/usb/gadget/f_uvc.c
+++ b/drivers/usb/gadget/f_uvc.c
@@ -61,12 +61,12 @@
 #define UVC_INTF_VIDEO_STREAMING		1
 
 static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
-	.bLength		= USB_DT_INTERFACE_ASSOCIATION_SIZE,
+	.bLength		= sizeof(uvc_iad),
 	.bDescriptorType	= USB_DT_INTERFACE_ASSOCIATION,
 	.bFirstInterface	= 0,
 	.bInterfaceCount	= 2,
 	.bFunctionClass		= USB_CLASS_VIDEO,
-	.bFunctionSubClass	= 0x03,
+	.bFunctionSubClass	= UVC_SC_VIDEO_INTERFACE_COLLECTION,
 	.bFunctionProtocol	= 0x00,
 	.iFunction		= 0,
 };
@@ -78,7 +78,7 @@
 	.bAlternateSetting	= 0,
 	.bNumEndpoints		= 1,
 	.bInterfaceClass	= USB_CLASS_VIDEO,
-	.bInterfaceSubClass	= 0x01,
+	.bInterfaceSubClass	= UVC_SC_VIDEOCONTROL,
 	.bInterfaceProtocol	= 0x00,
 	.iInterface		= 0,
 };
@@ -106,7 +106,7 @@
 	.bAlternateSetting	= 0,
 	.bNumEndpoints		= 0,
 	.bInterfaceClass	= USB_CLASS_VIDEO,
-	.bInterfaceSubClass	= 0x02,
+	.bInterfaceSubClass	= UVC_SC_VIDEOSTREAMING,
 	.bInterfaceProtocol	= 0x00,
 	.iInterface		= 0,
 };
@@ -118,7 +118,7 @@
 	.bAlternateSetting	= 1,
 	.bNumEndpoints		= 1,
 	.bInterfaceClass	= USB_CLASS_VIDEO,
-	.bInterfaceSubClass	= 0x02,
+	.bInterfaceSubClass	= UVC_SC_VIDEOSTREAMING,
 	.bInterfaceProtocol	= 0x00,
 	.iInterface		= 0,
 };
@@ -603,15 +603,15 @@
 
 	/* Validate the descriptors. */
 	if (control == NULL || control[0] == NULL ||
-	    control[0]->bDescriptorSubType != UVC_DT_HEADER)
+	    control[0]->bDescriptorSubType != UVC_VC_HEADER)
 		goto error;
 
 	if (fs_streaming == NULL || fs_streaming[0] == NULL ||
-	    fs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER)
+	    fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
 		goto error;
 
 	if (hs_streaming == NULL || hs_streaming[0] == NULL ||
-	    hs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER)
+	    hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
 		goto error;
 
 	uvc->desc.control = control;
diff --git a/drivers/usb/gadget/f_uvc.h b/drivers/usb/gadget/f_uvc.h
index 8a5db7c..e18a663 100644
--- a/drivers/usb/gadget/f_uvc.h
+++ b/drivers/usb/gadget/f_uvc.h
@@ -15,357 +15,7 @@
 #define _F_UVC_H_
 
 #include <linux/usb/composite.h>
-
-#define USB_CLASS_VIDEO_CONTROL		1
-#define USB_CLASS_VIDEO_STREAMING	2
-
-struct uvc_descriptor_header {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-} __attribute__ ((packed));
-
-struct uvc_header_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u16 bcdUVC;
-	__u16 wTotalLength;
-	__u32 dwClockFrequency;
-	__u8  bInCollection;
-	__u8  baInterfaceNr[];
-} __attribute__((__packed__));
-
-#define UVC_HEADER_DESCRIPTOR(n)	uvc_header_descriptor_##n
-
-#define DECLARE_UVC_HEADER_DESCRIPTOR(n) 			\
-struct UVC_HEADER_DESCRIPTOR(n) {				\
-	__u8  bLength;						\
-	__u8  bDescriptorType;					\
-	__u8  bDescriptorSubType;				\
-	__u16 bcdUVC;						\
-	__u16 wTotalLength;					\
-	__u32 dwClockFrequency;					\
-	__u8  bInCollection;					\
-	__u8  baInterfaceNr[n];					\
-} __attribute__ ((packed))
-
-struct uvc_input_terminal_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u8  bTerminalID;
-	__u16 wTerminalType;
-	__u8  bAssocTerminal;
-	__u8  iTerminal;
-} __attribute__((__packed__));
-
-struct uvc_output_terminal_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u8  bTerminalID;
-	__u16 wTerminalType;
-	__u8  bAssocTerminal;
-	__u8  bSourceID;
-	__u8  iTerminal;
-} __attribute__((__packed__));
-
-struct uvc_camera_terminal_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u8  bTerminalID;
-	__u16 wTerminalType;
-	__u8  bAssocTerminal;
-	__u8  iTerminal;
-	__u16 wObjectiveFocalLengthMin;
-	__u16 wObjectiveFocalLengthMax;
-	__u16 wOcularFocalLength;
-	__u8  bControlSize;
-	__u8  bmControls[3];
-} __attribute__((__packed__));
-
-struct uvc_selector_unit_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u8  bUnitID;
-	__u8  bNrInPins;
-	__u8  baSourceID[0];
-	__u8  iSelector;
-} __attribute__((__packed__));
-
-#define UVC_SELECTOR_UNIT_DESCRIPTOR(n)	\
-	uvc_selector_unit_descriptor_##n
-
-#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n) 		\
-struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) {			\
-	__u8  bLength;						\
-	__u8  bDescriptorType;					\
-	__u8  bDescriptorSubType;				\
-	__u8  bUnitID;						\
-	__u8  bNrInPins;					\
-	__u8  baSourceID[n];					\
-	__u8  iSelector;					\
-} __attribute__ ((packed))
-
-struct uvc_processing_unit_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u8  bUnitID;
-	__u8  bSourceID;
-	__u16 wMaxMultiplier;
-	__u8  bControlSize;
-	__u8  bmControls[2];
-	__u8  iProcessing;
-} __attribute__((__packed__));
-
-struct uvc_extension_unit_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u8  bUnitID;
-	__u8  guidExtensionCode[16];
-	__u8  bNumControls;
-	__u8  bNrInPins;
-	__u8  baSourceID[0];
-	__u8  bControlSize;
-	__u8  bmControls[0];
-	__u8  iExtension;
-} __attribute__((__packed__));
-
-#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
-	uvc_extension_unit_descriptor_##p_##n
-
-#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) 		\
-struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) {			\
-	__u8  bLength;						\
-	__u8  bDescriptorType;					\
-	__u8  bDescriptorSubType;				\
-	__u8  bUnitID;						\
-	__u8  guidExtensionCode[16];				\
-	__u8  bNumControls;					\
-	__u8  bNrInPins;					\
-	__u8  baSourceID[p];					\
-	__u8  bControlSize;					\
-	__u8  bmControls[n];					\
-	__u8  iExtension;					\
-} __attribute__ ((packed))
-
-struct uvc_control_endpoint_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u16 wMaxTransferSize;
-} __attribute__((__packed__));
-
-#define UVC_DT_HEADER				1
-#define UVC_DT_INPUT_TERMINAL			2
-#define UVC_DT_OUTPUT_TERMINAL			3
-#define UVC_DT_SELECTOR_UNIT			4
-#define UVC_DT_PROCESSING_UNIT			5
-#define UVC_DT_EXTENSION_UNIT			6
-
-#define UVC_DT_HEADER_SIZE(n)			(12+(n))
-#define UVC_DT_INPUT_TERMINAL_SIZE		8
-#define UVC_DT_OUTPUT_TERMINAL_SIZE		9
-#define UVC_DT_CAMERA_TERMINAL_SIZE(n)		(15+(n))
-#define UVC_DT_SELECTOR_UNIT_SIZE(n)		(6+(n))
-#define UVC_DT_PROCESSING_UNIT_SIZE(n)		(9+(n))
-#define UVC_DT_EXTENSION_UNIT_SIZE(p,n)		(24+(p)+(n))
-#define UVC_DT_CONTROL_ENDPOINT_SIZE		5
-
-struct uvc_input_header_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u8  bNumFormats;
-	__u16 wTotalLength;
-	__u8  bEndpointAddress;
-	__u8  bmInfo;
-	__u8  bTerminalLink;
-	__u8  bStillCaptureMethod;
-	__u8  bTriggerSupport;
-	__u8  bTriggerUsage;
-	__u8  bControlSize;
-	__u8  bmaControls[];
-} __attribute__((__packed__));
-
-#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
-	uvc_input_header_descriptor_##n_##p
-
-#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p)		\
-struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) {			\
-	__u8  bLength;						\
-	__u8  bDescriptorType;					\
-	__u8  bDescriptorSubType;				\
-	__u8  bNumFormats;					\
-	__u16 wTotalLength;					\
-	__u8  bEndpointAddress;					\
-	__u8  bmInfo;						\
-	__u8  bTerminalLink;					\
-	__u8  bStillCaptureMethod;				\
-	__u8  bTriggerSupport;					\
-	__u8  bTriggerUsage;					\
-	__u8  bControlSize;					\
-	__u8  bmaControls[p][n];				\
-} __attribute__ ((packed))
-
-struct uvc_output_header_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u8  bNumFormats;
-	__u16 wTotalLength;
-	__u8  bEndpointAddress;
-	__u8  bTerminalLink;
-	__u8  bControlSize;
-	__u8  bmaControls[];
-} __attribute__((__packed__));
-
-#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
-	uvc_output_header_descriptor_##n_##p
-
-#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p)		\
-struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) {			\
-	__u8  bLength;						\
-	__u8  bDescriptorType;					\
-	__u8  bDescriptorSubType;				\
-	__u8  bNumFormats;					\
-	__u16 wTotalLength;					\
-	__u8  bEndpointAddress;					\
-	__u8  bTerminalLink;					\
-	__u8  bControlSize;					\
-	__u8  bmaControls[p][n];				\
-} __attribute__ ((packed))
-
-struct uvc_format_uncompressed {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u8  bFormatIndex;
-	__u8  bNumFrameDescriptors;
-	__u8  guidFormat[16];
-	__u8  bBitsPerPixel;
-	__u8  bDefaultFrameIndex;
-	__u8  bAspectRatioX;
-	__u8  bAspectRatioY;
-	__u8  bmInterfaceFlags;
-	__u8  bCopyProtect;
-} __attribute__((__packed__));
-
-struct uvc_frame_uncompressed {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u8  bFrameIndex;
-	__u8  bmCapabilities;
-	__u16 wWidth;
-	__u16 wHeight;
-	__u32 dwMinBitRate;
-	__u32 dwMaxBitRate;
-	__u32 dwMaxVideoFrameBufferSize;
-	__u32 dwDefaultFrameInterval;
-	__u8  bFrameIntervalType;
-	__u32 dwFrameInterval[];
-} __attribute__((__packed__));
-
-#define UVC_FRAME_UNCOMPRESSED(n) \
-	uvc_frame_uncompressed_##n
-
-#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) 			\
-struct UVC_FRAME_UNCOMPRESSED(n) {				\
-	__u8  bLength;						\
-	__u8  bDescriptorType;					\
-	__u8  bDescriptorSubType;				\
-	__u8  bFrameIndex;					\
-	__u8  bmCapabilities;					\
-	__u16 wWidth;						\
-	__u16 wHeight;						\
-	__u32 dwMinBitRate;					\
-	__u32 dwMaxBitRate;					\
-	__u32 dwMaxVideoFrameBufferSize;			\
-	__u32 dwDefaultFrameInterval;				\
-	__u8  bFrameIntervalType;				\
-	__u32 dwFrameInterval[n];				\
-} __attribute__ ((packed))
-
-struct uvc_format_mjpeg {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u8  bFormatIndex;
-	__u8  bNumFrameDescriptors;
-	__u8  bmFlags;
-	__u8  bDefaultFrameIndex;
-	__u8  bAspectRatioX;
-	__u8  bAspectRatioY;
-	__u8  bmInterfaceFlags;
-	__u8  bCopyProtect;
-} __attribute__((__packed__));
-
-struct uvc_frame_mjpeg {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u8  bFrameIndex;
-	__u8  bmCapabilities;
-	__u16 wWidth;
-	__u16 wHeight;
-	__u32 dwMinBitRate;
-	__u32 dwMaxBitRate;
-	__u32 dwMaxVideoFrameBufferSize;
-	__u32 dwDefaultFrameInterval;
-	__u8  bFrameIntervalType;
-	__u32 dwFrameInterval[];
-} __attribute__((__packed__));
-
-#define UVC_FRAME_MJPEG(n) \
-	uvc_frame_mjpeg_##n
-
-#define DECLARE_UVC_FRAME_MJPEG(n) 				\
-struct UVC_FRAME_MJPEG(n) {					\
-	__u8  bLength;						\
-	__u8  bDescriptorType;					\
-	__u8  bDescriptorSubType;				\
-	__u8  bFrameIndex;					\
-	__u8  bmCapabilities;					\
-	__u16 wWidth;						\
-	__u16 wHeight;						\
-	__u32 dwMinBitRate;					\
-	__u32 dwMaxBitRate;					\
-	__u32 dwMaxVideoFrameBufferSize;			\
-	__u32 dwDefaultFrameInterval;				\
-	__u8  bFrameIntervalType;				\
-	__u32 dwFrameInterval[n];				\
-} __attribute__ ((packed))
-
-struct uvc_color_matching_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bDescriptorSubType;
-	__u8  bColorPrimaries;
-	__u8  bTransferCharacteristics;
-	__u8  bMatrixCoefficients;
-} __attribute__((__packed__));
-
-#define UVC_DT_INPUT_HEADER			1
-#define UVC_DT_OUTPUT_HEADER			2
-#define UVC_DT_FORMAT_UNCOMPRESSED		4
-#define UVC_DT_FRAME_UNCOMPRESSED		5
-#define UVC_DT_FORMAT_MJPEG			6
-#define UVC_DT_FRAME_MJPEG			7
-#define UVC_DT_COLOR_MATCHING			13
-
-#define UVC_DT_INPUT_HEADER_SIZE(n, p)		(13+(n*p))
-#define UVC_DT_OUTPUT_HEADER_SIZE(n, p)		(9+(n*p))
-#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE		27
-#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n)	(26+4*(n))
-#define UVC_DT_FORMAT_MJPEG_SIZE		11
-#define UVC_DT_FRAME_MJPEG_SIZE(n)		(26+4*(n))
-#define UVC_DT_COLOR_MATCHING_SIZE		6
+#include <linux/usb/video.h>
 
 extern int uvc_bind_config(struct usb_configuration *c,
 			   const struct uvc_descriptor_header * const *control,
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 5c0d06c..020fa5a 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -171,7 +171,8 @@
 	int			i, count;
 	rndis_query_cmplt_type	*resp;
 	struct net_device	*net;
-	const struct net_device_stats	*stats;
+	struct rtnl_link_stats64 temp;
+	const struct rtnl_link_stats64 *stats;
 
 	if (!r) return -ENOMEM;
 	resp = (rndis_query_cmplt_type *) r->buf;
@@ -194,7 +195,7 @@
 	resp->InformationBufferOffset = cpu_to_le32 (16);
 
 	net = rndis_per_dev_params[configNr].dev;
-	stats = dev_get_stats(net);
+	stats = dev_get_stats(net, &temp);
 
 	switch (OID) {
 
diff --git a/drivers/usb/gadget/uvc.h b/drivers/usb/gadget/uvc.h
index e92454c..5b79194 100644
--- a/drivers/usb/gadget/uvc.h
+++ b/drivers/usb/gadget/uvc.h
@@ -48,39 +48,6 @@
 #define UVC_INTF_STREAMING		1
 
 /* ------------------------------------------------------------------------
- * UVC constants & structures
- */
-
-/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
-#define UVC_STREAM_EOH				(1 << 7)
-#define UVC_STREAM_ERR				(1 << 6)
-#define UVC_STREAM_STI				(1 << 5)
-#define UVC_STREAM_RES				(1 << 4)
-#define UVC_STREAM_SCR				(1 << 3)
-#define UVC_STREAM_PTS				(1 << 2)
-#define UVC_STREAM_EOF				(1 << 1)
-#define UVC_STREAM_FID				(1 << 0)
-
-struct uvc_streaming_control {
-	__u16 bmHint;
-	__u8  bFormatIndex;
-	__u8  bFrameIndex;
-	__u32 dwFrameInterval;
-	__u16 wKeyFrameRate;
-	__u16 wPFrameRate;
-	__u16 wCompQuality;
-	__u16 wCompWindowSize;
-	__u16 wDelay;
-	__u32 dwMaxVideoFrameSize;
-	__u32 dwMaxPayloadTransferSize;
-	__u32 dwClockFrequency;
-	__u8  bmFramingInfo;
-	__u8  bPreferedVersion;
-	__u8  bMinVersion;
-	__u8  bMaxVersion;
-} __attribute__((__packed__));
-
-/* ------------------------------------------------------------------------
  * Debugging, printing and logging
  */
 
@@ -137,9 +104,6 @@
 #define UVC_MAX_REQUEST_SIZE			64
 #define UVC_MAX_EVENTS				4
 
-#define USB_DT_INTERFACE_ASSOCIATION_SIZE	8
-#define USB_CLASS_MISC				0xef
-
 /* ------------------------------------------------------------------------
  * Structures
  */
diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c
index f5f3030..288d211 100644
--- a/drivers/usb/gadget/webcam.c
+++ b/drivers/usb/gadget/webcam.c
@@ -90,7 +90,7 @@
 static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
 	.bLength		= UVC_DT_HEADER_SIZE(1),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubType	= UVC_DT_HEADER,
+	.bDescriptorSubType	= UVC_VC_HEADER,
 	.bcdUVC			= cpu_to_le16(0x0100),
 	.wTotalLength		= 0, /* dynamic */
 	.dwClockFrequency	= cpu_to_le32(48000000),
@@ -101,7 +101,7 @@
 static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
 	.bLength		= UVC_DT_CAMERA_TERMINAL_SIZE(3),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubType	= UVC_DT_INPUT_TERMINAL,
+	.bDescriptorSubType	= UVC_VC_INPUT_TERMINAL,
 	.bTerminalID		= 1,
 	.wTerminalType		= cpu_to_le16(0x0201),
 	.bAssocTerminal		= 0,
@@ -118,7 +118,7 @@
 static const struct uvc_processing_unit_descriptor uvc_processing = {
 	.bLength		= UVC_DT_PROCESSING_UNIT_SIZE(2),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubType	= UVC_DT_PROCESSING_UNIT,
+	.bDescriptorSubType	= UVC_VC_PROCESSING_UNIT,
 	.bUnitID		= 2,
 	.bSourceID		= 1,
 	.wMaxMultiplier		= cpu_to_le16(16*1024),
@@ -131,7 +131,7 @@
 static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
 	.bLength		= UVC_DT_OUTPUT_TERMINAL_SIZE,
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubType	= UVC_DT_OUTPUT_TERMINAL,
+	.bDescriptorSubType	= UVC_VC_OUTPUT_TERMINAL,
 	.bTerminalID		= 3,
 	.wTerminalType		= cpu_to_le16(0x0101),
 	.bAssocTerminal		= 0,
@@ -144,7 +144,7 @@
 static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
 	.bLength		= UVC_DT_INPUT_HEADER_SIZE(1, 2),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubType	= UVC_DT_INPUT_HEADER,
+	.bDescriptorSubType	= UVC_VS_INPUT_HEADER,
 	.bNumFormats		= 2,
 	.wTotalLength		= 0, /* dynamic */
 	.bEndpointAddress	= 0, /* dynamic */
@@ -161,7 +161,7 @@
 static const struct uvc_format_uncompressed uvc_format_yuv = {
 	.bLength		= UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubType	= UVC_DT_FORMAT_UNCOMPRESSED,
+	.bDescriptorSubType	= UVC_VS_FORMAT_UNCOMPRESSED,
 	.bFormatIndex		= 1,
 	.bNumFrameDescriptors	= 2,
 	.guidFormat		=
@@ -181,7 +181,7 @@
 static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
 	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubType	= UVC_DT_FRAME_UNCOMPRESSED,
+	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
 	.bFrameIndex		= 1,
 	.bmCapabilities		= 0,
 	.wWidth			= cpu_to_le16(640),
@@ -199,7 +199,7 @@
 static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
 	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubType	= UVC_DT_FRAME_UNCOMPRESSED,
+	.bDescriptorSubType	= UVC_VS_FRAME_UNCOMPRESSED,
 	.bFrameIndex		= 2,
 	.bmCapabilities		= 0,
 	.wWidth			= cpu_to_le16(1280),
@@ -215,7 +215,7 @@
 static const struct uvc_format_mjpeg uvc_format_mjpg = {
 	.bLength		= UVC_DT_FORMAT_MJPEG_SIZE,
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubType	= UVC_DT_FORMAT_MJPEG,
+	.bDescriptorSubType	= UVC_VS_FORMAT_MJPEG,
 	.bFormatIndex		= 2,
 	.bNumFrameDescriptors	= 2,
 	.bmFlags		= 0,
@@ -232,7 +232,7 @@
 static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
 	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(3),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubType	= UVC_DT_FRAME_MJPEG,
+	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
 	.bFrameIndex		= 1,
 	.bmCapabilities		= 0,
 	.wWidth			= cpu_to_le16(640),
@@ -250,7 +250,7 @@
 static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
 	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubType	= UVC_DT_FRAME_MJPEG,
+	.bDescriptorSubType	= UVC_VS_FRAME_MJPEG,
 	.bFrameIndex		= 2,
 	.bmCapabilities		= 0,
 	.wWidth			= cpu_to_le16(1280),
@@ -266,7 +266,7 @@
 static const struct uvc_color_matching_descriptor uvc_color_matching = {
 	.bLength		= UVC_DT_COLOR_MATCHING_SIZE,
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
-	.bDescriptorSubType	= UVC_DT_COLOR_MATCHING,
+	.bDescriptorSubType	= UVC_VS_COLORFORMAT,
 	.bColorPrimaries	= 1,
 	.bTransferCharacteristics	= 1,
 	.bMatrixCoefficients	= 4,
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index d219070..29e850a 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -74,6 +74,22 @@
 	}
 	return seg;
 }
+/* Copy iovec entries for len bytes from iovec. */
+static void copy_iovec_hdr(const struct iovec *from, struct iovec *to,
+			   size_t len, int iovcount)
+{
+	int seg = 0;
+	size_t size;
+	while (len && seg < iovcount) {
+		size = min(from->iov_len, len);
+		to->iov_base = from->iov_base;
+		to->iov_len = size;
+		len -= size;
+		++from;
+		++to;
+		++seg;
+	}
+}
 
 /* Caller must have TX VQ lock */
 static void tx_poll_stop(struct vhost_net *net)
@@ -129,7 +145,7 @@
 
 	if (wmem < sock->sk->sk_sndbuf / 2)
 		tx_poll_stop(net);
-	hdr_size = vq->hdr_size;
+	hdr_size = vq->vhost_hlen;
 
 	for (;;) {
 		head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
@@ -172,7 +188,7 @@
 		/* TODO: Check specific error and bomb out unless ENOBUFS? */
 		err = sock->ops->sendmsg(NULL, sock, &msg, len);
 		if (unlikely(err < 0)) {
-			vhost_discard_vq_desc(vq);
+			vhost_discard_vq_desc(vq, 1);
 			tx_poll_start(net, sock);
 			break;
 		}
@@ -191,9 +207,82 @@
 	unuse_mm(net->dev.mm);
 }
 
+static int peek_head_len(struct sock *sk)
+{
+	struct sk_buff *head;
+	int len = 0;
+
+	lock_sock(sk);
+	head = skb_peek(&sk->sk_receive_queue);
+	if (head)
+		len = head->len;
+	release_sock(sk);
+	return len;
+}
+
+/* This is a multi-buffer version of vhost_get_desc, that works if
+ *	vq has read descriptors only.
+ * @vq		- the relevant virtqueue
+ * @datalen	- data length we'll be reading
+ * @iovcount	- returned count of io vectors we fill
+ * @log		- vhost log
+ * @log_num	- log offset
+ *	returns number of buffer heads allocated, negative on error
+ */
+static int get_rx_bufs(struct vhost_virtqueue *vq,
+		       struct vring_used_elem *heads,
+		       int datalen,
+		       unsigned *iovcount,
+		       struct vhost_log *log,
+		       unsigned *log_num)
+{
+	unsigned int out, in;
+	int seg = 0;
+	int headcount = 0;
+	unsigned d;
+	int r, nlogs = 0;
+
+	while (datalen > 0) {
+		if (unlikely(headcount >= VHOST_NET_MAX_SG)) {
+			r = -ENOBUFS;
+			goto err;
+		}
+		d = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
+				      ARRAY_SIZE(vq->iov) - seg, &out,
+				      &in, log, log_num);
+		if (d == vq->num) {
+			r = 0;
+			goto err;
+		}
+		if (unlikely(out || in <= 0)) {
+			vq_err(vq, "unexpected descriptor format for RX: "
+				"out %d, in %d\n", out, in);
+			r = -EINVAL;
+			goto err;
+		}
+		if (unlikely(log)) {
+			nlogs += *log_num;
+			log += *log_num;
+		}
+		heads[headcount].id = d;
+		heads[headcount].len = iov_length(vq->iov + seg, in);
+		datalen -= heads[headcount].len;
+		++headcount;
+		seg += in;
+	}
+	heads[headcount - 1].len += datalen;
+	*iovcount = seg;
+	if (unlikely(log))
+		*log_num = nlogs;
+	return headcount;
+err:
+	vhost_discard_vq_desc(vq, headcount);
+	return r;
+}
+
 /* Expects to be always run from workqueue - which acts as
  * read-size critical section for our kind of RCU. */
-static void handle_rx(struct vhost_net *net)
+static void handle_rx_big(struct vhost_net *net)
 {
 	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
 	unsigned out, in, log, s;
@@ -223,7 +312,7 @@
 	use_mm(net->dev.mm);
 	mutex_lock(&vq->mutex);
 	vhost_disable_notify(vq);
-	hdr_size = vq->hdr_size;
+	hdr_size = vq->vhost_hlen;
 
 	vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
 		vq->log : NULL;
@@ -270,14 +359,14 @@
 					 len, MSG_DONTWAIT | MSG_TRUNC);
 		/* TODO: Check specific error and bomb out unless EAGAIN? */
 		if (err < 0) {
-			vhost_discard_vq_desc(vq);
+			vhost_discard_vq_desc(vq, 1);
 			break;
 		}
 		/* TODO: Should check and handle checksum. */
 		if (err > len) {
 			pr_debug("Discarded truncated rx packet: "
 				 " len %d > %zd\n", err, len);
-			vhost_discard_vq_desc(vq);
+			vhost_discard_vq_desc(vq, 1);
 			continue;
 		}
 		len = err;
@@ -302,54 +391,175 @@
 	unuse_mm(net->dev.mm);
 }
 
-static void handle_tx_kick(struct work_struct *work)
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_rx_mergeable(struct vhost_net *net)
 {
-	struct vhost_virtqueue *vq;
-	struct vhost_net *net;
-	vq = container_of(work, struct vhost_virtqueue, poll.work);
-	net = container_of(vq->dev, struct vhost_net, dev);
+	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
+	unsigned uninitialized_var(in), log;
+	struct vhost_log *vq_log;
+	struct msghdr msg = {
+		.msg_name = NULL,
+		.msg_namelen = 0,
+		.msg_control = NULL, /* FIXME: get and handle RX aux data. */
+		.msg_controllen = 0,
+		.msg_iov = vq->iov,
+		.msg_flags = MSG_DONTWAIT,
+	};
+
+	struct virtio_net_hdr_mrg_rxbuf hdr = {
+		.hdr.flags = 0,
+		.hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
+	};
+
+	size_t total_len = 0;
+	int err, headcount;
+	size_t vhost_hlen, sock_hlen;
+	size_t vhost_len, sock_len;
+	struct socket *sock = rcu_dereference(vq->private_data);
+	if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+		return;
+
+	use_mm(net->dev.mm);
+	mutex_lock(&vq->mutex);
+	vhost_disable_notify(vq);
+	vhost_hlen = vq->vhost_hlen;
+	sock_hlen = vq->sock_hlen;
+
+	vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
+		vq->log : NULL;
+
+	while ((sock_len = peek_head_len(sock->sk))) {
+		sock_len += sock_hlen;
+		vhost_len = sock_len + vhost_hlen;
+		headcount = get_rx_bufs(vq, vq->heads, vhost_len,
+					&in, vq_log, &log);
+		/* On error, stop handling until the next kick. */
+		if (unlikely(headcount < 0))
+			break;
+		/* OK, now we need to know about added descriptors. */
+		if (!headcount) {
+			if (unlikely(vhost_enable_notify(vq))) {
+				/* They have slipped one in as we were
+				 * doing that: check again. */
+				vhost_disable_notify(vq);
+				continue;
+			}
+			/* Nothing new?  Wait for eventfd to tell us
+			 * they refilled. */
+			break;
+		}
+		/* We don't need to be notified again. */
+		if (unlikely((vhost_hlen)))
+			/* Skip header. TODO: support TSO. */
+			move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, in);
+		else
+			/* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF:
+			 * needed because sendmsg can modify msg_iov. */
+			copy_iovec_hdr(vq->iov, vq->hdr, sock_hlen, in);
+		msg.msg_iovlen = in;
+		err = sock->ops->recvmsg(NULL, sock, &msg,
+					 sock_len, MSG_DONTWAIT | MSG_TRUNC);
+		/* Userspace might have consumed the packet meanwhile:
+		 * it's not supposed to do this usually, but might be hard
+		 * to prevent. Discard data we got (if any) and keep going. */
+		if (unlikely(err != sock_len)) {
+			pr_debug("Discarded rx packet: "
+				 " len %d, expected %zd\n", err, sock_len);
+			vhost_discard_vq_desc(vq, headcount);
+			continue;
+		}
+		if (unlikely(vhost_hlen) &&
+		    memcpy_toiovecend(vq->hdr, (unsigned char *)&hdr, 0,
+				      vhost_hlen)) {
+			vq_err(vq, "Unable to write vnet_hdr at addr %p\n",
+			       vq->iov->iov_base);
+			break;
+		}
+		/* TODO: Should check and handle checksum. */
+		if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF) &&
+		    memcpy_toiovecend(vq->hdr, (unsigned char *)&headcount,
+				      offsetof(typeof(hdr), num_buffers),
+				      sizeof hdr.num_buffers)) {
+			vq_err(vq, "Failed num_buffers write");
+			vhost_discard_vq_desc(vq, headcount);
+			break;
+		}
+		vhost_add_used_and_signal_n(&net->dev, vq, vq->heads,
+					    headcount);
+		if (unlikely(vq_log))
+			vhost_log_write(vq, vq_log, log, vhost_len);
+		total_len += vhost_len;
+		if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
+			vhost_poll_queue(&vq->poll);
+			break;
+		}
+	}
+
+	mutex_unlock(&vq->mutex);
+	unuse_mm(net->dev.mm);
+}
+
+static void handle_rx(struct vhost_net *net)
+{
+	if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF))
+		handle_rx_mergeable(net);
+	else
+		handle_rx_big(net);
+}
+
+static void handle_tx_kick(struct vhost_work *work)
+{
+	struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
+						  poll.work);
+	struct vhost_net *net = container_of(vq->dev, struct vhost_net, dev);
+
 	handle_tx(net);
 }
 
-static void handle_rx_kick(struct work_struct *work)
+static void handle_rx_kick(struct vhost_work *work)
 {
-	struct vhost_virtqueue *vq;
-	struct vhost_net *net;
-	vq = container_of(work, struct vhost_virtqueue, poll.work);
-	net = container_of(vq->dev, struct vhost_net, dev);
+	struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
+						  poll.work);
+	struct vhost_net *net = container_of(vq->dev, struct vhost_net, dev);
+
 	handle_rx(net);
 }
 
-static void handle_tx_net(struct work_struct *work)
+static void handle_tx_net(struct vhost_work *work)
 {
-	struct vhost_net *net;
-	net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_TX].work);
+	struct vhost_net *net = container_of(work, struct vhost_net,
+					     poll[VHOST_NET_VQ_TX].work);
 	handle_tx(net);
 }
 
-static void handle_rx_net(struct work_struct *work)
+static void handle_rx_net(struct vhost_work *work)
 {
-	struct vhost_net *net;
-	net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_RX].work);
+	struct vhost_net *net = container_of(work, struct vhost_net,
+					     poll[VHOST_NET_VQ_RX].work);
 	handle_rx(net);
 }
 
 static int vhost_net_open(struct inode *inode, struct file *f)
 {
 	struct vhost_net *n = kmalloc(sizeof *n, GFP_KERNEL);
+	struct vhost_dev *dev;
 	int r;
+
 	if (!n)
 		return -ENOMEM;
+
+	dev = &n->dev;
 	n->vqs[VHOST_NET_VQ_TX].handle_kick = handle_tx_kick;
 	n->vqs[VHOST_NET_VQ_RX].handle_kick = handle_rx_kick;
-	r = vhost_dev_init(&n->dev, n->vqs, VHOST_NET_VQ_MAX);
+	r = vhost_dev_init(dev, n->vqs, VHOST_NET_VQ_MAX);
 	if (r < 0) {
 		kfree(n);
 		return r;
 	}
 
-	vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT);
-	vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN);
+	vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT, dev);
+	vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN, dev);
 	n->tx_poll_state = VHOST_NET_POLL_DISABLED;
 
 	f->private_data = n;
@@ -527,13 +737,12 @@
 
 	/* start polling new socket */
 	oldsock = vq->private_data;
-	if (sock == oldsock)
-		goto done;
+	if (sock != oldsock) {
+                vhost_net_disable_vq(n, vq);
+                rcu_assign_pointer(vq->private_data, sock);
+                vhost_net_enable_vq(n, vq);
+	}
 
-	vhost_net_disable_vq(n, vq);
-	rcu_assign_pointer(vq->private_data, sock);
-	vhost_net_enable_vq(n, vq);
-done:
 	mutex_unlock(&vq->mutex);
 
 	if (oldsock) {
@@ -574,9 +783,21 @@
 
 static int vhost_net_set_features(struct vhost_net *n, u64 features)
 {
-	size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
-		sizeof(struct virtio_net_hdr) : 0;
+	size_t vhost_hlen, sock_hlen, hdr_len;
 	int i;
+
+	hdr_len = (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) ?
+			sizeof(struct virtio_net_hdr_mrg_rxbuf) :
+			sizeof(struct virtio_net_hdr);
+	if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR)) {
+		/* vhost provides vnet_hdr */
+		vhost_hlen = hdr_len;
+		sock_hlen = 0;
+	} else {
+		/* socket provides vnet_hdr */
+		vhost_hlen = 0;
+		sock_hlen = hdr_len;
+	}
 	mutex_lock(&n->dev.mutex);
 	if ((features & (1 << VHOST_F_LOG_ALL)) &&
 	    !vhost_log_access_ok(&n->dev)) {
@@ -587,7 +808,8 @@
 	smp_wmb();
 	for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
 		mutex_lock(&n->vqs[i].mutex);
-		n->vqs[i].hdr_size = hdr_size;
+		n->vqs[i].vhost_hlen = vhost_hlen;
+		n->vqs[i].sock_hlen = sock_hlen;
 		mutex_unlock(&n->vqs[i].mutex);
 	}
 	vhost_net_flush(n);
@@ -639,7 +861,7 @@
 }
 #endif
 
-const static struct file_operations vhost_net_fops = {
+static const struct file_operations vhost_net_fops = {
 	.owner          = THIS_MODULE,
 	.release        = vhost_net_release,
 	.unlocked_ioctl = vhost_net_ioctl,
@@ -657,25 +879,13 @@
 
 static int vhost_net_init(void)
 {
-	int r = vhost_init();
-	if (r)
-		goto err_init;
-	r = misc_register(&vhost_net_misc);
-	if (r)
-		goto err_reg;
-	return 0;
-err_reg:
-	vhost_cleanup();
-err_init:
-	return r;
-
+	return misc_register(&vhost_net_misc);
 }
 module_init(vhost_net_init);
 
 static void vhost_net_exit(void)
 {
 	misc_deregister(&vhost_net_misc);
-	vhost_cleanup();
 }
 module_exit(vhost_net_exit);
 
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 0b99783..e05557d 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -17,12 +17,13 @@
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
 #include <linux/mutex.h>
-#include <linux/workqueue.h>
 #include <linux/rcupdate.h>
 #include <linux/poll.h>
 #include <linux/file.h>
 #include <linux/highmem.h>
 #include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/cgroup.h>
 
 #include <linux/net.h>
 #include <linux/if_packet.h>
@@ -37,8 +38,6 @@
 	VHOST_MEMORY_F_LOG = 0x1,
 };
 
-static struct workqueue_struct *vhost_workqueue;
-
 static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
 			    poll_table *pt)
 {
@@ -52,23 +51,31 @@
 static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync,
 			     void *key)
 {
-	struct vhost_poll *poll;
-	poll = container_of(wait, struct vhost_poll, wait);
+	struct vhost_poll *poll = container_of(wait, struct vhost_poll, wait);
+
 	if (!((unsigned long)key & poll->mask))
 		return 0;
 
-	queue_work(vhost_workqueue, &poll->work);
+	vhost_poll_queue(poll);
 	return 0;
 }
 
 /* Init poll structure */
-void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
-		     unsigned long mask)
+void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn,
+		     unsigned long mask, struct vhost_dev *dev)
 {
-	INIT_WORK(&poll->work, func);
+	struct vhost_work *work = &poll->work;
+
 	init_waitqueue_func_entry(&poll->wait, vhost_poll_wakeup);
 	init_poll_funcptr(&poll->table, vhost_poll_func);
 	poll->mask = mask;
+	poll->dev = dev;
+
+	INIT_LIST_HEAD(&work->node);
+	work->fn = fn;
+	init_waitqueue_head(&work->done);
+	work->flushing = 0;
+	work->queue_seq = work->done_seq = 0;
 }
 
 /* Start polling a file. We add ourselves to file's wait queue. The caller must
@@ -92,12 +99,40 @@
  * locks that are also used by the callback. */
 void vhost_poll_flush(struct vhost_poll *poll)
 {
-	flush_work(&poll->work);
+	struct vhost_work *work = &poll->work;
+	unsigned seq;
+	int left;
+	int flushing;
+
+	spin_lock_irq(&poll->dev->work_lock);
+	seq = work->queue_seq;
+	work->flushing++;
+	spin_unlock_irq(&poll->dev->work_lock);
+	wait_event(work->done, ({
+		   spin_lock_irq(&poll->dev->work_lock);
+		   left = seq - work->done_seq <= 0;
+		   spin_unlock_irq(&poll->dev->work_lock);
+		   left;
+	}));
+	spin_lock_irq(&poll->dev->work_lock);
+	flushing = --work->flushing;
+	spin_unlock_irq(&poll->dev->work_lock);
+	BUG_ON(flushing < 0);
 }
 
 void vhost_poll_queue(struct vhost_poll *poll)
 {
-	queue_work(vhost_workqueue, &poll->work);
+	struct vhost_dev *dev = poll->dev;
+	struct vhost_work *work = &poll->work;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->work_lock, flags);
+	if (list_empty(&work->node)) {
+		list_add_tail(&work->node, &dev->work_list);
+		work->queue_seq++;
+		wake_up_process(dev->worker);
+	}
+	spin_unlock_irqrestore(&dev->work_lock, flags);
 }
 
 static void vhost_vq_reset(struct vhost_dev *dev,
@@ -114,7 +149,8 @@
 	vq->used_flags = 0;
 	vq->log_used = false;
 	vq->log_addr = -1ull;
-	vq->hdr_size = 0;
+	vq->vhost_hlen = 0;
+	vq->sock_hlen = 0;
 	vq->private_data = NULL;
 	vq->log_base = NULL;
 	vq->error_ctx = NULL;
@@ -125,10 +161,51 @@
 	vq->log_ctx = NULL;
 }
 
+static int vhost_worker(void *data)
+{
+	struct vhost_dev *dev = data;
+	struct vhost_work *work = NULL;
+	unsigned uninitialized_var(seq);
+
+	for (;;) {
+		/* mb paired w/ kthread_stop */
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irq(&dev->work_lock);
+		if (work) {
+			work->done_seq = seq;
+			if (work->flushing)
+				wake_up_all(&work->done);
+		}
+
+		if (kthread_should_stop()) {
+			spin_unlock_irq(&dev->work_lock);
+			__set_current_state(TASK_RUNNING);
+			return 0;
+		}
+		if (!list_empty(&dev->work_list)) {
+			work = list_first_entry(&dev->work_list,
+						struct vhost_work, node);
+			list_del_init(&work->node);
+			seq = work->queue_seq;
+		} else
+			work = NULL;
+		spin_unlock_irq(&dev->work_lock);
+
+		if (work) {
+			__set_current_state(TASK_RUNNING);
+			work->fn(work);
+		} else
+			schedule();
+
+	}
+}
+
 long vhost_dev_init(struct vhost_dev *dev,
 		    struct vhost_virtqueue *vqs, int nvqs)
 {
 	int i;
+
 	dev->vqs = vqs;
 	dev->nvqs = nvqs;
 	mutex_init(&dev->mutex);
@@ -136,6 +213,9 @@
 	dev->log_file = NULL;
 	dev->memory = NULL;
 	dev->mm = NULL;
+	spin_lock_init(&dev->work_lock);
+	INIT_LIST_HEAD(&dev->work_list);
+	dev->worker = NULL;
 
 	for (i = 0; i < dev->nvqs; ++i) {
 		dev->vqs[i].dev = dev;
@@ -143,9 +223,9 @@
 		vhost_vq_reset(dev, dev->vqs + i);
 		if (dev->vqs[i].handle_kick)
 			vhost_poll_init(&dev->vqs[i].poll,
-					dev->vqs[i].handle_kick,
-					POLLIN);
+					dev->vqs[i].handle_kick, POLLIN, dev);
 	}
+
 	return 0;
 }
 
@@ -159,12 +239,36 @@
 /* Caller should have device mutex */
 static long vhost_dev_set_owner(struct vhost_dev *dev)
 {
+	struct task_struct *worker;
+	int err;
 	/* Is there an owner already? */
-	if (dev->mm)
-		return -EBUSY;
+	if (dev->mm) {
+		err = -EBUSY;
+		goto err_mm;
+	}
 	/* No owner, become one */
 	dev->mm = get_task_mm(current);
+	worker = kthread_create(vhost_worker, dev, "vhost-%d", current->pid);
+	if (IS_ERR(worker)) {
+		err = PTR_ERR(worker);
+		goto err_worker;
+	}
+
+	dev->worker = worker;
+	err = cgroup_attach_task_current_cg(worker);
+	if (err)
+		goto err_cgroup;
+	wake_up_process(worker);	/* avoid contributing to loadavg */
+
 	return 0;
+err_cgroup:
+	kthread_stop(worker);
+err_worker:
+	if (dev->mm)
+		mmput(dev->mm);
+	dev->mm = NULL;
+err_mm:
+	return err;
 }
 
 /* Caller should have device mutex */
@@ -217,6 +321,9 @@
 	if (dev->mm)
 		mmput(dev->mm);
 	dev->mm = NULL;
+
+	WARN_ON(!list_empty(&dev->work_list));
+	kthread_stop(dev->worker);
 }
 
 static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
@@ -237,8 +344,8 @@
 {
 	int i;
 
-        if (!mem)
-                return 0;
+	if (!mem)
+		return 0;
 
 	for (i = 0; i < mem->nregions; ++i) {
 		struct vhost_memory_region *m = mem->regions + i;
@@ -995,9 +1102,9 @@
 }
 
 /* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
-void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+void vhost_discard_vq_desc(struct vhost_virtqueue *vq, int n)
 {
-	vq->last_avail_idx--;
+	vq->last_avail_idx -= n;
 }
 
 /* After we've used one of their buffers, we tell them about it.  We'll then
@@ -1042,6 +1149,67 @@
 	return 0;
 }
 
+static int __vhost_add_used_n(struct vhost_virtqueue *vq,
+			    struct vring_used_elem *heads,
+			    unsigned count)
+{
+	struct vring_used_elem __user *used;
+	int start;
+
+	start = vq->last_used_idx % vq->num;
+	used = vq->used->ring + start;
+	if (copy_to_user(used, heads, count * sizeof *used)) {
+		vq_err(vq, "Failed to write used");
+		return -EFAULT;
+	}
+	if (unlikely(vq->log_used)) {
+		/* Make sure data is seen before log. */
+		smp_wmb();
+		/* Log used ring entry write. */
+		log_write(vq->log_base,
+			  vq->log_addr +
+			   ((void __user *)used - (void __user *)vq->used),
+			  count * sizeof *used);
+	}
+	vq->last_used_idx += count;
+	return 0;
+}
+
+/* After we've used one of their buffers, we tell them about it.  We'll then
+ * want to notify the guest, using eventfd. */
+int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
+		     unsigned count)
+{
+	int start, n, r;
+
+	start = vq->last_used_idx % vq->num;
+	n = vq->num - start;
+	if (n < count) {
+		r = __vhost_add_used_n(vq, heads, n);
+		if (r < 0)
+			return r;
+		heads += n;
+		count -= n;
+	}
+	r = __vhost_add_used_n(vq, heads, count);
+
+	/* Make sure buffer is written before we update index. */
+	smp_wmb();
+	if (put_user(vq->last_used_idx, &vq->used->idx)) {
+		vq_err(vq, "Failed to increment used idx");
+		return -EFAULT;
+	}
+	if (unlikely(vq->log_used)) {
+		/* Log used index update. */
+		log_write(vq->log_base,
+			  vq->log_addr + offsetof(struct vring_used, idx),
+			  sizeof vq->used->idx);
+		if (vq->log_ctx)
+			eventfd_signal(vq->log_ctx, 1);
+	}
+	return r;
+}
+
 /* This actually signals the guest, using eventfd. */
 void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 {
@@ -1076,6 +1244,15 @@
 	vhost_signal(dev, vq);
 }
 
+/* multi-buffer version of vhost_add_used_and_signal */
+void vhost_add_used_and_signal_n(struct vhost_dev *dev,
+				 struct vhost_virtqueue *vq,
+				 struct vring_used_elem *heads, unsigned count)
+{
+	vhost_add_used_n(vq, heads, count);
+	vhost_signal(dev, vq);
+}
+
 /* OK, now we need to know about added descriptors. */
 bool vhost_enable_notify(struct vhost_virtqueue *vq)
 {
@@ -1100,7 +1277,7 @@
 		return false;
 	}
 
-	return avail_idx != vq->last_avail_idx;
+	return avail_idx != vq->avail_idx;
 }
 
 /* We don't need to be notified again. */
@@ -1115,16 +1292,3 @@
 		vq_err(vq, "Failed to enable notification at %p: %d\n",
 		       &vq->used->flags, r);
 }
-
-int vhost_init(void)
-{
-	vhost_workqueue = create_singlethread_workqueue("vhost");
-	if (!vhost_workqueue)
-		return -ENOMEM;
-	return 0;
-}
-
-void vhost_cleanup(void)
-{
-	destroy_workqueue(vhost_workqueue);
-}
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 11ee13d..afd7729 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -5,13 +5,13 @@
 #include <linux/vhost.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
-#include <linux/workqueue.h>
 #include <linux/poll.h>
 #include <linux/file.h>
 #include <linux/skbuff.h>
 #include <linux/uio.h>
 #include <linux/virtio_config.h>
 #include <linux/virtio_ring.h>
+#include <asm/atomic.h>
 
 struct vhost_device;
 
@@ -20,19 +20,31 @@
 	VHOST_NET_MAX_SG = MAX_SKB_FRAGS + 2,
 };
 
+struct vhost_work;
+typedef void (*vhost_work_fn_t)(struct vhost_work *work);
+
+struct vhost_work {
+	struct list_head	  node;
+	vhost_work_fn_t		  fn;
+	wait_queue_head_t	  done;
+	int			  flushing;
+	unsigned		  queue_seq;
+	unsigned		  done_seq;
+};
+
 /* Poll a file (eventfd or socket) */
 /* Note: there's nothing vhost specific about this structure. */
 struct vhost_poll {
 	poll_table                table;
 	wait_queue_head_t        *wqh;
 	wait_queue_t              wait;
-	/* struct which will handle all actual work. */
-	struct work_struct        work;
+	struct vhost_work	  work;
 	unsigned long		  mask;
+	struct vhost_dev	 *dev;
 };
 
-void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
-		     unsigned long mask);
+void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn,
+		     unsigned long mask, struct vhost_dev *dev);
 void vhost_poll_start(struct vhost_poll *poll, struct file *file);
 void vhost_poll_stop(struct vhost_poll *poll);
 void vhost_poll_flush(struct vhost_poll *poll);
@@ -63,7 +75,7 @@
 	struct vhost_poll poll;
 
 	/* The routine to call when the Guest pings us, or timeout. */
-	work_func_t handle_kick;
+	vhost_work_fn_t handle_kick;
 
 	/* Last available index we saw. */
 	u16 last_avail_idx;
@@ -84,13 +96,15 @@
 	struct iovec indirect[VHOST_NET_MAX_SG];
 	struct iovec iov[VHOST_NET_MAX_SG];
 	struct iovec hdr[VHOST_NET_MAX_SG];
-	size_t hdr_size;
+	size_t vhost_hlen;
+	size_t sock_hlen;
+	struct vring_used_elem heads[VHOST_NET_MAX_SG];
 	/* We use a kind of RCU to access private pointer.
-	 * All readers access it from workqueue, which makes it possible to
-	 * flush the workqueue instead of synchronize_rcu. Therefore readers do
+	 * All readers access it from worker, which makes it possible to
+	 * flush the vhost_work instead of synchronize_rcu. Therefore readers do
 	 * not need to call rcu_read_lock/rcu_read_unlock: the beginning of
-	 * work item execution acts instead of rcu_read_lock() and the end of
-	 * work item execution acts instead of rcu_read_lock().
+	 * vhost_work execution acts instead of rcu_read_lock() and the end of
+	 * vhost_work execution acts instead of rcu_read_lock().
 	 * Writers use virtqueue mutex. */
 	void *private_data;
 	/* Log write descriptors */
@@ -110,6 +124,9 @@
 	int nvqs;
 	struct file *log_file;
 	struct eventfd_ctx *log_ctx;
+	spinlock_t work_lock;
+	struct list_head work_list;
+	struct task_struct *worker;
 };
 
 long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs);
@@ -124,21 +141,22 @@
 		      struct iovec iov[], unsigned int iov_count,
 		      unsigned int *out_num, unsigned int *in_num,
 		      struct vhost_log *log, unsigned int *log_num);
-void vhost_discard_vq_desc(struct vhost_virtqueue *);
+void vhost_discard_vq_desc(struct vhost_virtqueue *, int n);
 
 int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
-void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
+int vhost_add_used_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
+		     unsigned count);
 void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
-			       unsigned int head, int len);
+			       unsigned int id, int len);
+void vhost_add_used_and_signal_n(struct vhost_dev *, struct vhost_virtqueue *,
+			       struct vring_used_elem *heads, unsigned count);
+void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
 void vhost_disable_notify(struct vhost_virtqueue *);
 bool vhost_enable_notify(struct vhost_virtqueue *);
 
 int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
 		    unsigned int log_num, u64 len);
 
-int vhost_init(void);
-void vhost_cleanup(void);
-
 #define vq_err(vq, fmt, ...) do {                                  \
 		pr_debug(pr_fmt(fmt), ##__VA_ARGS__);       \
 		if ((vq)->error_ctx)                               \
@@ -149,7 +167,8 @@
 	VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
 			 (1 << VIRTIO_RING_F_INDIRECT_DESC) |
 			 (1 << VHOST_F_LOG_ALL) |
-			 (1 << VHOST_NET_F_VIRTIO_NET_HDR),
+			 (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
+			 (1 << VIRTIO_NET_F_MRG_RXBUF),
 };
 
 static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
index 1f8eb70..07fbb8a 100644
--- a/drivers/video/omap2/displays/panel-acx565akm.c
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -592,7 +592,7 @@
 	r = omapdss_sdi_display_enable(dssdev);
 	if (r) {
 		pr_err("%s sdi enable failed\n", __func__);
-		return r;
+		goto fail_unlock;
 	}
 
 	/*FIXME tweak me */
@@ -633,6 +633,8 @@
 	return acx565akm_bl_update_status(md->bl_dev);
 fail:
 	omapdss_sdi_display_disable(dssdev);
+fail_unlock:
+	mutex_unlock(&md->mutex);
 	return r;
 }
 
diff --git a/firmware/Makefile b/firmware/Makefile
index 020e629..b27f09f 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -42,7 +42,7 @@
 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.4.0.bin \
+				   cxgb3/t3fw-7.10.0.bin \
 				   cxgb3/ael2005_opt_edc.bin \
 				   cxgb3/ael2005_twx_edc.bin \
 				   cxgb3/ael2020_twx_edc.bin
diff --git a/firmware/cxgb3/t3fw-7.10.0.bin.ihex b/firmware/cxgb3/t3fw-7.10.0.bin.ihex
new file mode 100644
index 0000000..96399d8
--- /dev/null
+++ b/firmware/cxgb3/t3fw-7.10.0.bin.ihex
@@ -0,0 +1,1935 @@
+:1000000060007400200380002003700000001000D6
+:1000100000002000E100028400070000E1000288E7
+:1000200000010000E0000000E00000A0010000006E
+:1000300044444440E3000183200200002001E0002A
+:100040002001FF101FFFD0001FFFC000E300043C91
+:100050000200000020006C841FFFC2A020006CCCB6
+:100060001FFFC2A420006D0C1FFFC2A820006D80DE
+:100070001FFFC2AC200003C0C00000E43100EA3121
+:1000800000A13100A03103020002ED306E2A05000C
+:10009000ED3100020002160012FFDBC03014FFDA5F
+:1000A000D30FD30FD30F03431F244C107249F0D347
+:1000B0000FD30FD30F12FFD5230A00240A00D30F4A
+:1000C000D30FD30F03431F244C107249F0D30FD327
+:1000D0000FD30F14FFCE03421F14FFCB03421F1296
+:1000E000FFCCC0302D37302D37342D37382D373CED
+:1000F000233D017233ED00020012FFC4C0302F37E0
+:10010000002F37102F37202F3730233D017233ED6A
+:1001100000020012FFBEC0302737002737102737F4
+:1001200020273730233D017233ED03020012FFB95F
+:1001300013FFBA0C0200932012FFB913FFB90C028F
+:1001400000932012FFB8C0319320822012FFB71312
+:10015000FFB7932012FFB715FFB316FFB6C030D715
+:100160002005660160001B00000000000000000088
+:10017000043605000200D30FD30F05330C6E3B1479
+:100180000747140704437631E604360505330C6F40
+:100190003BED00020012FFA615FFA3230A00D720A3
+:1001A000070443043E0505330C0747146F3BF00377
+:1001B000020012FFA1C03014FFA1D30FD30FD30F41
+:1001C0009340B4447249F2D30FD30FD30F14FF9B63
+:1001D000834014FF9B834012FF9B230A0014FF9A65
+:1001E000D30FD30FD30F9340B4447249F2D30FD33C
+:1001F0000FD30F14FF95834012FF95C92F832084DE
+:10020000218522BC22743B0F8650B4559630B433FE
+:100210007433F463FFE60000653FE1655FDE12FFC3
+:100220007C230A0028374028374428374828374C91
+: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
+:10048000E30005E01FFFC0181FFFC294E30005E072
+:100490001FFFC2941FFFC294E300085C1FFFC2A0AD
+:1004A0001FFFC59CE300085C200000002000016ADB
+:1004B000E3000B582000018020000180E3000CC401
+:1004C0002000020020000203E3000CC42000021CF4
+:1004D00020000220E3000CC8200002202000022699
+:1004E000E3000CCC2000023C20000240E3000CD4CE
+:1004F0002000024020000249E3000CD82000024CFA
+:1005000020000250E3000CE42000025020000259B9
+:10051000E3000CE82000025C20000260E3000CF421
+:100520002000026020000269E3000CF82000026C49
+:1005300020000270E3000D04200002702000027908
+:10054000E3000D082000028C2000028CE3000D1453
+:100550002000029020000293E3000D14200002AC62
+:10056000200002B0E3000D18200002D0200002F2AB
+:10057000E3000D1C200003B0200003B0E3000D4099
+:10058000200003B0200003B0E3000D40200003B0C2
+:10059000200003B0E3000D40200003B0200003B0B2
+:1005A000E3000D40200003B020006EA4E3000D40E6
+:1005B00020006EA420006EA4E30078340000000048
+:1005C00000000000000000001FFC00001FFC0000F5
+:1005D0001FFFC5A01FFFC69020006EA820006EA8B8
+:1005E000DEFFFE000000080CDEADBEEF1FFFC2B054
+:1005F0001FFCFE001FFFC0A41FFFC5D0300000007D
+:10060000003FFFFF8040000010000000080FFFFFC8
+:100610001FFFC27D000FFFFF804FFFFF8000000023
+:1006200000000880B000000560500000600000007D
+:1006300040000011350000004100000010000001E2
+:100640002000000000001000400000000500000035
+:10065000800000190400000000000800E100020012
+:1006600010000005806000007000000020000009FC
+:10067000001FF8008000001EA0000000F80000002D
+:1006800007FFFFFF080000001800000001008001C4
+:10069000420000001FFFC22D1FFFC0EC00010080C0
+:1006A000604000001A0000000C0000001000000A6A
+:1006B000000030000001000080000018FC00000075
+:1006C0008000000100004000600008008000001C65
+:1006D0008000001A030000008000040004030403EB
+:1006E00050000003FFFFBFFF1FFFC3E400000FFF28
+:1006F000FFFFF000000016D00000FFF7A50000008B
+:100700001FFFC4C01FFFC4710001000800000B20C0
+:10071000202FFF801FFFC46500002C00FFFEFFF8A4
+:1007200000FFFFFF1FFFC58800002000FFFFDFFF65
+:100730000000FFEF010011001FFFC3E21FFFC5A073
+:10074000FFFFEFFF0000FFFB1FFFC6501FFFBEB003
+:10075000FFFFF7FF1FFFC0740000FFFD1FFFC64033
+:100760000001FBD01FFFC5C01FFFC6801FFFC5A132
+:10077000E0FFFE001FFFC5B0000080001FFFC54C5A
+:100780001FFFC5C41FFFC0781FFFC4E41FFCFFD8B4
+:10079000000100817FFFFFFFE1000600000027103D
+:1007A0001FFCFE301FFCFE701FFFC5481FFFC56009
+:1007B0000003D0901FFFC5742B5063802B507980AD
+:1007C0002B5090802B50A6801FFFC4790100110F81
+:1007D000202FFE0020300080202FFF000000FFFFB0
+:1007E0000001FFF82B50B2002B50B208000100109E
+:1007F0002B50B1802B50B2802B50BA000001001159
+:100800002B50BD282B50BC802B50BDA020300000A9
+:10081000DFFFFE005000000200C0000002000000E8
+:10082000FFFFF7F41FFFC07C000FF800044000003A
+:10083000001000000C4000001C400000E00000A080
+:100840001FFFC5501FFD00081FFFC5641FFFC578AF
+:100850001FFFC58CE1000690E10006EC00000000DF
+:100860000000000000000000000000000100000087
+:100870000000000000000000000000002010004008
+:10088000201000402010004020140080200C0000A8
+:10089000200C0000200C00002010004020140080DC
+:1008A0002014008020140080201800C0201C0100AB
+:1008B000201C0100201C010020200140201800C045
+:1008C000201800C0201800C0201C0100201800C003
+:1008D000201800C0201800C0201C0100202001406A
+:1008E00020200140202001402020094020200940F4
+:1008F000202009402020094020240980FFFFFFFF1D
+:10090000FFFFFFFFFFFFFFFF0000000000000000EF
+:1009100000000000000000000000000020005588DA
+:1009200020005458200055882000558820005394FA
+:100930002000539420005394200051D4200051D41F
+:10094000200051CC2000513820004FE020004DC045
+:1009500020004B94000000000000000020005558CB
+:1009600020005424200054C8200054C82000527C89
+:100970002000527C2000527C2000527C2000527CBF
+:10098000200051C42000527C20004F0020004D70F8
+:1009900020004B40000000000000000020000BF091
+:1009A00020003ADC200004C02000473020000BE883
+:1009B000200041F4200003F0200046F020004B1CF2
+:1009C00020003F0020003E1C20003A58200038E85C
+:1009D00020003658200031B820003C7820002DD06F
+:1009E0002000286420006828200023F0200020D068
+:1009F0002000207C20001D68200018602000158841
+:100A000020000E5420000C3420001134200013204C
+:100A1000200043EC20003EB420000BF8200004C06E
+:100A200000000000000000000000000000000000C6
+:100A300000000000000000000000000000000000B6
+:100A400000000000000000000000000000000000A6
+:100A50000000000000000000000000000000000096
+:100A60000000000000000000000000000000000086
+:100A70000000000000000000000000000000000076
+:100A80000000000000000000000000000000000066
+:100A90000000000000000000000000000000000056
+:100AA0003264000000000000326400006400640052
+:100AB00064006400640064006400640000000000DE
+:100AC0000000000000000000000000000000000026
+:100AD0000000000000000000000000000000000016
+:100AE0000000000000000000000000000000000006
+:100AF00000000000000000000000000000000000F6
+:100B000000000000000010000000000000000000D5
+:100B100000000000000000000000000000001000C5
+:100B200000000000000000000000000000000000C5
+:100B300000432380000000000000000000000000CF
+:100B400000000000000000000000000000000000A5
+:100B50000000000000000000005C94015D94025E53
+:100B600094035F94004300000000000000000000B8
+:100B70000000000000000000000000000000000075
+:100B80000000000000000000000000000000000065
+:100B90000000000000000000005C90015D90025E1B
+:100BA00090035F9000530000000000000000000070
+:100BB0000000000000000000000000000000000035
+:100BC0000000000000000000000000000000000025
+:100BD0000000000000000000009C94001D90019D9A
+:100BE00094029E94039F94040894050994060A9421
+:100BF000070B94004300000000000000000000000C
+:100C000000000000000000000000000000000000E4
+:100C10000000000000000000009C90019D90029EDA
+:100C200090071D90039F90047890057990067A9024
+:100C3000077B90005300000000000000000000004F
+:100C400000000000000000000000000000000000A4
+:100C5000000000000000000000DC94001D9001DD99
+:100C60009402DE9403DF940404940505940606942C
+:100C70000707940808940909940A0A940B0B940036
+:100C80004300000000000000000000000000000021
+:100C9000000000000000000000DC9001DD9002DE9A
+:100CA000900B1D9003DF9004B49005B59006B690AC
+:100CB00007B79008B89009B9900ABA900BBB90009A
+:100CC0005300000063FFFC0020006C6010FFFF0A6F
+:100CD0000000000020006C8400D23110FFFE0A00EA
+:100CE0000000000020006CCC00D33110FFFE0A0091
+:100CF0000000000020006D0C00D43110FFFE0A003F
+:100D00000000000020006D8000D53110FFFE0A00B9
+:100D10000000000063FFFC00E00000A012FFF7826B
+:100D200020028257C82163FFFC12FFF303E830045E
+:100D3000EE3005C03093209421952263FFFC000023
+:100D40001FFFD000000400201FFFC5A01FFFC6909A
+:100D5000200A0011FFFB13FFFB03E631010200161E
+:100D6000FFFA17FFFAD30F776B069060B4667763CC
+:100D7000F85415F3541AA50F140063FFF90000008E
+:100D80006C1004C020D10F006C1004C0C71AEF060D
+:100D9000D830BC2BD72085720D4211837105450BCD
+:100DA000957202330C2376017B3B04233D0893713B
+:100DB000A32D12EEFE19EEFEA2767D632C2E0A0004
+:100DC000088202280A01038E380E0E42C8EE29A6B8
+:100DD0007E6D4A0500208800308C8271D10FC0F0F2
+:100DE000028F387FC0EA63FFE400C0F1C050037E89
+:100DF0000CA2EE0E3D1208820203F538050542CB27
+:100E00005729A67E2FDC100F4F366DFA050020887B
+:100E100000308CBC75C03008E208280A0105833810
+:100E2000030342C93E29A67E0D480CD30F6D8A05E7
+:100E300000208800B08C8271D10FC05008F5387541
+:100E4000C0C163FFBBC06002863876C0DA63FFD4DE
+:100E50006C101216EED8C1F9C1E8C1C72B221E28AA
+:100E6000221DC0D07B81352920060BB702299CFAB0
+:100E7000655008282072288CFF2824726491642A07
+:100E8000B0000CA80C64816F0EA90C6492BB7FA10A
+:100E90003FC1CE7CA13669AC336000370029200603
+:100EA000D7D0299CFACC57282072288CFF2824728E
+:100EB0006491392AD0000CA80C6481680EA90C64D6
+:100EC000931F7FA10BC1CE7CA10268AC06C020D1CC
+:100ED0000F2D25028A32C0900A6E5065E5B529248F
+:100EE00067090F4765F5B12C200C1FEEB30CCE112E
+:100EF000AFEE29E286B44879830260058219EEAF2D
+:100F000009C90A2992A36890078F2009FF0C65F58B
+:100F10006E2FE28564F56865559628221D7B810554
+:100F2000D9B060000200C0908B9417EEA50B881416
+:100F300087740B0B47A87718EEA309BB100877023C
+:100F400097F018EEA117EEA208A8010B8802074738
+:100F5000021BEE9E97F10B880298F22790232B90AC
+:100F60002204781006BB1007471208BB0228902104
+:100F70000777100C88100788020B880217EE968BF3
+:100F80003307BB0187340B880298F3979997F48B4A
+:100F90009587399BF588968B3898F688979BF897B4
+:100FA000F998F717EE8D28E28507C7082D74CF084A
+:100FB000480B28E68565550F2B221E28221D7B89AC
+:100FC000022B0A0064BF052CB00728B000DA200607
+:100FD000880A28824CC0D10B8000DBA065AFE76394
+:100FE000FEEA0000292072659E946004E72A2072C0
+:100FF00065AEBF6004DE00002EB0032C2067D4E095
+:1010000065C1058A328C330AFF500C4554BC5564C7
+:10101000F4EB19EE72882A09A90109880C64821F71
+:10102000C0926000DD2ED0032A2067D4E065A0D8EE
+:101030008A328B330AFC500B4554BC5564C4BE192C
+:10104000EE67882A09A9017989D50BEA5064A4E3DF
+:101050000CEE11C0F02F16132E16168AE78CE82A14
+:1010600016128EE9DFC0AAEA7EAB01B1CF0BA85001
+:101070006583468837DBC0AE89991E789B022BCCEE
+:10108000012B161B29120E2B0A0029161A7FC307E3
+:101090007FC9027EAB01C0B165B49D8B352F0A00BC
+:1010A0002A0A007AC30564C3CB2F0A0165F4892B91
+:1010B00012162B1619005104C0C100CC1A2CCCFFFB
+:1010C0002C16170CFC132C16182B121A2A121BDCC8
+:1010D000505819B6C0D0C0902E5CF42C12172812AC
+:1010E000182F121B2A121A08FF010CAA01883407B4
+:1010F0004C0AAB8B2812192BC6162F86082A860994
+:101100002E74102924672E70038975B1EA2A74039E
+:10111000B09909490C659DB42B20672D250265B354
+:10112000FA2B221E2C221D7BC901C0B064BD9D2C50
+:10113000B00728B000DA2006880A28824CC0D10BFC
+:101140008000DBA065AFE763FD8289BAB199659045
+:101150009788341CEE2398BA8F331EEE1C0F4F5421
+:101160002FB42C8D2A8A320EDD020CAC017DC966AB
+:101170000A49516F92608A3375A65B2CB0130AED51
+:10118000510DCD010D0D410C0C417DC9492EB01200
+:10119000B0EE65E3C6C0D08E378CB88A368FB97C86
+:1011A000A3077AC9027EFB01C0D1CED988350AAD2A
+:1011B000020E8E0878EB022DAC0189B7DAC0AF9B26
+:1011C00079BB01B1CADCB0C0B07DA3077AD9027C7B
+:1011D000EB01C0B164B161C091292467C020D10F77
+:1011E00000008ADAB1AA64A0C02C20672D25026510
+:1011F000C3111DEDF68A321EEDFB0DAD010EDD0CA7
+:1012000065D28A0A4E516FE202600281C0902924A1
+:1012100067090F4765F2F828221D7B89022B0A0017
+:1012200064BCA92CB00728B000DA2006880A2882FE
+:101230004CC0D10B8000DBA065AFE763FC8E0000E3
+:101240000CE9506492ED0CEF11C080281611AFBF6D
+:101250002F16198EF88BF7DAE08FF92B1610ABFBEF
+:101260007FBB01B1EA0CA8506580D68837DCE0AFBF
+:1012700089991C789B022CEC012C161B29120C2C32
+:101280000A0029161A7AE3077AE9027FBB01C0C176
+:1012900065C2A58B352C0A002A0A007AE30564E1B1
+:1012A000CA2C0A0164CE0D60028E88341BEDCD98E5
+:1012B000DA8F331EEDC60F4F542FD42C8C2A8A326E
+:1012C0000ECC020BAB010CBB0C65BF0A0A49516E78
+:1012D000920263FF018A330AAB5064BEF92CD0132B
+:1012E0000AEE510ECE010E0E410C0C410ECC0C65D7
+:1012F000CEE42FD012B0FF65F26EC0B08E378CD81E
+:101300008A362FD2097CA3077AC9027EFB01C0B1BD
+:1013100065BEC38835DBA0AE8E78EB01B1AB89D753
+:10132000DAC0AF9D79DB01B1CAC0C07BA3077AB92F
+:10133000027DEB01C0C165CE9DC090292467C0200D
+:10134000D10F88378C3698140CE90C29161408F83C
+:101350000C981D78FB07281214B088281614891DD4
+:101360009F159B16C0F02B121429161A2B161B8BD7
+:10137000147AE30B7AE90688158E1678EB01C0F132
+:1013800065F1BA29121A2F12118A352E121B9A1AD8
+:10139000AFEE2F1210C0A0AF9F79FB01B1EE9F11ED
+:1013A000881AC0F098107AE30A7EA9052A12017AF9
+:1013B0008B01C0F164F08160018389368B37991706
+:1013C0000BE80C981F09C90C29161578EB07281291
+:1013D00015B088281615D9C09A199E188A1F2E1282
+:1013E000152A161A2E161BDAC0C0E08C177F930B35
+:1013F0007FA90688188F1978FB01C0E165E13E29B5
+:10140000121A2F12138A352E121B9A1BAFEE2F12AF
+:1014100012C0A0AF9F79FB01B1EE9F13881BC0F0F3
+:1014200098127AE30A7EA9052A12037A8B01C0F189
+:1014300065F10A2E12162E16192A121B005104C02D
+:10144000E100EE1AB0EE2E16170EFF132F16180F2E
+:10145000CC01ACAA2F121A0EBC01ACFC7FCB01B19F
+:10146000AA2A161B2C161A63FC5E00007FB30263C7
+:10147000FE3163FE2B7EB30263FC3063FC2A000066
+:101480006450C0DA20DBC058168AC020D10FC0914A
+:1014900063FD7A00C09163FA44DA20DB70C0D12E7C
+:1014A0000A80C09A2924682C7007581575D2A0D1DB
+:1014B0000F03470B18ED4DDB70A8287873022B7DC6
+:1014C000F8D9B063FA6100002A2C74DB40580EEEA4
+:1014D00063FAE4000029221D2D25027B9901C0B08A
+:1014E000C9B62CB00728B000DA2006880A28824C3A
+:1014F000C0D10B8000DBA065AFE7C020D10FC09149
+:1015000063FBFF00022A0258024C0AA202060000F6
+:10151000022A025802490AA202060000DB70DA2001
+:10152000C0D12E0A80C09E2924682C7007581554FB
+:10153000C020D10FC09463FBC9C09663FBC4C096A2
+:1015400063FBBF002A2C74DB30DC405BFE0FDBA0AA
+:10155000C2A02AB4002C200C63FF27008D358CB765
+:101560007DCB0263FDD263FC6D8F358ED77FEB029E
+:1015700063FDC563FC6000006C1004C020D10F0047
+:101580006C1004C020D10F006C10042B221E2822E6
+:101590001DC0A0C0942924062A25027B8901DBA056
+:1015A000C9B913ED04DA2028B0002CB00703880A6B
+:1015B00028824CC0D10B8000DBA065AFE7C020D1F2
+:1015C0000F0000006C10042C20062A210268C805B8
+:1015D00028CCF965812E0A094C6591048F30C1B879
+:1015E0000F8F147FB00528212365812716ECF3297E
+:1015F000629E6F98026000F819ECEF2992266890BD
+:10160000078A2009AA0C65A0E72A629D64A0E12B45
+:10161000200C0CB911A6992D92866FD9026000DBBF
+:101620001DECE70DBD0A2DD2A368D0078E200DEE6C
+:101630000C65E0C7279285C0E06470BF1DECEC68C4
+:10164000434E1CECEB8A2B0CAA029A708920089955
+:10165000110D99029971882A98748F329F752821EB
+:1016600004088811987718ECDC0CBF11A6FF2DF246
+:1016700085A8B82E84CF2DDC282DF685C85A2A2CB3
+:1016800074DB40580E81D2A0D10FC020D10F0000D2
+:101690000029CCF96490B12C20668931B1CC0C0CB6
+:1016A000472C24666EC60260008509F85065807F6D
+:1016B0001CECD18A2B0F08400B881008AA020CAA38
+:1016C000029A7089200899110D99029971883398AE
+:1016D000738C329C728A2A9A748934997563FF7D5F
+:1016E00000CC57DA20DB30DC4058155FC020D10F2A
+:1016F00000DA20C0B65815EE63FFE500DA20581571
+:10170000EC63FFDC00DA20DB30DC40DD5058167A79
+:10171000D2A0D10FC858DA20DB305814C72A2102D2
+:1017200065AFBDC09409A90229250263FFB200007C
+:101730002B21045814731DECADC0E02E24668F30AD
+:101740002B200C0F8F1463FF66292138C088798302
+:101750001F8C310CFC5064CF562B2104C0C0581490
+:10176000681DECA2C0E08F302B200C0F8F1463FF9C
+:101770003E2C20662B2104B1CC0C0C472C2466583F
+:1017800014601DEC9AC0E02E24668F302B200C0FC5
+:101790008F1463FF1A0000006C1004C0B7C0A116BC
+:1017A000EC9615EC88D720D840B822C04005350209
+:1017B0009671957002A438040442C94B1AEC7B1947
+:1017C000EC7C29A67EC140D30F6D4A0500808800BD
+:1017D000208C220A88A272D10FC05008A53875B09B
+:1017E000E363FFD76C10069313941129200665520A
+:1017F00088C0716898052A9CF965A29816EC6F2933
+:1018000021028A1309094C6590CD8AA00A6A512ADF
+:10181000ACFD65A0C2CC5FDB30DA208C115815120C
+:10182000C0519A13C7BF9BA98E132EE20968E060CE
+:101830002F629E1DEC606FF8026000842DD2266836
+:10184000D0052F22007DF9782C629DC79064C0706E
+:101850009C108A132B200C2AA0200CBD11A6DD0A97
+:101860004F14BFA809880129D286AF88288C09792E
+:101870008B591FEC520FBF0A2FF2A368F0052822E4
+:10188000007F894729D285D4906590756000430018
+:10189000002B200C1FEC4A0CBD11A6DD29D2860FAF
+:1018A000BF0A6E96102FF2A368F00488207F890586
+:1018B00029D285659165DA2058157DC95C6001FFE4
+:1018C00000DA20C0B658157A60000C00C09063FFA3
+:1018D000B50000DA205815766551E48D138C11DBC4
+:1018E000D08DD0022A020D6D515813E39A1364A1D2
+:1018F000CEC75F8FA195A9C0510F0F479F1163FEFF
+:10190000FD00C091C0F12820062C2066288CF9A784
+:10191000CC0C0C472C24666FC6098D138DD170DE5C
+:1019200002290A00099D02648159C9D38A102B211A
+:10193000045813F38A13C0B02B24662EA2092AA0E0
+:10194000200E28141CEC298D1315EC1DC1700A778C
+:101950003685562DDC28AC2C9C12DED0A8557CD3C5
+:10196000022EDDF8D3E0DA40055B02DC305BFF8A53
+:10197000D4A028200CB455C0D02B0A882F0A800C84
+:101980008C11A6CC29C285AF3FAB9929C6851CEC2A
+:1019900012DEF0AC882D84CF28120229120378F3CE
+:1019A000022EFDF8289020D3E007880CC1700808AB
+:1019B00047289420087736657FAB891313EC10898C
+:1019C00090C0F47797491BEC0EC1CA2821048513F7
+:1019D000099E4006EE11875304881185520E880235
+:1019E0000C88029BA09FA18F2B9DA598A497A795DB
+:1019F000A603FF029FA22C200C1EEBF7AECE0CCC50
+:101A00001106CC082BC2852DE4CF2BBC202BC6851C
+:101A10002A2C748B11580D9CD2A0D10F28203DC0C8
+:101A2000E07C877F2E24670E0A4765A07B1AEBF5C2
+:101A300088201EEBE38F138EE48FF40888110A8848
+:101A4000020F8F14AFEE1FEBF098910FEE029E90F5
+:101A50001EEBEFC0801AEBE02CD285AABAB8CC28D6
+:101A6000A4CF2CD6852C21022F20720ECC02B1FFE0
+:101A70002F24722C2502C020D10F871387700707EF
+:101A80004763FD6E282138C099798B0263FE9ADD89
+:101A9000F063FE9500DA20DB308C11DD505815968E
+:101AA000D2A0D10FC0E163FF7A8B138C11DD50C03F
+:101AB000AA2E0A802A2468DA205813F1D2A0D10F66
+:101AC000C020D10F6C1006292102C0D07597102AB2
+:101AD00032047FA70A8B357FBF052D25020DD90261
+:101AE000090C4C65C18216EBB41EEBB228629EC095
+:101AF000FA78F30260018829E2266890078A2009B3
+:101B0000AA0C65A17A2A629DDFA064A1772B200C24
+:101B10000CBC11A6CC29C286C08C79830260015707
+:101B200019EBA709B90A2992A368900788200988A8
+:101B30000C65814327C2851CEBA964713A89310980
+:101B40008B140CBB016FB11D2C20669F10B1CC0C07
+:101B50000C472C24666EC60260014009FF5065F1F7
+:101B60003A8A102AAC188934C0C47F973C18EBA974
+:101B70001BEBA88F359C719B708B209D7408BB025A
+:101B80009B72C08298751BEBA40F08409B730F8853
+:101B90001198777FF70B2F2102284A0008FF022FA8
+:101BA0002502C0B4600004000000C0B07E97048F1E
+:101BB000362F25227D970488372825217C9736C02B
+:101BC000F1C0900AF9382F3C200909426490861927
+:101BD000EB7618EB7728967E00F08800A08C00F05A
+:101BE0008800A08C00F08800A08C2A629D2DE4A2C1
+:101BF0002AAC182A669D89307797388F338A321835
+:101C0000EB8007BE0B2C2104B4BB04CC1198E0C0C0
+:101C10008498E1882B9DE59AE69FE71AEB78099F67
+:101C20004006FF110FCC020A880298E2C1FC0FCCDB
+:101C3000022CE604C9B82C200C1EEB670CCA11AEAE
+:101C4000CC06AA0829A2852DC4CF09B90B29A685DF
+:101C5000CF5CC020D10FC081C0900F8938C0877978
+:101C6000880263FF7263FF6600CC57DA20DB30DC4A
+:101C7000405813FDC020D10FDA2058148D63FFE8BF
+:101C8000C0A063FE82DA20C0B658148963FFD90071
+:101C9000DB402A2C74580CFCD2A0D10F8A102B21C7
+:101CA000045813171EEB44C0D02D246663FEB10008
+:101CB0006C1006D62019EB3F1EEB4128610217EB92
+:101CC0003E08084C65805F8A300A6A5169A3572B29
+:101CD000729E6EB83F2A922668A0048C607AC9343E
+:101CE0002A729D2C4CFECAAB2B600CB64F0CBD115A
+:101CF000A7DD28D2860EBE0A78FB269C112EE2A311
+:101D00002C160068E0052F62007EF91522D285CFDF
+:101D10002560000D00DA60C0B6581465C85A60012D
+:101D20000F00DA60581462655106DC40DB308D30FC
+:101D3000DA600D6D515812D0D3A064A0F384A1C015
+:101D40005104044763FF6D00C0B02C60668931B157
+:101D5000CC0C0C472C64666FC60270960A2B61048B
+:101D60005812E7C0B02B64666550B42A3C10C0E737
+:101D7000DC20C0D1C0F002DF380F0F4264F09019B0
+:101D8000EB0A18EB0B28967E8D106DDA0500A08803
+:101D900000C08CC0A089301DEB1A77975388328C15
+:101DA000108F3302CE0BC02492E12261049DE00427
+:101DB00022118D6B9BE59FE798E61FEB1009984079
+:101DC0000688110822020FDD02C18D9DE208220261
+:101DD00092E4B4C22E600C1FEB000CE811A7882C13
+:101DE0008285AFEE0C220B2BE4CF228685D2A0D1C8
+:101DF0000F28600CD2A08C1119EAF80C8D11A9885B
+:101E0000A7DD2ED2852B84CF0ECC0B2CD685D10FFF
+:101E1000C0F00ADF387FE80263FF6C63FF600000F8
+:101E20002A6C74C0B2DC20DD405812C5C0B063FF1C
+:101E300063C020D10F0000006C10042920062A2264
+:101E40001EC0392C221D232468C0307AC107DDA0B2
+:101E5000600004000000C0D06E9738C08F2E0A804A
+:101E60002B2014C0962924060EBB022E21022B24FF
+:101E7000147E8004232502DE307AC10EC8ABDBD08D
+:101E8000DA202C0A00580B062E21020E0F4CC8FE39
+:101E90006000690068956528210208084C65805C2F
+:101EA0001AEAC61EEAC42BA29EC09A7B9B5E2BE256
+:101EB0002668B0048C207BC95329A29D1FEAC16407
+:101EC000904A9390C0C31DEAD52B21049D9608BB70
+:101ED000110CBB029B979B911CEAD2C08523E4A204
+:101EE0002BA29D2824068DFA282102B0DD2BBC30C0
+:101EF0002BA69D9DFA0C8802282502C8D2C020D1AD
+:101F00000F8EF912EAC82E2689C020D10FDA20C020
+:101F1000B65813E7C020D10F6C10062A2006941083
+:101F200068A80528ACF965825029210209094C6589
+:101F3000920ACC5FDB30DA208C1058134BC051D39F
+:101F4000A0C7AF9A3AC0D01CEA9D14EAA31EEA9C2F
+:101F50008F3A16EA99B1FB64B13128629E6F88020C
+:101F60006001ED294C332992266890078A2009AA3E
+:101F70000C65A1DC2A629DC08E64A1D42B200C0CC0
+:101F8000B7110677082972867983026001CD0CB9F2
+:101F90000A2992A36890082C220009CC0C65C1BBC9
+:101FA0002772856471B5282006288CF96481E52C98
+:101FB00020668931B1CC0C0C472C24666EC60260B9
+:101FC00001A109F85065819B2A21048CE488361E02
+:101FD000EA7D088914A9CC08084709881019EA92F3
+:101FE0000ECC029C7099718C2A1EEA9008CC020ECD
+:101FF000CC029C722E302C293013283012049910F8
+:102000000688100CEE109F740EAE0209880208EECE
+:10201000029E738C3704AA119C758938C0F4997696
+:102020008839C0C1987718EA828E359C7B9E780EDD
+:102030008E1408EE029E7A8E301CEA7177E73088A3
+:102040003289339C7C9F7D0E9C4006CC118F2B29BE
+:1020500076132D76112876120CAA0218EA68C1C9E7
+:102060000CAA022A761008FF029F7EC0AA60000117
+:10207000C0A6A4BC0CB911A6992892852DC4CF087E
+:10208000A80B289685655100C020D10F2B200C0C81
+:10209000B7110677082A72860CB90A6FA902600187
+:1020A000182992A36890082A220009AA0C65A109A0
+:1020B0002A728564A1032C203D0C2C4064C08C8CBA
+:1020C000350C8C1464C0848FE57CF37F8C360C8CCB
+:1020D0001464C0777CF374283013C0FC78F86CC0AB
+:1020E00090292467090C4765C0D719EA4718EA45C3
+:1020F0008F208C3508FF110C8C1408FF0288E49F98
+:10210000A1AC8C09CC029CA08C369FA30C8C14AC87
+:102110008809880298A218EA3DA4BC2F72852DC4B4
+:10212000CF2FFC102F76852F210229207208FF0265
+:10213000B2992924722F2502C020D10F00CC57DA82
+:1021400020DB308C105812C8C020D10FC09163FF23
+:102150008FDA20C0B658135663FFE100DA20581317
+:102160005463FFD82B21045811E61EEA152B200CCE
+:10217000C0D02D24668F3A63FE4DDA20DB30DC4080
+:10218000DD505813DDD2A0D10F2A2C748B10580BC0
+:10219000BED2A0D10F292138C08879832E8C310C72
+:1021A000FC5064CE222B2104C0C05811D5C0D01ED3
+:1021B000EA048F3A2B200C63FE0DDA2058133C639F
+:1021C000FF7ADA205BFF1CD2A0D10F002C20662BF7
+:1021D0002104B1CC0C0C472C24665811C91EE9F817
+:1021E0002B200CC0D02D24668F3A63FDDA0000004E
+:1021F0006C10089514C061C1B0D9402A203DC04080
+:102200000BAA010A64382A200629160568A8052C9D
+:10221000ACF965C33F1DE9EA6440052F120464F27E
+:10222000A02621021EE9E606064C6562E615E9E2F3
+:102230006440D98A352930039A130A990C6490CCEA
+:102240002C200C8B139C100CCC11A5CC9C112CC2F7
+:1022500086B4BB7CB3026002D78F100EFE0A2EE25A
+:10226000A368E0098620D30F0E660C6562C2881150
+:102270002882856482BA891364905EDA80D9308CB2
+:10228000201EE9E01FE9E11DE9CE8B138DD4D4B007
+:102290007FB718B88A293C10853608C6110E660229
+:1022A0009681058514A5D50F550295800418146DE7
+:1022B0008927889608CB110888140EBB02A8D82954
+:1022C0009C200F88029BA198A088929BA308881449
+:1022D000A8D80F880298A22AAC1019E9CCC0C08FE8
+:1022E000131EE9BD86118D10286285AEDD08FF0B37
+:1022F0002CD4CF2821022F66858B352A207209889D
+:1023000002ABAA2825022A2472C020D10F29529E8E
+:1023100018E9A96F980260020B28822668800829B4
+:10232000220008990C6591FC2A529DC1CE9A126434
+:10233000A1F22B200C2620060CB8110588082D824E
+:10234000860EBE0A7DC3026002052EE2A368E00885
+:102350002F22000EFF0C65F1F6288285D780DE80E3
+:102360006482009816266CF96462012C206688311C
+:102370002CCC010C0C472C24666EC6026001BC08F4
+:10238000FD5065D1B61DE9AB1CE98F19E9962A21EC
+:10239000048B2D2830102F211D0C88100BFB090AEF
+:1023A00088020988020CBB026441529B709D71989F
+:1023B00072C04D8D35D9E064D06ED730DBD0D830C7
+:1023C0007FD714273C10BCE92632168C3996E69C40
+:1023D000E78A37B4382AE6080B131464304A2A8295
+:1023E0001686799A9696978C778A7D9C982B821779
+:1023F0002C7C209A9A2A9C189B99867BB03B298C2E
+:10240000086DB9218BC996A52692162AAC18B899E1
+:102410009BA196A08BC786CD9BA22B921596A49BC1
+:10242000A386CB2CCC2026A605C0346BD4200D3B34
+:102430000C0DD8090E880A7FB705C0909988BC8812
+:10244000C0900B1A126DAA069988998B288C18C017
+:10245000D01BE97A1CE97916E96EB1FF2A211C2309
+:10246000E6130F0F4F26E6122F251D7FA906C0F099
+:10247000C08028251D05F6111AE9678F202BE61567
+:102480002CE6162DE61726E6180AFA022AE6142983
+:102490002006299CF96490F829200C8D14C0801A1C
+:1024A000E94E0C9C11AA99A5CCDA202BC285289460
+:1024B000CF0B4B0B2BC685C0B08C155811BBD2A0CF
+:1024C000D10F8A356FA546D8308BD56DA90C8A8679
+:1024D0000A8A14CBA77AB335288C10C080282467C9
+:1024E000080B4765B10BDA20DB302C12055811DEE2
+:1024F000D3A0C0C1C0D02DA4039C1463FD22863696
+:102500006461059B709D719872C04D63FEA4C0818B
+:1025100063FFC9008814CC87DA20DB308C15581192
+:10252000D2C020D10FDA20C0B658126163FFE40098
+:1025300000DA208B1058125E63FFD8009E178A12B3
+:102540002B21045810EF8E17C09029246663FE34A7
+:10255000C08063FE06DA20DB308C15DD505812E6B1
+:10256000D2A0D10FDA2058125263FFA7002B2138D6
+:10257000C0A87BAB026001048C310CFC5064CE041B
+:102580008A122B2104C0C098175810DD8E1763FDE6
+:10259000F32D21382DDCFF0D0D4F2D253865DEF78D
+:1025A00028206A7F87050826416460A3C09016E949
+:1025B000141CE9232A200723E61BB1AA0CFD0226DE
+:1025C000E61A2B200A29E61D2DE61E0CBB022BE67F
+:1025D0001C8B260A0A472BE6208B282AE53E2BE691
+:1025E000212924072820062A2064688346B44463EE
+:1025F000FEA5DB30DA208C158D142E0A80C08E28C3
+:10260000246858111FD2A0D10F2E7C4819E8ED2A5A
+:1026100032162B76129D712D761328761489960A20
+:102620002A14AA990C9902997069ED71C14663FD4B
+:102630008100000064AFB51DE8E22C20168DD20A9F
+:10264000CC0C00D10400CC1AACBC9C2963FF9D00CB
+:102650002B21046EB81E2C2066B8CC0C0C472C2401
+:1026600066C9C09E178A125810A68E17C0348F20D4
+:10267000C0D02D2466C06826240663FF2E8A122B44
+:1026800021042C20669817B1CC0C0C472C246658DA
+:10269000109C8E178716C0D02D246663FCE68D35FE
+:1026A000C08064D04AD9E0DC30DBE0DF301AE8E5F6
+:1026B000B188B4FF16E8E584C92D9DFF87C82CCCEE
+:1026C0001027D63006460127D6320A440117E8DF24
+:1026D00024D631A74727D63324F21596B794B68D62
+:1026E000C3BCBB9DB58D35299C107D83C22F211D98
+:1026F000C14663FD330000006C1006292006289CAB
+:10270000F86582BF2921022B200C09094C6590E154
+:1027100016E8AA0CBA11A6AA2DA2862C0A127DC30D
+:102720000260028C19E8A609B90A2992A3689007E9
+:102730008C2009CC0C65C27829A2856492722D6226
+:102740009E1AE89C6FD80260026E2AA22629160102
+:1027500068A0082B22000ABB0C65B25C29629DC1EF
+:102760008C6492542A21200A806099102C203CC746
+:10277000EF000F3E010B3EB1BD0FDB390BBB098FE4
+:10278000260DBD112DDC1C0D0D410EDD038E27B174
+:10279000DD0D0D410FEE0C0DBB0B2BBC1C0BB7025E
+:1027A0007EC71C2C21257BCB162D1AFC0CBA0C0DD8
+:1027B000A16000093E01073EB1780987390B770A0D
+:1027C00077EB0260020A2C2123282121B1CC0C0CCA
+:1027D0004F2C25237C8B29B0CD2D2523C855DA20FD
+:1027E000DB30581095292102CC96C0E80E9E022EAF
+:1027F0002502CC57DA20DB30DC4058111BC020D139
+:102800000F2C20668931B1CC0C0C472C24666EC687
+:10281000026001D309FD5065D1CD2F0A012E301180
+:1028200029221464E01128221B090C4400C1040071
+:10283000FA1A0A880228261B2E3010C0A0C0B094B5
+:102840001295131CE85F88302CC022088D147787FE
+:1028500004C0F10CFA38C041C0F225203CC0840805
+:1028600058010F5F010F4B3805354007BB10C0F012
+:10287000084F3808FF100FBB0228ECFEC0F0084FCD
+:1028800038842B0BA8100AFF102A21200F88020B76
+:10289000880208440218E86E8F1108440228212596
+:1028A0000A2A140828140488110A88022A21049488
+:1028B000F08B2004E41008BB1104BB02C04A04BB27
+:1028C000029BF1842A08AB110BEB0294F40A541119
+:1028D0000B44020555100D1B4094F707BB100B5518
+:1028E00002085502C08195F68433C05094F3B19428
+:1028F0008B3295F898F99BF2C080C1BC24261499BC
+:10290000FA9BF598FB853895FC843A94FD8B3B9BAC
+:10291000FE883998FF853525F6108436851324F610
+:10292000118B3784122BF612C0B064C07E893077C9
+:1029300097438D3288332E30108F111CE83109995E
+:10294000400699112CF614C0C42CF6158C2B2DF6CC
+:102950001A28F61B2BF61904A81109880208EE02A2
+:1029600019E827C18008EE0209C90229F6162EF6D9
+:1029700018C09E600001C09A2F200C18E8170CFEAA
+:1029800011A8FFA6EE2DE2852BF4CF0D9D0B2DE6B1
+:1029900085C87F8A268929A7AA9A260A990C090937
+:1029A00048292525655050C020D10F00C09A63FFEB
+:1029B000C6DA2058113F63FE38DA20C0B658113C01
+:1029C00063FE2E0068973C2B9CFD64BE24C020D182
+:1029D0000FDA20DB705810F8C0C0C0D10ADA390A0B
+:1029E000DC3865CDE063FE098A102B2104580FC442
+:1029F000C0B02B246663FE21DB402A2C745809A248
+:102A0000D2A0D10FDA20580FC963FCF76C1004C0B4
+:102A100020D10F006C1004290A801EE80E1FE80E5A
+:102A20001CE7E60C2B11ACBB2C2CFC2DB2850FCC7B
+:102A3000029ED19CD0C051C07013E80A14E8091856
+:102A4000E8072AB285A82804240A234691A986B853
+:102A5000AA2AB685A98827849F25649FD10F0000E4
+:102A60006C100AD630283010292006288CF9648290
+:102A70009B68980B2A9CF965A1B2022A02580FABF9
+:102A800089371BE7CFC89164520E2A21020A0C4CE9
+:102A900065C2588D3019E7C874D7052E212365E229
+:102AA0009E2F929E1AE7C46FF8026002532AA22654
+:102AB00068A0082C22000ACC0C65C2442A929D64AE
+:102AC000A23E9A151FE7BE8D67C1E6C8DD2B6206E0
+:102AD00018E7BC64B0052880217B8B432B200C18A1
+:102AE000E7B60CBC11A8CC29C28679EB460FBE0A0A
+:102AF0002EE2A368E0052F22007EF9372CC2859CC8
+:102B00001864C2332B212F87660B7B360B790C6F31
+:102B10009D266ED2462C203D7BC740CE5560001EC0
+:102B20002A200CC1B28C205811229A1864A2458D1B
+:102B30006763FFCFC0C063FFC5D7B063FFD300C0DA
+:102B4000E06000022E60030EDB0C6EB20EDC700C37
+:102B5000EA11AA6A2AAC20580199D7A0DA20DB70C2
+:102B6000C1C82D21205810BC8C268B279A160CBB6F
+:102B70000C7AB3348F18896399F3886298F28E6562
+:102B80009EF82D60108A189D1768D729C0D09DA97E
+:102B90002C22182B22139CAB9BAA97A58E667E73C2
+:102BA00002600097CF5860001FDA208B1658108201
+:102BB00065A13863FFBDC081C0908F18C0A29AF98B
+:102BC00099FB98FA97F563FFD2DB30DA20DC4058A6
+:102BD0001026C051D6A0C0C02BA0102CA4039B1758
+:102BE0002C1208022A02066B02DF702D60038E177A
+:102BF0009D149E100CDD11C0E0AD6D2DDC20580140
+:102C0000188C148B16ACAC2C64038A268929ABAAC9
+:102C10000A990C9A26886609094829252507880CEF
+:102C200098662F2218A7FF2F261863FE96DA20DB5E
+:102C300030DC40DD50581130D2A0D10FC0302C20F4
+:102C4000668961B1CC0C0C472C24666EC60260000C
+:102C5000D2C03009FD5065D0CA8E6764E0696470E7
+:102C600066DB608C18DF70DA202D60038E170CDDB8
+:102C7000119E10AD6D2DDC201EE7755800F923263E
+:102C800018DA208B16DC402F2213DD50B1FF2F26DF
+:102C900013580FC5D2A0D10F0028203D0848406529
+:102CA0008DE76F953EDA308DB56D990C8CA80C8C44
+:102CB00014CACF7CD32D2AAC10C090292467090DEB
+:102CC0004764DDC5600092002C1208066B022D6C73
+:102CD00020077F028E17DA209E101EE75C58007DC9
+:102CE00063FF9A00C09163FFD1000000655081DA54
+:102CF00020DB60DC40580FDCC020C0F02FA403D1E3
+:102D00000FDA20C0B658106A63FFE000006F95022A
+:102D100063FD6CDA20DB30DC40DD50C4E0580F5836
+:102D2000D2A0D10F8A152B2104580EF52324662832
+:102D30006010981763FF2100DA2058105D63FFAB25
+:102D4000C858DB30DA20580F3C2A210265AF9CC0FE
+:102D50009409A90229250263FF91DB30DC40DD5094
+:102D6000C0A32E0A802A2468DA20580F45D2A0D1A9
+:102D70000FC020D10FDA202B200C58107263FF6B8C
+:102D80006C1004282006C062288CF8658125C0508C
+:102D9000C7DF2B221BC0E12A206B29212300A104BD
+:102DA000B099292523B1AA00EC1A0BC4010A0A44E0
+:102DB0002A246B04E4390DCC030CBB012B261B64C5
+:102DC000406929200C1BE6FC0C9A110BAA082FA2C3
+:102DD000861BE6FA6FF9026000B60B9B0A2BB2A3C2
+:102DE00068B0082C22000BCC0C65C0A42BA2851D5A
+:102DF000E71E64B09B8C2B2421040DCC029CB08870
+:102E000020C0C50888110C880298B1882A0844118E
+:102E100098B48F3494B79FB5C0401EE6EF2DA285BD
+:102E20000E9E0825E4CF2DDC282DA6852921020938
+:102E3000094C68941A689820C9402A210265A00BA1
+:102E40002A221E2B221D7AB10265A079C020D10F43
+:102E50002C212365CFDE6000082E21212D21237E29
+:102E6000DBD52B221E2F221D2525027BF901C0B0A8
+:102E700064BFC413E6D02CB00728B000DA20038862
+:102E80000A28824CC0D10B8000DBA065AFE763FF4E
+:102E9000A62A2C74C0B02C0A02580E2F1CE6F49CF3
+:102EA000A08B2008BB1106BB029BA1893499A263A9
+:102EB000FF790000262468DA20DB30DC40DD505842
+:102EC000108ED2A0D10FDA202B200C580FF9C02081
+:102ED000D10F00006C1006073D14C080DC30DB40D1
+:102EE000DA20C047C02123BC3003283808084277C5
+:102EF0004001B1DD64815A1EE6AC19E6AD29E67EDB
+:102F0000D30F6DDA0500508800308CC0E0C020255A
+:102F1000A03C14E6ABB6D38FC0C0D00F87142440BA
+:102F2000220F8940941077F704C081048238C0F1E1
+:102F30000B2810C044C02204540104FD3802520181
+:102F400002FE3808DD10821C07EE100E6E020EDD48
+:102F500002242CFEC0E004FE380AEE100E88020D9A
+:102F600088028DAB1EE69B08D8020E880298B0C07E
+:102F7000E80428100E5E0184A025A125084411084C
+:102F80004402052514045511043402C0810E8E3903
+:102F900094B18FAA84109FB475660C26A11FC0F24D
+:102FA000062614600009000026A120C0F20626149F
+:102FB0000565020F770107873905E61007781008C5
+:102FC000660206550295B625A1040AE611085811B5
+:102FD00008280208660296B7C060644056649053A1
+:102FE000067E11C0F489C288C30B340B96459847FE
+:102FF000994618E6829F410459110E99021FE680F6
+:10300000020E4708D80298420E99029F40C1E00E76
+:10301000990299442FA00CB4380CF91114E66F1ED4
+:10302000E666A4FFAE992E928526F4CF0E880B2873
+:103030009685D10F2BA00C1FE6601CE6670CBE1115
+:10304000ACBBAFEE2DE28526B4CF0D3D0B2DE68552
+:10305000D10FC08005283878480263FEA263FE962F
+:103060006C1006C0C06570F18830C03008871477D6
+:103070008712C0B0C0A619E652299022C030CC9762
+:10308000C031600003C0B0C0A6C0E0C091C0D4C0D1
+:103090008225203C0B3F109712831CC070085801FA
+:1030A0000D5D01089738C0800B98380777100488A9
+:1030B00010086802087702C0800D98382D3CFE0881
+:1030C00088100D9E388D2B0AEE1008EE0207EE02D6
+:1030D0000CB8100FDD02053B400EDD029D4089203B
+:1030E000043D100899110D99022D210409A9020827
+:1030F000DD119941872A05B9100D3D020ABB110D5A
+:10310000BB02087702974428212587120828140457
+:103110008811071E4007EE100E99027566092621D8
+:103120001F062614600006002621200626140868C3
+:10313000029B47098802984629200CD2C0C0800C07
+:103140009E111BE6251FE61CAB99AFEE2DE28528EC
+:1031500094CF0DAD0B2DE685D10FDD40C0A6C0B0DC
+:103160008E51CAE0B2AAB1BB2DDC108F500E78365A
+:10317000981008770C9FD898D989538F5299119934
+:10318000DB9FDA7E8309B1CC255C10C97763FFCF62
+:1031900088108D1108E70C9751AD8DD7F078DB01C1
+:1031A000B1F79D5397528830C03008871408884083
+:1031B000648ED565BEC963FEBC0000006C1004D7E8
+:1031C00020B03A8820C0308221CAA0742B1E2972F8
+:1031D000046D080FC980C9918575B133A2527A3B3D
+:1031E0000B742B0863FFE900649FECD10FD240D130
+:1031F0000F0000006C100AD6302E3027D950DA406C
+:1032000015E5F02430269A1529160464E00264932B
+:10321000732920062A9CF865A3CE2A2102270A04D6
+:103220000A0B4C65B3978C3074C7052D212365D4E8
+:10323000A0C0A62B0A032C2200580F3664A3B9178E
+:10324000E5DE8E389A1664E3BA2F6027285021C92C
+:10325000F37E8311C2B08C202A200C580F55D7A0C2
+:10326000CDA16004A200C2B08C202A200C580F29E6
+:10327000D7A064A4862F212E8B680FBF360FB90C00
+:103280006F9D54296027D5B06E920528203D7B8F15
+:103290004CDA20DB50C1C42D211F580EEF8B269A2B
+:1032A000189A1989272AAC380B990C7A9353896399
+:1032B000C08099738F6298789F728E659E798D67B2
+:1032C0009D7B8C6695759C7A8E687E53026000B1FA
+:1032D0008B1465B050600038DBF063FFA5008A14E2
+:1032E000C9A92E60030E9B0C6EB2A5DC500CEA112E
+:1032F000AA6A2AAC285BFFB1D5A063FF93C0E06344
+:10330000FFE2DA208B18580EAC65A2B163FF9E0075
+:1033100000DA20DB308C15580E54D6A0C0C0C0D1C6
+:103320002D16042CA403DC70DA20DB60DF502D6046
+:1033300003C0E09E109D171EE5B90CDD110D6D0850
+:103340002DDC285BFF478E668F678817AF5FA8A8C4
+:1033500028640375FB01B1EE8A189E669F67892673
+:103360008829AA9909880C99268E6808084805EECC
+:103370000C28252515E5939E6865EECC63FEE600D6
+:103380000000C9432F21232B21212FFC010F0F4FB8
+:103390002F25237FBB026003142C20668961B1CCEA
+:1033A0000C0C472C24666EC60260022809FD50658D
+:1033B000D22264E1B62E602764E1B0DC70DF50DA1F
+:1033C00020DB601EE5AB2D6003C08098100CDD1182
+:1033D000AD6D2DDC285BFF22644181C0442B0A00C7
+:1033E0008C202A200C580ECB0AA70265A00FC0B073
+:1033F0002C22002A200C580EC7D7A064AFEFDA2089
+:10340000C1BCC1C82D21208F188E268929AFEE9E00
+:10341000260E990C090948292525580E8FC090C001
+:1034200050C0C288609A191EE566C0A12EE022082D
+:103430008F14778704C0810E8938C0800B93102DBC
+:10344000203C2921200CDC0104DB010929140BA8F4
+:10345000380CA5380D3D401CE57E8B2B08881007E5
+:1034600055100855020533022821250F154003BBCE
+:10347000020CBB0207551005D3100828140ADD11F1
+:103480000488110988020533022921040833029BAC
+:1034900070C0808A201BE57708AA110BAA029A71D6
+:1034A000C0A1852A9376957408931103DD020ADD85
+:1034B000029D778C63C1DC9C738B6298789A799BB0
+:1034C00072232214C0C0B1352526149C7B9D7593B0
+:1034D0007A2B621A9B7C2A621C9A7D28621D987E38
+:1034E00025621B957F2362172376102D62182D7697
+:1034F000112C62192C761264E0B98E6077E73DC01A
+:10350000FE13E53E1DE53FC1818A628B6304951180
+:103510000E9C4006CC110C5502247615085502C0AD
+:10352000802D76148D2B2B761B2A761A287619255A
+:10353000761803DD022D76166000030000C0FA2E17
+:10354000200C19E52518E51CA9E90CEE11A8EEC020
+:10355000802DE2852894CF0DFD0B2DE685DA208B9A
+:10356000198C158D14580D90D2A0D10FDC70DF503E
+:10357000DB602D6C28C0A01EE53E9A10DA205BFEB1
+:103580005563FE53002B203D0B4B4065BC826FE51D
+:1035900027DA308F556DE90C8EAA0E8E14C9E87E9D
+:1035A000F3162AAC10C090292467090F4764FC6009
+:1035B00060015F00C0FA63FF85C09163FFE8881473
+:1035C000658168DA20DB608C15580DA7C020C0909B
+:1035D00029A403D10F8A162B2104580CC9C0A02A94
+:1035E00024668E6863FDCA00002B9CF965B0FDDA85
+:1035F00020580CCE63FC220000DA20C0B6580E2CF6
+:1036000063FFBA002B200C0CBE11A7EE2DE286C181
+:10361000C27DC30260011819E4E909B90A2992A31D
+:103620006890082A220009AA0C65A10326E2856495
+:1036300060FD2C20668931B1CC0C0C472C24666FC0
+:10364000C60270960C8A162B2104580CADC0D02DE2
+:1036500024668E3077E74D1CE4E91BE4E98F32885D
+:1036600033C0A42D21040E994006991104DD1109DF
+:10367000DD029A61C19009DD029B60C0908B2B9D99
+:10368000649F66986799650CBB029B6228200C1AA0
+:10369000E4D2AA8A0C8811A7882F828529A4CF2F6B
+:1036A000FC202F86858A1465A0A6C020D10FB0FC0F
+:1036B0008B142C2523C8B7022A02066B02580CDE95
+:1036C0002A210265AEF7C0D80DAD022D250263FE9A
+:1036D000EC008E14C8E8DA20DB30580CD72A21021F
+:1036E00065AEDA07AF022F250263FED100DA20DBD8
+:1036F000308C158D14580E80D2A0D10FDA202B20DB
+:103700000C580DEB63FEB600DA202B200C580E0D82
+:1037100063FEAADA20DB308C152D12042E0A8028D5
+:103720000A00282468580CD663FAE500C020D10F9F
+:10373000DA20580DDF8914CD92DA20DB308C155851
+:103740000D4ADBA0C020C0A02AB403D10FC020D1F5
+:103750000F2A2C748B1558064CD2A0D10F000000F4
+:103760006C100E28210224160108084C6583A91F3D
+:10377000E49229F29E6F98026003AD1EE48E29E266
+:10378000266890082A220009AA0C65A39B24F29DB2
+:103790006443952A31160A4B412B240BB4BB0B0B07
+:1037A000472B240C0CB611AF66286286C1CC78C3B7
+:1037B0000260037F19E48209B90A2992A36890077D
+:1037C0008C2009CC0C65C36B276285647365293135
+:1037D00009C0D02D24668C3599139C2A88369C14F8
+:1037E000982B8E3798159E169E2C8C38C0E10C5C59
+:1037F000149C179C2D88392925042E251D28251C4D
+:103800002C3028C0822C243C2930290C0C4708C8B5
+:103810000129243D29311598189912090841089960
+:103820000C299CEC29251F7EC725921C8212282A70
+:1038300000082060991B01023E00093EB128098260
+:1038400039891B0E221102990C821C29251F821C0A
+:10385000941D951E24211F15E4880451609A10C1FF
+:10386000802B1610252014961F05054301063E00E7
+:103870000D3EB16B0DB6398B3C2D9CFC08663606AF
+:10388000441C893D2E26132E26142E26152E246B1D
+:1038900025241406D61CC05025261825261B2524B1
+:1038A000672524682832112525232525242525254B
+:1038B00025252C2925222D25202B252124252E26A2
+:1038C000252F14E46F16E46D1BE45298192D211C6A
+:1038D000C08498719B70892095759577957F967CAB
+:1038E000967E98799B7894731BE46714E4680C388F
+:1038F000400288100C064015E464016610947D9B1C
+:1039000074841D1BE444086602957B18E431851E0F
+:103910000B99029972997A0866022B121096768694
+:103920001F6FD2026001C8C0A0991A6D080AB1AA1F
+:1039300000A10400E81A7D8B0263FFEE891AC0E043
+:10394000961F1DE43E2B1610951E941D28203D2920
+:10395000761A297612C040C051C0B22D76130806DF
+:10396000408D170B8801065E380AEE101BE44A08EA
+:103970005438B0A609661188140B44102B761B042A
+:10398000EE028B1614E44308DA1406EE020D8810DA
+:103990002A761E86131AE41C04EE020D66110866D0
+:1039A000022E76160D14141EE41A0D44110BD814B1
+:1039B0000866020A44022E76182E76102476172600
+:1039C000761FC084287619287611C76F0C24400F03
+:1039D00044111CE3FB26761D26761C2676152676DA
+:1039E000148A262676242676252976222E762028E5
+:1039F00076218E1888150DB91016E4278BC70D880F
+:103A0000110E5E39ADBB851904EE022676230988B6
+:103A100002861F89102876260A04480544110505E8
+:103A2000480E551105440204EE02851E841D2E76B3
+:103A3000272820069B2D29246A2E31172B12102EA1
+:103A40002538CC83C0D02D2407C0D7090840648016
+:103A50008E9A290928416480AA64E0B42D2406C006
+:103A60009809E9362D0AA02A628501C404ADAA2D61
+:103A700021042A668508DD11883F8E3E2732100812
+:103A8000EA1800C40408E8180088110ECE5308771D
+:103A900002C08308DD029D4118E401090D4E9840E3
+:103AA00088209A4397449D4517E3FE1DE3CB058884
+:103AB0001108EE02ADBDC08007EE029E4228D4CFB1
+:103AC0002AF29D87CA2AAC18B1772AF69D1AE3B963
+:103AD00097CA28A4A268711C655060C020D10F004D
+:103AE0002D2406C080C09809E9360E893863FF731B
+:103AF000C0A063FE481BE3CB1AE3EB2AB68963FF41
+:103B0000D600000065EF54C098C0D82D240663FF8E
+:103B1000522D2406C09063FF4ACC57DA20DB308C4C
+:103B200011580C51C020D10F00DA20C0B6580CE05B
+:103B300063FFE500DA20580CDE63FFDC2A2C748B6F
+:103B400011580551D2A0D10F6C10062820068A33D7
+:103B50006F8202600161C05013E39729210216E3CE
+:103B600096699204252502D9502C20159A2814E331
+:103B7000948F2627200B0AFE0C0477092B712064F2
+:103B8000E1398E428D436FBC0260016F00E104B0E9
+:103B9000C800881A08A80808D80298272B200668A9
+:103BA000B32ECE972B221E2C221D0111027BC901A0
+:103BB000C0B064B0172CB00728B000DA2003880A20
+:103BC00028824CC0D10B8000DBA065AFE7C020D1BC
+:103BD0000F2D206464DFCA8B29C0F10BAB0C66BFCC
+:103BE000C02B200C0CBC11A6CC28C2862E0A08784B
+:103BF000EB611EE3720EBE0A2EE2A368E0052822E6
+:103C0000007E894F29C2851EE37E6490461FE38CA7
+:103C10009E90C084989128200A95930F88029892CC
+:103C20008E200FEE029E942F200788262F950A984B
+:103C3000969A972E200625240768E3432921022A15
+:103C4000C2851DE3652AAC20ADBD25D4CF2AC6852B
+:103C500063FF4E002E2065CBEDC082282465C9F697
+:103C600005E4310002002A62821BE36D2941020B48
+:103C7000AA022A668209E43129210263FF23000097
+:103C800064DFB88F422E201600F1040DEE0C00EE1A
+:103C90001AAEAE9E2963FFA38A202B3221B1AA9AC5
+:103CA000B0293221283223B4992936217989A92BC8
+:103CB00032222B362163FFA0C020D10F9F2725245D
+:103CC00015ACB82875202B2006C0C12EBCFE64E0C0
+:103CD000AB68B7772DBCFD65DEC72D2064C0F064EE
+:103CE000D0868E290EAE0C66E089C0F128205A28B5
+:103CF0008CFE08CF3865FEE863FF580000E00493AF
+:103D000010C0810AF30C038339C78F08D80308A8B1
+:103D10000108F80C080819A83303C80CA8B82875BE
+:103D200020030B472B24158310CBB700E104B0BC54
+:103D300000CC1AACAC0CDC029C27659E5EC0B20BBA
+:103D4000990209094F29250263FE50002D206A0DB2
+:103D50002D4165DF7EDA20C0B0580CA864AF18C0D2
+:103D6000F163FEEF9F2763FFD02E221F65EE3263C3
+:103D7000FF79000028221F658E2763FF6E25240629
+:103D800029210263FE1B00006C10066571332B4C69
+:103D900018C0C7293C18C0A1C08009A8380808422B
+:103DA0006481101CE3011AE3022AC67E2A5CFDD35B
+:103DB0000F6DAA0500B08800908C8940C0A00988CA
+:103DC000471FE32B080B47094C50090D5304DD1026
+:103DD000B4CC04CC100D5D029D310CBB029B30882D
+:103DE000438E2098350FEE029E328D26D850A6DDE8
+:103DF0009D268E40C0900E5E5064E0971CE3111E1D
+:103E0000E300038B0BC0F49FB19EB02D200A99B341
+:103E10000CDD029DB28F200CFF029FB48E262D2058
+:103E2000079EB68C282DB50A9CB72924072F20069B
+:103E30002B206469F339CBB61DE2E22320168DD224
+:103E40000B330C00D10400331AB48DA3C393292281
+:103E5000200C13E2E11FE2D80C2E11AFEEA32229B1
+:103E600024CF2FE285D2A00FDD0B2DE685D10F00E8
+:103E70002E200CB48C0CEB111FE2D81DE2CFAFEE5C
+:103E8000ADBB22B28529E4CF02C20B22B685D2A0F7
+:103E9000D10F00002E200C1CE2C81FE2CF0CEB114A
+:103EA000AFEEACBB22B28529E4CF02820B22B685ED
+:103EB000D2A0D10FC0D00BAD387DC80263FEEC6339
+:103EC000FEE08E40272C747BEE12DA70C0B32C3CDF
+:103ED00018DD50580A9B8940C08063FEE3066E02DD
+:103EE000022A02DB30DC40DD505800049A10DB501F
+:103EF000DA70580465881063FEF700006C100692B3
+:103F0000121EE2B98C40AE2D0C8C472E3C1804CA10
+:103F10000BD9A07DA30229ADF875C302600084C04F
+:103F2000B0C023C0A09D106D0844B89F0EB80A8D84
+:103F3000900EB70BB8770D6D36ADAA9D800D660C4F
+:103F4000D8F000808800708C879068B124B2227706
+:103F5000D3278891C0D0CB879890279C1000708879
+:103F600000F08C9D91CB6FC08108BB0375CB36638D
+:103F7000FFB4B1222EEC1863FFD485920D770C8626
+:103F8000939790A6D67D6B01B1559693959260005C
+:103F900016B3CC2D9C188810D9D078D3C729DDF85A
+:103FA00063FFC100C0238A421BE2C000CD322D4412
+:103FB000029B3092318942854379A1051EE2BC0EF5
+:103FC000550187121BE2AB897095350B9902993226
+:103FD00088420A880C98428676A6A696768F44AFC9
+:103FE000AF9F44D10F0000006C10089311D63088A9
+:103FF00030C0910863510808470598389812282165
+:1040000002293CFD08084C6581656591628A630A56
+:104010002B5065B18B0A6F142E0AFF7CA60A2C2048
+:104020005ACCC42D0A022D245A7FE0026002158961
+:104030002888261FE29F09880C65820F2E200B0F0F
+:10404000EE0B2DE0FE2EE0FF08DD110EDD021EE27C
+:1040500099AEDD1EE2991CE2990EDD010DCC37C14F
+:1040600080084837B88DB488981089601AE2557B6B
+:1040700096218B622AA0219C147BA3179D132A20D2
+:104080000C8B108C20580BCA8C148D13DBA0CEAC7B
+:104090006001C4002E200C1BE2480CEA110BAA0898
+:1040A0002BA2861FE2467BDB3B0FEF0A2FF2A368B1
+:1040B000F0052822007F892C2BA28564B0AA876294
+:1040C0008826DE700C7936097A0C6FAD1C8F279B21
+:1040D0001508FF0C77F3197E7B729D139C149B15BA
+:1040E000CF56600025C0B063FFD0D79063FFDD00DE
+:1040F000009D139C14DA20DB70580B2F8B158C1449
+:104100008D1365A06A8E6263FFCC00DA208B11DC10
+:1041100040580AD5D6A08B15C051DE70DA20DC607D
+:10412000DD405BFF768D138C14D9A02E200C1BE292
+:10413000221FE2290CEA11AFEFC0E0ABAA2BA28547
+:104140002EF4CF0B990B29A68563FF1D00DA20DC26
+:1041500060DD40DE708912282007DF50A9882824FE
+:10416000075BFF09D2A0D10F00DBE0DA20580B502B
+:104170006550EF2A20140A3A4065A0EBDB60DC4072
+:10418000DD30022A025809BCD6A064A0D584A183E0
+:10419000A00404470305479512036351C05163FE11
+:1041A0005C2C2006D30F28CCFD6480A568C704C012
+:1041B000932924062C2006C0B18D641FE2019D279F
+:1041C0009D289D298FF29D2600F10400BB1A00F066
+:1041D00004B0BE0EDD01C0F0ADBB8D652F24070D10
+:1041E0000E5E01EE11AEBB2E0AFEB0BB0B0B190E1C
+:1041F000BB36C0E20B0B470EBB372B241618E1F978
+:104200000A09450D0B422B240B29240AB4BE2E2487
+:104210000C7D88572920162FCCFDB09D0A5C520DCD
+:10422000CC362C246465FDEC0C0C4764CDE618E11B
+:10423000E48E2888820C9F0C00810400FF1AAFEEE8
+:104240009E2963FDCF1CE21163FE13001CE20B6389
+:10425000FE0C8D6563FFA500DA202B200C580B396E
+:10426000645F0FC020D10F00C020D10FC09329245C
+:1042700016C09363FFA000006C1004C06017E1CD6E
+:104280001DE1D0C3812931012A300829240A78A1EF
+:1042900008C3B27BA172D260D10FC0C16550512654
+:1042A00025022AD0202F200B290AFB2B20142E2098
+:1042B0001526241509BB010DFF0928F1202B241414
+:1042C000A8EE2EF52064A0A92B221E28221D011184
+:1042D000027B8901DB6064B0172CB00728B000DADC
+:1042E0002007880A28824CC0D10B8000DBA065AF74
+:1042F000E7DB30DC40DD50DA205800DE29210209FE
+:104300000B4CCAB2D2A0D10F00CC5A2C30087BC1C2
+:10431000372ED02064E02D022A02033B02DC40DD70
+:10432000505800D4D2A0D10F2B2014B0BB2B241492
+:104330000B0F4164F0797CB7CAC0C10C9C022C25DC
+:1043400002D2A0D10FC020D10F2E200669E2C126D3
+:1043500024062B221E2F221D29200B2820150D9903
+:10436000092A9120262415AA882895207BF14960E6
+:104370000048B0BB2B24140B0A4164A0627CB70236
+:104380002C25022B221E2C221DD30F7BC901C0B06D
+:10439000C9B62CB00728B000DA2007880A28824C5A
+:1043A000C0D10B8000DBA065AFE7C020D10F0000BB
+:1043B000262406D2A0D10F0000DB601DE18164BF7E
+:1043C0004F2CB00728B000DA2007880A28824CC09A
+:1043D000D10B8000DBA065AFE71DE17963FF310001
+:1043E00026240663FF9C00006C1004282006260A81
+:1043F000046F856364502A2920147D9724022A02C1
+:10440000DB30DC40DD50580019292102090A4CC874
+:10441000A2C020D10FC0B10B9B022B2502C020D11E
+:104420000F00022A02033B022C0A015800D1C9AA3C
+:10443000DA20DB30DC40580A0C29A011D3A07E978B
+:10444000082C0AFD0C9C012CA411C0512D2014062F
+:10445000DD022D241463FFA4DA20DB30DC40DD50C4
+:10446000C0E0580987D2A0D10F0000006C100616DA
+:10447000E1521CE152655157C0E117E14E2821027B
+:104480002D220008084C6580932B32000B695129BE
+:104490009CFD6590872A629E6EA84C2A722668A0B1
+:1044A000027AD9432A629DCBAD7CBE502B200C0CE6
+:1044B000BD11A6DD28D2862F4C0478FB160CBF0A4E
+:1044C0002FF2A368F0052822007F89072DD285D31B
+:1044D0000F65D0742A210419E17AD30F7A9B2EDA62
+:1044E00020580883600035002D21041BE1757DBB39
+:1044F00024DA20C0B658087ECA546001030B2B5042
+:104500002B240BB4BB0B0B472B240C63FFA0DA202E
+:10451000580A67600006DA20C0B6580A656550E0A0
+:10452000DC40DB302D3200022A020D6D515808D2DA
+:104530001CE123D3A064A0C8C05184A18EA00404B0
+:10454000470E0E4763FF3500002B2104C08B8931D5
+:10455000C070DF7009F950098F386EB8172C2066CB
+:10456000AECC0C0C472C24667CFB099D105808E44B
+:104570008D1027246694D11EE126B8DC9ED06550AC
+:1045800056C0D7B83AC0B1C0F00CBF380F0F42CBFD
+:10459000F119E10518E10728967EB04BD30F6DBAEB
+:1045A0000500A08800C08C2C200CC0201DE10B0C45
+:1045B000CF11A6FF2EF285ADCC27C4CF0E4E0B2E09
+:1045C000F685D10FC0800AB83878D0CD63FFC1001E
+:1045D0008E300E0E4763FEA12A2C742B0A01044D67
+:1045E000025808D72F200C12E0FC0CF911A699A252
+:1045F000FF27F4CF289285D2A008480B289685D1B2
+:104600000FC020D10F0000006C1004C060CB55DB40
+:1046100030DC40055D02022A025BFF942921020979
+:10462000084CC882D2A0D10F2B2014B0BB2B24146D
+:104630000B0C41CBC57DB7EBC0C10C9C022C2502F5
+:10464000D2A0D10F0000022A02033B02066C02C076
+:10465000D0C7F72E201428310126250228240A0F5E
+:10466000EE012E241458010E63FFA300262406D267
+:10467000A0D10F006C1006282102D62008084C6536
+:10468000809D2B200C12E0CC0CB811A2882A8286C7
+:10469000B5497A930260009719E0C909B90A2992CD
+:1046A000A36890082A620009AA0C65A08228828566
+:1046B0001CE0D46480799C80B887B14B9B819B10AF
+:1046C000655074C0A7D970280A01C0D0078D380D75
+:1046D0000D42CBDE1FE0B51EE0B62EF67ED830D3FD
+:1046E0000F6D4A0500808800908C2E3008C0A00015
+:1046F000EE322E740028600C19E0B80C8D11A2DD8A
+:10470000A988C0202CD2852284CFD2A00CBC0B2C2F
+:10471000D685D10FC0F0038F387FA0C063FFB400EF
+:10472000CC582A6C74DB30DC4058080BC020D10F09
+:10473000DA605809DF63FFE7DD402A6C74C0B0DC43
+:104740007058087F2E30088B1000EE322E7400282F
+:10475000600C19E0A10C8D11A2DDA988C0202CD21B
+:10476000852284CFD2A00CBC0B2CD685D10F0000A3
+:104770006C1004292014282006B19929241468817A
+:1047800024C0AF2C0A012B21022C24067BA004C0DC
+:10479000D02D2502022A02033B02044C02C0D0584D
+:1047A00000C0D2A0D10FC020D10F00006C1004298E
+:1047B0003101C2B429240A2A3011C28378A16C7B4A
+:1047C000A1696450472C2006C0686FC562CA572D86
+:1047D00020147CD722DA20DB30DC40DD505BFFA5E3
+:1047E000292102090E4CC8E2C020D10FC0F10F9F51
+:1047F000022F2502C020D10FDA20DB30C0C05BFFC2
+:10480000DC28201406880228241463FFC7292015F9
+:104810001BE06C2A200BC0C09C240BAA092BA120F2
+:104820002C2415AB9929A52063FF9900C020D10F36
+:10483000DA20DB30DC40DD50C0E0580891D2A0D156
+:104840000F0000006C1004CB5513E06725221F0DEC
+:10485000461106550CA32326221E25261F06440BAF
+:1048600024261E734B1DC852D240D10F280A80C087
+:104870004024261FA82828261E28261DD240D10FF6
+:10488000C020D10F244DF824261E63FFD80000005D
+:104890006C1004D620282006C0706E85026000D4FB
+:1048A0001DE04E19E04612E0442A8CFC64A1302B36
+:1048B0006102B44C0B0B4C65B0A22B600C8A600CEF
+:1048C000B8110288082E828609B90A7EC3026000E8
+:1048D0009A2992A368900509AA0C65A08E28828562
+:1048E000648088B8891BE04A94819B80655155C0DB
+:1048F000B7B8382A0A01C0C009AC380C0C4264C0F1
+:10490000421FE0291EE02B2EF67EB04AD30F6DAA7F
+:104910000500808800908CC0A029600C0C9C11A21E
+:10492000CC2BC285AD990B4B0B2BC6852860062777
+:1049300094CF6881222D6015D2A0C9D2C0E22E6426
+:1049400006D10F00C0F008AF387FB0BD63FFB100E3
+:10495000276406D2A0D10F00D2A0D10F00CC57DA25
+:1049600060DB30DC405808C0C020D10FDA60580945
+:104970005063FFE80028221E29221DD30F789901D9
+:10498000C080C1D6C1C11BE018C122AB6B6480429C
+:1049900078913F2A80000CAE0C64E0BB02AF0C643F
+:1049A000F0B52EACEC64E0AF0DAF0C64F0A92EAC0A
+:1049B000E864E0A32FACE764F09D2EACE664E097DA
+:1049C0002F800708F80BDA807B83022A8DF8D8A0A5
+:1049D00065AFBC28612308D739D97060007B00001F
+:1049E0002B600C0CB811A2882C82862A0A087CAB9A
+:1049F0007E09BA0A2AA2A368A0052C62007AC96FB0
+:104A00002A828564A0691FDFFE276504C0E3C0C455
+:104A10002E64069CA11CE02B9FA02E600A97A30C7D
+:104A2000EE029EA28F600CFF029FA42E60147AEF0C
+:104A30004627A417ADBC2F828527C4CF2FFC202F7B
+:104A4000868563FE692A6C74C0B1DC90DD4058072E
+:104A5000BC1DDFE163FEC100D9A0DA60DB30C2D04B
+:104A6000C1E0DC4009DE39DD50580805D2A0D10F85
+:104A7000DA6058090F63FEE4290A0129A4170DBF63
+:104A8000082E828527F4CF2EEC202E868564500BCD
+:104A90002A6C74DB4058017CD2A0D10FC020D10F0A
+:104AA0006C10062B221E28221D93107B8901C0B09A
+:104AB000C0C9C03BC1F20406401DDFCBC0E2C074D8
+:104AC0000747010E4E01AD2D9E11C0402E0A146401
+:104AD000B06E6D084428221D7B81652AB0007EA13E
+:104AE0003B7FA1477B51207CA14968A91768AA1484
+:104AF00073A111C09F79A10CC18B78A107C1AE2908
+:104B00000A1E29B4007CA12B2AB0070BAB0BDAB02C
+:104B10007DB3022ABDF8DBA0CAA563FFB428B0109C
+:104B200089116987BB649FB863FFDC00647FB4634D
+:104B3000FFD50000646FD0C041C1AE2AB40063FF4E
+:104B4000C62B2102CEBE2A221D2B221E7AB12A8C10
+:104B5000107CB1217AB901C0B0C9B913DF96DA204F
+:104B600028B0002CB00703880A28824CC0D10B80E3
+:104B700000DBA065AFE7D240D10F8910659FD463F9
+:104B8000FFF300006C1008C0D0C8598C30292102F6
+:104B90000C0C4760000C8E300E1E5065E19E2921E2
+:104BA00002C0C116DF85090B4C65B0908A300A6ED1
+:104BB0005168E3026000852F629E1BDF7E6EF85312
+:104BC0002BB22668B0052E22007BE94727629DB7ED
+:104BD00048CB7F97102B200CB04E0CBF11A6FF299D
+:104BE000F2869E12798B4117DF7507B70A2772A3E9
+:104BF000687004882077893029F285DF90D7906526
+:104C000090652A210419DFAE7A9B22DA205806B873
+:104C1000600029002C21041BDFAA7CBB18DA20C00D
+:104C2000B65806B3C95860014CC09063FFCCDA2077
+:104C300058089F600006DA20C0B658089D655135B7
+:104C4000DC40DB308D30DA200D6D5158070BC0D0C1
+:104C5000D3A064A120292102C05184A18CA0040406
+:104C6000470C0C4763FF3E00C09B8831DBD008F83F
+:104C700050089B3828210498116E8823282066ACA0
+:104C80008C0C0C472C24667CBB159F139E148A1039
+:104C90008B1158071B8E148F13C0D02D24668A30B9
+:104CA000C092C1C81BDF5B7FA6099BF099F12CF471
+:104CB0000827FC106550A4B83ADF70C051C08007C7
+:104CC000583808084264806718DF3819DF392986A8
+:104CD0007E6A420AD30F6DE90500A08800F08CC0FF
+:104CE000A08930B4E37F9628C0F207E90B2C940822
+:104CF0009B909F912F200C12DF380CF811A6882969
+:104D00008285A2FF2DF4CFD2A009330B238685D153
+:104D10000F22200C891218DF300C2B11A6BBA82201
+:104D20002D24CF2CB285D2A00C990B29B685D10F9A
+:104D3000C087C0900A593879809663FF8ADB30DAE1
+:104D400020C0C1C0D05BFF56292102C0D02A9CFEE2
+:104D500065AE4D2D2502C09063FE45009E142A2CA1
+:104D600074C0B1DC70DD405806F68E14C0D01BDF75
+:104D700028C1C863FF6AC020D10F00006C1006284C
+:104D8000210217DF0D08084C65824929729E6F9831
+:104D90000260025019DF082A922668A0078B200AB9
+:104DA000BB0C65B23F2A729DC0CB64A2371DDF04E5
+:104DB000C0602B3008C0F164B0712E0AFFB0B86437
+:104DC00081512DBCFE64D0F364505C2A2C74044BDA
+:104DD000025800AD0AA2020600000000001ADF0817
+:104DE0002C20076EBB0260022218DEFE13DF081BB8
+:104DF000DF36C0E229200A9AD09ED1ABCB039902BC
+:104E000099D223B08026B480B13308330293D318EB
+:104E1000DEF20CFD11A7DD2CD285A8F82684CF0C7C
+:104E2000EC0B2CD685655FA2C020D10F2B21048806
+:104E300031DE6008F85008CE386EB8102C2066B10C
+:104E4000CC0C0C472C24667CEB026001AF2E30109A
+:104E50002930112C301300993200CB3264E1452AFD
+:104E600030141EDF1A00AA3278CF050E9C092BC41D
+:104E70007F1CDF1766A0050E98092A8480B4A71846
+:104E8000DF15C76F009104AC9CDBC000AE1A00F3C5
+:104E90001A6EC1048BD00BCB0C1CDF0F08B81C069C
+:104EA0003303AC882A848B2CD03627848C03CC0126
+:104EB0000ECC022CD4365801AD63FF0B2F200C0C06
+:104EC000FB11A7BB2DB286C0987D9302600121190A
+:104ED000DEBB09F90A2992A36890082D220009DD9A
+:104EE0000C65D10C2DB285DE6064D10488312B2194
+:104EF0000408F85008CE386FB80263FEDF2C206635
+:104F0000B1CC0C0C472C24667CE30263FECE9D10D2
+:104F100060013100293108292504283014B0886443
+:104F200080A62B31092B240AC0812B30162FD423C5
+:104F30002B240BB4BC2C240C8D378B36292504DE96
+:104F4000D00D8E39DCB00B8C390ECC0264CE7808D3
+:104F50009C1101C4048F380DBE1800C4040DB8188C
+:104F600000881108FF02C08308CC0218DECC9CA187
+:104F700098A018DECB8C209EA39FA405CC110BCF4C
+:104F800053C1E09EA50CFF0208FF029FA218DE8914
+:104F90002624662C729D2684A22CCC182C769D6328
+:104FA000FE250000002D30121CDECD00DA3278DF45
+:104FB000050C9E0B2AE47F66B0050C9F0B2BF4803A
+:104FC0002A301100AA3263FEEC2E240A2B31099BF1
+:104FD0002B63FF5300CC57DA20DB30DC405807222C
+:104FE000C020D10F00DA20C0B65807B163FFE5003A
+:104FF00000DBF0DA205807AE63FFD9000058064006
+:105000001DDE70C0F126246663FE41008B20280A55
+:10501000FFB1CE23200A2C21040E0E472E24077840
+:1050200031359AD02CD50A96D319DEA62ED416C0C7
+:105030008398D1C0E309B80298D409390299D226DD
+:10504000240763FDC958062E8D102624662B2104E3
+:105050002F200C63FD86000008B81119DE6808EEE9
+:1050600002882B9ED59AD0C0EF09880298D204C935
+:10507000110E990299D4C0E49ED163FFC1000000D3
+:105080006C1004C020D10F006C100485210D381164
+:1050900014DE478622A42408660C962205330B935F
+:1050A00021743B13C862D230D10FC030BC29992182
+:1050B00099209322D230D10F233DF8932163FFE34F
+:1050C0006C100AD620941817DE3CD930B8389819DD
+:1050D0009914655256C0E1D2E02E61021DDE390EF0
+:1050E0000E4C65E1628F308E190F6F512FFCFD65FC
+:1050F000F1558EE129D0230E8F5077E66B8F181E65
+:10510000DE78B0FF0FF4110F1F146590CE18DE7516
+:105110008C60A8CCC0B119DE2728600B09CC0B0D20
+:10512000880929812028811E2A0A0009880C08BACA
+:10513000381BDE6B0CA90A2992947B9B0260008CC1
+:105140002B600C94160CBD11A7DD29D286B84879C6
+:1051500083026000D219DE1909B80A2882A39817C1
+:105160006880026000A36000A51ADE5F84180AEE62
+:1051700001CA981BDE108C192BB0008CC06EB313C3
+:105180001DDE0D0C1C520DCC0B2DC295C0A17EDB7B
+:10519000AE6000380C0C5360000900000018DE51AE
+:1051A0008C60A8CCC0B119DE0328600B09CC0B0DB4
+:1051B000880929812028811E2A0A0009880C08BA3A
+:1051C000380CA90A2992947E930263FF72DA60C0B8
+:1051D000BA58073764507360026A00001ADDF68C13
+:1051E000192AA0008CC06EA31A18DDF20C1C5208FC
+:1051F000CC0B18DE3B2BC295C0A178B30263FF3FF6
+:1052000063FFC9000C0C5363FF0989607899182962
+:10521000D285C9922B729E1DDDE76EB8232DD22652
+:10522000991369D00B60000DDA60580721600017F0
+:105230000088607D890A9A1A29729D9C129915CF5F
+:1052400095DA60C0B658071A6551F98D148C18DBD1
+:10525000D08DD0066A020D6D51580587D3A09A14DF
+:1052600064A1E182A085A1B8AF9F1905054702029C
+:10527000479518C05163FE602B6104C08B8931C013
+:10528000A009F950098A386EB81F2C6066A2CC0CB0
+:105290000C472C64667CAB119F119E1B8A15580528
+:1052A000988E1B8F11C0A02A64669F1164F0E58957
+:1052B0001388190FFD022E0A006DD9172F810300E4
+:1052C000908DAEFE0080889F9200908C008088B800
+:1052D0009900908C65514E8A10851A8B301FDDC85D
+:1052E000881229600708580A2C82942D61040ECC7C
+:1052F0000C2C86946FDB3C1CDDF4AC9C29C0800B2D
+:105300005D50A29909094729C48065D0DA2E600C46
+:10531000C0D01FDDB10CE811AFEEA7882282852D29
+:10532000E4CF02420B228685D2A0D10F8E300E0E22
+:105330004763FDA2A29C0C0C472C64077AB6CD8B68
+:10534000602E600A280AFF08E80C64810E18DDDD73
+:1053500083168213B33902330B2C34162D350AC051
+:105360002392319F30C020923308B20208E80292A3
+:10537000349832C0802864072B600CD2A01CDD96C4
+:105380000CBE11A7EE2DE285ACBB28B4CF0D9D0B52
+:105390002DE685D10F8B1888138D30B88C0D8F4773
+:1053A0000D4950B4990499100D0D5F04DD1009FFEB
+:1053B000029F800DBB029B8165508D851AB83AC053
+:1053C000F1C0800CF83808084264806B1BDD771947
+:1053D000DD7829B67E8D18B0DD6DDA0500A0880075
+:1053E000C08CC0A063FEF30082138B161DDD8828DD
+:1053F000600AC0E02EC4800D880202B20B99239F80
+:1054000020C0D298229D2122600CB2BB0C2D11A786
+:10541000DD28D28508BB0B18DD702BD685A8222E7F
+:1054200024CFD2A0D10F9E1B851A2A6C748B185BD7
+:10543000FF168E1B63FEA300C087C0900AF938795F
+:10544000809263FF86C020D10F9E1B2A6C74C0B16E
+:105450008D1858053B8E1B851A63FE7E886B821360
+:10546000891608BE110ECE0202920B9E25B4991E1B
+:10547000DD639F200E88029822C0EF04D8110E88A9
+:10548000029824C0E49E21C080D2A02B600C286426
+:10549000071CDD510CBE11A7EE2DE285ACBB28B474
+:1054A000CF0D9D0B2DE685D10F0000006C1004C0C0
+:1054B00020D10F006C10048633C071C03060000131
+:1054C000B13300310400741A0462017460F1D10F29
+:1054D0006C1004022A02033B025BFFF61CDD391B41
+:1054E000DD83C79F88B009A903098A019AB0798032
+:1054F0001EC0F00FE4311DDD300002002BD2821EF1
+:10550000DD7C2AC1020EBB022BD6820AE431D10F08
+:1055100028C102C19009880208084F28C50208E482
+:1055200031D10F006C1004C0C00CE43112DD251A1B
+:10553000DD2200020029A28218DD701BDD6E26210B
+:10554000020B990108660129A68226250206E4318C
+:1055500014DD6B15DD66236A9023261685502426FC
+:1055600015252617222C50D10F0000006C1008D6EC
+:10557000102B0A64291AB41ADD0F0D23111CDD103B
+:105580000F2511B81898130E551118DD5DAC55A8EC
+:1055900038AA332C80FF2A80FEA933288D01298068
+:1055A0000108AA112880000CAA02088811098802A3
+:1055B00008AA1C288C0828160458086814DD010A5B
+:1055C000A70224411A2A30802B120407AA2858085F
+:1055D00063B1338B13B4559A6004AC28B4662C566F
+:1055E0002B7B69E016DD3A9412C050C0D017DCF472
+:1055F0009D15D370D4102F60802E60829F169E1749
+:10560000881672891A8D128C402A607F0DCC282B47
+:105610003A200CAA28580851C0B10ABE372E354886
+:105620008F1772F91A8D128C402A60810DCC282BAD
+:105630003A200CAA28580849C0B10ABE372E354A6C
+:10564000B233B444B1556952B6B466C0508F15B880
+:1056500077D370B2FF9F156EF899D10F6C1004C00C
+:1056600021D10F006C1004270A001CDCD31FDCE4DE
+:105670001EDCE71DDCD01ADD141BDD22C02824B09F
+:10568000006D2A75AA48288080C09164806100411D
+:105690000415DCCBC03125503600361A06550105FD
+:1056A00095390C56110C66082962966E974D0D5966
+:1056B0000A29922468900812DD0602420872993B7A
+:1056C00023629512DCC8CB349F300282020E440262
+:1056D000C092993194329233AD52246295C0902495
+:1056E0004C1024669524B0002924A0AA42292480C5
+:1056F000B177B14404044224B400D10FD10FD10FCB
+:105700006C10041ADCAC2AA00058021C5BFFD50206
+:105710002A02033B025BFFD11BDCAAC9A12CB10208
+:10572000C0D40DCC020C0C4F2CB5020CE431D10FBF
+:10573000C0A00AE43118DCA00002002F828219DC2C
+:10574000B32EB10209FF022F86820EE431D10F0081
+:105750006C1004C02002E43114DC9A16DC970002BD
+:1057600000226282234102732F0603E431C020D15C
+:105770000F19DCE61ADCE52841020A2A0109880132
+:105780002A668228450208E43115DCDC12DCE125BA
+:105790004621D10F6C1004292006289CF96480A0B2
+:1057A0002A9CFD65A0968A288D262F0A087AD9049E
+:1057B0002B221FC8BD2C206464C0812E22090EAE8E
+:1057C0000C66E0782B200C1EDC7C0CBC11AECC28C7
+:1057D000C28619DC7A78F3026000AD09B90A299211
+:1057E000A36890082E220009EE0C65E09B29C28573
+:1057F0001FDC846490929F90C0E41FDC919E9128EE
+:10580000200AC0E09E930F8802989288200F880299
+:1058100098942F20079A979D962F950A2E24072853
+:10582000200629206468833328C28512DC6B288C0B
+:1058300020A2B22E24CF28C685C020D10FC020D1EF
+:105840000F2A206A0111020A2A4165AF52DA20C0EC
+:10585000B05805EA64AFE5C021D10F00649FC81FAE
+:10586000DC582D20168FF209DD0C00F10400DD1A42
+:10587000ADAD9D2912DC5928C285A2B22E24CF28B5
+:105880008C2028C685C020D10FC021D10F00000078
+:105890006C1004260A001BDC9F15DC4928206517C4
+:1058A000DC46288CFE6480940C4D110DBD082CD272
+:1058B000F52BD2F42ED2F77CB13DB4BB2BD6F47BC2
+:1058C000E9052BD2F62BD6F47CB92C2AD2F62AD6AF
+:1058D000F52AD6F406E4310002002872822AFAFF83
+:1058E000004104290A012F510200991A0A9903095B
+:1058F00088012876820FE4312624652BD2F48E5C51
+:105900002CD2F5B0EE9E5C7BCB1629D2F62FD2F7C7
+:105910000CB80C09FF0C08FF0C0F2F14C8F960001D
+:10592000320BCA0C0A2A14CEA92B5102C0C20CBBDE
+:10593000020B0B4F2B55020BE431D10F00DB30DA99
+:10594000205BFF941BDC7464AF5D0C4D11ADBD6337
+:10595000FFA8000006E4310002002F728218DC303C
+:105960002E510208FF022F76820EE431D10F000083
+:105970006C1004C03003E43116DC1015DC11000299
+:105980000024628274472118DC64875C084801287F
+:105990006682CD7319DC620C2A11AA99229283299E
+:1059A00092847291038220CC292B51020BE431C0E6
+:1059B00020D10F001FDC5B2E51020FEE012E55028D
+:1059C0000EE431B02DB17C9C5C12DC5608DD112D4B
+:1059D000561DD10F6C10061BDBF71EDBF922B00041
+:1059E0001ADC526F23721DDC39C04818DC511FDCF1
+:1059F0004FDC10D5C083F000808600508A6D4A4F7E
+:105A00000F35110D34092440800B560A296294B1D8
+:105A1000330E55092251480F44110C440A8740099E
+:105A2000A80C02883622514907883608770CA899B5
+:105A30002966949740296295874109A80C02883607
+:105A400007883608770CA899296695974103034281
+:105A5000B13808084298F0D10F1CDC3613DC372728
+:105A6000B0002332B5647057C091C0D016DC351534
+:105A7000DC33C0402AC00003884328C4006D793C51
+:105A8000004104B14400971A7780148E502FB295CC
+:105A90002DB695AFEE2EED2006EE369E5060001826
+:105AA00077A00983509D5023B69560000223B295DC
+:105AB000223D2006223622B695B455B8BBD10F0040
+:105AC00003884328C400D10F6C1004C04004E431A3
+:105AD00015DC1D000200885013DC1CCB815BFFBD70
+:105AE0001CDC1B0C2D11ADCC2BC2822AC28394501E
+:105AF0007BAB142EC28429C2850ABD0C0E990C0DF5
+:105B0000990C0929146000050BA90C092914993076
+:105B100015DBAC2A51020AE4312A2CFC58004B2B2D
+:105B200032000AA2022BBCFF9B30CCB6C8A4D2A084
+:105B3000D10F000004E4311EDBA00002002DE28240
+:105B40002FBAFF2C51020FDD012DE6820CE431D17A
+:105B50000F0000006C1004D10F0000006C1004C096
+:105B600020D10F006C100413DBFAC0D103230923EA
+:105B7000318FC0A06F340260008D19DB8F1BDB906A
+:105B800017DBF30C2811A8772672832572822CFA72
+:105B9000FF76514788502E7285255C0425768275E4
+:105BA000E9052572842576827659292E72842E760F
+:105BB000822E76830AE431000200239282002104BF
+:105BC0002FB10200D61A0C66030633012396820F0A
+:105BD000E43126728325728260000200D8A07659D3
+:105BE000220AE43100020023928200210400D21A2A
+:105BF0002FB1020C22030232012296820FE431D22D
+:105C000080D10F00D280D10FC020D10F6C1004DBE7
+:105C100030862015DB68280A00282502DA2028B003
+:105C2000002CB00705880A28824C2D0A010B800041
+:105C3000DBA065AFE61ADB610A4A0A29A2A3C7BF47
+:105C4000769101D10F2BA6A3D10F00006C1004C0D8
+:105C5000D1C7CF1BDB5B19DB5817DB560C2811A80B
+:105C60007786758574C0A076516288508E77B4555A
+:105C7000957475E903857695747659278F769F75A7
+:105C80009F740AE431000200239282B42E2FB102E5
+:105C900000E10400D61A0C66030633012396820F36
+:105CA000E431867583747639280AE4310002002EC7
+:105CB0009282B42200210424B10200DF1A0CFF03F7
+:105CC0000FEE012E968204E431D280D10FD8A07657
+:105CD00051D6D280D10F00006C1004290A801EDB3F
+:105CE0005D1FDB5D1CDB350C2B11ACBB2C2CFC2DA4
+:105CF000B2850FCC029ED19CD0C051C07013DB592D
+:105D000014DB5818DB562AB285A82804240A234637
+:105D100091A986B8AA2AB685A98827849F25649F59
+:105D2000D10F00006C100419DB8B0C2A11A9A98972
+:105D300090C484798B761BDB79ABAC2AC2832CC2EE
+:105D4000847AC1688AA02BBC30D3A064A05E0B2BE0
+:105D50000A2CB2A319DB4268C0071DDB7FD30F7D7D
+:105D6000C94AA929299D0129901F68913270A6036B
+:105D7000D3A0CA9E689210C7AF2AB6A32A2CFC5B98
+:105D8000FFB3D230D10F000013DB7503A3018C31B8
+:105D90001DDB130C8C140DCC012CB6A363FFDC00AF
+:105DA000C020D10FDA205BFFCCC020D10FC020D1A2
+:105DB0000F0000006C1004DB30C0D019DAFEDA20CE
+:105DC00028300022300708481209880A28824CDC53
+:105DD000200B80001BDAF90C4A11ABAA29A2840916
+:105DE000290B29A684D10F006C1004C04118DAF2E7
+:105DF00017DAF40C2611A727277038A866256286C3
+:105E0000007104A35500441A75414822628415DBD1
+:105E10001502320BC922882117DAF10884140744CD
+:105E200001754905C834C020D10FD10F0809471D9D
+:105E3000DB4AC0B28E201FDADF0E0E43AFEC2BC45C
+:105E4000A00FEE0A2DE6242A6284C0200A990B29AD
+:105E50006684D10FC020D10F6C1004DB30C0D01885
+:105E6000DAD5DA2025300022300708580A28824C7B
+:105E7000DC200B80008931709E121BDACF0C4A1196
+:105E8000ABAA29A28409290B29A684D10F09C952DA
+:105E900068532600910418DACAC0A12F811600AAFF
+:105EA0001A0AFF022F85161EDAC40C4D11AEDD2C26
+:105EB000D2840C2C0B2CD684D10FC0811FDAC1B830
+:105EC0009A0A0A472EF11600A10400881A08EE0269
+:105ED0002EF5161DDAB90C4C11ADCC2BC2840B2B50
+:105EE0000B2BC684D10F00006C1004DB30C0D0191E
+:105EF000DAB1DA2028300022300709880A28824CDB
+:105F0000DC200B80001CDAAC0C4B11ACBB2AB28439
+:105F10000A2A0B2AB684D10F6C1004C04118DAA6E5
+:105F200016DAA80C2711A626266038A87225228624
+:105F3000006104A35500441A7541082222840232EC
+:105F40000BD10F00C020D10F6C100415DB050249E6
+:105F5000142956112452120208430F8811C07300ED
+:105F6000810400361A008104C78F00771A0877036E
+:105F7000074401064402245612D10F006C10066E2D
+:105F800023026000AC6420A7C0A0851013DADD16E0
+:105F9000DAF4C040A6AA2BA2AE0B19416490666841
+:105FA000915D68925268933C2AA2AA283C7F288C73
+:105FB0007F0A0A4D2980012880002AACF208881146
+:105FC0000988027589462B3D0129B0002BB00108D4
+:105FD00099110B99027A9934B8332A2A00B1447284
+:105FE00049B160004A7FBF0715DADF63FFB90000DF
+:105FF000253AE863FFB10000253AE863FFA90000F5
+:10600000250A6463FFA1C05A63FF9C0000705F080B
+:106010002534FF058C142C34FE70AF0B0A8D142E22
+:106020003D012AE4012DE400DA405BFD5063FFA747
+:10603000D10FD10F6C10041ADA6219DA5F1CDACAB8
+:106040001BDACBC080C07160000D00000022A438B4
+:10605000B1AA299C107B915F26928679C2156E6247
+:1060600062C0206D080AB12200210400741A764B28
+:10607000DB63FFEE2292850D6311032514645FCF6D
+:10608000D650032D436DD9039820B4220644146DD5
+:106090004922982098219822982398249825982678
+:1060A000982798289829982A982B982C982D982EDC
+:1060B000982F222C4063FF971EDA4027E68027E6C0
+:1060C00081D10F00C02063FF830000006C1004C06A
+:1060D00062C04112DA3B1ADA3713DA522AA00023DF
+:1060E000322D19DA9F2BACFE2992AE6EA30260000E
+:1060F0008E090E402D1AC2C2CD0EDC392C251A6431
+:10610000B0895BFF9E15DA9A1ADA952B3AE80A3ABB
+:10611000015805922B211A0ABB28D3A09B50580581
+:10612000A92B52000ABB082A0A005805A815DA91C3
+:106130002D21022C3AE80C3C2804DD022D25029C7E
+:10614000505805A08B50AABBC0A15805A01CDA8AE4
+:106150002D21020C3C2806DD0213DA882D25029C35
+:10616000305805988B30AABBC0A25805982A210246
+:10617000C0B40BAA020A0A4F2A25025805ACD10F57
+:10618000242423C3CC2C251A63FF760018DA801C44
+:10619000DA7C19DA7D1BDA7B17DA4F85202E0AFDAF
+:1061A0001FDA7C2D203624F47A24F47E24F4820E27
+:1061B000DD0124F4862E0AF707552806DD02C07596
+:1061C0000EDD01050506AB5BA959C0E8AC5C24C433
+:1061D000AB0EDD0227C4AC2E0ADFA85527B4EC0EA7
+:1061E000DD0124B4EBC2E027942C0EDD0224942BB5
+:1061F0002E0A800D0D4627546C24546B0EDD022DA3
+:10620000243663FEFC0000006C10042A0A302B0ABE
+:10621000035BFF4D12DA53C390292616C3A1C0B306
+:10622000C08A2826175BFF48C03CC3B12B26161A2C
+:10623000D9E42AA02023261764A079C3A2C0B15BA9
+:10624000FF42C3A2C0B15BFF40C3C22C2616C2AF3F
+:10625000C0B12326175BFF3CC28F282616C0FE2F35
+:106260002617C2E22E26162A0AA1C0B1C0D82D26B2
+:10627000175BFF352A0AA12A2616C3A6C0B3C1920E
+:106280002926175BFF31C3C62C2616C1B32A0AA2E2
+:106290002B2617C0B35BFF2C290AA2292616C1851D
+:1062A000282617C2FB2F2616C0E72E26171DDA391F
+:1062B0002D2610D10FC3A2C0B35BFF2363FF820062
+:1062C0006C10041CDA031BD9ED18DA3317DA341614
+:1062D000DA3415DA34C0E0C0D414D9FF1FD9B9C0FC
+:1062E000288FF06D2A36DAC0D9C07C5B020FC90C4A
+:1062F0001CD9F90C9C28A8C3A6C22A36802A25845A
+:10630000A4C2A7CC2D248C2B248A2B24872E248B4B
+:10631000B1BB2E369F2C369E2C369DB1AC1CD9D7E6
+:106320001BDA22C0286D2A33DAC0D9C07C5B020F89
+:10633000C90C1CD9E80C9C28A8C3A6C22A36802BFD
+:106340002584A4C2B1BBA7CC2D248C2E248B2A2457
+:106350008A2E369F2C369E2C369DB1ACC07919D929
+:10636000D81BDA1413DA121ADA1218DA1314D9D97C
+:1063700016DA1304F42812DA1204660C040506A2D5
+:1063800052A858AA5AA3539B3029A50027848AC033
+:1063900091C0A52A848C29848B17DA0B18DA0AA7F6
+:1063A0005726361D26361E2E361F16DA0813DA0833
+:1063B000A65504330C2826C82E75002D54AC2E5437
+:1063C000AB2E54AA2326E62326E52E26E7D10F007E
+:1063D0006C100613D99417D9E224723D2232937FB0
+:1063E0002F0B6D08052832937F8F0263FFF3C0C423
+:1063F000C0B01AD973C051D94004593929A4206EAC
+:1064000044020BB502C3281ED96EDDB025E4220577
+:106410002D392DE421C0501ED9EF19D9DF18D9DF4D
+:1064200016D9E11DD9ED94102A724517D9AB6DA983
+:106430004BD450B3557A5B17DF50756B071FD9608B
+:106440008FF00F5F0C12D9A302F228AE2222D68160
+:10645000D54013D9A0746B0715D95A855005450C42
+:10646000035328B145A73FA832A93322369D2236CF
+:106470009E2436802B369F2BF48B2CF48C14D969F8
+:1064800024424DC030041414C84C6D0806B13304C6
+:106490001414C84263FFF20015D947C44000310408
+:1064A0001AD948C0D193A200DD1AC138B0DD9DA32E
+:1064B00018D95D2B824D29824E29A5202882537A36
+:1064C000871E2C54008E106FE45D12D93D2F2121C0
+:1064D0002321202F251F04330C23252023251ED103
+:1064E0000FC06218D99F88807E87D98910265400F2
+:1064F0006F94191BD9332AB1200A1A1404AA0C2A42
+:10650000B5202AB5212AB51E2AB51FD10F1BD92CBB
+:106510002AB1200A1A1403AA0C2AB5202AB5212A66
+:10652000B51E2AB51FD10F001CD9262BC1212DC1A4
+:10653000202BC51F03DD0C2DC5202DC51ED10F003E
+:106540006C100619D91F14D98612D93615D9A3C7CC
+:106550003FC0E02E56A82E56A92E56AA2E56AB2383
+:10656000262918D946DB101CD99DC0D42A42452DB6
+:1065700016012C160000B0890A880C98905BFF94D5
+:106580002C22E318D90F0C5C149C842B22E48C84FD
+:10659000B1BB0B5B140CBB0C9B852A22E50A5A1479
+:1065A0002A86062922CD0959142986072F22892FE8
+:1065B00086095BFF435BFF1423463BC1B01ED90035
+:1065C0001DD9602AE1022D463A0BAA020A0A4F2A77
+:1065D000E5025804965BFEBD5BFE96C050C0B01647
+:1065E000D8F614D8FE17D96FC0C0C73E93122C2618
+:1065F0002DC0306000440000007F9F0FB155091985
+:1066000014659FF4C0500AA9027FA7EF18D8EADAF0
+:106610005008580A28822C2B0A000B8000005104D5
+:10662000D2A0C091C7AF00991A0A99039912CE3827
+:1066300064206BD3202B20072516032C12022A621C
+:10664000827CA86318D8DC01110208580A28822C21
+:10665000DA500B8000D2A0643FD58A310A8A140434
+:10666000AA01C82A2B22010B8B1404BB017BA9456C
+:10667000DDA07A7B081DD8D22DD2000DAD0CDB3009
+:1066800019D8CD1AD91488130ADA28DC801DD951FB
+:1066900009880A28823C0DAA080B8000652F93D335
+:1066A00020C0B063FF9400007FAF34B155005004A8
+:1066B0000A091963FF42DAB07B7B081AD8C12AA203
+:1066C000000ABA0C1BD9048C310BAB280C8A141CA1
+:1066D000D941ACBB1CD94104AA012BC68163FF8FF1
+:1066E000645F60C050C0B0C7CE9C1263FF5500000D
+:1066F0006C100427221EC08008E4311BD8AF0002B2
+:10670000002AB28219D8AF003104C06100661A298C
+:1067100091020A6A022AB68209E43115D90C0C38B2
+:1067200011A8532832822432842A8CFC7841102903
+:1067300021022A368297A0096902292502D10F0079
+:106740002B21022C32850B6B022CCCFC2C36829731
+:10675000C02B2502D10F00006C1004C0E71DD89299
+:106760001CD8940D4911D7208B228A200B4B0BD2B9
+:10677000A007A80C9B72288CF4C8346F8E026000AE
+:10678000A31FD88AA298AF7B78B334C93DC081C01B
+:10679000F0028F380F0F42C9FA2CD67ED5206D4AF1
+:1067A0000500308800508C887008980878B16DD248
+:1067B000A09870D10FC0F0038F387FE0DE63FFD860
+:1067C000027B0CAFBB0B990C643047D830C0F1C0D2
+:1067D0005002F5380505426450792CD67E0B3612EE
+:1067E0002F6C100F4F366DFA0500808800208C0644
+:1067F000440CC081C05003B208237C0C03853805CB
+:10680000054264505A2CD67ED30F6D4A050020886D
+:1068100000308CD2A0A798BC889870D10FD2A0BCB1
+:10682000799970D10FD2302BAD08C0F1C0500BF563
+:1068300038050542CB542CD67E083F14260A100F8B
+:10684000660C0646366D6A0500208800B08C8270A2
+:1068500063FF2D00C05003F53875E08063FF7A00B8
+:10686000C06002863876E09F63FF9900C05003F550
+:106870003875E0C463FFBE006C1004D62068520F68
+:10688000695324DA20DB30DC405800F7D2A0D10F66
+:10689000DA20DB30DC405800F49A2424240EC02196
+:1068A00022640FC020D10F00B83BB04C2A2C748951
+:1068B000242D200E2E200FA4DDB1EE2E240FB0DDEE
+:1068C0002D240E2890072D9003A488B088B1DD2DCB
+:1068D00094032894075BFFA069511DC0E082242A1D
+:1068E000600F18D8BF2A240329600E8F202924079F
+:1068F00008FF029F209E64D10FC020D10F0000002E
+:106900006C1004942319D8B7C0B3083A110BAA022B
+:10691000992019D8299A2116D827C05028929D2548
+:1069200064A2288C1828969DD10F00006C100428B2
+:106930002066C038232406B788282466D10F0000BB
+:106940006C10060D3C111AD819D820035B0C862256
+:106950000D55118221AA8902320B928105630C9395
+:10696000820C550C792B54CB531CD8111DD80FC059
+:10697000F7A256C031C0A0043A380A0A42769343BF
+:10698000044302C9AB2CD67ED30F6DBA0500208814
+:1069900000308C8281A25272917D92818382C83EA6
+:1069A000D10FC071C06002763876F0DB63FFD5008E
+:1069B000C020BC89998199809282D10F222DF892B2
+:1069C0008163FFA219D7FA02860CA9669611D940F5
+:1069D000063612961006BB0C64A0442CD67E8A1094
+:1069E000D30F6DAA0500208800908CBC828311C053
+:1069F000E0A433240A01034E380E0E42CAEC2CD612
+:106A00007E6DBA0500208800308C821102520CA2E3
+:106A100082BC22928163FF83BC82928163FF7C00EF
+:106A2000C06002363876F0B563FFAF00C070024731
+:106A30003877F0CC63FFC6006C100414D7EBC1525A
+:106A4000A424CA3128221D73811C292102659016B5
+:106A50002A300075A912022A02033B022C3007C01B
+:106A6000D25801D5653FDCD10F2B300703BB0B0B90
+:106A7000BA0274B3022ABDF8D3A063FFC4000000B9
+:106A80006C1004292006C0706E9741292102C08F26
+:106A90002A2014C0B62B240606AA022A24147980C0
+:106AA000022725022A221E2C221D7AC10EC8ABDA2B
+:106AB00020DB302C0A00033D025BF7F96450892D7E
+:106AC00021020D0D4CC9D3C020D10F00002E9CFB1C
+:106AD00064E0962F21020F0F4C65F0A51AD7B71E60
+:106AE000D7B529A29EC08A798B712BE22668B004A3
+:106AF0008C207BC96629A29D1FD7B264905D9790B8
+:106B0000C0C31DD7C62B21049D9608BB110CBB0228
+:106B10009B919B971CD7C3C08527E4A22BA29D28DD
+:106B200024068DFA282102B0DD2BBC302BA69D9DBA
+:106B3000FA0C8802282502C8D2C020D10F8EF91283
+:106B4000D7B92E2689C020D10F283000688938DABD
+:106B500020DB30DC4058004463FF6300022A022B34
+:106B60000A065800D3220A00D10F655010293000C0
+:106B7000689924022A02033B02DC4058003BC020F3
+:106B8000D10FD270D10F00002A2C74033B02044CA9
+:106B9000025BFEF163FF2700DB30DC402A2C745BD4
+:106BA000FEEEC020D10F00006C1004C83F8926887B
+:106BB00029A399992609880C080848282525CC522C
+:106BC000C020D10FDB402A2C745BF92FD2A0D10F4B
+:106BD0006C1004D820D73082220D451105220C926A
+:106BE0008264207407420B13D771D420A3837323CC
+:106BF00002242DF8858074514CBC82C0906D08161B
+:106C000000408800708C773903D720C0918680744B
+:106C10003901D42074610263FFE2CA98C097C04171
+:106C20001BD7F2C0A00B8B0C0B4A380A0A42C9AA28
+:106C30001DD75E1CD75F2CD67EC140D30F6D4A0591
+:106C400000208800308C9780D270D10FBC8FC0E0BC
+:106C50000F4E387E90E263FFD6BC8292819280C054
+:106C6000209282D10F0000006C1006C0D71CD74EB6
+:106C70001BD7500D4911D7202E221F28221D0E4E42
+:106C80000BD280078A0C2E761F2AAC80C8346FAED8
+:106C9000026000CB2F0A801AD754A29EAA7A7EA344
+:106CA0003FC93FC0E1C05002E538050542CA552B37
+:106CB000C67EDB20D30F6D4A0500308800B08C2ED5
+:106CC000721DAE9E0EA50C645086D2802E761DC01D
+:106CD00091298403D10FC05003E53875D0D363FFE9
+:106CE000CD15D741027E0CA5EE643051C0A1250A16
+:106CF0000002A538033A020505426450922BC67E75
+:106D00000E35129510255C10054536D30F6D5A05CA
+:106D100000A08800208CC0A1A3E2C05023FA800309
+:106D2000730C03A538AF730505426450722BC67E01
+:106D3000851005450C6D5A0500208800308CD280E6
+:106D4000C0A10E9B0CAB7BAFBB2B761D2A8403D15D
+:106D50000FD280C0C1AF7D2D761D2C8403D10F00D2
+:106D6000D2302E8D08C0F1C0500EF538050542CB4B
+:106D7000592BC67E0A3F14C1600F660C064636D3F7
+:106D80000F6D6A0500208800E08C22721D63FF03EE
+:106D9000C061C05003653875D80263FF6263FF5C51
+:106DA000C05002A53875D08763FF8100C06003F62C
+:106DB0003876D0BF63FFB9006C10042A2015292053
+:106DC0001614D6FF0A990CCB9D2E200B04ED092B2F
+:106DD000D1208F2809BC36ACAA0CBB0C2BD5200ABD
+:106DE0000A472A2415CAAF8B438942B0A8009104F0
+:106DF00000881AA8FF0FBB029B278F260FB80C78BC
+:106E00003B1AC020D10F0000292102C0A20A99021A
+:106E1000292502C021D10F008B2763FFDC2BD12055
+:106E20000CAA0C0A0A472A2415ACBB2BD520C9AEE4
+:106E30008B438C288F42B0AD00F10400DD1AADCC3D
+:106E40000CBB029B27DA20B7EB580019C021D10FE9
+:106E50009F2763FFEF0000006C100428203C643083
+:106E60004705306000073E01053EB156076539050C
+:106E70004928C77FA933030641076603B1660606A2
+:106E800041A6337E871E222125291AFC732B150269
+:106E9000380C09816000063E01023EB124064239E9
+:106EA00003220AD10FD230D10FC05163FFC00000BE
+:106EB0006C100427221EC08008E4311DD6BF0002DA
+:106EC000002CD2821BD6BF003104C06100661A2B91
+:106ED000B1020C6C022CD6820BE43119D7440C3A67
+:106EE00011AA932832829780253282243284B455A5
+:106EF00025368275410A292102096902292502D114
+:106F00000F2A21022B32830A6A022B36822A25029B
+:106F1000D10F00006C100418D6A80C2711087708B0
+:106F2000267286253C04765B1315D6A405220A2218
+:106F300022A3682002742904227285D10FC020D1B7
+:106F40000F0000006C100419D6A727221EC080096C
+:106F5000770208E4311DD6980002002CD2821BD69D
+:106F600098003104C06100661A2BB1020C6C022C2F
+:106F7000D6820BE43119D71D0C3A11AA932832821C
+:106F80009780253282243284B45525368275410B90
+:106F90002A21020A6A022A2502D10F002B21022C83
+:106FA00032830B6B022C36822B2502D10F0000009E
+:106FB0006C10041BD6810C2A11ABAA29A286B43806
+:106FC000798B221BD67E19D6A50B2B0A2BB2A309CF
+:106FD000290868B00274B90D299D0129901F6E928D
+:106FE0000822A285D10FC020D10FC892C020D10F96
+:106FF000DA205BEE88C020D10F0000006C10041472
+:10700000D66E28429E19D66B6F88026000BA29920C
+:10701000266890078A2009AA0C65A0AC2A429DC068
+:10702000DC64A0A42B200C19D6650CBC11A4CC2EBA
+:10703000C28609B90A7ED30260009A2992A3689099
+:10704000078D2009DD0C65D08C25C2856450862D06
+:107050002104C0306ED80D2C2066B8CC0C0C472C07
+:10706000246665C07B1CD6E218D66B1AD66219D688
+:10707000731DD667C0E49E519D508F209357935542
+:1070800099539A569A5408FF021AD6839F5288261B
+:107090009F5A9E599D58935E9C5D935C9A5B08082D
+:1070A00048058811985FC0D81FD64C0CB911A49917
+:1070B000289285AFBF23F4CF288C402896858E2652
+:1070C0002D24069E29C020D10FCA33DA20C0B65B1A
+:1070D000FF78C72FD10FC93ADA205BFF75C72FD1D0
+:1070E0000FDBD05BFE072324662B200C63FF7500AB
+:1070F000C72FD10FC72FD10F6C1004C85B292006F2
+:1071000068941C689607C020D10FC020D10FDA20E8
+:10711000DB30DC40DD502E0A005BFE59D2A0D10FDF
+:107120002E200C18D6250CEF11A8FF29F286C08856
+:10713000798B791AD6220AEA0A2AA2A368A0048BBC
+:10714000207AB96823F2856430621BD62C290A8024
+:107150002C20682820672D21040B881104DD1108DC
+:10716000DD020DCC02C0842D4A100DCC021DD624A8
+:1071700098319D308A2B99379C340BAA02C0C09C51
+:10718000359C369A322A2C74DB4028F285C0D328ED
+:107190008C2028F6852C25042D24061FD60FDD40D3
+:1071A000AFEE2CE4CF5BFDE6D2A0D10F00DA20DBFE
+:1071B000E05BFF3FC020D10F6C100AD6302A2006BA
+:1071C00024160128ACF86583862B2122C0F22A21DF
+:1071D00024CC572AAC010A0A4F2A25247ABB026024
+:1071E000037F2C21020C0C4C65C3192E22158D3205
+:1071F000C0910EDD0C65D39088381ED5EF64836B8B
+:107200008C37C0B8C0960CB9399914B49A9A120D3B
+:10721000991199138F6718D5EAC9FB2880217F83BC
+:10722000168B142C22002A200C5BFF61D4A064A3CF
+:10723000B38F6760002800002B200C89120CBA1154
+:10724000AEAA2CA2861DD5DD7C9B3E0DBD0A2DD29B
+:10725000A368D00488207D893024A28564436427F4
+:10726000212E07F73607F90C6F9D01D7F0DA20DBE6
+:1072700070C1C42D211F5BFEF889268827DDA00977
+:10728000880C7A8B179A10600006C04063FFCC0010
+:1072900000DA208B105BFEC88D1065A267C0E09EEF
+:1072A000488C649C498B658A669B4A9A4B97458FAC
+:1072B000677F7302600120CD529D10DA20DB302CF5
+:1072C00012015BFE698D10C051D6A08FA7C0C08A85
+:1072D00068974D9A4C8869896A984E994F8E6A8A48
+:1072E00069AE7E77EB01B1AA9E6A9A698B60C0A0F5
+:1072F0000B8E1477B701C0A1C091C08493159D1760
+:107300009516C0D025203CC030085801089338C0DD
+:1073100082083310085B010535400B9D3807DD10EE
+:107320000BAB100E19402A211F07991003DD020D27
+:10733000BB020553100933020A55112921250A2AD7
+:10734000140929140499110A99020933028A2B2974
+:1073500021040BAA021BD6270899110955020855CA
+:10736000020BAA029A408920881408991109880200
+:1073700019D5A61DD62109880298418B2A934695D6
+:107380004783150DBB0285168D179B448A65896658
+:10739000AACAA97C77CB01B1AA07FB0C9C669A65A7
+:1073A00088268E29AD87972607EE0C0E0E482E25CF
+:1073B000259B672B200C87131ED5800CB911AE9925
+:1073C000289285A78828968517D584C090A7BB29C1
+:1073D000B4CF871863FE3C008C60C0E0C091C0F061
+:1073E000C034C0B82A210428203C08AA110B8B0104
+:1073F000038301039F380B9B39C03208FF100388B9
+:1074000001089E380C881407EE100FEE0203880165
+:1074100008983905BF1029211F0ABB1107881008D9
+:10742000FF020BAA0218D57809291403AA022B21FE
+:107430002583200B2B1404BB110833110FBB020B47
+:1074400099028B148F2A0B33020833028B2B647042
+:10745000868868974D984C8769886A9341994697C2
+:107460004E984FC07077C701C0719A4718D5E30B8B
+:107470007C100CEC0208F802984418D5E00CBC0211
+:1074800008CC029C402A200C295CFEC0801FD54AF3
+:107490001CD5520CAE112B2124ACAAAFEEB0BB8F81
+:1074A000132CE28528A4CFAFCC2CE6852A22152BFD
+:1074B0002524B1AA2A26156490DBC9D28F262E2254
+:1074C000090DFF082F26060FEE0C0E0E482E25255F
+:1074D0006550E4C020D10F00C07093419F4499468D
+:1074E0009A4777C70A1CD5362CC022C0810C873832
+:1074F0001CD5C40B781008E80208B8020C88029862
+:107500004063FF8000CC57DA20DB608C115BFDD636
+:10751000292102689806689403C020D10F2B221EEF
+:10752000C0A029221D2A25027B9901C0B064BFE8B2
+:1075300013D5212CB00728B000DA2003880A28824E
+:107540004CC0D10B8000DBA065AFE763FFCA000031
+:1075500068A779DA20DB30DC40DD505BFEE7D2A0A3
+:10756000D10FC16DC19D29252C60000429252CD681
+:10757000902624672F2468DA20DB308C11DD502E12
+:107580000A805BFD3FD2A0D10FC168C1A82A252C7B
+:1075900063FFDD000000C8DF8C268B29ADCC9C2664
+:1075A0000CBB0C0B0B482B25252A2C74DB602C12F2
+:1075B000015BFD87D2A0D10F2A2C748B115BF6B230
+:1075C000D2A0D10FDA205BFE3A63FF3800DA20C088
+:1075D000B15BFE8A64ABF1655F352D2124B1DD2DF1
+:1075E000252463FF1FDA202B200C5BFE5663FF145B
+:1075F00012D5858220028257C82163FFFC12D581F3
+:1076000003E83004EE3005B13093209421952263D5
+:10761000FFFC000010D57D910092019302940311AC
+:10762000D554821001EA30A21101F031C04004E4C7
+:107630001600020011D5768210234A00032202921E
+:107640001011D540C021921004E4318403830282DA
+:1076500001810000D23001230000000010D56D919F
+:107660000092019302940311D543821001EA30A2E3
+:107670001101F131C04004E41600020011D564820A
+:107680001013D4E7032202921004E431840383022E
+:107690008201810000D330013300000010D55E91DB
+:1076A00000810165104981026510448103CF1F925A
+:1076B000019302940311D531821001EA30A2110125
+:1076C000F231C04004E41600020011D550821013BC
+:1076D000D4CF032202921004E43184038302820196
+:1076E000C010910391029101810000D43001430048
+:1076F00012D500C03028374028374428374828376B
+:107700004C233D017233ED03020063FFFC000000D7
+:1077100010D542910092019302940311D54082103A
+:10772000921011D4F28310032202921011D53D124F
+:10773000D5049210C04004E41600020011D5348232
+:107740001013D4EB032202921004E4318403830269
+:107750008201810000D53001530000006C10026EE0
+:10776000322FD620056F04043F04745B2A05440CB5
+:1077700000410400331A220A006D490D73630403AB
+:10778000660CB1220F2211031314736302222C0121
+:10779000D10FC83BD10F000073630CC021D10F0083
+:1077A0000000000044495630C020D10F6C10020088
+:1077B00040046B4C07032318020219D10F0203196E
+:1077C000C020D10F6C100202EA30D10F6C1002CC35
+:1077D0002503F03160000F006F220503F1316000D6
+:1077E000056F230503F231000200D10F6C1002CCAB
+:1077F0002502F030D10F00006F220402F130D10FCA
+:107800006F230402F230D10FC020D10F6C1002227E
+:107810000A20230A006D280E2837402837442837CD
+:107820004828374C233D01030200D10F6C1002029F
+:10783000E431D10F0A0000004368656C73696F2062
+:1078400046572044454255473D3020284275696CD3
+:1078500074204D6F6E204D61722020382031373AF0
+:1078600032383A3135205053542032303130206F85
+:107870006E20636C656F70617472612E61736963F1
+:1078800064657369676E6572732E636F6D3A2F68F6
+:107890006F6D652F66656C69782F772F66775F3718
+:1078A0002E392D6977617270292C205665727369A3
+:1078B0006F6E2054337878203030372E30612E3080
+:1078C00030202D20313030373061303010070A0041
+:0478D0000BDFE8756D
+:00000001FF
diff --git a/firmware/cxgb3/t3fw-7.4.0.bin.ihex b/firmware/cxgb3/t3fw-7.4.0.bin.ihex
deleted file mode 100644
index 38dda94..0000000
--- a/firmware/cxgb3/t3fw-7.4.0.bin.ihex
+++ /dev/null
@@ -1,1917 +0,0 @@
-:1000000060007400200380002003700000001000D6
-:1000100000002000E100028400070000E1000288E7
-:1000200000010000E0000000E00000A0010000006E
-:1000300044444440E3000183200200002001E0002A
-:100040002001FF101FFFD0001FFFC000E300043C91
-:100050000200000020006B741FFFC29020006BBCE8
-:100060001FFFC29420006BFC1FFFC29820006C7021
-:100070001FFFC29C200003C0C00000E43100EA3131
-:1000800000A13100A03103020002ED306E2A05000C
-:10009000ED3100020002160012FFDBC03014FFDA5F
-:1000A000D30FD30FD30F03431F244C107249F0D347
-:1000B0000FD30FD30F12FFD5230A00240A00D30F4A
-:1000C000D30FD30F03431F244C107249F0D30FD327
-:1000D0000FD30F14FFCE03421F14FFCB03421F1296
-:1000E000FFCCC0302D37302D37342D37382D373CED
-:1000F000233D017233ED00020012FFC4C0302F37E0
-:10010000002F37102F37202F3730233D017233ED6A
-:1001100000020012FFBEC0302737002737102737F4
-:1001200020273730233D017233ED03020012FFB95F
-:1001300013FFBA0C0200932012FFB913FFB90C028F
-:1001400000932012FFB8C0319320822012FFB71312
-:10015000FFB7932012FFB715FFB316FFB6C030D715
-:100160002005660160001B00000000000000000088
-:10017000043605000200D30FD30F05330C6E3B1479
-:100180000747140704437631E604360505330C6F40
-:100190003BED00020012FFA615FFA3230A00D720A3
-:1001A000070443043E0505330C0747146F3BF00377
-:1001B000020012FFA1C03014FFA1D30FD30FD30F41
-:1001C0009340B4447249F2D30FD30FD30F14FF9B63
-:1001D000834014FF9B834012FF9B230A0014FF9A65
-:1001E000D30FD30FD30F9340B4447249F2D30FD33C
-:1001F0000FD30F14FF95834012FF95C92F832084DE
-:10020000218522BC22743B0F8650B4559630B433FE
-:100210007433F463FFE60000653FE1655FDE12FFC3
-:100220007C230A0028374028374428374828374C91
-: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
-:10048000E30005E01FFFC0181FFFC290E30005E076
-:100490001FFFC2901FFFC290E30008581FFFC290C9
-:1004A0001FFFC58CE3000858200000002000016AEF
-:1004B000E3000B542000018020000180E3000CC009
-:1004C0002000020020000203E3000CC02000021CF8
-:1004D00020000220E3000CC420000220200002269D
-:1004E000E3000CC82000023C20000240E3000CD0D6
-:1004F0002000024020000249E3000CD42000024CFE
-:1005000020000250E3000CE02000025020000259BD
-:10051000E3000CE42000025C20000260E3000CF029
-:100520002000026020000269E3000CF42000026C4D
-:1005300020000270E3000D0020000270200002790C
-:10054000E3000D042000028C2000028CE3000D105B
-:100550002000029020000293E3000D10200002AC66
-:10056000200002B0E3000D14200002D0200002F2AF
-:10057000E3000D18200003B0200003B0E3000D3CA1
-:10058000200003B0200003B0E3000D3C200003B0C6
-:10059000200003B0E3000D3C200003B0200003B0B6
-:1005A000E3000D3C200003B020006D94E3000D3CFF
-:1005B00020006D9420006D94E3007720000000007F
-:1005C00000000000000000001FFC00001FFC0000F5
-:1005D0001FFFC5901FFFC67020006D9820006D980A
-:1005E000DEFFFE000000080CDEADBEEF1FFFC2A064
-:1005F0001FFCFE001FFFC0941FFFC5C0300000009D
-:10060000003FFFFF8040000010000000080FFFFFC8
-:100610001FFFC26D000FFFFF804FFFFF8000000033
-:1006200000000880B000000560500000600000007D
-:1006300040000011350000004100000010000001E2
-:100640002000000000001000400000000500000035
-:1006500080000019040000000000080010000005E0
-:10066000806000007000000020000009001FF800FA
-:100670008000001EA0000000F800000007FFFFFF40
-:100680000800000018000000010080014200000086
-:100690001FFFC21D1FFFC0DC000100806040000082
-:1006A0001A0000000C0000001000000A00003000DA
-:1006B000600008008000001C000100008000001A9B
-:1006C00080000018FC0000008000000100004000D5
-:1006D000030000008000040050000003FFFFBFFF84
-:1006E0001FFFC3D400000FFFFFFFF000000016D073
-:1006F0000000FFF7A50000001FFFC4B01FFFC4618A
-:100700000001000800000B20202FFF801FFFC455B0
-:1007100000002C00FFFEFFF800FFFFFF1FFFC57861
-:1007200000002000FFFFDFFF0000FFEF01001100CD
-:100730001FFFC3D21FFFC590FFFFEFFF0000FFFBAD
-:100740001FFFC6301FFFBEA0FFFFF7FF1FFFC064E3
-:100750000000FFFD1FFFC6200001FBD01FFFC5B03A
-:100760001FFFC6601FFFC591E0FFFE001FFFC5A071
-:10077000000080001FFFC53C1FFFC5B41FFFC068FD
-:100780001FFFC4D01FFCFFD8000100817FFFFFFFC7
-:10079000E1000600000027101FFCFE301FFCFE7069
-:1007A000E10002001FFFC5381FFFC5500003D090B5
-:1007B0001FFFC5642B5063802B5079802B50908095
-:1007C0002B50A6801FFFC4690100110F202FFE00CF
-:1007D00020300080202FFF000000FFFF0001FFF805
-:1007E0002B50B2002B50B208000100102B50B180EA
-:1007F0002B50B2802B50BA00000100112B50BD28A5
-:100800002B50BC802B50BDA020300000DFFFFE002D
-:100810005000000200C0000002000000FFFFF7F4DB
-:100820001FFFC06C000FF800044000000010000023
-:100830000C4000001C400000E00000A01FFFC5406D
-:100840001FFD00081FFFC5541FFFC5681FFFC57CA3
-:10085000E1000690E10006EC00000000000000004E
-:100860000000000000000000010000000000000087
-:100870000000000000000000201000402010004098
-:100880002010004020140080200C0000200C0000EC
-:10089000200C000020100040201400802014008054
-:1008A00020140080201800C0201C0100201C010022
-:1008B000201C010020200140201800C0201800C08A
-:1008C000201800C0201C0100201800C0201800C003
-:1008D000201800C0201C01002020014020200140E1
-:1008E00020200140202009402020094020200940EC
-:1008F0002020094020240980FFFFFFFFFFFFFFFFAA
-:10090000FFFFFFFF000000000000000000000000EB
-:100910000000000000000000200054902000536000
-:1009200020005490200054902000529C2000529CA3
-:100930002000529C200050DC200050DC200050D4CD
-:100940002000504020004EE820004CC820004A9C67
-:100950000000000000000000200054602000532C24
-:10096000200053D0200053D0200051842000518417
-:10097000200051842000518420005184200050CC5C
-:100980002000518420004E0820004C7820004A4866
-:10099000000000000000000020000BE820003A30BA
-:1009A000200004C02000463C20000BE0200041480D
-:1009B000200003F0200045FC20004A2420003E5483
-:1009C00020003D70200039AC2000383C200035ACC0
-:1009D0002000310C20003BCC20002D6C2000280092
-:1009E000200067182000238C2000206C2000201895
-:1009F00020001D04200018182000154820000E2C8F
-:100A000020000C2C2000110C200012F82000434084
-:100A100020003E0820000BF0200004C00000000071
-:100A200000000000000000000000000000000000C6
-:100A300000000000000000000000000000000000B6
-:100A400000000000000000000000000000000000A6
-:100A50000000000000000000000000000000000096
-:100A60000000000000000000000000000000000086
-:100A70000000000000000000000000000000000076
-:100A80000000000000000000000000000000000066
-:100A900000000000000000000000000032640000C0
-:100AA0000000000032640000640064006400640020
-:100AB00064006400640064000000000000000000A6
-:100AC0000000000000000000000000000000000026
-:100AD0000000000000000000000000000000000016
-:100AE0000000000000000000000000000000000006
-:100AF00000000000000000000000000000000000F6
-:100B000000001000000000000000000000000000D5
-:100B100000000000000000000000100000000000C5
-:100B200000000000000000000000000000432380DF
-:100B300000000000000000000000000000000000B5
-:100B400000000000000000000000000000000000A5
-:100B500000000000005C94015D94025E94035F94C9
-:100B60000043000000000000000000000000000042
-:100B70000000000000000000000000000000000075
-:100B80000000000000000000000000000000000065
-:100B900000000000005C90015D90025E90035F9099
-:100BA00000530000000000000000000000000000F2
-:100BB0000000000000000000000000000000000035
-:100BC0000000000000000000000000000000000025
-:100BD00000000000009C94001D90019D94029E94D2
-:100BE000039F94040894050994060A94070B940043
-:100BF00043000000000000000000000000000000B2
-:100C000000000000000000000000000000000000E4
-:100C100000000000009C90019D90029E90071D9096
-:100C2000039F90047890057990067A90077B900056
-:100C30005300000000000000000000000000000061
-:100C400000000000000000000000000000000000A4
-:100C50000000000000DC94001D9001DD9402DE9491
-:100C600003DF94040494050594060694070794088A
-:100C700008940909940A0A940B0B9400430000009D
-:100C80000000000000000000000000000000000064
-:100C90000000000000DC9001DD9002DE900B1D9052
-:100CA00003DF9004B49005B59006B69007B790089E
-:100CB000B89009B9900ABA900BBB9000530000009D
-:100CC00063FFFC0020006B5010FFFF0A00000000D3
-:100CD00020006B7400D23110FFFE0A0000000000FB
-:100CE00020006BBC00D33110FFFE0A0000000000A2
-:100CF00020006BFC00D43110FFFE0A000000000051
-:100D000020006C7000D53110FFFE0A0000000000CA
-:100D100063FFFC00E00000A012FFF7822002825770
-:100D2000C82163FFFC12FFF303E83004EE3005C076
-:100D30003093209421952263FFFC00001FFFD00018
-:100D4000000400201FFFC5901FFFC670200A00117D
-:100D5000FFFB13FFFB03E63101020016FFFA17FF4A
-:100D6000FAD30F776B069060B4667763F85415B5C5
-:100D7000541A610F140063FFF90000006C1004C0E6
-:100D800020D10F006C1004C0C71AEF06D830BC2B5E
-:100D9000D72085720D4211837105450B9572023380
-:100DA0000C2376017B3B04233D089371A32D12EEA7
-:100DB000FE19EEFEA2767D632C2E0A000882022820
-:100DC0000A01038E380E0E42C8EE29A67E6D4A0532
-:100DD00000208800308C8271D10FC0F0028F387FE4
-:100DE000C0EA63FFE400C0F1C050037E0CA2EE0E27
-:100DF0003D1208820203F538050542CB5729A67E2D
-:100E00002FDC100F4F366DFA0500208800308CBCA7
-:100E100075C03008E208280A01058338030342C977
-:100E20003E29A67E0D480CD30F6D8A050020880050
-:100E3000B08C8271D10FC05008F53875C0C163FF06
-:100E4000BBC06002863876C0DA63FFD46C1012161D
-:100E5000EED8C1F9C1E8C1C72B221E28221DC0D07F
-:100E60007B81312920060BB702299CFA655008289E
-:100E70002072288CFF28247264915C2AB0000CA890
-:100E80000C6481670EA90C6492B37FA13769AC2F03
-:100E90006000340000282006D7D0288CFACC572ACE
-:100EA00020722AACFF2A24726481352AD0000CA952
-:100EB0000C6491640EAC0C64C31B7FA10768AC0783
-:100EC000C020D10F002D25028A32C0900A6E5065D5
-:100ED000E5B5292467090F4765F5B12C200C1FEEF5
-:100EE000B50CCE11AFEE29E286B4487983026005D5
-:100EF0008219EEB109C90A2992A36890078F2009C7
-:100F0000FF0C65F56E2FE28564F56865559628221D
-:100F10001D7B8105D9B060000200C0908B9417EE54
-:100F2000A70B881487740B0B47A87718EEA509BB8D
-:100F30001008770297F018EEA317EEA408A8010B8B
-:100F400088020747021BEEA097F10B880298F22750
-:100F500090232B902204781006BB1007471208BB81
-:100F6000022890210777100C88100788020B88024E
-:100F700017EE988B3307BB0187340B880298F397E1
-:100F80009997F48B9587399BF588968B3898F688D6
-:100F90009797F99BF898F717EE8F28E28507C7080F
-:100FA0002D74CF08480B28E68565550F2B221E2887
-:100FB000221D7B89022B0A0064BF042CB00728B0D5
-:100FC00000DA2006880A28824CC0D10B8000DBA002
-:100FD00065AFE763FEE90000292072659E9C60040E
-:100FE000E72A207265AEC36004DE00002EB0032C39
-:100FF0002067D4E065C1058A328C330AFF500C4566
-:1010000054BC5564F4EB19EE74882A09A9010988C7
-:101010000C64821FC0926000DD2ED0032A2067D4AA
-:10102000E065A0D88A328B330AFC500B4554BC557E
-:1010300064C4BE19EE69882A09A9017989D50BEA29
-:101040005064A4E30CEE11C0F02F16132E16168A6E
-:10105000E78CE82A16128EE9DFC0AAEA7EAB01B15E
-:10106000CF0BA8506583468837DBC0AE89991E78C0
-:101070009B022BCC012B161B29120E2B0A002916C2
-:101080001A7FC3077FC9027EAB01C0B165B49D8BD7
-:10109000352F0A002A0A007AC30564C3CB2F0A0140
-:1010A00065F4892B12162B1619005104C0C100CC0F
-:1010B0001A2CCCFF2C16170CFC132C16182B121AFA
-:1010C0002A121BDC50581974C0D0C0902E5CF42C2E
-:1010D00012172812182F121B2A121A08FF010CAA25
-:1010E000018834074C0AAB8B2812192BC6162F86A1
-:1010F000082A86092E74102924672E70038975B179
-:10110000EA2A7403B09909490C659DB32B20672D19
-:10111000250265B3FA2B221E2C221D7BC901C0B00B
-:1011200064BD9C2CB00728B000DA2006880A28820B
-:101130004CC0D10B8000DBA065AFE763FD8189BAAD
-:10114000B19965909788341CEE2598BA8F331EEEBE
-:101150001E0F4F542FB42C8D2A8A320EDD020CAC98
-:10116000017DC9660A49516F92608A3375A65B2C6E
-:10117000B0130AED510DCD010D0D410C0C417DC98F
-:10118000492EB012B0EE65E3C6C0D08E378CB88A57
-:10119000368FB97CA3077AC9027EFB01C0D1CED9B4
-:1011A00088350AAD020E8E0878EB022DAC0189B7A6
-:1011B000DAC0AF9B79BB01B1CADCB0C0B07DA30778
-:1011C0007AD9027CEB01C0B164B161C09129246776
-:1011D000C020D10F00008ADAB1AA64A0C02C206719
-:1011E0002D250265C3111DEDF88A321EEDFD0DADF2
-:1011F000010EDD0C65D28A0A4E516FE20260028157
-:10120000C090292467090F4765F2F828221D7B89C1
-:10121000022B0A0064BCA82CB00728B000DA200614
-:10122000880A28824CC0D10B8000DBA065AFE76341
-:10123000FC8D00000CE9506492ED0CEF11C0802889
-:101240001611AFBF2F16198EF88BF7DAE08FF92B36
-:101250001610ABFB7FBB01B1EA0CA8506580D688A5
-:1012600037DCE0AF89991C789B022CEC012C161B13
-:1012700029120C2C0A0029161A7AE3077AE9027F50
-:10128000BB01C0C165C2A58B352C0A002A0A007AB1
-:10129000E30564E1CA2C0A0164CE0D60028E883435
-:1012A0001BEDCF98DA8F331EEDC80F4F542FD42C7F
-:1012B0008C2A8A320ECC020BAB010CBB0C65BF0A28
-:1012C0000A49516E920263FF018A330AAB5064BE31
-:1012D000F92CD0130AEE510ECE010E0E410C0C412A
-:1012E0000ECC0C65CEE42FD012B0FF65F26EC0B00C
-:1012F0008E378CD88A362FD2097CA3077AC9027E12
-:10130000FB01C0B165BEC38835DBA0AE8E78EB01B2
-:10131000B1AB89D7DAC0AF9D79DB01B1CAC0C07B60
-:10132000A3077AB9027DEB01C0C165CE9DC09029AB
-:101330002467C020D10F88378C3698140CE90C290B
-:10134000161408F80C981D78FB07281214B088288A
-:101350001614891D9F159B16C0F02B121429161AFE
-:101360002B161B8B147AE30B7AE90688158E1678F8
-:10137000EB01C0F165F1BA29121A2F12118A352E2C
-:10138000121B9A1AAFEE2F1210C0A0AF9F79FB016B
-:10139000B1EE9F11881AC0F098107AE30A7EA90571
-:1013A0002A12017A8B01C0F164F0816001838936D1
-:1013B0008B3799170BE80C981F09C90C291615785B
-:1013C000EB07281215B088281615D9C09A199E184F
-:1013D0008A1F2E12152A161A2E161BDAC0C0E08C90
-:1013E000177F930B7FA90688188F1978FB01C0E13E
-:1013F00065E13E29121A2F12138A352E121B9A1BF1
-:10140000AFEE2F1212C0A0AF9F79FB01B1EE9F1378
-:10141000881BC0F098127AE30A7EA9052A12037A83
-:101420008B01C0F165F10A2E12162E16192A121B15
-:10143000005104C0E100EE1AB0EE2E16170EFF1395
-:101440002F16180FCC01ACAA2F121A0EBC01ACFC3F
-:101450007FCB01B1AA2A161B2C161A63FC5E000072
-:101460007FB30263FE3163FE2B7EB30263FC306305
-:10147000FC2A00006450C0DA20DBC0581648C020A7
-:10148000D10FC09163FD7A00C09163FA44DA20DB8A
-:1014900070C0D12E0A80C09A2924682C7007581574
-:1014A00038D2A0D10F03470B18ED4FDB70A8287876
-:1014B00073022B7DF8D9B063FA6100002A2C74DB2B
-:1014C00040580EB363FAE4000029221D2D25027B4B
-:1014D0009901C0B0C9B62CB00728B000DA20068840
-:1014E0000A28824CC0D10B8000DBA065AFE7C0208A
-:1014F000D10FC09163FBFF00022A025802440AA2E6
-:1015000002060000022A025802410AA20206000056
-:10151000DB70DA20C0D12E0A80C09E2924682C708E
-:1015200007581517C020D10FC09463FBC9C096633C
-:10153000FBC4C09663FBBF002A2C74DB30DC405B2D
-:10154000FE11DBA0C2A02AB4002C200C63FF2700F0
-:101550008D358CB77DCB0263FDD263FC6D8F358EEC
-:10156000D77FEB0263FDC563FC6000006C1004C014
-:1015700020D10F006C1004C020D10F006C10042B80
-:10158000221E28221DC0A0C0942924062A25027BE1
-:101590008901DBA0C9B913ED06DA2028B0002CB010
-:1015A0000703880A28824CC0D10B8000DBA065AFFE
-:1015B000E7C020D10F0000006C10042C20062A2167
-:1015C0000268C80528CCF965812E0A094C6591048A
-:1015D0008F30C1B80F8F147FB00528212365812774
-:1015E00016ECF529629E6F98026000F819ECF1295B
-:1015F00092266890078A2009AA0C65A0E72A629DB6
-:1016000064A0E12B200C0CB911A6992D92866FD9FC
-:10161000026000DB1DECE90DBD0A2DD2A368D007E6
-:101620008E200DEE0C65E0C7279285C0E06470BF88
-:101630001DECEE68434E1CECED8A2B0CAA029A704E
-:1016400089200899110D99029971882A98748F320E
-:101650009F75282104088811987718ECDE0CBF11BB
-:10166000A6FF2DF285A8B82E84CF2DDC282DF68577
-:10167000C85A2A2C74DB40580E46D2A0D10FC02085
-:10168000D10F00000029CCF96490B12C206689317B
-:10169000B1CC0C0C472C24666EC60260008509F89C
-:1016A0005065807F1CECD38A2B0F08400B881008F4
-:1016B000AA020CAA029A7089200899110D99029920
-:1016C00071883398738C329C728A2A9A74893499FF
-:1016D0007563FF7D00CC57DA20DB30DC4058151DE8
-:1016E000C020D10F00DA20C0B65815AC63FFE5006A
-:1016F000DA205815AA63FFDC00DA20DB30DC40DD9D
-:1017000050581638D2A0D10FC858DA20DB30581400
-:101710008A2A210265AFBDC09409A9022925026366
-:10172000FFB200002B21045814351DECAFC0E02E91
-:1017300024668F302B200C0F8F1463FF662921380D
-:10174000C08879830263FF5B2C20662B2104B1CC17
-:101750000C0C472C24665814291DECA3C0E02E2441
-:10176000668F302B200C0F8F1463FF376C1004C072
-:10177000B7C0A116ECA015EC92D720D840B822C073
-:10178000400535029671957002A438040442C94B95
-:101790001AEC8519EC8629A67EC140D30F6D4A0547
-:1017A00000808800208C220A88A272D10FC05008C5
-:1017B000A53875B0E363FFD76C1006931394112915
-:1017C0002006655288C0716898052A9CF965A29820
-:1017D00016EC792921028A1309094C6590CD8AA05B
-:1017E0000A6A512AACFD65A0C2CC5FDB30DA208CDE
-:1017F000115814D8C0519A13C7BF9BA98E132EE25B
-:101800000968E0602F629E1DEC6A6FF80260008438
-:101810002DD22668D0052F22007DF9782C629DC735
-:101820009064C0709C108A132B200C2AA0200CBD41
-:1018300011A6DD0A4F14BFA809880129D286AF88F6
-:10184000288C09798B591FEC5C0FBF0A2FF2A36813
-:10185000F0052822007F894729D285D490659075AC
-:1018600060004300002B200C1FEC540CBD11A6DDC2
-:1018700029D2860FBF0A6E96102FF2A368F0048853
-:10188000207F890529D285659165DA20581543C9DD
-:101890005C6001FF00DA20C0B658154060000C0003
-:1018A000C09063FFB50000DA2058153C6551E48D07
-:1018B000138C11DBD08DD0022A020D6D515813AD5F
-:1018C0009A1364A1CEC75F8FA195A9C0510F0F478E
-:1018D0009F1163FEFD00C091C0F12820062C2066F8
-:1018E000288CF9A7CC0C0C472C24666FC6098D13E5
-:1018F0008DD170DE02290A00099D02648159C9D385
-:101900008A102B21045813BD8A13C0B02B24662ED5
-:10191000A2092AA0200E28141CEC338D1315EC27E5
-:10192000C1700A773685562DDC28AC2C9C12DED08F
-:10193000A8557CD3022EDDF8D3E0DA40055B02DC4B
-:10194000305BFF8AD4A028200CB455C0D02B0A8865
-:101950002F0A800C8C11A6CC29C285AF3FAB9929E8
-:10196000C6851CEC1CDEF0AC882D84CF2812022921
-:10197000120378F3022EFDF8289020D3E007880C9C
-:10198000C170080847289420087736657FAB891313
-:1019900013EC1A8990C0F47797491BEC18C1CA2838
-:1019A00021048513099E4006EE1187530488118592
-:1019B000520E88020C88029BA09FA18F2B9DA59898
-:1019C000A497A795A603FF029FA22C200C1EEC0152
-:1019D000AECE0CCC1106CC082BC2852DE4CF2BBC8F
-:1019E000202BC6852A2C748B11580D69D2A0D10FDB
-:1019F00028203DC0E07C877F2E24670E0A4765A023
-:101A00007B1AEBFF88201EEBED8F138EE48FF4081A
-:101A100088110A88020F8F14AFEE1FEBFA98910F0E
-:101A2000EE029E901EEBF9C0801AEBEA2CD285AA3A
-:101A3000BAB8CC28A4CF2CD6852C21022F20720E28
-:101A4000CC02B1FF2F24722C2502C020D10F8713A6
-:101A5000877007074763FD6E282138C099798B028C
-:101A600063FE9ADDF063FE9500DA20DB308C11DD39
-:101A70005058155CD2A0D10FC0E163FF7A8B138C54
-:101A800011DD50C0AA2E0A802A2468DA205813BC1F
-:101A9000D2A0D10FC020D10F6C1006292102C0D0D6
-:101AA0007597102A32047FA70A8B357FBF052D2535
-:101AB000020DD902090C4C65C18216EBBE1EEBBCAF
-:101AC00028629EC0FA78F30260018829E2266890B5
-:101AD000078A2009AA0C65A17A2A629DDFA064A169
-:101AE000772B200C0CBC11A6CC29C286C08C798324
-:101AF0000260015719EBB109B90A2992A36890074E
-:101B0000882009880C65814327C2851CEBB364716A
-:101B10003A8931098B140CBB016FB11D2C20669FD3
-:101B200010B1CC0C0C472C24666EC6026001400933
-:101B3000FF5065F13A8A102AAC188934C0C47F97E7
-:101B40003C18EBB31BEBB28F359C719B708B209DC7
-:101B50007408BB029B72C08298751BEBAE0F0840E5
-:101B60009B730F881198777FF70B2F2102284A006B
-:101B700008FF022F2502C0B4600004000000C0B0BE
-:101B80007E97048F362F25227D97048837282521BC
-:101B90007C9736C0F1C0900AF9382F3C20090942E1
-:101BA00064908619EB8018EB8128967E00F08800FF
-:101BB000A08C00F08800A08C00F08800A08C2A6225
-:101BC0009D2DE4A22AAC182A669D89307797388F1C
-:101BD000338A3218EB8A07BE0B2C2104B4BB04CC29
-:101BE0001198E0C08498E1882B9DE59AE69FE71A5A
-:101BF000EB82099F4006FF110FCC020A880298E28F
-:101C0000C1FC0FCC022CE604C9B82C200C1EEB71D1
-:101C10000CCA11AECC06AA0829A2852DC4CF09B9D9
-:101C20000B29A685CF5CC020D10FC081C0900F8941
-:101C300038C08779880263FF7263FF6600CC57DA89
-:101C400020DB30DC405813C3C020D10FDA205814F9
-:101C50005363FFE8C0A063FE82DA20C0B658144F79
-:101C600063FFD900DB402A2C74580CC9D2A0D10FD5
-:101C70008A102B21045812E11EEB4EC0D02D246691
-:101C800063FEB1006C1006D62019EB491EEB4B2801
-:101C9000610217EB4808084C65805F8A300A6A5178
-:101CA00069A3572B729E6EB83F2A922668A0048CB7
-:101CB000607AC9342A729D2C4CFECAAB2B600CB6DC
-:101CC0004F0CBD11A7DD28D2860EBE0A78FB269CDC
-:101CD000112EE2A32C160068E0052F62007EF91594
-:101CE00022D285CF2560000D00DA60C0B658142BD3
-:101CF000C85A60010F00DA60581428655106DC40AC
-:101D0000DB308D30DA600D6D5158129AD3A064A08B
-:101D1000F384A1C05104044763FF6D00C0B02C6080
-:101D2000668931B1CC0C0C472C64666FC602709684
-:101D30000A2B61045812B1C0B02B64666550B42AF6
-:101D40003C10C0E7DC20C0D1C0F002DF380F0F42EA
-:101D500064F09019EB1418EB1528967E8D106DDA4F
-:101D60000500A08800C08CC0A089301DEB247797A7
-:101D70005388328C108F3302CE0BC02492E1226143
-:101D8000049DE00422118D6B9BE59FE798E61FEB15
-:101D90001A0998400688110822020FDD02C18D9DA4
-:101DA000E208220292E4B4C22E600C1FEB0A0CE897
-:101DB00011A7882C8285AFEE0C220B2BE4CF228654
-:101DC00085D2A0D10F28600CD2A08C1119EB020C87
-:101DD0008D11A988A7DD2ED2852B84CF0ECC0B2C9C
-:101DE000D685D10FC0F00ADF387FE80263FF6C634D
-:101DF000FF6000002A6C74C0B2DC20DD4058128FF6
-:101E0000C0B063FF63C020D10F0000006C10042C31
-:101E1000221D2A221EC049D320293006243468C03E
-:101E2000407AC105DDA060000200C0D06E9738C0C6
-:101E30008F2E0A802B3014C0962934060EBB022E3A
-:101E400031022B34147E8004243502DE407AC10E28
-:101E5000C8ABDBD0DA302C0A00580AE52E31020E6E
-:101E60000F4CC8FEC020D10F6895F8283102080831
-:101E70004C658FEF1AEAD01CEACE2BA29EC09A7B4B
-:101E80009B462BC22668B0048D307BD93B29A29D8E
-:101E9000C0E3CB9394901BEAE02D31049B9608DDC0
-:101EA000110EDD029D979D9112EADDC0E524C4A2CA
-:101EB0002E34062F310228A29D02FF02288C3028E2
-:101EC000A69D2F3502C020D10FDA30C0B65813B30B
-:101ED000C020D10F6C1006292006689805289CF9AF
-:101EE00065825D29210209094C659210CD51DB30D4
-:101EF000DA20044C02581317C051D3A0C7AF2A36BA
-:101F00000AC0E019EAAD1DEAB31FEAAC8A3A16EA44
-:101F1000A9B1AC64C13528629E6F88026001F129C5
-:101F2000DC332992266890078B2009BB0C65B1E051
-:101F300027629DC08E6471D82B200C0CBC11A6CCDE
-:101F400029C2867983026001D219EA9B09B90A295C
-:101F500092A3971068900828220009880C6581BB1D
-:101F600027C2856471B5292006299CF96491EC2C5F
-:101F700020668931B1CC0C0C472C24666EC60260F9
-:101F800001A109F85065819B883689F4088C14AC4E
-:101F9000991CEA8B0C99022C2104997019EAA1086A
-:101FA00008479971892A09881008990218EA9E0839
-:101FB000990299722830132930120488100699105A
-:101FC00008990228302C9A740C881008C8020988D5
-:101FD00002987389379975883898768A39C0819ABA
-:101FE000771AEA918935987B99780989140A9902B8
-:101FF000997A8A30893277A73618EA808F33987CAD
-:10200000C084987D882B2E76112976122F7613198D
-:10201000EA7A0A9F4006FF1104CA110988020FAA32
-:1020200002987EC1F90FAA022A7610C0AA600001A8
-:10203000C0A6ADBF0CBC11A6CC29C2852EF4CF0919
-:10204000A90B29C685655107C020D10F2B200C0C88
-:10205000BC1106CC0828C28609B90A6F8902600142
-:102060002E2992A36890082A220009AA0C65A11FB4
-:102070002AC28564A11928203D08284064808C84E8
-:102080003504841464408485F574537F8436048455
-:1020900014644077745374293013C08C79886CC0F1
-:1020A000902924670908476580ED882089F48435E4
-:1020B0001FEA55048414A4940F440294A014EA5017
-:1020C00008881104880298A1843698A3048414A473
-:1020D000990F990299A219EA4CADB428C2852E44F1
-:1020E000CF288C1028C6852821022F20720988024B
-:1020F000B2FF2F2472282502C020D10F00CC57DA5E
-:1021000020DB30DC40581293C020D10FC09163FF18
-:102110008FDA20C0B658132163FFE100DA2058138C
-:102120001F63FFD88A102B21045811B41DEA2A1FFF
-:10213000EA232B200CC0E02E24668A3A63FE480076
-:1021400000DA20DB30DC40DD505813A6D2A0D10FDE
-:102150002A2C74DB40580B8ED2A0D10F292138C015
-:102160008879830263FE202A12002C20662B21042A
-:102170002CCC010C0C472C24665811A01DEA161F0C
-:10218000EA0F2B200CC0E02E24668A3A63FDF8008B
-:10219000DA2058130263FF64DA205BFF1CD2A0D15F
-:1021A0000F0000006C10089515C061C1B0D9402A1D
-:1021B000203DC0400BAA010A64382A2006291606D1
-:1021C00068A8052CACF965C33B1DE9FC6440052FEC
-:1021D000120564F29C2621021EE9F806064C65628F
-:1021E000E315E9F46440D98A352930039A140A9931
-:1021F0000C6490CC2C200C8B149C110CCC11A5CC15
-:102200009C122CC286B4BB7CB3026002D38F110E29
-:10221000FE0A2EE2A368E0098620D30F0E660C6545
-:1022200062BE88122882856482B6891464905EDA60
-:1022300080D9308C201EE9F21FE9F31DE9E08B14F0
-:102240008DD4D4B07FB718B88A293C10853608C61B
-:10225000110E66029681058514A5D50F550295804D
-:102260000418146D8927889608CB110888140EBBB2
-:1022700002A8D8299C200F88029BA198A088929B35
-:10228000A3088814A8D80F880298A22AAC1019E9CC
-:10229000DEC0C08F141EE9CF86128D11286285AE74
-:1022A000DD08FF0B2CD4CF2821022F66858B352A21
-:1022B0002072098802ABAA2825022A2472C020D1E4
-:1022C0000F29529E18E9BB6F9802600208288226E7
-:1022D00068800829220008990C6591F92A529DC14D
-:1022E000CA9A1364A1EF2B200C2620060CB811A566
-:1022F000882D82860EBE0A7DC3026002022EE2A3F2
-:1023000068E0082F22000EFF0C65F1F3288285DEBD
-:10231000806481FF9810266CF96461FF2C20668828
-:1023200031B1CC0C0C472C24666EC6026001BC088F
-:10233000FD5065D1B617E9BD19E9A21AE9A92C210A
-:10234000048B2D2830102F211D0C88100BFB090C3D
-:1023500088020A880209BB026441528910C04D9B61
-:1023600090979198928D35D9E064D06CD730DBD0BE
-:10237000D8307FD713273C10BCE92632168C39960B
-:10238000E69CE78A37B4389AE80B13146430492A7C
-:10239000821686799A9696978C778A7D9C982B825E
-:1023A000172C7C209A9A2A9C189B99867BB03BB864
-:1023B000896DB9218BC996A52692162AAC18B899B1
-:1023C0009BA196A08BC786CD9BA22B921596A49B12
-:1023D000A386CB2CCC2026A605C0346BD4200D3B85
-:1023E0000C0DD8090E880A7FB705C0909988BC8863
-:1023F000C0900B1A126DAA069988998B288C18C068
-:10240000D01BE98C1CE98B16E981B1FF2A211C2322
-:10241000E6130F0F4F26E6122F251D7FA906C0F0E9
-:10242000C08028251D05F6111AE97A8F202BE615A4
-:102430002CE6162DE61726E6180AFA022AE61429D3
-:102440002006299CF96490FF29200C8D15C0801A64
-:10245000E9610C9C11AA99A5CCDA202BC28528949D
-:10246000CF0B4B0B2BC685C0B08C1658118AD2A04F
-:10247000D10F8A356FA548D8308BD56DA90C8A86C7
-:102480000A8A14CBA97AB337288C10C08028246715
-:10249000080B4765B112DA20DB302C12065811AD5B
-:1024A000D3A0C0C1C0D02DA4039C1563FD268636E1
-:1024B00064610C8910C04D9B909791989263FEA423
-:1024C000C08163FFC78A15CCA7DA20DB308C165891
-:1024D00011A1C020D10FDA20C0B658123063FFE43A
-:1024E00000DA208B1158122D63FFD9009E178A1332
-:1024F0002B21045810C28E17C0B02B246663FE3403
-:10250000C08063FE09DA20DB308C16DD505812B52E
-:10251000D2A0D10FDA2058122163FFA82D2138C094
-:10252000C87DC30263FE0D8A132B21042C206698FC
-:1025300017B1CC0C0C472C24665810B08E17C0D0A5
-:102540002D246663FDEE0000262138B06606064F96
-:10255000262538656EF128206A7F870508294164A1
-:1025600090A5C0D01BE92619E93426200723E61BD5
-:10257000B16609FA022BE61A28200A2DE61D2AE682
-:102580001E09880228E61C882606064728E6202B16
-:10259000220826E53E2BE6212D24072C20062A20A2
-:1025A0006468C347B44463FE9EDB30DA208D15C0F7
-:1025B000CE2E0A802C24688C165810F1D2A0D10F90
-:1025C0008E102A321616E8FD0A2A1486662BE612A9
-:1025D00097E127E61328E614AA6609660296E02E1C
-:1025E000EC4869ED50C14663FD7A000064AFB41950
-:1025F000E8F328201689920A880C00910400881AB2
-:10260000A8B8982963FF9C002B21046EB81E2C20CB
-:1026100066B8CC0C0C472C2466C9C09E178A135888
-:1026200010778E17C0348F20C0D02D2466C0682646
-:10263000240663FF2C008D35C08064D04AD9E0DCCD
-:1026400030DBE0DF301AE8FDB188B4FF17E8FD8623
-:10265000C9249DFF8DC82CCC102D46300767012D55
-:1026600046320A66011DE8F7264631AD6D2D463328
-:1026700026F21597B796B684C3BCBB94B58D3529A1
-:102680009C107D83C22F211DC14663FD4B000000BD
-:102690006C1006292006289CF86582BF2921022B90
-:1026A000200C09094C6590E116E8C30CBA11A6AAE2
-:1026B0002DA2862C0A127DC30260028C19E8BF0984
-:1026C000B90A2992A36890078C2009CC0C65C278BE
-:1026D00029A2856492722D629E1AE8B56FD80260B5
-:1026E000026E2AA22629160168A0082B22000ABB26
-:1026F0000C65B25C29629DC18C6492542A21200A27
-:10270000806099102C203CC7EF000F3E010B3EB1BA
-:10271000BD0FDB390BBB098F260DBD112DDC1C0D48
-:102720000D410EDD038E27B1DD0D0D410FEE0C0DB9
-:10273000BB0B2BBC1C0BB7027EC71C2C21257BCBF3
-:10274000162D1AFC0CBA0C0DA16000093E01073EC3
-:10275000B1780987390B770A77EB0260020A2C21DE
-:1027600023282121B1CC0C0C4F2C25237C8B29B0A4
-:10277000CD2D2523C855DA20DB3058106F292102D2
-:10278000CC96C0E80E9E022E2502CC57DA20DB3014
-:10279000DC405810F0C020D10F2C20668931B1CC1C
-:1027A0000C0C472C24666EC6026001D309FD5065EF
-:1027B000D1CD2F0A012E301129221464E0112822D4
-:1027C0001B090C4400C10400FA1A0A880228261BBF
-:1027D0002E3010C0A0C0B0941295131CE878883039
-:1027E0002CC022088D14778704C0F10CFA38C04140
-:1027F000C0F225203CC0840858010F5F010F4B3800
-:1028000005354007BB10C0F0084F3808FF100FBB5C
-:102810000228ECFEC0F0084F38842B0BA8100AFFEA
-:10282000102A21200F88020B880208440218E8862B
-:102830008F110844022821250A2A14082814048824
-:10284000110A88022A210494F08B2004E41008BBAA
-:102850001104BB02C04A04BB029BF1842A08AB11DD
-:102860000BEB0294F40A54110B44020555100D1B96
-:102870004094F707BB100B5502085502C08195F62E
-:102880008433C05094F3B1948B3295F898F99BF24D
-:10289000C080C1BC24261499FA9BF598FB85389515
-:1028A000FC843A94FD8B3B9BFE883998FF85352547
-:1028B000F6108436851324F6118B3784122BF6120A
-:1028C000C0B064C07E89307797438D3288332E3014
-:1028D000108F111CE84A0999400699112CF614C072
-:1028E000C42CF6158C2B2DF61A28F61B2BF6190482
-:1028F000A81109880208EE0219E840C18008EE021A
-:1029000009C90229F6162EF618C09E600001C09A69
-:102910002F200C18E8300CFE11A8FFA6EE2DE28542
-:102920002BF4CF0D9D0B2DE685C87F8A268929A71C
-:10293000AA9A260A990C090948292525655050C0EC
-:1029400020D10F00C09A63FFC6DA2058111463FE2D
-:1029500038DA20C0B658111163FE2E0068973C2B60
-:102960009CFD64BE24C020D10FDA20DB705810CD4E
-:10297000C0C0C0D10ADA390ADC3865CDE063FE098F
-:102980008A102B2104580F9DC0B02B246663FE21B2
-:10299000DB402A2C7458097ED2A0D10FDA20580FC0
-:1029A000A263FCF76C1004C020D10F006C10042946
-:1029B0000A801EE8261FE8261CE7FF0C2B11ACBB83
-:1029C0002C2CFC2DB2850FCC029ED19CD0C051C0C6
-:1029D0007013E82214E82118E81F2AB285A82804F9
-:1029E000240A234691A986B8AA2AB685A9882784ED
-:1029F0009F25649FD10F00006C100AD6302830103C
-:102A0000292006288CF964829B68980B2A9CF9651A
-:102A1000A1B2022A02580F8489371BE7E8C89164E3
-:102A2000520E2A21020A0C4C65C2588D3019E7E17A
-:102A300074D7052E212365E29E2F929E1AE7DD6F43
-:102A4000F8026002532AA22668A0082C22000ACCB1
-:102A50000C65C2442A929D64A23E9A151FE7D78D49
-:102A600067C1E6C8DD2B620618E7D564B00528808B
-:102A7000217B8B432B200C18E7CF0CBC11A8CC2951
-:102A8000C28679EB460FBE0A2EE2A368E0052F222C
-:102A9000007EF9372CC2859C1864C2332B212F8706
-:102AA000660B7B360B790C6F9D266ED2462C203D33
-:102AB0007BC740CE5560001E2A200CC1B28C205826
-:102AC00010F79A1864A2458D6763FFCFC0C063FFFB
-:102AD000C5D7B063FFD300C0E06000022E60030ED4
-:102AE000DB0C6EB20EDC700CEA11AA6A2AAC20581C
-:102AF0000199D7A0DA20DB70C1C82D212058109190
-:102B00008C268B279A160CBB0C7AB3348F188963EA
-:102B100099F3886298F28E659EF82D60108A189D50
-:102B20001768D729C0D09DA92C22182B22139CAB43
-:102B30009BAA97A58E667E7302600097CF586000AF
-:102B40001FDA208B1658105765A13863FFBDC0816E
-:102B5000C0908F18C0A29AF999FB98FA97F563FF75
-:102B6000D2DB30DA20DC40580FFBC051D6A0C0C009
-:102B70002BA0102CA4039B172C1208022A02066B10
-:102B800002DF702D60038E179D149E100CDD11C0A6
-:102B9000E0AD6D2DDC205801188C148B16ACAC2CDC
-:102BA00064038A268929ABAA0A990C9A26886609A1
-:102BB000094829252507880C98662F2218A7FF2F7A
-:102BC000261863FE96DA20DB30DC40DD5058110514
-:102BD000D2A0D10FC0302C20668961B1CC0C0C473B
-:102BE0002C24666EC6026000D2C03009FD5065D04C
-:102BF000CA8E6764E069647066DB608C18DF70DA27
-:102C0000202D60038E170CDD119E10AD6D2DDC2084
-:102C10001EE78D5800F9232618DA208B16DC402F8A
-:102C20002213DD50B1FF2F2613580F9AD2A0D10FD7
-:102C30000028203D084840658DE76F953EDA308DCD
-:102C4000B56D990C8CA80C8C14CACF7CD32D2AACF2
-:102C500010C090292467090D4764DDC5600092000B
-:102C60002C1208066B022D6C20077F028E17DA20CB
-:102C70009E101EE77458007D63FF9A00C09163FFA9
-:102C8000D1000000655081DA20DB60DC40580FB1D4
-:102C9000C020C0F02FA403D10FDA20C0B658103FD7
-:102CA00063FFE000006F950263FD6CDA20DB30DC2F
-:102CB00040DD50C4E0580F32D2A0D10F8A152B212D
-:102CC00004580ECE232466286010981763FF210055
-:102CD000DA2058103263FFABC858DB30DA20580FC7
-:102CE000162A210265AF9CC09409A9022925026316
-:102CF000FF91DB30DC40DD50C0A32E0A802A24681F
-:102D0000DA20580F1FD2A0D10FC020D10FDA202B0C
-:102D1000200C58104763FF6B6C1004282006C0621B
-:102D2000288CF8658125C050C7DF2B221BC0E12A03
-:102D3000206B29212300A104B099292523B1AA00E1
-:102D4000EC1A0BC4010A0A442A246B04E4390DCCA2
-:102D5000030CBB012B261B64406929200C1BE715C3
-:102D60000C9A110BAA082FA2861BE7136FF90260B9
-:102D700000B60B9B0A2BB2A368B0082C22000BCC28
-:102D80000C65C0A42BA2851DE73664B09B8C2B2458
-:102D900021040DCC029CB08820C0C50888110C8885
-:102DA0000298B1882A08441198B48F3494B79FB51B
-:102DB000C0401EE7082DA2850E9E0825E4CF2DDC1D
-:102DC000282DA68529210209094C68941A689820A3
-:102DD000C9402A210265A00B2A221E2B221D7AB18E
-:102DE0000265A079C020D10F2C212365CFDE6000C1
-:102DF000082E21212D21237EDBD52B221E2F221DE3
-:102E00002525027BF901C0B064BFC413E6E92CB0EC
-:102E10000728B000DA2003880A28824CC0D10B8032
-:102E200000DBA065AFE763FFA62A2C74C0B02C0AB4
-:102E300002580E081CE70C9CA08B2008BB1106BB97
-:102E4000029BA1893499A263FF790000262468DAE5
-:102E500020DB30DC40DD50581063D2A0D10FDA20E7
-:102E60002B200C580FCEC020D10F00006C1006078D
-:102E70003D14C080DC30DB40DA20C047C02123BCD9
-:102E800030032838080842774001B1DD64815A1EBA
-:102E9000E6C519E6C629E67ED30F6DDA050050882F
-:102EA00000308CC0E0C02025A03C14E6C4B6D38F0F
-:102EB000C0C0D00F87142440220F8940941077F7A8
-:102EC00004C081048238C0F10B2810C044C0220421
-:102ED000540104FD3802520102FE3808DD10821C44
-:102EE00007EE100E6E020EDD02242CFEC0E004FE82
-:102EF000380AEE100E88020D88028DAB1EE6B4086B
-:102F0000D8020E880298B0C0E80428100E5E018432
-:102F1000A025A125084411084402052514045511D3
-:102F2000043402C0810E8E3994B18FAA84109FB4EC
-:102F300075660C26A11FC0F2062614600009000069
-:102F400026A120C0F20626140565020F7701078727
-:102F50003905E61007781008660206550295B62571
-:102F6000A1040AE61108581108280208660296B75B
-:102F7000C060644056649053067E11C0F489C288D4
-:102F8000C30B340B96459847994618E69B9F41041E
-:102F900059110E99021FE699020E4708D80298426D
-:102FA0000E99029F40C1E00E990299442FA00CB4E3
-:102FB000380CF91114E6881EE67FA4FFAE992E9214
-:102FC0008526F4CF0E880B289685D10F2BA00C1FD9
-:102FD000E6791CE6800CBE11ACBBAFEE2DE2852677
-:102FE000B4CF0D3D0B2DE685D10FC0800528387874
-:102FF000480263FEA263FE966C1006C0C06570F1C5
-:103000008830C030088714778712C0B0C0A619E690
-:103010006B299022C030CC97C031600003C0B0C093
-:10302000A6C0E0C091C0D4C08225203C0B3F1097C1
-:1030300012831CC0700858010D5D01089738C080CC
-:103040000B9838077710048810086802087702C0C8
-:10305000800D98382D3CFE0888100D9E388D2B0A67
-:10306000EE1008EE0207EE020CB8100FDD02053B71
-:10307000400EDD029D408920043D100899110D99F4
-:10308000022D210409A90208DD119941872A05B9F9
-:10309000100D3D020ABB110DBB02087702974428B0
-:1030A00021258712082814048811071E4007EE10F6
-:1030B0000E990275660926211F0626146000060077
-:1030C0002621200626140868029B47098802984694
-:1030D00029200CD2C0C0800C9E111BE63E1FE63595
-:1030E000AB99AFEE2DE2852894CF0DAD0B2DE68583
-:1030F000D10FDD40C0A6C0B08E51CAE0B2AAB1BBAC
-:103100002DDC108F500E7836981008770C9FD898C9
-:10311000D989538F52991199DB9FDA7E8309B1CCFB
-:10312000255C10C97763FFCF88108D1108E70C97D5
-:1031300051AD8DD7F078DB01B1F79D5397528830B0
-:10314000C030088714088840648ED565BEC963FE08
-:10315000BC0000006C1004D720B03A8820C0308238
-:1031600021CAA0742B1E2972046D080FC980C99151
-:103170008575B133A2527A3B0B742B0863FFE900CB
-:10318000649FECD10FD240D10F0000006C100AD622
-:10319000302E3027D950DA4015E6092430269A150A
-:1031A00029160464E0026493732920062A9CF865BA
-:1031B000A3CE2A2102270A040A0B4C65B3978C3050
-:1031C00074C7052D212365D4A0C0A62B0A032C2289
-:1031D00000580F0B64A3B917E5F78E389A1664E30D
-:1031E000BA2F6027285021C9F37E8311C2B08C20EA
-:1031F0002A200C580F2AD7A0CDA16004A200C2B08B
-:103200008C202A200C580EFED7A064A4862F212ED5
-:103210008B680FBF360FB90C6F9D54296027D5B04E
-:103220006E920528203D7B8F4CDA20DB50C1C42DE7
-:10323000211F580EC48B269A189A1989272AAC3850
-:103240000B990C7A93538963C08099738F62987835
-:103250009F728E659E798D679D7B8C6695759C7A35
-:103260008E687E53026000B18B1465B050600038E8
-:10327000DBF063FFA5008A14C9A92E60030E9B0C26
-:103280006EB2A5DC500CEA11AA6A2AAC285BFFB129
-:10329000D5A063FF93C0E063FFE2DA208B18580EDD
-:1032A0008165A2B163FF9E0000DA20DB308C1558E7
-:1032B0000E29D6A0C0C0C0D12D16042CA403DC70EA
-:1032C000DA20DB60DF502D6003C0E09E109D171EEA
-:1032D000E5D20CDD110D6D082DDC285BFF478E66F5
-:1032E0008F678817AF5FA8A828640375FB01B1EE4C
-:1032F0008A189E669F6789268829AA9909880C9949
-:10330000268E6808084805EE0C28252515E5AC9E94
-:103310006865EECC63FEE6000000C9432F21232B35
-:1033200021212FFC010F0F4F2F25237FBB026003AC
-:10333000142C20668961B1CC0C0C472C24666EC617
-:103340000260022809FD5065D22264E1B62E602792
-:1033500064E1B0DC70DF50DA20DB601EE5C32D6075
-:1033600003C08098100CDD11AD6D2DDC285BFF22B1
-:10337000644181C0442B0A008C202A200C580EA0E6
-:103380000AA70265A00FC0B02C22002A200C580EFC
-:103390009CD7A064AFEFDA20C1BCC1C82D21208F1B
-:1033A000188E268929AFEE9E260E990C0909482908
-:1033B0002525580E64C090C050C0C288609A191E5E
-:1033C000E57FC0A12EE022088F14778704C0810E0C
-:1033D0008938C0800B93102D203C2921200CDC0162
-:1033E00004DB010929140BA8380CA5380D3D401C3D
-:1033F000E5968B2B088810075510085502053302F7
-:103400002821250F154003BB020CBB0207551005F0
-:10341000D3100828140ADD11048811098802053325
-:10342000022921040833029B70C0808A201BE58F8B
-:1034300008AA110BAA029A71C0A1852A93769574E5
-:1034400008931103DD020ADD029D778C63C1DC9CC9
-:10345000738B6298789A799B72232214C0C0B1351D
-:103460002526149C7B9D75937A2B621A9B7C2A627D
-:103470001C9A7D28621D987E25621B957F2362170A
-:103480002376102D62182D76112C62192C76126479
-:10349000E0B98E6077E73DC0FE13E5571DE558C1E2
-:1034A000818A628B630495110E9C4006CC110C55E9
-:1034B00002247615085502C0802D76148D2B2B76AC
-:1034C0001B2A761A28761925761803DD022D761622
-:1034D0006000030000C0FA2E200C19E53E18E53507
-:1034E000A9E90CEE11A8EEC0802DE2852894CF0D3D
-:1034F000FD0B2DE685DA208B198C158D14580D6582
-:10350000D2A0D10FDC70DF50DB602D6C28C0A01E74
-:10351000E5569A10DA205BFE5563FE53002B203DE2
-:103520000B4B4065BC826FE527DA308F556DE90C97
-:103530008EAA0E8E14C9E87EF3162AAC10C090290C
-:103540002467090F4764FC6060015F00C0FA63FFF5
-:1035500085C09163FFE88814658168DA20DB608CA0
-:1035600015580D7CC020C09029A403D10F8A162BBA
-:103570002104580CA2C0A02A24668E6863FDCA00EC
-:10358000002B9CF965B0FDDA20580CA763FC2200E3
-:1035900000DA20C0B6580E0163FFBA002B200C0CD5
-:1035A000BE11A7EE2DE286C1C27DC30260011819CB
-:1035B000E50209B90A2992A36890082A220009AAFB
-:1035C0000C65A10326E2856460FD2C20668931B17B
-:1035D000CC0C0C472C24666FC60270960C8A162BF6
-:1035E0002104580C86C0D02D24668E3077E74D1C00
-:1035F000E5021BE5028F328833C0A42D21040E9909
-:103600004006991104DD1109DD029A61C19009DDBE
-:10361000029B60C0908B2B9D649F66986799650C98
-:10362000BB029B6228200C1AE4EBAA8A0C8811A723
-:10363000882F828529A4CF2FFC202F86858A1465A8
-:10364000A0A6C020D10FB0FC8B142C2523C8B70234
-:103650002A02066B02580CB82A210265AEF7C0D8C0
-:103660000DAD022D250263FEEC008E14C8E8DA20B1
-:10367000DB30580CB12A210265AEDA07AF022F25E4
-:103680000263FED100DA20DB308C158D14580E5504
-:10369000D2A0D10FDA202B200C580DC063FEB6004B
-:1036A000DA202B200C580DE263FEAADA20DB308CE6
-:1036B000152D12042E0A80280A00282468580CB000
-:1036C00063FAE500C020D10FDA20580DB48914CD7B
-:1036D00092DA20DB308C15580D1FDBA0C020C0A073
-:1036E0002AB403D10FC020D10F2A2C748B15580691
-:1036F00028D2A0D10F0000006C100C2821029410D9
-:1037000008084C6583621FE4AB29F29E6F98026043
-:1037100003661DE4A729D2266890082A220009AA78
-:103720000C65A3542CF29D64C34E2B200C0CB611D7
-:10373000AF66286286C1EC78E30260034619E49E16
-:1037400009B90A2992A36890078A2009AA0C65A3DF
-:103750003224628564432CC0E12A3109C0702724D9
-:103760006689359A11992A88369912982B89379843
-:1037700013992C883899140858149815982D89395C
-:103780002A25042E251D29251C283028C0922824EE
-:103790003C2A302908084798160989012A243D2A1D
-:1037A000311599170A094109A90C299CEC29251FF3
-:1037B0007E87192D2A000DA06000083E010A3EB147
-:1037C000AD08DA390EAA110A990C29251F2A211FE2
-:1037D00018E4A80A8160C1D0941A951B01083E0024
-:1037E000053EB184054839843C259CFC0D8836296A
-:1037F000201408AA1C8D3D2726182E26132E2614C9
-:103800002E261527261B2E246B27246727246808BD
-:10381000581C0909432924142932112A252E282548
-:103820002F27252427252527252C27252325252037
-:103830002425212D2522841A2D211C851B6FD202BF
-:10384000600209C0A099186D080AB1AA00A104007D
-:10385000E91A7D9B0263FFEE8918C080C0E1C07049
-:10386000C0D29B1D951B961C9C1E16E4722C203DFD
-:1038700015E4820C0B400DCC010BE7381DE4640A03
-:1038800077100CE8380B8810C0C49C410877029D63
-:1038900040B0A80988118B209C499D48954B9643C0
-:1038A000087702861418E47315E45A08770205BBFA
-:1038B000029B4A9B4297468812871108DA149A4E57
-:1038C0000D88100D77110877021AE44E06D8140DF2
-:1038D0006610087702974FC78F984D984C98458788
-:1038E0001598440715140D55110A5502954715E40E
-:1038F000638A262D46102D46182D46202C46112C65
-:1039000046192C46212B46122B461A2846142846C7
-:10391000152B462288162546242546268B170A0C89
-:1039200048090D4885130EDD1105CC110839400BEF
-:10393000EB390299101EE4520DCC020D5511082DE1
-:10394000400655022E461316E41D0FDD11254616BE
-:10395000080840851B0188100DBB0286671DE449DD
-:103960000988020CBB0219E4191CE4472B46172DE9
-:10397000461BA7661BE446C0702C461C0988028CB7
-:103980001E28461E2B4623C0908B1D29461D294606
-:103990001F18E43F2946272846252931162E2006E0
-:1039A00029246A243117962D242538861CCCE1273A
-:1039B0002407C0D7090E4064E0829A29092841648F
-:1039C000809164409B2D2406C098094936280AA09E
-:1039D00024628501C404A84428210424668508883B
-:1039E000118E3F8A3E2D32100EA41800C4040EAE74
-:1039F0001800EE110ACA530EDD02C0E30E880298C9
-:103A0000C11EE42409084E9EC08E2094C398C59D13
-:103A1000C418E3F01DE42105EE110EAA020DAA025E
-:103A2000A8B82784CF9AC21EE3E224F29D27E4A21D
-:103A3000244C1824F69D655052C020D10F2D240629
-:103A4000C0A0C09809493604A93863FF7FC0A063AD
-:103A5000FE070000654F6DC098C0A82A240663FFCA
-:103A60006B2D2406C09063FF63CC57DA20DB308CCB
-:103A700010580C38C020D10F00DA20C0B6580CC73F
-:103A800063FFE500DA20580CC563FFDC2A2C748B39
-:103A90001058053FD2A0D10F6C10062820068A339B
-:103AA0006F8202600161C05013E3C229210216E354
-:103AB000C1699204252502D9502C20159A2814E3B7
-:103AC000BF8F2627200B0AFE0C0477092B711C647C
-:103AD000E1398E428D436FBC0260016F00E104B09A
-:103AE000C800881A08A80808D80298272B2006685A
-:103AF000B32ECE972B221E2C221D0111027BC90151
-:103B0000C0B064B0172CB00728B000DA2003880AD0
-:103B100028824CC0D10B8000DBA065AFE7C020D16C
-:103B20000F2D206464DFCA8B29C0F10BAB0C66BF7C
-:103B3000C02B200C0CBC11A6CC28C2862E0A0878FB
-:103B4000EB611EE39D0EBE0A2EE2A368E00528226B
-:103B5000007E894F29C2851EE3A96490461FE3B603
-:103B60009E90C084989128200A95930F880298927D
-:103B70008E200FEE029E942F200788262F950A98FC
-:103B8000969A972E200625240768E3432921022AC6
-:103B9000C2851DE3902AAC20ADBD25D4CF2AC685B1
-:103BA00063FF4E002E2065CBEDC082282465C9F648
-:103BB00005E4310002002A62821BE3982941020BCE
-:103BC000AA022A668209E43129210263FF23000048
-:103BD00064DFB88F422E201600F1040DEE0C00EECB
-:103BE0001AAEAE9E2963FFA38A202B3221B1AA9A76
-:103BF000B0293221283223B4992936217989A92B79
-:103C000032222B362163FFA0C020D10F9F2725240D
-:103C100015ACB828751C2B2006C0C12EBCFE64E074
-:103C2000AB68B7772DBCFD65DEC72D2064C0F0649E
-:103C3000D0868E290EAE0C66E089C0F128205A2865
-:103C40008CFE08CF3865FEE863FF580000E004935F
-:103C500010C0810AF30C038339C78F08D80308A862
-:103C60000108F80C080819A83303C80CA8B828756F
-:103C70001C030B472B24158310CBB700E104B0BC09
-:103C800000CC1AACAC0CDC029C27659E5EC0B20B6B
-:103C9000990209094F29250263FE50002D206A0D63
-:103CA0002D4165DF7EDA20C0B0580C8F64AF18C09C
-:103CB000F163FEEF9F2763FFD02E221F65EE326374
-:103CC000FF79000028221F658E2763FF6E252406DA
-:103CD00029210263FE1B00006C10066571332B4C1A
-:103CE00018C0C7293C18C0A1C08009A838080842DC
-:103CF0006481101CE32C1AE32D2AC67E2A5CFDD3B6
-:103D00000F6DAA0500B08800908C8940C0A009887A
-:103D1000471FE355080B47094C50090D5304DD10AC
-:103D2000B4CC04CC100D5D029D310CBB029B3088DD
-:103D3000438E2098350FEE029E328D26D850A6DD98
-:103D40009D268E40C0900E5E5064E0971CE33B1EA3
-:103D5000E32B038B0BC0F49FB19EB02D200A99B3C7
-:103D60000CDD029DB28F200CFF029FB48E262D2009
-:103D7000079EB68C282DB50A9CB72924072F20064C
-:103D80002B206469F339CBB61DE30D2320168DD2A9
-:103D90000B330C00D10400331AB48DA3C393292232
-:103DA000200C13E30C1FE3030C2E11AFEEA322290A
-:103DB00024CF2FE285D2A00FDD0B2DE685D10F0099
-:103DC0002E200CB48C0CEB111FE3031DE2FAAFEEB6
-:103DD000ADBB22B28529E4CF02C20B22B685D2A0A8
-:103DE000D10F00002E200C1CE2F31FE2FA0CEB11A5
-:103DF000AFEEACBB22B28529E4CF02820B22B6859E
-:103E0000D2A0D10FC0D00BAD387DC80263FEEC63E9
-:103E1000FEE08E40272C747BEE12DA70C0B32C3C8F
-:103E200018DD50580A868940C08063FEE3066E02A2
-:103E3000022A02DB30DC40DD505800049A10DB50CF
-:103E4000DA70580453881063FEF700006C10069275
-:103E5000121EE2E48C40AE2D0C8C472E3C1804CA96
-:103E60000BD9A07DA30229ADF875C302600084C000
-:103E7000B0C023C0A09D106D0844B89F0EB80A8D35
-:103E8000900EB70BB8770D6D36ADAA9D800D660C00
-:103E9000D8F000808800708C879068B124B22277B7
-:103EA000D3278891C0D0CB879890279C100070882A
-:103EB00000F08C9D91CB6FC08108BB0375CB36633E
-:103EC000FFB4B1222EEC1863FFD485920D770C86D7
-:103ED000939790A6D67D6B01B1559693959260000D
-:103EE00016B3CC2D9C188810D9D078D3C729DDF80B
-:103EF00063FFC100C0238A421BE2E900CD322D449A
-:103F0000029B3092318942854379A1051EE2E50E7C
-:103F1000550187121BE2D5897095350B99029932AC
-:103F200088420A880C98428676A6A696768F44AF79
-:103F3000AF9F44D10F0000006C10089311D6308859
-:103F400030C0910863510808470598389812282115
-:103F500002293CFD08084C6581656591628A630A07
-:103F60002B5065B18B0A6F142E0AFF7CA60A2C20F9
-:103F70005ACCC42D0A022D245A7FE0026002158912
-:103F80002888261FE2C809880C65820F2E200B0F97
-:103F9000EE0B2DE0FE2EE0FF08DD110EDD021EE22D
-:103FA000C2AEDD1EE2C21CE2C20EDD010DCC37C185
-:103FB00080084837B88DB488981089601AE2807BF1
-:103FC00096218B622AA0219C147BA3179D132A2083
-:103FD0000C8B108C20580BB18C148D13DBA0CEAC45
-:103FE0006001C4002E200C1BE2730CEA110BAA081E
-:103FF0002BA2861FE2717BDB3B0FEF0A2FF2A36837
-:10400000F0052822007F892C2BA28564B0AA876244
-:104010008826DE700C7936097A0C6FAD1C8F279BD1
-:104020001508FF0C77F3197E7B729D139C149B156A
-:10403000CF56600025C0B063FFD0D79063FFDD008E
-:10404000009D139C14DA20DB70580B168B158C1412
-:104050008D1365A06A8E6263FFCC00DA208B11DCC1
-:1040600040580ABCD6A08B15C051DE70DA20DC6047
-:10407000DD405BFF768D138C14D9A02E200C1BE243
-:104080004D1FE2540CEA11AFEFC0E0ABAA2BA285A2
-:104090002EF4CF0B990B29A68563FF1D00DA20DCD7
-:1040A00060DD40DE708912282007DF50A9882824AF
-:1040B000075BFF09D2A0D10F00DBE0DA20580B37F5
-:1040C0006550EF2A20140A3A4065A0EBDB60DC4023
-:1040D000DD30022A025809A7D6A064A0D584A183A6
-:1040E000A00404470305479512036351C05163FEC2
-:1040F0005C2C2006D30F28CCFD6480A568C704C0C3
-:10410000932924062C2006C0B18D641FE22C9D2724
-:104110009D289D298FF29D2600F10400BB1A00F016
-:1041200004B0BE0EDD01C0F0ADBB8D652F24070DC0
-:104130000E5E01EE11AEBB2E0AFEB0BB0B0B190ECC
-:10414000BB36C0E20B0B470EBB372B241618E224FC
-:104150000A09450D0B422B240B29240AB4BE2E2438
-:104160000C7D88572920162FCCFDB09D0A5C520D7E
-:10417000CC362C246465FDEC0C0C4764CDE618E2CB
-:104180000F8E2888820C9F0C00810400FF1AAFEE6E
-:104190009E2963FDCF1CE23E63FE13001CE23563E3
-:1041A000FE0C8D6563FFA500DA202B200C580B2038
-:1041B000645F0FC020D10F00C020D10FC09329240D
-:1041C00016C09363FFA000006C1004C06017E1F8F4
-:1041D0001DE1FBC3812931012A300829240A78A175
-:1041E00008C3B27BA172D260D10FC0C16550512605
-:1041F00025022AD0202F200B290AFB2B20142E2049
-:104200001526241509BB010DFF0928F11C2B2414C8
-:10421000A8EE2EF51C64A0A92B221E28221D011138
-:10422000027B8901DB6064B0172CB00728B000DA8C
-:104230002007880A28824CC0D10B8000DBA065AF24
-:10424000E7DB30DC40DD50DA205800DE29210209AE
-:104250000B4CCAB2D2A0D10F00CC5A2C30087BC173
-:10426000372ED02064E02D022A02033B02DC40DD21
-:10427000505800D4D2A0D10F2B2014B0BB2B241443
-:104280000B0F4164F0797CB7CAC0C10C9C022C258D
-:1042900002D2A0D10FC020D10F2E200669E2C12684
-:1042A00024062B221E2F221D29200B2820150D99B4
-:1042B000092A911C262415AA8828951C7BF149609F
-:1042C0000048B0BB2B24140B0A4164A0627CB702E7
-:1042D0002C25022B221E2C221DD30F7BC901C0B01E
-:1042E000C9B62CB00728B000DA2007880A28824C0B
-:1042F000C0D10B8000DBA065AFE7C020D10F00006C
-:10430000262406D2A0D10F0000DB601DE1AC64BF03
-:104310004F2CB00728B000DA2007880A28824CC04A
-:10432000D10B8000DBA065AFE71DE1A463FF310086
-:1043300026240663FF9C00006C1004282006260A31
-:10434000046F856364502A2920147D9724022A0271
-:10435000DB30DC40DD50580019292102090A4CC825
-:10436000A2C020D10FC0B10B9B022B2502C020D1CF
-:104370000F00022A02033B022C0A015800D1C9AAED
-:10438000DA20DB30DC405809F329A011D3A07E9756
-:10439000082C0AFD0C9C012CA411C0512D201406E0
-:1043A000DD022D241463FFA4DA20DB30DC40DD5075
-:1043B000C0E0580973D2A0D10F0000006C1006169F
-:1043C000E17D1CE17D655157C0E117E179282102AB
-:1043D0002D220008084C6580932B32000B6951296F
-:1043E0009CFD6590872A629E6EA84C2A722668A062
-:1043F000027AD9432A629DCBAD7CBE502B200C0C97
-:10440000BD11A6DD28D2862F4C0478FB160CBF0AFE
-:104410002FF2A368F0052822007F89072DD285D3CB
-:104420000F65D0742A210419E1A3D30F7A9B2EDAE9
-:104430002058086E600035002D21041BE19E7DBBD5
-:1044400024DA20C0B6580869CA546001030B2B5007
-:104450002B240BB4BB0B0B472B240C63FFA0DA20DF
-:10446000580A4E600006DA20C0B6580A4C6550E083
-:10447000DC40DB302D3200022A020D6D515808BDA0
-:104480001CE14ED3A064A0C8C05184A18EA0040436
-:10449000470E0E4763FF3500002B2104C08C893185
-:1044A000C070DF7009F950098F386EB8172C20667C
-:1044B000AECC0C0C472C24667CFB099D105808CF11
-:1044C0008D1027246694D11EE151B8DC9ED0655032
-:1044D00056C0D7B83AC0B1C0F00CBF380F0F42CBAE
-:1044E000F119E13018E13228967EB04BD30F6DBA46
-:1044F0000500A08800C08C2C200CC0201DE1360CCB
-:10450000CF11A6FF2EF285ADCC27C4CF0E4E0B2EB9
-:10451000F685D10FC0800AB83878D0CD63FFC100CE
-:104520008E300E0E4763FEA12A2C742B0A01044D17
-:10453000025808C22F200C12E1270CF911A699A2EB
-:10454000FF27F4CF289285D2A008480B289685D162
-:104550000FC020D10F0000006C1004C060CB55DBF1
-:1045600030DC40055D02022A025BFF94292102092A
-:10457000084CC882D2A0D10F2B2014B0BB2B24141E
-:104580000B0C41CBC57DB7EBC0C10C9C022C2502A6
-:10459000D2A0D10F0000022A02033B02066C02C027
-:1045A000D0C7F72E201428310126250228240A0F0F
-:1045B000EE012E241458010E63FFA300262406D218
-:1045C000A0D10F006C1006282102D62008084C65E7
-:1045D000809D2B200C12E0F70CB811A2882A82864D
-:1045E000B5497A930260009719E0F409B90A299253
-:1045F000A36890082A620009AA0C65A08228828517
-:104600001CE0FF6480799C80B887B14B9B819B1034
-:10461000655074C0A7D970280A01C0D0078D380D25
-:104620000D42CBDE1FE0E01EE0E12EF67ED830D357
-:104630000F6D4A0500808800908C2E3008C0A000C5
-:10464000EE322E740028600C19E0E30C8D11A2DD0F
-:10465000A988C0202CD2852284CFD2A00CBC0B2CE0
-:10466000D685D10FC0F0038F387FA0C063FFB400A0
-:10467000CC582A6C74DB30DC405807F6C020D10FD0
-:10468000DA605809C663FFE7DD402A6C74C0B0DC0D
-:104690007058086A2E30088B1000EE322E740028F5
-:1046A000600C19E0CC0C8D11A2DDA988C0202CD2A1
-:1046B000852284CFD2A00CBC0B2CD685D10F000054
-:1046C0006C1004292014282006B19929241468812B
-:1046D00024C0AF2C0A012B21022C24067BA004C08D
-:1046E000D02D2502022A02033B02044C02C0D058FE
-:1046F00000C0D2A0D10FC020D10F00006C1004293F
-:104700003101C2B429240A2A3011C28378A16C7BFA
-:10471000A1696450472C2006C0686FC562CA572D36
-:1047200020147CD722DA20DB30DC40DD505BFFA593
-:10473000292102090E4CC8E2C020D10FC0F10F9F01
-:10474000022F2502C020D10FDA20DB30C0C05BFF72
-:10475000DC28201406880228241463FFC7292015AA
-:104760001BE0972A200BC0C09C240BAA092BA11C7C
-:104770002C2415AB9929A51C63FF9900C020D10FEB
-:10478000DA20DB30DC40DD50C0E058087DD2A0D11B
-:104790000F0000006C1004CB5513E09225221F0D72
-:1047A000461106550CA32326221E25261F06440B60
-:1047B00024261E734B1DC852D240D10F280A80C038
-:1047C0004024261FA82828261E28261DD240D10FA7
-:1047D000C020D10F244DF824261E63FFD80000000E
-:1047E0006C1004D620282006C0706E85026000D4AC
-:1047F0001DE07919E07112E06F2A8CFC64A1302B66
-:104800006102B44C0B0B4C65B0A22B600C8A600C9F
-:10481000B8110288082E828609B90A7EC302600098
-:104820009A2992A368900509AA0C65A08E28828512
-:10483000648088B8891BE07594819B80655155C060
-:10484000B7B8382A0A01C0C009AC380C0C4264C0A1
-:10485000421FE0541EE0562EF67EB04AD30F6DAADA
-:104860000500808800908CC0A029600C0C9C11A2CF
-:10487000CC2BC285AD990B4B0B2BC6852860062728
-:1048800094CF6881222D6015D2A0C9D2C0E22E64D7
-:1048900006D10F00C0F008AF387FB0BD63FFB10094
-:1048A000276406D2A0D10F00D2A0D10F00CC57DAD6
-:1048B00060DB30DC405808A7C020D10FDA6058090F
-:1048C0003763FFE80028221E29221DD30F789901A3
-:1048D000C080C1D6C1C11BE043C122AB6B64804222
-:1048E00078913F2A80000CAE0C64E0BB02AF0C64F0
-:1048F000F0B52EACEC64E0AF0DAF0C64F0A92EACBB
-:10490000E864E0A32FACE764F09D2EACE664E0978A
-:104910002F800708F80BDA807B83022A8DF8D8A055
-:1049200065AFBC28612308D739D97060007B0000CF
-:104930002B600C0CB811A2882C82862A0A087CAB4A
-:104940007E09BA0A2AA2A368A0052C62007AC96F60
-:104950002A828564A0691FE029276504C0E3C0C4DA
-:104960002E64069CA11CE0549FA02E600A97A30C05
-:10497000EE029EA28F600CFF029FA42E60147AEFBD
-:104980004627A417ADBC2F828527C4CF2FFC202F2C
-:10499000868563FE692A6C74C0B1DC90DD405807DF
-:1049A000A71DE00C63FEC100D9A0DA60DB30C2D0E5
-:1049B000C1E0DC4009DE39DD505807F1D2A0D10F4B
-:1049C000DA605808F663FEE4290A0129A4170DBF2E
-:1049D000082E828527F4CF2EEC202E868564500B7E
-:1049E0002A6C74DB4058016AD2A0D10FC020D10FCD
-:1049F0006C10062B221E28221D93107B8901C0B04B
-:104A0000C0C9C03BC1F20406401DDFF6C0E2C0745D
-:104A10000747010E4E01AD2D9E11C0402E0A1464B1
-:104A2000B06E6D084428221D7B81652AB0007EA1EE
-:104A30003B7FA1477B51207CA14968A91768AA1434
-:104A400073A111C09F79A10CC18B78A107C1AE29B8
-:104A50000A1E29B4007CA12B2AB0070BAB0BDAB0DD
-:104A60007DB3022ABDF8DBA0CAA563FFB428B0104D
-:104A700089116987BB649FB863FFDC00647FB463FE
-:104A8000FFD50000646FD0C041C1AE2AB40063FFFF
-:104A9000C62B2102CEBE2A221D2B221E7AB12A8CC1
-:104AA000107CB1217AB901C0B0C9B913DFC1DA20D5
-:104AB00028B0002CB00703880A28824CC0D10B8094
-:104AC00000DBA065AFE7D240D10F8910659FD463AA
-:104AD000FFF300006C1008C0D0C8598C30292102A7
-:104AE0000C0C4760000C8E300E1E5065E19E292193
-:104AF00002C0C116DFB0090B4C65B0908A300A6E57
-:104B00005168E3026000852F629E1BDFA96EF85397
-:104B10002BB22668B0052E22007BE94727629DB79D
-:104B200048CB7F97102B200CB04E0CBF11A6FF294D
-:104B3000F2869E12798B4117DFA007B70A2772A36E
-:104B4000687004882077893029F285DF90D79065D6
-:104B500090652A210419DFD77A9B22DA205806A310
-:104B6000600029002C21041BDFD37CBB18DA20C095
-:104B7000B658069EC95860014CC09063FFCCDA203D
-:104B8000580886600006DA20C0B65808846551359A
-:104B9000DC40DB308D30DA200D6D515806F6C0D088
-:104BA000D3A064A120292102C05184A18CA00404B7
-:104BB000470C0C4763FF3E00C09C8831DBD008F8EF
-:104BC00050089B3828210498116E8823282066AC51
-:104BD0008C0C0C472C24667CBB159F139E148A10EA
-:104BE0008B115807068E148F13C0D02D24668A307F
-:104BF000C092C1C81BDF867FA6099BF099F12CF4F7
-:104C00000827FC106550A4B83ADF70C051C0800777
-:104C1000583808084264806718DF6319DF64298602
-:104C20007E6A420AD30F6DE90500A08800F08CC0AF
-:104C3000A08930B4E37F9628C0F207E90B2C9408D2
-:104C40009B909F912F200C12DF630CF811A68829EE
-:104C50008285A2FF2DF4CFD2A009330B238685D104
-:104C60000F22200C891218DF5B0C2B11A6BBA82287
-:104C70002D24CF2CB285D2A00C990B29B685D10F4B
-:104C8000C087C0900A593879809663FF8ADB30DA92
-:104C900020C0C1C0D05BFF56292102C0D02A9CFE93
-:104CA00065AE4D2D2502C09063FE45009E142A2C52
-:104CB00074C0B1DC70DD405806E18E14C0D01BDF3B
-:104CC00053C1C863FF6AC020D10F00006C100628D2
-:104CD000210216DF3808084C65821929629E6F98F8
-:104CE0000260022019DF332992266890078A200982
-:104CF000AA0C65A20F27629DC0CC6472072B210409
-:104D00008E31C0A0DDA00EFE500ECD386EB8102C36
-:104D10002066B1CC0C0C472C24667CDB026001EFD2
-:104D2000C0C12930081BDF2564909C2F0AFFC0D327
-:104D3000B09E64E1026892136450882A2C74044B7C
-:104D4000025800930AA20206000000002B200C2744
-:104D500021040CBC11A6CC29C286280A087983023A
-:104D60006001B919DF1509B90A2992A36890082EC4
-:104D7000220009EE0C65E1A42EC28564E19E262086
-:104D80000713DF1E6E7B0260019A17DF151FDF1EFF
-:104D900019DF4BC0D228200A93E09DE1A9690F8852
-:104DA0000298E22F90802A9480B1FF07FF029FE3D0
-:104DB0002EC2851FDF080EDE0BAFBF2AF4CF2EC632
-:104DC00085655F76C020D10F2830102930112E3034
-:104DD0001300993200ED326480EE2A30141FDF3860
-:104DE00000AA3278EF050F9E092DE47F1EDF36669C
-:104DF000A0050F98092A8480B4A718DF33C76F0075
-:104E00009104AE9EDDE000AF1A00C31A6EE1052DDD
-:104E1000B2000DED0C1EDF2D08D81C063303AE8842
-:104E20002A848B2EB02E27848C03EE010FEE022EE7
-:104E3000B42E58018F63FEFF29310829250428303C
-:104E4000142E3109B0886480A32E240AC0812E302C
-:104E5000162CB4232E240BB4EF2F240C8C378B3656
-:104E6000292504DEB0DFC00C8F390B8E390FEE021E
-:104E700064EEC4089F1101C4048D380CB81800C436
-:104E8000040CBE1800EE110EDD02C0E30EFF021E80
-:104E9000DF019F719E701EDF008F2098739D740547
-:104EA000FF110BCD53C18098750FDD020EDD029D01
-:104EB000721EDEBF2A24662F629D2AE4A22FFC18F0
-:104EC0002F669D63FE710000002F30121BDF010072
-:104ED000FA3278FF050B980B2A847F66D0050B9A6F
-:104EE0000B2DA4802A301100AA3263FF442F240A1C
-:104EF0009E2B63FF56CC57DA20DB30DC4058071579
-:104F0000C020D10F00DA20C0B65807A463FFE50027
-:104F1000DA7058063AC0A02A246663FE02DA2058E6
-:104F2000079F63FFCFB16928200A862009094799A6
-:104F30001129240798107F812693E027E50A9AE338
-:104F400088109DE119DEDD8D11096F029FE42DE4CB
-:104F500016098802C0D398E22A240763FE51000094
-:104F60001DDEA60868118F11892B93E008FF02C08F
-:104F70008F9FE50D990299E2047F11C0D49DE1084D
-:104F8000FF029FE463FFD0006C1004C020D10F002B
-:104F90006C100485210D381114DE848622A42408A7
-:104FA000660C962205330B9321743B13C862D230F2
-:104FB000D10FC030BC29992199209322D230D10F32
-:104FC000233DF8932163FFE36C100AD62094181751
-:104FD000DE79D930B83898199914655252C0E1D2A7
-:104FE000E02E61021DDE760E0E4C65E1628F308E82
-:104FF000190F6F512FFCFD65F1558EE129D0230E5D
-:105000008F5077E66B8F181EDEB3B0FF0FF4110FD1
-:105010001F146590CE18DEB08C60A8CCC0B119DE2C
-:105020006428600B09CC0B0D880929811C28811A82
-:105030002A0A0009880C08BA381BDEA60CA90A291E
-:1050400092947B9B0260008C2B600C94160CBD111B
-:10505000A7DD29D286B8487983026000D219DE56CE
-:1050600009B80A2882A398176880026000A360002C
-:10507000A51ADE9A84180AEE01CA981BDE4D8C1917
-:105080002BB0008CC06EB3131DDE4A0C1C520DCC2D
-:105090000B2DC295C0A17EDBAE6000380C0C5360B6
-:1050A000000900000018DE8C8C60A8CCC0B119DEAD
-:1050B0004028600B09CC0B0D880929811C28811A16
-:1050C0002A0A0009880C08BA380CA90A2992947E89
-:1050D000930263FF72DA60C0BA580730645073609D
-:1050E000026600001ADE338C192AA0008CC06EA361
-:1050F0001A18DE2F0C1C5208CC0B18DE762BC2952A
-:10510000C0A178B30263FF3F63FFC9000C0C536377
-:10511000FF09896078991829D285C9922B729E1D42
-:10512000DE246EB8232DD226991369D00B60000DB2
-:10513000DA6058071A6000170088607D890A9A1A99
-:1051400029729D9C129915CF95DA60C0B658071345
-:105150006551F58D148C18DBD08DD0066A020D6D6B
-:1051600051580584D3A09A1464A1DD82A085A1B80A
-:10517000AF9F190505470202479518C05163FE60AD
-:105180002B6104C08C8931C0A009F950098A386E9E
-:10519000B81F2C6066A2CC0C0C472C64667CAB114B
-:1051A0009F119E1B8A155805958E1B8F11C0A02A32
-:1051B00064669F1164F0E12912032812096DF91742
-:1051C0002F810300908DAEFE0080889F9200908C0E
-:1051D000008088B89900908C65514E8A10851A8B92
-:1051E000301FDE06881229600708580A2C82942D89
-:1051F00061040ECC0C2C86946FDB3C1CDE30AC9C26
-:1052000029C0800B5D50A29909094729C48065D047
-:10521000DA2E600CC0D01FDDEF0CE811AFEEA788CE
-:105220002282852DE4CF02420B228685D2A0D10FA7
-:105230008E300E0E4763FDA6A29C0C0C472C640713
-:105240007AB6CD8B602E600A280AFF08E80C6481CC
-:105250000E18DE1983168213B33902330B2C341661
-:105260002D350AC02392319F30C020923308B202FC
-:1052700008E80292349832C0802864072B600CD270
-:10528000A01CDDD40CBE11A7EE2DE285ACBB28B46A
-:10529000CF0D9D0B2DE685D10F8B1888138D30B85F
-:1052A0008C0D8F470D4950B4990499100D0D5F0472
-:1052B000DD1009FF029F800DBB029B8165508D852B
-:1052C0001AB83AC0F1C0800CF83808084264806B04
-:1052D0001BDDB519DDB629B67E8D18B0DD6DDA059A
-:1052E00000A08800C08CC0A063FEF30082138B1660
-:1052F0001DDDC628600AC0E02EC4800D880202B2FF
-:105300000B99239F20C0D298229D2122600CB2BB12
-:105310000C2D11A7DD28D28508BB0B18DDAE2BD6CE
-:1053200085A8222E24CFD2A0D10F9E1B851A2A6CCD
-:10533000748B185BFF178E1B63FEA300C087C090A1
-:105340000AF93879809263FF86C020D10F9E1B2A0C
-:105350006C74C0B18D185805398E1B851A63FE7E9A
-:10536000886B8213891608BE110ECE0202920B9E24
-:1053700025B4991EDDA19F200E88029822C0EF045B
-:10538000D8110E88029824C0E49E21C080D2A02BA0
-:10539000600C2864071CDD8F0CBE11A7EE2DE28582
-:1053A000ACBB28B4CF0D9D0B2DE685D10F000000BE
-:1053B0006C1004C020D10F006C10048633C071C083
-:1053C00030600001B13300310400741A04620174CA
-:1053D00060F1D10F6C1004022A02033B025BFFF65E
-:1053E0001CDD771BDDBFC79F88B009A903098A01AF
-:1053F0009AB079801EC0F00FE4311DDD6E0002000E
-:105400002BD2821EDDB82AC1020EBB022BD6820A25
-:10541000E431D10F28C102C19009880208084F2841
-:10542000C50208E431D10F006C1004C0C00CE43197
-:1054300012DD631ADD6000020029A28218DDAC1BB8
-:10544000DDAA2621020B990108660129A6822625DC
-:105450000206E43114DDA715DDA2236A902326128B
-:105460008550242611252613222C40D10F00000040
-:105470006C1008D6102B0A64291AB41ADD4D0D23BE
-:10548000111CDD4E0F2511B81898130E551118DD9B
-:1054900099AC55A838AA332C80FF2A80FEA933285E
-:1054A0008D0129800108AA112880000CAA02088811
-:1054B0001109880208AA1C288C08281604580862BA
-:1054C00014DD3F0AA7022441162A30802B1204075C
-:1054D000AA2858085DB1338B13B4559A6004AC28E0
-:1054E000B4662C56277B69E016DD769412C050C056
-:1054F000D017DD329D15D370D4102F60802E6082BE
-:105500009F169E17881672891A8D128C402A607F0A
-:105510000DCC282B3A200CAA2858084BC0B10ABE43
-:10552000372E35408F1772F91A8D128C402A608100
-:105530000DCC282B3A200CAA28580843C0B10ABE2B
-:10554000372E3542B233B444B1556952B6B466C051
-:10555000508F15B877D370B2FF9F156EF899D10FA1
-:105560006C1004C021D10F006C1004270A001CDD50
-:10557000111FDD221EDD251DDD0E1ADD501BDD5E37
-:10558000C02824B0006D2A75AA48288080C0916484
-:10559000806100410415DD09C03125502E00361A06
-:1055A0000655010595390C56110C66082962966E50
-:1055B000974D0D590A29922468900812DD42024243
-:1055C0000872993B23629512DD06CB349F3002822C
-:1055D000020E4402C092993194329233AD52246249
-:1055E00095C090244C1024669524B0002924A0AACC
-:1055F00042292480B177B14404044224B400D10F7D
-:10560000D10FD10F6C10041ADCEA2AA00058021C3A
-:105610005BFFD5022A02033B025BFFD11BDCE8C91A
-:10562000A12CB102C0D40DCC020C0C4F2CB5020C35
-:10563000E431D10FC0A00AE43118DCDE0002002FF3
-:10564000828219DCF12EB10209FF022F86820EE45C
-:1056500031D10F006C1004C02002E43114DCD816E4
-:10566000DCD5000200226282234102732F0603E48C
-:1056700031C020D10F19DD221ADD212841020A2A6A
-:10568000010988012A668228450208E43115DD18DF
-:1056900012DD1D25461DD10F6C1004292006289C03
-:1056A000F96480A02A9CFD65A0968A288D262F0A81
-:1056B000087AD9042B221FC8BD2C206464C0812E17
-:1056C00022090EAE0C66E0782B200C1EDCBA0CBC56
-:1056D00011AECC28C28619DCB878F3026000AD099F
-:1056E000B90A2992A36890082E220009EE0C65E001
-:1056F0009B29C2851FDCC26490929F90C0E41FDC8E
-:10570000CE9E9128200AC0E09E930F88029892882E
-:10571000200F880298942F20079A979D962F950A1C
-:105720002E240728200629206468833328C2851286
-:10573000DCA9288C20A2B22E24CF28C685C020D177
-:105740000FC020D10F2A206A0111020A2A4165AF39
-:1057500052DA20C0B05805E464AFE5C021D10F0093
-:10576000649FC81FDC962D20168FF209DD0C00F116
-:105770000400DD1AADAD9D2912DC9728C285A2B2C6
-:105780002E24CF288C2028C685C020D10FC021D13F
-:105790000F0000006C1004260A001BDCDB15DC8700
-:1057A00028206517DC84288CFE6480940C4D110D34
-:1057B000BD082CD2F52BD2F42ED2F77CB13DB4BB70
-:1057C0002BD6F47BE9052BD2F62BD6F47CB92C2A08
-:1057D000D2F62AD6F52AD6F406E431000200287261
-:1057E000822AFAFF004104290A012F510200991A66
-:1057F0000A99030988012876820FE4312624652B53
-:10580000D2F48E5A2CD2F5B0EE9E5A7BCB1629D20A
-:10581000F62FD2F70CB80C09FF0C08FF0C0F2F1451
-:10582000C8F96000320BCA0C0A2A14CEA92B510207
-:10583000C0C20CBB020B0B4F2B55020BE431D10F36
-:1058400000DB30DA205BFF941BDCB064AF5D0C4DF5
-:1058500011ADBD63FFA8000006E4310002002F7205
-:105860008218DC6E2E510208FF022F76820EE43180
-:10587000D10F00006C1004C03003E43116DC4E156B
-:10588000DC4F00020024628274472118DCA0875A92
-:10589000084801286682CD7319DC9E0C2A11AA994A
-:1058A0002292832992847291038220CC292B510267
-:1058B0000BE431C020D10F001FDC972E51020FEEF8
-:1058C000012E55020EE431B02DB17C9C5A12DC92AF
-:1058D00008DD112D5619D10F6C10061BDC351EDCAE
-:1058E0003722B0001ADC8E6F23721DDC75C0481899
-:1058F000DC8D1FDC8BDC10D5C083F000808600506F
-:105900008A6D4A4F0F35110D34092440800B560A19
-:10591000296294B1330E55092251400F44110C44B1
-:105920000A874009A80C02883622514107883608A8
-:10593000770CA8992966949740296295874109A810
-:105940000C02883607883608770CA899296695973F
-:1059500041030342B13808084298F0D10F1CDC72B1
-:1059600013DC7327B0002332B5647057C091C0D0E8
-:1059700016DC7115DC6FC0402AC00003884328C4C0
-:10598000006D793C004104B14400971A7780148E71
-:10599000502FB2952DB695AFEE2EED2006EE369E29
-:1059A0005060001877A00983509D5023B695600081
-:1059B0000223B295223D2006223622B695B455B870
-:1059C000BBD10F0003884328C400D10F6C1004C062
-:1059D0004004E43115DC59000200885013DC58CB38
-:1059E000815BFFBD1CDC570C2D11ADCC2BC2822A74
-:1059F000C28394507BAB142EC28429C2850ABD0C8D
-:105A00000E990C0D990C0929146000050BA90C09BD
-:105A10002914993015DBEA2A51020AE4312A2CFCB8
-:105A200058004B2B32000AA2022BBCFF9B30CCB695
-:105A3000C8A4D2A0D10F000004E4311EDBDE0002B6
-:105A4000002DE2822FBAFF2C51020FDD012DE682DC
-:105A50000CE431D10F0000006C1004D10F000000E5
-:105A60006C1004C020D10F006C100413DC36C0D1C0
-:105A700003230923318DC0A06F340260008D19DB30
-:105A8000CD1BDBCE17DC2F0C2811A87726728325BF
-:105A900072822CFAFF76514788502E7285255C045D
-:105AA00025768275E9052572842576827659292E18
-:105AB00072842E76822E76830AE4310002002392CD
-:105AC000820021042FB10200D61A0C6603063301AE
-:105AD0002396820FE43126728325728260000200D1
-:105AE000D8A07659220AE4310002002392820021D4
-:105AF0000400D21A2FB1020C220302320122968234
-:105B00000FE431D280D10F00D280D10FC020D10F4D
-:105B10006C1004DB30862015DBA6280A002825023D
-:105B2000DA2028B0002CB00705880A28824C2D0AFC
-:105B3000010B8000DBA065AFE61ADB9F0A4A0A2949
-:105B4000A2A3C7BF769101D10F2BA6A3D10F00004E
-:105B50006C1004C0D1C7CF1BDB9919DB9617DB94FF
-:105B60000C2811A87786758574C0A076516288507C
-:105B70008E77B455957475E90385769574765927B3
-:105B80008F769F759F740AE431000200239282B4DD
-:105B90002E2FB10200E10400D61A0C660306330171
-:105BA0002396820FE431867583747639280AE431AE
-:105BB0000002002E9282B42200210424B10200DFF0
-:105BC0001A0CFF030FEE012E968204E431D280D12D
-:105BD0000FD8A07651D6D280D10F00006C100429C6
-:105BE0000A801EDB9A1FDB9A1CDB730C2B11ACBBEB
-:105BF0002C2CFC2DB2850FCC029ED19CD0C051C064
-:105C00007013DB9614DB9518DB932AB285A8280461
-:105C1000240A234691A986B8AA2AB685A98827848A
-:105C20009F25649FD10F00006C100419DBC70C2A5C
-:105C300011A9A98990C484798B761BDBB5ABAC2AFA
-:105C4000C2832CC2847AC1688AA02BBC30D3A064E2
-:105C5000A05E0B2B0A2CB2A319DB7F68C0071DDBEB
-:105C6000BBD30F7DC94AA929299D0129901F68919D
-:105C70003270A603D3A0CA9E689210C7AF2AB6A3FB
-:105C80002A2CFC5BFFB3D230D10F000013DBB10331
-:105C9000A3018C311DDB510C8C140DCC012CB6A34F
-:105CA00063FFDC00C020D10FDA205BFFCCC020D125
-:105CB0000FC020D10F0000006C1004DB30C0D019E1
-:105CC000DB3CDA2028300022300708481209880A15
-:105CD00028824CDC200B80001BDB370C4A11ABAA5E
-:105CE00029A28409290B29A684D10F006C1004C0B5
-:105CF0004118DB3017DB320C2611A727277030A89C
-:105D000066256286007104A35500441A7541482235
-:105D1000628415DB5202320BC922882117DB2F085F
-:105D20008414074401754905C834C020D10FD10F30
-:105D30000809471DDB86C0B28E201FDB1D0E0E43F7
-:105D4000AFEC2BC4A00FEE0A2DE6242A6284C020FB
-:105D50000A990B296684D10FC020D10F6C1004DB87
-:105D600030C0D018DB13DA20253000223007085865
-:105D70000A28824CDC200B80008931709E121BDBCC
-:105D80000D0C4A11ABAA29A28409290B29A684D19A
-:105D90000F09C95268532600910418DB08C0A12FCF
-:105DA000811200AA1A0AFF022F85121EDB020C4D77
-:105DB00011AEDD2CD2840C2C0B2CD684D10FC081DB
-:105DC0001FDAFFB89A0A0A472EF11200A1040088D0
-:105DD0001A08EE022EF5121DDAF70C4C11ADCC2B81
-:105DE000C2840B2B0B2BC684D10F00006C1004DB7C
-:105DF00030C0D019DAEFDA202830002230070988C5
-:105E00000A28824CDC200B80001CDAEA0C4B11AC17
-:105E1000BB2AB2840A2A0B2AB684D10F6C1004C0A4
-:105E20004118DAE416DAE60C2711A626266030A817
-:105E300072252286006104A35500441A7541082288
-:105E4000228402320BD10F00C020D10F6C10041538
-:105E5000DB410249142956112452120208430F88CB
-:105E600011C07300810400361A008104C78F0077C7
-:105E70001A087703074401064402245612D10F0082
-:105E80006C10066E23026000AC6420A7C0A08510D1
-:105E900013DB1916DB30C040A6AA2BA2AE0B1941AA
-:105EA00064906668915D68925268933C2AA2AA2821
-:105EB0003C7F288C7F0A0A4D2980012880002AAC6B
-:105EC000F20888110988027589462B3D0129B00026
-:105ED0002BB0010899110B99027A9934B8332A2A08
-:105EE00000B1447249B160004A7FBF0715DB1B63F4
-:105EF000FFB90000253AE863FFB10000253AE863E6
-:105F0000FFA90000250A6463FFA1C05A63FF9C003B
-:105F100000705F082534FF058C142C34FE70AF0B25
-:105F20000A8D142E3D012AE4012DE400DA405BFDC8
-:105F30005063FFA7D10FD10F6C10041ADAA019DA41
-:105F40009D1CDB061BDB07C080C07160000D0000DC
-:105F50000022A430B1AA299C107B915F26928679F9
-:105F6000C2156E6262C0206D080AB12200210400D1
-:105F7000741A764BDB63FFEE2292850D63110325C5
-:105F800014645FCFD650032D436DD9039820B422FB
-:105F90000644146D49229820982198229823982429
-:105FA00098259826982798289829982A982B982CED
-:105FB000982D982E982F222C4063FF971EDA7E276B
-:105FC000E68027E681D10F00C02063FF8300000038
-:105FD0006C1004C062C04112DA791ADA7513DAE182
-:105FE0002AA00023322D19DADB2BACFE2992AE6EEB
-:105FF000A30260008E090E402D1AC2C2CD0EDC39FC
-:106000002C251664B0895BFF9E15DAD71ADAD12BDE
-:106010003AE80A3A0158058C2B21160ABB28D3A06E
-:106020009B505805A32B52000ABB082A0A005805AA
-:10603000A215DACE2D21022C3AE80C3C2804DD0210
-:106040002D25029C5058059A8B50AABBC0A158051B
-:106050009A1CDAC72D21020C3C2806DD0213DAC592
-:106060002D25029C305805928B30AABBC0A2580542
-:10607000922A2102C0B40BAA020A0A4F2A2502580A
-:1060800005A6D10F242423C3CC2C251663FF76004C
-:1060900018DABD1CDAB919DABA1BDAB817DA8B8547
-:1060A000202E0AFD1FDAB92D202E24F47A24F47E46
-:1060B00024F4820EDD0124F4862E0AF70755280603
-:1060C000DD02C0750EDD01050506AB5BA959C0E810
-:1060D000AC5C24C4AB0EDD0227C4AC2E0ADFA8558D
-:1060E00027B4EC0EDD0124B4EBC2E027942C0EDDC6
-:1060F0000224942B2E0A800D0D4627546C24546BD9
-:106100000EDD022D242E63FEFC0000006C10042A1C
-:106110000A302B0A035BFF4D12DA8FC39029261633
-:10612000C3A1C0B3C08A2826175BFF48C03CC3B1D7
-:106130002B26161ADA222AA02023261764A079C358
-:10614000A2C0B15BFF42C3A2C0B15BFF40C3C22C7F
-:106150002616C2AFC0B12326175BFF3CC28F28268C
-:1061600016C0FE2F2617C2E22E26162A0AA1C0B19B
-:10617000C0D82D26175BFF352A0AA12A2616C3A6EA
-:10618000C0B3C1922926175BFF31C3C62C2616C1A6
-:10619000B32A0AA22B2617C0B35BFF2C290AA22917
-:1061A0002616C185282617C2FB2F2616C0E72E26E5
-:1061B000171DDA762D2610D10FC3A2C0B35BFF23C3
-:1061C00063FF82006C10041CDA3F1BDA2C18DA70B3
-:1061D00017DA7116DA7115DA71C0E0C0D414DA3B3F
-:1061E0001FD9F7C0288FF06D2A36DAC0D9C07C5B82
-:1061F000020FC90C1CDA350C9C28A8C3A6C22A368B
-:10620000802A2584A4C2A7CC2D248C2B248A2B245D
-:10621000872E248BB1BB2E369F2C369E2C369DB1FB
-:10622000AC1CDA161BDA5FC0286D2A33DAC0D9C07D
-:106230007C5B020FC90C1CDA240C9C28A8C3A6C2E4
-:106240002A36802B2584A4C2B1BBA7CC2D248C2E4A
-:10625000248B2A248A2E369F2C369E2C369DB1AC58
-:10626000C07919DA141BDA5113DA4F1ADA4F18DA37
-:106270005014DA1516DA5004F42812DA4F04660CBA
-:10628000040506A252A858AA5AA3539B3029A50078
-:1062900027848AC091C0A52A848C29848B17DA4868
-:1062A00018DA47A75726361D26361E2E361F16DA51
-:1062B0004513DA45A65504330C2826C82E75002D43
-:1062C00054AC2E54AB2E54AA2326E62326E52E26C4
-:1062D000E7D10F006C100613DA2317DA1E24723D83
-:1062E0002232937F2F0B6D08052832937F8F026334
-:1062F000FFF3C0C4C0B01AD9B1C051D94004593954
-:1063000029A4206E44020BB502C3281ED9ACDDB00F
-:1063100025E422052D392DE421C0501EDA2C19DA8E
-:106320001C18DA1C16DA1E1DDA2A94102A72451778
-:10633000D9E76DA94BD450B3557A5B17DF50756B15
-:10634000071FD99E8FF00F5F0C12D9DF02F228AE23
-:106350002222D681D54013D9DC746B0715D99885D4
-:106360005005450C035328B145A73FA832A9332255
-:10637000369D22369E2436802B369F2BF48B2CF4B0
-:106380008C14D9F824424DC030041414C84C6D0844
-:1063900006B133041414C84263FFF20015D985C452
-:1063A000400031041AD986C0D193A200DD1AC13849
-:1063B000B0DD9DA318D9EC2B824D29824E29A51C56
-:1063C0002882537A871E2C54008E106FE45D12D9F8
-:1063D0007B2F211D23211C2F251B04330C23251C5F
-:1063E00023251AD10FC06218D9DB88807E87D9890E
-:1063F000102654006F94191BD9712AB11C0A1A1463
-:1064000004AA0C2AB51C2AB51D2AB51A2AB51BD117
-:106410000F1BD96A2AB11C0A1A1403AA0C2AB51C2C
-:106420002AB51D2AB51A2AB51BD10F001CD9642B19
-:10643000C11D2DC11C2BC51B03DD0C2DC51C2DC57D
-:106440001AD10F006C100619D95D14D9C212D9C522
-:1064500015D9E0C73FC0E02E56A82E56A92E56AA41
-:106460002E56AB23262918D985DB101CD9DAC0D4C7
-:106470002A42452D16019C1000B0890A880C2896E6
-:10648000005BFF942B22E318D94D0B5B149B842AED
-:1064900022E48B84B1AA0A5A140BAA0C9A852922E9
-:1064A000E509591499862F22CD0F5F149F875BFF52
-:1064B000455BFF1623463BC1B01DD9401CD99E2A1F
-:1064C000D1022C463A0BAA020A0A4F2AD5025804D6
-:1064D000925BFEBF5BFE98C050C0B016D93614D98F
-:1064E0003E17D9AEC0C0C73E93122C262DC03060D7
-:1064F00000440000007F9F0FB155091914659FF4F7
-:10650000C0500AA9027FA7EF18D92ADA5008580A02
-:1065100028822C2B0A000B8000005104D2A0C091CD
-:10652000C7AF00991A0A99039912CE3864206BD329
-:10653000202B20072516032C12022A62827CA863D6
-:1065400018D91C01110208580A28822CDA500B8035
-:1065500000D2A0643FD58A310A8A1404AA01C82A4D
-:106560002B22010B8B1404BB017BA945DDA07A7B98
-:10657000081DD9122DD2000DAD0CDB3019D90D1A22
-:10658000D95288130ADA28DC801DD99009880A2894
-:10659000823C0DAA080B8000652F93D320C0B06306
-:1065A000FF9400007FAF34B1550050040A0919630D
-:1065B000FF42DAB07B7B081AD9012AA2000ABA0C82
-:1065C0001BD9428C310BAB280C8A141CD980ACBB74
-:1065D0001CD98004AA012BC68163FF8F645F60C051
-:1065E00050C0B0C7CE9C1263FF5500006C1004274A
-:1065F000221EC08008E4311BD8EF0002002AB282BC
-:1066000019D8EF003104C06100661A2991020A6AA4
-:10661000022AB68209E43115D94A0C3811A8532848
-:1066200032822432842A8CFC7841102921022A36B5
-:106630008297A0096902292502D10F002B21022C83
-:1066400032850B6B022CCCFC2C368297C02B25029A
-:10665000D10F00006C1004C0E71DD8D21CD8D40D97
-:106660004911D7208B228A200B4B0BD2A007A80CF4
-:106670009B72288CF4C8346F8E026000A31FD8CAA6
-:10668000A298AF7B78B334C93DC081C0F0028F3887
-:106690000F0F42C9FA2CD67ED5206D4A05003088EE
-:1066A00000508C887008980878B16DD2A09870D18D
-:1066B0000FC0F0038F387FE0DE63FFD8027B0CAFA2
-:1066C000BB0B990C643047D830C0F1C05002F5388C
-:1066D0000505426450792CD67E0B36122F6C100FB4
-:1066E0004F366DFA0500808800208C06440CC0816E
-:1066F000C05003B208237C0C038538050542645062
-:106700005A2CD67ED30F6D4A0500208800308CD2DB
-:10671000A0A798BC889870D10FD2A0BC799970D1ED
-:106720000FD2302BAD08C0F1C0500BF53805054233
-:10673000CB542CD67E083F14260A100F660C064652
-:10674000366D6A0500208800B08C827063FF2D00D2
-:10675000C05003F53875E08063FF7A00C0600286A0
-:106760003876E09F63FF9900C05003F53875E0C4A8
-:1067700063FFBE006C1004D62068520F695324DA00
-:1067800020DB30DC405800F3D2A0D10FDA20DB3020
-:10679000DC405800F09A2424240EC02122640FC04B
-:1067A00020D10F00B83BB04C2A2C7489242D200E28
-:1067B0002E200FA4DDB1EE2E240FB0DD2D240E28E7
-:1067C00090072D9003A488B088B1DD2D9403289400
-:1067D000075BFFA069511DC0E082242A600F18D812
-:1067E000FE2A240329600E8F2029240708FF029F18
-:1067F000209E64D10FC020D10F0000006C100494C3
-:106800002319D8F6C0B3083A110BAA02992019D857
-:10681000699A2116D867C05028929D2564A2288CB9
-:106820001828969DD10F00006C1004282066C038EF
-:10683000232406B788282466D10F00006C100603B5
-:106840005A0C0D36110D5C11D8208B2282210CBB05
-:106850000C06550F9B8202320B928113D853D9201C
-:10686000A38F6450561CD84FC0D71BD850A256C017
-:10687000E1C09004E93809094276F34F044302CAA3
-:10688000912BC67ED30F6DAA0500208800308C891D
-:1068900081A95909FA0C64A07D99818A8264A00FAC
-:1068A000D290D10FC06002E63876D0D763FFD10016
-:1068B000C020BC89998199809282D10F7F230429BD
-:1068C0002DF8998165BFD863FFE50000028F0CA306
-:1068D000FF0F3312931003AA0CD3406490402BC6D1
-:1068E0007E8610D30F6D6A0500208800308CBC8234
-:1068F000C090A4F3C041034938090942CA9B2BC682
-:106900007E6DAA0500208800308C0F590CA989BC27
-:1069100099998163FF8400BC89998163FF7C00C0E1
-:106920006002E63876D0B963FFB300C07002473822
-:1069300077D0CD63FFC700006C100414D82AC15271
-:10694000A424CA3128221D73811C292102659016B6
-:106950002A300075A912022A02033B022C3007C01C
-:10696000D25801D0653FDCD10F2B300703BB0B0B96
-:10697000BA0274B3022ABDF8D3A063FFC4000000BA
-:106980006C1004292006C0706E9741292102C08F27
-:106990002A2014C0B62B240606AA022A24147980C1
-:1069A000022725022A221E2C221D7AC10EC8ABDA2C
-:1069B00020DB302C0A00033D025BF80D6450742D7F
-:1069C00021020D0D4CC9D3C020D10F00002E9CFB1D
-:1069D00064E0822F21020F0F4C65F0911AD7F61C4C
-:1069E000D7F429A29EC08A798B5D2BC22668B00499
-:1069F0008D207BD95229A29DC0F364904A97901DA7
-:106A0000D8062E21049D9608EE110FEE029E979E49
-:106A10009118D802C0E527C4A22E24062BA29D2FD0
-:106A200021022BBC3008FF022F25022BA69DC0207F
-:106A3000D10F00002F300068F939DA20DB30044C28
-:106A40000258004463FF7700022A022B0A0658000E
-:106A5000D3220A00D10F6550102830006889240223
-:106A60002A02033B02DC4058003BC020D10FD27009
-:106A7000D10F00002A2C74033B02044C025BFEF58C
-:106A800063FF3B00DB30DC402A2C745BFEF2C0204D
-:106A9000D10F00006C1004C83F89268829A399995A
-:106AA0002609880C080848282525CC52C020D10F7B
-:106AB000DB402A2C745BF936D2A0D10F6C1004D8BD
-:106AC00020D73082220D451105220C928264207459
-:106AD00007420B13D7B5D420A383732302242DF8C8
-:106AE000858074514CBC82C0906D081600408800AF
-:106AF000708C773903D720C0918680743901D420F7
-:106B000074610263FFE2CA98C097C0411BD835C0C8
-:106B1000A00B8B0C0B4A380A0A42C9AA1DD7A21C2B
-:106B2000D7A32CD67EC140D30F6D4A050020880024
-:106B3000308C9780D270D10FBC8FC0E00F4E387E62
-:106B400090E263FFD6BC8292819280C0209282D173
-:106B50000F0000006C1006C0D71CD7921BD7940DF5
-:106B60004911D7202E221F28221D0E4E0BD280073E
-:106B70008A0C2E761F2AAC80C8346FAE026000CB20
-:106B80002F0A801AD798A29EAA7A7EA33FC93FC037
-:106B9000E1C05002E538050542CA552BC67EDB2010
-:106BA000D30F6D4A0500308800B08C2E721DAE9E4A
-:106BB0000EA50C645086D2802E761DC091298403C8
-:106BC000D10FC05003E53875D0D363FFCD15D785FD
-:106BD000027E0CA5EE643051C0A1250A0002A53842
-:106BE000033A020505426450922BC67E0E3512957B
-:106BF00010255C10054536D30F6D5A0500A088009E
-:106C0000208CC0A1A3E2C05023FA8003730C03A51B
-:106C100038AF730505426450722BC67E851005455A
-:106C20000C6D5A0500208800308CD280C0A10E9BCC
-:106C30000CAB7BAFBB2B761D2A8403D10FD280C057
-:106C4000C1AF7D2D761D2C8403D10F00D2302E8D47
-:106C500008C0F1C0500EF538050542CB592BC67E51
-:106C60000A3F14C1600F660C064636D30F6D6A05E5
-:106C700000208800E08C22721D63FF03C061C050B9
-:106C800003653875D80263FF6263FF5CC05002A5DC
-:106C90003875D08763FF8100C06003F63876D0BFB7
-:106CA00063FFB9006C10042A201529201614D7435D
-:106CB0000A990CCB9D2E200B04ED092BD11C8F289B
-:106CC00009BC36ACAA0CBB0C2BD51C0A0A472A24DB
-:106CD00015CAAF8B438942B0A800910400881AA856
-:106CE000FF0FBB029B278F260FB80C783B1AC020E2
-:106CF000D10F0000292102C0A20A9902292502C051
-:106D000021D10F008B2763FFDC2BD11C0CAA0C0AAE
-:106D10000A472A2415ACBB2BD51CC9AE8B438C2843
-:106D20008F42B0AD00F10400DD1AADCC0CBB029B6C
-:106D300027DA20B7EB580019C021D10F9F2763FF36
-:106D4000EF0000006C100428203C643047053060E0
-:106D500000073E01053EB156076539054928C77F42
-:106D6000A933030641076603B166060641A6337ED2
-:106D7000871E222125291AFC732B1502380C098144
-:106D80006000063E01023EB12406423903220AD1C8
-:106D90000FD230D10FC05163FFC000006C10042728
-:106DA000221EC08008E4311DD7030002002CD282CD
-:106DB0001BD703003104C06100661A2BB1020C6CB2
-:106DC000022CD6820BE43119D7870C3A11AA9328EA
-:106DD00032829780253282243284B45525368275DA
-:106DE000410A292102096902292502D10F2A21021B
-:106DF0002B32830A6A022B36822A2502D10F000029
-:106E00006C100418D6EC0C2711087708267286251A
-:106E10003C04765B1315D6E805220A2222A36820DB
-:106E200002742904227285D10FC020D10F00000006
-:106E30006C100419D6EB27221EC08009770208E4E3
-:106E4000311DD6DC0002002CD2821BD6DC003104BE
-:106E5000C06100661A2BB1020C6C022CD6820BE4C6
-:106E60003119D7600C3A11AA9328328297802532C3
-:106E700082243284B45525368275410B2A21020AB8
-:106E80006A022A2502D10F002B21022C32830B6BC0
-:106E9000022C36822B2502D10F0000006C10041B3F
-:106EA000D6C50C2A11ABAA29A286B438798B221B2D
-:106EB000D6C219D6E80B2B0A2BB2A309290868B051
-:106EC0000274B90D299D0129901F6E920822A28596
-:106ED000D10FC020D10FC892C020D10FDA205BEEB5
-:106EE000B3C020D10F0000006C100414D6B22842A9
-:106EF0009E19D6AF6F88026000BA29922668900763
-:106F00008A2009AA0C65A0AC2A429DC0DC64A0A41A
-:106F10002B200C19D6A90CBC11A4CC2EC28609B901
-:106F20000A7ED30260009A2992A36890078D2009F7
-:106F3000DD0C65D08C25C2856450862D2104C030BF
-:106F40006ED80D2C2066B8CC0C0C472C246665C07E
-:106F50007B1CD72518D6AF1AD6A619D6B61DD6AB28
-:106F6000C0E49E519D508F209357935599539A5644
-:106F70009A5408FF021AD6C29F5288269F5A9E59D9
-:106F80009D58935E9C5D935C9A5B08084805881148
-:106F9000985FC0D81FD6900CB911A499289285AFDC
-:106FA000BF23F4CF288C402896858E262D24069E5C
-:106FB00029C020D10FCA33DA20C0B65BFF78C72FB3
-:106FC000D10FC93ADA205BFF75C72FD10FDBD05B39
-:106FD000FE0B2324662B200C63FF7500C72FD10FF7
-:106FE000C72FD10F6C1004C85B29200668941C6859
-:106FF0009607C020D10FC020D10FDA20DB30DC4053
-:10700000DD502E0A005BFE5ED2A0D10F2E200C18A0
-:10701000D6690CEF11A8FF29F286C088798B791AFE
-:10702000D6660AEA0A2AA2A368A0048B207AB96865
-:1070300023F2856430621BD670290A802C206828D0
-:1070400020672D21040B881104DD1108DD020DCC11
-:1070500002C0842D4A100DCC021DD66898319D3097
-:107060008A2B99379C340BAA02C0C09C359C369A57
-:10707000322A2C74DB4028F285C0D3288C2028F6D5
-:10708000852C25042D24061FD653DD40AFEE2CE4BD
-:10709000CF5BFDEAD2A0D10F00DA20DBE05BFF3F3F
-:1070A000C020D10F6C100AD6302A200624160128E1
-:1070B000ACF86583862B2122C0F22A2124CC572AE2
-:1070C000AC010A0A4F2A25247ABB0260037F2C21D7
-:1070D000020C0C4C65C3192E22158D32C0910EDDA9
-:1070E0000C65D39088381ED63364836B8C37C0B858
-:1070F000C0960CB9399914B49A9A120D9911991332
-:107100008F6718D62EC9FB2880217F83168B142CFD
-:1071100022002A200C5BFF61D4A064A3B38F6760B8
-:10712000002800002B200C89120CBA11AEAA2CA248
-:10713000861DD6217C9B3E0DBD0A2DD2A368D004AE
-:1071400088207D893024A28564436427212E07F797
-:107150003607F90C6F9D01D7F0DA20DB70C1C42D22
-:10716000211F5BFEF889268827DDA009880C7A8B11
-:10717000179A10600006C04063FFCC0000DA208B35
-:10718000105BFEC88D1065A267C0E09E488C649CB1
-:10719000498B658A669B4A9A4B97458F677F730236
-:1071A000600120CD529D10DA20DB302C12015BFEF5
-:1071B000698D10C051D6A08FA7C0C08A68974D9A1C
-:1071C0004C8869896A984E994F8E6A8A69AE7E7733
-:1071D000EB01B1AA9E6A9A698B60C0A00B8E1477EE
-:1071E000B701C0A1C091C08493159D179516C0D05A
-:1071F00025203CC030085801089338C0820833105D
-:10720000085B010535400B9D3807DD100BAB100EF8
-:1072100019402A211F07991003DD020DBB020553F7
-:10722000100933020A55112921250A2A14092914A3
-:107230000499110A99020933028A2B2921040BAA05
-:10724000021BD66A0899110955020855020BAA02B9
-:107250009A408920881408991109880219D5EA1DD5
-:10726000D66409880298418B2A9346954783150D69
-:10727000BB0285168D179B448A658966AACAA97CBC
-:1072800077CB01B1AA07FB0C9C669A6588268E29EC
-:10729000AD87972607EE0C0E0E482E25259B672BF3
-:1072A000200C87131ED5C40CB911AE99289285A75E
-:1072B0008828968517D5C8C090A7BB29B4CF871852
-:1072C00063FE3C008C60C0E0C091C0F0C034C0B828
-:1072D0002A210428203C08AA110B8B0103830103F7
-:1072E0009F380B9B39C03208FF10038801089E3875
-:1072F0000C881407EE100FEE020388010898390578
-:10730000BF1029211F0ABB1107881008FF020BAA12
-:107310000218D5BC09291403AA022B212583200BAE
-:107320002B1404BB110833110FBB020B99028B14F1
-:107330008F2A0B33020833028B2B64708688689780
-:107340004D984C8769886A93419946974E984FC0EB
-:107350007077C701C0719A4718D6260B7C100CECC9
-:107360000208F802984418D6230CBC0208CC029CF0
-:10737000402A200C295CFEC0801FD58E1CD5960C9F
-:10738000AE112B2124ACAAAFEEB0BB8F132CE2853B
-:1073900028A4CFAFCC2CE6852A22152B2524B1AA10
-:1073A0002A26156490DBC9D28F262E22090DFF08EC
-:1073B0002F26060FEE0C0E0E482E25256550E4C034
-:1073C00020D10F00C07093419F4499469A4777C7D8
-:1073D0000A1CD57A2CC022C0810C87381CD6070B1A
-:1073E000781008E80208B8020C8802984063FF8011
-:1073F00000CC57DA20DB608C115BFDD629210268B6
-:107400009806689403C020D10F2B221EC0A0292209
-:107410001D2A25027B9901C0B064BFE813D5652CF5
-:10742000B00728B000DA2003880A28824CC0D10BAC
-:107430008000DBA065AFE763FFCA000068A779DAC8
-:1074400020DB30DC40DD505BFEE7D2A0D10FC16D08
-:10745000C19D29252C60000429252CD6902624675F
-:107460002F2468DA20DB308C11DD502E0A805BFD82
-:1074700044D2A0D10FC168C1A82A252C63FFDD002A
-:107480000000C8DF8C268B29ADCC9C260CBB0C0BD6
-:107490000B482B25252A2C74DB602C12015BFD8701
-:1074A000D2A0D10F2A2C748B115BF6B9D2A0D10FC8
-:1074B000DA205BFE3A63FF3800DA20C0B15BFE8A57
-:1074C00064ABF1655F352D2124B1DD2D252463FFEB
-:1074D0001FDA202B200C5BFE5663FF1412D5C882E6
-:1074E00020028257C82163FFFC12D5C403E8300490
-:1074F000EE3005B13093209421952263FFFC00000B
-:1075000010D5C0910092019302940311D597821077
-:1075100001EA30A21101F031C04004E4160002007B
-:1075200011D5B98210234A00032202921011D5828C
-:10753000C021921004E4318403830282018100009F
-:10754000D23001230000000010D5B09100920193C9
-:1075500002940311D586821001EA30A21101F131A3
-:10756000C04004E41600020011D5A7821013D52BE9
-:10757000032202921004E431840383028201810019
-:1075800000D330013300000010D5A19100810165C6
-:10759000104981026510448103CF1F920193029428
-:1075A0000311D574821001EA30A21101F231C040FA
-:1075B00004E41600020011D593821013D5130322A0
-:1075C00002921004E431840383028201C01091030B
-:1075D00091029101810000D43001430012D542C0D4
-:1075E0003028374028374428374828374C233D0176
-:1075F0007233ED03020063FFFC00000010D585919B
-:107600000092019302940311D5838210921011D538
-:10761000348310032202921011D58012D5469210A5
-:10762000C04004E41600020011D577821013D52D56
-:10763000032202921004E431840383028201810058
-:1076400000D53001530000006C10026E322FD6209E
-:10765000056F04043F04745B2A05440C00410400D8
-:10766000331A220A006D490D73630403660CB122BC
-:107670000F2211031314736302222C01D10FC83B94
-:10768000D10F000073630CC021D10F000000000077
-:1076900044495630C020D10F6C10020040046B4C9E
-:1076A00007032318020219D10F020319C020D10FBA
-:1076B0006C100202EA30D10F6C1002CC2503F031BD
-:1076C00060000F006F220503F1316000056F230594
-:1076D00003F231000200D10F6C1002CC2502F03011
-:1076E000D10F00006F220402F130D10F6F2304028A
-:1076F000F230D10FC020D10F6C1002220A20230AD1
-:10770000006D280E28374028374428374828374C42
-:10771000233D01030200D10F6C100202E431D10FAE
-:107720000A004368656C73696F20465720444542E0
-:1077300055473D3020284275696C74204672692097
-:107740004D61792020382031363A30373A333620AF
-:107750005044542032303039206F6E20636C656F96
-:1077600070617472612E6173696364657369676EB9
-:107770006572732E636F6D3A2F686F6D652F666546
-:107780006C69782F772F66775F372E31292C20563A
-:10779000657273696F6E2054337878203030372EDD
-:1077A00030342E3030202D203130303730343030EE
-:0877B000100704000071489469
-:00000001FF
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 99d6af8..b3171fb 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -681,8 +681,8 @@
 	if (!bd_may_claim(bdev, whole, holder))
 		return -EBUSY;
 
-	/* if someone else is claiming, wait for it to finish */
-	if (whole->bd_claiming && whole->bd_claiming != holder) {
+	/* if claiming is already in progress, wait for it to finish */
+	if (whole->bd_claiming) {
 		wait_queue_head_t *wq = bit_waitqueue(&whole->bd_claiming, 0);
 		DEFINE_WAIT(wait);
 
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 5ead376..63ae858 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -601,8 +601,11 @@
 }
 
 /* Bluetooth ioctls */
-#define HCIUARTSETPROTO	_IOW('U', 200, int)
-#define HCIUARTGETPROTO	_IOR('U', 201, int)
+#define HCIUARTSETPROTO		_IOW('U', 200, int)
+#define HCIUARTGETPROTO		_IOR('U', 201, int)
+#define HCIUARTGETDEVICE	_IOR('U', 202, int)
+#define HCIUARTSETFLAGS		_IOW('U', 203, int)
+#define HCIUARTGETFLAGS		_IOR('U', 204, int)
 
 #define BNEPCONNADD	_IOW('B', 200, int)
 #define BNEPCONNDEL	_IOW('B', 201, int)
@@ -1328,6 +1331,8 @@
 COMPATIBLE_IOCTL(HCISETLINKMODE)
 COMPATIBLE_IOCTL(HCISETACLMTU)
 COMPATIBLE_IOCTL(HCISETSCOMTU)
+COMPATIBLE_IOCTL(HCIBLOCKADDR)
+COMPATIBLE_IOCTL(HCIUNBLOCKADDR)
 COMPATIBLE_IOCTL(HCIINQUIRY)
 COMPATIBLE_IOCTL(HCIUARTSETPROTO)
 COMPATIBLE_IOCTL(HCIUARTGETPROTO)
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 3cdc5f7..431be07 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1016,7 +1016,7 @@
 		   exist.  So if permissions are revoked this won't be
 		   noticed immediately, only after the attribute
 		   timeout has expired */
-	} else if (mask & MAY_ACCESS) {
+	} else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
 		err = fuse_access(inode, mask);
 	} else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
 		if (!(inode->i_mode & S_IXUGO)) {
diff --git a/fs/namei.c b/fs/namei.c
index 868d0cb..42d2d28 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -282,8 +282,7 @@
 	if (retval)
 		return retval;
 
-	return security_inode_permission(inode,
-			mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
+	return security_inode_permission(inode, mask);
 }
 
 /**
@@ -1484,8 +1483,7 @@
 	 */
 	error = locks_verify_locked(inode);
 	if (!error)
-		error = security_path_truncate(path, 0,
-				       ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
+		error = security_path_truncate(path);
 	if (!error) {
 		error = do_truncate(path->dentry, 0,
 				    ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index e60416d..832e9e2 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1953,7 +1953,7 @@
 	if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
 		goto out;
 	/* Is this sys_access() ? */
-	if (mask & MAY_ACCESS)
+	if (mask & (MAY_ACCESS | MAY_CHDIR))
 		goto force_lookup;
 
 	switch (inode->i_mode & S_IFMT) {
diff --git a/fs/open.c b/fs/open.c
index 5463266..0d1fa3d 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -110,7 +110,7 @@
 
 	error = locks_verify_truncate(inode, NULL, length);
 	if (!error)
-		error = security_path_truncate(&path, length, 0);
+		error = security_path_truncate(&path);
 	if (!error)
 		error = do_truncate(path.dentry, length, 0, NULL);
 
@@ -165,8 +165,7 @@
 
 	error = locks_verify_truncate(inode, file, length);
 	if (!error)
-		error = security_path_truncate(&file->f_path, length,
-					       ATTR_MTIME|ATTR_CTIME);
+		error = security_path_truncate(&file->f_path);
 	if (!error)
 		error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
 out_putf:
@@ -367,7 +366,7 @@
 	if (error)
 		goto out;
 
-	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
+	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
 	if (error)
 		goto dput_and_out;
 
@@ -396,7 +395,7 @@
 	if (!S_ISDIR(inode->i_mode))
 		goto out_putf;
 
-	error = inode_permission(inode, MAY_EXEC | MAY_ACCESS);
+	error = inode_permission(inode, MAY_EXEC | MAY_CHDIR);
 	if (!error)
 		set_fs_pwd(current->fs, &file->f_path);
 out_putf:
@@ -414,7 +413,7 @@
 	if (error)
 		goto out;
 
-	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
+	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
 	if (error)
 		goto dput_and_out;
 
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index 7f0028e..8f8b072 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -33,6 +33,15 @@
  * subject to backwards-compatibility constraints.
  */
 
+#ifdef __KERNEL__
+/* For use by IPS driver */
+extern unsigned long i915_read_mch_val(void);
+extern bool i915_gpu_raise(void);
+extern bool i915_gpu_lower(void);
+extern bool i915_gpu_busy(void);
+extern bool i915_gpu_turbo_disable(void);
+#endif
+
 /* Each region is a minimum of 16k, and there are at most 255 of them.
  */
 #define I915_NR_TEX_REGIONS 255	/* table size 2k - maximum due to use
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 2fc8e14..9aa9bca 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -276,6 +276,7 @@
 		  $(srctree)/include/asm-$(SRCARCH)/kvm_para.h),)
 unifdef-y += kvm_para.h
 endif
+unifdef-y += l2tp.h
 unifdef-y += llc.h
 unifdef-y += loop.h
 unifdef-y += lp.h
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
index 817b237..f6481da 100644
--- a/include/linux/atmdev.h
+++ b/include/linux/atmdev.h
@@ -431,6 +431,14 @@
     int number,unsigned long *flags); /* number == -1: pick first available */
 struct atm_dev *atm_dev_lookup(int number);
 void atm_dev_deregister(struct atm_dev *dev);
+
+/* atm_dev_signal_change
+ *
+ * Propagate lower layer signal change in atm_dev->signal to netdevice.
+ * The event will be sent via a notifier call chain.
+ */
+void atm_dev_signal_change(struct atm_dev *dev, char signal);
+
 void vcc_insert_socket(struct sock *sk);
 
 
@@ -510,6 +518,15 @@
  */
 void deregister_atm_ioctl(struct atm_ioctl *);
 
+
+/* register_atmdevice_notifier - register atm_dev notify events
+ *
+ * Clients like br2684 will register notify events
+ * Currently we notify of signal found/lost
+ */
+int register_atmdevice_notifier(struct notifier_block *nb);
+void unregister_atmdevice_notifier(struct notifier_block *nb);
+
 #endif /* __KERNEL__ */
 
 #endif
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
index 7f437ca..b840a49 100644
--- a/include/linux/brcmphy.h
+++ b/include/linux/brcmphy.h
@@ -1,6 +1,13 @@
 #define PHY_ID_BCM50610			0x0143bd60
 #define PHY_ID_BCM50610M		0x0143bd70
+#define PHY_ID_BCM5241			0x0143bc30
 #define PHY_ID_BCMAC131			0x0143bc70
+#define PHY_ID_BCM5481			0x0143bca0
+#define PHY_ID_BCM5482			0x0143bcb0
+#define PHY_ID_BCM5411			0x00206070
+#define PHY_ID_BCM5421			0x002060e0
+#define PHY_ID_BCM5464			0x002060b0
+#define PHY_ID_BCM5461			0x002060c0
 #define PHY_ID_BCM57780			0x03625d90
 
 #define PHY_BCM_OUI_MASK		0xfffffc00
diff --git a/include/linux/caif/caif_socket.h b/include/linux/caif/caif_socket.h
index 2a61eb1..d9cb19b 100644
--- a/include/linux/caif/caif_socket.h
+++ b/include/linux/caif/caif_socket.h
@@ -62,6 +62,7 @@
  * @CAIFPROTO_DATAGRAM_LOOP:	Datagram loopback channel, used for testing.
  * @CAIFPROTO_UTIL:		Utility (Psock) channel.
  * @CAIFPROTO_RFM:		Remote File Manager
+ * @CAIFPROTO_DEBUG:		Debug link
  *
  * This enum defines the CAIF Channel type to be used. This defines
  * the service to connect to on the modem.
@@ -72,6 +73,7 @@
 	CAIFPROTO_DATAGRAM_LOOP,
 	CAIFPROTO_UTIL,
 	CAIFPROTO_RFM,
+	CAIFPROTO_DEBUG,
 	_CAIFPROTO_MAX
 };
 #define	CAIFPROTO_MAX _CAIFPROTO_MAX
@@ -83,6 +85,28 @@
 enum caif_at_type {
 	CAIF_ATTYPE_PLAIN = 2
 };
+ /**
+ * enum caif_debug_type - Content selection for debug connection
+ * @CAIF_DEBUG_TRACE_INTERACTIVE: Connection will contain
+ *				both trace and interactive debug.
+ * @CAIF_DEBUG_TRACE:		Connection contains trace only.
+ * @CAIF_DEBUG_INTERACTIVE:	Connection to interactive debug.
+ */
+enum caif_debug_type {
+	CAIF_DEBUG_TRACE_INTERACTIVE = 0,
+	CAIF_DEBUG_TRACE,
+	CAIF_DEBUG_INTERACTIVE,
+};
+
+/**
+ * enum caif_debug_service - Debug Service Endpoint
+ * @CAIF_RADIO_DEBUG_SERVICE:	Debug service on the Radio sub-system
+ * @CAIF_APP_DEBUG_SERVICE:	Debug for the applications sub-system
+ */
+enum caif_debug_service {
+	CAIF_RADIO_DEBUG_SERVICE = 1,
+	CAIF_APP_DEBUG_SERVICE
+};
 
 /**
  * struct sockaddr_caif - the sockaddr structure for CAIF sockets.
@@ -109,6 +133,12 @@
  *
  * @u.rfm.volume:            Volume to mount.
  *
+ * @u.dbg:		      Applies when family = CAIFPROTO_DEBUG.
+ *
+ * @u.dbg.type:			     Type of debug connection to set up
+ *			      (caif_debug_type).
+ *
+ * @u.dbg.service:	      Service sub-system to connect (caif_debug_service
  * Description:
  * This structure holds the connect parameters used for setting up a
  * CAIF Channel. It defines the service to connect to on the modem.
@@ -130,6 +160,10 @@
 			__u32 connection_id;
 			char	  volume[16];
 		} rfm;				/* CAIFPROTO_RFM */
+		struct {
+			__u8  type;		/* type:enum caif_debug_type */
+			__u8  service;		/* service:caif_debug_service */
+		} dbg;				/* CAIFPROTO_DEBUG */
 	} u;
 };
 
diff --git a/include/linux/can/platform/flexcan.h b/include/linux/can/platform/flexcan.h
new file mode 100644
index 0000000..72b713a
--- /dev/null
+++ b/include/linux/can/platform/flexcan.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2010 Marc Kleine-Budde <kernel@pengutronix.de>
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#ifndef __CAN_PLATFORM_FLEXCAN_H
+#define __CAN_PLATFORM_FLEXCAN_H
+
+/**
+ * struct flexcan_platform_data - flex CAN controller platform data
+ * @transceiver_enable:         - called to power on/off the transceiver
+ *
+ */
+struct flexcan_platform_data {
+	void (*transceiver_switch)(int enable);
+};
+
+#endif /* __CAN_PLATFORM_FLEXCAN_H */
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 39e5ff5..90012b9 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -49,9 +49,6 @@
 } __user *cap_user_data_t;
 
 
-#define XATTR_CAPS_SUFFIX "capability"
-#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
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index e3d00fd..ed3e92e 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -578,6 +578,7 @@
 void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it);
 int cgroup_scan_tasks(struct cgroup_scanner *scan);
 int cgroup_attach_task(struct cgroup *, struct task_struct *);
+int cgroup_attach_task_current_cg(struct task_struct *);
 
 /*
  * CSS ID is ID for cgroup_subsys_state structs under subsys. This only works
@@ -634,6 +635,12 @@
 	return -EINVAL;
 }
 
+/* No cgroups - nothing to do */
+static inline int cgroup_attach_task_current_cg(struct task_struct *t)
+{
+	return 0;
+}
+
 #endif /* !CONFIG_CGROUPS */
 
 #endif /* _LINUX_CGROUP_H */
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 9f15150..c3e9de8 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -196,11 +196,6 @@
 int cpufreq_register_governor(struct cpufreq_governor *governor);
 void cpufreq_unregister_governor(struct cpufreq_governor *governor);
 
-int lock_policy_rwsem_read(int cpu);
-int lock_policy_rwsem_write(int cpu);
-void unlock_policy_rwsem_read(int cpu);
-void unlock_policy_rwsem_write(int cpu);
-
 
 /*********************************************************************
  *                      CPUFREQ DRIVER INTERFACE                     *
diff --git a/include/linux/device.h b/include/linux/device.h
index 0713e10..6a8276f 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -638,43 +638,103 @@
 
 /* debugging and troubleshooting/diagnostic helpers. */
 extern const char *dev_driver_string(const struct device *dev);
-#define dev_printk(level, dev, format, arg...)	\
-	printk(level "%s %s: " format , dev_driver_string(dev) , \
-	       dev_name(dev) , ## arg)
 
-#define dev_emerg(dev, format, arg...)		\
-	dev_printk(KERN_EMERG , dev , format , ## arg)
-#define dev_alert(dev, format, arg...)		\
-	dev_printk(KERN_ALERT , dev , format , ## arg)
-#define dev_crit(dev, format, arg...)		\
-	dev_printk(KERN_CRIT , dev , format , ## arg)
-#define dev_err(dev, format, arg...)		\
-	dev_printk(KERN_ERR , dev , format , ## arg)
-#define dev_warn(dev, format, arg...)		\
-	dev_printk(KERN_WARNING , dev , format , ## arg)
-#define dev_notice(dev, format, arg...)		\
-	dev_printk(KERN_NOTICE , dev , format , ## arg)
-#define dev_info(dev, format, arg...)		\
-	dev_printk(KERN_INFO , dev , format , ## arg)
+
+#ifdef CONFIG_PRINTK
+
+extern int dev_printk(const char *level, const struct device *dev,
+		      const char *fmt, ...)
+	__attribute__ ((format (printf, 3, 4)));
+extern int dev_emerg(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int dev_alert(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int dev_crit(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int dev_err(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int dev_warn(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int dev_notice(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int _dev_info(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+
+#else
+
+static inline int dev_printk(const char *level, const struct device *dev,
+		      const char *fmt, ...)
+	__attribute__ ((format (printf, 3, 4)));
+static inline int dev_printk(const char *level, const struct device *dev,
+		      const char *fmt, ...)
+	 { return 0; }
+
+static inline int dev_emerg(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+static inline int dev_emerg(const struct device *dev, const char *fmt, ...)
+	{ return 0; }
+static inline int dev_crit(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+static inline int dev_crit(const struct device *dev, const char *fmt, ...)
+	{ return 0; }
+static inline int dev_alert(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+static inline int dev_alert(const struct device *dev, const char *fmt, ...)
+	{ return 0; }
+static inline int dev_err(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+static inline int dev_err(const struct device *dev, const char *fmt, ...)
+	{ return 0; }
+static inline int dev_warn(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+static inline int dev_warn(const struct device *dev, const char *fmt, ...)
+	{ return 0; }
+static inline int dev_notice(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+static inline int dev_notice(const struct device *dev, const char *fmt, ...)
+	{ return 0; }
+static inline int _dev_info(const struct device *dev, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+static inline int _dev_info(const struct device *dev, const char *fmt, ...)
+	{ return 0; }
+
+#endif
+
+/*
+ * Stupid hackaround for existing uses of non-printk uses dev_info
+ *
+ * Note that the definition of dev_info below is actually _dev_info
+ * and a macro is used to avoid redefining dev_info
+ */
+
+#define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
 
 #if defined(DEBUG)
 #define dev_dbg(dev, format, arg...)		\
-	dev_printk(KERN_DEBUG , dev , format , ## arg)
+	dev_printk(KERN_DEBUG, dev, format, ##arg)
 #elif defined(CONFIG_DYNAMIC_DEBUG)
-#define dev_dbg(dev, format, ...) do { \
+#define dev_dbg(dev, format, ...)		     \
+do {						     \
 	dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
-	} while (0)
+} while (0)
 #else
-#define dev_dbg(dev, format, arg...)		\
-	({ if (0) dev_printk(KERN_DEBUG, dev, format, ##arg); 0; })
+#define dev_dbg(dev, format, arg...)				\
+({								\
+	if (0)							\
+		dev_printk(KERN_DEBUG, dev, format, ##arg);	\
+	0;							\
+})
 #endif
 
 #ifdef VERBOSE_DEBUG
 #define dev_vdbg	dev_dbg
 #else
-
-#define dev_vdbg(dev, format, arg...)		\
-	({ if (0) dev_printk(KERN_DEBUG, dev, format, ##arg); 0; })
+#define dev_vdbg(dev, format, arg...)				\
+({								\
+	if (0)							\
+		dev_printk(KERN_DEBUG, dev, format, ##arg);	\
+	0;							\
+})
 #endif
 
 /*
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
index b6cb542..493a2bf 100644
--- a/include/linux/dvb/frontend.h
+++ b/include/linux/dvb/frontend.h
@@ -62,6 +62,7 @@
 	FE_CAN_8VSB			= 0x200000,
 	FE_CAN_16VSB			= 0x400000,
 	FE_HAS_EXTENDED_CAPS		= 0x800000,   /* We need more bitspace for newer APIs, indicate this. */
+	FE_CAN_TURBO_FEC		= 0x8000000,  /* frontend supports "turbo fec modulation" */
 	FE_CAN_2G_MODULATION		= 0x10000000, /* frontend supports "2nd generation modulation" (DVB-S2) */
 	FE_NEEDS_BENDING		= 0x20000000, /* not supported anymore, don't use (frontend requires frequency bending) */
 	FE_CAN_RECOVER			= 0x40000000, /* frontend can recover from a cable unplug automatically */
diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h
index 540b058..5a7546c 100644
--- a/include/linux/dvb/version.h
+++ b/include/linux/dvb/version.h
@@ -24,6 +24,6 @@
 #define _DVBVERSION_H_
 
 #define DVB_API_VERSION 5
-#define DVB_API_VERSION_MINOR 1
+#define DVB_API_VERSION_MINOR 2
 
 #endif /*_DVBVERSION_H_*/
diff --git a/include/linux/eeprom_93cx6.h b/include/linux/eeprom_93cx6.h
index a55c873..c4627cb 100644
--- a/include/linux/eeprom_93cx6.h
+++ b/include/linux/eeprom_93cx6.h
@@ -30,6 +30,7 @@
 #define PCI_EEPROM_WIDTH_93C46	6
 #define PCI_EEPROM_WIDTH_93C56	8
 #define PCI_EEPROM_WIDTH_93C66	8
+#define PCI_EEPROM_WIDTH_93C86	8
 #define PCI_EEPROM_WIDTH_OPCODE	3
 #define PCI_EEPROM_WRITE_OPCODE	0x05
 #define PCI_EEPROM_READ_OPCODE	0x06
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index 3d7a668..848480b 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -127,6 +127,20 @@
 }
 
 /**
+ * dev_hw_addr_random - Create random MAC and set device flag
+ * @dev: pointer to net_device structure
+ * @addr: Pointer to a six-byte array containing the Ethernet address
+ *
+ * Generate random MAC to be used by a device and set addr_assign_type
+ * so the state can be read by sysfs and be used by udev.
+ */
+static inline void dev_hw_addr_random(struct net_device *dev, u8 *hwaddr)
+{
+	dev->addr_assign_type |= NET_ADDR_RANDOM;
+	random_ether_addr(hwaddr);
+}
+
+/**
  * compare_ether_addr - Compare two Ethernet addresses
  * @addr1: Pointer to a six-byte array containing the Ethernet address
  * @addr2: Pointer other six-byte array containing the Ethernet address
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index b4207ca..991269e 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -386,6 +386,15 @@
 	__u32				rule_locs[0];
 };
 
+struct ethtool_rxfh_indir {
+	__u32	cmd;
+	/* On entry, this is the array size of the user buffer.  On
+	 * return from ETHTOOL_GRXFHINDIR, this is the array size of
+	 * the hardware indirection table. */
+	__u32	size;
+	__u32	ring_index[0];	/* ring/queue index for each hash value */
+};
+
 struct ethtool_rx_ntuple_flow_spec {
 	__u32		 flow_type;
 	union {
@@ -459,7 +468,7 @@
 u32 ethtool_op_get_ufo(struct net_device *dev);
 int ethtool_op_set_ufo(struct net_device *dev, u32 data);
 u32 ethtool_op_get_flags(struct net_device *dev);
-int ethtool_op_set_flags(struct net_device *dev, u32 data);
+int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported);
 void ethtool_ntuple_flush(struct net_device *dev);
 
 /**
@@ -578,6 +587,10 @@
 	int	(*set_rx_ntuple)(struct net_device *,
 				 struct ethtool_rx_ntuple *);
 	int	(*get_rx_ntuple)(struct net_device *, u32 stringset, void *);
+	int	(*get_rxfh_indir)(struct net_device *,
+				  struct ethtool_rxfh_indir *);
+	int	(*set_rxfh_indir)(struct net_device *,
+				  const struct ethtool_rxfh_indir *);
 };
 #endif /* __KERNEL__ */
 
@@ -588,29 +601,29 @@
 #define ETHTOOL_GREGS		0x00000004 /* Get NIC registers. */
 #define ETHTOOL_GWOL		0x00000005 /* Get wake-on-lan options. */
 #define ETHTOOL_SWOL		0x00000006 /* Set wake-on-lan options. */
-#define ETHTOOL_GMSGLVL	0x00000007 /* Get driver message level */
-#define ETHTOOL_SMSGLVL	0x00000008 /* Set driver msg level. */
+#define ETHTOOL_GMSGLVL		0x00000007 /* Get driver message level */
+#define ETHTOOL_SMSGLVL		0x00000008 /* Set driver msg level. */
 #define ETHTOOL_NWAY_RST	0x00000009 /* Restart autonegotiation. */
 #define ETHTOOL_GLINK		0x0000000a /* Get link status (ethtool_value) */
-#define ETHTOOL_GEEPROM	0x0000000b /* Get EEPROM data */
-#define ETHTOOL_SEEPROM	0x0000000c /* Set EEPROM data. */
+#define ETHTOOL_GEEPROM		0x0000000b /* Get EEPROM data */
+#define ETHTOOL_SEEPROM		0x0000000c /* Set EEPROM data. */
 #define ETHTOOL_GCOALESCE	0x0000000e /* Get coalesce config */
 #define ETHTOOL_SCOALESCE	0x0000000f /* Set coalesce config. */
 #define ETHTOOL_GRINGPARAM	0x00000010 /* Get ring parameters */
 #define ETHTOOL_SRINGPARAM	0x00000011 /* Set ring parameters. */
 #define ETHTOOL_GPAUSEPARAM	0x00000012 /* Get pause parameters */
 #define ETHTOOL_SPAUSEPARAM	0x00000013 /* Set pause parameters. */
-#define ETHTOOL_GRXCSUM	0x00000014 /* Get RX hw csum enable (ethtool_value) */
-#define ETHTOOL_SRXCSUM	0x00000015 /* Set RX hw csum enable (ethtool_value) */
-#define ETHTOOL_GTXCSUM	0x00000016 /* Get TX hw csum enable (ethtool_value) */
-#define ETHTOOL_STXCSUM	0x00000017 /* Set TX hw csum enable (ethtool_value) */
+#define ETHTOOL_GRXCSUM		0x00000014 /* Get RX hw csum enable (ethtool_value) */
+#define ETHTOOL_SRXCSUM		0x00000015 /* Set RX hw csum enable (ethtool_value) */
+#define ETHTOOL_GTXCSUM		0x00000016 /* Get TX hw csum enable (ethtool_value) */
+#define ETHTOOL_STXCSUM		0x00000017 /* Set TX hw csum enable (ethtool_value) */
 #define ETHTOOL_GSG		0x00000018 /* Get scatter-gather enable
 					    * (ethtool_value) */
 #define ETHTOOL_SSG		0x00000019 /* Set scatter-gather enable
 					    * (ethtool_value). */
 #define ETHTOOL_TEST		0x0000001a /* execute NIC self-test. */
 #define ETHTOOL_GSTRINGS	0x0000001b /* get specified string set */
-#define ETHTOOL_PHYS_ID	0x0000001c /* identify the NIC */
+#define ETHTOOL_PHYS_ID		0x0000001c /* identify the NIC */
 #define ETHTOOL_GSTATS		0x0000001d /* get NIC-specific statistics */
 #define ETHTOOL_GTSO		0x0000001e /* Get TSO enable (ethtool_value) */
 #define ETHTOOL_STSO		0x0000001f /* Set TSO enable (ethtool_value) */
@@ -621,8 +634,8 @@
 #define ETHTOOL_SGSO		0x00000024 /* Set GSO enable (ethtool_value) */
 #define ETHTOOL_GFLAGS		0x00000025 /* Get flags bitmap(ethtool_value) */
 #define ETHTOOL_SFLAGS		0x00000026 /* Set flags bitmap(ethtool_value) */
-#define ETHTOOL_GPFLAGS	0x00000027 /* Get driver-private flags bitmap */
-#define ETHTOOL_SPFLAGS	0x00000028 /* Set driver-private flags bitmap */
+#define ETHTOOL_GPFLAGS		0x00000027 /* Get driver-private flags bitmap */
+#define ETHTOOL_SPFLAGS		0x00000028 /* Set driver-private flags bitmap */
 
 #define ETHTOOL_GRXFH		0x00000029 /* Get RX flow hash configuration */
 #define ETHTOOL_SRXFH		0x0000002a /* Set RX flow hash configuration */
@@ -639,6 +652,8 @@
 #define ETHTOOL_SRXNTUPLE	0x00000035 /* Add an n-tuple filter to device */
 #define ETHTOOL_GRXNTUPLE	0x00000036 /* Get n-tuple filters from device */
 #define ETHTOOL_GSSET_INFO	0x00000037 /* Get string set info */
+#define ETHTOOL_GRXFHINDIR	0x00000038 /* Get RX flow hash indir'n table */
+#define ETHTOOL_SRXFHINDIR	0x00000039 /* Set RX flow hash indir'n table */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET		ETHTOOL_GSET
@@ -647,18 +662,18 @@
 /* Indicates what features are supported by the interface. */
 #define SUPPORTED_10baseT_Half		(1 << 0)
 #define SUPPORTED_10baseT_Full		(1 << 1)
-#define SUPPORTED_100baseT_Half	(1 << 2)
-#define SUPPORTED_100baseT_Full	(1 << 3)
+#define SUPPORTED_100baseT_Half		(1 << 2)
+#define SUPPORTED_100baseT_Full		(1 << 3)
 #define SUPPORTED_1000baseT_Half	(1 << 4)
 #define SUPPORTED_1000baseT_Full	(1 << 5)
 #define SUPPORTED_Autoneg		(1 << 6)
 #define SUPPORTED_TP			(1 << 7)
 #define SUPPORTED_AUI			(1 << 8)
 #define SUPPORTED_MII			(1 << 9)
-#define SUPPORTED_FIBRE		(1 << 10)
+#define SUPPORTED_FIBRE			(1 << 10)
 #define SUPPORTED_BNC			(1 << 11)
 #define SUPPORTED_10000baseT_Full	(1 << 12)
-#define SUPPORTED_Pause		(1 << 13)
+#define SUPPORTED_Pause			(1 << 13)
 #define SUPPORTED_Asym_Pause		(1 << 14)
 #define SUPPORTED_2500baseX_Full	(1 << 15)
 #define SUPPORTED_Backplane		(1 << 16)
@@ -668,8 +683,8 @@
 #define SUPPORTED_10000baseR_FEC	(1 << 20)
 
 /* Indicates what features are advertised by the interface. */
-#define ADVERTISED_10baseT_Half	(1 << 0)
-#define ADVERTISED_10baseT_Full	(1 << 1)
+#define ADVERTISED_10baseT_Half		(1 << 0)
+#define ADVERTISED_10baseT_Full		(1 << 1)
 #define ADVERTISED_100baseT_Half	(1 << 2)
 #define ADVERTISED_100baseT_Full	(1 << 3)
 #define ADVERTISED_1000baseT_Half	(1 << 4)
@@ -708,12 +723,12 @@
 #define DUPLEX_FULL		0x01
 
 /* Which connector port. */
-#define PORT_TP		0x00
+#define PORT_TP			0x00
 #define PORT_AUI		0x01
 #define PORT_MII		0x02
 #define PORT_FIBRE		0x03
 #define PORT_BNC		0x04
-#define PORT_DA		0x05
+#define PORT_DA			0x05
 #define PORT_NONE		0xef
 #define PORT_OTHER		0xff
 
@@ -727,7 +742,7 @@
 /* Enable or disable autonegotiation.  If this is set to enable,
  * the forced link modes above are completely ignored.
  */
-#define AUTONEG_DISABLE	0x00
+#define AUTONEG_DISABLE		0x00
 #define AUTONEG_ENABLE		0x01
 
 /* Mode MDI or MDI-X */
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 151f5d7..69b43db 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -91,6 +91,54 @@
 #define         BPF_TAX         0x00
 #define         BPF_TXA         0x80
 
+enum {
+	BPF_S_RET_K = 0,
+	BPF_S_RET_A,
+	BPF_S_ALU_ADD_K,
+	BPF_S_ALU_ADD_X,
+	BPF_S_ALU_SUB_K,
+	BPF_S_ALU_SUB_X,
+	BPF_S_ALU_MUL_K,
+	BPF_S_ALU_MUL_X,
+	BPF_S_ALU_DIV_X,
+	BPF_S_ALU_AND_K,
+	BPF_S_ALU_AND_X,
+	BPF_S_ALU_OR_K,
+	BPF_S_ALU_OR_X,
+	BPF_S_ALU_LSH_K,
+	BPF_S_ALU_LSH_X,
+	BPF_S_ALU_RSH_K,
+	BPF_S_ALU_RSH_X,
+	BPF_S_ALU_NEG,
+	BPF_S_LD_W_ABS,
+	BPF_S_LD_H_ABS,
+	BPF_S_LD_B_ABS,
+	BPF_S_LD_W_LEN,
+	BPF_S_LD_W_IND,
+	BPF_S_LD_H_IND,
+	BPF_S_LD_B_IND,
+	BPF_S_LD_IMM,
+	BPF_S_LDX_W_LEN,
+	BPF_S_LDX_B_MSH,
+	BPF_S_LDX_IMM,
+	BPF_S_MISC_TAX,
+	BPF_S_MISC_TXA,
+	BPF_S_ALU_DIV_K,
+	BPF_S_LD_MEM,
+	BPF_S_LDX_MEM,
+	BPF_S_ST,
+	BPF_S_STX,
+	BPF_S_JMP_JA,
+	BPF_S_JMP_JEQ_K,
+	BPF_S_JMP_JEQ_X,
+	BPF_S_JMP_JGE_K,
+	BPF_S_JMP_JGE_X,
+	BPF_S_JMP_JGT_K,
+	BPF_S_JMP_JGT_X,
+	BPF_S_JMP_JSET_K,
+	BPF_S_JMP_JSET_X,
+};
+
 #ifndef BPF_MAXINSNS
 #define BPF_MAXINSNS 4096
 #endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f91affb..e5106e4 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -53,6 +53,7 @@
 #define MAY_APPEND 8
 #define MAY_ACCESS 16
 #define MAY_OPEN 32
+#define MAY_CHDIR 64
 
 /*
  * flags in file.f_mode.  Note that FMODE_READ and FMODE_WRITE must correspond
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 895001f..42a0f1d 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -311,6 +311,7 @@
 #define HID_QUIRK_HIDDEV_FORCE			0x00000010
 #define HID_QUIRK_BADPAD			0x00000020
 #define HID_QUIRK_MULTI_INPUT			0x00000040
+#define HID_QUIRK_HIDINPUT_FORCE		0x00000080
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS		0x00010000
 #define HID_QUIRK_FULLSPEED_INTERVAL		0x10000000
 #define HID_QUIRK_NO_INIT_REPORTS		0x20000000
diff --git a/include/linux/i2c/adp5588.h b/include/linux/i2c/adp5588.h
index 02c9af3..269181b 100644
--- a/include/linux/i2c/adp5588.h
+++ b/include/linux/i2c/adp5588.h
@@ -78,6 +78,40 @@
 
 #define ADP5588_KEYMAPSIZE	80
 
+#define GPI_PIN_ROW0 97
+#define GPI_PIN_ROW1 98
+#define GPI_PIN_ROW2 99
+#define GPI_PIN_ROW3 100
+#define GPI_PIN_ROW4 101
+#define GPI_PIN_ROW5 102
+#define GPI_PIN_ROW6 103
+#define GPI_PIN_ROW7 104
+#define GPI_PIN_COL0 105
+#define GPI_PIN_COL1 106
+#define GPI_PIN_COL2 107
+#define GPI_PIN_COL3 108
+#define GPI_PIN_COL4 109
+#define GPI_PIN_COL5 110
+#define GPI_PIN_COL6 111
+#define GPI_PIN_COL7 112
+#define GPI_PIN_COL8 113
+#define GPI_PIN_COL9 114
+
+#define GPI_PIN_ROW_BASE GPI_PIN_ROW0
+#define GPI_PIN_ROW_END GPI_PIN_ROW7
+#define GPI_PIN_COL_BASE GPI_PIN_COL0
+#define GPI_PIN_COL_END GPI_PIN_COL9
+
+#define GPI_PIN_BASE GPI_PIN_ROW_BASE
+#define GPI_PIN_END GPI_PIN_COL_END
+
+#define ADP5588_GPIMAPSIZE_MAX (GPI_PIN_END - GPI_PIN_BASE + 1)
+
+struct adp5588_gpi_map {
+	unsigned short pin;
+	unsigned short sw_evt;
+};
+
 struct adp5588_kpad_platform_data {
 	int rows;			/* Number of rows */
 	int cols;			/* Number of columns */
@@ -87,6 +121,9 @@
 	unsigned en_keylock:1;		/* Enable Key Lock feature */
 	unsigned short unlock_key1;	/* Unlock Key 1 */
 	unsigned short unlock_key2;	/* Unlock Key 2 */
+	const struct adp5588_gpi_map *gpimap;
+	unsigned short gpimapsize;
+	const struct adp5588_gpio_platform_data *gpio_data;
 };
 
 struct adp5588_gpio_platform_data {
diff --git a/include/linux/i2c/mcs.h b/include/linux/i2c/mcs.h
new file mode 100644
index 0000000..725ae7c
--- /dev/null
+++ b/include/linux/i2c/mcs.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 - 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MCS_H
+#define __LINUX_MCS_H
+
+#define MCS_KEY_MAP(v, c)	((((v) & 0xff) << 16) | ((c) & 0xffff))
+#define MCS_KEY_VAL(v)		(((v) >> 16) & 0xff)
+#define MCS_KEY_CODE(v)		((v) & 0xffff)
+
+struct mcs_platform_data {
+	void (*cfg_pin)(void);
+
+	/* touchscreen */
+	unsigned int x_size;
+	unsigned int y_size;
+
+	/* touchkey */
+	const u32 *keymap;
+	unsigned int keymap_size;
+	unsigned int key_maxval;
+	bool no_autorepeat;
+};
+
+#endif	/* __LINUX_MCS_H */
diff --git a/include/linux/i2c/mcs5000_ts.h b/include/linux/i2c/mcs5000_ts.h
deleted file mode 100644
index 5a117b5..0000000
--- a/include/linux/i2c/mcs5000_ts.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * mcs5000_ts.h
- *
- * Copyright (C) 2009 Samsung Electronics Co.Ltd
- * Author: Joonyoung Shim <jy0922.shim@samsung.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
-
-#ifndef __LINUX_MCS5000_TS_H
-#define __LINUX_MCS5000_TS_H
-
-/* platform data for the MELFAS MCS-5000 touchscreen driver */
-struct mcs5000_ts_platform_data {
-	void (*cfg_pin)(void);
-	int x_size;
-	int y_size;
-};
-
-#endif	/* __LINUX_MCS5000_TS_H */
diff --git a/include/linux/i2c/qt602240_ts.h b/include/linux/i2c/qt602240_ts.h
new file mode 100644
index 0000000..c5033e1
--- /dev/null
+++ b/include/linux/i2c/qt602240_ts.h
@@ -0,0 +1,38 @@
+/*
+ * AT42QT602240/ATMXT224 Touchscreen driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __LINUX_QT602240_TS_H
+#define __LINUX_QT602240_TS_H
+
+/* Orient */
+#define QT602240_NORMAL			0x0
+#define QT602240_DIAGONAL		0x1
+#define QT602240_HORIZONTAL_FLIP	0x2
+#define QT602240_ROTATED_90_COUNTER	0x3
+#define QT602240_VERTICAL_FLIP		0x4
+#define QT602240_ROTATED_90		0x5
+#define QT602240_ROTATED_180		0x6
+#define QT602240_DIAGONAL_COUNTER	0x7
+
+/* The platform data for the AT42QT602240/ATMXT224 touchscreen driver */
+struct qt602240_platform_data {
+	unsigned int x_line;
+	unsigned int y_line;
+	unsigned int x_size;
+	unsigned int y_size;
+	unsigned int blen;
+	unsigned int threshold;
+	unsigned int voltage;
+	unsigned char orient;
+};
+
+#endif /* __LINUX_QT602240_TS_H */
diff --git a/include/linux/if.h b/include/linux/if.h
index be350e6..53558ec 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -73,6 +73,8 @@
 #define IFF_DONT_BRIDGE 0x800		/* disallow bridging this ether dev */
 #define IFF_IN_NETPOLL	0x1000		/* whether we are processing netpoll */
 #define IFF_DISABLE_NETPOLL	0x2000	/* disable netpoll at run-time */
+#define IFF_MACVLAN_PORT	0x4000	/* device used as macvlan port */
+#define IFF_BRIDGE_PORT	0x8000		/* device used as bridge port */
 
 #define IF_GET_IFACE	0x0001		/* for querying only */
 #define IF_GET_PROTO	0x0002
diff --git a/include/linux/if_bonding.h b/include/linux/if_bonding.h
index cd525fa..2c799437 100644
--- a/include/linux/if_bonding.h
+++ b/include/linux/if_bonding.h
@@ -83,6 +83,7 @@
 
 #define BOND_DEFAULT_MAX_BONDS  1   /* Default maximum number of devices to support */
 
+#define BOND_DEFAULT_TX_QUEUES 16   /* Default number of tx queues per device */
 /* hashing types */
 #define BOND_XMIT_POLICY_LAYER2		0 /* layer 2 (MAC only), default */
 #define BOND_XMIT_POLICY_LAYER34	1 /* layer 3+4 (IP ^ (TCP || UDP)) */
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 938b7e8..0d241a5 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -102,8 +102,6 @@
 #include <linux/netdevice.h>
 
 extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
-extern struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p,
-					       struct sk_buff *skb);
 extern int (*br_should_route_hook)(struct sk_buff *skb);
 
 #endif
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index bed7a46..c831467 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -119,7 +119,7 @@
 	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
 	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
 	__be16		h_proto;		/* packet type ID field	*/
-} __attribute__((packed));
+} __packed;
 
 #ifdef __KERNEL__
 #include <linux/skbuff.h>
diff --git a/include/linux/if_fddi.h b/include/linux/if_fddi.h
index 5459c5c..9947c39 100644
--- a/include/linux/if_fddi.h
+++ b/include/linux/if_fddi.h
@@ -67,7 +67,7 @@
 	__u8	dsap;					/* destination service access point */
 	__u8	ssap;					/* source service access point */
 	__u8	ctrl;					/* control byte #1 */
-} __attribute__ ((packed));
+} __packed;
 
 /* Define 802.2 Type 2 header */
 struct fddi_8022_2_hdr {
@@ -75,7 +75,7 @@
 	__u8	ssap;					/* source service access point */
 	__u8	ctrl_1;					/* control byte #1 */
 	__u8	ctrl_2;					/* control byte #2 */
-} __attribute__ ((packed));
+} __packed;
 
 /* Define 802.2 SNAP header */
 #define FDDI_K_OUI_LEN	3
@@ -85,7 +85,7 @@
 	__u8	ctrl;					/* always 0x03 */
 	__u8	oui[FDDI_K_OUI_LEN];	/* organizational universal id */
 	__be16	ethertype;				/* packet type ID field */
-} __attribute__ ((packed));
+} __packed;
 
 /* Define FDDI LLC frame header */
 struct fddihdr {
@@ -98,7 +98,7 @@
 		struct fddi_8022_2_hdr		llc_8022_2;
 		struct fddi_snap_hdr		llc_snap;
 		} hdr;
-} __attribute__ ((packed));
+} __packed;
 
 #ifdef __KERNEL__
 #include <linux/netdevice.h>
diff --git a/include/linux/if_frad.h b/include/linux/if_frad.h
index 80b3a10..191ee08 100644
--- a/include/linux/if_frad.h
+++ b/include/linux/if_frad.h
@@ -135,7 +135,7 @@
    __be16 PID;
 
 #define IP_NLPID pad 
-} __attribute__((packed));
+} __packed;
 
 /* see RFC 1490 for the definition of the following */
 #define FRAD_I_UI		0x03
diff --git a/include/linux/if_hippi.h b/include/linux/if_hippi.h
index 8d038eb..5fe5f30 100644
--- a/include/linux/if_hippi.h
+++ b/include/linux/if_hippi.h
@@ -104,7 +104,7 @@
 	__be32		fixed;
 #endif
 	__be32		d2_size;
-} __attribute__ ((packed));
+} __packed;
 
 struct hippi_le_hdr {
 #if defined (__BIG_ENDIAN_BITFIELD)
@@ -129,7 +129,7 @@
 	__u8		daddr[HIPPI_ALEN];
 	__u16		locally_administered;
 	__u8		saddr[HIPPI_ALEN];
-} __attribute__ ((packed));
+} __packed;
 
 #define HIPPI_OUI_LEN	3
 /*
@@ -142,12 +142,12 @@
 	__u8	ctrl;			/* always 0x03 */
 	__u8	oui[HIPPI_OUI_LEN];	/* organizational universal id (zero)*/
 	__be16	ethertype;		/* packet type ID field */
-} __attribute__ ((packed));
+} __packed;
 
 struct hippi_hdr {
 	struct hippi_fp_hdr	fp;
 	struct hippi_le_hdr	le;
 	struct hippi_snap_hdr	snap;
-} __attribute__ ((packed));
+} __packed;
 
 #endif	/* _LINUX_IF_HIPPI_H */
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 9d8f080..2fc66dd 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -4,7 +4,7 @@
 #include <linux/types.h>
 #include <linux/netlink.h>
 
-/* The struct should be in sync with struct net_device_stats */
+/* This struct should be in sync with struct rtnl_link_stats64 */
 struct rtnl_link_stats {
 	__u32	rx_packets;		/* total packets received	*/
 	__u32	tx_packets;		/* total packets transmitted	*/
@@ -37,6 +37,7 @@
 	__u32	tx_compressed;
 };
 
+/* The main device statistics structure */
 struct rtnl_link_stats64 {
 	__u64	rx_packets;		/* total packets received	*/
 	__u64	tx_packets;		/* total packets transmitted	*/
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
index 1ffaeff..35280b3 100644
--- a/include/linux/if_macvlan.h
+++ b/include/linux/if_macvlan.h
@@ -6,6 +6,7 @@
 #include <linux/netdevice.h>
 #include <linux/netlink.h>
 #include <net/netlink.h>
+#include <linux/u64_stats_sync.h>
 
 #if defined(CONFIG_MACVTAP) || defined(CONFIG_MACVTAP_MODULE)
 struct socket *macvtap_get_socket(struct file *);
@@ -27,14 +28,16 @@
  *	struct macvlan_rx_stats - MACVLAN percpu rx stats
  *	@rx_packets: number of received packets
  *	@rx_bytes: number of received bytes
- *	@multicast: number of received multicast packets
+ *	@rx_multicast: number of received multicast packets
+ *	@syncp: synchronization point for 64bit counters
  *	@rx_errors: number of errors
  */
 struct macvlan_rx_stats {
-	unsigned long rx_packets;
-	unsigned long rx_bytes;
-	unsigned long multicast;
-	unsigned long rx_errors;
+	u64			rx_packets;
+	u64			rx_bytes;
+	u64			rx_multicast;
+	struct u64_stats_sync	syncp;
+	unsigned long		rx_errors;
 };
 
 struct macvlan_dev {
@@ -56,12 +59,14 @@
 {
 	struct macvlan_rx_stats *rx_stats;
 
-	rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id());
+	rx_stats = this_cpu_ptr(vlan->rx_stats);
 	if (likely(success)) {
+		u64_stats_update_begin(&rx_stats->syncp);
 		rx_stats->rx_packets++;;
 		rx_stats->rx_bytes += len;
 		if (multicast)
-			rx_stats->multicast++;
+			rx_stats->rx_multicast++;
+		u64_stats_update_end(&rx_stats->syncp);
 	} else {
 		rx_stats->rx_errors++;
 	}
@@ -86,8 +91,4 @@
 extern netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
 				      struct net_device *dev);
 
-
-extern struct sk_buff *(*macvlan_handle_frame_hook)(struct macvlan_port *,
-						    struct sk_buff *);
-
 #endif /* _LINUX_IF_MACVLAN_H */
diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h
index 6ac23ef..72bfa5a 100644
--- a/include/linux/if_packet.h
+++ b/include/linux/if_packet.h
@@ -48,6 +48,7 @@
 #define PACKET_LOSS			14
 #define PACKET_VNET_HDR			15
 #define PACKET_TX_TIMESTAMP		16
+#define PACKET_TIMESTAMP		17
 
 struct tpacket_stats {
 	unsigned int	tp_packets;
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index a6577af..1925e0c 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -59,7 +59,7 @@
        union{ 
                struct pppoe_addr       pppoe; 
        }sa_addr; 
-}__attribute__ ((packed)); 
+} __packed;
 
 /* The use of the above union isn't viable because the size of this
  * struct must stay fixed over time -- applications use sizeof(struct
@@ -70,7 +70,7 @@
 	sa_family_t     sa_family;      /* address family, AF_PPPOX */
 	unsigned int    sa_protocol;    /* protocol identifier */
 	struct pppol2tp_addr pppol2tp;
-}__attribute__ ((packed));
+} __packed;
 
 /* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
  * bits. So we need a different sockaddr structure.
@@ -79,7 +79,7 @@
 	sa_family_t     sa_family;      /* address family, AF_PPPOX */
 	unsigned int    sa_protocol;    /* protocol identifier */
 	struct pppol2tpv3_addr pppol2tp;
-} __attribute__ ((packed));
+} __packed;
 
 /*********************************************************************
  *
@@ -129,7 +129,7 @@
 	__be16 sid;
 	__be16 length;
 	struct pppoe_tag tag[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Length of entire PPPoE + PPP header */
 #define PPPOE_SES_HLEN	8
diff --git a/include/linux/in.h b/include/linux/in.h
index 583c76f..41d88a4 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -85,6 +85,7 @@
 #define IP_RECVORIGDSTADDR   IP_ORIGDSTADDR
 
 #define IP_MINTTL       21
+#define IP_NODEFRAG     22
 
 /* IP_MTU_DISCOVER values */
 #define IP_PMTUDISC_DONT		0	/* Never send DF frames */
diff --git a/include/linux/input.h b/include/linux/input.h
index 6fcc9101..339d043 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -691,9 +691,12 @@
 #define ABS_TILT_X		0x1a
 #define ABS_TILT_Y		0x1b
 #define ABS_TOOL_WIDTH		0x1c
+
 #define ABS_VOLUME		0x20
+
 #define ABS_MISC		0x28
 
+#define ABS_MT_SLOT		0x2f	/* MT slot being modified */
 #define ABS_MT_TOUCH_MAJOR	0x30	/* Major axis of touching ellipse */
 #define ABS_MT_TOUCH_MINOR	0x31	/* Minor axis (omit if circular) */
 #define ABS_MT_WIDTH_MAJOR	0x32	/* Major axis of approaching ellipse */
@@ -706,6 +709,12 @@
 #define ABS_MT_TRACKING_ID	0x39	/* Unique ID of initiated contact */
 #define ABS_MT_PRESSURE		0x3a	/* Pressure on contact area */
 
+#ifdef __KERNEL__
+/* Implementation details, userspace should not care about these */
+#define ABS_MT_FIRST		ABS_MT_TOUCH_MAJOR
+#define ABS_MT_LAST		ABS_MT_PRESSURE
+#endif
+
 #define ABS_MAX			0x3f
 #define ABS_CNT			(ABS_MAX+1)
 
@@ -1048,6 +1057,14 @@
 #include <linux/mod_devicetable.h>
 
 /**
+ * struct input_mt_slot - represents the state of an input MT slot
+ * @abs: holds current values of ABS_MT axes for this slot
+ */
+struct input_mt_slot {
+	int abs[ABS_MT_LAST - ABS_MT_FIRST + 1];
+};
+
+/**
  * struct input_dev - represents an input device
  * @name: name of the device
  * @phys: physical path to the device in the system hierarchy
@@ -1063,6 +1080,10 @@
  * @sndbit: bitmap of sound effects supported by the device
  * @ffbit: bitmap of force feedback effects supported by the device
  * @swbit: bitmap of switches present on the device
+ * @hint_events_per_packet: average number of events generated by the
+ *	device in a packet (between EV_SYN/SYN_REPORT events). Used by
+ *	event handlers to estimate size of the buffer needed to hold
+ *	events.
  * @keycodemax: size of keycode table
  * @keycodesize: size of elements in keycode table
  * @keycode: map of scancodes to keycodes for this device
@@ -1078,9 +1099,12 @@
  * @repeat_key: stores key code of the last key pressed; used to implement
  *	software autorepeat
  * @timer: timer for software autorepeat
- * @sync: set to 1 when there were no new events since last EV_SYNC
  * @abs: current values for reports from absolute axes
  * @rep: current values for autorepeat parameters (delay, rate)
+ * @mt: pointer to array of struct input_mt_slot holding current values
+ *	of tracked contacts
+ * @mtsize: number of MT slots the device uses
+ * @slot: MT slot currently being transmitted
  * @key: reflects current state of device's keys/buttons
  * @led: reflects current state of device's LEDs
  * @snd: reflects current state of sound effects
@@ -1119,6 +1143,7 @@
  *	last user closes the device
  * @going_away: marks devices that are in a middle of unregistering and
  *	causes input_open_device*() fail with -ENODEV.
+ * @sync: set to %true when there were no new events since last EV_SYN
  * @dev: driver model's view of this device
  * @h_list: list of input handles associated with the device. When
  *	accessing the list dev->mutex must be held
@@ -1140,6 +1165,8 @@
 	unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
 	unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
 
+	unsigned int hint_events_per_packet;
+
 	unsigned int keycodemax;
 	unsigned int keycodesize;
 	void *keycode;
@@ -1153,11 +1180,13 @@
 	unsigned int repeat_key;
 	struct timer_list timer;
 
-	int sync;
-
 	int abs[ABS_CNT];
 	int rep[REP_MAX + 1];
 
+	struct input_mt_slot *mt;
+	int mtsize;
+	int slot;
+
 	unsigned long key[BITS_TO_LONGS(KEY_CNT)];
 	unsigned long led[BITS_TO_LONGS(LED_CNT)];
 	unsigned long snd[BITS_TO_LONGS(SND_CNT)];
@@ -1182,6 +1211,8 @@
 	unsigned int users;
 	bool going_away;
 
+	bool sync;
+
 	struct device dev;
 
 	struct list_head	h_list;
@@ -1406,8 +1437,28 @@
 	input_event(dev, EV_SYN, SYN_MT_REPORT, 0);
 }
 
+static inline void input_mt_slot(struct input_dev *dev, int slot)
+{
+	input_event(dev, EV_ABS, ABS_MT_SLOT, slot);
+}
+
 void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code);
 
+/**
+ * input_set_events_per_packet - tell handlers about the driver event rate
+ * @dev: the input device used by the driver
+ * @n_events: the average number of events between calls to input_sync()
+ *
+ * If the event rate sent from a device is unusually large, use this
+ * function to set the expected event rate. This will allow handlers
+ * to set up an appropriate buffer size for the event stream, in order
+ * to minimize information loss.
+ */
+static inline void input_set_events_per_packet(struct input_dev *dev, int n_events)
+{
+	dev->hint_events_per_packet = n_events;
+}
+
 static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
 {
 	dev->absmin[axis] = min;
@@ -1485,5 +1536,8 @@
 int input_ff_create_memless(struct input_dev *dev, void *data,
 		int (*play_effect)(struct input_dev *, void *, struct ff_effect *));
 
+int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots);
+void input_mt_destroy_slots(struct input_dev *dev);
+
 #endif
 #endif
diff --git a/include/linux/input/adxl34x.h b/include/linux/input/adxl34x.h
new file mode 100644
index 0000000..df00d99
--- /dev/null
+++ b/include/linux/input/adxl34x.h
@@ -0,0 +1,349 @@
+/*
+ * include/linux/input/adxl34x.h
+ *
+ * Digital Accelerometer characteristics are highly application specific
+ * and may vary between boards and models. The platform_data for the
+ * device's "struct device" holds this information.
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __LINUX_INPUT_ADXL34X_H__
+#define __LINUX_INPUT_ADXL34X_H__
+
+struct adxl34x_platform_data {
+
+	/*
+	 * X,Y,Z Axis Offset:
+	 * offer user offset adjustments in twoscompliment
+	 * form with a scale factor of 15.6 mg/LSB (i.e. 0x7F = +2 g)
+	 */
+
+	s8 x_axis_offset;
+	s8 y_axis_offset;
+	s8 z_axis_offset;
+
+	/*
+	 * TAP_X/Y/Z Enable: Setting TAP_X, Y, or Z Enable enables X,
+	 * Y, or Z participation in Tap detection. A '0' excludes the
+	 * selected axis from participation in Tap detection.
+	 * Setting the SUPPRESS bit suppresses Double Tap detection if
+	 * acceleration greater than tap_threshold is present between
+	 * taps.
+	 */
+
+#define ADXL_SUPPRESS	(1 << 3)
+#define ADXL_TAP_X_EN	(1 << 2)
+#define ADXL_TAP_Y_EN	(1 << 1)
+#define ADXL_TAP_Z_EN	(1 << 0)
+
+	u8 tap_axis_control;
+
+	/*
+	 * tap_threshold:
+	 * holds the threshold value for tap detection/interrupts.
+	 * The data format is unsigned. The scale factor is 62.5 mg/LSB
+	 * (i.e. 0xFF = +16 g). A zero value may result in undesirable
+	 * behavior if Tap/Double Tap is enabled.
+	 */
+
+	u8 tap_threshold;
+
+	/*
+	 * tap_duration:
+	 * is an unsigned time value representing the maximum
+	 * time that an event must be above the tap_threshold threshold
+	 * to qualify as a tap event. The scale factor is 625 us/LSB. A zero
+	 * value will prevent Tap/Double Tap functions from working.
+	 */
+
+	u8 tap_duration;
+
+	/*
+	 * tap_latency:
+	 * is an unsigned time value representing the wait time
+	 * from the detection of a tap event to the opening of the time
+	 * window tap_window for a possible second tap event. The scale
+	 * factor is 1.25 ms/LSB. A zero value will disable the Double Tap
+	 * function.
+	 */
+
+	u8 tap_latency;
+
+	/*
+	 * tap_window:
+	 * is an unsigned time value representing the amount
+	 * of time after the expiration of tap_latency during which a second
+	 * tap can begin. The scale factor is 1.25 ms/LSB. A zero value will
+	 * disable the Double Tap function.
+	 */
+
+	u8 tap_window;
+
+	/*
+	 * act_axis_control:
+	 * X/Y/Z Enable: A '1' enables X, Y, or Z participation in activity
+	 * or inactivity detection. A '0' excludes the selected axis from
+	 * participation. If all of the axes are excluded, the function is
+	 * disabled.
+	 * AC/DC: A '0' = DC coupled operation and a '1' = AC coupled
+	 * operation. In DC coupled operation, the current acceleration is
+	 * compared with activity_threshold and inactivity_threshold directly
+	 * to determine whether activity or inactivity is detected. In AC
+	 * coupled operation for activity detection, the acceleration value
+	 * at the start of activity detection is taken as a reference value.
+	 * New samples of acceleration are then compared to this
+	 * reference value and if the magnitude of the difference exceeds
+	 * activity_threshold the device will trigger an activity interrupt. In
+	 * AC coupled operation for inactivity detection, a reference value
+	 * is used again for comparison and is updated whenever the
+	 * device exceeds the inactivity threshold. Once the reference
+	 * value is selected, the device compares the magnitude of the
+	 * difference between the reference value and the current
+	 * acceleration with inactivity_threshold. If the difference is below
+	 * inactivity_threshold for a total of inactivity_time, the device is
+	 * considered inactive and the inactivity interrupt is triggered.
+	 */
+
+#define ADXL_ACT_ACDC		(1 << 7)
+#define ADXL_ACT_X_EN		(1 << 6)
+#define ADXL_ACT_Y_EN		(1 << 5)
+#define ADXL_ACT_Z_EN		(1 << 4)
+#define ADXL_INACT_ACDC		(1 << 3)
+#define ADXL_INACT_X_EN		(1 << 2)
+#define ADXL_INACT_Y_EN		(1 << 1)
+#define ADXL_INACT_Z_EN		(1 << 0)
+
+	u8 act_axis_control;
+
+	/*
+	 * activity_threshold:
+	 * holds the threshold value for activity detection.
+	 * The data format is unsigned. The scale factor is
+	 * 62.5 mg/LSB. A zero value may result in undesirable behavior if
+	 * Activity interrupt is enabled.
+	 */
+
+	u8 activity_threshold;
+
+	/*
+	 * inactivity_threshold:
+	 * holds the threshold value for inactivity
+	 * detection. The data format is unsigned. The scale
+	 * factor is 62.5 mg/LSB. A zero value may result in undesirable
+	 * behavior if Inactivity interrupt is enabled.
+	 */
+
+	u8 inactivity_threshold;
+
+	/*
+	 * inactivity_time:
+	 * is an unsigned time value representing the
+	 * amount of time that acceleration must be below the value in
+	 * inactivity_threshold for inactivity to be declared. The scale factor
+	 * is 1 second/LSB. Unlike the other interrupt functions, which
+	 * operate on unfiltered data, the inactivity function operates on the
+	 * filtered output data. At least one output sample must be
+	 * generated for the inactivity interrupt to be triggered. This will
+	 * result in the function appearing un-responsive if the
+	 * inactivity_time register is set with a value less than the time
+	 * constant of the Output Data Rate. A zero value will result in an
+	 * interrupt when the output data is below inactivity_threshold.
+	 */
+
+	u8 inactivity_time;
+
+	/*
+	 * free_fall_threshold:
+	 * holds the threshold value for Free-Fall detection.
+	 * The data format is unsigned. The root-sum-square(RSS) value
+	 * of all axes is calculated and compared to the value in
+	 * free_fall_threshold to determine if a free fall event may be
+	 * occurring.  The scale factor is 62.5 mg/LSB. A zero value may
+	 * result in undesirable behavior if Free-Fall interrupt is
+	 * enabled. Values between 300 and 600 mg (0x05 to 0x09) are
+	 * recommended.
+	 */
+
+	u8 free_fall_threshold;
+
+	/*
+	 * free_fall_time:
+	 * is an unsigned time value representing the minimum
+	 * time that the RSS value of all axes must be less than
+	 * free_fall_threshold to generate a Free-Fall interrupt. The
+	 * scale factor is 5 ms/LSB. A zero value may result in
+	 * undesirable behavior if Free-Fall interrupt is enabled.
+	 * Values between 100 to 350 ms (0x14 to 0x46) are recommended.
+	 */
+
+	u8 free_fall_time;
+
+	/*
+	 * data_rate:
+	 * Selects device bandwidth and output data rate.
+	 * RATE = 3200 Hz / (2^(15 - x)). Default value is 0x0A, or 100 Hz
+	 * Output Data Rate. An Output Data Rate should be selected that
+	 * is appropriate for the communication protocol and frequency
+	 * selected. Selecting too high of an Output Data Rate with a low
+	 * communication speed will result in samples being discarded.
+	 */
+
+	u8 data_rate;
+
+	/*
+	 * data_range:
+	 * FULL_RES: When this bit is set with the device is
+	 * in Full-Resolution Mode, where the output resolution increases
+	 * with RANGE to maintain a 4 mg/LSB scale factor. When this
+	 * bit is cleared the device is in 10-bit Mode and RANGE determine the
+	 * maximum g-Range and scale factor.
+	 */
+
+#define ADXL_FULL_RES		(1 << 3)
+#define ADXL_RANGE_PM_2g	0
+#define ADXL_RANGE_PM_4g	1
+#define ADXL_RANGE_PM_8g	2
+#define ADXL_RANGE_PM_16g	3
+
+	u8 data_range;
+
+	/*
+	 * low_power_mode:
+	 * A '0' = Normal operation and a '1' = Reduced
+	 * power operation with somewhat higher noise.
+	 */
+
+	u8 low_power_mode;
+
+	/*
+	 * power_mode:
+	 * LINK: A '1' with both the activity and inactivity functions
+	 * enabled will delay the start of the activity function until
+	 * inactivity is detected. Once activity is detected, inactivity
+	 * detection will begin and prevent the detection of activity. This
+	 * bit serially links the activity and inactivity functions. When '0'
+	 * the inactivity and activity functions are concurrent. Additional
+	 * information can be found in the Application section under Link
+	 * Mode.
+	 * AUTO_SLEEP: A '1' sets the ADXL34x to switch to Sleep Mode
+	 * when inactivity (acceleration has been below inactivity_threshold
+	 * for at least inactivity_time) is detected and the LINK bit is set.
+	 * A '0' disables automatic switching to Sleep Mode. See SLEEP
+	 * for further description.
+	 */
+
+#define ADXL_LINK	(1 << 5)
+#define ADXL_AUTO_SLEEP	(1 << 4)
+
+	u8 power_mode;
+
+	/*
+	 * fifo_mode:
+	 * BYPASS The FIFO is bypassed
+	 * FIFO   FIFO collects up to 32 values then stops collecting data
+	 * STREAM FIFO holds the last 32 data values. Once full, the FIFO's
+	 *        oldest data is lost as it is replaced with newer data
+	 *
+	 * DEFAULT should be ADXL_FIFO_STREAM
+	 */
+
+#define ADXL_FIFO_BYPASS	0
+#define ADXL_FIFO_FIFO		1
+#define ADXL_FIFO_STREAM	2
+
+	u8 fifo_mode;
+
+	/*
+	 * watermark:
+	 * The Watermark feature can be used to reduce the interrupt load
+	 * of the system. The FIFO fills up to the value stored in watermark
+	 * [1..32] and then generates an interrupt.
+	 * A '0' disables the watermark feature.
+	 */
+
+	u8 watermark;
+
+	u32 ev_type;	/* EV_ABS or EV_REL */
+
+	u32 ev_code_x;	/* ABS_X,Y,Z or REL_X,Y,Z */
+	u32 ev_code_y;	/* ABS_X,Y,Z or REL_X,Y,Z */
+	u32 ev_code_z;	/* ABS_X,Y,Z or REL_X,Y,Z */
+
+	/*
+	 * A valid BTN or KEY Code; use tap_axis_control to disable
+	 * event reporting
+	 */
+
+	u32 ev_code_tap[3];	/* EV_KEY {X-Axis, Y-Axis, Z-Axis} */
+
+	/*
+	 * A valid BTN or KEY Code for Free-Fall or Activity enables
+	 * input event reporting. A '0' disables the Free-Fall or
+	 * Activity reporting.
+	 */
+
+	u32 ev_code_ff;	/* EV_KEY */
+	u32 ev_code_act_inactivity;	/* EV_KEY */
+
+	/*
+	 * Use ADXL34x INT2 instead of INT1
+	 */
+	u8 use_int2;
+
+	/*
+	 * ADXL346 only ORIENTATION SENSING feature
+	 * The orientation function of the ADXL346 reports both 2-D and
+	 * 3-D orientation concurrently.
+	 */
+
+#define ADXL_EN_ORIENTATION_2D		1
+#define ADXL_EN_ORIENTATION_3D		2
+#define ADXL_EN_ORIENTATION_2D_3D	3
+
+	u8 orientation_enable;
+
+	/*
+	 * The width of the deadzone region between two or more
+	 * orientation positions is determined by setting the Deadzone
+	 * value. The deadzone region size can be specified with a
+	 * resolution of 3.6deg. The deadzone angle represents the total
+	 * angle where the orientation is considered invalid.
+	 */
+
+#define ADXL_DEADZONE_ANGLE_0p0		0	/* !!!0.0 [deg] */
+#define ADXL_DEADZONE_ANGLE_3p6		1	/* 3.6 [deg] */
+#define ADXL_DEADZONE_ANGLE_7p2		2	/* 7.2 [deg] */
+#define ADXL_DEADZONE_ANGLE_10p8	3	/* 10.8 [deg] */
+#define ADXL_DEADZONE_ANGLE_14p4	4	/* 14.4 [deg] */
+#define ADXL_DEADZONE_ANGLE_18p0	5	/* 18.0 [deg] */
+#define ADXL_DEADZONE_ANGLE_21p6	6	/* 21.6 [deg] */
+#define ADXL_DEADZONE_ANGLE_25p2	7	/* 25.2 [deg] */
+
+	u8 deadzone_angle;
+
+	/*
+	 * To eliminate most human motion such as walking or shaking,
+	 * a Divisor value should be selected to effectively limit the
+	 * orientation bandwidth. Set the depth of the filter used to
+	 * low-pass filter the measured acceleration for stable
+	 * orientation sensing
+	 */
+
+#define ADXL_LP_FILTER_DIVISOR_2	0
+#define ADXL_LP_FILTER_DIVISOR_4	1
+#define ADXL_LP_FILTER_DIVISOR_8	2
+#define ADXL_LP_FILTER_DIVISOR_16	3
+#define ADXL_LP_FILTER_DIVISOR_32	4
+#define ADXL_LP_FILTER_DIVISOR_64	5
+#define ADXL_LP_FILTER_DIVISOR_128	6
+#define ADXL_LP_FILTER_DIVISOR_256	7
+
+	u8 divisor_length;
+
+	u32 ev_codes_orient_2d[4];	/* EV_KEY {+X, -X, +Y, -Y} */
+	u32 ev_codes_orient_3d[6];	/* EV_KEY {+Z, +Y, +X, -X, -Y, -Z} */
+};
+#endif
diff --git a/include/linux/input/cy8ctmg110_pdata.h b/include/linux/input/cy8ctmg110_pdata.h
new file mode 100644
index 0000000..09522cb
--- /dev/null
+++ b/include/linux/input/cy8ctmg110_pdata.h
@@ -0,0 +1,10 @@
+#ifndef _LINUX_CY8CTMG110_PDATA_H
+#define _LINUX_CY8CTMG110_PDATA_H
+
+struct cy8ctmg110_pdata
+{
+	int reset_pin;		/* Reset pin is wired to this GPIO (optional) */
+	int irq_pin;		/* IRQ pin is wired to this GPIO */
+};
+
+#endif
diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h
index c964cd7..80352ad 100644
--- a/include/linux/input/matrix_keypad.h
+++ b/include/linux/input/matrix_keypad.h
@@ -41,6 +41,9 @@
  * @col_scan_delay_us: delay, measured in microseconds, that is
  *	needed before we can keypad after activating column gpio
  * @debounce_ms: debounce interval in milliseconds
+ * @clustered_irq: may be specified if interrupts of all row/column GPIOs
+ *	are bundled to one single irq
+ * @clustered_irq_flags: flags that are needed for the clustered irq
  * @active_low: gpio polarity
  * @wakeup: controls whether the device should be set up as wakeup
  *	source
@@ -63,6 +66,9 @@
 	/* key debounce interval in milli-second */
 	unsigned int	debounce_ms;
 
+	unsigned int	clustered_irq;
+	unsigned int	clustered_irq_flags;
+
 	bool		active_low;
 	bool		wakeup;
 	bool		no_autorepeat;
diff --git a/include/linux/intel_pmic_gpio.h b/include/linux/intel_pmic_gpio.h
new file mode 100644
index 0000000..920109a
--- /dev/null
+++ b/include/linux/intel_pmic_gpio.h
@@ -0,0 +1,15 @@
+#ifndef LINUX_INTEL_PMIC_H
+#define LINUX_INTEL_PMIC_H
+
+struct intel_pmic_gpio_platform_data {
+	/* the first IRQ of the chip */
+	unsigned	irq_base;
+	/* number assigned to the first GPIO */
+	unsigned	gpio_base;
+	/* sram address for gpiointr register, the langwell chip will map
+	 * the PMIC spi GPIO expander's GPIOINTR register in sram.
+	 */
+	unsigned	gpiointr;
+};
+
+#endif
diff --git a/include/linux/ip_vs.h b/include/linux/ip_vs.h
index dfc1703..9708de2 100644
--- a/include/linux/ip_vs.h
+++ b/include/linux/ip_vs.h
@@ -19,6 +19,7 @@
  */
 #define IP_VS_SVC_F_PERSISTENT	0x0001		/* persistent port */
 #define IP_VS_SVC_F_HASHED	0x0002		/* hashed entry */
+#define IP_VS_SVC_F_ONEPACKET	0x0004		/* one-packet scheduling */
 
 /*
  *      Destination Server Flags
@@ -85,6 +86,7 @@
 #define IP_VS_CONN_F_SEQ_MASK	0x0600		/* in/out sequence mask */
 #define IP_VS_CONN_F_NO_CPORT	0x0800		/* no client port set yet */
 #define IP_VS_CONN_F_TEMPLATE	0x1000		/* template, not connection */
+#define IP_VS_CONN_F_ONE_PACKET	0x2000		/* forward only one packet */
 
 #define IP_VS_SCHEDNAME_MAXLEN	16
 #define IP_VS_IFNAME_MAXLEN	16
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 99e1ab7..ab9e9e8 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -58,7 +58,7 @@
 	/* 
 	 * TLV encoded option data follows.
 	 */
-} __attribute__ ((packed));	/* required for some archs */
+} __packed;	/* required for some archs */
 
 #define ipv6_destopt_hdr ipv6_opt_hdr
 #define ipv6_hopopt_hdr  ipv6_opt_hdr
@@ -99,7 +99,7 @@
 	__u8			type;
 	__u8			length;
 	struct in6_addr		addr;
-} __attribute__ ((__packed__));
+} __packed;
 
 /*
  *	IPv6 fixed header
@@ -246,7 +246,7 @@
 	__u16			srcrt;
 	__u16			dst1;
 	__u16			lastopt;
-	__u32			nhoff;
+	__u16			nhoff;
 	__u16			flags;
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
 	__u16			dsthao;
diff --git a/include/linux/iscsi_boot_sysfs.h b/include/linux/iscsi_boot_sysfs.h
new file mode 100644
index 0000000..f1e6c18
--- /dev/null
+++ b/include/linux/iscsi_boot_sysfs.h
@@ -0,0 +1,123 @@
+/*
+ * Export the iSCSI boot info to userland via sysfs.
+ *
+ * Copyright (C) 2010 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2010 Mike Christie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _ISCSI_BOOT_SYSFS_
+#define _ISCSI_BOOT_SYSFS_
+
+/*
+ * The text attributes names for each of the kobjects.
+*/
+enum iscsi_boot_eth_properties_enum {
+	ISCSI_BOOT_ETH_INDEX,
+	ISCSI_BOOT_ETH_FLAGS,
+	ISCSI_BOOT_ETH_IP_ADDR,
+	ISCSI_BOOT_ETH_SUBNET_MASK,
+	ISCSI_BOOT_ETH_ORIGIN,
+	ISCSI_BOOT_ETH_GATEWAY,
+	ISCSI_BOOT_ETH_PRIMARY_DNS,
+	ISCSI_BOOT_ETH_SECONDARY_DNS,
+	ISCSI_BOOT_ETH_DHCP,
+	ISCSI_BOOT_ETH_VLAN,
+	ISCSI_BOOT_ETH_MAC,
+	/* eth_pci_bdf - this is replaced by link to the device itself. */
+	ISCSI_BOOT_ETH_HOSTNAME,
+	ISCSI_BOOT_ETH_END_MARKER,
+};
+
+enum iscsi_boot_tgt_properties_enum {
+	ISCSI_BOOT_TGT_INDEX,
+	ISCSI_BOOT_TGT_FLAGS,
+	ISCSI_BOOT_TGT_IP_ADDR,
+	ISCSI_BOOT_TGT_PORT,
+	ISCSI_BOOT_TGT_LUN,
+	ISCSI_BOOT_TGT_CHAP_TYPE,
+	ISCSI_BOOT_TGT_NIC_ASSOC,
+	ISCSI_BOOT_TGT_NAME,
+	ISCSI_BOOT_TGT_CHAP_NAME,
+	ISCSI_BOOT_TGT_CHAP_SECRET,
+	ISCSI_BOOT_TGT_REV_CHAP_NAME,
+	ISCSI_BOOT_TGT_REV_CHAP_SECRET,
+	ISCSI_BOOT_TGT_END_MARKER,
+};
+
+enum iscsi_boot_initiator_properties_enum {
+	ISCSI_BOOT_INI_INDEX,
+	ISCSI_BOOT_INI_FLAGS,
+	ISCSI_BOOT_INI_ISNS_SERVER,
+	ISCSI_BOOT_INI_SLP_SERVER,
+	ISCSI_BOOT_INI_PRI_RADIUS_SERVER,
+	ISCSI_BOOT_INI_SEC_RADIUS_SERVER,
+	ISCSI_BOOT_INI_INITIATOR_NAME,
+	ISCSI_BOOT_INI_END_MARKER,
+};
+
+struct attribute_group;
+
+struct iscsi_boot_kobj {
+	struct kobject kobj;
+	struct attribute_group *attr_group;
+	struct list_head list;
+
+	/*
+	 * Pointer to store driver specific info. If set this will
+	 * be freed for the LLD when the kobj release function is called.
+	 */
+	void *data;
+	/*
+	 * Driver specific show function.
+	 *
+	 * The enum of the type. This can be any value of the above
+	 * properties.
+	 */
+	ssize_t (*show) (void *data, int type, char *buf);
+
+	/*
+	 * Drivers specific visibility function.
+	 * The function should return if they the attr should be readable
+	 * writable or should not be shown.
+	 *
+	 * The enum of the type. This can be any value of the above
+	 * properties.
+	 */
+	mode_t (*is_visible) (void *data, int type);
+};
+
+struct iscsi_boot_kset {
+	struct list_head kobj_list;
+	struct kset *kset;
+};
+
+struct iscsi_boot_kobj *
+iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index,
+			    void *data,
+			    ssize_t (*show) (void *data, int type, char *buf),
+			    mode_t (*is_visible) (void *data, int type));
+
+struct iscsi_boot_kobj *
+iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index,
+			   void *data,
+			   ssize_t (*show) (void *data, int type, char *buf),
+			   mode_t (*is_visible) (void *data, int type));
+struct iscsi_boot_kobj *
+iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index,
+			 void *data,
+			 ssize_t (*show) (void *data, int type, char *buf),
+			 mode_t (*is_visible) (void *data, int type));
+
+struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name);
+struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno);
+void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset);
+
+#endif
diff --git a/include/linux/iscsi_ibft.h b/include/linux/iscsi_ibft.h
index d2e4042..8ba7e5b 100644
--- a/include/linux/iscsi_ibft.h
+++ b/include/linux/iscsi_ibft.h
@@ -21,21 +21,13 @@
 #ifndef ISCSI_IBFT_H
 #define ISCSI_IBFT_H
 
-struct ibft_table_header {
-	char signature[4];
-	u32 length;
-	u8 revision;
-	u8 checksum;
-	char oem_id[6];
-	char oem_table_id[8];
-	char reserved[24];
-} __attribute__((__packed__));
+#include <acpi/acpi.h>
 
 /*
  * Logical location of iSCSI Boot Format Table.
  * If the value is NULL there is no iBFT on the machine.
  */
-extern struct ibft_table_header *ibft_addr;
+extern struct acpi_table_ibft *ibft_addr;
 
 /*
  * Routine used to find and reserve the iSCSI Boot Format Table. The
diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h
index b9b5a68..b8c23f8 100644
--- a/include/linux/isdnif.h
+++ b/include/linux/isdnif.h
@@ -317,7 +317,7 @@
 	__u8 r_scantime;
 	__u8 r_id[FAXIDLEN];
 	__u8 r_code;
-} __attribute__((packed)) T30_s;
+} __packed T30_s;
 
 #define ISDN_TTY_FAX_CONN_IN	0
 #define ISDN_TTY_FAX_CONN_OUT	1
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index bd8501a..5de838b 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -171,6 +171,11 @@
 }
 #endif
 
+struct va_format {
+	const char *fmt;
+	va_list *va;
+};
+
 extern struct atomic_notifier_head panic_notifier_list;
 extern long (*panic_blink)(long time);
 NORET_TYPE void panic(const char * fmt, ...)
diff --git a/include/linux/ks8842.h b/include/linux/ks8842.h
index da0341b..14ba445 100644
--- a/include/linux/ks8842.h
+++ b/include/linux/ks8842.h
@@ -25,10 +25,14 @@
  * struct ks8842_platform_data - Platform data of the KS8842 network driver
  * @macaddr:	The MAC address of the device, set to all 0:s to use the on in
  *		the chip.
+ * @rx_dma_channel:	The DMA channel to use for RX, -1 for none.
+ * @tx_dma_channel:	The DMA channel to use for TX, -1 for none.
  *
  */
 struct ks8842_platform_data {
 	u8 macaddr[ETH_ALEN];
+	int rx_dma_channel;
+	int tx_dma_channel;
 };
 
 #endif
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 23ea022..636fc38 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -524,6 +524,12 @@
 #define KVM_CAP_PPC_OSI 52
 #define KVM_CAP_PPC_UNSET_IRQ 53
 #define KVM_CAP_ENABLE_CAP 54
+#ifdef __KVM_HAVE_XSAVE
+#define KVM_CAP_XSAVE 55
+#endif
+#ifdef __KVM_HAVE_XCRS
+#define KVM_CAP_XCRS 56
+#endif
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -613,6 +619,7 @@
  */
 #define KVM_CREATE_VCPU           _IO(KVMIO,   0x41)
 #define KVM_GET_DIRTY_LOG         _IOW(KVMIO,  0x42, struct kvm_dirty_log)
+/* KVM_SET_MEMORY_ALIAS is obsolete: */
 #define KVM_SET_MEMORY_ALIAS      _IOW(KVMIO,  0x43, struct kvm_memory_alias)
 #define KVM_SET_NR_MMU_PAGES      _IO(KVMIO,   0x44)
 #define KVM_GET_NR_MMU_PAGES      _IO(KVMIO,   0x45)
@@ -714,6 +721,12 @@
 #define KVM_GET_DEBUGREGS         _IOR(KVMIO,  0xa1, struct kvm_debugregs)
 #define KVM_SET_DEBUGREGS         _IOW(KVMIO,  0xa2, struct kvm_debugregs)
 #define KVM_ENABLE_CAP            _IOW(KVMIO,  0xa3, struct kvm_enable_cap)
+/* Available with KVM_CAP_XSAVE */
+#define KVM_GET_XSAVE		  _IOR(KVMIO,  0xa4, struct kvm_xsave)
+#define KVM_SET_XSAVE		  _IOW(KVMIO,  0xa5, struct kvm_xsave)
+/* Available with KVM_CAP_XCRS */
+#define KVM_GET_XCRS		  _IOR(KVMIO,  0xa6, struct kvm_xcrs)
+#define KVM_SET_XCRS		  _IOW(KVMIO,  0xa7, struct kvm_xcrs)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
 
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 7cb116a..c13cc48 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -81,13 +81,14 @@
 	int vcpu_id;
 	struct mutex mutex;
 	int   cpu;
+	atomic_t guest_mode;
 	struct kvm_run *run;
 	unsigned long requests;
 	unsigned long guest_debug;
 	int srcu_idx;
 
 	int fpu_active;
-	int guest_fpu_loaded;
+	int guest_fpu_loaded, guest_xcr0_loaded;
 	wait_queue_head_t wq;
 	int sigset_active;
 	sigset_t sigset;
@@ -123,6 +124,7 @@
 	} *lpage_info[KVM_NR_PAGE_SIZES - 1];
 	unsigned long userspace_addr;
 	int user_alloc;
+	int id;
 };
 
 static inline unsigned long kvm_dirty_bitmap_bytes(struct kvm_memory_slot *memslot)
@@ -266,6 +268,8 @@
 
 int is_error_page(struct page *page);
 int is_error_pfn(pfn_t pfn);
+int is_hwpoison_pfn(pfn_t pfn);
+int is_fault_pfn(pfn_t pfn);
 int kvm_is_error_hva(unsigned long addr);
 int kvm_set_memory_region(struct kvm *kvm,
 			  struct kvm_userspace_memory_region *mem,
@@ -284,8 +288,6 @@
 				int user_alloc);
 void kvm_disable_largepages(void);
 void kvm_arch_flush_shadow(struct kvm *kvm);
-gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn);
-gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn);
 
 struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
 unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn);
@@ -445,7 +447,8 @@
 				    struct kvm_irq_mask_notifier *kimn);
 void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
 				      struct kvm_irq_mask_notifier *kimn);
-void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask);
+void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin,
+			     bool mask);
 
 #ifdef __KVM_HAVE_IOAPIC
 void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
@@ -562,10 +565,6 @@
 }
 #endif
 
-#ifndef KVM_ARCH_HAS_UNALIAS_INSTANTIATION
-#define unalias_gfn_instantiation unalias_gfn
-#endif
-
 #ifdef CONFIG_HAVE_KVM_IRQCHIP
 
 #define KVM_MAX_IRQ_ROUTES 1024
@@ -628,5 +627,25 @@
 
 #endif
 
+static inline void kvm_make_request(int req, struct kvm_vcpu *vcpu)
+{
+	set_bit(req, &vcpu->requests);
+}
+
+static inline bool kvm_make_check_request(int req, struct kvm_vcpu *vcpu)
+{
+	return test_and_set_bit(req, &vcpu->requests);
+}
+
+static inline bool kvm_check_request(int req, struct kvm_vcpu *vcpu)
+{
+	if (test_bit(req, &vcpu->requests)) {
+		clear_bit(req, &vcpu->requests);
+		return true;
+	} else {
+		return false;
+	}
+}
+
 #endif
 
diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
index fb46efb..7ac0d4e 100644
--- a/include/linux/kvm_types.h
+++ b/include/linux/kvm_types.h
@@ -32,11 +32,11 @@
 
 typedef unsigned long  gva_t;
 typedef u64            gpa_t;
-typedef unsigned long  gfn_t;
+typedef u64            gfn_t;
 
 typedef unsigned long  hva_t;
 typedef u64            hpa_t;
-typedef unsigned long  hfn_t;
+typedef u64            hfn_t;
 
 typedef hfn_t pfn_t;
 
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
index 6907251..112a550 100644
--- a/include/linux/lsm_audit.h
+++ b/include/linux/lsm_audit.h
@@ -90,10 +90,42 @@
 			u32 requested;
 			u32 audited;
 			u32 denied;
+			/*
+			 * auditdeny is a bit tricky and unintuitive.  See the
+			 * comments in avc.c for it's meaning and usage.
+			 */
+			u32 auditdeny;
 			struct av_decision *avd;
 			int result;
 		} selinux_audit_data;
 #endif
+#ifdef CONFIG_SECURITY_APPARMOR
+		struct {
+			int error;
+			int op;
+			int type;
+			void *profile;
+			const char *name;
+			const char *info;
+			union {
+				void *target;
+				struct {
+					long pos;
+					void *target;
+				} iface;
+				struct {
+					int rlim;
+					unsigned long max;
+				} rlim;
+				struct {
+					const char *target;
+					u32 request;
+					u32 denied;
+					uid_t ouid;
+				} fs;
+			};
+		} apparmor_audit_data;
+#endif
 	};
 	/* these callback will be implemented by a specific LSM */
 	void (*lsm_pre_audit)(struct audit_buffer *, void *);
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index 78c3bed..b5e7f22 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -251,7 +251,7 @@
 struct mISDNhead {
 	unsigned int	prim;
 	unsigned int	id;
-}  __attribute__((packed));
+}  __packed;
 
 #define MISDN_HEADER_LEN	sizeof(struct mISDNhead)
 #define MAX_DATA_SIZE		2048
diff --git a/include/linux/marvell_phy.h b/include/linux/marvell_phy.h
index 2ed4fb8..d0f0801 100644
--- a/include/linux/marvell_phy.h
+++ b/include/linux/marvell_phy.h
@@ -12,6 +12,7 @@
 #define MARVELL_PHY_ID_88E1121R		0x01410cb0
 #define MARVELL_PHY_ID_88E1145		0x01410cd0
 #define MARVELL_PHY_ID_88E1240		0x01410e30
+#define MARVELL_PHY_ID_88EC048		0x01410e90
 
 /* struct phy_device dev_flags definitions */
 #define MARVELL_PHY_M1145_FLAGS_RESISTANCE	0x00000001
diff --git a/include/linux/mm.h b/include/linux/mm.h
index a2b4804..7a9ab7d 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1465,6 +1465,14 @@
 extern void shake_page(struct page *p, int access);
 extern atomic_long_t mce_bad_pages;
 extern int soft_offline_page(struct page *page, int flags);
+#ifdef CONFIG_MEMORY_FAILURE
+int is_hwpoison_address(unsigned long addr);
+#else
+static inline int is_hwpoison_address(unsigned long addr)
+{
+	return 0;
+}
+#endif
 
 extern void dump_page(struct page *page);
 
diff --git a/include/linux/nbd.h b/include/linux/nbd.h
index 155719d..bb58854 100644
--- a/include/linux/nbd.h
+++ b/include/linux/nbd.h
@@ -88,7 +88,7 @@
 	char handle[8];
 	__be64 from;
 	__be32 len;
-} __attribute__ ((packed));
+} __packed;
 
 /*
  * This is the reply packet that nbd-server sends back to the client after
diff --git a/include/linux/ncp.h b/include/linux/ncp.h
index 99f0ade..3ace837 100644
--- a/include/linux/ncp.h
+++ b/include/linux/ncp.h
@@ -27,7 +27,7 @@
 	__u8 conn_high;
 	__u8 function;
 	__u8 data[0];
-} __attribute__((packed));
+} __packed;
 
 #define NCP_REPLY                (0x3333)
 #define NCP_WATCHDOG		 (0x3E3E)
@@ -42,7 +42,7 @@
 	__u8 completion_code;
 	__u8 connection_state;
 	__u8 data[0];
-} __attribute__((packed));
+} __packed;
 
 #define NCP_VOLNAME_LEN (16)
 #define NCP_NUMBER_OF_VOLUMES (256)
@@ -158,7 +158,7 @@
 #ifdef __KERNEL__
 	struct nw_nfs_info nfs;
 #endif
-} __attribute__((packed));
+} __packed;
 
 /* modify mask - use with MODIFY_DOS_INFO structure */
 #define DM_ATTRIBUTES		  (cpu_to_le32(0x02))
@@ -190,12 +190,12 @@
 	__u16 inheritanceGrantMask;
 	__u16 inheritanceRevokeMask;
 	__u32 maximumSpace;
-} __attribute__((packed));
+} __packed;
 
 struct nw_search_sequence {
 	__u8 volNumber;
 	__u32 dirBase;
 	__u32 sequence;
-} __attribute__((packed));
+} __packed;
 
 #endif				/* _LINUX_NCP_H */
diff --git a/include/linux/ncp_fs_sb.h b/include/linux/ncp_fs_sb.h
index 5ec9ca6..8da05bc 100644
--- a/include/linux/ncp_fs_sb.h
+++ b/include/linux/ncp_fs_sb.h
@@ -104,13 +104,13 @@
 
 		unsigned int state;		/* STREAM only: receiver state */
 		struct {
-			__u32 magic __attribute__((packed));
-			__u32 len __attribute__((packed));
-			__u16 type __attribute__((packed));
-			__u16 p1 __attribute__((packed));
-			__u16 p2 __attribute__((packed));
-			__u16 p3 __attribute__((packed));
-			__u16 type2 __attribute__((packed));
+			__u32 magic __packed;
+			__u32 len __packed;
+			__u16 type __packed;
+			__u16 p1 __packed;
+			__u16 p2 __packed;
+			__u16 p3 __packed;
+			__u16 type2 __packed;
 		} buf;				/* STREAM only: temporary buffer */
 		unsigned char* ptr;		/* STREAM only: pointer to data */
 		size_t len;			/* STREAM only: length of data to receive */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 50d09aa..46c36ff 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -54,6 +54,7 @@
 
 struct vlan_group;
 struct netpoll_info;
+struct phy_device;
 /* 802.11 specific */
 struct wireless_dev;
 					/* source back-compat hooks */
@@ -65,6 +66,11 @@
 #define HAVE_FREE_NETDEV		/* free_netdev() */
 #define HAVE_NETDEV_PRIV		/* netdev_priv() */
 
+/* hardware address assignment types */
+#define NET_ADDR_PERM		0	/* address is permanent (default) */
+#define NET_ADDR_RANDOM		1	/* address is generated randomly */
+#define NET_ADDR_STOLEN		2	/* address is stolen from other device */
+
 /* Backlog congestion levels */
 #define NET_RX_SUCCESS		0	/* keep 'em coming, baby */
 #define NET_RX_DROP		1	/* packet dropped */
@@ -159,45 +165,39 @@
 #define MAX_HEADER (LL_MAX_HEADER + 48)
 #endif
 
-#endif  /*  __KERNEL__  */
-
 /*
- *	Network device statistics. Akin to the 2.0 ether stats but
- *	with byte counters.
+ *	Old network device statistics. Fields are native words
+ *	(unsigned long) so they can be read and written atomically.
  */
 
 struct net_device_stats {
-	unsigned long	rx_packets;		/* total packets received	*/
-	unsigned long	tx_packets;		/* total packets transmitted	*/
-	unsigned long	rx_bytes;		/* total bytes received 	*/
-	unsigned long	tx_bytes;		/* total bytes transmitted	*/
-	unsigned long	rx_errors;		/* bad packets received		*/
-	unsigned long	tx_errors;		/* packet transmit problems	*/
-	unsigned long	rx_dropped;		/* no space in linux buffers	*/
-	unsigned long	tx_dropped;		/* no space available in linux	*/
-	unsigned long	multicast;		/* multicast packets received	*/
+	unsigned long	rx_packets;
+	unsigned long	tx_packets;
+	unsigned long	rx_bytes;
+	unsigned long	tx_bytes;
+	unsigned long	rx_errors;
+	unsigned long	tx_errors;
+	unsigned long	rx_dropped;
+	unsigned long	tx_dropped;
+	unsigned long	multicast;
 	unsigned long	collisions;
-
-	/* detailed rx_errors: */
 	unsigned long	rx_length_errors;
-	unsigned long	rx_over_errors;		/* receiver ring buff overflow	*/
-	unsigned long	rx_crc_errors;		/* recved pkt with crc error	*/
-	unsigned long	rx_frame_errors;	/* recv'd frame alignment error */
-	unsigned long	rx_fifo_errors;		/* recv'r fifo overrun		*/
-	unsigned long	rx_missed_errors;	/* receiver missed packet	*/
-
-	/* detailed tx_errors */
+	unsigned long	rx_over_errors;
+	unsigned long	rx_crc_errors;
+	unsigned long	rx_frame_errors;
+	unsigned long	rx_fifo_errors;
+	unsigned long	rx_missed_errors;
 	unsigned long	tx_aborted_errors;
 	unsigned long	tx_carrier_errors;
 	unsigned long	tx_fifo_errors;
 	unsigned long	tx_heartbeat_errors;
 	unsigned long	tx_window_errors;
-	
-	/* for cslip etc */
 	unsigned long	rx_compressed;
 	unsigned long	tx_compressed;
 };
 
+#endif  /*  __KERNEL__  */
+
 
 /* Media selection options. */
 enum {
@@ -381,6 +381,8 @@
 };
 typedef enum gro_result gro_result_t;
 
+typedef struct sk_buff *rx_handler_func_t(struct sk_buff *skb);
+
 extern void __napi_schedule(struct napi_struct *n);
 
 static inline int napi_disable_pending(struct napi_struct *n)
@@ -504,9 +506,9 @@
 	 * please use this field instead of dev->trans_start
 	 */
 	unsigned long		trans_start;
-	unsigned long		tx_bytes;
-	unsigned long		tx_packets;
-	unsigned long		tx_dropped;
+	u64			tx_bytes;
+	u64			tx_packets;
+	u64			tx_dropped;
 } ____cacheline_aligned_in_smp;
 
 #ifdef CONFIG_RPS
@@ -660,10 +662,19 @@
  *	Callback uses when the transmitter has not made any progress
  *	for dev->watchdog ticks.
  *
+ * struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev,
+ *                      struct rtnl_link_stats64 *storage);
  * struct net_device_stats* (*ndo_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.
+ *	statistics. Drivers must do one of the following:
+ *	1. Define @ndo_get_stats64 to fill in a zero-initialised
+ *	   rtnl_link_stats64 structure passed by the caller.
+ *	2. Define @ndo_get_stats to update a net_device_stats structure
+ *	   (which should normally be dev->stats) and return a pointer to
+ *	   it. The structure may be changed asynchronously only if each
+ *	   field is written atomically.
+ *	3. Update dev->stats asynchronously and atomically, and define
+ *	   neither operation.
  *
  * void (*ndo_vlan_rx_register)(struct net_device *dev, struct vlan_group *grp);
  *	If device support VLAN receive accleration
@@ -718,6 +729,8 @@
 						   struct neigh_parms *);
 	void			(*ndo_tx_timeout) (struct net_device *dev);
 
+	struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev,
+						     struct rtnl_link_stats64 *storage);
 	struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
 
 	void			(*ndo_vlan_rx_register)(struct net_device *dev,
@@ -728,6 +741,8 @@
 						        unsigned short vid);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	void                    (*ndo_poll_controller)(struct net_device *dev);
+	int			(*ndo_netpoll_setup)(struct net_device *dev,
+						     struct netpoll_info *info);
 	void			(*ndo_netpoll_cleanup)(struct net_device *dev);
 #endif
 	int			(*ndo_set_vf_mac)(struct net_device *dev,
@@ -779,7 +794,7 @@
 	 */
 	char			name[IFNAMSIZ];
 
-	struct pm_qos_request_list *pm_qos_req;
+	struct pm_qos_request_list pm_qos_req;
 
 	/* device name hash chain */
 	struct hlist_node	name_hlist;
@@ -847,7 +862,8 @@
 #define NETIF_F_FSO		(SKB_GSO_FCOE << NETIF_F_GSO_SHIFT)
 
 	/* List of features with software fallbacks. */
-#define NETIF_F_GSO_SOFTWARE	(NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6)
+#define NETIF_F_GSO_SOFTWARE	(NETIF_F_TSO | NETIF_F_TSO_ECN | \
+				 NETIF_F_TSO6 | NETIF_F_UFO)
 
 
 #define NETIF_F_GEN_CSUM	(NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
@@ -908,6 +924,7 @@
 
 	/* Interface address info. */
 	unsigned char		perm_addr[MAX_ADDR_LEN]; /* permanent hw address */
+	unsigned char		addr_assign_type; /* hw address assignment type */
 	unsigned char		addr_len;	/* hardware address length	*/
 	unsigned short          dev_id;		/* for shared network cards */
 
@@ -957,6 +974,8 @@
 #endif
 
 	struct netdev_queue	rx_queue;
+	rx_handler_func_t	*rx_handler;
+	void			*rx_handler_data;
 
 	struct netdev_queue	*_tx ____cacheline_aligned_in_smp;
 
@@ -1024,10 +1043,6 @@
 	/* mid-layer private */
 	void			*ml_priv;
 
-	/* bridge stuff */
-	struct net_bridge_port	*br_port;
-	/* macvlan */
-	struct macvlan_port	*macvlan_port;
 	/* GARP */
 	struct garp_port	*garp_port;
 
@@ -1057,6 +1072,9 @@
 #endif
 	/* n-tuple filter list attached to this device */
 	struct ethtool_rx_ntuple_list ethtool_ntuple_list;
+
+	/* phy device may attach itself for hardware timestamping */
+	struct phy_device *phydev;
 };
 #define to_net_dev(d) container_of(d, struct net_device, dev)
 
@@ -1087,11 +1105,7 @@
 static inline
 struct net *dev_net(const struct net_device *dev)
 {
-#ifdef CONFIG_NET_NS
-	return dev->nd_net;
-#else
-	return &init_net;
-#endif
+	return read_pnet(&dev->nd_net);
 }
 
 static inline
@@ -1272,8 +1286,8 @@
 extern void		dev_remove_pack(struct packet_type *pt);
 extern void		__dev_remove_pack(struct packet_type *pt);
 
-extern struct net_device	*dev_get_by_flags(struct net *net, unsigned short flags,
-						  unsigned short mask);
+extern struct net_device	*dev_get_by_flags_rcu(struct net *net, unsigned short flags,
+						      unsigned short mask);
 extern struct net_device	*dev_get_by_name(struct net *net, const char *name);
 extern struct net_device	*dev_get_by_name_rcu(struct net *net, const char *name);
 extern struct net_device	*__dev_get_by_name(struct net *net, const char *name);
@@ -1696,6 +1710,11 @@
 	napi->skb = NULL;
 }
 
+extern int netdev_rx_handler_register(struct net_device *dev,
+				      rx_handler_func_t *rx_handler,
+				      void *rx_handler_data);
+extern void netdev_rx_handler_unregister(struct net_device *dev);
+
 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 *);
@@ -1775,6 +1794,8 @@
 
 extern void netif_carrier_off(struct net_device *dev);
 
+extern void netif_notify_peers(struct net_device *dev);
+
 /**
  *	netif_dormant_on - mark device as dormant.
  *	@dev: network device
@@ -2119,8 +2140,10 @@
 /* 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 void		dev_txq_stats_fold(const struct net_device *dev, struct net_device_stats *stats);
+extern struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
+					       struct rtnl_link_stats64 *storage);
+extern void		dev_txq_stats_fold(const struct net_device *dev,
+					   struct rtnl_link_stats64 *stats);
 
 extern int		netdev_max_backlog;
 extern int		netdev_tstamp_prequeue;
@@ -2230,25 +2253,23 @@
 	return dev->name;
 }
 
-#define netdev_printk(level, netdev, format, args...)		\
-	dev_printk(level, (netdev)->dev.parent,			\
-		   "%s: " format,				\
-		   netdev_name(netdev), ##args)
-
-#define netdev_emerg(dev, format, args...)			\
-	netdev_printk(KERN_EMERG, dev, format, ##args)
-#define netdev_alert(dev, format, args...)			\
-	netdev_printk(KERN_ALERT, dev, format, ##args)
-#define netdev_crit(dev, format, args...)			\
-	netdev_printk(KERN_CRIT, dev, format, ##args)
-#define netdev_err(dev, format, args...)			\
-	netdev_printk(KERN_ERR, dev, format, ##args)
-#define netdev_warn(dev, format, args...)			\
-	netdev_printk(KERN_WARNING, dev, format, ##args)
-#define netdev_notice(dev, format, args...)			\
-	netdev_printk(KERN_NOTICE, dev, format, ##args)
-#define netdev_info(dev, format, args...)			\
-	netdev_printk(KERN_INFO, dev, format, ##args)
+extern int netdev_printk(const char *level, const struct net_device *dev,
+			 const char *format, ...)
+	__attribute__ ((format (printf, 3, 4)));
+extern int netdev_emerg(const struct net_device *dev, const char *format, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int netdev_alert(const struct net_device *dev, const char *format, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int netdev_crit(const struct net_device *dev, const char *format, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int netdev_err(const struct net_device *dev, const char *format, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int netdev_warn(const struct net_device *dev, const char *format, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int netdev_notice(const struct net_device *dev, const char *format, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int netdev_info(const struct net_device *dev, const char *format, ...)
+	__attribute__ ((format (printf, 2, 3)));
 
 #if defined(DEBUG)
 #define netdev_dbg(__dev, format, args...)			\
@@ -2296,20 +2317,26 @@
 		netdev_printk(level, (dev), fmt, ##args);	\
 } while (0)
 
+#define netif_level(level, priv, type, dev, fmt, args...)	\
+do {								\
+	if (netif_msg_##type(priv))				\
+		netdev_##level(dev, fmt, ##args);		\
+} while (0)
+
 #define netif_emerg(priv, type, dev, fmt, args...)		\
-	netif_printk(priv, type, KERN_EMERG, dev, fmt, ##args)
+	netif_level(emerg, priv, type, dev, fmt, ##args)
 #define netif_alert(priv, type, dev, fmt, args...)		\
-	netif_printk(priv, type, KERN_ALERT, dev, fmt, ##args)
+	netif_level(alert, priv, type, dev, fmt, ##args)
 #define netif_crit(priv, type, dev, fmt, args...)		\
-	netif_printk(priv, type, KERN_CRIT, dev, fmt, ##args)
+	netif_level(crit, priv, type, dev, fmt, ##args)
 #define netif_err(priv, type, dev, fmt, args...)		\
-	netif_printk(priv, type, KERN_ERR, dev, fmt, ##args)
+	netif_level(err, priv, type, dev, fmt, ##args)
 #define netif_warn(priv, type, dev, fmt, args...)		\
-	netif_printk(priv, type, KERN_WARNING, dev, fmt, ##args)
+	netif_level(warn, priv, type, dev, fmt, ##args)
 #define netif_notice(priv, type, dev, fmt, args...)		\
-	netif_printk(priv, type, KERN_NOTICE, dev, fmt, ##args)
+	netif_level(notice, priv, type, dev, fmt, ##args)
 #define netif_info(priv, type, dev, fmt, args...)		\
-	netif_printk(priv, type, KERN_INFO, (dev), fmt, ##args)
+	netif_level(info, priv, type, dev, fmt, ##args)
 
 #if defined(DEBUG)
 #define netif_dbg(priv, type, dev, format, args...)		\
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild
index 48767cd..edeeabd 100644
--- a/include/linux/netfilter/Kbuild
+++ b/include/linux/netfilter/Kbuild
@@ -3,11 +3,13 @@
 header-y += nfnetlink_conntrack.h
 header-y += nfnetlink_log.h
 header-y += nfnetlink_queue.h
+header-y += xt_CHECKSUM.h
 header-y += xt_CLASSIFY.h
 header-y += xt_CONNMARK.h
 header-y += xt_CONNSECMARK.h
 header-y += xt_CT.h
 header-y += xt_DSCP.h
+header-y += xt_IDLETIMER.h
 header-y += xt_LED.h
 header-y += xt_MARK.h
 header-y += xt_NFLOG.h
@@ -18,17 +20,19 @@
 header-y += xt_TCPOPTSTRIP.h
 header-y += xt_TEE.h
 header-y += xt_TPROXY.h
+header-y += xt_cluster.h
 header-y += xt_comment.h
 header-y += xt_connbytes.h
 header-y += xt_connlimit.h
 header-y += xt_connmark.h
 header-y += xt_conntrack.h
-header-y += xt_cluster.h
+header-y += xt_cpu.h
 header-y += xt_dccp.h
 header-y += xt_dscp.h
 header-y += xt_esp.h
 header-y += xt_hashlimit.h
 header-y += xt_iprange.h
+header-y += xt_ipvs.h
 header-y += xt_helper.h
 header-y += xt_length.h
 header-y += xt_limit.h
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
index 14e6d32..1afd18c 100644
--- a/include/linux/netfilter/nf_conntrack_common.h
+++ b/include/linux/netfilter/nf_conntrack_common.h
@@ -76,6 +76,10 @@
 	/* Conntrack is a template */
 	IPS_TEMPLATE_BIT = 11,
 	IPS_TEMPLATE = (1 << IPS_TEMPLATE_BIT),
+
+	/* Conntrack is a fake untracked entry */
+	IPS_UNTRACKED_BIT = 12,
+	IPS_UNTRACKED = (1 << IPS_UNTRACKED_BIT),
 };
 
 /* Connection tracking event types */
diff --git a/include/linux/netfilter/nfnetlink_log.h b/include/linux/netfilter/nfnetlink_log.h
index d3bab7a..ea9b8d3 100644
--- a/include/linux/netfilter/nfnetlink_log.h
+++ b/include/linux/netfilter/nfnetlink_log.h
@@ -89,6 +89,7 @@
 #define NFULNL_COPY_NONE	0x00
 #define NFULNL_COPY_META	0x01
 #define NFULNL_COPY_PACKET	0x02
+/* 0xff is reserved, don't use it for new copy modes. */
 
 #define NFULNL_CFG_F_SEQ	0x0001
 #define NFULNL_CFG_F_SEQ_GLOBAL	0x0002
diff --git a/include/linux/netfilter/xt_CHECKSUM.h b/include/linux/netfilter/xt_CHECKSUM.h
new file mode 100644
index 0000000..9a2e466
--- /dev/null
+++ b/include/linux/netfilter/xt_CHECKSUM.h
@@ -0,0 +1,20 @@
+/* Header file for iptables ipt_CHECKSUM target
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 Red Hat Inc
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+*/
+#ifndef _XT_CHECKSUM_TARGET_H
+#define _XT_CHECKSUM_TARGET_H
+
+#include <linux/types.h>
+
+#define XT_CHECKSUM_OP_FILL	0x01	/* fill in checksum in IP header */
+
+struct xt_CHECKSUM_info {
+	__u8 operation;	/* bitset of operations */
+};
+
+#endif /* _XT_CHECKSUM_TARGET_H */
diff --git a/include/linux/netfilter/xt_IDLETIMER.h b/include/linux/netfilter/xt_IDLETIMER.h
new file mode 100644
index 0000000..3e1aa1b
--- /dev/null
+++ b/include/linux/netfilter/xt_IDLETIMER.h
@@ -0,0 +1,45 @@
+/*
+ * linux/include/linux/netfilter/xt_IDLETIMER.h
+ *
+ * Header file for Xtables timer target module.
+ *
+ * Copyright (C) 2004, 2010 Nokia Corporation
+ * Written by Timo Teras <ext-timo.teras@nokia.com>
+ *
+ * Converted to x_tables and forward-ported to 2.6.34
+ * by Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef _XT_IDLETIMER_H
+#define _XT_IDLETIMER_H
+
+#include <linux/types.h>
+
+#define MAX_IDLETIMER_LABEL_SIZE 28
+
+struct idletimer_tg_info {
+	__u32 timeout;
+
+	char label[MAX_IDLETIMER_LABEL_SIZE];
+
+	/* for kernel module internal use only */
+	struct idletimer_tg *timer __attribute((aligned(8)));
+};
+
+#endif
diff --git a/include/linux/netfilter/xt_cpu.h b/include/linux/netfilter/xt_cpu.h
new file mode 100644
index 0000000..93c7f11
--- /dev/null
+++ b/include/linux/netfilter/xt_cpu.h
@@ -0,0 +1,11 @@
+#ifndef _XT_CPU_H
+#define _XT_CPU_H
+
+#include <linux/types.h>
+
+struct xt_cpu_info {
+	__u32	cpu;
+	__u32	invert;
+};
+
+#endif /*_XT_CPU_H*/
diff --git a/include/linux/netfilter/xt_ipvs.h b/include/linux/netfilter/xt_ipvs.h
new file mode 100644
index 0000000..1167aeb
--- /dev/null
+++ b/include/linux/netfilter/xt_ipvs.h
@@ -0,0 +1,27 @@
+#ifndef _XT_IPVS_H
+#define _XT_IPVS_H
+
+enum {
+	XT_IPVS_IPVS_PROPERTY =	1 << 0, /* all other options imply this one */
+	XT_IPVS_PROTO =		1 << 1,
+	XT_IPVS_VADDR =		1 << 2,
+	XT_IPVS_VPORT =		1 << 3,
+	XT_IPVS_DIR =		1 << 4,
+	XT_IPVS_METHOD =	1 << 5,
+	XT_IPVS_VPORTCTL =	1 << 6,
+	XT_IPVS_MASK =		(1 << 7) - 1,
+	XT_IPVS_ONCE_MASK =	XT_IPVS_MASK & ~XT_IPVS_IPVS_PROPERTY
+};
+
+struct xt_ipvs_mtinfo {
+	union nf_inet_addr	vaddr, vmask;
+	__be16			vport;
+	__u8			l4proto;
+	__u8			fwd_method;
+	__be16			vportctl;
+
+	__u8			invert;
+	__u8			bitmask;
+};
+
+#endif /* _XT_IPVS_H */
diff --git a/include/linux/netfilter/xt_quota.h b/include/linux/netfilter/xt_quota.h
index 8dc89df..b0d28c6 100644
--- a/include/linux/netfilter/xt_quota.h
+++ b/include/linux/netfilter/xt_quota.h
@@ -11,9 +11,9 @@
 struct xt_quota_info {
 	u_int32_t		flags;
 	u_int32_t		pad;
+	aligned_u64		quota;
 
 	/* Used internally by the kernel */
-	aligned_u64		quota;
 	struct xt_quota_priv	*master;
 };
 
diff --git a/include/linux/netfilter_ipv4/ipt_LOG.h b/include/linux/netfilter_ipv4/ipt_LOG.h
index 90fa652..dcdbadf 100644
--- a/include/linux/netfilter_ipv4/ipt_LOG.h
+++ b/include/linux/netfilter_ipv4/ipt_LOG.h
@@ -7,7 +7,8 @@
 #define IPT_LOG_IPOPT		0x04	/* Log IP options */
 #define IPT_LOG_UID		0x08	/* Log UID owning local socket */
 #define IPT_LOG_NFLOG		0x10	/* Unsupported, don't reuse */
-#define IPT_LOG_MASK		0x1f
+#define IPT_LOG_MACDECODE	0x20	/* Decode MAC header */
+#define IPT_LOG_MASK		0x2f
 
 struct ipt_log_info {
 	unsigned char level;
diff --git a/include/linux/netfilter_ipv6/ip6t_LOG.h b/include/linux/netfilter_ipv6/ip6t_LOG.h
index 0d0119b..9dd5579 100644
--- a/include/linux/netfilter_ipv6/ip6t_LOG.h
+++ b/include/linux/netfilter_ipv6/ip6t_LOG.h
@@ -7,7 +7,8 @@
 #define IP6T_LOG_IPOPT		0x04	/* Log IP options */
 #define IP6T_LOG_UID		0x08	/* Log UID owning local socket */
 #define IP6T_LOG_NFLOG		0x10	/* Unsupported, don't use */
-#define IP6T_LOG_MASK		0x1f
+#define IP6T_LOG_MACDECODE	0x20	/* Decode MAC header */
+#define IP6T_LOG_MASK		0x2f
 
 struct ip6t_log_info {
 	unsigned char level;
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index e9e2312..413742c 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -46,9 +46,11 @@
 void netpoll_send_udp(struct netpoll *np, const char *msg, int len);
 void netpoll_print_options(struct netpoll *np);
 int netpoll_parse_options(struct netpoll *np, char *opt);
+int __netpoll_setup(struct netpoll *np);
 int netpoll_setup(struct netpoll *np);
 int netpoll_trap(void);
 void netpoll_set_trap(int trap);
+void __netpoll_cleanup(struct netpoll *np);
 void netpoll_cleanup(struct netpoll *np);
 int __netpoll_rx(struct sk_buff *skb);
 void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
@@ -57,12 +59,15 @@
 #ifdef CONFIG_NETPOLL
 static inline bool netpoll_rx(struct sk_buff *skb)
 {
-	struct netpoll_info *npinfo = skb->dev->npinfo;
+	struct netpoll_info *npinfo;
 	unsigned long flags;
 	bool ret = false;
 
+	rcu_read_lock_bh();
+	npinfo = rcu_dereference_bh(skb->dev->npinfo);
+
 	if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags))
-		return false;
+		goto out;
 
 	spin_lock_irqsave(&npinfo->rx_lock, flags);
 	/* check rx_flags again with the lock held */
@@ -70,12 +75,14 @@
 		ret = true;
 	spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 
+out:
+	rcu_read_unlock_bh();
 	return ret;
 }
 
 static inline int netpoll_rx_on(struct sk_buff *skb)
 {
-	struct netpoll_info *npinfo = skb->dev->npinfo;
+	struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo);
 
 	return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags);
 }
@@ -91,7 +98,6 @@
 {
 	struct net_device *dev = napi->dev;
 
-	rcu_read_lock(); /* deal with race on ->npinfo */
 	if (dev && dev->npinfo) {
 		spin_lock(&napi->poll_lock);
 		napi->poll_owner = smp_processor_id();
@@ -108,7 +114,11 @@
 		napi->poll_owner = -1;
 		spin_unlock(&napi->poll_lock);
 	}
-	rcu_read_unlock();
+}
+
+static inline int netpoll_tx_running(struct net_device *dev)
+{
+	return irqs_disabled();
 }
 
 #else
@@ -134,6 +144,10 @@
 static inline void netpoll_netdev_init(struct net_device *dev)
 {
 }
+static inline int netpoll_tx_running(struct net_device *dev)
+{
+	return 0;
+}
 #endif
 
 #endif
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index b7c77f9..2c87016 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -132,7 +132,7 @@
  * 	%NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
  * 	%NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
  * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
- * 	to the the specified ISO/IEC 3166-1 alpha2 country code. The core will
+ * 	to 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
@@ -725,6 +725,12 @@
  * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations
  *	connected to this BSS.
  *
+ * @NL80211_ATTR_WIPHY_TX_POWER_SETTING: Transmit power setting type. See
+ *      &enum nl80211_tx_power_setting for possible values.
+ * @NL80211_ATTR_WIPHY_TX_POWER_LEVEL: Transmit power level in signed mBm units.
+ *      This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING
+ *      for non-automatic settings.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -882,6 +888,9 @@
 
 	NL80211_ATTR_AP_ISOLATE,
 
+	NL80211_ATTR_WIPHY_TX_POWER_SETTING,
+	NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -1659,4 +1668,17 @@
 	NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
 };
 
+
+/**
+ * enum nl80211_tx_power_setting - TX power adjustment
+ * @NL80211_TX_POWER_AUTOMATIC: automatically determine transmit power
+ * @NL80211_TX_POWER_LIMITED: limit TX power by the mBm parameter
+ * @NL80211_TX_POWER_FIXED: fix TX power to the mBm parameter
+ */
+enum nl80211_tx_power_setting {
+	NL80211_TX_POWER_AUTOMATIC,
+	NL80211_TX_POWER_LIMITED,
+	NL80211_TX_POWER_FIXED,
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 540703b..b2f1a4d 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -210,6 +210,7 @@
 #define NETDEV_POST_INIT	0x0010
 #define NETDEV_UNREGISTER_BATCH 0x0011
 #define NETDEV_BONDING_DESLAVE  0x0012
+#define NETDEV_NOTIFY_PEERS	0x0013
 
 #define SYS_DOWN	0x0001	/* Notify of system down */
 #define SYS_RESTART	SYS_DOWN
diff --git a/include/linux/padata.h b/include/linux/padata.h
index 8d84062..bdcd1e9 100644
--- a/include/linux/padata.h
+++ b/include/linux/padata.h
@@ -25,6 +25,11 @@
 #include <linux/spinlock.h>
 #include <linux/list.h>
 #include <linux/timer.h>
+#include <linux/notifier.h>
+#include <linux/kobject.h>
+
+#define PADATA_CPU_SERIAL   0x01
+#define PADATA_CPU_PARALLEL 0x02
 
 /**
  * struct padata_priv -  Embedded to the users data structure.
@@ -59,7 +64,20 @@
 };
 
 /**
- * struct padata_queue - The percpu padata queues.
+* struct padata_serial_queue - The percpu padata serial queue
+*
+* @serial: List to wait for serialization after reordering.
+* @work: work struct for serialization.
+* @pd: Backpointer to the internal control structure.
+*/
+struct padata_serial_queue {
+       struct padata_list    serial;
+       struct work_struct    work;
+       struct parallel_data *pd;
+};
+
+/**
+ * struct padata_parallel_queue - The percpu padata parallel queue
  *
  * @parallel: List to wait for parallelization.
  * @reorder: List to wait for reordering after parallel processing.
@@ -67,18 +85,28 @@
  * @pwork: work struct for parallelization.
  * @swork: work struct for serialization.
  * @pd: Backpointer to the internal control structure.
+ * @work: work struct for parallelization.
  * @num_obj: Number of objects that are processed by this cpu.
  * @cpu_index: Index of the cpu.
  */
-struct padata_queue {
-	struct padata_list	parallel;
-	struct padata_list	reorder;
-	struct padata_list	serial;
-	struct work_struct	pwork;
-	struct work_struct	swork;
-	struct parallel_data    *pd;
-	atomic_t		num_obj;
-	int			cpu_index;
+struct padata_parallel_queue {
+       struct padata_list    parallel;
+       struct padata_list    reorder;
+       struct parallel_data *pd;
+       struct work_struct    work;
+       atomic_t              num_obj;
+       int                   cpu_index;
+};
+
+/**
+ * struct padata_cpumask - The cpumasks for the parallel/serial workers
+ *
+ * @pcpu: cpumask for the parallel workers.
+ * @cbcpu: cpumask for the serial (callback) workers.
+ */
+struct padata_cpumask {
+	cpumask_var_t	pcpu;
+	cpumask_var_t	cbcpu;
 };
 
 /**
@@ -86,25 +114,29 @@
  * that depends on the cpumask in use.
  *
  * @pinst: padata instance.
- * @queue: percpu padata queues.
+ * @pqueue: percpu padata queues used for parallelization.
+ * @squeue: percpu padata queues used for serialuzation.
  * @seq_nr: The sequence number that will be attached to the next object.
  * @reorder_objects: Number of objects waiting in the reorder queues.
  * @refcnt: Number of objects holding a reference on this parallel_data.
  * @max_seq_nr:  Maximal used sequence number.
- * @cpumask: cpumask in use.
+ * @cpumask: The cpumasks in use for parallel and serial workers.
  * @lock: Reorder lock.
+ * @processed: Number of already processed objects.
  * @timer: Reorder timer.
  */
 struct parallel_data {
-	struct padata_instance	*pinst;
-	struct padata_queue	*queue;
-	atomic_t		seq_nr;
-	atomic_t		reorder_objects;
-	atomic_t                refcnt;
-	unsigned int		max_seq_nr;
-	cpumask_var_t		cpumask;
-	spinlock_t              lock;
-	struct timer_list       timer;
+	struct padata_instance		*pinst;
+	struct padata_parallel_queue	*pqueue;
+	struct padata_serial_queue	*squeue;
+	atomic_t			seq_nr;
+	atomic_t			reorder_objects;
+	atomic_t			refcnt;
+	unsigned int			max_seq_nr;
+	struct padata_cpumask		cpumask;
+	spinlock_t                      lock ____cacheline_aligned;
+	unsigned int			processed;
+	struct timer_list		timer;
 };
 
 /**
@@ -113,31 +145,48 @@
  * @cpu_notifier: cpu hotplug notifier.
  * @wq: The workqueue in use.
  * @pd: The internal control structure.
- * @cpumask: User supplied cpumask.
+ * @cpumask: User supplied cpumasks for parallel and serial works.
+ * @cpumask_change_notifier: Notifiers chain for user-defined notify
+ *            callbacks that will be called when either @pcpu or @cbcpu
+ *            or both cpumasks change.
+ * @kobj: padata instance kernel object.
  * @lock: padata instance lock.
  * @flags: padata flags.
  */
 struct padata_instance {
-	struct notifier_block   cpu_notifier;
-	struct workqueue_struct *wq;
-	struct parallel_data	*pd;
-	cpumask_var_t           cpumask;
-	struct mutex		lock;
-	u8			flags;
-#define	PADATA_INIT		1
-#define	PADATA_RESET		2
+	struct notifier_block		 cpu_notifier;
+	struct workqueue_struct		*wq;
+	struct parallel_data		*pd;
+	struct padata_cpumask		cpumask;
+	struct blocking_notifier_head	 cpumask_change_notifier;
+	struct kobject                   kobj;
+	struct mutex			 lock;
+	u8				 flags;
+#define	PADATA_INIT	1
+#define	PADATA_RESET	2
+#define	PADATA_INVALID	4
 };
 
-extern struct padata_instance *padata_alloc(const struct cpumask *cpumask,
-					    struct workqueue_struct *wq);
+extern struct padata_instance *padata_alloc_possible(
+					struct workqueue_struct *wq);
+extern struct padata_instance *padata_alloc(struct workqueue_struct *wq,
+					    const struct cpumask *pcpumask,
+					    const struct cpumask *cbcpumask);
 extern void padata_free(struct padata_instance *pinst);
 extern int padata_do_parallel(struct padata_instance *pinst,
 			      struct padata_priv *padata, int cb_cpu);
 extern void padata_do_serial(struct padata_priv *padata);
-extern int padata_set_cpumask(struct padata_instance *pinst,
+extern int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type,
 			      cpumask_var_t cpumask);
-extern int padata_add_cpu(struct padata_instance *pinst, int cpu);
-extern int padata_remove_cpu(struct padata_instance *pinst, int cpu);
-extern void padata_start(struct padata_instance *pinst);
+extern int padata_set_cpumasks(struct padata_instance *pinst,
+			       cpumask_var_t pcpumask,
+			       cpumask_var_t cbcpumask);
+extern int padata_add_cpu(struct padata_instance *pinst, int cpu, int mask);
+extern int padata_remove_cpu(struct padata_instance *pinst, int cpu, int mask);
+extern int padata_start(struct padata_instance *pinst);
 extern void padata_stop(struct padata_instance *pinst);
+extern int padata_register_cpumask_notifier(struct padata_instance *pinst,
+					    struct notifier_block *nblock);
+extern int padata_unregister_cpumask_notifier(struct padata_instance *pinst,
+					      struct notifier_block *nblock);
 #endif
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 3bedcc1..e69612c 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1494,6 +1494,9 @@
 #define PCI_DEVICE_ID_SBE_WANXL100	0x0301
 #define PCI_DEVICE_ID_SBE_WANXL200	0x0302
 #define PCI_DEVICE_ID_SBE_WANXL400	0x0104
+#define PCI_SUBDEVICE_ID_SBE_T3E3	0x0009
+#define PCI_SUBDEVICE_ID_SBE_2T3E3_P0	0x0901
+#define PCI_SUBDEVICE_ID_SBE_2T3E3_P1	0x0902
 
 #define PCI_VENDOR_ID_TOSHIBA		0x1179
 #define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1	0x0101
@@ -2054,7 +2057,6 @@
 #define PCI_DEVICE_ID_NX2_57711E	0x1650
 #define PCI_DEVICE_ID_TIGON3_5705	0x1653
 #define PCI_DEVICE_ID_TIGON3_5705_2	0x1654
-#define PCI_DEVICE_ID_TIGON3_5720	0x1658
 #define PCI_DEVICE_ID_TIGON3_5721	0x1659
 #define PCI_DEVICE_ID_TIGON3_5722	0x165a
 #define PCI_DEVICE_ID_TIGON3_5723	0x165b
@@ -2068,13 +2070,11 @@
 #define PCI_DEVICE_ID_TIGON3_5754M	0x1672
 #define PCI_DEVICE_ID_TIGON3_5755M	0x1673
 #define PCI_DEVICE_ID_TIGON3_5756	0x1674
-#define PCI_DEVICE_ID_TIGON3_5750	0x1676
 #define PCI_DEVICE_ID_TIGON3_5751	0x1677
 #define PCI_DEVICE_ID_TIGON3_5715	0x1678
 #define PCI_DEVICE_ID_TIGON3_5715S	0x1679
 #define PCI_DEVICE_ID_TIGON3_5754	0x167a
 #define PCI_DEVICE_ID_TIGON3_5755	0x167b
-#define PCI_DEVICE_ID_TIGON3_5750M	0x167c
 #define PCI_DEVICE_ID_TIGON3_5751M	0x167d
 #define PCI_DEVICE_ID_TIGON3_5751F	0x167e
 #define PCI_DEVICE_ID_TIGON3_5787F	0x167f
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index d3a38d6..b8b9084 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -45,6 +45,16 @@
 #define PCPU_MIN_UNIT_SIZE		PFN_ALIGN(64 << 10)
 
 /*
+ * Percpu allocator can serve percpu allocations before slab is
+ * initialized which allows slab to depend on the percpu allocator.
+ * The following two parameters decide how much resource to
+ * preallocate for this.  Keep PERCPU_DYNAMIC_RESERVE equal to or
+ * larger than PERCPU_DYNAMIC_EARLY_SIZE.
+ */
+#define PERCPU_DYNAMIC_EARLY_SLOTS	128
+#define PERCPU_DYNAMIC_EARLY_SIZE	(12 << 10)
+
+/*
  * PERCPU_DYNAMIC_RESERVE indicates the amount of free area to piggy
  * back on the first chunk for dynamic percpu allocation if arch is
  * manually allocating and mapping it for faster access (as a part of
@@ -104,16 +114,11 @@
 							     int nr_units);
 extern void __init pcpu_free_alloc_info(struct pcpu_alloc_info *ai);
 
-extern struct pcpu_alloc_info * __init pcpu_build_alloc_info(
-				size_t reserved_size, ssize_t dyn_size,
-				size_t atom_size,
-				pcpu_fc_cpu_distance_fn_t cpu_distance_fn);
-
 extern int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
 					 void *base_addr);
 
 #ifdef CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK
-extern int __init pcpu_embed_first_chunk(size_t reserved_size, ssize_t dyn_size,
+extern int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size,
 				size_t atom_size,
 				pcpu_fc_cpu_distance_fn_t cpu_distance_fn,
 				pcpu_fc_alloc_fn_t alloc_fn,
@@ -140,6 +145,7 @@
 #ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
 extern void __init setup_per_cpu_areas(void);
 #endif
+extern void __init percpu_init_late(void);
 
 #else /* CONFIG_SMP */
 
@@ -153,6 +159,8 @@
 
 static inline void __init setup_per_cpu_areas(void) { }
 
+static inline void __init percpu_init_late(void) { }
+
 static inline void *pcpu_lpage_remapped(void *kaddr)
 {
 	return NULL;
diff --git a/include/linux/phonet.h b/include/linux/phonet.h
index e5126cf..24426c3 100644
--- a/include/linux/phonet.h
+++ b/include/linux/phonet.h
@@ -56,7 +56,7 @@
 	__be16	pn_length;
 	__u8	pn_robj;
 	__u8	pn_sobj;
-} __attribute__((packed));
+} __packed;
 
 /* Common Phonet payload header */
 struct phonetmsg {
@@ -98,7 +98,7 @@
 	__u8 spn_dev;
 	__u8 spn_resource;
 	__u8 spn_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - 3];
-} __attribute__ ((packed));
+} __packed;
 
 /* Well known address */
 #define PN_DEV_PC	0x10
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 987e111..6b0a782 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -234,6 +234,8 @@
 	PHY_RESUMING
 };
 
+struct sk_buff;
+
 /* phy_device: An instance of a PHY
  *
  * drv: Pointer to the driver for this PHY instance
@@ -402,6 +404,26 @@
 	/* Clears up any memory if needed */
 	void (*remove)(struct phy_device *phydev);
 
+	/* Handles SIOCSHWTSTAMP ioctl for hardware time stamping. */
+	int  (*hwtstamp)(struct phy_device *phydev, struct ifreq *ifr);
+
+	/*
+	 * Requests a Rx timestamp for 'skb'. If the skb is accepted,
+	 * the phy driver promises to deliver it using netif_rx() as
+	 * soon as a timestamp becomes available. One of the
+	 * PTP_CLASS_ values is passed in 'type'. The function must
+	 * return true if the skb is accepted for delivery.
+	 */
+	bool (*rxtstamp)(struct phy_device *dev, struct sk_buff *skb, int type);
+
+	/*
+	 * Requests a Tx timestamp for 'skb'. The phy driver promises
+	 * to deliver it to the socket's error queue as soon as a
+	 * timestamp becomes available. One of the PTP_CLASS_ values
+	 * is passed in 'type'.
+	 */
+	void (*txtstamp)(struct phy_device *dev, struct sk_buff *skb, int type);
+
 	struct device_driver driver;
 };
 #define to_phy_driver(d) container_of(d, struct phy_driver, driver)
@@ -498,7 +520,7 @@
 int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
 int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
 int phy_mii_ioctl(struct phy_device *phydev,
-		struct mii_ioctl_data *mii_data, int cmd);
+		struct ifreq *ifr, int cmd);
 int phy_start_interrupts(struct phy_device *phydev);
 void phy_print_status(struct phy_device *phydev);
 struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id);
diff --git a/include/linux/plist.h b/include/linux/plist.h
index 6898985..7254eda 100644
--- a/include/linux/plist.h
+++ b/include/linux/plist.h
@@ -260,6 +260,23 @@
 #endif
 
 /**
+ * plist_last_entry - get the struct for the last entry
+ * @head:	the &struct plist_head pointer
+ * @type:	the type of the struct this is embedded in
+ * @member:	the name of the list_struct within the struct
+ */
+#ifdef CONFIG_DEBUG_PI_LIST
+# define plist_last_entry(head, type, member)	\
+({ \
+	WARN_ON(plist_head_empty(head)); \
+	container_of(plist_last(head), type, member); \
+})
+#else
+# define plist_last_entry(head, type, member)	\
+	container_of(plist_last(head), type, member)
+#endif
+
+/**
  * plist_first - return the first node (and thus, highest priority)
  * @head:	the &struct plist_head pointer
  *
@@ -271,4 +288,16 @@
 			  struct plist_node, plist.node_list);
 }
 
+/**
+ * plist_last - return the last node (and thus, lowest priority)
+ * @head:	the &struct plist_head pointer
+ *
+ * Assumes the plist is _not_ empty.
+ */
+static inline struct plist_node *plist_last(const struct plist_head *head)
+{
+	return list_entry(head->node_list.prev,
+			  struct plist_node, plist.node_list);
+}
+
 #endif
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 8e258c7..52e8c55 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -457,6 +457,7 @@
 #ifdef CONFIG_PM_SLEEP
 	struct list_head	entry;
 	struct completion	completion;
+	unsigned long		wakeup_count;
 #endif
 #ifdef CONFIG_PM_RUNTIME
 	struct timer_list	suspend_timer;
@@ -476,9 +477,15 @@
 	enum rpm_request	request;
 	enum rpm_status		runtime_status;
 	int			runtime_error;
+	unsigned long		active_jiffies;
+	unsigned long		suspended_jiffies;
+	unsigned long		accounting_timestamp;
 #endif
 };
 
+extern void update_pm_runtime_accounting(struct device *dev);
+
+
 /*
  * The PM_EVENT_ messages are also used by drivers implementing the legacy
  * suspend framework, based on the ->suspend() and ->resume() callbacks common
@@ -552,6 +559,11 @@
 	} while (0)
 
 extern void device_pm_wait_for_dev(struct device *sub, struct device *dev);
+
+/* drivers/base/power/wakeup.c */
+extern void pm_wakeup_event(struct device *dev, unsigned int msec);
+extern void pm_stay_awake(struct device *dev);
+extern void pm_relax(void);
 #else /* !CONFIG_PM_SLEEP */
 
 #define device_pm_lock() do {} while (0)
@@ -565,6 +577,10 @@
 #define suspend_report_result(fn, ret)		do {} while (0)
 
 static inline void device_pm_wait_for_dev(struct device *a, struct device *b) {}
+
+static inline void pm_wakeup_event(struct device *dev, unsigned int msec) {}
+static inline void pm_stay_awake(struct device *dev) {}
+static inline void pm_relax(void) {}
 #endif /* !CONFIG_PM_SLEEP */
 
 /* How to reorder dpm_list after device_move() */
diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h
index 8ba440e..77cbddb 100644
--- a/include/linux/pm_qos_params.h
+++ b/include/linux/pm_qos_params.h
@@ -1,8 +1,10 @@
+#ifndef _LINUX_PM_QOS_PARAMS_H
+#define _LINUX_PM_QOS_PARAMS_H
 /* interface for the pm_qos_power infrastructure of the linux kernel.
  *
  * Mark Gross <mgross@linux.intel.com>
  */
-#include <linux/list.h>
+#include <linux/plist.h>
 #include <linux/notifier.h>
 #include <linux/miscdevice.h>
 
@@ -14,9 +16,12 @@
 #define PM_QOS_NUM_CLASSES 4
 #define PM_QOS_DEFAULT_VALUE -1
 
-struct pm_qos_request_list;
+struct pm_qos_request_list {
+	struct plist_node list;
+	int pm_qos_class;
+};
 
-struct pm_qos_request_list *pm_qos_add_request(int pm_qos_class, s32 value);
+void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
 void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
 		s32 new_value);
 void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
@@ -24,4 +29,6 @@
 int pm_qos_request(int pm_qos_class);
 int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
 int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
+int pm_qos_request_active(struct pm_qos_request_list *req);
 
+#endif
diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
index 22d64c1..76aca48 100644
--- a/include/linux/pm_wakeup.h
+++ b/include/linux/pm_wakeup.h
@@ -29,8 +29,11 @@
 
 #ifdef CONFIG_PM
 
-/* changes to device_may_wakeup take effect on the next pm state change.
- * by default, devices should wakeup if they can.
+/* Changes to device_may_wakeup take effect on the next pm state change.
+ *
+ * By default, most devices should leave wakeup disabled.  The exceptions
+ * are devices that everyone expects to be wakeup sources: keyboards,
+ * power buttons, possibly network interfaces, etc.
  */
 static inline void device_init_wakeup(struct device *dev, bool val)
 {
@@ -59,7 +62,7 @@
 
 #else /* !CONFIG_PM */
 
-/* For some reason the next two routines work even without CONFIG_PM */
+/* For some reason the following routines work even without CONFIG_PM */
 static inline void device_init_wakeup(struct device *dev, bool val)
 {
 	dev->power.can_wakeup = val;
@@ -67,6 +70,7 @@
 
 static inline void device_set_wakeup_capable(struct device *dev, bool capable)
 {
+	dev->power.can_wakeup = capable;
 }
 
 static inline bool device_can_wakeup(struct device *dev)
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index 7c4193e..1bc1338 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -414,6 +414,7 @@
 	int (*disable) (struct pnp_dev *dev);
 
 	/* protocol specific suspend/resume */
+	bool (*can_wakeup) (struct pnp_dev *dev);
 	int (*suspend) (struct pnp_dev * dev, pm_message_t state);
 	int (*resume) (struct pnp_dev * dev);
 
diff --git a/include/linux/ptp_classify.h b/include/linux/ptp_classify.h
new file mode 100644
index 0000000..943a85a
--- /dev/null
+++ b/include/linux/ptp_classify.h
@@ -0,0 +1,126 @@
+/*
+ * PTP 1588 support
+ *
+ * This file implements a BPF that recognizes PTP event messages.
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PTP_CLASSIFY_H_
+#define _PTP_CLASSIFY_H_
+
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/filter.h>
+#ifdef __KERNEL__
+#include <linux/in.h>
+#else
+#include <netinet/in.h>
+#endif
+
+#define PTP_CLASS_NONE  0x00 /* not a PTP event message */
+#define PTP_CLASS_V1    0x01 /* protocol version 1 */
+#define PTP_CLASS_V2    0x02 /* protocol version 2 */
+#define PTP_CLASS_VMASK 0x0f /* max protocol version is 15 */
+#define PTP_CLASS_IPV4  0x10 /* event in an IPV4 UDP packet */
+#define PTP_CLASS_IPV6  0x20 /* event in an IPV6 UDP packet */
+#define PTP_CLASS_L2    0x30 /* event in a L2 packet */
+#define PTP_CLASS_VLAN  0x40 /* event in a VLAN tagged L2 packet */
+#define PTP_CLASS_PMASK 0xf0 /* mask for the packet type field */
+
+#define PTP_CLASS_V1_IPV4 (PTP_CLASS_V1 | PTP_CLASS_IPV4)
+#define PTP_CLASS_V1_IPV6 (PTP_CLASS_V1 | PTP_CLASS_IPV6) /*probably DNE*/
+#define PTP_CLASS_V2_IPV4 (PTP_CLASS_V2 | PTP_CLASS_IPV4)
+#define PTP_CLASS_V2_IPV6 (PTP_CLASS_V2 | PTP_CLASS_IPV6)
+#define PTP_CLASS_V2_L2   (PTP_CLASS_V2 | PTP_CLASS_L2)
+#define PTP_CLASS_V2_VLAN (PTP_CLASS_V2 | PTP_CLASS_VLAN)
+
+#define PTP_EV_PORT 319
+
+#define OFF_ETYPE	12
+#define OFF_IHL		14
+#define OFF_FRAG	20
+#define OFF_PROTO4	23
+#define OFF_NEXT	6
+#define OFF_UDP_DST	2
+
+#define IP6_HLEN	40
+#define UDP_HLEN	8
+
+#define RELOFF_DST4	(ETH_HLEN + OFF_UDP_DST)
+#define OFF_DST6	(ETH_HLEN + IP6_HLEN + OFF_UDP_DST)
+#define OFF_PTP6	(ETH_HLEN + IP6_HLEN + UDP_HLEN)
+
+#define OP_AND	(BPF_ALU | BPF_AND  | BPF_K)
+#define OP_JEQ	(BPF_JMP | BPF_JEQ  | BPF_K)
+#define OP_JSET	(BPF_JMP | BPF_JSET | BPF_K)
+#define OP_LDB	(BPF_LD  | BPF_B    | BPF_ABS)
+#define OP_LDH	(BPF_LD  | BPF_H    | BPF_ABS)
+#define OP_LDHI	(BPF_LD  | BPF_H    | BPF_IND)
+#define OP_LDX	(BPF_LDX | BPF_B    | BPF_MSH)
+#define OP_OR	(BPF_ALU | BPF_OR   | BPF_K)
+#define OP_RETA	(BPF_RET | BPF_A)
+#define OP_RETK	(BPF_RET | BPF_K)
+
+static inline int ptp_filter_init(struct sock_filter *f, int len)
+{
+	if (OP_LDH == f[0].code)
+		return sk_chk_filter(f, len);
+	else
+		return 0;
+}
+
+#define PTP_FILTER \
+	{OP_LDH,	0,   0, OFF_ETYPE		}, /*              */ \
+	{OP_JEQ,	0,  12, ETH_P_IP		}, /* f goto L20   */ \
+	{OP_LDB,	0,   0, OFF_PROTO4		}, /*              */ \
+	{OP_JEQ,	0,   9, IPPROTO_UDP		}, /* f goto L10   */ \
+	{OP_LDH,	0,   0, OFF_FRAG		}, /*              */ \
+	{OP_JSET,	7,   0, 0x1fff			}, /* t goto L11   */ \
+	{OP_LDX,	0,   0, OFF_IHL			}, /*              */ \
+	{OP_LDHI,	0,   0, RELOFF_DST4		}, /*              */ \
+	{OP_JEQ,	0,   4, PTP_EV_PORT		}, /* f goto L12   */ \
+	{OP_LDHI,	0,   0, ETH_HLEN + UDP_HLEN	}, /*              */ \
+	{OP_AND,	0,   0, PTP_CLASS_VMASK		}, /*              */ \
+	{OP_OR,		0,   0, PTP_CLASS_IPV4		}, /*              */ \
+	{OP_RETA,	0,   0, 0			}, /*              */ \
+/*L1x*/	{OP_RETK,	0,   0, PTP_CLASS_NONE		}, /*              */ \
+/*L20*/	{OP_JEQ,	0,   9, ETH_P_IPV6		}, /* f goto L40   */ \
+	{OP_LDB,	0,   0, ETH_HLEN + OFF_NEXT	}, /*              */ \
+	{OP_JEQ,	0,   6, IPPROTO_UDP		}, /* f goto L30   */ \
+	{OP_LDH,	0,   0, OFF_DST6		}, /*              */ \
+	{OP_JEQ,	0,   4, PTP_EV_PORT		}, /* f goto L31   */ \
+	{OP_LDH,	0,   0, OFF_PTP6		}, /*              */ \
+	{OP_AND,	0,   0, PTP_CLASS_VMASK		}, /*              */ \
+	{OP_OR,		0,   0, PTP_CLASS_IPV6		}, /*              */ \
+	{OP_RETA,	0,   0, 0			}, /*              */ \
+/*L3x*/	{OP_RETK,	0,   0, PTP_CLASS_NONE		}, /*              */ \
+/*L40*/	{OP_JEQ,	0,   6, ETH_P_8021Q		}, /* f goto L50   */ \
+	{OP_LDH,	0,   0, OFF_ETYPE + 4		}, /*              */ \
+	{OP_JEQ,	0,   9, ETH_P_1588		}, /* f goto L60   */ \
+	{OP_LDH,	0,   0, ETH_HLEN + VLAN_HLEN	}, /*              */ \
+	{OP_AND,	0,   0, PTP_CLASS_VMASK		}, /*              */ \
+	{OP_OR,		0,   0, PTP_CLASS_VLAN		}, /*              */ \
+	{OP_RETA,	0,   0, 0			}, /*              */ \
+/*L50*/	{OP_JEQ,	0,   4, ETH_P_1588		}, /* f goto L61   */ \
+	{OP_LDH,	0,   0, ETH_HLEN		}, /*              */ \
+	{OP_AND,	0,   0, PTP_CLASS_VMASK		}, /*              */ \
+	{OP_OR,		0,   0, PTP_CLASS_L2		}, /*              */ \
+	{OP_RETA,	0,   0, 0			}, /*              */ \
+/*L6x*/	{OP_RETK,	0,   0, PTP_CLASS_NONE		},
+
+#endif
diff --git a/drivers/staging/rar_register/rar_register.h b/include/linux/rar_register.h
similarity index 100%
rename from drivers/staging/rar_register/rar_register.h
rename to include/linux/rar_register.h
diff --git a/include/linux/rds.h b/include/linux/rds.h
index cab4994..24bce3d 100644
--- a/include/linux/rds.h
+++ b/include/linux/rds.h
@@ -100,7 +100,7 @@
 struct rds_info_counter {
 	u_int8_t	name[32];
 	u_int64_t	value;
-} __attribute__((packed));
+} __packed;
 
 #define RDS_INFO_CONNECTION_FLAG_SENDING	0x01
 #define RDS_INFO_CONNECTION_FLAG_CONNECTING	0x02
@@ -115,7 +115,7 @@
 	__be32		faddr;
 	u_int8_t	transport[TRANSNAMSIZ];		/* null term ascii */
 	u_int8_t	flags;
-} __attribute__((packed));
+} __packed;
 
 struct rds_info_flow {
 	__be32		laddr;
@@ -123,7 +123,7 @@
 	u_int32_t	bytes;
 	__be16		lport;
 	__be16		fport;
-} __attribute__((packed));
+} __packed;
 
 #define RDS_INFO_MESSAGE_FLAG_ACK               0x01
 #define RDS_INFO_MESSAGE_FLAG_FAST_ACK          0x02
@@ -136,7 +136,7 @@
 	__be16		lport;
 	__be16		fport;
 	u_int8_t	flags;
-} __attribute__((packed));
+} __packed;
 
 struct rds_info_socket {
 	u_int32_t	sndbuf;
@@ -146,7 +146,7 @@
 	__be16		connected_port;
 	u_int32_t	rcvbuf;
 	u_int64_t	inum;
-} __attribute__((packed));
+} __packed;
 
 struct rds_info_tcp_socket {
 	__be32          local_addr;
@@ -158,7 +158,7 @@
 	u_int32_t       last_sent_nxt;
 	u_int32_t       last_expected_una;
 	u_int32_t       last_seen_una;
-} __attribute__((packed));
+} __packed;
 
 #define RDS_IB_GID_LEN	16
 struct rds_info_rdma_connection {
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index fbc8cb0..58d4449 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -282,6 +282,7 @@
 	RTA_SESSION, /* no longer used */
 	RTA_MP_ALGO, /* no longer used */
 	RTA_TABLE,
+	RTA_MARK,
 	__RTA_MAX
 };
 
diff --git a/include/linux/sctp.h b/include/linux/sctp.h
index c20d3ce..c11a287 100644
--- a/include/linux/sctp.h
+++ b/include/linux/sctp.h
@@ -61,7 +61,7 @@
 	__be16 dest;
 	__be32 vtag;
 	__le32 checksum;
-} __attribute__((packed)) sctp_sctphdr_t;
+} __packed sctp_sctphdr_t;
 
 #ifdef __KERNEL__
 #include <linux/skbuff.h>
@@ -77,7 +77,7 @@
 	__u8 type;
 	__u8 flags;
 	__be16 length;
-} __attribute__((packed)) sctp_chunkhdr_t;
+} __packed sctp_chunkhdr_t;
 
 
 /* Section 3.2.  Chunk Type Values.
@@ -167,7 +167,7 @@
 typedef struct sctp_paramhdr {
 	__be16 type;
 	__be16 length;
-} __attribute__((packed)) sctp_paramhdr_t;
+} __packed sctp_paramhdr_t;
 
 typedef enum {
 
@@ -228,12 +228,12 @@
 	__be16 ssn;
 	__be32 ppid;
 	__u8  payload[0];
-} __attribute__((packed)) sctp_datahdr_t;
+} __packed sctp_datahdr_t;
 
 typedef struct sctp_data_chunk {
         sctp_chunkhdr_t chunk_hdr;
         sctp_datahdr_t  data_hdr;
-} __attribute__((packed)) sctp_data_chunk_t;
+} __packed sctp_data_chunk_t;
 
 /* DATA Chuck Specific Flags */
 enum {
@@ -259,78 +259,78 @@
 	__be16 num_inbound_streams;
 	__be32 initial_tsn;
 	__u8  params[0];
-} __attribute__((packed)) sctp_inithdr_t;
+} __packed sctp_inithdr_t;
 
 typedef struct sctp_init_chunk {
 	sctp_chunkhdr_t chunk_hdr;
 	sctp_inithdr_t init_hdr;
-} __attribute__((packed)) sctp_init_chunk_t;
+} __packed sctp_init_chunk_t;
 
 
 /* Section 3.3.2.1. IPv4 Address Parameter (5) */
 typedef struct sctp_ipv4addr_param {
 	sctp_paramhdr_t param_hdr;
 	struct in_addr  addr;
-} __attribute__((packed)) sctp_ipv4addr_param_t;
+} __packed sctp_ipv4addr_param_t;
 
 /* Section 3.3.2.1. IPv6 Address Parameter (6) */
 typedef struct sctp_ipv6addr_param {
 	sctp_paramhdr_t param_hdr;
 	struct in6_addr addr;
-} __attribute__((packed)) sctp_ipv6addr_param_t;
+} __packed sctp_ipv6addr_param_t;
 
 /* Section 3.3.2.1 Cookie Preservative (9) */
 typedef struct sctp_cookie_preserve_param {
 	sctp_paramhdr_t param_hdr;
 	__be32          lifespan_increment;
-} __attribute__((packed)) sctp_cookie_preserve_param_t;
+} __packed sctp_cookie_preserve_param_t;
 
 /* Section 3.3.2.1 Host Name Address (11) */
 typedef struct sctp_hostname_param {
 	sctp_paramhdr_t param_hdr;
 	uint8_t hostname[0];
-} __attribute__((packed)) sctp_hostname_param_t;
+} __packed sctp_hostname_param_t;
 
 /* Section 3.3.2.1 Supported Address Types (12) */
 typedef struct sctp_supported_addrs_param {
 	sctp_paramhdr_t param_hdr;
 	__be16 types[0];
-} __attribute__((packed)) sctp_supported_addrs_param_t;
+} __packed sctp_supported_addrs_param_t;
 
 /* Appendix A. ECN Capable (32768) */
 typedef struct sctp_ecn_capable_param {
 	sctp_paramhdr_t param_hdr;
-} __attribute__((packed)) sctp_ecn_capable_param_t;
+} __packed sctp_ecn_capable_param_t;
 
 /* ADDIP Section 3.2.6 Adaptation Layer Indication */
 typedef struct sctp_adaptation_ind_param {
 	struct sctp_paramhdr param_hdr;
 	__be32 adaptation_ind;
-} __attribute__((packed)) sctp_adaptation_ind_param_t;
+} __packed sctp_adaptation_ind_param_t;
 
 /* ADDIP Section 4.2.7 Supported Extensions Parameter */
 typedef struct sctp_supported_ext_param {
 	struct sctp_paramhdr param_hdr;
 	__u8 chunks[0];
-} __attribute__((packed)) sctp_supported_ext_param_t;
+} __packed sctp_supported_ext_param_t;
 
 /* AUTH Section 3.1 Random */
 typedef struct sctp_random_param {
 	sctp_paramhdr_t param_hdr;
 	__u8 random_val[0];
-} __attribute__((packed)) sctp_random_param_t;
+} __packed sctp_random_param_t;
 
 /* AUTH Section 3.2 Chunk List */
 typedef struct sctp_chunks_param {
 	sctp_paramhdr_t param_hdr;
 	__u8 chunks[0];
-} __attribute__((packed)) sctp_chunks_param_t;
+} __packed sctp_chunks_param_t;
 
 /* AUTH Section 3.3 HMAC Algorithm */
 typedef struct sctp_hmac_algo_param {
 	sctp_paramhdr_t param_hdr;
 	__be16 hmac_ids[0];
-} __attribute__((packed)) sctp_hmac_algo_param_t;
+} __packed sctp_hmac_algo_param_t;
 
 /* RFC 2960.  Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2):
  *   The INIT ACK chunk is used to acknowledge the initiation of an SCTP
@@ -342,13 +342,13 @@
 typedef struct sctp_cookie_param {
 	sctp_paramhdr_t p;
 	__u8 body[0];
-} __attribute__((packed)) sctp_cookie_param_t;
+} __packed sctp_cookie_param_t;
 
 /* Section 3.3.3.1 Unrecognized Parameters (8) */
 typedef struct sctp_unrecognized_param {
 	sctp_paramhdr_t param_hdr;
 	sctp_paramhdr_t unrecognized;
-} __attribute__((packed)) sctp_unrecognized_param_t;
+} __packed sctp_unrecognized_param_t;
 
 
 
@@ -363,7 +363,7 @@
 typedef struct sctp_gap_ack_block {
 	__be16 start;
 	__be16 end;
-} __attribute__((packed)) sctp_gap_ack_block_t;
+} __packed sctp_gap_ack_block_t;
 
 typedef __be32 sctp_dup_tsn_t;
 
@@ -378,12 +378,12 @@
 	__be16 num_gap_ack_blocks;
 	__be16 num_dup_tsns;
 	sctp_sack_variable_t variable[0];
-} __attribute__((packed)) sctp_sackhdr_t;
+} __packed sctp_sackhdr_t;
 
 typedef struct sctp_sack_chunk {
 	sctp_chunkhdr_t chunk_hdr;
 	sctp_sackhdr_t sack_hdr;
-} __attribute__((packed)) sctp_sack_chunk_t;
+} __packed sctp_sack_chunk_t;
 
 
 /* RFC 2960.  Section 3.3.5 Heartbeat Request (HEARTBEAT) (4):
@@ -395,12 +395,12 @@
 
 typedef struct sctp_heartbeathdr {
 	sctp_paramhdr_t info;
-} __attribute__((packed)) sctp_heartbeathdr_t;
+} __packed sctp_heartbeathdr_t;
 
 typedef struct sctp_heartbeat_chunk {
 	sctp_chunkhdr_t chunk_hdr;
 	sctp_heartbeathdr_t hb_hdr;
-} __attribute__((packed)) sctp_heartbeat_chunk_t;
+} __packed sctp_heartbeat_chunk_t;
 
 
 /* For the abort and shutdown ACK we must carry the init tag in the
@@ -409,7 +409,7 @@
  */
 typedef struct sctp_abort_chunk {
         sctp_chunkhdr_t uh;
-} __attribute__((packed)) sctp_abort_chunk_t;
+} __packed sctp_abort_chunk_t;
 
 
 /* For the graceful shutdown we must carry the tag (in common header)
@@ -417,12 +417,12 @@
  */
 typedef struct sctp_shutdownhdr {
 	__be32 cum_tsn_ack;
-} __attribute__((packed)) sctp_shutdownhdr_t;
+} __packed sctp_shutdownhdr_t;
 
 struct sctp_shutdown_chunk_t {
         sctp_chunkhdr_t    chunk_hdr;
         sctp_shutdownhdr_t shutdown_hdr;
-} __attribute__ ((packed));
+} __packed;
 
 /* RFC 2960.  Section 3.3.10 Operation Error (ERROR) (9) */
 
@@ -430,12 +430,12 @@
 	__be16 cause;
 	__be16 length;
 	__u8  variable[0];
-} __attribute__((packed)) sctp_errhdr_t;
+} __packed sctp_errhdr_t;
 
 typedef struct sctp_operr_chunk {
         sctp_chunkhdr_t chunk_hdr;
 	sctp_errhdr_t   err_hdr;
-} __attribute__((packed)) sctp_operr_chunk_t;
+} __packed sctp_operr_chunk_t;
 
 /* RFC 2960 3.3.10 - Operation Error
  *
@@ -525,7 +525,7 @@
 typedef struct sctp_ecne_chunk {
 	sctp_chunkhdr_t chunk_hdr;
 	sctp_ecnehdr_t ence_hdr;
-} __attribute__((packed)) sctp_ecne_chunk_t;
+} __packed sctp_ecne_chunk_t;
 
 /* RFC 2960.  Appendix A.  Explicit Congestion Notification.
  *   Congestion Window Reduced (CWR) (13)
@@ -537,7 +537,7 @@
 typedef struct sctp_cwr_chunk {
 	sctp_chunkhdr_t chunk_hdr;
 	sctp_cwrhdr_t cwr_hdr;
-} __attribute__((packed)) sctp_cwr_chunk_t;
+} __packed sctp_cwr_chunk_t;
 
 /* PR-SCTP
  * 3.2 Forward Cumulative TSN Chunk Definition (FORWARD TSN)
@@ -588,17 +588,17 @@
 struct sctp_fwdtsn_skip {
 	__be16 stream;
 	__be16 ssn;
-} __attribute__((packed));
+} __packed;
 
 struct sctp_fwdtsn_hdr {
 	__be32 new_cum_tsn;
 	struct sctp_fwdtsn_skip skip[0];
-} __attribute((packed));
+} __packed;
 
 struct sctp_fwdtsn_chunk {
 	struct sctp_chunkhdr chunk_hdr;
 	struct sctp_fwdtsn_hdr fwdtsn_hdr;
-} __attribute((packed));
+} __packed;
 
 
 /* ADDIP
@@ -636,17 +636,17 @@
 typedef struct sctp_addip_param {
 	sctp_paramhdr_t	param_hdr;
 	__be32		crr_id;
-} __attribute__((packed)) sctp_addip_param_t;
+} __packed sctp_addip_param_t;
 
 typedef struct sctp_addiphdr {
 	__be32	serial;
 	__u8	params[0];
-} __attribute__((packed)) sctp_addiphdr_t;
+} __packed sctp_addiphdr_t;
 
 typedef struct sctp_addip_chunk {
 	sctp_chunkhdr_t chunk_hdr;
 	sctp_addiphdr_t addip_hdr;
-} __attribute__((packed)) sctp_addip_chunk_t;
+} __packed sctp_addip_chunk_t;
 
 /* AUTH
  * Section 4.1  Authentication Chunk (AUTH)
@@ -701,11 +701,11 @@
 	__be16 shkey_id;
 	__be16 hmac_id;
 	__u8   hmac[0];
-} __attribute__((packed)) sctp_authhdr_t;
+} __packed sctp_authhdr_t;
 
 typedef struct sctp_auth_chunk {
 	sctp_chunkhdr_t chunk_hdr;
 	sctp_authhdr_t auth_hdr;
-} __attribute__((packed)) sctp_auth_chunk_t;
+} __packed sctp_auth_chunk_t;
 
 #endif /* __LINUX_SCTP_H__ */
diff --git a/include/linux/security.h b/include/linux/security.h
index 0c88191..723a93d 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -470,8 +470,6 @@
  * @path_truncate:
  *	Check permission before truncating a file.
  *	@path contains the path structure for the file.
- *	@length is the new length of the file.
- *	@time_attrs is the flags passed to do_truncate().
  *	Return 0 if permission is granted.
  * @inode_getattr:
  *	Check permission before obtaining file attributes.
@@ -1412,8 +1410,7 @@
 	int (*path_rmdir) (struct path *dir, struct dentry *dentry);
 	int (*path_mknod) (struct path *dir, struct dentry *dentry, int mode,
 			   unsigned int dev);
-	int (*path_truncate) (struct path *path, loff_t length,
-			      unsigned int time_attrs);
+	int (*path_truncate) (struct path *path);
 	int (*path_symlink) (struct path *dir, struct dentry *dentry,
 			     const char *old_name);
 	int (*path_link) (struct dentry *old_dentry, struct path *new_dir,
@@ -2806,8 +2803,7 @@
 int security_path_rmdir(struct path *dir, struct dentry *dentry);
 int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
 			unsigned int dev);
-int security_path_truncate(struct path *path, loff_t length,
-			   unsigned int time_attrs);
+int security_path_truncate(struct path *path);
 int security_path_symlink(struct path *dir, struct dentry *dentry,
 			  const char *old_name);
 int security_path_link(struct dentry *old_dentry, struct path *new_dir,
@@ -2841,8 +2837,7 @@
 	return 0;
 }
 
-static inline int security_path_truncate(struct path *path, loff_t length,
-					 unsigned int time_attrs)
+static inline int security_path_truncate(struct path *path)
 {
 	return 0;
 }
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f89e7fd..d20d9e7 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -169,6 +169,7 @@
  * @software:		generate software time stamp
  * @in_progress:	device driver is going to provide
  *			hardware time stamp
+ * @prevent_sk_orphan:	make sk reference available on driver level
  * @flags:		all shared_tx flags
  *
  * These flags are attached to packets as part of the
@@ -178,7 +179,8 @@
 	struct {
 		__u8	hardware:1,
 			software:1,
-			in_progress:1;
+			in_progress:1,
+			prevent_sk_orphan:1;
 	};
 	__u8 flags;
 };
@@ -202,10 +204,11 @@
 	 */
 	atomic_t	dataref;
 
-	skb_frag_t	frags[MAX_SKB_FRAGS];
 	/* Intermediate layers must ensure that destructor_arg
 	 * remains valid until skb destructor */
 	void *		destructor_arg;
+	/* must be last field, see pskb_expand_head() */
+	skb_frag_t	frags[MAX_SKB_FRAGS];
 };
 
 /* We divide dataref into two halves.  The higher 16 bits hold references
@@ -1414,12 +1417,14 @@
  *
  * Various parts of the networking layer expect at least 32 bytes of
  * headroom, you should not reduce this.
- * With RPS, we raised NET_SKB_PAD to 64 so that get_rps_cpus() fetches span
- * a 64 bytes aligned block to fit modern (>= 64 bytes) cache line sizes
+ *
+ * Using max(32, L1_CACHE_BYTES) makes sense (especially with RPS)
+ * to reduce average number of cache lines per packet.
+ * get_rps_cpus() for example only access one 64 bytes aligned block :
  * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
  */
 #ifndef NET_SKB_PAD
-#define NET_SKB_PAD	64
+#define NET_SKB_PAD	max(32, L1_CACHE_BYTES)
 #endif
 
 extern int ___pskb_trim(struct sk_buff *skb, unsigned int len);
@@ -1931,6 +1936,36 @@
 	return ktime_set(0, 0);
 }
 
+extern void skb_timestamping_init(void);
+
+#ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
+
+extern void skb_clone_tx_timestamp(struct sk_buff *skb);
+extern bool skb_defer_rx_timestamp(struct sk_buff *skb);
+
+#else /* CONFIG_NETWORK_PHY_TIMESTAMPING */
+
+static inline void skb_clone_tx_timestamp(struct sk_buff *skb)
+{
+}
+
+static inline bool skb_defer_rx_timestamp(struct sk_buff *skb)
+{
+	return false;
+}
+
+#endif /* !CONFIG_NETWORK_PHY_TIMESTAMPING */
+
+/**
+ * skb_complete_tx_timestamp() - deliver cloned skb with tx timestamps
+ *
+ * @skb: clone of the the original outgoing packet
+ * @hwtstamps: hardware time stamps
+ *
+ */
+void skb_complete_tx_timestamp(struct sk_buff *skb,
+			       struct skb_shared_hwtstamps *hwtstamps);
+
 /**
  * skb_tstamp_tx - queue clone of skb with send time stamps
  * @orig_skb:	the original outgoing packet
@@ -1945,6 +1980,28 @@
 extern void skb_tstamp_tx(struct sk_buff *orig_skb,
 			struct skb_shared_hwtstamps *hwtstamps);
 
+static inline void sw_tx_timestamp(struct sk_buff *skb)
+{
+	union skb_shared_tx *shtx = skb_tx(skb);
+	if (shtx->software && !shtx->in_progress)
+		skb_tstamp_tx(skb, NULL);
+}
+
+/**
+ * skb_tx_timestamp() - Driver hook for transmit timestamping
+ *
+ * Ethernet MAC Drivers should call this function in their hard_xmit()
+ * function as soon as possible after giving the sk_buff to the MAC
+ * hardware, but before freeing the sk_buff.
+ *
+ * @skb: A socket buffer.
+ */
+static inline void skb_tx_timestamp(struct sk_buff *skb)
+{
+	skb_clone_tx_timestamp(skb);
+	sw_tx_timestamp(skb);
+}
+
 extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len);
 extern __sum16 __skb_checksum_complete(struct sk_buff *skb);
 
@@ -2132,7 +2189,8 @@
 	/* LRO sets gso_size but not gso_type, whereas if GSO is really
 	 * wanted then gso_type will be set. */
 	struct skb_shared_info *shinfo = skb_shinfo(skb);
-	if (shinfo->gso_size != 0 && unlikely(shinfo->gso_type == 0)) {
+	if (skb_is_nonlinear(skb) && shinfo->gso_size != 0 &&
+	    unlikely(shinfo->gso_type == 0)) {
 		__skb_warn_lro_forwarding(skb);
 		return true;
 	}
diff --git a/include/linux/snmp.h b/include/linux/snmp.h
index 5279771..ebb0c80 100644
--- a/include/linux/snmp.h
+++ b/include/linux/snmp.h
@@ -229,6 +229,7 @@
 	LINUX_MIB_TCPBACKLOGDROP,
 	LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */
 	LINUX_MIB_TCPDEFERACCEPTDROP,
+	LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
 	__LINUX_MIB_MAX
 };
 
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 032a19e..a2fada9 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -24,6 +24,9 @@
 #include <linux/types.h>		/* pid_t			*/
 #include <linux/compiler.h>		/* __user			*/
 
+struct pid;
+struct cred;
+
 #define __sockaddr_check_size(size)	\
 	BUILD_BUG_ON(((size) > sizeof(struct __kernel_sockaddr_storage)))
 
@@ -309,6 +312,8 @@
 #define IPX_TYPE	1
 
 #ifdef __KERNEL__
+extern void cred_to_ucred(struct pid *pid, const struct cred *cred, struct ucred *ucred);
+
 extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
 extern int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
 			       int offset, int len);
diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h
index b4ae570..92bd083 100644
--- a/include/linux/spi/ads7846.h
+++ b/include/linux/spi/ads7846.h
@@ -48,11 +48,12 @@
 					 * state if get_pendown_state == NULL
 					 */
 	int	(*get_pendown_state)(void);
-	int	(*filter_init)	(struct ads7846_platform_data *pdata,
+	int	(*filter_init)	(const struct ads7846_platform_data *pdata,
 				 void **filter_data);
 	int	(*filter)	(void *filter_data, int data_idx, int *val);
 	void	(*filter_cleanup)(void *filter_data);
 	void	(*wait_for_sync)(void);
 	bool	wakeup;
+	unsigned long irq_flags;
 };
 
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index a2608bf..623b704 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -167,7 +167,7 @@
 	 * is an optimization. */
 	const struct ssb_bus_ops *ops;
 
-	struct device *dev;
+	struct device *dev, *dma_dev;
 
 	struct ssb_bus *bus;
 	struct ssb_device_id id;
@@ -470,14 +470,6 @@
 #define SSB_DMA_TRANSLATION_MASK	0xC0000000
 #define SSB_DMA_TRANSLATION_SHIFT	30
 
-extern int ssb_dma_set_mask(struct ssb_device *dev, u64 mask);
-
-extern void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
-				       dma_addr_t *dma_handle, gfp_t gfp_flags);
-extern void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
-				    void *vaddr, dma_addr_t dma_handle,
-				    gfp_t gfp_flags);
-
 static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev)
 {
 #ifdef CONFIG_SSB_DEBUG
@@ -486,155 +478,6 @@
 #endif /* DEBUG */
 }
 
-static inline int ssb_dma_mapping_error(struct ssb_device *dev, dma_addr_t addr)
-{
-	switch (dev->bus->bustype) {
-	case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
-		return pci_dma_mapping_error(dev->bus->host_pci, addr);
-#endif
-		break;
-	case SSB_BUSTYPE_SSB:
-		return dma_mapping_error(dev->dev, addr);
-	default:
-		break;
-	}
-	__ssb_dma_not_implemented(dev);
-	return -ENOSYS;
-}
-
-static inline dma_addr_t ssb_dma_map_single(struct ssb_device *dev, void *p,
-					    size_t size, enum dma_data_direction dir)
-{
-	switch (dev->bus->bustype) {
-	case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
-		return pci_map_single(dev->bus->host_pci, p, size, dir);
-#endif
-		break;
-	case SSB_BUSTYPE_SSB:
-		return dma_map_single(dev->dev, p, size, dir);
-	default:
-		break;
-	}
-	__ssb_dma_not_implemented(dev);
-	return 0;
-}
-
-static inline void ssb_dma_unmap_single(struct ssb_device *dev, dma_addr_t dma_addr,
-					size_t size, enum dma_data_direction dir)
-{
-	switch (dev->bus->bustype) {
-	case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
-		pci_unmap_single(dev->bus->host_pci, dma_addr, size, dir);
-		return;
-#endif
-		break;
-	case SSB_BUSTYPE_SSB:
-		dma_unmap_single(dev->dev, dma_addr, size, dir);
-		return;
-	default:
-		break;
-	}
-	__ssb_dma_not_implemented(dev);
-}
-
-static inline void ssb_dma_sync_single_for_cpu(struct ssb_device *dev,
-					       dma_addr_t dma_addr,
-					       size_t size,
-					       enum dma_data_direction dir)
-{
-	switch (dev->bus->bustype) {
-	case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
-		pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
-					    size, dir);
-		return;
-#endif
-		break;
-	case SSB_BUSTYPE_SSB:
-		dma_sync_single_for_cpu(dev->dev, dma_addr, size, dir);
-		return;
-	default:
-		break;
-	}
-	__ssb_dma_not_implemented(dev);
-}
-
-static inline void ssb_dma_sync_single_for_device(struct ssb_device *dev,
-						  dma_addr_t dma_addr,
-						  size_t size,
-						  enum dma_data_direction dir)
-{
-	switch (dev->bus->bustype) {
-	case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
-		pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
-					       size, dir);
-		return;
-#endif
-		break;
-	case SSB_BUSTYPE_SSB:
-		dma_sync_single_for_device(dev->dev, dma_addr, size, dir);
-		return;
-	default:
-		break;
-	}
-	__ssb_dma_not_implemented(dev);
-}
-
-static inline void ssb_dma_sync_single_range_for_cpu(struct ssb_device *dev,
-						     dma_addr_t dma_addr,
-						     unsigned long offset,
-						     size_t size,
-						     enum dma_data_direction dir)
-{
-	switch (dev->bus->bustype) {
-	case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
-		/* Just sync everything. That's all the PCI API can do. */
-		pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
-					    offset + size, dir);
-		return;
-#endif
-		break;
-	case SSB_BUSTYPE_SSB:
-		dma_sync_single_range_for_cpu(dev->dev, dma_addr, offset,
-					      size, dir);
-		return;
-	default:
-		break;
-	}
-	__ssb_dma_not_implemented(dev);
-}
-
-static inline void ssb_dma_sync_single_range_for_device(struct ssb_device *dev,
-							dma_addr_t dma_addr,
-							unsigned long offset,
-							size_t size,
-							enum dma_data_direction dir)
-{
-	switch (dev->bus->bustype) {
-	case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
-		/* Just sync everything. That's all the PCI API can do. */
-		pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
-					       offset + size, dir);
-		return;
-#endif
-		break;
-	case SSB_BUSTYPE_SSB:
-		dma_sync_single_range_for_device(dev->dev, dma_addr, offset,
-						 size, dir);
-		return;
-	default:
-		break;
-	}
-	__ssb_dma_not_implemented(dev);
-}
-
-
 #ifdef CONFIG_SSB_PCIHOST
 /* PCI-host wrapper driver */
 extern int ssb_pcihost_register(struct pci_driver *driver);
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index bc7d6bb..4af270e 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -61,14 +61,15 @@
  *	before device drivers' late suspend callbacks are executed.  It returns
  *	0 on success or a negative error code otherwise, in which case the
  *	system cannot enter the desired sleep state (@prepare_late(), @enter(),
- *	@wake(), and @finish() will not be called in that case).
+ *	and @wake() will not be called in that case).
  *
  * @prepare_late: Finish preparing the platform for entering the system sleep
  *	state indicated by @begin().
  *	@prepare_late is called before disabling nonboot CPUs and after
  *	device drivers' late suspend callbacks have been executed.  It returns
  *	0 on success or a negative error code otherwise, in which case the
- *	system cannot enter the desired sleep state (@enter() and @wake()).
+ *	system cannot enter the desired sleep state (@enter() will not be
+ *	executed).
  *
  * @enter: Enter the system sleep state indicated by @begin() or represented by
  *	the argument if @begin() is not implemented.
@@ -81,14 +82,15 @@
  *	resume callbacks are executed.
  *	This callback is optional, but should be implemented by the platforms
  *	that implement @prepare_late().  If implemented, it is always called
- *	after @enter(), even if @enter() fails.
+ *	after @prepare_late and @enter(), even if one of them fails.
  *
  * @finish: Finish wake-up of the platform.
  *	@finish is called right prior to calling device drivers' regular suspend
  *	callbacks.
  *	This callback is optional, but should be implemented by the platforms
  *	that implement @prepare().  If implemented, it is always called after
- *	@enter() and @wake(), if implemented, even if any of them fails.
+ *	@enter() and @wake(), even if any of them fails.  It is executed after
+ *	a failing @prepare.
  *
  * @end: Called by the PM core right after resuming devices, to indicate to
  *	the platform that the system has returned to the working state or
@@ -286,6 +288,13 @@
 		{ .notifier_call = fn, .priority = pri };	\
 	register_pm_notifier(&fn##_nb);			\
 }
+
+/* drivers/base/power/wakeup.c */
+extern bool events_check_enabled;
+
+extern bool pm_check_wakeup_events(void);
+extern bool pm_get_wakeup_count(unsigned long *count);
+extern bool pm_save_wakeup_count(unsigned long count);
 #else /* !CONFIG_PM_SLEEP */
 
 static inline int register_pm_notifier(struct notifier_block *nb)
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
index 81a4e21..8c0e349 100644
--- a/include/linux/swiotlb.h
+++ b/include/linux/swiotlb.h
@@ -23,6 +23,29 @@
 #define IO_TLB_SHIFT 11
 
 extern void swiotlb_init(int verbose);
+extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose);
+
+/*
+ * Enumeration for sync targets
+ */
+enum dma_sync_target {
+	SYNC_FOR_CPU = 0,
+	SYNC_FOR_DEVICE = 1,
+};
+extern void *swiotlb_tbl_map_single(struct device *hwdev, dma_addr_t tbl_dma_addr,
+				    phys_addr_t phys, size_t size,
+				    enum dma_data_direction dir);
+
+extern void swiotlb_tbl_unmap_single(struct device *hwdev, char *dma_addr,
+				     size_t size, enum dma_data_direction dir);
+
+extern void swiotlb_tbl_sync_single(struct device *hwdev, char *dma_addr,
+				    size_t size, enum dma_data_direction dir,
+				    enum dma_sync_target target);
+
+/* Accessory functions. */
+extern void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
+			   enum dma_data_direction dir);
 
 extern void
 *swiotlb_alloc_coherent(struct device *hwdev, size_t size,
@@ -42,11 +65,11 @@
 
 extern int
 swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
-	       int direction);
+	       enum dma_data_direction dir);
 
 extern void
 swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
-		 int direction);
+		 enum dma_data_direction dir);
 
 extern int
 swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
diff --git a/include/linux/timer.h b/include/linux/timer.h
index ea965b8..38cf093 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -100,6 +100,13 @@
 		setup_timer_on_stack_key((timer), #timer, &__key,	\
 					 (fn), (data));			\
 	} while (0)
+#define setup_deferrable_timer_on_stack(timer, fn, data)		\
+	do {								\
+		static struct lock_class_key __key;			\
+		setup_deferrable_timer_on_stack_key((timer), #timer,	\
+						    &__key, (fn),	\
+						    (data));		\
+	} while (0)
 #else
 #define init_timer(timer)\
 	init_timer_key((timer), NULL, NULL)
@@ -111,6 +118,8 @@
 	setup_timer_key((timer), NULL, NULL, (fn), (data))
 #define setup_timer_on_stack(timer, fn, data)\
 	setup_timer_on_stack_key((timer), NULL, NULL, (fn), (data))
+#define setup_deferrable_timer_on_stack(timer, fn, data)\
+	setup_deferrable_timer_on_stack_key((timer), NULL, NULL, (fn), (data))
 #endif
 
 #ifdef CONFIG_DEBUG_OBJECTS_TIMERS
@@ -150,6 +159,12 @@
 	init_timer_on_stack_key(timer, name, key);
 }
 
+extern void setup_deferrable_timer_on_stack_key(struct timer_list *timer,
+						const char *name,
+						struct lock_class_key *key,
+						void (*function)(unsigned long),
+						unsigned long data);
+
 /**
  * timer_pending - is a timer pending?
  * @timer: the timer in question
diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h
new file mode 100644
index 0000000..fa261a0
--- /dev/null
+++ b/include/linux/u64_stats_sync.h
@@ -0,0 +1,140 @@
+#ifndef _LINUX_U64_STATS_SYNC_H
+#define _LINUX_U64_STATS_SYNC_H
+
+/*
+ * To properly implement 64bits network statistics on 32bit and 64bit hosts,
+ * we provide a synchronization point, that is a noop on 64bit or UP kernels.
+ *
+ * Key points :
+ * 1) Use a seqcount on SMP 32bits, with low overhead.
+ * 2) Whole thing is a noop on 64bit arches or UP kernels.
+ * 3) Write side must ensure mutual exclusion or one seqcount update could
+ *    be lost, thus blocking readers forever.
+ *    If this synchronization point is not a mutex, but a spinlock or
+ *    spinlock_bh() or disable_bh() :
+ * 3.1) Write side should not sleep.
+ * 3.2) Write side should not allow preemption.
+ * 3.3) If applicable, interrupts should be disabled.
+ *
+ * 4) If reader fetches several counters, there is no guarantee the whole values
+ *    are consistent (remember point 1) : this is a noop on 64bit arches anyway)
+ *
+ * 5) readers are allowed to sleep or be preempted/interrupted : They perform
+ *    pure reads. But if they have to fetch many values, it's better to not allow
+ *    preemptions/interruptions to avoid many retries.
+ *
+ * 6) If counter might be written by an interrupt, readers should block interrupts.
+ *    (On UP, there is no seqcount_t protection, a reader allowing interrupts could
+ *     read partial values)
+ *
+ * 7) For softirq uses, readers can use u64_stats_fetch_begin_bh() and
+ *    u64_stats_fetch_retry_bh() helpers
+ *
+ * Usage :
+ *
+ * Stats producer (writer) should use following template granted it already got
+ * an exclusive access to counters (a lock is already taken, or per cpu
+ * data is used [in a non preemptable context])
+ *
+ *   spin_lock_bh(...) or other synchronization to get exclusive access
+ *   ...
+ *   u64_stats_update_begin(&stats->syncp);
+ *   stats->bytes64 += len; // non atomic operation
+ *   stats->packets64++;    // non atomic operation
+ *   u64_stats_update_end(&stats->syncp);
+ *
+ * While a consumer (reader) should use following template to get consistent
+ * snapshot for each variable (but no guarantee on several ones)
+ *
+ * u64 tbytes, tpackets;
+ * unsigned int start;
+ *
+ * do {
+ *         start = u64_stats_fetch_begin(&stats->syncp);
+ *         tbytes = stats->bytes64; // non atomic operation
+ *         tpackets = stats->packets64; // non atomic operation
+ * } while (u64_stats_fetch_retry(&stats->syncp, start));
+ *
+ *
+ * Example of use in drivers/net/loopback.c, using per_cpu containers,
+ * in BH disabled context.
+ */
+#include <linux/seqlock.h>
+
+struct u64_stats_sync {
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+	seqcount_t	seq;
+#endif
+};
+
+static void inline u64_stats_update_begin(struct u64_stats_sync *syncp)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+	write_seqcount_begin(&syncp->seq);
+#endif
+}
+
+static void inline u64_stats_update_end(struct u64_stats_sync *syncp)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+	write_seqcount_end(&syncp->seq);
+#endif
+}
+
+static unsigned int inline u64_stats_fetch_begin(const struct u64_stats_sync *syncp)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+	return read_seqcount_begin(&syncp->seq);
+#else
+#if BITS_PER_LONG==32
+	preempt_disable();
+#endif
+	return 0;
+#endif
+}
+
+static bool inline u64_stats_fetch_retry(const struct u64_stats_sync *syncp,
+					 unsigned int start)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+	return read_seqcount_retry(&syncp->seq, start);
+#else
+#if BITS_PER_LONG==32
+	preempt_enable();
+#endif
+	return false;
+#endif
+}
+
+/*
+ * In case softirq handlers can update u64 counters, readers can use following helpers
+ * - SMP 32bit arches use seqcount protection, irq safe.
+ * - UP 32bit must disable BH.
+ * - 64bit have no problem atomically reading u64 values, irq safe.
+ */
+static unsigned int inline u64_stats_fetch_begin_bh(const struct u64_stats_sync *syncp)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+	return read_seqcount_begin(&syncp->seq);
+#else
+#if BITS_PER_LONG==32
+	local_bh_disable();
+#endif
+	return 0;
+#endif
+}
+
+static bool inline u64_stats_fetch_retry_bh(const struct u64_stats_sync *syncp,
+					 unsigned int start)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+	return read_seqcount_retry(&syncp->seq, start);
+#else
+#if BITS_PER_LONG==32
+	local_bh_enable();
+#endif
+	return false;
+#endif
+}
+
+#endif /* _LINUX_U64_STATS_SYNC_H */
diff --git a/include/linux/usb/video.h b/include/linux/usb/video.h
index be436d9..3b3b95e 100644
--- a/include/linux/usb/video.h
+++ b/include/linux/usb/video.h
@@ -160,5 +160,409 @@
 #define UVC_STATUS_TYPE_CONTROL				1
 #define UVC_STATUS_TYPE_STREAMING			2
 
+/* 2.4.3.3. Payload Header Information */
+#define UVC_STREAM_EOH					(1 << 7)
+#define UVC_STREAM_ERR					(1 << 6)
+#define UVC_STREAM_STI					(1 << 5)
+#define UVC_STREAM_RES					(1 << 4)
+#define UVC_STREAM_SCR					(1 << 3)
+#define UVC_STREAM_PTS					(1 << 2)
+#define UVC_STREAM_EOF					(1 << 1)
+#define UVC_STREAM_FID					(1 << 0)
+
+/* 4.1.2. Control Capabilities */
+#define UVC_CONTROL_CAP_GET				(1 << 0)
+#define UVC_CONTROL_CAP_SET				(1 << 1)
+#define UVC_CONTROL_CAP_DISABLED			(1 << 2)
+#define UVC_CONTROL_CAP_AUTOUPDATE			(1 << 3)
+#define UVC_CONTROL_CAP_ASYNCHRONOUS			(1 << 4)
+
+/* ------------------------------------------------------------------------
+ * UVC structures
+ */
+
+/* All UVC descriptors have these 3 fields at the beginning */
+struct uvc_descriptor_header {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+} __attribute__((packed));
+
+/* 3.7.2. Video Control Interface Header Descriptor */
+struct uvc_header_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u16 bcdUVC;
+	__u16 wTotalLength;
+	__u32 dwClockFrequency;
+	__u8  bInCollection;
+	__u8  baInterfaceNr[];
+} __attribute__((__packed__));
+
+#define UVC_DT_HEADER_SIZE(n)				(12+(n))
+
+#define UVC_HEADER_DESCRIPTOR(n) \
+	uvc_header_descriptor_##n
+
+#define DECLARE_UVC_HEADER_DESCRIPTOR(n)		\
+struct UVC_HEADER_DESCRIPTOR(n) {			\
+	__u8  bLength;					\
+	__u8  bDescriptorType;				\
+	__u8  bDescriptorSubType;			\
+	__u16 bcdUVC;					\
+	__u16 wTotalLength;				\
+	__u32 dwClockFrequency;				\
+	__u8  bInCollection;				\
+	__u8  baInterfaceNr[n];				\
+} __attribute__ ((packed))
+
+/* 3.7.2.1. Input Terminal Descriptor */
+struct uvc_input_terminal_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bTerminalID;
+	__u16 wTerminalType;
+	__u8  bAssocTerminal;
+	__u8  iTerminal;
+} __attribute__((__packed__));
+
+#define UVC_DT_INPUT_TERMINAL_SIZE			8
+
+/* 3.7.2.2. Output Terminal Descriptor */
+struct uvc_output_terminal_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bTerminalID;
+	__u16 wTerminalType;
+	__u8  bAssocTerminal;
+	__u8  bSourceID;
+	__u8  iTerminal;
+} __attribute__((__packed__));
+
+#define UVC_DT_OUTPUT_TERMINAL_SIZE			9
+
+/* 3.7.2.3. Camera Terminal Descriptor */
+struct uvc_camera_terminal_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bTerminalID;
+	__u16 wTerminalType;
+	__u8  bAssocTerminal;
+	__u8  iTerminal;
+	__u16 wObjectiveFocalLengthMin;
+	__u16 wObjectiveFocalLengthMax;
+	__u16 wOcularFocalLength;
+	__u8  bControlSize;
+	__u8  bmControls[3];
+} __attribute__((__packed__));
+
+#define UVC_DT_CAMERA_TERMINAL_SIZE(n)			(15+(n))
+
+/* 3.7.2.4. Selector Unit Descriptor */
+struct uvc_selector_unit_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bUnitID;
+	__u8  bNrInPins;
+	__u8  baSourceID[0];
+	__u8  iSelector;
+} __attribute__((__packed__));
+
+#define UVC_DT_SELECTOR_UNIT_SIZE(n)			(6+(n))
+
+#define UVC_SELECTOR_UNIT_DESCRIPTOR(n)	\
+	uvc_selector_unit_descriptor_##n
+
+#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n)	\
+struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) {		\
+	__u8  bLength;					\
+	__u8  bDescriptorType;				\
+	__u8  bDescriptorSubType;			\
+	__u8  bUnitID;					\
+	__u8  bNrInPins;				\
+	__u8  baSourceID[n];				\
+	__u8  iSelector;				\
+} __attribute__ ((packed))
+
+/* 3.7.2.5. Processing Unit Descriptor */
+struct uvc_processing_unit_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bUnitID;
+	__u8  bSourceID;
+	__u16 wMaxMultiplier;
+	__u8  bControlSize;
+	__u8  bmControls[2];
+	__u8  iProcessing;
+} __attribute__((__packed__));
+
+#define UVC_DT_PROCESSING_UNIT_SIZE(n)			(9+(n))
+
+/* 3.7.2.6. Extension Unit Descriptor */
+struct uvc_extension_unit_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bUnitID;
+	__u8  guidExtensionCode[16];
+	__u8  bNumControls;
+	__u8  bNrInPins;
+	__u8  baSourceID[0];
+	__u8  bControlSize;
+	__u8  bmControls[0];
+	__u8  iExtension;
+} __attribute__((__packed__));
+
+#define UVC_DT_EXTENSION_UNIT_SIZE(p, n)		(24+(p)+(n))
+
+#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
+	uvc_extension_unit_descriptor_##p_##n
+
+#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n)	\
+struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) {		\
+	__u8  bLength;					\
+	__u8  bDescriptorType;				\
+	__u8  bDescriptorSubType;			\
+	__u8  bUnitID;					\
+	__u8  guidExtensionCode[16];			\
+	__u8  bNumControls;				\
+	__u8  bNrInPins;				\
+	__u8  baSourceID[p];				\
+	__u8  bControlSize;				\
+	__u8  bmControls[n];				\
+	__u8  iExtension;				\
+} __attribute__ ((packed))
+
+/* 3.8.2.2. Video Control Interrupt Endpoint Descriptor */
+struct uvc_control_endpoint_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u16 wMaxTransferSize;
+} __attribute__((__packed__));
+
+#define UVC_DT_CONTROL_ENDPOINT_SIZE			5
+
+/* 3.9.2.1. Input Header Descriptor */
+struct uvc_input_header_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bNumFormats;
+	__u16 wTotalLength;
+	__u8  bEndpointAddress;
+	__u8  bmInfo;
+	__u8  bTerminalLink;
+	__u8  bStillCaptureMethod;
+	__u8  bTriggerSupport;
+	__u8  bTriggerUsage;
+	__u8  bControlSize;
+	__u8  bmaControls[];
+} __attribute__((__packed__));
+
+#define UVC_DT_INPUT_HEADER_SIZE(n, p)			(13+(n*p))
+
+#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
+	uvc_input_header_descriptor_##n_##p
+
+#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p)	\
+struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) {		\
+	__u8  bLength;					\
+	__u8  bDescriptorType;				\
+	__u8  bDescriptorSubType;			\
+	__u8  bNumFormats;				\
+	__u16 wTotalLength;				\
+	__u8  bEndpointAddress;				\
+	__u8  bmInfo;					\
+	__u8  bTerminalLink;				\
+	__u8  bStillCaptureMethod;			\
+	__u8  bTriggerSupport;				\
+	__u8  bTriggerUsage;				\
+	__u8  bControlSize;				\
+	__u8  bmaControls[p][n];			\
+} __attribute__ ((packed))
+
+/* 3.9.2.2. Output Header Descriptor */
+struct uvc_output_header_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bNumFormats;
+	__u16 wTotalLength;
+	__u8  bEndpointAddress;
+	__u8  bTerminalLink;
+	__u8  bControlSize;
+	__u8  bmaControls[];
+} __attribute__((__packed__));
+
+#define UVC_DT_OUTPUT_HEADER_SIZE(n, p)			(9+(n*p))
+
+#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
+	uvc_output_header_descriptor_##n_##p
+
+#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p)	\
+struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) {		\
+	__u8  bLength;					\
+	__u8  bDescriptorType;				\
+	__u8  bDescriptorSubType;			\
+	__u8  bNumFormats;				\
+	__u16 wTotalLength;				\
+	__u8  bEndpointAddress;				\
+	__u8  bTerminalLink;				\
+	__u8  bControlSize;				\
+	__u8  bmaControls[p][n];			\
+} __attribute__ ((packed))
+
+/* 3.9.2.6. Color matching descriptor */
+struct uvc_color_matching_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bColorPrimaries;
+	__u8  bTransferCharacteristics;
+	__u8  bMatrixCoefficients;
+} __attribute__((__packed__));
+
+#define UVC_DT_COLOR_MATCHING_SIZE			6
+
+/* 4.3.1.1. Video Probe and Commit Controls */
+struct uvc_streaming_control {
+	__u16 bmHint;
+	__u8  bFormatIndex;
+	__u8  bFrameIndex;
+	__u32 dwFrameInterval;
+	__u16 wKeyFrameRate;
+	__u16 wPFrameRate;
+	__u16 wCompQuality;
+	__u16 wCompWindowSize;
+	__u16 wDelay;
+	__u32 dwMaxVideoFrameSize;
+	__u32 dwMaxPayloadTransferSize;
+	__u32 dwClockFrequency;
+	__u8  bmFramingInfo;
+	__u8  bPreferedVersion;
+	__u8  bMinVersion;
+	__u8  bMaxVersion;
+} __attribute__((__packed__));
+
+/* Uncompressed Payload - 3.1.1. Uncompressed Video Format Descriptor */
+struct uvc_format_uncompressed {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bFormatIndex;
+	__u8  bNumFrameDescriptors;
+	__u8  guidFormat[16];
+	__u8  bBitsPerPixel;
+	__u8  bDefaultFrameIndex;
+	__u8  bAspectRatioX;
+	__u8  bAspectRatioY;
+	__u8  bmInterfaceFlags;
+	__u8  bCopyProtect;
+} __attribute__((__packed__));
+
+#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE			27
+
+/* Uncompressed Payload - 3.1.2. Uncompressed Video Frame Descriptor */
+struct uvc_frame_uncompressed {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bFrameIndex;
+	__u8  bmCapabilities;
+	__u16 wWidth;
+	__u16 wHeight;
+	__u32 dwMinBitRate;
+	__u32 dwMaxBitRate;
+	__u32 dwMaxVideoFrameBufferSize;
+	__u32 dwDefaultFrameInterval;
+	__u8  bFrameIntervalType;
+	__u32 dwFrameInterval[];
+} __attribute__((__packed__));
+
+#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n)		(26+4*(n))
+
+#define UVC_FRAME_UNCOMPRESSED(n) \
+	uvc_frame_uncompressed_##n
+
+#define DECLARE_UVC_FRAME_UNCOMPRESSED(n)		\
+struct UVC_FRAME_UNCOMPRESSED(n) {			\
+	__u8  bLength;					\
+	__u8  bDescriptorType;				\
+	__u8  bDescriptorSubType;			\
+	__u8  bFrameIndex;				\
+	__u8  bmCapabilities;				\
+	__u16 wWidth;					\
+	__u16 wHeight;					\
+	__u32 dwMinBitRate;				\
+	__u32 dwMaxBitRate;				\
+	__u32 dwMaxVideoFrameBufferSize;		\
+	__u32 dwDefaultFrameInterval;			\
+	__u8  bFrameIntervalType;			\
+	__u32 dwFrameInterval[n];			\
+} __attribute__ ((packed))
+
+/* MJPEG Payload - 3.1.1. MJPEG Video Format Descriptor */
+struct uvc_format_mjpeg {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bFormatIndex;
+	__u8  bNumFrameDescriptors;
+	__u8  bmFlags;
+	__u8  bDefaultFrameIndex;
+	__u8  bAspectRatioX;
+	__u8  bAspectRatioY;
+	__u8  bmInterfaceFlags;
+	__u8  bCopyProtect;
+} __attribute__((__packed__));
+
+#define UVC_DT_FORMAT_MJPEG_SIZE			11
+
+/* MJPEG Payload - 3.1.2. MJPEG Video Frame Descriptor */
+struct uvc_frame_mjpeg {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bFrameIndex;
+	__u8  bmCapabilities;
+	__u16 wWidth;
+	__u16 wHeight;
+	__u32 dwMinBitRate;
+	__u32 dwMaxBitRate;
+	__u32 dwMaxVideoFrameBufferSize;
+	__u32 dwDefaultFrameInterval;
+	__u8  bFrameIntervalType;
+	__u32 dwFrameInterval[];
+} __attribute__((__packed__));
+
+#define UVC_DT_FRAME_MJPEG_SIZE(n)			(26+4*(n))
+
+#define UVC_FRAME_MJPEG(n) \
+	uvc_frame_mjpeg_##n
+
+#define DECLARE_UVC_FRAME_MJPEG(n)			\
+struct UVC_FRAME_MJPEG(n) {				\
+	__u8  bLength;					\
+	__u8  bDescriptorType;				\
+	__u8  bDescriptorSubType;			\
+	__u8  bFrameIndex;				\
+	__u8  bmCapabilities;				\
+	__u16 wWidth;					\
+	__u16 wHeight;					\
+	__u32 dwMinBitRate;				\
+	__u32 dwMaxBitRate;				\
+	__u32 dwMaxVideoFrameBufferSize;		\
+	__u32 dwDefaultFrameInterval;			\
+	__u8  bFrameIntervalType;			\
+	__u32 dwFrameInterval[n];			\
+} __attribute__ ((packed))
+
 #endif /* __LINUX_USB_VIDEO_H */
 
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index cc4f453..8178156 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -36,6 +36,9 @@
 		kref_put(&ns->kref, free_user_ns);
 }
 
+uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid);
+gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid);
+
 #else
 
 static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
@@ -52,6 +55,17 @@
 {
 }
 
+static inline uid_t user_ns_map_uid(struct user_namespace *to,
+	const struct cred *cred, uid_t uid)
+{
+	return uid;
+}
+static inline gid_t user_ns_map_gid(struct user_namespace *to,
+	const struct cred *cred, gid_t gid)
+{
+	return gid;
+}
+
 #endif
 
 #endif /* _LINUX_USER_H */
diff --git a/include/linux/wlp.h b/include/linux/wlp.h
index ac95ce6..c76fe23 100644
--- a/include/linux/wlp.h
+++ b/include/linux/wlp.h
@@ -300,7 +300,7 @@
 	__le16 cycle_param;
 	__le16 acw_anchor_addr;
 	u8 wssid_hash_list[];
-} __attribute__((packed));
+} __packed;
 
 static inline int wlp_ie_hash_length(struct wlp_ie *ie)
 {
@@ -324,7 +324,7 @@
  */
 struct wlp_nonce {
 	u8 data[16];
-} __attribute__((packed));
+} __packed;
 
 /**
  * WLP UUID
@@ -336,7 +336,7 @@
  */
 struct wlp_uuid {
 	u8 data[16];
-} __attribute__((packed));
+} __packed;
 
 
 /**
@@ -348,7 +348,7 @@
 	u8 OUI[3];
 	u8 OUIsubdiv;
 	__le16 subID;
-} __attribute__((packed));
+} __packed;
 
 /**
  * WLP frame header
@@ -357,7 +357,7 @@
 struct wlp_frame_hdr {
 	__le16 mux_hdr;			/* WLP_PROTOCOL_ID */
 	enum wlp_frame_type type:8;
-} __attribute__((packed));
+} __packed;
 
 /**
  * WLP attribute field header
@@ -368,7 +368,7 @@
 struct wlp_attr_hdr {
 	__le16 type;
 	__le16 length;
-} __attribute__((packed));
+} __packed;
 
 /**
  * Device information commonly used together
@@ -401,13 +401,13 @@
 struct wlp_attr_##name {						\
 	struct wlp_attr_hdr hdr;					\
 	type name;							\
-} __attribute__((packed));
+} __packed;
 
 #define wlp_attr_array(type, name)					\
 struct wlp_attr_##name {						\
 	struct wlp_attr_hdr hdr;					\
 	type name[];							\
-} __attribute__((packed));
+} __packed;
 
 /**
  * WLP association attribute fields
@@ -483,7 +483,7 @@
 	struct wlp_attr_accept_enrl accept;
 	struct wlp_attr_wss_sec_status sec_stat;
 	struct wlp_attr_wss_bcast bcast;
-} __attribute__((packed));
+} __packed;
 
 /* WLP WSS Information */
 wlp_attr_array(struct wlp_wss_info, wss_info)
@@ -520,7 +520,7 @@
 struct wlp_frame_std_abbrv_hdr {
 	struct wlp_frame_hdr hdr;
 	u8 tag;
-} __attribute__((packed));
+} __packed;
 
 /**
  * WLP association frames
@@ -533,7 +533,7 @@
 	struct wlp_attr_version version;
 	struct wlp_attr_msg_type msg_type;
 	u8 attr[];
-} __attribute__((packed));
+} __packed;
 
 /* Ethernet to dev address mapping */
 struct wlp_eda {
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index 0cfa1e9..f1e5bde 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -33,6 +33,20 @@
 #define XATTR_USER_PREFIX "user."
 #define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
 
+/* Security namespace */
+#define XATTR_SELINUX_SUFFIX "selinux"
+#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
+
+#define XATTR_SMACK_SUFFIX "SMACK64"
+#define XATTR_SMACK_IPIN "SMACK64IPIN"
+#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
+#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
+#define XATTR_NAME_SMACKIPIN	XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
+#define XATTR_NAME_SMACKIPOUT	XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
+
+#define XATTR_CAPS_SUFFIX "capability"
+#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
+
 struct inode;
 struct dentry;
 
diff --git a/include/media/ir-core.h b/include/media/ir-core.h
index ad1303f..513e60d 100644
--- a/include/media/ir-core.h
+++ b/include/media/ir-core.h
@@ -47,15 +47,21 @@
  *	is opened.
  * @close: callback to allow drivers to disable polling/irq when IR input device
  *	is opened.
+ * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs)
+ * @s_tx_carrier: set transmit carrier frequency
+ * @tx_ir: transmit IR
  */
 struct ir_dev_props {
 	enum rc_driver_type	driver_type;
 	unsigned long		allowed_protos;
 	u32			scanmask;
-	void 			*priv;
+	void			*priv;
 	int			(*change_protocol)(void *priv, u64 ir_type);
 	int			(*open)(void *priv);
 	void			(*close)(void *priv);
+	int			(*s_tx_mask)(void *priv, u32 mask);
+	int			(*s_tx_carrier)(void *priv, u32 carrier);
+	int			(*tx_ir)(void *priv, int *txbuf, u32 n);
 };
 
 struct ir_input_dev {
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
index 0506e45..5e96d7a 100644
--- a/include/media/ir-kbd-i2c.h
+++ b/include/media/ir-kbd-i2c.h
@@ -11,7 +11,7 @@
 	struct i2c_client      *c;
 	struct input_dev       *input;
 	struct ir_input_state  ir;
-
+	u64                    ir_type;
 	/* Used to avoid fast repeating */
 	unsigned char          old;
 
diff --git a/include/media/lirc.h b/include/media/lirc.h
new file mode 100644
index 0000000..42c467c
--- /dev/null
+++ b/include/media/lirc.h
@@ -0,0 +1,165 @@
+/*
+ * lirc.h - linux infrared remote control header file
+ * last modified 2010/07/13 by Jarod Wilson
+ */
+
+#ifndef _LINUX_LIRC_H
+#define _LINUX_LIRC_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define PULSE_BIT       0x01000000
+#define PULSE_MASK      0x00FFFFFF
+
+#define LIRC_MODE2_SPACE     0x00000000
+#define LIRC_MODE2_PULSE     0x01000000
+#define LIRC_MODE2_FREQUENCY 0x02000000
+#define LIRC_MODE2_TIMEOUT   0x03000000
+
+#define LIRC_VALUE_MASK      0x00FFFFFF
+#define LIRC_MODE2_MASK      0xFF000000
+
+#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE)
+#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE)
+#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY)
+#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT)
+
+#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK)
+#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK)
+
+#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE)
+#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE)
+#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY)
+#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT)
+
+/* used heavily by lirc userspace */
+#define lirc_t int
+
+/*** lirc compatible hardware features ***/
+
+#define LIRC_MODE2SEND(x) (x)
+#define LIRC_SEND2MODE(x) (x)
+#define LIRC_MODE2REC(x) ((x) << 16)
+#define LIRC_REC2MODE(x) ((x) >> 16)
+
+#define LIRC_MODE_RAW                  0x00000001
+#define LIRC_MODE_PULSE                0x00000002
+#define LIRC_MODE_MODE2                0x00000004
+#define LIRC_MODE_LIRCCODE             0x00000010
+
+
+#define LIRC_CAN_SEND_RAW              LIRC_MODE2SEND(LIRC_MODE_RAW)
+#define LIRC_CAN_SEND_PULSE            LIRC_MODE2SEND(LIRC_MODE_PULSE)
+#define LIRC_CAN_SEND_MODE2            LIRC_MODE2SEND(LIRC_MODE_MODE2)
+#define LIRC_CAN_SEND_LIRCCODE         LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)
+
+#define LIRC_CAN_SEND_MASK             0x0000003f
+
+#define LIRC_CAN_SET_SEND_CARRIER      0x00000100
+#define LIRC_CAN_SET_SEND_DUTY_CYCLE   0x00000200
+#define LIRC_CAN_SET_TRANSMITTER_MASK  0x00000400
+
+#define LIRC_CAN_REC_RAW               LIRC_MODE2REC(LIRC_MODE_RAW)
+#define LIRC_CAN_REC_PULSE             LIRC_MODE2REC(LIRC_MODE_PULSE)
+#define LIRC_CAN_REC_MODE2             LIRC_MODE2REC(LIRC_MODE_MODE2)
+#define LIRC_CAN_REC_LIRCCODE          LIRC_MODE2REC(LIRC_MODE_LIRCCODE)
+
+#define LIRC_CAN_REC_MASK              LIRC_MODE2REC(LIRC_CAN_SEND_MASK)
+
+#define LIRC_CAN_SET_REC_CARRIER       (LIRC_CAN_SET_SEND_CARRIER << 16)
+#define LIRC_CAN_SET_REC_DUTY_CYCLE    (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16)
+
+#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000
+#define LIRC_CAN_SET_REC_CARRIER_RANGE    0x80000000
+#define LIRC_CAN_GET_REC_RESOLUTION       0x20000000
+#define LIRC_CAN_SET_REC_TIMEOUT          0x10000000
+#define LIRC_CAN_SET_REC_FILTER           0x08000000
+
+#define LIRC_CAN_MEASURE_CARRIER          0x02000000
+
+#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK)
+#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK)
+
+#define LIRC_CAN_NOTIFY_DECODE            0x01000000
+
+/*** IOCTL commands for lirc driver ***/
+
+#define LIRC_GET_FEATURES              _IOR('i', 0x00000000, __u32)
+
+#define LIRC_GET_SEND_MODE             _IOR('i', 0x00000001, __u32)
+#define LIRC_GET_REC_MODE              _IOR('i', 0x00000002, __u32)
+#define LIRC_GET_SEND_CARRIER          _IOR('i', 0x00000003, __u32)
+#define LIRC_GET_REC_CARRIER           _IOR('i', 0x00000004, __u32)
+#define LIRC_GET_SEND_DUTY_CYCLE       _IOR('i', 0x00000005, __u32)
+#define LIRC_GET_REC_DUTY_CYCLE        _IOR('i', 0x00000006, __u32)
+#define LIRC_GET_REC_RESOLUTION        _IOR('i', 0x00000007, __u32)
+
+#define LIRC_GET_MIN_TIMEOUT           _IOR('i', 0x00000008, __u32)
+#define LIRC_GET_MAX_TIMEOUT           _IOR('i', 0x00000009, __u32)
+
+#define LIRC_GET_MIN_FILTER_PULSE      _IOR('i', 0x0000000a, __u32)
+#define LIRC_GET_MAX_FILTER_PULSE      _IOR('i', 0x0000000b, __u32)
+#define LIRC_GET_MIN_FILTER_SPACE      _IOR('i', 0x0000000c, __u32)
+#define LIRC_GET_MAX_FILTER_SPACE      _IOR('i', 0x0000000d, __u32)
+
+/* code length in bits, currently only for LIRC_MODE_LIRCCODE */
+#define LIRC_GET_LENGTH                _IOR('i', 0x0000000f, __u32)
+
+#define LIRC_SET_SEND_MODE             _IOW('i', 0x00000011, __u32)
+#define LIRC_SET_REC_MODE              _IOW('i', 0x00000012, __u32)
+/* Note: these can reset the according pulse_width */
+#define LIRC_SET_SEND_CARRIER          _IOW('i', 0x00000013, __u32)
+#define LIRC_SET_REC_CARRIER           _IOW('i', 0x00000014, __u32)
+#define LIRC_SET_SEND_DUTY_CYCLE       _IOW('i', 0x00000015, __u32)
+#define LIRC_SET_REC_DUTY_CYCLE        _IOW('i', 0x00000016, __u32)
+#define LIRC_SET_TRANSMITTER_MASK      _IOW('i', 0x00000017, __u32)
+
+/*
+ * when a timeout != 0 is set the driver will send a
+ * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is
+ * never sent, timeout is disabled by default
+ */
+#define LIRC_SET_REC_TIMEOUT           _IOW('i', 0x00000018, __u32)
+
+/* 1 enables, 0 disables timeout reports in MODE2 */
+#define LIRC_SET_REC_TIMEOUT_REPORTS   _IOW('i', 0x00000019, __u32)
+
+/*
+ * pulses shorter than this are filtered out by hardware (software
+ * emulation in lirc_dev?)
+ */
+#define LIRC_SET_REC_FILTER_PULSE      _IOW('i', 0x0000001a, __u32)
+/*
+ * spaces shorter than this are filtered out by hardware (software
+ * emulation in lirc_dev?)
+ */
+#define LIRC_SET_REC_FILTER_SPACE      _IOW('i', 0x0000001b, __u32)
+/*
+ * if filter cannot be set independantly for pulse/space, this should
+ * be used
+ */
+#define LIRC_SET_REC_FILTER            _IOW('i', 0x0000001c, __u32)
+
+/*
+ * if enabled from the next key press on the driver will send
+ * LIRC_MODE2_FREQUENCY packets
+ */
+#define LIRC_SET_MEASURE_CARRIER_MODE  _IOW('i', 0x0000001d, __u32)
+
+/*
+ * to set a range use
+ * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the
+ * lower bound first and later
+ * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound
+ */
+
+#define LIRC_SET_REC_DUTY_CYCLE_RANGE  _IOW('i', 0x0000001e, __u32)
+#define LIRC_SET_REC_CARRIER_RANGE     _IOW('i', 0x0000001f, __u32)
+
+#define LIRC_NOTIFY_DECODE             _IO('i', 0x00000020)
+
+#define LIRC_SETUP_START               _IO('i', 0x00000021)
+#define LIRC_SETUP_END                 _IO('i', 0x00000022)
+
+#endif
diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h
new file mode 100644
index 0000000..b1f6066
--- /dev/null
+++ b/include/media/lirc_dev.h
@@ -0,0 +1,225 @@
+/*
+ * LIRC base driver
+ *
+ * by Artur Lipowski <alipowski@interia.pl>
+ *        This code is licensed under GNU GPL
+ *
+ */
+
+#ifndef _LINUX_LIRC_DEV_H
+#define _LINUX_LIRC_DEV_H
+
+#define MAX_IRCTL_DEVICES 4
+#define BUFLEN            16
+
+#define mod(n, div) ((n) % (div))
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+#include <linux/kfifo.h>
+#include <media/lirc.h>
+
+struct lirc_buffer {
+	wait_queue_head_t wait_poll;
+	spinlock_t fifo_lock;
+	unsigned int chunk_size;
+	unsigned int size; /* in chunks */
+	/* Using chunks instead of bytes pretends to simplify boundary checking
+	 * And should allow for some performance fine tunning later */
+	struct kfifo fifo;
+	u8 fifo_initialized;
+};
+
+static inline void lirc_buffer_clear(struct lirc_buffer *buf)
+{
+	unsigned long flags;
+
+	if (buf->fifo_initialized) {
+		spin_lock_irqsave(&buf->fifo_lock, flags);
+		kfifo_reset(&buf->fifo);
+		spin_unlock_irqrestore(&buf->fifo_lock, flags);
+	} else
+		WARN(1, "calling %s on an uninitialized lirc_buffer\n",
+		     __func__);
+}
+
+static inline int lirc_buffer_init(struct lirc_buffer *buf,
+				    unsigned int chunk_size,
+				    unsigned int size)
+{
+	int ret;
+
+	init_waitqueue_head(&buf->wait_poll);
+	spin_lock_init(&buf->fifo_lock);
+	buf->chunk_size = chunk_size;
+	buf->size = size;
+	ret = kfifo_alloc(&buf->fifo, size * chunk_size, GFP_KERNEL);
+	if (ret == 0)
+		buf->fifo_initialized = 1;
+
+	return ret;
+}
+
+static inline void lirc_buffer_free(struct lirc_buffer *buf)
+{
+	if (buf->fifo_initialized) {
+		kfifo_free(&buf->fifo);
+		buf->fifo_initialized = 0;
+	} else
+		WARN(1, "calling %s on an uninitialized lirc_buffer\n",
+		     __func__);
+}
+
+static inline int lirc_buffer_len(struct lirc_buffer *buf)
+{
+	int len;
+	unsigned long flags;
+
+	spin_lock_irqsave(&buf->fifo_lock, flags);
+	len = kfifo_len(&buf->fifo);
+	spin_unlock_irqrestore(&buf->fifo_lock, flags);
+
+	return len;
+}
+
+static inline int lirc_buffer_full(struct lirc_buffer *buf)
+{
+	return lirc_buffer_len(buf) == buf->size * buf->chunk_size;
+}
+
+static inline int lirc_buffer_empty(struct lirc_buffer *buf)
+{
+	return !lirc_buffer_len(buf);
+}
+
+static inline int lirc_buffer_available(struct lirc_buffer *buf)
+{
+	return buf->size - (lirc_buffer_len(buf) / buf->chunk_size);
+}
+
+static inline unsigned int lirc_buffer_read(struct lirc_buffer *buf,
+					    unsigned char *dest)
+{
+	unsigned int ret = 0;
+
+	if (lirc_buffer_len(buf) >= buf->chunk_size)
+		ret = kfifo_out_locked(&buf->fifo, dest, buf->chunk_size,
+				       &buf->fifo_lock);
+	return ret;
+
+}
+
+static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf,
+					     unsigned char *orig)
+{
+	unsigned int ret;
+
+	ret = kfifo_in_locked(&buf->fifo, orig, buf->chunk_size,
+			      &buf->fifo_lock);
+
+	return ret;
+}
+
+struct lirc_driver {
+	char name[40];
+	int minor;
+	unsigned long code_length;
+	unsigned int buffer_size; /* in chunks holding one code each */
+	int sample_rate;
+	unsigned long features;
+
+	unsigned int chunk_size;
+
+	void *data;
+	int min_timeout;
+	int max_timeout;
+	int (*add_to_buf) (void *data, struct lirc_buffer *buf);
+	struct lirc_buffer *rbuf;
+	int (*set_use_inc) (void *data);
+	void (*set_use_dec) (void *data);
+	struct file_operations *fops;
+	struct device *dev;
+	struct module *owner;
+};
+
+/* name:
+ * this string will be used for logs
+ *
+ * minor:
+ * indicates minor device (/dev/lirc) number for registered driver
+ * if caller fills it with negative value, then the first free minor
+ * number will be used (if available)
+ *
+ * code_length:
+ * length of the remote control key code expressed in bits
+ *
+ * sample_rate:
+ *
+ * data:
+ * it may point to any driver data and this pointer will be passed to
+ * all callback functions
+ *
+ * add_to_buf:
+ * add_to_buf will be called after specified period of the time or
+ * triggered by the external event, this behavior depends on value of
+ * the sample_rate this function will be called in user context. This
+ * routine should return 0 if data was added to the buffer and
+ * -ENODATA if none was available. This should add some number of bits
+ * evenly divisible by code_length to the buffer
+ *
+ * rbuf:
+ * if not NULL, it will be used as a read buffer, you will have to
+ * write to the buffer by other means, like irq's (see also
+ * lirc_serial.c).
+ *
+ * set_use_inc:
+ * set_use_inc will be called after device is opened
+ *
+ * set_use_dec:
+ * set_use_dec will be called after device is closed
+ *
+ * fops:
+ * file_operations for drivers which don't fit the current driver model.
+ *
+ * Some ioctl's can be directly handled by lirc_dev if the driver's
+ * ioctl function is NULL or if it returns -ENOIOCTLCMD (see also
+ * lirc_serial.c).
+ *
+ * owner:
+ * the module owning this struct
+ *
+ */
+
+
+/* following functions can be called ONLY from user context
+ *
+ * returns negative value on error or minor number
+ * of the registered device if success
+ * contents of the structure pointed by p is copied
+ */
+extern int lirc_register_driver(struct lirc_driver *d);
+
+/* returns negative value on error or 0 if success
+*/
+extern int lirc_unregister_driver(int minor);
+
+/* Returns the private data stored in the lirc_driver
+ * associated with the given device file pointer.
+ */
+void *lirc_get_pdata(struct file *file);
+
+/* default file operations
+ * used by drivers if they override only some operations
+ */
+int lirc_dev_fop_open(struct inode *inode, struct file *file);
+int lirc_dev_fop_close(struct inode *inode, struct file *file);
+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait);
+long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+ssize_t lirc_dev_fop_read(struct file *file, char *buffer, size_t length,
+			  loff_t *ppos);
+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, size_t length,
+			   loff_t *ppos);
+
+#endif
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index c78e99a..9569d08 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -17,8 +17,13 @@
 #define IR_TYPE_RC6	(1  << 2)	/* Philips RC6 protocol */
 #define IR_TYPE_JVC	(1  << 3)	/* JVC protocol */
 #define IR_TYPE_SONY	(1  << 4)	/* Sony12/15/20 protocol */
+#define IR_TYPE_LIRC	(1  << 30)	/* Pass raw IR to lirc userspace */
 #define IR_TYPE_OTHER	(1u << 31)
 
+#define IR_TYPE_ALL (IR_TYPE_RC5 | IR_TYPE_NEC  | IR_TYPE_RC6  | \
+		     IR_TYPE_JVC | IR_TYPE_SONY | IR_TYPE_LIRC | \
+		     IR_TYPE_OTHER)
+
 struct ir_scancode {
 	u32	scancode;
 	u32	keycode;
@@ -64,6 +69,8 @@
 #define RC_MAP_BUDGET_CI_OLD             "rc-budget-ci-old"
 #define RC_MAP_CINERGY_1400              "rc-cinergy-1400"
 #define RC_MAP_CINERGY                   "rc-cinergy"
+#define RC_MAP_DIB0700_NEC_TABLE         "rc-dib0700-nec"
+#define RC_MAP_DIB0700_RC5_TABLE         "rc-dib0700-rc5"
 #define RC_MAP_DM1105_NEC                "rc-dm1105-nec"
 #define RC_MAP_DNTV_LIVE_DVBT_PRO        "rc-dntv-live-dvbt-pro"
 #define RC_MAP_DNTV_LIVE_DVB_T           "rc-dntv-live-dvb-t"
@@ -87,6 +94,7 @@
 #define RC_MAP_KAIOMY                    "rc-kaiomy"
 #define RC_MAP_KWORLD_315U               "rc-kworld-315u"
 #define RC_MAP_KWORLD_PLUS_TV_ANALOG     "rc-kworld-plus-tv-analog"
+#define RC_MAP_LIRC                      "rc-lirc"
 #define RC_MAP_MANLI                     "rc-manli"
 #define RC_MAP_MSI_TVANYWHERE_PLUS       "rc-msi-tvanywhere-plus"
 #define RC_MAP_MSI_TVANYWHERE            "rc-msi-tvanywhere"
@@ -107,6 +115,7 @@
 #define RC_MAP_PV951                     "rc-pv951"
 #define RC_MAP_RC5_HAUPPAUGE_NEW         "rc-rc5-hauppauge-new"
 #define RC_MAP_RC5_TV                    "rc-rc5-tv"
+#define RC_MAP_RC6_MCE                   "rc-rc6-mce"
 #define RC_MAP_REAL_AUDIO_220_32_KEYS    "rc-real-audio-220-32-keys"
 #define RC_MAP_TBS_NEC                   "rc-tbs-nec"
 #define RC_MAP_TERRATEC_CINERGY_XS       "rc-terratec-cinergy-xs"
@@ -116,6 +125,7 @@
 #define RC_MAP_VIDEOMATE_TV_PVR          "rc-videomate-tv-pvr"
 #define RC_MAP_WINFAST                   "rc-winfast"
 #define RC_MAP_WINFAST_USBII_DELUXE      "rc-winfast-usbii-deluxe"
+
 /*
  * Please, do not just append newer Remote Controller names at the end.
  * The names should be ordered in alphabetical order
diff --git a/include/media/sh_mobile_ceu.h b/include/media/sh_mobile_ceu.h
index b677478..80346a6 100644
--- a/include/media/sh_mobile_ceu.h
+++ b/include/media/sh_mobile_ceu.h
@@ -6,8 +6,11 @@
 #define SH_CEU_FLAG_HSYNC_LOW		(1 << 2) /* default High if possible */
 #define SH_CEU_FLAG_VSYNC_LOW		(1 << 3) /* default High if possible */
 
+struct device;
+
 struct sh_mobile_ceu_info {
 	unsigned long flags;
+	struct device *csi2_dev;
 };
 
 #endif /* __ASM_SH_MOBILE_CEU_H__ */
diff --git a/include/media/sh_mobile_csi2.h b/include/media/sh_mobile_csi2.h
new file mode 100644
index 0000000..4d26151
--- /dev/null
+++ b/include/media/sh_mobile_csi2.h
@@ -0,0 +1,46 @@
+/*
+ * Driver header for the SH-Mobile MIPI CSI-2 unit
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SH_MIPI_CSI
+#define SH_MIPI_CSI
+
+enum sh_csi2_phy {
+	SH_CSI2_PHY_MAIN,
+	SH_CSI2_PHY_SUB,
+};
+
+enum sh_csi2_type {
+	SH_CSI2C,
+	SH_CSI2I,
+};
+
+#define SH_CSI2_CRC	(1 << 0)
+#define SH_CSI2_ECC	(1 << 1)
+
+struct platform_device;
+
+struct sh_csi2_client_config {
+	enum sh_csi2_phy phy;
+	unsigned char lanes;		/* bitmask[3:0] */
+	unsigned char channel;		/* 0..3 */
+	struct platform_device *pdev;	/* client platform device */
+};
+
+struct sh_csi2_pdata {
+	enum sh_csi2_type type;
+	unsigned int flags;
+	struct sh_csi2_client_config *clients;
+	int num_clients;
+};
+
+struct device;
+struct v4l2_device;
+
+#endif
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index b8289c2..2ce9573 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -12,12 +12,15 @@
 #ifndef SOC_CAMERA_H
 #define SOC_CAMERA_H
 
+#include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/pm.h>
 #include <linux/videodev2.h>
 #include <media/videobuf-core.h>
 #include <media/v4l2-device.h>
 
+extern struct bus_type soc_camera_bus_type;
+
 struct soc_camera_device {
 	struct list_head list;
 	struct device dev;
diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index 865cda7..f0cf2e7 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -24,10 +24,10 @@
  */
 enum v4l2_mbus_pixelcode {
 	V4L2_MBUS_FMT_FIXED = 1,
-	V4L2_MBUS_FMT_YUYV8_2X8_LE,
-	V4L2_MBUS_FMT_YVYU8_2X8_LE,
-	V4L2_MBUS_FMT_YUYV8_2X8_BE,
-	V4L2_MBUS_FMT_YVYU8_2X8_BE,
+	V4L2_MBUS_FMT_YUYV8_2X8,
+	V4L2_MBUS_FMT_YVYU8_2X8,
+	V4L2_MBUS_FMT_UYVY8_2X8,
+	V4L2_MBUS_FMT_VYUY8_2X8,
 	V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
 	V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
 	V4L2_MBUS_FMT_RGB565_2X8_LE,
@@ -41,6 +41,11 @@
 	V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
 	V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
 	V4L2_MBUS_FMT_SGRBG8_1X8,
+	V4L2_MBUS_FMT_SBGGR12_1X12,
+	V4L2_MBUS_FMT_YUYV8_1_5X8,
+	V4L2_MBUS_FMT_YVYU8_1_5X8,
+	V4L2_MBUS_FMT_UYVY8_1_5X8,
+	V4L2_MBUS_FMT_VYUY8_1_5X8,
 };
 
 /**
diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h
index f91a736..f2c41ce 100644
--- a/include/media/videobuf-core.h
+++ b/include/media/videobuf-core.h
@@ -54,8 +54,6 @@
 
 struct videobuf_mapping {
 	unsigned int count;
-	unsigned long start;
-	unsigned long end;
 	struct videobuf_queue *q;
 };
 
@@ -127,7 +125,7 @@
 struct videobuf_qtype_ops {
 	u32                     magic;
 
-	struct videobuf_buffer *(*alloc)(size_t size);
+	struct videobuf_buffer *(*alloc_vb)(size_t size);
 	void *(*vaddr)		(struct videobuf_buffer *buf);
 	int (*iolock)		(struct videobuf_queue *q,
 				 struct videobuf_buffer *vb,
@@ -173,7 +171,7 @@
 int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
 		struct v4l2_framebuffer *fbuf);
 
-struct videobuf_buffer *videobuf_alloc(struct videobuf_queue *q);
+struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q);
 
 /* Used on videobuf-dvb */
 void *videobuf_queue_to_vaddr(struct videobuf_queue *q,
diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h
index a195f3b..97e07f4 100644
--- a/include/media/videobuf-dma-sg.h
+++ b/include/media/videobuf-dma-sg.h
@@ -25,23 +25,6 @@
 /* --------------------------------------------------------------------- */
 
 /*
- * Return a scatterlist for some page-aligned vmalloc()'ed memory
- * block (NULL on errors).  Memory for the scatterlist is allocated
- * using kmalloc.  The caller must free the memory.
- */
-struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages);
-
-/*
- * Return a scatterlist for a an array of userpages (NULL on errors).
- * Memory for the scatterlist is allocated using kmalloc.  The caller
- * must free the memory.
- */
-struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages,
-					 int offset);
-
-/* --------------------------------------------------------------------- */
-
-/*
  * A small set of helper functions to manage buffers (both userland
  * and kernel) for DMA.
  *
@@ -68,7 +51,7 @@
 	struct page         **pages;
 
 	/* for kernel buffers */
-	void                *vmalloc;
+	void                *vaddr;
 
 	/* for overlay buffers (pci-pci dma) */
 	dma_addr_t          bus_addr;
@@ -87,6 +70,16 @@
 	struct videobuf_dmabuf  dma;
 };
 
+/*
+ * Scatter-gather DMA buffer API.
+ *
+ * These functions provide a simple way to create a page list and a
+ * scatter-gather list from a kernel, userspace of physical address and map the
+ * memory for DMA operation.
+ *
+ * Despite the name, this is totally unrelated to videobuf, except that
+ * videobuf-dma-sg uses the same API internally.
+ */
 void videobuf_dma_init(struct videobuf_dmabuf *dma);
 int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
 			   unsigned long data, unsigned long size);
@@ -96,8 +89,8 @@
 			      dma_addr_t addr, int nr_pages);
 int videobuf_dma_free(struct videobuf_dmabuf *dma);
 
-int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma);
-int videobuf_dma_unmap(struct videobuf_queue *q, struct videobuf_dmabuf *dma);
+int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma);
+int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma);
 struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf);
 
 void *videobuf_sg_alloc(size_t size);
@@ -111,11 +104,5 @@
 			 unsigned int msize,
 			 void *priv);
 
-/*FIXME: these variants are used only on *-alsa code, where videobuf is
- * used without queue
- */
-int videobuf_sg_dma_map(struct device *dev, struct videobuf_dmabuf *dma);
-int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma);
-
 #endif /* _VIDEOBUF_DMA_SG_H */
 
diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h
index 851eb1a..e19403c 100644
--- a/include/media/videobuf-vmalloc.h
+++ b/include/media/videobuf-vmalloc.h
@@ -22,7 +22,7 @@
 struct videobuf_vmalloc_memory {
 	u32                 magic;
 
-	void                *vmalloc;
+	void                *vaddr;
 
 	/* remap_vmalloc_range seems to need to run
 	 * after mmap() on some cases */
diff --git a/include/net/act_api.h b/include/net/act_api.h
index c05fd71..bab385f 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -20,6 +20,7 @@
 	struct gnet_stats_queue		tcfc_qstats;
 	struct gnet_stats_rate_est	tcfc_rate_est;
 	spinlock_t			tcfc_lock;
+	struct rcu_head			tcfc_rcu;
 };
 #define tcf_next	common.tcfc_next
 #define tcf_index	common.tcfc_index
@@ -32,6 +33,7 @@
 #define tcf_qstats	common.tcfc_qstats
 #define tcf_rate_est	common.tcfc_rate_est
 #define tcf_lock	common.tcfc_lock
+#define tcf_rcu		common.tcfc_rcu
 
 struct tcf_police {
 	struct tcf_common	common;
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 20725e2..90c9e28 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -23,7 +23,8 @@
 };
 
 struct unix_skb_parms {
-	struct ucred		creds;		/* Skb credentials	*/
+	struct pid		*pid;		/* Skb credentials	*/
+	const struct cred	*cred;
 	struct scm_fp_list	*fp;		/* Passed files		*/
 #ifdef CONFIG_SECURITY_NETWORK
 	u32			secid;		/* Security ID		*/
@@ -31,7 +32,6 @@
 };
 
 #define UNIXCB(skb) 	(*(struct unix_skb_parms *)&((skb)->cb))
-#define UNIXCREDS(skb)	(&UNIXCB((skb)).creds)
 #define UNIXSID(skb)	(&UNIXCB((skb)).secid)
 
 #define unix_state_lock(s)	spin_lock(&unix_sk(s)->lock)
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index ff77e8f..27a902d 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -84,7 +84,7 @@
 /* BD Address */
 typedef struct {
 	__u8 b[6];
-} __attribute__((packed)) bdaddr_t;
+} __packed bdaddr_t;
 
 #define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
 #define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
@@ -138,6 +138,7 @@
 struct bt_skb_cb {
 	__u8 pkt_type;
 	__u8 incoming;
+	__u16 expect;
 	__u8 tx_seq;
 	__u8 retries;
 	__u8 sar;
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index fc0c502..bcbdd6d 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -100,6 +100,9 @@
 #define HCISETACLMTU	_IOW('H', 227, int)
 #define HCISETSCOMTU	_IOW('H', 228, int)
 
+#define HCIBLOCKADDR	_IOW('H', 230, int)
+#define HCIUNBLOCKADDR	_IOW('H', 231, int)
+
 #define HCIINQUIRY	_IOR('H', 240, int)
 
 /* HCI timeouts */
@@ -227,7 +230,7 @@
 	__u8     lap[3];
 	__u8     length;
 	__u8     num_rsp;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_INQUIRY_CANCEL		0x0402
 
@@ -241,81 +244,81 @@
 	__u8     pscan_mode;
 	__le16   clock_offset;
 	__u8     role_switch;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_DISCONNECT		0x0406
 struct hci_cp_disconnect {
 	__le16   handle;
 	__u8     reason;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_ADD_SCO			0x0407
 struct hci_cp_add_sco {
 	__le16   handle;
 	__le16   pkt_type;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_CREATE_CONN_CANCEL	0x0408
 struct hci_cp_create_conn_cancel {
 	bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_ACCEPT_CONN_REQ		0x0409
 struct hci_cp_accept_conn_req {
 	bdaddr_t bdaddr;
 	__u8     role;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_REJECT_CONN_REQ		0x040a
 struct hci_cp_reject_conn_req {
 	bdaddr_t bdaddr;
 	__u8     reason;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_LINK_KEY_REPLY		0x040b
 struct hci_cp_link_key_reply {
 	bdaddr_t bdaddr;
 	__u8     link_key[16];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_LINK_KEY_NEG_REPLY	0x040c
 struct hci_cp_link_key_neg_reply {
 	bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_PIN_CODE_REPLY		0x040d
 struct hci_cp_pin_code_reply {
 	bdaddr_t bdaddr;
 	__u8     pin_len;
 	__u8     pin_code[16];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_PIN_CODE_NEG_REPLY	0x040e
 struct hci_cp_pin_code_neg_reply {
 	bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_CHANGE_CONN_PTYPE	0x040f
 struct hci_cp_change_conn_ptype {
 	__le16   handle;
 	__le16   pkt_type;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_AUTH_REQUESTED		0x0411
 struct hci_cp_auth_requested {
 	__le16   handle;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_SET_CONN_ENCRYPT		0x0413
 struct hci_cp_set_conn_encrypt {
 	__le16   handle;
 	__u8     encrypt;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_CHANGE_CONN_LINK_KEY	0x0415
 struct hci_cp_change_conn_link_key {
 	__le16   handle;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_REMOTE_NAME_REQ		0x0419
 struct hci_cp_remote_name_req {
@@ -323,28 +326,28 @@
 	__u8     pscan_rep_mode;
 	__u8     pscan_mode;
 	__le16   clock_offset;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_REMOTE_NAME_REQ_CANCEL	0x041a
 struct hci_cp_remote_name_req_cancel {
 	bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_REMOTE_FEATURES	0x041b
 struct hci_cp_read_remote_features {
 	__le16   handle;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_REMOTE_EXT_FEATURES	0x041c
 struct hci_cp_read_remote_ext_features {
 	__le16   handle;
 	__u8     page;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_REMOTE_VERSION	0x041d
 struct hci_cp_read_remote_version {
 	__le16   handle;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_SETUP_SYNC_CONN		0x0428
 struct hci_cp_setup_sync_conn {
@@ -355,7 +358,7 @@
 	__le16   voice_setting;
 	__u8     retrans_effort;
 	__le16   pkt_type;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_ACCEPT_SYNC_CONN_REQ	0x0429
 struct hci_cp_accept_sync_conn_req {
@@ -366,13 +369,13 @@
 	__le16   content_format;
 	__u8     retrans_effort;
 	__le16   pkt_type;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_REJECT_SYNC_CONN_REQ	0x042a
 struct hci_cp_reject_sync_conn_req {
 	bdaddr_t bdaddr;
 	__u8     reason;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_SNIFF_MODE		0x0803
 struct hci_cp_sniff_mode {
@@ -381,59 +384,59 @@
 	__le16   min_interval;
 	__le16   attempt;
 	__le16   timeout;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_EXIT_SNIFF_MODE		0x0804
 struct hci_cp_exit_sniff_mode {
 	__le16   handle;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_ROLE_DISCOVERY		0x0809
 struct hci_cp_role_discovery {
 	__le16   handle;
-} __attribute__ ((packed));
+} __packed;
 struct hci_rp_role_discovery {
 	__u8     status;
 	__le16   handle;
 	__u8     role;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_SWITCH_ROLE		0x080b
 struct hci_cp_switch_role {
 	bdaddr_t bdaddr;
 	__u8     role;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_LINK_POLICY		0x080c
 struct hci_cp_read_link_policy {
 	__le16   handle;
-} __attribute__ ((packed));
+} __packed;
 struct hci_rp_read_link_policy {
 	__u8     status;
 	__le16   handle;
 	__le16   policy;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_WRITE_LINK_POLICY	0x080d
 struct hci_cp_write_link_policy {
 	__le16   handle;
 	__le16   policy;
-} __attribute__ ((packed));
+} __packed;
 struct hci_rp_write_link_policy {
 	__u8     status;
 	__le16   handle;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_DEF_LINK_POLICY	0x080e
 struct hci_rp_read_def_link_policy {
 	__u8     status;
 	__le16   policy;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_WRITE_DEF_LINK_POLICY	0x080f
 struct hci_cp_write_def_link_policy {
 	__le16   policy;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_SNIFF_SUBRATE		0x0811
 struct hci_cp_sniff_subrate {
@@ -441,12 +444,12 @@
 	__le16   max_latency;
 	__le16   min_remote_timeout;
 	__le16   min_local_timeout;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_SET_EVENT_MASK		0x0c01
 struct hci_cp_set_event_mask {
 	__u8     mask[8];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_RESET			0x0c03
 
@@ -455,7 +458,7 @@
 	__u8     flt_type;
 	__u8     cond_type;
 	__u8     condition[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Filter types */
 #define HCI_FLT_CLEAR_ALL	0x00
@@ -474,13 +477,13 @@
 #define HCI_OP_WRITE_LOCAL_NAME		0x0c13
 struct hci_cp_write_local_name {
 	__u8     name[248];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_LOCAL_NAME		0x0c14
 struct hci_rp_read_local_name {
 	__u8     status;
 	__u8     name[248];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_WRITE_CA_TIMEOUT		0x0c16
 
@@ -508,23 +511,23 @@
 struct hci_rp_read_class_of_dev {
 	__u8     status;
 	__u8     dev_class[3];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_WRITE_CLASS_OF_DEV	0x0c24
 struct hci_cp_write_class_of_dev {
 	__u8     dev_class[3];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_VOICE_SETTING	0x0c25
 struct hci_rp_read_voice_setting {
 	__u8     status;
 	__le16   voice_setting;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_WRITE_VOICE_SETTING	0x0c26
 struct hci_cp_write_voice_setting {
 	__le16   voice_setting;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_HOST_BUFFER_SIZE		0x0c33
 struct hci_cp_host_buffer_size {
@@ -532,18 +535,18 @@
 	__u8     sco_mtu;
 	__le16   acl_max_pkt;
 	__le16   sco_max_pkt;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_SSP_MODE		0x0c55
 struct hci_rp_read_ssp_mode {
 	__u8     status;
 	__u8     mode;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_WRITE_SSP_MODE		0x0c56
 struct hci_cp_write_ssp_mode {
 	__u8     mode;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_LOCAL_VERSION	0x1001
 struct hci_rp_read_local_version {
@@ -553,19 +556,19 @@
 	__u8     lmp_ver;
 	__le16   manufacturer;
 	__le16   lmp_subver;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_LOCAL_COMMANDS	0x1002
 struct hci_rp_read_local_commands {
 	__u8     status;
 	__u8     commands[64];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_LOCAL_FEATURES	0x1003
 struct hci_rp_read_local_features {
 	__u8     status;
 	__u8     features[8];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_LOCAL_EXT_FEATURES	0x1004
 struct hci_rp_read_local_ext_features {
@@ -573,7 +576,7 @@
 	__u8     page;
 	__u8     max_page;
 	__u8     features[8];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_BUFFER_SIZE		0x1005
 struct hci_rp_read_buffer_size {
@@ -582,13 +585,13 @@
 	__u8     sco_mtu;
 	__le16   acl_max_pkt;
 	__le16   sco_max_pkt;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_OP_READ_BD_ADDR		0x1009
 struct hci_rp_read_bd_addr {
 	__u8     status;
 	bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
 
 /* ---- HCI Events ---- */
 #define HCI_EV_INQUIRY_COMPLETE		0x01
@@ -601,7 +604,7 @@
 	__u8     pscan_mode;
 	__u8     dev_class[3];
 	__le16   clock_offset;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_CONN_COMPLETE		0x03
 struct hci_ev_conn_complete {
@@ -610,54 +613,54 @@
 	bdaddr_t bdaddr;
 	__u8     link_type;
 	__u8     encr_mode;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_CONN_REQUEST		0x04
 struct hci_ev_conn_request {
 	bdaddr_t bdaddr;
 	__u8     dev_class[3];
 	__u8     link_type;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_DISCONN_COMPLETE		0x05
 struct hci_ev_disconn_complete {
 	__u8     status;
 	__le16   handle;
 	__u8     reason;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_AUTH_COMPLETE		0x06
 struct hci_ev_auth_complete {
 	__u8     status;
 	__le16   handle;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_REMOTE_NAME		0x07
 struct hci_ev_remote_name {
 	__u8     status;
 	bdaddr_t bdaddr;
 	__u8     name[248];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_ENCRYPT_CHANGE		0x08
 struct hci_ev_encrypt_change {
 	__u8     status;
 	__le16   handle;
 	__u8     encrypt;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_CHANGE_LINK_KEY_COMPLETE	0x09
 struct hci_ev_change_link_key_complete {
 	__u8     status;
 	__le16   handle;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_REMOTE_FEATURES		0x0b
 struct hci_ev_remote_features {
 	__u8     status;
 	__le16   handle;
 	__u8     features[8];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_REMOTE_VERSION		0x0c
 struct hci_ev_remote_version {
@@ -666,7 +669,7 @@
 	__u8     lmp_ver;
 	__le16   manufacturer;
 	__le16   lmp_subver;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_QOS_SETUP_COMPLETE	0x0d
 struct hci_qos {
@@ -675,38 +678,38 @@
 	__u32    peak_bandwidth;
 	__u32    latency;
 	__u32    delay_variation;
-} __attribute__ ((packed));
+} __packed;
 struct hci_ev_qos_setup_complete {
 	__u8     status;
 	__le16   handle;
 	struct   hci_qos qos;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_CMD_COMPLETE		0x0e
 struct hci_ev_cmd_complete {
 	__u8     ncmd;
 	__le16   opcode;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_CMD_STATUS		0x0f
 struct hci_ev_cmd_status {
 	__u8     status;
 	__u8     ncmd;
 	__le16   opcode;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_ROLE_CHANGE		0x12
 struct hci_ev_role_change {
 	__u8     status;
 	bdaddr_t bdaddr;
 	__u8     role;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_NUM_COMP_PKTS		0x13
 struct hci_ev_num_comp_pkts {
 	__u8     num_hndl;
 	/* variable length part */
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_MODE_CHANGE		0x14
 struct hci_ev_mode_change {
@@ -714,44 +717,44 @@
 	__le16   handle;
 	__u8     mode;
 	__le16   interval;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_PIN_CODE_REQ		0x16
 struct hci_ev_pin_code_req {
 	bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_LINK_KEY_REQ		0x17
 struct hci_ev_link_key_req {
 	bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_LINK_KEY_NOTIFY		0x18
 struct hci_ev_link_key_notify {
 	bdaddr_t bdaddr;
 	__u8     link_key[16];
 	__u8     key_type;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_CLOCK_OFFSET		0x1c
 struct hci_ev_clock_offset {
 	__u8     status;
 	__le16   handle;
 	__le16   clock_offset;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_PKT_TYPE_CHANGE		0x1d
 struct hci_ev_pkt_type_change {
 	__u8     status;
 	__le16   handle;
 	__le16   pkt_type;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_PSCAN_REP_MODE		0x20
 struct hci_ev_pscan_rep_mode {
 	bdaddr_t bdaddr;
 	__u8     pscan_rep_mode;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_INQUIRY_RESULT_WITH_RSSI	0x22
 struct inquiry_info_with_rssi {
@@ -761,7 +764,7 @@
 	__u8     dev_class[3];
 	__le16   clock_offset;
 	__s8     rssi;
-} __attribute__ ((packed));
+} __packed;
 struct inquiry_info_with_rssi_and_pscan_mode {
 	bdaddr_t bdaddr;
 	__u8     pscan_rep_mode;
@@ -770,7 +773,7 @@
 	__u8     dev_class[3];
 	__le16   clock_offset;
 	__s8     rssi;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_REMOTE_EXT_FEATURES	0x23
 struct hci_ev_remote_ext_features {
@@ -779,7 +782,7 @@
 	__u8     page;
 	__u8     max_page;
 	__u8     features[8];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_SYNC_CONN_COMPLETE	0x2c
 struct hci_ev_sync_conn_complete {
@@ -792,7 +795,7 @@
 	__le16   rx_pkt_len;
 	__le16   tx_pkt_len;
 	__u8     air_mode;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_SYNC_CONN_CHANGED	0x2d
 struct hci_ev_sync_conn_changed {
@@ -802,7 +805,7 @@
 	__u8     retrans_window;
 	__le16   rx_pkt_len;
 	__le16   tx_pkt_len;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_SNIFF_SUBRATE		0x2e
 struct hci_ev_sniff_subrate {
@@ -812,7 +815,7 @@
 	__le16   max_rx_latency;
 	__le16   max_remote_timeout;
 	__le16   max_local_timeout;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_EXTENDED_INQUIRY_RESULT	0x2f
 struct extended_inquiry_info {
@@ -823,37 +826,37 @@
 	__le16   clock_offset;
 	__s8     rssi;
 	__u8     data[240];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_IO_CAPA_REQUEST		0x31
 struct hci_ev_io_capa_request {
 	bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_SIMPLE_PAIR_COMPLETE	0x36
 struct hci_ev_simple_pair_complete {
 	__u8     status;
 	bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_REMOTE_HOST_FEATURES	0x3d
 struct hci_ev_remote_host_features {
 	bdaddr_t bdaddr;
 	__u8     features[8];
-} __attribute__ ((packed));
+} __packed;
 
 /* Internal events generated by Bluetooth stack */
 #define HCI_EV_STACK_INTERNAL	0xfd
 struct hci_ev_stack_internal {
 	__u16    type;
 	__u8     data[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_SI_DEVICE	0x01
 struct hci_ev_si_device {
 	__u16    event;
 	__u16    dev_id;
-} __attribute__ ((packed));
+} __packed;
 
 #define HCI_EV_SI_SECURITY	0x02
 struct hci_ev_si_security {
@@ -861,7 +864,7 @@
 	__u16    proto;
 	__u16    subproto;
 	__u8     incoming;
-} __attribute__ ((packed));
+} __packed;
 
 /* ---- HCI Packet structures ---- */
 #define HCI_COMMAND_HDR_SIZE 3
@@ -872,22 +875,22 @@
 struct hci_command_hdr {
 	__le16	opcode;		/* OCF & OGF */
 	__u8 	plen;
-} __attribute__ ((packed));
+} __packed;
 
 struct hci_event_hdr {
 	__u8	evt;
 	__u8	plen;
-} __attribute__ ((packed));
+} __packed;
 
 struct hci_acl_hdr {
 	__le16	handle;		/* Handle & Flags(PB, BC) */
 	__le16	dlen;
-} __attribute__ ((packed));
+} __packed;
 
 struct hci_sco_hdr {
 	__le16	handle;
 	__u8	dlen;
-} __attribute__ ((packed));
+} __packed;
 
 #ifdef __KERNEL__
 #include <linux/skbuff.h>
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e42f6ed..8b28962 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1,6 +1,6 @@
-/* 
+/*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
+   Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -12,13 +12,13 @@
    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 
+   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 
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
    SOFTWARE IS DISCLAIMED.
 */
 
@@ -62,6 +62,11 @@
 	unsigned int     sco_num;
 };
 
+struct bdaddr_list {
+	struct list_head list;
+	bdaddr_t bdaddr;
+};
+#define NUM_REASSEMBLY 4
 struct hci_dev {
 	struct list_head list;
 	spinlock_t	lock;
@@ -118,7 +123,7 @@
 	struct sk_buff_head	cmd_q;
 
 	struct sk_buff		*sent_cmd;
-	struct sk_buff		*reassembly[3];
+	struct sk_buff		*reassembly[NUM_REASSEMBLY];
 
 	struct mutex		req_lock;
 	wait_queue_head_t	req_wait_q;
@@ -127,6 +132,7 @@
 
 	struct inquiry_cache	inq_cache;
 	struct hci_conn_hash	conn_hash;
+	struct bdaddr_list	blacklist;
 
 	struct hci_dev_stats	stat;
 
@@ -250,6 +256,7 @@
 	HCI_CONN_ENCRYPT_PEND,
 	HCI_CONN_RSWITCH_PEND,
 	HCI_CONN_MODE_CHANGE_PEND,
+	HCI_CONN_SCO_SETUP_PEND,
 };
 
 static inline void hci_conn_hash_init(struct hci_dev *hdev)
@@ -330,6 +337,7 @@
 void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
 void hci_add_sco(struct hci_conn *conn, __u16 handle);
 void hci_setup_sync(struct hci_conn *conn, __u16 handle);
+void hci_sco_setup(struct hci_conn *conn, __u8 status);
 
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
 int hci_conn_del(struct hci_conn *conn);
@@ -380,7 +388,7 @@
 }
 
 static inline void hci_dev_put(struct hci_dev *d)
-{ 
+{
 	__hci_dev_put(d);
 	module_put(d->owner);
 }
@@ -424,10 +432,14 @@
 int hci_get_auth_info(struct hci_dev *hdev, void __user *arg);
 int hci_inquiry(void __user *arg);
 
+struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int hci_blacklist_clear(struct hci_dev *hdev);
+
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
 int hci_recv_frame(struct sk_buff *skb);
 int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
+int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
 
 int hci_register_sysfs(struct hci_dev *hdev);
 void hci_unregister_sysfs(struct hci_dev *hdev);
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 7c695bf..636724b 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -1,6 +1,8 @@
 /* 
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
+   Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
+   Copyright (C) 2010 Google Inc.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -129,31 +131,31 @@
 struct l2cap_hdr {
 	__le16     len;
 	__le16     cid;
-} __attribute__ ((packed));
+} __packed;
 #define L2CAP_HDR_SIZE		4
 
 struct l2cap_cmd_hdr {
 	__u8       code;
 	__u8       ident;
 	__le16     len;
-} __attribute__ ((packed));
+} __packed;
 #define L2CAP_CMD_HDR_SIZE	4
 
 struct l2cap_cmd_rej {
 	__le16     reason;
-} __attribute__ ((packed));
+} __packed;
 
 struct l2cap_conn_req {
 	__le16     psm;
 	__le16     scid;
-} __attribute__ ((packed));
+} __packed;
 
 struct l2cap_conn_rsp {
 	__le16     dcid;
 	__le16     scid;
 	__le16     result;
 	__le16     status;
-} __attribute__ ((packed));
+} __packed;
 
 /* channel indentifier */
 #define L2CAP_CID_SIGNALING	0x0001
@@ -177,14 +179,14 @@
 	__le16     dcid;
 	__le16     flags;
 	__u8       data[0];
-} __attribute__ ((packed));
+} __packed;
 
 struct l2cap_conf_rsp {
 	__le16     scid;
 	__le16     flags;
 	__le16     result;
 	__u8       data[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define L2CAP_CONF_SUCCESS	0x0000
 #define L2CAP_CONF_UNACCEPT	0x0001
@@ -195,7 +197,7 @@
 	__u8       type;
 	__u8       len;
 	__u8       val[0];
-} __attribute__ ((packed));
+} __packed;
 #define L2CAP_CONF_OPT_SIZE	2
 
 #define L2CAP_CONF_HINT		0x80
@@ -216,7 +218,7 @@
 	__le16     retrans_timeout;
 	__le16     monitor_timeout;
 	__le16     max_pdu_size;
-} __attribute__ ((packed));
+} __packed;
 
 #define L2CAP_MODE_BASIC	0x00
 #define L2CAP_MODE_RETRANS	0x01
@@ -227,22 +229,22 @@
 struct l2cap_disconn_req {
 	__le16     dcid;
 	__le16     scid;
-} __attribute__ ((packed));
+} __packed;
 
 struct l2cap_disconn_rsp {
 	__le16     dcid;
 	__le16     scid;
-} __attribute__ ((packed));
+} __packed;
 
 struct l2cap_info_req {
 	__le16      type;
-} __attribute__ ((packed));
+} __packed;
 
 struct l2cap_info_rsp {
 	__le16      type;
 	__le16      result;
 	__u8        data[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* info type */
 #define L2CAP_IT_CL_MTU     0x0001
@@ -287,6 +289,11 @@
 	struct l2cap_chan_list chan_list;
 };
 
+struct sock_del_list {
+	struct sock *sk;
+	struct list_head list;
+};
+
 #define L2CAP_INFO_CL_MTU_REQ_SENT	0x01
 #define L2CAP_INFO_FEAT_MASK_REQ_SENT	0x04
 #define L2CAP_INFO_FEAT_MASK_REQ_DONE	0x08
@@ -353,7 +360,6 @@
 
 	__le16		sport;
 
-	spinlock_t		send_lock;
 	struct timer_list	retrans_timer;
 	struct timer_list	monitor_timer;
 	struct timer_list	ack_timer;
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index 921d7b3..a140847 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -106,19 +106,19 @@
 	u8 addr;
 	u8 ctrl;
 	u8 len;    // Actual size can be 2 bytes
-} __attribute__ ((packed));
+} __packed;
 
 struct rfcomm_cmd {
 	u8 addr;
 	u8 ctrl;
 	u8 len;
 	u8 fcs;
-} __attribute__ ((packed));
+} __packed;
 
 struct rfcomm_mcc {
 	u8 type;
 	u8 len;
-} __attribute__ ((packed));
+} __packed;
 
 struct rfcomm_pn {
 	u8  dlci;
@@ -128,7 +128,7 @@
 	__le16 mtu;
 	u8  max_retrans;
 	u8  credits;
-} __attribute__ ((packed));
+} __packed;
 
 struct rfcomm_rpn {
 	u8  dlci;
@@ -138,17 +138,17 @@
 	u8  xon_char;
 	u8  xoff_char;
 	__le16 param_mask;
-} __attribute__ ((packed));
+} __packed;
 
 struct rfcomm_rls {
 	u8  dlci;
 	u8  status;
-} __attribute__ ((packed));
+} __packed;
 
 struct rfcomm_msc {
 	u8  dlci;
 	u8  v24_sig;
-} __attribute__ ((packed));
+} __packed;
 
 /* ---- Core structures, flags etc ---- */
 
diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h
index 318ab94..6da573c 100644
--- a/include/net/caif/caif_dev.h
+++ b/include/net/caif/caif_dev.h
@@ -50,6 +50,9 @@
  * @client_layer:	User implementation of client layer. This layer
  *			MUST have receive and control callback functions
  *			implemented.
+ * @ifindex:		Link layer interface index used for this connection.
+ * @headroom:		Head room needed by CAIF protocol.
+ * @tailroom:		Tail room needed by CAIF protocol.
  *
  * This function connects a CAIF channel. The Client must implement
  * the struct cflayer. This layer represents the Client layer and holds
@@ -59,8 +62,9 @@
  * E.g. CAIF Socket will call this function for each socket it connects
  * and have one client_layer instance for each socket.
  */
-int caif_connect_client(struct caif_connect_request *config,
-			   struct cflayer *client_layer);
+int caif_connect_client(struct caif_connect_request *conn_req,
+			struct cflayer *client_layer, int *ifindex,
+			int *headroom, int *tailroom);
 
 /**
  * caif_disconnect_client - Disconnects a client from the CAIF stack.
diff --git a/include/net/caif/caif_layer.h b/include/net/caif/caif_layer.h
index 25c472f..c8b07a9 100644
--- a/include/net/caif/caif_layer.h
+++ b/include/net/caif/caif_layer.h
@@ -15,14 +15,8 @@
 struct caif_payload_info;
 struct caif_packet_funcs;
 
-#define CAIF_MAX_FRAMESIZE 4096
-#define CAIF_MAX_PAYLOAD_SIZE (4096 - 64)
-#define CAIF_NEEDED_HEADROOM (10)
-#define CAIF_NEEDED_TAILROOM (2)
 
 #define CAIF_LAYER_NAME_SZ 16
-#define CAIF_SUCCESS	1
-#define CAIF_FAILURE	0
 
 /**
  * caif_assert() - Assert function for CAIF.
diff --git a/include/net/caif/caif_spi.h b/include/net/caif/caif_spi.h
new file mode 100644
index 0000000..ce4570d
--- /dev/null
+++ b/include/net/caif/caif_spi.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:	Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_SPI_H_
+#define CAIF_SPI_H_
+
+#include <net/caif/caif_device.h>
+
+#define SPI_CMD_WR			0x00
+#define SPI_CMD_RD			0x01
+#define SPI_CMD_EOT			0x02
+#define SPI_CMD_IND			0x04
+
+#define SPI_DMA_BUF_LEN			8192
+
+#define WL_SZ				2	/* 16 bits. */
+#define SPI_CMD_SZ			4	/* 32 bits. */
+#define SPI_IND_SZ			4	/* 32 bits. */
+
+#define SPI_XFER			0
+#define SPI_SS_ON			1
+#define SPI_SS_OFF			2
+#define SPI_TERMINATE			3
+
+/* Minimum time between different levels is 50 microseconds. */
+#define MIN_TRANSITION_TIME_USEC	50
+
+/* Defines for calculating duration of SPI transfers for a particular
+ * number of bytes.
+ */
+#define SPI_MASTER_CLK_MHZ		13
+#define SPI_XFER_TIME_USEC(bytes, clk) (((bytes) * 8) / clk)
+
+/* Normally this should be aligned on the modem in order to benefit from full
+ * duplex transfers. However a size of 8188 provokes errors when running with
+ * the modem. These errors occur when packet sizes approaches 4 kB of data.
+ */
+#define CAIF_MAX_SPI_FRAME 4092
+
+/* Maximum number of uplink CAIF frames that can reside in the same SPI frame.
+ * This number should correspond with the modem setting. The application side
+ * CAIF accepts any number of embedded downlink CAIF frames.
+ */
+#define CAIF_MAX_SPI_PKTS 9
+
+/* Decides if SPI buffers should be prefilled with 0xFF pattern for easier
+ * debugging. Both TX and RX buffers will be filled before the transfer.
+ */
+#define CFSPI_DBG_PREFILL		0
+
+/* Structure describing a SPI transfer. */
+struct cfspi_xfer {
+	u16 tx_dma_len;
+	u16 rx_dma_len;
+	void *va_tx;
+	dma_addr_t pa_tx;
+	void *va_rx;
+	dma_addr_t pa_rx;
+};
+
+/* Structure implemented by the SPI interface. */
+struct cfspi_ifc {
+	void (*ss_cb) (bool assert, struct cfspi_ifc *ifc);
+	void (*xfer_done_cb) (struct cfspi_ifc *ifc);
+	void *priv;
+};
+
+/* Structure implemented by SPI clients. */
+struct cfspi_dev {
+	int (*init_xfer) (struct cfspi_xfer *xfer, struct cfspi_dev *dev);
+	void (*sig_xfer) (bool xfer, struct cfspi_dev *dev);
+	struct cfspi_ifc *ifc;
+	char *name;
+	u32 clk_mhz;
+	void *priv;
+};
+
+/* Enumeration describing the CAIF SPI state. */
+enum cfspi_state {
+	CFSPI_STATE_WAITING = 0,
+	CFSPI_STATE_AWAKE,
+	CFSPI_STATE_FETCH_PKT,
+	CFSPI_STATE_GET_NEXT,
+	CFSPI_STATE_INIT_XFER,
+	CFSPI_STATE_WAIT_ACTIVE,
+	CFSPI_STATE_SIG_ACTIVE,
+	CFSPI_STATE_WAIT_XFER_DONE,
+	CFSPI_STATE_XFER_DONE,
+	CFSPI_STATE_WAIT_INACTIVE,
+	CFSPI_STATE_SIG_INACTIVE,
+	CFSPI_STATE_DELIVER_PKT,
+	CFSPI_STATE_MAX,
+};
+
+/* Structure implemented by SPI physical interfaces. */
+struct cfspi {
+	struct caif_dev_common cfdev;
+	struct net_device *ndev;
+	struct platform_device *pdev;
+	struct sk_buff_head qhead;
+	struct sk_buff_head chead;
+	u16 cmd;
+	u16 tx_cpck_len;
+	u16 tx_npck_len;
+	u16 rx_cpck_len;
+	u16 rx_npck_len;
+	struct cfspi_ifc ifc;
+	struct cfspi_xfer xfer;
+	struct cfspi_dev *dev;
+	unsigned long state;
+	struct work_struct work;
+	struct workqueue_struct *wq;
+	struct list_head list;
+	int    flow_off_sent;
+	u32 qd_low_mark;
+	u32 qd_high_mark;
+	struct completion comp;
+	wait_queue_head_t wait;
+	spinlock_t lock;
+	bool flow_stop;
+#ifdef CONFIG_DEBUG_FS
+	enum cfspi_state dbg_state;
+	u16 pcmd;
+	u16 tx_ppck_len;
+	u16 rx_ppck_len;
+	struct dentry *dbgfs_dir;
+	struct dentry *dbgfs_state;
+	struct dentry *dbgfs_frame;
+#endif				/* CONFIG_DEBUG_FS */
+};
+
+extern int spi_frm_align;
+extern int spi_up_head_align;
+extern int spi_up_tail_align;
+extern int spi_down_head_align;
+extern int spi_down_tail_align;
+extern struct platform_driver cfspi_spi_driver;
+
+void cfspi_dbg_state(struct cfspi *cfspi, int state);
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_xmitlen(struct cfspi *cfspi);
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_spi_remove(struct platform_device *pdev);
+int cfspi_spi_probe(struct platform_device *pdev);
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_xmitlen(struct cfspi *cfspi);
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+void cfspi_xfer(struct work_struct *work);
+
+#endif				/* CAIF_SPI_H_ */
diff --git a/include/net/caif/cfcnfg.h b/include/net/caif/cfcnfg.h
index 9fc2fc2..bd646fa 100644
--- a/include/net/caif/cfcnfg.h
+++ b/include/net/caif/cfcnfg.h
@@ -7,6 +7,7 @@
 #ifndef CFCNFG_H_
 #define CFCNFG_H_
 #include <linux/spinlock.h>
+#include <linux/netdevice.h>
 #include <net/caif/caif_layer.h>
 #include <net/caif/cfctrl.h>
 
@@ -73,8 +74,8 @@
 
 void
 cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
-		     void *dev, struct cflayer *phy_layer, u16 *phyid,
-		     enum cfcnfg_phy_preference pref,
+		     struct net_device *dev, struct cflayer *phy_layer,
+		     u16 *phyid, enum cfcnfg_phy_preference pref,
 		     bool fcs, bool stx);
 
 /**
@@ -114,11 +115,18 @@
  * @param:		Link setup parameters.
  * @adap_layer:		Specify the adaptation layer; the receive and
  *			flow-control functions MUST be set in the structure.
- *
+ * @ifindex:		Link layer interface index used for this connection.
+ * @proto_head:		Protocol head-space needed by CAIF protocol,
+ *			excluding link layer.
+ * @proto_tail:		Protocol tail-space needed by CAIF protocol,
+ *			excluding link layer.
  */
 int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
 			    struct cfctrl_link_param *param,
-			    struct cflayer *adap_layer);
+			    struct cflayer *adap_layer,
+			    int *ifindex,
+			    int *proto_head,
+			    int *proto_tail);
 
 /**
  * cfcnfg_get_phyid() - Get physical ID, given type.
diff --git a/include/net/caif/cfsrvl.h b/include/net/caif/cfsrvl.h
index 2dc9eb1..b1fa87e 100644
--- a/include/net/caif/cfsrvl.h
+++ b/include/net/caif/cfsrvl.h
@@ -16,6 +16,8 @@
 	bool open;
 	bool phy_flow_on;
 	bool modem_flow_on;
+	bool supports_flowctrl;
+	void (*release)(struct kref *);
 	struct dev_info dev_info;
 	struct kref ref;
 };
@@ -25,13 +27,15 @@
 struct cflayer *cfdgml_create(u8 linkid, struct dev_info *dev_info);
 struct cflayer *cfutill_create(u8 linkid, struct dev_info *dev_info);
 struct cflayer *cfvidl_create(u8 linkid, struct dev_info *dev_info);
-struct cflayer *cfrfml_create(u8 linkid, struct dev_info *dev_info);
+struct cflayer *cfrfml_create(u8 linkid, struct dev_info *dev_info,
+				int mtu_size);
 struct cflayer *cfdbgl_create(u8 linkid, struct dev_info *dev_info);
 bool cfsrvl_phyid_match(struct cflayer *layer, int phyid);
 void cfservl_destroy(struct cflayer *layer);
 void cfsrvl_init(struct cfsrvl *service,
-		 u8 channel_id,
-		 struct dev_info *dev_info);
+			u8 channel_id,
+			struct dev_info *dev_info,
+			bool supports_flowctrl);
 bool cfsrvl_ready(struct cfsrvl *service, int *err);
 u8 cfsrvl_getphyid(struct cflayer *layer);
 
@@ -50,7 +54,10 @@
 	if (layr == NULL)
 		return;
 	s = container_of(layr, struct cfsrvl, layer);
-	kref_put(&s->ref, cfsrvl_release);
+
+	WARN_ON(!s->release);
+	if (s->release)
+		kref_put(&s->ref, s->release);
 }
 
 #endif				/* CFSRVL_H_ */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b44a2e5..2fd06c6 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -37,6 +37,7 @@
  *
  * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band
  * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7)
+ * @IEEE80211_NUM_BANDS: number of defined bands
  */
 enum ieee80211_band {
 	IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ,
@@ -89,7 +90,7 @@
  * @max_power: maximum transmission power (in dBm)
  * @beacon_found: helper to regulatory code to indicate when a beacon
  *	has been found on this channel. Use regulatory_hint_found_beacon()
- *	to enable this, this is is useful only on 5 GHz band.
+ *	to enable this, this is useful only on 5 GHz band.
  * @orig_mag: internal use
  * @orig_mpwr: internal use
  */
@@ -188,6 +189,7 @@
  *	in this band. Must be sorted to give a valid "supported
  *	rates" IE, i.e. CCK rates first, then OFDM.
  * @n_bitrates: Number of bitrates in @bitrates
+ * @ht_cap: HT capabilities in this band
  */
 struct ieee80211_supported_band {
 	struct ieee80211_channel *channels;
@@ -225,6 +227,7 @@
  * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used
  *	with the get_key() callback, must be in little endian,
  *	length given by @seq_len.
+ * @seq_len: length of @seq.
  */
 struct key_params {
 	u8 *key;
@@ -237,6 +240,8 @@
 /**
  * enum survey_info_flags - survey information flags
  *
+ * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in
+ *
  * Used by the driver to indicate which info in &struct survey_info
  * it has filled in during the get_survey().
  */
@@ -247,13 +252,13 @@
 /**
  * struct survey_info - channel survey response
  *
- * Used by dump_survey() to report back per-channel survey information.
- *
  * @channel: the channel this survey record reports, mandatory
  * @filled: bitflag of flags from &enum survey_info_flags
  * @noise: channel noise in dBm. This and all following fields are
  *     optional
  *
+ * Used by dump_survey() to report back per-channel survey information.
+ *
  * This structure can later be expanded with things like
  * channel duty cycle etc.
  */
@@ -288,7 +293,7 @@
  *
  * @PLINK_ACTION_INVALID: action 0 is reserved
  * @PLINK_ACTION_OPEN: start mesh peer link establishment
- * @PLINK_ACTION_BLOCL: block traffic from this mesh peer
+ * @PLINK_ACTION_BLOCK: block traffic from this mesh peer
  */
 enum plink_actions {
 	PLINK_ACTION_INVALID,
@@ -311,6 +316,8 @@
  *	(bitmask of BIT(NL80211_STA_FLAG_...))
  * @listen_interval: listen interval or -1 for no change
  * @aid: AID or zero for no change
+ * @plink_action: plink action to take
+ * @ht_capa: HT capabilities of station
  */
 struct station_parameters {
 	u8 *supported_rates;
@@ -448,13 +455,13 @@
  * Used by the driver to indicate which info in &struct mpath_info it has filled
  * in during get_station() or dump_station().
  *
- * MPATH_INFO_FRAME_QLEN: @frame_qlen filled
- * MPATH_INFO_SN: @sn filled
- * MPATH_INFO_METRIC: @metric filled
- * MPATH_INFO_EXPTIME: @exptime filled
- * MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled
- * MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled
- * MPATH_INFO_FLAGS: @flags filled
+ * @MPATH_INFO_FRAME_QLEN: @frame_qlen filled
+ * @MPATH_INFO_SN: @sn filled
+ * @MPATH_INFO_METRIC: @metric filled
+ * @MPATH_INFO_EXPTIME: @exptime filled
+ * @MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled
+ * @MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled
+ * @MPATH_INFO_FLAGS: @flags filled
  */
 enum mpath_info_flags {
 	MPATH_INFO_FRAME_QLEN		= BIT(0),
@@ -587,6 +594,7 @@
  * @ie_len: length of ie in octets
  * @wiphy: the wiphy this was for
  * @dev: the interface
+ * @aborted: (internal) scan request was notified as aborted
  */
 struct cfg80211_scan_request {
 	struct cfg80211_ssid *ssids;
@@ -623,6 +631,7 @@
  * This structure describes a BSS (which may also be a mesh network)
  * for use in scan results and similar.
  *
+ * @channel: channel this BSS is on
  * @bssid: BSSID of the BSS
  * @tsf: timestamp of last received update
  * @beacon_interval: the beacon interval as from the frame
@@ -801,6 +810,7 @@
  * @beacon_interval: beacon interval to use
  * @privacy: this is a protected network, keys will be configured
  *	after joining
+ * @basic_rates: bitmap of basic rates to use when creating the IBSS
  */
 struct cfg80211_ibss_params {
 	u8 *ssid;
@@ -809,6 +819,7 @@
 	u8 *ie;
 	u8 ssid_len, ie_len;
 	u16 beacon_interval;
+	u32 basic_rates;
 	bool channel_fixed;
 	bool privacy;
 };
@@ -826,8 +837,8 @@
  * @ssid: SSID
  * @ssid_len: Length of ssid in octets
  * @auth_type: Authentication type (algorithm)
- * @assoc_ie: IEs for association request
- * @assoc_ie_len: Length of assoc_ie in octets
+ * @ie: IEs for association request
+ * @ie_len: Length of assoc_ie in octets
  * @privacy: indicates whether privacy-enabled APs should be used
  * @crypto: crypto settings
  * @key_len: length of WEP key for shared key authentication
@@ -850,10 +861,11 @@
 
 /**
  * enum wiphy_params_flags - set_wiphy_params bitfield values
- * WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed
- * WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed
- * WIPHY_PARAM_FRAG_THRESHOLD: wiphy->frag_threshold has changed
- * WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed
+ * @WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed
+ * @WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed
+ * @WIPHY_PARAM_FRAG_THRESHOLD: wiphy->frag_threshold has changed
+ * @WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed
+ * @WIPHY_PARAM_COVERAGE_CLASS: coverage class changed
  */
 enum wiphy_params_flags {
 	WIPHY_PARAM_RETRY_SHORT		= 1 << 0,
@@ -863,19 +875,6 @@
 	WIPHY_PARAM_COVERAGE_CLASS	= 1 << 4,
 };
 
-/**
- * enum tx_power_setting - TX power adjustment
- *
- * @TX_POWER_AUTOMATIC: the dbm parameter is ignored
- * @TX_POWER_LIMITED: limit TX power by the dbm parameter
- * @TX_POWER_FIXED: fix TX power to the dbm parameter
- */
-enum tx_power_setting {
-	TX_POWER_AUTOMATIC,
-	TX_POWER_LIMITED,
-	TX_POWER_FIXED,
-};
-
 /*
  * cfg80211_bitrate_mask - masks for bitrate control
  */
@@ -949,10 +948,16 @@
  * @del_beacon: Remove beacon configuration and stop sending the beacon.
  *
  * @add_station: Add a new station.
- *
  * @del_station: Remove a station; @mac may be NULL to remove all stations.
- *
  * @change_station: Modify a given station.
+ * @get_station: get station information for the station identified by @mac
+ * @dump_station: dump station callback -- resume dump at index @idx
+ *
+ * @add_mpath: add a fixed mesh path
+ * @del_mpath: delete a given mesh path
+ * @change_mpath: change a given mesh path
+ * @get_mpath: get a mesh path for the given parameters
+ * @dump_mpath: dump mesh path callback -- resume dump at index @idx
  *
  * @get_mesh_params: Put the current mesh parameters into *params
  *
@@ -960,8 +965,6 @@
  *	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
@@ -1002,6 +1005,8 @@
  * @get_tx_power: store the current TX power into the dbm variable;
  *	return 0 if successful
  *
+ * @set_wds_peer: set the WDS peer for a WDS interface
+ *
  * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
  *	functions to adjust rfkill hw state
  *
@@ -1019,6 +1024,8 @@
  *
  * @testmode_cmd: run a test mode command
  *
+ * @set_bitrate_mask: set the bitrate mask configuration
+ *
  * @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac
  *	devices running firmwares capable of generating the (re) association
  *	RSN IE. It allows for faster roaming between WPA2 BSSIDs.
@@ -1129,7 +1136,7 @@
 	int	(*set_wiphy_params)(struct wiphy *wiphy, u32 changed);
 
 	int	(*set_tx_power)(struct wiphy *wiphy,
-				enum tx_power_setting type, int dbm);
+				enum nl80211_tx_power_setting type, int mbm);
 	int	(*get_tx_power)(struct wiphy *wiphy, int *dbm);
 
 	int	(*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
@@ -1168,6 +1175,7 @@
 	int	(*action)(struct wiphy *wiphy, struct net_device *dev,
 			  struct ieee80211_channel *chan,
 			  enum nl80211_channel_type channel_type,
+			  bool channel_type_valid,
 			  const u8 *buf, size_t len, u64 *cookie);
 
 	int	(*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
@@ -1230,8 +1238,6 @@
 
 /**
  * struct wiphy - wireless hardware description
- * @idx: the wiphy index assigned to this item
- * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
  * @reg_notifier: the driver's regulatory notification callback
  * @regd: the driver's regulatory domain, if one was requested via
  * 	the regulatory_hint() API. This can be used by the driver
@@ -1245,7 +1251,7 @@
  * @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold);
  *	-1 = fragmentation disabled, only odd values >= 256 used
  * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
- * @net: the network namespace this wiphy currently lives in
+ * @_net: the network namespace this wiphy currently lives in
  * @perm_addr: permanent MAC address of this device
  * @addr_mask: If the device supports multiple MAC addresses by masking,
  *	set this to a mask with variable bits set to 1, e.g. if the last
@@ -1258,6 +1264,28 @@
  *	by default for perm_addr. In this case, the mask should be set to
  *	all-zeroes. In this case it is assumed that the device can handle
  *	the same number of arbitrary MAC addresses.
+ * @debugfsdir: debugfs directory used for this wiphy, will be renamed
+ *	automatically on wiphy renames
+ * @dev: (virtual) struct device for this wiphy
+ * @wext: wireless extension handlers
+ * @priv: driver private data (sized according to wiphy_new() parameter)
+ * @interface_modes: bitmask of interfaces types valid for this wiphy,
+ *	must be set by driver
+ * @flags: wiphy flags, see &enum wiphy_flags
+ * @bss_priv_size: each BSS struct has private data allocated with it,
+ *	this variable determines its size
+ * @max_scan_ssids: maximum number of SSIDs the device can scan for in
+ *	any given scan
+ * @max_scan_ie_len: maximum length of user-controlled IEs device can
+ *	add to probe request frames transmitted during a scan, must not
+ *	include fixed IEs like supported rates
+ * @coverage_class: current coverage class
+ * @fw_version: firmware version for ethtool reporting
+ * @hw_version: hardware version for ethtool reporting
+ * @max_num_pmkids: maximum number of PMKIDs supported by device
+ * @privid: a pointer that drivers can use to identify if an arbitrary
+ *	wiphy is theirs, e.g. in global notifiers
+ * @bands: information about bands/channels supported by this device
  */
 struct wiphy {
 	/* assign these fields before you register the wiphy */
@@ -1330,26 +1358,15 @@
 	char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
 };
 
-#ifdef CONFIG_NET_NS
 static inline struct net *wiphy_net(struct wiphy *wiphy)
 {
-	return wiphy->_net;
+	return read_pnet(&wiphy->_net);
 }
 
 static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net)
 {
-	wiphy->_net = net;
+	write_pnet(&wiphy->_net, net);
 }
-#else
-static inline struct net *wiphy_net(struct wiphy *wiphy)
-{
-	return &init_net;
-}
-
-static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net)
-{
-}
-#endif
 
 /**
  * wiphy_priv - return priv from wiphy
@@ -1399,7 +1416,7 @@
  *
  * @wiphy: The wiphy whose name to return
  */
-static inline const char *wiphy_name(struct wiphy *wiphy)
+static inline const char *wiphy_name(const struct wiphy *wiphy)
 {
 	return dev_name(&wiphy->dev);
 }
@@ -1471,13 +1488,14 @@
  * @ssid: (private) Used by the internal configuration code
  * @ssid_len: (private) Used by the internal configuration code
  * @wext: (private) Used by the internal wireless extensions compat code
- * @wext_bssid: (private) Used by the internal wireless extensions compat code
  * @use_4addr: indicates 4addr mode is used on this interface, must be
  *	set by driver (if supported) on add_interface BEFORE registering the
  *	netdev and may otherwise be used by driver read-only, will be update
  *	by cfg80211 on change_interface
  * @action_registrations: list of registrations for action frames
  * @action_registrations_lock: lock for the list
+ * @mtx: mutex used to lock data in this struct
+ * @cleanup_work: work struct used for cleanup that can't be done directly
  */
 struct wireless_dev {
 	struct wiphy *wiphy;
@@ -1551,11 +1569,13 @@
 
 /**
  * ieee80211_channel_to_frequency - convert channel number to frequency
+ * @chan: channel number
  */
 extern int ieee80211_channel_to_frequency(int chan);
 
 /**
  * ieee80211_frequency_to_channel - convert frequency to channel number
+ * @freq: center frequency
  */
 extern int ieee80211_frequency_to_channel(int freq);
 
@@ -1570,6 +1590,8 @@
 							 int freq);
 /**
  * ieee80211_get_channel - get channel struct from wiphy for specified frequency
+ * @wiphy: the struct wiphy to get the channel for
+ * @freq: the center frequency of the channel
  */
 static inline struct ieee80211_channel *
 ieee80211_get_channel(struct wiphy *wiphy, int freq)
@@ -1630,9 +1652,6 @@
  * @is_radiotap_ns: indicates whether the current namespace is the default
  *	radiotap namespace or not
  *
- * @overrides: override standard radiotap fields
- * @n_overrides: number of overrides
- *
  * @_rtheader: pointer to the radiotap header we are walking through
  * @_max_length: length of radiotap header in cpu byte ordering
  * @_arg_index: next argument index
@@ -1933,6 +1952,10 @@
 			struct iw_request_info *info,
 			struct sockaddr *ap_addr, char *extra);
 
+int cfg80211_wext_siwpmksa(struct net_device *dev,
+			   struct iw_request_info *info,
+			   struct iw_point *data, char *extra);
+
 /*
  * callbacks for asynchronous cfg80211 methods, notification
  * functions and BSS handling helpers
@@ -1948,10 +1971,12 @@
 void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted);
 
 /**
- * cfg80211_inform_bss - inform cfg80211 of a new BSS
+ * cfg80211_inform_bss_frame - inform cfg80211 of a received BSS frame
  *
  * @wiphy: the wiphy reporting the BSS
- * @bss: the found BSS
+ * @channel: The channel the frame was received on
+ * @mgmt: the management frame (probe response or beacon)
+ * @len: length of the management frame
  * @signal: the signal strength, type depends on the wiphy's signal_type
  * @gfp: context flags
  *
@@ -1964,6 +1989,23 @@
 			  struct ieee80211_mgmt *mgmt, size_t len,
 			  s32 signal, gfp_t gfp);
 
+/**
+ * cfg80211_inform_bss - inform cfg80211 of a new BSS
+ *
+ * @wiphy: the wiphy reporting the BSS
+ * @channel: The channel the frame was received on
+ * @bssid: the BSSID of the BSS
+ * @timestamp: the TSF timestamp sent by the peer
+ * @capability: the capability field sent by the peer
+ * @beacon_interval: the beacon interval announced by the peer
+ * @ie: additional IEs sent by the peer
+ * @ielen: length of the additional IEs
+ * @signal: the signal strength, type depends on the wiphy's signal_type
+ * @gfp: context flags
+ *
+ * This informs cfg80211 that BSS information was found and
+ * the BSS should be updated/added.
+ */
 struct cfg80211_bss*
 cfg80211_inform_bss(struct wiphy *wiphy,
 		    struct ieee80211_channel *channel,
@@ -2378,4 +2420,67 @@
 			      enum nl80211_cqm_rssi_threshold_event rssi_event,
 			      gfp_t gfp);
 
+#ifdef __KERNEL__
+
+/* Logging, debugging and troubleshooting/diagnostic helpers. */
+
+/* wiphy_printk helpers, similar to dev_printk */
+
+#define wiphy_printk(level, wiphy, format, args...)		\
+	printk(level "%s: " format, wiphy_name(wiphy), ##args)
+#define wiphy_emerg(wiphy, format, args...)			\
+	wiphy_printk(KERN_EMERG, wiphy, format, ##args)
+#define wiphy_alert(wiphy, format, args...)			\
+	wiphy_printk(KERN_ALERT, wiphy, format, ##args)
+#define wiphy_crit(wiphy, format, args...)			\
+	wiphy_printk(KERN_CRIT, wiphy, format, ##args)
+#define wiphy_err(wiphy, format, args...)			\
+	wiphy_printk(KERN_ERR, wiphy, format, ##args)
+#define wiphy_warn(wiphy, format, args...)			\
+	wiphy_printk(KERN_WARNING, wiphy, format, ##args)
+#define wiphy_notice(wiphy, format, args...)			\
+	wiphy_printk(KERN_NOTICE, wiphy, format, ##args)
+#define wiphy_info(wiphy, format, args...)			\
+	wiphy_printk(KERN_INFO, wiphy, format, ##args)
+
+int wiphy_debug(const struct wiphy *wiphy, const char *format, ...)
+	__attribute__ ((format (printf, 2, 3)));
+
+#if defined(DEBUG)
+#define wiphy_dbg(wiphy, format, args...)			\
+	wiphy_printk(KERN_DEBUG, wiphy, format, ##args)
+#elif defined(CONFIG_DYNAMIC_DEBUG)
+#define wiphy_dbg(wiphy, format, args...)			\
+	dynamic_pr_debug("%s: " format,	wiphy_name(wiphy), ##args)
+#else
+#define wiphy_dbg(wiphy, format, args...)				\
+({									\
+	if (0)								\
+		wiphy_printk(KERN_DEBUG, wiphy, format, ##args);	\
+	0;								\
+})
+#endif
+
+#if defined(VERBOSE_DEBUG)
+#define wiphy_vdbg	wiphy_dbg
+#else
+
+#define wiphy_vdbg(wiphy, format, args...)				\
+({									\
+	if (0)								\
+		wiphy_printk(KERN_DEBUG, wiphy, format, ##args);	\
+		0;							\
+})
+#endif
+
+/*
+ * wiphy_WARN() acts like wiphy_printk(), but with the key difference
+ * of using a WARN/WARN_ON to get the message out, including the
+ * file/line information and a backtrace.
+ */
+#define wiphy_WARN(wiphy, format, args...)			\
+	WARN(1, "wiphy: %s\n" format, wiphy_name(wiphy), ##args);
+
+#endif
+
 #endif /* __NET_CFG80211_H */
diff --git a/include/net/dn_dev.h b/include/net/dn_dev.h
index 511a459..0916bbf 100644
--- a/include/net/dn_dev.h
+++ b/include/net/dn_dev.h
@@ -101,7 +101,7 @@
 	__le16 dstnode;
 	__le16 srcnode;
 	__u8   forward;
-} __attribute__((packed));
+} __packed;
 
 struct dn_long_packet {
 	__u8   msgflg;
@@ -115,7 +115,7 @@
 	__u8   visit_ct;
 	__u8   s_class;
 	__u8   pt;
-} __attribute__((packed));
+} __packed;
 
 /*------------------------- DRP - Routing messages ---------------------*/
 
@@ -132,7 +132,7 @@
 	__u8   mpd;
 	__u8   datalen;
 	__u8   data[2];
-} __attribute__((packed));
+} __packed;
 
 struct rtnode_hello_message {
 	__u8   msgflg;
@@ -144,7 +144,7 @@
 	__u8   area;
 	__le16  timer;
 	__u8   mpd;
-} __attribute__((packed));
+} __packed;
 
 
 extern void dn_dev_init(void);
diff --git a/include/net/dn_nsp.h b/include/net/dn_nsp.h
index 17d43d2..e43a289 100644
--- a/include/net/dn_nsp.h
+++ b/include/net/dn_nsp.h
@@ -74,18 +74,18 @@
 	__u8   msgflg;
 	__le16 dstaddr;
 	__le16 srcaddr;
-} __attribute__((packed));
+} __packed;
 
 struct nsp_data_opt_msg {
 	__le16 acknum;
 	__le16 segnum;
 	__le16 lsflgs;
-} __attribute__((packed));
+} __packed;
 
 struct nsp_data_opt_msg1 {
 	__le16 acknum;
 	__le16 segnum;
-} __attribute__((packed));
+} __packed;
 
 
 /* Acknowledgment Message (data/other data)                             */
@@ -94,13 +94,13 @@
 	__le16 dstaddr;
 	__le16 srcaddr;
 	__le16 acknum;
-} __attribute__((packed));
+} __packed;
 
 /* Connect Acknowledgment Message */
 struct  nsp_conn_ack_msg {
 	__u8 msgflg;
 	__le16 dstaddr;
-} __attribute__((packed));
+} __packed;
 
 
 /* Connect Initiate/Retransmit Initiate/Connect Confirm */
@@ -117,7 +117,7 @@
 #define NSP_FC_MASK   0x0c            /* FC type mask         */
 	__u8   info;
 	__le16 segsize;
-} __attribute__((packed));
+} __packed;
 
 /* Disconnect Initiate/Disconnect Confirm */
 struct  nsp_disconn_init_msg {
@@ -125,7 +125,7 @@
 	__le16 dstaddr;
 	__le16 srcaddr;
 	__le16 reason;
-} __attribute__((packed));
+} __packed;
 
 
 
@@ -135,7 +135,7 @@
 	__le16 grpcode;
 	__le16 usrcode;
 	__u8   dlen;
-} __attribute__((packed));
+} __packed;
 
 /*
  * A collection of functions for manipulating the sequence
diff --git a/include/net/dn_route.h b/include/net/dn_route.h
index 60c9f22..ccadab3 100644
--- a/include/net/dn_route.h
+++ b/include/net/dn_route.h
@@ -65,9 +65,7 @@
  * packets to the originating host.
  */
 struct dn_route {
-	union {
-		struct dst_entry dst;
-	} u;
+	struct dst_entry dst;
 
 	struct flowi fl;
 
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index eb551ba..f7dcd2c 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -68,26 +68,15 @@
 #endif
 };
 
-#ifdef CONFIG_NET_NS
 static inline struct net *genl_info_net(struct genl_info *info)
 {
-	return info->_net;
+	return read_pnet(&info->_net);
 }
 
 static inline void genl_info_net_set(struct genl_info *info, struct net *net)
 {
-	info->_net = net;
+	write_pnet(&info->_net, net);
 }
-#else
-static inline struct net *genl_info_net(struct genl_info *info)
-{
-	return &init_net;
-}
-
-static inline void genl_info_net_set(struct genl_info *info, struct net *net)
-{
-}
-#endif
 
 /**
  * struct genl_ops - generic netlink operations
diff --git a/include/net/inet_common.h b/include/net/inet_common.h
index 18c7732..22fac98 100644
--- a/include/net/inet_common.h
+++ b/include/net/inet_common.h
@@ -1,8 +1,8 @@
 #ifndef _INET_COMMON_H
 #define _INET_COMMON_H
 
-extern const struct proto_ops		inet_stream_ops;
-extern const struct proto_ops		inet_dgram_ops;
+extern const struct proto_ops inet_stream_ops;
+extern const struct proto_ops inet_dgram_ops;
 
 /*
  *	INET4 prototypes used by INET6
@@ -13,37 +13,28 @@
 struct sockaddr;
 struct socket;
 
-extern int			inet_release(struct socket *sock);
-extern int			inet_stream_connect(struct socket *sock,
-						    struct sockaddr * uaddr,
-						    int addr_len, int flags);
-extern int			inet_dgram_connect(struct socket *sock, 
-						   struct sockaddr * uaddr,
-						   int addr_len, int flags);
-extern int			inet_accept(struct socket *sock, 
-					    struct socket *newsock, int flags);
-extern int			inet_sendmsg(struct kiocb *iocb,
-					     struct socket *sock, 
-					     struct msghdr *msg, 
-					     size_t size);
-extern int			inet_shutdown(struct socket *sock, int how);
-extern int			inet_listen(struct socket *sock, int backlog);
-
-extern void			inet_sock_destruct(struct sock *sk);
-
-extern int			inet_bind(struct socket *sock, 
-					  struct sockaddr *uaddr, int addr_len);
-extern int			inet_getname(struct socket *sock, 
-					     struct sockaddr *uaddr, 
-					     int *uaddr_len, int peer);
-extern int			inet_ioctl(struct socket *sock, 
-					   unsigned int cmd, unsigned long arg);
-
-extern int			inet_ctl_sock_create(struct sock **sk,
-						     unsigned short family,
-						     unsigned short type,
-						     unsigned char protocol,
-						     struct net *net);
+extern int inet_release(struct socket *sock);
+extern int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
+			       int addr_len, int flags);
+extern int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr,
+			      int addr_len, int flags);
+extern int inet_accept(struct socket *sock, struct socket *newsock, int flags);
+extern int inet_sendmsg(struct kiocb *iocb, struct socket *sock,
+			struct msghdr *msg, size_t size);
+extern ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
+			     size_t size, int flags);
+extern int inet_recvmsg(struct kiocb *iocb, struct socket *sock,
+			struct msghdr *msg, size_t size, int flags);
+extern int inet_shutdown(struct socket *sock, int how);
+extern int inet_listen(struct socket *sock, int backlog);
+extern void inet_sock_destruct(struct sock *sk);
+extern int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len);
+extern int inet_getname(struct socket *sock, struct sockaddr *uaddr,
+			int *uaddr_len, int peer);
+extern int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+extern int inet_ctl_sock_create(struct sock **sk, unsigned short family,
+				unsigned short type, unsigned char protocol,
+				struct net *net);
 
 static inline void inet_ctl_sock_destroy(struct sock *sk)
 {
@@ -51,5 +42,3 @@
 }
 
 #endif
-
-
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 39f2dc9..16ff29a 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -20,6 +20,7 @@
 	atomic_t		refcnt;
 	struct timer_list	timer;      /* when will this queue expire? */
 	struct sk_buff		*fragments; /* list of received fragments */
+	struct sk_buff		*fragments_tail;
 	ktime_t			stamp;
 	int			len;        /* total length of orig datagram */
 	int			meat;
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index 1653de5..1989cfd 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -137,7 +137,8 @@
 				hdrincl:1,
 				mc_loop:1,
 				transparent:1,
-				mc_all:1;
+				mc_all:1,
+				nodefrag:1;
 	int			mc_index;
 	__be32			mc_addr;
 	struct ip_mc_socklist	*mc_list;
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index 87b1df0..417d0c8 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -22,10 +22,21 @@
 	__u32			dtime;		/* the time of last use of not
 						 * referenced entries */
 	atomic_t		refcnt;
-	atomic_t		rid;		/* Frag reception counter */
-	atomic_t		ip_id_count;	/* IP ID for the next packet */
-	__u32			tcp_ts;
-	__u32			tcp_ts_stamp;
+	/*
+	 * Once inet_peer is queued for deletion (refcnt == -1), following fields
+	 * are not available: rid, ip_id_count, tcp_ts, tcp_ts_stamp
+	 * We can share memory with rcu_head to keep inet_peer small
+	 * (less then 64 bytes)
+	 */
+	union {
+		struct {
+			atomic_t	rid;		/* Frag reception counter */
+			atomic_t	ip_id_count;	/* IP ID for the next packet */
+			__u32		tcp_ts;
+			__u32		tcp_ts_stamp;
+		};
+		struct rcu_head         rcu;
+	};
 };
 
 void			inet_initpeers(void) __init;
@@ -36,10 +47,21 @@
 /* can be called from BH context or outside */
 extern void inet_putpeer(struct inet_peer *p);
 
+/*
+ * temporary check to make sure we dont access rid, ip_id_count, tcp_ts,
+ * tcp_ts_stamp if no refcount is taken on inet_peer
+ */
+static inline void inet_peer_refcheck(const struct inet_peer *p)
+{
+	WARN_ON_ONCE(atomic_read(&p->refcnt) <= 0);
+}
+
+
 /* can be called with or without local BH being disabled */
 static inline __u16	inet_getid(struct inet_peer *p, int more)
 {
 	more++;
+	inet_peer_refcheck(p);
 	return atomic_add_return(more, &p->ip_id_count) - more;
 }
 
diff --git a/include/net/ip.h b/include/net/ip.h
index 452f229..890f972 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -61,11 +61,14 @@
 struct ip_ra_chain {
 	struct ip_ra_chain	*next;
 	struct sock		*sk;
-	void			(*destructor)(struct sock *);
+	union {
+		void			(*destructor)(struct sock *);
+		struct sock		*saved_sk;
+	};
+	struct rcu_head		rcu;
 };
 
 extern struct ip_ra_chain *ip_ra_chain;
-extern rwlock_t ip_ra_lock;
 
 /* IP flags. */
 #define IP_CE		0x8000		/* Flag: "Congestion"		*/
@@ -162,12 +165,12 @@
 };
 
 extern struct ipv4_config ipv4_config;
-#define IP_INC_STATS(net, field)	SNMP_INC_STATS((net)->mib.ip_statistics, field)
-#define IP_INC_STATS_BH(net, field)	SNMP_INC_STATS_BH((net)->mib.ip_statistics, field)
-#define IP_ADD_STATS(net, field, val)	SNMP_ADD_STATS((net)->mib.ip_statistics, field, val)
-#define IP_ADD_STATS_BH(net, field, val) SNMP_ADD_STATS_BH((net)->mib.ip_statistics, field, val)
-#define IP_UPD_PO_STATS(net, field, val) SNMP_UPD_PO_STATS((net)->mib.ip_statistics, field, val)
-#define IP_UPD_PO_STATS_BH(net, field, val) SNMP_UPD_PO_STATS_BH((net)->mib.ip_statistics, field, val)
+#define IP_INC_STATS(net, field)	SNMP_INC_STATS64((net)->mib.ip_statistics, field)
+#define IP_INC_STATS_BH(net, field)	SNMP_INC_STATS64_BH((net)->mib.ip_statistics, field)
+#define IP_ADD_STATS(net, field, val)	SNMP_ADD_STATS64((net)->mib.ip_statistics, field, val)
+#define IP_ADD_STATS_BH(net, field, val) SNMP_ADD_STATS64_BH((net)->mib.ip_statistics, field, val)
+#define IP_UPD_PO_STATS(net, field, val) SNMP_UPD_PO_STATS64((net)->mib.ip_statistics, field, val)
+#define IP_UPD_PO_STATS_BH(net, field, val) SNMP_UPD_PO_STATS64_BH((net)->mib.ip_statistics, field, val)
 #define NET_INC_STATS(net, field)	SNMP_INC_STATS((net)->mib.net_statistics, field)
 #define NET_INC_STATS_BH(net, field)	SNMP_INC_STATS_BH((net)->mib.net_statistics, field)
 #define NET_INC_STATS_USER(net, field) 	SNMP_INC_STATS_USER((net)->mib.net_statistics, field)
@@ -175,7 +178,15 @@
 #define NET_ADD_STATS_USER(net, field, adnd) SNMP_ADD_STATS_USER((net)->mib.net_statistics, field, adnd)
 
 extern unsigned long snmp_fold_field(void __percpu *mib[], int offt);
-extern int snmp_mib_init(void __percpu *ptr[2], size_t mibsize);
+#if BITS_PER_LONG==32
+extern u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t sync_off);
+#else
+static inline u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_off)
+{
+	return snmp_fold_field(mib, offt);
+}
+#endif
+extern int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align);
 extern void snmp_mib_free(void __percpu *ptr[2]);
 
 extern struct local_ports {
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 4b1dc11..062a823 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -84,13 +84,11 @@
 struct fib6_table;
 
 struct rt6_info {
-	union {
-		struct dst_entry	dst;
-	} u;
+	struct dst_entry		dst;
 
-#define rt6i_dev			u.dst.dev
-#define rt6i_nexthop			u.dst.neighbour
-#define rt6i_expires			u.dst.expires
+#define rt6i_dev			dst.dev
+#define rt6i_nexthop			dst.neighbour
+#define rt6i_expires			dst.expires
 
 	/*
 	 * Tail elements of dst_entry (__refcnt etc.)
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index fbf9d1c..fc94ec5 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -27,6 +27,6 @@
 	__u8 type;		/* type-code for option         */
 	__u8 length;		/* option length                */
 	__u8 encap_limit;	/* tunnel encapsulation limit   */
-} __attribute__ ((packed));
+} __packed;
 
 #endif
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index fe82b1e1..a4747a0 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -632,10 +632,22 @@
 (int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
  const union nf_inet_addr *d_addr, __be16 d_port);
 
+struct ip_vs_conn * ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
+					    struct ip_vs_protocol *pp,
+					    const struct ip_vs_iphdr *iph,
+					    unsigned int proto_off,
+					    int inverse);
+
 extern struct ip_vs_conn *ip_vs_conn_out_get
 (int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
  const union nf_inet_addr *d_addr, __be16 d_port);
 
+struct ip_vs_conn * ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb,
+					     struct ip_vs_protocol *pp,
+					     const struct ip_vs_iphdr *iph,
+					     unsigned int proto_off,
+					     int inverse);
+
 /* put back the conn without restarting its timer */
 static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
 {
@@ -736,8 +748,6 @@
 
 extern int ip_vs_app_pkt_out(struct ip_vs_conn *, struct sk_buff *skb);
 extern int ip_vs_app_pkt_in(struct ip_vs_conn *, struct sk_buff *skb);
-extern int ip_vs_skb_replace(struct sk_buff *skb, gfp_t pri,
-			     char *o_buf, int o_len, char *n_buf, int n_len);
 extern int ip_vs_app_init(void);
 extern void ip_vs_app_cleanup(void);
 
diff --git a/include/net/ipip.h b/include/net/ipip.h
index 11e8513..65caea8 100644
--- a/include/net/ipip.h
+++ b/include/net/ipip.h
@@ -50,7 +50,7 @@
 	int pkt_len = skb->len - skb_transport_offset(skb);		\
 									\
 	skb->ip_summed = CHECKSUM_NONE;					\
-	ip_select_ident(iph, &rt->u.dst, NULL);				\
+	ip_select_ident(iph, &rt->dst, NULL);				\
 									\
 	err = ip_local_out(skb);					\
 	if (likely(net_xmit_eval(err) == 0)) {				\
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 2600b69..1f84124 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -136,17 +136,17 @@
 /* MIBs */
 
 #define IP6_INC_STATS(net, idev,field)		\
-		_DEVINC(net, ipv6, , idev, field)
+		_DEVINC(net, ipv6, 64, idev, field)
 #define IP6_INC_STATS_BH(net, idev,field)	\
-		_DEVINC(net, ipv6, _BH, idev, field)
+		_DEVINC(net, ipv6, 64_BH, idev, field)
 #define IP6_ADD_STATS(net, idev,field,val)	\
-		_DEVADD(net, ipv6, , idev, field, val)
+		_DEVADD(net, ipv6, 64, idev, field, val)
 #define IP6_ADD_STATS_BH(net, idev,field,val)	\
-		_DEVADD(net, ipv6, _BH, idev, field, val)
+		_DEVADD(net, ipv6, 64_BH, idev, field, val)
 #define IP6_UPD_PO_STATS(net, idev,field,val)   \
-		_DEVUPD(net, ipv6, , idev, field, val)
+		_DEVUPD(net, ipv6, 64, idev, field, val)
 #define IP6_UPD_PO_STATS_BH(net, idev,field,val)   \
-		_DEVUPD(net, ipv6, _BH, idev, field, val)
+		_DEVUPD(net, ipv6, 64_BH, idev, field, val)
 #define ICMP6_INC_STATS(net, idev, field)	\
 		_DEVINC(net, icmpv6, , idev, field)
 #define ICMP6_INC_STATS_BH(net, idev, field)	\
@@ -551,6 +551,10 @@
 
 extern int ipv6_find_tlv(struct sk_buff *skb, int offset, int type);
 
+extern struct in6_addr *fl6_update_dst(struct flowi *fl,
+				       const struct ipv6_txoptions *opt,
+				       struct in6_addr *orig);
+
 /*
  *	socket options (ipv6_sockglue.c)
  */
diff --git a/include/net/ipx.h b/include/net/ipx.h
index ef51a66..05d7e4a 100644
--- a/include/net/ipx.h
+++ b/include/net/ipx.h
@@ -27,9 +27,9 @@
 #define IPX_MAX_PPROP_HOPS 8
 
 struct ipxhdr {
-	__be16			ipx_checksum __attribute__ ((packed));
+	__be16			ipx_checksum __packed;
 #define IPX_NO_CHECKSUM	cpu_to_be16(0xFFFF)
-	__be16			ipx_pktsize __attribute__ ((packed));
+	__be16			ipx_pktsize __packed;
 	__u8			ipx_tctrl;
 	__u8			ipx_type;
 #define IPX_TYPE_UNKNOWN	0x00
@@ -38,8 +38,8 @@
 #define IPX_TYPE_SPX		0x05	/* SPX protocol */
 #define IPX_TYPE_NCP		0x11	/* $lots for docs on this (SPIT) */
 #define IPX_TYPE_PPROP		0x14	/* complicated flood fill brdcast */
-	struct ipx_address	ipx_dest __attribute__ ((packed));
-	struct ipx_address	ipx_source __attribute__ ((packed));
+	struct ipx_address	ipx_dest __packed;
+	struct ipx_address	ipx_source __packed;
 };
 
 static __inline__ struct ipxhdr *ipx_hdr(struct sk_buff *skb)
diff --git a/include/net/irda/irda.h b/include/net/irda/irda.h
index 7e58206..3bed61d 100644
--- a/include/net/irda/irda.h
+++ b/include/net/irda/irda.h
@@ -53,10 +53,6 @@
 #ifndef IRDA_ALIGN
 #  define IRDA_ALIGN __attribute__((aligned))
 #endif
-#ifndef IRDA_PACK
-#  define IRDA_PACK __attribute__((packed))
-#endif
-
 
 #ifdef CONFIG_IRDA_DEBUG
 
diff --git a/include/net/irda/irlap_frame.h b/include/net/irda/irlap_frame.h
index 641f88e..6b1dc4f 100644
--- a/include/net/irda/irlap_frame.h
+++ b/include/net/irda/irlap_frame.h
@@ -85,7 +85,7 @@
 struct disc_frame {
 	__u8 caddr;          /* Connection address */
 	__u8 control;
-} IRDA_PACK;
+} __packed;
 
 struct xid_frame {
 	__u8  caddr; /* Connection address */
@@ -96,41 +96,41 @@
 	__u8  flags; /* Discovery flags */
 	__u8  slotnr;
 	__u8  version;
-} IRDA_PACK;
+} __packed;
 
 struct test_frame {
 	__u8 caddr;          /* Connection address */
 	__u8 control;
 	__le32 saddr;         /* Source device address */
 	__le32 daddr;         /* Destination device address */
-} IRDA_PACK;
+} __packed;
 
 struct ua_frame {
 	__u8 caddr;
 	__u8 control;
 	__le32 saddr; /* Source device address */
 	__le32 daddr; /* Dest device address */
-} IRDA_PACK;
+} __packed;
 
 struct dm_frame {
 	__u8 caddr;          /* Connection address */
 	__u8 control;
-} IRDA_PACK;
+} __packed;
 
 struct rd_frame {
 	__u8 caddr;          /* Connection address */
 	__u8 control;
-} IRDA_PACK;
+} __packed;
 
 struct rr_frame {
 	__u8 caddr;          /* Connection address */
 	__u8 control;
-} IRDA_PACK;
+} __packed;
 
 struct i_frame {
 	__u8 caddr;
 	__u8 control;
-} IRDA_PACK;
+} __packed;
 
 struct snrm_frame {
 	__u8  caddr;
@@ -138,7 +138,7 @@
 	__le32 saddr;
 	__le32 daddr;
 	__u8  ncaddr;
-} IRDA_PACK;
+} __packed;
 
 void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb);
 void irlap_send_discovery_xid_frame(struct irlap_cb *, int S, __u8 s, 
diff --git a/include/net/lib80211.h b/include/net/lib80211.h
index fb4e278..848cce1 100644
--- a/include/net/lib80211.h
+++ b/include/net/lib80211.h
@@ -54,9 +54,6 @@
 	/* 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
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index de22cbf..b0787a1 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -146,6 +146,9 @@
  *	enabled/disabled (beaconing modes)
  * @BSS_CHANGED_CQM: Connection quality monitor config changed
  * @BSS_CHANGED_IBSS: IBSS join status changed
+ * @BSS_CHANGED_ARP_FILTER: Hardware ARP filter address list or state changed.
+ * @BSS_CHANGED_QOS: QoS for this association was enabled/disabled. Note
+ *	that it is only ever disabled for station mode.
  */
 enum ieee80211_bss_change {
 	BSS_CHANGED_ASSOC		= 1<<0,
@@ -160,10 +163,19 @@
 	BSS_CHANGED_BEACON_ENABLED	= 1<<9,
 	BSS_CHANGED_CQM			= 1<<10,
 	BSS_CHANGED_IBSS		= 1<<11,
+	BSS_CHANGED_ARP_FILTER		= 1<<12,
+	BSS_CHANGED_QOS			= 1<<13,
 
 	/* when adding here, make sure to change ieee80211_reconfig */
 };
 
+/*
+ * The maximum number of IPv4 addresses listed for ARP filtering. If the number
+ * of addresses for an interface increase beyond this value, hardware ARP
+ * filtering will be disabled.
+ */
+#define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4
+
 /**
  * struct ieee80211_bss_conf - holds the BSS's changing parameters
  *
@@ -182,7 +194,9 @@
  *	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 beaconing,
- *	not valid in station mode (cf. hw conf ps_dtim_period)
+ *	valid in station mode only while @assoc is true and if also
+ *	requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf
+ *	@ps_dtim_period)
  * @timestamp: beacon timestamp
  * @beacon_int: beacon interval
  * @assoc_capability: capabilities taken from assoc resp
@@ -199,6 +213,16 @@
  * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
  *	implies disabled
  * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
+ * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
+ *	may filter ARP queries targeted for other addresses than listed here.
+ *	The driver must allow ARP queries targeted for all address listed here
+ *	to pass through. An empty list implies no ARP queries need to pass.
+ * @arp_addr_cnt: Number of addresses currently on the list.
+ * @arp_filter_enabled: Enable ARP filtering - if enabled, the hardware may
+ *	filter ARP queries based on the @arp_addr_list, if disabled, the
+ *	hardware must not perform any ARP filtering. Note, that the filter will
+ *	be enabled also in promiscuous mode.
+ * @qos: This is a QoS-enabled BSS.
  */
 struct ieee80211_bss_conf {
 	const u8 *bssid;
@@ -219,6 +243,10 @@
 	s32 cqm_rssi_thold;
 	u32 cqm_rssi_hyst;
 	enum nl80211_channel_type channel_type;
+	__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
+	u8 arp_addr_cnt;
+	bool arp_filter_enabled;
+	bool qos;
 };
 
 /**
@@ -312,9 +340,10 @@
 	IEEE80211_TX_INTFL_NL80211_FRAME_TX	= BIT(21),
 	IEEE80211_TX_CTL_LDPC			= BIT(22),
 	IEEE80211_TX_CTL_STBC			= BIT(23) | BIT(24),
-#define IEEE80211_TX_CTL_STBC_SHIFT		23
 };
 
+#define IEEE80211_TX_CTL_STBC_SHIFT		23
+
 /**
  * enum mac80211_rate_control_flags - per-rate flags set by the
  *	Rate Control algorithm.
@@ -390,7 +419,7 @@
 	s8 idx;
 	u8 count;
 	u8 flags;
-} __attribute__((packed));
+} __packed;
 
 /**
  * struct ieee80211_tx_info - skb transmit information
@@ -412,8 +441,6 @@
  * @driver_data: array of driver_data pointers
  * @ampdu_ack_len: number of acked aggregated frames.
  * 	relevant only if IEEE80211_TX_STAT_AMPDU was set.
- * @ampdu_ack_map: block ack bit map for the aggregation.
- * 	relevant only if IEEE80211_TX_STAT_AMPDU was set.
  * @ampdu_len: number of aggregated frames.
  * 	relevant only if IEEE80211_TX_STAT_AMPDU was set.
  * @ack_signal: signal strength of the ACK frame
@@ -448,10 +475,9 @@
 		struct {
 			struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
 			u8 ampdu_ack_len;
-			u64 ampdu_ack_map;
 			int ack_signal;
 			u8 ampdu_len;
-			/* 7 bytes free */
+			/* 15 bytes free */
 		} status;
 		struct {
 			struct ieee80211_tx_rate driver_rates[
@@ -601,15 +627,14 @@
  *	may turn the device off as much as possible. Typically, this flag will
  *	be set when an interface is set UP but not associated or scanning, but
  *	it can also be unset in that case when monitor interfaces are active.
- * @IEEE80211_CONF_QOS: Enable 802.11e QoS also know as WMM (Wireless
- *      Multimedia). On some drivers (iwlwifi is one of know) we have
- *      to enable/disable QoS explicitly.
+ * @IEEE80211_CONF_OFFCHANNEL: The device is currently not on its main
+ *	operating channel.
  */
 enum ieee80211_conf_flags {
 	IEEE80211_CONF_MONITOR		= (1<<0),
 	IEEE80211_CONF_PS		= (1<<1),
 	IEEE80211_CONF_IDLE		= (1<<2),
-	IEEE80211_CONF_QOS		= (1<<3),
+	IEEE80211_CONF_OFFCHANNEL	= (1<<3),
 };
 
 
@@ -624,7 +649,6 @@
  * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
  * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
  * @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed
- * @IEEE80211_CONF_CHANGE_QOS: Quality of service was enabled or disabled
  */
 enum ieee80211_conf_changed {
 	IEEE80211_CONF_CHANGE_SMPS		= BIT(1),
@@ -635,7 +659,6 @@
 	IEEE80211_CONF_CHANGE_CHANNEL		= BIT(6),
 	IEEE80211_CONF_CHANGE_RETRY_LIMITS	= BIT(7),
 	IEEE80211_CONF_CHANGE_IDLE		= BIT(8),
-	IEEE80211_CONF_CHANGE_QOS		= BIT(9),
 };
 
 /**
@@ -676,9 +699,6 @@
  * @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the
  *	powersave documentation below. This variable is valid only when
  *	the CONF_PS flag is set.
- * @dynamic_ps_forced_timeout: The dynamic powersave timeout (in ms) configured
- *	by cfg80211 (essentially, wext) If set, this value overrules the value
- *	chosen by mac80211 based on ps qos network latency.
  *
  * @power_level: requested transmit power (in dBm)
  *
@@ -698,7 +718,7 @@
  */
 struct ieee80211_conf {
 	u32 flags;
-	int power_level, dynamic_ps_timeout, dynamic_ps_forced_timeout;
+	int power_level, dynamic_ps_timeout;
 	int max_sleep_period;
 
 	u16 listen_interval;
@@ -815,7 +835,6 @@
  *	encrypted in hardware.
  * @alg: The key algorithm.
  * @flags: key flags, see &enum ieee80211_key_flags.
- * @ap_addr: AP's MAC address
  * @keyidx: the key index (0-3)
  * @keylen: key material length
  * @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte)
@@ -881,16 +900,12 @@
  * 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,
- * or if a associated station made a power state transition.
+ * indicates if an associated station made a power state transition.
  *
- * @STA_NOTIFY_ADD: (DEPRECATED) a station was added to the station table
- * @STA_NOTIFY_REMOVE: (DEPRECATED) 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_SLEEP, STA_NOTIFY_AWAKE,
 };
 
@@ -1014,6 +1029,9 @@
  *	connection quality related parameters, such as the RSSI level and
  *	provide notifications if configured trigger levels are reached.
  *
+ * @IEEE80211_HW_NEED_DTIM_PERIOD:
+ *	This device needs to know the DTIM period for the BSS before
+ *	associating.
  */
 enum ieee80211_hw_flags {
 	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0,
@@ -1023,7 +1041,7 @@
 	IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE	= 1<<4,
 	IEEE80211_HW_SIGNAL_UNSPEC			= 1<<5,
 	IEEE80211_HW_SIGNAL_DBM				= 1<<6,
-	/* use this hole */
+	IEEE80211_HW_NEED_DTIM_PERIOD			= 1<<7,
 	IEEE80211_HW_SPECTRUM_MGMT			= 1<<8,
 	IEEE80211_HW_AMPDU_AGGREGATION			= 1<<9,
 	IEEE80211_HW_SUPPORTS_PS			= 1<<10,
@@ -1260,6 +1278,15 @@
  * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS
  * enabled whenever user has enabled powersave.
  *
+ * Some hardware need to toggle a single shared antenna between WLAN and
+ * Bluetooth to facilitate co-existence. These types of hardware set
+ * limitations on the use of host controlled dynamic powersave whenever there
+ * is simultaneous WLAN and Bluetooth traffic. For these types of hardware, the
+ * driver may request temporarily going into full power save, in order to
+ * enable toggling the antenna between BT and WLAN. If the driver requests
+ * disabling dynamic powersave, the @dynamic_ps_timeout value will be
+ * temporarily set to zero until the driver re-enables dynamic powersave.
+ *
  * Driver informs U-APSD client support by enabling
  * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the
  * uapsd paramater in conf_tx() operation. Hardware needs to send the QoS
@@ -1451,7 +1478,7 @@
  *
  * Note that drivers MUST be able to deal with a TX aggregation
  * session being stopped even before they OK'ed starting it by
- * calling ieee80211_start_tx_ba_cb(_irqsafe), because the peer
+ * calling ieee80211_start_tx_ba_cb_irqsafe, because the peer
  * might receive the addBA frame and send a delBA right away!
  *
  * @IEEE80211_AMPDU_RX_START: start Rx aggregation
@@ -1636,7 +1663,7 @@
  * 	is the first frame we expect to perform the action on. Notice
  * 	that TX/RX_STOP can pass NULL for this parameter.
  *	Returns a negative error code on failure.
- *	The callback must be atomic.
+ *	The callback can sleep.
  *
  * @get_survey: Return per-channel survey information
  *
@@ -2307,25 +2334,14 @@
 int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid);
 
 /**
- * ieee80211_start_tx_ba_cb - low level driver ready to aggregate.
- * @vif: &struct ieee80211_vif pointer from the add_interface callback
- * @ra: receiver address of the BA session recipient.
- * @tid: the TID to BA on.
- *
- * This function must be called by low level driver once it has
- * finished with preparations for the BA session.
- */
-void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
-
-/**
  * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate.
  * @vif: &struct ieee80211_vif pointer from the add_interface callback
  * @ra: receiver address of the BA session recipient.
  * @tid: the TID to BA on.
  *
  * This function must be called by low level driver once it has
- * finished with preparations for the BA session.
- * This version of the function is IRQ-safe.
+ * finished with preparations for the BA session. It can be called
+ * from any context.
  */
 void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra,
 				      u16 tid);
@@ -2334,27 +2350,14 @@
  * ieee80211_stop_tx_ba_session - Stop a Block Ack session.
  * @sta: the station whose BA session to stop
  * @tid: the TID to stop BA.
- * @initiator: if indicates initiator DELBA frame will be sent.
  *
- * Return: error if no sta with matching da found, success otherwise
+ * Return: negative error if the TID is invalid, or no aggregation active
  *
  * Although mac80211/low level driver/user space application can estimate
  * the need to stop aggregation on a certain RA/TID, the session level
  * will be managed by the mac80211.
  */
-int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid,
-				 enum ieee80211_back_parties initiator);
-
-/**
- * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
- * @vif: &struct ieee80211_vif pointer from the add_interface callback
- * @ra: receiver address of the BA session recipient.
- * @tid: the desired TID to BA on.
- *
- * This function must be called by low level driver once it has
- * finished with preparations for the BA session tear down.
- */
-void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
+int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid);
 
 /**
  * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate.
@@ -2363,8 +2366,8 @@
  * @tid: the desired TID to BA on.
  *
  * This function must be called by low level driver once it has
- * finished with preparations for the BA session tear down.
- * This version of the function is IRQ-safe.
+ * finished with preparations for the BA session tear down. It
+ * can be called from any context.
  */
 void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra,
 				     u16 tid);
@@ -2460,6 +2463,36 @@
 void ieee80211_connection_loss(struct ieee80211_vif *vif);
 
 /**
+ * ieee80211_disable_dyn_ps - force mac80211 to temporarily disable dynamic psm
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * Some hardware require full power save to manage simultaneous BT traffic
+ * on the WLAN frequency. Full PSM is required periodically, whenever there are
+ * burst of BT traffic. The hardware gets information of BT traffic via
+ * hardware co-existence lines, and consequentially requests mac80211 to
+ * (temporarily) enter full psm.
+ * This function will only temporarily disable dynamic PS, not enable PSM if
+ * it was not already enabled.
+ * The driver must make sure to re-enable dynamic PS using
+ * ieee80211_enable_dyn_ps() if the driver has disabled it.
+ *
+ */
+void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif);
+
+/**
+ * ieee80211_enable_dyn_ps - restore dynamic psm after being disabled
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * This function restores dynamic PS after being temporarily disabled via
+ * ieee80211_disable_dyn_ps(). Each ieee80211_disable_dyn_ps() call must
+ * be coupled with an eventual call to this function.
+ *
+ */
+void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif);
+
+/**
  * ieee80211_cqm_rssi_notify - inform a configured connection quality monitoring
  *	rssi threshold triggered
  *
diff --git a/include/net/mip6.h b/include/net/mip6.h
index a83ad19..26ba99b 100644
--- a/include/net/mip6.h
+++ b/include/net/mip6.h
@@ -39,7 +39,7 @@
 	__u16	ip6mh_cksum;
 	/* Followed by type specific messages */
 	__u8	data[0];
-} __attribute__ ((__packed__));
+} __packed;
 
 #define IP6_MH_TYPE_BRR		0   /* Binding Refresh Request */
 #define IP6_MH_TYPE_HOTI	1   /* HOTI Message   */
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index f76f22d..895997b 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -82,7 +82,7 @@
 struct nd_opt_hdr {
 	__u8		nd_opt_type;
 	__u8		nd_opt_len;
-} __attribute__((__packed__));
+} __packed;
 
 
 extern int			ndisc_init(void);
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index eb21340..242879b 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -151,7 +151,7 @@
 	void			(*proxy_redo)(struct sk_buff *skb);
 	char			*id;
 	struct neigh_parms	parms;
-	/* HACK. gc_* shoul follow parms without a gap! */
+	/* HACK. gc_* should follow parms without a gap! */
 	int			gc_interval;
 	int			gc_thresh1;
 	int			gc_thresh2;
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index bde095f..e624dae 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -152,11 +152,7 @@
 
 static inline struct net *nf_ct_net(const struct nf_conn *ct)
 {
-#ifdef CONFIG_NET_NS
-	return ct->ct_net;
-#else
-	return &init_net;
-#endif
+	return read_pnet(&ct->ct_net);
 }
 
 /* Alter reply tuple (maybe alter helper). */
@@ -261,7 +257,12 @@
 			       u32 seq);
 
 /* Fake conntrack entry for untracked connections */
-extern struct nf_conn nf_conntrack_untracked;
+DECLARE_PER_CPU(struct nf_conn, nf_conntrack_untracked);
+static inline struct nf_conn *nf_ct_untracked_get(void)
+{
+	return &__raw_get_cpu_var(nf_conntrack_untracked);
+}
+extern void nf_ct_untracked_status_or(unsigned long bits);
 
 /* Iterate over all conntracks: if iter returns true, it's deleted. */
 extern void
@@ -289,9 +290,9 @@
 	return test_bit(IPS_DYING_BIT, &ct->status);
 }
 
-static inline int nf_ct_is_untracked(const struct sk_buff *skb)
+static inline int nf_ct_is_untracked(const struct nf_conn *ct)
 {
-	return (skb->nfct == &nf_conntrack_untracked.ct_general);
+	return test_bit(IPS_UNTRACKED_BIT, &ct->status);
 }
 
 extern int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp);
diff --git a/include/net/netfilter/nf_conntrack_acct.h b/include/net/netfilter/nf_conntrack_acct.h
index 03e218f..4e9c63a 100644
--- a/include/net/netfilter/nf_conntrack_acct.h
+++ b/include/net/netfilter/nf_conntrack_acct.h
@@ -45,6 +45,18 @@
 extern unsigned int
 seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir);
 
+/* Check if connection tracking accounting is enabled */
+static inline bool nf_ct_acct_enabled(struct net *net)
+{
+	return net->ct.sysctl_acct != 0;
+}
+
+/* Enable/disable connection tracking accounting */
+static inline void nf_ct_set_acct(struct net *net, bool enable)
+{
+	net->ct.sysctl_acct = enable;
+}
+
 extern int nf_conntrack_acct_init(struct net *net);
 extern void nf_conntrack_acct_fini(struct net *net);
 
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index 3d7524f..aced085 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -60,7 +60,7 @@
 	struct nf_conn *ct = (struct nf_conn *)skb->nfct;
 	int ret = NF_ACCEPT;
 
-	if (ct && ct != &nf_conntrack_untracked) {
+	if (ct && !nf_ct_is_untracked(ct)) {
 		if (!nf_ct_is_confirmed(ct))
 			ret = __nf_conntrack_confirm(skb);
 		if (likely(ret == NF_ACCEPT))
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
index 32d15bd..0772d29 100644
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -28,9 +28,14 @@
 	char data[0];
 };
 
-static inline int nf_ct_ext_exist(const struct nf_conn *ct, u8 id)
+static inline bool __nf_ct_ext_exist(const struct nf_ct_ext *ext, u8 id)
 {
-	return (ct->ext && ct->ext->offset[id]);
+	return !!ext->offset[id];
+}
+
+static inline bool nf_ct_ext_exist(const struct nf_conn *ct, u8 id)
+{
+	return (ct->ext && __nf_ct_ext_exist(ct->ext, id));
 }
 
 static inline void *__nf_ct_ext_find(const struct nf_conn *ct, u8 id)
diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h
index c398017..df17bac 100644
--- a/include/net/netfilter/nf_nat_protocol.h
+++ b/include/net/netfilter/nf_nat_protocol.h
@@ -27,9 +27,9 @@
 
 	/* Alter the per-proto part of the tuple (depending on
 	   maniptype), to give a unique tuple in the given range if
-	   possible; return false if not.  Per-protocol part of tuple
-	   is initialized to the incoming packet. */
-	bool (*unique_tuple)(struct nf_conntrack_tuple *tuple,
+	   possible.  Per-protocol part of tuple is initialized to the
+	   incoming packet. */
+	void (*unique_tuple)(struct nf_conntrack_tuple *tuple,
 			     const struct nf_nat_range *range,
 			     enum nf_nat_manip_type maniptype,
 			     const struct nf_conn *ct);
@@ -63,7 +63,7 @@
 				  const union nf_conntrack_man_proto *min,
 				  const union nf_conntrack_man_proto *max);
 
-extern bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
+extern void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
 				      const struct nf_nat_range *range,
 				      enum nf_nat_manip_type maniptype,
 				      const struct nf_conn *ct,
diff --git a/include/net/netfilter/nf_nat_rule.h b/include/net/netfilter/nf_nat_rule.h
index e4a18ae..2890bdc 100644
--- a/include/net/netfilter/nf_nat_rule.h
+++ b/include/net/netfilter/nf_nat_rule.h
@@ -12,6 +12,4 @@
 			    const struct net_device *out,
 			    struct nf_conn *ct);
 
-extern unsigned int
-alloc_null_binding(struct nf_conn *ct, unsigned int hooknum);
 #endif /* _NF_NAT_RULE_H */
diff --git a/include/net/netfilter/nfnetlink_log.h b/include/net/netfilter/nfnetlink_log.h
index b0569ff..e2dec42 100644
--- a/include/net/netfilter/nfnetlink_log.h
+++ b/include/net/netfilter/nfnetlink_log.h
@@ -10,5 +10,7 @@
 		  const struct nf_loginfo *li_user,
 		  const char *prefix);
 
+#define NFULNL_COPY_DISABLED    0xff
+
 #endif /* _KER_NFNETLINK_LOG_H */
 
diff --git a/include/net/netfilter/xt_rateest.h b/include/net/netfilter/xt_rateest.h
index ddbf37e..5a2978d 100644
--- a/include/net/netfilter/xt_rateest.h
+++ b/include/net/netfilter/xt_rateest.h
@@ -2,13 +2,18 @@
 #define _XT_RATEEST_H
 
 struct xt_rateest {
+	/* keep lock and bstats on same cache line to speedup xt_rateest_tg() */
+	struct gnet_stats_basic_packed	bstats;
+	spinlock_t			lock;
+	/* keep rstats and lock on same cache line to speedup xt_rateest_mt() */
+	struct gnet_stats_rate_est	rstats;
+
+	/* following fields not accessed in hot path */
 	struct hlist_node		list;
 	char				name[IFNAMSIZ];
 	unsigned int			refcnt;
-	spinlock_t			lock;
 	struct gnet_estimator		params;
-	struct gnet_stats_rate_est	rstats;
-	struct gnet_stats_basic_packed	bstats;
+	struct rcu_head			rcu;
 };
 
 extern struct xt_rateest *xt_rateest_lookup(const char *name);
diff --git a/include/net/netlink.h b/include/net/netlink.h
index 4fc05b5..f3b201d 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -35,7 +35,7 @@
  *   nlmsg_new()			create a new netlink message
  *   nlmsg_put()			add a netlink message to an skb
  *   nlmsg_put_answer()			callback based nlmsg_put()
- *   nlmsg_end()			finanlize netlink message
+ *   nlmsg_end()			finalize netlink message
  *   nlmsg_get_pos()			return current position in message
  *   nlmsg_trim()			trim part of message
  *   nlmsg_cancel()			cancel message construction
diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h
index d7b989c..2d16783 100644
--- a/include/net/phonet/pn_dev.h
+++ b/include/net/phonet/pn_dev.h
@@ -34,6 +34,7 @@
 	struct list_head list;
 	struct net_device *netdev;
 	DECLARE_BITMAP(addrs, 64);
+	struct rcu_head	rcu;
 };
 
 int phonet_device_init(void);
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index 9d4d87c..d9549af 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -95,7 +95,7 @@
 
 static inline void qdisc_run(struct Qdisc *q)
 {
-	if (!test_and_set_bit(__QDISC_STATE_RUNNING, &q->state))
+	if (qdisc_run_begin(q))
 		__qdisc_run(q);
 }
 
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index f873ee3..9e103a4 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -54,7 +54,6 @@
 	enum nl80211_reg_initiator initiator;
 	char alpha2[2];
 	bool intersect;
-	u32 country_ie_checksum;
 	enum environment_cap country_ie_env;
 	struct list_head list;
 };
diff --git a/include/net/route.h b/include/net/route.h
index af6cf4b..bd732d6 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -50,9 +50,7 @@
 struct fib_nh;
 struct inet_peer;
 struct rtable {
-	union {
-		struct dst_entry	dst;
-	} u;
+	struct dst_entry	dst;
 
 	/* Cache lookup keys */
 	struct flowi		fl;
@@ -144,7 +142,7 @@
 static inline void ip_rt_put(struct rtable * rt)
 {
 	if (rt)
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 }
 
 #define IPTOS_RT_MASK	(IPTOS_TOS_MASK & ~3)
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 433604b..3c8728a 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -23,11 +23,17 @@
 };
 
 enum qdisc_state_t {
-	__QDISC_STATE_RUNNING,
 	__QDISC_STATE_SCHED,
 	__QDISC_STATE_DEACTIVATED,
 };
 
+/*
+ * following bits are only changed while qdisc lock is held
+ */
+enum qdisc___state_t {
+	__QDISC___STATE_RUNNING,
+};
+
 struct qdisc_size_table {
 	struct list_head	list;
 	struct tc_sizespec	szopts;
@@ -72,10 +78,27 @@
 	unsigned long		state;
 	struct sk_buff_head	q;
 	struct gnet_stats_basic_packed bstats;
+	unsigned long		__state;
 	struct gnet_stats_queue	qstats;
-	struct rcu_head     rcu_head;
+	struct rcu_head		rcu_head;
+	spinlock_t		busylock;
 };
 
+static inline bool qdisc_is_running(struct Qdisc *qdisc)
+{
+	return test_bit(__QDISC___STATE_RUNNING, &qdisc->__state);
+}
+
+static inline bool qdisc_run_begin(struct Qdisc *qdisc)
+{
+	return !__test_and_set_bit(__QDISC___STATE_RUNNING, &qdisc->__state);
+}
+
+static inline void qdisc_run_end(struct Qdisc *qdisc)
+{
+	__clear_bit(__QDISC___STATE_RUNNING, &qdisc->__state);
+}
+
 struct Qdisc_class_ops {
 	/* Child qdisc manipulation */
 	struct netdev_queue *	(*select_queue)(struct Qdisc *, struct tcmsg *);
@@ -583,9 +606,16 @@
 }
 
 #ifdef CONFIG_NET_CLS_ACT
-static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask)
+static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask,
+					    int action)
 {
-	struct sk_buff *n = skb_clone(skb, gfp_mask);
+	struct sk_buff *n;
+
+	if ((action == TC_ACT_STOLEN || action == TC_ACT_QUEUED) &&
+	    !skb_shared(skb))
+		n = skb_get(skb);
+	else
+		n = skb_clone(skb, gfp_mask);
 
 	if (n) {
 		n->tc_verd = SET_TC_VERD(n->tc_verd, 0);
diff --git a/include/net/scm.h b/include/net/scm.h
index 8360e47..3165650 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -19,8 +19,10 @@
 };
 
 struct scm_cookie {
-	struct ucred		creds;		/* Skb credentials	*/
+	struct pid		*pid;		/* Skb credentials */
+	const struct cred	*cred;
 	struct scm_fp_list	*fp;		/* Passed files		*/
+	struct ucred		creds;		/* Skb credentials	*/
 #ifdef CONFIG_SECURITY_NETWORK
 	u32			secid;		/* Passed security ID 	*/
 #endif
@@ -42,8 +44,27 @@
 { }
 #endif /* CONFIG_SECURITY_NETWORK */
 
+static __inline__ void scm_set_cred(struct scm_cookie *scm,
+				    struct pid *pid, const struct cred *cred)
+{
+	scm->pid  = get_pid(pid);
+	scm->cred = get_cred(cred);
+	cred_to_ucred(pid, cred, &scm->creds);
+}
+
+static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
+{
+	put_pid(scm->pid);
+	scm->pid  = NULL;
+
+	if (scm->cred)
+		put_cred(scm->cred);
+	scm->cred = NULL;
+}
+
 static __inline__ void scm_destroy(struct scm_cookie *scm)
 {
+	scm_destroy_cred(scm);
 	if (scm && scm->fp)
 		__scm_destroy(scm);
 }
@@ -51,10 +72,7 @@
 static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
 			       struct scm_cookie *scm)
 {
-	struct task_struct *p = current;
-	scm->creds.uid = current_uid();
-	scm->creds.gid = current_gid();
-	scm->creds.pid = task_tgid_vnr(p);
+	scm_set_cred(scm, task_tgid(current), current_cred());
 	scm->fp = NULL;
 	unix_get_peersec_dgram(sock, scm);
 	if (msg->msg_controllen <= 0)
@@ -96,6 +114,8 @@
 	if (test_bit(SOCK_PASSCRED, &sock->flags))
 		put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds);
 
+	scm_destroy_cred(scm);
+
 	scm_passec(sock, msg, scm);
 
 	if (!scm->fp)
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 4b86011..f9e7473 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -443,7 +443,7 @@
 	__u8 signature[SCTP_SECRET_SIZE];
 	__u32 __pad;		/* force sctp_cookie alignment to 64 bits */
 	struct sctp_cookie c;
-} __attribute__((packed));
+} __packed;
 
 /* This is another convenience type to allocate memory for address
  * params for the maximum size and pass such structures around
@@ -488,7 +488,7 @@
 	union sctp_addr daddr;
 	unsigned long sent_at;
 	__u64 hb_nonce;
-} __attribute__((packed)) sctp_sender_hb_info_t;
+} __packed sctp_sender_hb_info_t;
 
 /*
  *  RFC 2960 1.3.2 Sequenced Delivery within Streams
diff --git a/include/net/snmp.h b/include/net/snmp.h
index 899003d..a0e6180 100644
--- a/include/net/snmp.h
+++ b/include/net/snmp.h
@@ -47,15 +47,16 @@
 }
 
 /*
- * We use all unsigned longs. Linux will soon be so reliable that even 
- * these will rapidly get too small 8-). Seriously consider the IpInReceives 
- * count on the 20Gb/s + networks people expect in a few years time!
+ * We use unsigned longs for most mibs but u64 for ipstats.
  */
+#include <linux/u64_stats_sync.h>
 
 /* IPstats */
 #define IPSTATS_MIB_MAX	__IPSTATS_MIB_MAX
 struct ipstats_mib {
-	unsigned long	mibs[IPSTATS_MIB_MAX];
+	/* mibs[] must be first field of struct ipstats_mib */
+	u64		mibs[IPSTATS_MIB_MAX];
+	struct u64_stats_sync syncp;
 };
 
 /* ICMP */
@@ -155,4 +156,70 @@
 		ptr->mibs[basefield##PKTS]++; \
 		ptr->mibs[basefield##OCTETS] += addend;\
 	} while (0)
+
+
+#if BITS_PER_LONG==32
+
+#define SNMP_ADD_STATS64_BH(mib, field, addend) 			\
+	do {								\
+		__typeof__(*mib[0]) *ptr = __this_cpu_ptr((mib)[0]);	\
+		u64_stats_update_begin(&ptr->syncp);			\
+		ptr->mibs[field] += addend;				\
+		u64_stats_update_end(&ptr->syncp);			\
+	} while (0)
+#define SNMP_ADD_STATS64_USER(mib, field, addend) 			\
+	do {								\
+		__typeof__(*mib[0]) *ptr;				\
+		preempt_disable();					\
+		ptr = __this_cpu_ptr((mib)[1]);				\
+		u64_stats_update_begin(&ptr->syncp);			\
+		ptr->mibs[field] += addend;				\
+		u64_stats_update_end(&ptr->syncp);			\
+		preempt_enable();					\
+	} while (0)
+#define SNMP_ADD_STATS64(mib, field, addend)				\
+	do {								\
+		__typeof__(*mib[0]) *ptr;				\
+		preempt_disable();					\
+		ptr = __this_cpu_ptr((mib)[!in_softirq()]);		\
+		u64_stats_update_begin(&ptr->syncp);			\
+		ptr->mibs[field] += addend;				\
+		u64_stats_update_end(&ptr->syncp);			\
+		preempt_enable();					\
+	} while (0)
+#define SNMP_INC_STATS64_BH(mib, field) SNMP_ADD_STATS64_BH(mib, field, 1)
+#define SNMP_INC_STATS64_USER(mib, field) SNMP_ADD_STATS64_USER(mib, field, 1)
+#define SNMP_INC_STATS64(mib, field) SNMP_ADD_STATS64(mib, field, 1)
+#define SNMP_UPD_PO_STATS64(mib, basefield, addend)			\
+	do {								\
+		__typeof__(*mib[0]) *ptr;				\
+		preempt_disable();					\
+		ptr = __this_cpu_ptr((mib)[!in_softirq()]);		\
+		u64_stats_update_begin(&ptr->syncp);			\
+		ptr->mibs[basefield##PKTS]++;				\
+		ptr->mibs[basefield##OCTETS] += addend;			\
+		u64_stats_update_end(&ptr->syncp);			\
+		preempt_enable();					\
+	} while (0)
+#define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend)			\
+	do {								\
+		__typeof__(*mib[0]) *ptr;				\
+		ptr = __this_cpu_ptr((mib)[!in_softirq()]);		\
+		u64_stats_update_begin(&ptr->syncp);			\
+		ptr->mibs[basefield##PKTS]++;				\
+		ptr->mibs[basefield##OCTETS] += addend;			\
+		u64_stats_update_end(&ptr->syncp);			\
+	} while (0)
+#else
+#define SNMP_INC_STATS64_BH(mib, field)		SNMP_INC_STATS_BH(mib, field)
+#define SNMP_INC_STATS64_USER(mib, field)	SNMP_INC_STATS_USER(mib, field)
+#define SNMP_INC_STATS64(mib, field)		SNMP_INC_STATS(mib, field)
+#define SNMP_DEC_STATS64(mib, field)		SNMP_DEC_STATS(mib, field)
+#define SNMP_ADD_STATS64_BH(mib, field, addend) SNMP_ADD_STATS_BH(mib, field, addend)
+#define SNMP_ADD_STATS64_USER(mib, field, addend) SNMP_ADD_STATS_USER(mib, field, addend)
+#define SNMP_ADD_STATS64(mib, field, addend)	SNMP_ADD_STATS(mib, field, addend)
+#define SNMP_UPD_PO_STATS64(mib, basefield, addend) SNMP_UPD_PO_STATS(mib, basefield, addend)
+#define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend) SNMP_UPD_PO_STATS_BH(mib, basefield, addend)
+#endif
+
 #endif
diff --git a/include/net/sock.h b/include/net/sock.h
index 0a691ea..a441c9c 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -295,7 +295,8 @@
 	unsigned short		sk_ack_backlog;
 	unsigned short		sk_max_ack_backlog;
 	__u32			sk_priority;
-	struct ucred		sk_peercred;
+	struct pid		*sk_peer_pid;
+	const struct cred	*sk_peer_cred;
 	long			sk_rcvtimeo;
 	long			sk_sndtimeo;
 	struct sk_filter      	*sk_filter;
@@ -771,6 +772,7 @@
 	int			*sysctl_wmem;
 	int			*sysctl_rmem;
 	int			max_header;
+	bool			no_autobind;
 
 	struct kmem_cache	*slab;
 	unsigned int		obj_size;
@@ -1706,19 +1708,13 @@
 static inline
 struct net *sock_net(const struct sock *sk)
 {
-#ifdef CONFIG_NET_NS
-	return sk->sk_net;
-#else
-	return &init_net;
-#endif
+	return read_pnet(&sk->sk_net);
 }
 
 static inline
 void sock_net_set(struct sock *sk, struct net *net)
 {
-#ifdef CONFIG_NET_NS
-	sk->sk_net = net;
-#endif
+	write_pnet(&sk->sk_net, net);
 }
 
 /*
diff --git a/include/net/tcp.h b/include/net/tcp.h
index a144914..df6a2eb 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -296,45 +296,30 @@
 #define TCP_ADD_STATS_USER(net, field, val) SNMP_ADD_STATS_USER((net)->mib.tcp_statistics, field, val)
 #define TCP_ADD_STATS(net, field, val)	SNMP_ADD_STATS((net)->mib.tcp_statistics, field, val)
 
-extern void			tcp_v4_err(struct sk_buff *skb, u32);
+extern void tcp_v4_err(struct sk_buff *skb, u32);
 
-extern void			tcp_shutdown (struct sock *sk, int how);
+extern void tcp_shutdown (struct sock *sk, int how);
 
-extern int			tcp_v4_rcv(struct sk_buff *skb);
+extern int tcp_v4_rcv(struct sk_buff *skb);
 
-extern int			tcp_v4_remember_stamp(struct sock *sk);
-
-extern int		    	tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
-
-extern int			tcp_sendmsg(struct kiocb *iocb, struct socket *sock,
-					    struct msghdr *msg, size_t size);
-extern ssize_t			tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags);
-
-extern int			tcp_ioctl(struct sock *sk, 
-					  int cmd, 
-					  unsigned long arg);
-
-extern int			tcp_rcv_state_process(struct sock *sk, 
-						      struct sk_buff *skb,
-						      struct tcphdr *th,
-						      unsigned len);
-
-extern int			tcp_rcv_established(struct sock *sk, 
-						    struct sk_buff *skb,
-						    struct tcphdr *th, 
-						    unsigned len);
-
-extern void			tcp_rcv_space_adjust(struct sock *sk);
-
-extern void			tcp_cleanup_rbuf(struct sock *sk, int copied);
-
-extern int			tcp_twsk_unique(struct sock *sk,
-						struct sock *sktw, void *twp);
-
-extern void			tcp_twsk_destructor(struct sock *sk);
-
-extern ssize_t			tcp_splice_read(struct socket *sk, loff_t *ppos,
-					        struct pipe_inode_info *pipe, size_t len, unsigned int flags);
+extern int tcp_v4_remember_stamp(struct sock *sk);
+extern int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
+extern int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		       size_t size);
+extern int tcp_sendpage(struct sock *sk, struct page *page, int offset,
+			size_t size, int flags);
+extern int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);
+extern int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
+				 struct tcphdr *th, unsigned len);
+extern int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
+			       struct tcphdr *th, unsigned len);
+extern void tcp_rcv_space_adjust(struct sock *sk);
+extern void tcp_cleanup_rbuf(struct sock *sk, int copied);
+extern int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);
+extern void tcp_twsk_destructor(struct sock *sk);
+extern ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
+			       struct pipe_inode_info *pipe, size_t len,
+			       unsigned int flags);
 
 static inline void tcp_dec_quickack_mode(struct sock *sk,
 					 const unsigned int pkts)
@@ -372,88 +357,59 @@
 };
 
 
-extern enum tcp_tw_status	tcp_timewait_state_process(struct inet_timewait_sock *tw,
-							   struct sk_buff *skb,
-							   const struct tcphdr *th);
-
-extern struct sock *		tcp_check_req(struct sock *sk,struct sk_buff *skb,
-					      struct request_sock *req,
-					      struct request_sock **prev);
-extern int			tcp_child_process(struct sock *parent,
-						  struct sock *child,
-						  struct sk_buff *skb);
-extern int			tcp_use_frto(struct sock *sk);
-extern void			tcp_enter_frto(struct sock *sk);
-extern void			tcp_enter_loss(struct sock *sk, int how);
-extern void			tcp_clear_retrans(struct tcp_sock *tp);
-extern void			tcp_update_metrics(struct sock *sk);
-
-extern void			tcp_close(struct sock *sk, 
-					  long timeout);
-extern unsigned int		tcp_poll(struct file * file, struct socket *sock, struct poll_table_struct *wait);
-
-extern int			tcp_getsockopt(struct sock *sk, int level, 
-					       int optname,
-					       char __user *optval, 
-					       int __user *optlen);
-extern int			tcp_setsockopt(struct sock *sk, int level, 
-					       int optname, char __user *optval, 
-					       unsigned int optlen);
-extern int			compat_tcp_getsockopt(struct sock *sk,
-					int level, int optname,
-					char __user *optval, int __user *optlen);
-extern int			compat_tcp_setsockopt(struct sock *sk,
-					int level, int optname,
-					char __user *optval, unsigned int optlen);
-extern void			tcp_set_keepalive(struct sock *sk, int val);
-extern void			tcp_syn_ack_timeout(struct sock *sk,
-						    struct request_sock *req);
-extern int			tcp_recvmsg(struct kiocb *iocb, struct sock *sk,
-					    struct msghdr *msg,
-					    size_t len, int nonblock, 
-					    int flags, int *addr_len);
-
-extern void			tcp_parse_options(struct sk_buff *skb,
-						  struct tcp_options_received *opt_rx,
-						  u8 **hvpp,
-						  int estab);
-
-extern u8			*tcp_parse_md5sig_option(struct tcphdr *th);
+extern enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
+						     struct sk_buff *skb,
+						     const struct tcphdr *th);
+extern struct sock * tcp_check_req(struct sock *sk,struct sk_buff *skb,
+				   struct request_sock *req,
+				   struct request_sock **prev);
+extern int tcp_child_process(struct sock *parent, struct sock *child,
+			     struct sk_buff *skb);
+extern int tcp_use_frto(struct sock *sk);
+extern void tcp_enter_frto(struct sock *sk);
+extern void tcp_enter_loss(struct sock *sk, int how);
+extern void tcp_clear_retrans(struct tcp_sock *tp);
+extern void tcp_update_metrics(struct sock *sk);
+extern void tcp_close(struct sock *sk, long timeout);
+extern unsigned int tcp_poll(struct file * file, struct socket *sock,
+			     struct poll_table_struct *wait);
+extern int tcp_getsockopt(struct sock *sk, int level, int optname,
+			  char __user *optval, int __user *optlen);
+extern int tcp_setsockopt(struct sock *sk, int level, int optname,
+			  char __user *optval, unsigned int optlen);
+extern int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
+				 char __user *optval, int __user *optlen);
+extern int compat_tcp_setsockopt(struct sock *sk, int level, int optname,
+				 char __user *optval, unsigned int optlen);
+extern void tcp_set_keepalive(struct sock *sk, int val);
+extern void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req);
+extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		       size_t len, int nonblock, int flags, int *addr_len);
+extern void tcp_parse_options(struct sk_buff *skb,
+			      struct tcp_options_received *opt_rx, u8 **hvpp,
+			      int estab);
+extern u8 *tcp_parse_md5sig_option(struct tcphdr *th);
 
 /*
  *	TCP v4 functions exported for the inet6 API
  */
 
-extern void		       	tcp_v4_send_check(struct sock *sk,
-						  struct sk_buff *skb);
-
-extern int			tcp_v4_conn_request(struct sock *sk,
-						    struct sk_buff *skb);
-
-extern struct sock *		tcp_create_openreq_child(struct sock *sk,
-							 struct request_sock *req,
-							 struct sk_buff *skb);
-
-extern struct sock *		tcp_v4_syn_recv_sock(struct sock *sk,
-						     struct sk_buff *skb,
-						     struct request_sock *req,
-							struct dst_entry *dst);
-
-extern int			tcp_v4_do_rcv(struct sock *sk,
+extern void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb);
+extern int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
+extern struct sock * tcp_create_openreq_child(struct sock *sk,
+					      struct request_sock *req,
 					      struct sk_buff *skb);
-
-extern int			tcp_v4_connect(struct sock *sk,
-					       struct sockaddr *uaddr,
-					       int addr_len);
-
-extern int			tcp_connect(struct sock *sk);
-
-extern struct sk_buff *		tcp_make_synack(struct sock *sk,
-						struct dst_entry *dst,
-						struct request_sock *req,
-						struct request_values *rvp);
-
-extern int			tcp_disconnect(struct sock *sk, int flags);
+extern struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
+					  struct request_sock *req,
+					  struct dst_entry *dst);
+extern int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb);
+extern int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
+			  int addr_len);
+extern int tcp_connect(struct sock *sk);
+extern struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
+					struct request_sock *req,
+					struct request_values *rvp);
+extern int tcp_disconnect(struct sock *sk, int flags);
 
 
 /* From syncookies.c */
@@ -464,7 +420,7 @@
 				     __u16 *mss);
 
 extern __u32 cookie_init_timestamp(struct request_sock *req);
-extern void cookie_check_timestamp(struct tcp_options_received *tcp_opt);
+extern bool cookie_check_timestamp(struct tcp_options_received *opt, bool *);
 
 /* From net/ipv6/syncookies.c */
 extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb);
@@ -485,10 +441,10 @@
 
 extern void tcp_send_probe0(struct sock *);
 extern void tcp_send_partial(struct sock *);
-extern int  tcp_write_wakeup(struct sock *);
+extern int tcp_write_wakeup(struct sock *);
 extern void tcp_send_fin(struct sock *sk);
 extern void tcp_send_active_reset(struct sock *sk, gfp_t priority);
-extern int  tcp_send_synack(struct sock *);
+extern int tcp_send_synack(struct sock *);
 extern void tcp_push_one(struct sock *, unsigned int mss_now);
 extern void tcp_send_ack(struct sock *sk);
 extern void tcp_send_delayed_ack(struct sock *sk);
@@ -592,7 +548,7 @@
  * scaling applied to the result.  The caller does these things
  * if necessary.  This is a "raw" window selection.
  */
-extern u32	__tcp_select_window(struct sock *sk);
+extern u32 __tcp_select_window(struct sock *sk);
 
 /* TCP timestamps are only 32-bits, this causes a slight
  * complication on 64-bit systems since we store a snapshot
@@ -602,12 +558,22 @@
  */
 #define tcp_time_stamp		((__u32)(jiffies))
 
+#define tcp_flag_byte(th) (((u_int8_t *)th)[13])
+
+#define TCPHDR_FIN 0x01
+#define TCPHDR_SYN 0x02
+#define TCPHDR_RST 0x04
+#define TCPHDR_PSH 0x08
+#define TCPHDR_ACK 0x10
+#define TCPHDR_URG 0x20
+#define TCPHDR_ECE 0x40
+#define TCPHDR_CWR 0x80
+
 /* This is what the send packet queuing engine uses to pass
- * TCP per-packet control information to the transmission
- * code.  We also store the host-order sequence numbers in
- * here too.  This is 36 bytes on 32-bit architectures,
- * 40 bytes on 64-bit machines, if this grows please adjust
- * skbuff.h:skbuff->cb[xxx] size appropriately.
+ * TCP per-packet control information to the transmission code.
+ * We also store the host-order sequence numbers in here too.
+ * This is 44 bytes if IPV6 is enabled.
+ * If this grows please adjust skbuff.h:skbuff->cb[xxx] size appropriately.
  */
 struct tcp_skb_cb {
 	union {
@@ -620,19 +586,6 @@
 	__u32		end_seq;	/* SEQ + FIN + SYN + datalen	*/
 	__u32		when;		/* used to compute rtt's	*/
 	__u8		flags;		/* TCP header flags.		*/
-
-	/* NOTE: These must match up to the flags byte in a
-	 *       real TCP header.
-	 */
-#define TCPCB_FLAG_FIN		0x01
-#define TCPCB_FLAG_SYN		0x02
-#define TCPCB_FLAG_RST		0x04
-#define TCPCB_FLAG_PSH		0x08
-#define TCPCB_FLAG_ACK		0x10
-#define TCPCB_FLAG_URG		0x20
-#define TCPCB_FLAG_ECE		0x40
-#define TCPCB_FLAG_CWR		0x80
-
 	__u8		sacked;		/* State flags for SACK/FACK.	*/
 #define TCPCB_SACKED_ACKED	0x01	/* SKB ACK'd by a SACK block	*/
 #define TCPCB_SACKED_RETRANS	0x02	/* SKB retransmitted		*/
@@ -1176,22 +1129,14 @@
 #define TCP_MD5SIG_MAXKEYS	(~(u32)0)	/* really?! */
 
 /* - functions */
-extern int			tcp_v4_md5_hash_skb(char *md5_hash,
-						    struct tcp_md5sig_key *key,
-						    struct sock *sk,
-						    struct request_sock *req,
-						    struct sk_buff *skb);
-
-extern struct tcp_md5sig_key	*tcp_v4_md5_lookup(struct sock *sk,
-						   struct sock *addr_sk);
-
-extern int			tcp_v4_md5_do_add(struct sock *sk,
-						  __be32 addr,
-						  u8 *newkey,
-						  u8 newkeylen);
-
-extern int			tcp_v4_md5_do_del(struct sock *sk,
-						  __be32 addr);
+extern int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
+			       struct sock *sk, struct request_sock *req,
+			       struct sk_buff *skb);
+extern struct tcp_md5sig_key * tcp_v4_md5_lookup(struct sock *sk,
+						 struct sock *addr_sk);
+extern int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, u8 *newkey,
+			     u8 newkeylen);
+extern int tcp_v4_md5_do_del(struct sock *sk, __be32 addr);
 
 #ifdef CONFIG_TCP_MD5SIG
 #define tcp_twsk_md5_key(twsk)	((twsk)->tw_md5_keylen ? 		 \
@@ -1204,10 +1149,10 @@
 #endif
 
 extern struct tcp_md5sig_pool * __percpu *tcp_alloc_md5sig_pool(struct sock *);
-extern void			tcp_free_md5sig_pool(void);
+extern void tcp_free_md5sig_pool(void);
 
 extern struct tcp_md5sig_pool	*tcp_get_md5sig_pool(void);
-extern void			tcp_put_md5sig_pool(void);
+extern void tcp_put_md5sig_pool(void);
 
 extern int tcp_md5_hash_header(struct tcp_md5sig_pool *, struct tcphdr *);
 extern int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, struct sk_buff *,
@@ -1413,7 +1358,8 @@
 	sa_family_t		family;
 	enum tcp_seq_states	state;
 	struct sock		*syn_wait_sk;
-	int			bucket, sbucket, num, uid;
+	int			bucket, offset, sbucket, num, uid;
+	loff_t			last_pos;
 };
 
 extern int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo);
@@ -1434,7 +1380,7 @@
 extern int tcp4_gro_complete(struct sk_buff *skb);
 
 #ifdef CONFIG_PROC_FS
-extern int  tcp4_proc_init(void);
+extern int tcp4_proc_init(void);
 extern void tcp4_proc_exit(void);
 #endif
 
diff --git a/include/net/udp.h b/include/net/udp.h
index 5348d80..7abdf30 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -157,30 +157,28 @@
 	sk_common_release(sk);
 }
 
-extern int	udp_lib_get_port(struct sock *sk, unsigned short snum,
-		int (*)(const struct sock *,const struct sock *),
-		unsigned int hash2_nulladdr);
+extern int udp_lib_get_port(struct sock *sk, unsigned short snum,
+			    int (*)(const struct sock *,const struct sock *),
+			    unsigned int hash2_nulladdr);
 
 /* net/ipv4/udp.c */
-extern int	udp_get_port(struct sock *sk, unsigned short snum,
-			     int (*saddr_cmp)(const struct sock *, const struct sock *));
-extern void	udp_err(struct sk_buff *, u32);
-
-extern int	udp_sendmsg(struct kiocb *iocb, struct sock *sk,
+extern int udp_get_port(struct sock *sk, unsigned short snum,
+			int (*saddr_cmp)(const struct sock *,
+					 const struct sock *));
+extern void udp_err(struct sk_buff *, u32);
+extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk,
 			    struct msghdr *msg, size_t len);
-extern void	udp_flush_pending_frames(struct sock *sk);
-
-extern int	udp_rcv(struct sk_buff *skb);
-extern int	udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
-extern int	udp_disconnect(struct sock *sk, int flags);
+extern void udp_flush_pending_frames(struct sock *sk);
+extern int udp_rcv(struct sk_buff *skb);
+extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
+extern int udp_disconnect(struct sock *sk, int flags);
 extern unsigned int udp_poll(struct file *file, struct socket *sock,
 			     poll_table *wait);
-extern int 	udp_lib_getsockopt(struct sock *sk, int level, int optname,
-			           char __user *optval, int __user *optlen);
-extern int 	udp_lib_setsockopt(struct sock *sk, int level, int optname,
-				   char __user *optval, unsigned int optlen,
-				   int (*push_pending_frames)(struct sock *));
-
+extern int udp_lib_getsockopt(struct sock *sk, int level, int optname,
+			      char __user *optval, int __user *optlen);
+extern int udp_lib_setsockopt(struct sock *sk, int level, int optname,
+			      char __user *optval, unsigned int optlen,
+			      int (*push_pending_frames)(struct sock *));
 extern struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
 				    __be32 daddr, __be16 dport,
 				    int dif);
@@ -236,7 +234,7 @@
 extern int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo);
 extern void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo);
 
-extern int  udp4_proc_init(void);
+extern int udp4_proc_init(void);
 extern void udp4_proc_exit(void);
 #endif
 
diff --git a/include/rxrpc/packet.h b/include/rxrpc/packet.h
index b69e6e1..9b2c308 100644
--- a/include/rxrpc/packet.h
+++ b/include/rxrpc/packet.h
@@ -65,7 +65,7 @@
 	};
 	__be16		serviceId;	/* service ID */
 
-} __attribute__((packed));
+} __packed;
 
 #define __rxrpc_header_off(X) offsetof(struct rxrpc_header,X)
 
@@ -120,7 +120,7 @@
 #define RXRPC_ACK_TYPE_NACK		0
 #define RXRPC_ACK_TYPE_ACK		1
 
-} __attribute__((packed));
+} __packed;
 
 /*
  * ACK packets can have a further piece of information tagged on the end
@@ -141,7 +141,7 @@
 	__be32		nonce;		/* encrypted random number */
 	__be32		min_level;	/* minimum security level */
 	__be32		__padding;	/* padding to 8-byte boundary */
-} __attribute__((packed));
+} __packed;
 
 /*****************************************************************************/
 /*
@@ -164,7 +164,7 @@
 
 	__be32		kvno;		/* Kerberos key version number */
 	__be32		ticket_len;	/* Kerberos ticket length  */
-} __attribute__((packed));
+} __packed;
 
 /*****************************************************************************/
 /*
diff --git a/include/scsi/fc/fc_els.h b/include/scsi/fc/fc_els.h
index f943281..481abbd 100644
--- a/include/scsi/fc/fc_els.h
+++ b/include/scsi/fc/fc_els.h
@@ -191,6 +191,7 @@
 	ELS_RJT_UNAB =		0x09,	/* unable to perform command request */
 	ELS_RJT_UNSUP =		0x0b,	/* command not supported */
 	ELS_RJT_INPROG =	0x0e,	/* command already in progress */
+	ELS_RJT_FIP =		0x20,	/* FIP error */
 	ELS_RJT_VENDOR =	0xff,	/* vendor specific error */
 };
 
@@ -212,6 +213,7 @@
 	ELS_EXPL_UNAB_DATA =	0x2a,	/* unable to supply requested data */
 	ELS_EXPL_UNSUPR =	0x2c,	/* Request not supported */
 	ELS_EXPL_INV_LEN =	0x2d,	/* Invalid payload length */
+	ELS_EXPL_NOT_NEIGHBOR = 0x62,	/* VN2VN_Port not in neighbor set */
 	/* TBD - above definitions incomplete */
 };
 
@@ -405,6 +407,15 @@
 };
 
 /*
+ * ELS_PRLO - Process logout request and response.
+ */
+struct fc_els_prlo {
+	__u8            prlo_cmd;       /* command */
+	__u8            prlo_obs;       /* obsolete, but shall be set to 10h */
+	__be16          prlo_len;       /* payload length */
+};
+
+/*
  * ELS_ADISC payload
  */
 struct fc_els_adisc {
diff --git a/include/scsi/fc/fc_fcoe.h b/include/scsi/fc/fc_fcoe.h
index e6ad3d2..d5dcd60 100644
--- a/include/scsi/fc/fc_fcoe.h
+++ b/include/scsi/fc/fc_fcoe.h
@@ -22,23 +22,18 @@
 
 /*
  * FCoE - Fibre Channel over Ethernet.
+ * See T11 FC-BB-5 Rev 2.00 (09-056v5.pdf)
  */
 
 /*
- * FC_FCOE_OUI hasn't been standardized yet.   XXX TBD.
+ * Default FC_FCOE_OUI / FC-MAP value.
  */
-#ifndef FC_FCOE_OUI
-#define	FC_FCOE_OUI	0x0efc00	/* upper 24 bits of FCOE dest MAC TBD */
-#endif
+#define	FC_FCOE_OUI	0x0efc00	/* upper 24 bits of FCOE MAC */
 
 /*
- * The destination MAC address for the fabric login may get a different OUI.
- * This isn't standardized yet.
+ * Fabric Login (FLOGI) MAC for non-FIP use.  Non-FIP use is deprecated.
  */
-#ifndef FC_FCOE_FLOGI_MAC
-/* gateway MAC - TBD */
 #define	FC_FCOE_FLOGI_MAC { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe }
-#endif
 
 #define	FC_FCOE_VER	0			/* version */
 
@@ -51,8 +46,6 @@
 
 /*
  * FCoE frame header - 14 bytes
- *
- * This is the August 2007 version of the FCoE header as defined by T11.
  * This follows the VLAN header, which includes the ethertype.
  */
 struct fcoe_hdr {
diff --git a/include/scsi/fc/fc_fip.h b/include/scsi/fc/fc_fip.h
index 17baa19..ae25d4a 100644
--- a/include/scsi/fc/fc_fip.h
+++ b/include/scsi/fc/fc_fip.h
@@ -17,9 +17,12 @@
 #ifndef _FC_FIP_H_
 #define _FC_FIP_H_
 
+#include <scsi/fc/fc_ns.h>
+
 /*
  * This version is based on:
  * http://www.t11.org/ftp/t11/pub/fc/bb-5/08-543v1.pdf
+ * and T11 FC-BB-6 10-019v4.pdf (June 2010 VN2VN proposal)
  */
 
 #define FIP_DEF_PRI	128	/* default selection priority */
@@ -29,11 +32,24 @@
 #define FIP_FCF_FUZZ	100	/* random time added by FCF (mS) */
 
 /*
+ * VN2VN proposed-standard values.
+ */
+#define FIP_VN_FC_MAP	0x0efd00 /* MAC OUI for VN2VN use */
+#define FIP_VN_PROBE_WAIT 100	/* interval between VN2VN probes (ms) */
+#define FIP_VN_ANN_WAIT 400	/* interval between VN2VN announcements (ms) */
+#define FIP_VN_RLIM_INT 10000	/* interval between probes when rate limited */
+#define FIP_VN_RLIM_COUNT 10	/* number of probes before rate limiting */
+#define FIP_VN_BEACON_INT 8000	/* interval between VN2VN beacons */
+#define FIP_VN_BEACON_FUZZ 100	/* random time to add to beacon period (ms) */
+
+/*
  * Multicast MAC addresses.  T11-adopted.
  */
-#define FIP_ALL_FCOE_MACS	((u8[6]) { 1, 0x10, 0x18, 1, 0, 0 })
-#define FIP_ALL_ENODE_MACS	((u8[6]) { 1, 0x10, 0x18, 1, 0, 1 })
-#define FIP_ALL_FCF_MACS	((u8[6]) { 1, 0x10, 0x18, 1, 0, 2 })
+#define FIP_ALL_FCOE_MACS	((__u8[6]) { 1, 0x10, 0x18, 1, 0, 0 })
+#define FIP_ALL_ENODE_MACS	((__u8[6]) { 1, 0x10, 0x18, 1, 0, 1 })
+#define FIP_ALL_FCF_MACS	((__u8[6]) { 1, 0x10, 0x18, 1, 0, 2 })
+#define FIP_ALL_VN2VN_MACS	((__u8[6]) { 1, 0x10, 0x18, 1, 0, 4 })
+#define FIP_ALL_P2P_MACS	((__u8[6]) { 1, 0x10, 0x18, 1, 0, 5 })
 
 #define FIP_VER		1		/* version for fip_header */
 
@@ -60,6 +76,7 @@
 	FIP_OP_LS =	2,		/* Link Service request or reply */
 	FIP_OP_CTRL =	3,		/* Keep Alive / Link Reset */
 	FIP_OP_VLAN =	4,		/* VLAN discovery */
+	FIP_OP_VN2VN =	5,		/* VN2VN operation */
 	FIP_OP_VENDOR_MIN = 0xfff8,	/* min vendor-specific opcode */
 	FIP_OP_VENDOR_MAX = 0xfffe,	/* max vendor-specific opcode */
 };
@@ -97,11 +114,23 @@
 };
 
 /*
+ * Subcodes for FIP_OP_VN2VN.
+ */
+enum fip_vn2vn_subcode {
+	FIP_SC_VN_PROBE_REQ = 1,	/* probe request */
+	FIP_SC_VN_PROBE_REP = 2,	/* probe reply */
+	FIP_SC_VN_CLAIM_NOTIFY = 3,	/* claim notification */
+	FIP_SC_VN_CLAIM_REP = 4,	/* claim response */
+	FIP_SC_VN_BEACON = 5,		/* beacon */
+};
+
+/*
  * flags in header fip_flags.
  */
 enum fip_flag {
 	FIP_FL_FPMA =	0x8000,		/* supports FPMA fabric-provided MACs */
 	FIP_FL_SPMA =	0x4000,		/* supports SPMA server-provided MACs */
+	FIP_FL_REC_OR_P2P = 0x0008,	/* configured addr or point-to-point */
 	FIP_FL_AVAIL =	0x0004,		/* available for FLOGI/ELP */
 	FIP_FL_SOL =	0x0002,		/* this is a solicited message */
 	FIP_FL_FPORT =	0x0001,		/* sent from an F port */
@@ -130,6 +159,7 @@
 	FIP_DT_FKA =	12,		/* advertisement keep-alive period */
 	FIP_DT_VENDOR =	13,		/* vendor ID */
 	FIP_DT_VLAN =	14,		/* vlan number */
+	FIP_DT_FC4F =	15,		/* FC-4 features */
 	FIP_DT_LIMIT,			/* max defined desc_type + 1 */
 	FIP_DT_VENDOR_BASE = 128,	/* first vendor-specific desc_type */
 };
@@ -229,6 +259,16 @@
 /* FIP_DT_FKA flags */
 
 /*
+ * FIP_DT_FC4F - FC-4 features.
+ */
+struct fip_fc4_feat {
+	struct fip_desc fd_desc;
+	__u8		fd_resvd[2];
+	struct fc_ns_fts fd_fts;
+	struct fc_ns_ff	fd_ff;
+} __attribute__((packed));
+
+/*
  * FIP_DT_VENDOR descriptor.
  */
 struct fip_vendor_desc {
diff --git a/include/scsi/fc/fc_ns.h b/include/scsi/fc/fc_ns.h
index e7d3ac4..185015d 100644
--- a/include/scsi/fc/fc_ns.h
+++ b/include/scsi/fc/fc_ns.h
@@ -100,6 +100,13 @@
 };
 
 /*
+ * FC4-features object.
+ */
+struct fc_ns_ff	{
+	__be32	fd_feat[FC_NS_TYPES * 4 / FC_NS_BPW]; /* 4-bits per FC-type */
+};
+
+/*
  * GID_PT request.
  */
 struct fc_ns_gid_pt {
diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h
index 9b4867c..6d293c8 100644
--- a/include/scsi/fc_encode.h
+++ b/include/scsi/fc_encode.h
@@ -21,6 +21,13 @@
 #define _FC_ENCODE_H_
 #include <asm/unaligned.h>
 
+/*
+ * F_CTL values for simple requests and responses.
+ */
+#define FC_FCTL_REQ	(FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT)
+#define FC_FCTL_RESP	(FC_FC_EX_CTX | FC_FC_LAST_SEQ | \
+			FC_FC_END_SEQ | FC_FC_SEQ_INIT)
+
 struct fc_ns_rft {
 	struct fc_ns_fid fid;	/* port ID object */
 	struct fc_ns_fts fts;	/* FC4-types object */
diff --git a/include/scsi/fc_frame.h b/include/scsi/fc_frame.h
index 4d3e9c7..4ad0204 100644
--- a/include/scsi/fc_frame.h
+++ b/include/scsi/fc_frame.h
@@ -30,6 +30,23 @@
 
 #include <linux/if_ether.h>
 
+/* some helpful macros */
+
+#define ntohll(x) be64_to_cpu(x)
+#define htonll(x) cpu_to_be64(x)
+
+static inline u32 ntoh24(const u8 *p)
+{
+	return (p[0] << 16) | (p[1] << 8) | p[2];
+}
+
+static inline void hton24(u8 *p, u32 v)
+{
+	p[0] = (v >> 16) & 0xff;
+	p[1] = (v >> 8) & 0xff;
+	p[2] = v & 0xff;
+}
+
 /*
  * The fc_frame interface is used to pass frame data between functions.
  * The frame includes the data buffer, length, and SOF / EOF delimiter types.
@@ -51,6 +68,7 @@
 #define fr_sof(fp)	(fr_cb(fp)->fr_sof)
 #define fr_eof(fp)	(fr_cb(fp)->fr_eof)
 #define fr_flags(fp)	(fr_cb(fp)->fr_flags)
+#define fr_encaps(fp)	(fr_cb(fp)->fr_encaps)
 #define fr_max_payload(fp)	(fr_cb(fp)->fr_max_payload)
 #define fr_fsp(fp)	(fr_cb(fp)->fr_fsp)
 #define fr_crc(fp)	(fr_cb(fp)->fr_crc)
@@ -66,9 +84,10 @@
 	struct fc_fcp_pkt *fr_fsp;	/* for the corresponding fcp I/O */
 	u32		fr_crc;
 	u16		fr_max_payload;	/* max FC payload */
-	enum fc_sof	fr_sof;		/* start of frame delimiter */
-	enum fc_eof	fr_eof;		/* end of frame delimiter */
+	u8		fr_sof;		/* start of frame delimiter */
+	u8		fr_eof;		/* end of frame delimiter */
 	u8		fr_flags;	/* flags - see below */
+	u8		fr_encaps;	/* LLD encapsulation info (e.g. FIP) */
 	u8		granted_mac[ETH_ALEN]; /* FCoE MAC address */
 };
 
@@ -97,6 +116,7 @@
 	fr_dev(fp) = NULL;
 	fr_seq(fp) = NULL;
 	fr_flags(fp) = 0;
+	fr_encaps(fp) = 0;
 }
 
 struct fc_frame *fc_frame_alloc_fill(struct fc_lport *, size_t payload_len);
@@ -136,13 +156,39 @@
 
 /*
  * Get frame header from message in fc_frame structure.
+ * This version doesn't do a length check.
+ */
+static inline
+struct fc_frame_header *__fc_frame_header_get(const struct fc_frame *fp)
+{
+	return (struct fc_frame_header *)fr_hdr(fp);
+}
+
+/*
+ * Get frame header from message in fc_frame structure.
  * This hides a cast and provides a place to add some checking.
  */
 static inline
 struct fc_frame_header *fc_frame_header_get(const struct fc_frame *fp)
 {
 	WARN_ON(fr_len(fp) < sizeof(struct fc_frame_header));
-	return (struct fc_frame_header *) fr_hdr(fp);
+	return __fc_frame_header_get(fp);
+}
+
+/*
+ * Get source FC_ID (S_ID) from frame header in message.
+ */
+static inline u32 fc_frame_sid(const struct fc_frame *fp)
+{
+	return ntoh24(__fc_frame_header_get(fp)->fh_s_id);
+}
+
+/*
+ * Get destination FC_ID (D_ID) from frame header in message.
+ */
+static inline u32 fc_frame_did(const struct fc_frame *fp)
+{
+	return ntoh24(__fc_frame_header_get(fp)->fh_d_id);
 }
 
 /*
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 66d377b..a8631ac 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -313,6 +313,7 @@
 	ISCSI_PARAM_INITIATOR_NAME,
 
 	ISCSI_PARAM_TGT_RESET_TMO,
+	ISCSI_PARAM_TARGET_ALIAS,
 	/* must always be last */
 	ISCSI_PARAM_MAX,
 };
@@ -353,6 +354,7 @@
 #define ISCSI_ISID			(1ULL << ISCSI_PARAM_ISID)
 #define ISCSI_INITIATOR_NAME		(1ULL << ISCSI_PARAM_INITIATOR_NAME)
 #define ISCSI_TGT_RESET_TMO		(1ULL << ISCSI_PARAM_TGT_RESET_TMO)
+#define ISCSI_TARGET_ALIAS		(1ULL << ISCSI_PARAM_TARGET_ALIAS)
 
 /* iSCSI HBA params */
 enum iscsi_host_param {
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index 7495c0b..14be49b 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -42,24 +42,6 @@
 #define	FC_EX_TIMEOUT	1	/* Exchange timeout */
 #define	FC_EX_CLOSED	2	/* Exchange closed */
 
-/* some helpful macros */
-
-#define ntohll(x) be64_to_cpu(x)
-#define htonll(x) cpu_to_be64(x)
-
-
-static inline u32 ntoh24(const u8 *p)
-{
-	return (p[0] << 16) | (p[1] << 8) | p[2];
-}
-
-static inline void hton24(u8 *p, u32 v)
-{
-	p[0] = (v >> 16) & 0xff;
-	p[1] = (v >> 8) & 0xff;
-	p[2] = v & 0xff;
-}
-
 /**
  * enum fc_lport_state - Local port states
  * @LPORT_ST_DISABLED: Disabled
@@ -97,25 +79,25 @@
 /**
  * enum fc_rport_state - Remote port states
  * @RPORT_ST_INIT:    Initialized
+ * @RPORT_ST_FLOGI:   Waiting for FLOGI completion for point-to-multipoint
+ * @RPORT_ST_PLOGI_WAIT:   Waiting for peer to login for point-to-multipoint
  * @RPORT_ST_PLOGI:   Waiting for PLOGI completion
  * @RPORT_ST_PRLI:    Waiting for PRLI completion
  * @RPORT_ST_RTV:     Waiting for RTV completion
  * @RPORT_ST_READY:   Ready for use
- * @RPORT_ST_LOGO:    Remote port logout (LOGO) sent
  * @RPORT_ST_ADISC:   Discover Address sent
  * @RPORT_ST_DELETE:  Remote port being deleted
- * @RPORT_ST_RESTART: Remote port being deleted and will restart
 */
 enum fc_rport_state {
 	RPORT_ST_INIT,
+	RPORT_ST_FLOGI,
+	RPORT_ST_PLOGI_WAIT,
 	RPORT_ST_PLOGI,
 	RPORT_ST_PRLI,
 	RPORT_ST_RTV,
 	RPORT_ST_READY,
-	RPORT_ST_LOGO,
 	RPORT_ST_ADISC,
 	RPORT_ST_DELETE,
-	RPORT_ST_RESTART,
 };
 
 /**
@@ -173,6 +155,7 @@
 	u16			   flags;
 	#define FC_RP_FLAGS_REC_SUPPORTED	(1 << 0)
 	#define FC_RP_FLAGS_RETRY		(1 << 1)
+	#define FC_RP_STARTED			(1 << 2)
 	unsigned int	           e_d_tov;
 	unsigned int	           r_a_tov;
 };
@@ -185,16 +168,18 @@
  * @rp_state:       Enumeration that tracks progress of PLOGI, PRLI,
  *                  and RTV exchanges
  * @ids:            The remote port identifiers and roles
- * @flags:          REC and RETRY supported flags
+ * @flags:          STARTED, REC and RETRY_SUPPORTED flags
  * @max_seq:        Maximum number of concurrent sequences
  * @disc_id:        The discovery identifier
  * @maxframe_size:  The maximum frame size
  * @retries:        The retry count for the current state
+ * @major_retries:  The retry count for the entire PLOGI/PRLI state machine
  * @e_d_tov:        Error detect timeout value (in msec)
  * @r_a_tov:        Resource allocation timeout value (in msec)
  * @rp_mutex:       The mutex that protects the remote port
  * @retry_work:     Handle for retries
  * @event_callback: Callback when READY, FAILED or LOGO states complete
+ * @rcu:	    Structure used for freeing in an RCU-safe manner
  */
 struct fc_rport_priv {
 	struct fc_lport		    *local_port;
@@ -207,6 +192,7 @@
 	u16			    disc_id;
 	u16			    maxframe_size;
 	unsigned int	            retries;
+	unsigned int	            major_retries;
 	unsigned int	            e_d_tov;
 	unsigned int	            r_a_tov;
 	struct mutex                rp_mutex;
@@ -216,6 +202,7 @@
 	struct list_head            peers;
 	struct work_struct          event_work;
 	u32			    supported_classes;
+	struct rcu_head		    rcu;
 };
 
 /**
@@ -262,14 +249,12 @@
 
 /**
  * struct fc_seq_els_data - ELS data used for passing ELS specific responses
- * @fp:     The ELS frame
  * @reason: The reason for rejection
  * @explan: The explaination of the rejection
  *
  * Mainly used by the exchange manager layer.
  */
 struct fc_seq_els_data {
-	struct fc_frame *fp;
 	enum fc_els_rjt_reason reason;
 	enum fc_els_rjt_explan explan;
 };
@@ -405,6 +390,7 @@
  * @esb_stat:     ESB exchange status
  * @r_a_tov:      Resouce allocation time out value (in msecs)
  * @seq_id:       The next sequence ID to use
+ * @encaps:       encapsulation information for lower-level driver
  * @f_ctl:        F_CTL flags for the sequence
  * @fh_type:      The frame type
  * @class:        The class of service
@@ -436,6 +422,7 @@
 	u32		    esb_stat;
 	u32		    r_a_tov;
 	u8		    seq_id;
+	u8		    encaps;
 	u32		    f_ctl;
 	u8		    fh_type;
 	enum fc_class	    class;
@@ -530,12 +517,11 @@
 			struct fc_frame *);
 
 	/*
-	 * Send an ELS response using infomation from a previous
-	 * exchange and sequence.
+	 * Send an ELS response using infomation from the received frame.
 	 *
 	 * STATUS: OPTIONAL
 	 */
-	void (*seq_els_rsp_send)(struct fc_seq *, enum fc_els_cmd,
+	void (*seq_els_rsp_send)(struct fc_frame *, enum fc_els_cmd,
 				 struct fc_seq_els_data *);
 
 	/*
@@ -567,6 +553,13 @@
 	struct fc_seq *(*seq_start_next)(struct fc_seq *);
 
 	/*
+	 * Assign a sequence for an incoming request frame.
+	 *
+	 * STATUS: OPTIONAL
+	 */
+	struct fc_seq *(*seq_assign)(struct fc_lport *, struct fc_frame *);
+
+	/*
 	 * Reset an exchange manager, completing all sequences and exchanges.
 	 * If s_id is non-zero, reset only exchanges originating from that FID.
 	 * If d_id is non-zero, reset only exchanges sending to that FID.
@@ -587,8 +580,7 @@
 	 *
 	 * STATUS: OPTIONAL
 	 */
-	void (*lport_recv)(struct fc_lport *, struct fc_seq *,
-			   struct fc_frame *);
+	void (*lport_recv)(struct fc_lport *, struct fc_frame *);
 
 	/*
 	 * Reset the local port.
@@ -650,8 +642,7 @@
 	 *
 	 * STATUS: OPTIONAL
 	 */
-	void (*rport_recv_req)(struct fc_seq *, struct fc_frame *,
-			       struct fc_lport *);
+	void (*rport_recv_req)(struct fc_lport *, struct fc_frame *);
 
 	/*
 	 * lookup an rport by it's port ID.
@@ -697,8 +688,7 @@
 	 *
 	 * STATUS: OPTIONAL
 	 */
-	void (*disc_recv_req)(struct fc_seq *, struct fc_frame *,
-			      struct fc_lport *);
+	void (*disc_recv_req)(struct fc_lport *, struct fc_frame *);
 
 	/*
 	 * Start discovery for a local port.
@@ -736,7 +726,7 @@
  * @buf_len:       Length of the discovery buffer
  * @disc_id:       Discovery ID
  * @rports:        List of discovered remote ports
- * @lport:         The local port that discovery is for
+ * @priv:          Private pointer for use by discovery code
  * @disc_mutex:    Mutex that protects the discovery context
  * @partial_buf:   Partial name buffer (if names are returned
  *                 in multiple frames)
@@ -752,7 +742,7 @@
 	u16                   disc_id;
 
 	struct list_head      rports;
-	struct fc_lport	      *lport;
+	void		      *priv;
 	struct mutex	      disc_mutex;
 	struct fc_gpn_ft_resp partial_buf;
 	struct delayed_work   disc_work;
@@ -796,6 +786,7 @@
  * @mfs:                   The maximum Fibre Channel payload size
  * @max_retry_count:       The maximum retry attempts
  * @max_rport_retry_count: The maximum remote port retry attempts
+ * @rport_priv_size:       Size needed by driver after struct fc_rport_priv
  * @lro_xid:               The maximum XID for LRO
  * @lso_max:               The maximum large offload send size
  * @fcts:                  FC-4 type mask
@@ -842,9 +833,11 @@
 	u32			       lro_enabled:1;
 	u32			       does_npiv:1;
 	u32			       npiv_enabled:1;
+	u32			       point_to_multipoint:1;
 	u32			       mfs;
 	u8			       max_retry_count;
 	u8			       max_rport_retry_count;
+	u16			       rport_priv_size;
 	u16			       link_speed;
 	u16			       link_supported_speeds;
 	u16			       lro_xid;
@@ -986,6 +979,7 @@
 struct fc_lport *libfc_vport_create(struct fc_vport *, int privsize);
 struct fc_lport *fc_vport_id_lookup(struct fc_lport *, u32 port_id);
 int fc_lport_bsg_request(struct fc_bsg_job *);
+void fc_lport_set_local_id(struct fc_lport *, u32 port_id);
 
 /*
  * REMOTE PORT LAYER
@@ -998,6 +992,11 @@
  *****************************/
 int fc_disc_init(struct fc_lport *);
 
+static inline struct fc_lport *fc_disc_lport(struct fc_disc *disc)
+{
+	return container_of(disc, struct fc_lport, disc);
+}
+
 /*
  * FCP LAYER
  *****************************/
@@ -1029,6 +1028,10 @@
 				    void *arg, u32 timer_msec);
 void fc_lport_flogi_resp(struct fc_seq *, struct fc_frame *, void *);
 void fc_lport_logo_resp(struct fc_seq *, struct fc_frame *, void *);
+void fc_fill_reply_hdr(struct fc_frame *, const struct fc_frame *,
+		       enum fc_rctl, u32 parm_offset);
+void fc_fill_hdr(struct fc_frame *, const struct fc_frame *,
+		 enum fc_rctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset);
 
 
 /*
diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h
index ec13f51..06f1b5a 100644
--- a/include/scsi/libfcoe.h
+++ b/include/scsi/libfcoe.h
@@ -26,6 +26,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
+#include <linux/random.h>
 #include <scsi/fc/fc_fcoe.h>
 #include <scsi/libfc.h>
 
@@ -37,6 +38,7 @@
 #define FCOE_CTLR_START_DELAY	2000	/* mS after first adv. to choose FCF */
 #define FCOE_CTRL_SOL_TOV	2000	/* min. solicitation interval (mS) */
 #define FCOE_CTLR_FCF_LIMIT	20	/* max. number of FCF entries */
+#define FCOE_CTLR_VN2VN_LOGIN_LIMIT 3	/* max. VN2VN rport login retries */
 
 /**
  * enum fip_state - internal state of FCoE controller.
@@ -45,6 +47,11 @@
  * @FIP_ST_AUTO:	determining whether to use FIP or non-FIP mode.
  * @FIP_ST_NON_FIP:	non-FIP mode selected.
  * @FIP_ST_ENABLED:	FIP mode selected.
+ * @FIP_ST_VNMP_START:	VN2VN multipath mode start, wait
+ * @FIP_ST_VNMP_PROBE1:	VN2VN sent first probe, listening
+ * @FIP_ST_VNMP_PROBE2:	VN2VN sent second probe, listening
+ * @FIP_ST_VNMP_CLAIM:	VN2VN sent claim, waiting for responses
+ * @FIP_ST_VNMP_UP:	VN2VN multipath mode operation
  */
 enum fip_state {
 	FIP_ST_DISABLED,
@@ -52,8 +59,23 @@
 	FIP_ST_AUTO,
 	FIP_ST_NON_FIP,
 	FIP_ST_ENABLED,
+	FIP_ST_VNMP_START,
+	FIP_ST_VNMP_PROBE1,
+	FIP_ST_VNMP_PROBE2,
+	FIP_ST_VNMP_CLAIM,
+	FIP_ST_VNMP_UP,
 };
 
+/*
+ * Modes:
+ * The mode is the state that is to be entered after link up.
+ * It must not change after fcoe_ctlr_init() sets it.
+ */
+#define FIP_MODE_AUTO		FIP_ST_AUTO
+#define FIP_MODE_NON_FIP	FIP_ST_NON_FIP
+#define FIP_MODE_FABRIC		FIP_ST_ENABLED
+#define FIP_MODE_VN2VN		FIP_ST_VNMP_START
+
 /**
  * struct fcoe_ctlr - FCoE Controller and FIP state
  * @state:	   internal FIP state for network link and FIP or non-FIP mode.
@@ -70,19 +92,20 @@
  * @timer_work:	   &work_struct for doing keep-alives and resets.
  * @recv_work:	   &work_struct for receiving FIP frames.
  * @fip_recv_list: list of received FIP frames.
+ * @rnd_state:	   state for pseudo-random number generator.
+ * @port_id:	   proposed or selected local-port ID.
  * @user_mfs:	   configured maximum FC frame size, including FC header.
  * @flogi_oxid:    exchange ID of most recent fabric login.
  * @flogi_count:   number of FLOGI attempts in AUTO mode.
  * @map_dest:	   use the FC_MAP mode for destination MAC addresses.
  * @spma:	   supports SPMA server-provided MACs mode
- * @send_ctlr_ka:  need to send controller keep alive
- * @send_port_ka:  need to send port keep alives
+ * @probe_tries:   number of FC_IDs probed
  * @dest_addr:	   MAC address of the selected FC forwarder.
  * @ctl_src_addr:  the native MAC address of our local port.
  * @send:	   LLD-supplied function to handle sending FIP Ethernet frames
  * @update_mac:    LLD-supplied function to handle changes to MAC addresses.
  * @get_src_addr:  LLD-supplied function to supply a source MAC address.
- * @lock:	   lock protecting this structure.
+ * @ctlr_mutex:	   lock protecting this structure.
  *
  * This structure is used by all FCoE drivers.  It contains information
  * needed by all FCoE low-level drivers (LLDs) as well as internal state
@@ -103,21 +126,23 @@
 	struct work_struct timer_work;
 	struct work_struct recv_work;
 	struct sk_buff_head fip_recv_list;
+
+	struct rnd_state rnd_state;
+	u32 port_id;
+
 	u16 user_mfs;
 	u16 flogi_oxid;
 	u8 flogi_count;
-	u8 reset_req;
 	u8 map_dest;
 	u8 spma;
-	u8 send_ctlr_ka;
-	u8 send_port_ka;
+	u8 probe_tries;
 	u8 dest_addr[ETH_ALEN];
 	u8 ctl_src_addr[ETH_ALEN];
 
 	void (*send)(struct fcoe_ctlr *, struct sk_buff *);
 	void (*update_mac)(struct fc_lport *, u8 *addr);
 	u8 * (*get_src_addr)(struct fc_lport *);
-	spinlock_t lock;
+	struct mutex ctlr_mutex;
 };
 
 /**
@@ -156,8 +181,26 @@
 	u8 fd_flags:1;
 };
 
+/**
+ * struct fcoe_rport - VN2VN remote port
+ * @time:	time of create or last beacon packet received from node
+ * @fcoe_len:	max FCoE frame size, not including VLAN or Ethernet headers
+ * @flags:	flags from probe or claim
+ * @login_count: number of unsuccessful rport logins to this port
+ * @enode_mac:	E_Node control MAC address
+ * @vn_mac:	VN_Node assigned MAC address for data
+ */
+struct fcoe_rport {
+	unsigned long time;
+	u16 fcoe_len;
+	u16 flags;
+	u8 login_count;
+	u8 enode_mac[ETH_ALEN];
+	u8 vn_mac[ETH_ALEN];
+};
+
 /* FIP API functions */
-void fcoe_ctlr_init(struct fcoe_ctlr *);
+void fcoe_ctlr_init(struct fcoe_ctlr *, enum fip_state);
 void fcoe_ctlr_destroy(struct fcoe_ctlr *);
 void fcoe_ctlr_link_up(struct fcoe_ctlr *);
 int fcoe_ctlr_link_down(struct fcoe_ctlr *);
@@ -168,6 +211,17 @@
 
 /* libfcoe funcs */
 u64 fcoe_wwn_from_mac(unsigned char mac[], unsigned int, unsigned int);
-int fcoe_libfc_config(struct fc_lport *, struct libfc_function_template *);
+int fcoe_libfc_config(struct fc_lport *, struct fcoe_ctlr *,
+		      const struct libfc_function_template *, int init_fcp);
+
+/**
+ * is_fip_mode() - returns true if FIP mode selected.
+ * @fip:	FCoE controller.
+ */
+static inline bool is_fip_mode(struct fcoe_ctlr *fip)
+{
+	return fip->state == FIP_ST_ENABLED;
+}
+
 
 #endif /* _LIBFCOE_H */
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 3b58685..d06e13b 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -422,16 +422,7 @@
 };
 
 enum exec_status {
-	SAM_GOOD         = 0,
-	SAM_CHECK_COND   = 2,
-	SAM_COND_MET     = 4,
-	SAM_BUSY         = 8,
-	SAM_INTERMEDIATE = 0x10,
-	SAM_IM_COND_MET  = 0x12,
-	SAM_RESV_CONFLICT= 0x14,
-	SAM_TASK_SET_FULL= 0x28,
-	SAM_ACA_ACTIVE   = 0x30,
-	SAM_TASK_ABORTED = 0x40,
+	/* The SAM_STAT_.. codes fit in the lower 6 bits */
 
 	SAS_DEV_NO_RESPONSE = 0x80,
 	SAS_DATA_UNDERRUN,
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index d80b6db..50cb34f 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -381,6 +381,14 @@
 			    struct scsi_sense_hdr *, int timeout, int retries,
 			    int *resid);
 
+#ifdef CONFIG_PM_RUNTIME
+extern int scsi_autopm_get_device(struct scsi_device *);
+extern void scsi_autopm_put_device(struct scsi_device *);
+#else
+static inline int scsi_autopm_get_device(struct scsi_device *d) { return 0; }
+static inline void scsi_autopm_put_device(struct scsi_device *d) {}
+#endif /* CONFIG_PM_RUNTIME */
+
 static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev)
 {
 	return device_reprobe(&sdev->sdev_gendev);
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 349c7f3..7fff94b 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -32,6 +32,7 @@
 struct iscsi_transport;
 struct iscsi_endpoint;
 struct Scsi_Host;
+struct scsi_cmnd;
 struct iscsi_cls_conn;
 struct iscsi_conn;
 struct iscsi_task;
@@ -255,5 +256,6 @@
 extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size);
 extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
 extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle);
+extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd);
 
 #endif
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index dd76cde..6e3a297 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -366,7 +366,7 @@
 	int number;
 	char name[32];			/* substream name */
 	int stream;			/* stream (direction) */
-	struct pm_qos_request_list *latency_pm_qos_req; /* pm_qos request */
+	struct pm_qos_request_list latency_pm_qos_req; /* pm_qos request */
 	size_t buffer_bytes_max;	/* limit ring buffer size */
 	struct snd_dma_buffer dma_buffer;
 	unsigned int dma_buf_id;
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index c4efe9b..35a2a6e 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -18,52 +18,55 @@
 
 DECLARE_EVENT_CLASS(power,
 
-	TP_PROTO(unsigned int type, unsigned int state),
+	TP_PROTO(unsigned int type, unsigned int state, unsigned int cpu_id),
 
-	TP_ARGS(type, state),
+	TP_ARGS(type, state, cpu_id),
 
 	TP_STRUCT__entry(
 		__field(	u64,		type		)
 		__field(	u64,		state		)
+		__field(	u64,		cpu_id		)
 	),
 
 	TP_fast_assign(
 		__entry->type = type;
 		__entry->state = state;
+		__entry->cpu_id = cpu_id;
 	),
 
-	TP_printk("type=%lu state=%lu", (unsigned long)__entry->type, (unsigned long)__entry->state)
+	TP_printk("type=%lu state=%lu cpu_id=%lu", (unsigned long)__entry->type,
+		(unsigned long)__entry->state, (unsigned long)__entry->cpu_id)
 );
 
 DEFINE_EVENT(power, power_start,
 
-	TP_PROTO(unsigned int type, unsigned int state),
+	TP_PROTO(unsigned int type, unsigned int state, unsigned int cpu_id),
 
-	TP_ARGS(type, state)
+	TP_ARGS(type, state, cpu_id)
 );
 
 DEFINE_EVENT(power, power_frequency,
 
-	TP_PROTO(unsigned int type, unsigned int state),
+	TP_PROTO(unsigned int type, unsigned int state, unsigned int cpu_id),
 
-	TP_ARGS(type, state)
+	TP_ARGS(type, state, cpu_id)
 );
 
 TRACE_EVENT(power_end,
 
-	TP_PROTO(int dummy),
+	TP_PROTO(unsigned int cpu_id),
 
-	TP_ARGS(dummy),
+	TP_ARGS(cpu_id),
 
 	TP_STRUCT__entry(
-		__field(	u64,		dummy		)
+		__field(	u64,		cpu_id		)
 	),
 
 	TP_fast_assign(
-		__entry->dummy = 0xffff;
+		__entry->cpu_id = cpu_id;
 	),
 
-	TP_printk("dummy=%lu", (unsigned long)__entry->dummy)
+	TP_printk("cpu_id=%lu", (unsigned long)__entry->cpu_id)
 
 );
 
diff --git a/init/main.c b/init/main.c
index a42fdf4..4ddb53f 100644
--- a/init/main.c
+++ b/init/main.c
@@ -532,6 +532,7 @@
 	page_cgroup_init_flatmem();
 	mem_init();
 	kmem_cache_init();
+	percpu_init_late();
 	pgtable_cache_init();
 	vmalloc_init();
 }
diff --git a/kernel/audit.c b/kernel/audit.c
index c71bd26..8296aa5 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -407,7 +407,7 @@
 		audit_hold_skb(skb);
 	} else
 		/* drop the extra reference if sent ok */
-		kfree_skb(skb);
+		consume_skb(skb);
 }
 
 static int kauditd_thread(void *dummy)
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 3ac6f5b..a8ce099 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1788,6 +1788,29 @@
 	return retval;
 }
 
+/**
+ * cgroup_attach_task_current_cg - attach task 'tsk' to current task's cgroup
+ * @tsk: the task to be attached
+ */
+int cgroup_attach_task_current_cg(struct task_struct *tsk)
+{
+	struct cgroupfs_root *root;
+	struct cgroup *cur_cg;
+	int retval = 0;
+
+	cgroup_lock();
+	for_each_active_root(root) {
+		cur_cg = task_cgroup_from_root(current, root);
+		retval = cgroup_attach_task(cur_cg, tsk);
+		if (retval)
+			break;
+	}
+	cgroup_unlock();
+
+	return retval;
+}
+EXPORT_SYMBOL_GPL(cgroup_attach_task_current_cg);
+
 /*
  * Attach task with pid 'pid' to cgroup 'cgrp'. Call with cgroup_mutex
  * held. May take task_lock of task
diff --git a/kernel/padata.c b/kernel/padata.c
index fdd8ae6..7510194 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -26,18 +26,19 @@
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/sysfs.h>
 #include <linux/rcupdate.h>
 
-#define MAX_SEQ_NR INT_MAX - NR_CPUS
+#define MAX_SEQ_NR (INT_MAX - NR_CPUS)
 #define MAX_OBJ_NUM 1000
 
 static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index)
 {
 	int cpu, target_cpu;
 
-	target_cpu = cpumask_first(pd->cpumask);
+	target_cpu = cpumask_first(pd->cpumask.pcpu);
 	for (cpu = 0; cpu < cpu_index; cpu++)
-		target_cpu = cpumask_next(target_cpu, pd->cpumask);
+		target_cpu = cpumask_next(target_cpu, pd->cpumask.pcpu);
 
 	return target_cpu;
 }
@@ -53,26 +54,27 @@
 	 * Hash the sequence numbers to the cpus by taking
 	 * seq_nr mod. number of cpus in use.
 	 */
-	cpu_index =  padata->seq_nr % cpumask_weight(pd->cpumask);
+	cpu_index =  padata->seq_nr % cpumask_weight(pd->cpumask.pcpu);
 
 	return padata_index_to_cpu(pd, cpu_index);
 }
 
-static void padata_parallel_worker(struct work_struct *work)
+static void padata_parallel_worker(struct work_struct *parallel_work)
 {
-	struct padata_queue *queue;
+	struct padata_parallel_queue *pqueue;
 	struct parallel_data *pd;
 	struct padata_instance *pinst;
 	LIST_HEAD(local_list);
 
 	local_bh_disable();
-	queue = container_of(work, struct padata_queue, pwork);
-	pd = queue->pd;
+	pqueue = container_of(parallel_work,
+			      struct padata_parallel_queue, work);
+	pd = pqueue->pd;
 	pinst = pd->pinst;
 
-	spin_lock(&queue->parallel.lock);
-	list_replace_init(&queue->parallel.list, &local_list);
-	spin_unlock(&queue->parallel.lock);
+	spin_lock(&pqueue->parallel.lock);
+	list_replace_init(&pqueue->parallel.list, &local_list);
+	spin_unlock(&pqueue->parallel.lock);
 
 	while (!list_empty(&local_list)) {
 		struct padata_priv *padata;
@@ -94,7 +96,7 @@
  * @pinst: padata instance
  * @padata: object to be parallelized
  * @cb_cpu: cpu the serialization callback function will run on,
- *          must be in the cpumask of padata.
+ *          must be in the serial cpumask of padata(i.e. cpumask.cbcpu).
  *
  * The parallelization callback function will run with BHs off.
  * Note: Every object which is parallelized by padata_do_parallel
@@ -104,15 +106,18 @@
 		       struct padata_priv *padata, int cb_cpu)
 {
 	int target_cpu, err;
-	struct padata_queue *queue;
+	struct padata_parallel_queue *queue;
 	struct parallel_data *pd;
 
 	rcu_read_lock_bh();
 
 	pd = rcu_dereference(pinst->pd);
 
-	err = 0;
-	if (!(pinst->flags & PADATA_INIT))
+	err = -EINVAL;
+	if (!(pinst->flags & PADATA_INIT) || pinst->flags & PADATA_INVALID)
+		goto out;
+
+	if (!cpumask_test_cpu(cb_cpu, pd->cpumask.cbcpu))
 		goto out;
 
 	err =  -EBUSY;
@@ -122,11 +127,7 @@
 	if (atomic_read(&pd->refcnt) >= MAX_OBJ_NUM)
 		goto out;
 
-	err = -EINVAL;
-	if (!cpumask_test_cpu(cb_cpu, pd->cpumask))
-		goto out;
-
-	err = -EINPROGRESS;
+	err = 0;
 	atomic_inc(&pd->refcnt);
 	padata->pd = pd;
 	padata->cb_cpu = cb_cpu;
@@ -137,13 +138,13 @@
 	padata->seq_nr = atomic_inc_return(&pd->seq_nr);
 
 	target_cpu = padata_cpu_hash(padata);
-	queue = per_cpu_ptr(pd->queue, target_cpu);
+	queue = per_cpu_ptr(pd->pqueue, target_cpu);
 
 	spin_lock(&queue->parallel.lock);
 	list_add_tail(&padata->list, &queue->parallel.list);
 	spin_unlock(&queue->parallel.lock);
 
-	queue_work_on(target_cpu, pinst->wq, &queue->pwork);
+	queue_work_on(target_cpu, pinst->wq, &queue->work);
 
 out:
 	rcu_read_unlock_bh();
@@ -171,84 +172,52 @@
  */
 static struct padata_priv *padata_get_next(struct parallel_data *pd)
 {
-	int cpu, num_cpus, empty, calc_seq_nr;
-	int seq_nr, next_nr, overrun, next_overrun;
-	struct padata_queue *queue, *next_queue;
+	int cpu, num_cpus;
+	int next_nr, next_index;
+	struct padata_parallel_queue *queue, *next_queue;
 	struct padata_priv *padata;
 	struct padata_list *reorder;
 
-	empty = 0;
-	next_nr = -1;
-	next_overrun = 0;
-	next_queue = NULL;
+	num_cpus = cpumask_weight(pd->cpumask.pcpu);
 
-	num_cpus = cpumask_weight(pd->cpumask);
+	/*
+	 * Calculate the percpu reorder queue and the sequence
+	 * number of the next object.
+	 */
+	next_nr = pd->processed;
+	next_index = next_nr % num_cpus;
+	cpu = padata_index_to_cpu(pd, next_index);
+	next_queue = per_cpu_ptr(pd->pqueue, cpu);
 
-	for_each_cpu(cpu, pd->cpumask) {
-		queue = per_cpu_ptr(pd->queue, cpu);
-		reorder = &queue->reorder;
-
-		/*
-		 * Calculate the seq_nr of the object that should be
-		 * next in this reorder queue.
-		 */
-		overrun = 0;
-		calc_seq_nr = (atomic_read(&queue->num_obj) * num_cpus)
-			       + queue->cpu_index;
-
-		if (unlikely(calc_seq_nr > pd->max_seq_nr)) {
-			calc_seq_nr = calc_seq_nr - pd->max_seq_nr - 1;
-			overrun = 1;
-		}
-
-		if (!list_empty(&reorder->list)) {
-			padata = list_entry(reorder->list.next,
-					    struct padata_priv, list);
-
-			seq_nr  = padata->seq_nr;
-			BUG_ON(calc_seq_nr != seq_nr);
-		} else {
-			seq_nr = calc_seq_nr;
-			empty++;
-		}
-
-		if (next_nr < 0 || seq_nr < next_nr
-		    || (next_overrun && !overrun)) {
-			next_nr = seq_nr;
-			next_overrun = overrun;
-			next_queue = queue;
-		}
+	if (unlikely(next_nr > pd->max_seq_nr)) {
+		next_nr = next_nr - pd->max_seq_nr - 1;
+		next_index = next_nr % num_cpus;
+		cpu = padata_index_to_cpu(pd, next_index);
+		next_queue = per_cpu_ptr(pd->pqueue, cpu);
+		pd->processed = 0;
 	}
 
 	padata = NULL;
 
-	if (empty == num_cpus)
-		goto out;
-
 	reorder = &next_queue->reorder;
 
 	if (!list_empty(&reorder->list)) {
 		padata = list_entry(reorder->list.next,
 				    struct padata_priv, list);
 
-		if (unlikely(next_overrun)) {
-			for_each_cpu(cpu, pd->cpumask) {
-				queue = per_cpu_ptr(pd->queue, cpu);
-				atomic_set(&queue->num_obj, 0);
-			}
-		}
+		BUG_ON(next_nr != padata->seq_nr);
 
 		spin_lock(&reorder->lock);
 		list_del_init(&padata->list);
 		atomic_dec(&pd->reorder_objects);
 		spin_unlock(&reorder->lock);
 
-		atomic_inc(&next_queue->num_obj);
+		pd->processed++;
 
 		goto out;
 	}
 
-	queue = per_cpu_ptr(pd->queue, smp_processor_id());
+	queue = per_cpu_ptr(pd->pqueue, smp_processor_id());
 	if (queue->cpu_index == next_queue->cpu_index) {
 		padata = ERR_PTR(-ENODATA);
 		goto out;
@@ -262,7 +231,7 @@
 static void padata_reorder(struct parallel_data *pd)
 {
 	struct padata_priv *padata;
-	struct padata_queue *queue;
+	struct padata_serial_queue *squeue;
 	struct padata_instance *pinst = pd->pinst;
 
 	/*
@@ -301,13 +270,13 @@
 			return;
 		}
 
-		queue = per_cpu_ptr(pd->queue, padata->cb_cpu);
+		squeue = per_cpu_ptr(pd->squeue, padata->cb_cpu);
 
-		spin_lock(&queue->serial.lock);
-		list_add_tail(&padata->list, &queue->serial.list);
-		spin_unlock(&queue->serial.lock);
+		spin_lock(&squeue->serial.lock);
+		list_add_tail(&padata->list, &squeue->serial.list);
+		spin_unlock(&squeue->serial.lock);
 
-		queue_work_on(padata->cb_cpu, pinst->wq, &queue->swork);
+		queue_work_on(padata->cb_cpu, pinst->wq, &squeue->work);
 	}
 
 	spin_unlock_bh(&pd->lock);
@@ -333,19 +302,19 @@
 	padata_reorder(pd);
 }
 
-static void padata_serial_worker(struct work_struct *work)
+static void padata_serial_worker(struct work_struct *serial_work)
 {
-	struct padata_queue *queue;
+	struct padata_serial_queue *squeue;
 	struct parallel_data *pd;
 	LIST_HEAD(local_list);
 
 	local_bh_disable();
-	queue = container_of(work, struct padata_queue, swork);
-	pd = queue->pd;
+	squeue = container_of(serial_work, struct padata_serial_queue, work);
+	pd = squeue->pd;
 
-	spin_lock(&queue->serial.lock);
-	list_replace_init(&queue->serial.list, &local_list);
-	spin_unlock(&queue->serial.lock);
+	spin_lock(&squeue->serial.lock);
+	list_replace_init(&squeue->serial.list, &local_list);
+	spin_unlock(&squeue->serial.lock);
 
 	while (!list_empty(&local_list)) {
 		struct padata_priv *padata;
@@ -372,18 +341,18 @@
 void padata_do_serial(struct padata_priv *padata)
 {
 	int cpu;
-	struct padata_queue *queue;
+	struct padata_parallel_queue *pqueue;
 	struct parallel_data *pd;
 
 	pd = padata->pd;
 
 	cpu = get_cpu();
-	queue = per_cpu_ptr(pd->queue, cpu);
+	pqueue = per_cpu_ptr(pd->pqueue, cpu);
 
-	spin_lock(&queue->reorder.lock);
+	spin_lock(&pqueue->reorder.lock);
 	atomic_inc(&pd->reorder_objects);
-	list_add_tail(&padata->list, &queue->reorder.list);
-	spin_unlock(&queue->reorder.lock);
+	list_add_tail(&padata->list, &pqueue->reorder.list);
+	spin_unlock(&pqueue->reorder.lock);
 
 	put_cpu();
 
@@ -391,52 +360,89 @@
 }
 EXPORT_SYMBOL(padata_do_serial);
 
-/* Allocate and initialize the internal cpumask dependend resources. */
-static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst,
-					     const struct cpumask *cpumask)
+static int padata_setup_cpumasks(struct parallel_data *pd,
+				 const struct cpumask *pcpumask,
+				 const struct cpumask *cbcpumask)
 {
-	int cpu, cpu_index, num_cpus;
-	struct padata_queue *queue;
-	struct parallel_data *pd;
+	if (!alloc_cpumask_var(&pd->cpumask.pcpu, GFP_KERNEL))
+		return -ENOMEM;
+
+	cpumask_and(pd->cpumask.pcpu, pcpumask, cpu_active_mask);
+	if (!alloc_cpumask_var(&pd->cpumask.cbcpu, GFP_KERNEL)) {
+		free_cpumask_var(pd->cpumask.cbcpu);
+		return -ENOMEM;
+	}
+
+	cpumask_and(pd->cpumask.cbcpu, cbcpumask, cpu_active_mask);
+	return 0;
+}
+
+static void __padata_list_init(struct padata_list *pd_list)
+{
+	INIT_LIST_HEAD(&pd_list->list);
+	spin_lock_init(&pd_list->lock);
+}
+
+/* Initialize all percpu queues used by serial workers */
+static void padata_init_squeues(struct parallel_data *pd)
+{
+	int cpu;
+	struct padata_serial_queue *squeue;
+
+	for_each_cpu(cpu, pd->cpumask.cbcpu) {
+		squeue = per_cpu_ptr(pd->squeue, cpu);
+		squeue->pd = pd;
+		__padata_list_init(&squeue->serial);
+		INIT_WORK(&squeue->work, padata_serial_worker);
+	}
+}
+
+/* Initialize all percpu queues used by parallel workers */
+static void padata_init_pqueues(struct parallel_data *pd)
+{
+	int cpu_index, num_cpus, cpu;
+	struct padata_parallel_queue *pqueue;
 
 	cpu_index = 0;
+	for_each_cpu(cpu, pd->cpumask.pcpu) {
+		pqueue = per_cpu_ptr(pd->pqueue, cpu);
+		pqueue->pd = pd;
+		pqueue->cpu_index = cpu_index;
+		cpu_index++;
+
+		__padata_list_init(&pqueue->reorder);
+		__padata_list_init(&pqueue->parallel);
+		INIT_WORK(&pqueue->work, padata_parallel_worker);
+		atomic_set(&pqueue->num_obj, 0);
+	}
+
+	num_cpus = cpumask_weight(pd->cpumask.pcpu);
+	pd->max_seq_nr = num_cpus ? (MAX_SEQ_NR / num_cpus) * num_cpus - 1 : 0;
+}
+
+/* Allocate and initialize the internal cpumask dependend resources. */
+static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst,
+					     const struct cpumask *pcpumask,
+					     const struct cpumask *cbcpumask)
+{
+	struct parallel_data *pd;
 
 	pd = kzalloc(sizeof(struct parallel_data), GFP_KERNEL);
 	if (!pd)
 		goto err;
 
-	pd->queue = alloc_percpu(struct padata_queue);
-	if (!pd->queue)
+	pd->pqueue = alloc_percpu(struct padata_parallel_queue);
+	if (!pd->pqueue)
 		goto err_free_pd;
 
-	if (!alloc_cpumask_var(&pd->cpumask, GFP_KERNEL))
-		goto err_free_queue;
+	pd->squeue = alloc_percpu(struct padata_serial_queue);
+	if (!pd->squeue)
+		goto err_free_pqueue;
+	if (padata_setup_cpumasks(pd, pcpumask, cbcpumask) < 0)
+		goto err_free_squeue;
 
-	cpumask_and(pd->cpumask, cpumask, cpu_active_mask);
-
-	for_each_cpu(cpu, pd->cpumask) {
-		queue = per_cpu_ptr(pd->queue, cpu);
-
-		queue->pd = pd;
-
-		queue->cpu_index = cpu_index;
-		cpu_index++;
-
-		INIT_LIST_HEAD(&queue->reorder.list);
-		INIT_LIST_HEAD(&queue->parallel.list);
-		INIT_LIST_HEAD(&queue->serial.list);
-		spin_lock_init(&queue->reorder.lock);
-		spin_lock_init(&queue->parallel.lock);
-		spin_lock_init(&queue->serial.lock);
-
-		INIT_WORK(&queue->pwork, padata_parallel_worker);
-		INIT_WORK(&queue->swork, padata_serial_worker);
-		atomic_set(&queue->num_obj, 0);
-	}
-
-	num_cpus = cpumask_weight(pd->cpumask);
-	pd->max_seq_nr = (MAX_SEQ_NR / num_cpus) * num_cpus - 1;
-
+	padata_init_pqueues(pd);
+	padata_init_squeues(pd);
 	setup_timer(&pd->timer, padata_reorder_timer, (unsigned long)pd);
 	atomic_set(&pd->seq_nr, -1);
 	atomic_set(&pd->reorder_objects, 0);
@@ -446,8 +452,10 @@
 
 	return pd;
 
-err_free_queue:
-	free_percpu(pd->queue);
+err_free_squeue:
+	free_percpu(pd->squeue);
+err_free_pqueue:
+	free_percpu(pd->pqueue);
 err_free_pd:
 	kfree(pd);
 err:
@@ -456,8 +464,10 @@
 
 static void padata_free_pd(struct parallel_data *pd)
 {
-	free_cpumask_var(pd->cpumask);
-	free_percpu(pd->queue);
+	free_cpumask_var(pd->cpumask.pcpu);
+	free_cpumask_var(pd->cpumask.cbcpu);
+	free_percpu(pd->pqueue);
+	free_percpu(pd->squeue);
 	kfree(pd);
 }
 
@@ -465,11 +475,12 @@
 static void padata_flush_queues(struct parallel_data *pd)
 {
 	int cpu;
-	struct padata_queue *queue;
+	struct padata_parallel_queue *pqueue;
+	struct padata_serial_queue *squeue;
 
-	for_each_cpu(cpu, pd->cpumask) {
-		queue = per_cpu_ptr(pd->queue, cpu);
-		flush_work(&queue->pwork);
+	for_each_cpu(cpu, pd->cpumask.pcpu) {
+		pqueue = per_cpu_ptr(pd->pqueue, cpu);
+		flush_work(&pqueue->work);
 	}
 
 	del_timer_sync(&pd->timer);
@@ -477,19 +488,39 @@
 	if (atomic_read(&pd->reorder_objects))
 		padata_reorder(pd);
 
-	for_each_cpu(cpu, pd->cpumask) {
-		queue = per_cpu_ptr(pd->queue, cpu);
-		flush_work(&queue->swork);
+	for_each_cpu(cpu, pd->cpumask.cbcpu) {
+		squeue = per_cpu_ptr(pd->squeue, cpu);
+		flush_work(&squeue->work);
 	}
 
 	BUG_ON(atomic_read(&pd->refcnt) != 0);
 }
 
+static void __padata_start(struct padata_instance *pinst)
+{
+	pinst->flags |= PADATA_INIT;
+}
+
+static void __padata_stop(struct padata_instance *pinst)
+{
+	if (!(pinst->flags & PADATA_INIT))
+		return;
+
+	pinst->flags &= ~PADATA_INIT;
+
+	synchronize_rcu();
+
+	get_online_cpus();
+	padata_flush_queues(pinst->pd);
+	put_online_cpus();
+}
+
 /* Replace the internal control stucture with a new one. */
 static void padata_replace(struct padata_instance *pinst,
 			   struct parallel_data *pd_new)
 {
 	struct parallel_data *pd_old = pinst->pd;
+	int notification_mask = 0;
 
 	pinst->flags |= PADATA_RESET;
 
@@ -497,41 +528,162 @@
 
 	synchronize_rcu();
 
+	if (!cpumask_equal(pd_old->cpumask.pcpu, pd_new->cpumask.pcpu))
+		notification_mask |= PADATA_CPU_PARALLEL;
+	if (!cpumask_equal(pd_old->cpumask.cbcpu, pd_new->cpumask.cbcpu))
+		notification_mask |= PADATA_CPU_SERIAL;
+
 	padata_flush_queues(pd_old);
 	padata_free_pd(pd_old);
 
+	if (notification_mask)
+		blocking_notifier_call_chain(&pinst->cpumask_change_notifier,
+					     notification_mask,
+					     &pd_new->cpumask);
+
 	pinst->flags &= ~PADATA_RESET;
 }
 
 /**
- * padata_set_cpumask - set the cpumask that padata should use
+ * padata_register_cpumask_notifier - Registers a notifier that will be called
+ *                             if either pcpu or cbcpu or both cpumasks change.
  *
- * @pinst: padata instance
- * @cpumask: the cpumask to use
+ * @pinst: A poineter to padata instance
+ * @nblock: A pointer to notifier block.
  */
-int padata_set_cpumask(struct padata_instance *pinst,
-			cpumask_var_t cpumask)
+int padata_register_cpumask_notifier(struct padata_instance *pinst,
+				     struct notifier_block *nblock)
 {
-	struct parallel_data *pd;
-	int err = 0;
+	return blocking_notifier_chain_register(&pinst->cpumask_change_notifier,
+						nblock);
+}
+EXPORT_SYMBOL(padata_register_cpumask_notifier);
 
-	mutex_lock(&pinst->lock);
+/**
+ * padata_unregister_cpumask_notifier - Unregisters cpumask notifier
+ *        registered earlier  using padata_register_cpumask_notifier
+ *
+ * @pinst: A pointer to data instance.
+ * @nlock: A pointer to notifier block.
+ */
+int padata_unregister_cpumask_notifier(struct padata_instance *pinst,
+				       struct notifier_block *nblock)
+{
+	return blocking_notifier_chain_unregister(
+		&pinst->cpumask_change_notifier,
+		nblock);
+}
+EXPORT_SYMBOL(padata_unregister_cpumask_notifier);
 
-	get_online_cpus();
 
-	pd = padata_alloc_pd(pinst, cpumask);
-	if (!pd) {
-		err = -ENOMEM;
-		goto out;
+/* If cpumask contains no active cpu, we mark the instance as invalid. */
+static bool padata_validate_cpumask(struct padata_instance *pinst,
+				    const struct cpumask *cpumask)
+{
+	if (!cpumask_intersects(cpumask, cpu_active_mask)) {
+		pinst->flags |= PADATA_INVALID;
+		return false;
 	}
 
-	cpumask_copy(pinst->cpumask, cpumask);
+	pinst->flags &= ~PADATA_INVALID;
+	return true;
+}
+
+static int __padata_set_cpumasks(struct padata_instance *pinst,
+				 cpumask_var_t pcpumask,
+				 cpumask_var_t cbcpumask)
+{
+	int valid;
+	struct parallel_data *pd;
+
+	valid = padata_validate_cpumask(pinst, pcpumask);
+	if (!valid) {
+		__padata_stop(pinst);
+		goto out_replace;
+	}
+
+	valid = padata_validate_cpumask(pinst, cbcpumask);
+	if (!valid)
+		__padata_stop(pinst);
+
+out_replace:
+	pd = padata_alloc_pd(pinst, pcpumask, cbcpumask);
+	if (!pd)
+		return -ENOMEM;
+
+	cpumask_copy(pinst->cpumask.pcpu, pcpumask);
+	cpumask_copy(pinst->cpumask.cbcpu, cbcpumask);
 
 	padata_replace(pinst, pd);
 
+	if (valid)
+		__padata_start(pinst);
+
+	return 0;
+}
+
+/**
+ * padata_set_cpumasks - Set both parallel and serial cpumasks. The first
+ *                       one is used by parallel workers and the second one
+ *                       by the wokers doing serialization.
+ *
+ * @pinst: padata instance
+ * @pcpumask: the cpumask to use for parallel workers
+ * @cbcpumask: the cpumsak to use for serial workers
+ */
+int padata_set_cpumasks(struct padata_instance *pinst, cpumask_var_t pcpumask,
+			cpumask_var_t cbcpumask)
+{
+	int err;
+
+	mutex_lock(&pinst->lock);
+	get_online_cpus();
+
+	err = __padata_set_cpumasks(pinst, pcpumask, cbcpumask);
+
+	put_online_cpus();
+	mutex_unlock(&pinst->lock);
+
+	return err;
+
+}
+EXPORT_SYMBOL(padata_set_cpumasks);
+
+/**
+ * padata_set_cpumask: Sets specified by @cpumask_type cpumask to the value
+ *                     equivalent to @cpumask.
+ *
+ * @pinst: padata instance
+ * @cpumask_type: PADATA_CPU_SERIAL or PADATA_CPU_PARALLEL corresponding
+ *                to parallel and serial cpumasks respectively.
+ * @cpumask: the cpumask to use
+ */
+int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type,
+		       cpumask_var_t cpumask)
+{
+	struct cpumask *serial_mask, *parallel_mask;
+	int err = -EINVAL;
+
+	mutex_lock(&pinst->lock);
+	get_online_cpus();
+
+	switch (cpumask_type) {
+	case PADATA_CPU_PARALLEL:
+		serial_mask = pinst->cpumask.cbcpu;
+		parallel_mask = cpumask;
+		break;
+	case PADATA_CPU_SERIAL:
+		parallel_mask = pinst->cpumask.pcpu;
+		serial_mask = cpumask;
+		break;
+	default:
+		 goto out;
+	}
+
+	err =  __padata_set_cpumasks(pinst, parallel_mask, serial_mask);
+
 out:
 	put_online_cpus();
-
 	mutex_unlock(&pinst->lock);
 
 	return err;
@@ -543,30 +695,48 @@
 	struct parallel_data *pd;
 
 	if (cpumask_test_cpu(cpu, cpu_active_mask)) {
-		pd = padata_alloc_pd(pinst, pinst->cpumask);
+		pd = padata_alloc_pd(pinst, pinst->cpumask.pcpu,
+				     pinst->cpumask.cbcpu);
 		if (!pd)
 			return -ENOMEM;
 
 		padata_replace(pinst, pd);
+
+		if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) &&
+		    padata_validate_cpumask(pinst, pinst->cpumask.cbcpu))
+			__padata_start(pinst);
 	}
 
 	return 0;
 }
 
-/**
- * padata_add_cpu - add a cpu to the padata cpumask
+ /**
+ * padata_add_cpu - add a cpu to one or both(parallel and serial)
+ *                  padata cpumasks.
  *
  * @pinst: padata instance
  * @cpu: cpu to add
+ * @mask: bitmask of flags specifying to which cpumask @cpu shuld be added.
+ *        The @mask may be any combination of the following flags:
+ *          PADATA_CPU_SERIAL   - serial cpumask
+ *          PADATA_CPU_PARALLEL - parallel cpumask
  */
-int padata_add_cpu(struct padata_instance *pinst, int cpu)
+
+int padata_add_cpu(struct padata_instance *pinst, int cpu, int mask)
 {
 	int err;
 
+	if (!(mask & (PADATA_CPU_SERIAL | PADATA_CPU_PARALLEL)))
+		return -EINVAL;
+
 	mutex_lock(&pinst->lock);
 
 	get_online_cpus();
-	cpumask_set_cpu(cpu, pinst->cpumask);
+	if (mask & PADATA_CPU_SERIAL)
+		cpumask_set_cpu(cpu, pinst->cpumask.cbcpu);
+	if (mask & PADATA_CPU_PARALLEL)
+		cpumask_set_cpu(cpu, pinst->cpumask.pcpu);
+
 	err = __padata_add_cpu(pinst, cpu);
 	put_online_cpus();
 
@@ -578,10 +748,16 @@
 
 static int __padata_remove_cpu(struct padata_instance *pinst, int cpu)
 {
-	struct parallel_data *pd;
+	struct parallel_data *pd = NULL;
 
 	if (cpumask_test_cpu(cpu, cpu_online_mask)) {
-		pd = padata_alloc_pd(pinst, pinst->cpumask);
+
+		if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) ||
+		    !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu))
+			__padata_stop(pinst);
+
+		pd = padata_alloc_pd(pinst, pinst->cpumask.pcpu,
+				     pinst->cpumask.cbcpu);
 		if (!pd)
 			return -ENOMEM;
 
@@ -591,20 +767,32 @@
 	return 0;
 }
 
-/**
- * padata_remove_cpu - remove a cpu from the padata cpumask
+ /**
+ * padata_remove_cpu - remove a cpu from the one or both(serial and paralell)
+ *                     padata cpumasks.
  *
  * @pinst: padata instance
  * @cpu: cpu to remove
+ * @mask: bitmask specifying from which cpumask @cpu should be removed
+ *        The @mask may be any combination of the following flags:
+ *          PADATA_CPU_SERIAL   - serial cpumask
+ *          PADATA_CPU_PARALLEL - parallel cpumask
  */
-int padata_remove_cpu(struct padata_instance *pinst, int cpu)
+int padata_remove_cpu(struct padata_instance *pinst, int cpu, int mask)
 {
 	int err;
 
+	if (!(mask & (PADATA_CPU_SERIAL | PADATA_CPU_PARALLEL)))
+		return -EINVAL;
+
 	mutex_lock(&pinst->lock);
 
 	get_online_cpus();
-	cpumask_clear_cpu(cpu, pinst->cpumask);
+	if (mask & PADATA_CPU_SERIAL)
+		cpumask_clear_cpu(cpu, pinst->cpumask.cbcpu);
+	if (mask & PADATA_CPU_PARALLEL)
+		cpumask_clear_cpu(cpu, pinst->cpumask.pcpu);
+
 	err = __padata_remove_cpu(pinst, cpu);
 	put_online_cpus();
 
@@ -619,11 +807,20 @@
  *
  * @pinst: padata instance to start
  */
-void padata_start(struct padata_instance *pinst)
+int padata_start(struct padata_instance *pinst)
 {
+	int err = 0;
+
 	mutex_lock(&pinst->lock);
-	pinst->flags |= PADATA_INIT;
+
+	if (pinst->flags & PADATA_INVALID)
+		err =-EINVAL;
+
+	 __padata_start(pinst);
+
 	mutex_unlock(&pinst->lock);
+
+	return err;
 }
 EXPORT_SYMBOL(padata_start);
 
@@ -635,12 +832,20 @@
 void padata_stop(struct padata_instance *pinst)
 {
 	mutex_lock(&pinst->lock);
-	pinst->flags &= ~PADATA_INIT;
+	__padata_stop(pinst);
 	mutex_unlock(&pinst->lock);
 }
 EXPORT_SYMBOL(padata_stop);
 
 #ifdef CONFIG_HOTPLUG_CPU
+
+static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu)
+{
+	return cpumask_test_cpu(cpu, pinst->cpumask.pcpu) ||
+		cpumask_test_cpu(cpu, pinst->cpumask.cbcpu);
+}
+
+
 static int padata_cpu_callback(struct notifier_block *nfb,
 			       unsigned long action, void *hcpu)
 {
@@ -653,7 +858,7 @@
 	switch (action) {
 	case CPU_ONLINE:
 	case CPU_ONLINE_FROZEN:
-		if (!cpumask_test_cpu(cpu, pinst->cpumask))
+		if (!pinst_has_cpu(pinst, cpu))
 			break;
 		mutex_lock(&pinst->lock);
 		err = __padata_add_cpu(pinst, cpu);
@@ -664,7 +869,7 @@
 
 	case CPU_DOWN_PREPARE:
 	case CPU_DOWN_PREPARE_FROZEN:
-		if (!cpumask_test_cpu(cpu, pinst->cpumask))
+		if (!pinst_has_cpu(pinst, cpu))
 			break;
 		mutex_lock(&pinst->lock);
 		err = __padata_remove_cpu(pinst, cpu);
@@ -675,7 +880,7 @@
 
 	case CPU_UP_CANCELED:
 	case CPU_UP_CANCELED_FROZEN:
-		if (!cpumask_test_cpu(cpu, pinst->cpumask))
+		if (!pinst_has_cpu(pinst, cpu))
 			break;
 		mutex_lock(&pinst->lock);
 		__padata_remove_cpu(pinst, cpu);
@@ -683,7 +888,7 @@
 
 	case CPU_DOWN_FAILED:
 	case CPU_DOWN_FAILED_FROZEN:
-		if (!cpumask_test_cpu(cpu, pinst->cpumask))
+		if (!pinst_has_cpu(pinst, cpu))
 			break;
 		mutex_lock(&pinst->lock);
 		__padata_add_cpu(pinst, cpu);
@@ -694,36 +899,202 @@
 }
 #endif
 
-/**
- * padata_alloc - allocate and initialize a padata instance
- *
- * @cpumask: cpumask that padata uses for parallelization
- * @wq: workqueue to use for the allocated padata instance
+static void __padata_free(struct padata_instance *pinst)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+	unregister_hotcpu_notifier(&pinst->cpu_notifier);
+#endif
+
+	padata_stop(pinst);
+	padata_free_pd(pinst->pd);
+	free_cpumask_var(pinst->cpumask.pcpu);
+	free_cpumask_var(pinst->cpumask.cbcpu);
+	kfree(pinst);
+}
+
+#define kobj2pinst(_kobj)					\
+	container_of(_kobj, struct padata_instance, kobj)
+#define attr2pentry(_attr)					\
+	container_of(_attr, struct padata_sysfs_entry, attr)
+
+static void padata_sysfs_release(struct kobject *kobj)
+{
+	struct padata_instance *pinst = kobj2pinst(kobj);
+	__padata_free(pinst);
+}
+
+struct padata_sysfs_entry {
+	struct attribute attr;
+	ssize_t (*show)(struct padata_instance *, struct attribute *, char *);
+	ssize_t (*store)(struct padata_instance *, struct attribute *,
+			 const char *, size_t);
+};
+
+static ssize_t show_cpumask(struct padata_instance *pinst,
+			    struct attribute *attr,  char *buf)
+{
+	struct cpumask *cpumask;
+	ssize_t len;
+
+	mutex_lock(&pinst->lock);
+	if (!strcmp(attr->name, "serial_cpumask"))
+		cpumask = pinst->cpumask.cbcpu;
+	else
+		cpumask = pinst->cpumask.pcpu;
+
+	len = bitmap_scnprintf(buf, PAGE_SIZE, cpumask_bits(cpumask),
+			       nr_cpu_ids);
+	if (PAGE_SIZE - len < 2)
+		len = -EINVAL;
+	else
+		len += sprintf(buf + len, "\n");
+
+	mutex_unlock(&pinst->lock);
+	return len;
+}
+
+static ssize_t store_cpumask(struct padata_instance *pinst,
+			     struct attribute *attr,
+			     const char *buf, size_t count)
+{
+	cpumask_var_t new_cpumask;
+	ssize_t ret;
+	int mask_type;
+
+	if (!alloc_cpumask_var(&new_cpumask, GFP_KERNEL))
+		return -ENOMEM;
+
+	ret = bitmap_parse(buf, count, cpumask_bits(new_cpumask),
+			   nr_cpumask_bits);
+	if (ret < 0)
+		goto out;
+
+	mask_type = !strcmp(attr->name, "serial_cpumask") ?
+		PADATA_CPU_SERIAL : PADATA_CPU_PARALLEL;
+	ret = padata_set_cpumask(pinst, mask_type, new_cpumask);
+	if (!ret)
+		ret = count;
+
+out:
+	free_cpumask_var(new_cpumask);
+	return ret;
+}
+
+#define PADATA_ATTR_RW(_name, _show_name, _store_name)		\
+	static struct padata_sysfs_entry _name##_attr =		\
+		__ATTR(_name, 0644, _show_name, _store_name)
+#define PADATA_ATTR_RO(_name, _show_name)		\
+	static struct padata_sysfs_entry _name##_attr = \
+		__ATTR(_name, 0400, _show_name, NULL)
+
+PADATA_ATTR_RW(serial_cpumask, show_cpumask, store_cpumask);
+PADATA_ATTR_RW(parallel_cpumask, show_cpumask, store_cpumask);
+
+/*
+ * Padata sysfs provides the following objects:
+ * serial_cpumask   [RW] - cpumask for serial workers
+ * parallel_cpumask [RW] - cpumask for parallel workers
  */
-struct padata_instance *padata_alloc(const struct cpumask *cpumask,
-				     struct workqueue_struct *wq)
+static struct attribute *padata_default_attrs[] = {
+	&serial_cpumask_attr.attr,
+	&parallel_cpumask_attr.attr,
+	NULL,
+};
+
+static ssize_t padata_sysfs_show(struct kobject *kobj,
+				 struct attribute *attr, char *buf)
 {
 	struct padata_instance *pinst;
-	struct parallel_data *pd;
+	struct padata_sysfs_entry *pentry;
+	ssize_t ret = -EIO;
+
+	pinst = kobj2pinst(kobj);
+	pentry = attr2pentry(attr);
+	if (pentry->show)
+		ret = pentry->show(pinst, attr, buf);
+
+	return ret;
+}
+
+static ssize_t padata_sysfs_store(struct kobject *kobj, struct attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct padata_instance *pinst;
+	struct padata_sysfs_entry *pentry;
+	ssize_t ret = -EIO;
+
+	pinst = kobj2pinst(kobj);
+	pentry = attr2pentry(attr);
+	if (pentry->show)
+		ret = pentry->store(pinst, attr, buf, count);
+
+	return ret;
+}
+
+static const struct sysfs_ops padata_sysfs_ops = {
+	.show = padata_sysfs_show,
+	.store = padata_sysfs_store,
+};
+
+static struct kobj_type padata_attr_type = {
+	.sysfs_ops = &padata_sysfs_ops,
+	.default_attrs = padata_default_attrs,
+	.release = padata_sysfs_release,
+};
+
+/**
+ * padata_alloc_possible - Allocate and initialize padata instance.
+ *                         Use the cpu_possible_mask for serial and
+ *                         parallel workers.
+ *
+ * @wq: workqueue to use for the allocated padata instance
+ */
+struct padata_instance *padata_alloc_possible(struct workqueue_struct *wq)
+{
+	return padata_alloc(wq, cpu_possible_mask, cpu_possible_mask);
+}
+EXPORT_SYMBOL(padata_alloc_possible);
+
+/**
+ * padata_alloc - allocate and initialize a padata instance and specify
+ *                cpumasks for serial and parallel workers.
+ *
+ * @wq: workqueue to use for the allocated padata instance
+ * @pcpumask: cpumask that will be used for padata parallelization
+ * @cbcpumask: cpumask that will be used for padata serialization
+ */
+struct padata_instance *padata_alloc(struct workqueue_struct *wq,
+				     const struct cpumask *pcpumask,
+				     const struct cpumask *cbcpumask)
+{
+	struct padata_instance *pinst;
+	struct parallel_data *pd = NULL;
 
 	pinst = kzalloc(sizeof(struct padata_instance), GFP_KERNEL);
 	if (!pinst)
 		goto err;
 
 	get_online_cpus();
-
-	pd = padata_alloc_pd(pinst, cpumask);
-	if (!pd)
+	if (!alloc_cpumask_var(&pinst->cpumask.pcpu, GFP_KERNEL))
 		goto err_free_inst;
+	if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) {
+		free_cpumask_var(pinst->cpumask.pcpu);
+		goto err_free_inst;
+	}
+	if (!padata_validate_cpumask(pinst, pcpumask) ||
+	    !padata_validate_cpumask(pinst, cbcpumask))
+		goto err_free_masks;
 
-	if (!alloc_cpumask_var(&pinst->cpumask, GFP_KERNEL))
-		goto err_free_pd;
+	pd = padata_alloc_pd(pinst, pcpumask, cbcpumask);
+	if (!pd)
+		goto err_free_masks;
 
 	rcu_assign_pointer(pinst->pd, pd);
 
 	pinst->wq = wq;
 
-	cpumask_copy(pinst->cpumask, cpumask);
+	cpumask_copy(pinst->cpumask.pcpu, pcpumask);
+	cpumask_copy(pinst->cpumask.cbcpu, cbcpumask);
 
 	pinst->flags = 0;
 
@@ -735,12 +1106,15 @@
 
 	put_online_cpus();
 
+	BLOCKING_INIT_NOTIFIER_HEAD(&pinst->cpumask_change_notifier);
+	kobject_init(&pinst->kobj, &padata_attr_type);
 	mutex_init(&pinst->lock);
 
 	return pinst;
 
-err_free_pd:
-	padata_free_pd(pd);
+err_free_masks:
+	free_cpumask_var(pinst->cpumask.pcpu);
+	free_cpumask_var(pinst->cpumask.cbcpu);
 err_free_inst:
 	kfree(pinst);
 	put_online_cpus();
@@ -756,19 +1130,6 @@
  */
 void padata_free(struct padata_instance *pinst)
 {
-	padata_stop(pinst);
-
-	synchronize_rcu();
-
-#ifdef CONFIG_HOTPLUG_CPU
-	unregister_hotcpu_notifier(&pinst->cpu_notifier);
-#endif
-	get_online_cpus();
-	padata_flush_queues(pinst->pd);
-	put_online_cpus();
-
-	padata_free_pd(pinst->pd);
-	free_cpumask_var(pinst->cpumask);
-	kfree(pinst);
+	kobject_put(&pinst->kobj);
 }
 EXPORT_SYMBOL(padata_free);
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
index f42d3f7..996a4de 100644
--- a/kernel/pm_qos_params.c
+++ b/kernel/pm_qos_params.c
@@ -48,59 +48,49 @@
  * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
  * held, taken with _irqsave.  One lock to rule them all
  */
-struct pm_qos_request_list {
-	struct list_head list;
-	union {
-		s32 value;
-		s32 usec;
-		s32 kbps;
-	};
-	int pm_qos_class;
+enum pm_qos_type {
+	PM_QOS_MAX,		/* return the largest value */
+	PM_QOS_MIN		/* return the smallest value */
 };
 
-static s32 max_compare(s32 v1, s32 v2);
-static s32 min_compare(s32 v1, s32 v2);
-
 struct pm_qos_object {
-	struct pm_qos_request_list requests;
+	struct plist_head requests;
 	struct blocking_notifier_head *notifiers;
 	struct miscdevice pm_qos_power_miscdev;
 	char *name;
 	s32 default_value;
-	atomic_t target_value;
-	s32 (*comparitor)(s32, s32);
+	enum pm_qos_type type;
 };
 
+static DEFINE_SPINLOCK(pm_qos_lock);
+
 static struct pm_qos_object null_pm_qos;
 static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
 static struct pm_qos_object cpu_dma_pm_qos = {
-	.requests = {LIST_HEAD_INIT(cpu_dma_pm_qos.requests.list)},
+	.requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
 	.notifiers = &cpu_dma_lat_notifier,
 	.name = "cpu_dma_latency",
 	.default_value = 2000 * USEC_PER_SEC,
-	.target_value = ATOMIC_INIT(2000 * USEC_PER_SEC),
-	.comparitor = min_compare
+	.type = PM_QOS_MIN,
 };
 
 static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
 static struct pm_qos_object network_lat_pm_qos = {
-	.requests = {LIST_HEAD_INIT(network_lat_pm_qos.requests.list)},
+	.requests = PLIST_HEAD_INIT(network_lat_pm_qos.requests, pm_qos_lock),
 	.notifiers = &network_lat_notifier,
 	.name = "network_latency",
 	.default_value = 2000 * USEC_PER_SEC,
-	.target_value = ATOMIC_INIT(2000 * USEC_PER_SEC),
-	.comparitor = min_compare
+	.type = PM_QOS_MIN
 };
 
 
 static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
 static struct pm_qos_object network_throughput_pm_qos = {
-	.requests = {LIST_HEAD_INIT(network_throughput_pm_qos.requests.list)},
+	.requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
 	.notifiers = &network_throughput_notifier,
 	.name = "network_throughput",
 	.default_value = 0,
-	.target_value = ATOMIC_INIT(0),
-	.comparitor = max_compare
+	.type = PM_QOS_MAX,
 };
 
 
@@ -111,8 +101,6 @@
 	&network_throughput_pm_qos
 };
 
-static DEFINE_SPINLOCK(pm_qos_lock);
-
 static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
 		size_t count, loff_t *f_pos);
 static int pm_qos_power_open(struct inode *inode, struct file *filp);
@@ -124,46 +112,55 @@
 	.release = pm_qos_power_release,
 };
 
-/* static helper functions */
-static s32 max_compare(s32 v1, s32 v2)
+/* unlocked internal variant */
+static inline int pm_qos_get_value(struct pm_qos_object *o)
 {
-	return max(v1, v2);
+	if (plist_head_empty(&o->requests))
+		return o->default_value;
+
+	switch (o->type) {
+	case PM_QOS_MIN:
+		return plist_last(&o->requests)->prio;
+
+	case PM_QOS_MAX:
+		return plist_first(&o->requests)->prio;
+
+	default:
+		/* runtime check for not using enum */
+		BUG();
+	}
 }
 
-static s32 min_compare(s32 v1, s32 v2)
+static void update_target(struct pm_qos_object *o, struct plist_node *node,
+			  int del, int value)
 {
-	return min(v1, v2);
-}
-
-
-static void update_target(int pm_qos_class)
-{
-	s32 extreme_value;
-	struct pm_qos_request_list *node;
 	unsigned long flags;
-	int call_notifier = 0;
+	int prev_value, curr_value;
 
 	spin_lock_irqsave(&pm_qos_lock, flags);
-	extreme_value = pm_qos_array[pm_qos_class]->default_value;
-	list_for_each_entry(node,
-			&pm_qos_array[pm_qos_class]->requests.list, list) {
-		extreme_value = pm_qos_array[pm_qos_class]->comparitor(
-				extreme_value, node->value);
+	prev_value = pm_qos_get_value(o);
+	/* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
+	if (value != PM_QOS_DEFAULT_VALUE) {
+		/*
+		 * to change the list, we atomically remove, reinit
+		 * with new value and add, then see if the extremal
+		 * changed
+		 */
+		plist_del(node, &o->requests);
+		plist_node_init(node, value);
+		plist_add(node, &o->requests);
+	} else if (del) {
+		plist_del(node, &o->requests);
+	} else {
+		plist_add(node, &o->requests);
 	}
-	if (atomic_read(&pm_qos_array[pm_qos_class]->target_value) !=
-			extreme_value) {
-		call_notifier = 1;
-		atomic_set(&pm_qos_array[pm_qos_class]->target_value,
-				extreme_value);
-		pr_debug(KERN_ERR "new target for qos %d is %d\n", pm_qos_class,
-			atomic_read(&pm_qos_array[pm_qos_class]->target_value));
-	}
+	curr_value = pm_qos_get_value(o);
 	spin_unlock_irqrestore(&pm_qos_lock, flags);
 
-	if (call_notifier)
-		blocking_notifier_call_chain(
-				pm_qos_array[pm_qos_class]->notifiers,
-					(unsigned long) extreme_value, NULL);
+	if (prev_value != curr_value)
+		blocking_notifier_call_chain(o->notifiers,
+					     (unsigned long)curr_value,
+					     NULL);
 }
 
 static int register_pm_qos_misc(struct pm_qos_object *qos)
@@ -196,10 +193,23 @@
  */
 int pm_qos_request(int pm_qos_class)
 {
-	return atomic_read(&pm_qos_array[pm_qos_class]->target_value);
+	unsigned long flags;
+	int value;
+
+	spin_lock_irqsave(&pm_qos_lock, flags);
+	value = pm_qos_get_value(pm_qos_array[pm_qos_class]);
+	spin_unlock_irqrestore(&pm_qos_lock, flags);
+
+	return value;
 }
 EXPORT_SYMBOL_GPL(pm_qos_request);
 
+int pm_qos_request_active(struct pm_qos_request_list *req)
+{
+	return req->pm_qos_class != 0;
+}
+EXPORT_SYMBOL_GPL(pm_qos_request_active);
+
 /**
  * pm_qos_add_request - inserts new qos request into the list
  * @pm_qos_class: identifies which list of qos request to us
@@ -211,27 +221,23 @@
  * element as a handle for use in updating and removal.  Call needs to save
  * this handle for later use.
  */
-struct pm_qos_request_list *pm_qos_add_request(int pm_qos_class, s32 value)
+void pm_qos_add_request(struct pm_qos_request_list *dep,
+			int pm_qos_class, s32 value)
 {
-	struct pm_qos_request_list *dep;
-	unsigned long flags;
+	struct pm_qos_object *o =  pm_qos_array[pm_qos_class];
+	int new_value;
 
-	dep = kzalloc(sizeof(struct pm_qos_request_list), GFP_KERNEL);
-	if (dep) {
-		if (value == PM_QOS_DEFAULT_VALUE)
-			dep->value = pm_qos_array[pm_qos_class]->default_value;
-		else
-			dep->value = value;
-		dep->pm_qos_class = pm_qos_class;
-
-		spin_lock_irqsave(&pm_qos_lock, flags);
-		list_add(&dep->list,
-			&pm_qos_array[pm_qos_class]->requests.list);
-		spin_unlock_irqrestore(&pm_qos_lock, flags);
-		update_target(pm_qos_class);
+	if (pm_qos_request_active(dep)) {
+		WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
+		return;
 	}
-
-	return dep;
+	if (value == PM_QOS_DEFAULT_VALUE)
+		new_value = o->default_value;
+	else
+		new_value = value;
+	plist_node_init(&dep->list, new_value);
+	dep->pm_qos_class = pm_qos_class;
+	update_target(o, &dep->list, 0, PM_QOS_DEFAULT_VALUE);
 }
 EXPORT_SYMBOL_GPL(pm_qos_add_request);
 
@@ -246,27 +252,28 @@
  * Attempts are made to make this code callable on hot code paths.
  */
 void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
-		s32 new_value)
+			   s32 new_value)
 {
-	unsigned long flags;
-	int pending_update = 0;
 	s32 temp;
+	struct pm_qos_object *o;
 
-	if (pm_qos_req) { /*guard against callers passing in null */
-		spin_lock_irqsave(&pm_qos_lock, flags);
-		if (new_value == PM_QOS_DEFAULT_VALUE)
-			temp = pm_qos_array[pm_qos_req->pm_qos_class]->default_value;
-		else
-			temp = new_value;
+	if (!pm_qos_req) /*guard against callers passing in null */
+		return;
 
-		if (temp != pm_qos_req->value) {
-			pending_update = 1;
-			pm_qos_req->value = temp;
-		}
-		spin_unlock_irqrestore(&pm_qos_lock, flags);
-		if (pending_update)
-			update_target(pm_qos_req->pm_qos_class);
+	if (!pm_qos_request_active(pm_qos_req)) {
+		WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n");
+		return;
 	}
+
+	o = pm_qos_array[pm_qos_req->pm_qos_class];
+
+	if (new_value == PM_QOS_DEFAULT_VALUE)
+		temp = o->default_value;
+	else
+		temp = new_value;
+
+	if (temp != pm_qos_req->list.prio)
+		update_target(o, &pm_qos_req->list, 0, temp);
 }
 EXPORT_SYMBOL_GPL(pm_qos_update_request);
 
@@ -280,19 +287,20 @@
  */
 void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req)
 {
-	unsigned long flags;
-	int qos_class;
+	struct pm_qos_object *o;
 
 	if (pm_qos_req == NULL)
 		return;
 		/* silent return to keep pcm code cleaner */
 
-	qos_class = pm_qos_req->pm_qos_class;
-	spin_lock_irqsave(&pm_qos_lock, flags);
-	list_del(&pm_qos_req->list);
-	kfree(pm_qos_req);
-	spin_unlock_irqrestore(&pm_qos_lock, flags);
-	update_target(qos_class);
+	if (!pm_qos_request_active(pm_qos_req)) {
+		WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
+		return;
+	}
+
+	o = pm_qos_array[pm_qos_req->pm_qos_class];
+	update_target(o, &pm_qos_req->list, 1, PM_QOS_DEFAULT_VALUE);
+	memset(pm_qos_req, 0, sizeof(*pm_qos_req));
 }
 EXPORT_SYMBOL_GPL(pm_qos_remove_request);
 
@@ -340,8 +348,12 @@
 
 	pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
 	if (pm_qos_class >= 0) {
-		filp->private_data = (void *) pm_qos_add_request(pm_qos_class,
-				PM_QOS_DEFAULT_VALUE);
+		struct pm_qos_request_list *req = kzalloc(GFP_KERNEL, sizeof(*req));
+		if (!req)
+			return -ENOMEM;
+
+		pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
+		filp->private_data = req;
 
 		if (filp->private_data)
 			return 0;
@@ -353,8 +365,9 @@
 {
 	struct pm_qos_request_list *req;
 
-	req = (struct pm_qos_request_list *)filp->private_data;
+	req = filp->private_data;
 	pm_qos_remove_request(req);
+	kfree(req);
 
 	return 0;
 }
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 6b202e7..8dc31e0 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -277,7 +277,7 @@
 		goto Enable_irqs;
 	}
 
-	if (hibernation_test(TEST_CORE))
+	if (hibernation_test(TEST_CORE) || !pm_check_wakeup_events())
 		goto Power_up;
 
 	in_suspend = 1;
@@ -288,8 +288,10 @@
 			error);
 	/* Restore control flow magically appears here */
 	restore_processor_state();
-	if (!in_suspend)
+	if (!in_suspend) {
+		events_check_enabled = false;
 		platform_leave(platform_mode);
+	}
 
  Power_up:
 	sysdev_resume();
@@ -328,7 +330,7 @@
 
 	error = platform_begin(platform_mode);
 	if (error)
-		return error;
+		goto Close;
 
 	/* Preallocate image memory before shutting down devices. */
 	error = hibernate_preallocate_memory();
@@ -511,18 +513,24 @@
 
 	local_irq_disable();
 	sysdev_suspend(PMSG_HIBERNATE);
+	if (!pm_check_wakeup_events()) {
+		error = -EAGAIN;
+		goto Power_up;
+	}
+
 	hibernation_ops->enter();
 	/* We should never get here */
 	while (1);
 
-	/*
-	 * We don't need to reenable the nonboot CPUs or resume consoles, since
-	 * the system is going to be halted anyway.
-	 */
+ Power_up:
+	sysdev_resume();
+	local_irq_enable();
+	enable_nonboot_cpus();
+
  Platform_finish:
 	hibernation_ops->finish();
 
-	dpm_suspend_noirq(PMSG_RESTORE);
+	dpm_resume_noirq(PMSG_RESTORE);
 
  Resume_devices:
 	entering_platform_hibernation = false;
diff --git a/kernel/power/main.c b/kernel/power/main.c
index b58800b..62b0bc6 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -204,6 +204,60 @@
 
 power_attr(state);
 
+#ifdef CONFIG_PM_SLEEP
+/*
+ * The 'wakeup_count' attribute, along with the functions defined in
+ * drivers/base/power/wakeup.c, provides a means by which wakeup events can be
+ * handled in a non-racy way.
+ *
+ * If a wakeup event occurs when the system is in a sleep state, it simply is
+ * woken up.  In turn, if an event that would wake the system up from a sleep
+ * state occurs when it is undergoing a transition to that sleep state, the
+ * transition should be aborted.  Moreover, if such an event occurs when the
+ * system is in the working state, an attempt to start a transition to the
+ * given sleep state should fail during certain period after the detection of
+ * the event.  Using the 'state' attribute alone is not sufficient to satisfy
+ * these requirements, because a wakeup event may occur exactly when 'state'
+ * is being written to and may be delivered to user space right before it is
+ * frozen, so the event will remain only partially processed until the system is
+ * woken up by another event.  In particular, it won't cause the transition to
+ * a sleep state to be aborted.
+ *
+ * This difficulty may be overcome if user space uses 'wakeup_count' before
+ * writing to 'state'.  It first should read from 'wakeup_count' and store
+ * the read value.  Then, after carrying out its own preparations for the system
+ * transition to a sleep state, it should write the stored value to
+ * 'wakeup_count'.  If that fails, at least one wakeup event has occured since
+ * 'wakeup_count' was read and 'state' should not be written to.  Otherwise, it
+ * is allowed to write to 'state', but the transition will be aborted if there
+ * are any wakeup events detected after 'wakeup_count' was written to.
+ */
+
+static ssize_t wakeup_count_show(struct kobject *kobj,
+				struct kobj_attribute *attr,
+				char *buf)
+{
+	unsigned long val;
+
+	return pm_get_wakeup_count(&val) ? sprintf(buf, "%lu\n", val) : -EINTR;
+}
+
+static ssize_t wakeup_count_store(struct kobject *kobj,
+				struct kobj_attribute *attr,
+				const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lu", &val) == 1) {
+		if (pm_save_wakeup_count(val))
+			return n;
+	}
+	return -EINVAL;
+}
+
+power_attr(wakeup_count);
+#endif /* CONFIG_PM_SLEEP */
+
 #ifdef CONFIG_PM_TRACE
 int pm_trace_enabled;
 
@@ -236,6 +290,7 @@
 #endif
 #ifdef CONFIG_PM_SLEEP
 	&pm_async_attr.attr,
+	&wakeup_count_attr.attr,
 #ifdef CONFIG_PM_DEBUG
 	&pm_test_attr.attr,
 #endif
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index f37cb7d..7335952 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -136,19 +136,19 @@
 	if (suspend_ops->prepare) {
 		error = suspend_ops->prepare();
 		if (error)
-			return error;
+			goto Platform_finish;
 	}
 
 	error = dpm_suspend_noirq(PMSG_SUSPEND);
 	if (error) {
 		printk(KERN_ERR "PM: Some devices failed to power down\n");
-		goto Platfrom_finish;
+		goto Platform_finish;
 	}
 
 	if (suspend_ops->prepare_late) {
 		error = suspend_ops->prepare_late();
 		if (error)
-			goto Power_up_devices;
+			goto Platform_wake;
 	}
 
 	if (suspend_test(TEST_PLATFORM))
@@ -163,8 +163,10 @@
 
 	error = sysdev_suspend(PMSG_SUSPEND);
 	if (!error) {
-		if (!suspend_test(TEST_CORE))
+		if (!suspend_test(TEST_CORE) && pm_check_wakeup_events()) {
 			error = suspend_ops->enter(state);
+			events_check_enabled = false;
+		}
 		sysdev_resume();
 	}
 
@@ -178,10 +180,9 @@
 	if (suspend_ops->wake)
 		suspend_ops->wake();
 
- Power_up_devices:
 	dpm_resume_noirq(PMSG_RESUME);
 
- Platfrom_finish:
+ Platform_finish:
 	if (suspend_ops->finish)
 		suspend_ops->finish();
 
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 48a0aa9..e6a5bdf 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -32,7 +32,7 @@
 /*
  *	The swap map is a data structure used for keeping track of each page
  *	written to a swap partition.  It consists of many swap_map_page
- *	structures that contain each an array of MAP_PAGE_SIZE swap entries.
+ *	structures that contain each an array of MAP_PAGE_ENTRIES swap entries.
  *	These structures are stored on the swap and linked together with the
  *	help of the .next_swap member.
  *
@@ -148,7 +148,7 @@
 
 /**
  *	free_all_swap_pages - free swap pages allocated for saving image data.
- *	It also frees the extents used to register which swap entres had been
+ *	It also frees the extents used to register which swap entries had been
  *	allocated.
  */
 
diff --git a/kernel/signal.c b/kernel/signal.c
index 906ae5a1..bded651 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -637,7 +637,7 @@
 
 /*
  * Bad permissions for sending the signal
- * - the caller must hold at least the RCU read lock
+ * - the caller must hold the RCU read lock
  */
 static int check_kill_permission(int sig, struct siginfo *info,
 				 struct task_struct *t)
@@ -1127,11 +1127,14 @@
 
 /*
  * 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)
 {
-	int ret = check_kill_permission(sig, info, p);
+	int ret;
+
+	rcu_read_lock();
+	ret = check_kill_permission(sig, info, p);
+	rcu_read_unlock();
 
 	if (!ret && sig)
 		ret = do_send_sig_info(sig, info, p, true);
diff --git a/kernel/timer.c b/kernel/timer.c
index ee305c8..efde11e 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -577,6 +577,19 @@
 	lockdep_init_map(&timer->lockdep_map, name, key, 0);
 }
 
+void setup_deferrable_timer_on_stack_key(struct timer_list *timer,
+					 const char *name,
+					 struct lock_class_key *key,
+					 void (*function)(unsigned long),
+					 unsigned long data)
+{
+	timer->function = function;
+	timer->data = data;
+	init_timer_on_stack_key(timer, name, key);
+	timer_set_deferrable(timer);
+}
+EXPORT_SYMBOL_GPL(setup_deferrable_timer_on_stack_key);
+
 /**
  * init_timer_key - initialize a timer
  * @timer: the timer to be initialized
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index b2d70d3..2591583 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -9,6 +9,7 @@
 #include <linux/nsproxy.h>
 #include <linux/slab.h>
 #include <linux/user_namespace.h>
+#include <linux/highuid.h>
 #include <linux/cred.h>
 
 /*
@@ -82,3 +83,46 @@
 	schedule_work(&ns->destroyer);
 }
 EXPORT_SYMBOL(free_user_ns);
+
+uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid)
+{
+	struct user_namespace *tmp;
+
+	if (likely(to == cred->user->user_ns))
+		return uid;
+
+
+	/* Is cred->user the creator of the target user_ns
+	 * or the creator of one of it's parents?
+	 */
+	for ( tmp = to; tmp != &init_user_ns;
+	      tmp = tmp->creator->user_ns ) {
+		if (cred->user == tmp->creator) {
+			return (uid_t)0;
+		}
+	}
+
+	/* No useful relationship so no mapping */
+	return overflowuid;
+}
+
+gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid)
+{
+	struct user_namespace *tmp;
+
+	if (likely(to == cred->user->user_ns))
+		return gid;
+
+	/* Is cred->user the creator of the target user_ns
+	 * or the creator of one of it's parents?
+	 */
+	for ( tmp = to; tmp != &init_user_ns;
+	      tmp = tmp->creator->user_ns ) {
+		if (cred->user == tmp->creator) {
+			return (gid_t)0;
+		}
+	}
+
+	/* No useful relationship so no mapping */
+	return overflowgid;
+}
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index a009055..34e3082 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -50,19 +50,11 @@
  */
 #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
 
-/*
- * Enumeration for sync targets
- */
-enum dma_sync_target {
-	SYNC_FOR_CPU = 0,
-	SYNC_FOR_DEVICE = 1,
-};
-
 int swiotlb_force;
 
 /*
- * Used to do a quick range check in unmap_single and
- * sync_single_*, to see if the memory was in fact allocated by this
+ * Used to do a quick range check in swiotlb_tbl_unmap_single and
+ * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
  * API.
  */
 static char *io_tlb_start, *io_tlb_end;
@@ -140,28 +132,14 @@
 	       (unsigned long long)pend);
 }
 
-/*
- * Statically reserve bounce buffer space and initialize bounce buffer data
- * structures for the software IO TLB used to implement the DMA API.
- */
-void __init
-swiotlb_init_with_default_size(size_t default_size, int verbose)
+void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
 {
 	unsigned long i, bytes;
 
-	if (!io_tlb_nslabs) {
-		io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
-		io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
-	}
+	bytes = nslabs << IO_TLB_SHIFT;
 
-	bytes = io_tlb_nslabs << IO_TLB_SHIFT;
-
-	/*
-	 * Get IO TLB memory from the low pages
-	 */
-	io_tlb_start = alloc_bootmem_low_pages(bytes);
-	if (!io_tlb_start)
-		panic("Cannot allocate SWIOTLB buffer");
+	io_tlb_nslabs = nslabs;
+	io_tlb_start = tlb;
 	io_tlb_end = io_tlb_start + bytes;
 
 	/*
@@ -185,6 +163,32 @@
 		swiotlb_print_info();
 }
 
+/*
+ * Statically reserve bounce buffer space and initialize bounce buffer data
+ * structures for the software IO TLB used to implement the DMA API.
+ */
+void __init
+swiotlb_init_with_default_size(size_t default_size, int verbose)
+{
+	unsigned long bytes;
+
+	if (!io_tlb_nslabs) {
+		io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
+		io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
+	}
+
+	bytes = io_tlb_nslabs << IO_TLB_SHIFT;
+
+	/*
+	 * Get IO TLB memory from the low pages
+	 */
+	io_tlb_start = alloc_bootmem_low_pages(bytes);
+	if (!io_tlb_start)
+		panic("Cannot allocate SWIOTLB buffer");
+
+	swiotlb_init_with_tbl(io_tlb_start, io_tlb_nslabs, verbose);
+}
+
 void __init
 swiotlb_init(int verbose)
 {
@@ -323,8 +327,8 @@
 /*
  * Bounce: copy the swiotlb buffer back to the original dma location
  */
-static void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
-			   enum dma_data_direction dir)
+void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
+		    enum dma_data_direction dir)
 {
 	unsigned long pfn = PFN_DOWN(phys);
 
@@ -360,26 +364,25 @@
 			memcpy(phys_to_virt(phys), dma_addr, size);
 	}
 }
+EXPORT_SYMBOL_GPL(swiotlb_bounce);
 
-/*
- * Allocates bounce buffer and returns its kernel virtual address.
- */
-static void *
-map_single(struct device *hwdev, phys_addr_t phys, size_t size, int dir)
+void *swiotlb_tbl_map_single(struct device *hwdev, dma_addr_t tbl_dma_addr,
+			     phys_addr_t phys, size_t size,
+			     enum dma_data_direction dir)
 {
 	unsigned long flags;
 	char *dma_addr;
 	unsigned int nslots, stride, index, wrap;
 	int i;
-	unsigned long start_dma_addr;
 	unsigned long mask;
 	unsigned long offset_slots;
 	unsigned long max_slots;
 
 	mask = dma_get_seg_boundary(hwdev);
-	start_dma_addr = swiotlb_virt_to_bus(hwdev, io_tlb_start) & mask;
 
-	offset_slots = ALIGN(start_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+	tbl_dma_addr &= mask;
+
+	offset_slots = ALIGN(tbl_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
 
 	/*
  	 * Carefully handle integer overflow which can occur when mask == ~0UL.
@@ -466,12 +469,27 @@
 
 	return dma_addr;
 }
+EXPORT_SYMBOL_GPL(swiotlb_tbl_map_single);
+
+/*
+ * Allocates bounce buffer and returns its kernel virtual address.
+ */
+
+static void *
+map_single(struct device *hwdev, phys_addr_t phys, size_t size,
+	   enum dma_data_direction dir)
+{
+	dma_addr_t start_dma_addr = swiotlb_virt_to_bus(hwdev, io_tlb_start);
+
+	return swiotlb_tbl_map_single(hwdev, start_dma_addr, phys, size, dir);
+}
 
 /*
  * dma_addr is the kernel virtual address of the bounce buffer to unmap.
  */
-static void
-do_unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
+void
+swiotlb_tbl_unmap_single(struct device *hwdev, char *dma_addr, size_t size,
+			enum dma_data_direction dir)
 {
 	unsigned long flags;
 	int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
@@ -509,10 +527,12 @@
 	}
 	spin_unlock_irqrestore(&io_tlb_lock, flags);
 }
+EXPORT_SYMBOL_GPL(swiotlb_tbl_unmap_single);
 
-static void
-sync_single(struct device *hwdev, char *dma_addr, size_t size,
-	    int dir, int target)
+void
+swiotlb_tbl_sync_single(struct device *hwdev, char *dma_addr, size_t size,
+			enum dma_data_direction dir,
+			enum dma_sync_target target)
 {
 	int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
 	phys_addr_t phys = io_tlb_orig_addr[index];
@@ -536,6 +556,7 @@
 		BUG();
 	}
 }
+EXPORT_SYMBOL_GPL(swiotlb_tbl_sync_single);
 
 void *
 swiotlb_alloc_coherent(struct device *hwdev, size_t size,
@@ -559,8 +580,8 @@
 	}
 	if (!ret) {
 		/*
-		 * We are either out of memory or the device can't DMA
-		 * to GFP_DMA memory; fall back on map_single(), which
+		 * We are either out of memory or the device can't DMA to
+		 * GFP_DMA memory; fall back on map_single(), which
 		 * will grab memory from the lowest available address range.
 		 */
 		ret = map_single(hwdev, 0, size, DMA_FROM_DEVICE);
@@ -578,7 +599,7 @@
 		       (unsigned long long)dev_addr);
 
 		/* DMA_TO_DEVICE to avoid memcpy in unmap_single */
-		do_unmap_single(hwdev, ret, size, DMA_TO_DEVICE);
+		swiotlb_tbl_unmap_single(hwdev, ret, size, DMA_TO_DEVICE);
 		return NULL;
 	}
 	*dma_handle = dev_addr;
@@ -596,13 +617,14 @@
 	if (!is_swiotlb_buffer(paddr))
 		free_pages((unsigned long)vaddr, get_order(size));
 	else
-		/* DMA_TO_DEVICE to avoid memcpy in unmap_single */
-		do_unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE);
+		/* DMA_TO_DEVICE to avoid memcpy in swiotlb_tbl_unmap_single */
+		swiotlb_tbl_unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE);
 }
 EXPORT_SYMBOL(swiotlb_free_coherent);
 
 static void
-swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
+swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir,
+	     int do_panic)
 {
 	/*
 	 * Ran out of IOMMU space for this operation. This is very bad.
@@ -680,14 +702,14 @@
  * whatever the device wrote there.
  */
 static void unmap_single(struct device *hwdev, dma_addr_t dev_addr,
-			 size_t size, int dir)
+			 size_t size, enum dma_data_direction dir)
 {
 	phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
 
 	BUG_ON(dir == DMA_NONE);
 
 	if (is_swiotlb_buffer(paddr)) {
-		do_unmap_single(hwdev, phys_to_virt(paddr), size, dir);
+		swiotlb_tbl_unmap_single(hwdev, phys_to_virt(paddr), size, dir);
 		return;
 	}
 
@@ -723,14 +745,16 @@
  */
 static void
 swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
-		    size_t size, int dir, int target)
+		    size_t size, enum dma_data_direction dir,
+		    enum dma_sync_target target)
 {
 	phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
 
 	BUG_ON(dir == DMA_NONE);
 
 	if (is_swiotlb_buffer(paddr)) {
-		sync_single(hwdev, phys_to_virt(paddr), size, dir, target);
+		swiotlb_tbl_sync_single(hwdev, phys_to_virt(paddr), size, dir,
+				       target);
 		return;
 	}
 
@@ -809,7 +833,7 @@
 
 int
 swiotlb_map_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
-	       int dir)
+	       enum dma_data_direction dir)
 {
 	return swiotlb_map_sg_attrs(hwdev, sgl, nelems, dir, NULL);
 }
@@ -836,7 +860,7 @@
 
 void
 swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
-		 int dir)
+		 enum dma_data_direction dir)
 {
 	return swiotlb_unmap_sg_attrs(hwdev, sgl, nelems, dir, NULL);
 }
@@ -851,7 +875,8 @@
  */
 static void
 swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sgl,
-		int nelems, int dir, int target)
+		int nelems, enum dma_data_direction dir,
+		enum dma_sync_target target)
 {
 	struct scatterlist *sg;
 	int i;
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index b8a2f54..4ee19d0 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -980,6 +980,11 @@
  *             [0][1][2][3]-[4][5]-[6][7]-[8][9]-[10][11][12][13][14][15]
  *           little endian output byte order is:
  *             [3][2][1][0]-[5][4]-[7][6]-[8][9]-[10][11][12][13][14][15]
+ * - 'V' For a struct va_format which contains a format string * and va_list *,
+ *       call vsnprintf(->format, *->va_list).
+ *       Implements a "recursive vsnprintf".
+ *       Do not use this feature without some mechanism to verify the
+ *       correctness of the format string and va_list arguments.
  *
  * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
  * function pointers are really function descriptors, which contain a
@@ -1025,6 +1030,10 @@
 		break;
 	case 'U':
 		return uuid_string(buf, end, ptr, spec, fmt);
+	case 'V':
+		return buf + vsnprintf(buf, end - buf,
+				       ((struct va_format *)ptr)->fmt,
+				       *(((struct va_format *)ptr)->va));
 	}
 	spec.flags |= SMALL;
 	if (spec.field_width == -1) {
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 620b0b4..6b44e52 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -45,6 +45,7 @@
 #include <linux/page-isolation.h>
 #include <linux/suspend.h>
 #include <linux/slab.h>
+#include <linux/swapops.h>
 #include "internal.h"
 
 int sysctl_memory_failure_early_kill __read_mostly = 0;
@@ -1296,3 +1297,35 @@
 	/* keep elevated page count for bad page */
 	return ret;
 }
+
+/*
+ * The caller must hold current->mm->mmap_sem in read mode.
+ */
+int is_hwpoison_address(unsigned long addr)
+{
+	pgd_t *pgdp;
+	pud_t pud, *pudp;
+	pmd_t pmd, *pmdp;
+	pte_t pte, *ptep;
+	swp_entry_t entry;
+
+	pgdp = pgd_offset(current->mm, addr);
+	if (!pgd_present(*pgdp))
+		return 0;
+	pudp = pud_offset(pgdp, addr);
+	pud = *pudp;
+	if (!pud_present(pud) || pud_large(pud))
+		return 0;
+	pmdp = pmd_offset(pudp, addr);
+	pmd = *pmdp;
+	if (!pmd_present(pmd) || pmd_large(pmd))
+		return 0;
+	ptep = pte_offset_map(pmdp, addr);
+	pte = *ptep;
+	pte_unmap(ptep);
+	if (!is_swap_pte(pte))
+		return 0;
+	entry = pte_to_swp_entry(pte);
+	return is_hwpoison_entry(entry);
+}
+EXPORT_SYMBOL_GPL(is_hwpoison_address);
diff --git a/mm/percpu.c b/mm/percpu.c
index 6470e77..e61dc2c 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -282,6 +282,9 @@
  */
 static void *pcpu_mem_alloc(size_t size)
 {
+	if (WARN_ON_ONCE(!slab_is_available()))
+		return NULL;
+
 	if (size <= PAGE_SIZE)
 		return kzalloc(size, GFP_KERNEL);
 	else {
@@ -392,13 +395,6 @@
 	old_size = chunk->map_alloc * sizeof(chunk->map[0]);
 	memcpy(new, chunk->map, old_size);
 
-	/*
-	 * map_alloc < PCPU_DFL_MAP_ALLOC indicates that the chunk is
-	 * one of the first chunks and still using static map.
-	 */
-	if (chunk->map_alloc >= PCPU_DFL_MAP_ALLOC)
-		old = chunk->map;
-
 	chunk->map_alloc = new_alloc;
 	chunk->map = new;
 	new = NULL;
@@ -604,7 +600,7 @@
 {
 	struct pcpu_chunk *chunk;
 
-	chunk = kzalloc(pcpu_chunk_struct_size, GFP_KERNEL);
+	chunk = pcpu_mem_alloc(pcpu_chunk_struct_size);
 	if (!chunk)
 		return NULL;
 
@@ -1013,20 +1009,6 @@
 		return page_to_phys(pcpu_addr_to_page(addr));
 }
 
-static inline size_t pcpu_calc_fc_sizes(size_t static_size,
-					size_t reserved_size,
-					ssize_t *dyn_sizep)
-{
-	size_t size_sum;
-
-	size_sum = PFN_ALIGN(static_size + reserved_size +
-			     (*dyn_sizep >= 0 ? *dyn_sizep : 0));
-	if (*dyn_sizep != 0)
-		*dyn_sizep = size_sum - static_size - reserved_size;
-
-	return size_sum;
-}
-
 /**
  * pcpu_alloc_alloc_info - allocate percpu allocation info
  * @nr_groups: the number of groups
@@ -1085,7 +1067,7 @@
 /**
  * pcpu_build_alloc_info - build alloc_info considering distances between CPUs
  * @reserved_size: the size of reserved percpu area in bytes
- * @dyn_size: free size for dynamic allocation in bytes, -1 for auto
+ * @dyn_size: minimum free size for dynamic allocation in bytes
  * @atom_size: allocation atom size
  * @cpu_distance_fn: callback to determine distance between cpus, optional
  *
@@ -1103,8 +1085,8 @@
  * On success, pointer to the new allocation_info is returned.  On
  * failure, ERR_PTR value is returned.
  */
-struct pcpu_alloc_info * __init pcpu_build_alloc_info(
-				size_t reserved_size, ssize_t dyn_size,
+static struct pcpu_alloc_info * __init pcpu_build_alloc_info(
+				size_t reserved_size, size_t dyn_size,
 				size_t atom_size,
 				pcpu_fc_cpu_distance_fn_t cpu_distance_fn)
 {
@@ -1123,13 +1105,17 @@
 	memset(group_map, 0, sizeof(group_map));
 	memset(group_cnt, 0, sizeof(group_cnt));
 
+	/* calculate size_sum and ensure dyn_size is enough for early alloc */
+	size_sum = PFN_ALIGN(static_size + reserved_size +
+			    max_t(size_t, dyn_size, PERCPU_DYNAMIC_EARLY_SIZE));
+	dyn_size = size_sum - static_size - reserved_size;
+
 	/*
 	 * Determine min_unit_size, alloc_size and max_upa such that
 	 * alloc_size is multiple of atom_size and is the smallest
 	 * which can accomodate 4k aligned segments which are equal to
 	 * or larger than min_unit_size.
 	 */
-	size_sum = pcpu_calc_fc_sizes(static_size, reserved_size, &dyn_size);
 	min_unit_size = max_t(size_t, size_sum, PCPU_MIN_UNIT_SIZE);
 
 	alloc_size = roundup(min_unit_size, atom_size);
@@ -1350,7 +1336,8 @@
 				  void *base_addr)
 {
 	static char cpus_buf[4096] __initdata;
-	static int smap[2], dmap[2];
+	static int smap[PERCPU_DYNAMIC_EARLY_SLOTS] __initdata;
+	static int dmap[PERCPU_DYNAMIC_EARLY_SLOTS] __initdata;
 	size_t dyn_size = ai->dyn_size;
 	size_t size_sum = ai->static_size + ai->reserved_size + dyn_size;
 	struct pcpu_chunk *schunk, *dchunk = NULL;
@@ -1373,14 +1360,13 @@
 } while (0)
 
 	/* sanity checks */
-	BUILD_BUG_ON(ARRAY_SIZE(smap) >= PCPU_DFL_MAP_ALLOC ||
-		     ARRAY_SIZE(dmap) >= PCPU_DFL_MAP_ALLOC);
 	PCPU_SETUP_BUG_ON(ai->nr_groups <= 0);
 	PCPU_SETUP_BUG_ON(!ai->static_size);
 	PCPU_SETUP_BUG_ON(!base_addr);
 	PCPU_SETUP_BUG_ON(ai->unit_size < size_sum);
 	PCPU_SETUP_BUG_ON(ai->unit_size & ~PAGE_MASK);
 	PCPU_SETUP_BUG_ON(ai->unit_size < PCPU_MIN_UNIT_SIZE);
+	PCPU_SETUP_BUG_ON(ai->dyn_size < PERCPU_DYNAMIC_EARLY_SIZE);
 	PCPU_SETUP_BUG_ON(pcpu_verify_alloc_info(ai) < 0);
 
 	/* process group information and build config tables accordingly */
@@ -1532,7 +1518,7 @@
 /**
  * pcpu_embed_first_chunk - embed the first percpu chunk into bootmem
  * @reserved_size: the size of reserved percpu area in bytes
- * @dyn_size: free size for dynamic allocation in bytes, -1 for auto
+ * @dyn_size: minimum free size for dynamic allocation in bytes
  * @atom_size: allocation atom size
  * @cpu_distance_fn: callback to determine distance between cpus, optional
  * @alloc_fn: function to allocate percpu page
@@ -1553,10 +1539,7 @@
  * vmalloc space is not orders of magnitude larger than distances
  * between node memory addresses (ie. 32bit NUMA machines).
  *
- * When @dyn_size is positive, dynamic area might be larger than
- * specified to fill page alignment.  When @dyn_size is auto,
- * @dyn_size is just big enough to fill page alignment after static
- * and reserved areas.
+ * @dyn_size specifies the minimum dynamic area size.
  *
  * If the needed size is smaller than the minimum or specified unit
  * size, the leftover is returned using @free_fn.
@@ -1564,7 +1547,7 @@
  * RETURNS:
  * 0 on success, -errno on failure.
  */
-int __init pcpu_embed_first_chunk(size_t reserved_size, ssize_t dyn_size,
+int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size,
 				  size_t atom_size,
 				  pcpu_fc_cpu_distance_fn_t cpu_distance_fn,
 				  pcpu_fc_alloc_fn_t alloc_fn,
@@ -1695,7 +1678,7 @@
 
 	snprintf(psize_str, sizeof(psize_str), "%luK", PAGE_SIZE >> 10);
 
-	ai = pcpu_build_alloc_info(reserved_size, -1, PAGE_SIZE, NULL);
+	ai = pcpu_build_alloc_info(reserved_size, 0, PAGE_SIZE, NULL);
 	if (IS_ERR(ai))
 		return PTR_ERR(ai);
 	BUG_ON(ai->nr_groups != 1);
@@ -1821,3 +1804,33 @@
 		__per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu];
 }
 #endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
+
+/*
+ * First and reserved chunks are initialized with temporary allocation
+ * map in initdata so that they can be used before slab is online.
+ * This function is called after slab is brought up and replaces those
+ * with properly allocated maps.
+ */
+void __init percpu_init_late(void)
+{
+	struct pcpu_chunk *target_chunks[] =
+		{ pcpu_first_chunk, pcpu_reserved_chunk, NULL };
+	struct pcpu_chunk *chunk;
+	unsigned long flags;
+	int i;
+
+	for (i = 0; (chunk = target_chunks[i]); i++) {
+		int *map;
+		const size_t size = PERCPU_DYNAMIC_EARLY_SLOTS * sizeof(map[0]);
+
+		BUILD_BUG_ON(size > PAGE_SIZE);
+
+		map = pcpu_mem_alloc(size);
+		BUG_ON(!map);
+
+		spin_lock_irqsave(&pcpu_lock, flags);
+		memcpy(map, chunk->map, size);
+		chunk->map = map;
+		spin_unlock_irqrestore(&pcpu_lock, flags);
+	}
+}
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 3c1c8c1..a2ad152 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -155,9 +155,10 @@
 	BUG_ON(!grp);
 
 	/* Take it out of our own structures, but be sure to interlock with
-	 * HW accelerating devices or SW vlan input packet processing.
+	 * HW accelerating devices or SW vlan input packet processing if
+	 * VLAN is not 0 (leave it there for 802.1p).
 	 */
-	if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
+	if (vlan_id && (real_dev->features & NETIF_F_HW_VLAN_FILTER))
 		ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id);
 
 	grp->nr_vlans--;
@@ -419,6 +420,14 @@
 	if (is_vlan_dev(dev))
 		__vlan_device_event(dev, event);
 
+	if ((event == NETDEV_UP) &&
+	    (dev->features & NETIF_F_HW_VLAN_FILTER) &&
+	    dev->netdev_ops->ndo_vlan_rx_add_vid) {
+		pr_info("8021q: adding VLAN 0 to HW filter on device %s\n",
+			dev->name);
+		dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0);
+	}
+
 	grp = __vlan_find_group(dev);
 	if (!grp)
 		goto out;
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 6abdcac..8d9503a 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -2,6 +2,7 @@
 #define __BEN_VLAN_802_1Q_INC__
 
 #include <linux/if_vlan.h>
+#include <linux/u64_stats_sync.h>
 
 
 /**
@@ -21,14 +22,16 @@
  *	struct vlan_rx_stats - VLAN percpu rx stats
  *	@rx_packets: number of received packets
  *	@rx_bytes: number of received bytes
- *	@multicast: number of received multicast packets
+ *	@rx_multicast: number of received multicast packets
+ *	@syncp: synchronization point for 64bit counters
  *	@rx_errors: number of errors
  */
 struct vlan_rx_stats {
-	unsigned long rx_packets;
-	unsigned long rx_bytes;
-	unsigned long multicast;
-	unsigned long rx_errors;
+	u64			rx_packets;
+	u64			rx_bytes;
+	u64			rx_multicast;
+	struct u64_stats_sync	syncp;
+	unsigned long		rx_errors;
 };
 
 /**
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 50f58f5..01ddb04 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -8,6 +8,9 @@
 int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
 		      u16 vlan_tci, int polling)
 {
+	struct net_device *vlan_dev;
+	u16 vlan_id;
+
 	if (netpoll_rx(skb))
 		return NET_RX_DROP;
 
@@ -16,9 +19,12 @@
 
 	skb->skb_iif = skb->dev->ifindex;
 	__vlan_hwaccel_put_tag(skb, vlan_tci);
-	skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK);
+	vlan_id = vlan_tci & VLAN_VID_MASK;
+	vlan_dev = vlan_group_get_device(grp, vlan_id);
 
-	if (!skb->dev)
+	if (vlan_dev)
+		skb->dev = vlan_dev;
+	else if (vlan_id)
 		goto drop;
 
 	return (polling ? netif_receive_skb(skb) : netif_rx(skb));
@@ -41,9 +47,9 @@
 	skb->priority = vlan_get_ingress_priority(dev, skb->vlan_tci);
 	skb->vlan_tci = 0;
 
-	rx_stats = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats,
-			       smp_processor_id());
+	rx_stats = this_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats);
 
+	u64_stats_update_begin(&rx_stats->syncp);
 	rx_stats->rx_packets++;
 	rx_stats->rx_bytes += skb->len;
 
@@ -51,7 +57,7 @@
 	case PACKET_BROADCAST:
 		break;
 	case PACKET_MULTICAST:
-		rx_stats->multicast++;
+		rx_stats->rx_multicast++;
 		break;
 	case PACKET_OTHERHOST:
 		/* Our lower layer thinks this is not local, let's make sure.
@@ -62,6 +68,7 @@
 			skb->pkt_type = PACKET_HOST;
 		break;
 	}
+	u64_stats_update_end(&rx_stats->syncp);
 	return 0;
 }
 
@@ -82,15 +89,20 @@
 		unsigned int vlan_tci, struct sk_buff *skb)
 {
 	struct sk_buff *p;
+	struct net_device *vlan_dev;
+	u16 vlan_id;
 
 	if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master)))
 		skb->deliver_no_wcard = 1;
 
 	skb->skb_iif = skb->dev->ifindex;
 	__vlan_hwaccel_put_tag(skb, vlan_tci);
-	skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK);
+	vlan_id = vlan_tci & VLAN_VID_MASK;
+	vlan_dev = vlan_group_get_device(grp, vlan_id);
 
-	if (!skb->dev)
+	if (vlan_dev)
+		skb->dev = vlan_dev;
+	else if (vlan_id)
 		goto drop;
 
 	for (p = napi->gro_list; p; p = p->next) {
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 5298426..3d59c9b 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -142,6 +142,7 @@
 {
 	struct vlan_hdr *vhdr;
 	struct vlan_rx_stats *rx_stats;
+	struct net_device *vlan_dev;
 	u16 vlan_id;
 	u16 vlan_tci;
 
@@ -157,53 +158,71 @@
 	vlan_id = vlan_tci & VLAN_VID_MASK;
 
 	rcu_read_lock();
-	skb->dev = __find_vlan_dev(dev, vlan_id);
-	if (!skb->dev) {
-		pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
-			 __func__, vlan_id, dev->name);
-		goto err_unlock;
-	}
+	vlan_dev = __find_vlan_dev(dev, vlan_id);
 
-	rx_stats = per_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats,
-			       smp_processor_id());
-	rx_stats->rx_packets++;
-	rx_stats->rx_bytes += skb->len;
+	/* If the VLAN device is defined, we use it.
+	 * If not, and the VID is 0, it is a 802.1p packet (not
+	 * really a VLAN), so we will just netif_rx it later to the
+	 * original interface, but with the skb->proto set to the
+	 * wrapped proto: we do nothing here.
+	 */
+
+	if (!vlan_dev) {
+		if (vlan_id) {
+			pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
+				 __func__, vlan_id, dev->name);
+			goto err_unlock;
+		}
+		rx_stats = NULL;
+	} else {
+		skb->dev = vlan_dev;
+
+		rx_stats = per_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats,
+					smp_processor_id());
+		u64_stats_update_begin(&rx_stats->syncp);
+		rx_stats->rx_packets++;
+		rx_stats->rx_bytes += skb->len;
+
+		skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);
+
+		pr_debug("%s: priority: %u for TCI: %hu\n",
+			 __func__, skb->priority, vlan_tci);
+
+		switch (skb->pkt_type) {
+		case PACKET_BROADCAST:
+			/* Yeah, stats collect these together.. */
+			/* stats->broadcast ++; // no such counter :-( */
+			break;
+
+		case PACKET_MULTICAST:
+			rx_stats->rx_multicast++;
+			break;
+
+		case PACKET_OTHERHOST:
+			/* Our lower layer thinks this is not local, let's make
+			 * sure.
+			 * This allows the VLAN to have a different MAC than the
+			 * underlying device, and still route correctly.
+			 */
+			if (!compare_ether_addr(eth_hdr(skb)->h_dest,
+						skb->dev->dev_addr))
+				skb->pkt_type = PACKET_HOST;
+			break;
+		default:
+			break;
+		}
+		u64_stats_update_end(&rx_stats->syncp);
+	}
 
 	skb_pull_rcsum(skb, VLAN_HLEN);
-
-	skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);
-
-	pr_debug("%s: priority: %u for TCI: %hu\n",
-		 __func__, skb->priority, vlan_tci);
-
-	switch (skb->pkt_type) {
-	case PACKET_BROADCAST: /* Yeah, stats collect these together.. */
-		/* stats->broadcast ++; // no such counter :-( */
-		break;
-
-	case PACKET_MULTICAST:
-		rx_stats->multicast++;
-		break;
-
-	case PACKET_OTHERHOST:
-		/* Our lower layer thinks this is not local, let's make sure.
-		 * This allows the VLAN to have a different MAC than the
-		 * underlying device, and still route correctly.
-		 */
-		if (!compare_ether_addr(eth_hdr(skb)->h_dest,
-					skb->dev->dev_addr))
-			skb->pkt_type = PACKET_HOST;
-		break;
-	default:
-		break;
-	}
-
 	vlan_set_encap_proto(skb, vhdr);
 
-	skb = vlan_check_reorder_header(skb);
-	if (!skb) {
-		rx_stats->rx_errors++;
-		goto err_unlock;
+	if (vlan_dev) {
+		skb = vlan_check_reorder_header(skb);
+		if (!skb) {
+			rx_stats->rx_errors++;
+			goto err_unlock;
+		}
 	}
 
 	netif_rx(skb);
@@ -801,37 +820,65 @@
 	return dev_ethtool_get_flags(vlan->real_dev);
 }
 
-static struct net_device_stats *vlan_dev_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
-	struct net_device_stats *stats = &dev->stats;
-
 	dev_txq_stats_fold(dev, stats);
 
 	if (vlan_dev_info(dev)->vlan_rx_stats) {
-		struct vlan_rx_stats *p, rx = {0};
+		struct vlan_rx_stats *p, accum = {0};
 		int i;
 
 		for_each_possible_cpu(i) {
+			u64 rxpackets, rxbytes, rxmulticast;
+			unsigned int start;
+
 			p = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, i);
-			rx.rx_packets += p->rx_packets;
-			rx.rx_bytes   += p->rx_bytes;
-			rx.rx_errors  += p->rx_errors;
-			rx.multicast  += p->multicast;
+			do {
+				start = u64_stats_fetch_begin_bh(&p->syncp);
+				rxpackets	= p->rx_packets;
+				rxbytes		= p->rx_bytes;
+				rxmulticast	= p->rx_multicast;
+			} while (u64_stats_fetch_retry_bh(&p->syncp, start));
+			accum.rx_packets += rxpackets;
+			accum.rx_bytes   += rxbytes;
+			accum.rx_multicast += rxmulticast;
+			/* rx_errors is an ulong, not protected by syncp */
+			accum.rx_errors  += p->rx_errors;
 		}
-		stats->rx_packets = rx.rx_packets;
-		stats->rx_bytes   = rx.rx_bytes;
-		stats->rx_errors  = rx.rx_errors;
-		stats->multicast  = rx.multicast;
+		stats->rx_packets = accum.rx_packets;
+		stats->rx_bytes   = accum.rx_bytes;
+		stats->rx_errors  = accum.rx_errors;
+		stats->multicast  = accum.rx_multicast;
 	}
 	return stats;
 }
 
+static int vlan_ethtool_set_tso(struct net_device *dev, u32 data)
+{
+       if (data) {
+		struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
+
+		/* Underlying device must support TSO for VLAN-tagged packets
+		 * and must have TSO enabled now.
+		 */
+		if (!(real_dev->vlan_features & NETIF_F_TSO))
+			return -EOPNOTSUPP;
+		if (!(real_dev->features & NETIF_F_TSO))
+			return -EINVAL;
+		dev->features |= NETIF_F_TSO;
+	} else {
+		dev->features &= ~NETIF_F_TSO;
+	}
+	return 0;
+}
+
 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,
+	.set_tso                = vlan_ethtool_set_tso,
 };
 
 static const struct net_device_ops vlan_netdev_ops = {
@@ -848,7 +895,7 @@
 	.ndo_change_rx_flags	= vlan_dev_change_rx_flags,
 	.ndo_do_ioctl		= vlan_dev_ioctl,
 	.ndo_neigh_setup	= vlan_dev_neigh_setup,
-	.ndo_get_stats		= vlan_dev_get_stats,
+	.ndo_get_stats64	= vlan_dev_get_stats64,
 #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
 	.ndo_fcoe_ddp_setup	= vlan_dev_fcoe_ddp_setup,
 	.ndo_fcoe_ddp_done	= vlan_dev_fcoe_ddp_done,
@@ -872,7 +919,7 @@
 	.ndo_change_rx_flags	= vlan_dev_change_rx_flags,
 	.ndo_do_ioctl		= vlan_dev_ioctl,
 	.ndo_neigh_setup	= vlan_dev_neigh_setup,
-	.ndo_get_stats		= vlan_dev_get_stats,
+	.ndo_get_stats64	= vlan_dev_get_stats64,
 #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
 	.ndo_fcoe_ddp_setup	= vlan_dev_fcoe_ddp_setup,
 	.ndo_fcoe_ddp_done	= vlan_dev_fcoe_ddp_done,
@@ -897,7 +944,7 @@
 	.ndo_change_rx_flags	= vlan_dev_change_rx_flags,
 	.ndo_do_ioctl		= vlan_dev_ioctl,
 	.ndo_neigh_setup	= vlan_dev_neigh_setup,
-	.ndo_get_stats		= vlan_dev_get_stats,
+	.ndo_get_stats64	= vlan_dev_get_stats64,
 #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
 	.ndo_fcoe_ddp_setup	= vlan_dev_fcoe_ddp_setup,
 	.ndo_fcoe_ddp_done	= vlan_dev_fcoe_ddp_done,
@@ -922,7 +969,7 @@
 	.ndo_change_rx_flags	= vlan_dev_change_rx_flags,
 	.ndo_do_ioctl		= vlan_dev_ioctl,
 	.ndo_neigh_setup	= vlan_dev_neigh_setup,
-	.ndo_get_stats		= vlan_dev_get_stats,
+	.ndo_get_stats64	= vlan_dev_get_stats64,
 #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
 	.ndo_fcoe_ddp_setup	= vlan_dev_fcoe_ddp_setup,
 	.ndo_fcoe_ddp_done	= vlan_dev_fcoe_ddp_done,
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index afead35..80e280f 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -278,25 +278,27 @@
 {
 	struct net_device *vlandev = (struct net_device *) seq->private;
 	const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev);
-	const struct net_device_stats *stats;
+	struct rtnl_link_stats64 temp;
+	const struct rtnl_link_stats64 *stats;
 	static const char fmt[] = "%30s %12lu\n";
+	static const char fmt64[] = "%30s %12llu\n";
 	int i;
 
 	if (!is_vlan_dev(vlandev))
 		return 0;
 
-	stats = dev_get_stats(vlandev);
+	stats = dev_get_stats(vlandev, &temp);
 	seq_printf(seq,
 		   "%s  VID: %d	 REORDER_HDR: %i  dev->priv_flags: %hx\n",
 		   vlandev->name, dev_info->vlan_id,
 		   (int)(dev_info->flags & 1), vlandev->priv_flags);
 
-	seq_printf(seq, fmt, "total frames received", stats->rx_packets);
-	seq_printf(seq, fmt, "total bytes received", stats->rx_bytes);
-	seq_printf(seq, fmt, "Broadcast/Multicast Rcvd", stats->multicast);
+	seq_printf(seq, fmt64, "total frames received", stats->rx_packets);
+	seq_printf(seq, fmt64, "total bytes received", stats->rx_bytes);
+	seq_printf(seq, fmt64, "Broadcast/Multicast Rcvd", stats->multicast);
 	seq_puts(seq, "\n");
-	seq_printf(seq, fmt, "total frames transmitted", stats->tx_packets);
-	seq_printf(seq, fmt, "total bytes transmitted", stats->tx_bytes);
+	seq_printf(seq, fmt64, "total frames transmitted", stats->tx_packets);
+	seq_printf(seq, fmt64, "total bytes transmitted", stats->tx_bytes);
 	seq_printf(seq, fmt, "total headroom inc",
 		   dev_info->cnt_inc_headroom_on_tx);
 	seq_printf(seq, fmt, "total encap on xmit",
diff --git a/net/Kconfig b/net/Kconfig
index 0d68b40..e24fa08 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -32,7 +32,7 @@
 config COMPAT_NETLINK_MESSAGES
 	def_bool y
 	depends on COMPAT
-	depends on WIRELESS_EXT || WANT_COMPAT_NETLINK_MESSAGES
+	depends on WEXT_CORE || WANT_COMPAT_NETLINK_MESSAGES
 	help
 	  This option makes it possible to send different netlink messages
 	  to tasks depending on whether the task is a compat task or not. To
@@ -86,6 +86,16 @@
 	  to nfmark, but designated for security purposes.
 	  If you are unsure how to answer this question, answer N.
 
+config NETWORK_PHY_TIMESTAMPING
+	bool "Timestamping in PHY devices"
+	depends on EXPERIMENTAL
+	help
+	  This allows timestamping of network packets by PHYs with
+	  hardware timestamping capabilities. This option adds some
+	  overhead in the transmit and receive paths.
+
+	  If you are unsure how to answer this question, answer N.
+
 menuconfig NETFILTER
 	bool "Network packet filtering framework (Netfilter)"
 	---help---
diff --git a/net/Makefile b/net/Makefile
index cb7bdc1..41d4200 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -50,7 +50,7 @@
 obj-$(CONFIG_IP_DCCP)		+= dccp/
 obj-$(CONFIG_IP_SCTP)		+= sctp/
 obj-$(CONFIG_RDS)		+= rds/
-obj-y				+= wireless/
+obj-$(CONFIG_WIRELESS)		+= wireless/
 obj-$(CONFIG_MAC80211)		+= mac80211/
 obj-$(CONFIG_TIPC)		+= tipc/
 obj-$(CONFIG_NETLABEL)		+= netlabel/
@@ -61,7 +61,7 @@
 ifneq ($(CONFIG_DCB),)
 obj-y				+= dcb/
 endif
-obj-y				+= ieee802154/
+obj-$(CONFIG_IEEE802154)	+= ieee802154/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 6719af6..651babd 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -139,6 +139,43 @@
 	return NULL;
 }
 
+static int atm_dev_event(struct notifier_block *this, unsigned long event,
+		 void *arg)
+{
+	struct atm_dev *atm_dev = arg;
+	struct list_head *lh;
+	struct net_device *net_dev;
+	struct br2684_vcc *brvcc;
+	struct atm_vcc *atm_vcc;
+	unsigned long flags;
+
+	pr_debug("event=%ld dev=%p\n", event, atm_dev);
+
+	read_lock_irqsave(&devs_lock, flags);
+	list_for_each(lh, &br2684_devs) {
+		net_dev = list_entry_brdev(lh);
+
+		list_for_each_entry(brvcc, &BRPRIV(net_dev)->brvccs, brvccs) {
+			atm_vcc = brvcc->atmvcc;
+			if (atm_vcc && brvcc->atmvcc->dev == atm_dev) {
+
+				if (atm_vcc->dev->signal == ATM_PHY_SIG_LOST)
+					netif_carrier_off(net_dev);
+				else
+					netif_carrier_on(net_dev);
+
+			}
+		}
+	}
+	read_unlock_irqrestore(&devs_lock, flags);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block atm_dev_notifier = {
+	.notifier_call = atm_dev_event,
+};
+
 /* chained vcc->pop function.  Check if we should wake the netif_queue */
 static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb)
 {
@@ -362,6 +399,12 @@
 			unregister_netdev(net_dev);
 			free_netdev(net_dev);
 		}
+		read_lock_irq(&devs_lock);
+		if (list_empty(&br2684_devs)) {
+			/* last br2684 device */
+			unregister_atmdevice_notifier(&atm_dev_notifier);
+		}
+		read_unlock_irq(&devs_lock);
 		return;
 	}
 
@@ -530,6 +573,13 @@
 
 		br2684_push(atmvcc, skb);
 	}
+
+	/* initialize netdev carrier state */
+	if (atmvcc->dev->signal == ATM_PHY_SIG_LOST)
+		netif_carrier_off(net_dev);
+	else
+		netif_carrier_on(net_dev);
+
 	__module_get(THIS_MODULE);
 	return 0;
 
@@ -620,9 +670,16 @@
 	}
 
 	write_lock_irq(&devs_lock);
+
 	brdev->payload = payload;
-	brdev->number = list_empty(&br2684_devs) ? 1 :
-	    BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1;
+
+	if (list_empty(&br2684_devs)) {
+		/* 1st br2684 device */
+		register_atmdevice_notifier(&atm_dev_notifier);
+		brdev->number = 1;
+	} else
+		brdev->number = BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1;
+
 	list_add_tail(&brdev->br2684_devs, &br2684_devs);
 	write_unlock_irq(&devs_lock);
 	return 0;
@@ -772,6 +829,11 @@
 	remove_proc_entry("br2684", atm_proc_root);
 #endif
 
+
+	/* if not already empty */
+	if (!list_empty(&br2684_devs))
+		unregister_atmdevice_notifier(&atm_dev_notifier);
+
 	while (!list_empty(&br2684_devs)) {
 		net_dev = list_entry_brdev(br2684_devs.next);
 		brdev = BRPRIV(net_dev);
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 313aba1..95fdd11 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -522,7 +522,7 @@
 	error = ip_route_output_key(&init_net, &rt, &fl);
 	if (error)
 		return error;
-	neigh = __neigh_lookup(&clip_tbl, &ip, rt->u.dst.dev, 1);
+	neigh = __neigh_lookup(&clip_tbl, &ip, rt->dst.dev, 1);
 	ip_rt_put(rt);
 	if (!neigh)
 		return -ENOMEM;
diff --git a/net/atm/common.c b/net/atm/common.c
index b43feb1..940404a 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -37,6 +37,8 @@
 DEFINE_RWLOCK(vcc_sklist_lock);
 EXPORT_SYMBOL(vcc_sklist_lock);
 
+static ATOMIC_NOTIFIER_HEAD(atm_dev_notify_chain);
+
 static void __vcc_insert_socket(struct sock *sk)
 {
 	struct atm_vcc *vcc = atm_sk(sk);
@@ -212,6 +214,22 @@
 }
 EXPORT_SYMBOL(vcc_release_async);
 
+void atm_dev_signal_change(struct atm_dev *dev, char signal)
+{
+	pr_debug("%s signal=%d dev=%p number=%d dev->signal=%d\n",
+		__func__, signal, dev, dev->number, dev->signal);
+
+	/* atm driver sending invalid signal */
+	WARN_ON(signal < ATM_PHY_SIG_LOST || signal > ATM_PHY_SIG_FOUND);
+
+	if (dev->signal == signal)
+		return; /* no change */
+
+	dev->signal = signal;
+
+	atomic_notifier_call_chain(&atm_dev_notify_chain, signal, dev);
+}
+EXPORT_SYMBOL(atm_dev_signal_change);
 
 void atm_dev_release_vccs(struct atm_dev *dev)
 {
@@ -781,6 +799,18 @@
 	return vcc->dev->ops->getsockopt(vcc, level, optname, optval, len);
 }
 
+int register_atmdevice_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&atm_dev_notify_chain, nb);
+}
+EXPORT_SYMBOL_GPL(register_atmdevice_notifier);
+
+void unregister_atmdevice_notifier(struct notifier_block *nb)
+{
+	atomic_notifier_chain_unregister(&atm_dev_notify_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_atmdevice_notifier);
+
 static int __init atm_init(void)
 {
 	int error;
diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig
index ee3b304..ed37168 100644
--- a/net/bluetooth/Kconfig
+++ b/net/bluetooth/Kconfig
@@ -43,19 +43,6 @@
 	  Say Y here to compile L2CAP support into the kernel or say M to
 	  compile it as module (l2cap).
 
-config BT_L2CAP_EXT_FEATURES
-	bool "L2CAP Extended Features support (EXPERIMENTAL)"
-	depends on BT_L2CAP && EXPERIMENTAL
-	help
-	  This option enables the L2CAP Extended Features support. These
-	  new features include the Enhanced Retransmission and Streaming
-	  Modes, the Frame Check Sequence (FCS), and Segmentation and
-	  Reassembly (SAR) for L2CAP packets. They are a required for the
-	  new Alternate MAC/PHY and the Bluetooth Medical Profile.
-
-	  You should say N unless you know what you are doing. Note that
-	  this is in an experimental state yet.
-
 config BT_SCO
 	tristate "SCO links support"
 	depends on BT
diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h
index 0d9e506..70672544 100644
--- a/net/bluetooth/bnep/bnep.h
+++ b/net/bluetooth/bnep/bnep.h
@@ -86,26 +86,26 @@
 	__u8  ctrl;
 	__u8  uuid_size;
 	__u8  service[0];
-} __attribute__((packed));
+} __packed;
 
 struct bnep_set_filter_req {
 	__u8  type;
 	__u8  ctrl;
 	__be16 len;
 	__u8  list[0];
-} __attribute__((packed));
+} __packed;
 
 struct bnep_control_rsp {
 	__u8  type;
 	__u8  ctrl;
 	__be16 resp;
-} __attribute__((packed));
+} __packed;
 
 struct bnep_ext_hdr {
 	__u8  type;
 	__u8  len;
 	__u8  data[0];
-} __attribute__((packed));
+} __packed;
 
 /* BNEP ioctl defines */
 #define BNEPCONNADD	_IOW('B', 200, int)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 800b6b9..0b1e460 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
+   Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -155,6 +155,27 @@
 	hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
 }
 
+/* Device _must_ be locked */
+void hci_sco_setup(struct hci_conn *conn, __u8 status)
+{
+	struct hci_conn *sco = conn->link;
+
+	BT_DBG("%p", conn);
+
+	if (!sco)
+		return;
+
+	if (!status) {
+		if (lmp_esco_capable(conn->hdev))
+			hci_setup_sync(sco, conn->handle);
+		else
+			hci_add_sco(sco, conn->handle);
+	} else {
+		hci_proto_connect_cfm(sco, status);
+		hci_conn_del(sco);
+	}
+}
+
 static void hci_conn_timeout(unsigned long arg)
 {
 	struct hci_conn *conn = (void *) arg;
@@ -385,10 +406,13 @@
 		acl->power_save = 1;
 		hci_conn_enter_active_mode(acl);
 
-		if (lmp_esco_capable(hdev))
-			hci_setup_sync(sco, acl->handle);
-		else
-			hci_add_sco(sco, acl->handle);
+		if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) {
+			/* defer SCO setup until mode change completed */
+			set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->pend);
+			return sco;
+		}
+
+		hci_sco_setup(acl, 0x00);
 	}
 
 	return sco;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 2f768de..8303f1c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -562,6 +562,7 @@
 	hci_dev_lock_bh(hdev);
 	inquiry_cache_flush(hdev);
 	hci_conn_hash_flush(hdev);
+	hci_blacklist_clear(hdev);
 	hci_dev_unlock_bh(hdev);
 
 	hci_notify(hdev, HCI_DEV_DOWN);
@@ -913,7 +914,7 @@
 	skb_queue_head_init(&hdev->cmd_q);
 	skb_queue_head_init(&hdev->raw_q);
 
-	for (i = 0; i < 3; i++)
+	for (i = 0; i < NUM_REASSEMBLY; i++)
 		hdev->reassembly[i] = NULL;
 
 	init_waitqueue_head(&hdev->req_wait_q);
@@ -923,6 +924,8 @@
 
 	hci_conn_hash_init(hdev);
 
+	INIT_LIST_HEAD(&hdev->blacklist.list);
+
 	memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
 
 	atomic_set(&hdev->promisc, 0);
@@ -970,7 +973,7 @@
 
 	hci_dev_do_close(hdev);
 
-	for (i = 0; i < 3; i++)
+	for (i = 0; i < NUM_REASSEMBLY; i++)
 		kfree_skb(hdev->reassembly[i]);
 
 	hci_notify(hdev, HCI_DEV_UNREG);
@@ -1030,90 +1033,171 @@
 }
 EXPORT_SYMBOL(hci_recv_frame);
 
-/* Receive packet type fragment */
-#define __reassembly(hdev, type)  ((hdev)->reassembly[(type) - 2])
-
-int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
+static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
+			  int count, __u8 index, gfp_t gfp_mask)
 {
-	if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
+	int len = 0;
+	int hlen = 0;
+	int remain = count;
+	struct sk_buff *skb;
+	struct bt_skb_cb *scb;
+
+	if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) ||
+				index >= NUM_REASSEMBLY)
 		return -EILSEQ;
 
-	while (count) {
-		struct sk_buff *skb = __reassembly(hdev, type);
-		struct { int expect; } *scb;
-		int len = 0;
+	skb = hdev->reassembly[index];
 
-		if (!skb) {
-			/* Start of the frame */
-
-			switch (type) {
-			case HCI_EVENT_PKT:
-				if (count >= HCI_EVENT_HDR_SIZE) {
-					struct hci_event_hdr *h = data;
-					len = HCI_EVENT_HDR_SIZE + h->plen;
-				} else
-					return -EILSEQ;
-				break;
-
-			case HCI_ACLDATA_PKT:
-				if (count >= HCI_ACL_HDR_SIZE) {
-					struct hci_acl_hdr *h = data;
-					len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen);
-				} else
-					return -EILSEQ;
-				break;
-
-			case HCI_SCODATA_PKT:
-				if (count >= HCI_SCO_HDR_SIZE) {
-					struct hci_sco_hdr *h = data;
-					len = HCI_SCO_HDR_SIZE + h->dlen;
-				} else
-					return -EILSEQ;
-				break;
-			}
-
-			skb = bt_skb_alloc(len, GFP_ATOMIC);
-			if (!skb) {
-				BT_ERR("%s no memory for packet", hdev->name);
-				return -ENOMEM;
-			}
-
-			skb->dev = (void *) hdev;
-			bt_cb(skb)->pkt_type = type;
-
-			__reassembly(hdev, type) = skb;
-
-			scb = (void *) skb->cb;
-			scb->expect = len;
-		} else {
-			/* Continuation */
-
-			scb = (void *) skb->cb;
-			len = scb->expect;
+	if (!skb) {
+		switch (type) {
+		case HCI_ACLDATA_PKT:
+			len = HCI_MAX_FRAME_SIZE;
+			hlen = HCI_ACL_HDR_SIZE;
+			break;
+		case HCI_EVENT_PKT:
+			len = HCI_MAX_EVENT_SIZE;
+			hlen = HCI_EVENT_HDR_SIZE;
+			break;
+		case HCI_SCODATA_PKT:
+			len = HCI_MAX_SCO_SIZE;
+			hlen = HCI_SCO_HDR_SIZE;
+			break;
 		}
 
-		len = min(len, count);
+		skb = bt_skb_alloc(len, gfp_mask);
+		if (!skb)
+			return -ENOMEM;
+
+		scb = (void *) skb->cb;
+		scb->expect = hlen;
+		scb->pkt_type = type;
+
+		skb->dev = (void *) hdev;
+		hdev->reassembly[index] = skb;
+	}
+
+	while (count) {
+		scb = (void *) skb->cb;
+		len = min(scb->expect, (__u16)count);
 
 		memcpy(skb_put(skb, len), data, len);
 
+		count -= len;
+		data += len;
 		scb->expect -= len;
+		remain = count;
+
+		switch (type) {
+		case HCI_EVENT_PKT:
+			if (skb->len == HCI_EVENT_HDR_SIZE) {
+				struct hci_event_hdr *h = hci_event_hdr(skb);
+				scb->expect = h->plen;
+
+				if (skb_tailroom(skb) < scb->expect) {
+					kfree_skb(skb);
+					hdev->reassembly[index] = NULL;
+					return -ENOMEM;
+				}
+			}
+			break;
+
+		case HCI_ACLDATA_PKT:
+			if (skb->len  == HCI_ACL_HDR_SIZE) {
+				struct hci_acl_hdr *h = hci_acl_hdr(skb);
+				scb->expect = __le16_to_cpu(h->dlen);
+
+				if (skb_tailroom(skb) < scb->expect) {
+					kfree_skb(skb);
+					hdev->reassembly[index] = NULL;
+					return -ENOMEM;
+				}
+			}
+			break;
+
+		case HCI_SCODATA_PKT:
+			if (skb->len == HCI_SCO_HDR_SIZE) {
+				struct hci_sco_hdr *h = hci_sco_hdr(skb);
+				scb->expect = h->dlen;
+
+				if (skb_tailroom(skb) < scb->expect) {
+					kfree_skb(skb);
+					hdev->reassembly[index] = NULL;
+					return -ENOMEM;
+				}
+			}
+			break;
+		}
 
 		if (scb->expect == 0) {
 			/* Complete frame */
 
-			__reassembly(hdev, type) = NULL;
-
 			bt_cb(skb)->pkt_type = type;
 			hci_recv_frame(skb);
-		}
 
-		count -= len; data += len;
+			hdev->reassembly[index] = NULL;
+			return remain;
+		}
 	}
 
-	return 0;
+	return remain;
+}
+
+int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
+{
+	int rem = 0;
+
+	if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
+		return -EILSEQ;
+
+	while (count) {
+		rem = hci_reassembly(hdev, type, data, count,
+						type - 1, GFP_ATOMIC);
+		if (rem < 0)
+			return rem;
+
+		data += (count - rem);
+		count = rem;
+	};
+
+	return rem;
 }
 EXPORT_SYMBOL(hci_recv_fragment);
 
+#define STREAM_REASSEMBLY 0
+
+int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
+{
+	int type;
+	int rem = 0;
+
+	while (count) {
+		struct sk_buff *skb = hdev->reassembly[STREAM_REASSEMBLY];
+
+		if (!skb) {
+			struct { char type; } *pkt;
+
+			/* Start of the frame */
+			pkt = data;
+			type = pkt->type;
+
+			data++;
+			count--;
+		} else
+			type = bt_cb(skb)->pkt_type;
+
+		rem = hci_reassembly(hdev, type, data,
+					count, STREAM_REASSEMBLY, GFP_ATOMIC);
+		if (rem < 0)
+			return rem;
+
+		data += (count - rem);
+		count = rem;
+	};
+
+	return rem;
+}
+EXPORT_SYMBOL(hci_recv_stream_fragment);
+
 /* ---- Interface to upper protocols ---- */
 
 /* Register/Unregister protocols.
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 786b5de..bfef5ba 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
+   Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -584,7 +584,7 @@
 				conn->out = 1;
 				conn->link_mode |= HCI_LM_MASTER;
 			} else
-				BT_ERR("No memmory for new connection");
+				BT_ERR("No memory for new connection");
 		}
 	}
 
@@ -785,9 +785,13 @@
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
-	if (conn)
+	if (conn) {
 		clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
 
+		if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+			hci_sco_setup(conn, status);
+	}
+
 	hci_dev_unlock(hdev);
 }
 
@@ -808,9 +812,13 @@
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
-	if (conn)
+	if (conn) {
 		clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
 
+		if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+			hci_sco_setup(conn, status);
+	}
+
 	hci_dev_unlock(hdev);
 }
 
@@ -915,20 +923,8 @@
 	} else
 		conn->state = BT_CLOSED;
 
-	if (conn->type == ACL_LINK) {
-		struct hci_conn *sco = conn->link;
-		if (sco) {
-			if (!ev->status) {
-				if (lmp_esco_capable(hdev))
-					hci_setup_sync(sco, conn->handle);
-				else
-					hci_add_sco(sco, conn->handle);
-			} else {
-				hci_proto_connect_cfm(sco, ev->status);
-				hci_conn_del(sco);
-			}
-		}
-	}
+	if (conn->type == ACL_LINK)
+		hci_sco_setup(conn, ev->status);
 
 	if (ev->status) {
 		hci_proto_connect_cfm(conn, ev->status);
@@ -952,7 +948,7 @@
 
 	mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
 
-	if (mask & HCI_LM_ACCEPT) {
+	if ((mask & HCI_LM_ACCEPT) && !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
 		/* Connection accepted */
 		struct inquiry_entry *ie;
 		struct hci_conn *conn;
@@ -965,7 +961,7 @@
 		conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
 		if (!conn) {
 			if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) {
-				BT_ERR("No memmory for new connection");
+				BT_ERR("No memory for new connection");
 				hci_dev_unlock(hdev);
 				return;
 			}
@@ -1481,6 +1477,9 @@
 			else
 				conn->power_save = 0;
 		}
+
+		if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+			hci_sco_setup(conn, ev->status);
 	}
 
 	hci_dev_unlock(hdev);
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 38f08f6..4f170a5 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -165,6 +165,86 @@
 	return 0;
 }
 
+struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+	struct list_head *p;
+	struct bdaddr_list *blacklist = &hdev->blacklist;
+
+	list_for_each(p, &blacklist->list) {
+		struct bdaddr_list *b;
+
+		b = list_entry(p, struct bdaddr_list, list);
+
+		if (bacmp(bdaddr, &b->bdaddr) == 0)
+			return b;
+	}
+
+	return NULL;
+}
+
+static int hci_blacklist_add(struct hci_dev *hdev, void __user *arg)
+{
+	bdaddr_t bdaddr;
+	struct bdaddr_list *entry;
+
+	if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
+		return -EFAULT;
+
+	if (bacmp(&bdaddr, BDADDR_ANY) == 0)
+		return -EBADF;
+
+	if (hci_blacklist_lookup(hdev, &bdaddr))
+		return -EEXIST;
+
+	entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	bacpy(&entry->bdaddr, &bdaddr);
+
+	list_add(&entry->list, &hdev->blacklist.list);
+
+	return 0;
+}
+
+int hci_blacklist_clear(struct hci_dev *hdev)
+{
+	struct list_head *p, *n;
+	struct bdaddr_list *blacklist = &hdev->blacklist;
+
+	list_for_each_safe(p, n, &blacklist->list) {
+		struct bdaddr_list *b;
+
+		b = list_entry(p, struct bdaddr_list, list);
+
+		list_del(p);
+		kfree(b);
+	}
+
+	return 0;
+}
+
+static int hci_blacklist_del(struct hci_dev *hdev, void __user *arg)
+{
+	bdaddr_t bdaddr;
+	struct bdaddr_list *entry;
+
+	if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
+		return -EFAULT;
+
+	if (bacmp(&bdaddr, BDADDR_ANY) == 0)
+		return hci_blacklist_clear(hdev);
+
+	entry = hci_blacklist_lookup(hdev, &bdaddr);
+	if (!entry)
+		return -ENOENT;
+
+	list_del(&entry->list);
+	kfree(entry);
+
+	return 0;
+}
+
 /* Ioctls that require bound socket */
 static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
 {
@@ -194,6 +274,16 @@
 	case HCIGETAUTHINFO:
 		return hci_get_auth_info(hdev, (void __user *) arg);
 
+	case HCIBLOCKADDR:
+		if (!capable(CAP_NET_ADMIN))
+			return -EACCES;
+		return hci_blacklist_add(hdev, (void __user *) arg);
+
+	case HCIUNBLOCKADDR:
+		if (!capable(CAP_NET_ADMIN))
+			return -EACCES;
+		return hci_blacklist_del(hdev, (void __user *) arg);
+
 	default:
 		if (hdev->ioctl)
 			return hdev->ioctl(hdev, cmd, arg);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 463ffa4..ce44c47 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -436,6 +436,41 @@
 	.release	= single_release,
 };
 
+static int blacklist_show(struct seq_file *f, void *p)
+{
+	struct hci_dev *hdev = f->private;
+	struct bdaddr_list *blacklist = &hdev->blacklist;
+	struct list_head *l;
+
+	hci_dev_lock_bh(hdev);
+
+	list_for_each(l, &blacklist->list) {
+		struct bdaddr_list *b;
+		bdaddr_t bdaddr;
+
+		b = list_entry(l, struct bdaddr_list, list);
+
+		baswap(&bdaddr, &b->bdaddr);
+
+		seq_printf(f, "%s\n", batostr(&bdaddr));
+	}
+
+	hci_dev_unlock_bh(hdev);
+
+	return 0;
+}
+
+static int blacklist_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, blacklist_show, inode->i_private);
+}
+
+static const struct file_operations blacklist_fops = {
+	.open		= blacklist_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
 int hci_register_sysfs(struct hci_dev *hdev)
 {
 	struct device *dev = &hdev->dev;
@@ -465,6 +500,9 @@
 	debugfs_create_file("inquiry_cache", 0444, hdev->debugfs,
 						hdev, &inquiry_cache_fops);
 
+	debugfs_create_file("blacklist", 0444, hdev->debugfs,
+						hdev, &blacklist_fops);
+
 	return 0;
 }
 
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index cf3c407..9ba1e8e 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1,6 +1,8 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
+   Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
+   Copyright (C) 2010 Google Inc.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -53,15 +55,9 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 
-#define VERSION "2.14"
+#define VERSION "2.15"
 
-#ifdef CONFIG_BT_L2CAP_EXT_FEATURES
-static int enable_ertm = 1;
-#else
-static int enable_ertm = 0;
-#endif
-static int max_transmit = L2CAP_DEFAULT_MAX_TX;
-static int tx_window = L2CAP_DEFAULT_TX_WINDOW;
+static int disable_ertm = 0;
 
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
 static u8 l2cap_fixed_chan[8] = { 0x02, };
@@ -80,9 +76,12 @@
 static void l2cap_sock_close(struct sock *sk);
 static void l2cap_sock_kill(struct sock *sk);
 
+static int l2cap_build_conf_req(struct sock *sk, void *data);
 static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
 				u8 code, u8 ident, u16 dlen, void *data);
 
+static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
+
 /* ---- L2CAP timers ---- */
 static void l2cap_sock_timeout(unsigned long arg)
 {
@@ -278,6 +277,24 @@
 		parent->sk_data_ready(parent, 0);
 	} else
 		sk->sk_state_change(sk);
+
+	skb_queue_purge(TX_QUEUE(sk));
+
+	if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
+		struct srej_list *l, *tmp;
+
+		del_timer(&l2cap_pi(sk)->retrans_timer);
+		del_timer(&l2cap_pi(sk)->monitor_timer);
+		del_timer(&l2cap_pi(sk)->ack_timer);
+
+		skb_queue_purge(SREJ_QUEUE(sk));
+		skb_queue_purge(BUSY_QUEUE(sk));
+
+		list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) {
+			list_del(&l->list);
+			kfree(l);
+		}
+	}
 }
 
 /* Service level security */
@@ -351,8 +368,12 @@
 	struct sk_buff *skb;
 	struct l2cap_hdr *lh;
 	struct l2cap_conn *conn = pi->conn;
+	struct sock *sk = (struct sock *)pi;
 	int count, hlen = L2CAP_HDR_SIZE + 2;
 
+	if (sk->sk_state != BT_CONNECTED)
+		return;
+
 	if (pi->fcs == L2CAP_FCS_CRC16)
 		hlen += 2;
 
@@ -440,24 +461,57 @@
 	}
 }
 
-static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk)
+static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
+{
+	u32 local_feat_mask = l2cap_feat_mask;
+	if (!disable_ertm)
+		local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
+
+	switch (mode) {
+	case L2CAP_MODE_ERTM:
+		return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
+	case L2CAP_MODE_STREAMING:
+		return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
+	default:
+		return 0x00;
+	}
+}
+
+static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err)
 {
 	struct l2cap_disconn_req req;
 
+	if (!conn)
+		return;
+
+	skb_queue_purge(TX_QUEUE(sk));
+
+	if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
+		del_timer(&l2cap_pi(sk)->retrans_timer);
+		del_timer(&l2cap_pi(sk)->monitor_timer);
+		del_timer(&l2cap_pi(sk)->ack_timer);
+	}
+
 	req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid);
 	req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
 	l2cap_send_cmd(conn, l2cap_get_ident(conn),
 			L2CAP_DISCONN_REQ, sizeof(req), &req);
+
+	sk->sk_state = BT_DISCONN;
+	sk->sk_err = err;
 }
 
 /* ---- L2CAP connections ---- */
 static void l2cap_conn_start(struct l2cap_conn *conn)
 {
 	struct l2cap_chan_list *l = &conn->chan_list;
+	struct sock_del_list del, *tmp1, *tmp2;
 	struct sock *sk;
 
 	BT_DBG("conn %p", conn);
 
+	INIT_LIST_HEAD(&del.list);
+
 	read_lock(&l->lock);
 
 	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
@@ -470,20 +524,38 @@
 		}
 
 		if (sk->sk_state == BT_CONNECT) {
-			if (l2cap_check_security(sk) &&
-					__l2cap_no_conn_pending(sk)) {
-				struct l2cap_conn_req req;
-				req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
-				req.psm  = l2cap_pi(sk)->psm;
+			struct l2cap_conn_req req;
 
-				l2cap_pi(sk)->ident = l2cap_get_ident(conn);
-				l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
-
-				l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
-					L2CAP_CONN_REQ, sizeof(req), &req);
+			if (!l2cap_check_security(sk) ||
+					!__l2cap_no_conn_pending(sk)) {
+				bh_unlock_sock(sk);
+				continue;
 			}
+
+			if (!l2cap_mode_supported(l2cap_pi(sk)->mode,
+					conn->feat_mask)
+					&& l2cap_pi(sk)->conf_state &
+					L2CAP_CONF_STATE2_DEVICE) {
+				tmp1 = kzalloc(sizeof(struct sock_del_list),
+						GFP_ATOMIC);
+				tmp1->sk = sk;
+				list_add_tail(&tmp1->list, &del.list);
+				bh_unlock_sock(sk);
+				continue;
+			}
+
+			req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
+			req.psm  = l2cap_pi(sk)->psm;
+
+			l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+			l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
+
+			l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+				L2CAP_CONN_REQ, sizeof(req), &req);
+
 		} else if (sk->sk_state == BT_CONNECT2) {
 			struct l2cap_conn_rsp rsp;
+			char buf[128];
 			rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
 			rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
 
@@ -506,12 +578,31 @@
 
 			l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
 					L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+
+			if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT ||
+					rsp.result != L2CAP_CR_SUCCESS) {
+				bh_unlock_sock(sk);
+				continue;
+			}
+
+			l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+			l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+						l2cap_build_conf_req(sk, buf), buf);
+			l2cap_pi(sk)->num_conf_req++;
 		}
 
 		bh_unlock_sock(sk);
 	}
 
 	read_unlock(&l->lock);
+
+	list_for_each_entry_safe(tmp1, tmp2, &del.list, list) {
+		bh_lock_sock(tmp1->sk);
+		__l2cap_sock_close(tmp1->sk, ECONNRESET);
+		bh_unlock_sock(tmp1->sk);
+		list_del(&tmp1->list);
+		kfree(tmp1);
+	}
 }
 
 static void l2cap_conn_ready(struct l2cap_conn *conn)
@@ -740,9 +831,8 @@
 				sk->sk_type == SOCK_STREAM) {
 			struct l2cap_conn *conn = l2cap_pi(sk)->conn;
 
-			sk->sk_state = BT_DISCONN;
 			l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
-			l2cap_send_disconn_req(conn, sk);
+			l2cap_send_disconn_req(conn, sk, reason);
 		} else
 			l2cap_chan_del(sk, reason);
 		break;
@@ -802,6 +892,7 @@
 
 		pi->imtu = l2cap_pi(parent)->imtu;
 		pi->omtu = l2cap_pi(parent)->omtu;
+		pi->conf_state = l2cap_pi(parent)->conf_state;
 		pi->mode = l2cap_pi(parent)->mode;
 		pi->fcs  = l2cap_pi(parent)->fcs;
 		pi->max_tx = l2cap_pi(parent)->max_tx;
@@ -812,13 +903,15 @@
 	} else {
 		pi->imtu = L2CAP_DEFAULT_MTU;
 		pi->omtu = 0;
-		if (enable_ertm && sk->sk_type == SOCK_STREAM)
+		if (!disable_ertm && sk->sk_type == SOCK_STREAM) {
 			pi->mode = L2CAP_MODE_ERTM;
-		else
+			pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
+		} else {
 			pi->mode = L2CAP_MODE_BASIC;
-		pi->max_tx = max_transmit;
+		}
+		pi->max_tx = L2CAP_DEFAULT_MAX_TX;
 		pi->fcs  = L2CAP_FCS_CRC16;
-		pi->tx_win = tx_window;
+		pi->tx_win = L2CAP_DEFAULT_TX_WINDOW;
 		pi->sec_level = BT_SECURITY_LOW;
 		pi->role_switch = 0;
 		pi->force_reliable = 0;
@@ -1067,7 +1160,7 @@
 		break;
 	case L2CAP_MODE_ERTM:
 	case L2CAP_MODE_STREAMING:
-		if (enable_ertm)
+		if (!disable_ertm)
 			break;
 		/* fall through */
 	default:
@@ -1084,6 +1177,7 @@
 
 	case BT_CONNECTED:
 		/* Already connected */
+		err = -EISCONN;
 		goto done;
 
 	case BT_OPEN:
@@ -1132,7 +1226,7 @@
 		break;
 	case L2CAP_MODE_ERTM:
 	case L2CAP_MODE_STREAMING:
-		if (enable_ertm)
+		if (!disable_ertm)
 			break;
 		/* fall through */
 	default:
@@ -1285,9 +1379,11 @@
 {
 	struct sock *sk = (void *) arg;
 
+	BT_DBG("sk %p", sk);
+
 	bh_lock_sock(sk);
 	if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) {
-		l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk);
+		l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED);
 		bh_unlock_sock(sk);
 		return;
 	}
@@ -1303,6 +1399,8 @@
 {
 	struct sock *sk = (void *) arg;
 
+	BT_DBG("sk %p", sk);
+
 	bh_lock_sock(sk);
 	l2cap_pi(sk)->retry_count = 1;
 	__mod_monitor_timer();
@@ -1341,7 +1439,7 @@
 	hci_send_acl(pi->conn->hcon, skb, 0);
 }
 
-static int l2cap_streaming_send(struct sock *sk)
+static void l2cap_streaming_send(struct sock *sk)
 {
 	struct sk_buff *skb, *tx_skb;
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
@@ -1371,7 +1469,6 @@
 		skb = skb_dequeue(TX_QUEUE(sk));
 		kfree_skb(skb);
 	}
-	return 0;
 }
 
 static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq)
@@ -1395,15 +1492,22 @@
 
 	if (pi->remote_max_tx &&
 			bt_cb(skb)->retries == pi->remote_max_tx) {
-		l2cap_send_disconn_req(pi->conn, sk);
+		l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED);
 		return;
 	}
 
 	tx_skb = skb_clone(skb, GFP_ATOMIC);
 	bt_cb(skb)->retries++;
 	control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+
+	if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
+		control |= L2CAP_CTRL_FINAL;
+		pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+	}
+
 	control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
 			| (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
+
 	put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
 
 	if (pi->fcs == L2CAP_FCS_CRC16) {
@@ -1421,15 +1525,14 @@
 	u16 control, fcs;
 	int nsent = 0;
 
-	if (pi->conn_state & L2CAP_CONN_WAIT_F)
-		return 0;
+	if (sk->sk_state != BT_CONNECTED)
+		return -ENOTCONN;
 
-	while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk)) &&
-			!(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) {
+	while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) {
 
 		if (pi->remote_max_tx &&
 				bt_cb(skb)->retries == pi->remote_max_tx) {
-			l2cap_send_disconn_req(pi->conn, sk);
+			l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED);
 			break;
 		}
 
@@ -1438,6 +1541,8 @@
 		bt_cb(skb)->retries++;
 
 		control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+		control &= L2CAP_CTRL_SAR;
+
 		if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
 			control |= L2CAP_CTRL_FINAL;
 			pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
@@ -1478,16 +1583,11 @@
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	int ret;
 
-	spin_lock_bh(&pi->send_lock);
-
 	if (!skb_queue_empty(TX_QUEUE(sk)))
 		sk->sk_send_head = TX_QUEUE(sk)->next;
 
 	pi->next_tx_seq = pi->expected_ack_seq;
 	ret = l2cap_ertm_send(sk);
-
-	spin_unlock_bh(&pi->send_lock);
-
 	return ret;
 }
 
@@ -1495,7 +1595,6 @@
 {
 	struct sock *sk = (struct sock *)pi;
 	u16 control = 0;
-	int nframes;
 
 	control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 
@@ -1506,11 +1605,7 @@
 		return;
 	}
 
-	spin_lock_bh(&pi->send_lock);
-	nframes = l2cap_ertm_send(sk);
-	spin_unlock_bh(&pi->send_lock);
-
-	if (nframes > 0)
+	if (l2cap_ertm_send(sk) > 0)
 		return;
 
 	control |= L2CAP_SUPER_RCV_READY;
@@ -1705,10 +1800,8 @@
 		size += buflen;
 	}
 	skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk));
-	spin_lock_bh(&pi->send_lock);
 	if (sk->sk_send_head == NULL)
 		sk->sk_send_head = sar_queue.next;
-	spin_unlock_bh(&pi->send_lock);
 
 	return size;
 }
@@ -1753,7 +1846,7 @@
 	case L2CAP_MODE_BASIC:
 		/* Check outgoing MTU */
 		if (len > pi->omtu) {
-			err = -EINVAL;
+			err = -EMSGSIZE;
 			goto done;
 		}
 
@@ -1780,14 +1873,9 @@
 			}
 			__skb_queue_tail(TX_QUEUE(sk), skb);
 
-			if (pi->mode == L2CAP_MODE_ERTM)
-				spin_lock_bh(&pi->send_lock);
-
 			if (sk->sk_send_head == NULL)
 				sk->sk_send_head = skb;
 
-			if (pi->mode == L2CAP_MODE_ERTM)
-				spin_unlock_bh(&pi->send_lock);
 		} else {
 		/* Segment SDU into multiples PDUs */
 			err = l2cap_sar_segment_sdu(sk, msg, len);
@@ -1796,11 +1884,14 @@
 		}
 
 		if (pi->mode == L2CAP_MODE_STREAMING) {
-			err = l2cap_streaming_send(sk);
+			l2cap_streaming_send(sk);
 		} else {
-			spin_lock_bh(&pi->send_lock);
+			if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY &&
+					pi->conn_state && L2CAP_CONN_WAIT_F) {
+				err = len;
+				break;
+			}
 			err = l2cap_ertm_send(sk);
-			spin_unlock_bh(&pi->send_lock);
 		}
 
 		if (err >= 0)
@@ -1809,7 +1900,7 @@
 
 	default:
 		BT_DBG("bad state %1.1x", pi->mode);
-		err = -EINVAL;
+		err = -EBADFD;
 	}
 
 done:
@@ -1825,6 +1916,8 @@
 
 	if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
 		struct l2cap_conn_rsp rsp;
+		struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+		u8 buf[128];
 
 		sk->sk_state = BT_CONFIG;
 
@@ -1835,6 +1928,16 @@
 		l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident,
 					L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 
+		if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) {
+			release_sock(sk);
+			return 0;
+		}
+
+		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+				l2cap_build_conf_req(sk, buf), buf);
+		l2cap_pi(sk)->num_conf_req++;
+
 		release_sock(sk);
 		return 0;
 	}
@@ -1871,13 +1974,19 @@
 			break;
 		}
 
+		if (opts.txwin_size > L2CAP_DEFAULT_TX_WINDOW) {
+			err = -EINVAL;
+			break;
+		}
+
 		l2cap_pi(sk)->mode = opts.mode;
 		switch (l2cap_pi(sk)->mode) {
 		case L2CAP_MODE_BASIC:
+			l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE;
 			break;
 		case L2CAP_MODE_ERTM:
 		case L2CAP_MODE_STREAMING:
-			if (enable_ertm)
+			if (!disable_ertm)
 				break;
 			/* fall through */
 		default:
@@ -2145,6 +2254,10 @@
 			err = bt_sock_wait_state(sk, BT_CLOSED,
 							sk->sk_lingertime);
 	}
+
+	if (!err && sk->sk_err)
+		err = -sk->sk_err;
+
 	release_sock(sk);
 	return err;
 }
@@ -2365,25 +2478,10 @@
 
 	__skb_queue_head_init(SREJ_QUEUE(sk));
 	__skb_queue_head_init(BUSY_QUEUE(sk));
-	spin_lock_init(&l2cap_pi(sk)->send_lock);
 
 	INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work);
-}
 
-static int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
-{
-	u32 local_feat_mask = l2cap_feat_mask;
-	if (enable_ertm)
-		local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
-
-	switch (mode) {
-	case L2CAP_MODE_ERTM:
-		return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
-	case L2CAP_MODE_STREAMING:
-		return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
-	default:
-		return 0x00;
-	}
+	sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
 }
 
 static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
@@ -2414,10 +2512,10 @@
 	switch (pi->mode) {
 	case L2CAP_MODE_STREAMING:
 	case L2CAP_MODE_ERTM:
-		pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
-		if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask))
-			l2cap_send_disconn_req(pi->conn, sk);
-		break;
+		if (pi->conf_state & L2CAP_CONF_STATE2_DEVICE)
+			break;
+
+		/* fall through */
 	default:
 		pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask);
 		break;
@@ -2428,6 +2526,14 @@
 	case L2CAP_MODE_BASIC:
 		if (pi->imtu != L2CAP_DEFAULT_MTU)
 			l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+
+		rfc.mode            = L2CAP_MODE_BASIC;
+		rfc.txwin_size      = 0;
+		rfc.max_transmit    = 0;
+		rfc.retrans_timeout = 0;
+		rfc.monitor_timeout = 0;
+		rfc.max_pdu_size    = 0;
+
 		break;
 
 	case L2CAP_MODE_ERTM:
@@ -2440,9 +2546,6 @@
 		if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
 			rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
 
-		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-					sizeof(rfc), (unsigned long) &rfc);
-
 		if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
 			break;
 
@@ -2463,9 +2566,6 @@
 		if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
 			rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
 
-		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-					sizeof(rfc), (unsigned long) &rfc);
-
 		if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
 			break;
 
@@ -2477,6 +2577,9 @@
 		break;
 	}
 
+	l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+						(unsigned long) &rfc);
+
 	/* FIXME: Need actual value of the flush timeout */
 	//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
 	//   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
@@ -2541,18 +2644,21 @@
 		}
 	}
 
-	if (pi->num_conf_rsp || pi->num_conf_req)
+	if (pi->num_conf_rsp || pi->num_conf_req > 1)
 		goto done;
 
 	switch (pi->mode) {
 	case L2CAP_MODE_STREAMING:
 	case L2CAP_MODE_ERTM:
-		pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
-		if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask))
+		if (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
+			pi->mode = l2cap_select_mode(rfc.mode,
+					pi->conn->feat_mask);
+			break;
+		}
+
+		if (pi->mode != rfc.mode)
 			return -ECONNREFUSED;
-		break;
-	default:
-		pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask);
+
 		break;
 	}
 
@@ -2675,7 +2781,6 @@
 							rfc.mode != pi->mode)
 				return -ECONNREFUSED;
 
-			pi->mode = rfc.mode;
 			pi->fcs = 0;
 
 			l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
@@ -2684,6 +2789,11 @@
 		}
 	}
 
+	if (pi->mode == L2CAP_MODE_BASIC && pi->mode != rfc.mode)
+		return -ECONNREFUSED;
+
+	pi->mode = rfc.mode;
+
 	if (*result == L2CAP_CONF_SUCCESS) {
 		switch (rfc.mode) {
 		case L2CAP_MODE_ERTM:
@@ -2778,7 +2888,7 @@
 	struct l2cap_chan_list *list = &conn->chan_list;
 	struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
 	struct l2cap_conn_rsp rsp;
-	struct sock *sk, *parent;
+	struct sock *parent, *uninitialized_var(sk);
 	int result, status = L2CAP_CS_NO_INFO;
 
 	u16 dcid = 0, scid = __le16_to_cpu(req->scid);
@@ -2887,6 +2997,15 @@
 					L2CAP_INFO_REQ, sizeof(info), &info);
 	}
 
+	if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) &&
+				result == L2CAP_CR_SUCCESS) {
+		u8 buf[128];
+		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+					l2cap_build_conf_req(sk, buf), buf);
+		l2cap_pi(sk)->num_conf_req++;
+	}
+
 	return 0;
 }
 
@@ -2907,11 +3026,11 @@
 	if (scid) {
 		sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
 		if (!sk)
-			return 0;
+			return -EFAULT;
 	} else {
 		sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident);
 		if (!sk)
-			return 0;
+			return -EFAULT;
 	}
 
 	switch (result) {
@@ -2919,9 +3038,13 @@
 		sk->sk_state = BT_CONFIG;
 		l2cap_pi(sk)->ident = 0;
 		l2cap_pi(sk)->dcid = dcid;
-		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
 		l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
 
+		if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)
+			break;
+
+		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+
 		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 					l2cap_build_conf_req(sk, req), req);
 		l2cap_pi(sk)->num_conf_req++;
@@ -2957,8 +3080,14 @@
 	if (!sk)
 		return -ENOENT;
 
-	if (sk->sk_state == BT_DISCONN)
+	if (sk->sk_state != BT_CONFIG) {
+		struct l2cap_cmd_rej rej;
+
+		rej.reason = cpu_to_le16(0x0002);
+		l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
+				sizeof(rej), &rej);
 		goto unlock;
+	}
 
 	/* Reject if config buffer is too small. */
 	len = cmd_len - sizeof(*req);
@@ -2984,7 +3113,7 @@
 	/* Complete config. */
 	len = l2cap_parse_conf_req(sk, rsp);
 	if (len < 0) {
-		l2cap_send_disconn_req(conn, sk);
+		l2cap_send_disconn_req(conn, sk, ECONNRESET);
 		goto unlock;
 	}
 
@@ -3054,7 +3183,7 @@
 			char req[64];
 
 			if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
-				l2cap_send_disconn_req(conn, sk);
+				l2cap_send_disconn_req(conn, sk, ECONNRESET);
 				goto done;
 			}
 
@@ -3063,7 +3192,7 @@
 			len = l2cap_parse_conf_rsp(sk, rsp->data,
 							len, req, &result);
 			if (len < 0) {
-				l2cap_send_disconn_req(conn, sk);
+				l2cap_send_disconn_req(conn, sk, ECONNRESET);
 				goto done;
 			}
 
@@ -3076,10 +3205,9 @@
 		}
 
 	default:
-		sk->sk_state = BT_DISCONN;
 		sk->sk_err = ECONNRESET;
 		l2cap_sock_set_timer(sk, HZ * 5);
-		l2cap_send_disconn_req(conn, sk);
+		l2cap_send_disconn_req(conn, sk, ECONNRESET);
 		goto done;
 	}
 
@@ -3130,16 +3258,6 @@
 
 	sk->sk_shutdown = SHUTDOWN_MASK;
 
-	skb_queue_purge(TX_QUEUE(sk));
-
-	if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
-		skb_queue_purge(SREJ_QUEUE(sk));
-		skb_queue_purge(BUSY_QUEUE(sk));
-		del_timer(&l2cap_pi(sk)->retrans_timer);
-		del_timer(&l2cap_pi(sk)->monitor_timer);
-		del_timer(&l2cap_pi(sk)->ack_timer);
-	}
-
 	l2cap_chan_del(sk, ECONNRESET);
 	bh_unlock_sock(sk);
 
@@ -3162,16 +3280,6 @@
 	if (!sk)
 		return 0;
 
-	skb_queue_purge(TX_QUEUE(sk));
-
-	if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
-		skb_queue_purge(SREJ_QUEUE(sk));
-		skb_queue_purge(BUSY_QUEUE(sk));
-		del_timer(&l2cap_pi(sk)->retrans_timer);
-		del_timer(&l2cap_pi(sk)->monitor_timer);
-		del_timer(&l2cap_pi(sk)->ack_timer);
-	}
-
 	l2cap_chan_del(sk, 0);
 	bh_unlock_sock(sk);
 
@@ -3194,7 +3302,7 @@
 		struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
 		rsp->type   = cpu_to_le16(L2CAP_IT_FEAT_MASK);
 		rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
-		if (enable_ertm)
+		if (!disable_ertm)
 			feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
 							 | L2CAP_FEAT_FCS;
 		put_unaligned_le32(feat_mask, rsp->data);
@@ -3359,7 +3467,7 @@
 		our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
 
 		if (our_fcs != rcv_fcs)
-			return -EINVAL;
+			return -EBADMSG;
 	}
 	return 0;
 }
@@ -3370,25 +3478,19 @@
 	u16 control = 0;
 
 	pi->frames_sent = 0;
-	pi->conn_state |= L2CAP_CONN_SEND_FBIT;
 
 	control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 
 	if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
-		control |= L2CAP_SUPER_RCV_NOT_READY | L2CAP_CTRL_FINAL;
+		control |= L2CAP_SUPER_RCV_NOT_READY;
 		l2cap_send_sframe(pi, control);
 		pi->conn_state |= L2CAP_CONN_RNR_SENT;
-		pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
 	}
 
-	if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && pi->unacked_frames > 0)
-		__mod_retrans_timer();
+	if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY)
+		l2cap_retransmit_frames(sk);
 
-	pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
-
-	spin_lock_bh(&pi->send_lock);
 	l2cap_ertm_send(sk);
-	spin_unlock_bh(&pi->send_lock);
 
 	if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
 			pi->frames_sent == 0) {
@@ -3400,6 +3502,8 @@
 static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar)
 {
 	struct sk_buff *next_skb;
+	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	int tx_seq_offset, next_tx_seq_offset;
 
 	bt_cb(skb)->tx_seq = tx_seq;
 	bt_cb(skb)->sar = sar;
@@ -3410,11 +3514,20 @@
 		return 0;
 	}
 
+	tx_seq_offset = (tx_seq - pi->buffer_seq) % 64;
+	if (tx_seq_offset < 0)
+		tx_seq_offset += 64;
+
 	do {
 		if (bt_cb(next_skb)->tx_seq == tx_seq)
 			return -EINVAL;
 
-		if (bt_cb(next_skb)->tx_seq > tx_seq) {
+		next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
+						pi->buffer_seq) % 64;
+		if (next_tx_seq_offset < 0)
+			next_tx_seq_offset += 64;
+
+		if (next_tx_seq_offset > tx_seq_offset) {
 			__skb_queue_before(SREJ_QUEUE(sk), next_skb, skb);
 			return 0;
 		}
@@ -3532,62 +3645,27 @@
 	pi->sdu = NULL;
 
 disconnect:
-	l2cap_send_disconn_req(pi->conn, sk);
+	l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
 	kfree_skb(skb);
 	return 0;
 }
 
-static void l2cap_busy_work(struct work_struct *work)
+static int l2cap_try_push_rx_skb(struct sock *sk)
 {
-	DECLARE_WAITQUEUE(wait, current);
-	struct l2cap_pinfo *pi =
-		container_of(work, struct l2cap_pinfo, busy_work);
-	struct sock *sk = (struct sock *)pi;
-	int n_tries = 0, timeo = HZ/5, err;
+	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	struct sk_buff *skb;
 	u16 control;
+	int err;
 
-	lock_sock(sk);
-
-	add_wait_queue(sk_sleep(sk), &wait);
-	while ((skb = skb_peek(BUSY_QUEUE(sk)))) {
-		set_current_state(TASK_INTERRUPTIBLE);
-
-		if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
-			err = -EBUSY;
-			l2cap_send_disconn_req(pi->conn, sk);
-			goto done;
+	while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) {
+		control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
+		err = l2cap_ertm_reassembly_sdu(sk, skb, control);
+		if (err < 0) {
+			skb_queue_head(BUSY_QUEUE(sk), skb);
+			return -EBUSY;
 		}
 
-		if (!timeo)
-			timeo = HZ/5;
-
-		if (signal_pending(current)) {
-			err = sock_intr_errno(timeo);
-			goto done;
-		}
-
-		release_sock(sk);
-		timeo = schedule_timeout(timeo);
-		lock_sock(sk);
-
-		err = sock_error(sk);
-		if (err)
-			goto done;
-
-		while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) {
-			control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
-			err = l2cap_ertm_reassembly_sdu(sk, skb, control);
-			if (err < 0) {
-				skb_queue_head(BUSY_QUEUE(sk), skb);
-				break;
-			}
-
-			pi->buffer_seq = (pi->buffer_seq + 1) % 64;
-		}
-
-		if (!skb)
-			break;
+		pi->buffer_seq = (pi->buffer_seq + 1) % 64;
 	}
 
 	if (!(pi->conn_state & L2CAP_CONN_RNR_SENT))
@@ -3607,6 +3685,52 @@
 	pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
 	pi->conn_state &= ~L2CAP_CONN_RNR_SENT;
 
+	BT_DBG("sk %p, Exit local busy", sk);
+
+	return 0;
+}
+
+static void l2cap_busy_work(struct work_struct *work)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct l2cap_pinfo *pi =
+		container_of(work, struct l2cap_pinfo, busy_work);
+	struct sock *sk = (struct sock *)pi;
+	int n_tries = 0, timeo = HZ/5, err;
+	struct sk_buff *skb;
+
+	lock_sock(sk);
+
+	add_wait_queue(sk_sleep(sk), &wait);
+	while ((skb = skb_peek(BUSY_QUEUE(sk)))) {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
+			err = -EBUSY;
+			l2cap_send_disconn_req(pi->conn, sk, EBUSY);
+			break;
+		}
+
+		if (!timeo)
+			timeo = HZ/5;
+
+		if (signal_pending(current)) {
+			err = sock_intr_errno(timeo);
+			break;
+		}
+
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+
+		err = sock_error(sk);
+		if (err)
+			break;
+
+		if (l2cap_try_push_rx_skb(sk) == 0)
+			break;
+	}
+
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(sk_sleep(sk), &wait);
 
@@ -3621,7 +3745,9 @@
 	if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 		bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
 		__skb_queue_tail(BUSY_QUEUE(sk), skb);
-		return -EBUSY;
+		return l2cap_try_push_rx_skb(sk);
+
+
 	}
 
 	err = l2cap_ertm_reassembly_sdu(sk, skb, control);
@@ -3631,6 +3757,8 @@
 	}
 
 	/* Busy Condition */
+	BT_DBG("sk %p, Enter local busy", sk);
+
 	pi->conn_state |= L2CAP_CONN_LOCAL_BUSY;
 	bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
 	__skb_queue_tail(BUSY_QUEUE(sk), skb);
@@ -3641,6 +3769,8 @@
 
 	pi->conn_state |= L2CAP_CONN_RNR_SENT;
 
+	del_timer(&pi->ack_timer);
+
 	queue_work(_busy_wq, &pi->busy_work);
 
 	return err;
@@ -3754,7 +3884,7 @@
 		l2cap_ertm_reassembly_sdu(sk, skb, control);
 		l2cap_pi(sk)->buffer_seq_srej =
 			(l2cap_pi(sk)->buffer_seq_srej + 1) % 64;
-		tx_seq++;
+		tx_seq = (tx_seq + 1) % 64;
 	}
 }
 
@@ -3790,10 +3920,11 @@
 		l2cap_send_sframe(pi, control);
 
 		new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
-		new->tx_seq = pi->expected_tx_seq++;
+		new->tx_seq = pi->expected_tx_seq;
+		pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
 		list_add_tail(&new->list, SREJ_LIST(sk));
 	}
-	pi->expected_tx_seq++;
+	pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
 }
 
 static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb)
@@ -3802,11 +3933,12 @@
 	u8 tx_seq = __get_txseq(rx_control);
 	u8 req_seq = __get_reqseq(rx_control);
 	u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
-	u8 tx_seq_offset, expected_tx_seq_offset;
+	int tx_seq_offset, expected_tx_seq_offset;
 	int num_to_ack = (pi->tx_win/6) + 1;
 	int err = 0;
 
-	BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
+	BT_DBG("sk %p len %d tx_seq %d rx_control 0x%4.4x", sk, skb->len, tx_seq,
+								rx_control);
 
 	if (L2CAP_CTRL_FINAL & rx_control &&
 			l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) {
@@ -3828,7 +3960,7 @@
 
 	/* invalid tx_seq */
 	if (tx_seq_offset >= pi->tx_win) {
-		l2cap_send_disconn_req(pi->conn, sk);
+		l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
 		goto drop;
 	}
 
@@ -3851,6 +3983,7 @@
 				pi->buffer_seq = pi->buffer_seq_srej;
 				pi->conn_state &= ~L2CAP_CONN_SREJ_SENT;
 				l2cap_send_ack(pi);
+				BT_DBG("sk %p, Exit SREJ_SENT", sk);
 			}
 		} else {
 			struct srej_list *l;
@@ -3879,6 +4012,8 @@
 
 		pi->conn_state |= L2CAP_CONN_SREJ_SENT;
 
+		BT_DBG("sk %p, Enter SREJ", sk);
+
 		INIT_LIST_HEAD(SREJ_LIST(sk));
 		pi->buffer_seq_srej = pi->buffer_seq;
 
@@ -3889,6 +4024,8 @@
 		pi->conn_state |= L2CAP_CONN_SEND_PBIT;
 
 		l2cap_send_srejframe(sk, tx_seq);
+
+		del_timer(&pi->ack_timer);
 	}
 	return 0;
 
@@ -3902,6 +4039,10 @@
 		return 0;
 	}
 
+	err = l2cap_push_rx_skb(sk, skb, rx_control);
+	if (err < 0)
+		return 0;
+
 	if (rx_control & L2CAP_CTRL_FINAL) {
 		if (pi->conn_state & L2CAP_CONN_REJ_ACT)
 			pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
@@ -3909,10 +4050,6 @@
 			l2cap_retransmit_frames(sk);
 	}
 
-	err = l2cap_push_rx_skb(sk, skb, rx_control);
-	if (err < 0)
-		return 0;
-
 	__mod_ack_timer();
 
 	pi->num_acked = (pi->num_acked + 1) % num_to_ack;
@@ -3930,10 +4067,14 @@
 {
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
 
+	BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control),
+						rx_control);
+
 	pi->expected_ack_seq = __get_reqseq(rx_control);
 	l2cap_drop_acked_frames(sk);
 
 	if (rx_control & L2CAP_CTRL_POLL) {
+		pi->conn_state |= L2CAP_CONN_SEND_FBIT;
 		if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
 			if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
 					(pi->unacked_frames > 0))
@@ -3962,9 +4103,7 @@
 		if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
 			l2cap_send_ack(pi);
 		} else {
-			spin_lock_bh(&pi->send_lock);
 			l2cap_ertm_send(sk);
-			spin_unlock_bh(&pi->send_lock);
 		}
 	}
 }
@@ -3974,6 +4113,8 @@
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	u8 tx_seq = __get_reqseq(rx_control);
 
+	BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
+
 	pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 
 	pi->expected_ack_seq = tx_seq;
@@ -3996,16 +4137,18 @@
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	u8 tx_seq = __get_reqseq(rx_control);
 
+	BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
+
 	pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 
 	if (rx_control & L2CAP_CTRL_POLL) {
 		pi->expected_ack_seq = tx_seq;
 		l2cap_drop_acked_frames(sk);
+
+		pi->conn_state |= L2CAP_CONN_SEND_FBIT;
 		l2cap_retransmit_one_frame(sk, tx_seq);
 
-		spin_lock_bh(&pi->send_lock);
 		l2cap_ertm_send(sk);
-		spin_unlock_bh(&pi->send_lock);
 
 		if (pi->conn_state & L2CAP_CONN_WAIT_F) {
 			pi->srej_save_reqseq = tx_seq;
@@ -4031,10 +4174,15 @@
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	u8 tx_seq = __get_reqseq(rx_control);
 
+	BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
+
 	pi->conn_state |= L2CAP_CONN_REMOTE_BUSY;
 	pi->expected_ack_seq = tx_seq;
 	l2cap_drop_acked_frames(sk);
 
+	if (rx_control & L2CAP_CTRL_POLL)
+		pi->conn_state |= L2CAP_CONN_SEND_FBIT;
+
 	if (!(pi->conn_state & L2CAP_CONN_SREJ_SENT)) {
 		del_timer(&pi->retrans_timer);
 		if (rx_control & L2CAP_CTRL_POLL)
@@ -4082,12 +4230,83 @@
 	return 0;
 }
 
+static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
+{
+	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	u16 control;
+	u8 req_seq;
+	int len, next_tx_seq_offset, req_seq_offset;
+
+	control = get_unaligned_le16(skb->data);
+	skb_pull(skb, 2);
+	len = skb->len;
+
+	/*
+	 * We can just drop the corrupted I-frame here.
+	 * Receiver will miss it and start proper recovery
+	 * procedures and ask retransmission.
+	 */
+	if (l2cap_check_fcs(pi, skb))
+		goto drop;
+
+	if (__is_sar_start(control) && __is_iframe(control))
+		len -= 2;
+
+	if (pi->fcs == L2CAP_FCS_CRC16)
+		len -= 2;
+
+	if (len > pi->mps) {
+		l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+		goto drop;
+	}
+
+	req_seq = __get_reqseq(control);
+	req_seq_offset = (req_seq - pi->expected_ack_seq) % 64;
+	if (req_seq_offset < 0)
+		req_seq_offset += 64;
+
+	next_tx_seq_offset =
+		(pi->next_tx_seq - pi->expected_ack_seq) % 64;
+	if (next_tx_seq_offset < 0)
+		next_tx_seq_offset += 64;
+
+	/* check for invalid req-seq */
+	if (req_seq_offset > next_tx_seq_offset) {
+		l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+		goto drop;
+	}
+
+	if (__is_iframe(control)) {
+		if (len < 0) {
+			l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+			goto drop;
+		}
+
+		l2cap_data_channel_iframe(sk, control, skb);
+	} else {
+		if (len != 0) {
+			BT_ERR("%d", len);
+			l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+			goto drop;
+		}
+
+		l2cap_data_channel_sframe(sk, control, skb);
+	}
+
+	return 0;
+
+drop:
+	kfree_skb(skb);
+	return 0;
+}
+
 static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
 {
 	struct sock *sk;
 	struct l2cap_pinfo *pi;
-	u16 control, len;
-	u8 tx_seq, req_seq, next_tx_seq_offset, req_seq_offset;
+	u16 control;
+	u8 tx_seq;
+	int len;
 
 	sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
 	if (!sk) {
@@ -4117,59 +4336,11 @@
 		break;
 
 	case L2CAP_MODE_ERTM:
-		control = get_unaligned_le16(skb->data);
-		skb_pull(skb, 2);
-		len = skb->len;
-
-		if (__is_sar_start(control))
-			len -= 2;
-
-		if (pi->fcs == L2CAP_FCS_CRC16)
-			len -= 2;
-
-		/*
-		 * We can just drop the corrupted I-frame here.
-		 * Receiver will miss it and start proper recovery
-		 * procedures and ask retransmission.
-		 */
-		if (len > pi->mps) {
-			l2cap_send_disconn_req(pi->conn, sk);
-			goto drop;
-		}
-
-		if (l2cap_check_fcs(pi, skb))
-			goto drop;
-
-		req_seq = __get_reqseq(control);
-		req_seq_offset = (req_seq - pi->expected_ack_seq) % 64;
-		if (req_seq_offset < 0)
-			req_seq_offset += 64;
-
-		next_tx_seq_offset =
-			(pi->next_tx_seq - pi->expected_ack_seq) % 64;
-		if (next_tx_seq_offset < 0)
-			next_tx_seq_offset += 64;
-
-		/* check for invalid req-seq */
-		if (req_seq_offset > next_tx_seq_offset) {
-			l2cap_send_disconn_req(pi->conn, sk);
-			goto drop;
-		}
-
-		if (__is_iframe(control)) {
-			if (len < 4) {
-				l2cap_send_disconn_req(pi->conn, sk);
-				goto drop;
-			}
-
-			l2cap_data_channel_iframe(sk, control, skb);
+		if (!sock_owned_by_user(sk)) {
+			l2cap_ertm_data_rcv(sk, skb);
 		} else {
-			if (len != 0) {
-				l2cap_send_disconn_req(pi->conn, sk);
+			if (sk_add_backlog(sk, skb))
 				goto drop;
-			}
-
-			l2cap_data_channel_sframe(sk, control, skb);
 		}
 
 		goto done;
@@ -4179,16 +4350,16 @@
 		skb_pull(skb, 2);
 		len = skb->len;
 
+		if (l2cap_check_fcs(pi, skb))
+			goto drop;
+
 		if (__is_sar_start(control))
 			len -= 2;
 
 		if (pi->fcs == L2CAP_FCS_CRC16)
 			len -= 2;
 
-		if (len > pi->mps || len < 4 || __is_sframe(control))
-			goto drop;
-
-		if (l2cap_check_fcs(pi, skb))
+		if (len > pi->mps || len < 0 || __is_sframe(control))
 			goto drop;
 
 		tx_seq = __get_txseq(control);
@@ -4288,7 +4459,7 @@
 	struct hlist_node *node;
 
 	if (type != ACL_LINK)
-		return 0;
+		return -EINVAL;
 
 	BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
 
@@ -4321,7 +4492,7 @@
 	BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
 
 	if (hcon->type != ACL_LINK)
-		return 0;
+		return -EINVAL;
 
 	if (!status) {
 		conn = l2cap_conn_add(hcon, status);
@@ -4350,7 +4521,7 @@
 	BT_DBG("hcon %p reason %d", hcon, reason);
 
 	if (hcon->type != ACL_LINK)
-		return 0;
+		return -EINVAL;
 
 	l2cap_conn_del(hcon, bt_err(reason));
 
@@ -4679,14 +4850,8 @@
 module_init(l2cap_init);
 module_exit(l2cap_exit);
 
-module_param(enable_ertm, bool, 0644);
-MODULE_PARM_DESC(enable_ertm, "Enable enhanced retransmission mode");
-
-module_param(max_transmit, uint, 0644);
-MODULE_PARM_DESC(max_transmit, "Max transmit value (default = 3)");
-
-module_param(tx_window, uint, 0644);
-MODULE_PARM_DESC(tx_window, "Transmission window size value (default = 63)");
+module_param(disable_ertm, bool, 0644);
+MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
 
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 43fbf6b..44a6232 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -1152,7 +1152,7 @@
 	return err;
 }
 
-void rfcomm_cleanup_sockets(void)
+void __exit rfcomm_cleanup_sockets(void)
 {
 	debugfs_remove(rfcomm_sock_debugfs);
 
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 309b6c2..026205c 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -1153,7 +1153,7 @@
 	.tiocmset		= rfcomm_tty_tiocmset,
 };
 
-int rfcomm_init_ttys(void)
+int __init rfcomm_init_ttys(void)
 {
 	rfcomm_tty_driver = alloc_tty_driver(RFCOMM_TTY_PORTS);
 	if (!rfcomm_tty_driver)
@@ -1183,7 +1183,7 @@
 	return 0;
 }
 
-void rfcomm_cleanup_ttys(void)
+void __exit rfcomm_cleanup_ttys(void)
 {
 	tty_unregister_driver(rfcomm_tty_driver);
 	put_tty_driver(rfcomm_tty_driver);
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 76357b5..c8436fa 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -63,7 +63,6 @@
 		goto err_out4;
 
 	brioctl_set(br_ioctl_deviceless_stub);
-	br_handle_frame_hook = br_handle_frame;
 
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 	br_fdb_test_addr_hook = br_fdb_test_addr;
@@ -100,7 +99,6 @@
 	br_fdb_test_addr_hook = NULL;
 #endif
 
-	br_handle_frame_hook = NULL;
 	br_fdb_fini();
 }
 
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 753fc42..cf09fe59 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -22,7 +22,7 @@
 #include <asm/uaccess.h>
 #include "br_private.h"
 
-/* net device transmit always called with no BH (preempt_disabled) */
+/* net device transmit always called with BH disabled */
 netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct net_bridge *br = netdev_priv(dev);
@@ -38,17 +38,26 @@
 	}
 #endif
 
+	u64_stats_update_begin(&brstats->syncp);
 	brstats->tx_packets++;
 	brstats->tx_bytes += skb->len;
+	u64_stats_update_end(&brstats->syncp);
 
 	BR_INPUT_SKB_CB(skb)->brdev = dev;
 
 	skb_reset_mac_header(skb);
 	skb_pull(skb, ETH_HLEN);
 
+	rcu_read_lock();
 	if (is_multicast_ether_addr(dest)) {
-		if (br_multicast_rcv(br, NULL, skb))
+		if (unlikely(netpoll_tx_running(dev))) {
+			br_flood_deliver(br, skb);
 			goto out;
+		}
+		if (br_multicast_rcv(br, NULL, skb)) {
+			kfree_skb(skb);
+			goto out;
+		}
 
 		mdst = br_mdb_get(br, skb);
 		if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb))
@@ -61,6 +70,7 @@
 		br_flood_deliver(br, skb);
 
 out:
+	rcu_read_unlock();
 	return NETDEV_TX_OK;
 }
 
@@ -92,21 +102,25 @@
 	return 0;
 }
 
-static struct net_device_stats *br_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev,
+						struct rtnl_link_stats64 *stats)
 {
 	struct net_bridge *br = netdev_priv(dev);
-	struct net_device_stats *stats = &dev->stats;
-	struct br_cpu_netstats sum = { 0 };
+	struct br_cpu_netstats tmp, sum = { 0 };
 	unsigned int cpu;
 
 	for_each_possible_cpu(cpu) {
+		unsigned int start;
 		const struct br_cpu_netstats *bstats
 			= per_cpu_ptr(br->stats, cpu);
-
-		sum.tx_bytes   += bstats->tx_bytes;
-		sum.tx_packets += bstats->tx_packets;
-		sum.rx_bytes   += bstats->rx_bytes;
-		sum.rx_packets += bstats->rx_packets;
+		do {
+			start = u64_stats_fetch_begin(&bstats->syncp);
+			memcpy(&tmp, bstats, sizeof(tmp));
+		} while (u64_stats_fetch_retry(&bstats->syncp, start));
+		sum.tx_bytes   += tmp.tx_bytes;
+		sum.tx_packets += tmp.tx_packets;
+		sum.rx_bytes   += tmp.rx_bytes;
+		sum.rx_packets += tmp.rx_packets;
 	}
 
 	stats->tx_bytes   = sum.tx_bytes;
@@ -127,7 +141,7 @@
 
 #ifdef CONFIG_BRIDGE_NETFILTER
 	/* remember the MTU in the rtable for PMTU */
-	br->fake_rtable.u.dst.metrics[RTAX_MTU - 1] = new_mtu;
+	br->fake_rtable.dst.metrics[RTAX_MTU - 1] = new_mtu;
 #endif
 
 	return 0;
@@ -199,65 +213,81 @@
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-static bool br_devices_support_netpoll(struct net_bridge *br)
+static void br_poll_controller(struct net_device *br_dev)
 {
-	struct net_bridge_port *p;
-	bool ret = true;
-	int count = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&br->lock, flags);
-	list_for_each_entry(p, &br->port_list, list) {
-		count++;
-		if ((p->dev->priv_flags & IFF_DISABLE_NETPOLL) ||
-		    !p->dev->netdev_ops->ndo_poll_controller)
-			ret = false;
-	}
-	spin_unlock_irqrestore(&br->lock, flags);
-	return count != 0 && ret;
 }
 
-void br_netpoll_cleanup(struct net_device *dev)
+static void br_netpoll_cleanup(struct net_device *dev)
 {
 	struct net_bridge *br = netdev_priv(dev);
 	struct net_bridge_port *p, *n;
-	const struct net_device_ops *ops;
 
-	br->dev->npinfo = NULL;
 	list_for_each_entry_safe(p, n, &br->port_list, list) {
-		if (p->dev) {
-			ops = p->dev->netdev_ops;
-			if (ops->ndo_netpoll_cleanup)
-				ops->ndo_netpoll_cleanup(p->dev);
-			else
-				p->dev->npinfo = NULL;
-		}
+		br_netpoll_disable(p);
 	}
 }
 
-void br_netpoll_disable(struct net_bridge *br,
-			struct net_device *dev)
+static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
 {
-	if (br_devices_support_netpoll(br))
-		br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
-	if (dev->netdev_ops->ndo_netpoll_cleanup)
-		dev->netdev_ops->ndo_netpoll_cleanup(dev);
-	else
-		dev->npinfo = NULL;
+	struct net_bridge *br = netdev_priv(dev);
+	struct net_bridge_port *p, *n;
+	int err = 0;
+
+	list_for_each_entry_safe(p, n, &br->port_list, list) {
+		if (!p->dev)
+			continue;
+
+		err = br_netpoll_enable(p);
+		if (err)
+			goto fail;
+	}
+
+out:
+	return err;
+
+fail:
+	br_netpoll_cleanup(dev);
+	goto out;
 }
 
-void br_netpoll_enable(struct net_bridge *br,
-		       struct net_device *dev)
+int br_netpoll_enable(struct net_bridge_port *p)
 {
-	if (br_devices_support_netpoll(br)) {
-		br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
-		if (br->dev->npinfo)
-			dev->npinfo = br->dev->npinfo;
-	} else if (!(br->dev->priv_flags & IFF_DISABLE_NETPOLL)) {
-		br->dev->priv_flags |= IFF_DISABLE_NETPOLL;
-		br_info(br,"new device %s does not support netpoll (disabling)",
-			dev->name);
+	struct netpoll *np;
+	int err = 0;
+
+	np = kzalloc(sizeof(*p->np), GFP_KERNEL);
+	err = -ENOMEM;
+	if (!np)
+		goto out;
+
+	np->dev = p->dev;
+
+	err = __netpoll_setup(np);
+	if (err) {
+		kfree(np);
+		goto out;
 	}
+
+	p->np = np;
+
+out:
+	return err;
+}
+
+void br_netpoll_disable(struct net_bridge_port *p)
+{
+	struct netpoll *np = p->np;
+
+	if (!np)
+		return;
+
+	p->np = NULL;
+
+	/* Wait for transmitting packets to finish before freeing. */
+	synchronize_rcu_bh();
+
+	__netpoll_cleanup(np);
+	kfree(np);
 }
 
 #endif
@@ -280,13 +310,15 @@
 	.ndo_open		 = br_dev_open,
 	.ndo_stop		 = br_dev_stop,
 	.ndo_start_xmit		 = br_dev_xmit,
-	.ndo_get_stats		 = br_get_stats,
+	.ndo_get_stats64	 = br_get_stats64,
 	.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,
 #ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_netpoll_setup	 = br_netpoll_setup,
 	.ndo_netpoll_cleanup	 = br_netpoll_cleanup,
+	.ndo_poll_controller	 = br_poll_controller,
 #endif
 };
 
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index b01dde3..90512cc 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -214,7 +214,7 @@
 	spin_unlock_bh(&br->hash_lock);
 }
 
-/* No locking or refcounting, assumes caller has no preempt (rcu_read_lock) */
+/* No locking or refcounting, assumes caller has rcu_read_lock */
 struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
 					  const unsigned char *addr)
 {
@@ -240,11 +240,11 @@
 	struct net_bridge_fdb_entry *fdb;
 	int ret;
 
-	if (!dev->br_port)
+	if (!br_port_exists(dev))
 		return 0;
 
 	rcu_read_lock();
-	fdb = __br_fdb_get(dev->br_port->br, addr);
+	fdb = __br_fdb_get(br_port_get_rcu(dev)->br, addr);
 	ret = fdb && fdb->dst->dev != dev &&
 		fdb->dst->state == BR_STATE_FORWARDING;
 	rcu_read_unlock();
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 595da45..cbfe87f 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -67,6 +67,17 @@
 static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
 {
 	skb->dev = to->dev;
+
+	if (unlikely(netpoll_tx_running(to->dev))) {
+		if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
+			kfree_skb(skb);
+		else {
+			skb_push(skb, ETH_HLEN);
+			br_netpoll_send_skb(to, skb);
+		}
+		return;
+	}
+
 	NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
 		br_forward_finish);
 }
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 18b245e..c03d2c3 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -147,14 +147,17 @@
 
 	list_del_rcu(&p->list);
 
-	rcu_assign_pointer(dev->br_port, NULL);
+	dev->priv_flags &= ~IFF_BRIDGE_PORT;
+
+	netdev_rx_handler_unregister(dev);
 
 	br_multicast_del_port(p);
 
 	kobject_uevent(&p->kobj, KOBJ_REMOVE);
 	kobject_del(&p->kobj);
 
-	br_netpoll_disable(br, dev);
+	br_netpoll_disable(p);
+
 	call_rcu(&p->rcu, destroy_nbp_rcu);
 }
 
@@ -167,8 +170,6 @@
 		del_nbp(p);
 	}
 
-	br_netpoll_cleanup(br->dev);
-
 	del_timer_sync(&br->gc_timer);
 
 	br_sysfs_delbr(br->dev);
@@ -400,7 +401,7 @@
 		return -ELOOP;
 
 	/* Device is already being bridged */
-	if (dev->br_port != NULL)
+	if (br_port_exists(dev))
 		return -EBUSY;
 
 	/* No bridging devices that dislike that (e.g. wireless) */
@@ -428,7 +429,15 @@
 	if (err)
 		goto err2;
 
-	rcu_assign_pointer(dev->br_port, p);
+	if (br_netpoll_info(br) && ((err = br_netpoll_enable(p))))
+		goto err3;
+
+	err = netdev_rx_handler_register(dev, br_handle_frame, p);
+	if (err)
+		goto err3;
+
+	dev->priv_flags |= IFF_BRIDGE_PORT;
+
 	dev_disable_lro(dev);
 
 	list_add_rcu(&p->list, &br->port_list);
@@ -448,9 +457,9 @@
 
 	kobject_uevent(&p->kobj, KOBJ_ADD);
 
-	br_netpoll_enable(br, dev);
-
 	return 0;
+err3:
+	sysfs_remove_link(br->ifobj, p->dev->name);
 err2:
 	br_fdb_delete_by_port(br, p, 1);
 err1:
@@ -467,9 +476,13 @@
 /* called with RTNL */
 int br_del_if(struct net_bridge *br, struct net_device *dev)
 {
-	struct net_bridge_port *p = dev->br_port;
+	struct net_bridge_port *p;
 
-	if (!p || p->br != br)
+	if (!br_port_exists(dev))
+		return -EINVAL;
+
+	p = br_port_get(dev);
+	if (p->br != br)
 		return -EINVAL;
 
 	del_nbp(p);
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index d36e700..826cd52 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -27,8 +27,10 @@
 	struct net_bridge *br = netdev_priv(brdev);
 	struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
 
+	u64_stats_update_begin(&brstats->syncp);
 	brstats->rx_packets++;
 	brstats->rx_bytes += skb->len;
+	u64_stats_update_end(&brstats->syncp);
 
 	indev = skb->dev;
 	skb->dev = brdev;
@@ -37,11 +39,11 @@
 		       netif_receive_skb);
 }
 
-/* note: already called with rcu_read_lock (preempt_disabled) */
+/* note: already called with rcu_read_lock */
 int br_handle_frame_finish(struct sk_buff *skb)
 {
 	const unsigned char *dest = eth_hdr(skb)->h_dest;
-	struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
+	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
 	struct net_bridge *br;
 	struct net_bridge_fdb_entry *dst;
 	struct net_bridge_mdb_entry *mdst;
@@ -108,13 +110,12 @@
 	goto out;
 }
 
-/* note: already called with rcu_read_lock (preempt_disabled) */
+/* note: already called with rcu_read_lock */
 static int br_handle_local_finish(struct sk_buff *skb)
 {
-	struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
+	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
 
-	if (p)
-		br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
+	br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
 	return 0;	 /* process further */
 }
 
@@ -131,15 +132,18 @@
 }
 
 /*
- * Called via br_handle_frame_hook.
  * Return NULL if skb is handled
- * note: already called with rcu_read_lock (preempt_disabled)
+ * note: already called with rcu_read_lock
  */
-struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
+struct sk_buff *br_handle_frame(struct sk_buff *skb)
 {
+	struct net_bridge_port *p;
 	const unsigned char *dest = eth_hdr(skb)->h_dest;
 	int (*rhook)(struct sk_buff *skb);
 
+	if (skb->pkt_type == PACKET_LOOPBACK)
+		return skb;
+
 	if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
 		goto drop;
 
@@ -147,6 +151,8 @@
 	if (!skb)
 		return NULL;
 
+	p = br_port_get_rcu(skb->dev);
+
 	if (unlikely(is_link_local(dest))) {
 		/* Pause frames shouldn't be passed up by driver anyway */
 		if (skb->protocol == htons(ETH_P_PAUSE))
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 27ae946..eb5b256 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1435,7 +1435,7 @@
 	struct icmp6hdr *icmp6h;
 	u8 nexthdr;
 	unsigned len;
-	unsigned offset;
+	int offset;
 	int err;
 
 	if (!pskb_may_pull(skb, sizeof(*ip6h)))
@@ -1728,13 +1728,9 @@
 int br_multicast_toggle(struct net_bridge *br, unsigned long val)
 {
 	struct net_bridge_port *port;
-	int err = -ENOENT;
+	int err = 0;
 
 	spin_lock(&br->multicast_lock);
-	if (!netif_running(br->dev))
-		goto unlock;
-
-	err = 0;
 	if (br->multicast_disabled == !val)
 		goto unlock;
 
@@ -1742,6 +1738,9 @@
 	if (br->multicast_disabled)
 		goto unlock;
 
+	if (!netif_running(br->dev))
+		goto unlock;
+
 	if (br->mdb) {
 		if (br->mdb->old) {
 			err = -EEXIST;
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 8fb75f8..2c911c0 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -55,6 +55,9 @@
 static int brnf_filter_vlan_tagged __read_mostly = 0;
 static int brnf_filter_pppoe_tagged __read_mostly = 0;
 #else
+#define brnf_call_iptables 1
+#define brnf_call_ip6tables 1
+#define brnf_call_arptables 1
 #define brnf_filter_vlan_tagged 0
 #define brnf_filter_pppoe_tagged 0
 #endif
@@ -117,26 +120,27 @@
 {
 	struct rtable *rt = &br->fake_rtable;
 
-	atomic_set(&rt->u.dst.__refcnt, 1);
-	rt->u.dst.dev = br->dev;
-	rt->u.dst.path = &rt->u.dst;
-	rt->u.dst.metrics[RTAX_MTU - 1] = 1500;
-	rt->u.dst.flags	= DST_NOXFRM;
-	rt->u.dst.ops = &fake_dst_ops;
+	atomic_set(&rt->dst.__refcnt, 1);
+	rt->dst.dev = br->dev;
+	rt->dst.path = &rt->dst;
+	rt->dst.metrics[RTAX_MTU - 1] = 1500;
+	rt->dst.flags	= DST_NOXFRM;
+	rt->dst.ops = &fake_dst_ops;
 }
 
 static inline struct rtable *bridge_parent_rtable(const struct net_device *dev)
 {
-	struct net_bridge_port *port = rcu_dereference(dev->br_port);
-
-	return port ? &port->br->fake_rtable : NULL;
+	if (!br_port_exists(dev))
+		return NULL;
+	return &br_port_get_rcu(dev)->br->fake_rtable;
 }
 
 static inline struct net_device *bridge_parent(const struct net_device *dev)
 {
-	struct net_bridge_port *port = rcu_dereference(dev->br_port);
+	if (!br_port_exists(dev))
+		return NULL;
 
-	return port ? port->br->dev : NULL;
+	return br_port_get_rcu(dev)->br->dev;
 }
 
 static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
@@ -244,8 +248,7 @@
 		kfree_skb(skb);
 		return 0;
 	}
-	dst_hold(&rt->u.dst);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set_noref(skb, &rt->dst);
 
 	skb->dev = nf_bridge->physindev;
 	nf_bridge_update_protocol(skb);
@@ -396,8 +399,7 @@
 			kfree_skb(skb);
 			return 0;
 		}
-		dst_hold(&rt->u.dst);
-		skb_dst_set(skb, &rt->u.dst);
+		skb_dst_set_noref(skb, &rt->dst);
 	}
 
 	skb->dev = nf_bridge->physindev;
@@ -545,25 +547,30 @@
 				      const struct net_device *out,
 				      int (*okfn)(struct sk_buff *))
 {
+	struct net_bridge_port *p;
+	struct net_bridge *br;
 	struct iphdr *iph;
 	__u32 len = nf_bridge_encap_header_len(skb);
 
 	if (unlikely(!pskb_may_pull(skb, len)))
 		goto out;
 
+	p = br_port_get_rcu(in);
+	if (p == NULL)
+		goto out;
+	br = p->br;
+
 	if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) ||
 	    IS_PPPOE_IPV6(skb)) {
-#ifdef CONFIG_SYSCTL
-		if (!brnf_call_ip6tables)
+		if (!brnf_call_ip6tables && !br->nf_call_ip6tables)
 			return NF_ACCEPT;
-#endif
+
 		nf_bridge_pull_encap_header_rcsum(skb);
 		return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn);
 	}
-#ifdef CONFIG_SYSCTL
-	if (!brnf_call_iptables)
+
+	if (!brnf_call_iptables && !br->nf_call_iptables)
 		return NF_ACCEPT;
-#endif
 
 	if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb) &&
 	    !IS_PPPOE_IP(skb))
@@ -719,12 +726,17 @@
 				      const struct net_device *out,
 				      int (*okfn)(struct sk_buff *))
 {
+	struct net_bridge_port *p;
+	struct net_bridge *br;
 	struct net_device **d = (struct net_device **)(skb->cb);
 
-#ifdef CONFIG_SYSCTL
-	if (!brnf_call_arptables)
+	p = br_port_get_rcu(out);
+	if (p == NULL)
 		return NF_ACCEPT;
-#endif
+	br = p->br;
+
+	if (!brnf_call_arptables && !br->nf_call_arptables)
+		return NF_ACCEPT;
 
 	if (skb->protocol != htons(ETH_P_ARP)) {
 		if (!IS_VLAN_ARP(skb))
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index fe0a790..4a6a378 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -120,10 +120,11 @@
 	idx = 0;
 	for_each_netdev(net, dev) {
 		/* not a bridge port */
-		if (dev->br_port == NULL || idx < cb->args[0])
+		if (!br_port_exists(dev) || idx < cb->args[0])
 			goto skip;
 
-		if (br_fill_ifinfo(skb, dev->br_port, NETLINK_CB(cb->skb).pid,
+		if (br_fill_ifinfo(skb, br_port_get(dev),
+				   NETLINK_CB(cb->skb).pid,
 				   cb->nlh->nlmsg_seq, RTM_NEWLINK,
 				   NLM_F_MULTI) < 0)
 			break;
@@ -168,9 +169,9 @@
 	if (!dev)
 		return -ENODEV;
 
-	p = dev->br_port;
-	if (!p)
+	if (!br_port_exists(dev))
 		return -EINVAL;
+	p = br_port_get(dev);
 
 	/* if kernel STP is running, don't allow changes */
 	if (p->br->stp_enabled == BR_KERNEL_STP)
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 717e1fd..404d4e1 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -32,14 +32,15 @@
 static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
 {
 	struct net_device *dev = ptr;
-	struct net_bridge_port *p = dev->br_port;
+	struct net_bridge_port *p = br_port_get(dev);
 	struct net_bridge *br;
 	int err;
 
 	/* not a port of a bridge */
-	if (p == NULL)
+	if (!br_port_exists(dev))
 		return NOTIFY_DONE;
 
+	p = br_port_get(dev);
 	br = p->br;
 
 	switch (event) {
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 0f4a74b..75c90ed 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -15,6 +15,8 @@
 
 #include <linux/netdevice.h>
 #include <linux/if_bridge.h>
+#include <linux/netpoll.h>
+#include <linux/u64_stats_sync.h>
 #include <net/route.h>
 
 #define BR_HASH_BITS 8
@@ -143,13 +145,23 @@
 #ifdef CONFIG_SYSFS
 	char				sysfs_name[IFNAMSIZ];
 #endif
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	struct netpoll			*np;
+#endif
 };
 
+#define br_port_get_rcu(dev) \
+	((struct net_bridge_port *) rcu_dereference(dev->rx_handler_data))
+#define br_port_get(dev) ((struct net_bridge_port *) dev->rx_handler_data)
+#define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT)
+
 struct br_cpu_netstats {
-	unsigned long	rx_packets;
-	unsigned long	rx_bytes;
-	unsigned long	tx_packets;
-	unsigned long	tx_bytes;
+	u64			rx_packets;
+	u64			rx_bytes;
+	u64			tx_packets;
+	u64			tx_bytes;
+	struct u64_stats_sync	syncp;
 };
 
 struct net_bridge
@@ -164,6 +176,9 @@
 	unsigned long			feature_mask;
 #ifdef CONFIG_BRIDGE_NETFILTER
 	struct rtable 			fake_rtable;
+	bool				nf_call_iptables;
+	bool				nf_call_ip6tables;
+	bool				nf_call_arptables;
 #endif
 	unsigned long			flags;
 #define BR_SET_MAC_ADDR		0x00000001
@@ -273,16 +288,41 @@
 extern netdev_tx_t br_dev_xmit(struct sk_buff *skb,
 			       struct net_device *dev);
 #ifdef CONFIG_NET_POLL_CONTROLLER
-extern void br_netpoll_cleanup(struct net_device *dev);
-extern void br_netpoll_enable(struct net_bridge *br,
-			      struct net_device *dev);
-extern void br_netpoll_disable(struct net_bridge *br,
-			       struct net_device *dev);
-#else
-#define br_netpoll_cleanup(br)
-#define br_netpoll_enable(br, dev)
-#define br_netpoll_disable(br, dev)
+static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
+{
+	return br->dev->npinfo;
+}
 
+static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
+				       struct sk_buff *skb)
+{
+	struct netpoll *np = p->np;
+
+	if (np)
+		netpoll_send_skb(np, skb);
+}
+
+extern int br_netpoll_enable(struct net_bridge_port *p);
+extern void br_netpoll_disable(struct net_bridge_port *p);
+#else
+static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
+{
+	return NULL;
+}
+
+static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
+				       struct sk_buff *skb)
+{
+}
+
+static inline int br_netpoll_enable(struct net_bridge_port *p)
+{
+	return 0;
+}
+
+static inline void br_netpoll_disable(struct net_bridge_port *p)
+{
+}
 #endif
 
 /* br_fdb.c */
@@ -331,8 +371,7 @@
 
 /* br_input.c */
 extern int br_handle_frame_finish(struct sk_buff *skb);
-extern struct sk_buff *br_handle_frame(struct net_bridge_port *p,
-				       struct sk_buff *skb);
+extern struct sk_buff *br_handle_frame(struct sk_buff *skb);
 
 /* br_ioctl.c */
 extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
index 217bd22..35cf270 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -131,18 +131,19 @@
 /*
  * Called from llc.
  *
- * NO locks, but rcu_read_lock (preempt_disabled)
+ * NO locks, but rcu_read_lock
  */
 void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
 		struct net_device *dev)
 {
 	const unsigned char *dest = eth_hdr(skb)->h_dest;
-	struct net_bridge_port *p = rcu_dereference(dev->br_port);
+	struct net_bridge_port *p;
 	struct net_bridge *br;
 	const unsigned char *buf;
 
-	if (!p)
+	if (!br_port_exists(dev))
 		goto err;
+	p = br_port_get_rcu(dev);
 
 	if (!pskb_may_pull(skb, 4))
 		goto err;
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 486b8f3..5c1e555 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -611,6 +611,73 @@
 		   show_multicast_startup_query_interval,
 		   store_multicast_startup_query_interval);
 #endif
+#ifdef CONFIG_BRIDGE_NETFILTER
+static ssize_t show_nf_call_iptables(
+	struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct net_bridge *br = to_bridge(d);
+	return sprintf(buf, "%u\n", br->nf_call_iptables);
+}
+
+static int set_nf_call_iptables(struct net_bridge *br, unsigned long val)
+{
+	br->nf_call_iptables = val ? true : false;
+	return 0;
+}
+
+static ssize_t store_nf_call_iptables(
+	struct device *d, struct device_attribute *attr, const char *buf,
+	size_t len)
+{
+	return store_bridge_parm(d, buf, len, set_nf_call_iptables);
+}
+static DEVICE_ATTR(nf_call_iptables, S_IRUGO | S_IWUSR,
+		   show_nf_call_iptables, store_nf_call_iptables);
+
+static ssize_t show_nf_call_ip6tables(
+	struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct net_bridge *br = to_bridge(d);
+	return sprintf(buf, "%u\n", br->nf_call_ip6tables);
+}
+
+static int set_nf_call_ip6tables(struct net_bridge *br, unsigned long val)
+{
+	br->nf_call_ip6tables = val ? true : false;
+	return 0;
+}
+
+static ssize_t store_nf_call_ip6tables(
+	struct device *d, struct device_attribute *attr, const char *buf,
+	size_t len)
+{
+	return store_bridge_parm(d, buf, len, set_nf_call_ip6tables);
+}
+static DEVICE_ATTR(nf_call_ip6tables, S_IRUGO | S_IWUSR,
+		   show_nf_call_ip6tables, store_nf_call_ip6tables);
+
+static ssize_t show_nf_call_arptables(
+	struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct net_bridge *br = to_bridge(d);
+	return sprintf(buf, "%u\n", br->nf_call_arptables);
+}
+
+static int set_nf_call_arptables(struct net_bridge *br, unsigned long val)
+{
+	br->nf_call_arptables = val ? true : false;
+	return 0;
+}
+
+static ssize_t store_nf_call_arptables(
+	struct device *d, struct device_attribute *attr, const char *buf,
+	size_t len)
+{
+	return store_bridge_parm(d, buf, len, set_nf_call_arptables);
+}
+static DEVICE_ATTR(nf_call_arptables, S_IRUGO | S_IWUSR,
+		   show_nf_call_arptables, store_nf_call_arptables);
+#endif
 
 static struct attribute *bridge_attrs[] = {
 	&dev_attr_forward_delay.attr,
@@ -645,6 +712,11 @@
 	&dev_attr_multicast_query_response_interval.attr,
 	&dev_attr_multicast_startup_query_interval.attr,
 #endif
+#ifdef CONFIG_BRIDGE_NETFILTER
+	&dev_attr_nf_call_iptables.attr,
+	&dev_attr_nf_call_ip6tables.attr,
+	&dev_attr_nf_call_arptables.attr,
+#endif
 	NULL
 };
 
diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c
index 9e19166..46624bb 100644
--- a/net/bridge/netfilter/ebt_redirect.c
+++ b/net/bridge/netfilter/ebt_redirect.c
@@ -24,8 +24,9 @@
 		return EBT_DROP;
 
 	if (par->hooknum != NF_BR_BROUTING)
+		/* rcu_read_lock()ed by nf_hook_slow */
 		memcpy(eth_hdr(skb)->h_dest,
-		       par->in->br_port->br->dev->dev_addr, ETH_ALEN);
+		       br_port_get_rcu(par->in)->br->dev->dev_addr, ETH_ALEN);
 	else
 		memcpy(eth_hdr(skb)->h_dest, par->in->dev_addr, ETH_ALEN);
 	skb->pkt_type = PACKET_HOST;
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
index ae3c7ce..26377e9 100644
--- a/net/bridge/netfilter/ebt_ulog.c
+++ b/net/bridge/netfilter/ebt_ulog.c
@@ -177,8 +177,9 @@
 	if (in) {
 		strcpy(pm->physindev, in->name);
 		/* If in isn't a bridge, then physindev==indev */
-		if (in->br_port)
-			strcpy(pm->indev, in->br_port->br->dev->name);
+		if (br_port_exists(in))
+			/* rcu_read_lock()ed by nf_hook_slow */
+			strcpy(pm->indev, br_port_get_rcu(in)->br->dev->name);
 		else
 			strcpy(pm->indev, in->name);
 	} else
@@ -187,7 +188,8 @@
 	if (out) {
 		/* If out exists, then out is a bridge port */
 		strcpy(pm->physoutdev, out->name);
-		strcpy(pm->outdev, out->br_port->br->dev->name);
+		/* rcu_read_lock()ed by nf_hook_slow */
+		strcpy(pm->outdev, br_port_get_rcu(out)->br->dev->name);
 	} else
 		pm->outdev[0] = pm->physoutdev[0] = '\0';
 
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 59ca00e..bcc102e 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -140,11 +140,14 @@
 		return 1;
 	if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
 		return 1;
-	if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
-	   e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
+	/* rcu_read_lock()ed by nf_hook_slow */
+	if (in && br_port_exists(in) &&
+	    FWINV2(ebt_dev_check(e->logical_in, br_port_get_rcu(in)->br->dev),
+		   EBT_ILOGICALIN))
 		return 1;
-	if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
-	   e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
+	if (out && br_port_exists(out) &&
+	    FWINV2(ebt_dev_check(e->logical_out, br_port_get_rcu(out)->br->dev),
+		   EBT_ILOGICALOUT))
 		return 1;
 
 	if (e->bitmask & EBT_SOURCEMAC) {
diff --git a/net/caif/Kconfig b/net/caif/Kconfig
index ed65178..529750d 100644
--- a/net/caif/Kconfig
+++ b/net/caif/Kconfig
@@ -21,19 +21,18 @@
 	See Documentation/networking/caif for a further explanation on how to
 	use and configure CAIF.
 
-if CAIF
-
 config  CAIF_DEBUG
 	bool "Enable Debug"
+	depends on CAIF
 	default n
 	--- help ---
 	Enable the inclusion of debug code in the CAIF stack.
 	Be aware that doing this will impact performance.
 	If unsure say N.
 
-
 config CAIF_NETDEV
 	tristate "CAIF GPRS Network device"
+	depends on CAIF
 	default CAIF
 	---help---
 	Say Y if you will be using a CAIF based GPRS network device.
@@ -41,5 +40,3 @@
 	If you select to build it as a built-in then the main CAIF device must
 	also be a built-in.
 	If unsure say Y.
-
-endif
diff --git a/net/caif/Makefile b/net/caif/Makefile
index 34852af..f87481f 100644
--- a/net/caif/Makefile
+++ b/net/caif/Makefile
@@ -1,23 +1,13 @@
-ifeq ($(CONFIG_CAIF_DEBUG),1)
-CAIF_DBG_FLAGS := -DDEBUG
+ifeq ($(CONFIG_CAIF_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
 endif
 
-ccflags-y := $(CAIF_FLAGS) $(CAIF_DBG_FLAGS)
-
 caif-objs := caif_dev.o \
 	cfcnfg.o cfmuxl.o cfctrl.o  \
 	cffrml.o cfveil.o cfdbgl.o\
 	cfserl.o cfdgml.o  \
 	cfrfml.o cfvidl.o cfutill.o \
 	cfsrvl.o cfpkt_skbuff.o caif_config_util.o
-clean-dirs:= .tmp_versions
-
-clean-files:= \
-	Module.symvers \
-	modules.order \
-	*.cmd \
-	*.o \
-	*~
 
 obj-$(CONFIG_CAIF) += caif.o
 obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o
diff --git a/net/caif/caif_config_util.c b/net/caif/caif_config_util.c
index 6f36580..76ae683 100644
--- a/net/caif/caif_config_util.c
+++ b/net/caif/caif_config_util.c
@@ -80,6 +80,11 @@
 		       l->u.utility.paramlen);
 
 		break;
+	case CAIFPROTO_DEBUG:
+		l->linktype = CFCTRL_SRV_DBG;
+		l->endpoint = s->sockaddr.u.dbg.service;
+		l->chtype = s->sockaddr.u.dbg.type;
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
index e2b86f1..0b586e9 100644
--- a/net/caif/caif_dev.c
+++ b/net/caif/caif_dev.c
@@ -255,7 +255,7 @@
 			pref = CFPHYPREF_HIGH_BW;
 			break;
 		}
-
+		dev_hold(dev);
 		cfcnfg_add_phy_layer(get_caif_conf(),
 				     phy_type,
 				     dev,
@@ -285,6 +285,7 @@
 		caifd->layer.up->ctrlcmd(caifd->layer.up,
 					 _CAIF_CTRLCMD_PHYIF_DOWN_IND,
 					 caifd->layer.id);
+		might_sleep();
 		res = wait_event_interruptible_timeout(caifd->event,
 					atomic_read(&caifd->in_use) == 0,
 					TIMEOUT);
@@ -300,6 +301,7 @@
 				   "Unregistering an active CAIF device: %s\n",
 				   __func__, dev->name);
 		cfcnfg_del_phy_layer(get_caif_conf(), &caifd->layer);
+		dev_put(dev);
 		atomic_set(&caifd->state, what);
 		break;
 
@@ -326,7 +328,8 @@
 EXPORT_SYMBOL(get_caif_conf);
 
 int caif_connect_client(struct caif_connect_request *conn_req,
-			   struct cflayer *client_layer)
+			struct cflayer *client_layer, int *ifindex,
+			int *headroom, int *tailroom)
 {
 	struct cfctrl_link_param param;
 	int ret;
@@ -334,8 +337,9 @@
 	if (ret)
 		return ret;
 	/* Hook up the adaptation layer. */
-	return cfcnfg_add_adaptation_layer(get_caif_conf(),
-						&param, client_layer);
+	return cfcnfg_add_adaptation_layer(get_caif_conf(), &param,
+					client_layer, ifindex,
+					headroom, tailroom);
 }
 EXPORT_SYMBOL(caif_connect_client);
 
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 3d0e095..8ce9047 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -28,8 +28,8 @@
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_NETPROTO(AF_CAIF);
 
-#define CAIF_DEF_SNDBUF (CAIF_MAX_PAYLOAD_SIZE*10)
-#define CAIF_DEF_RCVBUF (CAIF_MAX_PAYLOAD_SIZE*100)
+#define CAIF_DEF_SNDBUF (4096*10)
+#define CAIF_DEF_RCVBUF (4096*100)
 
 /*
  * CAIF state is re-using the TCP socket states.
@@ -76,6 +76,7 @@
 	struct caif_connect_request conn_req;
 	struct mutex readlock;
 	struct dentry *debugfs_socket_dir;
+	int headroom, tailroom, maxframe;
 };
 
 static int rx_flow_is_on(struct caifsock *cf_sk)
@@ -594,27 +595,32 @@
 		goto err;
 	noblock = msg->msg_flags & MSG_DONTWAIT;
 
-	buffer_size = len + CAIF_NEEDED_HEADROOM + CAIF_NEEDED_TAILROOM;
-
-	ret = -EMSGSIZE;
-	if (buffer_size > CAIF_MAX_PAYLOAD_SIZE)
-		goto err;
-
 	timeo = sock_sndtimeo(sk, noblock);
 	timeo = caif_wait_for_flow_on(container_of(sk, struct caifsock, sk),
 				1, timeo, &ret);
 
+	if (ret)
+		goto err;
 	ret = -EPIPE;
 	if (cf_sk->sk.sk_state != CAIF_CONNECTED ||
 		sock_flag(sk, SOCK_DEAD) ||
 		(sk->sk_shutdown & RCV_SHUTDOWN))
 		goto err;
 
+	/* Error if trying to write more than maximum frame size. */
+	ret = -EMSGSIZE;
+	if (len > cf_sk->maxframe && cf_sk->sk.sk_protocol != CAIFPROTO_RFM)
+		goto err;
+
+	buffer_size = len + cf_sk->headroom + cf_sk->tailroom;
+
 	ret = -ENOMEM;
 	skb = sock_alloc_send_skb(sk, buffer_size, noblock, &ret);
-	if (!skb)
+
+	if (!skb || skb_tailroom(skb) < buffer_size)
 		goto err;
-	skb_reserve(skb, CAIF_NEEDED_HEADROOM);
+
+	skb_reserve(skb, cf_sk->headroom);
 
 	ret = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
 
@@ -645,7 +651,6 @@
 	long timeo;
 
 	err = -EOPNOTSUPP;
-
 	if (unlikely(msg->msg_flags&MSG_OOB))
 		goto out_err;
 
@@ -662,8 +667,8 @@
 
 		size = len-sent;
 
-		if (size > CAIF_MAX_PAYLOAD_SIZE)
-			size = CAIF_MAX_PAYLOAD_SIZE;
+		if (size > cf_sk->maxframe)
+			size = cf_sk->maxframe;
 
 		/* If size is more than half of sndbuf, chop up message */
 		if (size > ((sk->sk_sndbuf >> 1) - 64))
@@ -673,14 +678,14 @@
 			size = SKB_MAX_ALLOC;
 
 		skb = sock_alloc_send_skb(sk,
-					size + CAIF_NEEDED_HEADROOM
-					+ CAIF_NEEDED_TAILROOM,
+					size + cf_sk->headroom +
+					cf_sk->tailroom,
 					msg->msg_flags&MSG_DONTWAIT,
 					&err);
 		if (skb == NULL)
 			goto out_err;
 
-		skb_reserve(skb, CAIF_NEEDED_HEADROOM);
+		skb_reserve(skb, cf_sk->headroom);
 		/*
 		 *	If you pass two values to the sock_alloc_send_skb
 		 *	it tries to grab the large buffer with GFP_NOFS
@@ -821,17 +826,15 @@
 	struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
 	long timeo;
 	int err;
+	int ifindex, headroom, tailroom;
+	struct net_device *dev;
+
 	lock_sock(sk);
 
 	err = -EAFNOSUPPORT;
 	if (uaddr->sa_family != AF_CAIF)
 		goto out;
 
-	err = -ESOCKTNOSUPPORT;
-	if (unlikely(!(sk->sk_type == SOCK_STREAM &&
-		       cf_sk->sk.sk_protocol == CAIFPROTO_AT) &&
-		       sk->sk_type != SOCK_SEQPACKET))
-		goto out;
 	switch (sock->state) {
 	case SS_UNCONNECTED:
 		/* Normal case, a fresh connect */
@@ -874,8 +877,7 @@
 	sk_stream_kill_queues(&cf_sk->sk);
 
 	err = -EINVAL;
-	if (addr_len != sizeof(struct sockaddr_caif) ||
-		!uaddr)
+	if (addr_len != sizeof(struct sockaddr_caif))
 		goto out;
 
 	memcpy(&cf_sk->conn_req.sockaddr, uaddr,
@@ -888,12 +890,23 @@
 	dbfs_atomic_inc(&cnt.num_connect_req);
 	cf_sk->layer.receive = caif_sktrecv_cb;
 	err = caif_connect_client(&cf_sk->conn_req,
-				&cf_sk->layer);
+				&cf_sk->layer, &ifindex, &headroom, &tailroom);
 	if (err < 0) {
 		cf_sk->sk.sk_socket->state = SS_UNCONNECTED;
 		cf_sk->sk.sk_state = CAIF_DISCONNECTED;
 		goto out;
 	}
+	dev = dev_get_by_index(sock_net(sk), ifindex);
+	cf_sk->headroom = LL_RESERVED_SPACE_EXTRA(dev, headroom);
+	cf_sk->tailroom = tailroom;
+	cf_sk->maxframe = dev->mtu - (headroom + tailroom);
+	dev_put(dev);
+	if (cf_sk->maxframe < 1) {
+		pr_warning("CAIF: %s(): CAIF Interface MTU too small (%d)\n",
+			__func__, dev->mtu);
+		err = -ENODEV;
+		goto out;
+	}
 
 	err = -EINPROGRESS;
 wait_connect:
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
index df43f26..1c29189 100644
--- a/net/caif/cfcnfg.c
+++ b/net/caif/cfcnfg.c
@@ -6,6 +6,7 @@
 #include <linux/kernel.h>
 #include <linux/stddef.h>
 #include <linux/slab.h>
+#include <linux/netdevice.h>
 #include <net/caif/caif_layer.h>
 #include <net/caif/cfpkt.h>
 #include <net/caif/cfcnfg.h>
@@ -22,6 +23,7 @@
 #define PHY_NAME_LEN 20
 
 #define container_obj(layr) container_of(layr, struct cfcnfg, layer)
+#define RFM_FRAGMENT_SIZE 4030
 
 /* Information about CAIF physical interfaces held by Config Module in order
  * to manage physical interfaces
@@ -41,6 +43,15 @@
 
 	/* Information about the physical device */
 	struct dev_info dev_info;
+
+	/* Interface index */
+	int ifindex;
+
+	/* Use Start of frame extension */
+	bool use_stx;
+
+	/* Use Start of frame checksum */
+	bool use_fcs;
 };
 
 struct cfcnfg {
@@ -248,9 +259,20 @@
 {
 }
 
+int protohead[CFCTRL_SRV_MASK] = {
+	[CFCTRL_SRV_VEI] = 4,
+	[CFCTRL_SRV_DATAGRAM] = 7,
+	[CFCTRL_SRV_UTIL] = 4,
+	[CFCTRL_SRV_RFM] = 3,
+	[CFCTRL_SRV_DBG] = 3,
+};
+
 int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
 				struct cfctrl_link_param *param,
-				struct cflayer *adap_layer)
+				struct cflayer *adap_layer,
+				int *ifindex,
+				int *proto_head,
+				int *proto_tail)
 {
 	struct cflayer *frml;
 	if (adap_layer == NULL) {
@@ -276,6 +298,14 @@
 		     param->phyid);
 	caif_assert(cnfg->phy_layers[param->phyid].phy_layer->id ==
 		     param->phyid);
+
+	*ifindex = cnfg->phy_layers[param->phyid].ifindex;
+	*proto_head =
+		protohead[param->linktype]+
+		(cnfg->phy_layers[param->phyid].use_stx ? 1 : 0);
+
+	*proto_tail = 2;
+
 	/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
 	cfctrl_enum_req(cnfg->ctrl, param->phyid);
 	return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer);
@@ -297,6 +327,8 @@
 	struct cfcnfg *cnfg = container_obj(layer);
 	struct cflayer *servicel = NULL;
 	struct cfcnfg_phyinfo *phyinfo;
+	struct net_device *netdev;
+
 	if (adapt_layer == NULL) {
 		pr_debug("CAIF: %s(): link setup response "
 				"but no client exist, send linkdown back\n",
@@ -308,19 +340,15 @@
 	caif_assert(cnfg != NULL);
 	caif_assert(phyid != 0);
 	phyinfo = &cnfg->phy_layers[phyid];
-	caif_assert(phyinfo != NULL);
 	caif_assert(phyinfo->id == phyid);
 	caif_assert(phyinfo->phy_layer != NULL);
 	caif_assert(phyinfo->phy_layer->id == phyid);
 
-	if (phyinfo != NULL &&
-	    phyinfo->phy_ref_count++ == 0 &&
-	    phyinfo->phy_layer != NULL &&
+	phyinfo->phy_ref_count++;
+	if (phyinfo->phy_ref_count == 1 &&
 	    phyinfo->phy_layer->modemcmd != NULL) {
-		caif_assert(phyinfo->phy_layer->id == phyid);
 		phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
 					     _CAIF_MODEMCMD_PHYIF_USEFULL);
-
 	}
 	adapt_layer->id = channel_id;
 
@@ -332,7 +360,9 @@
 		servicel = cfdgml_create(channel_id, &phyinfo->dev_info);
 		break;
 	case CFCTRL_SRV_RFM:
-		servicel = cfrfml_create(channel_id, &phyinfo->dev_info);
+		netdev = phyinfo->dev_info.dev;
+		servicel = cfrfml_create(channel_id, &phyinfo->dev_info,
+						netdev->mtu);
 		break;
 	case CFCTRL_SRV_UTIL:
 		servicel = cfutill_create(channel_id, &phyinfo->dev_info);
@@ -363,8 +393,8 @@
 
 void
 cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
-		     void *dev, struct cflayer *phy_layer, u16 *phyid,
-		     enum cfcnfg_phy_preference pref,
+		     struct net_device *dev, struct cflayer *phy_layer,
+		     u16 *phyid, enum cfcnfg_phy_preference pref,
 		     bool fcs, bool stx)
 {
 	struct cflayer *frml;
@@ -418,6 +448,10 @@
 	cnfg->phy_layers[*phyid].dev_info.dev = dev;
 	cnfg->phy_layers[*phyid].phy_layer = phy_layer;
 	cnfg->phy_layers[*phyid].phy_ref_count = 0;
+	cnfg->phy_layers[*phyid].ifindex = dev->ifindex;
+	cnfg->phy_layers[*phyid].use_stx = stx;
+	cnfg->phy_layers[*phyid].use_fcs = fcs;
+
 	phy_layer->type = phy_type;
 	frml = cffrml_create(*phyid, fcs);
 	if (!frml) {
diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
index fcfda98..563145f 100644
--- a/net/caif/cfctrl.c
+++ b/net/caif/cfctrl.c
@@ -19,7 +19,7 @@
 #ifdef CAIF_NO_LOOP
 static int handle_loop(struct cfctrl *ctrl,
 			      int cmd, struct cfpkt *pkt){
-	return CAIF_FAILURE;
+	return -1;
 }
 #else
 static int handle_loop(struct cfctrl *ctrl,
@@ -43,7 +43,7 @@
 	memset(&dev_info, 0, sizeof(dev_info));
 	dev_info.id = 0xff;
 	memset(this, 0, sizeof(*this));
-	cfsrvl_init(&this->serv, 0, &dev_info);
+	cfsrvl_init(&this->serv, 0, &dev_info, false);
 	atomic_set(&this->req_seq_no, 1);
 	atomic_set(&this->rsp_seq_no, 1);
 	this->serv.layer.receive = cfctrl_recv;
@@ -395,7 +395,7 @@
 	cmd = cmdrsp & CFCTRL_CMD_MASK;
 	if (cmd != CFCTRL_CMD_LINK_ERR
 	    && CFCTRL_RSP_BIT != (CFCTRL_RSP_BIT & cmdrsp)) {
-		if (handle_loop(cfctrl, cmd, pkt) == CAIF_FAILURE)
+		if (handle_loop(cfctrl, cmd, pkt) != 0)
 			cmdrsp |= CFCTRL_ERR_BIT;
 	}
 
@@ -647,6 +647,6 @@
 	default:
 		break;
 	}
-	return CAIF_SUCCESS;
+	return 0;
 }
 #endif
diff --git a/net/caif/cfdbgl.c b/net/caif/cfdbgl.c
index ab6b6dc..676648c 100644
--- a/net/caif/cfdbgl.c
+++ b/net/caif/cfdbgl.c
@@ -22,7 +22,7 @@
 	}
 	caif_assert(offsetof(struct cfsrvl, layer) == 0);
 	memset(dbg, 0, sizeof(struct cfsrvl));
-	cfsrvl_init(dbg, channel_id, dev_info);
+	cfsrvl_init(dbg, channel_id, dev_info, false);
 	dbg->layer.receive = cfdbgl_receive;
 	dbg->layer.transmit = cfdbgl_transmit;
 	snprintf(dbg->layer.name, CAIF_LAYER_NAME_SZ - 1, "dbg%d", channel_id);
diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c
index 5319484..ed9d53a 100644
--- a/net/caif/cfdgml.c
+++ b/net/caif/cfdgml.c
@@ -17,6 +17,7 @@
 #define DGM_FLOW_OFF 0x81
 #define DGM_FLOW_ON  0x80
 #define DGM_CTRL_PKT_SIZE 1
+#define DGM_MTU 1500
 
 static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt);
 static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt);
@@ -30,7 +31,7 @@
 	}
 	caif_assert(offsetof(struct cfsrvl, layer) == 0);
 	memset(dgm, 0, sizeof(struct cfsrvl));
-	cfsrvl_init(dgm, channel_id, dev_info);
+	cfsrvl_init(dgm, channel_id, dev_info, true);
 	dgm->layer.receive = cfdgml_receive;
 	dgm->layer.transmit = cfdgml_transmit;
 	snprintf(dgm->layer.name, CAIF_LAYER_NAME_SZ - 1, "dgm%d", channel_id);
@@ -89,6 +90,10 @@
 	if (!cfsrvl_ready(service, &ret))
 		return ret;
 
+	/* STE Modem cannot handle more than 1500 bytes datagrams */
+	if (cfpkt_getlen(pkt) > DGM_MTU)
+		return -EMSGSIZE;
+
 	cfpkt_add_head(pkt, &zero, 4);
 
 	/* Add info for MUX-layer to route the packet out. */
diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c
index a6fdf89..01f238f 100644
--- a/net/caif/cfpkt_skbuff.c
+++ b/net/caif/cfpkt_skbuff.c
@@ -9,8 +9,8 @@
 #include <linux/hardirq.h>
 #include <net/caif/cfpkt.h>
 
-#define PKT_PREFIX CAIF_NEEDED_HEADROOM
-#define PKT_POSTFIX CAIF_NEEDED_TAILROOM
+#define PKT_PREFIX  16
+#define PKT_POSTFIX 2
 #define PKT_LEN_WHEN_EXTENDING 128
 #define PKT_ERROR(pkt, errmsg) do {	   \
     cfpkt_priv(pkt)->erronous = true;	   \
@@ -338,7 +338,6 @@
 	u16 dstlen;
 	u16 createlen;
 	if (unlikely(is_erronous(dstpkt) || is_erronous(addpkt))) {
-		cfpkt_destroy(addpkt);
 		return dstpkt;
 	}
 	if (expectlen > addlen)
diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c
index fd27b17..eb16020 100644
--- a/net/caif/cfrfml.c
+++ b/net/caif/cfrfml.c
@@ -7,102 +7,304 @@
 #include <linux/stddef.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
+#include <linux/unaligned/le_byteshift.h>
 #include <net/caif/caif_layer.h>
 #include <net/caif/cfsrvl.h>
 #include <net/caif/cfpkt.h>
 
-#define container_obj(layr) container_of(layr, struct cfsrvl, layer)
-
+#define container_obj(layr) container_of(layr, struct cfrfml, serv.layer)
 #define RFM_SEGMENTATION_BIT 0x01
-#define RFM_PAYLOAD  0x00
-#define RFM_CMD_BIT  0x80
-#define RFM_FLOW_OFF 0x81
-#define RFM_FLOW_ON  0x80
-#define RFM_SET_PIN  0x82
-#define RFM_CTRL_PKT_SIZE 1
+#define RFM_HEAD_SIZE 7
 
 static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt);
 static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt);
-static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl);
 
-struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info)
+struct cfrfml {
+	struct cfsrvl serv;
+	struct cfpkt *incomplete_frm;
+	int fragment_size;
+	u8  seghead[6];
+	u16 pdu_size;
+	/* Protects serialized processing of packets */
+	spinlock_t sync;
+};
+
+static void cfrfml_release(struct kref *kref)
 {
-	struct cfsrvl *rfm = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
-	if (!rfm) {
+	struct cfsrvl *srvl = container_of(kref, struct cfsrvl, ref);
+	struct cfrfml *rfml = container_obj(&srvl->layer);
+
+	if (rfml->incomplete_frm)
+		cfpkt_destroy(rfml->incomplete_frm);
+
+	kfree(srvl);
+}
+
+struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info,
+					int mtu_size)
+{
+	int tmp;
+	struct cfrfml *this =
+		kzalloc(sizeof(struct cfrfml), GFP_ATOMIC);
+
+	if (!this) {
 		pr_warning("CAIF: %s(): Out of memory\n", __func__);
 		return NULL;
 	}
-	caif_assert(offsetof(struct cfsrvl, layer) == 0);
-	memset(rfm, 0, sizeof(struct cfsrvl));
-	cfsrvl_init(rfm, channel_id, dev_info);
-	rfm->layer.modemcmd = cfservl_modemcmd;
-	rfm->layer.receive = cfrfml_receive;
-	rfm->layer.transmit = cfrfml_transmit;
-	snprintf(rfm->layer.name, CAIF_LAYER_NAME_SZ, "rfm%d", channel_id);
-	return &rfm->layer;
+
+	cfsrvl_init(&this->serv, channel_id, dev_info, false);
+	this->serv.release = cfrfml_release;
+	this->serv.layer.receive = cfrfml_receive;
+	this->serv.layer.transmit = cfrfml_transmit;
+
+	/* Round down to closest multiple of 16 */
+	tmp = (mtu_size - RFM_HEAD_SIZE - 6) / 16;
+	tmp *= 16;
+
+	this->fragment_size = tmp;
+	spin_lock_init(&this->sync);
+	snprintf(this->serv.layer.name, CAIF_LAYER_NAME_SZ,
+		"rfm%d", channel_id);
+
+	return &this->serv.layer;
 }
 
-static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
+static struct cfpkt *rfm_append(struct cfrfml *rfml, char *seghead,
+			struct cfpkt *pkt, int *err)
 {
-       return -EPROTO;
+	struct cfpkt *tmppkt;
+	*err = -EPROTO;
+	/* n-th but not last segment */
+
+	if (cfpkt_extr_head(pkt, seghead, 6) < 0)
+		return NULL;
+
+	/* Verify correct header */
+	if (memcmp(seghead, rfml->seghead, 6) != 0)
+		return NULL;
+
+	tmppkt = cfpkt_append(rfml->incomplete_frm, pkt,
+			rfml->pdu_size + RFM_HEAD_SIZE);
+
+	/* If cfpkt_append failes input pkts are not freed */
+	*err = -ENOMEM;
+	if (tmppkt == NULL)
+		return NULL;
+
+	*err = 0;
+	return tmppkt;
 }
 
 static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt)
 {
 	u8 tmp;
 	bool segmented;
-	int ret;
+	int err;
+	u8 seghead[6];
+	struct cfrfml *rfml;
+	struct cfpkt *tmppkt = NULL;
+
 	caif_assert(layr->up != NULL);
 	caif_assert(layr->receive != NULL);
+	rfml = container_obj(layr);
+	spin_lock(&rfml->sync);
 
-	/*
-	 * RFM is taking care of segmentation and stripping of
-	 * segmentation bit.
-	 */
-	if (cfpkt_extr_head(pkt, &tmp, 1) < 0) {
-		pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
-		cfpkt_destroy(pkt);
-		return -EPROTO;
-	}
+	err = -EPROTO;
+	if (cfpkt_extr_head(pkt, &tmp, 1) < 0)
+		goto out;
 	segmented = tmp & RFM_SEGMENTATION_BIT;
-	caif_assert(!segmented);
 
-	ret = layr->up->receive(layr->up, pkt);
-	return ret;
+	if (segmented) {
+		if (rfml->incomplete_frm == NULL) {
+			/* Initial Segment */
+			if (cfpkt_peek_head(pkt, rfml->seghead, 6) < 0)
+				goto out;
+
+			rfml->pdu_size = get_unaligned_le16(rfml->seghead+4);
+
+			if (cfpkt_erroneous(pkt))
+				goto out;
+			rfml->incomplete_frm = pkt;
+			pkt = NULL;
+		} else {
+
+			tmppkt = rfm_append(rfml, seghead, pkt, &err);
+			if (tmppkt == NULL)
+				goto out;
+
+			if (cfpkt_erroneous(tmppkt))
+				goto out;
+
+			rfml->incomplete_frm = tmppkt;
+
+
+			if (cfpkt_erroneous(tmppkt))
+				goto out;
+		}
+		err = 0;
+		goto out;
+	}
+
+	if (rfml->incomplete_frm) {
+
+		/* Last Segment */
+		tmppkt = rfm_append(rfml, seghead, pkt, &err);
+		if (tmppkt == NULL)
+			goto out;
+
+		if (cfpkt_erroneous(tmppkt))
+			goto out;
+
+		rfml->incomplete_frm = NULL;
+		pkt = tmppkt;
+		tmppkt = NULL;
+
+		/* Verify that length is correct */
+		err = EPROTO;
+		if (rfml->pdu_size != cfpkt_getlen(pkt) - RFM_HEAD_SIZE + 1)
+			goto out;
+	}
+
+	err = rfml->serv.layer.up->receive(rfml->serv.layer.up, pkt);
+
+out:
+
+	if (err != 0) {
+		if (tmppkt)
+			cfpkt_destroy(tmppkt);
+		if (pkt)
+			cfpkt_destroy(pkt);
+		if (rfml->incomplete_frm)
+			cfpkt_destroy(rfml->incomplete_frm);
+		rfml->incomplete_frm = NULL;
+
+		pr_info("CAIF: %s(): "
+				"Connection error %d triggered on RFM link\n",
+				__func__, err);
+
+		/* Trigger connection error upon failure.*/
+		layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND,
+					rfml->serv.dev_info.id);
+	}
+	spin_unlock(&rfml->sync);
+	return err;
 }
 
-static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
+
+static int cfrfml_transmit_segment(struct cfrfml *rfml, struct cfpkt *pkt)
 {
-	u8 tmp = 0;
-	int ret;
-	struct cfsrvl *service = container_obj(layr);
-
-	caif_assert(layr->dn != NULL);
-	caif_assert(layr->dn->transmit != NULL);
-
-	if (!cfsrvl_ready(service, &ret))
-		return ret;
-
-	if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
-		pr_err("CAIF: %s():Packet too large - size=%d\n",
-			__func__, cfpkt_getlen(pkt));
-		return -EOVERFLOW;
-	}
-	if (cfpkt_add_head(pkt, &tmp, 1) < 0) {
-		pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
-		return -EPROTO;
-	}
+	caif_assert(cfpkt_getlen(pkt) >= rfml->fragment_size);
 
 	/* Add info for MUX-layer to route the packet out. */
-	cfpkt_info(pkt)->channel_id = service->layer.id;
+	cfpkt_info(pkt)->channel_id = rfml->serv.layer.id;
+
 	/*
 	 * To optimize alignment, we add up the size of CAIF header before
 	 * payload.
 	 */
-	cfpkt_info(pkt)->hdr_len = 1;
-	cfpkt_info(pkt)->dev_info = &service->dev_info;
-	ret = layr->dn->transmit(layr->dn, pkt);
-	if (ret < 0)
-		cfpkt_extr_head(pkt, &tmp, 1);
-	return ret;
+	cfpkt_info(pkt)->hdr_len = RFM_HEAD_SIZE;
+	cfpkt_info(pkt)->dev_info = &rfml->serv.dev_info;
+
+	return rfml->serv.layer.dn->transmit(rfml->serv.layer.dn, pkt);
+}
+
+static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
+{
+	int err;
+	u8 seg;
+	u8 head[6];
+	struct cfpkt *rearpkt = NULL;
+	struct cfpkt *frontpkt = pkt;
+	struct cfrfml *rfml = container_obj(layr);
+
+	caif_assert(layr->dn != NULL);
+	caif_assert(layr->dn->transmit != NULL);
+
+	if (!cfsrvl_ready(&rfml->serv, &err))
+		return err;
+
+	err = -EPROTO;
+	if (cfpkt_getlen(pkt) <= RFM_HEAD_SIZE-1)
+		goto out;
+
+	err = 0;
+	if (cfpkt_getlen(pkt) > rfml->fragment_size + RFM_HEAD_SIZE)
+		err = cfpkt_peek_head(pkt, head, 6);
+
+	if (err < 0)
+		goto out;
+
+	while (cfpkt_getlen(frontpkt) > rfml->fragment_size + RFM_HEAD_SIZE) {
+
+		seg = 1;
+		err = -EPROTO;
+
+		if (cfpkt_add_head(frontpkt, &seg, 1) < 0)
+			goto out;
+		/*
+		 * On OOM error cfpkt_split returns NULL.
+		 *
+		 * NOTE: Segmented pdu is not correctly aligned.
+		 * This has negative performance impact.
+		 */
+
+		rearpkt = cfpkt_split(frontpkt, rfml->fragment_size);
+		if (rearpkt == NULL)
+			goto out;
+
+		err = cfrfml_transmit_segment(rfml, frontpkt);
+
+		if (err != 0)
+			goto out;
+		frontpkt = rearpkt;
+		rearpkt = NULL;
+
+		err = -ENOMEM;
+		if (frontpkt == NULL)
+			goto out;
+		err = -EPROTO;
+		if (cfpkt_add_head(frontpkt, head, 6) < 0)
+			goto out;
+
+	}
+
+	seg = 0;
+	err = -EPROTO;
+
+	if (cfpkt_add_head(frontpkt, &seg, 1) < 0)
+		goto out;
+
+	err = cfrfml_transmit_segment(rfml, frontpkt);
+
+	frontpkt = NULL;
+out:
+
+	if (err != 0) {
+		pr_info("CAIF: %s(): "
+				"Connection error %d triggered on RFM link\n",
+				__func__, err);
+		/* Trigger connection error upon failure.*/
+
+		layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND,
+					rfml->serv.dev_info.id);
+
+		if (rearpkt)
+			cfpkt_destroy(rearpkt);
+
+		if (frontpkt && frontpkt != pkt) {
+
+			cfpkt_destroy(frontpkt);
+			/*
+			 * Socket layer will free the original packet,
+			 * but this packet may already be sent and
+			 * freed. So we have to return 0 in this case
+			 * to avoid socket layer to re-free this packet.
+			 * The return of shutdown indication will
+			 * cause connection to be invalidated anyhow.
+			 */
+			err = 0;
+		}
+	}
+
+	return err;
 }
diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c
index 965c5ba..a11fbd6 100644
--- a/net/caif/cfserl.c
+++ b/net/caif/cfserl.c
@@ -14,7 +14,8 @@
 #define container_obj(layr) ((struct cfserl *) layr)
 
 #define CFSERL_STX 0x02
-#define CAIF_MINIUM_PACKET_SIZE 4
+#define SERIAL_MINIUM_PACKET_SIZE 4
+#define SERIAL_MAX_FRAMESIZE 4096
 struct cfserl {
 	struct cflayer layer;
 	struct cfpkt *incomplete_frm;
@@ -119,8 +120,8 @@
 		/*
 		 * Frame error handling
 		 */
-		if (expectlen < CAIF_MINIUM_PACKET_SIZE
-		    || expectlen > CAIF_MAX_FRAMESIZE) {
+		if (expectlen < SERIAL_MINIUM_PACKET_SIZE
+		    || expectlen > SERIAL_MAX_FRAMESIZE) {
 			if (!layr->usestx) {
 				if (pkt != NULL)
 					cfpkt_destroy(pkt);
diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c
index 6e5b7079..f40939a 100644
--- a/net/caif/cfsrvl.c
+++ b/net/caif/cfsrvl.c
@@ -24,8 +24,10 @@
 				int phyid)
 {
 	struct cfsrvl *service = container_obj(layr);
+
 	caif_assert(layr->up != NULL);
 	caif_assert(layr->up->ctrlcmd != NULL);
+
 	switch (ctrl) {
 	case CAIF_CTRLCMD_INIT_RSP:
 		service->open = true;
@@ -89,9 +91,14 @@
 static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
 {
 	struct cfsrvl *service = container_obj(layr);
+
 	caif_assert(layr != NULL);
 	caif_assert(layr->dn != NULL);
 	caif_assert(layr->dn->transmit != NULL);
+
+	if (!service->supports_flowctrl)
+		return 0;
+
 	switch (ctrl) {
 	case CAIF_MODEMCMD_FLOW_ON_REQ:
 		{
@@ -152,9 +159,17 @@
 	kfree(layer);
 }
 
+void cfsrvl_release(struct kref *kref)
+{
+	struct cfsrvl *service = container_of(kref, struct cfsrvl, ref);
+	kfree(service);
+}
+
 void cfsrvl_init(struct cfsrvl *service,
-		 u8 channel_id,
-		 struct dev_info *dev_info)
+			u8 channel_id,
+			struct dev_info *dev_info,
+			bool supports_flowctrl
+			)
 {
 	caif_assert(offsetof(struct cfsrvl, layer) == 0);
 	service->open = false;
@@ -164,14 +179,11 @@
 	service->layer.ctrlcmd = cfservl_ctrlcmd;
 	service->layer.modemcmd = cfservl_modemcmd;
 	service->dev_info = *dev_info;
+	service->supports_flowctrl = supports_flowctrl;
+	service->release = cfsrvl_release;
 	kref_init(&service->ref);
 }
 
-void cfsrvl_release(struct kref *kref)
-{
-	struct cfsrvl *service = container_of(kref, struct cfsrvl, ref);
-	kfree(service);
-}
 
 bool cfsrvl_ready(struct cfsrvl *service, int *err)
 {
diff --git a/net/caif/cfutill.c b/net/caif/cfutill.c
index 5fd2c9e..02795af 100644
--- a/net/caif/cfutill.c
+++ b/net/caif/cfutill.c
@@ -31,7 +31,7 @@
 	}
 	caif_assert(offsetof(struct cfsrvl, layer) == 0);
 	memset(util, 0, sizeof(struct cfsrvl));
-	cfsrvl_init(util, channel_id, dev_info);
+	cfsrvl_init(util, channel_id, dev_info, true);
 	util->layer.receive = cfutill_receive;
 	util->layer.transmit = cfutill_transmit;
 	snprintf(util->layer.name, CAIF_LAYER_NAME_SZ - 1, "util1");
@@ -90,12 +90,6 @@
 	if (!cfsrvl_ready(service, &ret))
 		return ret;
 
-	if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
-		pr_err("CAIF: %s(): packet too large size=%d\n",
-			__func__, cfpkt_getlen(pkt));
-		return -EOVERFLOW;
-	}
-
 	cfpkt_add_head(pkt, &zero, 1);
 	/* Add info for MUX-layer to route the packet out. */
 	info = cfpkt_info(pkt);
diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c
index e04f7d9..77cc09f 100644
--- a/net/caif/cfveil.c
+++ b/net/caif/cfveil.c
@@ -30,7 +30,7 @@
 	}
 	caif_assert(offsetof(struct cfsrvl, layer) == 0);
 	memset(vei, 0, sizeof(struct cfsrvl));
-	cfsrvl_init(vei, channel_id, dev_info);
+	cfsrvl_init(vei, channel_id, dev_info, true);
 	vei->layer.receive = cfvei_receive;
 	vei->layer.transmit = cfvei_transmit;
 	snprintf(vei->layer.name, CAIF_LAYER_NAME_SZ - 1, "vei%d", channel_id);
@@ -84,11 +84,6 @@
 		return ret;
 	caif_assert(layr->dn != NULL);
 	caif_assert(layr->dn->transmit != NULL);
-	if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
-		pr_warning("CAIF: %s(): Packet too large - size=%d\n",
-			   __func__, cfpkt_getlen(pkt));
-		return -EOVERFLOW;
-	}
 
 	if (cfpkt_add_head(pkt, &tmp, 1) < 0) {
 		pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
diff --git a/net/caif/cfvidl.c b/net/caif/cfvidl.c
index 89ad4ea..ada6ee2 100644
--- a/net/caif/cfvidl.c
+++ b/net/caif/cfvidl.c
@@ -27,7 +27,7 @@
 	caif_assert(offsetof(struct cfsrvl, layer) == 0);
 
 	memset(vid, 0, sizeof(struct cfsrvl));
-	cfsrvl_init(vid, channel_id, dev_info);
+	cfsrvl_init(vid, channel_id, dev_info, false);
 	vid->layer.receive = cfvidl_receive;
 	vid->layer.transmit = cfvidl_transmit;
 	snprintf(vid->layer.name, CAIF_LAYER_NAME_SZ - 1, "vid1");
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
index 610966a..4293e19 100644
--- a/net/caif/chnl_net.c
+++ b/net/caif/chnl_net.c
@@ -23,7 +23,7 @@
 #include <net/caif/caif_dev.h>
 
 /* GPRS PDP connection has MTU to 1500 */
-#define SIZE_MTU 1500
+#define GPRS_PDP_MTU 1500
 /* 5 sec. connect timeout */
 #define CONNECT_TIMEOUT (5 * HZ)
 #define CAIF_NET_DEFAULT_QUEUE_LEN 500
@@ -232,6 +232,8 @@
 {
 	struct chnl_net *priv = NULL;
 	int result = -1;
+	int llifindex, headroom, tailroom, mtu;
+	struct net_device *lldev;
 	ASSERT_RTNL();
 	priv = netdev_priv(dev);
 	if (!priv) {
@@ -241,41 +243,88 @@
 
 	if (priv->state != CAIF_CONNECTING) {
 		priv->state = CAIF_CONNECTING;
-		result = caif_connect_client(&priv->conn_req, &priv->chnl);
+		result = caif_connect_client(&priv->conn_req, &priv->chnl,
+					&llifindex, &headroom, &tailroom);
 		if (result != 0) {
-				priv->state = CAIF_DISCONNECTED;
 				pr_debug("CAIF: %s(): err: "
 					"Unable to register and open device,"
 					" Err:%d\n",
 					__func__,
 					result);
-				return result;
+				goto error;
+		}
+
+		lldev = dev_get_by_index(dev_net(dev), llifindex);
+
+		if (lldev == NULL) {
+			pr_debug("CAIF: %s(): no interface?\n", __func__);
+			result = -ENODEV;
+			goto error;
+		}
+
+		dev->needed_tailroom = tailroom + lldev->needed_tailroom;
+		dev->hard_header_len = headroom + lldev->hard_header_len +
+			lldev->needed_tailroom;
+
+		/*
+		 * MTU, head-room etc is not know before we have a
+		 * CAIF link layer device available. MTU calculation may
+		 * override initial RTNL configuration.
+		 * MTU is minimum of current mtu, link layer mtu pluss
+		 * CAIF head and tail, and PDP GPRS contexts max MTU.
+		 */
+		mtu = min_t(int, dev->mtu, lldev->mtu - (headroom + tailroom));
+		mtu = min_t(int, GPRS_PDP_MTU, mtu);
+		dev_set_mtu(dev, mtu);
+		dev_put(lldev);
+
+		if (mtu < 100) {
+			pr_warning("CAIF: %s(): "
+				"CAIF Interface MTU too small (%d)\n",
+				__func__, mtu);
+			result = -ENODEV;
+			goto error;
 		}
 	}
 
+	rtnl_unlock();  /* Release RTNL lock during connect wait */
+
 	result = wait_event_interruptible_timeout(priv->netmgmt_wq,
 						priv->state != CAIF_CONNECTING,
 						CONNECT_TIMEOUT);
 
+	rtnl_lock();
+
 	if (result == -ERESTARTSYS) {
 		pr_debug("CAIF: %s(): wait_event_interruptible"
 			 " woken by a signal\n", __func__);
-		return -ERESTARTSYS;
+		result = -ERESTARTSYS;
+		goto error;
 	}
+
 	if (result == 0) {
 		pr_debug("CAIF: %s(): connect timeout\n", __func__);
 		caif_disconnect_client(&priv->chnl);
 		priv->state = CAIF_DISCONNECTED;
 		pr_debug("CAIF: %s(): state disconnected\n", __func__);
-		return -ETIMEDOUT;
+		result = -ETIMEDOUT;
+		goto error;
 	}
 
 	if (priv->state != CAIF_CONNECTED) {
 		pr_debug("CAIF: %s(): connect failed\n", __func__);
-		return -ECONNREFUSED;
+		result = -ECONNREFUSED;
+		goto error;
 	}
 	pr_debug("CAIF: %s(): CAIF Netdevice connected\n", __func__);
 	return 0;
+
+error:
+	caif_disconnect_client(&priv->chnl);
+	priv->state = CAIF_DISCONNECTED;
+	pr_debug("CAIF: %s(): state disconnected\n", __func__);
+	return result;
+
 }
 
 static int chnl_net_stop(struct net_device *dev)
@@ -321,9 +370,7 @@
 	dev->destructor = free_netdev;
 	dev->flags |= IFF_NOARP;
 	dev->flags |= IFF_POINTOPOINT;
-	dev->needed_headroom = CAIF_NEEDED_HEADROOM;
-	dev->needed_tailroom = CAIF_NEEDED_TAILROOM;
-	dev->mtu = SIZE_MTU;
+	dev->mtu = GPRS_PDP_MTU;
 	dev->tx_queue_len = CAIF_NET_DEFAULT_QUEUE_LEN;
 
 	priv = netdev_priv(dev);
diff --git a/net/can/raw.c b/net/can/raw.c
index da99cf1..a10e333 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -436,14 +436,9 @@
 
 		if (count > 1) {
 			/* filter does not fit into dfilter => alloc space */
-			filter = kmalloc(optlen, GFP_KERNEL);
-			if (!filter)
-				return -ENOMEM;
-
-			if (copy_from_user(filter, optval, optlen)) {
-				kfree(filter);
-				return -EFAULT;
-			}
+			filter = memdup_user(optval, optlen);
+			if (IS_ERR(filter))
+				return PTR_ERR(filter);
 		} else if (count == 1) {
 			if (copy_from_user(&sfilter, optval, sizeof(sfilter)))
 				return -EFAULT;
@@ -655,6 +650,10 @@
 	err = sock_tx_timestamp(msg, sk, skb_tx(skb));
 	if (err < 0)
 		goto free_skb;
+
+	/* to be able to check the received tx sock reference in raw_rcv() */
+	skb_tx(skb)->prevent_sk_orphan = 1;
+
 	skb->dev = dev;
 	skb->sk  = sk;
 
diff --git a/net/compat.c b/net/compat.c
index ec24d9e..63d260e 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -81,7 +81,7 @@
 	int tot_len;
 
 	if (kern_msg->msg_namelen) {
-		if (mode==VERIFY_READ) {
+		if (mode == VERIFY_READ) {
 			int err = move_addr_to_kernel(kern_msg->msg_name,
 						      kern_msg->msg_namelen,
 						      kern_address);
@@ -354,7 +354,7 @@
 static int do_set_sock_timeout(struct socket *sock, int level,
 		int optname, char __user *optval, unsigned int optlen)
 {
-	struct compat_timeval __user *up = (struct compat_timeval __user *) optval;
+	struct compat_timeval __user *up = (struct compat_timeval __user *)optval;
 	struct timeval ktime;
 	mm_segment_t old_fs;
 	int err;
@@ -367,7 +367,7 @@
 		return -EFAULT;
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	err = sock_setsockopt(sock, level, optname, (char *) &ktime, sizeof(ktime));
+	err = sock_setsockopt(sock, level, optname, (char *)&ktime, sizeof(ktime));
 	set_fs(old_fs);
 
 	return err;
@@ -389,11 +389,10 @@
 				char __user *optval, unsigned int optlen)
 {
 	int err;
-	struct socket *sock;
+	struct socket *sock = sockfd_lookup(fd, &err);
 
-	if ((sock = sockfd_lookup(fd, &err))!=NULL)
-	{
-		err = security_socket_setsockopt(sock,level,optname);
+	if (sock) {
+		err = security_socket_setsockopt(sock, level, optname);
 		if (err) {
 			sockfd_put(sock);
 			return err;
@@ -453,7 +452,7 @@
 int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
 {
 	struct compat_timeval __user *ctv =
-			(struct compat_timeval __user*) userstamp;
+			(struct compat_timeval __user *) userstamp;
 	int err = -ENOENT;
 	struct timeval tv;
 
@@ -477,7 +476,7 @@
 int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
 {
 	struct compat_timespec __user *ctv =
-			(struct compat_timespec __user*) userstamp;
+			(struct compat_timespec __user *) userstamp;
 	int err = -ENOENT;
 	struct timespec ts;
 
@@ -502,12 +501,10 @@
 				char __user *optval, int __user *optlen)
 {
 	int err;
-	struct socket *sock;
+	struct socket *sock = sockfd_lookup(fd, &err);
 
-	if ((sock = sockfd_lookup(fd, &err))!=NULL)
-	{
-		err = security_socket_getsockopt(sock, level,
-							   optname);
+	if (sock) {
+		err = security_socket_getsockopt(sock, level, optname);
 		if (err) {
 			sockfd_put(sock);
 			return err;
@@ -531,7 +528,7 @@
 	__u32				 gr_interface;
 	struct __kernel_sockaddr_storage gr_group
 		__attribute__ ((aligned(4)));
-} __attribute__ ((packed));
+} __packed;
 
 struct compat_group_source_req {
 	__u32				 gsr_interface;
@@ -539,7 +536,7 @@
 		__attribute__ ((aligned(4)));
 	struct __kernel_sockaddr_storage gsr_source
 		__attribute__ ((aligned(4)));
-} __attribute__ ((packed));
+} __packed;
 
 struct compat_group_filter {
 	__u32				 gf_interface;
@@ -549,7 +546,7 @@
 	__u32				 gf_numsrc;
 	struct __kernel_sockaddr_storage gf_slist[1]
 		__attribute__ ((aligned(4)));
-} __attribute__ ((packed));
+} __packed;
 
 #define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
 			sizeof(struct __kernel_sockaddr_storage))
@@ -557,7 +554,7 @@
 
 int compat_mc_setsockopt(struct sock *sock, int level, int optname,
 	char __user *optval, unsigned int optlen,
-	int (*setsockopt)(struct sock *,int,int,char __user *,unsigned int))
+	int (*setsockopt)(struct sock *, int, int, char __user *, unsigned int))
 {
 	char __user	*koptval = optval;
 	int		koptlen = optlen;
@@ -640,12 +637,11 @@
 	}
 	return setsockopt(sock, level, optname, koptval, koptlen);
 }
-
 EXPORT_SYMBOL(compat_mc_setsockopt);
 
 int compat_mc_getsockopt(struct sock *sock, int level, int optname,
 	char __user *optval, int __user *optlen,
-	int (*getsockopt)(struct sock *,int,int,char __user *,int __user *))
+	int (*getsockopt)(struct sock *, int, int, char __user *, int __user *))
 {
 	struct compat_group_filter __user *gf32 = (void *)optval;
 	struct group_filter __user *kgf;
@@ -681,7 +677,7 @@
 	    __put_user(interface, &kgf->gf_interface) ||
 	    __put_user(fmode, &kgf->gf_fmode) ||
 	    __put_user(numsrc, &kgf->gf_numsrc) ||
-	    copy_in_user(&kgf->gf_group,&gf32->gf_group,sizeof(kgf->gf_group)))
+	    copy_in_user(&kgf->gf_group, &gf32->gf_group, sizeof(kgf->gf_group)))
 		return -EFAULT;
 
 	err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen);
@@ -714,21 +710,22 @@
 		copylen = numsrc * sizeof(gf32->gf_slist[0]);
 		if (copylen > klen)
 			copylen = klen;
-	        if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
+		if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
 			return -EFAULT;
 	}
 	return err;
 }
-
 EXPORT_SYMBOL(compat_mc_getsockopt);
 
 
 /* Argument list sizes for compat_sys_socketcall */
 #define AL(x) ((x) * sizeof(u32))
-static unsigned char nas[20]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
-				AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
-				AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
-				AL(4),AL(5)};
+static unsigned char nas[20] = {
+	AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
+	AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
+	AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
+	AL(4), AL(5)
+};
 #undef AL
 
 asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags)
@@ -827,7 +824,7 @@
 					  compat_ptr(a[4]), compat_ptr(a[5]));
 		break;
 	case SYS_SHUTDOWN:
-		ret = sys_shutdown(a0,a1);
+		ret = sys_shutdown(a0, a1);
 		break;
 	case SYS_SETSOCKOPT:
 		ret = compat_sys_setsockopt(a0, a1, a[2],
diff --git a/net/core/Makefile b/net/core/Makefile
index 51c3eec..8a04dd2 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -18,4 +18,4 @@
 obj-$(CONFIG_FIB_RULES) += fib_rules.o
 obj-$(CONFIG_TRACEPOINTS) += net-traces.o
 obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o
-
+obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o
diff --git a/net/core/datagram.c b/net/core/datagram.c
index f5b6f43..251997a 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -219,6 +219,7 @@
 	return __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
 				   &peeked, err);
 }
+EXPORT_SYMBOL(skb_recv_datagram);
 
 void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
 {
@@ -288,7 +289,6 @@
 
 	return err;
 }
-
 EXPORT_SYMBOL(skb_kill_datagram);
 
 /**
@@ -373,6 +373,7 @@
 fault:
 	return -EFAULT;
 }
+EXPORT_SYMBOL(skb_copy_datagram_iovec);
 
 /**
  *	skb_copy_datagram_const_iovec - Copy a datagram to an iovec.
@@ -716,6 +717,7 @@
 fault:
 	return -EFAULT;
 }
+EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
 
 /**
  * 	datagram_poll - generic datagram poll
@@ -770,8 +772,4 @@
 
 	return mask;
 }
-
 EXPORT_SYMBOL(datagram_poll);
-EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
-EXPORT_SYMBOL(skb_copy_datagram_iovec);
-EXPORT_SYMBOL(skb_recv_datagram);
diff --git a/net/core/dev.c b/net/core/dev.c
index 1f466e8..e1c1cdc 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -101,8 +101,6 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/stat.h>
-#include <linux/if_bridge.h>
-#include <linux/if_macvlan.h>
 #include <net/dst.h>
 #include <net/pkt_sched.h>
 #include <net/checksum.h>
@@ -803,35 +801,31 @@
 EXPORT_SYMBOL(dev_getfirstbyhwtype);
 
 /**
- *	dev_get_by_flags - find any device with given flags
+ *	dev_get_by_flags_rcu - find any device with given flags
  *	@net: the applicable net namespace
  *	@if_flags: IFF_* values
  *	@mask: bitmask of bits in if_flags to check
  *
  *	Search for any interface with the given flags. Returns NULL if a device
- *	is not found or a pointer to the device. The device returned has
- *	had a reference added and the pointer is safe until the user calls
- *	dev_put to indicate they have finished with it.
+ *	is not found or a pointer to the device. Must be called inside
+ *	rcu_read_lock(), and result refcount is unchanged.
  */
 
-struct net_device *dev_get_by_flags(struct net *net, unsigned short if_flags,
+struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short if_flags,
 				    unsigned short mask)
 {
 	struct net_device *dev, *ret;
 
 	ret = NULL;
-	rcu_read_lock();
 	for_each_netdev_rcu(net, dev) {
 		if (((dev->flags ^ if_flags) & mask) == 0) {
-			dev_hold(dev);
 			ret = dev;
 			break;
 		}
 	}
-	rcu_read_unlock();
 	return ret;
 }
-EXPORT_SYMBOL(dev_get_by_flags);
+EXPORT_SYMBOL(dev_get_by_flags_rcu);
 
 /**
  *	dev_valid_name - check if name is okay for network device
@@ -1542,7 +1536,8 @@
 				if (net_ratelimit())
 					printk(KERN_CRIT "protocol %04x is "
 					       "buggy, dev %s\n",
-					       skb2->protocol, dev->name);
+					       ntohs(skb2->protocol),
+					       dev->name);
 				skb_reset_network_header(skb2);
 			}
 
@@ -1924,6 +1919,22 @@
 	}
 }
 
+/*
+ * Returns true if either:
+ *	1. skb has frag_list and the device doesn't support FRAGLIST, or
+ *	2. skb is fragmented and the device does not support SG, or if
+ *	   at least one of fragments is in highmem and device does not
+ *	   support DMA from it.
+ */
+static inline int skb_needs_linearize(struct sk_buff *skb,
+				      struct net_device *dev)
+{
+	return skb_is_nonlinear(skb) &&
+	       ((skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) ||
+	        (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) ||
+					      illegal_highdma(dev, skb))));
+}
+
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 			struct netdev_queue *txq)
 {
@@ -1948,6 +1959,22 @@
 				goto out_kfree_skb;
 			if (skb->next)
 				goto gso;
+		} else {
+			if (skb_needs_linearize(skb, dev) &&
+			    __skb_linearize(skb))
+				goto out_kfree_skb;
+
+			/* If packet is not checksummed and device does not
+			 * support checksumming for this protocol, complete
+			 * checksumming here.
+			 */
+			if (skb->ip_summed == CHECKSUM_PARTIAL) {
+				skb_set_transport_header(skb, skb->csum_start -
+					      skb_headroom(skb));
+				if (!dev_can_checksum(dev, skb) &&
+				     skb_checksum_help(skb))
+					goto out_kfree_skb;
+			}
 		}
 
 		rc = ops->ndo_start_xmit(skb, dev);
@@ -2063,14 +2090,24 @@
 				 struct netdev_queue *txq)
 {
 	spinlock_t *root_lock = qdisc_lock(q);
+	bool contended = qdisc_is_running(q);
 	int rc;
 
+	/*
+	 * Heuristic to force contended enqueues to serialize on a
+	 * separate lock before trying to get qdisc main lock.
+	 * This permits __QDISC_STATE_RUNNING owner to get the lock more often
+	 * and dequeue packets faster.
+	 */
+	if (unlikely(contended))
+		spin_lock(&q->busylock);
+
 	spin_lock(root_lock);
 	if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) {
 		kfree_skb(skb);
 		rc = NET_XMIT_DROP;
 	} else if ((q->flags & TCQ_F_CAN_BYPASS) && !qdisc_qlen(q) &&
-		   !test_and_set_bit(__QDISC_STATE_RUNNING, &q->state)) {
+		   qdisc_run_begin(q)) {
 		/*
 		 * This is a work-conserving queue; there are no old skbs
 		 * waiting to be sent out; and the qdisc is not running -
@@ -2079,37 +2116,33 @@
 		if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE))
 			skb_dst_force(skb);
 		__qdisc_update_bstats(q, skb->len);
-		if (sch_direct_xmit(skb, q, dev, txq, root_lock))
+		if (sch_direct_xmit(skb, q, dev, txq, root_lock)) {
+			if (unlikely(contended)) {
+				spin_unlock(&q->busylock);
+				contended = false;
+			}
 			__qdisc_run(q);
-		else
-			clear_bit(__QDISC_STATE_RUNNING, &q->state);
+		} else
+			qdisc_run_end(q);
 
 		rc = NET_XMIT_SUCCESS;
 	} else {
 		skb_dst_force(skb);
 		rc = qdisc_enqueue_root(skb, q);
-		qdisc_run(q);
+		if (qdisc_run_begin(q)) {
+			if (unlikely(contended)) {
+				spin_unlock(&q->busylock);
+				contended = false;
+			}
+			__qdisc_run(q);
+		}
 	}
 	spin_unlock(root_lock);
-
+	if (unlikely(contended))
+		spin_unlock(&q->busylock);
 	return rc;
 }
 
-/*
- * Returns true if either:
- *	1. skb has frag_list and the device doesn't support FRAGLIST, or
- *	2. skb is fragmented and the device does not support SG, or if
- *	   at least one of fragments is in highmem and device does not
- *	   support DMA from it.
- */
-static inline int skb_needs_linearize(struct sk_buff *skb,
-				      struct net_device *dev)
-{
-	return (skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) ||
-	       (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) ||
-					      illegal_highdma(dev, skb)));
-}
-
 /**
  *	dev_queue_xmit - transmit a buffer
  *	@skb: buffer to transmit
@@ -2142,25 +2175,6 @@
 	struct Qdisc *q;
 	int rc = -ENOMEM;
 
-	/* GSO will handle the following emulations directly. */
-	if (netif_needs_gso(dev, skb))
-		goto gso;
-
-	/* Convert a paged skb to linear, if required */
-	if (skb_needs_linearize(skb, dev) && __skb_linearize(skb))
-		goto out_kfree_skb;
-
-	/* If packet is not checksummed and device does not support
-	 * checksumming for this protocol, complete checksumming here.
-	 */
-	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		skb_set_transport_header(skb, skb->csum_start -
-					      skb_headroom(skb));
-		if (!dev_can_checksum(dev, skb) && skb_checksum_help(skb))
-			goto out_kfree_skb;
-	}
-
-gso:
 	/* Disable soft irqs for various locks below. Also
 	 * stops preemption for RCU.
 	 */
@@ -2219,7 +2233,6 @@
 	rc = -ENETDOWN;
 	rcu_read_unlock_bh();
 
-out_kfree_skb:
 	kfree_skb(skb);
 	return rc;
 out:
@@ -2604,70 +2617,14 @@
 	return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
 }
 
-#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE)
-
-#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+#if (defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)) && \
+    (defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE))
 /* This hook is defined here for ATM LANE */
 int (*br_fdb_test_addr_hook)(struct net_device *dev,
 			     unsigned char *addr) __read_mostly;
 EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook);
 #endif
 
-/*
- * If bridge module is loaded call bridging hook.
- *  returns NULL if packet was consumed.
- */
-struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p,
-					struct sk_buff *skb) __read_mostly;
-EXPORT_SYMBOL_GPL(br_handle_frame_hook);
-
-static inline struct sk_buff *handle_bridge(struct sk_buff *skb,
-					    struct packet_type **pt_prev, int *ret,
-					    struct net_device *orig_dev)
-{
-	struct net_bridge_port *port;
-
-	if (skb->pkt_type == PACKET_LOOPBACK ||
-	    (port = rcu_dereference(skb->dev->br_port)) == NULL)
-		return skb;
-
-	if (*pt_prev) {
-		*ret = deliver_skb(skb, *pt_prev, orig_dev);
-		*pt_prev = NULL;
-	}
-
-	return br_handle_frame_hook(port, skb);
-}
-#else
-#define handle_bridge(skb, pt_prev, ret, orig_dev)	(skb)
-#endif
-
-#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE)
-struct sk_buff *(*macvlan_handle_frame_hook)(struct macvlan_port *p,
-					     struct sk_buff *skb) __read_mostly;
-EXPORT_SYMBOL_GPL(macvlan_handle_frame_hook);
-
-static inline struct sk_buff *handle_macvlan(struct sk_buff *skb,
-					     struct packet_type **pt_prev,
-					     int *ret,
-					     struct net_device *orig_dev)
-{
-	struct macvlan_port *port;
-
-	port = rcu_dereference(skb->dev->macvlan_port);
-	if (!port)
-		return skb;
-
-	if (*pt_prev) {
-		*ret = deliver_skb(skb, *pt_prev, orig_dev);
-		*pt_prev = NULL;
-	}
-	return macvlan_handle_frame_hook(port, skb);
-}
-#else
-#define handle_macvlan(skb, pt_prev, ret, orig_dev)	(skb)
-#endif
-
 #ifdef CONFIG_NET_CLS_ACT
 /* TODO: Maybe we should just force sch_ingress to be compiled in
  * when CONFIG_NET_CLS_ACT is? otherwise some useless instructions
@@ -2685,10 +2642,10 @@
 	int result = TC_ACT_OK;
 	struct Qdisc *q;
 
-	if (MAX_RED_LOOP < ttl++) {
-		printk(KERN_WARNING
-		       "Redir loop detected Dropping packet (%d->%d)\n",
-		       skb->skb_iif, dev->ifindex);
+	if (unlikely(MAX_RED_LOOP < ttl++)) {
+		if (net_ratelimit())
+			pr_warning( "Redir loop detected Dropping packet (%d->%d)\n",
+			       skb->skb_iif, dev->ifindex);
 		return TC_ACT_SHOT;
 	}
 
@@ -2718,9 +2675,6 @@
 	if (*pt_prev) {
 		*ret = deliver_skb(skb, *pt_prev, orig_dev);
 		*pt_prev = NULL;
-	} else {
-		/* Huh? Why does turning on AF_PACKET affect this? */
-		skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
 	}
 
 	switch (ing_filter(skb)) {
@@ -2763,6 +2717,51 @@
 	rcu_read_unlock();
 }
 
+/**
+ *	netdev_rx_handler_register - register receive handler
+ *	@dev: device to register a handler for
+ *	@rx_handler: receive handler to register
+ *	@rx_handler_data: data pointer that is used by rx handler
+ *
+ *	Register a receive hander for a device. This handler will then be
+ *	called from __netif_receive_skb. A negative errno code is returned
+ *	on a failure.
+ *
+ *	The caller must hold the rtnl_mutex.
+ */
+int netdev_rx_handler_register(struct net_device *dev,
+			       rx_handler_func_t *rx_handler,
+			       void *rx_handler_data)
+{
+	ASSERT_RTNL();
+
+	if (dev->rx_handler)
+		return -EBUSY;
+
+	rcu_assign_pointer(dev->rx_handler_data, rx_handler_data);
+	rcu_assign_pointer(dev->rx_handler, rx_handler);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(netdev_rx_handler_register);
+
+/**
+ *	netdev_rx_handler_unregister - unregister receive handler
+ *	@dev: device to unregister a handler from
+ *
+ *	Unregister a receive hander from a device.
+ *
+ *	The caller must hold the rtnl_mutex.
+ */
+void netdev_rx_handler_unregister(struct net_device *dev)
+{
+
+	ASSERT_RTNL();
+	rcu_assign_pointer(dev->rx_handler, NULL);
+	rcu_assign_pointer(dev->rx_handler_data, NULL);
+}
+EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
+
 static inline void skb_bond_set_mac_by_master(struct sk_buff *skb,
 					      struct net_device *master)
 {
@@ -2784,7 +2783,8 @@
 	if (master->priv_flags & IFF_MASTER_ARPMON)
 		dev->last_rx = jiffies;
 
-	if ((master->priv_flags & IFF_MASTER_ALB) && master->br_port) {
+	if ((master->priv_flags & IFF_MASTER_ALB) &&
+	    (master->priv_flags & IFF_BRIDGE_PORT)) {
 		/* Do address unmangle. The local destination address
 		 * will be always the one master has. Provides the right
 		 * functionality in a bridge.
@@ -2815,6 +2815,7 @@
 static int __netif_receive_skb(struct sk_buff *skb)
 {
 	struct packet_type *ptype, *pt_prev;
+	rx_handler_func_t *rx_handler;
 	struct net_device *orig_dev;
 	struct net_device *master;
 	struct net_device *null_or_orig;
@@ -2856,8 +2857,7 @@
 			skb->dev = master;
 	}
 
-	__get_cpu_var(softnet_data).processed++;
-
+	__this_cpu_inc(softnet_data.processed);
 	skb_reset_network_header(skb);
 	skb_reset_transport_header(skb);
 	skb->mac_len = skb->network_header - skb->mac_header;
@@ -2889,12 +2889,17 @@
 ncls:
 #endif
 
-	skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
-	if (!skb)
-		goto out;
-	skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
-	if (!skb)
-		goto out;
+	/* Handle special case of bridge or macvlan */
+	rx_handler = rcu_dereference(skb->dev->rx_handler);
+	if (rx_handler) {
+		if (pt_prev) {
+			ret = deliver_skb(skb, pt_prev, orig_dev);
+			pt_prev = NULL;
+		}
+		skb = rx_handler(skb);
+		if (!skb)
+			goto out;
+	}
 
 	/*
 	 * Make sure frames received on VLAN interfaces stacked on
@@ -2955,6 +2960,9 @@
 	if (netdev_tstamp_prequeue)
 		net_timestamp_check(skb);
 
+	if (skb_defer_rx_timestamp(skb))
+		return NET_RX_SUCCESS;
+
 #ifdef CONFIG_RPS
 	{
 		struct rps_dev_flow voidflow, *rflow = &voidflow;
@@ -3719,10 +3727,11 @@
 
 static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
 {
-	const struct net_device_stats *stats = dev_get_stats(dev);
+	struct rtnl_link_stats64 temp;
+	const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
 
-	seq_printf(seq, "%6s: %7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
-		   "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
+	seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu "
+		   "%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n",
 		   dev->name, stats->rx_bytes, stats->rx_packets,
 		   stats->rx_errors,
 		   stats->rx_dropped + stats->rx_missed_errors,
@@ -5271,20 +5280,22 @@
 /**
  *	dev_txq_stats_fold - fold tx_queues stats
  *	@dev: device to get statistics from
- *	@stats: struct net_device_stats to hold results
+ *	@stats: struct rtnl_link_stats64 to hold results
  */
 void dev_txq_stats_fold(const struct net_device *dev,
-			struct net_device_stats *stats)
+			struct rtnl_link_stats64 *stats)
 {
-	unsigned long tx_bytes = 0, tx_packets = 0, tx_dropped = 0;
+	u64 tx_bytes = 0, tx_packets = 0, tx_dropped = 0;
 	unsigned int i;
 	struct netdev_queue *txq;
 
 	for (i = 0; i < dev->num_tx_queues; i++) {
 		txq = netdev_get_tx_queue(dev, i);
+		spin_lock_bh(&txq->_xmit_lock);
 		tx_bytes   += txq->tx_bytes;
 		tx_packets += txq->tx_packets;
 		tx_dropped += txq->tx_dropped;
+		spin_unlock_bh(&txq->_xmit_lock);
 	}
 	if (tx_bytes || tx_packets || tx_dropped) {
 		stats->tx_bytes   = tx_bytes;
@@ -5294,23 +5305,53 @@
 }
 EXPORT_SYMBOL(dev_txq_stats_fold);
 
+/* Convert net_device_stats to rtnl_link_stats64.  They have the same
+ * fields in the same order, with only the type differing.
+ */
+static void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
+				    const struct net_device_stats *netdev_stats)
+{
+#if BITS_PER_LONG == 64
+        BUILD_BUG_ON(sizeof(*stats64) != sizeof(*netdev_stats));
+        memcpy(stats64, netdev_stats, sizeof(*stats64));
+#else
+	size_t i, n = sizeof(*stats64) / sizeof(u64);
+	const unsigned long *src = (const unsigned long *)netdev_stats;
+	u64 *dst = (u64 *)stats64;
+
+	BUILD_BUG_ON(sizeof(*netdev_stats) / sizeof(unsigned long) !=
+		     sizeof(*stats64) / sizeof(u64));
+	for (i = 0; i < n; i++)
+		dst[i] = src[i];
+#endif
+}
+
 /**
  *	dev_get_stats	- get network device statistics
  *	@dev: device to get statistics from
+ *	@storage: place to store stats
  *
- *	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.
+ *	Get network statistics from device. Return @storage.
+ *	The device driver may provide its own method by setting
+ *	dev->netdev_ops->get_stats64 or dev->netdev_ops->get_stats;
+ *	otherwise the internal statistics structure is used.
  */
-const struct net_device_stats *dev_get_stats(struct net_device *dev)
+struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
+					struct rtnl_link_stats64 *storage)
 {
 	const struct net_device_ops *ops = dev->netdev_ops;
 
-	if (ops->ndo_get_stats)
-		return ops->ndo_get_stats(dev);
-
-	dev_txq_stats_fold(dev, &dev->stats);
-	return &dev->stats;
+	if (ops->ndo_get_stats64) {
+		memset(storage, 0, sizeof(*storage));
+		return ops->ndo_get_stats64(dev, storage);
+	}
+	if (ops->ndo_get_stats) {
+		netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev));
+		return storage;
+	}
+	netdev_stats_to_stats64(storage, &dev->stats);
+	dev_txq_stats_fold(dev, storage);
+	return storage;
 }
 EXPORT_SYMBOL(dev_get_stats);
 
@@ -5815,6 +5856,68 @@
 	return buffer;
 }
 
+static int __netdev_printk(const char *level, const struct net_device *dev,
+			   struct va_format *vaf)
+{
+	int r;
+
+	if (dev && dev->dev.parent)
+		r = dev_printk(level, dev->dev.parent, "%s: %pV",
+			       netdev_name(dev), vaf);
+	else if (dev)
+		r = printk("%s%s: %pV", level, netdev_name(dev), vaf);
+	else
+		r = printk("%s(NULL net_device): %pV", level, vaf);
+
+	return r;
+}
+
+int netdev_printk(const char *level, const struct net_device *dev,
+		  const char *format, ...)
+{
+	struct va_format vaf;
+	va_list args;
+	int r;
+
+	va_start(args, format);
+
+	vaf.fmt = format;
+	vaf.va = &args;
+
+	r = __netdev_printk(level, dev, &vaf);
+	va_end(args);
+
+	return r;
+}
+EXPORT_SYMBOL(netdev_printk);
+
+#define define_netdev_printk_level(func, level)			\
+int func(const struct net_device *dev, const char *fmt, ...)	\
+{								\
+	int r;							\
+	struct va_format vaf;					\
+	va_list args;						\
+								\
+	va_start(args, fmt);					\
+								\
+	vaf.fmt = fmt;						\
+	vaf.va = &args;						\
+								\
+	r = __netdev_printk(level, dev, &vaf);			\
+	va_end(args);						\
+								\
+	return r;						\
+}								\
+EXPORT_SYMBOL(func);
+
+define_netdev_printk_level(netdev_emerg, KERN_EMERG);
+define_netdev_printk_level(netdev_alert, KERN_ALERT);
+define_netdev_printk_level(netdev_crit, KERN_CRIT);
+define_netdev_printk_level(netdev_err, KERN_ERR);
+define_netdev_printk_level(netdev_warn, KERN_WARNING);
+define_netdev_printk_level(netdev_notice, KERN_NOTICE);
+define_netdev_printk_level(netdev_info, KERN_INFO);
+
 static void __net_exit netdev_exit(struct net *net)
 {
 	kfree(net->dev_name_head);
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
index ad41529..36e603c 100644
--- a/net/core/drop_monitor.c
+++ b/net/core/drop_monitor.c
@@ -223,6 +223,11 @@
 
 	spin_lock(&trace_state_lock);
 
+	if (state == trace_state) {
+		rc = -EAGAIN;
+		goto out_unlock;
+	}
+
 	switch (state) {
 	case TRACE_ON:
 		rc |= register_trace_kfree_skb(trace_kfree_skb_hit, NULL);
@@ -251,11 +256,12 @@
 
 	if (!rc)
 		trace_state = state;
+	else
+		rc = -EINPROGRESS;
 
+out_unlock:
 	spin_unlock(&trace_state_lock);
 
-	if (rc)
-		return -EINPROGRESS;
 	return rc;
 }
 
@@ -341,9 +347,9 @@
 
 static int __init init_net_drop_monitor(void)
 {
-	int cpu;
-	int rc, i, ret;
 	struct per_cpu_dm_data *data;
+	int cpu, rc;
+
 	printk(KERN_INFO "Initalizing network drop monitor service\n");
 
 	if (sizeof(void *) > 8) {
@@ -351,21 +357,12 @@
 		return -ENOSPC;
 	}
 
-	if (genl_register_family(&net_drop_monitor_family) < 0) {
+	rc = genl_register_family_with_ops(&net_drop_monitor_family,
+					   dropmon_ops,
+					   ARRAY_SIZE(dropmon_ops));
+	if (rc) {
 		printk(KERN_ERR "Could not create drop monitor netlink family\n");
-		return -EFAULT;
-	}
-
-	rc = -EFAULT;
-
-	for (i = 0; i < ARRAY_SIZE(dropmon_ops); i++) {
-		ret = genl_register_ops(&net_drop_monitor_family,
-					&dropmon_ops[i]);
-		if (ret) {
-			printk(KERN_CRIT "Failed to register operation %d\n",
-				dropmon_ops[i].cmd);
-			goto out_unreg;
-		}
+		return rc;
 	}
 
 	rc = register_netdevice_notifier(&dropmon_net_notifier);
diff --git a/net/core/dst.c b/net/core/dst.c
index 9920722..6c41b1f 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -197,7 +197,6 @@
 		dst->input = dst->output = dst_discard;
 	dst->obsolete = 2;
 }
-EXPORT_SYMBOL(__dst_free);
 
 void __dst_free(struct dst_entry *dst)
 {
@@ -213,6 +212,7 @@
 	}
 	spin_unlock_bh(&dst_garbage.lock);
 }
+EXPORT_SYMBOL(__dst_free);
 
 struct dst_entry *dst_destroy(struct dst_entry * dst)
 {
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 75e4ffe..7a85367 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -144,31 +144,13 @@
 }
 EXPORT_SYMBOL(ethtool_op_get_flags);
 
-int ethtool_op_set_flags(struct net_device *dev, u32 data)
+int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported)
 {
-	const struct ethtool_ops *ops = dev->ethtool_ops;
-	unsigned long features = dev->features;
+	if (data & ~supported)
+		return -EINVAL;
 
-	if (data & ETH_FLAG_LRO)
-		features |= NETIF_F_LRO;
-	else
-		features &= ~NETIF_F_LRO;
-
-	if (data & ETH_FLAG_NTUPLE) {
-		if (!ops->set_rx_ntuple)
-			return -EOPNOTSUPP;
-		features |= NETIF_F_NTUPLE;
-	} else {
-		/* safe to clear regardless */
-		features &= ~NETIF_F_NTUPLE;
-	}
-
-	if (data & ETH_FLAG_RXHASH)
-		features |= NETIF_F_RXHASH;
-	else
-		features &= ~NETIF_F_RXHASH;
-
-	dev->features = features;
+	dev->features = ((dev->features & ~flags_dup_features) |
+			 (data & flags_dup_features));
 	return 0;
 }
 EXPORT_SYMBOL(ethtool_op_set_flags);
@@ -395,6 +377,80 @@
 	return ret;
 }
 
+static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
+						     void __user *useraddr)
+{
+	struct ethtool_rxfh_indir *indir;
+	u32 table_size;
+	size_t full_size;
+	int ret;
+
+	if (!dev->ethtool_ops->get_rxfh_indir)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&table_size,
+			   useraddr + offsetof(struct ethtool_rxfh_indir, size),
+			   sizeof(table_size)))
+		return -EFAULT;
+
+	if (table_size >
+	    (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index))
+		return -ENOMEM;
+	full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size;
+	indir = kmalloc(full_size, GFP_USER);
+	if (!indir)
+		return -ENOMEM;
+
+	indir->cmd = ETHTOOL_GRXFHINDIR;
+	indir->size = table_size;
+	ret = dev->ethtool_ops->get_rxfh_indir(dev, indir);
+	if (ret)
+		goto out;
+
+	if (copy_to_user(useraddr, indir, full_size))
+		ret = -EFAULT;
+
+out:
+	kfree(indir);
+	return ret;
+}
+
+static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
+						     void __user *useraddr)
+{
+	struct ethtool_rxfh_indir *indir;
+	u32 table_size;
+	size_t full_size;
+	int ret;
+
+	if (!dev->ethtool_ops->set_rxfh_indir)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&table_size,
+			   useraddr + offsetof(struct ethtool_rxfh_indir, size),
+			   sizeof(table_size)))
+		return -EFAULT;
+
+	if (table_size >
+	    (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index))
+		return -ENOMEM;
+	full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size;
+	indir = kmalloc(full_size, GFP_USER);
+	if (!indir)
+		return -ENOMEM;
+
+	if (copy_from_user(indir, useraddr, full_size)) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	ret = dev->ethtool_ops->set_rxfh_indir(dev, indir);
+
+out:
+	kfree(indir);
+	return ret;
+}
+
 static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,
 			struct ethtool_rx_ntuple_flow_spec *spec,
 			struct ethtool_rx_ntuple_flow_spec_container *fsc)
@@ -1563,6 +1619,12 @@
 	case ETHTOOL_GSSET_INFO:
 		rc = ethtool_get_sset_info(dev, useraddr);
 		break;
+	case ETHTOOL_GRXFHINDIR:
+		rc = ethtool_get_rxfh_indir(dev, useraddr);
+		break;
+	case ETHTOOL_SRXFHINDIR:
+		rc = ethtool_set_rxfh_indir(dev, useraddr);
+		break;
 	default:
 		rc = -EOPNOTSUPP;
 	}
diff --git a/net/core/filter.c b/net/core/filter.c
index da69fb7..52b051f 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -128,87 +128,87 @@
 		fentry = &filter[pc];
 
 		switch (fentry->code) {
-		case BPF_ALU|BPF_ADD|BPF_X:
+		case BPF_S_ALU_ADD_X:
 			A += X;
 			continue;
-		case BPF_ALU|BPF_ADD|BPF_K:
+		case BPF_S_ALU_ADD_K:
 			A += fentry->k;
 			continue;
-		case BPF_ALU|BPF_SUB|BPF_X:
+		case BPF_S_ALU_SUB_X:
 			A -= X;
 			continue;
-		case BPF_ALU|BPF_SUB|BPF_K:
+		case BPF_S_ALU_SUB_K:
 			A -= fentry->k;
 			continue;
-		case BPF_ALU|BPF_MUL|BPF_X:
+		case BPF_S_ALU_MUL_X:
 			A *= X;
 			continue;
-		case BPF_ALU|BPF_MUL|BPF_K:
+		case BPF_S_ALU_MUL_K:
 			A *= fentry->k;
 			continue;
-		case BPF_ALU|BPF_DIV|BPF_X:
+		case BPF_S_ALU_DIV_X:
 			if (X == 0)
 				return 0;
 			A /= X;
 			continue;
-		case BPF_ALU|BPF_DIV|BPF_K:
+		case BPF_S_ALU_DIV_K:
 			A /= fentry->k;
 			continue;
-		case BPF_ALU|BPF_AND|BPF_X:
+		case BPF_S_ALU_AND_X:
 			A &= X;
 			continue;
-		case BPF_ALU|BPF_AND|BPF_K:
+		case BPF_S_ALU_AND_K:
 			A &= fentry->k;
 			continue;
-		case BPF_ALU|BPF_OR|BPF_X:
+		case BPF_S_ALU_OR_X:
 			A |= X;
 			continue;
-		case BPF_ALU|BPF_OR|BPF_K:
+		case BPF_S_ALU_OR_K:
 			A |= fentry->k;
 			continue;
-		case BPF_ALU|BPF_LSH|BPF_X:
+		case BPF_S_ALU_LSH_X:
 			A <<= X;
 			continue;
-		case BPF_ALU|BPF_LSH|BPF_K:
+		case BPF_S_ALU_LSH_K:
 			A <<= fentry->k;
 			continue;
-		case BPF_ALU|BPF_RSH|BPF_X:
+		case BPF_S_ALU_RSH_X:
 			A >>= X;
 			continue;
-		case BPF_ALU|BPF_RSH|BPF_K:
+		case BPF_S_ALU_RSH_K:
 			A >>= fentry->k;
 			continue;
-		case BPF_ALU|BPF_NEG:
+		case BPF_S_ALU_NEG:
 			A = -A;
 			continue;
-		case BPF_JMP|BPF_JA:
+		case BPF_S_JMP_JA:
 			pc += fentry->k;
 			continue;
-		case BPF_JMP|BPF_JGT|BPF_K:
+		case BPF_S_JMP_JGT_K:
 			pc += (A > fentry->k) ? fentry->jt : fentry->jf;
 			continue;
-		case BPF_JMP|BPF_JGE|BPF_K:
+		case BPF_S_JMP_JGE_K:
 			pc += (A >= fentry->k) ? fentry->jt : fentry->jf;
 			continue;
-		case BPF_JMP|BPF_JEQ|BPF_K:
+		case BPF_S_JMP_JEQ_K:
 			pc += (A == fentry->k) ? fentry->jt : fentry->jf;
 			continue;
-		case BPF_JMP|BPF_JSET|BPF_K:
+		case BPF_S_JMP_JSET_K:
 			pc += (A & fentry->k) ? fentry->jt : fentry->jf;
 			continue;
-		case BPF_JMP|BPF_JGT|BPF_X:
+		case BPF_S_JMP_JGT_X:
 			pc += (A > X) ? fentry->jt : fentry->jf;
 			continue;
-		case BPF_JMP|BPF_JGE|BPF_X:
+		case BPF_S_JMP_JGE_X:
 			pc += (A >= X) ? fentry->jt : fentry->jf;
 			continue;
-		case BPF_JMP|BPF_JEQ|BPF_X:
+		case BPF_S_JMP_JEQ_X:
 			pc += (A == X) ? fentry->jt : fentry->jf;
 			continue;
-		case BPF_JMP|BPF_JSET|BPF_X:
+		case BPF_S_JMP_JSET_X:
 			pc += (A & X) ? fentry->jt : fentry->jf;
 			continue;
-		case BPF_LD|BPF_W|BPF_ABS:
+		case BPF_S_LD_W_ABS:
 			k = fentry->k;
 load_w:
 			ptr = load_pointer(skb, k, 4, &tmp);
@@ -217,7 +217,7 @@
 				continue;
 			}
 			break;
-		case BPF_LD|BPF_H|BPF_ABS:
+		case BPF_S_LD_H_ABS:
 			k = fentry->k;
 load_h:
 			ptr = load_pointer(skb, k, 2, &tmp);
@@ -226,7 +226,7 @@
 				continue;
 			}
 			break;
-		case BPF_LD|BPF_B|BPF_ABS:
+		case BPF_S_LD_B_ABS:
 			k = fentry->k;
 load_b:
 			ptr = load_pointer(skb, k, 1, &tmp);
@@ -235,54 +235,54 @@
 				continue;
 			}
 			break;
-		case BPF_LD|BPF_W|BPF_LEN:
+		case BPF_S_LD_W_LEN:
 			A = skb->len;
 			continue;
-		case BPF_LDX|BPF_W|BPF_LEN:
+		case BPF_S_LDX_W_LEN:
 			X = skb->len;
 			continue;
-		case BPF_LD|BPF_W|BPF_IND:
+		case BPF_S_LD_W_IND:
 			k = X + fentry->k;
 			goto load_w;
-		case BPF_LD|BPF_H|BPF_IND:
+		case BPF_S_LD_H_IND:
 			k = X + fentry->k;
 			goto load_h;
-		case BPF_LD|BPF_B|BPF_IND:
+		case BPF_S_LD_B_IND:
 			k = X + fentry->k;
 			goto load_b;
-		case BPF_LDX|BPF_B|BPF_MSH:
+		case BPF_S_LDX_B_MSH:
 			ptr = load_pointer(skb, fentry->k, 1, &tmp);
 			if (ptr != NULL) {
 				X = (*(u8 *)ptr & 0xf) << 2;
 				continue;
 			}
 			return 0;
-		case BPF_LD|BPF_IMM:
+		case BPF_S_LD_IMM:
 			A = fentry->k;
 			continue;
-		case BPF_LDX|BPF_IMM:
+		case BPF_S_LDX_IMM:
 			X = fentry->k;
 			continue;
-		case BPF_LD|BPF_MEM:
+		case BPF_S_LD_MEM:
 			A = mem[fentry->k];
 			continue;
-		case BPF_LDX|BPF_MEM:
+		case BPF_S_LDX_MEM:
 			X = mem[fentry->k];
 			continue;
-		case BPF_MISC|BPF_TAX:
+		case BPF_S_MISC_TAX:
 			X = A;
 			continue;
-		case BPF_MISC|BPF_TXA:
+		case BPF_S_MISC_TXA:
 			A = X;
 			continue;
-		case BPF_RET|BPF_K:
+		case BPF_S_RET_K:
 			return fentry->k;
-		case BPF_RET|BPF_A:
+		case BPF_S_RET_A:
 			return A;
-		case BPF_ST:
+		case BPF_S_ST:
 			mem[fentry->k] = A;
 			continue;
-		case BPF_STX:
+		case BPF_S_STX:
 			mem[fentry->k] = X;
 			continue;
 		default:
@@ -390,53 +390,128 @@
 		/* Only allow valid instructions */
 		switch (ftest->code) {
 		case BPF_ALU|BPF_ADD|BPF_K:
+			ftest->code = BPF_S_ALU_ADD_K;
+			break;
 		case BPF_ALU|BPF_ADD|BPF_X:
+			ftest->code = BPF_S_ALU_ADD_X;
+			break;
 		case BPF_ALU|BPF_SUB|BPF_K:
+			ftest->code = BPF_S_ALU_SUB_K;
+			break;
 		case BPF_ALU|BPF_SUB|BPF_X:
+			ftest->code = BPF_S_ALU_SUB_X;
+			break;
 		case BPF_ALU|BPF_MUL|BPF_K:
+			ftest->code = BPF_S_ALU_MUL_K;
+			break;
 		case BPF_ALU|BPF_MUL|BPF_X:
+			ftest->code = BPF_S_ALU_MUL_X;
+			break;
 		case BPF_ALU|BPF_DIV|BPF_X:
+			ftest->code = BPF_S_ALU_DIV_X;
+			break;
 		case BPF_ALU|BPF_AND|BPF_K:
+			ftest->code = BPF_S_ALU_AND_K;
+			break;
 		case BPF_ALU|BPF_AND|BPF_X:
+			ftest->code = BPF_S_ALU_AND_X;
+			break;
 		case BPF_ALU|BPF_OR|BPF_K:
+			ftest->code = BPF_S_ALU_OR_K;
+			break;
 		case BPF_ALU|BPF_OR|BPF_X:
+			ftest->code = BPF_S_ALU_OR_X;
+			break;
 		case BPF_ALU|BPF_LSH|BPF_K:
+			ftest->code = BPF_S_ALU_LSH_K;
+			break;
 		case BPF_ALU|BPF_LSH|BPF_X:
+			ftest->code = BPF_S_ALU_LSH_X;
+			break;
 		case BPF_ALU|BPF_RSH|BPF_K:
+			ftest->code = BPF_S_ALU_RSH_K;
+			break;
 		case BPF_ALU|BPF_RSH|BPF_X:
+			ftest->code = BPF_S_ALU_RSH_X;
+			break;
 		case BPF_ALU|BPF_NEG:
+			ftest->code = BPF_S_ALU_NEG;
+			break;
 		case BPF_LD|BPF_W|BPF_ABS:
+			ftest->code = BPF_S_LD_W_ABS;
+			break;
 		case BPF_LD|BPF_H|BPF_ABS:
+			ftest->code = BPF_S_LD_H_ABS;
+			break;
 		case BPF_LD|BPF_B|BPF_ABS:
+			ftest->code = BPF_S_LD_B_ABS;
+			break;
 		case BPF_LD|BPF_W|BPF_LEN:
+			ftest->code = BPF_S_LD_W_LEN;
+			break;
 		case BPF_LD|BPF_W|BPF_IND:
+			ftest->code = BPF_S_LD_W_IND;
+			break;
 		case BPF_LD|BPF_H|BPF_IND:
+			ftest->code = BPF_S_LD_H_IND;
+			break;
 		case BPF_LD|BPF_B|BPF_IND:
+			ftest->code = BPF_S_LD_B_IND;
+			break;
 		case BPF_LD|BPF_IMM:
+			ftest->code = BPF_S_LD_IMM;
+			break;
 		case BPF_LDX|BPF_W|BPF_LEN:
+			ftest->code = BPF_S_LDX_W_LEN;
+			break;
 		case BPF_LDX|BPF_B|BPF_MSH:
+			ftest->code = BPF_S_LDX_B_MSH;
+			break;
 		case BPF_LDX|BPF_IMM:
+			ftest->code = BPF_S_LDX_IMM;
+			break;
 		case BPF_MISC|BPF_TAX:
+			ftest->code = BPF_S_MISC_TAX;
+			break;
 		case BPF_MISC|BPF_TXA:
+			ftest->code = BPF_S_MISC_TXA;
+			break;
 		case BPF_RET|BPF_K:
+			ftest->code = BPF_S_RET_K;
+			break;
 		case BPF_RET|BPF_A:
+			ftest->code = BPF_S_RET_A;
 			break;
 
 		/* Some instructions need special checks */
 
-		case BPF_ALU|BPF_DIV|BPF_K:
 			/* check for division by zero */
+		case BPF_ALU|BPF_DIV|BPF_K:
 			if (ftest->k == 0)
 				return -EINVAL;
+			ftest->code = BPF_S_ALU_DIV_K;
 			break;
 
+		/* check for invalid memory addresses */
 		case BPF_LD|BPF_MEM:
-		case BPF_LDX|BPF_MEM:
-		case BPF_ST:
-		case BPF_STX:
-			/* check for invalid memory addresses */
 			if (ftest->k >= BPF_MEMWORDS)
 				return -EINVAL;
+			ftest->code = BPF_S_LD_MEM;
+			break;
+		case BPF_LDX|BPF_MEM:
+			if (ftest->k >= BPF_MEMWORDS)
+				return -EINVAL;
+			ftest->code = BPF_S_LDX_MEM;
+			break;
+		case BPF_ST:
+			if (ftest->k >= BPF_MEMWORDS)
+				return -EINVAL;
+			ftest->code = BPF_S_ST;
+			break;
+		case BPF_STX:
+			if (ftest->k >= BPF_MEMWORDS)
+				return -EINVAL;
+			ftest->code = BPF_S_STX;
 			break;
 
 		case BPF_JMP|BPF_JA:
@@ -447,28 +522,63 @@
 			 */
 			if (ftest->k >= (unsigned)(flen-pc-1))
 				return -EINVAL;
+			ftest->code = BPF_S_JMP_JA;
 			break;
 
 		case BPF_JMP|BPF_JEQ|BPF_K:
+			ftest->code = BPF_S_JMP_JEQ_K;
+			break;
 		case BPF_JMP|BPF_JEQ|BPF_X:
+			ftest->code = BPF_S_JMP_JEQ_X;
+			break;
 		case BPF_JMP|BPF_JGE|BPF_K:
+			ftest->code = BPF_S_JMP_JGE_K;
+			break;
 		case BPF_JMP|BPF_JGE|BPF_X:
+			ftest->code = BPF_S_JMP_JGE_X;
+			break;
 		case BPF_JMP|BPF_JGT|BPF_K:
+			ftest->code = BPF_S_JMP_JGT_K;
+			break;
 		case BPF_JMP|BPF_JGT|BPF_X:
+			ftest->code = BPF_S_JMP_JGT_X;
+			break;
 		case BPF_JMP|BPF_JSET|BPF_K:
+			ftest->code = BPF_S_JMP_JSET_K;
+			break;
 		case BPF_JMP|BPF_JSET|BPF_X:
-			/* for conditionals both must be safe */
-			if (pc + ftest->jt + 1 >= flen ||
-			    pc + ftest->jf + 1 >= flen)
-				return -EINVAL;
+			ftest->code = BPF_S_JMP_JSET_X;
 			break;
 
 		default:
 			return -EINVAL;
 		}
+
+			/* for conditionals both must be safe */
+		switch (ftest->code) {
+		case BPF_S_JMP_JEQ_K:
+		case BPF_S_JMP_JEQ_X:
+		case BPF_S_JMP_JGE_K:
+		case BPF_S_JMP_JGE_X:
+		case BPF_S_JMP_JGT_K:
+		case BPF_S_JMP_JGT_X:
+		case BPF_S_JMP_JSET_X:
+		case BPF_S_JMP_JSET_K:
+			if (pc + ftest->jt + 1 >= flen ||
+			    pc + ftest->jf + 1 >= flen)
+				return -EINVAL;
+		}
 	}
 
-	return (BPF_CLASS(filter[flen - 1].code) == BPF_RET) ? 0 : -EINVAL;
+	/* last instruction must be a RET code */
+	switch (filter[flen - 1].code) {
+	case BPF_S_RET_K:
+	case BPF_S_RET_A:
+		return 0;
+		break;
+		default:
+			return -EINVAL;
+		}
 }
 EXPORT_SYMBOL(sk_chk_filter);
 
diff --git a/net/core/flow.c b/net/core/flow.c
index 1619006..f67dcbf 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -62,6 +62,7 @@
 };
 
 atomic_t flow_cache_genid = ATOMIC_INIT(0);
+EXPORT_SYMBOL(flow_cache_genid);
 static struct flow_cache flow_cache_global;
 static struct kmem_cache *flow_cachep;
 
@@ -222,7 +223,7 @@
 	unsigned int hash;
 
 	local_bh_disable();
-	fcp = per_cpu_ptr(fc->percpu, smp_processor_id());
+	fcp = this_cpu_ptr(fc->percpu);
 
 	fle = NULL;
 	flo = NULL;
@@ -291,6 +292,7 @@
 	local_bh_enable();
 	return flo;
 }
+EXPORT_SYMBOL(flow_cache_lookup);
 
 static void flow_cache_flush_tasklet(unsigned long data)
 {
@@ -302,7 +304,7 @@
 	LIST_HEAD(gc_list);
 	int i, deleted = 0;
 
-	fcp = per_cpu_ptr(fc->percpu, smp_processor_id());
+	fcp = this_cpu_ptr(fc->percpu);
 	for (i = 0; i < flow_cache_hash_size(fc); i++) {
 		hlist_for_each_entry_safe(fle, entry, tmp,
 					  &fcp->hash_table[i], u.hlist) {
@@ -424,6 +426,3 @@
 }
 
 module_init(flow_cache_init_global);
-
-EXPORT_SYMBOL(flow_cache_genid);
-EXPORT_SYMBOL(flow_cache_lookup);
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
index 785e527..9fbe7f7 100644
--- a/net/core/gen_estimator.c
+++ b/net/core/gen_estimator.c
@@ -263,6 +263,7 @@
  *
  * Removes the rate estimator specified by &bstats and &rate_est.
  *
+ * Note : Caller should respect an RCU grace period before freeing stats_lock
  */
 void gen_kill_estimator(struct gnet_stats_basic_packed *bstats,
 			struct gnet_stats_rate_est *rate_est)
diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c
index 393b1d8..0452eb2 100644
--- a/net/core/gen_stats.c
+++ b/net/core/gen_stats.c
@@ -73,6 +73,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(gnet_stats_start_copy_compat);
 
 /**
  * gnet_stats_start_copy_compat - start dumping procedure in compatibility mode
@@ -93,6 +94,7 @@
 {
 	return gnet_stats_start_copy_compat(skb, type, 0, 0, lock, d);
 }
+EXPORT_SYMBOL(gnet_stats_start_copy);
 
 /**
  * gnet_stats_copy_basic - copy basic statistics into statistic TLV
@@ -123,6 +125,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL(gnet_stats_copy_basic);
 
 /**
  * gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV
@@ -154,6 +157,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(gnet_stats_copy_rate_est);
 
 /**
  * gnet_stats_copy_queue - copy queue statistics into statistics TLV
@@ -181,6 +185,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(gnet_stats_copy_queue);
 
 /**
  * gnet_stats_copy_app - copy application specific statistics into statistics TLV
@@ -208,6 +213,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(gnet_stats_copy_app);
 
 /**
  * gnet_stats_finish_copy - finish dumping procedure
@@ -241,12 +247,4 @@
 	spin_unlock_bh(d->lock);
 	return 0;
 }
-
-
-EXPORT_SYMBOL(gnet_stats_start_copy);
-EXPORT_SYMBOL(gnet_stats_start_copy_compat);
-EXPORT_SYMBOL(gnet_stats_copy_basic);
-EXPORT_SYMBOL(gnet_stats_copy_rate_est);
-EXPORT_SYMBOL(gnet_stats_copy_queue);
-EXPORT_SYMBOL(gnet_stats_copy_app);
 EXPORT_SYMBOL(gnet_stats_finish_copy);
diff --git a/net/core/iovec.c b/net/core/iovec.c
index 1e7f4e9..1cd98df 100644
--- a/net/core/iovec.c
+++ b/net/core/iovec.c
@@ -95,6 +95,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(memcpy_toiovec);
 
 /*
  *	Copy kernel to iovec. Returns -EFAULT on error.
@@ -120,6 +121,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(memcpy_toiovecend);
 
 /*
  *	Copy iovec to kernel. Returns -EFAULT on error.
@@ -144,6 +146,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(memcpy_fromiovec);
 
 /*
  *	Copy iovec from kernel. Returns -EFAULT on error.
@@ -172,6 +175,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(memcpy_fromiovecend);
 
 /*
  *	And now for the all-in-one: copy and checksum from a user iovec
@@ -256,9 +260,4 @@
 	err = -EFAULT;
 	goto out;
 }
-
 EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
-EXPORT_SYMBOL(memcpy_fromiovec);
-EXPORT_SYMBOL(memcpy_fromiovecend);
-EXPORT_SYMBOL(memcpy_toiovec);
-EXPORT_SYMBOL(memcpy_toiovecend);
diff --git a/net/core/link_watch.c b/net/core/link_watch.c
index bdbce2f..01a1101 100644
--- a/net/core/link_watch.c
+++ b/net/core/link_watch.c
@@ -243,5 +243,4 @@
 
 	linkwatch_schedule_work(urgent);
 }
-
 EXPORT_SYMBOL(linkwatch_fire_event);
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 99e7052..af4dfba 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -29,6 +29,7 @@
 static const char fmt_long_hex[] = "%#lx\n";
 static const char fmt_dec[] = "%d\n";
 static const char fmt_ulong[] = "%lu\n";
+static const char fmt_u64[] = "%llu\n";
 
 static inline int dev_isalive(const struct net_device *dev)
 {
@@ -94,6 +95,7 @@
 }
 
 NETDEVICE_SHOW(dev_id, fmt_hex);
+NETDEVICE_SHOW(addr_assign_type, fmt_dec);
 NETDEVICE_SHOW(addr_len, fmt_dec);
 NETDEVICE_SHOW(iflink, fmt_dec);
 NETDEVICE_SHOW(ifindex, fmt_dec);
@@ -294,6 +296,7 @@
 }
 
 static struct device_attribute net_class_attributes[] = {
+	__ATTR(addr_assign_type, S_IRUGO, show_addr_assign_type, NULL),
 	__ATTR(addr_len, S_IRUGO, show_addr_len, NULL),
 	__ATTR(dev_id, S_IRUGO, show_dev_id, NULL),
 	__ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias),
@@ -324,14 +327,15 @@
 	struct net_device *dev = to_net_dev(d);
 	ssize_t ret = -EINVAL;
 
-	WARN_ON(offset > sizeof(struct net_device_stats) ||
-			offset % sizeof(unsigned long) != 0);
+	WARN_ON(offset > sizeof(struct rtnl_link_stats64) ||
+			offset % sizeof(u64) != 0);
 
 	read_lock(&dev_base_lock);
 	if (dev_isalive(dev)) {
-		const struct net_device_stats *stats = dev_get_stats(dev);
-		ret = sprintf(buf, fmt_ulong,
-			      *(unsigned long *)(((u8 *) stats) + offset));
+		struct rtnl_link_stats64 temp;
+		const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
+
+		ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *) stats) + offset));
 	}
 	read_unlock(&dev_base_lock);
 	return ret;
@@ -343,7 +347,7 @@
 			   struct device_attribute *attr, char *buf) 	\
 {									\
 	return netstat_show(d, attr, buf,				\
-			    offsetof(struct net_device_stats, name));	\
+			    offsetof(struct rtnl_link_stats64, name));	\
 }									\
 static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
 
@@ -922,13 +926,12 @@
 {
 	return class_create_file(&net_class, class_attr);
 }
+EXPORT_SYMBOL(netdev_class_create_file);
 
 void netdev_class_remove_file(struct class_attribute *class_attr)
 {
 	class_remove_file(&net_class, class_attr);
 }
-
-EXPORT_SYMBOL(netdev_class_create_file);
 EXPORT_SYMBOL(netdev_class_remove_file);
 
 int netdev_kobject_init(void)
diff --git a/net/core/netevent.c b/net/core/netevent.c
index 95f81de..865f0ce 100644
--- a/net/core/netevent.c
+++ b/net/core/netevent.c
@@ -35,6 +35,7 @@
 	err = atomic_notifier_chain_register(&netevent_notif_chain, nb);
 	return err;
 }
+EXPORT_SYMBOL_GPL(register_netevent_notifier);
 
 /**
  *	netevent_unregister_notifier - unregister a netevent notifier block
@@ -50,6 +51,7 @@
 {
 	return atomic_notifier_chain_unregister(&netevent_notif_chain, nb);
 }
+EXPORT_SYMBOL_GPL(unregister_netevent_notifier);
 
 /**
  *	call_netevent_notifiers - call all netevent notifier blocks
@@ -64,7 +66,4 @@
 {
 	return atomic_notifier_call_chain(&netevent_notif_chain, val, v);
 }
-
-EXPORT_SYMBOL_GPL(register_netevent_notifier);
-EXPORT_SYMBOL_GPL(unregister_netevent_notifier);
 EXPORT_SYMBOL_GPL(call_netevent_notifiers);
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 94825b1..537e01a 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -199,11 +199,13 @@
 
 	zap_completion_queue();
 }
+EXPORT_SYMBOL(netpoll_poll_dev);
 
 void netpoll_poll(struct netpoll *np)
 {
 	netpoll_poll_dev(np->dev);
 }
+EXPORT_SYMBOL(netpoll_poll);
 
 static void refill_skbs(void)
 {
@@ -292,6 +294,7 @@
 	unsigned long tries;
 	struct net_device *dev = np->dev;
 	const struct net_device_ops *ops = dev->netdev_ops;
+	/* It is up to the caller to keep npinfo alive. */
 	struct netpoll_info *npinfo = np->dev->npinfo;
 
 	if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) {
@@ -343,6 +346,7 @@
 		schedule_delayed_work(&npinfo->tx_work,0);
 	}
 }
+EXPORT_SYMBOL(netpoll_send_skb);
 
 void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 {
@@ -404,6 +408,7 @@
 
 	netpoll_send_skb(np, skb);
 }
+EXPORT_SYMBOL(netpoll_send_udp);
 
 static void arp_reply(struct sk_buff *skb)
 {
@@ -630,6 +635,7 @@
 	printk(KERN_INFO "%s: remote ethernet address %pM\n",
 	                 np->name, np->remote_mac);
 }
+EXPORT_SYMBOL(netpoll_print_options);
 
 int netpoll_parse_options(struct netpoll *np, char *opt)
 {
@@ -722,30 +728,29 @@
 	       np->name, cur);
 	return -1;
 }
+EXPORT_SYMBOL(netpoll_parse_options);
 
-int netpoll_setup(struct netpoll *np)
+int __netpoll_setup(struct netpoll *np)
 {
-	struct net_device *ndev = NULL;
-	struct in_device *in_dev;
+	struct net_device *ndev = np->dev;
 	struct netpoll_info *npinfo;
-	struct netpoll *npe, *tmp;
+	const struct net_device_ops *ops;
 	unsigned long flags;
 	int err;
 
-	if (np->dev_name)
-		ndev = dev_get_by_name(&init_net, np->dev_name);
-	if (!ndev) {
-		printk(KERN_ERR "%s: %s doesn't exist, aborting.\n",
+	if ((ndev->priv_flags & IFF_DISABLE_NETPOLL) ||
+	    !ndev->netdev_ops->ndo_poll_controller) {
+		printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
 		       np->name, np->dev_name);
-		return -ENODEV;
+		err = -ENOTSUPP;
+		goto out;
 	}
 
-	np->dev = ndev;
 	if (!ndev->npinfo) {
 		npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
 		if (!npinfo) {
 			err = -ENOMEM;
-			goto put;
+			goto out;
 		}
 
 		npinfo->rx_flags = 0;
@@ -757,6 +762,13 @@
 		INIT_DELAYED_WORK(&npinfo->tx_work, queue_process);
 
 		atomic_set(&npinfo->refcnt, 1);
+
+		ops = np->dev->netdev_ops;
+		if (ops->ndo_netpoll_setup) {
+			err = ops->ndo_netpoll_setup(ndev, npinfo);
+			if (err)
+				goto free_npinfo;
+		}
 	} else {
 		npinfo = ndev->npinfo;
 		atomic_inc(&npinfo->refcnt);
@@ -764,12 +776,37 @@
 
 	npinfo->netpoll = np;
 
-	if ((ndev->priv_flags & IFF_DISABLE_NETPOLL) ||
-	    !ndev->netdev_ops->ndo_poll_controller) {
-		printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
+	if (np->rx_hook) {
+		spin_lock_irqsave(&npinfo->rx_lock, flags);
+		npinfo->rx_flags |= NETPOLL_RX_ENABLED;
+		list_add_tail(&np->rx, &npinfo->rx_np);
+		spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+	}
+
+	/* last thing to do is link it to the net device structure */
+	rcu_assign_pointer(ndev->npinfo, npinfo);
+
+	return 0;
+
+free_npinfo:
+	kfree(npinfo);
+out:
+	return err;
+}
+EXPORT_SYMBOL_GPL(__netpoll_setup);
+
+int netpoll_setup(struct netpoll *np)
+{
+	struct net_device *ndev = NULL;
+	struct in_device *in_dev;
+	int err;
+
+	if (np->dev_name)
+		ndev = dev_get_by_name(&init_net, np->dev_name);
+	if (!ndev) {
+		printk(KERN_ERR "%s: %s doesn't exist, aborting.\n",
 		       np->name, np->dev_name);
-		err = -ENOTSUPP;
-		goto release;
+		return -ENODEV;
 	}
 
 	if (!netif_running(ndev)) {
@@ -785,7 +822,7 @@
 		if (err) {
 			printk(KERN_ERR "%s: failed to open %s\n",
 			       np->name, ndev->name);
-			goto release;
+			goto put;
 		}
 
 		atleast = jiffies + HZ/10;
@@ -822,7 +859,7 @@
 			printk(KERN_ERR "%s: no IP address for %s, aborting\n",
 			       np->name, np->dev_name);
 			err = -EDESTADDRREQ;
-			goto release;
+			goto put;
 		}
 
 		np->local_ip = in_dev->ifa_list->ifa_local;
@@ -830,38 +867,25 @@
 		printk(KERN_INFO "%s: local IP %pI4\n", np->name, &np->local_ip);
 	}
 
-	if (np->rx_hook) {
-		spin_lock_irqsave(&npinfo->rx_lock, flags);
-		npinfo->rx_flags |= NETPOLL_RX_ENABLED;
-		list_add_tail(&np->rx, &npinfo->rx_np);
-		spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-	}
+	np->dev = ndev;
 
 	/* fill up the skb queue */
 	refill_skbs();
 
-	/* last thing to do is link it to the net device structure */
-	ndev->npinfo = npinfo;
+	rtnl_lock();
+	err = __netpoll_setup(np);
+	rtnl_unlock();
 
-	/* avoid racing with NAPI reading npinfo */
-	synchronize_rcu();
+	if (err)
+		goto put;
 
 	return 0;
 
- release:
-	if (!ndev->npinfo) {
-		spin_lock_irqsave(&npinfo->rx_lock, flags);
-		list_for_each_entry_safe(npe, tmp, &npinfo->rx_np, rx) {
-			npe->dev = NULL;
-		}
-		spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-
-		kfree(npinfo);
-	}
 put:
 	dev_put(ndev);
 	return err;
 }
+EXPORT_SYMBOL(netpoll_setup);
 
 static int __init netpoll_init(void)
 {
@@ -870,49 +894,65 @@
 }
 core_initcall(netpoll_init);
 
-void netpoll_cleanup(struct netpoll *np)
+void __netpoll_cleanup(struct netpoll *np)
 {
 	struct netpoll_info *npinfo;
 	unsigned long flags;
 
-	if (np->dev) {
-		npinfo = np->dev->npinfo;
-		if (npinfo) {
-			if (!list_empty(&npinfo->rx_np)) {
-				spin_lock_irqsave(&npinfo->rx_lock, flags);
-				list_del(&np->rx);
-				if (list_empty(&npinfo->rx_np))
-					npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
-				spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-			}
+	npinfo = np->dev->npinfo;
+	if (!npinfo)
+		return;
 
-			if (atomic_dec_and_test(&npinfo->refcnt)) {
-				const struct net_device_ops *ops;
-				skb_queue_purge(&npinfo->arp_tx);
-				skb_queue_purge(&npinfo->txq);
-				cancel_rearming_delayed_work(&npinfo->tx_work);
-
-				/* clean after last, unfinished work */
-				__skb_queue_purge(&npinfo->txq);
-				kfree(npinfo);
-				ops = np->dev->netdev_ops;
-				if (ops->ndo_netpoll_cleanup)
-					ops->ndo_netpoll_cleanup(np->dev);
-				else
-					np->dev->npinfo = NULL;
-			}
-		}
-
-		dev_put(np->dev);
+	if (!list_empty(&npinfo->rx_np)) {
+		spin_lock_irqsave(&npinfo->rx_lock, flags);
+		list_del(&np->rx);
+		if (list_empty(&npinfo->rx_np))
+			npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
+		spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 	}
 
+	if (atomic_dec_and_test(&npinfo->refcnt)) {
+		const struct net_device_ops *ops;
+
+		ops = np->dev->netdev_ops;
+		if (ops->ndo_netpoll_cleanup)
+			ops->ndo_netpoll_cleanup(np->dev);
+
+		rcu_assign_pointer(np->dev->npinfo, NULL);
+
+		/* avoid racing with NAPI reading npinfo */
+		synchronize_rcu_bh();
+
+		skb_queue_purge(&npinfo->arp_tx);
+		skb_queue_purge(&npinfo->txq);
+		cancel_rearming_delayed_work(&npinfo->tx_work);
+
+		/* clean after last, unfinished work */
+		__skb_queue_purge(&npinfo->txq);
+		kfree(npinfo);
+	}
+}
+EXPORT_SYMBOL_GPL(__netpoll_cleanup);
+
+void netpoll_cleanup(struct netpoll *np)
+{
+	if (!np->dev)
+		return;
+
+	rtnl_lock();
+	__netpoll_cleanup(np);
+	rtnl_unlock();
+
+	dev_put(np->dev);
 	np->dev = NULL;
 }
+EXPORT_SYMBOL(netpoll_cleanup);
 
 int netpoll_trap(void)
 {
 	return atomic_read(&trapped);
 }
+EXPORT_SYMBOL(netpoll_trap);
 
 void netpoll_set_trap(int trap)
 {
@@ -921,14 +961,4 @@
 	else
 		atomic_dec(&trapped);
 }
-
-EXPORT_SYMBOL(netpoll_send_skb);
 EXPORT_SYMBOL(netpoll_set_trap);
-EXPORT_SYMBOL(netpoll_trap);
-EXPORT_SYMBOL(netpoll_print_options);
-EXPORT_SYMBOL(netpoll_parse_options);
-EXPORT_SYMBOL(netpoll_setup);
-EXPORT_SYMBOL(netpoll_cleanup);
-EXPORT_SYMBOL(netpoll_send_udp);
-EXPORT_SYMBOL(netpoll_poll_dev);
-EXPORT_SYMBOL(netpoll_poll);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 1dacd7b..10a1ea7 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -115,6 +115,9 @@
  * command by Adit Ranadive <adit.262@gmail.com>
  *
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/sys.h>
 #include <linux/types.h>
 #include <linux/module.h>
@@ -169,11 +172,13 @@
 #include <asm/dma.h>
 #include <asm/div64.h>		/* do_div */
 
-#define VERSION 	"2.73"
+#define VERSION	"2.74"
 #define IP_NAME_SZ 32
 #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
 #define MPLS_STACK_BOTTOM htonl(0x00000100)
 
+#define func_enter() pr_debug("entering %s\n", __func__);
+
 /* Device flag bits */
 #define F_IPSRC_RND   (1<<0)	/* IP-Src Random  */
 #define F_IPDST_RND   (1<<1)	/* IP-Dst Random  */
@@ -424,7 +429,8 @@
 }
 
 static const char version[] =
-	"pktgen " VERSION ": Packet Generator for packet performance testing.\n";
+	"Packet Generator for packet performance testing. "
+	"Version: " VERSION "\n";
 
 static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
 static int pktgen_add_device(struct pktgen_thread *t, const char *ifname);
@@ -495,7 +501,7 @@
 		pktgen_reset_all_threads();
 
 	else
-		printk(KERN_WARNING "pktgen: Unknown command: %s\n", data);
+		pr_warning("Unknown command: %s\n", data);
 
 	err = count;
 
@@ -840,7 +846,7 @@
 			       const char __user * user_buffer, size_t count,
 			       loff_t * offset)
 {
-	struct seq_file *seq = (struct seq_file *)file->private_data;
+	struct seq_file *seq = file->private_data;
 	struct pktgen_dev *pkt_dev = seq->private;
 	int i = 0, max, len;
 	char name[16], valstr[32];
@@ -852,14 +858,14 @@
 	pg_result = &(pkt_dev->result[0]);
 
 	if (count < 1) {
-		printk(KERN_WARNING "pktgen: wrong command format\n");
+		pr_warning("wrong command format\n");
 		return -EINVAL;
 	}
 
 	max = count - i;
 	tmp = count_trail_chars(&user_buffer[i], max);
 	if (tmp < 0) {
-		printk(KERN_WARNING "pktgen: illegal format\n");
+		pr_warning("illegal format\n");
 		return tmp;
 	}
 	i += tmp;
@@ -980,6 +986,36 @@
 			(unsigned long long) pkt_dev->delay);
 		return count;
 	}
+	if (!strcmp(name, "rate")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+
+		i += len;
+		if (!value)
+			return len;
+		pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value;
+		if (debug)
+			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
+
+		sprintf(pg_result, "OK: rate=%lu", value);
+		return count;
+	}
+	if (!strcmp(name, "ratep")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+
+		i += len;
+		if (!value)
+			return len;
+		pkt_dev->delay = NSEC_PER_SEC/value;
+		if (debug)
+			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
+
+		sprintf(pg_result, "OK: rate=%lu", value);
+		return count;
+	}
 	if (!strcmp(name, "udp_src_min")) {
 		len = num_arg(&user_buffer[i], 10, &value);
 		if (len < 0)
@@ -1398,18 +1434,12 @@
 		i += len;
 
 		for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) {
-			if (*v >= '0' && *v <= '9') {
-				*m *= 16;
-				*m += *v - '0';
-			}
-			if (*v >= 'A' && *v <= 'F') {
-				*m *= 16;
-				*m += *v - 'A' + 10;
-			}
-			if (*v >= 'a' && *v <= 'f') {
-				*m *= 16;
-				*m += *v - 'a' + 10;
-			}
+			int value;
+
+			value = hex_to_bin(*v);
+			if (value >= 0)
+				*m = *m * 16 + value;
+
 			if (*v == ':') {
 				m++;
 				*m = 0;
@@ -1440,18 +1470,12 @@
 		i += len;
 
 		for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) {
-			if (*v >= '0' && *v <= '9') {
-				*m *= 16;
-				*m += *v - '0';
-			}
-			if (*v >= 'A' && *v <= 'F') {
-				*m *= 16;
-				*m += *v - 'A' + 10;
-			}
-			if (*v >= 'a' && *v <= 'f') {
-				*m *= 16;
-				*m += *v - 'a' + 10;
-			}
+			int value;
+
+			value = hex_to_bin(*v);
+			if (value >= 0)
+				*m = *m * 16 + value;
+
 			if (*v == ':') {
 				m++;
 				*m = 0;
@@ -1740,7 +1764,7 @@
 				   const char __user * user_buffer,
 				   size_t count, loff_t * offset)
 {
-	struct seq_file *seq = (struct seq_file *)file->private_data;
+	struct seq_file *seq = file->private_data;
 	struct pktgen_thread *t = seq->private;
 	int i = 0, max, len, ret;
 	char name[40];
@@ -1781,7 +1805,7 @@
 		       name, (unsigned long)count);
 
 	if (!t) {
-		printk(KERN_ERR "pktgen: ERROR: No thread\n");
+		pr_err("ERROR: No thread\n");
 		ret = -EINVAL;
 		goto out;
 	}
@@ -1874,7 +1898,7 @@
 	int i = 0;
 
 	mutex_lock(&pktgen_thread_lock);
-	pr_debug("pktgen: pktgen_mark_device marking %s for removal\n", ifname);
+	pr_debug("%s: marking %s for removal\n", __func__, ifname);
 
 	while (1) {
 
@@ -1883,15 +1907,14 @@
 			break;	/* success */
 
 		mutex_unlock(&pktgen_thread_lock);
-		pr_debug("pktgen: pktgen_mark_device waiting for %s "
-				"to disappear....\n", ifname);
+		pr_debug("%s: waiting for %s to disappear....\n",
+			 __func__, ifname);
 		schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
 		mutex_lock(&pktgen_thread_lock);
 
 		if (++i >= max_tries) {
-			printk(KERN_ERR "pktgen_mark_device: timed out after "
-			       "waiting %d msec for device %s to be removed\n",
-			       msec_per_try * i, ifname);
+			pr_err("%s: timed out after waiting %d msec for device %s to be removed\n",
+			       __func__, msec_per_try * i, ifname);
 			break;
 		}
 
@@ -1918,8 +1941,8 @@
 							  &pktgen_if_fops,
 							  pkt_dev);
 			if (!pkt_dev->entry)
-				printk(KERN_ERR "pktgen: can't move proc "
-				       " entry for '%s'\n", dev->name);
+				pr_err("can't move proc entry for '%s'\n",
+				       dev->name);
 			break;
 		}
 	}
@@ -1983,15 +2006,15 @@
 
 	odev = pktgen_dev_get_by_name(pkt_dev, ifname);
 	if (!odev) {
-		printk(KERN_ERR "pktgen: no such netdevice: \"%s\"\n", ifname);
+		pr_err("no such netdevice: \"%s\"\n", ifname);
 		return -ENODEV;
 	}
 
 	if (odev->type != ARPHRD_ETHER) {
-		printk(KERN_ERR "pktgen: not an ethernet device: \"%s\"\n", ifname);
+		pr_err("not an ethernet device: \"%s\"\n", ifname);
 		err = -EINVAL;
 	} else if (!netif_running(odev)) {
-		printk(KERN_ERR "pktgen: device is down: \"%s\"\n", ifname);
+		pr_err("device is down: \"%s\"\n", ifname);
 		err = -ENETDOWN;
 	} else {
 		pkt_dev->odev = odev;
@@ -2010,8 +2033,7 @@
 	int ntxq;
 
 	if (!pkt_dev->odev) {
-		printk(KERN_ERR "pktgen: ERROR: pkt_dev->odev == NULL in "
-		       "setup_inject.\n");
+		pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n");
 		sprintf(pkt_dev->result,
 			"ERROR: pkt_dev->odev == NULL in setup_inject.\n");
 		return;
@@ -2021,19 +2043,15 @@
 	ntxq = pkt_dev->odev->real_num_tx_queues;
 
 	if (ntxq <= pkt_dev->queue_map_min) {
-		printk(KERN_WARNING "pktgen: WARNING: Requested "
-		       "queue_map_min (zero-based) (%d) exceeds valid range "
-		       "[0 - %d] for (%d) queues on %s, resetting\n",
-		       pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq,
-		       pkt_dev->odevname);
+		pr_warning("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
+			   pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq,
+			   pkt_dev->odevname);
 		pkt_dev->queue_map_min = ntxq - 1;
 	}
 	if (pkt_dev->queue_map_max >= ntxq) {
-		printk(KERN_WARNING "pktgen: WARNING: Requested "
-		       "queue_map_max (zero-based) (%d) exceeds valid range "
-		       "[0 - %d] for (%d) queues on %s, resetting\n",
-		       pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq,
-		       pkt_dev->odevname);
+		pr_warning("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
+			   pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq,
+			   pkt_dev->odevname);
 		pkt_dev->queue_map_max = ntxq - 1;
 	}
 
@@ -2093,8 +2111,7 @@
 			}
 			rcu_read_unlock();
 			if (err)
-				printk(KERN_ERR "pktgen: ERROR: IPv6 link "
-				       "address not availble.\n");
+				pr_err("ERROR: IPv6 link address not available\n");
 		}
 #endif
 	} else {
@@ -2142,15 +2159,15 @@
 	hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
 	hrtimer_set_expires(&t.timer, spin_until);
 
-	remaining = ktime_to_us(hrtimer_expires_remaining(&t.timer));
+	remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer));
 	if (remaining <= 0) {
 		pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay);
 		return;
 	}
 
 	start_time = ktime_now();
-	if (remaining < 100)
-		udelay(remaining); 	/* really small just spin */
+	if (remaining < 100000)
+		ndelay(remaining);	/* really small just spin */
 	else {
 		/* see do_nanosleep */
 		hrtimer_init_sleeper(&t, current);
@@ -2528,8 +2545,8 @@
 			if (nhead > 0) {
 				ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
 				if (ret < 0) {
-					printk(KERN_ERR "Error expanding "
-					       "ipsec packet %d\n", ret);
+					pr_err("Error expanding ipsec packet %d\n",
+					       ret);
 					goto err;
 				}
 			}
@@ -2538,8 +2555,7 @@
 			skb_pull(skb, ETH_HLEN);
 			ret = pktgen_output_ipsec(skb, pkt_dev);
 			if (ret) {
-				printk(KERN_ERR "Error creating ipsec "
-				       "packet %d\n", ret);
+				pr_err("Error creating ipsec packet %d\n", ret);
 				goto err;
 			}
 			/* restore ll */
@@ -3015,8 +3031,7 @@
 	if (datalen < sizeof(struct pktgen_hdr)) {
 		datalen = sizeof(struct pktgen_hdr);
 		if (net_ratelimit())
-			printk(KERN_INFO "pktgen: increased datalen to %d\n",
-			       datalen);
+			pr_info("increased datalen to %d\n", datalen);
 	}
 
 	udph->source = htons(pkt_dev->cur_udp_src);
@@ -3143,7 +3158,7 @@
 	struct pktgen_dev *pkt_dev;
 	int started = 0;
 
-	pr_debug("pktgen: entering pktgen_run. %p\n", t);
+	func_enter();
 
 	if_lock(t);
 	list_for_each_entry(pkt_dev, &t->if_list, list) {
@@ -3176,7 +3191,7 @@
 {
 	struct pktgen_thread *t;
 
-	pr_debug("pktgen: entering pktgen_stop_all_threads_ifs.\n");
+	func_enter();
 
 	mutex_lock(&pktgen_thread_lock);
 
@@ -3241,7 +3256,7 @@
 {
 	struct pktgen_thread *t;
 
-	pr_debug("pktgen: entering pktgen_run_all_threads.\n");
+	func_enter();
 
 	mutex_lock(&pktgen_thread_lock);
 
@@ -3260,7 +3275,7 @@
 {
 	struct pktgen_thread *t;
 
-	pr_debug("pktgen: entering pktgen_reset_all_threads.\n");
+	func_enter();
 
 	mutex_lock(&pktgen_thread_lock);
 
@@ -3310,8 +3325,8 @@
 	int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
 
 	if (!pkt_dev->running) {
-		printk(KERN_WARNING "pktgen: interface: %s is already "
-		       "stopped\n", pkt_dev->odevname);
+		pr_warning("interface: %s is already stopped\n",
+			   pkt_dev->odevname);
 		return -EINVAL;
 	}
 
@@ -3347,7 +3362,7 @@
 {
 	struct pktgen_dev *pkt_dev;
 
-	pr_debug("pktgen: entering pktgen_stop\n");
+	func_enter();
 
 	if_lock(t);
 
@@ -3367,7 +3382,7 @@
 	struct list_head *q, *n;
 	struct pktgen_dev *cur;
 
-	pr_debug("pktgen: entering pktgen_rem_one_if\n");
+	func_enter();
 
 	if_lock(t);
 
@@ -3393,9 +3408,10 @@
 	struct list_head *q, *n;
 	struct pktgen_dev *cur;
 
+	func_enter();
+
 	/* Remove all devices, free mem */
 
-	pr_debug("pktgen: entering pktgen_rem_all_ifs\n");
 	if_lock(t);
 
 	list_for_each_safe(q, n, &t->if_list) {
@@ -3477,8 +3493,7 @@
 
 		pkt_dev->skb = fill_packet(odev, pkt_dev);
 		if (pkt_dev->skb == NULL) {
-			printk(KERN_ERR "pktgen: ERROR: couldn't "
-			       "allocate skb in fill_packet.\n");
+			pr_err("ERROR: couldn't allocate skb in fill_packet\n");
 			schedule();
 			pkt_dev->clone_count--;	/* back out increment, OOM */
 			return;
@@ -3558,8 +3573,7 @@
 	init_waitqueue_head(&t->queue);
 	complete(&t->start_done);
 
-	pr_debug("pktgen: starting pktgen/%d:  pid=%d\n",
-		 cpu, task_pid_nr(current));
+	pr_debug("starting pktgen/%d:  pid=%d\n", cpu, task_pid_nr(current));
 
 	set_current_state(TASK_INTERRUPTIBLE);
 
@@ -3612,13 +3626,13 @@
 		set_current_state(TASK_INTERRUPTIBLE);
 	}
 
-	pr_debug("pktgen: %s stopping all device\n", t->tsk->comm);
+	pr_debug("%s stopping all device\n", t->tsk->comm);
 	pktgen_stop(t);
 
-	pr_debug("pktgen: %s removing all device\n", t->tsk->comm);
+	pr_debug("%s removing all device\n", t->tsk->comm);
 	pktgen_rem_all_ifs(t);
 
-	pr_debug("pktgen: %s removing thread.\n", t->tsk->comm);
+	pr_debug("%s removing thread\n", t->tsk->comm);
 	pktgen_rem_thread(t);
 
 	return 0;
@@ -3642,7 +3656,7 @@
 		}
 
 	if_unlock(t);
-	pr_debug("pktgen: find_dev(%s) returning %p\n", ifname, pkt_dev);
+	pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev);
 	return pkt_dev;
 }
 
@@ -3658,8 +3672,7 @@
 	if_lock(t);
 
 	if (pkt_dev->pg_thread) {
-		printk(KERN_ERR "pktgen: ERROR: already assigned "
-		       "to a thread.\n");
+		pr_err("ERROR: already assigned to a thread\n");
 		rv = -EBUSY;
 		goto out;
 	}
@@ -3685,7 +3698,7 @@
 
 	pkt_dev = __pktgen_NN_threads(ifname, FIND);
 	if (pkt_dev) {
-		printk(KERN_ERR "pktgen: ERROR: interface already used.\n");
+		pr_err("ERROR: interface already used\n");
 		return -EBUSY;
 	}
 
@@ -3730,7 +3743,7 @@
 	pkt_dev->entry = proc_create_data(ifname, 0600, pg_proc_dir,
 					  &pktgen_if_fops, pkt_dev);
 	if (!pkt_dev->entry) {
-		printk(KERN_ERR "pktgen: cannot create %s/%s procfs entry.\n",
+		pr_err("cannot create %s/%s procfs entry\n",
 		       PG_PROC_DIR, ifname);
 		err = -EINVAL;
 		goto out2;
@@ -3761,8 +3774,7 @@
 	t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL,
 			 cpu_to_node(cpu));
 	if (!t) {
-		printk(KERN_ERR "pktgen: ERROR: out of memory, can't "
-		       "create new thread.\n");
+		pr_err("ERROR: out of memory, can't create new thread\n");
 		return -ENOMEM;
 	}
 
@@ -3776,8 +3788,7 @@
 
 	p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu);
 	if (IS_ERR(p)) {
-		printk(KERN_ERR "pktgen: kernel_thread() failed "
-		       "for cpu %d\n", t->cpu);
+		pr_err("kernel_thread() failed for cpu %d\n", t->cpu);
 		list_del(&t->th_list);
 		kfree(t);
 		return PTR_ERR(p);
@@ -3788,7 +3799,7 @@
 	pe = proc_create_data(t->tsk->comm, 0600, pg_proc_dir,
 			      &pktgen_thread_fops, t);
 	if (!pe) {
-		printk(KERN_ERR "pktgen: cannot create %s/%s procfs entry.\n",
+		pr_err("cannot create %s/%s procfs entry\n",
 		       PG_PROC_DIR, t->tsk->comm);
 		kthread_stop(p);
 		list_del(&t->th_list);
@@ -3822,11 +3833,10 @@
 				struct pktgen_dev *pkt_dev)
 {
 
-	pr_debug("pktgen: remove_device pkt_dev=%p\n", pkt_dev);
+	pr_debug("remove_device pkt_dev=%p\n", pkt_dev);
 
 	if (pkt_dev->running) {
-		printk(KERN_WARNING "pktgen: WARNING: trying to remove a "
-		       "running interface, stopping it now.\n");
+		pr_warning("WARNING: trying to remove a running interface, stopping it now\n");
 		pktgen_stop_device(pkt_dev);
 	}
 
@@ -3857,7 +3867,7 @@
 	int cpu;
 	struct proc_dir_entry *pe;
 
-	printk(KERN_INFO "%s", version);
+	pr_info("%s", version);
 
 	pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net);
 	if (!pg_proc_dir)
@@ -3865,8 +3875,7 @@
 
 	pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops);
 	if (pe == NULL) {
-		printk(KERN_ERR "pktgen: ERROR: cannot create %s "
-		       "procfs entry.\n", PGCTRL);
+		pr_err("ERROR: cannot create %s procfs entry\n", PGCTRL);
 		proc_net_remove(&init_net, PG_PROC_DIR);
 		return -EINVAL;
 	}
@@ -3879,13 +3888,12 @@
 
 		err = pktgen_create_thread(cpu);
 		if (err)
-			printk(KERN_WARNING "pktgen: WARNING: Cannot create "
-			       "thread for cpu %d (%d)\n", cpu, err);
+			pr_warning("WARNING: Cannot create thread for cpu %d (%d)\n",
+				   cpu, err);
 	}
 
 	if (list_empty(&pktgen_threads)) {
-		printk(KERN_ERR "pktgen: ERROR: Initialization failed for "
-		       "all threads\n");
+		pr_err("ERROR: Initialization failed for all threads\n");
 		unregister_netdevice_notifier(&pktgen_notifier_block);
 		remove_proc_entry(PGCTRL, pg_proc_dir);
 		proc_net_remove(&init_net, PG_PROC_DIR);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 1a2af24..f78d821 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -579,7 +579,7 @@
 }
 
 static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
-				 const struct net_device_stats *b)
+				 const struct rtnl_link_stats64 *b)
 {
 	a->rx_packets = b->rx_packets;
 	a->tx_packets = b->tx_packets;
@@ -610,7 +610,7 @@
 	a->tx_compressed = b->tx_compressed;
 }
 
-static void copy_rtnl_link_stats64(void *v, const struct net_device_stats *b)
+static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b)
 {
 	struct rtnl_link_stats64 a;
 
@@ -686,7 +686,7 @@
 		return port_self_size;
 }
 
-static inline size_t if_nlmsg_size(const struct net_device *dev)
+static noinline size_t if_nlmsg_size(const struct net_device *dev)
 {
 	return NLMSG_ALIGN(sizeof(struct ifinfomsg))
 	       + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
@@ -791,7 +791,8 @@
 {
 	struct ifinfomsg *ifm;
 	struct nlmsghdr *nlh;
-	const struct net_device_stats *stats;
+	struct rtnl_link_stats64 temp;
+	const struct rtnl_link_stats64 *stats;
 	struct nlattr *attr;
 
 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
@@ -847,7 +848,7 @@
 	if (attr == NULL)
 		goto nla_put_failure;
 
-	stats = dev_get_stats(dev);
+	stats = dev_get_stats(dev, &temp);
 	copy_rtnl_link_stats(nla_data(attr), stats);
 
 	attr = nla_reserve(skb, IFLA_STATS64,
diff --git a/net/core/scm.c b/net/core/scm.c
index b88f6f9..413cab8 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -130,6 +130,7 @@
 		}
 	}
 }
+EXPORT_SYMBOL(__scm_destroy);
 
 int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
 {
@@ -170,6 +171,30 @@
 			err = scm_check_creds(&p->creds);
 			if (err)
 				goto error;
+
+			if (pid_vnr(p->pid) != p->creds.pid) {
+				struct pid *pid;
+				err = -ESRCH;
+				pid = find_get_pid(p->creds.pid);
+				if (!pid)
+					goto error;
+				put_pid(p->pid);
+				p->pid = pid;
+			}
+
+			if ((p->cred->euid != p->creds.uid) ||
+				(p->cred->egid != p->creds.gid)) {
+				struct cred *cred;
+				err = -ENOMEM;
+				cred = prepare_creds();
+				if (!cred)
+					goto error;
+
+				cred->uid = cred->euid = p->creds.uid;
+				cred->gid = cred->egid = p->creds.uid;
+				put_cred(p->cred);
+				p->cred = cred;
+			}
 			break;
 		default:
 			goto error;
@@ -187,6 +212,7 @@
 	scm_destroy(p);
 	return err;
 }
+EXPORT_SYMBOL(__scm_send);
 
 int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
 {
@@ -225,6 +251,7 @@
 out:
 	return err;
 }
+EXPORT_SYMBOL(put_cmsg);
 
 void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
 {
@@ -294,6 +321,7 @@
 	 */
 	__scm_destroy(scm);
 }
+EXPORT_SYMBOL(scm_detach_fds);
 
 struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
 {
@@ -311,9 +339,4 @@
 	}
 	return new_fpl;
 }
-
-EXPORT_SYMBOL(__scm_destroy);
-EXPORT_SYMBOL(__scm_send);
-EXPORT_SYMBOL(put_cmsg);
-EXPORT_SYMBOL(scm_detach_fds);
 EXPORT_SYMBOL(scm_fp_dup);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index ce88293..3a2513f 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -817,7 +817,7 @@
 	memcpy(data + nhead, skb->head, skb->tail - skb->head);
 #endif
 	memcpy(data + size, skb_end_pointer(skb),
-	       sizeof(struct skb_shared_info));
+	       offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));
 
 	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
 		get_page(skb_shinfo(skb)->frags[i].page);
@@ -2486,7 +2486,6 @@
 	skb_postpull_rcsum(skb, skb->data, len);
 	return skb->data += len;
 }
-
 EXPORT_SYMBOL_GPL(skb_pull_rcsum);
 
 /**
diff --git a/net/core/sock.c b/net/core/sock.c
index 2cf7f9f..b05b9b6 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -110,6 +110,7 @@
 #include <linux/tcp.h>
 #include <linux/init.h>
 #include <linux/highmem.h>
+#include <linux/user_namespace.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -156,7 +157,7 @@
   "sk_lock-27"       , "sk_lock-28"          , "sk_lock-AF_CAN"      ,
   "sk_lock-AF_TIPC"  , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV"        ,
   "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN"     , "sk_lock-AF_PHONET"   ,
-  "sk_lock-AF_IEEE802154",
+  "sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" ,
   "sk_lock-AF_MAX"
 };
 static const char *const af_family_slock_key_strings[AF_MAX+1] = {
@@ -172,7 +173,7 @@
   "slock-27"       , "slock-28"          , "slock-AF_CAN"      ,
   "slock-AF_TIPC"  , "slock-AF_BLUETOOTH", "slock-AF_IUCV"     ,
   "slock-AF_RXRPC" , "slock-AF_ISDN"     , "slock-AF_PHONET"   ,
-  "slock-AF_IEEE802154",
+  "slock-AF_IEEE802154", "slock-AF_CAIF" ,
   "slock-AF_MAX"
 };
 static const char *const af_family_clock_key_strings[AF_MAX+1] = {
@@ -188,7 +189,7 @@
   "clock-27"       , "clock-28"          , "clock-AF_CAN"      ,
   "clock-AF_TIPC"  , "clock-AF_BLUETOOTH", "clock-AF_IUCV"     ,
   "clock-AF_RXRPC" , "clock-AF_ISDN"     , "clock-AF_PHONET"   ,
-  "clock-AF_IEEE802154",
+  "clock-AF_IEEE802154", "clock-AF_CAIF" ,
   "clock-AF_MAX"
 };
 
@@ -749,6 +750,20 @@
 EXPORT_SYMBOL(sock_setsockopt);
 
 
+void cred_to_ucred(struct pid *pid, const struct cred *cred,
+		   struct ucred *ucred)
+{
+	ucred->pid = pid_vnr(pid);
+	ucred->uid = ucred->gid = -1;
+	if (cred) {
+		struct user_namespace *current_ns = current_user_ns();
+
+		ucred->uid = user_ns_map_uid(current_ns, cred, cred->euid);
+		ucred->gid = user_ns_map_gid(current_ns, cred, cred->egid);
+	}
+}
+EXPORT_SYMBOL_GPL(cred_to_ucred);
+
 int sock_getsockopt(struct socket *sock, int level, int optname,
 		    char __user *optval, int __user *optlen)
 {
@@ -901,11 +916,15 @@
 		break;
 
 	case SO_PEERCRED:
-		if (len > sizeof(sk->sk_peercred))
-			len = sizeof(sk->sk_peercred);
-		if (copy_to_user(optval, &sk->sk_peercred, len))
+	{
+		struct ucred peercred;
+		if (len > sizeof(peercred))
+			len = sizeof(peercred);
+		cred_to_ucred(sk->sk_peer_pid, sk->sk_peer_cred, &peercred);
+		if (copy_to_user(optval, &peercred, len))
 			return -EFAULT;
 		goto lenout;
+	}
 
 	case SO_PEERNAME:
 	{
@@ -1119,6 +1138,9 @@
 		printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n",
 		       __func__, atomic_read(&sk->sk_omem_alloc));
 
+	if (sk->sk_peer_cred)
+		put_cred(sk->sk_peer_cred);
+	put_pid(sk->sk_peer_pid);
 	put_net(sock_net(sk));
 	sk_prot_free(sk->sk_prot_creator, sk);
 }
@@ -1317,9 +1339,10 @@
 void sock_rfree(struct sk_buff *skb)
 {
 	struct sock *sk = skb->sk;
+	unsigned int len = skb->truesize;
 
-	atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
-	sk_mem_uncharge(skb->sk, skb->truesize);
+	atomic_sub(len, &sk->sk_rmem_alloc);
+	sk_mem_uncharge(sk, len);
 }
 EXPORT_SYMBOL(sock_rfree);
 
@@ -1954,9 +1977,8 @@
 	sk->sk_sndmsg_page	=	NULL;
 	sk->sk_sndmsg_off	=	0;
 
-	sk->sk_peercred.pid 	=	0;
-	sk->sk_peercred.uid	=	-1;
-	sk->sk_peercred.gid	=	-1;
+	sk->sk_peer_pid 	=	NULL;
+	sk->sk_peer_cred	=	NULL;
 	sk->sk_write_pending	=	0;
 	sk->sk_rcvlowat		=	1;
 	sk->sk_rcvtimeo		=	MAX_SCHEDULE_TIMEOUT;
@@ -2210,8 +2232,7 @@
 #ifdef CONFIG_NET_NS
 void sock_prot_inuse_add(struct net *net, struct proto *prot, int val)
 {
-	int cpu = smp_processor_id();
-	per_cpu_ptr(net->core.inuse, cpu)->val[prot->inuse_idx] += val;
+	__this_cpu_add(net->core.inuse->val[prot->inuse_idx], val);
 }
 EXPORT_SYMBOL_GPL(sock_prot_inuse_add);
 
@@ -2257,7 +2278,7 @@
 
 void sock_prot_inuse_add(struct net *net, struct proto *prot, int val)
 {
-	__get_cpu_var(prot_inuse).val[prot->inuse_idx] += val;
+	__this_cpu_add(prot_inuse.val[prot->inuse_idx], val);
 }
 EXPORT_SYMBOL_GPL(sock_prot_inuse_add);
 
diff --git a/net/core/stream.c b/net/core/stream.c
index cc196f4..d959e0f 100644
--- a/net/core/stream.c
+++ b/net/core/stream.c
@@ -43,7 +43,6 @@
 		rcu_read_unlock();
 	}
 }
-
 EXPORT_SYMBOL(sk_stream_write_space);
 
 /**
@@ -81,7 +80,6 @@
 	} while (!done);
 	return 0;
 }
-
 EXPORT_SYMBOL(sk_stream_wait_connect);
 
 /**
@@ -109,7 +107,6 @@
 		finish_wait(sk_sleep(sk), &wait);
 	}
 }
-
 EXPORT_SYMBOL(sk_stream_wait_close);
 
 /**
@@ -174,7 +171,6 @@
 	err = sock_intr_errno(*timeo_p);
 	goto out;
 }
-
 EXPORT_SYMBOL(sk_stream_wait_memory);
 
 int sk_stream_error(struct sock *sk, int flags, int err)
@@ -185,7 +181,6 @@
 		send_sig(SIGPIPE, current, 0);
 	return err;
 }
-
 EXPORT_SYMBOL(sk_stream_error);
 
 void sk_stream_kill_queues(struct sock *sk)
@@ -210,5 +205,4 @@
 	 * have gone away, only the net layer knows can touch it.
 	 */
 }
-
 EXPORT_SYMBOL(sk_stream_kill_queues);
diff --git a/net/core/timestamping.c b/net/core/timestamping.c
new file mode 100644
index 0000000..0ae6c22
--- /dev/null
+++ b/net/core/timestamping.c
@@ -0,0 +1,126 @@
+/*
+ * PTP 1588 clock support - support for timestamping in PHY devices
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/errqueue.h>
+#include <linux/phy.h>
+#include <linux/ptp_classify.h>
+#include <linux/skbuff.h>
+
+static struct sock_filter ptp_filter[] = {
+	PTP_FILTER
+};
+
+static unsigned int classify(struct sk_buff *skb)
+{
+	if (likely(skb->dev &&
+		   skb->dev->phydev &&
+		   skb->dev->phydev->drv))
+		return sk_run_filter(skb, ptp_filter, ARRAY_SIZE(ptp_filter));
+	else
+		return PTP_CLASS_NONE;
+}
+
+void skb_clone_tx_timestamp(struct sk_buff *skb)
+{
+	struct phy_device *phydev;
+	struct sk_buff *clone;
+	struct sock *sk = skb->sk;
+	unsigned int type;
+
+	if (!sk)
+		return;
+
+	type = classify(skb);
+
+	switch (type) {
+	case PTP_CLASS_V1_IPV4:
+	case PTP_CLASS_V1_IPV6:
+	case PTP_CLASS_V2_IPV4:
+	case PTP_CLASS_V2_IPV6:
+	case PTP_CLASS_V2_L2:
+	case PTP_CLASS_V2_VLAN:
+		phydev = skb->dev->phydev;
+		if (likely(phydev->drv->txtstamp)) {
+			clone = skb_clone(skb, GFP_ATOMIC);
+			if (!clone)
+				return;
+			clone->sk = sk;
+			phydev->drv->txtstamp(phydev, clone, type);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+void skb_complete_tx_timestamp(struct sk_buff *skb,
+			       struct skb_shared_hwtstamps *hwtstamps)
+{
+	struct sock *sk = skb->sk;
+	struct sock_exterr_skb *serr;
+	int err;
+
+	if (!hwtstamps)
+		return;
+
+	*skb_hwtstamps(skb) = *hwtstamps;
+	serr = SKB_EXT_ERR(skb);
+	memset(serr, 0, sizeof(*serr));
+	serr->ee.ee_errno = ENOMSG;
+	serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
+	skb->sk = NULL;
+	err = sock_queue_err_skb(sk, skb);
+	if (err)
+		kfree_skb(skb);
+}
+EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp);
+
+bool skb_defer_rx_timestamp(struct sk_buff *skb)
+{
+	struct phy_device *phydev;
+	unsigned int type;
+
+	skb_push(skb, ETH_HLEN);
+
+	type = classify(skb);
+
+	skb_pull(skb, ETH_HLEN);
+
+	switch (type) {
+	case PTP_CLASS_V1_IPV4:
+	case PTP_CLASS_V1_IPV6:
+	case PTP_CLASS_V2_IPV4:
+	case PTP_CLASS_V2_IPV6:
+	case PTP_CLASS_V2_L2:
+	case PTP_CLASS_V2_VLAN:
+		phydev = skb->dev->phydev;
+		if (likely(phydev->drv->rxtstamp))
+			return phydev->drv->rxtstamp(phydev, skb, type);
+		break;
+	default:
+		break;
+	}
+
+	return false;
+}
+
+void __init skb_timestamping_init(void)
+{
+	BUG_ON(sk_chk_filter(ptp_filter, ARRAY_SIZE(ptp_filter)));
+}
diff --git a/net/core/utils.c b/net/core/utils.c
index 8382502..f418544 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -77,7 +77,6 @@
 	}
 	return(htonl(l));
 }
-
 EXPORT_SYMBOL(in_aton);
 
 #define IN6PTON_XDIGIT		0x00010000
@@ -162,7 +161,6 @@
 		*end = s;
 	return ret;
 }
-
 EXPORT_SYMBOL(in4_pton);
 
 int in6_pton(const char *src, int srclen,
@@ -280,7 +278,6 @@
 		*end = s;
 	return ret;
 }
-
 EXPORT_SYMBOL(in6_pton);
 
 void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 01e4d39..92a6fcb 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -82,7 +82,7 @@
 	elapsed_time = delta / 10;
 
 	if (elapsed_time != 0 &&
-	    dccp_insert_option_elapsed_time(sk, skb, elapsed_time))
+	    dccp_insert_option_elapsed_time(skb, elapsed_time))
 		return -1;
 
 	avr = dccp_ackvec_record_new();
@@ -201,7 +201,7 @@
 						 const unsigned int packets,
 						 const unsigned char state)
 {
-	unsigned int gap;
+	long gap;
 	long new_head;
 
 	if (av->av_vec_len + packets > DCCP_MAX_ACKVEC_LEN)
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index d323589..95f7529 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -715,9 +715,9 @@
 	x_recv = htonl(hc->rx_x_recv);
 	pinv   = htonl(hc->rx_pinv);
 
-	if (dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
+	if (dccp_insert_option(skb, TFRC_OPT_LOSS_EVENT_RATE,
 			       &pinv, sizeof(pinv)) ||
-	    dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE,
+	    dccp_insert_option(skb, TFRC_OPT_RECEIVE_RATE,
 			       &x_recv, sizeof(x_recv)))
 		return -1;
 
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index a10a61a..3ccef1b 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -446,16 +446,12 @@
 
 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,
-					    struct sk_buff *skb,
-					    u32 elapsed_time);
+extern int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed);
 extern u32 dccp_timestamp(void);
 extern void dccp_timestamping_init(void);
-extern int dccp_insert_option_timestamp(struct sock *sk,
-					 struct sk_buff *skb);
-extern int dccp_insert_option(struct sock *sk, struct sk_buff *skb,
-			       unsigned char option,
-			       const void *value, unsigned char len);
+extern int dccp_insert_option_timestamp(struct sk_buff *skb);
+extern int dccp_insert_option(struct sk_buff *skb, unsigned char option,
+			      const void *value, unsigned char len);
 
 #ifdef CONFIG_SYSCTL
 extern int dccp_sysctl_init(void);
diff --git a/net/dccp/input.c b/net/dccp/input.c
index 6beb6a7..10c957a 100644
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -430,7 +430,7 @@
 		if (dccp_parse_options(sk, NULL, skb))
 			return 1;
 
-		/* Obtain usec RTT sample from SYN exchange (used by CCID 3) */
+		/* Obtain usec RTT sample from SYN exchange (used by TFRC). */
 		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));
@@ -535,6 +535,8 @@
 						   const struct dccp_hdr *dh,
 						   const unsigned len)
 {
+	struct dccp_sock *dp = dccp_sk(sk);
+	u32 sample = dp->dccps_options_received.dccpor_timestamp_echo;
 	int queued = 0;
 
 	switch (dh->dccph_type) {
@@ -559,7 +561,14 @@
 		if (sk->sk_state == DCCP_PARTOPEN)
 			inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
 
-		dccp_sk(sk)->dccps_osr = DCCP_SKB_CB(skb)->dccpd_seq;
+		/* Obtain usec RTT sample from SYN exchange (used by TFRC). */
+		if (likely(sample)) {
+			long delta = dccp_timestamp() - sample;
+
+			dp->dccps_syn_rtt = dccp_sample_rtt(sk, 10 * delta);
+		}
+
+		dp->dccps_osr = DCCP_SKB_CB(skb)->dccpd_seq;
 		dccp_set_state(sk, DCCP_OPEN);
 
 		if (dh->dccph_type == DCCP_PKT_DATAACK ||
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index d9b11ef..d4a166f 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -105,7 +105,7 @@
 		goto failure;
 
 	/* OK, now commit destination to socket.  */
-	sk_setup_caps(sk, &rt->u.dst);
+	sk_setup_caps(sk, &rt->dst);
 
 	dp->dccps_iss = secure_dccp_sequence_number(inet->inet_saddr,
 						    inet->inet_daddr,
@@ -475,7 +475,7 @@
 		return NULL;
 	}
 
-	return &rt->u.dst;
+	return &rt->dst;
 }
 
 static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 0916988..6e3f325 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -248,7 +248,7 @@
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct sk_buff *skb;
 	struct ipv6_txoptions *opt = NULL;
-	struct in6_addr *final_p = NULL, final;
+	struct in6_addr *final_p, final;
 	struct flowi fl;
 	int err = -1;
 	struct dst_entry *dst;
@@ -265,13 +265,7 @@
 
 	opt = np->opt;
 
-	if (opt != NULL && opt->srcrt != NULL) {
-		const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
-
-		ipv6_addr_copy(&final, &fl.fl6_dst);
-		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-		final_p = &final;
-	}
+	final_p = fl6_update_dst(&fl, opt, &final);
 
 	err = ip6_dst_lookup(sk, &dst, &fl);
 	if (err)
@@ -545,19 +539,13 @@
 		goto out_overflow;
 
 	if (dst == NULL) {
-		struct in6_addr *final_p = NULL, final;
+		struct in6_addr *final_p, final;
 		struct flowi fl;
 
 		memset(&fl, 0, sizeof(fl));
 		fl.proto = IPPROTO_DCCP;
 		ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
-		if (opt != NULL && opt->srcrt != NULL) {
-			const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
-
-			ipv6_addr_copy(&final, &fl.fl6_dst);
-			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-			final_p = &final;
-		}
+		final_p = fl6_update_dst(&fl, opt, &final);
 		ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
 		fl.oif = sk->sk_bound_dev_if;
 		fl.fl_ip_dport = inet_rsk(req)->rmt_port;
@@ -885,7 +873,7 @@
 	struct inet_sock *inet = inet_sk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct in6_addr *saddr = NULL, *final_p = NULL, final;
+	struct in6_addr *saddr = NULL, *final_p, final;
 	struct flowi fl;
 	struct dst_entry *dst;
 	int addr_type;
@@ -988,13 +976,7 @@
 	fl.fl_ip_sport = inet->inet_sport;
 	security_sk_classify_flow(sk, &fl);
 
-	if (np->opt != NULL && np->opt->srcrt != NULL) {
-		const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
-
-		ipv6_addr_copy(&final, &fl.fl6_dst);
-		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-		final_p = &final;
-	}
+	final_p = fl6_update_dst(&fl, np->opt, &final);
 
 	err = ip6_dst_lookup(sk, &dst, &fl);
 	if (err)
diff --git a/net/dccp/options.c b/net/dccp/options.c
index 07395f8..bfda087 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -299,9 +299,8 @@
 	return likely(ndp <= USHRT_MAX) ? 2 : (ndp <= UINT_MAX ? 4 : 6);
 }
 
-int dccp_insert_option(struct sock *sk, struct sk_buff *skb,
-			const unsigned char option,
-			const void *value, const unsigned char len)
+int dccp_insert_option(struct sk_buff *skb, const unsigned char option,
+		       const void *value, const unsigned char len)
 {
 	unsigned char *to;
 
@@ -354,8 +353,7 @@
 	return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4;
 }
 
-int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb,
-				    u32 elapsed_time)
+int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed_time)
 {
 	const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
 	const int len = 2 + elapsed_time_len;
@@ -386,13 +384,13 @@
 
 EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time);
 
-int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
+int dccp_insert_option_timestamp(struct sk_buff *skb)
 {
 	__be32 now = htonl(dccp_timestamp());
 	/* yes this will overflow but that is the point as we want a
 	 * 10 usec 32 bit timer which mean it wraps every 11.9 hours */
 
-	return dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now));
+	return dccp_insert_option(skb, DCCPO_TIMESTAMP, &now, sizeof(now));
 }
 
 EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp);
@@ -531,9 +529,9 @@
 		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.
+			 * This is currently used for TFRC initialisation.
 			 */
-			if (dccp_insert_option_timestamp(sk, skb))
+			if (dccp_insert_option_timestamp(skb))
 				return -1;
 
 		} else if (dp->dccps_hc_rx_ackvec != NULL &&
@@ -564,6 +562,10 @@
 	if (dccp_feat_insert_opts(NULL, dreq, skb))
 		return -1;
 
+	/* Obtain RTT sample from Response/Ack exchange (used by TFRC). */
+	if (dccp_insert_option_timestamp(skb))
+		return -1;
+
 	if (dreq->dreq_timestamp_echo != 0 &&
 	    dccp_insert_option_timestamp_echo(NULL, dreq, skb))
 		return -1;
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index b03ecf6..096250d 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -473,14 +473,9 @@
 	if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
 		return -EINVAL;
 
-	val = kmalloc(optlen, GFP_KERNEL);
-	if (val == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(val, optval, optlen)) {
-		kfree(val);
-		return -EFAULT;
-	}
+	val = memdup_user(optval, optlen);
+	if (IS_ERR(val))
+		return PTR_ERR(val);
 
 	lock_sock(sk);
 	if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
@@ -1007,7 +1002,8 @@
 static inline int dccp_mib_init(void)
 {
 	return snmp_mib_init((void __percpu **)dccp_statistics,
-			     sizeof(struct dccp_mib));
+			     sizeof(struct dccp_mib),
+			     __alignof__(struct dccp_mib));
 }
 
 static inline void dccp_mib_exit(void)
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 812e6df..6585ea6 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -146,13 +146,13 @@
 
 static inline void dnrt_free(struct dn_route *rt)
 {
-	call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
+	call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
 }
 
 static inline void dnrt_drop(struct dn_route *rt)
 {
-	dst_release(&rt->u.dst);
-	call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
+	dst_release(&rt->dst);
+	call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
 }
 
 static void dn_dst_check_expire(unsigned long dummy)
@@ -167,13 +167,13 @@
 
 		spin_lock(&dn_rt_hash_table[i].lock);
 		while((rt=*rtp) != NULL) {
-			if (atomic_read(&rt->u.dst.__refcnt) ||
-					(now - rt->u.dst.lastuse) < expire) {
-				rtp = &rt->u.dst.dn_next;
+			if (atomic_read(&rt->dst.__refcnt) ||
+					(now - rt->dst.lastuse) < expire) {
+				rtp = &rt->dst.dn_next;
 				continue;
 			}
-			*rtp = rt->u.dst.dn_next;
-			rt->u.dst.dn_next = NULL;
+			*rtp = rt->dst.dn_next;
+			rt->dst.dn_next = NULL;
 			dnrt_free(rt);
 		}
 		spin_unlock(&dn_rt_hash_table[i].lock);
@@ -198,13 +198,13 @@
 		rtp = &dn_rt_hash_table[i].chain;
 
 		while((rt=*rtp) != NULL) {
-			if (atomic_read(&rt->u.dst.__refcnt) ||
-					(now - rt->u.dst.lastuse) < expire) {
-				rtp = &rt->u.dst.dn_next;
+			if (atomic_read(&rt->dst.__refcnt) ||
+					(now - rt->dst.lastuse) < expire) {
+				rtp = &rt->dst.dn_next;
 				continue;
 			}
-			*rtp = rt->u.dst.dn_next;
-			rt->u.dst.dn_next = NULL;
+			*rtp = rt->dst.dn_next;
+			rt->dst.dn_next = NULL;
 			dnrt_drop(rt);
 			break;
 		}
@@ -287,25 +287,25 @@
 	while((rth = *rthp) != NULL) {
 		if (compare_keys(&rth->fl, &rt->fl)) {
 			/* Put it first */
-			*rthp = rth->u.dst.dn_next;
-			rcu_assign_pointer(rth->u.dst.dn_next,
+			*rthp = rth->dst.dn_next;
+			rcu_assign_pointer(rth->dst.dn_next,
 					   dn_rt_hash_table[hash].chain);
 			rcu_assign_pointer(dn_rt_hash_table[hash].chain, rth);
 
-			dst_use(&rth->u.dst, now);
+			dst_use(&rth->dst, now);
 			spin_unlock_bh(&dn_rt_hash_table[hash].lock);
 
 			dnrt_drop(rt);
 			*rp = rth;
 			return 0;
 		}
-		rthp = &rth->u.dst.dn_next;
+		rthp = &rth->dst.dn_next;
 	}
 
-	rcu_assign_pointer(rt->u.dst.dn_next, dn_rt_hash_table[hash].chain);
+	rcu_assign_pointer(rt->dst.dn_next, dn_rt_hash_table[hash].chain);
 	rcu_assign_pointer(dn_rt_hash_table[hash].chain, rt);
 
-	dst_use(&rt->u.dst, now);
+	dst_use(&rt->dst, now);
 	spin_unlock_bh(&dn_rt_hash_table[hash].lock);
 	*rp = rt;
 	return 0;
@@ -323,8 +323,8 @@
 			goto nothing_to_declare;
 
 		for(; rt; rt=next) {
-			next = rt->u.dst.dn_next;
-			rt->u.dst.dn_next = NULL;
+			next = rt->dst.dn_next;
+			rt->dst.dn_next = NULL;
 			dst_free((struct dst_entry *)rt);
 		}
 
@@ -743,7 +743,7 @@
 	/* Ensure that we have enough space for headers */
 	rt = (struct dn_route *)skb_dst(skb);
 	header_len = dn_db->use_long ? 21 : 6;
-	if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+header_len))
+	if (skb_cow(skb, LL_RESERVED_SPACE(rt->dst.dev)+header_len))
 		goto drop;
 
 	/*
@@ -752,7 +752,7 @@
 	if (++cb->hops > 30)
 		goto drop;
 
-	skb->dev = rt->u.dst.dev;
+	skb->dev = rt->dst.dev;
 
 	/*
 	 * If packet goes out same interface it came in on, then set
@@ -792,7 +792,7 @@
 static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
 {
 	struct dn_fib_info *fi = res->fi;
-	struct net_device *dev = rt->u.dst.dev;
+	struct net_device *dev = rt->dst.dev;
 	struct neighbour *n;
 	unsigned mss;
 
@@ -800,25 +800,25 @@
 		if (DN_FIB_RES_GW(*res) &&
 		    DN_FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
 			rt->rt_gateway = DN_FIB_RES_GW(*res);
-		memcpy(rt->u.dst.metrics, fi->fib_metrics,
-		       sizeof(rt->u.dst.metrics));
+		memcpy(rt->dst.metrics, fi->fib_metrics,
+		       sizeof(rt->dst.metrics));
 	}
 	rt->rt_type = res->type;
 
-	if (dev != NULL && rt->u.dst.neighbour == NULL) {
+	if (dev != NULL && rt->dst.neighbour == NULL) {
 		n = __neigh_lookup_errno(&dn_neigh_table, &rt->rt_gateway, dev);
 		if (IS_ERR(n))
 			return PTR_ERR(n);
-		rt->u.dst.neighbour = n;
+		rt->dst.neighbour = n;
 	}
 
-	if (dst_metric(&rt->u.dst, RTAX_MTU) == 0 ||
-	    dst_metric(&rt->u.dst, RTAX_MTU) > rt->u.dst.dev->mtu)
-		rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu;
-	mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->u.dst));
-	if (dst_metric(&rt->u.dst, RTAX_ADVMSS) == 0 ||
-	    dst_metric(&rt->u.dst, RTAX_ADVMSS) > mss)
-		rt->u.dst.metrics[RTAX_ADVMSS-1] = mss;
+	if (dst_metric(&rt->dst, RTAX_MTU) == 0 ||
+	    dst_metric(&rt->dst, RTAX_MTU) > rt->dst.dev->mtu)
+		rt->dst.metrics[RTAX_MTU-1] = rt->dst.dev->mtu;
+	mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->dst));
+	if (dst_metric(&rt->dst, RTAX_ADVMSS) == 0 ||
+	    dst_metric(&rt->dst, RTAX_ADVMSS) > mss)
+		rt->dst.metrics[RTAX_ADVMSS-1] = mss;
 	return 0;
 }
 
@@ -1096,8 +1096,8 @@
 	if (rt == NULL)
 		goto e_nobufs;
 
-	atomic_set(&rt->u.dst.__refcnt, 1);
-	rt->u.dst.flags   = DST_HOST;
+	atomic_set(&rt->dst.__refcnt, 1);
+	rt->dst.flags   = DST_HOST;
 
 	rt->fl.fld_src    = oldflp->fld_src;
 	rt->fl.fld_dst    = oldflp->fld_dst;
@@ -1113,17 +1113,17 @@
 	rt->rt_dst_map    = fl.fld_dst;
 	rt->rt_src_map    = fl.fld_src;
 
-	rt->u.dst.dev = dev_out;
+	rt->dst.dev = dev_out;
 	dev_hold(dev_out);
-	rt->u.dst.neighbour = neigh;
+	rt->dst.neighbour = neigh;
 	neigh = NULL;
 
-	rt->u.dst.lastuse = jiffies;
-	rt->u.dst.output  = dn_output;
-	rt->u.dst.input   = dn_rt_bug;
+	rt->dst.lastuse = jiffies;
+	rt->dst.output  = dn_output;
+	rt->dst.input   = dn_rt_bug;
 	rt->rt_flags      = flags;
 	if (flags & RTCF_LOCAL)
-		rt->u.dst.input = dn_nsp_rx;
+		rt->dst.input = dn_nsp_rx;
 
 	err = dn_rt_set_next_hop(rt, &res);
 	if (err)
@@ -1152,7 +1152,7 @@
 	err = -ENOBUFS;
 	goto done;
 e_neighbour:
-	dst_free(&rt->u.dst);
+	dst_free(&rt->dst);
 	goto e_nobufs;
 }
 
@@ -1168,15 +1168,15 @@
 	if (!(flags & MSG_TRYHARD)) {
 		rcu_read_lock_bh();
 		for (rt = rcu_dereference_bh(dn_rt_hash_table[hash].chain); rt;
-			rt = rcu_dereference_bh(rt->u.dst.dn_next)) {
+			rt = rcu_dereference_bh(rt->dst.dn_next)) {
 			if ((flp->fld_dst == rt->fl.fld_dst) &&
 			    (flp->fld_src == rt->fl.fld_src) &&
 			    (flp->mark == rt->fl.mark) &&
 			    (rt->fl.iif == 0) &&
 			    (rt->fl.oif == flp->oif)) {
-				dst_use(&rt->u.dst, jiffies);
+				dst_use(&rt->dst, jiffies);
 				rcu_read_unlock_bh();
-				*pprt = &rt->u.dst;
+				*pprt = &rt->dst;
 				return 0;
 			}
 		}
@@ -1375,29 +1375,29 @@
 	rt->fl.iif        = in_dev->ifindex;
 	rt->fl.mark       = fl.mark;
 
-	rt->u.dst.flags = DST_HOST;
-	rt->u.dst.neighbour = neigh;
-	rt->u.dst.dev = out_dev;
-	rt->u.dst.lastuse = jiffies;
-	rt->u.dst.output = dn_rt_bug;
+	rt->dst.flags = DST_HOST;
+	rt->dst.neighbour = neigh;
+	rt->dst.dev = out_dev;
+	rt->dst.lastuse = jiffies;
+	rt->dst.output = dn_rt_bug;
 	switch(res.type) {
 		case RTN_UNICAST:
-			rt->u.dst.input = dn_forward;
+			rt->dst.input = dn_forward;
 			break;
 		case RTN_LOCAL:
-			rt->u.dst.output = dn_output;
-			rt->u.dst.input = dn_nsp_rx;
-			rt->u.dst.dev = in_dev;
+			rt->dst.output = dn_output;
+			rt->dst.input = dn_nsp_rx;
+			rt->dst.dev = in_dev;
 			flags |= RTCF_LOCAL;
 			break;
 		default:
 		case RTN_UNREACHABLE:
 		case RTN_BLACKHOLE:
-			rt->u.dst.input = dst_discard;
+			rt->dst.input = dst_discard;
 	}
 	rt->rt_flags = flags;
-	if (rt->u.dst.dev)
-		dev_hold(rt->u.dst.dev);
+	if (rt->dst.dev)
+		dev_hold(rt->dst.dev);
 
 	err = dn_rt_set_next_hop(rt, &res);
 	if (err)
@@ -1405,7 +1405,7 @@
 
 	hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst);
 	dn_insert_route(rt, hash, &rt);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 done:
 	if (neigh)
@@ -1427,7 +1427,7 @@
 	goto done;
 
 e_neighbour:
-	dst_free(&rt->u.dst);
+	dst_free(&rt->dst);
 	goto done;
 }
 
@@ -1442,13 +1442,13 @@
 
 	rcu_read_lock();
 	for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt != NULL;
-	    rt = rcu_dereference(rt->u.dst.dn_next)) {
+	    rt = rcu_dereference(rt->dst.dn_next)) {
 		if ((rt->fl.fld_src == cb->src) &&
 		    (rt->fl.fld_dst == cb->dst) &&
 		    (rt->fl.oif == 0) &&
 		    (rt->fl.mark == skb->mark) &&
 		    (rt->fl.iif == cb->iif)) {
-			dst_use(&rt->u.dst, jiffies);
+			dst_use(&rt->dst, jiffies);
 			rcu_read_unlock();
 			skb_dst_set(skb, (struct dst_entry *)rt);
 			return 0;
@@ -1487,8 +1487,8 @@
 		r->rtm_src_len = 16;
 		RTA_PUT(skb, RTA_SRC, 2, &rt->fl.fld_src);
 	}
-	if (rt->u.dst.dev)
-		RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
+	if (rt->dst.dev)
+		RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->dst.dev->ifindex);
 	/*
 	 * Note to self - change this if input routes reverse direction when
 	 * they deal only with inputs and not with replies like they do
@@ -1497,11 +1497,11 @@
 	RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_local_src);
 	if (rt->rt_daddr != rt->rt_gateway)
 		RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway);
-	if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
+	if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0)
 		goto rtattr_failure;
-	expires = rt->u.dst.expires ? rt->u.dst.expires - jiffies : 0;
-	if (rtnl_put_cacheinfo(skb, &rt->u.dst, 0, 0, 0, expires,
-			       rt->u.dst.error) < 0)
+	expires = rt->dst.expires ? rt->dst.expires - jiffies : 0;
+	if (rtnl_put_cacheinfo(skb, &rt->dst, 0, 0, 0, expires,
+			       rt->dst.error) < 0)
 		goto rtattr_failure;
 	if (rt->fl.iif)
 		RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif);
@@ -1568,8 +1568,8 @@
 		local_bh_enable();
 		memset(cb, 0, sizeof(struct dn_skb_cb));
 		rt = (struct dn_route *)skb_dst(skb);
-		if (!err && -rt->u.dst.error)
-			err = rt->u.dst.error;
+		if (!err && -rt->dst.error)
+			err = rt->dst.error;
 	} else {
 		int oif = 0;
 		if (rta[RTA_OIF - 1])
@@ -1583,7 +1583,7 @@
 	skb->dev = NULL;
 	if (err)
 		goto out_free;
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 	if (rtm->rtm_flags & RTM_F_NOTIFY)
 		rt->rt_flags |= RTCF_NOTIFY;
 
@@ -1632,10 +1632,10 @@
 		rcu_read_lock_bh();
 		for(rt = rcu_dereference_bh(dn_rt_hash_table[h].chain), idx = 0;
 			rt;
-			rt = rcu_dereference_bh(rt->u.dst.dn_next), idx++) {
+			rt = rcu_dereference_bh(rt->dst.dn_next), idx++) {
 			if (idx < s_idx)
 				continue;
-			skb_dst_set(skb, dst_clone(&rt->u.dst));
+			skb_dst_set(skb, dst_clone(&rt->dst));
 			if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid,
 					cb->nlh->nlmsg_seq, RTM_NEWROUTE,
 					1, NLM_F_MULTI) <= 0) {
@@ -1678,7 +1678,7 @@
 {
 	struct dn_rt_cache_iter_state *s = seq->private;
 
-	rt = rt->u.dst.dn_next;
+	rt = rt->dst.dn_next;
 	while(!rt) {
 		rcu_read_unlock_bh();
 		if (--s->bucket < 0)
@@ -1719,12 +1719,12 @@
 	char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN];
 
 	seq_printf(seq, "%-8s %-7s %-7s %04d %04d %04d\n",
-			rt->u.dst.dev ? rt->u.dst.dev->name : "*",
+			rt->dst.dev ? rt->dst.dev->name : "*",
 			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));
+			atomic_read(&rt->dst.__refcnt),
+			rt->dst.__use,
+			(int) dst_metric(&rt->dst, RTAX_RTT));
 	return 0;
 }
 
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 8fdca56..64ca2a6 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -164,10 +164,9 @@
 static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
-	struct mii_ioctl_data *mii_data = if_mii(ifr);
 
 	if (p->phy != NULL)
-		return phy_mii_ioctl(p->phy, mii_data, cmd);
+		return phy_mii_ioctl(p->phy, ifr, cmd);
 
 	return -EOPNOTSUPP;
 }
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 2a5a805..dc54bd0 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -48,7 +48,7 @@
 
 static const struct proto_ops econet_ops;
 static struct hlist_head econet_sklist;
-static DEFINE_RWLOCK(econet_lock);
+static DEFINE_SPINLOCK(econet_lock);
 static DEFINE_MUTEX(econet_mutex);
 
 /* Since there are only 256 possible network numbers (or fewer, depends
@@ -98,16 +98,16 @@
 
 static void econet_remove_socket(struct hlist_head *list, struct sock *sk)
 {
-	write_lock_bh(&econet_lock);
+	spin_lock_bh(&econet_lock);
 	sk_del_node_init(sk);
-	write_unlock_bh(&econet_lock);
+	spin_unlock_bh(&econet_lock);
 }
 
 static void econet_insert_socket(struct hlist_head *list, struct sock *sk)
 {
-	write_lock_bh(&econet_lock);
+	spin_lock_bh(&econet_lock);
 	sk_add_node(sk, list);
-	write_unlock_bh(&econet_lock);
+	spin_unlock_bh(&econet_lock);
 }
 
 /*
@@ -782,15 +782,19 @@
 	struct sock *sk;
 	struct hlist_node *node;
 
+	spin_lock(&econet_lock);
 	sk_for_each(sk, node, &econet_sklist) {
 		struct econet_sock *opt = ec_sk(sk);
 		if ((opt->port == port || opt->port == 0) &&
 		    (opt->station == station || opt->station == 0) &&
-		    (opt->net == net || opt->net == 0))
+		    (opt->net == net || opt->net == 0)) {
+			sock_hold(sk);
 			goto found;
+		}
 	}
 	sk = NULL;
 found:
+	spin_unlock(&econet_lock);
 	return sk;
 }
 
@@ -852,7 +856,7 @@
 {
 	struct iphdr *ip = ip_hdr(skb);
 	unsigned char stn = ntohl(ip->saddr) & 0xff;
-	struct sock *sk;
+	struct sock *sk = NULL;
 	struct sk_buff *newskb;
 	struct ec_device *edev = skb->dev->ec_ptr;
 
@@ -882,10 +886,13 @@
 	}
 
 	aun_send_response(ip->saddr, ah->handle, 3, 0);
+	sock_put(sk);
 	return;
 
 bad:
 	aun_send_response(ip->saddr, ah->handle, 4, 0);
+	if (sk)
+		sock_put(sk);
 }
 
 /*
@@ -1050,7 +1057,7 @@
 static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
 	struct ec_framehdr *hdr;
-	struct sock *sk;
+	struct sock *sk = NULL;
 	struct ec_device *edev = dev->ec_ptr;
 
 	if (!net_eq(dev_net(dev), &init_net))
@@ -1085,10 +1092,12 @@
 	if (ec_queue_packet(sk, skb, edev->net, hdr->src_stn, hdr->cb,
 			    hdr->port))
 		goto drop;
-
+	sock_put(sk);
 	return NET_RX_SUCCESS;
 
 drop:
+	if (sk)
+		sock_put(sk);
 	kfree_skb(skb);
 	return NET_RX_DROP;
 }
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 61ec032..215c839 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -158,7 +158,6 @@
 __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ethhdr *eth;
-	unsigned char *rawp;
 
 	skb->dev = dev;
 	skb_reset_mac_header(skb);
@@ -199,15 +198,13 @@
 	if (ntohs(eth->h_proto) >= 1536)
 		return eth->h_proto;
 
-	rawp = skb->data;
-
 	/*
 	 *      This is a magic hack to spot IPX packets. Older Novell breaks
 	 *      the protocol design and runs IPX over 802.3 without an 802.2 LLC
 	 *      layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
 	 *      won't work for fault tolerant netware but does for the rest.
 	 */
-	if (*(unsigned short *)rawp == 0xFFFF)
+	if (skb->len >= 2 && *(unsigned short *)(skb->data) == 0xFFFF)
 		return htons(ETH_P_802_3);
 
 	/*
diff --git a/net/ethernet/pe2.c b/net/ethernet/pe2.c
index eb00796..85d574a 100644
--- a/net/ethernet/pe2.c
+++ b/net/ethernet/pe2.c
@@ -28,11 +28,10 @@
 
 	return proto;
 }
+EXPORT_SYMBOL(make_EII_client);
 
 void destroy_EII_client(struct datalink_proto *dl)
 {
 	kfree(dl);
 }
-
 EXPORT_SYMBOL(destroy_EII_client);
-EXPORT_SYMBOL(make_EII_client);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 551ce56..6a1100c 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -355,6 +355,8 @@
 	inet = inet_sk(sk);
 	inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
 
+	inet->nodefrag = 0;
+
 	if (SOCK_RAW == sock->type) {
 		inet->inet_num = protocol;
 		if (IPPROTO_RAW == protocol)
@@ -725,28 +727,31 @@
 	sock_rps_record_flow(sk);
 
 	/* We may need to bind the socket. */
-	if (!inet_sk(sk)->inet_num && inet_autobind(sk))
+	if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind &&
+	    inet_autobind(sk))
 		return -EAGAIN;
 
 	return sk->sk_prot->sendmsg(iocb, sk, msg, size);
 }
 EXPORT_SYMBOL(inet_sendmsg);
 
-static ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
-			     size_t size, int flags)
+ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
+		      size_t size, int flags)
 {
 	struct sock *sk = sock->sk;
 
 	sock_rps_record_flow(sk);
 
 	/* We may need to bind the socket. */
-	if (!inet_sk(sk)->inet_num && inet_autobind(sk))
+	if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind &&
+	    inet_autobind(sk))
 		return -EAGAIN;
 
 	if (sk->sk_prot->sendpage)
 		return sk->sk_prot->sendpage(sk, page, offset, size, flags);
 	return sock_no_sendpage(sock, page, offset, size, flags);
 }
+EXPORT_SYMBOL(inet_sendpage);
 
 int inet_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
 		 size_t size, int flags)
@@ -892,10 +897,10 @@
 	.shutdown	   = inet_shutdown,
 	.setsockopt	   = sock_common_setsockopt,
 	.getsockopt	   = sock_common_getsockopt,
-	.sendmsg	   = tcp_sendmsg,
+	.sendmsg	   = inet_sendmsg,
 	.recvmsg	   = inet_recvmsg,
 	.mmap		   = sock_no_mmap,
-	.sendpage	   = tcp_sendpage,
+	.sendpage	   = inet_sendpage,
 	.splice_read	   = tcp_splice_read,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_sock_common_setsockopt,
@@ -1100,7 +1105,7 @@
 	if (err)
 		return err;
 
-	sk_setup_caps(sk, &rt->u.dst);
+	sk_setup_caps(sk, &rt->dst);
 
 	new_saddr = rt->rt_src;
 
@@ -1166,7 +1171,7 @@
 	err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0);
 }
 	if (!err)
-		sk_setup_caps(sk, &rt->u.dst);
+		sk_setup_caps(sk, &rt->dst);
 	else {
 		/* Routing failed... */
 		sk->sk_route_caps = 0;
@@ -1425,13 +1430,49 @@
 }
 EXPORT_SYMBOL_GPL(snmp_fold_field);
 
-int snmp_mib_init(void __percpu *ptr[2], size_t mibsize)
+#if BITS_PER_LONG==32
+
+u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_offset)
+{
+	u64 res = 0;
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		void *bhptr, *userptr;
+		struct u64_stats_sync *syncp;
+		u64 v_bh, v_user;
+		unsigned int start;
+
+		/* first mib used by softirq context, we must use _bh() accessors */
+		bhptr = per_cpu_ptr(SNMP_STAT_BHPTR(mib), cpu);
+		syncp = (struct u64_stats_sync *)(bhptr + syncp_offset);
+		do {
+			start = u64_stats_fetch_begin_bh(syncp);
+			v_bh = *(((u64 *) bhptr) + offt);
+		} while (u64_stats_fetch_retry_bh(syncp, start));
+
+		/* second mib used in USER context */
+		userptr = per_cpu_ptr(SNMP_STAT_USRPTR(mib), cpu);
+		syncp = (struct u64_stats_sync *)(userptr + syncp_offset);
+		do {
+			start = u64_stats_fetch_begin(syncp);
+			v_user = *(((u64 *) userptr) + offt);
+		} while (u64_stats_fetch_retry(syncp, start));
+
+		res += v_bh + v_user;
+	}
+	return res;
+}
+EXPORT_SYMBOL_GPL(snmp_fold_field64);
+#endif
+
+int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align)
 {
 	BUG_ON(ptr == NULL);
-	ptr[0] = __alloc_percpu(mibsize, __alignof__(unsigned long));
+	ptr[0] = __alloc_percpu(mibsize, align);
 	if (!ptr[0])
 		goto err0;
-	ptr[1] = __alloc_percpu(mibsize, __alignof__(unsigned long));
+	ptr[1] = __alloc_percpu(mibsize, align);
 	if (!ptr[1])
 		goto err1;
 	return 0;
@@ -1488,25 +1529,32 @@
 static __net_init int ipv4_mib_init_net(struct net *net)
 {
 	if (snmp_mib_init((void __percpu **)net->mib.tcp_statistics,
-			  sizeof(struct tcp_mib)) < 0)
+			  sizeof(struct tcp_mib),
+			  __alignof__(struct tcp_mib)) < 0)
 		goto err_tcp_mib;
 	if (snmp_mib_init((void __percpu **)net->mib.ip_statistics,
-			  sizeof(struct ipstats_mib)) < 0)
+			  sizeof(struct ipstats_mib),
+			  __alignof__(struct ipstats_mib)) < 0)
 		goto err_ip_mib;
 	if (snmp_mib_init((void __percpu **)net->mib.net_statistics,
-			  sizeof(struct linux_mib)) < 0)
+			  sizeof(struct linux_mib),
+			  __alignof__(struct linux_mib)) < 0)
 		goto err_net_mib;
 	if (snmp_mib_init((void __percpu **)net->mib.udp_statistics,
-			  sizeof(struct udp_mib)) < 0)
+			  sizeof(struct udp_mib),
+			  __alignof__(struct udp_mib)) < 0)
 		goto err_udp_mib;
 	if (snmp_mib_init((void __percpu **)net->mib.udplite_statistics,
-			  sizeof(struct udp_mib)) < 0)
+			  sizeof(struct udp_mib),
+			  __alignof__(struct udp_mib)) < 0)
 		goto err_udplite_mib;
 	if (snmp_mib_init((void __percpu **)net->mib.icmp_statistics,
-			  sizeof(struct icmp_mib)) < 0)
+			  sizeof(struct icmp_mib),
+			  __alignof__(struct icmp_mib)) < 0)
 		goto err_icmp_mib;
 	if (snmp_mib_init((void __percpu **)net->mib.icmpmsg_statistics,
-			  sizeof(struct icmpmsg_mib)) < 0)
+			  sizeof(struct icmpmsg_mib),
+			  __alignof__(struct icmpmsg_mib)) < 0)
 		goto err_icmpmsg_mib;
 
 	tcp_mib_init(net);
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index f094b75..96c1955 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -116,6 +116,7 @@
 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
 #include <net/atmclip.h>
 struct neigh_table *clip_tbl_hook;
+EXPORT_SYMBOL(clip_tbl_hook);
 #endif
 
 #include <asm/system.h>
@@ -169,6 +170,7 @@
 	.hh_output =		dev_queue_xmit,
 	.queue_xmit =		dev_queue_xmit,
 };
+EXPORT_SYMBOL(arp_broken_ops);
 
 struct neigh_table arp_tbl = {
 	.family =	AF_INET,
@@ -198,6 +200,7 @@
 	.gc_thresh2 =	512,
 	.gc_thresh3 =	1024,
 };
+EXPORT_SYMBOL(arp_tbl);
 
 int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir)
 {
@@ -333,11 +336,14 @@
 	struct net_device *dev = neigh->dev;
 	__be32 target = *(__be32*)neigh->primary_key;
 	int probes = atomic_read(&neigh->probes);
-	struct in_device *in_dev = in_dev_get(dev);
+	struct in_device *in_dev;
 
-	if (!in_dev)
+	rcu_read_lock();
+	in_dev = __in_dev_get_rcu(dev);
+	if (!in_dev) {
+		rcu_read_unlock();
 		return;
-
+	}
 	switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
 	default:
 	case 0:		/* By default announce any local IP */
@@ -358,9 +364,8 @@
 	case 2:		/* Avoid secondary IPs, get a primary/preferred one */
 		break;
 	}
+	rcu_read_unlock();
 
-	if (in_dev)
-		in_dev_put(in_dev);
 	if (!saddr)
 		saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
 
@@ -427,7 +432,7 @@
 
 	if (ip_route_output_key(net, &rt, &fl) < 0)
 		return 1;
-	if (rt->u.dst.dev != dev) {
+	if (rt->dst.dev != dev) {
 		NET_INC_STATS_BH(net, LINUX_MIB_ARPFILTER);
 		flag = 1;
 	}
@@ -497,6 +502,7 @@
 		kfree_skb(skb);
 	return 1;
 }
+EXPORT_SYMBOL(arp_find);
 
 /* END OF OBSOLETE FUNCTIONS */
 
@@ -532,7 +538,7 @@
 	struct in_device *out_dev;
 	int imi, omi = -1;
 
-	if (rt->u.dst.dev == dev)
+	if (rt->dst.dev == dev)
 		return 0;
 
 	if (!IN_DEV_PROXY_ARP(in_dev))
@@ -545,10 +551,10 @@
 
 	/* place to check for proxy_arp for routes */
 
-	if ((out_dev = in_dev_get(rt->u.dst.dev)) != NULL) {
+	out_dev = __in_dev_get_rcu(rt->dst.dev);
+	if (out_dev)
 		omi = IN_DEV_MEDIUM_ID(out_dev);
-		in_dev_put(out_dev);
-	}
+
 	return (omi != imi && omi != -1);
 }
 
@@ -576,7 +582,7 @@
 				__be32 sip, __be32 tip)
 {
 	/* Private VLAN is only concerned about the same ethernet segment */
-	if (rt->u.dst.dev != dev)
+	if (rt->dst.dev != dev)
 		return 0;
 
 	/* Don't reply on self probes (often done by windowz boxes)*/
@@ -698,6 +704,7 @@
 	kfree_skb(skb);
 	return NULL;
 }
+EXPORT_SYMBOL(arp_create);
 
 /*
  *	Send an arp packet.
@@ -707,6 +714,7 @@
 	/* Send it off, maybe filter it using firewalling first.  */
 	NF_HOOK(NFPROTO_ARP, NF_ARP_OUT, skb, NULL, skb->dev, dev_queue_xmit);
 }
+EXPORT_SYMBOL(arp_xmit);
 
 /*
  *	Create and send an arp packet.
@@ -733,6 +741,7 @@
 
 	arp_xmit(skb);
 }
+EXPORT_SYMBOL(arp_send);
 
 /*
  *	Process an arp request.
@@ -741,7 +750,7 @@
 static int arp_process(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
-	struct in_device *in_dev = in_dev_get(dev);
+	struct in_device *in_dev = __in_dev_get_rcu(dev);
 	struct arphdr *arp;
 	unsigned char *arp_ptr;
 	struct rtable *rt;
@@ -890,7 +899,6 @@
 					arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
 				} else {
 					pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb);
-					in_dev_put(in_dev);
 					return 0;
 				}
 				goto out;
@@ -936,8 +944,6 @@
 	}
 
 out:
-	if (in_dev)
-		in_dev_put(in_dev);
 	consume_skb(skb);
 	return 0;
 }
@@ -1045,7 +1051,7 @@
 		struct rtable * rt;
 		if ((err = ip_route_output_key(net, &rt, &fl)) != 0)
 			return err;
-		dev = rt->u.dst.dev;
+		dev = rt->dst.dev;
 		ip_rt_put(rt);
 		if (!dev)
 			return -EINVAL;
@@ -1152,7 +1158,7 @@
 		struct rtable * rt;
 		if ((err = ip_route_output_key(net, &rt, &fl)) != 0)
 			return err;
-		dev = rt->u.dst.dev;
+		dev = rt->dst.dev;
 		ip_rt_put(rt);
 		if (!dev)
 			return -EINVAL;
@@ -1453,14 +1459,3 @@
 }
 
 #endif /* CONFIG_PROC_FS */
-
-EXPORT_SYMBOL(arp_broken_ops);
-EXPORT_SYMBOL(arp_find);
-EXPORT_SYMBOL(arp_create);
-EXPORT_SYMBOL(arp_xmit);
-EXPORT_SYMBOL(arp_send);
-EXPORT_SYMBOL(arp_tbl);
-
-#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
-EXPORT_SYMBOL(clip_tbl_hook);
-#endif
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
index fb24658..f055094 100644
--- a/net/ipv4/datagram.c
+++ b/net/ipv4/datagram.c
@@ -69,9 +69,7 @@
 	sk->sk_state = TCP_ESTABLISHED;
 	inet->inet_id = jiffies;
 
-	sk_dst_set(sk, &rt->u.dst);
+	sk_dst_set(sk, &rt->dst);
 	return(0);
 }
-
 EXPORT_SYMBOL(ip4_datagram_connect);
-
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 382bc76..da14c49 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1081,6 +1081,7 @@
 		}
 		ip_mc_up(in_dev);
 		/* fall through */
+	case NETDEV_NOTIFY_PEERS:
 	case NETDEV_CHANGEADDR:
 		/* Send gratuitous ARP to notify of link change */
 		if (IN_DEV_ARP_NOTIFY(in_dev)) {
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 4f0ed45..a439689 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -175,6 +175,7 @@
 	fib_res_put(&res);
 	return dev;
 }
+EXPORT_SYMBOL(ip_dev_find);
 
 /*
  * Find address type as if only "dev" was present in the system. If
@@ -214,12 +215,14 @@
 {
 	return __inet_dev_addr_type(net, NULL, addr);
 }
+EXPORT_SYMBOL(inet_addr_type);
 
 unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
 				__be32 addr)
 {
        return __inet_dev_addr_type(net, dev, addr);
 }
+EXPORT_SYMBOL(inet_dev_addr_type);
 
 /* Given (packet source, input interface) and optional (dst, oif, tos):
    - (main) check, that source is valid i.e. not broadcast or our local
@@ -284,7 +287,7 @@
 	if (no_addr)
 		goto last_resort;
 	if (rpf == 1)
-		goto e_inval;
+		goto e_rpf;
 	fl.oif = dev->ifindex;
 
 	ret = 0;
@@ -299,7 +302,7 @@
 
 last_resort:
 	if (rpf)
-		goto e_inval;
+		goto e_rpf;
 	*spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
 	*itag = 0;
 	return 0;
@@ -308,6 +311,8 @@
 	fib_res_put(&res);
 e_inval:
 	return -EINVAL;
+e_rpf:
+	return -EXDEV;
 }
 
 static inline __be32 sk_extract_addr(struct sockaddr *addr)
@@ -1075,7 +1080,3 @@
 
 	fib_hash_init();
 }
-
-EXPORT_SYMBOL(inet_addr_type);
-EXPORT_SYMBOL(inet_dev_addr_type);
-EXPORT_SYMBOL(ip_dev_find);
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index d65e9215..a0d847c 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -181,6 +181,7 @@
 		.fatal = 1,
 	},
 };
+EXPORT_SYMBOL(icmp_err_convert);
 
 /*
  *	ICMP control array. This specifies what to do with each ICMP.
@@ -267,11 +268,12 @@
 	dst->rate_tokens = token;
 	return rc;
 }
+EXPORT_SYMBOL(xrlim_allow);
 
 static inline int icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
 		int type, int code)
 {
-	struct dst_entry *dst = &rt->u.dst;
+	struct dst_entry *dst = &rt->dst;
 	int rc = 1;
 
 	if (type > NR_ICMP_TYPES)
@@ -327,7 +329,7 @@
 	struct sock *sk;
 	struct sk_buff *skb;
 
-	sk = icmp_sk(dev_net((*rt)->u.dst.dev));
+	sk = icmp_sk(dev_net((*rt)->dst.dev));
 	if (ip_append_data(sk, icmp_glue_bits, icmp_param,
 			   icmp_param->data_len+icmp_param->head_len,
 			   icmp_param->head_len,
@@ -359,7 +361,7 @@
 {
 	struct ipcm_cookie ipc;
 	struct rtable *rt = skb_rtable(skb);
-	struct net *net = dev_net(rt->u.dst.dev);
+	struct net *net = dev_net(rt->dst.dev);
 	struct sock *sk;
 	struct inet_sock *inet;
 	__be32 daddr;
@@ -427,7 +429,7 @@
 
 	if (!rt)
 		goto out;
-	net = dev_net(rt->u.dst.dev);
+	net = dev_net(rt->dst.dev);
 
 	/*
 	 *	Find the original header. It is expected to be valid, of course.
@@ -596,9 +598,9 @@
 			/* Ugh! */
 			orefdst = skb_in->_skb_refdst; /* save old refdst */
 			err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src,
-					     RT_TOS(tos), rt2->u.dst.dev);
+					     RT_TOS(tos), rt2->dst.dev);
 
-			dst_release(&rt2->u.dst);
+			dst_release(&rt2->dst);
 			rt2 = skb_rtable(skb_in);
 			skb_in->_skb_refdst = orefdst; /* restore old refdst */
 		}
@@ -610,7 +612,7 @@
 				  XFRM_LOOKUP_ICMP);
 		switch (err) {
 		case 0:
-			dst_release(&rt->u.dst);
+			dst_release(&rt->dst);
 			rt = rt2;
 			break;
 		case -EPERM:
@@ -629,7 +631,7 @@
 
 	/* RFC says return as much as we can without exceeding 576 bytes. */
 
-	room = dst_mtu(&rt->u.dst);
+	room = dst_mtu(&rt->dst);
 	if (room > 576)
 		room = 576;
 	room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
@@ -647,6 +649,7 @@
 	icmp_xmit_unlock(sk);
 out:;
 }
+EXPORT_SYMBOL(icmp_send);
 
 
 /*
@@ -925,6 +928,7 @@
 /*
  * RFC1812 (4.3.3.9).	A router SHOULD listen all replies, and complain
  *			loudly if an inconsistency is found.
+ * called with rcu_read_lock()
  */
 
 static void icmp_address_reply(struct sk_buff *skb)
@@ -935,12 +939,12 @@
 	struct in_ifaddr *ifa;
 
 	if (skb->len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC))
-		goto out;
+		return;
 
-	in_dev = in_dev_get(dev);
+	in_dev = __in_dev_get_rcu(dev);
 	if (!in_dev)
-		goto out;
-	rcu_read_lock();
+		return;
+
 	if (in_dev->ifa_list &&
 	    IN_DEV_LOG_MARTIANS(in_dev) &&
 	    IN_DEV_FORWARD(in_dev)) {
@@ -958,9 +962,6 @@
 			       mp, dev->name, &rt->rt_src);
 		}
 	}
-	rcu_read_unlock();
-	in_dev_put(in_dev);
-out:;
 }
 
 static void icmp_discard(struct sk_buff *skb)
@@ -974,7 +975,7 @@
 {
 	struct icmphdr *icmph;
 	struct rtable *rt = skb_rtable(skb);
-	struct net *net = dev_net(rt->u.dst.dev);
+	struct net *net = dev_net(rt->dst.dev);
 
 	if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
 		struct sec_path *sp = skb_sec_path(skb);
@@ -1216,7 +1217,3 @@
 {
 	return register_pernet_subsys(&icmp_sk_ops);
 }
-
-EXPORT_SYMBOL(icmp_err_convert);
-EXPORT_SYMBOL(icmp_send);
-EXPORT_SYMBOL(xrlim_allow);
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 5fff865..a1ad0e7 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -312,7 +312,7 @@
 		return NULL;
 	}
 
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 	skb->dev = dev;
 
 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
@@ -330,7 +330,7 @@
 	pip->saddr    = rt->rt_src;
 	pip->protocol = IPPROTO_IGMP;
 	pip->tot_len  = 0;	/* filled in later */
-	ip_select_ident(pip, &rt->u.dst, NULL);
+	ip_select_ident(pip, &rt->dst, NULL);
 	((u8*)&pip[1])[0] = IPOPT_RA;
 	((u8*)&pip[1])[1] = 4;
 	((u8*)&pip[1])[2] = 0;
@@ -660,7 +660,7 @@
 		return -1;
 	}
 
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
 
@@ -676,7 +676,7 @@
 	iph->daddr    = dst;
 	iph->saddr    = rt->rt_src;
 	iph->protocol = IPPROTO_IGMP;
-	ip_select_ident(iph, &rt->u.dst, NULL);
+	ip_select_ident(iph, &rt->dst, NULL);
 	((u8*)&iph[1])[0] = IPOPT_RA;
 	((u8*)&iph[1])[1] = 4;
 	((u8*)&iph[1])[2] = 0;
@@ -916,18 +916,19 @@
 	read_unlock(&in_dev->mc_list_lock);
 }
 
+/* called in rcu_read_lock() section */
 int igmp_rcv(struct sk_buff *skb)
 {
 	/* This basically follows the spec line by line -- see RFC1112 */
 	struct igmphdr *ih;
-	struct in_device *in_dev = in_dev_get(skb->dev);
+	struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
 	int len = skb->len;
 
 	if (in_dev == NULL)
 		goto drop;
 
 	if (!pskb_may_pull(skb, sizeof(struct igmphdr)))
-		goto drop_ref;
+		goto drop;
 
 	switch (skb->ip_summed) {
 	case CHECKSUM_COMPLETE:
@@ -937,7 +938,7 @@
 	case CHECKSUM_NONE:
 		skb->csum = 0;
 		if (__skb_checksum_complete(skb))
-			goto drop_ref;
+			goto drop;
 	}
 
 	ih = igmp_hdr(skb);
@@ -957,7 +958,6 @@
 		break;
 	case IGMP_PIM:
 #ifdef CONFIG_IP_PIMSM_V1
-		in_dev_put(in_dev);
 		return pim_rcv_v1(skb);
 #endif
 	case IGMPV3_HOST_MEMBERSHIP_REPORT:
@@ -971,8 +971,6 @@
 		break;
 	}
 
-drop_ref:
-	in_dev_put(in_dev);
 drop:
 	kfree_skb(skb);
 	return 0;
@@ -1246,6 +1244,7 @@
 out:
 	return;
 }
+EXPORT_SYMBOL(ip_mc_inc_group);
 
 /*
  *	Resend IGMP JOIN report; used for bonding.
@@ -1268,6 +1267,7 @@
 	igmp_ifc_event(in_dev);
 #endif
 }
+EXPORT_SYMBOL(ip_mc_rejoin_group);
 
 /*
  *	A socket has left a multicast group on device dev
@@ -1298,6 +1298,7 @@
 		}
 	}
 }
+EXPORT_SYMBOL(ip_mc_dec_group);
 
 /* Device changing type */
 
@@ -1427,7 +1428,7 @@
 	}
 
 	if (!dev && !ip_route_output_key(net, &rt, &fl)) {
-		dev = rt->u.dst.dev;
+		dev = rt->dst.dev;
 		ip_rt_put(rt);
 	}
 	if (dev) {
@@ -1646,8 +1647,7 @@
 				if (dpsf->sf_inaddr == psf->sf_inaddr)
 					break;
 			if (!dpsf) {
-				dpsf = (struct ip_sf_list *)
-					kmalloc(sizeof(*dpsf), GFP_ATOMIC);
+				dpsf = kmalloc(sizeof(*dpsf), GFP_ATOMIC);
 				if (!dpsf)
 					continue;
 				*dpsf = *psf;
@@ -1807,6 +1807,7 @@
 	rtnl_unlock();
 	return err;
 }
+EXPORT_SYMBOL(ip_mc_join_group);
 
 static void ip_sf_socklist_reclaim(struct rcu_head *rp)
 {
@@ -2679,8 +2680,3 @@
 	return register_pernet_subsys(&igmp_net_ops);
 }
 #endif
-
-EXPORT_SYMBOL(ip_mc_dec_group);
-EXPORT_SYMBOL(ip_mc_inc_group);
-EXPORT_SYMBOL(ip_mc_join_group);
-EXPORT_SYMBOL(ip_mc_rejoin_group);
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 70eb350..7174370 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -84,7 +84,6 @@
 	}
 	return node != NULL;
 }
-
 EXPORT_SYMBOL_GPL(inet_csk_bind_conflict);
 
 /* Obtain a reference to a local port for the given sock,
@@ -212,7 +211,6 @@
 	local_bh_enable();
 	return ret;
 }
-
 EXPORT_SYMBOL_GPL(inet_csk_get_port);
 
 /*
@@ -305,7 +303,6 @@
 	*err = error;
 	goto out;
 }
-
 EXPORT_SYMBOL(inet_csk_accept);
 
 /*
@@ -327,7 +324,6 @@
 	setup_timer(&sk->sk_timer, keepalive_handler, (unsigned long)sk);
 	icsk->icsk_pending = icsk->icsk_ack.pending = 0;
 }
-
 EXPORT_SYMBOL(inet_csk_init_xmit_timers);
 
 void inet_csk_clear_xmit_timers(struct sock *sk)
@@ -340,21 +336,18 @@
 	sk_stop_timer(sk, &icsk->icsk_delack_timer);
 	sk_stop_timer(sk, &sk->sk_timer);
 }
-
 EXPORT_SYMBOL(inet_csk_clear_xmit_timers);
 
 void inet_csk_delete_keepalive_timer(struct sock *sk)
 {
 	sk_stop_timer(sk, &sk->sk_timer);
 }
-
 EXPORT_SYMBOL(inet_csk_delete_keepalive_timer);
 
 void inet_csk_reset_keepalive_timer(struct sock *sk, unsigned long len)
 {
 	sk_reset_timer(sk, &sk->sk_timer, jiffies + len);
 }
-
 EXPORT_SYMBOL(inet_csk_reset_keepalive_timer);
 
 struct dst_entry *inet_csk_route_req(struct sock *sk,
@@ -383,7 +376,7 @@
 		goto no_route;
 	if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
 		goto route_err;
-	return &rt->u.dst;
+	return &rt->dst;
 
 route_err:
 	ip_rt_put(rt);
@@ -391,7 +384,6 @@
 	IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
 	return NULL;
 }
-
 EXPORT_SYMBOL_GPL(inet_csk_route_req);
 
 static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport,
@@ -433,7 +425,6 @@
 
 	return req;
 }
-
 EXPORT_SYMBOL_GPL(inet_csk_search_req);
 
 void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
@@ -447,11 +438,11 @@
 	reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout);
 	inet_csk_reqsk_queue_added(sk, timeout);
 }
+EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_hash_add);
 
 /* Only thing we need from tcp.h */
 extern int sysctl_tcp_synack_retries;
 
-EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_hash_add);
 
 /* Decide when to expire the request and when to resend SYN-ACK */
 static inline void syn_ack_recalc(struct request_sock *req, const int thresh,
@@ -569,7 +560,6 @@
 	if (lopt->qlen)
 		inet_csk_reset_keepalive_timer(parent, interval);
 }
-
 EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_prune);
 
 struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req,
@@ -599,7 +589,6 @@
 	}
 	return newsk;
 }
-
 EXPORT_SYMBOL_GPL(inet_csk_clone);
 
 /*
@@ -630,7 +619,6 @@
 	percpu_counter_dec(sk->sk_prot->orphan_count);
 	sock_put(sk);
 }
-
 EXPORT_SYMBOL(inet_csk_destroy_sock);
 
 int inet_csk_listen_start(struct sock *sk, const int nr_table_entries)
@@ -665,7 +653,6 @@
 	__reqsk_queue_destroy(&icsk->icsk_accept_queue);
 	return -EADDRINUSE;
 }
-
 EXPORT_SYMBOL_GPL(inet_csk_listen_start);
 
 /*
@@ -720,7 +707,6 @@
 	}
 	WARN_ON(sk->sk_ack_backlog);
 }
-
 EXPORT_SYMBOL_GPL(inet_csk_listen_stop);
 
 void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr)
@@ -732,7 +718,6 @@
 	sin->sin_addr.s_addr	= inet->inet_daddr;
 	sin->sin_port		= inet->inet_dport;
 }
-
 EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr);
 
 #ifdef CONFIG_COMPAT
@@ -747,7 +732,6 @@
 	return icsk->icsk_af_ops->getsockopt(sk, level, optname,
 					     optval, optlen);
 }
-
 EXPORT_SYMBOL_GPL(inet_csk_compat_getsockopt);
 
 int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname,
@@ -761,6 +745,5 @@
 	return icsk->icsk_af_ops->setsockopt(sk, level, optname,
 					     optval, optlen);
 }
-
 EXPORT_SYMBOL_GPL(inet_csk_compat_setsockopt);
 #endif
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index a2ca6ae..5ff2a51 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -114,7 +114,6 @@
 		fq->last_in |= INET_FRAG_COMPLETE;
 	}
 }
-
 EXPORT_SYMBOL(inet_frag_kill);
 
 static inline void frag_kfree_skb(struct netns_frags *nf, struct inet_frags *f,
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index d3e160a..fb7ad5a 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -99,7 +99,6 @@
 	__inet_put_port(sk);
 	local_bh_enable();
 }
-
 EXPORT_SYMBOL(inet_put_port);
 
 void __inet_inherit_port(struct sock *sk, struct sock *child)
@@ -116,7 +115,6 @@
 	inet_csk(child)->icsk_bind_hash = tb;
 	spin_unlock(&head->lock);
 }
-
 EXPORT_SYMBOL_GPL(__inet_inherit_port);
 
 static inline int compute_score(struct sock *sk, struct net *net,
@@ -546,7 +544,6 @@
 	return __inet_hash_connect(death_row, sk, inet_sk_port_offset(sk),
 			__inet_check_established, __inet_hash_nolisten);
 }
-
 EXPORT_SYMBOL_GPL(inet_hash_connect);
 
 void inet_hashinfo_init(struct inet_hashinfo *h)
@@ -560,5 +557,4 @@
 				      i + LISTENING_NULLS_BASE);
 		}
 }
-
 EXPORT_SYMBOL_GPL(inet_hashinfo_init);
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index 6bcfe52..9ffa24b 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -51,8 +51,8 @@
  *  lookups performed with disabled BHs.
  *
  *  Serialisation issues.
- *  1.  Nodes may appear in the tree only with the pool write lock held.
- *  2.  Nodes may disappear from the tree only with the pool write lock held
+ *  1.  Nodes may appear in the tree only with the pool lock held.
+ *  2.  Nodes may disappear from the tree only with the pool lock held
  *      AND reference count being 0.
  *  3.  Nodes appears and disappears from unused node list only under
  *      "inet_peer_unused_lock".
@@ -64,23 +64,31 @@
  *		   usually under some other lock to prevent node disappearing
  *		dtime: unused node list lock
  *		v4daddr: unchangeable
- *		ip_id_count: idlock
+ *		ip_id_count: atomic value (no lock needed)
  */
 
 static struct kmem_cache *peer_cachep __read_mostly;
 
 #define node_height(x) x->avl_height
-static struct inet_peer peer_fake_node = {
-	.avl_left	= &peer_fake_node,
-	.avl_right	= &peer_fake_node,
+
+#define peer_avl_empty ((struct inet_peer *)&peer_fake_node)
+static const struct inet_peer peer_fake_node = {
+	.avl_left	= peer_avl_empty,
+	.avl_right	= peer_avl_empty,
 	.avl_height	= 0
 };
-#define peer_avl_empty (&peer_fake_node)
-static struct inet_peer *peer_root = peer_avl_empty;
-static DEFINE_RWLOCK(peer_pool_lock);
+
+static struct {
+	struct inet_peer *root;
+	spinlock_t	lock;
+	int		total;
+} peers = {
+	.root		= peer_avl_empty,
+	.lock		= __SPIN_LOCK_UNLOCKED(peers.lock),
+	.total		= 0,
+};
 #define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */
 
-static int peer_total;
 /* Exported for sysctl_net_ipv4.  */
 int inet_peer_threshold __read_mostly = 65536 + 128;	/* start to throw entries more
 					 * aggressively at this stage */
@@ -89,8 +97,13 @@
 int inet_peer_gc_mintime __read_mostly = 10 * HZ;
 int inet_peer_gc_maxtime __read_mostly = 120 * HZ;
 
-static LIST_HEAD(unused_peers);
-static DEFINE_SPINLOCK(inet_peer_unused_lock);
+static struct {
+	struct list_head	list;
+	spinlock_t		lock;
+} unused_peers = {
+	.list			= LIST_HEAD_INIT(unused_peers.list),
+	.lock			= __SPIN_LOCK_UNLOCKED(unused_peers.lock),
+};
 
 static void peer_check_expire(unsigned long dummy);
 static DEFINE_TIMER(peer_periodic_timer, peer_check_expire, 0, 0);
@@ -116,7 +129,7 @@
 
 	peer_cachep = kmem_cache_create("inet_peer_cache",
 			sizeof(struct inet_peer),
-			0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+			0, SLAB_HWCACHE_ALIGN | SLAB_PANIC,
 			NULL);
 
 	/* All the timers, started at system startup tend
@@ -131,38 +144,69 @@
 /* Called with or without local BH being disabled. */
 static void unlink_from_unused(struct inet_peer *p)
 {
-	spin_lock_bh(&inet_peer_unused_lock);
-	list_del_init(&p->unused);
-	spin_unlock_bh(&inet_peer_unused_lock);
+	if (!list_empty(&p->unused)) {
+		spin_lock_bh(&unused_peers.lock);
+		list_del_init(&p->unused);
+		spin_unlock_bh(&unused_peers.lock);
+	}
 }
 
 /*
  * Called with local BH disabled and the pool lock held.
- * _stack is known to be NULL or not at compile time,
- * so compiler will optimize the if (_stack) tests.
  */
 #define lookup(_daddr, _stack) 					\
 ({								\
 	struct inet_peer *u, **v;				\
-	if (_stack != NULL) {					\
-		stackptr = _stack;				\
-		*stackptr++ = &peer_root;			\
-	}							\
-	for (u = peer_root; u != peer_avl_empty; ) {		\
+								\
+	stackptr = _stack;					\
+	*stackptr++ = &peers.root;				\
+	for (u = peers.root; u != peer_avl_empty; ) {		\
 		if (_daddr == u->v4daddr)			\
 			break;					\
 		if ((__force __u32)_daddr < (__force __u32)u->v4daddr)	\
 			v = &u->avl_left;			\
 		else						\
 			v = &u->avl_right;			\
-		if (_stack != NULL)				\
-			*stackptr++ = v;			\
+		*stackptr++ = v;				\
 		u = *v;						\
 	}							\
 	u;							\
 })
 
-/* Called with local BH disabled and the pool write lock held. */
+/*
+ * Called with rcu_read_lock_bh()
+ * Because we hold no lock against a writer, its quite possible we fall
+ * in an endless loop.
+ * But every pointer we follow is guaranteed to be valid thanks to RCU.
+ * We exit from this function if number of links exceeds PEER_MAXDEPTH
+ */
+static struct inet_peer *lookup_rcu_bh(__be32 daddr)
+{
+	struct inet_peer *u = rcu_dereference_bh(peers.root);
+	int count = 0;
+
+	while (u != peer_avl_empty) {
+		if (daddr == u->v4daddr) {
+			/* Before taking a reference, check if this entry was
+			 * deleted, unlink_from_pool() sets refcnt=-1 to make
+			 * distinction between an unused entry (refcnt=0) and
+			 * a freed one.
+			 */
+			if (unlikely(!atomic_add_unless(&u->refcnt, 1, -1)))
+				u = NULL;
+			return u;
+		}
+		if ((__force __u32)daddr < (__force __u32)u->v4daddr)
+			u = rcu_dereference_bh(u->avl_left);
+		else
+			u = rcu_dereference_bh(u->avl_right);
+		if (unlikely(++count == PEER_MAXDEPTH))
+			break;
+	}
+	return NULL;
+}
+
+/* Called with local BH disabled and the pool lock held. */
 #define lookup_rightempty(start)				\
 ({								\
 	struct inet_peer *u, **v;				\
@@ -176,9 +220,10 @@
 	u;							\
 })
 
-/* Called with local BH disabled and the pool write lock held.
+/* Called with local BH disabled and the pool lock held.
  * Variable names are the proof of operation correctness.
- * Look into mm/map_avl.c for more detail description of the ideas.  */
+ * Look into mm/map_avl.c for more detail description of the ideas.
+ */
 static void peer_avl_rebalance(struct inet_peer **stack[],
 		struct inet_peer ***stackend)
 {
@@ -254,15 +299,21 @@
 	}
 }
 
-/* Called with local BH disabled and the pool write lock held. */
+/* Called with local BH disabled and the pool lock held. */
 #define link_to_pool(n)						\
 do {								\
 	n->avl_height = 1;					\
 	n->avl_left = peer_avl_empty;				\
 	n->avl_right = peer_avl_empty;				\
+	smp_wmb(); /* lockless readers can catch us now */	\
 	**--stackptr = n;					\
 	peer_avl_rebalance(stack, stackptr);			\
-} while(0)
+} while (0)
+
+static void inetpeer_free_rcu(struct rcu_head *head)
+{
+	kmem_cache_free(peer_cachep, container_of(head, struct inet_peer, rcu));
+}
 
 /* May be called with local BH enabled. */
 static void unlink_from_pool(struct inet_peer *p)
@@ -271,13 +322,14 @@
 
 	do_free = 0;
 
-	write_lock_bh(&peer_pool_lock);
+	spin_lock_bh(&peers.lock);
 	/* Check the reference counter.  It was artificially incremented by 1
-	 * in cleanup() function to prevent sudden disappearing.  If the
-	 * reference count is still 1 then the node is referenced only as `p'
-	 * here and from the pool.  So under the exclusive pool lock it's safe
-	 * to remove the node and free it later. */
-	if (atomic_read(&p->refcnt) == 1) {
+	 * in cleanup() function to prevent sudden disappearing.  If we can
+	 * atomically (because of lockless readers) take this last reference,
+	 * it's safe to remove the node and free it later.
+	 * We use refcnt=-1 to alert lockless readers this entry is deleted.
+	 */
+	if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) {
 		struct inet_peer **stack[PEER_MAXDEPTH];
 		struct inet_peer ***stackptr, ***delp;
 		if (lookup(p->v4daddr, stack) != p)
@@ -303,20 +355,21 @@
 			delp[1] = &t->avl_left; /* was &p->avl_left */
 		}
 		peer_avl_rebalance(stack, stackptr);
-		peer_total--;
+		peers.total--;
 		do_free = 1;
 	}
-	write_unlock_bh(&peer_pool_lock);
+	spin_unlock_bh(&peers.lock);
 
 	if (do_free)
-		kmem_cache_free(peer_cachep, p);
+		call_rcu_bh(&p->rcu, inetpeer_free_rcu);
 	else
 		/* The node is used again.  Decrease the reference counter
 		 * back.  The loop "cleanup -> unlink_from_unused
 		 *   -> unlink_from_pool -> putpeer -> link_to_unused
 		 *   -> cleanup (for the same node)"
 		 * doesn't really exist because the entry will have a
-		 * recent deletion time and will not be cleaned again soon. */
+		 * recent deletion time and will not be cleaned again soon.
+		 */
 		inet_putpeer(p);
 }
 
@@ -326,16 +379,16 @@
 	struct inet_peer *p = NULL;
 
 	/* Remove the first entry from the list of unused nodes. */
-	spin_lock_bh(&inet_peer_unused_lock);
-	if (!list_empty(&unused_peers)) {
+	spin_lock_bh(&unused_peers.lock);
+	if (!list_empty(&unused_peers.list)) {
 		__u32 delta;
 
-		p = list_first_entry(&unused_peers, struct inet_peer, unused);
+		p = list_first_entry(&unused_peers.list, struct inet_peer, unused);
 		delta = (__u32)jiffies - p->dtime;
 
 		if (delta < ttl) {
 			/* Do not prune fresh entries. */
-			spin_unlock_bh(&inet_peer_unused_lock);
+			spin_unlock_bh(&unused_peers.lock);
 			return -1;
 		}
 
@@ -345,7 +398,7 @@
 		 * before unlink_from_pool() call. */
 		atomic_inc(&p->refcnt);
 	}
-	spin_unlock_bh(&inet_peer_unused_lock);
+	spin_unlock_bh(&unused_peers.lock);
 
 	if (p == NULL)
 		/* It means that the total number of USED entries has
@@ -360,62 +413,56 @@
 /* Called with or without local BH being disabled. */
 struct inet_peer *inet_getpeer(__be32 daddr, int create)
 {
-	struct inet_peer *p, *n;
+	struct inet_peer *p;
 	struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr;
 
-	/* Look up for the address quickly. */
-	read_lock_bh(&peer_pool_lock);
-	p = lookup(daddr, NULL);
-	if (p != peer_avl_empty)
-		atomic_inc(&p->refcnt);
-	read_unlock_bh(&peer_pool_lock);
+	/* Look up for the address quickly, lockless.
+	 * Because of a concurrent writer, we might not find an existing entry.
+	 */
+	rcu_read_lock_bh();
+	p = lookup_rcu_bh(daddr);
+	rcu_read_unlock_bh();
 
-	if (p != peer_avl_empty) {
-		/* The existing node has been found. */
-		/* Remove the entry from unused list if it was there. */
+	if (p) {
+		/* The existing node has been found.
+		 * Remove the entry from unused list if it was there.
+		 */
 		unlink_from_unused(p);
 		return p;
 	}
 
-	if (!create)
-		return NULL;
-
-	/* Allocate the space outside the locked region. */
-	n = kmem_cache_alloc(peer_cachep, GFP_ATOMIC);
-	if (n == NULL)
-		return NULL;
-	n->v4daddr = daddr;
-	atomic_set(&n->refcnt, 1);
-	atomic_set(&n->rid, 0);
-	atomic_set(&n->ip_id_count, secure_ip_id(daddr));
-	n->tcp_ts_stamp = 0;
-
-	write_lock_bh(&peer_pool_lock);
-	/* Check if an entry has suddenly appeared. */
+	/* retry an exact lookup, taking the lock before.
+	 * At least, nodes should be hot in our cache.
+	 */
+	spin_lock_bh(&peers.lock);
 	p = lookup(daddr, stack);
-	if (p != peer_avl_empty)
-		goto out_free;
+	if (p != peer_avl_empty) {
+		atomic_inc(&p->refcnt);
+		spin_unlock_bh(&peers.lock);
+		/* Remove the entry from unused list if it was there. */
+		unlink_from_unused(p);
+		return p;
+	}
+	p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL;
+	if (p) {
+		p->v4daddr = daddr;
+		atomic_set(&p->refcnt, 1);
+		atomic_set(&p->rid, 0);
+		atomic_set(&p->ip_id_count, secure_ip_id(daddr));
+		p->tcp_ts_stamp = 0;
+		INIT_LIST_HEAD(&p->unused);
 
-	/* Link the node. */
-	link_to_pool(n);
-	INIT_LIST_HEAD(&n->unused);
-	peer_total++;
-	write_unlock_bh(&peer_pool_lock);
 
-	if (peer_total >= inet_peer_threshold)
+		/* Link the node. */
+		link_to_pool(p);
+		peers.total++;
+	}
+	spin_unlock_bh(&peers.lock);
+
+	if (peers.total >= inet_peer_threshold)
 		/* Remove one less-recently-used entry. */
 		cleanup_once(0);
 
-	return n;
-
-out_free:
-	/* The appropriate node is already in the pool. */
-	atomic_inc(&p->refcnt);
-	write_unlock_bh(&peer_pool_lock);
-	/* Remove the entry from unused list if it was there. */
-	unlink_from_unused(p);
-	/* Free preallocated the preallocated node. */
-	kmem_cache_free(peer_cachep, n);
 	return p;
 }
 
@@ -425,12 +472,12 @@
 	unsigned long now = jiffies;
 	int ttl;
 
-	if (peer_total >= inet_peer_threshold)
+	if (peers.total >= inet_peer_threshold)
 		ttl = inet_peer_minttl;
 	else
 		ttl = inet_peer_maxttl
 				- (inet_peer_maxttl - inet_peer_minttl) / HZ *
-					peer_total / inet_peer_threshold * HZ;
+					peers.total / inet_peer_threshold * HZ;
 	while (!cleanup_once(ttl)) {
 		if (jiffies != now)
 			break;
@@ -439,22 +486,25 @@
 	/* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime
 	 * interval depending on the total number of entries (more entries,
 	 * less interval). */
-	if (peer_total >= inet_peer_threshold)
+	if (peers.total >= inet_peer_threshold)
 		peer_periodic_timer.expires = jiffies + inet_peer_gc_mintime;
 	else
 		peer_periodic_timer.expires = jiffies
 			+ inet_peer_gc_maxtime
 			- (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ *
-				peer_total / inet_peer_threshold * HZ;
+				peers.total / inet_peer_threshold * HZ;
 	add_timer(&peer_periodic_timer);
 }
 
 void inet_putpeer(struct inet_peer *p)
 {
-	spin_lock_bh(&inet_peer_unused_lock);
-	if (atomic_dec_and_test(&p->refcnt)) {
-		list_add_tail(&p->unused, &unused_peers);
+	local_bh_disable();
+
+	if (atomic_dec_and_lock(&p->refcnt, &unused_peers.lock)) {
+		list_add_tail(&p->unused, &unused_peers.list);
 		p->dtime = (__u32)jiffies;
+		spin_unlock(&unused_peers.lock);
 	}
-	spin_unlock_bh(&inet_peer_unused_lock);
+
+	local_bh_enable();
 }
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index 56cdf68..99461f0 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -87,16 +87,16 @@
 	if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
 		goto sr_failed;
 
-	if (unlikely(skb->len > dst_mtu(&rt->u.dst) && !skb_is_gso(skb) &&
+	if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) &&
 		     (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
-		IP_INC_STATS(dev_net(rt->u.dst.dev), IPSTATS_MIB_FRAGFAILS);
+		IP_INC_STATS(dev_net(rt->dst.dev), IPSTATS_MIB_FRAGFAILS);
 		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-			  htonl(dst_mtu(&rt->u.dst)));
+			  htonl(dst_mtu(&rt->dst)));
 		goto drop;
 	}
 
 	/* We are about to mangle packet. Copy it! */
-	if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+rt->u.dst.header_len))
+	if (skb_cow(skb, LL_RESERVED_SPACE(rt->dst.dev)+rt->dst.header_len))
 		goto drop;
 	iph = ip_hdr(skb);
 
@@ -113,7 +113,7 @@
 	skb->priority = rt_tos2priority(iph->tos);
 
 	return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev,
-		       rt->u.dst.dev, ip_forward_finish);
+		       rt->dst.dev, ip_forward_finish);
 
 sr_failed:
 	/*
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 75347ea..b7c4165 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -124,11 +124,8 @@
 }
 
 /* Memory Tracking Functions. */
-static __inline__ void frag_kfree_skb(struct netns_frags *nf,
-		struct sk_buff *skb, int *work)
+static void frag_kfree_skb(struct netns_frags *nf, struct sk_buff *skb)
 {
-	if (work)
-		*work -= skb->truesize;
 	atomic_sub(skb->truesize, &nf->mem);
 	kfree_skb(skb);
 }
@@ -309,7 +306,7 @@
 	fp = qp->q.fragments;
 	do {
 		struct sk_buff *xp = fp->next;
-		frag_kfree_skb(qp->q.net, fp, NULL);
+		frag_kfree_skb(qp->q.net, fp);
 		fp = xp;
 	} while (fp);
 
@@ -317,6 +314,7 @@
 	qp->q.len = 0;
 	qp->q.meat = 0;
 	qp->q.fragments = NULL;
+	qp->q.fragments_tail = NULL;
 	qp->iif = 0;
 
 	return 0;
@@ -389,6 +387,11 @@
 	 * in the chain of fragments so far.  We must know where to put
 	 * this fragment, right?
 	 */
+	prev = qp->q.fragments_tail;
+	if (!prev || FRAG_CB(prev)->offset < offset) {
+		next = NULL;
+		goto found;
+	}
 	prev = NULL;
 	for (next = qp->q.fragments; next != NULL; next = next->next) {
 		if (FRAG_CB(next)->offset >= offset)
@@ -396,6 +399,7 @@
 		prev = next;
 	}
 
+found:
 	/* We found where to put this one.  Check for overlap with
 	 * preceding fragment, and, if needed, align things so that
 	 * any overlaps are eliminated.
@@ -446,7 +450,7 @@
 				qp->q.fragments = next;
 
 			qp->q.meat -= free_it->len;
-			frag_kfree_skb(qp->q.net, free_it, NULL);
+			frag_kfree_skb(qp->q.net, free_it);
 		}
 	}
 
@@ -454,6 +458,8 @@
 
 	/* Insert this fragment in the chain of fragments. */
 	skb->next = next;
+	if (!next)
+		qp->q.fragments_tail = skb;
 	if (prev)
 		prev->next = skb;
 	else
@@ -507,6 +513,8 @@
 			goto out_nomem;
 
 		fp->next = head->next;
+		if (!fp->next)
+			qp->q.fragments_tail = fp;
 		prev->next = fp;
 
 		skb_morph(head, qp->q.fragments);
@@ -556,7 +564,6 @@
 
 	skb_shinfo(head)->frag_list = head->next;
 	skb_push(head, head->data - skb_network_header(head));
-	atomic_sub(head->truesize, &qp->q.net->mem);
 
 	for (fp=head->next; fp; fp = fp->next) {
 		head->data_len += fp->len;
@@ -566,8 +573,8 @@
 		else if (head->ip_summed == CHECKSUM_COMPLETE)
 			head->csum = csum_add(head->csum, fp->csum);
 		head->truesize += fp->truesize;
-		atomic_sub(fp->truesize, &qp->q.net->mem);
 	}
+	atomic_sub(head->truesize, &qp->q.net->mem);
 
 	head->next = NULL;
 	head->dev = dev;
@@ -578,6 +585,7 @@
 	iph->tot_len = htons(len);
 	IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
 	qp->q.fragments = NULL;
+	qp->q.fragments_tail = NULL;
 	return 0;
 
 out_nomem:
@@ -624,6 +632,7 @@
 	kfree_skb(skb);
 	return -ENOMEM;
 }
+EXPORT_SYMBOL(ip_defrag);
 
 #ifdef CONFIG_SYSCTL
 static int zero;
@@ -777,5 +786,3 @@
 	ip4_frags.secret_interval = 10 * 60 * HZ;
 	inet_frags_init(&ip4_frags);
 }
-
-EXPORT_SYMBOL(ip_defrag);
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 32618e1..945b20a 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -731,6 +731,8 @@
 		tos = 0;
 		if (skb->protocol == htons(ETH_P_IP))
 			tos = old_iph->tos;
+		else if (skb->protocol == htons(ETH_P_IPV6))
+			tos = ipv6_get_dsfield((struct ipv6hdr *)old_iph);
 	}
 
 	{
@@ -745,7 +747,7 @@
 			goto tx_error;
 		}
 	}
-	tdev = rt->u.dst.dev;
+	tdev = rt->dst.dev;
 
 	if (tdev == dev) {
 		ip_rt_put(rt);
@@ -755,7 +757,7 @@
 
 	df = tiph->frag_off;
 	if (df)
-		mtu = dst_mtu(&rt->u.dst) - dev->hard_header_len - tunnel->hlen;
+		mtu = dst_mtu(&rt->dst) - dev->hard_header_len - tunnel->hlen;
 	else
 		mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
 
@@ -803,7 +805,7 @@
 			tunnel->err_count = 0;
 	}
 
-	max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->u.dst.header_len;
+	max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->dst.header_len;
 
 	if (skb_headroom(skb) < max_headroom || skb_shared(skb)||
 	    (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
@@ -830,7 +832,7 @@
 	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
 			      IPSKB_REROUTED);
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	/*
 	 *	Push down and install the IPIP header.
@@ -853,7 +855,7 @@
 			iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit;
 #endif
 		else
-			iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT);
+			iph->ttl = dst_metric(&rt->dst, RTAX_HOPLIMIT);
 	}
 
 	((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags;
@@ -915,7 +917,7 @@
 				    .proto = IPPROTO_GRE };
 		struct rtable *rt;
 		if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
-			tdev = rt->u.dst.dev;
+			tdev = rt->dst.dev;
 			ip_rt_put(rt);
 		}
 
@@ -1174,7 +1176,7 @@
 		struct rtable *rt;
 		if (ip_route_output_key(dev_net(dev), &rt, &fl))
 			return -EADDRNOTAVAIL;
-		dev = rt->u.dst.dev;
+		dev = rt->dst.dev;
 		ip_rt_put(rt);
 		if (__in_dev_get_rtnl(dev) == NULL)
 			return -EADDRNOTAVAIL;
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index d930dc5..d859bcc 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -146,7 +146,7 @@
 #include <linux/netlink.h>
 
 /*
- *	Process Router Attention IP option
+ *	Process Router Attention IP option (RFC 2113)
  */
 int ip_call_ra_chain(struct sk_buff *skb)
 {
@@ -155,8 +155,7 @@
 	struct sock *last = NULL;
 	struct net_device *dev = skb->dev;
 
-	read_lock(&ip_ra_lock);
-	for (ra = ip_ra_chain; ra; ra = ra->next) {
+	for (ra = rcu_dereference(ip_ra_chain); ra; ra = rcu_dereference(ra->next)) {
 		struct sock *sk = ra->sk;
 
 		/* If socket is bound to an interface, only report
@@ -167,10 +166,8 @@
 		     sk->sk_bound_dev_if == dev->ifindex) &&
 		    net_eq(sock_net(sk), dev_net(dev))) {
 			if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
-				if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) {
-					read_unlock(&ip_ra_lock);
+				if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN))
 					return 1;
-				}
 			}
 			if (last) {
 				struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
@@ -183,10 +180,8 @@
 
 	if (last) {
 		raw_rcv(last, skb);
-		read_unlock(&ip_ra_lock);
 		return 1;
 	}
-	read_unlock(&ip_ra_lock);
 	return 0;
 }
 
@@ -298,18 +293,16 @@
 	}
 
 	if (unlikely(opt->srr)) {
-		struct in_device *in_dev = in_dev_get(dev);
+		struct in_device *in_dev = __in_dev_get_rcu(dev);
+
 		if (in_dev) {
 			if (!IN_DEV_SOURCE_ROUTE(in_dev)) {
 				if (IN_DEV_LOG_MARTIANS(in_dev) &&
 				    net_ratelimit())
 					printk(KERN_INFO "source route option %pI4 -> %pI4\n",
 					       &iph->saddr, &iph->daddr);
-				in_dev_put(in_dev);
 				goto drop;
 			}
-
-			in_dev_put(in_dev);
 		}
 
 		if (ip_options_rcv_srr(skb))
@@ -340,13 +333,16 @@
 			else if (err == -ENETUNREACH)
 				IP_INC_STATS_BH(dev_net(skb->dev),
 						IPSTATS_MIB_INNOROUTES);
+			else if (err == -EXDEV)
+				NET_INC_STATS_BH(dev_net(skb->dev),
+						 LINUX_MIB_IPRPFILTER);
 			goto drop;
 		}
 	}
 
 #ifdef CONFIG_NET_CLS_ROUTE
 	if (unlikely(skb_dst(skb)->tclassid)) {
-		struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id());
+		struct ip_rt_acct *st = this_cpu_ptr(ip_rt_acct);
 		u32 idx = skb_dst(skb)->tclassid;
 		st[idx&0xFF].o_packets++;
 		st[idx&0xFF].o_bytes += skb->len;
@@ -360,10 +356,10 @@
 
 	rt = skb_rtable(skb);
 	if (rt->rt_type == RTN_MULTICAST) {
-		IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCAST,
+		IP_UPD_PO_STATS_BH(dev_net(rt->dst.dev), IPSTATS_MIB_INMCAST,
 				skb->len);
 	} else if (rt->rt_type == RTN_BROADCAST)
-		IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCAST,
+		IP_UPD_PO_STATS_BH(dev_net(rt->dst.dev), IPSTATS_MIB_INBCAST,
 				skb->len);
 
 	return dst_input(skb);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 041d41d..04b6989 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -89,6 +89,7 @@
 	iph->check = 0;
 	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 }
+EXPORT_SYMBOL(ip_send_check);
 
 int __ip_local_out(struct sk_buff *skb)
 {
@@ -151,15 +152,15 @@
 	iph->version  = 4;
 	iph->ihl      = 5;
 	iph->tos      = inet->tos;
-	if (ip_dont_fragment(sk, &rt->u.dst))
+	if (ip_dont_fragment(sk, &rt->dst))
 		iph->frag_off = htons(IP_DF);
 	else
 		iph->frag_off = 0;
-	iph->ttl      = ip_select_ttl(inet, &rt->u.dst);
+	iph->ttl      = ip_select_ttl(inet, &rt->dst);
 	iph->daddr    = rt->rt_dst;
 	iph->saddr    = rt->rt_src;
 	iph->protocol = sk->sk_protocol;
-	ip_select_ident(iph, &rt->u.dst, sk);
+	ip_select_ident(iph, &rt->dst, sk);
 
 	if (opt && opt->optlen) {
 		iph->ihl += opt->optlen>>2;
@@ -172,7 +173,6 @@
 	/* Send it out. */
 	return ip_local_out(skb);
 }
-
 EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
 
 static inline int ip_finish_output2(struct sk_buff *skb)
@@ -240,7 +240,7 @@
 {
 	struct sock *sk = skb->sk;
 	struct rtable *rt = skb_rtable(skb);
-	struct net_device *dev = rt->u.dst.dev;
+	struct net_device *dev = rt->dst.dev;
 
 	/*
 	 *	If the indicated interface is up and running, send the packet.
@@ -359,9 +359,9 @@
 			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0))
 				goto no_route;
 		}
-		sk_setup_caps(sk, &rt->u.dst);
+		sk_setup_caps(sk, &rt->dst);
 	}
-	skb_dst_set_noref(skb, &rt->u.dst);
+	skb_dst_set_noref(skb, &rt->dst);
 
 packet_routed:
 	if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
@@ -372,11 +372,11 @@
 	skb_reset_network_header(skb);
 	iph = ip_hdr(skb);
 	*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
-	if (ip_dont_fragment(sk, &rt->u.dst) && !skb->local_df)
+	if (ip_dont_fragment(sk, &rt->dst) && !skb->local_df)
 		iph->frag_off = htons(IP_DF);
 	else
 		iph->frag_off = 0;
-	iph->ttl      = ip_select_ttl(inet, &rt->u.dst);
+	iph->ttl      = ip_select_ttl(inet, &rt->dst);
 	iph->protocol = sk->sk_protocol;
 	iph->saddr    = rt->rt_src;
 	iph->daddr    = rt->rt_dst;
@@ -387,7 +387,7 @@
 		ip_options_build(skb, opt, inet->inet_daddr, rt, 0);
 	}
 
-	ip_select_ident_more(iph, &rt->u.dst, sk,
+	ip_select_ident_more(iph, &rt->dst, sk,
 			     (skb_shinfo(skb)->gso_segs ?: 1) - 1);
 
 	skb->priority = sk->sk_priority;
@@ -403,6 +403,7 @@
 	kfree_skb(skb);
 	return -EHOSTUNREACH;
 }
+EXPORT_SYMBOL(ip_queue_xmit);
 
 
 static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
@@ -411,7 +412,7 @@
 	to->priority = from->priority;
 	to->protocol = from->protocol;
 	skb_dst_drop(to);
-	skb_dst_set(to, dst_clone(skb_dst(from)));
+	skb_dst_copy(to, from);
 	to->dev = from->dev;
 	to->mark = from->mark;
 
@@ -442,17 +443,16 @@
 int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 {
 	struct iphdr *iph;
-	int raw = 0;
 	int ptr;
 	struct net_device *dev;
 	struct sk_buff *skb2;
-	unsigned int mtu, hlen, left, len, ll_rs, pad;
+	unsigned int mtu, hlen, left, len, ll_rs;
 	int offset;
 	__be16 not_last_frag;
 	struct rtable *rt = skb_rtable(skb);
 	int err = 0;
 
-	dev = rt->u.dst.dev;
+	dev = rt->dst.dev;
 
 	/*
 	 *	Point into the IP datagram header.
@@ -473,7 +473,7 @@
 	 */
 
 	hlen = iph->ihl * 4;
-	mtu = dst_mtu(&rt->u.dst) - hlen;	/* Size of data space */
+	mtu = dst_mtu(&rt->dst) - hlen;	/* Size of data space */
 #ifdef CONFIG_BRIDGE_NETFILTER
 	if (skb->nf_bridge)
 		mtu -= nf_bridge_mtu_reduction(skb);
@@ -580,14 +580,12 @@
 
 slow_path:
 	left = skb->len - hlen;		/* Space per frame */
-	ptr = raw + hlen;		/* Where to start from */
+	ptr = hlen;		/* Where to start from */
 
 	/* for bridged IP traffic encapsulated inside f.e. a vlan header,
 	 * we need to make room for the encapsulating header
 	 */
-	pad = nf_bridge_pad(skb);
-	ll_rs = LL_RESERVED_SPACE_EXTRA(rt->u.dst.dev, pad);
-	mtu -= pad;
+	ll_rs = LL_RESERVED_SPACE_EXTRA(rt->dst.dev, nf_bridge_pad(skb));
 
 	/*
 	 *	Fragment the datagram.
@@ -697,7 +695,6 @@
 	IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
 	return err;
 }
-
 EXPORT_SYMBOL(ip_fragment);
 
 int
@@ -716,6 +713,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL(ip_generic_getfrag);
 
 static inline __wsum
 csum_page(struct page *page, int offset, int copy)
@@ -833,13 +831,13 @@
 		 */
 		*rtp = NULL;
 		inet->cork.fragsize = mtu = inet->pmtudisc == IP_PMTUDISC_PROBE ?
-					    rt->u.dst.dev->mtu :
-					    dst_mtu(rt->u.dst.path);
-		inet->cork.dst = &rt->u.dst;
+					    rt->dst.dev->mtu :
+					    dst_mtu(rt->dst.path);
+		inet->cork.dst = &rt->dst;
 		inet->cork.length = 0;
 		sk->sk_sndmsg_page = NULL;
 		sk->sk_sndmsg_off = 0;
-		if ((exthdrlen = rt->u.dst.header_len) != 0) {
+		if ((exthdrlen = rt->dst.header_len) != 0) {
 			length += exthdrlen;
 			transhdrlen += exthdrlen;
 		}
@@ -852,7 +850,7 @@
 		exthdrlen = 0;
 		mtu = inet->cork.fragsize;
 	}
-	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
+	hh_len = LL_RESERVED_SPACE(rt->dst.dev);
 
 	fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);
 	maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen;
@@ -869,7 +867,7 @@
 	 */
 	if (transhdrlen &&
 	    length + fragheaderlen <= mtu &&
-	    rt->u.dst.dev->features & NETIF_F_V4_CSUM &&
+	    rt->dst.dev->features & NETIF_F_V4_CSUM &&
 	    !exthdrlen)
 		csummode = CHECKSUM_PARTIAL;
 
@@ -878,7 +876,7 @@
 	inet->cork.length += length;
 	if (((length > mtu) || (skb && skb_is_gso(skb))) &&
 	    (sk->sk_protocol == IPPROTO_UDP) &&
-	    (rt->u.dst.dev->features & NETIF_F_UFO)) {
+	    (rt->dst.dev->features & NETIF_F_UFO)) {
 		err = ip_ufo_append_data(sk, getfrag, from, length, hh_len,
 					 fragheaderlen, transhdrlen, mtu,
 					 flags);
@@ -926,7 +924,7 @@
 			fraglen = datalen + fragheaderlen;
 
 			if ((flags & MSG_MORE) &&
-			    !(rt->u.dst.dev->features&NETIF_F_SG))
+			    !(rt->dst.dev->features&NETIF_F_SG))
 				alloclen = mtu;
 			else
 				alloclen = datalen + fragheaderlen;
@@ -937,7 +935,7 @@
 			 * the last.
 			 */
 			if (datalen == length + fraggap)
-				alloclen += rt->u.dst.trailer_len;
+				alloclen += rt->dst.trailer_len;
 
 			if (transhdrlen) {
 				skb = sock_alloc_send_skb(sk,
@@ -1010,7 +1008,7 @@
 		if (copy > length)
 			copy = length;
 
-		if (!(rt->u.dst.dev->features&NETIF_F_SG)) {
+		if (!(rt->dst.dev->features&NETIF_F_SG)) {
 			unsigned int off;
 
 			off = skb->len;
@@ -1105,10 +1103,10 @@
 	if (inet->cork.flags & IPCORK_OPT)
 		opt = inet->cork.opt;
 
-	if (!(rt->u.dst.dev->features&NETIF_F_SG))
+	if (!(rt->dst.dev->features&NETIF_F_SG))
 		return -EOPNOTSUPP;
 
-	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
+	hh_len = LL_RESERVED_SPACE(rt->dst.dev);
 	mtu = inet->cork.fragsize;
 
 	fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);
@@ -1125,7 +1123,7 @@
 	inet->cork.length += size;
 	if ((size + skb->len > mtu) &&
 	    (sk->sk_protocol == IPPROTO_UDP) &&
-	    (rt->u.dst.dev->features & NETIF_F_UFO)) {
+	    (rt->dst.dev->features & NETIF_F_UFO)) {
 		skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
 		skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
 	}
@@ -1277,8 +1275,8 @@
 	 * If local_df is set too, we still allow to fragment this frame
 	 * locally. */
 	if (inet->pmtudisc >= IP_PMTUDISC_DO ||
-	    (skb->len <= dst_mtu(&rt->u.dst) &&
-	     ip_dont_fragment(sk, &rt->u.dst)))
+	    (skb->len <= dst_mtu(&rt->dst) &&
+	     ip_dont_fragment(sk, &rt->dst)))
 		df = htons(IP_DF);
 
 	if (inet->cork.flags & IPCORK_OPT)
@@ -1287,7 +1285,7 @@
 	if (rt->rt_type == RTN_MULTICAST)
 		ttl = inet->mc_ttl;
 	else
-		ttl = ip_select_ttl(inet, &rt->u.dst);
+		ttl = ip_select_ttl(inet, &rt->dst);
 
 	iph = (struct iphdr *)skb->data;
 	iph->version = 4;
@@ -1298,7 +1296,7 @@
 	}
 	iph->tos = inet->tos;
 	iph->frag_off = df;
-	ip_select_ident(iph, &rt->u.dst, sk);
+	ip_select_ident(iph, &rt->dst, sk);
 	iph->ttl = ttl;
 	iph->protocol = sk->sk_protocol;
 	iph->saddr = rt->rt_src;
@@ -1311,7 +1309,7 @@
 	 * on dst refcount
 	 */
 	inet->cork.dst = NULL;
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	if (iph->protocol == IPPROTO_ICMP)
 		icmp_out_count(net, ((struct icmphdr *)
@@ -1448,7 +1446,3 @@
 	igmp_mc_proc_init();
 #endif
 }
-
-EXPORT_SYMBOL(ip_generic_getfrag);
-EXPORT_SYMBOL(ip_queue_xmit);
-EXPORT_SYMBOL(ip_send_check);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index ce23178..6c40a8c 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -239,7 +239,16 @@
    sent to multicast group to reach destination designated router.
  */
 struct ip_ra_chain *ip_ra_chain;
-DEFINE_RWLOCK(ip_ra_lock);
+static DEFINE_SPINLOCK(ip_ra_lock);
+
+
+static void ip_ra_destroy_rcu(struct rcu_head *head)
+{
+	struct ip_ra_chain *ra = container_of(head, struct ip_ra_chain, rcu);
+
+	sock_put(ra->saved_sk);
+	kfree(ra);
+}
 
 int ip_ra_control(struct sock *sk, unsigned char on,
 		  void (*destructor)(struct sock *))
@@ -251,35 +260,42 @@
 
 	new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
 
-	write_lock_bh(&ip_ra_lock);
+	spin_lock_bh(&ip_ra_lock);
 	for (rap = &ip_ra_chain; (ra = *rap) != NULL; rap = &ra->next) {
 		if (ra->sk == sk) {
 			if (on) {
-				write_unlock_bh(&ip_ra_lock);
+				spin_unlock_bh(&ip_ra_lock);
 				kfree(new_ra);
 				return -EADDRINUSE;
 			}
-			*rap = ra->next;
-			write_unlock_bh(&ip_ra_lock);
+			/* dont let ip_call_ra_chain() use sk again */
+			ra->sk = NULL;
+			rcu_assign_pointer(*rap, ra->next);
+			spin_unlock_bh(&ip_ra_lock);
 
 			if (ra->destructor)
 				ra->destructor(sk);
-			sock_put(sk);
-			kfree(ra);
+			/*
+			 * Delay sock_put(sk) and kfree(ra) after one rcu grace
+			 * period. This guarantee ip_call_ra_chain() dont need
+			 * to mess with socket refcounts.
+			 */
+			ra->saved_sk = sk;
+			call_rcu(&ra->rcu, ip_ra_destroy_rcu);
 			return 0;
 		}
 	}
 	if (new_ra == NULL) {
-		write_unlock_bh(&ip_ra_lock);
+		spin_unlock_bh(&ip_ra_lock);
 		return -ENOBUFS;
 	}
 	new_ra->sk = sk;
 	new_ra->destructor = destructor;
 
 	new_ra->next = ra;
-	*rap = new_ra;
+	rcu_assign_pointer(*rap, new_ra);
 	sock_hold(sk);
-	write_unlock_bh(&ip_ra_lock);
+	spin_unlock_bh(&ip_ra_lock);
 
 	return 0;
 }
@@ -449,7 +465,7 @@
 			     (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
 			     (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
 			     (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT) |
-			     (1<<IP_MINTTL))) ||
+			     (1<<IP_MINTTL) | (1<<IP_NODEFRAG))) ||
 	    optname == IP_MULTICAST_TTL ||
 	    optname == IP_MULTICAST_ALL ||
 	    optname == IP_MULTICAST_LOOP ||
@@ -572,6 +588,13 @@
 		}
 		inet->hdrincl = val ? 1 : 0;
 		break;
+	case IP_NODEFRAG:
+		if (sk->sk_type != SOCK_RAW) {
+			err = -ENOPROTOOPT;
+			break;
+		}
+		inet->nodefrag = val ? 1 : 0;
+		break;
 	case IP_MTU_DISCOVER:
 		if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE)
 			goto e_inval;
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index b9d84e8..3a6e1ec 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -665,6 +665,13 @@
 		memcpy(e, ic_req_params, sizeof(ic_req_params));
 		e += sizeof(ic_req_params);
 
+		if (ic_host_name_set) {
+			*e++ = 12;	/* host-name */
+			len = strlen(utsname()->nodename);
+			*e++ = len;
+			memcpy(e, utsname()->nodename, len);
+			e += len;
+		}
 		if (*vendor_class_identifier) {
 			printk(KERN_INFO "DHCP: sending class identifier \"%s\"\n",
 			       vendor_class_identifier);
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 7fd6367..ec03673 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -435,7 +435,7 @@
 			goto tx_error_icmp;
 		}
 	}
-	tdev = rt->u.dst.dev;
+	tdev = rt->dst.dev;
 
 	if (tdev == dev) {
 		ip_rt_put(rt);
@@ -446,7 +446,7 @@
 	df |= old_iph->frag_off & htons(IP_DF);
 
 	if (df) {
-		mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
+		mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
 
 		if (mtu < 68) {
 			stats->collisions++;
@@ -503,7 +503,7 @@
 	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
 			      IPSKB_REROUTED);
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	/*
 	 *	Push down and install the IPIP header.
@@ -552,7 +552,7 @@
 				    .proto = IPPROTO_IPIP };
 		struct rtable *rt;
 		if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
-			tdev = rt->u.dst.dev;
+			tdev = rt->dst.dev;
 			ip_rt_put(rt);
 		}
 		dev->flags |= IFF_POINTOPOINT;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 7f62735..179fcab 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1555,9 +1555,9 @@
 			goto out_free;
 	}
 
-	dev = rt->u.dst.dev;
+	dev = rt->dst.dev;
 
-	if (skb->len+encap > dst_mtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) {
+	if (skb->len+encap > dst_mtu(&rt->dst) && (ntohs(iph->frag_off) & IP_DF)) {
 		/* Do not fragment multicasts. Alas, IPv4 does not
 		   allow to send ICMP, so that packets will disappear
 		   to blackhole.
@@ -1568,7 +1568,7 @@
 		goto out_free;
 	}
 
-	encap += LL_RESERVED_SPACE(dev) + rt->u.dst.header_len;
+	encap += LL_RESERVED_SPACE(dev) + rt->dst.header_len;
 
 	if (skb_cow(skb, encap)) {
 		ip_rt_put(rt);
@@ -1579,7 +1579,7 @@
 	vif->bytes_out += skb->len;
 
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 	ip_decrease_ttl(ip_hdr(skb));
 
 	/* FIXME: forward and output firewalls used to be called here.
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 07de855..d88a46c 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -43,7 +43,7 @@
 
 		/* Drop old route. */
 		skb_dst_drop(skb);
-		skb_dst_set(skb, &rt->u.dst);
+		skb_dst_set(skb, &rt->dst);
 	} else {
 		/* non-local src, find valid iif to satisfy
 		 * rp-filter when calling ip_route_input. */
@@ -53,11 +53,11 @@
 
 		orefdst = skb->_skb_refdst;
 		if (ip_route_input(skb, iph->daddr, iph->saddr,
-				   RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
-			dst_release(&rt->u.dst);
+				   RT_TOS(iph->tos), rt->dst.dev) != 0) {
+			dst_release(&rt->dst);
 			return -1;
 		}
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 		refdst_drop(orefdst);
 	}
 
@@ -212,9 +212,7 @@
 		skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, protocol,
 					       skb->len - dataoff, 0);
 		skb->ip_summed = CHECKSUM_NONE;
-		csum = __skb_checksum_complete_head(skb, dataoff + len);
-		if (!csum)
-			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		return __skb_checksum_complete_head(skb, dataoff + len);
 	}
 	return csum;
 }
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 1ac01b1..6bccba3 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -283,16 +283,13 @@
 	arp = arp_hdr(skb);
 	do {
 		const struct arpt_entry_target *t;
-		int hdr_len;
 
 		if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) {
 			e = arpt_next_entry(e);
 			continue;
 		}
 
-		hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) +
-			(2 * skb->dev->addr_len);
-		ADD_COUNTER(e->counters, hdr_len, 1);
+		ADD_COUNTER(e->counters, arp_hdr_len(skb->dev), 1);
 
 		t = arpt_get_target_c(e);
 
@@ -713,7 +710,7 @@
 	struct arpt_entry *iter;
 	unsigned int cpu;
 	unsigned int i;
-	unsigned int curcpu;
+	unsigned int curcpu = get_cpu();
 
 	/* Instead of clearing (by a previous call to memset())
 	 * the counters and using adds, we set the counters
@@ -723,14 +720,16 @@
 	 * if new softirq were to run and call ipt_do_table
 	 */
 	local_bh_disable();
-	curcpu = smp_processor_id();
-
 	i = 0;
 	xt_entry_foreach(iter, t->entries[curcpu], t->size) {
 		SET_COUNTER(counters[i], iter->counters.bcnt,
 			    iter->counters.pcnt);
 		++i;
 	}
+	local_bh_enable();
+	/* Processing counters from other cpus, we can let bottom half enabled,
+	 * (preemption is disabled)
+	 */
 
 	for_each_possible_cpu(cpu) {
 		if (cpu == curcpu)
@@ -744,7 +743,7 @@
 		}
 		xt_info_wrunlock(cpu);
 	}
-	local_bh_enable();
+	put_cpu();
 }
 
 static struct xt_counters *alloc_counters(const struct xt_table *table)
@@ -758,7 +757,7 @@
 	 * about).
 	 */
 	countersize = sizeof(struct xt_counters) * private->number;
-	counters = vmalloc_node(countersize, numa_node_id());
+	counters = vmalloc(countersize);
 
 	if (counters == NULL)
 		return ERR_PTR(-ENOMEM);
@@ -1005,8 +1004,7 @@
 	struct arpt_entry *iter;
 
 	ret = 0;
-	counters = vmalloc_node(num_counters * sizeof(struct xt_counters),
-				numa_node_id());
+	counters = vmalloc(num_counters * sizeof(struct xt_counters));
 	if (!counters) {
 		ret = -ENOMEM;
 		goto out;
@@ -1159,7 +1157,7 @@
 	if (len != size + num_counters * sizeof(struct xt_counters))
 		return -EINVAL;
 
-	paddc = vmalloc_node(len - size, numa_node_id());
+	paddc = vmalloc(len - size);
 	if (!paddc)
 		return -ENOMEM;
 
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index a4e5fc5..d2c1311 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -42,7 +42,7 @@
 
 static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE;
 static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT;
-static DEFINE_RWLOCK(queue_lock);
+static DEFINE_SPINLOCK(queue_lock);
 static int peer_pid __read_mostly;
 static unsigned int copy_range __read_mostly;
 static unsigned int queue_total;
@@ -72,10 +72,10 @@
 		break;
 
 	case IPQ_COPY_PACKET:
-		copy_mode = mode;
+		if (range > 0xFFFF)
+			range = 0xFFFF;
 		copy_range = range;
-		if (copy_range > 0xFFFF)
-			copy_range = 0xFFFF;
+		copy_mode = mode;
 		break;
 
 	default:
@@ -101,7 +101,7 @@
 {
 	struct nf_queue_entry *entry = NULL, *i;
 
-	write_lock_bh(&queue_lock);
+	spin_lock_bh(&queue_lock);
 
 	list_for_each_entry(i, &queue_list, list) {
 		if ((unsigned long)i == id) {
@@ -115,7 +115,7 @@
 		queue_total--;
 	}
 
-	write_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 	return entry;
 }
 
@@ -136,9 +136,9 @@
 static void
 ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
 {
-	write_lock_bh(&queue_lock);
+	spin_lock_bh(&queue_lock);
 	__ipq_flush(cmpfn, data);
-	write_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 }
 
 static struct sk_buff *
@@ -152,9 +152,7 @@
 	struct nlmsghdr *nlh;
 	struct timeval tv;
 
-	read_lock_bh(&queue_lock);
-
-	switch (copy_mode) {
+	switch (ACCESS_ONCE(copy_mode)) {
 	case IPQ_COPY_META:
 	case IPQ_COPY_NONE:
 		size = NLMSG_SPACE(sizeof(*pmsg));
@@ -162,26 +160,21 @@
 
 	case IPQ_COPY_PACKET:
 		if (entry->skb->ip_summed == CHECKSUM_PARTIAL &&
-		    (*errp = skb_checksum_help(entry->skb))) {
-			read_unlock_bh(&queue_lock);
+		    (*errp = skb_checksum_help(entry->skb)))
 			return NULL;
-		}
-		if (copy_range == 0 || copy_range > entry->skb->len)
+
+		data_len = ACCESS_ONCE(copy_range);
+		if (data_len == 0 || data_len > entry->skb->len)
 			data_len = entry->skb->len;
-		else
-			data_len = copy_range;
 
 		size = NLMSG_SPACE(sizeof(*pmsg) + data_len);
 		break;
 
 	default:
 		*errp = -EINVAL;
-		read_unlock_bh(&queue_lock);
 		return NULL;
 	}
 
-	read_unlock_bh(&queue_lock);
-
 	skb = alloc_skb(size, GFP_ATOMIC);
 	if (!skb)
 		goto nlmsg_failure;
@@ -242,7 +235,7 @@
 	if (nskb == NULL)
 		return status;
 
-	write_lock_bh(&queue_lock);
+	spin_lock_bh(&queue_lock);
 
 	if (!peer_pid)
 		goto err_out_free_nskb;
@@ -266,14 +259,14 @@
 
 	__ipq_enqueue_entry(entry);
 
-	write_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 	return status;
 
 err_out_free_nskb:
 	kfree_skb(nskb);
 
 err_out_unlock:
-	write_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 	return status;
 }
 
@@ -342,9 +335,9 @@
 {
 	int status;
 
-	write_lock_bh(&queue_lock);
+	spin_lock_bh(&queue_lock);
 	status = __ipq_set_mode(mode, range);
-	write_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 	return status;
 }
 
@@ -440,11 +433,11 @@
 	if (security_netlink_recv(skb, CAP_NET_ADMIN))
 		RCV_SKB_FAIL(-EPERM);
 
-	write_lock_bh(&queue_lock);
+	spin_lock_bh(&queue_lock);
 
 	if (peer_pid) {
 		if (peer_pid != pid) {
-			write_unlock_bh(&queue_lock);
+			spin_unlock_bh(&queue_lock);
 			RCV_SKB_FAIL(-EBUSY);
 		}
 	} else {
@@ -452,7 +445,7 @@
 		peer_pid = pid;
 	}
 
-	write_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 
 	status = ipq_receive_peer(NLMSG_DATA(nlh), type,
 				  nlmsglen - NLMSG_LENGTH(0));
@@ -497,10 +490,10 @@
 	struct netlink_notify *n = ptr;
 
 	if (event == NETLINK_URELEASE && n->protocol == NETLINK_FIREWALL) {
-		write_lock_bh(&queue_lock);
+		spin_lock_bh(&queue_lock);
 		if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid))
 			__ipq_reset();
-		write_unlock_bh(&queue_lock);
+		spin_unlock_bh(&queue_lock);
 	}
 	return NOTIFY_DONE;
 }
@@ -527,7 +520,7 @@
 #ifdef CONFIG_PROC_FS
 static int ip_queue_show(struct seq_file *m, void *v)
 {
-	read_lock_bh(&queue_lock);
+	spin_lock_bh(&queue_lock);
 
 	seq_printf(m,
 		      "Peer PID          : %d\n"
@@ -545,7 +538,7 @@
 		      queue_dropped,
 		      queue_user_dropped);
 
-	read_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 	return 0;
 }
 
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 4b6c5ca..c439721 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -364,7 +364,7 @@
 				goto no_match;
 		}
 
-		ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
+		ADD_COUNTER(e->counters, skb->len, 1);
 
 		t = ipt_get_target(e);
 		IP_NF_ASSERT(t->u.kernel.target);
@@ -884,7 +884,7 @@
 	struct ipt_entry *iter;
 	unsigned int cpu;
 	unsigned int i;
-	unsigned int curcpu;
+	unsigned int curcpu = get_cpu();
 
 	/* Instead of clearing (by a previous call to memset())
 	 * the counters and using adds, we set the counters
@@ -894,14 +894,16 @@
 	 * if new softirq were to run and call ipt_do_table
 	 */
 	local_bh_disable();
-	curcpu = smp_processor_id();
-
 	i = 0;
 	xt_entry_foreach(iter, t->entries[curcpu], t->size) {
 		SET_COUNTER(counters[i], iter->counters.bcnt,
 			    iter->counters.pcnt);
 		++i;
 	}
+	local_bh_enable();
+	/* Processing counters from other cpus, we can let bottom half enabled,
+	 * (preemption is disabled)
+	 */
 
 	for_each_possible_cpu(cpu) {
 		if (cpu == curcpu)
@@ -915,7 +917,7 @@
 		}
 		xt_info_wrunlock(cpu);
 	}
-	local_bh_enable();
+	put_cpu();
 }
 
 static struct xt_counters *alloc_counters(const struct xt_table *table)
@@ -928,7 +930,7 @@
 	   (other than comefrom, which userspace doesn't care
 	   about). */
 	countersize = sizeof(struct xt_counters) * private->number;
-	counters = vmalloc_node(countersize, numa_node_id());
+	counters = vmalloc(countersize);
 
 	if (counters == NULL)
 		return ERR_PTR(-ENOMEM);
@@ -1352,7 +1354,7 @@
 	if (len != size + num_counters * sizeof(struct xt_counters))
 		return -EINVAL;
 
-	paddc = vmalloc_node(len - size, numa_node_id());
+	paddc = vmalloc(len - size);
 	if (!paddc)
 		return -ENOMEM;
 
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index f91c94b..3a43cf3 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -53,12 +53,13 @@
 #endif
 	enum clusterip_hashmode hash_mode;	/* which hashing mode */
 	u_int32_t hash_initval;			/* hash initialization */
+	struct rcu_head rcu;
 };
 
 static LIST_HEAD(clusterip_configs);
 
 /* clusterip_lock protects the clusterip_configs list */
-static DEFINE_RWLOCK(clusterip_lock);
+static DEFINE_SPINLOCK(clusterip_lock);
 
 #ifdef CONFIG_PROC_FS
 static const struct file_operations clusterip_proc_fops;
@@ -71,11 +72,17 @@
 	atomic_inc(&c->refcount);
 }
 
+
+static void clusterip_config_rcu_free(struct rcu_head *head)
+{
+	kfree(container_of(head, struct clusterip_config, rcu));
+}
+
 static inline void
 clusterip_config_put(struct clusterip_config *c)
 {
 	if (atomic_dec_and_test(&c->refcount))
-		kfree(c);
+		call_rcu_bh(&c->rcu, clusterip_config_rcu_free);
 }
 
 /* decrease the count of entries using/referencing this config.  If last
@@ -84,10 +91,11 @@
 static inline void
 clusterip_config_entry_put(struct clusterip_config *c)
 {
-	write_lock_bh(&clusterip_lock);
-	if (atomic_dec_and_test(&c->entries)) {
-		list_del(&c->list);
-		write_unlock_bh(&clusterip_lock);
+	local_bh_disable();
+	if (atomic_dec_and_lock(&c->entries, &clusterip_lock)) {
+		list_del_rcu(&c->list);
+		spin_unlock(&clusterip_lock);
+		local_bh_enable();
 
 		dev_mc_del(c->dev, c->clustermac);
 		dev_put(c->dev);
@@ -100,7 +108,7 @@
 #endif
 		return;
 	}
-	write_unlock_bh(&clusterip_lock);
+	local_bh_enable();
 }
 
 static struct clusterip_config *
@@ -108,7 +116,7 @@
 {
 	struct clusterip_config *c;
 
-	list_for_each_entry(c, &clusterip_configs, list) {
+	list_for_each_entry_rcu(c, &clusterip_configs, list) {
 		if (c->clusterip == clusterip)
 			return c;
 	}
@@ -121,16 +129,15 @@
 {
 	struct clusterip_config *c;
 
-	read_lock_bh(&clusterip_lock);
+	rcu_read_lock_bh();
 	c = __clusterip_config_find(clusterip);
-	if (!c) {
-		read_unlock_bh(&clusterip_lock);
-		return NULL;
+	if (c) {
+		if (unlikely(!atomic_inc_not_zero(&c->refcount)))
+			c = NULL;
+		else if (entry)
+			atomic_inc(&c->entries);
 	}
-	atomic_inc(&c->refcount);
-	if (entry)
-		atomic_inc(&c->entries);
-	read_unlock_bh(&clusterip_lock);
+	rcu_read_unlock_bh();
 
 	return c;
 }
@@ -181,9 +188,9 @@
 	}
 #endif
 
-	write_lock_bh(&clusterip_lock);
-	list_add(&c->list, &clusterip_configs);
-	write_unlock_bh(&clusterip_lock);
+	spin_lock_bh(&clusterip_lock);
+	list_add_rcu(&c->list, &clusterip_configs);
+	spin_unlock_bh(&clusterip_lock);
 
 	return c;
 }
@@ -462,7 +469,7 @@
 	__be32 src_ip;
 	u_int8_t dst_hw[ETH_ALEN];
 	__be32 dst_ip;
-} __attribute__ ((packed));
+} __packed;
 
 #ifdef DEBUG
 static void arp_print(struct arp_payload *payload)
@@ -733,6 +740,9 @@
 #endif
 	nf_unregister_hook(&cip_arp_ops);
 	xt_unregister_target(&clusterip_tg_reg);
+
+	/* Wait for completion of call_rcu_bh()'s (clusterip_config_rcu_free) */
+	rcu_barrier_bh();
 }
 
 module_init(clusterip_tg_init);
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index 5234f4f..915fc17 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/skbuff.h>
+#include <linux/if_arp.h>
 #include <linux/ip.h>
 #include <net/icmp.h>
 #include <net/udp.h>
@@ -363,6 +364,42 @@
 	/* maxlen = 230+   91  + 230 + 252 = 803 */
 }
 
+static void dump_mac_header(const struct nf_loginfo *info,
+			    const struct sk_buff *skb)
+{
+	struct net_device *dev = skb->dev;
+	unsigned int logflags = 0;
+
+	if (info->type == NF_LOG_TYPE_LOG)
+		logflags = info->u.log.logflags;
+
+	if (!(logflags & IPT_LOG_MACDECODE))
+		goto fallback;
+
+	switch (dev->type) {
+	case ARPHRD_ETHER:
+		printk("MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
+		       eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
+		       ntohs(eth_hdr(skb)->h_proto));
+		return;
+	default:
+		break;
+	}
+
+fallback:
+	printk("MAC=");
+	if (dev->hard_header_len &&
+	    skb->mac_header != skb->network_header) {
+		const unsigned char *p = skb_mac_header(skb);
+		unsigned int i;
+
+		printk("%02x", *p++);
+		for (i = 1; i < dev->hard_header_len; i++, p++)
+			printk(":%02x", *p);
+	}
+	printk(" ");
+}
+
 static struct nf_loginfo default_loginfo = {
 	.type	= NF_LOG_TYPE_LOG,
 	.u = {
@@ -404,20 +441,9 @@
 	}
 #endif
 
-	if (in && !out) {
-		/* MAC logging for input chain only. */
-		printk("MAC=");
-		if (skb->dev && skb->dev->hard_header_len &&
-		    skb->mac_header != skb->network_header) {
-			int i;
-			const unsigned char *p = skb_mac_header(skb);
-			for (i = 0; i < skb->dev->hard_header_len; i++,p++)
-				printk("%02x%c", *p,
-				       i==skb->dev->hard_header_len - 1
-				       ? ' ':':');
-		} else
-			printk(" ");
-	}
+	/* MAC logging for input path only. */
+	if (in && !out)
+		dump_mac_header(loginfo, skb);
 
 	dump_packet(loginfo, skb, 0);
 	printk("\n");
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index f43867d..6cdb298 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -48,7 +48,8 @@
 
 	NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
 		     par->hooknum == NF_INET_POST_ROUTING ||
-		     par->hooknum == NF_INET_LOCAL_OUT);
+		     par->hooknum == NF_INET_LOCAL_OUT ||
+		     par->hooknum == NF_INET_LOCAL_IN);
 	ct = nf_ct_get(skb, &ctinfo);
 
 	netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip);
@@ -77,7 +78,8 @@
 	.table		= "nat",
 	.hooks		= (1 << NF_INET_PRE_ROUTING) |
 			  (1 << NF_INET_POST_ROUTING) |
-			  (1 << NF_INET_LOCAL_OUT),
+			  (1 << NF_INET_LOCAL_OUT) |
+			  (1 << NF_INET_LOCAL_IN),
 	.checkentry 	= netmap_tg_check,
 	.me 		= THIS_MODULE
 };
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index f5f4a88..b254daf 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -95,10 +95,11 @@
 	}
 
 	tcph->rst	= 1;
-	tcph->check	= tcp_v4_check(sizeof(struct tcphdr),
-				       niph->saddr, niph->daddr,
-				       csum_partial(tcph,
-						    sizeof(struct tcphdr), 0));
+	tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
+				    niph->daddr, 0);
+	nskb->ip_summed = CHECKSUM_PARTIAL;
+	nskb->csum_start = (unsigned char *)tcph - nskb->head;
+	nskb->csum_offset = offsetof(struct tcphdr, check);
 
 	addr_type = RTN_UNSPEC;
 	if (hook != NF_INET_FORWARD
@@ -109,13 +110,12 @@
 		addr_type = RTN_LOCAL;
 
 	/* ip_route_me_harder expects skb->dst to be set */
-	skb_dst_set(nskb, dst_clone(skb_dst(oldskb)));
+	skb_dst_set_noref(nskb, skb_dst(oldskb));
 
 	if (ip_route_me_harder(nskb, addr_type))
 		goto free_nskb;
 
 	niph->ttl	= dst_metric(skb_dst(nskb), RTAX_HOPLIMIT);
-	nskb->ip_summed = CHECKSUM_NONE;
 
 	/* "Never happens" */
 	if (nskb->len > dst_mtu(skb_dst(nskb)))
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index cb763ae..eab8de3 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -66,6 +66,11 @@
 					  const struct net_device *out,
 					  int (*okfn)(struct sk_buff *))
 {
+	struct inet_sock *inet = inet_sk(skb->sk);
+
+	if (inet && inet->nodefrag)
+		return NF_ACCEPT;
+
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 #if !defined(CONFIG_NF_NAT) && !defined(CONFIG_NF_NAT_MODULE)
 	/* Previously seen (loopback)?  Ignore.  Do this before
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 4f8bddb..8c8632d 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -261,14 +261,9 @@
 	rcu_read_lock();
 	proto = __nf_nat_proto_find(orig_tuple->dst.protonum);
 
-	/* Change protocol info to have some randomization */
-	if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) {
-		proto->unique_tuple(tuple, range, maniptype, ct);
-		goto out;
-	}
-
 	/* Only bother mapping if it's not already in range and unique */
-	if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
+	if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM) &&
+	    (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
 	     proto->in_range(tuple, maniptype, &range->min, &range->max)) &&
 	    !nf_nat_used_tuple(tuple, ct))
 		goto out;
@@ -440,7 +435,7 @@
 	if (!skb_make_writable(skb, hdrlen + sizeof(*inside)))
 		return 0;
 
-	inside = (void *)skb->data + ip_hdrlen(skb);
+	inside = (void *)skb->data + hdrlen;
 
 	/* We're actually going to mangle it beyond trivial checksum
 	   adjustment, so make sure the current checksum is correct. */
@@ -470,12 +465,10 @@
 	/* rcu_read_lock()ed by nf_hook_slow */
 	l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
 
-	if (!nf_ct_get_tuple(skb,
-			     ip_hdrlen(skb) + sizeof(struct icmphdr),
-			     (ip_hdrlen(skb) +
+	if (!nf_ct_get_tuple(skb, hdrlen + sizeof(struct icmphdr),
+			     (hdrlen +
 			      sizeof(struct icmphdr) + inside->ip.ihl * 4),
-			     (u_int16_t)AF_INET,
-			     inside->ip.protocol,
+			     (u_int16_t)AF_INET, inside->ip.protocol,
 			     &inner, l3proto, l4proto))
 		return 0;
 
@@ -484,15 +477,13 @@
 	   pass all hooks (locally-generated ICMP).  Consider incoming
 	   packet: PREROUTING (DST manip), routing produces ICMP, goes
 	   through POSTROUTING (which must correct the DST manip). */
-	if (!manip_pkt(inside->ip.protocol, skb,
-		       ip_hdrlen(skb) + sizeof(inside->icmp),
-		       &ct->tuplehash[!dir].tuple,
-		       !manip))
+	if (!manip_pkt(inside->ip.protocol, skb, hdrlen + sizeof(inside->icmp),
+		       &ct->tuplehash[!dir].tuple, !manip))
 		return 0;
 
 	if (skb->ip_summed != CHECKSUM_PARTIAL) {
 		/* Reloading "inside" here since manip_pkt inner. */
-		inside = (void *)skb->data + ip_hdrlen(skb);
+		inside = (void *)skb->data + hdrlen;
 		inside->icmp.checksum = 0;
 		inside->icmp.checksum =
 			csum_fold(skb_checksum(skb, hdrlen,
@@ -742,7 +733,7 @@
 	spin_unlock_bh(&nf_nat_lock);
 
 	/* Initialize fake conntrack so that NAT will skip it */
-	nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK;
+	nf_ct_untracked_status_or(IPS_NAT_DONE_MASK);
 
 	l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
 
diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c
index 6c4f11f..3e61faf 100644
--- a/net/ipv4/netfilter/nf_nat_proto_common.c
+++ b/net/ipv4/netfilter/nf_nat_proto_common.c
@@ -34,7 +34,7 @@
 }
 EXPORT_SYMBOL_GPL(nf_nat_proto_in_range);
 
-bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
+void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
 			       const struct nf_nat_range *range,
 			       enum nf_nat_manip_type maniptype,
 			       const struct nf_conn *ct,
@@ -53,7 +53,7 @@
 	if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
 		/* If it's dst rewrite, can't change port */
 		if (maniptype == IP_NAT_MANIP_DST)
-			return false;
+			return;
 
 		if (ntohs(*portptr) < 1024) {
 			/* Loose convention: >> 512 is credential passing */
@@ -81,15 +81,15 @@
 	else
 		off = *rover;
 
-	for (i = 0; i < range_size; i++, off++) {
+	for (i = 0; ; ++off) {
 		*portptr = htons(min + off % range_size);
-		if (nf_nat_used_tuple(tuple, ct))
+		if (++i != range_size && nf_nat_used_tuple(tuple, ct))
 			continue;
 		if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
 			*rover = off;
-		return true;
+		return;
 	}
-	return false;
+	return;
 }
 EXPORT_SYMBOL_GPL(nf_nat_proto_unique_tuple);
 
diff --git a/net/ipv4/netfilter/nf_nat_proto_dccp.c b/net/ipv4/netfilter/nf_nat_proto_dccp.c
index 22485ce..570faf2 100644
--- a/net/ipv4/netfilter/nf_nat_proto_dccp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_dccp.c
@@ -22,14 +22,14 @@
 
 static u_int16_t dccp_port_rover;
 
-static bool
+static void
 dccp_unique_tuple(struct nf_conntrack_tuple *tuple,
 		  const struct nf_nat_range *range,
 		  enum nf_nat_manip_type maniptype,
 		  const struct nf_conn *ct)
 {
-	return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
-					 &dccp_port_rover);
+	nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
+				  &dccp_port_rover);
 }
 
 static bool
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c
index d7e8920..bc8d83a 100644
--- a/net/ipv4/netfilter/nf_nat_proto_gre.c
+++ b/net/ipv4/netfilter/nf_nat_proto_gre.c
@@ -37,7 +37,7 @@
 MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
 
 /* generate unique tuple ... */
-static bool
+static void
 gre_unique_tuple(struct nf_conntrack_tuple *tuple,
 		 const struct nf_nat_range *range,
 		 enum nf_nat_manip_type maniptype,
@@ -50,7 +50,7 @@
 	/* If there is no master conntrack we are not PPTP,
 	   do not change tuples */
 	if (!ct->master)
-		return false;
+		return;
 
 	if (maniptype == IP_NAT_MANIP_SRC)
 		keyptr = &tuple->src.u.gre.key;
@@ -68,14 +68,14 @@
 
 	pr_debug("min = %u, range_size = %u\n", min, range_size);
 
-	for (i = 0; i < range_size; i++, key++) {
+	for (i = 0; ; ++key) {
 		*keyptr = htons(min + key % range_size);
-		if (!nf_nat_used_tuple(tuple, ct))
-			return true;
+		if (++i == range_size || !nf_nat_used_tuple(tuple, ct))
+			return;
 	}
 
 	pr_debug("%p: no NAT mapping\n", ct);
-	return false;
+	return;
 }
 
 /* manipulate a GRE packet according to maniptype */
diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c
index 19a8b0b..5744c3e 100644
--- a/net/ipv4/netfilter/nf_nat_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c
@@ -27,7 +27,7 @@
 	       ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id);
 }
 
-static bool
+static void
 icmp_unique_tuple(struct nf_conntrack_tuple *tuple,
 		  const struct nf_nat_range *range,
 		  enum nf_nat_manip_type maniptype,
@@ -42,13 +42,13 @@
 	if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED))
 		range_size = 0xFFFF;
 
-	for (i = 0; i < range_size; i++, id++) {
+	for (i = 0; ; ++id) {
 		tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) +
 					     (id % range_size));
-		if (!nf_nat_used_tuple(tuple, ct))
-			return true;
+		if (++i == range_size || !nf_nat_used_tuple(tuple, ct))
+			return;
 	}
-	return false;
+	return;
 }
 
 static bool
diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/ipv4/netfilter/nf_nat_proto_sctp.c
index 3fc598ee..756331d 100644
--- a/net/ipv4/netfilter/nf_nat_proto_sctp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_sctp.c
@@ -16,14 +16,14 @@
 
 static u_int16_t nf_sctp_port_rover;
 
-static bool
+static void
 sctp_unique_tuple(struct nf_conntrack_tuple *tuple,
 		  const struct nf_nat_range *range,
 		  enum nf_nat_manip_type maniptype,
 		  const struct nf_conn *ct)
 {
-	return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
-					 &nf_sctp_port_rover);
+	nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
+				  &nf_sctp_port_rover);
 }
 
 static bool
diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c
index 399e2cf..aa460a5 100644
--- a/net/ipv4/netfilter/nf_nat_proto_tcp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c
@@ -20,14 +20,13 @@
 
 static u_int16_t tcp_port_rover;
 
-static bool
+static void
 tcp_unique_tuple(struct nf_conntrack_tuple *tuple,
 		 const struct nf_nat_range *range,
 		 enum nf_nat_manip_type maniptype,
 		 const struct nf_conn *ct)
 {
-	return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
-					 &tcp_port_rover);
+	nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, &tcp_port_rover);
 }
 
 static bool
diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c
index 9e61c79..dfe65c7 100644
--- a/net/ipv4/netfilter/nf_nat_proto_udp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_udp.c
@@ -19,14 +19,13 @@
 
 static u_int16_t udp_port_rover;
 
-static bool
+static void
 udp_unique_tuple(struct nf_conntrack_tuple *tuple,
 		 const struct nf_nat_range *range,
 		 enum nf_nat_manip_type maniptype,
 		 const struct nf_conn *ct)
 {
-	return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
-					 &udp_port_rover);
+	nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, &udp_port_rover);
 }
 
 static bool
diff --git a/net/ipv4/netfilter/nf_nat_proto_udplite.c b/net/ipv4/netfilter/nf_nat_proto_udplite.c
index 440a229..3cc8c8a 100644
--- a/net/ipv4/netfilter/nf_nat_proto_udplite.c
+++ b/net/ipv4/netfilter/nf_nat_proto_udplite.c
@@ -18,14 +18,14 @@
 
 static u_int16_t udplite_port_rover;
 
-static bool
+static void
 udplite_unique_tuple(struct nf_conntrack_tuple *tuple,
 		     const struct nf_nat_range *range,
 		     enum nf_nat_manip_type maniptype,
 		     const struct nf_conn *ct)
 {
-	return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
-					 &udplite_port_rover);
+	nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
+				  &udplite_port_rover);
 }
 
 static bool
diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/ipv4/netfilter/nf_nat_proto_unknown.c
index 14381c6..a50f2bc 100644
--- a/net/ipv4/netfilter/nf_nat_proto_unknown.c
+++ b/net/ipv4/netfilter/nf_nat_proto_unknown.c
@@ -26,14 +26,14 @@
 	return true;
 }
 
-static bool unknown_unique_tuple(struct nf_conntrack_tuple *tuple,
+static void unknown_unique_tuple(struct nf_conntrack_tuple *tuple,
 				 const struct nf_nat_range *range,
 				 enum nf_nat_manip_type maniptype,
 				 const struct nf_conn *ct)
 {
 	/* Sorry: we can't help you; if it's not unique, we can't frob
 	   anything. */
-	return false;
+	return;
 }
 
 static bool
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index 98ed782..ebbd319 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -28,7 +28,8 @@
 
 #define NAT_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | \
 			 (1 << NF_INET_POST_ROUTING) | \
-			 (1 << NF_INET_LOCAL_OUT))
+			 (1 << NF_INET_LOCAL_OUT) | \
+			 (1 << NF_INET_LOCAL_IN))
 
 static const struct xt_table nat_table = {
 	.name		= "nat",
@@ -45,7 +46,8 @@
 	enum ip_conntrack_info ctinfo;
 	const struct nf_nat_multi_range_compat *mr = par->targinfo;
 
-	NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING);
+	NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING ||
+		     par->hooknum == NF_INET_LOCAL_IN);
 
 	ct = nf_ct_get(skb, &ctinfo);
 
@@ -99,7 +101,7 @@
 	return 0;
 }
 
-unsigned int
+static unsigned int
 alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
 {
 	/* Force range to this IP; let proto decide mapping for
@@ -141,7 +143,7 @@
 	.target		= ipt_snat_target,
 	.targetsize	= sizeof(struct nf_nat_multi_range_compat),
 	.table		= "nat",
-	.hooks		= 1 << NF_INET_POST_ROUTING,
+	.hooks		= (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_LOCAL_IN),
 	.checkentry	= ipt_snat_checkentry,
 	.family		= AF_INET,
 };
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
index beb2581..95481fe 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -98,7 +98,7 @@
 		return NF_ACCEPT;
 
 	/* Don't try to NAT if this packet is not conntracked */
-	if (ct == &nf_conntrack_untracked)
+	if (nf_ct_is_untracked(ct))
 		return NF_ACCEPT;
 
 	nat = nfct_nat(ct);
@@ -131,13 +131,7 @@
 		if (!nf_nat_initialized(ct, maniptype)) {
 			unsigned int ret;
 
-			if (hooknum == NF_INET_LOCAL_IN)
-				/* LOCAL_IN hook doesn't have a chain!  */
-				ret = alloc_null_binding(ct, hooknum);
-			else
-				ret = nf_nat_rule_find(skb, hooknum, in, out,
-						       ct);
-
+			ret = nf_nat_rule_find(skb, hooknum, in, out, ct);
 			if (ret != NF_ACCEPT)
 				return ret;
 		} else
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 3dc9914..4ae1f20 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -252,6 +252,7 @@
 	SNMP_MIB_ITEM("TCPBacklogDrop", LINUX_MIB_TCPBACKLOGDROP),
 	SNMP_MIB_ITEM("TCPMinTTLDrop", LINUX_MIB_TCPMINTTLDROP),
 	SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP),
+	SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER),
 	SNMP_MIB_SENTINEL
 };
 
@@ -342,10 +343,12 @@
 		   IPV4_DEVCONF_ALL(net, FORWARDING) ? 1 : 2,
 		   sysctl_ip_default_ttl);
 
+	BUILD_BUG_ON(offsetof(struct ipstats_mib, mibs) != 0);
 	for (i = 0; snmp4_ipstats_list[i].name != NULL; i++)
-		seq_printf(seq, " %lu",
-			   snmp_fold_field((void __percpu **)net->mib.ip_statistics,
-					   snmp4_ipstats_list[i].entry));
+		seq_printf(seq, " %llu",
+			   snmp_fold_field64((void __percpu **)net->mib.ip_statistics,
+					     snmp4_ipstats_list[i].entry,
+					     offsetof(struct ipstats_mib, syncp)));
 
 	icmp_put(seq);	/* RFC 2011 compatibility */
 	icmpmsg_put(seq);
@@ -431,9 +434,10 @@
 
 	seq_puts(seq, "\nIpExt:");
 	for (i = 0; snmp4_ipextstats_list[i].name != NULL; i++)
-		seq_printf(seq, " %lu",
-			   snmp_fold_field((void __percpu **)net->mib.ip_statistics,
-					   snmp4_ipextstats_list[i].entry));
+		seq_printf(seq, " %llu",
+			   snmp_fold_field64((void __percpu **)net->mib.ip_statistics,
+					     snmp4_ipextstats_list[i].entry,
+					     offsetof(struct ipstats_mib, syncp)));
 
 	seq_putc(seq, '\n');
 	return 0;
diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c
index 542f22f..f2d2973 100644
--- a/net/ipv4/protocol.c
+++ b/net/ipv4/protocol.c
@@ -52,6 +52,7 @@
 
 	return ret;
 }
+EXPORT_SYMBOL(inet_add_protocol);
 
 /*
  *	Remove a protocol from the hash tables.
@@ -76,6 +77,4 @@
 
 	return ret;
 }
-
-EXPORT_SYMBOL(inet_add_protocol);
 EXPORT_SYMBOL(inet_del_protocol);
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 2c7a163..009a7b2 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -314,7 +314,7 @@
 }
 
 static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
-			struct rtable *rt,
+			struct rtable **rtp,
 			unsigned int flags)
 {
 	struct inet_sock *inet = inet_sk(sk);
@@ -323,25 +323,27 @@
 	struct sk_buff *skb;
 	unsigned int iphlen;
 	int err;
+	struct rtable *rt = *rtp;
 
-	if (length > rt->u.dst.dev->mtu) {
+	if (length > rt->dst.dev->mtu) {
 		ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport,
-			       rt->u.dst.dev->mtu);
+			       rt->dst.dev->mtu);
 		return -EMSGSIZE;
 	}
 	if (flags&MSG_PROBE)
 		goto out;
 
 	skb = sock_alloc_send_skb(sk,
-				  length + LL_ALLOCATED_SPACE(rt->u.dst.dev) + 15,
+				  length + LL_ALLOCATED_SPACE(rt->dst.dev) + 15,
 				  flags & MSG_DONTWAIT, &err);
 	if (skb == NULL)
 		goto error;
-	skb_reserve(skb, LL_RESERVED_SPACE(rt->u.dst.dev));
+	skb_reserve(skb, LL_RESERVED_SPACE(rt->dst.dev));
 
 	skb->priority = sk->sk_priority;
 	skb->mark = sk->sk_mark;
-	skb_dst_set(skb, dst_clone(&rt->u.dst));
+	skb_dst_set(skb, &rt->dst);
+	*rtp = NULL;
 
 	skb_reset_network_header(skb);
 	iph = ip_hdr(skb);
@@ -373,7 +375,7 @@
 		iph->check   = 0;
 		iph->tot_len = htons(length);
 		if (!iph->id)
-			ip_select_ident(iph, &rt->u.dst, NULL);
+			ip_select_ident(iph, &rt->dst, NULL);
 
 		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 	}
@@ -382,7 +384,7 @@
 			skb_transport_header(skb))->type);
 
 	err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL,
-		      rt->u.dst.dev, dst_output);
+		      rt->dst.dev, dst_output);
 	if (err > 0)
 		err = net_xmit_errno(err);
 	if (err)
@@ -576,7 +578,7 @@
 
 	if (inet->hdrincl)
 		err = raw_send_hdrinc(sk, msg->msg_iov, len,
-					rt, msg->msg_flags);
+					&rt, msg->msg_flags);
 
 	 else {
 		if (!ipc.addr)
@@ -604,7 +606,7 @@
 	return len;
 
 do_confirm:
-	dst_confirm(&rt->u.dst);
+	dst_confirm(&rt->dst);
 	if (!(msg->msg_flags & MSG_PROBE) || len)
 		goto back_from_confirm;
 	err = 0;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 560acc6..3f56b6e 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -253,8 +253,7 @@
 static unsigned int		rt_hash_log  __read_mostly;
 
 static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
-#define RT_CACHE_STAT_INC(field) \
-	(__raw_get_cpu_var(rt_cache_stat).field++)
+#define RT_CACHE_STAT_INC(field) __this_cpu_inc(rt_cache_stat.field)
 
 static inline unsigned int rt_hash(__be32 daddr, __be32 saddr, int idx,
 				   int genid)
@@ -287,10 +286,10 @@
 		rcu_read_lock_bh();
 		r = rcu_dereference_bh(rt_hash_table[st->bucket].chain);
 		while (r) {
-			if (dev_net(r->u.dst.dev) == seq_file_net(seq) &&
+			if (dev_net(r->dst.dev) == seq_file_net(seq) &&
 			    r->rt_genid == st->genid)
 				return r;
-			r = rcu_dereference_bh(r->u.dst.rt_next);
+			r = rcu_dereference_bh(r->dst.rt_next);
 		}
 		rcu_read_unlock_bh();
 	}
@@ -302,7 +301,7 @@
 {
 	struct rt_cache_iter_state *st = seq->private;
 
-	r = r->u.dst.rt_next;
+	r = r->dst.rt_next;
 	while (!r) {
 		rcu_read_unlock_bh();
 		do {
@@ -320,7 +319,7 @@
 {
 	struct rt_cache_iter_state *st = seq->private;
 	while ((r = __rt_cache_get_next(seq, r)) != NULL) {
-		if (dev_net(r->u.dst.dev) != seq_file_net(seq))
+		if (dev_net(r->dst.dev) != seq_file_net(seq))
 			continue;
 		if (r->rt_genid == st->genid)
 			break;
@@ -378,19 +377,19 @@
 
 		seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t"
 			      "%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n",
-			r->u.dst.dev ? r->u.dst.dev->name : "*",
+			r->dst.dev ? r->dst.dev->name : "*",
 			(__force u32)r->rt_dst,
 			(__force u32)r->rt_gateway,
-			r->rt_flags, atomic_read(&r->u.dst.__refcnt),
-			r->u.dst.__use, 0, (__force u32)r->rt_src,
-			(dst_metric(&r->u.dst, RTAX_ADVMSS) ?
-			     (int)dst_metric(&r->u.dst, RTAX_ADVMSS) + 40 : 0),
-			dst_metric(&r->u.dst, RTAX_WINDOW),
-			(int)((dst_metric(&r->u.dst, RTAX_RTT) >> 3) +
-			      dst_metric(&r->u.dst, RTAX_RTTVAR)),
+			r->rt_flags, atomic_read(&r->dst.__refcnt),
+			r->dst.__use, 0, (__force u32)r->rt_src,
+			(dst_metric(&r->dst, RTAX_ADVMSS) ?
+			     (int)dst_metric(&r->dst, RTAX_ADVMSS) + 40 : 0),
+			dst_metric(&r->dst, RTAX_WINDOW),
+			(int)((dst_metric(&r->dst, RTAX_RTT) >> 3) +
+			      dst_metric(&r->dst, RTAX_RTTVAR)),
 			r->fl.fl4_tos,
-			r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1,
-			r->u.dst.hh ? (r->u.dst.hh->hh_output ==
+			r->dst.hh ? atomic_read(&r->dst.hh->hh_refcnt) : -1,
+			r->dst.hh ? (r->dst.hh->hh_output ==
 				       dev_queue_xmit) : 0,
 			r->rt_spec_dst, &len);
 
@@ -609,13 +608,13 @@
 
 static inline void rt_free(struct rtable *rt)
 {
-	call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
+	call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
 }
 
 static inline void rt_drop(struct rtable *rt)
 {
 	ip_rt_put(rt);
-	call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
+	call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
 }
 
 static inline int rt_fast_clean(struct rtable *rth)
@@ -623,13 +622,13 @@
 	/* Kill broadcast/multicast entries very aggresively, if they
 	   collide in hash table with more useful entries */
 	return (rth->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) &&
-		rth->fl.iif && rth->u.dst.rt_next;
+		rth->fl.iif && rth->dst.rt_next;
 }
 
 static inline int rt_valuable(struct rtable *rth)
 {
 	return (rth->rt_flags & (RTCF_REDIRECTED | RTCF_NOTIFY)) ||
-		rth->u.dst.expires;
+		rth->dst.expires;
 }
 
 static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long tmo2)
@@ -637,15 +636,15 @@
 	unsigned long age;
 	int ret = 0;
 
-	if (atomic_read(&rth->u.dst.__refcnt))
+	if (atomic_read(&rth->dst.__refcnt))
 		goto out;
 
 	ret = 1;
-	if (rth->u.dst.expires &&
-	    time_after_eq(jiffies, rth->u.dst.expires))
+	if (rth->dst.expires &&
+	    time_after_eq(jiffies, rth->dst.expires))
 		goto out;
 
-	age = jiffies - rth->u.dst.lastuse;
+	age = jiffies - rth->dst.lastuse;
 	ret = 0;
 	if ((age <= tmo1 && !rt_fast_clean(rth)) ||
 	    (age <= tmo2 && rt_valuable(rth)))
@@ -661,7 +660,7 @@
  */
 static inline u32 rt_score(struct rtable *rt)
 {
-	u32 score = jiffies - rt->u.dst.lastuse;
+	u32 score = jiffies - rt->dst.lastuse;
 
 	score = ~score & ~(3<<30);
 
@@ -701,12 +700,12 @@
 
 static inline int compare_netns(struct rtable *rt1, struct rtable *rt2)
 {
-	return net_eq(dev_net(rt1->u.dst.dev), dev_net(rt2->u.dst.dev));
+	return net_eq(dev_net(rt1->dst.dev), dev_net(rt2->dst.dev));
 }
 
 static inline int rt_is_expired(struct rtable *rth)
 {
-	return rth->rt_genid != rt_genid(dev_net(rth->u.dst.dev));
+	return rth->rt_genid != rt_genid(dev_net(rth->dst.dev));
 }
 
 /*
@@ -735,7 +734,7 @@
 		rth = rt_hash_table[i].chain;
 
 		/* defer releasing the head of the list after spin_unlock */
-		for (tail = rth; tail; tail = tail->u.dst.rt_next)
+		for (tail = rth; tail; tail = tail->dst.rt_next)
 			if (!rt_is_expired(tail))
 				break;
 		if (rth != tail)
@@ -744,9 +743,9 @@
 		/* call rt_free on entries after the tail requiring flush */
 		prev = &rt_hash_table[i].chain;
 		for (p = *prev; p; p = next) {
-			next = p->u.dst.rt_next;
+			next = p->dst.rt_next;
 			if (!rt_is_expired(p)) {
-				prev = &p->u.dst.rt_next;
+				prev = &p->dst.rt_next;
 			} else {
 				*prev = next;
 				rt_free(p);
@@ -761,7 +760,7 @@
 		spin_unlock_bh(rt_hash_lock_addr(i));
 
 		for (; rth != tail; rth = next) {
-			next = rth->u.dst.rt_next;
+			next = rth->dst.rt_next;
 			rt_free(rth);
 		}
 	}
@@ -792,7 +791,7 @@
 	while (aux != rth) {
 		if (compare_hash_inputs(&aux->fl, &rth->fl))
 			return 0;
-		aux = aux->u.dst.rt_next;
+		aux = aux->dst.rt_next;
 	}
 	return ONE;
 }
@@ -832,18 +831,18 @@
 		length = 0;
 		spin_lock_bh(rt_hash_lock_addr(i));
 		while ((rth = *rthp) != NULL) {
-			prefetch(rth->u.dst.rt_next);
+			prefetch(rth->dst.rt_next);
 			if (rt_is_expired(rth)) {
-				*rthp = rth->u.dst.rt_next;
+				*rthp = rth->dst.rt_next;
 				rt_free(rth);
 				continue;
 			}
-			if (rth->u.dst.expires) {
+			if (rth->dst.expires) {
 				/* Entry is expired even if it is in use */
-				if (time_before_eq(jiffies, rth->u.dst.expires)) {
+				if (time_before_eq(jiffies, rth->dst.expires)) {
 nofree:
 					tmo >>= 1;
-					rthp = &rth->u.dst.rt_next;
+					rthp = &rth->dst.rt_next;
 					/*
 					 * We only count entries on
 					 * a chain with equal hash inputs once
@@ -859,7 +858,7 @@
 				goto nofree;
 
 			/* Cleanup aged off entries. */
-			*rthp = rth->u.dst.rt_next;
+			*rthp = rth->dst.rt_next;
 			rt_free(rth);
 		}
 		spin_unlock_bh(rt_hash_lock_addr(i));
@@ -1000,10 +999,10 @@
 				if (!rt_is_expired(rth) &&
 					!rt_may_expire(rth, tmo, expire)) {
 					tmo >>= 1;
-					rthp = &rth->u.dst.rt_next;
+					rthp = &rth->dst.rt_next;
 					continue;
 				}
-				*rthp = rth->u.dst.rt_next;
+				*rthp = rth->dst.rt_next;
 				rt_free(rth);
 				goal--;
 			}
@@ -1069,7 +1068,7 @@
 
 	while (rth) {
 		length += has_noalias(head, rth);
-		rth = rth->u.dst.rt_next;
+		rth = rth->dst.rt_next;
 	}
 	return length >> FRACT_BITS;
 }
@@ -1091,7 +1090,7 @@
 	candp = NULL;
 	now = jiffies;
 
-	if (!rt_caching(dev_net(rt->u.dst.dev))) {
+	if (!rt_caching(dev_net(rt->dst.dev))) {
 		/*
 		 * If we're not caching, just tell the caller we
 		 * were successful and don't touch the route.  The
@@ -1109,7 +1108,7 @@
 		 */
 
 		if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
-			int err = arp_bind_neighbour(&rt->u.dst);
+			int err = arp_bind_neighbour(&rt->dst);
 			if (err) {
 				if (net_ratelimit())
 					printk(KERN_WARNING
@@ -1128,19 +1127,19 @@
 	spin_lock_bh(rt_hash_lock_addr(hash));
 	while ((rth = *rthp) != NULL) {
 		if (rt_is_expired(rth)) {
-			*rthp = rth->u.dst.rt_next;
+			*rthp = rth->dst.rt_next;
 			rt_free(rth);
 			continue;
 		}
 		if (compare_keys(&rth->fl, &rt->fl) && compare_netns(rth, rt)) {
 			/* Put it first */
-			*rthp = rth->u.dst.rt_next;
+			*rthp = rth->dst.rt_next;
 			/*
 			 * Since lookup is lockfree, the deletion
 			 * must be visible to another weakly ordered CPU before
 			 * the insertion at the start of the hash chain.
 			 */
-			rcu_assign_pointer(rth->u.dst.rt_next,
+			rcu_assign_pointer(rth->dst.rt_next,
 					   rt_hash_table[hash].chain);
 			/*
 			 * Since lookup is lockfree, the update writes
@@ -1148,18 +1147,18 @@
 			 */
 			rcu_assign_pointer(rt_hash_table[hash].chain, rth);
 
-			dst_use(&rth->u.dst, now);
+			dst_use(&rth->dst, now);
 			spin_unlock_bh(rt_hash_lock_addr(hash));
 
 			rt_drop(rt);
 			if (rp)
 				*rp = rth;
 			else
-				skb_dst_set(skb, &rth->u.dst);
+				skb_dst_set(skb, &rth->dst);
 			return 0;
 		}
 
-		if (!atomic_read(&rth->u.dst.__refcnt)) {
+		if (!atomic_read(&rth->dst.__refcnt)) {
 			u32 score = rt_score(rth);
 
 			if (score <= min_score) {
@@ -1171,7 +1170,7 @@
 
 		chain_length++;
 
-		rthp = &rth->u.dst.rt_next;
+		rthp = &rth->dst.rt_next;
 	}
 
 	if (cand) {
@@ -1182,17 +1181,17 @@
 		 * only 2 entries per bucket. We will see.
 		 */
 		if (chain_length > ip_rt_gc_elasticity) {
-			*candp = cand->u.dst.rt_next;
+			*candp = cand->dst.rt_next;
 			rt_free(cand);
 		}
 	} else {
 		if (chain_length > rt_chain_length_max &&
 		    slow_chain_length(rt_hash_table[hash].chain) > rt_chain_length_max) {
-			struct net *net = dev_net(rt->u.dst.dev);
+			struct net *net = dev_net(rt->dst.dev);
 			int num = ++net->ipv4.current_rt_cache_rebuild_count;
 			if (!rt_caching(net)) {
 				printk(KERN_WARNING "%s: %d rebuilds is over limit, route caching disabled\n",
-					rt->u.dst.dev->name, num);
+					rt->dst.dev->name, num);
 			}
 			rt_emergency_hash_rebuild(net);
 			spin_unlock_bh(rt_hash_lock_addr(hash));
@@ -1207,7 +1206,7 @@
 	   route or unicast forwarding path.
 	 */
 	if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
-		int err = arp_bind_neighbour(&rt->u.dst);
+		int err = arp_bind_neighbour(&rt->dst);
 		if (err) {
 			spin_unlock_bh(rt_hash_lock_addr(hash));
 
@@ -1238,14 +1237,14 @@
 		}
 	}
 
-	rt->u.dst.rt_next = rt_hash_table[hash].chain;
+	rt->dst.rt_next = rt_hash_table[hash].chain;
 
 #if RT_CACHE_DEBUG >= 2
-	if (rt->u.dst.rt_next) {
+	if (rt->dst.rt_next) {
 		struct rtable *trt;
 		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)
+		for (trt = rt->dst.rt_next; trt; trt = trt->dst.rt_next)
 			printk(" . %pI4", &trt->rt_dst);
 		printk("\n");
 	}
@@ -1263,7 +1262,7 @@
 	if (rp)
 		*rp = rt;
 	else
-		skb_dst_set(skb, &rt->u.dst);
+		skb_dst_set(skb, &rt->dst);
 	return 0;
 }
 
@@ -1325,6 +1324,7 @@
 
 	ip_select_fb_ident(iph);
 }
+EXPORT_SYMBOL(__ip_select_ident);
 
 static void rt_del(unsigned hash, struct rtable *rt)
 {
@@ -1335,20 +1335,21 @@
 	ip_rt_put(rt);
 	while ((aux = *rthp) != NULL) {
 		if (aux == rt || rt_is_expired(aux)) {
-			*rthp = aux->u.dst.rt_next;
+			*rthp = aux->dst.rt_next;
 			rt_free(aux);
 			continue;
 		}
-		rthp = &aux->u.dst.rt_next;
+		rthp = &aux->dst.rt_next;
 	}
 	spin_unlock_bh(rt_hash_lock_addr(hash));
 }
 
+/* called in rcu_read_lock() section */
 void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
 		    __be32 saddr, struct net_device *dev)
 {
 	int i, k;
-	struct in_device *in_dev = in_dev_get(dev);
+	struct in_device *in_dev = __in_dev_get_rcu(dev);
 	struct rtable *rth, **rthp;
 	__be32  skeys[2] = { saddr, 0 };
 	int  ikeys[2] = { dev->ifindex, 0 };
@@ -1384,7 +1385,6 @@
 
 			rthp=&rt_hash_table[hash].chain;
 
-			rcu_read_lock();
 			while ((rth = rcu_dereference(*rthp)) != NULL) {
 				struct rtable *rt;
 
@@ -1393,44 +1393,42 @@
 				    rth->fl.oif != ikeys[k] ||
 				    rth->fl.iif != 0 ||
 				    rt_is_expired(rth) ||
-				    !net_eq(dev_net(rth->u.dst.dev), net)) {
-					rthp = &rth->u.dst.rt_next;
+				    !net_eq(dev_net(rth->dst.dev), net)) {
+					rthp = &rth->dst.rt_next;
 					continue;
 				}
 
 				if (rth->rt_dst != daddr ||
 				    rth->rt_src != saddr ||
-				    rth->u.dst.error ||
+				    rth->dst.error ||
 				    rth->rt_gateway != old_gw ||
-				    rth->u.dst.dev != dev)
+				    rth->dst.dev != dev)
 					break;
 
-				dst_hold(&rth->u.dst);
-				rcu_read_unlock();
+				dst_hold(&rth->dst);
 
 				rt = dst_alloc(&ipv4_dst_ops);
 				if (rt == NULL) {
 					ip_rt_put(rth);
-					in_dev_put(in_dev);
 					return;
 				}
 
 				/* Copy all the information. */
 				*rt = *rth;
-				rt->u.dst.__use		= 1;
-				atomic_set(&rt->u.dst.__refcnt, 1);
-				rt->u.dst.child		= NULL;
-				if (rt->u.dst.dev)
-					dev_hold(rt->u.dst.dev);
+				rt->dst.__use		= 1;
+				atomic_set(&rt->dst.__refcnt, 1);
+				rt->dst.child		= NULL;
+				if (rt->dst.dev)
+					dev_hold(rt->dst.dev);
 				if (rt->idev)
 					in_dev_hold(rt->idev);
-				rt->u.dst.obsolete	= -1;
-				rt->u.dst.lastuse	= jiffies;
-				rt->u.dst.path		= &rt->u.dst;
-				rt->u.dst.neighbour	= NULL;
-				rt->u.dst.hh		= NULL;
+				rt->dst.obsolete	= -1;
+				rt->dst.lastuse	= jiffies;
+				rt->dst.path		= &rt->dst;
+				rt->dst.neighbour	= NULL;
+				rt->dst.hh		= NULL;
 #ifdef CONFIG_XFRM
-				rt->u.dst.xfrm		= NULL;
+				rt->dst.xfrm		= NULL;
 #endif
 				rt->rt_genid		= rt_genid(net);
 				rt->rt_flags		|= RTCF_REDIRECTED;
@@ -1439,23 +1437,23 @@
 				rt->rt_gateway		= new_gw;
 
 				/* Redirect received -> path was valid */
-				dst_confirm(&rth->u.dst);
+				dst_confirm(&rth->dst);
 
 				if (rt->peer)
 					atomic_inc(&rt->peer->refcnt);
 
-				if (arp_bind_neighbour(&rt->u.dst) ||
-				    !(rt->u.dst.neighbour->nud_state &
+				if (arp_bind_neighbour(&rt->dst) ||
+				    !(rt->dst.neighbour->nud_state &
 					    NUD_VALID)) {
-					if (rt->u.dst.neighbour)
-						neigh_event_send(rt->u.dst.neighbour, NULL);
+					if (rt->dst.neighbour)
+						neigh_event_send(rt->dst.neighbour, NULL);
 					ip_rt_put(rth);
 					rt_drop(rt);
 					goto do_next;
 				}
 
-				netevent.old = &rth->u.dst;
-				netevent.new = &rt->u.dst;
+				netevent.old = &rth->dst;
+				netevent.new = &rt->dst;
 				call_netevent_notifiers(NETEVENT_REDIRECT,
 							&netevent);
 
@@ -1464,12 +1462,10 @@
 					ip_rt_put(rt);
 				goto do_next;
 			}
-			rcu_read_unlock();
 		do_next:
 			;
 		}
 	}
-	in_dev_put(in_dev);
 	return;
 
 reject_redirect:
@@ -1480,7 +1476,7 @@
 		       &old_gw, dev->name, &new_gw,
 		       &saddr, &daddr);
 #endif
-	in_dev_put(in_dev);
+	;
 }
 
 static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
@@ -1493,8 +1489,8 @@
 			ip_rt_put(rt);
 			ret = NULL;
 		} else if ((rt->rt_flags & RTCF_REDIRECTED) ||
-			   (rt->u.dst.expires &&
-			    time_after_eq(jiffies, rt->u.dst.expires))) {
+			   (rt->dst.expires &&
+			    time_after_eq(jiffies, rt->dst.expires))) {
 			unsigned hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src,
 						rt->fl.oif,
 						rt_genid(dev_net(dst->dev)));
@@ -1532,7 +1528,7 @@
 	int log_martians;
 
 	rcu_read_lock();
-	in_dev = __in_dev_get_rcu(rt->u.dst.dev);
+	in_dev = __in_dev_get_rcu(rt->dst.dev);
 	if (!in_dev || !IN_DEV_TX_REDIRECTS(in_dev)) {
 		rcu_read_unlock();
 		return;
@@ -1543,30 +1539,30 @@
 	/* No redirected packets during ip_rt_redirect_silence;
 	 * reset the algorithm.
 	 */
-	if (time_after(jiffies, rt->u.dst.rate_last + ip_rt_redirect_silence))
-		rt->u.dst.rate_tokens = 0;
+	if (time_after(jiffies, rt->dst.rate_last + ip_rt_redirect_silence))
+		rt->dst.rate_tokens = 0;
 
 	/* Too many ignored redirects; do not send anything
-	 * set u.dst.rate_last to the last seen redirected packet.
+	 * set dst.rate_last to the last seen redirected packet.
 	 */
-	if (rt->u.dst.rate_tokens >= ip_rt_redirect_number) {
-		rt->u.dst.rate_last = jiffies;
+	if (rt->dst.rate_tokens >= ip_rt_redirect_number) {
+		rt->dst.rate_last = jiffies;
 		return;
 	}
 
 	/* Check for load limit; set rate_last to the latest sent
 	 * redirect.
 	 */
-	if (rt->u.dst.rate_tokens == 0 ||
+	if (rt->dst.rate_tokens == 0 ||
 	    time_after(jiffies,
-		       (rt->u.dst.rate_last +
-			(ip_rt_redirect_load << rt->u.dst.rate_tokens)))) {
+		       (rt->dst.rate_last +
+			(ip_rt_redirect_load << rt->dst.rate_tokens)))) {
 		icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
-		rt->u.dst.rate_last = jiffies;
-		++rt->u.dst.rate_tokens;
+		rt->dst.rate_last = jiffies;
+		++rt->dst.rate_tokens;
 #ifdef CONFIG_IP_ROUTE_VERBOSE
 		if (log_martians &&
-		    rt->u.dst.rate_tokens == ip_rt_redirect_number &&
+		    rt->dst.rate_tokens == ip_rt_redirect_number &&
 		    net_ratelimit())
 			printk(KERN_WARNING "host %pI4/if%d ignores redirects for %pI4 to %pI4.\n",
 				&rt->rt_src, rt->rt_iif,
@@ -1581,7 +1577,7 @@
 	unsigned long now;
 	int code;
 
-	switch (rt->u.dst.error) {
+	switch (rt->dst.error) {
 		case EINVAL:
 		default:
 			goto out;
@@ -1590,7 +1586,7 @@
 			break;
 		case ENETUNREACH:
 			code = ICMP_NET_UNREACH;
-			IP_INC_STATS_BH(dev_net(rt->u.dst.dev),
+			IP_INC_STATS_BH(dev_net(rt->dst.dev),
 					IPSTATS_MIB_INNOROUTES);
 			break;
 		case EACCES:
@@ -1599,12 +1595,12 @@
 	}
 
 	now = jiffies;
-	rt->u.dst.rate_tokens += now - rt->u.dst.rate_last;
-	if (rt->u.dst.rate_tokens > ip_rt_error_burst)
-		rt->u.dst.rate_tokens = ip_rt_error_burst;
-	rt->u.dst.rate_last = now;
-	if (rt->u.dst.rate_tokens >= ip_rt_error_cost) {
-		rt->u.dst.rate_tokens -= ip_rt_error_cost;
+	rt->dst.rate_tokens += now - rt->dst.rate_last;
+	if (rt->dst.rate_tokens > ip_rt_error_burst)
+		rt->dst.rate_tokens = ip_rt_error_burst;
+	rt->dst.rate_last = now;
+	if (rt->dst.rate_tokens >= ip_rt_error_cost) {
+		rt->dst.rate_tokens -= ip_rt_error_cost;
 		icmp_send(skb, ICMP_DEST_UNREACH, code, 0);
 	}
 
@@ -1649,7 +1645,7 @@
 
 			rcu_read_lock();
 			for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
-			     rth = rcu_dereference(rth->u.dst.rt_next)) {
+			     rth = rcu_dereference(rth->dst.rt_next)) {
 				unsigned short mtu = new_mtu;
 
 				if (rth->fl.fl4_dst != daddr ||
@@ -1658,8 +1654,8 @@
 				    rth->rt_src != iph->saddr ||
 				    rth->fl.oif != ikeys[k] ||
 				    rth->fl.iif != 0 ||
-				    dst_metric_locked(&rth->u.dst, RTAX_MTU) ||
-				    !net_eq(dev_net(rth->u.dst.dev), net) ||
+				    dst_metric_locked(&rth->dst, RTAX_MTU) ||
+				    !net_eq(dev_net(rth->dst.dev), net) ||
 				    rt_is_expired(rth))
 					continue;
 
@@ -1667,22 +1663,22 @@
 
 					/* BSD 4.2 compatibility hack :-( */
 					if (mtu == 0 &&
-					    old_mtu >= dst_mtu(&rth->u.dst) &&
+					    old_mtu >= dst_mtu(&rth->dst) &&
 					    old_mtu >= 68 + (iph->ihl << 2))
 						old_mtu -= iph->ihl << 2;
 
 					mtu = guess_mtu(old_mtu);
 				}
-				if (mtu <= dst_mtu(&rth->u.dst)) {
-					if (mtu < dst_mtu(&rth->u.dst)) {
-						dst_confirm(&rth->u.dst);
+				if (mtu <= dst_mtu(&rth->dst)) {
+					if (mtu < dst_mtu(&rth->dst)) {
+						dst_confirm(&rth->dst);
 						if (mtu < ip_rt_min_pmtu) {
 							mtu = ip_rt_min_pmtu;
-							rth->u.dst.metrics[RTAX_LOCK-1] |=
+							rth->dst.metrics[RTAX_LOCK-1] |=
 								(1 << RTAX_MTU);
 						}
-						rth->u.dst.metrics[RTAX_MTU-1] = mtu;
-						dst_set_expires(&rth->u.dst,
+						rth->dst.metrics[RTAX_MTU-1] = mtu;
+						dst_set_expires(&rth->dst,
 							ip_rt_mtu_expires);
 					}
 					est_mtu = mtu;
@@ -1755,7 +1751,7 @@
 
 	rt = skb_rtable(skb);
 	if (rt)
-		dst_set_expires(&rt->u.dst, 0);
+		dst_set_expires(&rt->dst, 0);
 }
 
 static int ip_rt_bug(struct sk_buff *skb)
@@ -1783,11 +1779,11 @@
 
 	if (rt->fl.iif == 0)
 		src = rt->rt_src;
-	else if (fib_lookup(dev_net(rt->u.dst.dev), &rt->fl, &res) == 0) {
+	else if (fib_lookup(dev_net(rt->dst.dev), &rt->fl, &res) == 0) {
 		src = FIB_RES_PREFSRC(res);
 		fib_res_put(&res);
 	} else
-		src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
+		src = inet_select_addr(rt->dst.dev, rt->rt_gateway,
 					RT_SCOPE_UNIVERSE);
 	memcpy(addr, &src, 4);
 }
@@ -1795,10 +1791,10 @@
 #ifdef CONFIG_NET_CLS_ROUTE
 static void set_class_tag(struct rtable *rt, u32 tag)
 {
-	if (!(rt->u.dst.tclassid & 0xFFFF))
-		rt->u.dst.tclassid |= tag & 0xFFFF;
-	if (!(rt->u.dst.tclassid & 0xFFFF0000))
-		rt->u.dst.tclassid |= tag & 0xFFFF0000;
+	if (!(rt->dst.tclassid & 0xFFFF))
+		rt->dst.tclassid |= tag & 0xFFFF;
+	if (!(rt->dst.tclassid & 0xFFFF0000))
+		rt->dst.tclassid |= tag & 0xFFFF0000;
 }
 #endif
 
@@ -1810,30 +1806,30 @@
 		if (FIB_RES_GW(*res) &&
 		    FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
 			rt->rt_gateway = FIB_RES_GW(*res);
-		memcpy(rt->u.dst.metrics, fi->fib_metrics,
-		       sizeof(rt->u.dst.metrics));
+		memcpy(rt->dst.metrics, fi->fib_metrics,
+		       sizeof(rt->dst.metrics));
 		if (fi->fib_mtu == 0) {
-			rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu;
-			if (dst_metric_locked(&rt->u.dst, RTAX_MTU) &&
+			rt->dst.metrics[RTAX_MTU-1] = rt->dst.dev->mtu;
+			if (dst_metric_locked(&rt->dst, RTAX_MTU) &&
 			    rt->rt_gateway != rt->rt_dst &&
-			    rt->u.dst.dev->mtu > 576)
-				rt->u.dst.metrics[RTAX_MTU-1] = 576;
+			    rt->dst.dev->mtu > 576)
+				rt->dst.metrics[RTAX_MTU-1] = 576;
 		}
 #ifdef CONFIG_NET_CLS_ROUTE
-		rt->u.dst.tclassid = FIB_RES_NH(*res).nh_tclassid;
+		rt->dst.tclassid = FIB_RES_NH(*res).nh_tclassid;
 #endif
 	} else
-		rt->u.dst.metrics[RTAX_MTU-1]= rt->u.dst.dev->mtu;
+		rt->dst.metrics[RTAX_MTU-1]= rt->dst.dev->mtu;
 
-	if (dst_metric(&rt->u.dst, RTAX_HOPLIMIT) == 0)
-		rt->u.dst.metrics[RTAX_HOPLIMIT-1] = sysctl_ip_default_ttl;
-	if (dst_mtu(&rt->u.dst) > IP_MAX_MTU)
-		rt->u.dst.metrics[RTAX_MTU-1] = IP_MAX_MTU;
-	if (dst_metric(&rt->u.dst, RTAX_ADVMSS) == 0)
-		rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, rt->u.dst.dev->mtu - 40,
+	if (dst_metric(&rt->dst, RTAX_HOPLIMIT) == 0)
+		rt->dst.metrics[RTAX_HOPLIMIT-1] = sysctl_ip_default_ttl;
+	if (dst_mtu(&rt->dst) > IP_MAX_MTU)
+		rt->dst.metrics[RTAX_MTU-1] = IP_MAX_MTU;
+	if (dst_metric(&rt->dst, RTAX_ADVMSS) == 0)
+		rt->dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, rt->dst.dev->mtu - 40,
 				       ip_rt_min_advmss);
-	if (dst_metric(&rt->u.dst, RTAX_ADVMSS) > 65535 - 40)
-		rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535 - 40;
+	if (dst_metric(&rt->dst, RTAX_ADVMSS) > 65535 - 40)
+		rt->dst.metrics[RTAX_ADVMSS-1] = 65535 - 40;
 
 #ifdef CONFIG_NET_CLS_ROUTE
 #ifdef CONFIG_IP_MULTIPLE_TABLES
@@ -1844,14 +1840,16 @@
 	rt->rt_type = res->type;
 }
 
+/* called in rcu_read_lock() section */
 static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 				u8 tos, struct net_device *dev, int our)
 {
-	unsigned hash;
+	unsigned int hash;
 	struct rtable *rth;
 	__be32 spec_dst;
-	struct in_device *in_dev = in_dev_get(dev);
+	struct in_device *in_dev = __in_dev_get_rcu(dev);
 	u32 itag = 0;
+	int err;
 
 	/* Primary sanity checks. */
 
@@ -1866,21 +1864,23 @@
 		if (!ipv4_is_local_multicast(daddr))
 			goto e_inval;
 		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
-	} else if (fib_validate_source(saddr, 0, tos, 0,
-					dev, &spec_dst, &itag, 0) < 0)
-		goto e_inval;
-
+	} else {
+		err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
+					  &itag, 0);
+		if (err < 0)
+			goto e_err;
+	}
 	rth = dst_alloc(&ipv4_dst_ops);
 	if (!rth)
 		goto e_nobufs;
 
-	rth->u.dst.output = ip_rt_bug;
-	rth->u.dst.obsolete = -1;
+	rth->dst.output = ip_rt_bug;
+	rth->dst.obsolete = -1;
 
-	atomic_set(&rth->u.dst.__refcnt, 1);
-	rth->u.dst.flags= DST_HOST;
+	atomic_set(&rth->dst.__refcnt, 1);
+	rth->dst.flags= DST_HOST;
 	if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
-		rth->u.dst.flags |= DST_NOPOLICY;
+		rth->dst.flags |= DST_NOPOLICY;
 	rth->fl.fl4_dst	= daddr;
 	rth->rt_dst	= daddr;
 	rth->fl.fl4_tos	= tos;
@@ -1888,13 +1888,13 @@
 	rth->fl.fl4_src	= saddr;
 	rth->rt_src	= saddr;
 #ifdef CONFIG_NET_CLS_ROUTE
-	rth->u.dst.tclassid = itag;
+	rth->dst.tclassid = itag;
 #endif
 	rth->rt_iif	=
 	rth->fl.iif	= dev->ifindex;
-	rth->u.dst.dev	= init_net.loopback_dev;
-	dev_hold(rth->u.dst.dev);
-	rth->idev	= in_dev_get(rth->u.dst.dev);
+	rth->dst.dev	= init_net.loopback_dev;
+	dev_hold(rth->dst.dev);
+	rth->idev	= in_dev_get(rth->dst.dev);
 	rth->fl.oif	= 0;
 	rth->rt_gateway	= daddr;
 	rth->rt_spec_dst= spec_dst;
@@ -1902,27 +1902,25 @@
 	rth->rt_flags	= RTCF_MULTICAST;
 	rth->rt_type	= RTN_MULTICAST;
 	if (our) {
-		rth->u.dst.input= ip_local_deliver;
+		rth->dst.input= ip_local_deliver;
 		rth->rt_flags |= RTCF_LOCAL;
 	}
 
 #ifdef CONFIG_IP_MROUTE
 	if (!ipv4_is_local_multicast(daddr) && IN_DEV_MFORWARD(in_dev))
-		rth->u.dst.input = ip_mr_input;
+		rth->dst.input = ip_mr_input;
 #endif
 	RT_CACHE_STAT_INC(in_slow_mc);
 
-	in_dev_put(in_dev);
 	hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev)));
 	return rt_intern_hash(hash, rth, NULL, skb, dev->ifindex);
 
 e_nobufs:
-	in_dev_put(in_dev);
 	return -ENOBUFS;
-
 e_inval:
-	in_dev_put(in_dev);
 	return -EINVAL;
+e_err:
+	return err;
 }
 
 
@@ -1956,22 +1954,22 @@
 #endif
 }
 
+/* called in rcu_read_lock() section */
 static int __mkroute_input(struct sk_buff *skb,
 			   struct fib_result *res,
 			   struct in_device *in_dev,
 			   __be32 daddr, __be32 saddr, u32 tos,
 			   struct rtable **result)
 {
-
 	struct rtable *rth;
 	int err;
 	struct in_device *out_dev;
-	unsigned flags = 0;
+	unsigned int flags = 0;
 	__be32 spec_dst;
 	u32 itag;
 
 	/* get a working reference to the output device */
-	out_dev = in_dev_get(FIB_RES_DEV(*res));
+	out_dev = __in_dev_get_rcu(FIB_RES_DEV(*res));
 	if (out_dev == NULL) {
 		if (net_ratelimit())
 			printk(KERN_CRIT "Bug in ip_route_input" \
@@ -1986,7 +1984,6 @@
 		ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr,
 					 saddr);
 
-		err = -EINVAL;
 		goto cleanup;
 	}
 
@@ -2020,12 +2017,12 @@
 		goto cleanup;
 	}
 
-	atomic_set(&rth->u.dst.__refcnt, 1);
-	rth->u.dst.flags= DST_HOST;
+	atomic_set(&rth->dst.__refcnt, 1);
+	rth->dst.flags= DST_HOST;
 	if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
-		rth->u.dst.flags |= DST_NOPOLICY;
+		rth->dst.flags |= DST_NOPOLICY;
 	if (IN_DEV_CONF_GET(out_dev, NOXFRM))
-		rth->u.dst.flags |= DST_NOXFRM;
+		rth->dst.flags |= DST_NOXFRM;
 	rth->fl.fl4_dst	= daddr;
 	rth->rt_dst	= daddr;
 	rth->fl.fl4_tos	= tos;
@@ -2035,16 +2032,16 @@
 	rth->rt_gateway	= daddr;
 	rth->rt_iif 	=
 		rth->fl.iif	= in_dev->dev->ifindex;
-	rth->u.dst.dev	= (out_dev)->dev;
-	dev_hold(rth->u.dst.dev);
-	rth->idev	= in_dev_get(rth->u.dst.dev);
+	rth->dst.dev	= (out_dev)->dev;
+	dev_hold(rth->dst.dev);
+	rth->idev	= in_dev_get(rth->dst.dev);
 	rth->fl.oif 	= 0;
 	rth->rt_spec_dst= spec_dst;
 
-	rth->u.dst.obsolete = -1;
-	rth->u.dst.input = ip_forward;
-	rth->u.dst.output = ip_output;
-	rth->rt_genid = rt_genid(dev_net(rth->u.dst.dev));
+	rth->dst.obsolete = -1;
+	rth->dst.input = ip_forward;
+	rth->dst.output = ip_output;
+	rth->rt_genid = rt_genid(dev_net(rth->dst.dev));
 
 	rt_set_nexthop(rth, res, itag);
 
@@ -2053,8 +2050,6 @@
 	*result = rth;
 	err = 0;
  cleanup:
-	/* release the working reference to the output device */
-	in_dev_put(out_dev);
 	return err;
 }
 
@@ -2080,7 +2075,7 @@
 
 	/* put it into the cache */
 	hash = rt_hash(daddr, saddr, fl->iif,
-		       rt_genid(dev_net(rth->u.dst.dev)));
+		       rt_genid(dev_net(rth->dst.dev)));
 	return rt_intern_hash(hash, rth, NULL, skb, fl->iif);
 }
 
@@ -2098,7 +2093,7 @@
 			       u8 tos, struct net_device *dev)
 {
 	struct fib_result res;
-	struct in_device *in_dev = in_dev_get(dev);
+	struct in_device *in_dev = __in_dev_get_rcu(dev);
 	struct flowi fl = { .nl_u = { .ip4_u =
 				      { .daddr = daddr,
 					.saddr = saddr,
@@ -2158,13 +2153,12 @@
 		goto brd_input;
 
 	if (res.type == RTN_LOCAL) {
-		int result;
-		result = fib_validate_source(saddr, daddr, tos,
+		err = fib_validate_source(saddr, daddr, tos,
 					     net->loopback_dev->ifindex,
 					     dev, &spec_dst, &itag, skb->mark);
-		if (result < 0)
-			goto martian_source;
-		if (result)
+		if (err < 0)
+			goto martian_source_keep_err;
+		if (err)
 			flags |= RTCF_DIRECTSRC;
 		spec_dst = daddr;
 		goto local_input;
@@ -2177,7 +2171,6 @@
 
 	err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);
 done:
-	in_dev_put(in_dev);
 	if (free_res)
 		fib_res_put(&res);
 out:	return err;
@@ -2192,7 +2185,7 @@
 		err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
 					  &itag, skb->mark);
 		if (err < 0)
-			goto martian_source;
+			goto martian_source_keep_err;
 		if (err)
 			flags |= RTCF_DIRECTSRC;
 	}
@@ -2205,14 +2198,14 @@
 	if (!rth)
 		goto e_nobufs;
 
-	rth->u.dst.output= ip_rt_bug;
-	rth->u.dst.obsolete = -1;
+	rth->dst.output= ip_rt_bug;
+	rth->dst.obsolete = -1;
 	rth->rt_genid = rt_genid(net);
 
-	atomic_set(&rth->u.dst.__refcnt, 1);
-	rth->u.dst.flags= DST_HOST;
+	atomic_set(&rth->dst.__refcnt, 1);
+	rth->dst.flags= DST_HOST;
 	if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
-		rth->u.dst.flags |= DST_NOPOLICY;
+		rth->dst.flags |= DST_NOPOLICY;
 	rth->fl.fl4_dst	= daddr;
 	rth->rt_dst	= daddr;
 	rth->fl.fl4_tos	= tos;
@@ -2220,20 +2213,20 @@
 	rth->fl.fl4_src	= saddr;
 	rth->rt_src	= saddr;
 #ifdef CONFIG_NET_CLS_ROUTE
-	rth->u.dst.tclassid = itag;
+	rth->dst.tclassid = itag;
 #endif
 	rth->rt_iif	=
 	rth->fl.iif	= dev->ifindex;
-	rth->u.dst.dev	= net->loopback_dev;
-	dev_hold(rth->u.dst.dev);
-	rth->idev	= in_dev_get(rth->u.dst.dev);
+	rth->dst.dev	= net->loopback_dev;
+	dev_hold(rth->dst.dev);
+	rth->idev	= in_dev_get(rth->dst.dev);
 	rth->rt_gateway	= daddr;
 	rth->rt_spec_dst= spec_dst;
-	rth->u.dst.input= ip_local_deliver;
+	rth->dst.input= ip_local_deliver;
 	rth->rt_flags 	= flags|RTCF_LOCAL;
 	if (res.type == RTN_UNREACHABLE) {
-		rth->u.dst.input= ip_error;
-		rth->u.dst.error= -err;
+		rth->dst.input= ip_error;
+		rth->dst.error= -err;
 		rth->rt_flags 	&= ~RTCF_LOCAL;
 	}
 	rth->rt_type	= res.type;
@@ -2273,8 +2266,10 @@
 	goto done;
 
 martian_source:
+	err = -EINVAL;
+martian_source_keep_err:
 	ip_handle_martian_source(dev, in_dev, skb, daddr, saddr);
-	goto e_inval;
+	goto done;
 }
 
 int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
@@ -2284,32 +2279,34 @@
 	unsigned	hash;
 	int iif = dev->ifindex;
 	struct net *net;
+	int res;
 
 	net = dev_net(dev);
 
+	rcu_read_lock();
+
 	if (!rt_caching(net))
 		goto skip_cache;
 
 	tos &= IPTOS_RT_MASK;
 	hash = rt_hash(daddr, saddr, iif, rt_genid(net));
 
-	rcu_read_lock();
 	for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
-	     rth = rcu_dereference(rth->u.dst.rt_next)) {
+	     rth = rcu_dereference(rth->dst.rt_next)) {
 		if ((((__force u32)rth->fl.fl4_dst ^ (__force u32)daddr) |
 		     ((__force u32)rth->fl.fl4_src ^ (__force u32)saddr) |
 		     (rth->fl.iif ^ iif) |
 		     rth->fl.oif |
 		     (rth->fl.fl4_tos ^ tos)) == 0 &&
 		    rth->fl.mark == skb->mark &&
-		    net_eq(dev_net(rth->u.dst.dev), net) &&
+		    net_eq(dev_net(rth->dst.dev), net) &&
 		    !rt_is_expired(rth)) {
 			if (noref) {
-				dst_use_noref(&rth->u.dst, jiffies);
-				skb_dst_set_noref(skb, &rth->u.dst);
+				dst_use_noref(&rth->dst, jiffies);
+				skb_dst_set_noref(skb, &rth->dst);
 			} else {
-				dst_use(&rth->u.dst, jiffies);
-				skb_dst_set(skb, &rth->u.dst);
+				dst_use(&rth->dst, jiffies);
+				skb_dst_set(skb, &rth->dst);
 			}
 			RT_CACHE_STAT_INC(in_hit);
 			rcu_read_unlock();
@@ -2317,7 +2314,6 @@
 		}
 		RT_CACHE_STAT_INC(in_hlist_search);
 	}
-	rcu_read_unlock();
 
 skip_cache:
 	/* Multicast recognition logic is moved from route cache to here.
@@ -2332,12 +2328,11 @@
 	   route cache entry is created eventually.
 	 */
 	if (ipv4_is_multicast(daddr)) {
-		struct in_device *in_dev;
+		struct in_device *in_dev = __in_dev_get_rcu(dev);
 
-		rcu_read_lock();
-		if ((in_dev = __in_dev_get_rcu(dev)) != NULL) {
+		if (in_dev) {
 			int our = ip_check_mc(in_dev, daddr, saddr,
-				ip_hdr(skb)->protocol);
+					      ip_hdr(skb)->protocol);
 			if (our
 #ifdef CONFIG_IP_MROUTE
 				||
@@ -2345,15 +2340,18 @@
 			     IN_DEV_MFORWARD(in_dev))
 #endif
 			   ) {
+				int res = ip_route_input_mc(skb, daddr, saddr,
+							    tos, dev, our);
 				rcu_read_unlock();
-				return ip_route_input_mc(skb, daddr, saddr,
-							 tos, dev, our);
+				return res;
 			}
 		}
 		rcu_read_unlock();
 		return -EINVAL;
 	}
-	return ip_route_input_slow(skb, daddr, saddr, tos, dev);
+	res = ip_route_input_slow(skb, daddr, saddr, tos, dev);
+	rcu_read_unlock();
+	return res;
 }
 EXPORT_SYMBOL(ip_route_input_common);
 
@@ -2415,12 +2413,12 @@
 		goto cleanup;
 	}
 
-	atomic_set(&rth->u.dst.__refcnt, 1);
-	rth->u.dst.flags= DST_HOST;
+	atomic_set(&rth->dst.__refcnt, 1);
+	rth->dst.flags= DST_HOST;
 	if (IN_DEV_CONF_GET(in_dev, NOXFRM))
-		rth->u.dst.flags |= DST_NOXFRM;
+		rth->dst.flags |= DST_NOXFRM;
 	if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
-		rth->u.dst.flags |= DST_NOPOLICY;
+		rth->dst.flags |= DST_NOPOLICY;
 
 	rth->fl.fl4_dst	= oldflp->fl4_dst;
 	rth->fl.fl4_tos	= tos;
@@ -2432,35 +2430,35 @@
 	rth->rt_iif	= oldflp->oif ? : dev_out->ifindex;
 	/* get references to the devices that are to be hold by the routing
 	   cache entry */
-	rth->u.dst.dev	= dev_out;
+	rth->dst.dev	= dev_out;
 	dev_hold(dev_out);
 	rth->idev	= in_dev_get(dev_out);
 	rth->rt_gateway = fl->fl4_dst;
 	rth->rt_spec_dst= fl->fl4_src;
 
-	rth->u.dst.output=ip_output;
-	rth->u.dst.obsolete = -1;
+	rth->dst.output=ip_output;
+	rth->dst.obsolete = -1;
 	rth->rt_genid = rt_genid(dev_net(dev_out));
 
 	RT_CACHE_STAT_INC(out_slow_tot);
 
 	if (flags & RTCF_LOCAL) {
-		rth->u.dst.input = ip_local_deliver;
+		rth->dst.input = ip_local_deliver;
 		rth->rt_spec_dst = fl->fl4_dst;
 	}
 	if (flags & (RTCF_BROADCAST | RTCF_MULTICAST)) {
 		rth->rt_spec_dst = fl->fl4_src;
 		if (flags & RTCF_LOCAL &&
 		    !(dev_out->flags & IFF_LOOPBACK)) {
-			rth->u.dst.output = ip_mc_output;
+			rth->dst.output = ip_mc_output;
 			RT_CACHE_STAT_INC(out_slow_mc);
 		}
 #ifdef CONFIG_IP_MROUTE
 		if (res->type == RTN_MULTICAST) {
 			if (IN_DEV_MFORWARD(in_dev) &&
 			    !ipv4_is_local_multicast(oldflp->fl4_dst)) {
-				rth->u.dst.input = ip_mr_input;
-				rth->u.dst.output = ip_mc_output;
+				rth->dst.input = ip_mr_input;
+				rth->dst.output = ip_mc_output;
 			}
 		}
 #endif
@@ -2715,7 +2713,7 @@
 
 	rcu_read_lock_bh();
 	for (rth = rcu_dereference_bh(rt_hash_table[hash].chain); rth;
-		rth = rcu_dereference_bh(rth->u.dst.rt_next)) {
+		rth = rcu_dereference_bh(rth->dst.rt_next)) {
 		if (rth->fl.fl4_dst == flp->fl4_dst &&
 		    rth->fl.fl4_src == flp->fl4_src &&
 		    rth->fl.iif == 0 &&
@@ -2723,9 +2721,9 @@
 		    rth->fl.mark == flp->mark &&
 		    !((rth->fl.fl4_tos ^ flp->fl4_tos) &
 			    (IPTOS_RT_MASK | RTO_ONLINK)) &&
-		    net_eq(dev_net(rth->u.dst.dev), net) &&
+		    net_eq(dev_net(rth->dst.dev), net) &&
 		    !rt_is_expired(rth)) {
-			dst_use(&rth->u.dst, jiffies);
+			dst_use(&rth->dst, jiffies);
 			RT_CACHE_STAT_INC(out_hit);
 			rcu_read_unlock_bh();
 			*rp = rth;
@@ -2738,7 +2736,6 @@
 slow_output:
 	return ip_route_output_slow(net, rp, flp);
 }
-
 EXPORT_SYMBOL_GPL(__ip_route_output_key);
 
 static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
@@ -2762,15 +2759,15 @@
 		dst_alloc(&ipv4_dst_blackhole_ops);
 
 	if (rt) {
-		struct dst_entry *new = &rt->u.dst;
+		struct dst_entry *new = &rt->dst;
 
 		atomic_set(&new->__refcnt, 1);
 		new->__use = 1;
 		new->input = dst_discard;
 		new->output = dst_discard;
-		memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
+		memcpy(new->metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32));
 
-		new->dev = ort->u.dst.dev;
+		new->dev = ort->dst.dev;
 		if (new->dev)
 			dev_hold(new->dev);
 
@@ -2794,7 +2791,7 @@
 		dst_free(new);
 	}
 
-	dst_release(&(*rp)->u.dst);
+	dst_release(&(*rp)->dst);
 	*rp = rt;
 	return (rt ? 0 : -ENOMEM);
 }
@@ -2822,13 +2819,13 @@
 
 	return 0;
 }
-
 EXPORT_SYMBOL_GPL(ip_route_output_flow);
 
 int ip_route_output_key(struct net *net, struct rtable **rp, struct flowi *flp)
 {
 	return ip_route_output_flow(net, rp, flp, NULL, 0);
 }
+EXPORT_SYMBOL(ip_route_output_key);
 
 static int rt_fill_info(struct net *net,
 			struct sk_buff *skb, u32 pid, u32 seq, int event,
@@ -2864,11 +2861,11 @@
 		r->rtm_src_len = 32;
 		NLA_PUT_BE32(skb, RTA_SRC, rt->fl.fl4_src);
 	}
-	if (rt->u.dst.dev)
-		NLA_PUT_U32(skb, RTA_OIF, rt->u.dst.dev->ifindex);
+	if (rt->dst.dev)
+		NLA_PUT_U32(skb, RTA_OIF, rt->dst.dev->ifindex);
 #ifdef CONFIG_NET_CLS_ROUTE
-	if (rt->u.dst.tclassid)
-		NLA_PUT_U32(skb, RTA_FLOW, rt->u.dst.tclassid);
+	if (rt->dst.tclassid)
+		NLA_PUT_U32(skb, RTA_FLOW, rt->dst.tclassid);
 #endif
 	if (rt->fl.iif)
 		NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_spec_dst);
@@ -2878,12 +2875,16 @@
 	if (rt->rt_dst != rt->rt_gateway)
 		NLA_PUT_BE32(skb, RTA_GATEWAY, rt->rt_gateway);
 
-	if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
+	if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0)
 		goto nla_put_failure;
 
-	error = rt->u.dst.error;
-	expires = rt->u.dst.expires ? rt->u.dst.expires - jiffies : 0;
+	if (rt->fl.mark)
+		NLA_PUT_BE32(skb, RTA_MARK, rt->fl.mark);
+
+	error = rt->dst.error;
+	expires = rt->dst.expires ? rt->dst.expires - jiffies : 0;
 	if (rt->peer) {
+		inet_peer_refcheck(rt->peer);
 		id = atomic_read(&rt->peer->ip_id_count) & 0xffff;
 		if (rt->peer->tcp_ts_stamp) {
 			ts = rt->peer->tcp_ts;
@@ -2914,7 +2915,7 @@
 			NLA_PUT_U32(skb, RTA_IIF, rt->fl.iif);
 	}
 
-	if (rtnl_put_cacheinfo(skb, &rt->u.dst, id, ts, tsage,
+	if (rtnl_put_cacheinfo(skb, &rt->dst, id, ts, tsage,
 			       expires, error) < 0)
 		goto nla_put_failure;
 
@@ -2935,6 +2936,7 @@
 	__be32 src = 0;
 	u32 iif;
 	int err;
+	int mark;
 	struct sk_buff *skb;
 
 	err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy);
@@ -2962,6 +2964,7 @@
 	src = tb[RTA_SRC] ? nla_get_be32(tb[RTA_SRC]) : 0;
 	dst = tb[RTA_DST] ? nla_get_be32(tb[RTA_DST]) : 0;
 	iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0;
+	mark = tb[RTA_MARK] ? nla_get_u32(tb[RTA_MARK]) : 0;
 
 	if (iif) {
 		struct net_device *dev;
@@ -2974,13 +2977,14 @@
 
 		skb->protocol	= htons(ETH_P_IP);
 		skb->dev	= dev;
+		skb->mark	= mark;
 		local_bh_disable();
 		err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
 		local_bh_enable();
 
 		rt = skb_rtable(skb);
-		if (err == 0 && rt->u.dst.error)
-			err = -rt->u.dst.error;
+		if (err == 0 && rt->dst.error)
+			err = -rt->dst.error;
 	} else {
 		struct flowi fl = {
 			.nl_u = {
@@ -2991,6 +2995,7 @@
 				},
 			},
 			.oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0,
+			.mark = mark,
 		};
 		err = ip_route_output_key(net, &rt, &fl);
 	}
@@ -2998,7 +3003,7 @@
 	if (err)
 		goto errout_free;
 
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 	if (rtm->rtm_flags & RTM_F_NOTIFY)
 		rt->rt_flags |= RTCF_NOTIFY;
 
@@ -3034,12 +3039,12 @@
 			continue;
 		rcu_read_lock_bh();
 		for (rt = rcu_dereference_bh(rt_hash_table[h].chain), idx = 0; rt;
-		     rt = rcu_dereference_bh(rt->u.dst.rt_next), idx++) {
-			if (!net_eq(dev_net(rt->u.dst.dev), net) || idx < s_idx)
+		     rt = rcu_dereference_bh(rt->dst.rt_next), idx++) {
+			if (!net_eq(dev_net(rt->dst.dev), net) || idx < s_idx)
 				continue;
 			if (rt_is_expired(rt))
 				continue;
-			skb_dst_set_noref(skb, &rt->u.dst);
+			skb_dst_set_noref(skb, &rt->dst);
 			if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid,
 					 cb->nlh->nlmsg_seq, RTM_NEWROUTE,
 					 1, NLM_F_MULTI) <= 0) {
@@ -3365,6 +3370,3 @@
 	register_sysctl_paths(ipv4_path, ipv4_skeleton);
 }
 #endif
-
-EXPORT_SYMBOL(__ip_select_ident);
-EXPORT_SYMBOL(ip_route_output_key);
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 9f6b222..650cace 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -18,8 +18,8 @@
 #include <net/tcp.h>
 #include <net/route.h>
 
-/* Timestamps: lowest 9 bits store TCP options */
-#define TSBITS 9
+/* Timestamps: lowest bits store TCP options */
+#define TSBITS 6
 #define TSMASK (((__u32)1 << TSBITS) - 1)
 
 extern int sysctl_tcp_syncookies;
@@ -58,7 +58,7 @@
 
 /*
  * when syncookies are in effect and tcp timestamps are enabled we encode
- * tcp options in the lowest 9 bits of the timestamp value that will be
+ * tcp options in the lower bits of the timestamp value that will be
  * sent in the syn-ack.
  * Since subsequent timestamps use the normal tcp_time_stamp value, we
  * must make sure that the resulting initial timestamp is <= tcp_time_stamp.
@@ -70,11 +70,10 @@
 	u32 options = 0;
 
 	ireq = inet_rsk(req);
-	if (ireq->wscale_ok) {
-		options = ireq->snd_wscale;
-		options |= ireq->rcv_wscale << 4;
-	}
-	options |= ireq->sack_ok << 8;
+
+	options = ireq->wscale_ok ? ireq->snd_wscale : 0xf;
+	options |= ireq->sack_ok << 4;
+	options |= ireq->ecn_ok << 5;
 
 	ts = ts_now & ~TSMASK;
 	ts |= options;
@@ -138,23 +137,23 @@
 }
 
 /*
- * This table has to be sorted and terminated with (__u16)-1.
- * XXX generate a better table.
- * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
+ * MSS Values are taken from the 2009 paper
+ * 'Measuring TCP Maximum Segment Size' by S. Alcock and R. Nelson:
+ *  - values 1440 to 1460 accounted for 80% of observed mss values
+ *  - values outside the 536-1460 range are rare (<0.2%).
+ *
+ * Table must be sorted.
  */
 static __u16 const msstab[] = {
-	64 - 1,
-	256 - 1,
-	512 - 1,
-	536 - 1,
-	1024 - 1,
-	1440 - 1,
-	1460 - 1,
-	4312 - 1,
-	(__u16)-1
+	64,
+	512,
+	536,
+	1024,
+	1440,
+	1460,
+	4312,
+	8960,
 };
-/* The number doesn't include the -1 terminator */
-#define NUM_MSS (ARRAY_SIZE(msstab) - 1)
 
 /*
  * Generate a syncookie.  mssp points to the mss, which is returned
@@ -169,10 +168,10 @@
 
 	tcp_synq_overflow(sk);
 
-	/* XXX sort msstab[] by probability?  Binary search? */
-	for (mssind = 0; mss > msstab[mssind + 1]; mssind++)
-		;
-	*mssp = msstab[mssind] + 1;
+	for (mssind = ARRAY_SIZE(msstab) - 1; mssind ; mssind--)
+		if (mss >= msstab[mssind])
+			break;
+	*mssp = msstab[mssind];
 
 	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT);
 
@@ -202,7 +201,7 @@
 					    jiffies / (HZ * 60),
 					    COUNTER_TRIES);
 
-	return mssind < NUM_MSS ? msstab[mssind] + 1 : 0;
+	return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0;
 }
 
 static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
@@ -227,26 +226,38 @@
  * additional tcp options in the timestamp.
  * This extracts these options from the timestamp echo.
  *
- * The lowest 4 bits are for snd_wscale
- * The next 4 lsb are for rcv_wscale
- * The next lsb is for sack_ok
+ * The lowest 4 bits store snd_wscale.
+ * next 2 bits indicate SACK and ECN support.
+ *
+ * return false if we decode an option that should not be.
  */
-void cookie_check_timestamp(struct tcp_options_received *tcp_opt)
+bool cookie_check_timestamp(struct tcp_options_received *tcp_opt, bool *ecn_ok)
 {
-	/* echoed timestamp, 9 lowest bits contain options */
+	/* echoed timestamp, lowest bits contain options */
 	u32 options = tcp_opt->rcv_tsecr & TSMASK;
 
-	tcp_opt->snd_wscale = options & 0xf;
-	options >>= 4;
-	tcp_opt->rcv_wscale = options & 0xf;
+	if (!tcp_opt->saw_tstamp)  {
+		tcp_clear_options(tcp_opt);
+		return true;
+	}
+
+	if (!sysctl_tcp_timestamps)
+		return false;
 
 	tcp_opt->sack_ok = (options >> 4) & 0x1;
+	*ecn_ok = (options >> 5) & 1;
+	if (*ecn_ok && !sysctl_tcp_ecn)
+		return false;
 
-	if (tcp_opt->sack_ok)
-		tcp_sack_reset(tcp_opt);
+	if (tcp_opt->sack_ok && !sysctl_tcp_sack)
+		return false;
 
-	if (tcp_opt->snd_wscale || tcp_opt->rcv_wscale)
-		tcp_opt->wscale_ok = 1;
+	if ((options & 0xf) == 0xf)
+		return true; /* no window scaling */
+
+	tcp_opt->wscale_ok = 1;
+	tcp_opt->snd_wscale = options & 0xf;
+	return sysctl_tcp_window_scaling != 0;
 }
 EXPORT_SYMBOL(cookie_check_timestamp);
 
@@ -265,8 +276,9 @@
 	int mss;
 	struct rtable *rt;
 	__u8 rcv_wscale;
+	bool ecn_ok;
 
-	if (!sysctl_tcp_syncookies || !th->ack)
+	if (!sysctl_tcp_syncookies || !th->ack || th->rst)
 		goto out;
 
 	if (tcp_synq_no_recent_overflow(sk) ||
@@ -281,8 +293,8 @@
 	memset(&tcp_opt, 0, sizeof(tcp_opt));
 	tcp_parse_options(skb, &tcp_opt, &hash_location, 0);
 
-	if (tcp_opt.saw_tstamp)
-		cookie_check_timestamp(&tcp_opt);
+	if (!cookie_check_timestamp(&tcp_opt, &ecn_ok))
+		goto out;
 
 	ret = NULL;
 	req = inet_reqsk_alloc(&tcp_request_sock_ops); /* for safety */
@@ -298,9 +310,8 @@
 	ireq->rmt_port		= th->source;
 	ireq->loc_addr		= ip_hdr(skb)->daddr;
 	ireq->rmt_addr		= ip_hdr(skb)->saddr;
-	ireq->ecn_ok		= 0;
+	ireq->ecn_ok		= ecn_ok;
 	ireq->snd_wscale	= tcp_opt.snd_wscale;
-	ireq->rcv_wscale	= tcp_opt.rcv_wscale;
 	ireq->sack_ok		= tcp_opt.sack_ok;
 	ireq->wscale_ok		= tcp_opt.wscale_ok;
 	ireq->tstamp_ok		= tcp_opt.saw_tstamp;
@@ -354,15 +365,15 @@
 	}
 
 	/* Try to redo what tcp_v4_send_synack did. */
-	req->window_clamp = tp->window_clamp ? :dst_metric(&rt->u.dst, RTAX_WINDOW);
+	req->window_clamp = tp->window_clamp ? :dst_metric(&rt->dst, RTAX_WINDOW);
 
 	tcp_select_initial_window(tcp_full_space(sk), req->mss,
 				  &req->rcv_wnd, &req->window_clamp,
 				  ireq->wscale_ok, &rcv_wscale,
-				  dst_metric(&rt->u.dst, RTAX_INITRWND));
+				  dst_metric(&rt->dst, RTAX_INITRWND));
 
 	ireq->rcv_wscale  = rcv_wscale;
 
-	ret = get_cookie_sock(sk, skb, req, &rt->u.dst);
+	ret = get_cookie_sock(sk, skb, req, &rt->dst);
 out:	return ret;
 }
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 65afeae..176e11a 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -315,7 +315,6 @@
  * is strict, actions are advisory and have some latency.
  */
 int tcp_memory_pressure __read_mostly;
-
 EXPORT_SYMBOL(tcp_memory_pressure);
 
 void tcp_enter_memory_pressure(struct sock *sk)
@@ -325,7 +324,6 @@
 		tcp_memory_pressure = 1;
 	}
 }
-
 EXPORT_SYMBOL(tcp_enter_memory_pressure);
 
 /* Convert seconds to retransmits based on initial and max timeout */
@@ -460,6 +458,7 @@
 	}
 	return mask;
 }
+EXPORT_SYMBOL(tcp_poll);
 
 int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
@@ -508,10 +507,11 @@
 
 	return put_user(answ, (int __user *)arg);
 }
+EXPORT_SYMBOL(tcp_ioctl);
 
 static inline void tcp_mark_push(struct tcp_sock *tp, struct sk_buff *skb)
 {
-	TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
+	TCP_SKB_CB(skb)->flags |= TCPHDR_PSH;
 	tp->pushed_seq = tp->write_seq;
 }
 
@@ -527,7 +527,7 @@
 
 	skb->csum    = 0;
 	tcb->seq     = tcb->end_seq = tp->write_seq;
-	tcb->flags   = TCPCB_FLAG_ACK;
+	tcb->flags   = TCPHDR_ACK;
 	tcb->sacked  = 0;
 	skb_header_release(skb);
 	tcp_add_write_queue_tail(sk, skb);
@@ -676,6 +676,7 @@
 
 	return ret;
 }
+EXPORT_SYMBOL(tcp_splice_read);
 
 struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp)
 {
@@ -816,7 +817,7 @@
 		skb_shinfo(skb)->gso_segs = 0;
 
 		if (!copied)
-			TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;
+			TCP_SKB_CB(skb)->flags &= ~TCPHDR_PSH;
 
 		copied += copy;
 		poffset += copy;
@@ -857,15 +858,15 @@
 	return sk_stream_error(sk, flags, err);
 }
 
-ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset,
-		     size_t size, int flags)
+int tcp_sendpage(struct sock *sk, struct page *page, int offset,
+		 size_t size, int flags)
 {
 	ssize_t res;
-	struct sock *sk = sock->sk;
 
 	if (!(sk->sk_route_caps & NETIF_F_SG) ||
 	    !(sk->sk_route_caps & NETIF_F_ALL_CSUM))
-		return sock_no_sendpage(sock, page, offset, size, flags);
+		return sock_no_sendpage(sk->sk_socket, page, offset, size,
+					flags);
 
 	lock_sock(sk);
 	TCP_CHECK_TIMER(sk);
@@ -874,6 +875,7 @@
 	release_sock(sk);
 	return res;
 }
+EXPORT_SYMBOL(tcp_sendpage);
 
 #define TCP_PAGE(sk)	(sk->sk_sndmsg_page)
 #define TCP_OFF(sk)	(sk->sk_sndmsg_off)
@@ -898,10 +900,9 @@
 	return tmp;
 }
 
-int tcp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 		size_t size)
 {
-	struct sock *sk = sock->sk;
 	struct iovec *iov;
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
@@ -1062,7 +1063,7 @@
 			}
 
 			if (!copied)
-				TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;
+				TCP_SKB_CB(skb)->flags &= ~TCPHDR_PSH;
 
 			tp->write_seq += copy;
 			TCP_SKB_CB(skb)->end_seq += copy;
@@ -1122,6 +1123,7 @@
 	release_sock(sk);
 	return err;
 }
+EXPORT_SYMBOL(tcp_sendmsg);
 
 /*
  *	Handle reading urgent data. BSD has very simple semantics for
@@ -1381,6 +1383,7 @@
 		tcp_cleanup_rbuf(sk, copied);
 	return copied;
 }
+EXPORT_SYMBOL(tcp_read_sock);
 
 /*
  *	This routine copies from a sock struct into the user buffer.
@@ -1775,6 +1778,7 @@
 	err = tcp_recv_urg(sk, msg, len, flags);
 	goto out;
 }
+EXPORT_SYMBOL(tcp_recvmsg);
 
 void tcp_set_state(struct sock *sk, int state)
 {
@@ -1867,6 +1871,7 @@
 			tcp_send_fin(sk);
 	}
 }
+EXPORT_SYMBOL(tcp_shutdown);
 
 void tcp_close(struct sock *sk, long timeout)
 {
@@ -1899,6 +1904,10 @@
 
 	sk_mem_reclaim(sk);
 
+	/* If socket has been already reset (e.g. in tcp_reset()) - kill it. */
+	if (sk->sk_state == TCP_CLOSE)
+		goto adjudge_to_death;
+
 	/* As outlined in RFC 2525, section 2.17, we send a RST here because
 	 * data was lost. To witness the awful effects of the old behavior of
 	 * always doing a FIN, run an older 2.1.x kernel or 2.0.x, start a bulk
@@ -2026,6 +2035,7 @@
 	local_bh_enable();
 	sock_put(sk);
 }
+EXPORT_SYMBOL(tcp_close);
 
 /* These states need RST on ABORT according to RFC793 */
 
@@ -2099,6 +2109,7 @@
 	sk->sk_error_report(sk);
 	return err;
 }
+EXPORT_SYMBOL(tcp_disconnect);
 
 /*
  *	Socket option code for TCP.
@@ -2176,6 +2187,8 @@
 				      GFP_KERNEL);
 			if (cvp == NULL)
 				return -ENOMEM;
+
+			kref_init(&cvp->kref);
 		}
 		lock_sock(sk);
 		tp->rx_opt.cookie_in_always =
@@ -2190,12 +2203,11 @@
 				 */
 				kref_put(&tp->cookie_values->kref,
 					 tcp_cookie_values_release);
-				kref_init(&cvp->kref);
-				tp->cookie_values = cvp;
 			} else {
 				cvp = tp->cookie_values;
 			}
 		}
+
 		if (cvp != NULL) {
 			cvp->cookie_desired = ctd.tcpct_cookie_desired;
 
@@ -2209,6 +2221,8 @@
 				cvp->s_data_desired = ctd.tcpct_s_data_desired;
 				cvp->s_data_constant = 0; /* false */
 			}
+
+			tp->cookie_values = cvp;
 		}
 		release_sock(sk);
 		return err;
@@ -2397,6 +2411,7 @@
 						     optval, optlen);
 	return do_tcp_setsockopt(sk, level, optname, optval, optlen);
 }
+EXPORT_SYMBOL(tcp_setsockopt);
 
 #ifdef CONFIG_COMPAT
 int compat_tcp_setsockopt(struct sock *sk, int level, int optname,
@@ -2407,7 +2422,6 @@
 						  optval, optlen);
 	return do_tcp_setsockopt(sk, level, optname, optval, optlen);
 }
-
 EXPORT_SYMBOL(compat_tcp_setsockopt);
 #endif
 
@@ -2473,7 +2487,6 @@
 
 	info->tcpi_total_retrans = tp->total_retrans;
 }
-
 EXPORT_SYMBOL_GPL(tcp_get_info);
 
 static int do_tcp_getsockopt(struct sock *sk, int level,
@@ -2591,6 +2604,12 @@
 			return -EFAULT;
 		return 0;
 	}
+	case TCP_THIN_LINEAR_TIMEOUTS:
+		val = tp->thin_lto;
+		break;
+	case TCP_THIN_DUPACK:
+		val = tp->thin_dupack;
+		break;
 	default:
 		return -ENOPROTOOPT;
 	}
@@ -2612,6 +2631,7 @@
 						     optval, optlen);
 	return do_tcp_getsockopt(sk, level, optname, optval, optlen);
 }
+EXPORT_SYMBOL(tcp_getsockopt);
 
 #ifdef CONFIG_COMPAT
 int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
@@ -2622,7 +2642,6 @@
 						  optval, optlen);
 	return do_tcp_getsockopt(sk, level, optname, optval, optlen);
 }
-
 EXPORT_SYMBOL(compat_tcp_getsockopt);
 #endif
 
@@ -2859,7 +2878,6 @@
 	if (pool)
 		__tcp_free_md5sig_pool(pool);
 }
-
 EXPORT_SYMBOL(tcp_free_md5sig_pool);
 
 static struct tcp_md5sig_pool * __percpu *
@@ -2935,7 +2953,6 @@
 	}
 	return pool;
 }
-
 EXPORT_SYMBOL(tcp_alloc_md5sig_pool);
 
 
@@ -2959,7 +2976,7 @@
 	spin_unlock(&tcp_md5sig_pool_lock);
 
 	if (p)
-		return *per_cpu_ptr(p, smp_processor_id());
+		return *this_cpu_ptr(p);
 
 	local_bh_enable();
 	return NULL;
@@ -2987,7 +3004,6 @@
 	th->check = old_checksum;
 	return err;
 }
-
 EXPORT_SYMBOL(tcp_md5_hash_header);
 
 int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
@@ -3000,6 +3016,7 @@
 	const unsigned head_data_len = skb_headlen(skb) > header_len ?
 				       skb_headlen(skb) - header_len : 0;
 	const struct skb_shared_info *shi = skb_shinfo(skb);
+	struct sk_buff *frag_iter;
 
 	sg_init_table(&sg, 1);
 
@@ -3014,9 +3031,12 @@
 			return 1;
 	}
 
+	skb_walk_frags(skb, frag_iter)
+		if (tcp_md5_hash_skb_data(hp, frag_iter, 0))
+			return 1;
+
 	return 0;
 }
-
 EXPORT_SYMBOL(tcp_md5_hash_skb_data);
 
 int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, struct tcp_md5sig_key *key)
@@ -3026,7 +3046,6 @@
 	sg_init_one(&sg, key->key, key->keylen);
 	return crypto_hash_update(&hp->md5_desc, &sg, key->keylen);
 }
-
 EXPORT_SYMBOL(tcp_md5_hash_key);
 
 #endif
@@ -3298,16 +3317,3 @@
 	tcp_secret_retiring = &tcp_secret_two;
 	tcp_secret_secondary = &tcp_secret_two;
 }
-
-EXPORT_SYMBOL(tcp_close);
-EXPORT_SYMBOL(tcp_disconnect);
-EXPORT_SYMBOL(tcp_getsockopt);
-EXPORT_SYMBOL(tcp_ioctl);
-EXPORT_SYMBOL(tcp_poll);
-EXPORT_SYMBOL(tcp_read_sock);
-EXPORT_SYMBOL(tcp_recvmsg);
-EXPORT_SYMBOL(tcp_sendmsg);
-EXPORT_SYMBOL(tcp_splice_read);
-EXPORT_SYMBOL(tcp_sendpage);
-EXPORT_SYMBOL(tcp_setsockopt);
-EXPORT_SYMBOL(tcp_shutdown);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 548d575..3c426cb 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -78,10 +78,13 @@
 int sysctl_tcp_sack __read_mostly = 1;
 int sysctl_tcp_fack __read_mostly = 1;
 int sysctl_tcp_reordering __read_mostly = TCP_FASTRETRANS_THRESH;
+EXPORT_SYMBOL(sysctl_tcp_reordering);
 int sysctl_tcp_ecn __read_mostly = 2;
+EXPORT_SYMBOL(sysctl_tcp_ecn);
 int sysctl_tcp_dsack __read_mostly = 1;
 int sysctl_tcp_app_win __read_mostly = 31;
 int sysctl_tcp_adv_win_scale __read_mostly = 2;
+EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
 
 int sysctl_tcp_stdurg __read_mostly;
 int sysctl_tcp_rfc1337 __read_mostly;
@@ -419,6 +422,7 @@
 
 	inet_csk(sk)->icsk_ack.rcv_mss = hint;
 }
+EXPORT_SYMBOL(tcp_initialize_rcv_mss);
 
 /* Receiver "autotuning" code.
  *
@@ -2938,6 +2942,7 @@
 	}
 	tcp_xmit_retransmit_queue(sk);
 }
+EXPORT_SYMBOL(tcp_simple_retransmit);
 
 /* Process an event, which can update packets-in-flight not trivially.
  * Main goal of this function is to calculate new estimate for left_out,
@@ -3286,7 +3291,7 @@
 		 * connection startup slow start one packet too
 		 * quickly.  This is severely frowned upon behavior.
 		 */
-		if (!(scb->flags & TCPCB_FLAG_SYN)) {
+		if (!(scb->flags & TCPHDR_SYN)) {
 			flag |= FLAG_DATA_ACKED;
 		} else {
 			flag |= FLAG_SYN_ACKED;
@@ -3858,6 +3863,7 @@
 		}
 	}
 }
+EXPORT_SYMBOL(tcp_parse_options);
 
 static int tcp_parse_aligned_timestamp(struct tcp_sock *tp, struct tcphdr *th)
 {
@@ -3931,6 +3937,7 @@
 	}
 	return NULL;
 }
+EXPORT_SYMBOL(tcp_parse_md5sig_option);
 #endif
 
 static inline void tcp_store_ts_recent(struct tcp_sock *tp)
@@ -5432,6 +5439,7 @@
 	__kfree_skb(skb);
 	return 0;
 }
+EXPORT_SYMBOL(tcp_rcv_established);
 
 static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
 					 struct tcphdr *th, unsigned len)
@@ -5931,14 +5939,4 @@
 	}
 	return 0;
 }
-
-EXPORT_SYMBOL(sysctl_tcp_ecn);
-EXPORT_SYMBOL(sysctl_tcp_reordering);
-EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
-EXPORT_SYMBOL(tcp_parse_options);
-#ifdef CONFIG_TCP_MD5SIG
-EXPORT_SYMBOL(tcp_parse_md5sig_option);
-#endif
-EXPORT_SYMBOL(tcp_rcv_established);
 EXPORT_SYMBOL(tcp_rcv_state_process);
-EXPORT_SYMBOL(tcp_initialize_rcv_mss);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index fe193e5..0207662 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -84,6 +84,7 @@
 
 int sysctl_tcp_tw_reuse __read_mostly;
 int sysctl_tcp_low_latency __read_mostly;
+EXPORT_SYMBOL(sysctl_tcp_low_latency);
 
 
 #ifdef CONFIG_TCP_MD5SIG
@@ -100,6 +101,7 @@
 #endif
 
 struct inet_hashinfo tcp_hashinfo;
+EXPORT_SYMBOL(tcp_hashinfo);
 
 static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb)
 {
@@ -139,7 +141,6 @@
 
 	return 0;
 }
-
 EXPORT_SYMBOL_GPL(tcp_twsk_unique);
 
 /* This will initiate an outgoing connection. */
@@ -204,10 +205,12 @@
 		 * TIME-WAIT * and initialize rx_opt.ts_recent from it,
 		 * when trying new connection.
 		 */
-		if (peer != NULL &&
-		    (u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) {
-			tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp;
-			tp->rx_opt.ts_recent = peer->tcp_ts;
+		if (peer) {
+			inet_peer_refcheck(peer);
+			if ((u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) {
+				tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp;
+				tp->rx_opt.ts_recent = peer->tcp_ts;
+			}
 		}
 	}
 
@@ -237,7 +240,7 @@
 
 	/* OK, now commit destination to socket.  */
 	sk->sk_gso_type = SKB_GSO_TCPV4;
-	sk_setup_caps(sk, &rt->u.dst);
+	sk_setup_caps(sk, &rt->dst);
 
 	if (!tp->write_seq)
 		tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
@@ -265,6 +268,7 @@
 	inet->inet_dport = 0;
 	return err;
 }
+EXPORT_SYMBOL(tcp_v4_connect);
 
 /*
  * This routine does path mtu discovery as defined in RFC1191.
@@ -543,6 +547,7 @@
 
 	__tcp_v4_send_check(skb, inet->inet_saddr, inet->inet_daddr);
 }
+EXPORT_SYMBOL(tcp_v4_send_check);
 
 int tcp_v4_gso_send_check(struct sk_buff *skb)
 {
@@ -793,19 +798,20 @@
 	kfree(inet_rsk(req)->opt);
 }
 
-#ifdef CONFIG_SYN_COOKIES
-static void syn_flood_warning(struct sk_buff *skb)
+static void syn_flood_warning(const struct sk_buff *skb)
 {
-	static unsigned long warntime;
+	const char *msg;
 
-	if (time_after(jiffies, (warntime + HZ * 60))) {
-		warntime = jiffies;
-		printk(KERN_INFO
-		       "possible SYN flooding on port %d. Sending cookies.\n",
-		       ntohs(tcp_hdr(skb)->dest));
-	}
-}
+#ifdef CONFIG_SYN_COOKIES
+	if (sysctl_tcp_syncookies)
+		msg = "Sending cookies";
+	else
 #endif
+		msg = "Dropping request";
+
+	pr_info("TCP: Possible SYN flooding on port %d. %s.\n",
+				ntohs(tcp_hdr(skb)->dest), msg);
+}
 
 /*
  * Save and compile IPv4 options into the request_sock if needed.
@@ -857,7 +863,6 @@
 {
 	return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->inet_daddr);
 }
-
 EXPORT_SYMBOL(tcp_v4_md5_lookup);
 
 static struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk,
@@ -924,7 +929,6 @@
 	}
 	return 0;
 }
-
 EXPORT_SYMBOL(tcp_v4_md5_do_add);
 
 static int tcp_v4_md5_add_func(struct sock *sk, struct sock *addr_sk,
@@ -962,7 +966,6 @@
 	}
 	return -ENOENT;
 }
-
 EXPORT_SYMBOL(tcp_v4_md5_do_del);
 
 static void tcp_v4_clear_md5_list(struct sock *sk)
@@ -1135,7 +1138,6 @@
 	memset(md5_hash, 0, 16);
 	return 1;
 }
-
 EXPORT_SYMBOL(tcp_v4_md5_hash_skb);
 
 static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
@@ -1243,6 +1245,8 @@
 	 * evidently real one.
 	 */
 	if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
+		if (net_ratelimit())
+			syn_flood_warning(skb);
 #ifdef CONFIG_SYN_COOKIES
 		if (sysctl_tcp_syncookies) {
 			want_cookie = 1;
@@ -1323,15 +1327,12 @@
 	if (security_inet_conn_request(sk, skb, req))
 		goto drop_and_free;
 
-	if (!want_cookie)
+	if (!want_cookie || tmp_opt.tstamp_ok)
 		TCP_ECN_create_request(req, tcp_hdr(skb));
 
 	if (want_cookie) {
-#ifdef CONFIG_SYN_COOKIES
-		syn_flood_warning(skb);
-		req->cookie_ts = tmp_opt.tstamp_ok;
-#endif
 		isn = cookie_v4_init_sequence(sk, skb, &req->mss);
+		req->cookie_ts = tmp_opt.tstamp_ok;
 	} else if (!isn) {
 		struct inet_peer *peer = NULL;
 
@@ -1349,6 +1350,7 @@
 		    (dst = inet_csk_route_req(sk, req)) != NULL &&
 		    (peer = rt_get_peer((struct rtable *)dst)) != NULL &&
 		    peer->v4daddr == saddr) {
+			inet_peer_refcheck(peer);
 			if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL &&
 			    (s32)(peer->tcp_ts - req->ts_recent) >
 							TCP_PAWS_WINDOW) {
@@ -1393,6 +1395,7 @@
 drop:
 	return 0;
 }
+EXPORT_SYMBOL(tcp_v4_conn_request);
 
 
 /*
@@ -1478,6 +1481,7 @@
 	dst_release(dst);
 	return NULL;
 }
+EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
 
 static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
 {
@@ -1504,7 +1508,7 @@
 	}
 
 #ifdef CONFIG_SYN_COOKIES
-	if (!th->rst && !th->syn && th->ack)
+	if (!th->syn)
 		sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt));
 #endif
 	return sk;
@@ -1607,6 +1611,7 @@
 	TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
 	goto discard;
 }
+EXPORT_SYMBOL(tcp_v4_do_rcv);
 
 /*
  *	From tcp_input.c
@@ -1793,6 +1798,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(tcp_v4_remember_stamp);
 
 int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw)
 {
@@ -1832,6 +1838,7 @@
 	.compat_getsockopt = compat_ip_getsockopt,
 #endif
 };
+EXPORT_SYMBOL(ipv4_specific);
 
 #ifdef CONFIG_TCP_MD5SIG
 static const struct tcp_sock_af_ops tcp_sock_ipv4_specific = {
@@ -1960,7 +1967,6 @@
 
 	percpu_counter_dec(&tcp_sockets_allocated);
 }
-
 EXPORT_SYMBOL(tcp_v4_destroy_sock);
 
 #ifdef CONFIG_PROC_FS
@@ -1978,6 +1984,11 @@
 		hlist_nulls_entry(tw->tw_node.next, typeof(*tw), tw_node) : NULL;
 }
 
+/*
+ * Get next listener socket follow cur.  If cur is NULL, get first socket
+ * starting from bucket given in st->bucket; when st->bucket is zero the
+ * very first socket in the hash table is returned.
+ */
 static void *listening_get_next(struct seq_file *seq, void *cur)
 {
 	struct inet_connection_sock *icsk;
@@ -1988,14 +1999,15 @@
 	struct net *net = seq_file_net(seq);
 
 	if (!sk) {
-		st->bucket = 0;
-		ilb = &tcp_hashinfo.listening_hash[0];
+		ilb = &tcp_hashinfo.listening_hash[st->bucket];
 		spin_lock_bh(&ilb->lock);
 		sk = sk_nulls_head(&ilb->head);
+		st->offset = 0;
 		goto get_sk;
 	}
 	ilb = &tcp_hashinfo.listening_hash[st->bucket];
 	++st->num;
+	++st->offset;
 
 	if (st->state == TCP_SEQ_STATE_OPENREQ) {
 		struct request_sock *req = cur;
@@ -2010,6 +2022,7 @@
 				}
 				req = req->dl_next;
 			}
+			st->offset = 0;
 			if (++st->sbucket >= icsk->icsk_accept_queue.listen_opt->nr_table_entries)
 				break;
 get_req:
@@ -2045,6 +2058,7 @@
 		read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
 	}
 	spin_unlock_bh(&ilb->lock);
+	st->offset = 0;
 	if (++st->bucket < INET_LHTABLE_SIZE) {
 		ilb = &tcp_hashinfo.listening_hash[st->bucket];
 		spin_lock_bh(&ilb->lock);
@@ -2058,7 +2072,12 @@
 
 static void *listening_get_idx(struct seq_file *seq, loff_t *pos)
 {
-	void *rc = listening_get_next(seq, NULL);
+	struct tcp_iter_state *st = seq->private;
+	void *rc;
+
+	st->bucket = 0;
+	st->offset = 0;
+	rc = listening_get_next(seq, NULL);
 
 	while (rc && *pos) {
 		rc = listening_get_next(seq, rc);
@@ -2073,13 +2092,18 @@
 		hlist_nulls_empty(&tcp_hashinfo.ehash[st->bucket].twchain);
 }
 
+/*
+ * Get first established socket starting from bucket given in st->bucket.
+ * If st->bucket is zero, the very first socket in the hash is returned.
+ */
 static void *established_get_first(struct seq_file *seq)
 {
 	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_mask; ++st->bucket) {
+	st->offset = 0;
+	for (; st->bucket <= tcp_hashinfo.ehash_mask; ++st->bucket) {
 		struct sock *sk;
 		struct hlist_nulls_node *node;
 		struct inet_timewait_sock *tw;
@@ -2124,6 +2148,7 @@
 	struct net *net = seq_file_net(seq);
 
 	++st->num;
+	++st->offset;
 
 	if (st->state == TCP_SEQ_STATE_TIME_WAIT) {
 		tw = cur;
@@ -2140,6 +2165,7 @@
 		st->state = TCP_SEQ_STATE_ESTABLISHED;
 
 		/* Look for next non empty bucket */
+		st->offset = 0;
 		while (++st->bucket <= tcp_hashinfo.ehash_mask &&
 				empty_bucket(st))
 			;
@@ -2167,7 +2193,11 @@
 
 static void *established_get_idx(struct seq_file *seq, loff_t pos)
 {
-	void *rc = established_get_first(seq);
+	struct tcp_iter_state *st = seq->private;
+	void *rc;
+
+	st->bucket = 0;
+	rc = established_get_first(seq);
 
 	while (rc && pos) {
 		rc = established_get_next(seq, rc);
@@ -2192,24 +2222,72 @@
 	return rc;
 }
 
+static void *tcp_seek_last_pos(struct seq_file *seq)
+{
+	struct tcp_iter_state *st = seq->private;
+	int offset = st->offset;
+	int orig_num = st->num;
+	void *rc = NULL;
+
+	switch (st->state) {
+	case TCP_SEQ_STATE_OPENREQ:
+	case TCP_SEQ_STATE_LISTENING:
+		if (st->bucket >= INET_LHTABLE_SIZE)
+			break;
+		st->state = TCP_SEQ_STATE_LISTENING;
+		rc = listening_get_next(seq, NULL);
+		while (offset-- && rc)
+			rc = listening_get_next(seq, rc);
+		if (rc)
+			break;
+		st->bucket = 0;
+		/* Fallthrough */
+	case TCP_SEQ_STATE_ESTABLISHED:
+	case TCP_SEQ_STATE_TIME_WAIT:
+		st->state = TCP_SEQ_STATE_ESTABLISHED;
+		if (st->bucket > tcp_hashinfo.ehash_mask)
+			break;
+		rc = established_get_first(seq);
+		while (offset-- && rc)
+			rc = established_get_next(seq, rc);
+	}
+
+	st->num = orig_num;
+
+	return rc;
+}
+
 static void *tcp_seq_start(struct seq_file *seq, loff_t *pos)
 {
 	struct tcp_iter_state *st = seq->private;
+	void *rc;
+
+	if (*pos && *pos == st->last_pos) {
+		rc = tcp_seek_last_pos(seq);
+		if (rc)
+			goto out;
+	}
+
 	st->state = TCP_SEQ_STATE_LISTENING;
 	st->num = 0;
-	return *pos ? tcp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
+	st->bucket = 0;
+	st->offset = 0;
+	rc = *pos ? tcp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
+
+out:
+	st->last_pos = *pos;
+	return rc;
 }
 
 static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
+	struct tcp_iter_state *st = seq->private;
 	void *rc = NULL;
-	struct tcp_iter_state *st;
 
 	if (v == SEQ_START_TOKEN) {
 		rc = tcp_get_idx(seq, 0);
 		goto out;
 	}
-	st = seq->private;
 
 	switch (st->state) {
 	case TCP_SEQ_STATE_OPENREQ:
@@ -2217,6 +2295,8 @@
 		rc = listening_get_next(seq, v);
 		if (!rc) {
 			st->state = TCP_SEQ_STATE_ESTABLISHED;
+			st->bucket = 0;
+			st->offset = 0;
 			rc	  = established_get_first(seq);
 		}
 		break;
@@ -2227,6 +2307,7 @@
 	}
 out:
 	++*pos;
+	st->last_pos = *pos;
 	return rc;
 }
 
@@ -2265,6 +2346,7 @@
 
 	s = ((struct seq_file *)file->private_data)->private;
 	s->family		= afinfo->family;
+	s->last_pos 		= 0;
 	return 0;
 }
 
@@ -2288,11 +2370,13 @@
 		rc = -ENOMEM;
 	return rc;
 }
+EXPORT_SYMBOL(tcp_proc_register);
 
 void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo)
 {
 	proc_net_remove(net, afinfo->name);
 }
+EXPORT_SYMBOL(tcp_proc_unregister);
 
 static void get_openreq4(struct sock *sk, struct request_sock *req,
 			 struct seq_file *f, int i, int uid, int *len)
@@ -2516,6 +2600,8 @@
 	.setsockopt		= tcp_setsockopt,
 	.getsockopt		= tcp_getsockopt,
 	.recvmsg		= tcp_recvmsg,
+	.sendmsg		= tcp_sendmsg,
+	.sendpage		= tcp_sendpage,
 	.backlog_rcv		= tcp_v4_do_rcv,
 	.hash			= inet_hash,
 	.unhash			= inet_unhash,
@@ -2534,11 +2620,13 @@
 	.twsk_prot		= &tcp_timewait_sock_ops,
 	.rsk_prot		= &tcp_request_sock_ops,
 	.h.hashinfo		= &tcp_hashinfo,
+	.no_autobind		= true,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt	= compat_tcp_setsockopt,
 	.compat_getsockopt	= compat_tcp_getsockopt,
 #endif
 };
+EXPORT_SYMBOL(tcp_prot);
 
 
 static int __net_init tcp_sk_init(struct net *net)
@@ -2569,20 +2657,3 @@
 	if (register_pernet_subsys(&tcp_sk_ops))
 		panic("Failed to create the TCP control socket.\n");
 }
-
-EXPORT_SYMBOL(ipv4_specific);
-EXPORT_SYMBOL(tcp_hashinfo);
-EXPORT_SYMBOL(tcp_prot);
-EXPORT_SYMBOL(tcp_v4_conn_request);
-EXPORT_SYMBOL(tcp_v4_connect);
-EXPORT_SYMBOL(tcp_v4_do_rcv);
-EXPORT_SYMBOL(tcp_v4_remember_stamp);
-EXPORT_SYMBOL(tcp_v4_send_check);
-EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
-
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(tcp_proc_register);
-EXPORT_SYMBOL(tcp_proc_unregister);
-#endif
-EXPORT_SYMBOL(sysctl_tcp_low_latency);
-
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 794c2e1..f25b56c 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -47,7 +47,6 @@
 	.twcal_timer	= TIMER_INITIALIZER(inet_twdr_twcal_tick, 0,
 					    (unsigned long)&tcp_death_row),
 };
-
 EXPORT_SYMBOL_GPL(tcp_death_row);
 
 static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
@@ -262,6 +261,7 @@
 	inet_twsk_put(tw);
 	return TCP_TW_SUCCESS;
 }
+EXPORT_SYMBOL(tcp_timewait_state_process);
 
 /*
  * Move a socket to time-wait or dead fin-wait-2 state.
@@ -362,7 +362,6 @@
 		tcp_free_md5sig_pool();
 #endif
 }
-
 EXPORT_SYMBOL_GPL(tcp_twsk_destructor);
 
 static inline void TCP_ECN_openreq_child(struct tcp_sock *tp,
@@ -510,6 +509,7 @@
 	}
 	return newsk;
 }
+EXPORT_SYMBOL(tcp_create_openreq_child);
 
 /*
  *	Process an incoming packet for SYN_RECV sockets represented
@@ -706,6 +706,7 @@
 	inet_csk_reqsk_queue_drop(sk, req, prev);
 	return NULL;
 }
+EXPORT_SYMBOL(tcp_check_req);
 
 /*
  * Queue segment on the new socket if the new socket is active,
@@ -737,8 +738,4 @@
 	sock_put(child);
 	return ret;
 }
-
-EXPORT_SYMBOL(tcp_check_req);
 EXPORT_SYMBOL(tcp_child_process);
-EXPORT_SYMBOL(tcp_create_openreq_child);
-EXPORT_SYMBOL(tcp_timewait_state_process);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 7ed9dc1..de3bd84 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -247,6 +247,7 @@
 	/* Set the clamp no higher than max representable value */
 	(*window_clamp) = min(65535U << (*rcv_wscale), *window_clamp);
 }
+EXPORT_SYMBOL(tcp_select_initial_window);
 
 /* Chose a new window to advertise, update state in tcp_sock for the
  * socket, and return result with RFC1323 scaling applied.  The return
@@ -294,9 +295,9 @@
 /* Packet ECN state for a SYN-ACK */
 static inline void TCP_ECN_send_synack(struct tcp_sock *tp, struct sk_buff *skb)
 {
-	TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_CWR;
+	TCP_SKB_CB(skb)->flags &= ~TCPHDR_CWR;
 	if (!(tp->ecn_flags & TCP_ECN_OK))
-		TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_ECE;
+		TCP_SKB_CB(skb)->flags &= ~TCPHDR_ECE;
 }
 
 /* Packet ECN state for a SYN.  */
@@ -306,7 +307,7 @@
 
 	tp->ecn_flags = 0;
 	if (sysctl_tcp_ecn == 1) {
-		TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE | TCPCB_FLAG_CWR;
+		TCP_SKB_CB(skb)->flags |= TCPHDR_ECE | TCPHDR_CWR;
 		tp->ecn_flags = TCP_ECN_OK;
 	}
 }
@@ -361,7 +362,7 @@
 	skb_shinfo(skb)->gso_type = 0;
 
 	TCP_SKB_CB(skb)->seq = seq;
-	if (flags & (TCPCB_FLAG_SYN | TCPCB_FLAG_FIN))
+	if (flags & (TCPHDR_SYN | TCPHDR_FIN))
 		seq++;
 	TCP_SKB_CB(skb)->end_seq = seq;
 }
@@ -820,7 +821,7 @@
 	tcb = TCP_SKB_CB(skb);
 	memset(&opts, 0, sizeof(opts));
 
-	if (unlikely(tcb->flags & TCPCB_FLAG_SYN))
+	if (unlikely(tcb->flags & TCPHDR_SYN))
 		tcp_options_size = tcp_syn_options(sk, skb, &opts, &md5);
 	else
 		tcp_options_size = tcp_established_options(sk, skb, &opts,
@@ -843,7 +844,7 @@
 	*(((__be16 *)th) + 6)	= htons(((tcp_header_size >> 2) << 12) |
 					tcb->flags);
 
-	if (unlikely(tcb->flags & TCPCB_FLAG_SYN)) {
+	if (unlikely(tcb->flags & TCPHDR_SYN)) {
 		/* RFC1323: The window in SYN & SYN/ACK segments
 		 * is never scaled.
 		 */
@@ -866,7 +867,7 @@
 	}
 
 	tcp_options_write((__be32 *)(th + 1), tp, &opts);
-	if (likely((tcb->flags & TCPCB_FLAG_SYN) == 0))
+	if (likely((tcb->flags & TCPHDR_SYN) == 0))
 		TCP_ECN_send(sk, skb, tcp_header_size);
 
 #ifdef CONFIG_TCP_MD5SIG
@@ -880,7 +881,7 @@
 
 	icsk->icsk_af_ops->send_check(sk, skb);
 
-	if (likely(tcb->flags & TCPCB_FLAG_ACK))
+	if (likely(tcb->flags & TCPHDR_ACK))
 		tcp_event_ack_sent(sk, tcp_skb_pcount(skb));
 
 	if (skb->len != tcp_header_size)
@@ -1023,7 +1024,7 @@
 
 	/* PSH and FIN should only be set in the second packet. */
 	flags = TCP_SKB_CB(skb)->flags;
-	TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN | TCPCB_FLAG_PSH);
+	TCP_SKB_CB(skb)->flags = flags & ~(TCPHDR_FIN | TCPHDR_PSH);
 	TCP_SKB_CB(buff)->flags = flags;
 	TCP_SKB_CB(buff)->sacked = TCP_SKB_CB(skb)->sacked;
 
@@ -1189,6 +1190,7 @@
 	icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, sysctl_tcp_base_mss);
 	icsk->icsk_mtup.probe_size = 0;
 }
+EXPORT_SYMBOL(tcp_mtup_init);
 
 /* This function synchronize snd mss to current pmtu/exthdr set.
 
@@ -1232,6 +1234,7 @@
 
 	return mss_now;
 }
+EXPORT_SYMBOL(tcp_sync_mss);
 
 /* Compute the current effective MSS, taking SACKs and IP options,
  * and even PMTU discovery events into account.
@@ -1328,8 +1331,7 @@
 	u32 in_flight, cwnd;
 
 	/* Don't be strict about the congestion window for the final FIN.  */
-	if ((TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
-	    tcp_skb_pcount(skb) == 1)
+	if ((TCP_SKB_CB(skb)->flags & TCPHDR_FIN) && tcp_skb_pcount(skb) == 1)
 		return 1;
 
 	in_flight = tcp_packets_in_flight(tp);
@@ -1398,7 +1400,7 @@
 	 * Nagle can be ignored during F-RTO too (see RFC4138).
 	 */
 	if (tcp_urg_mode(tp) || (tp->frto_counter == 2) ||
-	    (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN))
+	    (TCP_SKB_CB(skb)->flags & TCPHDR_FIN))
 		return 1;
 
 	if (!tcp_nagle_check(tp, skb, cur_mss, nonagle))
@@ -1461,7 +1463,7 @@
  * packet has never been sent out before (and thus is not cloned).
  */
 static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len,
-			unsigned int mss_now)
+			unsigned int mss_now, gfp_t gfp)
 {
 	struct sk_buff *buff;
 	int nlen = skb->len - len;
@@ -1471,7 +1473,7 @@
 	if (skb->len != skb->data_len)
 		return tcp_fragment(sk, skb, len, mss_now);
 
-	buff = sk_stream_alloc_skb(sk, 0, GFP_ATOMIC);
+	buff = sk_stream_alloc_skb(sk, 0, gfp);
 	if (unlikely(buff == NULL))
 		return -ENOMEM;
 
@@ -1487,7 +1489,7 @@
 
 	/* PSH and FIN should only be set in the second packet. */
 	flags = TCP_SKB_CB(skb)->flags;
-	TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN | TCPCB_FLAG_PSH);
+	TCP_SKB_CB(skb)->flags = flags & ~(TCPHDR_FIN | TCPHDR_PSH);
 	TCP_SKB_CB(buff)->flags = flags;
 
 	/* This packet was never sent out yet, so no SACK bits. */
@@ -1518,7 +1520,7 @@
 	const struct inet_connection_sock *icsk = inet_csk(sk);
 	u32 send_win, cong_win, limit, in_flight;
 
-	if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)
+	if (TCP_SKB_CB(skb)->flags & TCPHDR_FIN)
 		goto send_now;
 
 	if (icsk->icsk_ca_state != TCP_CA_Open)
@@ -1644,7 +1646,7 @@
 
 	TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(skb)->seq;
 	TCP_SKB_CB(nskb)->end_seq = TCP_SKB_CB(skb)->seq + probe_size;
-	TCP_SKB_CB(nskb)->flags = TCPCB_FLAG_ACK;
+	TCP_SKB_CB(nskb)->flags = TCPHDR_ACK;
 	TCP_SKB_CB(nskb)->sacked = 0;
 	nskb->csum = 0;
 	nskb->ip_summed = skb->ip_summed;
@@ -1669,7 +1671,7 @@
 			sk_wmem_free_skb(sk, skb);
 		} else {
 			TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags &
-						   ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH);
+						   ~(TCPHDR_FIN|TCPHDR_PSH);
 			if (!skb_shinfo(skb)->nr_frags) {
 				skb_pull(skb, copy);
 				if (skb->ip_summed != CHECKSUM_PARTIAL)
@@ -1769,7 +1771,7 @@
 						    cwnd_quota);
 
 		if (skb->len > limit &&
-		    unlikely(tso_fragment(sk, skb, limit, mss_now)))
+		    unlikely(tso_fragment(sk, skb, limit, mss_now, gfp)))
 			break;
 
 		TCP_SKB_CB(skb)->when = tcp_time_stamp;
@@ -2020,7 +2022,7 @@
 
 	if (!sysctl_tcp_retrans_collapse)
 		return;
-	if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN)
+	if (TCP_SKB_CB(skb)->flags & TCPHDR_SYN)
 		return;
 
 	tcp_for_write_queue_from_safe(skb, tmp, sk) {
@@ -2112,7 +2114,7 @@
 	 * since it is cheap to do so and saves bytes on the network.
 	 */
 	if (skb->len > 0 &&
-	    (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
+	    (TCP_SKB_CB(skb)->flags & TCPHDR_FIN) &&
 	    tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
 		if (!pskb_trim(skb, 0)) {
 			/* Reuse, even though it does some unnecessary work */
@@ -2304,7 +2306,7 @@
 	mss_now = tcp_current_mss(sk);
 
 	if (tcp_send_head(sk) != NULL) {
-		TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN;
+		TCP_SKB_CB(skb)->flags |= TCPHDR_FIN;
 		TCP_SKB_CB(skb)->end_seq++;
 		tp->write_seq++;
 	} else {
@@ -2321,7 +2323,7 @@
 		skb_reserve(skb, MAX_TCP_HEADER);
 		/* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
 		tcp_init_nondata_skb(skb, tp->write_seq,
-				     TCPCB_FLAG_ACK | TCPCB_FLAG_FIN);
+				     TCPHDR_ACK | TCPHDR_FIN);
 		tcp_queue_skb(sk, skb);
 	}
 	__tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_OFF);
@@ -2346,7 +2348,7 @@
 	/* Reserve space for headers and prepare control bits. */
 	skb_reserve(skb, MAX_TCP_HEADER);
 	tcp_init_nondata_skb(skb, tcp_acceptable_seq(sk),
-			     TCPCB_FLAG_ACK | TCPCB_FLAG_RST);
+			     TCPHDR_ACK | TCPHDR_RST);
 	/* Send it off. */
 	TCP_SKB_CB(skb)->when = tcp_time_stamp;
 	if (tcp_transmit_skb(sk, skb, 0, priority))
@@ -2366,11 +2368,11 @@
 	struct sk_buff *skb;
 
 	skb = tcp_write_queue_head(sk);
-	if (skb == NULL || !(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN)) {
+	if (skb == NULL || !(TCP_SKB_CB(skb)->flags & TCPHDR_SYN)) {
 		printk(KERN_DEBUG "tcp_send_synack: wrong queue state\n");
 		return -EFAULT;
 	}
-	if (!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_ACK)) {
+	if (!(TCP_SKB_CB(skb)->flags & TCPHDR_ACK)) {
 		if (skb_cloned(skb)) {
 			struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
 			if (nskb == NULL)
@@ -2384,7 +2386,7 @@
 			skb = nskb;
 		}
 
-		TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ACK;
+		TCP_SKB_CB(skb)->flags |= TCPHDR_ACK;
 		TCP_ECN_send_synack(tcp_sk(sk), skb);
 	}
 	TCP_SKB_CB(skb)->when = tcp_time_stamp;
@@ -2463,7 +2465,7 @@
 	 * not even correctly set)
 	 */
 	tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn,
-			     TCPCB_FLAG_SYN | TCPCB_FLAG_ACK);
+			     TCPHDR_SYN | TCPHDR_ACK);
 
 	if (OPTION_COOKIE_EXTENSION & opts.options) {
 		if (s_data_desired) {
@@ -2518,6 +2520,7 @@
 
 	return skb;
 }
+EXPORT_SYMBOL(tcp_make_synack);
 
 /* Do all connect socket setups that can be done AF independent. */
 static void tcp_connect_init(struct sock *sk)
@@ -2595,7 +2598,7 @@
 	skb_reserve(buff, MAX_TCP_HEADER);
 
 	tp->snd_nxt = tp->write_seq;
-	tcp_init_nondata_skb(buff, tp->write_seq++, TCPCB_FLAG_SYN);
+	tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
 	TCP_ECN_send_syn(sk, buff);
 
 	/* Send it off. */
@@ -2620,6 +2623,7 @@
 				  inet_csk(sk)->icsk_rto, TCP_RTO_MAX);
 	return 0;
 }
+EXPORT_SYMBOL(tcp_connect);
 
 /* Send out a delayed ack, the caller does the policy checking
  * to see if we should even be here.  See tcp_input.c:tcp_ack_snd_check()
@@ -2701,7 +2705,7 @@
 
 	/* Reserve space for headers and prepare control bits. */
 	skb_reserve(buff, MAX_TCP_HEADER);
-	tcp_init_nondata_skb(buff, tcp_acceptable_seq(sk), TCPCB_FLAG_ACK);
+	tcp_init_nondata_skb(buff, tcp_acceptable_seq(sk), TCPHDR_ACK);
 
 	/* Send it off, this clears delayed acks for us. */
 	TCP_SKB_CB(buff)->when = tcp_time_stamp;
@@ -2735,7 +2739,7 @@
 	 * end to send an ack.  Don't queue or clone SKB, just
 	 * send it.
 	 */
-	tcp_init_nondata_skb(skb, tp->snd_una - !urgent, TCPCB_FLAG_ACK);
+	tcp_init_nondata_skb(skb, tp->snd_una - !urgent, TCPHDR_ACK);
 	TCP_SKB_CB(skb)->when = tcp_time_stamp;
 	return tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC);
 }
@@ -2765,13 +2769,13 @@
 		if (seg_size < TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq ||
 		    skb->len > mss) {
 			seg_size = min(seg_size, mss);
-			TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
+			TCP_SKB_CB(skb)->flags |= TCPHDR_PSH;
 			if (tcp_fragment(sk, skb, seg_size, mss))
 				return -1;
 		} else if (!tcp_skb_pcount(skb))
 			tcp_set_skb_tso_segs(sk, skb, mss);
 
-		TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
+		TCP_SKB_CB(skb)->flags |= TCPHDR_PSH;
 		TCP_SKB_CB(skb)->when = tcp_time_stamp;
 		err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
 		if (!err)
@@ -2824,10 +2828,3 @@
 					  TCP_RTO_MAX);
 	}
 }
-
-EXPORT_SYMBOL(tcp_select_initial_window);
-EXPORT_SYMBOL(tcp_connect);
-EXPORT_SYMBOL(tcp_make_synack);
-EXPORT_SYMBOL(tcp_simple_retransmit);
-EXPORT_SYMBOL(tcp_sync_mss);
-EXPORT_SYMBOL(tcp_mtup_init);
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 440a5c6..808bb92 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -41,7 +41,6 @@
 	inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer,
 				  &tcp_keepalive_timer);
 }
-
 EXPORT_SYMBOL(tcp_init_xmit_timers);
 
 static void tcp_write_err(struct sock *sk)
diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c
index 3b3813c..59186ca 100644
--- a/net/ipv4/tunnel4.c
+++ b/net/ipv4/tunnel4.c
@@ -48,7 +48,6 @@
 
 	return ret;
 }
-
 EXPORT_SYMBOL(xfrm4_tunnel_register);
 
 int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
@@ -72,7 +71,6 @@
 
 	return ret;
 }
-
 EXPORT_SYMBOL(xfrm4_tunnel_deregister);
 
 static int tunnel4_rcv(struct sk_buff *skb)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index eec4ff4..32e0bef 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -914,7 +914,7 @@
 		    !sock_flag(sk, SOCK_BROADCAST))
 			goto out;
 		if (connected)
-			sk_dst_set(sk, dst_clone(&rt->u.dst));
+			sk_dst_set(sk, dst_clone(&rt->dst));
 	}
 
 	if (msg->msg_flags&MSG_CONFIRM)
@@ -978,7 +978,7 @@
 	return err;
 
 do_confirm:
-	dst_confirm(&rt->u.dst);
+	dst_confirm(&rt->dst);
 	if (!(msg->msg_flags&MSG_PROBE) || len)
 		goto back_from_confirm;
 	err = 0;
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index 6610bf7..ab76aa9 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -58,6 +58,7 @@
 	.compat_getsockopt = compat_udp_getsockopt,
 #endif
 };
+EXPORT_SYMBOL(udplite_prot);
 
 static struct inet_protosw udplite4_protosw = {
 	.type		=  SOCK_DGRAM,
@@ -127,5 +128,3 @@
 out_register_err:
 	printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __func__);
 }
-
-EXPORT_SYMBOL(udplite_prot);
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index ad8fbb8..06814b6 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -163,5 +163,4 @@
 {
 	return xfrm4_rcv_spi(skb, ip_hdr(skb)->protocol, 0);
 }
-
 EXPORT_SYMBOL(xfrm4_rcv);
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 23883a4..869078d 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -37,7 +37,7 @@
 		fl.fl4_src = saddr->a4;
 
 	err = __ip_route_output_key(net, &rt, &fl);
-	dst = &rt->u.dst;
+	dst = &rt->dst;
 	if (err)
 		dst = ERR_PTR(err);
 	return dst;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 784f34d..ab70a3f 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -121,8 +121,6 @@
 static int __ipv6_regen_rndid(struct inet6_dev *idev);
 static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr);
 static void ipv6_regen_rndid(unsigned long data);
-
-static int desync_factor = MAX_DESYNC_FACTOR * HZ;
 #endif
 
 static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
@@ -284,13 +282,16 @@
 static int snmp6_alloc_dev(struct inet6_dev *idev)
 {
 	if (snmp_mib_init((void __percpu **)idev->stats.ipv6,
-			  sizeof(struct ipstats_mib)) < 0)
+			  sizeof(struct ipstats_mib),
+			  __alignof__(struct ipstats_mib)) < 0)
 		goto err_ip;
 	if (snmp_mib_init((void __percpu **)idev->stats.icmpv6,
-			  sizeof(struct icmpv6_mib)) < 0)
+			  sizeof(struct icmpv6_mib),
+			  __alignof__(struct icmpv6_mib)) < 0)
 		goto err_icmp;
 	if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg,
-			  sizeof(struct icmpv6msg_mib)) < 0)
+			  sizeof(struct icmpv6msg_mib),
+			  __alignof__(struct icmpv6msg_mib)) < 0)
 		goto err_icmpmsg;
 
 	return 0;
@@ -557,7 +558,7 @@
 		pr_warning("Freeing alive inet6 address %p\n", ifp);
 		return;
 	}
-	dst_release(&ifp->rt->u.dst);
+	dst_release(&ifp->rt->dst);
 
 	call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu);
 }
@@ -823,7 +824,7 @@
 				rt->rt6i_flags |= RTF_EXPIRES;
 			}
 		}
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 	}
 
 out:
@@ -890,7 +891,8 @@
 			      idev->cnf.temp_valid_lft);
 	tmp_prefered_lft = min_t(__u32,
 				 ifp->prefered_lft,
-				 idev->cnf.temp_prefered_lft - desync_factor / HZ);
+				 idev->cnf.temp_prefered_lft -
+				 idev->cnf.max_desync_factor);
 	tmp_plen = ifp->prefix_len;
 	max_addresses = idev->cnf.max_addresses;
 	tmp_cstamp = ifp->cstamp;
@@ -1650,7 +1652,8 @@
 
 	expires = jiffies +
 		idev->cnf.temp_prefered_lft * HZ -
-		idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - desync_factor;
+		idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time -
+		idev->cnf.max_desync_factor * HZ;
 	if (time_before(expires, jiffies)) {
 		printk(KERN_WARNING
 			"ipv6_regen_rndid(): too short regeneration interval; timer disabled for %s.\n",
@@ -1866,7 +1869,7 @@
 					      dev, expires, flags);
 		}
 		if (rt)
-			dst_release(&rt->u.dst);
+			dst_release(&rt->dst);
 	}
 
 	/* Try to figure out our local address for this prefix */
@@ -3496,8 +3499,12 @@
 				preferred -= tval;
 			else
 				preferred = 0;
-			if (valid != INFINITY_LIFE_TIME)
-				valid -= tval;
+			if (valid != INFINITY_LIFE_TIME) {
+				if (valid > tval)
+					valid -= tval;
+				else
+					valid = 0;
+			}
 		}
 	} else {
 		preferred = INFINITY_LIFE_TIME;
@@ -3859,12 +3866,28 @@
 	memset(&stats[items], 0, pad);
 }
 
+static inline void __snmp6_fill_stats64(u64 *stats, void __percpu **mib,
+				      int items, int bytes, size_t syncpoff)
+{
+	int i;
+	int pad = bytes - sizeof(u64) * items;
+	BUG_ON(pad < 0);
+
+	/* Use put_unaligned() because stats may not be aligned for u64. */
+	put_unaligned(items, &stats[0]);
+	for (i = 1; i < items; i++)
+		put_unaligned(snmp_fold_field64(mib, i, syncpoff), &stats[i]);
+
+	memset(&stats[items], 0, pad);
+}
+
 static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
 			     int bytes)
 {
 	switch (attrtype) {
 	case IFLA_INET6_STATS:
-		__snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
+		__snmp6_fill_stats64(stats, (void __percpu **)idev->stats.ipv6,
+				     IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp));
 		break;
 	case IFLA_INET6_ICMP6STATS:
 		__snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
@@ -4097,11 +4120,11 @@
 		if (ifp->idev->cnf.forwarding)
 			addrconf_leave_anycast(ifp);
 		addrconf_leave_solict(ifp->idev, &ifp->addr);
-		dst_hold(&ifp->rt->u.dst);
+		dst_hold(&ifp->rt->dst);
 
 		if (ifp->state == INET6_IFADDR_STATE_DEAD &&
 		    ip6_del_rt(ifp->rt))
-			dst_free(&ifp->rt->u.dst);
+			dst_free(&ifp->rt->dst);
 		break;
 	}
 }
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index 8c4348c..f0e774c 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -53,11 +53,7 @@
 static inline
 struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl)
 {
-#ifdef CONFIG_NET_NS
-	return lbl->lbl_net;
-#else
-	return &init_net;
-#endif
+	return read_pnet(&lbl->lbl_net);
 }
 
 /*
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index e733942d..56b9bf2 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -522,10 +522,10 @@
 	.shutdown	   = inet_shutdown,		/* ok		*/
 	.setsockopt	   = sock_common_setsockopt,	/* ok		*/
 	.getsockopt	   = sock_common_getsockopt,	/* ok		*/
-	.sendmsg	   = tcp_sendmsg,		/* ok		*/
-	.recvmsg	   = sock_common_recvmsg,	/* ok		*/
+	.sendmsg	   = inet_sendmsg,		/* ok		*/
+	.recvmsg	   = inet_recvmsg,		/* ok		*/
 	.mmap		   = sock_no_mmap,
-	.sendpage	   = tcp_sendpage,
+	.sendpage	   = inet_sendpage,
 	.splice_read	   = tcp_splice_read,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_sock_common_setsockopt,
@@ -549,7 +549,7 @@
 	.setsockopt	   = sock_common_setsockopt,	/* ok		*/
 	.getsockopt	   = sock_common_getsockopt,	/* ok		*/
 	.sendmsg	   = inet_sendmsg,		/* ok		*/
-	.recvmsg	   = sock_common_recvmsg,	/* ok		*/
+	.recvmsg	   = inet_recvmsg,		/* ok		*/
 	.mmap		   = sock_no_mmap,
 	.sendpage	   = sock_no_sendpage,
 #ifdef CONFIG_COMPAT
@@ -651,7 +651,7 @@
 
 	if (dst == NULL) {
 		struct inet_sock *inet = inet_sk(sk);
-		struct in6_addr *final_p = NULL, final;
+		struct in6_addr *final_p, final;
 		struct flowi fl;
 
 		memset(&fl, 0, sizeof(fl));
@@ -665,12 +665,7 @@
 		fl.fl_ip_sport = inet->inet_sport;
 		security_sk_classify_flow(sk, &fl);
 
-		if (np->opt && np->opt->srcrt) {
-			struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
-			ipv6_addr_copy(&final, &fl.fl6_dst);
-			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-			final_p = &final;
-		}
+		final_p = fl6_update_dst(&fl, np->opt, &final);
 
 		err = ip6_dst_lookup(sk, &dst, &fl);
 		if (err) {
@@ -976,19 +971,24 @@
 static int __net_init ipv6_init_mibs(struct net *net)
 {
 	if (snmp_mib_init((void __percpu **)net->mib.udp_stats_in6,
-			  sizeof (struct udp_mib)) < 0)
+			  sizeof(struct udp_mib),
+			  __alignof__(struct udp_mib)) < 0)
 		return -ENOMEM;
 	if (snmp_mib_init((void __percpu **)net->mib.udplite_stats_in6,
-			  sizeof (struct udp_mib)) < 0)
+			  sizeof(struct udp_mib),
+			  __alignof__(struct udp_mib)) < 0)
 		goto err_udplite_mib;
 	if (snmp_mib_init((void __percpu **)net->mib.ipv6_statistics,
-			  sizeof(struct ipstats_mib)) < 0)
+			  sizeof(struct ipstats_mib),
+			  __alignof__(struct ipstats_mib)) < 0)
 		goto err_ip_mib;
 	if (snmp_mib_init((void __percpu **)net->mib.icmpv6_statistics,
-			  sizeof(struct icmpv6_mib)) < 0)
+			  sizeof(struct icmpv6_mib),
+			  __alignof__(struct icmpv6_mib)) < 0)
 		goto err_icmp_mib;
 	if (snmp_mib_init((void __percpu **)net->mib.icmpv6msg_statistics,
-			  sizeof(struct icmpv6msg_mib)) < 0)
+			  sizeof(struct icmpv6msg_mib),
+			  __alignof__(struct icmpv6msg_mib)) < 0)
 		goto err_icmpmsg_mib;
 	return 0;
 
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index b5b0705..0e5e943 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -77,41 +77,40 @@
 	pac->acl_next = NULL;
 	ipv6_addr_copy(&pac->acl_addr, addr);
 
+	rcu_read_lock();
 	if (ifindex == 0) {
 		struct rt6_info *rt;
 
 		rt = rt6_lookup(net, addr, NULL, 0, 0);
 		if (rt) {
 			dev = rt->rt6i_dev;
-			dev_hold(dev);
-			dst_release(&rt->u.dst);
+			dst_release(&rt->dst);
 		} else if (ishost) {
 			err = -EADDRNOTAVAIL;
-			goto out_free_pac;
+			goto error;
 		} else {
 			/* router, no matching interface: just pick one */
-
-			dev = dev_get_by_flags(net, IFF_UP, IFF_UP|IFF_LOOPBACK);
+			dev = dev_get_by_flags_rcu(net, IFF_UP,
+						   IFF_UP | IFF_LOOPBACK);
 		}
 	} else
-		dev = dev_get_by_index(net, ifindex);
+		dev = dev_get_by_index_rcu(net, ifindex);
 
 	if (dev == NULL) {
 		err = -ENODEV;
-		goto out_free_pac;
+		goto error;
 	}
 
-	idev = in6_dev_get(dev);
+	idev = __in6_dev_get(dev);
 	if (!idev) {
 		if (ifindex)
 			err = -ENODEV;
 		else
 			err = -EADDRNOTAVAIL;
-		goto out_dev_put;
+		goto error;
 	}
 	/* reset ishost, now that we have a specific device */
 	ishost = !idev->cnf.forwarding;
-	in6_dev_put(idev);
 
 	pac->acl_ifindex = dev->ifindex;
 
@@ -124,26 +123,22 @@
 		if (ishost)
 			err = -EADDRNOTAVAIL;
 		if (err)
-			goto out_dev_put;
+			goto error;
 	}
 
 	err = ipv6_dev_ac_inc(dev, addr);
-	if (err)
-		goto out_dev_put;
+	if (!err) {
+		write_lock_bh(&ipv6_sk_ac_lock);
+		pac->acl_next = np->ipv6_ac_list;
+		np->ipv6_ac_list = pac;
+		write_unlock_bh(&ipv6_sk_ac_lock);
+		pac = NULL;
+	}
 
-	write_lock_bh(&ipv6_sk_ac_lock);
-	pac->acl_next = np->ipv6_ac_list;
-	np->ipv6_ac_list = pac;
-	write_unlock_bh(&ipv6_sk_ac_lock);
-
-	dev_put(dev);
-
-	return 0;
-
-out_dev_put:
-	dev_put(dev);
-out_free_pac:
-	sock_kfree_s(sk, pac, sizeof(*pac));
+error:
+	rcu_read_unlock();
+	if (pac)
+		sock_kfree_s(sk, pac, sizeof(*pac));
 	return err;
 }
 
@@ -176,11 +171,12 @@
 
 	write_unlock_bh(&ipv6_sk_ac_lock);
 
-	dev = dev_get_by_index(net, pac->acl_ifindex);
-	if (dev) {
+	rcu_read_lock();
+	dev = dev_get_by_index_rcu(net, pac->acl_ifindex);
+	if (dev)
 		ipv6_dev_ac_dec(dev, &pac->acl_addr);
-		dev_put(dev);
-	}
+	rcu_read_unlock();
+
 	sock_kfree_s(sk, pac, sizeof(*pac));
 	return 0;
 }
@@ -199,13 +195,12 @@
 	write_unlock_bh(&ipv6_sk_ac_lock);
 
 	prev_index = 0;
+	rcu_read_lock();
 	while (pac) {
 		struct ipv6_ac_socklist *next = pac->acl_next;
 
 		if (pac->acl_ifindex != prev_index) {
-			if (dev)
-				dev_put(dev);
-			dev = dev_get_by_index(net, pac->acl_ifindex);
+			dev = dev_get_by_index_rcu(net, pac->acl_ifindex);
 			prev_index = pac->acl_ifindex;
 		}
 		if (dev)
@@ -213,8 +208,7 @@
 		sock_kfree_s(sk, pac, sizeof(*pac));
 		pac = next;
 	}
-	if (dev)
-		dev_put(dev);
+	rcu_read_unlock();
 }
 
 #if 0
@@ -250,7 +244,7 @@
 {
 	if (atomic_dec_and_test(&ac->aca_refcnt)) {
 		in6_dev_put(ac->aca_idev);
-		dst_release(&ac->aca_rt->u.dst);
+		dst_release(&ac->aca_rt->dst);
 		kfree(ac);
 	}
 }
@@ -356,40 +350,39 @@
 	write_unlock_bh(&idev->lock);
 	addrconf_leave_solict(idev, &aca->aca_addr);
 
-	dst_hold(&aca->aca_rt->u.dst);
+	dst_hold(&aca->aca_rt->dst);
 	ip6_del_rt(aca->aca_rt);
 
 	aca_put(aca);
 	return 0;
 }
 
+/* called with rcu_read_lock() */
 static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
 {
-	int ret;
-	struct inet6_dev *idev = in6_dev_get(dev);
+	struct inet6_dev *idev = __in6_dev_get(dev);
+
 	if (idev == NULL)
 		return -ENODEV;
-	ret = __ipv6_dev_ac_dec(idev, addr);
-	in6_dev_put(idev);
-	return ret;
+	return __ipv6_dev_ac_dec(idev, addr);
 }
 
 /*
  *	check if the interface has this anycast address
+ *	called with rcu_read_lock()
  */
 static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr)
 {
 	struct inet6_dev *idev;
 	struct ifacaddr6 *aca;
 
-	idev = in6_dev_get(dev);
+	idev = __in6_dev_get(dev);
 	if (idev) {
 		read_lock_bh(&idev->lock);
 		for (aca = idev->ac_list; aca; aca = aca->aca_next)
 			if (ipv6_addr_equal(&aca->aca_addr, addr))
 				break;
 		read_unlock_bh(&idev->lock);
-		in6_dev_put(idev);
 		return aca != NULL;
 	}
 	return 0;
@@ -403,14 +396,15 @@
 {
 	int found = 0;
 
-	if (dev)
-		return ipv6_chk_acast_dev(dev, addr);
 	rcu_read_lock();
-	for_each_netdev_rcu(net, dev)
-		if (ipv6_chk_acast_dev(dev, addr)) {
-			found = 1;
-			break;
-		}
+	if (dev)
+		found = ipv6_chk_acast_dev(dev, addr);
+	else
+		for_each_netdev_rcu(net, dev)
+			if (ipv6_chk_acast_dev(dev, addr)) {
+				found = 1;
+				break;
+			}
 	rcu_read_unlock();
 	return found;
 }
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 7126846..7d929a2 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -38,10 +38,11 @@
 	struct sockaddr_in6	*usin = (struct sockaddr_in6 *) uaddr;
 	struct inet_sock      	*inet = inet_sk(sk);
 	struct ipv6_pinfo      	*np = inet6_sk(sk);
-	struct in6_addr		*daddr, *final_p = NULL, final;
+	struct in6_addr		*daddr, *final_p, final;
 	struct dst_entry	*dst;
 	struct flowi		fl;
 	struct ip6_flowlabel	*flowlabel = NULL;
+	struct ipv6_txoptions   *opt;
 	int			addr_type;
 	int			err;
 
@@ -155,19 +156,8 @@
 
 	security_sk_classify_flow(sk, &fl);
 
-	if (flowlabel) {
-		if (flowlabel->opt && flowlabel->opt->srcrt) {
-			struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
-			ipv6_addr_copy(&final, &fl.fl6_dst);
-			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-			final_p = &final;
-		}
-	} else if (np->opt && np->opt->srcrt) {
-		struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
-		ipv6_addr_copy(&final, &fl.fl6_dst);
-		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-		final_p = &final;
-	}
+	opt = flowlabel ? flowlabel->opt : np->opt;
+	final_p = fl6_update_dst(&fl, opt, &final);
 
 	err = ip6_dst_lookup(sk, &dst, &fl);
 	if (err)
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 8a659f9..262f105 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -312,6 +312,7 @@
   Routing header.
  ********************************/
 
+/* called with rcu_read_lock() */
 static int ipv6_rthdr_rcv(struct sk_buff *skb)
 {
 	struct inet6_skb_parm *opt = IP6CB(skb);
@@ -324,12 +325,9 @@
 	struct net *net = dev_net(skb->dev);
 	int accept_source_route = net->ipv6.devconf_all->accept_source_route;
 
-	idev = in6_dev_get(skb->dev);
-	if (idev) {
-		if (accept_source_route > idev->cnf.accept_source_route)
-			accept_source_route = idev->cnf.accept_source_route;
-		in6_dev_put(idev);
-	}
+	idev = __in6_dev_get(skb->dev);
+	if (idev && accept_source_route > idev->cnf.accept_source_route)
+		accept_source_route = idev->cnf.accept_source_route;
 
 	if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
 	    !pskb_may_pull(skb, (skb_transport_offset(skb) +
@@ -874,3 +872,27 @@
 	return opt;
 }
 
+/**
+ * fl6_update_dst - update flowi destination address with info given
+ *                  by srcrt option, if any.
+ *
+ * @fl: flowi for which fl6_dst is to be updated
+ * @opt: struct ipv6_txoptions in which to look for srcrt opt
+ * @orig: copy of original fl6_dst address if modified
+ *
+ * Returns NULL if no txoptions or no srcrt, otherwise returns orig
+ * and initial value of fl->fl6_dst set in orig
+ */
+struct in6_addr *fl6_update_dst(struct flowi *fl,
+				const struct ipv6_txoptions *opt,
+				struct in6_addr *orig)
+{
+	if (!opt || !opt->srcrt)
+		return NULL;
+
+	ipv6_addr_copy(orig, &fl->fl6_dst);
+	ipv6_addr_copy(&fl->fl6_dst, ((struct rt0_hdr *)opt->srcrt)->addr);
+	return orig;
+}
+
+EXPORT_SYMBOL_GPL(fl6_update_dst);
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index 8e44f8f..b1108ed 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -43,8 +43,8 @@
 	if (arg.result)
 		return arg.result;
 
-	dst_hold(&net->ipv6.ip6_null_entry->u.dst);
-	return &net->ipv6.ip6_null_entry->u.dst;
+	dst_hold(&net->ipv6.ip6_null_entry->dst);
+	return &net->ipv6.ip6_null_entry->dst;
 }
 
 static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
@@ -86,7 +86,7 @@
 			struct in6_addr saddr;
 
 			if (ipv6_dev_get_saddr(net,
-					       ip6_dst_idev(&rt->u.dst)->dev,
+					       ip6_dst_idev(&rt->dst)->dev,
 					       &flp->fl6_dst,
 					       rt6_flags2srcprefs(flags),
 					       &saddr))
@@ -99,12 +99,12 @@
 		goto out;
 	}
 again:
-	dst_release(&rt->u.dst);
+	dst_release(&rt->dst);
 	rt = NULL;
 	goto out;
 
 discard_pkt:
-	dst_hold(&rt->u.dst);
+	dst_hold(&rt->dst);
 out:
 	arg->result = rt;
 	return rt == NULL ? -EAGAIN : 0;
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 0c5e3c3..8a16280 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -185,7 +185,7 @@
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct flowi fl;
 	struct dst_entry *dst;
-	struct in6_addr *final_p = NULL, final;
+	struct in6_addr *final_p, final;
 
 	memset(&fl, 0, sizeof(fl));
 	fl.proto = sk->sk_protocol;
@@ -199,12 +199,7 @@
 	fl.fl_ip_dport = inet->inet_dport;
 	security_sk_classify_flow(sk, &fl);
 
-	if (np->opt && np->opt->srcrt) {
-		struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
-		ipv6_addr_copy(&final, &fl.fl6_dst);
-		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-		final_p = &final;
-	}
+	final_p = fl6_update_dst(&fl, np->opt, &final);
 
 	dst = __inet6_csk_dst_check(sk, np->dst_cookie);
 
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 92a122b..b6a5859 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -165,7 +165,7 @@
 static __inline__ void rt6_release(struct rt6_info *rt)
 {
 	if (atomic_dec_and_test(&rt->rt6i_ref))
-		dst_free(&rt->u.dst);
+		dst_free(&rt->dst);
 }
 
 static void fib6_link_table(struct net *net, struct fib6_table *tb)
@@ -278,7 +278,7 @@
 	int res;
 	struct rt6_info *rt;
 
-	for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) {
+	for (rt = w->leaf; rt; rt = rt->dst.rt6_next) {
 		res = rt6_dump_route(rt, w->args);
 		if (res < 0) {
 			/* Frame is full, suspend walking */
@@ -619,7 +619,7 @@
 
 	ins = &fn->leaf;
 
-	for (iter = fn->leaf; iter; iter=iter->u.dst.rt6_next) {
+	for (iter = fn->leaf; iter; iter=iter->dst.rt6_next) {
 		/*
 		 *	Search for duplicates
 		 */
@@ -647,7 +647,7 @@
 		if (iter->rt6i_metric > rt->rt6i_metric)
 			break;
 
-		ins = &iter->u.dst.rt6_next;
+		ins = &iter->dst.rt6_next;
 	}
 
 	/* Reset round-robin state, if necessary */
@@ -658,7 +658,7 @@
 	 *	insert node
 	 */
 
-	rt->u.dst.rt6_next = iter;
+	rt->dst.rt6_next = iter;
 	*ins = rt;
 	rt->rt6i_node = fn;
 	atomic_inc(&rt->rt6i_ref);
@@ -799,7 +799,7 @@
 			atomic_inc(&pn->leaf->rt6i_ref);
 		}
 #endif
-		dst_free(&rt->u.dst);
+		dst_free(&rt->dst);
 	}
 	return err;
 
@@ -810,7 +810,7 @@
 st_failure:
 	if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
 		fib6_repair_tree(info->nl_net, fn);
-	dst_free(&rt->u.dst);
+	dst_free(&rt->dst);
 	return err;
 #endif
 }
@@ -1108,7 +1108,7 @@
 	RT6_TRACE("fib6_del_route\n");
 
 	/* Unlink it */
-	*rtp = rt->u.dst.rt6_next;
+	*rtp = rt->dst.rt6_next;
 	rt->rt6i_node = NULL;
 	net->ipv6.rt6_stats->fib_rt_entries--;
 	net->ipv6.rt6_stats->fib_discarded_routes++;
@@ -1122,14 +1122,14 @@
 	FOR_WALKERS(w) {
 		if (w->state == FWS_C && w->leaf == rt) {
 			RT6_TRACE("walker %p adjusted by delroute\n", w);
-			w->leaf = rt->u.dst.rt6_next;
+			w->leaf = rt->dst.rt6_next;
 			if (w->leaf == NULL)
 				w->state = FWS_U;
 		}
 	}
 	read_unlock(&fib6_walker_lock);
 
-	rt->u.dst.rt6_next = NULL;
+	rt->dst.rt6_next = NULL;
 
 	/* If it was last route, expunge its radix tree node */
 	if (fn->leaf == NULL) {
@@ -1168,7 +1168,7 @@
 	struct rt6_info **rtp;
 
 #if RT6_DEBUG >= 2
-	if (rt->u.dst.obsolete>0) {
+	if (rt->dst.obsolete>0) {
 		WARN_ON(fn != NULL);
 		return -ENOENT;
 	}
@@ -1195,7 +1195,7 @@
 	 *	Walk the leaf entries looking for ourself
 	 */
 
-	for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.dst.rt6_next) {
+	for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->dst.rt6_next) {
 		if (*rtp == rt) {
 			fib6_del_route(fn, rtp, info);
 			return 0;
@@ -1334,7 +1334,7 @@
 		.nl_net = c->net,
 	};
 
-	for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) {
+	for (rt = w->leaf; rt; rt = rt->dst.rt6_next) {
 		res = c->func(rt, c->arg);
 		if (res < 0) {
 			w->leaf = rt;
@@ -1448,8 +1448,8 @@
 		}
 		gc_args.more++;
 	} else if (rt->rt6i_flags & RTF_CACHE) {
-		if (atomic_read(&rt->u.dst.__refcnt) == 0 &&
-		    time_after_eq(now, rt->u.dst.lastuse + gc_args.timeout)) {
+		if (atomic_read(&rt->dst.__refcnt) == 0 &&
+		    time_after_eq(now, rt->dst.lastuse + gc_args.timeout)) {
 			RT6_TRACE("aging clone %p\n", rt);
 			return -1;
 		} else if ((rt->rt6i_flags & RTF_GATEWAY) &&
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 89425af..d40b330 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -698,7 +698,7 @@
 		ipv6_hdr(skb)->payload_len = htons(first_len -
 						   sizeof(struct ipv6hdr));
 
-		dst_hold(&rt->u.dst);
+		dst_hold(&rt->dst);
 
 		for (;;) {
 			/* Prepare header of the next frame,
@@ -726,7 +726,7 @@
 
 			err = output(skb);
 			if(!err)
-				IP6_INC_STATS(net, ip6_dst_idev(&rt->u.dst),
+				IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
 					      IPSTATS_MIB_FRAGCREATES);
 
 			if (err || !frag)
@@ -740,9 +740,9 @@
 		kfree(tmp_hdr);
 
 		if (err == 0) {
-			IP6_INC_STATS(net, ip6_dst_idev(&rt->u.dst),
+			IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
 				      IPSTATS_MIB_FRAGOKS);
-			dst_release(&rt->u.dst);
+			dst_release(&rt->dst);
 			return 0;
 		}
 
@@ -752,9 +752,9 @@
 			frag = skb;
 		}
 
-		IP6_INC_STATS(net, ip6_dst_idev(&rt->u.dst),
+		IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
 			      IPSTATS_MIB_FRAGFAILS);
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 		return err;
 	}
 
@@ -785,7 +785,7 @@
 		 *	Allocate buffer.
 		 */
 
-		if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
+		if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->dst.dev), GFP_ATOMIC)) == NULL) {
 			NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
 			IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
 				      IPSTATS_MIB_FRAGFAILS);
@@ -798,7 +798,7 @@
 		 */
 
 		ip6_copy_metadata(frag, skb);
-		skb_reserve(frag, LL_RESERVED_SPACE(rt->u.dst.dev));
+		skb_reserve(frag, LL_RESERVED_SPACE(rt->dst.dev));
 		skb_put(frag, len + hlen + sizeof(struct frag_hdr));
 		skb_reset_network_header(frag);
 		fh = (struct frag_hdr *)(skb_network_header(frag) + hlen);
@@ -1156,24 +1156,24 @@
 
 			/* need source address above miyazawa*/
 		}
-		dst_hold(&rt->u.dst);
-		inet->cork.dst = &rt->u.dst;
+		dst_hold(&rt->dst);
+		inet->cork.dst = &rt->dst;
 		inet->cork.fl = *fl;
 		np->cork.hop_limit = hlimit;
 		np->cork.tclass = tclass;
 		mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
-		      rt->u.dst.dev->mtu : dst_mtu(rt->u.dst.path);
+		      rt->dst.dev->mtu : dst_mtu(rt->dst.path);
 		if (np->frag_size < mtu) {
 			if (np->frag_size)
 				mtu = np->frag_size;
 		}
 		inet->cork.fragsize = mtu;
-		if (dst_allfrag(rt->u.dst.path))
+		if (dst_allfrag(rt->dst.path))
 			inet->cork.flags |= IPCORK_ALLFRAG;
 		inet->cork.length = 0;
 		sk->sk_sndmsg_page = NULL;
 		sk->sk_sndmsg_off = 0;
-		exthdrlen = rt->u.dst.header_len + (opt ? opt->opt_flen : 0) -
+		exthdrlen = rt->dst.header_len + (opt ? opt->opt_flen : 0) -
 			    rt->rt6i_nfheader_len;
 		length += exthdrlen;
 		transhdrlen += exthdrlen;
@@ -1186,7 +1186,7 @@
 		mtu = inet->cork.fragsize;
 	}
 
-	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
+	hh_len = LL_RESERVED_SPACE(rt->dst.dev);
 
 	fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len +
 			(opt ? opt->opt_nflen : 0);
@@ -1224,7 +1224,7 @@
 		}
 
 		if (proto == IPPROTO_UDP &&
-		    (rt->u.dst.dev->features & NETIF_F_UFO)) {
+		    (rt->dst.dev->features & NETIF_F_UFO)) {
 
 			err = ip6_ufo_append_data(sk, getfrag, from, length,
 						  hh_len, fragheaderlen,
@@ -1270,7 +1270,7 @@
 
 			fraglen = datalen + fragheaderlen;
 			if ((flags & MSG_MORE) &&
-			    !(rt->u.dst.dev->features&NETIF_F_SG))
+			    !(rt->dst.dev->features&NETIF_F_SG))
 				alloclen = mtu;
 			else
 				alloclen = datalen + fragheaderlen;
@@ -1281,7 +1281,7 @@
 			 * because we have no idea if we're the last one.
 			 */
 			if (datalen == length + fraggap)
-				alloclen += rt->u.dst.trailer_len;
+				alloclen += rt->dst.trailer_len;
 
 			/*
 			 * We just reserve space for fragment header.
@@ -1358,7 +1358,7 @@
 		if (copy > length)
 			copy = length;
 
-		if (!(rt->u.dst.dev->features&NETIF_F_SG)) {
+		if (!(rt->dst.dev->features&NETIF_F_SG)) {
 			unsigned int off;
 
 			off = skb->len;
@@ -1503,7 +1503,7 @@
 	skb->priority = sk->sk_priority;
 	skb->mark = sk->sk_mark;
 
-	skb_dst_set(skb, dst_clone(&rt->u.dst));
+	skb_dst_set(skb, dst_clone(&rt->dst));
 	IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
 	if (proto == IPPROTO_ICMPV6) {
 		struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 8f39893..0fd027f 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -552,7 +552,7 @@
 	if (ip_route_output_key(dev_net(skb->dev), &rt, &fl))
 		goto out;
 
-	skb2->dev = rt->u.dst.dev;
+	skb2->dev = rt->dst.dev;
 
 	/* route "incoming" packet */
 	if (rt->rt_flags & RTCF_LOCAL) {
@@ -562,7 +562,7 @@
 		fl.fl4_src = eiph->saddr;
 		fl.fl4_tos = eiph->tos;
 		if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) ||
-		    rt->u.dst.dev->type != ARPHRD_TUNNEL) {
+		    rt->dst.dev->type != ARPHRD_TUNNEL) {
 			ip_rt_put(rt);
 			goto out;
 		}
@@ -626,7 +626,7 @@
 		icmpv6_send(skb2, rel_type, rel_code, rel_info);
 
 		if (rt)
-			dst_release(&rt->u.dst);
+			dst_release(&rt->dst);
 
 		kfree_skb(skb2);
 	}
@@ -1135,7 +1135,7 @@
 			if (dev->mtu < IPV6_MIN_MTU)
 				dev->mtu = IPV6_MIN_MTU;
 		}
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 	}
 }
 
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index bd43f01..a7f66bc 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -55,8 +55,6 @@
 
 #include <asm/uaccess.h>
 
-DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly;
-
 struct ip6_ra_chain *ip6_ra_chain;
 DEFINE_RWLOCK(ip6_ra_lock);
 
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index ab1622d..d1444b9 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -152,18 +152,19 @@
 	mc_lst->next = NULL;
 	ipv6_addr_copy(&mc_lst->addr, addr);
 
+	rcu_read_lock();
 	if (ifindex == 0) {
 		struct rt6_info *rt;
 		rt = rt6_lookup(net, addr, NULL, 0, 0);
 		if (rt) {
 			dev = rt->rt6i_dev;
-			dev_hold(dev);
-			dst_release(&rt->u.dst);
+			dst_release(&rt->dst);
 		}
 	} else
-		dev = dev_get_by_index(net, ifindex);
+		dev = dev_get_by_index_rcu(net, ifindex);
 
 	if (dev == NULL) {
+		rcu_read_unlock();
 		sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
 		return -ENODEV;
 	}
@@ -180,8 +181,8 @@
 	err = ipv6_dev_mc_inc(dev, addr);
 
 	if (err) {
+		rcu_read_unlock();
 		sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
-		dev_put(dev);
 		return err;
 	}
 
@@ -190,7 +191,7 @@
 	np->ipv6_mc_list = mc_lst;
 	write_unlock_bh(&ipv6_sk_mc_lock);
 
-	dev_put(dev);
+	rcu_read_unlock();
 
 	return 0;
 }
@@ -213,18 +214,17 @@
 			*lnk = mc_lst->next;
 			write_unlock_bh(&ipv6_sk_mc_lock);
 
-			dev = dev_get_by_index(net, mc_lst->ifindex);
+			rcu_read_lock();
+			dev = dev_get_by_index_rcu(net, mc_lst->ifindex);
 			if (dev != NULL) {
-				struct inet6_dev *idev = in6_dev_get(dev);
+				struct inet6_dev *idev = __in6_dev_get(dev);
 
 				(void) ip6_mc_leave_src(sk, mc_lst, idev);
-				if (idev) {
+				if (idev)
 					__ipv6_dev_mc_dec(idev, &mc_lst->addr);
-					in6_dev_put(idev);
-				}
-				dev_put(dev);
 			} else
 				(void) ip6_mc_leave_src(sk, mc_lst, NULL);
+			rcu_read_unlock();
 			sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
 			return 0;
 		}
@@ -234,43 +234,36 @@
 	return -EADDRNOTAVAIL;
 }
 
-static struct inet6_dev *ip6_mc_find_dev(struct net *net,
-					 struct in6_addr *group,
-					 int ifindex)
+/* called with rcu_read_lock() */
+static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
+					     struct in6_addr *group,
+					     int ifindex)
 {
 	struct net_device *dev = NULL;
 	struct inet6_dev *idev = NULL;
 
 	if (ifindex == 0) {
-		struct rt6_info *rt;
+		struct rt6_info *rt = rt6_lookup(net, group, NULL, 0, 0);
 
-		rt = rt6_lookup(net, group, NULL, 0, 0);
 		if (rt) {
 			dev = rt->rt6i_dev;
 			dev_hold(dev);
-			dst_release(&rt->u.dst);
+			dst_release(&rt->dst);
 		}
 	} else
-		dev = dev_get_by_index(net, ifindex);
+		dev = dev_get_by_index_rcu(net, ifindex);
 
 	if (!dev)
-		goto nodev;
-	idev = in6_dev_get(dev);
+		return NULL;
+	idev = __in6_dev_get(dev);
 	if (!idev)
-		goto release;
+		return NULL;;
 	read_lock_bh(&idev->lock);
-	if (idev->dead)
-		goto unlock_release;
-
+	if (idev->dead) {
+		read_unlock_bh(&idev->lock);
+		return NULL;
+	}
 	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)
@@ -286,19 +279,17 @@
 		np->ipv6_mc_list = mc_lst->next;
 		write_unlock_bh(&ipv6_sk_mc_lock);
 
-		dev = dev_get_by_index(net, mc_lst->ifindex);
+		rcu_read_lock();
+		dev = dev_get_by_index_rcu(net, mc_lst->ifindex);
 		if (dev) {
-			struct inet6_dev *idev = in6_dev_get(dev);
+			struct inet6_dev *idev = __in6_dev_get(dev);
 
 			(void) ip6_mc_leave_src(sk, mc_lst, idev);
-			if (idev) {
+			if (idev)
 				__ipv6_dev_mc_dec(idev, &mc_lst->addr);
-				in6_dev_put(idev);
-			}
-			dev_put(dev);
 		} else
 			(void) ip6_mc_leave_src(sk, mc_lst, NULL);
-
+		rcu_read_unlock();
 		sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
 
 		write_lock_bh(&ipv6_sk_mc_lock);
@@ -327,14 +318,17 @@
 	if (!ipv6_addr_is_multicast(group))
 		return -EINVAL;
 
-	idev = ip6_mc_find_dev(net, group, pgsr->gsr_interface);
-	if (!idev)
+	rcu_read_lock();
+	idev = ip6_mc_find_dev_rcu(net, group, pgsr->gsr_interface);
+	if (!idev) {
+		rcu_read_unlock();
 		return -ENODEV;
+	}
 	dev = idev->dev;
 
 	err = -EADDRNOTAVAIL;
 
-	read_lock_bh(&ipv6_sk_mc_lock);
+	read_lock(&ipv6_sk_mc_lock);
 	for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
 		if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface)
 			continue;
@@ -358,7 +352,7 @@
 		pmc->sfmode = omode;
 	}
 
-	write_lock_bh(&pmc->sflock);
+	write_lock(&pmc->sflock);
 	pmclocked = 1;
 
 	psl = pmc->sflist;
@@ -433,11 +427,10 @@
 	ip6_mc_add_src(idev, group, omode, 1, source, 1);
 done:
 	if (pmclocked)
-		write_unlock_bh(&pmc->sflock);
-	read_unlock_bh(&ipv6_sk_mc_lock);
+		write_unlock(&pmc->sflock);
+	read_unlock(&ipv6_sk_mc_lock);
 	read_unlock_bh(&idev->lock);
-	in6_dev_put(idev);
-	dev_put(dev);
+	rcu_read_unlock();
 	if (leavegroup)
 		return ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group);
 	return err;
@@ -463,14 +456,17 @@
 	    gsf->gf_fmode != MCAST_EXCLUDE)
 		return -EINVAL;
 
-	idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
+	rcu_read_lock();
+	idev = ip6_mc_find_dev_rcu(net, group, gsf->gf_interface);
 
-	if (!idev)
+	if (!idev) {
+		rcu_read_unlock();
 		return -ENODEV;
+	}
 	dev = idev->dev;
 
 	err = 0;
-	read_lock_bh(&ipv6_sk_mc_lock);
+	read_lock(&ipv6_sk_mc_lock);
 
 	if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) {
 		leavegroup = 1;
@@ -512,7 +508,7 @@
 		(void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0);
 	}
 
-	write_lock_bh(&pmc->sflock);
+	write_lock(&pmc->sflock);
 	psl = pmc->sflist;
 	if (psl) {
 		(void) ip6_mc_del_src(idev, group, pmc->sfmode,
@@ -522,13 +518,12 @@
 		(void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0);
 	pmc->sflist = newpsl;
 	pmc->sfmode = gsf->gf_fmode;
-	write_unlock_bh(&pmc->sflock);
+	write_unlock(&pmc->sflock);
 	err = 0;
 done:
-	read_unlock_bh(&ipv6_sk_mc_lock);
+	read_unlock(&ipv6_sk_mc_lock);
 	read_unlock_bh(&idev->lock);
-	in6_dev_put(idev);
-	dev_put(dev);
+	rcu_read_unlock();
 	if (leavegroup)
 		err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group);
 	return err;
@@ -551,11 +546,13 @@
 	if (!ipv6_addr_is_multicast(group))
 		return -EINVAL;
 
-	idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
+	rcu_read_lock();
+	idev = ip6_mc_find_dev_rcu(net, group, gsf->gf_interface);
 
-	if (!idev)
+	if (!idev) {
+		rcu_read_unlock();
 		return -ENODEV;
-
+	}
 	dev = idev->dev;
 
 	err = -EADDRNOTAVAIL;
@@ -577,8 +574,7 @@
 	psl = pmc->sflist;
 	count = psl ? psl->sl_count : 0;
 	read_unlock_bh(&idev->lock);
-	in6_dev_put(idev);
-	dev_put(dev);
+	rcu_read_unlock();
 
 	copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
 	gsf->gf_numsrc = count;
@@ -604,8 +600,7 @@
 	return 0;
 done:
 	read_unlock_bh(&idev->lock);
-	in6_dev_put(idev);
-	dev_put(dev);
+	rcu_read_unlock();
 	return err;
 }
 
@@ -822,6 +817,7 @@
 	struct ifmcaddr6 *mc;
 	struct inet6_dev *idev;
 
+	/* we need to take a reference on idev */
 	idev = in6_dev_get(dev);
 
 	if (idev == NULL)
@@ -860,7 +856,7 @@
 	setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc);
 
 	ipv6_addr_copy(&mc->mca_addr, addr);
-	mc->idev = idev;
+	mc->idev = idev; /* (reference taken) */
 	mc->mca_users = 1;
 	/* mca_stamp should be updated upon changes */
 	mc->mca_cstamp = mc->mca_tstamp = jiffies;
@@ -915,16 +911,18 @@
 
 int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr)
 {
-	struct inet6_dev *idev = in6_dev_get(dev);
+	struct inet6_dev *idev;
 	int err;
 
+	rcu_read_lock();
+
+	idev = __in6_dev_get(dev);
 	if (!idev)
-		return -ENODEV;
+		err = -ENODEV;
+	else
+		err = __ipv6_dev_mc_dec(idev, addr);
 
-	err = __ipv6_dev_mc_dec(idev, addr);
-
-	in6_dev_put(idev);
-
+	rcu_read_unlock();
 	return err;
 }
 
@@ -965,7 +963,8 @@
 	struct ifmcaddr6 *mc;
 	int rv = 0;
 
-	idev = in6_dev_get(dev);
+	rcu_read_lock();
+	idev = __in6_dev_get(dev);
 	if (idev) {
 		read_lock_bh(&idev->lock);
 		for (mc = idev->mc_list; mc; mc=mc->next) {
@@ -992,8 +991,8 @@
 				rv = 1; /* don't filter unspecified source */
 		}
 		read_unlock_bh(&idev->lock);
-		in6_dev_put(idev);
 	}
+	rcu_read_unlock();
 	return rv;
 }
 
@@ -1104,6 +1103,7 @@
 	return 1;
 }
 
+/* called with rcu_read_lock() */
 int igmp6_event_query(struct sk_buff *skb)
 {
 	struct mld2_query *mlh2 = NULL;
@@ -1127,7 +1127,7 @@
 	if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL))
 		return -EINVAL;
 
-	idev = in6_dev_get(skb->dev);
+	idev = __in6_dev_get(skb->dev);
 
 	if (idev == NULL)
 		return 0;
@@ -1137,10 +1137,8 @@
 	group_type = ipv6_addr_type(group);
 
 	if (group_type != IPV6_ADDR_ANY &&
-	    !(group_type&IPV6_ADDR_MULTICAST)) {
-		in6_dev_put(idev);
+	    !(group_type&IPV6_ADDR_MULTICAST))
 		return -EINVAL;
-	}
 
 	if (len == 24) {
 		int switchback;
@@ -1161,10 +1159,9 @@
 	} else if (len >= 28) {
 		int srcs_offset = sizeof(struct mld2_query) -
 				  sizeof(struct icmp6hdr);
-		if (!pskb_may_pull(skb, srcs_offset)) {
-			in6_dev_put(idev);
+		if (!pskb_may_pull(skb, srcs_offset))
 			return -EINVAL;
-		}
+
 		mlh2 = (struct mld2_query *)skb_transport_header(skb);
 		max_delay = (MLDV2_MRC(ntohs(mlh2->mld2q_mrc))*HZ)/1000;
 		if (!max_delay)
@@ -1173,28 +1170,23 @@
 		if (mlh2->mld2q_qrv)
 			idev->mc_qrv = mlh2->mld2q_qrv;
 		if (group_type == IPV6_ADDR_ANY) { /* general query */
-			if (mlh2->mld2q_nsrcs) {
-				in6_dev_put(idev);
+			if (mlh2->mld2q_nsrcs)
 				return -EINVAL; /* no sources allowed */
-			}
+
 			mld_gq_start_timer(idev);
-			in6_dev_put(idev);
 			return 0;
 		}
 		/* mark sources to include, if group & source-specific */
 		if (mlh2->mld2q_nsrcs != 0) {
 			if (!pskb_may_pull(skb, srcs_offset +
-			    ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr))) {
-				in6_dev_put(idev);
+			    ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr)))
 				return -EINVAL;
-			}
+
 			mlh2 = (struct mld2_query *)skb_transport_header(skb);
 			mark = 1;
 		}
-	} else {
-		in6_dev_put(idev);
+	} else
 		return -EINVAL;
-	}
 
 	read_lock_bh(&idev->lock);
 	if (group_type == IPV6_ADDR_ANY) {
@@ -1227,12 +1219,11 @@
 		}
 	}
 	read_unlock_bh(&idev->lock);
-	in6_dev_put(idev);
 
 	return 0;
 }
 
-
+/* called with rcu_read_lock() */
 int igmp6_event_report(struct sk_buff *skb)
 {
 	struct ifmcaddr6 *ma;
@@ -1260,7 +1251,7 @@
 	    !(addr_type&IPV6_ADDR_LINKLOCAL))
 		return -EINVAL;
 
-	idev = in6_dev_get(skb->dev);
+	idev = __in6_dev_get(skb->dev);
 	if (idev == NULL)
 		return -ENODEV;
 
@@ -1280,7 +1271,6 @@
 		}
 	}
 	read_unlock_bh(&idev->lock);
-	in6_dev_put(idev);
 	return 0;
 }
 
@@ -1396,12 +1386,14 @@
 	struct mld2_report *pmr =
 			      (struct mld2_report *)skb_transport_header(skb);
 	int payload_len, mldlen;
-	struct inet6_dev *idev = in6_dev_get(skb->dev);
+	struct inet6_dev *idev;
 	struct net *net = dev_net(skb->dev);
 	int err;
 	struct flowi fl;
 	struct dst_entry *dst;
 
+	rcu_read_lock();
+	idev = __in6_dev_get(skb->dev);
 	IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
 
 	payload_len = (skb->tail - skb->network_header) - sizeof(*pip6);
@@ -1441,8 +1433,7 @@
 	} else
 		IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTDISCARDS);
 
-	if (likely(idev != NULL))
-		in6_dev_put(idev);
+	rcu_read_unlock();
 	return;
 
 err_out:
@@ -1779,7 +1770,8 @@
 					 IPPROTO_ICMPV6,
 					 csum_partial(hdr, len, 0));
 
-	idev = in6_dev_get(skb->dev);
+	rcu_read_lock();
+	idev = __in6_dev_get(skb->dev);
 
 	dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
 	if (!dst) {
@@ -1806,8 +1798,7 @@
 	} else
 		IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
 
-	if (likely(idev != NULL))
-		in6_dev_put(idev);
+	rcu_read_unlock();
 	return;
 
 err_out:
@@ -1998,8 +1989,7 @@
 				    &psf->sf_addr))
 					break;
 			if (!dpsf) {
-				dpsf = (struct ip6_sf_list *)
-					kmalloc(sizeof(*dpsf), GFP_ATOMIC);
+				dpsf = kmalloc(sizeof(*dpsf), GFP_ATOMIC);
 				if (!dpsf)
 					continue;
 				*dpsf = *psf;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 2efef52..58841c4 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1229,7 +1229,7 @@
 			ND_PRINTK0(KERN_ERR
 				   "ICMPv6 RA: %s() got default router without neighbour.\n",
 				   __func__);
-			dst_release(&rt->u.dst);
+			dst_release(&rt->dst);
 			in6_dev_put(in6_dev);
 			return;
 		}
@@ -1244,7 +1244,7 @@
 	if (ra_msg->icmph.icmp6_hop_limit) {
 		in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
 		if (rt)
-			rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
+			rt->dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
 	}
 
 skip_defrtr:
@@ -1363,7 +1363,7 @@
 			in6_dev->cnf.mtu6 = mtu;
 
 			if (rt)
-				rt->u.dst.metrics[RTAX_MTU-1] = mtu;
+				rt->dst.metrics[RTAX_MTU-1] = mtu;
 
 			rt6_mtu_change(skb->dev, mtu);
 		}
@@ -1384,7 +1384,7 @@
 	}
 out:
 	if (rt)
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 	else if (neigh)
 		neigh_release(neigh);
 	in6_dev_put(in6_dev);
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index a74951c..7155b24 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -151,9 +151,7 @@
 							 protocol,
 							 csum_sub(0, hsum)));
 		skb->ip_summed = CHECKSUM_NONE;
-		csum = __skb_checksum_complete_head(skb, dataoff + len);
-		if (!csum)
-			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		return __skb_checksum_complete_head(skb, dataoff + len);
 	}
 	return csum;
 };
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 8c20174..413ab07 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -43,7 +43,7 @@
 
 static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE;
 static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT;
-static DEFINE_RWLOCK(queue_lock);
+static DEFINE_SPINLOCK(queue_lock);
 static int peer_pid __read_mostly;
 static unsigned int copy_range __read_mostly;
 static unsigned int queue_total;
@@ -73,10 +73,10 @@
 		break;
 
 	case IPQ_COPY_PACKET:
-		copy_mode = mode;
+		if (range > 0xFFFF)
+			range = 0xFFFF;
 		copy_range = range;
-		if (copy_range > 0xFFFF)
-			copy_range = 0xFFFF;
+		copy_mode = mode;
 		break;
 
 	default:
@@ -102,7 +102,7 @@
 {
 	struct nf_queue_entry *entry = NULL, *i;
 
-	write_lock_bh(&queue_lock);
+	spin_lock_bh(&queue_lock);
 
 	list_for_each_entry(i, &queue_list, list) {
 		if ((unsigned long)i == id) {
@@ -116,7 +116,7 @@
 		queue_total--;
 	}
 
-	write_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 	return entry;
 }
 
@@ -137,9 +137,9 @@
 static void
 ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
 {
-	write_lock_bh(&queue_lock);
+	spin_lock_bh(&queue_lock);
 	__ipq_flush(cmpfn, data);
-	write_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 }
 
 static struct sk_buff *
@@ -153,9 +153,7 @@
 	struct nlmsghdr *nlh;
 	struct timeval tv;
 
-	read_lock_bh(&queue_lock);
-
-	switch (copy_mode) {
+	switch (ACCESS_ONCE(copy_mode)) {
 	case IPQ_COPY_META:
 	case IPQ_COPY_NONE:
 		size = NLMSG_SPACE(sizeof(*pmsg));
@@ -163,26 +161,21 @@
 
 	case IPQ_COPY_PACKET:
 		if (entry->skb->ip_summed == CHECKSUM_PARTIAL &&
-		    (*errp = skb_checksum_help(entry->skb))) {
-			read_unlock_bh(&queue_lock);
+		    (*errp = skb_checksum_help(entry->skb)))
 			return NULL;
-		}
-		if (copy_range == 0 || copy_range > entry->skb->len)
+
+		data_len = ACCESS_ONCE(copy_range);
+		if (data_len == 0 || data_len > entry->skb->len)
 			data_len = entry->skb->len;
-		else
-			data_len = copy_range;
 
 		size = NLMSG_SPACE(sizeof(*pmsg) + data_len);
 		break;
 
 	default:
 		*errp = -EINVAL;
-		read_unlock_bh(&queue_lock);
 		return NULL;
 	}
 
-	read_unlock_bh(&queue_lock);
-
 	skb = alloc_skb(size, GFP_ATOMIC);
 	if (!skb)
 		goto nlmsg_failure;
@@ -242,7 +235,7 @@
 	if (nskb == NULL)
 		return status;
 
-	write_lock_bh(&queue_lock);
+	spin_lock_bh(&queue_lock);
 
 	if (!peer_pid)
 		goto err_out_free_nskb;
@@ -266,14 +259,14 @@
 
 	__ipq_enqueue_entry(entry);
 
-	write_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 	return status;
 
 err_out_free_nskb:
 	kfree_skb(nskb);
 
 err_out_unlock:
-	write_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 	return status;
 }
 
@@ -342,9 +335,9 @@
 {
 	int status;
 
-	write_lock_bh(&queue_lock);
+	spin_lock_bh(&queue_lock);
 	status = __ipq_set_mode(mode, range);
-	write_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 	return status;
 }
 
@@ -441,11 +434,11 @@
 	if (security_netlink_recv(skb, CAP_NET_ADMIN))
 		RCV_SKB_FAIL(-EPERM);
 
-	write_lock_bh(&queue_lock);
+	spin_lock_bh(&queue_lock);
 
 	if (peer_pid) {
 		if (peer_pid != pid) {
-			write_unlock_bh(&queue_lock);
+			spin_unlock_bh(&queue_lock);
 			RCV_SKB_FAIL(-EBUSY);
 		}
 	} else {
@@ -453,7 +446,7 @@
 		peer_pid = pid;
 	}
 
-	write_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 
 	status = ipq_receive_peer(NLMSG_DATA(nlh), type,
 				  nlmsglen - NLMSG_LENGTH(0));
@@ -498,10 +491,10 @@
 	struct netlink_notify *n = ptr;
 
 	if (event == NETLINK_URELEASE && n->protocol == NETLINK_IP6_FW) {
-		write_lock_bh(&queue_lock);
+		spin_lock_bh(&queue_lock);
 		if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid))
 			__ipq_reset();
-		write_unlock_bh(&queue_lock);
+		spin_unlock_bh(&queue_lock);
 	}
 	return NOTIFY_DONE;
 }
@@ -528,7 +521,7 @@
 #ifdef CONFIG_PROC_FS
 static int ip6_queue_show(struct seq_file *m, void *v)
 {
-	read_lock_bh(&queue_lock);
+	spin_lock_bh(&queue_lock);
 
 	seq_printf(m,
 		      "Peer PID          : %d\n"
@@ -546,7 +539,7 @@
 		      queue_dropped,
 		      queue_user_dropped);
 
-	read_unlock_bh(&queue_lock);
+	spin_unlock_bh(&queue_lock);
 	return 0;
 }
 
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 9d2d68f..5359ef4 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -387,9 +387,7 @@
 				goto no_match;
 		}
 
-		ADD_COUNTER(e->counters,
-			    ntohs(ipv6_hdr(skb)->payload_len) +
-			    sizeof(struct ipv6hdr), 1);
+		ADD_COUNTER(e->counters, skb->len, 1);
 
 		t = ip6t_get_target_c(e);
 		IP_NF_ASSERT(t->u.kernel.target);
@@ -899,7 +897,7 @@
 	struct ip6t_entry *iter;
 	unsigned int cpu;
 	unsigned int i;
-	unsigned int curcpu;
+	unsigned int curcpu = get_cpu();
 
 	/* Instead of clearing (by a previous call to memset())
 	 * the counters and using adds, we set the counters
@@ -909,14 +907,16 @@
 	 * if new softirq were to run and call ipt_do_table
 	 */
 	local_bh_disable();
-	curcpu = smp_processor_id();
-
 	i = 0;
 	xt_entry_foreach(iter, t->entries[curcpu], t->size) {
 		SET_COUNTER(counters[i], iter->counters.bcnt,
 			    iter->counters.pcnt);
 		++i;
 	}
+	local_bh_enable();
+	/* Processing counters from other cpus, we can let bottom half enabled,
+	 * (preemption is disabled)
+	 */
 
 	for_each_possible_cpu(cpu) {
 		if (cpu == curcpu)
@@ -930,7 +930,7 @@
 		}
 		xt_info_wrunlock(cpu);
 	}
-	local_bh_enable();
+	put_cpu();
 }
 
 static struct xt_counters *alloc_counters(const struct xt_table *table)
@@ -943,7 +943,7 @@
 	   (other than comefrom, which userspace doesn't care
 	   about). */
 	countersize = sizeof(struct xt_counters) * private->number;
-	counters = vmalloc_node(countersize, numa_node_id());
+	counters = vmalloc(countersize);
 
 	if (counters == NULL)
 		return ERR_PTR(-ENOMEM);
@@ -1213,8 +1213,7 @@
 	struct ip6t_entry *iter;
 
 	ret = 0;
-	counters = vmalloc_node(num_counters * sizeof(struct xt_counters),
-				numa_node_id());
+	counters = vmalloc(num_counters * sizeof(struct xt_counters));
 	if (!counters) {
 		ret = -ENOMEM;
 		goto out;
@@ -1368,7 +1367,7 @@
 	if (len != size + num_counters * sizeof(struct xt_counters))
 		return -EINVAL;
 
-	paddc = vmalloc_node(len - size, numa_node_id());
+	paddc = vmalloc(len - size);
 	if (!paddc)
 		return -ENOMEM;
 
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index af4ee11..0a07ae7 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -373,6 +373,56 @@
 		printk("MARK=0x%x ", skb->mark);
 }
 
+static void dump_mac_header(const struct nf_loginfo *info,
+			    const struct sk_buff *skb)
+{
+	struct net_device *dev = skb->dev;
+	unsigned int logflags = 0;
+
+	if (info->type == NF_LOG_TYPE_LOG)
+		logflags = info->u.log.logflags;
+
+	if (!(logflags & IP6T_LOG_MACDECODE))
+		goto fallback;
+
+	switch (dev->type) {
+	case ARPHRD_ETHER:
+		printk("MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
+		       eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
+		       ntohs(eth_hdr(skb)->h_proto));
+		return;
+	default:
+		break;
+	}
+
+fallback:
+	printk("MAC=");
+	if (dev->hard_header_len &&
+	    skb->mac_header != skb->network_header) {
+		const unsigned char *p = skb_mac_header(skb);
+		unsigned int len = dev->hard_header_len;
+		unsigned int i;
+
+		if (dev->type == ARPHRD_SIT &&
+		    (p -= ETH_HLEN) < skb->head)
+			p = NULL;
+
+		if (p != NULL) {
+			printk("%02x", *p++);
+			for (i = 1; i < len; i++)
+				printk(":%02x", p[i]);
+		}
+		printk(" ");
+
+		if (dev->type == ARPHRD_SIT) {
+			const struct iphdr *iph =
+				(struct iphdr *)skb_mac_header(skb);
+			printk("TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr);
+		}
+	} else
+		printk(" ");
+}
+
 static struct nf_loginfo default_loginfo = {
 	.type	= NF_LOG_TYPE_LOG,
 	.u = {
@@ -400,35 +450,10 @@
 		prefix,
 		in ? in->name : "",
 		out ? out->name : "");
-	if (in && !out) {
-		unsigned int len;
-		/* MAC logging for input chain only. */
-		printk("MAC=");
-		if (skb->dev && (len = skb->dev->hard_header_len) &&
-		    skb->mac_header != skb->network_header) {
-			const unsigned char *p = skb_mac_header(skb);
-			int i;
 
-			if (skb->dev->type == ARPHRD_SIT &&
-			    (p -= ETH_HLEN) < skb->head)
-				p = NULL;
-
-			if (p != NULL) {
-				for (i = 0; i < len; i++)
-					printk("%02x%s", p[i],
-					       i == len - 1 ? "" : ":");
-			}
-			printk(" ");
-
-			if (skb->dev->type == ARPHRD_SIT) {
-				const struct iphdr *iph =
-					(struct iphdr *)skb_mac_header(skb);
-				printk("TUNNEL=%pI4->%pI4 ",
-				       &iph->saddr, &iph->daddr);
-			}
-		} else
-			printk(" ");
-	}
+	/* MAC logging for input path only. */
+	if (in && !out)
+		dump_mac_header(loginfo, skb);
 
 	dump_packet(loginfo, skb, skb_network_offset(skb), 1);
 	printk("\n");
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 9be8177..1df3c8b 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -208,7 +208,7 @@
 	type = icmp6h->icmp6_type - 130;
 	if (type >= 0 && type < sizeof(noct_valid_new) &&
 	    noct_valid_new[type]) {
-		skb->nfct = &nf_conntrack_untracked.ct_general;
+		skb->nfct = &nf_ct_untracked_get()->ct_general;
 		skb->nfctinfo = IP_CT_NEW;
 		nf_conntrack_get(skb->nfct);
 		return NF_ACCEPT;
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 4dc8805..13ef5bc 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -114,10 +114,8 @@
 }
 
 /* Memory Tracking Functions. */
-static inline void frag_kfree_skb(struct sk_buff *skb, unsigned int *work)
+static void frag_kfree_skb(struct sk_buff *skb)
 {
-	if (work)
-		*work -= skb->truesize;
 	atomic_sub(skb->truesize, &nf_init_frags.mem);
 	nf_skb_free(skb);
 	kfree_skb(skb);
@@ -271,6 +269,11 @@
 	 * in the chain of fragments so far.  We must know where to put
 	 * this fragment, right?
 	 */
+	prev = fq->q.fragments_tail;
+	if (!prev || NFCT_FRAG6_CB(prev)->offset < offset) {
+		next = NULL;
+		goto found;
+	}
 	prev = NULL;
 	for (next = fq->q.fragments; next != NULL; next = next->next) {
 		if (NFCT_FRAG6_CB(next)->offset >= offset)
@@ -278,6 +281,7 @@
 		prev = next;
 	}
 
+found:
 	/* We found where to put this one.  Check for overlap with
 	 * preceding fragment, and, if needed, align things so that
 	 * any overlaps are eliminated.
@@ -335,7 +339,7 @@
 				fq->q.fragments = next;
 
 			fq->q.meat -= free_it->len;
-			frag_kfree_skb(free_it, NULL);
+			frag_kfree_skb(free_it);
 		}
 	}
 
@@ -343,6 +347,8 @@
 
 	/* Insert this fragment in the chain of fragments. */
 	skb->next = next;
+	if (!next)
+		fq->q.fragments_tail = skb;
 	if (prev)
 		prev->next = skb;
 	else
@@ -442,7 +448,6 @@
 	skb_shinfo(head)->frag_list = head->next;
 	skb_reset_transport_header(head);
 	skb_push(head, head->data - skb_network_header(head));
-	atomic_sub(head->truesize, &nf_init_frags.mem);
 
 	for (fp=head->next; fp; fp = fp->next) {
 		head->data_len += fp->len;
@@ -452,8 +457,8 @@
 		else if (head->ip_summed == CHECKSUM_COMPLETE)
 			head->csum = csum_add(head->csum, fp->csum);
 		head->truesize += fp->truesize;
-		atomic_sub(fp->truesize, &nf_init_frags.mem);
 	}
+	atomic_sub(head->truesize, &nf_init_frags.mem);
 
 	head->next = NULL;
 	head->dev = dev;
@@ -467,6 +472,7 @@
 					  head->csum);
 
 	fq->q.fragments = NULL;
+	fq->q.fragments_tail = NULL;
 
 	/* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */
 	fp = skb_shinfo(head)->frag_list;
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index 566798d..d082eae 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -174,17 +174,28 @@
 				const struct snmp_mib *itemlist)
 {
 	int i;
-	for (i=0; itemlist[i].name; i++)
+
+	for (i = 0; itemlist[i].name; i++)
 		seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name,
 			   snmp_fold_field(mib, itemlist[i].entry));
 }
 
+static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu **mib,
+				  const struct snmp_mib *itemlist, size_t syncpoff)
+{
+	int i;
+
+	for (i = 0; itemlist[i].name; i++)
+		seq_printf(seq, "%-32s\t%llu\n", itemlist[i].name,
+			   snmp_fold_field64(mib, itemlist[i].entry, syncpoff));
+}
+
 static int snmp6_seq_show(struct seq_file *seq, void *v)
 {
 	struct net *net = (struct net *)seq->private;
 
-	snmp6_seq_show_item(seq, (void __percpu **)net->mib.ipv6_statistics,
-			    snmp6_ipstats_list);
+	snmp6_seq_show_item64(seq, (void __percpu **)net->mib.ipv6_statistics,
+			    snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp));
 	snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics,
 			    snmp6_icmp6_list);
 	snmp6_seq_show_icmpv6msg(seq,
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 4a4dcbe..e677937 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -602,31 +602,33 @@
 }
 
 static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
-			struct flowi *fl, struct rt6_info *rt,
+			struct flowi *fl, struct dst_entry **dstp,
 			unsigned int flags)
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct ipv6hdr *iph;
 	struct sk_buff *skb;
 	int err;
+	struct rt6_info *rt = (struct rt6_info *)*dstp;
 
-	if (length > rt->u.dst.dev->mtu) {
-		ipv6_local_error(sk, EMSGSIZE, fl, rt->u.dst.dev->mtu);
+	if (length > rt->dst.dev->mtu) {
+		ipv6_local_error(sk, EMSGSIZE, fl, rt->dst.dev->mtu);
 		return -EMSGSIZE;
 	}
 	if (flags&MSG_PROBE)
 		goto out;
 
 	skb = sock_alloc_send_skb(sk,
-				  length + LL_ALLOCATED_SPACE(rt->u.dst.dev) + 15,
+				  length + LL_ALLOCATED_SPACE(rt->dst.dev) + 15,
 				  flags & MSG_DONTWAIT, &err);
 	if (skb == NULL)
 		goto error;
-	skb_reserve(skb, LL_RESERVED_SPACE(rt->u.dst.dev));
+	skb_reserve(skb, LL_RESERVED_SPACE(rt->dst.dev));
 
 	skb->priority = sk->sk_priority;
 	skb->mark = sk->sk_mark;
-	skb_dst_set(skb, dst_clone(&rt->u.dst));
+	skb_dst_set(skb, &rt->dst);
+	*dstp = NULL;
 
 	skb_put(skb, length);
 	skb_reset_network_header(skb);
@@ -641,7 +643,7 @@
 
 	IP6_UPD_PO_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
 	err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
-		      rt->u.dst.dev, dst_output);
+		      rt->dst.dev, dst_output);
 	if (err > 0)
 		err = net_xmit_errno(err);
 	if (err)
@@ -725,7 +727,7 @@
 {
 	struct ipv6_txoptions opt_space;
 	struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
-	struct in6_addr *daddr, *final_p = NULL, final;
+	struct in6_addr *daddr, *final_p, final;
 	struct inet_sock *inet = inet_sk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct raw6_sock *rp = raw6_sk(sk);
@@ -847,13 +849,7 @@
 	if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
 		ipv6_addr_copy(&fl.fl6_src, &np->saddr);
 
-	/* merge ip6_build_xmit from ip6_output */
-	if (opt && opt->srcrt) {
-		struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
-		ipv6_addr_copy(&final, &fl.fl6_dst);
-		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-		final_p = &final;
-	}
+	final_p = fl6_update_dst(&fl, opt, &final);
 
 	if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
 		fl.oif = np->mcast_oif;
@@ -892,9 +888,9 @@
 		goto do_confirm;
 
 back_from_confirm:
-	if (inet->hdrincl) {
-		err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, (struct rt6_info*)dst, msg->msg_flags);
-	} else {
+	if (inet->hdrincl)
+		err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, &dst, msg->msg_flags);
+	else {
 		lock_sock(sk);
 		err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
 			len, 0, hlimit, tclass, opt, &fl, (struct rt6_info*)dst,
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 6d4292f..545c414 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -150,11 +150,8 @@
 EXPORT_SYMBOL(ip6_frag_match);
 
 /* Memory Tracking Functions. */
-static inline void frag_kfree_skb(struct netns_frags *nf,
-		struct sk_buff *skb, int *work)
+static void frag_kfree_skb(struct netns_frags *nf, struct sk_buff *skb)
 {
-	if (work)
-		*work -= skb->truesize;
 	atomic_sub(skb->truesize, &nf->mem);
 	kfree_skb(skb);
 }
@@ -336,6 +333,11 @@
 	 * in the chain of fragments so far.  We must know where to put
 	 * this fragment, right?
 	 */
+	prev = fq->q.fragments_tail;
+	if (!prev || FRAG6_CB(prev)->offset < offset) {
+		next = NULL;
+		goto found;
+	}
 	prev = NULL;
 	for(next = fq->q.fragments; next != NULL; next = next->next) {
 		if (FRAG6_CB(next)->offset >= offset)
@@ -343,6 +345,7 @@
 		prev = next;
 	}
 
+found:
 	/* We found where to put this one.  Check for overlap with
 	 * preceding fragment, and, if needed, align things so that
 	 * any overlaps are eliminated.
@@ -392,7 +395,7 @@
 				fq->q.fragments = next;
 
 			fq->q.meat -= free_it->len;
-			frag_kfree_skb(fq->q.net, free_it, NULL);
+			frag_kfree_skb(fq->q.net, free_it);
 		}
 	}
 
@@ -400,6 +403,8 @@
 
 	/* Insert this fragment in the chain of fragments. */
 	skb->next = next;
+	if (!next)
+		fq->q.fragments_tail = skb;
 	if (prev)
 		prev->next = skb;
 	else
@@ -466,6 +471,8 @@
 			goto out_oom;
 
 		fp->next = head->next;
+		if (!fp->next)
+			fq->q.fragments_tail = fp;
 		prev->next = fp;
 
 		skb_morph(head, fq->q.fragments);
@@ -524,7 +531,6 @@
 	skb_shinfo(head)->frag_list = head->next;
 	skb_reset_transport_header(head);
 	skb_push(head, head->data - skb_network_header(head));
-	atomic_sub(head->truesize, &fq->q.net->mem);
 
 	for (fp=head->next; fp; fp = fp->next) {
 		head->data_len += fp->len;
@@ -534,8 +540,8 @@
 		else if (head->ip_summed == CHECKSUM_COMPLETE)
 			head->csum = csum_add(head->csum, fp->csum);
 		head->truesize += fp->truesize;
-		atomic_sub(fp->truesize, &fq->q.net->mem);
 	}
+	atomic_sub(head->truesize, &fq->q.net->mem);
 
 	head->next = NULL;
 	head->dev = dev;
@@ -553,6 +559,7 @@
 	IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
 	rcu_read_unlock();
 	fq->q.fragments = NULL;
+	fq->q.fragments_tail = NULL;
 	return 1;
 
 out_oversize:
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 252d761..8f2d040 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -126,16 +126,14 @@
 };
 
 static struct rt6_info ip6_null_entry_template = {
-	.u = {
-		.dst = {
-			.__refcnt	= ATOMIC_INIT(1),
-			.__use		= 1,
-			.obsolete	= -1,
-			.error		= -ENETUNREACH,
-			.metrics	= { [RTAX_HOPLIMIT - 1] = 255, },
-			.input		= ip6_pkt_discard,
-			.output		= ip6_pkt_discard_out,
-		}
+	.dst = {
+		.__refcnt	= ATOMIC_INIT(1),
+		.__use		= 1,
+		.obsolete	= -1,
+		.error		= -ENETUNREACH,
+		.metrics	= { [RTAX_HOPLIMIT - 1] = 255, },
+		.input		= ip6_pkt_discard,
+		.output		= ip6_pkt_discard_out,
 	},
 	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
 	.rt6i_protocol  = RTPROT_KERNEL,
@@ -149,16 +147,14 @@
 static int ip6_pkt_prohibit_out(struct sk_buff *skb);
 
 static struct rt6_info ip6_prohibit_entry_template = {
-	.u = {
-		.dst = {
-			.__refcnt	= ATOMIC_INIT(1),
-			.__use		= 1,
-			.obsolete	= -1,
-			.error		= -EACCES,
-			.metrics	= { [RTAX_HOPLIMIT - 1] = 255, },
-			.input		= ip6_pkt_prohibit,
-			.output		= ip6_pkt_prohibit_out,
-		}
+	.dst = {
+		.__refcnt	= ATOMIC_INIT(1),
+		.__use		= 1,
+		.obsolete	= -1,
+		.error		= -EACCES,
+		.metrics	= { [RTAX_HOPLIMIT - 1] = 255, },
+		.input		= ip6_pkt_prohibit,
+		.output		= ip6_pkt_prohibit_out,
 	},
 	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
 	.rt6i_protocol  = RTPROT_KERNEL,
@@ -167,16 +163,14 @@
 };
 
 static struct rt6_info ip6_blk_hole_entry_template = {
-	.u = {
-		.dst = {
-			.__refcnt	= ATOMIC_INIT(1),
-			.__use		= 1,
-			.obsolete	= -1,
-			.error		= -EINVAL,
-			.metrics	= { [RTAX_HOPLIMIT - 1] = 255, },
-			.input		= dst_discard,
-			.output		= dst_discard,
-		}
+	.dst = {
+		.__refcnt	= ATOMIC_INIT(1),
+		.__use		= 1,
+		.obsolete	= -1,
+		.error		= -EINVAL,
+		.metrics	= { [RTAX_HOPLIMIT - 1] = 255, },
+		.input		= dst_discard,
+		.output		= dst_discard,
 	},
 	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
 	.rt6i_protocol  = RTPROT_KERNEL,
@@ -249,7 +243,7 @@
 	if (!oif && ipv6_addr_any(saddr))
 		goto out;
 
-	for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) {
+	for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
 		struct net_device *dev = sprt->rt6i_dev;
 
 		if (oif) {
@@ -407,10 +401,10 @@
 
 	match = NULL;
 	for (rt = rr_head; rt && rt->rt6i_metric == metric;
-	     rt = rt->u.dst.rt6_next)
+	     rt = rt->dst.rt6_next)
 		match = find_match(rt, oif, strict, &mpri, match);
 	for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric;
-	     rt = rt->u.dst.rt6_next)
+	     rt = rt->dst.rt6_next)
 		match = find_match(rt, oif, strict, &mpri, match);
 
 	return match;
@@ -432,7 +426,7 @@
 
 	if (!match &&
 	    (strict & RT6_LOOKUP_F_REACHABLE)) {
-		struct rt6_info *next = rt0->u.dst.rt6_next;
+		struct rt6_info *next = rt0->dst.rt6_next;
 
 		/* no entries matched; do round-robin */
 		if (!next || next->rt6i_metric != rt0->rt6i_metric)
@@ -517,7 +511,7 @@
 			rt->rt6i_expires = jiffies + HZ * lifetime;
 			rt->rt6i_flags |= RTF_EXPIRES;
 		}
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 	}
 	return 0;
 }
@@ -555,7 +549,7 @@
 	rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags);
 	BACKTRACK(net, &fl->fl6_src);
 out:
-	dst_use(&rt->u.dst, jiffies);
+	dst_use(&rt->dst, jiffies);
 	read_unlock_bh(&table->tb6_lock);
 	return rt;
 
@@ -643,7 +637,7 @@
 		ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
 		rt->rt6i_dst.plen = 128;
 		rt->rt6i_flags |= RTF_CACHE;
-		rt->u.dst.flags |= DST_HOST;
+		rt->dst.flags |= DST_HOST;
 
 #ifdef CONFIG_IPV6_SUBTREES
 		if (rt->rt6i_src.plen && saddr) {
@@ -677,7 +671,7 @@
 			if (net_ratelimit())
 				printk(KERN_WARNING
 				       "Neighbour table overflow.\n");
-			dst_free(&rt->u.dst);
+			dst_free(&rt->dst);
 			return NULL;
 		}
 		rt->rt6i_nexthop = neigh;
@@ -694,7 +688,7 @@
 		ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
 		rt->rt6i_dst.plen = 128;
 		rt->rt6i_flags |= RTF_CACHE;
-		rt->u.dst.flags |= DST_HOST;
+		rt->dst.flags |= DST_HOST;
 		rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop);
 	}
 	return rt;
@@ -726,7 +720,7 @@
 	    rt->rt6i_flags & RTF_CACHE)
 		goto out;
 
-	dst_hold(&rt->u.dst);
+	dst_hold(&rt->dst);
 	read_unlock_bh(&table->tb6_lock);
 
 	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
@@ -739,10 +733,10 @@
 #endif
 	}
 
-	dst_release(&rt->u.dst);
+	dst_release(&rt->dst);
 	rt = nrt ? : net->ipv6.ip6_null_entry;
 
-	dst_hold(&rt->u.dst);
+	dst_hold(&rt->dst);
 	if (nrt) {
 		err = ip6_ins_rt(nrt);
 		if (!err)
@@ -756,7 +750,7 @@
 	 * Race condition! In the gap, when table->tb6_lock was
 	 * released someone could insert this route.  Relookup.
 	 */
-	dst_release(&rt->u.dst);
+	dst_release(&rt->dst);
 	goto relookup;
 
 out:
@@ -764,11 +758,11 @@
 		reachable = 0;
 		goto restart_2;
 	}
-	dst_hold(&rt->u.dst);
+	dst_hold(&rt->dst);
 	read_unlock_bh(&table->tb6_lock);
 out2:
-	rt->u.dst.lastuse = jiffies;
-	rt->u.dst.__use++;
+	rt->dst.lastuse = jiffies;
+	rt->dst.__use++;
 
 	return rt;
 }
@@ -835,15 +829,15 @@
 	struct dst_entry *new = NULL;
 
 	if (rt) {
-		new = &rt->u.dst;
+		new = &rt->dst;
 
 		atomic_set(&new->__refcnt, 1);
 		new->__use = 1;
 		new->input = dst_discard;
 		new->output = dst_discard;
 
-		memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
-		new->dev = ort->u.dst.dev;
+		memcpy(new->metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32));
+		new->dev = ort->dst.dev;
 		if (new->dev)
 			dev_hold(new->dev);
 		rt->rt6i_idev = ort->rt6i_idev;
@@ -912,7 +906,7 @@
 	rt = (struct rt6_info *) skb_dst(skb);
 	if (rt) {
 		if (rt->rt6i_flags&RTF_CACHE) {
-			dst_set_expires(&rt->u.dst, 0);
+			dst_set_expires(&rt->dst, 0);
 			rt->rt6i_flags |= RTF_EXPIRES;
 		} else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT))
 			rt->rt6i_node->fn_sernum = -1;
@@ -986,14 +980,14 @@
 	rt->rt6i_dev	  = dev;
 	rt->rt6i_idev     = idev;
 	rt->rt6i_nexthop  = neigh;
-	atomic_set(&rt->u.dst.__refcnt, 1);
-	rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255;
-	rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
-	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst));
-	rt->u.dst.output  = ip6_output;
+	atomic_set(&rt->dst.__refcnt, 1);
+	rt->dst.metrics[RTAX_HOPLIMIT-1] = 255;
+	rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
+	rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst));
+	rt->dst.output  = ip6_output;
 
 #if 0	/* there's no chance to use these for ndisc */
-	rt->u.dst.flags   = ipv6_addr_type(addr) & IPV6_ADDR_UNICAST
+	rt->dst.flags   = ipv6_addr_type(addr) & IPV6_ADDR_UNICAST
 				? DST_HOST
 				: 0;
 	ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
@@ -1001,14 +995,14 @@
 #endif
 
 	spin_lock_bh(&icmp6_dst_lock);
-	rt->u.dst.next = icmp6_dst_gc_list;
-	icmp6_dst_gc_list = &rt->u.dst;
+	rt->dst.next = icmp6_dst_gc_list;
+	icmp6_dst_gc_list = &rt->dst;
 	spin_unlock_bh(&icmp6_dst_lock);
 
 	fib6_force_start_gc(net);
 
 out:
-	return &rt->u.dst;
+	return &rt->dst;
 }
 
 int icmp6_dst_gc(void)
@@ -1090,11 +1084,11 @@
 	int mtu = IPV6_MIN_MTU;
 	struct inet6_dev *idev;
 
-	idev = in6_dev_get(dev);
-	if (idev) {
+	rcu_read_lock();
+	idev = __in6_dev_get(dev);
+	if (idev)
 		mtu = idev->cnf.mtu6;
-		in6_dev_put(idev);
-	}
+	rcu_read_unlock();
 	return mtu;
 }
 
@@ -1103,12 +1097,15 @@
 	int hoplimit = dst_metric(dst, RTAX_HOPLIMIT);
 	if (hoplimit < 0) {
 		struct net_device *dev = dst->dev;
-		struct inet6_dev *idev = in6_dev_get(dev);
-		if (idev) {
+		struct inet6_dev *idev;
+
+		rcu_read_lock();
+		idev = __in6_dev_get(dev);
+		if (idev)
 			hoplimit = idev->cnf.hop_limit;
-			in6_dev_put(idev);
-		} else
+		else
 			hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit;
+		rcu_read_unlock();
 	}
 	return hoplimit;
 }
@@ -1159,7 +1156,7 @@
 		goto out;
 	}
 
-	rt->u.dst.obsolete = -1;
+	rt->dst.obsolete = -1;
 	rt->rt6i_expires = (cfg->fc_flags & RTF_EXPIRES) ?
 				jiffies + clock_t_to_jiffies(cfg->fc_expires) :
 				0;
@@ -1171,16 +1168,16 @@
 	addr_type = ipv6_addr_type(&cfg->fc_dst);
 
 	if (addr_type & IPV6_ADDR_MULTICAST)
-		rt->u.dst.input = ip6_mc_input;
+		rt->dst.input = ip6_mc_input;
 	else
-		rt->u.dst.input = ip6_forward;
+		rt->dst.input = ip6_forward;
 
-	rt->u.dst.output = ip6_output;
+	rt->dst.output = ip6_output;
 
 	ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
 	rt->rt6i_dst.plen = cfg->fc_dst_len;
 	if (rt->rt6i_dst.plen == 128)
-	       rt->u.dst.flags = DST_HOST;
+	       rt->dst.flags = DST_HOST;
 
 #ifdef CONFIG_IPV6_SUBTREES
 	ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
@@ -1208,9 +1205,9 @@
 				goto out;
 			}
 		}
-		rt->u.dst.output = ip6_pkt_discard_out;
-		rt->u.dst.input = ip6_pkt_discard;
-		rt->u.dst.error = -ENETUNREACH;
+		rt->dst.output = ip6_pkt_discard_out;
+		rt->dst.input = ip6_pkt_discard;
+		rt->dst.error = -ENETUNREACH;
 		rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
 		goto install_route;
 	}
@@ -1244,7 +1241,7 @@
 				goto out;
 			if (dev) {
 				if (dev != grt->rt6i_dev) {
-					dst_release(&grt->u.dst);
+					dst_release(&grt->dst);
 					goto out;
 				}
 			} else {
@@ -1255,7 +1252,7 @@
 			}
 			if (!(grt->rt6i_flags&RTF_GATEWAY))
 				err = 0;
-			dst_release(&grt->u.dst);
+			dst_release(&grt->dst);
 
 			if (err)
 				goto out;
@@ -1294,18 +1291,18 @@
 					goto out;
 				}
 
-				rt->u.dst.metrics[type - 1] = nla_get_u32(nla);
+				rt->dst.metrics[type - 1] = nla_get_u32(nla);
 			}
 		}
 	}
 
-	if (dst_metric(&rt->u.dst, RTAX_HOPLIMIT) == 0)
-		rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1;
-	if (!dst_mtu(&rt->u.dst))
-		rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
-	if (!dst_metric(&rt->u.dst, RTAX_ADVMSS))
-		rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst));
-	rt->u.dst.dev = dev;
+	if (dst_metric(&rt->dst, RTAX_HOPLIMIT) == 0)
+		rt->dst.metrics[RTAX_HOPLIMIT-1] = -1;
+	if (!dst_mtu(&rt->dst))
+		rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
+	if (!dst_metric(&rt->dst, RTAX_ADVMSS))
+		rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst));
+	rt->dst.dev = dev;
 	rt->rt6i_idev = idev;
 	rt->rt6i_table = table;
 
@@ -1319,7 +1316,7 @@
 	if (idev)
 		in6_dev_put(idev);
 	if (rt)
-		dst_free(&rt->u.dst);
+		dst_free(&rt->dst);
 	return err;
 }
 
@@ -1336,7 +1333,7 @@
 	write_lock_bh(&table->tb6_lock);
 
 	err = fib6_del(rt, info);
-	dst_release(&rt->u.dst);
+	dst_release(&rt->dst);
 
 	write_unlock_bh(&table->tb6_lock);
 
@@ -1369,7 +1366,7 @@
 			 &cfg->fc_src, cfg->fc_src_len);
 
 	if (fn) {
-		for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) {
+		for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
 			if (cfg->fc_ifindex &&
 			    (rt->rt6i_dev == NULL ||
 			     rt->rt6i_dev->ifindex != cfg->fc_ifindex))
@@ -1379,7 +1376,7 @@
 				continue;
 			if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
 				continue;
-			dst_hold(&rt->u.dst);
+			dst_hold(&rt->dst);
 			read_unlock_bh(&table->tb6_lock);
 
 			return __ip6_del_rt(rt, &cfg->fc_nlinfo);
@@ -1421,7 +1418,7 @@
 	read_lock_bh(&table->tb6_lock);
 	fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
 restart:
-	for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) {
+	for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
 		/*
 		 * Current route is on-link; redirect is always invalid.
 		 *
@@ -1445,7 +1442,7 @@
 		rt = net->ipv6.ip6_null_entry;
 	BACKTRACK(net, &fl->fl6_src);
 out:
-	dst_hold(&rt->u.dst);
+	dst_hold(&rt->dst);
 
 	read_unlock_bh(&table->tb6_lock);
 
@@ -1513,10 +1510,10 @@
 	 * Look, redirects are sent only in response to data packets,
 	 * so that this nexthop apparently is reachable. --ANK
 	 */
-	dst_confirm(&rt->u.dst);
+	dst_confirm(&rt->dst);
 
 	/* Duplicate redirect: silently ignore. */
-	if (neigh == rt->u.dst.neighbour)
+	if (neigh == rt->dst.neighbour)
 		goto out;
 
 	nrt = ip6_rt_copy(rt);
@@ -1529,20 +1526,20 @@
 
 	ipv6_addr_copy(&nrt->rt6i_dst.addr, dest);
 	nrt->rt6i_dst.plen = 128;
-	nrt->u.dst.flags |= DST_HOST;
+	nrt->dst.flags |= DST_HOST;
 
 	ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key);
 	nrt->rt6i_nexthop = neigh_clone(neigh);
 	/* Reset pmtu, it may be better */
-	nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev);
-	nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dev_net(neigh->dev),
-							dst_mtu(&nrt->u.dst));
+	nrt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev);
+	nrt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dev_net(neigh->dev),
+							dst_mtu(&nrt->dst));
 
 	if (ip6_ins_rt(nrt))
 		goto out;
 
-	netevent.old = &rt->u.dst;
-	netevent.new = &nrt->u.dst;
+	netevent.old = &rt->dst;
+	netevent.new = &nrt->dst;
 	call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
 
 	if (rt->rt6i_flags&RTF_CACHE) {
@@ -1551,7 +1548,7 @@
 	}
 
 out:
-	dst_release(&rt->u.dst);
+	dst_release(&rt->dst);
 }
 
 /*
@@ -1570,7 +1567,7 @@
 	if (rt == NULL)
 		return;
 
-	if (pmtu >= dst_mtu(&rt->u.dst))
+	if (pmtu >= dst_mtu(&rt->dst))
 		goto out;
 
 	if (pmtu < IPV6_MIN_MTU) {
@@ -1588,7 +1585,7 @@
 	   They are sent only in response to data packets,
 	   so that this nexthop apparently is reachable. --ANK
 	 */
-	dst_confirm(&rt->u.dst);
+	dst_confirm(&rt->dst);
 
 	/* Host route. If it is static, it would be better
 	   not to override it, but add new one, so that
@@ -1596,10 +1593,10 @@
 	   would return automatically.
 	 */
 	if (rt->rt6i_flags & RTF_CACHE) {
-		rt->u.dst.metrics[RTAX_MTU-1] = pmtu;
+		rt->dst.metrics[RTAX_MTU-1] = pmtu;
 		if (allfrag)
-			rt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
-		dst_set_expires(&rt->u.dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
+			rt->dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
+		dst_set_expires(&rt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
 		rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;
 		goto out;
 	}
@@ -1615,9 +1612,9 @@
 		nrt = rt6_alloc_clone(rt, daddr);
 
 	if (nrt) {
-		nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
+		nrt->dst.metrics[RTAX_MTU-1] = pmtu;
 		if (allfrag)
-			nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
+			nrt->dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
 
 		/* According to RFC 1981, detecting PMTU increase shouldn't be
 		 * happened within 5 mins, the recommended timer is 10 mins.
@@ -1625,13 +1622,13 @@
 		 * which is 10 mins. After 10 mins the decreased pmtu is expired
 		 * and detecting PMTU increase will be automatically happened.
 		 */
-		dst_set_expires(&nrt->u.dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
+		dst_set_expires(&nrt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
 		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
 
 		ip6_ins_rt(nrt);
 	}
 out:
-	dst_release(&rt->u.dst);
+	dst_release(&rt->dst);
 }
 
 /*
@@ -1644,18 +1641,18 @@
 	struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops);
 
 	if (rt) {
-		rt->u.dst.input = ort->u.dst.input;
-		rt->u.dst.output = ort->u.dst.output;
+		rt->dst.input = ort->dst.input;
+		rt->dst.output = ort->dst.output;
 
-		memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
-		rt->u.dst.error = ort->u.dst.error;
-		rt->u.dst.dev = ort->u.dst.dev;
-		if (rt->u.dst.dev)
-			dev_hold(rt->u.dst.dev);
+		memcpy(rt->dst.metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32));
+		rt->dst.error = ort->dst.error;
+		rt->dst.dev = ort->dst.dev;
+		if (rt->dst.dev)
+			dev_hold(rt->dst.dev);
 		rt->rt6i_idev = ort->rt6i_idev;
 		if (rt->rt6i_idev)
 			in6_dev_hold(rt->rt6i_idev);
-		rt->u.dst.lastuse = jiffies;
+		rt->dst.lastuse = jiffies;
 		rt->rt6i_expires = 0;
 
 		ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway);
@@ -1689,14 +1686,14 @@
 	if (!fn)
 		goto out;
 
-	for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) {
+	for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
 		if (rt->rt6i_dev->ifindex != ifindex)
 			continue;
 		if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
 			continue;
 		if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
 			continue;
-		dst_hold(&rt->u.dst);
+		dst_hold(&rt->dst);
 		break;
 	}
 out:
@@ -1744,14 +1741,14 @@
 		return NULL;
 
 	write_lock_bh(&table->tb6_lock);
-	for (rt = table->tb6_root.leaf; rt; rt=rt->u.dst.rt6_next) {
+	for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) {
 		if (dev == rt->rt6i_dev &&
 		    ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
 		    ipv6_addr_equal(&rt->rt6i_gateway, addr))
 			break;
 	}
 	if (rt)
-		dst_hold(&rt->u.dst);
+		dst_hold(&rt->dst);
 	write_unlock_bh(&table->tb6_lock);
 	return rt;
 }
@@ -1790,9 +1787,9 @@
 
 restart:
 	read_lock_bh(&table->tb6_lock);
-	for (rt = table->tb6_root.leaf; rt; rt = rt->u.dst.rt6_next) {
+	for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
 		if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
-			dst_hold(&rt->u.dst);
+			dst_hold(&rt->dst);
 			read_unlock_bh(&table->tb6_lock);
 			ip6_del_rt(rt);
 			goto restart;
@@ -1930,15 +1927,15 @@
 	dev_hold(net->loopback_dev);
 	in6_dev_hold(idev);
 
-	rt->u.dst.flags = DST_HOST;
-	rt->u.dst.input = ip6_input;
-	rt->u.dst.output = ip6_output;
+	rt->dst.flags = DST_HOST;
+	rt->dst.input = ip6_input;
+	rt->dst.output = ip6_output;
 	rt->rt6i_dev = net->loopback_dev;
 	rt->rt6i_idev = idev;
-	rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
-	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst));
-	rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1;
-	rt->u.dst.obsolete = -1;
+	rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
+	rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst));
+	rt->dst.metrics[RTAX_HOPLIMIT-1] = -1;
+	rt->dst.obsolete = -1;
 
 	rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
 	if (anycast)
@@ -1947,7 +1944,7 @@
 		rt->rt6i_flags |= RTF_LOCAL;
 	neigh = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
 	if (IS_ERR(neigh)) {
-		dst_free(&rt->u.dst);
+		dst_free(&rt->dst);
 
 		/* We are casting this because that is the return
 		 * value type.  But an errno encoded pointer is the
@@ -1962,7 +1959,7 @@
 	rt->rt6i_dst.plen = 128;
 	rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
 
-	atomic_set(&rt->u.dst.__refcnt, 1);
+	atomic_set(&rt->dst.__refcnt, 1);
 
 	return rt;
 }
@@ -2033,12 +2030,12 @@
 	   PMTU discouvery.
 	 */
 	if (rt->rt6i_dev == arg->dev &&
-	    !dst_metric_locked(&rt->u.dst, RTAX_MTU) &&
-	    (dst_mtu(&rt->u.dst) >= arg->mtu ||
-	     (dst_mtu(&rt->u.dst) < arg->mtu &&
-	      dst_mtu(&rt->u.dst) == idev->cnf.mtu6))) {
-		rt->u.dst.metrics[RTAX_MTU-1] = arg->mtu;
-		rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, arg->mtu);
+	    !dst_metric_locked(&rt->dst, RTAX_MTU) &&
+	    (dst_mtu(&rt->dst) >= arg->mtu ||
+	     (dst_mtu(&rt->dst) < arg->mtu &&
+	      dst_mtu(&rt->dst) == idev->cnf.mtu6))) {
+		rt->dst.metrics[RTAX_MTU-1] = arg->mtu;
+		rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, arg->mtu);
 	}
 	return 0;
 }
@@ -2252,20 +2249,20 @@
 #endif
 			NLA_PUT_U32(skb, RTA_IIF, iif);
 	} else if (dst) {
-		struct inet6_dev *idev = ip6_dst_idev(&rt->u.dst);
+		struct inet6_dev *idev = ip6_dst_idev(&rt->dst);
 		struct in6_addr saddr_buf;
 		if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
 				       dst, 0, &saddr_buf) == 0)
 			NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
 	}
 
-	if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
+	if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0)
 		goto nla_put_failure;
 
-	if (rt->u.dst.neighbour)
-		NLA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key);
+	if (rt->dst.neighbour)
+		NLA_PUT(skb, RTA_GATEWAY, 16, &rt->dst.neighbour->primary_key);
 
-	if (rt->u.dst.dev)
+	if (rt->dst.dev)
 		NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex);
 
 	NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric);
@@ -2277,8 +2274,8 @@
 	else
 		expires = INT_MAX;
 
-	if (rtnl_put_cacheinfo(skb, &rt->u.dst, 0, 0, 0,
-			       expires, rt->u.dst.error) < 0)
+	if (rtnl_put_cacheinfo(skb, &rt->dst, 0, 0, 0,
+			       expires, rt->dst.error) < 0)
 		goto nla_put_failure;
 
 	return nlmsg_end(skb, nlh);
@@ -2364,7 +2361,7 @@
 	skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
 
 	rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
 			    RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
@@ -2416,12 +2413,12 @@
 	struct net *net = dev_net(dev);
 
 	if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
-		net->ipv6.ip6_null_entry->u.dst.dev = dev;
+		net->ipv6.ip6_null_entry->dst.dev = dev;
 		net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
-		net->ipv6.ip6_prohibit_entry->u.dst.dev = dev;
+		net->ipv6.ip6_prohibit_entry->dst.dev = dev;
 		net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
-		net->ipv6.ip6_blk_hole_entry->u.dst.dev = dev;
+		net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
 		net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
 #endif
 	}
@@ -2464,8 +2461,8 @@
 		seq_puts(m, "00000000000000000000000000000000");
 	}
 	seq_printf(m, " %08x %08x %08x %08x %8s\n",
-		   rt->rt6i_metric, atomic_read(&rt->u.dst.__refcnt),
-		   rt->u.dst.__use, rt->rt6i_flags,
+		   rt->rt6i_metric, atomic_read(&rt->dst.__refcnt),
+		   rt->dst.__use, rt->rt6i_flags,
 		   rt->rt6i_dev ? rt->rt6i_dev->name : "");
 	return 0;
 }
@@ -2646,9 +2643,9 @@
 					   GFP_KERNEL);
 	if (!net->ipv6.ip6_null_entry)
 		goto out_ip6_dst_ops;
-	net->ipv6.ip6_null_entry->u.dst.path =
+	net->ipv6.ip6_null_entry->dst.path =
 		(struct dst_entry *)net->ipv6.ip6_null_entry;
-	net->ipv6.ip6_null_entry->u.dst.ops = &net->ipv6.ip6_dst_ops;
+	net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
 
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 	net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
@@ -2656,18 +2653,18 @@
 					       GFP_KERNEL);
 	if (!net->ipv6.ip6_prohibit_entry)
 		goto out_ip6_null_entry;
-	net->ipv6.ip6_prohibit_entry->u.dst.path =
+	net->ipv6.ip6_prohibit_entry->dst.path =
 		(struct dst_entry *)net->ipv6.ip6_prohibit_entry;
-	net->ipv6.ip6_prohibit_entry->u.dst.ops = &net->ipv6.ip6_dst_ops;
+	net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
 
 	net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
 					       sizeof(*net->ipv6.ip6_blk_hole_entry),
 					       GFP_KERNEL);
 	if (!net->ipv6.ip6_blk_hole_entry)
 		goto out_ip6_prohibit_entry;
-	net->ipv6.ip6_blk_hole_entry->u.dst.path =
+	net->ipv6.ip6_blk_hole_entry->dst.path =
 		(struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
-	net->ipv6.ip6_blk_hole_entry->u.dst.ops = &net->ipv6.ip6_dst_ops;
+	net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
 #endif
 
 	net->ipv6.sysctl.flush_delay = 0;
@@ -2742,12 +2739,12 @@
 	/* Registering of the loopback is done before this portion of code,
 	 * the loopback reference in rt6_info will not be taken, do it
 	 * manually for init_net */
-	init_net.ipv6.ip6_null_entry->u.dst.dev = init_net.loopback_dev;
+	init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
 	init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
   #ifdef CONFIG_IPV6_MULTIPLE_TABLES
-	init_net.ipv6.ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev;
+	init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
 	init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
-	init_net.ipv6.ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev;
+	init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
 	init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
   #endif
 	ret = fib6_init();
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index e51e650..4699cd3 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -249,8 +249,6 @@
 	return NULL;
 }
 
-static DEFINE_SPINLOCK(ipip6_prl_lock);
-
 #define for_each_prl_rcu(start)			\
 	for (prl = rcu_dereference(start);	\
 	     prl;				\
@@ -340,7 +338,7 @@
 	if (a->addr == htonl(INADDR_ANY))
 		return -EINVAL;
 
-	spin_lock(&ipip6_prl_lock);
+	ASSERT_RTNL();
 
 	for (p = t->prl; p; p = p->next) {
 		if (p->addr == a->addr) {
@@ -370,7 +368,6 @@
 	t->prl_count++;
 	rcu_assign_pointer(t->prl, p);
 out:
-	spin_unlock(&ipip6_prl_lock);
 	return err;
 }
 
@@ -397,7 +394,7 @@
 	struct ip_tunnel_prl_entry *x, **p;
 	int err = 0;
 
-	spin_lock(&ipip6_prl_lock);
+	ASSERT_RTNL();
 
 	if (a && a->addr != htonl(INADDR_ANY)) {
 		for (p = &t->prl; *p; p = &(*p)->next) {
@@ -419,7 +416,6 @@
 		}
 	}
 out:
-	spin_unlock(&ipip6_prl_lock);
 	return err;
 }
 
@@ -716,7 +712,7 @@
 		stats->tx_carrier_errors++;
 		goto tx_error_icmp;
 	}
-	tdev = rt->u.dst.dev;
+	tdev = rt->dst.dev;
 
 	if (tdev == dev) {
 		ip_rt_put(rt);
@@ -725,7 +721,7 @@
 	}
 
 	if (df) {
-		mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
+		mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
 
 		if (mtu < 68) {
 			stats->collisions++;
@@ -784,7 +780,7 @@
 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 	IPCB(skb)->flags = 0;
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	/*
 	 *	Push down and install the IPIP header.
@@ -833,7 +829,7 @@
 				    .proto = IPPROTO_IPV6 };
 		struct rtable *rt;
 		if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
-			tdev = rt->u.dst.dev;
+			tdev = rt->dst.dev;
 			ip_rt_put(rt);
 		}
 		dev->flags |= IFF_POINTOPOINT;
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 34d1f06..09fd34f 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -27,28 +27,17 @@
 #define COOKIEBITS 24	/* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
 
-/*
- * This table has to be sorted and terminated with (__u16)-1.
- * XXX generate a better table.
- * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
- *
- * Taken directly from ipv4 implementation.
- * Should this list be modified for ipv6 use or is it close enough?
- * rfc 2460 8.3 suggests mss values 20 bytes less than ipv4 counterpart
- */
+/* Table must be sorted. */
 static __u16 const msstab[] = {
-	64 - 1,
-	256 - 1,
-	512 - 1,
-	536 - 1,
-	1024 - 1,
-	1440 - 1,
-	1460 - 1,
-	4312 - 1,
-	(__u16)-1
+	64,
+	512,
+	536,
+	1280 - 60,
+	1480 - 60,
+	1500 - 60,
+	4460 - 60,
+	9000 - 60,
 };
-/* The number doesn't include the -1 terminator */
-#define NUM_MSS (ARRAY_SIZE(msstab) - 1)
 
 /*
  * This (misnamed) value is the age of syncookie which is permitted.
@@ -134,9 +123,11 @@
 
 	tcp_synq_overflow(sk);
 
-	for (mssind = 0; mss > msstab[mssind + 1]; mssind++)
-		;
-	*mssp = msstab[mssind] + 1;
+	for (mssind = ARRAY_SIZE(msstab) - 1; mssind ; mssind--)
+		if (mss >= msstab[mssind])
+			break;
+
+	*mssp = msstab[mssind];
 
 	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT);
 
@@ -154,7 +145,7 @@
 					    th->source, th->dest, seq,
 					    jiffies / (HZ * 60), COUNTER_TRIES);
 
-	return mssind < NUM_MSS ? msstab[mssind] + 1 : 0;
+	return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0;
 }
 
 struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
@@ -173,8 +164,9 @@
 	int mss;
 	struct dst_entry *dst;
 	__u8 rcv_wscale;
+	bool ecn_ok;
 
-	if (!sysctl_tcp_syncookies || !th->ack)
+	if (!sysctl_tcp_syncookies || !th->ack || th->rst)
 		goto out;
 
 	if (tcp_synq_no_recent_overflow(sk) ||
@@ -189,8 +181,8 @@
 	memset(&tcp_opt, 0, sizeof(tcp_opt));
 	tcp_parse_options(skb, &tcp_opt, &hash_location, 0);
 
-	if (tcp_opt.saw_tstamp)
-		cookie_check_timestamp(&tcp_opt);
+	if (!cookie_check_timestamp(&tcp_opt, &ecn_ok))
+		goto out;
 
 	ret = NULL;
 	req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
@@ -224,9 +216,8 @@
 
 	req->expires = 0UL;
 	req->retrans = 0;
-	ireq->ecn_ok		= 0;
+	ireq->ecn_ok		= ecn_ok;
 	ireq->snd_wscale	= tcp_opt.snd_wscale;
-	ireq->rcv_wscale	= tcp_opt.rcv_wscale;
 	ireq->sack_ok		= tcp_opt.sack_ok;
 	ireq->wscale_ok		= tcp_opt.wscale_ok;
 	ireq->tstamp_ok		= tcp_opt.saw_tstamp;
@@ -240,17 +231,12 @@
 	 * me if there is a preferred way.
 	 */
 	{
-		struct in6_addr *final_p = NULL, final;
+		struct in6_addr *final_p, final;
 		struct flowi fl;
 		memset(&fl, 0, sizeof(fl));
 		fl.proto = IPPROTO_TCP;
 		ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
-		if (np->opt && np->opt->srcrt) {
-			struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
-			ipv6_addr_copy(&final, &fl.fl6_dst);
-			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-			final_p = &final;
-		}
+		final_p = fl6_update_dst(&fl, np->opt, &final);
 		ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
 		fl.oif = sk->sk_bound_dev_if;
 		fl.mark = sk->sk_mark;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 2b7c3a1..fe6d404 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -129,7 +129,7 @@
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct tcp_sock *tp = tcp_sk(sk);
-	struct in6_addr *saddr = NULL, *final_p = NULL, final;
+	struct in6_addr *saddr = NULL, *final_p, final;
 	struct flowi fl;
 	struct dst_entry *dst;
 	int addr_type;
@@ -250,12 +250,7 @@
 	fl.fl_ip_dport = usin->sin6_port;
 	fl.fl_ip_sport = inet->inet_sport;
 
-	if (np->opt && np->opt->srcrt) {
-		struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
-		ipv6_addr_copy(&final, &fl.fl6_dst);
-		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-		final_p = &final;
-	}
+	final_p = fl6_update_dst(&fl, np->opt, &final);
 
 	security_sk_classify_flow(sk, &fl);
 
@@ -477,7 +472,7 @@
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct sk_buff * skb;
 	struct ipv6_txoptions *opt = NULL;
-	struct in6_addr * final_p = NULL, final;
+	struct in6_addr * final_p, final;
 	struct flowi fl;
 	struct dst_entry *dst;
 	int err = -1;
@@ -494,12 +489,7 @@
 	security_req_classify_flow(req, &fl);
 
 	opt = np->opt;
-	if (opt && opt->srcrt) {
-		struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
-		ipv6_addr_copy(&final, &fl.fl6_dst);
-		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-		final_p = &final;
-	}
+	final_p = fl6_update_dst(&fl, opt, &final);
 
 	err = ip6_dst_lookup(sk, &dst, &fl);
 	if (err)
@@ -1167,7 +1157,7 @@
 	}
 
 #ifdef CONFIG_SYN_COOKIES
-	if (!th->rst && !th->syn && th->ack)
+	if (!th->syn)
 		sk = cookie_v6_check(sk, skb);
 #endif
 	return sk;
@@ -1279,13 +1269,10 @@
 	treq = inet6_rsk(req);
 	ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
 	ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
-	if (!want_cookie)
+	if (!want_cookie || tmp_opt.tstamp_ok)
 		TCP_ECN_create_request(req, tcp_hdr(skb));
 
-	if (want_cookie) {
-		isn = cookie_v6_init_sequence(sk, skb, &req->mss);
-		req->cookie_ts = tmp_opt.tstamp_ok;
-	} else if (!isn) {
+	if (!isn) {
 		if (ipv6_opt_accepted(sk, skb) ||
 		    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
 		    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
@@ -1298,8 +1285,12 @@
 		if (!sk->sk_bound_dev_if &&
 		    ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
 			treq->iif = inet6_iif(skb);
-
-		isn = tcp_v6_init_sequence(skb);
+		if (!want_cookie) {
+			isn = tcp_v6_init_sequence(skb);
+		} else {
+			isn = cookie_v6_init_sequence(sk, skb, &req->mss);
+			req->cookie_ts = tmp_opt.tstamp_ok;
+		}
 	}
 	tcp_rsk(req)->snt_isn = isn;
 
@@ -1392,18 +1383,13 @@
 		goto out_overflow;
 
 	if (dst == NULL) {
-		struct in6_addr *final_p = NULL, final;
+		struct in6_addr *final_p, final;
 		struct flowi fl;
 
 		memset(&fl, 0, sizeof(fl));
 		fl.proto = IPPROTO_TCP;
 		ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
-		if (opt && opt->srcrt) {
-			struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
-			ipv6_addr_copy(&final, &fl.fl6_dst);
-			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-			final_p = &final;
-		}
+		final_p = fl6_update_dst(&fl, opt, &final);
 		ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
 		fl.oif = sk->sk_bound_dev_if;
 		fl.mark = sk->sk_mark;
@@ -2156,6 +2142,8 @@
 	.setsockopt		= tcp_setsockopt,
 	.getsockopt		= tcp_getsockopt,
 	.recvmsg		= tcp_recvmsg,
+	.sendmsg		= tcp_sendmsg,
+	.sendpage		= tcp_sendpage,
 	.backlog_rcv		= tcp_v6_do_rcv,
 	.hash			= tcp_v6_hash,
 	.unhash			= inet_unhash,
@@ -2174,6 +2162,7 @@
 	.twsk_prot		= &tcp6_timewait_sock_ops,
 	.rsk_prot		= &tcp6_request_sock_ops,
 	.h.hashinfo		= &tcp_hashinfo,
+	.no_autobind		= true,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt	= compat_tcp_setsockopt,
 	.compat_getsockopt	= compat_tcp_getsockopt,
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 87be586..1dd1aff 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -927,7 +927,7 @@
 	struct inet_sock *inet = inet_sk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;
-	struct in6_addr *daddr, *final_p = NULL, final;
+	struct in6_addr *daddr, *final_p, final;
 	struct ipv6_txoptions *opt = NULL;
 	struct ip6_flowlabel *flowlabel = NULL;
 	struct flowi fl;
@@ -1097,14 +1097,9 @@
 		ipv6_addr_copy(&fl.fl6_src, &np->saddr);
 	fl.fl_ip_sport = inet->inet_sport;
 
-	/* merge ip6_build_xmit from ip6_output */
-	if (opt && opt->srcrt) {
-		struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
-		ipv6_addr_copy(&final, &fl.fl6_dst);
-		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-		final_p = &final;
+	final_p = fl6_update_dst(&fl, opt, &final);
+	if (final_p)
 		connected = 0;
-	}
 
 	if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) {
 		fl.oif = np->mcast_oif;
diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
index 6a1a202..800bc53 100644
--- a/net/irda/irnet/irnet_ppp.c
+++ b/net/irda/irnet/irnet_ppp.c
@@ -527,7 +527,7 @@
 dev_irnet_close(struct inode *	inode,
 		struct file *	file)
 {
-  irnet_socket *	ap = (struct irnet_socket *) file->private_data;
+  irnet_socket *	ap = file->private_data;
 
   DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n",
 	 file, ap);
@@ -564,7 +564,7 @@
 		size_t		count,
 		loff_t *	ppos)
 {
-  irnet_socket *	ap = (struct irnet_socket *) file->private_data;
+  irnet_socket *	ap = file->private_data;
 
   DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%Zd)\n",
 	file, ap, count);
@@ -588,7 +588,7 @@
 	       size_t		count,
 	       loff_t *		ppos)
 {
-  irnet_socket *	ap = (struct irnet_socket *) file->private_data;
+  irnet_socket *	ap = file->private_data;
 
   DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%Zd)\n",
 	file, ap, count);
@@ -609,7 +609,7 @@
 dev_irnet_poll(struct file *	file,
 	       poll_table *	wait)
 {
-  irnet_socket *	ap = (struct irnet_socket *) file->private_data;
+  irnet_socket *	ap = file->private_data;
   unsigned int		mask;
 
   DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n",
@@ -638,7 +638,7 @@
 		unsigned int	cmd,
 		unsigned long	arg)
 {
-  irnet_socket *	ap = (struct irnet_socket *) file->private_data;
+  irnet_socket *	ap = file->private_data;
   int			err;
   int			val;
   void __user *argp = (void __user *)arg;
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index 47db1d8..285761e 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -1853,23 +1853,23 @@
 		   self->remote_credit);
 	seq_printf(seq, "send credit: %d\n",
 		   self->send_credit);
-	seq_printf(seq, "  tx packets: %ld, ",
+	seq_printf(seq, "  tx packets: %lu, ",
 		   self->stats.tx_packets);
-	seq_printf(seq, "rx packets: %ld, ",
+	seq_printf(seq, "rx packets: %lu, ",
 		   self->stats.rx_packets);
-	seq_printf(seq, "tx_queue len: %d ",
+	seq_printf(seq, "tx_queue len: %u ",
 		   skb_queue_len(&self->tx_queue));
-	seq_printf(seq, "rx_queue len: %d\n",
+	seq_printf(seq, "rx_queue len: %u\n",
 		   skb_queue_len(&self->rx_queue));
 	seq_printf(seq, "  tx_sdu_busy: %s, ",
 		   self->tx_sdu_busy? "TRUE":"FALSE");
 	seq_printf(seq, "rx_sdu_busy: %s\n",
 		   self->rx_sdu_busy? "TRUE":"FALSE");
-	seq_printf(seq, "  max_seg_size: %d, ",
+	seq_printf(seq, "  max_seg_size: %u, ",
 		   self->max_seg_size);
-	seq_printf(seq, "tx_max_sdu_size: %d, ",
+	seq_printf(seq, "tx_max_sdu_size: %u, ",
 		   self->tx_max_sdu_size);
-	seq_printf(seq, "rx_max_sdu_size: %d\n",
+	seq_printf(seq, "rx_max_sdu_size: %u\n",
 		   self->rx_max_sdu_size);
 
 	seq_printf(seq, "  Used by (%s)\n\n",
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index f28ad2cc..499c045 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -1463,7 +1463,7 @@
 	u32 res3;
 	u8  ippollfg;
 	u8  res4[3];
-} __attribute__ ((packed));
+} __packed;
 
 static void iucv_path_pending(struct iucv_irq_data *data)
 {
@@ -1524,7 +1524,7 @@
 	u32 res3;
 	u8  ippollfg;
 	u8  res4[3];
-} __attribute__ ((packed));
+} __packed;
 
 static void iucv_path_complete(struct iucv_irq_data *data)
 {
@@ -1554,7 +1554,7 @@
 	u32 res4;
 	u8  ippollfg;
 	u8  res5[3];
-} __attribute__ ((packed));
+} __packed;
 
 static void iucv_path_severed(struct iucv_irq_data *data)
 {
@@ -1590,7 +1590,7 @@
 	u32 res4;
 	u8  ippollfg;
 	u8  res5[3];
-} __attribute__ ((packed));
+} __packed;
 
 static void iucv_path_quiesced(struct iucv_irq_data *data)
 {
@@ -1618,7 +1618,7 @@
 	u32 res4;
 	u8  ippollfg;
 	u8  res5[3];
-} __attribute__ ((packed));
+} __packed;
 
 static void iucv_path_resumed(struct iucv_irq_data *data)
 {
@@ -1649,7 +1649,7 @@
 	u32 ipbfln2f;
 	u8  ippollfg;
 	u8  res2[3];
-} __attribute__ ((packed));
+} __packed;
 
 static void iucv_message_complete(struct iucv_irq_data *data)
 {
@@ -1694,7 +1694,7 @@
 	u32 ipbfln2f;
 	u8  ippollfg;
 	u8  res2[3];
-} __attribute__ ((packed));
+} __packed;
 
 static void iucv_message_pending(struct iucv_irq_data *data)
 {
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index 0852512..226a0ae 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -348,7 +348,7 @@
 	sk->sk_state = TCP_ESTABLISHED;
 	inet->inet_id = jiffies;
 
-	sk_dst_set(sk, &rt->u.dst);
+	sk_dst_set(sk, &rt->dst);
 
 	write_lock_bh(&l2tp_ip_lock);
 	hlist_del_init(&sk->sk_bind_node);
@@ -496,9 +496,9 @@
 			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0))
 				goto no_route;
 		}
-		sk_setup_caps(sk, &rt->u.dst);
+		sk_setup_caps(sk, &rt->dst);
 	}
-	skb_dst_set(skb, dst_clone(&rt->u.dst));
+	skb_dst_set(skb, dst_clone(&rt->dst));
 
 	/* Queue the packet to IP for output */
 	rc = ip_queue_xmit(skb);
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 8a91f6c..4d6f865 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -33,6 +33,13 @@
 	---help---
 	  This option enables the 'minstrel' TX rate control algorithm
 
+config MAC80211_RC_MINSTREL_HT
+	bool "Minstrel 802.11n support" if EMBEDDED
+	depends on MAC80211_RC_MINSTREL
+	default y
+	---help---
+	  This option enables the 'minstrel_ht' TX rate control algorithm
+
 choice
 	prompt "Default rate control algorithm"
 	depends on MAC80211_HAS_RC
@@ -62,6 +69,7 @@
 
 config MAC80211_RC_DEFAULT
 	string
+	default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT
 	default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL
 	default "pid" if MAC80211_RC_DEFAULT_PID
 	default ""
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 84b48ba..fdb54e6 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -51,7 +51,11 @@
 rc80211_minstrel-y := rc80211_minstrel.o
 rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o
 
+rc80211_minstrel_ht-y := rc80211_minstrel_ht.o
+rc80211_minstrel_ht-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_ht_debugfs.o
+
 mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y)
 mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y)
+mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y)
 
 ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index 6bb9a9a..965b272 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -6,39 +6,70 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
- * Copyright 2007-2008, Intel Corporation
+ * Copyright 2007-2010, 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.
  */
 
+/**
+ * DOC: RX A-MPDU aggregation
+ *
+ * Aggregation on the RX side requires only implementing the
+ * @ampdu_action callback that is invoked to start/stop any
+ * block-ack sessions for RX aggregation.
+ *
+ * When RX aggregation is started by the peer, the driver is
+ * notified via @ampdu_action function, with the
+ * %IEEE80211_AMPDU_RX_START action, and may reject the request
+ * in which case a negative response is sent to the peer, if it
+ * accepts it a positive response is sent.
+ *
+ * While the session is active, the device/driver are required
+ * to de-aggregate frames and pass them up one by one to mac80211,
+ * which will handle the reorder buffer.
+ *
+ * When the aggregation session is stopped again by the peer or
+ * ourselves, the driver's @ampdu_action function will be called
+ * with the action %IEEE80211_AMPDU_RX_STOP. In this case, the
+ * call must not fail.
+ */
+
 #include <linux/ieee80211.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
-static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
-					    u16 initiator, u16 reason,
-					    bool from_timer)
+static void ieee80211_free_tid_rx(struct rcu_head *h)
+{
+	struct tid_ampdu_rx *tid_rx =
+		container_of(h, struct tid_ampdu_rx, rcu_head);
+	int i;
+
+	for (i = 0; i < tid_rx->buf_size; i++)
+		dev_kfree_skb(tid_rx->reorder_buf[i]);
+	kfree(tid_rx->reorder_buf);
+	kfree(tid_rx->reorder_time);
+	kfree(tid_rx);
+}
+
+void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+				     u16 initiator, u16 reason)
 {
 	struct ieee80211_local *local = sta->local;
 	struct tid_ampdu_rx *tid_rx;
-	int i;
 
-	spin_lock_bh(&sta->lock);
-
-	/* check if TID is in operational state */
-	if (!sta->ampdu_mlme.tid_active_rx[tid]) {
-		spin_unlock_bh(&sta->lock);
-		return;
-	}
-
-	sta->ampdu_mlme.tid_active_rx[tid] = false;
+	lockdep_assert_held(&sta->ampdu_mlme.mtx);
 
 	tid_rx = sta->ampdu_mlme.tid_rx[tid];
 
+	if (!tid_rx)
+		return;
+
+	rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], NULL);
+
 #ifdef CONFIG_MAC80211_HT_DEBUG
 	printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
 	       sta->sta.addr, tid);
@@ -54,32 +85,17 @@
 		ieee80211_send_delba(sta->sdata, sta->sta.addr,
 				     tid, 0, reason);
 
-	/* free the reordering buffer */
-	for (i = 0; i < tid_rx->buf_size; i++) {
-		if (tid_rx->reorder_buf[i]) {
-			/* release the reordered frames */
-			dev_kfree_skb(tid_rx->reorder_buf[i]);
-			tid_rx->stored_mpdu_num--;
-			tid_rx->reorder_buf[i] = NULL;
-		}
-	}
+	del_timer_sync(&tid_rx->session_timer);
 
-	/* free resources */
-	kfree(tid_rx->reorder_buf);
-	kfree(tid_rx->reorder_time);
-	sta->ampdu_mlme.tid_rx[tid] = NULL;
-
-	spin_unlock_bh(&sta->lock);
-
-	if (!from_timer)
-		del_timer_sync(&tid_rx->session_timer);
-	kfree(tid_rx);
+	call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
 }
 
 void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 				    u16 initiator, u16 reason)
 {
-	___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, false);
+	mutex_lock(&sta->ampdu_mlme.mtx);
+	___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason);
+	mutex_unlock(&sta->ampdu_mlme.mtx);
 }
 
 /*
@@ -100,8 +116,8 @@
 #ifdef CONFIG_MAC80211_HT_DEBUG
 	printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
 #endif
-	___ieee80211_stop_rx_ba_session(sta, *ptid, WLAN_BACK_RECIPIENT,
-					WLAN_REASON_QSTA_TIMEOUT, true);
+	set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired);
+	ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
 }
 
 static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
@@ -212,9 +228,9 @@
 
 
 	/* examine state machine */
-	spin_lock_bh(&sta->lock);
+	mutex_lock(&sta->ampdu_mlme.mtx);
 
-	if (sta->ampdu_mlme.tid_active_rx[tid]) {
+	if (sta->ampdu_mlme.tid_rx[tid]) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		if (net_ratelimit())
 			printk(KERN_DEBUG "unexpected AddBA Req from "
@@ -225,9 +241,8 @@
 	}
 
 	/* prepare A-MPDU MLME for Rx aggregation */
-	sta->ampdu_mlme.tid_rx[tid] =
-			kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
-	if (!sta->ampdu_mlme.tid_rx[tid]) {
+	tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
+	if (!tid_agg_rx) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		if (net_ratelimit())
 			printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
@@ -235,14 +250,11 @@
 #endif
 		goto end;
 	}
-	/* rx timer */
-	sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
-				sta_rx_agg_session_timer_expired;
-	sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
-				(unsigned long)&sta->timer_to_tid[tid];
-	init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
 
-	tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
+	/* rx timer */
+	tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
+	tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
+	init_timer(&tid_agg_rx->session_timer);
 
 	/* prepare reordering buffer */
 	tid_agg_rx->reorder_buf =
@@ -257,8 +269,7 @@
 #endif
 		kfree(tid_agg_rx->reorder_buf);
 		kfree(tid_agg_rx->reorder_time);
-		kfree(sta->ampdu_mlme.tid_rx[tid]);
-		sta->ampdu_mlme.tid_rx[tid] = NULL;
+		kfree(tid_agg_rx);
 		goto end;
 	}
 
@@ -270,13 +281,12 @@
 
 	if (ret) {
 		kfree(tid_agg_rx->reorder_buf);
+		kfree(tid_agg_rx->reorder_time);
 		kfree(tid_agg_rx);
-		sta->ampdu_mlme.tid_rx[tid] = NULL;
 		goto end;
 	}
 
-	/* change state and send addba resp */
-	sta->ampdu_mlme.tid_active_rx[tid] = true;
+	/* update data */
 	tid_agg_rx->dialog_token = dialog_token;
 	tid_agg_rx->ssn = start_seq_num;
 	tid_agg_rx->head_seq_num = start_seq_num;
@@ -284,8 +294,15 @@
 	tid_agg_rx->timeout = timeout;
 	tid_agg_rx->stored_mpdu_num = 0;
 	status = WLAN_STATUS_SUCCESS;
+
+	/* activate it for RX */
+	rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
+
+	if (timeout)
+		mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
+
 end:
-	spin_unlock_bh(&sta->lock);
+	mutex_unlock(&sta->ampdu_mlme.mtx);
 
 end_no_lock:
 	ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 98258b7..c893f23 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -6,7 +6,7 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
- * Copyright 2007-2009, Intel Corporation
+ * Copyright 2007-2010, 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
@@ -21,28 +21,39 @@
 #include "wme.h"
 
 /**
- * DOC: TX aggregation
+ * DOC: TX A-MPDU aggregation
  *
  * Aggregation on the TX side requires setting the hardware flag
- * %IEEE80211_HW_AMPDU_AGGREGATION as well as, if present, the @ampdu_queues
- * hardware parameter to the number of hardware AMPDU queues. If there are no
- * hardware queues then the driver will (currently) have to do all frame
- * buffering.
+ * %IEEE80211_HW_AMPDU_AGGREGATION. The driver will then be handed
+ * packets with a flag indicating A-MPDU aggregation. The driver
+ * or device is responsible for actually aggregating the frames,
+ * as well as deciding how many and which to aggregate.
  *
- * When TX aggregation is started by some subsystem (usually the rate control
- * algorithm would be appropriate) by calling the
- * ieee80211_start_tx_ba_session() function, the driver will be notified via
- * its @ampdu_action function, with the %IEEE80211_AMPDU_TX_START action.
+ * When TX aggregation is started by some subsystem (usually the rate
+ * control algorithm would be appropriate) by calling the
+ * ieee80211_start_tx_ba_session() function, the driver will be
+ * notified via its @ampdu_action function, with the
+ * %IEEE80211_AMPDU_TX_START action.
  *
  * In response to that, the driver is later required to call the
- * ieee80211_start_tx_ba_cb() (or ieee80211_start_tx_ba_cb_irqsafe())
- * function, which will start the aggregation session.
+ * ieee80211_start_tx_ba_cb_irqsafe() function, which will really
+ * start the aggregation session after the peer has also responded.
+ * If the peer responds negatively, the session will be stopped
+ * again right away. Note that it is possible for the aggregation
+ * session to be stopped before the driver has indicated that it
+ * is done setting it up, in which case it must not indicate the
+ * setup completion.
  *
- * Similarly, when the aggregation session is stopped by
- * ieee80211_stop_tx_ba_session(), the driver's @ampdu_action function will
- * be called with the action %IEEE80211_AMPDU_TX_STOP. In this case, the
- * call must not fail, and the driver must later call ieee80211_stop_tx_ba_cb()
- * (or ieee80211_stop_tx_ba_cb_irqsafe()).
+ * Also note that, since we also need to wait for a response from
+ * the peer, the driver is notified of the completion of the
+ * handshake by the %IEEE80211_AMPDU_TX_OPERATIONAL action to the
+ * @ampdu_action callback.
+ *
+ * Similarly, when the aggregation session is stopped by the peer
+ * or something calling ieee80211_stop_tx_ba_session(), the driver's
+ * @ampdu_action function will be called with the action
+ * %IEEE80211_AMPDU_TX_STOP. In this case, the call must not fail,
+ * and the driver must later call ieee80211_stop_tx_ba_cb_irqsafe().
  */
 
 static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
@@ -125,25 +136,53 @@
 	ieee80211_tx_skb(sdata, skb);
 }
 
+static void kfree_tid_tx(struct rcu_head *rcu_head)
+{
+	struct tid_ampdu_tx *tid_tx =
+	    container_of(rcu_head, struct tid_ampdu_tx, rcu_head);
+
+	kfree(tid_tx);
+}
+
 int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 				    enum ieee80211_back_parties initiator)
 {
 	struct ieee80211_local *local = sta->local;
+	struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
 	int ret;
-	u8 *state;
+
+	lockdep_assert_held(&sta->ampdu_mlme.mtx);
+
+	if (!tid_tx)
+		return -ENOENT;
+
+	spin_lock_bh(&sta->lock);
+
+	if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
+		/* not even started yet! */
+		rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+		spin_unlock_bh(&sta->lock);
+		call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
+		return 0;
+	}
+
+	spin_unlock_bh(&sta->lock);
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
 	printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
 	       sta->sta.addr, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
 
-	if (*state == HT_AGG_STATE_OPERATIONAL)
-		sta->ampdu_mlme.addba_req_num[tid] = 0;
+	/*
+	 * After this packets are no longer handed right through
+	 * to the driver but are put onto tid_tx->pending instead,
+	 * with locking to ensure proper access.
+	 */
+	clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
 
-	*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
-		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+	tid_tx->stop_initiator = initiator;
 
 	ret = drv_ampdu_action(local, sta->sdata,
 			       IEEE80211_AMPDU_TX_STOP,
@@ -174,16 +213,14 @@
 	u16 tid = *(u8 *)data;
 	struct sta_info *sta = container_of((void *)data,
 		struct sta_info, timer_to_tid[tid]);
-	u8 *state;
-
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	struct tid_ampdu_tx *tid_tx;
 
 	/* check if the TID waits for addBA response */
-	spin_lock_bh(&sta->lock);
-	if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK |
-		       HT_AGG_STATE_REQ_STOP_BA_MSK)) !=
-						HT_ADDBA_REQUESTED_MSK) {
-		spin_unlock_bh(&sta->lock);
+	rcu_read_lock();
+	tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
+	if (!tid_tx ||
+	    test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
+		rcu_read_unlock();
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		printk(KERN_DEBUG "timer expired on tid %d but we are not "
 				"(or no longer) expecting addBA response there\n",
@@ -196,8 +233,8 @@
 	printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
 #endif
 
-	___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
-	spin_unlock_bh(&sta->lock);
+	ieee80211_stop_tx_ba_session(&sta->sta, tid);
+	rcu_read_unlock();
 }
 
 static inline int ieee80211_ac_from_tid(int tid)
@@ -205,14 +242,112 @@
 	return ieee802_1d_to_ac[tid & 7];
 }
 
+/*
+ * When multiple aggregation sessions on multiple stations
+ * are being created/destroyed simultaneously, we need to
+ * refcount the global queue stop caused by that in order
+ * to not get into a situation where one of the aggregation
+ * setup or teardown re-enables queues before the other is
+ * ready to handle that.
+ *
+ * These two functions take care of this issue by keeping
+ * a global "agg_queue_stop" refcount.
+ */
+static void __acquires(agg_queue)
+ieee80211_stop_queue_agg(struct ieee80211_local *local, int tid)
+{
+	int queue = ieee80211_ac_from_tid(tid);
+
+	if (atomic_inc_return(&local->agg_queue_stop[queue]) == 1)
+		ieee80211_stop_queue_by_reason(
+			&local->hw, queue,
+			IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+	__acquire(agg_queue);
+}
+
+static void __releases(agg_queue)
+ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
+{
+	int queue = ieee80211_ac_from_tid(tid);
+
+	if (atomic_dec_return(&local->agg_queue_stop[queue]) == 0)
+		ieee80211_wake_queue_by_reason(
+			&local->hw, queue,
+			IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+	__release(agg_queue);
+}
+
+void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
+{
+	struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
+	struct ieee80211_local *local = sta->local;
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	u16 start_seq_num;
+	int ret;
+
+	lockdep_assert_held(&sta->ampdu_mlme.mtx);
+
+	/*
+	 * While we're asking the driver about the aggregation,
+	 * stop the AC queue so that we don't have to worry
+	 * about frames that came in while we were doing that,
+	 * which would require us to put them to the AC pending
+	 * afterwards which just makes the code more complex.
+	 */
+	ieee80211_stop_queue_agg(local, tid);
+
+	clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
+
+	/*
+	 * make sure no packets are being processed to get
+	 * valid starting sequence number
+	 */
+	synchronize_net();
+
+	start_seq_num = sta->tid_seq[tid] >> 4;
+
+	ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
+			       &sta->sta, tid, &start_seq_num);
+	if (ret) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "BA request denied - HW unavailable for"
+					" tid %d\n", tid);
+#endif
+		spin_lock_bh(&sta->lock);
+		rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+		spin_unlock_bh(&sta->lock);
+
+		ieee80211_wake_queue_agg(local, tid);
+		call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
+		return;
+	}
+
+	/* we can take packets again now */
+	ieee80211_wake_queue_agg(local, tid);
+
+	/* activate the timer for the recipient's addBA response */
+	mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
+#endif
+
+	spin_lock_bh(&sta->lock);
+	sta->ampdu_mlme.addba_req_num[tid]++;
+	spin_unlock_bh(&sta->lock);
+
+	/* send AddBA request */
+	ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
+				     tid_tx->dialog_token, start_seq_num,
+				     0x40, 5000);
+}
+
 int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
 {
 	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
 	struct ieee80211_local *local = sdata->local;
-	u8 *state;
+	struct tid_ampdu_tx *tid_tx;
 	int ret = 0;
-	u16 start_seq_num;
 
 	trace_api_start_tx_ba_session(pubsta, tid);
 
@@ -239,24 +374,15 @@
 	    sdata->vif.type != NL80211_IFTYPE_AP)
 		return -EINVAL;
 
-	if (test_sta_flags(sta, WLAN_STA_DISASSOC)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Disassociation is in progress. "
-		       "Denying BA session request\n");
-#endif
-		return -EINVAL;
-	}
-
 	if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Suspend in progress. "
+		printk(KERN_DEBUG "BA sessions blocked. "
 		       "Denying BA session request\n");
 #endif
 		return -EINVAL;
 	}
 
 	spin_lock_bh(&sta->lock);
-	spin_lock(&local->ampdu_lock);
 
 	/* we have tried too many times, receiver does not want A-MPDU */
 	if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
@@ -264,9 +390,9 @@
 		goto err_unlock_sta;
 	}
 
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	tid_tx = sta->ampdu_mlme.tid_tx[tid];
 	/* check if the TID is not in aggregation flow already */
-	if (*state != HT_AGG_STATE_IDLE) {
+	if (tid_tx) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		printk(KERN_DEBUG "BA request denied - session is not "
 				 "idle on tid %u\n", tid);
@@ -275,96 +401,37 @@
 		goto err_unlock_sta;
 	}
 
-	/*
-	 * While we're asking the driver about the aggregation,
-	 * stop the AC queue so that we don't have to worry
-	 * about frames that came in while we were doing that,
-	 * which would require us to put them to the AC pending
-	 * afterwards which just makes the code more complex.
-	 */
-	ieee80211_stop_queue_by_reason(
-		&local->hw, ieee80211_ac_from_tid(tid),
-		IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
-
 	/* prepare A-MPDU MLME for Tx aggregation */
-	sta->ampdu_mlme.tid_tx[tid] =
-			kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
-	if (!sta->ampdu_mlme.tid_tx[tid]) {
+	tid_tx = kzalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
+	if (!tid_tx) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		if (net_ratelimit())
 			printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
 					tid);
 #endif
 		ret = -ENOMEM;
-		goto err_wake_queue;
+		goto err_unlock_sta;
 	}
 
-	skb_queue_head_init(&sta->ampdu_mlme.tid_tx[tid]->pending);
+	skb_queue_head_init(&tid_tx->pending);
+	__set_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
 
 	/* Tx timer */
-	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
-			sta_addba_resp_timer_expired;
-	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
-			(unsigned long)&sta->timer_to_tid[tid];
-	init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+	tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired;
+	tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid];
+	init_timer(&tid_tx->addba_resp_timer);
 
-	/* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
-	 * call back right away, it must see that the flow has begun */
-	*state |= HT_ADDBA_REQUESTED_MSK;
-
-	start_seq_num = sta->tid_seq[tid] >> 4;
-
-	ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
-			       pubsta, tid, &start_seq_num);
-
-	if (ret) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "BA request denied - HW unavailable for"
-					" tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-		*state = HT_AGG_STATE_IDLE;
-		goto err_free;
-	}
-
-	/* Driver vetoed or OKed, but we can take packets again now */
-	ieee80211_wake_queue_by_reason(
-		&local->hw, ieee80211_ac_from_tid(tid),
-		IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
-
-	spin_unlock(&local->ampdu_lock);
-
-	/* prepare tid data */
+	/* assign a dialog token */
 	sta->ampdu_mlme.dialog_token_allocator++;
-	sta->ampdu_mlme.tid_tx[tid]->dialog_token =
-			sta->ampdu_mlme.dialog_token_allocator;
-	sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
+	tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
 
-	spin_unlock_bh(&sta->lock);
+	/* finally, assign it to the array */
+	rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
 
-	/* send AddBA request */
-	ieee80211_send_addba_request(sdata, pubsta->addr, tid,
-			 sta->ampdu_mlme.tid_tx[tid]->dialog_token,
-			 sta->ampdu_mlme.tid_tx[tid]->ssn,
-			 0x40, 5000);
-	sta->ampdu_mlme.addba_req_num[tid]++;
-	/* activate the timer for the recipient's addBA response */
-	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
-				jiffies + ADDBA_RESP_INTERVAL;
-	add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
-#endif
-	return 0;
+	ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
 
- err_free:
-	kfree(sta->ampdu_mlme.tid_tx[tid]);
-	sta->ampdu_mlme.tid_tx[tid] = NULL;
- err_wake_queue:
-	ieee80211_wake_queue_by_reason(
-		&local->hw, ieee80211_ac_from_tid(tid),
-		IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+	/* this flow continues off the work */
  err_unlock_sta:
-	spin_unlock(&local->ampdu_lock);
 	spin_unlock_bh(&sta->lock);
 	return ret;
 }
@@ -372,69 +439,65 @@
 
 /*
  * splice packets from the STA's pending to the local pending,
- * requires a call to ieee80211_agg_splice_finish and holding
- * local->ampdu_lock across both calls.
+ * requires a call to ieee80211_agg_splice_finish later
  */
-static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
-					 struct sta_info *sta, u16 tid)
+static void __acquires(agg_queue)
+ieee80211_agg_splice_packets(struct ieee80211_local *local,
+			     struct tid_ampdu_tx *tid_tx, u16 tid)
 {
+	int queue = ieee80211_ac_from_tid(tid);
 	unsigned long flags;
-	u16 queue = ieee80211_ac_from_tid(tid);
 
-	ieee80211_stop_queue_by_reason(
-		&local->hw, queue,
-		IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+	ieee80211_stop_queue_agg(local, tid);
 
-	if (!(sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK))
+	if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
+			  " from the pending queue\n", tid))
 		return;
 
-	if (WARN(!sta->ampdu_mlme.tid_tx[tid],
-		 "TID %d gone but expected when splicing aggregates from"
-		 "the pending queue\n", tid))
-		return;
-
-	if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
+	if (!skb_queue_empty(&tid_tx->pending)) {
 		spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
 		/* copy over remaining packets */
-		skb_queue_splice_tail_init(
-			&sta->ampdu_mlme.tid_tx[tid]->pending,
-			&local->pending[queue]);
+		skb_queue_splice_tail_init(&tid_tx->pending,
+					   &local->pending[queue]);
 		spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 	}
 }
 
-static void ieee80211_agg_splice_finish(struct ieee80211_local *local,
-					struct sta_info *sta, u16 tid)
+static void __releases(agg_queue)
+ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
 {
-	u16 queue = ieee80211_ac_from_tid(tid);
-
-	ieee80211_wake_queue_by_reason(
-		&local->hw, queue,
-		IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+	ieee80211_wake_queue_agg(local, tid);
 }
 
-/* caller must hold sta->lock */
 static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
 					 struct sta_info *sta, u16 tid)
 {
+	lockdep_assert_held(&sta->ampdu_mlme.mtx);
+
 #ifdef CONFIG_MAC80211_HT_DEBUG
 	printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
 #endif
 
-	spin_lock(&local->ampdu_lock);
-	ieee80211_agg_splice_packets(local, sta, tid);
-	/*
-	 * NB: we rely on sta->lock being taken in the TX
-	 * processing here when adding to the pending queue,
-	 * otherwise we could only change the state of the
-	 * session to OPERATIONAL _here_.
-	 */
-	ieee80211_agg_splice_finish(local, sta, tid);
-	spin_unlock(&local->ampdu_lock);
-
 	drv_ampdu_action(local, sta->sdata,
 			 IEEE80211_AMPDU_TX_OPERATIONAL,
 			 &sta->sta, tid, NULL);
+
+	/*
+	 * synchronize with TX path, while splicing the TX path
+	 * should block so it won't put more packets onto pending.
+	 */
+	spin_lock_bh(&sta->lock);
+
+	ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid);
+	/*
+	 * Now mark as operational. This will be visible
+	 * in the TX path, and lets it go lock-free in
+	 * the common case.
+	 */
+	set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state);
+	ieee80211_agg_splice_finish(local, tid);
+
+	spin_unlock_bh(&sta->lock);
 }
 
 void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
@@ -442,7 +505,7 @@
 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
-	u8 *state;
+	struct tid_ampdu_tx *tid_tx;
 
 	trace_api_start_tx_ba_cb(sdata, ra, tid);
 
@@ -454,42 +517,36 @@
 		return;
 	}
 
-	rcu_read_lock();
+	mutex_lock(&local->sta_mtx);
 	sta = sta_info_get(sdata, ra);
 	if (!sta) {
-		rcu_read_unlock();
+		mutex_unlock(&local->sta_mtx);
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		printk(KERN_DEBUG "Could not find station: %pM\n", ra);
 #endif
 		return;
 	}
 
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-	spin_lock_bh(&sta->lock);
+	mutex_lock(&sta->ampdu_mlme.mtx);
+	tid_tx = sta->ampdu_mlme.tid_tx[tid];
 
-	if (WARN_ON(!(*state & HT_ADDBA_REQUESTED_MSK))) {
+	if (WARN_ON(!tid_tx)) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
-				*state);
+		printk(KERN_DEBUG "addBA was not requested!\n");
 #endif
-		spin_unlock_bh(&sta->lock);
-		rcu_read_unlock();
-		return;
+		goto unlock;
 	}
 
-	if (WARN_ON(*state & HT_ADDBA_DRV_READY_MSK))
-		goto out;
+	if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state)))
+		goto unlock;
 
-	*state |= HT_ADDBA_DRV_READY_MSK;
-
-	if (*state == HT_AGG_STATE_OPERATIONAL)
+	if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state))
 		ieee80211_agg_tx_operational(local, sta, tid);
 
- out:
-	spin_unlock_bh(&sta->lock);
-	rcu_read_unlock();
+ unlock:
+	mutex_unlock(&sta->ampdu_mlme.mtx);
+	mutex_unlock(&local->sta_mtx);
 }
-EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
 
 void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
 				      const u8 *ra, u16 tid)
@@ -510,44 +567,36 @@
 	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
 	memcpy(&ra_tid->ra, ra, ETH_ALEN);
 	ra_tid->tid = tid;
-	ra_tid->vif = vif;
 
-	skb->pkt_type = IEEE80211_ADDBA_MSG;
-	skb_queue_tail(&local->skb_queue, skb);
-	tasklet_schedule(&local->tasklet);
+	skb->pkt_type = IEEE80211_SDATA_QUEUE_AGG_START;
+	skb_queue_tail(&sdata->skb_queue, skb);
+	ieee80211_queue_work(&local->hw, &sdata->work);
 }
 EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
 
 int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 				   enum ieee80211_back_parties initiator)
 {
-	u8 *state;
 	int ret;
 
-	/* check if the TID is in aggregation */
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
-	spin_lock_bh(&sta->lock);
-
-	if (*state != HT_AGG_STATE_OPERATIONAL) {
-		ret = -ENOENT;
-		goto unlock;
-	}
+	mutex_lock(&sta->ampdu_mlme.mtx);
 
 	ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator);
 
- unlock:
-	spin_unlock_bh(&sta->lock);
+	mutex_unlock(&sta->ampdu_mlme.mtx);
+
 	return ret;
 }
 
-int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
-				 enum ieee80211_back_parties initiator)
+int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
 {
 	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
 	struct ieee80211_local *local = sdata->local;
+	struct tid_ampdu_tx *tid_tx;
+	int ret = 0;
 
-	trace_api_stop_tx_ba_session(pubsta, tid, initiator);
+	trace_api_stop_tx_ba_session(pubsta, tid);
 
 	if (!local->ops->ampdu_action)
 		return -EINVAL;
@@ -555,7 +604,26 @@
 	if (tid >= STA_TID_NUM)
 		return -EINVAL;
 
-	return __ieee80211_stop_tx_ba_session(sta, tid, initiator);
+	spin_lock_bh(&sta->lock);
+	tid_tx = sta->ampdu_mlme.tid_tx[tid];
+
+	if (!tid_tx) {
+		ret = -ENOENT;
+		goto unlock;
+	}
+
+	if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
+		/* already in progress stopping it */
+		ret = 0;
+		goto unlock;
+	}
+
+	set_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state);
+	ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
+
+ unlock:
+	spin_unlock_bh(&sta->lock);
+	return ret;
 }
 EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
 
@@ -564,7 +632,7 @@
 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
-	u8 *state;
+	struct tid_ampdu_tx *tid_tx;
 
 	trace_api_stop_tx_ba_cb(sdata, ra, tid);
 
@@ -581,51 +649,56 @@
 	       ra, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-	rcu_read_lock();
+	mutex_lock(&local->sta_mtx);
+
 	sta = sta_info_get(sdata, ra);
 	if (!sta) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		printk(KERN_DEBUG "Could not find station: %pM\n", ra);
 #endif
-		rcu_read_unlock();
-		return;
+		goto unlock;
 	}
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
 
-	/* NOTE: no need to use sta->lock in this state check, as
-	 * ieee80211_stop_tx_ba_session will let only one stop call to
-	 * pass through per sta/tid
-	 */
-	if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
+	mutex_lock(&sta->ampdu_mlme.mtx);
+	spin_lock_bh(&sta->lock);
+	tid_tx = sta->ampdu_mlme.tid_tx[tid];
+
+	if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
 #endif
-		rcu_read_unlock();
-		return;
+		goto unlock_sta;
 	}
 
-	if (*state & HT_AGG_STATE_INITIATOR_MSK)
+	if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR)
 		ieee80211_send_delba(sta->sdata, ra, tid,
 			WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
 
-	spin_lock_bh(&sta->lock);
-	spin_lock(&local->ampdu_lock);
+	/*
+	 * When we get here, the TX path will not be lockless any more wrt.
+	 * aggregation, since the OPERATIONAL bit has long been cleared.
+	 * Thus it will block on getting the lock, if it occurs. So if we
+	 * stop the queue now, we will not get any more packets, and any
+	 * that might be being processed will wait for us here, thereby
+	 * guaranteeing that no packets go to the tid_tx pending queue any
+	 * more.
+	 */
 
-	ieee80211_agg_splice_packets(local, sta, tid);
+	ieee80211_agg_splice_packets(local, tid_tx, tid);
 
-	*state = HT_AGG_STATE_IDLE;
-	/* from now on packets are no longer put onto sta->pending */
-	kfree(sta->ampdu_mlme.tid_tx[tid]);
-	sta->ampdu_mlme.tid_tx[tid] = NULL;
+	/* future packets must not find the tid_tx struct any more */
+	rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
 
-	ieee80211_agg_splice_finish(local, sta, tid);
+	ieee80211_agg_splice_finish(local, tid);
 
-	spin_unlock(&local->ampdu_lock);
+	call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
+
+ unlock_sta:
 	spin_unlock_bh(&sta->lock);
-
-	rcu_read_unlock();
+	mutex_unlock(&sta->ampdu_mlme.mtx);
+ unlock:
+	mutex_unlock(&local->sta_mtx);
 }
-EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
 
 void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
 				     const u8 *ra, u16 tid)
@@ -646,11 +719,10 @@
 	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
 	memcpy(&ra_tid->ra, ra, ETH_ALEN);
 	ra_tid->tid = tid;
-	ra_tid->vif = vif;
 
-	skb->pkt_type = IEEE80211_DELBA_MSG;
-	skb_queue_tail(&local->skb_queue, skb);
-	tasklet_schedule(&local->tasklet);
+	skb->pkt_type = IEEE80211_SDATA_QUEUE_AGG_STOP;
+	skb_queue_tail(&sdata->skb_queue, skb);
+	ieee80211_queue_work(&local->hw, &sdata->work);
 }
 EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
 
@@ -660,40 +732,40 @@
 				  struct ieee80211_mgmt *mgmt,
 				  size_t len)
 {
+	struct tid_ampdu_tx *tid_tx;
 	u16 capab, tid;
-	u8 *state;
 
 	capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
 	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
 
-	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	mutex_lock(&sta->ampdu_mlme.mtx);
 
-	spin_lock_bh(&sta->lock);
-
-	if (!(*state & HT_ADDBA_REQUESTED_MSK))
+	tid_tx = sta->ampdu_mlme.tid_tx[tid];
+	if (!tid_tx)
 		goto out;
 
-	if (mgmt->u.action.u.addba_resp.dialog_token !=
-		sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
+	if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+#endif
 		goto out;
 	}
 
-	del_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+	del_timer(&tid_tx->addba_resp_timer);
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
 	printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+#endif
 
 	if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
 			== WLAN_STATUS_SUCCESS) {
-		u8 curstate = *state;
+		if (test_and_set_bit(HT_AGG_STATE_RESPONSE_RECEIVED,
+				     &tid_tx->state)) {
+			/* ignore duplicate response */
+			goto out;
+		}
 
-		*state |= HT_ADDBA_RECEIVED_MSK;
-
-		if (*state != curstate && *state == HT_AGG_STATE_OPERATIONAL)
+		if (test_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))
 			ieee80211_agg_tx_operational(local, sta, tid);
 
 		sta->ampdu_mlme.addba_req_num[tid] = 0;
@@ -702,5 +774,5 @@
 	}
 
  out:
-	spin_unlock_bh(&sta->lock);
+	mutex_unlock(&sta->ampdu_mlme.mtx);
 }
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 67ee34f..29ac8e1 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -120,6 +120,9 @@
 	struct ieee80211_key *key;
 	int err;
 
+	if (!netif_running(dev))
+		return -ENETDOWN;
+
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
 	switch (params->cipher) {
@@ -140,17 +143,22 @@
 		return -EINVAL;
 	}
 
+	/* reject WEP and TKIP keys if WEP failed to initialize */
+	if ((alg == ALG_WEP || alg == ALG_TKIP) &&
+	    IS_ERR(sdata->local->wep_tx_tfm))
+		return -EINVAL;
+
 	key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key,
 				  params->seq_len, params->seq);
 	if (!key)
 		return -ENOMEM;
 
-	rcu_read_lock();
+	mutex_lock(&sdata->local->sta_mtx);
 
 	if (mac_addr) {
 		sta = sta_info_get_bss(sdata, mac_addr);
 		if (!sta) {
-			ieee80211_key_free(key);
+			ieee80211_key_free(sdata->local, key);
 			err = -ENOENT;
 			goto out_unlock;
 		}
@@ -160,7 +168,7 @@
 
 	err = 0;
  out_unlock:
-	rcu_read_unlock();
+	mutex_unlock(&sdata->local->sta_mtx);
 
 	return err;
 }
@@ -174,7 +182,7 @@
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	rcu_read_lock();
+	mutex_lock(&sdata->local->sta_mtx);
 
 	if (mac_addr) {
 		ret = -ENOENT;
@@ -184,7 +192,7 @@
 			goto out_unlock;
 
 		if (sta->key) {
-			ieee80211_key_free(sta->key);
+			ieee80211_key_free(sdata->local, sta->key);
 			WARN_ON(sta->key);
 			ret = 0;
 		}
@@ -197,12 +205,12 @@
 		goto out_unlock;
 	}
 
-	ieee80211_key_free(sdata->keys[key_idx]);
+	ieee80211_key_free(sdata->local, sdata->keys[key_idx]);
 	WARN_ON(sdata->keys[key_idx]);
 
 	ret = 0;
  out_unlock:
-	rcu_read_unlock();
+	mutex_unlock(&sdata->local->sta_mtx);
 
 	return ret;
 }
@@ -305,15 +313,10 @@
 					struct net_device *dev,
 					u8 key_idx)
 {
-	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	rcu_read_lock();
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	ieee80211_set_default_key(sdata, key_idx);
 
-	rcu_read_unlock();
-
 	return 0;
 }
 
@@ -321,15 +324,10 @@
 					     struct net_device *dev,
 					     u8 key_idx)
 {
-	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	rcu_read_lock();
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	ieee80211_set_default_mgmt_key(sdata, key_idx);
 
-	rcu_read_unlock();
-
 	return 0;
 }
 
@@ -415,9 +413,6 @@
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-	if (!local->ops->get_survey)
-		return -EOPNOTSUPP;
-
 	return drv_get_survey(local, idx, survey);
 }
 
@@ -600,7 +595,7 @@
 	u8 ssap;		/* 0 */
 	u8 control;
 	u8 xid_info[3];
-} __attribute__ ((packed));
+} __packed;
 
 static void ieee80211_send_layer2_update(struct sta_info *sta)
 {
@@ -1154,10 +1149,6 @@
 		return -EINVAL;
 	}
 
-	/* enable WMM or activate new settings */
-	local->hw.conf.flags |= IEEE80211_CONF_QOS;
-	drv_config(local, IEEE80211_CONF_CHANGE_QOS);
-
 	return 0;
 }
 
@@ -1331,28 +1322,28 @@
 }
 
 static int ieee80211_set_tx_power(struct wiphy *wiphy,
-				  enum tx_power_setting type, int dbm)
+				  enum nl80211_tx_power_setting type, int mbm)
 {
 	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct ieee80211_channel *chan = local->hw.conf.channel;
 	u32 changes = 0;
 
 	switch (type) {
-	case TX_POWER_AUTOMATIC:
+	case NL80211_TX_POWER_AUTOMATIC:
 		local->user_power_level = -1;
 		break;
-	case TX_POWER_LIMITED:
-		if (dbm < 0)
-			return -EINVAL;
-		local->user_power_level = dbm;
+	case NL80211_TX_POWER_LIMITED:
+		if (mbm < 0 || (mbm % 100))
+			return -EOPNOTSUPP;
+		local->user_power_level = MBM_TO_DBM(mbm);
 		break;
-	case TX_POWER_FIXED:
-		if (dbm < 0)
-			return -EINVAL;
+	case NL80211_TX_POWER_FIXED:
+		if (mbm < 0 || (mbm % 100))
+			return -EOPNOTSUPP;
 		/* TODO: move to cfg80211 when it knows the channel */
-		if (dbm > chan->max_power)
+		if (MBM_TO_DBM(mbm) > chan->max_power)
 			return -EINVAL;
-		local->user_power_level = dbm;
+		local->user_power_level = MBM_TO_DBM(mbm);
 		break;
 	}
 
@@ -1448,7 +1439,6 @@
 {
 	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;
 
 	if (sdata->vif.type != NL80211_IFTYPE_STATION)
 		return -EOPNOTSUPP;
@@ -1457,11 +1447,11 @@
 		return -EOPNOTSUPP;
 
 	if (enabled == sdata->u.mgd.powersave &&
-	    timeout == conf->dynamic_ps_forced_timeout)
+	    timeout == local->dynamic_ps_forced_timeout)
 		return 0;
 
 	sdata->u.mgd.powersave = enabled;
-	conf->dynamic_ps_forced_timeout = timeout;
+	local->dynamic_ps_forced_timeout = timeout;
 
 	/* no change, but if automatic follow powersave */
 	mutex_lock(&sdata->u.mgd.mtx);
@@ -1554,10 +1544,58 @@
 static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
 			    struct ieee80211_channel *chan,
 			    enum nl80211_channel_type channel_type,
+			    bool channel_type_valid,
 			    const u8 *buf, size_t len, u64 *cookie)
 {
-	return ieee80211_mgd_action(IEEE80211_DEV_TO_SUB_IF(dev), chan,
-				    channel_type, buf, len, cookie);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
+	struct sk_buff *skb;
+	struct sta_info *sta;
+	const struct ieee80211_mgmt *mgmt = (void *)buf;
+	u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+		    IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+	/* Check that we are on the requested channel for transmission */
+	if (chan != local->tmp_channel &&
+	    chan != local->oper_channel)
+		return -EBUSY;
+	if (channel_type_valid &&
+	    (channel_type != local->tmp_channel_type &&
+	     channel_type != local->_oper_channel_type))
+		return -EBUSY;
+
+	switch (sdata->vif.type) {
+	case NL80211_IFTYPE_ADHOC:
+		if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
+			break;
+		rcu_read_lock();
+		sta = sta_info_get(sdata, mgmt->da);
+		rcu_read_unlock();
+		if (!sta)
+			return -ENOLINK;
+		break;
+	case NL80211_IFTYPE_STATION:
+		if (!(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED))
+			flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
+	if (!skb)
+		return -ENOMEM;
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+
+	memcpy(skb_put(skb, len), buf, len);
+
+	IEEE80211_SKB_CB(skb)->flags = flags;
+
+	skb->dev = sdata->dev;
+	ieee80211_tx_skb(sdata, skb);
+
+	*cookie = (unsigned long) skb;
+	return 0;
 }
 
 struct cfg80211_ops mac80211_config_ops = {
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 637929b..a694c59 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -307,9 +307,6 @@
 
 /* statistics stuff */
 
-#define DEBUGFS_STATS_FILE(name, buflen, fmt, value...)			\
-	DEBUGFS_READONLY_FILE(stats_ ##name, buflen, fmt, ##value)
-
 static ssize_t format_devstat_counter(struct ieee80211_local *local,
 	char __user *userbuf,
 	size_t count, loff_t *ppos,
@@ -351,75 +348,16 @@
 	.open = mac80211_open_file_generic,				\
 };
 
-#define DEBUGFS_STATS_ADD(name)						\
+#define DEBUGFS_STATS_ADD(name, field)					\
+	debugfs_create_u32(#name, 0400, statsd, (u32 *) &field);
+#define DEBUGFS_DEVSTATS_ADD(name)					\
 	debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops);
 
-DEBUGFS_STATS_FILE(transmitted_fragment_count, 20, "%u",
-		   local->dot11TransmittedFragmentCount);
-DEBUGFS_STATS_FILE(multicast_transmitted_frame_count, 20, "%u",
-		   local->dot11MulticastTransmittedFrameCount);
-DEBUGFS_STATS_FILE(failed_count, 20, "%u",
-		   local->dot11FailedCount);
-DEBUGFS_STATS_FILE(retry_count, 20, "%u",
-		   local->dot11RetryCount);
-DEBUGFS_STATS_FILE(multiple_retry_count, 20, "%u",
-		   local->dot11MultipleRetryCount);
-DEBUGFS_STATS_FILE(frame_duplicate_count, 20, "%u",
-		   local->dot11FrameDuplicateCount);
-DEBUGFS_STATS_FILE(received_fragment_count, 20, "%u",
-		   local->dot11ReceivedFragmentCount);
-DEBUGFS_STATS_FILE(multicast_received_frame_count, 20, "%u",
-		   local->dot11MulticastReceivedFrameCount);
-DEBUGFS_STATS_FILE(transmitted_frame_count, 20, "%u",
-		   local->dot11TransmittedFrameCount);
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-DEBUGFS_STATS_FILE(tx_handlers_drop, 20, "%u",
-		   local->tx_handlers_drop);
-DEBUGFS_STATS_FILE(tx_handlers_queued, 20, "%u",
-		   local->tx_handlers_queued);
-DEBUGFS_STATS_FILE(tx_handlers_drop_unencrypted, 20, "%u",
-		   local->tx_handlers_drop_unencrypted);
-DEBUGFS_STATS_FILE(tx_handlers_drop_fragment, 20, "%u",
-		   local->tx_handlers_drop_fragment);
-DEBUGFS_STATS_FILE(tx_handlers_drop_wep, 20, "%u",
-		   local->tx_handlers_drop_wep);
-DEBUGFS_STATS_FILE(tx_handlers_drop_not_assoc, 20, "%u",
-		   local->tx_handlers_drop_not_assoc);
-DEBUGFS_STATS_FILE(tx_handlers_drop_unauth_port, 20, "%u",
-		   local->tx_handlers_drop_unauth_port);
-DEBUGFS_STATS_FILE(rx_handlers_drop, 20, "%u",
-		   local->rx_handlers_drop);
-DEBUGFS_STATS_FILE(rx_handlers_queued, 20, "%u",
-		   local->rx_handlers_queued);
-DEBUGFS_STATS_FILE(rx_handlers_drop_nullfunc, 20, "%u",
-		   local->rx_handlers_drop_nullfunc);
-DEBUGFS_STATS_FILE(rx_handlers_drop_defrag, 20, "%u",
-		   local->rx_handlers_drop_defrag);
-DEBUGFS_STATS_FILE(rx_handlers_drop_short, 20, "%u",
-		   local->rx_handlers_drop_short);
-DEBUGFS_STATS_FILE(rx_handlers_drop_passive_scan, 20, "%u",
-		   local->rx_handlers_drop_passive_scan);
-DEBUGFS_STATS_FILE(tx_expand_skb_head, 20, "%u",
-		   local->tx_expand_skb_head);
-DEBUGFS_STATS_FILE(tx_expand_skb_head_cloned, 20, "%u",
-		   local->tx_expand_skb_head_cloned);
-DEBUGFS_STATS_FILE(rx_expand_skb_head, 20, "%u",
-		   local->rx_expand_skb_head);
-DEBUGFS_STATS_FILE(rx_expand_skb_head2, 20, "%u",
-		   local->rx_expand_skb_head2);
-DEBUGFS_STATS_FILE(rx_handlers_fragments, 20, "%u",
-		   local->rx_handlers_fragments);
-DEBUGFS_STATS_FILE(tx_status_drop, 20, "%u",
-		   local->tx_status_drop);
-
-#endif
-
 DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount);
 DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount);
 DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount);
 DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount);
 
-
 void debugfs_hw_add(struct ieee80211_local *local)
 {
 	struct dentry *phyd = local->hw.wiphy->debugfsdir;
@@ -448,38 +386,60 @@
 	if (!statsd)
 		return;
 
-	DEBUGFS_STATS_ADD(transmitted_fragment_count);
-	DEBUGFS_STATS_ADD(multicast_transmitted_frame_count);
-	DEBUGFS_STATS_ADD(failed_count);
-	DEBUGFS_STATS_ADD(retry_count);
-	DEBUGFS_STATS_ADD(multiple_retry_count);
-	DEBUGFS_STATS_ADD(frame_duplicate_count);
-	DEBUGFS_STATS_ADD(received_fragment_count);
-	DEBUGFS_STATS_ADD(multicast_received_frame_count);
-	DEBUGFS_STATS_ADD(transmitted_frame_count);
+	DEBUGFS_STATS_ADD(transmitted_fragment_count,
+		local->dot11TransmittedFragmentCount);
+	DEBUGFS_STATS_ADD(multicast_transmitted_frame_count,
+		local->dot11MulticastTransmittedFrameCount);
+	DEBUGFS_STATS_ADD(failed_count, local->dot11FailedCount);
+	DEBUGFS_STATS_ADD(retry_count, local->dot11RetryCount);
+	DEBUGFS_STATS_ADD(multiple_retry_count,
+		local->dot11MultipleRetryCount);
+	DEBUGFS_STATS_ADD(frame_duplicate_count,
+		local->dot11FrameDuplicateCount);
+	DEBUGFS_STATS_ADD(received_fragment_count,
+		local->dot11ReceivedFragmentCount);
+	DEBUGFS_STATS_ADD(multicast_received_frame_count,
+		local->dot11MulticastReceivedFrameCount);
+	DEBUGFS_STATS_ADD(transmitted_frame_count,
+		local->dot11TransmittedFrameCount);
 #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-	DEBUGFS_STATS_ADD(tx_handlers_drop);
-	DEBUGFS_STATS_ADD(tx_handlers_queued);
-	DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted);
-	DEBUGFS_STATS_ADD(tx_handlers_drop_fragment);
-	DEBUGFS_STATS_ADD(tx_handlers_drop_wep);
-	DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc);
-	DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port);
-	DEBUGFS_STATS_ADD(rx_handlers_drop);
-	DEBUGFS_STATS_ADD(rx_handlers_queued);
-	DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc);
-	DEBUGFS_STATS_ADD(rx_handlers_drop_defrag);
-	DEBUGFS_STATS_ADD(rx_handlers_drop_short);
-	DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan);
-	DEBUGFS_STATS_ADD(tx_expand_skb_head);
-	DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned);
-	DEBUGFS_STATS_ADD(rx_expand_skb_head);
-	DEBUGFS_STATS_ADD(rx_expand_skb_head2);
-	DEBUGFS_STATS_ADD(rx_handlers_fragments);
-	DEBUGFS_STATS_ADD(tx_status_drop);
+	DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop);
+	DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued);
+	DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted,
+		local->tx_handlers_drop_unencrypted);
+	DEBUGFS_STATS_ADD(tx_handlers_drop_fragment,
+		local->tx_handlers_drop_fragment);
+	DEBUGFS_STATS_ADD(tx_handlers_drop_wep,
+		local->tx_handlers_drop_wep);
+	DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc,
+		local->tx_handlers_drop_not_assoc);
+	DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port,
+		local->tx_handlers_drop_unauth_port);
+	DEBUGFS_STATS_ADD(rx_handlers_drop, local->rx_handlers_drop);
+	DEBUGFS_STATS_ADD(rx_handlers_queued, local->rx_handlers_queued);
+	DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc,
+		local->rx_handlers_drop_nullfunc);
+	DEBUGFS_STATS_ADD(rx_handlers_drop_defrag,
+		local->rx_handlers_drop_defrag);
+	DEBUGFS_STATS_ADD(rx_handlers_drop_short,
+		local->rx_handlers_drop_short);
+	DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan,
+		local->rx_handlers_drop_passive_scan);
+	DEBUGFS_STATS_ADD(tx_expand_skb_head,
+		local->tx_expand_skb_head);
+	DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned,
+		local->tx_expand_skb_head_cloned);
+	DEBUGFS_STATS_ADD(rx_expand_skb_head,
+		local->rx_expand_skb_head);
+	DEBUGFS_STATS_ADD(rx_expand_skb_head2,
+		local->rx_expand_skb_head2);
+	DEBUGFS_STATS_ADD(rx_handlers_fragments,
+		local->rx_handlers_fragments);
+	DEBUGFS_STATS_ADD(tx_status_drop,
+		local->tx_status_drop);
 #endif
-	DEBUGFS_STATS_ADD(dot11ACKFailureCount);
-	DEBUGFS_STATS_ADD(dot11RTSFailureCount);
-	DEBUGFS_STATS_ADD(dot11FCSErrorCount);
-	DEBUGFS_STATS_ADD(dot11RTSSuccessCount);
+	DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount);
+	DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
+	DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);
+	DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);
 }
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 97c9e46..fa5e76e 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -143,7 +143,7 @@
 		len = p - buf;
 		break;
 	case ALG_CCMP:
-		for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
+		for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) {
 			rpn = key->u.ccmp.rx_pn[i];
 			p += scnprintf(p, sizeof(buf)+buf-p,
 				       "%02x%02x%02x%02x%02x%02x\n",
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index e763f15..76839d4 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -30,7 +30,6 @@
 }
 #define STA_READ_D(name, field) STA_READ(name, 20, field, "%d\n")
 #define STA_READ_U(name, field) STA_READ(name, 20, field, "%u\n")
-#define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n")
 #define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n")
 
 #define STA_OPS(name)							\
@@ -52,19 +51,7 @@
 
 STA_FILE(aid, sta.aid, D);
 STA_FILE(dev, sdata->name, S);
-STA_FILE(rx_packets, rx_packets, LU);
-STA_FILE(tx_packets, tx_packets, LU);
-STA_FILE(rx_bytes, rx_bytes, LU);
-STA_FILE(tx_bytes, tx_bytes, LU);
-STA_FILE(rx_duplicates, num_duplicates, LU);
-STA_FILE(rx_fragments, rx_fragments, LU);
-STA_FILE(rx_dropped, rx_dropped, LU);
-STA_FILE(tx_fragments, tx_fragments, LU);
-STA_FILE(tx_filtered, tx_filtered_count, LU);
-STA_FILE(tx_retry_failed, tx_retry_failed, LU);
-STA_FILE(tx_retry_count, tx_retry_count, LU);
 STA_FILE(last_signal, last_signal, D);
-STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU);
 
 static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
 			      size_t count, loff_t *ppos)
@@ -134,28 +121,25 @@
 	p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n",
 			sta->ampdu_mlme.dialog_token_allocator + 1);
 	p += scnprintf(p, sizeof(buf) + buf - p,
-		       "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n");
+		       "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n");
 	for (i = 0; i < STA_TID_NUM; i++) {
 		p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i);
 		p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
-				sta->ampdu_mlme.tid_active_rx[i]);
+				!!sta->ampdu_mlme.tid_rx[i]);
 		p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
-				sta->ampdu_mlme.tid_active_rx[i] ?
+				sta->ampdu_mlme.tid_rx[i] ?
 				sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
 		p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
-				sta->ampdu_mlme.tid_active_rx[i] ?
+				sta->ampdu_mlme.tid_rx[i] ?
 				sta->ampdu_mlme.tid_rx[i]->ssn : 0);
 
 		p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
-				sta->ampdu_mlme.tid_state_tx[i]);
+				!!sta->ampdu_mlme.tid_tx[i]);
 		p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
-				sta->ampdu_mlme.tid_state_tx[i] ?
+				sta->ampdu_mlme.tid_tx[i] ?
 				sta->ampdu_mlme.tid_tx[i]->dialog_token : 0);
-		p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
-				sta->ampdu_mlme.tid_state_tx[i] ?
-				sta->ampdu_mlme.tid_tx[i]->ssn : 0);
 		p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d",
-				sta->ampdu_mlme.tid_state_tx[i] ?
+				sta->ampdu_mlme.tid_tx[i] ?
 				skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0);
 		p += scnprintf(p, sizeof(buf) + buf - p, "\n");
 	}
@@ -210,8 +194,7 @@
 		if (start)
 			ret = ieee80211_start_tx_ba_session(&sta->sta, tid);
 		else
-			ret = ieee80211_stop_tx_ba_session(&sta->sta, tid,
-							   WLAN_BACK_RECIPIENT);
+			ret = ieee80211_stop_tx_ba_session(&sta->sta, tid);
 	} else {
 		__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, 3);
 		ret = 0;
@@ -307,6 +290,13 @@
 	debugfs_create_file(#name, 0400, \
 		sta->debugfs.dir, sta, &sta_ ##name## _ops);
 
+#define DEBUGFS_ADD_COUNTER(name, field)				\
+	if (sizeof(sta->field) == sizeof(u32))				\
+		debugfs_create_u32(#name, 0400, sta->debugfs.dir,	\
+			(u32 *) &sta->field);				\
+	else								\
+		debugfs_create_u64(#name, 0400, sta->debugfs.dir,	\
+			(u64 *) &sta->field);
 
 void ieee80211_sta_debugfs_add(struct sta_info *sta)
 {
@@ -339,20 +329,21 @@
 	DEBUGFS_ADD(last_seq_ctrl);
 	DEBUGFS_ADD(agg_status);
 	DEBUGFS_ADD(dev);
-	DEBUGFS_ADD(rx_packets);
-	DEBUGFS_ADD(tx_packets);
-	DEBUGFS_ADD(rx_bytes);
-	DEBUGFS_ADD(tx_bytes);
-	DEBUGFS_ADD(rx_duplicates);
-	DEBUGFS_ADD(rx_fragments);
-	DEBUGFS_ADD(rx_dropped);
-	DEBUGFS_ADD(tx_fragments);
-	DEBUGFS_ADD(tx_filtered);
-	DEBUGFS_ADD(tx_retry_failed);
-	DEBUGFS_ADD(tx_retry_count);
 	DEBUGFS_ADD(last_signal);
-	DEBUGFS_ADD(wep_weak_iv_count);
 	DEBUGFS_ADD(ht_capa);
+
+	DEBUGFS_ADD_COUNTER(rx_packets, rx_packets);
+	DEBUGFS_ADD_COUNTER(tx_packets, tx_packets);
+	DEBUGFS_ADD_COUNTER(rx_bytes, rx_bytes);
+	DEBUGFS_ADD_COUNTER(tx_bytes, tx_bytes);
+	DEBUGFS_ADD_COUNTER(rx_duplicates, num_duplicates);
+	DEBUGFS_ADD_COUNTER(rx_fragments, rx_fragments);
+	DEBUGFS_ADD_COUNTER(rx_dropped, rx_dropped);
+	DEBUGFS_ADD_COUNTER(tx_fragments, tx_fragments);
+	DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count);
+	DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed);
+	DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count);
+	DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count);
 }
 
 void ieee80211_sta_debugfs_remove(struct sta_info *sta)
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 9c1da08..14123dc 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -16,10 +16,11 @@
 
 	might_sleep();
 
+	trace_drv_start(local);
 	local->started = true;
 	smp_mb();
 	ret = local->ops->start(&local->hw);
-	trace_drv_start(local, ret);
+	trace_drv_return_int(local, ret);
 	return ret;
 }
 
@@ -27,8 +28,9 @@
 {
 	might_sleep();
 
-	local->ops->stop(&local->hw);
 	trace_drv_stop(local);
+	local->ops->stop(&local->hw);
+	trace_drv_return_void(local);
 
 	/* sync away all work on the tasklet before clearing started */
 	tasklet_disable(&local->tasklet);
@@ -46,8 +48,9 @@
 
 	might_sleep();
 
+	trace_drv_add_interface(local, vif_to_sdata(vif));
 	ret = local->ops->add_interface(&local->hw, vif);
-	trace_drv_add_interface(local, vif_to_sdata(vif), ret);
+	trace_drv_return_int(local, ret);
 	return ret;
 }
 
@@ -56,8 +59,9 @@
 {
 	might_sleep();
 
-	local->ops->remove_interface(&local->hw, vif);
 	trace_drv_remove_interface(local, vif_to_sdata(vif));
+	local->ops->remove_interface(&local->hw, vif);
+	trace_drv_return_void(local);
 }
 
 static inline int drv_config(struct ieee80211_local *local, u32 changed)
@@ -66,8 +70,9 @@
 
 	might_sleep();
 
+	trace_drv_config(local, changed);
 	ret = local->ops->config(&local->hw, changed);
-	trace_drv_config(local, changed, ret);
+	trace_drv_return_int(local, ret);
 	return ret;
 }
 
@@ -78,9 +83,10 @@
 {
 	might_sleep();
 
+	trace_drv_bss_info_changed(local, sdata, info, changed);
 	if (local->ops->bss_info_changed)
 		local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed);
-	trace_drv_bss_info_changed(local, sdata, info, changed);
+	trace_drv_return_void(local);
 }
 
 static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
@@ -88,10 +94,12 @@
 {
 	u64 ret = 0;
 
+	trace_drv_prepare_multicast(local, mc_list->count);
+
 	if (local->ops->prepare_multicast)
 		ret = local->ops->prepare_multicast(&local->hw, mc_list);
 
-	trace_drv_prepare_multicast(local, mc_list->count, ret);
+	trace_drv_return_u64(local, ret);
 
 	return ret;
 }
@@ -103,19 +111,21 @@
 {
 	might_sleep();
 
-	local->ops->configure_filter(&local->hw, changed_flags, total_flags,
-				     multicast);
 	trace_drv_configure_filter(local, changed_flags, total_flags,
 				   multicast);
+	local->ops->configure_filter(&local->hw, changed_flags, total_flags,
+				     multicast);
+	trace_drv_return_void(local);
 }
 
 static inline int drv_set_tim(struct ieee80211_local *local,
 			      struct ieee80211_sta *sta, bool set)
 {
 	int ret = 0;
+	trace_drv_set_tim(local, sta, set);
 	if (local->ops->set_tim)
 		ret = local->ops->set_tim(&local->hw, sta, set);
-	trace_drv_set_tim(local, sta, set, ret);
+	trace_drv_return_int(local, ret);
 	return ret;
 }
 
@@ -129,8 +139,9 @@
 
 	might_sleep();
 
+	trace_drv_set_key(local, cmd, sdata, sta, key);
 	ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
-	trace_drv_set_key(local, cmd, sdata, sta, key, ret);
+	trace_drv_return_int(local, ret);
 	return ret;
 }
 
@@ -145,10 +156,11 @@
 	if (sta)
 		ista = &sta->sta;
 
+	trace_drv_update_tkip_key(local, sdata, conf, ista, iv32);
 	if (local->ops->update_tkip_key)
 		local->ops->update_tkip_key(&local->hw, &sdata->vif, conf,
 					    ista, iv32, phase1key);
-	trace_drv_update_tkip_key(local, sdata, conf, ista, iv32);
+	trace_drv_return_void(local);
 }
 
 static inline int drv_hw_scan(struct ieee80211_local *local,
@@ -159,8 +171,9 @@
 
 	might_sleep();
 
+	trace_drv_hw_scan(local, sdata, req);
 	ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
-	trace_drv_hw_scan(local, sdata, req, ret);
+	trace_drv_return_int(local, ret);
 	return ret;
 }
 
@@ -168,18 +181,20 @@
 {
 	might_sleep();
 
+	trace_drv_sw_scan_start(local);
 	if (local->ops->sw_scan_start)
 		local->ops->sw_scan_start(&local->hw);
-	trace_drv_sw_scan_start(local);
+	trace_drv_return_void(local);
 }
 
 static inline void drv_sw_scan_complete(struct ieee80211_local *local)
 {
 	might_sleep();
 
+	trace_drv_sw_scan_complete(local);
 	if (local->ops->sw_scan_complete)
 		local->ops->sw_scan_complete(&local->hw);
-	trace_drv_sw_scan_complete(local);
+	trace_drv_return_void(local);
 }
 
 static inline int drv_get_stats(struct ieee80211_local *local,
@@ -211,9 +226,10 @@
 
 	might_sleep();
 
+	trace_drv_set_rts_threshold(local, value);
 	if (local->ops->set_rts_threshold)
 		ret = local->ops->set_rts_threshold(&local->hw, value);
-	trace_drv_set_rts_threshold(local, value, ret);
+	trace_drv_return_int(local, ret);
 	return ret;
 }
 
@@ -223,12 +239,13 @@
 	int ret = 0;
 	might_sleep();
 
+	trace_drv_set_coverage_class(local, value);
 	if (local->ops->set_coverage_class)
 		local->ops->set_coverage_class(&local->hw, value);
 	else
 		ret = -EOPNOTSUPP;
 
-	trace_drv_set_coverage_class(local, value, ret);
+	trace_drv_return_int(local, ret);
 	return ret;
 }
 
@@ -237,9 +254,10 @@
 				  enum sta_notify_cmd cmd,
 				  struct ieee80211_sta *sta)
 {
+	trace_drv_sta_notify(local, sdata, cmd, sta);
 	if (local->ops->sta_notify)
 		local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta);
-	trace_drv_sta_notify(local, sdata, cmd, sta);
+	trace_drv_return_void(local);
 }
 
 static inline int drv_sta_add(struct ieee80211_local *local,
@@ -250,13 +268,11 @@
 
 	might_sleep();
 
+	trace_drv_sta_add(local, sdata, sta);
 	if (local->ops->sta_add)
 		ret = local->ops->sta_add(&local->hw, &sdata->vif, sta);
-	else if (local->ops->sta_notify)
-		local->ops->sta_notify(&local->hw, &sdata->vif,
-					STA_NOTIFY_ADD, sta);
 
-	trace_drv_sta_add(local, sdata, sta, ret);
+	trace_drv_return_int(local, ret);
 
 	return ret;
 }
@@ -267,13 +283,11 @@
 {
 	might_sleep();
 
+	trace_drv_sta_remove(local, sdata, sta);
 	if (local->ops->sta_remove)
 		local->ops->sta_remove(&local->hw, &sdata->vif, sta);
-	else if (local->ops->sta_notify)
-		local->ops->sta_notify(&local->hw, &sdata->vif,
-					STA_NOTIFY_REMOVE, sta);
 
-	trace_drv_sta_remove(local, sdata, sta);
+	trace_drv_return_void(local);
 }
 
 static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
@@ -283,9 +297,10 @@
 
 	might_sleep();
 
+	trace_drv_conf_tx(local, queue, params);
 	if (local->ops->conf_tx)
 		ret = local->ops->conf_tx(&local->hw, queue, params);
-	trace_drv_conf_tx(local, queue, params, ret);
+	trace_drv_return_int(local, ret);
 	return ret;
 }
 
@@ -295,9 +310,10 @@
 
 	might_sleep();
 
+	trace_drv_get_tsf(local);
 	if (local->ops->get_tsf)
 		ret = local->ops->get_tsf(&local->hw);
-	trace_drv_get_tsf(local, ret);
+	trace_drv_return_u64(local, ret);
 	return ret;
 }
 
@@ -305,18 +321,20 @@
 {
 	might_sleep();
 
+	trace_drv_set_tsf(local, tsf);
 	if (local->ops->set_tsf)
 		local->ops->set_tsf(&local->hw, tsf);
-	trace_drv_set_tsf(local, tsf);
+	trace_drv_return_void(local);
 }
 
 static inline void drv_reset_tsf(struct ieee80211_local *local)
 {
 	might_sleep();
 
+	trace_drv_reset_tsf(local);
 	if (local->ops->reset_tsf)
 		local->ops->reset_tsf(&local->hw);
-	trace_drv_reset_tsf(local);
+	trace_drv_return_void(local);
 }
 
 static inline int drv_tx_last_beacon(struct ieee80211_local *local)
@@ -325,9 +343,10 @@
 
 	might_sleep();
 
+	trace_drv_tx_last_beacon(local);
 	if (local->ops->tx_last_beacon)
 		ret = local->ops->tx_last_beacon(&local->hw);
-	trace_drv_tx_last_beacon(local, ret);
+	trace_drv_return_int(local, ret);
 	return ret;
 }
 
@@ -338,10 +357,17 @@
 				   u16 *ssn)
 {
 	int ret = -EOPNOTSUPP;
+
+	might_sleep();
+
+	trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn);
+
 	if (local->ops->ampdu_action)
 		ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
 					       sta, tid, ssn);
-	trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, ret);
+
+	trace_drv_return_int(local, ret);
+
 	return ret;
 }
 
@@ -349,9 +375,14 @@
 				struct survey_info *survey)
 {
 	int ret = -EOPNOTSUPP;
+
+	trace_drv_get_survey(local, idx, survey);
+
 	if (local->ops->get_survey)
 		ret = local->ops->get_survey(&local->hw, idx, survey);
-	/* trace_drv_get_survey(local, idx, survey, ret); */
+
+	trace_drv_return_int(local, ret);
+
 	return ret;
 }
 
@@ -370,6 +401,7 @@
 	trace_drv_flush(local, drop);
 	if (local->ops->flush)
 		local->ops->flush(&local->hw, drop);
+	trace_drv_return_void(local);
 }
 
 static inline void drv_channel_switch(struct ieee80211_local *local,
@@ -377,9 +409,9 @@
 {
 	might_sleep();
 
-	local->ops->channel_switch(&local->hw, ch_switch);
-
 	trace_drv_channel_switch(local, ch_switch);
+	local->ops->channel_switch(&local->hw, ch_switch);
+	trace_drv_return_void(local);
 }
 
 #endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 6a9b234..5d5d2a9 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -36,20 +36,58 @@
  * Tracing for driver callbacks.
  */
 
-TRACE_EVENT(drv_start,
+TRACE_EVENT(drv_return_void,
+	TP_PROTO(struct ieee80211_local *local),
+	TP_ARGS(local),
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+	),
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+	),
+	TP_printk(LOCAL_PR_FMT, LOCAL_PR_ARG)
+);
+
+TRACE_EVENT(drv_return_int,
 	TP_PROTO(struct ieee80211_local *local, int ret),
-
 	TP_ARGS(local, ret),
-
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
 		__field(int, ret)
 	),
-
 	TP_fast_assign(
 		LOCAL_ASSIGN;
 		__entry->ret = ret;
 	),
+	TP_printk(LOCAL_PR_FMT " - %d", LOCAL_PR_ARG, __entry->ret)
+);
+
+TRACE_EVENT(drv_return_u64,
+	TP_PROTO(struct ieee80211_local *local, u64 ret),
+	TP_ARGS(local, ret),
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u64, ret)
+	),
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->ret = ret;
+	),
+	TP_printk(LOCAL_PR_FMT " - %llu", LOCAL_PR_ARG, __entry->ret)
+);
+
+TRACE_EVENT(drv_start,
+	TP_PROTO(struct ieee80211_local *local),
+
+	TP_ARGS(local),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+	),
 
 	TP_printk(
 		LOCAL_PR_FMT, LOCAL_PR_ARG
@@ -76,28 +114,25 @@
 
 TRACE_EVENT(drv_add_interface,
 	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sub_if_data *sdata,
-		 int ret),
+		 struct ieee80211_sub_if_data *sdata),
 
-	TP_ARGS(local, sdata, ret),
+	TP_ARGS(local, sdata),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
 		VIF_ENTRY
 		__array(char, addr, 6)
-		__field(int, ret)
 	),
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
 		VIF_ASSIGN;
 		memcpy(__entry->addr, sdata->vif.addr, 6);
-		__entry->ret = ret;
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT " addr:%pM ret:%d",
-		LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr, __entry->ret
+		LOCAL_PR_FMT  VIF_PR_FMT " addr:%pM",
+		LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr
 	)
 );
 
@@ -126,15 +161,13 @@
 
 TRACE_EVENT(drv_config,
 	TP_PROTO(struct ieee80211_local *local,
-		 u32 changed,
-		 int ret),
+		 u32 changed),
 
-	TP_ARGS(local, changed, ret),
+	TP_ARGS(local, changed),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
 		__field(u32, changed)
-		__field(int, ret)
 		__field(u32, flags)
 		__field(int, power_level)
 		__field(int, dynamic_ps_timeout)
@@ -150,7 +183,6 @@
 	TP_fast_assign(
 		LOCAL_ASSIGN;
 		__entry->changed = changed;
-		__entry->ret = ret;
 		__entry->flags = local->hw.conf.flags;
 		__entry->power_level = local->hw.conf.power_level;
 		__entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout;
@@ -164,8 +196,8 @@
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT " ch:%#x freq:%d ret:%d",
-		LOCAL_PR_ARG, __entry->changed, __entry->center_freq, __entry->ret
+		LOCAL_PR_FMT " ch:%#x freq:%d",
+		LOCAL_PR_ARG, __entry->changed, __entry->center_freq
 	)
 );
 
@@ -220,26 +252,23 @@
 );
 
 TRACE_EVENT(drv_prepare_multicast,
-	TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret),
+	TP_PROTO(struct ieee80211_local *local, int mc_count),
 
-	TP_ARGS(local, mc_count, ret),
+	TP_ARGS(local, mc_count),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
 		__field(int, mc_count)
-		__field(u64, ret)
 	),
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
 		__entry->mc_count = mc_count;
-		__entry->ret = ret;
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT " prepare mc (%d): %llx",
-		LOCAL_PR_ARG, __entry->mc_count,
-		(unsigned long long) __entry->ret
+		LOCAL_PR_FMT " prepare mc (%d)",
+		LOCAL_PR_ARG, __entry->mc_count
 	)
 );
 
@@ -273,27 +302,25 @@
 
 TRACE_EVENT(drv_set_tim,
 	TP_PROTO(struct ieee80211_local *local,
-		 struct ieee80211_sta *sta, bool set, int ret),
+		 struct ieee80211_sta *sta, bool set),
 
-	TP_ARGS(local, sta, set, ret),
+	TP_ARGS(local, sta, set),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
 		STA_ENTRY
 		__field(bool, set)
-		__field(int, ret)
 	),
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
 		STA_ASSIGN;
 		__entry->set = set;
-		__entry->ret = ret;
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT STA_PR_FMT " set:%d ret:%d",
-		LOCAL_PR_ARG, STA_PR_FMT, __entry->set, __entry->ret
+		LOCAL_PR_FMT STA_PR_FMT " set:%d",
+		LOCAL_PR_ARG, STA_PR_FMT, __entry->set
 	)
 );
 
@@ -301,9 +328,9 @@
 	TP_PROTO(struct ieee80211_local *local,
 		 enum set_key_cmd cmd, struct ieee80211_sub_if_data *sdata,
 		 struct ieee80211_sta *sta,
-		 struct ieee80211_key_conf *key, int ret),
+		 struct ieee80211_key_conf *key),
 
-	TP_ARGS(local, cmd, sdata, sta, key, ret),
+	TP_ARGS(local, cmd, sdata, sta, key),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
@@ -313,7 +340,6 @@
 		__field(u8, hw_key_idx)
 		__field(u8, flags)
 		__field(s8, keyidx)
-		__field(int, ret)
 	),
 
 	TP_fast_assign(
@@ -324,12 +350,11 @@
 		__entry->flags = key->flags;
 		__entry->keyidx = key->keyidx;
 		__entry->hw_key_idx = key->hw_key_idx;
-		__entry->ret = ret;
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " ret:%d",
-		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret
+		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
 	)
 );
 
@@ -364,25 +389,23 @@
 TRACE_EVENT(drv_hw_scan,
 	TP_PROTO(struct ieee80211_local *local,
 		 struct ieee80211_sub_if_data *sdata,
-		 struct cfg80211_scan_request *req, int ret),
+		 struct cfg80211_scan_request *req),
 
-	TP_ARGS(local, sdata, req, ret),
+	TP_ARGS(local, sdata, req),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
 		VIF_ENTRY
-		__field(int, ret)
 	),
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
 		VIF_ASSIGN;
-		__entry->ret = ret;
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT VIF_PR_FMT " ret:%d",
-		LOCAL_PR_ARG,VIF_PR_ARG, __entry->ret
+		LOCAL_PR_FMT VIF_PR_FMT,
+		LOCAL_PR_ARG,VIF_PR_ARG
 	)
 );
 
@@ -479,48 +502,44 @@
 );
 
 TRACE_EVENT(drv_set_rts_threshold,
-	TP_PROTO(struct ieee80211_local *local, u32 value, int ret),
+	TP_PROTO(struct ieee80211_local *local, u32 value),
 
-	TP_ARGS(local, value, ret),
+	TP_ARGS(local, value),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
 		__field(u32, value)
-		__field(int, ret)
 	),
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
-		__entry->ret = ret;
 		__entry->value = value;
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT " value:%d ret:%d",
-		LOCAL_PR_ARG, __entry->value, __entry->ret
+		LOCAL_PR_FMT " value:%d",
+		LOCAL_PR_ARG, __entry->value
 	)
 );
 
 TRACE_EVENT(drv_set_coverage_class,
-	TP_PROTO(struct ieee80211_local *local, u8 value, int ret),
+	TP_PROTO(struct ieee80211_local *local, u8 value),
 
-	TP_ARGS(local, value, ret),
+	TP_ARGS(local, value),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
 		__field(u8, value)
-		__field(int, ret)
 	),
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
-		__entry->ret = ret;
 		__entry->value = value;
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT " value:%d ret:%d",
-		LOCAL_PR_ARG, __entry->value, __entry->ret
+		LOCAL_PR_FMT " value:%d",
+		LOCAL_PR_ARG, __entry->value
 	)
 );
 
@@ -555,27 +574,25 @@
 TRACE_EVENT(drv_sta_add,
 	TP_PROTO(struct ieee80211_local *local,
 		 struct ieee80211_sub_if_data *sdata,
-		 struct ieee80211_sta *sta, int ret),
+		 struct ieee80211_sta *sta),
 
-	TP_ARGS(local, sdata, sta, ret),
+	TP_ARGS(local, sdata, sta),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
 		VIF_ENTRY
 		STA_ENTRY
-		__field(int, ret)
 	),
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
 		VIF_ASSIGN;
 		STA_ASSIGN;
-		__entry->ret = ret;
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " ret:%d",
-		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret
+		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
 	)
 );
 
@@ -606,10 +623,9 @@
 
 TRACE_EVENT(drv_conf_tx,
 	TP_PROTO(struct ieee80211_local *local, u16 queue,
-		 const struct ieee80211_tx_queue_params *params,
-		 int ret),
+		 const struct ieee80211_tx_queue_params *params),
 
-	TP_ARGS(local, queue, params, ret),
+	TP_ARGS(local, queue, params),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
@@ -618,13 +634,11 @@
 		__field(u16, cw_min)
 		__field(u16, cw_max)
 		__field(u8, aifs)
-		__field(int, ret)
 	),
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
 		__entry->queue = queue;
-		__entry->ret = ret;
 		__entry->txop = params->txop;
 		__entry->cw_max = params->cw_max;
 		__entry->cw_min = params->cw_min;
@@ -632,29 +646,27 @@
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT " queue:%d ret:%d",
-		LOCAL_PR_ARG, __entry->queue, __entry->ret
+		LOCAL_PR_FMT " queue:%d",
+		LOCAL_PR_ARG, __entry->queue
 	)
 );
 
 TRACE_EVENT(drv_get_tsf,
-	TP_PROTO(struct ieee80211_local *local, u64 ret),
+	TP_PROTO(struct ieee80211_local *local),
 
-	TP_ARGS(local, ret),
+	TP_ARGS(local),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
-		__field(u64, ret)
 	),
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
-		__entry->ret = ret;
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT " ret:%llu",
-		LOCAL_PR_ARG, (unsigned long long)__entry->ret
+		LOCAL_PR_FMT,
+		LOCAL_PR_ARG
 	)
 );
 
@@ -698,23 +710,21 @@
 );
 
 TRACE_EVENT(drv_tx_last_beacon,
-	TP_PROTO(struct ieee80211_local *local, int ret),
+	TP_PROTO(struct ieee80211_local *local),
 
-	TP_ARGS(local, ret),
+	TP_ARGS(local),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
-		__field(int, ret)
 	),
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
-		__entry->ret = ret;
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT " ret:%d",
-		LOCAL_PR_ARG, __entry->ret
+		LOCAL_PR_FMT,
+		LOCAL_PR_ARG
 	)
 );
 
@@ -723,9 +733,9 @@
 		 struct ieee80211_sub_if_data *sdata,
 		 enum ieee80211_ampdu_mlme_action action,
 		 struct ieee80211_sta *sta, u16 tid,
-		 u16 *ssn, int ret),
+		 u16 *ssn),
 
-	TP_ARGS(local, sdata, action, sta, tid, ssn, ret),
+	TP_ARGS(local, sdata, action, sta, tid, ssn),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
@@ -733,7 +743,6 @@
 		__field(u32, action)
 		__field(u16, tid)
 		__field(u16, ssn)
-		__field(int, ret)
 		VIF_ENTRY
 	),
 
@@ -741,15 +750,36 @@
 		LOCAL_ASSIGN;
 		VIF_ASSIGN;
 		STA_ASSIGN;
-		__entry->ret = ret;
 		__entry->action = action;
 		__entry->tid = tid;
 		__entry->ssn = ssn ? *ssn : 0;
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d",
-		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
+		LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d",
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid
+	)
+);
+
+TRACE_EVENT(drv_get_survey,
+	TP_PROTO(struct ieee80211_local *local, int idx,
+		 struct survey_info *survey),
+
+	TP_ARGS(local, idx, survey),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(int, idx)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->idx = idx;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " idx:%d",
+		LOCAL_PR_ARG, __entry->idx
 	)
 );
 
@@ -851,25 +881,23 @@
 );
 
 TRACE_EVENT(api_stop_tx_ba_session,
-	TP_PROTO(struct ieee80211_sta *sta, u16 tid, u16 initiator),
+	TP_PROTO(struct ieee80211_sta *sta, u16 tid),
 
-	TP_ARGS(sta, tid, initiator),
+	TP_ARGS(sta, tid),
 
 	TP_STRUCT__entry(
 		STA_ENTRY
 		__field(u16, tid)
-		__field(u16, initiator)
 	),
 
 	TP_fast_assign(
 		STA_ASSIGN;
 		__entry->tid = tid;
-		__entry->initiator = initiator;
 	),
 
 	TP_printk(
-		STA_PR_FMT " tid:%d initiator:%d",
-		STA_PR_ARG, __entry->tid, __entry->initiator
+		STA_PR_FMT " tid:%d",
+		STA_PR_ARG, __entry->tid
 	)
 );
 
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 2ab106a..9d101fb 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -6,7 +6,7 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
- * Copyright 2007-2008, Intel Corporation
+ * Copyright 2007-2010, 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
@@ -29,7 +29,7 @@
 
 	memset(ht_cap, 0, sizeof(*ht_cap));
 
-	if (!ht_cap_ie)
+	if (!ht_cap_ie || !sband->ht_cap.ht_supported)
 		return;
 
 	ht_cap->ht_supported = true;
@@ -105,6 +105,8 @@
 {
 	int i;
 
+	cancel_work_sync(&sta->ampdu_mlme.work);
+
 	for (i = 0; i <  STA_TID_NUM; i++) {
 		__ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR);
 		__ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
@@ -112,6 +114,43 @@
 	}
 }
 
+void ieee80211_ba_session_work(struct work_struct *work)
+{
+	struct sta_info *sta =
+		container_of(work, struct sta_info, ampdu_mlme.work);
+	struct tid_ampdu_tx *tid_tx;
+	int tid;
+
+	/*
+	 * When this flag is set, new sessions should be
+	 * blocked, and existing sessions will be torn
+	 * down by the code that set the flag, so this
+	 * need not run.
+	 */
+	if (test_sta_flags(sta, WLAN_STA_BLOCK_BA))
+		return;
+
+	mutex_lock(&sta->ampdu_mlme.mtx);
+	for (tid = 0; tid < STA_TID_NUM; tid++) {
+		if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired))
+			___ieee80211_stop_rx_ba_session(
+				sta, tid, WLAN_BACK_RECIPIENT,
+				WLAN_REASON_QSTA_TIMEOUT);
+
+		tid_tx = sta->ampdu_mlme.tid_tx[tid];
+		if (!tid_tx)
+			continue;
+
+		if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state))
+			ieee80211_tx_ba_session_handle_start(sta, tid);
+		else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
+					    &tid_tx->state))
+			___ieee80211_stop_tx_ba_session(sta, tid,
+							WLAN_BACK_INITIATOR);
+	}
+	mutex_unlock(&sta->ampdu_mlme.mtx);
+}
+
 void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
 			  const u8 *da, u16 tid,
 			  u16 initiator, u16 reason_code)
@@ -176,13 +215,8 @@
 
 	if (initiator == WLAN_BACK_INITIATOR)
 		__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0);
-	else { /* WLAN_BACK_RECIPIENT */
-		spin_lock_bh(&sta->lock);
-		if (sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK)
-			___ieee80211_stop_tx_ba_session(sta, tid,
-							WLAN_BACK_RECIPIENT);
-		spin_unlock_bh(&sta->lock);
-	}
+	else
+		__ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT);
 }
 
 int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index b2cc1fd..c691780 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -43,6 +43,8 @@
 {
 	u16 auth_alg, auth_transaction, status_code;
 
+	lockdep_assert_held(&sdata->u.ibss.mtx);
+
 	if (len < 24 + 6)
 		return;
 
@@ -78,6 +80,8 @@
 	u32 bss_change;
 	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
 
+	lockdep_assert_held(&ifibss->mtx);
+
 	/* Reset own TSF to allow time synchronization work. */
 	drv_reset_tsf(local);
 
@@ -172,11 +176,13 @@
 	rcu_assign_pointer(ifibss->presp, skb);
 
 	sdata->vif.bss_conf.beacon_int = beacon_int;
+	sdata->vif.bss_conf.basic_rates = basic_rates;
 	bss_change = BSS_CHANGED_BEACON_INT;
 	bss_change |= ieee80211_reset_erp_info(sdata);
 	bss_change |= BSS_CHANGED_BSSID;
 	bss_change |= BSS_CHANGED_BEACON;
 	bss_change |= BSS_CHANGED_BEACON_ENABLED;
+	bss_change |= BSS_CHANGED_BASIC_RATES;
 	bss_change |= BSS_CHANGED_IBSS;
 	sdata->vif.bss_conf.ibss_joined = true;
 	ieee80211_bss_info_change_notify(sdata, bss_change);
@@ -203,6 +209,8 @@
 	int i, j;
 	u16 beacon_int = cbss->beacon_interval;
 
+	lockdep_assert_held(&sdata->u.ibss.mtx);
+
 	if (beacon_int < 10)
 		beacon_int = 10;
 
@@ -447,6 +455,8 @@
 	int active = 0;
 	struct sta_info *sta;
 
+	lockdep_assert_held(&sdata->u.ibss.mtx);
+
 	rcu_read_lock();
 
 	list_for_each_entry_rcu(sta, &local->sta_list, list) {
@@ -471,6 +481,8 @@
 {
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 
+	lockdep_assert_held(&ifibss->mtx);
+
 	mod_timer(&ifibss->timer,
 		  round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
 
@@ -503,6 +515,8 @@
 	u16 capability;
 	int i;
 
+	lockdep_assert_held(&ifibss->mtx);
+
 	if (ifibss->fixed_bssid) {
 		memcpy(bssid, ifibss->bssid, ETH_ALEN);
 	} else {
@@ -529,7 +543,7 @@
 		sdata->drop_unencrypted = 0;
 
 	__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
-				  ifibss->channel, 3, /* first two are basic */
+				  ifibss->channel, ifibss->basic_rates,
 				  capability, 0);
 }
 
@@ -547,6 +561,8 @@
 	int active_ibss;
 	u16 capability;
 
+	lockdep_assert_held(&ifibss->mtx);
+
 	active_ibss = ieee80211_sta_active_ibss(sdata);
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 	printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
@@ -635,6 +651,8 @@
 	struct ieee80211_mgmt *resp;
 	u8 *pos, *end;
 
+	lockdep_assert_held(&ifibss->mtx);
+
 	if (ifibss->state != IEEE80211_IBSS_MLME_JOINED ||
 	    len < 24 + 2 || !ifibss->presp)
 		return;
@@ -727,8 +745,8 @@
 	ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
 }
 
-static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
-					  struct sk_buff *skb)
+void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+				   struct sk_buff *skb)
 {
 	struct ieee80211_rx_status *rx_status;
 	struct ieee80211_mgmt *mgmt;
@@ -738,6 +756,8 @@
 	mgmt = (struct ieee80211_mgmt *) skb->data;
 	fc = le16_to_cpu(mgmt->frame_control);
 
+	mutex_lock(&sdata->u.ibss.mtx);
+
 	switch (fc & IEEE80211_FCTL_STYPE) {
 	case IEEE80211_STYPE_PROBE_REQ:
 		ieee80211_rx_mgmt_probe_req(sdata, mgmt, skb->len);
@@ -755,35 +775,22 @@
 		break;
 	}
 
-	kfree_skb(skb);
+	mutex_unlock(&sdata->u.ibss.mtx);
 }
 
-static void ieee80211_ibss_work(struct work_struct *work)
+void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata =
-		container_of(work, struct ieee80211_sub_if_data, u.ibss.work);
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_if_ibss *ifibss;
-	struct sk_buff *skb;
+	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 
-	if (WARN_ON(local->suspended))
-		return;
+	mutex_lock(&ifibss->mtx);
 
-	if (!ieee80211_sdata_running(sdata))
-		return;
-
-	if (local->scanning)
-		return;
-
-	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC))
-		return;
-	ifibss = &sdata->u.ibss;
-
-	while ((skb = skb_dequeue(&ifibss->skb_queue)))
-		ieee80211_ibss_rx_queued_mgmt(sdata, skb);
-
-	if (!test_and_clear_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request))
-		return;
+	/*
+	 * Work could be scheduled after scan or similar
+	 * when we aren't even joined (or trying) with a
+	 * network.
+	 */
+	if (!ifibss->ssid_len)
+		goto out;
 
 	switch (ifibss->state) {
 	case IEEE80211_IBSS_MLME_SEARCH:
@@ -796,6 +803,9 @@
 		WARN_ON(1);
 		break;
 	}
+
+ out:
+	mutex_unlock(&ifibss->mtx);
 }
 
 static void ieee80211_ibss_timer(unsigned long data)
@@ -810,8 +820,7 @@
 		return;
 	}
 
-	set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request);
-	ieee80211_queue_work(&local->hw, &ifibss->work);
+	ieee80211_queue_work(&local->hw, &sdata->work);
 }
 
 #ifdef CONFIG_PM
@@ -819,7 +828,6 @@
 {
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 
-	cancel_work_sync(&ifibss->work);
 	if (del_timer_sync(&ifibss->timer))
 		ifibss->timer_running = true;
 }
@@ -839,10 +847,9 @@
 {
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 
-	INIT_WORK(&ifibss->work, ieee80211_ibss_work);
 	setup_timer(&ifibss->timer, ieee80211_ibss_timer,
 		    (unsigned long) sdata);
-	skb_queue_head_init(&ifibss->skb_queue);
+	mutex_init(&ifibss->mtx);
 }
 
 /* scan finished notification */
@@ -856,45 +863,28 @@
 			continue;
 		if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
 			continue;
-		if (!sdata->u.ibss.ssid_len)
-			continue;
 		sdata->u.ibss.last_scan_completed = jiffies;
-		mod_timer(&sdata->u.ibss.timer, 0);
+		ieee80211_queue_work(&local->hw, &sdata->work);
 	}
 	mutex_unlock(&local->iflist_mtx);
 }
 
-ieee80211_rx_result
-ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_mgmt *mgmt;
-	u16 fc;
-
-	if (skb->len < 24)
-		return RX_DROP_MONITOR;
-
-	mgmt = (struct ieee80211_mgmt *) skb->data;
-	fc = le16_to_cpu(mgmt->frame_control);
-
-	switch (fc & IEEE80211_FCTL_STYPE) {
-	case IEEE80211_STYPE_PROBE_RESP:
-	case IEEE80211_STYPE_BEACON:
-	case IEEE80211_STYPE_PROBE_REQ:
-	case IEEE80211_STYPE_AUTH:
-		skb_queue_tail(&sdata->u.ibss.skb_queue, skb);
-		ieee80211_queue_work(&local->hw, &sdata->u.ibss.work);
-		return RX_QUEUED;
-	}
-
-	return RX_DROP_MONITOR;
-}
-
 int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
 			struct cfg80211_ibss_params *params)
 {
 	struct sk_buff *skb;
 
+	skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
+			    36 /* bitrates */ +
+			    34 /* SSID */ +
+			    3  /* DS params */ +
+			    4  /* IBSS params */ +
+			    params->ie_len);
+	if (!skb)
+		return -ENOMEM;
+
+	mutex_lock(&sdata->u.ibss.mtx);
+
 	if (params->bssid) {
 		memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);
 		sdata->u.ibss.fixed_bssid = true;
@@ -902,6 +892,7 @@
 		sdata->u.ibss.fixed_bssid = false;
 
 	sdata->u.ibss.privacy = params->privacy;
+	sdata->u.ibss.basic_rates = params->basic_rates;
 
 	sdata->vif.bss_conf.beacon_int = params->beacon_interval;
 
@@ -922,34 +913,18 @@
 			sdata->u.ibss.ie_len = params->ie_len;
 	}
 
-	skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
-			    36 /* bitrates */ +
-			    34 /* SSID */ +
-			    3  /* DS params */ +
-			    4  /* IBSS params */ +
-			    params->ie_len);
-	if (!skb)
-		return -ENOMEM;
-
 	sdata->u.ibss.skb = skb;
 	sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH;
 	sdata->u.ibss.ibss_join_req = jiffies;
 
 	memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN);
-
-	/*
-	 * The ssid_len setting below is used to see whether
-	 * we are active, and we need all other settings
-	 * before that may get visible.
-	 */
-	mb();
-
 	sdata->u.ibss.ssid_len = params->ssid_len;
 
 	ieee80211_recalc_idle(sdata->local);
 
-	set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
-	ieee80211_queue_work(&sdata->local->hw, &sdata->u.ibss.work);
+	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+
+	mutex_unlock(&sdata->u.ibss.mtx);
 
 	return 0;
 }
@@ -957,11 +932,33 @@
 int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
 {
 	struct sk_buff *skb;
+	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+	struct ieee80211_local *local = sdata->local;
+	struct cfg80211_bss *cbss;
+	u16 capability;
+	int active_ibss;
 
-	del_timer_sync(&sdata->u.ibss.timer);
-	clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
-	cancel_work_sync(&sdata->u.ibss.work);
-	clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
+	mutex_lock(&sdata->u.ibss.mtx);
+
+	active_ibss = ieee80211_sta_active_ibss(sdata);
+
+	if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
+		capability = WLAN_CAPABILITY_IBSS;
+
+		if (ifibss->privacy)
+			capability |= WLAN_CAPABILITY_PRIVACY;
+
+		cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->channel,
+					ifibss->bssid, ifibss->ssid,
+					ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
+					WLAN_CAPABILITY_PRIVACY,
+					capability);
+
+		if (cbss) {
+			cfg80211_unlink_bss(local->hw.wiphy, cbss);
+			cfg80211_put_bss(cbss);
+		}
+	}
 
 	sta_info_flush(sdata->local, sdata);
 
@@ -975,10 +972,14 @@
 	synchronize_rcu();
 	kfree_skb(skb);
 
-	skb_queue_purge(&sdata->u.ibss.skb_queue);
+	skb_queue_purge(&sdata->skb_queue);
 	memset(sdata->u.ibss.bssid, 0, ETH_ALEN);
 	sdata->u.ibss.ssid_len = 0;
 
+	del_timer_sync(&sdata->u.ibss.timer);
+
+	mutex_unlock(&sdata->u.ibss.mtx);
+
 	ieee80211_recalc_idle(sdata->local);
 
 	return 0;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 1a9e2da..65e0ed6 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -238,6 +238,7 @@
 	IEEE80211_WORK_ABORT,
 	IEEE80211_WORK_DIRECT_PROBE,
 	IEEE80211_WORK_AUTH,
+	IEEE80211_WORK_ASSOC_BEACON_WAIT,
 	IEEE80211_WORK_ASSOC,
 	IEEE80211_WORK_REMAIN_ON_CHANNEL,
 };
@@ -325,7 +326,6 @@
 	struct timer_list conn_mon_timer;
 	struct timer_list bcn_mon_timer;
 	struct timer_list chswitch_timer;
-	struct work_struct work;
 	struct work_struct monitor_work;
 	struct work_struct chswitch_work;
 	struct work_struct beacon_connection_loss_work;
@@ -340,8 +340,6 @@
 
 	u16 aid;
 
-	struct sk_buff_head skb_queue;
-
 	unsigned long timers_running; /* used for quiesce/restart */
 	bool powersave; /* powersave requested for this iface */
 	enum ieee80211_smps_mode req_smps, /* requested smps mode */
@@ -380,19 +378,15 @@
 	int last_cqm_event_signal;
 };
 
-enum ieee80211_ibss_request {
-	IEEE80211_IBSS_REQ_RUN	= 0,
-};
-
 struct ieee80211_if_ibss {
 	struct timer_list timer;
-	struct work_struct work;
 
-	struct sk_buff_head skb_queue;
+	struct mutex mtx;
 
-	unsigned long request;
 	unsigned long last_scan_completed;
 
+	u32 basic_rates;
+
 	bool timer_running;
 
 	bool fixed_bssid;
@@ -416,11 +410,9 @@
 };
 
 struct ieee80211_if_mesh {
-	struct work_struct work;
 	struct timer_list housekeeping_timer;
 	struct timer_list mesh_path_timer;
 	struct timer_list mesh_path_root_timer;
-	struct sk_buff_head skb_queue;
 
 	unsigned long timers_running;
 
@@ -517,6 +509,11 @@
 
 	u16 sequence_number;
 
+	struct work_struct work;
+	struct sk_buff_head skb_queue;
+
+	bool arp_filter_state;
+
 	/*
 	 * AP this belongs to: self in AP mode and
 	 * corresponding AP in VLAN mode, NULL for
@@ -569,11 +566,15 @@
 #endif
 }
 
+enum sdata_queue_type {
+	IEEE80211_SDATA_QUEUE_TYPE_FRAME	= 0,
+	IEEE80211_SDATA_QUEUE_AGG_START		= 1,
+	IEEE80211_SDATA_QUEUE_AGG_STOP		= 2,
+};
+
 enum {
 	IEEE80211_RX_MSG	= 1,
 	IEEE80211_TX_STATUS_MSG	= 2,
-	IEEE80211_DELBA_MSG	= 3,
-	IEEE80211_ADDBA_MSG	= 4,
 };
 
 enum queue_stop_reason {
@@ -724,13 +725,7 @@
 	struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
 	struct tasklet_struct tx_pending_tasklet;
 
-	/*
-	 * This lock is used to prevent concurrent A-MPDU
-	 * session start/stop processing, this thus also
-	 * synchronises the ->ampdu_action() callback to
-	 * drivers and limits it to one at a time.
-	 */
-	spinlock_t ampdu_lock;
+	atomic_t agg_queue_stop[IEEE80211_MAX_QUEUES];
 
 	/* number of interfaces with corresponding IFF_ flags */
 	atomic_t iff_allmultis, iff_promiscs;
@@ -746,10 +741,10 @@
 	struct mutex iflist_mtx;
 
 	/*
-	 * Key lock, protects sdata's key_list and sta_info's
+	 * Key mutex, protects sdata's key_list and sta_info's
 	 * key pointers (write access, they're RCU.)
 	 */
-	spinlock_t key_lock;
+	struct mutex key_mtx;
 
 
 	/* Scanning and BSS list */
@@ -851,6 +846,15 @@
 	struct work_struct dynamic_ps_disable_work;
 	struct timer_list dynamic_ps_timer;
 	struct notifier_block network_latency_notifier;
+	struct notifier_block ifa_notifier;
+
+	/*
+	 * The dynamic ps timeout configured from user space via WEXT -
+	 * this will override whatever chosen by mac80211 internally.
+	 */
+	int dynamic_ps_forced_timeout;
+	int dynamic_ps_user_timeout;
+	bool disable_dynamic_ps;
 
 	int user_power_level; /* in dBm */
 	int power_constr_level; /* in dBm */
@@ -874,9 +878,8 @@
 	return netdev_priv(dev);
 }
 
-/* this struct represents 802.11n's RA/TID combination along with our vif */
+/* this struct represents 802.11n's RA/TID combination */
 struct ieee80211_ra_tid {
-	struct ieee80211_vif *vif;
 	u8 ra[ETH_ALEN];
 	u16 tid;
 };
@@ -985,29 +988,25 @@
 int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
 			   struct cfg80211_disassoc_request *req,
 			   void *cookie);
-int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
-			 struct ieee80211_channel *chan,
-			 enum nl80211_channel_type channel_type,
-			 const u8 *buf, size_t len, u64 *cookie);
-ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
-					  struct sk_buff *skb);
 void ieee80211_send_pspoll(struct ieee80211_local *local,
 			   struct ieee80211_sub_if_data *sdata);
 void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
 int ieee80211_max_network_latency(struct notifier_block *nb,
 				  unsigned long data, void *dummy);
+int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata);
 void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 				      struct ieee80211_channel_sw_ie *sw_elem,
 				      struct ieee80211_bss *bss,
 				      u64 timestamp);
 void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata);
 void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
+void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata);
+void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+				  struct sk_buff *skb);
 
 /* IBSS code */
 void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
 void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata);
-ieee80211_rx_result
-ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
 struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
 					u8 *bssid, u8 *addr, u32 supp_rates,
 					gfp_t gfp);
@@ -1016,6 +1015,14 @@
 int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
 void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata);
 void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata);
+void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata);
+void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+				   struct sk_buff *skb);
+
+/* mesh code */
+void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
+void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+				   struct sk_buff *skb);
 
 /* scan/BSS handling */
 void ieee80211_scan_work(struct work_struct *work);
@@ -1084,7 +1091,7 @@
 	u8 padding_for_rate;
 	__le16 tx_flags;
 	u8 data_retries;
-} __attribute__ ((packed));
+} __packed;
 
 
 /* HT */
@@ -1099,6 +1106,8 @@
 			       enum ieee80211_smps_mode smps, const u8 *da,
 			       const u8 *bssid);
 
+void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+				     u16 initiator, u16 reason);
 void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 				    u16 initiator, u16 reason);
 void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta);
@@ -1118,6 +1127,10 @@
 				   enum ieee80211_back_parties initiator);
 int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 				    enum ieee80211_back_parties initiator);
+void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
+void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
+void ieee80211_ba_session_work(struct work_struct *work);
+void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid);
 
 /* Spectrum management */
 void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 50deb01..ebbe264 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -249,6 +249,8 @@
 			local->fif_other_bss++;
 
 		ieee80211_configure_filter(local);
+
+		netif_carrier_on(dev);
 		break;
 	default:
 		res = drv_add_interface(local, &sdata->vif);
@@ -268,7 +270,6 @@
 
 		changed |= ieee80211_reset_erp_info(sdata);
 		ieee80211_bss_info_change_notify(sdata, changed);
-		ieee80211_enable_keys(sdata);
 
 		if (sdata->vif.type == NL80211_IFTYPE_STATION)
 			netif_carrier_off(dev);
@@ -321,15 +322,6 @@
 
 	ieee80211_recalc_ps(local, -1);
 
-	/*
-	 * ieee80211_sta_work is disabled while network interface
-	 * is down. Therefore, some configuration changes may not
-	 * yet be effective. Trigger execution of ieee80211_sta_work
-	 * to fix this.
-	 */
-	if (sdata->vif.type == NL80211_IFTYPE_STATION)
-		ieee80211_queue_work(&local->hw, &sdata->u.mgd.work);
-
 	netif_tx_start_all_queues(dev);
 
 	return 0;
@@ -349,7 +341,6 @@
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
-	struct sta_info *sta;
 	unsigned long flags;
 	struct sk_buff *skb, *tmp;
 	u32 hw_reconf_flags = 0;
@@ -366,18 +357,6 @@
 	ieee80211_work_purge(sdata);
 
 	/*
-	 * Now delete all active aggregation sessions.
-	 */
-	rcu_read_lock();
-
-	list_for_each_entry_rcu(sta, &local->sta_list, list) {
-		if (sta->sdata == sdata)
-			ieee80211_sta_tear_down_BA_sessions(sta);
-	}
-
-	rcu_read_unlock();
-
-	/*
 	 * Remove all stations associated with this interface.
 	 *
 	 * This must be done before calling ops->remove_interface()
@@ -483,27 +462,14 @@
 		 * whether the interface is running, which, at this point,
 		 * it no longer is.
 		 */
-		cancel_work_sync(&sdata->u.mgd.work);
 		cancel_work_sync(&sdata->u.mgd.chswitch_work);
 		cancel_work_sync(&sdata->u.mgd.monitor_work);
 		cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work);
 
-		/*
-		 * When we get here, the interface is marked down.
-		 * Call synchronize_rcu() to wait for the RX path
-		 * should it be using the interface and enqueuing
-		 * frames at this very time on another CPU.
-		 */
-		synchronize_rcu();
-		skb_queue_purge(&sdata->u.mgd.skb_queue);
 		/* fall through */
 	case NL80211_IFTYPE_ADHOC:
-		if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+		if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
 			del_timer_sync(&sdata->u.ibss.timer);
-			cancel_work_sync(&sdata->u.ibss.work);
-			synchronize_rcu();
-			skb_queue_purge(&sdata->u.ibss.skb_queue);
-		}
 		/* fall through */
 	case NL80211_IFTYPE_MESH_POINT:
 		if (ieee80211_vif_is_mesh(&sdata->vif)) {
@@ -518,6 +484,16 @@
 		}
 		/* fall through */
 	default:
+		flush_work(&sdata->work);
+		/*
+		 * When we get here, the interface is marked down.
+		 * Call synchronize_rcu() to wait for the RX path
+		 * should it be using the interface and enqueuing
+		 * frames at this very time on another CPU.
+		 */
+		synchronize_rcu();
+		skb_queue_purge(&sdata->skb_queue);
+
 		if (local->scan_sdata == sdata)
 			ieee80211_scan_cancel(local);
 
@@ -531,8 +507,8 @@
 				BSS_CHANGED_BEACON_ENABLED);
 		}
 
-		/* disable all keys for as long as this netdev is down */
-		ieee80211_disable_keys(sdata);
+		/* free all remaining keys, there shouldn't be any */
+		ieee80211_free_keys(sdata);
 		drv_remove_interface(local, &sdata->vif);
 	}
 
@@ -727,6 +703,136 @@
 	dev->destructor = free_netdev;
 }
 
+static void ieee80211_iface_work(struct work_struct *work)
+{
+	struct ieee80211_sub_if_data *sdata =
+		container_of(work, struct ieee80211_sub_if_data, work);
+	struct ieee80211_local *local = sdata->local;
+	struct sk_buff *skb;
+	struct sta_info *sta;
+	struct ieee80211_ra_tid *ra_tid;
+
+	if (!ieee80211_sdata_running(sdata))
+		return;
+
+	if (local->scanning)
+		return;
+
+	/*
+	 * ieee80211_queue_work() should have picked up most cases,
+	 * here we'll pick the rest.
+	 */
+	if (WARN(local->suspended,
+		 "interface work scheduled while going to suspend\n"))
+		return;
+
+	/* first process frames */
+	while ((skb = skb_dequeue(&sdata->skb_queue))) {
+		struct ieee80211_mgmt *mgmt = (void *)skb->data;
+
+		if (skb->pkt_type == IEEE80211_SDATA_QUEUE_AGG_START) {
+			ra_tid = (void *)&skb->cb;
+			ieee80211_start_tx_ba_cb(&sdata->vif, ra_tid->ra,
+						 ra_tid->tid);
+		} else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_AGG_STOP) {
+			ra_tid = (void *)&skb->cb;
+			ieee80211_stop_tx_ba_cb(&sdata->vif, ra_tid->ra,
+						ra_tid->tid);
+		} else if (ieee80211_is_action(mgmt->frame_control) &&
+			   mgmt->u.action.category == WLAN_CATEGORY_BACK) {
+			int len = skb->len;
+
+			mutex_lock(&local->sta_mtx);
+			sta = sta_info_get_bss(sdata, mgmt->sa);
+			if (sta) {
+				switch (mgmt->u.action.u.addba_req.action_code) {
+				case WLAN_ACTION_ADDBA_REQ:
+					ieee80211_process_addba_request(
+							local, sta, mgmt, len);
+					break;
+				case WLAN_ACTION_ADDBA_RESP:
+					ieee80211_process_addba_resp(local, sta,
+								     mgmt, len);
+					break;
+				case WLAN_ACTION_DELBA:
+					ieee80211_process_delba(sdata, sta,
+								mgmt, len);
+					break;
+				default:
+					WARN_ON(1);
+					break;
+				}
+			}
+			mutex_unlock(&local->sta_mtx);
+		} else if (ieee80211_is_data_qos(mgmt->frame_control)) {
+			struct ieee80211_hdr *hdr = (void *)mgmt;
+			/*
+			 * So the frame isn't mgmt, but frame_control
+			 * is at the right place anyway, of course, so
+			 * the if statement is correct.
+			 *
+			 * Warn if we have other data frame types here,
+			 * they must not get here.
+			 */
+			WARN_ON(hdr->frame_control &
+					cpu_to_le16(IEEE80211_STYPE_NULLFUNC));
+			WARN_ON(!(hdr->seq_ctrl &
+					cpu_to_le16(IEEE80211_SCTL_FRAG)));
+			/*
+			 * This was a fragment of a frame, received while
+			 * a block-ack session was active. That cannot be
+			 * right, so terminate the session.
+			 */
+			mutex_lock(&local->sta_mtx);
+			sta = sta_info_get_bss(sdata, mgmt->sa);
+			if (sta) {
+				u16 tid = *ieee80211_get_qos_ctl(hdr) &
+						IEEE80211_QOS_CTL_TID_MASK;
+
+				__ieee80211_stop_rx_ba_session(
+					sta, tid, WLAN_BACK_RECIPIENT,
+					WLAN_REASON_QSTA_REQUIRE_SETUP);
+			}
+			mutex_unlock(&local->sta_mtx);
+		} else switch (sdata->vif.type) {
+		case NL80211_IFTYPE_STATION:
+			ieee80211_sta_rx_queued_mgmt(sdata, skb);
+			break;
+		case NL80211_IFTYPE_ADHOC:
+			ieee80211_ibss_rx_queued_mgmt(sdata, skb);
+			break;
+		case NL80211_IFTYPE_MESH_POINT:
+			if (!ieee80211_vif_is_mesh(&sdata->vif))
+				break;
+			ieee80211_mesh_rx_queued_mgmt(sdata, skb);
+			break;
+		default:
+			WARN(1, "frame for unexpected interface type");
+			break;
+		}
+
+		kfree_skb(skb);
+	}
+
+	/* then other type-dependent work */
+	switch (sdata->vif.type) {
+	case NL80211_IFTYPE_STATION:
+		ieee80211_sta_work(sdata);
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		ieee80211_ibss_work(sdata);
+		break;
+	case NL80211_IFTYPE_MESH_POINT:
+		if (!ieee80211_vif_is_mesh(&sdata->vif))
+			break;
+		ieee80211_mesh_work(sdata);
+		break;
+	default:
+		break;
+	}
+}
+
+
 /*
  * Helper function to initialise an interface to a specific type.
  */
@@ -744,6 +850,9 @@
 	/* only monitor differs */
 	sdata->dev->type = ARPHRD_ETHER;
 
+	skb_queue_head_init(&sdata->skb_queue);
+	INIT_WORK(&sdata->work, ieee80211_iface_work);
+
 	switch (type) {
 	case NL80211_IFTYPE_AP:
 		skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
@@ -969,6 +1078,9 @@
 	sdata->wdev.wiphy = local->hw.wiphy;
 	sdata->local = local;
 	sdata->dev = ndev;
+#ifdef CONFIG_INET
+	sdata->arp_filter_state = true;
+#endif
 
 	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
 		skb_queue_head_init(&sdata->fragments[i].skb_list);
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index e8f6e3b..1b9d87e 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -36,80 +36,20 @@
  * There is currently no way of knowing this except by looking into
  * debugfs.
  *
- * All key operations are protected internally so you can call them at
- * any time.
+ * All key operations are protected internally.
  *
  * Within mac80211, key references are, just as STA structure references,
  * protected by RCU. Note, however, that some things are unprotected,
  * namely the key->sta dereferences within the hardware acceleration
- * functions. This means that sta_info_destroy() must flush the key todo
- * list.
- *
- * All the direct key list manipulation functions must not sleep because
- * they can operate on STA info structs that are protected by RCU.
+ * functions. This means that sta_info_destroy() must remove the key
+ * which waits for an RCU grace period.
  */
 
 static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
-/* key mutex: used to synchronise todo runners */
-static DEFINE_MUTEX(key_mutex);
-static DEFINE_SPINLOCK(todo_lock);
-static LIST_HEAD(todo_list);
-
-static void key_todo(struct work_struct *work)
+static void assert_key_lock(struct ieee80211_local *local)
 {
-	ieee80211_key_todo();
-}
-
-static DECLARE_WORK(todo_work, key_todo);
-
-/**
- * add_todo - add todo item for a key
- *
- * @key: key to add to do item for
- * @flag: todo flag(s)
- *
- * Must be called with IRQs or softirqs disabled.
- */
-static void add_todo(struct ieee80211_key *key, u32 flag)
-{
-	if (!key)
-		return;
-
-	spin_lock(&todo_lock);
-	key->flags |= flag;
-	/*
-	 * Remove again if already on the list so that we move it to the end.
-	 */
-	if (!list_empty(&key->todo))
-		list_del(&key->todo);
-	list_add_tail(&key->todo, &todo_list);
-	schedule_work(&todo_work);
-	spin_unlock(&todo_lock);
-}
-
-/**
- * ieee80211_key_lock - lock the mac80211 key operation lock
- *
- * This locks the (global) mac80211 key operation lock, all
- * key operations must be done under this lock.
- */
-static void ieee80211_key_lock(void)
-{
-	mutex_lock(&key_mutex);
-}
-
-/**
- * ieee80211_key_unlock - unlock the mac80211 key operation lock
- */
-static void ieee80211_key_unlock(void)
-{
-	mutex_unlock(&key_mutex);
-}
-
-static void assert_key_lock(void)
-{
-	WARN_ON(!mutex_is_locked(&key_mutex));
+	WARN_ON(!mutex_is_locked(&local->key_mtx));
 }
 
 static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
@@ -126,12 +66,13 @@
 	struct ieee80211_sta *sta;
 	int ret;
 
-	assert_key_lock();
 	might_sleep();
 
 	if (!key->local->ops->set_key)
 		return;
 
+	assert_key_lock(key->local);
+
 	sta = get_sta_for_key(key);
 
 	sdata = key->sdata;
@@ -142,11 +83,8 @@
 
 	ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
 
-	if (!ret) {
-		spin_lock_bh(&todo_lock);
+	if (!ret)
 		key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
-		spin_unlock_bh(&todo_lock);
-	}
 
 	if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
 		printk(KERN_ERR "mac80211-%s: failed to set key "
@@ -161,18 +99,15 @@
 	struct ieee80211_sta *sta;
 	int ret;
 
-	assert_key_lock();
 	might_sleep();
 
 	if (!key || !key->local->ops->set_key)
 		return;
 
-	spin_lock_bh(&todo_lock);
-	if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
-		spin_unlock_bh(&todo_lock);
+	assert_key_lock(key->local);
+
+	if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
 		return;
-	}
-	spin_unlock_bh(&todo_lock);
 
 	sta = get_sta_for_key(key);
 	sdata = key->sdata;
@@ -191,9 +126,7 @@
 		       wiphy_name(key->local->hw.wiphy),
 		       key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
 
-	spin_lock_bh(&todo_lock);
 	key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
-	spin_unlock_bh(&todo_lock);
 }
 
 static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
@@ -201,22 +134,24 @@
 {
 	struct ieee80211_key *key = NULL;
 
+	assert_key_lock(sdata->local);
+
 	if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
 		key = sdata->keys[idx];
 
 	rcu_assign_pointer(sdata->default_key, key);
 
-	if (key)
-		add_todo(key, KEY_FLAG_TODO_DEFKEY);
+	if (key) {
+		ieee80211_debugfs_key_remove_default(key->sdata);
+		ieee80211_debugfs_key_add_default(key->sdata);
+	}
 }
 
 void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&sdata->local->key_lock, flags);
+	mutex_lock(&sdata->local->key_mtx);
 	__ieee80211_set_default_key(sdata, idx);
-	spin_unlock_irqrestore(&sdata->local->key_lock, flags);
+	mutex_unlock(&sdata->local->key_mtx);
 }
 
 static void
@@ -224,24 +159,26 @@
 {
 	struct ieee80211_key *key = NULL;
 
+	assert_key_lock(sdata->local);
+
 	if (idx >= NUM_DEFAULT_KEYS &&
 	    idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
 		key = sdata->keys[idx];
 
 	rcu_assign_pointer(sdata->default_mgmt_key, key);
 
-	if (key)
-		add_todo(key, KEY_FLAG_TODO_DEFMGMTKEY);
+	if (key) {
+		ieee80211_debugfs_key_remove_mgmt_default(key->sdata);
+		ieee80211_debugfs_key_add_mgmt_default(key->sdata);
+	}
 }
 
 void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
 				    int idx)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&sdata->local->key_lock, flags);
+	mutex_lock(&sdata->local->key_mtx);
 	__ieee80211_set_default_mgmt_key(sdata, idx);
-	spin_unlock_irqrestore(&sdata->local->key_lock, flags);
+	mutex_unlock(&sdata->local->key_mtx);
 }
 
 
@@ -336,7 +273,7 @@
 		key->conf.iv_len = CCMP_HDR_LEN;
 		key->conf.icv_len = CCMP_MIC_LEN;
 		if (seq) {
-			for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+			for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++)
 				for (j = 0; j < CCMP_PN_LEN; j++)
 					key->u.ccmp.rx_pn[i][j] =
 						seq[CCMP_PN_LEN - j - 1];
@@ -352,7 +289,6 @@
 	}
 	memcpy(key->conf.key, key_data, key_len);
 	INIT_LIST_HEAD(&key->list);
-	INIT_LIST_HEAD(&key->todo);
 
 	if (alg == ALG_CCMP) {
 		/*
@@ -382,12 +318,29 @@
 	return key;
 }
 
+static void __ieee80211_key_destroy(struct ieee80211_key *key)
+{
+	if (!key)
+		return;
+
+	if (key->local)
+		ieee80211_key_disable_hw_accel(key);
+
+	if (key->conf.alg == ALG_CCMP)
+		ieee80211_aes_key_free(key->u.ccmp.tfm);
+	if (key->conf.alg == ALG_AES_CMAC)
+		ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
+	if (key->local)
+		ieee80211_debugfs_key_remove(key);
+
+	kfree(key);
+}
+
 void ieee80211_key_link(struct ieee80211_key *key,
 			struct ieee80211_sub_if_data *sdata,
 			struct sta_info *sta)
 {
 	struct ieee80211_key *old_key;
-	unsigned long flags;
 	int idx;
 
 	BUG_ON(!sdata);
@@ -431,7 +384,7 @@
 		}
 	}
 
-	spin_lock_irqsave(&sdata->local->key_lock, flags);
+	mutex_lock(&sdata->local->key_mtx);
 
 	if (sta)
 		old_key = sta->key;
@@ -439,15 +392,13 @@
 		old_key = sdata->keys[idx];
 
 	__ieee80211_key_replace(sdata, sta, old_key, key);
+	__ieee80211_key_destroy(old_key);
 
-	/* free old key later */
-	add_todo(old_key, KEY_FLAG_TODO_DELETE);
+	ieee80211_debugfs_key_add(key);
 
-	add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
-	if (ieee80211_sdata_running(sdata))
-		add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
+	ieee80211_key_enable_hw_accel(key);
 
-	spin_unlock_irqrestore(&sdata->local->key_lock, flags);
+	mutex_unlock(&sdata->local->key_mtx);
 }
 
 static void __ieee80211_key_free(struct ieee80211_key *key)
@@ -458,170 +409,62 @@
 	if (key->sdata)
 		__ieee80211_key_replace(key->sdata, key->sta,
 					key, NULL);
-
-	add_todo(key, KEY_FLAG_TODO_DELETE);
+	__ieee80211_key_destroy(key);
 }
 
-void ieee80211_key_free(struct ieee80211_key *key)
+void ieee80211_key_free(struct ieee80211_local *local,
+			struct ieee80211_key *key)
 {
-	unsigned long flags;
-
 	if (!key)
 		return;
 
-	if (!key->sdata) {
-		/* The key has not been linked yet, simply free it
-		 * and don't Oops */
-		if (key->conf.alg == ALG_CCMP)
-			ieee80211_aes_key_free(key->u.ccmp.tfm);
-		kfree(key);
-		return;
-	}
-
-	spin_lock_irqsave(&key->sdata->local->key_lock, flags);
+	mutex_lock(&local->key_mtx);
 	__ieee80211_key_free(key);
-	spin_unlock_irqrestore(&key->sdata->local->key_lock, flags);
-}
-
-/*
- * To be safe against concurrent manipulations of the list (which shouldn't
- * actually happen) we need to hold the spinlock. But under the spinlock we
- * can't actually do much, so we defer processing to the todo list. Then run
- * the todo list to be sure the operation and possibly previously pending
- * operations are completed.
- */
-static void ieee80211_todo_for_each_key(struct ieee80211_sub_if_data *sdata,
-					u32 todo_flags)
-{
-	struct ieee80211_key *key;
-	unsigned long flags;
-
-	might_sleep();
-
-	spin_lock_irqsave(&sdata->local->key_lock, flags);
-	list_for_each_entry(key, &sdata->key_list, list)
-		add_todo(key, todo_flags);
-	spin_unlock_irqrestore(&sdata->local->key_lock, flags);
-
-	ieee80211_key_todo();
+	mutex_unlock(&local->key_mtx);
 }
 
 void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
 {
+	struct ieee80211_key *key;
+
 	ASSERT_RTNL();
 
 	if (WARN_ON(!ieee80211_sdata_running(sdata)))
 		return;
 
-	ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD);
+	mutex_lock(&sdata->local->key_mtx);
+
+	list_for_each_entry(key, &sdata->key_list, list)
+		ieee80211_key_enable_hw_accel(key);
+
+	mutex_unlock(&sdata->local->key_mtx);
 }
 
 void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
 {
+	struct ieee80211_key *key;
+
 	ASSERT_RTNL();
 
-	ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_REMOVE);
-}
+	mutex_lock(&sdata->local->key_mtx);
 
-static void __ieee80211_key_destroy(struct ieee80211_key *key)
-{
-	if (!key)
-		return;
+	list_for_each_entry(key, &sdata->key_list, list)
+		ieee80211_key_disable_hw_accel(key);
 
-	ieee80211_key_disable_hw_accel(key);
-
-	if (key->conf.alg == ALG_CCMP)
-		ieee80211_aes_key_free(key->u.ccmp.tfm);
-	if (key->conf.alg == ALG_AES_CMAC)
-		ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
-	ieee80211_debugfs_key_remove(key);
-
-	kfree(key);
-}
-
-static void __ieee80211_key_todo(void)
-{
-	struct ieee80211_key *key;
-	bool work_done;
-	u32 todoflags;
-
-	/*
-	 * NB: sta_info_destroy relies on this!
-	 */
-	synchronize_rcu();
-
-	spin_lock_bh(&todo_lock);
-	while (!list_empty(&todo_list)) {
-		key = list_first_entry(&todo_list, struct ieee80211_key, todo);
-		list_del_init(&key->todo);
-		todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS |
-					  KEY_FLAG_TODO_DEFKEY |
-					  KEY_FLAG_TODO_DEFMGMTKEY |
-					  KEY_FLAG_TODO_HWACCEL_ADD |
-					  KEY_FLAG_TODO_HWACCEL_REMOVE |
-					  KEY_FLAG_TODO_DELETE);
-		key->flags &= ~todoflags;
-		spin_unlock_bh(&todo_lock);
-
-		work_done = false;
-
-		if (todoflags & KEY_FLAG_TODO_ADD_DEBUGFS) {
-			ieee80211_debugfs_key_add(key);
-			work_done = true;
-		}
-		if (todoflags & KEY_FLAG_TODO_DEFKEY) {
-			ieee80211_debugfs_key_remove_default(key->sdata);
-			ieee80211_debugfs_key_add_default(key->sdata);
-			work_done = true;
-		}
-		if (todoflags & KEY_FLAG_TODO_DEFMGMTKEY) {
-			ieee80211_debugfs_key_remove_mgmt_default(key->sdata);
-			ieee80211_debugfs_key_add_mgmt_default(key->sdata);
-			work_done = true;
-		}
-		if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) {
-			ieee80211_key_enable_hw_accel(key);
-			work_done = true;
-		}
-		if (todoflags & KEY_FLAG_TODO_HWACCEL_REMOVE) {
-			ieee80211_key_disable_hw_accel(key);
-			work_done = true;
-		}
-		if (todoflags & KEY_FLAG_TODO_DELETE) {
-			__ieee80211_key_destroy(key);
-			work_done = true;
-		}
-
-		WARN_ON(!work_done);
-
-		spin_lock_bh(&todo_lock);
-	}
-	spin_unlock_bh(&todo_lock);
-}
-
-void ieee80211_key_todo(void)
-{
-	ieee80211_key_lock();
-	__ieee80211_key_todo();
-	ieee80211_key_unlock();
+	mutex_unlock(&sdata->local->key_mtx);
 }
 
 void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_key *key, *tmp;
-	unsigned long flags;
 
-	ieee80211_key_lock();
+	mutex_lock(&sdata->local->key_mtx);
 
 	ieee80211_debugfs_key_remove_default(sdata);
 	ieee80211_debugfs_key_remove_mgmt_default(sdata);
 
-	spin_lock_irqsave(&sdata->local->key_lock, flags);
 	list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
 		__ieee80211_key_free(key);
-	spin_unlock_irqrestore(&sdata->local->key_lock, flags);
 
-	__ieee80211_key_todo();
-
-	ieee80211_key_unlock();
+	mutex_unlock(&sdata->local->key_mtx);
 }
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index bdc2968..b665bbb 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -38,25 +38,9 @@
  *
  * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present
  *	in the hardware for TX crypto hardware acceleration.
- * @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an
- *	RCU grace period, no longer be reachable other than from the
- *	todo list.
- * @KEY_FLAG_TODO_HWACCEL_ADD: Key needs to be added to hardware acceleration.
- * @KEY_FLAG_TODO_HWACCEL_REMOVE: Key needs to be removed from hardware
- *	acceleration.
- * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated.
- * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs.
- * @KEY_FLAG_TODO_DEFMGMTKEY: Key is default management key and debugfs needs
- *	to be updated.
  */
 enum ieee80211_internal_key_flags {
 	KEY_FLAG_UPLOADED_TO_HARDWARE	= BIT(0),
-	KEY_FLAG_TODO_DELETE		= BIT(1),
-	KEY_FLAG_TODO_HWACCEL_ADD	= BIT(2),
-	KEY_FLAG_TODO_HWACCEL_REMOVE	= BIT(3),
-	KEY_FLAG_TODO_DEFKEY		= BIT(4),
-	KEY_FLAG_TODO_ADD_DEBUGFS	= BIT(5),
-	KEY_FLAG_TODO_DEFMGMTKEY	= BIT(6),
 };
 
 enum ieee80211_internal_tkip_state {
@@ -79,10 +63,8 @@
 
 	/* for sdata list */
 	struct list_head list;
-	/* for todo list */
-	struct list_head todo;
 
-	/* protected by todo lock! */
+	/* protected by key mutex */
 	unsigned int flags;
 
 	union {
@@ -95,7 +77,13 @@
 		} tkip;
 		struct {
 			u8 tx_pn[6];
-			u8 rx_pn[NUM_RX_DATA_QUEUES][6];
+			/*
+			 * Last received packet number. The first
+			 * NUM_RX_DATA_QUEUES counters are used with Data
+			 * frames and the last counter is used with Robust
+			 * Management frames.
+			 */
+			u8 rx_pn[NUM_RX_DATA_QUEUES + 1][6];
 			struct crypto_cipher *tfm;
 			u32 replays; /* dot11RSNAStatsCCMPReplays */
 			/* scratch buffers for virt_to_page() (crypto API) */
@@ -147,7 +135,8 @@
 void ieee80211_key_link(struct ieee80211_key *key,
 			struct ieee80211_sub_if_data *sdata,
 			struct sta_info *sta);
-void ieee80211_key_free(struct ieee80211_key *key);
+void ieee80211_key_free(struct ieee80211_local *local,
+			struct ieee80211_key *key);
 void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx);
 void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
 				    int idx);
@@ -155,6 +144,4 @@
 void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
 void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata);
 
-void ieee80211_key_todo(void);
-
 #endif /* IEEE80211_KEY_H */
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 22a384d..7cc4f91 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -20,6 +20,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/bitmap.h>
 #include <linux/pm_qos_params.h>
+#include <linux/inetdevice.h>
 #include <net/net_namespace.h>
 #include <net/cfg80211.h>
 
@@ -106,12 +107,15 @@
 	if (scan_chan) {
 		chan = scan_chan;
 		channel_type = NL80211_CHAN_NO_HT;
+		local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
 	} else if (local->tmp_channel) {
 		chan = scan_chan = local->tmp_channel;
 		channel_type = local->tmp_channel_type;
+		local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
 	} else {
 		chan = local->oper_channel;
 		channel_type = local->_oper_channel_type;
+		local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL;
 	}
 
 	if (chan != local->hw.conf.channel ||
@@ -259,7 +263,6 @@
 {
 	struct ieee80211_local *local = (struct ieee80211_local *) data;
 	struct sk_buff *skb;
-	struct ieee80211_ra_tid *ra_tid;
 
 	while ((skb = skb_dequeue(&local->skb_queue)) ||
 	       (skb = skb_dequeue(&local->skb_queue_unreliable))) {
@@ -274,18 +277,6 @@
 			skb->pkt_type = 0;
 			ieee80211_tx_status(local_to_hw(local), skb);
 			break;
-		case IEEE80211_DELBA_MSG:
-			ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
-			ieee80211_stop_tx_ba_cb(ra_tid->vif, ra_tid->ra,
-						ra_tid->tid);
-			dev_kfree_skb(skb);
-			break;
-		case IEEE80211_ADDBA_MSG:
-			ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
-			ieee80211_start_tx_ba_cb(ra_tid->vif, ra_tid->ra,
-						 ra_tid->tid);
-			dev_kfree_skb(skb);
-			break ;
 		default:
 			WARN(1, "mac80211: Packet is of unknown type %d\n",
 			     skb->pkt_type);
@@ -329,6 +320,76 @@
 	mutex_unlock(&local->iflist_mtx);
 }
 
+#ifdef CONFIG_INET
+static int ieee80211_ifa_changed(struct notifier_block *nb,
+				 unsigned long data, void *arg)
+{
+	struct in_ifaddr *ifa = arg;
+	struct ieee80211_local *local =
+		container_of(nb, struct ieee80211_local,
+			     ifa_notifier);
+	struct net_device *ndev = ifa->ifa_dev->dev;
+	struct wireless_dev *wdev = ndev->ieee80211_ptr;
+	struct in_device *idev;
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_bss_conf *bss_conf;
+	struct ieee80211_if_managed *ifmgd;
+	int c = 0;
+
+	if (!netif_running(ndev))
+		return NOTIFY_DONE;
+
+	/* Make sure it's our interface that got changed */
+	if (!wdev)
+		return NOTIFY_DONE;
+
+	if (wdev->wiphy != local->hw.wiphy)
+		return NOTIFY_DONE;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+	bss_conf = &sdata->vif.bss_conf;
+
+	/* ARP filtering is only supported in managed mode */
+	if (sdata->vif.type != NL80211_IFTYPE_STATION)
+		return NOTIFY_DONE;
+
+	idev = sdata->dev->ip_ptr;
+	if (!idev)
+		return NOTIFY_DONE;
+
+	ifmgd = &sdata->u.mgd;
+	mutex_lock(&ifmgd->mtx);
+
+	/* Copy the addresses to the bss_conf list */
+	ifa = idev->ifa_list;
+	while (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN && ifa) {
+		bss_conf->arp_addr_list[c] = ifa->ifa_address;
+		ifa = ifa->ifa_next;
+		c++;
+	}
+
+	/* If not all addresses fit the list, disable filtering */
+	if (ifa) {
+		sdata->arp_filter_state = false;
+		c = 0;
+	} else {
+		sdata->arp_filter_state = true;
+	}
+	bss_conf->arp_addr_cnt = c;
+
+	/* Configure driver only if associated */
+	if (ifmgd->associated) {
+		bss_conf->arp_filter_enabled = sdata->arp_filter_state;
+		ieee80211_bss_info_change_notify(sdata,
+						 BSS_CHANGED_ARP_FILTER);
+	}
+
+	mutex_unlock(&ifmgd->mtx);
+
+	return NOTIFY_DONE;
+}
+#endif
+
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 					const struct ieee80211_ops *ops)
 {
@@ -396,7 +457,7 @@
 	mutex_init(&local->iflist_mtx);
 	mutex_init(&local->scan_mtx);
 
-	spin_lock_init(&local->key_lock);
+	mutex_init(&local->key_mtx);
 	spin_lock_init(&local->filter_lock);
 	spin_lock_init(&local->queue_stop_reason_lock);
 
@@ -419,8 +480,10 @@
 
 	sta_info_init(local);
 
-	for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
+	for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
 		skb_queue_head_init(&local->pending[i]);
+		atomic_set(&local->agg_queue_stop[i], 0);
+	}
 	tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
 		     (unsigned long)local);
 
@@ -431,8 +494,6 @@
 	skb_queue_head_init(&local->skb_queue);
 	skb_queue_head_init(&local->skb_queue_unreliable);
 
-	spin_lock_init(&local->ampdu_lock);
-
 	return local_to_hw(local);
 }
 EXPORT_SYMBOL(ieee80211_alloc_hw);
@@ -572,18 +633,16 @@
 
 	local->hw.conf.listen_interval = local->hw.max_listen_interval;
 
-	local->hw.conf.dynamic_ps_forced_timeout = -1;
+	local->dynamic_ps_forced_timeout = -1;
 
 	result = sta_info_start(local);
 	if (result < 0)
 		goto fail_sta_info;
 
 	result = ieee80211_wep_init(local);
-	if (result < 0) {
+	if (result < 0)
 		printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n",
 		       wiphy_name(local->hw.wiphy), result);
-		goto fail_wep;
-	}
 
 	rtnl_lock();
 
@@ -612,21 +671,30 @@
 		ieee80211_max_network_latency;
 	result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY,
 				     &local->network_latency_notifier);
-
 	if (result) {
 		rtnl_lock();
 		goto fail_pm_qos;
 	}
 
+#ifdef CONFIG_INET
+	local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
+	result = register_inetaddr_notifier(&local->ifa_notifier);
+	if (result)
+		goto fail_ifa;
+#endif
+
 	return 0;
 
+ fail_ifa:
+	pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
+			       &local->network_latency_notifier);
+	rtnl_lock();
  fail_pm_qos:
 	ieee80211_led_exit(local);
 	ieee80211_remove_interfaces(local);
  fail_rate:
 	rtnl_unlock();
 	ieee80211_wep_free(local);
- fail_wep:
 	sta_info_stop(local);
  fail_sta_info:
 	destroy_workqueue(local->workqueue);
@@ -647,6 +715,9 @@
 
 	pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
 			       &local->network_latency_notifier);
+#ifdef CONFIG_INET
+	unregister_inetaddr_notifier(&local->ifa_notifier);
+#endif
 
 	rtnl_lock();
 
@@ -704,6 +775,10 @@
 	if (ret)
 		return ret;
 
+	ret = rc80211_minstrel_ht_init();
+	if (ret)
+		goto err_minstrel;
+
 	ret = rc80211_pid_init();
 	if (ret)
 		goto err_pid;
@@ -716,6 +791,8 @@
  err_netdev:
 	rc80211_pid_exit();
  err_pid:
+	rc80211_minstrel_ht_exit();
+ err_minstrel:
 	rc80211_minstrel_exit();
 
 	return ret;
@@ -724,6 +801,7 @@
 static void __exit ieee80211_exit(void)
 {
 	rc80211_pid_exit();
+	rc80211_minstrel_ht_exit();
 	rc80211_minstrel_exit();
 
 	/*
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index bde8103..c8a4f19 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -54,7 +54,7 @@
 		return;
 	}
 
-	ieee80211_queue_work(&local->hw, &ifmsh->work);
+	ieee80211_queue_work(&local->hw, &sdata->work);
 }
 
 /**
@@ -345,7 +345,7 @@
 		return;
 	}
 
-	ieee80211_queue_work(&local->hw, &ifmsh->work);
+	ieee80211_queue_work(&local->hw, &sdata->work);
 }
 
 static void ieee80211_mesh_path_root_timer(unsigned long data)
@@ -362,7 +362,7 @@
 		return;
 	}
 
-	ieee80211_queue_work(&local->hw, &ifmsh->work);
+	ieee80211_queue_work(&local->hw, &sdata->work);
 }
 
 void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
@@ -484,9 +484,6 @@
 {
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
-	/* might restart the timer but that doesn't matter */
-	cancel_work_sync(&ifmsh->work);
-
 	/* use atomic bitops in case both timers fire at the same time */
 
 	if (del_timer_sync(&ifmsh->housekeeping_timer))
@@ -518,7 +515,7 @@
 
 	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
 	ieee80211_mesh_root_setup(ifmsh);
-	ieee80211_queue_work(&local->hw, &ifmsh->work);
+	ieee80211_queue_work(&local->hw, &sdata->work);
 	sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
 						BSS_CHANGED_BEACON_ENABLED |
@@ -536,16 +533,7 @@
 	 * whether the interface is running, which, at this point,
 	 * it no longer is.
 	 */
-	cancel_work_sync(&sdata->u.mesh.work);
-
-	/*
-	 * When we get here, the interface is marked down.
-	 * Call synchronize_rcu() to wait for the RX path
-	 * should it be using the interface and enqueuing
-	 * frames at this very time on another CPU.
-	 */
-	rcu_barrier(); /* Wait for RX path and call_rcu()'s */
-	skb_queue_purge(&sdata->u.mesh.skb_queue);
+	cancel_work_sync(&sdata->work);
 }
 
 static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
@@ -608,8 +596,8 @@
 	}
 }
 
-static void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
-					  struct sk_buff *skb)
+void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+				   struct sk_buff *skb)
 {
 	struct ieee80211_rx_status *rx_status;
 	struct ieee80211_if_mesh *ifmsh;
@@ -632,26 +620,11 @@
 		ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
 		break;
 	}
-
-	kfree_skb(skb);
 }
 
-static void ieee80211_mesh_work(struct work_struct *work)
+void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata =
-		container_of(work, struct ieee80211_sub_if_data, u.mesh.work);
-	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-	struct sk_buff *skb;
-
-	if (!ieee80211_sdata_running(sdata))
-		return;
-
-	if (local->scanning)
-		return;
-
-	while ((skb = skb_dequeue(&ifmsh->skb_queue)))
-		ieee80211_mesh_rx_queued_mgmt(sdata, skb);
 
 	if (ifmsh->preq_queue_len &&
 	    time_after(jiffies,
@@ -678,7 +651,7 @@
 	rcu_read_lock();
 	list_for_each_entry_rcu(sdata, &local->interfaces, list)
 		if (ieee80211_vif_is_mesh(&sdata->vif))
-			ieee80211_queue_work(&local->hw, &sdata->u.mesh.work);
+			ieee80211_queue_work(&local->hw, &sdata->work);
 	rcu_read_unlock();
 }
 
@@ -686,11 +659,9 @@
 {
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
-	INIT_WORK(&ifmsh->work, ieee80211_mesh_work);
 	setup_timer(&ifmsh->housekeeping_timer,
 		    ieee80211_mesh_housekeeping_timer,
 		    (unsigned long) sdata);
-	skb_queue_head_init(&sdata->u.mesh.skb_queue);
 
 	ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
 	ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
@@ -731,29 +702,3 @@
 	INIT_LIST_HEAD(&ifmsh->preq_queue.list);
 	spin_lock_init(&ifmsh->mesh_preq_queue_lock);
 }
-
-ieee80211_rx_result
-ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-	struct ieee80211_mgmt *mgmt;
-	u16 fc;
-
-	if (skb->len < 24)
-		return RX_DROP_MONITOR;
-
-	mgmt = (struct ieee80211_mgmt *) skb->data;
-	fc = le16_to_cpu(mgmt->frame_control);
-
-	switch (fc & IEEE80211_FCTL_STYPE) {
-	case IEEE80211_STYPE_ACTION:
-	case IEEE80211_STYPE_PROBE_RESP:
-	case IEEE80211_STYPE_BEACON:
-		skb_queue_tail(&ifmsh->skb_queue, skb);
-		ieee80211_queue_work(&local->hw, &ifmsh->work);
-		return RX_QUEUED;
-	}
-
-	return RX_CONTINUE;
-}
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index c88087f..ebd3f1d 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -237,8 +237,6 @@
 		struct sta_info *stainfo, struct sk_buff *skb);
 void ieee80211s_stop(void);
 void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
-ieee80211_rx_result
-ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
 void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
 void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
 void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 0705018..829e08a 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -805,14 +805,14 @@
 	spin_unlock(&ifmsh->mesh_preq_queue_lock);
 
 	if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata)))
-		ieee80211_queue_work(&sdata->local->hw, &ifmsh->work);
+		ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 
 	else if (time_before(jiffies, ifmsh->last_preq)) {
 		/* avoid long wait if did not send preqs for a long time
 		 * and jiffies wrapped around
 		 */
 		ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
-		ieee80211_queue_work(&sdata->local->hw, &ifmsh->work);
+		ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 	} else
 		mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq +
 						min_preq_int_jiff(sdata));
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 181ffd6..349e466 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -315,7 +315,7 @@
 	read_unlock(&pathtbl_resize_lock);
 	if (grow) {
 		set_bit(MESH_WORK_GROW_MPATH_TABLE,  &ifmsh->wrkq_flags);
-		ieee80211_queue_work(&local->hw, &ifmsh->work);
+		ieee80211_queue_work(&local->hw, &sdata->work);
 	}
 	return 0;
 
@@ -425,7 +425,7 @@
 	read_unlock(&pathtbl_resize_lock);
 	if (grow) {
 		set_bit(MESH_WORK_GROW_MPP_TABLE,  &ifmsh->wrkq_flags);
-		ieee80211_queue_work(&local->hw, &ifmsh->work);
+		ieee80211_queue_work(&local->hw, &sdata->work);
 	}
 	return 0;
 
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 3cd5f7b..ea13a80 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -65,7 +65,6 @@
 {
 	atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
 	mesh_accept_plinks_update(sdata);
-	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 }
 
 static inline
@@ -73,7 +72,6 @@
 {
 	atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
 	mesh_accept_plinks_update(sdata);
-	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 }
 
 /**
@@ -115,7 +113,7 @@
 }
 
 /**
- * mesh_plink_deactivate - deactivate mesh peer link
+ * __mesh_plink_deactivate - deactivate mesh peer link
  *
  * @sta: mesh peer link to deactivate
  *
@@ -123,18 +121,23 @@
  *
  * Locking: the caller must hold sta->lock
  */
-static void __mesh_plink_deactivate(struct sta_info *sta)
+static bool __mesh_plink_deactivate(struct sta_info *sta)
 {
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	bool deactivated = false;
 
-	if (sta->plink_state == PLINK_ESTAB)
+	if (sta->plink_state == PLINK_ESTAB) {
 		mesh_plink_dec_estab_count(sdata);
+		deactivated = true;
+	}
 	sta->plink_state = PLINK_BLOCKED;
 	mesh_path_flush_by_nexthop(sta);
+
+	return deactivated;
 }
 
 /**
- * __mesh_plink_deactivate - deactivate mesh peer link
+ * mesh_plink_deactivate - deactivate mesh peer link
  *
  * @sta: mesh peer link to deactivate
  *
@@ -142,9 +145,15 @@
  */
 void mesh_plink_deactivate(struct sta_info *sta)
 {
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	bool deactivated;
+
 	spin_lock_bh(&sta->lock);
-	__mesh_plink_deactivate(sta);
+	deactivated = __mesh_plink_deactivate(sta);
 	spin_unlock_bh(&sta->lock);
+
+	if (deactivated)
+		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 }
 
 static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
@@ -381,10 +390,16 @@
 
 void mesh_plink_block(struct sta_info *sta)
 {
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	bool deactivated;
+
 	spin_lock_bh(&sta->lock);
-	__mesh_plink_deactivate(sta);
+	deactivated = __mesh_plink_deactivate(sta);
 	sta->plink_state = PLINK_BLOCKED;
 	spin_unlock_bh(&sta->lock);
+
+	if (deactivated)
+		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 }
 
 
@@ -397,6 +412,7 @@
 	enum plink_event event;
 	enum plink_frame_type ftype;
 	size_t baselen;
+	bool deactivated;
 	u8 ie_len;
 	u8 *baseaddr;
 	__le16 plid, llid, reason;
@@ -651,8 +667,9 @@
 		case CNF_ACPT:
 			del_timer(&sta->plink_timer);
 			sta->plink_state = PLINK_ESTAB;
-			mesh_plink_inc_estab_count(sdata);
 			spin_unlock_bh(&sta->lock);
+			mesh_plink_inc_estab_count(sdata);
+			ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 			mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
 				sta->sta.addr);
 			break;
@@ -684,8 +701,9 @@
 		case OPN_ACPT:
 			del_timer(&sta->plink_timer);
 			sta->plink_state = PLINK_ESTAB;
-			mesh_plink_inc_estab_count(sdata);
 			spin_unlock_bh(&sta->lock);
+			mesh_plink_inc_estab_count(sdata);
+			ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 			mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
 				sta->sta.addr);
 			mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
@@ -702,11 +720,13 @@
 		case CLS_ACPT:
 			reason = cpu_to_le16(MESH_CLOSE_RCVD);
 			sta->reason = reason;
-			__mesh_plink_deactivate(sta);
+			deactivated = __mesh_plink_deactivate(sta);
 			sta->plink_state = PLINK_HOLDING;
 			llid = sta->llid;
 			mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
 			spin_unlock_bh(&sta->lock);
+			if (deactivated)
+				ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 			mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
 					    plid, reason);
 			break;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index f803f8b..b6c163a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -478,6 +478,39 @@
 	}
 }
 
+void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
+{
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_conf *conf = &local->hw.conf;
+
+	WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
+		!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
+		(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
+
+	local->disable_dynamic_ps = false;
+	conf->dynamic_ps_timeout = local->dynamic_ps_user_timeout;
+}
+EXPORT_SYMBOL(ieee80211_enable_dyn_ps);
+
+void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif)
+{
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_conf *conf = &local->hw.conf;
+
+	WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
+		!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
+		(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
+
+	local->disable_dynamic_ps = true;
+	conf->dynamic_ps_timeout = 0;
+	del_timer_sync(&local->dynamic_ps_timer);
+	ieee80211_queue_work(&local->hw,
+			     &local->dynamic_ps_enable_work);
+}
+EXPORT_SYMBOL(ieee80211_disable_dyn_ps);
+
 /* powersave */
 static void ieee80211_enable_ps(struct ieee80211_local *local,
 				struct ieee80211_sub_if_data *sdata)
@@ -553,6 +586,7 @@
 	    found->u.mgd.associated->beacon_ies &&
 	    !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
 				    IEEE80211_STA_CONNECTION_POLL))) {
+		struct ieee80211_conf *conf = &local->hw.conf;
 		s32 beaconint_us;
 
 		if (latency < 0)
@@ -561,25 +595,24 @@
 		beaconint_us = ieee80211_tu_to_usec(
 					found->vif.bss_conf.beacon_int);
 
-		timeout = local->hw.conf.dynamic_ps_forced_timeout;
+		timeout = local->dynamic_ps_forced_timeout;
 		if (timeout < 0) {
 			/*
+			 * Go to full PSM if the user configures a very low
+			 * latency requirement.
 			 * The 2 second value is there for compatibility until
 			 * the PM_QOS_NETWORK_LATENCY is configured with real
 			 * values.
 			 */
-			if (latency == 2000000000)
-				timeout = 100;
-			else if (latency <= 50000)
-				timeout = 300;
-			else if (latency <= 100000)
-				timeout = 100;
-			else if (latency <= 500000)
-				timeout = 50;
-			else
+			if (latency > 1900000000 && latency != 2000000000)
 				timeout = 0;
+			else
+				timeout = 100;
 		}
-		local->hw.conf.dynamic_ps_timeout = timeout;
+		local->dynamic_ps_user_timeout = timeout;
+		if (!local->disable_dynamic_ps)
+			conf->dynamic_ps_timeout =
+				local->dynamic_ps_user_timeout;
 
 		if (beaconint_us > latency) {
 			local->ps_sdata = NULL;
@@ -665,10 +698,11 @@
 
 /* MLME */
 static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
-				     struct ieee80211_if_managed *ifmgd,
+				     struct ieee80211_sub_if_data *sdata,
 				     u8 *wmm_param, size_t wmm_param_len)
 {
 	struct ieee80211_tx_queue_params params;
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	size_t left;
 	int count;
 	u8 *pos, uapsd_queues = 0;
@@ -757,8 +791,8 @@
 	}
 
 	/* enable WMM or activate new settings */
-	local->hw.conf.flags |=	IEEE80211_CONF_QOS;
-	drv_config(local, IEEE80211_CONF_CHANGE_QOS);
+	sdata->vif.bss_conf.qos = true;
+	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
 }
 
 static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
@@ -806,11 +840,12 @@
 {
 	struct ieee80211_bss *bss = (void *)cbss->priv;
 	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
 
 	bss_info_changed |= BSS_CHANGED_ASSOC;
 	/* set timing information */
-	sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
-	sdata->vif.bss_conf.timestamp = cbss->tsf;
+	bss_conf->beacon_int = cbss->beacon_interval;
+	bss_conf->timestamp = cbss->tsf;
 
 	bss_info_changed |= BSS_CHANGED_BEACON_INT;
 	bss_info_changed |= ieee80211_handle_bss_capability(sdata,
@@ -835,7 +870,12 @@
 
 	ieee80211_led_assoc(local, 1);
 
-	sdata->vif.bss_conf.assoc = 1;
+	if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
+		bss_conf->dtim_period = bss->dtim_period;
+	else
+		bss_conf->dtim_period = 0;
+
+	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
@@ -848,9 +888,15 @@
 
 	/* Tell the driver to monitor connection quality (if supported) */
 	if ((local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) &&
-	    sdata->vif.bss_conf.cqm_rssi_thold)
+	    bss_conf->cqm_rssi_thold)
 		bss_info_changed |= BSS_CHANGED_CQM;
 
+	/* Enable ARP filtering */
+	if (bss_conf->arp_filter_enabled != sdata->arp_filter_state) {
+		bss_conf->arp_filter_enabled = sdata->arp_filter_state;
+		bss_info_changed |= BSS_CHANGED_ARP_FILTER;
+	}
+
 	ieee80211_bss_info_change_notify(sdata, bss_info_changed);
 
 	mutex_lock(&local->iflist_mtx);
@@ -898,13 +944,13 @@
 	netif_tx_stop_all_queues(sdata->dev);
 	netif_carrier_off(sdata->dev);
 
-	rcu_read_lock();
+	mutex_lock(&local->sta_mtx);
 	sta = sta_info_get(sdata, bssid);
 	if (sta) {
-		set_sta_flags(sta, WLAN_STA_DISASSOC);
+		set_sta_flags(sta, WLAN_STA_BLOCK_BA);
 		ieee80211_sta_tear_down_BA_sessions(sta);
 	}
-	rcu_read_unlock();
+	mutex_unlock(&local->sta_mtx);
 
 	changed |= ieee80211_reset_erp_info(sdata);
 
@@ -932,6 +978,12 @@
 
 	ieee80211_hw_config(local, config_changed);
 
+	/* Disable ARP filtering */
+	if (sdata->vif.bss_conf.arp_filter_enabled) {
+		sdata->vif.bss_conf.arp_filter_enabled = false;
+		changed |= BSS_CHANGED_ARP_FILTER;
+	}
+
 	/* The BSSID (not really interesting) and HT changed */
 	changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
 	ieee80211_bss_info_change_notify(sdata, changed);
@@ -1279,7 +1331,7 @@
 	}
 
 	if (elems.wmm_param)
-		ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
+		ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
 					 elems.wmm_param_len);
 	else
 		ieee80211_set_wmm_default(sdata);
@@ -1551,7 +1603,7 @@
 		ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
 				      true);
 
-		ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
+		ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
 					 elems.wmm_param_len);
 	}
 
@@ -1633,35 +1685,8 @@
 	ieee80211_bss_info_change_notify(sdata, changed);
 }
 
-ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
-					  struct sk_buff *skb)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_mgmt *mgmt;
-	u16 fc;
-
-	if (skb->len < 24)
-		return RX_DROP_MONITOR;
-
-	mgmt = (struct ieee80211_mgmt *) skb->data;
-	fc = le16_to_cpu(mgmt->frame_control);
-
-	switch (fc & IEEE80211_FCTL_STYPE) {
-	case IEEE80211_STYPE_PROBE_RESP:
-	case IEEE80211_STYPE_BEACON:
-	case IEEE80211_STYPE_DEAUTH:
-	case IEEE80211_STYPE_DISASSOC:
-	case IEEE80211_STYPE_ACTION:
-		skb_queue_tail(&sdata->u.mgd.skb_queue, skb);
-		ieee80211_queue_work(&local->hw, &sdata->u.mgd.work);
-		return RX_QUEUED;
-	}
-
-	return RX_DROP_MONITOR;
-}
-
-static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
-					 struct sk_buff *skb)
+void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+				  struct sk_buff *skb)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_rx_status *rx_status;
@@ -1693,44 +1718,6 @@
 			break;
 		case IEEE80211_STYPE_ACTION:
 			switch (mgmt->u.action.category) {
-			case WLAN_CATEGORY_BACK: {
-				struct ieee80211_local *local = sdata->local;
-				int len = skb->len;
-				struct sta_info *sta;
-
-				rcu_read_lock();
-				sta = sta_info_get(sdata, mgmt->sa);
-				if (!sta) {
-					rcu_read_unlock();
-					break;
-				}
-
-				local_bh_disable();
-
-				switch (mgmt->u.action.u.addba_req.action_code) {
-				case WLAN_ACTION_ADDBA_REQ:
-					if (len < (IEEE80211_MIN_ACTION_SIZE +
-						   sizeof(mgmt->u.action.u.addba_req)))
-						break;
-					ieee80211_process_addba_request(local, sta, mgmt, len);
-					break;
-				case WLAN_ACTION_ADDBA_RESP:
-					if (len < (IEEE80211_MIN_ACTION_SIZE +
-						   sizeof(mgmt->u.action.u.addba_resp)))
-						break;
-					ieee80211_process_addba_resp(local, sta, mgmt, len);
-					break;
-				case WLAN_ACTION_DELBA:
-					if (len < (IEEE80211_MIN_ACTION_SIZE +
-						   sizeof(mgmt->u.action.u.delba)))
-						break;
-					ieee80211_process_delba(sdata, sta, mgmt, len);
-					break;
-				}
-				local_bh_enable();
-				rcu_read_unlock();
-				break;
-				}
 			case WLAN_CATEGORY_SPECTRUM_MGMT:
 				ieee80211_sta_process_chanswitch(sdata,
 						&mgmt->u.action.u.chan_switch.sw_elem,
@@ -1754,7 +1741,7 @@
 		default:
 			WARN(1, "unexpected: %d", rma);
 		}
-		goto out;
+		return;
 	}
 
 	mutex_unlock(&ifmgd->mtx);
@@ -1769,7 +1756,8 @@
 			if (wk->sdata != sdata)
 				continue;
 
-			if (wk->type != IEEE80211_WORK_ASSOC)
+			if (wk->type != IEEE80211_WORK_ASSOC &&
+			    wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
 				continue;
 
 			if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN))
@@ -1799,8 +1787,6 @@
 
 		cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
 	}
- out:
-	kfree_skb(skb);
 }
 
 static void ieee80211_sta_timer(unsigned long data)
@@ -1815,39 +1801,13 @@
 		return;
 	}
 
-	ieee80211_queue_work(&local->hw, &ifmgd->work);
+	ieee80211_queue_work(&local->hw, &sdata->work);
 }
 
-static void ieee80211_sta_work(struct work_struct *work)
+void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata =
-		container_of(work, struct ieee80211_sub_if_data, u.mgd.work);
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_if_managed *ifmgd;
-	struct sk_buff *skb;
-
-	if (!ieee80211_sdata_running(sdata))
-		return;
-
-	if (local->scanning)
-		return;
-
-	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
-		return;
-
-	/*
-	 * ieee80211_queue_work() should have picked up most cases,
-	 * here we'll pick the the rest.
-	 */
-	if (WARN(local->suspended, "STA MLME work scheduled while "
-		 "going to suspend\n"))
-		return;
-
-	ifmgd = &sdata->u.mgd;
-
-	/* first process frames to avoid timing out while a frame is pending */
-	while ((skb = skb_dequeue(&ifmgd->skb_queue)))
-		ieee80211_sta_rx_queued_mgmt(sdata, skb);
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
 	/* then process the rest of the work */
 	mutex_lock(&ifmgd->mtx);
@@ -1942,8 +1902,7 @@
 		ieee80211_queue_work(&sdata->local->hw,
 			   &sdata->u.mgd.monitor_work);
 		/* and do all the other regular work too */
-		ieee80211_queue_work(&sdata->local->hw,
-			   &sdata->u.mgd.work);
+		ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 	}
 }
 
@@ -1958,7 +1917,6 @@
 	 * time -- the code here is properly synchronised.
 	 */
 
-	cancel_work_sync(&ifmgd->work);
 	cancel_work_sync(&ifmgd->beacon_connection_loss_work);
 	if (del_timer_sync(&ifmgd->timer))
 		set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
@@ -1990,7 +1948,6 @@
 	struct ieee80211_if_managed *ifmgd;
 
 	ifmgd = &sdata->u.mgd;
-	INIT_WORK(&ifmgd->work, ieee80211_sta_work);
 	INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
 	INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
 	INIT_WORK(&ifmgd->beacon_connection_loss_work,
@@ -2003,7 +1960,6 @@
 		    (unsigned long) sdata);
 	setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
 		    (unsigned long) sdata);
-	skb_queue_head_init(&ifmgd->skb_queue);
 
 	ifmgd->flags = 0;
 
@@ -2081,6 +2037,8 @@
 		auth_alg = WLAN_AUTH_OPEN;
 		break;
 	case NL80211_AUTHTYPE_SHARED_KEY:
+		if (IS_ERR(sdata->local->wep_tx_tfm))
+			return -EOPNOTSUPP;
 		auth_alg = WLAN_AUTH_SHARED_KEY;
 		break;
 	case NL80211_AUTHTYPE_FT:
@@ -2134,6 +2092,8 @@
 						  struct sk_buff *skb)
 {
 	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_rx_status *rx_status;
+	struct ieee802_11_elems elems;
 	u16 status;
 
 	if (!skb) {
@@ -2141,6 +2101,19 @@
 		return WORK_DONE_DESTROY;
 	}
 
+	if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) {
+		mutex_lock(&wk->sdata->u.mgd.mtx);
+		rx_status = (void *) skb->cb;
+		ieee802_11_parse_elems(skb->data + 24 + 12, skb->len - 24 - 12, &elems);
+		ieee80211_rx_bss_info(wk->sdata, (void *)skb->data, skb->len, rx_status,
+				      &elems, true);
+		mutex_unlock(&wk->sdata->u.mgd.mtx);
+
+		wk->type = IEEE80211_WORK_ASSOC;
+		/* not really done yet */
+		return WORK_DONE_REQUEUE;
+	}
+
 	mgmt = (void *)skb->data;
 	status = le16_to_cpu(mgmt->u.assoc_resp.status_code);
 
@@ -2153,6 +2126,7 @@
 						    wk->filter_ta);
 			return WORK_DONE_DESTROY;
 		}
+
 		mutex_unlock(&wk->sdata->u.mgd.mtx);
 	}
 
@@ -2253,10 +2227,14 @@
 	if (req->prev_bssid)
 		memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN);
 
-	wk->type = IEEE80211_WORK_ASSOC;
 	wk->chan = req->bss->channel;
 	wk->sdata = sdata;
 	wk->done = ieee80211_assoc_done;
+	if (!bss->dtim_period &&
+	    sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
+		wk->type = IEEE80211_WORK_ASSOC_BEACON_WAIT;
+	else
+		wk->type = IEEE80211_WORK_ASSOC;
 
 	if (req->use_mfp) {
 		ifmgd->mfp = IEEE80211_MFP_REQUIRED;
@@ -2282,14 +2260,16 @@
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_work *wk;
-	const u8 *bssid = req->bss->bssid;
+	u8 bssid[ETH_ALEN];
+	bool assoc_bss = false;
 
 	mutex_lock(&ifmgd->mtx);
 
+	memcpy(bssid, req->bss->bssid, ETH_ALEN);
 	if (ifmgd->associated == req->bss) {
-		bssid = req->bss->bssid;
-		ieee80211_set_disassoc(sdata, true);
+		ieee80211_set_disassoc(sdata, false);
 		mutex_unlock(&ifmgd->mtx);
+		assoc_bss = true;
 	} else {
 		bool not_auth_yet = false;
 
@@ -2302,7 +2282,8 @@
 
 			if (wk->type != IEEE80211_WORK_DIRECT_PROBE &&
 			    wk->type != IEEE80211_WORK_AUTH &&
-			    wk->type != IEEE80211_WORK_ASSOC)
+			    wk->type != IEEE80211_WORK_ASSOC &&
+			    wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
 				continue;
 
 			if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN))
@@ -2335,6 +2316,8 @@
 	ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH,
 				       req->reason_code, cookie,
 				       !req->local_state_change);
+	if (assoc_bss)
+		sta_info_destroy_addr(sdata, bssid);
 
 	ieee80211_recalc_idle(sdata->local);
 
@@ -2379,41 +2362,6 @@
 	return 0;
 }
 
-int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
-			 struct ieee80211_channel *chan,
-			 enum nl80211_channel_type channel_type,
-			 const u8 *buf, size_t len, u64 *cookie)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	struct sk_buff *skb;
-
-	/* Check that we are on the requested channel for transmission */
-	if ((chan != local->tmp_channel ||
-	     channel_type != local->tmp_channel_type) &&
-	    (chan != local->oper_channel ||
-	     channel_type != local->_oper_channel_type))
-		return -EBUSY;
-
-	skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
-	if (!skb)
-		return -ENOMEM;
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-
-	memcpy(skb_put(skb, len), buf, len);
-
-	if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
-		IEEE80211_SKB_CB(skb)->flags |=
-			IEEE80211_TX_INTFL_DONT_ENCRYPT;
-	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX |
-		IEEE80211_TX_CTL_REQ_TX_STATUS;
-	skb->dev = sdata->dev;
-	ieee80211_tx_skb(sdata, skb);
-
-	*cookie = (unsigned long) skb;
-	return 0;
-}
-
 void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 			       enum nl80211_cqm_rssi_threshold_event rssi_event,
 			       gfp_t gfp)
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 75202b2..d287fde 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -40,22 +40,14 @@
 	list_for_each_entry(sdata, &local->interfaces, list)
 		ieee80211_disable_keys(sdata);
 
-	/* Tear down aggregation sessions */
-
-	rcu_read_lock();
-
-	if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
-		list_for_each_entry_rcu(sta, &local->sta_list, list) {
+	/* tear down aggregation sessions and remove STAs */
+	mutex_lock(&local->sta_mtx);
+	list_for_each_entry(sta, &local->sta_list, list) {
+		if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
 			set_sta_flags(sta, WLAN_STA_BLOCK_BA);
 			ieee80211_sta_tear_down_BA_sessions(sta);
 		}
-	}
 
-	rcu_read_unlock();
-
-	/* remove STAs */
-	mutex_lock(&local->sta_mtx);
-	list_for_each_entry(sta, &local->sta_list, list) {
 		if (sta->uploaded) {
 			sdata = sta->sdata;
 			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@@ -72,6 +64,8 @@
 
 	/* remove all interfaces */
 	list_for_each_entry(sdata, &local->interfaces, list) {
+		cancel_work_sync(&sdata->work);
+
 		switch(sdata->vif.type) {
 		case NL80211_IFTYPE_STATION:
 			ieee80211_sta_quiesce(sdata);
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index 065a9619..168427b 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -147,5 +147,18 @@
 }
 #endif
 
+#ifdef CONFIG_MAC80211_RC_MINSTREL_HT
+extern int rc80211_minstrel_ht_init(void);
+extern void rc80211_minstrel_ht_exit(void);
+#else
+static inline int rc80211_minstrel_ht_init(void)
+{
+	return 0;
+}
+static inline void rc80211_minstrel_ht_exit(void)
+{
+}
+#endif
+
 
 #endif /* IEEE80211_RATE_H */
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index f65ce6d..778c604 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -67,7 +67,6 @@
 	for (i = rix; i >= 0; i--)
 		if (mi->r[i].rix == rix)
 			break;
-	WARN_ON(i < 0);
 	return i;
 }
 
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
new file mode 100644
index 0000000..c5b4659
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -0,0 +1,827 @@
+/*
+ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/random.h>
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "rate.h"
+#include "rc80211_minstrel.h"
+#include "rc80211_minstrel_ht.h"
+
+#define AVG_PKT_SIZE	1200
+#define SAMPLE_COLUMNS	10
+#define EWMA_LEVEL		75
+
+/* Number of bits for an average sized packet */
+#define MCS_NBITS (AVG_PKT_SIZE << 3)
+
+/* Number of symbols for a packet with (bps) bits per symbol */
+#define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps))
+
+/* Transmission time for a packet containing (syms) symbols */
+#define MCS_SYMBOL_TIME(sgi, syms)					\
+	(sgi ?								\
+	  ((syms) * 18 + 4) / 5 :	/* syms * 3.6 us */		\
+	  (syms) << 2			/* syms * 4 us */		\
+	)
+
+/* Transmit duration for the raw data part of an average sized packet */
+#define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps)))
+
+/* MCS rate information for an MCS group */
+#define MCS_GROUP(_streams, _sgi, _ht40) {				\
+	.streams = _streams,						\
+	.flags =							\
+		(_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) |			\
+		(_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0),		\
+	.duration = {							\
+		MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26),		\
+		MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52),		\
+		MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78),		\
+		MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104),	\
+		MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156),	\
+		MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208),	\
+		MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234),	\
+		MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260)		\
+	}								\
+}
+
+/*
+ * To enable sufficiently targeted rate sampling, MCS rates are divided into
+ * groups, based on the number of streams and flags (HT40, SGI) that they
+ * use.
+ */
+const struct mcs_group minstrel_mcs_groups[] = {
+	MCS_GROUP(1, 0, 0),
+	MCS_GROUP(2, 0, 0),
+#if MINSTREL_MAX_STREAMS >= 3
+	MCS_GROUP(3, 0, 0),
+#endif
+
+	MCS_GROUP(1, 1, 0),
+	MCS_GROUP(2, 1, 0),
+#if MINSTREL_MAX_STREAMS >= 3
+	MCS_GROUP(3, 1, 0),
+#endif
+
+	MCS_GROUP(1, 0, 1),
+	MCS_GROUP(2, 0, 1),
+#if MINSTREL_MAX_STREAMS >= 3
+	MCS_GROUP(3, 0, 1),
+#endif
+
+	MCS_GROUP(1, 1, 1),
+	MCS_GROUP(2, 1, 1),
+#if MINSTREL_MAX_STREAMS >= 3
+	MCS_GROUP(3, 1, 1),
+#endif
+};
+
+static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES];
+
+/*
+ * Perform EWMA (Exponentially Weighted Moving Average) calculation
+ */
+static int
+minstrel_ewma(int old, int new, int weight)
+{
+	return (new * (100 - weight) + old * weight) / 100;
+}
+
+/*
+ * Look up an MCS group index based on mac80211 rate information
+ */
+static int
+minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
+{
+	int streams = (rate->idx / MCS_GROUP_RATES) + 1;
+	u32 flags = IEEE80211_TX_RC_SHORT_GI | IEEE80211_TX_RC_40_MHZ_WIDTH;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) {
+		if (minstrel_mcs_groups[i].streams != streams)
+			continue;
+		if (minstrel_mcs_groups[i].flags != (rate->flags & flags))
+			continue;
+
+		return i;
+	}
+
+	WARN_ON(1);
+	return 0;
+}
+
+static inline struct minstrel_rate_stats *
+minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
+{
+	return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES];
+}
+
+
+/*
+ * Recalculate success probabilities and counters for a rate using EWMA
+ */
+static void
+minstrel_calc_rate_ewma(struct minstrel_priv *mp, struct minstrel_rate_stats *mr)
+{
+	if (unlikely(mr->attempts > 0)) {
+		mr->sample_skipped = 0;
+		mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts);
+		if (!mr->att_hist)
+			mr->probability = mr->cur_prob;
+		else
+			mr->probability = minstrel_ewma(mr->probability,
+				mr->cur_prob, EWMA_LEVEL);
+		mr->att_hist += mr->attempts;
+		mr->succ_hist += mr->success;
+	} else {
+		mr->sample_skipped++;
+	}
+	mr->last_success = mr->success;
+	mr->last_attempts = mr->attempts;
+	mr->success = 0;
+	mr->attempts = 0;
+}
+
+/*
+ * Calculate throughput based on the average A-MPDU length, taking into account
+ * the expected number of retransmissions and their expected length
+ */
+static void
+minstrel_ht_calc_tp(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
+                    int group, int rate)
+{
+	struct minstrel_rate_stats *mr;
+	unsigned int usecs;
+
+	mr = &mi->groups[group].rates[rate];
+
+	if (mr->probability < MINSTREL_FRAC(1, 10)) {
+		mr->cur_tp = 0;
+		return;
+	}
+
+	usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
+	usecs += minstrel_mcs_groups[group].duration[rate];
+	mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability);
+}
+
+/*
+ * Update rate statistics and select new primary rates
+ *
+ * Rules for rate selection:
+ *  - max_prob_rate must use only one stream, as a tradeoff between delivery
+ *    probability and throughput during strong fluctuations
+ *  - as long as the max prob rate has a probability of more than 3/4, pick
+ *    higher throughput rates, even if the probablity is a bit lower
+ */
+static void
+minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
+{
+	struct minstrel_mcs_group_data *mg;
+	struct minstrel_rate_stats *mr;
+	int cur_prob, cur_prob_tp, cur_tp, cur_tp2;
+	int group, i, index;
+
+	if (mi->ampdu_packets > 0) {
+		mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len,
+			MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), EWMA_LEVEL);
+		mi->ampdu_len = 0;
+		mi->ampdu_packets = 0;
+	}
+
+	mi->sample_slow = 0;
+	mi->sample_count = 0;
+	mi->max_tp_rate = 0;
+	mi->max_tp_rate2 = 0;
+	mi->max_prob_rate = 0;
+
+	for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
+		cur_prob = 0;
+		cur_prob_tp = 0;
+		cur_tp = 0;
+		cur_tp2 = 0;
+
+		mg = &mi->groups[group];
+		if (!mg->supported)
+			continue;
+
+		mg->max_tp_rate = 0;
+		mg->max_tp_rate2 = 0;
+		mg->max_prob_rate = 0;
+		mi->sample_count++;
+
+		for (i = 0; i < MCS_GROUP_RATES; i++) {
+			if (!(mg->supported & BIT(i)))
+				continue;
+
+			mr = &mg->rates[i];
+			mr->retry_updated = false;
+			index = MCS_GROUP_RATES * group + i;
+			minstrel_calc_rate_ewma(mp, mr);
+			minstrel_ht_calc_tp(mp, mi, group, i);
+
+			if (!mr->cur_tp)
+				continue;
+
+			/* ignore the lowest rate of each single-stream group */
+			if (!i && minstrel_mcs_groups[group].streams == 1)
+				continue;
+
+			if ((mr->cur_tp > cur_prob_tp && mr->probability >
+			     MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) {
+				mg->max_prob_rate = index;
+				cur_prob = mr->probability;
+				cur_prob_tp = mr->cur_tp;
+			}
+
+			if (mr->cur_tp > cur_tp) {
+				swap(index, mg->max_tp_rate);
+				cur_tp = mr->cur_tp;
+				mr = minstrel_get_ratestats(mi, index);
+			}
+
+			if (index >= mg->max_tp_rate)
+				continue;
+
+			if (mr->cur_tp > cur_tp2) {
+				mg->max_tp_rate2 = index;
+				cur_tp2 = mr->cur_tp;
+			}
+		}
+	}
+
+	/* try to sample up to half of the availble rates during each interval */
+	mi->sample_count *= 4;
+
+	cur_prob = 0;
+	cur_prob_tp = 0;
+	cur_tp = 0;
+	cur_tp2 = 0;
+	for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
+		mg = &mi->groups[group];
+		if (!mg->supported)
+			continue;
+
+		mr = minstrel_get_ratestats(mi, mg->max_prob_rate);
+		if (cur_prob_tp < mr->cur_tp &&
+		    minstrel_mcs_groups[group].streams == 1) {
+			mi->max_prob_rate = mg->max_prob_rate;
+			cur_prob = mr->cur_prob;
+			cur_prob_tp = mr->cur_tp;
+		}
+
+		mr = minstrel_get_ratestats(mi, mg->max_tp_rate);
+		if (cur_tp < mr->cur_tp) {
+			mi->max_tp_rate = mg->max_tp_rate;
+			cur_tp = mr->cur_tp;
+		}
+
+		mr = minstrel_get_ratestats(mi, mg->max_tp_rate2);
+		if (cur_tp2 < mr->cur_tp) {
+			mi->max_tp_rate2 = mg->max_tp_rate2;
+			cur_tp2 = mr->cur_tp;
+		}
+	}
+
+	mi->stats_update = jiffies;
+}
+
+static bool
+minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate)
+{
+	if (!rate->count)
+		return false;
+
+	if (rate->idx < 0)
+		return false;
+
+	return !!(rate->flags & IEEE80211_TX_RC_MCS);
+}
+
+static void
+minstrel_next_sample_idx(struct minstrel_ht_sta *mi)
+{
+	struct minstrel_mcs_group_data *mg;
+
+	for (;;) {
+		mi->sample_group++;
+		mi->sample_group %= ARRAY_SIZE(minstrel_mcs_groups);
+		mg = &mi->groups[mi->sample_group];
+
+		if (!mg->supported)
+			continue;
+
+		if (++mg->index >= MCS_GROUP_RATES) {
+			mg->index = 0;
+			if (++mg->column >= ARRAY_SIZE(sample_table))
+				mg->column = 0;
+		}
+		break;
+	}
+}
+
+static void
+minstrel_downgrade_rate(struct minstrel_ht_sta *mi, unsigned int *idx,
+			bool primary)
+{
+	int group, orig_group;
+
+	orig_group = group = *idx / MCS_GROUP_RATES;
+	while (group > 0) {
+		group--;
+
+		if (!mi->groups[group].supported)
+			continue;
+
+		if (minstrel_mcs_groups[group].streams >
+		    minstrel_mcs_groups[orig_group].streams)
+			continue;
+
+		if (primary)
+			*idx = mi->groups[group].max_tp_rate;
+		else
+			*idx = mi->groups[group].max_tp_rate2;
+		break;
+	}
+}
+
+static void
+minstrel_aggr_check(struct minstrel_priv *mp, struct ieee80211_sta *pubsta, struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+	u16 tid;
+
+	if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
+		return;
+
+	if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
+		return;
+
+	tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+	if (likely(sta->ampdu_mlme.tid_tx[tid]))
+		return;
+
+	ieee80211_start_tx_ba_session(pubsta, tid);
+}
+
+static void
+minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
+                      struct ieee80211_sta *sta, void *priv_sta,
+                      struct sk_buff *skb)
+{
+	struct minstrel_ht_sta_priv *msp = priv_sta;
+	struct minstrel_ht_sta *mi = &msp->ht;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_tx_rate *ar = info->status.rates;
+	struct minstrel_rate_stats *rate, *rate2;
+	struct minstrel_priv *mp = priv;
+	bool last = false;
+	int group;
+	int i = 0;
+
+	if (!msp->is_ht)
+		return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb);
+
+	/* This packet was aggregated but doesn't carry status info */
+	if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+	    !(info->flags & IEEE80211_TX_STAT_AMPDU))
+		return;
+
+	if (!info->status.ampdu_len) {
+		info->status.ampdu_ack_len = 1;
+		info->status.ampdu_len = 1;
+	}
+
+	mi->ampdu_packets++;
+	mi->ampdu_len += info->status.ampdu_len;
+
+	if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) {
+		mi->sample_wait = 4 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len);
+		mi->sample_tries = 3;
+		mi->sample_count--;
+	}
+
+	if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
+		mi->sample_packets += info->status.ampdu_len;
+		minstrel_next_sample_idx(mi);
+	}
+
+	for (i = 0; !last; i++) {
+		last = (i == IEEE80211_TX_MAX_RATES - 1) ||
+		       !minstrel_ht_txstat_valid(&ar[i + 1]);
+
+		if (!minstrel_ht_txstat_valid(&ar[i]))
+			break;
+
+		group = minstrel_ht_get_group_idx(&ar[i]);
+		rate = &mi->groups[group].rates[ar[i].idx % 8];
+
+		if (last && (info->flags & IEEE80211_TX_STAT_ACK))
+			rate->success += info->status.ampdu_ack_len;
+
+		rate->attempts += ar[i].count * info->status.ampdu_len;
+	}
+
+	/*
+	 * check for sudden death of spatial multiplexing,
+	 * downgrade to a lower number of streams if necessary.
+	 */
+	rate = minstrel_get_ratestats(mi, mi->max_tp_rate);
+	if (rate->attempts > 30 &&
+	    MINSTREL_FRAC(rate->success, rate->attempts) <
+	    MINSTREL_FRAC(20, 100))
+		minstrel_downgrade_rate(mi, &mi->max_tp_rate, true);
+
+	rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2);
+	if (rate2->attempts > 30 &&
+	    MINSTREL_FRAC(rate2->success, rate2->attempts) <
+	    MINSTREL_FRAC(20, 100))
+		minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false);
+
+	if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
+		minstrel_ht_update_stats(mp, mi);
+		minstrel_aggr_check(mp, sta, skb);
+	}
+}
+
+static void
+minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
+                         int index)
+{
+	struct minstrel_rate_stats *mr;
+	const struct mcs_group *group;
+	unsigned int tx_time, tx_time_rtscts, tx_time_data;
+	unsigned int cw = mp->cw_min;
+	unsigned int t_slot = 9; /* FIXME */
+	unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len);
+
+	mr = minstrel_get_ratestats(mi, index);
+	if (mr->probability < MINSTREL_FRAC(1, 10)) {
+		mr->retry_count = 1;
+		mr->retry_count_rtscts = 1;
+		return;
+	}
+
+	mr->retry_count = 2;
+	mr->retry_count_rtscts = 2;
+	mr->retry_updated = true;
+
+	group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
+	tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len;
+	tx_time = 2 * (t_slot + mi->overhead + tx_time_data);
+	tx_time_rtscts = 2 * (t_slot + mi->overhead_rtscts + tx_time_data);
+	do {
+		cw = (cw << 1) | 1;
+		cw = min(cw, mp->cw_max);
+		tx_time += cw + t_slot + mi->overhead;
+		tx_time_rtscts += cw + t_slot + mi->overhead_rtscts;
+		if (tx_time_rtscts < mp->segment_size)
+			mr->retry_count_rtscts++;
+	} while ((tx_time < mp->segment_size) &&
+	         (++mr->retry_count < mp->max_retry));
+}
+
+
+static void
+minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
+                     struct ieee80211_tx_rate *rate, int index,
+                     struct ieee80211_tx_rate_control *txrc,
+                     bool sample, bool rtscts)
+{
+	const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
+	struct minstrel_rate_stats *mr;
+
+	mr = minstrel_get_ratestats(mi, index);
+	if (!mr->retry_updated)
+		minstrel_calc_retransmit(mp, mi, index);
+
+	if (mr->probability < MINSTREL_FRAC(20, 100))
+		rate->count = 2;
+	else if (rtscts)
+		rate->count = mr->retry_count_rtscts;
+	else
+		rate->count = mr->retry_count;
+
+	rate->flags = IEEE80211_TX_RC_MCS | group->flags;
+	if (txrc->short_preamble)
+		rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
+	if (txrc->rts || rtscts)
+		rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
+	rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES;
+}
+
+static inline int
+minstrel_get_duration(int index)
+{
+	const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
+	return group->duration[index % MCS_GROUP_RATES];
+}
+
+static int
+minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
+{
+	struct minstrel_rate_stats *mr;
+	struct minstrel_mcs_group_data *mg;
+	int sample_idx = 0;
+
+	if (mi->sample_wait > 0) {
+		mi->sample_wait--;
+		return -1;
+	}
+
+	if (!mi->sample_tries)
+		return -1;
+
+	mi->sample_tries--;
+	mg = &mi->groups[mi->sample_group];
+	sample_idx = sample_table[mg->column][mg->index];
+	mr = &mg->rates[sample_idx];
+	sample_idx += mi->sample_group * MCS_GROUP_RATES;
+
+	/*
+	 * When not using MRR, do not sample if the probability is already
+	 * higher than 95% to avoid wasting airtime
+	 */
+	if (!mp->has_mrr && (mr->probability > MINSTREL_FRAC(95, 100)))
+		goto next;
+
+	/*
+	 * Make sure that lower rates get sampled only occasionally,
+	 * if the link is working perfectly.
+	 */
+	if (minstrel_get_duration(sample_idx) >
+	    minstrel_get_duration(mi->max_tp_rate)) {
+		if (mr->sample_skipped < 10)
+			goto next;
+
+		if (mi->sample_slow++ > 2)
+			goto next;
+	}
+
+	return sample_idx;
+
+next:
+	minstrel_next_sample_idx(mi);
+	return -1;
+}
+
+static void
+minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+                     struct ieee80211_tx_rate_control *txrc)
+{
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
+	struct ieee80211_tx_rate *ar = info->status.rates;
+	struct minstrel_ht_sta_priv *msp = priv_sta;
+	struct minstrel_ht_sta *mi = &msp->ht;
+	struct minstrel_priv *mp = priv;
+	int sample_idx;
+
+	if (rate_control_send_low(sta, priv_sta, txrc))
+		return;
+
+	if (!msp->is_ht)
+		return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
+
+	info->flags |= mi->tx_flags;
+	sample_idx = minstrel_get_sample_rate(mp, mi);
+	if (sample_idx >= 0) {
+		minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx,
+			txrc, true, false);
+		minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate,
+			txrc, false, true);
+		info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+	} else {
+		minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate,
+			txrc, false, false);
+		minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2,
+			txrc, false, true);
+	}
+	minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, txrc, false, true);
+
+	ar[3].count = 0;
+	ar[3].idx = -1;
+
+	mi->total_packets++;
+
+	/* wraparound */
+	if (mi->total_packets == ~0) {
+		mi->total_packets = 0;
+		mi->sample_packets = 0;
+	}
+}
+
+static void
+minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
+                        struct ieee80211_sta *sta, void *priv_sta,
+			enum nl80211_channel_type oper_chan_type)
+{
+	struct minstrel_priv *mp = priv;
+	struct minstrel_ht_sta_priv *msp = priv_sta;
+	struct minstrel_ht_sta *mi = &msp->ht;
+	struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs;
+	struct ieee80211_local *local = hw_to_local(mp->hw);
+	u16 sta_cap = sta->ht_cap.cap;
+	int ack_dur;
+	int stbc;
+	int i;
+
+	/* fall back to the old minstrel for legacy stations */
+	if (!sta->ht_cap.ht_supported) {
+		msp->is_ht = false;
+		memset(&msp->legacy, 0, sizeof(msp->legacy));
+		msp->legacy.r = msp->ratelist;
+		msp->legacy.sample_table = msp->sample_table;
+		return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy);
+	}
+
+	BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) !=
+		MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS);
+
+	msp->is_ht = true;
+	memset(mi, 0, sizeof(*mi));
+	mi->stats_update = jiffies;
+
+	ack_dur = ieee80211_frame_duration(local, 10, 60, 1, 1);
+	mi->overhead = ieee80211_frame_duration(local, 0, 60, 1, 1) + ack_dur;
+	mi->overhead_rtscts = mi->overhead + 2 * ack_dur;
+
+	mi->avg_ampdu_len = MINSTREL_FRAC(1, 1);
+
+	/* When using MRR, sample more on the first attempt, without delay */
+	if (mp->has_mrr) {
+		mi->sample_count = 16;
+		mi->sample_wait = 0;
+	} else {
+		mi->sample_count = 8;
+		mi->sample_wait = 8;
+	}
+	mi->sample_tries = 4;
+
+	stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >>
+		IEEE80211_HT_CAP_RX_STBC_SHIFT;
+	mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT;
+
+	if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
+		mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
+
+	if (oper_chan_type != NL80211_CHAN_HT40MINUS &&
+	    oper_chan_type != NL80211_CHAN_HT40PLUS)
+		sta_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+	for (i = 0; i < ARRAY_SIZE(mi->groups); i++) {
+		u16 req = 0;
+
+		mi->groups[i].supported = 0;
+		if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) {
+			if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+				req |= IEEE80211_HT_CAP_SGI_40;
+			else
+				req |= IEEE80211_HT_CAP_SGI_20;
+		}
+
+		if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+			req |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+		if ((sta_cap & req) != req)
+			continue;
+
+		mi->groups[i].supported =
+			mcs->rx_mask[minstrel_mcs_groups[i].streams - 1];
+	}
+}
+
+static void
+minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband,
+                      struct ieee80211_sta *sta, void *priv_sta)
+{
+	struct minstrel_priv *mp = priv;
+
+	minstrel_ht_update_caps(priv, sband, sta, priv_sta, mp->hw->conf.channel_type);
+}
+
+static void
+minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband,
+                        struct ieee80211_sta *sta, void *priv_sta,
+                        u32 changed, enum nl80211_channel_type oper_chan_type)
+{
+	minstrel_ht_update_caps(priv, sband, sta, priv_sta, oper_chan_type);
+}
+
+static void *
+minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
+{
+	struct ieee80211_supported_band *sband;
+	struct minstrel_ht_sta_priv *msp;
+	struct minstrel_priv *mp = priv;
+	struct ieee80211_hw *hw = mp->hw;
+	int max_rates = 0;
+	int i;
+
+	for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
+		sband = hw->wiphy->bands[i];
+		if (sband && sband->n_bitrates > max_rates)
+			max_rates = sband->n_bitrates;
+	}
+
+	msp = kzalloc(sizeof(struct minstrel_ht_sta), gfp);
+	if (!msp)
+		return NULL;
+
+	msp->ratelist = kzalloc(sizeof(struct minstrel_rate) * max_rates, gfp);
+	if (!msp->ratelist)
+		goto error;
+
+	msp->sample_table = kmalloc(SAMPLE_COLUMNS * max_rates, gfp);
+	if (!msp->sample_table)
+		goto error1;
+
+	return msp;
+
+error1:
+	kfree(msp->ratelist);
+error:
+	kfree(msp);
+	return NULL;
+}
+
+static void
+minstrel_ht_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta)
+{
+	struct minstrel_ht_sta_priv *msp = priv_sta;
+
+	kfree(msp->sample_table);
+	kfree(msp->ratelist);
+	kfree(msp);
+}
+
+static void *
+minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
+{
+	return mac80211_minstrel.alloc(hw, debugfsdir);
+}
+
+static void
+minstrel_ht_free(void *priv)
+{
+	mac80211_minstrel.free(priv);
+}
+
+static struct rate_control_ops mac80211_minstrel_ht = {
+	.name = "minstrel_ht",
+	.tx_status = minstrel_ht_tx_status,
+	.get_rate = minstrel_ht_get_rate,
+	.rate_init = minstrel_ht_rate_init,
+	.rate_update = minstrel_ht_rate_update,
+	.alloc_sta = minstrel_ht_alloc_sta,
+	.free_sta = minstrel_ht_free_sta,
+	.alloc = minstrel_ht_alloc,
+	.free = minstrel_ht_free,
+#ifdef CONFIG_MAC80211_DEBUGFS
+	.add_sta_debugfs = minstrel_ht_add_sta_debugfs,
+	.remove_sta_debugfs = minstrel_ht_remove_sta_debugfs,
+#endif
+};
+
+
+static void
+init_sample_table(void)
+{
+	int col, i, new_idx;
+	u8 rnd[MCS_GROUP_RATES];
+
+	memset(sample_table, 0xff, sizeof(sample_table));
+	for (col = 0; col < SAMPLE_COLUMNS; col++) {
+		for (i = 0; i < MCS_GROUP_RATES; i++) {
+			get_random_bytes(rnd, sizeof(rnd));
+			new_idx = (i + rnd[i]) % MCS_GROUP_RATES;
+
+			while (sample_table[col][new_idx] != 0xff)
+				new_idx = (new_idx + 1) % MCS_GROUP_RATES;
+
+			sample_table[col][new_idx] = i;
+		}
+	}
+}
+
+int __init
+rc80211_minstrel_ht_init(void)
+{
+	init_sample_table();
+	return ieee80211_rate_control_register(&mac80211_minstrel_ht);
+}
+
+void
+rc80211_minstrel_ht_exit(void)
+{
+	ieee80211_rate_control_unregister(&mac80211_minstrel_ht);
+}
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
new file mode 100644
index 0000000..462d2b2
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.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 __RC_MINSTREL_HT_H
+#define __RC_MINSTREL_HT_H
+
+/*
+ * The number of streams can be changed to 2 to reduce code
+ * size and memory footprint.
+ */
+#define MINSTREL_MAX_STREAMS	3
+#define MINSTREL_STREAM_GROUPS	4
+
+/* scaled fraction values */
+#define MINSTREL_SCALE	16
+#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
+#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
+
+#define MCS_GROUP_RATES	8
+
+struct mcs_group {
+	u32 flags;
+	unsigned int streams;
+	unsigned int duration[MCS_GROUP_RATES];
+};
+
+extern const struct mcs_group minstrel_mcs_groups[];
+
+struct minstrel_rate_stats {
+	/* current / last sampling period attempts/success counters */
+	unsigned int attempts, last_attempts;
+	unsigned int success, last_success;
+
+	/* total attempts/success counters */
+	u64 att_hist, succ_hist;
+
+	/* current throughput */
+	unsigned int cur_tp;
+
+	/* packet delivery probabilities */
+	unsigned int cur_prob, probability;
+
+	/* maximum retry counts */
+	unsigned int retry_count;
+	unsigned int retry_count_rtscts;
+
+	bool retry_updated;
+	u8 sample_skipped;
+};
+
+struct minstrel_mcs_group_data {
+	u8 index;
+	u8 column;
+
+	/* bitfield of supported MCS rates of this group */
+	u8 supported;
+
+	/* selected primary rates */
+	unsigned int max_tp_rate;
+	unsigned int max_tp_rate2;
+	unsigned int max_prob_rate;
+
+	/* MCS rate statistics */
+	struct minstrel_rate_stats rates[MCS_GROUP_RATES];
+};
+
+struct minstrel_ht_sta {
+	/* ampdu length (average, per sampling interval) */
+	unsigned int ampdu_len;
+	unsigned int ampdu_packets;
+
+	/* ampdu length (EWMA) */
+	unsigned int avg_ampdu_len;
+
+	/* best throughput rate */
+	unsigned int max_tp_rate;
+
+	/* second best throughput rate */
+	unsigned int max_tp_rate2;
+
+	/* best probability rate */
+	unsigned int max_prob_rate;
+
+	/* time of last status update */
+	unsigned long stats_update;
+
+	/* overhead time in usec for each frame */
+	unsigned int overhead;
+	unsigned int overhead_rtscts;
+
+	unsigned int total_packets;
+	unsigned int sample_packets;
+
+	/* tx flags to add for frames for this sta */
+	u32 tx_flags;
+
+	u8 sample_wait;
+	u8 sample_tries;
+	u8 sample_count;
+	u8 sample_slow;
+
+	/* current MCS group to be sampled */
+	u8 sample_group;
+
+	/* MCS rate group info and statistics */
+	struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS];
+};
+
+struct minstrel_ht_sta_priv {
+	union {
+		struct minstrel_ht_sta ht;
+		struct minstrel_sta_info legacy;
+	};
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct dentry *dbg_stats;
+#endif
+	void *ratelist;
+	void *sample_table;
+	bool is_ht;
+};
+
+void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
+void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta);
+
+#endif
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
new file mode 100644
index 0000000..4a5a4b3
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "rc80211_minstrel.h"
+#include "rc80211_minstrel_ht.h"
+
+static int
+minstrel_ht_stats_open(struct inode *inode, struct file *file)
+{
+	struct minstrel_ht_sta_priv *msp = inode->i_private;
+	struct minstrel_ht_sta *mi = &msp->ht;
+	struct minstrel_debugfs_info *ms;
+	unsigned int i, j, tp, prob, eprob;
+	char *p;
+	int ret;
+
+	if (!msp->is_ht) {
+		inode->i_private = &msp->legacy;
+		ret = minstrel_stats_open(inode, file);
+		inode->i_private = msp;
+		return ret;
+	}
+
+	ms = kmalloc(sizeof(*ms) + 8192, GFP_KERNEL);
+	if (!ms)
+		return -ENOMEM;
+
+	file->private_data = ms;
+	p = ms->buf;
+	p += sprintf(p, "type      rate     throughput  ewma prob   this prob  "
+			"this succ/attempt   success    attempts\n");
+	for (i = 0; i < MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; i++) {
+		char htmode = '2';
+		char gimode = 'L';
+
+		if (!mi->groups[i].supported)
+			continue;
+
+		if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+			htmode = '4';
+		if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI)
+			gimode = 'S';
+
+		for (j = 0; j < MCS_GROUP_RATES; j++) {
+			struct minstrel_rate_stats *mr = &mi->groups[i].rates[j];
+			int idx = i * MCS_GROUP_RATES + j;
+
+			if (!(mi->groups[i].supported & BIT(j)))
+				continue;
+
+			p += sprintf(p, "HT%c0/%cGI ", htmode, gimode);
+
+			*(p++) = (idx == mi->max_tp_rate) ? 'T' : ' ';
+			*(p++) = (idx == mi->max_tp_rate2) ? 't' : ' ';
+			*(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
+			p += sprintf(p, "MCS%-2u", (minstrel_mcs_groups[i].streams - 1) *
+					MCS_GROUP_RATES + j);
+
+			tp = mr->cur_tp / 10;
+			prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
+			eprob = MINSTREL_TRUNC(mr->probability * 1000);
+
+			p += sprintf(p, "  %6u.%1u   %6u.%1u   %6u.%1u        "
+					"%3u(%3u)   %8llu    %8llu\n",
+					tp / 10, tp % 10,
+					eprob / 10, eprob % 10,
+					prob / 10, prob % 10,
+					mr->last_success,
+					mr->last_attempts,
+					(unsigned long long)mr->succ_hist,
+					(unsigned long long)mr->att_hist);
+		}
+	}
+	p += sprintf(p, "\nTotal packet count::    ideal %d      "
+			"lookaround %d\n",
+			max(0, (int) mi->total_packets - (int) mi->sample_packets),
+			mi->sample_packets);
+	p += sprintf(p, "Average A-MPDU length: %d.%d\n",
+		MINSTREL_TRUNC(mi->avg_ampdu_len),
+		MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
+	ms->len = p - ms->buf;
+
+	return 0;
+}
+
+static const struct file_operations minstrel_ht_stat_fops = {
+	.owner = THIS_MODULE,
+	.open = minstrel_ht_stats_open,
+	.read = minstrel_stats_read,
+	.release = minstrel_stats_release,
+};
+
+void
+minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir)
+{
+	struct minstrel_ht_sta_priv *msp = priv_sta;
+
+	msp->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, msp,
+			&minstrel_ht_stat_fops);
+}
+
+void
+minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta)
+{
+	struct minstrel_ht_sta_priv *msp = priv_sta;
+
+	debugfs_remove(msp->dbg_stats);
+}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index be9abc2..fa0f37e 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -293,7 +293,7 @@
 			skb2 = skb_clone(skb, GFP_ATOMIC);
 			if (skb2) {
 				skb2->dev = prev_dev;
-				netif_rx(skb2);
+				netif_receive_skb(skb2);
 			}
 		}
 
@@ -304,7 +304,7 @@
 
 	if (prev_dev) {
 		skb->dev = prev_dev;
-		netif_rx(skb);
+		netif_receive_skb(skb);
 	} else
 		dev_kfree_skb(skb);
 
@@ -719,16 +719,13 @@
 
 	tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 
-	spin_lock(&sta->lock);
-
-	if (!sta->ampdu_mlme.tid_active_rx[tid])
-		goto dont_reorder_unlock;
-
-	tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
+	tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
+	if (!tid_agg_rx)
+		goto dont_reorder;
 
 	/* qos null data frames are excluded */
 	if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
-		goto dont_reorder_unlock;
+		goto dont_reorder;
 
 	/* new, potentially un-ordered, ampdu frame - process it */
 
@@ -740,20 +737,22 @@
 	/* if this mpdu is fragmented - terminate rx aggregation session */
 	sc = le16_to_cpu(hdr->seq_ctrl);
 	if (sc & IEEE80211_SCTL_FRAG) {
-		spin_unlock(&sta->lock);
-		__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
-					       WLAN_REASON_QSTA_REQUIRE_SETUP);
-		dev_kfree_skb(skb);
+		skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
+		skb_queue_tail(&rx->sdata->skb_queue, skb);
+		ieee80211_queue_work(&local->hw, &rx->sdata->work);
 		return;
 	}
 
-	if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames)) {
-		spin_unlock(&sta->lock);
+	/*
+	 * No locking needed -- we will only ever process one
+	 * RX packet at a time, and thus own tid_agg_rx. All
+	 * other code manipulating it needs to (and does) make
+	 * sure that we cannot get to it any more before doing
+	 * anything with it.
+	 */
+	if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames))
 		return;
-	}
 
- dont_reorder_unlock:
-	spin_unlock(&sta->lock);
  dont_reorder:
 	__skb_queue_tail(frames, skb);
 }
@@ -825,6 +824,7 @@
 	ieee80211_rx_result result = RX_DROP_UNUSABLE;
 	struct ieee80211_key *stakey = NULL;
 	int mmie_keyidx = -1;
+	__le16 fc;
 
 	/*
 	 * Key selection 101
@@ -866,13 +866,15 @@
 	if (rx->sta)
 		stakey = rcu_dereference(rx->sta->key);
 
-	if (!ieee80211_has_protected(hdr->frame_control))
+	fc = hdr->frame_control;
+
+	if (!ieee80211_has_protected(fc))
 		mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
 
 	if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
 		rx->key = stakey;
 		/* Skip decryption if the frame is not protected. */
-		if (!ieee80211_has_protected(hdr->frame_control))
+		if (!ieee80211_has_protected(fc))
 			return RX_CONTINUE;
 	} else if (mmie_keyidx >= 0) {
 		/* Broadcast/multicast robust management frame / BIP */
@@ -884,7 +886,7 @@
 		    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
 			return RX_DROP_MONITOR; /* unexpected BIP keyidx */
 		rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
-	} else if (!ieee80211_has_protected(hdr->frame_control)) {
+	} else if (!ieee80211_has_protected(fc)) {
 		/*
 		 * The frame was not protected, so skip decryption. However, we
 		 * need to set rx->key if there is a key that could have been
@@ -892,7 +894,7 @@
 		 * have been expected.
 		 */
 		struct ieee80211_key *key = NULL;
-		if (ieee80211_is_mgmt(hdr->frame_control) &&
+		if (ieee80211_is_mgmt(fc) &&
 		    is_multicast_ether_addr(hdr->addr1) &&
 		    (key = rcu_dereference(rx->sdata->default_mgmt_key)))
 			rx->key = key;
@@ -914,7 +916,7 @@
 		    (status->flag & RX_FLAG_IV_STRIPPED))
 			return RX_CONTINUE;
 
-		hdrlen = ieee80211_hdrlen(hdr->frame_control);
+		hdrlen = ieee80211_hdrlen(fc);
 
 		if (rx->skb->len < 8 + hdrlen)
 			return RX_DROP_UNUSABLE; /* TODO: count this? */
@@ -947,19 +949,17 @@
 
 	if (skb_linearize(rx->skb))
 		return RX_DROP_UNUSABLE;
-
-	hdr = (struct ieee80211_hdr *)rx->skb->data;
-
-	/* Check for weak IVs if possible */
-	if (rx->sta && rx->key->conf.alg == ALG_WEP &&
-	    ieee80211_is_data(hdr->frame_control) &&
-	    (!(status->flag & RX_FLAG_IV_STRIPPED) ||
-	     !(status->flag & RX_FLAG_DECRYPTED)) &&
-	    ieee80211_wep_is_weak_iv(rx->skb, rx->key))
-		rx->sta->wep_weak_iv_count++;
+	/* the hdr variable is invalid now! */
 
 	switch (rx->key->conf.alg) {
 	case ALG_WEP:
+		/* Check for weak IVs if possible */
+		if (rx->sta && ieee80211_is_data(fc) &&
+		    (!(status->flag & RX_FLAG_IV_STRIPPED) ||
+		     !(status->flag & RX_FLAG_DECRYPTED)) &&
+		    ieee80211_wep_is_weak_iv(rx->skb, rx->key))
+			rx->sta->wep_weak_iv_count++;
+
 		result = ieee80211_crypto_wep_decrypt(rx);
 		break;
 	case ALG_TKIP:
@@ -1267,11 +1267,13 @@
 						 rx->queue, &(rx->skb));
 		if (rx->key && rx->key->conf.alg == ALG_CCMP &&
 		    ieee80211_has_protected(fc)) {
+			int queue = ieee80211_is_mgmt(fc) ?
+				NUM_RX_DATA_QUEUES : rx->queue;
 			/* Store CCMP PN so that we can verify that the next
 			 * fragment has a sequential PN value. */
 			entry->ccmp = 1;
 			memcpy(entry->last_pn,
-			       rx->key->u.ccmp.rx_pn[rx->queue],
+			       rx->key->u.ccmp.rx_pn[queue],
 			       CCMP_PN_LEN);
 		}
 		return RX_QUEUED;
@@ -1291,6 +1293,7 @@
 	if (entry->ccmp) {
 		int i;
 		u8 pn[CCMP_PN_LEN], *rpn;
+		int queue;
 		if (!rx->key || rx->key->conf.alg != ALG_CCMP)
 			return RX_DROP_UNUSABLE;
 		memcpy(pn, entry->last_pn, CCMP_PN_LEN);
@@ -1299,7 +1302,9 @@
 			if (pn[i])
 				break;
 		}
-		rpn = rx->key->u.ccmp.rx_pn[rx->queue];
+		queue = ieee80211_is_mgmt(fc) ?
+			NUM_RX_DATA_QUEUES : rx->queue;
+		rpn = rx->key->u.ccmp.rx_pn[queue];
 		if (memcmp(pn, rpn, CCMP_PN_LEN))
 			return RX_DROP_UNUSABLE;
 		memcpy(entry->last_pn, pn, CCMP_PN_LEN);
@@ -1573,7 +1578,7 @@
 			/* deliver to local stack */
 			skb->protocol = eth_type_trans(skb, dev);
 			memset(skb->cb, 0, sizeof(skb->cb));
-			netif_rx(skb);
+			netif_receive_skb(skb);
 		}
 	}
 
@@ -1829,13 +1834,11 @@
 				  &bar_data, sizeof(bar_data)))
 			return RX_DROP_MONITOR;
 
-		spin_lock(&rx->sta->lock);
 		tid = le16_to_cpu(bar_data.control) >> 12;
-		if (!rx->sta->ampdu_mlme.tid_active_rx[tid]) {
-			spin_unlock(&rx->sta->lock);
+
+		tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]);
+		if (!tid_agg_rx)
 			return RX_DROP_MONITOR;
-		}
-		tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid];
 
 		start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4;
 
@@ -1848,11 +1851,15 @@
 		ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num,
 						 frames);
 		kfree_skb(skb);
-		spin_unlock(&rx->sta->lock);
 		return RX_QUEUED;
 	}
 
-	return RX_CONTINUE;
+	/*
+	 * After this point, we only want management frames,
+	 * so we can drop all remaining control frames to
+	 * cooked monitor interfaces.
+	 */
+	return RX_DROP_MONITOR;
 }
 
 static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
@@ -1944,30 +1951,27 @@
 		if (len < IEEE80211_MIN_ACTION_SIZE + 1)
 			break;
 
-		if (sdata->vif.type == NL80211_IFTYPE_STATION)
-			return ieee80211_sta_rx_mgmt(sdata, rx->skb);
-
 		switch (mgmt->u.action.u.addba_req.action_code) {
 		case WLAN_ACTION_ADDBA_REQ:
 			if (len < (IEEE80211_MIN_ACTION_SIZE +
 				   sizeof(mgmt->u.action.u.addba_req)))
-				return RX_DROP_MONITOR;
-			ieee80211_process_addba_request(local, rx->sta, mgmt, len);
-			goto handled;
+				goto invalid;
+			break;
 		case WLAN_ACTION_ADDBA_RESP:
 			if (len < (IEEE80211_MIN_ACTION_SIZE +
 				   sizeof(mgmt->u.action.u.addba_resp)))
-				break;
-			ieee80211_process_addba_resp(local, rx->sta, mgmt, len);
-			goto handled;
+				goto invalid;
+			break;
 		case WLAN_ACTION_DELBA:
 			if (len < (IEEE80211_MIN_ACTION_SIZE +
 				   sizeof(mgmt->u.action.u.delba)))
-				break;
-			ieee80211_process_delba(sdata, rx->sta, mgmt, len);
-			goto handled;
+				goto invalid;
+			break;
+		default:
+			goto invalid;
 		}
-		break;
+
+		goto queue;
 	case WLAN_CATEGORY_SPECTRUM_MGMT:
 		if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
 			break;
@@ -1997,7 +2001,7 @@
 			if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
 				break;
 
-			return ieee80211_sta_rx_mgmt(sdata, rx->skb);
+			goto queue;
 		}
 		break;
 	case WLAN_CATEGORY_SA_QUERY:
@@ -2015,11 +2019,12 @@
 		break;
 	case WLAN_CATEGORY_MESH_PLINK:
 	case WLAN_CATEGORY_MESH_PATH_SEL:
-		if (ieee80211_vif_is_mesh(&sdata->vif))
-			return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
-		break;
+		if (!ieee80211_vif_is_mesh(&sdata->vif))
+			break;
+		goto queue;
 	}
 
+ invalid:
 	/*
 	 * For AP mode, hostapd is responsible for handling any action
 	 * frames that we didn't handle, including returning unknown
@@ -2039,8 +2044,7 @@
 	 */
 	status = IEEE80211_SKB_RXCB(rx->skb);
 
-	if (sdata->vif.type == NL80211_IFTYPE_STATION &&
-	    cfg80211_rx_action(rx->sdata->dev, status->freq,
+	if (cfg80211_rx_action(rx->sdata->dev, status->freq,
 			       rx->skb->data, rx->skb->len,
 			       GFP_ATOMIC))
 		goto handled;
@@ -2052,11 +2056,11 @@
 	nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0,
 			       GFP_ATOMIC);
 	if (nskb) {
-		struct ieee80211_mgmt *mgmt = (void *)nskb->data;
+		struct ieee80211_mgmt *nmgmt = (void *)nskb->data;
 
-		mgmt->u.action.category |= 0x80;
-		memcpy(mgmt->da, mgmt->sa, ETH_ALEN);
-		memcpy(mgmt->sa, rx->sdata->vif.addr, ETH_ALEN);
+		nmgmt->u.action.category |= 0x80;
+		memcpy(nmgmt->da, nmgmt->sa, ETH_ALEN);
+		memcpy(nmgmt->sa, rx->sdata->vif.addr, ETH_ALEN);
 
 		memset(nskb->cb, 0, sizeof(nskb->cb));
 
@@ -2068,6 +2072,14 @@
 		rx->sta->rx_packets++;
 	dev_kfree_skb(rx->skb);
 	return RX_QUEUED;
+
+ queue:
+	rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
+	skb_queue_tail(&sdata->skb_queue, rx->skb);
+	ieee80211_queue_work(&local->hw, &sdata->work);
+	if (rx->sta)
+		rx->sta->rx_packets++;
+	return RX_QUEUED;
 }
 
 static ieee80211_rx_result debug_noinline
@@ -2075,10 +2087,15 @@
 {
 	struct ieee80211_sub_if_data *sdata = rx->sdata;
 	ieee80211_rx_result rxs;
+	struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
+	__le16 stype;
 
 	if (!(rx->flags & IEEE80211_RX_RA_MATCH))
 		return RX_DROP_MONITOR;
 
+	if (rx->skb->len < 24)
+		return RX_DROP_MONITOR;
+
 	if (ieee80211_drop_unencrypted_mgmt(rx))
 		return RX_DROP_UNUSABLE;
 
@@ -2086,16 +2103,42 @@
 	if (rxs != RX_CONTINUE)
 		return rxs;
 
-	if (ieee80211_vif_is_mesh(&sdata->vif))
-		return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
+	stype = mgmt->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);
 
-	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
-		return ieee80211_ibss_rx_mgmt(sdata, rx->skb);
+	if (!ieee80211_vif_is_mesh(&sdata->vif) &&
+	    sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+	    sdata->vif.type != NL80211_IFTYPE_STATION)
+		return RX_DROP_MONITOR;
 
-	if (sdata->vif.type == NL80211_IFTYPE_STATION)
-		return ieee80211_sta_rx_mgmt(sdata, rx->skb);
+	switch (stype) {
+	case cpu_to_le16(IEEE80211_STYPE_BEACON):
+	case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
+		/* process for all: mesh, mlme, ibss */
+		break;
+	case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+	case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
+		/* process only for station */
+		if (sdata->vif.type != NL80211_IFTYPE_STATION)
+			return RX_DROP_MONITOR;
+		break;
+	case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
+	case cpu_to_le16(IEEE80211_STYPE_AUTH):
+		/* process only for ibss */
+		if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
+			return RX_DROP_MONITOR;
+		break;
+	default:
+		return RX_DROP_MONITOR;
+	}
 
-	return RX_DROP_MONITOR;
+	/* queue up frame and kick off work to process it */
+	rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
+	skb_queue_tail(&sdata->skb_queue, rx->skb);
+	ieee80211_queue_work(&rx->local->hw, &sdata->work);
+	if (rx->sta)
+		rx->sta->rx_packets++;
+
+	return RX_QUEUED;
 }
 
 static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
@@ -2151,7 +2194,7 @@
 		u8 rate_or_pad;
 		__le16 chan_freq;
 		__le16 chan_flags;
-	} __attribute__ ((packed)) *rthdr;
+	} __packed *rthdr;
 	struct sk_buff *skb = rx->skb, *skb2;
 	struct net_device *prev_dev = NULL;
 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
@@ -2201,7 +2244,7 @@
 			skb2 = skb_clone(skb, GFP_ATOMIC);
 			if (skb2) {
 				skb2->dev = prev_dev;
-				netif_rx(skb2);
+				netif_receive_skb(skb2);
 			}
 		}
 
@@ -2212,7 +2255,7 @@
 
 	if (prev_dev) {
 		skb->dev = prev_dev;
-		netif_rx(skb);
+		netif_receive_skb(skb);
 		skb = NULL;
 	} else
 		goto out_free_skb;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index e1b0be7..41f20fb 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -114,6 +114,10 @@
 		bss->dtim_period = tim_ie->dtim_period;
 	}
 
+	/* If the beacon had no TIM IE, or it was invalid, use 1 */
+	if (beacon && !bss->dtim_period)
+		bss->dtim_period = 1;
+
 	/* replace old supported rates if we get new values */
 	srlen = 0;
 	if (elems->supp_rates) {
@@ -734,7 +738,7 @@
 {
 	struct ieee80211_local *local = sdata->local;
 	int ret = -EBUSY;
-	enum nl80211_band band;
+	enum ieee80211_band band;
 
 	mutex_lock(&local->scan_mtx);
 
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ba9360a..6d86f0c 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -235,6 +235,8 @@
 	spin_lock_init(&sta->lock);
 	spin_lock_init(&sta->flaglock);
 	INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
+	INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
+	mutex_init(&sta->ampdu_mlme.mtx);
 
 	memcpy(sta->sta.addr, addr, ETH_ALEN);
 	sta->local = local;
@@ -246,14 +248,12 @@
 	}
 
 	for (i = 0; i < STA_TID_NUM; i++) {
-		/* timer_to_tid must be initialized with identity mapping to
-		 * enable session_timer's data differentiation. refer to
-		 * sta_rx_agg_session_timer_expired for useage */
+		/*
+		 * timer_to_tid must be initialized with identity mapping
+		 * to enable session_timer's data differentiation. See
+		 * sta_rx_agg_session_timer_expired for usage.
+		 */
 		sta->timer_to_tid[i] = i;
-		/* tx */
-		sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE;
-		sta->ampdu_mlme.tid_tx[i] = NULL;
-		sta->ampdu_mlme.addba_req_num[i] = 0;
 	}
 	skb_queue_head_init(&sta->ps_tx_buf);
 	skb_queue_head_init(&sta->tx_filtered);
@@ -647,15 +647,7 @@
 		return ret;
 
 	if (sta->key) {
-		ieee80211_key_free(sta->key);
-		/*
-		 * We have only unlinked the key, and actually destroying it
-		 * may mean it is removed from hardware which requires that
-		 * the key->sta pointer is still valid, so flush the key todo
-		 * list here.
-		 */
-		ieee80211_key_todo();
-
+		ieee80211_key_free(local, sta->key);
 		WARN_ON(sta->key);
 	}
 
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index df9d455..54262e7 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -42,9 +42,6 @@
  *	be in the queues
  * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping
  *	station in power-save mode, reply when the driver unblocks.
- * @WLAN_STA_DISASSOC: Disassociation in progress.
- *	This is used to reject TX BA session requests when disassociation
- *	is in progress.
  */
 enum ieee80211_sta_info_flags {
 	WLAN_STA_AUTH		= 1<<0,
@@ -60,38 +57,44 @@
 	WLAN_STA_BLOCK_BA	= 1<<11,
 	WLAN_STA_PS_DRIVER	= 1<<12,
 	WLAN_STA_PSPOLL		= 1<<13,
-	WLAN_STA_DISASSOC       = 1<<14,
 };
 
 #define STA_TID_NUM 16
 #define ADDBA_RESP_INTERVAL HZ
-#define HT_AGG_MAX_RETRIES		(0x3)
+#define HT_AGG_MAX_RETRIES		0x3
 
-#define HT_AGG_STATE_INITIATOR_SHIFT	(4)
-
-#define HT_ADDBA_REQUESTED_MSK		BIT(0)
-#define HT_ADDBA_DRV_READY_MSK		BIT(1)
-#define HT_ADDBA_RECEIVED_MSK		BIT(2)
-#define HT_AGG_STATE_REQ_STOP_BA_MSK	BIT(3)
-#define HT_AGG_STATE_INITIATOR_MSK      BIT(HT_AGG_STATE_INITIATOR_SHIFT)
-#define HT_AGG_STATE_IDLE		(0x0)
-#define HT_AGG_STATE_OPERATIONAL	(HT_ADDBA_REQUESTED_MSK |	\
-					 HT_ADDBA_DRV_READY_MSK |	\
-					 HT_ADDBA_RECEIVED_MSK)
+#define HT_AGG_STATE_DRV_READY		0
+#define HT_AGG_STATE_RESPONSE_RECEIVED	1
+#define HT_AGG_STATE_OPERATIONAL	2
+#define HT_AGG_STATE_STOPPING		3
+#define HT_AGG_STATE_WANT_START		4
+#define HT_AGG_STATE_WANT_STOP		5
 
 /**
  * struct tid_ampdu_tx - TID aggregation information (Tx).
  *
+ * @rcu_head: rcu head for freeing structure
  * @addba_resp_timer: timer for peer's response to addba request
  * @pending: pending frames queue -- use sta's spinlock to protect
- * @ssn: Starting Sequence Number expected to be aggregated.
  * @dialog_token: dialog token for aggregation session
+ * @state: session state (see above)
+ * @stop_initiator: initiator of a session stop
+ *
+ * This structure is protected by RCU and the per-station
+ * spinlock. Assignments to the array holding it must hold
+ * the spinlock, only the TX path can access it under RCU
+ * lock-free if, and only if, the state has  the flag
+ * %HT_AGG_STATE_OPERATIONAL set. Otherwise, the TX path
+ * must also acquire the spinlock and re-check the state,
+ * see comments in the tx code touching it.
  */
 struct tid_ampdu_tx {
+	struct rcu_head rcu_head;
 	struct timer_list addba_resp_timer;
 	struct sk_buff_head pending;
-	u16 ssn;
+	unsigned long state;
 	u8 dialog_token;
+	u8 stop_initiator;
 };
 
 /**
@@ -106,8 +109,18 @@
  * @buf_size: buffer size for incoming A-MPDUs
  * @timeout: reset timer value (in TUs).
  * @dialog_token: dialog token for aggregation session
+ * @rcu_head: RCU head used for freeing this struct
+ *
+ * This structure is protected by RCU and the per-station
+ * spinlock. Assignments to the array holding it must hold
+ * the spinlock, only the RX path can access it under RCU
+ * lock-free. The RX path, since it is single-threaded,
+ * can even modify the structure without locking since the
+ * only other modifications to it are done when the struct
+ * can not yet or no longer be found by the RX path.
  */
 struct tid_ampdu_rx {
+	struct rcu_head rcu_head;
 	struct sk_buff **reorder_buf;
 	unsigned long *reorder_time;
 	struct timer_list session_timer;
@@ -120,6 +133,32 @@
 };
 
 /**
+ * struct sta_ampdu_mlme - STA aggregation information.
+ *
+ * @tid_rx: aggregation info for Rx per TID -- RCU protected
+ * @tid_tx: aggregation info for Tx per TID
+ * @addba_req_num: number of times addBA request has been sent.
+ * @dialog_token_allocator: dialog token enumerator for each new session;
+ * @work: work struct for starting/stopping aggregation
+ * @tid_rx_timer_expired: bitmap indicating on which TIDs the
+ *	RX timer expired until the work for it runs
+ * @mtx: mutex to protect all TX data (except non-NULL assignments
+ *	to tid_tx[idx], which are protected by the sta spinlock)
+ */
+struct sta_ampdu_mlme {
+	struct mutex mtx;
+	/* rx */
+	struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
+	unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)];
+	/* tx */
+	struct work_struct work;
+	struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
+	u8 addba_req_num[STA_TID_NUM];
+	u8 dialog_token_allocator;
+};
+
+
+/**
  * enum plink_state - state of a mesh peer link finite state machine
  *
  * @PLINK_LISTEN: initial state, considered the implicit state of non existant
@@ -143,28 +182,6 @@
 };
 
 /**
- * struct sta_ampdu_mlme - STA aggregation information.
- *
- * @tid_active_rx: TID's state in Rx session state machine.
- * @tid_rx: aggregation info for Rx per TID
- * @tid_state_tx: TID's state in Tx session state machine.
- * @tid_tx: aggregation info for Tx per TID
- * @addba_req_num: number of times addBA request has been sent.
- * @dialog_token_allocator: dialog token enumerator for each new session;
- */
-struct sta_ampdu_mlme {
-	/* rx */
-	bool tid_active_rx[STA_TID_NUM];
-	struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
-	/* tx */
-	u8 tid_state_tx[STA_TID_NUM];
-	struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
-	u8 addba_req_num[STA_TID_NUM];
-	u8 dialog_token_allocator;
-};
-
-
-/**
  * struct sta_info - STA information
  *
  * This structure collects information about a station that
@@ -410,20 +427,20 @@
 {
 }
 
-#define for_each_sta_info(local, _addr, sta, nxt) 			\
+#define for_each_sta_info(local, _addr, _sta, nxt) 			\
 	for (	/* initialise loop */					\
-		sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
-		nxt = sta ? rcu_dereference(sta->hnext) : NULL;		\
+		_sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
+		nxt = _sta ? rcu_dereference(_sta->hnext) : NULL;	\
 		/* typecheck */						\
-		for_each_sta_info_type_check(local, (_addr), sta, nxt),	\
+		for_each_sta_info_type_check(local, (_addr), _sta, nxt),\
 		/* continue condition */				\
-		sta;							\
+		_sta;							\
 		/* advance loop */					\
-		sta = nxt,						\
-		nxt = sta ? rcu_dereference(sta->hnext) : NULL		\
+		_sta = nxt,						\
+		nxt = _sta ? rcu_dereference(_sta->hnext) : NULL	\
 	     )								\
 	/* compare address and run code only if it matches */		\
-	if (memcmp(sta->sta.addr, (_addr), ETH_ALEN) == 0)
+	if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0)
 
 /*
  * Get STA info by index, BROKEN!
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 94613af..10caec5 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -47,7 +47,7 @@
 	/*
 	 * This skb 'survived' a round-trip through the driver, and
 	 * hopefully the driver didn't mangle it too badly. However,
-	 * we can definitely not rely on the the control information
+	 * we can definitely not rely on the control information
 	 * being correct. Clear it so we don't get junk there, and
 	 * indicate that it needs new processing, but must not be
 	 * modified/encrypted again.
@@ -377,7 +377,7 @@
 				skb2 = skb_clone(skb, GFP_ATOMIC);
 				if (skb2) {
 					skb2->dev = prev_dev;
-					netif_rx(skb2);
+					netif_receive_skb(skb2);
 				}
 			}
 
@@ -386,7 +386,7 @@
 	}
 	if (prev_dev) {
 		skb->dev = prev_dev;
-		netif_rx(skb);
+		netif_receive_skb(skb);
 		skb = NULL;
 	}
 	rcu_read_unlock();
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 7ef491e..e840c9c 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -202,9 +202,9 @@
  * @payload_len is the length of payload (_not_ including IV/ICV length).
  * @ta is the transmitter addresses.
  */
-void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
-				 struct ieee80211_key *key,
-				 u8 *pos, size_t payload_len, u8 *ta)
+int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
+				struct ieee80211_key *key,
+				u8 *pos, size_t payload_len, u8 *ta)
 {
 	u8 rc4key[16];
 	struct tkip_ctx *ctx = &key->u.tkip.tx;
@@ -216,7 +216,7 @@
 
 	tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key);
 
-	ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
+	return ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
 }
 
 /* Decrypt packet payload with TKIP using @key. @pos is a pointer to the
diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h
index d471438..7e83dee 100644
--- a/net/mac80211/tkip.h
+++ b/net/mac80211/tkip.h
@@ -15,7 +15,7 @@
 
 u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16);
 
-void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
+int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
 				 struct ieee80211_key *key,
 				 u8 *pos, size_t payload_len, u8 *ta);
 enum {
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 680bcb7..c54db96 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -576,17 +576,6 @@
 }
 
 static ieee80211_tx_result debug_noinline
-ieee80211_tx_h_sta(struct ieee80211_tx_data *tx)
-{
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
-
-	if (tx->sta && tx->sta->uploaded)
-		info->control.sta = &tx->sta->sta;
-
-	return TX_CONTINUE;
-}
-
-static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
@@ -1092,6 +1081,59 @@
 	return true;
 }
 
+static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
+				  struct sk_buff *skb,
+				  struct ieee80211_tx_info *info,
+				  struct tid_ampdu_tx *tid_tx,
+				  int tid)
+{
+	bool queued = false;
+
+	if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
+		info->flags |= IEEE80211_TX_CTL_AMPDU;
+	} else if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
+		/*
+		 * nothing -- this aggregation session is being started
+		 * but that might still fail with the driver
+		 */
+	} else {
+		spin_lock(&tx->sta->lock);
+		/*
+		 * Need to re-check now, because we may get here
+		 *
+		 *  1) in the window during which the setup is actually
+		 *     already done, but not marked yet because not all
+		 *     packets are spliced over to the driver pending
+		 *     queue yet -- if this happened we acquire the lock
+		 *     either before or after the splice happens, but
+		 *     need to recheck which of these cases happened.
+		 *
+		 *  2) during session teardown, if the OPERATIONAL bit
+		 *     was cleared due to the teardown but the pointer
+		 *     hasn't been assigned NULL yet (or we loaded it
+		 *     before it was assigned) -- in this case it may
+		 *     now be NULL which means we should just let the
+		 *     packet pass through because splicing the frames
+		 *     back is already done.
+		 */
+		tid_tx = tx->sta->ampdu_mlme.tid_tx[tid];
+
+		if (!tid_tx) {
+			/* do nothing, let packet pass through */
+		} else if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
+			info->flags |= IEEE80211_TX_CTL_AMPDU;
+		} else {
+			queued = true;
+			info->control.vif = &tx->sdata->vif;
+			info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+			__skb_queue_tail(&tid_tx->pending, skb);
+		}
+		spin_unlock(&tx->sta->lock);
+	}
+
+	return queued;
+}
+
 /*
  * initialises @tx
  */
@@ -1104,8 +1146,7 @@
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	int hdrlen, tid;
-	u8 *qc, *state;
-	bool queued = false;
+	u8 *qc;
 
 	memset(tx, 0, sizeof(*tx));
 	tx->skb = skb;
@@ -1157,35 +1198,16 @@
 		qc = ieee80211_get_qos_ctl(hdr);
 		tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
 
-		spin_lock(&tx->sta->lock);
-		/*
-		 * XXX: This spinlock could be fairly expensive, but see the
-		 *	comment in agg-tx.c:ieee80211_agg_tx_operational().
-		 *	One way to solve this would be to do something RCU-like
-		 *	for managing the tid_tx struct and using atomic bitops
-		 *	for the actual state -- by introducing an actual
-		 *	'operational' bit that would be possible. It would
-		 *	require changing ieee80211_agg_tx_operational() to
-		 *	set that bit, and changing the way tid_tx is managed
-		 *	everywhere, including races between that bit and
-		 *	tid_tx going away (tid_tx being added can be easily
-		 *	committed to memory before the 'operational' bit).
-		 */
-		tid_tx = tx->sta->ampdu_mlme.tid_tx[tid];
-		state = &tx->sta->ampdu_mlme.tid_state_tx[tid];
-		if (*state == HT_AGG_STATE_OPERATIONAL) {
-			info->flags |= IEEE80211_TX_CTL_AMPDU;
-		} else if (*state != HT_AGG_STATE_IDLE) {
-			/* in progress */
-			queued = true;
-			info->control.vif = &sdata->vif;
-			info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
-			__skb_queue_tail(&tid_tx->pending, skb);
-		}
-		spin_unlock(&tx->sta->lock);
+		tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
+		if (tid_tx) {
+			bool queued;
 
-		if (unlikely(queued))
-			return TX_QUEUED;
+			queued = ieee80211_tx_prep_agg(tx, skb, info,
+						       tid_tx, tid);
+
+			if (unlikely(queued))
+				return TX_QUEUED;
+		}
 	}
 
 	if (is_multicast_ether_addr(hdr->addr1)) {
@@ -1274,6 +1296,11 @@
 			break;
 		}
 
+		if (sta && sta->uploaded)
+			info->control.sta = &sta->sta;
+		else
+			info->control.sta = NULL;
+
 		ret = drv_tx(local, skb);
 		if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) {
 			dev_kfree_skb(skb);
@@ -1313,7 +1340,6 @@
 	CALL_TXH(ieee80211_tx_h_check_assoc);
 	CALL_TXH(ieee80211_tx_h_ps_buf);
 	CALL_TXH(ieee80211_tx_h_select_key);
-	CALL_TXH(ieee80211_tx_h_sta);
 	if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
 		CALL_TXH(ieee80211_tx_h_rate_ctrl);
 
@@ -1909,11 +1935,13 @@
 		h_pos += encaps_len;
 	}
 
+#ifdef CONFIG_MAC80211_MESH
 	if (meshhdrlen > 0) {
 		memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
 		nh_pos += meshhdrlen;
 		h_pos += meshhdrlen;
 	}
+#endif
 
 	if (ieee80211_is_data_qos(fc)) {
 		__le16 *qos_control;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 5b79d55..748387d 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -803,8 +803,12 @@
 
 	/* after reinitialize QoS TX queues setting to default,
 	 * disable QoS at all */
-	local->hw.conf.flags &=	~IEEE80211_CONF_QOS;
-	drv_config(local, IEEE80211_CONF_CHANGE_QOS);
+
+	if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
+		sdata->vif.bss_conf.qos =
+			sdata->vif.type != NL80211_IFTYPE_STATION;
+		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
+	}
 }
 
 void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
@@ -1138,18 +1142,6 @@
 	}
 	mutex_unlock(&local->sta_mtx);
 
-	/* Clear Suspend state so that ADDBA requests can be processed */
-
-	rcu_read_lock();
-
-	if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
-		list_for_each_entry_rcu(sta, &local->sta_list, list) {
-			clear_sta_flags(sta, WLAN_STA_BLOCK_BA);
-		}
-	}
-
-	rcu_read_unlock();
-
 	/* setup RTS threshold */
 	drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
 
@@ -1173,7 +1165,8 @@
 			  BSS_CHANGED_BASIC_RATES |
 			  BSS_CHANGED_BEACON_INT |
 			  BSS_CHANGED_BSSID |
-			  BSS_CHANGED_CQM;
+			  BSS_CHANGED_CQM |
+			  BSS_CHANGED_QOS;
 
 		switch (sdata->vif.type) {
 		case NL80211_IFTYPE_STATION:
@@ -1202,13 +1195,26 @@
 		}
 	}
 
-	rcu_read_lock();
+	/*
+	 * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
+	 * sessions can be established after a resume.
+	 *
+	 * Also tear down aggregation sessions since reconfiguring
+	 * them in a hardware restart scenario is not easily done
+	 * right now, and the hardware will have lost information
+	 * about the sessions, but we and the AP still think they
+	 * are active. This is really a workaround though.
+	 */
 	if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
-		list_for_each_entry_rcu(sta, &local->sta_list, list) {
+		mutex_lock(&local->sta_mtx);
+
+		list_for_each_entry(sta, &local->sta_list, list) {
 			ieee80211_sta_tear_down_BA_sessions(sta);
+			clear_sta_flags(sta, WLAN_STA_BLOCK_BA);
 		}
+
+		mutex_unlock(&local->sta_mtx);
 	}
-	rcu_read_unlock();
 
 	/* add back keys */
 	list_for_each_entry(sdata, &local->interfaces, list)
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index 5f3a411..9ebc8d8 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -32,13 +32,16 @@
 
 	local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
 						CRYPTO_ALG_ASYNC);
-	if (IS_ERR(local->wep_tx_tfm))
+	if (IS_ERR(local->wep_tx_tfm)) {
+		local->wep_rx_tfm = ERR_PTR(-EINVAL);
 		return PTR_ERR(local->wep_tx_tfm);
+	}
 
 	local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
 						CRYPTO_ALG_ASYNC);
 	if (IS_ERR(local->wep_rx_tfm)) {
 		crypto_free_blkcipher(local->wep_tx_tfm);
+		local->wep_tx_tfm = ERR_PTR(-EINVAL);
 		return PTR_ERR(local->wep_rx_tfm);
 	}
 
@@ -47,8 +50,10 @@
 
 void ieee80211_wep_free(struct ieee80211_local *local)
 {
-	crypto_free_blkcipher(local->wep_tx_tfm);
-	crypto_free_blkcipher(local->wep_rx_tfm);
+	if (!IS_ERR(local->wep_tx_tfm))
+		crypto_free_blkcipher(local->wep_tx_tfm);
+	if (!IS_ERR(local->wep_rx_tfm))
+		crypto_free_blkcipher(local->wep_rx_tfm);
 }
 
 static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)
@@ -122,19 +127,24 @@
 /* Perform WEP encryption using given key. data buffer must have tailroom
  * for 4-byte ICV. data_len must not include this ICV. Note: this function
  * does _not_ add IV. data = RC4(data | CRC32(data)) */
-void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
-				size_t klen, u8 *data, size_t data_len)
+int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+			       size_t klen, u8 *data, size_t data_len)
 {
 	struct blkcipher_desc desc = { .tfm = tfm };
 	struct scatterlist sg;
 	__le32 icv;
 
+	if (IS_ERR(tfm))
+		return -1;
+
 	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);
 	crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
+
+	return 0;
 }
 
 
@@ -168,10 +178,8 @@
 	/* Add room for ICV */
 	skb_put(skb, WEP_ICV_LEN);
 
-	ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, keylen + 3,
-				   iv + WEP_IV_LEN, len);
-
-	return 0;
+	return ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, keylen + 3,
+					  iv + WEP_IV_LEN, len);
 }
 
 
@@ -185,6 +193,9 @@
 	struct scatterlist sg;
 	__le32 crc;
 
+	if (IS_ERR(tfm))
+		return -1;
+
 	crypto_blkcipher_setkey(tfm, rc4key, klen);
 	sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
 	crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h
index fe29d7e..58654ee 100644
--- a/net/mac80211/wep.h
+++ b/net/mac80211/wep.h
@@ -18,7 +18,7 @@
 
 int ieee80211_wep_init(struct ieee80211_local *local);
 void ieee80211_wep_free(struct ieee80211_local *local);
-void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
 				size_t klen, u8 *data, size_t data_len);
 int ieee80211_wep_encrypt(struct ieee80211_local *local,
 			  struct sk_buff *skb,
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index b025dc7..81d4ad6 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -560,6 +560,22 @@
 	return WORK_ACT_TIMEOUT;
 }
 
+static enum work_action __must_check
+ieee80211_assoc_beacon_wait(struct ieee80211_work *wk)
+{
+	if (wk->started)
+		return WORK_ACT_TIMEOUT;
+
+	/*
+	 * Wait up to one beacon interval ...
+	 * should this be more if we miss one?
+	 */
+	printk(KERN_DEBUG "%s: waiting for beacon from %pM\n",
+	       wk->sdata->name, wk->filter_ta);
+	wk->timeout = TU_TO_EXP_TIME(wk->assoc.bss->beacon_interval);
+	return WORK_ACT_NONE;
+}
+
 static void ieee80211_auth_challenge(struct ieee80211_work *wk,
 				     struct ieee80211_mgmt *mgmt,
 				     size_t len)
@@ -709,6 +725,25 @@
 	return WORK_ACT_DONE;
 }
 
+static enum work_action __must_check
+ieee80211_rx_mgmt_beacon(struct ieee80211_work *wk,
+			 struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct ieee80211_sub_if_data *sdata = wk->sdata;
+	struct ieee80211_local *local = sdata->local;
+
+	ASSERT_WORK_MTX(local);
+
+	if (wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
+		return WORK_ACT_MISMATCH;
+
+	if (len < 24 + 12)
+		return WORK_ACT_NONE;
+
+	printk(KERN_DEBUG "%s: beacon received\n", sdata->name);
+	return WORK_ACT_DONE;
+}
+
 static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
 					  struct sk_buff *skb)
 {
@@ -731,6 +766,7 @@
 		case IEEE80211_WORK_DIRECT_PROBE:
 		case IEEE80211_WORK_AUTH:
 		case IEEE80211_WORK_ASSOC:
+		case IEEE80211_WORK_ASSOC_BEACON_WAIT:
 			bssid = wk->filter_ta;
 			break;
 		default:
@@ -745,6 +781,9 @@
 			continue;
 
 		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_BEACON:
+			rma = ieee80211_rx_mgmt_beacon(wk, mgmt, skb->len);
+			break;
 		case IEEE80211_STYPE_PROBE_RESP:
 			rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len,
 							   rx_status);
@@ -840,7 +879,7 @@
 
 	/*
 	 * ieee80211_queue_work() should have picked up most cases,
-	 * here we'll pick the the rest.
+	 * here we'll pick the rest.
 	 */
 	if (WARN(local->suspended, "work scheduled while going to suspend\n"))
 		return;
@@ -916,6 +955,9 @@
 		case IEEE80211_WORK_REMAIN_ON_CHANNEL:
 			rma = ieee80211_remain_on_channel_timeout(wk);
 			break;
+		case IEEE80211_WORK_ASSOC_BEACON_WAIT:
+			rma = ieee80211_assoc_beacon_wait(wk);
+			break;
 		}
 
 		wk->started = started;
@@ -1065,6 +1107,7 @@
 		case IEEE80211_STYPE_PROBE_RESP:
 		case IEEE80211_STYPE_ASSOC_RESP:
 		case IEEE80211_STYPE_REASSOC_RESP:
+		case IEEE80211_STYPE_BEACON:
 			skb_queue_tail(&local->work_skb_queue, skb);
 			ieee80211_queue_work(&local->hw, &local->work_work);
 			return RX_QUEUED;
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 0adbcc9..8d59d27 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -183,9 +183,8 @@
 	skb_put(skb, TKIP_ICV_LEN);
 
 	hdr = (struct ieee80211_hdr *) skb->data;
-	ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm,
-				    key, pos, len, hdr->addr2);
-	return 0;
+	return ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm,
+					   key, pos, len, hdr->addr2);
 }
 
 
@@ -436,6 +435,7 @@
 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 	u8 pn[CCMP_PN_LEN];
 	int data_len;
+	int queue;
 
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
@@ -453,7 +453,10 @@
 
 	ccmp_hdr2pn(pn, skb->data + hdrlen);
 
-	if (memcmp(pn, key->u.ccmp.rx_pn[rx->queue], CCMP_PN_LEN) <= 0) {
+	queue = ieee80211_is_mgmt(hdr->frame_control) ?
+		NUM_RX_DATA_QUEUES : rx->queue;
+
+	if (memcmp(pn, key->u.ccmp.rx_pn[queue], CCMP_PN_LEN) <= 0) {
 		key->u.ccmp.replays++;
 		return RX_DROP_UNUSABLE;
 	}
@@ -470,7 +473,7 @@
 			return RX_DROP_UNUSABLE;
 	}
 
-	memcpy(key->u.ccmp.rx_pn[rx->queue], pn, CCMP_PN_LEN);
+	memcpy(key->u.ccmp.rx_pn[queue], pn, CCMP_PN_LEN);
 
 	/* Remove CCMP header and MIC */
 	skb_trim(skb, skb->len - CCMP_MIC_LEN);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 8593a77..4328825 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -40,27 +40,6 @@
 
 if NF_CONNTRACK
 
-config NF_CT_ACCT
-	bool "Connection tracking flow accounting"
-	depends on NETFILTER_ADVANCED
-	help
-	  If this option is enabled, the connection tracking code will
-	  keep per-flow packet and byte counters.
-
-	  Those counters can be used for flow-based accounting or the
-	  `connbytes' match.
-
-	  Please note that currently this option only sets a default state.
-	  You may change it at boot time with nf_conntrack.acct=0/1 kernel
-	  parameter or by loading the nf_conntrack module with acct=0/1.
-
-	  You may also disable/enable it on a running system with:
-	   sysctl net.netfilter.nf_conntrack_acct=0/1
-
-	  This option will be removed in 2.6.29.
-
-	  If unsure, say `N'.
-
 config NF_CONNTRACK_MARK
 	bool  'Connection mark tracking support'
 	depends on NETFILTER_ADVANCED
@@ -347,6 +326,22 @@
 
 comment "Xtables targets"
 
+config NETFILTER_XT_TARGET_CHECKSUM
+	tristate "CHECKSUM target support"
+	depends on IP_NF_MANGLE || IP6_NF_MANGLE
+	depends on NETFILTER_ADVANCED
+	---help---
+	  This option adds a `CHECKSUM' target, which can be used in the iptables mangle
+	  table.
+
+	  You can use this target to compute and fill in the checksum in
+	  a packet that lacks a checksum.  This is particularly useful,
+	  if you need to work around old applications such as dhcp clients,
+	  that do not work well with checksum offloads, but don't want to disable
+	  checksum offload in your device.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_TARGET_CLASSIFY
 	tristate '"CLASSIFY" target support'
 	depends on NETFILTER_ADVANCED
@@ -424,6 +419,18 @@
 	since you can easily create immortal packets that loop
 	forever on the network.
 
+config NETFILTER_XT_TARGET_IDLETIMER
+	tristate  "IDLETIMER target support"
+	depends on NETFILTER_ADVANCED
+	help
+
+	  This option adds the `IDLETIMER' target.  Each matching packet
+	  resets the timer associated with label specified when the rule is
+	  added.  When the timer expires, it triggers a sysfs notification.
+	  The remaining time for expiration can be read via sysfs.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_TARGET_LED
 	tristate '"LED" target support'
 	depends on LEDS_CLASS && LEDS_TRIGGERS
@@ -503,7 +510,7 @@
 	  To compile it as a module, choose M here.  If unsure, say N.
 
 config NETFILTER_XT_TARGET_TEE
-	tristate '"TEE" - packet cloning to alternate destiantion'
+	tristate '"TEE" - packet cloning to alternate destination'
 	depends on NETFILTER_ADVANCED
 	depends on (IPV6 || IPV6=n)
 	depends on !NF_CONNTRACK || NF_CONNTRACK
@@ -618,7 +625,6 @@
 	tristate  '"connbytes" per-connection counter match support'
 	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
-	select NF_CT_ACCT
 	help
 	  This option adds a `connbytes' match, which allows you to match the
 	  number of bytes and/or packets for each direction within a connection.
@@ -657,6 +663,15 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_MATCH_CPU
+	tristate '"cpu" match support'
+	depends on NETFILTER_ADVANCED
+	help
+	  CPU matching allows you to match packets based on the CPU
+	  currently handling the packet.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_MATCH_DCCP
 	tristate '"dccp" protocol match support'
 	depends on NETFILTER_ADVANCED
@@ -736,6 +751,16 @@
 
 	If unsure, say M.
 
+config NETFILTER_XT_MATCH_IPVS
+	tristate '"ipvs" match support'
+	depends on IP_VS
+	depends on NETFILTER_ADVANCED
+	depends on NF_CONNTRACK
+	help
+	  This option allows you to match against IPVS properties of a packet.
+
+	  If unsure, say N.
+
 config NETFILTER_XT_MATCH_LENGTH
 	tristate '"length" match support'
 	depends on NETFILTER_ADVANCED
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 14e3a8f..441050f 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -45,6 +45,7 @@
 obj-$(CONFIG_NETFILTER_XT_CONNMARK) += xt_connmark.o
 
 # targets
+obj-$(CONFIG_NETFILTER_XT_TARGET_CHECKSUM) += xt_CHECKSUM.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o
@@ -61,6 +62,7 @@
 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TEE) += xt_TEE.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_IDLETIMER) += xt_IDLETIMER.o
 
 # matches
 obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o
@@ -68,6 +70,7 @@
 obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CPU) += xt_cpu.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o
@@ -75,6 +78,7 @@
 obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig
index 712ccad..46a77d5 100644
--- a/net/netfilter/ipvs/Kconfig
+++ b/net/netfilter/ipvs/Kconfig
@@ -3,7 +3,7 @@
 #
 menuconfig IP_VS
 	tristate "IP virtual server support"
-	depends on NET && INET && NETFILTER
+	depends on NET && INET && NETFILTER && NF_CONNTRACK
 	---help---
 	  IP Virtual Server support will let you build a high-performance
 	  virtual server based on cluster of two or more real servers. This
@@ -26,7 +26,7 @@
 
 config	IP_VS_IPV6
 	bool "IPv6 support for IPVS"
-	depends on EXPERIMENTAL && (IPV6 = y || IP_VS = IPV6)
+	depends on IPV6 = y || IP_VS = IPV6
 	---help---
 	  Add IPv6 support to IPVS. This is incomplete and might be dangerous.
 
@@ -87,19 +87,16 @@
 	  protocol. Say Y if unsure.
 
 config	IP_VS_PROTO_AH_ESP
-	bool
-	depends on UNDEFINED
+	def_bool IP_VS_PROTO_ESP || IP_VS_PROTO_AH
 
 config	IP_VS_PROTO_ESP
 	bool "ESP load balancing support"
-	select IP_VS_PROTO_AH_ESP
 	---help---
 	  This option enables support for load balancing ESP (Encapsulation
 	  Security Payload) transport protocol. Say Y if unsure.
 
 config	IP_VS_PROTO_AH
 	bool "AH load balancing support"
-	select IP_VS_PROTO_AH_ESP
 	---help---
 	  This option enables support for load balancing AH (Authentication
 	  Header) transport protocol. Say Y if unsure.
@@ -238,7 +235,7 @@
 
 config	IP_VS_FTP
   	tristate "FTP protocol helper"
-        depends on IP_VS_PROTO_TCP
+        depends on IP_VS_PROTO_TCP && NF_NAT
 	---help---
 	  FTP is a protocol that transfers IP address and/or port number in
 	  the payload. In the virtual server via Network Address Translation,
diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c
index 1cb0e83..e76f87f 100644
--- a/net/netfilter/ipvs/ip_vs_app.c
+++ b/net/netfilter/ipvs/ip_vs_app.c
@@ -569,49 +569,6 @@
 };
 #endif
 
-
-/*
- *	Replace a segment of data with a new segment
- */
-int ip_vs_skb_replace(struct sk_buff *skb, gfp_t pri,
-		      char *o_buf, int o_len, char *n_buf, int n_len)
-{
-	int diff;
-	int o_offset;
-	int o_left;
-
-	EnterFunction(9);
-
-	diff = n_len - o_len;
-	o_offset = o_buf - (char *)skb->data;
-	/* The length of left data after o_buf+o_len in the skb data */
-	o_left = skb->len - (o_offset + o_len);
-
-	if (diff <= 0) {
-		memmove(o_buf + n_len, o_buf + o_len, o_left);
-		memcpy(o_buf, n_buf, n_len);
-		skb_trim(skb, skb->len + diff);
-	} else if (diff <= skb_tailroom(skb)) {
-		skb_put(skb, diff);
-		memmove(o_buf + n_len, o_buf + o_len, o_left);
-		memcpy(o_buf, n_buf, n_len);
-	} else {
-		if (pskb_expand_head(skb, skb_headroom(skb), diff, pri))
-			return -ENOMEM;
-		skb_put(skb, diff);
-		memmove(skb->data + o_offset + n_len,
-			skb->data + o_offset + o_len, o_left);
-		skb_copy_to_linear_data_offset(skb, o_offset, n_buf, n_len);
-	}
-
-	/* must update the iph total length here */
-	ip_hdr(skb)->tot_len = htons(skb->len);
-
-	LeaveFunction(9);
-	return 0;
-}
-
-
 int __init ip_vs_app_init(void)
 {
 	/* we will replace it with proc_net_ipvs_create() soon */
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index ff04e9e..b71c69a 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -158,6 +158,9 @@
 	unsigned hash;
 	int ret;
 
+	if (cp->flags & IP_VS_CONN_F_ONE_PACKET)
+		return 0;
+
 	/* Hash by protocol, client address and port */
 	hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
 
@@ -268,6 +271,29 @@
 	return cp;
 }
 
+struct ip_vs_conn *
+ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
+			struct ip_vs_protocol *pp,
+			const struct ip_vs_iphdr *iph,
+			unsigned int proto_off, int inverse)
+{
+	__be16 _ports[2], *pptr;
+
+	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+	if (pptr == NULL)
+		return NULL;
+
+	if (likely(!inverse))
+		return ip_vs_conn_in_get(af, iph->protocol,
+					 &iph->saddr, pptr[0],
+					 &iph->daddr, pptr[1]);
+	else
+		return ip_vs_conn_in_get(af, iph->protocol,
+					 &iph->daddr, pptr[1],
+					 &iph->saddr, pptr[0]);
+}
+EXPORT_SYMBOL_GPL(ip_vs_conn_in_get_proto);
+
 /* Get reference to connection template */
 struct ip_vs_conn *ip_vs_ct_in_get
 (int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
@@ -353,14 +379,37 @@
 	return ret;
 }
 
+struct ip_vs_conn *
+ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb,
+			 struct ip_vs_protocol *pp,
+			 const struct ip_vs_iphdr *iph,
+			 unsigned int proto_off, int inverse)
+{
+	__be16 _ports[2], *pptr;
+
+	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+	if (pptr == NULL)
+		return NULL;
+
+	if (likely(!inverse))
+		return ip_vs_conn_out_get(af, iph->protocol,
+					  &iph->saddr, pptr[0],
+					  &iph->daddr, pptr[1]);
+	else
+		return ip_vs_conn_out_get(af, iph->protocol,
+					  &iph->daddr, pptr[1],
+					  &iph->saddr, pptr[0]);
+}
+EXPORT_SYMBOL_GPL(ip_vs_conn_out_get_proto);
 
 /*
  *      Put back the conn and restart its timer with its timeout
  */
 void ip_vs_conn_put(struct ip_vs_conn *cp)
 {
-	/* reset it expire in its timeout */
-	mod_timer(&cp->timer, jiffies+cp->timeout);
+	unsigned long t = (cp->flags & IP_VS_CONN_F_ONE_PACKET) ?
+		0 : cp->timeout;
+	mod_timer(&cp->timer, jiffies+t);
 
 	__ip_vs_conn_put(cp);
 }
@@ -653,7 +702,7 @@
 	/*
 	 *	unhash it if it is hashed in the conn table
 	 */
-	if (!ip_vs_conn_unhash(cp))
+	if (!ip_vs_conn_unhash(cp) && !(cp->flags & IP_VS_CONN_F_ONE_PACKET))
 		goto expire_later;
 
 	/*
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 1cd6e3f..4f8ddba4 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -54,7 +54,6 @@
 
 EXPORT_SYMBOL(register_ip_vs_scheduler);
 EXPORT_SYMBOL(unregister_ip_vs_scheduler);
-EXPORT_SYMBOL(ip_vs_skb_replace);
 EXPORT_SYMBOL(ip_vs_proto_name);
 EXPORT_SYMBOL(ip_vs_conn_new);
 EXPORT_SYMBOL(ip_vs_conn_in_get);
@@ -194,6 +193,7 @@
 	struct ip_vs_dest *dest;
 	struct ip_vs_conn *ct;
 	__be16  dport;			/* destination port to forward */
+	__be16  flags;
 	union nf_inet_addr snet;	/* source network of the client,
 					   after masking */
 
@@ -340,6 +340,10 @@
 		dport = ports[1];
 	}
 
+	flags = (svc->flags & IP_VS_SVC_F_ONEPACKET
+		 && iph.protocol == IPPROTO_UDP)?
+		IP_VS_CONN_F_ONE_PACKET : 0;
+
 	/*
 	 *    Create a new connection according to the template
 	 */
@@ -347,7 +351,7 @@
 			    &iph.saddr, ports[0],
 			    &iph.daddr, ports[1],
 			    &dest->addr, dport,
-			    0,
+			    flags,
 			    dest);
 	if (cp == NULL) {
 		ip_vs_conn_put(ct);
@@ -377,7 +381,7 @@
 	struct ip_vs_conn *cp = NULL;
 	struct ip_vs_iphdr iph;
 	struct ip_vs_dest *dest;
-	__be16 _ports[2], *pptr;
+	__be16 _ports[2], *pptr, flags;
 
 	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
 	pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
@@ -407,6 +411,10 @@
 		return NULL;
 	}
 
+	flags = (svc->flags & IP_VS_SVC_F_ONEPACKET
+		 && iph.protocol == IPPROTO_UDP)?
+		IP_VS_CONN_F_ONE_PACKET : 0;
+
 	/*
 	 *    Create a connection entry.
 	 */
@@ -414,7 +422,7 @@
 			    &iph.saddr, pptr[0],
 			    &iph.daddr, pptr[1],
 			    &dest->addr, dest->port ? dest->port : pptr[1],
-			    0,
+			    flags,
 			    dest);
 	if (cp == NULL)
 		return NULL;
@@ -464,6 +472,9 @@
 	if (sysctl_ip_vs_cache_bypass && svc->fwmark && unicast) {
 		int ret, cs;
 		struct ip_vs_conn *cp;
+		__u16 flags = (svc->flags & IP_VS_SVC_F_ONEPACKET &&
+				iph.protocol == IPPROTO_UDP)?
+				IP_VS_CONN_F_ONE_PACKET : 0;
 		union nf_inet_addr daddr =  { .all = { 0, 0, 0, 0 } };
 
 		ip_vs_service_put(svc);
@@ -474,7 +485,7 @@
 				    &iph.saddr, pptr[0],
 				    &iph.daddr, pptr[1],
 				    &daddr, 0,
-				    IP_VS_CONN_F_BYPASS,
+				    IP_VS_CONN_F_BYPASS | flags,
 				    NULL);
 		if (cp == NULL)
 			return NF_DROP;
@@ -524,26 +535,6 @@
 	return NF_DROP;
 }
 
-
-/*
- *      It is hooked before NF_IP_PRI_NAT_SRC at the NF_INET_POST_ROUTING
- *      chain, and is used for VS/NAT.
- *      It detects packets for VS/NAT connections and sends the packets
- *      immediately. This can avoid that iptable_nat mangles the packets
- *      for VS/NAT.
- */
-static unsigned int ip_vs_post_routing(unsigned int hooknum,
-				       struct sk_buff *skb,
-				       const struct net_device *in,
-				       const struct net_device *out,
-				       int (*okfn)(struct sk_buff *))
-{
-	if (!skb->ipvs_property)
-		return NF_ACCEPT;
-	/* The packet was sent from IPVS, exit this chain */
-	return NF_STOP;
-}
-
 __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
 {
 	return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));
@@ -1487,14 +1478,6 @@
 		.hooknum        = NF_INET_FORWARD,
 		.priority       = 99,
 	},
-	/* Before the netfilter connection tracking, exit from POST_ROUTING */
-	{
-		.hook		= ip_vs_post_routing,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum        = NF_INET_POST_ROUTING,
-		.priority       = NF_IP_PRI_NAT_SRC-1,
-	},
 #ifdef CONFIG_IP_VS_IPV6
 	/* After packet filtering, forward packet through VS/DR, VS/TUN,
 	 * or VS/NAT(change destination), so that filtering rules can be
@@ -1523,14 +1506,6 @@
 		.hooknum        = NF_INET_FORWARD,
 		.priority       = 99,
 	},
-	/* Before the netfilter connection tracking, exit from POST_ROUTING */
-	{
-		.hook		= ip_vs_post_routing,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET6,
-		.hooknum        = NF_INET_POST_ROUTING,
-		.priority       = NF_IP6_PRI_NAT_SRC-1,
-	},
 #endif
 };
 
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 36dc1d8..0f0c079 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -1864,14 +1864,16 @@
 					   svc->scheduler->name);
 			else
 #endif
-				seq_printf(seq, "%s  %08X:%04X %s ",
+				seq_printf(seq, "%s  %08X:%04X %s %s ",
 					   ip_vs_proto_name(svc->protocol),
 					   ntohl(svc->addr.ip),
 					   ntohs(svc->port),
-					   svc->scheduler->name);
+					   svc->scheduler->name,
+					   (svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
 		} else {
-			seq_printf(seq, "FWM  %08X %s ",
-				   svc->fwmark, svc->scheduler->name);
+			seq_printf(seq, "FWM  %08X %s %s",
+				   svc->fwmark, svc->scheduler->name,
+				   (svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
 		}
 
 		if (svc->flags & IP_VS_SVC_F_PERSISTENT)
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c
index 2ae747a..f228a17 100644
--- a/net/netfilter/ipvs/ip_vs_ftp.c
+++ b/net/netfilter/ipvs/ip_vs_ftp.c
@@ -20,6 +20,17 @@
  *
  * Author:	Wouter Gadeyne
  *
+ *
+ * Code for ip_vs_expect_related and ip_vs_expect_callback is taken from
+ * http://www.ssi.bg/~ja/nfct/:
+ *
+ * ip_vs_nfct.c:	Netfilter connection tracking support for IPVS
+ *
+ * Portions Copyright (C) 2001-2002
+ * Antefacto Ltd, 181 Parnell St, Dublin 1, Ireland.
+ *
+ * Portions Copyright (C) 2003-2008
+ * Julian Anastasov
  */
 
 #define KMSG_COMPONENT "IPVS"
@@ -32,6 +43,9 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/netfilter.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_expect.h>
+#include <net/netfilter/nf_nat_helper.h>
 #include <linux/gfp.h>
 #include <net/protocol.h>
 #include <net/tcp.h>
@@ -43,6 +57,16 @@
 #define SERVER_STRING "227 Entering Passive Mode ("
 #define CLIENT_STRING "PORT "
 
+#define FMT_TUPLE	"%pI4:%u->%pI4:%u/%u"
+#define ARG_TUPLE(T)	&(T)->src.u3.ip, ntohs((T)->src.u.all), \
+			&(T)->dst.u3.ip, ntohs((T)->dst.u.all), \
+			(T)->dst.protonum
+
+#define FMT_CONN	"%pI4:%u->%pI4:%u->%pI4:%u/%u:%u"
+#define ARG_CONN(C)	&((C)->caddr.ip), ntohs((C)->cport), \
+			&((C)->vaddr.ip), ntohs((C)->vport), \
+			&((C)->daddr.ip), ntohs((C)->dport), \
+			(C)->protocol, (C)->state
 
 /*
  * List of ports (up to IP_VS_APP_MAX_PORTS) to be handled by helper
@@ -123,6 +147,119 @@
 	return 1;
 }
 
+/*
+ * Called from init_conntrack() as expectfn handler.
+ */
+static void
+ip_vs_expect_callback(struct nf_conn *ct,
+		      struct nf_conntrack_expect *exp)
+{
+	struct nf_conntrack_tuple *orig, new_reply;
+	struct ip_vs_conn *cp;
+
+	if (exp->tuple.src.l3num != PF_INET)
+		return;
+
+	/*
+	 * We assume that no NF locks are held before this callback.
+	 * ip_vs_conn_out_get and ip_vs_conn_in_get should match their
+	 * expectations even if they use wildcard values, now we provide the
+	 * actual values from the newly created original conntrack direction.
+	 * The conntrack is confirmed when packet reaches IPVS hooks.
+	 */
+
+	/* RS->CLIENT */
+	orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+	cp = ip_vs_conn_out_get(exp->tuple.src.l3num, orig->dst.protonum,
+				&orig->src.u3, orig->src.u.tcp.port,
+				&orig->dst.u3, orig->dst.u.tcp.port);
+	if (cp) {
+		/* Change reply CLIENT->RS to CLIENT->VS */
+		new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+		IP_VS_DBG(7, "%s(): ct=%p, status=0x%lX, tuples=" FMT_TUPLE ", "
+			  FMT_TUPLE ", found inout cp=" FMT_CONN "\n",
+			  __func__, ct, ct->status,
+			  ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+			  ARG_CONN(cp));
+		new_reply.dst.u3 = cp->vaddr;
+		new_reply.dst.u.tcp.port = cp->vport;
+		IP_VS_DBG(7, "%s(): ct=%p, new tuples=" FMT_TUPLE ", " FMT_TUPLE
+			  ", inout cp=" FMT_CONN "\n",
+			  __func__, ct,
+			  ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+			  ARG_CONN(cp));
+		goto alter;
+	}
+
+	/* CLIENT->VS */
+	cp = ip_vs_conn_in_get(exp->tuple.src.l3num, orig->dst.protonum,
+			       &orig->src.u3, orig->src.u.tcp.port,
+			       &orig->dst.u3, orig->dst.u.tcp.port);
+	if (cp) {
+		/* Change reply VS->CLIENT to RS->CLIENT */
+		new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+		IP_VS_DBG(7, "%s(): ct=%p, status=0x%lX, tuples=" FMT_TUPLE ", "
+			  FMT_TUPLE ", found outin cp=" FMT_CONN "\n",
+			  __func__, ct, ct->status,
+			  ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+			  ARG_CONN(cp));
+		new_reply.src.u3 = cp->daddr;
+		new_reply.src.u.tcp.port = cp->dport;
+		IP_VS_DBG(7, "%s(): ct=%p, new tuples=" FMT_TUPLE ", "
+			  FMT_TUPLE ", outin cp=" FMT_CONN "\n",
+			  __func__, ct,
+			  ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+			  ARG_CONN(cp));
+		goto alter;
+	}
+
+	IP_VS_DBG(7, "%s(): ct=%p, status=0x%lX, tuple=" FMT_TUPLE
+		  " - unknown expect\n",
+		  __func__, ct, ct->status, ARG_TUPLE(orig));
+	return;
+
+alter:
+	/* Never alter conntrack for non-NAT conns */
+	if (IP_VS_FWD_METHOD(cp) == IP_VS_CONN_F_MASQ)
+		nf_conntrack_alter_reply(ct, &new_reply);
+	ip_vs_conn_put(cp);
+	return;
+}
+
+/*
+ * Create NF conntrack expectation with wildcard (optional) source port.
+ * Then the default callback function will alter the reply and will confirm
+ * the conntrack entry when the first packet comes.
+ */
+static void
+ip_vs_expect_related(struct sk_buff *skb, struct nf_conn *ct,
+		     struct ip_vs_conn *cp, u_int8_t proto,
+		     const __be16 *port, int from_rs)
+{
+	struct nf_conntrack_expect *exp;
+
+	BUG_ON(!ct || ct == &nf_conntrack_untracked);
+
+	exp = nf_ct_expect_alloc(ct);
+	if (!exp)
+		return;
+
+	if (from_rs)
+		nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+				  nf_ct_l3num(ct), &cp->daddr, &cp->caddr,
+				  proto, port, &cp->cport);
+	else
+		nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+				  nf_ct_l3num(ct), &cp->caddr, &cp->vaddr,
+				  proto, port, &cp->vport);
+
+	exp->expectfn = ip_vs_expect_callback;
+
+	IP_VS_DBG(7, "%s(): ct=%p, expect tuple=" FMT_TUPLE "\n",
+		  __func__, ct, ARG_TUPLE(&exp->tuple));
+	nf_ct_expect_related(exp);
+	nf_ct_expect_put(exp);
+}
 
 /*
  * Look at outgoing ftp packets to catch the response to a PASV command
@@ -149,7 +286,9 @@
 	struct ip_vs_conn *n_cp;
 	char buf[24];		/* xxx.xxx.xxx.xxx,ppp,ppp\000 */
 	unsigned buf_len;
-	int ret;
+	int ret = 0;
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct;
 
 #ifdef CONFIG_IP_VS_IPV6
 	/* This application helper doesn't work with IPv6 yet,
@@ -219,20 +358,27 @@
 
 		buf_len = strlen(buf);
 
-		/*
-		 * Calculate required delta-offset to keep TCP happy
-		 */
-		*diff = buf_len - (end-start);
-
-		if (*diff == 0) {
-			/* simply replace it with new passive address */
-			memcpy(start, buf, buf_len);
-			ret = 1;
-		} else {
-			ret = !ip_vs_skb_replace(skb, GFP_ATOMIC, start,
-					  end-start, buf, buf_len);
+		ct = nf_ct_get(skb, &ctinfo);
+		if (ct && !nf_ct_is_untracked(ct)) {
+			/* If mangling fails this function will return 0
+			 * which will cause the packet to be dropped.
+			 * Mangling can only fail under memory pressure,
+			 * hopefully it will succeed on the retransmitted
+			 * packet.
+			 */
+			ret = nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
+						       start-data, end-start,
+						       buf, buf_len);
+			if (ret)
+				ip_vs_expect_related(skb, ct, n_cp,
+						     IPPROTO_TCP, NULL, 0);
 		}
 
+		/*
+		 * Not setting 'diff' is intentional, otherwise the sequence
+		 * would be adjusted twice.
+		 */
+
 		cp->app_data = NULL;
 		ip_vs_tcp_conn_listen(n_cp);
 		ip_vs_conn_put(n_cp);
@@ -263,6 +409,7 @@
 	union nf_inet_addr to;
 	__be16 port;
 	struct ip_vs_conn *n_cp;
+	struct nf_conn *ct;
 
 #ifdef CONFIG_IP_VS_IPV6
 	/* This application helper doesn't work with IPv6 yet,
@@ -349,6 +496,11 @@
 		ip_vs_control_add(n_cp, cp);
 	}
 
+	ct = (struct nf_conn *)skb->nfct;
+	if (ct && ct != &nf_conntrack_untracked)
+		ip_vs_expect_related(skb, ct, n_cp,
+				     IPPROTO_TCP, &n_cp->dport, 1);
+
 	/*
 	 *	Move tunnel to listen state
 	 */
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
index 2d3d5e4..027f654 100644
--- a/net/netfilter/ipvs/ip_vs_proto.c
+++ b/net/netfilter/ipvs/ip_vs_proto.c
@@ -98,6 +98,7 @@
 
 	return NULL;
 }
+EXPORT_SYMBOL(ip_vs_proto_get);
 
 
 /*
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
index c9a3f7a..4c0855c 100644
--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
@@ -8,55 +8,6 @@
 #include <net/sctp/checksum.h>
 #include <net/ip_vs.h>
 
-
-static struct ip_vs_conn *
-sctp_conn_in_get(int af,
-		 const struct sk_buff *skb,
-		 struct ip_vs_protocol *pp,
-		 const struct ip_vs_iphdr *iph,
-		 unsigned int proto_off,
-		 int inverse)
-{
-	__be16 _ports[2], *pptr;
-
-	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
-	if (pptr == NULL)
-		return NULL;
-
-	if (likely(!inverse)) 
-		return ip_vs_conn_in_get(af, iph->protocol,
-					 &iph->saddr, pptr[0],
-					 &iph->daddr, pptr[1]);
-	else 
-		return ip_vs_conn_in_get(af, iph->protocol,
-					 &iph->daddr, pptr[1],
-					 &iph->saddr, pptr[0]);
-}
-
-static struct ip_vs_conn *
-sctp_conn_out_get(int af,
-		  const struct sk_buff *skb,
-		  struct ip_vs_protocol *pp,
-		  const struct ip_vs_iphdr *iph,
-		  unsigned int proto_off,
-		  int inverse)
-{
-	__be16 _ports[2], *pptr;
-
-	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
-	if (pptr == NULL)
-		return NULL;
-
-	if (likely(!inverse)) 
-		return ip_vs_conn_out_get(af, iph->protocol,
-					  &iph->saddr, pptr[0],
-					  &iph->daddr, pptr[1]);
-	else 
-		return ip_vs_conn_out_get(af, iph->protocol,
-					  &iph->daddr, pptr[1],
-					  &iph->saddr, pptr[0]);
-}
-
 static int
 sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 		   int *verdict, struct ip_vs_conn **cpp)
@@ -173,7 +124,7 @@
 			return 0;
 
 		/* Call application helper if needed */
-		if (!ip_vs_app_pkt_out(cp, skb))
+		if (!ip_vs_app_pkt_in(cp, skb))
 			return 0;
 	}
 
@@ -1169,8 +1120,8 @@
 	.register_app = sctp_register_app,
 	.unregister_app = sctp_unregister_app,
 	.conn_schedule = sctp_conn_schedule,
-	.conn_in_get = sctp_conn_in_get,
-	.conn_out_get = sctp_conn_out_get,
+	.conn_in_get = ip_vs_conn_in_get_proto,
+	.conn_out_get = ip_vs_conn_out_get_proto,
 	.snat_handler = sctp_snat_handler,
 	.dnat_handler = sctp_dnat_handler,
 	.csum_check = sctp_csum_check,
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
index 91d28e0..282d24d 100644
--- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
@@ -27,52 +27,6 @@
 
 #include <net/ip_vs.h>
 
-
-static struct ip_vs_conn *
-tcp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		const struct ip_vs_iphdr *iph, unsigned int proto_off,
-		int inverse)
-{
-	__be16 _ports[2], *pptr;
-
-	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
-	if (pptr == NULL)
-		return NULL;
-
-	if (likely(!inverse)) {
-		return ip_vs_conn_in_get(af, iph->protocol,
-					 &iph->saddr, pptr[0],
-					 &iph->daddr, pptr[1]);
-	} else {
-		return ip_vs_conn_in_get(af, iph->protocol,
-					 &iph->daddr, pptr[1],
-					 &iph->saddr, pptr[0]);
-	}
-}
-
-static struct ip_vs_conn *
-tcp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		 const struct ip_vs_iphdr *iph, unsigned int proto_off,
-		 int inverse)
-{
-	__be16 _ports[2], *pptr;
-
-	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
-	if (pptr == NULL)
-		return NULL;
-
-	if (likely(!inverse)) {
-		return ip_vs_conn_out_get(af, iph->protocol,
-					  &iph->saddr, pptr[0],
-					  &iph->daddr, pptr[1]);
-	} else {
-		return ip_vs_conn_out_get(af, iph->protocol,
-					  &iph->daddr, pptr[1],
-					  &iph->saddr, pptr[0]);
-	}
-}
-
-
 static int
 tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 		  int *verdict, struct ip_vs_conn **cpp)
@@ -721,8 +675,8 @@
 	.register_app =		tcp_register_app,
 	.unregister_app =	tcp_unregister_app,
 	.conn_schedule =	tcp_conn_schedule,
-	.conn_in_get =		tcp_conn_in_get,
-	.conn_out_get =		tcp_conn_out_get,
+	.conn_in_get =		ip_vs_conn_in_get_proto,
+	.conn_out_get =		ip_vs_conn_out_get_proto,
 	.snat_handler =		tcp_snat_handler,
 	.dnat_handler =		tcp_dnat_handler,
 	.csum_check =		tcp_csum_check,
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
index e7a6885..8553231 100644
--- a/net/netfilter/ipvs/ip_vs_proto_udp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
@@ -27,58 +27,6 @@
 #include <net/ip.h>
 #include <net/ip6_checksum.h>
 
-static struct ip_vs_conn *
-udp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		const struct ip_vs_iphdr *iph, unsigned int proto_off,
-		int inverse)
-{
-	struct ip_vs_conn *cp;
-	__be16 _ports[2], *pptr;
-
-	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
-	if (pptr == NULL)
-		return NULL;
-
-	if (likely(!inverse)) {
-		cp = ip_vs_conn_in_get(af, iph->protocol,
-				       &iph->saddr, pptr[0],
-				       &iph->daddr, pptr[1]);
-	} else {
-		cp = ip_vs_conn_in_get(af, iph->protocol,
-				       &iph->daddr, pptr[1],
-				       &iph->saddr, pptr[0]);
-	}
-
-	return cp;
-}
-
-
-static struct ip_vs_conn *
-udp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
-		 const struct ip_vs_iphdr *iph, unsigned int proto_off,
-		 int inverse)
-{
-	struct ip_vs_conn *cp;
-	__be16 _ports[2], *pptr;
-
-	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
-	if (pptr == NULL)
-		return NULL;
-
-	if (likely(!inverse)) {
-		cp = ip_vs_conn_out_get(af, iph->protocol,
-					&iph->saddr, pptr[0],
-					&iph->daddr, pptr[1]);
-	} else {
-		cp = ip_vs_conn_out_get(af, iph->protocol,
-					&iph->daddr, pptr[1],
-					&iph->saddr, pptr[0]);
-	}
-
-	return cp;
-}
-
-
 static int
 udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 		  int *verdict, struct ip_vs_conn **cpp)
@@ -520,8 +468,8 @@
 	.init =			udp_init,
 	.exit =			udp_exit,
 	.conn_schedule =	udp_conn_schedule,
-	.conn_in_get =		udp_conn_in_get,
-	.conn_out_get =		udp_conn_out_get,
+	.conn_in_get =		ip_vs_conn_in_get_proto,
+	.conn_out_get =		ip_vs_conn_out_get_proto,
 	.snat_handler =		udp_snat_handler,
 	.dnat_handler =		udp_dnat_handler,
 	.csum_check =		udp_csum_check,
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 93c15a1..21e1a5e 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -28,6 +28,7 @@
 #include <net/ip6_route.h>
 #include <linux/icmpv6.h>
 #include <linux/netfilter.h>
+#include <net/netfilter/nf_conntrack.h>
 #include <linux/netfilter_ipv4.h>
 
 #include <net/ip_vs.h>
@@ -90,10 +91,10 @@
 					     &dest->addr.ip);
 				return NULL;
 			}
-			__ip_vs_dst_set(dest, rtos, dst_clone(&rt->u.dst));
+			__ip_vs_dst_set(dest, rtos, dst_clone(&rt->dst));
 			IP_VS_DBG(10, "new dst %pI4, refcnt=%d, rtos=%X\n",
 				  &dest->addr.ip,
-				  atomic_read(&rt->u.dst.__refcnt), rtos);
+				  atomic_read(&rt->dst.__refcnt), rtos);
 		}
 		spin_unlock(&dest->dst_lock);
 	} else {
@@ -148,10 +149,10 @@
 					     &dest->addr.in6);
 				return NULL;
 			}
-			__ip_vs_dst_set(dest, 0, dst_clone(&rt->u.dst));
+			__ip_vs_dst_set(dest, 0, dst_clone(&rt->dst));
 			IP_VS_DBG(10, "new dst %pI6, refcnt=%d\n",
 				  &dest->addr.in6,
-				  atomic_read(&rt->u.dst.__refcnt));
+				  atomic_read(&rt->dst.__refcnt));
 		}
 		spin_unlock(&dest->dst_lock);
 	} else {
@@ -198,7 +199,7 @@
 	(skb)->ipvs_property = 1;			\
 	skb_forward_csum(skb);				\
 	NF_HOOK(pf, NF_INET_LOCAL_OUT, (skb), NULL,	\
-		(rt)->u.dst.dev, dst_output);		\
+		(rt)->dst.dev, dst_output);		\
 } while (0)
 
 
@@ -245,7 +246,7 @@
 	}
 
 	/* MTU checking */
-	mtu = dst_mtu(&rt->u.dst);
+	mtu = dst_mtu(&rt->dst);
 	if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
 		ip_rt_put(rt);
 		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
@@ -265,7 +266,7 @@
 
 	/* drop old route */
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->local_df = 1;
@@ -309,9 +310,9 @@
 	}
 
 	/* MTU checking */
-	mtu = dst_mtu(&rt->u.dst);
+	mtu = dst_mtu(&rt->dst);
 	if (skb->len > mtu) {
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
 		IP_VS_DBG_RL("%s(): frag needed\n", __func__);
 		goto tx_error;
@@ -323,13 +324,13 @@
 	 */
 	skb = skb_share_check(skb, GFP_ATOMIC);
 	if (unlikely(skb == NULL)) {
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 		return NF_STOLEN;
 	}
 
 	/* drop old route */
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->local_df = 1;
@@ -348,6 +349,30 @@
 }
 #endif
 
+static void
+ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp)
+{
+	struct nf_conn *ct = (struct nf_conn *)skb->nfct;
+	struct nf_conntrack_tuple new_tuple;
+
+	if (ct == NULL || nf_ct_is_untracked(ct) || nf_ct_is_confirmed(ct))
+		return;
+
+	/*
+	 * The connection is not yet in the hashtable, so we update it.
+	 * CIP->VIP will remain the same, so leave the tuple in
+	 * IP_CT_DIR_ORIGINAL untouched.  When the reply comes back from the
+	 * real-server we will see RIP->DIP.
+	 */
+	new_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+	new_tuple.src.u3 = cp->daddr;
+	/*
+	 * This will also take care of UDP and other protocols.
+	 */
+	new_tuple.src.u.tcp.port = cp->dport;
+	nf_conntrack_alter_reply(ct, &new_tuple);
+}
+
 /*
  *      NAT transmitter (only for outside-to-inside nat forwarding)
  *      Not used for related ICMP
@@ -376,7 +401,7 @@
 		goto tx_error_icmp;
 
 	/* MTU checking */
-	mtu = dst_mtu(&rt->u.dst);
+	mtu = dst_mtu(&rt->dst);
 	if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
 		ip_rt_put(rt);
 		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
@@ -388,12 +413,12 @@
 	if (!skb_make_writable(skb, sizeof(struct iphdr)))
 		goto tx_error_put;
 
-	if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+	if (skb_cow(skb, rt->dst.dev->hard_header_len))
 		goto tx_error_put;
 
 	/* drop old route */
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	/* mangle the packet */
 	if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
@@ -403,6 +428,8 @@
 
 	IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
 
+	ip_vs_update_conntrack(skb, cp);
+
 	/* FIXME: when application helper enlarges the packet and the length
 	   is larger than the MTU of outgoing device, there will be still
 	   MTU problem. */
@@ -452,9 +479,9 @@
 		goto tx_error_icmp;
 
 	/* MTU checking */
-	mtu = dst_mtu(&rt->u.dst);
+	mtu = dst_mtu(&rt->dst);
 	if (skb->len > mtu) {
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
 		IP_VS_DBG_RL_PKT(0, pp, skb, 0,
 				 "ip_vs_nat_xmit_v6(): frag needed for");
@@ -465,12 +492,12 @@
 	if (!skb_make_writable(skb, sizeof(struct ipv6hdr)))
 		goto tx_error_put;
 
-	if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+	if (skb_cow(skb, rt->dst.dev->hard_header_len))
 		goto tx_error_put;
 
 	/* drop old route */
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	/* mangle the packet */
 	if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
@@ -479,6 +506,8 @@
 
 	IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
 
+	ip_vs_update_conntrack(skb, cp);
+
 	/* FIXME: when application helper enlarges the packet and the length
 	   is larger than the MTU of outgoing device, there will be still
 	   MTU problem. */
@@ -498,7 +527,7 @@
 	kfree_skb(skb);
 	return NF_STOLEN;
 tx_error_put:
-	dst_release(&rt->u.dst);
+	dst_release(&rt->dst);
 	goto tx_error;
 }
 #endif
@@ -549,9 +578,9 @@
 	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(tos))))
 		goto tx_error_icmp;
 
-	tdev = rt->u.dst.dev;
+	tdev = rt->dst.dev;
 
-	mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
+	mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
 	if (mtu < 68) {
 		ip_rt_put(rt);
 		IP_VS_DBG_RL("%s(): mtu less than 68\n", __func__);
@@ -601,7 +630,7 @@
 
 	/* drop old route */
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	/*
 	 *	Push down and install the IPIP header.
@@ -615,7 +644,7 @@
 	iph->daddr		=	rt->rt_dst;
 	iph->saddr		=	rt->rt_src;
 	iph->ttl		=	old_iph->ttl;
-	ip_select_ident(iph, &rt->u.dst, NULL);
+	ip_select_ident(iph, &rt->dst, NULL);
 
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->local_df = 1;
@@ -660,12 +689,12 @@
 	if (!rt)
 		goto tx_error_icmp;
 
-	tdev = rt->u.dst.dev;
+	tdev = rt->dst.dev;
 
-	mtu = dst_mtu(&rt->u.dst) - sizeof(struct ipv6hdr);
+	mtu = dst_mtu(&rt->dst) - sizeof(struct ipv6hdr);
 	/* TODO IPv6: do we need this check in IPv6? */
 	if (mtu < 1280) {
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 		IP_VS_DBG_RL("%s(): mtu less than 1280\n", __func__);
 		goto tx_error;
 	}
@@ -674,7 +703,7 @@
 
 	if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) {
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 		IP_VS_DBG_RL("%s(): frag needed\n", __func__);
 		goto tx_error;
 	}
@@ -689,7 +718,7 @@
 		struct sk_buff *new_skb =
 			skb_realloc_headroom(skb, max_headroom);
 		if (!new_skb) {
-			dst_release(&rt->u.dst);
+			dst_release(&rt->dst);
 			kfree_skb(skb);
 			IP_VS_ERR_RL("%s(): no memory\n", __func__);
 			return NF_STOLEN;
@@ -707,7 +736,7 @@
 
 	/* drop old route */
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	/*
 	 *	Push down and install the IPIP header.
@@ -760,7 +789,7 @@
 		goto tx_error_icmp;
 
 	/* MTU checking */
-	mtu = dst_mtu(&rt->u.dst);
+	mtu = dst_mtu(&rt->dst);
 	if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu) {
 		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
 		ip_rt_put(rt);
@@ -780,7 +809,7 @@
 
 	/* drop old route */
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->local_df = 1;
@@ -813,10 +842,10 @@
 		goto tx_error_icmp;
 
 	/* MTU checking */
-	mtu = dst_mtu(&rt->u.dst);
+	mtu = dst_mtu(&rt->dst);
 	if (skb->len > mtu) {
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 		IP_VS_DBG_RL("%s(): frag needed\n", __func__);
 		goto tx_error;
 	}
@@ -827,13 +856,13 @@
 	 */
 	skb = skb_share_check(skb, GFP_ATOMIC);
 	if (unlikely(skb == NULL)) {
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 		return NF_STOLEN;
 	}
 
 	/* drop old route */
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->local_df = 1;
@@ -888,7 +917,7 @@
 		goto tx_error_icmp;
 
 	/* MTU checking */
-	mtu = dst_mtu(&rt->u.dst);
+	mtu = dst_mtu(&rt->dst);
 	if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF))) {
 		ip_rt_put(rt);
 		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
@@ -900,12 +929,12 @@
 	if (!skb_make_writable(skb, offset))
 		goto tx_error_put;
 
-	if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+	if (skb_cow(skb, rt->dst.dev->hard_header_len))
 		goto tx_error_put;
 
 	/* drop the old route when skb is not shared */
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	ip_vs_nat_icmp(skb, pp, cp, 0);
 
@@ -963,9 +992,9 @@
 		goto tx_error_icmp;
 
 	/* MTU checking */
-	mtu = dst_mtu(&rt->u.dst);
+	mtu = dst_mtu(&rt->dst);
 	if (skb->len > mtu) {
-		dst_release(&rt->u.dst);
+		dst_release(&rt->dst);
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
 		IP_VS_DBG_RL("%s(): frag needed\n", __func__);
 		goto tx_error;
@@ -975,12 +1004,12 @@
 	if (!skb_make_writable(skb, offset))
 		goto tx_error_put;
 
-	if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+	if (skb_cow(skb, rt->dst.dev->hard_header_len))
 		goto tx_error_put;
 
 	/* drop the old route when skb is not shared */
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
+	skb_dst_set(skb, &rt->dst);
 
 	ip_vs_nat_icmp_v6(skb, pp, cp, 0);
 
@@ -1001,7 +1030,7 @@
 	LeaveFunction(10);
 	return rc;
 tx_error_put:
-	dst_release(&rt->u.dst);
+	dst_release(&rt->dst);
 	goto tx_error;
 }
 #endif
diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c
index ab81b38..5178c69 100644
--- a/net/netfilter/nf_conntrack_acct.c
+++ b/net/netfilter/nf_conntrack_acct.c
@@ -17,13 +17,7 @@
 #include <net/netfilter/nf_conntrack_extend.h>
 #include <net/netfilter/nf_conntrack_acct.h>
 
-#ifdef CONFIG_NF_CT_ACCT
-#define NF_CT_ACCT_DEFAULT 1
-#else
-#define NF_CT_ACCT_DEFAULT 0
-#endif
-
-static int nf_ct_acct __read_mostly = NF_CT_ACCT_DEFAULT;
+static int nf_ct_acct __read_mostly;
 
 module_param_named(acct, nf_ct_acct, bool, 0644);
 MODULE_PARM_DESC(acct, "Enable connection tracking flow accounting.");
@@ -114,12 +108,6 @@
 	net->ct.sysctl_acct = nf_ct_acct;
 
 	if (net_eq(net, &init_net)) {
-#ifdef CONFIG_NF_CT_ACCT
-	printk(KERN_WARNING "CONFIG_NF_CT_ACCT is deprecated and will be removed soon. Please use\n");
-		printk(KERN_WARNING "nf_conntrack.acct=1 kernel parameter, acct=1 nf_conntrack module option or\n");
-		printk(KERN_WARNING "sysctl net.netfilter.nf_conntrack_acct=1 to enable it.\n");
-#endif
-
 		ret = nf_ct_extend_register(&acct_extend);
 		if (ret < 0) {
 			printk(KERN_ERR "nf_conntrack_acct: Unable to register extension\n");
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index eeeb8bc..df3eedb 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -62,8 +62,8 @@
 unsigned int nf_conntrack_max __read_mostly;
 EXPORT_SYMBOL_GPL(nf_conntrack_max);
 
-struct nf_conn nf_conntrack_untracked __read_mostly;
-EXPORT_SYMBOL_GPL(nf_conntrack_untracked);
+DEFINE_PER_CPU(struct nf_conn, nf_conntrack_untracked);
+EXPORT_PER_CPU_SYMBOL(nf_conntrack_untracked);
 
 static int nf_conntrack_hash_rnd_initted;
 static unsigned int nf_conntrack_hash_rnd;
@@ -619,9 +619,7 @@
 	ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev = NULL;
 	/* Don't set timer yet: wait for confirmation */
 	setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct);
-#ifdef CONFIG_NET_NS
-	ct->ct_net = net;
-#endif
+	write_pnet(&ct->ct_net, net);
 #ifdef CONFIG_NF_CONNTRACK_ZONES
 	if (zone) {
 		struct nf_conntrack_zone *nf_ct_zone;
@@ -968,8 +966,7 @@
 		if (acct) {
 			spin_lock_bh(&ct->lock);
 			acct[CTINFO2DIR(ctinfo)].packets++;
-			acct[CTINFO2DIR(ctinfo)].bytes +=
-				skb->len - skb_network_offset(skb);
+			acct[CTINFO2DIR(ctinfo)].bytes += skb->len;
 			spin_unlock_bh(&ct->lock);
 		}
 	}
@@ -1183,10 +1180,21 @@
 	spin_unlock_bh(&nf_conntrack_lock);
 }
 
+static int untrack_refs(void)
+{
+	int cnt = 0, cpu;
+
+	for_each_possible_cpu(cpu) {
+		struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu);
+
+		cnt += atomic_read(&ct->ct_general.use) - 1;
+	}
+	return cnt;
+}
+
 static void nf_conntrack_cleanup_init_net(void)
 {
-	/* wait until all references to nf_conntrack_untracked are dropped */
-	while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1)
+	while (untrack_refs() > 0)
 		schedule();
 
 	nf_conntrack_helper_fini();
@@ -1321,10 +1329,19 @@
 module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
 		  &nf_conntrack_htable_size, 0600);
 
+void nf_ct_untracked_status_or(unsigned long bits)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu)
+		per_cpu(nf_conntrack_untracked, cpu).status |= bits;
+}
+EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or);
+
 static int nf_conntrack_init_init_net(void)
 {
 	int max_factor = 8;
-	int ret;
+	int ret, cpu;
 
 	/* Idea from tcp.c: use 1/16384 of memory.  On i386: 32MB
 	 * machine has 512 buckets. >= 1GB machines have 16384 buckets. */
@@ -1363,13 +1380,13 @@
 		goto err_extend;
 #endif
 	/* Set up fake conntrack: to never be deleted, not in any hashes */
-#ifdef CONFIG_NET_NS
-	nf_conntrack_untracked.ct_net = &init_net;
-#endif
-	atomic_set(&nf_conntrack_untracked.ct_general.use, 1);
+	for_each_possible_cpu(cpu) {
+		struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu);
+		write_pnet(&ct->ct_net, &init_net);
+		atomic_set(&ct->ct_general.use, 1);
+	}
 	/*  - and look it like as a confirmed connection */
-	set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status);
-
+	nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED);
 	return 0;
 
 #ifdef CONFIG_NF_CONNTRACK_ZONES
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
index fdc8fb4..7dcf7a4 100644
--- a/net/netfilter/nf_conntrack_extend.c
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -23,9 +23,10 @@
 {
 	unsigned int i;
 	struct nf_ct_ext_type *t;
+	struct nf_ct_ext *ext = ct->ext;
 
 	for (i = 0; i < NF_CT_EXT_NUM; i++) {
-		if (!nf_ct_ext_exist(ct, i))
+		if (!__nf_ct_ext_exist(ext, i))
 			continue;
 
 		rcu_read_lock();
@@ -73,44 +74,45 @@
 
 void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
 {
-	struct nf_ct_ext *new;
+	struct nf_ct_ext *old, *new;
 	int i, newlen, newoff;
 	struct nf_ct_ext_type *t;
 
 	/* Conntrack must not be confirmed to avoid races on reallocation. */
 	NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
 
-	if (!ct->ext)
+	old = ct->ext;
+	if (!old)
 		return nf_ct_ext_create(&ct->ext, id, gfp);
 
-	if (nf_ct_ext_exist(ct, id))
+	if (__nf_ct_ext_exist(old, id))
 		return NULL;
 
 	rcu_read_lock();
 	t = rcu_dereference(nf_ct_ext_types[id]);
 	BUG_ON(t == NULL);
 
-	newoff = ALIGN(ct->ext->len, t->align);
+	newoff = ALIGN(old->len, t->align);
 	newlen = newoff + t->len;
 	rcu_read_unlock();
 
-	new = __krealloc(ct->ext, newlen, gfp);
+	new = __krealloc(old, newlen, gfp);
 	if (!new)
 		return NULL;
 
-	if (new != ct->ext) {
+	if (new != old) {
 		for (i = 0; i < NF_CT_EXT_NUM; i++) {
-			if (!nf_ct_ext_exist(ct, i))
+			if (!__nf_ct_ext_exist(old, i))
 				continue;
 
 			rcu_read_lock();
 			t = rcu_dereference(nf_ct_ext_types[i]);
 			if (t && t->move)
 				t->move((void *)new + new->offset[i],
-					(void *)ct->ext + ct->ext->offset[i]);
+					(void *)old + old->offset[i]);
 			rcu_read_unlock();
 		}
-		call_rcu(&ct->ext->rcu, __nf_ct_ext_free_rcu);
+		call_rcu(&old->rcu, __nf_ct_ext_free_rcu);
 		ct->ext = new;
 	}
 
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 6eaee7c..b969025 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -734,11 +734,11 @@
 		if (!afinfo->route((struct dst_entry **)&rt1, &fl1)) {
 			if (!afinfo->route((struct dst_entry **)&rt2, &fl2)) {
 				if (rt1->rt_gateway == rt2->rt_gateway &&
-				    rt1->u.dst.dev  == rt2->u.dst.dev)
+				    rt1->dst.dev  == rt2->dst.dev)
 					ret = 1;
-				dst_release(&rt2->u.dst);
+				dst_release(&rt2->dst);
 			}
-			dst_release(&rt1->u.dst);
+			dst_release(&rt1->dst);
 		}
 		break;
 	}
@@ -753,11 +753,11 @@
 			if (!afinfo->route((struct dst_entry **)&rt2, &fl2)) {
 				if (!memcmp(&rt1->rt6i_gateway, &rt2->rt6i_gateway,
 					    sizeof(rt1->rt6i_gateway)) &&
-				    rt1->u.dst.dev == rt2->u.dst.dev)
+				    rt1->dst.dev == rt2->dst.dev)
 					ret = 1;
-				dst_release(&rt2->u.dst);
+				dst_release(&rt2->dst);
 			}
-			dst_release(&rt1->u.dst);
+			dst_release(&rt1->dst);
 		}
 		break;
 	}
diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c
index 497b222..aadde01 100644
--- a/net/netfilter/nf_conntrack_netbios_ns.c
+++ b/net/netfilter/nf_conntrack_netbios_ns.c
@@ -61,7 +61,7 @@
 		goto out;
 
 	rcu_read_lock();
-	in_dev = __in_dev_get_rcu(rt->u.dst.dev);
+	in_dev = __in_dev_get_rcu(rt->dst.dev);
 	if (in_dev != NULL) {
 		for_primary_ifa(in_dev) {
 			if (ifa->ifa_broadcast == iph->daddr) {
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index c42ff6a..5bae1cd 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -480,7 +480,7 @@
 	int err;
 
 	/* ignore our fake conntrack entry */
-	if (ct == &nf_conntrack_untracked)
+	if (nf_ct_is_untracked(ct))
 		return 0;
 
 	if (events & (1 << IPCT_DESTROY)) {
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 9dd8cd4..c4c885d 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -585,8 +585,16 @@
 			 * Let's try to use the data from the packet.
 			 */
 			sender->td_end = end;
+			win <<= sender->td_scale;
 			sender->td_maxwin = (win == 0 ? 1 : win);
 			sender->td_maxend = end + sender->td_maxwin;
+			/*
+			 * We haven't seen traffic in the other direction yet
+			 * but we have to tweak window tracking to pass III
+			 * and IV until that happens.
+			 */
+			if (receiver->td_maxwin == 0)
+				receiver->td_end = receiver->td_maxend = sack;
 		}
 	} else if (((state->state == TCP_CONNTRACK_SYN_SENT
 		     && dir == IP_CT_DIR_ORIGINAL)
@@ -680,7 +688,7 @@
 		/*
 		 * Update receiver data.
 		 */
-		if (after(end, sender->td_maxend))
+		if (receiver->td_maxwin != 0 && after(end, sender->td_maxend))
 			receiver->td_maxwin += end - sender->td_maxend;
 		if (after(sack + win, receiver->td_maxend - 1)) {
 			receiver->td_maxend = sack + win;
@@ -736,27 +744,19 @@
 	return res;
 }
 
-#define	TH_FIN	0x01
-#define	TH_SYN	0x02
-#define	TH_RST	0x04
-#define	TH_PUSH	0x08
-#define	TH_ACK	0x10
-#define	TH_URG	0x20
-#define	TH_ECE	0x40
-#define	TH_CWR	0x80
-
 /* table of valid flag combinations - PUSH, ECE and CWR are always valid */
-static const u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG) + 1] =
+static const u8 tcp_valid_flags[(TCPHDR_FIN|TCPHDR_SYN|TCPHDR_RST|TCPHDR_ACK|
+				 TCPHDR_URG) + 1] =
 {
-	[TH_SYN]			= 1,
-	[TH_SYN|TH_URG]			= 1,
-	[TH_SYN|TH_ACK]			= 1,
-	[TH_RST]			= 1,
-	[TH_RST|TH_ACK]			= 1,
-	[TH_FIN|TH_ACK]			= 1,
-	[TH_FIN|TH_ACK|TH_URG]		= 1,
-	[TH_ACK]			= 1,
-	[TH_ACK|TH_URG]			= 1,
+	[TCPHDR_SYN]				= 1,
+	[TCPHDR_SYN|TCPHDR_URG]			= 1,
+	[TCPHDR_SYN|TCPHDR_ACK]			= 1,
+	[TCPHDR_RST]				= 1,
+	[TCPHDR_RST|TCPHDR_ACK]			= 1,
+	[TCPHDR_FIN|TCPHDR_ACK]			= 1,
+	[TCPHDR_FIN|TCPHDR_ACK|TCPHDR_URG]	= 1,
+	[TCPHDR_ACK]				= 1,
+	[TCPHDR_ACK|TCPHDR_URG]			= 1,
 };
 
 /* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c.  */
@@ -803,7 +803,7 @@
 	}
 
 	/* Check TCP flags. */
-	tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR|TH_PUSH));
+	tcpflags = (tcp_flag_byte(th) & ~(TCPHDR_ECE|TCPHDR_CWR|TCPHDR_PSH));
 	if (!tcp_valid_flags[tcpflags]) {
 		if (LOG_INVALID(net, IPPROTO_TCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index fc9a211..6a1572b 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -66,9 +66,10 @@
 	u_int16_t group_num;		/* number of this queue */
 	u_int16_t flags;
 	u_int8_t copy_mode;
+	struct rcu_head rcu;
 };
 
-static DEFINE_RWLOCK(instances_lock);
+static DEFINE_SPINLOCK(instances_lock);
 static atomic_t global_seq;
 
 #define INSTANCE_BUCKETS	16
@@ -88,7 +89,7 @@
 	struct nfulnl_instance *inst;
 
 	head = &instance_table[instance_hashfn(group_num)];
-	hlist_for_each_entry(inst, pos, head, hlist) {
+	hlist_for_each_entry_rcu(inst, pos, head, hlist) {
 		if (inst->group_num == group_num)
 			return inst;
 	}
@@ -106,22 +107,26 @@
 {
 	struct nfulnl_instance *inst;
 
-	read_lock_bh(&instances_lock);
+	rcu_read_lock_bh();
 	inst = __instance_lookup(group_num);
-	if (inst)
-		instance_get(inst);
-	read_unlock_bh(&instances_lock);
+	if (inst && !atomic_inc_not_zero(&inst->use))
+		inst = NULL;
+	rcu_read_unlock_bh();
 
 	return inst;
 }
 
+static void nfulnl_instance_free_rcu(struct rcu_head *head)
+{
+	kfree(container_of(head, struct nfulnl_instance, rcu));
+	module_put(THIS_MODULE);
+}
+
 static void
 instance_put(struct nfulnl_instance *inst)
 {
-	if (inst && atomic_dec_and_test(&inst->use)) {
-		kfree(inst);
-		module_put(THIS_MODULE);
-	}
+	if (inst && atomic_dec_and_test(&inst->use))
+		call_rcu_bh(&inst->rcu, nfulnl_instance_free_rcu);
 }
 
 static void nfulnl_timer(unsigned long data);
@@ -132,7 +137,7 @@
 	struct nfulnl_instance *inst;
 	int err;
 
-	write_lock_bh(&instances_lock);
+	spin_lock_bh(&instances_lock);
 	if (__instance_lookup(group_num)) {
 		err = -EEXIST;
 		goto out_unlock;
@@ -166,32 +171,37 @@
 	inst->copy_mode 	= NFULNL_COPY_PACKET;
 	inst->copy_range 	= NFULNL_COPY_RANGE_MAX;
 
-	hlist_add_head(&inst->hlist,
+	hlist_add_head_rcu(&inst->hlist,
 		       &instance_table[instance_hashfn(group_num)]);
 
-	write_unlock_bh(&instances_lock);
+	spin_unlock_bh(&instances_lock);
 
 	return inst;
 
 out_unlock:
-	write_unlock_bh(&instances_lock);
+	spin_unlock_bh(&instances_lock);
 	return ERR_PTR(err);
 }
 
 static void __nfulnl_flush(struct nfulnl_instance *inst);
 
+/* called with BH disabled */
 static void
 __instance_destroy(struct nfulnl_instance *inst)
 {
 	/* first pull it out of the global list */
-	hlist_del(&inst->hlist);
+	hlist_del_rcu(&inst->hlist);
 
 	/* then flush all pending packets from skb */
 
-	spin_lock_bh(&inst->lock);
+	spin_lock(&inst->lock);
+
+	/* lockless readers wont be able to use us */
+	inst->copy_mode = NFULNL_COPY_DISABLED;
+
 	if (inst->skb)
 		__nfulnl_flush(inst);
-	spin_unlock_bh(&inst->lock);
+	spin_unlock(&inst->lock);
 
 	/* and finally put the refcount */
 	instance_put(inst);
@@ -200,9 +210,9 @@
 static inline void
 instance_destroy(struct nfulnl_instance *inst)
 {
-	write_lock_bh(&instances_lock);
+	spin_lock_bh(&instances_lock);
 	__instance_destroy(inst);
-	write_unlock_bh(&instances_lock);
+	spin_unlock_bh(&instances_lock);
 }
 
 static int
@@ -403,8 +413,9 @@
 			NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSINDEV,
 				     htonl(indev->ifindex));
 			/* this is the bridge group "brX" */
+			/* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
 			NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV,
-				     htonl(indev->br_port->br->dev->ifindex));
+				     htonl(br_port_get_rcu(indev)->br->dev->ifindex));
 		} else {
 			/* Case 2: indev is bridge group, we need to look for
 			 * physical device (when called from ipv4) */
@@ -430,8 +441,9 @@
 			NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
 				     htonl(outdev->ifindex));
 			/* this is the bridge group "brX" */
+			/* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
 			NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV,
-				     htonl(outdev->br_port->br->dev->ifindex));
+				     htonl(br_port_get_rcu(outdev)->br->dev->ifindex));
 		} else {
 			/* Case 2: indev is a bridge group, we need to look
 			 * for physical device (when called from ipv4) */
@@ -619,6 +631,7 @@
 		size += nla_total_size(data_len);
 		break;
 
+	case NFULNL_COPY_DISABLED:
 	default:
 		goto unlock_and_release;
 	}
@@ -672,7 +685,7 @@
 		int i;
 
 		/* destroy all instances for this pid */
-		write_lock_bh(&instances_lock);
+		spin_lock_bh(&instances_lock);
 		for  (i = 0; i < INSTANCE_BUCKETS; i++) {
 			struct hlist_node *tmp, *t2;
 			struct nfulnl_instance *inst;
@@ -684,7 +697,7 @@
 					__instance_destroy(inst);
 			}
 		}
-		write_unlock_bh(&instances_lock);
+		spin_unlock_bh(&instances_lock);
 	}
 	return NOTIFY_DONE;
 }
@@ -861,19 +874,19 @@
 
 	for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
 		if (!hlist_empty(&instance_table[st->bucket]))
-			return instance_table[st->bucket].first;
+			return rcu_dereference_bh(instance_table[st->bucket].first);
 	}
 	return NULL;
 }
 
 static struct hlist_node *get_next(struct iter_state *st, struct hlist_node *h)
 {
-	h = h->next;
+	h = rcu_dereference_bh(h->next);
 	while (!h) {
 		if (++st->bucket >= INSTANCE_BUCKETS)
 			return NULL;
 
-		h = instance_table[st->bucket].first;
+		h = rcu_dereference_bh(instance_table[st->bucket].first);
 	}
 	return h;
 }
@@ -890,9 +903,9 @@
 }
 
 static void *seq_start(struct seq_file *seq, loff_t *pos)
-	__acquires(instances_lock)
+	__acquires(rcu_bh)
 {
-	read_lock_bh(&instances_lock);
+	rcu_read_lock_bh();
 	return get_idx(seq->private, *pos);
 }
 
@@ -903,9 +916,9 @@
 }
 
 static void seq_stop(struct seq_file *s, void *v)
-	__releases(instances_lock)
+	__releases(rcu_bh)
 {
-	read_unlock_bh(&instances_lock);
+	rcu_read_unlock_bh();
 }
 
 static int seq_show(struct seq_file *s, void *v)
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 12e1ab3..68e67d1 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -46,17 +46,19 @@
 	int peer_pid;
 	unsigned int queue_maxlen;
 	unsigned int copy_range;
-	unsigned int queue_total;
 	unsigned int queue_dropped;
 	unsigned int queue_user_dropped;
 
-	unsigned int id_sequence;		/* 'sequence' of pkt ids */
 
 	u_int16_t queue_num;			/* number of this queue */
 	u_int8_t copy_mode;
-
-	spinlock_t lock;
-
+/*
+ * Following fields are dirtied for each queued packet,
+ * keep them in same cache line if possible.
+ */
+	spinlock_t	lock;
+	unsigned int	queue_total;
+	atomic_t	id_sequence;		/* 'sequence' of pkt ids */
 	struct list_head queue_list;		/* packets in queue */
 };
 
@@ -238,32 +240,24 @@
 
 	outdev = entry->outdev;
 
-	spin_lock_bh(&queue->lock);
-
-	switch ((enum nfqnl_config_mode)queue->copy_mode) {
+	switch ((enum nfqnl_config_mode)ACCESS_ONCE(queue->copy_mode)) {
 	case NFQNL_COPY_META:
 	case NFQNL_COPY_NONE:
 		break;
 
 	case NFQNL_COPY_PACKET:
 		if (entskb->ip_summed == CHECKSUM_PARTIAL &&
-		    skb_checksum_help(entskb)) {
-			spin_unlock_bh(&queue->lock);
+		    skb_checksum_help(entskb))
 			return NULL;
-		}
-		if (queue->copy_range == 0
-		    || queue->copy_range > entskb->len)
+
+		data_len = ACCESS_ONCE(queue->copy_range);
+		if (data_len == 0 || data_len > entskb->len)
 			data_len = entskb->len;
-		else
-			data_len = queue->copy_range;
 
 		size += nla_total_size(data_len);
 		break;
 	}
 
-	entry->id = queue->id_sequence++;
-
-	spin_unlock_bh(&queue->lock);
 
 	skb = alloc_skb(size, GFP_ATOMIC);
 	if (!skb)
@@ -278,6 +272,7 @@
 	nfmsg->version = NFNETLINK_V0;
 	nfmsg->res_id = htons(queue->queue_num);
 
+	entry->id = atomic_inc_return(&queue->id_sequence);
 	pmsg.packet_id 		= htonl(entry->id);
 	pmsg.hw_protocol	= entskb->protocol;
 	pmsg.hook		= entry->hook;
@@ -296,8 +291,9 @@
 			NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSINDEV,
 				     htonl(indev->ifindex));
 			/* this is the bridge group "brX" */
+			/* rcu_read_lock()ed by __nf_queue */
 			NLA_PUT_BE32(skb, NFQA_IFINDEX_INDEV,
-				     htonl(indev->br_port->br->dev->ifindex));
+				     htonl(br_port_get_rcu(indev)->br->dev->ifindex));
 		} else {
 			/* Case 2: indev is bridge group, we need to look for
 			 * physical device (when called from ipv4) */
@@ -321,8 +317,9 @@
 			NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSOUTDEV,
 				     htonl(outdev->ifindex));
 			/* this is the bridge group "brX" */
+			/* rcu_read_lock()ed by __nf_queue */
 			NLA_PUT_BE32(skb, NFQA_IFINDEX_OUTDEV,
-				     htonl(outdev->br_port->br->dev->ifindex));
+				     htonl(br_port_get_rcu(outdev)->br->dev->ifindex));
 		} else {
 			/* Case 2: outdev is bridge group, we need to look for
 			 * physical output device (when called from ipv4) */
@@ -866,7 +863,7 @@
 			  inst->peer_pid, inst->queue_total,
 			  inst->copy_mode, inst->copy_range,
 			  inst->queue_dropped, inst->queue_user_dropped,
-			  inst->id_sequence, 1);
+			  atomic_read(&inst->id_sequence), 1);
 }
 
 static const struct seq_operations nfqnl_seq_ops = {
diff --git a/net/netfilter/xt_CHECKSUM.c b/net/netfilter/xt_CHECKSUM.c
new file mode 100644
index 0000000..0f642ef
--- /dev/null
+++ b/net/netfilter/xt_CHECKSUM.c
@@ -0,0 +1,70 @@
+/* iptables module for the packet checksum mangling
+ *
+ * (C) 2002 by Harald Welte <laforge@netfilter.org>
+ * (C) 2010 Red Hat, Inc.
+ *
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_CHECKSUM.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael S. Tsirkin <mst@redhat.com>");
+MODULE_DESCRIPTION("Xtables: checksum modification");
+MODULE_ALIAS("ipt_CHECKSUM");
+MODULE_ALIAS("ip6t_CHECKSUM");
+
+static unsigned int
+checksum_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+	if (skb->ip_summed == CHECKSUM_PARTIAL)
+		skb_checksum_help(skb);
+
+	return XT_CONTINUE;
+}
+
+static int checksum_tg_check(const struct xt_tgchk_param *par)
+{
+	const struct xt_CHECKSUM_info *einfo = par->targinfo;
+
+	if (einfo->operation & ~XT_CHECKSUM_OP_FILL) {
+		pr_info("unsupported CHECKSUM operation %x\n", einfo->operation);
+		return -EINVAL;
+	}
+	if (!einfo->operation) {
+		pr_info("no CHECKSUM operation enabled\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static struct xt_target checksum_tg_reg __read_mostly = {
+	.name		= "CHECKSUM",
+	.family		= NFPROTO_UNSPEC,
+	.target		= checksum_tg,
+	.targetsize	= sizeof(struct xt_CHECKSUM_info),
+	.table		= "mangle",
+	.checkentry	= checksum_tg_check,
+	.me		= THIS_MODULE,
+};
+
+static int __init checksum_tg_init(void)
+{
+	return xt_register_target(&checksum_tg_reg);
+}
+
+static void __exit checksum_tg_exit(void)
+{
+	xt_unregister_target(&checksum_tg_reg);
+}
+
+module_init(checksum_tg_init);
+module_exit(checksum_tg_exit);
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index 562bf32..0cb6053 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -67,7 +67,7 @@
 		return -EINVAL;
 
 	if (info->flags & XT_CT_NOTRACK) {
-		ct = &nf_conntrack_untracked;
+		ct = nf_ct_untracked_get();
 		atomic_inc(&ct->ct_general.use);
 		goto out;
 	}
@@ -132,7 +132,7 @@
 	struct nf_conn *ct = info->ct;
 	struct nf_conn_help *help;
 
-	if (ct != &nf_conntrack_untracked) {
+	if (!nf_ct_is_untracked(ct)) {
 		help = nfct_help(ct);
 		if (help)
 			module_put(help->helper->me);
diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c
new file mode 100644
index 0000000..be1f22e
--- /dev/null
+++ b/net/netfilter/xt_IDLETIMER.c
@@ -0,0 +1,315 @@
+/*
+ * linux/net/netfilter/xt_IDLETIMER.c
+ *
+ * Netfilter module to trigger a timer when packet matches.
+ * After timer expires a kevent will be sent.
+ *
+ * Copyright (C) 2004, 2010 Nokia Corporation
+ * Written by Timo Teras <ext-timo.teras@nokia.com>
+ *
+ * Converted to x_tables and reworked for upstream inclusion
+ * by Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_IDLETIMER.h>
+#include <linux/kdev_t.h>
+#include <linux/kobject.h>
+#include <linux/workqueue.h>
+#include <linux/sysfs.h>
+
+struct idletimer_tg_attr {
+	struct attribute attr;
+	ssize_t	(*show)(struct kobject *kobj,
+			struct attribute *attr, char *buf);
+};
+
+struct idletimer_tg {
+	struct list_head entry;
+	struct timer_list timer;
+	struct work_struct work;
+
+	struct kobject *kobj;
+	struct idletimer_tg_attr attr;
+
+	unsigned int refcnt;
+};
+
+static LIST_HEAD(idletimer_tg_list);
+static DEFINE_MUTEX(list_mutex);
+
+static struct kobject *idletimer_tg_kobj;
+
+static
+struct idletimer_tg *__idletimer_tg_find_by_label(const char *label)
+{
+	struct idletimer_tg *entry;
+
+	BUG_ON(!label);
+
+	list_for_each_entry(entry, &idletimer_tg_list, entry) {
+		if (!strcmp(label, entry->attr.attr.name))
+			return entry;
+	}
+
+	return NULL;
+}
+
+static ssize_t idletimer_tg_show(struct kobject *kobj, struct attribute *attr,
+				 char *buf)
+{
+	struct idletimer_tg *timer;
+	unsigned long expires = 0;
+
+	mutex_lock(&list_mutex);
+
+	timer =	__idletimer_tg_find_by_label(attr->name);
+	if (timer)
+		expires = timer->timer.expires;
+
+	mutex_unlock(&list_mutex);
+
+	if (time_after(expires, jiffies))
+		return sprintf(buf, "%u\n",
+			       jiffies_to_msecs(expires - jiffies) / 1000);
+
+	return sprintf(buf, "0\n");
+}
+
+static void idletimer_tg_work(struct work_struct *work)
+{
+	struct idletimer_tg *timer = container_of(work, struct idletimer_tg,
+						  work);
+
+	sysfs_notify(idletimer_tg_kobj, NULL, timer->attr.attr.name);
+}
+
+static void idletimer_tg_expired(unsigned long data)
+{
+	struct idletimer_tg *timer = (struct idletimer_tg *) data;
+
+	pr_debug("timer %s expired\n", timer->attr.attr.name);
+
+	schedule_work(&timer->work);
+}
+
+static int idletimer_tg_create(struct idletimer_tg_info *info)
+{
+	int ret;
+
+	info->timer = kmalloc(sizeof(*info->timer), GFP_KERNEL);
+	if (!info->timer) {
+		pr_debug("couldn't alloc timer\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	info->timer->attr.attr.name = kstrdup(info->label, GFP_KERNEL);
+	if (!info->timer->attr.attr.name) {
+		pr_debug("couldn't alloc attribute name\n");
+		ret = -ENOMEM;
+		goto out_free_timer;
+	}
+	info->timer->attr.attr.mode = S_IRUGO;
+	info->timer->attr.show = idletimer_tg_show;
+
+	ret = sysfs_create_file(idletimer_tg_kobj, &info->timer->attr.attr);
+	if (ret < 0) {
+		pr_debug("couldn't add file to sysfs");
+		goto out_free_attr;
+	}
+
+	list_add(&info->timer->entry, &idletimer_tg_list);
+
+	setup_timer(&info->timer->timer, idletimer_tg_expired,
+		    (unsigned long) info->timer);
+	info->timer->refcnt = 1;
+
+	mod_timer(&info->timer->timer,
+		  msecs_to_jiffies(info->timeout * 1000) + jiffies);
+
+	INIT_WORK(&info->timer->work, idletimer_tg_work);
+
+	return 0;
+
+out_free_attr:
+	kfree(info->timer->attr.attr.name);
+out_free_timer:
+	kfree(info->timer);
+out:
+	return ret;
+}
+
+/*
+ * The actual xt_tables plugin.
+ */
+static unsigned int idletimer_tg_target(struct sk_buff *skb,
+					 const struct xt_action_param *par)
+{
+	const struct idletimer_tg_info *info = par->targinfo;
+
+	pr_debug("resetting timer %s, timeout period %u\n",
+		 info->label, info->timeout);
+
+	BUG_ON(!info->timer);
+
+	mod_timer(&info->timer->timer,
+		  msecs_to_jiffies(info->timeout * 1000) + jiffies);
+
+	return XT_CONTINUE;
+}
+
+static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
+{
+	struct idletimer_tg_info *info = par->targinfo;
+	int ret;
+
+	pr_debug("checkentry targinfo%s\n", info->label);
+
+	if (info->timeout == 0) {
+		pr_debug("timeout value is zero\n");
+		return -EINVAL;
+	}
+
+	if (info->label[0] == '\0' ||
+	    strnlen(info->label,
+		    MAX_IDLETIMER_LABEL_SIZE) == MAX_IDLETIMER_LABEL_SIZE) {
+		pr_debug("label is empty or not nul-terminated\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&list_mutex);
+
+	info->timer = __idletimer_tg_find_by_label(info->label);
+	if (info->timer) {
+		info->timer->refcnt++;
+		mod_timer(&info->timer->timer,
+			  msecs_to_jiffies(info->timeout * 1000) + jiffies);
+
+		pr_debug("increased refcnt of timer %s to %u\n",
+			 info->label, info->timer->refcnt);
+	} else {
+		ret = idletimer_tg_create(info);
+		if (ret < 0) {
+			pr_debug("failed to create timer\n");
+			mutex_unlock(&list_mutex);
+			return ret;
+		}
+	}
+
+	mutex_unlock(&list_mutex);
+	return 0;
+}
+
+static void idletimer_tg_destroy(const struct xt_tgdtor_param *par)
+{
+	const struct idletimer_tg_info *info = par->targinfo;
+
+	pr_debug("destroy targinfo %s\n", info->label);
+
+	mutex_lock(&list_mutex);
+
+	if (--info->timer->refcnt == 0) {
+		pr_debug("deleting timer %s\n", info->label);
+
+		list_del(&info->timer->entry);
+		del_timer_sync(&info->timer->timer);
+		sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
+		kfree(info->timer->attr.attr.name);
+		kfree(info->timer);
+	} else {
+		pr_debug("decreased refcnt of timer %s to %u\n",
+			 info->label, info->timer->refcnt);
+	}
+
+	mutex_unlock(&list_mutex);
+}
+
+static struct xt_target idletimer_tg __read_mostly = {
+	.name		= "IDLETIMER",
+	.family		= NFPROTO_UNSPEC,
+	.target		= idletimer_tg_target,
+	.targetsize     = sizeof(struct idletimer_tg_info),
+	.checkentry	= idletimer_tg_checkentry,
+	.destroy        = idletimer_tg_destroy,
+	.me		= THIS_MODULE,
+};
+
+static struct class *idletimer_tg_class;
+
+static struct device *idletimer_tg_device;
+
+static int __init idletimer_tg_init(void)
+{
+	int err;
+
+	idletimer_tg_class = class_create(THIS_MODULE, "xt_idletimer");
+	err = PTR_ERR(idletimer_tg_class);
+	if (IS_ERR(idletimer_tg_class)) {
+		pr_debug("couldn't register device class\n");
+		goto out;
+	}
+
+	idletimer_tg_device = device_create(idletimer_tg_class, NULL,
+					    MKDEV(0, 0), NULL, "timers");
+	err = PTR_ERR(idletimer_tg_device);
+	if (IS_ERR(idletimer_tg_device)) {
+		pr_debug("couldn't register system device\n");
+		goto out_class;
+	}
+
+	idletimer_tg_kobj = &idletimer_tg_device->kobj;
+
+	err =  xt_register_target(&idletimer_tg);
+	if (err < 0) {
+		pr_debug("couldn't register xt target\n");
+		goto out_dev;
+	}
+
+	return 0;
+out_dev:
+	device_destroy(idletimer_tg_class, MKDEV(0, 0));
+out_class:
+	class_destroy(idletimer_tg_class);
+out:
+	return err;
+}
+
+static void __exit idletimer_tg_exit(void)
+{
+	xt_unregister_target(&idletimer_tg);
+
+	device_destroy(idletimer_tg_class, MKDEV(0, 0));
+	class_destroy(idletimer_tg_class);
+}
+
+module_init(idletimer_tg_init);
+module_exit(idletimer_tg_exit);
+
+MODULE_AUTHOR("Timo Teras <ext-timo.teras@nokia.com>");
+MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
+MODULE_DESCRIPTION("Xtables: idle time monitor");
+MODULE_LICENSE("GPL v2");
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c
index 512b912..9d78218 100644
--- a/net/netfilter/xt_NOTRACK.c
+++ b/net/netfilter/xt_NOTRACK.c
@@ -23,7 +23,7 @@
 	   If there is a real ct entry correspondig to this packet,
 	   it'll hang aroun till timing out. We don't deal with it
 	   for performance reasons. JK */
-	skb->nfct = &nf_conntrack_untracked.ct_general;
+	skb->nfct = &nf_ct_untracked_get()->ct_general;
 	skb->nfctinfo = IP_CT_NEW;
 	nf_conntrack_get(skb->nfct);
 
diff --git a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c
index 69c01e1..de079abd 100644
--- a/net/netfilter/xt_RATEEST.c
+++ b/net/netfilter/xt_RATEEST.c
@@ -60,13 +60,22 @@
 }
 EXPORT_SYMBOL_GPL(xt_rateest_lookup);
 
+static void xt_rateest_free_rcu(struct rcu_head *head)
+{
+	kfree(container_of(head, struct xt_rateest, rcu));
+}
+
 void xt_rateest_put(struct xt_rateest *est)
 {
 	mutex_lock(&xt_rateest_mutex);
 	if (--est->refcnt == 0) {
 		hlist_del(&est->list);
 		gen_kill_estimator(&est->bstats, &est->rstats);
-		kfree(est);
+		/*
+		 * gen_estimator est_timer() might access est->lock or bstats,
+		 * wait a RCU grace period before freeing 'est'
+		 */
+		call_rcu(&est->rcu, xt_rateest_free_rcu);
 	}
 	mutex_unlock(&xt_rateest_mutex);
 }
@@ -179,6 +188,7 @@
 static void __exit xt_rateest_tg_fini(void)
 {
 	xt_unregister_target(&xt_rateest_tg_reg);
+	rcu_barrier(); /* Wait for completion of call_rcu()'s (xt_rateest_free_rcu) */
 }
 
 
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
index 62ec021..eb81c38 100644
--- a/net/netfilter/xt_TCPMSS.c
+++ b/net/netfilter/xt_TCPMSS.c
@@ -165,8 +165,8 @@
 	rcu_read_unlock();
 
 	if (rt != NULL) {
-		mtu = dst_mtu(&rt->u.dst);
-		dst_release(&rt->u.dst);
+		mtu = dst_mtu(&rt->dst);
+		dst_release(&rt->dst);
 	}
 	return mtu;
 }
@@ -220,15 +220,13 @@
 }
 #endif
 
-#define TH_SYN 0x02
-
 /* Must specify -p tcp --syn */
 static inline bool find_syn_match(const struct xt_entry_match *m)
 {
 	const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
 
 	if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
-	    tcpinfo->flg_cmp & TH_SYN &&
+	    tcpinfo->flg_cmp & TCPHDR_SYN &&
 	    !(tcpinfo->invflags & XT_TCP_INV_FLAGS))
 		return true;
 
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c
index 859d9fd..22a2d42 100644
--- a/net/netfilter/xt_TEE.c
+++ b/net/netfilter/xt_TEE.c
@@ -77,8 +77,8 @@
 		return false;
 
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->u.dst);
-	skb->dev      = rt->u.dst.dev;
+	skb_dst_set(skb, &rt->dst);
+	skb->dev      = rt->dst.dev;
 	skb->protocol = htons(ETH_P_IP);
 	return true;
 }
@@ -104,7 +104,7 @@
 #ifdef WITH_CONNTRACK
 	/* Avoid counting cloned packets towards the original connection. */
 	nf_conntrack_put(skb->nfct);
-	skb->nfct     = &nf_conntrack_untracked.ct_general;
+	skb->nfct     = &nf_ct_untracked_get()->ct_general;
 	skb->nfctinfo = IP_CT_NEW;
 	nf_conntrack_get(skb->nfct);
 #endif
@@ -177,7 +177,7 @@
 
 #ifdef WITH_CONNTRACK
 	nf_conntrack_put(skb->nfct);
-	skb->nfct     = &nf_conntrack_untracked.ct_general;
+	skb->nfct     = &nf_ct_untracked_get()->ct_general;
 	skb->nfctinfo = IP_CT_NEW;
 	nf_conntrack_get(skb->nfct);
 #endif
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index e1a0ded..c61294d 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -37,8 +37,10 @@
 		return NF_DROP;
 
 	sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
-				   iph->saddr, tgi->laddr ? tgi->laddr : iph->daddr,
-				   hp->source, tgi->lport ? tgi->lport : hp->dest,
+				   iph->saddr,
+				   tgi->laddr ? tgi->laddr : iph->daddr,
+				   hp->source,
+				   tgi->lport ? tgi->lport : hp->dest,
 				   par->in, true);
 
 	/* NOTE: assign_sock consumes our sk reference */
diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c
index 30b95a1..f4af1bf 100644
--- a/net/netfilter/xt_cluster.c
+++ b/net/netfilter/xt_cluster.c
@@ -120,7 +120,7 @@
 	if (ct == NULL)
 		return false;
 
-	if (ct == &nf_conntrack_untracked)
+	if (nf_ct_is_untracked(ct))
 		return false;
 
 	if (ct->master)
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
index 7351783..5b13850 100644
--- a/net/netfilter/xt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -112,6 +112,16 @@
 	if (ret < 0)
 		pr_info("cannot load conntrack support for proto=%u\n",
 			par->family);
+
+	/*
+	 * This filter cannot function correctly unless connection tracking
+	 * accounting is enabled, so complain in the hope that someone notices.
+	 */
+	if (!nf_ct_acct_enabled(par->net)) {
+		pr_warning("Forcing CT accounting to be enabled\n");
+		nf_ct_set_acct(par->net, true);
+	}
+
 	return ret;
 }
 
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index 39681f1..e536710 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -123,11 +123,12 @@
 
 	ct = nf_ct_get(skb, &ctinfo);
 
-	if (ct == &nf_conntrack_untracked)
-		statebit = XT_CONNTRACK_STATE_UNTRACKED;
-	else if (ct != NULL)
-		statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
-	else
+	if (ct) {
+		if (nf_ct_is_untracked(ct))
+			statebit = XT_CONNTRACK_STATE_UNTRACKED;
+		else
+			statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
+	} else
 		statebit = XT_CONNTRACK_STATE_INVALID;
 
 	if (info->match_flags & XT_CONNTRACK_STATE) {
diff --git a/net/netfilter/xt_cpu.c b/net/netfilter/xt_cpu.c
new file mode 100644
index 0000000..b39db8a
--- /dev/null
+++ b/net/netfilter/xt_cpu.c
@@ -0,0 +1,63 @@
+/* Kernel module to match running CPU */
+
+/*
+ * Might be used to distribute connections on several daemons, if
+ * RPS (Remote Packet Steering) is enabled or NIC is multiqueue capable,
+ * each RX queue IRQ affined to one CPU (1:1 mapping)
+ *
+ */
+
+/* (C) 2010 Eric Dumazet
+ *
+ * This program is free software; you can 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/skbuff.h>
+#include <linux/netfilter/xt_cpu.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Dumazet <eric.dumazet@gmail.com>");
+MODULE_DESCRIPTION("Xtables: CPU match");
+
+static int cpu_mt_check(const struct xt_mtchk_param *par)
+{
+	const struct xt_cpu_info *info = par->matchinfo;
+
+	if (info->invert & ~1)
+		return -EINVAL;
+	return 0;
+}
+
+static bool cpu_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+	const struct xt_cpu_info *info = par->matchinfo;
+
+	return (info->cpu == smp_processor_id()) ^ info->invert;
+}
+
+static struct xt_match cpu_mt_reg __read_mostly = {
+	.name       = "cpu",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.checkentry = cpu_mt_check,
+	.match      = cpu_mt,
+	.matchsize  = sizeof(struct xt_cpu_info),
+	.me         = THIS_MODULE,
+};
+
+static int __init cpu_mt_init(void)
+{
+	return xt_register_match(&cpu_mt_reg);
+}
+
+static void __exit cpu_mt_exit(void)
+{
+	xt_unregister_match(&cpu_mt_reg);
+}
+
+module_init(cpu_mt_init);
+module_exit(cpu_mt_exit);
diff --git a/net/netfilter/xt_ipvs.c b/net/netfilter/xt_ipvs.c
new file mode 100644
index 0000000..7a4d66d
--- /dev/null
+++ b/net/netfilter/xt_ipvs.c
@@ -0,0 +1,189 @@
+/*
+ *	xt_ipvs - kernel module to match IPVS connection properties
+ *
+ *	Author: Hannes Eder <heder@google.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#ifdef CONFIG_IP_VS_IPV6
+#include <net/ipv6.h>
+#endif
+#include <linux/ip_vs.h>
+#include <linux/types.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_ipvs.h>
+#include <net/netfilter/nf_conntrack.h>
+
+#include <net/ip_vs.h>
+
+MODULE_AUTHOR("Hannes Eder <heder@google.com>");
+MODULE_DESCRIPTION("Xtables: match IPVS connection properties");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_ipvs");
+MODULE_ALIAS("ip6t_ipvs");
+
+/* borrowed from xt_conntrack */
+static bool ipvs_mt_addrcmp(const union nf_inet_addr *kaddr,
+			    const union nf_inet_addr *uaddr,
+			    const union nf_inet_addr *umask,
+			    unsigned int l3proto)
+{
+	if (l3proto == NFPROTO_IPV4)
+		return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0;
+#ifdef CONFIG_IP_VS_IPV6
+	else if (l3proto == NFPROTO_IPV6)
+		return ipv6_masked_addr_cmp(&kaddr->in6, &umask->in6,
+		       &uaddr->in6) == 0;
+#endif
+	else
+		return false;
+}
+
+static bool
+ipvs_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+	const struct xt_ipvs_mtinfo *data = par->matchinfo;
+	/* ipvs_mt_check ensures that family is only NFPROTO_IPV[46]. */
+	const u_int8_t family = par->family;
+	struct ip_vs_iphdr iph;
+	struct ip_vs_protocol *pp;
+	struct ip_vs_conn *cp;
+	bool match = true;
+
+	if (data->bitmask == XT_IPVS_IPVS_PROPERTY) {
+		match = skb->ipvs_property ^
+			!!(data->invert & XT_IPVS_IPVS_PROPERTY);
+		goto out;
+	}
+
+	/* other flags than XT_IPVS_IPVS_PROPERTY are set */
+	if (!skb->ipvs_property) {
+		match = false;
+		goto out;
+	}
+
+	ip_vs_fill_iphdr(family, skb_network_header(skb), &iph);
+
+	if (data->bitmask & XT_IPVS_PROTO)
+		if ((iph.protocol == data->l4proto) ^
+		    !(data->invert & XT_IPVS_PROTO)) {
+			match = false;
+			goto out;
+		}
+
+	pp = ip_vs_proto_get(iph.protocol);
+	if (unlikely(!pp)) {
+		match = false;
+		goto out;
+	}
+
+	/*
+	 * Check if the packet belongs to an existing entry
+	 */
+	cp = pp->conn_out_get(family, skb, pp, &iph, iph.len, 1 /* inverse */);
+	if (unlikely(cp == NULL)) {
+		match = false;
+		goto out;
+	}
+
+	/*
+	 * We found a connection, i.e. ct != 0, make sure to call
+	 * __ip_vs_conn_put before returning.  In our case jump to out_put_con.
+	 */
+
+	if (data->bitmask & XT_IPVS_VPORT)
+		if ((cp->vport == data->vport) ^
+		    !(data->invert & XT_IPVS_VPORT)) {
+			match = false;
+			goto out_put_cp;
+		}
+
+	if (data->bitmask & XT_IPVS_VPORTCTL)
+		if ((cp->control != NULL &&
+		     cp->control->vport == data->vportctl) ^
+		    !(data->invert & XT_IPVS_VPORTCTL)) {
+			match = false;
+			goto out_put_cp;
+		}
+
+	if (data->bitmask & XT_IPVS_DIR) {
+		enum ip_conntrack_info ctinfo;
+		struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
+		if (ct == NULL || nf_ct_is_untracked(ct)) {
+			match = false;
+			goto out_put_cp;
+		}
+
+		if ((ctinfo >= IP_CT_IS_REPLY) ^
+		    !!(data->invert & XT_IPVS_DIR)) {
+			match = false;
+			goto out_put_cp;
+		}
+	}
+
+	if (data->bitmask & XT_IPVS_METHOD)
+		if (((cp->flags & IP_VS_CONN_F_FWD_MASK) == data->fwd_method) ^
+		    !(data->invert & XT_IPVS_METHOD)) {
+			match = false;
+			goto out_put_cp;
+		}
+
+	if (data->bitmask & XT_IPVS_VADDR) {
+		if (ipvs_mt_addrcmp(&cp->vaddr, &data->vaddr,
+				    &data->vmask, family) ^
+		    !(data->invert & XT_IPVS_VADDR)) {
+			match = false;
+			goto out_put_cp;
+		}
+	}
+
+out_put_cp:
+	__ip_vs_conn_put(cp);
+out:
+	pr_debug("match=%d\n", match);
+	return match;
+}
+
+static int ipvs_mt_check(const struct xt_mtchk_param *par)
+{
+	if (par->family != NFPROTO_IPV4
+#ifdef CONFIG_IP_VS_IPV6
+	    && par->family != NFPROTO_IPV6
+#endif
+		) {
+		pr_info("protocol family %u not supported\n", par->family);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct xt_match xt_ipvs_mt_reg __read_mostly = {
+	.name       = "ipvs",
+	.revision   = 0,
+	.family     = NFPROTO_UNSPEC,
+	.match      = ipvs_mt,
+	.checkentry = ipvs_mt_check,
+	.matchsize  = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
+	.me         = THIS_MODULE,
+};
+
+static int __init ipvs_mt_init(void)
+{
+	return xt_register_match(&xt_ipvs_mt_reg);
+}
+
+static void __exit ipvs_mt_exit(void)
+{
+	xt_unregister_match(&xt_ipvs_mt_reg);
+}
+
+module_init(ipvs_mt_init);
+module_exit(ipvs_mt_exit);
diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c
index b4f7dfe..70eb2b4 100644
--- a/net/netfilter/xt_quota.c
+++ b/net/netfilter/xt_quota.c
@@ -11,7 +11,8 @@
 #include <linux/netfilter/xt_quota.h>
 
 struct xt_quota_priv {
-	uint64_t quota;
+	spinlock_t	lock;
+	uint64_t	quota;
 };
 
 MODULE_LICENSE("GPL");
@@ -20,8 +21,6 @@
 MODULE_ALIAS("ipt_quota");
 MODULE_ALIAS("ip6t_quota");
 
-static DEFINE_SPINLOCK(quota_lock);
-
 static bool
 quota_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
@@ -29,7 +28,7 @@
 	struct xt_quota_priv *priv = q->master;
 	bool ret = q->flags & XT_QUOTA_INVERT;
 
-	spin_lock_bh(&quota_lock);
+	spin_lock_bh(&priv->lock);
 	if (priv->quota >= skb->len) {
 		priv->quota -= skb->len;
 		ret = !ret;
@@ -37,9 +36,7 @@
 		/* we do not allow even small packets from now on */
 		priv->quota = 0;
 	}
-	/* Copy quota back to matchinfo so that iptables can display it */
-	q->quota = priv->quota;
-	spin_unlock_bh(&quota_lock);
+	spin_unlock_bh(&priv->lock);
 
 	return ret;
 }
@@ -55,6 +52,7 @@
 	if (q->master == NULL)
 		return -ENOMEM;
 
+	spin_lock_init(&q->master->lock);
 	q->master->quota = q->quota;
 	return 0;
 }
diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c
index c04fcf3..ef36a56 100644
--- a/net/netfilter/xt_sctp.c
+++ b/net/netfilter/xt_sctp.c
@@ -3,6 +3,7 @@
 #include <linux/skbuff.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
+#include <net/sctp/sctp.h>
 #include <linux/sctp.h>
 
 #include <linux/netfilter/x_tables.h>
@@ -67,7 +68,7 @@
 			 ++i, offset, sch->type, htons(sch->length),
 			 sch->flags);
 #endif
-		offset += (ntohs(sch->length) + 3) & ~3;
+		offset += WORD_ROUND(ntohs(sch->length));
 
 		pr_debug("skb->len: %d\toffset: %d\n", skb->len, offset);
 
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index 3d54c23..1ca8990 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -127,7 +127,7 @@
 	 * reply packet of an established SNAT-ted connection. */
 
 	ct = nf_ct_get(skb, &ctinfo);
-	if (ct && (ct != &nf_conntrack_untracked) &&
+	if (ct && !nf_ct_is_untracked(ct) &&
 	    ((iph->protocol != IPPROTO_ICMP &&
 	      ctinfo == IP_CT_IS_REPLY + IP_CT_ESTABLISHED) ||
 	     (iph->protocol == IPPROTO_ICMP &&
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c
index e12e053..a507922 100644
--- a/net/netfilter/xt_state.c
+++ b/net/netfilter/xt_state.c
@@ -26,14 +26,16 @@
 	const struct xt_state_info *sinfo = par->matchinfo;
 	enum ip_conntrack_info ctinfo;
 	unsigned int statebit;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 
-	if (nf_ct_is_untracked(skb))
-		statebit = XT_STATE_UNTRACKED;
-	else if (!nf_ct_get(skb, &ctinfo))
+	if (!ct)
 		statebit = XT_STATE_INVALID;
-	else
-		statebit = XT_STATE_BIT(ctinfo);
-
+	else {
+		if (nf_ct_is_untracked(ct))
+			statebit = XT_STATE_UNTRACKED;
+		else
+			statebit = XT_STATE_BIT(ctinfo);
+	}
 	return (sinfo->statemask & statebit);
 }
 
diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c
index 96e62b8..42ecb71 100644
--- a/net/netfilter/xt_statistic.c
+++ b/net/netfilter/xt_statistic.c
@@ -18,8 +18,8 @@
 #include <linux/netfilter/x_tables.h>
 
 struct xt_statistic_priv {
-	uint32_t count;
-};
+	atomic_t count;
+} ____cacheline_aligned_in_smp;
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
@@ -27,13 +27,12 @@
 MODULE_ALIAS("ipt_statistic");
 MODULE_ALIAS("ip6t_statistic");
 
-static DEFINE_SPINLOCK(nth_lock);
-
 static bool
 statistic_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
 	const struct xt_statistic_info *info = par->matchinfo;
 	bool ret = info->flags & XT_STATISTIC_INVERT;
+	int nval, oval;
 
 	switch (info->mode) {
 	case XT_STATISTIC_MODE_RANDOM:
@@ -41,12 +40,12 @@
 			ret = !ret;
 		break;
 	case XT_STATISTIC_MODE_NTH:
-		spin_lock_bh(&nth_lock);
-		if (info->master->count++ == info->u.nth.every) {
-			info->master->count = 0;
+		do {
+			oval = atomic_read(&info->master->count);
+			nval = (oval == info->u.nth.every) ? 0 : oval + 1;
+		} while (atomic_cmpxchg(&info->master->count, oval, nval) != oval);
+		if (nval == 0)
 			ret = !ret;
-		}
-		spin_unlock_bh(&nth_lock);
 		break;
 	}
 
@@ -64,7 +63,7 @@
 	info->master = kzalloc(sizeof(*info->master), GFP_KERNEL);
 	if (info->master == NULL)
 		return -ENOMEM;
-	info->master->count = info->u.nth.count;
+	atomic_set(&info->master->count, info->u.nth.count);
 
 	return 0;
 }
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index a2eb965..2cbf380 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1076,14 +1076,15 @@
 	sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list)
 		do_one_broadcast(sk, &info);
 
-	kfree_skb(skb);
+	consume_skb(skb);
 
 	netlink_unlock_table();
 
-	kfree_skb(info.skb2);
-
-	if (info.delivery_failure)
+	if (info.delivery_failure) {
+		kfree_skb(info.skb2);
 		return -ENOBUFS;
+	} else
+		consume_skb(info.skb2);
 
 	if (info.delivered) {
 		if (info.congested && (allocation & __GFP_WAIT))
@@ -1323,19 +1324,23 @@
 	if (msg->msg_flags&MSG_OOB)
 		return -EOPNOTSUPP;
 
-	if (NULL == siocb->scm)
+	if (NULL == siocb->scm) {
 		siocb->scm = &scm;
+		memset(&scm, 0, sizeof(scm));
+	}
 	err = scm_send(sock, msg, siocb->scm);
 	if (err < 0)
 		return err;
 
 	if (msg->msg_namelen) {
+		err = -EINVAL;
 		if (addr->nl_family != AF_NETLINK)
-			return -EINVAL;
+			goto out;
 		dst_pid = addr->nl_pid;
 		dst_group = ffs(addr->nl_groups);
+		err =  -EPERM;
 		if (dst_group && !netlink_capable(sock, NL_NONROOT_SEND))
-			return -EPERM;
+			goto out;
 	} else {
 		dst_pid = nlk->dst_pid;
 		dst_group = nlk->dst_group;
@@ -1387,6 +1392,7 @@
 	err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT);
 
 out:
+	scm_destroy(siocb->scm);
 	return err;
 }
 
@@ -1400,7 +1406,7 @@
 	struct netlink_sock *nlk = nlk_sk(sk);
 	int noblock = flags&MSG_DONTWAIT;
 	size_t copied;
-	struct sk_buff *skb, *frag __maybe_unused = NULL;
+	struct sk_buff *skb;
 	int err;
 
 	if (flags&MSG_OOB)
@@ -1435,7 +1441,21 @@
 			kfree_skb(skb);
 			skb = compskb;
 		} else {
-			frag = skb_shinfo(skb)->frag_list;
+			/*
+			 * Before setting frag_list to NULL, we must get a
+			 * private copy of skb if shared (because of MSG_PEEK)
+			 */
+			if (skb_shared(skb)) {
+				struct sk_buff *nskb;
+
+				nskb = pskb_copy(skb, GFP_KERNEL);
+				kfree_skb(skb);
+				skb = nskb;
+				err = -ENOMEM;
+				if (!skb)
+					goto out;
+			}
+			kfree_skb(skb_shinfo(skb)->frag_list);
 			skb_shinfo(skb)->frag_list = NULL;
 		}
 	}
@@ -1472,10 +1492,6 @@
 	if (flags & MSG_TRUNC)
 		copied = skb->len;
 
-#ifdef CONFIG_COMPAT_NETLINK_MESSAGES
-	skb_shinfo(skb)->frag_list = frag;
-#endif
-
 	skb_free_datagram(sk, skb);
 
 	if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2)
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index aa4308a..26ed3e8 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -303,6 +303,7 @@
 errout:
 	return err;
 }
+EXPORT_SYMBOL(genl_register_ops);
 
 /**
  * genl_unregister_ops - unregister generic netlink operations
@@ -337,6 +338,7 @@
 
 	return -ENOENT;
 }
+EXPORT_SYMBOL(genl_unregister_ops);
 
 /**
  * genl_register_family - register a generic netlink family
@@ -405,6 +407,7 @@
 errout:
 	return err;
 }
+EXPORT_SYMBOL(genl_register_family);
 
 /**
  * genl_register_family_with_ops - register a generic netlink family
@@ -485,6 +488,7 @@
 
 	return -ENOENT;
 }
+EXPORT_SYMBOL(genl_unregister_family);
 
 static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
@@ -873,11 +877,7 @@
 	for (i = 0; i < GENL_FAM_TAB_SIZE; i++)
 		INIT_LIST_HEAD(&family_ht[i]);
 
-	err = genl_register_family(&genl_ctrl);
-	if (err < 0)
-		goto problem;
-
-	err = genl_register_ops(&genl_ctrl, &genl_ctrl_ops);
+	err = genl_register_family_with_ops(&genl_ctrl, &genl_ctrl_ops, 1);
 	if (err < 0)
 		goto problem;
 
@@ -899,11 +899,6 @@
 
 subsys_initcall(genl_init);
 
-EXPORT_SYMBOL(genl_register_ops);
-EXPORT_SYMBOL(genl_unregister_ops);
-EXPORT_SYMBOL(genl_register_family);
-EXPORT_SYMBOL(genl_unregister_family);
-
 static int genlmsg_mcast(struct sk_buff *skb, u32 pid, unsigned long group,
 			 gfp_t flags)
 {
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 2078a27..9a17f28 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -83,6 +83,7 @@
 #include <linux/if_vlan.h>
 #include <linux/virtio_net.h>
 #include <linux/errqueue.h>
+#include <linux/net_tstamp.h>
 
 #ifdef CONFIG_INET
 #include <net/inet_common.h>
@@ -202,6 +203,7 @@
 	unsigned int		tp_hdrlen;
 	unsigned int		tp_reserve;
 	unsigned int		tp_loss:1;
+	unsigned int		tp_tstamp;
 	struct packet_type	prot_hook ____cacheline_aligned_in_smp;
 };
 
@@ -656,6 +658,7 @@
 	struct sk_buff *copy_skb = NULL;
 	struct timeval tv;
 	struct timespec ts;
+	struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
 
 	if (skb->pkt_type == PACKET_LOOPBACK)
 		goto drop;
@@ -737,7 +740,13 @@
 		h.h1->tp_snaplen = snaplen;
 		h.h1->tp_mac = macoff;
 		h.h1->tp_net = netoff;
-		if (skb->tstamp.tv64)
+		if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
+				&& shhwtstamps->syststamp.tv64)
+			tv = ktime_to_timeval(shhwtstamps->syststamp);
+		else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
+				&& shhwtstamps->hwtstamp.tv64)
+			tv = ktime_to_timeval(shhwtstamps->hwtstamp);
+		else if (skb->tstamp.tv64)
 			tv = ktime_to_timeval(skb->tstamp);
 		else
 			do_gettimeofday(&tv);
@@ -750,7 +759,13 @@
 		h.h2->tp_snaplen = snaplen;
 		h.h2->tp_mac = macoff;
 		h.h2->tp_net = netoff;
-		if (skb->tstamp.tv64)
+		if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
+				&& shhwtstamps->syststamp.tv64)
+			ts = ktime_to_timespec(shhwtstamps->syststamp);
+		else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
+				&& shhwtstamps->hwtstamp.tv64)
+			ts = ktime_to_timespec(shhwtstamps->hwtstamp);
+		else if (skb->tstamp.tv64)
 			ts = ktime_to_timespec(skb->tstamp);
 		else
 			getnstimeofday(&ts);
@@ -2027,6 +2042,18 @@
 		po->has_vnet_hdr = !!val;
 		return 0;
 	}
+	case PACKET_TIMESTAMP:
+	{
+		int val;
+
+		if (optlen != sizeof(val))
+			return -EINVAL;
+		if (copy_from_user(&val, optval, sizeof(val)))
+			return -EFAULT;
+
+		po->tp_tstamp = val;
+		return 0;
+	}
 	default:
 		return -ENOPROTOOPT;
 	}
@@ -2119,6 +2146,12 @@
 		val = po->tp_loss;
 		data = &val;
 		break;
+	case PACKET_TIMESTAMP:
+		if (len > sizeof(int))
+			len = sizeof(int);
+		val = po->tp_tstamp;
+		data = &val;
+		break;
 	default:
 		return -ENOPROTOOPT;
 	}
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index c33da65..b18e48f 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -162,6 +162,14 @@
 	return err;
 }
 
+static void phonet_device_rcu_free(struct rcu_head *head)
+{
+	struct phonet_device *pnd;
+
+	pnd = container_of(head, struct phonet_device, rcu);
+	kfree(pnd);
+}
+
 int phonet_address_del(struct net_device *dev, u8 addr)
 {
 	struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
@@ -179,10 +187,9 @@
 		pnd = NULL;
 	mutex_unlock(&pndevs->lock);
 
-	if (pnd) {
-		synchronize_rcu();
-		kfree(pnd);
-	}
+	if (pnd)
+		call_rcu(&pnd->rcu, phonet_device_rcu_free);
+
 	return err;
 }
 
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index cbc244a1..b4fdaac 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -109,7 +109,9 @@
 		init_timer(&rose_neigh->t0timer);
 
 		if (rose_route->ndigis != 0) {
-			if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
+			rose_neigh->digipeat =
+				kmalloc(sizeof(ax25_digi), GFP_ATOMIC);
+			if (rose_neigh->digipeat == NULL) {
 				kfree(rose_neigh);
 				res = -ENOMEM;
 				goto out;
diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c
index f0f85b0..9f1729b 100644
--- a/net/rxrpc/ar-peer.c
+++ b/net/rxrpc/ar-peer.c
@@ -64,8 +64,8 @@
 		return;
 	}
 
-	peer->if_mtu = dst_mtu(&rt->u.dst);
-	dst_release(&rt->u.dst);
+	peer->if_mtu = dst_mtu(&rt->dst);
+	dst_release(&rt->dst);
 
 	_leave(" [if_mtu %u]", peer->if_mtu);
 }
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 972378f..23b25f8 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -26,6 +26,11 @@
 #include <net/act_api.h>
 #include <net/netlink.h>
 
+static void tcf_common_free_rcu(struct rcu_head *head)
+{
+	kfree(container_of(head, struct tcf_common, tcfc_rcu));
+}
+
 void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
 {
 	unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask);
@@ -38,7 +43,11 @@
 			write_unlock_bh(hinfo->lock);
 			gen_kill_estimator(&p->tcfc_bstats,
 					   &p->tcfc_rate_est);
-			kfree(p);
+			/*
+			 * gen_estimator est_timer() might access p->tcfc_lock
+			 * or bstats, wait a RCU grace period before freeing p
+			 */
+			call_rcu(&p->tcfc_rcu, tcf_common_free_rcu);
 			return;
 		}
 	}
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 1980b71..11f195a 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -165,6 +165,8 @@
 
 	spin_lock(&m->tcf_lock);
 	m->tcf_tm.lastuse = jiffies;
+	m->tcf_bstats.bytes += qdisc_pkt_len(skb);
+	m->tcf_bstats.packets++;
 
 	dev = m->tcfm_dev;
 	if (!dev) {
@@ -179,13 +181,11 @@
 		goto out;
 	}
 
-	skb2 = skb_act_clone(skb, GFP_ATOMIC);
+	at = G_TC_AT(skb->tc_verd);
+	skb2 = skb_act_clone(skb, GFP_ATOMIC, m->tcf_action);
 	if (skb2 == NULL)
 		goto out;
 
-	m->tcf_bstats.bytes += qdisc_pkt_len(skb2);
-	m->tcf_bstats.packets++;
-	at = G_TC_AT(skb->tc_verd);
 	if (!(at & AT_EGRESS)) {
 		if (m->tcfm_ok_push)
 			skb_push(skb2, skb2->dev->hard_header_len);
@@ -195,16 +195,14 @@
 	if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
 		skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at);
 
-	skb2->dev = dev;
 	skb2->skb_iif = skb->dev->ifindex;
+	skb2->dev = dev;
 	dev_queue_xmit(skb2);
 	err = 0;
 
 out:
 	if (err) {
 		m->tcf_qstats.overlimits++;
-		m->tcf_bstats.bytes += qdisc_pkt_len(skb);
-		m->tcf_bstats.packets++;
 		/* should we be asking for packet to be dropped?
 		 * may make sense for redirect case only
 		 */
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
index 724553e..d0386a4 100644
--- a/net/sched/act_nat.c
+++ b/net/sched/act_nat.c
@@ -218,6 +218,7 @@
 		if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph)))
 			goto drop;
 
+		icmph = (void *)(skb_network_header(skb) + ihl);
 		iph = (void *)(icmph + 1);
 		if (egress)
 			addr = iph->daddr;
@@ -246,7 +247,7 @@
 			iph->saddr = new_addr;
 
 		inet_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr,
-					 1);
+					 0);
 		break;
 	}
 	default:
@@ -268,40 +269,29 @@
 {
 	unsigned char *b = skb_tail_pointer(skb);
 	struct tcf_nat *p = a->priv;
-	struct tc_nat *opt;
+	struct tc_nat opt;
 	struct tcf_t t;
-	int s;
 
-	s = sizeof(*opt);
+	opt.old_addr = p->old_addr;
+	opt.new_addr = p->new_addr;
+	opt.mask = p->mask;
+	opt.flags = p->flags;
 
-	/* netlink spinlocks held above us - must use ATOMIC */
-	opt = kzalloc(s, GFP_ATOMIC);
-	if (unlikely(!opt))
-		return -ENOBUFS;
+	opt.index = p->tcf_index;
+	opt.action = p->tcf_action;
+	opt.refcnt = p->tcf_refcnt - ref;
+	opt.bindcnt = p->tcf_bindcnt - bind;
 
-	opt->old_addr = p->old_addr;
-	opt->new_addr = p->new_addr;
-	opt->mask = p->mask;
-	opt->flags = p->flags;
-
-	opt->index = p->tcf_index;
-	opt->action = p->tcf_action;
-	opt->refcnt = p->tcf_refcnt - ref;
-	opt->bindcnt = p->tcf_bindcnt - bind;
-
-	NLA_PUT(skb, TCA_NAT_PARMS, s, opt);
+	NLA_PUT(skb, TCA_NAT_PARMS, sizeof(opt), &opt);
 	t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
 	t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
 	t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
 	NLA_PUT(skb, TCA_NAT_TM, sizeof(t), &t);
 
-	kfree(opt);
-
 	return skb->len;
 
 nla_put_failure:
 	nlmsg_trim(skb, b);
-	kfree(opt);
 	return -1;
 }
 
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index 50e3d94..a0593c9 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -127,8 +127,7 @@
 	int i, munged = 0;
 	unsigned int off;
 
-	if (!(skb->tc_verd & TC_OK2MUNGE)) {
-		/* should we set skb->cloned? */
+	if (skb_cloned(skb)) {
 		if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
 			return p->tcf_action;
 		}
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 654f73d..537a487 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -97,6 +97,11 @@
 	goto done;
 }
 
+static void tcf_police_free_rcu(struct rcu_head *head)
+{
+	kfree(container_of(head, struct tcf_police, tcf_rcu));
+}
+
 static void tcf_police_destroy(struct tcf_police *p)
 {
 	unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK);
@@ -113,7 +118,11 @@
 				qdisc_put_rtab(p->tcfp_R_tab);
 			if (p->tcfp_P_tab)
 				qdisc_put_rtab(p->tcfp_P_tab);
-			kfree(p);
+			/*
+			 * gen_estimator est_timer() might access p->tcf_lock
+			 * or bstats, wait a RCU grace period before freeing p
+			 */
+			call_rcu(&p->tcf_rcu, tcf_police_free_rcu);
 			return;
 		}
 	}
@@ -397,6 +406,7 @@
 police_cleanup_module(void)
 {
 	tcf_unregister_action(&act_police_ops);
+	rcu_barrier(); /* Wait for completion of call_rcu()'s (tcf_police_free_rcu) */
 }
 
 module_init(police_init_module);
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index 1b4bc69..4a1d640 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -73,10 +73,10 @@
 
 static int alloc_defdata(struct tcf_defact *d, char *defdata)
 {
-	d->tcfd_defdata = kstrndup(defdata, SIMP_MAX_DATA, GFP_KERNEL);
+	d->tcfd_defdata = kzalloc(SIMP_MAX_DATA, GFP_KERNEL);
 	if (unlikely(!d->tcfd_defdata))
 		return -ENOMEM;
-
+	strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA);
 	return 0;
 }
 
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 4f52214..7416a5c 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -134,10 +134,12 @@
 #endif
 
 		for (i = n->sel.nkeys; i>0; i--, key++) {
-			unsigned int toff;
+			int toff = off + key->off + (off2 & key->offmask);
 			__be32 *data, _data;
 
-			toff = off + key->off + (off2 & key->offmask);
+			if (skb_headroom(skb) + toff < 0)
+				goto out;
+
 			data = skb_header_pointer(skb, toff, 4, &_data);
 			if (!data)
 				goto out;
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index fcbb86a..e114f23 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -52,7 +52,7 @@
 	int			ref;		/* reference count */
 	struct gnet_stats_basic_packed	bstats;
 	struct gnet_stats_queue	qstats;
-	struct atm_flow_data	*next;
+	struct list_head	list;
 	struct atm_flow_data	*excess;	/* flow for excess traffic;
 						   NULL to set CLP instead */
 	int			hdr_len;
@@ -61,34 +61,23 @@
 
 struct atm_qdisc_data {
 	struct atm_flow_data	link;		/* unclassified skbs go here */
-	struct atm_flow_data	*flows;		/* NB: "link" is also on this
+	struct list_head	flows;		/* NB: "link" is also on this
 						   list */
 	struct tasklet_struct	task;		/* dequeue tasklet */
 };
 
 /* ------------------------- Class/flow operations ------------------------- */
 
-static int find_flow(struct atm_qdisc_data *qdisc, struct atm_flow_data *flow)
-{
-	struct atm_flow_data *walk;
-
-	pr_debug("find_flow(qdisc %p,flow %p)\n", qdisc, flow);
-	for (walk = qdisc->flows; walk; walk = walk->next)
-		if (walk == flow)
-			return 1;
-	pr_debug("find_flow: not found\n");
-	return 0;
-}
-
 static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid)
 {
 	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow;
 
-	for (flow = p->flows; flow; flow = flow->next)
+	list_for_each_entry(flow, &p->flows, list) {
 		if (flow->classid == classid)
-			break;
-	return flow;
+			return flow;
+	}
+	return NULL;
 }
 
 static int atm_tc_graft(struct Qdisc *sch, unsigned long arg,
@@ -99,7 +88,7 @@
 
 	pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",
 		sch, p, flow, new, old);
-	if (!find_flow(p, flow))
+	if (list_empty(&flow->list))
 		return -EINVAL;
 	if (!new)
 		new = &noop_qdisc;
@@ -146,20 +135,12 @@
 {
 	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow = (struct atm_flow_data *)cl;
-	struct atm_flow_data **prev;
 
 	pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
 	if (--flow->ref)
 		return;
 	pr_debug("atm_tc_put: destroying\n");
-	for (prev = &p->flows; *prev; prev = &(*prev)->next)
-		if (*prev == flow)
-			break;
-	if (!*prev) {
-		printk(KERN_CRIT "atm_tc_put: class %p not found\n", flow);
-		return;
-	}
-	*prev = flow->next;
+	list_del_init(&flow->list);
 	pr_debug("atm_tc_put: qdisc %p\n", flow->q);
 	qdisc_destroy(flow->q);
 	tcf_destroy_chain(&flow->filter_list);
@@ -274,7 +255,7 @@
 			error = -EINVAL;
 			goto err_out;
 		}
-		if (find_flow(p, flow)) {
+		if (!list_empty(&flow->list)) {
 			error = -EEXIST;
 			goto err_out;
 		}
@@ -313,8 +294,7 @@
 	flow->classid = classid;
 	flow->ref = 1;
 	flow->excess = excess;
-	flow->next = p->link.next;
-	p->link.next = flow;
+	list_add(&flow->list, &p->link.list);
 	flow->hdr_len = hdr_len;
 	if (hdr)
 		memcpy(flow->hdr, hdr, hdr_len);
@@ -335,7 +315,7 @@
 	struct atm_flow_data *flow = (struct atm_flow_data *)arg;
 
 	pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
-	if (!find_flow(qdisc_priv(sch), flow))
+	if (list_empty(&flow->list))
 		return -EINVAL;
 	if (flow->filter_list || flow == &p->link)
 		return -EBUSY;
@@ -361,12 +341,12 @@
 	pr_debug("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);
 	if (walker->stop)
 		return;
-	for (flow = p->flows; flow; flow = flow->next) {
-		if (walker->count >= walker->skip)
-			if (walker->fn(sch, (unsigned long)flow, walker) < 0) {
-				walker->stop = 1;
-				break;
-			}
+	list_for_each_entry(flow, &p->flows, list) {
+		if (walker->count >= walker->skip &&
+		    walker->fn(sch, (unsigned long)flow, walker) < 0) {
+			walker->stop = 1;
+			break;
+		}
 		walker->count++;
 	}
 }
@@ -385,16 +365,17 @@
 static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
 	struct atm_qdisc_data *p = qdisc_priv(sch);
-	struct atm_flow_data *flow = NULL;	/* @@@ */
+	struct atm_flow_data *flow;
 	struct tcf_result res;
 	int result;
 	int ret = NET_XMIT_POLICED;
 
 	pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
 	result = TC_POLICE_OK;	/* be nice to gcc */
+	flow = NULL;
 	if (TC_H_MAJ(skb->priority) != sch->handle ||
-	    !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority)))
-		for (flow = p->flows; flow; flow = flow->next)
+	    !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority))) {
+		list_for_each_entry(flow, &p->flows, list) {
 			if (flow->filter_list) {
 				result = tc_classify_compat(skb,
 							    flow->filter_list,
@@ -404,8 +385,13 @@
 				flow = (struct atm_flow_data *)res.class;
 				if (!flow)
 					flow = lookup_flow(sch, res.classid);
-				break;
+				goto done;
 			}
+		}
+		flow = NULL;
+	done:
+		;		
+	}
 	if (!flow)
 		flow = &p->link;
 	else {
@@ -477,7 +463,9 @@
 	struct sk_buff *skb;
 
 	pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p);
-	for (flow = p->link.next; flow; flow = flow->next)
+	list_for_each_entry(flow, &p->flows, list) {
+		if (flow == &p->link)
+			continue;
 		/*
 		 * If traffic is properly shaped, this won't generate nasty
 		 * little bursts. Otherwise, it may ... (but that's okay)
@@ -512,6 +500,7 @@
 			/* atm.atm_options are already set by atm_tc_enqueue */
 			flow->vcc->send(flow->vcc, skb);
 		}
+	}
 }
 
 static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
@@ -543,9 +532,10 @@
 	unsigned int len;
 
 	pr_debug("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p);
-	for (flow = p->flows; flow; flow = flow->next)
+	list_for_each_entry(flow, &p->flows, list) {
 		if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q)))
 			return len;
+	}
 	return 0;
 }
 
@@ -554,7 +544,9 @@
 	struct atm_qdisc_data *p = qdisc_priv(sch);
 
 	pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
-	p->flows = &p->link;
+	INIT_LIST_HEAD(&p->flows);
+	INIT_LIST_HEAD(&p->link.list);
+	list_add(&p->link.list, &p->flows);
 	p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
 				      &pfifo_qdisc_ops, sch->handle);
 	if (!p->link.q)
@@ -565,7 +557,6 @@
 	p->link.sock = NULL;
 	p->link.classid = sch->handle;
 	p->link.ref = 1;
-	p->link.next = NULL;
 	tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch);
 	return 0;
 }
@@ -576,7 +567,7 @@
 	struct atm_flow_data *flow;
 
 	pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p);
-	for (flow = p->flows; flow; flow = flow->next)
+	list_for_each_entry(flow, &p->flows, list)
 		qdisc_reset(flow->q);
 	sch->q.qlen = 0;
 }
@@ -584,24 +575,17 @@
 static void atm_tc_destroy(struct Qdisc *sch)
 {
 	struct atm_qdisc_data *p = qdisc_priv(sch);
-	struct atm_flow_data *flow;
+	struct atm_flow_data *flow, *tmp;
 
 	pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
-	for (flow = p->flows; flow; flow = flow->next)
+	list_for_each_entry(flow, &p->flows, list)
 		tcf_destroy_chain(&flow->filter_list);
 
-	/* races ? */
-	while ((flow = p->flows)) {
+	list_for_each_entry_safe(flow, tmp, &p->flows, list) {
 		if (flow->ref > 1)
 			printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow,
 			       flow->ref);
 		atm_tc_put(sch, (unsigned long)flow);
-		if (p->flows == flow) {
-			printk(KERN_ERR "atm_destroy: putting flow %p didn't "
-			       "kill it\n", flow);
-			p->flows = flow->next;	/* brute force */
-			break;
-		}
 	}
 	tasklet_kill(&p->task);
 }
@@ -615,7 +599,7 @@
 
 	pr_debug("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n",
 		sch, p, flow, skb, tcm);
-	if (!find_flow(p, flow))
+	if (list_empty(&flow->list))
 		return -EINVAL;
 	tcm->tcm_handle = flow->classid;
 	tcm->tcm_info = flow->q->handle;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index a63029e..2aeb3a4 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -96,7 +96,7 @@
 		 * Another cpu is holding lock, requeue & delay xmits for
 		 * some time.
 		 */
-		__get_cpu_var(softnet_data).cpu_collision++;
+		__this_cpu_inc(softnet_data.cpu_collision);
 		ret = dev_requeue_skb(skb, q);
 	}
 
@@ -205,7 +205,7 @@
 		}
 	}
 
-	clear_bit(__QDISC_STATE_RUNNING, &q->state);
+	qdisc_run_end(q);
 }
 
 unsigned long dev_trans_start(struct net_device *dev)
@@ -327,6 +327,24 @@
 }
 EXPORT_SYMBOL(netif_carrier_off);
 
+/**
+ * 	netif_notify_peers - notify network peers about existence of @dev
+ * 	@dev: network device
+ *
+ * Generate traffic such that interested network peers are aware of
+ * @dev, such as by generating a gratuitous ARP. This may be used when
+ * a device wants to inform the rest of the network about some sort of
+ * reconfiguration such as a failover event or virtual machine
+ * migration.
+ */
+void netif_notify_peers(struct net_device *dev)
+{
+	rtnl_lock();
+	call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, dev);
+	rtnl_unlock();
+}
+EXPORT_SYMBOL(netif_notify_peers);
+
 /* "NOOP" scheduler: the best scheduler, recommended for all interfaces
    under all circumstances. It is difficult to invent anything faster or
    cheaper.
@@ -543,6 +561,7 @@
 
 	INIT_LIST_HEAD(&sch->list);
 	skb_queue_head_init(&sch->q);
+	spin_lock_init(&sch->busylock);
 	sch->ops = ops;
 	sch->enqueue = ops->enqueue;
 	sch->dequeue = ops->dequeue;
@@ -779,7 +798,7 @@
 
 		spin_lock_bh(root_lock);
 
-		val = (test_bit(__QDISC_STATE_RUNNING, &q->state) ||
+		val = (qdisc_is_running(q) ||
 		       test_bit(__QDISC_STATE_SCHED, &q->state));
 
 		spin_unlock_bh(root_lock);
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 0b52b8d..4be8d04 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1550,7 +1550,6 @@
 };
 
 static struct Qdisc_ops htb_qdisc_ops __read_mostly = {
-	.next		=	NULL,
 	.cl_ops		=	&htb_class_ops,
 	.id		=	"htb",
 	.priv_size	=	sizeof(struct htb_sched),
@@ -1561,7 +1560,6 @@
 	.init		=	htb_init,
 	.reset		=	htb_reset,
 	.destroy	=	htb_destroy,
-	.change		=	NULL /* htb_change */,
 	.dump		=	htb_dump,
 	.owner		=	THIS_MODULE,
 };
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 0f41b05..5027b83 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -490,7 +490,7 @@
 			  __func__, &fl.fl4_dst, &fl.fl4_src);
 
 	if (!ip_route_output_key(&init_net, &rt, &fl)) {
-		dst = &rt->u.dst;
+		dst = &rt->dst;
 	}
 
 	/* If there is no association or if a source address is passed, no
@@ -534,7 +534,7 @@
 			fl.fl4_src = laddr->a.v4.sin_addr.s_addr;
 			fl.fl_ip_sport = laddr->a.v4.sin_port;
 			if (!ip_route_output_key(&init_net, &rt, &fl)) {
-				dst = &rt->u.dst;
+				dst = &rt->dst;
 				goto out_unlock;
 			}
 		}
@@ -1002,7 +1002,8 @@
 static inline int init_sctp_mibs(void)
 {
 	return snmp_mib_init((void __percpu **)sctp_statistics,
-			     sizeof(struct sctp_mib));
+			     sizeof(struct sctp_mib),
+			     __alignof__(struct sctp_mib));
 }
 
 static inline void cleanup_sctp_mibs(void)
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index bd2a50b..246f929 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1817,7 +1817,7 @@
 struct __sctp_missing {
 	__be32 num_missing;
 	__be16 type;
-}  __attribute__((packed));
+}  __packed;
 
 /*
  * Report a missing mandatory parameter.
diff --git a/net/socket.c b/net/socket.c
index 367d547..2270b94 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -124,7 +124,7 @@
 static ssize_t sock_sendpage(struct file *file, struct page *page,
 			     int offset, size_t size, loff_t *ppos, int more);
 static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
-			        struct pipe_inode_info *pipe, size_t len,
+				struct pipe_inode_info *pipe, size_t len,
 				unsigned int flags);
 
 /*
@@ -162,7 +162,7 @@
  *	Statistics counters of the socket lists
  */
 
-static DEFINE_PER_CPU(int, sockets_in_use) = 0;
+static DEFINE_PER_CPU(int, sockets_in_use);
 
 /*
  * Support routines.
@@ -170,15 +170,6 @@
  * divide and look after the messy bits.
  */
 
-#define MAX_SOCK_ADDR	128		/* 108 for Unix domain -
-					   16 for IP, 16 for IPX,
-					   24 for IPv6,
-					   about 80 for AX.25
-					   must be at least one bigger than
-					   the AF_UNIX size (see net/unix/af_unix.c
-					   :unix_mkname()).
-					 */
-
 /**
  *	move_addr_to_kernel	-	copy a socket address into kernel space
  *	@uaddr: Address in user space
@@ -309,9 +300,9 @@
 }
 
 static const struct super_operations sockfs_ops = {
-	.alloc_inode =	sock_alloc_inode,
-	.destroy_inode =sock_destroy_inode,
-	.statfs =	simple_statfs,
+	.alloc_inode	= sock_alloc_inode,
+	.destroy_inode	= sock_destroy_inode,
+	.statfs		= simple_statfs,
 };
 
 static int sockfs_get_sb(struct file_system_type *fs_type,
@@ -411,6 +402,7 @@
 
 	return fd;
 }
+EXPORT_SYMBOL(sock_map_fd);
 
 static struct socket *sock_from_file(struct file *file, int *err)
 {
@@ -422,7 +414,7 @@
 }
 
 /**
- *	sockfd_lookup	- 	Go from a file number to its socket slot
+ *	sockfd_lookup - Go from a file number to its socket slot
  *	@fd: file handle
  *	@err: pointer to an error code return
  *
@@ -450,6 +442,7 @@
 		fput(file);
 	return sock;
 }
+EXPORT_SYMBOL(sockfd_lookup);
 
 static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
 {
@@ -540,6 +533,7 @@
 	}
 	sock->file = NULL;
 }
+EXPORT_SYMBOL(sock_release);
 
 int sock_tx_timestamp(struct msghdr *msg, struct sock *sk,
 		      union skb_shared_tx *shtx)
@@ -586,6 +580,7 @@
 		ret = wait_on_sync_kiocb(&iocb);
 	return ret;
 }
+EXPORT_SYMBOL(sock_sendmsg);
 
 int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
 		   struct kvec *vec, size_t num, size_t size)
@@ -604,6 +599,7 @@
 	set_fs(oldfs);
 	return result;
 }
+EXPORT_SYMBOL(kernel_sendmsg);
 
 static int ktime2ts(ktime_t kt, struct timespec *ts)
 {
@@ -664,7 +660,6 @@
 		put_cmsg(msg, SOL_SOCKET,
 			 SCM_TIMESTAMPING, sizeof(ts), &ts);
 }
-
 EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
 
 inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
@@ -720,6 +715,7 @@
 		ret = wait_on_sync_kiocb(&iocb);
 	return ret;
 }
+EXPORT_SYMBOL(sock_recvmsg);
 
 static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg,
 			      size_t size, int flags)
@@ -752,6 +748,7 @@
 	set_fs(oldfs);
 	return result;
 }
+EXPORT_SYMBOL(kernel_recvmsg);
 
 static void sock_aio_dtor(struct kiocb *iocb)
 {
@@ -774,7 +771,7 @@
 }
 
 static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
-			        struct pipe_inode_info *pipe, size_t len,
+				struct pipe_inode_info *pipe, size_t len,
 				unsigned int flags)
 {
 	struct socket *sock = file->private_data;
@@ -887,7 +884,7 @@
  */
 
 static DEFINE_MUTEX(br_ioctl_mutex);
-static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg) = NULL;
+static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg);
 
 void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *))
 {
@@ -895,7 +892,6 @@
 	br_ioctl_hook = hook;
 	mutex_unlock(&br_ioctl_mutex);
 }
-
 EXPORT_SYMBOL(brioctl_set);
 
 static DEFINE_MUTEX(vlan_ioctl_mutex);
@@ -907,7 +903,6 @@
 	vlan_ioctl_hook = hook;
 	mutex_unlock(&vlan_ioctl_mutex);
 }
-
 EXPORT_SYMBOL(vlan_ioctl_set);
 
 static DEFINE_MUTEX(dlci_ioctl_mutex);
@@ -919,7 +914,6 @@
 	dlci_ioctl_hook = hook;
 	mutex_unlock(&dlci_ioctl_mutex);
 }
-
 EXPORT_SYMBOL(dlci_ioctl_set);
 
 static long sock_do_ioctl(struct net *net, struct socket *sock,
@@ -1047,6 +1041,7 @@
 	sock = NULL;
 	goto out;
 }
+EXPORT_SYMBOL(sock_create_lite);
 
 /* No kernel lock held - perfect */
 static unsigned int sock_poll(struct file *file, poll_table *wait)
@@ -1147,6 +1142,7 @@
 	rcu_read_unlock();
 	return 0;
 }
+EXPORT_SYMBOL(sock_wake_async);
 
 static int __sock_create(struct net *net, int family, int type, int protocol,
 			 struct socket **res, int kern)
@@ -1265,11 +1261,13 @@
 {
 	return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
 }
+EXPORT_SYMBOL(sock_create);
 
 int sock_create_kern(int family, int type, int protocol, struct socket **res)
 {
 	return __sock_create(&init_net, family, type, protocol, res, 1);
 }
+EXPORT_SYMBOL(sock_create_kern);
 
 SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
 {
@@ -1474,7 +1472,8 @@
 		goto out;
 
 	err = -ENFILE;
-	if (!(newsock = sock_alloc()))
+	newsock = sock_alloc();
+	if (!newsock)
 		goto out_put;
 
 	newsock->type = sock->type;
@@ -1861,8 +1860,7 @@
 	if (MSG_CMSG_COMPAT & flags) {
 		if (get_compat_msghdr(&msg_sys, msg_compat))
 			return -EFAULT;
-	}
-	else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
+	} else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
 		return -EFAULT;
 
 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
@@ -1964,8 +1962,7 @@
 	if (MSG_CMSG_COMPAT & flags) {
 		if (get_compat_msghdr(msg_sys, msg_compat))
 			return -EFAULT;
-	}
-	else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
+	} else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
 		return -EFAULT;
 
 	err = -EMSGSIZE;
@@ -2191,10 +2188,10 @@
 /* Argument list sizes for sys_socketcall */
 #define AL(x) ((x) * sizeof(unsigned long))
 static const unsigned char nargs[20] = {
-	AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
-	AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
-	AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
-	AL(4),AL(5)
+	AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
+	AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
+	AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
+	AL(4), AL(5)
 };
 
 #undef AL
@@ -2340,6 +2337,7 @@
 	printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family);
 	return err;
 }
+EXPORT_SYMBOL(sock_register);
 
 /**
  *	sock_unregister - remove a protocol handler
@@ -2366,6 +2364,7 @@
 
 	printk(KERN_INFO "NET: Unregistered protocol family %d\n", family);
 }
+EXPORT_SYMBOL(sock_unregister);
 
 static int __init sock_init(void)
 {
@@ -2395,6 +2394,10 @@
 	netfilter_init();
 #endif
 
+#ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
+	skb_timestamping_init();
+#endif
+
 	return 0;
 }
 
@@ -2490,13 +2493,13 @@
 		ifc.ifc_req = NULL;
 		uifc = compat_alloc_user_space(sizeof(struct ifconf));
 	} else {
-		size_t len =((ifc32.ifc_len / sizeof (struct compat_ifreq)) + 1) *
-			sizeof (struct ifreq);
+		size_t len = ((ifc32.ifc_len / sizeof(struct compat_ifreq)) + 1) *
+			sizeof(struct ifreq);
 		uifc = compat_alloc_user_space(sizeof(struct ifconf) + len);
 		ifc.ifc_len = len;
 		ifr = ifc.ifc_req = (void __user *)(uifc + 1);
 		ifr32 = compat_ptr(ifc32.ifcbuf);
-		for (i = 0; i < ifc32.ifc_len; i += sizeof (struct compat_ifreq)) {
+		for (i = 0; i < ifc32.ifc_len; i += sizeof(struct compat_ifreq)) {
 			if (copy_in_user(ifr, ifr32, sizeof(struct compat_ifreq)))
 				return -EFAULT;
 			ifr++;
@@ -2516,9 +2519,9 @@
 	ifr = ifc.ifc_req;
 	ifr32 = compat_ptr(ifc32.ifcbuf);
 	for (i = 0, j = 0;
-             i + sizeof (struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len;
-	     i += sizeof (struct compat_ifreq), j += sizeof (struct ifreq)) {
-		if (copy_in_user(ifr32, ifr, sizeof (struct compat_ifreq)))
+	     i + sizeof(struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len;
+	     i += sizeof(struct compat_ifreq), j += sizeof(struct ifreq)) {
+		if (copy_in_user(ifr32, ifr, sizeof(struct compat_ifreq)))
 			return -EFAULT;
 		ifr32++;
 		ifr++;
@@ -2567,7 +2570,7 @@
 	compat_uptr_t uptr32;
 	struct ifreq __user *uifr;
 
-	uifr = compat_alloc_user_space(sizeof (*uifr));
+	uifr = compat_alloc_user_space(sizeof(*uifr));
 	if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
 		return -EFAULT;
 
@@ -2601,9 +2604,9 @@
 			return -EFAULT;
 
 		old_fs = get_fs();
-		set_fs (KERNEL_DS);
+		set_fs(KERNEL_DS);
 		err = dev_ioctl(net, cmd, &kifr);
-		set_fs (old_fs);
+		set_fs(old_fs);
 
 		return err;
 	case SIOCBONDSLAVEINFOQUERY:
@@ -2710,9 +2713,9 @@
 		return -EFAULT;
 
 	old_fs = get_fs();
-	set_fs (KERNEL_DS);
+	set_fs(KERNEL_DS);
 	err = dev_ioctl(net, cmd, (void __user *)&ifr);
-	set_fs (old_fs);
+	set_fs(old_fs);
 
 	if (cmd == SIOCGIFMAP && !err) {
 		err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name));
@@ -2734,7 +2737,7 @@
 	compat_uptr_t uptr32;
 	struct ifreq __user *uifr;
 
-	uifr = compat_alloc_user_space(sizeof (*uifr));
+	uifr = compat_alloc_user_space(sizeof(*uifr));
 	if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
 		return -EFAULT;
 
@@ -2750,20 +2753,20 @@
 }
 
 struct rtentry32 {
-	u32   		rt_pad1;
+	u32		rt_pad1;
 	struct sockaddr rt_dst;         /* target address               */
 	struct sockaddr rt_gateway;     /* gateway addr (RTF_GATEWAY)   */
 	struct sockaddr rt_genmask;     /* target network mask (IP)     */
-	unsigned short  rt_flags;
-	short           rt_pad2;
-	u32   		rt_pad3;
-	unsigned char   rt_tos;
-	unsigned char   rt_class;
-	short           rt_pad4;
-	short           rt_metric;      /* +1 for binary compatibility! */
+	unsigned short	rt_flags;
+	short		rt_pad2;
+	u32		rt_pad3;
+	unsigned char	rt_tos;
+	unsigned char	rt_class;
+	short		rt_pad4;
+	short		rt_metric;      /* +1 for binary compatibility! */
 	/* char * */ u32 rt_dev;        /* forcing the device at add    */
-	u32   		rt_mtu;         /* per route MTU/Window         */
-	u32   		rt_window;      /* Window clamping              */
+	u32		rt_mtu;         /* per route MTU/Window         */
+	u32		rt_window;      /* Window clamping              */
 	unsigned short  rt_irtt;        /* Initial RTT                  */
 };
 
@@ -2793,29 +2796,29 @@
 
 	if (sock && sock->sk && sock->sk->sk_family == AF_INET6) { /* ipv6 */
 		struct in6_rtmsg32 __user *ur6 = argp;
-		ret = copy_from_user (&r6.rtmsg_dst, &(ur6->rtmsg_dst),
+		ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst),
 			3 * sizeof(struct in6_addr));
-		ret |= __get_user (r6.rtmsg_type, &(ur6->rtmsg_type));
-		ret |= __get_user (r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len));
-		ret |= __get_user (r6.rtmsg_src_len, &(ur6->rtmsg_src_len));
-		ret |= __get_user (r6.rtmsg_metric, &(ur6->rtmsg_metric));
-		ret |= __get_user (r6.rtmsg_info, &(ur6->rtmsg_info));
-		ret |= __get_user (r6.rtmsg_flags, &(ur6->rtmsg_flags));
-		ret |= __get_user (r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex));
+		ret |= __get_user(r6.rtmsg_type, &(ur6->rtmsg_type));
+		ret |= __get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len));
+		ret |= __get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len));
+		ret |= __get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric));
+		ret |= __get_user(r6.rtmsg_info, &(ur6->rtmsg_info));
+		ret |= __get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags));
+		ret |= __get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex));
 
 		r = (void *) &r6;
 	} else { /* ipv4 */
 		struct rtentry32 __user *ur4 = argp;
-		ret = copy_from_user (&r4.rt_dst, &(ur4->rt_dst),
+		ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst),
 					3 * sizeof(struct sockaddr));
-		ret |= __get_user (r4.rt_flags, &(ur4->rt_flags));
-		ret |= __get_user (r4.rt_metric, &(ur4->rt_metric));
-		ret |= __get_user (r4.rt_mtu, &(ur4->rt_mtu));
-		ret |= __get_user (r4.rt_window, &(ur4->rt_window));
-		ret |= __get_user (r4.rt_irtt, &(ur4->rt_irtt));
-		ret |= __get_user (rtdev, &(ur4->rt_dev));
+		ret |= __get_user(r4.rt_flags, &(ur4->rt_flags));
+		ret |= __get_user(r4.rt_metric, &(ur4->rt_metric));
+		ret |= __get_user(r4.rt_mtu, &(ur4->rt_mtu));
+		ret |= __get_user(r4.rt_window, &(ur4->rt_window));
+		ret |= __get_user(r4.rt_irtt, &(ur4->rt_irtt));
+		ret |= __get_user(rtdev, &(ur4->rt_dev));
 		if (rtdev) {
-			ret |= copy_from_user (devname, compat_ptr(rtdev), 15);
+			ret |= copy_from_user(devname, compat_ptr(rtdev), 15);
 			r4.rt_dev = devname; devname[15] = 0;
 		} else
 			r4.rt_dev = NULL;
@@ -2828,9 +2831,9 @@
 		goto out;
 	}
 
-	set_fs (KERNEL_DS);
+	set_fs(KERNEL_DS);
 	ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r);
-	set_fs (old_fs);
+	set_fs(old_fs);
 
 out:
 	return ret;
@@ -2993,11 +2996,13 @@
 {
 	return sock->ops->bind(sock, addr, addrlen);
 }
+EXPORT_SYMBOL(kernel_bind);
 
 int kernel_listen(struct socket *sock, int backlog)
 {
 	return sock->ops->listen(sock, backlog);
 }
+EXPORT_SYMBOL(kernel_listen);
 
 int kernel_accept(struct socket *sock, struct socket **newsock, int flags)
 {
@@ -3022,24 +3027,28 @@
 done:
 	return err;
 }
+EXPORT_SYMBOL(kernel_accept);
 
 int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen,
 		   int flags)
 {
 	return sock->ops->connect(sock, addr, addrlen, flags);
 }
+EXPORT_SYMBOL(kernel_connect);
 
 int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
 			 int *addrlen)
 {
 	return sock->ops->getname(sock, addr, addrlen, 0);
 }
+EXPORT_SYMBOL(kernel_getsockname);
 
 int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
 			 int *addrlen)
 {
 	return sock->ops->getname(sock, addr, addrlen, 1);
 }
+EXPORT_SYMBOL(kernel_getpeername);
 
 int kernel_getsockopt(struct socket *sock, int level, int optname,
 			char *optval, int *optlen)
@@ -3056,6 +3065,7 @@
 	set_fs(oldfs);
 	return err;
 }
+EXPORT_SYMBOL(kernel_getsockopt);
 
 int kernel_setsockopt(struct socket *sock, int level, int optname,
 			char *optval, unsigned int optlen)
@@ -3072,6 +3082,7 @@
 	set_fs(oldfs);
 	return err;
 }
+EXPORT_SYMBOL(kernel_setsockopt);
 
 int kernel_sendpage(struct socket *sock, struct page *page, int offset,
 		    size_t size, int flags)
@@ -3083,6 +3094,7 @@
 
 	return sock_no_sendpage(sock, page, offset, size, flags);
 }
+EXPORT_SYMBOL(kernel_sendpage);
 
 int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
 {
@@ -3095,33 +3107,10 @@
 
 	return err;
 }
+EXPORT_SYMBOL(kernel_sock_ioctl);
 
 int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how)
 {
 	return sock->ops->shutdown(sock, how);
 }
-
-EXPORT_SYMBOL(sock_create);
-EXPORT_SYMBOL(sock_create_kern);
-EXPORT_SYMBOL(sock_create_lite);
-EXPORT_SYMBOL(sock_map_fd);
-EXPORT_SYMBOL(sock_recvmsg);
-EXPORT_SYMBOL(sock_register);
-EXPORT_SYMBOL(sock_release);
-EXPORT_SYMBOL(sock_sendmsg);
-EXPORT_SYMBOL(sock_unregister);
-EXPORT_SYMBOL(sock_wake_async);
-EXPORT_SYMBOL(sockfd_lookup);
-EXPORT_SYMBOL(kernel_sendmsg);
-EXPORT_SYMBOL(kernel_recvmsg);
-EXPORT_SYMBOL(kernel_bind);
-EXPORT_SYMBOL(kernel_listen);
-EXPORT_SYMBOL(kernel_accept);
-EXPORT_SYMBOL(kernel_connect);
-EXPORT_SYMBOL(kernel_getsockname);
-EXPORT_SYMBOL(kernel_getpeername);
-EXPORT_SYMBOL(kernel_getsockopt);
-EXPORT_SYMBOL(kernel_setsockopt);
-EXPORT_SYMBOL(kernel_sendpage);
-EXPORT_SYMBOL(kernel_sock_ioctl);
 EXPORT_SYMBOL(kernel_sock_shutdown);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index fef2cc5..4414a18 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -282,7 +282,7 @@
 	return s;
 }
 
-static struct sock *unix_find_socket_byinode(struct net *net, struct inode *i)
+static struct sock *unix_find_socket_byinode(struct inode *i)
 {
 	struct sock *s;
 	struct hlist_node *node;
@@ -292,9 +292,6 @@
 		    &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) {
 		struct dentry *dentry = unix_sk(s)->dentry;
 
-		if (!net_eq(sock_net(s), net))
-			continue;
-
 		if (dentry && dentry->d_inode == i) {
 			sock_hold(s);
 			goto found;
@@ -450,11 +447,31 @@
 	return 0;
 }
 
+static void init_peercred(struct sock *sk)
+{
+	put_pid(sk->sk_peer_pid);
+	if (sk->sk_peer_cred)
+		put_cred(sk->sk_peer_cred);
+	sk->sk_peer_pid  = get_pid(task_tgid(current));
+	sk->sk_peer_cred = get_current_cred();
+}
+
+static void copy_peercred(struct sock *sk, struct sock *peersk)
+{
+	put_pid(sk->sk_peer_pid);
+	if (sk->sk_peer_cred)
+		put_cred(sk->sk_peer_cred);
+	sk->sk_peer_pid  = get_pid(peersk->sk_peer_pid);
+	sk->sk_peer_cred = get_cred(peersk->sk_peer_cred);
+}
+
 static int unix_listen(struct socket *sock, int backlog)
 {
 	int err;
 	struct sock *sk = sock->sk;
 	struct unix_sock *u = unix_sk(sk);
+	struct pid *old_pid = NULL;
+	const struct cred *old_cred = NULL;
 
 	err = -EOPNOTSUPP;
 	if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET)
@@ -470,12 +487,14 @@
 	sk->sk_max_ack_backlog	= backlog;
 	sk->sk_state		= TCP_LISTEN;
 	/* set credentials so connect can copy them */
-	sk->sk_peercred.pid	= task_tgid_vnr(current);
-	current_euid_egid(&sk->sk_peercred.uid, &sk->sk_peercred.gid);
+	init_peercred(sk);
 	err = 0;
 
 out_unlock:
 	unix_state_unlock(sk);
+	put_pid(old_pid);
+	if (old_cred)
+		put_cred(old_cred);
 out:
 	return err;
 }
@@ -736,7 +755,7 @@
 		err = -ECONNREFUSED;
 		if (!S_ISSOCK(inode->i_mode))
 			goto put_fail;
-		u = unix_find_socket_byinode(net, inode);
+		u = unix_find_socket_byinode(inode);
 		if (!u)
 			goto put_fail;
 
@@ -1140,8 +1159,7 @@
 	unix_peer(newsk)	= sk;
 	newsk->sk_state		= TCP_ESTABLISHED;
 	newsk->sk_type		= sk->sk_type;
-	newsk->sk_peercred.pid	= task_tgid_vnr(current);
-	current_euid_egid(&newsk->sk_peercred.uid, &newsk->sk_peercred.gid);
+	init_peercred(newsk);
 	newu = unix_sk(newsk);
 	newsk->sk_wq		= &newu->peer_wq;
 	otheru = unix_sk(other);
@@ -1157,7 +1175,7 @@
 	}
 
 	/* Set credentials */
-	sk->sk_peercred = other->sk_peercred;
+	copy_peercred(sk, other);
 
 	sock->state	= SS_CONNECTED;
 	sk->sk_state	= TCP_ESTABLISHED;
@@ -1199,10 +1217,8 @@
 	sock_hold(skb);
 	unix_peer(ska) = skb;
 	unix_peer(skb) = ska;
-	ska->sk_peercred.pid = skb->sk_peercred.pid = task_tgid_vnr(current);
-	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;
+	init_peercred(ska);
+	init_peercred(skb);
 
 	if (ska->sk_type != SOCK_DGRAM) {
 		ska->sk_state = TCP_ESTABLISHED;
@@ -1297,18 +1313,20 @@
 	int i;
 
 	scm->fp = UNIXCB(skb).fp;
-	skb->destructor = sock_wfree;
 	UNIXCB(skb).fp = NULL;
 
 	for (i = scm->fp->count-1; i >= 0; i--)
 		unix_notinflight(scm->fp->fp[i]);
 }
 
-static void unix_destruct_fds(struct sk_buff *skb)
+static void unix_destruct_scm(struct sk_buff *skb)
 {
 	struct scm_cookie scm;
 	memset(&scm, 0, sizeof(scm));
-	unix_detach_fds(&scm, skb);
+	scm.pid  = UNIXCB(skb).pid;
+	scm.cred = UNIXCB(skb).cred;
+	if (UNIXCB(skb).fp)
+		unix_detach_fds(&scm, skb);
 
 	/* Alas, it calls VFS */
 	/* So fscking what? fput() had been SMP-safe since the last Summer */
@@ -1331,10 +1349,22 @@
 
 	for (i = scm->fp->count-1; i >= 0; i--)
 		unix_inflight(scm->fp->fp[i]);
-	skb->destructor = unix_destruct_fds;
 	return 0;
 }
 
+static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
+{
+	int err = 0;
+	UNIXCB(skb).pid  = get_pid(scm->pid);
+	UNIXCB(skb).cred = get_cred(scm->cred);
+	UNIXCB(skb).fp = NULL;
+	if (scm->fp && send_fds)
+		err = unix_attach_fds(scm, skb);
+
+	skb->destructor = unix_destruct_scm;
+	return err;
+}
+
 /*
  *	Send AF_UNIX data.
  */
@@ -1391,12 +1421,9 @@
 	if (skb == NULL)
 		goto out;
 
-	memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
-	if (siocb->scm->fp) {
-		err = unix_attach_fds(siocb->scm, skb);
-		if (err)
-			goto out_free;
-	}
+	err = unix_scm_to_skb(siocb->scm, skb, true);
+	if (err)
+		goto out_free;
 	unix_get_secdata(siocb->scm, skb);
 
 	skb_reset_transport_header(skb);
@@ -1566,16 +1593,14 @@
 		 */
 		size = min_t(int, size, skb_tailroom(skb));
 
-		memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
+
 		/* Only send the fds in the first buffer */
-		if (siocb->scm->fp && !fds_sent) {
-			err = unix_attach_fds(siocb->scm, skb);
-			if (err) {
-				kfree_skb(skb);
-				goto out_err;
-			}
-			fds_sent = true;
+		err = unix_scm_to_skb(siocb->scm, skb, !fds_sent);
+		if (err) {
+			kfree_skb(skb);
+			goto out_err;
 		}
+		fds_sent = true;
 
 		err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
 		if (err) {
@@ -1692,7 +1717,7 @@
 		siocb->scm = &tmp_scm;
 		memset(&tmp_scm, 0, sizeof(tmp_scm));
 	}
-	siocb->scm->creds = *UNIXCREDS(skb);
+	scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
 	unix_set_secdata(siocb->scm, skb);
 
 	if (!(flags & MSG_PEEK)) {
@@ -1841,14 +1866,14 @@
 
 		if (check_creds) {
 			/* Never glue messages from different writers */
-			if (memcmp(UNIXCREDS(skb), &siocb->scm->creds,
-				   sizeof(siocb->scm->creds)) != 0) {
+			if ((UNIXCB(skb).pid  != siocb->scm->pid) ||
+			    (UNIXCB(skb).cred != siocb->scm->cred)) {
 				skb_queue_head(&sk->sk_receive_queue, skb);
 				break;
 			}
 		} else {
 			/* Copy credentials */
-			siocb->scm->creds = *UNIXCREDS(skb);
+			scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
 			check_creds = 1;
 		}
 
@@ -1881,7 +1906,7 @@
 				break;
 			}
 
-			kfree_skb(skb);
+			consume_skb(skb);
 
 			if (siocb->scm->fp)
 				break;
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 258daa8..2bf2340 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -48,7 +48,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>	/* support for loadable modules */
 #include <linux/slab.h>		/* kmalloc(), kfree() */
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/mm.h>
 #include <linux/string.h>	/* inline mem*, str* functions */
 
@@ -71,6 +71,7 @@
  *	WAN device IOCTL handlers
  */
 
+static DEFINE_MUTEX(wanrouter_mutex);
 static int wanrouter_device_setup(struct wan_device *wandev,
 				  wandev_conf_t __user *u_conf);
 static int wanrouter_device_stat(struct wan_device *wandev,
@@ -376,7 +377,7 @@
 	if (wandev->magic != ROUTER_MAGIC)
 		return -EINVAL;
 
-	lock_kernel();
+	mutex_lock(&wanrouter_mutex);
 	switch (cmd) {
 	case ROUTER_SETUP:
 		err = wanrouter_device_setup(wandev, data);
@@ -408,7 +409,7 @@
 			err = wandev->ioctl(wandev, cmd, arg);
 		else err = -EINVAL;
 	}
-	unlock_kernel();
+	mutex_unlock(&wanrouter_mutex);
 	return err;
 }
 
diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
index c44d96b..11f25c7 100644
--- a/net/wanrouter/wanproc.c
+++ b/net/wanrouter/wanproc.c
@@ -27,7 +27,7 @@
 #include <linux/module.h>
 #include <linux/wanrouter.h>	/* WAN router API definitions */
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <net/net_namespace.h>
 #include <asm/io.h>
@@ -66,6 +66,7 @@
  *	/proc/net/router
  */
 
+static DEFINE_MUTEX(config_mutex);
 static struct proc_dir_entry *proc_router;
 
 /* Strings */
@@ -85,7 +86,7 @@
 	struct wan_device *wandev;
 	loff_t l = *pos;
 
-	lock_kernel();
+	mutex_lock(&config_mutex);
 	if (!l--)
 		return SEQ_START_TOKEN;
 	for (wandev = wanrouter_router_devlist; l-- && wandev;
@@ -104,7 +105,7 @@
 static void r_stop(struct seq_file *m, void *v)
 	__releases(kernel_lock)
 {
-	unlock_kernel();
+	mutex_unlock(&config_mutex);
 }
 
 static int config_show(struct seq_file *m, void *v)
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index b01a6f6..d0c92dd 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -35,8 +35,9 @@
 		if (!ht_cap->ht_supported)
 			return NULL;
 
-		if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
-		    ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
+		if (channel_type != NL80211_CHAN_HT20 &&
+		    (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
+		    ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
 			return NULL;
 	}
 
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 37d0e0a..541e2ff 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -472,24 +472,22 @@
 	/* check and set up bitrates */
 	ieee80211_set_bitrate_flags(wiphy);
 
+	mutex_lock(&cfg80211_mutex);
+
 	res = device_add(&rdev->wiphy.dev);
 	if (res)
-		return res;
+		goto out_unlock;
 
 	res = rfkill_register(rdev->rfkill);
 	if (res)
 		goto out_rm_dev;
 
-	mutex_lock(&cfg80211_mutex);
-
 	/* set up regulatory info */
 	wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
 
 	list_add_rcu(&rdev->list, &cfg80211_rdev_list);
 	cfg80211_rdev_list_generation++;
 
-	mutex_unlock(&cfg80211_mutex);
-
 	/* add to debugfs */
 	rdev->wiphy.debugfsdir =
 		debugfs_create_dir(wiphy_name(&rdev->wiphy),
@@ -509,11 +507,15 @@
 	}
 
 	cfg80211_debugfs_rdev_add(rdev);
+	mutex_unlock(&cfg80211_mutex);
 
 	return 0;
 
- out_rm_dev:
+out_rm_dev:
 	device_del(&rdev->wiphy.dev);
+
+out_unlock:
+	mutex_unlock(&cfg80211_mutex);
 	return res;
 }
 EXPORT_SYMBOL(wiphy_register);
@@ -894,7 +896,7 @@
 }
 subsys_initcall(cfg80211_init);
 
-static void cfg80211_exit(void)
+static void __exit cfg80211_exit(void)
 {
 	debugfs_remove(ieee80211_debugfs_dir);
 	nl80211_exit();
@@ -905,3 +907,52 @@
 	destroy_workqueue(cfg80211_wq);
 }
 module_exit(cfg80211_exit);
+
+static int ___wiphy_printk(const char *level, const struct wiphy *wiphy,
+			   struct va_format *vaf)
+{
+	if (!wiphy)
+		return printk("%s(NULL wiphy *): %pV", level, vaf);
+
+	return printk("%s%s: %pV", level, wiphy_name(wiphy), vaf);
+}
+
+int __wiphy_printk(const char *level, const struct wiphy *wiphy,
+		   const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+	int r;
+
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	r = ___wiphy_printk(level, wiphy, &vaf);
+	va_end(args);
+
+	return r;
+}
+EXPORT_SYMBOL(__wiphy_printk);
+
+#define define_wiphy_printk_level(func, kern_level)		\
+int func(const struct wiphy *wiphy, const char *fmt, ...)	\
+{								\
+	struct va_format vaf;					\
+	va_list args;						\
+	int r;							\
+								\
+	va_start(args, fmt);					\
+								\
+	vaf.fmt = fmt;						\
+	vaf.va = &args;						\
+								\
+	r = ___wiphy_printk(kern_level, wiphy, &vaf);		\
+	va_end(args);						\
+								\
+	return r;						\
+}								\
+EXPORT_SYMBOL(func);
+
+define_wiphy_printk_level(wiphy_debug, KERN_DEBUG);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index ae930ac..63d57ae 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -339,6 +339,7 @@
 			 struct net_device *dev,
 			 struct ieee80211_channel *chan,
 			 enum nl80211_channel_type channel_type,
+			 bool channel_type_valid,
 			 const u8 *buf, size_t len, u64 *cookie);
 
 /* SME */
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk
index 3cc9e69..53c143f 100644
--- a/net/wireless/genregdb.awk
+++ b/net/wireless/genregdb.awk
@@ -21,6 +21,7 @@
 	print ""
 	print "#include <linux/nl80211.h>"
 	print "#include <net/cfg80211.h>"
+	print "#include \"regdb.h\""
 	print ""
 	regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n"
 }
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index adcabba..27a8ce9 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -247,8 +247,10 @@
 	if (!netif_running(wdev->netdev))
 		return 0;
 
-	if (wdev->wext.keys)
+	if (wdev->wext.keys) {
 		wdev->wext.keys->def = wdev->wext.default_key;
+		wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key;
+	}
 
 	wdev->wext.ibss.privacy = wdev->wext.default_key != -1;
 
diff --git a/net/wireless/lib80211_crypt_ccmp.c b/net/wireless/lib80211_crypt_ccmp.c
index b7fa31d..dacb3b4 100644
--- a/net/wireless/lib80211_crypt_ccmp.c
+++ b/net/wireless/lib80211_crypt_ccmp.c
@@ -467,7 +467,6 @@
 	.name = "CCMP",
 	.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,
diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c
index 8cbdb32..0fe4051 100644
--- a/net/wireless/lib80211_crypt_tkip.c
+++ b/net/wireless/lib80211_crypt_tkip.c
@@ -578,7 +578,7 @@
 	}
 
 	if (ieee80211_is_data_qos(hdr11->frame_control)) {
-		hdr[12] = le16_to_cpu(*ieee80211_get_qos_ctl(hdr11))
+		hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11)))
 			& IEEE80211_QOS_CTL_TID_MASK;
 	} else
 		hdr[12] = 0;		/* priority */
@@ -757,7 +757,6 @@
 	.name = "TKIP",
 	.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,
diff --git a/net/wireless/lib80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c
index 6d41e05..e2e8887 100644
--- a/net/wireless/lib80211_crypt_wep.c
+++ b/net/wireless/lib80211_crypt_wep.c
@@ -269,7 +269,6 @@
 	.name = "WEP",
 	.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,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 48ead6f..e74a1a2 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -44,10 +44,10 @@
 		}
 	}
 
-	WARN_ON(!done);
-
-	nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
-	cfg80211_sme_rx_auth(dev, buf, len);
+	if (done) {
+		nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
+		cfg80211_sme_rx_auth(dev, buf, len);
+	}
 
 	wdev_unlock(wdev);
 }
@@ -827,6 +827,7 @@
 			 struct net_device *dev,
 			 struct ieee80211_channel *chan,
 			 enum nl80211_channel_type channel_type,
+			 bool channel_type_valid,
 			 const u8 *buf, size_t len, u64 *cookie)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -845,8 +846,9 @@
 		if (!wdev->current_bss ||
 		    memcmp(wdev->current_bss->pub.bssid, mgmt->bssid,
 			   ETH_ALEN) != 0 ||
-		    memcmp(wdev->current_bss->pub.bssid, mgmt->da,
-			   ETH_ALEN) != 0)
+		    (wdev->iftype == NL80211_IFTYPE_STATION &&
+		     memcmp(wdev->current_bss->pub.bssid, mgmt->da,
+			    ETH_ALEN) != 0))
 			return -ENOTCONN;
 	}
 
@@ -855,7 +857,7 @@
 
 	/* Transmit the Action frame as requested by user space */
 	return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type,
-				 buf, len, cookie);
+				 channel_type_valid, buf, len, cookie);
 }
 
 bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index db71150..37902a5 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -153,6 +153,9 @@
 	[NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
 	[NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
 	[NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
+
+	[NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
+	[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
 };
 
 /* policy for the attributes */
@@ -869,6 +872,34 @@
 			goto bad_res;
 	}
 
+	if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
+		enum nl80211_tx_power_setting type;
+		int idx, mbm = 0;
+
+		if (!rdev->ops->set_tx_power) {
+			result = -EOPNOTSUPP;
+			goto bad_res;
+		}
+
+		idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
+		type = nla_get_u32(info->attrs[idx]);
+
+		if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
+		    (type != NL80211_TX_POWER_AUTOMATIC)) {
+			result = -EINVAL;
+			goto bad_res;
+		}
+
+		if (type != NL80211_TX_POWER_AUTOMATIC) {
+			idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
+			mbm = nla_get_u32(info->attrs[idx]);
+		}
+
+		result = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm);
+		if (result)
+			goto bad_res;
+	}
+
 	changed = 0;
 
 	if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
@@ -1107,7 +1138,7 @@
 			       enum nl80211_iftype iftype)
 {
 	if (!use_4addr) {
-		if (netdev && netdev->br_port)
+		if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT))
 			return -EBUSY;
 		return 0;
 	}
@@ -2738,6 +2769,7 @@
 
  nla_put_failure:
 	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
 	err = -EMSGSIZE;
  out:
 	/* Cleanup */
@@ -2929,6 +2961,7 @@
 
 nla_put_failure:
 	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
 	err = -EMSGSIZE;
 out:
 	mutex_unlock(&cfg80211_mutex);
@@ -3955,6 +3988,55 @@
 		}
 	}
 
+	if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
+		u8 *rates =
+			nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
+		int n_rates =
+			nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
+		struct ieee80211_supported_band *sband =
+			wiphy->bands[ibss.channel->band];
+		int i, j;
+
+		if (n_rates == 0) {
+			err = -EINVAL;
+			goto out;
+		}
+
+		for (i = 0; i < n_rates; i++) {
+			int rate = (rates[i] & 0x7f) * 5;
+			bool found = false;
+
+			for (j = 0; j < sband->n_bitrates; j++) {
+				if (sband->bitrates[j].bitrate == rate) {
+					found = true;
+					ibss.basic_rates |= BIT(j);
+					break;
+				}
+			}
+			if (!found) {
+				err = -EINVAL;
+				goto out;
+			}
+		}
+	} else {
+		/*
+		* If no rates were explicitly configured,
+		* use the mandatory rate set for 11b or
+		* 11a for maximum compatibility.
+		*/
+		struct ieee80211_supported_band *sband =
+			wiphy->bands[ibss.channel->band];
+		int j;
+		u32 flag = ibss.channel->band == IEEE80211_BAND_5GHZ ?
+			IEEE80211_RATE_MANDATORY_A :
+			IEEE80211_RATE_MANDATORY_B;
+
+		for (j = 0; j < sband->n_bitrates; j++) {
+			if (sband->bitrates[j].flags & flag)
+				ibss.basic_rates |= BIT(j);
+		}
+	}
+
 	err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
 
 out:
@@ -4653,7 +4735,8 @@
 	if (err)
 		goto unlock_rtnl;
 
-	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
 		err = -EOPNOTSUPP;
 		goto out;
 	}
@@ -4681,6 +4764,7 @@
 	struct net_device *dev;
 	struct ieee80211_channel *chan;
 	enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+	bool channel_type_valid = false;
 	u32 freq;
 	int err;
 	void *hdr;
@@ -4702,7 +4786,8 @@
 		goto out;
 	}
 
-	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
 		err = -EOPNOTSUPP;
 		goto out;
 	}
@@ -4722,6 +4807,7 @@
 			err = -EINVAL;
 			goto out;
 		}
+		channel_type_valid = true;
 	}
 
 	freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
@@ -4745,6 +4831,7 @@
 		goto free_msg;
 	}
 	err = cfg80211_mlme_action(rdev, dev, chan, channel_type,
+				   channel_type_valid,
 				   nla_data(info->attrs[NL80211_ATTR_FRAME]),
 				   nla_len(info->attrs[NL80211_ATTR_FRAME]),
 				   &cookie);
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 8f0d97d..f180db0 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -67,20 +67,12 @@
 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;
-
-/*
  * Protects static reg.c components:
  *     - cfg80211_world_regdom
  *     - cfg80211_regdom
- *     - country_ie_regdomain
  *     - last_request
  */
-DEFINE_MUTEX(reg_mutex);
+static DEFINE_MUTEX(reg_mutex);
 #define assert_reg_lock() WARN_ON(!mutex_is_locked(&reg_mutex))
 
 /* Used to queue up regulatory hints */
@@ -275,25 +267,6 @@
 	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;
-}
-
 static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
 			 const struct ieee80211_regdomain *src_regd)
 {
@@ -506,471 +479,6 @@
 }
 
 /*
- * This is a work around for sanity checking ieee80211_channel_to_frequency()'s
- * work. ieee80211_channel_to_frequency() can for example currently provide a
- * 2 GHz channel when in fact a 5 GHz channel was desired. An example would be
- * an AP providing channel 8 on a country IE triplet when it sent this on the
- * 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz
- * channel.
- *
- * This can be removed once ieee80211_channel_to_frequency() takes in a band.
- */
-static bool chan_in_band(int chan, enum ieee80211_band band)
-{
-	int center_freq = ieee80211_channel_to_frequency(chan);
-
-	switch (band) {
-	case IEEE80211_BAND_2GHZ:
-		if (center_freq <= 2484)
-			return true;
-		return false;
-	case IEEE80211_BAND_5GHZ:
-		if (center_freq >= 5005)
-			return true;
-		return false;
-	default:
-		return false;
-	}
-}
-
-/*
- * Some APs may send a country IE triplet for each channel they
- * support and while this is completely overkill and silly we still
- * need to support it. We avoid making a single rule for each channel
- * though and to help us with this we use this helper to find the
- * actual subband end channel. These type of country IE triplet
- * scenerios are handled then, all yielding two regulaotry rules from
- * parsing a country IE:
- *
- * [1]
- * [2]
- * [36]
- * [40]
- *
- * [1]
- * [2-4]
- * [5-12]
- * [36]
- * [40-44]
- *
- * [1-4]
- * [5-7]
- * [36-44]
- * [48-64]
- *
- * [36-36]
- * [40-40]
- * [44-44]
- * [48-48]
- * [52-52]
- * [56-56]
- * [60-60]
- * [64-64]
- * [100-100]
- * [104-104]
- * [108-108]
- * [112-112]
- * [116-116]
- * [120-120]
- * [124-124]
- * [128-128]
- * [132-132]
- * [136-136]
- * [140-140]
- *
- * Returns 0 if the IE has been found to be invalid in the middle
- * somewhere.
- */
-static int max_subband_chan(enum ieee80211_band band,
-			    int orig_cur_chan,
-			    int orig_end_channel,
-			    s8 orig_max_power,
-			    u8 **country_ie,
-			    u8 *country_ie_len)
-{
-	u8 *triplets_start = *country_ie;
-	u8 len_at_triplet = *country_ie_len;
-	int end_subband_chan = orig_end_channel;
-
-	/*
-	 * We'll deal with padding for the caller unless
-	 * its not immediate and we don't process any channels
-	 */
-	if (*country_ie_len == 1) {
-		*country_ie += 1;
-		*country_ie_len -= 1;
-		return orig_end_channel;
-	}
-
-	/* Move to the next triplet and then start search */
-	*country_ie += 3;
-	*country_ie_len -= 3;
-
-	if (!chan_in_band(orig_cur_chan, band))
-		return 0;
-
-	while (*country_ie_len >= 3) {
-		int end_channel = 0;
-		struct ieee80211_country_ie_triplet *triplet =
-			(struct ieee80211_country_ie_triplet *) *country_ie;
-		int cur_channel = 0, next_expected_chan;
-
-		/* means last triplet is completely unrelated to this one */
-		if (triplet->ext.reg_extension_id >=
-				IEEE80211_COUNTRY_EXTENSION_ID) {
-			*country_ie -= 3;
-			*country_ie_len += 3;
-			break;
-		}
-
-		if (triplet->chans.first_channel == 0) {
-			*country_ie += 1;
-			*country_ie_len -= 1;
-			if (*country_ie_len != 0)
-				return 0;
-			break;
-		}
-
-		if (triplet->chans.num_channels == 0)
-			return 0;
-
-		/* Monitonically increasing channel order */
-		if (triplet->chans.first_channel <= end_subband_chan)
-			return 0;
-
-		if (!chan_in_band(triplet->chans.first_channel, band))
-			return 0;
-
-		/* 2 GHz */
-		if (triplet->chans.first_channel <= 14) {
-			end_channel = triplet->chans.first_channel +
-				triplet->chans.num_channels - 1;
-		}
-		else {
-			end_channel =  triplet->chans.first_channel +
-				(4 * (triplet->chans.num_channels - 1));
-		}
-
-		if (!chan_in_band(end_channel, band))
-			return 0;
-
-		if (orig_max_power != triplet->chans.max_power) {
-			*country_ie -= 3;
-			*country_ie_len += 3;
-			break;
-		}
-
-		cur_channel = triplet->chans.first_channel;
-
-		/* The key is finding the right next expected channel */
-		if (band == IEEE80211_BAND_2GHZ)
-			next_expected_chan = end_subband_chan + 1;
-		 else
-			next_expected_chan = end_subband_chan + 4;
-
-		if (cur_channel != next_expected_chan) {
-			*country_ie -= 3;
-			*country_ie_len += 3;
-			break;
-		}
-
-		end_subband_chan = end_channel;
-
-		/* Move to the next one */
-		*country_ie += 3;
-		*country_ie_len -= 3;
-
-		/*
-		 * Padding needs to be dealt with if we processed
-		 * some channels.
-		 */
-		if (*country_ie_len == 1) {
-			*country_ie += 1;
-			*country_ie_len -= 1;
-			break;
-		}
-
-		/* If seen, the IE is invalid */
-		if (*country_ie_len == 2)
-			return 0;
-	}
-
-	if (end_subband_chan == orig_end_channel) {
-		*country_ie = triplets_start;
-		*country_ie_len = len_at_triplet;
-		return orig_end_channel;
-	}
-
-	return end_subband_chan;
-}
-
-/*
- * 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(
-				enum ieee80211_band band,
-				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) {
-		int end_channel = 0;
-		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;
-		}
-
-		/*
-		 * APs can add padding to make length divisible
-		 * by two, required by the spec.
-		 */
-		if (triplet->chans.first_channel == 0) {
-			country_ie++;
-			country_ie_len--;
-			/* This is expected to be at the very end only */
-			if (country_ie_len != 0)
-				return NULL;
-			break;
-		}
-
-		if (triplet->chans.num_channels == 0)
-			return NULL;
-
-		if (!chan_in_band(triplet->chans.first_channel, band))
-			return NULL;
-
-		/* 2 GHz */
-		if (band == IEEE80211_BAND_2GHZ)
-			end_channel = triplet->chans.first_channel +
-				triplet->chans.num_channels - 1;
-		else
-			/*
-			 * 5 GHz -- For example in country IEs if the first
-			 * channel given is 36 and the number of channels is 4
-			 * then the individual channel numbers defined for the
-			 * 5 GHz PHY by these parameters are: 36, 40, 44, and 48
-			 * and not 36, 37, 38, 39.
-			 *
-			 * See: http://tinyurl.com/11d-clarification
-			 */
-			end_channel =  triplet->chans.first_channel +
-				(4 * (triplet->chans.num_channels - 1));
-
-		cur_channel = triplet->chans.first_channel;
-
-		/*
-		 * Enhancement for APs that send a triplet for every channel
-		 * or for whatever reason sends triplets with multiple channels
-		 * separated when in fact they should be together.
-		 */
-		end_channel = max_subband_chan(band,
-					       cur_channel,
-					       end_channel,
-					       triplet->chans.max_power,
-					       &country_ie,
-					       &country_ie_len);
-		if (!end_channel)
-			return NULL;
-
-		if (!chan_in_band(end_channel, band))
-			return NULL;
-
-		cur_sub_max_channel = end_channel;
-
-		/* 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;
-
-		num_rules++;
-
-		if (country_ie_len >= 3) {
-			country_ie += 3;
-			country_ie_len -= 3;
-		}
-
-		/*
-		 * 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) {
-		int end_channel = 0;
-		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;
-		}
-
-		if (triplet->chans.first_channel == 0) {
-			country_ie++;
-			country_ie_len--;
-			break;
-		}
-
-		reg_rule = &rd->reg_rules[i];
-		freq_range = &reg_rule->freq_range;
-		power_rule = &reg_rule->power_rule;
-
-		reg_rule->flags = flags;
-
-		/* 2 GHz */
-		if (band == IEEE80211_BAND_2GHZ)
-			end_channel = triplet->chans.first_channel +
-				triplet->chans.num_channels -1;
-		else
-			end_channel =  triplet->chans.first_channel +
-				(4 * (triplet->chans.num_channels - 1));
-
-		end_channel = max_subband_chan(band,
-					       triplet->chans.first_channel,
-					       end_channel,
-					       triplet->chans.max_power,
-					       &country_ie,
-					       &country_ie_len);
-
-		/*
-		 * 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(
-				end_channel) + 10);
-
-		/*
-		 * These are large arbitrary values we use to 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(triplet->chans.max_power);
-
-		i++;
-
-		if (country_ie_len >= 3) {
-			country_ie += 3;
-			country_ie_len -= 3;
-		}
-
-		BUG_ON(i > NL80211_MAX_SUPP_REG_RULES);
-	}
-
-	return rd;
-}
-
-
-/*
  * Helper for regdom_intersect(), this does the real
  * mathematical intersection fun
  */
@@ -1191,7 +699,6 @@
 
 	return -EINVAL;
 }
-EXPORT_SYMBOL(freq_reg_info);
 
 int freq_reg_info(struct wiphy *wiphy,
 		  u32 center_freq,
@@ -1205,6 +712,7 @@
 				  reg_rule,
 				  NULL);
 }
+EXPORT_SYMBOL(freq_reg_info);
 
 /*
  * Note that right now we assume the desired channel bandwidth
@@ -1243,41 +751,8 @@
 			  desired_bw_khz,
 			  &reg_rule);
 
-	if (r) {
-		/*
-		 * This means no regulatory rule was found in the country IE
-		 * with a frequency range on the center_freq's band, since
-		 * IEEE-802.11 allows for a country IE to have a subset of the
-		 * regulatory information provided in a country we ignore
-		 * disabling the channel unless at least one reg rule was
-		 * found on the center_freq's band. For details see this
-		 * clarification:
-		 *
-		 * http://tinyurl.com/11d-clarification
-		 */
-		if (r == -ERANGE &&
-		    last_request->initiator ==
-		    NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-			REG_DBG_PRINT("cfg80211: Leaving channel %d MHz "
-				"intact on %s - no rule found in band on "
-				"Country IE\n",
-			chan->center_freq, wiphy_name(wiphy));
-		} else {
-		/*
-		 * In this case we know the country IE has at least one reg rule
-		 * for the band so we respect its band definitions
-		 */
-			if (last_request->initiator ==
-			    NL80211_REGDOM_SET_BY_COUNTRY_IE)
-				REG_DBG_PRINT("cfg80211: Disabling "
-					"channel %d MHz on %s due to "
-					"Country IE\n",
-					chan->center_freq, wiphy_name(wiphy));
-			flags |= IEEE80211_CHAN_DISABLED;
-			chan->flags = flags;
-		}
+	if (r)
 		return;
-	}
 
 	power_rule = &reg_rule->power_rule;
 	freq_range = &reg_rule->freq_range;
@@ -1831,6 +1306,7 @@
 {
 	int r = 0;
 	struct wiphy *wiphy = NULL;
+	enum nl80211_reg_initiator initiator = reg_request->initiator;
 
 	BUG_ON(!reg_request->alpha2);
 
@@ -1850,7 +1326,7 @@
 	/* This is required so that the orig_* parameters are saved */
 	if (r == -EALREADY && wiphy &&
 	    wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
-		wiphy_update_regulatory(wiphy, reg_request->initiator);
+		wiphy_update_regulatory(wiphy, initiator);
 out:
 	mutex_unlock(&reg_mutex);
 	mutex_unlock(&cfg80211_mutex);
@@ -2008,35 +1484,6 @@
 }
 EXPORT_SYMBOL(regulatory_hint);
 
-/* Caller must hold reg_mutex */
-static bool reg_same_country_ie_hint(struct wiphy *wiphy,
-			u32 country_ie_checksum)
-{
-	struct wiphy *request_wiphy;
-
-	assert_reg_lock();
-
-	if (unlikely(last_request->initiator !=
-	    NL80211_REGDOM_SET_BY_COUNTRY_IE))
-		return false;
-
-	request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
-
-	if (!request_wiphy)
-		return false;
-
-	if (likely(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;
-}
-
 /*
  * We hold wdev_lock() here so we cannot hold cfg80211_mutex() and
  * therefore cannot iterate over the rdev list here.
@@ -2046,9 +1493,7 @@
 			 u8 *country_ie,
 			 u8 country_ie_len)
 {
-	struct ieee80211_regdomain *rd = NULL;
 	char alpha2[2];
-	u32 checksum = 0;
 	enum environment_cap env = ENVIRON_ANY;
 	struct regulatory_request *request;
 
@@ -2064,14 +1509,6 @@
 	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];
 
@@ -2090,39 +1527,14 @@
 	    wiphy_idx_valid(last_request->wiphy_idx)))
 		goto out;
 
-	rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum);
-	if (!rd) {
-		REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n");
-		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.
-	 *
-	 * 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 (WARN_ON(reg_same_country_ie_hint(wiphy, checksum)))
-		goto free_rd_out;
-
 	request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
 	if (!request)
-		goto free_rd_out;
-
-	/*
-	 * We keep this around for when CRDA comes back with a response so
-	 * we can intersect with that
-	 */
-	country_ie_regdomain = rd;
+		goto out;
 
 	request->wiphy_idx = get_wiphy_idx(wiphy);
-	request->alpha2[0] = rd->alpha2[0];
-	request->alpha2[1] = rd->alpha2[1];
+	request->alpha2[0] = alpha2[0];
+	request->alpha2[1] = alpha2[1];
 	request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE;
-	request->country_ie_checksum = checksum;
 	request->country_ie_env = env;
 
 	mutex_unlock(&reg_mutex);
@@ -2131,8 +1543,6 @@
 
 	return;
 
-free_rd_out:
-	kfree(rd);
 out:
 	mutex_unlock(&reg_mutex);
 }
@@ -2383,33 +1793,6 @@
 	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(intersected_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)
 {
@@ -2521,34 +1904,6 @@
 		return 0;
 	}
 
-	/*
-	 * Country IE requests are handled a bit differently, we intersect
-	 * the country IE rd with what CRDA believes that country should have
-	 */
-
-	/*
-	 * Userspace could have sent two replies with only
-	 * one kernel request. By the second reply we would have
-	 * already processed and consumed the country_ie_regdomain.
-	 */
-	if (!country_ie_regdomain)
-		return -EALREADY;
-	BUG_ON(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;
-
 	if (!intersected_rd)
 		return -EINVAL;
 
@@ -2630,7 +1985,7 @@
 	mutex_unlock(&reg_mutex);
 }
 
-int regulatory_init(void)
+int __init regulatory_init(void)
 {
 	int err = 0;
 
@@ -2676,7 +2031,7 @@
 	return 0;
 }
 
-void regulatory_exit(void)
+void /* __init_or_exit */ regulatory_exit(void)
 {
 	struct regulatory_request *reg_request, *tmp;
 	struct reg_beacon *reg_beacon, *btmp;
@@ -2688,9 +2043,6 @@
 
 	reset_regdomains();
 
-	kfree(country_ie_regdomain);
-	country_ie_regdomain = NULL;
-
 	kfree(last_request);
 
 	platform_device_unregister(reg_pdev);
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index b26224a..c4695d0 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -10,7 +10,7 @@
 
 void reg_device_remove(struct wiphy *wiphy);
 
-int regulatory_init(void);
+int __init regulatory_init(void);
 void regulatory_exit(void);
 
 int set_regdom(const struct ieee80211_regdomain *rd);
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 58401d2..5ca8c71 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -275,6 +275,7 @@
 {
 	struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
 	struct cfg80211_internal_bss *bss, *res = NULL;
+	unsigned long now = jiffies;
 
 	spin_lock_bh(&dev->bss_lock);
 
@@ -283,6 +284,10 @@
 			continue;
 		if (channel && bss->pub.channel != channel)
 			continue;
+		/* Don't get expired BSS structs */
+		if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) &&
+		    !atomic_read(&bss->hold))
+			continue;
 		if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
 			res = bss;
 			kref_get(&res->ref);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 72222f0..a8c2d6b 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -35,7 +35,7 @@
 	bool auto_auth, prev_bssid_valid;
 };
 
-bool cfg80211_is_all_idle(void)
+static bool cfg80211_is_all_idle(void)
 {
 	struct cfg80211_registered_device *rdev;
 	struct wireless_dev *wdev;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 3416373..0c8a1e8 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -770,8 +770,8 @@
 		return -EOPNOTSUPP;
 
 	/* if it's part of a bridge, reject changing type to station/ibss */
-	if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC ||
-			     ntype == NL80211_IFTYPE_STATION))
+	if ((dev->priv_flags & IFF_BRIDGE_PORT) &&
+	    (ntype == NL80211_IFTYPE_ADHOC || ntype == NL80211_IFTYPE_STATION))
 		return -EBUSY;
 
 	if (ntype != otype) {
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 9634299..bb5e0a5 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -829,7 +829,7 @@
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-	enum tx_power_setting type;
+	enum nl80211_tx_power_setting type;
 	int dbm = 0;
 
 	if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
@@ -852,7 +852,7 @@
 			if (data->txpower.value < 0)
 				return -EINVAL;
 			dbm = data->txpower.value;
-			type = TX_POWER_FIXED;
+			type = NL80211_TX_POWER_FIXED;
 			/* TODO: do regulatory check! */
 		} else {
 			/*
@@ -860,10 +860,10 @@
 			 * passed in from userland.
 			 */
 			if (data->txpower.value < 0) {
-				type = TX_POWER_AUTOMATIC;
+				type = NL80211_TX_POWER_AUTOMATIC;
 			} else {
 				dbm = data->txpower.value;
-				type = TX_POWER_LIMITED;
+				type = NL80211_TX_POWER_LIMITED;
 			}
 		}
 	} else {
@@ -872,7 +872,7 @@
 		return 0;
 	}
 
-	return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);
+	return rdev->ops->set_tx_power(wdev->wiphy, type, DBM_TO_MBM(dbm));
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower);
 
@@ -1471,6 +1471,7 @@
 		return -EOPNOTSUPP;
 	}
 }
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwpmksa);
 
 static const iw_handler cfg80211_handlers[] = {
 	[IW_IOCTL_IDX(SIOCGIWNAME)]	= (iw_handler) cfg80211_wext_giwname,
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index a7ec5a8..2b3ed7a 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2492,7 +2492,8 @@
 	int rv;
 
 	if (snmp_mib_init((void __percpu **)net->mib.xfrm_statistics,
-			  sizeof(struct linux_xfrm_mib)) < 0)
+			  sizeof(struct linux_xfrm_mib),
+			  __alignof__(struct linux_xfrm_mib)) < 0)
 		return -ENOMEM;
 	rv = xfrm_proc_init(net);
 	if (rv < 0)
diff --git a/security/Kconfig b/security/Kconfig
index 226b955..bd72ae6 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -140,6 +140,7 @@
 source security/selinux/Kconfig
 source security/smack/Kconfig
 source security/tomoyo/Kconfig
+source security/apparmor/Kconfig
 
 source security/integrity/ima/Kconfig
 
@@ -148,6 +149,7 @@
 	default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX
 	default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
 	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
+	default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
 	default DEFAULT_SECURITY_DAC
 
 	help
@@ -163,6 +165,9 @@
 	config DEFAULT_SECURITY_TOMOYO
 		bool "TOMOYO" if SECURITY_TOMOYO=y
 
+	config DEFAULT_SECURITY_APPARMOR
+		bool "AppArmor" if SECURITY_APPARMOR=y
+
 	config DEFAULT_SECURITY_DAC
 		bool "Unix Discretionary Access Controls"
 
@@ -173,6 +178,7 @@
 	default "selinux" if DEFAULT_SECURITY_SELINUX
 	default "smack" if DEFAULT_SECURITY_SMACK
 	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
+	default "apparmor" if DEFAULT_SECURITY_APPARMOR
 	default "" if DEFAULT_SECURITY_DAC
 
 endmenu
diff --git a/security/Makefile b/security/Makefile
index da20a19..8bb0fe9 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -6,6 +6,7 @@
 subdir-$(CONFIG_SECURITY_SELINUX)	+= selinux
 subdir-$(CONFIG_SECURITY_SMACK)		+= smack
 subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
+subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
 
 # always enable default capabilities
 obj-y					+= commoncap.o
@@ -19,6 +20,7 @@
 obj-$(CONFIG_SECURITY_SMACK)		+= smack/built-in.o
 obj-$(CONFIG_AUDIT)			+= lsm_audit.o
 obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/built-in.o
+obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/built-in.o
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
 
 # Object integrity file lists
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
new file mode 100644
index 0000000..0a0a99f
--- /dev/null
+++ b/security/apparmor/.gitignore
@@ -0,0 +1,5 @@
+#
+# Generated include files
+#
+af_names.h
+capability_names.h
diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
new file mode 100644
index 0000000..72555b9
--- /dev/null
+++ b/security/apparmor/Kconfig
@@ -0,0 +1,31 @@
+config SECURITY_APPARMOR
+	bool "AppArmor support"
+	depends on SECURITY
+	select AUDIT
+	select SECURITY_PATH
+	select SECURITYFS
+	select SECURITY_NETWORK
+	default n
+	help
+	  This enables the AppArmor security module.
+	  Required userspace tools (if they are not included in your
+	  distribution) and further information may be found at
+	  http://apparmor.wiki.kernel.org
+
+	  If you are unsure how to answer this question, answer N.
+
+config SECURITY_APPARMOR_BOOTPARAM_VALUE
+	int "AppArmor boot parameter default value"
+	depends on SECURITY_APPARMOR
+	range 0 1
+	default 1
+	help
+	  This option sets the default value for the kernel parameter
+	  'apparmor', which allows AppArmor to be enabled or disabled
+          at boot.  If this option is set to 0 (zero), the AppArmor
+	  kernel parameter will default to 0, disabling AppArmor at
+	  boot.  If this option is set to 1 (one), the AppArmor
+	  kernel parameter will default to 1, enabling AppArmor at
+	  boot.
+
+	  If you are unsure how to answer this question, answer 1.
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
new file mode 100644
index 0000000..f204869
--- /dev/null
+++ b/security/apparmor/Makefile
@@ -0,0 +1,24 @@
+# Makefile for AppArmor Linux Security Module
+#
+obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
+
+apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
+              path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
+              resource.o sid.o file.o
+
+clean-files: capability_names.h af_names.h
+
+quiet_cmd_make-caps = GEN     $@
+cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ; sed -n -e "/CAP_FS_MASK/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\$$/[\\2]  = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@
+
+quiet_cmd_make-rlim = GEN     $@
+cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ; sed -n --e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+RLIMIT_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/[\\2]  = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@ ; echo "static const int rlim_map[] = {" >> $@ ; sed -n -e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+\\(RLIMIT_[A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/\\1,/p" $< >> $@ ; echo "};" >> $@
+
+$(obj)/capability.o : $(obj)/capability_names.h
+$(obj)/resource.o : $(obj)/rlim_names.h
+$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
+	$(call cmd,make-caps)
+$(obj)/af_names.h : $(srctree)/include/linux/socket.h
+	$(call cmd,make-af)
+$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h
+	$(call cmd,make-rlim)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
new file mode 100644
index 0000000..7320331
--- /dev/null
+++ b/security/apparmor/apparmorfs.c
@@ -0,0 +1,239 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor /sys/kernel/security/apparmor interface functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#include <linux/security.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/namei.h>
+
+#include "include/apparmor.h"
+#include "include/apparmorfs.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/policy.h"
+
+/**
+ * aa_simple_write_to_buffer - common routine for getting policy from user
+ * @op: operation doing the user buffer copy
+ * @userbuf: user buffer to copy data from  (NOT NULL)
+ * @alloc_size: size of user buffer
+ * @copy_size: size of data to copy from user buffer
+ * @pos: position write is at in the file (NOT NULL)
+ *
+ * Returns: kernel buffer containing copy of user buffer data or an
+ *          ERR_PTR on failure.
+ */
+static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
+				       size_t alloc_size, size_t copy_size,
+				       loff_t *pos)
+{
+	char *data;
+
+	if (*pos != 0)
+		/* only writes from pos 0, that is complete writes */
+		return ERR_PTR(-ESPIPE);
+
+	/*
+	 * Don't allow profile load/replace/remove from profiles that don't
+	 * have CAP_MAC_ADMIN
+	 */
+	if (!aa_may_manage_policy(op))
+		return ERR_PTR(-EACCES);
+
+	/* freed by caller to simple_write_to_buffer */
+	data = kvmalloc(alloc_size);
+	if (data == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	if (copy_from_user(data, userbuf, copy_size)) {
+		kvfree(data);
+		return ERR_PTR(-EFAULT);
+	}
+
+	return data;
+}
+
+
+/* .load file hook fn to load policy */
+static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
+			    loff_t *pos)
+{
+	char *data;
+	ssize_t error;
+
+	data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos);
+
+	error = PTR_ERR(data);
+	if (!IS_ERR(data)) {
+		error = aa_replace_profiles(data, size, PROF_ADD);
+		kvfree(data);
+	}
+
+	return error;
+}
+
+static const struct file_operations aa_fs_profile_load = {
+	.write = profile_load
+};
+
+/* .replace file hook fn to load and/or replace policy */
+static ssize_t profile_replace(struct file *f, const char __user *buf,
+			       size_t size, loff_t *pos)
+{
+	char *data;
+	ssize_t error;
+
+	data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
+	error = PTR_ERR(data);
+	if (!IS_ERR(data)) {
+		error = aa_replace_profiles(data, size, PROF_REPLACE);
+		kvfree(data);
+	}
+
+	return error;
+}
+
+static const struct file_operations aa_fs_profile_replace = {
+	.write = profile_replace
+};
+
+/* .remove file hook fn to remove loaded policy */
+static ssize_t profile_remove(struct file *f, const char __user *buf,
+			      size_t size, loff_t *pos)
+{
+	char *data;
+	ssize_t error;
+
+	/*
+	 * aa_remove_profile needs a null terminated string so 1 extra
+	 * byte is allocated and the copied data is null terminated.
+	 */
+	data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos);
+
+	error = PTR_ERR(data);
+	if (!IS_ERR(data)) {
+		data[size] = 0;
+		error = aa_remove_profiles(data, size);
+		kvfree(data);
+	}
+
+	return error;
+}
+
+static const struct file_operations aa_fs_profile_remove = {
+	.write = profile_remove
+};
+
+/** Base file system setup **/
+
+static struct dentry *aa_fs_dentry __initdata;
+
+static void __init aafs_remove(const char *name)
+{
+	struct dentry *dentry;
+
+	dentry = lookup_one_len(name, aa_fs_dentry, strlen(name));
+	if (!IS_ERR(dentry)) {
+		securityfs_remove(dentry);
+		dput(dentry);
+	}
+}
+
+/**
+ * aafs_create - create an entry in the apparmor filesystem
+ * @name: name of the entry (NOT NULL)
+ * @mask: file permission mask of the file
+ * @fops: file operations for the file (NOT NULL)
+ *
+ * Used aafs_remove to remove entries created with this fn.
+ */
+static int __init aafs_create(const char *name, int mask,
+			      const struct file_operations *fops)
+{
+	struct dentry *dentry;
+
+	dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry,
+					NULL, fops);
+
+	return IS_ERR(dentry) ? PTR_ERR(dentry) : 0;
+}
+
+/**
+ * aa_destroy_aafs - cleanup and free aafs
+ *
+ * releases dentries allocated by aa_create_aafs
+ */
+void __init aa_destroy_aafs(void)
+{
+	if (aa_fs_dentry) {
+		aafs_remove(".remove");
+		aafs_remove(".replace");
+		aafs_remove(".load");
+
+		securityfs_remove(aa_fs_dentry);
+		aa_fs_dentry = NULL;
+	}
+}
+
+/**
+ * aa_create_aafs - create the apparmor security filesystem
+ *
+ * dentries created here are released by aa_destroy_aafs
+ *
+ * Returns: error on failure
+ */
+int __init aa_create_aafs(void)
+{
+	int error;
+
+	if (!apparmor_initialized)
+		return 0;
+
+	if (aa_fs_dentry) {
+		AA_ERROR("%s: AppArmor securityfs already exists\n", __func__);
+		return -EEXIST;
+	}
+
+	aa_fs_dentry = securityfs_create_dir("apparmor", NULL);
+	if (IS_ERR(aa_fs_dentry)) {
+		error = PTR_ERR(aa_fs_dentry);
+		aa_fs_dentry = NULL;
+		goto error;
+	}
+
+	error = aafs_create(".load", 0640, &aa_fs_profile_load);
+	if (error)
+		goto error;
+	error = aafs_create(".replace", 0640, &aa_fs_profile_replace);
+	if (error)
+		goto error;
+	error = aafs_create(".remove", 0640, &aa_fs_profile_remove);
+	if (error)
+		goto error;
+
+	/* TODO: add support for apparmorfs_null and apparmorfs_mnt */
+
+	/* Report that AppArmor fs is enabled */
+	aa_info_message("AppArmor Filesystem Enabled");
+	return 0;
+
+error:
+	aa_destroy_aafs();
+	AA_ERROR("Error creating AppArmor securityfs\n");
+	return error;
+}
+
+fs_initcall(aa_create_aafs);
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
new file mode 100644
index 0000000..96502b2
--- /dev/null
+++ b/security/apparmor/audit.c
@@ -0,0 +1,215 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor auditing functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#include <linux/audit.h>
+#include <linux/socket.h>
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/policy.h"
+
+const char *op_table[] = {
+	"null",
+
+	"sysctl",
+	"capable",
+
+	"unlink",
+	"mkdir",
+	"rmdir",
+	"mknod",
+	"truncate",
+	"link",
+	"symlink",
+	"rename_src",
+	"rename_dest",
+	"chmod",
+	"chown",
+	"getattr",
+	"open",
+
+	"file_perm",
+	"file_lock",
+	"file_mmap",
+	"file_mprotect",
+
+	"create",
+	"post_create",
+	"bind",
+	"connect",
+	"listen",
+	"accept",
+	"sendmsg",
+	"recvmsg",
+	"getsockname",
+	"getpeername",
+	"getsockopt",
+	"setsockopt",
+	"socket_shutdown",
+
+	"ptrace",
+
+	"exec",
+	"change_hat",
+	"change_profile",
+	"change_onexec",
+
+	"setprocattr",
+	"setrlimit",
+
+	"profile_replace",
+	"profile_load",
+	"profile_remove"
+};
+
+const char *audit_mode_names[] = {
+	"normal",
+	"quiet_denied",
+	"quiet",
+	"noquiet",
+	"all"
+};
+
+static char *aa_audit_type[] = {
+	"AUDIT",
+	"ALLOWED",
+	"DENIED",
+	"HINT",
+	"STATUS",
+	"ERROR",
+	"KILLED"
+};
+
+/*
+ * Currently AppArmor auditing is fed straight into the audit framework.
+ *
+ * TODO:
+ * netlink interface for complain mode
+ * user auditing, - send user auditing to netlink interface
+ * system control of whether user audit messages go to system log
+ */
+
+/**
+ * audit_base - core AppArmor function.
+ * @ab: audit buffer to fill (NOT NULL)
+ * @ca: audit structure containing data to audit (NOT NULL)
+ *
+ * Record common AppArmor audit data from @sa
+ */
+static void audit_pre(struct audit_buffer *ab, void *ca)
+{
+	struct common_audit_data *sa = ca;
+	struct task_struct *tsk = sa->tsk ? sa->tsk : current;
+
+	if (aa_g_audit_header) {
+		audit_log_format(ab, "apparmor=");
+		audit_log_string(ab, aa_audit_type[sa->aad.type]);
+	}
+
+	if (sa->aad.op) {
+		audit_log_format(ab, " operation=");
+		audit_log_string(ab, op_table[sa->aad.op]);
+	}
+
+	if (sa->aad.info) {
+		audit_log_format(ab, " info=");
+		audit_log_string(ab, sa->aad.info);
+		if (sa->aad.error)
+			audit_log_format(ab, " error=%d", sa->aad.error);
+	}
+
+	if (sa->aad.profile) {
+		struct aa_profile *profile = sa->aad.profile;
+		pid_t pid;
+		rcu_read_lock();
+		pid = tsk->real_parent->pid;
+		rcu_read_unlock();
+		audit_log_format(ab, " parent=%d", pid);
+		if (profile->ns != root_ns) {
+			audit_log_format(ab, " namespace=");
+			audit_log_untrustedstring(ab, profile->ns->base.hname);
+		}
+		audit_log_format(ab, " profile=");
+		audit_log_untrustedstring(ab, profile->base.hname);
+	}
+
+	if (sa->aad.name) {
+		audit_log_format(ab, " name=");
+		audit_log_untrustedstring(ab, sa->aad.name);
+	}
+}
+
+/**
+ * aa_audit_msg - Log a message to the audit subsystem
+ * @sa: audit event structure (NOT NULL)
+ * @cb: optional callback fn for type specific fields (MAYBE NULL)
+ */
+void aa_audit_msg(int type, struct common_audit_data *sa,
+		  void (*cb) (struct audit_buffer *, void *))
+{
+	sa->aad.type = type;
+	sa->lsm_pre_audit = audit_pre;
+	sa->lsm_post_audit = cb;
+	common_lsm_audit(sa);
+}
+
+/**
+ * aa_audit - Log a profile based audit event to the audit subsystem
+ * @type: audit type for the message
+ * @profile: profile to check against (NOT NULL)
+ * @gfp: allocation flags to use
+ * @sa: audit event (NOT NULL)
+ * @cb: optional callback fn for type specific fields (MAYBE NULL)
+ *
+ * Handle default message switching based off of audit mode flags
+ *
+ * Returns: error on failure
+ */
+int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
+	     struct common_audit_data *sa,
+	     void (*cb) (struct audit_buffer *, void *))
+{
+	BUG_ON(!profile);
+
+	if (type == AUDIT_APPARMOR_AUTO) {
+		if (likely(!sa->aad.error)) {
+			if (AUDIT_MODE(profile) != AUDIT_ALL)
+				return 0;
+			type = AUDIT_APPARMOR_AUDIT;
+		} else if (COMPLAIN_MODE(profile))
+			type = AUDIT_APPARMOR_ALLOWED;
+		else
+			type = AUDIT_APPARMOR_DENIED;
+	}
+	if (AUDIT_MODE(profile) == AUDIT_QUIET ||
+	    (type == AUDIT_APPARMOR_DENIED &&
+	     AUDIT_MODE(profile) == AUDIT_QUIET))
+		return sa->aad.error;
+
+	if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
+		type = AUDIT_APPARMOR_KILL;
+
+	if (!unconfined(profile))
+		sa->aad.profile = profile;
+
+	aa_audit_msg(type, sa, cb);
+
+	if (sa->aad.type == AUDIT_APPARMOR_KILL)
+		(void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current);
+
+	if (sa->aad.type == AUDIT_APPARMOR_ALLOWED)
+		return complain_error(sa->aad.error);
+
+	return sa->aad.error;
+}
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c
new file mode 100644
index 0000000..9982c48
--- /dev/null
+++ b/security/apparmor/capability.c
@@ -0,0 +1,141 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor capability mediation functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#include <linux/capability.h>
+#include <linux/errno.h>
+#include <linux/gfp.h>
+
+#include "include/apparmor.h"
+#include "include/capability.h"
+#include "include/context.h"
+#include "include/policy.h"
+#include "include/audit.h"
+
+/*
+ * Table of capability names: we generate it from capabilities.h.
+ */
+#include "capability_names.h"
+
+struct audit_cache {
+	struct aa_profile *profile;
+	kernel_cap_t caps;
+};
+
+static DEFINE_PER_CPU(struct audit_cache, audit_cache);
+
+/**
+ * audit_cb - call back for capability components of audit struct
+ * @ab - audit buffer   (NOT NULL)
+ * @va - audit struct to audit data from  (NOT NULL)
+ */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+	struct common_audit_data *sa = va;
+	audit_log_format(ab, " capname=");
+	audit_log_untrustedstring(ab, capability_names[sa->u.cap]);
+}
+
+/**
+ * audit_caps - audit a capability
+ * @profile: profile confining task (NOT NULL)
+ * @task: task capability test was performed against (NOT NULL)
+ * @cap: capability tested
+ * @error: error code returned by test
+ *
+ * Do auditing of capability and handle, audit/complain/kill modes switching
+ * and duplicate message elimination.
+ *
+ * Returns: 0 or sa->error on success,  error code on failure
+ */
+static int audit_caps(struct aa_profile *profile, struct task_struct *task,
+		      int cap, int error)
+{
+	struct audit_cache *ent;
+	int type = AUDIT_APPARMOR_AUTO;
+	struct common_audit_data sa;
+	COMMON_AUDIT_DATA_INIT(&sa, CAP);
+	sa.tsk = task;
+	sa.u.cap = cap;
+	sa.aad.op = OP_CAPABLE;
+	sa.aad.error = error;
+
+	if (likely(!error)) {
+		/* test if auditing is being forced */
+		if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
+			   !cap_raised(profile->caps.audit, cap)))
+			return 0;
+		type = AUDIT_APPARMOR_AUDIT;
+	} else if (KILL_MODE(profile) ||
+		   cap_raised(profile->caps.kill, cap)) {
+		type = AUDIT_APPARMOR_KILL;
+	} else if (cap_raised(profile->caps.quiet, cap) &&
+		   AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+		   AUDIT_MODE(profile) != AUDIT_ALL) {
+		/* quiet auditing */
+		return error;
+	}
+
+	/* Do simple duplicate message elimination */
+	ent = &get_cpu_var(audit_cache);
+	if (profile == ent->profile && cap_raised(ent->caps, cap)) {
+		put_cpu_var(audit_cache);
+		if (COMPLAIN_MODE(profile))
+			return complain_error(error);
+		return error;
+	} else {
+		aa_put_profile(ent->profile);
+		ent->profile = aa_get_profile(profile);
+		cap_raise(ent->caps, cap);
+	}
+	put_cpu_var(audit_cache);
+
+	return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb);
+}
+
+/**
+ * profile_capable - test if profile allows use of capability @cap
+ * @profile: profile being enforced    (NOT NULL, NOT unconfined)
+ * @cap: capability to test if allowed
+ *
+ * Returns: 0 if allowed else -EPERM
+ */
+static int profile_capable(struct aa_profile *profile, int cap)
+{
+	return cap_raised(profile->caps.allow, cap) ? 0 : -EPERM;
+}
+
+/**
+ * aa_capable - test permission to use capability
+ * @task: task doing capability test against (NOT NULL)
+ * @profile: profile confining @task (NOT NULL)
+ * @cap: capability to be tested
+ * @audit: whether an audit record should be generated
+ *
+ * Look up capability in profile capability set.
+ *
+ * Returns: 0 on success, or else an error code.
+ */
+int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
+	       int audit)
+{
+	int error = profile_capable(profile, cap);
+
+	if (!audit) {
+		if (COMPLAIN_MODE(profile))
+			return complain_error(error);
+		return error;
+	}
+
+	return audit_caps(profile, task, cap, error);
+}
diff --git a/security/apparmor/context.c b/security/apparmor/context.c
new file mode 100644
index 0000000..8a9b502
--- /dev/null
+++ b/security/apparmor/context.c
@@ -0,0 +1,216 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor functions used to manipulate object security
+ * contexts.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ *
+ *
+ * AppArmor sets confinement on every task, via the the aa_task_cxt and
+ * the aa_task_cxt.profile, both of which are required and are not allowed
+ * to be NULL.  The aa_task_cxt is not reference counted and is unique
+ * to each cred (which is reference count).  The profile pointed to by
+ * the task_cxt is reference counted.
+ *
+ * TODO
+ * If a task uses change_hat it currently does not return to the old
+ * cred or task context but instead creates a new one.  Ideally the task
+ * should return to the previous cred if it has not been modified.
+ *
+ */
+
+#include "include/context.h"
+#include "include/policy.h"
+
+/**
+ * aa_alloc_task_context - allocate a new task_cxt
+ * @flags: gfp flags for allocation
+ *
+ * Returns: allocated buffer or NULL on failure
+ */
+struct aa_task_cxt *aa_alloc_task_context(gfp_t flags)
+{
+	return kzalloc(sizeof(struct aa_task_cxt), flags);
+}
+
+/**
+ * aa_free_task_context - free a task_cxt
+ * @cxt: task_cxt to free (MAYBE NULL)
+ */
+void aa_free_task_context(struct aa_task_cxt *cxt)
+{
+	if (cxt) {
+		aa_put_profile(cxt->profile);
+		aa_put_profile(cxt->previous);
+		aa_put_profile(cxt->onexec);
+
+		kzfree(cxt);
+	}
+}
+
+/**
+ * aa_dup_task_context - duplicate a task context, incrementing reference counts
+ * @new: a blank task context      (NOT NULL)
+ * @old: the task context to copy  (NOT NULL)
+ */
+void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)
+{
+	*new = *old;
+	aa_get_profile(new->profile);
+	aa_get_profile(new->previous);
+	aa_get_profile(new->onexec);
+}
+
+/**
+ * aa_replace_current_profile - replace the current tasks profiles
+ * @profile: new profile  (NOT NULL)
+ *
+ * Returns: 0 or error on failure
+ */
+int aa_replace_current_profile(struct aa_profile *profile)
+{
+	struct aa_task_cxt *cxt = current_cred()->security;
+	struct cred *new;
+	BUG_ON(!profile);
+
+	if (cxt->profile == profile)
+		return 0;
+
+	new  = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+
+	cxt = new->security;
+	if (unconfined(profile) || (cxt->profile->ns != profile->ns)) {
+		/* if switching to unconfined or a different profile namespace
+		 * clear out context state
+		 */
+		aa_put_profile(cxt->previous);
+		aa_put_profile(cxt->onexec);
+		cxt->previous = NULL;
+		cxt->onexec = NULL;
+		cxt->token = 0;
+	}
+	/* be careful switching cxt->profile, when racing replacement it
+	 * is possible that cxt->profile->replacedby is the reference keeping
+	 * @profile valid, so make sure to get its reference before dropping
+	 * the reference on cxt->profile */
+	aa_get_profile(profile);
+	aa_put_profile(cxt->profile);
+	cxt->profile = profile;
+
+	commit_creds(new);
+	return 0;
+}
+
+/**
+ * aa_set_current_onexec - set the tasks change_profile to happen onexec
+ * @profile: system profile to set at exec  (MAYBE NULL to clear value)
+ *
+ * Returns: 0 or error on failure
+ */
+int aa_set_current_onexec(struct aa_profile *profile)
+{
+	struct aa_task_cxt *cxt;
+	struct cred *new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+
+	cxt = new->security;
+	aa_get_profile(profile);
+	aa_put_profile(cxt->onexec);
+	cxt->onexec = profile;
+
+	commit_creds(new);
+	return 0;
+}
+
+/**
+ * aa_set_current_hat - set the current tasks hat
+ * @profile: profile to set as the current hat  (NOT NULL)
+ * @token: token value that must be specified to change from the hat
+ *
+ * Do switch of tasks hat.  If the task is currently in a hat
+ * validate the token to match.
+ *
+ * Returns: 0 or error on failure
+ */
+int aa_set_current_hat(struct aa_profile *profile, u64 token)
+{
+	struct aa_task_cxt *cxt;
+	struct cred *new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+	BUG_ON(!profile);
+
+	cxt = new->security;
+	if (!cxt->previous) {
+		/* transfer refcount */
+		cxt->previous = cxt->profile;
+		cxt->token = token;
+	} else if (cxt->token == token) {
+		aa_put_profile(cxt->profile);
+	} else {
+		/* previous_profile && cxt->token != token */
+		abort_creds(new);
+		return -EACCES;
+	}
+	cxt->profile = aa_get_profile(aa_newest_version(profile));
+	/* clear exec on switching context */
+	aa_put_profile(cxt->onexec);
+	cxt->onexec = NULL;
+
+	commit_creds(new);
+	return 0;
+}
+
+/**
+ * aa_restore_previous_profile - exit from hat context restoring the profile
+ * @token: the token that must be matched to exit hat context
+ *
+ * Attempt to return out of a hat to the previous profile.  The token
+ * must match the stored token value.
+ *
+ * Returns: 0 or error of failure
+ */
+int aa_restore_previous_profile(u64 token)
+{
+	struct aa_task_cxt *cxt;
+	struct cred *new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+
+	cxt = new->security;
+	if (cxt->token != token) {
+		abort_creds(new);
+		return -EACCES;
+	}
+	/* ignore restores when there is no saved profile */
+	if (!cxt->previous) {
+		abort_creds(new);
+		return 0;
+	}
+
+	aa_put_profile(cxt->profile);
+	cxt->profile = aa_newest_version(cxt->previous);
+	BUG_ON(!cxt->profile);
+	if (unlikely(cxt->profile != cxt->previous)) {
+		aa_get_profile(cxt->profile);
+		aa_put_profile(cxt->previous);
+	}
+	/* clear exec && prev information when restoring to previous context */
+	cxt->previous = NULL;
+	cxt->token = 0;
+	aa_put_profile(cxt->onexec);
+	cxt->onexec = NULL;
+
+	commit_creds(new);
+	return 0;
+}
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
new file mode 100644
index 0000000..c825c6e
--- /dev/null
+++ b/security/apparmor/domain.c
@@ -0,0 +1,823 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy attachment and domain transitions
+ *
+ * Copyright (C) 2002-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#include <linux/errno.h>
+#include <linux/fdtable.h>
+#include <linux/file.h>
+#include <linux/mount.h>
+#include <linux/syscalls.h>
+#include <linux/tracehook.h>
+#include <linux/personality.h>
+
+#include "include/audit.h"
+#include "include/apparmorfs.h"
+#include "include/context.h"
+#include "include/domain.h"
+#include "include/file.h"
+#include "include/ipc.h"
+#include "include/match.h"
+#include "include/path.h"
+#include "include/policy.h"
+
+/**
+ * aa_free_domain_entries - free entries in a domain table
+ * @domain: the domain table to free  (MAYBE NULL)
+ */
+void aa_free_domain_entries(struct aa_domain *domain)
+{
+	int i;
+	if (domain) {
+		if (!domain->table)
+			return;
+
+		for (i = 0; i < domain->size; i++)
+			kzfree(domain->table[i]);
+		kzfree(domain->table);
+		domain->table = NULL;
+	}
+}
+
+/**
+ * may_change_ptraced_domain - check if can change profile on ptraced task
+ * @task: task we want to change profile of   (NOT NULL)
+ * @to_profile: profile to change to  (NOT NULL)
+ *
+ * Check if the task is ptraced and if so if the tracing task is allowed
+ * to trace the new domain
+ *
+ * Returns: %0 or error if change not allowed
+ */
+static int may_change_ptraced_domain(struct task_struct *task,
+				     struct aa_profile *to_profile)
+{
+	struct task_struct *tracer;
+	const struct cred *cred = NULL;
+	struct aa_profile *tracerp = NULL;
+	int error = 0;
+
+	rcu_read_lock();
+	tracer = tracehook_tracer_task(task);
+	if (tracer) {
+		/* released below */
+		cred = get_task_cred(tracer);
+		tracerp = aa_cred_profile(cred);
+	}
+	rcu_read_unlock();
+
+	/* not ptraced */
+	if (!tracer || unconfined(tracerp))
+		goto out;
+
+	error = aa_may_ptrace(tracer, tracerp, to_profile, PTRACE_MODE_ATTACH);
+
+out:
+	if (cred)
+		put_cred(cred);
+
+	return error;
+}
+
+/**
+ * change_profile_perms - find permissions for change_profile
+ * @profile: the current profile  (NOT NULL)
+ * @ns: the namespace being switched to  (NOT NULL)
+ * @name: the name of the profile to change to  (NOT NULL)
+ * @request: requested perms
+ * @start: state to start matching in
+ *
+ * Returns: permission set
+ */
+static struct file_perms change_profile_perms(struct aa_profile *profile,
+					      struct aa_namespace *ns,
+					      const char *name, u32 request,
+					      unsigned int start)
+{
+	struct file_perms perms;
+	struct path_cond cond = { };
+	unsigned int state;
+
+	if (unconfined(profile)) {
+		perms.allow = AA_MAY_CHANGE_PROFILE | AA_MAY_ONEXEC;
+		perms.audit = perms.quiet = perms.kill = 0;
+		return perms;
+	} else if (!profile->file.dfa) {
+		return nullperms;
+	} else if ((ns == profile->ns)) {
+		/* try matching against rules with out namespace prepended */
+		aa_str_perms(profile->file.dfa, start, name, &cond, &perms);
+		if (COMBINED_PERM_MASK(perms) & request)
+			return perms;
+	}
+
+	/* try matching with namespace name and then profile */
+	state = aa_dfa_match(profile->file.dfa, start, ns->base.name);
+	state = aa_dfa_match_len(profile->file.dfa, state, ":", 1);
+	aa_str_perms(profile->file.dfa, state, name, &cond, &perms);
+
+	return perms;
+}
+
+/**
+ * __attach_match_ - find an attachment match
+ * @name - to match against  (NOT NULL)
+ * @head - profile list to walk  (NOT NULL)
+ *
+ * Do a linear search on the profiles in the list.  There is a matching
+ * preference where an exact match is preferred over a name which uses
+ * expressions to match, and matching expressions with the greatest
+ * xmatch_len are preferred.
+ *
+ * Requires: @head not be shared or have appropriate locks held
+ *
+ * Returns: profile or NULL if no match found
+ */
+static struct aa_profile *__attach_match(const char *name,
+					 struct list_head *head)
+{
+	int len = 0;
+	struct aa_profile *profile, *candidate = NULL;
+
+	list_for_each_entry(profile, head, base.list) {
+		if (profile->flags & PFLAG_NULL)
+			continue;
+		if (profile->xmatch && profile->xmatch_len > len) {
+			unsigned int state = aa_dfa_match(profile->xmatch,
+							  DFA_START, name);
+			u32 perm = dfa_user_allow(profile->xmatch, state);
+			/* any accepting state means a valid match. */
+			if (perm & MAY_EXEC) {
+				candidate = profile;
+				len = profile->xmatch_len;
+			}
+		} else if (!strcmp(profile->base.name, name))
+			/* exact non-re match, no more searching required */
+			return profile;
+	}
+
+	return candidate;
+}
+
+/**
+ * find_attach - do attachment search for unconfined processes
+ * @ns: the current namespace  (NOT NULL)
+ * @list: list to search  (NOT NULL)
+ * @name: the executable name to match against  (NOT NULL)
+ *
+ * Returns: profile or NULL if no match found
+ */
+static struct aa_profile *find_attach(struct aa_namespace *ns,
+				      struct list_head *list, const char *name)
+{
+	struct aa_profile *profile;
+
+	read_lock(&ns->lock);
+	profile = aa_get_profile(__attach_match(name, list));
+	read_unlock(&ns->lock);
+
+	return profile;
+}
+
+/**
+ * separate_fqname - separate the namespace and profile names
+ * @fqname: the fqname name to split  (NOT NULL)
+ * @ns_name: the namespace name if it exists  (NOT NULL)
+ *
+ * This is the xtable equivalent routine of aa_split_fqname.  It finds the
+ * split in an xtable fqname which contains an embedded \0 instead of a :
+ * if a namespace is specified.  This is done so the xtable is constant and
+ * isn't re-split on every lookup.
+ *
+ * Either the profile or namespace name may be optional but if the namespace
+ * is specified the profile name termination must be present.  This results
+ * in the following possible encodings:
+ * profile_name\0
+ * :ns_name\0profile_name\0
+ * :ns_name\0\0
+ *
+ * NOTE: the xtable fqname is pre-validated at load time in unpack_trans_table
+ *
+ * Returns: profile name if it is specified else NULL
+ */
+static const char *separate_fqname(const char *fqname, const char **ns_name)
+{
+	const char *name;
+
+	if (fqname[0] == ':') {
+		/* In this case there is guaranteed to be two \0 terminators
+		 * in the string.  They are verified at load time by
+		 * by unpack_trans_table
+		 */
+		*ns_name = fqname + 1;		/* skip : */
+		name = *ns_name + strlen(*ns_name) + 1;
+		if (!*name)
+			name = NULL;
+	} else {
+		*ns_name = NULL;
+		name = fqname;
+	}
+
+	return name;
+}
+
+static const char *next_name(int xtype, const char *name)
+{
+	return NULL;
+}
+
+/**
+ * x_table_lookup - lookup an x transition name via transition table
+ * @profile: current profile (NOT NULL)
+ * @xindex: index into x transition table
+ *
+ * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
+ */
+static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
+{
+	struct aa_profile *new_profile = NULL;
+	struct aa_namespace *ns = profile->ns;
+	u32 xtype = xindex & AA_X_TYPE_MASK;
+	int index = xindex & AA_X_INDEX_MASK;
+	const char *name;
+
+	/* index is guaranteed to be in range, validated at load time */
+	for (name = profile->file.trans.table[index]; !new_profile && name;
+	     name = next_name(xtype, name)) {
+		struct aa_namespace *new_ns;
+		const char *xname = NULL;
+
+		new_ns = NULL;
+		if (xindex & AA_X_CHILD) {
+			/* release by caller */
+			new_profile = aa_find_child(profile, name);
+			continue;
+		} else if (*name == ':') {
+			/* switching namespace */
+			const char *ns_name;
+			xname = name = separate_fqname(name, &ns_name);
+			if (!xname)
+				/* no name so use profile name */
+				xname = profile->base.hname;
+			if (*ns_name == '@') {
+				/* TODO: variable support */
+				;
+			}
+			/* released below */
+			new_ns = aa_find_namespace(ns, ns_name);
+			if (!new_ns)
+				continue;
+		} else if (*name == '@') {
+			/* TODO: variable support */
+			continue;
+		} else {
+			/* basic namespace lookup */
+			xname = name;
+		}
+
+		/* released by caller */
+		new_profile = aa_lookup_profile(new_ns ? new_ns : ns, xname);
+		aa_put_namespace(new_ns);
+	}
+
+	/* released by caller */
+	return new_profile;
+}
+
+/**
+ * x_to_profile - get target profile for a given xindex
+ * @profile: current profile  (NOT NULL)
+ * @name: name to lookup (NOT NULL)
+ * @xindex: index into x transition table
+ *
+ * find profile for a transition index
+ *
+ * Returns: refcounted profile or NULL if not found available
+ */
+static struct aa_profile *x_to_profile(struct aa_profile *profile,
+				       const char *name, u32 xindex)
+{
+	struct aa_profile *new_profile = NULL;
+	struct aa_namespace *ns = profile->ns;
+	u32 xtype = xindex & AA_X_TYPE_MASK;
+
+	switch (xtype) {
+	case AA_X_NONE:
+		/* fail exec unless ix || ux fallback - handled by caller */
+		return NULL;
+	case AA_X_NAME:
+		if (xindex & AA_X_CHILD)
+			/* released by caller */
+			new_profile = find_attach(ns, &profile->base.profiles,
+						  name);
+		else
+			/* released by caller */
+			new_profile = find_attach(ns, &ns->base.profiles,
+						  name);
+		break;
+	case AA_X_TABLE:
+		/* released by caller */
+		new_profile = x_table_lookup(profile, xindex);
+		break;
+	}
+
+	/* released by caller */
+	return new_profile;
+}
+
+/**
+ * apparmor_bprm_set_creds - set the new creds on the bprm struct
+ * @bprm: binprm for the exec  (NOT NULL)
+ *
+ * Returns: %0 or error on failure
+ */
+int apparmor_bprm_set_creds(struct linux_binprm *bprm)
+{
+	struct aa_task_cxt *cxt;
+	struct aa_profile *profile, *new_profile = NULL;
+	struct aa_namespace *ns;
+	char *buffer = NULL;
+	unsigned int state;
+	struct file_perms perms = {};
+	struct path_cond cond = {
+		bprm->file->f_path.dentry->d_inode->i_uid,
+		bprm->file->f_path.dentry->d_inode->i_mode
+	};
+	const char *name = NULL, *target = NULL, *info = NULL;
+	int error = cap_bprm_set_creds(bprm);
+	if (error)
+		return error;
+
+	if (bprm->cred_prepared)
+		return 0;
+
+	cxt = bprm->cred->security;
+	BUG_ON(!cxt);
+
+	profile = aa_get_profile(aa_newest_version(cxt->profile));
+	/*
+	 * get the namespace from the replacement profile as replacement
+	 * can change the namespace
+	 */
+	ns = profile->ns;
+	state = profile->file.start;
+
+	/* buffer freed below, name is pointer into buffer */
+	error = aa_get_name(&bprm->file->f_path, profile->path_flags, &buffer,
+			    &name);
+	if (error) {
+		if (profile->flags &
+		    (PFLAG_IX_ON_NAME_ERROR | PFLAG_UNCONFINED))
+			error = 0;
+		info = "Exec failed name resolution";
+		name = bprm->filename;
+		goto audit;
+	}
+
+	/* Test for onexec first as onexec directives override other
+	 * x transitions.
+	 */
+	if (unconfined(profile)) {
+		/* unconfined task */
+		if (cxt->onexec)
+			/* change_profile on exec already been granted */
+			new_profile = aa_get_profile(cxt->onexec);
+		else
+			new_profile = find_attach(ns, &ns->base.profiles, name);
+		if (!new_profile)
+			goto cleanup;
+		goto apply;
+	}
+
+	/* find exec permissions for name */
+	state = aa_str_perms(profile->file.dfa, state, name, &cond, &perms);
+	if (cxt->onexec) {
+		struct file_perms cp;
+		info = "change_profile onexec";
+		if (!(perms.allow & AA_MAY_ONEXEC))
+			goto audit;
+
+		/* test if this exec can be paired with change_profile onexec.
+		 * onexec permission is linked to exec with a standard pairing
+		 * exec\0change_profile
+		 */
+		state = aa_dfa_null_transition(profile->file.dfa, state);
+		cp = change_profile_perms(profile, cxt->onexec->ns, name,
+					  AA_MAY_ONEXEC, state);
+
+		if (!(cp.allow & AA_MAY_ONEXEC))
+			goto audit;
+		new_profile = aa_get_profile(aa_newest_version(cxt->onexec));
+		goto apply;
+	}
+
+	if (perms.allow & MAY_EXEC) {
+		/* exec permission determine how to transition */
+		new_profile = x_to_profile(profile, name, perms.xindex);
+		if (!new_profile) {
+			if (perms.xindex & AA_X_INHERIT) {
+				/* (p|c|n)ix - don't change profile but do
+				 * use the newest version, which was picked
+				 * up above when getting profile
+				 */
+				info = "ix fallback";
+				new_profile = aa_get_profile(profile);
+				goto x_clear;
+			} else if (perms.xindex & AA_X_UNCONFINED) {
+				new_profile = aa_get_profile(ns->unconfined);
+				info = "ux fallback";
+			} else {
+				error = -ENOENT;
+				info = "profile not found";
+			}
+		}
+	} else if (COMPLAIN_MODE(profile)) {
+		/* no exec permission - are we in learning mode */
+		new_profile = aa_new_null_profile(profile, 0);
+		if (!new_profile) {
+			error = -ENOMEM;
+			info = "could not create null profile";
+		} else {
+			error = -EACCES;
+			target = new_profile->base.hname;
+		}
+		perms.xindex |= AA_X_UNSAFE;
+	} else
+		/* fail exec */
+		error = -EACCES;
+
+	if (!new_profile)
+		goto audit;
+
+	if (bprm->unsafe & LSM_UNSAFE_SHARE) {
+		/* FIXME: currently don't mediate shared state */
+		;
+	}
+
+	if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
+		error = may_change_ptraced_domain(current, new_profile);
+		if (error) {
+			aa_put_profile(new_profile);
+			goto audit;
+		}
+	}
+
+	/* Determine if secure exec is needed.
+	 * Can be at this point for the following reasons:
+	 * 1. unconfined switching to confined
+	 * 2. confined switching to different confinement
+	 * 3. confined switching to unconfined
+	 *
+	 * Cases 2 and 3 are marked as requiring secure exec
+	 * (unless policy specified "unsafe exec")
+	 *
+	 * bprm->unsafe is used to cache the AA_X_UNSAFE permission
+	 * to avoid having to recompute in secureexec
+	 */
+	if (!(perms.xindex & AA_X_UNSAFE)) {
+		AA_DEBUG("scrubbing environment variables for %s profile=%s\n",
+			 name, new_profile->base.hname);
+		bprm->unsafe |= AA_SECURE_X_NEEDED;
+	}
+apply:
+	target = new_profile->base.hname;
+	/* when transitioning profiles clear unsafe personality bits */
+	bprm->per_clear |= PER_CLEAR_ON_SETID;
+
+x_clear:
+	aa_put_profile(cxt->profile);
+	/* transfer new profile reference will be released when cxt is freed */
+	cxt->profile = new_profile;
+
+	/* clear out all temporary/transitional state from the context */
+	aa_put_profile(cxt->previous);
+	aa_put_profile(cxt->onexec);
+	cxt->previous = NULL;
+	cxt->onexec = NULL;
+	cxt->token = 0;
+
+audit:
+	error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC,
+			      name, target, cond.uid, info, error);
+
+cleanup:
+	aa_put_profile(profile);
+	kfree(buffer);
+
+	return error;
+}
+
+/**
+ * apparmor_bprm_secureexec - determine if secureexec is needed
+ * @bprm: binprm for exec  (NOT NULL)
+ *
+ * Returns: %1 if secureexec is needed else %0
+ */
+int apparmor_bprm_secureexec(struct linux_binprm *bprm)
+{
+	int ret = cap_bprm_secureexec(bprm);
+
+	/* the decision to use secure exec is computed in set_creds
+	 * and stored in bprm->unsafe.
+	 */
+	if (!ret && (bprm->unsafe & AA_SECURE_X_NEEDED))
+		ret = 1;
+
+	return ret;
+}
+
+/**
+ * apparmor_bprm_committing_creds - do task cleanup on committing new creds
+ * @bprm: binprm for the exec  (NOT NULL)
+ */
+void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
+{
+	struct aa_profile *profile = __aa_current_profile();
+	struct aa_task_cxt *new_cxt = bprm->cred->security;
+
+	/* bail out if unconfined or not changing profile */
+	if ((new_cxt->profile == profile) ||
+	    (unconfined(new_cxt->profile)))
+		return;
+
+	current->pdeath_signal = 0;
+
+	/* reset soft limits and set hard limits for the new profile */
+	__aa_transition_rlimits(profile, new_cxt->profile);
+}
+
+/**
+ * apparmor_bprm_commited_cred - do cleanup after new creds committed
+ * @bprm: binprm for the exec  (NOT NULL)
+ */
+void apparmor_bprm_committed_creds(struct linux_binprm *bprm)
+{
+	/* TODO: cleanup signals - ipc mediation */
+	return;
+}
+
+/*
+ * Functions for self directed profile change
+ */
+
+/**
+ * new_compound_name - create an hname with @n2 appended to @n1
+ * @n1: base of hname  (NOT NULL)
+ * @n2: name to append (NOT NULL)
+ *
+ * Returns: new name or NULL on error
+ */
+static char *new_compound_name(const char *n1, const char *n2)
+{
+	char *name = kmalloc(strlen(n1) + strlen(n2) + 3, GFP_KERNEL);
+	if (name)
+		sprintf(name, "%s//%s", n1, n2);
+	return name;
+}
+
+/**
+ * aa_change_hat - change hat to/from subprofile
+ * @hats: vector of hat names to try changing into (MAYBE NULL if @count == 0)
+ * @count: number of hat names in @hats
+ * @token: magic value to validate the hat change
+ * @permtest: true if this is just a permission test
+ *
+ * Change to the first profile specified in @hats that exists, and store
+ * the @hat_magic in the current task context.  If the count == 0 and the
+ * @token matches that stored in the current task context, return to the
+ * top level profile.
+ *
+ * Returns %0 on success, error otherwise.
+ */
+int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
+{
+	const struct cred *cred;
+	struct aa_task_cxt *cxt;
+	struct aa_profile *profile, *previous_profile, *hat = NULL;
+	char *name = NULL;
+	int i;
+	struct file_perms perms = {};
+	const char *target = NULL, *info = NULL;
+	int error = 0;
+
+	/* released below */
+	cred = get_current_cred();
+	cxt = cred->security;
+	profile = aa_cred_profile(cred);
+	previous_profile = cxt->previous;
+
+	if (unconfined(profile)) {
+		info = "unconfined";
+		error = -EPERM;
+		goto audit;
+	}
+
+	if (count) {
+		/* attempting to change into a new hat or switch to a sibling */
+		struct aa_profile *root;
+		root = PROFILE_IS_HAT(profile) ? profile->parent : profile;
+
+		/* find first matching hat */
+		for (i = 0; i < count && !hat; i++)
+			/* released below */
+			hat = aa_find_child(root, hats[i]);
+		if (!hat) {
+			if (!COMPLAIN_MODE(root) || permtest) {
+				if (list_empty(&root->base.profiles))
+					error = -ECHILD;
+				else
+					error = -ENOENT;
+				goto out;
+			}
+
+			/*
+			 * In complain mode and failed to match any hats.
+			 * Audit the failure is based off of the first hat
+			 * supplied.  This is done due how userspace
+			 * interacts with change_hat.
+			 *
+			 * TODO: Add logging of all failed hats
+			 */
+
+			/* freed below */
+			name = new_compound_name(root->base.hname, hats[0]);
+			target = name;
+			/* released below */
+			hat = aa_new_null_profile(profile, 1);
+			if (!hat) {
+				info = "failed null profile create";
+				error = -ENOMEM;
+				goto audit;
+			}
+		} else {
+			target = hat->base.hname;
+			if (!PROFILE_IS_HAT(hat)) {
+				info = "target not hat";
+				error = -EPERM;
+				goto audit;
+			}
+		}
+
+		error = may_change_ptraced_domain(current, hat);
+		if (error) {
+			info = "ptraced";
+			error = -EPERM;
+			goto audit;
+		}
+
+		if (!permtest) {
+			error = aa_set_current_hat(hat, token);
+			if (error == -EACCES)
+				/* kill task in case of brute force attacks */
+				perms.kill = AA_MAY_CHANGEHAT;
+			else if (name && !error)
+				/* reset error for learning of new hats */
+				error = -ENOENT;
+		}
+	} else if (previous_profile) {
+		/* Return to saved profile.  Kill task if restore fails
+		 * to avoid brute force attacks
+		 */
+		target = previous_profile->base.hname;
+		error = aa_restore_previous_profile(token);
+		perms.kill = AA_MAY_CHANGEHAT;
+	} else
+		/* ignore restores when there is no saved profile */
+		goto out;
+
+audit:
+	if (!permtest)
+		error = aa_audit_file(profile, &perms, GFP_KERNEL,
+				      OP_CHANGE_HAT, AA_MAY_CHANGEHAT, NULL,
+				      target, 0, info, error);
+
+out:
+	aa_put_profile(hat);
+	kfree(name);
+	put_cred(cred);
+
+	return error;
+}
+
+/**
+ * aa_change_profile - perform a one-way profile transition
+ * @ns_name: name of the profile namespace to change to (MAYBE NULL)
+ * @hname: name of profile to change to (MAYBE NULL)
+ * @onexec: whether this transition is to take place immediately or at exec
+ * @permtest: true if this is just a permission test
+ *
+ * Change to new profile @name.  Unlike with hats, there is no way
+ * to change back.  If @name isn't specified the current profile name is
+ * used.
+ * If @onexec then the transition is delayed until
+ * the next exec.
+ *
+ * Returns %0 on success, error otherwise.
+ */
+int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
+		      bool permtest)
+{
+	const struct cred *cred;
+	struct aa_task_cxt *cxt;
+	struct aa_profile *profile, *target = NULL;
+	struct aa_namespace *ns = NULL;
+	struct file_perms perms = {};
+	const char *name = NULL, *info = NULL;
+	int op, error = 0;
+	u32 request;
+
+	if (!hname && !ns_name)
+		return -EINVAL;
+
+	if (onexec) {
+		request = AA_MAY_ONEXEC;
+		op = OP_CHANGE_ONEXEC;
+	} else {
+		request = AA_MAY_CHANGE_PROFILE;
+		op = OP_CHANGE_PROFILE;
+	}
+
+	cred = get_current_cred();
+	cxt = cred->security;
+	profile = aa_cred_profile(cred);
+
+	if (ns_name) {
+		/* released below */
+		ns = aa_find_namespace(profile->ns, ns_name);
+		if (!ns) {
+			/* we don't create new namespace in complain mode */
+			name = ns_name;
+			info = "namespace not found";
+			error = -ENOENT;
+			goto audit;
+		}
+	} else
+		/* released below */
+		ns = aa_get_namespace(profile->ns);
+
+	/* if the name was not specified, use the name of the current profile */
+	if (!hname) {
+		if (unconfined(profile))
+			hname = ns->unconfined->base.hname;
+		else
+			hname = profile->base.hname;
+	}
+
+	perms = change_profile_perms(profile, ns, hname, request,
+				     profile->file.start);
+	if (!(perms.allow & request)) {
+		error = -EACCES;
+		goto audit;
+	}
+
+	/* released below */
+	target = aa_lookup_profile(ns, hname);
+	if (!target) {
+		info = "profile not found";
+		error = -ENOENT;
+		if (permtest || !COMPLAIN_MODE(profile))
+			goto audit;
+		/* released below */
+		target = aa_new_null_profile(profile, 0);
+		if (!target) {
+			info = "failed null profile create";
+			error = -ENOMEM;
+			goto audit;
+		}
+	}
+
+	/* check if tracing task is allowed to trace target domain */
+	error = may_change_ptraced_domain(current, target);
+	if (error) {
+		info = "ptrace prevents transition";
+		goto audit;
+	}
+
+	if (permtest)
+		goto audit;
+
+	if (onexec)
+		error = aa_set_current_onexec(target);
+	else
+		error = aa_replace_current_profile(target);
+
+audit:
+	if (!permtest)
+		error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request,
+				      name, hname, 0, info, error);
+
+	aa_put_namespace(ns);
+	aa_put_profile(target);
+	put_cred(cred);
+
+	return error;
+}
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
new file mode 100644
index 0000000..7312db7
--- /dev/null
+++ b/security/apparmor/file.c
@@ -0,0 +1,457 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor mediation of files
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/file.h"
+#include "include/match.h"
+#include "include/path.h"
+#include "include/policy.h"
+
+struct file_perms nullperms;
+
+
+/**
+ * audit_file_mask - convert mask to permission string
+ * @buffer: buffer to write string to (NOT NULL)
+ * @mask: permission mask to convert
+ */
+static void audit_file_mask(struct audit_buffer *ab, u32 mask)
+{
+	char str[10];
+
+	char *m = str;
+
+	if (mask & AA_EXEC_MMAP)
+		*m++ = 'm';
+	if (mask & (MAY_READ | AA_MAY_META_READ))
+		*m++ = 'r';
+	if (mask & (MAY_WRITE | AA_MAY_META_WRITE | AA_MAY_CHMOD |
+		    AA_MAY_CHOWN))
+		*m++ = 'w';
+	else if (mask & MAY_APPEND)
+		*m++ = 'a';
+	if (mask & AA_MAY_CREATE)
+		*m++ = 'c';
+	if (mask & AA_MAY_DELETE)
+		*m++ = 'd';
+	if (mask & AA_MAY_LINK)
+		*m++ = 'l';
+	if (mask & AA_MAY_LOCK)
+		*m++ = 'k';
+	if (mask & MAY_EXEC)
+		*m++ = 'x';
+	*m = '\0';
+
+	audit_log_string(ab, str);
+}
+
+/**
+ * file_audit_cb - call back for file specific audit fields
+ * @ab: audit_buffer  (NOT NULL)
+ * @va: audit struct to audit values of  (NOT NULL)
+ */
+static void file_audit_cb(struct audit_buffer *ab, void *va)
+{
+	struct common_audit_data *sa = va;
+	uid_t fsuid = current_fsuid();
+
+	if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
+		audit_log_format(ab, " requested_mask=");
+		audit_file_mask(ab, sa->aad.fs.request);
+	}
+	if (sa->aad.fs.denied & AA_AUDIT_FILE_MASK) {
+		audit_log_format(ab, " denied_mask=");
+		audit_file_mask(ab, sa->aad.fs.denied);
+	}
+	if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
+		audit_log_format(ab, " fsuid=%d", fsuid);
+		audit_log_format(ab, " ouid=%d", sa->aad.fs.ouid);
+	}
+
+	if (sa->aad.fs.target) {
+		audit_log_format(ab, " target=");
+		audit_log_untrustedstring(ab, sa->aad.fs.target);
+	}
+}
+
+/**
+ * aa_audit_file - handle the auditing of file operations
+ * @profile: the profile being enforced  (NOT NULL)
+ * @perms: the permissions computed for the request (NOT NULL)
+ * @gfp: allocation flags
+ * @op: operation being mediated
+ * @request: permissions requested
+ * @name: name of object being mediated (MAYBE NULL)
+ * @target: name of target (MAYBE NULL)
+ * @ouid: object uid
+ * @info: extra information message (MAYBE NULL)
+ * @error: 0 if operation allowed else failure error code
+ *
+ * Returns: %0 or error on failure
+ */
+int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
+		  gfp_t gfp, int op, u32 request, const char *name,
+		  const char *target, uid_t ouid, const char *info, int error)
+{
+	int type = AUDIT_APPARMOR_AUTO;
+	struct common_audit_data sa;
+	COMMON_AUDIT_DATA_INIT(&sa, NONE);
+	sa.aad.op = op,
+	sa.aad.fs.request = request;
+	sa.aad.name = name;
+	sa.aad.fs.target = target;
+	sa.aad.fs.ouid = ouid;
+	sa.aad.info = info;
+	sa.aad.error = error;
+
+	if (likely(!sa.aad.error)) {
+		u32 mask = perms->audit;
+
+		if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
+			mask = 0xffff;
+
+		/* mask off perms that are not being force audited */
+		sa.aad.fs.request &= mask;
+
+		if (likely(!sa.aad.fs.request))
+			return 0;
+		type = AUDIT_APPARMOR_AUDIT;
+	} else {
+		/* only report permissions that were denied */
+		sa.aad.fs.request = sa.aad.fs.request & ~perms->allow;
+
+		if (sa.aad.fs.request & perms->kill)
+			type = AUDIT_APPARMOR_KILL;
+
+		/* quiet known rejects, assumes quiet and kill do not overlap */
+		if ((sa.aad.fs.request & perms->quiet) &&
+		    AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+		    AUDIT_MODE(profile) != AUDIT_ALL)
+			sa.aad.fs.request &= ~perms->quiet;
+
+		if (!sa.aad.fs.request)
+			return COMPLAIN_MODE(profile) ? 0 : sa.aad.error;
+	}
+
+	sa.aad.fs.denied = sa.aad.fs.request & ~perms->allow;
+	return aa_audit(type, profile, gfp, &sa, file_audit_cb);
+}
+
+/**
+ * map_old_perms - map old file perms layout to the new layout
+ * @old: permission set in old mapping
+ *
+ * Returns: new permission mapping
+ */
+static u32 map_old_perms(u32 old)
+{
+	u32 new = old & 0xf;
+	if (old & MAY_READ)
+		new |= AA_MAY_META_READ;
+	if (old & MAY_WRITE)
+		new |= AA_MAY_META_WRITE | AA_MAY_CREATE | AA_MAY_DELETE |
+			AA_MAY_CHMOD | AA_MAY_CHOWN;
+	if (old & 0x10)
+		new |= AA_MAY_LINK;
+	/* the old mapping lock and link_subset flags where overlaid
+	 * and use was determined by part of a pair that they were in
+	 */
+	if (old & 0x20)
+		new |= AA_MAY_LOCK | AA_LINK_SUBSET;
+	if (old & 0x40)	/* AA_EXEC_MMAP */
+		new |= AA_EXEC_MMAP;
+
+	new |= AA_MAY_META_READ;
+
+	return new;
+}
+
+/**
+ * compute_perms - convert dfa compressed perms to internal perms
+ * @dfa: dfa to compute perms for   (NOT NULL)
+ * @state: state in dfa
+ * @cond:  conditions to consider  (NOT NULL)
+ *
+ * TODO: convert from dfa + state to permission entry, do computation conversion
+ *       at load time.
+ *
+ * Returns: computed permission set
+ */
+static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state,
+				       struct path_cond *cond)
+{
+	struct file_perms perms;
+
+	/* FIXME: change over to new dfa format
+	 * currently file perms are encoded in the dfa, new format
+	 * splits the permissions from the dfa.  This mapping can be
+	 * done at profile load
+	 */
+	perms.kill = 0;
+
+	if (current_fsuid() == cond->uid) {
+		perms.allow = map_old_perms(dfa_user_allow(dfa, state));
+		perms.audit = map_old_perms(dfa_user_audit(dfa, state));
+		perms.quiet = map_old_perms(dfa_user_quiet(dfa, state));
+		perms.xindex = dfa_user_xindex(dfa, state);
+	} else {
+		perms.allow = map_old_perms(dfa_other_allow(dfa, state));
+		perms.audit = map_old_perms(dfa_other_audit(dfa, state));
+		perms.quiet = map_old_perms(dfa_other_quiet(dfa, state));
+		perms.xindex = dfa_other_xindex(dfa, state);
+	}
+
+	/* change_profile wasn't determined by ownership in old mapping */
+	if (ACCEPT_TABLE(dfa)[state] & 0x80000000)
+		perms.allow |= AA_MAY_CHANGE_PROFILE;
+
+	return perms;
+}
+
+/**
+ * aa_str_perms - find permission that match @name
+ * @dfa: to match against  (MAYBE NULL)
+ * @state: state to start matching in
+ * @name: string to match against dfa  (NOT NULL)
+ * @cond: conditions to consider for permission set computation  (NOT NULL)
+ * @perms: Returns - the permissions found when matching @name
+ *
+ * Returns: the final state in @dfa when beginning @start and walking @name
+ */
+unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
+			  const char *name, struct path_cond *cond,
+			  struct file_perms *perms)
+{
+	unsigned int state;
+	if (!dfa) {
+		*perms = nullperms;
+		return DFA_NOMATCH;
+	}
+
+	state = aa_dfa_match(dfa, start, name);
+	*perms = compute_perms(dfa, state, cond);
+
+	return state;
+}
+
+/**
+ * is_deleted - test if a file has been completely unlinked
+ * @dentry: dentry of file to test for deletion  (NOT NULL)
+ *
+ * Returns: %1 if deleted else %0
+ */
+static inline bool is_deleted(struct dentry *dentry)
+{
+	if (d_unlinked(dentry) && dentry->d_inode->i_nlink == 0)
+		return 1;
+	return 0;
+}
+
+/**
+ * aa_path_perm - do permissions check & audit for @path
+ * @op: operation being checked
+ * @profile: profile being enforced  (NOT NULL)
+ * @path: path to check permissions of  (NOT NULL)
+ * @flags: any additional path flags beyond what the profile specifies
+ * @request: requested permissions
+ * @cond: conditional info for this request  (NOT NULL)
+ *
+ * Returns: %0 else error if access denied or other error
+ */
+int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
+		 int flags, u32 request, struct path_cond *cond)
+{
+	char *buffer = NULL;
+	struct file_perms perms = {};
+	const char *name, *info = NULL;
+	int error;
+
+	flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0);
+	error = aa_get_name(path, flags, &buffer, &name);
+	if (error) {
+		if (error == -ENOENT && is_deleted(path->dentry)) {
+			/* Access to open files that are deleted are
+			 * give a pass (implicit delegation)
+			 */
+			error = 0;
+			perms.allow = request;
+		} else if (error == -ENOENT)
+			info = "Failed name lookup - deleted entry";
+		else if (error == -ESTALE)
+			info = "Failed name lookup - disconnected path";
+		else if (error == -ENAMETOOLONG)
+			info = "Failed name lookup - name too long";
+		else
+			info = "Failed name lookup";
+	} else {
+		aa_str_perms(profile->file.dfa, profile->file.start, name, cond,
+			     &perms);
+		if (request & ~perms.allow)
+			error = -EACCES;
+	}
+	error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, name,
+			      NULL, cond->uid, info, error);
+	kfree(buffer);
+
+	return error;
+}
+
+/**
+ * xindex_is_subset - helper for aa_path_link
+ * @link: link permission set
+ * @target: target permission set
+ *
+ * test target x permissions are equal OR a subset of link x permissions
+ * this is done as part of the subset test, where a hardlink must have
+ * a subset of permissions that the target has.
+ *
+ * Returns: %1 if subset else %0
+ */
+static inline bool xindex_is_subset(u32 link, u32 target)
+{
+	if (((link & ~AA_X_UNSAFE) != (target & ~AA_X_UNSAFE)) ||
+	    ((link & AA_X_UNSAFE) && !(target & AA_X_UNSAFE)))
+		return 0;
+
+	return 1;
+}
+
+/**
+ * aa_path_link - Handle hard link permission check
+ * @profile: the profile being enforced  (NOT NULL)
+ * @old_dentry: the target dentry  (NOT NULL)
+ * @new_dir: directory the new link will be created in  (NOT NULL)
+ * @new_dentry: the link being created  (NOT NULL)
+ *
+ * Handle the permission test for a link & target pair.  Permission
+ * is encoded as a pair where the link permission is determined
+ * first, and if allowed, the target is tested.  The target test
+ * is done from the point of the link match (not start of DFA)
+ * making the target permission dependent on the link permission match.
+ *
+ * The subset test if required forces that permissions granted
+ * on link are a subset of the permission granted to target.
+ *
+ * Returns: %0 if allowed else error
+ */
+int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
+		 struct path *new_dir, struct dentry *new_dentry)
+{
+	struct path link = { new_dir->mnt, new_dentry };
+	struct path target = { new_dir->mnt, old_dentry };
+	struct path_cond cond = {
+		old_dentry->d_inode->i_uid,
+		old_dentry->d_inode->i_mode
+	};
+	char *buffer = NULL, *buffer2 = NULL;
+	const char *lname, *tname = NULL, *info = NULL;
+	struct file_perms lperms, perms;
+	u32 request = AA_MAY_LINK;
+	unsigned int state;
+	int error;
+
+	lperms = nullperms;
+
+	/* buffer freed below, lname is pointer in buffer */
+	error = aa_get_name(&link, profile->path_flags, &buffer, &lname);
+	if (error)
+		goto audit;
+
+	/* buffer2 freed below, tname is pointer in buffer2 */
+	error = aa_get_name(&target, profile->path_flags, &buffer2, &tname);
+	if (error)
+		goto audit;
+
+	error = -EACCES;
+	/* aa_str_perms - handles the case of the dfa being NULL */
+	state = aa_str_perms(profile->file.dfa, profile->file.start, lname,
+			     &cond, &lperms);
+
+	if (!(lperms.allow & AA_MAY_LINK))
+		goto audit;
+
+	/* test to see if target can be paired with link */
+	state = aa_dfa_null_transition(profile->file.dfa, state);
+	aa_str_perms(profile->file.dfa, state, tname, &cond, &perms);
+
+	/* force audit/quiet masks for link are stored in the second entry
+	 * in the link pair.
+	 */
+	lperms.audit = perms.audit;
+	lperms.quiet = perms.quiet;
+	lperms.kill = perms.kill;
+
+	if (!(perms.allow & AA_MAY_LINK)) {
+		info = "target restricted";
+		goto audit;
+	}
+
+	/* done if link subset test is not required */
+	if (!(perms.allow & AA_LINK_SUBSET))
+		goto done_tests;
+
+	/* Do link perm subset test requiring allowed permission on link are a
+	 * subset of the allowed permissions on target.
+	 */
+	aa_str_perms(profile->file.dfa, profile->file.start, tname, &cond,
+		     &perms);
+
+	/* AA_MAY_LINK is not considered in the subset test */
+	request = lperms.allow & ~AA_MAY_LINK;
+	lperms.allow &= perms.allow | AA_MAY_LINK;
+
+	request |= AA_AUDIT_FILE_MASK & (lperms.allow & ~perms.allow);
+	if (request & ~lperms.allow) {
+		goto audit;
+	} else if ((lperms.allow & MAY_EXEC) &&
+		   !xindex_is_subset(lperms.xindex, perms.xindex)) {
+		lperms.allow &= ~MAY_EXEC;
+		request |= MAY_EXEC;
+		info = "link not subset of target";
+		goto audit;
+	}
+
+done_tests:
+	error = 0;
+
+audit:
+	error = aa_audit_file(profile, &lperms, GFP_KERNEL, OP_LINK, request,
+			      lname, tname, cond.uid, info, error);
+	kfree(buffer);
+	kfree(buffer2);
+
+	return error;
+}
+
+/**
+ * aa_file_perm - do permission revalidation check & audit for @file
+ * @op: operation being checked
+ * @profile: profile being enforced   (NOT NULL)
+ * @file: file to revalidate access permissions on  (NOT NULL)
+ * @request: requested permissions
+ *
+ * Returns: %0 if access allowed else error
+ */
+int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
+		 u32 request)
+{
+	struct path_cond cond = {
+		.uid = file->f_path.dentry->d_inode->i_uid,
+		.mode = file->f_path.dentry->d_inode->i_mode
+	};
+
+	return aa_path_perm(op, profile, &file->f_path, PATH_DELEGATE_DELETED,
+			    request, &cond);
+}
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
new file mode 100644
index 0000000..38ccaea
--- /dev/null
+++ b/security/apparmor/include/apparmor.h
@@ -0,0 +1,92 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor basic global and lib definitions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __APPARMOR_H
+#define __APPARMOR_H
+
+#include <linux/fs.h>
+
+#include "match.h"
+
+/* Control parameters settable through module/boot flags */
+extern enum audit_mode aa_g_audit;
+extern int aa_g_audit_header;
+extern int aa_g_debug;
+extern int aa_g_lock_policy;
+extern int aa_g_logsyscall;
+extern int aa_g_paranoid_load;
+extern unsigned int aa_g_path_max;
+
+/*
+ * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
+ * which is not related to profile accesses.
+ */
+
+#define AA_DEBUG(fmt, args...)						\
+	do {								\
+		if (aa_g_debug && printk_ratelimit())			\
+			printk(KERN_DEBUG "AppArmor: " fmt, ##args);	\
+	} while (0)
+
+#define AA_ERROR(fmt, args...)						\
+	do {								\
+		if (printk_ratelimit())					\
+			printk(KERN_ERR "AppArmor: " fmt, ##args);	\
+	} while (0)
+
+/* Flag indicating whether initialization completed */
+extern int apparmor_initialized __initdata;
+
+/* fn's in lib */
+char *aa_split_fqname(char *args, char **ns_name);
+void aa_info_message(const char *str);
+void *kvmalloc(size_t size);
+void kvfree(void *buffer);
+
+
+/**
+ * aa_strneq - compare null terminated @str to a non null terminated substring
+ * @str: a null terminated string
+ * @sub: a substring, not necessarily null terminated
+ * @len: length of @sub to compare
+ *
+ * The @str string must be full consumed for this to be considered a match
+ */
+static inline bool aa_strneq(const char *str, const char *sub, int len)
+{
+	return !strncmp(str, sub, len) && !str[len];
+}
+
+/**
+ * aa_dfa_null_transition - step to next state after null character
+ * @dfa: the dfa to match against
+ * @start: the state of the dfa to start matching in
+ *
+ * aa_dfa_null_transition transitions to the next state after a null
+ * character which is not used in standard matching and is only
+ * used to separate pairs.
+ */
+static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
+						  unsigned int start)
+{
+	/* the null transition only needs the string's null terminator byte */
+	return aa_dfa_match_len(dfa, start, "", 1);
+}
+
+static inline bool mediated_filesystem(struct inode *inode)
+{
+	return !(inode->i_sb->s_flags & MS_NOUSER);
+}
+
+#endif /* __APPARMOR_H */
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
new file mode 100644
index 0000000..cb1e93a
--- /dev/null
+++ b/security/apparmor/include/apparmorfs.h
@@ -0,0 +1,20 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor filesystem definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_APPARMORFS_H
+#define __AA_APPARMORFS_H
+
+extern void __init aa_destroy_aafs(void);
+
+#endif /* __AA_APPARMORFS_H */
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
new file mode 100644
index 0000000..1951786
--- /dev/null
+++ b/security/apparmor/include/audit.h
@@ -0,0 +1,123 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor auditing function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_AUDIT_H
+#define __AA_AUDIT_H
+
+#include <linux/audit.h>
+#include <linux/fs.h>
+#include <linux/lsm_audit.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "file.h"
+
+struct aa_profile;
+
+extern const char *audit_mode_names[];
+#define AUDIT_MAX_INDEX 5
+
+#define AUDIT_APPARMOR_AUTO 0	/* auto choose audit message type */
+
+enum audit_mode {
+	AUDIT_NORMAL,		/* follow normal auditing of accesses */
+	AUDIT_QUIET_DENIED,	/* quiet all denied access messages */
+	AUDIT_QUIET,		/* quiet all messages */
+	AUDIT_NOQUIET,		/* do not quiet audit messages */
+	AUDIT_ALL		/* audit all accesses */
+};
+
+enum audit_type {
+	AUDIT_APPARMOR_AUDIT,
+	AUDIT_APPARMOR_ALLOWED,
+	AUDIT_APPARMOR_DENIED,
+	AUDIT_APPARMOR_HINT,
+	AUDIT_APPARMOR_STATUS,
+	AUDIT_APPARMOR_ERROR,
+	AUDIT_APPARMOR_KILL
+};
+
+extern const char *op_table[];
+enum aa_ops {
+	OP_NULL,
+
+	OP_SYSCTL,
+	OP_CAPABLE,
+
+	OP_UNLINK,
+	OP_MKDIR,
+	OP_RMDIR,
+	OP_MKNOD,
+	OP_TRUNC,
+	OP_LINK,
+	OP_SYMLINK,
+	OP_RENAME_SRC,
+	OP_RENAME_DEST,
+	OP_CHMOD,
+	OP_CHOWN,
+	OP_GETATTR,
+	OP_OPEN,
+
+	OP_FPERM,
+	OP_FLOCK,
+	OP_FMMAP,
+	OP_FMPROT,
+
+	OP_CREATE,
+	OP_POST_CREATE,
+	OP_BIND,
+	OP_CONNECT,
+	OP_LISTEN,
+	OP_ACCEPT,
+	OP_SENDMSG,
+	OP_RECVMSG,
+	OP_GETSOCKNAME,
+	OP_GETPEERNAME,
+	OP_GETSOCKOPT,
+	OP_SETSOCKOPT,
+	OP_SOCK_SHUTDOWN,
+
+	OP_PTRACE,
+
+	OP_EXEC,
+	OP_CHANGE_HAT,
+	OP_CHANGE_PROFILE,
+	OP_CHANGE_ONEXEC,
+
+	OP_SETPROCATTR,
+	OP_SETRLIMIT,
+
+	OP_PROF_REPL,
+	OP_PROF_LOAD,
+	OP_PROF_RM,
+};
+
+
+/* define a short hand for apparmor_audit_data portion of common_audit_data */
+#define aad apparmor_audit_data
+
+void aa_audit_msg(int type, struct common_audit_data *sa,
+		  void (*cb) (struct audit_buffer *, void *));
+int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
+	     struct common_audit_data *sa,
+	     void (*cb) (struct audit_buffer *, void *));
+
+static inline int complain_error(int error)
+{
+	if (error == -EPERM || error == -EACCES)
+		return 0;
+	return error;
+}
+
+#endif /* __AA_AUDIT_H */
diff --git a/security/apparmor/include/capability.h b/security/apparmor/include/capability.h
new file mode 100644
index 0000000..c24d295
--- /dev/null
+++ b/security/apparmor/include/capability.h
@@ -0,0 +1,45 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor capability mediation definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_CAPABILITY_H
+#define __AA_CAPABILITY_H
+
+#include <linux/sched.h>
+
+struct aa_profile;
+
+/* aa_caps - confinement data for capabilities
+ * @allowed: capabilities mask
+ * @audit: caps that are to be audited
+ * @quiet: caps that should not be audited
+ * @kill: caps that when requested will result in the task being killed
+ * @extended: caps that are subject finer grained mediation
+ */
+struct aa_caps {
+	kernel_cap_t allow;
+	kernel_cap_t audit;
+	kernel_cap_t quiet;
+	kernel_cap_t kill;
+	kernel_cap_t extended;
+};
+
+int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
+	       int audit);
+
+static inline void aa_free_cap_rules(struct aa_caps *caps)
+{
+	/* NOP */
+}
+
+#endif /* __AA_CAPBILITY_H */
diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h
new file mode 100644
index 0000000..a9cbee4
--- /dev/null
+++ b/security/apparmor/include/context.h
@@ -0,0 +1,154 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor contexts used to associate "labels" to objects.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_CONTEXT_H
+#define __AA_CONTEXT_H
+
+#include <linux/cred.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include "policy.h"
+
+/* struct aa_file_cxt - the AppArmor context the file was opened in
+ * @perms: the permission the file was opened with
+ *
+ * The file_cxt could currently be directly stored in file->f_security
+ * as the profile reference is now stored in the f_cred.  However the
+ * cxt struct will expand in the future so we keep the struct.
+ */
+struct aa_file_cxt {
+	u16 allow;
+};
+
+/**
+ * aa_alloc_file_context - allocate file_cxt
+ * @gfp: gfp flags for allocation
+ *
+ * Returns: file_cxt or NULL on failure
+ */
+static inline struct aa_file_cxt *aa_alloc_file_context(gfp_t gfp)
+{
+	return kzalloc(sizeof(struct aa_file_cxt), gfp);
+}
+
+/**
+ * aa_free_file_context - free a file_cxt
+ * @cxt: file_cxt to free  (MAYBE_NULL)
+ */
+static inline void aa_free_file_context(struct aa_file_cxt *cxt)
+{
+	if (cxt)
+		kzfree(cxt);
+}
+
+/**
+ * struct aa_task_cxt - primary label for confined tasks
+ * @profile: the current profile   (NOT NULL)
+ * @exec: profile to transition to on next exec  (MAYBE NULL)
+ * @previous: profile the task may return to     (MAYBE NULL)
+ * @token: magic value the task must know for returning to @previous_profile
+ *
+ * Contains the task's current profile (which could change due to
+ * change_hat).  Plus the hat_magic needed during change_hat.
+ *
+ * TODO: make so a task can be confined by a stack of contexts
+ */
+struct aa_task_cxt {
+	struct aa_profile *profile;
+	struct aa_profile *onexec;
+	struct aa_profile *previous;
+	u64 token;
+};
+
+struct aa_task_cxt *aa_alloc_task_context(gfp_t flags);
+void aa_free_task_context(struct aa_task_cxt *cxt);
+void aa_dup_task_context(struct aa_task_cxt *new,
+			 const struct aa_task_cxt *old);
+int aa_replace_current_profile(struct aa_profile *profile);
+int aa_set_current_onexec(struct aa_profile *profile);
+int aa_set_current_hat(struct aa_profile *profile, u64 token);
+int aa_restore_previous_profile(u64 cookie);
+
+/**
+ * __aa_task_is_confined - determine if @task has any confinement
+ * @task: task to check confinement of  (NOT NULL)
+ *
+ * If @task != current needs to be called in RCU safe critical section
+ */
+static inline bool __aa_task_is_confined(struct task_struct *task)
+{
+	struct aa_task_cxt *cxt = __task_cred(task)->security;
+
+	BUG_ON(!cxt || !cxt->profile);
+	if (unconfined(aa_newest_version(cxt->profile)))
+		return 0;
+
+	return 1;
+}
+
+/**
+ * aa_cred_profile - obtain cred's profiles
+ * @cred: cred to obtain profiles from  (NOT NULL)
+ *
+ * Returns: confining profile
+ *
+ * does NOT increment reference count
+ */
+static inline struct aa_profile *aa_cred_profile(const struct cred *cred)
+{
+	struct aa_task_cxt *cxt = cred->security;
+	BUG_ON(!cxt || !cxt->profile);
+	return aa_newest_version(cxt->profile);
+}
+
+/**
+ * __aa_current_profile - find the current tasks confining profile
+ *
+ * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
+ *
+ * This fn will not update the tasks cred to the most up to date version
+ * of the profile so it is safe to call when inside of locks.
+ */
+static inline struct aa_profile *__aa_current_profile(void)
+{
+	return aa_cred_profile(current_cred());
+}
+
+/**
+ * aa_current_profile - find the current tasks confining profile and do updates
+ *
+ * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
+ *
+ * This fn will update the tasks cred structure if the profile has been
+ * replaced.  Not safe to call inside locks
+ */
+static inline struct aa_profile *aa_current_profile(void)
+{
+	const struct aa_task_cxt *cxt = current_cred()->security;
+	struct aa_profile *profile;
+	BUG_ON(!cxt || !cxt->profile);
+
+	profile = aa_newest_version(cxt->profile);
+	/*
+	 * Whether or not replacement succeeds, use newest profile so
+	 * there is no need to update it after replacement.
+	 */
+	if (unlikely((cxt->profile != profile)))
+		aa_replace_current_profile(profile);
+
+	return profile;
+}
+
+#endif /* __AA_CONTEXT_H */
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
new file mode 100644
index 0000000..de04464
--- /dev/null
+++ b/security/apparmor/include/domain.h
@@ -0,0 +1,36 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor security domain transition function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#include <linux/binfmts.h>
+#include <linux/types.h>
+
+#ifndef __AA_DOMAIN_H
+#define __AA_DOMAIN_H
+
+struct aa_domain {
+	int size;
+	char **table;
+};
+
+int apparmor_bprm_set_creds(struct linux_binprm *bprm);
+int apparmor_bprm_secureexec(struct linux_binprm *bprm);
+void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
+void apparmor_bprm_committed_creds(struct linux_binprm *bprm);
+
+void aa_free_domain_entries(struct aa_domain *domain);
+int aa_change_hat(const char *hats[], int count, u64 token, bool permtest);
+int aa_change_profile(const char *ns_name, const char *name, bool onexec,
+		      bool permtest);
+
+#endif /* __AA_DOMAIN_H */
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
new file mode 100644
index 0000000..be36fea
--- /dev/null
+++ b/security/apparmor/include/file.h
@@ -0,0 +1,217 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor file mediation function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_FILE_H
+#define __AA_FILE_H
+
+#include <linux/path.h>
+
+#include "domain.h"
+#include "match.h"
+
+struct aa_profile;
+
+/*
+ * We use MAY_EXEC, MAY_WRITE, MAY_READ, MAY_APPEND and the following flags
+ * for profile permissions
+ */
+#define AA_MAY_CREATE                  0x0010
+#define AA_MAY_DELETE                  0x0020
+#define AA_MAY_META_WRITE              0x0040
+#define AA_MAY_META_READ               0x0080
+
+#define AA_MAY_CHMOD                   0x0100
+#define AA_MAY_CHOWN                   0x0200
+#define AA_MAY_LOCK                    0x0400
+#define AA_EXEC_MMAP                   0x0800
+
+#define AA_MAY_LINK			0x1000
+#define AA_LINK_SUBSET			AA_MAY_LOCK	/* overlaid */
+#define AA_MAY_ONEXEC			0x40000000	/* exec allows onexec */
+#define AA_MAY_CHANGE_PROFILE		0x80000000
+#define AA_MAY_CHANGEHAT		0x80000000	/* ctrl auditing only */
+
+#define AA_AUDIT_FILE_MASK	(MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND |\
+				 AA_MAY_CREATE | AA_MAY_DELETE |	\
+				 AA_MAY_META_READ | AA_MAY_META_WRITE | \
+				 AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
+				 AA_EXEC_MMAP | AA_MAY_LINK)
+
+/*
+ * The xindex is broken into 3 parts
+ * - index - an index into either the exec name table or the variable table
+ * - exec type - which determines how the executable name and index are used
+ * - flags - which modify how the destination name is applied
+ */
+#define AA_X_INDEX_MASK		0x03ff
+
+#define AA_X_TYPE_MASK		0x0c00
+#define AA_X_TYPE_SHIFT		10
+#define AA_X_NONE		0x0000
+#define AA_X_NAME		0x0400	/* use executable name px */
+#define AA_X_TABLE		0x0800	/* use a specified name ->n# */
+
+#define AA_X_UNSAFE		0x1000
+#define AA_X_CHILD		0x2000	/* make >AA_X_NONE apply to children */
+#define AA_X_INHERIT		0x4000
+#define AA_X_UNCONFINED		0x8000
+
+/* AA_SECURE_X_NEEDED - is passed in the bprm->unsafe field */
+#define AA_SECURE_X_NEEDED	0x8000
+
+/* need to make conditional which ones are being set */
+struct path_cond {
+	uid_t uid;
+	umode_t mode;
+};
+
+/* struct file_perms - file permission
+ * @allow: mask of permissions that are allowed
+ * @audit: mask of permissions to force an audit message for
+ * @quiet: mask of permissions to quiet audit messages for
+ * @kill: mask of permissions that when matched will kill the task
+ * @xindex: exec transition index if @allow contains MAY_EXEC
+ *
+ * The @audit and @queit mask should be mutually exclusive.
+ */
+struct file_perms {
+	u32 allow;
+	u32 audit;
+	u32 quiet;
+	u32 kill;
+	u16 xindex;
+};
+
+extern struct file_perms nullperms;
+
+#define COMBINED_PERM_MASK(X) ((X).allow | (X).audit | (X).quiet | (X).kill)
+
+/* FIXME: split perms from dfa and match this to description
+ *        also add delegation info.
+ */
+static inline u16 dfa_map_xindex(u16 mask)
+{
+	u16 old_index = (mask >> 10) & 0xf;
+	u16 index = 0;
+
+	if (mask & 0x100)
+		index |= AA_X_UNSAFE;
+	if (mask & 0x200)
+		index |= AA_X_INHERIT;
+	if (mask & 0x80)
+		index |= AA_X_UNCONFINED;
+
+	if (old_index == 1) {
+		index |= AA_X_UNCONFINED;
+	} else if (old_index == 2) {
+		index |= AA_X_NAME;
+	} else if (old_index == 3) {
+		index |= AA_X_NAME | AA_X_CHILD;
+	} else {
+		index |= AA_X_TABLE;
+		index |= old_index - 4;
+	}
+
+	return index;
+}
+
+/*
+ * map old dfa inline permissions to new format
+ */
+#define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \
+				    ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
+#define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f)
+#define dfa_user_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f)
+#define dfa_user_xindex(dfa, state) \
+	(dfa_map_xindex(ACCEPT_TABLE(dfa)[state] & 0x3fff))
+
+#define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \
+				      0x7f) |				\
+				     ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
+#define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f)
+#define dfa_other_quiet(dfa, state) \
+	((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f)
+#define dfa_other_xindex(dfa, state) \
+	dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff)
+
+int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
+		  gfp_t gfp, int op, u32 request, const char *name,
+		  const char *target, uid_t ouid, const char *info, int error);
+
+/**
+ * struct aa_file_rules - components used for file rule permissions
+ * @dfa: dfa to match path names and conditionals against
+ * @perms: permission table indexed by the matched state accept entry of @dfa
+ * @trans: transition table for indexed by named x transitions
+ *
+ * File permission are determined by matching a path against @dfa and then
+ * then using the value of the accept entry for the matching state as
+ * an index into @perms.  If a named exec transition is required it is
+ * looked up in the transition table.
+ */
+struct aa_file_rules {
+	unsigned int start;
+	struct aa_dfa *dfa;
+	/* struct perms perms; */
+	struct aa_domain trans;
+	/* TODO: add delegate table */
+};
+
+unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
+			  const char *name, struct path_cond *cond,
+			  struct file_perms *perms);
+
+int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
+		 int flags, u32 request, struct path_cond *cond);
+
+int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
+		 struct path *new_dir, struct dentry *new_dentry);
+
+int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
+		 u32 request);
+
+static inline void aa_free_file_rules(struct aa_file_rules *rules)
+{
+	aa_put_dfa(rules->dfa);
+	aa_free_domain_entries(&rules->trans);
+}
+
+#define ACC_FMODE(x) (("\000\004\002\006"[(x)&O_ACCMODE]) | (((x) << 1) & 0x40))
+
+/* from namei.c */
+#define MAP_OPEN_FLAGS(x) ((((x) + 1) & O_ACCMODE) ? (x) + 1 : (x))
+
+/**
+ * aa_map_file_perms - map file flags to AppArmor permissions
+ * @file: open file to map flags to AppArmor permissions
+ *
+ * Returns: apparmor permission set for the file
+ */
+static inline u32 aa_map_file_to_perms(struct file *file)
+{
+	int flags = MAP_OPEN_FLAGS(file->f_flags);
+	u32 perms = ACC_FMODE(file->f_mode);
+
+	if ((flags & O_APPEND) && (perms & MAY_WRITE))
+		perms = (perms & ~MAY_WRITE) | MAY_APPEND;
+	/* trunc implies write permission */
+	if (flags & O_TRUNC)
+		perms |= MAY_WRITE;
+	if (flags & O_CREAT)
+		perms |= AA_MAY_CREATE;
+
+	return perms;
+}
+
+#endif /* __AA_FILE_H */
diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h
new file mode 100644
index 0000000..aeda0fb
--- /dev/null
+++ b/security/apparmor/include/ipc.h
@@ -0,0 +1,28 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor ipc mediation function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_IPC_H
+#define __AA_IPC_H
+
+#include <linux/sched.h>
+
+struct aa_profile;
+
+int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
+		  struct aa_profile *tracee, unsigned int mode);
+
+int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
+	      unsigned int mode);
+
+#endif /* __AA_IPC_H */
diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
new file mode 100644
index 0000000..734a6d3
--- /dev/null
+++ b/security/apparmor/include/match.h
@@ -0,0 +1,132 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy dfa matching engine definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_MATCH_H
+#define __AA_MATCH_H
+
+#include <linux/workqueue.h>
+
+#define DFA_NOMATCH			0
+#define DFA_START			1
+
+#define DFA_VALID_PERM_MASK		0xffffffff
+#define DFA_VALID_PERM2_MASK		0xffffffff
+
+/**
+ * The format used for transition tables is based on the GNU flex table
+ * file format (--tables-file option; see Table File Format in the flex
+ * info pages and the flex sources for documentation). The magic number
+ * used in the header is 0x1B5E783D insted of 0xF13C57B1 though, because
+ * the YY_ID_CHK (check) and YY_ID_DEF (default) tables are used
+ * slightly differently (see the apparmor-parser package).
+ */
+
+#define YYTH_MAGIC	0x1B5E783D
+#define YYTH_DEF_RECURSE 0x1			/* DEF Table is recursive */
+
+struct table_set_header {
+	u32 th_magic;		/* YYTH_MAGIC */
+	u32 th_hsize;
+	u32 th_ssize;
+	u16 th_flags;
+	char th_version[];
+};
+
+/* The YYTD_ID are one less than flex table mappings.  The flex id
+ * has 1 subtracted at table load time, this allows us to directly use the
+ * ID's as indexes.
+ */
+#define	YYTD_ID_ACCEPT	0
+#define YYTD_ID_BASE	1
+#define YYTD_ID_CHK	2
+#define YYTD_ID_DEF	3
+#define YYTD_ID_EC	4
+#define YYTD_ID_META	5
+#define YYTD_ID_ACCEPT2 6
+#define YYTD_ID_NXT	7
+#define YYTD_ID_TSIZE	8
+
+#define YYTD_DATA8	1
+#define YYTD_DATA16	2
+#define YYTD_DATA32	4
+#define YYTD_DATA64	8
+
+/* Each ACCEPT2 table gets 6 dedicated flags, YYTD_DATAX define the
+ * first flags
+ */
+#define ACCEPT1_FLAGS(X) ((X) & 0x3f)
+#define ACCEPT2_FLAGS(X) ACCEPT1_FLAGS((X) >> YYTD_ID_ACCEPT2)
+#define TO_ACCEPT1_FLAG(X) ACCEPT1_FLAGS(X)
+#define TO_ACCEPT2_FLAG(X) (ACCEPT1_FLAGS(X) << YYTD_ID_ACCEPT2)
+#define DFA_FLAG_VERIFY_STATES 0x1000
+
+struct table_header {
+	u16 td_id;
+	u16 td_flags;
+	u32 td_hilen;
+	u32 td_lolen;
+	char td_data[];
+};
+
+#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF]->td_data))
+#define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE]->td_data))
+#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT]->td_data))
+#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK]->td_data))
+#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC]->td_data))
+#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT]->td_data))
+#define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2]->td_data))
+
+struct aa_dfa {
+	struct kref count;
+	u16 flags;
+	struct table_header *tables[YYTD_ID_TSIZE];
+};
+
+#define byte_to_byte(X) (X)
+
+#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
+	do { \
+		typeof(LEN) __i; \
+		TYPE *__t = (TYPE *) TABLE; \
+		TYPE *__b = (TYPE *) BLOB; \
+		for (__i = 0; __i < LEN; __i++) { \
+			__t[__i] = NTOHX(__b[__i]); \
+		} \
+	} while (0)
+
+static inline size_t table_size(size_t len, size_t el_size)
+{
+	return ALIGN(sizeof(struct table_header) + len * el_size, 8);
+}
+
+struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags);
+unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
+			      const char *str, int len);
+unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
+			  const char *str);
+void aa_dfa_free_kref(struct kref *kref);
+
+/**
+ * aa_put_dfa - put a dfa refcount
+ * @dfa: dfa to put refcount   (MAYBE NULL)
+ *
+ * Requires: if @dfa != NULL that a valid refcount be held
+ */
+static inline void aa_put_dfa(struct aa_dfa *dfa)
+{
+	if (dfa)
+		kref_put(&dfa->count, aa_dfa_free_kref);
+}
+
+#endif /* __AA_MATCH_H */
diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h
new file mode 100644
index 0000000..27b327a
--- /dev/null
+++ b/security/apparmor/include/path.h
@@ -0,0 +1,31 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor basic path manipulation function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_PATH_H
+#define __AA_PATH_H
+
+
+enum path_flags {
+	PATH_IS_DIR = 0x1,		/* path is a directory */
+	PATH_CONNECT_PATH = 0x4,	/* connect disconnected paths to / */
+	PATH_CHROOT_REL = 0x8,		/* do path lookup relative to chroot */
+	PATH_CHROOT_NSCONNECT = 0x10,	/* connect paths that are at ns root */
+
+	PATH_DELEGATE_DELETED = 0x08000, /* delegate deleted files */
+	PATH_MEDIATE_DELETED = 0x10000,	/* mediate deleted paths */
+};
+
+int aa_get_name(struct path *path, int flags, char **buffer, const char **name);
+
+#endif /* __AA_PATH_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
new file mode 100644
index 0000000..aeda5cf
--- /dev/null
+++ b/security/apparmor/include/policy.h
@@ -0,0 +1,305 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_POLICY_H
+#define __AA_POLICY_H
+
+#include <linux/capability.h>
+#include <linux/cred.h>
+#include <linux/kref.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+
+#include "apparmor.h"
+#include "audit.h"
+#include "capability.h"
+#include "domain.h"
+#include "file.h"
+#include "resource.h"
+
+extern const char *profile_mode_names[];
+#define APPARMOR_NAMES_MAX_INDEX 3
+
+#define COMPLAIN_MODE(_profile)	\
+	((aa_g_profile_mode == APPARMOR_COMPLAIN) || \
+	 ((_profile)->mode == APPARMOR_COMPLAIN))
+
+#define KILL_MODE(_profile) \
+	((aa_g_profile_mode == APPARMOR_KILL) || \
+	 ((_profile)->mode == APPARMOR_KILL))
+
+#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
+
+/*
+ * FIXME: currently need a clean way to replace and remove profiles as a
+ * set.  It should be done at the namespace level.
+ * Either, with a set of profiles loaded at the namespace level or via
+ * a mark and remove marked interface.
+ */
+enum profile_mode {
+	APPARMOR_ENFORCE,	/* enforce access rules */
+	APPARMOR_COMPLAIN,	/* allow and log access violations */
+	APPARMOR_KILL,		/* kill task on access violation */
+};
+
+enum profile_flags {
+	PFLAG_HAT = 1,			/* profile is a hat */
+	PFLAG_UNCONFINED = 2,		/* profile is an unconfined profile */
+	PFLAG_NULL = 4,			/* profile is null learning profile */
+	PFLAG_IX_ON_NAME_ERROR = 8,	/* fallback to ix on name lookup fail */
+	PFLAG_IMMUTABLE = 0x10,		/* don't allow changes/replacement */
+	PFLAG_USER_DEFINED = 0x20,	/* user based profile - lower privs */
+	PFLAG_NO_LIST_REF = 0x40,	/* list doesn't keep profile ref */
+	PFLAG_OLD_NULL_TRANS = 0x100,	/* use // as the null transition */
+
+	/* These flags must correspond with PATH_flags */
+	PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */
+};
+
+struct aa_profile;
+
+/* struct aa_policy - common part of both namespaces and profiles
+ * @name: name of the object
+ * @hname - The hierarchical name
+ * @count: reference count of the obj
+ * @list: list policy object is on
+ * @profiles: head of the profiles list contained in the object
+ */
+struct aa_policy {
+	char *name;
+	char *hname;
+	struct kref count;
+	struct list_head list;
+	struct list_head profiles;
+};
+
+/* struct aa_ns_acct - accounting of profiles in namespace
+ * @max_size: maximum space allowed for all profiles in namespace
+ * @max_count: maximum number of profiles that can be in this namespace
+ * @size: current size of profiles
+ * @count: current count of profiles (includes null profiles)
+ */
+struct aa_ns_acct {
+	int max_size;
+	int max_count;
+	int size;
+	int count;
+};
+
+/* struct aa_namespace - namespace for a set of profiles
+ * @base: common policy
+ * @parent: parent of namespace
+ * @lock: lock for modifying the object
+ * @acct: accounting for the namespace
+ * @unconfined: special unconfined profile for the namespace
+ * @sub_ns: list of namespaces under the current namespace.
+ *
+ * An aa_namespace defines the set profiles that are searched to determine
+ * which profile to attach to a task.  Profiles can not be shared between
+ * aa_namespaces and profile names within a namespace are guaranteed to be
+ * unique.  When profiles in separate namespaces have the same name they
+ * are NOT considered to be equivalent.
+ *
+ * Namespaces are hierarchical and only namespaces and profiles below the
+ * current namespace are visible.
+ *
+ * Namespace names must be unique and can not contain the characters :/\0
+ *
+ * FIXME TODO: add vserver support of namespaces (can it all be done in
+ *             userspace?)
+ */
+struct aa_namespace {
+	struct aa_policy base;
+	struct aa_namespace *parent;
+	rwlock_t lock;
+	struct aa_ns_acct acct;
+	struct aa_profile *unconfined;
+	struct list_head sub_ns;
+};
+
+/* struct aa_profile - basic confinement data
+ * @base - base components of the profile (name, refcount, lists, lock ...)
+ * @parent: parent of profile
+ * @ns: namespace the profile is in
+ * @replacedby: is set to the profile that replaced this profile
+ * @rename: optional profile name that this profile renamed
+ * @xmatch: optional extended matching for unconfined executables names
+ * @xmatch_len: xmatch prefix len, used to determine xmatch priority
+ * @sid: the unique security id number of this profile
+ * @audit: the auditing mode of the profile
+ * @mode: the enforcement mode of the profile
+ * @flags: flags controlling profile behavior
+ * @path_flags: flags controlling path generation behavior
+ * @size: the memory consumed by this profiles rules
+ * @file: The set of rules governing basic file access and domain transitions
+ * @caps: capabilities for the profile
+ * @rlimits: rlimits for the profile
+ *
+ * The AppArmor profile contains the basic confinement data.  Each profile
+ * has a name, and exists in a namespace.  The @name and @exec_match are
+ * used to determine profile attachment against unconfined tasks.  All other
+ * attachments are determined by profile X transition rules.
+ *
+ * The @replacedby field is write protected by the profile lock.  Reads
+ * are assumed to be atomic, and are done without locking.
+ *
+ * Profiles have a hierarchy where hats and children profiles keep
+ * a reference to their parent.
+ *
+ * Profile names can not begin with a : and can not contain the \0
+ * character.  If a profile name begins with / it will be considered when
+ * determining profile attachment on "unconfined" tasks.
+ */
+struct aa_profile {
+	struct aa_policy base;
+	struct aa_profile *parent;
+
+	struct aa_namespace *ns;
+	struct aa_profile *replacedby;
+	const char *rename;
+
+	struct aa_dfa *xmatch;
+	int xmatch_len;
+	u32 sid;
+	enum audit_mode audit;
+	enum profile_mode mode;
+	u32 flags;
+	u32 path_flags;
+	int size;
+
+	struct aa_file_rules file;
+	struct aa_caps caps;
+	struct aa_rlimit rlimits;
+};
+
+extern struct aa_namespace *root_ns;
+extern enum profile_mode aa_g_profile_mode;
+
+void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
+
+bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view);
+const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child);
+int aa_alloc_root_ns(void);
+void aa_free_root_ns(void);
+void aa_free_namespace_kref(struct kref *kref);
+
+struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
+				       const char *name);
+
+static inline struct aa_policy *aa_get_common(struct aa_policy *c)
+{
+	if (c)
+		kref_get(&c->count);
+
+	return c;
+}
+
+/**
+ * aa_get_namespace - increment references count on @ns
+ * @ns: namespace to increment reference count of (MAYBE NULL)
+ *
+ * Returns: pointer to @ns, if @ns is NULL returns NULL
+ * Requires: @ns must be held with valid refcount when called
+ */
+static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
+{
+	if (ns)
+		kref_get(&(ns->base.count));
+
+	return ns;
+}
+
+/**
+ * aa_put_namespace - decrement refcount on @ns
+ * @ns: namespace to put reference of
+ *
+ * Decrement reference count of @ns and if no longer in use free it
+ */
+static inline void aa_put_namespace(struct aa_namespace *ns)
+{
+	if (ns)
+		kref_put(&ns->base.count, aa_free_namespace_kref);
+}
+
+struct aa_profile *aa_alloc_profile(const char *name);
+struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat);
+void aa_free_profile_kref(struct kref *kref);
+struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
+struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *name);
+struct aa_profile *aa_match_profile(struct aa_namespace *ns, const char *name);
+
+ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace);
+ssize_t aa_remove_profiles(char *name, size_t size);
+
+#define PROF_ADD 1
+#define PROF_REPLACE 0
+
+#define unconfined(X) ((X)->flags & PFLAG_UNCONFINED)
+
+/**
+ * aa_newest_version - find the newest version of @profile
+ * @profile: the profile to check for newer versions of (NOT NULL)
+ *
+ * Returns: newest version of @profile, if @profile is the newest version
+ *          return @profile.
+ *
+ * NOTE: the profile returned is not refcounted, The refcount on @profile
+ * must be held until the caller decides what to do with the returned newest
+ * version.
+ */
+static inline struct aa_profile *aa_newest_version(struct aa_profile *profile)
+{
+	while (profile->replacedby)
+		profile = profile->replacedby;
+
+	return profile;
+}
+
+/**
+ * aa_get_profile - increment refcount on profile @p
+ * @p: profile  (MAYBE NULL)
+ *
+ * Returns: pointer to @p if @p is NULL will return NULL
+ * Requires: @p must be held with valid refcount when called
+ */
+static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
+{
+	if (p)
+		kref_get(&(p->base.count));
+
+	return p;
+}
+
+/**
+ * aa_put_profile - decrement refcount on profile @p
+ * @p: profile  (MAYBE NULL)
+ */
+static inline void aa_put_profile(struct aa_profile *p)
+{
+	if (p)
+		kref_put(&p->base.count, aa_free_profile_kref);
+}
+
+static inline int AUDIT_MODE(struct aa_profile *profile)
+{
+	if (aa_g_audit != AUDIT_NORMAL)
+		return aa_g_audit;
+
+	return profile->audit;
+}
+
+bool aa_may_manage_policy(int op);
+
+#endif /* __AA_POLICY_H */
diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h
new file mode 100644
index 0000000..a2dccca
--- /dev/null
+++ b/security/apparmor/include/policy_unpack.h
@@ -0,0 +1,20 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy loading interface function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __POLICY_INTERFACE_H
+#define __POLICY_INTERFACE_H
+
+struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns);
+
+#endif /* __POLICY_INTERFACE_H */
diff --git a/security/apparmor/include/procattr.h b/security/apparmor/include/procattr.h
new file mode 100644
index 0000000..544aa6b
--- /dev/null
+++ b/security/apparmor/include/procattr.h
@@ -0,0 +1,26 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor /proc/<pid>/attr/ interface function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_PROCATTR_H
+#define __AA_PROCATTR_H
+
+#define AA_DO_TEST 1
+#define AA_ONEXEC  1
+
+int aa_getprocattr(struct aa_profile *profile, char **string);
+int aa_setprocattr_changehat(char *args, size_t size, int test);
+int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test);
+int aa_setprocattr_permipc(char *fqname);
+
+#endif /* __AA_PROCATTR_H */
diff --git a/security/apparmor/include/resource.h b/security/apparmor/include/resource.h
new file mode 100644
index 0000000..3c88be9
--- /dev/null
+++ b/security/apparmor/include/resource.h
@@ -0,0 +1,46 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor resource limits function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_RESOURCE_H
+#define __AA_RESOURCE_H
+
+#include <linux/resource.h>
+#include <linux/sched.h>
+
+struct aa_profile;
+
+/* struct aa_rlimit - rlimit settings for the profile
+ * @mask: which hard limits to set
+ * @limits: rlimit values that override task limits
+ *
+ * AppArmor rlimits are used to set confined task rlimits.  Only the
+ * limits specified in @mask will be controlled by apparmor.
+ */
+struct aa_rlimit {
+	unsigned int mask;
+	struct rlimit limits[RLIM_NLIMITS];
+};
+
+int aa_map_resource(int resource);
+int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
+		      struct rlimit *new_rlim);
+
+void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new);
+
+static inline void aa_free_rlimit_rules(struct aa_rlimit *rlims)
+{
+	/* NOP */
+}
+
+#endif /* __AA_RESOURCE_H */
diff --git a/security/apparmor/include/sid.h b/security/apparmor/include/sid.h
new file mode 100644
index 0000000..020db35
--- /dev/null
+++ b/security/apparmor/include/sid.h
@@ -0,0 +1,24 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor security identifier (sid) definitions
+ *
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_SID_H
+#define __AA_SID_H
+
+#include <linux/types.h>
+
+struct aa_profile;
+
+u32 aa_alloc_sid(void);
+void aa_free_sid(u32 sid);
+
+#endif /* __AA_SID_H */
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
new file mode 100644
index 0000000..649fad8
--- /dev/null
+++ b/security/apparmor/ipc.c
@@ -0,0 +1,114 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor ipc mediation
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#include <linux/gfp.h>
+#include <linux/ptrace.h>
+
+#include "include/audit.h"
+#include "include/capability.h"
+#include "include/context.h"
+#include "include/policy.h"
+
+/* call back to audit ptrace fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+	struct common_audit_data *sa = va;
+	audit_log_format(ab, " target=");
+	audit_log_untrustedstring(ab, sa->aad.target);
+}
+
+/**
+ * aa_audit_ptrace - do auditing for ptrace
+ * @profile: profile being enforced  (NOT NULL)
+ * @target: profile being traced (NOT NULL)
+ * @error: error condition
+ *
+ * Returns: %0 or error code
+ */
+static int aa_audit_ptrace(struct aa_profile *profile,
+			   struct aa_profile *target, int error)
+{
+	struct common_audit_data sa;
+	COMMON_AUDIT_DATA_INIT(&sa, NONE);
+	sa.aad.op = OP_PTRACE;
+	sa.aad.target = target;
+	sa.aad.error = error;
+
+	return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa,
+			audit_cb);
+}
+
+/**
+ * aa_may_ptrace - test if tracer task can trace the tracee
+ * @tracer_task: task who will do the tracing  (NOT NULL)
+ * @tracer: profile of the task doing the tracing  (NOT NULL)
+ * @tracee: task to be traced
+ * @mode: whether PTRACE_MODE_READ || PTRACE_MODE_ATTACH
+ *
+ * Returns: %0 else error code if permission denied or error
+ */
+int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
+		  struct aa_profile *tracee, unsigned int mode)
+{
+	/* TODO: currently only based on capability, not extended ptrace
+	 *       rules,
+	 *       Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH
+	 */
+
+	if (unconfined(tracer) || tracer == tracee)
+		return 0;
+	/* log this capability request */
+	return aa_capable(tracer_task, tracer, CAP_SYS_PTRACE, 1);
+}
+
+/**
+ * aa_ptrace - do ptrace permission check and auditing
+ * @tracer: task doing the tracing (NOT NULL)
+ * @tracee: task being traced (NOT NULL)
+ * @mode: ptrace mode either PTRACE_MODE_READ || PTRACE_MODE_ATTACH
+ *
+ * Returns: %0 else error code if permission denied or error
+ */
+int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
+	      unsigned int mode)
+{
+	/*
+	 * tracer can ptrace tracee when
+	 * - tracer is unconfined ||
+	 *   - tracer is in complain mode
+	 *   - tracer has rules allowing it to trace tracee currently this is:
+	 *       - confined by the same profile ||
+	 *       - tracer profile has CAP_SYS_PTRACE
+	 */
+
+	struct aa_profile *tracer_p;
+	/* cred released below */
+	const struct cred *cred = get_task_cred(tracer);
+	int error = 0;
+	tracer_p = aa_cred_profile(cred);
+
+	if (!unconfined(tracer_p)) {
+		/* lcred released below */
+		const struct cred *lcred = get_task_cred(tracee);
+		struct aa_profile *tracee_p = aa_cred_profile(lcred);
+
+		error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode);
+		error = aa_audit_ptrace(tracer_p, tracee_p, error);
+
+		put_cred(lcred);
+	}
+	put_cred(cred);
+
+	return error;
+}
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
new file mode 100644
index 0000000..6e85cdb
--- /dev/null
+++ b/security/apparmor/lib.c
@@ -0,0 +1,133 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains basic common functions used in AppArmor
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+
+#include "include/audit.h"
+
+
+/**
+ * aa_split_fqname - split a fqname into a profile and namespace name
+ * @fqname: a full qualified name in namespace profile format (NOT NULL)
+ * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
+ *
+ * Returns: profile name or NULL if one is not specified
+ *
+ * Split a namespace name from a profile name (see policy.c for naming
+ * description).  If a portion of the name is missing it returns NULL for
+ * that portion.
+ *
+ * NOTE: may modify the @fqname string.  The pointers returned point
+ *       into the @fqname string.
+ */
+char *aa_split_fqname(char *fqname, char **ns_name)
+{
+	char *name = strim(fqname);
+
+	*ns_name = NULL;
+	if (name[0] == ':') {
+		char *split = strchr(&name[1], ':');
+		if (split) {
+			/* overwrite ':' with \0 */
+			*split = 0;
+			name = skip_spaces(split + 1);
+		} else
+			/* a ns name without a following profile is allowed */
+			name = NULL;
+		*ns_name = &name[1];
+	}
+	if (name && *name == 0)
+		name = NULL;
+
+	return name;
+}
+
+/**
+ * aa_info_message - log a none profile related status message
+ * @str: message to log
+ */
+void aa_info_message(const char *str)
+{
+	if (audit_enabled) {
+		struct common_audit_data sa;
+		COMMON_AUDIT_DATA_INIT(&sa, NONE);
+		sa.aad.info = str;
+		aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
+	}
+	printk(KERN_INFO "AppArmor: %s\n", str);
+}
+
+/**
+ * kvmalloc - do allocation preferring kmalloc but falling back to vmalloc
+ * @size: size of allocation
+ *
+ * Return: allocated buffer or NULL if failed
+ *
+ * It is possible that policy being loaded from the user is larger than
+ * what can be allocated by kmalloc, in those cases fall back to vmalloc.
+ */
+void *kvmalloc(size_t size)
+{
+	void *buffer = NULL;
+
+	if (size == 0)
+		return NULL;
+
+	/* do not attempt kmalloc if we need more than 16 pages at once */
+	if (size <= (16*PAGE_SIZE))
+		buffer = kmalloc(size, GFP_NOIO | __GFP_NOWARN);
+	if (!buffer) {
+		/* see kvfree for why size must be at least work_struct size
+		 * when allocated via vmalloc
+		 */
+		if (size < sizeof(struct work_struct))
+			size = sizeof(struct work_struct);
+		buffer = vmalloc(size);
+	}
+	return buffer;
+}
+
+/**
+ * do_vfree - workqueue routine for freeing vmalloced memory
+ * @work: data to be freed
+ *
+ * The work_struct is overlaid to the data being freed, as at the point
+ * the work is scheduled the data is no longer valid, be its freeing
+ * needs to be delayed until safe.
+ */
+static void do_vfree(struct work_struct *work)
+{
+	vfree(work);
+}
+
+/**
+ * kvfree - free an allocation do by kvmalloc
+ * @buffer: buffer to free (MAYBE_NULL)
+ *
+ * Free a buffer allocated by kvmalloc
+ */
+void kvfree(void *buffer)
+{
+	if (is_vmalloc_addr(buffer)) {
+		/* Data is no longer valid so just use the allocated space
+		 * as the work_struct
+		 */
+		struct work_struct *work = (struct work_struct *) buffer;
+		INIT_WORK(work, do_vfree);
+		schedule_work(work);
+	} else
+		kfree(buffer);
+}
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
new file mode 100644
index 0000000..8db33a8
--- /dev/null
+++ b/security/apparmor/lsm.c
@@ -0,0 +1,938 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor LSM hooks.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#include <linux/security.h>
+#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/ptrace.h>
+#include <linux/ctype.h>
+#include <linux/sysctl.h>
+#include <linux/audit.h>
+#include <net/sock.h>
+
+#include "include/apparmor.h"
+#include "include/apparmorfs.h"
+#include "include/audit.h"
+#include "include/capability.h"
+#include "include/context.h"
+#include "include/file.h"
+#include "include/ipc.h"
+#include "include/path.h"
+#include "include/policy.h"
+#include "include/procattr.h"
+
+/* Flag indicating whether initialization completed */
+int apparmor_initialized __initdata;
+
+/*
+ * LSM hook functions
+ */
+
+/*
+ * free the associated aa_task_cxt and put its profiles
+ */
+static void apparmor_cred_free(struct cred *cred)
+{
+	aa_free_task_context(cred->security);
+	cred->security = NULL;
+}
+
+/*
+ * allocate the apparmor part of blank credentials
+ */
+static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
+{
+	/* freed by apparmor_cred_free */
+	struct aa_task_cxt *cxt = aa_alloc_task_context(gfp);
+	if (!cxt)
+		return -ENOMEM;
+
+	cred->security = cxt;
+	return 0;
+}
+
+/*
+ * prepare new aa_task_cxt for modification by prepare_cred block
+ */
+static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
+				 gfp_t gfp)
+{
+	/* freed by apparmor_cred_free */
+	struct aa_task_cxt *cxt = aa_alloc_task_context(gfp);
+	if (!cxt)
+		return -ENOMEM;
+
+	aa_dup_task_context(cxt, old->security);
+	new->security = cxt;
+	return 0;
+}
+
+/*
+ * transfer the apparmor data to a blank set of creds
+ */
+static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
+{
+	const struct aa_task_cxt *old_cxt = old->security;
+	struct aa_task_cxt *new_cxt = new->security;
+
+	aa_dup_task_context(new_cxt, old_cxt);
+}
+
+static int apparmor_ptrace_access_check(struct task_struct *child,
+					unsigned int mode)
+{
+	int error = cap_ptrace_access_check(child, mode);
+	if (error)
+		return error;
+
+	return aa_ptrace(current, child, mode);
+}
+
+static int apparmor_ptrace_traceme(struct task_struct *parent)
+{
+	int error = cap_ptrace_traceme(parent);
+	if (error)
+		return error;
+
+	return aa_ptrace(parent, current, PTRACE_MODE_ATTACH);
+}
+
+/* Derived from security/commoncap.c:cap_capget */
+static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
+			   kernel_cap_t *inheritable, kernel_cap_t *permitted)
+{
+	struct aa_profile *profile;
+	const struct cred *cred;
+
+	rcu_read_lock();
+	cred = __task_cred(target);
+	profile = aa_cred_profile(cred);
+
+	*effective = cred->cap_effective;
+	*inheritable = cred->cap_inheritable;
+	*permitted = cred->cap_permitted;
+
+	if (!unconfined(profile)) {
+		*effective = cap_intersect(*effective, profile->caps.allow);
+		*permitted = cap_intersect(*permitted, profile->caps.allow);
+	}
+	rcu_read_unlock();
+
+	return 0;
+}
+
+static int apparmor_capable(struct task_struct *task, const struct cred *cred,
+			    int cap, int audit)
+{
+	struct aa_profile *profile;
+	/* cap_capable returns 0 on success, else -EPERM */
+	int error = cap_capable(task, cred, cap, audit);
+	if (!error) {
+		profile = aa_cred_profile(cred);
+		if (!unconfined(profile))
+			error = aa_capable(task, profile, cap, audit);
+	}
+	return error;
+}
+
+/**
+ * common_perm - basic common permission check wrapper fn for paths
+ * @op: operation being checked
+ * @path: path to check permission of  (NOT NULL)
+ * @mask: requested permissions mask
+ * @cond: conditional info for the permission request  (NOT NULL)
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm(int op, struct path *path, u32 mask,
+		       struct path_cond *cond)
+{
+	struct aa_profile *profile;
+	int error = 0;
+
+	profile = __aa_current_profile();
+	if (!unconfined(profile))
+		error = aa_path_perm(op, profile, path, 0, mask, cond);
+
+	return error;
+}
+
+/**
+ * common_perm_dir_dentry - common permission wrapper when path is dir, dentry
+ * @op: operation being checked
+ * @dir: directory of the dentry  (NOT NULL)
+ * @dentry: dentry to check  (NOT NULL)
+ * @mask: requested permissions mask
+ * @cond: conditional info for the permission request  (NOT NULL)
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm_dir_dentry(int op, struct path *dir,
+				  struct dentry *dentry, u32 mask,
+				  struct path_cond *cond)
+{
+	struct path path = { dir->mnt, dentry };
+
+	return common_perm(op, &path, mask, cond);
+}
+
+/**
+ * common_perm_mnt_dentry - common permission wrapper when mnt, dentry
+ * @op: operation being checked
+ * @mnt: mount point of dentry (NOT NULL)
+ * @dentry: dentry to check  (NOT NULL)
+ * @mask: requested permissions mask
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm_mnt_dentry(int op, struct vfsmount *mnt,
+				  struct dentry *dentry, u32 mask)
+{
+	struct path path = { mnt, dentry };
+	struct path_cond cond = { dentry->d_inode->i_uid,
+				  dentry->d_inode->i_mode
+	};
+
+	return common_perm(op, &path, mask, &cond);
+}
+
+/**
+ * common_perm_rm - common permission wrapper for operations doing rm
+ * @op: operation being checked
+ * @dir: directory that the dentry is in  (NOT NULL)
+ * @dentry: dentry being rm'd  (NOT NULL)
+ * @mask: requested permission mask
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm_rm(int op, struct path *dir,
+			  struct dentry *dentry, u32 mask)
+{
+	struct inode *inode = dentry->d_inode;
+	struct path_cond cond = { };
+
+	if (!inode || !dir->mnt || !mediated_filesystem(inode))
+		return 0;
+
+	cond.uid = inode->i_uid;
+	cond.mode = inode->i_mode;
+
+	return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
+}
+
+/**
+ * common_perm_create - common permission wrapper for operations doing create
+ * @op: operation being checked
+ * @dir: directory that dentry will be created in  (NOT NULL)
+ * @dentry: dentry to create   (NOT NULL)
+ * @mask: request permission mask
+ * @mode: created file mode
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm_create(int op, struct path *dir, struct dentry *dentry,
+			      u32 mask, umode_t mode)
+{
+	struct path_cond cond = { current_fsuid(), mode };
+
+	if (!dir->mnt || !mediated_filesystem(dir->dentry->d_inode))
+		return 0;
+
+	return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
+}
+
+static int apparmor_path_unlink(struct path *dir, struct dentry *dentry)
+{
+	return common_perm_rm(OP_UNLINK, dir, dentry, AA_MAY_DELETE);
+}
+
+static int apparmor_path_mkdir(struct path *dir, struct dentry *dentry,
+			       int mode)
+{
+	return common_perm_create(OP_MKDIR, dir, dentry, AA_MAY_CREATE,
+				  S_IFDIR);
+}
+
+static int apparmor_path_rmdir(struct path *dir, struct dentry *dentry)
+{
+	return common_perm_rm(OP_RMDIR, dir, dentry, AA_MAY_DELETE);
+}
+
+static int apparmor_path_mknod(struct path *dir, struct dentry *dentry,
+			       int mode, unsigned int dev)
+{
+	return common_perm_create(OP_MKNOD, dir, dentry, AA_MAY_CREATE, mode);
+}
+
+static int apparmor_path_truncate(struct path *path)
+{
+	struct path_cond cond = { path->dentry->d_inode->i_uid,
+				  path->dentry->d_inode->i_mode
+	};
+
+	if (!path->mnt || !mediated_filesystem(path->dentry->d_inode))
+		return 0;
+
+	return common_perm(OP_TRUNC, path, MAY_WRITE | AA_MAY_META_WRITE,
+			   &cond);
+}
+
+static int apparmor_path_symlink(struct path *dir, struct dentry *dentry,
+				 const char *old_name)
+{
+	return common_perm_create(OP_SYMLINK, dir, dentry, AA_MAY_CREATE,
+				  S_IFLNK);
+}
+
+static int apparmor_path_link(struct dentry *old_dentry, struct path *new_dir,
+			      struct dentry *new_dentry)
+{
+	struct aa_profile *profile;
+	int error = 0;
+
+	if (!mediated_filesystem(old_dentry->d_inode))
+		return 0;
+
+	profile = aa_current_profile();
+	if (!unconfined(profile))
+		error = aa_path_link(profile, old_dentry, new_dir, new_dentry);
+	return error;
+}
+
+static int apparmor_path_rename(struct path *old_dir, struct dentry *old_dentry,
+				struct path *new_dir, struct dentry *new_dentry)
+{
+	struct aa_profile *profile;
+	int error = 0;
+
+	if (!mediated_filesystem(old_dentry->d_inode))
+		return 0;
+
+	profile = aa_current_profile();
+	if (!unconfined(profile)) {
+		struct path old_path = { old_dir->mnt, old_dentry };
+		struct path new_path = { new_dir->mnt, new_dentry };
+		struct path_cond cond = { old_dentry->d_inode->i_uid,
+					  old_dentry->d_inode->i_mode
+		};
+
+		error = aa_path_perm(OP_RENAME_SRC, profile, &old_path, 0,
+				     MAY_READ | AA_MAY_META_READ | MAY_WRITE |
+				     AA_MAY_META_WRITE | AA_MAY_DELETE,
+				     &cond);
+		if (!error)
+			error = aa_path_perm(OP_RENAME_DEST, profile, &new_path,
+					     0, MAY_WRITE | AA_MAY_META_WRITE |
+					     AA_MAY_CREATE, &cond);
+
+	}
+	return error;
+}
+
+static int apparmor_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
+			       mode_t mode)
+{
+	if (!mediated_filesystem(dentry->d_inode))
+		return 0;
+
+	return common_perm_mnt_dentry(OP_CHMOD, mnt, dentry, AA_MAY_CHMOD);
+}
+
+static int apparmor_path_chown(struct path *path, uid_t uid, gid_t gid)
+{
+	struct path_cond cond =  { path->dentry->d_inode->i_uid,
+				   path->dentry->d_inode->i_mode
+	};
+
+	if (!mediated_filesystem(path->dentry->d_inode))
+		return 0;
+
+	return common_perm(OP_CHOWN, path, AA_MAY_CHOWN, &cond);
+}
+
+static int apparmor_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+{
+	if (!mediated_filesystem(dentry->d_inode))
+		return 0;
+
+	return common_perm_mnt_dentry(OP_GETATTR, mnt, dentry,
+				      AA_MAY_META_READ);
+}
+
+static int apparmor_dentry_open(struct file *file, const struct cred *cred)
+{
+	struct aa_file_cxt *fcxt = file->f_security;
+	struct aa_profile *profile;
+	int error = 0;
+
+	if (!mediated_filesystem(file->f_path.dentry->d_inode))
+		return 0;
+
+	/* If in exec, permission is handled by bprm hooks.
+	 * Cache permissions granted by the previous exec check, with
+	 * implicit read and executable mmap which are required to
+	 * actually execute the image.
+	 */
+	if (current->in_execve) {
+		fcxt->allow = MAY_EXEC | MAY_READ | AA_EXEC_MMAP;
+		return 0;
+	}
+
+	profile = aa_cred_profile(cred);
+	if (!unconfined(profile)) {
+		struct inode *inode = file->f_path.dentry->d_inode;
+		struct path_cond cond = { inode->i_uid, inode->i_mode };
+
+		error = aa_path_perm(OP_OPEN, profile, &file->f_path, 0,
+				     aa_map_file_to_perms(file), &cond);
+		/* todo cache full allowed permissions set and state */
+		fcxt->allow = aa_map_file_to_perms(file);
+	}
+
+	return error;
+}
+
+static int apparmor_file_alloc_security(struct file *file)
+{
+	/* freed by apparmor_file_free_security */
+	file->f_security = aa_alloc_file_context(GFP_KERNEL);
+	if (!file->f_security)
+		return -ENOMEM;
+	return 0;
+
+}
+
+static void apparmor_file_free_security(struct file *file)
+{
+	struct aa_file_cxt *cxt = file->f_security;
+
+	aa_free_file_context(cxt);
+}
+
+static int common_file_perm(int op, struct file *file, u32 mask)
+{
+	struct aa_file_cxt *fcxt = file->f_security;
+	struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred);
+	int error = 0;
+
+	BUG_ON(!fprofile);
+
+	if (!file->f_path.mnt ||
+	    !mediated_filesystem(file->f_path.dentry->d_inode))
+		return 0;
+
+	profile = __aa_current_profile();
+
+	/* revalidate access, if task is unconfined, or the cached cred
+	 * doesn't match or if the request is for more permissions than
+	 * was granted.
+	 *
+	 * Note: the test for !unconfined(fprofile) is to handle file
+	 *       delegation from unconfined tasks
+	 */
+	if (!unconfined(profile) && !unconfined(fprofile) &&
+	    ((fprofile != profile) || (mask & ~fcxt->allow)))
+		error = aa_file_perm(op, profile, file, mask);
+
+	return error;
+}
+
+static int apparmor_file_permission(struct file *file, int mask)
+{
+	return common_file_perm(OP_FPERM, file, mask);
+}
+
+static int apparmor_file_lock(struct file *file, unsigned int cmd)
+{
+	u32 mask = AA_MAY_LOCK;
+
+	if (cmd == F_WRLCK)
+		mask |= MAY_WRITE;
+
+	return common_file_perm(OP_FLOCK, file, mask);
+}
+
+static int common_mmap(int op, struct file *file, unsigned long prot,
+		       unsigned long flags)
+{
+	struct dentry *dentry;
+	int mask = 0;
+
+	if (!file || !file->f_security)
+		return 0;
+
+	if (prot & PROT_READ)
+		mask |= MAY_READ;
+	/*
+	 * Private mappings don't require write perms since they don't
+	 * write back to the files
+	 */
+	if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE))
+		mask |= MAY_WRITE;
+	if (prot & PROT_EXEC)
+		mask |= AA_EXEC_MMAP;
+
+	dentry = file->f_path.dentry;
+	return common_file_perm(op, file, mask);
+}
+
+static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
+			      unsigned long prot, unsigned long flags,
+			      unsigned long addr, unsigned long addr_only)
+{
+	int rc = 0;
+
+	/* do DAC check */
+	rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
+	if (rc || addr_only)
+		return rc;
+
+	return common_mmap(OP_FMMAP, file, prot, flags);
+}
+
+static int apparmor_file_mprotect(struct vm_area_struct *vma,
+				  unsigned long reqprot, unsigned long prot)
+{
+	return common_mmap(OP_FMPROT, vma->vm_file, prot,
+			   !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
+}
+
+static int apparmor_getprocattr(struct task_struct *task, char *name,
+				char **value)
+{
+	int error = -ENOENT;
+	struct aa_profile *profile;
+	/* released below */
+	const struct cred *cred = get_task_cred(task);
+	struct aa_task_cxt *cxt = cred->security;
+	profile = aa_cred_profile(cred);
+
+	if (strcmp(name, "current") == 0)
+		error = aa_getprocattr(aa_newest_version(cxt->profile),
+				       value);
+	else if (strcmp(name, "prev") == 0  && cxt->previous)
+		error = aa_getprocattr(aa_newest_version(cxt->previous),
+				       value);
+	else if (strcmp(name, "exec") == 0 && cxt->onexec)
+		error = aa_getprocattr(aa_newest_version(cxt->onexec),
+				       value);
+	else
+		error = -EINVAL;
+
+	put_cred(cred);
+
+	return error;
+}
+
+static int apparmor_setprocattr(struct task_struct *task, char *name,
+				void *value, size_t size)
+{
+	char *command, *args = value;
+	size_t arg_size;
+	int error;
+
+	if (size == 0)
+		return -EINVAL;
+	/* args points to a PAGE_SIZE buffer, AppArmor requires that
+	 * the buffer must be null terminated or have size <= PAGE_SIZE -1
+	 * so that AppArmor can null terminate them
+	 */
+	if (args[size - 1] != '\0') {
+		if (size == PAGE_SIZE)
+			return -EINVAL;
+		args[size] = '\0';
+	}
+
+	/* task can only write its own attributes */
+	if (current != task)
+		return -EACCES;
+
+	args = value;
+	args = strim(args);
+	command = strsep(&args, " ");
+	if (!args)
+		return -EINVAL;
+	args = skip_spaces(args);
+	if (!*args)
+		return -EINVAL;
+
+	arg_size = size - (args - (char *) value);
+	if (strcmp(name, "current") == 0) {
+		if (strcmp(command, "changehat") == 0) {
+			error = aa_setprocattr_changehat(args, arg_size,
+							 !AA_DO_TEST);
+		} else if (strcmp(command, "permhat") == 0) {
+			error = aa_setprocattr_changehat(args, arg_size,
+							 AA_DO_TEST);
+		} else if (strcmp(command, "changeprofile") == 0) {
+			error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
+							     !AA_DO_TEST);
+		} else if (strcmp(command, "permprofile") == 0) {
+			error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
+							     AA_DO_TEST);
+		} else if (strcmp(command, "permipc") == 0) {
+			error = aa_setprocattr_permipc(args);
+		} else {
+			struct common_audit_data sa;
+			COMMON_AUDIT_DATA_INIT(&sa, NONE);
+			sa.aad.op = OP_SETPROCATTR;
+			sa.aad.info = name;
+			sa.aad.error = -EINVAL;
+			return aa_audit(AUDIT_APPARMOR_DENIED, NULL, GFP_KERNEL,
+					&sa, NULL);
+		}
+	} else if (strcmp(name, "exec") == 0) {
+		error = aa_setprocattr_changeprofile(args, AA_ONEXEC,
+						     !AA_DO_TEST);
+	} else {
+		/* only support the "current" and "exec" process attributes */
+		return -EINVAL;
+	}
+	if (!error)
+		error = size;
+	return error;
+}
+
+static int apparmor_task_setrlimit(unsigned int resource,
+				   struct rlimit *new_rlim)
+{
+	struct aa_profile *profile = aa_current_profile();
+	int error = 0;
+
+	if (!unconfined(profile))
+		error = aa_task_setrlimit(profile, resource, new_rlim);
+
+	return error;
+}
+
+static struct security_operations apparmor_ops = {
+	.name =				"apparmor",
+
+	.ptrace_access_check =		apparmor_ptrace_access_check,
+	.ptrace_traceme =		apparmor_ptrace_traceme,
+	.capget =			apparmor_capget,
+	.capable =			apparmor_capable,
+
+	.path_link =			apparmor_path_link,
+	.path_unlink =			apparmor_path_unlink,
+	.path_symlink =			apparmor_path_symlink,
+	.path_mkdir =			apparmor_path_mkdir,
+	.path_rmdir =			apparmor_path_rmdir,
+	.path_mknod =			apparmor_path_mknod,
+	.path_rename =			apparmor_path_rename,
+	.path_chmod =			apparmor_path_chmod,
+	.path_chown =			apparmor_path_chown,
+	.path_truncate =		apparmor_path_truncate,
+	.dentry_open =			apparmor_dentry_open,
+	.inode_getattr =                apparmor_inode_getattr,
+
+	.file_permission =		apparmor_file_permission,
+	.file_alloc_security =		apparmor_file_alloc_security,
+	.file_free_security =		apparmor_file_free_security,
+	.file_mmap =			apparmor_file_mmap,
+	.file_mprotect =		apparmor_file_mprotect,
+	.file_lock =			apparmor_file_lock,
+
+	.getprocattr =			apparmor_getprocattr,
+	.setprocattr =			apparmor_setprocattr,
+
+	.cred_alloc_blank =		apparmor_cred_alloc_blank,
+	.cred_free =			apparmor_cred_free,
+	.cred_prepare =			apparmor_cred_prepare,
+	.cred_transfer =		apparmor_cred_transfer,
+
+	.bprm_set_creds =		apparmor_bprm_set_creds,
+	.bprm_committing_creds =	apparmor_bprm_committing_creds,
+	.bprm_committed_creds =		apparmor_bprm_committed_creds,
+	.bprm_secureexec =		apparmor_bprm_secureexec,
+
+	.task_setrlimit =		apparmor_task_setrlimit,
+};
+
+/*
+ * AppArmor sysfs module parameters
+ */
+
+static int param_set_aabool(const char *val, struct kernel_param *kp);
+static int param_get_aabool(char *buffer, struct kernel_param *kp);
+#define param_check_aabool(name, p) __param_check(name, p, int)
+
+static int param_set_aauint(const char *val, struct kernel_param *kp);
+static int param_get_aauint(char *buffer, struct kernel_param *kp);
+#define param_check_aauint(name, p) __param_check(name, p, int)
+
+static int param_set_aalockpolicy(const char *val, struct kernel_param *kp);
+static int param_get_aalockpolicy(char *buffer, struct kernel_param *kp);
+#define param_check_aalockpolicy(name, p) __param_check(name, p, int)
+
+static int param_set_audit(const char *val, struct kernel_param *kp);
+static int param_get_audit(char *buffer, struct kernel_param *kp);
+#define param_check_audit(name, p) __param_check(name, p, int)
+
+static int param_set_mode(const char *val, struct kernel_param *kp);
+static int param_get_mode(char *buffer, struct kernel_param *kp);
+#define param_check_mode(name, p) __param_check(name, p, int)
+
+/* Flag values, also controllable via /sys/module/apparmor/parameters
+ * We define special types as we want to do additional mediation.
+ */
+
+/* AppArmor global enforcement switch - complain, enforce, kill */
+enum profile_mode aa_g_profile_mode = APPARMOR_ENFORCE;
+module_param_call(mode, param_set_mode, param_get_mode,
+		  &aa_g_profile_mode, S_IRUSR | S_IWUSR);
+
+/* Debug mode */
+int aa_g_debug;
+module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR);
+
+/* Audit mode */
+enum audit_mode aa_g_audit;
+module_param_call(audit, param_set_audit, param_get_audit,
+		  &aa_g_audit, S_IRUSR | S_IWUSR);
+
+/* Determines if audit header is included in audited messages.  This
+ * provides more context if the audit daemon is not running
+ */
+int aa_g_audit_header = 1;
+module_param_named(audit_header, aa_g_audit_header, aabool,
+		   S_IRUSR | S_IWUSR);
+
+/* lock out loading/removal of policy
+ * TODO: add in at boot loading of policy, which is the only way to
+ *       load policy, if lock_policy is set
+ */
+int aa_g_lock_policy;
+module_param_named(lock_policy, aa_g_lock_policy, aalockpolicy,
+		   S_IRUSR | S_IWUSR);
+
+/* Syscall logging mode */
+int aa_g_logsyscall;
+module_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR);
+
+/* Maximum pathname length before accesses will start getting rejected */
+unsigned int aa_g_path_max = 2 * PATH_MAX;
+module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR | S_IWUSR);
+
+/* Determines how paranoid loading of policy is and how much verification
+ * on the loaded policy is done.
+ */
+int aa_g_paranoid_load = 1;
+module_param_named(paranoid_load, aa_g_paranoid_load, aabool,
+		   S_IRUSR | S_IWUSR);
+
+/* Boot time disable flag */
+static unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
+module_param_named(enabled, apparmor_enabled, aabool, S_IRUSR);
+
+static int __init apparmor_enabled_setup(char *str)
+{
+	unsigned long enabled;
+	int error = strict_strtoul(str, 0, &enabled);
+	if (!error)
+		apparmor_enabled = enabled ? 1 : 0;
+	return 1;
+}
+
+__setup("apparmor=", apparmor_enabled_setup);
+
+/* set global flag turning off the ability to load policy */
+static int param_set_aalockpolicy(const char *val, struct kernel_param *kp)
+{
+	if (!capable(CAP_MAC_ADMIN))
+		return -EPERM;
+	if (aa_g_lock_policy)
+		return -EACCES;
+	return param_set_bool(val, kp);
+}
+
+static int param_get_aalockpolicy(char *buffer, struct kernel_param *kp)
+{
+	if (!capable(CAP_MAC_ADMIN))
+		return -EPERM;
+	return param_get_bool(buffer, kp);
+}
+
+static int param_set_aabool(const char *val, struct kernel_param *kp)
+{
+	if (!capable(CAP_MAC_ADMIN))
+		return -EPERM;
+	return param_set_bool(val, kp);
+}
+
+static int param_get_aabool(char *buffer, struct kernel_param *kp)
+{
+	if (!capable(CAP_MAC_ADMIN))
+		return -EPERM;
+	return param_get_bool(buffer, kp);
+}
+
+static int param_set_aauint(const char *val, struct kernel_param *kp)
+{
+	if (!capable(CAP_MAC_ADMIN))
+		return -EPERM;
+	return param_set_uint(val, kp);
+}
+
+static int param_get_aauint(char *buffer, struct kernel_param *kp)
+{
+	if (!capable(CAP_MAC_ADMIN))
+		return -EPERM;
+	return param_get_uint(buffer, kp);
+}
+
+static int param_get_audit(char *buffer, struct kernel_param *kp)
+{
+	if (!capable(CAP_MAC_ADMIN))
+		return -EPERM;
+
+	if (!apparmor_enabled)
+		return -EINVAL;
+
+	return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]);
+}
+
+static int param_set_audit(const char *val, struct kernel_param *kp)
+{
+	int i;
+	if (!capable(CAP_MAC_ADMIN))
+		return -EPERM;
+
+	if (!apparmor_enabled)
+		return -EINVAL;
+
+	if (!val)
+		return -EINVAL;
+
+	for (i = 0; i < AUDIT_MAX_INDEX; i++) {
+		if (strcmp(val, audit_mode_names[i]) == 0) {
+			aa_g_audit = i;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int param_get_mode(char *buffer, struct kernel_param *kp)
+{
+	if (!capable(CAP_MAC_ADMIN))
+		return -EPERM;
+
+	if (!apparmor_enabled)
+		return -EINVAL;
+
+	return sprintf(buffer, "%s", profile_mode_names[aa_g_profile_mode]);
+}
+
+static int param_set_mode(const char *val, struct kernel_param *kp)
+{
+	int i;
+	if (!capable(CAP_MAC_ADMIN))
+		return -EPERM;
+
+	if (!apparmor_enabled)
+		return -EINVAL;
+
+	if (!val)
+		return -EINVAL;
+
+	for (i = 0; i < APPARMOR_NAMES_MAX_INDEX; i++) {
+		if (strcmp(val, profile_mode_names[i]) == 0) {
+			aa_g_profile_mode = i;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * AppArmor init functions
+ */
+
+/**
+ * set_init_cxt - set a task context and profile on the first task.
+ *
+ * TODO: allow setting an alternate profile than unconfined
+ */
+static int __init set_init_cxt(void)
+{
+	struct cred *cred = (struct cred *)current->real_cred;
+	struct aa_task_cxt *cxt;
+
+	cxt = aa_alloc_task_context(GFP_KERNEL);
+	if (!cxt)
+		return -ENOMEM;
+
+	cxt->profile = aa_get_profile(root_ns->unconfined);
+	cred->security = cxt;
+
+	return 0;
+}
+
+static int __init apparmor_init(void)
+{
+	int error;
+
+	if (!apparmor_enabled || !security_module_enable(&apparmor_ops)) {
+		aa_info_message("AppArmor disabled by boot time parameter");
+		apparmor_enabled = 0;
+		return 0;
+	}
+
+	error = aa_alloc_root_ns();
+	if (error) {
+		AA_ERROR("Unable to allocate default profile namespace\n");
+		goto alloc_out;
+	}
+
+	error = set_init_cxt();
+	if (error) {
+		AA_ERROR("Failed to set context on init task\n");
+		goto register_security_out;
+	}
+
+	error = register_security(&apparmor_ops);
+	if (error) {
+		AA_ERROR("Unable to register AppArmor\n");
+		goto register_security_out;
+	}
+
+	/* Report that AppArmor successfully initialized */
+	apparmor_initialized = 1;
+	if (aa_g_profile_mode == APPARMOR_COMPLAIN)
+		aa_info_message("AppArmor initialized: complain mode enabled");
+	else if (aa_g_profile_mode == APPARMOR_KILL)
+		aa_info_message("AppArmor initialized: kill mode enabled");
+	else
+		aa_info_message("AppArmor initialized");
+
+	return error;
+
+register_security_out:
+	aa_free_root_ns();
+
+alloc_out:
+	aa_destroy_aafs();
+
+	apparmor_enabled = 0;
+	return error;
+
+}
+
+security_initcall(apparmor_init);
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
new file mode 100644
index 0000000..5cb4dc1
--- /dev/null
+++ b/security/apparmor/match.c
@@ -0,0 +1,353 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor dfa based regular expression matching engine
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/err.h>
+#include <linux/kref.h>
+
+#include "include/apparmor.h"
+#include "include/match.h"
+
+/**
+ * unpack_table - unpack a dfa table (one of accept, default, base, next check)
+ * @blob: data to unpack (NOT NULL)
+ * @bsize: size of blob
+ *
+ * Returns: pointer to table else NULL on failure
+ *
+ * NOTE: must be freed by kvfree (not kmalloc)
+ */
+static struct table_header *unpack_table(char *blob, size_t bsize)
+{
+	struct table_header *table = NULL;
+	struct table_header th;
+	size_t tsize;
+
+	if (bsize < sizeof(struct table_header))
+		goto out;
+
+	/* loaded td_id's start at 1, subtract 1 now to avoid doing
+	 * it every time we use td_id as an index
+	 */
+	th.td_id = be16_to_cpu(*(u16 *) (blob)) - 1;
+	th.td_flags = be16_to_cpu(*(u16 *) (blob + 2));
+	th.td_lolen = be32_to_cpu(*(u32 *) (blob + 8));
+	blob += sizeof(struct table_header);
+
+	if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
+	      th.td_flags == YYTD_DATA8))
+		goto out;
+
+	tsize = table_size(th.td_lolen, th.td_flags);
+	if (bsize < tsize)
+		goto out;
+
+	table = kvmalloc(tsize);
+	if (table) {
+		*table = th;
+		if (th.td_flags == YYTD_DATA8)
+			UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+				     u8, byte_to_byte);
+		else if (th.td_flags == YYTD_DATA16)
+			UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+				     u16, be16_to_cpu);
+		else if (th.td_flags == YYTD_DATA32)
+			UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+				     u32, be32_to_cpu);
+		else
+			goto fail;
+	}
+
+out:
+	/* if table was vmalloced make sure the page tables are synced
+	 * before it is used, as it goes live to all cpus.
+	 */
+	if (is_vmalloc_addr(table))
+		vm_unmap_aliases();
+	return table;
+fail:
+	kvfree(table);
+	return NULL;
+}
+
+/**
+ * verify_dfa - verify that transitions and states in the tables are in bounds.
+ * @dfa: dfa to test  (NOT NULL)
+ * @flags: flags controlling what type of accept table are acceptable
+ *
+ * Assumes dfa has gone through the first pass verification done by unpacking
+ * NOTE: this does not valid accept table values
+ *
+ * Returns: %0 else error code on failure to verify
+ */
+static int verify_dfa(struct aa_dfa *dfa, int flags)
+{
+	size_t i, state_count, trans_count;
+	int error = -EPROTO;
+
+	/* check that required tables exist */
+	if (!(dfa->tables[YYTD_ID_DEF] &&
+	      dfa->tables[YYTD_ID_BASE] &&
+	      dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK]))
+		goto out;
+
+	/* accept.size == default.size == base.size */
+	state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
+	if (ACCEPT1_FLAGS(flags)) {
+		if (!dfa->tables[YYTD_ID_ACCEPT])
+			goto out;
+		if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen)
+			goto out;
+	}
+	if (ACCEPT2_FLAGS(flags)) {
+		if (!dfa->tables[YYTD_ID_ACCEPT2])
+			goto out;
+		if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen)
+			goto out;
+	}
+	if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen)
+		goto out;
+
+	/* next.size == chk.size */
+	trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen;
+	if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen)
+		goto out;
+
+	/* if equivalence classes then its table size must be 256 */
+	if (dfa->tables[YYTD_ID_EC] &&
+	    dfa->tables[YYTD_ID_EC]->td_lolen != 256)
+		goto out;
+
+	if (flags & DFA_FLAG_VERIFY_STATES) {
+		for (i = 0; i < state_count; i++) {
+			if (DEFAULT_TABLE(dfa)[i] >= state_count)
+				goto out;
+			/* TODO: do check that DEF state recursion terminates */
+			if (BASE_TABLE(dfa)[i] + 255 >= trans_count) {
+				printk(KERN_ERR "AppArmor DFA next/check upper "
+				       "bounds error\n");
+				goto out;
+			}
+		}
+
+		for (i = 0; i < trans_count; i++) {
+			if (NEXT_TABLE(dfa)[i] >= state_count)
+				goto out;
+			if (CHECK_TABLE(dfa)[i] >= state_count)
+				goto out;
+		}
+	}
+
+	error = 0;
+out:
+	return error;
+}
+
+/**
+ * dfa_free - free a dfa allocated by aa_dfa_unpack
+ * @dfa: the dfa to free  (MAYBE NULL)
+ *
+ * Requires: reference count to dfa == 0
+ */
+static void dfa_free(struct aa_dfa *dfa)
+{
+	if (dfa) {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) {
+			kvfree(dfa->tables[i]);
+			dfa->tables[i] = NULL;
+		}
+		kfree(dfa);
+	}
+}
+
+/**
+ * aa_dfa_free_kref - free aa_dfa by kref (called by aa_put_dfa)
+ * @kr: kref callback for freeing of a dfa  (NOT NULL)
+ */
+void aa_dfa_free_kref(struct kref *kref)
+{
+	struct aa_dfa *dfa = container_of(kref, struct aa_dfa, count);
+	dfa_free(dfa);
+}
+
+/**
+ * aa_dfa_unpack - unpack the binary tables of a serialized dfa
+ * @blob: aligned serialized stream of data to unpack  (NOT NULL)
+ * @size: size of data to unpack
+ * @flags: flags controlling what type of accept tables are acceptable
+ *
+ * Unpack a dfa that has been serialized.  To find information on the dfa
+ * format look in Documentation/apparmor.txt
+ * Assumes the dfa @blob stream has been aligned on a 8 byte boundry
+ *
+ * Returns: an unpacked dfa ready for matching or ERR_PTR on failure
+ */
+struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
+{
+	int hsize;
+	int error = -ENOMEM;
+	char *data = blob;
+	struct table_header *table = NULL;
+	struct aa_dfa *dfa = kzalloc(sizeof(struct aa_dfa), GFP_KERNEL);
+	if (!dfa)
+		goto fail;
+
+	kref_init(&dfa->count);
+
+	error = -EPROTO;
+
+	/* get dfa table set header */
+	if (size < sizeof(struct table_set_header))
+		goto fail;
+
+	if (ntohl(*(u32 *) data) != YYTH_MAGIC)
+		goto fail;
+
+	hsize = ntohl(*(u32 *) (data + 4));
+	if (size < hsize)
+		goto fail;
+
+	dfa->flags = ntohs(*(u16 *) (data + 12));
+	data += hsize;
+	size -= hsize;
+
+	while (size > 0) {
+		table = unpack_table(data, size);
+		if (!table)
+			goto fail;
+
+		switch (table->td_id) {
+		case YYTD_ID_ACCEPT:
+			if (!(table->td_flags & ACCEPT1_FLAGS(flags)))
+				goto fail;
+			break;
+		case YYTD_ID_ACCEPT2:
+			if (!(table->td_flags & ACCEPT2_FLAGS(flags)))
+				goto fail;
+			break;
+		case YYTD_ID_BASE:
+			if (table->td_flags != YYTD_DATA32)
+				goto fail;
+			break;
+		case YYTD_ID_DEF:
+		case YYTD_ID_NXT:
+		case YYTD_ID_CHK:
+			if (table->td_flags != YYTD_DATA16)
+				goto fail;
+			break;
+		case YYTD_ID_EC:
+			if (table->td_flags != YYTD_DATA8)
+				goto fail;
+			break;
+		default:
+			goto fail;
+		}
+		/* check for duplicate table entry */
+		if (dfa->tables[table->td_id])
+			goto fail;
+		dfa->tables[table->td_id] = table;
+		data += table_size(table->td_lolen, table->td_flags);
+		size -= table_size(table->td_lolen, table->td_flags);
+		table = NULL;
+	}
+
+	error = verify_dfa(dfa, flags);
+	if (error)
+		goto fail;
+
+	return dfa;
+
+fail:
+	kvfree(table);
+	dfa_free(dfa);
+	return ERR_PTR(error);
+}
+
+/**
+ * aa_dfa_match_len - traverse @dfa to find state @str stops at
+ * @dfa: the dfa to match @str against  (NOT NULL)
+ * @start: the state of the dfa to start matching in
+ * @str: the string of bytes to match against the dfa  (NOT NULL)
+ * @len: length of the string of bytes to match
+ *
+ * aa_dfa_match_len will match @str against the dfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
+ *
+ * This function will happily match again the 0 byte and only finishes
+ * when @len input is consumed.
+ *
+ * Returns: final state reached after input is consumed
+ */
+unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
+			      const char *str, int len)
+{
+	u16 *def = DEFAULT_TABLE(dfa);
+	u32 *base = BASE_TABLE(dfa);
+	u16 *next = NEXT_TABLE(dfa);
+	u16 *check = CHECK_TABLE(dfa);
+	unsigned int state = start, pos;
+
+	if (state == 0)
+		return 0;
+
+	/* current state is <state>, matching character *str */
+	if (dfa->tables[YYTD_ID_EC]) {
+		/* Equivalence class table defined */
+		u8 *equiv = EQUIV_TABLE(dfa);
+		/* default is direct to next state */
+		for (; len; len--) {
+			pos = base[state] + equiv[(u8) *str++];
+			if (check[pos] == state)
+				state = next[pos];
+			else
+				state = def[state];
+		}
+	} else {
+		/* default is direct to next state */
+		for (; len; len--) {
+			pos = base[state] + (u8) *str++;
+			if (check[pos] == state)
+				state = next[pos];
+			else
+				state = def[state];
+		}
+	}
+
+	return state;
+}
+
+/**
+ * aa_dfa_next_state - traverse @dfa to find state @str stops at
+ * @dfa: the dfa to match @str against  (NOT NULL)
+ * @start: the state of the dfa to start matching in
+ * @str: the null terminated string of bytes to match against the dfa (NOT NULL)
+ *
+ * aa_dfa_next_state will match @str against the dfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
+ *
+ * Returns: final state reached after input is consumed
+ */
+unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
+			  const char *str)
+{
+	return aa_dfa_match_len(dfa, start, str, strlen(str));
+}
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
new file mode 100644
index 0000000..96bab94
--- /dev/null
+++ b/security/apparmor/path.c
@@ -0,0 +1,235 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor function for pathnames
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#include <linux/magic.h>
+#include <linux/mnt_namespace.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/nsproxy.h>
+#include <linux/path.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/fs_struct.h>
+
+#include "include/apparmor.h"
+#include "include/path.h"
+#include "include/policy.h"
+
+
+/* modified from dcache.c */
+static int prepend(char **buffer, int buflen, const char *str, int namelen)
+{
+	buflen -= namelen;
+	if (buflen < 0)
+		return -ENAMETOOLONG;
+	*buffer -= namelen;
+	memcpy(*buffer, str, namelen);
+	return 0;
+}
+
+#define CHROOT_NSCONNECT (PATH_CHROOT_REL | PATH_CHROOT_NSCONNECT)
+
+/**
+ * d_namespace_path - lookup a name associated with a given path
+ * @path: path to lookup  (NOT NULL)
+ * @buf:  buffer to store path to  (NOT NULL)
+ * @buflen: length of @buf
+ * @name: Returns - pointer for start of path name with in @buf (NOT NULL)
+ * @flags: flags controlling path lookup
+ *
+ * Handle path name lookup.
+ *
+ * Returns: %0 else error code if path lookup fails
+ *          When no error the path name is returned in @name which points to
+ *          to a position in @buf
+ */
+static int d_namespace_path(struct path *path, char *buf, int buflen,
+			    char **name, int flags)
+{
+	struct path root, tmp;
+	char *res;
+	int deleted, connected;
+	int error = 0;
+
+	/* Get the root we want to resolve too */
+	if (flags & PATH_CHROOT_REL) {
+		/* resolve paths relative to chroot */
+		read_lock(&current->fs->lock);
+		root = current->fs->root;
+		/* released below */
+		path_get(&root);
+		read_unlock(&current->fs->lock);
+	} else {
+		/* resolve paths relative to namespace */
+		root.mnt = current->nsproxy->mnt_ns->root;
+		root.dentry = root.mnt->mnt_root;
+		/* released below */
+		path_get(&root);
+	}
+
+	spin_lock(&dcache_lock);
+	/* There is a race window between path lookup here and the
+	 * need to strip the " (deleted) string that __d_path applies
+	 * Detect the race and relookup the path
+	 *
+	 * The stripping of (deleted) is a hack that could be removed
+	 * with an updated __d_path
+	 */
+	do {
+		tmp = root;
+		deleted = d_unlinked(path->dentry);
+		res = __d_path(path, &tmp, buf, buflen);
+
+	} while (deleted != d_unlinked(path->dentry));
+	spin_unlock(&dcache_lock);
+
+	*name = res;
+	/* handle error conditions - and still allow a partial path to
+	 * be returned.
+	 */
+	if (IS_ERR(res)) {
+		error = PTR_ERR(res);
+		*name = buf;
+		goto out;
+	}
+	if (deleted) {
+		/* On some filesystems, newly allocated dentries appear to the
+		 * security_path hooks as a deleted dentry except without an
+		 * inode allocated.
+		 *
+		 * Remove the appended deleted text and return as string for
+		 * normal mediation, or auditing.  The (deleted) string is
+		 * guaranteed to be added in this case, so just strip it.
+		 */
+		buf[buflen - 11] = 0;	/* - (len(" (deleted)") +\0) */
+
+		if (path->dentry->d_inode && !(flags & PATH_MEDIATE_DELETED)) {
+			error = -ENOENT;
+			goto out;
+		}
+	}
+
+	/* Determine if the path is connected to the expected root */
+	connected = tmp.dentry == root.dentry && tmp.mnt == root.mnt;
+
+	/* If the path is not connected,
+	 * check if it is a sysctl and handle specially else remove any
+	 * leading / that __d_path may have returned.
+	 * Unless
+	 *     specifically directed to connect the path,
+	 * OR
+	 *     if in a chroot and doing chroot relative paths and the path
+	 *     resolves to the namespace root (would be connected outside
+	 *     of chroot) and specifically directed to connect paths to
+	 *     namespace root.
+	 */
+	if (!connected) {
+		/* is the disconnect path a sysctl? */
+		if (tmp.dentry->d_sb->s_magic == PROC_SUPER_MAGIC &&
+		    strncmp(*name, "/sys/", 5) == 0) {
+			/* TODO: convert over to using a per namespace
+			 * control instead of hard coded /proc
+			 */
+			error = prepend(name, *name - buf, "/proc", 5);
+		} else if (!(flags & PATH_CONNECT_PATH) &&
+			   !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&
+			     (tmp.mnt == current->nsproxy->mnt_ns->root &&
+			      tmp.dentry == tmp.mnt->mnt_root))) {
+			/* disconnected path, don't return pathname starting
+			 * with '/'
+			 */
+			error = -ESTALE;
+			if (*res == '/')
+				*name = res + 1;
+		}
+	}
+
+out:
+	path_put(&root);
+
+	return error;
+}
+
+/**
+ * get_name_to_buffer - get the pathname to a buffer ensure dir / is appended
+ * @path: path to get name for  (NOT NULL)
+ * @flags: flags controlling path lookup
+ * @buffer: buffer to put name in  (NOT NULL)
+ * @size: size of buffer
+ * @name: Returns - contains position of path name in @buffer (NOT NULL)
+ *
+ * Returns: %0 else error on failure
+ */
+static int get_name_to_buffer(struct path *path, int flags, char *buffer,
+			      int size, char **name)
+{
+	int adjust = (flags & PATH_IS_DIR) ? 1 : 0;
+	int error = d_namespace_path(path, buffer, size - adjust, name, flags);
+
+	if (!error && (flags & PATH_IS_DIR) && (*name)[1] != '\0')
+		/*
+		 * Append "/" to the pathname.  The root directory is a special
+		 * case; it already ends in slash.
+		 */
+		strcpy(&buffer[size - 2], "/");
+
+	return error;
+}
+
+/**
+ * aa_get_name - compute the pathname of a file
+ * @path: path the file  (NOT NULL)
+ * @flags: flags controlling path name generation
+ * @buffer: buffer that aa_get_name() allocated  (NOT NULL)
+ * @name: Returns - the generated path name if !error (NOT NULL)
+ *
+ * @name is a pointer to the beginning of the pathname (which usually differs
+ * from the beginning of the buffer), or NULL.  If there is an error @name
+ * may contain a partial or invalid name that can be used for audit purposes,
+ * but it can not be used for mediation.
+ *
+ * We need PATH_IS_DIR to indicate whether the file is a directory or not
+ * because the file may not yet exist, and so we cannot check the inode's
+ * file type.
+ *
+ * Returns: %0 else error code if could retrieve name
+ */
+int aa_get_name(struct path *path, int flags, char **buffer, const char **name)
+{
+	char *buf, *str = NULL;
+	int size = 256;
+	int error;
+
+	*name = NULL;
+	*buffer = NULL;
+	for (;;) {
+		/* freed by caller */
+		buf = kmalloc(size, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+
+		error = get_name_to_buffer(path, flags, buf, size, &str);
+		if (error != -ENAMETOOLONG)
+			break;
+
+		kfree(buf);
+		size <<= 1;
+		if (size > aa_g_path_max)
+			return -ENAMETOOLONG;
+	}
+	*buffer = buf;
+	*name = str;
+
+	return error;
+}
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
new file mode 100644
index 0000000..3cdc1ad
--- /dev/null
+++ b/security/apparmor/policy.c
@@ -0,0 +1,1184 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy manipulation functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ *
+ *
+ * AppArmor policy is based around profiles, which contain the rules a
+ * task is confined by.  Every task in the system has a profile attached
+ * to it determined either by matching "unconfined" tasks against the
+ * visible set of profiles or by following a profiles attachment rules.
+ *
+ * Each profile exists in a profile namespace which is a container of
+ * visible profiles.  Each namespace contains a special "unconfined" profile,
+ * which doesn't enforce any confinement on a task beyond DAC.
+ *
+ * Namespace and profile names can be written together in either
+ * of two syntaxes.
+ *	:namespace:profile - used by kernel interfaces for easy detection
+ *	namespace://profile - used by policy
+ *
+ * Profile names can not start with : or @ or ^ and may not contain \0
+ *
+ * Reserved profile names
+ *	unconfined - special automatically generated unconfined profile
+ *	inherit - special name to indicate profile inheritance
+ *	null-XXXX-YYYY - special automatically generated learning profiles
+ *
+ * Namespace names may not start with / or @ and may not contain \0 or :
+ * Reserved namespace names
+ *	user-XXXX - user defined profiles
+ *
+ * a // in a profile or namespace name indicates a hierarchical name with the
+ * name before the // being the parent and the name after the child.
+ *
+ * Profile and namespace hierarchies serve two different but similar purposes.
+ * The namespace contains the set of visible profiles that are considered
+ * for attachment.  The hierarchy of namespaces allows for virtualizing
+ * the namespace so that for example a chroot can have its own set of profiles
+ * which may define some local user namespaces.
+ * The profile hierarchy severs two distinct purposes,
+ * -  it allows for sub profiles or hats, which allows an application to run
+ *    subprograms under its own profile with different restriction than it
+ *    self, and not have it use the system profile.
+ *    eg. if a mail program starts an editor, the policy might make the
+ *        restrictions tighter on the editor tighter than the mail program,
+ *        and definitely different than general editor restrictions
+ * - it allows for binary hierarchy of profiles, so that execution history
+ *   is preserved.  This feature isn't exploited by AppArmor reference policy
+ *   but is allowed.  NOTE: this is currently suboptimal because profile
+ *   aliasing is not currently implemented so that a profile for each
+ *   level must be defined.
+ *   eg. /bin/bash///bin/ls as a name would indicate /bin/ls was started
+ *       from /bin/bash
+ *
+ *   A profile or namespace name that can contain one or more // separators
+ *   is referred to as an hname (hierarchical).
+ *   eg.  /bin/bash//bin/ls
+ *
+ *   An fqname is a name that may contain both namespace and profile hnames.
+ *   eg. :ns:/bin/bash//bin/ls
+ *
+ * NOTES:
+ *   - locking of profile lists is currently fairly coarse.  All profile
+ *     lists within a namespace use the namespace lock.
+ * FIXME: move profile lists to using rcu_lists
+ */
+
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+#include "include/apparmor.h"
+#include "include/capability.h"
+#include "include/context.h"
+#include "include/file.h"
+#include "include/ipc.h"
+#include "include/match.h"
+#include "include/path.h"
+#include "include/policy.h"
+#include "include/policy_unpack.h"
+#include "include/resource.h"
+#include "include/sid.h"
+
+
+/* root profile namespace */
+struct aa_namespace *root_ns;
+
+const char *profile_mode_names[] = {
+	"enforce",
+	"complain",
+	"kill",
+};
+
+/**
+ * hname_tail - find the last component of an hname
+ * @name: hname to find the base profile name component of  (NOT NULL)
+ *
+ * Returns: the tail (base profile name) name component of an hname
+ */
+static const char *hname_tail(const char *hname)
+{
+	char *split;
+	hname = strim((char *)hname);
+	for (split = strstr(hname, "//"); split; split = strstr(hname, "//"))
+		hname = split + 2;
+
+	return hname;
+}
+
+/**
+ * policy_init - initialize a policy structure
+ * @policy: policy to initialize  (NOT NULL)
+ * @prefix: prefix name if any is required.  (MAYBE NULL)
+ * @name: name of the policy, init will make a copy of it  (NOT NULL)
+ *
+ * Note: this fn creates a copy of strings passed in
+ *
+ * Returns: true if policy init successful
+ */
+static bool policy_init(struct aa_policy *policy, const char *prefix,
+			const char *name)
+{
+	/* freed by policy_free */
+	if (prefix) {
+		policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3,
+					GFP_KERNEL);
+		if (policy->hname)
+			sprintf(policy->hname, "%s//%s", prefix, name);
+	} else
+		policy->hname = kstrdup(name, GFP_KERNEL);
+	if (!policy->hname)
+		return 0;
+	/* base.name is a substring of fqname */
+	policy->name = (char *)hname_tail(policy->hname);
+	INIT_LIST_HEAD(&policy->list);
+	INIT_LIST_HEAD(&policy->profiles);
+	kref_init(&policy->count);
+
+	return 1;
+}
+
+/**
+ * policy_destroy - free the elements referenced by @policy
+ * @policy: policy that is to have its elements freed  (NOT NULL)
+ */
+static void policy_destroy(struct aa_policy *policy)
+{
+	/* still contains profiles -- invalid */
+	if (!list_empty(&policy->profiles)) {
+		AA_ERROR("%s: internal error, "
+			 "policy '%s' still contains profiles\n",
+			 __func__, policy->name);
+		BUG();
+	}
+	if (!list_empty(&policy->list)) {
+		AA_ERROR("%s: internal error, policy '%s' still on list\n",
+			 __func__, policy->name);
+		BUG();
+	}
+
+	/* don't free name as its a subset of hname */
+	kzfree(policy->hname);
+}
+
+/**
+ * __policy_find - find a policy by @name on a policy list
+ * @head: list to search  (NOT NULL)
+ * @name: name to search for  (NOT NULL)
+ *
+ * Requires: correct locks for the @head list be held
+ *
+ * Returns: unrefcounted policy that match @name or NULL if not found
+ */
+static struct aa_policy *__policy_find(struct list_head *head, const char *name)
+{
+	struct aa_policy *policy;
+
+	list_for_each_entry(policy, head, list) {
+		if (!strcmp(policy->name, name))
+			return policy;
+	}
+	return NULL;
+}
+
+/**
+ * __policy_strn_find - find a policy that's name matches @len chars of @str
+ * @head: list to search  (NOT NULL)
+ * @str: string to search for  (NOT NULL)
+ * @len: length of match required
+ *
+ * Requires: correct locks for the @head list be held
+ *
+ * Returns: unrefcounted policy that match @str or NULL if not found
+ *
+ * if @len == strlen(@strlen) then this is equiv to __policy_find
+ * other wise it allows searching for policy by a partial match of name
+ */
+static struct aa_policy *__policy_strn_find(struct list_head *head,
+					    const char *str, int len)
+{
+	struct aa_policy *policy;
+
+	list_for_each_entry(policy, head, list) {
+		if (aa_strneq(policy->name, str, len))
+			return policy;
+	}
+
+	return NULL;
+}
+
+/*
+ * Routines for AppArmor namespaces
+ */
+
+static const char *hidden_ns_name = "---";
+/**
+ * aa_ns_visible - test if @view is visible from @curr
+ * @curr: namespace to treat as the parent (NOT NULL)
+ * @view:  namespace to test if visible from @curr (NOT NULL)
+ *
+ * Returns: true if @view is visible from @curr else false
+ */
+bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view)
+{
+	if (curr == view)
+		return true;
+
+	for ( ; view; view = view->parent) {
+		if (view->parent == curr)
+			return true;
+	}
+	return false;
+}
+
+/**
+ * aa_na_name - Find the ns name to display for @view from @curr
+ * @curr - current namespace (NOT NULL)
+ * @view - namespace attempting to view (NOT NULL)
+ *
+ * Returns: name of @view visible from @curr
+ */
+const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view)
+{
+	/* if view == curr then the namespace name isn't displayed */
+	if (curr == view)
+		return "";
+
+	if (aa_ns_visible(curr, view)) {
+		/* at this point if a ns is visible it is in a view ns
+		 * thus the curr ns.hname is a prefix of its name.
+		 * Only output the virtualized portion of the name
+		 * Add + 2 to skip over // separating curr hname prefix
+		 * from the visible tail of the views hname
+		 */
+		return view->base.hname + strlen(curr->base.hname) + 2;
+	} else
+		return hidden_ns_name;
+}
+
+/**
+ * alloc_namespace - allocate, initialize and return a new namespace
+ * @prefix: parent namespace name (MAYBE NULL)
+ * @name: a preallocated name  (NOT NULL)
+ *
+ * Returns: refcounted namespace or NULL on failure.
+ */
+static struct aa_namespace *alloc_namespace(const char *prefix,
+					    const char *name)
+{
+	struct aa_namespace *ns;
+
+	ns = kzalloc(sizeof(*ns), GFP_KERNEL);
+	AA_DEBUG("%s(%p)\n", __func__, ns);
+	if (!ns)
+		return NULL;
+	if (!policy_init(&ns->base, prefix, name))
+		goto fail_ns;
+
+	INIT_LIST_HEAD(&ns->sub_ns);
+	rwlock_init(&ns->lock);
+
+	/* released by free_namespace */
+	ns->unconfined = aa_alloc_profile("unconfined");
+	if (!ns->unconfined)
+		goto fail_unconfined;
+
+	ns->unconfined->sid = aa_alloc_sid();
+	ns->unconfined->flags = PFLAG_UNCONFINED | PFLAG_IX_ON_NAME_ERROR |
+	    PFLAG_IMMUTABLE;
+
+	/*
+	 * released by free_namespace, however __remove_namespace breaks
+	 * the cyclic references (ns->unconfined, and unconfined->ns) and
+	 * replaces with refs to parent namespace unconfined
+	 */
+	ns->unconfined->ns = aa_get_namespace(ns);
+
+	return ns;
+
+fail_unconfined:
+	kzfree(ns->base.name);
+fail_ns:
+	kzfree(ns);
+	return NULL;
+}
+
+/**
+ * free_namespace - free a profile namespace
+ * @ns: the namespace to free  (MAYBE NULL)
+ *
+ * Requires: All references to the namespace must have been put, if the
+ *           namespace was referenced by a profile confining a task,
+ */
+static void free_namespace(struct aa_namespace *ns)
+{
+	if (!ns)
+		return;
+
+	policy_destroy(&ns->base);
+	aa_put_namespace(ns->parent);
+
+	if (ns->unconfined && ns->unconfined->ns == ns)
+		ns->unconfined->ns = NULL;
+
+	aa_put_profile(ns->unconfined);
+	kzfree(ns);
+}
+
+/**
+ * aa_free_namespace_kref - free aa_namespace by kref (see aa_put_namespace)
+ * @kr: kref callback for freeing of a namespace  (NOT NULL)
+ */
+void aa_free_namespace_kref(struct kref *kref)
+{
+	free_namespace(container_of(kref, struct aa_namespace, base.count));
+}
+
+/**
+ * __aa_find_namespace - find a namespace on a list by @name
+ * @head: list to search for namespace on  (NOT NULL)
+ * @name: name of namespace to look for  (NOT NULL)
+ *
+ * Returns: unrefcounted namespace
+ *
+ * Requires: ns lock be held
+ */
+static struct aa_namespace *__aa_find_namespace(struct list_head *head,
+						const char *name)
+{
+	return (struct aa_namespace *)__policy_find(head, name);
+}
+
+/**
+ * aa_find_namespace  -  look up a profile namespace on the namespace list
+ * @root: namespace to search in  (NOT NULL)
+ * @name: name of namespace to find  (NOT NULL)
+ *
+ * Returns: a refcounted namespace on the list, or NULL if no namespace
+ *          called @name exists.
+ *
+ * refcount released by caller
+ */
+struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
+				       const char *name)
+{
+	struct aa_namespace *ns = NULL;
+
+	read_lock(&root->lock);
+	ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name));
+	read_unlock(&root->lock);
+
+	return ns;
+}
+
+/**
+ * aa_prepare_namespace - find an existing or create a new namespace of @name
+ * @name: the namespace to find or add  (MAYBE NULL)
+ *
+ * Returns: refcounted namespace or NULL if failed to create one
+ */
+static struct aa_namespace *aa_prepare_namespace(const char *name)
+{
+	struct aa_namespace *ns, *root;
+
+	root = aa_current_profile()->ns;
+
+	write_lock(&root->lock);
+
+	/* if name isn't specified the profile is loaded to the current ns */
+	if (!name) {
+		/* released by caller */
+		ns = aa_get_namespace(root);
+		goto out;
+	}
+
+	/* try and find the specified ns and if it doesn't exist create it */
+	/* released by caller */
+	ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name));
+	if (!ns) {
+		/* namespace not found */
+		struct aa_namespace *new_ns;
+		write_unlock(&root->lock);
+		new_ns = alloc_namespace(root->base.hname, name);
+		if (!new_ns)
+			return NULL;
+		write_lock(&root->lock);
+		/* test for race when new_ns was allocated */
+		ns = __aa_find_namespace(&root->sub_ns, name);
+		if (!ns) {
+			/* add parent ref */
+			new_ns->parent = aa_get_namespace(root);
+
+			list_add(&new_ns->base.list, &root->sub_ns);
+			/* add list ref */
+			ns = aa_get_namespace(new_ns);
+		} else {
+			/* raced so free the new one */
+			free_namespace(new_ns);
+			/* get reference on namespace */
+			aa_get_namespace(ns);
+		}
+	}
+out:
+	write_unlock(&root->lock);
+
+	/* return ref */
+	return ns;
+}
+
+/**
+ * __list_add_profile - add a profile to a list
+ * @list: list to add it to  (NOT NULL)
+ * @profile: the profile to add  (NOT NULL)
+ *
+ * refcount @profile, should be put by __list_remove_profile
+ *
+ * Requires: namespace lock be held, or list not be shared
+ */
+static void __list_add_profile(struct list_head *list,
+			       struct aa_profile *profile)
+{
+	list_add(&profile->base.list, list);
+	/* get list reference */
+	aa_get_profile(profile);
+}
+
+/**
+ * __list_remove_profile - remove a profile from the list it is on
+ * @profile: the profile to remove  (NOT NULL)
+ *
+ * remove a profile from the list, warning generally removal should
+ * be done with __replace_profile as most profile removals are
+ * replacements to the unconfined profile.
+ *
+ * put @profile list refcount
+ *
+ * Requires: namespace lock be held, or list not have been live
+ */
+static void __list_remove_profile(struct aa_profile *profile)
+{
+	list_del_init(&profile->base.list);
+	if (!(profile->flags & PFLAG_NO_LIST_REF))
+		/* release list reference */
+		aa_put_profile(profile);
+}
+
+/**
+ * __replace_profile - replace @old with @new on a list
+ * @old: profile to be replaced  (NOT NULL)
+ * @new: profile to replace @old with  (NOT NULL)
+ *
+ * Will duplicate and refcount elements that @new inherits from @old
+ * and will inherit @old children.
+ *
+ * refcount @new for list, put @old list refcount
+ *
+ * Requires: namespace list lock be held, or list not be shared
+ */
+static void __replace_profile(struct aa_profile *old, struct aa_profile *new)
+{
+	struct aa_policy *policy;
+	struct aa_profile *child, *tmp;
+
+	if (old->parent)
+		policy = &old->parent->base;
+	else
+		policy = &old->ns->base;
+
+	/* released when @new is freed */
+	new->parent = aa_get_profile(old->parent);
+	new->ns = aa_get_namespace(old->ns);
+	new->sid = old->sid;
+	__list_add_profile(&policy->profiles, new);
+	/* inherit children */
+	list_for_each_entry_safe(child, tmp, &old->base.profiles, base.list) {
+		aa_put_profile(child->parent);
+		child->parent = aa_get_profile(new);
+		/* list refcount transferred to @new*/
+		list_move(&child->base.list, &new->base.profiles);
+	}
+
+	/* released by free_profile */
+	old->replacedby = aa_get_profile(new);
+	__list_remove_profile(old);
+}
+
+static void __profile_list_release(struct list_head *head);
+
+/**
+ * __remove_profile - remove old profile, and children
+ * @profile: profile to be replaced  (NOT NULL)
+ *
+ * Requires: namespace list lock be held, or list not be shared
+ */
+static void __remove_profile(struct aa_profile *profile)
+{
+	/* release any children lists first */
+	__profile_list_release(&profile->base.profiles);
+	/* released by free_profile */
+	profile->replacedby = aa_get_profile(profile->ns->unconfined);
+	__list_remove_profile(profile);
+}
+
+/**
+ * __profile_list_release - remove all profiles on the list and put refs
+ * @head: list of profiles  (NOT NULL)
+ *
+ * Requires: namespace lock be held
+ */
+static void __profile_list_release(struct list_head *head)
+{
+	struct aa_profile *profile, *tmp;
+	list_for_each_entry_safe(profile, tmp, head, base.list)
+		__remove_profile(profile);
+}
+
+static void __ns_list_release(struct list_head *head);
+
+/**
+ * destroy_namespace - remove everything contained by @ns
+ * @ns: namespace to have it contents removed  (NOT NULL)
+ */
+static void destroy_namespace(struct aa_namespace *ns)
+{
+	if (!ns)
+		return;
+
+	write_lock(&ns->lock);
+	/* release all profiles in this namespace */
+	__profile_list_release(&ns->base.profiles);
+
+	/* release all sub namespaces */
+	__ns_list_release(&ns->sub_ns);
+
+	write_unlock(&ns->lock);
+}
+
+/**
+ * __remove_namespace - remove a namespace and all its children
+ * @ns: namespace to be removed  (NOT NULL)
+ *
+ * Requires: ns->parent->lock be held and ns removed from parent.
+ */
+static void __remove_namespace(struct aa_namespace *ns)
+{
+	struct aa_profile *unconfined = ns->unconfined;
+
+	/* remove ns from namespace list */
+	list_del_init(&ns->base.list);
+
+	/*
+	 * break the ns, unconfined profile cyclic reference and forward
+	 * all new unconfined profiles requests to the parent namespace
+	 * This will result in all confined tasks that have a profile
+	 * being removed, inheriting the parent->unconfined profile.
+	 */
+	if (ns->parent)
+		ns->unconfined = aa_get_profile(ns->parent->unconfined);
+
+	destroy_namespace(ns);
+
+	/* release original ns->unconfined ref */
+	aa_put_profile(unconfined);
+	/* release ns->base.list ref, from removal above */
+	aa_put_namespace(ns);
+}
+
+/**
+ * __ns_list_release - remove all profile namespaces on the list put refs
+ * @head: list of profile namespaces  (NOT NULL)
+ *
+ * Requires: namespace lock be held
+ */
+static void __ns_list_release(struct list_head *head)
+{
+	struct aa_namespace *ns, *tmp;
+	list_for_each_entry_safe(ns, tmp, head, base.list)
+		__remove_namespace(ns);
+
+}
+
+/**
+ * aa_alloc_root_ns - allocate the root profile namespace
+ *
+ * Returns: %0 on success else error
+ *
+ */
+int __init aa_alloc_root_ns(void)
+{
+	/* released by aa_free_root_ns - used as list ref*/
+	root_ns = alloc_namespace(NULL, "root");
+	if (!root_ns)
+		return -ENOMEM;
+
+	return 0;
+}
+
+ /**
+  * aa_free_root_ns - free the root profile namespace
+  */
+void __init aa_free_root_ns(void)
+ {
+	 struct aa_namespace *ns = root_ns;
+	 root_ns = NULL;
+
+	 destroy_namespace(ns);
+	 aa_put_namespace(ns);
+}
+
+/**
+ * aa_alloc_profile - allocate, initialize and return a new profile
+ * @hname: name of the profile  (NOT NULL)
+ *
+ * Returns: refcount profile or NULL on failure
+ */
+struct aa_profile *aa_alloc_profile(const char *hname)
+{
+	struct aa_profile *profile;
+
+	/* freed by free_profile - usually through aa_put_profile */
+	profile = kzalloc(sizeof(*profile), GFP_KERNEL);
+	if (!profile)
+		return NULL;
+
+	if (!policy_init(&profile->base, NULL, hname)) {
+		kzfree(profile);
+		return NULL;
+	}
+
+	/* refcount released by caller */
+	return profile;
+}
+
+/**
+ * aa_new_null_profile - create a new null-X learning profile
+ * @parent: profile that caused this profile to be created (NOT NULL)
+ * @hat: true if the null- learning profile is a hat
+ *
+ * Create a null- complain mode profile used in learning mode.  The name of
+ * the profile is unique and follows the format of parent//null-sid.
+ *
+ * null profiles are added to the profile list but the list does not
+ * hold a count on them so that they are automatically released when
+ * not in use.
+ *
+ * Returns: new refcounted profile else NULL on failure
+ */
+struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
+{
+	struct aa_profile *profile = NULL;
+	char *name;
+	u32 sid = aa_alloc_sid();
+
+	/* freed below */
+	name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL);
+	if (!name)
+		goto fail;
+	sprintf(name, "%s//null-%x", parent->base.hname, sid);
+
+	profile = aa_alloc_profile(name);
+	kfree(name);
+	if (!profile)
+		goto fail;
+
+	profile->sid = sid;
+	profile->mode = APPARMOR_COMPLAIN;
+	profile->flags = PFLAG_NULL;
+	if (hat)
+		profile->flags |= PFLAG_HAT;
+
+	/* released on free_profile */
+	profile->parent = aa_get_profile(parent);
+	profile->ns = aa_get_namespace(parent->ns);
+
+	write_lock(&profile->ns->lock);
+	__list_add_profile(&parent->base.profiles, profile);
+	write_unlock(&profile->ns->lock);
+
+	/* refcount released by caller */
+	return profile;
+
+fail:
+	aa_free_sid(sid);
+	return NULL;
+}
+
+/**
+ * free_profile - free a profile
+ * @profile: the profile to free  (MAYBE NULL)
+ *
+ * Free a profile, its hats and null_profile. All references to the profile,
+ * its hats and null_profile must have been put.
+ *
+ * If the profile was referenced from a task context, free_profile() will
+ * be called from an rcu callback routine, so we must not sleep here.
+ */
+static void free_profile(struct aa_profile *profile)
+{
+	AA_DEBUG("%s(%p)\n", __func__, profile);
+
+	if (!profile)
+		return;
+
+	if (!list_empty(&profile->base.list)) {
+		AA_ERROR("%s: internal error, "
+			 "profile '%s' still on ns list\n",
+			 __func__, profile->base.name);
+		BUG();
+	}
+
+	/* free children profiles */
+	policy_destroy(&profile->base);
+	aa_put_profile(profile->parent);
+
+	aa_put_namespace(profile->ns);
+	kzfree(profile->rename);
+
+	aa_free_file_rules(&profile->file);
+	aa_free_cap_rules(&profile->caps);
+	aa_free_rlimit_rules(&profile->rlimits);
+
+	aa_free_sid(profile->sid);
+	aa_put_dfa(profile->xmatch);
+
+	aa_put_profile(profile->replacedby);
+
+	kzfree(profile);
+}
+
+/**
+ * aa_free_profile_kref - free aa_profile by kref (called by aa_put_profile)
+ * @kr: kref callback for freeing of a profile  (NOT NULL)
+ */
+void aa_free_profile_kref(struct kref *kref)
+{
+	struct aa_profile *p = container_of(kref, struct aa_profile,
+					    base.count);
+
+	free_profile(p);
+}
+
+/* TODO: profile accounting - setup in remove */
+
+/**
+ * __find_child - find a profile on @head list with a name matching @name
+ * @head: list to search  (NOT NULL)
+ * @name: name of profile (NOT NULL)
+ *
+ * Requires: ns lock protecting list be held
+ *
+ * Returns: unrefcounted profile ptr, or NULL if not found
+ */
+static struct aa_profile *__find_child(struct list_head *head, const char *name)
+{
+	return (struct aa_profile *)__policy_find(head, name);
+}
+
+/**
+ * __strn_find_child - find a profile on @head list using substring of @name
+ * @head: list to search  (NOT NULL)
+ * @name: name of profile (NOT NULL)
+ * @len: length of @name substring to match
+ *
+ * Requires: ns lock protecting list be held
+ *
+ * Returns: unrefcounted profile ptr, or NULL if not found
+ */
+static struct aa_profile *__strn_find_child(struct list_head *head,
+					    const char *name, int len)
+{
+	return (struct aa_profile *)__policy_strn_find(head, name, len);
+}
+
+/**
+ * aa_find_child - find a profile by @name in @parent
+ * @parent: profile to search  (NOT NULL)
+ * @name: profile name to search for  (NOT NULL)
+ *
+ * Returns: a refcounted profile or NULL if not found
+ */
+struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name)
+{
+	struct aa_profile *profile;
+
+	read_lock(&parent->ns->lock);
+	profile = aa_get_profile(__find_child(&parent->base.profiles, name));
+	read_unlock(&parent->ns->lock);
+
+	/* refcount released by caller */
+	return profile;
+}
+
+/**
+ * __lookup_parent - lookup the parent of a profile of name @hname
+ * @ns: namespace to lookup profile in  (NOT NULL)
+ * @hname: hierarchical profile name to find parent of  (NOT NULL)
+ *
+ * Lookups up the parent of a fully qualified profile name, the profile
+ * that matches hname does not need to exist, in general this
+ * is used to load a new profile.
+ *
+ * Requires: ns->lock be held
+ *
+ * Returns: unrefcounted policy or NULL if not found
+ */
+static struct aa_policy *__lookup_parent(struct aa_namespace *ns,
+					 const char *hname)
+{
+	struct aa_policy *policy;
+	struct aa_profile *profile = NULL;
+	char *split;
+
+	policy = &ns->base;
+
+	for (split = strstr(hname, "//"); split;) {
+		profile = __strn_find_child(&policy->profiles, hname,
+					    split - hname);
+		if (!profile)
+			return NULL;
+		policy = &profile->base;
+		hname = split + 2;
+		split = strstr(hname, "//");
+	}
+	if (!profile)
+		return &ns->base;
+	return &profile->base;
+}
+
+/**
+ * __lookup_profile - lookup the profile matching @hname
+ * @base: base list to start looking up profile name from  (NOT NULL)
+ * @hname: hierarchical profile name  (NOT NULL)
+ *
+ * Requires: ns->lock be held
+ *
+ * Returns: unrefcounted profile pointer or NULL if not found
+ *
+ * Do a relative name lookup, recursing through profile tree.
+ */
+static struct aa_profile *__lookup_profile(struct aa_policy *base,
+					   const char *hname)
+{
+	struct aa_profile *profile = NULL;
+	char *split;
+
+	for (split = strstr(hname, "//"); split;) {
+		profile = __strn_find_child(&base->profiles, hname,
+					    split - hname);
+		if (!profile)
+			return NULL;
+
+		base = &profile->base;
+		hname = split + 2;
+		split = strstr(hname, "//");
+	}
+
+	profile = __find_child(&base->profiles, hname);
+
+	return profile;
+}
+
+/**
+ * aa_lookup_profile - find a profile by its full or partial name
+ * @ns: the namespace to start from (NOT NULL)
+ * @hname: name to do lookup on.  Does not contain namespace prefix (NOT NULL)
+ *
+ * Returns: refcounted profile or NULL if not found
+ */
+struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname)
+{
+	struct aa_profile *profile;
+
+	read_lock(&ns->lock);
+	profile = aa_get_profile(__lookup_profile(&ns->base, hname));
+	read_unlock(&ns->lock);
+
+	/* refcount released by caller */
+	return profile;
+}
+
+/**
+ * replacement_allowed - test to see if replacement is allowed
+ * @profile: profile to test if it can be replaced  (MAYBE NULL)
+ * @noreplace: true if replacement shouldn't be allowed but addition is okay
+ * @info: Returns - info about why replacement failed (NOT NULL)
+ *
+ * Returns: %0 if replacement allowed else error code
+ */
+static int replacement_allowed(struct aa_profile *profile, int noreplace,
+			       const char **info)
+{
+	if (profile) {
+		if (profile->flags & PFLAG_IMMUTABLE) {
+			*info = "cannot replace immutible profile";
+			return -EPERM;
+		} else if (noreplace) {
+			*info = "profile already exists";
+			return -EEXIST;
+		}
+	}
+	return 0;
+}
+
+/**
+ * __add_new_profile - simple wrapper around __list_add_profile
+ * @ns: namespace that profile is being added to  (NOT NULL)
+ * @policy: the policy container to add the profile to  (NOT NULL)
+ * @profile: profile to add  (NOT NULL)
+ *
+ * add a profile to a list and do other required basic allocations
+ */
+static void __add_new_profile(struct aa_namespace *ns, struct aa_policy *policy,
+			      struct aa_profile *profile)
+{
+	if (policy != &ns->base)
+		/* released on profile replacement or free_profile */
+		profile->parent = aa_get_profile((struct aa_profile *) policy);
+	__list_add_profile(&policy->profiles, profile);
+	/* released on free_profile */
+	profile->sid = aa_alloc_sid();
+	profile->ns = aa_get_namespace(ns);
+}
+
+/**
+ * aa_audit_policy - Do auditing of policy changes
+ * @op: policy operation being performed
+ * @gfp: memory allocation flags
+ * @name: name of profile being manipulated (NOT NULL)
+ * @info: any extra information to be audited (MAYBE NULL)
+ * @error: error code
+ *
+ * Returns: the error to be returned after audit is done
+ */
+static int audit_policy(int op, gfp_t gfp, const char *name, const char *info,
+			int error)
+{
+	struct common_audit_data sa;
+	COMMON_AUDIT_DATA_INIT(&sa, NONE);
+	sa.aad.op = op;
+	sa.aad.name = name;
+	sa.aad.info = info;
+	sa.aad.error = error;
+
+	return aa_audit(AUDIT_APPARMOR_STATUS, __aa_current_profile(), gfp,
+			&sa, NULL);
+}
+
+/**
+ * aa_may_manage_policy - can the current task manage policy
+ * @op: the policy manipulation operation being done
+ *
+ * Returns: true if the task is allowed to manipulate policy
+ */
+bool aa_may_manage_policy(int op)
+{
+	/* check if loading policy is locked out */
+	if (aa_g_lock_policy) {
+		audit_policy(op, GFP_KERNEL, NULL, "policy_locked", -EACCES);
+		return 0;
+	}
+
+	if (!capable(CAP_MAC_ADMIN)) {
+		audit_policy(op, GFP_KERNEL, NULL, "not policy admin", -EACCES);
+		return 0;
+	}
+
+	return 1;
+}
+
+/**
+ * aa_replace_profiles - replace profile(s) on the profile list
+ * @udata: serialized data stream  (NOT NULL)
+ * @size: size of the serialized data stream
+ * @noreplace: true if only doing addition, no replacement allowed
+ *
+ * unpack and replace a profile on the profile list and uses of that profile
+ * by any aa_task_cxt.  If the profile does not exist on the profile list
+ * it is added.
+ *
+ * Returns: size of data consumed else error code on failure.
+ */
+ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
+{
+	struct aa_policy *policy;
+	struct aa_profile *old_profile = NULL, *new_profile = NULL;
+	struct aa_profile *rename_profile = NULL;
+	struct aa_namespace *ns = NULL;
+	const char *ns_name, *name = NULL, *info = NULL;
+	int op = OP_PROF_REPL;
+	ssize_t error;
+
+	/* released below */
+	new_profile = aa_unpack(udata, size, &ns_name);
+	if (IS_ERR(new_profile)) {
+		error = PTR_ERR(new_profile);
+		new_profile = NULL;
+		goto fail;
+	}
+
+	/* released below */
+	ns = aa_prepare_namespace(ns_name);
+	if (!ns) {
+		info = "failed to prepare namespace";
+		error = -ENOMEM;
+		name = ns_name;
+		goto fail;
+	}
+
+	name = new_profile->base.hname;
+
+	write_lock(&ns->lock);
+	/* no ref on policy only use inside lock */
+	policy = __lookup_parent(ns, new_profile->base.hname);
+
+	if (!policy) {
+		info = "parent does not exist";
+		error = -ENOENT;
+		goto audit;
+	}
+
+	old_profile = __find_child(&policy->profiles, new_profile->base.name);
+	/* released below */
+	aa_get_profile(old_profile);
+
+	if (new_profile->rename) {
+		rename_profile = __lookup_profile(&ns->base,
+						  new_profile->rename);
+		/* released below */
+		aa_get_profile(rename_profile);
+
+		if (!rename_profile) {
+			info = "profile to rename does not exist";
+			name = new_profile->rename;
+			error = -ENOENT;
+			goto audit;
+		}
+	}
+
+	error = replacement_allowed(old_profile, noreplace, &info);
+	if (error)
+		goto audit;
+
+	error = replacement_allowed(rename_profile, noreplace, &info);
+	if (error)
+		goto audit;
+
+audit:
+	if (!old_profile && !rename_profile)
+		op = OP_PROF_LOAD;
+
+	error = audit_policy(op, GFP_ATOMIC, name, info, error);
+
+	if (!error) {
+		if (rename_profile)
+			__replace_profile(rename_profile, new_profile);
+		if (old_profile) {
+			/* when there are both rename and old profiles
+			 * inherit old profiles sid
+			 */
+			if (rename_profile)
+				aa_free_sid(new_profile->sid);
+			__replace_profile(old_profile, new_profile);
+		}
+		if (!(old_profile || rename_profile))
+			__add_new_profile(ns, policy, new_profile);
+	}
+	write_unlock(&ns->lock);
+
+out:
+	aa_put_namespace(ns);
+	aa_put_profile(rename_profile);
+	aa_put_profile(old_profile);
+	aa_put_profile(new_profile);
+	if (error)
+		return error;
+	return size;
+
+fail:
+	error = audit_policy(op, GFP_KERNEL, name, info, error);
+	goto out;
+}
+
+/**
+ * aa_remove_profiles - remove profile(s) from the system
+ * @fqname: name of the profile or namespace to remove  (NOT NULL)
+ * @size: size of the name
+ *
+ * Remove a profile or sub namespace from the current namespace, so that
+ * they can not be found anymore and mark them as replaced by unconfined
+ *
+ * NOTE: removing confinement does not restore rlimits to preconfinemnet values
+ *
+ * Returns: size of data consume else error code if fails
+ */
+ssize_t aa_remove_profiles(char *fqname, size_t size)
+{
+	struct aa_namespace *root, *ns = NULL;
+	struct aa_profile *profile = NULL;
+	const char *name = fqname, *info = NULL;
+	ssize_t error = 0;
+
+	if (*fqname == 0) {
+		info = "no profile specified";
+		error = -ENOENT;
+		goto fail;
+	}
+
+	root = aa_current_profile()->ns;
+
+	if (fqname[0] == ':') {
+		char *ns_name;
+		name = aa_split_fqname(fqname, &ns_name);
+		if (ns_name) {
+			/* released below */
+			ns = aa_find_namespace(root, ns_name);
+			if (!ns) {
+				info = "namespace does not exist";
+				error = -ENOENT;
+				goto fail;
+			}
+		}
+	} else
+		/* released below */
+		ns = aa_get_namespace(root);
+
+	write_lock(&ns->lock);
+	if (!name) {
+		/* remove namespace - can only happen if fqname[0] == ':' */
+		__remove_namespace(ns);
+	} else {
+		/* remove profile */
+		profile = aa_get_profile(__lookup_profile(&ns->base, name));
+		if (!profile) {
+			error = -ENOENT;
+			info = "profile does not exist";
+			goto fail_ns_lock;
+		}
+		name = profile->base.hname;
+		__remove_profile(profile);
+	}
+	write_unlock(&ns->lock);
+
+	/* don't fail removal if audit fails */
+	(void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error);
+	aa_put_namespace(ns);
+	aa_put_profile(profile);
+	return size;
+
+fail_ns_lock:
+	write_unlock(&ns->lock);
+	aa_put_namespace(ns);
+
+fail:
+	(void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error);
+	return error;
+}
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
new file mode 100644
index 0000000..eb3700e
--- /dev/null
+++ b/security/apparmor/policy_unpack.c
@@ -0,0 +1,703 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor functions for unpacking policy loaded from
+ * userspace.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ *
+ * AppArmor uses a serialized binary format for loading policy.
+ * To find policy format documentation look in Documentation/apparmor.txt
+ * All policy is validated before it is used.
+ */
+
+#include <asm/unaligned.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/match.h"
+#include "include/policy.h"
+#include "include/policy_unpack.h"
+#include "include/sid.h"
+
+/*
+ * The AppArmor interface treats data as a type byte followed by the
+ * actual data.  The interface has the notion of a a named entry
+ * which has a name (AA_NAME typecode followed by name string) followed by
+ * the entries typecode and data.  Named types allow for optional
+ * elements and extensions to be added and tested for without breaking
+ * backwards compatibility.
+ */
+
+enum aa_code {
+	AA_U8,
+	AA_U16,
+	AA_U32,
+	AA_U64,
+	AA_NAME,		/* same as string except it is items name */
+	AA_STRING,
+	AA_BLOB,
+	AA_STRUCT,
+	AA_STRUCTEND,
+	AA_LIST,
+	AA_LISTEND,
+	AA_ARRAY,
+	AA_ARRAYEND,
+};
+
+/*
+ * aa_ext is the read of the buffer containing the serialized profile.  The
+ * data is copied into a kernel buffer in apparmorfs and then handed off to
+ * the unpack routines.
+ */
+struct aa_ext {
+	void *start;
+	void *end;
+	void *pos;		/* pointer to current position in the buffer */
+	u32 version;
+};
+
+/* audit callback for unpack fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+	struct common_audit_data *sa = va;
+	if (sa->aad.iface.target) {
+		struct aa_profile *name = sa->aad.iface.target;
+		audit_log_format(ab, " name=");
+		audit_log_untrustedstring(ab, name->base.hname);
+	}
+	if (sa->aad.iface.pos)
+		audit_log_format(ab, " offset=%ld", sa->aad.iface.pos);
+}
+
+/**
+ * audit_iface - do audit message for policy unpacking/load/replace/remove
+ * @new: profile if it has been allocated (MAYBE NULL)
+ * @name: name of the profile being manipulated (MAYBE NULL)
+ * @info: any extra info about the failure (MAYBE NULL)
+ * @e: buffer position info (NOT NULL)
+ * @error: error code
+ *
+ * Returns: %0 or error
+ */
+static int audit_iface(struct aa_profile *new, const char *name,
+		       const char *info, struct aa_ext *e, int error)
+{
+	struct aa_profile *profile = __aa_current_profile();
+	struct common_audit_data sa;
+	COMMON_AUDIT_DATA_INIT(&sa, NONE);
+	sa.aad.iface.pos = e->pos - e->start;
+	sa.aad.iface.target = new;
+	sa.aad.name = name;
+	sa.aad.info = info;
+	sa.aad.error = error;
+
+	return aa_audit(AUDIT_APPARMOR_STATUS, profile, GFP_KERNEL, &sa,
+			audit_cb);
+}
+
+/* test if read will be in packed data bounds */
+static bool inbounds(struct aa_ext *e, size_t size)
+{
+	return (size <= e->end - e->pos);
+}
+
+/**
+ * aa_u16_chunck - test and do bounds checking for a u16 size based chunk
+ * @e: serialized data read head (NOT NULL)
+ * @chunk: start address for chunk of data (NOT NULL)
+ *
+ * Returns: the size of chunk found with the read head at the end of the chunk.
+ */
+static size_t unpack_u16_chunk(struct aa_ext *e, char **chunk)
+{
+	size_t size = 0;
+
+	if (!inbounds(e, sizeof(u16)))
+		return 0;
+	size = le16_to_cpu(get_unaligned((u16 *) e->pos));
+	e->pos += sizeof(u16);
+	if (!inbounds(e, size))
+		return 0;
+	*chunk = e->pos;
+	e->pos += size;
+	return size;
+}
+
+/* unpack control byte */
+static bool unpack_X(struct aa_ext *e, enum aa_code code)
+{
+	if (!inbounds(e, 1))
+		return 0;
+	if (*(u8 *) e->pos != code)
+		return 0;
+	e->pos++;
+	return 1;
+}
+
+/**
+ * unpack_nameX - check is the next element is of type X with a name of @name
+ * @e: serialized data extent information  (NOT NULL)
+ * @code: type code
+ * @name: name to match to the serialized element.  (MAYBE NULL)
+ *
+ * check that the next serialized data element is of type X and has a tag
+ * name @name.  If @name is specified then there must be a matching
+ * name element in the stream.  If @name is NULL any name element will be
+ * skipped and only the typecode will be tested.
+ *
+ * Returns 1 on success (both type code and name tests match) and the read
+ * head is advanced past the headers
+ *
+ * Returns: 0 if either match fails, the read head does not move
+ */
+static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
+{
+	/*
+	 * May need to reset pos if name or type doesn't match
+	 */
+	void *pos = e->pos;
+	/*
+	 * Check for presence of a tagname, and if present name size
+	 * AA_NAME tag value is a u16.
+	 */
+	if (unpack_X(e, AA_NAME)) {
+		char *tag = NULL;
+		size_t size = unpack_u16_chunk(e, &tag);
+		/* if a name is specified it must match. otherwise skip tag */
+		if (name && (!size || strcmp(name, tag)))
+			goto fail;
+	} else if (name) {
+		/* if a name is specified and there is no name tag fail */
+		goto fail;
+	}
+
+	/* now check if type code matches */
+	if (unpack_X(e, code))
+		return 1;
+
+fail:
+	e->pos = pos;
+	return 0;
+}
+
+static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
+{
+	if (unpack_nameX(e, AA_U32, name)) {
+		if (!inbounds(e, sizeof(u32)))
+			return 0;
+		if (data)
+			*data = le32_to_cpu(get_unaligned((u32 *) e->pos));
+		e->pos += sizeof(u32);
+		return 1;
+	}
+	return 0;
+}
+
+static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name)
+{
+	if (unpack_nameX(e, AA_U64, name)) {
+		if (!inbounds(e, sizeof(u64)))
+			return 0;
+		if (data)
+			*data = le64_to_cpu(get_unaligned((u64 *) e->pos));
+		e->pos += sizeof(u64);
+		return 1;
+	}
+	return 0;
+}
+
+static size_t unpack_array(struct aa_ext *e, const char *name)
+{
+	if (unpack_nameX(e, AA_ARRAY, name)) {
+		int size;
+		if (!inbounds(e, sizeof(u16)))
+			return 0;
+		size = (int)le16_to_cpu(get_unaligned((u16 *) e->pos));
+		e->pos += sizeof(u16);
+		return size;
+	}
+	return 0;
+}
+
+static size_t unpack_blob(struct aa_ext *e, char **blob, const char *name)
+{
+	if (unpack_nameX(e, AA_BLOB, name)) {
+		u32 size;
+		if (!inbounds(e, sizeof(u32)))
+			return 0;
+		size = le32_to_cpu(get_unaligned((u32 *) e->pos));
+		e->pos += sizeof(u32);
+		if (inbounds(e, (size_t) size)) {
+			*blob = e->pos;
+			e->pos += size;
+			return size;
+		}
+	}
+	return 0;
+}
+
+static int unpack_str(struct aa_ext *e, const char **string, const char *name)
+{
+	char *src_str;
+	size_t size = 0;
+	void *pos = e->pos;
+	*string = NULL;
+	if (unpack_nameX(e, AA_STRING, name)) {
+		size = unpack_u16_chunk(e, &src_str);
+		if (size) {
+			/* strings are null terminated, length is size - 1 */
+			if (src_str[size - 1] != 0)
+				goto fail;
+			*string = src_str;
+		}
+	}
+	return size;
+
+fail:
+	e->pos = pos;
+	return 0;
+}
+
+static int unpack_strdup(struct aa_ext *e, char **string, const char *name)
+{
+	const char *tmp;
+	void *pos = e->pos;
+	int res = unpack_str(e, &tmp, name);
+	*string = NULL;
+
+	if (!res)
+		return 0;
+
+	*string = kmemdup(tmp, res, GFP_KERNEL);
+	if (!*string) {
+		e->pos = pos;
+		return 0;
+	}
+
+	return res;
+}
+
+/**
+ * verify_accept - verify the accept tables of a dfa
+ * @dfa: dfa to verify accept tables of (NOT NULL)
+ * @flags: flags governing dfa
+ *
+ * Returns: 1 if valid accept tables else 0 if error
+ */
+static bool verify_accept(struct aa_dfa *dfa, int flags)
+{
+	int i;
+
+	/* verify accept permissions */
+	for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) {
+		int mode = ACCEPT_TABLE(dfa)[i];
+
+		if (mode & ~DFA_VALID_PERM_MASK)
+			return 0;
+
+		if (ACCEPT_TABLE2(dfa)[i] & ~DFA_VALID_PERM2_MASK)
+			return 0;
+	}
+	return 1;
+}
+
+/**
+ * unpack_dfa - unpack a file rule dfa
+ * @e: serialized data extent information (NOT NULL)
+ *
+ * returns dfa or ERR_PTR or NULL if no dfa
+ */
+static struct aa_dfa *unpack_dfa(struct aa_ext *e)
+{
+	char *blob = NULL;
+	size_t size;
+	struct aa_dfa *dfa = NULL;
+
+	size = unpack_blob(e, &blob, "aadfa");
+	if (size) {
+		/*
+		 * The dfa is aligned with in the blob to 8 bytes
+		 * from the beginning of the stream.
+		 */
+		size_t sz = blob - (char *)e->start;
+		size_t pad = ALIGN(sz, 8) - sz;
+		int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |
+			TO_ACCEPT2_FLAG(YYTD_DATA32);
+
+
+		if (aa_g_paranoid_load)
+			flags |= DFA_FLAG_VERIFY_STATES;
+
+		dfa = aa_dfa_unpack(blob + pad, size - pad, flags);
+
+		if (IS_ERR(dfa))
+			return dfa;
+
+		if (!verify_accept(dfa, flags))
+			goto fail;
+	}
+
+	return dfa;
+
+fail:
+	aa_put_dfa(dfa);
+	return ERR_PTR(-EPROTO);
+}
+
+/**
+ * unpack_trans_table - unpack a profile transition table
+ * @e: serialized data extent information  (NOT NULL)
+ * @profile: profile to add the accept table to (NOT NULL)
+ *
+ * Returns: 1 if table succesfully unpacked
+ */
+static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
+{
+	void *pos = e->pos;
+
+	/* exec table is optional */
+	if (unpack_nameX(e, AA_STRUCT, "xtable")) {
+		int i, size;
+
+		size = unpack_array(e, NULL);
+		/* currently 4 exec bits and entries 0-3 are reserved iupcx */
+		if (size > 16 - 4)
+			goto fail;
+		profile->file.trans.table = kzalloc(sizeof(char *) * size,
+						    GFP_KERNEL);
+		if (!profile->file.trans.table)
+			goto fail;
+
+		profile->file.trans.size = size;
+		for (i = 0; i < size; i++) {
+			char *str;
+			int c, j, size = unpack_strdup(e, &str, NULL);
+			/* unpack_strdup verifies that the last character is
+			 * null termination byte.
+			 */
+			if (!size)
+				goto fail;
+			profile->file.trans.table[i] = str;
+			/* verify that name doesn't start with space */
+			if (isspace(*str))
+				goto fail;
+
+			/* count internal #  of internal \0 */
+			for (c = j = 0; j < size - 2; j++) {
+				if (!str[j])
+					c++;
+			}
+			if (*str == ':') {
+				/* beginning with : requires an embedded \0,
+				 * verify that exactly 1 internal \0 exists
+				 * trailing \0 already verified by unpack_strdup
+				 */
+				if (c != 1)
+					goto fail;
+				/* first character after : must be valid */
+				if (!str[1])
+					goto fail;
+			} else if (c)
+				/* fail - all other cases with embedded \0 */
+				goto fail;
+		}
+		if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+			goto fail;
+		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+			goto fail;
+	}
+	return 1;
+
+fail:
+	aa_free_domain_entries(&profile->file.trans);
+	e->pos = pos;
+	return 0;
+}
+
+static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
+{
+	void *pos = e->pos;
+
+	/* rlimits are optional */
+	if (unpack_nameX(e, AA_STRUCT, "rlimits")) {
+		int i, size;
+		u32 tmp = 0;
+		if (!unpack_u32(e, &tmp, NULL))
+			goto fail;
+		profile->rlimits.mask = tmp;
+
+		size = unpack_array(e, NULL);
+		if (size > RLIM_NLIMITS)
+			goto fail;
+		for (i = 0; i < size; i++) {
+			u64 tmp = 0;
+			int a = aa_map_resource(i);
+			if (!unpack_u64(e, &tmp, NULL))
+				goto fail;
+			profile->rlimits.limits[a].rlim_max = tmp;
+		}
+		if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+			goto fail;
+		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+			goto fail;
+	}
+	return 1;
+
+fail:
+	e->pos = pos;
+	return 0;
+}
+
+/**
+ * unpack_profile - unpack a serialized profile
+ * @e: serialized data extent information (NOT NULL)
+ *
+ * NOTE: unpack profile sets audit struct if there is a failure
+ */
+static struct aa_profile *unpack_profile(struct aa_ext *e)
+{
+	struct aa_profile *profile = NULL;
+	const char *name = NULL;
+	int error = -EPROTO;
+	kernel_cap_t tmpcap;
+	u32 tmp;
+
+	/* check that we have the right struct being passed */
+	if (!unpack_nameX(e, AA_STRUCT, "profile"))
+		goto fail;
+	if (!unpack_str(e, &name, NULL))
+		goto fail;
+
+	profile = aa_alloc_profile(name);
+	if (!profile)
+		return ERR_PTR(-ENOMEM);
+
+	/* profile renaming is optional */
+	(void) unpack_str(e, &profile->rename, "rename");
+
+	/* xmatch is optional and may be NULL */
+	profile->xmatch = unpack_dfa(e);
+	if (IS_ERR(profile->xmatch)) {
+		error = PTR_ERR(profile->xmatch);
+		profile->xmatch = NULL;
+		goto fail;
+	}
+	/* xmatch_len is not optional if xmatch is set */
+	if (profile->xmatch) {
+		if (!unpack_u32(e, &tmp, NULL))
+			goto fail;
+		profile->xmatch_len = tmp;
+	}
+
+	/* per profile debug flags (complain, audit) */
+	if (!unpack_nameX(e, AA_STRUCT, "flags"))
+		goto fail;
+	if (!unpack_u32(e, &tmp, NULL))
+		goto fail;
+	if (tmp)
+		profile->flags |= PFLAG_HAT;
+	if (!unpack_u32(e, &tmp, NULL))
+		goto fail;
+	if (tmp)
+		profile->mode = APPARMOR_COMPLAIN;
+	if (!unpack_u32(e, &tmp, NULL))
+		goto fail;
+	if (tmp)
+		profile->audit = AUDIT_ALL;
+
+	if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+		goto fail;
+
+	/* path_flags is optional */
+	if (unpack_u32(e, &profile->path_flags, "path_flags"))
+		profile->path_flags |= profile->flags & PFLAG_MEDIATE_DELETED;
+	else
+		/* set a default value if path_flags field is not present */
+		profile->path_flags = PFLAG_MEDIATE_DELETED;
+
+	if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
+		goto fail;
+	if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))
+		goto fail;
+	if (!unpack_u32(e, &(profile->caps.quiet.cap[0]), NULL))
+		goto fail;
+	if (!unpack_u32(e, &tmpcap.cap[0], NULL))
+		goto fail;
+
+	if (unpack_nameX(e, AA_STRUCT, "caps64")) {
+		/* optional upper half of 64 bit caps */
+		if (!unpack_u32(e, &(profile->caps.allow.cap[1]), NULL))
+			goto fail;
+		if (!unpack_u32(e, &(profile->caps.audit.cap[1]), NULL))
+			goto fail;
+		if (!unpack_u32(e, &(profile->caps.quiet.cap[1]), NULL))
+			goto fail;
+		if (!unpack_u32(e, &(tmpcap.cap[1]), NULL))
+			goto fail;
+		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+			goto fail;
+	}
+
+	if (unpack_nameX(e, AA_STRUCT, "capsx")) {
+		/* optional extended caps mediation mask */
+		if (!unpack_u32(e, &(profile->caps.extended.cap[0]), NULL))
+			goto fail;
+		if (!unpack_u32(e, &(profile->caps.extended.cap[1]), NULL))
+			goto fail;
+	}
+
+	if (!unpack_rlimits(e, profile))
+		goto fail;
+
+	/* get file rules */
+	profile->file.dfa = unpack_dfa(e);
+	if (IS_ERR(profile->file.dfa)) {
+		error = PTR_ERR(profile->file.dfa);
+		profile->file.dfa = NULL;
+		goto fail;
+	}
+
+	if (!unpack_u32(e, &profile->file.start, "dfa_start"))
+		/* default start state */
+		profile->file.start = DFA_START;
+
+	if (!unpack_trans_table(e, profile))
+		goto fail;
+
+	if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+		goto fail;
+
+	return profile;
+
+fail:
+	if (profile)
+		name = NULL;
+	else if (!name)
+		name = "unknown";
+	audit_iface(profile, name, "failed to unpack profile", e, error);
+	aa_put_profile(profile);
+
+	return ERR_PTR(error);
+}
+
+/**
+ * verify_head - unpack serialized stream header
+ * @e: serialized data read head (NOT NULL)
+ * @ns: Returns - namespace if one is specified else NULL (NOT NULL)
+ *
+ * Returns: error or 0 if header is good
+ */
+static int verify_header(struct aa_ext *e, const char **ns)
+{
+	int error = -EPROTONOSUPPORT;
+	/* get the interface version */
+	if (!unpack_u32(e, &e->version, "version")) {
+		audit_iface(NULL, NULL, "invalid profile format", e, error);
+		return error;
+	}
+
+	/* check that the interface version is currently supported */
+	if (e->version != 5) {
+		audit_iface(NULL, NULL, "unsupported interface version", e,
+			    error);
+		return error;
+	}
+
+	/* read the namespace if present */
+	if (!unpack_str(e, ns, "namespace"))
+		*ns = NULL;
+
+	return 0;
+}
+
+static bool verify_xindex(int xindex, int table_size)
+{
+	int index, xtype;
+	xtype = xindex & AA_X_TYPE_MASK;
+	index = xindex & AA_X_INDEX_MASK;
+	if (xtype == AA_X_TABLE && index > table_size)
+		return 0;
+	return 1;
+}
+
+/* verify dfa xindexes are in range of transition tables */
+static bool verify_dfa_xindex(struct aa_dfa *dfa, int table_size)
+{
+	int i;
+	for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) {
+		if (!verify_xindex(dfa_user_xindex(dfa, i), table_size))
+			return 0;
+		if (!verify_xindex(dfa_other_xindex(dfa, i), table_size))
+			return 0;
+	}
+	return 1;
+}
+
+/**
+ * verify_profile - Do post unpack analysis to verify profile consistency
+ * @profile: profile to verify (NOT NULL)
+ *
+ * Returns: 0 if passes verification else error
+ */
+static int verify_profile(struct aa_profile *profile)
+{
+	if (aa_g_paranoid_load) {
+		if (profile->file.dfa &&
+		    !verify_dfa_xindex(profile->file.dfa,
+				       profile->file.trans.size)) {
+			audit_iface(profile, NULL, "Invalid named transition",
+				    NULL, -EPROTO);
+			return -EPROTO;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * aa_unpack - unpack packed binary profile data loaded from user space
+ * @udata: user data copied to kmem  (NOT NULL)
+ * @size: the size of the user data
+ * @ns: Returns namespace profile is in if specified else NULL (NOT NULL)
+ *
+ * Unpack user data and return refcounted allocated profile or ERR_PTR
+ *
+ * Returns: profile else error pointer if fails to unpack
+ */
+struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns)
+{
+	struct aa_profile *profile = NULL;
+	int error;
+	struct aa_ext e = {
+		.start = udata,
+		.end = udata + size,
+		.pos = udata,
+	};
+
+	error = verify_header(&e, ns);
+	if (error)
+		return ERR_PTR(error);
+
+	profile = unpack_profile(&e);
+	if (IS_ERR(profile))
+		return profile;
+
+	error = verify_profile(profile);
+	if (error) {
+		aa_put_profile(profile);
+		profile = ERR_PTR(error);
+	}
+
+	/* return refcount */
+	return profile;
+}
diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c
new file mode 100644
index 0000000..04a2cf8
--- /dev/null
+++ b/security/apparmor/procattr.c
@@ -0,0 +1,170 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor /proc/<pid>/attr/ interface functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#include "include/apparmor.h"
+#include "include/context.h"
+#include "include/policy.h"
+#include "include/domain.h"
+
+
+/**
+ * aa_getprocattr - Return the profile information for @profile
+ * @profile: the profile to print profile info about  (NOT NULL)
+ * @string: Returns - string containing the profile info (NOT NULL)
+ *
+ * Returns: length of @string on success else error on failure
+ *
+ * Requires: profile != NULL
+ *
+ * Creates a string containing the namespace_name://profile_name for
+ * @profile.
+ *
+ * Returns: size of string placed in @string else error code on failure
+ */
+int aa_getprocattr(struct aa_profile *profile, char **string)
+{
+	char *str;
+	int len = 0, mode_len = 0, ns_len = 0, name_len;
+	const char *mode_str = profile_mode_names[profile->mode];
+	const char *ns_name = NULL;
+	struct aa_namespace *ns = profile->ns;
+	struct aa_namespace *current_ns = __aa_current_profile()->ns;
+	char *s;
+
+	if (!aa_ns_visible(current_ns, ns))
+		return -EACCES;
+
+	ns_name = aa_ns_name(current_ns, ns);
+	ns_len = strlen(ns_name);
+
+	/* if the visible ns_name is > 0 increase size for : :// seperator */
+	if (ns_len)
+		ns_len += 4;
+
+	/* unconfined profiles don't have a mode string appended */
+	if (!unconfined(profile))
+		mode_len = strlen(mode_str) + 3;	/* + 3 for _() */
+
+	name_len = strlen(profile->base.hname);
+	len = mode_len + ns_len + name_len + 1;	    /* + 1 for \n */
+	s = str = kmalloc(len + 1, GFP_KERNEL);	    /* + 1 \0 */
+	if (!str)
+		return -ENOMEM;
+
+	if (ns_len) {
+		/* skip over prefix current_ns->base.hname and separating // */
+		sprintf(s, ":%s://", ns_name);
+		s += ns_len;
+	}
+	if (unconfined(profile))
+		/* mode string not being appended */
+		sprintf(s, "%s\n", profile->base.hname);
+	else
+		sprintf(s, "%s (%s)\n", profile->base.hname, mode_str);
+	*string = str;
+
+	/* NOTE: len does not include \0 of string, not saved as part of file */
+	return len;
+}
+
+/**
+ * split_token_from_name - separate a string of form  <token>^<name>
+ * @op: operation being checked
+ * @args: string to parse  (NOT NULL)
+ * @token: stores returned parsed token value  (NOT NULL)
+ *
+ * Returns: start position of name after token else NULL on failure
+ */
+static char *split_token_from_name(int op, char *args, u64 * token)
+{
+	char *name;
+
+	*token = simple_strtoull(args, &name, 16);
+	if ((name == args) || *name != '^') {
+		AA_ERROR("%s: Invalid input '%s'", op_table[op], args);
+		return ERR_PTR(-EINVAL);
+	}
+
+	name++;			/* skip ^ */
+	if (!*name)
+		name = NULL;
+	return name;
+}
+
+/**
+ * aa_setprocattr_chagnehat - handle procattr interface to change_hat
+ * @args: args received from writing to /proc/<pid>/attr/current (NOT NULL)
+ * @size: size of the args
+ * @test: true if this is a test of change_hat permissions
+ *
+ * Returns: %0 or error code if change_hat fails
+ */
+int aa_setprocattr_changehat(char *args, size_t size, int test)
+{
+	char *hat;
+	u64 token;
+	const char *hats[16];		/* current hard limit on # of names */
+	int count = 0;
+
+	hat = split_token_from_name(OP_CHANGE_HAT, args, &token);
+	if (IS_ERR(hat))
+		return PTR_ERR(hat);
+
+	if (!hat && !token) {
+		AA_ERROR("change_hat: Invalid input, NULL hat and NULL magic");
+		return -EINVAL;
+	}
+
+	if (hat) {
+		/* set up hat name vector, args guaranteed null terminated
+		 * at args[size] by setprocattr.
+		 *
+		 * If there are multiple hat names in the buffer each is
+		 * separated by a \0.  Ie. userspace writes them pre tokenized
+		 */
+		char *end = args + size;
+		for (count = 0; (hat < end) && count < 16; ++count) {
+			char *next = hat + strlen(hat) + 1;
+			hats[count] = hat;
+			hat = next;
+		}
+	}
+
+	AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n",
+		 __func__, token, hat ? hat : NULL);
+
+	return aa_change_hat(hats, count, token, test);
+}
+
+/**
+ * aa_setprocattr_changeprofile - handle procattr interface to changeprofile
+ * @fqname: args received from writting to /proc/<pid>/attr/current (NOT NULL)
+ * @onexec: true if change_profile should be delayed until exec
+ * @test: true if this is a test of change_profile permissions
+ *
+ * Returns: %0 or error code if change_profile fails
+ */
+int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test)
+{
+	char *name, *ns_name;
+
+	name = aa_split_fqname(fqname, &ns_name);
+	return aa_change_profile(ns_name, name, onexec, test);
+}
+
+int aa_setprocattr_permipc(char *fqname)
+{
+	/* TODO: add ipc permission querying */
+	return -ENOTSUPP;
+}
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
new file mode 100644
index 0000000..4a368f1
--- /dev/null
+++ b/security/apparmor/resource.c
@@ -0,0 +1,134 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor resource mediation and attachment
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#include <linux/audit.h>
+
+#include "include/audit.h"
+#include "include/resource.h"
+#include "include/policy.h"
+
+/*
+ * Table of rlimit names: we generate it from resource.h.
+ */
+#include "rlim_names.h"
+
+/* audit callback for resource specific fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+	struct common_audit_data *sa = va;
+
+	audit_log_format(ab, " rlimit=%s value=%lu",
+			 rlim_names[sa->aad.rlim.rlim], sa->aad.rlim.max);
+}
+
+/**
+ * audit_resource - audit setting resource limit
+ * @profile: profile being enforced  (NOT NULL)
+ * @resoure: rlimit being auditing
+ * @value: value being set
+ * @error: error value
+ *
+ * Returns: 0 or sa->error else other error code on failure
+ */
+static int audit_resource(struct aa_profile *profile, unsigned int resource,
+			  unsigned long value, int error)
+{
+	struct common_audit_data sa;
+
+	COMMON_AUDIT_DATA_INIT(&sa, NONE);
+	sa.aad.op = OP_SETRLIMIT,
+	sa.aad.rlim.rlim = resource;
+	sa.aad.rlim.max = value;
+	sa.aad.error = error;
+	return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_KERNEL, &sa,
+			audit_cb);
+}
+
+/**
+ * aa_map_resouce - map compiled policy resource to internal #
+ * @resource: flattened policy resource number
+ *
+ * Returns: resource # for the current architecture.
+ *
+ * rlimit resource can vary based on architecture, map the compiled policy
+ * resource # to the internal representation for the architecture.
+ */
+int aa_map_resource(int resource)
+{
+	return rlim_map[resource];
+}
+
+/**
+ * aa_task_setrlimit - test permission to set an rlimit
+ * @profile - profile confining the task  (NOT NULL)
+ * @resource - the resource being set
+ * @new_rlim - the new resource limit  (NOT NULL)
+ *
+ * Control raising the processes hard limit.
+ *
+ * Returns: 0 or error code if setting resource failed
+ */
+int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
+		      struct rlimit *new_rlim)
+{
+	int error = 0;
+
+	if (profile->rlimits.mask & (1 << resource) &&
+	    new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max)
+
+		error = audit_resource(profile, resource, new_rlim->rlim_max,
+			-EACCES);
+
+	return error;
+}
+
+/**
+ * __aa_transition_rlimits - apply new profile rlimits
+ * @old: old profile on task  (NOT NULL)
+ * @new: new profile with rlimits to apply  (NOT NULL)
+ */
+void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new)
+{
+	unsigned int mask = 0;
+	struct rlimit *rlim, *initrlim;
+	int i;
+
+	/* for any rlimits the profile controlled reset the soft limit
+	 * to the less of the tasks hard limit and the init tasks soft limit
+	 */
+	if (old->rlimits.mask) {
+		for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) {
+			if (old->rlimits.mask & mask) {
+				rlim = current->signal->rlim + i;
+				initrlim = init_task.signal->rlim + i;
+				rlim->rlim_cur = min(rlim->rlim_max,
+						     initrlim->rlim_cur);
+			}
+		}
+	}
+
+	/* set any new hard limits as dictated by the new profile */
+	if (!new->rlimits.mask)
+		return;
+	for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) {
+		if (!(new->rlimits.mask & mask))
+			continue;
+
+		rlim = current->signal->rlim + i;
+		rlim->rlim_max = min(rlim->rlim_max,
+				     new->rlimits.limits[i].rlim_max);
+		/* soft limit should not exceed hard limit */
+		rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max);
+	}
+}
diff --git a/security/apparmor/sid.c b/security/apparmor/sid.c
new file mode 100644
index 0000000..f0b34f7
--- /dev/null
+++ b/security/apparmor/sid.c
@@ -0,0 +1,55 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor security identifier (sid) manipulation fns
+ *
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ *
+ *
+ * AppArmor allocates a unique sid for every profile loaded.  If a profile
+ * is replaced it receives the sid of the profile it is replacing.
+ *
+ * The sid value of 0 is invalid.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include "include/sid.h"
+
+/* global counter from which sids are allocated */
+static u32 global_sid;
+static DEFINE_SPINLOCK(sid_lock);
+
+/* TODO FIXME: add sid to profile mapping, and sid recycling */
+
+/**
+ * aa_alloc_sid - allocate a new sid for a profile
+ */
+u32 aa_alloc_sid(void)
+{
+	u32 sid;
+
+	/*
+	 * TODO FIXME: sid recycling - part of profile mapping table
+	 */
+	spin_lock(&sid_lock);
+	sid = (++global_sid);
+	spin_unlock(&sid_lock);
+	return sid;
+}
+
+/**
+ * aa_free_sid - free a sid
+ * @sid: sid to free
+ */
+void aa_free_sid(u32 sid)
+{
+	;			/* NOP ATM */
+}
diff --git a/security/capability.c b/security/capability.c
index 8168e3e..a0bbf30 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -27,7 +27,7 @@
 	return 0;
 }
 
-static int cap_bprm_check_security (struct linux_binprm *bprm)
+static int cap_bprm_check_security(struct linux_binprm *bprm)
 {
 	return 0;
 }
@@ -268,8 +268,7 @@
 	return 0;
 }
 
-static int cap_path_truncate(struct path *path, loff_t length,
-			     unsigned int time_attrs)
+static int cap_path_truncate(struct path *path)
 {
 	return 0;
 }
diff --git a/security/inode.c b/security/inode.c
index 1c812e8..8c777f0 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -86,7 +86,7 @@
 			 int mode, dev_t dev)
 {
 	struct inode *inode;
-	int error = -EPERM;
+	int error = -ENOMEM;
 
 	if (dentry->d_inode)
 		return -EEXIST;
@@ -166,6 +166,8 @@
 			error = mkdir(parent->d_inode, *dentry, mode);
 		else
 			error = create(parent->d_inode, *dentry, mode);
+		if (error)
+			dput(*dentry);
 	} else
 		error = PTR_ERR(*dentry);
 	mutex_unlock(&parent->d_inode->i_mutex);
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 8fe736a..ef21b96 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -45,7 +45,8 @@
 }
 
 static const struct file_operations ima_htable_violations_ops = {
-	.read = ima_show_htable_violations
+	.read = ima_show_htable_violations,
+	.llseek = generic_file_llseek,
 };
 
 static ssize_t ima_show_measurements_count(struct file *filp,
@@ -57,7 +58,8 @@
 }
 
 static const struct file_operations ima_measurements_count_ops = {
-	.read = ima_show_measurements_count
+	.read = ima_show_measurements_count,
+	.llseek = generic_file_llseek,
 };
 
 /* returns pointer to hlist_node */
@@ -319,7 +321,8 @@
 static const struct file_operations ima_measure_policy_ops = {
 	.open = ima_open_policy,
 	.write = ima_write_policy,
-	.release = ima_release_policy
+	.release = ima_release_policy,
+	.llseek = generic_file_llseek,
 };
 
 int __init ima_fs_init(void)
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 38783dc..addb67b 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -114,6 +114,10 @@
 				    const void *description,
 				    key_match_func_t match);
 
+extern key_ref_t search_my_process_keyrings(struct key_type *type,
+					    const void *description,
+					    key_match_func_t match,
+					    const struct cred *cred);
 extern key_ref_t search_process_keyrings(struct key_type *type,
 					 const void *description,
 					 key_match_func_t match,
@@ -134,6 +138,7 @@
 					struct key *dest_keyring,
 					unsigned long flags);
 
+extern int lookup_user_key_possessed(const struct key *key, const void *target);
 extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
 				 key_perm_t perm);
 #define KEY_LOOKUP_CREATE	0x01
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 6261745..b2b0998 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -505,13 +505,11 @@
 
 	ret = snprintf(tmpbuf, PAGE_SIZE - 1,
 		       "%s;%d;%d;%08x;%s",
-		       key_ref_to_ptr(key_ref)->type->name,
-		       key_ref_to_ptr(key_ref)->uid,
-		       key_ref_to_ptr(key_ref)->gid,
-		       key_ref_to_ptr(key_ref)->perm,
-		       key_ref_to_ptr(key_ref)->description ?
-		       key_ref_to_ptr(key_ref)->description : ""
-		       );
+		       key->type->name,
+		       key->uid,
+		       key->gid,
+		       key->perm,
+		       key->description ?: "");
 
 	/* include a NUL char at the end of the data */
 	if (ret > PAGE_SIZE - 1)
@@ -1091,7 +1089,7 @@
 long keyctl_set_timeout(key_serial_t id, unsigned timeout)
 {
 	struct timespec now;
-	struct key *key;
+	struct key *key, *instkey;
 	key_ref_t key_ref;
 	time_t expiry;
 	long ret;
@@ -1099,10 +1097,25 @@
 	key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
 				  KEY_SETATTR);
 	if (IS_ERR(key_ref)) {
+		/* setting the timeout on a key under construction is permitted
+		 * if we have the authorisation token handy */
+		if (PTR_ERR(key_ref) == -EACCES) {
+			instkey = key_get_instantiation_authkey(id);
+			if (!IS_ERR(instkey)) {
+				key_put(instkey);
+				key_ref = lookup_user_key(id,
+							  KEY_LOOKUP_PARTIAL,
+							  0);
+				if (!IS_ERR(key_ref))
+					goto okay;
+			}
+		}
+
 		ret = PTR_ERR(key_ref);
 		goto error;
 	}
 
+okay:
 	key = key_ref_to_ptr(key_ref);
 
 	/* make the changes with the locks held to prevent races */
diff --git a/security/keys/proc.c b/security/keys/proc.c
index 068b66e..70373966 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -184,20 +184,36 @@
 
 static int proc_keys_show(struct seq_file *m, void *v)
 {
+	const struct cred *cred = current_cred();
 	struct rb_node *_p = v;
 	struct key *key = rb_entry(_p, struct key, serial_node);
 	struct timespec now;
 	unsigned long timo;
+	key_ref_t key_ref, skey_ref;
 	char xbuf[12];
 	int rc;
 
+	key_ref = make_key_ref(key, 0);
+
+	/* determine if the key is possessed by this process (a test we can
+	 * skip if the key does not indicate the possessor can view it
+	 */
+	if (key->perm & KEY_POS_VIEW) {
+		skey_ref = search_my_process_keyrings(key->type, key,
+						      lookup_user_key_possessed,
+						      cred);
+		if (!IS_ERR(skey_ref)) {
+			key_ref_put(skey_ref);
+			key_ref = make_key_ref(key, 1);
+		}
+	}
+
 	/* check whether the current task is allowed to view the key (assuming
 	 * 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);
+	rc = key_task_permission(key_ref, cred, KEY_VIEW);
 	if (rc < 0)
 		return 0;
 
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 6b8e4ff..f8e7251 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -309,22 +309,19 @@
 
 /*****************************************************************************/
 /*
- * search the process keyrings for the first matching key
+ * search only my process keyrings for the first matching key
  * - we use the supplied match function to see if the description (or other
  *   feature of interest) matches
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we found only negative matching keys
  */
-key_ref_t search_process_keyrings(struct key_type *type,
-				  const void *description,
-				  key_match_func_t match,
-				  const struct cred *cred)
+key_ref_t search_my_process_keyrings(struct key_type *type,
+				     const void *description,
+				     key_match_func_t match,
+				     const struct cred *cred)
 {
-	struct request_key_auth *rka;
 	key_ref_t key_ref, ret, err;
 
-	might_sleep();
-
 	/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
 	 * searchable, but we failed to find a key or we found a negative key;
 	 * otherwise we want to return a sample error (probably -EACCES) if
@@ -424,6 +421,36 @@
 		}
 	}
 
+	/* no key - decide on the error we're going to go for */
+	key_ref = ret ? ret : err;
+
+found:
+	return key_ref;
+}
+
+/*****************************************************************************/
+/*
+ * search the process keyrings for the first matching key
+ * - we use the supplied match function to see if the description (or other
+ *   feature of interest) matches
+ * - we return -EAGAIN if we didn't find any matching key
+ * - we return -ENOKEY if we found only negative matching keys
+ */
+key_ref_t search_process_keyrings(struct key_type *type,
+				  const void *description,
+				  key_match_func_t match,
+				  const struct cred *cred)
+{
+	struct request_key_auth *rka;
+	key_ref_t key_ref, ret = ERR_PTR(-EACCES), err;
+
+	might_sleep();
+
+	key_ref = search_my_process_keyrings(type, description, match, cred);
+	if (!IS_ERR(key_ref))
+		goto found;
+	err = key_ref;
+
 	/* if this process has an instantiation authorisation key, then we also
 	 * search the keyrings of the process mentioned there
 	 * - we don't permit access to request_key auth keys via this method
@@ -446,24 +473,19 @@
 			if (!IS_ERR(key_ref))
 				goto found;
 
-			switch (PTR_ERR(key_ref)) {
-			case -EAGAIN: /* no key */
-				if (ret)
-					break;
-			case -ENOKEY: /* negative key */
-				ret = key_ref;
-				break;
-			default:
-				err = key_ref;
-				break;
-			}
+			ret = key_ref;
 		} else {
 			up_read(&cred->request_key_auth->sem);
 		}
 	}
 
 	/* no key - decide on the error we're going to go for */
-	key_ref = ret ? ret : err;
+	if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY))
+		key_ref = ERR_PTR(-ENOKEY);
+	else if (err == ERR_PTR(-EACCES))
+		key_ref = ret;
+	else
+		key_ref = err;
 
 found:
 	return key_ref;
@@ -474,7 +496,7 @@
 /*
  * see if the key we're looking at is the target key
  */
-static int lookup_user_key_possessed(const struct key *key, const void *target)
+int lookup_user_key_possessed(const struct key *key, const void *target)
 {
 	return key == target;
 
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index f5ec9ac..0d26f68 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -144,6 +144,7 @@
 	prkey = 0;
 	if (cred->tgcred->process_keyring)
 		prkey = cred->tgcred->process_keyring->serial;
+	sprintf(keyring_str[1], "%d", prkey);
 
 	rcu_read_lock();
 	session = rcu_dereference(cred->tgcred->session_keyring);
diff --git a/security/security.c b/security/security.c
index 351942a..e8c87b8 100644
--- a/security/security.c
+++ b/security/security.c
@@ -417,12 +417,11 @@
 					 new_dentry);
 }
 
-int security_path_truncate(struct path *path, loff_t length,
-			   unsigned int time_attrs)
+int security_path_truncate(struct path *path)
 {
 	if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
 		return 0;
-	return security_ops->path_truncate(path, length, time_attrs);
+	return security_ops->path_truncate(path);
 }
 
 int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 7f1a304..9da6420 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -288,7 +288,6 @@
 	if (!node)
 		goto out;
 
-	INIT_RCU_HEAD(&node->rhead);
 	INIT_HLIST_NODE(&node->list);
 	avc_cache_stats_incr(allocations);
 
@@ -489,9 +488,29 @@
 	struct common_audit_data stack_data;
 	u32 denied, audited;
 	denied = requested & ~avd->allowed;
-	if (denied)
+	if (denied) {
 		audited = denied & avd->auditdeny;
-	else if (result)
+		/*
+		 * a->selinux_audit_data.auditdeny is TRICKY!  Setting a bit in
+		 * this field means that ANY denials should NOT be audited if
+		 * the policy contains an explicit dontaudit rule for that
+		 * permission.  Take notice that this is unrelated to the
+		 * actual permissions that were denied.  As an example lets
+		 * assume:
+		 *
+		 * denied == READ
+		 * avd.auditdeny & ACCESS == 0 (not set means explicit rule)
+		 * selinux_audit_data.auditdeny & ACCESS == 1
+		 *
+		 * We will NOT audit the denial even though the denied
+		 * permission was READ and the auditdeny checks were for
+		 * ACCESS
+		 */
+		if (a &&
+		    a->selinux_audit_data.auditdeny &&
+		    !(a->selinux_audit_data.auditdeny & avd->auditdeny))
+			audited = 0;
+	} else if (result)
 		audited = denied = requested;
 	else
 		audited = requested & avd->auditallow;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 5c9f25b..9b40f4c 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -87,9 +87,6 @@
 #include "netlabel.h"
 #include "audit.h"
 
-#define XATTR_SELINUX_SUFFIX "selinux"
-#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
-
 #define NUM_SEL_MNT_OPTS 5
 
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
@@ -188,7 +185,7 @@
  */
 static inline u32 current_sid(void)
 {
-	const struct task_security_struct *tsec = current_cred()->security;
+	const struct task_security_struct *tsec = current_security();
 
 	return tsec->sid;
 }
@@ -279,32 +276,6 @@
 	kfree(sbsec);
 }
 
-static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
-{
-	struct sk_security_struct *sksec;
-
-	sksec = kzalloc(sizeof(*sksec), priority);
-	if (!sksec)
-		return -ENOMEM;
-
-	sksec->peer_sid = SECINITSID_UNLABELED;
-	sksec->sid = SECINITSID_UNLABELED;
-	sk->sk_security = sksec;
-
-	selinux_netlbl_sk_security_reset(sksec);
-
-	return 0;
-}
-
-static void sk_free_security(struct sock *sk)
-{
-	struct sk_security_struct *sksec = sk->sk_security;
-
-	sk->sk_security = NULL;
-	selinux_netlbl_sk_security_free(sksec);
-	kfree(sksec);
-}
-
 /* The security server must be initialized before
    any labeling or access decisions can be provided. */
 extern int ss_initialized;
@@ -1584,8 +1555,7 @@
 		      struct dentry *dentry,
 		      u16 tclass)
 {
-	const struct cred *cred = current_cred();
-	const struct task_security_struct *tsec = cred->security;
+	const struct task_security_struct *tsec = current_security();
 	struct inode_security_struct *dsec;
 	struct superblock_security_struct *sbsec;
 	u32 sid, newsid;
@@ -1806,27 +1776,9 @@
 {
 	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 if (S_ISSOCK(mode))
-			av |= SOCK_FILE__OPEN;
-		else
-			printk(KERN_ERR "SELinux: WARNING: inside %s with "
-				"unknown mode:%o\n", __func__, mode);
-	}
+	if (selinux_policycap_openperm)
+		av |= FILE__OPEN;
+
 	return av;
 }
 
@@ -2183,8 +2135,7 @@
 
 static int selinux_bprm_secureexec(struct linux_binprm *bprm)
 {
-	const struct cred *cred = current_cred();
-	const struct task_security_struct *tsec = cred->security;
+	const struct task_security_struct *tsec = current_security();
 	u32 sid, osid;
 	int atsecure = 0;
 
@@ -2559,8 +2510,7 @@
 				       char **name, void **value,
 				       size_t *len)
 {
-	const struct cred *cred = current_cred();
-	const struct task_security_struct *tsec = cred->security;
+	const struct task_security_struct *tsec = current_security();
 	struct inode_security_struct *dsec;
 	struct superblock_security_struct *sbsec;
 	u32 sid, newsid, clen;
@@ -2676,14 +2626,26 @@
 static int selinux_inode_permission(struct inode *inode, int mask)
 {
 	const struct cred *cred = current_cred();
+	struct common_audit_data ad;
+	u32 perms;
+	bool from_access;
 
-	if (!mask) {
-		/* No permission to check.  Existence test. */
+	from_access = mask & MAY_ACCESS;
+	mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
+
+	/* No permission to check.  Existence test. */
+	if (!mask)
 		return 0;
-	}
 
-	return inode_has_perm(cred, inode,
-			      file_mask_to_av(inode->i_mode, mask), NULL);
+	COMMON_AUDIT_DATA_INIT(&ad, FS);
+	ad.u.fs.inode = inode;
+
+	if (from_access)
+		ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
+
+	perms = file_mask_to_av(inode->i_mode, mask);
+
+	return inode_has_perm(cred, inode, perms, &ad);
 }
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -3671,71 +3633,54 @@
 }
 
 /* socket security operations */
-static int socket_has_perm(struct task_struct *task, struct socket *sock,
-			   u32 perms)
+
+static u32 socket_sockcreate_sid(const struct task_security_struct *tsec)
 {
-	struct inode_security_struct *isec;
+	return tsec->sockcreate_sid ? : tsec->sid;
+}
+
+static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
+{
+	struct sk_security_struct *sksec = sk->sk_security;
 	struct common_audit_data ad;
-	u32 sid;
-	int err = 0;
+	u32 tsid = task_sid(task);
 
-	isec = SOCK_INODE(sock)->i_security;
-
-	if (isec->sid == SECINITSID_KERNEL)
-		goto out;
-	sid = task_sid(task);
+	if (sksec->sid == SECINITSID_KERNEL)
+		return 0;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.sk = sock->sk;
-	err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
+	ad.u.net.sk = sk;
 
-out:
-	return err;
+	return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
 }
 
 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;
+	const struct task_security_struct *tsec = current_security();
+	u32 newsid;
 	u16 secclass;
-	int err = 0;
 
 	if (kern)
-		goto out;
+		return 0;
 
-	sid = tsec->sid;
-	newsid = tsec->sockcreate_sid ?: sid;
-
+	newsid = socket_sockcreate_sid(tsec);
 	secclass = socket_type_to_security_class(family, type, protocol);
-	err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
-
-out:
-	return err;
+	return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
 }
 
 static int selinux_socket_post_create(struct socket *sock, int family,
 				      int type, int protocol, int kern)
 {
-	const struct cred *cred = current_cred();
-	const struct task_security_struct *tsec = cred->security;
-	struct inode_security_struct *isec;
+	const struct task_security_struct *tsec = current_security();
+	struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
 	struct sk_security_struct *sksec;
-	u32 sid, newsid;
 	int err = 0;
 
-	sid = tsec->sid;
-	newsid = tsec->sockcreate_sid;
-
-	isec = SOCK_INODE(sock)->i_security;
-
 	if (kern)
 		isec->sid = SECINITSID_KERNEL;
-	else if (newsid)
-		isec->sid = newsid;
 	else
-		isec->sid = sid;
+		isec->sid = socket_sockcreate_sid(tsec);
 
 	isec->sclass = socket_type_to_security_class(family, type, protocol);
 	isec->initialized = 1;
@@ -3756,10 +3701,11 @@
 
 static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
 {
+	struct sock *sk = sock->sk;
 	u16 family;
 	int err;
 
-	err = socket_has_perm(current, sock, SOCKET__BIND);
+	err = sock_has_perm(current, sk, SOCKET__BIND);
 	if (err)
 		goto out;
 
@@ -3768,19 +3714,16 @@
 	 * Multiple address binding for SCTP is not supported yet: we just
 	 * check the first address now.
 	 */
-	family = sock->sk->sk_family;
+	family = sk->sk_family;
 	if (family == PF_INET || family == PF_INET6) {
 		char *addrp;
-		struct inode_security_struct *isec;
+		struct sk_security_struct *sksec = sk->sk_security;
 		struct common_audit_data ad;
 		struct sockaddr_in *addr4 = NULL;
 		struct sockaddr_in6 *addr6 = NULL;
 		unsigned short snum;
-		struct sock *sk = sock->sk;
 		u32 sid, node_perm;
 
-		isec = SOCK_INODE(sock)->i_security;
-
 		if (family == PF_INET) {
 			addr4 = (struct sockaddr_in *)address;
 			snum = ntohs(addr4->sin_port);
@@ -3804,15 +3747,15 @@
 				COMMON_AUDIT_DATA_INIT(&ad, NET);
 				ad.u.net.sport = htons(snum);
 				ad.u.net.family = family;
-				err = avc_has_perm(isec->sid, sid,
-						   isec->sclass,
+				err = avc_has_perm(sksec->sid, sid,
+						   sksec->sclass,
 						   SOCKET__NAME_BIND, &ad);
 				if (err)
 					goto out;
 			}
 		}
 
-		switch (isec->sclass) {
+		switch (sksec->sclass) {
 		case SECCLASS_TCP_SOCKET:
 			node_perm = TCP_SOCKET__NODE_BIND;
 			break;
@@ -3843,8 +3786,8 @@
 		else
 			ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
 
-		err = avc_has_perm(isec->sid, sid,
-				   isec->sclass, node_perm, &ad);
+		err = avc_has_perm(sksec->sid, sid,
+				   sksec->sclass, node_perm, &ad);
 		if (err)
 			goto out;
 	}
@@ -3855,19 +3798,18 @@
 static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
 {
 	struct sock *sk = sock->sk;
-	struct inode_security_struct *isec;
+	struct sk_security_struct *sksec = sk->sk_security;
 	int err;
 
-	err = socket_has_perm(current, sock, SOCKET__CONNECT);
+	err = sock_has_perm(current, sk, SOCKET__CONNECT);
 	if (err)
 		return err;
 
 	/*
 	 * If a TCP or DCCP socket, check name_connect permission for the port.
 	 */
-	isec = SOCK_INODE(sock)->i_security;
-	if (isec->sclass == SECCLASS_TCP_SOCKET ||
-	    isec->sclass == SECCLASS_DCCP_SOCKET) {
+	if (sksec->sclass == SECCLASS_TCP_SOCKET ||
+	    sksec->sclass == SECCLASS_DCCP_SOCKET) {
 		struct common_audit_data ad;
 		struct sockaddr_in *addr4 = NULL;
 		struct sockaddr_in6 *addr6 = NULL;
@@ -3890,13 +3832,13 @@
 		if (err)
 			goto out;
 
-		perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
+		perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
 		       TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
 
 		COMMON_AUDIT_DATA_INIT(&ad, NET);
 		ad.u.net.dport = htons(snum);
 		ad.u.net.family = sk->sk_family;
-		err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
+		err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
 		if (err)
 			goto out;
 	}
@@ -3909,7 +3851,7 @@
 
 static int selinux_socket_listen(struct socket *sock, int backlog)
 {
-	return socket_has_perm(current, sock, SOCKET__LISTEN);
+	return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
 }
 
 static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
@@ -3918,7 +3860,7 @@
 	struct inode_security_struct *isec;
 	struct inode_security_struct *newisec;
 
-	err = socket_has_perm(current, sock, SOCKET__ACCEPT);
+	err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
 	if (err)
 		return err;
 
@@ -3935,30 +3877,30 @@
 static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
 				  int size)
 {
-	return socket_has_perm(current, sock, SOCKET__WRITE);
+	return sock_has_perm(current, sock->sk, SOCKET__WRITE);
 }
 
 static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
 				  int size, int flags)
 {
-	return socket_has_perm(current, sock, SOCKET__READ);
+	return sock_has_perm(current, sock->sk, SOCKET__READ);
 }
 
 static int selinux_socket_getsockname(struct socket *sock)
 {
-	return socket_has_perm(current, sock, SOCKET__GETATTR);
+	return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
 }
 
 static int selinux_socket_getpeername(struct socket *sock)
 {
-	return socket_has_perm(current, sock, SOCKET__GETATTR);
+	return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
 }
 
 static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
 {
 	int err;
 
-	err = socket_has_perm(current, sock, SOCKET__SETOPT);
+	err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
 	if (err)
 		return err;
 
@@ -3968,68 +3910,58 @@
 static int selinux_socket_getsockopt(struct socket *sock, int level,
 				     int optname)
 {
-	return socket_has_perm(current, sock, SOCKET__GETOPT);
+	return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
 }
 
 static int selinux_socket_shutdown(struct socket *sock, int how)
 {
-	return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
+	return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
 }
 
 static int selinux_socket_unix_stream_connect(struct socket *sock,
 					      struct socket *other,
 					      struct sock *newsk)
 {
-	struct sk_security_struct *sksec;
-	struct inode_security_struct *isec;
-	struct inode_security_struct *other_isec;
+	struct sk_security_struct *sksec_sock = sock->sk->sk_security;
+	struct sk_security_struct *sksec_other = other->sk->sk_security;
+	struct sk_security_struct *sksec_new = newsk->sk_security;
 	struct common_audit_data ad;
 	int err;
 
-	isec = SOCK_INODE(sock)->i_security;
-	other_isec = SOCK_INODE(other)->i_security;
-
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
 	ad.u.net.sk = other->sk;
 
-	err = avc_has_perm(isec->sid, other_isec->sid,
-			   isec->sclass,
+	err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
+			   sksec_other->sclass,
 			   UNIX_STREAM_SOCKET__CONNECTTO, &ad);
 	if (err)
 		return err;
 
-	/* connecting socket */
-	sksec = sock->sk->sk_security;
-	sksec->peer_sid = other_isec->sid;
-
 	/* server child socket */
-	sksec = newsk->sk_security;
-	sksec->peer_sid = isec->sid;
-	err = security_sid_mls_copy(other_isec->sid, sksec->peer_sid, &sksec->sid);
+	sksec_new->peer_sid = sksec_sock->sid;
+	err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
+				    &sksec_new->sid);
+	if (err)
+		return err;
 
-	return err;
+	/* connecting socket */
+	sksec_sock->peer_sid = sksec_new->sid;
+
+	return 0;
 }
 
 static int selinux_socket_unix_may_send(struct socket *sock,
 					struct socket *other)
 {
-	struct inode_security_struct *isec;
-	struct inode_security_struct *other_isec;
+	struct sk_security_struct *ssec = sock->sk->sk_security;
+	struct sk_security_struct *osec = other->sk->sk_security;
 	struct common_audit_data ad;
-	int err;
-
-	isec = SOCK_INODE(sock)->i_security;
-	other_isec = SOCK_INODE(other)->i_security;
 
 	COMMON_AUDIT_DATA_INIT(&ad, NET);
 	ad.u.net.sk = other->sk;
 
-	err = avc_has_perm(isec->sid, other_isec->sid,
-			   isec->sclass, SOCKET__SENDTO, &ad);
-	if (err)
-		return err;
-
-	return 0;
+	return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
+			    &ad);
 }
 
 static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
@@ -4168,26 +4100,18 @@
 	int err = 0;
 	char *scontext;
 	u32 scontext_len;
-	struct sk_security_struct *sksec;
-	struct inode_security_struct *isec;
+	struct sk_security_struct *sksec = sock->sk->sk_security;
 	u32 peer_sid = SECSID_NULL;
 
-	isec = SOCK_INODE(sock)->i_security;
-
-	if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
-	    isec->sclass == SECCLASS_TCP_SOCKET) {
-		sksec = sock->sk->sk_security;
+	if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
+	    sksec->sclass == SECCLASS_TCP_SOCKET)
 		peer_sid = sksec->peer_sid;
-	}
-	if (peer_sid == SECSID_NULL) {
-		err = -ENOPROTOOPT;
-		goto out;
-	}
+	if (peer_sid == SECSID_NULL)
+		return -ENOPROTOOPT;
 
 	err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
-
 	if (err)
-		goto out;
+		return err;
 
 	if (scontext_len > len) {
 		err = -ERANGE;
@@ -4200,9 +4124,7 @@
 out_len:
 	if (put_user(scontext_len, optlen))
 		err = -EFAULT;
-
 	kfree(scontext);
-out:
 	return err;
 }
 
@@ -4234,12 +4156,27 @@
 
 static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 {
-	return sk_alloc_security(sk, family, priority);
+	struct sk_security_struct *sksec;
+
+	sksec = kzalloc(sizeof(*sksec), priority);
+	if (!sksec)
+		return -ENOMEM;
+
+	sksec->peer_sid = SECINITSID_UNLABELED;
+	sksec->sid = SECINITSID_UNLABELED;
+	selinux_netlbl_sk_security_reset(sksec);
+	sk->sk_security = sksec;
+
+	return 0;
 }
 
 static void selinux_sk_free_security(struct sock *sk)
 {
-	sk_free_security(sk);
+	struct sk_security_struct *sksec = sk->sk_security;
+
+	sk->sk_security = NULL;
+	selinux_netlbl_sk_security_free(sksec);
+	kfree(sksec);
 }
 
 static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
@@ -4399,8 +4336,7 @@
 	int err = 0;
 	u32 perm;
 	struct nlmsghdr *nlh;
-	struct socket *sock = sk->sk_socket;
-	struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+	struct sk_security_struct *sksec = sk->sk_security;
 
 	if (skb->len < NLMSG_SPACE(0)) {
 		err = -EINVAL;
@@ -4408,13 +4344,13 @@
 	}
 	nlh = nlmsg_hdr(skb);
 
-	err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
+	err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
 	if (err) {
 		if (err == -EINVAL) {
 			audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
 				  "SELinux:  unrecognized netlink message"
 				  " type=%hu for sclass=%hu\n",
-				  nlh->nlmsg_type, isec->sclass);
+				  nlh->nlmsg_type, sksec->sclass);
 			if (!selinux_enforcing || security_get_allow_unknown())
 				err = 0;
 		}
@@ -4425,7 +4361,7 @@
 		goto out;
 	}
 
-	err = socket_has_perm(current, sock, perm);
+	err = sock_has_perm(current, sk, perm);
 out:
 	return err;
 }
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 8b32e95..b4c9eb4 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -2,7 +2,8 @@
     "getattr", "setattr", "lock", "relabelfrom", "relabelto", "append"
 
 #define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \
-    "rename", "execute", "swapon", "quotaon", "mounton"
+    "rename", "execute", "swapon", "quotaon", "mounton", "audit_access", \
+    "open", "execmod"
 
 #define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \
     "listen", "accept", "getopt", "setopt", "shutdown", "recvfrom",  \
@@ -43,22 +44,21 @@
 	    "quotaget", NULL } },
 	{ "file",
 	  { COMMON_FILE_PERMS,
-	    "execute_no_trans", "entrypoint", "execmod", "open", NULL } },
+	    "execute_no_trans", "entrypoint", NULL } },
 	{ "dir",
 	  { COMMON_FILE_PERMS, "add_name", "remove_name",
-	    "reparent", "search", "rmdir", "open", NULL } },
+	    "reparent", "search", "rmdir", NULL } },
 	{ "fd", { "use", NULL } },
 	{ "lnk_file",
 	  { COMMON_FILE_PERMS, NULL } },
 	{ "chr_file",
-	  { COMMON_FILE_PERMS,
-	    "execute_no_trans", "entrypoint", "execmod", "open", NULL } },
+	  { COMMON_FILE_PERMS, NULL } },
 	{ "blk_file",
-	  { COMMON_FILE_PERMS, "open", NULL } },
+	  { COMMON_FILE_PERMS, NULL } },
 	{ "sock_file",
-	  { COMMON_FILE_PERMS, "open", NULL } },
+	  { COMMON_FILE_PERMS, NULL } },
 	{ "fifo_file",
-	  { COMMON_FILE_PERMS, "open", NULL } },
+	  { COMMON_FILE_PERMS, NULL } },
 	{ "socket",
 	  { COMMON_SOCK_PERMS, NULL } },
 	{ "tcp_socket",
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index dc92792..65ebfe9 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -183,8 +183,6 @@
 		BUG();
 	}
 
-	INIT_RCU_HEAD(&node->rcu);
-
 	/* we need to impose a limit on the growth of the hash table so check
 	 * this bucket to make sure it is within the specified bounds */
 	list_add_rcu(&node->list, &sel_netnode_hash[idx].list);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 0293843..79a1bb6 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -184,6 +184,7 @@
 static const struct file_operations sel_enforce_ops = {
 	.read		= sel_read_enforce,
 	.write		= sel_write_enforce,
+	.llseek		= generic_file_llseek,
 };
 
 static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
@@ -201,6 +202,7 @@
 
 static const struct file_operations sel_handle_unknown_ops = {
 	.read		= sel_read_handle_unknown,
+	.llseek		= generic_file_llseek,
 };
 
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
@@ -251,6 +253,7 @@
 
 static const struct file_operations sel_disable_ops = {
 	.write		= sel_write_disable,
+	.llseek		= generic_file_llseek,
 };
 
 static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
@@ -265,6 +268,7 @@
 
 static const struct file_operations sel_policyvers_ops = {
 	.read		= sel_read_policyvers,
+	.llseek		= generic_file_llseek,
 };
 
 /* declaration for sel_write_load */
@@ -289,6 +293,7 @@
 
 static const struct file_operations sel_mls_ops = {
 	.read		= sel_read_mls,
+	.llseek		= generic_file_llseek,
 };
 
 static ssize_t sel_write_load(struct file *file, const char __user *buf,
@@ -356,6 +361,7 @@
 
 static const struct file_operations sel_load_ops = {
 	.write		= sel_write_load,
+	.llseek		= generic_file_llseek,
 };
 
 static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
@@ -437,6 +443,7 @@
 static const struct file_operations sel_checkreqprot_ops = {
 	.read		= sel_read_checkreqprot,
 	.write		= sel_write_checkreqprot,
+	.llseek		= generic_file_llseek,
 };
 
 /*
@@ -482,6 +489,7 @@
 	.write		= selinux_transaction_write,
 	.read		= simple_transaction_read,
 	.release	= simple_transaction_release,
+	.llseek		= generic_file_llseek,
 };
 
 /*
@@ -883,6 +891,7 @@
 static const struct file_operations sel_bool_ops = {
 	.read		= sel_read_bool,
 	.write		= sel_write_bool,
+	.llseek		= generic_file_llseek,
 };
 
 static ssize_t sel_commit_bools_write(struct file *filep,
@@ -935,6 +944,7 @@
 
 static const struct file_operations sel_commit_bools_ops = {
 	.write		= sel_commit_bools_write,
+	.llseek		= generic_file_llseek,
 };
 
 static void sel_remove_entries(struct dentry *de)
@@ -1127,10 +1137,12 @@
 static const struct file_operations sel_avc_cache_threshold_ops = {
 	.read		= sel_read_avc_cache_threshold,
 	.write		= sel_write_avc_cache_threshold,
+	.llseek		= generic_file_llseek,
 };
 
 static const struct file_operations sel_avc_hash_stats_ops = {
 	.read		= sel_read_avc_hash_stats,
+	.llseek		= generic_file_llseek,
 };
 
 #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
@@ -1255,6 +1267,7 @@
 
 static const struct file_operations sel_initcon_ops = {
 	.read		= sel_read_initcon,
+	.llseek		= generic_file_llseek,
 };
 
 static int sel_make_initcon_files(struct dentry *dir)
@@ -1330,6 +1343,7 @@
 
 static const struct file_operations sel_class_ops = {
 	.read		= sel_read_class,
+	.llseek		= generic_file_llseek,
 };
 
 static ssize_t sel_read_perm(struct file *file, char __user *buf,
@@ -1354,6 +1368,7 @@
 
 static const struct file_operations sel_perm_ops = {
 	.read		= sel_read_perm,
+	.llseek		= generic_file_llseek,
 };
 
 static ssize_t sel_read_policycap(struct file *file, char __user *buf,
@@ -1372,6 +1387,7 @@
 
 static const struct file_operations sel_policycap_ops = {
 	.read		= sel_read_policycap,
+	.llseek		= generic_file_llseek,
 };
 
 static int sel_make_perm_files(char *objclass, int classvalue,
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 1215b8e..929480c 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -342,20 +342,20 @@
 
 	if (vers < POLICYDB_VERSION_AVTAB) {
 		rc = next_entry(buf32, fp, sizeof(u32));
-		if (rc < 0) {
+		if (rc) {
 			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
-			return -1;
+			return rc;
 		}
 		items2 = le32_to_cpu(buf32[0]);
 		if (items2 > ARRAY_SIZE(buf32)) {
 			printk(KERN_ERR "SELinux: avtab: entry overflow\n");
-			return -1;
+			return -EINVAL;
 
 		}
 		rc = next_entry(buf32, fp, sizeof(u32)*items2);
-		if (rc < 0) {
+		if (rc) {
 			printk(KERN_ERR "SELinux: avtab: truncated entry\n");
-			return -1;
+			return rc;
 		}
 		items = 0;
 
@@ -363,19 +363,19 @@
 		key.source_type = (u16)val;
 		if (key.source_type != val) {
 			printk(KERN_ERR "SELinux: avtab: truncated source type\n");
-			return -1;
+			return -EINVAL;
 		}
 		val = le32_to_cpu(buf32[items++]);
 		key.target_type = (u16)val;
 		if (key.target_type != val) {
 			printk(KERN_ERR "SELinux: avtab: truncated target type\n");
-			return -1;
+			return -EINVAL;
 		}
 		val = le32_to_cpu(buf32[items++]);
 		key.target_class = (u16)val;
 		if (key.target_class != val) {
 			printk(KERN_ERR "SELinux: avtab: truncated target class\n");
-			return -1;
+			return -EINVAL;
 		}
 
 		val = le32_to_cpu(buf32[items++]);
@@ -383,12 +383,12 @@
 
 		if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
 			printk(KERN_ERR "SELinux: avtab: null entry\n");
-			return -1;
+			return -EINVAL;
 		}
 		if ((val & AVTAB_AV) &&
 		    (val & AVTAB_TYPE)) {
 			printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n");
-			return -1;
+			return -EINVAL;
 		}
 
 		for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
@@ -403,15 +403,15 @@
 
 		if (items != items2) {
 			printk(KERN_ERR "SELinux: avtab: entry only had %d items, expected %d\n", items2, items);
-			return -1;
+			return -EINVAL;
 		}
 		return 0;
 	}
 
 	rc = next_entry(buf16, fp, sizeof(u16)*4);
-	if (rc < 0) {
+	if (rc) {
 		printk(KERN_ERR "SELinux: avtab: truncated entry\n");
-		return -1;
+		return rc;
 	}
 
 	items = 0;
@@ -424,7 +424,7 @@
 	    !policydb_type_isvalid(pol, key.target_type) ||
 	    !policydb_class_isvalid(pol, key.target_class)) {
 		printk(KERN_ERR "SELinux: avtab: invalid type or class\n");
-		return -1;
+		return -EINVAL;
 	}
 
 	set = 0;
@@ -434,19 +434,19 @@
 	}
 	if (!set || set > 1) {
 		printk(KERN_ERR "SELinux:  avtab:  more than one specifier\n");
-		return -1;
+		return -EINVAL;
 	}
 
 	rc = next_entry(buf32, fp, sizeof(u32));
-	if (rc < 0) {
+	if (rc) {
 		printk(KERN_ERR "SELinux: avtab: truncated entry\n");
-		return -1;
+		return rc;
 	}
 	datum.data = le32_to_cpu(*buf32);
 	if ((key.specified & AVTAB_TYPE) &&
 	    !policydb_type_isvalid(pol, datum.data)) {
 		printk(KERN_ERR "SELinux: avtab: invalid type\n");
-		return -1;
+		return -EINVAL;
 	}
 	return insertf(a, &key, &datum, p);
 }
@@ -487,8 +487,7 @@
 				printk(KERN_ERR "SELinux: avtab: out of memory\n");
 			else if (rc == -EEXIST)
 				printk(KERN_ERR "SELinux: avtab: duplicate entry\n");
-			else
-				rc = -EINVAL;
+
 			goto bad;
 		}
 	}
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index 4a4e35c..c91e150 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -117,10 +117,14 @@
 
 int cond_policydb_init(struct policydb *p)
 {
+	int rc;
+
 	p->bool_val_to_struct = NULL;
 	p->cond_list = NULL;
-	if (avtab_init(&p->te_cond_avtab))
-		return -1;
+
+	rc = avtab_init(&p->te_cond_avtab);
+	if (rc)
+		return rc;
 
 	return 0;
 }
@@ -219,34 +223,37 @@
 
 	booldatum = kzalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
 	if (!booldatum)
-		return -1;
+		return -ENOMEM;
 
 	rc = next_entry(buf, fp, sizeof buf);
-	if (rc < 0)
+	if (rc)
 		goto err;
 
 	booldatum->value = le32_to_cpu(buf[0]);
 	booldatum->state = le32_to_cpu(buf[1]);
 
+	rc = -EINVAL;
 	if (!bool_isvalid(booldatum))
 		goto err;
 
 	len = le32_to_cpu(buf[2]);
 
+	rc = -ENOMEM;
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key)
 		goto err;
 	rc = next_entry(key, fp, len);
-	if (rc < 0)
+	if (rc)
 		goto err;
 	key[len] = '\0';
-	if (hashtab_insert(h, key, booldatum))
+	rc = hashtab_insert(h, key, booldatum);
+	if (rc)
 		goto err;
 
 	return 0;
 err:
 	cond_destroy_bool(key, booldatum, NULL);
-	return -1;
+	return rc;
 }
 
 struct cond_insertf_data {
@@ -263,7 +270,7 @@
 	struct cond_av_list *other = data->other, *list, *cur;
 	struct avtab_node *node_ptr;
 	u8 found;
-
+	int rc = -EINVAL;
 
 	/*
 	 * For type rules we have to make certain there aren't any
@@ -313,12 +320,15 @@
 	node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
 	if (!node_ptr) {
 		printk(KERN_ERR "SELinux: could not insert rule.\n");
+		rc = -ENOMEM;
 		goto err;
 	}
 
 	list = kzalloc(sizeof(struct cond_av_list), GFP_KERNEL);
-	if (!list)
+	if (!list) {
+		rc = -ENOMEM;
 		goto err;
+	}
 
 	list->node = node_ptr;
 	if (!data->head)
@@ -331,7 +341,7 @@
 err:
 	cond_av_list_destroy(data->head);
 	data->head = NULL;
-	return -1;
+	return rc;
 }
 
 static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
@@ -345,8 +355,8 @@
 
 	len = 0;
 	rc = next_entry(buf, fp, sizeof(u32));
-	if (rc < 0)
-		return -1;
+	if (rc)
+		return rc;
 
 	len = le32_to_cpu(buf[0]);
 	if (len == 0)
@@ -361,7 +371,6 @@
 				     &data);
 		if (rc)
 			return rc;
-
 	}
 
 	*ret_list = data.head;
@@ -390,24 +399,25 @@
 	struct cond_expr *expr = NULL, *last = NULL;
 
 	rc = next_entry(buf, fp, sizeof(u32));
-	if (rc < 0)
-		return -1;
+	if (rc)
+		return rc;
 
 	node->cur_state = le32_to_cpu(buf[0]);
 
 	len = 0;
 	rc = next_entry(buf, fp, sizeof(u32));
-	if (rc < 0)
-		return -1;
+	if (rc)
+		return rc;
 
 	/* expr */
 	len = le32_to_cpu(buf[0]);
 
 	for (i = 0; i < len; i++) {
 		rc = next_entry(buf, fp, sizeof(u32) * 2);
-		if (rc < 0)
+		if (rc)
 			goto err;
 
+		rc = -ENOMEM;
 		expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL);
 		if (!expr)
 			goto err;
@@ -416,6 +426,7 @@
 		expr->bool = le32_to_cpu(buf[1]);
 
 		if (!expr_isvalid(p, expr)) {
+			rc = -EINVAL;
 			kfree(expr);
 			goto err;
 		}
@@ -427,14 +438,16 @@
 		last = expr;
 	}
 
-	if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
+	rc = cond_read_av_list(p, fp, &node->true_list, NULL);
+	if (rc)
 		goto err;
-	if (cond_read_av_list(p, fp, &node->false_list, node->true_list) != 0)
+	rc = cond_read_av_list(p, fp, &node->false_list, node->true_list);
+	if (rc)
 		goto err;
 	return 0;
 err:
 	cond_node_destroy(node);
-	return -1;
+	return rc;
 }
 
 int cond_read_list(struct policydb *p, void *fp)
@@ -445,8 +458,8 @@
 	int rc;
 
 	rc = next_entry(buf, fp, sizeof buf);
-	if (rc < 0)
-		return -1;
+	if (rc)
+		return rc;
 
 	len = le32_to_cpu(buf[0]);
 
@@ -455,11 +468,13 @@
 		goto err;
 
 	for (i = 0; i < len; i++) {
+		rc = -ENOMEM;
 		node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
 		if (!node)
 			goto err;
 
-		if (cond_read_node(p, node, fp) != 0)
+		rc = cond_read_node(p, node, fp);
+		if (rc)
 			goto err;
 
 		if (i == 0)
@@ -472,7 +487,7 @@
 err:
 	cond_list_destroy(p->cond_list);
 	p->cond_list = NULL;
-	return -1;
+	return rc;
 }
 
 /* Determine whether additional permissions are granted by the conditional
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index c57802a..3a29704 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -31,6 +31,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/audit.h>
+#include <linux/flex_array.h>
 #include "security.h"
 
 #include "policydb.h"
@@ -655,6 +656,9 @@
 
 static void ocontext_destroy(struct ocontext *c, int i)
 {
+	if (!c)
+		return;
+
 	context_destroy(&c->context[0]);
 	context_destroy(&c->context[1]);
 	if (i == OCON_ISID || i == OCON_FS ||
@@ -736,11 +740,17 @@
 	hashtab_map(p->range_tr, range_tr_destroy, NULL);
 	hashtab_destroy(p->range_tr);
 
-	if (p->type_attr_map) {
-		for (i = 0; i < p->p_types.nprim; i++)
-			ebitmap_destroy(&p->type_attr_map[i]);
+	if (p->type_attr_map_array) {
+		for (i = 0; i < p->p_types.nprim; i++) {
+			struct ebitmap *e;
+
+			e = flex_array_get(p->type_attr_map_array, i);
+			if (!e)
+				continue;
+			ebitmap_destroy(e);
+		}
+		flex_array_free(p->type_attr_map_array);
 	}
-	kfree(p->type_attr_map);
 	ebitmap_destroy(&p->policycaps);
 	ebitmap_destroy(&p->permissive_map);
 
@@ -1701,6 +1711,333 @@
 	return 1U << (perdatum->value-1);
 }
 
+static int range_read(struct policydb *p, void *fp)
+{
+	struct range_trans *rt = NULL;
+	struct mls_range *r = NULL;
+	int i, rc;
+	__le32 buf[2];
+	u32 nel;
+
+	if (p->policyvers < POLICYDB_VERSION_MLS)
+		return 0;
+
+	rc = next_entry(buf, fp, sizeof(u32));
+	if (rc)
+		goto out;
+
+	nel = le32_to_cpu(buf[0]);
+	for (i = 0; i < nel; i++) {
+		rc = -ENOMEM;
+		rt = kzalloc(sizeof(*rt), GFP_KERNEL);
+		if (!rt)
+			goto out;
+
+		rc = next_entry(buf, fp, (sizeof(u32) * 2));
+		if (rc)
+			goto out;
+
+		rt->source_type = le32_to_cpu(buf[0]);
+		rt->target_type = le32_to_cpu(buf[1]);
+		if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) {
+			rc = next_entry(buf, fp, sizeof(u32));
+			if (rc)
+				goto out;
+			rt->target_class = le32_to_cpu(buf[0]);
+		} else
+			rt->target_class = p->process_class;
+
+		rc = -EINVAL;
+		if (!policydb_type_isvalid(p, rt->source_type) ||
+		    !policydb_type_isvalid(p, rt->target_type) ||
+		    !policydb_class_isvalid(p, rt->target_class))
+			goto out;
+
+		rc = -ENOMEM;
+		r = kzalloc(sizeof(*r), GFP_KERNEL);
+		if (!r)
+			goto out;
+
+		rc = mls_read_range_helper(r, fp);
+		if (rc)
+			goto out;
+
+		rc = -EINVAL;
+		if (!mls_range_isvalid(p, r)) {
+			printk(KERN_WARNING "SELinux:  rangetrans:  invalid range\n");
+			goto out;
+		}
+
+		rc = hashtab_insert(p->range_tr, rt, r);
+		if (rc)
+			goto out;
+
+		rt = NULL;
+		r = NULL;
+	}
+	rangetr_hash_eval(p->range_tr);
+	rc = 0;
+out:
+	kfree(rt);
+	kfree(r);
+	return rc;
+}
+
+static int genfs_read(struct policydb *p, void *fp)
+{
+	int i, j, rc;
+	u32 nel, nel2, len, len2;
+	__le32 buf[1];
+	struct ocontext *l, *c;
+	struct ocontext *newc = NULL;
+	struct genfs *genfs_p, *genfs;
+	struct genfs *newgenfs = NULL;
+
+	rc = next_entry(buf, fp, sizeof(u32));
+	if (rc)
+		goto out;
+	nel = le32_to_cpu(buf[0]);
+
+	for (i = 0; i < nel; i++) {
+		rc = next_entry(buf, fp, sizeof(u32));
+		if (rc)
+			goto out;
+		len = le32_to_cpu(buf[0]);
+
+		rc = -ENOMEM;
+		newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
+		if (!newgenfs)
+			goto out;
+
+		rc = -ENOMEM;
+		newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL);
+		if (!newgenfs->fstype)
+			goto out;
+
+		rc = next_entry(newgenfs->fstype, fp, len);
+		if (rc)
+			goto out;
+
+		newgenfs->fstype[len] = 0;
+
+		for (genfs_p = NULL, genfs = p->genfs; genfs;
+		     genfs_p = genfs, genfs = genfs->next) {
+			rc = -EINVAL;
+			if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
+				printk(KERN_ERR "SELinux:  dup genfs fstype %s\n",
+				       newgenfs->fstype);
+				goto out;
+			}
+			if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
+				break;
+		}
+		newgenfs->next = genfs;
+		if (genfs_p)
+			genfs_p->next = newgenfs;
+		else
+			p->genfs = newgenfs;
+		genfs = newgenfs;
+		newgenfs = NULL;
+
+		rc = next_entry(buf, fp, sizeof(u32));
+		if (rc)
+			goto out;
+
+		nel2 = le32_to_cpu(buf[0]);
+		for (j = 0; j < nel2; j++) {
+			rc = next_entry(buf, fp, sizeof(u32));
+			if (rc)
+				goto out;
+			len = le32_to_cpu(buf[0]);
+
+			rc = -ENOMEM;
+			newc = kzalloc(sizeof(*newc), GFP_KERNEL);
+			if (!newc)
+				goto out;
+
+			rc = -ENOMEM;
+			newc->u.name = kmalloc(len + 1, GFP_KERNEL);
+			if (!newc->u.name)
+				goto out;
+
+			rc = next_entry(newc->u.name, fp, len);
+			if (rc)
+				goto out;
+			newc->u.name[len] = 0;
+
+			rc = next_entry(buf, fp, sizeof(u32));
+			if (rc)
+				goto out;
+
+			newc->v.sclass = le32_to_cpu(buf[0]);
+			rc = context_read_and_validate(&newc->context[0], p, fp);
+			if (rc)
+				goto out;
+
+			for (l = NULL, c = genfs->head; c;
+			     l = c, c = c->next) {
+				rc = -EINVAL;
+				if (!strcmp(newc->u.name, c->u.name) &&
+				    (!c->v.sclass || !newc->v.sclass ||
+				     newc->v.sclass == c->v.sclass)) {
+					printk(KERN_ERR "SELinux:  dup genfs entry (%s,%s)\n",
+					       genfs->fstype, c->u.name);
+					goto out;
+				}
+				len = strlen(newc->u.name);
+				len2 = strlen(c->u.name);
+				if (len > len2)
+					break;
+			}
+
+			newc->next = c;
+			if (l)
+				l->next = newc;
+			else
+				genfs->head = newc;
+			newc = NULL;
+		}
+	}
+	rc = 0;
+out:
+	if (newgenfs)
+		kfree(newgenfs->fstype);
+	kfree(newgenfs);
+	ocontext_destroy(newc, OCON_FSUSE);
+
+	return rc;
+}
+
+static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
+			 void *fp)
+{
+	int i, j, rc;
+	u32 nel, len;
+	__le32 buf[3];
+	struct ocontext *l, *c;
+	u32 nodebuf[8];
+
+	for (i = 0; i < info->ocon_num; i++) {
+		rc = next_entry(buf, fp, sizeof(u32));
+		if (rc)
+			goto out;
+		nel = le32_to_cpu(buf[0]);
+
+		l = NULL;
+		for (j = 0; j < nel; j++) {
+			rc = -ENOMEM;
+			c = kzalloc(sizeof(*c), GFP_KERNEL);
+			if (!c)
+				goto out;
+			if (l)
+				l->next = c;
+			else
+				p->ocontexts[i] = c;
+			l = c;
+
+			switch (i) {
+			case OCON_ISID:
+				rc = next_entry(buf, fp, sizeof(u32));
+				if (rc)
+					goto out;
+
+				c->sid[0] = le32_to_cpu(buf[0]);
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_FS:
+			case OCON_NETIF:
+				rc = next_entry(buf, fp, sizeof(u32));
+				if (rc)
+					goto out;
+				len = le32_to_cpu(buf[0]);
+
+				rc = -ENOMEM;
+				c->u.name = kmalloc(len + 1, GFP_KERNEL);
+				if (!c->u.name)
+					goto out;
+
+				rc = next_entry(c->u.name, fp, len);
+				if (rc)
+					goto out;
+
+				c->u.name[len] = 0;
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				rc = context_read_and_validate(&c->context[1], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_PORT:
+				rc = next_entry(buf, fp, sizeof(u32)*3);
+				if (rc)
+					goto out;
+				c->u.port.protocol = le32_to_cpu(buf[0]);
+				c->u.port.low_port = le32_to_cpu(buf[1]);
+				c->u.port.high_port = le32_to_cpu(buf[2]);
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_NODE:
+				rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
+				if (rc)
+					goto out;
+				c->u.node.addr = nodebuf[0]; /* network order */
+				c->u.node.mask = nodebuf[1]; /* network order */
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_FSUSE:
+				rc = next_entry(buf, fp, sizeof(u32)*2);
+				if (rc)
+					goto out;
+
+				rc = -EINVAL;
+				c->v.behavior = le32_to_cpu(buf[0]);
+				if (c->v.behavior > SECURITY_FS_USE_NONE)
+					goto out;
+
+				rc = -ENOMEM;
+				len = le32_to_cpu(buf[1]);
+				c->u.name = kmalloc(len + 1, GFP_KERNEL);
+				if (!c->u.name)
+					goto out;
+
+				rc = next_entry(c->u.name, fp, len);
+				if (rc)
+					goto out;
+				c->u.name[len] = 0;
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_NODE6: {
+				int k;
+
+				rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
+				if (rc)
+					goto out;
+				for (k = 0; k < 4; k++)
+					c->u.node6.addr[k] = nodebuf[k];
+				for (k = 0; k < 4; k++)
+					c->u.node6.mask[k] = nodebuf[k+4];
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			}
+			}
+		}
+	}
+	rc = 0;
+out:
+	return rc;
+}
+
 /*
  * Read the configuration data from a policy database binary
  * representation file into a policy database structure.
@@ -1709,16 +2046,12 @@
 {
 	struct role_allow *ra, *lra;
 	struct role_trans *tr, *ltr;
-	struct ocontext *l, *c, *newc;
-	struct genfs *genfs_p, *genfs, *newgenfs;
 	int i, j, rc;
 	__le32 buf[4];
-	u32 nodebuf[8];
-	u32 len, len2, nprim, nel, nel2;
+	u32 len, nprim, nel;
+
 	char *policydb_str;
 	struct policydb_compat_info *info;
-	struct range_trans *rt;
-	struct mls_range *r;
 
 	rc = policydb_init(p);
 	if (rc)
@@ -1919,294 +2252,45 @@
 	if (!p->process_trans_perms)
 		goto bad;
 
-	for (i = 0; i < info->ocon_num; i++) {
-		rc = next_entry(buf, fp, sizeof(u32));
-		if (rc < 0)
-			goto bad;
-		nel = le32_to_cpu(buf[0]);
-		l = NULL;
-		for (j = 0; j < nel; j++) {
-			c = kzalloc(sizeof(*c), GFP_KERNEL);
-			if (!c) {
-				rc = -ENOMEM;
-				goto bad;
-			}
-			if (l)
-				l->next = c;
-			else
-				p->ocontexts[i] = c;
-			l = c;
-			rc = -EINVAL;
-			switch (i) {
-			case OCON_ISID:
-				rc = next_entry(buf, fp, sizeof(u32));
-				if (rc < 0)
-					goto bad;
-				c->sid[0] = le32_to_cpu(buf[0]);
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_FS:
-			case OCON_NETIF:
-				rc = next_entry(buf, fp, sizeof(u32));
-				if (rc < 0)
-					goto bad;
-				len = le32_to_cpu(buf[0]);
-				c->u.name = kmalloc(len + 1, GFP_KERNEL);
-				if (!c->u.name) {
-					rc = -ENOMEM;
-					goto bad;
-				}
-				rc = next_entry(c->u.name, fp, len);
-				if (rc < 0)
-					goto bad;
-				c->u.name[len] = 0;
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				rc = context_read_and_validate(&c->context[1], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_PORT:
-				rc = next_entry(buf, fp, sizeof(u32)*3);
-				if (rc < 0)
-					goto bad;
-				c->u.port.protocol = le32_to_cpu(buf[0]);
-				c->u.port.low_port = le32_to_cpu(buf[1]);
-				c->u.port.high_port = le32_to_cpu(buf[2]);
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_NODE:
-				rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
-				if (rc < 0)
-					goto bad;
-				c->u.node.addr = nodebuf[0]; /* network order */
-				c->u.node.mask = nodebuf[1]; /* network order */
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_FSUSE:
-				rc = next_entry(buf, fp, sizeof(u32)*2);
-				if (rc < 0)
-					goto bad;
-				c->v.behavior = le32_to_cpu(buf[0]);
-				if (c->v.behavior > SECURITY_FS_USE_NONE)
-					goto bad;
-				len = le32_to_cpu(buf[1]);
-				c->u.name = kmalloc(len + 1, GFP_KERNEL);
-				if (!c->u.name) {
-					rc = -ENOMEM;
-					goto bad;
-				}
-				rc = next_entry(c->u.name, fp, len);
-				if (rc < 0)
-					goto bad;
-				c->u.name[len] = 0;
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_NODE6: {
-				int k;
-
-				rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
-				if (rc < 0)
-					goto bad;
-				for (k = 0; k < 4; k++)
-					c->u.node6.addr[k] = nodebuf[k];
-				for (k = 0; k < 4; k++)
-					c->u.node6.mask[k] = nodebuf[k+4];
-				if (context_read_and_validate(&c->context[0], p, fp))
-					goto bad;
-				break;
-			}
-			}
-		}
-	}
-
-	rc = next_entry(buf, fp, sizeof(u32));
-	if (rc < 0)
+	rc = ocontext_read(p, info, fp);
+	if (rc)
 		goto bad;
-	nel = le32_to_cpu(buf[0]);
-	genfs_p = NULL;
-	rc = -EINVAL;
-	for (i = 0; i < nel; i++) {
-		rc = next_entry(buf, fp, sizeof(u32));
-		if (rc < 0)
-			goto bad;
-		len = le32_to_cpu(buf[0]);
-		newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
-		if (!newgenfs) {
-			rc = -ENOMEM;
-			goto bad;
-		}
 
-		newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL);
-		if (!newgenfs->fstype) {
-			rc = -ENOMEM;
-			kfree(newgenfs);
-			goto bad;
-		}
-		rc = next_entry(newgenfs->fstype, fp, len);
-		if (rc < 0) {
-			kfree(newgenfs->fstype);
-			kfree(newgenfs);
-			goto bad;
-		}
-		newgenfs->fstype[len] = 0;
-		for (genfs_p = NULL, genfs = p->genfs; genfs;
-		     genfs_p = genfs, genfs = genfs->next) {
-			if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
-				printk(KERN_ERR "SELinux:  dup genfs "
-				       "fstype %s\n", newgenfs->fstype);
-				kfree(newgenfs->fstype);
-				kfree(newgenfs);
-				goto bad;
-			}
-			if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
-				break;
-		}
-		newgenfs->next = genfs;
-		if (genfs_p)
-			genfs_p->next = newgenfs;
-		else
-			p->genfs = newgenfs;
-		rc = next_entry(buf, fp, sizeof(u32));
-		if (rc < 0)
-			goto bad;
-		nel2 = le32_to_cpu(buf[0]);
-		for (j = 0; j < nel2; j++) {
-			rc = next_entry(buf, fp, sizeof(u32));
-			if (rc < 0)
-				goto bad;
-			len = le32_to_cpu(buf[0]);
+	rc = genfs_read(p, fp);
+	if (rc)
+		goto bad;
 
-			newc = kzalloc(sizeof(*newc), GFP_KERNEL);
-			if (!newc) {
-				rc = -ENOMEM;
-				goto bad;
-			}
+	rc = range_read(p, fp);
+	if (rc)
+		goto bad;
 
-			newc->u.name = kmalloc(len + 1, GFP_KERNEL);
-			if (!newc->u.name) {
-				rc = -ENOMEM;
-				goto bad_newc;
-			}
-			rc = next_entry(newc->u.name, fp, len);
-			if (rc < 0)
-				goto bad_newc;
-			newc->u.name[len] = 0;
-			rc = next_entry(buf, fp, sizeof(u32));
-			if (rc < 0)
-				goto bad_newc;
-			newc->v.sclass = le32_to_cpu(buf[0]);
-			if (context_read_and_validate(&newc->context[0], p, fp))
-				goto bad_newc;
-			for (l = NULL, c = newgenfs->head; c;
-			     l = c, c = c->next) {
-				if (!strcmp(newc->u.name, c->u.name) &&
-				    (!c->v.sclass || !newc->v.sclass ||
-				     newc->v.sclass == c->v.sclass)) {
-					printk(KERN_ERR "SELinux:  dup genfs "
-					       "entry (%s,%s)\n",
-					       newgenfs->fstype, c->u.name);
-					goto bad_newc;
-				}
-				len = strlen(newc->u.name);
-				len2 = strlen(c->u.name);
-				if (len > len2)
-					break;
-			}
+	rc = -ENOMEM;
+	p->type_attr_map_array = flex_array_alloc(sizeof(struct ebitmap),
+						  p->p_types.nprim,
+						  GFP_KERNEL | __GFP_ZERO);
+	if (!p->type_attr_map_array)
+		goto bad;
 
-			newc->next = c;
-			if (l)
-				l->next = newc;
-			else
-				newgenfs->head = newc;
-		}
-	}
-
-	if (p->policyvers >= POLICYDB_VERSION_MLS) {
-		int new_rangetr = p->policyvers >= POLICYDB_VERSION_RANGETRANS;
-		rc = next_entry(buf, fp, sizeof(u32));
-		if (rc < 0)
-			goto bad;
-		nel = le32_to_cpu(buf[0]);
-		for (i = 0; i < nel; i++) {
-			rt = kzalloc(sizeof(*rt), GFP_KERNEL);
-			if (!rt) {
-				rc = -ENOMEM;
-				goto bad;
-			}
-			rc = next_entry(buf, fp, (sizeof(u32) * 2));
-			if (rc < 0) {
-				kfree(rt);
-				goto bad;
-			}
-			rt->source_type = le32_to_cpu(buf[0]);
-			rt->target_type = le32_to_cpu(buf[1]);
-			if (new_rangetr) {
-				rc = next_entry(buf, fp, sizeof(u32));
-				if (rc < 0) {
-					kfree(rt);
-					goto bad;
-				}
-				rt->target_class = le32_to_cpu(buf[0]);
-			} else
-				rt->target_class = p->process_class;
-			if (!policydb_type_isvalid(p, rt->source_type) ||
-			    !policydb_type_isvalid(p, rt->target_type) ||
-			    !policydb_class_isvalid(p, rt->target_class)) {
-				kfree(rt);
-				rc = -EINVAL;
-				goto bad;
-			}
-			r = kzalloc(sizeof(*r), GFP_KERNEL);
-			if (!r) {
-				kfree(rt);
-				rc = -ENOMEM;
-				goto bad;
-			}
-			rc = mls_read_range_helper(r, fp);
-			if (rc) {
-				kfree(rt);
-				kfree(r);
-				goto bad;
-			}
-			if (!mls_range_isvalid(p, r)) {
-				printk(KERN_WARNING "SELinux:  rangetrans:  invalid range\n");
-				kfree(rt);
-				kfree(r);
-				goto bad;
-			}
-			rc = hashtab_insert(p->range_tr, rt, r);
-			if (rc) {
-				kfree(rt);
-				kfree(r);
-				goto bad;
-			}
-		}
-		rangetr_hash_eval(p->range_tr);
-	}
-
-	p->type_attr_map = kmalloc(p->p_types.nprim * sizeof(struct ebitmap), GFP_KERNEL);
-	if (!p->type_attr_map)
+	/* preallocate so we don't have to worry about the put ever failing */
+	rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim - 1,
+				 GFP_KERNEL | __GFP_ZERO);
+	if (rc)
 		goto bad;
 
 	for (i = 0; i < p->p_types.nprim; i++) {
-		ebitmap_init(&p->type_attr_map[i]);
+		struct ebitmap *e = flex_array_get(p->type_attr_map_array, i);
+
+		BUG_ON(!e);
+		ebitmap_init(e);
 		if (p->policyvers >= POLICYDB_VERSION_AVTAB) {
-			if (ebitmap_read(&p->type_attr_map[i], fp))
+			rc = ebitmap_read(e, fp);
+			if (rc)
 				goto bad;
 		}
 		/* add the type itself as the degenerate case */
-		if (ebitmap_set_bit(&p->type_attr_map[i], i, 1))
-				goto bad;
+		rc = ebitmap_set_bit(e, i, 1);
+		if (rc)
+			goto bad;
 	}
 
 	rc = policydb_bounds_sanity_check(p);
@@ -2216,8 +2300,6 @@
 	rc = 0;
 out:
 	return rc;
-bad_newc:
-	ocontext_destroy(newc, OCON_FSUSE);
 bad:
 	if (!rc)
 		rc = -EINVAL;
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index 26d9adf..310e944 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -24,6 +24,8 @@
 #ifndef _SS_POLICYDB_H_
 #define _SS_POLICYDB_H_
 
+#include <linux/flex_array.h>
+
 #include "symtab.h"
 #include "avtab.h"
 #include "sidtab.h"
@@ -246,7 +248,7 @@
 	struct hashtab *range_tr;
 
 	/* type -> attribute reverse mapping */
-	struct ebitmap *type_attr_map;
+	struct flex_array *type_attr_map_array;
 
 	struct ebitmap policycaps;
 
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 1de60ce9..9ea2fec 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -50,6 +50,7 @@
 #include <linux/audit.h>
 #include <linux/mutex.h>
 #include <linux/selinux.h>
+#include <linux/flex_array.h>
 #include <net/netlabel.h>
 
 #include "flask.h"
@@ -626,8 +627,10 @@
 	 */
 	avkey.target_class = tclass;
 	avkey.specified = AVTAB_AV;
-	sattr = &policydb.type_attr_map[scontext->type - 1];
-	tattr = &policydb.type_attr_map[tcontext->type - 1];
+	sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1);
+	BUG_ON(!sattr);
+	tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1);
+	BUG_ON(!tattr);
 	ebitmap_for_each_positive_bit(sattr, snode, i) {
 		ebitmap_for_each_positive_bit(tattr, tnode, j) {
 			avkey.source_type = i + 1;
diff --git a/security/selinux/ss/symtab.c b/security/selinux/ss/symtab.c
index bcf9f62..160326e 100644
--- a/security/selinux/ss/symtab.c
+++ b/security/selinux/ss/symtab.c
@@ -36,7 +36,7 @@
 {
 	s->table = hashtab_create(symhash, symcmp, size);
 	if (!s->table)
-		return -1;
+		return -ENOMEM;
 	s->nprim = 0;
 	return 0;
 }
diff --git a/security/smack/smack.h b/security/smack/smack.h
index c6e9aca..43ae747 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -123,16 +123,6 @@
 #define SMK_FSHAT	"smackfshat="
 #define SMK_FSROOT	"smackfsroot="
 
-/*
- * xattr names
- */
-#define XATTR_SMACK_SUFFIX	"SMACK64"
-#define XATTR_SMACK_IPIN	"SMACK64IPIN"
-#define XATTR_SMACK_IPOUT	"SMACK64IPOUT"
-#define XATTR_NAME_SMACK	XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
-#define XATTR_NAME_SMACKIPIN	XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
-#define XATTR_NAME_SMACKIPOUT	XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
-
 #define SMACK_CIPSO_OPTION 	"-CIPSO"
 
 /*
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 276bdc7..c448d57 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -598,6 +598,8 @@
 static int smack_inode_permission(struct inode *inode, int mask)
 {
 	struct smk_audit_info ad;
+
+	mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
 	/*
 	 * No permission to check. Existence test. Yup, it's there.
 	 */
@@ -2191,7 +2193,7 @@
 
 /**
  * smack_d_instantiate - Make sure the blob is correct on an inode
- * @opt_dentry: unused
+ * @opt_dentry: dentry where inode will be attached
  * @inode: the object
  *
  * Set the inode's security blob if it hasn't been done already.
@@ -2310,20 +2312,10 @@
 		/*
 		 * Get the dentry for xattr.
 		 */
-		if (opt_dentry == NULL) {
-			dp = d_find_alias(inode);
-			if (dp == NULL)
-				break;
-		} else {
-			dp = dget(opt_dentry);
-			if (dp == NULL)
-				break;
-		}
-
+		dp = dget(opt_dentry);
 		fetched = smk_fetch(inode, dp);
 		if (fetched != NULL)
 			final = fetched;
-
 		dput(dp);
 		break;
 	}
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile
index 4fb3903..91640e9 100644
--- a/security/tomoyo/Makefile
+++ b/security/tomoyo/Makefile
@@ -1 +1 @@
-obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o path_group.o
+obj-y = common.o domain.o file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index b5dbdc9..ef43995 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -3,99 +3,184 @@
  *
  * Common functions for TOMOYO.
  *
- * Copyright (C) 2005-2009  NTT DATA CORPORATION
- *
- * Version: 2.2.0   2009/04/01
- *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
  */
 
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/security.h>
-#include <linux/hardirq.h>
 #include "common.h"
 
-/* Lock for protecting policy. */
-DEFINE_MUTEX(tomoyo_policy_lock);
+static struct tomoyo_profile tomoyo_default_profile = {
+	.learning = &tomoyo_default_profile.preference,
+	.permissive = &tomoyo_default_profile.preference,
+	.enforcing = &tomoyo_default_profile.preference,
+	.preference.enforcing_verbose = true,
+	.preference.learning_max_entry = 2048,
+	.preference.learning_verbose = false,
+	.preference.permissive_verbose = true
+};
 
-/* Has loading policy done? */
-bool tomoyo_policy_loaded;
+/* Profile version. Currently only 20090903 is defined. */
+static unsigned int tomoyo_profile_version;
+
+/* Profile table. Memory is allocated as needed. */
+static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
 
 /* String table for functionality that takes 4 modes. */
-static const char *tomoyo_mode_4[4] = {
+static const char *tomoyo_mode[4] = {
 	"disabled", "learning", "permissive", "enforcing"
 };
-/* String table for functionality that takes 2 modes. */
-static const char *tomoyo_mode_2[4] = {
-	"disabled", "enabled", "enabled", "enabled"
-};
 
-/*
- * tomoyo_control_array is a static data which contains
- *
- *  (1) functionality name used by /sys/kernel/security/tomoyo/profile .
- *  (2) initial values for "struct tomoyo_profile".
- *  (3) max values for "struct tomoyo_profile".
- */
-static struct {
-	const char *keyword;
-	unsigned int current_value;
-	const unsigned int max_value;
-} tomoyo_control_array[TOMOYO_MAX_CONTROL_INDEX] = {
-	[TOMOYO_MAC_FOR_FILE]     = { "MAC_FOR_FILE",        0,       3 },
-	[TOMOYO_MAX_ACCEPT_ENTRY] = { "MAX_ACCEPT_ENTRY", 2048, INT_MAX },
-	[TOMOYO_VERBOSE]          = { "TOMOYO_VERBOSE",      1,       1 },
+/* String table for /sys/kernel/security/tomoyo/profile */
+static const char *tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
+				       + TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
+	[TOMOYO_MAC_FILE_EXECUTE]    = "file::execute",
+	[TOMOYO_MAC_FILE_OPEN]       = "file::open",
+	[TOMOYO_MAC_FILE_CREATE]     = "file::create",
+	[TOMOYO_MAC_FILE_UNLINK]     = "file::unlink",
+	[TOMOYO_MAC_FILE_MKDIR]      = "file::mkdir",
+	[TOMOYO_MAC_FILE_RMDIR]      = "file::rmdir",
+	[TOMOYO_MAC_FILE_MKFIFO]     = "file::mkfifo",
+	[TOMOYO_MAC_FILE_MKSOCK]     = "file::mksock",
+	[TOMOYO_MAC_FILE_TRUNCATE]   = "file::truncate",
+	[TOMOYO_MAC_FILE_SYMLINK]    = "file::symlink",
+	[TOMOYO_MAC_FILE_REWRITE]    = "file::rewrite",
+	[TOMOYO_MAC_FILE_MKBLOCK]    = "file::mkblock",
+	[TOMOYO_MAC_FILE_MKCHAR]     = "file::mkchar",
+	[TOMOYO_MAC_FILE_LINK]       = "file::link",
+	[TOMOYO_MAC_FILE_RENAME]     = "file::rename",
+	[TOMOYO_MAC_FILE_CHMOD]      = "file::chmod",
+	[TOMOYO_MAC_FILE_CHOWN]      = "file::chown",
+	[TOMOYO_MAC_FILE_CHGRP]      = "file::chgrp",
+	[TOMOYO_MAC_FILE_IOCTL]      = "file::ioctl",
+	[TOMOYO_MAC_FILE_CHROOT]     = "file::chroot",
+	[TOMOYO_MAC_FILE_MOUNT]      = "file::mount",
+	[TOMOYO_MAC_FILE_UMOUNT]     = "file::umount",
+	[TOMOYO_MAC_FILE_PIVOT_ROOT] = "file::pivot_root",
+	[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
 };
 
-/*
- * tomoyo_profile is a structure which is used for holding the mode of access
- * controls. TOMOYO has 4 modes: disabled, learning, permissive, enforcing.
- * An administrator can define up to 256 profiles.
- * The ->profile of "struct tomoyo_domain_info" is used for remembering
- * the profile's number (0 - 255) assigned to that domain.
- */
-static struct tomoyo_profile {
-	unsigned int value[TOMOYO_MAX_CONTROL_INDEX];
-	const struct tomoyo_path_info *comment;
-} *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
-
 /* Permit policy management by non-root user? */
 static bool tomoyo_manage_by_non_root;
 
 /* Utility functions. */
 
-/* Open operation for /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_open_control(const u8 type, struct file *file);
-/* Close /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_close_control(struct file *file);
-/* Read operation for /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_read_control(struct file *file, char __user *buffer,
-			       const int buffer_len);
-/* Write operation for /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_write_control(struct file *file, const char __user *buffer,
-				const int buffer_len);
+/**
+ * tomoyo_yesno - Return "yes" or "no".
+ *
+ * @value: Bool value.
+ */
+static const char *tomoyo_yesno(const unsigned int value)
+{
+	return value ? "yes" : "no";
+}
+
+static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...)
+{
+	va_list args;
+	const int pos = strlen(buffer);
+	va_start(args, fmt);
+	vsnprintf(buffer + pos, len - pos - 1, fmt, args);
+	va_end(args);
+}
 
 /**
- * tomoyo_parse_name_union - Parse a tomoyo_name_union.
+ * tomoyo_flush - Flush queued string to userspace's buffer.
  *
- * @filename: Name or name group.
- * @ptr:      Pointer to "struct tomoyo_name_union".
+ * @head:   Pointer to "struct tomoyo_io_buffer".
  *
- * Returns true on success, false otherwise.
+ * Returns true if all data was flushed, false otherwise.
  */
-bool tomoyo_parse_name_union(const char *filename,
-			     struct tomoyo_name_union *ptr)
+static bool tomoyo_flush(struct tomoyo_io_buffer *head)
 {
-	if (!tomoyo_is_correct_path(filename, 0, 0, 0))
-		return false;
-	if (filename[0] == '@') {
-		ptr->group = tomoyo_get_path_group(filename + 1);
-		ptr->is_group = true;
-		return ptr->group != NULL;
+	while (head->r.w_pos) {
+		const char *w = head->r.w[0];
+		int len = strlen(w);
+		if (len) {
+			if (len > head->read_user_buf_avail)
+				len = head->read_user_buf_avail;
+			if (!len)
+				return false;
+			if (copy_to_user(head->read_user_buf, w, len))
+				return false;
+			head->read_user_buf_avail -= len;
+			head->read_user_buf += len;
+			w += len;
+		}
+		if (*w) {
+			head->r.w[0] = w;
+			return false;
+		}
+		/* Add '\0' for query. */
+		if (head->poll) {
+			if (!head->read_user_buf_avail ||
+			    copy_to_user(head->read_user_buf, "", 1))
+				return false;
+			head->read_user_buf_avail--;
+			head->read_user_buf++;
+		}
+		head->r.w_pos--;
+		for (len = 0; len < head->r.w_pos; len++)
+			head->r.w[len] = head->r.w[len + 1];
 	}
-	ptr->filename = tomoyo_get_name(filename);
-	ptr->is_group = false;
-	return ptr->filename != NULL;
+	head->r.avail = 0;
+	return true;
+}
+
+/**
+ * tomoyo_set_string - Queue string to "struct tomoyo_io_buffer" structure.
+ *
+ * @head:   Pointer to "struct tomoyo_io_buffer".
+ * @string: String to print.
+ *
+ * Note that @string has to be kept valid until @head is kfree()d.
+ * This means that char[] allocated on stack memory cannot be passed to
+ * this function. Use tomoyo_io_printf() for char[] allocated on stack memory.
+ */
+static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string)
+{
+	if (head->r.w_pos < TOMOYO_MAX_IO_READ_QUEUE) {
+		head->r.w[head->r.w_pos++] = string;
+		tomoyo_flush(head);
+	} else
+		WARN_ON(1);
+}
+
+/**
+ * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @fmt:  The printf()'s format string, followed by parameters.
+ */
+void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
+{
+	va_list args;
+	int len;
+	int pos = head->r.avail;
+	int size = head->readbuf_size - pos;
+	if (size <= 0)
+		return;
+	va_start(args, fmt);
+	len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
+	va_end(args);
+	if (pos + len >= head->readbuf_size) {
+		WARN_ON(1);
+		return;
+	}
+	head->r.avail += len;
+	tomoyo_set_string(head, head->read_buf + pos);
+}
+
+static void tomoyo_set_space(struct tomoyo_io_buffer *head)
+{
+	tomoyo_set_string(head, " ");
+}
+
+static bool tomoyo_set_lf(struct tomoyo_io_buffer *head)
+{
+	tomoyo_set_string(head, "\n");
+	return !head->r.w_pos;
 }
 
 /**
@@ -103,874 +188,239 @@
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  * @ptr:  Pointer to "struct tomoyo_name_union".
- *
- * Returns true on success, false otherwise.
  */
-static bool tomoyo_print_name_union(struct tomoyo_io_buffer *head,
-				 const struct tomoyo_name_union *ptr)
+static void tomoyo_print_name_union(struct tomoyo_io_buffer *head,
+				    const struct tomoyo_name_union *ptr)
 {
-	int pos = head->read_avail;
-	if (pos && head->read_buf[pos - 1] == ' ')
-		head->read_avail--;
-	if (ptr->is_group)
-		return tomoyo_io_printf(head, " @%s",
-					ptr->group->group_name->name);
-	return tomoyo_io_printf(head, " %s", ptr->filename->name);
-}
-
-/**
- * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value.
- *
- * @str: Pointer to the string.
- *
- * Returns true if @str is a \ooo style octal value, false otherwise.
- *
- * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
- * This function verifies that \ooo is in valid range.
- */
-static inline bool tomoyo_is_byte_range(const char *str)
-{
-	return *str >= '0' && *str++ <= '3' &&
-		*str >= '0' && *str++ <= '7' &&
-		*str >= '0' && *str <= '7';
-}
-
-/**
- * tomoyo_is_alphabet_char - Check whether the character is an alphabet.
- *
- * @c: The character to check.
- *
- * Returns true if @c is an alphabet character, false otherwise.
- */
-static inline bool tomoyo_is_alphabet_char(const char c)
-{
-	return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
-}
-
-/**
- * tomoyo_make_byte - Make byte value from three octal characters.
- *
- * @c1: The first character.
- * @c2: The second character.
- * @c3: The third character.
- *
- * Returns byte value.
- */
-static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
-{
-	return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
-}
-
-/**
- * tomoyo_str_starts - Check whether the given string starts with the given keyword.
- *
- * @src:  Pointer to pointer to the string.
- * @find: Pointer to the keyword.
- *
- * Returns true if @src starts with @find, false otherwise.
- *
- * The @src is updated to point the first character after the @find
- * if @src starts with @find.
- */
-static bool tomoyo_str_starts(char **src, const char *find)
-{
-	const int len = strlen(find);
-	char *tmp = *src;
-
-	if (strncmp(tmp, find, len))
-		return false;
-	tmp += len;
-	*src = tmp;
-	return true;
-}
-
-/**
- * tomoyo_normalize_line - Format string.
- *
- * @buffer: The line to normalize.
- *
- * Leading and trailing whitespaces are removed.
- * Multiple whitespaces are packed into single space.
- *
- * Returns nothing.
- */
-static void tomoyo_normalize_line(unsigned char *buffer)
-{
-	unsigned char *sp = buffer;
-	unsigned char *dp = buffer;
-	bool first = true;
-
-	while (tomoyo_is_invalid(*sp))
-		sp++;
-	while (*sp) {
-		if (!first)
-			*dp++ = ' ';
-		first = false;
-		while (tomoyo_is_valid(*sp))
-			*dp++ = *sp++;
-		while (tomoyo_is_invalid(*sp))
-			sp++;
+	tomoyo_set_space(head);
+	if (ptr->is_group) {
+		tomoyo_set_string(head, "@");
+		tomoyo_set_string(head, ptr->group->group_name->name);
+	} else {
+		tomoyo_set_string(head, ptr->filename->name);
 	}
-	*dp = '\0';
 }
 
 /**
- * tomoyo_tokenize - Tokenize string.
+ * tomoyo_print_number_union - Print a tomoyo_number_union.
  *
- * @buffer: The line to tokenize.
- * @w:      Pointer to "char *".
- * @size:   Sizeof @w .
- *
- * Returns true on success, false otherwise.
+ * @head:       Pointer to "struct tomoyo_io_buffer".
+ * @ptr:        Pointer to "struct tomoyo_number_union".
  */
-bool tomoyo_tokenize(char *buffer, char *w[], size_t size)
+static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
+				      const struct tomoyo_number_union *ptr)
 {
-	int count = size / sizeof(char *);
-	int i;
-	for (i = 0; i < count; i++)
-		w[i] = "";
-	for (i = 0; i < count; i++) {
-		char *cp = strchr(buffer, ' ');
-		if (cp)
-			*cp = '\0';
-		w[i] = buffer;
-		if (!cp)
-			break;
-		buffer = cp + 1;
-	}
-	return i < count || !*buffer;
-}
-
-/**
- * tomoyo_is_correct_path - Validate a pathname.
- * @filename:     The pathname to check.
- * @start_type:   Should the pathname start with '/'?
- *                1 = must / -1 = must not / 0 = don't care
- * @pattern_type: Can the pathname contain a wildcard?
- *                1 = must / -1 = must not / 0 = don't care
- * @end_type:     Should the pathname end with '/'?
- *                1 = must / -1 = must not / 0 = don't care
- *
- * Check whether the given filename follows the naming rules.
- * Returns true if @filename follows the naming rules, false otherwise.
- */
-bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
-			    const s8 pattern_type, const s8 end_type)
-{
-	const char *const start = filename;
-	bool in_repetition = false;
-	bool contains_pattern = false;
-	unsigned char c;
-	unsigned char d;
-	unsigned char e;
-
-	if (!filename)
-		goto out;
-	c = *filename;
-	if (start_type == 1) { /* Must start with '/' */
-		if (c != '/')
-			goto out;
-	} else if (start_type == -1) { /* Must not start with '/' */
-		if (c == '/')
-			goto out;
-	}
-	if (c)
-		c = *(filename + strlen(filename) - 1);
-	if (end_type == 1) { /* Must end with '/' */
-		if (c != '/')
-			goto out;
-	} else if (end_type == -1) { /* Must not end with '/' */
-		if (c == '/')
-			goto out;
-	}
-	while (1) {
-		c = *filename++;
-		if (!c)
-			break;
-		if (c == '\\') {
-			c = *filename++;
-			switch (c) {
-			case '\\':  /* "\\" */
-				continue;
-			case '$':   /* "\$" */
-			case '+':   /* "\+" */
-			case '?':   /* "\?" */
-			case '*':   /* "\*" */
-			case '@':   /* "\@" */
-			case 'x':   /* "\x" */
-			case 'X':   /* "\X" */
-			case 'a':   /* "\a" */
-			case 'A':   /* "\A" */
-			case '-':   /* "\-" */
-				if (pattern_type == -1)
-					break; /* Must not contain pattern */
-				contains_pattern = true;
-				continue;
-			case '{':   /* "/\{" */
-				if (filename - 3 < start ||
-				    *(filename - 3) != '/')
-					break;
-				if (pattern_type == -1)
-					break; /* Must not contain pattern */
-				contains_pattern = true;
-				in_repetition = true;
-				continue;
-			case '}':   /* "\}/" */
-				if (*filename != '/')
-					break;
-				if (!in_repetition)
-					break;
-				in_repetition = false;
-				continue;
-			case '0':   /* "\ooo" */
-			case '1':
-			case '2':
-			case '3':
-				d = *filename++;
-				if (d < '0' || d > '7')
-					break;
-				e = *filename++;
-				if (e < '0' || e > '7')
-					break;
-				c = tomoyo_make_byte(c, d, e);
-				if (tomoyo_is_invalid(c))
-					continue; /* pattern is not \000 */
-			}
-			goto out;
-		} else if (in_repetition && c == '/') {
-			goto out;
-		} else if (tomoyo_is_invalid(c)) {
-			goto out;
-		}
-	}
-	if (pattern_type == 1) { /* Must contain pattern */
-		if (!contains_pattern)
-			goto out;
-	}
-	if (in_repetition)
-		goto out;
-	return true;
- out:
-	return false;
-}
-
-/**
- * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules.
- * @domainname:   The domainname to check.
- *
- * Returns true if @domainname follows the naming rules, false otherwise.
- */
-bool tomoyo_is_correct_domain(const unsigned char *domainname)
-{
-	unsigned char c;
-	unsigned char d;
-	unsigned char e;
-
-	if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
-				   TOMOYO_ROOT_NAME_LEN))
-		goto out;
-	domainname += TOMOYO_ROOT_NAME_LEN;
-	if (!*domainname)
-		return true;
-	do {
-		if (*domainname++ != ' ')
-			goto out;
-		if (*domainname++ != '/')
-			goto out;
-		while ((c = *domainname) != '\0' && c != ' ') {
-			domainname++;
-			if (c == '\\') {
-				c = *domainname++;
-				switch ((c)) {
-				case '\\':  /* "\\" */
-					continue;
-				case '0':   /* "\ooo" */
-				case '1':
-				case '2':
-				case '3':
-					d = *domainname++;
-					if (d < '0' || d > '7')
-						break;
-					e = *domainname++;
-					if (e < '0' || e > '7')
-						break;
-					c = tomoyo_make_byte(c, d, e);
-					if (tomoyo_is_invalid(c))
-						/* pattern is not \000 */
-						continue;
-				}
-				goto out;
-			} else if (tomoyo_is_invalid(c)) {
-				goto out;
-			}
-		}
-	} while (*domainname);
-	return true;
- out:
-	return false;
-}
-
-/**
- * tomoyo_is_domain_def - Check whether the given token can be a domainname.
- *
- * @buffer: The token to check.
- *
- * Returns true if @buffer possibly be a domainname, false otherwise.
- */
-bool tomoyo_is_domain_def(const unsigned char *buffer)
-{
-	return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
-}
-
-/**
- * tomoyo_find_domain - Find a domain by the given name.
- *
- * @domainname: The domainname to find.
- *
- * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
-{
-	struct tomoyo_domain_info *domain;
-	struct tomoyo_path_info name;
-
-	name.name = domainname;
-	tomoyo_fill_path_info(&name);
-	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
-		if (!domain->is_deleted &&
-		    !tomoyo_pathcmp(&name, domain->domainname))
-			return domain;
-	}
-	return NULL;
-}
-
-/**
- * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
- *
- * @filename: The string to evaluate.
- *
- * Returns the initial length without a pattern in @filename.
- */
-static int tomoyo_const_part_length(const char *filename)
-{
-	char c;
-	int len = 0;
-
-	if (!filename)
-		return 0;
-	while ((c = *filename++) != '\0') {
-		if (c != '\\') {
-			len++;
-			continue;
-		}
-		c = *filename++;
-		switch (c) {
-		case '\\':  /* "\\" */
-			len += 2;
-			continue;
-		case '0':   /* "\ooo" */
-		case '1':
-		case '2':
-		case '3':
-			c = *filename++;
-			if (c < '0' || c > '7')
+	tomoyo_set_space(head);
+	if (ptr->is_group) {
+		tomoyo_set_string(head, "@");
+		tomoyo_set_string(head, ptr->group->group_name->name);
+	} else {
+		int i;
+		unsigned long min = ptr->values[0];
+		const unsigned long max = ptr->values[1];
+		u8 min_type = ptr->min_type;
+		const u8 max_type = ptr->max_type;
+		char buffer[128];
+		buffer[0] = '\0';
+		for (i = 0; i < 2; i++) {
+			switch (min_type) {
+			case TOMOYO_VALUE_TYPE_HEXADECIMAL:
+				tomoyo_addprintf(buffer, sizeof(buffer),
+						 "0x%lX", min);
 				break;
-			c = *filename++;
-			if (c < '0' || c > '7')
+			case TOMOYO_VALUE_TYPE_OCTAL:
+				tomoyo_addprintf(buffer, sizeof(buffer),
+						 "0%lo", min);
 				break;
-			len += 4;
-			continue;
-		}
-		break;
-	}
-	return len;
-}
-
-/**
- * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
- *
- * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
- *
- * The caller sets "struct tomoyo_path_info"->name.
- */
-void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
-{
-	const char *name = ptr->name;
-	const int len = strlen(name);
-
-	ptr->const_len = tomoyo_const_part_length(name);
-	ptr->is_dir = len && (name[len - 1] == '/');
-	ptr->is_patterned = (ptr->const_len < len);
-	ptr->hash = full_name_hash(name, len);
-}
-
-/**
- * tomoyo_file_matches_pattern2 - Pattern matching without '/' character
- * and "\-" pattern.
- *
- * @filename:     The start of string to check.
- * @filename_end: The end of string to check.
- * @pattern:      The start of pattern to compare.
- * @pattern_end:  The end of pattern to compare.
- *
- * Returns true if @filename matches @pattern, false otherwise.
- */
-static bool tomoyo_file_matches_pattern2(const char *filename,
-					 const char *filename_end,
-					 const char *pattern,
-					 const char *pattern_end)
-{
-	while (filename < filename_end && pattern < pattern_end) {
-		char c;
-		if (*pattern != '\\') {
-			if (*filename++ != *pattern++)
-				return false;
-			continue;
-		}
-		c = *filename;
-		pattern++;
-		switch (*pattern) {
-			int i;
-			int j;
-		case '?':
-			if (c == '/') {
-				return false;
-			} else if (c == '\\') {
-				if (filename[1] == '\\')
-					filename++;
-				else if (tomoyo_is_byte_range(filename + 1))
-					filename += 3;
-				else
-					return false;
-			}
-			break;
-		case '\\':
-			if (c != '\\')
-				return false;
-			if (*++filename != '\\')
-				return false;
-			break;
-		case '+':
-			if (!isdigit(c))
-				return false;
-			break;
-		case 'x':
-			if (!isxdigit(c))
-				return false;
-			break;
-		case 'a':
-			if (!tomoyo_is_alphabet_char(c))
-				return false;
-			break;
-		case '0':
-		case '1':
-		case '2':
-		case '3':
-			if (c == '\\' && tomoyo_is_byte_range(filename + 1)
-			    && strncmp(filename + 1, pattern, 3) == 0) {
-				filename += 3;
-				pattern += 2;
+			default:
+				tomoyo_addprintf(buffer, sizeof(buffer),
+						 "%lu", min);
 				break;
 			}
-			return false; /* Not matched. */
-		case '*':
-		case '@':
-			for (i = 0; i <= filename_end - filename; i++) {
-				if (tomoyo_file_matches_pattern2(
-						    filename + i, filename_end,
-						    pattern + 1, pattern_end))
-					return true;
-				c = filename[i];
-				if (c == '.' && *pattern == '@')
-					break;
-				if (c != '\\')
-					continue;
-				if (filename[i + 1] == '\\')
-					i++;
-				else if (tomoyo_is_byte_range(filename + i + 1))
-					i += 3;
-				else
-					break; /* Bad pattern. */
-			}
-			return false; /* Not matched. */
-		default:
-			j = 0;
-			c = *pattern;
-			if (c == '$') {
-				while (isdigit(filename[j]))
-					j++;
-			} else if (c == 'X') {
-				while (isxdigit(filename[j]))
-					j++;
-			} else if (c == 'A') {
-				while (tomoyo_is_alphabet_char(filename[j]))
-					j++;
-			}
-			for (i = 1; i <= j; i++) {
-				if (tomoyo_file_matches_pattern2(
-						    filename + i, filename_end,
-						    pattern + 1, pattern_end))
-					return true;
-			}
-			return false; /* Not matched or bad pattern. */
+			if (min == max && min_type == max_type)
+				break;
+			tomoyo_addprintf(buffer, sizeof(buffer), "-");
+			min_type = max_type;
+			min = max;
 		}
-		filename++;
-		pattern++;
+		tomoyo_io_printf(head, "%s", buffer);
 	}
-	while (*pattern == '\\' &&
-	       (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
-		pattern += 2;
-	return filename == filename_end && pattern == pattern_end;
 }
 
 /**
- * tomoyo_file_matches_pattern - Pattern matching without without '/' character.
- *
- * @filename:     The start of string to check.
- * @filename_end: The end of string to check.
- * @pattern:      The start of pattern to compare.
- * @pattern_end:  The end of pattern to compare.
- *
- * Returns true if @filename matches @pattern, false otherwise.
- */
-static bool tomoyo_file_matches_pattern(const char *filename,
-					   const char *filename_end,
-					   const char *pattern,
-					   const char *pattern_end)
-{
-	const char *pattern_start = pattern;
-	bool first = true;
-	bool result;
-
-	while (pattern < pattern_end - 1) {
-		/* Split at "\-" pattern. */
-		if (*pattern++ != '\\' || *pattern++ != '-')
-			continue;
-		result = tomoyo_file_matches_pattern2(filename,
-						      filename_end,
-						      pattern_start,
-						      pattern - 2);
-		if (first)
-			result = !result;
-		if (result)
-			return false;
-		first = false;
-		pattern_start = pattern;
-	}
-	result = tomoyo_file_matches_pattern2(filename, filename_end,
-					      pattern_start, pattern_end);
-	return first ? result : !result;
-}
-
-/**
- * tomoyo_path_matches_pattern2 - Do pathname pattern matching.
- *
- * @f: The start of string to check.
- * @p: The start of pattern to compare.
- *
- * Returns true if @f matches @p, false otherwise.
- */
-static bool tomoyo_path_matches_pattern2(const char *f, const char *p)
-{
-	const char *f_delimiter;
-	const char *p_delimiter;
-
-	while (*f && *p) {
-		f_delimiter = strchr(f, '/');
-		if (!f_delimiter)
-			f_delimiter = f + strlen(f);
-		p_delimiter = strchr(p, '/');
-		if (!p_delimiter)
-			p_delimiter = p + strlen(p);
-		if (*p == '\\' && *(p + 1) == '{')
-			goto recursive;
-		if (!tomoyo_file_matches_pattern(f, f_delimiter, p,
-						 p_delimiter))
-			return false;
-		f = f_delimiter;
-		if (*f)
-			f++;
-		p = p_delimiter;
-		if (*p)
-			p++;
-	}
-	/* Ignore trailing "\*" and "\@" in @pattern. */
-	while (*p == '\\' &&
-	       (*(p + 1) == '*' || *(p + 1) == '@'))
-		p += 2;
-	return !*f && !*p;
- recursive:
-	/*
-	 * The "\{" pattern is permitted only after '/' character.
-	 * This guarantees that below "*(p - 1)" is safe.
-	 * Also, the "\}" pattern is permitted only before '/' character
-	 * so that "\{" + "\}" pair will not break the "\-" operator.
-	 */
-	if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
-	    *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
-		return false; /* Bad pattern. */
-	do {
-		/* Compare current component with pattern. */
-		if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2,
-						 p_delimiter - 2))
-			break;
-		/* Proceed to next component. */
-		f = f_delimiter;
-		if (!*f)
-			break;
-		f++;
-		/* Continue comparison. */
-		if (tomoyo_path_matches_pattern2(f, p_delimiter + 1))
-			return true;
-		f_delimiter = strchr(f, '/');
-	} while (f_delimiter);
-	return false; /* Not matched. */
-}
-
-/**
- * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
- *
- * @filename: The filename to check.
- * @pattern:  The pattern to compare.
- *
- * Returns true if matches, false otherwise.
- *
- * The following patterns are available.
- *   \\     \ itself.
- *   \ooo   Octal representation of a byte.
- *   \*     Zero or more repetitions of characters other than '/'.
- *   \@     Zero or more repetitions of characters other than '/' or '.'.
- *   \?     1 byte character other than '/'.
- *   \$     One or more repetitions of decimal digits.
- *   \+     1 decimal digit.
- *   \X     One or more repetitions of hexadecimal digits.
- *   \x     1 hexadecimal digit.
- *   \A     One or more repetitions of alphabet characters.
- *   \a     1 alphabet character.
- *
- *   \-     Subtraction operator.
- *
- *   /\{dir\}/   '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
- *               /dir/dir/dir/ ).
- */
-bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
-				 const struct tomoyo_path_info *pattern)
-{
-	const char *f = filename->name;
-	const char *p = pattern->name;
-	const int len = pattern->const_len;
-
-	/* If @pattern doesn't contain pattern, I can use strcmp(). */
-	if (!pattern->is_patterned)
-		return !tomoyo_pathcmp(filename, pattern);
-	/* Don't compare directory and non-directory. */
-	if (filename->is_dir != pattern->is_dir)
-		return false;
-	/* Compare the initial length without patterns. */
-	if (strncmp(f, p, len))
-		return false;
-	f += len;
-	p += len;
-	return tomoyo_path_matches_pattern2(f, p);
-}
-
-/**
- * tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- * @fmt:  The printf()'s format string, followed by parameters.
- *
- * Returns true if output was written, false otherwise.
- *
- * The snprintf() will truncate, but tomoyo_io_printf() won't.
- */
-bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
-{
-	va_list args;
-	int len;
-	int pos = head->read_avail;
-	int size = head->readbuf_size - pos;
-
-	if (size <= 0)
-		return false;
-	va_start(args, fmt);
-	len = vsnprintf(head->read_buf + pos, size, fmt, args);
-	va_end(args);
-	if (pos + len >= head->readbuf_size)
-		return false;
-	head->read_avail += len;
-	return true;
-}
-
-/**
- * tomoyo_get_exe - Get tomoyo_realpath() of current process.
- *
- * Returns the tomoyo_realpath() of current process on success, NULL otherwise.
- *
- * This function uses kzalloc(), so the caller must call kfree()
- * if this function didn't return NULL.
- */
-static const char *tomoyo_get_exe(void)
-{
-	struct mm_struct *mm = current->mm;
-	struct vm_area_struct *vma;
-	const char *cp = NULL;
-
-	if (!mm)
-		return NULL;
-	down_read(&mm->mmap_sem);
-	for (vma = mm->mmap; vma; vma = vma->vm_next) {
-		if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
-			cp = tomoyo_realpath_from_path(&vma->vm_file->f_path);
-			break;
-		}
-	}
-	up_read(&mm->mmap_sem);
-	return cp;
-}
-
-/**
- * tomoyo_get_msg - Get warning message.
- *
- * @is_enforce: Is it enforcing mode?
- *
- * Returns "ERROR" or "WARNING".
- */
-const char *tomoyo_get_msg(const bool is_enforce)
-{
-	if (is_enforce)
-		return "ERROR";
-	else
-		return "WARNING";
-}
-
-/**
- * tomoyo_check_flags - Check mode for specified functionality.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @index:  The functionality to check mode.
- *
- * TOMOYO checks only process context.
- * This code disables TOMOYO's enforcement in case the function is called from
- * interrupt context.
- */
-unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
-				const u8 index)
-{
-	const u8 profile = domain->profile;
-
-	if (WARN_ON(in_interrupt()))
-		return 0;
-	return tomoyo_policy_loaded && index < TOMOYO_MAX_CONTROL_INDEX
-#if TOMOYO_MAX_PROFILES != 256
-		&& profile < TOMOYO_MAX_PROFILES
-#endif
-		&& tomoyo_profile_ptr[profile] ?
-		tomoyo_profile_ptr[profile]->value[index] : 0;
-}
-
-/**
- * tomoyo_verbose_mode - Check whether TOMOYO is verbose mode.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- *
- * Returns true if domain policy violation warning should be printed to
- * console.
- */
-bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain)
-{
-	return tomoyo_check_flags(domain, TOMOYO_VERBOSE) != 0;
-}
-
-/**
- * tomoyo_domain_quota_is_ok - Check for domain's quota.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- *
- * Returns true if the domain is not exceeded quota, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
-{
-	unsigned int count = 0;
-	struct tomoyo_acl_info *ptr;
-
-	if (!domain)
-		return true;
-	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
-		switch (ptr->type) {
-			struct tomoyo_path_acl *acl;
-			u32 perm;
-			u8 i;
-		case TOMOYO_TYPE_PATH_ACL:
-			acl = container_of(ptr, struct tomoyo_path_acl, head);
-			perm = acl->perm | (((u32) acl->perm_high) << 16);
-			for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++)
-				if (perm & (1 << i))
-					count++;
-			if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
-				count -= 2;
-			break;
-		case TOMOYO_TYPE_PATH2_ACL:
-			perm = container_of(ptr, struct tomoyo_path2_acl, head)
-				->perm;
-			for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++)
-				if (perm & (1 << i))
-					count++;
-			break;
-		}
-	}
-	if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
-		return true;
-	if (!domain->quota_warned) {
-		domain->quota_warned = true;
-		printk(KERN_WARNING "TOMOYO-WARNING: "
-		       "Domain '%s' has so many ACLs to hold. "
-		       "Stopped learning mode.\n", domain->domainname->name);
-	}
-	return false;
-}
-
-/**
- * tomoyo_find_or_assign_new_profile - Create a new profile.
+ * tomoyo_assign_profile - Create a new profile.
  *
  * @profile: Profile number to create.
  *
  * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
  */
-static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
-								int profile)
+static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile)
 {
-	struct tomoyo_profile *ptr = NULL;
-	int i;
-
+	struct tomoyo_profile *ptr;
+	struct tomoyo_profile *entry;
 	if (profile >= TOMOYO_MAX_PROFILES)
 		return NULL;
-	if (mutex_lock_interruptible(&tomoyo_policy_lock))
-		return NULL;
 	ptr = tomoyo_profile_ptr[profile];
 	if (ptr)
-		goto ok;
-	ptr = kmalloc(sizeof(*ptr), GFP_NOFS);
-	if (!tomoyo_memory_ok(ptr)) {
-		kfree(ptr);
-		ptr = NULL;
-		goto ok;
+		return ptr;
+	entry = kzalloc(sizeof(*entry), GFP_NOFS);
+	if (mutex_lock_interruptible(&tomoyo_policy_lock))
+		goto out;
+	ptr = tomoyo_profile_ptr[profile];
+	if (!ptr && tomoyo_memory_ok(entry)) {
+		ptr = entry;
+		ptr->learning = &tomoyo_default_profile.preference;
+		ptr->permissive = &tomoyo_default_profile.preference;
+		ptr->enforcing = &tomoyo_default_profile.preference;
+		ptr->default_config = TOMOYO_CONFIG_DISABLED;
+		memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT,
+		       sizeof(ptr->config));
+		mb(); /* Avoid out-of-order execution. */
+		tomoyo_profile_ptr[profile] = ptr;
+		entry = NULL;
 	}
-	for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++)
-		ptr->value[i] = tomoyo_control_array[i].current_value;
-	mb(); /* Avoid out-of-order execution. */
-	tomoyo_profile_ptr[profile] = ptr;
- ok:
 	mutex_unlock(&tomoyo_policy_lock);
+ out:
+	kfree(entry);
 	return ptr;
 }
 
 /**
- * tomoyo_write_profile - Write to profile table.
+ * tomoyo_profile - Find a profile.
+ *
+ * @profile: Profile number to find.
+ *
+ * Returns pointer to "struct tomoyo_profile".
+ */
+struct tomoyo_profile *tomoyo_profile(const u8 profile)
+{
+	struct tomoyo_profile *ptr = tomoyo_profile_ptr[profile];
+	if (!tomoyo_policy_loaded)
+		return &tomoyo_default_profile;
+	BUG_ON(!ptr);
+	return ptr;
+}
+
+static s8 tomoyo_find_yesno(const char *string, const char *find)
+{
+	const char *cp = strstr(string, find);
+	if (cp) {
+		cp += strlen(find);
+		if (!strncmp(cp, "=yes", 4))
+			return 1;
+		else if (!strncmp(cp, "=no", 3))
+			return 0;
+	}
+	return -1;
+}
+
+static void tomoyo_set_bool(bool *b, const char *string, const char *find)
+{
+	switch (tomoyo_find_yesno(string, find)) {
+	case 1:
+		*b = true;
+		break;
+	case 0:
+		*b = false;
+		break;
+	}
+}
+
+static void tomoyo_set_uint(unsigned int *i, const char *string,
+			    const char *find)
+{
+	const char *cp = strstr(string, find);
+	if (cp)
+		sscanf(cp + strlen(find), "=%u", i);
+}
+
+static void tomoyo_set_pref(const char *name, const char *value,
+			    const bool use_default,
+			    struct tomoyo_profile *profile)
+{
+	struct tomoyo_preference **pref;
+	bool *verbose;
+	if (!strcmp(name, "enforcing")) {
+		if (use_default) {
+			pref = &profile->enforcing;
+			goto set_default;
+		}
+		profile->enforcing = &profile->preference;
+		verbose = &profile->preference.enforcing_verbose;
+		goto set_verbose;
+	}
+	if (!strcmp(name, "permissive")) {
+		if (use_default) {
+			pref = &profile->permissive;
+			goto set_default;
+		}
+		profile->permissive = &profile->preference;
+		verbose = &profile->preference.permissive_verbose;
+		goto set_verbose;
+	}
+	if (!strcmp(name, "learning")) {
+		if (use_default) {
+			pref = &profile->learning;
+			goto set_default;
+		}
+		profile->learning = &profile->preference;
+		tomoyo_set_uint(&profile->preference.learning_max_entry, value,
+			     "max_entry");
+		verbose = &profile->preference.learning_verbose;
+		goto set_verbose;
+	}
+	return;
+ set_default:
+	*pref = &tomoyo_default_profile.preference;
+	return;
+ set_verbose:
+	tomoyo_set_bool(verbose, value, "verbose");
+}
+
+static int tomoyo_set_mode(char *name, const char *value,
+			   const bool use_default,
+			   struct tomoyo_profile *profile)
+{
+	u8 i;
+	u8 config;
+	if (!strcmp(name, "CONFIG")) {
+		i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX;
+		config = profile->default_config;
+	} else if (tomoyo_str_starts(&name, "CONFIG::")) {
+		config = 0;
+		for (i = 0; i < TOMOYO_MAX_MAC_INDEX
+			     + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
+			if (strcmp(name, tomoyo_mac_keywords[i]))
+				continue;
+			config = profile->config[i];
+			break;
+		}
+		if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
+			return -EINVAL;
+	} else {
+		return -EINVAL;
+	}
+	if (use_default) {
+		config = TOMOYO_CONFIG_USE_DEFAULT;
+	} else {
+		u8 mode;
+		for (mode = 0; mode < 4; mode++)
+			if (strstr(value, tomoyo_mode[mode]))
+				/*
+				 * Update lower 3 bits in order to distinguish
+				 * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'.
+				 */
+				config = (config & ~7) | mode;
+	}
+	if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
+		profile->config[i] = config;
+	else if (config != TOMOYO_CONFIG_USE_DEFAULT)
+		profile->default_config = config;
+	return 0;
+}
+
+/**
+ * tomoyo_write_profile - Write profile table.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
@@ -980,153 +430,165 @@
 {
 	char *data = head->write_buf;
 	unsigned int i;
-	unsigned int value;
+	bool use_default = false;
 	char *cp;
 	struct tomoyo_profile *profile;
-	unsigned long num;
-
-	cp = strchr(data, '-');
-	if (cp)
-		*cp = '\0';
-	if (strict_strtoul(data, 10, &num))
-		return -EINVAL;
-	if (cp)
+	if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1)
+		return 0;
+	i = simple_strtoul(data, &cp, 10);
+	if (data == cp) {
+		profile = &tomoyo_default_profile;
+	} else {
+		if (*cp != '-')
+			return -EINVAL;
 		data = cp + 1;
-	profile = tomoyo_find_or_assign_new_profile(num);
-	if (!profile)
-		return -EINVAL;
+		profile = tomoyo_assign_profile(i);
+		if (!profile)
+			return -EINVAL;
+	}
 	cp = strchr(data, '=');
 	if (!cp)
 		return -EINVAL;
-	*cp = '\0';
+	*cp++ = '\0';
+	if (profile != &tomoyo_default_profile)
+		use_default = strstr(cp, "use_default") != NULL;
+	if (tomoyo_str_starts(&data, "PREFERENCE::")) {
+		tomoyo_set_pref(data, cp, use_default, profile);
+		return 0;
+	}
+	if (profile == &tomoyo_default_profile)
+		return -EINVAL;
 	if (!strcmp(data, "COMMENT")) {
 		const struct tomoyo_path_info *old_comment = profile->comment;
-		profile->comment = tomoyo_get_name(cp + 1);
+		profile->comment = tomoyo_get_name(cp);
 		tomoyo_put_name(old_comment);
 		return 0;
 	}
-	for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) {
-		if (strcmp(data, tomoyo_control_array[i].keyword))
-			continue;
-		if (sscanf(cp + 1, "%u", &value) != 1) {
-			int j;
-			const char **modes;
-			switch (i) {
-			case TOMOYO_VERBOSE:
-				modes = tomoyo_mode_2;
-				break;
-			default:
-				modes = tomoyo_mode_4;
-				break;
-			}
-			for (j = 0; j < 4; j++) {
-				if (strcmp(cp + 1, modes[j]))
-					continue;
-				value = j;
-				break;
-			}
-			if (j == 4)
-				return -EINVAL;
-		} else if (value > tomoyo_control_array[i].max_value) {
-			value = tomoyo_control_array[i].max_value;
-		}
-		profile->value[i] = value;
-		return 0;
+	return tomoyo_set_mode(data, cp, use_default, profile);
+}
+
+static void tomoyo_print_preference(struct tomoyo_io_buffer *head,
+				    const int idx)
+{
+	struct tomoyo_preference *pref = &tomoyo_default_profile.preference;
+	const struct tomoyo_profile *profile = idx >= 0 ?
+		tomoyo_profile_ptr[idx] : NULL;
+	char buffer[16] = "";
+	if (profile) {
+		buffer[sizeof(buffer) - 1] = '\0';
+		snprintf(buffer, sizeof(buffer) - 1, "%u-", idx);
 	}
-	return -EINVAL;
+	if (profile) {
+		pref = profile->learning;
+		if (pref == &tomoyo_default_profile.preference)
+			goto skip1;
+	}
+	tomoyo_io_printf(head, "%sPREFERENCE::%s={ "
+			 "verbose=%s max_entry=%u }\n",
+			 buffer, "learning",
+			 tomoyo_yesno(pref->learning_verbose),
+			 pref->learning_max_entry);
+ skip1:
+	if (profile) {
+		pref = profile->permissive;
+		if (pref == &tomoyo_default_profile.preference)
+			goto skip2;
+	}
+	tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n",
+			 buffer, "permissive",
+			 tomoyo_yesno(pref->permissive_verbose));
+ skip2:
+	if (profile) {
+		pref = profile->enforcing;
+		if (pref == &tomoyo_default_profile.preference)
+			return;
+	}
+	tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n",
+			 buffer, "enforcing",
+			 tomoyo_yesno(pref->enforcing_verbose));
+}
+
+static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config)
+{
+	tomoyo_io_printf(head, "={ mode=%s }\n", tomoyo_mode[config & 3]);
 }
 
 /**
- * tomoyo_read_profile - Read from profile table.
+ * tomoyo_read_profile - Read profile table.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns 0.
  */
-static int tomoyo_read_profile(struct tomoyo_io_buffer *head)
+static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
 {
-	static const int total = TOMOYO_MAX_CONTROL_INDEX + 1;
-	int step;
-
-	if (head->read_eof)
-		return 0;
-	for (step = head->read_step; step < TOMOYO_MAX_PROFILES * total;
-	     step++) {
-		const u8 index = step / total;
-		u8 type = step % total;
-		const struct tomoyo_profile *profile
-			= tomoyo_profile_ptr[index];
-		head->read_step = step;
-		if (!profile)
-			continue;
-		if (!type) { /* Print profile' comment tag. */
-			if (!tomoyo_io_printf(head, "%u-COMMENT=%s\n",
-					      index, profile->comment ?
-					      profile->comment->name : ""))
+	u8 index;
+	const struct tomoyo_profile *profile;
+ next:
+	index = head->r.index;
+	profile = tomoyo_profile_ptr[index];
+	switch (head->r.step) {
+	case 0:
+		tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903");
+		tomoyo_print_preference(head, -1);
+		head->r.step++;
+		break;
+	case 1:
+		for ( ; head->r.index < TOMOYO_MAX_PROFILES;
+		      head->r.index++)
+			if (tomoyo_profile_ptr[head->r.index])
 				break;
-			continue;
+		if (head->r.index == TOMOYO_MAX_PROFILES)
+			return;
+		head->r.step++;
+		break;
+	case 2:
+		{
+			const struct tomoyo_path_info *comment =
+				profile->comment;
+			tomoyo_io_printf(head, "%u-COMMENT=", index);
+			tomoyo_set_string(head, comment ? comment->name : "");
+			tomoyo_set_lf(head);
+			head->r.step++;
 		}
-		type--;
-		if (type < TOMOYO_MAX_CONTROL_INDEX) {
-			const unsigned int value = profile->value[type];
-			const char **modes = NULL;
-			const char *keyword
-				= tomoyo_control_array[type].keyword;
-			switch (tomoyo_control_array[type].max_value) {
-			case 3:
-				modes = tomoyo_mode_4;
-				break;
-			case 1:
-				modes = tomoyo_mode_2;
-				break;
-			}
-			if (modes) {
-				if (!tomoyo_io_printf(head, "%u-%s=%s\n", index,
-						      keyword, modes[value]))
-					break;
-			} else {
-				if (!tomoyo_io_printf(head, "%u-%s=%u\n", index,
-						      keyword, value))
-					break;
-			}
+		break;
+	case 3:
+		{
+			tomoyo_io_printf(head, "%u-%s", index, "CONFIG");
+			tomoyo_print_config(head, profile->default_config);
+			head->r.bit = 0;
+			head->r.step++;
 		}
+		break;
+	case 4:
+		for ( ; head->r.bit < TOMOYO_MAX_MAC_INDEX
+			      + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
+			const u8 i = head->r.bit;
+			const u8 config = profile->config[i];
+			if (config == TOMOYO_CONFIG_USE_DEFAULT)
+				continue;
+			tomoyo_io_printf(head, "%u-%s%s", index, "CONFIG::",
+					 tomoyo_mac_keywords[i]);
+			tomoyo_print_config(head, config);
+			head->r.bit++;
+			break;
+		}
+		if (head->r.bit == TOMOYO_MAX_MAC_INDEX
+		    + TOMOYO_MAX_MAC_CATEGORY_INDEX) {
+			tomoyo_print_preference(head, index);
+			head->r.index++;
+			head->r.step = 1;
+		}
+		break;
 	}
-	if (step == TOMOYO_MAX_PROFILES * total)
-		head->read_eof = true;
-	return 0;
+	if (tomoyo_flush(head))
+		goto next;
 }
 
-/*
- * tomoyo_policy_manager_list is used for holding list of domainnames or
- * programs which are permitted to modify configuration via
- * /sys/kernel/security/tomoyo/ interface.
- *
- * An entry is added by
- *
- * # echo '<kernel> /sbin/mingetty /bin/login /bin/bash' > \
- *                                        /sys/kernel/security/tomoyo/manager
- *  (if you want to specify by a domainname)
- *
- *  or
- *
- * # echo '/usr/lib/ccs/editpolicy' > /sys/kernel/security/tomoyo/manager
- *  (if you want to specify by a program's location)
- *
- * and is deleted by
- *
- * # echo 'delete <kernel> /sbin/mingetty /bin/login /bin/bash' > \
- *                                        /sys/kernel/security/tomoyo/manager
- *
- *  or
- *
- * # echo 'delete /usr/lib/ccs/editpolicy' > \
- *                                        /sys/kernel/security/tomoyo/manager
- *
- * and all entries are retrieved by
- *
- * # cat /sys/kernel/security/tomoyo/manager
- */
-LIST_HEAD(tomoyo_policy_manager_list);
+static bool tomoyo_same_manager(const struct tomoyo_acl_head *a,
+				const struct tomoyo_acl_head *b)
+{
+	return container_of(a, struct tomoyo_manager, head)->manager ==
+		container_of(b, struct tomoyo_manager, head)->manager;
+}
 
 /**
  * tomoyo_update_manager_entry - Add a manager entry.
@@ -1141,47 +603,29 @@
 static int tomoyo_update_manager_entry(const char *manager,
 				       const bool is_delete)
 {
-	struct tomoyo_policy_manager_entry *ptr;
-	struct tomoyo_policy_manager_entry e = { };
-	int error = is_delete ? -ENOENT : -ENOMEM;
+	struct tomoyo_manager e = { };
+	int error;
 
-	if (tomoyo_is_domain_def(manager)) {
-		if (!tomoyo_is_correct_domain(manager))
+	if (tomoyo_domain_def(manager)) {
+		if (!tomoyo_correct_domain(manager))
 			return -EINVAL;
 		e.is_domain = true;
 	} else {
-		if (!tomoyo_is_correct_path(manager, 1, -1, -1))
+		if (!tomoyo_correct_path(manager))
 			return -EINVAL;
 	}
 	e.manager = tomoyo_get_name(manager);
 	if (!e.manager)
 		return -ENOMEM;
-	if (mutex_lock_interruptible(&tomoyo_policy_lock))
-		goto out;
-	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
-		if (ptr->manager != e.manager)
-			continue;
-		ptr->is_deleted = is_delete;
-		error = 0;
-		break;
-	}
-	if (!is_delete && error) {
-		struct tomoyo_policy_manager_entry *entry =
-			tomoyo_commit_ok(&e, sizeof(e));
-		if (entry) {
-			list_add_tail_rcu(&entry->list,
-					  &tomoyo_policy_manager_list);
-			error = 0;
-		}
-	}
-	mutex_unlock(&tomoyo_policy_lock);
- out:
+	error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+				     &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+				     tomoyo_same_manager);
 	tomoyo_put_name(e.manager);
 	return error;
 }
 
 /**
- * tomoyo_write_manager_policy - Write manager policy.
+ * tomoyo_write_manager - Write manager policy.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
@@ -1189,7 +633,7 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
+static int tomoyo_write_manager(struct tomoyo_io_buffer *head)
 {
 	char *data = head->write_buf;
 	bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
@@ -1202,47 +646,41 @@
 }
 
 /**
- * tomoyo_read_manager_policy - Read manager policy.
+ * tomoyo_read_manager - Read manager policy.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
- * Returns 0.
- *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
+static void tomoyo_read_manager(struct tomoyo_io_buffer *head)
 {
-	struct list_head *pos;
-	bool done = true;
-
-	if (head->read_eof)
-		return 0;
-	list_for_each_cookie(pos, head->read_var2,
-			     &tomoyo_policy_manager_list) {
-		struct tomoyo_policy_manager_entry *ptr;
-		ptr = list_entry(pos, struct tomoyo_policy_manager_entry,
-				 list);
-		if (ptr->is_deleted)
+	if (head->r.eof)
+		return;
+	list_for_each_cookie(head->r.acl,
+			     &tomoyo_policy_list[TOMOYO_ID_MANAGER]) {
+		struct tomoyo_manager *ptr =
+			list_entry(head->r.acl, typeof(*ptr), head.list);
+		if (ptr->head.is_deleted)
 			continue;
-		done = tomoyo_io_printf(head, "%s\n", ptr->manager->name);
-		if (!done)
-			break;
+		if (!tomoyo_flush(head))
+			return;
+		tomoyo_set_string(head, ptr->manager->name);
+		tomoyo_set_lf(head);
 	}
-	head->read_eof = done;
-	return 0;
+	head->r.eof = true;
 }
 
 /**
- * tomoyo_is_policy_manager - Check whether the current process is a policy manager.
+ * tomoyo_manager - Check whether the current process is a policy manager.
  *
  * Returns true if the current process is permitted to modify policy
  * via /sys/kernel/security/tomoyo/ interface.
  *
  * Caller holds tomoyo_read_lock().
  */
-static bool tomoyo_is_policy_manager(void)
+static bool tomoyo_manager(void)
 {
-	struct tomoyo_policy_manager_entry *ptr;
+	struct tomoyo_manager *ptr;
 	const char *exe;
 	const struct task_struct *task = current;
 	const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname;
@@ -1252,8 +690,9 @@
 		return true;
 	if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
 		return false;
-	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
-		if (!ptr->is_deleted && ptr->is_domain
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+				head.list) {
+		if (!ptr->head.is_deleted && ptr->is_domain
 		    && !tomoyo_pathcmp(domainname, ptr->manager)) {
 			found = true;
 			break;
@@ -1264,8 +703,9 @@
 	exe = tomoyo_get_exe();
 	if (!exe)
 		return false;
-	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
-		if (!ptr->is_deleted && !ptr->is_domain
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+				head.list) {
+		if (!ptr->head.is_deleted && !ptr->is_domain
 		    && !strcmp(exe, ptr->manager->name)) {
 			found = true;
 			break;
@@ -1285,7 +725,7 @@
 }
 
 /**
- * tomoyo_is_select_one - Parse select command.
+ * tomoyo_select_one - Parse select command.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  * @data: String to parse.
@@ -1294,23 +734,31 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
-				 const char *data)
+static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data)
 {
 	unsigned int pid;
 	struct tomoyo_domain_info *domain = NULL;
+	bool global_pid = false;
 
-	if (sscanf(data, "pid=%u", &pid) == 1) {
+	if (!strcmp(data, "allow_execute")) {
+		head->r.print_execute_only = true;
+		return true;
+	}
+	if (sscanf(data, "pid=%u", &pid) == 1 ||
+	    (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
 		struct task_struct *p;
 		rcu_read_lock();
 		read_lock(&tasklist_lock);
-		p = find_task_by_vpid(pid);
+		if (global_pid)
+			p = find_task_by_pid_ns(pid, &init_pid_ns);
+		else
+			p = find_task_by_vpid(pid);
 		if (p)
 			domain = tomoyo_real_domain(p);
 		read_unlock(&tasklist_lock);
 		rcu_read_unlock();
 	} else if (!strncmp(data, "domain=", 7)) {
-		if (tomoyo_is_domain_def(data + 7))
+		if (tomoyo_domain_def(data + 7))
 			domain = tomoyo_find_domain(data + 7);
 	} else
 		return false;
@@ -1318,24 +766,13 @@
 	/* Accessing read_buf is safe because head->io_sem is held. */
 	if (!head->read_buf)
 		return true; /* Do nothing if open(O_WRONLY). */
-	head->read_avail = 0;
+	memset(&head->r, 0, sizeof(head->r));
+	head->r.print_this_domain_only = true;
+	head->r.eof = !domain;
+	head->r.domain = &domain->list;
 	tomoyo_io_printf(head, "# select %s\n", data);
-	head->read_single_domain = true;
-	head->read_eof = !domain;
-	if (domain) {
-		struct tomoyo_domain_info *d;
-		head->read_var1 = NULL;
-		list_for_each_entry_rcu(d, &tomoyo_domain_list, list) {
-			if (d == domain)
-				break;
-			head->read_var1 = &d->list;
-		}
-		head->read_var2 = NULL;
-		head->read_bit = 0;
-		head->read_step = 0;
-		if (domain->is_deleted)
-			tomoyo_io_printf(head, "# This is a deleted domain.\n");
-	}
+	if (domain && domain->is_deleted)
+		tomoyo_io_printf(head, "# This is a deleted domain.\n");
 	return true;
 }
 
@@ -1373,7 +810,7 @@
 }
 
 /**
- * tomoyo_write_domain_policy - Write domain policy.
+ * tomoyo_write_domain2 - Write domain policy.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
@@ -1381,7 +818,24 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
+static int tomoyo_write_domain2(char *data, struct tomoyo_domain_info *domain,
+				const bool is_delete)
+{
+	if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_MOUNT))
+		return tomoyo_write_mount(data, domain, is_delete);
+	return tomoyo_write_file(data, domain, is_delete);
+}
+
+/**
+ * tomoyo_write_domain - Write domain policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
 {
 	char *data = head->write_buf;
 	struct tomoyo_domain_info *domain = head->write_var1;
@@ -1393,19 +847,19 @@
 		is_delete = true;
 	else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_SELECT))
 		is_select = true;
-	if (is_select && tomoyo_is_select_one(head, data))
+	if (is_select && tomoyo_select_one(head, data))
 		return 0;
 	/* Don't allow updating policies by non manager programs. */
-	if (!tomoyo_is_policy_manager())
+	if (!tomoyo_manager())
 		return -EPERM;
-	if (tomoyo_is_domain_def(data)) {
+	if (tomoyo_domain_def(data)) {
 		domain = NULL;
 		if (is_delete)
 			tomoyo_delete_domain(data);
 		else if (is_select)
 			domain = tomoyo_find_domain(data);
 		else
-			domain = tomoyo_find_or_assign_new_domain(data, 0);
+			domain = tomoyo_assign_domain(data, 0);
 		head->write_var1 = domain;
 		return 0;
 	}
@@ -1422,179 +876,198 @@
 		domain->ignore_global_allow_read = !is_delete;
 		return 0;
 	}
-	return tomoyo_write_file_policy(data, domain, is_delete);
+	if (!strcmp(data, TOMOYO_KEYWORD_QUOTA_EXCEEDED)) {
+		domain->quota_warned = !is_delete;
+		return 0;
+	}
+	if (!strcmp(data, TOMOYO_KEYWORD_TRANSITION_FAILED)) {
+		domain->transition_failed = !is_delete;
+		return 0;
+	}
+	return tomoyo_write_domain2(data, domain, is_delete);
 }
 
 /**
- * tomoyo_print_path_acl - Print a single path ACL entry.
+ * tomoyo_fns - Find next set bit.
  *
- * @head: Pointer to "struct tomoyo_io_buffer".
- * @ptr:  Pointer to "struct tomoyo_path_acl".
+ * @perm: 8 bits value.
+ * @bit:  First bit to find.
  *
- * Returns true on success, false otherwise.
+ * Returns next on-bit on success, 8 otherwise.
  */
-static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head,
-				  struct tomoyo_path_acl *ptr)
+static u8 tomoyo_fns(const u8 perm, u8 bit)
 {
-	int pos;
-	u8 bit;
-	const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16);
-
-	for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
-		if (!(perm & (1 << bit)))
-			continue;
-		/* Print "read/write" instead of "read" and "write". */
-		if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE)
-		    && (perm & (1 << TOMOYO_TYPE_READ_WRITE)))
-			continue;
-		pos = head->read_avail;
-		if (!tomoyo_io_printf(head, "allow_%s ",
-				      tomoyo_path2keyword(bit)) ||
-		    !tomoyo_print_name_union(head, &ptr->name) ||
-		    !tomoyo_io_printf(head, "\n"))
-			goto out;
-	}
-	head->read_bit = 0;
-	return true;
- out:
-	head->read_bit = bit;
-	head->read_avail = pos;
-	return false;
-}
-
-/**
- * tomoyo_print_path2_acl - Print a double path ACL entry.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- * @ptr:  Pointer to "struct tomoyo_path2_acl".
- *
- * Returns true on success, false otherwise.
- */
-static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head,
-				   struct tomoyo_path2_acl *ptr)
-{
-	int pos;
-	const u8 perm = ptr->perm;
-	u8 bit;
-
-	for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) {
-		if (!(perm & (1 << bit)))
-			continue;
-		pos = head->read_avail;
-		if (!tomoyo_io_printf(head, "allow_%s ",
-				      tomoyo_path22keyword(bit)) ||
-		    !tomoyo_print_name_union(head, &ptr->name1) ||
-		    !tomoyo_print_name_union(head, &ptr->name2) ||
-		    !tomoyo_io_printf(head, "\n"))
-			goto out;
-	}
-	head->read_bit = 0;
-	return true;
- out:
-	head->read_bit = bit;
-	head->read_avail = pos;
-	return false;
+	for ( ; bit < 8; bit++)
+		if (perm & (1 << bit))
+			break;
+	return bit;
 }
 
 /**
  * tomoyo_print_entry - Print an ACL entry.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
- * @ptr:  Pointer to an ACL entry.
+ * @acl:  Pointer to an ACL entry.
  *
  * Returns true on success, false otherwise.
  */
 static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
-			       struct tomoyo_acl_info *ptr)
+			       struct tomoyo_acl_info *acl)
 {
-	const u8 acl_type = ptr->type;
+	const u8 acl_type = acl->type;
+	u8 bit;
 
-	if (acl_type == TOMOYO_TYPE_PATH_ACL) {
-		struct tomoyo_path_acl *acl
-			= container_of(ptr, struct tomoyo_path_acl, head);
-		return tomoyo_print_path_acl(head, acl);
+	if (acl->is_deleted)
+		return true;
+ next:
+	bit = head->r.bit;
+	if (!tomoyo_flush(head))
+		return false;
+	else if (acl_type == TOMOYO_TYPE_PATH_ACL) {
+		struct tomoyo_path_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+		const u16 perm = ptr->perm;
+		for ( ; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
+			if (!(perm & (1 << bit)))
+				continue;
+			if (head->r.print_execute_only &&
+			    bit != TOMOYO_TYPE_EXECUTE)
+				continue;
+			/* Print "read/write" instead of "read" and "write". */
+			if ((bit == TOMOYO_TYPE_READ ||
+			     bit == TOMOYO_TYPE_WRITE)
+			    && (perm & (1 << TOMOYO_TYPE_READ_WRITE)))
+				continue;
+			break;
+		}
+		if (bit >= TOMOYO_MAX_PATH_OPERATION)
+			goto done;
+		tomoyo_io_printf(head, "allow_%s", tomoyo_path_keyword[bit]);
+		tomoyo_print_name_union(head, &ptr->name);
+	} else if (head->r.print_execute_only) {
+		return true;
+	} else if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
+		struct tomoyo_path2_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+		bit = tomoyo_fns(ptr->perm, bit);
+		if (bit >= TOMOYO_MAX_PATH2_OPERATION)
+			goto done;
+		tomoyo_io_printf(head, "allow_%s", tomoyo_path2_keyword[bit]);
+		tomoyo_print_name_union(head, &ptr->name1);
+		tomoyo_print_name_union(head, &ptr->name2);
+	} else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) {
+		struct tomoyo_path_number_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+		bit = tomoyo_fns(ptr->perm, bit);
+		if (bit >= TOMOYO_MAX_PATH_NUMBER_OPERATION)
+			goto done;
+		tomoyo_io_printf(head, "allow_%s",
+				 tomoyo_path_number_keyword[bit]);
+		tomoyo_print_name_union(head, &ptr->name);
+		tomoyo_print_number_union(head, &ptr->number);
+	} else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) {
+		struct tomoyo_mkdev_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+		bit = tomoyo_fns(ptr->perm, bit);
+		if (bit >= TOMOYO_MAX_MKDEV_OPERATION)
+			goto done;
+		tomoyo_io_printf(head, "allow_%s", tomoyo_mkdev_keyword[bit]);
+		tomoyo_print_name_union(head, &ptr->name);
+		tomoyo_print_number_union(head, &ptr->mode);
+		tomoyo_print_number_union(head, &ptr->major);
+		tomoyo_print_number_union(head, &ptr->minor);
+	} else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
+		struct tomoyo_mount_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+		tomoyo_io_printf(head, "allow_mount");
+		tomoyo_print_name_union(head, &ptr->dev_name);
+		tomoyo_print_name_union(head, &ptr->dir_name);
+		tomoyo_print_name_union(head, &ptr->fs_type);
+		tomoyo_print_number_union(head, &ptr->flags);
 	}
-	if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
-		struct tomoyo_path2_acl *acl
-			= container_of(ptr, struct tomoyo_path2_acl, head);
-		return tomoyo_print_path2_acl(head, acl);
-	}
-	BUG(); /* This must not happen. */
-	return false;
+	head->r.bit = bit + 1;
+	tomoyo_io_printf(head, "\n");
+	if (acl_type != TOMOYO_TYPE_MOUNT_ACL)
+		goto next;
+ done:
+	head->r.bit = 0;
+	return true;
 }
 
 /**
- * tomoyo_read_domain_policy - Read domain policy.
+ * tomoyo_read_domain2 - Read domain policy.
+ *
+ * @head:   Pointer to "struct tomoyo_io_buffer".
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ *
+ * Caller holds tomoyo_read_lock().
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head,
+				struct tomoyo_domain_info *domain)
+{
+	list_for_each_cookie(head->r.acl, &domain->acl_info_list) {
+		struct tomoyo_acl_info *ptr =
+			list_entry(head->r.acl, typeof(*ptr), list);
+		if (!tomoyo_print_entry(head, ptr))
+			return false;
+	}
+	head->r.acl = NULL;
+	return true;
+}
+
+/**
+ * tomoyo_read_domain - Read domain policy.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
- * Returns 0.
- *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
+static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
 {
-	struct list_head *dpos;
-	struct list_head *apos;
-	bool done = true;
-
-	if (head->read_eof)
-		return 0;
-	if (head->read_step == 0)
-		head->read_step = 1;
-	list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) {
-		struct tomoyo_domain_info *domain;
-		const char *quota_exceeded = "";
-		const char *transition_failed = "";
-		const char *ignore_global_allow_read = "";
-		domain = list_entry(dpos, struct tomoyo_domain_info, list);
-		if (head->read_step != 1)
-			goto acl_loop;
-		if (domain->is_deleted && !head->read_single_domain)
-			continue;
-		/* Print domainname and flags. */
-		if (domain->quota_warned)
-			quota_exceeded = "quota_exceeded\n";
-		if (domain->transition_failed)
-			transition_failed = "transition_failed\n";
-		if (domain->ignore_global_allow_read)
-			ignore_global_allow_read
-				= TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n";
-		done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE
-					"%u\n%s%s%s\n",
-					domain->domainname->name,
-					domain->profile, quota_exceeded,
-					transition_failed,
-					ignore_global_allow_read);
-		if (!done)
-			break;
-		head->read_step = 2;
-acl_loop:
-		if (head->read_step == 3)
-			goto tail_mark;
-		/* Print ACL entries in the domain. */
-		list_for_each_cookie(apos, head->read_var2,
-				     &domain->acl_info_list) {
-			struct tomoyo_acl_info *ptr
-				= list_entry(apos, struct tomoyo_acl_info,
-					     list);
-			done = tomoyo_print_entry(head, ptr);
-			if (!done)
-				break;
+	if (head->r.eof)
+		return;
+	list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
+		struct tomoyo_domain_info *domain =
+			list_entry(head->r.domain, typeof(*domain), list);
+		switch (head->r.step) {
+		case 0:
+			if (domain->is_deleted &&
+			    !head->r.print_this_domain_only)
+				continue;
+			/* Print domainname and flags. */
+			tomoyo_set_string(head, domain->domainname->name);
+			tomoyo_set_lf(head);
+			tomoyo_io_printf(head,
+					 TOMOYO_KEYWORD_USE_PROFILE "%u\n",
+					 domain->profile);
+			if (domain->quota_warned)
+				tomoyo_set_string(head, "quota_exceeded\n");
+			if (domain->transition_failed)
+				tomoyo_set_string(head, "transition_failed\n");
+			if (domain->ignore_global_allow_read)
+				tomoyo_set_string(head,
+				       TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ
+						  "\n");
+			head->r.step++;
+			tomoyo_set_lf(head);
+			/* fall through */
+		case 1:
+			if (!tomoyo_read_domain2(head, domain))
+				return;
+			head->r.step++;
+			if (!tomoyo_set_lf(head))
+				return;
+			/* fall through */
+		case 2:
+			head->r.step = 0;
+			if (head->r.print_this_domain_only)
+				goto done;
 		}
-		if (!done)
-			break;
-		head->read_step = 3;
-tail_mark:
-		done = tomoyo_io_printf(head, "\n");
-		if (!done)
-			break;
-		head->read_step = 1;
-		if (head->read_single_domain)
-			break;
 	}
-	head->read_eof = done;
-	return 0;
+ done:
+	head->r.eof = true;
 }
 
 /**
@@ -1607,7 +1080,7 @@
  * This is equivalent to doing
  *
  *     ( echo "select " $domainname; echo "use_profile " $profile ) |
- *     /usr/lib/ccs/loadpolicy -d
+ *     /usr/sbin/tomoyo-loadpolicy -d
  *
  * Caller holds tomoyo_read_lock().
  */
@@ -1646,25 +1119,22 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
+static void tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
 {
-	struct list_head *pos;
-	bool done = true;
-
-	if (head->read_eof)
-		return 0;
-	list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
-		struct tomoyo_domain_info *domain;
-		domain = list_entry(pos, struct tomoyo_domain_info, list);
+	if (head->r.eof)
+		return;
+	list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
+		struct tomoyo_domain_info *domain =
+			list_entry(head->r.domain, typeof(*domain), list);
 		if (domain->is_deleted)
 			continue;
-		done = tomoyo_io_printf(head, "%u %s\n", domain->profile,
-					domain->domainname->name);
-		if (!done)
-			break;
+		if (!tomoyo_flush(head))
+			return;
+		tomoyo_io_printf(head, "%u ", domain->profile);
+		tomoyo_set_string(head, domain->domainname->name);
+		tomoyo_set_lf(head);
 	}
-	head->read_eof = done;
-	return 0;
+	head->r.eof = true;
 }
 
 /**
@@ -1676,11 +1146,7 @@
  */
 static int tomoyo_write_pid(struct tomoyo_io_buffer *head)
 {
-	unsigned long pid;
-	/* No error check. */
-	strict_strtoul(head->write_buf, 10, &pid);
-	head->read_step = (int) pid;
-	head->read_eof = false;
+	head->r.eof = false;
 	return 0;
 }
 
@@ -1694,29 +1160,57 @@
  * The PID is specified by tomoyo_write_pid() so that the user can obtain
  * using read()/write() interface rather than sysctl() interface.
  */
-static int tomoyo_read_pid(struct tomoyo_io_buffer *head)
+static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
 {
-	if (head->read_avail == 0 && !head->read_eof) {
-		const int pid = head->read_step;
-		struct task_struct *p;
-		struct tomoyo_domain_info *domain = NULL;
-		rcu_read_lock();
-		read_lock(&tasklist_lock);
-		p = find_task_by_vpid(pid);
-		if (p)
-			domain = tomoyo_real_domain(p);
-		read_unlock(&tasklist_lock);
-		rcu_read_unlock();
-		if (domain)
-			tomoyo_io_printf(head, "%d %u %s", pid, domain->profile,
-					 domain->domainname->name);
-		head->read_eof = true;
+	char *buf = head->write_buf;
+	bool global_pid = false;
+	unsigned int pid;
+	struct task_struct *p;
+	struct tomoyo_domain_info *domain = NULL;
+
+	/* Accessing write_buf is safe because head->io_sem is held. */
+	if (!buf) {
+		head->r.eof = true;
+		return; /* Do nothing if open(O_RDONLY). */
 	}
-	return 0;
+	if (head->r.w_pos || head->r.eof)
+		return;
+	head->r.eof = true;
+	if (tomoyo_str_starts(&buf, "global-pid "))
+		global_pid = true;
+	pid = (unsigned int) simple_strtoul(buf, NULL, 10);
+	rcu_read_lock();
+	read_lock(&tasklist_lock);
+	if (global_pid)
+		p = find_task_by_pid_ns(pid, &init_pid_ns);
+	else
+		p = find_task_by_vpid(pid);
+	if (p)
+		domain = tomoyo_real_domain(p);
+	read_unlock(&tasklist_lock);
+	rcu_read_unlock();
+	if (!domain)
+		return;
+	tomoyo_io_printf(head, "%u %u ", pid, domain->profile);
+	tomoyo_set_string(head, domain->domainname->name);
 }
 
+static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
+	[TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE]
+	= TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN,
+	[TOMOYO_TRANSITION_CONTROL_INITIALIZE]
+	= TOMOYO_KEYWORD_INITIALIZE_DOMAIN,
+	[TOMOYO_TRANSITION_CONTROL_NO_KEEP] = TOMOYO_KEYWORD_NO_KEEP_DOMAIN,
+	[TOMOYO_TRANSITION_CONTROL_KEEP] = TOMOYO_KEYWORD_KEEP_DOMAIN
+};
+
+static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
+	[TOMOYO_PATH_GROUP] = TOMOYO_KEYWORD_PATH_GROUP,
+	[TOMOYO_NUMBER_GROUP] = TOMOYO_KEYWORD_NUMBER_GROUP
+};
+
 /**
- * tomoyo_write_exception_policy - Write exception policy.
+ * tomoyo_write_exception - Write exception policy.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
@@ -1724,186 +1218,523 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
+static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
 {
 	char *data = head->write_buf;
 	bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
+	u8 i;
+	static const struct {
+		const char *keyword;
+		int (*write) (char *, const bool);
+	} tomoyo_callback[4] = {
+		{ TOMOYO_KEYWORD_AGGREGATOR, tomoyo_write_aggregator },
+		{ TOMOYO_KEYWORD_FILE_PATTERN, tomoyo_write_pattern },
+		{ TOMOYO_KEYWORD_DENY_REWRITE, tomoyo_write_no_rewrite },
+		{ TOMOYO_KEYWORD_ALLOW_READ, tomoyo_write_globally_readable },
+	};
 
-	if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_KEEP_DOMAIN))
-		return tomoyo_write_domain_keeper_policy(data, false,
-							 is_delete);
-	if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_KEEP_DOMAIN))
-		return tomoyo_write_domain_keeper_policy(data, true, is_delete);
-	if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_INITIALIZE_DOMAIN))
-		return tomoyo_write_domain_initializer_policy(data, false,
-							      is_delete);
-	if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN))
-		return tomoyo_write_domain_initializer_policy(data, true,
-							      is_delete);
-	if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS))
-		return tomoyo_write_alias_policy(data, is_delete);
-	if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ))
-		return tomoyo_write_globally_readable_policy(data, is_delete);
-	if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_FILE_PATTERN))
-		return tomoyo_write_pattern_policy(data, is_delete);
-	if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE))
-		return tomoyo_write_no_rewrite_policy(data, is_delete);
-	if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_PATH_GROUP))
-		return tomoyo_write_path_group_policy(data, is_delete);
+	for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
+		if (tomoyo_str_starts(&data, tomoyo_transition_type[i]))
+			return tomoyo_write_transition_control(data, is_delete,
+							       i);
+	for (i = 0; i < 4; i++)
+		if (tomoyo_str_starts(&data, tomoyo_callback[i].keyword))
+			return tomoyo_callback[i].write(data, is_delete);
+	for (i = 0; i < TOMOYO_MAX_GROUP; i++)
+		if (tomoyo_str_starts(&data, tomoyo_group_name[i]))
+			return tomoyo_write_group(data, is_delete, i);
 	return -EINVAL;
 }
 
 /**
- * tomoyo_read_exception_policy - Read exception policy.
+ * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
+ * @idx:  Index number.
  *
- * Returns 0 on success, -EINVAL otherwise.
+ * Returns true on success, false otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
+static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
 {
-	if (!head->read_eof) {
-		switch (head->read_step) {
-		case 0:
-			head->read_var2 = NULL;
-			head->read_step = 1;
-		case 1:
-			if (!tomoyo_read_domain_keeper_policy(head))
-				break;
-			head->read_var2 = NULL;
-			head->read_step = 2;
-		case 2:
-			if (!tomoyo_read_globally_readable_policy(head))
-				break;
-			head->read_var2 = NULL;
-			head->read_step = 3;
-		case 3:
-			head->read_var2 = NULL;
-			head->read_step = 4;
-		case 4:
-			if (!tomoyo_read_domain_initializer_policy(head))
-				break;
-			head->read_var2 = NULL;
-			head->read_step = 5;
-		case 5:
-			if (!tomoyo_read_alias_policy(head))
-				break;
-			head->read_var2 = NULL;
-			head->read_step = 6;
-		case 6:
-			head->read_var2 = NULL;
-			head->read_step = 7;
-		case 7:
-			if (!tomoyo_read_file_pattern(head))
-				break;
-			head->read_var2 = NULL;
-			head->read_step = 8;
-		case 8:
-			if (!tomoyo_read_no_rewrite_policy(head))
-				break;
-			head->read_var2 = NULL;
-			head->read_step = 9;
-		case 9:
-			if (!tomoyo_read_path_group_policy(head))
-				break;
-			head->read_var1 = NULL;
-			head->read_var2 = NULL;
-			head->read_step = 10;
-		case 10:
-			head->read_eof = true;
-			break;
-		default:
-			return -EINVAL;
+	list_for_each_cookie(head->r.group, &tomoyo_group_list[idx]) {
+		struct tomoyo_group *group =
+			list_entry(head->r.group, typeof(*group), list);
+		list_for_each_cookie(head->r.acl, &group->member_list) {
+			struct tomoyo_acl_head *ptr =
+				list_entry(head->r.acl, typeof(*ptr), list);
+			if (ptr->is_deleted)
+				continue;
+			if (!tomoyo_flush(head))
+				return false;
+			tomoyo_set_string(head, tomoyo_group_name[idx]);
+			tomoyo_set_string(head, group->group_name->name);
+			if (idx == TOMOYO_PATH_GROUP) {
+				tomoyo_set_space(head);
+				tomoyo_set_string(head, container_of
+					       (ptr, struct tomoyo_path_group,
+						head)->member_name->name);
+			} else if (idx == TOMOYO_NUMBER_GROUP) {
+				tomoyo_print_number_union(head, &container_of
+							  (ptr,
+						   struct tomoyo_number_group,
+							   head)->number);
+			}
+			tomoyo_set_lf(head);
 		}
+		head->r.acl = NULL;
 	}
-	return 0;
-}
-
-/* path to policy loader */
-static const char *tomoyo_loader = "/sbin/tomoyo-init";
-
-/**
- * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists.
- *
- * Returns true if /sbin/tomoyo-init exists, false otherwise.
- */
-static bool tomoyo_policy_loader_exists(void)
-{
-	/*
-	 * Don't activate MAC if the policy loader doesn't exist.
-	 * If the initrd includes /sbin/init but real-root-dev has not
-	 * mounted on / yet, activating MAC will block the system since
-	 * policies are not loaded yet.
-	 * Thus, let do_execve() call this function everytime.
-	 */
-	struct path path;
-
-	if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) {
-		printk(KERN_INFO "Not activating Mandatory Access Control now "
-		       "since %s doesn't exist.\n", tomoyo_loader);
-		return false;
-	}
-	path_put(&path);
+	head->r.group = NULL;
 	return true;
 }
 
 /**
- * tomoyo_load_policy - Run external policy loader to load policy.
+ * tomoyo_read_policy - Read "struct tomoyo_..._entry" list.
  *
- * @filename: The program about to start.
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @idx:  Index number.
  *
- * This function checks whether @filename is /sbin/init , and if so
- * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init
- * and then continues invocation of /sbin/init.
- * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and
- * writes to /sys/kernel/security/tomoyo/ interfaces.
+ * Returns true on success, false otherwise.
  *
- * Returns nothing.
+ * Caller holds tomoyo_read_lock().
  */
-void tomoyo_load_policy(const char *filename)
+static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
 {
-	char *argv[2];
-	char *envp[3];
-
-	if (tomoyo_policy_loaded)
-		return;
-	/*
-	 * Check filename is /sbin/init or /sbin/tomoyo-start.
-	 * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't
-	 * be passed.
-	 * You can create /sbin/tomoyo-start by
-	 * "ln -s /bin/true /sbin/tomoyo-start".
-	 */
-	if (strcmp(filename, "/sbin/init") &&
-	    strcmp(filename, "/sbin/tomoyo-start"))
-		return;
-	if (!tomoyo_policy_loader_exists())
-		return;
-
-	printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
-	       tomoyo_loader);
-	argv[0] = (char *) tomoyo_loader;
-	argv[1] = NULL;
-	envp[0] = "HOME=/";
-	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-	envp[2] = NULL;
-	call_usermodehelper(argv[0], argv, envp, 1);
-
-	printk(KERN_INFO "TOMOYO: 2.2.0   2009/04/01\n");
-	printk(KERN_INFO "Mandatory Access Control activated.\n");
-	tomoyo_policy_loaded = true;
-	{ /* Check all profiles currently assigned to domains are defined. */
-		struct tomoyo_domain_info *domain;
-		list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
-			const u8 profile = domain->profile;
-			if (tomoyo_profile_ptr[profile])
-				continue;
-			panic("Profile %u (used by '%s') not defined.\n",
-			      profile, domain->domainname->name);
+	list_for_each_cookie(head->r.acl, &tomoyo_policy_list[idx]) {
+		struct tomoyo_acl_head *acl =
+			container_of(head->r.acl, typeof(*acl), list);
+		if (acl->is_deleted)
+			continue;
+		if (!tomoyo_flush(head))
+			return false;
+		switch (idx) {
+		case TOMOYO_ID_TRANSITION_CONTROL:
+			{
+				struct tomoyo_transition_control *ptr =
+					container_of(acl, typeof(*ptr), head);
+				tomoyo_set_string(head,
+						  tomoyo_transition_type
+						  [ptr->type]);
+				if (ptr->program)
+					tomoyo_set_string(head,
+							  ptr->program->name);
+				if (ptr->program && ptr->domainname)
+					tomoyo_set_string(head, " from ");
+				if (ptr->domainname)
+					tomoyo_set_string(head,
+							  ptr->domainname->
+							  name);
+			}
+			break;
+		case TOMOYO_ID_GLOBALLY_READABLE:
+			{
+				struct tomoyo_readable_file *ptr =
+					container_of(acl, typeof(*ptr), head);
+				tomoyo_set_string(head,
+						  TOMOYO_KEYWORD_ALLOW_READ);
+				tomoyo_set_string(head, ptr->filename->name);
+			}
+			break;
+		case TOMOYO_ID_AGGREGATOR:
+			{
+				struct tomoyo_aggregator *ptr =
+					container_of(acl, typeof(*ptr), head);
+				tomoyo_set_string(head,
+						  TOMOYO_KEYWORD_AGGREGATOR);
+				tomoyo_set_string(head,
+						  ptr->original_name->name);
+				tomoyo_set_space(head);
+				tomoyo_set_string(head,
+					       ptr->aggregated_name->name);
+			}
+			break;
+		case TOMOYO_ID_PATTERN:
+			{
+				struct tomoyo_no_pattern *ptr =
+					container_of(acl, typeof(*ptr), head);
+				tomoyo_set_string(head,
+						  TOMOYO_KEYWORD_FILE_PATTERN);
+				tomoyo_set_string(head, ptr->pattern->name);
+			}
+			break;
+		case TOMOYO_ID_NO_REWRITE:
+			{
+				struct tomoyo_no_rewrite *ptr =
+					container_of(acl, typeof(*ptr), head);
+				tomoyo_set_string(head,
+						  TOMOYO_KEYWORD_DENY_REWRITE);
+				tomoyo_set_string(head, ptr->pattern->name);
+			}
+			break;
+		default:
+			continue;
 		}
+		tomoyo_set_lf(head);
 	}
+	head->r.acl = NULL;
+	return true;
+}
+
+/**
+ * tomoyo_read_exception - Read exception policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
+{
+	if (head->r.eof)
+		return;
+	while (head->r.step < TOMOYO_MAX_POLICY &&
+	       tomoyo_read_policy(head, head->r.step))
+		head->r.step++;
+	if (head->r.step < TOMOYO_MAX_POLICY)
+		return;
+	while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP &&
+	       tomoyo_read_group(head, head->r.step - TOMOYO_MAX_POLICY))
+		head->r.step++;
+	if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP)
+		return;
+	head->r.eof = true;
+}
+
+/**
+ * tomoyo_print_header - Get header line of audit log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns string representation.
+ *
+ * This function uses kmalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+static char *tomoyo_print_header(struct tomoyo_request_info *r)
+{
+	struct timeval tv;
+	const pid_t gpid = task_pid_nr(current);
+	static const int tomoyo_buffer_len = 4096;
+	char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
+	if (!buffer)
+		return NULL;
+	do_gettimeofday(&tv);
+	snprintf(buffer, tomoyo_buffer_len - 1,
+		 "#timestamp=%lu profile=%u mode=%s (global-pid=%u)"
+		 " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u"
+		 " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }",
+		 tv.tv_sec, r->profile, tomoyo_mode[r->mode], gpid,
+		 (pid_t) sys_getpid(), (pid_t) sys_getppid(),
+		 current_uid(), current_gid(), current_euid(),
+		 current_egid(), current_suid(), current_sgid(),
+		 current_fsuid(), current_fsgid());
+	return buffer;
+}
+
+/**
+ * tomoyo_init_audit_log - Allocate buffer for audit logs.
+ *
+ * @len: Required size.
+ * @r:   Pointer to "struct tomoyo_request_info".
+ *
+ * Returns pointer to allocated memory.
+ *
+ * The @len is updated to add the header lines' size on success.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+static char *tomoyo_init_audit_log(int *len, struct tomoyo_request_info *r)
+{
+	char *buf = NULL;
+	const char *header;
+	const char *domainname;
+	if (!r->domain)
+		r->domain = tomoyo_domain();
+	domainname = r->domain->domainname->name;
+	header = tomoyo_print_header(r);
+	if (!header)
+		return NULL;
+	*len += strlen(domainname) + strlen(header) + 10;
+	buf = kzalloc(*len, GFP_NOFS);
+	if (buf)
+		snprintf(buf, (*len) - 1, "%s\n%s\n", header, domainname);
+	kfree(header);
+	return buf;
+}
+
+/* Wait queue for tomoyo_query_list. */
+static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait);
+
+/* Lock for manipulating tomoyo_query_list. */
+static DEFINE_SPINLOCK(tomoyo_query_list_lock);
+
+/* Structure for query. */
+struct tomoyo_query {
+	struct list_head list;
+	char *query;
+	int query_len;
+	unsigned int serial;
+	int timer;
+	int answer;
+};
+
+/* The list for "struct tomoyo_query". */
+static LIST_HEAD(tomoyo_query_list);
+
+/*
+ * Number of "struct file" referring /sys/kernel/security/tomoyo/query
+ * interface.
+ */
+static atomic_t tomoyo_query_observers = ATOMIC_INIT(0);
+
+/**
+ * tomoyo_supervisor - Ask for the supervisor's decision.
+ *
+ * @r:       Pointer to "struct tomoyo_request_info".
+ * @fmt:     The printf()'s format string, followed by parameters.
+ *
+ * Returns 0 if the supervisor decided to permit the access request which
+ * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the
+ * supervisor decided to retry the access request which violated the policy in
+ * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise.
+ */
+int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
+{
+	va_list args;
+	int error = -EPERM;
+	int pos;
+	int len;
+	static unsigned int tomoyo_serial;
+	struct tomoyo_query *entry = NULL;
+	bool quota_exceeded = false;
+	char *header;
+	switch (r->mode) {
+		char *buffer;
+	case TOMOYO_CONFIG_LEARNING:
+		if (!tomoyo_domain_quota_is_ok(r))
+			return 0;
+		va_start(args, fmt);
+		len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 4;
+		va_end(args);
+		buffer = kmalloc(len, GFP_NOFS);
+		if (!buffer)
+			return 0;
+		va_start(args, fmt);
+		vsnprintf(buffer, len - 1, fmt, args);
+		va_end(args);
+		tomoyo_normalize_line(buffer);
+		tomoyo_write_domain2(buffer, r->domain, false);
+		kfree(buffer);
+		/* fall through */
+	case TOMOYO_CONFIG_PERMISSIVE:
+		return 0;
+	}
+	if (!r->domain)
+		r->domain = tomoyo_domain();
+	if (!atomic_read(&tomoyo_query_observers))
+		return -EPERM;
+	va_start(args, fmt);
+	len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;
+	va_end(args);
+	header = tomoyo_init_audit_log(&len, r);
+	if (!header)
+		goto out;
+	entry = kzalloc(sizeof(*entry), GFP_NOFS);
+	if (!entry)
+		goto out;
+	entry->query = kzalloc(len, GFP_NOFS);
+	if (!entry->query)
+		goto out;
+	len = ksize(entry->query);
+	spin_lock(&tomoyo_query_list_lock);
+	if (tomoyo_quota_for_query && tomoyo_query_memory_size + len +
+	    sizeof(*entry) >= tomoyo_quota_for_query) {
+		quota_exceeded = true;
+	} else {
+		tomoyo_query_memory_size += len + sizeof(*entry);
+		entry->serial = tomoyo_serial++;
+	}
+	spin_unlock(&tomoyo_query_list_lock);
+	if (quota_exceeded)
+		goto out;
+	pos = snprintf(entry->query, len - 1, "Q%u-%hu\n%s",
+		       entry->serial, r->retry, header);
+	kfree(header);
+	header = NULL;
+	va_start(args, fmt);
+	vsnprintf(entry->query + pos, len - 1 - pos, fmt, args);
+	entry->query_len = strlen(entry->query) + 1;
+	va_end(args);
+	spin_lock(&tomoyo_query_list_lock);
+	list_add_tail(&entry->list, &tomoyo_query_list);
+	spin_unlock(&tomoyo_query_list_lock);
+	/* Give 10 seconds for supervisor's opinion. */
+	for (entry->timer = 0;
+	     atomic_read(&tomoyo_query_observers) && entry->timer < 100;
+	     entry->timer++) {
+		wake_up(&tomoyo_query_wait);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ / 10);
+		if (entry->answer)
+			break;
+	}
+	spin_lock(&tomoyo_query_list_lock);
+	list_del(&entry->list);
+	tomoyo_query_memory_size -= len + sizeof(*entry);
+	spin_unlock(&tomoyo_query_list_lock);
+	switch (entry->answer) {
+	case 3: /* Asked to retry by administrator. */
+		error = TOMOYO_RETRY_REQUEST;
+		r->retry++;
+		break;
+	case 1:
+		/* Granted by administrator. */
+		error = 0;
+		break;
+	case 0:
+		/* Timed out. */
+		break;
+	default:
+		/* Rejected by administrator. */
+		break;
+	}
+ out:
+	if (entry)
+		kfree(entry->query);
+	kfree(entry);
+	kfree(header);
+	return error;
+}
+
+/**
+ * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query.
+ *
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table".
+ *
+ * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise.
+ *
+ * Waits for access requests which violated policy in enforcing mode.
+ */
+static int tomoyo_poll_query(struct file *file, poll_table *wait)
+{
+	struct list_head *tmp;
+	bool found = false;
+	u8 i;
+	for (i = 0; i < 2; i++) {
+		spin_lock(&tomoyo_query_list_lock);
+		list_for_each(tmp, &tomoyo_query_list) {
+			struct tomoyo_query *ptr =
+				list_entry(tmp, typeof(*ptr), list);
+			if (ptr->answer)
+				continue;
+			found = true;
+			break;
+		}
+		spin_unlock(&tomoyo_query_list_lock);
+		if (found)
+			return POLLIN | POLLRDNORM;
+		if (i)
+			break;
+		poll_wait(file, &tomoyo_query_wait, wait);
+	}
+	return 0;
+}
+
+/**
+ * tomoyo_read_query - Read access requests which violated policy in enforcing mode.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ */
+static void tomoyo_read_query(struct tomoyo_io_buffer *head)
+{
+	struct list_head *tmp;
+	int pos = 0;
+	int len = 0;
+	char *buf;
+	if (head->r.w_pos)
+		return;
+	if (head->read_buf) {
+		kfree(head->read_buf);
+		head->read_buf = NULL;
+	}
+	spin_lock(&tomoyo_query_list_lock);
+	list_for_each(tmp, &tomoyo_query_list) {
+		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+		if (ptr->answer)
+			continue;
+		if (pos++ != head->r.query_index)
+			continue;
+		len = ptr->query_len;
+		break;
+	}
+	spin_unlock(&tomoyo_query_list_lock);
+	if (!len) {
+		head->r.query_index = 0;
+		return;
+	}
+	buf = kzalloc(len, GFP_NOFS);
+	if (!buf)
+		return;
+	pos = 0;
+	spin_lock(&tomoyo_query_list_lock);
+	list_for_each(tmp, &tomoyo_query_list) {
+		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+		if (ptr->answer)
+			continue;
+		if (pos++ != head->r.query_index)
+			continue;
+		/*
+		 * Some query can be skipped because tomoyo_query_list
+		 * can change, but I don't care.
+		 */
+		if (len == ptr->query_len)
+			memmove(buf, ptr->query, len);
+		break;
+	}
+	spin_unlock(&tomoyo_query_list_lock);
+	if (buf[0]) {
+		head->read_buf = buf;
+		head->r.w[head->r.w_pos++] = buf;
+		head->r.query_index++;
+	} else {
+		kfree(buf);
+	}
+}
+
+/**
+ * tomoyo_write_answer - Write the supervisor's decision.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, -EINVAL otherwise.
+ */
+static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
+{
+	char *data = head->write_buf;
+	struct list_head *tmp;
+	unsigned int serial;
+	unsigned int answer;
+	spin_lock(&tomoyo_query_list_lock);
+	list_for_each(tmp, &tomoyo_query_list) {
+		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+		ptr->timer = 0;
+	}
+	spin_unlock(&tomoyo_query_list_lock);
+	if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
+		return -EINVAL;
+	spin_lock(&tomoyo_query_list_lock);
+	list_for_each(tmp, &tomoyo_query_list) {
+		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+		if (ptr->serial != serial)
+			continue;
+		if (!ptr->answer)
+			ptr->answer = answer;
+		break;
+	}
+	spin_unlock(&tomoyo_query_list_lock);
+	return 0;
 }
 
 /**
@@ -1913,13 +1744,12 @@
  *
  * Returns version information.
  */
-static int tomoyo_read_version(struct tomoyo_io_buffer *head)
+static void tomoyo_read_version(struct tomoyo_io_buffer *head)
 {
-	if (!head->read_eof) {
-		tomoyo_io_printf(head, "2.2.0");
-		head->read_eof = true;
+	if (!head->r.eof) {
+		tomoyo_io_printf(head, "2.3.0");
+		head->r.eof = true;
 	}
-	return 0;
 }
 
 /**
@@ -1929,18 +1759,17 @@
  *
  * Returns the current process's domainname.
  */
-static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
+static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
 {
-	if (!head->read_eof) {
+	if (!head->r.eof) {
 		/*
 		 * tomoyo_domain()->domainname != NULL
 		 * because every process belongs to a domain and
 		 * the domain's name cannot be NULL.
 		 */
 		tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name);
-		head->read_eof = true;
+		head->r.eof = true;
 	}
-	return 0;
 }
 
 /**
@@ -1953,23 +1782,24 @@
  *
  * Caller acquires tomoyo_read_lock().
  */
-static int tomoyo_open_control(const u8 type, struct file *file)
+int tomoyo_open_control(const u8 type, struct file *file)
 {
 	struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS);
 
 	if (!head)
 		return -ENOMEM;
 	mutex_init(&head->io_sem);
+	head->type = type;
 	switch (type) {
 	case TOMOYO_DOMAINPOLICY:
 		/* /sys/kernel/security/tomoyo/domain_policy */
-		head->write = tomoyo_write_domain_policy;
-		head->read = tomoyo_read_domain_policy;
+		head->write = tomoyo_write_domain;
+		head->read = tomoyo_read_domain;
 		break;
 	case TOMOYO_EXCEPTIONPOLICY:
 		/* /sys/kernel/security/tomoyo/exception_policy */
-		head->write = tomoyo_write_exception_policy;
-		head->read = tomoyo_read_exception_policy;
+		head->write = tomoyo_write_exception;
+		head->read = tomoyo_read_exception;
 		break;
 	case TOMOYO_SELFDOMAIN:
 		/* /sys/kernel/security/tomoyo/self_domain */
@@ -2001,10 +1831,15 @@
 		head->write = tomoyo_write_profile;
 		head->read = tomoyo_read_profile;
 		break;
+	case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */
+		head->poll = tomoyo_poll_query;
+		head->write = tomoyo_write_answer;
+		head->read = tomoyo_read_query;
+		break;
 	case TOMOYO_MANAGER:
 		/* /sys/kernel/security/tomoyo/manager */
-		head->write = tomoyo_write_manager_policy;
-		head->read = tomoyo_read_manager_policy;
+		head->write = tomoyo_write_manager;
+		head->read = tomoyo_read_manager;
 		break;
 	}
 	if (!(file->f_mode & FMODE_READ)) {
@@ -2013,7 +1848,9 @@
 		 * for reading.
 		 */
 		head->read = NULL;
-	} else {
+		head->poll = NULL;
+	} else if (!head->poll) {
+		/* Don't allocate read_buf for poll() access. */
 		if (!head->readbuf_size)
 			head->readbuf_size = 4096 * 2;
 		head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS);
@@ -2037,7 +1874,8 @@
 			return -ENOMEM;
 		}
 	}
-	head->reader_idx = tomoyo_read_lock();
+	if (type != TOMOYO_QUERY)
+		head->reader_idx = tomoyo_read_lock();
 	file->private_data = head;
 	/*
 	 * Call the handler now if the file is
@@ -2048,10 +1886,35 @@
 	 */
 	if (type == TOMOYO_SELFDOMAIN)
 		tomoyo_read_control(file, NULL, 0);
+	/*
+	 * If the file is /sys/kernel/security/tomoyo/query , increment the
+	 * observer counter.
+	 * The obserber counter is used by tomoyo_supervisor() to see if
+	 * there is some process monitoring /sys/kernel/security/tomoyo/query.
+	 */
+	else if (type == TOMOYO_QUERY)
+		atomic_inc(&tomoyo_query_observers);
 	return 0;
 }
 
 /**
+ * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table".
+ *
+ * Waits for read readiness.
+ * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd .
+ */
+int tomoyo_poll_control(struct file *file, poll_table *wait)
+{
+	struct tomoyo_io_buffer *head = file->private_data;
+	if (!head->poll)
+		return -ENOSYS;
+	return head->poll(file, wait);
+}
+
+/**
  * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface.
  *
  * @file:       Pointer to "struct file".
@@ -2062,36 +1925,23 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_read_control(struct file *file, char __user *buffer,
-			       const int buffer_len)
+int tomoyo_read_control(struct file *file, char __user *buffer,
+			const int buffer_len)
 {
-	int len = 0;
+	int len;
 	struct tomoyo_io_buffer *head = file->private_data;
-	char *cp;
 
 	if (!head->read)
 		return -ENOSYS;
 	if (mutex_lock_interruptible(&head->io_sem))
 		return -EINTR;
-	/* Call the policy handler. */
-	len = head->read(head);
-	if (len < 0)
-		goto out;
-	/* Write to buffer. */
-	len = head->read_avail;
-	if (len > buffer_len)
-		len = buffer_len;
-	if (!len)
-		goto out;
-	/* head->read_buf changes by some functions. */
-	cp = head->read_buf;
-	if (copy_to_user(buffer, cp, len)) {
-		len = -EFAULT;
-		goto out;
-	}
-	head->read_avail -= len;
-	memmove(cp, cp + len, head->read_avail);
- out:
+	head->read_user_buf = buffer;
+	head->read_user_buf_avail = buffer_len;
+	if (tomoyo_flush(head))
+		/* Call the policy handler. */
+		head->read(head);
+	tomoyo_flush(head);
+	len = head->read_user_buf - buffer;
 	mutex_unlock(&head->io_sem);
 	return len;
 }
@@ -2107,8 +1957,8 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_write_control(struct file *file, const char __user *buffer,
-				const int buffer_len)
+int tomoyo_write_control(struct file *file, const char __user *buffer,
+			 const int buffer_len)
 {
 	struct tomoyo_io_buffer *head = file->private_data;
 	int error = buffer_len;
@@ -2121,8 +1971,7 @@
 		return -EFAULT;
 	/* Don't allow updating policies by non manager programs. */
 	if (head->write != tomoyo_write_pid &&
-	    head->write != tomoyo_write_domain_policy &&
-	    !tomoyo_is_policy_manager())
+	    head->write != tomoyo_write_domain && !tomoyo_manager())
 		return -EPERM;
 	if (mutex_lock_interruptible(&head->io_sem))
 		return -EINTR;
@@ -2159,12 +2008,19 @@
  *
  * Caller looses tomoyo_read_lock().
  */
-static int tomoyo_close_control(struct file *file)
+int tomoyo_close_control(struct file *file)
 {
 	struct tomoyo_io_buffer *head = file->private_data;
 	const bool is_write = !!head->write_buf;
 
-	tomoyo_read_unlock(head->reader_idx);
+	/*
+	 * If the file is /sys/kernel/security/tomoyo/query , decrement the
+	 * observer counter.
+	 */
+	if (head->type == TOMOYO_QUERY)
+		atomic_dec(&tomoyo_query_observers);
+	else
+		tomoyo_read_unlock(head->reader_idx);
 	/* Release memory used for policy I/O. */
 	kfree(head->read_buf);
 	head->read_buf = NULL;
@@ -2179,129 +2035,25 @@
 }
 
 /**
- * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
- *
- * @inode: Pointer to "struct inode".
- * @file:  Pointer to "struct file".
- *
- * Returns 0 on success, negative value otherwise.
+ * tomoyo_check_profile - Check all profiles currently assigned to domains are defined.
  */
-static int tomoyo_open(struct inode *inode, struct file *file)
+void tomoyo_check_profile(void)
 {
-	const int key = ((u8 *) file->f_path.dentry->d_inode->i_private)
-		- ((u8 *) NULL);
-	return tomoyo_open_control(key, file);
+	struct tomoyo_domain_info *domain;
+	const int idx = tomoyo_read_lock();
+	tomoyo_policy_loaded = true;
+	/* Check all profiles currently assigned to domains are defined. */
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
+		const u8 profile = domain->profile;
+		if (tomoyo_profile_ptr[profile])
+			continue;
+		panic("Profile %u (used by '%s') not defined.\n",
+		      profile, domain->domainname->name);
+	}
+	tomoyo_read_unlock(idx);
+	if (tomoyo_profile_version != 20090903)
+		panic("Profile version %u is not supported.\n",
+		      tomoyo_profile_version);
+	printk(KERN_INFO "TOMOYO: 2.3.0\n");
+	printk(KERN_INFO "Mandatory Access Control activated.\n");
 }
-
-/**
- * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface.
- *
- * @inode: Pointer to "struct inode".
- * @file:  Pointer to "struct file".
- *
- * Returns 0 on success, negative value otherwise.
- */
-static int tomoyo_release(struct inode *inode, struct file *file)
-{
-	return tomoyo_close_control(file);
-}
-
-/**
- * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface.
- *
- * @file:  Pointer to "struct file".
- * @buf:   Pointer to buffer.
- * @count: Size of @buf.
- * @ppos:  Unused.
- *
- * Returns bytes read on success, negative value otherwise.
- */
-static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
-			   loff_t *ppos)
-{
-	return tomoyo_read_control(file, buf, count);
-}
-
-/**
- * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface.
- *
- * @file:  Pointer to "struct file".
- * @buf:   Pointer to buffer.
- * @count: Size of @buf.
- * @ppos:  Unused.
- *
- * Returns @count on success, negative value otherwise.
- */
-static ssize_t tomoyo_write(struct file *file, const char __user *buf,
-			    size_t count, loff_t *ppos)
-{
-	return tomoyo_write_control(file, buf, count);
-}
-
-/*
- * tomoyo_operations is a "struct file_operations" which is used for handling
- * /sys/kernel/security/tomoyo/ interface.
- *
- * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR).
- * See tomoyo_io_buffer for internals.
- */
-static const struct file_operations tomoyo_operations = {
-	.open    = tomoyo_open,
-	.release = tomoyo_release,
-	.read    = tomoyo_read,
-	.write   = tomoyo_write,
-};
-
-/**
- * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory.
- *
- * @name:   The name of the interface file.
- * @mode:   The permission of the interface file.
- * @parent: The parent directory.
- * @key:    Type of interface.
- *
- * Returns nothing.
- */
-static void __init tomoyo_create_entry(const char *name, const mode_t mode,
-				       struct dentry *parent, const u8 key)
-{
-	securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key,
-			       &tomoyo_operations);
-}
-
-/**
- * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface.
- *
- * Returns 0.
- */
-static int __init tomoyo_initerface_init(void)
-{
-	struct dentry *tomoyo_dir;
-
-	/* Don't create securityfs entries unless registered. */
-	if (current_cred()->security != &tomoyo_kernel_domain)
-		return 0;
-
-	tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
-	tomoyo_create_entry("domain_policy",    0600, tomoyo_dir,
-			    TOMOYO_DOMAINPOLICY);
-	tomoyo_create_entry("exception_policy", 0600, tomoyo_dir,
-			    TOMOYO_EXCEPTIONPOLICY);
-	tomoyo_create_entry("self_domain",      0400, tomoyo_dir,
-			    TOMOYO_SELFDOMAIN);
-	tomoyo_create_entry(".domain_status",   0600, tomoyo_dir,
-			    TOMOYO_DOMAIN_STATUS);
-	tomoyo_create_entry(".process_status",  0600, tomoyo_dir,
-			    TOMOYO_PROCESS_STATUS);
-	tomoyo_create_entry("meminfo",          0600, tomoyo_dir,
-			    TOMOYO_MEMINFO);
-	tomoyo_create_entry("profile",          0600, tomoyo_dir,
-			    TOMOYO_PROFILE);
-	tomoyo_create_entry("manager",          0600, tomoyo_dir,
-			    TOMOYO_MANAGER);
-	tomoyo_create_entry("version",          0400, tomoyo_dir,
-			    TOMOYO_VERSION);
-	return 0;
-}
-
-fs_initcall(tomoyo_initerface_init);
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 9f1ae5e..04454cb 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -20,6 +20,7 @@
 #include <linux/mount.h>
 #include <linux/list.h>
 #include <linux/cred.h>
+#include <linux/poll.h>
 struct linux_binprm;
 
 /********** Constants definitions. **********/
@@ -32,20 +33,44 @@
 #define TOMOYO_HASH_BITS  8
 #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS)
 
-/*
- * This is the max length of a token.
- *
- * A token consists of only ASCII printable characters.
- * Non printable characters in a token is represented in \ooo style
- * octal string. Thus, \ itself is represented as \\.
- */
-#define TOMOYO_MAX_PATHNAME_LEN 4000
+#define TOMOYO_EXEC_TMPSIZE     4096
 
 /* Profile number is an integer between 0 and 255. */
 #define TOMOYO_MAX_PROFILES 256
 
+enum tomoyo_mode_index {
+	TOMOYO_CONFIG_DISABLED,
+	TOMOYO_CONFIG_LEARNING,
+	TOMOYO_CONFIG_PERMISSIVE,
+	TOMOYO_CONFIG_ENFORCING,
+	TOMOYO_CONFIG_USE_DEFAULT = 255
+};
+
+enum tomoyo_policy_id {
+	TOMOYO_ID_GROUP,
+	TOMOYO_ID_PATH_GROUP,
+	TOMOYO_ID_NUMBER_GROUP,
+	TOMOYO_ID_TRANSITION_CONTROL,
+	TOMOYO_ID_AGGREGATOR,
+	TOMOYO_ID_GLOBALLY_READABLE,
+	TOMOYO_ID_PATTERN,
+	TOMOYO_ID_NO_REWRITE,
+	TOMOYO_ID_MANAGER,
+	TOMOYO_ID_NAME,
+	TOMOYO_ID_ACL,
+	TOMOYO_ID_DOMAIN,
+	TOMOYO_MAX_POLICY
+};
+
+enum tomoyo_group_id {
+	TOMOYO_PATH_GROUP,
+	TOMOYO_NUMBER_GROUP,
+	TOMOYO_MAX_GROUP
+};
+
 /* Keywords for ACLs. */
-#define TOMOYO_KEYWORD_ALIAS                     "alias "
+#define TOMOYO_KEYWORD_AGGREGATOR                "aggregator "
+#define TOMOYO_KEYWORD_ALLOW_MOUNT               "allow_mount "
 #define TOMOYO_KEYWORD_ALLOW_READ                "allow_read "
 #define TOMOYO_KEYWORD_DELETE                    "delete "
 #define TOMOYO_KEYWORD_DENY_REWRITE              "deny_rewrite "
@@ -55,36 +80,51 @@
 #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN      "no_initialize_domain "
 #define TOMOYO_KEYWORD_NO_KEEP_DOMAIN            "no_keep_domain "
 #define TOMOYO_KEYWORD_PATH_GROUP                "path_group "
+#define TOMOYO_KEYWORD_NUMBER_GROUP              "number_group "
 #define TOMOYO_KEYWORD_SELECT                    "select "
 #define TOMOYO_KEYWORD_USE_PROFILE               "use_profile "
 #define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ  "ignore_global_allow_read"
+#define TOMOYO_KEYWORD_QUOTA_EXCEEDED            "quota_exceeded"
+#define TOMOYO_KEYWORD_TRANSITION_FAILED         "transition_failed"
 /* A domain definition starts with <kernel>. */
 #define TOMOYO_ROOT_NAME                         "<kernel>"
 #define TOMOYO_ROOT_NAME_LEN                     (sizeof(TOMOYO_ROOT_NAME) - 1)
 
-/* Index numbers for Access Controls. */
-enum tomoyo_mac_index {
-	TOMOYO_MAC_FOR_FILE,  /* domain_policy.conf */
-	TOMOYO_MAX_ACCEPT_ENTRY,
-	TOMOYO_VERBOSE,
-	TOMOYO_MAX_CONTROL_INDEX
+/* Value type definition. */
+#define TOMOYO_VALUE_TYPE_INVALID     0
+#define TOMOYO_VALUE_TYPE_DECIMAL     1
+#define TOMOYO_VALUE_TYPE_OCTAL       2
+#define TOMOYO_VALUE_TYPE_HEXADECIMAL 3
+
+enum tomoyo_transition_type {
+	/* Do not change this order, */
+	TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE,
+	TOMOYO_TRANSITION_CONTROL_INITIALIZE,
+	TOMOYO_TRANSITION_CONTROL_NO_KEEP,
+	TOMOYO_TRANSITION_CONTROL_KEEP,
+	TOMOYO_MAX_TRANSITION_TYPE
 };
 
 /* Index numbers for Access Controls. */
 enum tomoyo_acl_entry_type_index {
 	TOMOYO_TYPE_PATH_ACL,
 	TOMOYO_TYPE_PATH2_ACL,
+	TOMOYO_TYPE_PATH_NUMBER_ACL,
+	TOMOYO_TYPE_MKDEV_ACL,
+	TOMOYO_TYPE_MOUNT_ACL,
 };
 
 /* Index numbers for File Controls. */
 
 /*
- * TYPE_READ_WRITE_ACL is special. TYPE_READ_WRITE_ACL is automatically set
- * if both TYPE_READ_ACL and TYPE_WRITE_ACL are set. Both TYPE_READ_ACL and
- * TYPE_WRITE_ACL are automatically set if TYPE_READ_WRITE_ACL is set.
- * TYPE_READ_WRITE_ACL is automatically cleared if either TYPE_READ_ACL or
- * TYPE_WRITE_ACL is cleared. Both TYPE_READ_ACL and TYPE_WRITE_ACL are
- * automatically cleared if TYPE_READ_WRITE_ACL is cleared.
+ * TOMOYO_TYPE_READ_WRITE is special. TOMOYO_TYPE_READ_WRITE is automatically
+ * set if both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are set.
+ * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically set if
+ * TOMOYO_TYPE_READ_WRITE is set.
+ * TOMOYO_TYPE_READ_WRITE is automatically cleared if either TOMOYO_TYPE_READ
+ * or TOMOYO_TYPE_WRITE is cleared.
+ * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically cleared if
+ * TOMOYO_TYPE_READ_WRITE is cleared.
  */
 
 enum tomoyo_path_acl_index {
@@ -92,27 +132,24 @@
 	TOMOYO_TYPE_EXECUTE,
 	TOMOYO_TYPE_READ,
 	TOMOYO_TYPE_WRITE,
-	TOMOYO_TYPE_CREATE,
 	TOMOYO_TYPE_UNLINK,
-	TOMOYO_TYPE_MKDIR,
 	TOMOYO_TYPE_RMDIR,
-	TOMOYO_TYPE_MKFIFO,
-	TOMOYO_TYPE_MKSOCK,
-	TOMOYO_TYPE_MKBLOCK,
-	TOMOYO_TYPE_MKCHAR,
 	TOMOYO_TYPE_TRUNCATE,
 	TOMOYO_TYPE_SYMLINK,
 	TOMOYO_TYPE_REWRITE,
-	TOMOYO_TYPE_IOCTL,
-	TOMOYO_TYPE_CHMOD,
-	TOMOYO_TYPE_CHOWN,
-	TOMOYO_TYPE_CHGRP,
 	TOMOYO_TYPE_CHROOT,
-	TOMOYO_TYPE_MOUNT,
 	TOMOYO_TYPE_UMOUNT,
 	TOMOYO_MAX_PATH_OPERATION
 };
 
+#define TOMOYO_RW_MASK ((1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE))
+
+enum tomoyo_mkdev_acl_index {
+	TOMOYO_TYPE_MKBLOCK,
+	TOMOYO_TYPE_MKCHAR,
+	TOMOYO_MAX_MKDEV_OPERATION
+};
+
 enum tomoyo_path2_acl_index {
 	TOMOYO_TYPE_LINK,
 	TOMOYO_TYPE_RENAME,
@@ -120,6 +157,18 @@
 	TOMOYO_MAX_PATH2_OPERATION
 };
 
+enum tomoyo_path_number_acl_index {
+	TOMOYO_TYPE_CREATE,
+	TOMOYO_TYPE_MKDIR,
+	TOMOYO_TYPE_MKFIFO,
+	TOMOYO_TYPE_MKSOCK,
+	TOMOYO_TYPE_IOCTL,
+	TOMOYO_TYPE_CHMOD,
+	TOMOYO_TYPE_CHOWN,
+	TOMOYO_TYPE_CHGRP,
+	TOMOYO_MAX_PATH_NUMBER_OPERATION
+};
+
 enum tomoyo_securityfs_interface_index {
 	TOMOYO_DOMAINPOLICY,
 	TOMOYO_EXCEPTIONPOLICY,
@@ -129,20 +178,109 @@
 	TOMOYO_SELFDOMAIN,
 	TOMOYO_VERSION,
 	TOMOYO_PROFILE,
+	TOMOYO_QUERY,
 	TOMOYO_MANAGER
 };
 
+enum tomoyo_mac_index {
+	TOMOYO_MAC_FILE_EXECUTE,
+	TOMOYO_MAC_FILE_OPEN,
+	TOMOYO_MAC_FILE_CREATE,
+	TOMOYO_MAC_FILE_UNLINK,
+	TOMOYO_MAC_FILE_MKDIR,
+	TOMOYO_MAC_FILE_RMDIR,
+	TOMOYO_MAC_FILE_MKFIFO,
+	TOMOYO_MAC_FILE_MKSOCK,
+	TOMOYO_MAC_FILE_TRUNCATE,
+	TOMOYO_MAC_FILE_SYMLINK,
+	TOMOYO_MAC_FILE_REWRITE,
+	TOMOYO_MAC_FILE_MKBLOCK,
+	TOMOYO_MAC_FILE_MKCHAR,
+	TOMOYO_MAC_FILE_LINK,
+	TOMOYO_MAC_FILE_RENAME,
+	TOMOYO_MAC_FILE_CHMOD,
+	TOMOYO_MAC_FILE_CHOWN,
+	TOMOYO_MAC_FILE_CHGRP,
+	TOMOYO_MAC_FILE_IOCTL,
+	TOMOYO_MAC_FILE_CHROOT,
+	TOMOYO_MAC_FILE_MOUNT,
+	TOMOYO_MAC_FILE_UMOUNT,
+	TOMOYO_MAC_FILE_PIVOT_ROOT,
+	TOMOYO_MAX_MAC_INDEX
+};
+
+enum tomoyo_mac_category_index {
+	TOMOYO_MAC_CATEGORY_FILE,
+	TOMOYO_MAX_MAC_CATEGORY_INDEX
+};
+
+#define TOMOYO_RETRY_REQUEST 1 /* Retry this request. */
+
 /********** Structure definitions. **********/
 
 /*
- * tomoyo_page_buffer is a structure which is used for holding a pathname
- * obtained from "struct dentry" and "struct vfsmount" pair.
- * As of now, it is 4096 bytes. If users complain that 4096 bytes is too small
- * (because TOMOYO escapes non ASCII printable characters using \ooo format),
- * we will make the buffer larger.
+ * tomoyo_acl_head is a structure which is used for holding elements not in
+ * domain policy.
+ * It has following fields.
+ *
+ *  (1) "list" which is linked to tomoyo_policy_list[] .
+ *  (2) "is_deleted" is a bool which is true if marked as deleted, false
+ *      otherwise.
  */
-struct tomoyo_page_buffer {
-	char buffer[4096];
+struct tomoyo_acl_head {
+	struct list_head list;
+	bool is_deleted;
+} __packed;
+
+/*
+ * tomoyo_request_info is a structure which is used for holding
+ *
+ * (1) Domain information of current process.
+ * (2) How many retries are made for this request.
+ * (3) Profile number used for this request.
+ * (4) Access control mode of the profile.
+ */
+struct tomoyo_request_info {
+	struct tomoyo_domain_info *domain;
+	/* For holding parameters. */
+	union {
+		struct {
+			const struct tomoyo_path_info *filename;
+			/* For using wildcards at tomoyo_find_next_domain(). */
+			const struct tomoyo_path_info *matched_path;
+			u8 operation;
+		} path;
+		struct {
+			const struct tomoyo_path_info *filename1;
+			const struct tomoyo_path_info *filename2;
+			u8 operation;
+		} path2;
+		struct {
+			const struct tomoyo_path_info *filename;
+			unsigned int mode;
+			unsigned int major;
+			unsigned int minor;
+			u8 operation;
+		} mkdev;
+		struct {
+			const struct tomoyo_path_info *filename;
+			unsigned long number;
+			u8 operation;
+		} path_number;
+		struct {
+			const struct tomoyo_path_info *type;
+			const struct tomoyo_path_info *dir;
+			const struct tomoyo_path_info *dev;
+			unsigned long flags;
+			int need_dev;
+		} mount;
+	} param;
+	u8 param_type;
+	bool granted;
+	u8 retry;
+	u8 profile;
+	u8 mode; /* One of tomoyo_mode_index . */
+	u8 type;
 };
 
 /*
@@ -174,45 +312,31 @@
 };
 
 /*
- * tomoyo_name_entry is a structure which is used for linking
+ * tomoyo_name is a structure which is used for linking
  * "struct tomoyo_path_info" into tomoyo_name_list .
  */
-struct tomoyo_name_entry {
+struct tomoyo_name {
 	struct list_head list;
 	atomic_t users;
 	struct tomoyo_path_info entry;
 };
 
-/*
- * tomoyo_path_info_with_data is a structure which is used for holding a
- * pathname obtained from "struct dentry" and "struct vfsmount" pair.
- *
- * "struct tomoyo_path_info_with_data" consists of "struct tomoyo_path_info"
- * and buffer for the pathname, while "struct tomoyo_page_buffer" consists of
- * buffer for the pathname only.
- *
- * "struct tomoyo_path_info_with_data" is intended to allow TOMOYO to release
- * both "struct tomoyo_path_info" and buffer for the pathname by single kfree()
- * so that we don't need to return two pointers to the caller. If the caller
- * puts "struct tomoyo_path_info" on stack memory, we will be able to remove
- * "struct tomoyo_path_info_with_data".
- */
-struct tomoyo_path_info_with_data {
-	/* Keep "head" first, for this pointer is passed to kfree(). */
-	struct tomoyo_path_info head;
-	char barrier1[16]; /* Safeguard for overrun. */
-	char body[TOMOYO_MAX_PATHNAME_LEN];
-	char barrier2[16]; /* Safeguard for overrun. */
-};
-
 struct tomoyo_name_union {
 	const struct tomoyo_path_info *filename;
-	struct tomoyo_path_group *group;
+	struct tomoyo_group *group;
 	u8 is_group;
 };
 
-/* Structure for "path_group" directive. */
-struct tomoyo_path_group {
+struct tomoyo_number_union {
+	unsigned long values[2];
+	struct tomoyo_group *group;
+	u8 min_type;
+	u8 max_type;
+	u8 is_group;
+};
+
+/* Structure for "path_group"/"number_group" directive. */
+struct tomoyo_group {
 	struct list_head list;
 	const struct tomoyo_path_info *group_name;
 	struct list_head member_list;
@@ -220,28 +344,35 @@
 };
 
 /* Structure for "path_group" directive. */
-struct tomoyo_path_group_member {
-	struct list_head list;
-	bool is_deleted;
+struct tomoyo_path_group {
+	struct tomoyo_acl_head head;
 	const struct tomoyo_path_info *member_name;
 };
 
+/* Structure for "number_group" directive. */
+struct tomoyo_number_group {
+	struct tomoyo_acl_head head;
+	struct tomoyo_number_union number;
+};
+
 /*
  * tomoyo_acl_info is a structure which is used for holding
  *
  *  (1) "list" which is linked to the ->acl_info_list of
  *      "struct tomoyo_domain_info"
- *  (2) "type" which tells type of the entry (either
- *      "struct tomoyo_path_acl" or "struct tomoyo_path2_acl").
+ *  (2) "is_deleted" is a bool which is true if this domain is marked as
+ *      "deleted", false otherwise.
+ *  (3) "type" which tells type of the entry.
  *
  * Packing "struct tomoyo_acl_info" allows
- * "struct tomoyo_path_acl" to embed "u8" + "u16" and
- * "struct tomoyo_path2_acl" to embed "u8"
- * without enlarging their structure size.
+ * "struct tomoyo_path_acl" to embed "u16" and "struct tomoyo_path2_acl"
+ * "struct tomoyo_path_number_acl" "struct tomoyo_mkdev_acl" to embed
+ * "u8" without enlarging their structure size.
  */
 struct tomoyo_acl_info {
 	struct list_head list;
-	u8 type;
+	bool is_deleted;
+	u8 type; /* = one of values in "enum tomoyo_acl_entry_type_index". */
 } __packed;
 
 /*
@@ -299,20 +430,62 @@
  *  (3) "name" is the pathname.
  *
  * Directives held by this structure are "allow_read/write", "allow_execute",
- * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir",
- * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock",
- * "allow_mkchar", "allow_truncate", "allow_symlink", "allow_rewrite",
- * "allow_chmod", "allow_chown", "allow_chgrp", "allow_chroot", "allow_mount"
- * and "allow_unmount".
+ * "allow_read", "allow_write", "allow_unlink", "allow_rmdir",
+ * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_chroot" and
+ * "allow_unmount".
  */
 struct tomoyo_path_acl {
 	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */
-	u8 perm_high;
 	u16 perm;
 	struct tomoyo_name_union name;
 };
 
 /*
+ * tomoyo_path_number_acl is a structure which is used for holding an
+ * entry with one pathname and one number operation.
+ * It has following fields.
+ *
+ *  (1) "head" which is a "struct tomoyo_acl_info".
+ *  (2) "perm" which is a bitmask of permitted operations.
+ *  (3) "name" is the pathname.
+ *  (4) "number" is the numeric value.
+ *
+ * Directives held by this structure are "allow_create", "allow_mkdir",
+ * "allow_ioctl", "allow_mkfifo", "allow_mksock", "allow_chmod", "allow_chown"
+ * and "allow_chgrp".
+ *
+ */
+struct tomoyo_path_number_acl {
+	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_NUMBER_ACL */
+	u8 perm;
+	struct tomoyo_name_union name;
+	struct tomoyo_number_union number;
+};
+
+/*
+ * tomoyo_mkdev_acl is a structure which is used for holding an
+ * entry with one pathname and three numbers operation.
+ * It has following fields.
+ *
+ *  (1) "head" which is a "struct tomoyo_acl_info".
+ *  (2) "perm" which is a bitmask of permitted operations.
+ *  (3) "mode" is the create mode.
+ *  (4) "major" is the major number of device node.
+ *  (5) "minor" is the minor number of device node.
+ *
+ * Directives held by this structure are "allow_mkchar", "allow_mkblock".
+ *
+ */
+struct tomoyo_mkdev_acl {
+	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MKDEV_ACL */
+	u8 perm;
+	struct tomoyo_name_union name;
+	struct tomoyo_number_union mode;
+	struct tomoyo_number_union major;
+	struct tomoyo_number_union minor;
+};
+
+/*
  * tomoyo_path2_acl is a structure which is used for holding an
  * entry with two pathnames operation (i.e. link(), rename() and pivot_root()).
  * It has following fields.
@@ -333,53 +506,61 @@
 };
 
 /*
- * tomoyo_io_buffer is a structure which is used for reading and modifying
- * configuration via /sys/kernel/security/tomoyo/ interface.
- * It has many fields. ->read_var1 , ->read_var2 , ->write_var1 are used as
- * cursors.
+ * tomoyo_mount_acl is a structure which is used for holding an
+ * entry for mount operation.
+ * It has following fields.
  *
- * Since the content of /sys/kernel/security/tomoyo/domain_policy is a list of
- * "struct tomoyo_domain_info" entries and each "struct tomoyo_domain_info"
- * entry has a list of "struct tomoyo_acl_info", we need two cursors when
- * reading (one is for traversing tomoyo_domain_list and the other is for
- * traversing "struct tomoyo_acl_info"->acl_info_list ).
+ *  (1) "head" which is a "struct tomoyo_acl_info".
+ *  (2) "dev_name" is the device name.
+ *  (3) "dir_name" is the mount point.
+ *  (4) "fs_type" is the filesystem type.
+ *  (5) "flags" is the mount flags.
  *
- * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
- * "select ", TOMOYO seeks the cursor ->read_var1 and ->write_var1 to the
- * domain with the domainname specified by the rest of that line (NULL is set
- * if seek failed).
- * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
- * "delete ", TOMOYO deletes an entry or a domain specified by the rest of that
- * line (->write_var1 is set to NULL if a domain was deleted).
- * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
- * neither "select " nor "delete ", an entry or a domain specified by that line
- * is appended.
+ * Directive held by this structure is "allow_mount".
+ */
+struct tomoyo_mount_acl {
+	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MOUNT_ACL */
+	struct tomoyo_name_union dev_name;
+	struct tomoyo_name_union dir_name;
+	struct tomoyo_name_union fs_type;
+	struct tomoyo_number_union flags;
+};
+
+#define TOMOYO_MAX_IO_READ_QUEUE 32
+
+/*
+ * Structure for reading/writing policy via /sys/kernel/security/tomoyo
+ * interfaces.
  */
 struct tomoyo_io_buffer {
-	int (*read) (struct tomoyo_io_buffer *);
+	void (*read) (struct tomoyo_io_buffer *);
 	int (*write) (struct tomoyo_io_buffer *);
+	int (*poll) (struct file *file, poll_table *wait);
 	/* Exclusive lock for this structure.   */
 	struct mutex io_sem;
 	/* Index returned by tomoyo_read_lock(). */
 	int reader_idx;
-	/* The position currently reading from. */
-	struct list_head *read_var1;
-	/* Extra variables for reading.         */
-	struct list_head *read_var2;
+	char __user *read_user_buf;
+	int read_user_buf_avail;
+	struct {
+		struct list_head *domain;
+		struct list_head *group;
+		struct list_head *acl;
+		int avail;
+		int step;
+		int query_index;
+		u16 index;
+		u8 bit;
+		u8 w_pos;
+		bool eof;
+		bool print_this_domain_only;
+		bool print_execute_only;
+		const char *w[TOMOYO_MAX_IO_READ_QUEUE];
+	} r;
 	/* The position currently writing to.   */
 	struct tomoyo_domain_info *write_var1;
-	/* The step for reading.                */
-	int read_step;
 	/* Buffer for reading.                  */
 	char *read_buf;
-	/* EOF flag for reading.                */
-	bool read_eof;
-	/* Read domain ACL of specified PID?    */
-	bool read_single_domain;
-	/* Extra variable for reading.          */
-	u8 read_bit;
-	/* Bytes available for reading.         */
-	int read_avail;
 	/* Size of read buffer.                 */
 	int readbuf_size;
 	/* Buffer for writing.                  */
@@ -388,215 +569,203 @@
 	int write_avail;
 	/* Size of write buffer.                */
 	int writebuf_size;
+	/* Type of this interface.              */
+	u8 type;
 };
 
 /*
- * tomoyo_globally_readable_file_entry is a structure which is used for holding
+ * tomoyo_readable_file is a structure which is used for holding
  * "allow_read" entries.
  * It has following fields.
  *
- *  (1) "list" which is linked to tomoyo_globally_readable_list .
+ *  (1) "head" is "struct tomoyo_acl_head".
  *  (2) "filename" is a pathname which is allowed to open(O_RDONLY).
- *  (3) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
  */
-struct tomoyo_globally_readable_file_entry {
-	struct list_head list;
+struct tomoyo_readable_file {
+	struct tomoyo_acl_head head;
 	const struct tomoyo_path_info *filename;
-	bool is_deleted;
 };
 
 /*
- * tomoyo_pattern_entry is a structure which is used for holding
- * "tomoyo_pattern_list" entries.
+ * tomoyo_no_pattern is a structure which is used for holding
+ * "file_pattern" entries.
  * It has following fields.
  *
- *  (1) "list" which is linked to tomoyo_pattern_list .
+ *  (1) "head" is "struct tomoyo_acl_head".
  *  (2) "pattern" is a pathname pattern which is used for converting pathnames
  *      to pathname patterns during learning mode.
- *  (3) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
  */
-struct tomoyo_pattern_entry {
-	struct list_head list;
+struct tomoyo_no_pattern {
+	struct tomoyo_acl_head head;
 	const struct tomoyo_path_info *pattern;
-	bool is_deleted;
 };
 
 /*
- * tomoyo_no_rewrite_entry is a structure which is used for holding
+ * tomoyo_no_rewrite is a structure which is used for holding
  * "deny_rewrite" entries.
  * It has following fields.
  *
- *  (1) "list" which is linked to tomoyo_no_rewrite_list .
+ *  (1) "head" is "struct tomoyo_acl_head".
  *  (2) "pattern" is a pathname which is by default not permitted to modify
  *      already existing content.
- *  (3) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
  */
-struct tomoyo_no_rewrite_entry {
-	struct list_head list;
+struct tomoyo_no_rewrite {
+	struct tomoyo_acl_head head;
 	const struct tomoyo_path_info *pattern;
-	bool is_deleted;
 };
 
 /*
- * tomoyo_domain_initializer_entry is a structure which is used for holding
- * "initialize_domain" and "no_initialize_domain" entries.
+ * tomoyo_transition_control is a structure which is used for holding
+ * "initialize_domain"/"no_initialize_domain"/"keep_domain"/"no_keep_domain"
+ * entries.
  * It has following fields.
  *
- *  (1) "list" which is linked to tomoyo_domain_initializer_list .
- *  (2) "domainname" which is "a domainname" or "the last component of a
- *      domainname". This field is NULL if "from" clause is not specified.
- *  (3) "program" which is a program's pathname.
- *  (4) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
- *  (5) "is_not" is a bool which is true if "no_initialize_domain", false
- *      otherwise.
- *  (6) "is_last_name" is a bool which is true if "domainname" is "the last
+ *  (1) "head" is "struct tomoyo_acl_head".
+ *  (2) "type" is type of this entry.
+ *  (3) "is_last_name" is a bool which is true if "domainname" is "the last
  *      component of a domainname", false otherwise.
- */
-struct tomoyo_domain_initializer_entry {
-	struct list_head list;
-	const struct tomoyo_path_info *domainname;    /* This may be NULL */
-	const struct tomoyo_path_info *program;
-	bool is_deleted;
-	bool is_not;       /* True if this entry is "no_initialize_domain".  */
-	/* True if the domainname is tomoyo_get_last_name(). */
-	bool is_last_name;
-};
-
-/*
- * tomoyo_domain_keeper_entry is a structure which is used for holding
- * "keep_domain" and "no_keep_domain" entries.
- * It has following fields.
- *
- *  (1) "list" which is linked to tomoyo_domain_keeper_list .
- *  (2) "domainname" which is "a domainname" or "the last component of a
+ *  (4) "domainname" which is "a domainname" or "the last component of a
  *      domainname".
- *  (3) "program" which is a program's pathname.
- *      This field is NULL if "from" clause is not specified.
- *  (4) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
- *  (5) "is_not" is a bool which is true if "no_initialize_domain", false
- *      otherwise.
- *  (6) "is_last_name" is a bool which is true if "domainname" is "the last
- *      component of a domainname", false otherwise.
+ *  (5) "program" which is a program's pathname.
  */
-struct tomoyo_domain_keeper_entry {
-	struct list_head list;
-	const struct tomoyo_path_info *domainname;
-	const struct tomoyo_path_info *program;       /* This may be NULL */
-	bool is_deleted;
-	bool is_not;       /* True if this entry is "no_keep_domain".        */
+struct tomoyo_transition_control {
+	struct tomoyo_acl_head head;
+	u8 type; /* One of values in "enum tomoyo_transition_type".  */
 	/* True if the domainname is tomoyo_get_last_name(). */
 	bool is_last_name;
+	const struct tomoyo_path_info *domainname; /* Maybe NULL */
+	const struct tomoyo_path_info *program;    /* Maybe NULL */
 };
 
 /*
- * tomoyo_alias_entry is a structure which is used for holding "alias" entries.
+ * tomoyo_aggregator is a structure which is used for holding
+ * "aggregator" entries.
  * It has following fields.
  *
- *  (1) "list" which is linked to tomoyo_alias_list .
- *  (2) "original_name" which is a dereferenced pathname.
- *  (3) "aliased_name" which is a symlink's pathname.
- *  (4) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
+ *  (1) "head" is "struct tomoyo_acl_head".
+ *  (2) "original_name" which is originally requested name.
+ *  (3) "aggregated_name" which is name to rewrite.
  */
-struct tomoyo_alias_entry {
-	struct list_head list;
+struct tomoyo_aggregator {
+	struct tomoyo_acl_head head;
 	const struct tomoyo_path_info *original_name;
-	const struct tomoyo_path_info *aliased_name;
-	bool is_deleted;
+	const struct tomoyo_path_info *aggregated_name;
 };
 
 /*
- * tomoyo_policy_manager_entry is a structure which is used for holding list of
+ * tomoyo_manager is a structure which is used for holding list of
  * domainnames or programs which are permitted to modify configuration via
  * /sys/kernel/security/tomoyo/ interface.
  * It has following fields.
  *
- *  (1) "list" which is linked to tomoyo_policy_manager_list .
- *  (2) "manager" is a domainname or a program's pathname.
- *  (3) "is_domain" is a bool which is true if "manager" is a domainname, false
+ *  (1) "head" is "struct tomoyo_acl_head".
+ *  (2) "is_domain" is a bool which is true if "manager" is a domainname, false
  *      otherwise.
- *  (4) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
+ *  (3) "manager" is a domainname or a program's pathname.
  */
-struct tomoyo_policy_manager_entry {
-	struct list_head list;
+struct tomoyo_manager {
+	struct tomoyo_acl_head head;
+	bool is_domain;  /* True if manager is a domainname. */
 	/* A path to program or a domainname. */
 	const struct tomoyo_path_info *manager;
-	bool is_domain;  /* True if manager is a domainname. */
-	bool is_deleted; /* True if this entry is deleted. */
+};
+
+struct tomoyo_preference {
+	unsigned int learning_max_entry;
+	bool enforcing_verbose;
+	bool learning_verbose;
+	bool permissive_verbose;
+};
+
+struct tomoyo_profile {
+	const struct tomoyo_path_info *comment;
+	struct tomoyo_preference *learning;
+	struct tomoyo_preference *permissive;
+	struct tomoyo_preference *enforcing;
+	struct tomoyo_preference preference;
+	u8 default_config;
+	u8 config[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX];
 };
 
 /********** Function prototypes. **********/
 
-/* Check whether the given name matches the given name_union. */
-bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
-			       const struct tomoyo_name_union *ptr);
+extern asmlinkage long sys_getpid(void);
+extern asmlinkage long sys_getppid(void);
+
+/* Check whether the given string starts with the given keyword. */
+bool tomoyo_str_starts(char **src, const char *find);
+/* Get tomoyo_realpath() of current process. */
+const char *tomoyo_get_exe(void);
+/* Format string. */
+void tomoyo_normalize_line(unsigned char *buffer);
+/* Print warning or error message on console. */
+void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
+     __attribute__ ((format(printf, 2, 3)));
+/* Check all profiles currently assigned to domains are defined. */
+void tomoyo_check_profile(void);
+/* Open operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_open_control(const u8 type, struct file *file);
+/* Close /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_close_control(struct file *file);
+/* Poll operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_poll_control(struct file *file, poll_table *wait);
+/* Read operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_read_control(struct file *file, char __user *buffer,
+			const int buffer_len);
+/* Write operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_write_control(struct file *file, const char __user *buffer,
+			 const int buffer_len);
 /* Check whether the domain has too many ACL entries to hold. */
-bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain);
-/* Transactional sprintf() for policy dump. */
-bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
+bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r);
+/* Print out of memory warning message. */
+void tomoyo_warn_oom(const char *function);
+/* Check whether the given name matches the given name_union. */
+const struct tomoyo_path_info *
+tomoyo_compare_name_union(const struct tomoyo_path_info *name,
+			  const struct tomoyo_name_union *ptr);
+/* Check whether the given number matches the given number_union. */
+bool tomoyo_compare_number_union(const unsigned long value,
+				 const struct tomoyo_number_union *ptr);
+int tomoyo_get_mode(const u8 profile, const u8 index);
+void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
 	__attribute__ ((format(printf, 2, 3)));
 /* Check whether the domainname is correct. */
-bool tomoyo_is_correct_domain(const unsigned char *domainname);
+bool tomoyo_correct_domain(const unsigned char *domainname);
 /* Check whether the token is correct. */
-bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
-			    const s8 pattern_type, const s8 end_type);
+bool tomoyo_correct_path(const char *filename);
+bool tomoyo_correct_word(const char *string);
 /* Check whether the token can be a domainname. */
-bool tomoyo_is_domain_def(const unsigned char *buffer);
+bool tomoyo_domain_def(const unsigned char *buffer);
 bool tomoyo_parse_name_union(const char *filename,
 			     struct tomoyo_name_union *ptr);
 /* Check whether the given filename matches the given path_group. */
-bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
-			       const struct tomoyo_path_group *group,
-			       const bool may_use_pattern);
+const struct tomoyo_path_info *
+tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
+			  const struct tomoyo_group *group);
+/* Check whether the given value matches the given number_group. */
+bool tomoyo_number_matches_group(const unsigned long min,
+				 const unsigned long max,
+				 const struct tomoyo_group *group);
 /* Check whether the given filename matches the given pattern. */
 bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
 				 const struct tomoyo_path_info *pattern);
-/* Read "alias" entry in exception policy. */
-bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head);
-/*
- * Read "initialize_domain" and "no_initialize_domain" entry
- * in exception policy.
- */
-bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head);
-/* Read "keep_domain" and "no_keep_domain" entry in exception policy. */
-bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head);
-/* Read "file_pattern" entry in exception policy. */
-bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head);
-/* Read "path_group" entry in exception policy. */
-bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head);
-/* Read "allow_read" entry in exception policy. */
-bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head);
-/* Read "deny_rewrite" entry in exception policy. */
-bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head);
+
+bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num);
 /* Tokenize a line. */
 bool tomoyo_tokenize(char *buffer, char *w[], size_t size);
 /* Write domain policy violation warning message to console? */
 bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain);
-/* Convert double path operation to operation name. */
-const char *tomoyo_path22keyword(const u8 operation);
-/* Get the last component of the given domainname. */
-const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain);
-/* Get warning message. */
-const char *tomoyo_get_msg(const bool is_enforce);
-/* Convert single path operation to operation name. */
-const char *tomoyo_path2keyword(const u8 operation);
-/* Create "alias" entry in exception policy. */
-int tomoyo_write_alias_policy(char *data, const bool is_delete);
-/*
- * Create "initialize_domain" and "no_initialize_domain" entry
- * in exception policy.
- */
-int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
-					   const bool is_delete);
-/* Create "keep_domain" and "no_keep_domain" entry in exception policy. */
-int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
-				      const bool is_delete);
+/* Fill "struct tomoyo_request_info". */
+int tomoyo_init_request_info(struct tomoyo_request_info *r,
+			     struct tomoyo_domain_info *domain,
+			     const u8 index);
+/* Check permission for mount operation. */
+int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
+			    unsigned long flags, void *data_page);
+/* Create "aggregator" entry in exception policy. */
+int tomoyo_write_aggregator(char *data, const bool is_delete);
+int tomoyo_write_transition_control(char *data, const bool is_delete,
+				    const u8 type);
 /*
  * Create "allow_read/write", "allow_execute", "allow_read", "allow_write",
  * "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir",
@@ -604,25 +773,31 @@
  * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_rename" and
  * "allow_link" entry in domain policy.
  */
-int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
-			     const bool is_delete);
+int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
+		      const bool is_delete);
 /* Create "allow_read" entry in exception policy. */
-int tomoyo_write_globally_readable_policy(char *data, const bool is_delete);
+int tomoyo_write_globally_readable(char *data, const bool is_delete);
+/* Create "allow_mount" entry in domain policy. */
+int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain,
+		       const bool is_delete);
 /* Create "deny_rewrite" entry in exception policy. */
-int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete);
+int tomoyo_write_no_rewrite(char *data, const bool is_delete);
 /* Create "file_pattern" entry in exception policy. */
-int tomoyo_write_pattern_policy(char *data, const bool is_delete);
-/* Create "path_group" entry in exception policy. */
-int tomoyo_write_path_group_policy(char *data, const bool is_delete);
+int tomoyo_write_pattern(char *data, const bool is_delete);
+/* Create "path_group"/"number_group" entry in exception policy. */
+int tomoyo_write_group(char *data, const bool is_delete, const u8 type);
+int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
+     __attribute__ ((format(printf, 2, 3)));
 /* Find a domain by the given name. */
 struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
 /* Find or create a domain by the given name. */
-struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
-							    domainname,
-							    const u8 profile);
-
-/* Allocate memory for "struct tomoyo_path_group". */
-struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name);
+struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
+						const u8 profile);
+struct tomoyo_profile *tomoyo_profile(const u8 profile);
+/*
+ * Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
+ */
+struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 type);
 
 /* Check mode for specified functionality. */
 unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
@@ -632,25 +807,23 @@
 /* Run policy loader when /sbin/init starts. */
 void tomoyo_load_policy(const char *filename);
 
+void tomoyo_put_number_union(struct tomoyo_number_union *ptr);
+
 /* Convert binary string to ascii string. */
-int tomoyo_encode(char *buffer, int buflen, const char *str);
-
-/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
-int tomoyo_realpath_from_path2(struct path *path, char *newname,
-			       int newname_len);
+char *tomoyo_encode(const char *str);
 
 /*
- * Returns realpath(3) of the given pathname but ignores chroot'ed root.
- * These functions use kzalloc(), so the caller must call kfree()
- * if these functions didn't return NULL.
- */
-char *tomoyo_realpath(const char *pathname);
-/*
- * Same with tomoyo_realpath() except that it doesn't follow the final symlink.
+ * Returns realpath(3) of the given pathname except that
+ * ignores chroot'ed root and does not follow the final symlink.
  */
 char *tomoyo_realpath_nofollow(const char *pathname);
-/* Same with tomoyo_realpath() except that the pathname is already solved. */
+/*
+ * Returns realpath(3) of the given pathname except that
+ * ignores chroot'ed root and the pathname is already solved.
+ */
 char *tomoyo_realpath_from_path(struct path *path);
+/* Get patterned pathname. */
+const char *tomoyo_pattern(const struct tomoyo_path_info *filename);
 
 /* Check memory quota. */
 bool tomoyo_memory_ok(void *ptr);
@@ -663,23 +836,29 @@
 const struct tomoyo_path_info *tomoyo_get_name(const char *name);
 
 /* Check for memory usage. */
-int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head);
+void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head);
 
 /* Set memory quota. */
 int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head);
 
-/* Initialize realpath related code. */
-void __init tomoyo_realpath_init(void);
-int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
+/* Initialize mm related code. */
+void __init tomoyo_mm_init(void);
+int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
 			   const struct tomoyo_path_info *filename);
 int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
 				 struct path *path, const int flag);
+int tomoyo_path_number_perm(const u8 operation, struct path *path,
+			    unsigned long number);
+int tomoyo_mkdev_perm(const u8 operation, struct path *path,
+		      const unsigned int mode, unsigned int dev);
 int tomoyo_path_perm(const u8 operation, struct path *path);
 int tomoyo_path2_perm(const u8 operation, struct path *path1,
 		      struct path *path2);
-int tomoyo_check_rewrite_permission(struct file *filp);
 int tomoyo_find_next_domain(struct linux_binprm *bprm);
 
+void tomoyo_print_ulong(char *buffer, const int buffer_len,
+			const unsigned long value, const u8 type);
+
 /* Drop refcount on tomoyo_name_union. */
 void tomoyo_put_name_union(struct tomoyo_name_union *ptr);
 
@@ -688,6 +867,25 @@
 
 void tomoyo_memory_free(void *ptr);
 
+int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
+			 bool is_delete, struct tomoyo_domain_info *domain,
+			 bool (*check_duplicate) (const struct tomoyo_acl_info
+						  *,
+						  const struct tomoyo_acl_info
+						  *),
+			 bool (*merge_duplicate) (struct tomoyo_acl_info *,
+						  struct tomoyo_acl_info *,
+						  const bool));
+int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
+			 bool is_delete, struct list_head *list,
+			 bool (*check_duplicate) (const struct tomoyo_acl_head
+						  *,
+						  const struct tomoyo_acl_head
+						  *));
+void tomoyo_check_acl(struct tomoyo_request_info *r,
+		      bool (*check_entry) (struct tomoyo_request_info *,
+					   const struct tomoyo_acl_info *));
+
 /********** External variable definitions. **********/
 
 /* Lock for GC. */
@@ -696,14 +894,8 @@
 /* The list for "struct tomoyo_domain_info". */
 extern struct list_head tomoyo_domain_list;
 
-extern struct list_head tomoyo_path_group_list;
-extern struct list_head tomoyo_domain_initializer_list;
-extern struct list_head tomoyo_domain_keeper_list;
-extern struct list_head tomoyo_alias_list;
-extern struct list_head tomoyo_globally_readable_list;
-extern struct list_head tomoyo_pattern_list;
-extern struct list_head tomoyo_no_rewrite_list;
-extern struct list_head tomoyo_policy_manager_list;
+extern struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
+extern struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
 extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
 
 /* Lock for protecting policy. */
@@ -715,6 +907,14 @@
 /* The kernel's domain. */
 extern struct tomoyo_domain_info tomoyo_kernel_domain;
 
+extern const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION];
+extern const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION];
+extern const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION];
+extern const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION];
+
+extern unsigned int tomoyo_quota_for_query;
+extern unsigned int tomoyo_query_memory_size;
+
 /********** Inlined functions. **********/
 
 static inline int tomoyo_read_lock(void)
@@ -735,25 +935,25 @@
 }
 
 /**
- * tomoyo_is_valid - Check whether the character is a valid char.
+ * tomoyo_valid - Check whether the character is a valid char.
  *
  * @c: The character to check.
  *
  * Returns true if @c is a valid character, false otherwise.
  */
-static inline bool tomoyo_is_valid(const unsigned char c)
+static inline bool tomoyo_valid(const unsigned char c)
 {
 	return c > ' ' && c < 127;
 }
 
 /**
- * tomoyo_is_invalid - Check whether the character is an invalid char.
+ * tomoyo_invalid - Check whether the character is an invalid char.
  *
  * @c: The character to check.
  *
  * Returns true if @c is an invalid character, false otherwise.
  */
-static inline bool tomoyo_is_invalid(const unsigned char c)
+static inline bool tomoyo_invalid(const unsigned char c)
 {
 	return c && (c <= ' ' || c >= 127);
 }
@@ -761,13 +961,13 @@
 static inline void tomoyo_put_name(const struct tomoyo_path_info *name)
 {
 	if (name) {
-		struct tomoyo_name_entry *ptr =
-			container_of(name, struct tomoyo_name_entry, entry);
+		struct tomoyo_name *ptr =
+			container_of(name, typeof(*ptr), entry);
 		atomic_dec(&ptr->users);
 	}
 }
 
-static inline void tomoyo_put_path_group(struct tomoyo_path_group *group)
+static inline void tomoyo_put_group(struct tomoyo_group *group)
 {
 	if (group)
 		atomic_dec(&group->users);
@@ -784,75 +984,35 @@
 	return task_cred_xxx(task, security);
 }
 
-static inline bool tomoyo_is_same_acl_head(const struct tomoyo_acl_info *p1,
+static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *p1,
 					   const struct tomoyo_acl_info *p2)
 {
 	return p1->type == p2->type;
 }
 
-static inline bool tomoyo_is_same_name_union
+static inline bool tomoyo_same_name_union
 (const struct tomoyo_name_union *p1, const struct tomoyo_name_union *p2)
 {
 	return p1->filename == p2->filename && p1->group == p2->group &&
 		p1->is_group == p2->is_group;
 }
 
-static inline bool tomoyo_is_same_path_acl(const struct tomoyo_path_acl *p1,
-					   const struct tomoyo_path_acl *p2)
+static inline bool tomoyo_same_number_union
+(const struct tomoyo_number_union *p1, const struct tomoyo_number_union *p2)
 {
-	return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
-		tomoyo_is_same_name_union(&p1->name, &p2->name);
-}
-
-static inline bool tomoyo_is_same_path2_acl(const struct tomoyo_path2_acl *p1,
-					    const struct tomoyo_path2_acl *p2)
-{
-	return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
-		tomoyo_is_same_name_union(&p1->name1, &p2->name1) &&
-		tomoyo_is_same_name_union(&p1->name2, &p2->name2);
-}
-
-static inline bool tomoyo_is_same_domain_initializer_entry
-(const struct tomoyo_domain_initializer_entry *p1,
- const struct tomoyo_domain_initializer_entry *p2)
-{
-	return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
-		&& p1->domainname == p2->domainname
-		&& p1->program == p2->program;
-}
-
-static inline bool tomoyo_is_same_domain_keeper_entry
-(const struct tomoyo_domain_keeper_entry *p1,
- const struct tomoyo_domain_keeper_entry *p2)
-{
-	return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
-		&& p1->domainname == p2->domainname
-		&& p1->program == p2->program;
-}
-
-static inline bool tomoyo_is_same_alias_entry
-(const struct tomoyo_alias_entry *p1, const struct tomoyo_alias_entry *p2)
-{
-	return p1->original_name == p2->original_name &&
-		p1->aliased_name == p2->aliased_name;
+	return p1->values[0] == p2->values[0] && p1->values[1] == p2->values[1]
+		&& p1->group == p2->group && p1->min_type == p2->min_type &&
+		p1->max_type == p2->max_type && p1->is_group == p2->is_group;
 }
 
 /**
  * list_for_each_cookie - iterate over a list with cookie.
  * @pos:        the &struct list_head to use as a loop cursor.
- * @cookie:     the &struct list_head to use as a cookie.
  * @head:       the head for your list.
- *
- * Same with list_for_each_rcu() except that this primitive uses @cookie
- * so that we can continue iteration.
- * @cookie must be NULL when iteration starts, and @cookie will become
- * NULL when iteration finishes.
  */
-#define list_for_each_cookie(pos, cookie, head)				\
-	for (({ if (!cookie)						\
-				     cookie = head; }),			\
-		     pos = rcu_dereference((cookie)->next);		\
-	     prefetch(pos->next), pos != (head) || ((cookie) = NULL);	\
-	     (cookie) = pos, pos = rcu_dereference(pos->next))
+#define list_for_each_cookie(pos, head)					\
+	if (!pos)							\
+		pos =  srcu_dereference((head)->next, &tomoyo_ss);	\
+	for ( ; pos != (head); pos = srcu_dereference(pos->next, &tomoyo_ss))
 
 #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index cd8ba44..3538840 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -1,12 +1,9 @@
 /*
  * security/tomoyo/domain.c
  *
- * Implementation of the Domain-Based Mandatory Access Control.
+ * Domain transition functions for TOMOYO.
  *
- * Copyright (C) 2005-2009  NTT DATA CORPORATION
- *
- * Version: 2.2.0   2009/04/01
- *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
  */
 
 #include "common.h"
@@ -18,366 +15,191 @@
 /* The initial domain. */
 struct tomoyo_domain_info tomoyo_kernel_domain;
 
-/*
- * tomoyo_domain_list is used for holding list of domains.
- * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding
- * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain.
- *
- * An entry is added by
- *
- * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \
- *                                  /sys/kernel/security/tomoyo/domain_policy
- *
- * and is deleted by
- *
- * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \
- *                                  /sys/kernel/security/tomoyo/domain_policy
- *
- * and all entries are retrieved by
- *
- * # cat /sys/kernel/security/tomoyo/domain_policy
- *
- * A domain is added by
- *
- * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy
- *
- * and is deleted by
- *
- * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy
- *
- * and all domains are retrieved by
- *
- * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy
- *
- * Normally, a domainname is monotonically getting longer because a domainname
- * which the process will belong to if an execve() operation succeeds is
- * defined as a concatenation of "current domainname" + "pathname passed to
- * execve()".
- * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for
- * exceptions.
- */
-LIST_HEAD(tomoyo_domain_list);
-
 /**
- * tomoyo_get_last_name - Get last component of a domainname.
+ * tomoyo_update_policy - Update an entry for exception policy.
  *
- * @domain: Pointer to "struct tomoyo_domain_info".
- *
- * Returns the last component of the domainname.
- */
-const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
-{
-	const char *cp0 = domain->domainname->name;
-	const char *cp1 = strrchr(cp0, ' ');
-
-	if (cp1)
-		return cp1 + 1;
-	return cp0;
-}
-
-/*
- * tomoyo_domain_initializer_list is used for holding list of programs which
- * triggers reinitialization of domainname. Normally, a domainname is
- * monotonically getting longer. But sometimes, we restart daemon programs.
- * It would be convenient for us that "a daemon started upon system boot" and
- * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO
- * provides a way to shorten domainnames.
- *
- * An entry is added by
- *
- * # echo 'initialize_domain /usr/sbin/httpd' > \
- *                               /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete initialize_domain /usr/sbin/httpd' > \
- *                               /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, /usr/sbin/httpd will belong to
- * "<kernel> /usr/sbin/httpd" domain.
- *
- * You may specify a domainname using "from" keyword.
- * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
- * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd"
- * domain to belong to "<kernel> /usr/sbin/httpd" domain.
- *
- * You may add "no_" prefix to "initialize_domain".
- * "initialize_domain /usr/sbin/httpd" and
- * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
- * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain
- * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain.
- */
-LIST_HEAD(tomoyo_domain_initializer_list);
-
-/**
- * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
- *
- * @domainname: The name of domain. May be NULL.
- * @program:    The name of program.
- * @is_not:     True if it is "no_initialize_domain" entry.
- * @is_delete:  True if it is a delete request.
+ * @new_entry:       Pointer to "struct tomoyo_acl_info".
+ * @size:            Size of @new_entry in bytes.
+ * @is_delete:       True if it is a delete request.
+ * @list:            Pointer to "struct list_head".
+ * @check_duplicate: Callback function to find duplicated entry.
  *
  * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_update_domain_initializer_entry(const char *domainname,
-						  const char *program,
-						  const bool is_not,
-						  const bool is_delete)
+int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
+			 bool is_delete, struct list_head *list,
+			 bool (*check_duplicate) (const struct tomoyo_acl_head
+						  *,
+						  const struct tomoyo_acl_head
+						  *))
 {
-	struct tomoyo_domain_initializer_entry *ptr;
-	struct tomoyo_domain_initializer_entry e = { .is_not = is_not };
 	int error = is_delete ? -ENOENT : -ENOMEM;
+	struct tomoyo_acl_head *entry;
 
-	if (!tomoyo_is_correct_path(program, 1, -1, -1))
-		return -EINVAL; /* No patterns allowed. */
-	if (domainname) {
-		if (!tomoyo_is_domain_def(domainname) &&
-		    tomoyo_is_correct_path(domainname, 1, -1, -1))
-			e.is_last_name = true;
-		else if (!tomoyo_is_correct_domain(domainname))
-			return -EINVAL;
-		e.domainname = tomoyo_get_name(domainname);
-		if (!e.domainname)
-			goto out;
-	}
-	e.program = tomoyo_get_name(program);
-	if (!e.program)
-		goto out;
 	if (mutex_lock_interruptible(&tomoyo_policy_lock))
-		goto out;
-	list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
-		if (!tomoyo_is_same_domain_initializer_entry(ptr, &e))
+		return -ENOMEM;
+	list_for_each_entry_rcu(entry, list, list) {
+		if (!check_duplicate(entry, new_entry))
 			continue;
-		ptr->is_deleted = is_delete;
+		entry->is_deleted = is_delete;
 		error = 0;
 		break;
 	}
-	if (!is_delete && error) {
-		struct tomoyo_domain_initializer_entry *entry =
-			tomoyo_commit_ok(&e, sizeof(e));
+	if (error && !is_delete) {
+		entry = tomoyo_commit_ok(new_entry, size);
 		if (entry) {
-			list_add_tail_rcu(&entry->list,
-					  &tomoyo_domain_initializer_list);
+			list_add_tail_rcu(&entry->list, list);
 			error = 0;
 		}
 	}
 	mutex_unlock(&tomoyo_policy_lock);
- out:
-	tomoyo_put_name(e.domainname);
-	tomoyo_put_name(e.program);
 	return error;
 }
 
 /**
- * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
+ * tomoyo_update_domain - Update an entry for domain policy.
  *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
-{
-	struct list_head *pos;
-	bool done = true;
-
-	list_for_each_cookie(pos, head->read_var2,
-			     &tomoyo_domain_initializer_list) {
-		const char *no;
-		const char *from = "";
-		const char *domain = "";
-		struct tomoyo_domain_initializer_entry *ptr;
-		ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
-				  list);
-		if (ptr->is_deleted)
-			continue;
-		no = ptr->is_not ? "no_" : "";
-		if (ptr->domainname) {
-			from = " from ";
-			domain = ptr->domainname->name;
-		}
-		done = tomoyo_io_printf(head,
-					"%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
-					"%s%s%s\n", no, ptr->program->name,
-					from, domain);
-		if (!done)
-			break;
-	}
-	return done;
-}
-
-/**
- * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list.
- *
- * @data:      String to parse.
- * @is_not:    True if it is "no_initialize_domain" entry.
- * @is_delete: True if it is a delete request.
+ * @new_entry:       Pointer to "struct tomoyo_acl_info".
+ * @size:            Size of @new_entry in bytes.
+ * @is_delete:       True if it is a delete request.
+ * @domain:          Pointer to "struct tomoyo_domain_info".
+ * @check_duplicate: Callback function to find duplicated entry.
+ * @merge_duplicate: Callback function to merge duplicated entry.
  *
  * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
-					   const bool is_delete)
+int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
+			 bool is_delete, struct tomoyo_domain_info *domain,
+			 bool (*check_duplicate) (const struct tomoyo_acl_info
+						  *,
+						  const struct tomoyo_acl_info
+						  *),
+			 bool (*merge_duplicate) (struct tomoyo_acl_info *,
+						  struct tomoyo_acl_info *,
+						  const bool))
 {
-	char *cp = strstr(data, " from ");
+	int error = is_delete ? -ENOENT : -ENOMEM;
+	struct tomoyo_acl_info *entry;
 
-	if (cp) {
-		*cp = '\0';
-		return tomoyo_update_domain_initializer_entry(cp + 6, data,
-							      is_not,
-							      is_delete);
+	if (mutex_lock_interruptible(&tomoyo_policy_lock))
+		return error;
+	list_for_each_entry_rcu(entry, &domain->acl_info_list, list) {
+		if (!check_duplicate(entry, new_entry))
+			continue;
+		if (merge_duplicate)
+			entry->is_deleted = merge_duplicate(entry, new_entry,
+							    is_delete);
+		else
+			entry->is_deleted = is_delete;
+		error = 0;
+		break;
 	}
-	return tomoyo_update_domain_initializer_entry(NULL, data, is_not,
-						      is_delete);
+	if (error && !is_delete) {
+		entry = tomoyo_commit_ok(new_entry, size);
+		if (entry) {
+			list_add_tail_rcu(&entry->list, &domain->acl_info_list);
+			error = 0;
+		}
+	}
+	mutex_unlock(&tomoyo_policy_lock);
+	return error;
+}
+
+void tomoyo_check_acl(struct tomoyo_request_info *r,
+		      bool (*check_entry) (struct tomoyo_request_info *,
+					   const struct tomoyo_acl_info *))
+{
+	const struct tomoyo_domain_info *domain = r->domain;
+	struct tomoyo_acl_info *ptr;
+
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+		if (ptr->is_deleted || ptr->type != r->param_type)
+			continue;
+		if (check_entry(r, ptr)) {
+			r->granted = true;
+			return;
+		}
+	}
+	r->granted = false;
+}
+
+/* The list for "struct tomoyo_domain_info". */
+LIST_HEAD(tomoyo_domain_list);
+
+struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
+struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
+
+/**
+ * tomoyo_last_word - Get last component of a domainname.
+ *
+ * @domainname: Domainname to check.
+ *
+ * Returns the last word of @domainname.
+ */
+static const char *tomoyo_last_word(const char *name)
+{
+        const char *cp = strrchr(name, ' ');
+        if (cp)
+                return cp + 1;
+        return name;
+}
+
+static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
+					   const struct tomoyo_acl_head *b)
+{
+	const struct tomoyo_transition_control *p1 = container_of(a,
+								  typeof(*p1),
+								  head);
+	const struct tomoyo_transition_control *p2 = container_of(b,
+								  typeof(*p2),
+								  head);
+	return p1->type == p2->type && p1->is_last_name == p2->is_last_name
+		&& p1->domainname == p2->domainname
+		&& p1->program == p2->program;
 }
 
 /**
- * tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization.
+ * tomoyo_update_transition_control_entry - Update "struct tomoyo_transition_control" list.
  *
- * @domainname: The name of domain.
- * @program:    The name of program.
- * @last_name:  The last component of @domainname.
- *
- * Returns true if executing @program reinitializes domain transition,
- * false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
-					 domainname,
-					 const struct tomoyo_path_info *program,
-					 const struct tomoyo_path_info *
-					 last_name)
-{
-	struct tomoyo_domain_initializer_entry *ptr;
-	bool flag = false;
-
-	list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
-		if (ptr->is_deleted)
-			continue;
-		if (ptr->domainname) {
-			if (!ptr->is_last_name) {
-				if (ptr->domainname != domainname)
-					continue;
-			} else {
-				if (tomoyo_pathcmp(ptr->domainname, last_name))
-					continue;
-			}
-		}
-		if (tomoyo_pathcmp(ptr->program, program))
-			continue;
-		if (ptr->is_not) {
-			flag = false;
-			break;
-		}
-		flag = true;
-	}
-	return flag;
-}
-
-/*
- * tomoyo_domain_keeper_list is used for holding list of domainnames which
- * suppresses domain transition. Normally, a domainname is monotonically
- * getting longer. But sometimes, we want to suppress domain transition.
- * It would be convenient for us that programs executed from a login session
- * belong to the same domain. Thus, TOMOYO provides a way to suppress domain
- * transition.
- *
- * An entry is added by
- *
- * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
- *                              /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
- *                              /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, any process which belongs to
- * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain,
- * unless explicitly specified by "initialize_domain" or "no_keep_domain".
- *
- * You may specify a program using "from" keyword.
- * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash"
- * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash"
- * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain.
- *
- * You may add "no_" prefix to "keep_domain".
- * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and
- * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will
- * cause "/usr/bin/passwd" to belong to
- * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless
- * explicitly specified by "initialize_domain".
- */
-LIST_HEAD(tomoyo_domain_keeper_list);
-
-/**
- * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
- *
- * @domainname: The name of domain.
- * @program:    The name of program. May be NULL.
- * @is_not:     True if it is "no_keep_domain" entry.
+ * @domainname: The name of domain. Maybe NULL.
+ * @program:    The name of program. Maybe NULL.
+ * @type:       Type of transition.
  * @is_delete:  True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_update_domain_keeper_entry(const char *domainname,
-					     const char *program,
-					     const bool is_not,
-					     const bool is_delete)
+static int tomoyo_update_transition_control_entry(const char *domainname,
+						  const char *program,
+						  const u8 type,
+						  const bool is_delete)
 {
-	struct tomoyo_domain_keeper_entry *ptr;
-	struct tomoyo_domain_keeper_entry e = { .is_not = is_not };
+	struct tomoyo_transition_control e = { .type = type };
 	int error = is_delete ? -ENOENT : -ENOMEM;
-
-	if (!tomoyo_is_domain_def(domainname) &&
-	    tomoyo_is_correct_path(domainname, 1, -1, -1))
-		e.is_last_name = true;
-	else if (!tomoyo_is_correct_domain(domainname))
-		return -EINVAL;
 	if (program) {
-		if (!tomoyo_is_correct_path(program, 1, -1, -1))
+		if (!tomoyo_correct_path(program))
 			return -EINVAL;
 		e.program = tomoyo_get_name(program);
 		if (!e.program)
 			goto out;
 	}
-	e.domainname = tomoyo_get_name(domainname);
-	if (!e.domainname)
-		goto out;
-	if (mutex_lock_interruptible(&tomoyo_policy_lock))
-		goto out;
-	list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
-		if (!tomoyo_is_same_domain_keeper_entry(ptr, &e))
-			continue;
-		ptr->is_deleted = is_delete;
-		error = 0;
-		break;
-	}
-	if (!is_delete && error) {
-		struct tomoyo_domain_keeper_entry *entry =
-			tomoyo_commit_ok(&e, sizeof(e));
-		if (entry) {
-			list_add_tail_rcu(&entry->list,
-					  &tomoyo_domain_keeper_list);
-			error = 0;
+	if (domainname) {
+		if (!tomoyo_correct_domain(domainname)) {
+			if (!tomoyo_correct_path(domainname))
+				goto out;
+			e.is_last_name = true;
 		}
+		e.domainname = tomoyo_get_name(domainname);
+		if (!e.domainname)
+			goto out;
 	}
-	mutex_unlock(&tomoyo_policy_lock);
+	error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+				     &tomoyo_policy_list
+				     [TOMOYO_ID_TRANSITION_CONTROL],
+				     tomoyo_same_transition_control);
  out:
 	tomoyo_put_name(e.domainname);
 	tomoyo_put_name(e.program);
@@ -385,219 +207,133 @@
 }
 
 /**
- * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
+ * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
  *
  * @data:      String to parse.
- * @is_not:    True if it is "no_keep_domain" entry.
  * @is_delete: True if it is a delete request.
+ * @type:      Type of this entry.
  *
- * Caller holds tomoyo_read_lock().
+ * Returns 0 on success, negative value otherwise.
  */
-int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
-				      const bool is_delete)
+int tomoyo_write_transition_control(char *data, const bool is_delete,
+				    const u8 type)
 {
-	char *cp = strstr(data, " from ");
-
-	if (cp) {
-		*cp = '\0';
-		return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
-							 is_delete);
+	char *domainname = strstr(data, " from ");
+	if (domainname) {
+		*domainname = '\0';
+		domainname += 6;
+	} else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
+		   type == TOMOYO_TRANSITION_CONTROL_KEEP) {
+		domainname = data;
+		data = NULL;
 	}
-	return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
+	return tomoyo_update_transition_control_entry(domainname, data, type,
+						      is_delete);
 }
 
 /**
- * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
-{
-	struct list_head *pos;
-	bool done = true;
-
-	list_for_each_cookie(pos, head->read_var2,
-			     &tomoyo_domain_keeper_list) {
-		struct tomoyo_domain_keeper_entry *ptr;
-		const char *no;
-		const char *from = "";
-		const char *program = "";
-
-		ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list);
-		if (ptr->is_deleted)
-			continue;
-		no = ptr->is_not ? "no_" : "";
-		if (ptr->program) {
-			from = " from ";
-			program = ptr->program->name;
-		}
-		done = tomoyo_io_printf(head,
-					"%s" TOMOYO_KEYWORD_KEEP_DOMAIN
-					"%s%s%s\n", no, program, from,
-					ptr->domainname->name);
-		if (!done)
-			break;
-	}
-	return done;
-}
-
-/**
- * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression.
+ * tomoyo_transition_type - Get domain transition type.
  *
  * @domainname: The name of domain.
  * @program:    The name of program.
- * @last_name:  The last component of @domainname.
  *
- * Returns true if executing @program supresses domain transition,
- * false otherwise.
+ * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program
+ * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing
+ * @program suppresses domain transition, others otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
-				    const struct tomoyo_path_info *program,
-				    const struct tomoyo_path_info *last_name)
+static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname,
+				 const struct tomoyo_path_info *program)
 {
-	struct tomoyo_domain_keeper_entry *ptr;
-	bool flag = false;
-
-	list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
-		if (ptr->is_deleted)
-			continue;
-		if (!ptr->is_last_name) {
-			if (ptr->domainname != domainname)
+	const struct tomoyo_transition_control *ptr;
+	const char *last_name = tomoyo_last_word(domainname->name);
+	u8 type;
+	for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) {
+ next:
+		list_for_each_entry_rcu(ptr, &tomoyo_policy_list
+					[TOMOYO_ID_TRANSITION_CONTROL],
+					head.list) {
+			if (ptr->head.is_deleted || ptr->type != type)
 				continue;
-		} else {
-			if (tomoyo_pathcmp(ptr->domainname, last_name))
+			if (ptr->domainname) {
+				if (!ptr->is_last_name) {
+					if (ptr->domainname != domainname)
+						continue;
+				} else {
+					/*
+					 * Use direct strcmp() since this is
+					 * unlikely used.
+					 */
+					if (strcmp(ptr->domainname->name,
+						   last_name))
+						continue;
+				}
+			}
+			if (ptr->program &&
+			    tomoyo_pathcmp(ptr->program, program))
 				continue;
+			if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) {
+				/*
+				 * Do not check for initialize_domain if
+				 * no_initialize_domain matched.
+				 */
+				type = TOMOYO_TRANSITION_CONTROL_NO_KEEP;
+				goto next;
+			}
+			goto done;
 		}
-		if (ptr->program && tomoyo_pathcmp(ptr->program, program))
-			continue;
-		if (ptr->is_not) {
-			flag = false;
-			break;
-		}
-		flag = true;
 	}
-	return flag;
+ done:
+	return type;
 }
 
-/*
- * tomoyo_alias_list is used for holding list of symlink's pathnames which are
- * allowed to be passed to an execve() request. Normally, the domainname which
- * the current process will belong to after execve() succeeds is calculated
- * using dereferenced pathnames. But some programs behave differently depending
- * on the name passed to argv[0]. For busybox, calculating domainname using
- * dereferenced pathnames will cause all programs in the busybox to belong to
- * the same domain. Thus, TOMOYO provides a way to allow use of symlink's
- * pathname for checking execve()'s permission and calculating domainname which
- * the current process will belong to after execve() succeeds.
- *
- * An entry is added by
- *
- * # echo 'alias /bin/busybox /bin/cat' > \
- *                            /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete alias /bin/busybox /bin/cat' > \
- *                            /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^alias /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, if /bin/cat is a symlink to /bin/busybox and execution
- * of /bin/cat is requested, permission is checked for /bin/cat rather than
- * /bin/busybox and domainname which the current process will belong to after
- * execve() succeeds is calculated using /bin/cat rather than /bin/busybox .
- */
-LIST_HEAD(tomoyo_alias_list);
+static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
+				   const struct tomoyo_acl_head *b)
+{
+	const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), head);
+	const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), head);
+	return p1->original_name == p2->original_name &&
+		p1->aggregated_name == p2->aggregated_name;
+}
 
 /**
- * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
+ * tomoyo_update_aggregator_entry - Update "struct tomoyo_aggregator" list.
  *
- * @original_name: The original program's real name.
- * @aliased_name:  The symbolic program's symbolic link's name.
- * @is_delete:     True if it is a delete request.
+ * @original_name:   The original program's name.
+ * @aggregated_name: The program name to use.
+ * @is_delete:       True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_update_alias_entry(const char *original_name,
-				     const char *aliased_name,
-				     const bool is_delete)
+static int tomoyo_update_aggregator_entry(const char *original_name,
+					  const char *aggregated_name,
+					  const bool is_delete)
 {
-	struct tomoyo_alias_entry *ptr;
-	struct tomoyo_alias_entry e = { };
+	struct tomoyo_aggregator e = { };
 	int error = is_delete ? -ENOENT : -ENOMEM;
 
-	if (!tomoyo_is_correct_path(original_name, 1, -1, -1) ||
-	    !tomoyo_is_correct_path(aliased_name, 1, -1, -1))
-		return -EINVAL; /* No patterns allowed. */
+	if (!tomoyo_correct_path(original_name) ||
+	    !tomoyo_correct_path(aggregated_name))
+		return -EINVAL;
 	e.original_name = tomoyo_get_name(original_name);
-	e.aliased_name = tomoyo_get_name(aliased_name);
-	if (!e.original_name || !e.aliased_name)
+	e.aggregated_name = tomoyo_get_name(aggregated_name);
+	if (!e.original_name || !e.aggregated_name ||
+	    e.aggregated_name->is_patterned) /* No patterns allowed. */
 		goto out;
-	if (mutex_lock_interruptible(&tomoyo_policy_lock))
-		goto out;
-	list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
-		if (!tomoyo_is_same_alias_entry(ptr, &e))
-			continue;
-		ptr->is_deleted = is_delete;
-		error = 0;
-		break;
-	}
-	if (!is_delete && error) {
-		struct tomoyo_alias_entry *entry =
-			tomoyo_commit_ok(&e, sizeof(e));
-		if (entry) {
-			list_add_tail_rcu(&entry->list, &tomoyo_alias_list);
-			error = 0;
-		}
-	}
-	mutex_unlock(&tomoyo_policy_lock);
+	error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+				     &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR],
+				     tomoyo_same_aggregator);
  out:
 	tomoyo_put_name(e.original_name);
-	tomoyo_put_name(e.aliased_name);
+	tomoyo_put_name(e.aggregated_name);
 	return error;
 }
 
 /**
- * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
-{
-	struct list_head *pos;
-	bool done = true;
-
-	list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
-		struct tomoyo_alias_entry *ptr;
-
-		ptr = list_entry(pos, struct tomoyo_alias_entry, list);
-		if (ptr->is_deleted)
-			continue;
-		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
-					ptr->original_name->name,
-					ptr->aliased_name->name);
-		if (!done)
-			break;
-	}
-	return done;
-}
-
-/**
- * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list.
+ * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
  *
  * @data:      String to parse.
  * @is_delete: True if it is a delete request.
@@ -606,18 +342,18 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_alias_policy(char *data, const bool is_delete)
+int tomoyo_write_aggregator(char *data, const bool is_delete)
 {
 	char *cp = strchr(data, ' ');
 
 	if (!cp)
 		return -EINVAL;
 	*cp++ = '\0';
-	return tomoyo_update_alias_entry(data, cp, is_delete);
+	return tomoyo_update_aggregator_entry(data, cp, is_delete);
 }
 
 /**
- * tomoyo_find_or_assign_new_domain - Create a domain.
+ * tomoyo_assign_domain - Create a domain.
  *
  * @domainname: The name of domain.
  * @profile:    Profile number to assign if the domain was newly created.
@@ -626,16 +362,15 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
-							    domainname,
-							    const u8 profile)
+struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
+						const u8 profile)
 {
 	struct tomoyo_domain_info *entry;
 	struct tomoyo_domain_info *domain = NULL;
 	const struct tomoyo_path_info *saved_domainname;
 	bool found = false;
 
-	if (!tomoyo_is_correct_domain(domainname))
+	if (!tomoyo_correct_domain(domainname))
 		return NULL;
 	saved_domainname = tomoyo_get_name(domainname);
 	if (!saved_domainname)
@@ -678,116 +413,118 @@
  */
 int tomoyo_find_next_domain(struct linux_binprm *bprm)
 {
-	/*
-	 * This function assumes that the size of buffer returned by
-	 * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
-	 */
-	struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS);
+	struct tomoyo_request_info r;
+	char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
 	struct tomoyo_domain_info *old_domain = tomoyo_domain();
 	struct tomoyo_domain_info *domain = NULL;
-	const char *old_domain_name = old_domain->domainname->name;
 	const char *original_name = bprm->filename;
-	char *new_domain_name = NULL;
-	char *real_program_name = NULL;
-	char *symlink_program_name = NULL;
-	const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
-	const bool is_enforce = (mode == 3);
+	u8 mode;
+	bool is_enforce;
 	int retval = -ENOMEM;
-	struct tomoyo_path_info r; /* real name */
-	struct tomoyo_path_info s; /* symlink name */
-	struct tomoyo_path_info l; /* last name */
-	static bool initialized;
+	bool need_kfree = false;
+	struct tomoyo_path_info rn = { }; /* real name */
 
+	mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
+	is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
 	if (!tmp)
 		goto out;
 
-	if (!initialized) {
-		/*
-		 * Built-in initializers. This is needed because policies are
-		 * not loaded until starting /sbin/init.
-		 */
-		tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug",
-						       false, false);
-		tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe",
-						       false, false);
-		initialized = true;
+ retry:
+	if (need_kfree) {
+		kfree(rn.name);
+		need_kfree = false;
 	}
-
-	/* Get tomoyo_realpath of program. */
+	/* Get symlink's pathname of program. */
 	retval = -ENOENT;
-	/* I hope tomoyo_realpath() won't fail with -ENOMEM. */
-	real_program_name = tomoyo_realpath(original_name);
-	if (!real_program_name)
+	rn.name = tomoyo_realpath_nofollow(original_name);
+	if (!rn.name)
 		goto out;
-	/* Get tomoyo_realpath of symbolic link. */
-	symlink_program_name = tomoyo_realpath_nofollow(original_name);
-	if (!symlink_program_name)
-		goto out;
+	tomoyo_fill_path_info(&rn);
+	need_kfree = true;
 
-	r.name = real_program_name;
-	tomoyo_fill_path_info(&r);
-	s.name = symlink_program_name;
-	tomoyo_fill_path_info(&s);
-	l.name = tomoyo_get_last_name(old_domain);
-	tomoyo_fill_path_info(&l);
-
-	/* Check 'alias' directive. */
-	if (tomoyo_pathcmp(&r, &s)) {
-		struct tomoyo_alias_entry *ptr;
-		/* Is this program allowed to be called via symbolic links? */
-		list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
-			if (ptr->is_deleted ||
-			    tomoyo_pathcmp(&r, ptr->original_name) ||
-			    tomoyo_pathcmp(&s, ptr->aliased_name))
+	/* Check 'aggregator' directive. */
+	{
+		struct tomoyo_aggregator *ptr;
+		list_for_each_entry_rcu(ptr, &tomoyo_policy_list
+					[TOMOYO_ID_AGGREGATOR], head.list) {
+			if (ptr->head.is_deleted ||
+			    !tomoyo_path_matches_pattern(&rn,
+							 ptr->original_name))
 				continue;
-			memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
-			strncpy(real_program_name, ptr->aliased_name->name,
-				TOMOYO_MAX_PATHNAME_LEN - 1);
-			tomoyo_fill_path_info(&r);
+			kfree(rn.name);
+			need_kfree = false;
+			/* This is OK because it is read only. */
+			rn = *ptr->aggregated_name;
 			break;
 		}
 	}
 
 	/* Check execute permission. */
-	retval = tomoyo_check_exec_perm(old_domain, &r);
+	retval = tomoyo_path_permission(&r, TOMOYO_TYPE_EXECUTE, &rn);
+	if (retval == TOMOYO_RETRY_REQUEST)
+		goto retry;
 	if (retval < 0)
 		goto out;
+	/*
+	 * To be able to specify domainnames with wildcards, use the
+	 * pathname specified in the policy (which may contain
+	 * wildcard) rather than the pathname passed to execve()
+	 * (which never contains wildcard).
+	 */
+	if (r.param.path.matched_path) {
+		if (need_kfree)
+			kfree(rn.name);
+		need_kfree = false;
+		/* This is OK because it is read only. */
+		rn = *r.param.path.matched_path;
+	}
 
-	new_domain_name = tmp->buffer;
-	if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
+	/* Calculate domain to transit to. */
+	switch (tomoyo_transition_type(old_domain->domainname, &rn)) {
+	case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
 		/* Transit to the child of tomoyo_kernel_domain domain. */
-		snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
-			 TOMOYO_ROOT_NAME " " "%s", real_program_name);
-	} else if (old_domain == &tomoyo_kernel_domain &&
-		   !tomoyo_policy_loaded) {
-		/*
-		 * Needn't to transit from kernel domain before starting
-		 * /sbin/init. But transit from kernel domain if executing
-		 * initializers because they might start before /sbin/init.
-		 */
-		domain = old_domain;
-	} else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
+		snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " "
+			 "%s", rn.name);
+		break;
+	case TOMOYO_TRANSITION_CONTROL_KEEP:
 		/* Keep current domain. */
 		domain = old_domain;
-	} else {
-		/* Normal domain transition. */
-		snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
-			 "%s %s", old_domain_name, real_program_name);
+		break;
+	default:
+		if (old_domain == &tomoyo_kernel_domain &&
+		    !tomoyo_policy_loaded) {
+			/*
+			 * Needn't to transit from kernel domain before
+			 * starting /sbin/init. But transit from kernel domain
+			 * if executing initializers because they might start
+			 * before /sbin/init.
+			 */
+			domain = old_domain;
+		} else {
+			/* Normal domain transition. */
+			snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+				 old_domain->domainname->name, rn.name);
+		}
+		break;
 	}
-	if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
+	if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
 		goto done;
-	domain = tomoyo_find_domain(new_domain_name);
+	domain = tomoyo_find_domain(tmp);
 	if (domain)
 		goto done;
-	if (is_enforce)
-		goto done;
-	domain = tomoyo_find_or_assign_new_domain(new_domain_name,
-						  old_domain->profile);
+	if (is_enforce) {
+		int error = tomoyo_supervisor(&r, "# wants to create domain\n"
+					      "%s\n", tmp);
+		if (error == TOMOYO_RETRY_REQUEST)
+			goto retry;
+		if (error < 0)
+			goto done;
+	}
+	domain = tomoyo_assign_domain(tmp, old_domain->profile);
  done:
 	if (domain)
 		goto out;
-	printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
-	       new_domain_name);
+	printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp);
 	if (is_enforce)
 		retval = -EPERM;
 	else
@@ -798,8 +535,8 @@
 	/* Update reference count on "struct tomoyo_domain_info". */
 	atomic_inc(&domain->users);
 	bprm->cred->security = domain;
-	kfree(real_program_name);
-	kfree(symlink_program_name);
+	if (need_kfree)
+		kfree(rn.name);
 	kfree(tmp);
 	return retval;
 }
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index 1c6f823..9d32f18 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -1,48 +1,88 @@
 /*
  * security/tomoyo/file.c
  *
- * Implementation of the Domain-Based Mandatory Access Control.
+ * Pathname restriction functions.
  *
- * Copyright (C) 2005-2009  NTT DATA CORPORATION
- *
- * Version: 2.2.0   2009/04/01
- *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
  */
 
 #include "common.h"
 #include <linux/slab.h>
 
-/* Keyword array for single path operations. */
-static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
+/* Keyword array for operations with one pathname. */
+const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
 	[TOMOYO_TYPE_READ_WRITE] = "read/write",
 	[TOMOYO_TYPE_EXECUTE]    = "execute",
 	[TOMOYO_TYPE_READ]       = "read",
 	[TOMOYO_TYPE_WRITE]      = "write",
-	[TOMOYO_TYPE_CREATE]     = "create",
 	[TOMOYO_TYPE_UNLINK]     = "unlink",
-	[TOMOYO_TYPE_MKDIR]      = "mkdir",
 	[TOMOYO_TYPE_RMDIR]      = "rmdir",
-	[TOMOYO_TYPE_MKFIFO]     = "mkfifo",
-	[TOMOYO_TYPE_MKSOCK]     = "mksock",
-	[TOMOYO_TYPE_MKBLOCK]    = "mkblock",
-	[TOMOYO_TYPE_MKCHAR]     = "mkchar",
 	[TOMOYO_TYPE_TRUNCATE]   = "truncate",
 	[TOMOYO_TYPE_SYMLINK]    = "symlink",
 	[TOMOYO_TYPE_REWRITE]    = "rewrite",
+	[TOMOYO_TYPE_CHROOT]     = "chroot",
+	[TOMOYO_TYPE_UMOUNT]     = "unmount",
+};
+
+/* Keyword array for operations with one pathname and three numbers. */
+const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = {
+	[TOMOYO_TYPE_MKBLOCK]    = "mkblock",
+	[TOMOYO_TYPE_MKCHAR]     = "mkchar",
+};
+
+/* Keyword array for operations with two pathnames. */
+const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
+	[TOMOYO_TYPE_LINK]       = "link",
+	[TOMOYO_TYPE_RENAME]     = "rename",
+	[TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
+};
+
+/* Keyword array for operations with one pathname and one number. */
+const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
+	[TOMOYO_TYPE_CREATE]     = "create",
+	[TOMOYO_TYPE_MKDIR]      = "mkdir",
+	[TOMOYO_TYPE_MKFIFO]     = "mkfifo",
+	[TOMOYO_TYPE_MKSOCK]     = "mksock",
 	[TOMOYO_TYPE_IOCTL]      = "ioctl",
 	[TOMOYO_TYPE_CHMOD]      = "chmod",
 	[TOMOYO_TYPE_CHOWN]      = "chown",
 	[TOMOYO_TYPE_CHGRP]      = "chgrp",
-	[TOMOYO_TYPE_CHROOT]     = "chroot",
-	[TOMOYO_TYPE_MOUNT]      = "mount",
-	[TOMOYO_TYPE_UMOUNT]     = "unmount",
 };
 
-/* Keyword array for double path operations. */
-static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
-	[TOMOYO_TYPE_LINK]    = "link",
-	[TOMOYO_TYPE_RENAME]  = "rename",
-	[TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
+static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
+	[TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN,
+	[TOMOYO_TYPE_EXECUTE]    = TOMOYO_MAC_FILE_EXECUTE,
+	[TOMOYO_TYPE_READ]       = TOMOYO_MAC_FILE_OPEN,
+	[TOMOYO_TYPE_WRITE]      = TOMOYO_MAC_FILE_OPEN,
+	[TOMOYO_TYPE_UNLINK]     = TOMOYO_MAC_FILE_UNLINK,
+	[TOMOYO_TYPE_RMDIR]      = TOMOYO_MAC_FILE_RMDIR,
+	[TOMOYO_TYPE_TRUNCATE]   = TOMOYO_MAC_FILE_TRUNCATE,
+	[TOMOYO_TYPE_SYMLINK]    = TOMOYO_MAC_FILE_SYMLINK,
+	[TOMOYO_TYPE_REWRITE]    = TOMOYO_MAC_FILE_REWRITE,
+	[TOMOYO_TYPE_CHROOT]     = TOMOYO_MAC_FILE_CHROOT,
+	[TOMOYO_TYPE_UMOUNT]     = TOMOYO_MAC_FILE_UMOUNT,
+};
+
+static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
+	[TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
+	[TOMOYO_TYPE_MKCHAR]  = TOMOYO_MAC_FILE_MKCHAR,
+};
+
+static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
+	[TOMOYO_TYPE_LINK]       = TOMOYO_MAC_FILE_LINK,
+	[TOMOYO_TYPE_RENAME]     = TOMOYO_MAC_FILE_RENAME,
+	[TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
+};
+
+static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
+	[TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
+	[TOMOYO_TYPE_MKDIR]  = TOMOYO_MAC_FILE_MKDIR,
+	[TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
+	[TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
+	[TOMOYO_TYPE_IOCTL]  = TOMOYO_MAC_FILE_IOCTL,
+	[TOMOYO_TYPE_CHMOD]  = TOMOYO_MAC_FILE_CHMOD,
+	[TOMOYO_TYPE_CHOWN]  = TOMOYO_MAC_FILE_CHOWN,
+	[TOMOYO_TYPE_CHGRP]  = TOMOYO_MAC_FILE_CHGRP,
 };
 
 void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
@@ -50,56 +90,45 @@
 	if (!ptr)
 		return;
 	if (ptr->is_group)
-		tomoyo_put_path_group(ptr->group);
+		tomoyo_put_group(ptr->group);
 	else
 		tomoyo_put_name(ptr->filename);
 }
 
-bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
-			       const struct tomoyo_name_union *ptr)
+const struct tomoyo_path_info *
+tomoyo_compare_name_union(const struct tomoyo_path_info *name,
+			  const struct tomoyo_name_union *ptr)
 {
 	if (ptr->is_group)
-		return tomoyo_path_matches_group(name, ptr->group, 1);
-	return tomoyo_path_matches_pattern(name, ptr->filename);
+		return tomoyo_path_matches_group(name, ptr->group);
+	if (tomoyo_path_matches_pattern(name, ptr->filename))
+		return ptr->filename;
+	return NULL;
 }
 
-static bool tomoyo_compare_name_union_pattern(const struct tomoyo_path_info
-					      *name,
-					      const struct tomoyo_name_union
-					      *ptr, const bool may_use_pattern)
+void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
+{
+	if (ptr && ptr->is_group)
+		tomoyo_put_group(ptr->group);
+}
+
+bool tomoyo_compare_number_union(const unsigned long value,
+				 const struct tomoyo_number_union *ptr)
 {
 	if (ptr->is_group)
-		return tomoyo_path_matches_group(name, ptr->group,
-						 may_use_pattern);
-	if (may_use_pattern || !ptr->filename->is_patterned)
-		return tomoyo_path_matches_pattern(name, ptr->filename);
-	return false;
+		return tomoyo_number_matches_group(value, value, ptr->group);
+	return value >= ptr->values[0] && value <= ptr->values[1];
 }
 
-/**
- * tomoyo_path2keyword - Get the name of single path operation.
- *
- * @operation: Type of operation.
- *
- * Returns the name of single path operation.
- */
-const char *tomoyo_path2keyword(const u8 operation)
+static void tomoyo_add_slash(struct tomoyo_path_info *buf)
 {
-	return (operation < TOMOYO_MAX_PATH_OPERATION)
-		? tomoyo_path_keyword[operation] : NULL;
-}
-
-/**
- * tomoyo_path22keyword - Get the name of double path operation.
- *
- * @operation: Type of operation.
- *
- * Returns the name of double path operation.
- */
-const char *tomoyo_path22keyword(const u8 operation)
-{
-	return (operation < TOMOYO_MAX_PATH2_OPERATION)
-		? tomoyo_path2_keyword[operation] : NULL;
+	if (buf->is_dir)
+		return;
+	/*
+	 * This is OK because tomoyo_encode() reserves space for appending "/".
+	 */
+	strcat((char *) buf->name, "/");
+	tomoyo_fill_path_info(buf);
 }
 
 /**
@@ -121,69 +150,134 @@
 }
 
 /**
- * tomoyo_get_path - Get realpath.
+ * tomoyo_get_realpath - Get realpath.
  *
+ * @buf:  Pointer to "struct tomoyo_path_info".
  * @path: Pointer to "struct path".
  *
- * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ * Returns true on success, false otherwise.
  */
-static struct tomoyo_path_info *tomoyo_get_path(struct path *path)
+static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
 {
-	int error;
-	struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf),
-							 GFP_NOFS);
-
-	if (!buf)
-		return NULL;
-	/* Reserve one byte for appending "/". */
-	error = tomoyo_realpath_from_path2(path, buf->body,
-					   sizeof(buf->body) - 2);
-	if (!error) {
-		buf->head.name = buf->body;
-		tomoyo_fill_path_info(&buf->head);
-		return &buf->head;
+	buf->name = tomoyo_realpath_from_path(path);
+	if (buf->name) {
+		tomoyo_fill_path_info(buf);
+		return true;
 	}
-	kfree(buf);
-	return NULL;
+        return false;
 }
 
-static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
-				   const char *filename2,
-				   struct tomoyo_domain_info *const domain,
-				   const bool is_delete);
-static int tomoyo_update_path_acl(const u8 type, const char *filename,
-				  struct tomoyo_domain_info *const domain,
-				  const bool is_delete);
-
-/*
- * tomoyo_globally_readable_list is used for holding list of pathnames which
- * are by default allowed to be open()ed for reading by any process.
+/**
+ * tomoyo_audit_path_log - Audit path request log.
  *
- * An entry is added by
+ * @r: Pointer to "struct tomoyo_request_info".
  *
- * # echo 'allow_read /lib/libc-2.5.so' > \
- *                               /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete allow_read /lib/libc-2.5.so' > \
- *                               /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, any process is allowed to
- * open("/lib/libc-2.5.so", O_RDONLY).
- * One exception is, if the domain which current process belongs to is marked
- * as "ignore_global_allow_read", current process can't do so unless explicitly
- * given "allow_read /lib/libc-2.5.so" to the domain which current process
- * belongs to.
+ * Returns 0 on success, negative value otherwise.
  */
-LIST_HEAD(tomoyo_globally_readable_list);
+static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
+{
+	const char *operation = tomoyo_path_keyword[r->param.path.operation];
+	const struct tomoyo_path_info *filename = r->param.path.filename;
+	if (r->granted)
+		return 0;
+	tomoyo_warn_log(r, "%s %s", operation, filename->name);
+	return tomoyo_supervisor(r, "allow_%s %s\n", operation,
+				 tomoyo_pattern(filename));
+}
 
 /**
- * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
+ * tomoyo_audit_path2_log - Audit path/path request log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
+{
+	const char *operation = tomoyo_path2_keyword[r->param.path2.operation];
+	const struct tomoyo_path_info *filename1 = r->param.path2.filename1;
+	const struct tomoyo_path_info *filename2 = r->param.path2.filename2;
+	if (r->granted)
+		return 0;
+	tomoyo_warn_log(r, "%s %s %s", operation, filename1->name,
+			filename2->name);
+	return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
+				 tomoyo_pattern(filename1),
+				 tomoyo_pattern(filename2));
+}
+
+/**
+ * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
+{
+	const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation];
+	const struct tomoyo_path_info *filename = r->param.mkdev.filename;
+	const unsigned int major = r->param.mkdev.major;
+	const unsigned int minor = r->param.mkdev.minor;
+	const unsigned int mode = r->param.mkdev.mode;
+	if (r->granted)
+		return 0;
+	tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode,
+			major, minor);
+	return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation,
+				 tomoyo_pattern(filename), mode, major, minor);
+}
+
+/**
+ * tomoyo_audit_path_number_log - Audit path/number request log.
+ *
+ * @r:     Pointer to "struct tomoyo_request_info".
+ * @error: Error code.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
+{
+	const u8 type = r->param.path_number.operation;
+	u8 radix;
+	const struct tomoyo_path_info *filename = r->param.path_number.filename;
+	const char *operation = tomoyo_path_number_keyword[type];
+	char buffer[64];
+	if (r->granted)
+		return 0;
+	switch (type) {
+	case TOMOYO_TYPE_CREATE:
+	case TOMOYO_TYPE_MKDIR:
+	case TOMOYO_TYPE_MKFIFO:
+	case TOMOYO_TYPE_MKSOCK:
+	case TOMOYO_TYPE_CHMOD:
+		radix = TOMOYO_VALUE_TYPE_OCTAL;
+		break;
+	case TOMOYO_TYPE_IOCTL:
+		radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
+		break;
+	default:
+		radix = TOMOYO_VALUE_TYPE_DECIMAL;
+		break;
+	}
+	tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
+			   radix);
+	tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer);
+	return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
+				 tomoyo_pattern(filename), buffer);
+}
+
+static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a,
+					  const struct tomoyo_acl_head *b)
+{
+	return container_of(a, struct tomoyo_readable_file,
+			    head)->filename ==
+		container_of(b, struct tomoyo_readable_file,
+			     head)->filename;
+}
+
+/**
+ * tomoyo_update_globally_readable_entry - Update "struct tomoyo_readable_file" list.
  *
  * @filename:  Filename unconditionally permitted to open() for reading.
  * @is_delete: True if it is a delete request.
@@ -195,41 +289,24 @@
 static int tomoyo_update_globally_readable_entry(const char *filename,
 						 const bool is_delete)
 {
-	struct tomoyo_globally_readable_file_entry *ptr;
-	struct tomoyo_globally_readable_file_entry e = { };
-	int error = is_delete ? -ENOENT : -ENOMEM;
+	struct tomoyo_readable_file e = { };
+	int error;
 
-	if (!tomoyo_is_correct_path(filename, 1, 0, -1))
+	if (!tomoyo_correct_word(filename))
 		return -EINVAL;
 	e.filename = tomoyo_get_name(filename);
 	if (!e.filename)
 		return -ENOMEM;
-	if (mutex_lock_interruptible(&tomoyo_policy_lock))
-		goto out;
-	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
-		if (ptr->filename != e.filename)
-			continue;
-		ptr->is_deleted = is_delete;
-		error = 0;
-		break;
-	}
-	if (!is_delete && error) {
-		struct tomoyo_globally_readable_file_entry *entry =
-			tomoyo_commit_ok(&e, sizeof(e));
-		if (entry) {
-			list_add_tail_rcu(&entry->list,
-					  &tomoyo_globally_readable_list);
-			error = 0;
-		}
-	}
-	mutex_unlock(&tomoyo_policy_lock);
- out:
+	error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+				     &tomoyo_policy_list
+				     [TOMOYO_ID_GLOBALLY_READABLE],
+				     tomoyo_same_globally_readable);
 	tomoyo_put_name(e.filename);
 	return error;
 }
 
 /**
- * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
+ * tomoyo_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
  *
  * @filename: The filename to check.
  *
@@ -237,14 +314,15 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
+static bool tomoyo_globally_readable_file(const struct tomoyo_path_info *
 					     filename)
 {
-	struct tomoyo_globally_readable_file_entry *ptr;
+	struct tomoyo_readable_file *ptr;
 	bool found = false;
 
-	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
-		if (!ptr->is_deleted &&
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_list
+				[TOMOYO_ID_GLOBALLY_READABLE], head.list) {
+		if (!ptr->head.is_deleted &&
 		    tomoyo_path_matches_pattern(filename, ptr->filename)) {
 			found = true;
 			break;
@@ -254,7 +332,7 @@
 }
 
 /**
- * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list.
+ * tomoyo_write_globally_readable - Write "struct tomoyo_readable_file" list.
  *
  * @data:      String to parse.
  * @is_delete: True if it is a delete request.
@@ -263,74 +341,20 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
+int tomoyo_write_globally_readable(char *data, const bool is_delete)
 {
 	return tomoyo_update_globally_readable_entry(data, is_delete);
 }
 
-/**
- * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
+static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a,
+				const struct tomoyo_acl_head *b)
 {
-	struct list_head *pos;
-	bool done = true;
-
-	list_for_each_cookie(pos, head->read_var2,
-			     &tomoyo_globally_readable_list) {
-		struct tomoyo_globally_readable_file_entry *ptr;
-		ptr = list_entry(pos,
-				 struct tomoyo_globally_readable_file_entry,
-				 list);
-		if (ptr->is_deleted)
-			continue;
-		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
-					ptr->filename->name);
-		if (!done)
-			break;
-	}
-	return done;
+	return container_of(a, struct tomoyo_no_pattern, head)->pattern ==
+		container_of(b, struct tomoyo_no_pattern, head)->pattern;
 }
 
-/* tomoyo_pattern_list is used for holding list of pathnames which are used for
- * converting pathnames to pathname patterns during learning mode.
- *
- * An entry is added by
- *
- * # echo 'file_pattern /proc/\$/mounts' > \
- *                             /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete file_pattern /proc/\$/mounts' > \
- *                             /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, if a process which belongs to a domain which is in
- * learning mode requested open("/proc/1/mounts", O_RDONLY),
- * "allow_read /proc/\$/mounts" is automatically added to the domain which that
- * process belongs to.
- *
- * It is not a desirable behavior that we have to use /proc/\$/ instead of
- * /proc/self/ when current process needs to access only current process's
- * information. As of now, LSM version of TOMOYO is using __d_path() for
- * calculating pathname. Non LSM version of TOMOYO is using its own function
- * which pretends as if /proc/self/ is not a symlink; so that we can forbid
- * current process from accessing other process's information.
- */
-LIST_HEAD(tomoyo_pattern_list);
-
 /**
- * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
+ * tomoyo_update_file_pattern_entry - Update "struct tomoyo_no_pattern" list.
  *
  * @pattern:   Pathname pattern.
  * @is_delete: True if it is a delete request.
@@ -342,39 +366,23 @@
 static int tomoyo_update_file_pattern_entry(const char *pattern,
 					    const bool is_delete)
 {
-	struct tomoyo_pattern_entry *ptr;
-	struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) };
-	int error = is_delete ? -ENOENT : -ENOMEM;
+	struct tomoyo_no_pattern e = { };
+	int error;
 
+	if (!tomoyo_correct_word(pattern))
+		return -EINVAL;
+	e.pattern = tomoyo_get_name(pattern);
 	if (!e.pattern)
-		return error;
-	if (!e.pattern->is_patterned)
-		goto out;
-	if (mutex_lock_interruptible(&tomoyo_policy_lock))
-		goto out;
-	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
-		if (e.pattern != ptr->pattern)
-			continue;
-		ptr->is_deleted = is_delete;
-		error = 0;
-		break;
-	}
-	if (!is_delete && error) {
-		struct tomoyo_pattern_entry *entry =
-			tomoyo_commit_ok(&e, sizeof(e));
-		if (entry) {
-			list_add_tail_rcu(&entry->list, &tomoyo_pattern_list);
-			error = 0;
-		}
-	}
-	mutex_unlock(&tomoyo_policy_lock);
- out:
+		return -ENOMEM;
+	error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+				     &tomoyo_policy_list[TOMOYO_ID_PATTERN],
+				     tomoyo_same_pattern);
 	tomoyo_put_name(e.pattern);
 	return error;
 }
 
 /**
- * tomoyo_get_file_pattern - Get patterned pathname.
+ * tomoyo_pattern - Get patterned pathname.
  *
  * @filename: The filename to find patterned pathname.
  *
@@ -382,14 +390,14 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-static const struct tomoyo_path_info *
-tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
+const char *tomoyo_pattern(const struct tomoyo_path_info *filename)
 {
-	struct tomoyo_pattern_entry *ptr;
+	struct tomoyo_no_pattern *ptr;
 	const struct tomoyo_path_info *pattern = NULL;
 
-	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
-		if (ptr->is_deleted)
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_PATTERN],
+				head.list) {
+		if (ptr->head.is_deleted)
 			continue;
 		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
 			continue;
@@ -403,11 +411,11 @@
 	}
 	if (pattern)
 		filename = pattern;
-	return filename;
+	return filename->name;
 }
 
 /**
- * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list.
+ * tomoyo_write_pattern - Write "struct tomoyo_no_pattern" list.
  *
  * @data:      String to parse.
  * @is_delete: True if it is a delete request.
@@ -416,71 +424,21 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_pattern_policy(char *data, const bool is_delete)
+int tomoyo_write_pattern(char *data, const bool is_delete)
 {
 	return tomoyo_update_file_pattern_entry(data, is_delete);
 }
 
-/**
- * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
+static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a,
+				   const struct tomoyo_acl_head *b)
 {
-	struct list_head *pos;
-	bool done = true;
-
-	list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
-		struct tomoyo_pattern_entry *ptr;
-		ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
-		if (ptr->is_deleted)
-			continue;
-		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN
-					"%s\n", ptr->pattern->name);
-		if (!done)
-			break;
-	}
-	return done;
+	return container_of(a, struct tomoyo_no_rewrite, head)->pattern
+		== container_of(b, struct tomoyo_no_rewrite, head)
+		->pattern;
 }
 
-/*
- * tomoyo_no_rewrite_list is used for holding list of pathnames which are by
- * default forbidden to modify already written content of a file.
- *
- * An entry is added by
- *
- * # echo 'deny_rewrite /var/log/messages' > \
- *                              /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete deny_rewrite /var/log/messages' > \
- *                              /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, if a process requested to rewrite /var/log/messages ,
- * the process can't rewrite unless the domain which that process belongs to
- * has "allow_rewrite /var/log/messages" entry.
- *
- * It is not a desirable behavior that we have to add "\040(deleted)" suffix
- * when we want to allow rewriting already unlink()ed file. As of now,
- * LSM version of TOMOYO is using __d_path() for calculating pathname.
- * Non LSM version of TOMOYO is using its own function which doesn't append
- * " (deleted)" suffix if the file is already unlink()ed; so that we don't
- * need to worry whether the file is already unlink()ed or not.
- */
-LIST_HEAD(tomoyo_no_rewrite_list);
-
 /**
- * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
+ * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite" list.
  *
  * @pattern:   Pathname pattern that are not rewritable by default.
  * @is_delete: True if it is a delete request.
@@ -492,41 +450,23 @@
 static int tomoyo_update_no_rewrite_entry(const char *pattern,
 					  const bool is_delete)
 {
-	struct tomoyo_no_rewrite_entry *ptr;
-	struct tomoyo_no_rewrite_entry e = { };
-	int error = is_delete ? -ENOENT : -ENOMEM;
+	struct tomoyo_no_rewrite e = { };
+	int error;
 
-	if (!tomoyo_is_correct_path(pattern, 0, 0, 0))
+	if (!tomoyo_correct_word(pattern))
 		return -EINVAL;
 	e.pattern = tomoyo_get_name(pattern);
 	if (!e.pattern)
-		return error;
-	if (mutex_lock_interruptible(&tomoyo_policy_lock))
-		goto out;
-	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
-		if (ptr->pattern != e.pattern)
-			continue;
-		ptr->is_deleted = is_delete;
-		error = 0;
-		break;
-	}
-	if (!is_delete && error) {
-		struct tomoyo_no_rewrite_entry *entry =
-			tomoyo_commit_ok(&e, sizeof(e));
-		if (entry) {
-			list_add_tail_rcu(&entry->list,
-					  &tomoyo_no_rewrite_list);
-			error = 0;
-		}
-	}
-	mutex_unlock(&tomoyo_policy_lock);
- out:
+		return -ENOMEM;
+	error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+				     &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
+				     tomoyo_same_no_rewrite);
 	tomoyo_put_name(e.pattern);
 	return error;
 }
 
 /**
- * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
+ * tomoyo_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
  *
  * @filename: Filename to check.
  *
@@ -535,13 +475,14 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
+static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename)
 {
-	struct tomoyo_no_rewrite_entry *ptr;
+	struct tomoyo_no_rewrite *ptr;
 	bool found = false;
 
-	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
-		if (ptr->is_deleted)
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
+				head.list) {
+		if (ptr->head.is_deleted)
 			continue;
 		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
 			continue;
@@ -552,7 +493,7 @@
 }
 
 /**
- * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list.
+ * tomoyo_write_no_rewrite - Write "struct tomoyo_no_rewrite" list.
  *
  * @data:      String to parse.
  * @is_delete: True if it is a delete request.
@@ -561,256 +502,96 @@
  *
  * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
+int tomoyo_write_no_rewrite(char *data, const bool is_delete)
 {
 	return tomoyo_update_no_rewrite_entry(data, is_delete);
 }
 
-/**
- * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
+static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
+				  const struct tomoyo_acl_info *ptr)
 {
-	struct list_head *pos;
-	bool done = true;
-
-	list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) {
-		struct tomoyo_no_rewrite_entry *ptr;
-		ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
-		if (ptr->is_deleted)
-			continue;
-		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE
-					"%s\n", ptr->pattern->name);
-		if (!done)
-			break;
+	const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
+							 head);
+	if (acl->perm & (1 << r->param.path.operation)) {
+		r->param.path.matched_path =
+			tomoyo_compare_name_union(r->param.path.filename,
+						  &acl->name);
+		return r->param.path.matched_path != NULL;
 	}
-	return done;
+	return false;
 }
 
-/**
- * tomoyo_update_file_acl - Update file's read/write/execute ACL.
- *
- * @filename:  Filename.
- * @perm:      Permission (between 1 to 7).
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * This is legacy support interface for older policy syntax.
- * Current policy syntax uses "allow_read/write" instead of "6",
- * "allow_read" instead of "4", "allow_write" instead of "2",
- * "allow_execute" instead of "1".
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_update_file_acl(const char *filename, u8 perm,
-				  struct tomoyo_domain_info * const domain,
+static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
+					 const struct tomoyo_acl_info *ptr)
+{
+	const struct tomoyo_path_number_acl *acl =
+		container_of(ptr, typeof(*acl), head);
+	return (acl->perm & (1 << r->param.path_number.operation)) &&
+		tomoyo_compare_number_union(r->param.path_number.number,
+					    &acl->number) &&
+		tomoyo_compare_name_union(r->param.path_number.filename,
+					  &acl->name);
+}
+
+static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
+				   const struct tomoyo_acl_info *ptr)
+{
+	const struct tomoyo_path2_acl *acl =
+		container_of(ptr, typeof(*acl), head);
+	return (acl->perm & (1 << r->param.path2.operation)) &&
+		tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
+		&& tomoyo_compare_name_union(r->param.path2.filename2,
+					     &acl->name2);
+}
+
+static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
+				const struct tomoyo_acl_info *ptr)
+{
+	const struct tomoyo_mkdev_acl *acl =
+		container_of(ptr, typeof(*acl), head);
+	return (acl->perm & (1 << r->param.mkdev.operation)) &&
+		tomoyo_compare_number_union(r->param.mkdev.mode,
+					    &acl->mode) &&
+		tomoyo_compare_number_union(r->param.mkdev.major,
+					    &acl->major) &&
+		tomoyo_compare_number_union(r->param.mkdev.minor,
+					    &acl->minor) &&
+		tomoyo_compare_name_union(r->param.mkdev.filename,
+					  &acl->name);
+}
+
+static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
+				 const struct tomoyo_acl_info *b)
+{
+	const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
+	const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
+	return tomoyo_same_acl_head(&p1->head, &p2->head) &&
+		tomoyo_same_name_union(&p1->name, &p2->name);
+}
+
+static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
+				  struct tomoyo_acl_info *b,
 				  const bool is_delete)
 {
-	if (perm > 7 || !perm) {
-		printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n",
-		       __func__, perm, filename);
-		return -EINVAL;
+	u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
+		->perm;
+	u16 perm = *a_perm;
+	const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
+	if (is_delete) {
+		perm &= ~b_perm;
+		if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK)
+			perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
+		else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE)))
+			perm &= ~TOMOYO_RW_MASK;
+	} else {
+		perm |= b_perm;
+		if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK)
+			perm |= (1 << TOMOYO_TYPE_READ_WRITE);
+		else if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
+			perm |= TOMOYO_RW_MASK;
 	}
-	if (filename[0] != '@' && tomoyo_strendswith(filename, "/"))
-		/*
-		 * Only 'allow_mkdir' and 'allow_rmdir' are valid for
-		 * directory permissions.
-		 */
-		return 0;
-	if (perm & 4)
-		tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain,
-				       is_delete);
-	if (perm & 2)
-		tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain,
-				       is_delete);
-	if (perm & 1)
-		tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain,
-				       is_delete);
-	return 0;
-}
-
-/**
- * tomoyo_path_acl2 - Check permission for single path operation.
- *
- * @domain:          Pointer to "struct tomoyo_domain_info".
- * @filename:        Filename to check.
- * @perm:            Permission.
- * @may_use_pattern: True if patterned ACL is permitted.
- *
- * Returns 0 on success, -EPERM otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain,
-			    const struct tomoyo_path_info *filename,
-			    const u32 perm, const bool may_use_pattern)
-{
-	struct tomoyo_acl_info *ptr;
-	int error = -EPERM;
-
-	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
-		struct tomoyo_path_acl *acl;
-		if (ptr->type != TOMOYO_TYPE_PATH_ACL)
-			continue;
-		acl = container_of(ptr, struct tomoyo_path_acl, head);
-		if (perm <= 0xFFFF) {
-			if (!(acl->perm & perm))
-				continue;
-		} else {
-			if (!(acl->perm_high & (perm >> 16)))
-				continue;
-		}
-		if (!tomoyo_compare_name_union_pattern(filename, &acl->name,
-                                                       may_use_pattern))
-			continue;
-		error = 0;
-		break;
-	}
-	return error;
-}
-
-/**
- * tomoyo_check_file_acl - Check permission for opening files.
- *
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @filename:  Filename to check.
- * @operation: Mode ("read" or "write" or "read/write" or "execute").
- *
- * Returns 0 on success, -EPERM otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
-				 const struct tomoyo_path_info *filename,
-				 const u8 operation)
-{
-	u32 perm = 0;
-
-	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
-		return 0;
-	if (operation == 6)
-		perm = 1 << TOMOYO_TYPE_READ_WRITE;
-	else if (operation == 4)
-		perm = 1 << TOMOYO_TYPE_READ;
-	else if (operation == 2)
-		perm = 1 << TOMOYO_TYPE_WRITE;
-	else if (operation == 1)
-		perm = 1 << TOMOYO_TYPE_EXECUTE;
-	else
-		BUG();
-	return tomoyo_path_acl2(domain, filename, perm, operation != 1);
-}
-
-/**
- * tomoyo_check_file_perm2 - Check permission for opening files.
- *
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @filename:  Filename to check.
- * @perm:      Mode ("read" or "write" or "read/write" or "execute").
- * @operation: Operation name passed used for verbose mode.
- * @mode:      Access control mode.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
-				   const struct tomoyo_path_info *filename,
-				   const u8 perm, const char *operation,
-				   const u8 mode)
-{
-	const bool is_enforce = (mode == 3);
-	const char *msg = "<unknown>";
-	int error = 0;
-
-	if (!filename)
-		return 0;
-	error = tomoyo_check_file_acl(domain, filename, perm);
-	if (error && perm == 4 && !domain->ignore_global_allow_read
-	    && tomoyo_is_globally_readable_file(filename))
-		error = 0;
-	if (perm == 6)
-		msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE);
-	else if (perm == 4)
-		msg = tomoyo_path2keyword(TOMOYO_TYPE_READ);
-	else if (perm == 2)
-		msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE);
-	else if (perm == 1)
-		msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE);
-	else
-		BUG();
-	if (!error)
-		return 0;
-	if (tomoyo_verbose_mode(domain))
-		printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied "
-		       "for %s\n", tomoyo_get_msg(is_enforce), msg, operation,
-		       filename->name, tomoyo_get_last_name(domain));
-	if (is_enforce)
-		return error;
-	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
-		/* Don't use patterns for execute permission. */
-		const struct tomoyo_path_info *patterned_file = (perm != 1) ?
-			tomoyo_get_file_pattern(filename) : filename;
-		tomoyo_update_file_acl(patterned_file->name, perm,
-				       domain, false);
-	}
-	return 0;
-}
-
-/**
- * tomoyo_write_file_policy - Update file related list.
- *
- * @data:      String to parse.
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
-			     const bool is_delete)
-{
-	char *filename = strchr(data, ' ');
-	char *filename2;
-	unsigned int perm;
-	u8 type;
-
-	if (!filename)
-		return -EINVAL;
-	*filename++ = '\0';
-	if (sscanf(data, "%u", &perm) == 1)
-		return tomoyo_update_file_acl(filename, (u8) perm, domain,
-					      is_delete);
-	if (strncmp(data, "allow_", 6))
-		goto out;
-	data += 6;
-	for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
-		if (strcmp(data, tomoyo_path_keyword[type]))
-			continue;
-		return tomoyo_update_path_acl(type, filename, domain,
-					      is_delete);
-	}
-	filename2 = strchr(filename, ' ');
-	if (!filename2)
-		goto out;
-	*filename2++ = '\0';
-	for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
-		if (strcmp(data, tomoyo_path2_keyword[type]))
-			continue;
-		return tomoyo_update_path2_acl(type, filename, filename2,
-					       domain, is_delete);
-	}
- out:
-	return -EINVAL;
+	*a_perm = perm;
+	return !perm;
 }
 
 /**
@@ -826,70 +607,123 @@
  * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_path_acl(const u8 type, const char *filename,
-				  struct tomoyo_domain_info *const domain,
+				  struct tomoyo_domain_info * const domain,
 				  const bool is_delete)
 {
-	static const u32 tomoyo_rw_mask =
-		(1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE);
-	const u32 perm = 1 << type;
-	struct tomoyo_acl_info *ptr;
 	struct tomoyo_path_acl e = {
 		.head.type = TOMOYO_TYPE_PATH_ACL,
-		.perm_high = perm >> 16,
-		.perm = perm
+		.perm = 1 << type
 	};
-	int error = is_delete ? -ENOENT : -ENOMEM;
-
-	if (type == TOMOYO_TYPE_READ_WRITE)
-		e.perm |= tomoyo_rw_mask;
-	if (!domain)
-		return -EINVAL;
+	int error;
+	if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE))
+		e.perm |= TOMOYO_RW_MASK;
 	if (!tomoyo_parse_name_union(filename, &e.name))
 		return -EINVAL;
-	if (mutex_lock_interruptible(&tomoyo_policy_lock))
-		goto out;
-	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
-		struct tomoyo_path_acl *acl =
-			container_of(ptr, struct tomoyo_path_acl, head);
-		if (!tomoyo_is_same_path_acl(acl, &e))
-			continue;
-		if (is_delete) {
-			if (perm <= 0xFFFF)
-				acl->perm &= ~perm;
-			else
-				acl->perm_high &= ~(perm >> 16);
-			if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask)
-				acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
-			else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)))
-				acl->perm &= ~tomoyo_rw_mask;
-		} else {
-			if (perm <= 0xFFFF)
-				acl->perm |= perm;
-			else
-				acl->perm_high |= (perm >> 16);
-			if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask)
-				acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE;
-			else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))
-				acl->perm |= tomoyo_rw_mask;
-		}
-		error = 0;
-		break;
-	}
-	if (!is_delete && error) {
-		struct tomoyo_path_acl *entry =
-			tomoyo_commit_ok(&e, sizeof(e));
-		if (entry) {
-			list_add_tail_rcu(&entry->head.list,
-					  &domain->acl_info_list);
-			error = 0;
-		}
-	}
-	mutex_unlock(&tomoyo_policy_lock);
- out:
+	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+				     tomoyo_same_path_acl,
+				     tomoyo_merge_path_acl);
 	tomoyo_put_name_union(&e.name);
 	return error;
 }
 
+static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
+					 const struct tomoyo_acl_info *b)
+{
+	const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1),
+								head);
+	const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2),
+								head);
+	return tomoyo_same_acl_head(&p1->head, &p2->head)
+		&& tomoyo_same_name_union(&p1->name, &p2->name)
+		&& tomoyo_same_number_union(&p1->mode, &p2->mode)
+		&& tomoyo_same_number_union(&p1->major, &p2->major)
+		&& tomoyo_same_number_union(&p1->minor, &p2->minor);
+}
+
+static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
+					  struct tomoyo_acl_info *b,
+					  const bool is_delete)
+{
+	u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
+					 head)->perm;
+	u8 perm = *a_perm;
+	const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
+		->perm;
+	if (is_delete)
+		perm &= ~b_perm;
+	else
+		perm |= b_perm;
+	*a_perm = perm;
+	return !perm;
+}
+
+/**
+ * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
+ *
+ * @type:      Type of operation.
+ * @filename:  Filename.
+ * @mode:      Create mode.
+ * @major:     Device major number.
+ * @minor:     Device minor number.
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_update_mkdev_acl(const u8 type, const char *filename,
+					  char *mode, char *major, char *minor,
+					  struct tomoyo_domain_info * const
+					  domain, const bool is_delete)
+{
+	struct tomoyo_mkdev_acl e = {
+		.head.type = TOMOYO_TYPE_MKDEV_ACL,
+		.perm = 1 << type
+	};
+	int error = is_delete ? -ENOENT : -ENOMEM;
+	if (!tomoyo_parse_name_union(filename, &e.name) ||
+	    !tomoyo_parse_number_union(mode, &e.mode) ||
+	    !tomoyo_parse_number_union(major, &e.major) ||
+	    !tomoyo_parse_number_union(minor, &e.minor))
+		goto out;
+	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+				     tomoyo_same_mkdev_acl,
+				     tomoyo_merge_mkdev_acl);
+ out:
+	tomoyo_put_name_union(&e.name);
+	tomoyo_put_number_union(&e.mode);
+	tomoyo_put_number_union(&e.major);
+	tomoyo_put_number_union(&e.minor);
+	return error;
+}
+
+static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
+				  const struct tomoyo_acl_info *b)
+{
+	const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
+	const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
+	return tomoyo_same_acl_head(&p1->head, &p2->head)
+		&& tomoyo_same_name_union(&p1->name1, &p2->name1)
+		&& tomoyo_same_name_union(&p1->name2, &p2->name2);
+}
+
+static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
+				   struct tomoyo_acl_info *b,
+				   const bool is_delete)
+{
+	u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
+		->perm;
+	u8 perm = *a_perm;
+	const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
+	if (is_delete)
+		perm &= ~b_perm;
+	else
+		perm |= b_perm;
+	*a_perm = perm;
+	return !perm;
+}
+
 /**
  * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
  *
@@ -905,46 +739,20 @@
  */
 static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
 				   const char *filename2,
-				   struct tomoyo_domain_info *const domain,
+				   struct tomoyo_domain_info * const domain,
 				   const bool is_delete)
 {
-	const u8 perm = 1 << type;
 	struct tomoyo_path2_acl e = {
 		.head.type = TOMOYO_TYPE_PATH2_ACL,
-		.perm = perm
+		.perm = 1 << type
 	};
-	struct tomoyo_acl_info *ptr;
 	int error = is_delete ? -ENOENT : -ENOMEM;
-
-	if (!domain)
-		return -EINVAL;
 	if (!tomoyo_parse_name_union(filename1, &e.name1) ||
 	    !tomoyo_parse_name_union(filename2, &e.name2))
 		goto out;
-	if (mutex_lock_interruptible(&tomoyo_policy_lock))
-		goto out;
-	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
-		struct tomoyo_path2_acl *acl =
-			container_of(ptr, struct tomoyo_path2_acl, head);
-		if (!tomoyo_is_same_path2_acl(acl, &e))
-			continue;
-		if (is_delete)
-			acl->perm &= ~perm;
-		else
-			acl->perm |= perm;
-		error = 0;
-		break;
-	}
-	if (!is_delete && error) {
-		struct tomoyo_path2_acl *entry =
-			tomoyo_commit_ok(&e, sizeof(e));
-		if (entry) {
-			list_add_tail_rcu(&entry->head.list,
-					  &domain->acl_info_list);
-			error = 0;
-		}
-	}
-	mutex_unlock(&tomoyo_policy_lock);
+	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+				     tomoyo_same_path2_acl,
+				     tomoyo_merge_path2_acl);
  out:
 	tomoyo_put_name_union(&e.name1);
 	tomoyo_put_name_union(&e.name2);
@@ -952,134 +760,158 @@
 }
 
 /**
- * tomoyo_path_acl - Check permission for single path operation.
+ * tomoyo_path_permission - Check permission for single path operation.
  *
- * @domain:   Pointer to "struct tomoyo_domain_info".
- * @type:     Type of operation.
- * @filename: Filename to check.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type,
-			   const struct tomoyo_path_info *filename)
-{
-	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
-		return 0;
-	return tomoyo_path_acl2(domain, filename, 1 << type, 1);
-}
-
-/**
- * tomoyo_path2_acl - Check permission for double path operation.
- *
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @type:      Type of operation.
- * @filename1: First filename to check.
- * @filename2: Second filename to check.
- *
- * Returns 0 on success, -EPERM otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain,
-			    const u8 type,
-			    const struct tomoyo_path_info *filename1,
-			    const struct tomoyo_path_info *filename2)
-{
-	struct tomoyo_acl_info *ptr;
-	const u8 perm = 1 << type;
-	int error = -EPERM;
-
-	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
-		return 0;
-	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
-		struct tomoyo_path2_acl *acl;
-		if (ptr->type != TOMOYO_TYPE_PATH2_ACL)
-			continue;
-		acl = container_of(ptr, struct tomoyo_path2_acl, head);
-		if (!(acl->perm & perm))
-			continue;
-		if (!tomoyo_compare_name_union(filename1, &acl->name1))
-			continue;
-		if (!tomoyo_compare_name_union(filename2, &acl->name2))
-			continue;
-		error = 0;
-		break;
-	}
-	return error;
-}
-
-/**
- * tomoyo_path_permission2 - Check permission for single path operation.
- *
- * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @r:         Pointer to "struct tomoyo_request_info".
  * @operation: Type of operation.
  * @filename:  Filename to check.
- * @mode:      Access control mode.
  *
  * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain,
-				   u8 operation,
-				   const struct tomoyo_path_info *filename,
-				   const u8 mode)
+int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
+			   const struct tomoyo_path_info *filename)
 {
-	const char *msg;
 	int error;
-	const bool is_enforce = (mode == 3);
 
-	if (!mode)
-		return 0;
  next:
-	error = tomoyo_path_acl(domain, operation, filename);
-	msg = tomoyo_path2keyword(operation);
-	if (!error)
-		goto ok;
-	if (tomoyo_verbose_mode(domain))
-		printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n",
-		       tomoyo_get_msg(is_enforce), msg, filename->name,
-		       tomoyo_get_last_name(domain));
-	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
-		const char *name = tomoyo_get_file_pattern(filename)->name;
-		tomoyo_update_path_acl(operation, name, domain, false);
-	}
-	if (!is_enforce)
-		error = 0;
- ok:
+	r->type = tomoyo_p2mac[operation];
+	r->mode = tomoyo_get_mode(r->profile, r->type);
+	if (r->mode == TOMOYO_CONFIG_DISABLED)
+		return 0;
+	r->param_type = TOMOYO_TYPE_PATH_ACL;
+	r->param.path.filename = filename;
+	r->param.path.operation = operation;
+	do {
+		tomoyo_check_acl(r, tomoyo_check_path_acl);
+		if (!r->granted && operation == TOMOYO_TYPE_READ &&
+		    !r->domain->ignore_global_allow_read &&
+		    tomoyo_globally_readable_file(filename))
+			r->granted = true;
+		error = tomoyo_audit_path_log(r);
+		/*
+		 * Do not retry for execute request, for alias may have
+		 * changed.
+		 */
+	} while (error == TOMOYO_RETRY_REQUEST &&
+		 operation != TOMOYO_TYPE_EXECUTE);
 	/*
 	 * Since "allow_truncate" doesn't imply "allow_rewrite" permission,
 	 * we need to check "allow_rewrite" permission if the filename is
 	 * specified by "deny_rewrite" keyword.
 	 */
 	if (!error && operation == TOMOYO_TYPE_TRUNCATE &&
-	    tomoyo_is_no_rewrite_file(filename)) {
+	    tomoyo_no_rewrite_file(filename)) {
 		operation = TOMOYO_TYPE_REWRITE;
 		goto next;
 	}
 	return error;
 }
 
-/**
- * tomoyo_check_exec_perm - Check permission for "execute".
- *
- * @domain:   Pointer to "struct tomoyo_domain_info".
- * @filename: Check permission for "execute".
- *
- * Returns 0 on success, negativevalue otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
-			   const struct tomoyo_path_info *filename)
+static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
+					const struct tomoyo_acl_info *b)
 {
-	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
+	const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
+							       head);
+	const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
+							       head);
+	return tomoyo_same_acl_head(&p1->head, &p2->head)
+		&& tomoyo_same_name_union(&p1->name, &p2->name)
+		&& tomoyo_same_number_union(&p1->number, &p2->number);
+}
 
-	if (!mode)
+static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
+					 struct tomoyo_acl_info *b,
+					 const bool is_delete)
+{
+	u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
+					  head)->perm;
+	u8 perm = *a_perm;
+	const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
+		->perm;
+	if (is_delete)
+		perm &= ~b_perm;
+	else
+		perm |= b_perm;
+	*a_perm = perm;
+	return !perm;
+}
+
+/**
+ * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
+ *
+ * @type:      Type of operation.
+ * @filename:  Filename.
+ * @number:    Number.
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_path_number_acl(const u8 type, const char *filename,
+					 char *number,
+					 struct tomoyo_domain_info * const
+					 domain,
+					 const bool is_delete)
+{
+	struct tomoyo_path_number_acl e = {
+		.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
+		.perm = 1 << type
+	};
+	int error = is_delete ? -ENOENT : -ENOMEM;
+	if (!tomoyo_parse_name_union(filename, &e.name))
+		return -EINVAL;
+	if (!tomoyo_parse_number_union(number, &e.number))
+		goto out;
+	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+				     tomoyo_same_path_number_acl,
+				     tomoyo_merge_path_number_acl);
+ out:
+	tomoyo_put_name_union(&e.name);
+	tomoyo_put_number_union(&e.number);
+	return error;
+}
+
+/**
+ * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
+ *
+ * @type:   Type of operation.
+ * @path:   Pointer to "struct path".
+ * @number: Number.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_path_number_perm(const u8 type, struct path *path,
+			    unsigned long number)
+{
+	struct tomoyo_request_info r;
+	int error = -ENOMEM;
+	struct tomoyo_path_info buf;
+	int idx;
+
+	if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
+	    == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry)
 		return 0;
-	return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode);
+	idx = tomoyo_read_lock();
+	if (!tomoyo_get_realpath(&buf, path))
+		goto out;
+	if (type == TOMOYO_TYPE_MKDIR)
+		tomoyo_add_slash(&buf);
+	r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
+	r.param.path_number.operation = type;
+	r.param.path_number.filename = &buf;
+	r.param.path_number.number = number;
+	do {
+		tomoyo_check_acl(&r, tomoyo_check_path_number_acl);
+		error = tomoyo_audit_path_number_log(&r);
+	} while (error == TOMOYO_RETRY_REQUEST);
+	kfree(buf.name);
+ out:
+	tomoyo_read_unlock(idx);
+	if (r.mode != TOMOYO_CONFIG_ENFORCING)
+		error = 0;
+	return error;
 }
 
 /**
@@ -1096,24 +928,17 @@
 {
 	const u8 acc_mode = ACC_MODE(flag);
 	int error = -ENOMEM;
-	struct tomoyo_path_info *buf;
-	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
-	const bool is_enforce = (mode == 3);
+	struct tomoyo_path_info buf;
+	struct tomoyo_request_info r;
 	int idx;
 
-	if (!mode || !path->mnt)
+	if (!path->mnt ||
+	    (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)))
 		return 0;
-	if (acc_mode == 0)
-		return 0;
-	if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))
-		/*
-		 * I don't check directories here because mkdir() and rmdir()
-		 * don't call me.
-		 */
-		return 0;
+	buf.name = NULL;
+	r.mode = TOMOYO_CONFIG_DISABLED;
 	idx = tomoyo_read_lock();
-	buf = tomoyo_get_path(path);
-	if (!buf)
+	if (!tomoyo_get_realpath(&buf, path))
 		goto out;
 	error = 0;
 	/*
@@ -1121,28 +946,43 @@
 	 * we need to check "allow_rewrite" permission when the filename is not
 	 * opened for append mode or the filename is truncated at open time.
 	 */
-	if ((acc_mode & MAY_WRITE) &&
-	    ((flag & O_TRUNC) || !(flag & O_APPEND)) &&
-	    (tomoyo_is_no_rewrite_file(buf))) {
-		error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE,
-						buf, mode);
+	if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND)
+	    && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE)
+	    != TOMOYO_CONFIG_DISABLED) {
+		if (!tomoyo_get_realpath(&buf, path)) {
+			error = -ENOMEM;
+			goto out;
+		}
+		if (tomoyo_no_rewrite_file(&buf))
+			error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE,
+						       &buf);
 	}
-	if (!error)
-		error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open",
-						mode);
-	if (!error && (flag & O_TRUNC))
-		error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE,
-						buf, mode);
+	if (!error && acc_mode &&
+	    tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
+	    != TOMOYO_CONFIG_DISABLED) {
+		u8 operation;
+		if (!buf.name && !tomoyo_get_realpath(&buf, path)) {
+			error = -ENOMEM;
+			goto out;
+		}
+		if (acc_mode == (MAY_READ | MAY_WRITE))
+			operation = TOMOYO_TYPE_READ_WRITE;
+		else if (acc_mode == MAY_READ)
+			operation = TOMOYO_TYPE_READ;
+		else
+			operation = TOMOYO_TYPE_WRITE;
+		error = tomoyo_path_permission(&r, operation, &buf);
+	}
  out:
-	kfree(buf);
+	kfree(buf.name);
 	tomoyo_read_unlock(idx);
-	if (!is_enforce)
+	if (r.mode != TOMOYO_CONFIG_ENFORCING)
 		error = 0;
 	return error;
 }
 
 /**
- * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount".
+ * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount".
  *
  * @operation: Type of operation.
  * @path:      Pointer to "struct path".
@@ -1152,71 +992,79 @@
 int tomoyo_path_perm(const u8 operation, struct path *path)
 {
 	int error = -ENOMEM;
-	struct tomoyo_path_info *buf;
-	struct tomoyo_domain_info *domain = tomoyo_domain();
-	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
-	const bool is_enforce = (mode == 3);
+	struct tomoyo_path_info buf;
+	struct tomoyo_request_info r;
 	int idx;
 
-	if (!mode || !path->mnt)
+	if (!path->mnt)
 		return 0;
+	if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
+	    == TOMOYO_CONFIG_DISABLED)
+		return 0;
+	buf.name = NULL;
 	idx = tomoyo_read_lock();
-	buf = tomoyo_get_path(path);
-	if (!buf)
+	if (!tomoyo_get_realpath(&buf, path))
 		goto out;
 	switch (operation) {
-	case TOMOYO_TYPE_MKDIR:
+	case TOMOYO_TYPE_REWRITE:
+		if (!tomoyo_no_rewrite_file(&buf)) {
+			error = 0;
+			goto out;
+		}
+		break;
 	case TOMOYO_TYPE_RMDIR:
 	case TOMOYO_TYPE_CHROOT:
-		if (!buf->is_dir) {
-			/*
-			 * tomoyo_get_path() reserves space for appending "/."
-			 */
-			strcat((char *) buf->name, "/");
-			tomoyo_fill_path_info(buf);
-		}
+	case TOMOYO_TYPE_UMOUNT:
+		tomoyo_add_slash(&buf);
+		break;
 	}
-	error = tomoyo_path_permission2(domain, operation, buf, mode);
+	error = tomoyo_path_permission(&r, operation, &buf);
  out:
-	kfree(buf);
+	kfree(buf.name);
 	tomoyo_read_unlock(idx);
-	if (!is_enforce)
+	if (r.mode != TOMOYO_CONFIG_ENFORCING)
 		error = 0;
 	return error;
 }
 
 /**
- * tomoyo_check_rewrite_permission - Check permission for "rewrite".
+ * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
  *
- * @filp: Pointer to "struct file".
+ * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
+ * @path:      Pointer to "struct path".
+ * @mode:      Create mode.
+ * @dev:       Device number.
  *
  * Returns 0 on success, negative value otherwise.
  */
-int tomoyo_check_rewrite_permission(struct file *filp)
+int tomoyo_mkdev_perm(const u8 operation, struct path *path,
+			     const unsigned int mode, unsigned int dev)
 {
+	struct tomoyo_request_info r;
 	int error = -ENOMEM;
-	struct tomoyo_domain_info *domain = tomoyo_domain();
-	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
-	const bool is_enforce = (mode == 3);
-	struct tomoyo_path_info *buf;
+	struct tomoyo_path_info buf;
 	int idx;
 
-	if (!mode || !filp->f_path.mnt)
+	if (!path->mnt ||
+	    tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
+	    == TOMOYO_CONFIG_DISABLED)
 		return 0;
-
 	idx = tomoyo_read_lock();
-	buf = tomoyo_get_path(&filp->f_path);
-	if (!buf)
-		goto out;
-	if (!tomoyo_is_no_rewrite_file(buf)) {
-		error = 0;
-		goto out;
+	error = -ENOMEM;
+	if (tomoyo_get_realpath(&buf, path)) {
+		dev = new_decode_dev(dev);
+		r.param_type = TOMOYO_TYPE_MKDEV_ACL;
+		r.param.mkdev.filename = &buf;
+		r.param.mkdev.operation = operation;
+		r.param.mkdev.mode = mode;
+		r.param.mkdev.major = MAJOR(dev);
+		r.param.mkdev.minor = MINOR(dev);
+		tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
+		error = tomoyo_audit_mkdev_log(&r);
+		kfree(buf.name);
 	}
-	error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode);
- out:
-	kfree(buf);
 	tomoyo_read_unlock(idx);
-	if (!is_enforce)
+	if (r.mode != TOMOYO_CONFIG_ENFORCING)
 		error = 0;
 	return error;
 }
@@ -1234,56 +1082,99 @@
 		      struct path *path2)
 {
 	int error = -ENOMEM;
-	struct tomoyo_path_info *buf1, *buf2;
-	struct tomoyo_domain_info *domain = tomoyo_domain();
-	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
-	const bool is_enforce = (mode == 3);
-	const char *msg;
+	struct tomoyo_path_info buf1;
+	struct tomoyo_path_info buf2;
+	struct tomoyo_request_info r;
 	int idx;
 
-	if (!mode || !path1->mnt || !path2->mnt)
+	if (!path1->mnt || !path2->mnt ||
+	    tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
+	    == TOMOYO_CONFIG_DISABLED)
 		return 0;
+	buf1.name = NULL;
+	buf2.name = NULL;
 	idx = tomoyo_read_lock();
-	buf1 = tomoyo_get_path(path1);
-	buf2 = tomoyo_get_path(path2);
-	if (!buf1 || !buf2)
+	if (!tomoyo_get_realpath(&buf1, path1) ||
+	    !tomoyo_get_realpath(&buf2, path2))
 		goto out;
-	{
-		struct dentry *dentry = path1->dentry;
-		if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
-			/*
-			 * tomoyo_get_path() reserves space for appending "/."
-			 */
-			if (!buf1->is_dir) {
-				strcat((char *) buf1->name, "/");
-				tomoyo_fill_path_info(buf1);
-			}
-			if (!buf2->is_dir) {
-				strcat((char *) buf2->name, "/");
-				tomoyo_fill_path_info(buf2);
-			}
-		}
-	}
-	error = tomoyo_path2_acl(domain, operation, buf1, buf2);
-	msg = tomoyo_path22keyword(operation);
-	if (!error)
-		goto out;
-	if (tomoyo_verbose_mode(domain))
-		printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' "
-		       "denied for %s\n", tomoyo_get_msg(is_enforce),
-		       msg, buf1->name, buf2->name,
-		       tomoyo_get_last_name(domain));
-	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
-		const char *name1 = tomoyo_get_file_pattern(buf1)->name;
-		const char *name2 = tomoyo_get_file_pattern(buf2)->name;
-		tomoyo_update_path2_acl(operation, name1, name2, domain,
-					false);
-	}
+	switch (operation) {
+		struct dentry *dentry;
+	case TOMOYO_TYPE_RENAME:
+        case TOMOYO_TYPE_LINK:
+		dentry = path1->dentry;
+	        if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
+                        break;
+                /* fall through */
+        case TOMOYO_TYPE_PIVOT_ROOT:
+                tomoyo_add_slash(&buf1);
+                tomoyo_add_slash(&buf2);
+		break;
+        }
+	r.param_type = TOMOYO_TYPE_PATH2_ACL;
+	r.param.path2.operation = operation;
+	r.param.path2.filename1 = &buf1;
+	r.param.path2.filename2 = &buf2;
+	do {
+		tomoyo_check_acl(&r, tomoyo_check_path2_acl);
+		error = tomoyo_audit_path2_log(&r);
+	} while (error == TOMOYO_RETRY_REQUEST);
  out:
-	kfree(buf1);
-	kfree(buf2);
+	kfree(buf1.name);
+	kfree(buf2.name);
 	tomoyo_read_unlock(idx);
-	if (!is_enforce)
+	if (r.mode != TOMOYO_CONFIG_ENFORCING)
 		error = 0;
 	return error;
 }
+
+/**
+ * tomoyo_write_file - Update file related list.
+ *
+ * @data:      String to parse.
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
+		      const bool is_delete)
+{
+	char *w[5];
+	u8 type;
+	if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
+		return -EINVAL;
+	if (strncmp(w[0], "allow_", 6))
+		goto out;
+	w[0] += 6;
+	for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
+		if (strcmp(w[0], tomoyo_path_keyword[type]))
+			continue;
+		return tomoyo_update_path_acl(type, w[1], domain, is_delete);
+	}
+	if (!w[2][0])
+		goto out;
+	for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
+		if (strcmp(w[0], tomoyo_path2_keyword[type]))
+			continue;
+		return tomoyo_update_path2_acl(type, w[1], w[2], domain,
+					       is_delete);
+	}
+	for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) {
+		if (strcmp(w[0], tomoyo_path_number_keyword[type]))
+			continue;
+		return tomoyo_update_path_number_acl(type, w[1], w[2], domain,
+						     is_delete);
+	}
+	if (!w[3][0] || !w[4][0])
+		goto out;
+	for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) {
+		if (strcmp(w[0], tomoyo_mkdev_keyword[type]))
+			continue;
+		return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3],
+					       w[4], domain, is_delete);
+	}
+ out:
+	return -EINVAL;
+}
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c
index b9cc71b..a877e4c 100644
--- a/security/tomoyo/gc.c
+++ b/security/tomoyo/gc.c
@@ -11,83 +11,75 @@
 #include <linux/kthread.h>
 #include <linux/slab.h>
 
-enum tomoyo_gc_id {
-	TOMOYO_ID_PATH_GROUP,
-	TOMOYO_ID_PATH_GROUP_MEMBER,
-	TOMOYO_ID_DOMAIN_INITIALIZER,
-	TOMOYO_ID_DOMAIN_KEEPER,
-	TOMOYO_ID_ALIAS,
-	TOMOYO_ID_GLOBALLY_READABLE,
-	TOMOYO_ID_PATTERN,
-	TOMOYO_ID_NO_REWRITE,
-	TOMOYO_ID_MANAGER,
-	TOMOYO_ID_NAME,
-	TOMOYO_ID_ACL,
-	TOMOYO_ID_DOMAIN
-};
-
-struct tomoyo_gc_entry {
+struct tomoyo_gc {
 	struct list_head list;
 	int type;
-	void *element;
+	struct list_head *element;
 };
 static LIST_HEAD(tomoyo_gc_queue);
 static DEFINE_MUTEX(tomoyo_gc_mutex);
 
 /* Caller holds tomoyo_policy_lock mutex. */
-static bool tomoyo_add_to_gc(const int type, void *element)
+static bool tomoyo_add_to_gc(const int type, struct list_head *element)
 {
-	struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+	struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 	if (!entry)
 		return false;
 	entry->type = type;
 	entry->element = element;
 	list_add(&entry->list, &tomoyo_gc_queue);
+	list_del_rcu(element);
 	return true;
 }
 
-static void tomoyo_del_allow_read
-(struct tomoyo_globally_readable_file_entry *ptr)
+static void tomoyo_del_allow_read(struct list_head *element)
 {
+	struct tomoyo_readable_file *ptr =
+		container_of(element, typeof(*ptr), head.list);
 	tomoyo_put_name(ptr->filename);
 }
 
-static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr)
+static void tomoyo_del_file_pattern(struct list_head *element)
 {
+	struct tomoyo_no_pattern *ptr =
+		container_of(element, typeof(*ptr), head.list);
 	tomoyo_put_name(ptr->pattern);
 }
 
-static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr)
+static void tomoyo_del_no_rewrite(struct list_head *element)
 {
+	struct tomoyo_no_rewrite *ptr =
+		container_of(element, typeof(*ptr), head.list);
 	tomoyo_put_name(ptr->pattern);
 }
 
-static void tomoyo_del_domain_initializer
-(struct tomoyo_domain_initializer_entry *ptr)
+static void tomoyo_del_transition_control(struct list_head *element)
 {
+	struct tomoyo_transition_control *ptr =
+		container_of(element, typeof(*ptr), head.list);
 	tomoyo_put_name(ptr->domainname);
 	tomoyo_put_name(ptr->program);
 }
 
-static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr)
+static void tomoyo_del_aggregator(struct list_head *element)
 {
-	tomoyo_put_name(ptr->domainname);
-	tomoyo_put_name(ptr->program);
-}
-
-static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr)
-{
+	struct tomoyo_aggregator *ptr =
+		container_of(element, typeof(*ptr), head.list);
 	tomoyo_put_name(ptr->original_name);
-	tomoyo_put_name(ptr->aliased_name);
+	tomoyo_put_name(ptr->aggregated_name);
 }
 
-static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr)
+static void tomoyo_del_manager(struct list_head *element)
 {
+	struct tomoyo_manager *ptr =
+		container_of(element, typeof(*ptr), head.list);
 	tomoyo_put_name(ptr->manager);
 }
 
-static void tomoyo_del_acl(struct tomoyo_acl_info *acl)
+static void tomoyo_del_acl(struct list_head *element)
 {
+	struct tomoyo_acl_info *acl =
+		container_of(element, typeof(*acl), list);
 	switch (acl->type) {
 	case TOMOYO_TYPE_PATH_ACL:
 		{
@@ -104,14 +96,41 @@
 			tomoyo_put_name_union(&entry->name2);
 		}
 		break;
-	default:
-		printk(KERN_WARNING "Unknown type\n");
+	case TOMOYO_TYPE_PATH_NUMBER_ACL:
+		{
+			struct tomoyo_path_number_acl *entry
+				= container_of(acl, typeof(*entry), head);
+			tomoyo_put_name_union(&entry->name);
+			tomoyo_put_number_union(&entry->number);
+		}
+		break;
+	case TOMOYO_TYPE_MKDEV_ACL:
+		{
+			struct tomoyo_mkdev_acl *entry
+				= container_of(acl, typeof(*entry), head);
+			tomoyo_put_name_union(&entry->name);
+			tomoyo_put_number_union(&entry->mode);
+			tomoyo_put_number_union(&entry->major);
+			tomoyo_put_number_union(&entry->minor);
+		}
+		break;
+	case TOMOYO_TYPE_MOUNT_ACL:
+		{
+			struct tomoyo_mount_acl *entry
+				= container_of(acl, typeof(*entry), head);
+			tomoyo_put_name_union(&entry->dev_name);
+			tomoyo_put_name_union(&entry->dir_name);
+			tomoyo_put_name_union(&entry->fs_type);
+			tomoyo_put_number_union(&entry->flags);
+		}
 		break;
 	}
 }
 
-static bool tomoyo_del_domain(struct tomoyo_domain_info *domain)
+static bool tomoyo_del_domain(struct list_head *element)
 {
+	struct tomoyo_domain_info *domain =
+		container_of(element, typeof(*domain), list);
 	struct tomoyo_acl_info *acl;
 	struct tomoyo_acl_info *tmp;
 	/*
@@ -139,7 +158,7 @@
 	if (atomic_read(&domain->users))
 		return false;
 	list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
-		tomoyo_del_acl(acl);
+		tomoyo_del_acl(&acl->list);
 		tomoyo_memory_free(acl);
 	}
 	tomoyo_put_name(domain->domainname);
@@ -147,135 +166,70 @@
 }
 
 
-static void tomoyo_del_name(const struct tomoyo_name_entry *ptr)
+static void tomoyo_del_name(struct list_head *element)
 {
+	const struct tomoyo_name *ptr =
+		container_of(element, typeof(*ptr), list);
 }
 
-static void tomoyo_del_path_group_member(struct tomoyo_path_group_member
-					 *member)
+static void tomoyo_del_path_group(struct list_head *element)
 {
+	struct tomoyo_path_group *member =
+		container_of(element, typeof(*member), head.list);
 	tomoyo_put_name(member->member_name);
 }
 
-static void tomoyo_del_path_group(struct tomoyo_path_group *group)
+static void tomoyo_del_group(struct list_head *element)
 {
+	struct tomoyo_group *group =
+		container_of(element, typeof(*group), list);
 	tomoyo_put_name(group->group_name);
 }
 
+static void tomoyo_del_number_group(struct list_head *element)
+{
+	struct tomoyo_number_group *member =
+		container_of(element, typeof(*member), head.list);
+}
+
+static bool tomoyo_collect_member(struct list_head *member_list, int id)
+{
+	struct tomoyo_acl_head *member;
+	list_for_each_entry(member, member_list, list) {
+		if (!member->is_deleted)
+			continue;
+		if (!tomoyo_add_to_gc(id, &member->list))
+			return false;
+	}
+        return true;
+}
+
+static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain)
+{
+	struct tomoyo_acl_info *acl;
+	list_for_each_entry(acl, &domain->acl_info_list, list) {
+		if (!acl->is_deleted)
+			continue;
+		if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list))
+			return false;
+	}
+	return true;
+}
+
 static void tomoyo_collect_entry(void)
 {
+	int i;
 	if (mutex_lock_interruptible(&tomoyo_policy_lock))
 		return;
-	{
-		struct tomoyo_globally_readable_file_entry *ptr;
-		list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list,
-					list) {
-			if (!ptr->is_deleted)
-				continue;
-			if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr))
-				list_del_rcu(&ptr->list);
-			else
-				break;
-		}
-	}
-	{
-		struct tomoyo_pattern_entry *ptr;
-		list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
-			if (!ptr->is_deleted)
-				continue;
-			if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr))
-				list_del_rcu(&ptr->list);
-			else
-				break;
-		}
-	}
-	{
-		struct tomoyo_no_rewrite_entry *ptr;
-		list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
-			if (!ptr->is_deleted)
-				continue;
-			if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr))
-				list_del_rcu(&ptr->list);
-			else
-				break;
-		}
-	}
-	{
-		struct tomoyo_domain_initializer_entry *ptr;
-		list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list,
-					list) {
-			if (!ptr->is_deleted)
-				continue;
-			if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr))
-				list_del_rcu(&ptr->list);
-			else
-				break;
-		}
-	}
-	{
-		struct tomoyo_domain_keeper_entry *ptr;
-		list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
-			if (!ptr->is_deleted)
-				continue;
-			if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr))
-				list_del_rcu(&ptr->list);
-			else
-				break;
-		}
-	}
-	{
-		struct tomoyo_alias_entry *ptr;
-		list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
-			if (!ptr->is_deleted)
-				continue;
-			if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr))
-				list_del_rcu(&ptr->list);
-			else
-				break;
-		}
-	}
-	{
-		struct tomoyo_policy_manager_entry *ptr;
-		list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list,
-					list) {
-			if (!ptr->is_deleted)
-				continue;
-			if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr))
-				list_del_rcu(&ptr->list);
-			else
-				break;
-		}
+	for (i = 0; i < TOMOYO_MAX_POLICY; i++) {
+		if (!tomoyo_collect_member(&tomoyo_policy_list[i], i))
+			goto unlock;
 	}
 	{
 		struct tomoyo_domain_info *domain;
 		list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
-			struct tomoyo_acl_info *acl;
-			list_for_each_entry_rcu(acl, &domain->acl_info_list,
-						list) {
-				switch (acl->type) {
-				case TOMOYO_TYPE_PATH_ACL:
-					if (container_of(acl,
-					 struct tomoyo_path_acl,
-							 head)->perm ||
-					    container_of(acl,
-					 struct tomoyo_path_acl,
-							 head)->perm_high)
-						continue;
-					break;
-				case TOMOYO_TYPE_PATH2_ACL:
-					if (container_of(acl,
-					 struct tomoyo_path2_acl,
-							 head)->perm)
-						continue;
-					break;
-				default:
-					continue;
-				}
-				if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl))
-					list_del_rcu(&acl->list);
-				else
-					break;
-			}
+			if (!tomoyo_collect_acl(domain))
+				goto unlock;
 			if (!domain->is_deleted || atomic_read(&domain->users))
 				continue;
 			/*
@@ -283,104 +237,92 @@
 			 * refer this domain after successful execve().
 			 * We recheck domain->users after SRCU synchronization.
 			 */
-			if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain))
-				list_del_rcu(&domain->list);
-			else
-				break;
+			if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list))
+				goto unlock;
 		}
 	}
-	{
-		int i;
-		for (i = 0; i < TOMOYO_MAX_HASH; i++) {
-			struct tomoyo_name_entry *ptr;
-			list_for_each_entry_rcu(ptr, &tomoyo_name_list[i],
-						list) {
-				if (atomic_read(&ptr->users))
-					continue;
-				if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr))
-					list_del_rcu(&ptr->list);
-				else {
-					i = TOMOYO_MAX_HASH;
-					break;
-				}
-			}
+	for (i = 0; i < TOMOYO_MAX_HASH; i++) {
+		struct tomoyo_name *ptr;
+		list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], list) {
+			if (atomic_read(&ptr->users))
+				continue;
+			if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list))
+				goto unlock;
 		}
 	}
-	{
-		struct tomoyo_path_group *group;
-		list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) {
-			struct tomoyo_path_group_member *member;
-			list_for_each_entry_rcu(member, &group->member_list,
-						list) {
-				if (!member->is_deleted)
-					continue;
-				if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP_MEMBER,
-						     member))
-					list_del_rcu(&member->list);
-				else
-					break;
-			}
+	for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
+		struct list_head *list = &tomoyo_group_list[i];
+		int id;
+		struct tomoyo_group *group;
+		switch (i) {
+		case 0:
+			id = TOMOYO_ID_PATH_GROUP;
+			break;
+		default:
+			id = TOMOYO_ID_NUMBER_GROUP;
+			break;
+		}
+		list_for_each_entry(group, list, list) {
+			if (!tomoyo_collect_member(&group->member_list, id))
+				goto unlock;
 			if (!list_empty(&group->member_list) ||
 			    atomic_read(&group->users))
 				continue;
-			if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP, group))
-				list_del_rcu(&group->list);
-			else
-				break;
+			if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, &group->list))
+				goto unlock;
 		}
 	}
+ unlock:
 	mutex_unlock(&tomoyo_policy_lock);
 }
 
 static void tomoyo_kfree_entry(void)
 {
-	struct tomoyo_gc_entry *p;
-	struct tomoyo_gc_entry *tmp;
+	struct tomoyo_gc *p;
+	struct tomoyo_gc *tmp;
 
 	list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
+		struct list_head *element = p->element;
 		switch (p->type) {
-		case TOMOYO_ID_DOMAIN_INITIALIZER:
-			tomoyo_del_domain_initializer(p->element);
+		case TOMOYO_ID_TRANSITION_CONTROL:
+			tomoyo_del_transition_control(element);
 			break;
-		case TOMOYO_ID_DOMAIN_KEEPER:
-			tomoyo_del_domain_keeper(p->element);
-			break;
-		case TOMOYO_ID_ALIAS:
-			tomoyo_del_alias(p->element);
+		case TOMOYO_ID_AGGREGATOR:
+			tomoyo_del_aggregator(element);
 			break;
 		case TOMOYO_ID_GLOBALLY_READABLE:
-			tomoyo_del_allow_read(p->element);
+			tomoyo_del_allow_read(element);
 			break;
 		case TOMOYO_ID_PATTERN:
-			tomoyo_del_file_pattern(p->element);
+			tomoyo_del_file_pattern(element);
 			break;
 		case TOMOYO_ID_NO_REWRITE:
-			tomoyo_del_no_rewrite(p->element);
+			tomoyo_del_no_rewrite(element);
 			break;
 		case TOMOYO_ID_MANAGER:
-			tomoyo_del_manager(p->element);
+			tomoyo_del_manager(element);
 			break;
 		case TOMOYO_ID_NAME:
-			tomoyo_del_name(p->element);
+			tomoyo_del_name(element);
 			break;
 		case TOMOYO_ID_ACL:
-			tomoyo_del_acl(p->element);
+			tomoyo_del_acl(element);
 			break;
 		case TOMOYO_ID_DOMAIN:
-			if (!tomoyo_del_domain(p->element))
+			if (!tomoyo_del_domain(element))
 				continue;
 			break;
-		case TOMOYO_ID_PATH_GROUP_MEMBER:
-			tomoyo_del_path_group_member(p->element);
-			break;
 		case TOMOYO_ID_PATH_GROUP:
-			tomoyo_del_path_group(p->element);
+			tomoyo_del_path_group(element);
 			break;
-		default:
-			printk(KERN_WARNING "Unknown type\n");
+		case TOMOYO_ID_GROUP:
+			tomoyo_del_group(element);
+			break;
+		case TOMOYO_ID_NUMBER_GROUP:
+			tomoyo_del_number_group(element);
 			break;
 		}
-		tomoyo_memory_free(p->element);
+		tomoyo_memory_free(element);
 		list_del(&p->list);
 		kfree(p);
 	}
diff --git a/security/tomoyo/group.c b/security/tomoyo/group.c
new file mode 100644
index 0000000..e94352c
--- /dev/null
+++ b/security/tomoyo/group.c
@@ -0,0 +1,130 @@
+/*
+ * security/tomoyo/group.c
+ *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+static bool tomoyo_same_path_group(const struct tomoyo_acl_head *a,
+				const struct tomoyo_acl_head *b)
+{
+	return container_of(a, struct tomoyo_path_group, head)->member_name ==
+		container_of(b, struct tomoyo_path_group, head)->member_name;
+}
+
+static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a,
+				  const struct tomoyo_acl_head *b)
+{
+	return !memcmp(&container_of(a, struct tomoyo_number_group, head)
+		       ->number,
+		       &container_of(b, struct tomoyo_number_group, head)
+		       ->number,
+		       sizeof(container_of(a, struct tomoyo_number_group, head)
+			      ->number));
+}
+
+/**
+ * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
+ *
+ * @data:      String to parse.
+ * @is_delete: True if it is a delete request.
+ * @type:      Type of this group.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_group(char *data, const bool is_delete, const u8 type)
+{
+	struct tomoyo_group *group;
+	struct list_head *member;
+	char *w[2];
+	int error = -EINVAL;
+	if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
+		return -EINVAL;
+	group = tomoyo_get_group(w[0], type);
+	if (!group)
+		return -ENOMEM;
+	member = &group->member_list;
+	if (type == TOMOYO_PATH_GROUP) {
+		struct tomoyo_path_group e = { };
+		e.member_name = tomoyo_get_name(w[1]);
+		if (!e.member_name) {
+			error = -ENOMEM;
+			goto out;
+		}
+		error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+					     member, tomoyo_same_path_group);
+		tomoyo_put_name(e.member_name);
+	} else if (type == TOMOYO_NUMBER_GROUP) {
+		struct tomoyo_number_group e = { };
+		if (w[1][0] == '@'
+		    || !tomoyo_parse_number_union(w[1], &e.number)
+		    || e.number.values[0] > e.number.values[1])
+			goto out;
+		error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+					     member, tomoyo_same_number_group);
+		/*
+		 * tomoyo_put_number_union() is not needed because
+		 * w[1][0] != '@'.
+		 */
+	}
+ out:
+	tomoyo_put_group(group);
+	return error;
+}
+
+/**
+ * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group.
+ *
+ * @pathname:        The name of pathname.
+ * @group:           Pointer to "struct tomoyo_path_group".
+ *
+ * Returns matched member's pathname if @pathname matches pathnames in @group,
+ * NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+const struct tomoyo_path_info *
+tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
+			  const struct tomoyo_group *group)
+{
+	struct tomoyo_path_group *member;
+	list_for_each_entry_rcu(member, &group->member_list, head.list) {
+		if (member->head.is_deleted)
+			continue;
+		if (!tomoyo_path_matches_pattern(pathname, member->member_name))
+			continue;
+		return member->member_name;
+	}
+	return NULL;
+}
+
+/**
+ * tomoyo_number_matches_group - Check whether the given number matches members of the given number group.
+ *
+ * @min:   Min number.
+ * @max:   Max number.
+ * @group: Pointer to "struct tomoyo_number_group".
+ *
+ * Returns true if @min and @max partially overlaps @group, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_number_matches_group(const unsigned long min,
+				 const unsigned long max,
+				 const struct tomoyo_group *group)
+{
+	struct tomoyo_number_group *member;
+	bool matched = false;
+	list_for_each_entry_rcu(member, &group->member_list, head.list) {
+		if (member->head.is_deleted)
+			continue;
+		if (min > member->number.values[1] ||
+		    max < member->number.values[0])
+			continue;
+		matched = true;
+		break;
+	}
+	return matched;
+}
diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c
new file mode 100644
index 0000000..bbada7c
--- /dev/null
+++ b/security/tomoyo/load_policy.c
@@ -0,0 +1,81 @@
+/*
+ * security/tomoyo/load_policy.c
+ *
+ * Policy loader launcher for TOMOYO.
+ *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ */
+
+#include "common.h"
+
+/* path to policy loader */
+static const char *tomoyo_loader = "/sbin/tomoyo-init";
+
+/**
+ * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists.
+ *
+ * Returns true if /sbin/tomoyo-init exists, false otherwise.
+ */
+static bool tomoyo_policy_loader_exists(void)
+{
+	/*
+	 * Don't activate MAC if the policy loader doesn't exist.
+	 * If the initrd includes /sbin/init but real-root-dev has not
+	 * mounted on / yet, activating MAC will block the system since
+	 * policies are not loaded yet.
+	 * Thus, let do_execve() call this function everytime.
+	 */
+	struct path path;
+
+	if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) {
+		printk(KERN_INFO "Not activating Mandatory Access Control now "
+		       "since %s doesn't exist.\n", tomoyo_loader);
+		return false;
+	}
+	path_put(&path);
+	return true;
+}
+
+/**
+ * tomoyo_load_policy - Run external policy loader to load policy.
+ *
+ * @filename: The program about to start.
+ *
+ * This function checks whether @filename is /sbin/init , and if so
+ * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init
+ * and then continues invocation of /sbin/init.
+ * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and
+ * writes to /sys/kernel/security/tomoyo/ interfaces.
+ *
+ * Returns nothing.
+ */
+void tomoyo_load_policy(const char *filename)
+{
+	char *argv[2];
+	char *envp[3];
+
+	if (tomoyo_policy_loaded)
+		return;
+	/*
+	 * Check filename is /sbin/init or /sbin/tomoyo-start.
+	 * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't
+	 * be passed.
+	 * You can create /sbin/tomoyo-start by
+	 * "ln -s /bin/true /sbin/tomoyo-start".
+	 */
+	if (strcmp(filename, "/sbin/init") &&
+	    strcmp(filename, "/sbin/tomoyo-start"))
+		return;
+	if (!tomoyo_policy_loader_exists())
+		return;
+
+	printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
+	       tomoyo_loader);
+	argv[0] = (char *) tomoyo_loader;
+	argv[1] = NULL;
+	envp[0] = "HOME=/";
+	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	envp[2] = NULL;
+	call_usermodehelper(argv[0], argv, envp, 1);
+	tomoyo_check_profile();
+}
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c
new file mode 100644
index 0000000..2976126
--- /dev/null
+++ b/security/tomoyo/memory.c
@@ -0,0 +1,282 @@
+/*
+ * security/tomoyo/memory.c
+ *
+ * Memory management functions for TOMOYO.
+ *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ */
+
+#include <linux/hash.h>
+#include <linux/slab.h>
+#include "common.h"
+
+/**
+ * tomoyo_warn_oom - Print out of memory warning message.
+ *
+ * @function: Function's name.
+ */
+void tomoyo_warn_oom(const char *function)
+{
+	/* Reduce error messages. */
+	static pid_t tomoyo_last_pid;
+	const pid_t pid = current->pid;
+	if (tomoyo_last_pid != pid) {
+		printk(KERN_WARNING "ERROR: Out of memory at %s.\n",
+		       function);
+		tomoyo_last_pid = pid;
+	}
+	if (!tomoyo_policy_loaded)
+		panic("MAC Initialization failed.\n");
+}
+
+/* Memory allocated for policy. */
+static atomic_t tomoyo_policy_memory_size;
+/* Quota for holding policy. */
+static unsigned int tomoyo_quota_for_policy;
+
+/**
+ * tomoyo_memory_ok - Check memory quota.
+ *
+ * @ptr: Pointer to allocated memory.
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
+ */
+bool tomoyo_memory_ok(void *ptr)
+{
+	size_t s = ptr ? ksize(ptr) : 0;
+	atomic_add(s, &tomoyo_policy_memory_size);
+	if (ptr && (!tomoyo_quota_for_policy ||
+		    atomic_read(&tomoyo_policy_memory_size)
+		    <= tomoyo_quota_for_policy)) {
+		memset(ptr, 0, s);
+		return true;
+	}
+	atomic_sub(s, &tomoyo_policy_memory_size);
+	tomoyo_warn_oom(__func__);
+	return false;
+}
+
+/**
+ * tomoyo_commit_ok - Check memory quota.
+ *
+ * @data:   Data to copy from.
+ * @size:   Size in byte.
+ *
+ * Returns pointer to allocated memory on success, NULL otherwise.
+ * @data is zero-cleared on success.
+ */
+void *tomoyo_commit_ok(void *data, const unsigned int size)
+{
+	void *ptr = kzalloc(size, GFP_NOFS);
+	if (tomoyo_memory_ok(ptr)) {
+		memmove(ptr, data, size);
+		memset(data, 0, size);
+		return ptr;
+	}
+	return NULL;
+}
+
+/**
+ * tomoyo_memory_free - Free memory for elements.
+ *
+ * @ptr:  Pointer to allocated memory.
+ */
+void tomoyo_memory_free(void *ptr)
+{
+	atomic_sub(ksize(ptr), &tomoyo_policy_memory_size);
+	kfree(ptr);
+}
+
+/**
+ * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
+ *
+ * @group_name: The name of address group.
+ * @idx:        Index number.
+ *
+ * Returns pointer to "struct tomoyo_group" on success, NULL otherwise.
+ */
+struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx)
+{
+	struct tomoyo_group e = { };
+	struct tomoyo_group *group = NULL;
+	bool found = false;
+	if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP)
+		return NULL;
+	e.group_name = tomoyo_get_name(group_name);
+	if (!e.group_name)
+		return NULL;
+	if (mutex_lock_interruptible(&tomoyo_policy_lock))
+		goto out;
+	list_for_each_entry(group, &tomoyo_group_list[idx], list) {
+		if (e.group_name != group->group_name)
+			continue;
+		atomic_inc(&group->users);
+		found = true;
+		break;
+	}
+	if (!found) {
+		struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e));
+		if (entry) {
+			INIT_LIST_HEAD(&entry->member_list);
+			atomic_set(&entry->users, 1);
+			list_add_tail_rcu(&entry->list,
+					  &tomoyo_group_list[idx]);
+			group = entry;
+			found = true;
+		}
+	}
+	mutex_unlock(&tomoyo_policy_lock);
+ out:
+	tomoyo_put_name(e.group_name);
+	return found ? group : NULL;
+}
+
+/*
+ * tomoyo_name_list is used for holding string data used by TOMOYO.
+ * Since same string data is likely used for multiple times (e.g.
+ * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
+ * "const struct tomoyo_path_info *".
+ */
+struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+
+/**
+ * tomoyo_get_name - Allocate permanent memory for string data.
+ *
+ * @name: The string to store into the permernent memory.
+ *
+ * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ */
+const struct tomoyo_path_info *tomoyo_get_name(const char *name)
+{
+	struct tomoyo_name *ptr;
+	unsigned int hash;
+	int len;
+	int allocated_len;
+	struct list_head *head;
+
+	if (!name)
+		return NULL;
+	len = strlen(name) + 1;
+	hash = full_name_hash((const unsigned char *) name, len - 1);
+	head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
+	if (mutex_lock_interruptible(&tomoyo_policy_lock))
+		return NULL;
+	list_for_each_entry(ptr, head, list) {
+		if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
+			continue;
+		atomic_inc(&ptr->users);
+		goto out;
+	}
+	ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS);
+	allocated_len = ptr ? ksize(ptr) : 0;
+	if (!ptr || (tomoyo_quota_for_policy &&
+		     atomic_read(&tomoyo_policy_memory_size) + allocated_len
+		     > tomoyo_quota_for_policy)) {
+		kfree(ptr);
+		ptr = NULL;
+		tomoyo_warn_oom(__func__);
+		goto out;
+	}
+	atomic_add(allocated_len, &tomoyo_policy_memory_size);
+	ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
+	memmove((char *) ptr->entry.name, name, len);
+	atomic_set(&ptr->users, 1);
+	tomoyo_fill_path_info(&ptr->entry);
+	list_add_tail(&ptr->list, head);
+ out:
+	mutex_unlock(&tomoyo_policy_lock);
+	return ptr ? &ptr->entry : NULL;
+}
+
+/**
+ * tomoyo_mm_init - Initialize mm related code.
+ */
+void __init tomoyo_mm_init(void)
+{
+	int idx;
+
+	for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
+		INIT_LIST_HEAD(&tomoyo_policy_list[idx]);
+	for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
+		INIT_LIST_HEAD(&tomoyo_group_list[idx]);
+	for (idx = 0; idx < TOMOYO_MAX_HASH; idx++)
+		INIT_LIST_HEAD(&tomoyo_name_list[idx]);
+	INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
+	tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
+	list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
+	idx = tomoyo_read_lock();
+	if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
+		panic("Can't register tomoyo_kernel_domain");
+	{
+		/* Load built-in policy. */
+		tomoyo_write_transition_control("/sbin/hotplug", false,
+					TOMOYO_TRANSITION_CONTROL_INITIALIZE);
+		tomoyo_write_transition_control("/sbin/modprobe", false,
+					TOMOYO_TRANSITION_CONTROL_INITIALIZE);
+	}
+	tomoyo_read_unlock(idx);
+}
+
+
+/* Memory allocated for query lists. */
+unsigned int tomoyo_query_memory_size;
+/* Quota for holding query lists. */
+unsigned int tomoyo_quota_for_query;
+
+/**
+ * tomoyo_read_memory_counter - Check for memory usage in bytes.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns memory usage.
+ */
+void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
+{
+	if (!head->r.eof) {
+		const unsigned int policy
+			= atomic_read(&tomoyo_policy_memory_size);
+		const unsigned int query = tomoyo_query_memory_size;
+		char buffer[64];
+
+		memset(buffer, 0, sizeof(buffer));
+		if (tomoyo_quota_for_policy)
+			snprintf(buffer, sizeof(buffer) - 1,
+				 "   (Quota: %10u)",
+				 tomoyo_quota_for_policy);
+		else
+			buffer[0] = '\0';
+		tomoyo_io_printf(head, "Policy:       %10u%s\n", policy,
+				 buffer);
+		if (tomoyo_quota_for_query)
+			snprintf(buffer, sizeof(buffer) - 1,
+				 "   (Quota: %10u)",
+				 tomoyo_quota_for_query);
+		else
+			buffer[0] = '\0';
+		tomoyo_io_printf(head, "Query lists:  %10u%s\n", query,
+				 buffer);
+		tomoyo_io_printf(head, "Total:        %10u\n", policy + query);
+		head->r.eof = true;
+	}
+}
+
+/**
+ * tomoyo_write_memory_quota - Set memory quota.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
+{
+	char *data = head->write_buf;
+	unsigned int size;
+
+	if (sscanf(data, "Policy: %u", &size) == 1)
+		tomoyo_quota_for_policy = size;
+	else if (sscanf(data, "Query lists: %u", &size) == 1)
+		tomoyo_quota_for_query = size;
+	return 0;
+}
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c
new file mode 100644
index 0000000..82bf8c2
--- /dev/null
+++ b/security/tomoyo/mount.c
@@ -0,0 +1,284 @@
+/*
+ * security/tomoyo/mount.c
+ *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+/* Keywords for mount restrictions. */
+
+/* Allow to call 'mount --bind /source_dir /dest_dir' */
+#define TOMOYO_MOUNT_BIND_KEYWORD                        "--bind"
+/* Allow to call 'mount --move /old_dir    /new_dir ' */
+#define TOMOYO_MOUNT_MOVE_KEYWORD                        "--move"
+/* Allow to call 'mount -o remount /dir             ' */
+#define TOMOYO_MOUNT_REMOUNT_KEYWORD                     "--remount"
+/* Allow to call 'mount --make-unbindable /dir'       */
+#define TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD             "--make-unbindable"
+/* Allow to call 'mount --make-private /dir'          */
+#define TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD                "--make-private"
+/* Allow to call 'mount --make-slave /dir'            */
+#define TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD                  "--make-slave"
+/* Allow to call 'mount --make-shared /dir'           */
+#define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD                 "--make-shared"
+
+/**
+ * tomoyo_audit_mount_log - Audit mount log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_mount_log(struct tomoyo_request_info *r)
+{
+	const char *dev = r->param.mount.dev->name;
+	const char *dir = r->param.mount.dir->name;
+	const char *type = r->param.mount.type->name;
+	const unsigned long flags = r->param.mount.flags;
+	if (r->granted)
+		return 0;
+	if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD))
+		tomoyo_warn_log(r, "mount -o remount %s 0x%lX", dir, flags);
+	else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD)
+		 || !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD))
+		tomoyo_warn_log(r, "mount %s %s %s 0x%lX", type, dev, dir,
+				flags);
+	else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
+		 !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) ||
+		 !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) ||
+		 !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD))
+		tomoyo_warn_log(r, "mount %s %s 0x%lX", type, dir, flags);
+	else
+		tomoyo_warn_log(r, "mount -t %s %s %s 0x%lX", type, dev, dir,
+				flags);
+	return tomoyo_supervisor(r,
+				 TOMOYO_KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n",
+				 tomoyo_pattern(r->param.mount.dev),
+				 tomoyo_pattern(r->param.mount.dir), type,
+				 flags);
+}
+
+static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r,
+				   const struct tomoyo_acl_info *ptr)
+{
+	const struct tomoyo_mount_acl *acl =
+		container_of(ptr, typeof(*acl), head);
+	return tomoyo_compare_number_union(r->param.mount.flags, &acl->flags) &&
+		tomoyo_compare_name_union(r->param.mount.type, &acl->fs_type) &&
+		tomoyo_compare_name_union(r->param.mount.dir, &acl->dir_name) &&
+		(!r->param.mount.need_dev ||
+		 tomoyo_compare_name_union(r->param.mount.dev, &acl->dev_name));
+}
+
+/**
+ * tomoyo_mount_acl - Check permission for mount() operation.
+ *
+ * @r:        Pointer to "struct tomoyo_request_info".
+ * @dev_name: Name of device file.
+ * @dir:      Pointer to "struct path".
+ * @type:     Name of filesystem type.
+ * @flags:    Mount options.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
+			    struct path *dir, char *type, unsigned long flags)
+{
+	struct path path;
+	struct file_system_type *fstype = NULL;
+	const char *requested_type = NULL;
+	const char *requested_dir_name = NULL;
+	const char *requested_dev_name = NULL;
+	struct tomoyo_path_info rtype;
+	struct tomoyo_path_info rdev;
+	struct tomoyo_path_info rdir;
+	int need_dev = 0;
+	int error = -ENOMEM;
+
+	/* Get fstype. */
+	requested_type = tomoyo_encode(type);
+	if (!requested_type)
+		goto out;
+	rtype.name = requested_type;
+	tomoyo_fill_path_info(&rtype);
+
+	/* Get mount point. */
+	requested_dir_name = tomoyo_realpath_from_path(dir);
+	if (!requested_dir_name) {
+		error = -ENOMEM;
+		goto out;
+	}
+	rdir.name = requested_dir_name;
+	tomoyo_fill_path_info(&rdir);
+
+	/* Compare fs name. */
+	if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD)) {
+		/* dev_name is ignored. */
+	} else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
+		   !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) ||
+		   !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) ||
+		   !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD)) {
+		/* dev_name is ignored. */
+	} else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD) ||
+		   !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD)) {
+		need_dev = -1; /* dev_name is a directory */
+	} else {
+		fstype = get_fs_type(type);
+		if (!fstype) {
+			error = -ENODEV;
+			goto out;
+		}
+		if (fstype->fs_flags & FS_REQUIRES_DEV)
+			/* dev_name is a block device file. */
+			need_dev = 1;
+	}
+	if (need_dev) {
+		/* Get mount point or device file. */
+		if (kern_path(dev_name, LOOKUP_FOLLOW, &path)) {
+			error = -ENOENT;
+			goto out;
+		}
+		requested_dev_name = tomoyo_realpath_from_path(&path);
+		if (!requested_dev_name) {
+			error = -ENOENT;
+			goto out;
+		}
+	} else {
+		/* Map dev_name to "<NULL>" if no dev_name given. */
+		if (!dev_name)
+			dev_name = "<NULL>";
+		requested_dev_name = tomoyo_encode(dev_name);
+		if (!requested_dev_name) {
+			error = -ENOMEM;
+			goto out;
+		}
+	}
+	rdev.name = requested_dev_name;
+	tomoyo_fill_path_info(&rdev);
+	r->param_type = TOMOYO_TYPE_MOUNT_ACL;
+	r->param.mount.need_dev = need_dev;
+	r->param.mount.dev = &rdev;
+	r->param.mount.dir = &rdir;
+	r->param.mount.type = &rtype;
+	r->param.mount.flags = flags;
+	do {
+		tomoyo_check_acl(r, tomoyo_check_mount_acl);
+		error = tomoyo_audit_mount_log(r);
+	} while (error == TOMOYO_RETRY_REQUEST);
+ out:
+	kfree(requested_dev_name);
+	kfree(requested_dir_name);
+	if (fstype)
+		put_filesystem(fstype);
+	kfree(requested_type);
+	return error;
+}
+
+/**
+ * tomoyo_mount_permission - Check permission for mount() operation.
+ *
+ * @dev_name:  Name of device file.
+ * @path:      Pointer to "struct path".
+ * @type:      Name of filesystem type. May be NULL.
+ * @flags:     Mount options.
+ * @data_page: Optional data. May be NULL.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
+			    unsigned long flags, void *data_page)
+{
+	struct tomoyo_request_info r;
+	int error;
+	int idx;
+
+	if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT)
+	    == TOMOYO_CONFIG_DISABLED)
+		return 0;
+	if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
+		flags &= ~MS_MGC_MSK;
+	if (flags & MS_REMOUNT) {
+		type = TOMOYO_MOUNT_REMOUNT_KEYWORD;
+		flags &= ~MS_REMOUNT;
+	}
+	if (flags & MS_MOVE) {
+		type = TOMOYO_MOUNT_MOVE_KEYWORD;
+		flags &= ~MS_MOVE;
+	}
+	if (flags & MS_BIND) {
+		type = TOMOYO_MOUNT_BIND_KEYWORD;
+		flags &= ~MS_BIND;
+	}
+	if (flags & MS_UNBINDABLE) {
+		type = TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD;
+		flags &= ~MS_UNBINDABLE;
+	}
+	if (flags & MS_PRIVATE) {
+		type = TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD;
+		flags &= ~MS_PRIVATE;
+	}
+	if (flags & MS_SLAVE) {
+		type = TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD;
+		flags &= ~MS_SLAVE;
+	}
+	if (flags & MS_SHARED) {
+		type = TOMOYO_MOUNT_MAKE_SHARED_KEYWORD;
+		flags &= ~MS_SHARED;
+	}
+	if (!type)
+		type = "<NULL>";
+	idx = tomoyo_read_lock();
+	error = tomoyo_mount_acl(&r, dev_name, path, type, flags);
+	tomoyo_read_unlock(idx);
+	return error;
+}
+
+static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
+				  const struct tomoyo_acl_info *b)
+{
+	const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
+	const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
+	return tomoyo_same_acl_head(&p1->head, &p2->head) &&
+		tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
+		tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
+		tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
+		tomoyo_same_number_union(&p1->flags, &p2->flags);
+}
+
+/**
+ * tomoyo_write_mount - Write "struct tomoyo_mount_acl" list.
+ *
+ * @data:      String to parse.
+ * @domain:    Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain,
+		       const bool is_delete)
+{
+	struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
+	int error = is_delete ? -ENOENT : -ENOMEM;
+	char *w[4];
+	if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0])
+		return -EINVAL;
+	if (!tomoyo_parse_name_union(w[0], &e.dev_name) ||
+	    !tomoyo_parse_name_union(w[1], &e.dir_name) ||
+	    !tomoyo_parse_name_union(w[2], &e.fs_type) ||
+	    !tomoyo_parse_number_union(w[3], &e.flags))
+		goto out;
+	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+				     tomoyo_same_mount_acl, NULL);
+ out:
+	tomoyo_put_name_union(&e.dev_name);
+	tomoyo_put_name_union(&e.dir_name);
+	tomoyo_put_name_union(&e.fs_type);
+	tomoyo_put_number_union(&e.flags);
+	return error;
+}
diff --git a/security/tomoyo/path_group.c b/security/tomoyo/path_group.c
deleted file mode 100644
index c988041..0000000
--- a/security/tomoyo/path_group.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * security/tomoyo/path_group.c
- *
- * Copyright (C) 2005-2009  NTT DATA CORPORATION
- */
-
-#include <linux/slab.h>
-#include "common.h"
-/* The list for "struct ccs_path_group". */
-LIST_HEAD(tomoyo_path_group_list);
-
-/**
- * tomoyo_get_path_group - Allocate memory for "struct tomoyo_path_group".
- *
- * @group_name: The name of pathname group.
- *
- * Returns pointer to "struct tomoyo_path_group" on success, NULL otherwise.
- */
-struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name)
-{
-	struct tomoyo_path_group *entry = NULL;
-	struct tomoyo_path_group *group = NULL;
-	const struct tomoyo_path_info *saved_group_name;
-	int error = -ENOMEM;
-	if (!tomoyo_is_correct_path(group_name, 0, 0, 0) ||
-	    !group_name[0])
-		return NULL;
-	saved_group_name = tomoyo_get_name(group_name);
-	if (!saved_group_name)
-		return NULL;
-	entry = kzalloc(sizeof(*entry), GFP_NOFS);
-	if (mutex_lock_interruptible(&tomoyo_policy_lock))
-		goto out;
-	list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) {
-		if (saved_group_name != group->group_name)
-			continue;
-		atomic_inc(&group->users);
-		error = 0;
-		break;
-	}
-	if (error && tomoyo_memory_ok(entry)) {
-		INIT_LIST_HEAD(&entry->member_list);
-		entry->group_name = saved_group_name;
-		saved_group_name = NULL;
-		atomic_set(&entry->users, 1);
-		list_add_tail_rcu(&entry->list, &tomoyo_path_group_list);
-		group = entry;
-		entry = NULL;
-		error = 0;
-	}
-	mutex_unlock(&tomoyo_policy_lock);
- out:
-	tomoyo_put_name(saved_group_name);
-	kfree(entry);
-	return !error ? group : NULL;
-}
-
-/**
- * tomoyo_write_path_group_policy - Write "struct tomoyo_path_group" list.
- *
- * @data:      String to parse.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, nagative value otherwise.
- */
-int tomoyo_write_path_group_policy(char *data, const bool is_delete)
-{
-	struct tomoyo_path_group *group;
-	struct tomoyo_path_group_member *member;
-	struct tomoyo_path_group_member e = { };
-	int error = is_delete ? -ENOENT : -ENOMEM;
-	char *w[2];
-	if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
-		return -EINVAL;
-	group = tomoyo_get_path_group(w[0]);
-	if (!group)
-		return -ENOMEM;
-	e.member_name = tomoyo_get_name(w[1]);
-	if (!e.member_name)
-		goto out;
-	if (mutex_lock_interruptible(&tomoyo_policy_lock))
-		goto out;
-	list_for_each_entry_rcu(member, &group->member_list, list) {
-		if (member->member_name != e.member_name)
-			continue;
-		member->is_deleted = is_delete;
-		error = 0;
-		break;
-	}
-	if (!is_delete && error) {
-		struct tomoyo_path_group_member *entry =
-			tomoyo_commit_ok(&e, sizeof(e));
-		if (entry) {
-			list_add_tail_rcu(&entry->list, &group->member_list);
-			error = 0;
-		}
-	}
-	mutex_unlock(&tomoyo_policy_lock);
- out:
-	tomoyo_put_name(e.member_name);
-	tomoyo_put_path_group(group);
-	return error;
-}
-
-/**
- * tomoyo_read_path_group_policy - Read "struct tomoyo_path_group" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head)
-{
-	struct list_head *gpos;
-	struct list_head *mpos;
-	list_for_each_cookie(gpos, head->read_var1, &tomoyo_path_group_list) {
-		struct tomoyo_path_group *group;
-		group = list_entry(gpos, struct tomoyo_path_group, list);
-		list_for_each_cookie(mpos, head->read_var2,
-				     &group->member_list) {
-			struct tomoyo_path_group_member *member;
-			member = list_entry(mpos,
-					    struct tomoyo_path_group_member,
-					    list);
-			if (member->is_deleted)
-				continue;
-			if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_PATH_GROUP
-					      "%s %s\n",
-					      group->group_name->name,
-					      member->member_name->name))
-				return false;
-		}
-	}
-	return true;
-}
-
-/**
- * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group.
- *
- * @pathname:        The name of pathname.
- * @group:           Pointer to "struct tomoyo_path_group".
- * @may_use_pattern: True if wild card is permitted.
- *
- * Returns true if @pathname matches pathnames in @group, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
-			       const struct tomoyo_path_group *group,
-			       const bool may_use_pattern)
-{
-	struct tomoyo_path_group_member *member;
-	bool matched = false;
-	list_for_each_entry_rcu(member, &group->member_list, list) {
-		if (member->is_deleted)
-			continue;
-		if (!member->member_name->is_patterned) {
-			if (tomoyo_pathcmp(pathname, member->member_name))
-				continue;
-		} else if (may_use_pattern) {
-			if (!tomoyo_path_matches_pattern(pathname,
-							 member->member_name))
-				continue;
-		} else
-			continue;
-		matched = true;
-		break;
-	}
-	return matched;
-}
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
index d1b96f0..ed8ccd6 100644
--- a/security/tomoyo/realpath.c
+++ b/security/tomoyo/realpath.c
@@ -1,130 +1,71 @@
 /*
  * security/tomoyo/realpath.c
  *
- * Get the canonicalized absolute pathnames. The basis for TOMOYO.
+ * Pathname calculation functions for TOMOYO.
  *
- * Copyright (C) 2005-2009  NTT DATA CORPORATION
- *
- * Version: 2.2.0   2009/04/01
- *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
  */
 
 #include <linux/types.h>
 #include <linux/mount.h>
 #include <linux/mnt_namespace.h>
 #include <linux/fs_struct.h>
-#include <linux/hash.h>
 #include <linux/magic.h>
 #include <linux/slab.h>
+#include <net/sock.h>
 #include "common.h"
 
 /**
  * tomoyo_encode: Convert binary string to ascii string.
  *
- * @buffer:  Buffer for ASCII string.
- * @buflen:  Size of @buffer.
- * @str:     Binary string.
+ * @str: String in binary format.
  *
- * Returns 0 on success, -ENOMEM otherwise.
+ * Returns pointer to @str in ascii format on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
  */
-int tomoyo_encode(char *buffer, int buflen, const char *str)
+char *tomoyo_encode(const char *str)
 {
-	while (1) {
-		const unsigned char c = *(unsigned char *) str++;
+	int len = 0;
+	const char *p = str;
+	char *cp;
+	char *cp0;
 
-		if (tomoyo_is_valid(c)) {
-			if (--buflen <= 0)
-				break;
-			*buffer++ = (char) c;
-			if (c != '\\')
-				continue;
-			if (--buflen <= 0)
-				break;
-			*buffer++ = (char) c;
-			continue;
-		}
-		if (!c) {
-			if (--buflen <= 0)
-				break;
-			*buffer = '\0';
-			return 0;
-		}
-		buflen -= 4;
-		if (buflen <= 0)
-			break;
-		*buffer++ = '\\';
-		*buffer++ = (c >> 6) + '0';
-		*buffer++ = ((c >> 3) & 7) + '0';
-		*buffer++ = (c & 7) + '0';
+	if (!p)
+		return NULL;
+	while (*p) {
+		const unsigned char c = *p++;
+		if (c == '\\')
+			len += 2;
+		else if (c > ' ' && c < 127)
+			len++;
+		else
+			len += 4;
 	}
-	return -ENOMEM;
-}
+	len++;
+	/* Reserve space for appending "/". */
+	cp = kzalloc(len + 10, GFP_NOFS);
+	if (!cp)
+		return NULL;
+	cp0 = cp;
+	p = str;
+	while (*p) {
+		const unsigned char c = *p++;
 
-/**
- * tomoyo_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root.
- *
- * @path:        Pointer to "struct path".
- * @newname:     Pointer to buffer to return value in.
- * @newname_len: Size of @newname.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * If dentry is a directory, trailing '/' is appended.
- * Characters out of 0x20 < c < 0x7F range are converted to
- * \ooo style octal string.
- * Character \ is converted to \\ string.
- */
-int tomoyo_realpath_from_path2(struct path *path, char *newname,
-			       int newname_len)
-{
-	int error = -ENOMEM;
-	struct dentry *dentry = path->dentry;
-	char *sp;
-
-	if (!dentry || !path->mnt || !newname || newname_len <= 2048)
-		return -EINVAL;
-	if (dentry->d_op && dentry->d_op->d_dname) {
-		/* For "socket:[\$]" and "pipe:[\$]". */
-		static const int offset = 1536;
-		sp = dentry->d_op->d_dname(dentry, newname + offset,
-					   newname_len - offset);
-	} else {
-		struct path ns_root = {.mnt = NULL, .dentry = NULL};
-
-		spin_lock(&dcache_lock);
-		/* go to whatever namespace root we are under */
-		sp = __d_path(path, &ns_root, newname, newname_len);
-		spin_unlock(&dcache_lock);
-		/* Prepend "/proc" prefix if using internal proc vfs mount. */
-		if (!IS_ERR(sp) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
-		    (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
-			sp -= 5;
-			if (sp >= newname)
-				memcpy(sp, "/proc", 5);
-			else
-				sp = ERR_PTR(-ENOMEM);
+		if (c == '\\') {
+			*cp++ = '\\';
+			*cp++ = '\\';
+		} else if (c > ' ' && c < 127) {
+			*cp++ = c;
+		} else {
+			*cp++ = '\\';
+			*cp++ = (c >> 6) + '0';
+			*cp++ = ((c >> 3) & 7) + '0';
+			*cp++ = (c & 7) + '0';
 		}
 	}
-	if (IS_ERR(sp))
-		error = PTR_ERR(sp);
-	else
-		error = tomoyo_encode(newname, sp - newname, sp);
-	/* Append trailing '/' if dentry is a directory. */
-	if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)
-	    && *newname) {
-		sp = newname + strlen(newname);
-		if (*(sp - 1) != '/') {
-			if (sp < newname + newname_len - 4) {
-				*sp++ = '/';
-				*sp = '\0';
-			} else {
-				error = -ENOMEM;
-			}
-		}
-	}
-	if (error)
-		printk(KERN_WARNING "tomoyo_realpath: Pathname too long.\n");
-	return error;
+	return cp0;
 }
 
 /**
@@ -134,41 +75,90 @@
  *
  * Returns the realpath of the given @path on success, NULL otherwise.
  *
+ * If dentry is a directory, trailing '/' is appended.
+ * Characters out of 0x20 < c < 0x7F range are converted to
+ * \ooo style octal string.
+ * Character \ is converted to \\ string.
+ *
  * These functions use kzalloc(), so the caller must call kfree()
  * if these functions didn't return NULL.
  */
 char *tomoyo_realpath_from_path(struct path *path)
 {
-	char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_NOFS);
-
-	BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer)
-		     <= TOMOYO_MAX_PATHNAME_LEN - 1);
-	if (!buf)
+	char *buf = NULL;
+	char *name = NULL;
+	unsigned int buf_len = PAGE_SIZE / 2;
+	struct dentry *dentry = path->dentry;
+	bool is_dir;
+	if (!dentry)
 		return NULL;
-	if (tomoyo_realpath_from_path2(path, buf,
-				       TOMOYO_MAX_PATHNAME_LEN - 1) == 0)
-		return buf;
-	kfree(buf);
-	return NULL;
-}
-
-/**
- * tomoyo_realpath - Get realpath of a pathname.
- *
- * @pathname: The pathname to solve.
- *
- * Returns the realpath of @pathname on success, NULL otherwise.
- */
-char *tomoyo_realpath(const char *pathname)
-{
-	struct path path;
-
-	if (pathname && kern_path(pathname, LOOKUP_FOLLOW, &path) == 0) {
-		char *buf = tomoyo_realpath_from_path(&path);
-		path_put(&path);
-		return buf;
+	is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode);
+	while (1) {
+		struct path ns_root = { .mnt = NULL, .dentry = NULL };
+		char *pos;
+		buf_len <<= 1;
+		kfree(buf);
+		buf = kmalloc(buf_len, GFP_NOFS);
+		if (!buf)
+			break;
+		/* Get better name for socket. */
+		if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
+			struct inode *inode = dentry->d_inode;
+			struct socket *sock = inode ? SOCKET_I(inode) : NULL;
+			struct sock *sk = sock ? sock->sk : NULL;
+			if (sk) {
+				snprintf(buf, buf_len - 1, "socket:[family=%u:"
+					 "type=%u:protocol=%u]", sk->sk_family,
+					 sk->sk_type, sk->sk_protocol);
+			} else {
+				snprintf(buf, buf_len - 1, "socket:[unknown]");
+			}
+			name = tomoyo_encode(buf);
+			break;
+		}
+		/* For "socket:[\$]" and "pipe:[\$]". */
+		if (dentry->d_op && dentry->d_op->d_dname) {
+			pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
+			if (IS_ERR(pos))
+				continue;
+			name = tomoyo_encode(pos);
+			break;
+		}
+		/* If we don't have a vfsmount, we can't calculate. */
+		if (!path->mnt)
+			break;
+		spin_lock(&dcache_lock);
+		/* go to whatever namespace root we are under */
+		pos = __d_path(path, &ns_root, buf, buf_len);
+		spin_unlock(&dcache_lock);
+		/* Prepend "/proc" prefix if using internal proc vfs mount. */
+		if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
+		    (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
+			pos -= 5;
+			if (pos >= buf)
+				memcpy(pos, "/proc", 5);
+			else
+				pos = ERR_PTR(-ENOMEM);
+		}
+		if (IS_ERR(pos))
+			continue;
+		name = tomoyo_encode(pos);
+		break;
 	}
-	return NULL;
+	kfree(buf);
+	if (!name)
+		tomoyo_warn_oom(__func__);
+	else if (is_dir && *name) {
+		/* Append trailing '/' if dentry is a directory. */
+		char *pos = name + strlen(name) - 1;
+		if (*pos != '/')
+			/*
+			 * This is OK because tomoyo_encode() reserves space
+			 * for appending "/".
+			 */
+			*++pos = '/';
+	}
+	return name;
 }
 
 /**
@@ -189,191 +179,3 @@
 	}
 	return NULL;
 }
-
-/* Memory allocated for non-string data. */
-static atomic_t tomoyo_policy_memory_size;
-/* Quota for holding policy. */
-static unsigned int tomoyo_quota_for_policy;
-
-/**
- * tomoyo_memory_ok - Check memory quota.
- *
- * @ptr: Pointer to allocated memory.
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_policy_lock.
- * Memory pointed by @ptr will be zeroed on success.
- */
-bool tomoyo_memory_ok(void *ptr)
-{
-	int allocated_len = ptr ? ksize(ptr) : 0;
-	atomic_add(allocated_len, &tomoyo_policy_memory_size);
-	if (ptr && (!tomoyo_quota_for_policy ||
-		    atomic_read(&tomoyo_policy_memory_size)
-		    <= tomoyo_quota_for_policy)) {
-		memset(ptr, 0, allocated_len);
-		return true;
-	}
-	printk(KERN_WARNING "ERROR: Out of memory "
-	       "for tomoyo_alloc_element().\n");
-	if (!tomoyo_policy_loaded)
-		panic("MAC Initialization failed.\n");
-	return false;
-}
-
-/**
- * tomoyo_commit_ok - Check memory quota.
- *
- * @data:   Data to copy from.
- * @size:   Size in byte.
- *
- * Returns pointer to allocated memory on success, NULL otherwise.
- */
-void *tomoyo_commit_ok(void *data, const unsigned int size)
-{
-	void *ptr = kzalloc(size, GFP_NOFS);
-	if (tomoyo_memory_ok(ptr)) {
-		memmove(ptr, data, size);
-		memset(data, 0, size);
-		return ptr;
-	}
-	return NULL;
-}
-
-/**
- * tomoyo_memory_free - Free memory for elements.
- *
- * @ptr:  Pointer to allocated memory.
- */
-void tomoyo_memory_free(void *ptr)
-{
-	atomic_sub(ksize(ptr), &tomoyo_policy_memory_size);
-	kfree(ptr);
-}
-
-/*
- * tomoyo_name_list is used for holding string data used by TOMOYO.
- * Since same string data is likely used for multiple times (e.g.
- * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
- * "const struct tomoyo_path_info *".
- */
-struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
-
-/**
- * tomoyo_get_name - Allocate permanent memory for string data.
- *
- * @name: The string to store into the permernent memory.
- *
- * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
- */
-const struct tomoyo_path_info *tomoyo_get_name(const char *name)
-{
-	struct tomoyo_name_entry *ptr;
-	unsigned int hash;
-	int len;
-	int allocated_len;
-	struct list_head *head;
-
-	if (!name)
-		return NULL;
-	len = strlen(name) + 1;
-	hash = full_name_hash((const unsigned char *) name, len - 1);
-	head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
-	if (mutex_lock_interruptible(&tomoyo_policy_lock))
-		return NULL;
-	list_for_each_entry(ptr, head, list) {
-		if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
-			continue;
-		atomic_inc(&ptr->users);
-		goto out;
-	}
-	ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS);
-	allocated_len = ptr ? ksize(ptr) : 0;
-	if (!ptr || (tomoyo_quota_for_policy &&
-		     atomic_read(&tomoyo_policy_memory_size) + allocated_len
-		     > tomoyo_quota_for_policy)) {
-		kfree(ptr);
-		printk(KERN_WARNING "ERROR: Out of memory "
-		       "for tomoyo_get_name().\n");
-		if (!tomoyo_policy_loaded)
-			panic("MAC Initialization failed.\n");
-		ptr = NULL;
-		goto out;
-	}
-	atomic_add(allocated_len, &tomoyo_policy_memory_size);
-	ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
-	memmove((char *) ptr->entry.name, name, len);
-	atomic_set(&ptr->users, 1);
-	tomoyo_fill_path_info(&ptr->entry);
-	list_add_tail(&ptr->list, head);
- out:
-	mutex_unlock(&tomoyo_policy_lock);
-	return ptr ? &ptr->entry : NULL;
-}
-
-/**
- * tomoyo_realpath_init - Initialize realpath related code.
- */
-void __init tomoyo_realpath_init(void)
-{
-	int i;
-
-	BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX);
-	for (i = 0; i < TOMOYO_MAX_HASH; i++)
-		INIT_LIST_HEAD(&tomoyo_name_list[i]);
-	INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
-	tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
-	/*
-	 * tomoyo_read_lock() is not needed because this function is
-	 * called before the first "delete" request.
-	 */
-	list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
-	if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
-		panic("Can't register tomoyo_kernel_domain");
-}
-
-/**
- * tomoyo_read_memory_counter - Check for memory usage in bytes.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns memory usage.
- */
-int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
-{
-	if (!head->read_eof) {
-		const unsigned int policy
-			= atomic_read(&tomoyo_policy_memory_size);
-		char buffer[64];
-
-		memset(buffer, 0, sizeof(buffer));
-		if (tomoyo_quota_for_policy)
-			snprintf(buffer, sizeof(buffer) - 1,
-				 "   (Quota: %10u)",
-				 tomoyo_quota_for_policy);
-		else
-			buffer[0] = '\0';
-		tomoyo_io_printf(head, "Policy:  %10u%s\n", policy, buffer);
-		tomoyo_io_printf(head, "Total:   %10u\n", policy);
-		head->read_eof = true;
-	}
-	return 0;
-}
-
-/**
- * tomoyo_write_memory_quota - Set memory quota.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns 0.
- */
-int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
-{
-	char *data = head->write_buf;
-	unsigned int size;
-
-	if (sscanf(data, "Policy: %u", &size) == 1)
-		tomoyo_quota_for_policy = size;
-	return 0;
-}
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
new file mode 100644
index 0000000..e43d555
--- /dev/null
+++ b/security/tomoyo/securityfs_if.c
@@ -0,0 +1,155 @@
+/*
+ * security/tomoyo/common.c
+ *
+ * Securityfs interface for TOMOYO.
+ *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ */
+
+#include <linux/security.h>
+#include "common.h"
+
+/**
+ * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @inode: Pointer to "struct inode".
+ * @file:  Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_open(struct inode *inode, struct file *file)
+{
+	const int key = ((u8 *) file->f_path.dentry->d_inode->i_private)
+		- ((u8 *) NULL);
+	return tomoyo_open_control(key, file);
+}
+
+/**
+ * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @inode: Pointer to "struct inode".
+ * @file:  Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_release(struct inode *inode, struct file *file)
+{
+	return tomoyo_close_control(file);
+}
+
+/**
+ * tomoyo_poll - poll() for /proc/ccs/ interface.
+ *
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static unsigned int tomoyo_poll(struct file *file, poll_table *wait)
+{
+	return tomoyo_poll_control(file, wait);
+}
+
+/**
+ * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file:  Pointer to "struct file".
+ * @buf:   Pointer to buffer.
+ * @count: Size of @buf.
+ * @ppos:  Unused.
+ *
+ * Returns bytes read on success, negative value otherwise.
+ */
+static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
+			   loff_t *ppos)
+{
+	return tomoyo_read_control(file, buf, count);
+}
+
+/**
+ * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file:  Pointer to "struct file".
+ * @buf:   Pointer to buffer.
+ * @count: Size of @buf.
+ * @ppos:  Unused.
+ *
+ * Returns @count on success, negative value otherwise.
+ */
+static ssize_t tomoyo_write(struct file *file, const char __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	return tomoyo_write_control(file, buf, count);
+}
+
+/*
+ * tomoyo_operations is a "struct file_operations" which is used for handling
+ * /sys/kernel/security/tomoyo/ interface.
+ *
+ * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR).
+ * See tomoyo_io_buffer for internals.
+ */
+static const struct file_operations tomoyo_operations = {
+	.open    = tomoyo_open,
+	.release = tomoyo_release,
+	.poll    = tomoyo_poll,
+	.read    = tomoyo_read,
+	.write   = tomoyo_write,
+	.llseek  = noop_llseek,
+};
+
+/**
+ * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory.
+ *
+ * @name:   The name of the interface file.
+ * @mode:   The permission of the interface file.
+ * @parent: The parent directory.
+ * @key:    Type of interface.
+ *
+ * Returns nothing.
+ */
+static void __init tomoyo_create_entry(const char *name, const mode_t mode,
+				       struct dentry *parent, const u8 key)
+{
+	securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key,
+			       &tomoyo_operations);
+}
+
+/**
+ * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface.
+ *
+ * Returns 0.
+ */
+static int __init tomoyo_initerface_init(void)
+{
+	struct dentry *tomoyo_dir;
+
+	/* Don't create securityfs entries unless registered. */
+	if (current_cred()->security != &tomoyo_kernel_domain)
+		return 0;
+
+	tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
+	tomoyo_create_entry("query",            0600, tomoyo_dir,
+			    TOMOYO_QUERY);
+	tomoyo_create_entry("domain_policy",    0600, tomoyo_dir,
+			    TOMOYO_DOMAINPOLICY);
+	tomoyo_create_entry("exception_policy", 0600, tomoyo_dir,
+			    TOMOYO_EXCEPTIONPOLICY);
+	tomoyo_create_entry("self_domain",      0400, tomoyo_dir,
+			    TOMOYO_SELFDOMAIN);
+	tomoyo_create_entry(".domain_status",   0600, tomoyo_dir,
+			    TOMOYO_DOMAIN_STATUS);
+	tomoyo_create_entry(".process_status",  0600, tomoyo_dir,
+			    TOMOYO_PROCESS_STATUS);
+	tomoyo_create_entry("meminfo",          0600, tomoyo_dir,
+			    TOMOYO_MEMINFO);
+	tomoyo_create_entry("profile",          0600, tomoyo_dir,
+			    TOMOYO_PROFILE);
+	tomoyo_create_entry("manager",          0600, tomoyo_dir,
+			    TOMOYO_MANAGER);
+	tomoyo_create_entry("version",          0400, tomoyo_dir,
+			    TOMOYO_VERSION);
+	return 0;
+}
+
+fs_initcall(tomoyo_initerface_init);
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index dedd97d..95d3f95 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -3,10 +3,7 @@
  *
  * LSM hooks for TOMOYO Linux.
  *
- * Copyright (C) 2005-2009  NTT DATA CORPORATION
- *
- * Version: 2.2.0   2009/04/01
- *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
  */
 
 #include <linux/security.h>
@@ -96,8 +93,7 @@
 	return tomoyo_check_open_permission(domain, &bprm->file->f_path, O_RDONLY);
 }
 
-static int tomoyo_path_truncate(struct path *path, loff_t length,
-				unsigned int time_attrs)
+static int tomoyo_path_truncate(struct path *path)
 {
 	return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path);
 }
@@ -112,7 +108,8 @@
 			     int mode)
 {
 	struct path path = { parent->mnt, dentry };
-	return tomoyo_path_perm(TOMOYO_TYPE_MKDIR, &path);
+	return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path,
+				       mode & S_IALLUGO);
 }
 
 static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry)
@@ -133,6 +130,7 @@
 {
 	struct path path = { parent->mnt, dentry };
 	int type = TOMOYO_TYPE_CREATE;
+	const unsigned int perm = mode & S_IALLUGO;
 
 	switch (mode & S_IFMT) {
 	case S_IFCHR:
@@ -141,6 +139,12 @@
 	case S_IFBLK:
 		type = TOMOYO_TYPE_MKBLOCK;
 		break;
+	default:
+		goto no_dev;
+	}
+	return tomoyo_mkdev_perm(type, &path, perm, dev);
+ no_dev:
+	switch (mode & S_IFMT) {
 	case S_IFIFO:
 		type = TOMOYO_TYPE_MKFIFO;
 		break;
@@ -148,7 +152,7 @@
 		type = TOMOYO_TYPE_MKSOCK;
 		break;
 	}
-	return tomoyo_path_perm(type, &path);
+	return tomoyo_path_number_perm(type, &path, perm);
 }
 
 static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir,
@@ -173,7 +177,7 @@
 			     unsigned long arg)
 {
 	if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))
-		return tomoyo_check_rewrite_permission(file);
+		return tomoyo_path_perm(TOMOYO_TYPE_REWRITE, &file->f_path);
 	return 0;
 }
 
@@ -189,23 +193,24 @@
 static int tomoyo_file_ioctl(struct file *file, unsigned int cmd,
 			     unsigned long arg)
 {
-	return tomoyo_path_perm(TOMOYO_TYPE_IOCTL, &file->f_path);
+	return tomoyo_path_number_perm(TOMOYO_TYPE_IOCTL, &file->f_path, cmd);
 }
 
 static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
 			     mode_t mode)
 {
 	struct path path = { mnt, dentry };
-	return tomoyo_path_perm(TOMOYO_TYPE_CHMOD, &path);
+	return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, &path,
+				       mode & S_IALLUGO);
 }
 
 static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid)
 {
 	int error = 0;
 	if (uid != (uid_t) -1)
-		error = tomoyo_path_perm(TOMOYO_TYPE_CHOWN, path);
+		error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, uid);
 	if (!error && gid != (gid_t) -1)
-		error = tomoyo_path_perm(TOMOYO_TYPE_CHGRP, path);
+		error = tomoyo_path_number_perm(TOMOYO_TYPE_CHGRP, path, gid);
 	return error;
 }
 
@@ -217,7 +222,7 @@
 static int tomoyo_sb_mount(char *dev_name, struct path *path,
 			   char *type, unsigned long flags, void *data)
 {
-	return tomoyo_path_perm(TOMOYO_TYPE_MOUNT, path);
+	return tomoyo_mount_permission(dev_name, path, type, flags, data);
 }
 
 static int tomoyo_sb_umount(struct vfsmount *mnt, int flags)
@@ -277,7 +282,7 @@
 		panic("Failure registering TOMOYO Linux");
 	printk(KERN_INFO "TOMOYO Linux initialized\n");
 	cred->security = &tomoyo_kernel_domain;
-	tomoyo_realpath_init();
+	tomoyo_mm_init();
 	return 0;
 }
 
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c
new file mode 100644
index 0000000..9bfc1ee
--- /dev/null
+++ b/security/tomoyo/util.c
@@ -0,0 +1,963 @@
+/*
+ * security/tomoyo/util.c
+ *
+ * Utility functions for TOMOYO.
+ *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+/* Lock for protecting policy. */
+DEFINE_MUTEX(tomoyo_policy_lock);
+
+/* Has /sbin/init started? */
+bool tomoyo_policy_loaded;
+
+/**
+ * tomoyo_parse_ulong - Parse an "unsigned long" value.
+ *
+ * @result: Pointer to "unsigned long".
+ * @str:    Pointer to string to parse.
+ *
+ * Returns value type on success, 0 otherwise.
+ *
+ * The @src is updated to point the first character after the value
+ * on success.
+ */
+static u8 tomoyo_parse_ulong(unsigned long *result, char **str)
+{
+	const char *cp = *str;
+	char *ep;
+	int base = 10;
+	if (*cp == '0') {
+		char c = *(cp + 1);
+		if (c == 'x' || c == 'X') {
+			base = 16;
+			cp += 2;
+		} else if (c >= '0' && c <= '7') {
+			base = 8;
+			cp++;
+		}
+	}
+	*result = simple_strtoul(cp, &ep, base);
+	if (cp == ep)
+		return 0;
+	*str = ep;
+	switch (base) {
+	case 16:
+		return TOMOYO_VALUE_TYPE_HEXADECIMAL;
+	case 8:
+		return TOMOYO_VALUE_TYPE_OCTAL;
+	default:
+		return TOMOYO_VALUE_TYPE_DECIMAL;
+	}
+}
+
+/**
+ * tomoyo_print_ulong - Print an "unsigned long" value.
+ *
+ * @buffer:     Pointer to buffer.
+ * @buffer_len: Size of @buffer.
+ * @value:      An "unsigned long" value.
+ * @type:       Type of @value.
+ *
+ * Returns nothing.
+ */
+void tomoyo_print_ulong(char *buffer, const int buffer_len,
+			const unsigned long value, const u8 type)
+{
+	if (type == TOMOYO_VALUE_TYPE_DECIMAL)
+		snprintf(buffer, buffer_len, "%lu", value);
+	else if (type == TOMOYO_VALUE_TYPE_OCTAL)
+		snprintf(buffer, buffer_len, "0%lo", value);
+	else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL)
+		snprintf(buffer, buffer_len, "0x%lX", value);
+	else
+		snprintf(buffer, buffer_len, "type(%u)", type);
+}
+
+/**
+ * tomoyo_parse_name_union - Parse a tomoyo_name_union.
+ *
+ * @filename: Name or name group.
+ * @ptr:      Pointer to "struct tomoyo_name_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_parse_name_union(const char *filename,
+			     struct tomoyo_name_union *ptr)
+{
+	if (!tomoyo_correct_word(filename))
+		return false;
+	if (filename[0] == '@') {
+		ptr->group = tomoyo_get_group(filename + 1, TOMOYO_PATH_GROUP);
+		ptr->is_group = true;
+		return ptr->group != NULL;
+	}
+	ptr->filename = tomoyo_get_name(filename);
+	ptr->is_group = false;
+	return ptr->filename != NULL;
+}
+
+/**
+ * tomoyo_parse_number_union - Parse a tomoyo_number_union.
+ *
+ * @data: Number or number range or number group.
+ * @ptr:  Pointer to "struct tomoyo_number_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num)
+{
+	u8 type;
+	unsigned long v;
+	memset(num, 0, sizeof(*num));
+	if (data[0] == '@') {
+		if (!tomoyo_correct_word(data))
+			return false;
+		num->group = tomoyo_get_group(data + 1, TOMOYO_NUMBER_GROUP);
+		num->is_group = true;
+		return num->group != NULL;
+	}
+	type = tomoyo_parse_ulong(&v, &data);
+	if (!type)
+		return false;
+	num->values[0] = v;
+	num->min_type = type;
+	if (!*data) {
+		num->values[1] = v;
+		num->max_type = type;
+		return true;
+	}
+	if (*data++ != '-')
+		return false;
+	type = tomoyo_parse_ulong(&v, &data);
+	if (!type || *data)
+		return false;
+	num->values[1] = v;
+	num->max_type = type;
+	return true;
+}
+
+/**
+ * tomoyo_byte_range - Check whether the string is a \ooo style octal value.
+ *
+ * @str: Pointer to the string.
+ *
+ * Returns true if @str is a \ooo style octal value, false otherwise.
+ *
+ * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
+ * This function verifies that \ooo is in valid range.
+ */
+static inline bool tomoyo_byte_range(const char *str)
+{
+	return *str >= '0' && *str++ <= '3' &&
+		*str >= '0' && *str++ <= '7' &&
+		*str >= '0' && *str <= '7';
+}
+
+/**
+ * tomoyo_alphabet_char - Check whether the character is an alphabet.
+ *
+ * @c: The character to check.
+ *
+ * Returns true if @c is an alphabet character, false otherwise.
+ */
+static inline bool tomoyo_alphabet_char(const char c)
+{
+	return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+}
+
+/**
+ * tomoyo_make_byte - Make byte value from three octal characters.
+ *
+ * @c1: The first character.
+ * @c2: The second character.
+ * @c3: The third character.
+ *
+ * Returns byte value.
+ */
+static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
+{
+	return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
+}
+
+/**
+ * tomoyo_str_starts - Check whether the given string starts with the given keyword.
+ *
+ * @src:  Pointer to pointer to the string.
+ * @find: Pointer to the keyword.
+ *
+ * Returns true if @src starts with @find, false otherwise.
+ *
+ * The @src is updated to point the first character after the @find
+ * if @src starts with @find.
+ */
+bool tomoyo_str_starts(char **src, const char *find)
+{
+	const int len = strlen(find);
+	char *tmp = *src;
+
+	if (strncmp(tmp, find, len))
+		return false;
+	tmp += len;
+	*src = tmp;
+	return true;
+}
+
+/**
+ * tomoyo_normalize_line - Format string.
+ *
+ * @buffer: The line to normalize.
+ *
+ * Leading and trailing whitespaces are removed.
+ * Multiple whitespaces are packed into single space.
+ *
+ * Returns nothing.
+ */
+void tomoyo_normalize_line(unsigned char *buffer)
+{
+	unsigned char *sp = buffer;
+	unsigned char *dp = buffer;
+	bool first = true;
+
+	while (tomoyo_invalid(*sp))
+		sp++;
+	while (*sp) {
+		if (!first)
+			*dp++ = ' ';
+		first = false;
+		while (tomoyo_valid(*sp))
+			*dp++ = *sp++;
+		while (tomoyo_invalid(*sp))
+			sp++;
+	}
+	*dp = '\0';
+}
+
+/**
+ * tomoyo_tokenize - Tokenize string.
+ *
+ * @buffer: The line to tokenize.
+ * @w:      Pointer to "char *".
+ * @size:   Sizeof @w .
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_tokenize(char *buffer, char *w[], size_t size)
+{
+	int count = size / sizeof(char *);
+	int i;
+	for (i = 0; i < count; i++)
+		w[i] = "";
+	for (i = 0; i < count; i++) {
+		char *cp = strchr(buffer, ' ');
+		if (cp)
+			*cp = '\0';
+		w[i] = buffer;
+		if (!cp)
+			break;
+		buffer = cp + 1;
+	}
+	return i < count || !*buffer;
+}
+
+/**
+ * tomoyo_correct_word2 - Validate a string.
+ *
+ * @string: The string to check. May be non-'\0'-terminated.
+ * @len:    Length of @string.
+ *
+ * Check whether the given string follows the naming rules.
+ * Returns true if @string follows the naming rules, false otherwise.
+ */
+static bool tomoyo_correct_word2(const char *string, size_t len)
+{
+	const char *const start = string;
+	bool in_repetition = false;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	if (!len)
+		goto out;
+	while (len--) {
+		c = *string++;
+		if (c == '\\') {
+			if (!len--)
+				goto out;
+			c = *string++;
+			switch (c) {
+			case '\\':  /* "\\" */
+				continue;
+			case '$':   /* "\$" */
+			case '+':   /* "\+" */
+			case '?':   /* "\?" */
+			case '*':   /* "\*" */
+			case '@':   /* "\@" */
+			case 'x':   /* "\x" */
+			case 'X':   /* "\X" */
+			case 'a':   /* "\a" */
+			case 'A':   /* "\A" */
+			case '-':   /* "\-" */
+				continue;
+			case '{':   /* "/\{" */
+				if (string - 3 < start || *(string - 3) != '/')
+					break;
+				in_repetition = true;
+				continue;
+			case '}':   /* "\}/" */
+				if (*string != '/')
+					break;
+				if (!in_repetition)
+					break;
+				in_repetition = false;
+				continue;
+			case '0':   /* "\ooo" */
+			case '1':
+			case '2':
+			case '3':
+				if (!len-- || !len--)
+					break;
+				d = *string++;
+				e = *string++;
+				if (d < '0' || d > '7' || e < '0' || e > '7')
+					break;
+				c = tomoyo_make_byte(c, d, e);
+				if (tomoyo_invalid(c))
+					continue; /* pattern is not \000 */
+			}
+			goto out;
+		} else if (in_repetition && c == '/') {
+			goto out;
+		} else if (tomoyo_invalid(c)) {
+			goto out;
+		}
+	}
+	if (in_repetition)
+		goto out;
+	return true;
+ out:
+	return false;
+}
+
+/**
+ * tomoyo_correct_word - Validate a string.
+ *
+ * @string: The string to check.
+ *
+ * Check whether the given string follows the naming rules.
+ * Returns true if @string follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_word(const char *string)
+{
+	return tomoyo_correct_word2(string, strlen(string));
+}
+
+/**
+ * tomoyo_correct_path - Validate a pathname.
+ *
+ * @filename: The pathname to check.
+ *
+ * Check whether the given pathname follows the naming rules.
+ * Returns true if @filename follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_path(const char *filename)
+{
+	return *filename == '/' && tomoyo_correct_word(filename);
+}
+
+/**
+ * tomoyo_correct_domain - Check whether the given domainname follows the naming rules.
+ *
+ * @domainname: The domainname to check.
+ *
+ * Returns true if @domainname follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_domain(const unsigned char *domainname)
+{
+	if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
+				   TOMOYO_ROOT_NAME_LEN))
+		goto out;
+	domainname += TOMOYO_ROOT_NAME_LEN;
+	if (!*domainname)
+		return true;
+	if (*domainname++ != ' ')
+		goto out;
+	while (1) {
+		const unsigned char *cp = strchr(domainname, ' ');
+		if (!cp)
+			break;
+		if (*domainname != '/' ||
+		    !tomoyo_correct_word2(domainname, cp - domainname - 1))
+			goto out;
+		domainname = cp + 1;
+	}
+	return tomoyo_correct_path(domainname);
+ out:
+	return false;
+}
+
+/**
+ * tomoyo_domain_def - Check whether the given token can be a domainname.
+ *
+ * @buffer: The token to check.
+ *
+ * Returns true if @buffer possibly be a domainname, false otherwise.
+ */
+bool tomoyo_domain_def(const unsigned char *buffer)
+{
+	return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
+}
+
+/**
+ * tomoyo_find_domain - Find a domain by the given name.
+ *
+ * @domainname: The domainname to find.
+ *
+ * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
+{
+	struct tomoyo_domain_info *domain;
+	struct tomoyo_path_info name;
+
+	name.name = domainname;
+	tomoyo_fill_path_info(&name);
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
+		if (!domain->is_deleted &&
+		    !tomoyo_pathcmp(&name, domain->domainname))
+			return domain;
+	}
+	return NULL;
+}
+
+/**
+ * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
+ *
+ * @filename: The string to evaluate.
+ *
+ * Returns the initial length without a pattern in @filename.
+ */
+static int tomoyo_const_part_length(const char *filename)
+{
+	char c;
+	int len = 0;
+
+	if (!filename)
+		return 0;
+	while ((c = *filename++) != '\0') {
+		if (c != '\\') {
+			len++;
+			continue;
+		}
+		c = *filename++;
+		switch (c) {
+		case '\\':  /* "\\" */
+			len += 2;
+			continue;
+		case '0':   /* "\ooo" */
+		case '1':
+		case '2':
+		case '3':
+			c = *filename++;
+			if (c < '0' || c > '7')
+				break;
+			c = *filename++;
+			if (c < '0' || c > '7')
+				break;
+			len += 4;
+			continue;
+		}
+		break;
+	}
+	return len;
+}
+
+/**
+ * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
+ *
+ * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
+ *
+ * The caller sets "struct tomoyo_path_info"->name.
+ */
+void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
+{
+	const char *name = ptr->name;
+	const int len = strlen(name);
+
+	ptr->const_len = tomoyo_const_part_length(name);
+	ptr->is_dir = len && (name[len - 1] == '/');
+	ptr->is_patterned = (ptr->const_len < len);
+	ptr->hash = full_name_hash(name, len);
+}
+
+/**
+ * tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
+ *
+ * @filename:     The start of string to check.
+ * @filename_end: The end of string to check.
+ * @pattern:      The start of pattern to compare.
+ * @pattern_end:  The end of pattern to compare.
+ *
+ * Returns true if @filename matches @pattern, false otherwise.
+ */
+static bool tomoyo_file_matches_pattern2(const char *filename,
+					 const char *filename_end,
+					 const char *pattern,
+					 const char *pattern_end)
+{
+	while (filename < filename_end && pattern < pattern_end) {
+		char c;
+		if (*pattern != '\\') {
+			if (*filename++ != *pattern++)
+				return false;
+			continue;
+		}
+		c = *filename;
+		pattern++;
+		switch (*pattern) {
+			int i;
+			int j;
+		case '?':
+			if (c == '/') {
+				return false;
+			} else if (c == '\\') {
+				if (filename[1] == '\\')
+					filename++;
+				else if (tomoyo_byte_range(filename + 1))
+					filename += 3;
+				else
+					return false;
+			}
+			break;
+		case '\\':
+			if (c != '\\')
+				return false;
+			if (*++filename != '\\')
+				return false;
+			break;
+		case '+':
+			if (!isdigit(c))
+				return false;
+			break;
+		case 'x':
+			if (!isxdigit(c))
+				return false;
+			break;
+		case 'a':
+			if (!tomoyo_alphabet_char(c))
+				return false;
+			break;
+		case '0':
+		case '1':
+		case '2':
+		case '3':
+			if (c == '\\' && tomoyo_byte_range(filename + 1)
+			    && strncmp(filename + 1, pattern, 3) == 0) {
+				filename += 3;
+				pattern += 2;
+				break;
+			}
+			return false; /* Not matched. */
+		case '*':
+		case '@':
+			for (i = 0; i <= filename_end - filename; i++) {
+				if (tomoyo_file_matches_pattern2(
+						    filename + i, filename_end,
+						    pattern + 1, pattern_end))
+					return true;
+				c = filename[i];
+				if (c == '.' && *pattern == '@')
+					break;
+				if (c != '\\')
+					continue;
+				if (filename[i + 1] == '\\')
+					i++;
+				else if (tomoyo_byte_range(filename + i + 1))
+					i += 3;
+				else
+					break; /* Bad pattern. */
+			}
+			return false; /* Not matched. */
+		default:
+			j = 0;
+			c = *pattern;
+			if (c == '$') {
+				while (isdigit(filename[j]))
+					j++;
+			} else if (c == 'X') {
+				while (isxdigit(filename[j]))
+					j++;
+			} else if (c == 'A') {
+				while (tomoyo_alphabet_char(filename[j]))
+					j++;
+			}
+			for (i = 1; i <= j; i++) {
+				if (tomoyo_file_matches_pattern2(
+						    filename + i, filename_end,
+						    pattern + 1, pattern_end))
+					return true;
+			}
+			return false; /* Not matched or bad pattern. */
+		}
+		filename++;
+		pattern++;
+	}
+	while (*pattern == '\\' &&
+	       (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
+		pattern += 2;
+	return filename == filename_end && pattern == pattern_end;
+}
+
+/**
+ * tomoyo_file_matches_pattern - Pattern matching without '/' character.
+ *
+ * @filename:     The start of string to check.
+ * @filename_end: The end of string to check.
+ * @pattern:      The start of pattern to compare.
+ * @pattern_end:  The end of pattern to compare.
+ *
+ * Returns true if @filename matches @pattern, false otherwise.
+ */
+static bool tomoyo_file_matches_pattern(const char *filename,
+					const char *filename_end,
+					const char *pattern,
+					const char *pattern_end)
+{
+	const char *pattern_start = pattern;
+	bool first = true;
+	bool result;
+
+	while (pattern < pattern_end - 1) {
+		/* Split at "\-" pattern. */
+		if (*pattern++ != '\\' || *pattern++ != '-')
+			continue;
+		result = tomoyo_file_matches_pattern2(filename,
+						      filename_end,
+						      pattern_start,
+						      pattern - 2);
+		if (first)
+			result = !result;
+		if (result)
+			return false;
+		first = false;
+		pattern_start = pattern;
+	}
+	result = tomoyo_file_matches_pattern2(filename, filename_end,
+					      pattern_start, pattern_end);
+	return first ? result : !result;
+}
+
+/**
+ * tomoyo_path_matches_pattern2 - Do pathname pattern matching.
+ *
+ * @f: The start of string to check.
+ * @p: The start of pattern to compare.
+ *
+ * Returns true if @f matches @p, false otherwise.
+ */
+static bool tomoyo_path_matches_pattern2(const char *f, const char *p)
+{
+	const char *f_delimiter;
+	const char *p_delimiter;
+
+	while (*f && *p) {
+		f_delimiter = strchr(f, '/');
+		if (!f_delimiter)
+			f_delimiter = f + strlen(f);
+		p_delimiter = strchr(p, '/');
+		if (!p_delimiter)
+			p_delimiter = p + strlen(p);
+		if (*p == '\\' && *(p + 1) == '{')
+			goto recursive;
+		if (!tomoyo_file_matches_pattern(f, f_delimiter, p,
+						 p_delimiter))
+			return false;
+		f = f_delimiter;
+		if (*f)
+			f++;
+		p = p_delimiter;
+		if (*p)
+			p++;
+	}
+	/* Ignore trailing "\*" and "\@" in @pattern. */
+	while (*p == '\\' &&
+	       (*(p + 1) == '*' || *(p + 1) == '@'))
+		p += 2;
+	return !*f && !*p;
+ recursive:
+	/*
+	 * The "\{" pattern is permitted only after '/' character.
+	 * This guarantees that below "*(p - 1)" is safe.
+	 * Also, the "\}" pattern is permitted only before '/' character
+	 * so that "\{" + "\}" pair will not break the "\-" operator.
+	 */
+	if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
+	    *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
+		return false; /* Bad pattern. */
+	do {
+		/* Compare current component with pattern. */
+		if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2,
+						 p_delimiter - 2))
+			break;
+		/* Proceed to next component. */
+		f = f_delimiter;
+		if (!*f)
+			break;
+		f++;
+		/* Continue comparison. */
+		if (tomoyo_path_matches_pattern2(f, p_delimiter + 1))
+			return true;
+		f_delimiter = strchr(f, '/');
+	} while (f_delimiter);
+	return false; /* Not matched. */
+}
+
+/**
+ * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
+ *
+ * @filename: The filename to check.
+ * @pattern:  The pattern to compare.
+ *
+ * Returns true if matches, false otherwise.
+ *
+ * The following patterns are available.
+ *   \\     \ itself.
+ *   \ooo   Octal representation of a byte.
+ *   \*     Zero or more repetitions of characters other than '/'.
+ *   \@     Zero or more repetitions of characters other than '/' or '.'.
+ *   \?     1 byte character other than '/'.
+ *   \$     One or more repetitions of decimal digits.
+ *   \+     1 decimal digit.
+ *   \X     One or more repetitions of hexadecimal digits.
+ *   \x     1 hexadecimal digit.
+ *   \A     One or more repetitions of alphabet characters.
+ *   \a     1 alphabet character.
+ *
+ *   \-     Subtraction operator.
+ *
+ *   /\{dir\}/   '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
+ *               /dir/dir/dir/ ).
+ */
+bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
+				 const struct tomoyo_path_info *pattern)
+{
+	const char *f = filename->name;
+	const char *p = pattern->name;
+	const int len = pattern->const_len;
+
+	/* If @pattern doesn't contain pattern, I can use strcmp(). */
+	if (!pattern->is_patterned)
+		return !tomoyo_pathcmp(filename, pattern);
+	/* Don't compare directory and non-directory. */
+	if (filename->is_dir != pattern->is_dir)
+		return false;
+	/* Compare the initial length without patterns. */
+	if (strncmp(f, p, len))
+		return false;
+	f += len;
+	p += len;
+	return tomoyo_path_matches_pattern2(f, p);
+}
+
+/**
+ * tomoyo_get_exe - Get tomoyo_realpath() of current process.
+ *
+ * Returns the tomoyo_realpath() of current process on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so the caller must call kfree()
+ * if this function didn't return NULL.
+ */
+const char *tomoyo_get_exe(void)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	const char *cp = NULL;
+
+	if (!mm)
+		return NULL;
+	down_read(&mm->mmap_sem);
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
+			cp = tomoyo_realpath_from_path(&vma->vm_file->f_path);
+			break;
+		}
+	}
+	up_read(&mm->mmap_sem);
+	return cp;
+}
+
+/**
+ * tomoyo_get_mode - Get MAC mode.
+ *
+ * @profile: Profile number.
+ * @index:   Index number of functionality.
+ *
+ * Returns mode.
+ */
+int tomoyo_get_mode(const u8 profile, const u8 index)
+{
+	u8 mode;
+	const u8 category = TOMOYO_MAC_CATEGORY_FILE;
+	if (!tomoyo_policy_loaded)
+		return TOMOYO_CONFIG_DISABLED;
+	mode = tomoyo_profile(profile)->config[index];
+	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+		mode = tomoyo_profile(profile)->config[category];
+	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+		mode = tomoyo_profile(profile)->default_config;
+	return mode & 3;
+}
+
+/**
+ * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members.
+ *
+ * @r:      Pointer to "struct tomoyo_request_info" to initialize.
+ * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain().
+ * @index:  Index number of functionality.
+ *
+ * Returns mode.
+ */
+int tomoyo_init_request_info(struct tomoyo_request_info *r,
+			     struct tomoyo_domain_info *domain, const u8 index)
+{
+	u8 profile;
+	memset(r, 0, sizeof(*r));
+	if (!domain)
+		domain = tomoyo_domain();
+	r->domain = domain;
+	profile = domain->profile;
+	r->profile = profile;
+	r->type = index;
+	r->mode = tomoyo_get_mode(profile, index);
+	return r->mode;
+}
+
+/**
+ * tomoyo_last_word - Get last component of a line.
+ *
+ * @line: A line.
+ *
+ * Returns the last word of a line.
+ */
+const char *tomoyo_last_word(const char *name)
+{
+	const char *cp = strrchr(name, ' ');
+	if (cp)
+		return cp + 1;
+	return name;
+}
+
+/**
+ * tomoyo_warn_log - Print warning or error message on console.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @fmt: The printf()'s format string, followed by parameters.
+ */
+void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
+{
+	va_list args;
+	char *buffer;
+	const struct tomoyo_domain_info * const domain = r->domain;
+	const struct tomoyo_profile *profile = tomoyo_profile(domain->profile);
+	switch (r->mode) {
+	case TOMOYO_CONFIG_ENFORCING:
+		if (!profile->enforcing->enforcing_verbose)
+			return;
+		break;
+	case TOMOYO_CONFIG_PERMISSIVE:
+		if (!profile->permissive->permissive_verbose)
+			return;
+		break;
+	case TOMOYO_CONFIG_LEARNING:
+		if (!profile->learning->learning_verbose)
+			return;
+		break;
+	}
+	buffer = kmalloc(4096, GFP_NOFS);
+	if (!buffer)
+		return;
+	va_start(args, fmt);
+	vsnprintf(buffer, 4095, fmt, args);
+	va_end(args);
+	buffer[4095] = '\0';
+	printk(KERN_WARNING "%s: Access %s denied for %s\n",
+	       r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer,
+	       tomoyo_last_word(domain->domainname->name));
+	kfree(buffer);
+}
+
+/**
+ * tomoyo_domain_quota_is_ok - Check for domain's quota.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns true if the domain is not exceeded quota, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
+{
+	unsigned int count = 0;
+	struct tomoyo_domain_info *domain = r->domain;
+	struct tomoyo_acl_info *ptr;
+
+	if (r->mode != TOMOYO_CONFIG_LEARNING)
+		return false;
+	if (!domain)
+		return true;
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+		if (ptr->is_deleted)
+			continue;
+		switch (ptr->type) {
+			u16 perm;
+			u8 i;
+		case TOMOYO_TYPE_PATH_ACL:
+			perm = container_of(ptr, struct tomoyo_path_acl, head)
+				->perm;
+			for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++)
+				if (perm & (1 << i))
+					count++;
+			if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
+				count -= 2;
+			break;
+		case TOMOYO_TYPE_PATH2_ACL:
+			perm = container_of(ptr, struct tomoyo_path2_acl, head)
+				->perm;
+			for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++)
+				if (perm & (1 << i))
+					count++;
+			break;
+		case TOMOYO_TYPE_PATH_NUMBER_ACL:
+			perm = container_of(ptr, struct tomoyo_path_number_acl,
+					    head)->perm;
+			for (i = 0; i < TOMOYO_MAX_PATH_NUMBER_OPERATION; i++)
+				if (perm & (1 << i))
+					count++;
+			break;
+		case TOMOYO_TYPE_MKDEV_ACL:
+			perm = container_of(ptr, struct tomoyo_mkdev_acl,
+					    head)->perm;
+			for (i = 0; i < TOMOYO_MAX_MKDEV_OPERATION; i++)
+				if (perm & (1 << i))
+					count++;
+			break;
+		default:
+			count++;
+		}
+	}
+	if (count < tomoyo_profile(domain->profile)->learning->
+	    learning_max_entry)
+		return true;
+	if (!domain->quota_warned) {
+		domain->quota_warned = true;
+		printk(KERN_WARNING "TOMOYO-WARNING: "
+		       "Domain '%s' has so many ACLs to hold. "
+		       "Stopped learning mode.\n", domain->domainname->name);
+	}
+	return false;
+}
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 303ac04..a3b2a64 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -451,13 +451,11 @@
 	snd_pcm_timer_resolution_change(substream);
 	runtime->status->state = SNDRV_PCM_STATE_SETUP;
 
-	if (substream->latency_pm_qos_req) {
-		pm_qos_remove_request(substream->latency_pm_qos_req);
-		substream->latency_pm_qos_req = NULL;
-	}
+	if (pm_qos_request_active(&substream->latency_pm_qos_req))
+		pm_qos_remove_request(&substream->latency_pm_qos_req);
 	if ((usecs = period_to_usecs(runtime)) >= 0)
-		substream->latency_pm_qos_req = pm_qos_add_request(
-					PM_QOS_CPU_DMA_LATENCY, usecs);
+		pm_qos_add_request(&substream->latency_pm_qos_req,
+				   PM_QOS_CPU_DMA_LATENCY, usecs);
 	return 0;
  _error:
 	/* hardware might be unuseable from this time,
@@ -512,8 +510,7 @@
 	if (substream->ops->hw_free)
 		result = substream->ops->hw_free(substream);
 	runtime->status->state = SNDRV_PCM_STATE_OPEN;
-	pm_qos_remove_request(substream->latency_pm_qos_req);
-	substream->latency_pm_qos_req = NULL;
+	pm_qos_remove_request(&substream->latency_pm_qos_req);
 	return result;
 }
 
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 5a52ed9..5161619 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -300,8 +300,9 @@
 
 struct power_entry {
 	struct trace_entry te;
-	s64	type;
-	s64	value;
+	u64	type;
+	u64	value;
+	u64	cpu_id;
 };
 
 #define TASK_COMM_LEN 16
@@ -498,13 +499,13 @@
 			return 0;
 
 		if (strcmp(event_str, "power:power_start") == 0)
-			c_state_start(data.cpu, data.time, pe->value);
+			c_state_start(pe->cpu_id, data.time, pe->value);
 
 		if (strcmp(event_str, "power:power_end") == 0)
-			c_state_end(data.cpu, data.time);
+			c_state_end(pe->cpu_id, data.time);
 
 		if (strcmp(event_str, "power:power_frequency") == 0)
-			p_state_change(data.cpu, data.time, pe->value);
+			p_state_change(pe->cpu_id, data.time, pe->value);
 
 		if (strcmp(event_str, "sched:sched_wakeup") == 0)
 			sched_wakeup(data.cpu, data.time, data.pid, te);
diff --git a/virt/kvm/assigned-dev.c b/virt/kvm/assigned-dev.c
index 4d10b1e..7c98928 100644
--- a/virt/kvm/assigned-dev.c
+++ b/virt/kvm/assigned-dev.c
@@ -1,7 +1,7 @@
 /*
  * Kernel-based Virtual Machine - device assignment support
  *
- * Copyright (C) 2006-9 Red Hat, Inc
+ * Copyright (C) 2010 Red Hat, Inc. and/or its affiliates.
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
@@ -58,12 +58,10 @@
 static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
 {
 	struct kvm_assigned_dev_kernel *assigned_dev;
-	struct kvm *kvm;
 	int i;
 
 	assigned_dev = container_of(work, struct kvm_assigned_dev_kernel,
 				    interrupt_work);
-	kvm = assigned_dev->kvm;
 
 	spin_lock_irq(&assigned_dev->assigned_dev_lock);
 	if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
@@ -448,9 +446,6 @@
 	struct kvm_assigned_dev_kernel *match;
 	unsigned long host_irq_type, guest_irq_type;
 
-	if (!capable(CAP_SYS_RAWIO))
-		return -EPERM;
-
 	if (!irqchip_in_kernel(kvm))
 		return r;
 
diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c
index 5385017..fc84875 100644
--- a/virt/kvm/coalesced_mmio.c
+++ b/virt/kvm/coalesced_mmio.c
@@ -2,6 +2,7 @@
  * KVM coalesced MMIO
  *
  * Copyright (c) 2008 Bull S.A.S.
+ * Copyright 2009 Red Hat, Inc. and/or its affiliates.
  *
  *  Author: Laurent Vivier <Laurent.Vivier@bull.net>
  *
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
index b81f0eb..66cf65b 100644
--- a/virt/kvm/eventfd.c
+++ b/virt/kvm/eventfd.c
@@ -2,6 +2,7 @@
  * kvm eventfd support - use eventfd objects to signal various KVM events
  *
  * Copyright 2009 Novell.  All Rights Reserved.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
  *
  * Author:
  *	Gregory Haskins <ghaskins@novell.com>
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 3500dee..0b9df83 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -1,5 +1,6 @@
 /*
  *  Copyright (C) 2001  MandrakeSoft S.A.
+ *  Copyright 2010 Red Hat, Inc. and/or its affiliates.
  *
  *    MandrakeSoft S.A.
  *    43, rue d'Aboukir
@@ -151,7 +152,7 @@
 		update_handled_vectors(ioapic);
 		mask_after = e->fields.mask;
 		if (mask_before != mask_after)
-			kvm_fire_mask_notifiers(ioapic->kvm, index, mask_after);
+			kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after);
 		if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG
 		    && ioapic->irr & (1 << index))
 			ioapic_service(ioapic, index);
diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
index 96048ee..62a9caf 100644
--- a/virt/kvm/iommu.c
+++ b/virt/kvm/iommu.c
@@ -16,6 +16,8 @@
  *
  * Copyright (C) 2006-2008 Intel Corporation
  * Copyright IBM Corporation, 2008
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
+ *
  * Author: Allen M. Kay <allen.m.kay@intel.com>
  * Author: Weidong Han <weidong.han@intel.com>
  * Author: Ben-Ami Yassour <benami@il.ibm.com>
@@ -106,7 +108,7 @@
 			      get_order(page_size), flags);
 		if (r) {
 			printk(KERN_ERR "kvm_iommu_map_address:"
-			       "iommu failed to map pfn=%lx\n", pfn);
+			       "iommu failed to map pfn=%llx\n", pfn);
 			goto unmap_pages;
 		}
 
@@ -124,9 +126,10 @@
 
 static int kvm_iommu_map_memslots(struct kvm *kvm)
 {
-	int i, r = 0;
+	int i, idx, r = 0;
 	struct kvm_memslots *slots;
 
+	idx = srcu_read_lock(&kvm->srcu);
 	slots = kvm_memslots(kvm);
 
 	for (i = 0; i < slots->nmemslots; i++) {
@@ -134,6 +137,7 @@
 		if (r)
 			break;
 	}
+	srcu_read_unlock(&kvm->srcu, idx);
 
 	return r;
 }
@@ -283,15 +287,17 @@
 
 static int kvm_iommu_unmap_memslots(struct kvm *kvm)
 {
-	int i;
+	int i, idx;
 	struct kvm_memslots *slots;
 
+	idx = srcu_read_lock(&kvm->srcu);
 	slots = kvm_memslots(kvm);
 
 	for (i = 0; i < slots->nmemslots; i++) {
 		kvm_iommu_put_pages(kvm, slots->memslots[i].base_gfn,
 				    slots->memslots[i].npages);
 	}
+	srcu_read_unlock(&kvm->srcu, idx);
 
 	return 0;
 }
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index a0e8880..369e380 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -17,6 +17,7 @@
  * Authors:
  *   Yaozu (Eddie) Dong <Eddie.dong@intel.com>
  *
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
  */
 
 #include <linux/kvm_host.h>
@@ -99,7 +100,7 @@
 			if (r < 0)
 				r = 0;
 			r += kvm_apic_set_irq(vcpu, irq);
-		} else {
+		} else if (kvm_lapic_enabled(vcpu)) {
 			if (!lowest)
 				lowest = vcpu;
 			else if (kvm_apic_compare_prio(vcpu, lowest) < 0)
@@ -278,15 +279,19 @@
 	synchronize_rcu();
 }
 
-void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask)
+void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin,
+			     bool mask)
 {
 	struct kvm_irq_mask_notifier *kimn;
 	struct hlist_node *n;
+	int gsi;
 
 	rcu_read_lock();
-	hlist_for_each_entry_rcu(kimn, n, &kvm->mask_notifier_list, link)
-		if (kimn->irq == irq)
-			kimn->func(kimn, mask);
+	gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin];
+	if (gsi != -1)
+		hlist_for_each_entry_rcu(kimn, n, &kvm->mask_notifier_list, link)
+			if (kimn->irq == gsi)
+				kimn->func(kimn, mask);
 	rcu_read_unlock();
 }
 
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index f032806..b78b794 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -5,6 +5,7 @@
  * machines without emulation or binary translation.
  *
  * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
  *
  * Authors:
  *   Avi Kivity   <avi@qumranet.com>
@@ -92,6 +93,12 @@
 
 static bool largepages_enabled = true;
 
+static struct page *hwpoison_page;
+static pfn_t hwpoison_pfn;
+
+static struct page *fault_page;
+static pfn_t fault_pfn;
+
 inline int kvm_is_mmio_pfn(pfn_t pfn)
 {
 	if (pfn_valid(pfn)) {
@@ -141,7 +148,7 @@
 	raw_spin_lock(&kvm->requests_lock);
 	me = smp_processor_id();
 	kvm_for_each_vcpu(i, vcpu, kvm) {
-		if (test_and_set_bit(req, &vcpu->requests))
+		if (kvm_make_check_request(req, vcpu))
 			continue;
 		cpu = vcpu->cpu;
 		if (cpus != NULL && cpu != -1 && cpu != me)
@@ -566,6 +573,7 @@
 
 	new = old = *memslot;
 
+	new.id = mem->slot;
 	new.base_gfn = base_gfn;
 	new.npages = npages;
 	new.flags = mem->flags;
@@ -596,7 +604,7 @@
 	/* Allocate if a slot is being created */
 #ifndef CONFIG_S390
 	if (npages && !new.rmap) {
-		new.rmap = vmalloc(npages * sizeof(struct page *));
+		new.rmap = vmalloc(npages * sizeof(*new.rmap));
 
 		if (!new.rmap)
 			goto out_free;
@@ -621,9 +629,9 @@
 		if (new.lpage_info[i])
 			continue;
 
-		lpages = 1 + (base_gfn + npages - 1) /
-			     KVM_PAGES_PER_HPAGE(level);
-		lpages -= base_gfn / KVM_PAGES_PER_HPAGE(level);
+		lpages = 1 + ((base_gfn + npages - 1)
+			     >> KVM_HPAGE_GFN_SHIFT(level));
+		lpages -= base_gfn >> KVM_HPAGE_GFN_SHIFT(level);
 
 		new.lpage_info[i] = vmalloc(lpages * sizeof(*new.lpage_info[i]));
 
@@ -633,9 +641,9 @@
 		memset(new.lpage_info[i], 0,
 		       lpages * sizeof(*new.lpage_info[i]));
 
-		if (base_gfn % KVM_PAGES_PER_HPAGE(level))
+		if (base_gfn & (KVM_PAGES_PER_HPAGE(level) - 1))
 			new.lpage_info[i][0].write_count = 1;
-		if ((base_gfn+npages) % KVM_PAGES_PER_HPAGE(level))
+		if ((base_gfn+npages) & (KVM_PAGES_PER_HPAGE(level) - 1))
 			new.lpage_info[i][lpages - 1].write_count = 1;
 		ugfn = new.userspace_addr >> PAGE_SHIFT;
 		/*
@@ -810,16 +818,28 @@
 
 int is_error_page(struct page *page)
 {
-	return page == bad_page;
+	return page == bad_page || page == hwpoison_page || page == fault_page;
 }
 EXPORT_SYMBOL_GPL(is_error_page);
 
 int is_error_pfn(pfn_t pfn)
 {
-	return pfn == bad_pfn;
+	return pfn == bad_pfn || pfn == hwpoison_pfn || pfn == fault_pfn;
 }
 EXPORT_SYMBOL_GPL(is_error_pfn);
 
+int is_hwpoison_pfn(pfn_t pfn)
+{
+	return pfn == hwpoison_pfn;
+}
+EXPORT_SYMBOL_GPL(is_hwpoison_pfn);
+
+int is_fault_pfn(pfn_t pfn)
+{
+	return pfn == fault_pfn;
+}
+EXPORT_SYMBOL_GPL(is_fault_pfn);
+
 static inline unsigned long bad_hva(void)
 {
 	return PAGE_OFFSET;
@@ -831,7 +851,7 @@
 }
 EXPORT_SYMBOL_GPL(kvm_is_error_hva);
 
-struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn)
+struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
 {
 	int i;
 	struct kvm_memslots *slots = kvm_memslots(kvm);
@@ -845,20 +865,13 @@
 	}
 	return NULL;
 }
-EXPORT_SYMBOL_GPL(gfn_to_memslot_unaliased);
-
-struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
-{
-	gfn = unalias_gfn(kvm, gfn);
-	return gfn_to_memslot_unaliased(kvm, gfn);
-}
+EXPORT_SYMBOL_GPL(gfn_to_memslot);
 
 int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
 {
 	int i;
 	struct kvm_memslots *slots = kvm_memslots(kvm);
 
-	gfn = unalias_gfn_instantiation(kvm, gfn);
 	for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
 		struct kvm_memory_slot *memslot = &slots->memslots[i];
 
@@ -903,7 +916,6 @@
 	struct kvm_memslots *slots = kvm_memslots(kvm);
 	struct kvm_memory_slot *memslot = NULL;
 
-	gfn = unalias_gfn(kvm, gfn);
 	for (i = 0; i < slots->nmemslots; ++i) {
 		memslot = &slots->memslots[i];
 
@@ -924,8 +936,7 @@
 {
 	struct kvm_memory_slot *slot;
 
-	gfn = unalias_gfn_instantiation(kvm, gfn);
-	slot = gfn_to_memslot_unaliased(kvm, gfn);
+	slot = gfn_to_memslot(kvm, gfn);
 	if (!slot || slot->flags & KVM_MEMSLOT_INVALID)
 		return bad_hva();
 	return gfn_to_hva_memslot(slot, gfn);
@@ -946,13 +957,19 @@
 		struct vm_area_struct *vma;
 
 		down_read(&current->mm->mmap_sem);
+		if (is_hwpoison_address(addr)) {
+			up_read(&current->mm->mmap_sem);
+			get_page(hwpoison_page);
+			return page_to_pfn(hwpoison_page);
+		}
+
 		vma = find_vma(current->mm, addr);
 
 		if (vma == NULL || addr < vma->vm_start ||
 		    !(vma->vm_flags & VM_PFNMAP)) {
 			up_read(&current->mm->mmap_sem);
-			get_page(bad_page);
-			return page_to_pfn(bad_page);
+			get_page(fault_page);
+			return page_to_pfn(fault_page);
 		}
 
 		pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
@@ -1187,8 +1204,7 @@
 {
 	struct kvm_memory_slot *memslot;
 
-	gfn = unalias_gfn(kvm, gfn);
-	memslot = gfn_to_memslot_unaliased(kvm, gfn);
+	memslot = gfn_to_memslot(kvm, gfn);
 	if (memslot && memslot->dirty_bitmap) {
 		unsigned long rel_gfn = gfn - memslot->base_gfn;
 
@@ -1207,7 +1223,7 @@
 		prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE);
 
 		if (kvm_arch_vcpu_runnable(vcpu)) {
-			set_bit(KVM_REQ_UNHALT, &vcpu->requests);
+			kvm_make_request(KVM_REQ_UNHALT, vcpu);
 			break;
 		}
 		if (kvm_cpu_has_pending_timer(vcpu))
@@ -1378,6 +1394,18 @@
 
 	if (vcpu->kvm->mm != current->mm)
 		return -EIO;
+
+#if defined(CONFIG_S390) || defined(CONFIG_PPC)
+	/*
+	 * Special cases: vcpu ioctls that are asynchronous to vcpu execution,
+	 * so vcpu_load() would break it.
+	 */
+	if (ioctl == KVM_S390_INTERRUPT || ioctl == KVM_INTERRUPT)
+		return kvm_arch_vcpu_ioctl(filp, ioctl, arg);
+#endif
+
+
+	vcpu_load(vcpu);
 	switch (ioctl) {
 	case KVM_RUN:
 		r = -EINVAL;
@@ -1520,7 +1548,7 @@
 				goto out;
 			p = &sigset;
 		}
-		r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset);
+		r = kvm_vcpu_ioctl_set_sigmask(vcpu, p);
 		break;
 	}
 	case KVM_GET_FPU: {
@@ -1555,6 +1583,7 @@
 		r = kvm_arch_vcpu_ioctl(filp, ioctl, arg);
 	}
 out:
+	vcpu_put(vcpu);
 	kfree(fpu);
 	kfree(kvm_sregs);
 	return r;
@@ -2197,6 +2226,24 @@
 
 	bad_pfn = page_to_pfn(bad_page);
 
+	hwpoison_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+
+	if (hwpoison_page == NULL) {
+		r = -ENOMEM;
+		goto out_free_0;
+	}
+
+	hwpoison_pfn = page_to_pfn(hwpoison_page);
+
+	fault_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+
+	if (fault_page == NULL) {
+		r = -ENOMEM;
+		goto out_free_0;
+	}
+
+	fault_pfn = page_to_pfn(fault_page);
+
 	if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) {
 		r = -ENOMEM;
 		goto out_free_0;
@@ -2269,6 +2316,10 @@
 out_free_0a:
 	free_cpumask_var(cpus_hardware_enabled);
 out_free_0:
+	if (fault_page)
+		__free_page(fault_page);
+	if (hwpoison_page)
+		__free_page(hwpoison_page);
 	__free_page(bad_page);
 out:
 	kvm_arch_exit();
@@ -2290,6 +2341,7 @@
 	kvm_arch_hardware_unsetup();
 	kvm_arch_exit();
 	free_cpumask_var(cpus_hardware_enabled);
+	__free_page(hwpoison_page);
 	__free_page(bad_page);
 }
 EXPORT_SYMBOL_GPL(kvm_exit);